From c000780dba99a611fadbf83873073e024be1be0b Mon Sep 17 00:00:00 2001 From: Zeke Mostov <32168567+emostov@users.noreply.github.com> Date: Thu, 16 Sep 2021 19:25:21 -0700 Subject: [PATCH 0001/1472] Implement `pallet-bags-list` and its interfaces with `pallet-staking` (#9507) * remove extra whitespace Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * only emit rebag event on success * add doc explaining the term voter * revamp/simplify rebag test * ensure genesis accounts are placed into the correct nodes/bags * bond_extra implicitly rebags * types at top; doc public type * start sketching out adjustable thresholds * add integrity test for voter bag threshold requirements * get rid of BagIdx This reorganizes bag storage such that bags are always referred to by their upper threshold. This in turn means that adding and removing bags is cheaper; you only need to migrate certain voters, not all of them. * implement migration logic for when the threshold list changes * start sketching out threshold proc macros * further refine macro signatures * WIP: implement make_ratio macro * start rethinking the process of producing threshold lists The macro approach seems to be a non-starter; that only really works if we're throwing around numeric literals everywhere, and that's just not nice in this case. Instead, let's write helper functions and make it really easy to generate the tables in separate, permanent files, which humans can then edit. * write helper functions to emit voter bags module * WIP: demo generating voter bags for a realistic runtime This isn't yet done, becuase it seems to take a Very Long Time to run, and it really shouldn't. Need to look into that. Still, it's a lot closer than it was this morning. * rm unnecessary arg_enum * fix voter bags math Turns out that when you're working in exponential space, you need to divide, not subtract, in order to keep the math working properly. Also neaten up the output a little bit to make it easier to read. * add computed voter bags thresholds to node * fixup some docs * iter from large bags to small, fulfuilling the contract * make tests compile * add VoterBagThresholds to some configs * ensure that iteration covers all voters even with implied final bag * use sp_std::boxed::Box; * fix unused import * add some more voter bags tests * file_header.txt * integrity test to ensure min bag exceeds existential weight * add more debug assertions about node list length * rm unused imports * Kian enters * Update frame/election-provider-support/src/onchain.rs Co-authored-by: Zeke Mostov <32168567+emostov@users.noreply.github.com> * Suggestions for #9081 (Store voters in unsorted bags) (#9328) * Add some debug asserts to node::get and remove_node * Improve the debug asserts in remove_node * improve debug asserts * Space * Remove bad assertions * Tests: WIP take_works * Take test * Doc comment * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Test storage is cleaned up; * formatting * Switch to simpler thresholds * Update the storage cleanup test * Remove hardcoded values from benchmark to make it more robust * Fix tests to acces bags properly * Sanity check WIP; tests failing * Update sanity checks to be more correct * Improve storage cleanup tests * WIP remote_ext_tests * Some notes on next steps * Remove some stuff that was for remote-ext tests * Some more cleanup to reduce diff * More :clean: * Mo cleanin * small fix * A lot of changes from kian Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: kianenigma * merge fallout * Run cargo +nightly fmt * Fix a bunch of stuff, remove not needed runtime arg of make-bags * add logs * Glue the new staking bags to the election snapshot (#9415) * Glue the new staking bags to the election snapshot * add CheckedRem (#9412) * add CheckedRem * fix * Run fmt * Test comment Co-authored-by: Xiliang Chen Co-authored-by: emostov <32168567+emostov@users.noreply.github.com> * Update node runtime with VoterSnapshotPerBlock * Unit test for pallet-staking unsorted bags feature (targets #9081) (#9422) * impl notional_bag_for_works * Add tests: insert_as_works & insert_works * Impl test: remove_works * Trivial cleaning * Add test: update_position_for_works * Write out edge case; probably can delete later * Add test: bags::get_works * Add test: remove_node_happy_path_works * Add test: remove_node_bad_paths_documented * WIP: voting_data_works * done * Improve test voting_data_works * Add comment * Fill out test basic_setup_works * Update: iteration_is_semi_sorted * Improve remove_works * Update update_position_for_works; create set_ledger_and_free_balance * Improve get_works * Improve storage clean up checks in remove test * Test: impl rebag_works + insert_and_remove_works * forgot file - Test: impl rebag_works + insert_and_remove_works * Small tweak * Update voter_bags test to reflect unused bags are removed * Unbond & Rebond: do_rebag * Prevent infinite loops with duplicate tail insert * Check iter.count on voter list in pre-migrate * undo strang fmt comment stuff * Add in todo Co-authored-by: kianenigma * Try prepare for master merge * Reduce diff * Add comment for test to add * Add in code TODO for update_position efficiency updates * Initial impl compiles * impl StakingVoterListStub * Sample impl VoterListProvider for VoterList * impl VoterListProvider for voter-bags * WIP integrate pallet-voter-bags to staking mock * the trait `pallet_staking::pallet::pallet::Config` is not implemented for `mock::Test` * random * pushing my stuff * Mock working * WIP voter list tests * Add bag insert, remove tests * Add test for bag insert and remove * Add remaining tests for VoterList * Add tests for node * Add rebag works * Add rebag extrinsic tests * Rename to bags-list and name the list .. list! * Rename VoterBagThresholds => BagThresholds * Add test count_works * Test on_update_works * test sanity check * a round of test fixes * push a lot of changes * my last changes * all bags-list test work; fmt * Beautify some tests * Doc comment for bags-list * Add insert warnings * Setup initial benchmark * Wire up WeightInfo * is_terminal wip; everything broken! * Is terminal working * add TODOs for remove_node * clean up remoe_node * Fix all staking tests * retire VoterBagFor * commit * bring in stashed changes * save * bench pipeline works now, but I can't run stuff * sabe * benchmarks now run, but we have a failure * WIP: Wire up make_bags * bags-thresholds compiles * Fix most build issues * This will fix all the tests * move bag thresholds to bags-list * Move bag-thresholds bin to within pallet-bags * Remove some unnescary TODOs * Impl tets wrong_rebag_is_noop * assert remove is a noop with bad data * Assert integrity test panics * Return an error when inserting duplicates * Update to handle error in staking pallet when inserting to list * Test contains and on_insert error * Test re-nominate does not mess up list or count * Everything builds and works, only the benchmark... * fuck yeah benchmarks * more cleanup, more hardening. * use the bags list again * fix benhc * Some questions and changs for List::migration * Fix migration removed_bags and new_bags usage * Some trivial aesthetic changes * Some more trivial changes * tiny changes/ * mega rename * fix all tests and ci build * nit * Test and fix migration * nit * fmt * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * fmt * remove unused * make a few things pub * make node also pub.. for remote-ext test * Fix all tests again * Force bag changes in relevant benchmarks (targets #9507) (#9529) * force rebag for unbond, rebond, and bond_extra * nit * Improve utils * fmt * nits * Move generate_bags to its own pallet * Get runtime-benchmarks feature setup with prepare_on_update_benchmark * Withdraw unbonded kill working * Nominate bench working * some cleanup * WIP * update to check head pre & post conditions * Add some post condition verification stuff for on_remove * Update nominate * fmt * Improvements * Fix build * fix build with polkadot companion * Update frame/bags-list/src/list/tests.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * move generate-bag from frame to utils * wip * refactor WIP * WIP save * Refactor working * some variable renaming * WIP: prepare to remove head checks * Finish MvP refactor * Some cleanup * Soem more cleanup * save * fix a lot of stuff * Update client/db/src/bench.rs Co-authored-by: Shawn Tabrizi * Apply suggestions from code review * Apply suggestions from code review * Fix some issues that came from trying to merge comments on github * some small changes * simplify it Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: kianenigma Co-authored-by: Shawn Tabrizi * Build works * Apply suggestions from code review Co-authored-by: Guillaume Thiolliere * Apply suggestions from code review Co-authored-by: Guillaume Thiolliere * Remove commented out debug assert * Remove some unused deps and some unused benchmarking stuff * Fix stakings ElectionDataProvider clear * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_bags_list --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/bags-list/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_bags_list --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/bags-list/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_bags_list --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/bags-list/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_bags_list --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/bags-list/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Improving staking pallet-bags-list migration * fix build and some comments; * comment * Reduce visibility in bags list components * make node.bag_upper only accesible to benchmarks * Address some feedback; comments updates * use nominator map comment * fix vec capacity debug assert * Apply suggestions from code review Co-authored-by: Guillaume Thiolliere * clarify VoterSnapshotPerBlock * Reduce diff on create_validators by wrapping with_seed * Some small improvements to staking benches * Soem comment updates * fix vec capacity debug assert ... for real this time * Reduce ListBags viz * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Remove supports_eq_unordered & Support eq_unordered * Update utils/frame/generate-bags/src/lib.rs Co-authored-by: Guillaume Thiolliere * Make total-issuance & minimium-balance CLI args; Dont use emptry ext * Improve docs for generate bags CLI args * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Don't use default bags weight in node runtime * Feature gating sanity_check not working * Feature gate sanity check by creating duplicate fns * Fix line wrapping * Document VoteWeightProvider * Make bags ext-builder not a module * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * use pallet_bags_list instead of crate in mock * Make get_bags test helper fn live in List * use remove_from_storage_unchecked for node removal * Remove count of ids removed in remove_many * Add node sanity check, improve list sanity check * Do a list sanity check after on_update * List::migrate: clean up debug assert, exit early when no change in thresholds * Improve public doc comments for pallet_bags_list::list::List * Improve public doc comments for pallet_bags_list::list::List * Update generate bags docs * Fix grammar in bags-list benchmark * Add benchmark case for `rebag` extrinsic * Add count parameter to List::clear; WIP adding MaxEncodedLen to list' * MaxEncodeLen + generate_storage_info not working for Bag or Node * Get MaxEncodeLen derive to work * Try to correctly feature gate SortedListProvider::clear * Use u32::MAX, not u32::max_value * Get up to nominators_quota noms * SortedListProvider::clear takes an Option * Eplicitly ignore SortedListProvider return value * Fix doc comment * Update node-runtime voter snapshot per block * Add test get_max_len_voters_even_if_some_nominators_are_slashed * Add test only_iterates_max_2_times_nominators_quota * Fix generate bags cargo.toml * use sp_std vec * Remove v8 migration hooks from pallet-staking * Update npos trait * Try respect line width * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_bags_list --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/bags-list/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/bags-list/src/benchmarks.rs * Unwrap try-runtime error; remove sortedlistprovider pre upgrade len check * trigger ci * restore * trigger ci * restore * trigger ci * revert * trigger ci * revert Co-authored-by: Peter Goodspeed-Niklaus Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Peter Goodspeed-Niklaus Co-authored-by: kianenigma Co-authored-by: Xiliang Chen Co-authored-by: Parity Benchmarking Bot Co-authored-by: Shawn Tabrizi Co-authored-by: Guillaume Thiolliere --- Cargo.lock | 82 ++ Cargo.toml | 3 + bin/node/runtime/Cargo.toml | 3 + bin/node/runtime/src/lib.rs | 26 + bin/node/runtime/src/voter_bags.rs | 235 ++++++ frame/babe/src/mock.rs | 1 + frame/bags-list/Cargo.toml | 66 ++ frame/bags-list/src/benchmarks.rs | 144 ++++ frame/bags-list/src/lib.rs | 306 +++++++ frame/bags-list/src/list/mod.rs | 786 ++++++++++++++++++ frame/bags-list/src/list/tests.rs | 735 ++++++++++++++++ frame/bags-list/src/mock.rs | 154 ++++ frame/bags-list/src/tests.rs | 389 +++++++++ frame/bags-list/src/weights.rs | 95 +++ .../election-provider-multi-phase/src/lib.rs | 58 +- .../election-provider-multi-phase/src/mock.rs | 8 +- frame/election-provider-support/src/lib.rs | 69 ++ frame/executive/src/lib.rs | 4 +- frame/grandpa/src/mock.rs | 1 + frame/offences/benchmarking/src/mock.rs | 1 + frame/session/benchmarking/src/mock.rs | 1 + frame/staking/Cargo.toml | 2 + frame/staking/src/benchmarking.rs | 327 +++++++- frame/staking/src/lib.rs | 17 +- frame/staking/src/migrations.rs | 50 ++ frame/staking/src/mock.rs | 44 +- frame/staking/src/pallet/impls.rs | 255 ++++-- frame/staking/src/pallet/mod.rs | 45 +- frame/staking/src/testing_utils.rs | 50 +- frame/staking/src/tests.rs | 173 +++- frame/staking/src/weights.rs | 468 ++++++----- primitives/npos-elections/src/traits.rs | 9 +- utils/frame/generate-bags/Cargo.toml | 26 + .../generate-bags/node-runtime/Cargo.toml | 17 + .../generate-bags/node-runtime/src/main.rs | 46 + utils/frame/generate-bags/src/lib.rs | 246 ++++++ 36 files changed, 4602 insertions(+), 340 deletions(-) create mode 100644 bin/node/runtime/src/voter_bags.rs create mode 100644 frame/bags-list/Cargo.toml create mode 100644 frame/bags-list/src/benchmarks.rs create mode 100644 frame/bags-list/src/lib.rs create mode 100644 frame/bags-list/src/list/mod.rs create mode 100644 frame/bags-list/src/list/tests.rs create mode 100644 frame/bags-list/src/mock.rs create mode 100644 frame/bags-list/src/tests.rs create mode 100644 frame/bags-list/src/weights.rs create mode 100644 utils/frame/generate-bags/Cargo.toml create mode 100644 utils/frame/generate-bags/node-runtime/Cargo.toml create mode 100644 utils/frame/generate-bags/node-runtime/src/main.rs create mode 100644 utils/frame/generate-bags/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 7754e0ae6b62f..37773a4ae3a69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2314,6 +2314,21 @@ version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +[[package]] +name = "generate-bags" +version = "3.0.0" +dependencies = [ + "chrono", + "frame-election-provider-support", + "frame-support", + "frame-system", + "git2", + "num-format", + "pallet-staking", + "sp-io", + "structopt", +] + [[package]] name = "generic-array" version = "0.12.4" @@ -2395,6 +2410,19 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "git2" +version = "0.13.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659cd14835e75b64d9dba5b660463506763cf0aa6cb640aeeb0e98d841093490" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log 0.4.14", + "url 2.2.1", +] + [[package]] name = "glob" version = "0.3.0" @@ -3203,6 +3231,18 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" +[[package]] +name = "libgit2-sys" +version = "0.12.22+1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89c53ac117c44f7042ad8d8f5681378dfbc6010e49ec2c0d1f11dfedc7a4a1c3" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + [[package]] name = "libloading" version = "0.5.2" @@ -3775,6 +3815,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" dependencies = [ "cc", + "libc", "pkg-config", "vcpkg", ] @@ -4530,6 +4571,7 @@ dependencies = [ "pallet-authority-discovery", "pallet-authorship", "pallet-babe", + "pallet-bags-list", "pallet-balances", "pallet-bounties", "pallet-collective", @@ -4591,6 +4633,15 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "node-runtime-generate-bags" +version = "3.0.0" +dependencies = [ + "generate-bags", + "node-runtime", + "structopt", +] + [[package]] name = "node-template" version = "3.0.0" @@ -4750,6 +4801,16 @@ dependencies = [ "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", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -5017,6 +5078,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-bags-list" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log 0.4.14", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-tracing", +] + [[package]] name = "pallet-balances" version = "4.0.0-dev" @@ -5707,6 +5787,7 @@ dependencies = [ "frame-system", "log 0.4.14", "pallet-authorship", + "pallet-bags-list", "pallet-balances", "pallet-session", "pallet-staking-reward-curve", @@ -5718,6 +5799,7 @@ dependencies = [ "sp-application-crypto", "sp-core", "sp-io", + "sp-npos-elections", "sp-runtime", "sp-staking", "sp-std", diff --git a/Cargo.toml b/Cargo.toml index bca0c816217ee..e110c27b20d77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -128,6 +128,7 @@ members = [ "frame/uniques", "frame/utility", "frame/vesting", + "frame/bags-list", "primitives/api", "primitives/api/proc-macro", "primitives/api/test", @@ -198,6 +199,8 @@ members = [ "utils/frame/try-runtime/cli", "utils/frame/rpc/support", "utils/frame/rpc/system", + "utils/frame/generate-bags", + "utils/frame/generate-bags/node-runtime", "utils/prometheus", "utils/wasm-builder", ] diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index dafd9db8bab96..d434be8f3c609 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -55,6 +55,7 @@ pallet-assets = { version = "4.0.0-dev", default-features = false, path = "../.. pallet-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/authority-discovery" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../../../frame/authorship" } pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../../frame/babe" } +pallet-bags-list = { version = "4.0.0-dev", default-features = false, path = "../../../frame/bags-list" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../../frame/balances" } pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../../../frame/bounties" } pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../../../frame/collective" } @@ -110,6 +111,7 @@ std = [ "pallet-authorship/std", "sp-consensus-babe/std", "pallet-babe/std", + "pallet-bags-list/std", "pallet-balances/std", "pallet-bounties/std", "sp-block-builder/std", @@ -179,6 +181,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-babe/runtime-benchmarks", + "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-bounties/runtime-benchmarks", "pallet-collective/runtime-benchmarks", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 7c6475bd18d6a..9e8adfcd0910e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -92,6 +92,9 @@ pub mod constants; use constants::{currency::*, time::*}; use sp_runtime::generic::Era; +/// Generated voter bag information. +mod voter_bags; + // Make the WASM binary available. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); @@ -525,6 +528,9 @@ impl pallet_staking::Config for Runtime { type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainSequentialPhragmen; + // Alternatively, use pallet_staking::UseNominatorsMap to just use the nominators map. + // Note that the aforementioned does not scale to a very large number of nominators. + type SortedListProvider = BagsList; type WeightInfo = pallet_staking::weights::SubstrateWeight; } @@ -552,6 +558,11 @@ parameter_types! { *RuntimeBlockLength::get() .max .get(DispatchClass::Normal); + + // BagsList allows a practically unbounded count of nominators to participate in NPoS elections. + // To ensure we respect memory limits when using the BagsList this must be set to a number of + // voters we know can fit into a single vec allocation. + pub const VoterSnapshotPerBlock: u32 = 10_000; } sp_npos_elections::generate_solution_type!( @@ -634,6 +645,18 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; type ForceOrigin = EnsureRootOrHalfCouncil; type BenchmarkingConfig = BenchmarkConfig; + type VoterSnapshotPerBlock = VoterSnapshotPerBlock; +} + +parameter_types! { + pub const BagThresholds: &'static [u64] = &voter_bags::THRESHOLDS; +} + +impl pallet_bags_list::Config for Runtime { + type Event = Event; + type VoteWeightProvider = Staking; + type WeightInfo = pallet_bags_list::weights::SubstrateWeight; + type BagThresholds = BagThresholds; } parameter_types! { @@ -1254,6 +1277,7 @@ construct_runtime!( Gilt: pallet_gilt::{Pallet, Call, Storage, Event, Config}, Uniques: pallet_uniques::{Pallet, Call, Storage, Event}, TransactionStorage: pallet_transaction_storage::{Pallet, Call, Storage, Inherent, Config, Event}, + BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, } ); @@ -1581,6 +1605,7 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_assets, Assets); list_benchmark!(list, extra, pallet_babe, Babe); + list_benchmark!(list, extra, pallet_bags_list, BagsList); list_benchmark!(list, extra, pallet_balances, Balances); list_benchmark!(list, extra, pallet_bounties, Bounties); list_benchmark!(list, extra, pallet_collective, Council); @@ -1655,6 +1680,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_assets, Assets); add_benchmark!(params, batches, pallet_babe, Babe); add_benchmark!(params, batches, pallet_balances, Balances); + add_benchmark!(params, batches, pallet_bags_list, BagsList); add_benchmark!(params, batches, pallet_bounties, Bounties); add_benchmark!(params, batches, pallet_collective, Council); add_benchmark!(params, batches, pallet_contracts, Contracts); diff --git a/bin/node/runtime/src/voter_bags.rs b/bin/node/runtime/src/voter_bags.rs new file mode 100644 index 0000000000000..c4c731a58badc --- /dev/null +++ b/bin/node/runtime/src/voter_bags.rs @@ -0,0 +1,235 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated voter bag thresholds. +//! +//! Generated on 2021-07-05T09:17:40.469754927+00:00 +//! for the node runtime. + +/// Existential weight for this runtime. +#[cfg(any(test, feature = "std"))] +#[allow(unused)] +pub const EXISTENTIAL_WEIGHT: u64 = 100_000_000_000_000; + +/// Constant ratio between bags for this runtime. +#[cfg(any(test, feature = "std"))] +#[allow(unused)] +pub const CONSTANT_RATIO: f64 = 1.0628253590743408; + +/// Upper thresholds delimiting the bag list. +pub const THRESHOLDS: [u64; 200] = [ + 100_000_000_000_000, + 106_282_535_907_434, + 112_959_774_389_150, + 120_056_512_776_105, + 127_599_106_300_477, + 135_615_565_971_369, + 144_135_662_599_590, + 153_191_037_357_827, + 162_815_319_286_803, + 173_044_250_183_800, + 183_915_817_337_347, + 195_470_394_601_017, + 207_750_892_330_229, + 220_802_916_738_890, + 234_674_939_267_673, + 249_418_476_592_914, + 265_088_281_944_639, + 281_742_548_444_211, + 299_443_125_216_738, + 318_255_747_080_822, + 338_250_278_668_647, + 359_500_973_883_001, + 382_086_751_654_776, + 406_091_489_025_036, + 431_604_332_640_068, + 458_720_029_816_222, + 487_539_280_404_019, + 518_169_110_758_247, + 550_723_271_202_866, + 585_322_658_466_782, + 622_095_764_659_305, + 661_179_154_452_653, + 702_717_972_243_610, + 746_866_481_177_808, + 793_788_636_038_393, + 843_658_692_126_636, + 896_661_852_395_681, + 952_994_955_240_703, + 1_012_867_205_499_736, + 1_076_500_951_379_881, + 1_144_132_510_194_192, + 1_216_013_045_975_769, + 1_292_409_502_228_280, + 1_373_605_593_276_862, + 1_459_902_857_901_004, + 1_551_621_779_162_291, + 1_649_102_974_585_730, + 1_752_708_461_114_642, + 1_862_822_999_536_805, + 1_979_855_523_374_646, + 2_104_240_657_545_975, + 2_236_440_332_435_128, + 2_376_945_499_368_703, + 2_526_277_953_866_680, + 2_684_992_273_439_945, + 2_853_677_877_130_641, + 3_032_961_214_443_876, + 3_223_508_091_799_862, + 3_426_026_145_146_232, + 3_641_267_467_913_124, + 3_870_031_404_070_482, + 4_113_167_516_660_186, + 4_371_578_742_827_277, + 4_646_224_747_067_156, + 4_938_125_485_141_739, + 5_248_364_991_899_922, + 5_578_095_407_069_235, + 5_928_541_253_969_291, + 6_301_003_987_036_955, + 6_696_866_825_051_405, + 7_117_599_888_008_300, + 7_564_765_656_719_910, + 8_040_024_775_416_580, + 8_545_142_218_898_723, + 9_081_993_847_142_344, + 9_652_573_371_700_016, + 10_258_999_759_768_490, + 10_903_525_103_419_522, + 11_588_542_983_217_942, + 12_316_597_357_287_042, + 13_090_392_008_832_678, + 13_912_800_587_211_472, + 14_786_877_279_832_732, + 15_715_868_154_526_436, + 16_703_223_214_499_558, + 17_752_609_210_649_358, + 18_867_923_258_814_856, + 20_053_307_312_537_008, + 21_313_163_545_075_252, + 22_652_170_697_804_756, + 24_075_301_455_707_600, + 25_587_840_914_485_432, + 27_195_406_207_875_088, + 28_903_967_368_057_400, + 30_719_869_496_628_636, + 32_649_856_328_471_220, + 34_701_095_276_033_064, + 36_881_204_047_022_752, + 39_198_278_934_370_992, + 41_660_924_883_519_016, + 44_278_287_448_695_240, + 47_060_086_756_856_400, + 50_016_653_605_425_536, + 53_158_967_827_883_320, + 56_498_699_069_691_424, + 60_048_250_125_977_912, + 63_820_803_001_928_304, + 67_830_367_866_937_216, + 72_091_835_084_322_176, + 76_621_030_509_822_880, + 81_434_774_264_248_528, + 86_550_943_198_537_824, + 91_988_537_283_208_848, + 97_767_750_168_749_840, + 103_910_044_178_992_000, + 110_438_230_015_967_792, + 117_376_551_472_255_616, + 124_750_775_465_407_920, + 132_588_287_728_824_640, + 140_918_194_514_440_064, + 149_771_430_684_917_568, + 159_180_874_596_775_264, + 169_181_470_201_085_280, + 179_810_356_815_193_344, + 191_107_007_047_393_216, + 203_113_373_386_768_288, + 215_874_044_002_592_672, + 229_436_408_331_885_600, + 243_850_833_070_063_392, + 259_170_849_218_267_264, + 275_453_350_882_006_752, + 292_758_806_559_399_232, + 311_151_483_703_668_992, + 330_699_687_393_865_920, + 351_476_014_000_157_824, + 373_557_620_785_735_808, + 397_026_512_446_556_096, + 421_969_845_653_044_224, + 448_480_252_724_740_928, + 476_656_185_639_923_904, + 506_602_281_657_757_760, + 538_429_751_910_786_752, + 572_256_794_410_890_176, + 608_209_033_002_485_632, + 646_419_983_893_124_352, + 687_031_551_494_039_552, + 730_194_555_412_054_016, + 776_069_290_549_944_960, + 824_826_122_395_314_176, + 876_646_119_708_695_936, + 931_721_726_960_522_368, + 990_257_479_014_182_144, + 1_052_470_760_709_299_712, + 1_118_592_614_166_106_112, + 1_188_868_596_808_997_376, + 1_263_559_693_295_730_432, + 1_342_943_284_738_898_688, + 1_427_314_178_819_094_784, + 1_516_985_704_615_302_400, + 1_612_290_876_218_400_768, + 1_713_583_629_449_105_408, + 1_821_240_136_273_157_632, + 1_935_660_201_795_120_128, + 2_057_268_749_018_809_600, + 2_186_517_396_888_336_384, + 2_323_886_137_470_138_880, + 2_469_885_118_504_583_168, + 2_625_056_537_947_004_416, + 2_789_976_657_533_970_944, + 2_965_257_942_852_572_160, + 3_151_551_337_860_326_400, + 3_349_548_682_302_620_672, + 3_559_985_281_005_267_968, + 3_783_642_634_583_792_128, + 4_021_351_341_710_503_936, + 4_273_994_183_717_548_544, + 4_542_509_402_991_247_872, + 4_827_894_187_332_742_144, + 5_131_208_373_224_844_288, + 5_453_578_381_757_959_168, + 5_796_201_401_831_965_696, + 6_160_349_836_169_256_960, + 6_547_376_026_650_146_816, + 6_958_717_276_519_173_120, + 7_395_901_188_113_309_696, + 7_860_551_335_934_872_576, + 8_354_393_296_137_270_272, + 8_879_261_054_815_360_000, + 9_437_103_818_898_946_048, + 10_029_993_254_943_105_024, + 10_660_131_182_698_121_216, + 11_329_857_752_030_707_712, + 12_041_660_133_563_240_448, + 12_798_181_755_305_525_248, + 13_602_232_119_581_272_064, + 14_456_797_236_706_498_560, + 15_365_050_714_167_523_328, + 16_330_365_542_480_556_032, + 17_356_326_621_502_140_416, + 18_446_744_073_709_551_615, +]; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index bc0be32624cba..833a68fbddb6c 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -216,6 +216,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type WeightInfo = (); + type SortedListProvider = pallet_staking::UseNominatorsMap; } impl pallet_offences::Config for Test { diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml new file mode 100644 index 0000000000000..860a6edc42143 --- /dev/null +++ b/frame/bags-list/Cargo.toml @@ -0,0 +1,66 @@ +[package] +name = "pallet-bags-list" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet bags list" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +# parity +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } + +# primitives +sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } + +# FRAME +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } + +# third party +log = { version = "0.4.14", default-features = false } + +# Optional imports for benchmarking +frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking", optional = true, default-features = false } +pallet-balances = { version = "4.0.0-dev", path = "../balances", optional = true, default-features = false } +sp-core = { version = "4.0.0-dev", path = "../../primitives/core", optional = true, default-features = false } +sp-io = { version = "4.0.0-dev", path = "../../primitives/io", optional = true, default-features = false } +sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing", optional = true, default-features = false } + +[dev-dependencies] +sp-core = { version = "4.0.0-dev", path = "../../primitives/core"} +sp-io = { version = "4.0.0-dev", path = "../../primitives/io"} +sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +pallet-balances = { version = "4.0.0-dev", path = "../balances" } +frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support", features = ["runtime-benchmarks"] } +frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-runtime/std", + "sp-std/std", + "frame-support/std", + "frame-system/std", + "frame-election-provider-support/std", + "log/std", +] +runtime-benchmarks = [ + "frame-benchmarking", + "sp-core", + "sp-io", + "pallet-balances", + "sp-tracing", + "frame-election-provider-support/runtime-benchmarks", +] + diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs new file mode 100644 index 0000000000000..a820eeba13b12 --- /dev/null +++ b/frame/bags-list/src/benchmarks.rs @@ -0,0 +1,144 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmarks for the bags list pallet. + +use super::*; +use crate::list::List; +use frame_benchmarking::{account, whitelisted_caller}; +use frame_election_provider_support::VoteWeightProvider; +use frame_support::{assert_ok, traits::Get}; +use frame_system::RawOrigin as SystemOrigin; + +frame_benchmarking::benchmarks! { + rebag_non_terminal { + // An expensive case for rebag-ing (rebag a non-terminal node): + // + // - The node to be rebagged, _R_, should exist as a non-terminal node in a bag with at + // least 2 other nodes. Thus _R_ will have both its `prev` and `next` nodes updated when + // it is removed. (3 W/R) + // - The destination bag is not empty, thus we need to update the `next` pointer of the last + // node in the destination in addition to the work we do otherwise. (2 W/R) + + // clear any pre-existing storage. + List::::clear(None); + + // define our origin and destination thresholds. + let origin_bag_thresh = T::BagThresholds::get()[0]; + let dest_bag_thresh = T::BagThresholds::get()[1]; + + // seed items in the origin bag. + let origin_head: T::AccountId = account("origin_head", 0, 0); + assert_ok!(List::::insert(origin_head.clone(), origin_bag_thresh)); + + let origin_middle: T::AccountId = account("origin_middle", 0, 0); // the node we rebag (_R_) + assert_ok!(List::::insert(origin_middle.clone(), origin_bag_thresh)); + + let origin_tail: T::AccountId = account("origin_tail", 0, 0); + assert_ok!(List::::insert(origin_tail.clone(), origin_bag_thresh)); + + // seed items in the destination bag. + let dest_head: T::AccountId = account("dest_head", 0, 0); + assert_ok!(List::::insert(dest_head.clone(), dest_bag_thresh)); + + // the bags are in the expected state after initial setup. + assert_eq!( + List::::get_bags(), + vec![ + (origin_bag_thresh, vec![origin_head.clone(), origin_middle.clone(), origin_tail.clone()]), + (dest_bag_thresh, vec![dest_head.clone()]) + ] + ); + + let caller = whitelisted_caller(); + // update the weight of `origin_middle` to guarantee it will be rebagged into the destination. + T::VoteWeightProvider::set_vote_weight_of(&origin_middle, dest_bag_thresh); + }: rebag(SystemOrigin::Signed(caller), origin_middle.clone()) + verify { + // check the bags have updated as expected. + assert_eq!( + List::::get_bags(), + vec![ + ( + origin_bag_thresh, + vec![origin_head, origin_tail], + ), + ( + dest_bag_thresh, + vec![dest_head, origin_middle], + ) + ] + ); + } + + rebag_terminal { + // An expensive case for rebag-ing (rebag a terminal node): + // + // - The node to be rebagged, _R_, is a terminal node; so _R_, the node pointing to _R_ and + // the origin bag itself will need to be updated. (3 W/R) + // - The destination bag is not empty, thus we need to update the `next` pointer of the last + // node in the destination in addition to the work we do otherwise. (2 W/R) + + // clear any pre-existing storage. + List::::clear(None); + + // define our origin and destination thresholds. + let origin_bag_thresh = T::BagThresholds::get()[0]; + let dest_bag_thresh = T::BagThresholds::get()[1]; + + // seed items in the origin bag. + let origin_head: T::AccountId = account("origin_head", 0, 0); + assert_ok!(List::::insert(origin_head.clone(), origin_bag_thresh)); + + let origin_tail: T::AccountId = account("origin_tail", 0, 0); // the node we rebag (_R_) + assert_ok!(List::::insert(origin_tail.clone(), origin_bag_thresh)); + + // seed items in the destination bag. + let dest_head: T::AccountId = account("dest_head", 0, 0); + assert_ok!(List::::insert(dest_head.clone(), dest_bag_thresh)); + + // the bags are in the expected state after initial setup. + assert_eq!( + List::::get_bags(), + vec![ + (origin_bag_thresh, vec![origin_head.clone(), origin_tail.clone()]), + (dest_bag_thresh, vec![dest_head.clone()]) + ] + ); + + let caller = whitelisted_caller(); + // update the weight of `origin_tail` to guarantee it will be rebagged into the destination. + T::VoteWeightProvider::set_vote_weight_of(&origin_tail, dest_bag_thresh); + }: rebag(SystemOrigin::Signed(caller), origin_tail.clone()) + verify { + // check the bags have updated as expected. + assert_eq!( + List::::get_bags(), + vec![ + (origin_bag_thresh, vec![origin_head.clone()]), + (dest_bag_thresh, vec![dest_head.clone(), origin_tail.clone()]) + ] + ); + } +} + +use frame_benchmarking::impl_benchmark_test_suite; +impl_benchmark_test_suite!( + Pallet, + crate::mock::ExtBuilder::default().build(), + crate::mock::Runtime, +); diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs new file mode 100644 index 0000000000000..4202a4d499895 --- /dev/null +++ b/frame/bags-list/src/lib.rs @@ -0,0 +1,306 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Bags-List Pallet +//! +//! A semi-sorted list, where items hold an `AccountId` based on some `VoteWeight`. The `AccountId` +//! (`id` for short) might be synonym to a `voter` or `nominator` in some context, and `VoteWeight` +//! signifies the chance of each id being included in the final [`VoteWeightProvider::iter`]. +//! +//! It implements [`sp_election_provider_support::SortedListProvider`] to provide a semi-sorted list +//! of accounts to another pallet. It needs some other pallet to give it some information about the +//! weights of accounts via [`sp_election_provider_support::VoteWeightProvider`]. +//! +//! This pallet is not configurable at genesis. Whoever uses it should call appropriate functions of +//! the `SortedListProvider` (e.g. `on_insert`, or `regenerate`) at their genesis. +//! +//! # Goals +//! +//! The data structure exposed by this pallet aims to be optimized for: +//! +//! - insertions and removals. +//! - iteration over the top* N items by weight, where the precise ordering of items doesn't +//! particularly matter. +//! +//! # Details +//! +//! - items are kept in bags, which are delineated by their range of weight (See [`BagThresholds`]). +//! - for iteration, bags are chained together from highest to lowest and elements within the bag +//! are iterated from head to tail. +//! - items within a bag are iterated in order of insertion. Thus removing an item and re-inserting +//! it will worsen its position in list iteration; this reduces incentives for some types of spam +//! that involve consistently removing and inserting for better position. Further, ordering +//! granularity is thus dictated by range between each bag threshold. +//! - if an item's weight changes to a value no longer within the range of its current bag the +//! item's position will need to be updated by an external actor with rebag (update), or removal +//! and insertion. + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_election_provider_support::{SortedListProvider, VoteWeight, VoteWeightProvider}; +use frame_system::ensure_signed; +use sp_std::prelude::*; + +#[cfg(any(feature = "runtime-benchmarks", test))] +mod benchmarks; + +mod list; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; +pub mod weights; + +pub use pallet::*; +pub use weights::WeightInfo; + +pub use list::Error; +use list::List; + +pub(crate) const LOG_TARGET: &'static str = "runtime::bags_list"; + +// syntactic sugar for logging. +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: crate::LOG_TARGET, + concat!("[{:?}] 👜", $patter), >::block_number() $(, $values)* + ) + }; +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(crate) trait Store)] + #[pallet::generate_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: weights::WeightInfo; + + /// Something that provides the weights of ids. + type VoteWeightProvider: VoteWeightProvider; + + /// The list of thresholds separating the various bags. + /// + /// Ids are separated into unsorted bags according to their vote weight. This specifies the + /// thresholds separating the bags. An id's bag is the largest bag for which the id's weight + /// is less than or equal to its upper threshold. + /// + /// When ids are iterated, higher bags are iterated completely before lower bags. This means + /// that iteration is _semi-sorted_: ids of higher weight tend to come before ids of lower + /// weight, but peer ids within a particular bag are sorted in insertion order. + /// + /// # Expressing the constant + /// + /// This constant must be sorted in strictly increasing order. Duplicate items are not + /// permitted. + /// + /// There is an implied upper limit of `VoteWeight::MAX`; that value does not need to be + /// specified within the bag. For any two threshold lists, if one ends with + /// `VoteWeight::MAX`, the other one does not, and they are otherwise equal, the two lists + /// will behave identically. + /// + /// # Calculation + /// + /// It is recommended to generate the set of thresholds in a geometric series, such that + /// there exists some constant ratio such that `threshold[k + 1] == (threshold[k] * + /// constant_ratio).max(threshold[k] + 1)` for all `k`. + /// + /// The helpers in the `/utils/frame/generate-bags` module can simplify this calculation. + /// + /// # Examples + /// + /// - If `BagThresholds::get().is_empty()`, then all ids are put into the same bag, and + /// iteration is strictly in insertion order. + /// - If `BagThresholds::get().len() == 64`, and the thresholds are determined according to + /// the procedure given above, then the constant ratio is equal to 2. + /// - If `BagThresholds::get().len() == 200`, and the thresholds are determined according to + /// the procedure given above, then the constant ratio is approximately equal to 1.248. + /// - If the threshold list begins `[1, 2, 3, ...]`, then an id with weight 0 or 1 will fall + /// into bag 0, an id with weight 2 will fall into bag 1, etc. + /// + /// # Migration + /// + /// In the event that this list ever changes, a copy of the old bags list must be retained. + /// With that `List::migrate` can be called, which will perform the appropriate migration. + #[pallet::constant] + type BagThresholds: Get<&'static [VoteWeight]>; + } + + /// How many ids are registered. + // NOTE: This is merely a counter for `ListNodes`. It should someday be replaced by the + // `CountedMaop` storage. + #[pallet::storage] + pub(crate) type CounterForListNodes = StorageValue<_, u32, ValueQuery>; + + /// A single node, within some bag. + /// + /// Nodes store links forward and back within their respective bags. + #[pallet::storage] + pub(crate) type ListNodes = StorageMap<_, Twox64Concat, T::AccountId, list::Node>; + + /// A bag stored in storage. + /// + /// Stores a `Bag` struct, which stores head and tail pointers to itself. + #[pallet::storage] + pub(crate) type ListBags = StorageMap<_, Twox64Concat, VoteWeight, list::Bag>; + + #[pallet::event] + #[pallet::generate_deposit(pub(crate) fn deposit_event)] + pub enum Event { + /// Moved an account from one bag to another. \[who, from, to\]. + Rebagged(T::AccountId, VoteWeight, VoteWeight), + } + + #[pallet::call] + impl Pallet { + /// Declare that some `dislocated` account has, through rewards or penalties, sufficiently + /// changed its weight that it should properly fall into a different bag than its current + /// one. + /// + /// Anyone can call this function about any potentially dislocated account. + /// + /// Will never return an error; if `dislocated` does not exist or doesn't need a rebag, then + /// it is a noop and fees are still collected from `origin`. + #[pallet::weight(T::WeightInfo::rebag_non_terminal().max(T::WeightInfo::rebag_terminal()))] + pub fn rebag(origin: OriginFor, dislocated: T::AccountId) -> DispatchResult { + ensure_signed(origin)?; + let current_weight = T::VoteWeightProvider::vote_weight(&dislocated); + let _ = Pallet::::do_rebag(&dislocated, current_weight); + Ok(()) + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + // ensure they are strictly increasing, this also implies that duplicates are detected. + assert!( + T::BagThresholds::get().windows(2).all(|window| window[1] > window[0]), + "thresholds must strictly increase, and have no duplicates", + ); + } + } +} + +impl Pallet { + /// Move an account from one bag to another, depositing an event on success. + /// + /// If the account changed bags, returns `Some((from, to))`. + pub fn do_rebag( + account: &T::AccountId, + new_weight: VoteWeight, + ) -> Option<(VoteWeight, VoteWeight)> { + // if no voter at that node, don't do anything. + // the caller just wasted the fee to call this. + let maybe_movement = list::Node::::get(&account) + .and_then(|node| List::update_position_for(node, new_weight)); + if let Some((from, to)) = maybe_movement { + Self::deposit_event(Event::::Rebagged(account.clone(), from, to)); + }; + maybe_movement + } + + /// Equivalent to `ListBags::get`, but public. Useful for tests in outside of this crate. + #[cfg(feature = "std")] + pub fn list_bags_get(weight: VoteWeight) -> Option> { + ListBags::get(weight) + } +} + +impl SortedListProvider for Pallet { + type Error = Error; + + fn iter() -> Box> { + Box::new(List::::iter().map(|n| n.id().clone())) + } + + fn count() -> u32 { + CounterForListNodes::::get() + } + + fn contains(id: &T::AccountId) -> bool { + List::::contains(id) + } + + fn on_insert(id: T::AccountId, weight: VoteWeight) -> Result<(), Error> { + List::::insert(id, weight) + } + + fn on_update(id: &T::AccountId, new_weight: VoteWeight) { + Pallet::::do_rebag(id, new_weight); + } + + fn on_remove(id: &T::AccountId) { + List::::remove(id) + } + + fn regenerate( + all: impl IntoIterator, + weight_of: Box VoteWeight>, + ) -> u32 { + List::::regenerate(all, weight_of) + } + + #[cfg(feature = "std")] + fn sanity_check() -> Result<(), &'static str> { + List::::sanity_check() + } + + #[cfg(not(feature = "std"))] + fn sanity_check() -> Result<(), &'static str> { + Ok(()) + } + + fn clear(maybe_count: Option) -> u32 { + List::::clear(maybe_count) + } + + #[cfg(feature = "runtime-benchmarks")] + fn weight_update_worst_case(who: &T::AccountId, is_increase: bool) -> VoteWeight { + use frame_support::traits::Get as _; + let thresholds = T::BagThresholds::get(); + let node = list::Node::::get(who).unwrap(); + let current_bag_idx = thresholds + .iter() + .chain(sp_std::iter::once(&VoteWeight::MAX)) + .position(|w| w == &node.bag_upper()) + .unwrap(); + + if is_increase { + let next_threshold_idx = current_bag_idx + 1; + assert!(thresholds.len() > next_threshold_idx); + thresholds[next_threshold_idx] + } else { + assert!(current_bag_idx != 0); + let prev_threshold_idx = current_bag_idx - 1; + thresholds[prev_threshold_idx] + } + } +} diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs new file mode 100644 index 0000000000000..3f55f22271910 --- /dev/null +++ b/frame/bags-list/src/list/mod.rs @@ -0,0 +1,786 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of a "bags list": a semi-sorted list where ordering granularity is dictated by +//! configurable thresholds that delineate the boundaries of bags. It uses a pattern of composite +//! data structures, where multiple storage items are masked by one outer API. See [`ListNodes`], +//! [`CounterForListNodes`] and [`ListBags`] for more information. +//! +//! The outer API of this module is the [`List`] struct. It wraps all acceptable operations on top +//! of the aggregate linked list. All operations with the bags list should happen through this +//! interface. + +use crate::Config; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_election_provider_support::{VoteWeight, VoteWeightProvider}; +use frame_support::{traits::Get, DefaultNoBound}; +use scale_info::TypeInfo; +use sp_std::{ + boxed::Box, + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + iter, + marker::PhantomData, + vec::Vec, +}; + +#[derive(Debug, PartialEq, Eq)] +pub enum Error { + /// A duplicate id has been detected. + Duplicate, +} + +#[cfg(test)] +mod tests; + +/// Given a certain vote weight, to which bag does it belong to? +/// +/// Bags are identified by their upper threshold; the value returned by this function is guaranteed +/// to be a member of `T::BagThresholds`. +/// +/// Note that even if the thresholds list does not have `VoteWeight::MAX` as its final member, this +/// function behaves as if it does. +pub(crate) fn notional_bag_for(weight: VoteWeight) -> VoteWeight { + let thresholds = T::BagThresholds::get(); + let idx = thresholds.partition_point(|&threshold| weight > threshold); + thresholds.get(idx).copied().unwrap_or(VoteWeight::MAX) +} + +/// The **ONLY** entry point of this module. All operations to the bags-list should happen through +/// this interface. It is forbidden to access other module members directly. +// +// Data structure providing efficient mostly-accurate selection of the top N id by `VoteWeight`. +// +// It's implemented as a set of linked lists. Each linked list comprises a bag of ids of +// arbitrary and unbounded length, all having a vote weight within a particular constant range. +// This structure means that ids can be added and removed in `O(1)` time. +// +// Iteration is accomplished by chaining the iteration of each bag, from greatest to least. While +// the users within any particular bag are sorted in an entirely arbitrary order, the overall vote +// weight decreases as successive bags are reached. This means that it is valid to truncate +// iteration at any desired point; only those ids in the lowest bag can be excluded. This +// satisfies both the desire for fairness and the requirement for efficiency. +pub struct List(PhantomData); + +impl List { + /// Remove all data associated with the list from storage. Parameter `items` is the number of + /// items to clear from the list. WARNING: `None` will clear all items and should generally not + /// be used in production as it could lead to an infinite number of storage accesses. + pub(crate) fn clear(maybe_count: Option) -> u32 { + crate::ListBags::::remove_all(maybe_count); + crate::ListNodes::::remove_all(maybe_count); + if let Some(count) = maybe_count { + crate::CounterForListNodes::::mutate(|items| *items - count); + count + } else { + crate::CounterForListNodes::::take() + } + } + + /// Regenerate all of the data from the given ids. + /// + /// WARNING: this is expensive and should only ever be performed when the list needs to be + /// generated from scratch. Care needs to be taken to ensure + /// + /// This may or may not need to be called at genesis as well, based on the configuration of the + /// pallet using this `List`. + /// + /// Returns the number of ids migrated. + pub fn regenerate( + all: impl IntoIterator, + weight_of: Box VoteWeight>, + ) -> u32 { + Self::clear(None); + Self::insert_many(all, weight_of) + } + + /// Migrate the list from one set of thresholds to another. + /// + /// This should only be called as part of an intentional migration; it's fairly expensive. + /// + /// Returns the number of accounts affected. + /// + /// Preconditions: + /// + /// - `old_thresholds` is the previous list of thresholds. + /// - All `bag_upper` currently in storage are members of `old_thresholds`. + /// - `T::BagThresholds` has already been updated and is the new set of thresholds. + /// + /// Postconditions: + /// + /// - All `bag_upper` currently in storage are members of `T::BagThresholds`. + /// - No id is changed unless required to by the difference between the old threshold list and + /// the new. + /// - ids whose bags change at all are implicitly rebagged into the appropriate bag in the new + /// threshold set. + #[allow(dead_code)] + pub fn migrate(old_thresholds: &[VoteWeight]) -> u32 { + let new_thresholds = T::BagThresholds::get(); + if new_thresholds == old_thresholds { + return 0 + } + + // we can't check all preconditions, but we can check one + debug_assert!( + crate::ListBags::::iter().all(|(threshold, _)| old_thresholds.contains(&threshold)), + "not all `bag_upper` currently in storage are members of `old_thresholds`", + ); + debug_assert!( + crate::ListNodes::::iter().all(|(_, node)| old_thresholds.contains(&node.bag_upper)), + "not all `node.bag_upper` currently in storage are members of `old_thresholds`", + ); + + let old_set: BTreeSet<_> = old_thresholds.iter().copied().collect(); + let new_set: BTreeSet<_> = new_thresholds.iter().copied().collect(); + + // accounts that need to be rebagged + let mut affected_accounts = BTreeSet::new(); + // track affected old bags to make sure we only iterate them once + let mut affected_old_bags = BTreeSet::new(); + + let new_bags = new_set.difference(&old_set).copied(); + // a new bag means that all accounts previously using the old bag's threshold must now + // be rebagged + for inserted_bag in new_bags { + let affected_bag = { + // this recreates `notional_bag_for` logic, but with the old thresholds. + let idx = old_thresholds.partition_point(|&threshold| inserted_bag > threshold); + old_thresholds.get(idx).copied().unwrap_or(VoteWeight::MAX) + }; + if !affected_old_bags.insert(affected_bag) { + // If the previous threshold list was [10, 20], and we insert [3, 5], then there's + // no point iterating through bag 10 twice. + continue + } + + if let Some(bag) = Bag::::get(affected_bag) { + affected_accounts.extend(bag.iter().map(|node| node.id)); + } + } + + let removed_bags = old_set.difference(&new_set).copied(); + // a removed bag means that all members of that bag must be rebagged + for removed_bag in removed_bags.clone() { + if !affected_old_bags.insert(removed_bag) { + continue + } + + if let Some(bag) = Bag::::get(removed_bag) { + affected_accounts.extend(bag.iter().map(|node| node.id)); + } + } + + // migrate the voters whose bag has changed + let num_affected = affected_accounts.len() as u32; + let weight_of = T::VoteWeightProvider::vote_weight; + let _removed = Self::remove_many(&affected_accounts); + debug_assert_eq!(_removed, num_affected); + let _inserted = Self::insert_many(affected_accounts.into_iter(), weight_of); + debug_assert_eq!(_inserted, num_affected); + + // we couldn't previously remove the old bags because both insertion and removal assume that + // it's always safe to add a bag if it's not present. Now that that's sorted, we can get rid + // of them. + // + // it's pretty cheap to iterate this again, because both sets are in-memory and require no + // lookups. + for removed_bag in removed_bags { + debug_assert!( + !crate::ListNodes::::iter().any(|(_, node)| node.bag_upper == removed_bag), + "no id should be present in a removed bag", + ); + crate::ListBags::::remove(removed_bag); + } + + debug_assert_eq!(Self::sanity_check(), Ok(())); + + num_affected + } + + /// Returns `true` if the list contains `id`, otherwise returns `false`. + pub(crate) fn contains(id: &T::AccountId) -> bool { + crate::ListNodes::::contains_key(id) + } + + /// Iterate over all nodes in all bags in the list. + /// + /// Full iteration can be expensive; it's recommended to limit the number of items with + /// `.take(n)`. + pub(crate) fn iter() -> impl Iterator> { + // We need a touch of special handling here: because we permit `T::BagThresholds` to + // omit the final bound, we need to ensure that we explicitly include that threshold in the + // list. + // + // It's important to retain the ability to omit the final bound because it makes tests much + // easier; they can just configure `type BagThresholds = ()`. + let thresholds = T::BagThresholds::get(); + let iter = thresholds.iter().copied(); + let iter: Box> = if thresholds.last() == Some(&VoteWeight::MAX) { + // in the event that they included it, we can just pass the iterator through unchanged. + Box::new(iter.rev()) + } else { + // otherwise, insert it here. + Box::new(iter.chain(iter::once(VoteWeight::MAX)).rev()) + }; + + iter.filter_map(Bag::get).flat_map(|bag| bag.iter()) + } + + /// Insert several ids into the appropriate bags in the list. Continues with insertions + /// if duplicates are detected. + /// + /// Returns the final count of number of ids inserted. + fn insert_many( + ids: impl IntoIterator, + weight_of: impl Fn(&T::AccountId) -> VoteWeight, + ) -> u32 { + let mut count = 0; + ids.into_iter().for_each(|v| { + let weight = weight_of(&v); + if Self::insert(v, weight).is_ok() { + count += 1; + } + }); + + count + } + + /// Insert a new id into the appropriate bag in the list. + /// + /// Returns an error if the list already contains `id`. + pub(crate) fn insert(id: T::AccountId, weight: VoteWeight) -> Result<(), Error> { + if Self::contains(&id) { + return Err(Error::Duplicate) + } + + let bag_weight = notional_bag_for::(weight); + let mut bag = Bag::::get_or_make(bag_weight); + // unchecked insertion is okay; we just got the correct `notional_bag_for`. + bag.insert_unchecked(id.clone()); + + // new inserts are always the tail, so we must write the bag. + bag.put(); + + crate::CounterForListNodes::::mutate(|prev_count| { + *prev_count = prev_count.saturating_add(1) + }); + + crate::log!( + debug, + "inserted {:?} with weight {} into bag {:?}, new count is {}", + id, + weight, + bag_weight, + crate::CounterForListNodes::::get(), + ); + + Ok(()) + } + + /// Remove an id from the list. + pub(crate) fn remove(id: &T::AccountId) { + Self::remove_many(sp_std::iter::once(id)); + } + + /// Remove many ids from the list. + /// + /// This is more efficient than repeated calls to `Self::remove`. + /// + /// Returns the final count of number of ids removed. + fn remove_many<'a>(ids: impl IntoIterator) -> u32 { + let mut bags = BTreeMap::new(); + let mut count = 0; + + for id in ids.into_iter() { + let node = match Node::::get(id) { + Some(node) => node, + None => continue, + }; + count += 1; + + if !node.is_terminal() { + // this node is not a head or a tail and thus the bag does not need to be updated + node.excise() + } else { + // this node is a head or tail, so the bag needs to be updated + let bag = bags + .entry(node.bag_upper) + .or_insert_with(|| Bag::::get_or_make(node.bag_upper)); + // node.bag_upper must be correct, therefore this bag will contain this node. + bag.remove_node_unchecked(&node); + } + + // now get rid of the node itself + node.remove_from_storage_unchecked() + } + + for (_, bag) in bags { + bag.put(); + } + + crate::CounterForListNodes::::mutate(|prev_count| { + *prev_count = prev_count.saturating_sub(count) + }); + + count + } + + /// Update a node's position in the list. + /// + /// If the node was in the correct bag, no effect. If the node was in the incorrect bag, they + /// are moved into the correct bag. + /// + /// Returns `Some((old_idx, new_idx))` if the node moved, otherwise `None`. + /// + /// This operation is somewhat more efficient than simply calling [`self.remove`] followed by + /// [`self.insert`]. However, given large quantities of nodes to move, it may be more efficient + /// to call [`self.remove_many`] followed by [`self.insert_many`]. + pub(crate) fn update_position_for( + node: Node, + new_weight: VoteWeight, + ) -> Option<(VoteWeight, VoteWeight)> { + node.is_misplaced(new_weight).then(move || { + let old_bag_upper = node.bag_upper; + + if !node.is_terminal() { + // this node is not a head or a tail, so we can just cut it out of the list. update + // and put the prev and next of this node, we do `node.put` inside `insert_note`. + node.excise(); + } else if let Some(mut bag) = Bag::::get(node.bag_upper) { + // this is a head or tail, so the bag must be updated. + bag.remove_node_unchecked(&node); + bag.put(); + } else { + crate::log!( + error, + "Node {:?} did not have a bag; ListBags is in an inconsistent state", + node.id, + ); + debug_assert!(false, "every node must have an extant bag associated with it"); + } + + // put the node into the appropriate new bag. + let new_bag_upper = notional_bag_for::(new_weight); + let mut bag = Bag::::get_or_make(new_bag_upper); + // prev, next, and bag_upper of the node are updated inside `insert_node`, also + // `node.put` is in there. + bag.insert_node_unchecked(node); + bag.put(); + + (old_bag_upper, new_bag_upper) + }) + } + + /// Sanity check the list. + /// + /// This should be called from the call-site, whenever one of the mutating apis (e.g. `insert`) + /// is being used, after all other staking data (such as counter) has been updated. It checks: + /// + /// * there are no duplicate ids, + /// * length of this list is in sync with `CounterForListNodes`, + /// * and sanity-checks all bags. This will cascade down all the checks and makes sure all bags + /// are checked per *any* update to `List`. + #[cfg(feature = "std")] + pub(crate) fn sanity_check() -> Result<(), &'static str> { + use frame_support::ensure; + let mut seen_in_list = BTreeSet::new(); + ensure!( + Self::iter().map(|node| node.id).all(|id| seen_in_list.insert(id)), + "duplicate identified", + ); + + let iter_count = Self::iter().count() as u32; + let stored_count = crate::CounterForListNodes::::get(); + let nodes_count = crate::ListNodes::::iter().count() as u32; + ensure!(iter_count == stored_count, "iter_count != stored_count"); + ensure!(stored_count == nodes_count, "stored_count != nodes_count"); + + crate::log!(debug, "count of nodes: {}", stored_count); + + let active_bags = { + let thresholds = T::BagThresholds::get().iter().copied(); + let thresholds: Vec = if thresholds.clone().last() == Some(VoteWeight::MAX) { + // in the event that they included it, we don't need to make any changes + // Box::new(thresholds.collect() + thresholds.collect() + } else { + // otherwise, insert it here. + thresholds.chain(iter::once(VoteWeight::MAX)).collect() + }; + thresholds.into_iter().filter_map(|t| Bag::::get(t)) + }; + + let _ = active_bags.clone().map(|b| b.sanity_check()).collect::>()?; + + let nodes_in_bags_count = + active_bags.clone().fold(0u32, |acc, cur| acc + cur.iter().count() as u32); + ensure!(nodes_count == nodes_in_bags_count, "stored_count != nodes_in_bags_count"); + + crate::log!(debug, "count of active bags {}", active_bags.count()); + + // check that all nodes are sane. We check the `ListNodes` storage item directly in case we + // have some "stale" nodes that are not in a bag. + for (_id, node) in crate::ListNodes::::iter() { + node.sanity_check()? + } + + Ok(()) + } + + #[cfg(not(feature = "std"))] + pub(crate) fn sanity_check() -> Result<(), &'static str> { + Ok(()) + } + + /// Returns the nodes of all non-empty bags. For testing and benchmarks. + #[cfg(any(feature = "std", feature = "runtime-benchmarks"))] + #[allow(dead_code)] + pub(crate) fn get_bags() -> Vec<(VoteWeight, Vec)> { + use frame_support::traits::Get as _; + + let thresholds = T::BagThresholds::get(); + let iter = thresholds.iter().copied(); + let iter: Box> = if thresholds.last() == Some(&VoteWeight::MAX) { + // in the event that they included it, we can just pass the iterator through unchanged. + Box::new(iter) + } else { + // otherwise, insert it here. + Box::new(iter.chain(sp_std::iter::once(VoteWeight::MAX))) + }; + + iter.filter_map(|t| { + Bag::::get(t).map(|bag| (t, bag.iter().map(|n| n.id().clone()).collect::>())) + }) + .collect::>() + } +} + +/// A Bag is a doubly-linked list of ids, where each id is mapped to a [`ListNode`]. +/// +/// Note that we maintain both head and tail pointers. While it would be possible to get away with +/// maintaining only a head pointer and cons-ing elements onto the front of the list, it's more +/// desirable to ensure that there is some element of first-come, first-serve to the list's +/// iteration so that there's no incentive to churn ids positioning to improve the chances of +/// appearing within the ids set. +#[derive(DefaultNoBound, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +#[cfg_attr(feature = "std", derive(frame_support::DebugNoBound, Clone, PartialEq))] +pub struct Bag { + head: Option, + tail: Option, + + #[codec(skip)] + bag_upper: VoteWeight, +} + +impl Bag { + #[cfg(test)] + pub(crate) fn new( + head: Option, + tail: Option, + bag_upper: VoteWeight, + ) -> Self { + Self { head, tail, bag_upper } + } + + /// Get a bag by its upper vote weight. + pub(crate) fn get(bag_upper: VoteWeight) -> Option> { + crate::ListBags::::try_get(bag_upper).ok().map(|mut bag| { + bag.bag_upper = bag_upper; + bag + }) + } + + /// Get a bag by its upper vote weight or make it, appropriately initialized. Does not check if + /// if `bag_upper` is a valid threshold. + fn get_or_make(bag_upper: VoteWeight) -> Bag { + Self::get(bag_upper).unwrap_or(Bag { bag_upper, ..Default::default() }) + } + + /// `True` if self is empty. + fn is_empty(&self) -> bool { + self.head.is_none() && self.tail.is_none() + } + + /// Put the bag back into storage. + fn put(self) { + if self.is_empty() { + crate::ListBags::::remove(self.bag_upper); + } else { + crate::ListBags::::insert(self.bag_upper, self); + } + } + + /// Get the head node in this bag. + fn head(&self) -> Option> { + self.head.as_ref().and_then(|id| Node::get(id)) + } + + /// Get the tail node in this bag. + fn tail(&self) -> Option> { + self.tail.as_ref().and_then(|id| Node::get(id)) + } + + /// Iterate over the nodes in this bag. + pub(crate) fn iter(&self) -> impl Iterator> { + sp_std::iter::successors(self.head(), |prev| prev.next()) + } + + /// Insert a new id into this bag. + /// + /// This is private on purpose because it's naive: it doesn't check whether this is the + /// appropriate bag for this id at all. Generally, use [`List::insert`] instead. + /// + /// Storage note: this modifies storage, but only for the nodes. You still need to call + /// `self.put()` after use. + fn insert_unchecked(&mut self, id: T::AccountId) { + // insert_node will overwrite `prev`, `next` and `bag_upper` to the proper values. As long + // as this bag is the correct one, we're good. All calls to this must come after getting the + // correct [`notional_bag_for`]. + self.insert_node_unchecked(Node:: { id, prev: None, next: None, bag_upper: 0 }); + } + + /// Insert a node into this bag. + /// + /// This is private on purpose because it's naive; it doesn't check whether this is the + /// appropriate bag for this node at all. Generally, use [`List::insert`] instead. + /// + /// Storage note: this modifies storage, but only for the node. You still need to call + /// `self.put()` after use. + fn insert_node_unchecked(&mut self, mut node: Node) { + if let Some(tail) = &self.tail { + if *tail == node.id { + // this should never happen, but this check prevents one path to a worst case + // infinite loop. + debug_assert!(false, "system logic error: inserting a node who has the id of tail"); + crate::log!(warn, "system logic error: inserting a node who has the id of tail"); + return + }; + } + + // re-set the `bag_upper`. Regardless of whatever the node had previously, now it is going + // to be `self.bag_upper`. + node.bag_upper = self.bag_upper; + + let id = node.id.clone(); + // update this node now, treating it as the new tail. + node.prev = self.tail.clone(); + node.next = None; + node.put(); + + // update the previous tail. + if let Some(mut old_tail) = self.tail() { + old_tail.next = Some(id.clone()); + old_tail.put(); + } + self.tail = Some(id.clone()); + + // ensure head exist. This is only set when the length of the bag is just 1, i.e. if this is + // the first insertion into the bag. In this case, both head and tail should point to the + // same node. + if self.head.is_none() { + self.head = Some(id.clone()); + debug_assert!(self.iter().count() == 1); + } + } + + /// Remove a node from this bag. + /// + /// This is private on purpose because it doesn't check whether this bag contains the node in + /// the first place. Generally, use [`List::remove`] instead, similar to `insert_unchecked`. + /// + /// Storage note: this modifies storage, but only for adjacent nodes. You still need to call + /// `self.put()` and `ListNodes::remove(id)` to update storage for the bag and `node`. + fn remove_node_unchecked(&mut self, node: &Node) { + // reassign neighboring nodes. + node.excise(); + + // clear the bag head/tail pointers as necessary. + if self.tail.as_ref() == Some(&node.id) { + self.tail = node.prev.clone(); + } + if self.head.as_ref() == Some(&node.id) { + self.head = node.next.clone(); + } + } + + /// Sanity check this bag. + /// + /// Should be called by the call-site, after any mutating operation on a bag. The call site of + /// this struct is always `List`. + /// + /// * Ensures head has no prev. + /// * Ensures tail has no next. + /// * Ensures there are no loops, traversal from head to tail is correct. + #[cfg(feature = "std")] + fn sanity_check(&self) -> Result<(), &'static str> { + frame_support::ensure!( + self.head() + .map(|head| head.prev().is_none()) + // if there is no head, then there must not be a tail, meaning that the bag is + // empty. + .unwrap_or_else(|| self.tail.is_none()), + "head has a prev" + ); + + frame_support::ensure!( + self.tail() + .map(|tail| tail.next().is_none()) + // if there is no tail, then there must not be a head, meaning that the bag is + // empty. + .unwrap_or_else(|| self.head.is_none()), + "tail has a next" + ); + + let mut seen_in_bag = BTreeSet::new(); + frame_support::ensure!( + self.iter() + .map(|node| node.id) + // each voter is only seen once, thus there is no cycle within a bag + .all(|voter| seen_in_bag.insert(voter)), + "duplicate found in bag" + ); + + Ok(()) + } + + #[cfg(not(feature = "std"))] + fn sanity_check(&self) -> Result<(), &'static str> { + Ok(()) + } + + /// Iterate over the nodes in this bag (public for tests). + #[cfg(feature = "std")] + #[allow(dead_code)] + pub fn std_iter(&self) -> impl Iterator> { + sp_std::iter::successors(self.head(), |prev| prev.next()) + } + + /// Check if the bag contains a node with `id`. + #[cfg(feature = "std")] + fn contains(&self, id: &T::AccountId) -> bool { + self.iter().find(|n| n.id() == id).is_some() + } +} + +/// A Node is the fundamental element comprising the doubly-linked list described by `Bag`. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +#[cfg_attr(feature = "std", derive(frame_support::DebugNoBound, Clone, PartialEq))] +pub struct Node { + id: T::AccountId, + prev: Option, + next: Option, + bag_upper: VoteWeight, +} + +impl Node { + /// Get a node by id. + pub(crate) fn get(id: &T::AccountId) -> Option> { + crate::ListNodes::::try_get(id).ok() + } + + /// Put the node back into storage. + fn put(self) { + crate::ListNodes::::insert(self.id.clone(), self); + } + + /// Update neighboring nodes to point to reach other. + /// + /// Only updates storage for adjacent nodes, but not `self`; so the user may need to call + /// `self.put`. + fn excise(&self) { + // Update previous node. + if let Some(mut prev) = self.prev() { + prev.next = self.next.clone(); + prev.put(); + } + // Update next self. + if let Some(mut next) = self.next() { + next.prev = self.prev.clone(); + next.put(); + } + } + + /// This is a naive function that removes a node from the `ListNodes` storage item. + /// + /// It is naive because it does not check if the node has first been removed from its bag. + fn remove_from_storage_unchecked(&self) { + crate::ListNodes::::remove(&self.id) + } + + /// Get the previous node in the bag. + fn prev(&self) -> Option> { + self.prev.as_ref().and_then(|id| Node::get(id)) + } + + /// Get the next node in the bag. + fn next(&self) -> Option> { + self.next.as_ref().and_then(|id| Node::get(id)) + } + + /// `true` when this voter is in the wrong bag. + pub(crate) fn is_misplaced(&self, current_weight: VoteWeight) -> bool { + notional_bag_for::(current_weight) != self.bag_upper + } + + /// `true` when this voter is a bag head or tail. + fn is_terminal(&self) -> bool { + self.prev.is_none() || self.next.is_none() + } + + /// Get the underlying voter. + pub(crate) fn id(&self) -> &T::AccountId { + &self.id + } + + /// Get the underlying voter (public fo tests). + #[cfg(feature = "std")] + #[allow(dead_code)] + pub fn std_id(&self) -> &T::AccountId { + &self.id + } + + /// The bag this nodes belongs to (public for benchmarks). + #[cfg(feature = "runtime-benchmarks")] + #[allow(dead_code)] + pub fn bag_upper(&self) -> VoteWeight { + self.bag_upper + } + + #[cfg(feature = "std")] + fn sanity_check(&self) -> Result<(), &'static str> { + let expected_bag = Bag::::get(self.bag_upper).ok_or("bag not found for node")?; + + let id = self.id(); + + frame_support::ensure!( + expected_bag.contains(id), + "node does not exist in the expected bag" + ); + + frame_support::ensure!( + !self.is_terminal() || + expected_bag.head.as_ref() == Some(id) || + expected_bag.tail.as_ref() == Some(id), + "a terminal node is neither its bag head or tail" + ); + + Ok(()) + } +} diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs new file mode 100644 index 0000000000000..e2730cbf4e33d --- /dev/null +++ b/frame/bags-list/src/list/tests.rs @@ -0,0 +1,735 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate::{ + mock::{test_utils::*, *}, + CounterForListNodes, ListBags, ListNodes, +}; +use frame_election_provider_support::SortedListProvider; +use frame_support::{assert_ok, assert_storage_noop}; + +#[test] +fn basic_setup_works() { + ExtBuilder::default().build_and_execute(|| { + // syntactic sugar to create a raw node + let node = |id, prev, next, bag_upper| Node:: { id, prev, next, bag_upper }; + + assert_eq!(CounterForListNodes::::get(), 4); + assert_eq!(ListNodes::::iter().count(), 4); + assert_eq!(ListBags::::iter().count(), 2); + + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + // the state of the bags is as expected + assert_eq!( + ListBags::::get(10).unwrap(), + Bag:: { head: Some(1), tail: Some(1), bag_upper: 0 } + ); + assert_eq!( + ListBags::::get(1_000).unwrap(), + Bag:: { head: Some(2), tail: Some(4), bag_upper: 0 } + ); + + assert_eq!(ListNodes::::get(2).unwrap(), node(2, None, Some(3), 1_000)); + assert_eq!(ListNodes::::get(3).unwrap(), node(3, Some(2), Some(4), 1_000)); + assert_eq!(ListNodes::::get(4).unwrap(), node(4, Some(3), None, 1_000)); + assert_eq!(ListNodes::::get(1).unwrap(), node(1, None, None, 10)); + + // non-existent id does not have a storage footprint + assert_eq!(ListNodes::::get(42), None); + + // iteration of the bags would yield: + assert_eq!( + List::::iter().map(|n| *n.id()).collect::>(), + vec![2, 3, 4, 1], + // ^^ note the order of insertion in genesis! + ); + }); +} + +#[test] +fn notional_bag_for_works() { + // under a threshold gives the next threshold. + assert_eq!(notional_bag_for::(0), 10); + assert_eq!(notional_bag_for::(9), 10); + + // at a threshold gives that threshold. + assert_eq!(notional_bag_for::(10), 10); + + // above the threshold, gives the next threshold. + assert_eq!(notional_bag_for::(11), 20); + + let max_explicit_threshold = *::BagThresholds::get().last().unwrap(); + assert_eq!(max_explicit_threshold, 10_000); + + // if the max explicit threshold is less than VoteWeight::MAX, + assert!(VoteWeight::MAX > max_explicit_threshold); + + // then anything above it will belong to the VoteWeight::MAX bag. + assert_eq!(notional_bag_for::(max_explicit_threshold), max_explicit_threshold); + assert_eq!(notional_bag_for::(max_explicit_threshold + 1), VoteWeight::MAX); +} + +#[test] +fn remove_last_node_in_bags_cleans_bag() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + // bump 1 to a bigger bag + List::::remove(&1); + assert_ok!(List::::insert(1, 10_000)); + + // then the bag with bound 10 is wiped from storage. + assert_eq!(List::::get_bags(), vec![(1_000, vec![2, 3, 4]), (10_000, vec![1])]); + + // and can be recreated again as needed. + assert_ok!(List::::insert(77, 10)); + assert_eq!( + List::::get_bags(), + vec![(10, vec![77]), (1_000, vec![2, 3, 4]), (10_000, vec![1])] + ); + }); +} + +#[test] +fn migrate_works() { + ExtBuilder::default() + .add_ids(vec![(710, 15), (711, 16), (712, 2_000)]) + .build_and_execute(|| { + // given + assert_eq!( + List::::get_bags(), + vec![ + (10, vec![1]), + (20, vec![710, 711]), + (1_000, vec![2, 3, 4]), + (2_000, vec![712]) + ] + ); + let old_thresholds = ::BagThresholds::get(); + assert_eq!(old_thresholds, vec![10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]); + + // when the new thresholds adds `15` and removes `2_000` + const NEW_THRESHOLDS: &'static [VoteWeight] = + &[10, 15, 20, 30, 40, 50, 60, 1_000, 10_000]; + BagThresholds::set(NEW_THRESHOLDS); + // and we call + List::::migrate(old_thresholds); + + // then + assert_eq!( + List::::get_bags(), + vec![ + (10, vec![1]), + (15, vec![710]), // nodes in range 11 ..= 15 move from bag 20 to bag 15 + (20, vec![711]), + (1_000, vec![2, 3, 4]), + // nodes in range 1_001 ..= 2_000 move from bag 2_000 to bag 10_000 + (10_000, vec![712]), + ] + ); + }); +} + +mod list { + use super::*; + + #[test] + fn iteration_is_semi_sorted() { + ExtBuilder::default() + .add_ids(vec![(5, 2_000), (6, 2_000)]) + .build_and_execute(|| { + // given + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![5, 6])] + ); + assert_eq!( + get_list_as_ids(), + vec![ + 5, 6, // best bag + 2, 3, 4, // middle bag + 1, // last bag. + ] + ); + + // when adding an id that has a higher weight than pre-existing ids in the bag + assert_ok!(List::::insert(7, 10)); + + // then + assert_eq!( + get_list_as_ids(), + vec![ + 5, 6, // best bag + 2, 3, 4, // middle bag + 1, 7, // last bag; new id is last. + ] + ); + }) + } + + /// we can `take` x ids, even if that quantity ends midway through a list. + #[test] + fn take_works() { + ExtBuilder::default() + .add_ids(vec![(5, 2_000), (6, 2_000)]) + .build_and_execute(|| { + // given + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![5, 6])] + ); + + // when + let iteration = + List::::iter().map(|node| *node.id()).take(4).collect::>(); + + // then + assert_eq!( + iteration, + vec![ + 5, 6, // best bag, fully iterated + 2, 3, // middle bag, partially iterated + ] + ); + }) + } + + #[test] + fn insert_works() { + ExtBuilder::default().build_and_execute(|| { + // when inserting into an existing bag + assert_ok!(List::::insert(5, 1_000)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5])]); + assert_eq!(get_list_as_ids(), vec![2, 3, 4, 5, 1]); + + // when inserting into a non-existent bag + assert_ok!(List::::insert(6, 1_001)); + + // then + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5]), (2_000, vec![6])] + ); + assert_eq!(get_list_as_ids(), vec![6, 2, 3, 4, 5, 1]); + }); + } + + #[test] + fn insert_errors_with_duplicate_id() { + ExtBuilder::default().build_and_execute(|| { + // given + assert!(get_list_as_ids().contains(&3)); + + // then + assert_storage_noop!(assert_eq!( + List::::insert(3, 20).unwrap_err(), + Error::Duplicate + )); + }); + } + + #[test] + fn remove_works() { + use crate::{CounterForListNodes, ListBags, ListNodes}; + let ensure_left = |id, counter| { + assert!(!ListNodes::::contains_key(id)); + assert_eq!(CounterForListNodes::::get(), counter); + assert_eq!(ListNodes::::iter().count() as u32, counter); + }; + + ExtBuilder::default().build_and_execute(|| { + // removing a non-existent id is a noop + assert!(!ListNodes::::contains_key(42)); + assert_storage_noop!(List::::remove(&42)); + + // when removing a node from a bag with multiple nodes: + List::::remove(&2); + + // then + assert_eq!(get_list_as_ids(), vec![3, 4, 1]); + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 4])]); + ensure_left(2, 3); + + // when removing a node from a bag with only one node: + List::::remove(&1); + + // then + assert_eq!(get_list_as_ids(), vec![3, 4]); + assert_eq!(List::::get_bags(), vec![(1_000, vec![3, 4])]); + ensure_left(1, 2); + // bag 10 is removed + assert!(!ListBags::::contains_key(10)); + + // remove remaining ids to make sure storage cleans up as expected + List::::remove(&3); + ensure_left(3, 1); + assert_eq!(get_list_as_ids(), vec![4]); + + List::::remove(&4); + ensure_left(4, 0); + assert_eq!(get_list_as_ids(), Vec::::new()); + + // bags are deleted via removals + assert_eq!(ListBags::::iter().count(), 0); + }); + } + + #[test] + fn remove_many_is_noop_with_non_existent_ids() { + ExtBuilder::default().build_and_execute(|| { + let non_existent_ids = vec![&42, &666, &13]; + + // when account ids don' exist in the list + assert!(non_existent_ids.iter().all(|id| !BagsList::contains(id))); + + // then removing them is a noop + assert_storage_noop!(List::::remove_many(non_existent_ids)); + }); + } + + #[test] + fn update_position_for_works() { + ExtBuilder::default().build_and_execute(|| { + // given a correctly placed account 1 at bag 10. + let node = Node::::get(&1).unwrap(); + assert!(!node.is_misplaced(10)); + + // .. it is invalid with weight 20 + assert!(node.is_misplaced(20)); + + // move it to bag 20. + assert_eq!(List::::update_position_for(node, 20), Some((10, 20))); + + assert_eq!(List::::get_bags(), vec![(20, vec![1]), (1_000, vec![2, 3, 4])]); + + // get the new updated node; try and update the position with no change in weight. + let node = Node::::get(&1).unwrap(); + assert_storage_noop!(assert_eq!( + List::::update_position_for(node.clone(), 20), + None + )); + + // then move it to bag 1_000 by giving it weight 500. + assert_eq!(List::::update_position_for(node.clone(), 500), Some((20, 1_000))); + assert_eq!(List::::get_bags(), vec![(1_000, vec![2, 3, 4, 1])]); + + // moving within that bag again is a noop + let node = Node::::get(&1).unwrap(); + assert_storage_noop!(assert_eq!( + List::::update_position_for(node.clone(), 750), + None, + )); + assert_storage_noop!(assert_eq!( + List::::update_position_for(node, 1_000), + None, + )); + }); + } + + #[test] + fn sanity_check_works() { + ExtBuilder::default().build_and_execute_no_post_check(|| { + assert_ok!(List::::sanity_check()); + }); + + // make sure there are no duplicates. + ExtBuilder::default().build_and_execute_no_post_check(|| { + Bag::::get(10).unwrap().insert_unchecked(2); + assert_eq!(List::::sanity_check(), Err("duplicate identified")); + }); + + // ensure count is in sync with `CounterForListNodes`. + ExtBuilder::default().build_and_execute_no_post_check(|| { + crate::CounterForListNodes::::mutate(|counter| *counter += 1); + assert_eq!(crate::CounterForListNodes::::get(), 5); + assert_eq!(List::::sanity_check(), Err("iter_count != stored_count")); + }); + } + + #[test] + fn contains_works() { + ExtBuilder::default().build_and_execute(|| { + assert!(GENESIS_IDS.iter().all(|(id, _)| List::::contains(id))); + + let non_existent_ids = vec![&42, &666, &13]; + assert!(non_existent_ids.iter().all(|id| !List::::contains(id))); + }) + } +} + +mod bags { + use super::*; + + #[test] + fn get_works() { + ExtBuilder::default().build_and_execute(|| { + let check_bag = |bag_upper, head, tail, ids| { + let bag = Bag::::get(bag_upper).unwrap(); + let bag_ids = bag.iter().map(|n| *n.id()).collect::>(); + + assert_eq!(bag, Bag:: { head, tail, bag_upper }); + assert_eq!(bag_ids, ids); + }; + + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + // we can fetch them + check_bag(10, Some(1), Some(1), vec![1]); + check_bag(1_000, Some(2), Some(4), vec![2, 3, 4]); + + // and all other bag thresholds don't get bags. + ::BagThresholds::get() + .iter() + .chain(iter::once(&VoteWeight::MAX)) + .filter(|bag_upper| !vec![10, 1_000].contains(bag_upper)) + .for_each(|bag_upper| { + assert_storage_noop!(assert_eq!(Bag::::get(*bag_upper), None)); + assert!(!ListBags::::contains_key(*bag_upper)); + }); + + // when we make a pre-existing bag empty + List::::remove(&1); + + // then + assert_eq!(Bag::::get(10), None) + }); + } + + #[test] + fn insert_node_sets_proper_bag() { + ExtBuilder::default().build_and_execute_no_post_check(|| { + let node = |id, bag_upper| Node:: { id, prev: None, next: None, bag_upper }; + + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + let mut bag_10 = Bag::::get(10).unwrap(); + bag_10.insert_node_unchecked(node(42, 5)); + + assert_eq!( + ListNodes::::get(&42).unwrap(), + Node { bag_upper: 10, prev: Some(1), next: None, id: 42 } + ); + }); + } + + #[test] + fn insert_node_happy_paths_works() { + ExtBuilder::default().build_and_execute_no_post_check(|| { + let node = |id, bag_upper| Node:: { id, prev: None, next: None, bag_upper }; + + // when inserting into a bag with 1 node + let mut bag_10 = Bag::::get(10).unwrap(); + bag_10.insert_node_unchecked(node(42, bag_10.bag_upper)); + // then + assert_eq!(bag_as_ids(&bag_10), vec![1, 42]); + + // when inserting into a bag with 3 nodes + let mut bag_1000 = Bag::::get(1_000).unwrap(); + bag_1000.insert_node_unchecked(node(52, bag_1000.bag_upper)); + // then + assert_eq!(bag_as_ids(&bag_1000), vec![2, 3, 4, 52]); + + // when inserting into a new bag + let mut bag_20 = Bag::::get_or_make(20); + bag_20.insert_node_unchecked(node(62, bag_20.bag_upper)); + // then + assert_eq!(bag_as_ids(&bag_20), vec![62]); + + // when inserting a node pointing to the accounts not in the bag + let node_61 = + Node:: { id: 61, prev: Some(21), next: Some(101), bag_upper: 20 }; + bag_20.insert_node_unchecked(node_61); + // then ids are in order + assert_eq!(bag_as_ids(&bag_20), vec![62, 61]); + // and when the node is re-fetched all the info is correct + assert_eq!( + Node::::get(&61).unwrap(), + Node:: { id: 61, prev: Some(62), next: None, bag_upper: 20 } + ); + + // state of all bags is as expected + bag_20.put(); // need to put this newly created bag so its in the storage map + assert_eq!( + List::::get_bags(), + vec![(10, vec![1, 42]), (20, vec![62, 61]), (1_000, vec![2, 3, 4, 52])] + ); + }); + } + + // Document improper ways `insert_node` may be getting used. + #[test] + fn insert_node_bad_paths_documented() { + let node = |id, prev, next, bag_upper| Node:: { id, prev, next, bag_upper }; + ExtBuilder::default().build_and_execute_no_post_check(|| { + // when inserting a node with both prev & next pointing at an account in an incorrect + // bag. + let mut bag_1000 = Bag::::get(1_000).unwrap(); + bag_1000.insert_node_unchecked(node(42, Some(1), Some(1), 500)); + + // then the proper prev and next is set. + assert_eq!(bag_as_ids(&bag_1000), vec![2, 3, 4, 42]); + + // and when the node is re-fetched all the info is correct + assert_eq!( + Node::::get(&42).unwrap(), + node(42, Some(4), None, bag_1000.bag_upper) + ); + }); + + ExtBuilder::default().build_and_execute_no_post_check(|| { + // given 3 is in bag_1000 (and not a tail node) + let mut bag_1000 = Bag::::get(1_000).unwrap(); + assert_eq!(bag_as_ids(&bag_1000), vec![2, 3, 4]); + + // when inserting a node with duplicate id 3 + bag_1000.insert_node_unchecked(node(3, None, None, bag_1000.bag_upper)); + + // then all the nodes after the duplicate are lost (because it is set as the tail) + assert_eq!(bag_as_ids(&bag_1000), vec![2, 3]); + // also in the full iteration, 2 and 3 are from bag_1000 and 1 is from bag_10. + assert_eq!(get_list_as_ids(), vec![2, 3, 1]); + + // and the last accessible node has an **incorrect** prev pointer. + assert_eq!( + Node::::get(&3).unwrap(), + node(3, Some(4), None, bag_1000.bag_upper) + ); + }); + + ExtBuilder::default().build_and_execute_no_post_check(|| { + // when inserting a duplicate id of the head + let mut bag_1000 = Bag::::get(1_000).unwrap(); + assert_eq!(bag_as_ids(&bag_1000), vec![2, 3, 4]); + bag_1000.insert_node_unchecked(node(2, None, None, 0)); + + // then all nodes after the head are lost + assert_eq!(bag_as_ids(&bag_1000), vec![2]); + + // and the re-fetched node has bad pointers + assert_eq!( + Node::::get(&2).unwrap(), + node(2, Some(4), None, bag_1000.bag_upper) + ); + // ^^^ despite being the bags head, it has a prev + + assert_eq!(bag_1000, Bag { head: Some(2), tail: Some(2), bag_upper: 1_000 }) + }); + } + + // Panics in case of duplicate tail insert (which would result in an infinite loop). + #[test] + #[should_panic = "system logic error: inserting a node who has the id of tail"] + fn insert_node_duplicate_tail_panics_with_debug_assert() { + ExtBuilder::default().build_and_execute(|| { + let node = |id, prev, next, bag_upper| Node:: { id, prev, next, bag_upper }; + + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])],); + let mut bag_1000 = Bag::::get(1_000).unwrap(); + + // when inserting a duplicate id that is already the tail + assert_eq!(bag_1000.tail, Some(4)); + bag_1000.insert_node_unchecked(node(4, None, None, bag_1000.bag_upper)); // panics + }); + } + + #[test] + fn remove_node_happy_paths_works() { + ExtBuilder::default() + .add_ids(vec![ + (11, 10), + (12, 10), + (13, 1_000), + (14, 1_000), + (15, 2_000), + (16, 2_000), + (17, 2_000), + (18, 2_000), + (19, 2_000), + ]) + .build_and_execute_no_post_check(|| { + let mut bag_10 = Bag::::get(10).unwrap(); + let mut bag_1000 = Bag::::get(1_000).unwrap(); + let mut bag_2000 = Bag::::get(2_000).unwrap(); + + // given + assert_eq!(bag_as_ids(&bag_10), vec![1, 11, 12]); + assert_eq!(bag_as_ids(&bag_1000), vec![2, 3, 4, 13, 14]); + assert_eq!(bag_as_ids(&bag_2000), vec![15, 16, 17, 18, 19]); + + // when removing a node that is not pointing at the head or tail + let node_4 = Node::::get(&4).unwrap(); + let node_4_pre_remove = node_4.clone(); + bag_1000.remove_node_unchecked(&node_4); + + // then + assert_eq!(bag_as_ids(&bag_1000), vec![2, 3, 13, 14]); + assert_ok!(bag_1000.sanity_check()); + // and the node isn't mutated when its removed + assert_eq!(node_4, node_4_pre_remove); + + // when removing a head that is not pointing at the tail + let node_2 = Node::::get(&2).unwrap(); + bag_1000.remove_node_unchecked(&node_2); + + // then + assert_eq!(bag_as_ids(&bag_1000), vec![3, 13, 14]); + assert_ok!(bag_1000.sanity_check()); + + // when removing a tail that is not pointing at the head + let node_14 = Node::::get(&14).unwrap(); + bag_1000.remove_node_unchecked(&node_14); + + // then + assert_eq!(bag_as_ids(&bag_1000), vec![3, 13]); + assert_ok!(bag_1000.sanity_check()); + + // when removing a tail that is pointing at the head + let node_13 = Node::::get(&13).unwrap(); + bag_1000.remove_node_unchecked(&node_13); + + // then + assert_eq!(bag_as_ids(&bag_1000), vec![3]); + assert_ok!(bag_1000.sanity_check()); + + // when removing a node that is both the head & tail + let node_3 = Node::::get(&3).unwrap(); + bag_1000.remove_node_unchecked(&node_3); + bag_1000.put(); // put into storage so `get` returns the updated bag + + // then + assert_eq!(Bag::::get(1_000), None); + + // when removing a node that is pointing at both the head & tail + let node_11 = Node::::get(&11).unwrap(); + bag_10.remove_node_unchecked(&node_11); + + // then + assert_eq!(bag_as_ids(&bag_10), vec![1, 12]); + assert_ok!(bag_10.sanity_check()); + + // when removing a head that is pointing at the tail + let node_1 = Node::::get(&1).unwrap(); + bag_10.remove_node_unchecked(&node_1); + + // then + assert_eq!(bag_as_ids(&bag_10), vec![12]); + assert_ok!(bag_10.sanity_check()); + // and since we updated the bag's head/tail, we need to write this storage so we + // can correctly `get` it again in later checks + bag_10.put(); + + // when removing a node that is pointing at the head but not the tail + let node_16 = Node::::get(&16).unwrap(); + bag_2000.remove_node_unchecked(&node_16); + + // then + assert_eq!(bag_as_ids(&bag_2000), vec![15, 17, 18, 19]); + assert_ok!(bag_2000.sanity_check()); + + // when removing a node that is pointing at tail, but not head + let node_18 = Node::::get(&18).unwrap(); + bag_2000.remove_node_unchecked(&node_18); + + // then + assert_eq!(bag_as_ids(&bag_2000), vec![15, 17, 19]); + assert_ok!(bag_2000.sanity_check()); + + // finally, when reading from storage, the state of all bags is as expected + assert_eq!( + List::::get_bags(), + vec![(10, vec![12]), (2_000, vec![15, 17, 19])] + ); + }); + } + + #[test] + fn remove_node_bad_paths_documented() { + ExtBuilder::default().build_and_execute_no_post_check(|| { + let bad_upper_node_2 = Node:: { + id: 2, + prev: None, + next: Some(3), + bag_upper: 10, // should be 1_000 + }; + let mut bag_1000 = Bag::::get(1_000).unwrap(); + + // when removing a node that is in the bag but has the wrong upper + bag_1000.remove_node_unchecked(&bad_upper_node_2); + bag_1000.put(); + + // then the node is no longer in any bags + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 4])]); + // .. and the bag it was removed from + let bag_1000 = Bag::::get(1_000).unwrap(); + // is sane + assert_ok!(bag_1000.sanity_check()); + // and has the correct head and tail. + assert_eq!(bag_1000.head, Some(3)); + assert_eq!(bag_1000.tail, Some(4)); + }); + + // Removing a node that is in another bag, will mess up that other bag. + ExtBuilder::default().build_and_execute_no_post_check(|| { + // given a tail node is in bag 1_000 + let node_4 = Node::::get(&4).unwrap(); + + // when we remove it from bag 10 + let mut bag_10 = Bag::::get(10).unwrap(); + bag_10.remove_node_unchecked(&node_4); + bag_10.put(); + + // then bag remove was called on is ok, + let bag_10 = Bag::::get(10).unwrap(); + assert_eq!(bag_10.tail, Some(1)); + assert_eq!(bag_10.head, Some(1)); + + // but the bag that the node belonged to is in an invalid state + let bag_1000 = Bag::::get(1_000).unwrap(); + // because it still has the removed node as its tail. + assert_eq!(bag_1000.tail, Some(4)); + assert_eq!(bag_1000.head, Some(2)); + }); + } +} + +mod node { + use super::*; + + #[test] + fn is_misplaced_works() { + ExtBuilder::default().build_and_execute(|| { + let node = Node::::get(&1).unwrap(); + + // given + assert_eq!(node.bag_upper, 10); + + // then within bag 10 its not misplaced, + assert!(!node.is_misplaced(0)); + assert!(!node.is_misplaced(9)); + assert!(!node.is_misplaced(10)); + + // and out of bag 10 it is misplaced + assert!(node.is_misplaced(11)); + }); + } +} diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs new file mode 100644 index 0000000000000..a6ab35896b1e7 --- /dev/null +++ b/frame/bags-list/src/mock.rs @@ -0,0 +1,154 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Mock runtime for pallet-bags-lists tests. + +use super::*; +use crate::{self as bags_list}; +use frame_election_provider_support::VoteWeight; +use frame_support::parameter_types; + +pub type AccountId = u32; +pub type Balance = u32; + +parameter_types! { + pub static NextVoteWeight: VoteWeight = 0; +} + +pub struct StakingMock; +impl frame_election_provider_support::VoteWeightProvider for StakingMock { + fn vote_weight(id: &AccountId) -> VoteWeight { + match id { + 710 => 15, + 711 => 16, + 712 => 2_000, // special cases used for migrate test + _ => NextVoteWeight::get(), + } + } + #[cfg(any(feature = "runtime-benchmarks", test))] + fn set_vote_weight_of(_: &AccountId, weight: VoteWeight) { + // we don't really keep a mapping, just set weight for everyone. + NextVoteWeight::set(weight) + } +} + +impl frame_system::Config for Runtime { + type SS58Prefix = (); + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = Call; + type Hash = sp_core::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = sp_runtime::testing::Header; + type Event = Event; + type BlockHashCount = (); + type DbWeight = (); + type BlockLength = (); + type BlockWeights = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type OnSetCode = (); +} + +parameter_types! { + pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; +} + +impl bags_list::Config for Runtime { + type Event = Event; + type WeightInfo = (); + type BagThresholds = BagThresholds; + type VoteWeightProvider = StakingMock; +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Storage, Event, Config}, + BagsList: bags_list::{Pallet, Call, Storage, Event}, + } +); + +/// Default AccountIds and their weights. +pub(crate) const GENESIS_IDS: [(AccountId, VoteWeight); 4] = + [(1, 10), (2, 1_000), (3, 1_000), (4, 1_000)]; + +#[derive(Default)] +pub(crate) struct ExtBuilder { + ids: Vec<(AccountId, VoteWeight)>, +} + +impl ExtBuilder { + /// Add some AccountIds to insert into `List`. + pub(crate) fn add_ids(mut self, ids: Vec<(AccountId, VoteWeight)>) -> Self { + self.ids = ids; + self + } + + pub(crate) fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + let mut ext = sp_io::TestExternalities::from(storage); + ext.execute_with(|| { + for (id, weight) in GENESIS_IDS.iter().chain(self.ids.iter()) { + frame_support::assert_ok!(List::::insert(*id, *weight)); + } + }); + + ext + } + + pub(crate) fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(|| { + test(); + List::::sanity_check().expect("Sanity check post condition failed") + }) + } + + pub(crate) fn build_and_execute_no_post_check(self, test: impl FnOnce() -> ()) { + self.build().execute_with(test) + } +} + +pub(crate) mod test_utils { + use super::*; + use list::Bag; + + /// Returns the ordered ids within the given bag. + pub(crate) fn bag_as_ids(bag: &Bag) -> Vec { + bag.iter().map(|n| *n.id()).collect::>() + } + + /// Returns the ordered ids from the list. + pub(crate) fn get_list_as_ids() -> Vec { + List::::iter().map(|n| *n.id()).collect::>() + } +} diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs new file mode 100644 index 0000000000000..e94017730668b --- /dev/null +++ b/frame/bags-list/src/tests.rs @@ -0,0 +1,389 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_support::{assert_ok, assert_storage_noop, traits::IntegrityTest}; + +use super::*; +use frame_election_provider_support::SortedListProvider; +use list::Bag; +use mock::{test_utils::*, *}; + +mod pallet { + use super::*; + + #[test] + fn rebag_works() { + ExtBuilder::default().add_ids(vec![(42, 20)]).build_and_execute(|| { + // given + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (20, vec![42]), (1_000, vec![2, 3, 4])] + ); + + // when increasing vote weight to the level of non-existent bag + NextVoteWeight::set(2_000); + assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + + // then a new bag is created and the id moves into it + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![42])] + ); + + // when decreasing weight within the range of the current bag + NextVoteWeight::set(1001); + assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + + // then the id does not move + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![42])] + ); + + // when reducing weight to the level of a non-existent bag + NextVoteWeight::set(30); + assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + + // then a new bag is created and the id moves into it + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (30, vec![42]), (1_000, vec![2, 3, 4])] + ); + + // when increasing weight to the level of a pre-existing bag + NextVoteWeight::set(500); + assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + + // then the id moves into that bag + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4, 42])] + ); + }); + } + + // Rebagging the tail of a bag results in the old bag having a new tail and an overall correct + // state. + #[test] + fn rebag_tail_works() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + // when + NextVoteWeight::set(10); + assert_ok!(BagsList::rebag(Origin::signed(0), 4)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1, 4]), (1_000, vec![2, 3])]); + assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(2), Some(3), 1_000)); + + // when + assert_ok!(BagsList::rebag(Origin::signed(0), 3)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1, 4, 3]), (1_000, vec![2])]); + + assert_eq!(Bag::::get(10).unwrap(), Bag::new(Some(1), Some(3), 10)); + assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(2), Some(2), 1_000)); + assert_eq!(get_list_as_ids(), vec![2u32, 1, 4, 3]); + + // when + assert_ok!(BagsList::rebag(Origin::signed(0), 2)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1, 4, 3, 2])]); + assert_eq!(Bag::::get(1_000), None); + }); + } + + // Rebagging the head of a bag results in the old bag having a new head and an overall correct + // state. + #[test] + fn rebag_head_works() { + ExtBuilder::default().build_and_execute(|| { + // when + NextVoteWeight::set(10); + assert_ok!(BagsList::rebag(Origin::signed(0), 2)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1, 2]), (1_000, vec![3, 4])]); + assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(3), Some(4), 1_000)); + + // when + assert_ok!(BagsList::rebag(Origin::signed(0), 3)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1, 2, 3]), (1_000, vec![4])]); + assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(4), Some(4), 1_000)); + + // when + assert_ok!(BagsList::rebag(Origin::signed(0), 4)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1, 2, 3, 4])]); + assert_eq!(Bag::::get(1_000), None); + }); + } + + #[test] + fn wrong_rebag_is_noop() { + ExtBuilder::default().build_and_execute(|| { + let node_3 = list::Node::::get(&3).unwrap(); + // when account 3 is _not_ misplaced with weight 500 + NextVoteWeight::set(500); + assert!(!node_3.is_misplaced(500)); + + // then calling rebag on account 3 with weight 500 is a noop + assert_storage_noop!(assert_eq!(BagsList::rebag(Origin::signed(0), 3), Ok(()))); + + // when account 42 is not in the list + assert!(!BagsList::contains(&42)); + + // then rebag-ing account 42 is a noop + assert_storage_noop!(assert_eq!(BagsList::rebag(Origin::signed(0), 42), Ok(()))); + }); + } + + #[test] + #[should_panic = "thresholds must strictly increase, and have no duplicates"] + fn duplicate_in_bags_threshold_panics() { + const DUPE_THRESH: &[VoteWeight; 4] = &[10, 20, 30, 30]; + BagThresholds::set(DUPE_THRESH); + BagsList::integrity_test(); + } + + #[test] + #[should_panic = "thresholds must strictly increase, and have no duplicates"] + fn decreasing_in_bags_threshold_panics() { + const DECREASING_THRESH: &[VoteWeight; 4] = &[10, 30, 20, 40]; + BagThresholds::set(DECREASING_THRESH); + BagsList::integrity_test(); + } + + #[test] + fn empty_threshold_works() { + BagThresholds::set(Default::default()); // which is the same as passing `()` to `Get<_>`. + + ExtBuilder::default().build_and_execute(|| { + // everyone in the same bag. + assert_eq!(List::::get_bags(), vec![(VoteWeight::MAX, vec![1, 2, 3, 4])]); + + // any insertion goes there as well. + assert_ok!(List::::insert(5, 999)); + assert_ok!(List::::insert(6, 0)); + assert_eq!( + List::::get_bags(), + vec![(VoteWeight::MAX, vec![1, 2, 3, 4, 5, 6])] + ); + + // any rebag is noop. + assert_storage_noop!(assert!(BagsList::rebag(Origin::signed(0), 1).is_ok())); + assert_storage_noop!(assert!(BagsList::rebag(Origin::signed(0), 10).is_ok())); + }) + } +} + +mod sorted_list_provider { + use super::*; + + #[test] + fn iter_works() { + ExtBuilder::default().build_and_execute(|| { + let expected = vec![2, 3, 4, 1]; + for (i, id) in BagsList::iter().enumerate() { + assert_eq!(id, expected[i]) + } + }); + } + + #[test] + fn count_works() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(BagsList::count(), 4); + + // when inserting + assert_ok!(BagsList::on_insert(201, 0)); + // then the count goes up + assert_eq!(BagsList::count(), 5); + + // when removing + BagsList::on_remove(&201); + // then the count goes down + assert_eq!(BagsList::count(), 4); + + // when updating + BagsList::on_update(&201, VoteWeight::MAX); + // then the count stays the same + assert_eq!(BagsList::count(), 4); + }); + } + + #[test] + fn on_insert_works() { + ExtBuilder::default().build_and_execute(|| { + // when + assert_ok!(BagsList::on_insert(6, 1_000)); + + // then the bags + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 6])]); + // and list correctly include the new id, + assert_eq!(BagsList::iter().collect::>(), vec![2, 3, 4, 6, 1]); + // and the count is incremented. + assert_eq!(BagsList::count(), 5); + + // when + assert_ok!(BagsList::on_insert(7, 1_001)); + + // then the bags + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4, 6]), (2_000, vec![7])] + ); + // and list correctly include the new id, + assert_eq!(BagsList::iter().collect::>(), vec![7, 2, 3, 4, 6, 1]); + // and the count is incremented. + assert_eq!(BagsList::count(), 6); + }) + } + + #[test] + fn on_insert_errors_with_duplicate_id() { + ExtBuilder::default().build_and_execute(|| { + // given + assert!(get_list_as_ids().contains(&3)); + + // then + assert_storage_noop!(assert_eq!( + BagsList::on_insert(3, 20).unwrap_err(), + Error::Duplicate + )); + }); + } + + #[test] + fn on_update_works() { + ExtBuilder::default().add_ids(vec![(42, 20)]).build_and_execute(|| { + // given + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (20, vec![42]), (1_000, vec![2, 3, 4])] + ); + assert_eq!(BagsList::count(), 5); + + // when increasing weight to the level of non-existent bag + BagsList::on_update(&42, 2_000); + + // then the bag is created with the id in it, + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2000, vec![42])] + ); + // and the id position is updated in the list. + assert_eq!(BagsList::iter().collect::>(), vec![42, 2, 3, 4, 1]); + + // when decreasing weight within the range of the current bag + BagsList::on_update(&42, 1_001); + + // then the id does not change bags, + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2000, vec![42])] + ); + // or change position in the list. + assert_eq!(BagsList::iter().collect::>(), vec![42, 2, 3, 4, 1]); + + // when increasing weight to the level of a non-existent bag with the max threshold + BagsList::on_update(&42, VoteWeight::MAX); + + // the the new bag is created with the id in it, + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (VoteWeight::MAX, vec![42])] + ); + // and the id position is updated in the list. + assert_eq!(BagsList::iter().collect::>(), vec![42, 2, 3, 4, 1]); + + // when decreasing the weight to a pre-existing bag + BagsList::on_update(&42, 1_000); + + // then id is moved to the correct bag (as the last member), + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4, 42])] + ); + // and the id position is updated in the list. + assert_eq!(BagsList::iter().collect::>(), vec![2, 3, 4, 42, 1]); + + // since we have only called on_update, the `count` has not changed. + assert_eq!(BagsList::count(), 5); + }); + } + + #[test] + fn on_remove_works() { + let ensure_left = |id, counter| { + assert!(!ListNodes::::contains_key(id)); + assert_eq!(BagsList::count(), counter); + assert_eq!(CounterForListNodes::::get(), counter); + assert_eq!(ListNodes::::iter().count() as u32, counter); + }; + + ExtBuilder::default().build_and_execute(|| { + // it is a noop removing a non-existent id + assert!(!ListNodes::::contains_key(42)); + assert_storage_noop!(BagsList::on_remove(&42)); + + // when removing a node from a bag with multiple nodes + BagsList::on_remove(&2); + + // then + assert_eq!(get_list_as_ids(), vec![3, 4, 1]); + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 4])]); + ensure_left(2, 3); + + // when removing a node from a bag with only one node + BagsList::on_remove(&1); + + // then + assert_eq!(get_list_as_ids(), vec![3, 4]); + assert_eq!(List::::get_bags(), vec![(1_000, vec![3, 4])]); + ensure_left(1, 2); + + // when removing all remaining ids + BagsList::on_remove(&4); + assert_eq!(get_list_as_ids(), vec![3]); + ensure_left(4, 1); + BagsList::on_remove(&3); + + // then the storage is completely cleaned up + assert_eq!(get_list_as_ids(), Vec::::new()); + ensure_left(3, 0); + }); + } + + #[test] + fn contains_works() { + ExtBuilder::default().build_and_execute(|| { + assert!(GENESIS_IDS.iter().all(|(id, _)| BagsList::contains(id))); + + let non_existent_ids = vec![&42, &666, &13]; + assert!(non_existent_ids.iter().all(|id| !BagsList::contains(id))); + }) + } +} diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs new file mode 100644 index 0000000000000..95d3dfa6eb989 --- /dev/null +++ b/frame/bags-list/src/weights.rs @@ -0,0 +1,95 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_bags_list +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-09-15, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// target/release/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_bags_list +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/bags-list/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_bags_list. +pub trait WeightInfo { + fn rebag_non_terminal() -> Weight; + fn rebag_terminal() -> Weight; +} + +/// Weights for pallet_bags_list using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:0) + // Storage: BagsList ListNodes (r:4 w:4) + // Storage: BagsList ListBags (r:1 w:1) + fn rebag_non_terminal() -> Weight { + (74_175_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:0) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: BagsList ListBags (r:2 w:2) + fn rebag_terminal() -> Weight { + (73_305_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:0) + // Storage: BagsList ListNodes (r:4 w:4) + // Storage: BagsList ListBags (r:1 w:1) + fn rebag_non_terminal() -> Weight { + (74_175_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:0) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: BagsList ListBags (r:2 w:2) + fn rebag_terminal() -> Weight { + (73_305_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } +} diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 269057b55b094..e83c49433e2bb 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -620,6 +620,15 @@ pub mod pallet { #[pallet::constant] type SignedDepositWeight: Get>; + /// The maximum number of voters to put in the snapshot. At the moment, snapshots are only + /// over a single block, but once multi-block elections are introduced they will take place + /// over multiple blocks. + /// + /// Also, note the data type: If the voters are represented by a `u32` in `type + /// CompactSolution`, the same `u32` is used here to ensure bounds are respected. + #[pallet::constant] + type VoterSnapshotPerBlock: Get>; + /// Handler for the slashed deposits. type SlashHandler: OnUnbalanced>; @@ -1274,7 +1283,8 @@ impl Pallet { fn create_snapshot_external( ) -> Result<(Vec, Vec>, u32), ElectionError> { let target_limit = >::max_value().saturated_into::(); - let voter_limit = >::max_value().saturated_into::(); + // for now we have just a single block snapshot. + let voter_limit = T::VoterSnapshotPerBlock::get().saturated_into::(); let targets = T::DataProvider::targets(Some(target_limit)).map_err(ElectionError::DataProvider)?; @@ -1933,7 +1943,8 @@ mod tests { } #[test] - fn snapshot_creation_fails_if_too_big() { + fn snapshot_too_big_failure_onchain_fallback() { + // the `MockStaking` is designed such that if it has too many targets, it simply fails. ExtBuilder::default().build_and_execute(|| { Targets::set((0..(TargetIndex::max_value() as AccountId) + 1).collect::>()); @@ -1949,6 +1960,49 @@ mod tests { roll_to(29); let supports = MultiPhase::elect().unwrap(); assert!(supports.len() > 0); + }); + } + + #[test] + fn snapshot_too_big_failure_no_fallback() { + // and if the backup mode is nothing, we go into the emergency mode.. + ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { + crate::mock::Targets::set( + (0..(TargetIndex::max_value() as AccountId) + 1).collect::>(), + ); + + // Signed phase failed to open. + roll_to(15); + assert_eq!(MultiPhase::current_phase(), Phase::Off); + + // Unsigned phase failed to open. + roll_to(25); + assert_eq!(MultiPhase::current_phase(), Phase::Off); + + roll_to(29); + let err = MultiPhase::elect().unwrap_err(); + assert_eq!(err, ElectionError::Fallback("NoFallback.")); + assert_eq!(MultiPhase::current_phase(), Phase::Emergency); + }); + } + + #[test] + fn snapshot_too_big_truncate() { + // but if there are too many voters, we simply truncate them. + ExtBuilder::default().build_and_execute(|| { + // we have 8 voters in total. + assert_eq!(crate::mock::Voters::get().len(), 8); + // but we want to take 2. + crate::mock::VoterSnapshotPerBlock::set(2); + + // Signed phase opens just fine. + roll_to(15); + assert_eq!(MultiPhase::current_phase(), Phase::Signed); + + assert_eq!( + MultiPhase::snapshot_metadata().unwrap(), + SolutionOrSnapshotSize { voters: 2, targets: 4 } + ); }) } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 28a15291e6520..0d563955595a8 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -268,6 +268,7 @@ parameter_types! { pub static MinerMaxWeight: Weight = BlockWeights::get().max_block; pub static MinerMaxLength: u32 = 256; pub static MockWeightInfo: bool = false; + pub static VoterSnapshotPerBlock: VoterIndex = u32::max_value(); pub static EpochLength: u64 = 30; pub static OnChianFallback: bool = true; @@ -401,6 +402,7 @@ impl crate::Config for Runtime { type Fallback = MockFallback; type ForceOrigin = frame_system::EnsureRoot; type Solution = TestNposSolution; + type VoterSnapshotPerBlock = VoterSnapshotPerBlock; type Solver = SequentialPhragmen, Balancing>; } @@ -433,9 +435,9 @@ impl ElectionDataProvider for StakingMock { fn voters( maybe_max_len: Option, ) -> data_provider::Result)>> { - let voters = Voters::get(); - if maybe_max_len.map_or(false, |max_len| voters.len() > max_len) { - return Err("Voters too big") + let mut voters = Voters::get(); + if let Some(max_len) = maybe_max_len { + voters.truncate(max_len) } Ok(voters) diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index d2c4b1053cc6d..cb36e025c3bee 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -297,6 +297,75 @@ impl ElectionProvider for () { } } +/// A utility trait for something to implement `ElectionDataProvider` in a sensible way. +/// +/// This is generic over `AccountId` and it can represent a validator, a nominator, or any other +/// entity. +/// +/// To simplify the trait, the `VoteWeight` is hardcoded as the weight of each entity. The weights +/// are ascending, the higher, the better. In the long term, if this trait ends up having use cases +/// outside of the election context, it is easy enough to make it generic over the `VoteWeight`. +/// +/// Something that implements this trait will do a best-effort sort over ids, and thus can be +/// used on the implementing side of [`ElectionDataProvider`]. +pub trait SortedListProvider { + /// The list's error type. + type Error; + + /// An iterator over the list, which can have `take` called on it. + fn iter() -> Box>; + + /// The current count of ids in the list. + fn count() -> u32; + + /// Return true if the list already contains `id`. + fn contains(id: &AccountId) -> bool; + + /// Hook for inserting a new id. + fn on_insert(id: AccountId, weight: VoteWeight) -> Result<(), Self::Error>; + + /// Hook for updating a single id. + fn on_update(id: &AccountId, weight: VoteWeight); + + /// Hook for removing am id from the list. + fn on_remove(id: &AccountId); + + /// Regenerate this list from scratch. Returns the count of items inserted. + /// + /// This should typically only be used at a runtime upgrade. + fn regenerate( + all: impl IntoIterator, + weight_of: Box VoteWeight>, + ) -> u32; + + /// Remove `maybe_count` number of items from the list. Returns the number of items actually + /// removed. WARNING: removes all items if `maybe_count` is `None`, which should never be done + /// in production settings because it can lead to an unbounded amount of storage accesses. + fn clear(maybe_count: Option) -> u32; + + /// Sanity check internal state of list. Only meant for debug compilation. + fn sanity_check() -> Result<(), &'static str>; + + /// If `who` changes by the returned amount they are guaranteed to have a worst case change + /// in their list position. + #[cfg(feature = "runtime-benchmarks")] + fn weight_update_worst_case(_who: &AccountId, _is_increase: bool) -> VoteWeight { + VoteWeight::MAX + } +} + +/// Something that can provide the `VoteWeight` of an account. Similar to [`ElectionProvider`] and +/// [`ElectionDataProvider`], this should typically be implementing by whoever is supposed to *use* +/// `SortedListProvider`. +pub trait VoteWeightProvider { + /// Get the current `VoteWeight` of `who`. + fn vote_weight(who: &AccountId) -> VoteWeight; + + /// For tests and benchmarks, set the `VoteWeight`. + #[cfg(any(feature = "runtime-benchmarks", test))] + fn set_vote_weight_of(_: &AccountId, _: VoteWeight) {} +} + /// Something that can compute the result to an NPoS solution. pub trait NposSolver { /// The account identifier type of this solver. diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 655a38fe1b540..9a0fce4d6b5b4 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -229,7 +229,7 @@ where (frame_system::Pallet::, COnRuntimeUpgrade, AllPallets) as OnRuntimeUpgrade - >::pre_upgrade()?; + >::pre_upgrade().unwrap(); let weight = Self::execute_on_runtime_upgrade(); @@ -237,7 +237,7 @@ where (frame_system::Pallet::, COnRuntimeUpgrade, AllPallets) as OnRuntimeUpgrade - >::post_upgrade()?; + >::post_upgrade().unwrap(); Ok(weight) } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 26dda514516a3..2f1b2630b2241 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -217,6 +217,7 @@ impl pallet_staking::Config for Test { type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; + type SortedListProvider = pallet_staking::UseNominatorsMap; type WeightInfo = (); } diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index c4fd88def0e33..82662295dea84 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -174,6 +174,7 @@ impl pallet_staking::Config for Test { type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; + type SortedListProvider = pallet_staking::UseNominatorsMap; type WeightInfo = (); } diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index c685db2bb2524..4d3a1a2d8689d 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -182,6 +182,7 @@ impl pallet_staking::Config for Test { type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; + type SortedListProvider = pallet_staking::UseNominatorsMap; type WeightInfo = (); } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index aba19ba56357a..70637bcd7726f 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -39,9 +39,11 @@ rand_chacha = { version = "0.2", default-features = false, optional = true } [dev-dependencies] sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } +pallet-bags-list = { version = "4.0.0-dev", features = ["runtime-benchmarks"], path = "../bags-list" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index bdc3d81f3c29b..f3def7206320c 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -21,9 +21,10 @@ use super::*; use crate::Pallet as Staking; use testing_utils::*; +use frame_election_provider_support::SortedListProvider; use frame_support::{ pallet_prelude::*, - traits::{Currency, Get, Imbalance}, + traits::{Currency, CurrencyToVote, Get, Imbalance}, }; use sp_runtime::{ traits::{StaticLookup, Zero}, @@ -110,6 +111,8 @@ pub fn create_validator_with_nominators( assert_eq!(new_validators.len(), 1); assert_eq!(new_validators[0], v_stash, "Our validator was not selected!"); + assert_ne!(CounterForValidators::::get(), 0); + assert_ne!(CounterForNominators::::get(), 0); // Give Era Points let reward = EraRewardPoints:: { @@ -129,13 +132,91 @@ pub fn create_validator_with_nominators( Ok((v_stash, nominators)) } +struct ListScenario { + /// Stash that is expected to be moved. + origin_stash1: T::AccountId, + /// Controller of the Stash that is expected to be moved. + origin_controller1: T::AccountId, + dest_weight: BalanceOf, +} + +impl ListScenario { + /// An expensive scenario for bags-list implementation: + /// + /// - the node to be updated (r) is the head of a bag that has at least one other node. The bag + /// itself will need to be read and written to update its head. The node pointed to by r.next + /// will need to be read and written as it will need to have its prev pointer updated. Note + /// that there are two other worst case scenarios for bag removal: 1) the node is a tail and + /// 2) the node is a middle node with prev and next; all scenarios end up with the same number + /// of storage reads and writes. + /// + /// - the destination bag has at least one node, which will need its next pointer updated. + /// + /// NOTE: while this scenario specifically targets a worst case for the bags-list, it should + /// also elicit a worst case for other known `SortedListProvider` implementations; although + /// this may not be true against unknown `SortedListProvider` implementations. + fn new(origin_weight: BalanceOf, is_increase: bool) -> Result { + ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0"); + + // burn the entire issuance. + let i = T::Currency::burn(T::Currency::total_issuance()); + sp_std::mem::forget(i); + + // create accounts with the origin weight + + let (origin_stash1, origin_controller1) = create_stash_controller_with_balance::( + USER_SEED + 2, + origin_weight, + Default::default(), + )?; + Staking::::nominate( + RawOrigin::Signed(origin_controller1.clone()).into(), + // NOTE: these don't really need to be validators. + vec![T::Lookup::unlookup(account("random_validator", 0, SEED))], + )?; + + let (_origin_stash2, origin_controller2) = create_stash_controller_with_balance::( + USER_SEED + 3, + origin_weight, + Default::default(), + )?; + Staking::::nominate( + RawOrigin::Signed(origin_controller2.clone()).into(), + vec![T::Lookup::unlookup(account("random_validator", 0, SEED))].clone(), + )?; + + // find a destination weight that will trigger the worst case scenario + let dest_weight_as_vote = + T::SortedListProvider::weight_update_worst_case(&origin_stash1, is_increase); + + let total_issuance = T::Currency::total_issuance(); + + let dest_weight = + T::CurrencyToVote::to_currency(dest_weight_as_vote as u128, total_issuance); + + // create an account with the worst case destination weight + let (_dest_stash1, dest_controller1) = create_stash_controller_with_balance::( + USER_SEED + 1, + dest_weight, + Default::default(), + )?; + Staking::::nominate( + RawOrigin::Signed(dest_controller1).into(), + vec![T::Lookup::unlookup(account("random_validator", 0, SEED))], + )?; + + Ok(ListScenario { origin_stash1, origin_controller1, dest_weight }) + } +} + const USER_SEED: u32 = 999666; benchmarks! { bond { let stash = create_funded_user::("stash", USER_SEED, 100); let controller = create_funded_user::("controller", USER_SEED, 100); - let controller_lookup: ::Source = T::Lookup::unlookup(controller.clone()); + let controller_lookup: ::Source + = T::Lookup::unlookup(controller.clone()); let reward_destination = RewardDestination::Staked; let amount = T::Currency::minimum_balance() * 10u32.into(); whitelist_account!(stash); @@ -146,10 +227,25 @@ benchmarks! { } bond_extra { - let (stash, controller) = create_stash_controller::(USER_SEED, 100, Default::default())?; - let max_additional = T::Currency::minimum_balance() * 10u32.into(); - let ledger = Ledger::::get(&controller).ok_or("ledger not created before")?; - let original_bonded: BalanceOf = ledger.active; + // clean up any existing state. + clear_validators_and_nominators::(); + + let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + + // setup the worst case list scenario. + + // the weight the nominator will start at. + let scenario = ListScenario::::new(origin_weight, true)?; + + let max_additional = scenario.dest_weight.clone() - origin_weight; + + let stash = scenario.origin_stash1.clone(); + let controller = scenario.origin_controller1.clone(); + let original_bonded: BalanceOf + = Ledger::::get(&controller).map(|l| l.active).ok_or("ledger not created after")?; + + T::Currency::deposit_into_existing(&stash, max_additional).unwrap(); + whitelist_account!(stash); }: _(RawOrigin::Signed(stash), max_additional) verify { @@ -159,10 +255,25 @@ benchmarks! { } unbond { - let (_, controller) = create_stash_controller::(USER_SEED, 100, Default::default())?; - let amount = T::Currency::minimum_balance() * 10u32.into(); + use sp_std::convert::TryFrom; + // clean up any existing state. + clear_validators_and_nominators::(); + + // setup the worst case list scenario. + let total_issuance = T::Currency::total_issuance(); + // the weight the nominator will start at. The value used here is expected to be + // significantly higher than the first position in a list (e.g. the first bag threshold). + let origin_weight = BalanceOf::::try_from(952_994_955_240_703u128) + .map_err(|_| "balance expected to be a u128") + .unwrap(); + let scenario = ListScenario::::new(origin_weight, false)?; + + let stash = scenario.origin_stash1.clone(); + let controller = scenario.origin_controller1.clone(); + let amount = origin_weight - scenario.dest_weight.clone(); let ledger = Ledger::::get(&controller).ok_or("ledger not created before")?; let original_bonded: BalanceOf = ledger.active; + whitelist_account!(controller); }: _(RawOrigin::Signed(controller.clone()), amount) verify { @@ -194,26 +305,50 @@ benchmarks! { withdraw_unbonded_kill { // Slashing Spans let s in 0 .. MAX_SPANS; - let (stash, controller) = create_stash_controller::(0, 100, Default::default())?; - add_slashing_spans::(&stash, s); - let amount = T::Currency::minimum_balance() * 10u32.into(); - Staking::::unbond(RawOrigin::Signed(controller.clone()).into(), amount)?; + // clean up any existing state. + clear_validators_and_nominators::(); + + let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + + // setup a worst case list scenario. Note that we don't care about the setup of the + // destination position because we are doing a removal from the list but no insert. + let scenario = ListScenario::::new(origin_weight, true)?; + let controller = scenario.origin_controller1.clone(); + let stash = scenario.origin_stash1.clone(); + assert!(T::SortedListProvider::contains(&stash)); + + let ed = T::Currency::minimum_balance(); + let mut ledger = Ledger::::get(&controller).unwrap(); + ledger.active = ed - One::one(); + Ledger::::insert(&controller, ledger); CurrentEra::::put(EraIndex::max_value()); - let ledger = Ledger::::get(&controller).ok_or("ledger not created before")?; - let original_total: BalanceOf = ledger.total; + whitelist_account!(controller); }: withdraw_unbonded(RawOrigin::Signed(controller.clone()), s) verify { assert!(!Ledger::::contains_key(controller)); + assert!(!T::SortedListProvider::contains(&stash)); } validate { - let (stash, controller) = create_stash_controller::(USER_SEED, 100, Default::default())?; + // clean up any existing state. + clear_validators_and_nominators::(); + + let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + + // setup a worst case scenario where the user calling validate was formerly a nominator so + // they must be removed from the list. + let scenario = ListScenario::::new(origin_weight, true)?; + let controller = scenario.origin_controller1.clone(); + let stash = scenario.origin_stash1.clone(); + assert!(T::SortedListProvider::contains(&stash)); + let prefs = ValidatorPrefs::default(); whitelist_account!(controller); }: _(RawOrigin::Signed(controller), prefs) verify { - assert!(Validators::::contains_key(stash)); + assert!(Validators::::contains_key(&stash)); + assert!(!T::SortedListProvider::contains(&stash)); } kick { @@ -225,7 +360,7 @@ benchmarks! { // these are the other validators; there are `T::MAX_NOMINATIONS - 1` of them, so // there are a total of `T::MAX_NOMINATIONS` validators in the system. - let rest_of_validators = create_validators::(T::MAX_NOMINATIONS - 1, 100)?; + let rest_of_validators = create_validators_with_seed::(T::MAX_NOMINATIONS - 1, 100, 415)?; // this is the validator that will be kicking. let (stash, controller) = create_stash_controller::( @@ -282,18 +417,50 @@ benchmarks! { // Worst case scenario, T::MAX_NOMINATIONS nominate { let n in 1 .. T::MAX_NOMINATIONS; - let (stash, controller) = create_stash_controller::(n + 1, 100, Default::default())?; - let validators = create_validators::(n, 100)?; + + // clean up any existing state. + clear_validators_and_nominators::(); + + let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + + // setup a worst case list scenario. Note we don't care about the destination position, because + // we are just doing an insert into the origin position. + let scenario = ListScenario::::new(origin_weight, true)?; + let (stash, controller) = create_stash_controller_with_balance::( + SEED + T::MAX_NOMINATIONS + 1, // make sure the account does not conflict with others + origin_weight, + Default::default(), + ).unwrap(); + + assert!(!Nominators::::contains_key(&stash)); + assert!(!T::SortedListProvider::contains(&stash)); + + let validators = create_validators::(n, 100).unwrap(); whitelist_account!(controller); }: _(RawOrigin::Signed(controller), validators) verify { - assert!(Nominators::::contains_key(stash)); + assert!(Nominators::::contains_key(&stash)); + assert!(T::SortedListProvider::contains(&stash)) } chill { - let (_, controller) = create_stash_controller::(USER_SEED, 100, Default::default())?; + // clean up any existing state. + clear_validators_and_nominators::(); + + let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + + // setup a worst case list scenario. Note that we don't care about the setup of the + // destination position because we are doing a removal from the list but no insert. + let scenario = ListScenario::::new(origin_weight, true)?; + let controller = scenario.origin_controller1.clone(); + let stash = scenario.origin_stash1.clone(); + assert!(T::SortedListProvider::contains(&stash)); + whitelist_account!(controller); }: _(RawOrigin::Signed(controller)) + verify { + assert!(!T::SortedListProvider::contains(&stash)); + } set_payee { let (stash, controller) = create_stash_controller::(USER_SEED, 100, Default::default())?; @@ -345,11 +512,23 @@ benchmarks! { force_unstake { // Slashing Spans let s in 0 .. MAX_SPANS; - let (stash, controller) = create_stash_controller::(0, 100, Default::default())?; + // Clean up any existing state. + clear_validators_and_nominators::(); + + let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + + // setup a worst case list scenario. Note that we don't care about the setup of the + // destination position because we are doing a removal from the list but no insert. + let scenario = ListScenario::::new(origin_weight, true)?; + let controller = scenario.origin_controller1.clone(); + let stash = scenario.origin_stash1.clone(); + assert!(T::SortedListProvider::contains(&stash)); add_slashing_spans::(&stash, s); - }: _(RawOrigin::Root, stash, s) + + }: _(RawOrigin::Root, stash.clone(), s) verify { assert!(!Ledger::::contains_key(&controller)); + assert!(!T::SortedListProvider::contains(&stash)); } cancel_deferred_slash { @@ -438,19 +617,46 @@ benchmarks! { rebond { let l in 1 .. MAX_UNLOCKING_CHUNKS as u32; - let (_, controller) = create_stash_controller::(USER_SEED, 100, Default::default())?; - let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); + + // clean up any existing state. + clear_validators_and_nominators::(); + + let origin_weight = MinNominatorBond::::get() + .max(T::Currency::minimum_balance()) + // we use 100 to play friendly with the list threshold values in the mock + .max(100u32.into()); + + // setup a worst case list scenario. + let scenario = ListScenario::::new(origin_weight, true)?; + let dest_weight = scenario.dest_weight.clone(); + + // rebond an amount that will give the user dest_weight + let rebond_amount = dest_weight - origin_weight; + + // spread that amount to rebond across `l` unlocking chunks, + let value = rebond_amount / l.into(); + // if `value` is zero, we need a greater delta between dest <=> origin weight + assert_ne!(value, Zero::zero()); + // so the sum of unlocking chunks puts voter into the dest bag. + assert!(value * l.into() + origin_weight > origin_weight); + assert!(value * l.into() + origin_weight <= dest_weight); let unlock_chunk = UnlockChunk::> { - value: 1u32.into(), + value, era: EraIndex::zero(), }; + + let stash = scenario.origin_stash1.clone(); + let controller = scenario.origin_controller1.clone(); + let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); + for _ in 0 .. l { staking_ledger.unlocking.push(unlock_chunk.clone()) } Ledger::::insert(controller.clone(), staking_ledger.clone()); let original_bonded: BalanceOf = staking_ledger.active; + whitelist_account!(controller); - }: _(RawOrigin::Signed(controller.clone()), (l + 100).into()) + }: _(RawOrigin::Signed(controller.clone()), rebond_amount) verify { let ledger = Ledger::::get(&controller).ok_or("ledger not created after")?; let new_bonded: BalanceOf = ledger.active; @@ -477,19 +683,28 @@ benchmarks! { reap_stash { let s in 1 .. MAX_SPANS; - let (stash, controller) = create_stash_controller::(0, 100, Default::default())?; - Staking::::validate(RawOrigin::Signed(controller.clone()).into(), ValidatorPrefs::default())?; + // clean up any existing state. + clear_validators_and_nominators::(); + + let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + + // setup a worst case list scenario. Note that we don't care about the setup of the + // destination position because we are doing a removal from the list but no insert. + let scenario = ListScenario::::new(origin_weight, true)?; + let controller = scenario.origin_controller1.clone(); + let stash = scenario.origin_stash1.clone(); + add_slashing_spans::(&stash, s); T::Currency::make_free_balance_be(&stash, T::Currency::minimum_balance()); - whitelist_account!(controller); assert!(Bonded::::contains_key(&stash)); - assert!(Validators::::contains_key(&stash)); + assert!(T::SortedListProvider::contains(&stash)); + whitelist_account!(controller); }: _(RawOrigin::Signed(controller), stash.clone(), s) verify { assert!(!Bonded::::contains_key(&stash)); - assert!(!Validators::::contains_key(&stash)); + assert!(!T::SortedListProvider::contains(&stash)); } new_era { @@ -590,17 +805,21 @@ benchmarks! { // total number of slashing spans. Assigned to validators randomly. let s in 1 .. 20; - let validators = create_validators_with_nominators_for_era::(v, n, T::MAX_NOMINATIONS as usize, false, None)? - .into_iter() - .map(|v| T::Lookup::lookup(v).unwrap()) - .collect::>(); + let validators = create_validators_with_nominators_for_era::( + v, n, T::MAX_NOMINATIONS as usize, false, None + )? + .into_iter() + .map(|v| T::Lookup::lookup(v).unwrap()) + .collect::>(); (0..s).for_each(|index| { add_slashing_spans::(&validators[index as usize], 10); }); + + let num_voters = (v + n) as usize; }: { - let voters = >::get_npos_voters(); - assert_eq!(voters.len() as u32, v + n); + let voters = >::get_npos_voters(None); + assert_eq!(voters.len(), num_voters); } get_npos_targets { @@ -609,7 +828,9 @@ benchmarks! { // number of nominator intention. let n = MAX_NOMINATORS; - let _ = create_validators_with_nominators_for_era::(v, n, T::MAX_NOMINATIONS as usize, false, None)?; + let _ = create_validators_with_nominators_for_era::( + v, n, T::MAX_NOMINATIONS as usize, false, None + )?; }: { let targets = >::get_npos_targets(); assert_eq!(targets.len() as u32, v); @@ -633,8 +854,18 @@ benchmarks! { } chill_other { - let (_, controller) = create_stash_controller::(USER_SEED, 100, Default::default())?; - Staking::::validate(RawOrigin::Signed(controller.clone()).into(), ValidatorPrefs::default())?; + // clean up any existing state. + clear_validators_and_nominators::(); + + let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + + // setup a worst case list scenario. Note that we don't care about the setup of the + // destination position because we are doing a removal from the list but no insert. + let scenario = ListScenario::::new(origin_weight, true)?; + let controller = scenario.origin_controller1.clone(); + let stash = scenario.origin_stash1.clone(); + assert!(T::SortedListProvider::contains(&stash)); + Staking::::set_staking_limits( RawOrigin::Root.into(), BalanceOf::::max_value(), @@ -643,10 +874,11 @@ benchmarks! { Some(0), Some(Percent::from_percent(0)) )?; + let caller = whitelisted_caller(); }: _(RawOrigin::Signed(caller), controller.clone()) verify { - assert!(!Validators::::contains_key(controller)); + assert!(!T::SortedListProvider::contains(&stash)); } } @@ -658,7 +890,7 @@ mod tests { #[test] fn create_validators_with_nominators_for_era_works() { - ExtBuilder::default().has_stakers(true).build_and_execute(|| { + ExtBuilder::default().build_and_execute(|| { let v = 10; let n = 100; @@ -674,6 +906,9 @@ mod tests { let count_validators = Validators::::iter().count(); let count_nominators = Nominators::::iter().count(); + assert_eq!(count_validators, CounterForValidators::::get() as usize); + assert_eq!(count_nominators, CounterForNominators::::get() as usize); + assert_eq!(count_validators, v as usize); assert_eq!(count_nominators, n as usize); }); @@ -681,7 +916,7 @@ mod tests { #[test] fn create_validator_with_nominators_works() { - ExtBuilder::default().has_stakers(true).build_and_execute(|| { + ExtBuilder::default().build_and_execute(|| { let n = 10; let (validator_stash, nominators) = create_validator_with_nominators::( @@ -706,7 +941,7 @@ mod tests { #[test] fn add_slashing_spans_works() { - ExtBuilder::default().has_stakers(true).build_and_execute(|| { + ExtBuilder::default().build_and_execute(|| { let n = 10; let (validator_stash, _nominators) = create_validator_with_nominators::( @@ -738,7 +973,7 @@ mod tests { #[test] fn test_payout_all() { - ExtBuilder::default().has_stakers(true).build_and_execute(|| { + ExtBuilder::default().build_and_execute(|| { let v = 10; let n = 100; diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 31b35acdd99aa..136515a5d6168 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -100,6 +100,13 @@ //! //! An account can become a nominator via the [`nominate`](Call::nominate) call. //! +//! #### Voting +//! +//! Staking is closely related to elections; actual validators are chosen from among all potential +//! validators via election by the potential validators and nominators. To reduce use of the phrase +//! "potential validators and nominators", we often use the term **voters**, who are simply +//! the union of potential validators and nominators. +//! //! #### Rewards and Slash //! //! The **reward and slashing** procedure is the core of the Staking pallet, attempting to _embrace @@ -264,15 +271,15 @@ //! - [Session](../pallet_session/index.html): Used to manage sessions. Also, a list of new //! validators is stored in the Session pallet's `Validators` at the end of each era. -#![recursion_limit = "128"] #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; -#[cfg(test)] -mod mock; #[cfg(any(feature = "runtime-benchmarks", test))] pub mod testing_utils; + +#[cfg(test)] +pub(crate) mod mock; #[cfg(test)] mod tests; @@ -420,6 +427,7 @@ pub struct UnlockChunk { } /// The ledger of a (bonded) stash. +#[cfg_attr(feature = "runtime-benchmarks", derive(Default))] #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct StakingLedger { /// The stash account whose balance is actually locked and at stake. @@ -727,11 +735,12 @@ enum Releases { V5_0_0, // blockable validators. V6_0_0, // removal of all storage associated with offchain phragmen. V7_0_0, // keep track of number of nominators / validators in map + V8_0_0, // populate `SortedListProvider`. } impl Default for Releases { fn default() -> Self { - Releases::V7_0_0 + Releases::V8_0_0 } } diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index d7fa2afc63082..7064f06dd12c7 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -18,6 +18,56 @@ use super::*; +pub mod v8 { + use frame_election_provider_support::SortedListProvider; + use frame_support::traits::Get; + + use crate::{Config, Nominators, Pallet, StorageVersion, Weight}; + + #[cfg(feature = "try-runtime")] + pub fn pre_migrate() -> Result<(), &'static str> { + frame_support::ensure!( + StorageVersion::::get() == crate::Releases::V7_0_0, + "must upgrade linearly" + ); + + crate::log!(info, "👜 staking bags-list migration passes PRE migrate checks ✅",); + Ok(()) + } + + /// Migration to sorted [`SortedListProvider`]. + pub fn migrate() -> Weight { + if StorageVersion::::get() == crate::Releases::V7_0_0 { + crate::log!(info, "migrating staking to Releases::V8_0_0"); + + let migrated = T::SortedListProvider::regenerate( + Nominators::::iter().map(|(id, _)| id), + Pallet::::weight_of_fn(), + ); + debug_assert_eq!(T::SortedListProvider::sanity_check(), Ok(())); + + StorageVersion::::put(crate::Releases::V8_0_0); + crate::log!( + info, + "👜 completed staking migration to Releases::V8_0_0 with {} voters migrated", + migrated, + ); + + T::BlockWeights::get().max_block + } else { + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + pub fn post_migrate() -> Result<(), &'static str> { + T::SortedListProvider::sanity_check() + .map_err(|_| "SortedListProvider is not in a sane state.")?; + crate::log!(info, "👜 staking bags-list migration passes POST migrate checks ✅",); + Ok(()) + } +} + pub mod v7 { use super::*; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 0357fa05cb1dd..b3ce8e063cb61 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -17,9 +17,8 @@ //! Test utilities -use crate as staking; -use crate::*; -use frame_election_provider_support::onchain; +use crate::{self as pallet_staking, *}; +use frame_election_provider_support::{onchain, SortedListProvider}; use frame_support::{ assert_ok, parameter_types, traits::{ @@ -104,8 +103,9 @@ frame_support::construct_runtime!( Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Staking: staking::{Pallet, Call, Config, Storage, Event}, + Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, + BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, } ); @@ -242,12 +242,26 @@ impl OnUnbalanced> for RewardRemainderMock { } } +const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = + [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; + +parameter_types! { + pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; +} + +impl pallet_bags_list::Config for Test { + type Event = Event; + type WeightInfo = (); + type VoteWeightProvider = Staking; + type BagThresholds = BagThresholds; +} + impl onchain::Config for Test { type Accuracy = Perbill; type DataProvider = Staking; } -impl Config for Test { +impl crate::pallet::pallet::Config for Test { const MAX_NOMINATIONS: u32 = 16; type Currency = Balances; type UnixTime = Timestamp; @@ -267,6 +281,8 @@ impl Config for Test { type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type WeightInfo = (); + // NOTE: consider a macro and use `UseNominatorsMap` as well. + type SortedListProvider = BagsList; } impl frame_system::offchain::SendTransactionTypes for Test @@ -469,7 +485,7 @@ impl ExtBuilder { stakers.extend(self.stakers) } - let _ = staking::GenesisConfig:: { + let _ = pallet_staking::GenesisConfig:: { stakers, validator_count: self.validator_count, minimum_validator_count: self.minimum_validator_count, @@ -533,6 +549,10 @@ fn check_count() { let validator_count = Validators::::iter().count() as u32; assert_eq!(nominator_count, CounterForNominators::::get()); assert_eq!(validator_count, CounterForValidators::::get()); + + // the voters that the `SortedListProvider` list is storing for us. + let external_voters = ::SortedListProvider::count(); + assert_eq!(external_voters, nominator_count); } fn check_ledgers() { @@ -625,10 +645,14 @@ pub(crate) fn current_era() -> EraIndex { Staking::current_era().unwrap() } -pub(crate) fn bond_validator(stash: AccountId, ctrl: AccountId, val: Balance) { +pub(crate) fn bond(stash: AccountId, ctrl: AccountId, val: Balance) { let _ = Balances::make_free_balance_be(&stash, val); let _ = Balances::make_free_balance_be(&ctrl, val); assert_ok!(Staking::bond(Origin::signed(stash), ctrl, val, RewardDestination::Controller)); +} + +pub(crate) fn bond_validator(stash: AccountId, ctrl: AccountId, val: Balance) { + bond(stash, ctrl, val); assert_ok!(Staking::validate(Origin::signed(ctrl), ValidatorPrefs::default())); } @@ -638,9 +662,7 @@ pub(crate) fn bond_nominator( val: Balance, target: Vec, ) { - let _ = Balances::make_free_balance_be(&stash, val); - let _ = Balances::make_free_balance_be(&ctrl, val); - assert_ok!(Staking::bond(Origin::signed(stash), ctrl, val, RewardDestination::Controller)); + bond(stash, ctrl, val); assert_ok!(Staking::nominate(Origin::signed(ctrl), target)); } @@ -833,7 +855,7 @@ macro_rules! assert_session_era { }; } -pub(crate) fn staking_events() -> Vec> { +pub(crate) fn staking_events() -> Vec> { System::events() .into_iter() .map(|r| r.event) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index fecd493eea022..3ae520872f278 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -17,7 +17,10 @@ //! Implementations for the Staking FRAME Pallet. -use frame_election_provider_support::{data_provider, ElectionProvider, Supports, VoteWeight}; +use frame_election_provider_support::{ + data_provider, ElectionDataProvider, ElectionProvider, SortedListProvider, Supports, + VoteWeight, VoteWeightProvider, +}; use frame_support::{ pallet_prelude::*, traits::{ @@ -26,6 +29,7 @@ use frame_support::{ }, weights::{Weight, WithPostDispatchInfo}, }; +use frame_system::pallet_prelude::BlockNumberFor; use pallet_session::historical; use sp_runtime::{ traits::{Bounded, Convert, SaturatedConversion, Saturating, Zero}, @@ -64,7 +68,7 @@ impl Pallet { /// /// This prevents call sites from repeatedly requesting `total_issuance` from backend. But it is /// important to be only used while the total issuance is not changing. - pub fn slashable_balance_of_fn() -> Box VoteWeight> { + pub fn weight_of_fn() -> Box VoteWeight> { // NOTE: changing this to unboxed `impl Fn(..)` return type and the pallet will still // compile, while some types in mock fail to resolve. let issuance = T::Currency::total_issuance(); @@ -73,6 +77,12 @@ impl Pallet { }) } + /// Same as `weight_of_fn`, but made for one time use. + pub fn weight_of(who: &T::AccountId) -> VoteWeight { + let issuance = T::Currency::total_issuance(); + Self::slashable_balance_of_vote_weight(who, issuance) + } + pub(super) fn do_payout_stakers( validator_stash: T::AccountId, era: EraIndex, @@ -629,54 +639,92 @@ impl Pallet { /// Get all of the voters that are eligible for the npos election. /// - /// This will use all on-chain nominators, and all the validators will inject a self vote. + /// `maybe_max_len` can imposes a cap on the number of voters returned; First all the validator + /// are included in no particular order, then remainder is taken from the nominators, as + /// returned by [`Config::SortedListProvider`]. + /// + /// This will use nominators, and all the validators will inject a self vote. /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. /// /// ### Slashing /// /// All nominations that have been submitted before the last non-zero slash of the validator are - /// auto-chilled. - pub fn get_npos_voters() -> Vec<(T::AccountId, VoteWeight, Vec)> { - let weight_of = Self::slashable_balance_of_fn(); - let mut all_voters = Vec::new(); + /// auto-chilled, but still count towards the limit imposed by `maybe_max_len`. + pub fn get_npos_voters( + maybe_max_len: Option, + ) -> Vec<(T::AccountId, VoteWeight, Vec)> { + let max_allowed_len = { + let nominator_count = CounterForNominators::::get() as usize; + let validator_count = CounterForValidators::::get() as usize; + let all_voter_count = validator_count.saturating_add(nominator_count); + maybe_max_len.unwrap_or(all_voter_count).min(all_voter_count) + }; - let mut validator_count = 0u32; - for (validator, _) in >::iter() { + let mut all_voters = Vec::<_>::with_capacity(max_allowed_len); + + // first, grab all validators in no particular order, capped by the maximum allowed length. + let mut validators_taken = 0u32; + for (validator, _) in >::iter().take(max_allowed_len) { // Append self vote. - let self_vote = (validator.clone(), weight_of(&validator), vec![validator.clone()]); + let self_vote = + (validator.clone(), Self::weight_of(&validator), vec![validator.clone()]); all_voters.push(self_vote); - validator_count.saturating_inc(); + validators_taken.saturating_inc(); } - // Collect all slashing spans into a BTreeMap for further queries. + // .. and grab whatever we have left from nominators. + let nominators_quota = (max_allowed_len as u32).saturating_sub(validators_taken); let slashing_spans = >::iter().collect::>(); - let mut nominator_count = 0u32; - for (nominator, nominations) in Nominators::::iter() { - let Nominations { submitted_in, mut targets, suppressed: _ } = nominations; - - // Filter out nomination targets which were nominated before the most recent - // slashing span. - targets.retain(|stash| { - slashing_spans - .get(stash) - .map_or(true, |spans| submitted_in >= spans.last_nonzero_slash()) - }); + // track the count of nominators added to `all_voters + let mut nominators_taken = 0u32; + // track every nominator iterated over, but not necessarily added to `all_voters` + let mut nominators_seen = 0u32; + + let mut nominators_iter = T::SortedListProvider::iter(); + while nominators_taken < nominators_quota && nominators_seen < nominators_quota * 2 { + let nominator = match nominators_iter.next() { + Some(nominator) => { + nominators_seen.saturating_inc(); + nominator + }, + None => break, + }; - if !targets.is_empty() { - let vote_weight = weight_of(&nominator); - all_voters.push((nominator, vote_weight, targets)); - nominator_count.saturating_inc(); + if let Some(Nominations { submitted_in, mut targets, suppressed: _ }) = + >::get(&nominator) + { + targets.retain(|stash| { + slashing_spans + .get(stash) + .map_or(true, |spans| submitted_in >= spans.last_nonzero_slash()) + }); + if !targets.len().is_zero() { + all_voters.push((nominator.clone(), Self::weight_of(&nominator), targets)); + nominators_taken.saturating_inc(); + } + } else { + log!(error, "invalid item in `SortedListProvider`: {:?}", nominator) } } + // all_voters should have not re-allocated. + debug_assert!(all_voters.capacity() == max_allowed_len); + Self::register_weight(T::WeightInfo::get_npos_voters( - validator_count, - nominator_count, + validators_taken, + nominators_taken, slashing_spans.len() as u32, )); + log!( + info, + "generated {} npos voters, {} from validators and {} nominators", + all_voters.len(), + validators_taken, + nominators_taken + ); all_voters } @@ -698,34 +746,59 @@ impl Pallet { } /// This function will add a nominator to the `Nominators` storage map, - /// and keep track of the `CounterForNominators`. + /// [`SortedListProvider`] and keep track of the `CounterForNominators`. /// /// If the nominator already exists, their nominations will be updated. + /// + /// NOTE: you must ALWAYS use this function to add nominator or update their targets. Any access + /// to `Nominators`, its counter, or `VoterList` outside of this function is almost certainly + /// wrong. pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { if !Nominators::::contains_key(who) { - CounterForNominators::::mutate(|x| x.saturating_inc()) + // maybe update the counter. + CounterForNominators::::mutate(|x| x.saturating_inc()); + + // maybe update sorted list. Error checking is defensive-only - this should never fail. + if T::SortedListProvider::on_insert(who.clone(), Self::weight_of(who)).is_err() { + log!(warn, "attempt to insert duplicate nominator ({:#?})", who); + debug_assert!(false, "attempt to insert duplicate nominator"); + }; + + debug_assert_eq!(T::SortedListProvider::sanity_check(), Ok(())); } + Nominators::::insert(who, nominations); } /// This function will remove a nominator from the `Nominators` storage map, - /// and keep track of the `CounterForNominators`. + /// [`SortedListProvider`] and keep track of the `CounterForNominators`. /// /// Returns true if `who` was removed from `Nominators`, otherwise false. + /// + /// NOTE: you must ALWAYS use this function to remove a nominator from the system. Any access to + /// `Nominators`, its counter, or `VoterList` outside of this function is almost certainly + /// wrong. pub fn do_remove_nominator(who: &T::AccountId) -> bool { if Nominators::::contains_key(who) { Nominators::::remove(who); CounterForNominators::::mutate(|x| x.saturating_dec()); + T::SortedListProvider::on_remove(who); + debug_assert_eq!(T::SortedListProvider::sanity_check(), Ok(())); + debug_assert_eq!(CounterForNominators::::get(), T::SortedListProvider::count()); true } else { false } } - /// This function will add a validator to the `Validators` storage map, - /// and keep track of the `CounterForValidators`. + /// This function will add a validator to the `Validators` storage map, and keep track of the + /// `CounterForValidators`. /// /// If the validator already exists, their preferences will be updated. + /// + /// NOTE: you must ALWAYS use this function to add a validator to the system. Any access to + /// `Validators`, its counter, or `VoterList` outside of this function is almost certainly + /// wrong. pub fn do_add_validator(who: &T::AccountId, prefs: ValidatorPrefs) { if !Validators::::contains_key(who) { CounterForValidators::::mutate(|x| x.saturating_inc()) @@ -737,6 +810,10 @@ impl Pallet { /// and keep track of the `CounterForValidators`. /// /// Returns true if `who` was removed from `Validators`, otherwise false. + /// + /// NOTE: you must ALWAYS use this function to remove a validator from the system. Any access to + /// `Validators`, its counter, or `VoterList` outside of this function is almost certainly + /// wrong. pub fn do_remove_validator(who: &T::AccountId) -> bool { if Validators::::contains_key(who) { Validators::::remove(who); @@ -758,10 +835,9 @@ impl Pallet { } } -impl frame_election_provider_support::ElectionDataProvider - for Pallet -{ +impl ElectionDataProvider> for Pallet { const MAXIMUM_VOTES_PER_VOTER: u32 = T::MAX_NOMINATIONS; + fn desired_targets() -> data_provider::Result { Self::register_weight(T::DbWeight::get().reads(1)); Ok(Self::validator_count()) @@ -770,30 +846,26 @@ impl frame_election_provider_support::ElectionDataProvider, ) -> data_provider::Result)>> { - let nominator_count = CounterForNominators::::get(); - let validator_count = CounterForValidators::::get(); - - let voter_count = nominator_count.saturating_add(validator_count) as usize; debug_assert!(>::iter().count() as u32 == CounterForNominators::::get()); debug_assert!(>::iter().count() as u32 == CounterForValidators::::get()); + debug_assert_eq!( + CounterForNominators::::get(), + T::SortedListProvider::count(), + "voter_count must be accurate", + ); - // register the extra 2 reads - Self::register_weight(T::DbWeight::get().reads(2)); - - if maybe_max_len.map_or(false, |max_len| voter_count > max_len) { - return Err("Voter snapshot too big") - } + // This can never fail -- if `maybe_max_len` is `Some(_)` we handle it. + let voters = Self::get_npos_voters(maybe_max_len); + debug_assert!(maybe_max_len.map_or(true, |max| voters.len() <= max)); - Ok(Self::get_npos_voters()) + Ok(voters) } fn targets(maybe_max_len: Option) -> data_provider::Result> { - let target_count = CounterForValidators::::get() as usize; + let target_count = CounterForValidators::::get(); - // register the extra 1 read - Self::register_weight(T::DbWeight::get().reads(1)); - - if maybe_max_len.map_or(false, |max_len| target_count > max_len) { + // We can't handle this case yet -- return an error. + if maybe_max_len.map_or(false, |max_len| target_count > max_len as u32) { return Err("Target snapshot too big") } @@ -879,6 +951,9 @@ impl frame_election_provider_support::ElectionDataProvider>::remove_all(None); >::remove_all(None); >::remove_all(None); + >::kill(); + >::kill(); + let _ = T::SortedListProvider::clear(None); } #[cfg(feature = "runtime-benchmarks")] @@ -1152,3 +1227,77 @@ where consumed_weight } } + +impl VoteWeightProvider for Pallet { + fn vote_weight(who: &T::AccountId) -> VoteWeight { + Self::weight_of(who) + } + + #[cfg(feature = "runtime-benchmarks")] + fn set_vote_weight_of(who: &T::AccountId, weight: VoteWeight) { + // this will clearly results in an inconsistent state, but it should not matter for a + // benchmark. + use sp_std::convert::TryInto; + let active: BalanceOf = weight.try_into().map_err(|_| ()).unwrap(); + let mut ledger = Self::ledger(who).unwrap_or_default(); + ledger.active = active; + >::insert(who, ledger); + >::insert(who, who); + + // also, we play a trick to make sure that a issuance based-`CurrencyToVote` behaves well: + // This will make sure that total issuance is zero, thus the currency to vote will be a 1-1 + // conversion. + let imbalance = T::Currency::burn(T::Currency::total_issuance()); + // kinda ugly, but gets the job done. The fact that this works here is a HUGE exception. + // Don't try this pattern in other places. + sp_std::mem::forget(imbalance); + } +} + +/// A simple voter list implementation that does not require any additional pallets. Note, this +/// does not provided nominators in sorted ordered. If you desire nominators in a sorted order take +/// a look at [`pallet-bags-list]. +pub struct UseNominatorsMap(sp_std::marker::PhantomData); +impl SortedListProvider for UseNominatorsMap { + type Error = (); + + /// Returns iterator over voter list, which can have `take` called on it. + fn iter() -> Box> { + Box::new(Nominators::::iter().map(|(n, _)| n)) + } + fn count() -> u32 { + CounterForNominators::::get() + } + fn contains(id: &T::AccountId) -> bool { + Nominators::::contains_key(id) + } + fn on_insert(_: T::AccountId, _weight: VoteWeight) -> Result<(), Self::Error> { + // nothing to do on insert. + Ok(()) + } + fn on_update(_: &T::AccountId, _weight: VoteWeight) { + // nothing to do on update. + } + fn on_remove(_: &T::AccountId) { + // nothing to do on remove. + } + fn regenerate( + _: impl IntoIterator, + _: Box VoteWeight>, + ) -> u32 { + // nothing to do upon regenerate. + 0 + } + fn sanity_check() -> Result<(), &'static str> { + Ok(()) + } + fn clear(maybe_count: Option) -> u32 { + Nominators::::remove_all(maybe_count); + if let Some(count) = maybe_count { + CounterForNominators::::mutate(|noms| *noms - count); + count + } else { + CounterForNominators::::take() + } + } +} diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index d99cd89f3b06c..c71130a3492b1 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -17,6 +17,7 @@ //! Staking FRAME Pallet. +use frame_election_provider_support::SortedListProvider; use frame_support::{ pallet_prelude::*, traits::{ @@ -38,7 +39,7 @@ mod impls; pub use impls::*; use crate::{ - migrations, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraIndex, EraPayout, + log, migrations, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraIndex, EraPayout, EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, @@ -140,6 +141,11 @@ pub mod pallet { #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; + /// Something that can provide a sorted list of voters in a somewhat sorted way. The + /// original use case for this was designed with [`pallet_bags_list::Pallet`] in mind. If + /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. + type SortedListProvider: SortedListProvider; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -492,6 +498,13 @@ pub mod pallet { MinValidatorBond::::put(self.min_validator_bond); for &(ref stash, ref controller, balance, ref status) in &self.stakers { + log!( + trace, + "inserting genesis staker: {:?} => {:?} => {:?}", + stash, + balance, + status + ); assert!( T::Currency::free_balance(&stash) >= balance, "Stash does not have enough balance to bond." @@ -514,6 +527,13 @@ pub mod pallet { _ => Ok(()), }); } + + // all voters are reported to the `SortedListProvider`. + assert_eq!( + T::SortedListProvider::count(), + CounterForNominators::::get(), + "not all genesis stakers were inserted into sorted list provider, something is wrong." + ); } } @@ -763,8 +783,15 @@ pub mod pallet { Error::::InsufficientBond ); - Self::deposit_event(Event::::Bonded(stash, extra)); + // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); + // update this staker in the sorted list, if they exist in it. + if T::SortedListProvider::contains(&stash) { + T::SortedListProvider::on_update(&stash, Self::weight_of(&ledger.stash)); + debug_assert_eq!(T::SortedListProvider::sanity_check(), Ok(())); + } + + Self::deposit_event(Event::::Bonded(stash.clone(), extra)); } Ok(()) } @@ -823,7 +850,14 @@ pub mod pallet { // Note: in case there is no current era it is fine to bond one era more. let era = Self::current_era().unwrap_or(0) + T::BondingDuration::get(); ledger.unlocking.push(UnlockChunk { value, era }); + // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); + + // update this staker in the sorted list, if they exist in it. + if T::SortedListProvider::contains(&ledger.stash) { + T::SortedListProvider::on_update(&ledger.stash, Self::weight_of(&ledger.stash)); + } + Self::deposit_event(Event::::Unbonded(ledger.stash, value)); } Ok(()) @@ -1319,7 +1353,12 @@ pub mod pallet { ensure!(ledger.active >= T::Currency::minimum_balance(), Error::::InsufficientBond); Self::deposit_event(Event::::Bonded(ledger.stash.clone(), value)); + + // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); + if T::SortedListProvider::contains(&ledger.stash) { + T::SortedListProvider::on_update(&ledger.stash, Self::weight_of(&ledger.stash)); + } let removed_chunks = 1u32 // for the case where the last iterated chunk is not removed .saturating_add(initial_unlocking) @@ -1492,8 +1531,6 @@ pub mod pallet { /// /// This can be helpful if bond requirements are updated, and we need to remove old users /// who do not satisfy these requirements. - // TODO: Maybe we can deprecate `chill` in the future. - // https://github.com/paritytech/substrate/issues/9111 #[pallet::weight(T::WeightInfo::chill_other())] pub fn chill_other(origin: OriginFor, controller: T::AccountId) -> DispatchResult { // Anyone can call this function. diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 795c066d09bb3..13762cf5886db 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -27,6 +27,7 @@ use rand_chacha::{ }; use sp_io::hashing::blake2_256; +use frame_election_provider_support::SortedListProvider; use frame_support::{pallet_prelude::*, traits::Currency}; use sp_runtime::{traits::StaticLookup, Perbill}; use sp_std::prelude::*; @@ -37,8 +38,11 @@ const SEED: u32 = 0; pub fn clear_validators_and_nominators() { Validators::::remove_all(None); CounterForValidators::::kill(); + + // whenever we touch nominators counter we should update `T::SortedListProvider` as well. Nominators::::remove_all(None); CounterForNominators::::kill(); + let _ = T::SortedListProvider::clear(None); } /// Grab a funded user. @@ -49,9 +53,18 @@ pub fn create_funded_user( ) -> T::AccountId { let user = account(string, n, SEED); let balance = T::Currency::minimum_balance() * balance_factor.into(); - T::Currency::make_free_balance_be(&user, balance); - // ensure T::CurrencyToVote will work correctly. - T::Currency::issue(balance); + let _ = T::Currency::make_free_balance_be(&user, balance); + user +} + +/// Grab a funded user with max Balance. +pub fn create_funded_user_with_balance( + string: &'static str, + n: u32, + balance: BalanceOf, +) -> T::AccountId { + let user = account(string, n, SEED); + let _ = T::Currency::make_free_balance_be(&user, balance); user } @@ -75,6 +88,26 @@ pub fn create_stash_controller( return Ok((stash, controller)) } +/// Create a stash and controller pair with fixed balance. +pub fn create_stash_controller_with_balance( + n: u32, + balance: crate::BalanceOf, + destination: RewardDestination, +) -> Result<(T::AccountId, T::AccountId), &'static str> { + let stash = create_funded_user_with_balance::("stash", n, balance); + let controller = create_funded_user_with_balance::("controller", n, balance); + let controller_lookup: ::Source = + T::Lookup::unlookup(controller.clone()); + + Staking::::bond( + RawOrigin::Signed(stash.clone()).into(), + controller_lookup, + balance, + destination, + )?; + Ok((stash, controller)) +} + /// Create a stash and controller pair, where the controller is dead, and payouts go to controller. /// This is used to test worst case payout scenarios. pub fn create_stash_and_dead_controller( @@ -101,11 +134,20 @@ pub fn create_stash_and_dead_controller( pub fn create_validators( max: u32, balance_factor: u32, +) -> Result::Source>, &'static str> { + create_validators_with_seed::(max, balance_factor, 0) +} + +/// create `max` validators, with a seed to help unintentional prevent account collisions. +pub fn create_validators_with_seed( + max: u32, + balance_factor: u32, + seed: u32, ) -> Result::Source>, &'static str> { let mut validators: Vec<::Source> = Vec::with_capacity(max as usize); for i in 0..max { let (stash, controller) = - create_stash_controller::(i, balance_factor, RewardDestination::Staked)?; + create_stash_controller::(i + seed, balance_factor, RewardDestination::Staked)?; let validator_prefs = ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }; Staking::::validate(RawOrigin::Signed(controller).into(), validator_prefs)?; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 97dfaa39c84a9..5e7fe3d6266aa 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for the module. use super::{Event, *}; -use frame_election_provider_support::{ElectionProvider, Support}; +use frame_election_provider_support::{ElectionProvider, SortedListProvider, Support}; use frame_support::{ assert_noop, assert_ok, dispatch::WithPostDispatchInfo, @@ -542,8 +542,8 @@ fn nominating_and_rewards_should_work() { total: 1000 + 800, own: 1000, others: vec![ - IndividualExposure { who: 3, value: 400 }, IndividualExposure { who: 1, value: 400 }, + IndividualExposure { who: 3, value: 400 }, ] }, ); @@ -553,8 +553,8 @@ fn nominating_and_rewards_should_work() { total: 1000 + 1200, own: 1000, others: vec![ - IndividualExposure { who: 3, value: 600 }, IndividualExposure { who: 1, value: 600 }, + IndividualExposure { who: 3, value: 600 }, ] }, ); @@ -1907,8 +1907,8 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { assert_eq!( supports, vec![ - (21, Support { total: 1800, voters: vec![(21, 1000), (3, 400), (1, 400)] }), - (31, Support { total: 2200, voters: vec![(31, 1000), (3, 600), (1, 600)] }) + (21, Support { total: 1800, voters: vec![(21, 1000), (1, 400), (3, 400)] }), + (31, Support { total: 2200, voters: vec![(31, 1000), (1, 600), (3, 600)] }) ], ); }); @@ -1952,7 +1952,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { supports, vec![ (11, Support { total: 1500, voters: vec![(11, 1000), (1, 500)] }), - (21, Support { total: 2500, voters: vec![(21, 1000), (3, 1000), (1, 500)] }) + (21, Support { total: 2500, voters: vec![(21, 1000), (1, 500), (3, 1000)] }) ], ); }); @@ -3881,11 +3881,137 @@ mod election_data_provider { } #[test] - fn respects_len_limits() { - ExtBuilder::default().build_and_execute(|| { - assert_eq!(Staking::voters(Some(1)).unwrap_err(), "Voter snapshot too big"); - assert_eq!(Staking::targets(Some(1)).unwrap_err(), "Target snapshot too big"); - }); + fn respects_snapshot_len_limits() { + ExtBuilder::default() + .set_status(41, StakerStatus::Validator) + .build_and_execute(|| { + // sum of all nominators who'd be voters (1), plus the self-votes (4). + assert_eq!( + ::SortedListProvider::count() + + >::iter().count() as u32, + 5 + ); + + // if limits is less.. + assert_eq!(Staking::voters(Some(1)).unwrap().len(), 1); + + // if limit is equal.. + assert_eq!(Staking::voters(Some(5)).unwrap().len(), 5); + + // if limit is more. + assert_eq!(Staking::voters(Some(55)).unwrap().len(), 5); + + // if target limit is more.. + assert_eq!(Staking::targets(Some(6)).unwrap().len(), 4); + assert_eq!(Staking::targets(Some(4)).unwrap().len(), 4); + + // if target limit is less, then we return an error. + assert_eq!(Staking::targets(Some(1)).unwrap_err(), "Target snapshot too big"); + }); + } + + #[test] + fn only_iterates_max_2_times_nominators_quota() { + ExtBuilder::default() + .nominate(true) // add nominator 101, who nominates [11, 21] + // the other nominators only nominate 21 + .add_staker(61, 60, 2_000, StakerStatus::::Nominator(vec![21])) + .add_staker(71, 70, 2_000, StakerStatus::::Nominator(vec![21])) + .add_staker(81, 80, 2_000, StakerStatus::::Nominator(vec![21])) + .build_and_execute(|| { + // given our nominators ordered by stake, + assert_eq!( + ::SortedListProvider::iter().collect::>(), + vec![61, 71, 81, 101] + ); + + // and total voters + assert_eq!( + ::SortedListProvider::count() + + >::iter().count() as u32, + 7 + ); + + // roll to session 5 + run_to_block(25); + + // slash 21, the only validator nominated by our first 3 nominators + add_slash(&21); + + // we take 4 voters: 2 validators and 2 nominators (so nominators quota = 2) + assert_eq!( + Staking::voters(Some(3)) + .unwrap() + .iter() + .map(|(stash, _, _)| stash) + .copied() + .collect::>(), + vec![31, 11], // 2 validators, but no nominators because we hit the quota + ); + }); + } + + // Even if some of the higher staked nominators are slashed, we still get up to max len voters + // by adding more lower staked nominators. In other words, we assert that we keep on adding + // valid nominators until we reach max len voters; which is opposed to simply stopping after we + // have iterated max len voters, but not adding all of them to voters due to some nominators not + // having valid targets. + #[test] + fn get_max_len_voters_even_if_some_nominators_are_slashed() { + ExtBuilder::default() + .nominate(true) // add nominator 101, who nominates [11, 21] + .add_staker(61, 60, 20, StakerStatus::::Nominator(vec![21])) + // 61 only nominates validator 21 ^^ + .add_staker(71, 70, 10, StakerStatus::::Nominator(vec![11, 21])) + .build_and_execute(|| { + // given our nominators ordered by stake, + assert_eq!( + ::SortedListProvider::iter().collect::>(), + vec![101, 61, 71] + ); + + // and total voters + assert_eq!( + ::SortedListProvider::count() + + >::iter().count() as u32, + 6 + ); + + // we take 5 voters + assert_eq!( + Staking::voters(Some(5)) + .unwrap() + .iter() + .map(|(stash, _, _)| stash) + .copied() + .collect::>(), + // then + vec![ + 31, 21, 11, // 3 nominators + 101, 61 // 2 validators, and 71 is excluded + ], + ); + + // roll to session 5 + run_to_block(25); + + // slash 21, the only validator nominated by 61 + add_slash(&21); + + // we take 4 voters + assert_eq!( + Staking::voters(Some(4)) + .unwrap() + .iter() + .map(|(stash, _, _)| stash) + .copied() + .collect::>(), + vec![ + 31, 11, // 2 validators (21 was slashed) + 101, 71 // 2 nominators, excluding 61 + ], + ); + }); } #[test] @@ -4232,3 +4358,28 @@ fn capped_stakers_works() { assert_ok!(Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default())); }) } + +mod sorted_list_provider { + use super::*; + use frame_election_provider_support::SortedListProvider; + + #[test] + fn re_nominate_does_not_change_counters_or_list() { + ExtBuilder::default().nominate(true).build_and_execute(|| { + // given + let pre_insert_nominator_count = Nominators::::iter().count() as u32; + assert_eq!(::SortedListProvider::count(), pre_insert_nominator_count); + assert!(Nominators::::contains_key(101)); + assert_eq!(::SortedListProvider::iter().collect::>(), vec![101]); + + // when account 101 renominates + assert_ok!(Staking::nominate(Origin::signed(100), vec![41])); + + // then counts don't change + assert_eq!(::SortedListProvider::count(), pre_insert_nominator_count); + assert_eq!(Nominators::::iter().count() as u32, pre_insert_nominator_count); + // and the list is the same + assert_eq!(::SortedListProvider::iter().collect::>(), vec![101]); + }); + } +} diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 0bcf179e29339..32c8dc80da158 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-09-04, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -85,37 +85,42 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (73_523_000 as Weight) + (73_865_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (58_129_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + (114_296_000 as Weight) + .saturating_add(T::DbWeight::get().reads(8 as Weight)) + .saturating_add(T::DbWeight::get().writes(7 as Weight)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Nominators (r:1 w:0) - // Storage: Staking Validators (r:1 w:0) + // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (61_542_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (121_737_000 as Weight) + .saturating_add(T::DbWeight::get().reads(12 as Weight)) + .saturating_add(T::DbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (53_160_000 as Weight) + (51_631_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -124,36 +129,40 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - // Storage: Staking SpanSlash (r:0 w:2) - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - (85_826_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_453_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(8 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + (101_870_000 as Weight) + .saturating_add(T::DbWeight::get().reads(13 as Weight)) + .saturating_add(T::DbWeight::get().writes(11 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) // Storage: Staking Validators (r:1 w:1) // Storage: Staking MaxValidatorsCount (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (34_936_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + (69_092_000 as Weight) + .saturating_add(T::DbWeight::get().reads(11 as Weight)) + .saturating_add(T::DbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (23_493_000 as Weight) - // Standard Error: 17_000 - .saturating_add((16_632_000 as Weight).saturating_mul(k as Weight)) + (21_468_000 as Weight) + // Standard Error: 19_000 + .saturating_add((16_415_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -165,84 +174,97 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (41_733_000 as Weight) - // Standard Error: 11_000 - .saturating_add((5_840_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) + (82_389_000 as Weight) + // Standard Error: 14_000 + .saturating_add((5_597_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (17_901_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) + (69_655_000 as Weight) + .saturating_add(T::DbWeight::get().reads(8 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (13_760_000 as Weight) + (12_770_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (28_388_000 as Weight) + (27_756_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (2_537_000 as Weight) + (2_446_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (2_749_000 as Weight) + (2_720_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (2_834_000 as Weight) + (2_711_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (2_800_000 as Weight) + (2_796_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (3_429_000 as Weight) + (3_141_000 as Weight) // Standard Error: 0 - .saturating_add((56_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (61_799_000 as Weight) + (97_394_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_451_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + .saturating_add((2_370_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(11 as Weight)) + .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (3_383_988_000 as Weight) - // Standard Error: 223_000 - .saturating_add((19_981_000 as Weight).saturating_mul(s as Weight)) + (2_783_746_000 as Weight) + // Standard Error: 182_000 + .saturating_add((16_223_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -257,9 +279,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (124_714_000 as Weight) - // Standard Error: 23_000 - .saturating_add((47_575_000 as Weight).saturating_mul(n as Weight)) + (109_233_000 as Weight) + // Standard Error: 17_000 + .saturating_add((47_612_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -277,9 +299,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (160_203_000 as Weight) - // Standard Error: 24_000 - .saturating_add((61_321_000 as Weight).saturating_mul(n as Weight)) + (177_392_000 as Weight) + // Standard Error: 20_000 + .saturating_add((60_771_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -288,12 +310,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (49_593_000 as Weight) - // Standard Error: 3_000 - .saturating_add((78_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (111_858_000 as Weight) + // Standard Error: 4_000 + .saturating_add((36_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(T::DbWeight::get().reads(9 as Weight)) + .saturating_add(T::DbWeight::get().writes(8 as Weight)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:1) @@ -306,8 +331,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 71_000 - .saturating_add((35_237_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 68_000 + .saturating_add((33_495_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) .saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -315,19 +340,22 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:1) - // Storage: Staking Validators (r:1 w:1) - // Storage: Staking CounterForValidators (r:1 w:1) - // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (72_484_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_452_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(8 as Weight)) + (100_178_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_358_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(11 as Weight)) + .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking CounterForNominators (r:1 w:0) @@ -336,7 +364,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:101 w:0) // Storage: Staking Ledger (r:101 w:0) // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: Staking Nominators (r:101 w:0) + // Storage: BagsList ListBags (r:200 w:0) + // Storage: BagsList ListNodes (r:100 w:0) + // Storage: Staking Nominators (r:100 w:0) // Storage: Staking ValidatorCount (r:1 w:0) // Storage: Staking MinimumValidatorCount (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:1) @@ -348,39 +378,43 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 856_000 - .saturating_add((305_057_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 860_000 + .saturating_add((298_721_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 43_000 - .saturating_add((47_890_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(9 as Weight)) + .saturating_add((49_427_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) + .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) } + // Storage: Staking CounterForNominators (r:1 w:0) + // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:501 w:0) // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) // Storage: Staking SlashingSpans (r:21 w:0) - // Storage: Staking Nominators (r:1001 w:0) + // Storage: BagsList ListBags (r:200 w:0) + // Storage: BagsList ListNodes (r:1000 w:0) + // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 98_000 - .saturating_add((25_610_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 98_000 - .saturating_add((28_064_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 3_346_000 - .saturating_add((18_123_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) + // Standard Error: 91_000 + .saturating_add((26_605_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 91_000 + .saturating_add((31_481_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 3_122_000 + .saturating_add((16_672_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(204 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) + .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { - (30_422_000 as Weight) - // Standard Error: 33_000 - .saturating_add((11_252_000 as Weight).saturating_mul(v as Weight)) + (0 as Weight) + // Standard Error: 34_000 + .saturating_add((10_558_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -390,20 +424,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_limits() -> Weight { - (6_486_000 as Weight) + (6_353_000 as Weight) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking ChillThreshold (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) - // Storage: Staking Validators (r:1 w:1) - // Storage: Staking MaxValidatorsCount (r:1 w:0) - // Storage: Staking CounterForValidators (r:1 w:1) - // Storage: Staking MinValidatorBond (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking MaxNominatorsCount (r:1 w:0) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (58_222_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + (83_389_000 as Weight) + .saturating_add(T::DbWeight::get().reads(11 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) } } @@ -416,37 +453,42 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (73_523_000 as Weight) + (73_865_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (58_129_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + (114_296_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(8 as Weight)) + .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Nominators (r:1 w:0) - // Storage: Staking Validators (r:1 w:0) + // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (61_542_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (121_737_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(12 as Weight)) + .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (53_160_000 as Weight) + (51_631_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -455,36 +497,40 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - // Storage: Staking SpanSlash (r:0 w:2) - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - (85_826_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_453_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(8 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + (101_870_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(13 as Weight)) + .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) // Storage: Staking Validators (r:1 w:1) // Storage: Staking MaxValidatorsCount (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (34_936_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + (69_092_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(11 as Weight)) + .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (23_493_000 as Weight) - // Standard Error: 17_000 - .saturating_add((16_632_000 as Weight).saturating_mul(k as Weight)) + (21_468_000 as Weight) + // Standard Error: 19_000 + .saturating_add((16_415_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -496,84 +542,97 @@ impl WeightInfo for () { // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (41_733_000 as Weight) - // Standard Error: 11_000 - .saturating_add((5_840_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + (82_389_000 as Weight) + // Standard Error: 14_000 + .saturating_add((5_597_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (17_901_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + (69_655_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(8 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (13_760_000 as Weight) + (12_770_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (28_388_000 as Weight) + (27_756_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (2_537_000 as Weight) + (2_446_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (2_749_000 as Weight) + (2_720_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (2_834_000 as Weight) + (2_711_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (2_800_000 as Weight) + (2_796_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (3_429_000 as Weight) + (3_141_000 as Weight) // Standard Error: 0 - .saturating_add((56_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (61_799_000 as Weight) + (97_394_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_451_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + .saturating_add((2_370_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(11 as Weight)) + .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (3_383_988_000 as Weight) - // Standard Error: 223_000 - .saturating_add((19_981_000 as Weight).saturating_mul(s as Weight)) + (2_783_746_000 as Weight) + // Standard Error: 182_000 + .saturating_add((16_223_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -588,9 +647,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (124_714_000 as Weight) - // Standard Error: 23_000 - .saturating_add((47_575_000 as Weight).saturating_mul(n as Weight)) + (109_233_000 as Weight) + // Standard Error: 17_000 + .saturating_add((47_612_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -608,9 +667,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (160_203_000 as Weight) - // Standard Error: 24_000 - .saturating_add((61_321_000 as Weight).saturating_mul(n as Weight)) + (177_392_000 as Weight) + // Standard Error: 20_000 + .saturating_add((60_771_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -619,12 +678,15 @@ impl WeightInfo for () { // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (49_593_000 as Weight) - // Standard Error: 3_000 - .saturating_add((78_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (111_858_000 as Weight) + // Standard Error: 4_000 + .saturating_add((36_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(RocksDbWeight::get().reads(9 as Weight)) + .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:1) @@ -637,8 +699,8 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 71_000 - .saturating_add((35_237_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 68_000 + .saturating_add((33_495_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) .saturating_add(RocksDbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -646,19 +708,22 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:1) - // Storage: Staking Validators (r:1 w:1) - // Storage: Staking CounterForValidators (r:1 w:1) - // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (72_484_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_452_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(8 as Weight)) + (100_178_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_358_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(11 as Weight)) + .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking CounterForNominators (r:1 w:0) @@ -667,7 +732,9 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:101 w:0) // Storage: Staking Ledger (r:101 w:0) // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: Staking Nominators (r:101 w:0) + // Storage: BagsList ListBags (r:200 w:0) + // Storage: BagsList ListNodes (r:100 w:0) + // Storage: Staking Nominators (r:100 w:0) // Storage: Staking ValidatorCount (r:1 w:0) // Storage: Staking MinimumValidatorCount (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:1) @@ -679,39 +746,43 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 856_000 - .saturating_add((305_057_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 860_000 + .saturating_add((298_721_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 43_000 - .saturating_add((47_890_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(9 as Weight)) + .saturating_add((49_427_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) + .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) } + // Storage: Staking CounterForNominators (r:1 w:0) + // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:501 w:0) // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) // Storage: Staking SlashingSpans (r:21 w:0) - // Storage: Staking Nominators (r:1001 w:0) + // Storage: BagsList ListBags (r:200 w:0) + // Storage: BagsList ListNodes (r:1000 w:0) + // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 98_000 - .saturating_add((25_610_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 98_000 - .saturating_add((28_064_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 3_346_000 - .saturating_add((18_123_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + // Standard Error: 91_000 + .saturating_add((26_605_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 91_000 + .saturating_add((31_481_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 3_122_000 + .saturating_add((16_672_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(204 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) + .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { - (30_422_000 as Weight) - // Standard Error: 33_000 - .saturating_add((11_252_000 as Weight).saturating_mul(v as Weight)) + (0 as Weight) + // Standard Error: 34_000 + .saturating_add((10_558_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -721,19 +792,22 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_limits() -> Weight { - (6_486_000 as Weight) + (6_353_000 as Weight) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking ChillThreshold (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) - // Storage: Staking Validators (r:1 w:1) - // Storage: Staking MaxValidatorsCount (r:1 w:0) - // Storage: Staking CounterForValidators (r:1 w:1) - // Storage: Staking MinValidatorBond (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking MaxNominatorsCount (r:1 w:0) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (58_222_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + (83_389_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(11 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } } diff --git a/primitives/npos-elections/src/traits.rs b/primitives/npos-elections/src/traits.rs index 45b6fa368ae2a..597d7e648fd9b 100644 --- a/primitives/npos-elections/src/traits.rs +++ b/primitives/npos-elections/src/traits.rs @@ -10,8 +10,8 @@ // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// distributed under the License is distributed on an "AS IS" BASIS, // See the License for the specific language governing permissions and // limitations under the License. @@ -22,6 +22,7 @@ use crate::{ VoteWeight, }; use codec::Encode; +use scale_info::TypeInfo; use sp_arithmetic::{ traits::{Bounded, UniqueSaturatedInto}, PerThing, @@ -72,7 +73,8 @@ where + Copy + Clone + Bounded - + Encode; + + Encode + + TypeInfo; /// The target type. Needs to be an index (convert to usize). type TargetIndex: UniqueSaturatedInto @@ -82,7 +84,8 @@ where + Copy + Clone + Bounded - + Encode; + + Encode + + TypeInfo; /// The weight/accuracy type of each vote. type Accuracy: PerThing128; diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml new file mode 100644 index 0000000000000..384307fbec9e5 --- /dev/null +++ b/utils/frame/generate-bags/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "generate-bags" +version = "3.0.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "Bag threshold generation script for pallet-bag-list" +readme = "README.md" + +[dependencies] +# FRAME +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/support" } +frame-election-provider-support = { version = "4.0.0-dev", path = "../../../frame/election-provider-support", features = ["runtime-benchmarks"] } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } +pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" } + +# primitives +sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } + +# third party +chrono = { version = "0.4.19" } +git2 = { version = "0.13.20", default-features = false } +num-format = { version = "0.4.0" } +structopt = "0.3.21" diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml new file mode 100644 index 0000000000000..7fcd981a6bbd6 --- /dev/null +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "node-runtime-generate-bags" +version = "3.0.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "Bag threshold generation script for pallet-bag-list and node-runtime." +readme = "README.md" + +[dependencies] +node-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runtime" } +generate-bags = { version = "3.0.0", path = "../" } + +# third-party +structopt = "0.3.21" diff --git a/utils/frame/generate-bags/node-runtime/src/main.rs b/utils/frame/generate-bags/node-runtime/src/main.rs new file mode 100644 index 0000000000000..5d36b381a7d0c --- /dev/null +++ b/utils/frame/generate-bags/node-runtime/src/main.rs @@ -0,0 +1,46 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Make the set of bag thresholds to be used with pallet-bags-list. + +use generate_bags::generate_thresholds; +use std::path::PathBuf; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +struct Opt { + /// How many bags to generate. + #[structopt(long, default_value = "200")] + n_bags: usize, + + /// Where to write the output. + output: PathBuf, + + /// The total issuance of the currency used to create `VoteWeight`. + #[structopt(short, long)] + total_issuance: u128, + + /// The minimum account balance (i.e. existential deposit) for the currency used to create + /// `VoteWeight`. + #[structopt(short, long)] + minimum_balance: u128, +} + +fn main() -> Result<(), std::io::Error> { + let Opt { n_bags, output, total_issuance, minimum_balance } = Opt::from_args(); + generate_thresholds::(n_bags, &output, total_issuance, minimum_balance) +} diff --git a/utils/frame/generate-bags/src/lib.rs b/utils/frame/generate-bags/src/lib.rs new file mode 100644 index 0000000000000..af9df4435bcab --- /dev/null +++ b/utils/frame/generate-bags/src/lib.rs @@ -0,0 +1,246 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Support code to ease the process of generating bag thresholds. +//! +//! NOTE: this assume the runtime implements [`pallet_staking::Config`], as it requires an +//! implementation of the traits [`frame_support::traits::Currency`] and +//! [`frame_support::traits::CurrencyToVote`]. +//! +//! The process of adding bags to a runtime requires only four steps. +//! +//! 1. Update the runtime definition. +//! +//! ```ignore +//! parameter_types!{ +//! pub const BagThresholds: &'static [u64] = &[]; +//! } +//! +//! impl pallet_bags_list::Config for Runtime { +//! // +//! type BagThresholds = BagThresholds; +//! } +//! ``` +//! +//! 2. Write a little program to generate the definitions. This program exists only to hook together +//! the runtime definitions with the various calculations here. Take a look at +//! _utils/frame/generate_bags/node-runtime_ for an example. +//! +//! 3. Run that program: +//! +//! ```sh,notrust +//! $ cargo run -p node-runtime-generate-bags -- --total-issuance 1234 --minimum-balance 1 +//! output.rs ``` +//! +//! 4. Update the runtime definition. +//! +//! ```diff,notrust +//! + mod output; +//! - pub const BagThresholds: &'static [u64] = &[]; +//! + pub const BagThresholds: &'static [u64] = &output::THRESHOLDS; +//! ``` + +use frame_election_provider_support::VoteWeight; +use frame_support::traits::Get; +use std::{ + io::Write, + path::{Path, PathBuf}, +}; + +/// Compute the existential weight for the specified configuration. +/// +/// Note that this value depends on the current issuance, a quantity known to change over time. +/// This makes the project of computing a static value suitable for inclusion in a static, +/// generated file _excitingly unstable_. +fn existential_weight( + total_issuance: u128, + minimum_balance: u128, +) -> VoteWeight { + use frame_support::traits::CurrencyToVote; + use std::convert::TryInto; + + T::CurrencyToVote::to_vote( + minimum_balance + .try_into() + .map_err(|_| "failed to convert minimum_balance to type Balance") + .unwrap(), + total_issuance + .try_into() + .map_err(|_| "failed to convert total_issuance to type Balance") + .unwrap(), + ) +} + +/// Return the path to a header file used in this repository if is exists. +/// +/// Just searches the git working directory root for files matching certain patterns; it's +/// pretty naive. +fn path_to_header_file() -> Option { + let repo = git2::Repository::open_from_env().ok()?; + let workdir = repo.workdir()?; + for file_name in &["HEADER-APACHE2", "HEADER-GPL3", "HEADER", "file_header.txt"] { + let path = workdir.join(file_name); + if path.exists() { + return Some(path) + } + } + None +} + +/// Create an underscore formatter: a formatter which inserts `_` every 3 digits of a number. +fn underscore_formatter() -> num_format::CustomFormat { + num_format::CustomFormat::builder() + .grouping(num_format::Grouping::Standard) + .separator("_") + .build() + .expect("format described here meets all constraints") +} + +/// Compute the constant ratio for the thresholds. +/// +/// This ratio ensures that each bag, with the possible exceptions of certain small ones and the +/// final one, is a constant multiple of the previous, while fully occupying the `VoteWeight` +/// space. +pub fn constant_ratio(existential_weight: VoteWeight, n_bags: usize) -> f64 { + ((VoteWeight::MAX as f64 / existential_weight as f64).ln() / ((n_bags - 1) as f64)).exp() +} + +/// Compute the list of bag thresholds. +/// +/// Returns a list of exactly `n_bags` elements, except in the case of overflow. +/// The first element is always `existential_weight`. +/// The last element is always `VoteWeight::MAX`. +/// +/// All other elements are computed from the previous according to the formula +/// `threshold[k + 1] = (threshold[k] * ratio).max(threshold[k] + 1); +pub fn thresholds( + existential_weight: VoteWeight, + constant_ratio: f64, + n_bags: usize, +) -> Vec { + const WEIGHT_LIMIT: f64 = VoteWeight::MAX as f64; + + let mut thresholds = Vec::with_capacity(n_bags); + + if n_bags > 1 { + thresholds.push(existential_weight); + } + + while n_bags > 0 && thresholds.len() < n_bags - 1 { + let last = thresholds.last().copied().unwrap_or(existential_weight); + let successor = (last as f64 * constant_ratio).round().max(last as f64 + 1.0); + if successor < WEIGHT_LIMIT { + thresholds.push(successor as VoteWeight); + } else { + eprintln!("unexpectedly exceeded weight limit; breaking threshold generation loop"); + break + } + } + + thresholds.push(VoteWeight::MAX); + + debug_assert_eq!(thresholds.len(), n_bags); + debug_assert!(n_bags == 0 || thresholds[0] == existential_weight); + debug_assert!(n_bags == 0 || thresholds[thresholds.len() - 1] == VoteWeight::MAX); + + thresholds +} + +/// Write a thresholds module to the path specified. +/// +/// Parameters: +/// - `n_bags` the number of bags to generate. +/// - `output` the path to write to; should terminate with a Rust module name, i.e. +/// `foo/bar/thresholds.rs`. +/// - `total_issuance` the total amount of the currency in the network. +/// - `minimum_balance` the minimum balance of the currency required for an account to exist (i.e. +/// existential deposit). +/// +/// This generated module contains, in order: +/// +/// - The contents of the header file in this repository's root, if found. +/// - Module documentation noting that this is autogenerated and when. +/// - Some associated constants. +/// - The constant array of thresholds. +pub fn generate_thresholds( + n_bags: usize, + output: &Path, + total_issuance: u128, + minimum_balance: u128, +) -> Result<(), std::io::Error> { + // ensure the file is accessable + if let Some(parent) = output.parent() { + if !parent.exists() { + std::fs::create_dir_all(parent)?; + } + } + + // copy the header file + if let Some(header_path) = path_to_header_file() { + std::fs::copy(header_path, output)?; + } + + // open an append buffer + let file = std::fs::OpenOptions::new().create(true).append(true).open(output)?; + let mut buf = std::io::BufWriter::new(file); + + // create underscore formatter and format buffer + let mut num_buf = num_format::Buffer::new(); + let format = underscore_formatter(); + + // module docs + let now = chrono::Utc::now(); + writeln!(buf)?; + writeln!(buf, "//! Autogenerated bag thresholds.")?; + writeln!(buf, "//!")?; + writeln!(buf, "//! Generated on {}", now.to_rfc3339())?; + writeln!( + buf, + "//! for the {} runtime.", + ::Version::get().spec_name, + )?; + + let existential_weight = existential_weight::(total_issuance, minimum_balance); + num_buf.write_formatted(&existential_weight, &format); + writeln!(buf)?; + writeln!(buf, "/// Existential weight for this runtime.")?; + writeln!(buf, "#[cfg(any(test, feature = \"std\"))]")?; + writeln!(buf, "#[allow(unused)]")?; + writeln!(buf, "pub const EXISTENTIAL_WEIGHT: u64 = {};", num_buf.as_str())?; + + // constant ratio + let constant_ratio = constant_ratio(existential_weight, n_bags); + writeln!(buf)?; + writeln!(buf, "/// Constant ratio between bags for this runtime.")?; + writeln!(buf, "#[cfg(any(test, feature = \"std\"))]")?; + writeln!(buf, "#[allow(unused)]")?; + writeln!(buf, "pub const CONSTANT_RATIO: f64 = {:.16};", constant_ratio)?; + + // thresholds + let thresholds = thresholds(existential_weight, constant_ratio, n_bags); + writeln!(buf)?; + writeln!(buf, "/// Upper thresholds delimiting the bag list.")?; + writeln!(buf, "pub const THRESHOLDS: [u64; {}] = [", thresholds.len())?; + for threshold in thresholds { + num_buf.write_formatted(&threshold, &format); + // u64::MAX, with spacers every 3 digits, is 26 characters wide + writeln!(buf, " {:>26},", num_buf.as_str())?; + } + writeln!(buf, "];")?; + + Ok(()) +} From 91b386ff07a85b3dd50ff3ed29c97e6b29d15f05 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Sun, 19 Sep 2021 05:25:30 +1200 Subject: [PATCH 0002/1472] make nonce public (#9810) --- frame/system/src/extensions/check_nonce.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/system/src/extensions/check_nonce.rs b/frame/system/src/extensions/check_nonce.rs index 081a0efa3db71..74be83398421e 100644 --- a/frame/system/src/extensions/check_nonce.rs +++ b/frame/system/src/extensions/check_nonce.rs @@ -34,7 +34,7 @@ use sp_std::vec; /// extension sets some kind of priority upon validating transactions. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] -pub struct CheckNonce(#[codec(compact)] T::Index); +pub struct CheckNonce(#[codec(compact)] pub T::Index); impl CheckNonce { /// utility constructor. Used only in client/factory code. From 58256613b50e6b3dc4dd6e20b463df0435104bb9 Mon Sep 17 00:00:00 2001 From: Jimmy Chu Date: Mon, 20 Sep 2021 18:50:15 +0800 Subject: [PATCH 0003/1472] Added template and scripts for generating rustdocs (#9785) Co-authored-by: Denis Pisarev --- .gitlab-ci.yml | 46 +++++++++++++++++++++++++----- .maintain/docs-index-tpl.ejs | 55 ++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 .maintain/docs-index-tpl.ejs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ecafc9338a587..70a8fd9bbbe93 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -618,6 +618,7 @@ build-rustdoc: variables: <<: *default-vars SKIP_WASM_BUILD: 1 + DOC_INDEX_PAGE: "sc_service/index.html" # default redirected page artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" when: on_success @@ -632,7 +633,7 @@ build-rustdoc: - mv ./target/doc ./crate-docs # FIXME: remove me after CI image gets nonroot - chown -R nonroot:nonroot ./crate-docs - - echo "" > ./crate-docs/index.html + - echo "" > ./crate-docs/index.html - sccache -s #### stage: publish @@ -728,42 +729,73 @@ publish-rustdoc: stage: publish <<: *kubernetes-env <<: *vault-secrets - image: paritytech/tools:latest + image: node:16 variables: GIT_DEPTH: 100 + # --- Following variables are for rustdocs deployment --- + # Space separated values of branches and tags to generate rustdocs + RUSTDOCS_DEPLOY_REFS: "master monthly-2021-09+1 monthly-2021-08 v3.0.0" + # Location of the docs index template + INDEX_TPL: ".maintain/docs-index-tpl.ejs" + # Where the `/latest` symbolic link links to. One of the $RUSTDOCS_DEPLOY_REFS value. + LATEST: "monthly-2021-09+1" rules: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME == "master" + - if: $CI_COMMIT_REF_NAME =~ /^monthly-20[0-9]{2}-[0-9]{2}.*$/ # to support: monthly-2021-09+1 + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 # `needs:` can be removed after CI image gets nonroot. In this case `needs:` stops other # artifacts from being dowloaded by this job. needs: - job: build-rustdoc artifacts: true script: + # If $CI_COMMIT_REF_NAME doesn't match one of $RUSTDOCS_DEPLOY_REFS space-separated values, we + # exit immediately. + # Putting spaces at the front and back to ensure we are not matching just any substring, but the + # whole space-separated value. + - '[[ " ${RUSTDOCS_DEPLOY_REFS} " =~ " ${CI_COMMIT_REF_NAME} " ]] || exit 0' - rm -rf /tmp/* # Set git config - rm -rf .git/config - git config user.email "devops-team@parity.io" - git config user.name "${GITHUB_USER}" - - git config remote.origin.url "https://${GITHUB_TOKEN}@github.com/paritytech/substrate.git" + - git config remote.origin.url "https://${GITHUB_TOKEN}@github.com/paritytech/${CI_PROJECT_NAME}.git" - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch origin gh-pages + # Install `ejs` and generate index.html based on RUSTDOCS_DEPLOY_REFS + - yarn global add ejs + - 'ejs ${INDEX_TPL} -i "{\"deploy_refs\":\"${RUSTDOCS_DEPLOY_REFS}\",\"repo_name\":\"${CI_PROJECT_NAME}\",\"latest\":\"${LATEST}\"}" > /tmp/index.html' # Save README and docs - cp -r ./crate-docs/ /tmp/doc/ - cp README.md /tmp/doc/ - git checkout gh-pages - # Remove everything and restore generated docs and README - - rm -rf ./* - - mv /tmp/doc/* . + # Remove directories no longer necessary, as specified in $RUSTDOCS_DEPLOY_REFS. + # Also ensure $RUSTDOCS_DEPLOY_REFS is non-space + - if [[ ! -z ${RUSTDOCS_DEPLOY_REFS// } ]]; then + for FILE in *; do + if [[ ! " $RUSTDOCS_DEPLOY_REFS " =~ " $FILE " ]]; then + echo "Removing ${FILE}..." + rm -rf $FILE + fi + done + fi + # Move the index page & built back + - mv -f /tmp/index.html . + # Ensure the destination dir doesn't exist. + - rm -rf ${CI_COMMIT_REF_NAME} + - mv -f /tmp/doc ${CI_COMMIT_REF_NAME} + # Add the symlink + - '[[ -e "$LATEST" ]] && ln -sf "${LATEST}" latest' # Upload files - git add --all --force # `git commit` has an exit code of > 0 if there is nothing to commit. # This causes GitLab to exit immediately and marks this job failed. # We don't want to mark the entire job failed if there's nothing to # publish though, hence the `|| true`. - - git commit -m "Updated docs for ${CI_COMMIT_REF_NAME}" || + - git commit -m "___Updated docs for ${CI_COMMIT_REF_NAME}___" || echo "___Nothing to commit___" - git push origin gh-pages --force after_script: diff --git a/.maintain/docs-index-tpl.ejs b/.maintain/docs-index-tpl.ejs new file mode 100644 index 0000000000000..81c619a926b2b --- /dev/null +++ b/.maintain/docs-index-tpl.ejs @@ -0,0 +1,55 @@ +<% + const capFirst = s => (s && s[0].toUpperCase() + s.slice(1)) || ""; +%> + + + + + + + + <%= capFirst(repo_name) %> Rustdocs + + + + + + +
+
+

<%= capFirst(repo_name) %> Rustdocs

+
+
    + <%_ deploy_refs.split(/\s+/).forEach(ref => { _%> +
  • + <%- ref -%> + <%_ if (latest && latest.trim() !== '' && latest === ref) { _%> + (latest) + <%_ } _%> +
  • + <%_ }) _%> +
+
+
+
+ + From e30db04a7ec3b259e66d7b0334e42e538ed69b96 Mon Sep 17 00:00:00 2001 From: Georges Date: Mon, 20 Sep 2021 11:56:43 +0100 Subject: [PATCH 0004/1472] Generate storage info for pallet im_online (#9654) * Integrating WrapperOpaque from PR #9738 * Adding storage_info to pallet im-online Changing some `Vec` to `WeakBoundedVec` Adding the following bounds: * `MaxKeys * `MaxPeerInHeartbeats` * `MaxPeerDataEncodingSize` to limit the size of `WeakBoundedVec` * Fix syntax * Need to clone keys * Changes in formatting --- bin/node/runtime/src/lib.rs | 6 ++ frame/im-online/src/benchmarking.rs | 6 +- frame/im-online/src/lib.rs | 133 +++++++++++++++++++++--- frame/im-online/src/mock.rs | 6 ++ frame/offences/benchmarking/src/mock.rs | 6 ++ frame/session/src/lib.rs | 4 +- frame/support/src/traits.rs | 2 +- frame/support/src/traits/misc.rs | 49 ++++++++- frame/support/src/traits/validation.rs | 4 +- primitives/runtime/src/testing.rs | 3 +- 10 files changed, 196 insertions(+), 23 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 9e8adfcd0910e..28f8e5dc3fd6a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -932,6 +932,9 @@ parameter_types! { /// We prioritize im-online heartbeats over election solution submission. pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2; pub const MaxAuthorities: u32 = 100; + pub const MaxKeys: u32 = 10_000; + pub const MaxPeerInHeartbeats: u32 = 10_000; + pub const MaxPeerDataEncodingSize: u32 = 1_000; } impl frame_system::offchain::CreateSignedTransaction for Runtime @@ -996,6 +999,9 @@ impl pallet_im_online::Config for Runtime { type ReportUnresponsiveness = Offences; type UnsignedPriority = ImOnlineUnsignedPriority; type WeightInfo = pallet_im_online::weights::SubstrateWeight; + type MaxKeys = MaxKeys; + type MaxPeerInHeartbeats = MaxPeerInHeartbeats; + type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize; } impl pallet_offences::Config for Runtime { diff --git a/frame/im-online/src/benchmarking.rs b/frame/im-online/src/benchmarking.rs index 1043a97f67def..20812f03d28dd 100644 --- a/frame/im-online/src/benchmarking.rs +++ b/frame/im-online/src/benchmarking.rs @@ -22,7 +22,7 @@ use super::*; use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; -use frame_support::traits::UnfilteredDispatchable; +use frame_support::{traits::UnfilteredDispatchable, WeakBoundedVec}; use frame_system::RawOrigin; use sp_core::{offchain::OpaqueMultiaddr, OpaquePeerId}; use sp_runtime::{ @@ -46,7 +46,9 @@ pub fn create_heartbeat( for _ in 0..k { keys.push(T::AuthorityId::generate_pair(None)); } - Keys::::put(keys.clone()); + let bounded_keys = WeakBoundedVec::<_, T::MaxKeys>::try_from(keys.clone()) + .map_err(|()| "More than the maximum number of keys provided")?; + Keys::::put(bounded_keys); let network_state = OpaqueNetworkState { peer_id: OpaquePeerId::default(), diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index ab4f7001574e5..2fcaed1820ff9 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -74,9 +74,14 @@ mod mock; mod tests; pub mod weights; -use codec::{Decode, Encode}; -use frame_support::traits::{ - EstimateNextSessionRotation, OneSessionHandler, ValidatorSet, ValidatorSetWithIdentification, +use codec::{Decode, Encode, MaxEncodedLen}; +use core::convert::TryFrom; +use frame_support::{ + traits::{ + EstimateNextSessionRotation, Get, OneSessionHandler, ValidatorSet, + ValidatorSetWithIdentification, WrapperOpaque, + }, + BoundedSlice, WeakBoundedVec, }; use frame_system::offchain::{SendTransactionTypes, SubmitTransaction}; pub use pallet::*; @@ -220,6 +225,65 @@ where pub validators_len: u32, } +/// A type that is the same as [`OpaqueNetworkState`] but with [`Vec`] replaced with +/// [`WeakBoundedVec`] where Limit is the respective size limit +/// `PeerIdEncodingLimit` represents the size limit of the encoding of `PeerId` +/// `MultiAddrEncodingLimit` represents the size limit of the encoding of `MultiAddr` +/// `AddressesLimit` represents the size limit of the vector of peers connected +#[derive(Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[codec(mel_bound(PeerIdEncodingLimit: Get, + MultiAddrEncodingLimit: Get, AddressesLimit: Get))] +#[scale_info(skip_type_params(PeerIdEncodingLimit, MultiAddrEncodingLimit, AddressesLimit))] +pub struct BoundedOpaqueNetworkState +where + PeerIdEncodingLimit: Get, + MultiAddrEncodingLimit: Get, + AddressesLimit: Get, +{ + /// PeerId of the local node in SCALE encoded. + pub peer_id: WeakBoundedVec, + /// List of addresses the node knows it can be reached as. + pub external_addresses: + WeakBoundedVec, AddressesLimit>, +} + +impl, MultiAddrEncodingLimit: Get, AddressesLimit: Get> + BoundedOpaqueNetworkState +{ + fn force_from(ons: &OpaqueNetworkState) -> Self { + let peer_id = WeakBoundedVec::<_, PeerIdEncodingLimit>::force_from( + ons.peer_id.0.clone(), + Some( + "Warning: The size of the encoding of PeerId \ + is bigger than expected. A runtime configuration \ + adjustment may be needed.", + ), + ); + + let external_addresses = WeakBoundedVec::<_, AddressesLimit>::force_from( + ons.external_addresses + .iter() + .map(|x| { + WeakBoundedVec::<_, MultiAddrEncodingLimit>::force_from( + x.0.clone(), + Some( + "Warning: The size of the encoding of MultiAddr \ + is bigger than expected. A runtime configuration \ + adjustment may be needed.", + ), + ) + }) + .collect(), + Some( + "Warning: The network has more peers than expected \ + A runtime configuration adjustment may be needed.", + ), + ); + + Self { peer_id, external_addresses } + } +} + /// A type for representing the validator id in a session. pub type ValidatorId = <::ValidatorSet as ValidatorSet< ::AccountId, @@ -251,6 +315,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] @@ -261,7 +326,18 @@ pub mod pallet { + RuntimeAppPublic + Default + Ord - + MaybeSerializeDeserialize; + + MaybeSerializeDeserialize + + MaxEncodedLen; + + /// The maximum number of keys that can be added. + type MaxKeys: Get; + + /// The maximum number of peers to be stored in `ReceivedHeartbeats` + type MaxPeerInHeartbeats: Get; + + /// The maximum size of the encoding of `PeerId` and `MultiAddr` that are coming + /// from the hearbeat + type MaxPeerDataEncodingSize: Get; /// The overarching event type. type Event: From> + IsType<::Event>; @@ -333,14 +409,27 @@ pub mod pallet { /// The current set of keys that may issue a heartbeat. #[pallet::storage] #[pallet::getter(fn keys)] - pub(crate) type Keys = StorageValue<_, Vec, ValueQuery>; + pub(crate) type Keys = + StorageValue<_, WeakBoundedVec, ValueQuery>; - /// For each session index, we keep a mapping of `AuthIndex` to - /// `offchain::OpaqueNetworkState`. + /// For each session index, we keep a mapping of 'SessionIndex` and `AuthIndex` to + /// `WrapperOpaque`. #[pallet::storage] #[pallet::getter(fn received_heartbeats)] - pub(crate) type ReceivedHeartbeats = - StorageDoubleMap<_, Twox64Concat, SessionIndex, Twox64Concat, AuthIndex, Vec>; + pub(crate) type ReceivedHeartbeats = StorageDoubleMap< + _, + Twox64Concat, + SessionIndex, + Twox64Concat, + AuthIndex, + WrapperOpaque< + BoundedOpaqueNetworkState< + T::MaxPeerDataEncodingSize, + T::MaxPeerDataEncodingSize, + T::MaxPeerInHeartbeats, + >, + >, + >; /// For each session index, we keep a mapping of `ValidatorId` to the /// number of blocks authored by the given authority. @@ -409,11 +498,15 @@ pub mod pallet { if let (false, Some(public)) = (exists, public) { Self::deposit_event(Event::::HeartbeatReceived(public.clone())); - let network_state = heartbeat.network_state.encode(); + let network_state_bounded = BoundedOpaqueNetworkState::< + T::MaxPeerDataEncodingSize, + T::MaxPeerDataEncodingSize, + T::MaxPeerInHeartbeats, + >::force_from(&heartbeat.network_state); ReceivedHeartbeats::::insert( ¤t_session, &heartbeat.authority_index, - &network_state, + WrapperOpaque::from(network_state_bounded), ); Ok(()) @@ -739,13 +832,17 @@ impl Pallet { fn initialize_keys(keys: &[T::AuthorityId]) { if !keys.is_empty() { assert!(Keys::::get().is_empty(), "Keys are already initialized!"); - Keys::::put(keys); + let bounded_keys = >::try_from(keys) + .expect("More than the maximum number of keys provided"); + Keys::::put(bounded_keys); } } #[cfg(test)] fn set_keys(keys: Vec) { - Keys::::put(&keys) + let bounded_keys = WeakBoundedVec::<_, T::MaxKeys>::try_from(keys) + .expect("More than the maximum number of keys provided"); + Keys::::put(bounded_keys); } } @@ -776,7 +873,15 @@ impl OneSessionHandler for Pallet { >::put(block_number + half_session); // Remember who the authorities are for the new session. - Keys::::put(validators.map(|x| x.1).collect::>()); + let keys = validators.map(|x| x.1).collect::>(); + let bounded_keys = WeakBoundedVec::<_, T::MaxKeys>::force_from( + keys, + Some( + "Warning: The session has more keys than expected. \ + A runtime configuration adjustment may be needed.", + ), + ); + Keys::::put(bounded_keys); } fn on_before_session_ending() { diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index e4031b04271b9..92d1fe8e3f8b9 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -217,6 +217,9 @@ impl frame_support::traits::EstimateNextSessionRotation for TestNextSession parameter_types! { pub const UnsignedPriority: u64 = 1 << 20; + pub const MaxKeys: u32 = 10_000; + pub const MaxPeerInHeartbeats: u32 = 10_000; + pub const MaxPeerDataEncodingSize: u32 = 1_000; } impl Config for Runtime { @@ -227,6 +230,9 @@ impl Config for Runtime { type ReportUnresponsiveness = OffenceHandler; type UnsignedPriority = UnsignedPriority; type WeightInfo = (); + type MaxKeys = MaxKeys; + type MaxPeerInHeartbeats = MaxPeerInHeartbeats; + type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize; } impl frame_system::offchain::SendTransactionTypes for Runtime diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 82662295dea84..6973e25371d4f 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -146,6 +146,9 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxKeys: u32 = 10_000; + pub const MaxPeerInHeartbeats: u32 = 10_000; + pub const MaxPeerDataEncodingSize: u32 = 1_000; } pub type Extrinsic = sp_runtime::testing::TestXt; @@ -186,6 +189,9 @@ impl pallet_im_online::Config for Test { type ReportUnresponsiveness = Offences; type UnsignedPriority = (); type WeightInfo = (); + type MaxKeys = MaxKeys; + type MaxPeerInHeartbeats = MaxPeerInHeartbeats; + type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize; } impl pallet_offences::Config for Test { diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 3f5d853d4fa21..e57decec8c651 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -114,7 +114,7 @@ mod mock; mod tests; pub mod weights; -use codec::Decode; +use codec::{Decode, MaxEncodedLen}; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, dispatch::{self, DispatchError, DispatchResult}, @@ -367,7 +367,7 @@ pub trait Config: frame_system::Config { type Event: From + Into<::Event>; /// A stable ID for a validator. - type ValidatorId: Member + Parameter; + type ValidatorId: Member + Parameter + MaxEncodedLen; /// A conversion from account ID to validator ID. /// diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index efb5559ed0622..d5d0decd117eb 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -52,7 +52,7 @@ mod misc; pub use misc::{ Backing, ConstU32, EnsureInherentsAreFirst, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, - OnKilledAccount, OnNewAccount, SameOrOther, Time, TryDrop, UnixTime, + OnKilledAccount, OnNewAccount, SameOrOther, Time, TryDrop, UnixTime, WrapperOpaque, }; mod stored_map; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 1776e1ba320ea..75f2f8ac3fef1 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -17,8 +17,10 @@ //! Smaller traits used in FRAME which don't need their own file. -use crate::dispatch::Parameter; +use crate::{dispatch::Parameter, TypeInfo}; +use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen}; use sp_runtime::{traits::Block as BlockT, DispatchError}; +use sp_std::vec::Vec; /// Anything that can have a `::len()` method. pub trait Len { @@ -377,3 +379,48 @@ impl, const T: u32> EstimateCallFee for T.into() } } + +/// A wrapper for any type `T` which implement encode/decode in a way compatible with `Vec`. +/// +/// The encoding is the encoding of `T` prepended with the compact encoding of its size in bytes. +/// Thus the encoded value can be decoded as a `Vec`. +#[derive(Debug, Eq, PartialEq, Default, Clone, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +pub struct WrapperOpaque(pub T); + +impl EncodeLike for WrapperOpaque {} + +impl Encode for WrapperOpaque { + fn size_hint(&self) -> usize { + // Compact usually takes at most 4 bytes + self.0.size_hint().saturating_add(4) + } + + fn encode_to(&self, dest: &mut O) { + self.0.encode().encode_to(dest); + } + + fn encode(&self) -> Vec { + self.0.encode().encode() + } + + fn using_encoded R>(&self, f: F) -> R { + self.0.encode().using_encoded(f) + } +} + +impl Decode for WrapperOpaque { + fn decode(input: &mut I) -> Result { + Ok(Self(T::decode(&mut &>::decode(input)?[..])?)) + } + + fn skip(input: &mut I) -> Result<(), codec::Error> { + >::skip(input) + } +} + +impl From for WrapperOpaque { + fn from(t: T) -> Self { + Self(t) + } +} diff --git a/frame/support/src/traits/validation.rs b/frame/support/src/traits/validation.rs index f4107ef6e2b02..11ea5a79f67ba 100644 --- a/frame/support/src/traits/validation.rs +++ b/frame/support/src/traits/validation.rs @@ -18,7 +18,7 @@ //! Traits for dealing with validation and validators. use crate::{dispatch::Parameter, weights::Weight}; -use codec::{Codec, Decode}; +use codec::{Codec, Decode, MaxEncodedLen}; use sp_runtime::{ traits::{Convert, Zero}, BoundToRuntimeAppPublic, ConsensusEngineId, Permill, RuntimeAppPublic, @@ -31,7 +31,7 @@ use sp_std::prelude::*; /// Something that can give information about the current validator set. pub trait ValidatorSet { /// Type for representing validator id in a session. - type ValidatorId: Parameter; + type ValidatorId: Parameter + MaxEncodedLen; /// A type for converting `AccountId` to `ValidatorId`. type ValidatorIdOf: Convert>; diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index 781f342d43c1e..fe9ba588adb87 100644 --- a/primitives/runtime/src/testing.rs +++ b/primitives/runtime/src/testing.rs @@ -18,7 +18,7 @@ //! Testing utilities. use crate::{ - codec::{Codec, Decode, Encode}, + codec::{Codec, Decode, Encode, MaxEncodedLen}, generic, scale_info::TypeInfo, traits::{ @@ -59,6 +59,7 @@ use std::{ Deserialize, PartialOrd, Ord, + MaxEncodedLen, TypeInfo, )] pub struct UintAuthorityId(pub u64); From 50c84cb8f92b6446b4a7b3043684b116aaea6866 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Mon, 20 Sep 2021 16:49:04 +0200 Subject: [PATCH 0005/1472] add feature and fix ci (#9800) --- .gitlab-ci.yml | 2 +- frame/support/test/Cargo.toml | 2 ++ frame/support/test/tests/construct_runtime_ui.rs | 1 + frame/support/test/tests/decl_module_ui.rs | 1 + frame/support/test/tests/decl_storage_ui.rs | 1 + frame/support/test/tests/derive_no_bound_ui.rs | 1 + frame/support/test/tests/pallet_ui.rs | 1 + 7 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 70a8fd9bbbe93..fd7bfe7155918 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -516,7 +516,7 @@ test-wasmer-sandbox: variables: <<: *default-vars script: - - time cargo test --release --features runtime-benchmarks,wasmer-sandbox + - time cargo test --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests - sccache -s cargo-check-macos: diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index e12880871e5c2..863afceac4a98 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -48,3 +48,5 @@ try-runtime = ["frame-support/try-runtime"] # WARNING: CI only execute pallet test with this feature, # if the feature intended to be used outside, CI and this message need to be updated. conditional-storage = [] +# Disable ui tests +disable-ui-tests = [] diff --git a/frame/support/test/tests/construct_runtime_ui.rs b/frame/support/test/tests/construct_runtime_ui.rs index a55e800628582..ee475e37605ef 100644 --- a/frame/support/test/tests/construct_runtime_ui.rs +++ b/frame/support/test/tests/construct_runtime_ui.rs @@ -18,6 +18,7 @@ use std::env; #[rustversion::attr(not(stable), ignore)] +#[cfg(not(feature = "disable-ui-tests"))] #[test] fn ui() { // As trybuild is using `cargo check`, we don't need the real WASM binaries. diff --git a/frame/support/test/tests/decl_module_ui.rs b/frame/support/test/tests/decl_module_ui.rs index 2c097bb6e1332..e84025b9f2564 100644 --- a/frame/support/test/tests/decl_module_ui.rs +++ b/frame/support/test/tests/decl_module_ui.rs @@ -16,6 +16,7 @@ // limitations under the License. #[rustversion::attr(not(stable), ignore)] +#[cfg(not(feature = "disable-ui-tests"))] #[test] fn decl_module_ui() { // As trybuild is using `cargo check`, we don't need the real WASM binaries. diff --git a/frame/support/test/tests/decl_storage_ui.rs b/frame/support/test/tests/decl_storage_ui.rs index 99d2da87aca28..400ddfc0f94f4 100644 --- a/frame/support/test/tests/decl_storage_ui.rs +++ b/frame/support/test/tests/decl_storage_ui.rs @@ -16,6 +16,7 @@ // limitations under the License. #[rustversion::attr(not(stable), ignore)] +#[cfg(not(feature = "disable-ui-tests"))] #[test] fn decl_storage_ui() { // As trybuild is using `cargo check`, we don't need the real WASM binaries. diff --git a/frame/support/test/tests/derive_no_bound_ui.rs b/frame/support/test/tests/derive_no_bound_ui.rs index 434671e19b105..22c116931a47e 100644 --- a/frame/support/test/tests/derive_no_bound_ui.rs +++ b/frame/support/test/tests/derive_no_bound_ui.rs @@ -16,6 +16,7 @@ // limitations under the License. #[rustversion::attr(not(stable), ignore)] +#[cfg(not(feature = "disable-ui-tests"))] #[test] fn derive_no_bound_ui() { // As trybuild is using `cargo check`, we don't need the real WASM binaries. diff --git a/frame/support/test/tests/pallet_ui.rs b/frame/support/test/tests/pallet_ui.rs index e5f4a54dfb000..6f56c1efd6d73 100644 --- a/frame/support/test/tests/pallet_ui.rs +++ b/frame/support/test/tests/pallet_ui.rs @@ -16,6 +16,7 @@ // limitations under the License. #[rustversion::attr(not(stable), ignore)] +#[cfg(not(feature = "disable-ui-tests"))] #[test] fn pallet_ui() { // As trybuild is using `cargo check`, we don't need the real WASM binaries. From 0997854ccfd977783591f40f93cd0294e51c3631 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 21 Sep 2021 14:32:13 +0300 Subject: [PATCH 0006/1472] Don't answer peers with a low reputation (#9008) * Init architecture for not answering peers with a low reputation * Get reputation inside of RequestResponsesBehaviour::poll * Filter reputation in RequestResponsesBehaviour * Pass PeersetHandle to RequestResponsesBehaviour * Add more docs * Fix tests compilation * Fix compiler warnings (still FIXME) * Fix tests * Fmt code --- client/network/src/behaviour.rs | 3 + client/network/src/request_responses.rs | 215 +++++++++++++++++++----- client/network/src/service.rs | 1 + client/peerset/src/lib.rs | 22 ++- 4 files changed, 193 insertions(+), 48 deletions(-) diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 08d061ee26b23..7b334175a2805 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -38,6 +38,7 @@ use libp2p::{ use log::debug; use prost::Message; use sc_consensus::import_queue::{IncomingBlock, Origin}; +use sc_peerset::PeersetHandle; use sp_consensus::BlockOrigin; use sp_runtime::{ traits::{Block as BlockT, NumberFor}, @@ -206,6 +207,7 @@ impl Behaviour { light_client_request_protocol_config: request_responses::ProtocolConfig, // All remaining request protocol configs. mut request_response_protocols: Vec, + peerset: PeersetHandle, ) -> Result { // Extract protocol name and add to `request_response_protocols`. let block_request_protocol_name = block_request_protocol_config.name.to_string(); @@ -229,6 +231,7 @@ impl Behaviour { bitswap: bitswap.into(), request_responses: request_responses::RequestResponsesBehaviour::new( request_response_protocols.into_iter(), + peerset, )?, light_client_request_sender, events: VecDeque::new(), diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 6ebc7416c2a35..0908d7510e359 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -64,6 +64,7 @@ use std::{ }; pub use libp2p::request_response::{InboundFailure, OutboundFailure, RequestId}; +use sc_peerset::{PeersetHandle, BANNED_THRESHOLD}; /// Configuration for a single request-response protocol. #[derive(Debug, Clone)] @@ -256,6 +257,27 @@ pub struct RequestResponsesBehaviour { /// Whenever a response is received on `pending_responses`, insert a channel to be notified /// when the request has been sent out. send_feedback: HashMap>, + + /// Primarily used to get a reputation of a node. + peerset: PeersetHandle, + + /// Pending message request, holds `MessageRequest` as a Future state to poll it + /// until we get a response from `Peerset` + message_request: Option, +} + +// This is a state of processing incoming request Message. +// The main reason of this struct is to hold `get_peer_reputation` as a Future state. +struct MessageRequest { + peer: PeerId, + request_id: RequestId, + request: Vec, + channel: ResponseChannel, ()>>, + protocol: String, + resp_builder: Option>, + // Once we get incoming request we save all params, create an async call to Peerset + // to get the reputation of the peer. + get_peer_reputation: Pin> + Send>>, } /// Generated by the response builder and waiting to be processed. @@ -270,7 +292,10 @@ struct RequestProcessingOutcome { impl RequestResponsesBehaviour { /// Creates a new behaviour. Must be passed a list of supported protocols. Returns an error if /// the same protocol is passed twice. - pub fn new(list: impl Iterator) -> Result { + pub fn new( + list: impl Iterator, + peerset: PeersetHandle, + ) -> Result { let mut protocols = HashMap::new(); for protocol in list { let mut cfg = RequestResponseConfig::default(); @@ -304,6 +329,8 @@ impl RequestResponsesBehaviour { pending_responses: Default::default(), pending_responses_arrival_time: Default::default(), send_feedback: Default::default(), + peerset, + message_request: None, }) } @@ -492,6 +519,93 @@ impl NetworkBehaviour for RequestResponsesBehaviour { >, > { 'poll_all: loop { + if let Some(message_request) = self.message_request.take() { + // Now we can can poll `MessageRequest` until we get the reputation + + let MessageRequest { + peer, + request_id, + request, + channel, + protocol, + resp_builder, + mut get_peer_reputation, + } = message_request; + + let reputation = Future::poll(Pin::new(&mut get_peer_reputation), cx); + match reputation { + Poll::Pending => { + // Save the state to poll it again next time. + + self.message_request = Some(MessageRequest { + peer, + request_id, + request, + channel, + protocol, + resp_builder, + get_peer_reputation, + }); + return Poll::Pending + }, + Poll::Ready(reputation) => { + // Once we get the reputation we can continue processing the request. + + let reputation = reputation.expect( + "The channel can only be closed if the peerset no longer exists; qed", + ); + + if reputation < BANNED_THRESHOLD { + log::debug!( + target: "sub-libp2p", + "Cannot handle requests from a node with a low reputation {}: {}", + peer, + reputation, + ); + continue 'poll_all + } + + let (tx, rx) = oneshot::channel(); + + // Submit the request to the "response builder" passed by the user at + // initialization. + if let Some(mut resp_builder) = resp_builder { + // If the response builder is too busy, silently drop `tx`. This + // will be reported by the corresponding `RequestResponse` through + // an `InboundFailure::Omission` event. + let _ = resp_builder.try_send(IncomingRequest { + peer: peer.clone(), + payload: request, + pending_response: tx, + }); + } else { + debug_assert!(false, "Received message on outbound-only protocol."); + } + + let protocol = Cow::from(protocol); + self.pending_responses.push(Box::pin(async move { + // The `tx` created above can be dropped if we are not capable of + // processing this request, which is reflected as a + // `InboundFailure::Omission` event. + if let Ok(response) = rx.await { + Some(RequestProcessingOutcome { + peer, + request_id, + protocol, + inner_channel: channel, + response, + }) + } else { + None + } + })); + + // This `continue` makes sure that `pending_responses` gets polled + // after we have added the new element. + continue 'poll_all + }, + } + } // Poll to see if any response is ready to be sent back. while let Poll::Ready(Some(outcome)) = self.pending_responses.poll_next_unpin(cx) { let RequestProcessingOutcome { @@ -585,42 +699,24 @@ impl NetworkBehaviour for RequestResponsesBehaviour { Instant::now(), ); - let (tx, rx) = oneshot::channel(); - - // Submit the request to the "response builder" passed by the user at - // initialization. - if let Some(resp_builder) = resp_builder { - // If the response builder is too busy, silently drop `tx`. This - // will be reported by the corresponding `RequestResponse` through - // an `InboundFailure::Omission` event. - let _ = resp_builder.try_send(IncomingRequest { - peer: peer.clone(), - payload: request, - pending_response: tx, - }); - } else { - debug_assert!(false, "Received message on outbound-only protocol."); - } + let get_peer_reputation = + self.peerset.clone().peer_reputation(peer.clone()); + let get_peer_reputation = Box::pin(get_peer_reputation); - let protocol = protocol.clone(); - self.pending_responses.push(Box::pin(async move { - // The `tx` created above can be dropped if we are not capable of - // processing this request, which is reflected as a - // `InboundFailure::Omission` event. - if let Ok(response) = rx.await { - Some(RequestProcessingOutcome { - peer, - request_id, - protocol, - inner_channel: channel, - response, - }) - } else { - None - } - })); - - // This `continue` makes sure that `pending_responses` gets polled + // Save the Future-like state with params to poll `get_peer_reputation` + // and to continue processing the request once we get the reputation of + // the peer. + self.message_request = Some(MessageRequest { + peer, + request_id, + request, + channel, + protocol: protocol.to_string(), + resp_builder: resp_builder.clone(), + get_peer_reputation, + }); + + // This `continue` makes sure that `message_request` gets polled // after we have added the new element. continue 'poll_all }, @@ -934,11 +1030,12 @@ mod tests { swarm::{Swarm, SwarmEvent}, Multiaddr, }; + use sc_peerset::{Peerset, PeersetConfig, SetConfig}; use std::{iter, time::Duration}; fn build_swarm( list: impl Iterator, - ) -> (Swarm, Multiaddr) { + ) -> (Swarm, Multiaddr, Peerset) { let keypair = Keypair::generate_ed25519(); let noise_keys = @@ -950,13 +1047,29 @@ mod tests { .multiplex(libp2p::yamux::YamuxConfig::default()) .boxed(); - let behaviour = RequestResponsesBehaviour::new(list).unwrap(); + let config = PeersetConfig { + sets: vec![SetConfig { + in_peers: u32::max_value(), + out_peers: u32::max_value(), + bootnodes: vec![], + reserved_nodes: Default::default(), + reserved_only: false, + }], + }; + + let (peerset, handle) = Peerset::from_config(config); + + let behaviour = RequestResponsesBehaviour::new(list, handle).unwrap(); let mut swarm = Swarm::new(transport, behaviour, keypair.public().into_peer_id()); let listen_addr: Multiaddr = format!("/memory/{}", rand::random::()).parse().unwrap(); swarm.listen_on(listen_addr.clone()).unwrap(); - (swarm, listen_addr) + (swarm, listen_addr, peerset) + } + + async fn loop_peerset(peerset: Peerset) { + let _: Vec<_> = peerset.collect().await; } #[test] @@ -1007,10 +1120,12 @@ mod tests { Swarm::dial_addr(&mut swarms[0].0, dial_addr).unwrap(); } + let (mut swarm, _, peerset) = swarms.remove(0); + // Process every peerset event in the background. + pool.spawner().spawn_obj(loop_peerset(peerset).boxed().into()).unwrap(); // Running `swarm[0]` in the background. pool.spawner() .spawn_obj({ - let (mut swarm, _) = swarms.remove(0); async move { loop { match swarm.select_next_some().await { @@ -1027,7 +1142,9 @@ mod tests { .unwrap(); // Remove and run the remaining swarm. - let (mut swarm, _) = swarms.remove(0); + let (mut swarm, _, peerset) = swarms.remove(0); + // Process every peerset event in the background. + pool.spawner().spawn_obj(loop_peerset(peerset).boxed().into()).unwrap(); pool.run_until(async move { let mut response_receiver = None; @@ -1105,9 +1222,11 @@ mod tests { // Running `swarm[0]` in the background until a `InboundRequest` event happens, // which is a hint about the test having ended. + let (mut swarm, _, peerset) = swarms.remove(0); + // Process every peerset event in the background. + pool.spawner().spawn_obj(loop_peerset(peerset).boxed().into()).unwrap(); pool.spawner() .spawn_obj({ - let (mut swarm, _) = swarms.remove(0); async move { loop { match swarm.select_next_some().await { @@ -1125,7 +1244,9 @@ mod tests { .unwrap(); // Remove and run the remaining swarm. - let (mut swarm, _) = swarms.remove(0); + let (mut swarm, _, peerset) = swarms.remove(0); + // Process every peerset event in the background. + pool.spawner().spawn_obj(loop_peerset(peerset).boxed().into()).unwrap(); pool.run_until(async move { let mut response_receiver = None; @@ -1195,7 +1316,7 @@ mod tests { build_swarm(protocol_configs.into_iter()).0 }; - let (mut swarm_2, mut swarm_2_handler_1, mut swarm_2_handler_2, listen_add_2) = { + let (mut swarm_2, mut swarm_2_handler_1, mut swarm_2_handler_2, listen_add_2, peerset) = { let (tx_1, rx_1) = mpsc::channel(64); let (tx_2, rx_2) = mpsc::channel(64); @@ -1216,10 +1337,12 @@ mod tests { }, ]; - let (swarm, listen_addr) = build_swarm(protocol_configs.into_iter()); + let (swarm, listen_addr, peerset) = build_swarm(protocol_configs.into_iter()); - (swarm, rx_1, rx_2, listen_addr) + (swarm, rx_1, rx_2, listen_addr, peerset) }; + // Process every peerset event in the background. + pool.spawner().spawn_obj(loop_peerset(peerset).boxed().into()).unwrap(); // Ask swarm 1 to dial swarm 2. There isn't any discovery mechanism in place in this test, // so they wouldn't connect to each other. diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 525470145b78c..23f9c614d9069 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -355,6 +355,7 @@ impl NetworkWorker { bitswap, params.light_client_request_protocol_config, params.network_config.request_response_protocols, + peerset_handle.clone(), ); match result { diff --git a/client/peerset/src/lib.rs b/client/peerset/src/lib.rs index 9c6c5617c34b1..0775354befee4 100644 --- a/client/peerset/src/lib.rs +++ b/client/peerset/src/lib.rs @@ -34,7 +34,7 @@ mod peersstate; -use futures::prelude::*; +use futures::{channel::oneshot, prelude::*}; use log::{debug, error, trace}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use serde_json::json; @@ -49,7 +49,7 @@ use wasm_timer::Delay; pub use libp2p::PeerId; /// We don't accept nodes whose reputation is under this value. -const BANNED_THRESHOLD: i32 = 82 * (i32::MIN / 100); +pub const BANNED_THRESHOLD: i32 = 82 * (i32::MIN / 100); /// Reputation change for a node when we get disconnected from it. const DISCONNECT_REPUTATION_CHANGE: i32 = -256; /// Amount of time between the moment we disconnect from a node and the moment we remove it from @@ -65,6 +65,7 @@ enum Action { ReportPeer(PeerId, ReputationChange), AddToPeersSet(SetId, PeerId), RemoveFromPeersSet(SetId, PeerId), + PeerReputation(PeerId, oneshot::Sender), } /// Identifier of a set in the peerset. @@ -165,6 +166,16 @@ impl PeersetHandle { pub fn remove_from_peers_set(&self, set_id: SetId, peer_id: PeerId) { let _ = self.tx.unbounded_send(Action::RemoveFromPeersSet(set_id, peer_id)); } + + /// Returns the reputation value of the peer. + pub async fn peer_reputation(self, peer_id: PeerId) -> Result { + let (tx, rx) = oneshot::channel(); + + let _ = self.tx.unbounded_send(Action::PeerReputation(peer_id, tx)); + + // The channel can only be closed if the peerset no longer exists. + rx.await.map_err(|_| ()) + } } /// Message that can be sent by the peer set manager (PSM). @@ -454,6 +465,11 @@ impl Peerset { } } + fn on_peer_reputation(&mut self, peer_id: PeerId, pending_response: oneshot::Sender) { + let reputation = self.data.peer_reputation(peer_id); + let _ = pending_response.send(reputation.reputation()); + } + /// Updates the value of `self.latest_time_update` and performs all the updates that happen /// over time, such as reputation increases for staying connected. fn update_time(&mut self) { @@ -744,6 +760,8 @@ impl Stream for Peerset { self.add_to_peers_set(sets_name, peer_id), Action::RemoveFromPeersSet(sets_name, peer_id) => self.on_remove_from_peers_set(sets_name, peer_id), + Action::PeerReputation(peer_id, pending_response) => + self.on_peer_reputation(peer_id, pending_response), } } } From 3486a134e826f115907dcbb1b65d4eb422505b6f Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 21 Sep 2021 12:37:57 +0100 Subject: [PATCH 0007/1472] check line width not needed (#9820) * check line width not needed (cargo fmt checks this) * Fixing test to work in release mode. --- .gitlab-ci.yml | 10 ----- .maintain/gitlab/check_line_width.sh | 55 ---------------------------- frame/bags-list/src/list/tests.rs | 9 ++++- 3 files changed, 7 insertions(+), 67 deletions(-) delete mode 100755 .maintain/gitlab/check_line_width.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fd7bfe7155918..c5cb6c571b475 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -269,16 +269,6 @@ check-signed-tag: script: - ./.maintain/gitlab/check_signed.sh -check-line-width: - stage: check - image: paritytech/tools:latest - <<: *kubernetes-env - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - script: - - ./.maintain/gitlab/check_line_width.sh - allow_failure: true - test-dependency-rules: stage: check image: paritytech/tools:latest diff --git a/.maintain/gitlab/check_line_width.sh b/.maintain/gitlab/check_line_width.sh deleted file mode 100755 index ebab3013e4b48..0000000000000 --- a/.maintain/gitlab/check_line_width.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/sh -# -# check if line width of rust source files is not beyond x characters -# -set -e -set -o pipefail - -BASE_ORIGIN="origin" -BASE_BRANCH_NAME="master" -LINE_WIDTH="120" -GOOD_LINE_WIDTH="100" -BASE_BRANCH="${BASE_ORIGIN}/${BASE_BRANCH_NAME}" -git fetch ${BASE_ORIGIN} ${BASE_BRANCH_NAME} --depth 100 -BASE_HASH=$(git merge-base ${BASE_BRANCH} HEAD) - -git diff --name-only ${BASE_HASH} -- \*.rs | ( while read file -do - if [ ! -f ${file} ]; - then - echo "Skipping removed file." - elif git diff ${BASE_HASH} -- ${file} | grep -q "^+.\{$(( $LINE_WIDTH + 1 ))\}" - then - if [ -z "${FAIL}" ] - then - echo "| error!" - echo "| Lines must not be longer than ${LINE_WIDTH} characters." - echo "| " - echo "| see more https://github.com/paritytech/substrate/blob/master/docs/STYLE_GUIDE.md" - echo "|" - FAIL="true" - fi - echo "| file: ${file}" - git diff ${BASE_HASH} -- ${file} \ - | grep -n "^+.\{$(( $LINE_WIDTH + 1))\}" - echo "|" - else - if git diff ${BASE_HASH} -- ${file} | grep -q "^+.\{$(( $GOOD_LINE_WIDTH + 1 ))\}" - then - if [ -z "${FAIL}" ] - then - echo "| warning!" - echo "| Lines should be longer than ${GOOD_LINE_WIDTH} characters only in exceptional circumstances!" - echo "| " - echo "| see more https://github.com/paritytech/substrate/blob/master/docs/STYLE_GUIDE.md" - echo "|" - fi - echo "| file: ${file}" - git diff ${BASE_HASH} -- ${file} | grep -n "^+.\{$(( $GOOD_LINE_WIDTH + 1 ))\}" - echo "|" - fi - fi -done - -test -z "${FAIL}" -) diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index e2730cbf4e33d..14802bac9d1d8 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -537,7 +537,10 @@ mod bags { // Panics in case of duplicate tail insert (which would result in an infinite loop). #[test] - #[should_panic = "system logic error: inserting a node who has the id of tail"] + #[cfg_attr( + debug_assertions, + should_panic = "system logic error: inserting a node who has the id of tail" + )] fn insert_node_duplicate_tail_panics_with_debug_assert() { ExtBuilder::default().build_and_execute(|| { let node = |id, prev, next, bag_upper| Node:: { id, prev, next, bag_upper }; @@ -548,7 +551,9 @@ mod bags { // when inserting a duplicate id that is already the tail assert_eq!(bag_1000.tail, Some(4)); - bag_1000.insert_node_unchecked(node(4, None, None, bag_1000.bag_upper)); // panics + assert_eq!(bag_1000.iter().count(), 3); + bag_1000.insert_node_unchecked(node(4, None, None, bag_1000.bag_upper)); // panics in debug + assert_eq!(bag_1000.iter().count(), 3); // in release we expect it to silently ignore the request. }); } From ce3c31f2bfa7e10817a8a0833faddeaee818910d Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Tue, 21 Sep 2021 14:36:53 +0200 Subject: [PATCH 0008/1472] Improve post and pre migration checks for pallet-membership (#9746) * improve post and pre migration checks * prevent some more false positive * prevent another false positive * fix unused import * Apply suggestions from code review --- frame/membership/src/lib.rs | 11 ++++- frame/membership/src/migrations/v4.rs | 70 ++++++++++++--------------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 7922d9efaf569..57a12c7c8a453 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -790,9 +790,16 @@ mod tests { fn migration_v4() { new_test_ext().execute_with(|| { use frame_support::traits::PalletInfo; - let old_pallet_name = + let old_pallet_name = "OldMembership"; + let new_pallet_name = ::PalletInfo::name::().unwrap(); - let new_pallet_name = "NewMembership"; + + frame_support::storage::migration::move_pallet( + new_pallet_name.as_bytes(), + old_pallet_name.as_bytes(), + ); + + StorageVersion::new(0).put::(); crate::migrations::v4::pre_migrate::(old_pallet_name, new_pallet_name); crate::migrations::v4::migrate::(old_pallet_name, new_pallet_name); diff --git a/frame/membership/src/migrations/v4.rs b/frame/membership/src/migrations/v4.rs index 9f4b15e468b38..c1c944be1fd4f 100644 --- a/frame/membership/src/migrations/v4.rs +++ b/frame/membership/src/migrations/v4.rs @@ -15,8 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use sp_core::hexdisplay::HexDisplay; -use sp_io::{hashing::twox_128, storage}; +use sp_io::hashing::twox_128; use frame_support::{ traits::{ @@ -85,28 +84,22 @@ pub fn pre_migrate>(old_pallet_name: N, new_ let new_pallet_name = new_pallet_name.as_ref(); log_migration("pre-migration", old_pallet_name, new_pallet_name); - let old_pallet_prefix = twox_128(old_pallet_name.as_bytes()); - assert!(storage::next_key(&old_pallet_prefix) - .map_or(true, |next_key| next_key.starts_with(&old_pallet_prefix))); + if new_pallet_name == old_pallet_name { + return + } let new_pallet_prefix = twox_128(new_pallet_name.as_bytes()); - let storage_version_key = - [&new_pallet_prefix, &twox_128(STORAGE_VERSION_STORAGE_KEY_POSTFIX)[..]].concat(); - // ensure nothing is stored in the new prefix. - assert!( - storage::next_key(&new_pallet_prefix).map_or( - // either nothing is there - true, - // or we ensure that it has no common prefix with twox_128(new), - // or isn't the storage version that is already stored using the pallet name - |next_key| { - !next_key.starts_with(&new_pallet_prefix) || next_key == storage_version_key - }, - ), - "unexpected next_key({}) = {:?}", - new_pallet_name, - HexDisplay::from(&storage::next_key(&new_pallet_prefix).unwrap()), + let storage_version_key = twox_128(STORAGE_VERSION_STORAGE_KEY_POSTFIX); + + let mut new_pallet_prefix_iter = frame_support::storage::KeyPrefixIterator::new( + new_pallet_prefix.to_vec(), + new_pallet_prefix.to_vec(), + |key| Ok(key.to_vec()), ); + + // Ensure nothing except maybe the storage_version_key is stored in the new prefix. + assert!(new_pallet_prefix_iter.all(|key| key == storage_version_key)); + assert!(

::on_chain_storage_version() < 4); } @@ -119,26 +112,27 @@ pub fn post_migrate>(old_pallet_name: N, new let new_pallet_name = new_pallet_name.as_ref(); log_migration("post-migration", old_pallet_name, new_pallet_name); - let old_pallet_prefix = twox_128(old_pallet_name.as_bytes()); - #[cfg(test)] - { - let storage_version_key = - [&old_pallet_prefix, &twox_128(STORAGE_VERSION_STORAGE_KEY_POSTFIX)[..]].concat(); - assert!(storage::next_key(&old_pallet_prefix) - .map_or(true, |next_key| !next_key.starts_with(&old_pallet_prefix) || - next_key == storage_version_key)); - } - #[cfg(not(test))] - { - // Assert that nothing remains at the old prefix - assert!(storage::next_key(&old_pallet_prefix) - .map_or(true, |next_key| !next_key.starts_with(&old_pallet_prefix))); + if new_pallet_name == old_pallet_name { + return } + // Assert that nothing remains at the old prefix. + let old_pallet_prefix = twox_128(old_pallet_name.as_bytes()); + let old_pallet_prefix_iter = frame_support::storage::KeyPrefixIterator::new( + old_pallet_prefix.to_vec(), + old_pallet_prefix.to_vec(), + |_| Ok(()), + ); + assert_eq!(old_pallet_prefix_iter.count(), 0); + + // NOTE: storage_version_key is already in the new prefix. let new_pallet_prefix = twox_128(new_pallet_name.as_bytes()); - // Assert that the storages have been moved to the new prefix - assert!(storage::next_key(&new_pallet_prefix) - .map_or(true, |next_key| next_key.starts_with(&new_pallet_prefix))); + let new_pallet_prefix_iter = frame_support::storage::KeyPrefixIterator::new( + new_pallet_prefix.to_vec(), + new_pallet_prefix.to_vec(), + |_| Ok(()), + ); + assert!(new_pallet_prefix_iter.count() >= 1); assert_eq!(

::on_chain_storage_version(), 4); } From 78ce06139243df5fbbf85356a754e6c97ec7cb9c Mon Sep 17 00:00:00 2001 From: ferrell-code Date: Tue, 21 Sep 2021 09:07:36 -0400 Subject: [PATCH 0009/1472] Bounties Pallet to FrameV2 (#9566) * migrate bounties pallet * events in tests * test import event * Update frame/bounties/src/lib.rs Co-authored-by: Keith Yeung * cargo fmt * line width * benchmarks compile * add migrations * fmt * comments * mod migrations * fix Cargo.toml * never remember cargo fmt * fix migration * migrations and test * change checks in migration * remove unused values * Update frame/bounties/src/migrations/v4.rs * cargo fmt * fix benchmarking * trigger ci Co-authored-by: Keith Yeung Co-authored-by: Guillaume Thiolliere --- Cargo.lock | 1 + frame/bounties/Cargo.toml | 9 +- frame/bounties/src/benchmarking.rs | 34 +- frame/bounties/src/lib.rs | 454 ++++++++++++++------------- frame/bounties/src/migrations/mod.rs | 19 ++ frame/bounties/src/migrations/v4.rs | 230 ++++++++++++++ frame/bounties/src/tests.rs | 58 +++- 7 files changed, 566 insertions(+), 239 deletions(-) create mode 100644 frame/bounties/src/migrations/mod.rs create mode 100644 frame/bounties/src/migrations/v4.rs diff --git a/Cargo.lock b/Cargo.lock index 37773a4ae3a69..839c68b71fbf1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5121,6 +5121,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log 0.4.14", "pallet-balances", "pallet-treasury", "parity-scale-codec", diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 3bb184d5b3393..93a7ababb2ebd 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -22,24 +22,27 @@ sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../pr frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } - +sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } +sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +log = { version = "0.4.14", default-features = false } [dev-dependencies] -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] std = [ "codec/std", + "sp-core/std", + "sp-io/std", "scale-info/std", "sp-std/std", "sp-runtime/std", "frame-support/std", "frame-system/std", "pallet-treasury/std", + "log/std", ] runtime-benchmarks = [ "frame-benchmarking", diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 798d929d241f7..1aa1eabdb5177 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -22,11 +22,10 @@ use super::*; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; -use frame_support::traits::OnInitialize; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; -use crate::Module as Bounties; +use crate::Pallet as Bounties; use pallet_treasury::Pallet as Treasury; const SEED: u32 = 0; @@ -36,10 +35,10 @@ fn create_approved_bounties(n: u32) -> Result<(), &'static str> { for i in 0..n { let (caller, _curator, _fee, value, reason) = setup_bounty::(i, MAX_BYTES); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; } - ensure!(BountyApprovals::get().len() == n as usize, "Not all bounty approved"); + ensure!(BountyApprovals::::get().len() == n as usize, "Not all bounty approved"); Ok(()) } @@ -64,7 +63,7 @@ fn create_bounty( let (caller, curator, fee, value, reason) = setup_bounty::(0, MAX_BYTES); let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); Bounties::::propose_curator(RawOrigin::Root.into(), bounty_id, curator_lookup.clone(), fee)?; @@ -94,7 +93,7 @@ benchmarks! { approve_bounty { let (caller, curator, fee, value, reason) = setup_bounty::(0, MAX_BYTES); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; }: _(RawOrigin::Root, bounty_id) propose_curator { @@ -102,7 +101,7 @@ benchmarks! { let (caller, curator, fee, value, reason) = setup_bounty::(0, MAX_BYTES); let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; Bounties::::on_initialize(T::BlockNumber::zero()); }: _(RawOrigin::Root, bounty_id, curator_lookup, fee) @@ -112,7 +111,7 @@ benchmarks! { setup_pot_account::(); let (curator_lookup, bounty_id) = create_bounty::()?; Bounties::::on_initialize(T::BlockNumber::zero()); - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; frame_system::Pallet::::set_block_number(T::BountyUpdatePeriod::get() + 1u32.into()); let caller = whitelisted_caller(); }: _(RawOrigin::Signed(caller), bounty_id) @@ -122,7 +121,7 @@ benchmarks! { let (caller, curator, fee, value, reason) = setup_bounty::(0, MAX_BYTES); let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; Bounties::::on_initialize(T::BlockNumber::zero()); Bounties::::propose_curator(RawOrigin::Root.into(), bounty_id, curator_lookup, fee)?; @@ -133,7 +132,7 @@ benchmarks! { let (curator_lookup, bounty_id) = create_bounty::()?; Bounties::::on_initialize(T::BlockNumber::zero()); - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; let curator = T::Lookup::lookup(curator_lookup).map_err(<&str>::from)?; let beneficiary = T::Lookup::unlookup(account("beneficiary", 0, SEED)); @@ -144,10 +143,9 @@ benchmarks! { let (curator_lookup, bounty_id) = create_bounty::()?; Bounties::::on_initialize(T::BlockNumber::zero()); - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; let curator = T::Lookup::lookup(curator_lookup).map_err(<&str>::from)?; - let beneficiary_account: T::AccountId = account("beneficiary", 0, SEED); let beneficiary = T::Lookup::unlookup(beneficiary_account.clone()); Bounties::::award_bounty(RawOrigin::Signed(curator.clone()).into(), bounty_id, beneficiary)?; @@ -164,17 +162,17 @@ benchmarks! { setup_pot_account::(); let (caller, curator, fee, value, reason) = setup_bounty::(0, 0); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; }: close_bounty(RawOrigin::Root, bounty_id) close_bounty_active { setup_pot_account::(); let (curator_lookup, bounty_id) = create_bounty::()?; Bounties::::on_initialize(T::BlockNumber::zero()); - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; }: close_bounty(RawOrigin::Root, bounty_id) verify { - assert_last_event::(RawEvent::BountyCanceled(bounty_id).into()) + assert_last_event::(Event::BountyCanceled(bounty_id).into()) } extend_bounty_expiry { @@ -182,11 +180,11 @@ benchmarks! { let (curator_lookup, bounty_id) = create_bounty::()?; Bounties::::on_initialize(T::BlockNumber::zero()); - let bounty_id = BountyCount::get() - 1; + let bounty_id = BountyCount::::get() - 1; let curator = T::Lookup::lookup(curator_lookup).map_err(<&str>::from)?; }: _(RawOrigin::Signed(curator), bounty_id, Vec::new()) verify { - assert_last_event::(RawEvent::BountyExtended(bounty_id).into()) + assert_last_event::(Event::BountyExtended(bounty_id).into()) } spend_funds { @@ -209,7 +207,7 @@ benchmarks! { verify { ensure!(budget_remaining < BalanceOf::::max_value(), "Budget not used"); ensure!(missed_any == false, "Missed some"); - assert_last_event::(RawEvent::BountyBecameActive(b - 1).into()) + assert_last_event::(Event::BountyBecameActive(b - 1).into()) } } diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 77a8e47174019..69380502bad3f 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -75,13 +75,12 @@ #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; +pub mod migrations; mod tests; pub mod weights; use sp_std::prelude::*; -use frame_support::{decl_error, decl_event, decl_module, decl_storage, ensure}; - use frame_support::traits::{ Currency, ExistenceRequirement::AllowDeath, Get, Imbalance, OnUnbalanced, ReservableCurrency, }; @@ -93,46 +92,17 @@ use sp_runtime::{ use frame_support::{dispatch::DispatchResultWithPostInfo, traits::EnsureOrigin}; -use frame_support::weights::Weight; - -use codec::{Decode, Encode}; -use frame_system::{self as system, ensure_signed}; +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; use scale_info::TypeInfo; pub use weights::WeightInfo; +pub use pallet::*; + type BalanceOf = pallet_treasury::BalanceOf; type PositiveImbalanceOf = pallet_treasury::PositiveImbalanceOf; -pub trait Config: frame_system::Config + pallet_treasury::Config { - /// The amount held on deposit for placing a bounty proposal. - type BountyDepositBase: Get>; - - /// The delay period for which a bounty beneficiary need to wait before claim the payout. - type BountyDepositPayoutDelay: Get; - - /// Bounty duration in blocks. - type BountyUpdatePeriod: Get; - - /// Percentage of the curator fee that will be reserved upfront as deposit for bounty curator. - type BountyCuratorDeposit: Get; - - /// Minimum value for a bounty. - type BountyValueMinimum: Get>; - - /// The amount held on deposit per byte within the tip report reason or bounty description. - type DataDepositPerByte: Get>; - - /// The overarching event type. - type Event: From> + Into<::Event>; - - /// Maximum acceptable reason length. - type MaximumReasonLength: Get; - - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; -} - /// An index of a bounty. Just a `u32`. pub type BountyIndex = u32; @@ -186,55 +156,54 @@ pub enum BountyStatus { }, } -// Note :: For backward compatibility reasons, -// pallet-bounties uses Treasury for storage. -// This is temporary solution, soon will get replaced with -// Own storage identifier. -decl_storage! { - trait Store for Module as Treasury { +#[frame_support::pallet] +pub mod pallet { + use super::*; - /// Number of bounty proposals that have been made. - pub BountyCount get(fn bounty_count): BountyIndex; + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); - /// Bounties that have been made. - pub Bounties get(fn bounties): - map hasher(twox_64_concat) BountyIndex - => Option, T::BlockNumber>>; + #[pallet::config] + pub trait Config: frame_system::Config + pallet_treasury::Config { + /// The amount held on deposit for placing a bounty proposal. + #[pallet::constant] + type BountyDepositBase: Get>; - /// The description of each bounty. - pub BountyDescriptions get(fn bounty_descriptions): map hasher(twox_64_concat) BountyIndex => Option>; + /// The delay period for which a bounty beneficiary need to wait before claim the payout. + #[pallet::constant] + type BountyDepositPayoutDelay: Get; - /// Bounty indices that have been approved but not yet funded. - pub BountyApprovals get(fn bounty_approvals): Vec; - } -} + /// Bounty duration in blocks. + #[pallet::constant] + type BountyUpdatePeriod: Get; -decl_event!( - pub enum Event - where - Balance = BalanceOf, - ::AccountId, - { - /// New bounty proposal. \[index\] - BountyProposed(BountyIndex), - /// A bounty proposal was rejected; funds were slashed. \[index, bond\] - BountyRejected(BountyIndex, Balance), - /// A bounty proposal is funded and became active. \[index\] - BountyBecameActive(BountyIndex), - /// A bounty is awarded to a beneficiary. \[index, beneficiary\] - BountyAwarded(BountyIndex, AccountId), - /// A bounty is claimed by beneficiary. \[index, payout, beneficiary\] - BountyClaimed(BountyIndex, Balance, AccountId), - /// A bounty is cancelled. \[index\] - BountyCanceled(BountyIndex), - /// A bounty expiry is extended. \[index\] - BountyExtended(BountyIndex), + /// Percentage of the curator fee that will be reserved upfront as deposit for bounty + /// curator. + #[pallet::constant] + type BountyCuratorDeposit: Get; + + /// Minimum value for a bounty. + #[pallet::constant] + type BountyValueMinimum: Get>; + + /// The amount held on deposit per byte within the tip report reason or bounty description. + #[pallet::constant] + type DataDepositPerByte: Get>; + + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// Maximum acceptable reason length. + #[pallet::constant] + type MaximumReasonLength: Get; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; } -); -decl_error! { - /// Error for the treasury module. - pub enum Error for Module { + #[pallet::error] + pub enum Error { /// Proposer's balance is too low. InsufficientProposersBalance, /// No proposal or bounty at that index. @@ -255,38 +224,53 @@ decl_error! { /// The bounties cannot be claimed/closed because it's still in the countdown period. Premature, } -} - -decl_module! { - pub struct Module - for enum Call - where origin: T::Origin - { - /// The amount held on deposit per byte within bounty description. - const DataDepositPerByte: BalanceOf = T::DataDepositPerByte::get(); - - /// The amount held on deposit for placing a bounty proposal. - const BountyDepositBase: BalanceOf = T::BountyDepositBase::get(); - - /// The delay period for which a bounty beneficiary need to wait before claim the payout. - const BountyDepositPayoutDelay: T::BlockNumber = T::BountyDepositPayoutDelay::get(); - /// Bounty duration in blocks. - const BountyUpdatePeriod: T::BlockNumber = T::BountyUpdatePeriod::get(); - - /// Percentage of the curator fee that will be reserved upfront as deposit for bounty curator. - const BountyCuratorDeposit: Permill = T::BountyCuratorDeposit::get(); - - /// Minimum value for a bounty. - const BountyValueMinimum: BalanceOf = T::BountyValueMinimum::get(); - - /// Maximum acceptable reason length. - const MaximumReasonLength: u32 = T::MaximumReasonLength::get(); - - type Error = Error; - - fn deposit_event() = default; + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// New bounty proposal. \[index\] + BountyProposed(BountyIndex), + /// A bounty proposal was rejected; funds were slashed. \[index, bond\] + BountyRejected(BountyIndex, BalanceOf), + /// A bounty proposal is funded and became active. \[index\] + BountyBecameActive(BountyIndex), + /// A bounty is awarded to a beneficiary. \[index, beneficiary\] + BountyAwarded(BountyIndex, T::AccountId), + /// A bounty is claimed by beneficiary. \[index, payout, beneficiary\] + BountyClaimed(BountyIndex, BalanceOf, T::AccountId), + /// A bounty is cancelled. \[index\] + BountyCanceled(BountyIndex), + /// A bounty expiry is extended. \[index\] + BountyExtended(BountyIndex), + } + /// Number of bounty proposals that have been made. + #[pallet::storage] + #[pallet::getter(fn bounty_count)] + pub type BountyCount = StorageValue<_, BountyIndex, ValueQuery>; + + /// Bounties that have been made. + #[pallet::storage] + #[pallet::getter(fn bounties)] + pub type Bounties = StorageMap< + _, + Twox64Concat, + BountyIndex, + Bounty, T::BlockNumber>, + >; + + /// The description of each bounty. + #[pallet::storage] + #[pallet::getter(fn bounty_descriptions)] + pub type BountyDescriptions = StorageMap<_, Twox64Concat, BountyIndex, Vec>; + + /// Bounty indices that have been approved but not yet funded. + #[pallet::storage] + #[pallet::getter(fn bounty_approvals)] + pub type BountyApprovals = StorageValue<_, Vec, ValueQuery>; + + #[pallet::call] + impl Pallet { /// Propose a new bounty. /// /// The dispatch origin for this call must be _Signed_. @@ -299,14 +283,15 @@ decl_module! { /// - `fee`: The curator fee. /// - `value`: The total payment amount of this bounty, curator fee included. /// - `description`: The description of this bounty. - #[weight = ::WeightInfo::propose_bounty(description.len() as u32)] - fn propose_bounty( - origin, - #[compact] value: BalanceOf, + #[pallet::weight(::WeightInfo::propose_bounty(description.len() as u32))] + pub fn propose_bounty( + origin: OriginFor, + #[pallet::compact] value: BalanceOf, description: Vec, - ) { + ) -> DispatchResult { let proposer = ensure_signed(origin)?; Self::create_bounty(proposer, description, value)?; + Ok(()) } /// Approve a bounty proposal. At a later time, the bounty will be funded and become active @@ -317,8 +302,11 @@ decl_module! { /// # /// - O(1). /// # - #[weight = ::WeightInfo::approve_bounty()] - fn approve_bounty(origin, #[compact] bounty_id: BountyIndex) { + #[pallet::weight(::WeightInfo::approve_bounty())] + pub fn approve_bounty( + origin: OriginFor, + #[pallet::compact] bounty_id: BountyIndex, + ) -> DispatchResult { T::ApproveOrigin::ensure_origin(origin)?; Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { @@ -327,10 +315,11 @@ decl_module! { bounty.status = BountyStatus::Approved; - BountyApprovals::append(bounty_id); + BountyApprovals::::append(bounty_id); Ok(()) })?; + Ok(()) } /// Assign a curator to a funded bounty. @@ -340,18 +329,17 @@ decl_module! { /// # /// - O(1). /// # - #[weight = ::WeightInfo::propose_curator()] - fn propose_curator( - origin, - #[compact] bounty_id: BountyIndex, + #[pallet::weight(::WeightInfo::propose_curator())] + pub fn propose_curator( + origin: OriginFor, + #[pallet::compact] bounty_id: BountyIndex, curator: ::Source, - #[compact] fee: BalanceOf, - ) { + #[pallet::compact] fee: BalanceOf, + ) -> DispatchResult { T::ApproveOrigin::ensure_origin(origin)?; let curator = T::Lookup::lookup(curator)?; Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { - let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; match bounty.status { BountyStatus::Proposed | BountyStatus::Approved | BountyStatus::Funded => {}, @@ -365,14 +353,15 @@ decl_module! { Ok(()) })?; + Ok(()) } /// Unassign curator from a bounty. /// /// This function can only be called by the `RejectOrigin` a signed origin. /// - /// If this function is called by the `RejectOrigin`, we assume that the curator is malicious - /// or inactive. As a result, we will slash the curator when possible. + /// If this function is called by the `RejectOrigin`, we assume that the curator is + /// malicious or inactive. As a result, we will slash the curator when possible. /// /// If the origin is the curator, we take this as a sign they are unable to do their job and /// they willingly give up. We could slash them, but for now we allow them to recover their @@ -385,11 +374,11 @@ decl_module! { /// # /// - O(1). /// # - #[weight = ::WeightInfo::unassign_curator()] - fn unassign_curator( - origin, - #[compact] bounty_id: BountyIndex, - ) { + #[pallet::weight(::WeightInfo::unassign_curator())] + pub fn unassign_curator( + origin: OriginFor, + #[pallet::compact] bounty_id: BountyIndex, + ) -> DispatchResult { let maybe_sender = ensure_signed(origin.clone()) .map(Some) .or_else(|_| T::RejectOrigin::ensure_origin(origin).map(|_| None))?; @@ -407,7 +396,7 @@ decl_module! { BountyStatus::Proposed | BountyStatus::Approved | BountyStatus::Funded => { // No curator to unassign at this point. return Err(Error::::UnexpectedStatus.into()) - } + }, BountyStatus::CuratorProposed { ref curator } => { // A curator has been proposed, but not accepted yet. // Either `RejectOrigin` or the proposed curator can unassign the curator. @@ -425,10 +414,10 @@ decl_module! { // If the sender is not the curator, and the curator is inactive, // slash the curator. if sender != *curator { - let block_number = system::Pallet::::block_number(); + let block_number = frame_system::Pallet::::block_number(); if *update_due < block_number { slash_curator(curator, &mut bounty.curator_deposit); - // Continue to change bounty status below... + // Continue to change bounty status below... } else { // Curator has more time to give an update. return Err(Error::::Premature.into()) @@ -436,7 +425,8 @@ decl_module! { } else { // Else this is the curator, willingly giving up their role. // Give back their deposit. - let err_amount = T::Currency::unreserve(&curator, bounty.curator_deposit); + let err_amount = + T::Currency::unreserve(&curator, bounty.curator_deposit); debug_assert!(err_amount.is_zero()); // Continue to change bounty status below... } @@ -450,12 +440,13 @@ decl_module! { ensure!(maybe_sender.is_none(), BadOrigin); slash_curator(curator, &mut bounty.curator_deposit); // Continue to change bounty status below... - } + }, }; bounty.status = BountyStatus::Funded; Ok(()) })?; + Ok(()) } /// Accept the curator role for a bounty. @@ -466,8 +457,11 @@ decl_module! { /// # /// - O(1). /// # - #[weight = ::WeightInfo::accept_curator()] - fn accept_curator(origin, #[compact] bounty_id: BountyIndex) { + #[pallet::weight(::WeightInfo::accept_curator())] + pub fn accept_curator( + origin: OriginFor, + #[pallet::compact] bounty_id: BountyIndex, + ) -> DispatchResult { let signer = ensure_signed(origin)?; Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { @@ -481,17 +475,21 @@ decl_module! { T::Currency::reserve(curator, deposit)?; bounty.curator_deposit = deposit; - let update_due = system::Pallet::::block_number() + T::BountyUpdatePeriod::get(); - bounty.status = BountyStatus::Active { curator: curator.clone(), update_due }; + let update_due = frame_system::Pallet::::block_number() + + T::BountyUpdatePeriod::get(); + bounty.status = + BountyStatus::Active { curator: curator.clone(), update_due }; Ok(()) }, _ => Err(Error::::UnexpectedStatus.into()), } })?; + Ok(()) } - /// Award bounty to a beneficiary account. The beneficiary will be able to claim the funds after a delay. + /// Award bounty to a beneficiary account. The beneficiary will be able to claim the funds + /// after a delay. /// /// The dispatch origin for this call must be the curator of this bounty. /// @@ -501,18 +499,19 @@ decl_module! { /// # /// - O(1). /// # - #[weight = ::WeightInfo::award_bounty()] - fn award_bounty(origin, #[compact] bounty_id: BountyIndex, beneficiary: ::Source) { + #[pallet::weight(::WeightInfo::award_bounty())] + pub fn award_bounty( + origin: OriginFor, + #[pallet::compact] bounty_id: BountyIndex, + beneficiary: ::Source, + ) -> DispatchResult { let signer = ensure_signed(origin)?; let beneficiary = T::Lookup::lookup(beneficiary)?; Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; match &bounty.status { - BountyStatus::Active { - curator, - .. - } => { + BountyStatus::Active { curator, .. } => { ensure!(signer == *curator, Error::::RequireCurator); }, _ => return Err(Error::::UnexpectedStatus.into()), @@ -520,13 +519,15 @@ decl_module! { bounty.status = BountyStatus::PendingPayout { curator: signer, beneficiary: beneficiary.clone(), - unlock_at: system::Pallet::::block_number() + T::BountyDepositPayoutDelay::get(), + unlock_at: frame_system::Pallet::::block_number() + + T::BountyDepositPayoutDelay::get(), }; Ok(()) })?; Self::deposit_event(Event::::BountyAwarded(bounty_id, beneficiary)); + Ok(()) } /// Claim the payout from an awarded bounty after payout delay. @@ -538,14 +539,22 @@ decl_module! { /// # /// - O(1). /// # - #[weight = ::WeightInfo::claim_bounty()] - fn claim_bounty(origin, #[compact] bounty_id: BountyIndex) { + #[pallet::weight(::WeightInfo::claim_bounty())] + pub fn claim_bounty( + origin: OriginFor, + #[pallet::compact] bounty_id: BountyIndex, + ) -> DispatchResult { let _ = ensure_signed(origin)?; // anyone can trigger claim Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { let bounty = maybe_bounty.take().ok_or(Error::::InvalidIndex)?; - if let BountyStatus::PendingPayout { curator, beneficiary, unlock_at } = bounty.status { - ensure!(system::Pallet::::block_number() >= unlock_at, Error::::Premature); + if let BountyStatus::PendingPayout { curator, beneficiary, unlock_at } = + bounty.status + { + ensure!( + frame_system::Pallet::::block_number() >= unlock_at, + Error::::Premature + ); let bounty_account = Self::bounty_account_id(bounty_id); let balance = T::Currency::free_balance(&bounty_account); let fee = bounty.fee.min(balance); // just to be safe @@ -554,12 +563,13 @@ decl_module! { debug_assert!(err_amount.is_zero()); let res = T::Currency::transfer(&bounty_account, &curator, fee, AllowDeath); // should not fail debug_assert!(res.is_ok()); - let res = T::Currency::transfer(&bounty_account, &beneficiary, payout, AllowDeath); // should not fail + let res = + T::Currency::transfer(&bounty_account, &beneficiary, payout, AllowDeath); // should not fail debug_assert!(res.is_ok()); *maybe_bounty = None; - BountyDescriptions::remove(bounty_id); + BountyDescriptions::::remove(bounty_id); Self::deposit_event(Event::::BountyClaimed(bounty_id, payout, beneficiary)); Ok(()) @@ -567,6 +577,7 @@ decl_module! { Err(Error::::UnexpectedStatus.into()) } })?; + Ok(()) } /// Cancel a proposed or active bounty. All the funds will be sent to treasury and @@ -579,62 +590,76 @@ decl_module! { /// # /// - O(1). /// # - #[weight = ::WeightInfo::close_bounty_proposed().max(::WeightInfo::close_bounty_active())] - fn close_bounty(origin, #[compact] bounty_id: BountyIndex) -> DispatchResultWithPostInfo { + #[pallet::weight(::WeightInfo::close_bounty_proposed() + .max(::WeightInfo::close_bounty_active()))] + pub fn close_bounty( + origin: OriginFor, + #[pallet::compact] bounty_id: BountyIndex, + ) -> DispatchResultWithPostInfo { T::RejectOrigin::ensure_origin(origin)?; - Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResultWithPostInfo { - let bounty = maybe_bounty.as_ref().ok_or(Error::::InvalidIndex)?; - - match &bounty.status { - BountyStatus::Proposed => { - // The reject origin would like to cancel a proposed bounty. - BountyDescriptions::remove(bounty_id); - let value = bounty.bond; - let imbalance = T::Currency::slash_reserved(&bounty.proposer, value).0; - T::OnSlash::on_unbalanced(imbalance); - *maybe_bounty = None; - - Self::deposit_event(Event::::BountyRejected(bounty_id, value)); - // Return early, nothing else to do. - return Ok(Some(::WeightInfo::close_bounty_proposed()).into()) - }, - BountyStatus::Approved => { - // For weight reasons, we don't allow a council to cancel in this phase. - // We ask for them to wait until it is funded before they can cancel. - return Err(Error::::UnexpectedStatus.into()) - }, - BountyStatus::Funded | - BountyStatus::CuratorProposed { .. } => { - // Nothing extra to do besides the removal of the bounty below. - }, - BountyStatus::Active { curator, .. } => { - // Cancelled by council, refund deposit of the working curator. - let err_amount = T::Currency::unreserve(&curator, bounty.curator_deposit); - debug_assert!(err_amount.is_zero()); - // Then execute removal of the bounty below. - }, - BountyStatus::PendingPayout { .. } => { - // Bounty is already pending payout. If council wants to cancel - // this bounty, it should mean the curator was acting maliciously. - // So the council should first unassign the curator, slashing their - // deposit. - return Err(Error::::PendingPayout.into()) + Bounties::::try_mutate_exists( + bounty_id, + |maybe_bounty| -> DispatchResultWithPostInfo { + let bounty = maybe_bounty.as_ref().ok_or(Error::::InvalidIndex)?; + + match &bounty.status { + BountyStatus::Proposed => { + // The reject origin would like to cancel a proposed bounty. + BountyDescriptions::::remove(bounty_id); + let value = bounty.bond; + let imbalance = T::Currency::slash_reserved(&bounty.proposer, value).0; + T::OnSlash::on_unbalanced(imbalance); + *maybe_bounty = None; + + Self::deposit_event(Event::::BountyRejected(bounty_id, value)); + // Return early, nothing else to do. + return Ok( + Some(::WeightInfo::close_bounty_proposed()).into() + ) + }, + BountyStatus::Approved => { + // For weight reasons, we don't allow a council to cancel in this phase. + // We ask for them to wait until it is funded before they can cancel. + return Err(Error::::UnexpectedStatus.into()) + }, + BountyStatus::Funded | BountyStatus::CuratorProposed { .. } => { + // Nothing extra to do besides the removal of the bounty below. + }, + BountyStatus::Active { curator, .. } => { + // Cancelled by council, refund deposit of the working curator. + let err_amount = + T::Currency::unreserve(&curator, bounty.curator_deposit); + debug_assert!(err_amount.is_zero()); + // Then execute removal of the bounty below. + }, + BountyStatus::PendingPayout { .. } => { + // Bounty is already pending payout. If council wants to cancel + // this bounty, it should mean the curator was acting maliciously. + // So the council should first unassign the curator, slashing their + // deposit. + return Err(Error::::PendingPayout.into()) + }, } - } - let bounty_account = Self::bounty_account_id(bounty_id); + let bounty_account = Self::bounty_account_id(bounty_id); - BountyDescriptions::remove(bounty_id); + BountyDescriptions::::remove(bounty_id); - let balance = T::Currency::free_balance(&bounty_account); - let res = T::Currency::transfer(&bounty_account, &Self::account_id(), balance, AllowDeath); // should not fail - debug_assert!(res.is_ok()); - *maybe_bounty = None; + let balance = T::Currency::free_balance(&bounty_account); + let res = T::Currency::transfer( + &bounty_account, + &Self::account_id(), + balance, + AllowDeath, + ); // should not fail + debug_assert!(res.is_ok()); + *maybe_bounty = None; - Self::deposit_event(Event::::BountyCanceled(bounty_id)); - Ok(Some(::WeightInfo::close_bounty_active()).into()) - }) + Self::deposit_event(Event::::BountyCanceled(bounty_id)); + Ok(Some(::WeightInfo::close_bounty_active()).into()) + }, + ) } /// Extend the expiry time of an active bounty. @@ -647,8 +672,12 @@ decl_module! { /// # /// - O(1). /// # - #[weight = ::WeightInfo::extend_bounty_expiry()] - fn extend_bounty_expiry(origin, #[compact] bounty_id: BountyIndex, _remark: Vec) { + #[pallet::weight(::WeightInfo::extend_bounty_expiry())] + pub fn extend_bounty_expiry( + origin: OriginFor, + #[pallet::compact] bounty_id: BountyIndex, + _remark: Vec, + ) -> DispatchResult { let signer = ensure_signed(origin)?; Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { @@ -657,7 +686,9 @@ decl_module! { match bounty.status { BountyStatus::Active { ref curator, ref mut update_due } => { ensure!(*curator == signer, Error::::RequireCurator); - *update_due = (system::Pallet::::block_number() + T::BountyUpdatePeriod::get()).max(*update_due); + *update_due = (frame_system::Pallet::::block_number() + + T::BountyUpdatePeriod::get()) + .max(*update_due); }, _ => return Err(Error::::UnexpectedStatus.into()), } @@ -666,11 +697,12 @@ decl_module! { })?; Self::deposit_event(Event::::BountyExtended(bounty_id)); + Ok(()) } } } -impl Module { +impl Pallet { // Add public immutables and private mutables. /// The account ID of the treasury pot. @@ -707,7 +739,7 @@ impl Module { T::Currency::reserve(&proposer, bond) .map_err(|_| Error::::InsufficientProposersBalance)?; - BountyCount::put(index + 1); + BountyCount::::put(index + 1); let bounty = Bounty { proposer, @@ -719,22 +751,22 @@ impl Module { }; Bounties::::insert(index, &bounty); - BountyDescriptions::insert(index, description); + BountyDescriptions::::insert(index, description); - Self::deposit_event(RawEvent::BountyProposed(index)); + Self::deposit_event(Event::::BountyProposed(index)); Ok(()) } } -impl pallet_treasury::SpendFunds for Module { +impl pallet_treasury::SpendFunds for Pallet { fn spend_funds( budget_remaining: &mut BalanceOf, imbalance: &mut PositiveImbalanceOf, total_weight: &mut Weight, missed_any: &mut bool, ) { - let bounties_len = BountyApprovals::mutate(|v| { + let bounties_len = BountyApprovals::::mutate(|v| { let bounties_approval_len = v.len() as u32; v.retain(|&index| { Bounties::::mutate(index, |bounty| { @@ -755,7 +787,7 @@ impl pallet_treasury::SpendFunds for Module { bounty.value, )); - Self::deposit_event(RawEvent::BountyBecameActive(index)); + Self::deposit_event(Event::::BountyBecameActive(index)); false } else { *missed_any = true; diff --git a/frame/bounties/src/migrations/mod.rs b/frame/bounties/src/migrations/mod.rs new file mode 100644 index 0000000000000..26d07a0cd5ac8 --- /dev/null +++ b/frame/bounties/src/migrations/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Version 4. +pub mod v4; diff --git a/frame/bounties/src/migrations/v4.rs b/frame/bounties/src/migrations/v4.rs new file mode 100644 index 0000000000000..a1ca0e47680b0 --- /dev/null +++ b/frame/bounties/src/migrations/v4.rs @@ -0,0 +1,230 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_support::{ + storage::{generator::StorageValue, StoragePrefixedMap}, + traits::{ + Get, GetStorageVersion, PalletInfoAccess, StorageVersion, + STORAGE_VERSION_STORAGE_KEY_POSTFIX, + }, + weights::Weight, +}; +use sp_core::hexdisplay::HexDisplay; +use sp_io::{hashing::twox_128, storage}; +use sp_std::str; + +use crate as pallet_bounties; + +/// Migrate the storage of the bounties pallet to a new prefix, leaving all other storage untouched +/// +/// This new prefix must be the same as the one set in construct_runtime. For safety, use +/// `PalletInfo` to get it, as: +/// `::PalletInfo::name::`. +/// +/// The migration will look into the storage version in order not to trigger a migration on an up +/// to date storage. Thus the on chain storage version must be less than 4 in order to trigger the +/// migration. +pub fn migrate< + T: pallet_bounties::Config, + P: GetStorageVersion + PalletInfoAccess, + N: AsRef, +>( + old_pallet_name: N, + new_pallet_name: N, +) -> Weight { + let old_pallet_name = old_pallet_name.as_ref(); + let new_pallet_name = new_pallet_name.as_ref(); + + if new_pallet_name == old_pallet_name { + log::info!( + target: "runtime::bounties", + "New pallet name is equal to the old prefix. No migration needs to be done.", + ); + return 0 + } + + let on_chain_storage_version =

::on_chain_storage_version(); + log::info!( + target: "runtime::bounties", + "Running migration to v4 for bounties with storage version {:?}", + on_chain_storage_version, + ); + + if on_chain_storage_version < 4 { + let storage_prefix = pallet_bounties::BountyCount::::storage_prefix(); + frame_support::storage::migration::move_storage_from_pallet( + storage_prefix, + old_pallet_name.as_bytes(), + new_pallet_name.as_bytes(), + ); + log_migration("migration", storage_prefix, old_pallet_name, new_pallet_name); + + let storage_prefix = pallet_bounties::Bounties::::storage_prefix(); + frame_support::storage::migration::move_storage_from_pallet( + storage_prefix, + old_pallet_name.as_bytes(), + new_pallet_name.as_bytes(), + ); + log_migration("migration", storage_prefix, old_pallet_name, new_pallet_name); + + let storage_prefix = pallet_bounties::BountyDescriptions::::storage_prefix(); + frame_support::storage::migration::move_storage_from_pallet( + storage_prefix, + old_pallet_name.as_bytes(), + new_pallet_name.as_bytes(), + ); + log_migration("migration", storage_prefix, old_pallet_name, new_pallet_name); + + let storage_prefix = pallet_bounties::BountyApprovals::::storage_prefix(); + frame_support::storage::migration::move_storage_from_pallet( + storage_prefix, + old_pallet_name.as_bytes(), + new_pallet_name.as_bytes(), + ); + log_migration("migration", storage_prefix, old_pallet_name, new_pallet_name); + + StorageVersion::new(4).put::

(); + ::BlockWeights::get().max_block + } else { + log::warn!( + target: "runtime::bounties", + "Attempted to apply migration to v4 but failed because storage version is {:?}", + on_chain_storage_version, + ); + 0 + } +} + +/// Some checks prior to migration. This can be linked to +/// [`frame_support::traits::OnRuntimeUpgrade::pre_upgrade`] for further testing. +/// +/// Panics if anything goes wrong. +pub fn pre_migration>( + old_pallet_name: N, + new_pallet_name: N, +) { + let old_pallet_name = old_pallet_name.as_ref(); + let new_pallet_name = new_pallet_name.as_ref(); + let storage_prefix_bounties_count = pallet_bounties::BountyCount::::storage_prefix(); + let storage_prefix_bounties = pallet_bounties::Bounties::::storage_prefix(); + let storage_prefix_bounties_description = + pallet_bounties::BountyDescriptions::::storage_prefix(); + let storage_prefix_bounties_approvals = pallet_bounties::BountyApprovals::::storage_prefix(); + log_migration("pre-migration", storage_prefix_bounties_count, old_pallet_name, new_pallet_name); + log_migration("pre-migration", storage_prefix_bounties, old_pallet_name, new_pallet_name); + log_migration( + "pre-migration", + storage_prefix_bounties_description, + old_pallet_name, + new_pallet_name, + ); + log_migration( + "pre-migration", + storage_prefix_bounties_approvals, + old_pallet_name, + new_pallet_name, + ); + + let new_pallet_prefix = twox_128(new_pallet_name.as_bytes()); + let storage_version_key = + [&new_pallet_prefix, &twox_128(STORAGE_VERSION_STORAGE_KEY_POSTFIX)[..]].concat(); + + // ensure nothing is stored in the new prefix. + assert!( + storage::next_key(&new_pallet_prefix).map_or( + // either nothing is there + true, + // or we ensure that the next key has no common prefix with twox_128(new), + // or is the pallet version that is already stored using the pallet name + |next_key| { + storage::next_key(&next_key).map_or(true, |next_key| { + !next_key.starts_with(&new_pallet_prefix) || next_key == storage_version_key + }) + }, + ), + "unexpected next_key({}) = {:?}", + new_pallet_name, + HexDisplay::from(&sp_io::storage::next_key(&new_pallet_prefix).unwrap()), + ); + assert!(

::on_chain_storage_version() < 4); +} + +/// Some checks for after migration. This can be linked to +/// [`frame_support::traits::OnRuntimeUpgrade::post_upgrade`] for further testing. +/// +/// Panics if anything goes wrong. +pub fn post_migration>( + old_pallet_name: N, + new_pallet_name: N, +) { + let old_pallet_name = old_pallet_name.as_ref(); + let new_pallet_name = new_pallet_name.as_ref(); + let storage_prefix_bounties_count = pallet_bounties::BountyCount::::storage_prefix(); + let storage_prefix_bounties = pallet_bounties::Bounties::::storage_prefix(); + let storage_prefix_bounties_description = + pallet_bounties::BountyDescriptions::::storage_prefix(); + let storage_prefix_bounties_approvals = pallet_bounties::BountyApprovals::::storage_prefix(); + log_migration( + "post-migration", + storage_prefix_bounties_count, + old_pallet_name, + new_pallet_name, + ); + log_migration("post-migration", storage_prefix_bounties, old_pallet_name, new_pallet_name); + log_migration( + "post-migration", + storage_prefix_bounties_description, + old_pallet_name, + new_pallet_name, + ); + log_migration( + "post-migration", + storage_prefix_bounties_approvals, + old_pallet_name, + new_pallet_name, + ); + + let old_pallet_prefix = twox_128(old_pallet_name.as_bytes()); + let old_bounties_count_key = + [&old_pallet_prefix, &twox_128(storage_prefix_bounties_count)[..]].concat(); + let old_bounties_key = [&old_pallet_prefix, &twox_128(storage_prefix_bounties)[..]].concat(); + let old_bounties_description_key = + [&old_pallet_prefix, &twox_128(storage_prefix_bounties_description)[..]].concat(); + let old_bounties_approvals_key = + [&old_pallet_prefix, &twox_128(storage_prefix_bounties_approvals)[..]].concat(); + assert!(storage::next_key(&old_bounties_count_key) + .map_or(true, |next_key| !next_key.starts_with(&old_bounties_count_key))); + assert!(storage::next_key(&old_bounties_key) + .map_or(true, |next_key| !next_key.starts_with(&old_bounties_key))); + assert!(storage::next_key(&old_bounties_description_key) + .map_or(true, |next_key| !next_key.starts_with(&old_bounties_description_key))); + assert!(storage::next_key(&old_bounties_approvals_key) + .map_or(true, |next_key| !next_key.starts_with(&old_bounties_approvals_key))); + + assert_eq!(

::on_chain_storage_version(), 4); +} + +fn log_migration(stage: &str, storage_prefix: &[u8], old_pallet_name: &str, new_pallet_name: &str) { + log::info!( + target: "runtime::bounties", + "{} prefix of storage '{}': '{}' ==> '{}'", + stage, + str::from_utf8(storage_prefix).unwrap_or(""), + old_pallet_name, + new_pallet_name, + ); +} diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index ff058a3601e07..96c09581fdd1e 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -32,9 +32,11 @@ use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BadOrigin, BlakeTwo256, IdentityLookup}, - Perbill, + Perbill, Storage, }; +use super::Event as BountiesEvent; + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -160,7 +162,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { t.into() } -fn last_event() -> RawEvent { +fn last_event() -> BountiesEvent { System::events() .into_iter() .map(|r| r.event) @@ -396,7 +398,7 @@ fn propose_bounty_works() { assert_ok!(Bounties::propose_bounty(Origin::signed(0), 10, b"1234567890".to_vec())); - assert_eq!(last_event(), RawEvent::BountyProposed(0)); + assert_eq!(last_event(), BountiesEvent::BountyProposed(0)); let deposit: u64 = 85 + 5; assert_eq!(Balances::reserved_balance(0), deposit); @@ -458,7 +460,7 @@ fn close_bounty_works() { let deposit: u64 = 80 + 5; - assert_eq!(last_event(), RawEvent::BountyRejected(0, deposit)); + assert_eq!(last_event(), BountiesEvent::BountyRejected(0, deposit)); assert_eq!(Balances::reserved_balance(0), 0); assert_eq!(Balances::free_balance(0), 100 - deposit); @@ -690,7 +692,7 @@ fn award_and_claim_bounty_works() { assert_ok!(Bounties::claim_bounty(Origin::signed(1), 0)); - assert_eq!(last_event(), RawEvent::BountyClaimed(0, 56, 3)); + assert_eq!(last_event(), BountiesEvent::BountyClaimed(0, 56, 3)); assert_eq!(Balances::free_balance(4), 14); // initial 10 + fee 4 @@ -729,7 +731,7 @@ fn claim_handles_high_fee() { assert_ok!(Bounties::claim_bounty(Origin::signed(1), 0)); - assert_eq!(last_event(), RawEvent::BountyClaimed(0, 0, 3)); + assert_eq!(last_event(), BountiesEvent::BountyClaimed(0, 0, 3)); assert_eq!(Balances::free_balance(4), 70); // 30 + 50 - 10 assert_eq!(Balances::free_balance(3), 0); @@ -806,7 +808,7 @@ fn award_and_cancel() { assert_ok!(Bounties::unassign_curator(Origin::root(), 0)); assert_ok!(Bounties::close_bounty(Origin::root(), 0)); - assert_eq!(last_event(), RawEvent::BountyCanceled(0)); + assert_eq!(last_event(), BountiesEvent::BountyCanceled(0)); assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 0); @@ -934,6 +936,48 @@ fn extend_expiry() { }); } +#[test] +fn test_migration_v4() { + let mut s = Storage::default(); + + let index: u32 = 10; + + let bounty = Bounty:: { + proposer: 0, + value: 20, + fee: 20, + curator_deposit: 20, + bond: 50, + status: BountyStatus::::Proposed, + }; + + let data = vec![ + (pallet_bounties::BountyCount::::hashed_key().to_vec(), 10.encode().to_vec()), + (pallet_bounties::Bounties::::hashed_key_for(index), bounty.encode().to_vec()), + (pallet_bounties::BountyDescriptions::::hashed_key_for(index), vec![0, 0]), + ( + pallet_bounties::BountyApprovals::::hashed_key().to_vec(), + vec![10 as u32].encode().to_vec(), + ), + ]; + + s.top = data.into_iter().collect(); + + sp_io::TestExternalities::new(s).execute_with(|| { + use frame_support::traits::PalletInfo; + let old_pallet_name = ::PalletInfo::name::() + .expect("Bounties is part of runtime, so it has a name; qed"); + let new_pallet_name = "NewBounties"; + + crate::migrations::v4::pre_migration::(old_pallet_name, new_pallet_name); + crate::migrations::v4::migrate::(old_pallet_name, new_pallet_name); + crate::migrations::v4::post_migration::( + old_pallet_name, + new_pallet_name, + ); + }); +} + #[test] fn genesis_funding_works() { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); From 700c9e2a476f94438f653423c23b9f0332dbd708 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 21 Sep 2021 16:59:57 +0200 Subject: [PATCH 0010/1472] Silence Kademlia InboundRequestServed event (#9797) Co-authored-by: Roman Proskuryakov --- client/network/src/discovery.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 71e46f73234c7..431de50c0f192 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -733,7 +733,8 @@ impl NetworkBehaviour for DiscoveryBehaviour { let ev = DiscoveryOut::Discovered(peer); return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) }, - KademliaEvent::PendingRoutablePeer { .. } => { + KademliaEvent::PendingRoutablePeer { .. } | + KademliaEvent::InboundRequestServed { .. } => { // We are not interested in this event at the moment. }, KademliaEvent::OutboundQueryCompleted { @@ -844,8 +845,8 @@ impl NetworkBehaviour for DiscoveryBehaviour { ), }, // We never start any other type of query. - e => { - debug!(target: "sub-libp2p", "Libp2p => Unhandled Kademlia event: {:?}", e) + KademliaEvent::OutboundQueryCompleted { result: e, .. } => { + warn!(target: "sub-libp2p", "Libp2p => Unhandled Kademlia event: {:?}", e) }, }, NetworkBehaviourAction::DialAddress { address } => From 04bb4e02137f7aba9c20be071bcf9ba6bceaf8da Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 21 Sep 2021 16:04:28 +0100 Subject: [PATCH 0011/1472] `follow-chain` testing mode for try-runtime (and revamp CLI configs). (#9788) * deadlock, need to ask someone to help now * Finally it seems to be working.. at least for a few blocks * self-review * major mega revamp * some small fixes * another mega refactor * add license * Apply suggestions from code review * hack around signature verification * Some fixes * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: Zeke Mostov <32168567+emostov@users.noreply.github.com> * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: Zeke Mostov <32168567+emostov@users.noreply.github.com> * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: Zeke Mostov <32168567+emostov@users.noreply.github.com> * final tweaks, hopefully. * a little self-review * Add the ext root check Co-authored-by: Zeke Mostov <32168567+emostov@users.noreply.github.com> --- Cargo.lock | 4 + bin/node/runtime/src/lib.rs | 13 +- frame/executive/src/lib.rs | 31 + frame/try-runtime/src/lib.rs | 8 +- primitives/state-machine/src/testing.rs | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/remote-externalities/src/lib.rs | 33 +- utils/frame/try-runtime/cli/Cargo.toml | 6 + .../cli/src/commands/execute_block.rs | 182 ++++ .../cli/src/commands/follow_chain.rs | 176 ++++ .../frame/try-runtime/cli/src/commands/mod.rs | 21 + .../cli/src/commands/offchain_worker.rs | 165 ++++ .../cli/src/commands/on_runtime_upgrade.rs | 92 ++ utils/frame/try-runtime/cli/src/lib.rs | 883 +++++++++++------- 14 files changed, 1238 insertions(+), 380 deletions(-) create mode 100644 utils/frame/try-runtime/cli/src/commands/execute_block.rs create mode 100644 utils/frame/try-runtime/cli/src/commands/follow_chain.rs create mode 100644 utils/frame/try-runtime/cli/src/commands/mod.rs create mode 100644 utils/frame/try-runtime/cli/src/commands/offchain_worker.rs create mode 100644 utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs diff --git a/Cargo.lock b/Cargo.lock index 839c68b71fbf1..e386b600f79ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10687,6 +10687,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ + "jsonrpsee-ws-client", "log 0.4.14", "parity-scale-codec", "remote-externalities", @@ -10696,9 +10697,12 @@ dependencies = [ "sc-service", "serde", "sp-core", + "sp-externalities", + "sp-io", "sp-keystore", "sp-runtime", "sp-state-machine", + "sp-version", "structopt", ] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 28f8e5dc3fd6a..4cf313f8d26f0 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1585,9 +1585,16 @@ impl_runtime_apis! { #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade() -> Result<(Weight, Weight), sp_runtime::RuntimeString> { - let weight = Executive::try_runtime_upgrade()?; - Ok((weight, RuntimeBlockWeights::get().max_block)) + fn on_runtime_upgrade() -> (Weight, Weight) { + // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to + // have a backtrace here. If any of the pre/post migration checks fail, we shall stop + // right here and right now. + let weight = Executive::try_runtime_upgrade().unwrap(); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block_no_check(block: Block) -> Weight { + Executive::execute_block_no_check(block) } } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 9a0fce4d6b5b4..244253185d238 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -220,6 +220,37 @@ where weight } + /// Execute given block, but don't do any of the [`final_checks`]. + /// + /// Should only be used for testing. + #[cfg(feature = "try-runtime")] + pub fn execute_block_no_check(block: Block) -> frame_support::weights::Weight { + Self::initialize_block(block.header()); + Self::initial_checks(&block); + + let (header, extrinsics) = block.deconstruct(); + + Self::execute_extrinsics_with_book_keeping(extrinsics, *header.number()); + + // do some of the checks that would normally happen in `final_checks`, but definitely skip + // the state root check. + { + let new_header = >::finalize(); + let items_zip = header.digest().logs().iter().zip(new_header.digest().logs().iter()); + for (header_item, computed_item) in items_zip { + header_item.check_equal(&computed_item); + assert!(header_item == computed_item, "Digest item must match that calculated."); + } + + assert!( + header.extrinsics_root() == new_header.extrinsics_root(), + "Transaction trie root must be valid.", + ); + } + + frame_system::Pallet::::block_weight().total() + } + /// Execute all `OnRuntimeUpgrade` of this runtime, including the pre and post migration checks. /// /// This should only be used for testing. diff --git a/frame/try-runtime/src/lib.rs b/frame/try-runtime/src/lib.rs index b2dfdfac6429e..754fc1d2a3303 100644 --- a/frame/try-runtime/src/lib.rs +++ b/frame/try-runtime/src/lib.rs @@ -32,6 +32,12 @@ sp_api::decl_runtime_apis! { /// /// Returns the consumed weight of the migration in case of a successful one, combined with /// the total allowed block weight of the runtime. - fn on_runtime_upgrade() -> Result<(Weight, Weight), sp_runtime::RuntimeString>; + fn on_runtime_upgrade() -> (Weight, Weight); + + /// Execute the given block, but don't check that its state root matches that of yours. + /// + /// This is only sensible where the incoming block is from a different network, yet it has + /// the same block format as the runtime implementing this API. + fn execute_block_no_check(block: Block) -> Weight; } } diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index ec1772ba8666f..23f66ee14d87e 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -159,7 +159,7 @@ where /// /// In contrast to [`commit_all`](Self::commit_all) this will not panic if there are open /// transactions. - fn as_backend(&self) -> InMemoryBackend { + pub fn as_backend(&self) -> InMemoryBackend { let top: Vec<_> = self.overlay.changes().map(|(k, v)| (k.clone(), v.value().cloned())).collect(); let mut transaction = vec![(None, top)]; diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index d255499d6c3ad..ce774679f94c2 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee-ws-client = { version = "0.3.0", default-features = false, features = [ "tokio1", -] } +]} jsonrpsee-proc-macros = "0.3.0" env_logger = "0.9" diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index addb3d1dd3c17..2052780286c66 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -112,8 +112,8 @@ pub struct OnlineConfig { pub at: Option, /// An optional state snapshot file to WRITE to, not for reading. Not written if set to `None`. pub state_snapshot: Option, - /// The modules to scrape. If empty, entire chain state will be scraped. - pub modules: Vec, + /// The pallets to scrape. If empty, entire chain state will be scraped. + pub pallets: Vec, /// Transport config. pub transport: Transport, } @@ -134,7 +134,7 @@ impl Default for OnlineConfig { transport: Transport { uri: DEFAULT_TARGET.to_owned(), client: None }, at: None, state_snapshot: None, - modules: vec![], + pallets: vec![], } } } @@ -360,9 +360,9 @@ impl Builder { .clone(); info!(target: LOG_TARGET, "scraping key-pairs from remote @ {:?}", at); - let mut keys_and_values = if config.modules.len() > 0 { + let mut keys_and_values = if config.pallets.len() > 0 { let mut filtered_kv = vec![]; - for f in config.modules.iter() { + for f in config.pallets.iter() { let hashed_prefix = StorageKey(twox_128(f.as_bytes()).to_vec()); let module_kv = self.rpc_get_pairs_paged(hashed_prefix.clone(), at).await?; info!( @@ -376,7 +376,7 @@ impl Builder { } filtered_kv } else { - info!(target: LOG_TARGET, "downloading data for all modules."); + info!(target: LOG_TARGET, "downloading data for all pallets."); self.rpc_get_pairs_paged(StorageKey(vec![]), at).await? }; @@ -482,12 +482,23 @@ impl Builder { self } + /// overwrite the `at` value, if `mode` is set to [`Mode::Online`]. + /// + /// noop if `mode` is [`Mode::Offline`] + pub fn overwrite_online_at(mut self, at: B::Hash) -> Self { + if let Mode::Online(mut online) = self.mode.clone() { + online.at = Some(at); + self.mode = Mode::Online(online); + } + self + } + /// Build the test externalities. pub async fn build(self) -> Result { let kv = self.pre_build().await?; let mut ext = TestExternalities::new_empty(); - debug!(target: LOG_TARGET, "injecting a total of {} keys", kv.len()); + info!(target: LOG_TARGET, "injecting a total of {} keys", kv.len()); for (k, v) in kv { let (k, v) = (k.0, v.0); // Insert the key,value pair into the test trie backend @@ -541,7 +552,7 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - modules: vec!["System".to_owned()], + pallets: vec!["System".to_owned()], ..Default::default() })) .build() @@ -555,7 +566,7 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - modules: vec![ + pallets: vec![ "Proxy".to_owned(), "Multisig".to_owned(), "PhragmenElection".to_owned(), @@ -583,7 +594,7 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - modules: vec!["PhragmenElection".to_owned()], + pallets: vec!["PhragmenElection".to_owned()], ..Default::default() })) .build() @@ -609,7 +620,7 @@ mod remote_tests { Builder::::new() .mode(Mode::Online(OnlineConfig { state_snapshot: Some(SnapshotConfig::new("test_snapshot_to_remove.bin")), - modules: vec!["Balances".to_owned()], + pallets: vec!["Balances".to_owned()], ..Default::default() })) .build() diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 5cc5ae6ee58bb..11b899db4ca47 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -25,6 +25,12 @@ sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" sp-state-machine = { version = "0.10.0-dev", path = "../../../../primitives/state-machine" } sp-runtime = { version = "4.0.0-dev", path = "../../../../primitives/runtime" } sp-core = { version = "4.0.0-dev", path = "../../../../primitives/core" } +sp-io = { version = "4.0.0-dev", path = "../../../../primitives/io" } sp-keystore = { version = "0.10.0-dev", path = "../../../../primitives/keystore" } +sp-externalities = { version = "0.10.0-dev", path = "../../../../primitives/externalities" } +sp-version = { version = "4.0.0-dev", path = "../../../../primitives/version" } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } +jsonrpsee-ws-client = { version = "0.3.0", default-features = false, features = [ + "tokio1", +]} diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs new file mode 100644 index 0000000000000..19422db90119f --- /dev/null +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -0,0 +1,182 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{ + build_executor, ensure_matching_spec, extract_code, full_extensions, hash_of, local_spec, + state_machine_call, SharedParams, State, LOG_TARGET, +}; +use remote_externalities::rpc_api; +use sc_service::{Configuration, NativeExecutionDispatch}; +use sp_core::storage::well_known_keys; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use std::{fmt::Debug, str::FromStr}; + +/// Configurations of the [`Command::ExecuteBlock`]. +#[derive(Debug, Clone, structopt::StructOpt)] +pub struct ExecuteBlockCmd { + /// Overwrite the wasm code in state or not. + #[structopt(long)] + overwrite_wasm_code: bool, + + /// If set, then the state root check is disabled by the virtue of calling into + /// `TryRuntime_execute_block_no_check` instead of + /// `Core_execute_block`. + #[structopt(long)] + no_check: bool, + + /// The block hash at which to fetch the block. + /// + /// If the `live` state type is being used, then this can be omitted, and is equal to whatever + /// the `state::at` is. Only use this (with care) when combined with a snapshot. + #[structopt( + long, + multiple = false, + parse(try_from_str = crate::parse::hash) + )] + block_at: Option, + + /// The ws uri from which to fetch the block. + /// + /// If the `live` state type is being used, then this can be omitted, and is equal to whatever + /// the `state::uri` is. Only use this (with care) when combined with a snapshot. + #[structopt( + long, + multiple = false, + parse(try_from_str = crate::parse::url) + )] + block_ws_uri: Option, + + /// The state type to use. + /// + /// For this command only, if the `live` is used, then state of the parent block is fetched. + /// + /// If `block_at` is provided, then the [`State::Live::at`] is being ignored. + #[structopt(subcommand)] + state: State, +} + +impl ExecuteBlockCmd { + fn block_at(&self) -> sc_cli::Result + where + Block::Hash: FromStr, + ::Err: Debug, + { + match (&self.block_at, &self.state) { + (Some(block_at), State::Snap { .. }) => hash_of::(&block_at), + (Some(block_at), State::Live { .. }) => { + log::warn!(target: LOG_TARGET, "--block-at is provided while state type is live. the `Live::at` will be ignored"); + hash_of::(&block_at) + }, + (None, State::Live { at: Some(at), .. }) => hash_of::(&at), + _ => { + panic!("either `--block-at` must be provided, or state must be `live with a proper `--at``"); + }, + } + } + + fn block_ws_uri(&self) -> String + where + Block::Hash: FromStr, + ::Err: Debug, + { + match (&self.block_ws_uri, &self.state) { + (Some(block_ws_uri), State::Snap { .. }) => block_ws_uri.to_owned(), + (Some(block_ws_uri), State::Live { .. }) => { + log::error!(target: LOG_TARGET, "--block-uri is provided while state type is live, Are you sure you know what you are doing?"); + block_ws_uri.to_owned() + }, + (None, State::Live { uri, .. }) => uri.clone(), + (None, State::Snap { .. }) => { + panic!("either `--block-uri` must be provided, or state must be `live`"); + }, + } + } +} + +pub(crate) async fn execute_block( + shared: SharedParams, + command: ExecuteBlockCmd, + config: Configuration, +) -> sc_cli::Result<()> +where + Block: BlockT + serde::de::DeserializeOwned, + Block::Hash: FromStr, + ::Err: Debug, + NumberFor: FromStr, + as FromStr>::Err: Debug, + ExecDispatch: NativeExecutionDispatch + 'static, +{ + let executor = build_executor::(&shared, &config); + let execution = shared.execution; + + let block_at = command.block_at::()?; + let block_ws_uri = command.block_ws_uri::(); + let block: Block = rpc_api::get_block::(block_ws_uri.clone(), block_at).await?; + let parent_hash = block.header().parent_hash(); + log::info!( + target: LOG_TARGET, + "fetched block from {:?}, parent_hash to fetch the state {:?}", + block_ws_uri, + parent_hash + ); + + let ext = { + let builder = command + .state + .builder::()? + // make sure the state is being build with the parent hash, if it is online. + .overwrite_online_at(parent_hash.to_owned()); + + let builder = if command.overwrite_wasm_code { + let (code_key, code) = extract_code(&config.chain_spec)?; + builder.inject_key_value(&[(code_key, code)]) + } else { + builder.inject_hashed_key(well_known_keys::CODE) + }; + + builder.build().await? + }; + + // A digest item gets added when the runtime is processing the block, so we need to pop + // the last one to be consistent with what a gossiped block would contain. + let (mut header, extrinsics) = block.deconstruct(); + header.digest_mut().pop(); + let block = Block::new(header, extrinsics); + + let (expected_spec_name, expected_spec_version) = + local_spec::(&ext, &executor); + ensure_matching_spec::( + block_ws_uri.clone(), + expected_spec_name, + expected_spec_version, + shared.no_spec_name_check, + ) + .await; + + let _ = state_machine_call::( + &ext, + &executor, + execution, + if command.no_check { "TryRuntime_execute_block_no_check" } else { "Core_execute_block" }, + block.encode().as_ref(), + full_extensions(), + )?; + + log::info!(target: LOG_TARGET, "Core_execute_block executed without errors."); + + Ok(()) +} diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs new file mode 100644 index 0000000000000..0526f5d327fb2 --- /dev/null +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -0,0 +1,176 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{ + build_executor, ensure_matching_spec, extract_code, full_extensions, local_spec, parse, + state_machine_call, SharedParams, LOG_TARGET, +}; +use jsonrpsee_ws_client::{ + types::{traits::SubscriptionClient, v2::params::JsonRpcParams, Subscription}, + WsClientBuilder, +}; +use parity_scale_codec::Decode; +use remote_externalities::{rpc_api, Builder, Mode, OnlineConfig}; +use sc_executor::NativeExecutionDispatch; +use sc_service::Configuration; +use sp_core::H256; +use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; +use std::{fmt::Debug, str::FromStr}; + +const SUB: &'static str = "chain_subscribeFinalizedHeads"; +const UN_SUB: &'static str = "chain_unsubscribeFinalizedHeads"; + +/// Configurations of the [`Command::FollowChain`]. +#[derive(Debug, Clone, structopt::StructOpt)] +pub struct FollowChainCmd { + /// The url to connect to. + #[structopt( + short, + long, + parse(try_from_str = parse::url), + )] + uri: String, +} + +pub(crate) async fn follow_chain( + shared: SharedParams, + command: FollowChainCmd, + config: Configuration, +) -> sc_cli::Result<()> +where + Block: BlockT + serde::de::DeserializeOwned, + Block::Hash: FromStr, + Block::Header: serde::de::DeserializeOwned, + ::Err: Debug, + NumberFor: FromStr, + as FromStr>::Err: Debug, + ExecDispatch: NativeExecutionDispatch + 'static, +{ + let mut maybe_state_ext = None; + + let client = WsClientBuilder::default() + .connection_timeout(std::time::Duration::new(20, 0)) + .max_notifs_per_subscription(1024) + .max_request_body_size(u32::MAX) + .build(&command.uri) + .await + .unwrap(); + + log::info!(target: LOG_TARGET, "subscribing to {:?} / {:?}", SUB, UN_SUB); + let mut subscription: Subscription = + client.subscribe(&SUB, JsonRpcParams::NoParams, &UN_SUB).await.unwrap(); + + let (code_key, code) = extract_code(&config.chain_spec)?; + let executor = build_executor::(&shared, &config); + let execution = shared.execution; + + loop { + let header = match subscription.next().await { + Ok(Some(header)) => header, + Ok(None) => { + log::warn!("subscription returned `None`. Probably decoding has failed."); + break + }, + Err(why) => { + log::warn!("subscription returned error: {:?}.", why); + continue + }, + }; + + let hash = header.hash(); + let number = header.number(); + + let block = rpc_api::get_block::(&command.uri, hash).await.unwrap(); + + log::debug!( + target: LOG_TARGET, + "new block event: {:?} => {:?}, extrinsics: {}", + hash, + number, + block.extrinsics().len() + ); + + // create an ext at the state of this block, whatever is the first subscription event. + if maybe_state_ext.is_none() { + let builder = Builder::::new().mode(Mode::Online(OnlineConfig { + transport: command.uri.clone().into(), + at: Some(header.parent_hash().clone()), + ..Default::default() + })); + + let new_ext = + builder.inject_key_value(&[(code_key.clone(), code.clone())]).build().await?; + log::info!( + target: LOG_TARGET, + "initialized state externalities at {:?}, storage root {:?}", + number, + new_ext.as_backend().root() + ); + + let (expected_spec_name, expected_spec_version) = + local_spec::(&new_ext, &executor); + ensure_matching_spec::( + command.uri.clone(), + expected_spec_name, + expected_spec_version, + shared.no_spec_name_check, + ) + .await; + + maybe_state_ext = Some(new_ext); + } + + let state_ext = + maybe_state_ext.as_mut().expect("state_ext either existed or was just created"); + + let (mut changes, encoded_result) = state_machine_call::( + &state_ext, + &executor, + execution, + "TryRuntime_execute_block_no_check", + block.encode().as_ref(), + full_extensions(), + )?; + + let consumed_weight = ::decode(&mut &*encoded_result) + .map_err(|e| format!("failed to decode output: {:?}", e))?; + + let storage_changes = changes + .drain_storage_changes::<_, _, NumberFor>( + &state_ext.backend, + None, + Default::default(), + &mut Default::default(), + ) + .unwrap(); + state_ext.backend.apply_transaction( + storage_changes.transaction_storage_root, + storage_changes.transaction, + ); + + log::info!( + target: LOG_TARGET, + "executed block {}, consumed weight {}, new storage root {:?}", + number, + consumed_weight, + state_ext.as_backend().root(), + ); + } + + log::error!(target: LOG_TARGET, "ws subscription must have terminated."); + Ok(()) +} diff --git a/utils/frame/try-runtime/cli/src/commands/mod.rs b/utils/frame/try-runtime/cli/src/commands/mod.rs new file mode 100644 index 0000000000000..bfd8290fb31c1 --- /dev/null +++ b/utils/frame/try-runtime/cli/src/commands/mod.rs @@ -0,0 +1,21 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub(crate) mod execute_block; +pub(crate) mod follow_chain; +pub(crate) mod offchain_worker; +pub(crate) mod on_runtime_upgrade; diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs new file mode 100644 index 0000000000000..6f37e4b3849fa --- /dev/null +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -0,0 +1,165 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{ + build_executor, ensure_matching_spec, extract_code, full_extensions, hash_of, local_spec, + parse, state_machine_call, SharedParams, State, LOG_TARGET, +}; +use parity_scale_codec::Encode; +use remote_externalities::rpc_api; +use sc_executor::NativeExecutionDispatch; +use sc_service::Configuration; +use sp_core::storage::well_known_keys; +use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; +use std::{fmt::Debug, str::FromStr}; + +/// Configurations of the [`Command::OffchainWorker`]. +#[derive(Debug, Clone, structopt::StructOpt)] +pub struct OffchainWorkerCmd { + /// Overwrite the wasm code in state or not. + #[structopt(long)] + overwrite_wasm_code: bool, + + /// The block hash at which to fetch the header. + /// + /// If the `live` state type is being used, then this can be omitted, and is equal to whatever + /// the `state::at` is. Only use this (with care) when combined with a snapshot. + #[structopt( + long, + multiple = false, + parse(try_from_str = parse::hash) + )] + header_at: Option, + + /// The ws uri from which to fetch the header. + /// + /// If the `live` state type is being used, then this can be omitted, and is equal to whatever + /// the `state::uri` is. Only use this (with care) when combined with a snapshot. + #[structopt( + long, + multiple = false, + parse(try_from_str = parse::url) + )] + header_ws_uri: Option, + + /// The state type to use. + #[structopt(subcommand)] + pub state: State, +} + +impl OffchainWorkerCmd { + fn header_at(&self) -> sc_cli::Result + where + Block::Hash: FromStr, + ::Err: Debug, + { + match (&self.header_at, &self.state) { + (Some(header_at), State::Snap { .. }) => hash_of::(&header_at), + (Some(header_at), State::Live { .. }) => { + log::error!(target: LOG_TARGET, "--header-at is provided while state type is live, this will most likely lead to a nonsensical result."); + hash_of::(&header_at) + }, + (None, State::Live { at: Some(at), .. }) => hash_of::(&at), + _ => { + panic!("either `--header-at` must be provided, or state must be `live` with a proper `--at`"); + }, + } + } + + fn header_ws_uri(&self) -> String + where + Block::Hash: FromStr, + ::Err: Debug, + { + match (&self.header_ws_uri, &self.state) { + (Some(header_ws_uri), State::Snap { .. }) => header_ws_uri.to_owned(), + (Some(header_ws_uri), State::Live { .. }) => { + log::error!(target: LOG_TARGET, "--header-uri is provided while state type is live, this will most likely lead to a nonsensical result."); + header_ws_uri.to_owned() + }, + (None, State::Live { uri, .. }) => uri.clone(), + (None, State::Snap { .. }) => { + panic!("either `--header-uri` must be provided, or state must be `live`"); + }, + } + } +} + +pub(crate) async fn offchain_worker( + shared: SharedParams, + command: OffchainWorkerCmd, + config: Configuration, +) -> sc_cli::Result<()> +where + Block: BlockT + serde::de::DeserializeOwned, + Block::Hash: FromStr, + Block::Header: serde::de::DeserializeOwned, + ::Err: Debug, + NumberFor: FromStr, + as FromStr>::Err: Debug, + ExecDispatch: NativeExecutionDispatch + 'static, +{ + let executor = build_executor(&shared, &config); + let execution = shared.execution; + + let header_at = command.header_at::()?; + let header_ws_uri = command.header_ws_uri::(); + + let header = rpc_api::get_header::(header_ws_uri.clone(), header_at).await?; + log::info!( + target: LOG_TARGET, + "fetched header from {:?}, block number: {:?}", + header_ws_uri, + header.number() + ); + + let ext = { + let builder = command.state.builder::()?; + + let builder = if command.overwrite_wasm_code { + let (code_key, code) = extract_code(&config.chain_spec)?; + builder.inject_key_value(&[(code_key, code)]) + } else { + builder.inject_hashed_key(well_known_keys::CODE) + }; + + builder.build().await? + }; + + let (expected_spec_name, expected_spec_version) = + local_spec::(&ext, &executor); + ensure_matching_spec::( + header_ws_uri, + expected_spec_name, + expected_spec_version, + shared.no_spec_name_check, + ) + .await; + + let _ = state_machine_call::( + &ext, + &executor, + execution, + "OffchainWorkerApi_offchain_worker", + header.encode().as_ref(), + full_extensions(), + )?; + + log::info!(target: LOG_TARGET, "OffchainWorkerApi_offchain_worker executed without errors."); + + Ok(()) +} diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs new file mode 100644 index 0000000000000..86f5548b8aafa --- /dev/null +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -0,0 +1,92 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::{fmt::Debug, str::FromStr}; + +use parity_scale_codec::Decode; +use sc_executor::NativeExecutionDispatch; +use sc_service::Configuration; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +use crate::{ + build_executor, ensure_matching_spec, extract_code, local_spec, state_machine_call, + SharedParams, State, LOG_TARGET, +}; + +/// Configurations of the [`Command::OnRuntimeUpgrade`]. +#[derive(Debug, Clone, structopt::StructOpt)] +pub struct OnRuntimeUpgradeCmd { + /// The state type to use. + #[structopt(subcommand)] + pub state: State, +} + +pub(crate) async fn on_runtime_upgrade( + shared: SharedParams, + command: OnRuntimeUpgradeCmd, + config: Configuration, +) -> sc_cli::Result<()> +where + Block: BlockT + serde::de::DeserializeOwned, + Block::Hash: FromStr, + ::Err: Debug, + NumberFor: FromStr, + as FromStr>::Err: Debug, + ExecDispatch: NativeExecutionDispatch + 'static, +{ + let executor = build_executor(&shared, &config); + let execution = shared.execution; + + let ext = { + let builder = command.state.builder::()?; + let (code_key, code) = extract_code(&config.chain_spec)?; + builder.inject_key_value(&[(code_key, code)]).build().await? + }; + + if let Some(uri) = command.state.live_uri() { + let (expected_spec_name, expected_spec_version) = + local_spec::(&ext, &executor); + ensure_matching_spec::( + uri, + expected_spec_name, + expected_spec_version, + shared.no_spec_name_check, + ) + .await; + } + + let (_, encoded_result) = state_machine_call::( + &ext, + &executor, + execution, + "TryRuntime_on_runtime_upgrade", + &[], + Default::default(), // we don't really need any extensions here. + )?; + + let (weight, total_weight) = <(u64, u64) as Decode>::decode(&mut &*encoded_result) + .map_err(|e| format!("failed to decode output: {:?}", e))?; + log::info!( + target: LOG_TARGET, + "TryRuntime_on_runtime_upgrade executed without errors. Consumed weight = {}, total weight = {} ({})", + weight, + total_weight, + weight as f64 / total_weight.max(1) as f64 + ); + + Ok(()) +} diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index c92c3959535e9..e7407f2f408fa 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -15,67 +15,331 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! `Structopt`-ready structs for `try-runtime`. - -use parity_scale_codec::{Decode, Encode}; -use remote_externalities::{rpc_api, Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig}; +//! # Try-runtime +//! +//! Substrate's ultimate testing framework for the power users. +//! +//! > As the name suggests, `try-runtime` is a detailed testing framework that gives you a lot of +//! control over what is being executed in which environment. It is recommended that user's first +//! familiarize themselves with substrate in depth, particularly the execution model. It is critical +//! to deeply understand how the wasm/native interactions, and the runtime apis work in the +//! substrate runtime, before commencing to working with `try-runtime`. +//! +//! #### Resources +//! +//! Some resources about the above: +//! +//! 1. https://substrate.dev/docs/en/knowledgebase/integrate/try-runtime +//! 2. https://www.crowdcast.io/e/substrate-seminar/41 +//! 3. https://substrate.dev/docs/en/knowledgebase/advanced/executor +//! +//! --- +//! +//! ## Overview +//! +//! The basis of all try-runtime commands is the same: connect to a live node, scrape its *state* +//! and put it inside a `TestExternalities`, then call into a *specific runtime-api* using the given +//! state and some *runtime*. +//! +//! All of the variables in the above statement are made *italic*. Let's look at each of them: +//! +//! 1. **State** is the key-value pairs of data that comprise the canonical information that any +//! blockchain is keeping. A state can be full (all key-value pairs), or be partial (only pairs +//! related to some pallets). Moreover, some keys are special and are not related to specific +//! pallets, known as [`well_known_keys`] in substrate. The most important of these is the +//! `:CODE:` key, which contains the code used for execution, when wasm execution is chosen. +//! +//! 2. *A runtime-api* call is a call into a function defined in the runtime, *on top of a given +//! state*. Each subcommand of `try-runtime` utilizes a specific *runtime-api*. +//! +//! 3. Finally, the **runtime** is the actual code that is used to execute the aforementioned +//! runtime-api. All substrate based chains always have two runtimes: native and wasm. The +//! decision of which one is chosen is non-trivial. First, let's look at the options: +//! +//! 1. Native: this means that the runtime that is **in your codebase**, aka whatever you see in +//! your editor, is being used. This runtime is easier for diagnostics. We refer to this as +//! the "local runtime". +//! +//! 2. Wasm: this means that whatever is stored in the `:CODE:` key of the state that your +//! scrape is being used. In plain sight, since the entire state (including `:CODE:`) is +//! scraped from a remote chain, you could conclude that the wasm runtime, if used, is always +//! equal to the canonical runtime of the live chain (i.e. NOT the "local runtime"). That's +//! factually true, but then the testing would be quite lame. Typically, with try-runtime, +//! you don't want to execute whatever code is already on the live chain. Instead, you want +//! your local runtime (which typically includes a non-released feature) to be used. This is +//! why try-runtime overwrites the wasm runtime (at `:CODE:`) with the local runtime as well. +//! That being said, this behavior can be controlled in certain subcommands with a special +//! flag (`--overwrite-wasm-code`). +//! +//! The decision of which runtime is eventually used is based on two facts: +//! +//! 1. `--execution` flag. If you specify `wasm`, then it is *always* wasm. If it is `native`, then +//! if and ONLY IF the spec versions match, then the native runtime is used. Else, wasm runtime +//! is used again. +//! 2. `--chain` flag (if present in your cli), which determines *which local runtime*, is selected. +//! This will specify: +//! 1. which native runtime is used, if you select `--execution Native` +//! 2. which wasm runtime is used to replace the `:CODE:`, if try-runtime is instructed to do +//! so. +//! +//! All in all, if the term "local runtime" is used in the rest of this crate's documentation, it +//! means either the native runtime, or the wasm runtime when overwritten inside `:CODE:`. In other +//! words, it means your... well, "local runtime", regardless of wasm or native. +//! +//! //! See [`Command`] for more information about each command's specific customization flags, and +//! assumptions regarding the runtime being used. +//! +//! Finally, To make sure there are no errors regarding this, always run any `try-runtime` command +//! with `executor=trace` logging targets, which will specify which runtime is being used per api +//! call. +//! +//! Furthermore, other relevant log targets are: `try-runtime::cli`, `remote-ext`, and `runtime`. +//! +//! ## Spec name check +//! +//! A common pitfall is that you might be running some test on top of the state of chain `x`, with +//! the runtime of chain `y`. To avoid this all commands do a spec-name check before executing +//! anything by default. This will check the spec name of the remote node your are connected to, +//! with the spec name of your local runtime and ensure that they match. +//! +//! Should you need to disable this on certain occasions, a top level flag of `--no-spec-name-check` +//! can be used. +//! +//! The spec version is also always inspected, but if it is a mismatch, it will only emit a warning. +//! +//! ## Note nodes that operate with `try-runtime` +//! +//! There are a number of flags that need to be preferably set on a running node in order to work +//! well with try-runtime's expensive RPC queries: +//! +//! - set `--rpc-max-payload 1000` to ensure large RPC queries can work. +//! - set `--rpc-cors all` to ensure ws connections can come through. +//! +//! Note that *none* of the try-runtime operations need unsafe RPCs. +//! +//! ## Examples +//! +//! Run the migrations of the local runtime on the state of polkadot, from the polkadot repo where +//! we have `--chain polkadot-dev`, on the latest finalized block's state +//! +//! ```ignore +//! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ +//! cargo run try-runtime \ +//! --execution Native \ +//! --chain polkadot-dev \ +//! on-runtime-upgrade \ +//! live \ +//! --uri wss://rpc.polkadot.io +//! # note that we don't pass any --at, nothing means latest block. +//! ``` +//! +//! Same as previous one, but let's say we want to run this command from the substrate repo, where +//! we don't have a matching spec name/version. +//! +//! ```ignore +//! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ +//! cargo run try-runtime \ +//! --execution Native \ +//! --chain dev \ +//! --no-spec-name-check \ # mind this one! +//! on-runtime-upgrade \ +//! live \ +//! --uri wss://rpc.polkadot.io +//! ``` +//! +//! Same as the previous one, but run it at specific block number's state. This means that this +//! block hash's state shall not yet have been pruned in `rpc.polkadot.io`. +//! +//! ```ignore +//! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ +//! cargo run try-runtime \ +//! --execution Native \ +//! --chain dev \ +//! --no-spec-name-check \ # mind this one! on-runtime-upgrade \ +//! on-runtime-upgrade \ +//! live \ +//! --uri wss://rpc.polkadot.io \ +//! --at +//! ``` +//! +//! Moving to `execute-block` and `offchain-workers`. For these commands, you always needs to +//! specify a block hash. For the rest of these examples, we assume we're in the polkadot repo. +//! +//! First, let's assume you are in a branch that has the same spec name/version as the live polkadot +//! network. +//! +//! ```ignore +//! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ +//! cargo run try-runtime \ +//! --execution Wasm \ +//! --chain polkadot-dev \ +//! --uri wss://rpc.polkadot.io \ +//! execute-block \ +//! live \ +//! --at +//! ``` +//! +//! This is wasm, so it will technically execute the code that lives on the live network. Let's say +//! you want to execute your local runtime. Since you have a matching spec versions, you can simply +//! change `--execution Wasm` to `--execution Native` to achieve this. Your logs of `executor=trace` +//! should show something among the lines of: +//! +//! ```ignore +//! Request for native execution succeeded (native: polkadot-9900 (parity-polkadot-0.tx7.au0), chain: polkadot-9900 (parity-polkadot-0.tx7.au0)) +//! ``` +//! +//! If you don't have matching spec versions, then are doomed to execute wasm. In this case, you can +//! manually overwrite the wasm code with your local runtime: +//! +//! ```ignore +//! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ +//! cargo run try-runtime \ +//! --execution Wasm \ +//! --chain polkadot-dev \ +//! execute-block \ +//! live \ +//! --uri wss://rpc.polkadot.io \ +//! --at \ +//! --overwrite-wasm-code +//! ``` +//! +//! For all of these blocks, the block with hash `` is being used, and the initial state +//! is the state of the parent hash. This is because by omitting [`ExecuteBlockCmd::block_at`], the +//! `--at` is used for both. This should be good enough for 99% of the cases. The only case where +//! you need to specify `block-at` and `block-ws-uri` is with snapshots. Let's say you have a file +//! `snap` and you know it corresponds to the state of the parent block of `X`. Then you'd do: +//! +//! ```ignore +//! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ +//! cargo run try-runtime \ +//! --execution Wasm \ +//! --chain polkadot-dev \ +//! --uri wss://rpc.polkadot.io \ +//! execute-block \ +//! --block-at \ +//! --block-ws-uri wss://rpc.polkadot.io \ +//! --overwrite-wasm-code \ +//! snap \ +//! -s snap \ +//! ``` + +use parity_scale_codec::Decode; +use remote_externalities::{ + Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, TestExternalities, +}; use sc_chain_spec::ChainSpec; use sc_cli::{CliConfiguration, ExecutionStrategy, WasmExecutionMethod}; use sc_executor::NativeElseWasmExecutor; use sc_service::{Configuration, NativeExecutionDispatch}; use sp_core::{ - hashing::twox_128, offchain::{ testing::{TestOffchainExt, TestTransactionPoolExt}, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, }, storage::{well_known_keys, StorageData, StorageKey}, + testing::TaskExecutor, + traits::TaskExecutorExt, + twox_128, H256, }; +use sp_externalities::Extensions; use sp_keystore::{testing::KeyStore, KeystoreExt}; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; -use sp_state_machine::StateMachine; -use std::{fmt::Debug, path::PathBuf, str::FromStr, sync::Arc}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; +use sp_state_machine::{OverlayedChanges, StateMachine}; +use std::{fmt::Debug, path::PathBuf, str::FromStr}; -mod parse; +mod commands; +pub(crate) mod parse; +pub(crate) const LOG_TARGET: &'static str = "try-runtime::cli"; -/// Possible subcommands of `try-runtime`. +/// Possible commands of `try-runtime`. #[derive(Debug, Clone, structopt::StructOpt)] pub enum Command { - /// Execute "TryRuntime_on_runtime_upgrade" against the given runtime state. - OnRuntimeUpgrade(OnRuntimeUpgradeCmd), - /// Execute "OffchainWorkerApi_offchain_worker" against the given runtime state. - OffchainWorker(OffchainWorkerCmd), - /// Execute "Core_execute_block" using the given block and the runtime state of the parent - /// block. - ExecuteBlock(ExecuteBlockCmd), -} - -#[derive(Debug, Clone, structopt::StructOpt)] -pub struct OnRuntimeUpgradeCmd { - #[structopt(subcommand)] - pub state: State, -} - -#[derive(Debug, Clone, structopt::StructOpt)] -pub struct OffchainWorkerCmd { - #[structopt(subcommand)] - pub state: State, -} - -#[derive(Debug, Clone, structopt::StructOpt)] -pub struct ExecuteBlockCmd { - #[structopt(subcommand)] - pub state: State, + /// Execute the migrations of the "local runtime". + /// + /// This uses a custom runtime api call, namely "TryRuntime_on_runtime_upgrade". + /// + /// This always overwrites the wasm code with the local runtime (specified by `--chain`), to + /// ensure the new migrations are being executed. Re-executing already existing migrations is + /// evidently not very exciting. + OnRuntimeUpgrade(commands::on_runtime_upgrade::OnRuntimeUpgradeCmd), + + /// Executes the given block against some state. + /// + /// Unlike [`Command:::OnRuntimeUpgrade`], this command needs two inputs: the state, and the + /// block data. Since the state could be cached (see [`State::Snap`]), different flags are + /// provided for both. `--block-at` and `--block-uri`, if provided, are only used for fetching + /// the block. For convenience, these flags can be both emitted, if the [`State::Live`] is + /// being used. + /// + /// Note that by default, this command does not overwrite the code, so in wasm execution, the + /// live chain's code is used. This can be disabled if desired, see + /// [`ExecuteBlockCmd::overwrite_wasm_code`]. + /// + /// Note that if you do overwrite the wasm code, or generally use the local runtime for this, + /// you might + /// - not be able to decode the block, if the block format has changed. + /// - quite possibly will get a signature verification failure, since the spec and + /// transaction version are part of the signature's payload, and if they differ between + /// your local runtime and the remote counterparts, the signatures cannot be verified. + /// - almost certainly will get a state root mismatch, since, well, you are executing a + /// different state transition function. + /// + /// To make testing slightly more dynamic, you can disable the state root check by enabling + /// [`ExecuteBlockCmd::no_check`]. If you get signature verification errors, you should + /// manually tweak your local runtime's spec version to fix this. + /// + /// A subtle detail of execute block is that if you want to execute block 100 of a live chain + /// again, you need to scrape the state of block 99. This is already done automatically if you + /// use [`State::Live`], and the parent hash of the target block is used to scrape the state. + /// If [`State::Snap`] is being used, then this needs to be manually taken into consideration. + /// + /// This executes the same runtime api as normal block import, namely `Core_execute_block`. If + /// [`ExecuteBlockCmd::no_check`] is set, it uses a custom, try-runtime-only runtime + /// api called `TryRuntime_execute_block_no_check`. + ExecuteBlock(commands::execute_block::ExecuteBlockCmd), + + /// Executes *the offchain worker hooks* of a given block against some state. + /// + /// Similar to [`Command:::ExecuteBlock`], this command needs two inputs: the state, and the + /// header data. Likewise, `--header-at` and `--header-uri` can be filled, or omitted if + /// [`State::Live`] is used. + /// + /// Similar to [`Command:::ExecuteBlock`], this command does not overwrite the code, so in wasm + /// execution, the live chain's code is used. This can be disabled if desired, see + /// [`OffchainWorkerCmd::overwrite_wasm_code`]. + /// + /// This executes the same runtime api as normal block import, namely + /// `OffchainWorkerApi_offchain_worker`. + OffchainWorker(commands::offchain_worker::OffchainWorkerCmd), + + /// Follow the given chain's finalized blocks and apply all of its extrinsics. + /// + /// This is essentially repeated calls to [`Command::ExecuteBlock`], whilst the local runtime + /// is always at use, the state root check is disabled, and the state is persisted between + /// executions. + /// + /// This allows the behavior of a new runtime to be inspected over a long period of time, with + /// realistic transactions coming as input. + /// + /// NOTE: this does NOT execute the offchain worker hooks of mirrored blocks. This might be + /// added in the future. + /// + /// This does not support snapshot states, and can only work with a remote chain. Upon first + /// connections, starts listening for finalized block events. Upon first block notification, it + /// initializes the state from the remote node, and starts applying that block, plus all the + /// blocks that follow, to the same growing state. + FollowChain(commands::follow_chain::FollowChainCmd), } +/// Shared parameters of the `try-runtime` commands #[derive(Debug, Clone, structopt::StructOpt)] pub struct SharedParams { - /// The shared parameters + /// Shared parameters of substrate cli. #[allow(missing_docs)] #[structopt(flatten)] pub shared_params: sc_cli::SharedParams, - /// The execution strategy that should be used for benchmarks + /// The execution strategy that should be used. #[structopt( long = "execution", value_name = "STRATEGY", @@ -85,7 +349,7 @@ pub struct SharedParams { )] pub execution: ExecutionStrategy, - /// Method for executing Wasm runtime code. + /// Type of wasm execution used. #[structopt( long = "wasm-execution", value_name = "METHOD", @@ -96,52 +360,18 @@ pub struct SharedParams { pub wasm_method: WasmExecutionMethod, /// The number of 64KB pages to allocate for Wasm execution. Defaults to - /// sc_service::Configuration.default_heap_pages. + /// [`sc_service::Configuration.default_heap_pages`]. #[structopt(long)] pub heap_pages: Option, - /// The block hash at which to read state. This is required for execute-block, offchain-worker, - /// or any command that used the live subcommand. - #[structopt( - short, - long, - multiple = false, - parse(try_from_str = parse::hash), - required_ifs( - &[("command", "offchain-worker"), ("command", "execute-block"), ("subcommand", "live")] - ) - )] - block_at: String, - - /// Whether or not to overwrite the code from state with the code from - /// the specified chain spec. + /// When enabled, the spec name check will not panic, and instead only show a warning. #[structopt(long)] - pub overwrite_code: bool, - - /// The url to connect to. - // TODO having this a shared parm is a temporary hack; the url is used just - // to get the header/block. We should try and get that out of state, OR allow - // the user to feed in a header/block via file. - // https://github.com/paritytech/substrate/issues/9027 - #[structopt(short, long, default_value = "ws://localhost:9944", parse(try_from_str = parse::url))] - url: String, + pub no_spec_name_check: bool, } -impl SharedParams { - /// Get the configured value of `block_at`, interpreted as the hash type of `Block`. - pub fn block_at(&self) -> sc_cli::Result - where - Block: BlockT, - ::Hash: FromStr, - <::Hash as FromStr>::Err: Debug, - { - self.block_at - .parse::<::Hash>() - .map_err(|e| format!("Could not parse block hash: {:?}", e).into()) - } -} - -/// Various commands to try out against runtime state at a specific block. +/// Our `try-runtime` command. +/// +/// See [`Command`] for more info. #[derive(Debug, Clone, structopt::StructOpt)] pub struct TryRuntimeCmd { #[structopt(flatten)] @@ -151,11 +381,12 @@ pub struct TryRuntimeCmd { pub command: Command, } -/// The source of runtime state to try operations against. +/// The source of runtime *state* to use. #[derive(Debug, Clone, structopt::StructOpt)] pub enum State { - /// Use a state snapshot as the source of runtime state. NOTE: for the offchain-worker and - /// execute-block command this is only partially supported and requires a archive node url. + /// Use a state snapshot as the source of runtime state. + /// + /// This can be crated by passing a value to [`State::Live::snapshot_path`]. Snap { #[structopt(short, long)] snapshot_path: PathBuf, @@ -163,285 +394,80 @@ pub enum State { /// Use a live chain as the source of runtime state. Live { + /// The url to connect to. + #[structopt( + short, + long, + parse(try_from_str = parse::url), + )] + uri: String, + + /// The block hash at which to fetch the state. + /// + /// If non provided, then the latest finalized head is used. This is particularly useful + /// for [`Command::OnRuntimeUpgrade`]. + #[structopt( + short, + long, + multiple = false, + parse(try_from_str = parse::hash), + )] + at: Option, + /// An optional state snapshot file to WRITE to. Not written if set to `None`. #[structopt(short, long)] snapshot_path: Option, - /// The modules to scrape. If empty, entire chain state will be scraped. + /// The pallets to scrape. If empty, entire chain state will be scraped. #[structopt(short, long, require_delimiter = true)] - modules: Option>, + pallets: Option>, }, } -async fn on_runtime_upgrade( - shared: SharedParams, - command: OnRuntimeUpgradeCmd, - config: Configuration, -) -> sc_cli::Result<()> -where - Block: BlockT + serde::de::DeserializeOwned, - Block::Hash: FromStr, - ::Err: Debug, - NumberFor: FromStr, - as FromStr>::Err: Debug, - ExecDispatch: NativeExecutionDispatch + 'static, -{ - let wasm_method = shared.wasm_method; - let execution = shared.execution; - let heap_pages = shared.heap_pages.or(config.default_heap_pages); - - let mut changes = Default::default(); - let max_runtime_instances = config.max_runtime_instances; - let executor = NativeElseWasmExecutor::::new( - wasm_method.into(), - heap_pages, - max_runtime_instances, - ); - - check_spec_name::(shared.url.clone(), config.chain_spec.name().to_string()).await; - - let ext = { - let builder = match command.state { +impl State { + /// Create the [`remote_externalities::Builder`] from self. + pub(crate) fn builder(&self) -> sc_cli::Result> + where + Block::Hash: FromStr, + ::Err: Debug, + { + Ok(match self { State::Snap { snapshot_path } => Builder::::new().mode(Mode::Offline(OfflineConfig { state_snapshot: SnapshotConfig::new(snapshot_path), })), - State::Live { snapshot_path, modules } => - Builder::::new().mode(Mode::Online(OnlineConfig { - transport: shared.url.to_owned().into(), - state_snapshot: snapshot_path.as_ref().map(SnapshotConfig::new), - modules: modules.to_owned().unwrap_or_default(), - at: Some(shared.block_at::()?), - ..Default::default() - })), - }; - - let (code_key, code) = extract_code(config.chain_spec)?; - builder - .inject_key_value(&[(code_key, code)]) - .inject_hashed_key(&[twox_128(b"System"), twox_128(b"LastRuntimeUpgrade")].concat()) - .build() - .await? - }; - - let encoded_result = StateMachine::<_, _, NumberFor, _>::new( - &ext.backend, - None, - &mut changes, - &executor, - "TryRuntime_on_runtime_upgrade", - &[], - ext.extensions, - &sp_state_machine::backend::BackendRuntimeCode::new(&ext.backend).runtime_code()?, - sp_core::testing::TaskExecutor::new(), - ) - .execute(execution.into()) - .map_err(|e| format!("failed to execute 'TryRuntime_on_runtime_upgrade': {:?}", e))?; - - let (weight, total_weight) = <(u64, u64) as Decode>::decode(&mut &*encoded_result) - .map_err(|e| format!("failed to decode output: {:?}", e))?; - log::info!( - "TryRuntime_on_runtime_upgrade executed without errors. Consumed weight = {}, total weight = {} ({})", - weight, - total_weight, - weight as f64 / total_weight as f64 - ); - - Ok(()) -} - -async fn offchain_worker( - shared: SharedParams, - command: OffchainWorkerCmd, - config: Configuration, -) -> sc_cli::Result<()> -where - Block: BlockT + serde::de::DeserializeOwned, - Block::Hash: FromStr, - Block::Header: serde::de::DeserializeOwned, - ::Err: Debug, - NumberFor: FromStr, - as FromStr>::Err: Debug, - ExecDispatch: NativeExecutionDispatch + 'static, -{ - let wasm_method = shared.wasm_method; - let execution = shared.execution; - let heap_pages = shared.heap_pages.or(config.default_heap_pages); - - let mut changes = Default::default(); - let max_runtime_instances = config.max_runtime_instances; - let executor = NativeElseWasmExecutor::::new( - wasm_method.into(), - heap_pages, - max_runtime_instances, - ); - - check_spec_name::(shared.url.clone(), config.chain_spec.name().to_string()).await; - - let mode = match command.state { - State::Live { snapshot_path, modules } => { - let at = shared.block_at::()?; - let online_config = OnlineConfig { - transport: shared.url.to_owned().into(), - state_snapshot: snapshot_path.as_ref().map(SnapshotConfig::new), - modules: modules.to_owned().unwrap_or_default(), - at: Some(at), - ..Default::default() - }; - - Mode::Online(online_config) - }, - State::Snap { snapshot_path } => { - let mode = - Mode::Offline(OfflineConfig { state_snapshot: SnapshotConfig::new(snapshot_path) }); - - mode - }, - }; - let builder = Builder::::new() - .mode(mode) - .inject_hashed_key(&[twox_128(b"System"), twox_128(b"LastRuntimeUpgrade")].concat()); - let mut ext = if shared.overwrite_code { - let (code_key, code) = extract_code(config.chain_spec)?; - builder.inject_key_value(&[(code_key, code)]).build().await? - } else { - builder.inject_hashed_key(well_known_keys::CODE).build().await? - }; - - let (offchain, _offchain_state) = TestOffchainExt::new(); - let (pool, _pool_state) = TestTransactionPoolExt::new(); - ext.register_extension(OffchainDbExt::new(offchain.clone())); - ext.register_extension(OffchainWorkerExt::new(offchain)); - ext.register_extension(KeystoreExt(Arc::new(KeyStore::new()))); - ext.register_extension(TransactionPoolExt::new(pool)); - - let header_hash = shared.block_at::()?; - let header = rpc_api::get_header::(shared.url, header_hash).await?; - - let _ = StateMachine::<_, _, NumberFor, _>::new( - &ext.backend, - None, - &mut changes, - &executor, - "OffchainWorkerApi_offchain_worker", - header.encode().as_ref(), - ext.extensions, - &sp_state_machine::backend::BackendRuntimeCode::new(&ext.backend).runtime_code()?, - sp_core::testing::TaskExecutor::new(), - ) - .execute(execution.into()) - .map_err(|e| format!("failed to execute 'OffchainWorkerApi_offchain_worker': {:?}", e))?; - - log::info!("OffchainWorkerApi_offchain_worker executed without errors."); - - Ok(()) -} - -async fn execute_block( - shared: SharedParams, - command: ExecuteBlockCmd, - config: Configuration, -) -> sc_cli::Result<()> -where - Block: BlockT + serde::de::DeserializeOwned, - Block::Hash: FromStr, - ::Err: Debug, - NumberFor: FromStr, - as FromStr>::Err: Debug, - ExecDispatch: NativeExecutionDispatch + 'static, -{ - let wasm_method = shared.wasm_method; - let execution = shared.execution; - let heap_pages = shared.heap_pages.or(config.default_heap_pages); - - let mut changes = Default::default(); - let max_runtime_instances = config.max_runtime_instances; - let executor = NativeElseWasmExecutor::::new( - wasm_method.into(), - heap_pages, - max_runtime_instances, - ); - - let block_hash = shared.block_at::()?; - let block: Block = rpc_api::get_block::(shared.url.clone(), block_hash).await?; - - check_spec_name::(shared.url.clone(), config.chain_spec.name().to_string()).await; - - let mode = match command.state { - State::Snap { snapshot_path } => { - let mode = - Mode::Offline(OfflineConfig { state_snapshot: SnapshotConfig::new(snapshot_path) }); - - mode - }, - State::Live { snapshot_path, modules } => { - let parent_hash = block.header().parent_hash(); - - let mode = Mode::Online(OnlineConfig { - transport: shared.url.to_owned().into(), - state_snapshot: snapshot_path.as_ref().map(SnapshotConfig::new), - modules: modules.to_owned().unwrap_or_default(), - at: Some(parent_hash.to_owned()), - ..Default::default() - }); - - mode - }, - }; - - let ext = { - let builder = Builder::::new() - .mode(mode) - .inject_hashed_key(&[twox_128(b"System"), twox_128(b"LastRuntimeUpgrade")].concat()); - let mut ext = if shared.overwrite_code { - let (code_key, code) = extract_code(config.chain_spec)?; - builder.inject_key_value(&[(code_key, code)]).build().await? - } else { - builder.inject_hashed_key(well_known_keys::CODE).build().await? - }; - - // register externality extensions in order to provide host interface for OCW to the - // runtime. - let (offchain, _offchain_state) = TestOffchainExt::new(); - let (pool, _pool_state) = TestTransactionPoolExt::new(); - ext.register_extension(OffchainDbExt::new(offchain.clone())); - ext.register_extension(OffchainWorkerExt::new(offchain)); - ext.register_extension(KeystoreExt(Arc::new(KeyStore::new()))); - ext.register_extension(TransactionPoolExt::new(pool)); - - ext - }; - - // A digest item gets added when the runtime is processing the block, so we need to pop - // the last one to be consistent with what a gossiped block would contain. - let (mut header, extrinsics) = block.deconstruct(); - header.digest_mut().pop(); - let block = Block::new(header, extrinsics); - - let _encoded_result = StateMachine::<_, _, NumberFor, _>::new( - &ext.backend, - None, - &mut changes, - &executor, - "Core_execute_block", - block.encode().as_ref(), - ext.extensions, - &sp_state_machine::backend::BackendRuntimeCode::new(&ext.backend).runtime_code()?, - sp_core::testing::TaskExecutor::new(), - ) - .execute(execution.into()) - .map_err(|e| format!("failed to execute 'Core_execute_block': {:?}", e))?; - debug_assert!(_encoded_result == vec![1]); - - log::info!("Core_execute_block executed without errors."); + State::Live { snapshot_path, pallets, uri, at } => { + let at = match at { + Some(at_str) => Some(hash_of::(at_str)?), + None => None, + }; + Builder::::new() + .mode(Mode::Online(OnlineConfig { + transport: uri.to_owned().into(), + state_snapshot: snapshot_path.as_ref().map(SnapshotConfig::new), + pallets: pallets.to_owned().unwrap_or_default(), + at, + })) + .inject_hashed_key( + &[twox_128(b"System"), twox_128(b"LastRuntimeUpgrade")].concat(), + ) + }, + }) + } - Ok(()) + /// Get the uri, if self is `Live`. + pub(crate) fn live_uri(&self) -> Option { + match self { + State::Live { uri, .. } => Some(uri.clone()), + _ => None, + } + } } impl TryRuntimeCmd { pub async fn run(&self, config: Configuration) -> sc_cli::Result<()> where - Block: BlockT + serde::de::DeserializeOwned, + Block: BlockT + serde::de::DeserializeOwned, Block::Header: serde::de::DeserializeOwned, Block::Hash: FromStr, ::Err: Debug, @@ -451,13 +477,33 @@ impl TryRuntimeCmd { { match &self.command { Command::OnRuntimeUpgrade(ref cmd) => - on_runtime_upgrade::(self.shared.clone(), cmd.clone(), config) - .await, + commands::on_runtime_upgrade::on_runtime_upgrade::( + self.shared.clone(), + cmd.clone(), + config, + ) + .await, Command::OffchainWorker(cmd) => - offchain_worker::(self.shared.clone(), cmd.clone(), config) - .await, + commands::offchain_worker::offchain_worker::( + self.shared.clone(), + cmd.clone(), + config, + ) + .await, Command::ExecuteBlock(cmd) => - execute_block::(self.shared.clone(), cmd.clone(), config).await, + commands::execute_block::execute_block::( + self.shared.clone(), + cmd.clone(), + config, + ) + .await, + Command::FollowChain(cmd) => + commands::follow_chain::follow_chain::( + self.shared.clone(), + cmd.clone(), + config, + ) + .await, } } } @@ -477,7 +523,7 @@ impl CliConfiguration for TryRuntimeCmd { /// Extract `:code` from the given chain spec and return as `StorageData` along with the /// corresponding `StorageKey`. -fn extract_code(spec: Box) -> sc_cli::Result<(StorageKey, StorageData)> { +pub(crate) fn extract_code(spec: &Box) -> sc_cli::Result<(StorageKey, StorageData)> { let genesis_storage = spec.build_storage()?; let code = StorageData( genesis_storage @@ -491,31 +537,142 @@ fn extract_code(spec: Box) -> sc_cli::Result<(StorageKey, Storage Ok((code_key, code)) } +/// Get the hash type of the generic `Block` from a `hash_str`. +pub(crate) fn hash_of(hash_str: &str) -> sc_cli::Result +where + Block::Hash: FromStr, + ::Err: Debug, +{ + hash_str + .parse::<::Hash>() + .map_err(|e| format!("Could not parse block hash: {:?}", e).into()) +} + /// Check the spec_name of an `ext` /// -/// If the version does not exist, or if it does not match with the given, it emits a warning. -async fn check_spec_name( +/// If the spec names don't match, if `relaxed`, then it emits a warning, else it panics. +/// If the spec versions don't match, it only ever emits a warning. +pub(crate) async fn ensure_matching_spec( uri: String, expected_spec_name: String, + expected_spec_version: u32, + relaxed: bool, ) { - let expected_spec_name = expected_spec_name.to_lowercase(); match remote_externalities::rpc_api::get_runtime_version::(uri.clone(), None) .await - .map(|version| String::from(version.spec_name.clone())) - .map(|spec_name| spec_name.to_lowercase()) + .map(|version| (String::from(version.spec_name.clone()), version.spec_version)) + .map(|(spec_name, spec_version)| (spec_name.to_lowercase(), spec_version)) { - Ok(spec) if spec == expected_spec_name => { - log::debug!("found matching spec name: {:?}", spec); - }, - Ok(spec) => { - log::warn!( - "version mismatch: remote spec name: '{}', expected (local chain spec, aka. `--chain`): '{}'", - spec, - expected_spec_name, - ); + Ok((name, version)) => { + // first, deal with spec name + if expected_spec_name == name { + log::info!(target: LOG_TARGET, "found matching spec name: {:?}", name); + } else { + let msg = format!( + "version mismatch: remote spec name: '{}', expected (local chain spec, aka. `--chain`): '{}'", + name, + expected_spec_name + ); + if relaxed { + log::warn!(target: LOG_TARGET, "{}", msg); + } else { + panic!("{}", msg); + } + } + + if expected_spec_version == version { + log::info!(target: LOG_TARGET, "found matching spec version: {:?}", version); + } else { + log::warn!( + target: LOG_TARGET, + "spec version mismatch (local {} != remote {}). This could cause some issues.", + expected_spec_version, + version + ); + } }, Err(why) => { - log::error!("failed to fetch runtime version from {}: {:?}", uri, why); + log::error!( + target: LOG_TARGET, + "failed to fetch runtime version from {}: {:?}. Skipping the check", + uri, + why + ); }, } } + +/// Build all extensions that we typically use. +pub(crate) fn full_extensions() -> Extensions { + let mut extensions = Extensions::default(); + extensions.register(TaskExecutorExt::new(TaskExecutor::new())); + let (offchain, _offchain_state) = TestOffchainExt::new(); + let (pool, _pool_state) = TestTransactionPoolExt::new(); + extensions.register(OffchainDbExt::new(offchain.clone())); + extensions.register(OffchainWorkerExt::new(offchain)); + extensions.register(KeystoreExt(std::sync::Arc::new(KeyStore::new()))); + extensions.register(TransactionPoolExt::new(pool)); + + extensions +} + +/// Build a default execution that we typically use. +pub(crate) fn build_executor( + shared: &SharedParams, + config: &sc_service::Configuration, +) -> NativeElseWasmExecutor { + let wasm_method = shared.wasm_method; + let heap_pages = shared.heap_pages.or(config.default_heap_pages); + let max_runtime_instances = config.max_runtime_instances; + + NativeElseWasmExecutor::::new(wasm_method.into(), heap_pages, max_runtime_instances) +} + +/// Execute the given `method` and `data` on top of `ext`, returning the results (encoded) and the +/// state `changes`. +pub(crate) fn state_machine_call( + ext: &TestExternalities, + executor: &NativeElseWasmExecutor, + execution: sc_cli::ExecutionStrategy, + method: &'static str, + data: &[u8], + extensions: Extensions, +) -> sc_cli::Result<(OverlayedChanges, Vec)> { + let mut changes = Default::default(); + let encoded_results = StateMachine::<_, _, NumberFor, _>::new( + &ext.backend, + None, + &mut changes, + executor, + method, + data, + extensions, + &sp_state_machine::backend::BackendRuntimeCode::new(&ext.backend).runtime_code()?, + sp_core::testing::TaskExecutor::new(), + ) + .execute(execution.into()) + .map_err(|e| format!("failed to execute 'TryRuntime_on_runtime_upgrade': {:?}", e)) + .map_err::(Into::into)?; + + Ok((changes, encoded_results)) +} + +/// Get the spec `(name, version)` from the local runtime. +pub(crate) fn local_spec( + ext: &TestExternalities, + executor: &NativeElseWasmExecutor, +) -> (String, u32) { + let (_, encoded) = state_machine_call::( + &ext, + &executor, + sc_cli::ExecutionStrategy::NativeElseWasm, + "Core_version", + &[], + Default::default(), + ) + .expect("all runtimes should have version; qed"); + ::decode(&mut &*encoded) + .map_err(|e| format!("failed to decode output: {:?}", e)) + .map(|v| (v.spec_name.into(), v.spec_version)) + .expect("all runtimes should have version; qed") +} From da6094d286cca99a9bc5acb2412341280e3828ab Mon Sep 17 00:00:00 2001 From: Alexander Popiak Date: Tue, 21 Sep 2021 20:43:45 +0200 Subject: [PATCH 0012/1472] Pull Request Template Suggestions (#9717) * pull request template suggestions * Update docs/PULL_REQUEST_TEMPLATE.md Co-authored-by: Squirrel Co-authored-by: Squirrel Co-authored-by: thiolliere --- docs/PULL_REQUEST_TEMPLATE.md | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md index 77f5f79f60d40..12f39371892e7 100644 --- a/docs/PULL_REQUEST_TEMPLATE.md +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -1,26 +1,32 @@ -Thank you for your Pull Request! -Before you submitting, please check that: -- [ ] You added a brief description of the PR, e.g.: +✄ ----------------------------------------------------------------------------- + +Thank you for your Pull Request! 🙏 + +Before you submit, please check that: + +- [ ] **Description:** You added a brief description of the PR, e.g.: - What does it do? - - What important points reviewers should know? + - What important points should reviewers know? - Is there something left for follow-up PRs? -- [ ] You labeled the PR appropriately if you have permissions to do so: +- [ ] **Labels:** You labeled the PR appropriately if you have permissions to do so: - [ ] `A*` for PR status (**one required**) - [ ] `B*` for changelog (**one required**) - [ ] `C*` for release notes (**exactly one required**) - [ ] `D*` for various implications/requirements - - [ ] Github's project assignment -- [ ] You mentioned a related issue if this PR related to it, e.g. `Fixes #228` or `Related #1337`. -- [ ] You asked any particular reviewers to review. If you aren't sure, start with GH suggestions. -- [ ] Your PR adheres to [the style guide](https://github.com/paritytech/substrate/blob/master/docs/STYLE_GUIDE.md) + - [ ] Github project assignment +- [ ] **Related Issues:** You mentioned a related issue if this PR is related to it, e.g. `Fixes #228` or `Related #1337`. +- [ ] **2 Reviewers:** You asked at least two reviewers to review. If you aren't sure, start with GH suggestions. +- [ ] **Style Guide:** Your PR adheres to [the style guide](https://github.com/paritytech/substrate/blob/master/docs/STYLE_GUIDE.md) - In particular, mind the maximal line length of 100 (120 in exceptional circumstances). - There is no commented code checked in unless necessary. - - Any panickers have a proof or removed. -- [ ] You bumped the runtime version if there are breaking changes in the **runtime**. -- [ ] You updated any rustdocs which may have changed -- [ ] Has the PR altered the external API or interfaces used by Polkadot? Do you have the corresponding Polkadot PR ready? + - Any panickers in the runtime have a proof or were removed. +- [ ] **Runtime Version:** You bumped the runtime version if there are breaking changes in the **runtime**. +- [ ] **Docs:** You updated any rustdocs which may need to change. +- [ ] **Polkadot Companion:** Has the PR altered the external API or interfaces used by Polkadot? + - [ ] If so, do you have the corresponding Polkadot PR ready? + - [ ] Optionally: Do you have a corresponding Cumulus PR? Refer to [the contributing guide](https://github.com/paritytech/substrate/blob/master/docs/CONTRIBUTING.adoc) for details. From 0a18fa066c781aa12ae57803759a5dec317b2e5c Mon Sep 17 00:00:00 2001 From: ferrell-code Date: Tue, 21 Sep 2021 19:21:41 -0400 Subject: [PATCH 0013/1472] Society Pallet to FrameV2 (#9472) * migrate society * remove unused imports * cargo fmt * trigger ci * pass new ci * Apply suggestions from code review * fmt * regression bench ci? * remove metadata, fixed with typing! Co-authored-by: Guillaume Thiolliere Co-authored-by: charlesferrell --- frame/society/src/lib.rs | 754 +++++++++++++++++++++----------------- frame/society/src/mock.rs | 5 +- 2 files changed, 422 insertions(+), 337 deletions(-) diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index c6d63eed20ac0..83b1c4203722b 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -15,14 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Society Module +//! # Society Pallet //! //! - [`Config`] //! - [`Call`] //! //! ## Overview //! -//! The Society module is an economic game which incentivizes users to participate +//! The Society pallet is an economic game which incentivizes users to participate //! and maintain a membership society. //! //! ### User Types @@ -77,7 +77,7 @@ //! #### Society Treasury //! //! The membership society is independently funded by a treasury managed by this -//! module. Some subset of this treasury is placed in a Society Pot, which is used +//! pallet. Some subset of this treasury is placed in a Society Pot, which is used //! to determine the number of accepted bids. //! //! #### Rate of Growth @@ -132,7 +132,7 @@ //! the society. A vouching bid can additionally request some portion of that reward as a tip //! to the voucher for vouching for the prospective candidate. //! -//! Every rotation period, Bids are ordered by reward amount, and the module +//! Every rotation period, Bids are ordered by reward amount, and the pallet //! selects as many bids the Society Pot can support for that period. //! //! These selected bids become candidates and move on to the Candidate phase. @@ -251,19 +251,15 @@ mod mock; #[cfg(test)] mod tests; -use codec::{Decode, Encode}; use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, - dispatch::DispatchResult, - ensure, + pallet_prelude::*, traits::{ BalanceStatus, ChangeMembers, Currency, EnsureOrigin, ExistenceRequirement::AllowDeath, - Get, Imbalance, OnUnbalanced, Randomness, ReservableCurrency, + Imbalance, OnUnbalanced, Randomness, ReservableCurrency, }, - weights::Weight, PalletId, }; -use frame_system::{self as system, ensure_root, ensure_signed}; +use frame_system::pallet_prelude::*; use rand_chacha::{ rand_core::{RngCore, SeedableRng}, ChaChaRng, @@ -278,62 +274,14 @@ use sp_runtime::{ }; use sp_std::prelude::*; +pub use pallet::*; + type BalanceOf = - <>::Currency as Currency<::AccountId>>::Balance; -type NegativeImbalanceOf = <::Currency as Currency< + <>::Currency as Currency<::AccountId>>::Balance; +type NegativeImbalanceOf = <>::Currency as Currency< ::AccountId, >>::NegativeImbalance; -/// The module's configuration trait. -pub trait Config: system::Config { - /// The overarching event type. - type Event: From> + Into<::Event>; - - /// The societies's module id - type PalletId: Get; - - /// The currency type used for bidding. - type Currency: ReservableCurrency; - - /// Something that provides randomness in the runtime. - type Randomness: Randomness; - - /// The minimum amount of a deposit required for a bid to be made. - type CandidateDeposit: Get>; - - /// The amount of the unpaid reward that gets deducted in the case that either a skeptic - /// doesn't vote or someone votes in the wrong way. - type WrongSideDeduction: Get>; - - /// The number of times a member may vote the wrong way (or not at all, when they are a skeptic) - /// before they become suspended. - type MaxStrikes: Get; - - /// The amount of incentive paid within each period. Doesn't include VoterTip. - type PeriodSpend: Get>; - - /// The receiver of the signal for when the members have changed. - type MembershipChanged: ChangeMembers; - - /// The number of blocks between candidate/membership rotation periods. - type RotationPeriod: Get; - - /// The maximum duration of the payout lock. - type MaxLockDuration: Get; - - /// The origin that is allowed to call `found`. - type FounderSetOrigin: EnsureOrigin; - - /// The origin that is allowed to make suspension judgements. - type SuspensionJudgementOrigin: EnsureOrigin; - - /// The number of blocks between membership challenges. - type ChallengePeriod: Get; - - /// The maximum number of candidates that we accept per round. - type MaxCandidateIntake: Get; -} - /// A vote by a member on a candidate application. #[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub enum Vote { @@ -417,108 +365,320 @@ impl BidKind { } } -// This module's storage items. -decl_storage! { - trait Store for Module, I: Instance=DefaultInstance> as Society { - /// The first member. - pub Founder get(fn founder) build(|config: &GenesisConfig| config.members.first().cloned()): - Option; +#[frame_support::pallet] +pub mod pallet { + use super::*; - /// A hash of the rules of this society concerning membership. Can only be set once and - /// only by the founder. - pub Rules get(fn rules): Option; + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); - /// The current set of candidates; bidders that are attempting to become members. - pub Candidates get(fn candidates): Vec>>; + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; - /// The set of suspended candidates. - pub SuspendedCandidates get(fn suspended_candidate): - map hasher(twox_64_concat) T::AccountId - => Option<(BalanceOf, BidKind>)>; + /// The societies's pallet id + #[pallet::constant] + type PalletId: Get; - /// Amount of our account balance that is specifically for the next round's bid(s). - pub Pot get(fn pot) config(): BalanceOf; + /// The currency type used for bidding. + type Currency: ReservableCurrency; - /// The most primary from the most recently approved members. - pub Head get(fn head) build(|config: &GenesisConfig| config.members.first().cloned()): - Option; + /// Something that provides randomness in the runtime. + type Randomness: Randomness; - /// The current set of members, ordered. - pub Members get(fn members) build(|config: &GenesisConfig| { - let mut m = config.members.clone(); - m.sort(); - m - }): Vec; + /// The minimum amount of a deposit required for a bid to be made. + #[pallet::constant] + type CandidateDeposit: Get>; + + /// The amount of the unpaid reward that gets deducted in the case that either a skeptic + /// doesn't vote or someone votes in the wrong way. + #[pallet::constant] + type WrongSideDeduction: Get>; - /// The set of suspended members. - pub SuspendedMembers get(fn suspended_member): map hasher(twox_64_concat) T::AccountId => bool; + /// The number of times a member may vote the wrong way (or not at all, when they are a + /// skeptic) before they become suspended. + #[pallet::constant] + type MaxStrikes: Get; - /// The current bids, stored ordered by the value of the bid. - Bids: Vec>>; + /// The amount of incentive paid within each period. Doesn't include VoterTip. + #[pallet::constant] + type PeriodSpend: Get>; - /// Members currently vouching or banned from vouching again - Vouching get(fn vouching): map hasher(twox_64_concat) T::AccountId => Option; + /// The receiver of the signal for when the members have changed. + type MembershipChanged: ChangeMembers; - /// Pending payouts; ordered by block number, with the amount that should be paid out. - Payouts: map hasher(twox_64_concat) T::AccountId => Vec<(T::BlockNumber, BalanceOf)>; + /// The number of blocks between candidate/membership rotation periods. + #[pallet::constant] + type RotationPeriod: Get; - /// The ongoing number of losing votes cast by the member. - Strikes: map hasher(twox_64_concat) T::AccountId => StrikeCount; + /// The maximum duration of the payout lock. + #[pallet::constant] + type MaxLockDuration: Get; - /// Double map from Candidate -> Voter -> (Maybe) Vote. - Votes: double_map - hasher(twox_64_concat) T::AccountId, - hasher(twox_64_concat) T::AccountId - => Option; + /// The origin that is allowed to call `found`. + type FounderSetOrigin: EnsureOrigin; - /// The defending member currently being challenged. - Defender get(fn defender): Option; + /// The origin that is allowed to make suspension judgements. + type SuspensionJudgementOrigin: EnsureOrigin; - /// Votes for the defender. - DefenderVotes: map hasher(twox_64_concat) T::AccountId => Option; + /// The number of blocks between membership challenges. + #[pallet::constant] + type ChallengePeriod: Get; - /// The max number of members for the society at one time. - MaxMembers get(fn max_members) config(): u32; + /// The maximum number of candidates that we accept per round. + #[pallet::constant] + type MaxCandidateIntake: Get; + } + + #[pallet::error] + pub enum Error { + /// An incorrect position was provided. + BadPosition, + /// User is not a member. + NotMember, + /// User is already a member. + AlreadyMember, + /// User is suspended. + Suspended, + /// User is not suspended. + NotSuspended, + /// Nothing to payout. + NoPayout, + /// Society already founded. + AlreadyFounded, + /// Not enough in pot to accept candidate. + InsufficientPot, + /// Member is already vouching or banned from vouching again. + AlreadyVouching, + /// Member is not vouching. + NotVouching, + /// Cannot remove the head of the chain. + Head, + /// Cannot remove the founder. + Founder, + /// User has already made a bid. + AlreadyBid, + /// User is already a candidate. + AlreadyCandidate, + /// User is not a candidate. + NotCandidate, + /// Too many members in the society. + MaxMembers, + /// The caller is not the founder. + NotFounder, + /// The caller is not the head. + NotHead, } - add_extra_genesis { - config(members): Vec; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// The society is founded by the given identity. \[founder\] + Founded(T::AccountId), + /// A membership bid just happened. The given account is the candidate's ID and their offer + /// is the second. \[candidate_id, offer\] + Bid(T::AccountId, BalanceOf), + /// A membership bid just happened by vouching. The given account is the candidate's ID and + /// their offer is the second. The vouching party is the third. \[candidate_id, offer, + /// vouching\] + Vouch(T::AccountId, BalanceOf, T::AccountId), + /// A \[candidate\] was dropped (due to an excess of bids in the system). + AutoUnbid(T::AccountId), + /// A \[candidate\] was dropped (by their request). + Unbid(T::AccountId), + /// A \[candidate\] was dropped (by request of who vouched for them). + Unvouch(T::AccountId), + /// A group of candidates have been inducted. The batch's primary is the first value, the + /// batch in full is the second. \[primary, candidates\] + Inducted(T::AccountId, Vec), + /// A suspended member has been judged. \[who, judged\] + SuspendedMemberJudgement(T::AccountId, bool), + /// A \[candidate\] has been suspended + CandidateSuspended(T::AccountId), + /// A \[member\] has been suspended + MemberSuspended(T::AccountId), + /// A \[member\] has been challenged + Challenged(T::AccountId), + /// A vote has been placed \[candidate, voter, vote\] + Vote(T::AccountId, T::AccountId, bool), + /// A vote has been placed for a defending member \[voter, vote\] + DefenderVote(T::AccountId, bool), + /// A new \[max\] member count has been set + NewMaxMembers(u32), + /// Society is unfounded. \[founder\] + Unfounded(T::AccountId), + /// Some funds were deposited into the society account. \[value\] + Deposit(BalanceOf), } -} -// The module's dispatchable functions. -decl_module! { - /// The module declaration. - pub struct Module, I: Instance=DefaultInstance> for enum Call where origin: T::Origin { - type Error = Error; - /// The minimum amount of a deposit required for a bid to be made. - const CandidateDeposit: BalanceOf = T::CandidateDeposit::get(); + /// Old name generated by `decl_event`. + #[deprecated(note = "use `Event` instead")] + pub type RawEvent = Event; + + /// The first member. + #[pallet::storage] + #[pallet::getter(fn founder)] + pub type Founder, I: 'static = ()> = StorageValue<_, T::AccountId>; + + /// A hash of the rules of this society concerning membership. Can only be set once and + /// only by the founder. + #[pallet::storage] + #[pallet::getter(fn rules)] + pub type Rules, I: 'static = ()> = StorageValue<_, T::Hash>; + + /// The current set of candidates; bidders that are attempting to become members. + #[pallet::storage] + #[pallet::getter(fn candidates)] + pub type Candidates, I: 'static = ()> = + StorageValue<_, Vec>>, ValueQuery>; + + /// The set of suspended candidates. + #[pallet::storage] + #[pallet::getter(fn suspended_candidate)] + pub type SuspendedCandidates, I: 'static = ()> = StorageMap< + _, + Twox64Concat, + T::AccountId, + (BalanceOf, BidKind>), + >; + + /// Amount of our account balance that is specifically for the next round's bid(s). + #[pallet::storage] + #[pallet::getter(fn pot)] + pub type Pot, I: 'static = ()> = StorageValue<_, BalanceOf, ValueQuery>; + + /// The most primary from the most recently approved members. + #[pallet::storage] + #[pallet::getter(fn head)] + pub type Head, I: 'static = ()> = StorageValue<_, T::AccountId>; + + /// The current set of members, ordered. + #[pallet::storage] + #[pallet::getter(fn members)] + pub type Members, I: 'static = ()> = + StorageValue<_, Vec, ValueQuery>; + + /// The set of suspended members. + #[pallet::storage] + #[pallet::getter(fn suspended_member)] + pub type SuspendedMembers, I: 'static = ()> = + StorageMap<_, Twox64Concat, T::AccountId, bool, ValueQuery>; + + /// The current bids, stored ordered by the value of the bid. + #[pallet::storage] + pub(super) type Bids, I: 'static = ()> = + StorageValue<_, Vec>>, ValueQuery>; + + /// Members currently vouching or banned from vouching again + #[pallet::storage] + #[pallet::getter(fn vouching)] + pub(super) type Vouching, I: 'static = ()> = + StorageMap<_, Twox64Concat, T::AccountId, VouchingStatus>; + + /// Pending payouts; ordered by block number, with the amount that should be paid out. + #[pallet::storage] + pub(super) type Payouts, I: 'static = ()> = StorageMap< + _, + Twox64Concat, + T::AccountId, + Vec<(T::BlockNumber, BalanceOf)>, + ValueQuery, + >; + + /// The ongoing number of losing votes cast by the member. + #[pallet::storage] + pub(super) type Strikes, I: 'static = ()> = + StorageMap<_, Twox64Concat, T::AccountId, StrikeCount, ValueQuery>; + + /// Double map from Candidate -> Voter -> (Maybe) Vote. + #[pallet::storage] + pub(super) type Votes, I: 'static = ()> = + StorageDoubleMap<_, Twox64Concat, T::AccountId, Twox64Concat, T::AccountId, Vote>; + + /// The defending member currently being challenged. + #[pallet::storage] + #[pallet::getter(fn defender)] + pub(super) type Defender, I: 'static = ()> = StorageValue<_, T::AccountId>; + + /// Votes for the defender. + #[pallet::storage] + pub(super) type DefenderVotes, I: 'static = ()> = + StorageMap<_, Twox64Concat, T::AccountId, Vote>; + + /// The max number of members for the society at one time. + #[pallet::storage] + #[pallet::getter(fn max_members)] + pub(super) type MaxMembers, I: 'static = ()> = StorageValue<_, u32, ValueQuery>; + + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { + fn on_initialize(n: T::BlockNumber) -> Weight { + let mut members = vec![]; - /// The amount of the unpaid reward that gets deducted in the case that either a skeptic - /// doesn't vote or someone votes in the wrong way. - const WrongSideDeduction: BalanceOf = T::WrongSideDeduction::get(); + let mut weight = 0; + let weights = T::BlockWeights::get(); - /// The number of times a member may vote the wrong way (or not at all, when they are a skeptic) - /// before they become suspended. - const MaxStrikes: u32 = T::MaxStrikes::get(); + // Run a candidate/membership rotation + if (n % T::RotationPeriod::get()).is_zero() { + members = >::get(); + Self::rotate_period(&mut members); - /// The amount of incentive paid within each period. Doesn't include VoterTip. - const PeriodSpend: BalanceOf = T::PeriodSpend::get(); + weight += weights.max_block / 20; + } - /// The number of blocks between candidate/membership rotation periods. - const RotationPeriod: T::BlockNumber = T::RotationPeriod::get(); + // Run a challenge rotation + if (n % T::ChallengePeriod::get()).is_zero() { + // Only read members if not already read. + if members.is_empty() { + members = >::get(); + } + Self::rotate_challenge(&mut members); - /// The number of blocks between membership challenges. - const ChallengePeriod: T::BlockNumber = T::ChallengePeriod::get(); + weight += weights.max_block / 20; + } - /// The societies's module id - const PalletId: PalletId = T::PalletId::get(); + weight + } + } + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + pub pot: BalanceOf, + pub members: Vec, + pub max_members: u32, + } - /// Maximum candidate intake per round. - const MaxCandidateIntake: u32 = T::MaxCandidateIntake::get(); + #[cfg(feature = "std")] + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + Self { + pot: Default::default(), + members: Default::default(), + max_members: Default::default(), + } + } + } - // Used for handling module events. - fn deposit_event() = default; + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { + Pot::::put(self.pot); + MaxMembers::::put(self.max_members); + let first_member = self.members.first(); + if let Some(member) = first_member { + Founder::::put(member.clone()); + Head::::put(member.clone()); + }; + let mut m = self.members.clone(); + m.sort(); + Members::::put(m); + } + } + #[pallet::call] + impl, I: 'static> Pallet { /// A user outside of the society can make a bid for entry. /// /// Payment: `CandidateDeposit` will be reserved for making a bid. It is returned @@ -538,12 +698,13 @@ decl_module! { /// - One storage read to retrieve all current candidates. O(C) /// - One storage read to retrieve all members. O(M) /// - Storage Writes: - /// - One storage mutate to add a new bid to the vector O(B) (TODO: possible optimization w/ read) + /// - One storage mutate to add a new bid to the vector O(B) (TODO: possible optimization + /// w/ read) /// - Up to one storage removal if bid.len() > MAX_BID_COUNT. O(1) /// - Notable Computation: /// - O(B + C + log M) search to check user is not already a part of society. /// - O(log B) search to insert the new bid sorted. - /// - External Module Operations: + /// - External Pallet Operations: /// - One balance reserve operation. O(X) /// - Up to one balance unreserve operation if bids.len() > MAX_BID_COUNT. /// - Events: @@ -552,8 +713,8 @@ decl_module! { /// /// Total Complexity: O(M + B + C + logM + logB + X) /// # - #[weight = T::BlockWeights::get().max_block / 10] - pub fn bid(origin, value: BalanceOf) -> DispatchResult { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn bid(origin: OriginFor, value: BalanceOf) -> DispatchResult { let who = ensure_signed(origin)?; ensure!(!>::contains_key(&who), Error::::Suspended); ensure!(!>::contains_key(&who), Error::::Suspended); @@ -562,13 +723,13 @@ decl_module! { let candidates = >::get(); ensure!(!Self::is_candidate(&candidates, &who), Error::::AlreadyCandidate); let members = >::get(); - ensure!(!Self::is_member(&members ,&who), Error::::AlreadyMember); + ensure!(!Self::is_member(&members, &who), Error::::AlreadyMember); let deposit = T::CandidateDeposit::get(); T::Currency::reserve(&who, deposit)?; Self::put_bid(bids, &who, value.clone(), BidKind::Deposit(deposit)); - Self::deposit_event(RawEvent::Bid(who, value)); + Self::deposit_event(Event::::Bid(who, value)); Ok(()) } @@ -591,12 +752,12 @@ decl_module! { /// /// Total Complexity: O(B + X) /// # - #[weight = T::BlockWeights::get().max_block / 10] - pub fn unbid(origin, pos: u32) -> DispatchResult { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn unbid(origin: OriginFor, pos: u32) -> DispatchResult { let who = ensure_signed(origin)?; let pos = pos as usize; - >::mutate(|b| + >::mutate(|b| { if pos < b.len() && b[pos].who == who { // Either unreserve the deposit or free up the vouching member. // In neither case can we do much if the action isn't completable, but there's @@ -605,17 +766,17 @@ decl_module! { BidKind::Deposit(deposit) => { let err_amount = T::Currency::unreserve(&who, deposit); debug_assert!(err_amount.is_zero()); - } + }, BidKind::Vouch(voucher, _) => { >::remove(&voucher); - } + }, } - Self::deposit_event(RawEvent::Unbid(who)); + Self::deposit_event(Event::::Unbid(who)); Ok(()) } else { Err(Error::::BadPosition)? } - ) + }) } /// As a member, vouch for someone to join society by placing a bid on their behalf. @@ -647,13 +808,14 @@ decl_module! { /// - One storage read to retrieve all current candidates. O(C) /// - Storage Writes: /// - One storage write to insert vouching status to the member. O(1) - /// - One storage mutate to add a new bid to the vector O(B) (TODO: possible optimization w/ read) + /// - One storage mutate to add a new bid to the vector O(B) (TODO: possible optimization + /// w/ read) /// - Up to one storage removal if bid.len() > MAX_BID_COUNT. O(1) /// - Notable Computation: /// - O(log M) search to check sender is a member. /// - O(B + C + log M) search to check user is not already a part of society. /// - O(log B) search to insert the new bid sorted. - /// - External Module Operations: + /// - External Pallet Operations: /// - One balance reserve operation. O(X) /// - Up to one balance unreserve operation if bids.len() > MAX_BID_COUNT. /// - Events: @@ -662,8 +824,13 @@ decl_module! { /// /// Total Complexity: O(M + B + C + logM + logB + X) /// # - #[weight = T::BlockWeights::get().max_block / 10] - pub fn vouch(origin, who: T::AccountId, value: BalanceOf, tip: BalanceOf) -> DispatchResult { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn vouch( + origin: OriginFor, + who: T::AccountId, + value: BalanceOf, + tip: BalanceOf, + ) -> DispatchResult { let voucher = ensure_signed(origin)?; // Check user is not suspended. ensure!(!>::contains_key(&who), Error::::Suspended); @@ -682,7 +849,7 @@ decl_module! { >::insert(&voucher, VouchingStatus::Vouching); Self::put_bid(bids, &who, value.clone(), BidKind::Vouch(voucher.clone(), tip)); - Self::deposit_event(RawEvent::Vouch(who, value, voucher)); + Self::deposit_event(Event::::Vouch(who, value, voucher)); Ok(()) } @@ -703,23 +870,26 @@ decl_module! { /// /// Total Complexity: O(B) /// # - #[weight = T::BlockWeights::get().max_block / 10] - pub fn unvouch(origin, pos: u32) -> DispatchResult { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn unvouch(origin: OriginFor, pos: u32) -> DispatchResult { let voucher = ensure_signed(origin)?; - ensure!(Self::vouching(&voucher) == Some(VouchingStatus::Vouching), Error::::NotVouching); + ensure!( + Self::vouching(&voucher) == Some(VouchingStatus::Vouching), + Error::::NotVouching + ); let pos = pos as usize; - >::mutate(|b| + >::mutate(|b| { if pos < b.len() { b[pos].kind.check_voucher(&voucher)?; >::remove(&voucher); let who = b.remove(pos).who; - Self::deposit_event(RawEvent::Unvouch(who)); + Self::deposit_event(Event::::Unvouch(who)); Ok(()) } else { Err(Error::::BadPosition)? } - ) + }) } /// As a member, vote on a candidate. @@ -728,8 +898,8 @@ decl_module! { /// /// Parameters: /// - `candidate`: The candidate that the member would like to bid on. - /// - `approve`: A boolean which says if the candidate should be - /// approved (`true`) or rejected (`false`). + /// - `approve`: A boolean which says if the candidate should be approved (`true`) or + /// rejected (`false`). /// /// # /// Key: C (len of candidates), M (len of members) @@ -741,8 +911,12 @@ decl_module! { /// /// Total Complexity: O(M + logM + C) /// # - #[weight = T::BlockWeights::get().max_block / 10] - pub fn vote(origin, candidate: ::Source, approve: bool) { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn vote( + origin: OriginFor, + candidate: ::Source, + approve: bool, + ) -> DispatchResult { let voter = ensure_signed(origin)?; let candidate = T::Lookup::lookup(candidate)?; let candidates = >::get(); @@ -753,7 +927,8 @@ decl_module! { let vote = if approve { Vote::Approve } else { Vote::Reject }; >::insert(&candidate, &voter, vote); - Self::deposit_event(RawEvent::Vote(candidate, voter, approve)); + Self::deposit_event(Event::::Vote(candidate, voter, approve)); + Ok(()) } /// As a member, vote on the defender. @@ -772,8 +947,8 @@ decl_module! { /// /// Total Complexity: O(M + logM) /// # - #[weight = T::BlockWeights::get().max_block / 10] - pub fn defender_vote(origin, approve: bool) { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn defender_vote(origin: OriginFor, approve: bool) -> DispatchResult { let voter = ensure_signed(origin)?; let members = >::get(); ensure!(Self::is_member(&members, &voter), Error::::NotMember); @@ -781,12 +956,14 @@ decl_module! { let vote = if approve { Vote::Approve } else { Vote::Reject }; >::insert(&voter, vote); - Self::deposit_event(RawEvent::DefenderVote(voter, approve)); + Self::deposit_event(Event::::DefenderVote(voter, approve)); + Ok(()) } /// Transfer the first matured payout for the sender and remove it from the records. /// - /// NOTE: This extrinsic needs to be called multiple times to claim multiple matured payouts. + /// NOTE: This extrinsic needs to be called multiple times to claim multiple matured + /// payouts. /// /// Payment: The member will receive a payment equal to their first matured /// payout to their free balance. @@ -804,8 +981,8 @@ decl_module! { /// /// Total Complexity: O(M + logM + P + X) /// # - #[weight = T::BlockWeights::get().max_block / 10] - pub fn payout(origin) { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn payout(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; let members = >::get(); @@ -813,7 +990,7 @@ decl_module! { let mut payouts = >::get(&who); if let Some((when, amount)) = payouts.first() { - if when <= &>::block_number() { + if when <= &>::block_number() { T::Currency::transfer(&Self::payouts(), &who, *amount, AllowDeath)?; payouts.remove(0); if payouts.is_empty() { @@ -830,7 +1007,7 @@ decl_module! { /// Found the society. /// /// This is done as a discrete action in order to allow for the - /// module to be included into a running chain and can only be done once. + /// pallet to be included into a running chain and can only be done once. /// /// The dispatch origin for this call must be from the _FounderSetOrigin_. /// @@ -846,18 +1023,24 @@ decl_module! { /// /// Total Complexity: O(1) /// # - #[weight = T::BlockWeights::get().max_block / 10] - fn found(origin, founder: T::AccountId, max_members: u32, rules: Vec) { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn found( + origin: OriginFor, + founder: T::AccountId, + max_members: u32, + rules: Vec, + ) -> DispatchResult { T::FounderSetOrigin::ensure_origin(origin)?; ensure!(!>::exists(), Error::::AlreadyFounded); ensure!(max_members > 1, Error::::MaxMembers); // This should never fail in the context of this function... - >::put(max_members); + >::put(max_members); Self::add_member(&founder)?; >::put(&founder); >::put(&founder); Rules::::put(T::Hashing::hash(&rules)); - Self::deposit_event(RawEvent::Founded(founder)); + Self::deposit_event(Event::::Founded(founder)); + Ok(()) } /// Annul the founding of the society. @@ -873,8 +1056,8 @@ decl_module! { /// /// Total Complexity: O(1) /// # - #[weight = T::BlockWeights::get().max_block / 10] - fn unfound(origin) { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn unfound(origin: OriginFor) -> DispatchResult { let founder = ensure_signed(origin)?; ensure!(Founder::::get() == Some(founder.clone()), Error::::NotFounder); ensure!(Head::::get() == Some(founder.clone()), Error::::NotHead); @@ -885,7 +1068,8 @@ decl_module! { Rules::::kill(); Candidates::::kill(); SuspendedCandidates::::remove_all(None); - Self::deposit_event(RawEvent::Unfounded(founder)); + Self::deposit_event(Event::::Unfounded(founder)); + Ok(()) } /// Allow suspension judgement origin to make judgement on a suspended member. @@ -900,13 +1084,14 @@ decl_module! { /// /// Parameters: /// - `who` - The suspended member to be judged. - /// - `forgive` - A boolean representing whether the suspension judgement origin - /// forgives (`true`) or rejects (`false`) a suspended member. + /// - `forgive` - A boolean representing whether the suspension judgement origin forgives + /// (`true`) or rejects (`false`) a suspended member. /// /// # /// Key: B (len of bids), M (len of members) /// - One storage read to check `who` is a suspended member. O(1) - /// - Up to one storage write O(M) with O(log M) binary search to add a member back to society. + /// - Up to one storage write O(M) with O(log M) binary search to add a member back to + /// society. /// - Up to 3 storage removals O(1) to clean up a removed member. /// - Up to one storage write O(B) with O(B) search to remove vouched bid from bids. /// - Up to one additional event if unvouch takes place. @@ -915,8 +1100,12 @@ decl_module! { /// /// Total Complexity: O(M + logM + B) /// # - #[weight = T::BlockWeights::get().max_block / 10] - fn judge_suspended_member(origin, who: T::AccountId, forgive: bool) { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn judge_suspended_member( + origin: OriginFor, + who: T::AccountId, + forgive: bool, + ) -> DispatchResult { T::SuspensionJudgementOrigin::ensure_origin(origin)?; ensure!(>::contains_key(&who), Error::::NotSuspended); @@ -936,14 +1125,15 @@ decl_module! { if let Some(pos) = bids.iter().position(|b| b.kind.check_voucher(&who).is_ok()) { // Remove the bid, and emit an event let vouched = bids.remove(pos).who; - Self::deposit_event(RawEvent::Unvouch(vouched)); + Self::deposit_event(Event::::Unvouch(vouched)); } ); } } >::remove(&who); - Self::deposit_event(RawEvent::SuspendedMemberJudgement(who, forgive)); + Self::deposit_event(Event::::SuspendedMemberJudgement(who, forgive)); + Ok(()) } /// Allow suspended judgement origin to make judgement on a suspended candidate. @@ -986,8 +1176,12 @@ decl_module! { /// /// Total Complexity: O(M + logM + B + X) /// # - #[weight = T::BlockWeights::get().max_block / 10] - fn judge_suspended_candidate(origin, who: T::AccountId, judgement: Judgement) { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn judge_suspended_candidate( + origin: OriginFor, + who: T::AccountId, + judgement: Judgement, + ) -> DispatchResult { T::SuspensionJudgementOrigin::ensure_origin(origin)?; if let Some((value, kind)) = >::get(&who) { match judgement { @@ -1001,29 +1195,35 @@ decl_module! { // Reduce next pot by payout >::put(pot - value); // Add payout for new candidate - let maturity = >::block_number() - + Self::lock_duration(Self::members().len() as u32); + let maturity = >::block_number() + + Self::lock_duration(Self::members().len() as u32); Self::pay_accepted_candidate(&who, value, kind, maturity); - } + }, Judgement::Reject => { // Founder has rejected this candidate match kind { BidKind::Deposit(deposit) => { // Slash deposit and move it to the society account - let res = T::Currency::repatriate_reserved(&who, &Self::account_id(), deposit, BalanceStatus::Free); + let res = T::Currency::repatriate_reserved( + &who, + &Self::account_id(), + deposit, + BalanceStatus::Free, + ); debug_assert!(res.is_ok()); - } + }, BidKind::Vouch(voucher, _) => { // Ban the voucher from vouching again >::insert(&voucher, VouchingStatus::Banned); - } + }, } - } + }, Judgement::Rebid => { - // Founder has taken no judgement, and candidate is placed back into the pool. + // Founder has taken no judgement, and candidate is placed back into the + // pool. let bids = >::get(); Self::put_bid(bids, &who, value, kind); - } + }, } // Remove suspended candidate @@ -1031,6 +1231,7 @@ decl_module! { } else { Err(Error::::NotSuspended)? } + Ok(()) } /// Allows root origin to change the maximum number of members in society. @@ -1047,137 +1248,24 @@ decl_module! { /// /// Total Complexity: O(1) /// # - #[weight = T::BlockWeights::get().max_block / 10] - fn set_max_members(origin, max: u32) { + #[pallet::weight(T::BlockWeights::get().max_block / 10)] + pub fn set_max_members(origin: OriginFor, max: u32) -> DispatchResult { ensure_root(origin)?; ensure!(max > 1, Error::::MaxMembers); - MaxMembers::::put(max); - Self::deposit_event(RawEvent::NewMaxMembers(max)); - } - - fn on_initialize(n: T::BlockNumber) -> Weight { - let mut members = vec![]; - - let mut weight = 0; - let weights = T::BlockWeights::get(); - - // Run a candidate/membership rotation - if (n % T::RotationPeriod::get()).is_zero() { - members = >::get(); - Self::rotate_period(&mut members); - - weight += weights.max_block / 20; - } - - // Run a challenge rotation - if (n % T::ChallengePeriod::get()).is_zero() { - // Only read members if not already read. - if members.is_empty() { - members = >::get(); - } - Self::rotate_challenge(&mut members); - - weight += weights.max_block / 20; - } - - weight + MaxMembers::::put(max); + Self::deposit_event(Event::::NewMaxMembers(max)); + Ok(()) } } } -decl_error! { - /// Errors for this module. - pub enum Error for Module, I: Instance> { - /// An incorrect position was provided. - BadPosition, - /// User is not a member. - NotMember, - /// User is already a member. - AlreadyMember, - /// User is suspended. - Suspended, - /// User is not suspended. - NotSuspended, - /// Nothing to payout. - NoPayout, - /// Society already founded. - AlreadyFounded, - /// Not enough in pot to accept candidate. - InsufficientPot, - /// Member is already vouching or banned from vouching again. - AlreadyVouching, - /// Member is not vouching. - NotVouching, - /// Cannot remove the head of the chain. - Head, - /// Cannot remove the founder. - Founder, - /// User has already made a bid. - AlreadyBid, - /// User is already a candidate. - AlreadyCandidate, - /// User is not a candidate. - NotCandidate, - /// Too many members in the society. - MaxMembers, - /// The caller is not the founder. - NotFounder, - /// The caller is not the head. - NotHead, - } -} - -decl_event! { - /// Events for this module. - pub enum Event where - AccountId = ::AccountId, - Balance = BalanceOf - { - /// The society is founded by the given identity. \[founder\] - Founded(AccountId), - /// A membership bid just happened. The given account is the candidate's ID and their offer - /// is the second. \[candidate_id, offer\] - Bid(AccountId, Balance), - /// A membership bid just happened by vouching. The given account is the candidate's ID and - /// their offer is the second. The vouching party is the third. \[candidate_id, offer, vouching\] - Vouch(AccountId, Balance, AccountId), - /// A \[candidate\] was dropped (due to an excess of bids in the system). - AutoUnbid(AccountId), - /// A \[candidate\] was dropped (by their request). - Unbid(AccountId), - /// A \[candidate\] was dropped (by request of who vouched for them). - Unvouch(AccountId), - /// A group of candidates have been inducted. The batch's primary is the first value, the - /// batch in full is the second. \[primary, candidates\] - Inducted(AccountId, Vec), - /// A suspended member has been judged. \[who, judged\] - SuspendedMemberJudgement(AccountId, bool), - /// A \[candidate\] has been suspended - CandidateSuspended(AccountId), - /// A \[member\] has been suspended - MemberSuspended(AccountId), - /// A \[member\] has been challenged - Challenged(AccountId), - /// A vote has been placed \[candidate, voter, vote\] - Vote(AccountId, AccountId, bool), - /// A vote has been placed for a defending member \[voter, vote\] - DefenderVote(AccountId, bool), - /// A new \[max\] member count has been set - NewMaxMembers(u32), - /// Society is unfounded. \[founder\] - Unfounded(AccountId), - /// Some funds were deposited into the society account. \[value\] - Deposit(Balance), - } -} - /// Simple ensure origin struct to filter for the founder account. pub struct EnsureFounder(sp_std::marker::PhantomData); impl EnsureOrigin for EnsureFounder { type Success = T::AccountId; fn try_origin(o: T::Origin) -> Result { o.into().and_then(|o| match (o, Founder::::get()) { - (system::RawOrigin::Signed(ref who), Some(ref f)) if who == f => Ok(who.clone()), + (frame_system::RawOrigin::Signed(ref who), Some(ref f)) if who == f => Ok(who.clone()), (r, _) => Err(T::Origin::from(r)), }) } @@ -1185,7 +1273,7 @@ impl EnsureOrigin for EnsureFounder { #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> T::Origin { let founder = Founder::::get().expect("society founder should exist"); - T::Origin::from(system::RawOrigin::Signed(founder)) + T::Origin::from(frame_system::RawOrigin::Signed(founder)) } } @@ -1203,7 +1291,7 @@ fn pick_usize<'a, R: RngCore>(rng: &mut R, max: usize) -> usize { (rng.next_u32() % (max as u32 + 1)) as usize } -impl, I: Instance> Module { +impl, I: 'static> Pallet { /// Puts a bid into storage ordered by smallest to largest value. /// Allows a maximum of 1000 bids in queue, removing largest value people first. fn put_bid( @@ -1251,7 +1339,7 @@ impl, I: Instance> Module { >::remove(&voucher); }, } - Self::deposit_event(RawEvent::AutoUnbid(popped)); + Self::deposit_event(Event::::AutoUnbid(popped)); } >::put(bids); @@ -1281,7 +1369,7 @@ impl, I: Instance> Module { /// Can fail when `MaxMember` limit is reached, but has no side-effects. fn add_member(who: &T::AccountId) -> DispatchResult { let mut members = >::get(); - ensure!(members.len() < MaxMembers::::get() as usize, Error::::MaxMembers); + ensure!(members.len() < MaxMembers::::get() as usize, Error::::MaxMembers); match members.binary_search(who) { // Add the new member Err(i) => { @@ -1338,8 +1426,8 @@ impl, I: Instance> Module { // out of society. members.reserve(candidates.len()); - let maturity = - >::block_number() + Self::lock_duration(members.len() as u32); + let maturity = >::block_number() + + Self::lock_duration(members.len() as u32); let mut rewardees = Vec::new(); let mut total_approvals = 0; @@ -1416,7 +1504,7 @@ impl, I: Instance> Module { } else { // Suspend Candidate >::insert(&candidate, (value, kind)); - Self::deposit_event(RawEvent::CandidateSuspended(candidate)); + Self::deposit_event(Event::::CandidateSuspended(candidate)); None } }) @@ -1485,7 +1573,7 @@ impl, I: Instance> Module { >::put(&primary); T::MembershipChanged::change_members_sorted(&accounts, &[], &members); - Self::deposit_event(RawEvent::Inducted(primary, accounts)); + Self::deposit_event(Event::::Inducted(primary, accounts)); } // Bump the pot by at most PeriodSpend, but less if there's not very much left in our @@ -1550,7 +1638,7 @@ impl, I: Instance> Module { if Self::remove_member(&who).is_ok() { >::insert(who, true); >::remove(who); - Self::deposit_event(RawEvent::MemberSuspended(who.clone())); + Self::deposit_event(Event::::MemberSuspended(who.clone())); } } @@ -1628,7 +1716,7 @@ impl, I: Instance> Module { let chosen = pick_item(&mut rng, &members[1..members.len() - 1]) .expect("exited if members empty; qed"); >::put(&chosen); - Self::deposit_event(RawEvent::Challenged(chosen.clone())); + Self::deposit_event(Event::::Challenged(chosen.clone())); } else { >::kill(); } @@ -1668,7 +1756,7 @@ impl, I: Instance> Module { members_len: usize, pot: BalanceOf, ) -> Vec>> { - let max_members = MaxMembers::::get() as usize; + let max_members = MaxMembers::::get() as usize; let mut max_selections: usize = (T::MaxCandidateIntake::get() as usize).min(max_members.saturating_sub(members_len)); @@ -1725,13 +1813,13 @@ impl, I: Instance> Module { } } -impl OnUnbalanced> for Module { - fn on_nonzero_unbalanced(amount: NegativeImbalanceOf) { +impl, I: 'static> OnUnbalanced> for Pallet { + fn on_nonzero_unbalanced(amount: NegativeImbalanceOf) { let numeric_amount = amount.peek(); // Must resolve into existing but better to be safe. let _ = T::Currency::resolve_creating(&Self::account_id(), amount); - Self::deposit_event(RawEvent::Deposit(numeric_amount)); + Self::deposit_event(Event::::Deposit(numeric_amount)); } } diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 38c2586323135..9356c083f2331 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -20,10 +20,7 @@ use super::*; use crate as pallet_society; -use frame_support::{ - ord_parameter_types, parameter_types, - traits::{OnFinalize, OnInitialize}, -}; +use frame_support::{ord_parameter_types, parameter_types}; use frame_support_test::TestRandomness; use frame_system::EnsureSignedBy; use sp_core::H256; From 49e91e2f2390fda92e41726c2fb728cd778e7631 Mon Sep 17 00:00:00 2001 From: Georges Date: Wed, 22 Sep 2021 10:42:57 +0100 Subject: [PATCH 0014/1472] Adding storage_info to pallet grandpa (#9817) Converting some `Vec` to `WeakBoundedVec` Adding `MaxAuthorities` type to bound the `WeakBoundedVec` Co-authored-by: thiolliere --- bin/node-template/runtime/src/lib.rs | 1 + bin/node/runtime/src/lib.rs | 1 + frame/grandpa/src/lib.rs | 48 ++++++++++++++++++++++------ frame/grandpa/src/mock.rs | 2 ++ 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index eecc93e166666..ca6e6b1822d45 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -222,6 +222,7 @@ impl pallet_grandpa::Config for Runtime { type HandleEquivocation = (); type WeightInfo = (); + type MaxAuthorities = MaxAuthorities; } parameter_types! { diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4cf313f8d26f0..75b80cccd8cb6 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1035,6 +1035,7 @@ impl pallet_grandpa::Config for Runtime { >; type WeightInfo = (); + type MaxAuthorities = MaxAuthorities; } parameter_types! { diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index cd75deea770b4..687207151f4f4 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -33,7 +33,7 @@ pub use sp_finality_grandpa as fg_primitives; use sp_std::prelude::*; -use codec::{self as codec, Decode, Encode}; +use codec::{self as codec, Decode, Encode, MaxEncodedLen}; pub use fg_primitives::{AuthorityId, AuthorityList, AuthorityWeight, VersionedAuthorityList}; use fg_primitives::{ ConsensusLog, EquivocationProof, ScheduledChange, SetId, GRANDPA_AUTHORITIES_KEY, @@ -41,9 +41,11 @@ use fg_primitives::{ }; use frame_support::{ dispatch::DispatchResultWithPostInfo, + pallet_prelude::Get, storage, traits::{KeyOwnerProofSystem, OneSessionHandler, StorageVersion}, weights::{Pays, Weight}, + WeakBoundedVec, }; use sp_runtime::{generic::DigestItem, traits::Zero, DispatchResult, KeyTypeId}; use sp_session::{GetSessionNumber, GetValidatorCount}; @@ -81,6 +83,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] @@ -119,6 +122,10 @@ pub mod pallet { /// Weights for this pallet. type WeightInfo: WeightInfo; + + /// Max Authorities in use + #[pallet::constant] + type MaxAuthorities: Get; } #[pallet::hooks] @@ -133,13 +140,13 @@ pub mod pallet { median, ScheduledChange { delay: pending_change.delay, - next_authorities: pending_change.next_authorities.clone(), + next_authorities: pending_change.next_authorities.to_vec(), }, )) } else { Self::deposit_log(ConsensusLog::ScheduledChange(ScheduledChange { delay: pending_change.delay, - next_authorities: pending_change.next_authorities.clone(), + next_authorities: pending_change.next_authorities.to_vec(), })); } } @@ -147,7 +154,9 @@ pub mod pallet { // enact the change if we've reached the enacting block if block_number == pending_change.scheduled_at + pending_change.delay { Self::set_grandpa_authorities(&pending_change.next_authorities); - Self::deposit_event(Event::NewAuthorities(pending_change.next_authorities)); + Self::deposit_event(Event::NewAuthorities( + pending_change.next_authorities.to_vec(), + )); >::kill(); } } @@ -291,7 +300,8 @@ pub mod pallet { /// Pending change: (signaled at, scheduled change). #[pallet::storage] #[pallet::getter(fn pending_change)] - pub(super) type PendingChange = StorageValue<_, StoredPendingChange>; + pub(super) type PendingChange = + StorageValue<_, StoredPendingChange>; /// next block number where we can force a change. #[pallet::storage] @@ -355,15 +365,25 @@ pub trait WeightInfo { fn note_stalled() -> Weight; } +/// Bounded version of `AuthorityList`, `Limit` being the bound +pub type BoundedAuthorityList = WeakBoundedVec<(AuthorityId, AuthorityWeight), Limit>; + /// A stored pending change. -#[derive(Encode, Decode, TypeInfo)] -pub struct StoredPendingChange { +/// `Limit` is the bound for `next_authorities` +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] +#[codec(mel_bound(Limit: Get))] +#[scale_info(skip_type_params(Limit))] +pub struct StoredPendingChange +where + Limit: Get, + N: MaxEncodedLen, +{ /// The block number this was scheduled at. pub scheduled_at: N, /// The delay in blocks until it will be applied. pub delay: N, - /// The next authority set. - pub next_authorities: AuthorityList, + /// The next authority set, weakly bounded in size by `Limit`. + pub next_authorities: BoundedAuthorityList, /// If defined it means the change was forced and the given block number /// indicates the median last finalized block when the change was signaled. pub forced: Option, @@ -372,7 +392,7 @@ pub struct StoredPendingChange { /// Current state of the GRANDPA authority set. State transitions must happen in /// the same order of states defined below, e.g. `Paused` implies a prior /// `PendingPause`. -#[derive(Decode, Encode, TypeInfo)] +#[derive(Decode, Encode, TypeInfo, MaxEncodedLen)] #[cfg_attr(test, derive(Debug, PartialEq))] pub enum StoredState { /// The current authority set is live, and GRANDPA is enabled. @@ -465,6 +485,14 @@ impl Pallet { >::put(scheduled_at + in_blocks * 2u32.into()); } + let next_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from( + next_authorities, + Some( + "Warning: The number of authorities given is too big. \ + A runtime configuration adjustment may be needed.", + ), + ); + >::put(StoredPendingChange { delay: in_blocks, scheduled_at, diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 2f1b2630b2241..4e5e44ce36e7a 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -230,6 +230,7 @@ impl pallet_offences::Config for Test { parameter_types! { pub const ReportLongevity: u64 = BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * Period::get(); + pub const MaxAuthorities: u32 = 100; } impl Config for Test { @@ -250,6 +251,7 @@ impl Config for Test { super::EquivocationHandler; type WeightInfo = (); + type MaxAuthorities = MaxAuthorities; } pub fn grandpa_log(log: ConsensusLog) -> DigestItem { From 136120674703bf5541ee2368ebb330d803b61cce Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 22 Sep 2021 15:38:21 +0100 Subject: [PATCH 0015/1472] Use the automated call decode weight for `submit_unsigned` benchmark (#9766) * Use the automated call decode weight for benchmark * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * reduce the boundaries * Fix * Fox * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * reduce the numbers even less * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Fix a few things * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * update comment Co-authored-by: Parity Bot --- bin/node/runtime/src/lib.rs | 19 +-- .../src/benchmarking.rs | 33 +---- .../election-provider-multi-phase/src/lib.rs | 4 +- .../election-provider-multi-phase/src/mock.rs | 4 +- .../src/unsigned.rs | 2 +- .../src/weights.rs | 132 ++++++++++-------- 6 files changed, 94 insertions(+), 100 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 75b80cccd8cb6..af465fc0ffc1d 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -576,17 +576,18 @@ sp_npos_elections::generate_solution_type!( pub const MAX_NOMINATIONS: u32 = ::LIMIT as u32; -/// The numbers configured here should always be more than the the maximum limits of staking pallet -/// to ensure election snapshot will not run out of memory. +/// The numbers configured here could always be more than the the maximum limits of staking pallet +/// to ensure election snapshot will not run out of memory. For now, we set them to smaller values +/// since the staking is bounded and the weight pipeline takes hours for this single pallet. pub struct BenchmarkConfig; impl pallet_election_provider_multi_phase::BenchmarkingConfig for BenchmarkConfig { - const VOTERS: [u32; 2] = [5_000, 10_000]; - const TARGETS: [u32; 2] = [1_000, 2_000]; - const ACTIVE_VOTERS: [u32; 2] = [1000, 4_000]; - const DESIRED_TARGETS: [u32; 2] = [400, 800]; - const SNAPSHOT_MAXIMUM_VOTERS: u32 = 25_000; - const MINER_MAXIMUM_VOTERS: u32 = 15_000; - const MAXIMUM_TARGETS: u32 = 2000; + const VOTERS: [u32; 2] = [1000, 2000]; + const TARGETS: [u32; 2] = [500, 1000]; + const ACTIVE_VOTERS: [u32; 2] = [500, 800]; + const DESIRED_TARGETS: [u32; 2] = [200, 400]; + const SNAPSHOT_MAXIMUM_VOTERS: u32 = 1000; + const MINER_MAXIMUM_VOTERS: u32 = 1000; + const MAXIMUM_TARGETS: u32 = 300; } /// Maximum number of iterations for balancing that will be executed in the embedded OCW diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index fb5adda52e166..a5bb0d6351c15 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -243,10 +243,10 @@ frame_benchmarking::benchmarks! { } create_snapshot_internal { - // number of votes in snapshot. Fixed to maximum. - let v = T::BenchmarkingConfig::SNAPSHOT_MAXIMUM_VOTERS; - // number of targets in snapshot. Fixed to maximum. - let t = T::BenchmarkingConfig::MAXIMUM_TARGETS; + // number of votes in snapshot. + let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1]; + // number of targets in snapshot. + let t in (T::BenchmarkingConfig::TARGETS[0]) .. T::BenchmarkingConfig::TARGETS[1]; // we don't directly need the data-provider to be populated, but it is just easy to use it. set_up_data_provider::(v, t); @@ -351,24 +351,8 @@ frame_benchmarking::benchmarks! { assert!(>::queued_solution().is_none()); >::put(Phase::Unsigned((true, 1u32.into()))); - // encode the most significant storage item that needs to be decoded in the dispatch. - let encoded_snapshot = >::snapshot().ok_or("missing snapshot")?.encode(); - let encoded_call = Call::::submit_unsigned { - raw_solution: Box::new(raw_solution.clone()), - witness - }.encode(); - }: { - assert_ok!( - >::submit_unsigned( - RawOrigin::None.into(), - Box::new(raw_solution), - witness, - ) - ); - let _decoded_snap = as Decode>::decode(&mut &*encoded_snapshot) - .expect("decoding should not fail; qed."); - let _decoded_call = as Decode>::decode(&mut &*encoded_call).expect("decoding should not fail; qed."); - } verify { + }: _(RawOrigin::None, Box::new(raw_solution), witness) + verify { assert!(>::queued_solution().is_some()); } @@ -389,13 +373,8 @@ frame_benchmarking::benchmarks! { assert_eq!(raw_solution.solution.voter_count() as u32, a); assert_eq!(raw_solution.solution.unique_targets().len() as u32, d); - - // encode the most significant storage item that needs to be decoded in the dispatch. - let encoded_snapshot = >::snapshot().ok_or("snapshot missing")?.encode(); }: { assert_ok!(>::feasibility_check(raw_solution, ElectionCompute::Unsigned)); - let _decoded_snap = as Decode>::decode(&mut &*encoded_snapshot) - .expect("decoding should not fail; qed."); } // NOTE: this weight is not used anywhere, but the fact that it should succeed when execution in diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index e83c49433e2bb..6b0329afc0d77 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1317,8 +1317,10 @@ impl Pallet { let (targets, voters, desired_targets) = Self::create_snapshot_external()?; // ..therefore we only measure the weight of this and add it. + let internal_weight = + T::WeightInfo::create_snapshot_internal(voters.len() as u32, targets.len() as u32); Self::create_snapshot_internal(targets, voters, desired_targets); - Self::register_weight(T::WeightInfo::create_snapshot_internal()); + Self::register_weight(internal_weight); Ok(()) } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 0d563955595a8..1a65316be1f10 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -304,11 +304,11 @@ impl multi_phase::weights::WeightInfo for DualMockWeightInfo { <() as multi_phase::weights::WeightInfo>::on_initialize_nothing() } } - fn create_snapshot_internal() -> Weight { + fn create_snapshot_internal(v: u32, t: u32) -> Weight { if MockWeightInfo::get() { Zero::zero() } else { - <() as multi_phase::weights::WeightInfo>::create_snapshot_internal() + <() as multi_phase::weights::WeightInfo>::create_snapshot_internal(v, t) } } fn on_initialize_open_signed() -> Weight { diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index af0b79177d86c..31ad502ac076e 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -651,7 +651,7 @@ mod max_weight { fn elect_queued(a: u32, d: u32) -> Weight { unreachable!() } - fn create_snapshot_internal() -> Weight { + fn create_snapshot_internal(v: u32, t: u32) -> Weight { unreachable!() } fn on_initialize_nothing() -> Weight { diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 262838bcb9e70..4d49f60fabfc3 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_election_provider_multi_phase //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-09-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -50,7 +50,7 @@ pub trait WeightInfo { fn on_initialize_open_unsigned() -> Weight; fn finalize_signed_phase_accept_solution() -> Weight; fn finalize_signed_phase_reject_solution() -> Weight; - fn create_snapshot_internal() -> Weight; + fn create_snapshot_internal(v: u32, t: u32, ) -> Weight; fn elect_queued(a: u32, d: u32, ) -> Weight; fn submit(c: u32, ) -> Weight; fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight; @@ -69,41 +69,45 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (23_878_000 as Weight) + (22_784_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (34_547_000 as Weight) + (32_763_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (33_568_000 as Weight) + (29_117_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (50_596_000 as Weight) + (48_996_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (33_389_000 as Weight) + (32_508_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - fn create_snapshot_internal() -> Weight { - (8_835_233_000 as Weight) + fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { + (96_001_000 as Weight) + // Standard Error: 1_000 + .saturating_add((307_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 2_000 + .saturating_add((133_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -116,11 +120,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (82_395_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_769_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 13_000 - .saturating_add((320_000 as Weight).saturating_mul(d as Weight)) + (100_505_000 as Weight) + // Standard Error: 6_000 + .saturating_add((1_665_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 10_000 + .saturating_add((443_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -131,9 +135,9 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit(c: u32, ) -> Weight { - (77_368_000 as Weight) - // Standard Error: 9_000 - .saturating_add((369_000 as Weight).saturating_mul(c as Weight)) + (74_088_000 as Weight) + // Standard Error: 59_000 + .saturating_add((187_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -146,14 +150,14 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_000 - .saturating_add((3_553_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 23_000 - .saturating_add((35_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 7_000 - .saturating_add((10_600_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 59_000 - .saturating_add((6_128_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 5_000 + .saturating_add((1_970_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 10_000 + .saturating_add((173_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 18_000 + .saturating_add((9_783_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 27_000 + .saturating_add((2_224_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -161,14 +165,16 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { + fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((3_478_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 6_000 - .saturating_add((8_930_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 47_000 - .saturating_add((5_199_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((1_910_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 7_000 + .saturating_add((111_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 13_000 + .saturating_add((7_741_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 19_000 + .saturating_add((1_844_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) } } @@ -184,41 +190,45 @@ impl WeightInfo for () { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (23_878_000 as Weight) + (22_784_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (34_547_000 as Weight) + (32_763_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (33_568_000 as Weight) + (29_117_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (50_596_000 as Weight) + (48_996_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (33_389_000 as Weight) + (32_508_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - fn create_snapshot_internal() -> Weight { - (8_835_233_000 as Weight) + fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { + (96_001_000 as Weight) + // Standard Error: 1_000 + .saturating_add((307_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 2_000 + .saturating_add((133_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -231,11 +241,11 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (82_395_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_769_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 13_000 - .saturating_add((320_000 as Weight).saturating_mul(d as Weight)) + (100_505_000 as Weight) + // Standard Error: 6_000 + .saturating_add((1_665_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 10_000 + .saturating_add((443_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -246,9 +256,9 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit(c: u32, ) -> Weight { - (77_368_000 as Weight) - // Standard Error: 9_000 - .saturating_add((369_000 as Weight).saturating_mul(c as Weight)) + (74_088_000 as Weight) + // Standard Error: 59_000 + .saturating_add((187_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -261,14 +271,14 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_000 - .saturating_add((3_553_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 23_000 - .saturating_add((35_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 7_000 - .saturating_add((10_600_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 59_000 - .saturating_add((6_128_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 5_000 + .saturating_add((1_970_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 10_000 + .saturating_add((173_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 18_000 + .saturating_add((9_783_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 27_000 + .saturating_add((2_224_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -276,14 +286,16 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { + fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((3_478_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 6_000 - .saturating_add((8_930_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 47_000 - .saturating_add((5_199_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((1_910_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 7_000 + .saturating_add((111_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 13_000 + .saturating_add((7_741_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 19_000 + .saturating_add((1_844_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) } } From eded99055e32c1b096993b94b38d3f6e04237c18 Mon Sep 17 00:00:00 2001 From: Georges Date: Wed, 22 Sep 2021 23:49:36 +0100 Subject: [PATCH 0016/1472] Generate storage info for pallet babe (#9760) * Adding MaxEncodedLen for: * NextConfigDescriptor * AllowedSlots * BabeEpochConfiguration In prepation for adding storage information on pallet babe * Adding stotage_info to pallet babe Refactored UNDER_CONSTRUCTION_SEGMENT_LENGTH to become a runtime parameter MaxSegmentLength * Reinstate Slice as opposed to Vec * Refactoring code to make it neater * Replace `MaxSegmentLength` by `UNDER_CONSTRUCTION_SEGMENT_LENGTH` Stop exposing the bounds to the runtime * Removing extra line Co-authored-by: thiolliere --- bin/node/runtime/src/lib.rs | 3 +- frame/babe/src/lib.rs | 86 ++++++++++++++++++------ frame/babe/src/mock.rs | 3 + frame/babe/src/tests.rs | 2 +- primitives/consensus/babe/src/digests.rs | 6 +- primitives/consensus/babe/src/lib.rs | 6 +- test-utils/runtime/src/lib.rs | 4 +- 7 files changed, 80 insertions(+), 30 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index af465fc0ffc1d..587a54ebd0d9b 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -376,6 +376,7 @@ impl pallet_babe::Config for Runtime { pallet_babe::EquivocationHandler; type WeightInfo = (); + type MaxAuthorities = MaxAuthorities; } parameter_types! { @@ -1441,7 +1442,7 @@ impl_runtime_apis! { slot_duration: Babe::slot_duration(), epoch_length: EpochDuration::get(), c: BABE_GENESIS_EPOCH_CONFIG.c, - genesis_authorities: Babe::authorities(), + genesis_authorities: Babe::authorities().to_vec(), randomness: Babe::randomness(), allowed_slots: BABE_GENESIS_EPOCH_CONFIG.allowed_slots, } diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index b39074bb3f057..4ccfdf6c13fe0 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -25,11 +25,13 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::DispatchResultWithPostInfo, traits::{ - DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem, OnTimestampSet, OneSessionHandler, + ConstU32, DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem, OnTimestampSet, + OneSessionHandler, }, weights::{Pays, Weight}, + BoundedVec, WeakBoundedVec, }; -use sp_application_crypto::Public; +use sp_application_crypto::{Public, TryFrom}; use sp_runtime::{ generic::DigestItem, traits::{IsMember, One, SaturatedConversion, Saturating, Zero}, @@ -100,7 +102,7 @@ impl EpochChangeTrigger for SameAuthoritiesForever { } } -const UNDER_CONSTRUCTION_SEGMENT_LENGTH: usize = 256; +const UNDER_CONSTRUCTION_SEGMENT_LENGTH: u32 = 256; type MaybeRandomness = Option; @@ -113,6 +115,7 @@ pub mod pallet { /// The BABE Pallet #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] @@ -169,6 +172,10 @@ pub mod pallet { type HandleEquivocation: HandleEquivocation; type WeightInfo: WeightInfo; + + /// Max number of authorities allowed + #[pallet::constant] + type MaxAuthorities: Get; } #[pallet::error] @@ -189,7 +196,11 @@ pub mod pallet { /// Current epoch authorities. #[pallet::storage] #[pallet::getter(fn authorities)] - pub type Authorities = StorageValue<_, Vec<(AuthorityId, BabeAuthorityWeight)>, ValueQuery>; + pub type Authorities = StorageValue< + _, + WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>, + ValueQuery, + >; /// The slot at which the first epoch actually started. This is 0 /// until the first block of the chain. @@ -229,8 +240,11 @@ pub mod pallet { /// Next epoch authorities. #[pallet::storage] - pub(super) type NextAuthorities = - StorageValue<_, Vec<(AuthorityId, BabeAuthorityWeight)>, ValueQuery>; + pub(super) type NextAuthorities = StorageValue< + _, + WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>, + ValueQuery, + >; /// Randomness under construction. /// @@ -246,8 +260,13 @@ pub mod pallet { /// TWOX-NOTE: `SegmentIndex` is an increasing integer, so this is okay. #[pallet::storage] - pub(super) type UnderConstruction = - StorageMap<_, Twox64Concat, u32, Vec, ValueQuery>; + pub(super) type UnderConstruction = StorageMap< + _, + Twox64Concat, + u32, + BoundedVec>, + ValueQuery, + >; /// Temporary value (cleared at block finalization) which is `Some` /// if per-block initialization has already been called for current block. @@ -503,8 +522,8 @@ impl Pallet { /// Typically, this is not handled directly by the user, but by higher-level validator-set /// manager logic like `pallet-session`. pub fn enact_epoch_change( - authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, - next_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, + authorities: WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>, + next_authorities: WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>, ) { // PRECONDITION: caller has done initialization and is guaranteed // by the session module to be called before this. @@ -541,8 +560,10 @@ impl Pallet { // so that nodes can track changes. let next_randomness = NextRandomness::::get(); - let next_epoch = - NextEpochDescriptor { authorities: next_authorities, randomness: next_randomness }; + let next_epoch = NextEpochDescriptor { + authorities: next_authorities.to_vec(), + randomness: next_randomness, + }; Self::deposit_consensus(ConsensusLog::NextEpochData(next_epoch)); if let Some(next_config) = NextEpochConfig::::get() { @@ -571,7 +592,7 @@ impl Pallet { epoch_index: EpochIndex::::get(), start_slot: Self::current_epoch_start(), duration: T::EpochDuration::get(), - authorities: Self::authorities(), + authorities: Self::authorities().to_vec(), randomness: Self::randomness(), config: EpochConfig::::get() .expect("EpochConfig is initialized in genesis; we never `take` or `kill` it; qed"), @@ -590,7 +611,7 @@ impl Pallet { epoch_index: next_epoch_index, start_slot: Self::epoch_start(next_epoch_index), duration: T::EpochDuration::get(), - authorities: NextAuthorities::::get(), + authorities: NextAuthorities::::get().to_vec(), randomness: NextRandomness::::get(), config: NextEpochConfig::::get().unwrap_or_else(|| { EpochConfig::::get().expect( @@ -619,14 +640,18 @@ impl Pallet { fn deposit_randomness(randomness: &schnorrkel::Randomness) { let segment_idx = SegmentIndex::::get(); let mut segment = UnderConstruction::::get(&segment_idx); - if segment.len() < UNDER_CONSTRUCTION_SEGMENT_LENGTH { + if segment.try_push(*randomness).is_ok() { // push onto current segment: not full. - segment.push(*randomness); UnderConstruction::::insert(&segment_idx, &segment); } else { // move onto the next segment and update the index. let segment_idx = segment_idx + 1; - UnderConstruction::::insert(&segment_idx, &vec![randomness.clone()]); + let bounded_randomness = + BoundedVec::<_, ConstU32>::try_from(vec![ + randomness.clone(), + ]) + .expect("UNDER_CONSTRUCTION_SEGMENT_LENGTH >= 1"); + UnderConstruction::::insert(&segment_idx, bounded_randomness); SegmentIndex::::put(&segment_idx); } } @@ -667,7 +692,7 @@ impl Pallet { // we use the same values as genesis because we haven't collected any // randomness yet. let next = NextEpochDescriptor { - authorities: Self::authorities(), + authorities: Self::authorities().to_vec(), randomness: Self::randomness(), }; @@ -732,7 +757,7 @@ impl Pallet { let segment_idx: u32 = SegmentIndex::::mutate(|s| sp_std::mem::replace(s, 0)); // overestimate to the segment being full. - let rho_size = segment_idx.saturating_add(1) as usize * UNDER_CONSTRUCTION_SEGMENT_LENGTH; + let rho_size = (segment_idx.saturating_add(1) * UNDER_CONSTRUCTION_SEGMENT_LENGTH) as usize; let next_randomness = compute_randomness( this_randomness, @@ -747,8 +772,11 @@ impl Pallet { fn initialize_authorities(authorities: &[(AuthorityId, BabeAuthorityWeight)]) { if !authorities.is_empty() { assert!(Authorities::::get().is_empty(), "Authorities are already initialized!"); - Authorities::::put(authorities); - NextAuthorities::::put(authorities); + let bounded_authorities = + WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.to_vec()) + .expect("Initial number of authorities should be lower than T::MaxAuthorities"); + Authorities::::put(&bounded_authorities); + NextAuthorities::::put(&bounded_authorities); } } @@ -878,10 +906,24 @@ impl OneSessionHandler for Pallet { I: Iterator, { let authorities = validators.map(|(_account, k)| (k, 1)).collect::>(); + let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from( + authorities, + Some( + "Warning: The session has more validators than expected. \ + A runtime configuration adjustment may be needed.", + ), + ); let next_authorities = queued_validators.map(|(_account, k)| (k, 1)).collect::>(); + let next_bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from( + next_authorities, + Some( + "Warning: The session has more queued validators than expected. \ + A runtime configuration adjustment may be needed.", + ), + ); - Self::enact_epoch_change(authorities, next_authorities) + Self::enact_epoch_change(bounded_authorities, next_bounded_authorities) } fn on_disabled(i: usize) { diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 833a68fbddb6c..a05072bc3319e 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -230,6 +230,8 @@ parameter_types! { pub const ExpectedBlockTime: u64 = 1; pub const ReportLongevity: u64 = BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get(); + pub const MaxAuthorities: u32 = 10; + pub const MaxSegmentLength: u32 = 256; } impl Config for Test { @@ -252,6 +254,7 @@ impl Config for Test { super::EquivocationHandler; type WeightInfo = (); + type MaxAuthorities = MaxAuthorities; } pub fn go_to_block(n: u64, s: u64) { diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index dc2f74c719519..34d861d5d97f7 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -92,7 +92,7 @@ fn first_block_epoch_zero_start() { let consensus_log = sp_consensus_babe::ConsensusLog::NextEpochData( sp_consensus_babe::digests::NextEpochDescriptor { - authorities: Babe::authorities(), + authorities: Babe::authorities().to_vec(), randomness: Babe::randomness(), }, ); diff --git a/primitives/consensus/babe/src/digests.rs b/primitives/consensus/babe/src/digests.rs index 470a028021ca1..1c908fe61fc0b 100644 --- a/primitives/consensus/babe/src/digests.rs +++ b/primitives/consensus/babe/src/digests.rs @@ -21,7 +21,7 @@ use super::{ AllowedSlots, AuthorityId, AuthorityIndex, AuthoritySignature, BabeAuthorityWeight, BabeEpochConfiguration, Slot, BABE_ENGINE_ID, }; -use codec::{Codec, Decode, Encode}; +use codec::{Codec, Decode, Encode, MaxEncodedLen}; use sp_runtime::{DigestItem, RuntimeDebug}; use sp_std::vec::Vec; @@ -134,7 +134,9 @@ pub struct NextEpochDescriptor { /// Information about the next epoch config, if changed. This is broadcast in the first /// block of the epoch, and applies using the same rules as `NextEpochDescriptor`. -#[derive(Decode, Encode, PartialEq, Eq, Clone, RuntimeDebug, scale_info::TypeInfo)] +#[derive( + Decode, Encode, PartialEq, Eq, Clone, RuntimeDebug, MaxEncodedLen, scale_info::TypeInfo, +)] pub enum NextConfigDescriptor { /// Version 1. #[codec(index = 1)] diff --git a/primitives/consensus/babe/src/lib.rs b/primitives/consensus/babe/src/lib.rs index 4417670f4144b..560866cfb2ab5 100644 --- a/primitives/consensus/babe/src/lib.rs +++ b/primitives/consensus/babe/src/lib.rs @@ -28,7 +28,7 @@ pub use sp_consensus_vrf::schnorrkel::{ Randomness, RANDOMNESS_LENGTH, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH, }; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -214,7 +214,7 @@ pub struct BabeGenesisConfiguration { } /// Types of allowed slots. -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum AllowedSlots { /// Only allow primary slots. @@ -247,7 +247,7 @@ impl sp_consensus::SlotData for BabeGenesisConfiguration { } /// Configuration data used by the BABE consensus engine. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct BabeEpochConfiguration { /// A constant value that is used in the threshold calculation formula. diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 0d880d508ef38..479d69c437567 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -574,6 +574,7 @@ impl pallet_timestamp::Config for Runtime { parameter_types! { pub const EpochDuration: u64 = 6; pub const ExpectedBlockTime: u64 = 10_000; + pub const MaxAuthorities: u32 = 10; } impl pallet_babe::Config for Runtime { @@ -596,8 +597,9 @@ impl pallet_babe::Config for Runtime { )>>::IdentificationTuple; type HandleEquivocation = (); - type WeightInfo = (); + + type MaxAuthorities = MaxAuthorities; } /// Adds one to the given input and returns the final result. From 4f8e0cf68f34ec3eb8e4b483683368d553a01c6d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 23 Sep 2021 09:20:37 +0100 Subject: [PATCH 0017/1472] Add some docs about runtime migration best practices (#9837) * Add some docs about runtime migration best practices as well. * Update docs/CONTRIBUTING.adoc * Update docs/CONTRIBUTING.adoc Co-authored-by: Chevdor Co-authored-by: Chevdor --- docs/CONTRIBUTING.adoc | 5 ++- utils/frame/try-runtime/cli/src/lib.rs | 44 ++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/docs/CONTRIBUTING.adoc b/docs/CONTRIBUTING.adoc index b0eaec04455e4..0a9a7ebacff5b 100644 --- a/docs/CONTRIBUTING.adoc +++ b/docs/CONTRIBUTING.adoc @@ -42,7 +42,7 @@ A Pull Request (PR) needs to be reviewed and approved by project maintainers unl . PRs must be tagged with their release importance via the `C1-C9` labels. . PRs must be tagged with their audit requirements via the `D1-D9` labels. . PRs that must be backported to a stable branch must be tagged with https://github.com/paritytech/substrate/labels/E1-runtimemigration[`E0-patchthis`]. -. PRs that introduce runtime migrations must be tagged with https://github.com/paritytech/substrate/labels/E1-runtimemigration[`E1-runtimemigration`]. +. PRs that introduce runtime migrations must be tagged with https://github.com/paritytech/substrate/labels/E1-runtimemigration[`E1-runtimemigration`]. See the https://github.com/paritytech/substrate/blob/master/utils/frame/try-runtime/cli/src/lib.rs#L18[Migration Best Practices here] for more info about how to test runtime migrations. . PRs that introduce irreversible database migrations must be tagged with https://github.com/paritytech/substrate/labels/E2-databasemigration[`E2-databasemigration`]. . PRs that add host functions must be tagged with with https://github.com/paritytech/substrate/labels/E4-newhostfunctions[`E4-newhostfunctions`]. . PRs that break the external API must be tagged with https://github.com/paritytech/substrate/labels/E5-breaksapi[`E5-breaksapi`]. @@ -88,8 +88,7 @@ To create a Polkadot companion PR: - The bot will push a commit to the Polkadot PR updating its Substrate reference. - If the polkadot PR origins from a fork then a project member may need to press `approve run` on the polkadot PR. - The bot will merge the Polkadot PR once all its CI `{"build_allow_failure":false}` checks are green. - - Note: The merge-bot currently doesn't work with forks on org accounts, only individual accounts. + Note: The merge-bot currently doesn't work with forks on org accounts, only individual accounts. If your PR is reviewed well, but a Polkadot PR is missing, signal it with https://github.com/paritytech/substrate/labels/A7-needspolkadotpr[`A7-needspolkadotpr`] to prevent it from getting automatically merged. diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index e7407f2f408fa..d5ccca9560252 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -29,9 +29,9 @@ //! //! Some resources about the above: //! -//! 1. https://substrate.dev/docs/en/knowledgebase/integrate/try-runtime -//! 2. https://www.crowdcast.io/e/substrate-seminar/41 -//! 3. https://substrate.dev/docs/en/knowledgebase/advanced/executor +//! 1. +//! 2. +//! 3. //! //! --- //! @@ -117,6 +117,44 @@ //! //! Note that *none* of the try-runtime operations need unsafe RPCs. //! +//! ## Migration Best Practices +//! +//! One of the main use-cases of try-runtime is using it for testing storage migrations. The +//! following points makes sure you can *effectively* test your migrations with try-runtime. +//! +//! #### Adding pre/post hooks +//! +//! One of the gems that come only in the `try-runtime` feature flag is the `pre_upgrade` and +//! `post_upgrade` hooks for [`OnRuntimeUpgrade`]. This trait is implemented either inside the +//! pallet, or manually in a runtime, to define a migration. In both cases, these functions can be +//! added, given the right flag: +//! +//! ```ignore +//! #[cfg(feature = try-runtime)] +//! fn pre_upgrade() -> Result<(), &'static str> {} +//! +//! #[cfg(feature = try-runtime)] +//! fn post_upgrade() -> Result<(), &'static str> {} +//! ``` +//! +//! (The pallet macro syntax will support this simply as a part of `#[pallet::hooks]`). +//! +//! These hooks allow you to execute some code, only within the `on-runtime-upgrade` command, before +//! and after the migration. If any data needs to be temporarily stored between the pre/post +//! migration hooks, [`OnRuntimeUpgradeHelpersExt`] can help with that. +//! +//! #### Logging +//! +//! It is super helpful to make sure your migration code uses logging (always with a `runtime` log +//! target prefix, e.g. `runtime::balance`) and state exactly at which stage it is, and what it is +//! doing. +//! +//! #### Guarding migrations +//! +//! Always make sure that any migration code is guarded either by [`StorageVersion`], or by some +//! custom storage item, so that it is NEVER executed twice, even if the code lives in two +//! consecutive runtimes. +//! //! ## Examples //! //! Run the migrations of the local runtime on the state of polkadot, from the polkadot repo where From 0df70939659abedde7275ee8aa13570026ff4b77 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Thu, 23 Sep 2021 13:51:40 +0200 Subject: [PATCH 0018/1472] add test (#9822) --- frame/support/src/traits/misc.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 75f2f8ac3fef1..82c5512ac15c5 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -424,3 +424,19 @@ impl From for WrapperOpaque { Self(t) } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_opaque_wrapper() { + let encoded = WrapperOpaque(3u32).encode(); + assert_eq!(encoded, [codec::Compact(4u32).encode(), 3u32.to_le_bytes().to_vec()].concat()); + let vec_u8 = >::decode(&mut &encoded[..]).unwrap(); + let decoded_from_vec_u8 = u32::decode(&mut &vec_u8[..]).unwrap(); + assert_eq!(decoded_from_vec_u8, 3u32); + let decoded = >::decode(&mut &encoded[..]).unwrap(); + assert_eq!(decoded.0, 3u32); + } +} From 7fcebc86856164a346f6762d339e8cc3b6ec9d30 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Thu, 23 Sep 2021 14:19:59 +0200 Subject: [PATCH 0019/1472] improve test (#9835) --- frame/support/test/tests/pallet.rs | 252 ++--------------------------- 1 file changed, 9 insertions(+), 243 deletions(-) diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 6a9a18ea48d4b..7eb8431ce146d 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -553,7 +553,7 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: frame_system::{Pallet, Call, Event}, + System: frame_system::{Call, Event}, Example: pallet::{Pallet, Call, Event, Config, Storage, Inherent, Origin, ValidateUnsigned}, Example2: pallet2::{Pallet, Call, Event, Config, Storage}, } @@ -1000,52 +1000,6 @@ fn metadata() { use frame_support::metadata::*; let pallets = vec![ - PalletMetadata { - index: 0, - name: "System", - storage: None, - calls: Some(meta_type::>().into()), - event: Some(meta_type::>().into()), - constants: vec![ - PalletConstantMetadata { - name: "BlockWeights", - ty: meta_type::(), - value: vec![], - docs: vec![], - }, - PalletConstantMetadata { - name: "BlockLength", - ty: meta_type::(), - value: vec![], - docs: vec![], - }, - PalletConstantMetadata { - name: "BlockHashCount", - ty: meta_type::(), - value: vec![], - docs: vec![], - }, - PalletConstantMetadata { - name: "DbWeight", - ty: meta_type::(), - value: vec![], - docs: vec![], - }, - PalletConstantMetadata { - name: "Version", - ty: meta_type::(), - value: vec![], - docs: vec![], - }, - PalletConstantMetadata { - name: "SS58Prefix", - ty: meta_type::(), - value: vec![], - docs: vec![], - }, - ], - error: Some(meta_type::>().into()), - }, PalletMetadata { index: 1, name: "Example", @@ -1255,170 +1209,31 @@ fn metadata() { error: Some(PalletErrorMetadata { ty: meta_type::>() }), }, PalletMetadata { - index: 1, - name: "Example", + index: 2, + name: "Example2", storage: Some(PalletStorageMetadata { - prefix: "Example", + prefix: "Example2", entries: vec![ StorageEntryMetadata { - name: "ValueWhereClause", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(meta_type::()), - default: vec![0], - docs: vec![], - }, - StorageEntryMetadata { - name: "Value", + name: "SomeValue", modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(meta_type::()), + ty: StorageEntryType::Plain(meta_type::>()), default: vec![0], docs: vec![], }, StorageEntryMetadata { - name: "Value2", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(meta_type::()), - default: vec![0], - docs: vec![], - }, - StorageEntryMetadata { - name: "Map", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - key: meta_type::(), - value: meta_type::(), - hashers: vec![StorageHasher::Blake2_128Concat], - }, - default: vec![4, 0], - docs: vec![], - }, - StorageEntryMetadata { - name: "Map2", + name: "SomeCountedStorageMap", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { - key: meta_type::(), - value: meta_type::(), hashers: vec![StorageHasher::Twox64Concat], - }, - default: vec![0], - docs: vec![], - }, - StorageEntryMetadata { - name: "DoubleMap", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - value: meta_type::(), - key: meta_type::<(u8, u16)>(), - hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Twox64Concat, - ], - }, - default: vec![0], - docs: vec![], - }, - StorageEntryMetadata { - name: "DoubleMap2", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - value: meta_type::(), - key: meta_type::<(u16, u32)>(), - hashers: vec![ - StorageHasher::Twox64Concat, - StorageHasher::Blake2_128Concat, - ], - }, - default: vec![0], - docs: vec![], - }, - StorageEntryMetadata { - name: "NMap", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { key: meta_type::(), - hashers: vec![StorageHasher::Blake2_128Concat], value: meta_type::(), }, default: vec![0], docs: vec![], }, StorageEntryMetadata { - name: "NMap2", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - key: meta_type::<(u16, u32)>(), - hashers: vec![ - StorageHasher::Twox64Concat, - StorageHasher::Blake2_128Concat, - ], - value: meta_type::(), - }, - default: vec![0], - docs: vec![], - }, - #[cfg(feature = "conditional-storage")] - StorageEntryMetadata { - name: "ConditionalValue", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(meta_type::()), - default: vec![0], - docs: vec![], - }, - #[cfg(feature = "conditional-storage")] - StorageEntryMetadata { - name: "ConditionalMap", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - key: meta_type::(), - value: meta_type::(), - hashers: vec![StorageHasher::Twox64Concat], - }, - default: vec![0], - docs: vec![], - }, - #[cfg(feature = "conditional-storage")] - StorageEntryMetadata { - name: "ConditionalDoubleMap", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - value: meta_type::(), - key: meta_type::<(u8, u16)>(), - hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Twox64Concat, - ], - }, - default: vec![0], - docs: vec![], - }, - #[cfg(feature = "conditional-storage")] - StorageEntryMetadata { - name: "ConditionalNMap", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - key: meta_type::<(u8, u16)>(), - hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Twox64Concat, - ], - value: meta_type::(), - }, - default: vec![0], - docs: vec![], - }, - StorageEntryMetadata { - name: "RenamedCountedMap", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Twox64Concat], - key: meta_type::(), - value: meta_type::(), - }, - default: vec![0], - docs: vec![], - }, - StorageEntryMetadata { - name: "CounterForRenamedCountedMap", + name: "CounterForSomeCountedStorageMap", modifier: StorageEntryModifier::Default, ty: StorageEntryType::Plain(meta_type::()), default: vec![0, 0, 0, 0], @@ -1426,55 +1241,6 @@ fn metadata() { }, ], }), - calls: Some(meta_type::>().into()), - event: Some(meta_type::>().into()), - constants: vec![ - PalletConstantMetadata { - name: "MyGetParam", - ty: meta_type::(), - value: vec![10, 0, 0, 0], - docs: vec![" Some comment", " Some comment"], - }, - PalletConstantMetadata { - name: "MyGetParam2", - ty: meta_type::(), - value: vec![11, 0, 0, 0], - docs: vec![" Some comment", " Some comment"], - }, - PalletConstantMetadata { - name: "MyGetParam3", - ty: meta_type::(), - value: vec![12, 0, 0, 0, 0, 0, 0, 0], - docs: vec![], - }, - PalletConstantMetadata { - name: "some_extra", - ty: meta_type::(), - value: vec![100, 0, 0, 0, 0, 0, 0, 0], - docs: vec![" Some doc", " Some doc"], - }, - PalletConstantMetadata { - name: "some_extra_extra", - ty: meta_type::(), - value: vec![0, 0, 0, 0, 0, 0, 0, 0], - docs: vec![" Some doc"], - }, - ], - error: Some(PalletErrorMetadata { ty: meta_type::>() }), - }, - PalletMetadata { - index: 2, - name: "Example2", - storage: Some(PalletStorageMetadata { - prefix: "Example2", - entries: vec![StorageEntryMetadata { - name: "SomeValue", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(meta_type::>()), - default: vec![0], - docs: vec![], - }], - }), calls: Some(meta_type::>().into()), event: Some(PalletEventMetadata { ty: meta_type::() }), constants: vec![], @@ -1504,7 +1270,7 @@ fn metadata() { _ => panic!("metadata has been bumped, test needs to be updated"), }; - pretty_assertions::assert_eq!(actual_metadata.pallets[1], expected_metadata.pallets[1]); + pretty_assertions::assert_eq!(actual_metadata.pallets, expected_metadata.pallets); } #[test] From 65ac6f39c72e77fd98f337f1a5beddd539ee8d6f Mon Sep 17 00:00:00 2001 From: Andreas Doerr Date: Thu, 23 Sep 2021 21:02:30 +0200 Subject: [PATCH 0020/1472] Integrate BEEFY (#9833) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial project setup and skeleton (#4) * initial project setup for beefy gadget client * update editorconfig * update gitignore * add initial skeleton for beefy gadget worker * add skeleton for gossip processing * add app crypto * move around some code * add basic flow for voting * add logic for picking blocks to sign * add rustfmt config * add example node with beefy gadget * use u32::next_power_of_two * make maximum periodicity configurable * add copyright header * rename max_periodicity to min_interval * CI stuff (#5) * CI stuff. * Fix workspace. * cargo fmt --all * Add license for beefy-gadget * One toolchain to rule them all. * Clippy. * Fix clippy. * Clippy in the runtime. * Fix clippy grumbles. * cargo fmt --all * Primitives & Light Client examples (#8) * Primitives. * Docs. * Document primitives. * Simple tests. * Light client examples. * Fix stuff. * cargo fmt --all * Add a bunch of tests for imports. * Add more examples. * cargo fmt --all * Fix clippy. * cargo fmt --all * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Add GRANDPA / FG clarifications. * Fix min number of signatures. Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Update to substrate master (#22) * update to substrate master * update dependencies * fix clippy issues Co-authored-by: Tomasz Drwięga * Add beefy pallet (#25) * move beefy application crypto to primitives * make primitives compile under no_std * add beefy pallet that maintains authority set * add beefy pallet to node example runtime * tabify node-example cargo.toml files * use double quotes in Cargo.toml files * add missing hex-literal dependency * add runtime api to fetch BEEFY authorities * fix clippy warnings * rename beefy-pallet to pallet-beefy * sort dependencies in node-example/runtime/Cargo.toml * Signed commitments rpc pubsub (#26) * move beefy application crypto to primitives * make primitives compile under no_std * add beefy pallet that maintains authority set * add beefy pallet to node example runtime * tabify node-example cargo.toml files * use double quotes in Cargo.toml files * add missing hex-literal dependency * add runtime api to fetch BEEFY authorities * fix clippy warnings * gadget: use commitment and signedcommitment * gadget: send notifications for signed commitments * gadget: add rpc pubsub for signed commitments * node-example: enable beefy rpc * gadget: fix clippy warnings * rename beefy-pallet to pallet-beefy * sort dependencies in node-example/runtime/Cargo.toml * gadget: add documentation on SignedCommitment rpc wrapper type * gadget: add todos about dummy beefy commitments * gadget: remove redundant closure Co-authored-by: Tomasz Drwięga Co-authored-by: Tomasz Drwięga * Integrate MMR and deposit root into the digest. (#24) * Add basic MMR. * Deposit digest item. * cargo fmt --all * Merge with primitives. * cargo fmt --all * Fix extra spaces. * cargo fmt --all * Switch branch. * remove stray whitespace * update to latest td-mmr commit * fix clippy error Co-authored-by: André Silva * use new mmr root as commitment payload (#27) * use new mmr root as commitment payload * fix mmr root codec index * warn on MMR root digest not found Co-authored-by: Tomasz Drwięga * add type alias for MMR root hash Co-authored-by: Tomasz Drwięga * Bump serde_json from 1.0.59 to 1.0.60 (#28) * Update to latest substrate. (#32) * Update to latest substrate. * Fix tests. * cargo fmt --all * Switch to master. * Bump serde from 1.0.117 to 1.0.118 (#29) * Bump serde from 1.0.117 to 1.0.118 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.117 to 1.0.118. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.117...v1.0.118) Signed-off-by: dependabot-preview[bot] * Bump arc-swap. Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Tomasz Drwięga Co-authored-by: Tomasz Drwięga * Remove transition flag (#35) * Get rid of is_set_transition_flag * Fix tests. * cargo fmt --all * Bump futures from 0.3.9 to 0.3.12 (#50) * Bump log from 0.4.11 to 0.4.13 (#52) * Bump Substrate and Deps (#57) * Update README (#58) * Update README * Apply suggestions from code review Co-authored-by: Tomasz Drwięga * address review comments * missed a typo Co-authored-by: Tomasz Drwięga * Add validator set to the pallet. (#65) * Bump Substrate and Deps (#71) * Bump Substrate and Deps * pin serde and syn * bump Substrate again for '__Nonexhaustive' fix * add cargo deny ignore * Beefy pallet test (#74) * setup mock * test session change * silence beefy * clippy still * no change - no log * clippy again * Apply suggestions from code review Co-authored-by: Tomasz Drwięga * code review changes, added additional test Co-authored-by: Tomasz Drwięga * Beefy node cleanup (#75) * bump serde * bump substrate, scale-codec 2.0.0 * we need a proper beefy node * rename primitives as well * Sort members. Co-authored-by: Tomasz Drwięga * Migrate beefy-pallet to FRAMEv2 (#76) * migrate beefy-pallet to FRAMEv2 * Code review Co-authored-by: Hernando Castano Co-authored-by: Hernando Castano * Run BEEFY worker as non-validator (#77) * run BEEFY worker as non-validator * don't check for roloe.is_authority * change enum type name * Bump Substrate and Deps (#79) * Add BEEFY gadget as extra peer set (#80) * Add BEEFY gadget as extra peer set * use BEEFY protocol * Add ValidatorSetId to BEEFY digest (#85) * add ValidatorSetId to BEEFY digest * apply review changes * Bump Substrate and Deps (#91) * Bump Substrate and Deps * Bump Substrate again in order to include a hot-fix * redo again * use CryptoStore issue * cargo fmt * Bump serde_json from 1.0.63 to 1.0.64 (#93) * Track BEEFY validator set (#94) * Track BEEFY validator set * Add validator_set_id to BeefyWorker * Make validattor_set_id optional * Ad 92 (#97) * sign_commitment() * Error handling todo * Add error type (#99) * Add error type * Address review * Extract worker and round logic (#104) * Bump serde from 1.0.123 to 1.0.124 (#106) * Rework BeefyAPI (#110) * Initialize BeefyWorker with current validator set (#111) * Update toolchain (#115) * Use nightly toolchain * dongradde to latest clippy stable * GH workflow trail and error * next try * use stable for clippy * update wasm builder * yet another try * fun with CI * no env var * and one more * allow from_over_into bco contruct_runtime * back to start * well ... * full circle * old version was still used * Bump Substrate and Deps (#117) * Bump Substrate and Deps * cargo fmt should enforce uniform imports * merge some imports * Delayed BEEFY worker initialization (#121) * lifecycle state * add Client convenience trait * rework trait identifiers * WIP * rework BeefyWorker::new() signature * Delayed BEEFY gadget initialization * address review * Bump substrate. (#123) * Bump substrate. * Fix tests. * Lower log-level for a missing validator set (#124) * lower log-level for a missing validator set * move best_finalized_block initialization * Setup Prometheus metrics (#125) * setup Prometheus metrics * expose validator set id * cargo fmt * Update beefy-gadget/src/lib.rs Co-authored-by: Tomasz Drwięga * add vote messages gossiped metric * track authorities change, before checking for MMR root digest Co-authored-by: Tomasz Drwięga * Make Client convenience trait public (#126) * Bump serde from 1.0.124 to 1.0.125 (#131) * Reset rounds on new validator set. (#133) * Re-set rounds on new validator set. * Fix docs. * Bump Substrate and Deps (#134) * beefy: authority set changes fixes (#139) * node: fix grandpa peers set config * gadget: update best finalized number only when finalized with beefy * gadget: process authorities changes regardless of vote status * gadget: remove superfluous signature type (#140) * node: fix grandpa peers set config * gadget: update best finalized number only when finalized with beefy * gadget: process authorities changes regardless of vote status * gadget: remove superfluous signature type Co-authored-by: Tomasz Drwięga * gadget: reduce gossip spam (#141) * node: fix grandpa peers set config * gadget: update best finalized number only when finalized with beefy * gadget: process authorities changes regardless of vote status * gadget: remove superfluous signature type * gadget: only gossip last 5 rounds * gadget: note round to gossip validator before gossiping message * gadget: fix clippy warnings * gadget: update docs Co-authored-by: Tomasz Drwięga Co-authored-by: Tomasz Drwięga Co-authored-by: adoerr <0xad@gmx.net> * gadget: verify SignedCommitment message signature (#142) * gadget: verify SignedCommitment message signature * gadget: log messages with bad sigs * gadget: move todo comment * Bump futures from 0.3.13 to 0.3.14 (#145) * Milestone 1 (#144) * use best_finalized, prevent race * make best_finalized_block an Option, should_vote_on bails on None * Bump futures from 0.3.13 to 0.3.14 * Revert futures bump * Revert "Revert futures bump" This reverts commit a1b5e7e9bac526f2897ebfdfee7f02dd29a13ac5. * Revert "Bump futures from 0.3.13 to 0.3.14" This reverts commit a4e508b118ad2c4b52909d24143c284073961458. * debug msg if the bail voting * validator_set() * local_id() * get rid of worker state * Apply review suggestions * fix should_vote_on() * Extract BeefyGossipValidator (#147) * Extract BeefyGossipValidator * Apply review suggestions * Add block_delta parameter to start_beefy_gadget (#151) * Add block_delta parameter * rename to min_block_delta * Add additional metrics (#152) * Add additional metrics * add skipped session metric * add some comment for temp metric * don't log under info for every concluded round (#156) * don't log error on missing validator keys (#157) * don't log error on missing validator keys * remove unused import * Fix validator set change handling (#158) * reduce some logs from debug to trace * fix validator set changes handling * rename validator module to gossip * run rustfmt * Fix should_vote_on() (#160) * Fix should_vote_on() * by the textbook * fix the algorithm * Apply review suggestions * don't use NumberFor in vote_target Co-authored-by: André Silva * Make KeyStore optional (#173) * Use builder pattern for NonDefaultSetConfig (#178) Co-authored-by: adoerr <0xad@gmx.net> * Append SignedCommitment to block justifications (#177) * Append SignedCommitment * add BeefyParams * add WorkerParams * use warn * versioned variant for SignedCommitment * Bump serde from 1.0.125 to 1.0.126 (#184) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.125 to 1.0.126. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.125...v1.0.126) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump strum from 0.20.0 to 0.21.0 (#195) * Bump strum from 0.20.0 to 0.21.0 Bumps [strum](https://github.com/Peternator7/strum) from 0.20.0 to 0.21.0. - [Release notes](https://github.com/Peternator7/strum/releases) - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/commits) --- updated-dependencies: - dependency-name: strum dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * use dervie feature for strum; clippy and deny housekeeping Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: adoerr <0xad@gmx.net> * Make concluded round an info log (#200) * Remove external crypto trait bounds (#207) * BeefyKeystore newtype * WIP * remove mod ecdsa * WIP * fix tests * some polishing * Rename AuthorityId to BeefyId to avoid type conflict in UI (#211) * Add trace points; Reduce MAX_LIVE_GOSSIP_ROUNDS (#210) * Add trace points; Reduce MAX_LIVE_GOSSIP_ROUNDS * log local authority id * Additional initial authority id's (#217) * Scratch concluded rounds * adjust testnet doc * fix authority key typo * We don't want no scratches * address review comments * Fix note_round() (#219) * rename BeefyGossipValidator * Fix note_round() * use const for assert * put message trace points back in * test case note_same_round_twice() * address review comments * remove redundant check * Use LocalKeystore for tests (#224) * private_keys() * Use LocalKeystore for tests * Use keystore helper * Address review * some reformatting * Cache known votes in gossip (#227) * Implement known messages cache. * Add tests. * Appease clippy. * More clippy Co-authored-by: adoerr <0xad@gmx.net> * Some key store sanity checks (#232) * verify vote message * verify_validator_set() * rework logging * some rework * Tone down warnings. * Add signature verification. * Tone down more. * Fix clippy Co-authored-by: Tomasz Drwięga * Use Binary Merkle Tree instead of a trie (#225) * Binary tree merkle root. * Add proofs and verification. * Clean up debug. * Use BEEFY addresses instead of pubkeys. * Use new merkle tree. * Optimize allocations. * Add test for larger trees. * Add tests for larger cases. * Appease clippy * Appease clippy2. * Fix proof generation & verification. * Add more test data. * Fix CLI. * Update README * Bump version. * Update docs. * Rename beefy-merkle-root to beefy-merkle-tree Co-authored-by: adoerr <0xad@gmx.net> * Bump Substrate and Deps (#235) * BEEFY+MMR pallet (#236) * Add MMR leaf format to primitives. * Fix tests * Initial work on the BEEFY-MMR pallet. * Add tests to MMR pallet. * Use eth addresses. * Use binary merkle tree. * Bump libsecp256k1 * Fix compilation. * Bump deps. * Appease cargo deny. * Re-format. * Module-level docs. * no-std fix. * update README Co-authored-by: adoerr <0xad@gmx.net> * Fix noting rounds for non-authorities (#238) * Bump env_logger from 0.8.4 to 0.9.0 (#242) Bumps [env_logger](https://github.com/env-logger-rs/env_logger) from 0.8.4 to 0.9.0. - [Release notes](https://github.com/env-logger-rs/env_logger/releases) - [Changelog](https://github.com/env-logger-rs/env_logger/blob/main/CHANGELOG.md) - [Commits](https://github.com/env-logger-rs/env_logger/compare/v0.8.4...v0.9.0) --- updated-dependencies: - dependency-name: env_logger 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> * gadget: add global timeout for rebroadcasting messages (#243) * gadget: add global timeout for rebroadcasting messages * update rustfmt.toml * make message_allowed() a debug trace Co-authored-by: adoerr <0xad@gmx.net> * Bump Substrate and Deps (#245) * Bump Substrate and Deps * Bump Substrate again * Bump futures from 0.3.15 to 0.3.16 (#247) Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.15 to 0.3.16. - [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.15...0.3.16) --- 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> * Bump libsecp256k1 from 0.5.0 to 0.6.0 (#249) * Bump libsecp256k1 from 0.5.0 to 0.6.0 Bumps [libsecp256k1](https://github.com/paritytech/libsecp256k1) from 0.5.0 to 0.6.0. - [Release notes](https://github.com/paritytech/libsecp256k1/releases) - [Changelog](https://github.com/paritytech/libsecp256k1/blob/master/CHANGELOG.md) - [Commits](https://github.com/paritytech/libsecp256k1/commits) --- updated-dependencies: - dependency-name: libsecp256k1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * use correct crate name Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: adoerr <0xad@gmx.net> * Derive `scale_info::TypeInfo` for types used in polkadot (#218) * Add scale-info TypeInfo derives * Update scale-info * Add crates.io patches * Use substrate aj-metadata-vnext branch * Revert master branch substrate deps * Add scale-info to beefy-pallet * scale-info v0.9.0 * Remove github dependencies and patches * More TypeInfo derives * Update scale-info to 0.10.0 * Add missing scale-info dependency * Add missing TypeInfo derive * Hide TypeInfo under a feature. Co-authored-by: Tomasz Drwięga * Bump serde from 1.0.126 to 1.0.127 (#260) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.126 to 1.0.127. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.126...v1.0.127) --- 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> * Bump Substrate and Deps (#262) * Update jsonrpc (#265) * Update jsonrpc * Update Substrate * bump Substrate and Deps (#268) * Bump serde from 1.0.127 to 1.0.128 (#272) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.127 to 1.0.128. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.127...v1.0.128) --- 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> * Fix spelling (#271) * Bump serde from 1.0.128 to 1.0.130 (#276) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.128 to 1.0.130. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.128...v1.0.130) --- 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> * Bump scale-info from 0.10.0 to 0.12.0 (#275) Bumps [scale-info](https://github.com/paritytech/scale-info) from 0.10.0 to 0.12.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/commits) --- 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> Co-authored-by: adoerr <0xad@gmx.net> * Update to scale-info 1.0 (#278) * bump substrate (#282) * bump Substrate and Deps * cargo fmt Co-authored-by: Wenfeng Wang * Update worker.rs (#287) * Bump anyhow from 1.0.43 to 1.0.44 (#290) * Bump anyhow from 1.0.43 to 1.0.44 Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.43 to 1.0.44. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.43...1.0.44) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * derive Default Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: adoerr <0xad@gmx.net> * Remove optional `scale-info` feature (#292) * Make scale-info dependency non-optional * Remove feature gated TypeInfo derives * Import TypeInfo * Update substrate * Fix up runtime * prune .git suffix (#294) * remove unused deps (#295) * remove unused deps * update lock file * Bump libsecp256k1 from 0.6.0 to 0.7.0 (#296) * Bump libsecp256k1 from 0.6.0 to 0.7.0 Bumps [libsecp256k1](https://github.com/paritytech/libsecp256k1) from 0.6.0 to 0.7.0. - [Release notes](https://github.com/paritytech/libsecp256k1/releases) - [Changelog](https://github.com/paritytech/libsecp256k1/blob/master/CHANGELOG.md) - [Commits](https://github.com/paritytech/libsecp256k1/commits) --- updated-dependencies: - dependency-name: libsecp256k1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * update sec advisories Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: adoerr <0xad@gmx.net> * clean compile * use path dependencies * beefy-gadget license header * pallet-beefy license header * pallet-beefy-mmr license header * beefy-primitves license header * carg fmt * more formatting * shorten line * downgrade parity-scale-codec to 2.2.0 * use path dependency for Prometheus endpoint * remove clippy annotations Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Tomasz Drwięga Co-authored-by: Tomasz Drwięga Co-authored-by: André Silva Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Hernando Castano Co-authored-by: Pierre Krieger Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrew Jones Co-authored-by: Bastian Köcher Co-authored-by: drewstone Co-authored-by: Andronik Ordian Co-authored-by: Wenfeng Wang Co-authored-by: Joshy Orndorff Co-authored-by: Squirrel --- Cargo.lock | 191 +++++- Cargo.toml | 6 + client/beefy/Cargo.toml | 38 ++ client/beefy/rpc/Cargo.toml | 26 + client/beefy/rpc/src/lib.rs | 114 ++++ client/beefy/rpc/src/notification.rs | 39 ++ client/beefy/src/error.rs | 31 + client/beefy/src/gossip.rs | 236 ++++++++ client/beefy/src/gossip_tests.rs | 182 ++++++ client/beefy/src/keystore.rs | 119 ++++ client/beefy/src/keystore_tests.rs | 275 +++++++++ client/beefy/src/lib.rs | 159 +++++ client/beefy/src/metrics.rs | 93 +++ client/beefy/src/notification.rs | 113 ++++ client/beefy/src/round.rs | 121 ++++ client/beefy/src/worker.rs | 534 +++++++++++++++++ frame/beefy-mmr/Cargo.toml | 56 ++ frame/beefy-mmr/primitives/Cargo.toml | 23 + frame/beefy-mmr/primitives/src/lib.rs | 806 ++++++++++++++++++++++++++ frame/beefy-mmr/src/lib.rs | 236 ++++++++ frame/beefy-mmr/src/mock.rs | 205 +++++++ frame/beefy-mmr/src/tests.rs | 148 +++++ frame/beefy/Cargo.toml | 40 ++ frame/beefy/src/lib.rs | 179 ++++++ frame/beefy/src/mock.rs | 164 ++++++ frame/beefy/src/tests.rs | 142 +++++ primitives/beefy/Cargo.toml | 33 ++ primitives/beefy/src/commitment.rs | 264 +++++++++ primitives/beefy/src/lib.rs | 137 +++++ primitives/beefy/src/mmr.rs | 132 +++++ primitives/beefy/src/witness.rs | 162 ++++++ 31 files changed, 4992 insertions(+), 12 deletions(-) create mode 100644 client/beefy/Cargo.toml create mode 100644 client/beefy/rpc/Cargo.toml create mode 100644 client/beefy/rpc/src/lib.rs create mode 100644 client/beefy/rpc/src/notification.rs create mode 100644 client/beefy/src/error.rs create mode 100644 client/beefy/src/gossip.rs create mode 100644 client/beefy/src/gossip_tests.rs create mode 100644 client/beefy/src/keystore.rs create mode 100644 client/beefy/src/keystore_tests.rs create mode 100644 client/beefy/src/lib.rs create mode 100644 client/beefy/src/metrics.rs create mode 100644 client/beefy/src/notification.rs create mode 100644 client/beefy/src/round.rs create mode 100644 client/beefy/src/worker.rs create mode 100644 frame/beefy-mmr/Cargo.toml create mode 100644 frame/beefy-mmr/primitives/Cargo.toml create mode 100644 frame/beefy-mmr/primitives/src/lib.rs create mode 100644 frame/beefy-mmr/src/lib.rs create mode 100644 frame/beefy-mmr/src/mock.rs create mode 100644 frame/beefy-mmr/src/tests.rs create mode 100644 frame/beefy/Cargo.toml create mode 100644 frame/beefy/src/lib.rs create mode 100644 frame/beefy/src/mock.rs create mode 100644 frame/beefy/src/tests.rs create mode 100644 primitives/beefy/Cargo.toml create mode 100644 primitives/beefy/src/commitment.rs create mode 100644 primitives/beefy/src/lib.rs create mode 100644 primitives/beefy/src/mmr.rs create mode 100644 primitives/beefy/src/witness.rs diff --git a/Cargo.lock b/Cargo.lock index e386b600f79ba..693388a5299ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -492,6 +492,80 @@ dependencies = [ "serde", ] +[[package]] +name = "beefy-gadget" +version = "4.0.0-dev" +dependencies = [ + "beefy-primitives", + "fnv", + "futures 0.3.16", + "log 0.4.14", + "parity-scale-codec", + "parking_lot 0.11.1", + "sc-client-api", + "sc-keystore", + "sc-network", + "sc-network-gossip", + "sc-network-test", + "sc-utils", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-blockchain", + "sp-core", + "sp-keystore", + "sp-runtime", + "strum 0.21.0", + "substrate-prometheus-endpoint", + "thiserror", + "wasm-timer", +] + +[[package]] +name = "beefy-gadget-rpc" +version = "4.0.0-dev" +dependencies = [ + "beefy-gadget", + "beefy-primitives", + "futures 0.3.16", + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-derive", + "jsonrpc-pubsub", + "log 0.4.14", + "parity-scale-codec", + "sc-rpc", + "serde", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "beefy-merkle-tree" +version = "4.0.0-dev" +dependencies = [ + "env_logger 0.9.0", + "hex", + "hex-literal", + "log 0.4.14", + "tiny-keccak", +] + +[[package]] +name = "beefy-primitives" +version = "4.0.0-dev" +dependencies = [ + "hex-literal", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-keystore", + "sp-runtime", + "sp-std", +] + [[package]] name = "bincode" version = "1.3.2" @@ -3751,9 +3825,9 @@ dependencies = [ "base64 0.12.3", "digest 0.9.0", "hmac-drbg 0.3.0", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", + "libsecp256k1-core 0.2.2", + "libsecp256k1-gen-ecmult 0.2.1", + "libsecp256k1-gen-genmult 0.2.1", "rand 0.7.3", "serde", "sha2 0.9.3", @@ -3770,15 +3844,32 @@ dependencies = [ "base64 0.12.3", "digest 0.9.0", "hmac-drbg 0.3.0", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", + "libsecp256k1-core 0.2.2", + "libsecp256k1-gen-ecmult 0.2.1", + "libsecp256k1-gen-genmult 0.2.1", "rand 0.7.3", "serde", "sha2 0.9.3", "typenum", ] +[[package]] +name = "libsecp256k1" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0452aac8bab02242429380e9b2f94ea20cea2b37e2c1777a1358799bbe97f37" +dependencies = [ + "arrayref", + "base64 0.13.0", + "digest 0.9.0", + "libsecp256k1-core 0.3.0", + "libsecp256k1-gen-ecmult 0.3.0", + "libsecp256k1-gen-genmult 0.3.0", + "rand 0.8.4", + "serde", + "sha2 0.9.3", +] + [[package]] name = "libsecp256k1-core" version = "0.2.2" @@ -3790,13 +3881,33 @@ dependencies = [ "subtle 2.4.0", ] +[[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 2.4.0", +] + [[package]] name = "libsecp256k1-gen-ecmult" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" dependencies = [ - "libsecp256k1-core", + "libsecp256k1-core 0.2.2", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core 0.3.0", ] [[package]] @@ -3805,7 +3916,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" dependencies = [ - "libsecp256k1-core", + "libsecp256k1-core 0.2.2", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core 0.3.0", ] [[package]] @@ -5114,6 +5234,50 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-beefy" +version = "4.0.0-dev" +dependencies = [ + "beefy-primitives", + "frame-support", + "frame-system", + "pallet-session", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-beefy-mmr" +version = "4.0.0-dev" +dependencies = [ + "beefy-merkle-tree", + "beefy-primitives", + "frame-support", + "frame-system", + "hex", + "hex-literal", + "libsecp256k1 0.7.0", + "log 0.4.14", + "pallet-beefy", + "pallet-mmr", + "pallet-mmr-primitives", + "pallet-session", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + [[package]] name = "pallet-bounties" version = "4.0.0-dev" @@ -8629,9 +8793,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.126" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] @@ -8657,9 +8821,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2", "quote", @@ -9779,6 +9943,9 @@ name = "strum" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" +dependencies = [ + "strum_macros 0.21.1", +] [[package]] name = "strum_macros" diff --git a/Cargo.toml b/Cargo.toml index e110c27b20d77..71473a4bc5689 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ members = [ "client/api", "client/authority-discovery", "client/basic-authorship", + "client/beefy", + "client/beefy/rpc", "client/block-builder", "client/chain-spec", "client/chain-spec/derive", @@ -69,6 +71,9 @@ members = [ "frame/authorship", "frame/babe", "frame/balances", + "frame/beefy", + "frame/beefy-mmr", + "frame/beefy-mmr/primitives", "frame/benchmarking", "frame/bounties", "frame/collective", @@ -138,6 +143,7 @@ members = [ "primitives/arithmetic/fuzzer", "primitives/authority-discovery", "primitives/authorship", + "primitives/beefy", "primitives/block-builder", "primitives/blockchain", "primitives/consensus/aura", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml new file mode 100644 index 0000000000000..d4541288a6287 --- /dev/null +++ b/client/beefy/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "beefy-gadget" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +fnv = "1.0.6" +futures = "0.3" +log = "0.4" +parking_lot = "0.11" +thiserror = "1.0" +wasm-timer = "0.2.5" + +codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive"] } +prometheus = { version = "0.9.0", package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } + +sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } +sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } +sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } +sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } + +sc-utils = { version = "4.0.0-dev", path = "../utils" } +sc-client-api = { version = "4.0.0-dev", path = "../api" } +sc-keystore = { version = "4.0.0-dev", path = "../keystore" } +sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } + +beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } + +[dev-dependencies] +sc-network-test = { version = "0.8.0", path = "../network/test" } + +strum = { version = "0.21", features = ["derive"] } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml new file mode 100644 index 0000000000000..6bb5c5fcc668e --- /dev/null +++ b/client/beefy/rpc/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "beefy-gadget-rpc" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +futures = "0.3.16" +log = "0.4" +serde = { version = "1.0.130", features = ["derive"] } + +jsonrpc-core = "18.0.0" +jsonrpc-core-client = "18.0.0" +jsonrpc-derive = "18.0.0" +jsonrpc-pubsub = "18.0.0" + +codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive"] } + +sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } + +sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-runtime = { versin = "4.0.0-dev", path = "../../../primitives/runtime" } + +beefy-gadget = { version = "4.0.0-dev", path = "../." } +beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs new file mode 100644 index 0000000000000..c9a09525569b8 --- /dev/null +++ b/client/beefy/rpc/src/lib.rs @@ -0,0 +1,114 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! RPC API for BEEFY. + +#![warn(missing_docs)] + +use std::sync::Arc; + +use sp_runtime::traits::Block as BlockT; + +use futures::{FutureExt, SinkExt, StreamExt}; +use jsonrpc_derive::rpc; +use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; +use log::warn; + +use beefy_gadget::notification::BeefySignedCommitmentStream; + +mod notification; + +/// Provides RPC methods for interacting with BEEFY. +#[rpc] +pub trait BeefyApi { + /// RPC Metadata + type Metadata; + + /// Returns the block most recently finalized by BEEFY, alongside side its justification. + #[pubsub( + subscription = "beefy_justifications", + subscribe, + name = "beefy_subscribeJustifications" + )] + fn subscribe_justifications( + &self, + metadata: Self::Metadata, + subscriber: Subscriber, + ); + + /// Unsubscribe from receiving notifications about recently finalized blocks. + #[pubsub( + subscription = "beefy_justifications", + unsubscribe, + name = "beefy_unsubscribeJustifications" + )] + fn unsubscribe_justifications( + &self, + metadata: Option, + id: SubscriptionId, + ) -> jsonrpc_core::Result; +} + +/// Implements the BeefyApi RPC trait for interacting with BEEFY. +pub struct BeefyRpcHandler { + signed_commitment_stream: BeefySignedCommitmentStream, + manager: SubscriptionManager, +} + +impl BeefyRpcHandler { + /// Creates a new BeefyRpcHandler instance. + pub fn new(signed_commitment_stream: BeefySignedCommitmentStream, executor: E) -> Self + where + E: futures::task::Spawn + Send + Sync + 'static, + { + let manager = SubscriptionManager::new(Arc::new(executor)); + Self { signed_commitment_stream, manager } + } +} + +impl BeefyApi for BeefyRpcHandler +where + Block: BlockT, +{ + type Metadata = sc_rpc::Metadata; + + fn subscribe_justifications( + &self, + _metadata: Self::Metadata, + subscriber: Subscriber, + ) { + let stream = self + .signed_commitment_stream + .subscribe() + .map(|x| Ok::<_, ()>(Ok(notification::SignedCommitment::new::(x)))); + + self.manager.add(subscriber, |sink| { + stream + .forward(sink.sink_map_err(|e| warn!("Error sending notifications: {:?}", e))) + .map(|_| ()) + }); + } + + fn unsubscribe_justifications( + &self, + _metadata: Option, + id: SubscriptionId, + ) -> jsonrpc_core::Result { + Ok(self.manager.cancel(id)) + } +} diff --git a/client/beefy/rpc/src/notification.rs b/client/beefy/rpc/src/notification.rs new file mode 100644 index 0000000000000..4830d72905a98 --- /dev/null +++ b/client/beefy/rpc/src/notification.rs @@ -0,0 +1,39 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use codec::Encode; +use serde::{Deserialize, Serialize}; + +use sp_runtime::traits::Block as BlockT; + +/// An encoded signed commitment proving that the given header has been finalized. +/// The given bytes should be the SCALE-encoded representation of a +/// `beefy_primitives::SignedCommitment`. +#[derive(Clone, Serialize, Deserialize)] +pub struct SignedCommitment(sp_core::Bytes); + +impl SignedCommitment { + pub fn new( + signed_commitment: beefy_gadget::notification::SignedCommitment, + ) -> Self + where + Block: BlockT, + { + SignedCommitment(signed_commitment.encode().into()) + } +} diff --git a/client/beefy/src/error.rs b/client/beefy/src/error.rs new file mode 100644 index 0000000000000..db532d34c1e3b --- /dev/null +++ b/client/beefy/src/error.rs @@ -0,0 +1,31 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! BEEFY gadget specific errors +//! +//! Used for BEEFY gadget interal error handling only + +use std::fmt::Debug; + +#[derive(Debug, thiserror::Error, PartialEq)] +pub enum Error { + #[error("Keystore error: {0}")] + Keystore(String), + #[error("Signature error: {0}")] + Signature(String), +} diff --git a/client/beefy/src/gossip.rs b/client/beefy/src/gossip.rs new file mode 100644 index 0000000000000..d0199964b6ebf --- /dev/null +++ b/client/beefy/src/gossip.rs @@ -0,0 +1,236 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::{collections::BTreeMap, time::Duration}; + +use sc_network::PeerId; +use sc_network_gossip::{MessageIntent, ValidationResult, Validator, ValidatorContext}; +use sp_core::hashing::twox_64; +use sp_runtime::traits::{Block, Hash, Header, NumberFor}; + +use codec::{Decode, Encode}; +use log::{debug, trace}; +use parking_lot::{Mutex, RwLock}; +use wasm_timer::Instant; + +use beefy_primitives::{ + crypto::{Public, Signature}, + MmrRootHash, VoteMessage, +}; + +use crate::keystore::BeefyKeystore; + +#[cfg(test)] +#[path = "gossip_tests.rs"] +mod tests; + +// Limit BEEFY gossip by keeping only a bound number of voting rounds alive. +const MAX_LIVE_GOSSIP_ROUNDS: usize = 3; + +// Timeout for rebroadcasting messages. +const REBROADCAST_AFTER: Duration = Duration::from_secs(60 * 5); + +/// Gossip engine messages topic +pub(crate) fn topic() -> B::Hash +where + B: Block, +{ + <::Hashing as Hash>::hash(b"beefy") +} + +/// A type that represents hash of the message. +pub type MessageHash = [u8; 8]; + +type KnownVotes = BTreeMap, fnv::FnvHashSet>; + +/// BEEFY gossip validator +/// +/// Validate BEEFY gossip messages and limit the number of live BEEFY voting rounds. +/// +/// Allows messages from last [`MAX_LIVE_GOSSIP_ROUNDS`] to flow, everything else gets +/// rejected/expired. +/// +///All messaging is handled in a single BEEFY global topic. +pub(crate) struct GossipValidator +where + B: Block, +{ + topic: B::Hash, + known_votes: RwLock>, + next_rebroadcast: Mutex, +} + +impl GossipValidator +where + B: Block, +{ + pub fn new() -> GossipValidator { + GossipValidator { + topic: topic::(), + known_votes: RwLock::new(BTreeMap::new()), + next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), + } + } + + /// Note a voting round. + /// + /// Noting `round` will keep `round` live. + /// + /// We retain the [`MAX_LIVE_GOSSIP_ROUNDS`] most **recent** voting rounds as live. + /// As long as a voting round is live, it will be gossiped to peer nodes. + pub(crate) fn note_round(&self, round: NumberFor) { + debug!(target: "beefy", "🥩 About to note round #{}", round); + + let mut live = self.known_votes.write(); + + if !live.contains_key(&round) { + live.insert(round, Default::default()); + } + + if live.len() > MAX_LIVE_GOSSIP_ROUNDS { + let to_remove = live.iter().next().map(|x| x.0).copied(); + if let Some(first) = to_remove { + live.remove(&first); + } + } + } + + fn add_known(known_votes: &mut KnownVotes, round: &NumberFor, hash: MessageHash) { + known_votes.get_mut(round).map(|known| known.insert(hash)); + } + + // Note that we will always keep the most recent unseen round alive. + // + // This is a preliminary fix and the detailed description why we are + // doing this can be found as part of the issue below + // + // https://github.com/paritytech/grandpa-bridge-gadget/issues/237 + // + fn is_live(known_votes: &KnownVotes, round: &NumberFor) -> bool { + let unseen_round = if let Some(max_known_round) = known_votes.keys().last() { + round > max_known_round + } else { + known_votes.is_empty() + }; + + known_votes.contains_key(round) || unseen_round + } + + fn is_known(known_votes: &KnownVotes, round: &NumberFor, hash: &MessageHash) -> bool { + known_votes.get(round).map(|known| known.contains(hash)).unwrap_or(false) + } +} + +impl Validator for GossipValidator +where + B: Block, +{ + fn validate( + &self, + _context: &mut dyn ValidatorContext, + sender: &PeerId, + mut data: &[u8], + ) -> ValidationResult { + if let Ok(msg) = + VoteMessage::, Public, Signature>::decode(&mut data) + { + let msg_hash = twox_64(data); + let round = msg.commitment.block_number; + + // Verify general usefulness of the message. + // We are going to discard old votes right away (without verification) + // Also we keep track of already received votes to avoid verifying duplicates. + { + let known_votes = self.known_votes.read(); + + if !GossipValidator::::is_live(&known_votes, &round) { + return ValidationResult::Discard + } + + if GossipValidator::::is_known(&known_votes, &round, &msg_hash) { + return ValidationResult::ProcessAndKeep(self.topic) + } + } + + if BeefyKeystore::verify(&msg.id, &msg.signature, &msg.commitment.encode()) { + GossipValidator::::add_known(&mut *self.known_votes.write(), &round, msg_hash); + return ValidationResult::ProcessAndKeep(self.topic) + } else { + // TODO: report peer + debug!(target: "beefy", "🥩 Bad signature on message: {:?}, from: {:?}", msg, sender); + } + } + + ValidationResult::Discard + } + + fn message_expired<'a>(&'a self) -> Box bool + 'a> { + let known_votes = self.known_votes.read(); + Box::new(move |_topic, mut data| { + let msg = match VoteMessage::, Public, Signature>::decode( + &mut data, + ) { + Ok(vote) => vote, + Err(_) => return true, + }; + + let round = msg.commitment.block_number; + let expired = !GossipValidator::::is_live(&known_votes, &round); + + trace!(target: "beefy", "🥩 Message for round #{} expired: {}", round, expired); + + expired + }) + } + + fn message_allowed<'a>( + &'a self, + ) -> Box bool + 'a> { + let do_rebroadcast = { + let now = Instant::now(); + let mut next_rebroadcast = self.next_rebroadcast.lock(); + if now >= *next_rebroadcast { + *next_rebroadcast = now + REBROADCAST_AFTER; + true + } else { + false + } + }; + + let known_votes = self.known_votes.read(); + Box::new(move |_who, intent, _topic, mut data| { + if let MessageIntent::PeriodicRebroadcast = intent { + return do_rebroadcast + } + + let msg = match VoteMessage::, Public, Signature>::decode( + &mut data, + ) { + Ok(vote) => vote, + Err(_) => return true, + }; + + let round = msg.commitment.block_number; + let allowed = GossipValidator::::is_live(&known_votes, &round); + + debug!(target: "beefy", "🥩 Message for round #{} allowed: {}", round, allowed); + + allowed + }) + } +} diff --git a/client/beefy/src/gossip_tests.rs b/client/beefy/src/gossip_tests.rs new file mode 100644 index 0000000000000..2d46b873cb7b0 --- /dev/null +++ b/client/beefy/src/gossip_tests.rs @@ -0,0 +1,182 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use sc_keystore::LocalKeystore; +use sc_network_test::Block; +use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; + +use beefy_primitives::{crypto::Signature, Commitment, MmrRootHash, VoteMessage, KEY_TYPE}; + +use crate::keystore::{tests::Keyring, BeefyKeystore}; + +use super::*; + +#[test] +fn note_round_works() { + let gv = GossipValidator::::new(); + + gv.note_round(1u64); + + let live = gv.known_votes.read(); + assert!(GossipValidator::::is_live(&live, &1u64)); + + drop(live); + + gv.note_round(3u64); + gv.note_round(7u64); + gv.note_round(10u64); + + let live = gv.known_votes.read(); + + assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + + assert!(!GossipValidator::::is_live(&live, &1u64)); + assert!(GossipValidator::::is_live(&live, &3u64)); + assert!(GossipValidator::::is_live(&live, &7u64)); + assert!(GossipValidator::::is_live(&live, &10u64)); +} + +#[test] +fn keeps_most_recent_max_rounds() { + let gv = GossipValidator::::new(); + + gv.note_round(3u64); + gv.note_round(7u64); + gv.note_round(10u64); + gv.note_round(1u64); + + let live = gv.known_votes.read(); + + assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + + assert!(GossipValidator::::is_live(&live, &3u64)); + assert!(!GossipValidator::::is_live(&live, &1u64)); + + drop(live); + + gv.note_round(23u64); + gv.note_round(15u64); + gv.note_round(20u64); + gv.note_round(2u64); + + let live = gv.known_votes.read(); + + assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + + assert!(GossipValidator::::is_live(&live, &15u64)); + assert!(GossipValidator::::is_live(&live, &20u64)); + assert!(GossipValidator::::is_live(&live, &23u64)); +} + +#[test] +fn note_same_round_twice() { + let gv = GossipValidator::::new(); + + gv.note_round(3u64); + gv.note_round(7u64); + gv.note_round(10u64); + + let live = gv.known_votes.read(); + + assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + + drop(live); + + // note round #7 again -> should not change anything + gv.note_round(7u64); + + let live = gv.known_votes.read(); + + assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + + assert!(GossipValidator::::is_live(&live, &3u64)); + assert!(GossipValidator::::is_live(&live, &7u64)); + assert!(GossipValidator::::is_live(&live, &10u64)); +} + +struct TestContext; +impl ValidatorContext for TestContext { + fn broadcast_topic(&mut self, _topic: B::Hash, _force: bool) { + todo!() + } + + fn broadcast_message(&mut self, _topic: B::Hash, _message: Vec, _force: bool) { + todo!() + } + + fn send_message(&mut self, _who: &sc_network::PeerId, _message: Vec) { + todo!() + } + + fn send_topic(&mut self, _who: &sc_network::PeerId, _topic: B::Hash, _force: bool) { + todo!() + } +} + +fn sign_commitment( + who: &Keyring, + commitment: &Commitment, +) -> Signature { + let store: SyncCryptoStorePtr = std::sync::Arc::new(LocalKeystore::in_memory()); + SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&who.to_seed())).unwrap(); + let beefy_keystore: BeefyKeystore = Some(store).into(); + + beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() +} + +#[test] +fn should_avoid_verifying_signatures_twice() { + let gv = GossipValidator::::new(); + let sender = sc_network::PeerId::random(); + let mut context = TestContext; + + let commitment = + Commitment { payload: MmrRootHash::default(), block_number: 3_u64, validator_set_id: 0 }; + + let signature = sign_commitment(&Keyring::Alice, &commitment); + + let vote = VoteMessage { commitment, id: Keyring::Alice.public(), signature }; + + gv.note_round(3u64); + gv.note_round(7u64); + gv.note_round(10u64); + + // first time the cache should be populated. + let res = gv.validate(&mut context, &sender, &vote.encode()); + + assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); + assert_eq!(gv.known_votes.read().get(&vote.commitment.block_number).map(|x| x.len()), Some(1)); + + // second time we should hit the cache + let res = gv.validate(&mut context, &sender, &vote.encode()); + + assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); + + // next we should quickly reject if the round is not live. + gv.note_round(11_u64); + gv.note_round(12_u64); + + assert!(!GossipValidator::::is_live( + &*gv.known_votes.read(), + &vote.commitment.block_number + )); + + let res = gv.validate(&mut context, &sender, &vote.encode()); + + assert!(matches!(res, ValidationResult::Discard)); +} diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs new file mode 100644 index 0000000000000..88618b8a5a140 --- /dev/null +++ b/client/beefy/src/keystore.rs @@ -0,0 +1,119 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::convert::{From, TryInto}; + +use sp_application_crypto::RuntimeAppPublic; +use sp_core::keccak_256; +use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; + +use log::warn; + +use beefy_primitives::{ + crypto::{Public, Signature}, + KEY_TYPE, +}; + +use crate::error; + +#[cfg(test)] +#[path = "keystore_tests.rs"] +pub mod tests; + +/// A BEEFY specific keystore implemented as a `Newtype`. This is basically a +/// wrapper around [`sp_keystore::SyncCryptoStore`] and allows to customize +/// common cryptographic functionality. +pub(crate) struct BeefyKeystore(Option); + +impl BeefyKeystore { + /// Check if the keystore contains a private key for one of the public keys + /// contained in `keys`. A public key with a matching private key is known + /// as a local authority id. + /// + /// Return the public key for which we also do have a private key. If no + /// matching private key is found, `None` will be returned. + pub fn authority_id(&self, keys: &[Public]) -> Option { + let store = self.0.clone()?; + + // we do check for multiple private keys as a key store sanity check. + let public: Vec = keys + .iter() + .filter(|k| SyncCryptoStore::has_keys(&*store, &[(k.to_raw_vec(), KEY_TYPE)])) + .cloned() + .collect(); + + if public.len() > 1 { + warn!(target: "beefy", "🥩 Multiple private keys found for: {:?} ({})", public, public.len()); + } + + public.get(0).cloned() + } + + /// Sign `message` with the `public` key. + /// + /// Note that `message` usually will be pre-hashed before being signed. + /// + /// Return the message signature or an error in case of failure. + pub fn sign(&self, public: &Public, message: &[u8]) -> Result { + let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; + + let msg = keccak_256(message); + let public = public.as_ref(); + + let sig = SyncCryptoStore::ecdsa_sign_prehashed(&*store, KEY_TYPE, public, &msg) + .map_err(|e| error::Error::Keystore(e.to_string()))? + .ok_or_else(|| error::Error::Signature("ecdsa_sign_prehashed() failed".to_string()))?; + + // check that `sig` has the expected result type + let sig = sig.clone().try_into().map_err(|_| { + error::Error::Signature(format!("invalid signature {:?} for key {:?}", sig, public)) + })?; + + Ok(sig) + } + + /// Returns a vector of [`beefy_primitives::crypto::Public`] keys which are currently supported + /// (i.e. found in the keystore). + pub fn public_keys(&self) -> Result, error::Error> { + let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; + + let pk: Vec = SyncCryptoStore::ecdsa_public_keys(&*store, KEY_TYPE) + .iter() + .map(|k| Public::from(k.clone())) + .collect(); + + Ok(pk) + } + + /// Use the `public` key to verify that `sig` is a valid signature for `message`. + /// + /// Return `true` if the signature is authentic, `false` otherwise. + pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool { + let msg = keccak_256(message); + let sig = sig.as_ref(); + let public = public.as_ref(); + + sp_core::ecdsa::Pair::verify_prehashed(sig, &msg, public) + } +} + +impl From> for BeefyKeystore { + fn from(store: Option) -> BeefyKeystore { + BeefyKeystore(store) + } +} diff --git a/client/beefy/src/keystore_tests.rs b/client/beefy/src/keystore_tests.rs new file mode 100644 index 0000000000000..99e3e42228df2 --- /dev/null +++ b/client/beefy/src/keystore_tests.rs @@ -0,0 +1,275 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::sync::Arc; + +use sc_keystore::LocalKeystore; +use sp_core::{ecdsa, keccak_256, Pair}; +use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; + +use beefy_primitives::{crypto, KEY_TYPE}; + +use super::BeefyKeystore; +use crate::error::Error; + +/// Set of test accounts using [`beefy_primitives::crypto`] types. +#[allow(missing_docs)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display, strum::EnumIter)] +pub(crate) enum Keyring { + Alice, + Bob, + Charlie, + Dave, + Eve, + Ferdie, + One, + Two, +} + +impl Keyring { + /// Sign `msg`. + pub fn sign(self, msg: &[u8]) -> crypto::Signature { + let msg = keccak_256(msg); + ecdsa::Pair::from(self).sign_prehashed(&msg).into() + } + + /// Return key pair. + pub fn pair(self) -> crypto::Pair { + ecdsa::Pair::from_string(self.to_seed().as_str(), None).unwrap().into() + } + + /// Return public key. + pub fn public(self) -> crypto::Public { + self.pair().public() + } + + /// Return seed string. + pub fn to_seed(self) -> String { + format!("//{}", self) + } +} + +impl From for crypto::Pair { + fn from(k: Keyring) -> Self { + k.pair() + } +} + +impl From for ecdsa::Pair { + fn from(k: Keyring) -> Self { + k.pair().into() + } +} + +fn keystore() -> SyncCryptoStorePtr { + Arc::new(LocalKeystore::in_memory()) +} + +#[test] +fn verify_should_work() { + let msg = keccak_256(b"I am Alice!"); + let sig = Keyring::Alice.sign(b"I am Alice!"); + + assert!(ecdsa::Pair::verify_prehashed( + &sig.clone().into(), + &msg, + &Keyring::Alice.public().into(), + )); + + // different public key -> fail + assert!(!ecdsa::Pair::verify_prehashed( + &sig.clone().into(), + &msg, + &Keyring::Bob.public().into(), + )); + + let msg = keccak_256(b"I am not Alice!"); + + // different msg -> fail + assert!(!ecdsa::Pair::verify_prehashed(&sig.into(), &msg, &Keyring::Alice.public().into(),)); +} + +#[test] +fn pair_works() { + let want = crypto::Pair::from_string("//Alice", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Alice.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Bob", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Bob.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Charlie", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Charlie.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Dave", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Dave.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Eve", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Eve.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Ferdie", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Ferdie.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//One", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::One.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Two", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Two.pair().to_raw_vec(); + assert_eq!(want, got); +} + +#[test] +fn authority_id_works() { + let store = keystore(); + + let alice: crypto::Public = + SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) + .ok() + .unwrap() + .into(); + + let bob = Keyring::Bob.public(); + let charlie = Keyring::Charlie.public(); + + let store: BeefyKeystore = Some(store).into(); + + let mut keys = vec![bob, charlie]; + + let id = store.authority_id(keys.as_slice()); + assert!(id.is_none()); + + keys.push(alice.clone()); + + let id = store.authority_id(keys.as_slice()).unwrap(); + assert_eq!(id, alice); +} + +#[test] +fn sign_works() { + let store = keystore(); + + let alice: crypto::Public = + SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) + .ok() + .unwrap() + .into(); + + let store: BeefyKeystore = Some(store).into(); + + let msg = b"are you involved or commited?"; + + let sig1 = store.sign(&alice, msg).unwrap(); + let sig2 = Keyring::Alice.sign(msg); + + assert_eq!(sig1, sig2); +} + +#[test] +fn sign_error() { + let store = keystore(); + + let _ = SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Bob.to_seed())) + .ok() + .unwrap(); + + let store: BeefyKeystore = Some(store).into(); + + let alice = Keyring::Alice.public(); + + let msg = b"are you involved or commited?"; + let sig = store.sign(&alice, msg).err().unwrap(); + let err = Error::Signature("ecdsa_sign_prehashed() failed".to_string()); + + assert_eq!(sig, err); +} + +#[test] +fn sign_no_keystore() { + let store: BeefyKeystore = None.into(); + + let alice = Keyring::Alice.public(); + let msg = b"are you involved or commited"; + + let sig = store.sign(&alice, msg).err().unwrap(); + let err = Error::Keystore("no Keystore".to_string()); + assert_eq!(sig, err); +} + +#[test] +fn verify_works() { + let store = keystore(); + + let alice: crypto::Public = + SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) + .ok() + .unwrap() + .into(); + + let store: BeefyKeystore = Some(store).into(); + + // `msg` and `sig` match + let msg = b"are you involved or commited?"; + let sig = store.sign(&alice, msg).unwrap(); + assert!(BeefyKeystore::verify(&alice, &sig, msg)); + + // `msg and `sig` don't match + let msg = b"you are just involved"; + assert!(!BeefyKeystore::verify(&alice, &sig, msg)); +} + +// Note that we use keys with and without a seed for this test. +#[test] +fn public_keys_works() { + const TEST_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"test"); + + let store = keystore(); + + let add_key = |key_type, seed: Option<&str>| { + SyncCryptoStore::ecdsa_generate_new(&*store, key_type, seed).unwrap() + }; + + // test keys + let _ = add_key(TEST_TYPE, Some(Keyring::Alice.to_seed().as_str())); + let _ = add_key(TEST_TYPE, Some(Keyring::Bob.to_seed().as_str())); + + let _ = add_key(TEST_TYPE, None); + let _ = add_key(TEST_TYPE, None); + + // BEEFY keys + let _ = add_key(KEY_TYPE, Some(Keyring::Dave.to_seed().as_str())); + let _ = add_key(KEY_TYPE, Some(Keyring::Eve.to_seed().as_str())); + + let key1: crypto::Public = add_key(KEY_TYPE, None).into(); + let key2: crypto::Public = add_key(KEY_TYPE, None).into(); + + let store: BeefyKeystore = Some(store).into(); + + let keys = store.public_keys().ok().unwrap(); + + assert!(keys.len() == 4); + assert!(keys.contains(&Keyring::Dave.public())); + assert!(keys.contains(&Keyring::Eve.public())); + assert!(keys.contains(&key1)); + assert!(keys.contains(&key2)); +} diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs new file mode 100644 index 0000000000000..b2372b2a6c518 --- /dev/null +++ b/client/beefy/src/lib.rs @@ -0,0 +1,159 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::sync::Arc; + +use log::debug; +use prometheus::Registry; + +use sc_client_api::{Backend, BlockchainEvents, Finalizer}; +use sc_network_gossip::{GossipEngine, Network as GossipNetwork}; + +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_keystore::SyncCryptoStorePtr; +use sp_runtime::traits::Block; + +use beefy_primitives::BeefyApi; + +mod error; +mod gossip; +mod keystore; +mod metrics; +mod round; +mod worker; + +pub mod notification; + +pub const BEEFY_PROTOCOL_NAME: &str = "/paritytech/beefy/1"; + +/// Returns the configuration value to put in +/// [`sc_network::config::NetworkConfiguration::extra_sets`]. +pub fn beefy_peers_set_config() -> sc_network::config::NonDefaultSetConfig { + let mut cfg = + sc_network::config::NonDefaultSetConfig::new(BEEFY_PROTOCOL_NAME.into(), 1024 * 1024); + cfg.allow_non_reserved(25, 25); + cfg +} + +/// A convenience BEEFY client trait that defines all the type bounds a BEEFY client +/// has to satisfy. Ideally that should actually be a trait alias. Unfortunately as +/// of today, Rust does not allow a type alias to be used as a trait bound. Tracking +/// issue is . +pub trait Client: + BlockchainEvents + HeaderBackend + Finalizer + ProvideRuntimeApi + Send + Sync +where + B: Block, + BE: Backend, +{ + // empty +} + +impl Client for T +where + B: Block, + BE: Backend, + T: BlockchainEvents + + HeaderBackend + + Finalizer + + ProvideRuntimeApi + + Send + + Sync, +{ + // empty +} + +/// BEEFY gadget initialization parameters. +pub struct BeefyParams +where + B: Block, + BE: Backend, + C: Client, + C::Api: BeefyApi, + N: GossipNetwork + Clone + Send + 'static, +{ + /// BEEFY client + pub client: Arc, + /// Client Backend + pub backend: Arc, + /// Local key store + pub key_store: Option, + /// Gossip network + pub network: N, + /// BEEFY signed commitment sender + pub signed_commitment_sender: notification::BeefySignedCommitmentSender, + /// Minimal delta between blocks, BEEFY should vote for + pub min_block_delta: u32, + /// Prometheus metric registry + pub prometheus_registry: Option, +} + +/// Start the BEEFY gadget. +/// +/// This is a thin shim around running and awaiting a BEEFY worker. +pub async fn start_beefy_gadget(beefy_params: BeefyParams) +where + B: Block, + BE: Backend, + C: Client, + C::Api: BeefyApi, + N: GossipNetwork + Clone + Send + 'static, +{ + let BeefyParams { + client, + backend, + key_store, + network, + signed_commitment_sender, + min_block_delta, + prometheus_registry, + } = beefy_params; + + let gossip_validator = Arc::new(gossip::GossipValidator::new()); + let gossip_engine = + GossipEngine::new(network, BEEFY_PROTOCOL_NAME, gossip_validator.clone(), None); + + let metrics = + prometheus_registry.as_ref().map(metrics::Metrics::register).and_then( + |result| match result { + Ok(metrics) => { + debug!(target: "beefy", "🥩 Registered metrics"); + Some(metrics) + }, + Err(err) => { + debug!(target: "beefy", "🥩 Failed to register metrics: {:?}", err); + None + }, + }, + ); + + let worker_params = worker::WorkerParams { + client, + backend, + key_store: key_store.into(), + signed_commitment_sender, + gossip_engine, + gossip_validator, + min_block_delta, + metrics, + }; + + let worker = worker::BeefyWorker::<_, _, _>::new(worker_params); + + worker.run().await +} diff --git a/client/beefy/src/metrics.rs b/client/beefy/src/metrics.rs new file mode 100644 index 0000000000000..0fdc29f97c37a --- /dev/null +++ b/client/beefy/src/metrics.rs @@ -0,0 +1,93 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! BEEFY Prometheus metrics definition + +use prometheus::{register, Counter, Gauge, PrometheusError, Registry, U64}; + +/// BEEFY metrics exposed through Prometheus +pub(crate) struct Metrics { + /// Current active validator set id + pub beefy_validator_set_id: Gauge, + /// Total number of votes sent by this node + pub beefy_votes_sent: Counter, + /// Most recent concluded voting round + pub beefy_round_concluded: Gauge, + /// Best block finalized by BEEFY + pub beefy_best_block: Gauge, + /// Next block BEEFY should vote on + pub beefy_should_vote_on: Gauge, + /// Number of sessions without a signed commitment + pub beefy_skipped_sessions: Counter, +} + +impl Metrics { + pub(crate) fn register(registry: &Registry) -> Result { + Ok(Self { + beefy_validator_set_id: register( + Gauge::new("beefy_validator_set_id", "Current BEEFY active validator set id.")?, + registry, + )?, + beefy_votes_sent: register( + Counter::new("beefy_votes_sent", "Number of votes sent by this node")?, + registry, + )?, + beefy_round_concluded: register( + Gauge::new("beefy_round_concluded", "Voting round, that has been concluded")?, + registry, + )?, + beefy_best_block: register( + Gauge::new("beefy_best_block", "Best block finalized by BEEFY")?, + registry, + )?, + beefy_should_vote_on: register( + Gauge::new("beefy_should_vote_on", "Next block, BEEFY should vote on")?, + registry, + )?, + beefy_skipped_sessions: register( + Counter::new( + "beefy_skipped_sessions", + "Number of sessions without a signed commitment", + )?, + registry, + )?, + }) + } +} + +// Note: we use the `format` macro to convert an expr into a `u64`. This will fail, +// if expr does not derive `Display`. +#[macro_export] +macro_rules! metric_set { + ($self:ident, $m:ident, $v:expr) => {{ + let val: u64 = format!("{}", $v).parse().unwrap(); + + if let Some(metrics) = $self.metrics.as_ref() { + metrics.$m.set(val); + } + }}; +} + +#[macro_export] +macro_rules! metric_inc { + ($self:ident, $m:ident) => {{ + if let Some(metrics) = $self.metrics.as_ref() { + metrics.$m.inc(); + } + }}; +} diff --git a/client/beefy/src/notification.rs b/client/beefy/src/notification.rs new file mode 100644 index 0000000000000..6099c9681447b --- /dev/null +++ b/client/beefy/src/notification.rs @@ -0,0 +1,113 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::sync::Arc; + +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; +use sp_runtime::traits::{Block, NumberFor}; + +use parking_lot::Mutex; + +/// Stream of signed commitments returned when subscribing. +pub type SignedCommitment = + beefy_primitives::SignedCommitment, beefy_primitives::MmrRootHash>; + +/// Stream of signed commitments returned when subscribing. +type SignedCommitmentStream = TracingUnboundedReceiver>; + +/// Sending endpoint for notifying about signed commitments. +type SignedCommitmentSender = TracingUnboundedSender>; + +/// Collection of channel sending endpoints shared with the receiver side so they can register +/// themselves. +type SharedSignedCommitmentSenders = Arc>>>; + +/// The sending half of the signed commitment channel(s). +/// +/// Used to send notifications about signed commitments generated at the end of a BEEFY round. +#[derive(Clone)] +pub struct BeefySignedCommitmentSender +where + B: Block, +{ + subscribers: SharedSignedCommitmentSenders, +} + +impl BeefySignedCommitmentSender +where + B: Block, +{ + /// The `subscribers` should be shared with a corresponding `SignedCommitmentSender`. + fn new(subscribers: SharedSignedCommitmentSenders) -> Self { + Self { subscribers } + } + + /// Send out a notification to all subscribers that a new signed commitment is available for a + /// block. + pub fn notify(&self, signed_commitment: SignedCommitment) { + let mut subscribers = self.subscribers.lock(); + + // do an initial prune on closed subscriptions + subscribers.retain(|n| !n.is_closed()); + + if !subscribers.is_empty() { + subscribers.retain(|n| n.unbounded_send(signed_commitment.clone()).is_ok()); + } + } +} + +/// The receiving half of the signed commitments channel. +/// +/// Used to receive notifications about signed commitments generated at the end of a BEEFY round. +/// The `BeefySignedCommitmentStream` entity stores the `SharedSignedCommitmentSenders` so it can be +/// used to add more subscriptions. +#[derive(Clone)] +pub struct BeefySignedCommitmentStream +where + B: Block, +{ + subscribers: SharedSignedCommitmentSenders, +} + +impl BeefySignedCommitmentStream +where + B: Block, +{ + /// Creates a new pair of receiver and sender of signed commitment notifications. + pub fn channel() -> (BeefySignedCommitmentSender, Self) { + let subscribers = Arc::new(Mutex::new(vec![])); + let receiver = BeefySignedCommitmentStream::new(subscribers.clone()); + let sender = BeefySignedCommitmentSender::new(subscribers); + (sender, receiver) + } + + /// Create a new receiver of signed commitment notifications. + /// + /// The `subscribers` should be shared with a corresponding `BeefySignedCommitmentSender`. + fn new(subscribers: SharedSignedCommitmentSenders) -> Self { + Self { subscribers } + } + + /// Subscribe to a channel through which signed commitments are sent at the end of each BEEFY + /// voting round. + pub fn subscribe(&self) -> SignedCommitmentStream { + let (sender, receiver) = tracing_unbounded("mpsc_signed_commitments_notification_stream"); + self.subscribers.lock().push(sender); + receiver + } +} diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs new file mode 100644 index 0000000000000..7d443603b364e --- /dev/null +++ b/client/beefy/src/round.rs @@ -0,0 +1,121 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::{collections::BTreeMap, hash::Hash}; + +use log::{debug, trace}; + +use beefy_primitives::{ + crypto::{Public, Signature}, + ValidatorSet, ValidatorSetId, +}; +use sp_arithmetic::traits::AtLeast32BitUnsigned; +use sp_runtime::traits::MaybeDisplay; + +#[derive(Default)] +struct RoundTracker { + votes: Vec<(Public, Signature)>, +} + +impl RoundTracker { + fn add_vote(&mut self, vote: (Public, Signature)) -> bool { + // this needs to handle equivocations in the future + if self.votes.contains(&vote) { + return false + } + + self.votes.push(vote); + true + } + + fn is_done(&self, threshold: usize) -> bool { + self.votes.len() >= threshold + } +} + +fn threshold(authorities: usize) -> usize { + let faulty = authorities.saturating_sub(1) / 3; + authorities - faulty +} + +pub(crate) struct Rounds { + rounds: BTreeMap<(Hash, Number), RoundTracker>, + validator_set: ValidatorSet, +} + +impl Rounds +where + H: Ord + Hash, + N: Ord + AtLeast32BitUnsigned + MaybeDisplay, +{ + pub(crate) fn new(validator_set: ValidatorSet) -> Self { + Rounds { rounds: BTreeMap::new(), validator_set } + } +} + +impl Rounds +where + H: Ord + Hash, + N: Ord + AtLeast32BitUnsigned + MaybeDisplay, +{ + pub(crate) fn validator_set_id(&self) -> ValidatorSetId { + self.validator_set.id + } + + pub(crate) fn validators(&self) -> Vec { + self.validator_set.validators.clone() + } + + pub(crate) fn add_vote(&mut self, round: (H, N), vote: (Public, Signature)) -> bool { + self.rounds.entry(round).or_default().add_vote(vote) + } + + pub(crate) fn is_done(&self, round: &(H, N)) -> bool { + let done = self + .rounds + .get(round) + .map(|tracker| tracker.is_done(threshold(self.validator_set.validators.len()))) + .unwrap_or(false); + + debug!(target: "beefy", "🥩 Round #{} done: {}", round.1, done); + + done + } + + pub(crate) fn drop(&mut self, round: &(H, N)) -> Option>> { + trace!(target: "beefy", "🥩 About to drop round #{}", round.1); + + let signatures = self.rounds.remove(round)?.votes; + + Some( + self.validator_set + .validators + .iter() + .map(|authority_id| { + signatures.iter().find_map(|(id, sig)| { + if id == authority_id { + Some(sig.clone()) + } else { + None + } + }) + }) + .collect(), + ) + } +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs new file mode 100644 index 0000000000000..3f52686930332 --- /dev/null +++ b/client/beefy/src/worker.rs @@ -0,0 +1,534 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::{collections::BTreeSet, fmt::Debug, marker::PhantomData, sync::Arc}; + +use codec::{Codec, Decode, Encode}; +use futures::{future, FutureExt, StreamExt}; +use log::{debug, error, info, trace, warn}; +use parking_lot::Mutex; + +use sc_client_api::{Backend, FinalityNotification, FinalityNotifications}; +use sc_network_gossip::GossipEngine; + +use sp_api::BlockId; +use sp_arithmetic::traits::AtLeast32Bit; +use sp_runtime::{ + generic::OpaqueDigestItemId, + traits::{Block, Header, NumberFor}, + SaturatedConversion, +}; + +use beefy_primitives::{ + crypto::{AuthorityId, Public, Signature}, + BeefyApi, Commitment, ConsensusLog, MmrRootHash, SignedCommitment, ValidatorSet, + VersionedCommitment, VoteMessage, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, +}; + +use crate::{ + error, + gossip::{topic, GossipValidator}, + keystore::BeefyKeystore, + metric_inc, metric_set, + metrics::Metrics, + notification, round, Client, +}; + +pub(crate) struct WorkerParams +where + B: Block, +{ + pub client: Arc, + pub backend: Arc, + pub key_store: BeefyKeystore, + pub signed_commitment_sender: notification::BeefySignedCommitmentSender, + pub gossip_engine: GossipEngine, + pub gossip_validator: Arc>, + pub min_block_delta: u32, + pub metrics: Option, +} + +/// A BEEFY worker plays the BEEFY protocol +pub(crate) struct BeefyWorker +where + B: Block, + BE: Backend, + C: Client, +{ + client: Arc, + backend: Arc, + key_store: BeefyKeystore, + signed_commitment_sender: notification::BeefySignedCommitmentSender, + gossip_engine: Arc>>, + gossip_validator: Arc>, + /// Min delta in block numbers between two blocks, BEEFY should vote on + min_block_delta: u32, + metrics: Option, + rounds: round::Rounds>, + finality_notifications: FinalityNotifications, + /// Best block we received a GRANDPA notification for + best_grandpa_block: NumberFor, + /// Best block a BEEFY voting round has been concluded for + best_beefy_block: Option>, + /// Validator set id for the last signed commitment + last_signed_id: u64, + // keep rustc happy + _backend: PhantomData, +} + +impl BeefyWorker +where + B: Block + Codec, + BE: Backend, + C: Client, + C::Api: BeefyApi, +{ + /// Return a new BEEFY worker instance. + /// + /// Note that a BEEFY worker is only fully functional if a corresponding + /// BEEFY pallet has been deployed on-chain. + /// + /// The BEEFY pallet is needed in order to keep track of the BEEFY authority set. + pub(crate) fn new(worker_params: WorkerParams) -> Self { + let WorkerParams { + client, + backend, + key_store, + signed_commitment_sender, + gossip_engine, + gossip_validator, + min_block_delta, + metrics, + } = worker_params; + + BeefyWorker { + client: client.clone(), + backend, + key_store, + signed_commitment_sender, + gossip_engine: Arc::new(Mutex::new(gossip_engine)), + gossip_validator, + min_block_delta, + metrics, + rounds: round::Rounds::new(ValidatorSet::empty()), + finality_notifications: client.finality_notification_stream(), + best_grandpa_block: client.info().finalized_number, + best_beefy_block: None, + last_signed_id: 0, + _backend: PhantomData, + } + } +} + +impl BeefyWorker +where + B: Block, + BE: Backend, + C: Client, + C::Api: BeefyApi, +{ + /// Return `true`, if we should vote on block `number` + fn should_vote_on(&self, number: NumberFor) -> bool { + let best_beefy_block = if let Some(block) = self.best_beefy_block { + block + } else { + debug!(target: "beefy", "🥩 Missing best BEEFY block - won't vote for: {:?}", number); + return false + }; + + let target = vote_target(self.best_grandpa_block, best_beefy_block, self.min_block_delta); + + trace!(target: "beefy", "🥩 should_vote_on: #{:?}, next_block_to_vote_on: #{:?}", number, target); + + metric_set!(self, beefy_should_vote_on, target); + + number == target + } + + /// Return the current active validator set at header `header`. + /// + /// Note that the validator set could be `None`. This is the case if we don't find + /// a BEEFY authority set change and we can't fetch the authority set from the + /// BEEFY on-chain state. + /// + /// Such a failure is usually an indication that the BEEFY pallet has not been deployed (yet). + fn validator_set(&self, header: &B::Header) -> Option> { + let new = if let Some(new) = find_authorities_change::(header) { + Some(new) + } else { + let at = BlockId::hash(header.hash()); + self.client.runtime_api().validator_set(&at).ok() + }; + + trace!(target: "beefy", "🥩 active validator set: {:?}", new); + + new + } + + /// Verify `active` validator set for `block` against the key store + /// + /// The critical case is, if we do have a public key in the key store which is not + /// part of the active validator set. + /// + /// Note that for a non-authority node there will be no keystore, and we will + /// return an error and don't check. The error can usually be ignored. + fn verify_validator_set( + &self, + block: &NumberFor, + mut active: ValidatorSet, + ) -> Result<(), error::Error> { + let active: BTreeSet = active.validators.drain(..).collect(); + + let store: BTreeSet = self.key_store.public_keys()?.drain(..).collect(); + + let missing: Vec<_> = store.difference(&active).cloned().collect(); + + if !missing.is_empty() { + debug!(target: "beefy", "🥩 for block {:?} public key missing in validator set: {:?}", block, missing); + } + + Ok(()) + } + + fn handle_finality_notification(&mut self, notification: FinalityNotification) { + trace!(target: "beefy", "🥩 Finality notification: {:?}", notification); + + // update best GRANDPA finalized block we have seen + self.best_grandpa_block = *notification.header.number(); + + if let Some(active) = self.validator_set(¬ification.header) { + // Authority set change or genesis set id triggers new voting rounds + // + // TODO: (adoerr) Enacting a new authority set will also implicitly 'conclude' + // the currently active BEEFY voting round by starting a new one. This is + // temporary and needs to be replaced by proper round life cycle handling. + if active.id != self.rounds.validator_set_id() || + (active.id == GENESIS_AUTHORITY_SET_ID && self.best_beefy_block.is_none()) + { + debug!(target: "beefy", "🥩 New active validator set id: {:?}", active); + metric_set!(self, beefy_validator_set_id, active.id); + + // BEEFY should produce a signed commitment for each session + if active.id != self.last_signed_id + 1 && active.id != GENESIS_AUTHORITY_SET_ID { + metric_inc!(self, beefy_skipped_sessions); + } + + // verify the new validator set + let _ = self.verify_validator_set(notification.header.number(), active.clone()); + + self.rounds = round::Rounds::new(active.clone()); + + debug!(target: "beefy", "🥩 New Rounds for id: {:?}", active.id); + + self.best_beefy_block = Some(*notification.header.number()); + + // this metric is kind of 'fake'. Best BEEFY block should only be updated once we + // have a signed commitment for the block. Remove once the above TODO is done. + metric_set!(self, beefy_best_block, *notification.header.number()); + } + } + + if self.should_vote_on(*notification.header.number()) { + let authority_id = if let Some(id) = + self.key_store.authority_id(self.rounds.validators().as_slice()) + { + debug!(target: "beefy", "🥩 Local authority id: {:?}", id); + id + } else { + debug!(target: "beefy", "🥩 Missing validator id - can't vote for: {:?}", notification.header.hash()); + return + }; + + let mmr_root = + if let Some(hash) = find_mmr_root_digest::(¬ification.header) { + hash + } else { + warn!(target: "beefy", "🥩 No MMR root digest found for: {:?}", notification.header.hash()); + return + }; + + let commitment = Commitment { + payload: mmr_root, + block_number: notification.header.number(), + validator_set_id: self.rounds.validator_set_id(), + }; + let encoded_commitment = commitment.encode(); + + let signature = match self.key_store.sign(&authority_id, &*encoded_commitment) { + Ok(sig) => sig, + Err(err) => { + warn!(target: "beefy", "🥩 Error signing commitment: {:?}", err); + return + }, + }; + + trace!( + target: "beefy", + "🥩 Produced signature using {:?}, is_valid: {:?}", + authority_id, + BeefyKeystore::verify(&authority_id, &signature, &*encoded_commitment) + ); + + let message = VoteMessage { commitment, id: authority_id, signature }; + + let encoded_message = message.encode(); + + metric_inc!(self, beefy_votes_sent); + + debug!(target: "beefy", "🥩 Sent vote message: {:?}", message); + + self.handle_vote( + (message.commitment.payload, *message.commitment.block_number), + (message.id, message.signature), + ); + + self.gossip_engine.lock().gossip_message(topic::(), encoded_message, false); + } + } + + fn handle_vote(&mut self, round: (MmrRootHash, NumberFor), vote: (Public, Signature)) { + self.gossip_validator.note_round(round.1); + + let vote_added = self.rounds.add_vote(round, vote); + + if vote_added && self.rounds.is_done(&round) { + if let Some(signatures) = self.rounds.drop(&round) { + // id is stored for skipped session metric calculation + self.last_signed_id = self.rounds.validator_set_id(); + + let commitment = Commitment { + payload: round.0, + block_number: round.1, + validator_set_id: self.last_signed_id, + }; + + let signed_commitment = SignedCommitment { commitment, signatures }; + + metric_set!(self, beefy_round_concluded, round.1); + + info!(target: "beefy", "🥩 Round #{} concluded, committed: {:?}.", round.1, signed_commitment); + + if self + .backend + .append_justification( + BlockId::Number(round.1), + ( + BEEFY_ENGINE_ID, + VersionedCommitment::V1(signed_commitment.clone()).encode(), + ), + ) + .is_err() + { + // just a trace, because until the round lifecycle is improved, we will + // conclude certain rounds multiple times. + trace!(target: "beefy", "🥩 Failed to append justification: {:?}", signed_commitment); + } + + self.signed_commitment_sender.notify(signed_commitment); + self.best_beefy_block = Some(round.1); + + metric_set!(self, beefy_best_block, round.1); + } + } + } + + pub(crate) async fn run(mut self) { + let mut votes = Box::pin(self.gossip_engine.lock().messages_for(topic::()).filter_map( + |notification| async move { + debug!(target: "beefy", "🥩 Got vote message: {:?}", notification); + + VoteMessage::, Public, Signature>::decode( + &mut ¬ification.message[..], + ) + .ok() + }, + )); + + loop { + let engine = self.gossip_engine.clone(); + let gossip_engine = future::poll_fn(|cx| engine.lock().poll_unpin(cx)); + + futures::select! { + notification = self.finality_notifications.next().fuse() => { + if let Some(notification) = notification { + self.handle_finality_notification(notification); + } else { + return; + } + }, + vote = votes.next().fuse() => { + if let Some(vote) = vote { + self.handle_vote( + (vote.commitment.payload, vote.commitment.block_number), + (vote.id, vote.signature), + ); + } else { + return; + } + }, + _ = gossip_engine.fuse() => { + error!(target: "beefy", "🥩 Gossip engine has terminated."); + return; + } + } + } + } +} + +/// Extract the MMR root hash from a digest in the given header, if it exists. +fn find_mmr_root_digest(header: &B::Header) -> Option +where + B: Block, + Id: Codec, +{ + header.digest().logs().iter().find_map(|log| { + match log.try_to::>(OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID)) { + Some(ConsensusLog::MmrRoot(root)) => Some(root), + _ => None, + } + }) +} + +/// Scan the `header` digest log for a BEEFY validator set change. Return either the new +/// validator set or `None` in case no validator set change has been signaled. +fn find_authorities_change(header: &B::Header) -> Option> +where + B: Block, +{ + let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); + + let filter = |log: ConsensusLog| match log { + ConsensusLog::AuthoritiesChange(validator_set) => Some(validator_set), + _ => None, + }; + + header.digest().convert_first(|l| l.try_to(id).and_then(filter)) +} + +/// Calculate next block number to vote on +fn vote_target(best_grandpa: N, best_beefy: N, min_delta: u32) -> N +where + N: AtLeast32Bit + Copy + Debug, +{ + let diff = best_grandpa.saturating_sub(best_beefy); + let diff = diff.saturated_into::(); + let target = best_beefy + min_delta.max(diff.next_power_of_two()).into(); + + trace!( + target: "beefy", + "🥩 vote target - diff: {:?}, next_power_of_two: {:?}, target block: #{:?}", + diff, + diff.next_power_of_two(), + target, + ); + + target +} + +#[cfg(test)] +mod tests { + use super::vote_target; + + #[test] + fn vote_on_min_block_delta() { + let t = vote_target(1u32, 0, 4); + assert_eq!(4, t); + let t = vote_target(2u32, 0, 4); + assert_eq!(4, t); + let t = vote_target(3u32, 0, 4); + assert_eq!(4, t); + let t = vote_target(4u32, 0, 4); + assert_eq!(4, t); + + let t = vote_target(4u32, 4, 4); + assert_eq!(8, t); + + let t = vote_target(10u32, 10, 4); + assert_eq!(14, t); + let t = vote_target(11u32, 10, 4); + assert_eq!(14, t); + let t = vote_target(12u32, 10, 4); + assert_eq!(14, t); + let t = vote_target(13u32, 10, 4); + assert_eq!(14, t); + + let t = vote_target(10u32, 10, 8); + assert_eq!(18, t); + let t = vote_target(11u32, 10, 8); + assert_eq!(18, t); + let t = vote_target(12u32, 10, 8); + assert_eq!(18, t); + let t = vote_target(13u32, 10, 8); + assert_eq!(18, t); + } + + #[test] + fn vote_on_power_of_two() { + let t = vote_target(1008u32, 1000, 4); + assert_eq!(1008, t); + + let t = vote_target(1016u32, 1000, 4); + assert_eq!(1016, t); + + let t = vote_target(1032u32, 1000, 4); + assert_eq!(1032, t); + + let t = vote_target(1064u32, 1000, 4); + assert_eq!(1064, t); + + let t = vote_target(1128u32, 1000, 4); + assert_eq!(1128, t); + + let t = vote_target(1256u32, 1000, 4); + assert_eq!(1256, t); + + let t = vote_target(1512u32, 1000, 4); + assert_eq!(1512, t); + + let t = vote_target(1024u32, 0, 4); + assert_eq!(1024, t); + } + + #[test] + fn vote_on_target_block() { + let t = vote_target(1008u32, 1002, 4); + assert_eq!(1010, t); + let t = vote_target(1010u32, 1002, 4); + assert_eq!(1010, t); + + let t = vote_target(1016u32, 1006, 4); + assert_eq!(1022, t); + let t = vote_target(1022u32, 1006, 4); + assert_eq!(1022, t); + + let t = vote_target(1032u32, 1012, 4); + assert_eq!(1044, t); + let t = vote_target(1044u32, 1012, 4); + assert_eq!(1044, t); + + let t = vote_target(1064u32, 1014, 4); + assert_eq!(1078, t); + let t = vote_target(1078u32, 1014, 4); + assert_eq!(1078, t); + + let t = vote_target(1128u32, 1008, 4); + assert_eq!(1136, t); + let t = vote_target(1136u32, 1008, 4); + assert_eq!(1136, t); + } +} diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml new file mode 100644 index 0000000000000..3d4a9a72ddf86 --- /dev/null +++ b/frame/beefy-mmr/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "pallet-beefy-mmr" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +description = "BEEFY + MMR runtime utilities" + +[dependencies] +hex = { version = "0.4", optional = true } +codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } +libsecp256k1 = { version = "0.7.0", default-features = false } +log = { version = "0.4.13", default-features = false } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +serde = { version = "1.0.130", optional = true } + +frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } +frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } +pallet-mmr = { version = "4.0.0-dev", path = "../merkle-mountain-range", default-features = false } +pallet-mmr-primitives = { version = "4.0.0-dev", path = "../merkle-mountain-range/primitives", default-features = false } +pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } + +sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } +sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } +sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } +sp-std = { version = "4.0.0-dev", path = "../../primitives/std", default-features = false } + +beefy-merkle-tree = { version = "4.0.0-dev", path = "./primitives", default-features = false } +beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", default-features = false } +pallet-beefy = { version = "4.0.0-dev", path = "../beefy", default-features = false } + +[dev-dependencies] +sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } +hex-literal = "0.3" + +[features] +default = ["std"] +std = [ + "beefy-merkle-tree/std", + "beefy-primitives/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "hex", + "libsecp256k1/std", + "log/std", + "pallet-beefy/std", + "pallet-mmr-primitives/std", + "pallet-mmr/std", + "pallet-session/std", + "serde", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/frame/beefy-mmr/primitives/Cargo.toml new file mode 100644 index 0000000000000..d5dcc0eed3350 --- /dev/null +++ b/frame/beefy-mmr/primitives/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "beefy-merkle-tree" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +description = "A no-std/Substrate compatible library to construct binary merkle tree." + +[dependencies] +hex = { version = "0.4", optional = true, default-features = false } +log = { version = "0.4", optional = true, default-features = false } +tiny-keccak = { version = "2.0.2", features = ["keccak"], optional = true } + +[dev-dependencies] +env_logger = "0.9" +hex = "0.4" +hex-literal = "0.3" + +[features] +debug = ["hex", "log"] +default = ["std", "debug", "keccak"] +keccak = ["tiny-keccak"] +std = [] diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/frame/beefy-mmr/primitives/src/lib.rs new file mode 100644 index 0000000000000..4d4d4e8721ac8 --- /dev/null +++ b/frame/beefy-mmr/primitives/src/lib.rs @@ -0,0 +1,806 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] + +//! This crate implements a simple binary Merkle Tree utilities required for inter-op with Ethereum +//! bridge & Solidity contract. +//! +//! The implementation is optimised for usage within Substrate Runtime and supports no-std +//! compilation targets. +//! +//! Merkle Tree is constructed from arbitrary-length leaves, that are initially hashed using the +//! same [Hasher] as the inner nodes. +//! Inner nodes are created by concatenating child hashes and hashing again. The implementation +//! does not perform any sorting of the input data (leaves) nor when inner nodes are created. +//! +//! If the number of leaves is not even, last leave (hash of) is promoted to the upper layer. + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +/// Supported hashing output size. +/// +/// The size is restricted to 32 bytes to allow for a more optimised implementation. +pub type Hash = [u8; 32]; + +/// Generic hasher trait. +/// +/// Implement the function to support custom way of hashing data. +/// The implementation must return a [Hash] type, so only 32-byte output hashes are supported. +pub trait Hasher { + /// Hash given arbitrary-length piece of data. + fn hash(data: &[u8]) -> Hash; +} + +#[cfg(feature = "keccak")] +mod keccak256 { + use tiny_keccak::{Hasher as _, Keccak}; + + /// Keccak256 hasher implementation. + pub struct Keccak256; + impl Keccak256 { + /// Hash given data. + pub fn hash(data: &[u8]) -> super::Hash { + ::hash(data) + } + } + impl super::Hasher for Keccak256 { + fn hash(data: &[u8]) -> super::Hash { + let mut keccak = Keccak::v256(); + keccak.update(data); + let mut output = [0_u8; 32]; + keccak.finalize(&mut output); + output + } + } +} +#[cfg(feature = "keccak")] +pub use keccak256::Keccak256; + +/// Construct a root hash of a Binary Merkle Tree created from given leaves. +/// +/// See crate-level docs for details about Merkle Tree construction. +/// +/// In case an empty list of leaves is passed the function returns a 0-filled hash. +pub fn merkle_root(leaves: I) -> Hash +where + H: Hasher, + I: IntoIterator, + T: AsRef<[u8]>, +{ + let iter = leaves.into_iter().map(|l| H::hash(l.as_ref())); + merkelize::(iter, &mut ()) +} + +fn merkelize(leaves: I, visitor: &mut V) -> Hash +where + H: Hasher, + V: Visitor, + I: Iterator, +{ + let upper = Vec::with_capacity(leaves.size_hint().0); + let mut next = match merkelize_row::(leaves, upper, visitor) { + Ok(root) => return root, + Err(next) if next.is_empty() => return Hash::default(), + Err(next) => next, + }; + + let mut upper = Vec::with_capacity((next.len() + 1) / 2); + loop { + visitor.move_up(); + + match merkelize_row::(next.drain(..), upper, visitor) { + Ok(root) => return root, + Err(t) => { + // swap collections to avoid allocations + upper = next; + next = t; + }, + }; + } +} + +/// A generated merkle proof. +/// +/// The structure contains all necessary data to later on verify the proof and the leaf itself. +#[derive(Debug, PartialEq, Eq)] +pub struct MerkleProof { + /// Root hash of generated merkle tree. + pub root: Hash, + /// Proof items (does not contain the leaf hash, nor the root obviously). + /// + /// This vec contains all inner node hashes necessary to reconstruct the root hash given the + /// leaf hash. + pub proof: Vec, + /// Number of leaves in the original tree. + /// + /// This is needed to detect a case where we have an odd number of leaves that "get promoted" + /// to upper layers. + pub number_of_leaves: usize, + /// Index of the leaf the proof is for (0-based). + pub leaf_index: usize, + /// Leaf content. + pub leaf: T, +} + +/// A trait of object inspecting merkle root creation. +/// +/// It can be passed to [`merkelize_row`] or [`merkelize`] functions and will be notified +/// about tree traversal. +trait Visitor { + /// We are moving one level up in the tree. + fn move_up(&mut self); + + /// We are creating an inner node from given `left` and `right` nodes. + /// + /// Note that in case of last odd node in the row `right` might be empty. + /// The method will also visit the `root` hash (level 0). + /// + /// The `index` is an index of `left` item. + fn visit(&mut self, index: usize, left: &Option, right: &Option); +} + +/// No-op implementation of the visitor. +impl Visitor for () { + fn move_up(&mut self) {} + fn visit(&mut self, _index: usize, _left: &Option, _right: &Option) {} +} + +/// Construct a Merkle Proof for leaves given by indices. +/// +/// The function constructs a (partial) Merkle Tree first and stores all elements required +/// to prove requested item (leaf) given the root hash. +/// +/// Both the Proof and the Root Hash is returned. +/// +/// # Panic +/// +/// The function will panic if given [`leaf_index`] is greater than the number of leaves. +pub fn merkle_proof(leaves: I, leaf_index: usize) -> MerkleProof +where + H: Hasher, + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + T: AsRef<[u8]>, +{ + let mut leaf = None; + let iter = leaves.into_iter().enumerate().map(|(idx, l)| { + let hash = H::hash(l.as_ref()); + if idx == leaf_index { + leaf = Some(l); + } + hash + }); + + /// The struct collects a proof for single leaf. + struct ProofCollection { + proof: Vec, + position: usize, + } + + impl ProofCollection { + fn new(position: usize) -> Self { + ProofCollection { proof: Default::default(), position } + } + } + + impl Visitor for ProofCollection { + fn move_up(&mut self) { + self.position /= 2; + } + + fn visit(&mut self, index: usize, left: &Option, right: &Option) { + // we are at left branch - right goes to the proof. + if self.position == index { + if let Some(right) = right { + self.proof.push(*right); + } + } + // we are at right branch - left goes to the proof. + if self.position == index + 1 { + if let Some(left) = left { + self.proof.push(*left); + } + } + } + } + + let number_of_leaves = iter.len(); + let mut collect_proof = ProofCollection::new(leaf_index); + + let root = merkelize::(iter, &mut collect_proof); + let leaf = leaf.expect("Requested `leaf_index` is greater than number of leaves."); + + #[cfg(feature = "debug")] + log::debug!( + "[merkle_proof] Proof: {:?}", + collect_proof.proof.iter().map(hex::encode).collect::>() + ); + + MerkleProof { root, proof: collect_proof.proof, number_of_leaves, leaf_index, leaf } +} + +/// Leaf node for proof verification. +/// +/// Can be either a value that needs to be hashed first, +/// or the hash itself. +#[derive(Debug, PartialEq, Eq)] +pub enum Leaf<'a> { + /// Leaf content. + Value(&'a [u8]), + /// Hash of the leaf content. + Hash(Hash), +} + +impl<'a, T: AsRef<[u8]>> From<&'a T> for Leaf<'a> { + fn from(v: &'a T) -> Self { + Leaf::Value(v.as_ref()) + } +} + +impl<'a> From for Leaf<'a> { + fn from(v: Hash) -> Self { + Leaf::Hash(v) + } +} + +/// Verify Merkle Proof correctness versus given root hash. +/// +/// The proof is NOT expected to contain leaf hash as the first +/// element, but only all adjacent nodes required to eventually by process of +/// concatenating and hashing end up with given root hash. +/// +/// The proof must not contain the root hash. +pub fn verify_proof<'a, H, P, L>( + root: &'a Hash, + proof: P, + number_of_leaves: usize, + leaf_index: usize, + leaf: L, +) -> bool +where + H: Hasher, + P: IntoIterator, + L: Into>, +{ + if leaf_index >= number_of_leaves { + return false + } + + let leaf_hash = match leaf.into() { + Leaf::Value(content) => H::hash(content), + Leaf::Hash(hash) => hash, + }; + + let mut combined = [0_u8; 64]; + let mut position = leaf_index; + let mut width = number_of_leaves; + let computed = proof.into_iter().fold(leaf_hash, |a, b| { + if position % 2 == 1 || position + 1 == width { + combined[0..32].copy_from_slice(&b); + combined[32..64].copy_from_slice(&a); + } else { + combined[0..32].copy_from_slice(&a); + combined[32..64].copy_from_slice(&b); + } + let hash = H::hash(&combined); + #[cfg(feature = "debug")] + log::debug!( + "[verify_proof]: (a, b) {:?}, {:?} => {:?} ({:?}) hash", + hex::encode(a), + hex::encode(b), + hex::encode(hash), + hex::encode(combined) + ); + position /= 2; + width = ((width - 1) / 2) + 1; + hash + }); + + root == &computed +} + +/// Processes a single row (layer) of a tree by taking pairs of elements, +/// concatenating them, hashing and placing into resulting vector. +/// +/// In case only one element is provided it is returned via `Ok` result, in any other case (also an +/// empty iterator) an `Err` with the inner nodes of upper layer is returned. +fn merkelize_row( + mut iter: I, + mut next: Vec, + visitor: &mut V, +) -> Result> +where + H: Hasher, + V: Visitor, + I: Iterator, +{ + #[cfg(feature = "debug")] + log::debug!("[merkelize_row]"); + next.clear(); + + let mut index = 0; + let mut combined = [0_u8; 64]; + loop { + let a = iter.next(); + let b = iter.next(); + visitor.visit(index, &a, &b); + + #[cfg(feature = "debug")] + log::debug!(" {:?}\n {:?}", a.as_ref().map(hex::encode), b.as_ref().map(hex::encode)); + + index += 2; + match (a, b) { + (Some(a), Some(b)) => { + combined[0..32].copy_from_slice(&a); + combined[32..64].copy_from_slice(&b); + + next.push(H::hash(&combined)); + }, + // Odd number of items. Promote the item to the upper layer. + (Some(a), None) if !next.is_empty() => { + next.push(a); + }, + // Last item = root. + (Some(a), None) => return Ok(a), + // Finish up, no more items. + _ => { + #[cfg(feature = "debug")] + log::debug!( + "[merkelize_row] Next: {:?}", + next.iter().map(hex::encode).collect::>() + ); + return Err(next) + }, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use hex_literal::hex; + + #[test] + fn should_generate_empty_root() { + // given + let _ = env_logger::try_init(); + let data: Vec<[u8; 1]> = Default::default(); + + // when + let out = merkle_root::(data); + + // then + assert_eq!( + hex::encode(&out), + "0000000000000000000000000000000000000000000000000000000000000000" + ); + } + + #[test] + fn should_generate_single_root() { + // given + let _ = env_logger::try_init(); + let data = vec![hex!("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b")]; + + // when + let out = merkle_root::(data); + + // then + assert_eq!( + hex::encode(&out), + "aeb47a269393297f4b0a3c9c9cfd00c7a4195255274cf39d83dabc2fcc9ff3d7" + ); + } + + #[test] + fn should_generate_root_pow_2() { + // given + let _ = env_logger::try_init(); + let data = vec![ + hex!("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b"), + hex!("25451A4de12dcCc2D166922fA938E900fCc4ED24"), + ]; + + // when + let out = merkle_root::(data); + + // then + assert_eq!( + hex::encode(&out), + "697ea2a8fe5b03468548a7a413424a6292ab44a82a6f5cc594c3fa7dda7ce402" + ); + } + + #[test] + fn should_generate_root_complex() { + let _ = env_logger::try_init(); + let test = |root, data| { + assert_eq!(hex::encode(&merkle_root::(data)), root); + }; + + test( + "aff1208e69c9e8be9b584b07ebac4e48a1ee9d15ce3afe20b77a4d29e4175aa3", + vec!["a", "b", "c"], + ); + + test( + "b8912f7269068901f231a965adfefbc10f0eedcfa61852b103efd54dac7db3d7", + vec!["a", "b", "a"], + ); + + test( + "dc8e73fe6903148ff5079baecc043983625c23b39f31537e322cd0deee09fa9c", + vec!["a", "b", "a", "b"], + ); + + test( + "fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239", + vec!["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"], + ); + } + + #[test] + fn should_generate_and_verify_proof_simple() { + // given + let _ = env_logger::try_init(); + let data = vec!["a", "b", "c"]; + + // when + let proof0 = merkle_proof::(data.clone(), 0); + assert!(verify_proof::( + &proof0.root, + proof0.proof.clone(), + data.len(), + proof0.leaf_index, + &proof0.leaf, + )); + + let proof1 = merkle_proof::(data.clone(), 1); + assert!(verify_proof::( + &proof1.root, + proof1.proof, + data.len(), + proof1.leaf_index, + &proof1.leaf, + )); + + let proof2 = merkle_proof::(data.clone(), 2); + assert!(verify_proof::( + &proof2.root, + proof2.proof, + data.len(), + proof2.leaf_index, + &proof2.leaf + )); + + // then + assert_eq!(hex::encode(proof0.root), hex::encode(proof1.root)); + assert_eq!(hex::encode(proof2.root), hex::encode(proof1.root)); + + assert!(!verify_proof::( + &hex!("fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239"), + proof0.proof, + data.len(), + proof0.leaf_index, + &proof0.leaf + )); + + assert!(!verify_proof::( + &proof0.root, + vec![], + data.len(), + proof0.leaf_index, + &proof0.leaf + )); + } + + #[test] + fn should_generate_and_verify_proof_complex() { + // given + let _ = env_logger::try_init(); + let data = vec!["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]; + + for l in 0..data.len() { + // when + let proof = merkle_proof::(data.clone(), l); + // then + assert!(verify_proof::( + &proof.root, + proof.proof, + data.len(), + proof.leaf_index, + &proof.leaf + )); + } + } + + #[test] + fn should_generate_and_verify_proof_large() { + // given + let _ = env_logger::try_init(); + let mut data = vec![]; + for i in 1..16 { + for c in 'a'..'z' { + if c as usize % i != 0 { + data.push(c.to_string()); + } + } + + for l in 0..data.len() { + // when + let proof = merkle_proof::(data.clone(), l); + // then + assert!(verify_proof::( + &proof.root, + proof.proof, + data.len(), + proof.leaf_index, + &proof.leaf + )); + } + } + } + + #[test] + fn should_generate_and_verify_proof_large_tree() { + // given + let _ = env_logger::try_init(); + let mut data = vec![]; + for i in 0..6000 { + data.push(format!("{}", i)); + } + + for l in (0..data.len()).step_by(13) { + // when + let proof = merkle_proof::(data.clone(), l); + // then + assert!(verify_proof::( + &proof.root, + proof.proof, + data.len(), + proof.leaf_index, + &proof.leaf + )); + } + } + + #[test] + #[should_panic] + fn should_panic_on_invalid_leaf_index() { + let _ = env_logger::try_init(); + merkle_proof::(vec!["a"], 5); + } + + #[test] + fn should_generate_and_verify_proof_on_test_data() { + let addresses = vec![ + "0x9aF1Ca5941148eB6A3e9b9C741b69738292C533f", + "0xDD6ca953fddA25c496165D9040F7F77f75B75002", + "0x60e9C47B64Bc1C7C906E891255EaEC19123E7F42", + "0xfa4859480Aa6D899858DE54334d2911E01C070df", + "0x19B9b128470584F7209eEf65B69F3624549Abe6d", + "0xC436aC1f261802C4494504A11fc2926C726cB83b", + "0xc304C8C2c12522F78aD1E28dD86b9947D7744bd0", + "0xDa0C2Cba6e832E55dE89cF4033affc90CC147352", + "0xf850Fd22c96e3501Aad4CDCBf38E4AEC95622411", + "0x684918D4387CEb5E7eda969042f036E226E50642", + "0x963F0A1bFbb6813C0AC88FcDe6ceB96EA634A595", + "0x39B38ad74b8bCc5CE564f7a27Ac19037A95B6099", + "0xC2Dec7Fdd1fef3ee95aD88EC8F3Cd5bd4065f3C7", + "0x9E311f05c2b6A43C2CCF16fB2209491BaBc2ec01", + "0x927607C30eCE4Ef274e250d0bf414d4a210b16f0", + "0x98882bcf85E1E2DFF780D0eB360678C1cf443266", + "0xFBb50191cd0662049E7C4EE32830a4Cc9B353047", + "0x963854fc2C358c48C3F9F0A598B9572c581B8DEF", + "0xF9D7Bc222cF6e3e07bF66711e6f409E51aB75292", + "0xF2E3fd32D063F8bBAcB9e6Ea8101C2edd899AFe6", + "0x407a5b9047B76E8668570120A96d580589fd1325", + "0xEAD9726FAFB900A07dAd24a43AE941d2eFDD6E97", + "0x42f5C8D9384034A9030313B51125C32a526b6ee8", + "0x158fD2529Bc4116570Eb7C80CC76FEf33ad5eD95", + "0x0A436EE2E4dEF3383Cf4546d4278326Ccc82514E", + "0x34229A215db8FeaC93Caf8B5B255e3c6eA51d855", + "0xEb3B7CF8B1840242CB98A732BA464a17D00b5dDF", + "0x2079692bf9ab2d6dc7D79BBDdEE71611E9aA3B72", + "0x46e2A67e5d450e2Cf7317779f8274a2a630f3C9B", + "0xA7Ece4A5390DAB18D08201aE18800375caD78aab", + "0x15E1c0D24D62057Bf082Cb2253dA11Ef0d469570", + "0xADDEF4C9b5687Eb1F7E55F2251916200A3598878", + "0xe0B16Fb96F936035db2b5A68EB37D470fED2f013", + "0x0c9A84993feaa779ae21E39F9793d09e6b69B62D", + "0x3bc4D5148906F70F0A7D1e2756572655fd8b7B34", + "0xFf4675C26903D5319795cbd3a44b109E7DDD9fDe", + "0xCec4450569A8945C6D2Aba0045e4339030128a92", + "0x85f0584B10950E421A32F471635b424063FD8405", + "0xb38bEe7Bdc0bC43c096e206EFdFEad63869929E3", + "0xc9609466274Fef19D0e58E1Ee3b321D5C141067E", + "0xa08EA868cF75268E7401021E9f945BAe73872ecc", + "0x67C9Cb1A29E964Fe87Ff669735cf7eb87f6868fE", + "0x1B6BEF636aFcdd6085cD4455BbcC93796A12F6E2", + "0x46B37b243E09540b55cF91C333188e7D5FD786dD", + "0x8E719E272f62Fa97da93CF9C941F5e53AA09e44a", + "0xa511B7E7DB9cb24AD5c89fBb6032C7a9c2EfA0a5", + "0x4D11FDcAeD335d839132AD450B02af974A3A66f8", + "0xB8cf790a5090E709B4619E1F335317114294E17E", + "0x7f0f57eA064A83210Cafd3a536866ffD2C5eDCB3", + "0xC03C848A4521356EF800e399D889e9c2A25D1f9E", + "0xC6b03DF05cb686D933DD31fCa5A993bF823dc4FE", + "0x58611696b6a8102cf95A32c25612E4cEF32b910F", + "0x2ed4bC7197AEF13560F6771D930Bf907772DE3CE", + "0x3C5E58f334306be029B0e47e119b8977B2639eb4", + "0x288646a1a4FeeC560B349d210263c609aDF649a6", + "0xb4F4981E0d027Dc2B3c86afA0D0fC03d317e83C0", + "0xaAE4A87F8058feDA3971f9DEd639Ec9189aA2500", + "0x355069DA35E598913d8736E5B8340527099960b8", + "0x3cf5A0F274cd243C0A186d9fCBdADad089821B93", + "0xca55155dCc4591538A8A0ca322a56EB0E4aD03C4", + "0xE824D0268366ec5C4F23652b8eD70D552B1F2b8B", + "0x84C3e9B25AE8a9b39FF5E331F9A597F2DCf27Ca9", + "0xcA0018e278751De10d26539915d9c7E7503432FE", + "0xf13077dE6191D6c1509ac7E088b8BE7Fe656c28b", + "0x7a6bcA1ec9Db506e47ac6FD86D001c2aBc59C531", + "0xeA7f9A2A9dd6Ba9bc93ca615C3Ddf26973146911", + "0x8D0d8577e16F8731d4F8712BAbFa97aF4c453458", + "0xB7a7855629dF104246997e9ACa0E6510df75d0ea", + "0x5C1009BDC70b0C8Ab2e5a53931672ab448C17c89", + "0x40B47D1AfefEF5eF41e0789F0285DE7b1C31631C", + "0x5086933d549cEcEB20652CE00973703CF10Da373", + "0xeb364f6FE356882F92ae9314fa96116Cf65F47d8", + "0xdC4D31516A416cEf533C01a92D9a04bbdb85EE67", + "0x9b36E086E5A274332AFd3D8509e12ca5F6af918d", + "0xBC26394fF36e1673aE0608ce91A53B9768aD0D76", + "0x81B5AB400be9e563fA476c100BE898C09966426c", + "0x9d93C8ae5793054D28278A5DE6d4653EC79e90FE", + "0x3B8E75804F71e121008991E3177fc942b6c28F50", + "0xC6Eb5886eB43dD473f5BB4e21e56E08dA464D9B4", + "0xfdf1277b71A73c813cD0e1a94B800f4B1Db66DBE", + "0xc2ff2cCc98971556670e287Ff0CC39DA795231ad", + "0x76b7E1473f0D0A87E9B4a14E2B179266802740f5", + "0xA7Bc965660a6EF4687CCa4F69A97563163A3C2Ef", + "0xB9C2b47888B9F8f7D03dC1de83F3F55E738CebD3", + "0xEd400162E6Dd6bD2271728FFb04176bF770De94a", + "0xE3E8331156700339142189B6E555DCb2c0962750", + "0xbf62e342Bc7706a448EdD52AE871d9C4497A53b1", + "0xb9d7A1A111eed75714a0AcD2dd467E872eE6B03D", + "0x03942919DFD0383b8c574AB8A701d89fd4bfA69D", + "0x0Ef4C92355D3c8c7050DFeb319790EFCcBE6fe9e", + "0xA6895a3cf0C60212a73B3891948ACEcF1753f25E", + "0x0Ed509239DB59ef3503ded3d31013C983d52803A", + "0xc4CE8abD123BfAFc4deFf37c7D11DeCd5c350EE4", + "0x4A4Bf59f7038eDcd8597004f35d7Ee24a7Bdd2d3", + "0x5769E8e8A2656b5ed6b6e6fa2a2bFAeaf970BB87", + "0xf9E15cCE181332F4F57386687c1776b66C377060", + "0xc98f8d4843D56a46C21171900d3eE538Cc74dbb5", + "0x3605965B47544Ce4302b988788B8195601AE4dEd", + "0xe993BDfdcAac2e65018efeE0F69A12678031c71d", + "0x274fDf8801385D3FAc954BCc1446Af45f5a8304c", + "0xBFb3f476fcD6429F4a475bA23cEFdDdd85c6b964", + "0x806cD16588Fe812ae740e931f95A289aFb4a4B50", + "0xa89488CE3bD9C25C3aF797D1bbE6CA689De79d81", + "0xd412f1AfAcf0Ebf3Cd324593A231Fc74CC488B12", + "0xd1f715b2D7951d54bc31210BbD41852D9BF98Ed1", + "0xf65aD707c344171F467b2ADba3d14f312219cE23", + "0x2971a4b242e9566dEF7bcdB7347f5E484E11919B", + "0x12b113D6827E07E7D426649fBd605f427da52314", + "0x1c6CA45171CDb9856A6C9Dba9c5F1216913C1e97", + "0x11cC6ee1d74963Db23294FCE1E3e0A0555779CeA", + "0x8Aa1C721255CDC8F895E4E4c782D86726b068667", + "0xA2cDC1f37510814485129aC6310b22dF04e9Bbf0", + "0xCf531b71d388EB3f5889F1f78E0d77f6fb109767", + "0xBe703e3545B2510979A0cb0C440C0Fba55c6dCB5", + "0x30a35886F989db39c797D8C93880180Fdd71b0c8", + "0x1071370D981F60c47A9Cd27ac0A61873a372cBB2", + "0x3515d74A11e0Cb65F0F46cB70ecf91dD1712daaa", + "0x50500a3c2b7b1229c6884505D00ac6Be29Aecd0C", + "0x9A223c2a11D4FD3585103B21B161a2B771aDA3d1", + "0xd7218df03AD0907e6c08E707B15d9BD14285e657", + "0x76CfD72eF5f93D1a44aD1F80856797fBE060c70a", + "0x44d093cB745944991EFF5cBa151AA6602d6f5420", + "0x626516DfF43bf09A71eb6fd1510E124F96ED0Cde", + "0x6530824632dfe099304E2DC5701cA99E6d031E08", + "0x57e6c423d6a7607160d6379A0c335025A14DaFC0", + "0x3966D4AD461Ef150E0B10163C81E79b9029E69c3", + "0xF608aCfd0C286E23721a3c347b2b65039f6690F1", + "0xbfB8FAac31A25646681936977837f7740fCd0072", + "0xd80aa634a623a7ED1F069a1a3A28a173061705c7", + "0x9122a77B36363e24e12E1E2D73F87b32926D3dF5", + "0x62562f0d1cD31315bCCf176049B6279B2bfc39C2", + "0x48aBF7A2a7119e5675059E27a7082ba7F38498b2", + "0xb4596983AB9A9166b29517acD634415807569e5F", + "0x52519D16E20BC8f5E96Da6d736963e85b2adA118", + "0x7663893C3dC0850EfC5391f5E5887eD723e51B83", + "0x5FF323a29bCC3B5b4B107e177EccEF4272959e61", + "0xee6e499AdDf4364D75c05D50d9344e9daA5A9AdF", + "0x1631b0BD31fF904aD67dD58994C6C2051CDe4E75", + "0xbc208e9723D44B9811C428f6A55722a26204eEF2", + "0xe76103a222Ee2C7Cf05B580858CEe625C4dc00E1", + "0xC71Bb2DBC51760f4fc2D46D84464410760971B8a", + "0xB4C18811e6BFe564D69E12c224FFc57351f7a7ff", + "0xD11DB0F5b41061A887cB7eE9c8711438844C298A", + "0xB931269934A3D4432c084bAAc3d0de8143199F4f", + "0x070037cc85C761946ec43ea2b8A2d5729908A2a1", + "0x2E34aa8C95Ffdbb37f14dCfBcA69291c55Ba48DE", + "0x052D93e8d9220787c31d6D83f87eC7dB088E998f", + "0x498dAC6C69b8b9ad645217050054840f1D91D029", + "0xE4F7D60f9d84301e1fFFd01385a585F3A11F8E89", + "0xEa637992f30eA06460732EDCBaCDa89355c2a107", + "0x4960d8Da07c27CB6Be48a79B96dD70657c57a6bF", + "0x7e471A003C8C9fdc8789Ded9C3dbe371d8aa0329", + "0xd24265Cc10eecb9e8d355CCc0dE4b11C556E74D7", + "0xDE59C8f7557Af779674f41CA2cA855d571018690", + "0x2fA8A6b3b6226d8efC9d8f6EBDc73Ca33DDcA4d8", + "0xe44102664c6c2024673Ff07DFe66E187Db77c65f", + "0x94E3f4f90a5f7CBF2cc2623e66B8583248F01022", + "0x0383EdBbc21D73DEd039E9C1Ff6bf56017b4CC40", + "0x64C3E49898B88d1E0f0d02DA23E0c00A2Cd0cA99", + "0xF4ccfB67b938d82B70bAb20975acFAe402E812E1", + "0x4f9ee5829e9852E32E7BC154D02c91D8E203e074", + "0xb006312eF9713463bB33D22De60444Ba95609f6B", + "0x7Cbe76ef69B52110DDb2e3b441C04dDb11D63248", + "0x70ADEEa65488F439392B869b1Df7241EF317e221", + "0x64C0bf8AA36Ba590477585Bc0D2BDa7970769463", + "0xA4cDc98593CE52d01Fe5Ca47CB3dA5320e0D7592", + "0xc26B34D375533fFc4c5276282Fa5D660F3d8cbcB", + ]; + let root = hex!("72b0acd7c302a84f1f6b6cefe0ba7194b7398afb440e1b44a9dbbe270394ca53"); + + let data = addresses + .into_iter() + .map(|address| hex::decode(&address[2..]).unwrap()) + .collect::>(); + + for l in 0..data.len() { + // when + let proof = merkle_proof::(data.clone(), l); + assert_eq!(hex::encode(&proof.root), hex::encode(&root)); + assert_eq!(proof.leaf_index, l); + assert_eq!(&proof.leaf, &data[l]); + + // then + assert!(verify_proof::( + &proof.root, + proof.proof, + data.len(), + proof.leaf_index, + &proof.leaf + )); + } + + let proof = merkle_proof::(data.clone(), data.len() - 1); + + assert_eq!( + proof, + MerkleProof { + root, + proof: vec![ + hex!("340bcb1d49b2d82802ddbcf5b85043edb3427b65d09d7f758fbc76932ad2da2f"), + hex!("ba0580e5bd530bc93d61276df7969fb5b4ae8f1864b4a28c280249575198ff1f"), + hex!("d02609d2bbdb28aa25f58b85afec937d5a4c85d37925bce6d0cf802f9d76ba79"), + hex!("ae3f8991955ed884613b0a5f40295902eea0e0abe5858fc520b72959bc016d4e"), + ], + number_of_leaves: data.len(), + leaf_index: data.len() - 1, + leaf: hex!("c26B34D375533fFc4c5276282Fa5D660F3d8cbcB").to_vec(), + } + ); + } +} diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs new file mode 100644 index 0000000000000..001831639b169 --- /dev/null +++ b/frame/beefy-mmr/src/lib.rs @@ -0,0 +1,236 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] + +//! A BEEFY+MMR pallet combo. +//! +//! While both BEEFY and Merkle Mountain Range (MMR) can be used separately, +//! these tools were designed to work together in unison. +//! +//! The pallet provides a standardized MMR Leaf format that is can be used +//! to bridge BEEFY+MMR-based networks (both standalone and polkadot-like). +//! +//! The MMR leaf contains: +//! 1. Block number and parent block hash. +//! 2. Merkle Tree Root Hash of next BEEFY validator set. +//! 3. Merkle Tree Root Hash of current parachain heads state. +//! +//! and thanks to versioning can be easily updated in the future. + +use sp_runtime::traits::{Convert, Hash}; +use sp_std::prelude::*; + +use beefy_primitives::mmr::{BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}; +use pallet_mmr::primitives::LeafDataProvider; + +use codec::Encode; +use frame_support::traits::Get; + +pub use pallet::*; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +/// A BEEFY consensus digest item with MMR root hash. +pub struct DepositBeefyDigest(sp_std::marker::PhantomData); + +impl pallet_mmr::primitives::OnNewRoot for DepositBeefyDigest +where + T: pallet_mmr::Config, + T: pallet_beefy::Config, +{ + fn on_new_root(root: &::Hash) { + let digest = sp_runtime::generic::DigestItem::Consensus( + beefy_primitives::BEEFY_ENGINE_ID, + codec::Encode::encode(&beefy_primitives::ConsensusLog::< + ::BeefyId, + >::MmrRoot(*root)), + ); + >::deposit_log(digest); + } +} + +/// Convert BEEFY secp256k1 public keys into Ethereum addresses +pub struct BeefyEcdsaToEthereum; +impl Convert> for BeefyEcdsaToEthereum { + fn convert(a: beefy_primitives::crypto::AuthorityId) -> Vec { + use sp_core::crypto::Public; + let compressed_key = a.as_slice(); + + libsecp256k1::PublicKey::parse_slice( + compressed_key, + Some(libsecp256k1::PublicKeyFormat::Compressed), + ) + // uncompress the key + .map(|pub_key| pub_key.serialize().to_vec()) + // now convert to ETH address + .map(|uncompressed| sp_io::hashing::keccak_256(&uncompressed[1..])[12..].to_vec()) + .map_err(|_| { + log::error!(target: "runtime::beefy", "Invalid BEEFY PublicKey format!"); + }) + .unwrap_or_default() + } +} + +type MerkleRootOf = ::Hash; +type ParaId = u32; +type ParaHead = Vec; + +/// A type that is able to return current list of parachain heads that end up in the MMR leaf. +pub trait ParachainHeadsProvider { + /// Return a list of tuples containing a `ParaId` and Parachain Header data (ParaHead). + /// + /// The returned data does not have to be sorted. + fn parachain_heads() -> Vec<(ParaId, ParaHead)>; +} + +/// A default implementation for runtimes without parachains. +impl ParachainHeadsProvider for () { + fn parachain_heads() -> Vec<(ParaId, ParaHead)> { + Default::default() + } +} + +#[frame_support::pallet] +pub mod pallet { + #![allow(missing_docs)] + + use super::*; + use frame_support::pallet_prelude::*; + + /// BEEFY-MMR pallet. + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + /// The module's configuration trait. + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: pallet_mmr::Config + pallet_beefy::Config { + /// Current leaf version. + /// + /// Specifies the version number added to every leaf that get's appended to the MMR. + /// Read more in [`MmrLeafVersion`] docs about versioning leaves. + type LeafVersion: Get; + + /// Convert BEEFY AuthorityId to a form that would end up in the Merkle Tree. + /// + /// For instance for ECDSA (secp256k1) we want to store uncompressed public keys (65 bytes) + /// and later to Ethereum Addresses (160 bits) to simplify using them on Ethereum chain, + /// but the rest of the Substrate codebase is storing them compressed (33 bytes) for + /// efficiency reasons. + type BeefyAuthorityToMerkleLeaf: Convert<::BeefyId, Vec>; + + /// Retrieve a list of current parachain heads. + /// + /// The trait is implemented for `paras` module, but since not all chains might have + /// parachains, and we want to keep the MMR leaf structure uniform, it's possible to use + /// `()` as well to simply put dummy data to the leaf. + type ParachainHeads: ParachainHeadsProvider; + } + + /// Details of next BEEFY authority set. + /// + /// This storage entry is used as cache for calls to [`update_beefy_next_authority_set`]. + #[pallet::storage] + #[pallet::getter(fn beefy_next_authorities)] + pub type BeefyNextAuthorities = + StorageValue<_, BeefyNextAuthoritySet>, ValueQuery>; +} + +impl LeafDataProvider for Pallet +where + MerkleRootOf: From + Into, +{ + type LeafData = MmrLeaf< + ::BlockNumber, + ::Hash, + MerkleRootOf, + >; + + fn leaf_data() -> Self::LeafData { + MmrLeaf { + version: T::LeafVersion::get(), + parent_number_and_hash: frame_system::Pallet::::leaf_data(), + parachain_heads: Pallet::::parachain_heads_merkle_root(), + beefy_next_authority_set: Pallet::::update_beefy_next_authority_set(), + } + } +} + +impl beefy_merkle_tree::Hasher for Pallet +where + MerkleRootOf: Into, +{ + fn hash(data: &[u8]) -> beefy_merkle_tree::Hash { + ::Hashing::hash(data).into() + } +} + +impl Pallet +where + MerkleRootOf: From + Into, +{ + /// Returns latest root hash of a merkle tree constructed from all active parachain headers. + /// + /// The leafs are sorted by `ParaId` to allow more efficient lookups and non-existence proofs. + /// + /// NOTE this does not include parathreads - only parachains are part of the merkle tree. + /// + /// NOTE This is an initial and inefficient implementation, which re-constructs + /// the merkle tree every block. Instead we should update the merkle root in + /// [Self::on_initialize] call of this pallet and update the merkle tree efficiently (use + /// on-chain storage to persist inner nodes). + fn parachain_heads_merkle_root() -> MerkleRootOf { + let mut para_heads = T::ParachainHeads::parachain_heads(); + para_heads.sort(); + let para_heads = para_heads.into_iter().map(|pair| pair.encode()); + beefy_merkle_tree::merkle_root::(para_heads).into() + } + + /// Returns details of the next BEEFY authority set. + /// + /// Details contain authority set id, authority set length and a merkle root, + /// constructed from uncompressed secp256k1 public keys converted to Ethereum addresses + /// of the next BEEFY authority set. + /// + /// This function will use a storage-cached entry in case the set didn't change, or compute and + /// cache new one in case it did. + fn update_beefy_next_authority_set() -> BeefyNextAuthoritySet> { + let id = pallet_beefy::Pallet::::validator_set_id() + 1; + let current_next = Self::beefy_next_authorities(); + // avoid computing the merkle tree if validator set id didn't change. + if id == current_next.id { + return current_next + } + + let beefy_addresses = pallet_beefy::Pallet::::next_authorities() + .into_iter() + .map(T::BeefyAuthorityToMerkleLeaf::convert) + .collect::>(); + let len = beefy_addresses.len() as u32; + let root = beefy_merkle_tree::merkle_root::(beefy_addresses).into(); + let next_set = BeefyNextAuthoritySet { id, len, root }; + // cache the result + BeefyNextAuthorities::::put(&next_set); + next_set + } +} diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs new file mode 100644 index 0000000000000..a8d136b192aec --- /dev/null +++ b/frame/beefy-mmr/src/mock.rs @@ -0,0 +1,205 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::vec; + +use beefy_primitives::mmr::MmrLeafVersion; +use frame_support::{ + construct_runtime, parameter_types, sp_io::TestExternalities, BasicExternalities, +}; +use sp_core::{Hasher, H256}; +use sp_runtime::{ + app_crypto::ecdsa::Public, + impl_opaque_keys, + testing::Header, + traits::{BlakeTwo256, ConvertInto, IdentityLookup, Keccak256, OpaqueKeys}, + Perbill, +}; + +use crate as pallet_beefy_mmr; + +pub use beefy_primitives::{crypto::AuthorityId as BeefyId, ConsensusLog, BEEFY_ENGINE_ID}; + +impl_opaque_keys! { + pub struct MockSessionKeys { + pub dummy: pallet_beefy::Pallet, + } +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Session: pallet_session::{Pallet, Call, Storage, Event, Config}, + Mmr: pallet_mmr::{Pallet, Storage}, + Beefy: pallet_beefy::{Pallet, Config, Storage}, + BeefyMmr: pallet_beefy_mmr::{Pallet, Storage}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; +} + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Call = Call; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); +} + +parameter_types! { + pub const Period: u64 = 1; + pub const Offset: u64 = 0; + pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); +} + +impl pallet_session::Config for Test { + type Event = Event; + type ValidatorId = u64; + type ValidatorIdOf = ConvertInto; + type ShouldEndSession = pallet_session::PeriodicSessions; + type NextSessionRotation = pallet_session::PeriodicSessions; + type SessionManager = MockSessionManager; + type SessionHandler = ::KeyTypeIdProviders; + type Keys = MockSessionKeys; + type DisabledValidatorsThreshold = DisabledValidatorsThreshold; + type WeightInfo = (); +} + +pub type MmrLeaf = beefy_primitives::mmr::MmrLeaf< + ::BlockNumber, + ::Hash, + ::Hash, +>; + +impl pallet_mmr::Config for Test { + const INDEXING_PREFIX: &'static [u8] = b"mmr"; + + type Hashing = Keccak256; + + type Hash = ::Out; + + type LeafData = BeefyMmr; + + type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; + + type WeightInfo = (); +} + +impl pallet_beefy::Config for Test { + type BeefyId = BeefyId; +} + +parameter_types! { + pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(1, 5); +} + +impl pallet_beefy_mmr::Config for Test { + type LeafVersion = LeafVersion; + + type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; + + type ParachainHeads = DummyParaHeads; +} + +pub struct DummyParaHeads; +impl pallet_beefy_mmr::ParachainHeadsProvider for DummyParaHeads { + fn parachain_heads() -> Vec<(pallet_beefy_mmr::ParaId, pallet_beefy_mmr::ParaHead)> { + vec![(15, vec![1, 2, 3]), (5, vec![4, 5, 6])] + } +} + +pub struct MockSessionManager; +impl pallet_session::SessionManager for MockSessionManager { + fn end_session(_: sp_staking::SessionIndex) {} + fn start_session(_: sp_staking::SessionIndex) {} + fn new_session(idx: sp_staking::SessionIndex) -> Option> { + if idx == 0 || idx == 1 { + Some(vec![1, 2]) + } else if idx == 2 { + Some(vec![3, 4]) + } else { + None + } + } +} + +// Note, that we can't use `UintAuthorityId` here. Reason is that the implementation +// of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for +// ed25519 and sr25519 but *not* for ecdsa. An ecdsa public key is 33 bytes. +pub fn mock_beefy_id(id: u8) -> BeefyId { + let buf: [u8; 33] = [id; 33]; + let pk = Public::from_raw(buf); + BeefyId::from(pk) +} + +pub fn mock_authorities(vec: Vec) -> Vec<(u64, BeefyId)> { + vec.into_iter().map(|id| ((id as u64), mock_beefy_id(id))).collect() +} + +pub fn new_test_ext(ids: Vec) -> TestExternalities { + new_test_ext_raw_authorities(mock_authorities(ids)) +} + +pub fn new_test_ext_raw_authorities(authorities: Vec<(u64, BeefyId)>) -> TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + let session_keys: Vec<_> = authorities + .iter() + .enumerate() + .map(|(_, id)| (id.0 as u64, id.0 as u64, MockSessionKeys { dummy: id.1.clone() })) + .collect(); + + BasicExternalities::execute_with_storage(&mut t, || { + for (ref id, ..) in &session_keys { + frame_system::Pallet::::inc_providers(id); + } + }); + + pallet_session::GenesisConfig:: { keys: session_keys } + .assimilate_storage(&mut t) + .unwrap(); + + t.into() +} diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs new file mode 100644 index 0000000000000..7c70766623b4d --- /dev/null +++ b/frame/beefy-mmr/src/tests.rs @@ -0,0 +1,148 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::vec; + +use beefy_primitives::{ + mmr::{BeefyNextAuthoritySet, MmrLeafVersion}, + ValidatorSet, +}; +use codec::{Decode, Encode}; +use hex_literal::hex; + +use sp_core::H256; +use sp_io::TestExternalities; +use sp_runtime::{traits::Keccak256, DigestItem}; + +use frame_support::traits::OnInitialize; + +use crate::mock::*; + +fn init_block(block: u64) { + System::set_block_number(block); + Session::on_initialize(block); + Mmr::on_initialize(block); + Beefy::on_initialize(block); + BeefyMmr::on_initialize(block); +} + +pub fn beefy_log(log: ConsensusLog) -> DigestItem { + DigestItem::Consensus(BEEFY_ENGINE_ID, log.encode()) +} + +fn offchain_key(pos: usize) -> Vec { + (::INDEXING_PREFIX, pos as u64).encode() +} + +fn read_mmr_leaf(ext: &mut TestExternalities, index: usize) -> MmrLeaf { + type Node = pallet_mmr_primitives::DataOrHash; + ext.persist_offchain_overlay(); + let offchain_db = ext.offchain_db(); + offchain_db + .get(&offchain_key(index)) + .map(|d| Node::decode(&mut &*d).unwrap()) + .map(|n| match n { + Node::Data(d) => d, + _ => panic!("Unexpected MMR node."), + }) + .unwrap() +} + +#[test] +fn should_contain_mmr_digest() { + let mut ext = new_test_ext(vec![1, 2, 3, 4]); + ext.execute_with(|| { + init_block(1); + + assert_eq!( + System::digest().logs, + vec![beefy_log(ConsensusLog::MmrRoot( + hex!("f3e3afbfa69e89cd1e99f8d3570155962f3346d1d8758dc079be49ef70387758").into() + ))] + ); + + // unique every time + init_block(2); + + assert_eq!( + System::digest().logs, + vec![ + beefy_log(ConsensusLog::MmrRoot( + hex!("f3e3afbfa69e89cd1e99f8d3570155962f3346d1d8758dc079be49ef70387758").into() + )), + beefy_log(ConsensusLog::AuthoritiesChange(ValidatorSet { + validators: vec![mock_beefy_id(3), mock_beefy_id(4),], + id: 1, + })), + beefy_log(ConsensusLog::MmrRoot( + hex!("7d4ae4524bae75d52b63f08eab173b0c263eb95ae2c55c3a1d871241bd0cc559").into() + )), + ] + ); + }); +} + +#[test] +fn should_contain_valid_leaf_data() { + let mut ext = new_test_ext(vec![1, 2, 3, 4]); + ext.execute_with(|| { + init_block(1); + }); + + let mmr_leaf = read_mmr_leaf(&mut ext, 0); + assert_eq!( + mmr_leaf, + MmrLeaf { + version: MmrLeafVersion::new(1, 5), + parent_number_and_hash: (0_u64, H256::repeat_byte(0x45)), + beefy_next_authority_set: BeefyNextAuthoritySet { + id: 1, + len: 2, + root: hex!("01b1a742589773fc054c8f5021a456316ffcec0370b25678b0696e116d1ef9ae") + .into(), + }, + parachain_heads: hex!( + "ed893c8f8cc87195a5d4d2805b011506322036bcace79642aa3e94ab431e442e" + ) + .into(), + } + ); + + // build second block on top + ext.execute_with(|| { + init_block(2); + }); + + let mmr_leaf = read_mmr_leaf(&mut ext, 1); + assert_eq!( + mmr_leaf, + MmrLeaf { + version: MmrLeafVersion::new(1, 5), + parent_number_and_hash: (1_u64, H256::repeat_byte(0x45)), + beefy_next_authority_set: BeefyNextAuthoritySet { + id: 2, + len: 2, + root: hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5") + .into(), + }, + parachain_heads: hex!( + "ed893c8f8cc87195a5d4d2805b011506322036bcace79642aa3e94ab431e442e" + ) + .into(), + } + ); +} diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml new file mode 100644 index 0000000000000..e5af666e7ca54 --- /dev/null +++ b/frame/beefy/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "pallet-beefy" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" + +[dependencies] +codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +serde = { version = "1.0.130", optional = true } + +frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } +frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } + +sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } +sp-std = { version = "4.0.0-dev", path = "../../primitives/std", default-features = false } + +pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } + +beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", default-features = false } + +[dev-dependencies] +sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "serde", + "beefy-primitives/std", + "frame-support/std", + "frame-system/std", + "sp-runtime/std", + "sp-std/std", + "pallet-session/std", +] diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs new file mode 100644 index 0000000000000..32f3133373432 --- /dev/null +++ b/frame/beefy/src/lib.rs @@ -0,0 +1,179 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Encode; + +use frame_support::{traits::OneSessionHandler, Parameter}; + +use sp_runtime::{ + generic::DigestItem, + traits::{IsMember, Member}, + RuntimeAppPublic, +}; +use sp_std::prelude::*; + +use beefy_primitives::{AuthorityIndex, ConsensusLog, ValidatorSet, BEEFY_ENGINE_ID}; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// Authority identifier type + type BeefyId: Member + Parameter + RuntimeAppPublic + Default + MaybeSerializeDeserialize; + } + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} + + /// The current authorities set + #[pallet::storage] + #[pallet::getter(fn authorities)] + pub(super) type Authorities = StorageValue<_, Vec, ValueQuery>; + + /// The current validator set id + #[pallet::storage] + #[pallet::getter(fn validator_set_id)] + pub(super) type ValidatorSetId = + StorageValue<_, beefy_primitives::ValidatorSetId, ValueQuery>; + + /// Authorities set scheduled to be used with the next session + #[pallet::storage] + #[pallet::getter(fn next_authorities)] + pub(super) type NextAuthorities = StorageValue<_, Vec, ValueQuery>; + + #[pallet::genesis_config] + pub struct GenesisConfig { + pub authorities: Vec, + } + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + Self { authorities: Vec::new() } + } + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + Pallet::::initialize_authorities(&self.authorities); + } + } +} + +impl Pallet { + /// Return the current active BEEFY validator set. + pub fn validator_set() -> ValidatorSet { + ValidatorSet:: { validators: Self::authorities(), id: Self::validator_set_id() } + } + + fn change_authorities(new: Vec, queued: Vec) { + // As in GRANDPA, we trigger a validator set change only if the the validator + // set has actually changed. + if new != Self::authorities() { + >::put(&new); + + let next_id = Self::validator_set_id() + 1u64; + >::put(next_id); + + let log: DigestItem = DigestItem::Consensus( + BEEFY_ENGINE_ID, + ConsensusLog::AuthoritiesChange(ValidatorSet { validators: new, id: next_id }) + .encode(), + ); + >::deposit_log(log); + } + + >::put(&queued); + } + + fn initialize_authorities(authorities: &[T::BeefyId]) { + if authorities.is_empty() { + return + } + + assert!(>::get().is_empty(), "Authorities are already initialized!"); + + >::put(authorities); + >::put(0); + // Like `pallet_session`, initialize the next validator set as well. + >::put(authorities); + } +} + +impl sp_runtime::BoundToRuntimeAppPublic for Pallet { + type Public = T::BeefyId; +} + +impl OneSessionHandler for Pallet { + type Key = T::BeefyId; + + fn on_genesis_session<'a, I: 'a>(validators: I) + where + I: Iterator, + { + let authorities = validators.map(|(_, k)| k).collect::>(); + Self::initialize_authorities(&authorities); + } + + fn on_new_session<'a, I: 'a>(changed: bool, validators: I, queued_validators: I) + where + I: Iterator, + { + if changed { + let next_authorities = validators.map(|(_, k)| k).collect::>(); + let next_queued_authorities = queued_validators.map(|(_, k)| k).collect::>(); + + Self::change_authorities(next_authorities, next_queued_authorities); + } + } + + fn on_disabled(i: usize) { + let log: DigestItem = DigestItem::Consensus( + BEEFY_ENGINE_ID, + ConsensusLog::::OnDisabled(i as AuthorityIndex).encode(), + ); + + >::deposit_log(log); + } +} + +impl IsMember for Pallet { + fn is_member(authority_id: &T::BeefyId) -> bool { + Self::authorities().iter().any(|id| id == authority_id) + } +} diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs new file mode 100644 index 0000000000000..696d0d972e70c --- /dev/null +++ b/frame/beefy/src/mock.rs @@ -0,0 +1,164 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::vec; + +use frame_support::{ + construct_runtime, parameter_types, sp_io::TestExternalities, BasicExternalities, +}; +use sp_core::H256; +use sp_runtime::{ + app_crypto::ecdsa::Public, + impl_opaque_keys, + testing::Header, + traits::{BlakeTwo256, ConvertInto, IdentityLookup, OpaqueKeys}, + Perbill, +}; + +use crate as pallet_beefy; + +pub use beefy_primitives::{crypto::AuthorityId as BeefyId, ConsensusLog, BEEFY_ENGINE_ID}; + +impl_opaque_keys! { + pub struct MockSessionKeys { + pub dummy: pallet_beefy::Pallet, + } +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Beefy: pallet_beefy::{Pallet, Call, Config, Storage}, + Session: pallet_session::{Pallet, Call, Storage, Event, Config}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; +} + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Call = Call; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); +} + +impl pallet_beefy::Config for Test { + type BeefyId = BeefyId; +} + +parameter_types! { + pub const Period: u64 = 1; + pub const Offset: u64 = 0; + pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); +} + +impl pallet_session::Config for Test { + type Event = Event; + type ValidatorId = u64; + type ValidatorIdOf = ConvertInto; + type ShouldEndSession = pallet_session::PeriodicSessions; + type NextSessionRotation = pallet_session::PeriodicSessions; + type SessionManager = MockSessionManager; + type SessionHandler = ::KeyTypeIdProviders; + type Keys = MockSessionKeys; + type DisabledValidatorsThreshold = DisabledValidatorsThreshold; + type WeightInfo = (); +} + +pub struct MockSessionManager; + +impl pallet_session::SessionManager for MockSessionManager { + fn end_session(_: sp_staking::SessionIndex) {} + fn start_session(_: sp_staking::SessionIndex) {} + fn new_session(idx: sp_staking::SessionIndex) -> Option> { + if idx == 0 || idx == 1 { + Some(vec![1, 2]) + } else if idx == 2 { + Some(vec![3, 4]) + } else { + None + } + } +} + +// Note, that we can't use `UintAuthorityId` here. Reason is that the implementation +// of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for +// ed25519 and sr25519 but *not* for ecdsa. An ecdsa public key is 33 bytes. +pub fn mock_beefy_id(id: u8) -> BeefyId { + let buf: [u8; 33] = [id; 33]; + let pk = Public::from_raw(buf); + BeefyId::from(pk) +} + +pub fn mock_authorities(vec: Vec) -> Vec<(u64, BeefyId)> { + vec.into_iter().map(|id| ((id as u64), mock_beefy_id(id))).collect() +} + +pub fn new_test_ext(ids: Vec) -> TestExternalities { + new_test_ext_raw_authorities(mock_authorities(ids)) +} + +pub fn new_test_ext_raw_authorities(authorities: Vec<(u64, BeefyId)>) -> TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + let session_keys: Vec<_> = authorities + .iter() + .enumerate() + .map(|(_, id)| (id.0 as u64, id.0 as u64, MockSessionKeys { dummy: id.1.clone() })) + .collect(); + + BasicExternalities::execute_with_storage(&mut t, || { + for (ref id, ..) in &session_keys { + frame_system::Pallet::::inc_providers(id); + } + }); + + pallet_session::GenesisConfig:: { keys: session_keys } + .assimilate_storage(&mut t) + .unwrap(); + + t.into() +} diff --git a/frame/beefy/src/tests.rs b/frame/beefy/src/tests.rs new file mode 100644 index 0000000000000..24f9acaf76bfc --- /dev/null +++ b/frame/beefy/src/tests.rs @@ -0,0 +1,142 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::vec; + +use beefy_primitives::ValidatorSet; +use codec::Encode; + +use sp_core::H256; +use sp_runtime::DigestItem; + +use frame_support::traits::OnInitialize; + +use crate::mock::*; + +fn init_block(block: u64) { + System::set_block_number(block); + Session::on_initialize(block); +} + +pub fn beefy_log(log: ConsensusLog) -> DigestItem { + DigestItem::Consensus(BEEFY_ENGINE_ID, log.encode()) +} + +#[test] +fn genesis_session_initializes_authorities() { + let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)]; + + new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { + let authorities = Beefy::authorities(); + + assert!(authorities.len() == 2); + assert_eq!(want[0], authorities[0]); + assert_eq!(want[1], authorities[1]); + + assert!(Beefy::validator_set_id() == 0); + + let next_authorities = Beefy::next_authorities(); + + assert!(next_authorities.len() == 2); + assert_eq!(want[0], next_authorities[0]); + assert_eq!(want[1], next_authorities[1]); + }); +} + +#[test] +fn session_change_updates_authorities() { + new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { + init_block(1); + + assert!(0 == Beefy::validator_set_id()); + + // no change - no log + assert!(System::digest().logs.is_empty()); + + init_block(2); + + assert!(1 == Beefy::validator_set_id()); + + let want = beefy_log(ConsensusLog::AuthoritiesChange(ValidatorSet { + validators: vec![mock_beefy_id(3), mock_beefy_id(4)], + id: 1, + })); + + let log = System::digest().logs[0].clone(); + + assert_eq!(want, log); + }); +} + +#[test] +fn session_change_updates_next_authorities() { + let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)]; + + new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { + init_block(1); + + let next_authorities = Beefy::next_authorities(); + + assert!(next_authorities.len() == 2); + assert_eq!(want[0], next_authorities[0]); + assert_eq!(want[1], next_authorities[1]); + + init_block(2); + + let next_authorities = Beefy::next_authorities(); + + assert!(next_authorities.len() == 2); + assert_eq!(want[2], next_authorities[0]); + assert_eq!(want[3], next_authorities[1]); + }); +} + +#[test] +fn validator_set_at_genesis() { + let want = vec![mock_beefy_id(1), mock_beefy_id(2)]; + + new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { + let vs = Beefy::validator_set(); + + assert_eq!(vs.id, 0u64); + assert_eq!(vs.validators[0], want[0]); + assert_eq!(vs.validators[1], want[1]); + }); +} + +#[test] +fn validator_set_updates_work() { + let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)]; + + new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { + init_block(1); + + let vs = Beefy::validator_set(); + + assert_eq!(vs.id, 0u64); + assert_eq!(want[0], vs.validators[0]); + assert_eq!(want[1], vs.validators[1]); + + init_block(2); + + let vs = Beefy::validator_set(); + + assert_eq!(vs.id, 1u64); + assert_eq!(want[2], vs.validators[0]); + assert_eq!(want[3], vs.validators[1]); + }); +} diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml new file mode 100644 index 0000000000000..633ac0e8fbcd1 --- /dev/null +++ b/primitives/beefy/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "beefy-primitives" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" + +[dependencies] +codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } + +sp-api = { version = "4.0.0-dev", path = "../api", default-features = false } +sp-application-crypto = { version = "4.0.0-dev", path = "../application-crypto", default-features = false } +sp-core = { version = "4.0.0-dev", path = "../core", default-features = false } +sp-runtime = { version = "4.0.0-dev", path = "../runtime", default-features = false } +sp-std = { version = "4.0.0-dev", path = "../std", default-features = false } + +[dev-dependencies] +hex-literal = "0.3" + +sp-keystore = { version = "0.10.0-dev", path = "../keystore" } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "sp-api/std", + "sp-application-crypto/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs new file mode 100644 index 0000000000000..7aab93bbcb973 --- /dev/null +++ b/primitives/beefy/src/commitment.rs @@ -0,0 +1,264 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sp_std::{cmp, prelude::*}; + +use crate::{crypto::Signature, ValidatorSetId}; + +/// A commitment signed by GRANDPA validators as part of BEEFY protocol. +/// +/// The commitment contains a [payload] extracted from the finalized block at height [block_number]. +/// GRANDPA validators collect signatures on commitments and a stream of such signed commitments +/// (see [SignedCommitment]) forms the BEEFY protocol. +#[derive(Clone, Debug, PartialEq, Eq, codec::Encode, codec::Decode)] +pub struct Commitment { + /// The payload being signed. + /// + /// This should be some form of cumulative representation of the chain (think MMR root hash). + /// The payload should also contain some details that allow the light client to verify next + /// validator set. The protocol does not enforce any particular format of this data, + /// nor how often it should be present in commitments, however the light client has to be + /// provided with full validator set whenever it performs the transition (i.e. importing first + /// block with [validator_set_id] incremented). + pub payload: TPayload, + + /// Finalized block number this commitment is for. + /// + /// GRANDPA validators agree on a block they create a commitment for and start collecting + /// signatures. This process is called a round. + /// There might be multiple rounds in progress (depending on the block choice rule), however + /// since the payload is supposed to be cumulative, it is not required to import all + /// commitments. + /// BEEFY light client is expected to import at least one commitment per epoch, + /// but is free to import as many as it requires. + pub block_number: TBlockNumber, + + /// BEEFY validator set supposed to sign this commitment. + /// + /// Validator set is changing once per epoch. The Light Client must be provided by details + /// about the validator set whenever it's importing first commitment with a new + /// `validator_set_id`. Validator set data MUST be verifiable, for instance using [payload] + /// information. + pub validator_set_id: ValidatorSetId, +} + +impl cmp::PartialOrd for Commitment +where + TBlockNumber: cmp::Ord, + TPayload: cmp::Eq, +{ + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl cmp::Ord for Commitment +where + TBlockNumber: cmp::Ord, + TPayload: cmp::Eq, +{ + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.validator_set_id + .cmp(&other.validator_set_id) + .then_with(|| self.block_number.cmp(&other.block_number)) + } +} + +/// A commitment with matching GRANDPA validators' signatures. +#[derive(Clone, Debug, PartialEq, Eq, codec::Encode, codec::Decode)] +pub struct SignedCommitment { + /// The commitment signatures are collected for. + pub commitment: Commitment, + /// GRANDPA validators' signatures for the commitment. + /// + /// The length of this `Vec` must match number of validators in the current set (see + /// [Commitment::validator_set_id]). + pub signatures: Vec>, +} + +impl SignedCommitment { + /// Return the number of collected signatures. + pub fn no_of_signatures(&self) -> usize { + self.signatures.iter().filter(|x| x.is_some()).count() + } +} + +/// A [SignedCommitment] with a version number. This variant will be appended +/// to the block justifications for the block for which the signed commitment +/// has been generated. +#[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] +pub enum VersionedCommitment { + #[codec(index = 1)] + /// Current active version + V1(SignedCommitment), +} + +#[cfg(test)] +mod tests { + + use sp_core::{keccak_256, Pair}; + use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr}; + + use super::*; + use codec::Decode; + + use crate::{crypto, KEY_TYPE}; + + type TestCommitment = Commitment; + type TestSignedCommitment = SignedCommitment; + type TestVersionedCommitment = VersionedCommitment; + + // The mock signatures are equivalent to the ones produced by the BEEFY keystore + fn mock_signatures() -> (crypto::Signature, crypto::Signature) { + let store: SyncCryptoStorePtr = KeyStore::new().into(); + + let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap(); + let _ = + SyncCryptoStore::insert_unknown(&*store, KEY_TYPE, "//Alice", alice.public().as_ref()) + .unwrap(); + + let msg = keccak_256(b"This is the first message"); + let sig1 = SyncCryptoStore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg) + .unwrap() + .unwrap(); + + let msg = keccak_256(b"This is the second message"); + let sig2 = SyncCryptoStore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg) + .unwrap() + .unwrap(); + + (sig1.into(), sig2.into()) + } + + #[test] + fn commitment_encode_decode() { + // given + let commitment: TestCommitment = + Commitment { payload: "Hello World!".into(), block_number: 5, validator_set_id: 0 }; + + // when + let encoded = codec::Encode::encode(&commitment); + let decoded = TestCommitment::decode(&mut &*encoded); + + // then + assert_eq!(decoded, Ok(commitment)); + assert_eq!( + encoded, + hex_literal::hex!( + "3048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000" + ) + ); + } + + #[test] + fn signed_commitment_encode_decode() { + // given + let commitment: TestCommitment = + Commitment { payload: "Hello World!".into(), block_number: 5, validator_set_id: 0 }; + + let sigs = mock_signatures(); + + let signed = SignedCommitment { + commitment, + signatures: vec![None, None, Some(sigs.0), Some(sigs.1)], + }; + + // when + let encoded = codec::Encode::encode(&signed); + let decoded = TestSignedCommitment::decode(&mut &*encoded); + + // then + assert_eq!(decoded, Ok(signed)); + assert_eq!( + encoded, + hex_literal::hex!( + "3048656c6c6f20576f726c64210500000000000000000000000000000000000000000000001000 + 0001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d + 10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a + 2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a00" + ) + ); + } + + #[test] + fn signed_commitment_count_signatures() { + // given + let commitment: TestCommitment = + Commitment { payload: "Hello World!".into(), block_number: 5, validator_set_id: 0 }; + + let sigs = mock_signatures(); + + let mut signed = SignedCommitment { + commitment, + signatures: vec![None, None, Some(sigs.0), Some(sigs.1)], + }; + assert_eq!(signed.no_of_signatures(), 2); + + // when + signed.signatures[2] = None; + + // then + assert_eq!(signed.no_of_signatures(), 1); + } + + #[test] + fn commitment_ordering() { + fn commitment( + block_number: u128, + validator_set_id: crate::ValidatorSetId, + ) -> TestCommitment { + Commitment { payload: "Hello World!".into(), block_number, validator_set_id } + } + + // given + let a = commitment(1, 0); + let b = commitment(2, 1); + let c = commitment(10, 0); + let d = commitment(10, 1); + + // then + assert!(a < b); + assert!(a < c); + assert!(c < b); + assert!(c < d); + assert!(b < d); + } + + #[test] + fn versioned_commitment_encode_decode() { + let commitment: TestCommitment = + Commitment { payload: "Hello World!".into(), block_number: 5, validator_set_id: 0 }; + + let sigs = mock_signatures(); + + let signed = SignedCommitment { + commitment, + signatures: vec![None, None, Some(sigs.0), Some(sigs.1)], + }; + + let versioned = TestVersionedCommitment::V1(signed.clone()); + + let encoded = codec::Encode::encode(&versioned); + + assert_eq!(1, encoded[0]); + assert_eq!(encoded[1..], codec::Encode::encode(&signed)); + + let decoded = TestVersionedCommitment::decode(&mut &*encoded); + + assert_eq!(decoded, Ok(versioned)); + } +} diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs new file mode 100644 index 0000000000000..790b915ab98db --- /dev/null +++ b/primitives/beefy/src/lib.rs @@ -0,0 +1,137 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] + +//! Primitives for BEEFY protocol. +//! +//! The crate contains shared data types used by BEEFY protocol and documentation (in a form of +//! code) for building a BEEFY light client. +//! +//! BEEFY is a gadget that runs alongside another finality gadget (for instance GRANDPA). +//! For simplicity (and the initially intended use case) the documentation says GRANDPA in places +//! where a more abstract "Finality Gadget" term could be used, but there is no reason why BEEFY +//! wouldn't run with some other finality scheme. +//! BEEFY validator set is supposed to be tracking the Finality Gadget validator set, but note that +//! it will use a different set of keys. For Polkadot use case we plan to use `secp256k1` for BEEFY, +//! while GRANDPA uses `ed25519`. + +mod commitment; +pub mod mmr; +pub mod witness; + +pub use commitment::{Commitment, SignedCommitment, VersionedCommitment}; + +use codec::{Codec, Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::H256; +use sp_std::prelude::*; + +/// Key type for BEEFY module. +pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"beef"); + +/// BEEFY cryptographic types +/// +/// This module basically introduces three crypto types: +/// - `crypto::Pair` +/// - `crypto::Public` +/// - `crypto::Signature` +/// +/// Your code should use the above types as concrete types for all crypto related +/// functionality. +/// +/// The current underlying crypto scheme used is ECDSA. This can be changed, +/// without affecting code restricted against the above listed crypto types. +pub mod crypto { + use sp_application_crypto::{app_crypto, ecdsa}; + app_crypto!(ecdsa, crate::KEY_TYPE); + + /// Identity of a BEEFY authority using ECDSA as its crypto. + pub type AuthorityId = Public; + + /// Signature for a BEEFY authority using ECDSA as its crypto. + pub type AuthoritySignature = Signature; +} + +/// The `ConsensusEngineId` of BEEFY. +pub const BEEFY_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"BEEF"; + +/// Authority set id starts with zero at genesis +pub const GENESIS_AUTHORITY_SET_ID: u64 = 0; + +/// A typedef for validator set id. +pub type ValidatorSetId = u64; + +/// A set of BEEFY authorities, a.k.a. validators. +#[derive(Decode, Encode, Debug, PartialEq, Clone, TypeInfo)] +pub struct ValidatorSet { + /// Public keys of the validator set elements + pub validators: Vec, + /// Identifier of the validator set + pub id: ValidatorSetId, +} + +impl ValidatorSet { + /// Return an empty validator set with id of 0. + pub fn empty() -> Self { + Self { validators: Default::default(), id: Default::default() } + } +} + +/// The index of an authority. +pub type AuthorityIndex = u32; + +/// The type used to represent an MMR root hash. +pub type MmrRootHash = H256; + +/// A consensus log item for BEEFY. +#[derive(Decode, Encode, TypeInfo)] +pub enum ConsensusLog { + /// The authorities have changed. + #[codec(index = 1)] + AuthoritiesChange(ValidatorSet), + /// Disable the authority with given index. + #[codec(index = 2)] + OnDisabled(AuthorityIndex), + /// MMR root hash. + #[codec(index = 3)] + MmrRoot(MmrRootHash), +} + +/// BEEFY vote message. +/// +/// A vote message is a direct vote created by a BEEFY node on every voting round +/// and is gossiped to its peers. +#[derive(Debug, Decode, Encode, TypeInfo)] +pub struct VoteMessage { + /// Commit to information extracted from a finalized block + pub commitment: Commitment, + /// Node authority id + pub id: Id, + /// Node signature + pub signature: Signature, +} + +sp_api::decl_runtime_apis! { + /// API necessary for BEEFY voters. + pub trait BeefyApi + { + /// Return the current active BEEFY validator set + fn validator_set() -> ValidatorSet; + } +} diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs new file mode 100644 index 0000000000000..e428c0ea01215 --- /dev/null +++ b/primitives/beefy/src/mmr.rs @@ -0,0 +1,132 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! BEEFY + MMR utilties. +//! +//! While BEEFY can be used completely indepentently as an additional consensus gadget, +//! it is designed around a main use case of making bridging standalone networks together. +//! For that use case it's common to use some aggregated data structure (like MMR) to be +//! used in conjunction with BEEFY, to be able to efficiently prove any past blockchain data. +//! +//! This module contains primitives used by Polkadot implementation of the BEEFY+MMR bridge, +//! but we imagine they will be useful for other chains that either want to bridge with Polkadot +//! or are completely standalone, but heavily inspired by Polkadot. + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +/// A standard leaf that gets added every block to the MMR constructed by Substrate's `pallet_mmr`. +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] +pub struct MmrLeaf { + /// Version of the leaf format. + /// + /// Can be used to enable future format migrations and compatibility. + /// See [`MmrLeafVersion`] documentation for details. + pub version: MmrLeafVersion, + /// Current block parent number and hash. + pub parent_number_and_hash: (BlockNumber, Hash), + /// A merkle root of the next BEEFY authority set. + pub beefy_next_authority_set: BeefyNextAuthoritySet, + /// A merkle root of all registered parachain heads. + pub parachain_heads: MerkleRoot, +} + +/// A MMR leaf versioning scheme. +/// +/// Version is a single byte that constist of two components: +/// - `major` - 3 bits +/// - `minor` - 5 bits +/// +/// Any change in encoding that adds new items to the structure is considered non-breaking, hence +/// only requires an update of `minor` version. Any backward incompatible change (i.e. decoding to a +/// previous leaf format fails) should be indicated with `major` version bump. +/// +/// Given that adding new struct elements in SCALE is backward compatible (i.e. old format can be +/// still decoded, the new fields will simply be ignored). We expect the major version to be bumped +/// very rarely (hopefuly never). +#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode)] +pub struct MmrLeafVersion(u8); +impl MmrLeafVersion { + /// Create new version object from `major` and `minor` components. + /// + /// Panics if any of the component occupies more than 4 bits. + pub fn new(major: u8, minor: u8) -> Self { + if major > 0b111 || minor > 0b11111 { + panic!("Version components are too big."); + } + let version = (major << 5) + minor; + Self(version) + } + + /// Split the version into `major` and `minor` sub-components. + pub fn split(&self) -> (u8, u8) { + let major = self.0 >> 5; + let minor = self.0 & 0b11111; + (major, minor) + } +} + +/// Details of the next BEEFY authority set. +#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] +pub struct BeefyNextAuthoritySet { + /// Id of the next set. + /// + /// Id is required to correlate BEEFY signed commitments with the validator set. + /// Light Client can easily verify that the commitment witness it is getting is + /// produced by the latest validator set. + pub id: crate::ValidatorSetId, + /// Number of validators in the set. + /// + /// Some BEEFY Light Clients may use an interactive protocol to verify only subset + /// of signatures. We put set length here, so that these clients can verify the minimal + /// number of required signatures. + pub len: u32, + /// Merkle Root Hash build from BEEFY AuthorityIds. + /// + /// This is used by Light Clients to confirm that the commitments are signed by the correct + /// validator set. Light Clients using interactive protocol, might verify only subset of + /// signatures, hence don't require the full list here (will receive inclusion proofs). + pub root: MerkleRoot, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_construct_version_correctly() { + let tests = vec![(0, 0, 0b00000000), (7, 2, 0b11100010), (7, 31, 0b11111111)]; + + for (major, minor, version) in tests { + let v = MmrLeafVersion::new(major, minor); + assert_eq!(v.encode(), vec![version], "Encoding does not match."); + assert_eq!(v.split(), (major, minor)); + } + } + + #[test] + #[should_panic] + fn should_panic_if_major_too_large() { + MmrLeafVersion::new(8, 0); + } + + #[test] + #[should_panic] + fn should_panic_if_minor_too_large() { + MmrLeafVersion::new(0, 32); + } +} diff --git a/primitives/beefy/src/witness.rs b/primitives/beefy/src/witness.rs new file mode 100644 index 0000000000000..c28a464e72df5 --- /dev/null +++ b/primitives/beefy/src/witness.rs @@ -0,0 +1,162 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Primitives for light, 2-phase interactive verification protocol. +//! +//! Instead of submitting full list of signatures, it's possible to submit first a witness +//! form of [SignedCommitment]. +//! This can later be verified by the client requesting only some (out of all) signatures for +//! verification. This allows lowering the data and computation cost of verifying the +//! signed commitment. + +use sp_std::prelude::*; + +use crate::{ + commitment::{Commitment, SignedCommitment}, + crypto::Signature, +}; + +/// A light form of [SignedCommitment]. +/// +/// This is a light ("witness") form of the signed commitment. Instead of containing full list of +/// signatures, which might be heavy and expensive to verify, it only contains a bit vector of +/// validators which signed the original [SignedCommitment] and a merkle root of all signatures. +/// +/// This can be used by light clients for 2-phase interactive verification (for instance for +/// Ethereum Mainnet), in a commit-reveal like scheme, where first we submit only the signed +/// commitment witness and later on, the client picks only some signatures to verify at random. +#[derive(Debug, PartialEq, Eq, codec::Encode, codec::Decode)] +pub struct SignedCommitmentWitness { + /// The full content of the commitment. + pub commitment: Commitment, + + /// The bit vector of validators who signed the commitment. + pub signed_by: Vec, // TODO [ToDr] Consider replacing with bitvec crate + + /// A merkle root of signatures in the original signed commitment. + pub signatures_merkle_root: TMerkleRoot, +} + +impl + SignedCommitmentWitness +{ + /// Convert [SignedCommitment] into [SignedCommitmentWitness]. + /// + /// This takes a [SignedCommitment], which contains full signatures + /// and converts it into a witness form, which does not contain full signatures, + /// only a bit vector indicating which validators have signed the original [SignedCommitment] + /// and a merkle root of all signatures. + /// + /// Returns the full list of signatures along with the witness. + pub fn from_signed( + signed: SignedCommitment, + merkelize: TMerkelize, + ) -> (Self, Vec>) + where + TMerkelize: FnOnce(&[Option]) -> TMerkleRoot, + { + let SignedCommitment { commitment, signatures } = signed; + let signed_by = signatures.iter().map(|s| s.is_some()).collect(); + let signatures_merkle_root = merkelize(&signatures); + + (Self { commitment, signed_by, signatures_merkle_root }, signatures) + } +} + +#[cfg(test)] +mod tests { + + use sp_core::{keccak_256, Pair}; + use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr}; + + use super::*; + use codec::Decode; + + use crate::{crypto, KEY_TYPE}; + + type TestCommitment = Commitment; + type TestSignedCommitment = SignedCommitment; + type TestSignedCommitmentWitness = + SignedCommitmentWitness>>; + + // The mock signatures are equivalent to the ones produced by the BEEFY keystore + fn mock_signatures() -> (crypto::Signature, crypto::Signature) { + let store: SyncCryptoStorePtr = KeyStore::new().into(); + + let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap(); + let _ = + SyncCryptoStore::insert_unknown(&*store, KEY_TYPE, "//Alice", alice.public().as_ref()) + .unwrap(); + + let msg = keccak_256(b"This is the first message"); + let sig1 = SyncCryptoStore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg) + .unwrap() + .unwrap(); + + let msg = keccak_256(b"This is the second message"); + let sig2 = SyncCryptoStore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg) + .unwrap() + .unwrap(); + + (sig1.into(), sig2.into()) + } + + fn signed_commitment() -> TestSignedCommitment { + let commitment: TestCommitment = + Commitment { payload: "Hello World!".into(), block_number: 5, validator_set_id: 0 }; + + let sigs = mock_signatures(); + + SignedCommitment { commitment, signatures: vec![None, None, Some(sigs.0), Some(sigs.1)] } + } + + #[test] + fn should_convert_signed_commitment_to_witness() { + // given + let signed = signed_commitment(); + + // when + let (witness, signatures) = + TestSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec()); + + // then + assert_eq!(witness.signatures_merkle_root, signatures); + } + + #[test] + fn should_encode_and_decode_witness() { + // given + let signed = signed_commitment(); + let (witness, _) = TestSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec()); + + // when + let encoded = codec::Encode::encode(&witness); + let decoded = TestSignedCommitmentWitness::decode(&mut &*encoded); + + // then + assert_eq!(decoded, Ok(witness)); + assert_eq!( + encoded, + hex_literal::hex!( + "3048656c6c6f20576f726c64210500000000000000000000000000000000000000000000001000 + 00010110000001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e9 + 9a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd + 48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a00" + ) + ); + } +} From e254b24b4bd9eb14abb75df205706d38b585f60c Mon Sep 17 00:00:00 2001 From: Jimmy Chu Date: Fri, 24 Sep 2021 07:34:37 +0800 Subject: [PATCH 0021/1472] Fix gitlab command (#9843) --- .gitlab-ci.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c5cb6c571b475..fa986923708d3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -763,12 +763,14 @@ publish-rustdoc: - cp README.md /tmp/doc/ - git checkout gh-pages # Remove directories no longer necessary, as specified in $RUSTDOCS_DEPLOY_REFS. - # Also ensure $RUSTDOCS_DEPLOY_REFS is non-space + # Also ensure $RUSTDOCS_DEPLOY_REFS is not just empty spaces. + # Even though this block spans multiple lines, they are concatenated to run as a single line + # command, so note for the semi-colons in the inner-most code block. - if [[ ! -z ${RUSTDOCS_DEPLOY_REFS// } ]]; then for FILE in *; do if [[ ! " $RUSTDOCS_DEPLOY_REFS " =~ " $FILE " ]]; then - echo "Removing ${FILE}..." - rm -rf $FILE + echo "Removing ${FILE}..."; + rm -rf $FILE; fi done fi From 68e34234bc0a00b380e53ad8b21cf3ac47f82628 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Fri, 24 Sep 2021 15:30:38 +0800 Subject: [PATCH 0022/1472] beefy-gadget-rpc: fix toml warnings (#9854) Signed-off-by: koushiro --- client/beefy/rpc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 6bb5c5fcc668e..8af2fa3eac867 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -20,7 +20,7 @@ codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } -sp-runtime = { versin = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } beefy-gadget = { version = "4.0.0-dev", path = "../." } beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } From b00e05470787422aab31a09d7e1198148d0ec7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Fri, 24 Sep 2021 12:17:51 +0200 Subject: [PATCH 0023/1472] De-duplicate the dispatchable and the bare_* functions (#9838) --- frame/contracts/src/lib.rs | 208 ++++++++++++++++++++++--------------- 1 file changed, 125 insertions(+), 83 deletions(-) diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 77efcc6986e64..0d7e4cbf56474 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -104,7 +104,7 @@ pub use crate::{ schedule::{HostFnWeights, InstructionWeights, Limits, Schedule}, }; use crate::{ - exec::{Executable, Stack as ExecStack}, + exec::{AccountIdOf, ExecError, Executable, Stack as ExecStack}, gas::GasMeter, storage::{ContractInfo, DeletedContract, Storage}, wasm::PrefabWasmModule, @@ -112,13 +112,14 @@ use crate::{ }; use frame_support::{ dispatch::Dispatchable, + ensure, traits::{Contains, Currency, Get, Randomness, StorageVersion, Time}, weights::{GetDispatchInfo, PostDispatchInfo, Weight}, }; use frame_system::Pallet as System; use pallet_contracts_primitives::{ - Code, ContractAccessError, ContractExecResult, ContractInstantiateResult, GetStorageResult, - InstantiateReturnValue, + Code, ContractAccessError, ContractExecResult, ContractInstantiateResult, ExecReturnValue, + GetStorageResult, InstantiateReturnValue, }; use sp_core::{crypto::UncheckedFrom, Bytes}; use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup}; @@ -272,18 +273,8 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; - let mut gas_meter = GasMeter::new(gas_limit); - let schedule = T::Schedule::get(); - let result = ExecStack::>::run_call( - origin, - dest, - &mut gas_meter, - &schedule, - value, - data, - None, - ); - gas_meter.into_dispatch_result(result, T::WeightInfo::call()) + let output = Self::internal_call(origin, dest, value, gas_limit, data, None); + output.gas_meter.into_dispatch_result(output.result, T::WeightInfo::call()) } /// Instantiates a new contract from the supplied `code` optionally transferring @@ -325,26 +316,19 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let code_len = code.len() as u32; - ensure!(code_len <= T::Schedule::get().limits.code_len, Error::::CodeTooLarge); - let mut gas_meter = GasMeter::new(gas_limit); - let schedule = T::Schedule::get(); - let executable = PrefabWasmModule::from_code(code, &schedule)?; - let code_len = executable.code_len(); - ensure!(code_len <= T::Schedule::get().limits.code_len, Error::::CodeTooLarge); - let result = ExecStack::>::run_instantiate( + let salt_len = salt.len() as u32; + let output = Self::internal_instantiate( origin, - executable, - &mut gas_meter, - &schedule, endowment, + gas_limit, + Code::Upload(Bytes(code)), data, - &salt, + salt, None, - ) - .map(|(_address, output)| output); - gas_meter.into_dispatch_result( - result, - T::WeightInfo::instantiate_with_code(code_len / 1024, salt.len() as u32 / 1024), + ); + output.gas_meter.into_dispatch_result( + output.result.map(|(_address, result)| result), + T::WeightInfo::instantiate_with_code(code_len / 1024, salt_len / 1024), ) } @@ -365,22 +349,20 @@ pub mod pallet { salt: Vec, ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; - let mut gas_meter = GasMeter::new(gas_limit); - let schedule = T::Schedule::get(); - let executable = PrefabWasmModule::from_storage(code_hash, &schedule, &mut gas_meter)?; - let result = ExecStack::>::run_instantiate( + let salt_len = salt.len() as u32; + let output = Self::internal_instantiate( origin, - executable, - &mut gas_meter, - &schedule, endowment, + gas_limit, + Code::Existing(code_hash), data, - &salt, + salt, None, + ); + output.gas_meter.into_dispatch_result( + output.result.map(|(_address, output)| output), + T::WeightInfo::instantiate(salt_len / 1024), ) - .map(|(_address, output)| output); - gas_meter - .into_dispatch_result(result, T::WeightInfo::instantiate(salt.len() as u32 / 1024)) } } @@ -535,6 +517,20 @@ pub mod pallet { pub(crate) type DeletionQueue = StorageValue<_, Vec, ValueQuery>; } +/// Return type of the private [`Pallet::internal_call`] function. +type InternalCallOutput = InternalOutput; + +/// Return type of the private [`Pallet::internal_instantiate`] function. +type InternalInstantiateOutput = InternalOutput, ExecReturnValue)>; + +/// Return type of private helper functions. +struct InternalOutput { + /// The gas meter that was used to execute the call. + gas_meter: GasMeter, + /// The result of the call. + result: Result, +} + impl Pallet where T::AccountId: UncheckedFrom + AsRef<[u8]>, @@ -556,25 +552,16 @@ where dest: T::AccountId, value: BalanceOf, gas_limit: Weight, - input_data: Vec, + data: Vec, debug: bool, ) -> ContractExecResult { - let mut gas_meter = GasMeter::new(gas_limit); - let schedule = T::Schedule::get(); let mut debug_message = if debug { Some(Vec::new()) } else { None }; - let result = ExecStack::>::run_call( - origin, - dest, - &mut gas_meter, - &schedule, - value, - input_data, - debug_message.as_mut(), - ); + let output = + Self::internal_call(origin, dest, value, gas_limit, data, debug_message.as_mut()); ContractExecResult { - result: result.map_err(|r| r.error), - gas_consumed: gas_meter.gas_consumed(), - gas_required: gas_meter.gas_required(), + result: output.result.map_err(|r| r.error), + gas_consumed: output.gas_meter.gas_consumed(), + gas_required: output.gas_meter.gas_required(), debug_message: debug_message.unwrap_or_default(), } } @@ -601,38 +588,23 @@ where salt: Vec, debug: bool, ) -> ContractInstantiateResult { - let mut gas_meter = GasMeter::new(gas_limit); - let schedule = T::Schedule::get(); - let executable = match code { - Code::Upload(Bytes(binary)) => PrefabWasmModule::from_code(binary, &schedule), - Code::Existing(hash) => PrefabWasmModule::from_storage(hash, &schedule, &mut gas_meter), - }; - let executable = match executable { - Ok(executable) => executable, - Err(error) => - return ContractInstantiateResult { - result: Err(error.into()), - gas_consumed: gas_meter.gas_consumed(), - gas_required: gas_meter.gas_required(), - debug_message: Vec::new(), - }, - }; let mut debug_message = if debug { Some(Vec::new()) } else { None }; - let result = ExecStack::>::run_instantiate( + let output = Self::internal_instantiate( origin, - executable, - &mut gas_meter, - &schedule, endowment, + gas_limit, + code, data, - &salt, + salt, debug_message.as_mut(), - ) - .and_then(|(account_id, result)| Ok(InstantiateReturnValue { result, account_id })); + ); ContractInstantiateResult { - result: result.map_err(|e| e.error), - gas_consumed: gas_meter.gas_consumed(), - gas_required: gas_meter.gas_required(), + result: output + .result + .map(|(account_id, result)| InstantiateReturnValue { result, account_id }) + .map_err(|e| e.error), + gas_consumed: output.gas_meter.gas_consumed(), + gas_required: output.gas_meter.gas_required(), debug_message: debug_message.unwrap_or_default(), } } @@ -709,4 +681,74 @@ where ) -> frame_support::dispatch::DispatchResult { self::wasm::reinstrument(module, schedule) } + + /// Internal function that does the actual call. + /// + /// Called by dispatchables and public functions. + fn internal_call( + origin: T::AccountId, + dest: T::AccountId, + value: BalanceOf, + gas_limit: Weight, + data: Vec, + debug_message: Option<&mut Vec>, + ) -> InternalCallOutput { + let mut gas_meter = GasMeter::new(gas_limit); + let schedule = T::Schedule::get(); + let result = ExecStack::>::run_call( + origin, + dest, + &mut gas_meter, + &schedule, + value, + data, + debug_message, + ); + InternalCallOutput { gas_meter, result } + } + + /// Internal function that does the actual instantiation. + /// + /// Called by dispatchables and public functions. + fn internal_instantiate( + origin: T::AccountId, + endowment: BalanceOf, + gas_limit: Weight, + code: Code>, + data: Vec, + salt: Vec, + debug_message: Option<&mut Vec>, + ) -> InternalInstantiateOutput { + let mut gas_meter = GasMeter::new(gas_limit); + let schedule = T::Schedule::get(); + let try_exec = || { + let executable = match code { + Code::Upload(Bytes(binary)) => { + ensure!( + binary.len() as u32 <= schedule.limits.code_len, + >::CodeTooLarge + ); + let executable = PrefabWasmModule::from_code(binary, &schedule)?; + ensure!( + executable.code_len() <= schedule.limits.code_len, + >::CodeTooLarge + ); + executable + }, + Code::Existing(hash) => + PrefabWasmModule::from_storage(hash, &schedule, &mut gas_meter)?, + }; + ExecStack::>::run_instantiate( + origin, + executable, + &mut gas_meter, + &schedule, + endowment, + data, + &salt, + debug_message, + ) + }; + InternalInstantiateOutput { result: try_exec(), gas_meter } + } } From 2ab5cd2880b1ec798a7c2a72c29f995f54b45f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 24 Sep 2021 13:42:08 +0300 Subject: [PATCH 0024/1472] Prepare UI tests for rust 1.55 (#9637) * Prepare UI tests for rust 1.54 * Delete wrong_page.stderr * CI: run with a staging CI image * Revert "CI: run with a staging CI image" This reverts commit 66f5b00d14b50fd9d8fbf773f7e884f380697591. * CI: debug, again * LOG_TARGET is only used in std * Remove unnecessary unsafe * Fixes * Use correct rustc locally * FMT * Compile with benchmarking * Review feedback * Some ui tests * I know... * Fix wasm tests Co-authored-by: Denis P Co-authored-by: thiolliere --- .gitlab-ci.yml | 4 +- client/chain-spec/src/chain_spec.rs | 1 + client/db/src/storage_cache.rs | 1 + client/executor/runtime-test/src/lib.rs | 6 +- client/executor/src/native_executor.rs | 3 - client/network/src/protocol/message.rs | 8 +- client/service/src/client/call_executor.rs | 6 +- client/service/src/client/wasm_override.rs | 34 ++--- frame/contracts/src/benchmarking/mod.rs | 2 +- frame/grandpa/src/benchmarking.rs | 2 - .../merkle-mountain-range/src/benchmarking.rs | 2 - .../support/src/storage/bounded_btree_map.rs | 8 +- .../support/src/storage/bounded_btree_set.rs | 8 +- frame/support/src/storage/bounded_vec.rs | 8 +- frame/support/src/storage/weak_bounded_vec.rs | 8 +- frame/support/src/traits/hooks.rs | 4 +- .../no_std_genesis_config.stderr | 8 +- .../undefined_call_part.stderr | 6 +- .../undefined_event_part.stderr | 10 +- .../undefined_genesis_config_part.stderr | 8 +- .../undefined_inherent_part.stderr | 6 +- .../undefined_origin_part.stderr | 10 +- .../undefined_validate_unsigned_part.stderr | 6 +- ...ed_keyword_two_times_integrity_test.stderr | 2 +- ...eserved_keyword_two_times_on_initialize.rs | 2 + ...ved_keyword_two_times_on_initialize.stderr | 14 +- .../tests/derive_no_bound_ui/clone.stderr | 16 +- .../tests/derive_no_bound_ui/default.stderr | 16 +- .../call_argument_invalid_bound.stderr | 16 +- .../call_argument_invalid_bound_2.stderr | 16 +- .../call_argument_invalid_bound_3.stderr | 18 ++- .../pallet_ui/event_field_not_member.stderr | 16 +- .../tests/pallet_ui/event_not_in_trait.stderr | 2 +- .../genesis_default_not_satisfied.stderr | 2 +- .../pallet_ui/genesis_invalid_generic.stderr | 2 +- .../tests/pallet_ui/hooks_invalid_item.stderr | 8 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 142 +++++++++++------- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 142 +++++++++++------- .../pallet_ui/storage_info_unsatisfied.stderr | 6 +- .../storage_info_unsatisfied_nmap.stderr | 10 +- .../reserved_keyword/on_initialize.stderr | 10 +- frame/transaction-payment/src/lib.rs | 16 +- frame/transaction-storage/src/lib.rs | 4 +- .../ui/empty_impl_runtime_apis_call.stderr | 2 +- .../ui/impl_incorrect_method_signature.stderr | 4 +- .../ui/mock_advanced_block_id_by_value.stderr | 2 +- .../tests/ui/mock_only_self_reference.stderr | 4 +- ...reference_in_impl_runtime_apis_call.stderr | 4 +- primitives/io/src/lib.rs | 15 +- .../tests/ui/pass_by_enum_with_struct.stderr | 2 +- .../ui/pass_by_enum_with_value_variant.stderr | 2 +- .../ui/pass_by_inner_with_two_fields.stderr | 2 +- primitives/runtime/src/traits.rs | 1 + primitives/state-machine/src/backend.rs | 16 +- primitives/state-machine/src/ext.rs | 24 ++- primitives/state-machine/src/lib.rs | 27 ++-- .../src/overlayed_changes/mod.rs | 26 ++-- .../state-machine/src/trie_backend_essence.rs | 11 +- test-utils/runtime/client/src/trait_tests.rs | 1 - utils/wasm-builder/src/wasm_project.rs | 4 + 60 files changed, 431 insertions(+), 335 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fa986923708d3..2b3284d9e1a83 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -38,7 +38,9 @@ variables: &default-vars CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux:production" + # FIXME: revert me + # CI_IMAGE: "paritytech/ci-linux:production" + CI_IMAGE: "paritytech/ci-linux:staging-1.54.0" # FIXME set to release CARGO_UNLEASH_INSTALL_PARAMS: "--version 1.0.0-alpha.12" CARGO_UNLEASH_PKG_DEF: "--skip node node-* pallet-template pallet-example pallet-example-* subkey chain-spec-builder" diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index fcdb053c47c16..ff3a99760bd28 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -163,6 +163,7 @@ struct ClientSpec { // Never used, left only for backward compatibility. consensus_engine: (), #[serde(skip_serializing)] + #[allow(unused)] genesis: serde::de::IgnoredAny, /// Mapping from `block_hash` to `wasm_code`. /// diff --git a/client/db/src/storage_cache.rs b/client/db/src/storage_cache.rs index a895324a2e7b9..5fef0e5b12d08 100644 --- a/client/db/src/storage_cache.rs +++ b/client/db/src/storage_cache.rs @@ -1418,6 +1418,7 @@ mod qc { #[derive(Debug, Clone)] struct Node { hash: H256, + #[allow(unused)] parent: H256, state: KeyMap, changes: KeySet, diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index c9f7d6b1e2970..2b5699fa3f77a 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -91,7 +91,7 @@ sp_core::wasm_export_functions! { // This function dirties the **host** pages. I.e. we dirty 4KiB at a time and it will take // 16 writes to process a single wasm page. - let mut heap_ptr = heap_base as usize; + let heap_ptr = heap_base as usize; // Find the next wasm page boundary. let heap_ptr = round_up_to(heap_ptr, 65536); @@ -234,7 +234,7 @@ sp_core::wasm_export_functions! { match instance.get_global_val("test_global") { Some(sp_sandbox::Value::I64(val)) => val, None => 30, - val => 40, + _ => 40, } } @@ -362,7 +362,7 @@ sp_core::wasm_export_functions! { // It is expected that the given pointer is not allocated. fn check_and_set_in_heap(heap_base: u32, offset: u32) { let test_message = b"Hello invalid heap memory"; - let ptr = unsafe { (heap_base + offset) as *mut u8 }; + let ptr = (heap_base + offset) as *mut u8; let message_slice = unsafe { sp_std::slice::from_raw_parts_mut(ptr, test_message.len()) }; diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 38dba55b5f87c..77b1ec7abf4f2 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -101,8 +101,6 @@ pub struct WasmExecutor { host_functions: Arc>, /// WASM runtime cache. cache: Arc, - /// The size of the instances cache. - max_runtime_instances: usize, /// The path to a directory which the executor can leverage for a file cache, e.g. put there /// compiled artifacts. cache_path: Option, @@ -138,7 +136,6 @@ impl WasmExecutor { default_heap_pages: default_heap_pages.unwrap_or(DEFAULT_HEAP_PAGES), host_functions: Arc::new(host_functions), cache: Arc::new(RuntimeCache::new(max_runtime_instances, cache_path.clone())), - max_runtime_instances, cache_path, } } diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index 8938c27aeddd8..001f6cbd7e455 100644 --- a/client/network/src/protocol/message.rs +++ b/client/network/src/protocol/message.rs @@ -143,10 +143,10 @@ pub struct RemoteReadResponse { /// Announcement summary used for debug logging. #[derive(Debug)] pub struct AnnouncementSummary { - block_hash: H::Hash, - number: H::Number, - parent_hash: H::Hash, - state: Option, + pub block_hash: H::Hash, + pub number: H::Number, + pub parent_hash: H::Hash, + pub state: Option, } impl generic::BlockAnnounce { diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 9b8774ce6d497..d7a8b6f227e8f 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -41,7 +41,7 @@ use std::{cell::RefCell, panic::UnwindSafe, result, sync::Arc}; pub struct LocalCallExecutor { backend: Arc, executor: E, - wasm_override: Option>, + wasm_override: Option, wasm_substitutes: WasmSubstitutes, spawn_handle: Box, client_config: ClientConfig, @@ -62,7 +62,7 @@ where let wasm_override = client_config .wasm_runtime_overrides .as_ref() - .map(|p| WasmOverride::new(p.clone(), executor.clone())) + .map(|p| WasmOverride::new(p.clone(), &executor)) .transpose()?; let wasm_substitutes = WasmSubstitutes::new( @@ -371,7 +371,7 @@ mod tests { 1, ); - let overrides = crate::client::wasm_override::dummy_overrides(&executor); + let overrides = crate::client::wasm_override::dummy_overrides(); let onchain_code = WrappedRuntimeCode(substrate_test_runtime::wasm_binary_unwrap().into()); let onchain_code = RuntimeCode { code_fetcher: &onchain_code, diff --git a/client/service/src/client/wasm_override.rs b/client/service/src/client/wasm_override.rs index 6d5a071269d4d..3d28467a9cbd9 100644 --- a/client/service/src/client/wasm_override.rs +++ b/client/service/src/client/wasm_override.rs @@ -104,22 +104,19 @@ impl From for sp_blockchain::Error { /// Scrapes WASM from a folder and returns WASM from that folder /// if the runtime spec version matches. #[derive(Clone, Debug)] -pub struct WasmOverride { +pub struct WasmOverride { // Map of runtime spec version -> Wasm Blob overrides: HashMap, - executor: E, } -impl WasmOverride -where - E: RuntimeVersionOf + Clone + 'static, -{ - pub fn new

(path: P, executor: E) -> Result +impl WasmOverride { + pub fn new(path: P, executor: &E) -> Result where P: AsRef, + E: RuntimeVersionOf, { - let overrides = Self::scrape_overrides(path.as_ref(), &executor)?; - Ok(Self { overrides, executor }) + let overrides = Self::scrape_overrides(path.as_ref(), executor)?; + Ok(Self { overrides }) } /// Gets an override by it's runtime spec version. @@ -131,7 +128,10 @@ where /// Scrapes a folder for WASM runtimes. /// Returns a hashmap of the runtime version and wasm runtime code. - fn scrape_overrides(dir: &Path, executor: &E) -> Result> { + fn scrape_overrides(dir: &Path, executor: &E) -> Result> + where + E: RuntimeVersionOf, + { let handle_err = |e: std::io::Error| -> sp_blockchain::Error { WasmOverrideError::Io(dir.to_owned(), e).into() }; @@ -176,11 +176,14 @@ where Ok(overrides) } - fn runtime_version( + fn runtime_version( executor: &E, code: &WasmBlob, heap_pages: Option, - ) -> Result { + ) -> Result + where + E: RuntimeVersionOf, + { let mut ext = BasicExternalities::default(); executor .runtime_version(&mut ext, &code.runtime_code(heap_pages)) @@ -190,15 +193,12 @@ where /// Returns a WasmOverride struct filled with dummy data for testing. #[cfg(test)] -pub fn dummy_overrides(executor: &E) -> WasmOverride -where - E: RuntimeVersionOf + Clone + 'static, -{ +pub fn dummy_overrides() -> WasmOverride { let mut overrides = HashMap::new(); overrides.insert(0, WasmBlob::new(vec![0, 0, 0, 0, 0, 0, 0, 0])); overrides.insert(1, WasmBlob::new(vec![1, 1, 1, 1, 1, 1, 1, 1])); overrides.insert(2, WasmBlob::new(vec![2, 2, 2, 2, 2, 2, 2, 2])); - WasmOverride { overrides, executor: executor.clone() } + WasmOverride { overrides } } #[cfg(test)] diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index db657e618322e..981af218ea5a2 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -2241,7 +2241,7 @@ benchmarks! { ); } #[cfg(not(feature = "std"))] - return Err("Run this bench with a native runtime in order to see the schedule.".into()); + Err("Run this bench with a native runtime in order to see the schedule.")?; }: {} // Execute one erc20 transfer using the ink! erc20 example contract. diff --git a/frame/grandpa/src/benchmarking.rs b/frame/grandpa/src/benchmarking.rs index b0f70adb6061d..815a18d13531e 100644 --- a/frame/grandpa/src/benchmarking.rs +++ b/frame/grandpa/src/benchmarking.rs @@ -17,8 +17,6 @@ //! Benchmarks for the GRANDPA pallet. -#![cfg_attr(not(feature = "std"), no_std)] - use super::{Pallet as Grandpa, *}; use frame_benchmarking::benchmarks; use frame_system::RawOrigin; diff --git a/frame/merkle-mountain-range/src/benchmarking.rs b/frame/merkle-mountain-range/src/benchmarking.rs index 2680b3d030067..c269afb75855c 100644 --- a/frame/merkle-mountain-range/src/benchmarking.rs +++ b/frame/merkle-mountain-range/src/benchmarking.rs @@ -17,8 +17,6 @@ //! Benchmarks for the MMR pallet. -#![cfg_attr(not(feature = "std"), no_std)] - use crate::*; use frame_benchmarking::{benchmarks_instance_pallet, impl_benchmark_test_suite}; use frame_support::traits::OnInitialize; diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index d0c0aa7c4f155..404814cb81693 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -20,7 +20,7 @@ use crate::{storage::StorageDecodeLength, traits::Get}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_std::{ - borrow::Borrow, collections::btree_map::BTreeMap, convert::TryFrom, fmt, marker::PhantomData, + borrow::Borrow, collections::btree_map::BTreeMap, convert::TryFrom, marker::PhantomData, ops::Deref, }; @@ -173,12 +173,12 @@ where } #[cfg(feature = "std")] -impl fmt::Debug for BoundedBTreeMap +impl std::fmt::Debug for BoundedBTreeMap where - BTreeMap: fmt::Debug, + BTreeMap: std::fmt::Debug, S: Get, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("BoundedBTreeMap").field(&self.0).field(&Self::bound()).finish() } } diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index 182884e655dd2..f74ff12854a58 100644 --- a/frame/support/src/storage/bounded_btree_set.rs +++ b/frame/support/src/storage/bounded_btree_set.rs @@ -20,7 +20,7 @@ use crate::{storage::StorageDecodeLength, traits::Get}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_std::{ - borrow::Borrow, collections::btree_set::BTreeSet, convert::TryFrom, fmt, marker::PhantomData, + borrow::Borrow, collections::btree_set::BTreeSet, convert::TryFrom, marker::PhantomData, ops::Deref, }; @@ -157,12 +157,12 @@ where } #[cfg(feature = "std")] -impl fmt::Debug for BoundedBTreeSet +impl std::fmt::Debug for BoundedBTreeSet where - BTreeSet: fmt::Debug, + BTreeSet: std::fmt::Debug, S: Get, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("BoundedBTreeSet").field(&self.0).field(&Self::bound()).finish() } } diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index b45c294f8d4a4..44eaab905423b 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -28,7 +28,7 @@ use core::{ ops::{Deref, Index, IndexMut}, slice::SliceIndex, }; -use sp_std::{convert::TryFrom, fmt, marker::PhantomData, prelude::*}; +use sp_std::{convert::TryFrom, marker::PhantomData, prelude::*}; /// A bounded vector. /// @@ -201,12 +201,12 @@ impl Default for BoundedVec { } #[cfg(feature = "std")] -impl fmt::Debug for BoundedVec +impl std::fmt::Debug for BoundedVec where - T: fmt::Debug, + T: std::fmt::Debug, S: Get, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("BoundedVec").field(&self.0).field(&Self::bound()).finish() } } diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 9c30c45c3e2e1..4655c809e014b 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -27,7 +27,7 @@ use core::{ ops::{Deref, Index, IndexMut}, slice::SliceIndex, }; -use sp_std::{convert::TryFrom, fmt, marker::PhantomData, prelude::*}; +use sp_std::{convert::TryFrom, marker::PhantomData, prelude::*}; /// A weakly bounded vector. /// @@ -171,12 +171,12 @@ impl Default for WeakBoundedVec { } #[cfg(feature = "std")] -impl fmt::Debug for WeakBoundedVec +impl std::fmt::Debug for WeakBoundedVec where - T: fmt::Debug, + T: std::fmt::Debug, S: Get, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("WeakBoundedVec").field(&self.0).field(&Self::bound()).finish() } } diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index adba88e5acbf3..2a8b0a156247a 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -19,7 +19,7 @@ use impl_trait_for_tuples::impl_for_tuples; use sp_arithmetic::traits::Saturating; -use sp_runtime::traits::{AtLeast32BitUnsigned, MaybeSerializeDeserialize}; +use sp_runtime::traits::AtLeast32BitUnsigned; /// The block initialization trait. /// @@ -294,7 +294,7 @@ pub trait Hooks { /// A trait to define the build function of a genesis config, T and I are placeholder for pallet /// trait and pallet instance. #[cfg(feature = "std")] -pub trait GenesisBuild: Default + MaybeSerializeDeserialize { +pub trait GenesisBuild: Default + sp_runtime::traits::MaybeSerializeDeserialize { /// The build function is called within an externalities allowing storage APIs. /// Thus one can write to storage using regular pallet storages. fn build(&self); diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr index 5bc831f58988b..3dc7fcda9f18a 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr @@ -10,7 +10,7 @@ error: `Pallet` does not have the std feature enabled, this will cause the `test 22 | | } | |_^ | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `test_pallet::__substrate_genesis_config_check::is_std_enabled_for_genesis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0433]: failed to resolve: use of undeclared crate or module `system` --> $DIR/no_std_genesis_config.rs:19:11 @@ -30,7 +30,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 22 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this enum | 1 | use frame_system::RawOrigin; @@ -48,7 +48,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 22 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | 1 | use frame_support_test::Pallet; @@ -70,7 +70,7 @@ error[E0412]: cannot find type `GenesisConfig` in crate `test_pallet` 22 | | } | |_^ not found in `test_pallet` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this struct | 1 | use frame_system::GenesisConfig; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr index 8781fe0df201a..2629cf4101923 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::call] defined, perhaps you should remove 31 | | } | |_- in this macro invocation | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_call_check::is_call_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0433]: failed to resolve: use of undeclared crate or module `system` --> $DIR/undefined_call_part.rs:28:11 @@ -33,7 +33,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this enum | 1 | use frame_system::RawOrigin; @@ -51,7 +51,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | 1 | use crate::pallet::Pallet; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index fa837698aa642..af69b79ed1a64 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::event] defined, perhaps you should remov 31 | | } | |_- in this macro invocation | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_event_check::is_event_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0433]: failed to resolve: use of undeclared crate or module `system` --> $DIR/undefined_event_part.rs:28:11 @@ -33,7 +33,7 @@ error[E0412]: cannot find type `Event` in module `pallet` 31 | | } | |_^ not found in `pallet` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this enum | 1 | use frame_system::Event; @@ -51,7 +51,7 @@ error[E0412]: cannot find type `Event` in module `pallet` 31 | | } | |_^ not found in `pallet` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | 1 | use crate::Event; @@ -71,7 +71,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this enum | 1 | use frame_system::RawOrigin; @@ -89,7 +89,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | 1 | use crate::pallet::Pallet; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr index 699f66a414ed2..bfedb921bca44 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::genesis_config] defined, perhaps you sho 31 | | } | |_- in this macro invocation | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_genesis_config_check::is_genesis_config_defined` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0433]: failed to resolve: use of undeclared crate or module `system` --> $DIR/undefined_genesis_config_part.rs:28:17 @@ -33,7 +33,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this enum | 1 | use frame_system::RawOrigin; @@ -51,7 +51,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | 1 | use crate::pallet::Pallet; @@ -75,7 +75,7 @@ error[E0412]: cannot find type `GenesisConfig` in module `pallet` 31 | | } | |_^ not found in `pallet` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this struct | 1 | use frame_system::GenesisConfig; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr index 88ff9ee910937..50dde1108263b 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::inherent] defined, perhaps you should re 31 | | } | |_- in this macro invocation | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_inherent_check::is_inherent_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0433]: failed to resolve: use of undeclared crate or module `system` --> $DIR/undefined_inherent_part.rs:28:11 @@ -33,7 +33,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this enum | 1 | use frame_system::RawOrigin; @@ -51,7 +51,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | 1 | use crate::pallet::Pallet; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr index 3b3aa75c1ea08..b5f3ec4d381bc 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::origin] defined, perhaps you should remo 31 | | } | |_- in this macro invocation | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_origin_check::is_origin_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0433]: failed to resolve: use of undeclared crate or module `system` --> $DIR/undefined_origin_part.rs:28:11 @@ -33,7 +33,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this enum | 1 | use frame_system::RawOrigin; @@ -51,7 +51,7 @@ error[E0412]: cannot find type `Origin` in module `pallet` 31 | | } | |_^ not found in `pallet` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this type alias | 1 | use frame_system::Origin; @@ -69,7 +69,7 @@ error[E0412]: cannot find type `Origin` in module `pallet` 31 | | } | |_^ not found in `pallet` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | 1 | use crate::Origin; @@ -89,7 +89,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | 1 | use crate::pallet::Pallet; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr index ac12c56d5c279..12bdce67cf038 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::validate_unsigned] defined, perhaps you 31 | | } | |_- in this macro invocation | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0433]: failed to resolve: use of undeclared crate or module `system` --> $DIR/undefined_validate_unsigned_part.rs:28:11 @@ -33,7 +33,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this enum | 1 | use frame_system::RawOrigin; @@ -51,7 +51,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `system` 31 | | } | |_^ not found in `system` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing one of these items | 1 | use crate::pallet::Pallet; diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr index 3bf5f58b43a39..86c427d8080be 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr @@ -10,7 +10,7 @@ error: `integrity_test` can only be passed once as input. 7 | | } | |_^ | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0601]: `main` function not found in crate `$CRATE` --> $DIR/reserved_keyword_two_times_integrity_test.rs:1:1 diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs index ddde7c72c1cc5..18aaec12c5f39 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs @@ -9,3 +9,5 @@ frame_support::decl_module! { } } } + +fn main() {} diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr index 2911d7ded8a23..369be77b8d249 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr @@ -10,16 +10,4 @@ error: `on_initialize` can only be passed once as input. 11 | | } | |_^ | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0601]: `main` function not found in crate `$CRATE` - --> $DIR/reserved_keyword_two_times_on_initialize.rs:1:1 - | -1 | / frame_support::decl_module! { -2 | | pub struct Module for enum Call where origin: T::Origin, system=self { -3 | | fn on_initialize() -> Weight { -4 | | 0 -... | -10 | | } -11 | | } - | |_^ consider adding a `main` function to `$DIR/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs` + = note: this error originates in the macro `$crate::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/derive_no_bound_ui/clone.stderr b/frame/support/test/tests/derive_no_bound_ui/clone.stderr index 4b253ad12451b..050b576c8b9ed 100644 --- a/frame/support/test/tests/derive_no_bound_ui/clone.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/clone.stderr @@ -1,7 +1,11 @@ error[E0277]: the trait bound `::C: Clone` is not satisfied - --> $DIR/clone.rs:7:2 - | -7 | c: T::C, - | ^ the trait `Clone` is not implemented for `::C` - | - = note: required by `clone` + --> $DIR/clone.rs:7:2 + | +7 | c: T::C, + | ^ the trait `Clone` is not implemented for `::C` + | +note: required by `clone` + --> $DIR/clone.rs:121:5 + | +121 | fn clone(&self) -> Self; + | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/derive_no_bound_ui/default.stderr b/frame/support/test/tests/derive_no_bound_ui/default.stderr index d58b5e9185268..7608f877a3b56 100644 --- a/frame/support/test/tests/derive_no_bound_ui/default.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/default.stderr @@ -1,7 +1,11 @@ error[E0277]: the trait bound `::C: std::default::Default` is not satisfied - --> $DIR/default.rs:7:2 - | -7 | c: T::C, - | ^ the trait `std::default::Default` is not implemented for `::C` - | - = note: required by `std::default::Default::default` + --> $DIR/default.rs:7:2 + | +7 | c: T::C, + | ^ the trait `std::default::Default` is not implemented for `::C` + | +note: required by `std::default::Default::default` + --> $DIR/default.rs:116:5 + | +116 | fn default() -> Self; + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index d1b040c16091f..3d1ea1adc9862 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -9,12 +9,16 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` = note: required for the cast to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> $DIR/call_argument_invalid_bound.rs:20:36 - | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `Clone` is not implemented for `::Bar` - | - = note: required by `clone` + --> $DIR/call_argument_invalid_bound.rs:20:36 + | +20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^ the trait `Clone` is not implemented for `::Bar` + | +note: required by `clone` + --> $DIR/clone.rs:121:5 + | +121 | fn clone(&self) -> Self; + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `==` cannot be applied to type `&::Bar` --> $DIR/call_argument_invalid_bound.rs:20:36 diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index 84d4863672957..c9ff843103b3b 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -9,12 +9,16 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` = note: required for the cast to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> $DIR/call_argument_invalid_bound_2.rs:20:36 - | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `Clone` is not implemented for `::Bar` - | - = note: required by `clone` + --> $DIR/call_argument_invalid_bound_2.rs:20:36 + | +20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^ the trait `Clone` is not implemented for `::Bar` + | +note: required by `clone` + --> $DIR/clone.rs:121:5 + | +121 | fn clone(&self) -> Self; + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `==` cannot be applied to type `&::Bar` --> $DIR/call_argument_invalid_bound_2.rs:20:36 diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr index 73513907e85f3..144b7e12bd664 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr @@ -5,17 +5,21 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` | ^^^ `Bar` cannot be formatted using `{:?}` | = help: the trait `std::fmt::Debug` is not implemented for `Bar` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` + = note: add `#[derive(Debug)]` to `Bar` or manually `impl std::fmt::Debug for Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Bar` = note: required for the cast to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `Bar: Clone` is not satisfied - --> $DIR/call_argument_invalid_bound_3.rs:22:36 - | -22 | pub fn foo(origin: OriginFor, bar: Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `Clone` is not implemented for `Bar` - | - = note: required by `clone` + --> $DIR/call_argument_invalid_bound_3.rs:22:36 + | +22 | pub fn foo(origin: OriginFor, bar: Bar) -> DispatchResultWithPostInfo { + | ^^^ the trait `Clone` is not implemented for `Bar` + | +note: required by `clone` + --> $DIR/clone.rs:121:5 + | +121 | fn clone(&self) -> Self; + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `==` cannot be applied to type `&Bar` --> $DIR/call_argument_invalid_bound_3.rs:22:36 diff --git a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr index d48012a6c952d..bf4c05bb4e5b5 100644 --- a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr +++ b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr @@ -1,10 +1,14 @@ error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> $DIR/event_field_not_member.rs:23:7 - | -23 | B { b: T::Bar }, - | ^ the trait `Clone` is not implemented for `::Bar` - | - = note: required by `clone` + --> $DIR/event_field_not_member.rs:23:7 + | +23 | B { b: T::Bar }, + | ^ the trait `Clone` is not implemented for `::Bar` + | +note: required by `clone` + --> $DIR/clone.rs:121:5 + | +121 | fn clone(&self) -> Self; + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `==` cannot be applied to type `&::Bar` --> $DIR/event_field_not_member.rs:23:7 diff --git a/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr b/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr index dd96c700ce7e5..e3126ad6a85dc 100644 --- a/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr +++ b/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr @@ -4,4 +4,4 @@ error: Invalid usage of Event, `Config` contains no associated type `Event`, but 1 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr b/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr index 4bc3cfdcbf9b7..ad8300b8d89b8 100644 --- a/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr +++ b/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr @@ -6,5 +6,5 @@ error[E0277]: the trait bound `pallet::GenesisConfig: std::default::Default` is | ::: $WORKSPACE/frame/support/src/traits/hooks.rs | - | pub trait GenesisBuild: Default + MaybeSerializeDeserialize { + | pub trait GenesisBuild: Default + sp_runtime::traits::MaybeSerializeDeserialize { | ------- required by this bound in `GenesisBuild` diff --git a/frame/support/test/tests/pallet_ui/genesis_invalid_generic.stderr b/frame/support/test/tests/pallet_ui/genesis_invalid_generic.stderr index f451f7b16aee5..f57b4a61c80c5 100644 --- a/frame/support/test/tests/pallet_ui/genesis_invalid_generic.stderr +++ b/frame/support/test/tests/pallet_ui/genesis_invalid_generic.stderr @@ -10,4 +10,4 @@ error: expected `<` 1 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr b/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr index 3d7303fafdcf5..ecb57bec37a7b 100644 --- a/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr +++ b/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr @@ -2,14 +2,14 @@ error[E0107]: missing generics for trait `Hooks` --> $DIR/hooks_invalid_item.rs:12:18 | 12 | impl Hooks for Pallet {} - | ^^^^^ expected 1 type argument + | ^^^^^ expected 1 generic argument | -note: trait defined here, with 1 type parameter: `BlockNumber` +note: trait defined here, with 1 generic parameter: `BlockNumber` --> $DIR/hooks.rs:214:11 | 214 | pub trait Hooks { | ^^^^^ ----------- -help: use angle brackets to add missing type argument +help: add missing generic argument | 12 | impl Hooks for Pallet {} - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index 239de4dba949b..cd3032c49735a 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -1,77 +1,105 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 - | -20 | #[pallet::storage] - | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `build_metadata` + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + | +20 | #[pallet::storage] + | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `build_metadata` + --> $DIR/mod.rs:113:2 + | +113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + | +20 | #[pallet::storage] + | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Decode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `build_metadata` + --> $DIR/mod.rs:113:2 + | +113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + | +20 | #[pallet::storage] + | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `build_metadata` + --> $DIR/mod.rs:113:2 + | +113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + | +20 | #[pallet::storage] + | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Encode` for `Bar` + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `build_metadata` + --> $DIR/mod.rs:113:2 + | +113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 | -20 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `build_metadata` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 | -20 | #[pallet::storage] - | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` +9 | #[pallet::pallet] + | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `build_metadata` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 | -20 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `build_metadata` - -error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Decode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `partial_storage_info` - -error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `partial_storage_info` - -error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Encode` for `Bar` - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `partial_storage_info` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index a5bf32a0ef2d2..3d03af836986a 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -1,77 +1,105 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 - | -20 | #[pallet::storage] - | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `build_metadata` + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + | +20 | #[pallet::storage] + | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `build_metadata` + --> $DIR/mod.rs:113:2 + | +113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + | +20 | #[pallet::storage] + | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Decode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `build_metadata` + --> $DIR/mod.rs:113:2 + | +113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + | +20 | #[pallet::storage] + | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `build_metadata` + --> $DIR/mod.rs:113:2 + | +113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + | +20 | #[pallet::storage] + | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Encode` for `Bar` + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `build_metadata` + --> $DIR/mod.rs:113:2 + | +113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 | -20 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `build_metadata` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 | -20 | #[pallet::storage] - | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` +9 | #[pallet::pallet] + | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `build_metadata` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 | -20 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `build_metadata` - -error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Decode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `partial_storage_info` - -error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `partial_storage_info` - -error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Encode` for `Bar` - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `partial_storage_info` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index ad415911bc933..0ffb015e36bca 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -5,4 +5,8 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` - = note: required by `storage_info` +note: required by `storage_info` + --> $DIR/storage.rs:71:2 + | +71 | fn storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 6c92423c6a7fe..ffbc5aeea6b4f 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -4,6 +4,10 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied 10 | #[pallet::generate_storage_info] | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | - = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` - = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` - = note: required by `storage_info` + = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `NMapKey` + = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>` +note: required by `storage_info` + --> $DIR/storage.rs:71:2 + | +71 | fn storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/reserved_keyword/on_initialize.stderr b/frame/support/test/tests/reserved_keyword/on_initialize.stderr index 3df392dee9005..84e93fa52c2d9 100644 --- a/frame/support/test/tests/reserved_keyword/on_initialize.stderr +++ b/frame/support/test/tests/reserved_keyword/on_initialize.stderr @@ -4,7 +4,7 @@ error: Invalid call fn name: `on_finalize`, name is reserved and doesn't match e 28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) error: Invalid call fn name: `on_initialize`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. --> $DIR/on_initialize.rs:28:1 @@ -12,7 +12,7 @@ error: Invalid call fn name: `on_initialize`, name is reserved and doesn't match 28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) error: Invalid call fn name: `on_runtime_upgrade`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. --> $DIR/on_initialize.rs:28:1 @@ -20,7 +20,7 @@ error: Invalid call fn name: `on_runtime_upgrade`, name is reserved and doesn't 28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) error: Invalid call fn name: `offchain_worker`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. --> $DIR/on_initialize.rs:28:1 @@ -28,7 +28,7 @@ error: Invalid call fn name: `offchain_worker`, name is reserved and doesn't mat 28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) error: Invalid call fn name: `deposit_event`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. --> $DIR/on_initialize.rs:28:1 @@ -36,4 +36,4 @@ error: Invalid call fn name: `deposit_event`, name is reserved and doesn't match 28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index e3a3bccc3d39a..11dbcc010f67c 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -332,12 +332,7 @@ pub mod pallet { .unwrap(), ); - // This is the minimum value of the multiplier. Make sure that if we collapse to this - // value, we can recover with a reasonable amount of traffic. For this test we assert - // that if we collapse to minimum, the trend will be positive with a weight value - // which is 1% more than the target. - let min_value = T::FeeMultiplierUpdate::min(); - let mut target = T::FeeMultiplierUpdate::target() * + let target = T::FeeMultiplierUpdate::target() * T::BlockWeights::get().get(DispatchClass::Normal).max_total.expect( "Setting `max_total` for `Normal` dispatch class is not compatible with \ `transaction-payment` pallet.", @@ -348,10 +343,17 @@ pub mod pallet { // this is most likely because in a test setup we set everything to (). return } - target += addition; #[cfg(any(feature = "std", test))] sp_io::TestExternalities::new_empty().execute_with(|| { + // This is the minimum value of the multiplier. Make sure that if we collapse to + // this value, we can recover with a reasonable amount of traffic. For this test we + // assert that if we collapse to minimum, the trend will be positive with a weight + // value which is 1% more than the target. + let min_value = T::FeeMultiplierUpdate::min(); + + let target = target + addition; + >::set_block_consumed_resources(target, 0); let next = T::FeeMultiplierUpdate::convert(min_value); assert!( diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index 2fe3c04e0229f..bc31199d90391 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -37,7 +37,7 @@ use sp_runtime::traits::{BlakeTwo256, Hash, One, Saturating, Zero}; use sp_std::{prelude::*, result}; use sp_transaction_storage_proof::{ encode_index, random_chunk, InherentError, TransactionStorageProof, CHUNK_SIZE, - DEFAULT_STORAGE_PERIOD, INHERENT_IDENTIFIER, + INHERENT_IDENTIFIER, }; /// A type alias for the balance type from this pallet's point of view. @@ -380,7 +380,7 @@ pub mod pallet { Self { byte_fee: 10u32.into(), entry_fee: 1000u32.into(), - storage_period: DEFAULT_STORAGE_PERIOD.into(), + storage_period: sp_transaction_storage_proof::DEFAULT_STORAGE_PERIOD.into(), max_block_transactions: DEFAULT_MAX_BLOCK_TRANSACTIONS, max_transaction_size: DEFAULT_MAX_TRANSACTION_SIZE, } diff --git a/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.stderr b/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.stderr index b08f056b57d1c..bf201e8b55a78 100644 --- a/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.stderr +++ b/primitives/api/test/tests/ui/empty_impl_runtime_apis_call.stderr @@ -4,4 +4,4 @@ error: No api implementation given! 17 | sp_api::impl_runtime_apis! {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr index 9dd84c24b6781..2fb06c3565ea2 100644 --- a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr +++ b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr @@ -38,7 +38,7 @@ error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for tr | = note: expected fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option, Vec<_>) -> Result<_, _>` found fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option, Vec<_>) -> Result<_, _>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/impl_incorrect_method_signature.rs:17:1 @@ -52,7 +52,7 @@ error[E0308]: mismatched types 33 | | } | |_^ expected `u64`, found struct `std::string::String` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/impl_incorrect_method_signature.rs:19:11 diff --git a/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.stderr b/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.stderr index 47cd9e01d910f..befe67c1d0b4a 100644 --- a/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.stderr +++ b/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.stderr @@ -10,4 +10,4 @@ error: `BlockId` needs to be taken by reference and not by value! 19 | | } | |_^ | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/primitives/api/test/tests/ui/mock_only_self_reference.stderr b/primitives/api/test/tests/ui/mock_only_self_reference.stderr index 7385fe4745989..1b1d2553940a5 100644 --- a/primitives/api/test/tests/ui/mock_only_self_reference.stderr +++ b/primitives/api/test/tests/ui/mock_only_self_reference.stderr @@ -36,7 +36,7 @@ error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for tr | = note: expected fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option, Vec<_>) -> Result<_, _>` found fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option<()>, Vec<_>) -> Result<_, _>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0053]: method `Api_test2_runtime_api_impl` has an incompatible type for trait --> $DIR/mock_only_self_reference.rs:12:1 @@ -64,4 +64,4 @@ error[E0053]: method `Api_test2_runtime_api_impl` has an incompatible type for t | = note: expected fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option, Vec<_>) -> Result<_, _>` found fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option<()>, Vec<_>) -> Result<_, _>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index a0a16c4a493db..063cbff60f81e 100644 --- a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -38,7 +38,7 @@ error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for tr | = note: expected fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option, Vec<_>) -> Result<_, _>` found fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option<&u64>, Vec<_>) -> Result<_, _>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/type_reference_in_impl_runtime_apis_call.rs:17:1 @@ -52,7 +52,7 @@ error[E0308]: mismatched types 35 | | } | |_^ expected `u64`, found `&u64` | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/type_reference_in_impl_runtime_apis_call.rs:19:11 diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 5faeb59c72db6..78e6f0c847952 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -73,6 +73,7 @@ mod batch_verifier; #[cfg(feature = "std")] use batch_verifier::BatchVerifier; +#[cfg(feature = "std")] const LOG_TARGET: &str = "runtime::io"; /// Error verifying ECDSA signature @@ -1481,21 +1482,17 @@ mod allocator_impl { #[panic_handler] #[no_mangle] pub fn panic(info: &core::panic::PanicInfo) -> ! { - unsafe { - let message = sp_std::alloc::format!("{}", info); - logging::log(LogLevel::Error, "runtime", message.as_bytes()); - core::arch::wasm32::unreachable(); - } + let message = sp_std::alloc::format!("{}", info); + logging::log(LogLevel::Error, "runtime", message.as_bytes()); + core::arch::wasm32::unreachable(); } /// A default OOM handler for WASM environment. #[cfg(all(not(feature = "disable_oom"), not(feature = "std")))] #[alloc_error_handler] pub fn oom(_: core::alloc::Layout) -> ! { - unsafe { - logging::log(LogLevel::Error, "runtime", b"Runtime memory exhausted. Aborting"); - core::arch::wasm32::unreachable(); - } + logging::log(LogLevel::Error, "runtime", b"Runtime memory exhausted. Aborting"); + core::arch::wasm32::unreachable(); } /// Type alias for Externalities implementation used in tests. diff --git a/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr b/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr index c7ed1af3b1a03..44fb5a244e03d 100644 --- a/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr +++ b/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr @@ -4,4 +4,4 @@ error: `PassByEnum` only supports enums as input type. 3 | #[derive(PassByEnum)] | ^^^^^^^^^^ | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `PassByEnum` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr b/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr index f6c85ed2bba3e..633dc3bbe8bc4 100644 --- a/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr +++ b/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr @@ -4,4 +4,4 @@ error: `PassByEnum` only supports unit variants. 3 | #[derive(PassByEnum)] | ^^^^^^^^^^ | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `PassByEnum` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr b/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr index 9afbce76f0c23..0ffee00210e79 100644 --- a/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr +++ b/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr @@ -4,4 +4,4 @@ error: Only newtype/one field structs are supported by `PassByInner`! 3 | #[derive(PassByInner)] | ^^^^^^^^^^^ | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `PassByInner` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 65c063fde1696..6d79d740dc4e1 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1474,6 +1474,7 @@ macro_rules! impl_opaque_keys { #[macro_export] #[cfg(not(feature = "std"))] +#[doc(hidden)] macro_rules! impl_opaque_keys { { $( #[ $attr:meta ] )* diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index 1b1a732f8d0fc..7dcf92b06de06 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -21,9 +21,9 @@ use crate::{ trie_backend::TrieBackend, trie_backend_essence::TrieBackendStorage, ChildStorageCollection, StorageCollection, StorageKey, StorageValue, UsageInfo, }; -use codec::{Decode, Encode}; +use codec::Encode; use hash_db::Hasher; -use sp_core::storage::{well_known_keys, ChildInfo, TrackedStorageKey}; +use sp_core::storage::{ChildInfo, TrackedStorageKey}; #[cfg(feature = "std")] use sp_core::traits::RuntimeCode; use sp_std::vec::Vec; @@ -330,7 +330,11 @@ impl<'a, B: Backend, H: Hasher> sp_core::traits::FetchRuntimeCode for BackendRuntimeCode<'a, B, H> { fn fetch_runtime_code<'b>(&'b self) -> Option> { - self.backend.storage(well_known_keys::CODE).ok().flatten().map(Into::into) + self.backend + .storage(sp_core::storage::well_known_keys::CODE) + .ok() + .flatten() + .map(Into::into) } } @@ -348,17 +352,17 @@ where pub fn runtime_code(&self) -> Result { let hash = self .backend - .storage_hash(well_known_keys::CODE) + .storage_hash(sp_core::storage::well_known_keys::CODE) .ok() .flatten() .ok_or("`:code` hash not found")? .encode(); let heap_pages = self .backend - .storage(well_known_keys::HEAP_PAGES) + .storage(sp_core::storage::well_known_keys::HEAP_PAGES) .ok() .flatten() - .and_then(|d| Decode::decode(&mut &d[..]).ok()); + .and_then(|d| codec::Decode::decode(&mut &d[..]).ok()); Ok(RuntimeCode { code_fetcher: self, hash, heap_pages }) } diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index c9693ca6a88c1..c20d8492fb1f3 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -17,17 +17,15 @@ //! Concrete externalities implementation. -use crate::{ - backend::Backend, overlayed_changes::OverlayedExtensions, IndexOperation, OverlayedChanges, - StorageKey, StorageValue, -}; +#[cfg(feature = "std")] +use crate::overlayed_changes::OverlayedExtensions; +use crate::{backend::Backend, IndexOperation, OverlayedChanges, StorageKey, StorageValue}; use codec::{Decode, Encode, EncodeAppend}; use hash_db::Hasher; -use sp_core::{ - hexdisplay::HexDisplay, - storage::{well_known_keys::is_child_storage_key, ChildInfo, TrackedStorageKey}, -}; -use sp_externalities::{Extension, ExtensionStore, Extensions, Externalities}; +#[cfg(feature = "std")] +use sp_core::hexdisplay::HexDisplay; +use sp_core::storage::{well_known_keys::is_child_storage_key, ChildInfo, TrackedStorageKey}; +use sp_externalities::{Extension, ExtensionStore, Externalities}; use sp_trie::{empty_child_trie_root, trie_types::Layout}; #[cfg(feature = "std")] @@ -37,7 +35,7 @@ use sp_std::{ any::{Any, TypeId}, boxed::Box, cmp::Ordering, - fmt, vec, + vec, vec::Vec, }; #[cfg(feature = "std")] @@ -72,8 +70,8 @@ pub enum Error { } #[cfg(feature = "std")] -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match *self { Error::Backend(ref e) => write!(f, "Storage backend error: {}", e), Error::Executor(ref e) => write!(f, "Sub-call execution error: {}", e), @@ -139,7 +137,7 @@ where storage_transaction_cache: &'a mut StorageTransactionCache, backend: &'a B, changes_trie_state: Option>, - extensions: Option<&'a mut Extensions>, + extensions: Option<&'a mut sp_externalities::Extensions>, ) -> Self { Self { overlay, diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 05d2c6d20ccee..7bd0c645f3c00 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -55,11 +55,19 @@ pub use tracing::trace; #[cfg(not(feature = "std"))] #[macro_export] macro_rules! warn { - (target: $target:expr, $($arg:tt)+) => { - () + (target: $target:expr, $message:expr $( , $arg:ident )* $( , )?) => { + { + $( + let _ = &$arg; + )* + } }; - ($($arg:tt)+) => { - () + ($message:expr, $( $arg:expr, )*) => { + { + $( + let _ = &$arg; + )* + } }; } @@ -68,11 +76,12 @@ macro_rules! warn { #[cfg(not(feature = "std"))] #[macro_export] macro_rules! debug { - (target: $target:expr, $($arg:tt)+) => { - () - }; - ($($arg:tt)+) => { - () + (target: $target:expr, $message:expr $( , $arg:ident )* $( , )?) => { + { + $( + let _ = &$arg; + )* + } }; } diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index a0558e06a380e..cf7af1c9a6f3a 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -21,15 +21,7 @@ mod changeset; mod offchain; use self::changeset::OverlayedChangeSet; -use crate::{backend::Backend, stats::StateMachineStats}; -pub use offchain::OffchainOverlayedChanges; -use sp_std::{ - any::{Any, TypeId}, - boxed::Box, - vec::Vec, -}; - -use crate::{changes_trie::BlockNumber, DefaultError}; +use crate::{backend::Backend, changes_trie::BlockNumber, stats::StateMachineStats, DefaultError}; #[cfg(feature = "std")] use crate::{ changes_trie::{build_changes_trie, State as ChangesTrieState}, @@ -37,16 +29,23 @@ use crate::{ }; use codec::{Decode, Encode}; use hash_db::Hasher; +pub use offchain::OffchainOverlayedChanges; use sp_core::{ offchain::OffchainOverlayedChange, storage::{well_known_keys::EXTRINSIC_INDEX, ChildInfo}, }; +#[cfg(feature = "std")] use sp_externalities::{Extension, Extensions}; #[cfg(not(feature = "std"))] -use sp_std::collections::btree_map::{BTreeMap as Map, Entry as MapEntry}; -use sp_std::collections::btree_set::BTreeSet; +use sp_std::collections::btree_map::BTreeMap as Map; +use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; #[cfg(feature = "std")] use std::collections::{hash_map::Entry as MapEntry, HashMap as Map}; +#[cfg(feature = "std")] +use std::{ + any::{Any, TypeId}, + boxed::Box, +}; pub use self::changeset::{AlreadyInRuntime, NoOpenTransaction, NotInRuntime, OverlayedValue}; @@ -581,6 +580,8 @@ impl OverlayedChanges { self.changes_trie_root(backend, changes_trie_state, parent_hash, false, &mut cache) .map_err(|_| "Failed to generate changes trie transaction")?; } + #[cfg(not(feature = "std"))] + let _ = parent_hash; #[cfg(feature = "std")] let changes_trie_transaction = cache @@ -758,6 +759,7 @@ where /// An overlayed extension is either a mutable reference /// or an owned extension. +#[cfg(feature = "std")] pub enum OverlayedExtension<'a> { MutRef(&'a mut Box), Owned(Box), @@ -770,10 +772,12 @@ pub enum OverlayedExtension<'a> { /// as owned references. After the execution of a runtime function, we /// can safely drop this object while not having modified the original /// list. +#[cfg(feature = "std")] pub struct OverlayedExtensions<'a> { extensions: Map>, } +#[cfg(feature = "std")] impl<'a> OverlayedExtensions<'a> { /// Create a new instance of overalyed extensions from the given extensions. pub fn new(extensions: &'a mut Extensions) -> Self { diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 557a098fbaf79..6c575f0d76bc7 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -24,7 +24,7 @@ use hash_db::{self, Hasher, Prefix}; #[cfg(feature = "std")] use parking_lot::RwLock; use sp_core::storage::ChildInfo; -use sp_std::{boxed::Box, ops::Deref, vec::Vec}; +use sp_std::{boxed::Box, vec::Vec}; use sp_trie::{ empty_child_trie_root, read_child_trie_value, read_trie_value, trie_types::{Layout, TrieDB, TrieError}, @@ -37,8 +37,11 @@ use std::sync::Arc; #[cfg(not(feature = "std"))] macro_rules! format { - ($($arg:tt)+) => { - crate::DefaultError + ( $message:expr, $( $arg:expr )* ) => { + { + $( let _ = &$arg; )* + crate::DefaultError + } }; } @@ -488,7 +491,7 @@ impl TrieBackendStorage for Arc> { type Overlay = PrefixedMemoryDB; fn get(&self, key: &H::Out, prefix: Prefix) -> Result> { - Storage::::get(self.deref(), key, prefix) + Storage::::get(std::ops::Deref::deref(self), key, prefix) } } diff --git a/test-utils/runtime/client/src/trait_tests.rs b/test-utils/runtime/client/src/trait_tests.rs index c5e0ba49fcf5b..938aeda36d319 100644 --- a/test-utils/runtime/client/src/trait_tests.rs +++ b/test-utils/runtime/client/src/trait_tests.rs @@ -67,7 +67,6 @@ where .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); - #[allow(deprecated)] assert_eq!(blockchain.leaves().unwrap(), vec![a2.hash()]); // A2 -> A3 diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 868692d341ff0..3806a890a1064 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -436,6 +436,10 @@ fn build_project(project: &Path, default_rustflags: &str, cargo_cmd: CargoComman // exclusive). The runner project is created in `CARGO_TARGET_DIR` and executing it will // create a sub target directory inside of `CARGO_TARGET_DIR`. .env_remove("CARGO_TARGET_DIR") + // As we are being called inside a build-script, this env variable is set. However, we set + // our own `RUSTFLAGS` and thus, we need to remove this. Otherwise cargo favors this + // env variable. + .env_remove("CARGO_ENCODED_RUSTFLAGS") // We don't want to call ourselves recursively .env(crate::SKIP_BUILD_ENV, ""); From de064973b46ffe82710338c5c250288c7a0eb435 Mon Sep 17 00:00:00 2001 From: Denis Pisarev Date: Fri, 24 Sep 2021 16:50:32 +0200 Subject: [PATCH 0025/1472] CI: undebug CI image (#9857) * CI: undebug CI image * Update .gitlab-ci.yml Co-authored-by: Andronik Ordian --- .gitlab-ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2b3284d9e1a83..fa986923708d3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -38,9 +38,7 @@ variables: &default-vars CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - # FIXME: revert me - # CI_IMAGE: "paritytech/ci-linux:production" - CI_IMAGE: "paritytech/ci-linux:staging-1.54.0" + CI_IMAGE: "paritytech/ci-linux:production" # FIXME set to release CARGO_UNLEASH_INSTALL_PARAMS: "--version 1.0.0-alpha.12" CARGO_UNLEASH_PKG_DEF: "--skip node node-* pallet-template pallet-example pallet-example-* subkey chain-spec-builder" From e02e90ce68eb486c9eb69256eb38b4cb0096afca Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 24 Sep 2021 18:53:22 +0100 Subject: [PATCH 0026/1472] Remove unused sp-maybe-compressed-blob from sp-io (#9849) --- Cargo.lock | 1 - primitives/io/Cargo.toml | 2 -- 2 files changed, 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 693388a5299ff..9f740f4de4f59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9427,7 +9427,6 @@ dependencies = [ "sp-core", "sp-externalities", "sp-keystore", - "sp-maybe-compressed-blob", "sp-runtime-interface", "sp-state-machine", "sp-std", diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index d3a2b56705926..5a8c1c4af4f99 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -24,7 +24,6 @@ libsecp256k1 = { version = "0.6", optional = true } sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../state-machine" } sp-wasm-interface = { version = "4.0.0-dev", path = "../wasm-interface", default-features = false } sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" } -sp-maybe-compressed-blob = { version = "4.0.0-dev", optional = true, path = "../maybe-compressed-blob" } sp-trie = { version = "4.0.0-dev", optional = true, path = "../trie" } sp-externalities = { version = "0.10.0-dev", optional = true, path = "../externalities" } sp-tracing = { version = "4.0.0-dev", default-features = false, path = "../tracing" } @@ -48,7 +47,6 @@ std = [ "sp-runtime-interface/std", "sp-externalities", "sp-wasm-interface/std", - "sp-maybe-compressed-blob", "sp-tracing/std", "tracing/std", "tracing-core/std", From 6f1b223a7292ea2cc362089d9dfa260038dd0ffc Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Sun, 26 Sep 2021 09:41:11 +1300 Subject: [PATCH 0027/1472] Expose trait Balance & AssetId (#9863) * expose trait Balance * expose trait AssetId --- frame/support/src/traits/tokens.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/src/traits/tokens.rs b/frame/support/src/traits/tokens.rs index aca62bcad65c7..91a9382d07fcc 100644 --- a/frame/support/src/traits/tokens.rs +++ b/frame/support/src/traits/tokens.rs @@ -26,6 +26,6 @@ pub mod nonfungible; pub mod nonfungibles; pub use imbalance::Imbalance; pub use misc::{ - BalanceConversion, BalanceStatus, DepositConsequence, ExistenceRequirement, + AssetId, Balance, BalanceConversion, BalanceStatus, DepositConsequence, ExistenceRequirement, WithdrawConsequence, WithdrawReasons, }; From 45f8ec6ad0f1cb7a3cfb5d59252efe0a86b4a995 Mon Sep 17 00:00:00 2001 From: Georges Date: Sat, 25 Sep 2021 22:08:04 +0100 Subject: [PATCH 0028/1472] Removing a trailing `MaxSegmentLength` (#9850) --- frame/babe/src/mock.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index a05072bc3319e..b504a26f60421 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -231,7 +231,6 @@ parameter_types! { pub const ReportLongevity: u64 = BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get(); pub const MaxAuthorities: u32 = 10; - pub const MaxSegmentLength: u32 = 256; } impl Config for Test { From bba169cd7e7599b217b97f58cb45b6dbf65b199b Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sun, 26 Sep 2021 02:26:57 -0400 Subject: [PATCH 0029/1472] Fix amount emitted in rebonded event (#9866) --- frame/staking/src/lib.rs | 6 ++-- frame/staking/src/pallet/mod.rs | 4 +-- frame/staking/src/tests.rs | 59 +++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 136515a5d6168..d8e72e267ea9a 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -478,7 +478,9 @@ impl } /// Re-bond funds that were scheduled for unlocking. - fn rebond(mut self, value: Balance) -> Self { + /// + /// Returns the updated ledger, and the amount actually rebonded. + fn rebond(mut self, value: Balance) -> (Self, Balance) { let mut unlocking_balance: Balance = Zero::zero(); while let Some(last) = self.unlocking.last_mut() { @@ -499,7 +501,7 @@ impl } } - self + (self, unlocking_balance) } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index c71130a3492b1..dad958ccaea2f 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -1348,11 +1348,11 @@ pub mod pallet { ensure!(!ledger.unlocking.is_empty(), Error::::NoUnlockChunk); let initial_unlocking = ledger.unlocking.len() as u32; - let ledger = ledger.rebond(value); + let (ledger, rebonded_value) = ledger.rebond(value); // Last check: the new active amount of ledger must be more than ED. ensure!(ledger.active >= T::Currency::minimum_balance(), Error::::InsufficientBond); - Self::deposit_event(Event::::Bonded(ledger.stash.clone(), value)); + Self::deposit_event(Event::::Bonded(ledger.stash.clone(), rebonded_value)); // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 5e7fe3d6266aa..38b760896d7d8 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1517,6 +1517,65 @@ fn rebond_is_fifo() { }) } +#[test] +fn rebond_emits_right_value_in_event() { + // When a user calls rebond with more than can be rebonded, things succeed, + // and the rebond event emits the actual value rebonded. + ExtBuilder::default().nominate(false).build_and_execute(|| { + // Set payee to controller. avoids confusion + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + + // Give account 11 some large free balance greater than total + let _ = Balances::make_free_balance_be(&11, 1000000); + + // confirm that 10 is a normal validator and gets paid at the end of the era. + mock::start_active_era(1); + + // Unbond almost all of the funds in stash. + Staking::unbond(Origin::signed(10), 900).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + total: 1000, + active: 100, + unlocking: vec![UnlockChunk { value: 900, era: 1 + 3 }], + claimed_rewards: vec![], + }) + ); + + // Re-bond less than the total + Staking::rebond(Origin::signed(10), 100).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + total: 1000, + active: 200, + unlocking: vec![UnlockChunk { value: 800, era: 1 + 3 }], + claimed_rewards: vec![], + }) + ); + // Event emitted should be correct + assert_eq!(*staking_events().last().unwrap(), Event::Bonded(11, 100)); + + // Re-bond way more than available + Staking::rebond(Origin::signed(10), 100_000).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + total: 1000, + active: 1000, + unlocking: vec![], + claimed_rewards: vec![], + }) + ); + // Event emitted should be correct, only 800 + assert_eq!(*staking_events().last().unwrap(), Event::Bonded(11, 800)); + }); +} + #[test] fn reward_to_stake_works() { ExtBuilder::default() From a3d128d9ff7623b33bf1413774d8fffb5a375ab9 Mon Sep 17 00:00:00 2001 From: Andreas Doerr Date: Sun, 26 Sep 2021 22:42:09 +0200 Subject: [PATCH 0030/1472] BEEFY code owner (#9852) --- docs/CODEOWNERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 42d25a0a228f7..ee6382b72f1b2 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -40,6 +40,12 @@ /client/consensus/pow/ @sorpaas /primitives/consensus/pow/ @sorpaas +# BEEFY +/client/beefy/ @adoerr +/frame/beefy/ @adoerr +/frame/beefy-mmr/ @adoerr +/primitives/beefy/ @adoerr + # Contracts /frame/contracts/ @athei From 58649c449cc5b1acf65eeb4f5bb33d2d6d31b24b Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sun, 26 Sep 2021 18:05:01 -0400 Subject: [PATCH 0031/1472] Fungibles and Non-Fungibles Create and Destroy Traits + Assets and Uniques Implementation (#9844) * refactor `do_destroy` * destroy trait * refactor do_force_create * impl create trait * do not bleed weight into api * Do the same for uniques * add docs --- frame/assets/src/functions.rs | 84 +++++++++++++++++++ frame/assets/src/impl_fungibles.rs | 27 ++++++ frame/assets/src/lib.rs | 65 ++------------ frame/support/src/traits/tokens/fungibles.rs | 36 ++++++++ .../support/src/traits/tokens/nonfungibles.rs | 27 +++++- frame/uniques/src/functions.rs | 35 ++++++++ frame/uniques/src/impl_nonfungibles.rs | 23 +++-- frame/uniques/src/lib.rs | 36 ++------ 8 files changed, 244 insertions(+), 89 deletions(-) diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index 81b490eaf877c..ae31b8e395194 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -478,4 +478,88 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::Transferred(id, source.clone(), dest.clone(), credit)); Ok(credit) } + + /// Create a new asset without taking a deposit. + /// + /// * `id`: The `AssetId` you want the new asset to have. Must not already be in use. + /// * `owner`: The owner, issuer, admin, and freezer of this asset upon creation. + /// * `is_sufficient`: Whether this asset needs users to have an existential deposit to hold + /// this asset. + /// * `min_balance`: The minimum balance a user is allowed to have of this asset before they are + /// considered dust and cleaned up. + pub(super) fn do_force_create( + id: T::AssetId, + owner: T::AccountId, + is_sufficient: bool, + min_balance: T::Balance, + ) -> DispatchResult { + ensure!(!Asset::::contains_key(id), Error::::InUse); + ensure!(!min_balance.is_zero(), Error::::MinBalanceZero); + + Asset::::insert( + id, + AssetDetails { + owner: owner.clone(), + issuer: owner.clone(), + admin: owner.clone(), + freezer: owner.clone(), + supply: Zero::zero(), + deposit: Zero::zero(), + min_balance, + is_sufficient, + accounts: 0, + sufficients: 0, + approvals: 0, + is_frozen: false, + }, + ); + Self::deposit_event(Event::ForceCreated(id, owner)); + Ok(()) + } + + /// Destroy an existing asset. + /// + /// * `id`: The asset you want to destroy. + /// * `witness`: Witness data needed about the current state of the asset, used to confirm + /// complexity of the operation. + /// * `maybe_check_owner`: An optional check before destroying the asset, if the provided + /// account is the owner of that asset. Can be used for authorization checks. + pub(super) fn do_destroy( + id: T::AssetId, + witness: DestroyWitness, + maybe_check_owner: Option, + ) -> Result { + Asset::::try_mutate_exists(id, |maybe_details| { + let mut details = maybe_details.take().ok_or(Error::::Unknown)?; + if let Some(check_owner) = maybe_check_owner { + ensure!(details.owner == check_owner, Error::::NoPermission); + } + ensure!(details.accounts <= witness.accounts, Error::::BadWitness); + ensure!(details.sufficients <= witness.sufficients, Error::::BadWitness); + ensure!(details.approvals <= witness.approvals, Error::::BadWitness); + + for (who, v) in Account::::drain_prefix(id) { + Self::dead_account(id, &who, &mut details, v.sufficient); + } + debug_assert_eq!(details.accounts, 0); + debug_assert_eq!(details.sufficients, 0); + + let metadata = Metadata::::take(&id); + T::Currency::unreserve( + &details.owner, + details.deposit.saturating_add(metadata.deposit), + ); + + for ((owner, _), approval) in Approvals::::drain_prefix((&id,)) { + T::Currency::unreserve(&owner, approval.deposit); + } + Self::deposit_event(Event::Destroyed(id)); + + Ok(DestroyWitness { + accounts: details.accounts, + sufficients: details.sufficients, + approvals: details.approvals, + }) + }) + } } diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 4e85b20a1fbb1..25e18bfd437bb 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -147,3 +147,30 @@ impl, I: 'static> fungibles::Unbalanced for Pallet, I: 'static> fungibles::Create for Pallet { + fn create( + id: T::AssetId, + admin: T::AccountId, + is_sufficient: bool, + min_balance: Self::Balance, + ) -> DispatchResult { + Self::do_force_create(id, admin, is_sufficient, min_balance) + } +} + +impl, I: 'static> fungibles::Destroy for Pallet { + type DestroyWitness = DestroyWitness; + + fn get_destroy_witness(asset: &T::AssetId) -> Option { + Asset::::get(asset).map(|asset_details| asset_details.destroy_witness()) + } + + fn destroy( + id: T::AssetId, + witness: Self::DestroyWitness, + maybe_check_owner: Option, + ) -> Result { + Self::do_destroy(id, witness, maybe_check_owner) + } +} diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 797a3ae7ee9fb..2c9f994b3fef8 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -143,6 +143,7 @@ use codec::HasCompact; use frame_support::{ dispatch::{DispatchError, DispatchResult}, ensure, + pallet_prelude::DispatchResultWithPostInfo, traits::{ tokens::{fungibles, DepositConsequence, WithdrawConsequence}, BalanceStatus::Reserved, @@ -437,29 +438,7 @@ pub mod pallet { ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; - - ensure!(!Asset::::contains_key(id), Error::::InUse); - ensure!(!min_balance.is_zero(), Error::::MinBalanceZero); - - Asset::::insert( - id, - AssetDetails { - owner: owner.clone(), - issuer: owner.clone(), - admin: owner.clone(), - freezer: owner.clone(), - supply: Zero::zero(), - deposit: Zero::zero(), - min_balance, - is_sufficient, - accounts: 0, - sufficients: 0, - approvals: 0, - is_frozen: false, - }, - ); - Self::deposit_event(Event::ForceCreated(id, owner)); - Ok(()) + Self::do_force_create(id, owner, is_sufficient, min_balance) } /// Destroy a class of fungible assets. @@ -494,39 +473,13 @@ pub mod pallet { Ok(_) => None, Err(origin) => Some(ensure_signed(origin)?), }; - Asset::::try_mutate_exists(id, |maybe_details| { - let mut details = maybe_details.take().ok_or(Error::::Unknown)?; - if let Some(check_owner) = maybe_check_owner { - ensure!(details.owner == check_owner, Error::::NoPermission); - } - ensure!(details.accounts <= witness.accounts, Error::::BadWitness); - ensure!(details.sufficients <= witness.sufficients, Error::::BadWitness); - ensure!(details.approvals <= witness.approvals, Error::::BadWitness); - - for (who, v) in Account::::drain_prefix(id) { - Self::dead_account(id, &who, &mut details, v.sufficient); - } - debug_assert_eq!(details.accounts, 0); - debug_assert_eq!(details.sufficients, 0); - - let metadata = Metadata::::take(&id); - T::Currency::unreserve( - &details.owner, - details.deposit.saturating_add(metadata.deposit), - ); - - for ((owner, _), approval) in Approvals::::drain_prefix((&id,)) { - T::Currency::unreserve(&owner, approval.deposit); - } - Self::deposit_event(Event::Destroyed(id)); - - Ok(Some(T::WeightInfo::destroy( - details.accounts.saturating_sub(details.sufficients), - details.sufficients, - details.approvals, - )) - .into()) - }) + let details = Self::do_destroy(id, witness, maybe_check_owner)?; + Ok(Some(T::WeightInfo::destroy( + details.accounts.saturating_sub(details.sufficients), + details.sufficients, + details.approvals, + )) + .into()) } /// Mint assets of a particular class. diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 3f5a1c75860c2..457ec4e8bf20f 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -227,3 +227,39 @@ impl + MutateHold> BalancedHold>::slash(asset, who, actual) } } + +/// Trait for providing the ability to create new fungible assets. +pub trait Create: Inspect { + /// Create a new fungible asset. + fn create( + id: Self::AssetId, + admin: AccountId, + is_sufficient: bool, + min_balance: Self::Balance, + ) -> DispatchResult; +} + +/// Trait for providing the ability to destroy existing fungible assets. +pub trait Destroy: Inspect { + /// The witness data needed to destroy an asset. + type DestroyWitness; + + /// Provide the appropriate witness data needed to destroy an asset. + fn get_destroy_witness(id: &Self::AssetId) -> Option; + + /// Destroy an existing fungible asset. + /// * `id`: The `AssetId` to be destroyed. + /// * `witness`: Any witness data that needs to be provided to complete the operation + /// successfully. + /// * `maybe_check_owner`: An optional account id that can be used to authorize the destroy + /// command. If not provided, we will not do any authorization checks before destroying the + /// asset. + /// + /// If successful, this function will return the actual witness data from the destroyed asset. + /// This may be different than the witness data provided, and can be used to refund weight. + fn destroy( + id: Self::AssetId, + witness: Self::DestroyWitness, + maybe_check_owner: Option, + ) -> Result; +} diff --git a/frame/support/src/traits/tokens/nonfungibles.rs b/frame/support/src/traits/tokens/nonfungibles.rs index 452ee2212d62a..b5a14761064f3 100644 --- a/frame/support/src/traits/tokens/nonfungibles.rs +++ b/frame/support/src/traits/tokens/nonfungibles.rs @@ -27,7 +27,7 @@ //! Implementations of these traits may be converted to implementations of corresponding //! `nonfungible` traits by using the `nonfungible::ItemOf` type adapter. -use crate::dispatch::DispatchResult; +use crate::dispatch::{DispatchError, DispatchResult}; use codec::{Decode, Encode}; use sp_runtime::TokenError; use sp_std::prelude::*; @@ -123,6 +123,31 @@ pub trait Create: Inspect { fn create_class(class: &Self::ClassId, who: &AccountId, admin: &AccountId) -> DispatchResult; } +/// Trait for providing the ability to destroy classes of nonfungible assets. +pub trait Destroy: Inspect { + /// The witness data needed to destroy an asset. + type DestroyWitness; + + /// Provide the appropriate witness data needed to destroy an asset. + fn get_destroy_witness(class: &Self::ClassId) -> Option; + + /// Destroy an existing fungible asset. + /// * `class`: The `ClassId` to be destroyed. + /// * `witness`: Any witness data that needs to be provided to complete the operation + /// successfully. + /// * `maybe_check_owner`: An optional account id that can be used to authorize the destroy + /// command. If not provided, we will not do any authorization checks before destroying the + /// asset. + /// + /// If successful, this function will return the actual witness data from the destroyed asset. + /// This may be different than the witness data provided, and can be used to refund weight. + fn destroy( + class: Self::ClassId, + witness: Self::DestroyWitness, + maybe_check_owner: Option, + ) -> Result; +} + /// Trait for providing an interface for multiple classes of NFT-like assets which may be minted, /// burned and/or have attributes set on them. pub trait Mutate: Inspect { diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index a878a4910f769..68acf7f1879fb 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -80,6 +80,41 @@ impl, I: 'static> Pallet { Ok(()) } + pub(super) fn do_destroy_class( + class: T::ClassId, + witness: DestroyWitness, + maybe_check_owner: Option, + ) -> Result { + Class::::try_mutate_exists(class, |maybe_details| { + let class_details = maybe_details.take().ok_or(Error::::Unknown)?; + if let Some(check_owner) = maybe_check_owner { + ensure!(class_details.owner == check_owner, Error::::NoPermission); + } + ensure!(class_details.instances == witness.instances, Error::::BadWitness); + ensure!( + class_details.instance_metadatas == witness.instance_metadatas, + Error::::BadWitness + ); + ensure!(class_details.attributes == witness.attributes, Error::::BadWitness); + + for (instance, details) in Asset::::drain_prefix(&class) { + Account::::remove((&details.owner, &class, &instance)); + } + InstanceMetadataOf::::remove_prefix(&class, None); + ClassMetadataOf::::remove(&class); + Attribute::::remove_prefix((&class,), None); + T::Currency::unreserve(&class_details.owner, class_details.total_deposit); + + Self::deposit_event(Event::Destroyed(class)); + + Ok(DestroyWitness { + instances: class_details.instances, + instance_metadatas: class_details.instance_metadatas, + attributes: class_details.attributes, + }) + }) + } + pub(super) fn do_mint( class: T::ClassId, instance: T::InstanceId, diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index c5d5c6089f865..e68d2d4deecda 100644 --- a/frame/uniques/src/impl_nonfungibles.rs +++ b/frame/uniques/src/impl_nonfungibles.rs @@ -19,13 +19,10 @@ use super::*; use frame_support::{ - traits::{ - tokens::nonfungibles::{Create, Inspect, InspectEnumerable, Mutate, Transfer}, - Get, - }, + traits::{tokens::nonfungibles::*, Get}, BoundedSlice, }; -use sp_runtime::DispatchResult; +use sp_runtime::{DispatchError, DispatchResult}; use sp_std::convert::TryFrom; impl, I: 'static> Inspect<::AccountId> for Pallet { @@ -106,6 +103,22 @@ impl, I: 'static> Create<::AccountId> for Pallet } } +impl, I: 'static> Destroy<::AccountId> for Pallet { + type DestroyWitness = DestroyWitness; + + fn get_destroy_witness(class: &Self::ClassId) -> Option { + Class::::get(class).map(|a| a.destroy_witness()) + } + + fn destroy( + class: Self::ClassId, + witness: Self::DestroyWitness, + maybe_check_owner: Option, + ) -> Result { + Self::do_destroy_class(class, witness, maybe_check_owner) + } +} + impl, I: 'static> Mutate<::AccountId> for Pallet { fn mint_into( class: &Self::ClassId, diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 8c716694051b5..1bf220e4a7876 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -381,37 +381,19 @@ pub mod pallet { origin: OriginFor, #[pallet::compact] class: T::ClassId, witness: DestroyWitness, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let maybe_check_owner = match T::ForceOrigin::try_origin(origin) { Ok(_) => None, Err(origin) => Some(ensure_signed(origin)?), }; - Class::::try_mutate_exists(class, |maybe_details| { - let class_details = maybe_details.take().ok_or(Error::::Unknown)?; - if let Some(check_owner) = maybe_check_owner { - ensure!(class_details.owner == check_owner, Error::::NoPermission); - } - ensure!(class_details.instances == witness.instances, Error::::BadWitness); - ensure!( - class_details.instance_metadatas == witness.instance_metadatas, - Error::::BadWitness - ); - ensure!(class_details.attributes == witness.attributes, Error::::BadWitness); - - for (instance, details) in Asset::::drain_prefix(&class) { - Account::::remove((&details.owner, &class, &instance)); - } - InstanceMetadataOf::::remove_prefix(&class, None); - ClassMetadataOf::::remove(&class); - Attribute::::remove_prefix((&class,), None); - T::Currency::unreserve(&class_details.owner, class_details.total_deposit); - - Self::deposit_event(Event::Destroyed(class)); - - // NOTE: could use postinfo to reflect the actual number of - // accounts/sufficient/approvals - Ok(()) - }) + let details = Self::do_destroy_class(class, witness, maybe_check_owner)?; + + Ok(Some(T::WeightInfo::destroy( + details.instances, + details.instance_metadatas, + details.attributes, + )) + .into()) } /// Mint an asset instance of a particular class. From b677b3a9d0c6d157b6ca5c1ed19f0ed764038a65 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Mon, 27 Sep 2021 11:24:25 +0800 Subject: [PATCH 0032/1472] Migrate the pallet macros of some tests and benches (#9853) Signed-off-by: koushiro --- frame/executive/src/lib.rs | 177 +++++++++++++++++++--------------- frame/system/benches/bench.rs | 39 ++++---- 2 files changed, 121 insertions(+), 95 deletions(-) diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 244253185d238..41f679909e6fd 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -575,15 +575,9 @@ where #[cfg(test)] mod tests { use super::*; - use frame_support::{ - assert_err, parameter_types, - traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons}, - weights::{IdentityFee, RuntimeDbWeight, Weight, WeightToFeePolynomial}, - }; - use frame_system::{Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo}; + use hex_literal::hex; - use pallet_balances::Call as BalancesCall; - use pallet_transaction_payment::CurrencyAdapter; + use sp_core::H256; use sp_runtime::{ generic::{DigestItem, Era}, @@ -594,95 +588,135 @@ mod tests { }, DispatchError, }; + + use frame_support::{ + assert_err, parameter_types, + traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons}, + weights::{IdentityFee, RuntimeDbWeight, Weight, WeightToFeePolynomial}, + }; + use frame_system::{Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo}; + use pallet_balances::Call as BalancesCall; + use pallet_transaction_payment::CurrencyAdapter; + const TEST_KEY: &[u8] = &*b":test:key:"; + #[frame_support::pallet] mod custom { - use frame_support::weights::{DispatchClass, Weight}; - use sp_runtime::transaction_validity::{ - TransactionSource, TransactionValidity, TransactionValidityError, UnknownTransaction, - }; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::config] pub trait Config: frame_system::Config {} - frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin { - #[weight = 100] - fn some_function(origin) { - // NOTE: does not make any different. - frame_system::ensure_signed(origin)?; - } - #[weight = (200, DispatchClass::Operational)] - fn some_root_operation(origin) { - frame_system::ensure_root(origin)?; - } - #[weight = 0] - fn some_unsigned_message(origin) { - frame_system::ensure_none(origin)?; - } + #[pallet::hooks] + impl Hooks> for Pallet { + // module hooks. + // one with block number arg and one without + fn on_initialize(n: T::BlockNumber) -> Weight { + println!("on_initialize({})", n); + 175 + } - #[weight = 0] - fn allowed_unsigned(origin) { - frame_system::ensure_root(origin)?; - } + fn on_idle(n: T::BlockNumber, remaining_weight: Weight) -> Weight { + println!("on_idle{}, {})", n, remaining_weight); + 175 + } - #[weight = 0] - fn unallowed_unsigned(origin) { - frame_system::ensure_root(origin)?; - } + fn on_finalize(n: T::BlockNumber) { + println!("on_finalize({})", n); + } - #[weight = 0] - fn inherent_call(origin) { - let _ = frame_system::ensure_none(origin)?; - } + fn on_runtime_upgrade() -> Weight { + sp_io::storage::set(super::TEST_KEY, "module".as_bytes()); + 200 + } - // module hooks. - // one with block number arg and one without - fn on_initialize(n: T::BlockNumber) -> Weight { - println!("on_initialize({})", n); - 175 - } + fn offchain_worker(n: T::BlockNumber) { + assert_eq!(T::BlockNumber::from(1u32), n); + } + } - fn on_idle(n: T::BlockNumber, remaining_weight: Weight) -> Weight { - println!("on_idle{}, {})", n, remaining_weight); - 175 - } + #[pallet::call] + impl Pallet { + #[pallet::weight(100)] + pub fn some_function(origin: OriginFor) -> DispatchResult { + // NOTE: does not make any different. + frame_system::ensure_signed(origin)?; + Ok(()) + } - fn on_finalize() { - println!("on_finalize(?)"); - } + #[pallet::weight((200, DispatchClass::Operational))] + pub fn some_root_operation(origin: OriginFor) -> DispatchResult { + frame_system::ensure_root(origin)?; + Ok(()) + } - fn on_runtime_upgrade() -> Weight { - sp_io::storage::set(super::TEST_KEY, "module".as_bytes()); - 200 - } + #[pallet::weight(0)] + pub fn some_unsigned_message(origin: OriginFor) -> DispatchResult { + frame_system::ensure_none(origin)?; + Ok(()) + } - fn offchain_worker(n: T::BlockNumber) { - assert_eq!(T::BlockNumber::from(1u32), n); - } + #[pallet::weight(0)] + pub fn allowed_unsigned(origin: OriginFor) -> DispatchResult { + frame_system::ensure_root(origin)?; + Ok(()) + } - #[weight = 0] - fn calculate_storage_root(_origin) { - let root = sp_io::storage::root(); - sp_io::storage::set("storage_root".as_bytes(), &root); - } + #[pallet::weight(0)] + pub fn unallowed_unsigned(origin: OriginFor) -> DispatchResult { + frame_system::ensure_root(origin)?; + Ok(()) + } + + #[pallet::weight(0)] + pub fn inherent_call(origin: OriginFor) -> DispatchResult { + let _ = frame_system::ensure_none(origin)?; + Ok(()) + } + + #[pallet::weight(0)] + pub fn calculate_storage_root(_origin: OriginFor) -> DispatchResult { + let root = sp_io::storage::root(); + sp_io::storage::set("storage_root".as_bytes(), &root); + Ok(()) } } - impl frame_support::inherent::ProvideInherent for Module { + #[pallet::inherent] + impl ProvideInherent for Pallet { type Call = Call; + type Error = sp_inherents::MakeFatalError<()>; + const INHERENT_IDENTIFIER: [u8; 8] = *b"test1234"; - fn create_inherent(_data: &sp_inherents::InherentData) -> Option { + + fn create_inherent(_data: &InherentData) -> Option { None } + fn is_inherent(call: &Self::Call) -> bool { *call == Call::::inherent_call {} } } - impl sp_runtime::traits::ValidateUnsigned for Module { + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { type Call = Call; + // Inherent call is accepted for being dispatched + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { + match call { + Call::allowed_unsigned { .. } => Ok(()), + Call::inherent_call { .. } => Ok(()), + _ => Err(UnknownTransaction::NoUnsignedValidator.into()), + } + } + // Inherent call is not validated as unsigned fn validate_unsigned( _source: TransactionSource, @@ -693,15 +727,6 @@ mod tests { _ => UnknownTransaction::NoUnsignedValidator.into(), } } - - // Inherent call is accepted for being dispatched - fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { - match call { - Call::allowed_unsigned { .. } => Ok(()), - Call::inherent_call { .. } => Ok(()), - _ => Err(UnknownTransaction::NoUnsignedValidator.into()), - } - } } } diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index 97c19c5e8159a..c8a9d4eadfea0 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -16,8 +16,6 @@ // limitations under the License. use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use frame_support::{decl_event, decl_module}; -use frame_system as system; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -25,24 +23,24 @@ use sp_runtime::{ Perbill, }; +#[frame_support::pallet] mod module { - use super::*; + use frame_support::pallet_prelude::*; - pub trait Config: system::Config { - type Event: From + Into<::Event>; - } + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); - decl_module! { - pub struct Module for enum Call where origin: T::Origin { - pub fn deposit_event() = default; - } + #[pallet::config] + pub trait Config: frame_system::Config { + type Event: From + IsType<::Event>; } - decl_event!( - pub enum Event { - Complex(Vec, u32, u16, u128), - } - ); + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + Complex(Vec, u32, u16, u128), + } } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -55,7 +53,7 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - Module: module::{Pallet, Call, Event}, + Module: module::{Pallet, Event}, } ); @@ -70,7 +68,7 @@ frame_support::parameter_types! { 4 * 1024 * 1024, Perbill::from_percent(75), ); } -impl system::Config for Runtime { +impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = BlockLength; @@ -101,14 +99,17 @@ impl module::Config for Runtime { } fn new_test_ext() -> sp_io::TestExternalities { - system::GenesisConfig::default().build_storage::().unwrap().into() + frame_system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into() } fn deposit_events(n: usize) { let mut t = new_test_ext(); t.execute_with(|| { for _ in 0..n { - module::Module::::deposit_event(module::Event::Complex( + module::Pallet::::deposit_event(module::Event::Complex( vec![1, 2, 3], 2, 3, From be28ab08da7ee34eba9a6f599833738dda7dda22 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Mon, 27 Sep 2021 10:25:24 +0200 Subject: [PATCH 0033/1472] pallet macro: allow to declare individual unbounded storage for those who cannot go into PoV (#9670) * allow unbounded individual storage * better doc * fix UI tests * update doc * Update frame/support/procedural/src/pallet/parse/storage.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- .../src/pallet/expand/pallet_struct.rs | 49 +++++++++------ .../procedural/src/pallet/parse/storage.rs | 62 +++++++++++++------ frame/support/src/lib.rs | 11 +++- frame/support/test/tests/pallet.rs | 22 +++++++ .../storage_invalid_attribute.stderr | 2 +- .../pallet_ui/storage_multiple_getters.stderr | 2 +- .../pallet_ui/storage_multiple_renames.stderr | 2 +- 7 files changed, 106 insertions(+), 44 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index a217742fec55d..0ad8a25b8e9a2 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -98,28 +98,39 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { ) }; - // Depending on the flag `generate_storage_info` we use partial or full storage info from - // storage. - let (storage_info_span, storage_info_trait, storage_info_method) = - if let Some(span) = def.pallet_struct.generate_storage_info { - ( - span, - quote::quote_spanned!(span => StorageInfoTrait), - quote::quote_spanned!(span => storage_info), - ) - } else { - let span = def.pallet_struct.attr_span; - ( - span, - quote::quote_spanned!(span => PartialStorageInfoTrait), - quote::quote_spanned!(span => partial_storage_info), - ) - }; + let storage_info_span = + def.pallet_struct.generate_storage_info.unwrap_or(def.pallet_struct.attr_span); let storage_names = &def.storages.iter().map(|storage| &storage.ident).collect::>(); let storage_cfg_attrs = &def.storages.iter().map(|storage| &storage.cfg_attrs).collect::>(); + // Depending on the flag `generate_storage_info` and the storage attribute `unbounded`, we use + // partial or full storage info from storage. + let storage_info_traits = &def + .storages + .iter() + .map(|storage| { + if storage.unbounded || def.pallet_struct.generate_storage_info.is_none() { + quote::quote_spanned!(storage_info_span => PartialStorageInfoTrait) + } else { + quote::quote_spanned!(storage_info_span => StorageInfoTrait) + } + }) + .collect::>(); + + let storage_info_methods = &def + .storages + .iter() + .map(|storage| { + if storage.unbounded || def.pallet_struct.generate_storage_info.is_none() { + quote::quote_spanned!(storage_info_span => partial_storage_info) + } else { + quote::quote_spanned!(storage_info_span => storage_info) + } + }) + .collect::>(); + let storage_info = quote::quote_spanned!(storage_info_span => impl<#type_impl_gen> #frame_support::traits::StorageInfoTrait for #pallet_ident<#type_use_gen> @@ -136,8 +147,8 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { { let mut storage_info = < #storage_names<#type_use_gen> - as #frame_support::traits::#storage_info_trait - >::#storage_info_method(); + as #frame_support::traits::#storage_info_traits + >::#storage_info_methods(); res.append(&mut storage_info); } )* diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 8075daacb6f44..cd29baf93d849 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -27,6 +27,7 @@ mod keyword { syn::custom_keyword!(pallet); syn::custom_keyword!(getter); syn::custom_keyword!(storage_prefix); + syn::custom_keyword!(unbounded); syn::custom_keyword!(OptionQuery); syn::custom_keyword!(ValueQuery); } @@ -34,15 +35,17 @@ mod keyword { /// Parse for one of the following: /// * `#[pallet::getter(fn dummy)]` /// * `#[pallet::storage_prefix = "CustomName"]` +/// * `#[pallet::unbounded]` pub enum PalletStorageAttr { Getter(syn::Ident, proc_macro2::Span), StorageName(syn::LitStr, proc_macro2::Span), + Unbounded(proc_macro2::Span), } impl PalletStorageAttr { fn attr_span(&self) -> proc_macro2::Span { match self { - Self::Getter(_, span) | Self::StorageName(_, span) => *span, + Self::Getter(_, span) | Self::StorageName(_, span) | Self::Unbounded(span) => *span, } } } @@ -76,12 +79,45 @@ impl syn::parse::Parse for PalletStorageAttr { })?; Ok(Self::StorageName(renamed_prefix, attr_span)) + } else if lookahead.peek(keyword::unbounded) { + content.parse::()?; + + Ok(Self::Unbounded(attr_span)) } else { Err(lookahead.error()) } } } +struct PalletStorageAttrInfo { + getter: Option, + rename_as: Option, + unbounded: bool, +} + +impl PalletStorageAttrInfo { + fn from_attrs(attrs: Vec) -> syn::Result { + let mut getter = None; + let mut rename_as = None; + let mut unbounded = false; + for attr in attrs { + match attr { + PalletStorageAttr::Getter(ident, ..) if getter.is_none() => getter = Some(ident), + PalletStorageAttr::StorageName(name, ..) if rename_as.is_none() => + rename_as = Some(name), + PalletStorageAttr::Unbounded(..) if !unbounded => unbounded = true, + attr => + return Err(syn::Error::new( + attr.attr_span(), + "Invalid attribute: Duplicate attribute", + )), + } + } + + Ok(PalletStorageAttrInfo { getter, rename_as, unbounded }) + } +} + /// The value and key types used by storages. Needed to expand metadata. pub enum Metadata { Value { value: syn::Type }, @@ -131,6 +167,8 @@ pub struct StorageDef { /// generics of the storage. /// If generics are not named, this is none. pub named_generics: Option, + /// If the value stored in this storage is unbounded. + pub unbounded: bool, } /// The parsed generic from the @@ -629,25 +667,8 @@ impl StorageDef { }; let attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; - let (mut getters, mut names) = attrs - .into_iter() - .partition::, _>(|attr| matches!(attr, PalletStorageAttr::Getter(..))); - if getters.len() > 1 { - let msg = "Invalid pallet::storage, multiple argument pallet::getter found"; - return Err(syn::Error::new(getters[1].attr_span(), msg)) - } - if names.len() > 1 { - let msg = "Invalid pallet::storage, multiple argument pallet::storage_prefix found"; - return Err(syn::Error::new(names[1].attr_span(), msg)) - } - let getter = getters.pop().map(|attr| match attr { - PalletStorageAttr::Getter(ident, _) => ident, - _ => unreachable!(), - }); - let rename_as = names.pop().map(|attr| match attr { - PalletStorageAttr::StorageName(lit, _) => lit, - _ => unreachable!(), - }); + let PalletStorageAttrInfo { getter, rename_as, unbounded } = + PalletStorageAttrInfo::from_attrs(attrs)?; let cfg_attrs = helper::get_item_cfg_attrs(&item.attrs); @@ -704,6 +725,7 @@ impl StorageDef { where_clause, cfg_attrs, named_generics, + unbounded, }) } } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 459698707366d..f56af036eb2a3 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1411,15 +1411,17 @@ pub mod pallet_prelude { /// `::Foo`. /// /// To generate the full storage info (used for PoV calculation) use the attribute -/// `#[pallet::set_storage_max_encoded_len]`, e.g.: +/// `#[pallet::generate_storage_info]`, e.g.: /// ```ignore /// #[pallet::pallet] -/// #[pallet::set_storage_max_encoded_len] +/// #[pallet::generate_storage_info] /// pub struct Pallet(_); /// ``` /// /// This require all storage to implement the trait [`traits::StorageInfoTrait`], thus all keys /// and value types must bound [`pallet_prelude::MaxEncodedLen`]. +/// Some individual storage can opt-out from this constraint by using `#[pallet::unbounded]`, +/// see `#[pallet::storage]` documentation. /// /// As the macro implements [`traits::GetStorageVersion`], the current storage version needs to /// be communicated to the macro. This can be done by using the `storage_version` attribute: @@ -1721,6 +1723,11 @@ pub mod pallet_prelude { /// pub(super) type MyStorage = StorageMap<_, Blake2_128Concat, u32, u32>; /// ``` /// +/// The optional attribute `#[pallet::unbounded]` allows to declare the storage as unbounded. +/// When implementating the storage info (when #[pallet::generate_storage_info]` is specified +/// on the pallet struct placeholder), the size of the storage will be declared as unbounded. +/// This can be useful for storage which can never go into PoV (Proof of Validity). +/// /// The optional attributes `#[cfg(..)]` allow conditional compilation for the storage. /// /// E.g: diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 7eb8431ce146d..25fc2d46d2560 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -329,6 +329,10 @@ pub mod pallet { pub type SomeCountedStorageMap = CountedStorageMap; + #[pallet::storage] + #[pallet::unbounded] + pub type Unbounded = StorageValue>; + #[pallet::genesis_config] #[derive(Default)] pub struct GenesisConfig { @@ -917,6 +921,10 @@ fn storage_expand() { assert_eq!(unhashed::get::(&k), Some(2u32)); let k = [twox_128(b"Example"), twox_128(b"CounterForRenamedCountedMap")].concat(); assert_eq!(unhashed::get::(&k), Some(1u32)); + + pallet::Unbounded::::put(vec![1, 2]); + let k = [twox_128(b"Example"), twox_128(b"Unbounded")].concat(); + assert_eq!(unhashed::get::>(&k), Some(vec![1, 2])); }) } @@ -1170,6 +1178,13 @@ fn metadata() { default: vec![0, 0, 0, 0], docs: vec!["Counter for the related counted storage map"], }, + StorageEntryMetadata { + name: "Unbounded", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(meta_type::>()), + default: vec![0], + docs: vec![], + }, ], }), calls: Some(meta_type::>().into()), @@ -1411,6 +1426,13 @@ fn test_storage_info() { max_values: Some(1), max_size: Some(4), }, + StorageInfo { + pallet_name: b"Example".to_vec(), + storage_name: b"Unbounded".to_vec(), + prefix: prefix(b"Example", b"Unbounded").to_vec(), + max_values: Some(1), + max_size: None, + }, ], ); diff --git a/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr b/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr index bf93d99cf56bd..6313bd691f943 100644 --- a/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr +++ b/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr @@ -1,4 +1,4 @@ -error: expected `getter` or `storage_prefix` +error: expected one of: `getter`, `storage_prefix`, `unbounded` --> $DIR/storage_invalid_attribute.rs:16:12 | 16 | #[pallet::generate_store(pub trait Store)] diff --git a/frame/support/test/tests/pallet_ui/storage_multiple_getters.stderr b/frame/support/test/tests/pallet_ui/storage_multiple_getters.stderr index 188eed3cb0d17..40f57f16e0df5 100644 --- a/frame/support/test/tests/pallet_ui/storage_multiple_getters.stderr +++ b/frame/support/test/tests/pallet_ui/storage_multiple_getters.stderr @@ -1,4 +1,4 @@ -error: Invalid pallet::storage, multiple argument pallet::getter found +error: Invalid attribute: Duplicate attribute --> $DIR/storage_multiple_getters.rs:20:3 | 20 | #[pallet::getter(fn foo_error)] diff --git a/frame/support/test/tests/pallet_ui/storage_multiple_renames.stderr b/frame/support/test/tests/pallet_ui/storage_multiple_renames.stderr index 9288d131d95af..52cb7e85adf21 100644 --- a/frame/support/test/tests/pallet_ui/storage_multiple_renames.stderr +++ b/frame/support/test/tests/pallet_ui/storage_multiple_renames.stderr @@ -1,4 +1,4 @@ -error: Invalid pallet::storage, multiple argument pallet::storage_prefix found +error: Invalid attribute: Duplicate attribute --> $DIR/storage_multiple_renames.rs:20:3 | 20 | #[pallet::storage_prefix = "Baz"] From aa3ea045d39ec0f8880d339c11ec61302f9fca24 Mon Sep 17 00:00:00 2001 From: Falco Hirschenberger Date: Mon, 27 Sep 2021 17:17:38 +0200 Subject: [PATCH 0034/1472] Add weight for decoding the call to benchmarks (#9781) * First two bechmarks converted * Add decoding weight to benchmarks. * Update frame/democracy/src/benchmarking.rs * Adapt to new Call-ing convention * Resolve conflicts and change more calls * Remove error impl for codec and use plain `expect` for error handling instead * Compile fix * Spaces to tabs * Update frame/democracy/src/benchmarking.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Add origin-type specifier to benchmarks macro * formatting * Update frame/benchmarking/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Change manual to automatic benchmark syntax * Formatting * Revert "Change manual to automatic benchmark syntax" This reverts commit ea5b5d906b318b6525c1e6d2bd05c5011595c21a. Because tests are lost and cleanup code in the verify function is not run on failing calls. Co-authored-by: Guillaume Thiolliere Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/benchmarking/src/lib.rs | 33 ++++++++++++---- frame/benchmarking/src/utils.rs | 1 - frame/democracy/src/benchmarking.rs | 38 +++++++------------ .../src/benchmarking.rs | 1 - frame/elections-phragmen/src/benchmarking.rs | 15 +++++++- frame/gilt/src/benchmarking.rs | 15 +++----- frame/im-online/src/benchmarking.rs | 8 ++-- frame/lottery/src/benchmarking.rs | 13 ++----- frame/staking/src/benchmarking.rs | 11 +++++- 9 files changed, 75 insertions(+), 60 deletions(-) diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 6c124a8a75761..4a6c5e15ae20c 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -131,6 +131,13 @@ macro_rules! whitelist { /// let c = 0 .. 10 => setup_c_in_some_other_way(&caller, c); /// }: baz(Origin::Signed(caller)) /// +/// // You may optionally specify the origin type if it can't be determined automatically like +/// // this. +/// baz3 { +/// let caller = account::(b"caller", 0, benchmarks_seed); +/// let l in 1 .. MAX_LENGTH => initialize_l(l); +/// }: baz(Origin::Signed(caller), vec![0u8; l]) +/// /// // this is benchmarking some code that is not a dispatchable. /// populate_a_set { /// let x in 0 .. 10_000; @@ -305,7 +312,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) // This contains $( $( { $instance } )? $name:ident )* ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) - $name:ident { $( $code:tt )* }: _ ( $origin:expr $( , $arg:expr )* ) + $name:ident { $( $code:tt )* }: _ $(< $origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) verify $postcode:block $( $rest:tt )* ) => { @@ -315,7 +322,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) - $name { $( $code )* }: $name ( $origin $( , $arg )* ) + $name { $( $code )* }: $name $(< $origin_type >)? ( $origin $( , $arg )* ) verify $postcode $( $rest )* } @@ -327,7 +334,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) - $name:ident { $( $code:tt )* }: $dispatch:ident ( $origin:expr $( , $arg:expr )* ) + $name:ident { $( $code:tt )* }: $dispatch:ident $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) verify $postcode:block $( $rest:tt )* ) => { @@ -350,15 +357,14 @@ macro_rules! benchmarks_iter { &__call ); }: { - let call_decoded = < + let __call_decoded = < Call as $crate::frame_support::codec::Decode >::decode(&mut &__benchmarked_call_encoded[..]) .expect("call is encoded above, encoding must be correct"); - - < - Call as $crate::frame_support::traits::UnfilteredDispatchable - >::dispatch_bypass_filter(call_decoded, $origin.into())?; + let __origin = $crate::to_origin!($origin $(, $origin_type)?); + as $crate::frame_support::traits::UnfilteredDispatchable + >::dispatch_bypass_filter(__call_decoded, __origin)?; } verify $postcode $( $rest )* @@ -488,6 +494,17 @@ macro_rules! benchmarks_iter { }; } +#[macro_export] +#[doc(hidden)] +macro_rules! to_origin { + ($origin:expr) => { + $origin.into() + }; + ($origin:expr, $origin_type:ty) => { + >::from($origin) + }; +} + #[macro_export] #[doc(hidden)] macro_rules! benchmark_backend { diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index 158f5c5b57573..c24ad2f64e18d 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -16,7 +16,6 @@ // limitations under the License. //! Interfaces, types and utils for benchmarking a FRAME runtime. - use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchError, DispatchErrorWithPostInfo}, diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index 7d4d7aee140b9..a00e6f4686fd3 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -22,6 +22,7 @@ use super::*; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelist_account}; use frame_support::{ assert_noop, assert_ok, + codec::Decode, traits::{ schedule::DispatchTime, Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable, }, @@ -194,9 +195,8 @@ benchmarks! { emergency_cancel { let origin = T::CancellationOrigin::successful_origin(); let referendum_index = add_referendum::(0)?; - let call = Call::::emergency_cancel { ref_index: referendum_index }; assert_ok!(Democracy::::referendum_status(referendum_index)); - }: { call.dispatch_bypass_filter(origin)? } + }: _(origin, referendum_index) verify { // Referendum has been canceled assert_noop!( @@ -219,14 +219,11 @@ benchmarks! { assert_ok!( Democracy::::external_propose(T::ExternalOrigin::successful_origin(), hash.clone()) ); - + let origin = T::BlacklistOrigin::successful_origin(); // Add a referendum of our proposal. let referendum_index = add_referendum::(0)?; assert_ok!(Democracy::::referendum_status(referendum_index)); - - let call = Call::::blacklist { proposal_hash: hash, maybe_ref_index: Some(referendum_index) }; - let origin = T::BlacklistOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } + }: _(origin, hash, Some(referendum_index)) verify { // Referendum has been canceled assert_noop!( @@ -246,9 +243,7 @@ benchmarks! { proposal_hash, (T::BlockNumber::zero(), vec![T::AccountId::default(); v as usize]) ); - - let call = Call::::external_propose { proposal_hash }; - }: { call.dispatch_bypass_filter(origin)? } + }: _(origin, proposal_hash) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -257,8 +252,7 @@ benchmarks! { external_propose_majority { let origin = T::ExternalMajorityOrigin::successful_origin(); let proposal_hash = T::Hashing::hash_of(&0); - let call = Call::::external_propose_majority { proposal_hash }; - }: { call.dispatch_bypass_filter(origin)? } + }: _(origin, proposal_hash) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -267,8 +261,7 @@ benchmarks! { external_propose_default { let origin = T::ExternalDefaultOrigin::successful_origin(); let proposal_hash = T::Hashing::hash_of(&0); - let call = Call::::external_propose_default { proposal_hash }; - }: { call.dispatch_bypass_filter(origin)? } + }: _(origin, proposal_hash) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -283,13 +276,7 @@ benchmarks! { let origin_fast_track = T::FastTrackOrigin::successful_origin(); let voting_period = T::FastTrackVotingPeriod::get(); let delay = 0u32; - let call = Call::::fast_track { - proposal_hash, - voting_period: voting_period.into(), - delay: delay.into() - }; - - }: { call.dispatch_bypass_filter(origin_fast_track)? } + }: _(origin_fast_track, proposal_hash, voting_period.into(), delay.into()) verify { assert_eq!(Democracy::::referendum_count(), 1, "referendum not created") } @@ -310,10 +297,9 @@ benchmarks! { vetoers.sort(); Blacklist::::insert(proposal_hash, (T::BlockNumber::zero(), vetoers)); - let call = Call::::veto_external { proposal_hash }; let origin = T::VetoOrigin::successful_origin(); ensure!(NextExternal::::get().is_some(), "no external proposal"); - }: { call.dispatch_bypass_filter(origin)? } + }: _(origin, proposal_hash) verify { assert!(NextExternal::::get().is_none()); let (_, new_vetoers) = >::get(&proposal_hash).ok_or("no blacklist")?; @@ -774,9 +760,13 @@ benchmarks! { Some(PreimageStatus::Available { .. }) => (), _ => return Err("preimage not available".into()) } + let origin = RawOrigin::Root.into(); + let call = Call::::enact_proposal { proposal_hash, index: 0 }.encode(); }: { assert_eq!( - Democracy::::enact_proposal(RawOrigin::Root.into(), proposal_hash, 0), + as Decode>::decode(&mut &*call) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(origin), Err(Error::::PreimageInvalid.into()) ); } diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index a5bb0d6351c15..b8d7bc45c4487 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -350,7 +350,6 @@ frame_benchmarking::benchmarks! { assert!(>::queued_solution().is_none()); >::put(Phase::Unsigned((true, 1u32.into()))); - }: _(RawOrigin::None, Box::new(raw_solution), witness) verify { assert!(>::queued_solution().is_some()); diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 7cb83b3dd7799..6e3ce0234c4fb 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -24,7 +24,10 @@ use super::*; use frame_benchmarking::{ account, benchmarks, impl_benchmark_test_suite, whitelist, BenchmarkError, BenchmarkResult, }; -use frame_support::{dispatch::DispatchResultWithPostInfo, traits::OnInitialize}; +use frame_support::{ + dispatch::{DispatchResultWithPostInfo, UnfilteredDispatchable}, + traits::OnInitialize, +}; use frame_system::RawOrigin; use crate::Pallet as Elections; @@ -401,15 +404,23 @@ benchmarks! { let _ = fill_seats_up_to::(m)?; let removing = as_lookup::(>::members_ids()[0].clone()); + let who = T::Lookup::lookup(removing.clone()).expect("member was added above"); + let call = Call::::remove_member { who: removing, has_replacement: false }.encode(); }: { assert_eq!( - >::remove_member(RawOrigin::Root.into(), removing, false).unwrap_err().error, + as Decode>::decode(&mut &*call) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(RawOrigin::Root.into()) + .unwrap_err() + .error, Error::::InvalidReplacement.into(), ); } verify { // must still have enough members. assert_eq!(>::members().len() as u32, T::DesiredMembers::get()); + // on fail, `who` must still be a member + assert!(>::members_ids().contains(&who)); #[cfg(test)] { // reset members in between benchmark tests. diff --git a/frame/gilt/src/benchmarking.rs b/frame/gilt/src/benchmarking.rs index 55d34a35a7ce4..cfc503cf897b4 100644 --- a/frame/gilt/src/benchmarking.rs +++ b/frame/gilt/src/benchmarking.rs @@ -50,17 +50,12 @@ benchmarks! { place_bid_max { let caller: T::AccountId = whitelisted_caller(); + let origin = RawOrigin::Signed(caller.clone()); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); for i in 0..T::MaxQueueLen::get() { - Gilt::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinFreeze::get(), 1)?; + Gilt::::place_bid(origin.clone().into(), T::MinFreeze::get(), 1)?; } - }: { - Gilt::::place_bid( - RawOrigin::Signed(caller.clone()).into(), - T::MinFreeze::get() * BalanceOf::::from(2u32), - 1, - )? - } + }: place_bid(origin, T::MinFreeze::get() * BalanceOf::::from(2u32), 1) verify { assert_eq!(QueueTotals::::get()[0], ( T::MaxQueueLen::get(), @@ -81,9 +76,9 @@ benchmarks! { } set_target { - let call = Call::::set_target { target: Default::default() }; let origin = T::AdminOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } + }: _(origin, Default::default()) + verify {} thaw { let caller: T::AccountId = whitelisted_caller(); diff --git a/frame/im-online/src/benchmarking.rs b/frame/im-online/src/benchmarking.rs index 20812f03d28dd..b39b0057c48e8 100644 --- a/frame/im-online/src/benchmarking.rs +++ b/frame/im-online/src/benchmarking.rs @@ -93,10 +93,12 @@ benchmarks! { let e in 1 .. MAX_EXTERNAL_ADDRESSES; let (input_heartbeat, signature) = create_heartbeat::(k, e)?; let call = Call::heartbeat { heartbeat: input_heartbeat, signature }; + let call_enc = call.encode(); }: { - ImOnline::::validate_unsigned(TransactionSource::InBlock, &call) - .map_err(<&str>::from)?; - call.dispatch_bypass_filter(RawOrigin::None.into())?; + ImOnline::::validate_unsigned(TransactionSource::InBlock, &call).map_err(<&str>::from)?; + as Decode>::decode(&mut &*call_enc) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(RawOrigin::None.into())?; } } diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index 3b7035c72deb0..7af20bbb0e11f 100644 --- a/frame/lottery/src/benchmarking.rs +++ b/frame/lottery/src/benchmarking.rs @@ -22,7 +22,7 @@ use super::*; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; -use frame_support::traits::{EnsureOrigin, OnInitialize, UnfilteredDispatchable}; +use frame_support::traits::{EnsureOrigin, OnInitialize}; use frame_system::RawOrigin; use sp_runtime::traits::{Bounded, Zero}; @@ -73,11 +73,9 @@ benchmarks! { set_calls { let n in 0 .. T::MaxCalls::get() as u32; let calls = vec![frame_system::Call::::remark { remark: vec![] }.into(); n as usize]; - - let call = Call::::set_calls { calls }; let origin = T::ManagerOrigin::successful_origin(); assert!(CallIndices::::get().is_empty()); - }: { call.dispatch_bypass_filter(origin)? } + }: _(origin, calls) verify { if !n.is_zero() { assert!(!CallIndices::::get().is_empty()); @@ -88,10 +86,8 @@ benchmarks! { let price = BalanceOf::::max_value(); let end = 10u32.into(); let payout = 5u32.into(); - - let call = Call::::start_lottery { price, length: end, delay: payout, repeat: true }; let origin = T::ManagerOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } + }: _(origin, price, end, payout, true) verify { assert!(crate::Lottery::::get().is_some()); } @@ -99,9 +95,8 @@ benchmarks! { stop_repeat { setup_lottery::(true)?; assert_eq!(crate::Lottery::::get().unwrap().repeat, true); - let call = Call::::stop_repeat {}; let origin = T::ManagerOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } + }: _(origin) verify { assert_eq!(crate::Lottery::::get().unwrap().repeat, false); } diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index f3def7206320c..fe60d516e144c 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -23,6 +23,7 @@ use testing_utils::*; use frame_election_provider_support::SortedListProvider; use frame_support::{ + dispatch::UnfilteredDispatchable, pallet_prelude::*, traits::{Currency, CurrencyToVote, Get, Imbalance}, }; @@ -764,9 +765,15 @@ benchmarks! { >::insert(current_era, total_payout); let caller: T::AccountId = whitelisted_caller(); + let origin = RawOrigin::Signed(caller); + let calls: Vec<_> = payout_calls_arg.iter().map(|arg| + Call::::payout_stakers { validator_stash: arg.0.clone(), era: arg.1 }.encode() + ).collect(); }: { - for arg in payout_calls_arg { - >::payout_stakers(RawOrigin::Signed(caller.clone()).into(), arg.0, arg.1)?; + for call in calls { + as Decode>::decode(&mut &*call) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(origin.clone().into())?; } } From 03c2c2fe44b405c4b84561cc2c65e5cf7d2c263a Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Tue, 28 Sep 2021 11:12:57 +0800 Subject: [PATCH 0035/1472] Migrate `pallet-session` to the new pallet macro (#9796) * Migrate pallet-session to the new pallet macro Signed-off-by: koushiro * Remove old macros Signed-off-by: koushiro * Fix Signed-off-by: koushiro --- frame/beefy-mmr/src/mock.rs | 3 +- frame/beefy/src/mock.rs | 3 +- frame/session/Cargo.toml | 24 +- frame/session/README.md | 8 +- frame/session/benchmarking/Cargo.toml | 28 +- frame/session/benchmarking/src/lib.rs | 6 +- frame/session/src/historical/mod.rs | 12 +- frame/session/src/historical/offchain.rs | 29 +- frame/session/src/historical/onchain.rs | 10 +- frame/session/src/historical/shared.rs | 2 +- frame/session/src/lib.rs | 377 +++++++++++++---------- frame/session/src/mock.rs | 7 +- frame/session/src/tests.rs | 8 +- frame/staking/src/mock.rs | 3 +- frame/staking/src/tests.rs | 2 +- 15 files changed, 285 insertions(+), 237 deletions(-) diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index a8d136b192aec..4c9e103eb7b82 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -19,7 +19,8 @@ use std::vec; use beefy_primitives::mmr::MmrLeafVersion; use frame_support::{ - construct_runtime, parameter_types, sp_io::TestExternalities, BasicExternalities, + construct_runtime, parameter_types, sp_io::TestExternalities, traits::GenesisBuild, + BasicExternalities, }; use sp_core::{Hasher, H256}; use sp_runtime::{ diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 696d0d972e70c..baa2fae746fe3 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -18,7 +18,8 @@ use std::vec; use frame_support::{ - construct_runtime, parameter_types, sp_io::TestExternalities, BasicExternalities, + construct_runtime, parameter_types, sp_io::TestExternalities, traits::GenesisBuild, + BasicExternalities, }; use sp_core::H256; use sp_runtime::{ diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 8f07de2e7a6db..3d2de5339543e 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -13,38 +13,40 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ - "derive", -] } +log = { version = "0.4.0", default-features = false } +impl-trait-for-tuples = "0.2.1" + +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } + sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } +sp-trie = { version = "4.0.0-dev", default-features = false, path = "../../primitives/trie", optional = true } + frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } -sp-trie = { version = "4.0.0-dev", optional = true, default-features = false, path = "../../primitives/trie" } -log = { version = "0.4.0", default-features = false } -impl-trait-for-tuples = "0.2.1" [features] default = ["std", "historical"] historical = ["sp-trie"] std = [ + "log/std", "codec/std", "scale-info/std", "sp-std/std", - "sp-io/std", - "frame-support/std", "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-session/std", "sp-staking/std", - "pallet-timestamp/std", "sp-trie/std", - "log/std", + "frame-support/std", + "frame-system/std", + "pallet-timestamp/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/session/README.md b/frame/session/README.md index c47b5610de09c..09132470d4433 100644 --- a/frame/session/README.md +++ b/frame/session/README.md @@ -1,11 +1,11 @@ -# Session Module +# Session Pallet The Session module allows validators to manage their session keys, provides a function for changing the session length, and handles session rotation. - [`session::Trait`](https://docs.rs/pallet-session/latest/pallet_session/trait.Config.html) - [`Call`](https://docs.rs/pallet-session/latest/pallet_session/enum.Call.html) -- [`Module`](https://docs.rs/pallet-session/latest/pallet_session/struct.Module.html) +- [`Pallet`](https://docs.rs/pallet-session/latest/pallet_session/struct.Pallet.html) ## Overview @@ -72,11 +72,11 @@ The [Staking pallet](https://docs.rs/pallet-staking/latest/pallet_staking/) uses use pallet_session as session; fn validators() -> Vec<::ValidatorId> { - >::validators() + >::validators() } ``` -## Related Modules +## Related Pallets - [Staking](https://docs.rs/pallet-staking/latest/pallet_staking/) diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index cc242085bf5e4..a24d4a1173ab1 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -13,39 +13,37 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +rand = { version = "0.7.2", default-features = false } + sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } +sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } + frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } -pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ - "runtime-benchmarks", -], path = "../../staking" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../../session" } -rand = { version = "0.7.2", default-features = false } +pallet-staking = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../staking" } [dev-dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", features = [ - "derive", -] } +codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } scale-info = "1.0" sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } -pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } -pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } pallet-balances = { version = "4.0.0-dev", path = "../../balances" } +pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } +pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } frame-election-provider-support = { version = "4.0.0-dev", path = "../../election-provider-support" } [features] default = ["std"] std = [ "sp-std/std", - "sp-session/std", "sp-runtime/std", - "frame-system/std", + "sp-session/std", "frame-benchmarking/std", "frame-support/std", - "pallet-staking/std", + "frame-system/std", "pallet-session/std", + "pallet-staking/std", ] diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index 8b84145c1acfd..c0131957c8732 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -30,7 +30,7 @@ use frame_support::{ traits::{KeyOwnerProofSystem, OnInitialize}, }; use frame_system::RawOrigin; -use pallet_session::{historical::Module as Historical, Module as Session, *}; +use pallet_session::{historical::Module as Historical, Pallet as Session, *}; use pallet_staking::{ benchmarking::create_validator_with_nominators, testing_utils::create_validators, RewardDestination, @@ -39,7 +39,7 @@ use sp_runtime::traits::{One, StaticLookup}; const MAX_VALIDATORS: u32 = 1000; -pub struct Pallet(pallet_session::Module); +pub struct Pallet(pallet_session::Pallet); pub trait Config: pallet_session::Config + pallet_session::historical::Config + pallet_staking::Config { @@ -47,7 +47,7 @@ pub trait Config: impl OnInitialize for Pallet { fn on_initialize(n: T::BlockNumber) -> frame_support::weights::Weight { - pallet_session::Module::::on_initialize(n) + pallet_session::Pallet::::on_initialize(n) } } diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index c9b13e3c7f262..0801b2aca1701 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -26,7 +26,7 @@ //! These roots and proofs of inclusion can be generated at any time during the current session. //! Afterwards, the proofs can be fed to a consensus module when reporting misbehavior. -use super::{Module as SessionModule, SessionIndex}; +use super::{Pallet as SessionModule, SessionIndex}; use codec::{Decode, Encode}; use frame_support::{ decl_module, decl_storage, print, @@ -114,11 +114,11 @@ impl ValidatorSet for Module { type ValidatorIdOf = T::ValidatorIdOf; fn session_index() -> sp_staking::SessionIndex { - super::Module::::current_index() + super::Pallet::::current_index() } fn validators() -> Vec { - super::Module::::validators() + super::Pallet::::validators() } } @@ -366,11 +366,13 @@ pub(crate) mod tests { use crate::mock::{ force_new_session, set_next_validators, Session, System, Test, NEXT_VALIDATORS, }; + + use sp_runtime::{key_types::DUMMY, testing::UintAuthorityId}; + use frame_support::{ - traits::{KeyOwnerProofSystem, OnInitialize}, + traits::{GenesisBuild, KeyOwnerProofSystem, OnInitialize}, BasicExternalities, }; - use sp_runtime::{key_types::DUMMY, testing::UintAuthorityId}; type Historical = Module; diff --git a/frame/session/src/historical/offchain.rs b/frame/session/src/historical/offchain.rs index 8583c2bb439be..b646ecc2764f7 100644 --- a/frame/session/src/historical/offchain.rs +++ b/frame/session/src/historical/offchain.rs @@ -30,15 +30,11 @@ use sp_runtime::{ KeyTypeId, }; use sp_session::MembershipProof; - -use super::{ - super::{Pallet as SessionModule, SessionIndex}, - Config, IdentificationTuple, ProvingTrie, -}; - -use super::shared; use sp_std::prelude::*; +use super::{shared, Config, IdentificationTuple, ProvingTrie}; +use crate::{Pallet as SessionModule, SessionIndex}; + /// A set of validators, which was used for a fixed session index. struct ValidatorSet { validator_set: Vec>, @@ -142,23 +138,24 @@ pub fn keep_newest(n_to_keep: usize) { #[cfg(test)] mod tests { - use super::{ - super::{onchain, Module}, - *, - }; - use crate::mock::{ - force_new_session, set_next_validators, Session, System, Test, NEXT_VALIDATORS, + use super::*; + use crate::{ + historical::{onchain, Module}, + mock::{force_new_session, set_next_validators, Session, System, Test, NEXT_VALIDATORS}, }; + use codec::Encode; - use frame_support::traits::{KeyOwnerProofSystem, OnInitialize}; use sp_core::{ crypto::key_types::DUMMY, offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt, StorageKind}, }; - - use frame_support::BasicExternalities; use sp_runtime::testing::UintAuthorityId; + use frame_support::{ + traits::{GenesisBuild, KeyOwnerProofSystem, OnInitialize}, + BasicExternalities, + }; + type Historical = Module; pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/session/src/historical/onchain.rs b/frame/session/src/historical/onchain.rs index 514e343f4e0f6..c80817c28d723 100644 --- a/frame/session/src/historical/onchain.rs +++ b/frame/session/src/historical/onchain.rs @@ -19,15 +19,11 @@ use codec::Encode; use sp_runtime::traits::Convert; - -use super::{ - super::{Config as SessionConfig, Pallet as SessionModule, SessionIndex}, - Config as HistoricalConfig, -}; - -use super::shared; use sp_std::prelude::*; +use super::{shared, Config as HistoricalConfig}; +use crate::{Config as SessionConfig, Pallet as SessionModule, SessionIndex}; + /// Store the validator-set associated to the `session_index` to the off-chain database. /// /// Further processing is then done [`off-chain side`](super::offchain). diff --git a/frame/session/src/historical/shared.rs b/frame/session/src/historical/shared.rs index e801aa80eef4c..182e9ecacee19 100644 --- a/frame/session/src/historical/shared.rs +++ b/frame/session/src/historical/shared.rs @@ -18,8 +18,8 @@ //! Shared logic between on-chain and off-chain components used for slashing using an off-chain //! worker. -use super::SessionIndex; use codec::Encode; +use sp_staking::SessionIndex; use sp_std::prelude::*; pub(super) const PREFIX: &[u8] = b"session_historical"; diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index e57decec8c651..2742d302ce439 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -15,14 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Session Module +//! # Session Pallet //! -//! The Session module allows validators to manage their session keys, provides a function for +//! The Session pallet allows validators to manage their session keys, provides a function for //! changing the session length, and handles session rotation. //! //! - [`Config`] //! - [`Call`] -//! - [`Module`] +//! - [`Pallet`] //! //! ## Overview //! @@ -95,12 +95,12 @@ //! use pallet_session as session; //! //! fn validators() -> Vec<::ValidatorId> { -//! >::validators() +//! >::validators() //! } //! # fn main(){} //! ``` //! -//! ## Related Modules +//! ## Related Pallets //! //! - [Staking](../pallet_staking/index.html) @@ -114,22 +114,9 @@ mod mock; mod tests; pub mod weights; -use codec::{Decode, MaxEncodedLen}; -use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, - dispatch::{self, DispatchError, DispatchResult}, - ensure, - traits::{ - EstimateNextNewSession, EstimateNextSessionRotation, FindAuthor, Get, OneSessionHandler, - ValidatorRegistration, ValidatorSet, - }, - weights::Weight, - ConsensusEngineId, Parameter, -}; -use frame_system::ensure_signed; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Convert, Member, One, OpaqueKeys, Zero}, - KeyTypeId, Perbill, Permill, RuntimeAppPublic, + ConsensusEngineId, KeyTypeId, Perbill, Permill, RuntimeAppPublic, }; use sp_staking::SessionIndex; use sp_std::{ @@ -137,6 +124,20 @@ use sp_std::{ ops::{Rem, Sub}, prelude::*, }; + +use frame_support::{ + codec::{Decode, MaxEncodedLen}, + dispatch::{DispatchError, DispatchResult}, + ensure, + traits::{ + EstimateNextNewSession, EstimateNextSessionRotation, FindAuthor, Get, OneSessionHandler, + StorageVersion, ValidatorRegistration, ValidatorSet, + }, + weights::Weight, + Parameter, +}; + +pub use pallet::*; pub use weights::WeightInfo; /// Decides whether the session should be ended. @@ -228,7 +229,7 @@ pub trait SessionManager { /// /// Even if the validator-set is the same as before, if any underlying economic conditions have /// changed (i.e. stake-weights), the new validator set must be returned. This is necessary for - /// consensus engines making use of the session module to issue a validator-set change so + /// consensus engines making use of the session pallet to issue a validator-set change so /// misbehavior can be provably associated with the new economic conditions as opposed to the /// old. The returned validator set, if any, will not be applied until `new_index`. `new_index` /// is strictly greater than from previous call. @@ -280,7 +281,7 @@ pub trait SessionHandler { fn on_genesis_session(validators: &[(ValidatorId, Ks)]); /// Session set has changed; act appropriately. Note that this can be called - /// before initialization of your module. + /// before initialization of your pallet. /// /// `changed` is true whenever any of the session keys or underlying economic /// identities or weightings behind those keys has changed. @@ -356,86 +357,83 @@ impl SessionHandler for TestSessionHandler { fn on_disabled(_: usize) {} } -impl ValidatorRegistration for Module { - fn is_registered(id: &T::ValidatorId) -> bool { - Self::load_keys(id).is_some() - } -} - -pub trait Config: frame_system::Config { - /// The overarching event type. - type Event: From + Into<::Event>; +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; - /// A stable ID for a validator. - type ValidatorId: Member + Parameter + MaxEncodedLen; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); - /// A conversion from account ID to validator ID. - /// - /// Its cost must be at most one storage read. - type ValidatorIdOf: Convert>; - - /// Indicator for when to end the session. - type ShouldEndSession: ShouldEndSession; - - /// Something that can predict the next session rotation. This should typically come from the - /// same logical unit that provides [`ShouldEndSession`], yet, it gives a best effort estimate. - /// It is helpful to implement [`EstimateNextNewSession`]. - type NextSessionRotation: EstimateNextSessionRotation; - - /// Handler for managing new session. - type SessionManager: SessionManager; + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); - /// Handler when a session has changed. - type SessionHandler: SessionHandler; + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From + IsType<::Event>; - /// The keys. - type Keys: OpaqueKeys + Member + Parameter + Default; + /// A stable ID for a validator. + type ValidatorId: Member + Parameter + MaybeSerializeDeserialize + MaxEncodedLen; - /// The fraction of validators set that is safe to be disabled. - /// - /// After the threshold is reached `disabled` method starts to return true, - /// which in combination with `pallet_staking` forces a new era. - type DisabledValidatorsThreshold: Get; + /// A conversion from account ID to validator ID. + /// + /// Its cost must be at most one storage read. + type ValidatorIdOf: Convert>; - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; -} + /// Indicator for when to end the session. + type ShouldEndSession: ShouldEndSession; -decl_storage! { - trait Store for Module as Session { - /// The current set of validators. - Validators get(fn validators): Vec; + /// Something that can predict the next session rotation. This should typically come from + /// the same logical unit that provides [`ShouldEndSession`], yet, it gives a best effort + /// estimate. It is helpful to implement [`EstimateNextNewSession`]. + type NextSessionRotation: EstimateNextSessionRotation; - /// Current index of the session. - CurrentIndex get(fn current_index): SessionIndex; + /// Handler for managing new session. + type SessionManager: SessionManager; - /// True if the underlying economic identities or weighting behind the validators - /// has changed in the queued validator set. - QueuedChanged: bool; + /// Handler when a session has changed. + type SessionHandler: SessionHandler; - /// The queued keys for the next session. When the next session begins, these keys - /// will be used to determine the validator's session keys. - QueuedKeys get(fn queued_keys): Vec<(T::ValidatorId, T::Keys)>; + /// The keys. + type Keys: OpaqueKeys + Member + Parameter + Default + MaybeSerializeDeserialize; - /// Indices of disabled validators. + /// The fraction of validators set that is safe to be disabled. /// - /// The set is cleared when `on_session_ending` returns a new set of identities. - DisabledValidators get(fn disabled_validators): Vec; + /// After the threshold is reached `disabled` method starts to return true, + /// which in combination with `pallet_staking` forces a new era. + type DisabledValidatorsThreshold: Get; - /// The next session keys for a validator. - NextKeys: map hasher(twox_64_concat) T::ValidatorId => Option; + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::genesis_config] + pub struct GenesisConfig { + pub keys: Vec<(T::AccountId, T::ValidatorId, T::Keys)>, + } - /// The owner of a key. The key is the `KeyTypeId` + the encoded key. - KeyOwner: map hasher(twox_64_concat) (KeyTypeId, Vec) => Option; + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + Self { keys: Default::default() } + } } - add_extra_genesis { - config(keys): Vec<(T::AccountId, T::ValidatorId, T::Keys)>; - build(|config: &GenesisConfig| { + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { if T::SessionHandler::KEY_TYPE_IDS.len() != T::Keys::key_ids().len() { panic!("Number of keys in session handler and session keys does not match"); } - T::SessionHandler::KEY_TYPE_IDS.iter().zip(T::Keys::key_ids()).enumerate() + T::SessionHandler::KEY_TYPE_IDS + .iter() + .zip(T::Keys::key_ids()) + .enumerate() .for_each(|(i, (sk, kk))| { if sk != kk { panic!( @@ -445,8 +443,8 @@ decl_storage! { } }); - for (account, val, keys) in config.keys.iter().cloned() { - >::inner_set_keys(&val, keys) + for (account, val, keys) in self.keys.iter().cloned() { + >::inner_set_keys(&val, keys) .expect("genesis config must not contain duplicates; qed"); if frame_system::Pallet::::inc_consumers(&account).is_err() { // This will leak a provider reference, however it only happens once (at @@ -457,25 +455,30 @@ decl_storage! { } } - let initial_validators_0 = T::SessionManager::new_session_genesis(0) - .unwrap_or_else(|| { - frame_support::print("No initial validator provided by `SessionManager`, use \ - session config keys to generate initial validator set."); - config.keys.iter().map(|x| x.1.clone()).collect() + let initial_validators_0 = + T::SessionManager::new_session_genesis(0).unwrap_or_else(|| { + frame_support::print( + "No initial validator provided by `SessionManager`, use \ + session config keys to generate initial validator set.", + ); + self.keys.iter().map(|x| x.1.clone()).collect() }); - assert!(!initial_validators_0.is_empty(), "Empty validator set for session 0 in genesis block!"); + assert!( + !initial_validators_0.is_empty(), + "Empty validator set for session 0 in genesis block!" + ); let initial_validators_1 = T::SessionManager::new_session_genesis(1) .unwrap_or_else(|| initial_validators_0.clone()); - assert!(!initial_validators_1.is_empty(), "Empty validator set for session 1 in genesis block!"); + assert!( + !initial_validators_1.is_empty(), + "Empty validator set for session 1 in genesis block!" + ); let queued_keys: Vec<_> = initial_validators_1 .iter() .cloned() - .map(|v| ( - v.clone(), - >::load_keys(&v).unwrap_or_default(), - )) + .map(|v| (v.clone(), >::load_keys(&v).unwrap_or_default())) .collect(); // Tell everyone about the genesis session keys @@ -485,21 +488,62 @@ decl_storage! { >::put(queued_keys); T::SessionManager::start_session(0); - }); + } } -} -decl_event!( + /// The current set of validators. + #[pallet::storage] + #[pallet::getter(fn validators)] + pub type Validators = StorageValue<_, Vec, ValueQuery>; + + /// Current index of the session. + #[pallet::storage] + #[pallet::getter(fn current_index)] + pub type CurrentIndex = StorageValue<_, SessionIndex, ValueQuery>; + + /// True if the underlying economic identities or weighting behind the validators + /// has changed in the queued validator set. + #[pallet::storage] + pub type QueuedChanged = StorageValue<_, bool, ValueQuery>; + + /// The queued keys for the next session. When the next session begins, these keys + /// will be used to determine the validator's session keys. + #[pallet::storage] + #[pallet::getter(fn queued_keys)] + pub type QueuedKeys = StorageValue<_, Vec<(T::ValidatorId, T::Keys)>, ValueQuery>; + + /// Indices of disabled validators. + /// + /// The set is cleared when `on_session_ending` returns a new set of identities. + #[pallet::storage] + #[pallet::getter(fn disabled_validators)] + pub type DisabledValidators = StorageValue<_, Vec, ValueQuery>; + + /// The next session keys for a validator. + #[pallet::storage] + pub type NextKeys = + StorageMap<_, Twox64Concat, T::ValidatorId, T::Keys, OptionQuery>; + + /// The owner of a key. The key is the `KeyTypeId` + the encoded key. + #[pallet::storage] + pub type KeyOwner = + StorageMap<_, Twox64Concat, (KeyTypeId, Vec), T::ValidatorId, OptionQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// New session has happened. Note that the argument is the \[session_index\], not the /// block number as the type might suggest. NewSession(SessionIndex), } -); -decl_error! { - /// Error for the session module. - pub enum Error for Module { + /// Old name generated by `decl_event`. + #[deprecated(note = "use `Event` instead")] + pub type RawEvent = Event; + + /// Error for the session pallet. + #[pallet::error] + pub enum Error { /// Invalid ownership proof. InvalidProof, /// No associated validator ID for account. @@ -511,14 +555,26 @@ decl_error! { /// Key setting account is not live, so it's impossible to associate keys. NoAccount, } -} -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - type Error = Error; - - fn deposit_event() = default; + #[pallet::hooks] + impl Hooks> for Pallet { + /// Called when a block is initialized. Will rotate session if it is the last + /// block of the current session. + fn on_initialize(n: T::BlockNumber) -> Weight { + if T::ShouldEndSession::should_end_session(n) { + Self::rotate_session(); + T::BlockWeights::get().max_block + } else { + // NOTE: the non-database part of the weight for `should_end_session(n)` is + // included as weight for empty block, the database part is expected to be in + // cache. + 0 + } + } + } + #[pallet::call] + impl Pallet { /// Sets the session key(s) of the function caller to `keys`. /// Allows an account to set its session key prior to becoming a validator. /// This doesn't take effect until the next session. @@ -526,21 +582,19 @@ decl_module! { /// The dispatch origin of this function must be signed. /// /// # - /// - Complexity: `O(1)` - /// Actual cost depends on the number of length of `T::Keys::key_ids()` which is fixed. + /// - Complexity: `O(1)`. Actual cost depends on the number of length of + /// `T::Keys::key_ids()` which is fixed. /// - DbReads: `origin account`, `T::ValidatorIdOf`, `NextKeys` /// - DbWrites: `origin account`, `NextKeys` /// - DbReads per key id: `KeyOwner` /// - DbWrites per key id: `KeyOwner` /// # - #[weight = T::WeightInfo::set_keys()] - pub fn set_keys(origin, keys: T::Keys, proof: Vec) -> dispatch::DispatchResult { + #[pallet::weight(T::WeightInfo::set_keys())] + pub fn set_keys(origin: OriginFor, keys: T::Keys, proof: Vec) -> DispatchResult { let who = ensure_signed(origin)?; - ensure!(keys.ownership_proof_is_valid(&proof), Error::::InvalidProof); Self::do_set_keys(&who, keys)?; - Ok(()) } @@ -550,43 +604,30 @@ decl_module! { /// The dispatch origin of this function must be signed. /// /// # - /// - Complexity: `O(1)` in number of key types. - /// Actual cost depends on the number of length of `T::Keys::key_ids()` which is fixed. + /// - Complexity: `O(1)` in number of key types. Actual cost depends on the number of length + /// of `T::Keys::key_ids()` which is fixed. /// - DbReads: `T::ValidatorIdOf`, `NextKeys`, `origin account` /// - DbWrites: `NextKeys`, `origin account` /// - DbWrites per key id: `KeyOwner` /// # - #[weight = T::WeightInfo::purge_keys()] - pub fn purge_keys(origin) { + #[pallet::weight(T::WeightInfo::purge_keys())] + pub fn purge_keys(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; Self::do_purge_keys(&who)?; - } - - /// Called when a block is initialized. Will rotate session if it is the last - /// block of the current session. - fn on_initialize(n: T::BlockNumber) -> Weight { - if T::ShouldEndSession::should_end_session(n) { - Self::rotate_session(); - T::BlockWeights::get().max_block - } else { - // NOTE: the non-database part of the weight for `should_end_session(n)` is - // included as weight for empty block, the database part is expected to be in - // cache. - 0 - } + Ok(()) } } } -impl Module { +impl Pallet { /// Move on to next session. Register new validator set and session keys. Changes to the /// validator set have a session of delay to take effect. This allows for equivocation /// punishment after a fork. pub fn rotate_session() { - let session_index = CurrentIndex::get(); + let session_index = >::get(); log::trace!(target: "runtime::session", "rotating session {:?}", session_index); - let changed = QueuedChanged::get(); + let changed = >::get(); // Inform the session handlers that a session is going to end. T::SessionHandler::on_before_session_ending(); @@ -600,12 +641,12 @@ impl Module { if changed { // reset disabled validators - DisabledValidators::take(); + >::take(); } // Increment session index. let session_index = session_index + 1; - CurrentIndex::put(session_index); + >::put(session_index); T::SessionManager::start_session(session_index); @@ -655,7 +696,7 @@ impl Module { }; >::put(queued_amalgamated.clone()); - QueuedChanged::put(next_changed); + >::put(next_changed); // Record that this happened. Self::deposit_event(Event::NewSession(session_index)); @@ -669,7 +710,7 @@ impl Module { /// Returns `true` if this causes a `DisabledValidatorsThreshold` of validators /// to be already disabled. pub fn disable_index(i: usize) -> bool { - let (fire_event, threshold_reached) = DisabledValidators::mutate(|disabled| { + let (fire_event, threshold_reached) = >::mutate(|disabled| { let i = i as u32; if let Err(index) = disabled.binary_search(&i) { let count = >::decode_len().unwrap_or(0) as u32; @@ -688,12 +729,12 @@ impl Module { threshold_reached } - /// Disable the validator identified by `c`. (If using with the staking module, + /// Disable the validator identified by `c`. (If using with the staking pallet, /// this would be their *stash* account.) /// /// Returns `Ok(true)` if more than `DisabledValidatorsThreshold` validators in current /// session is already disabled. - /// If used with the staking module it allows to force a new era in such case. + /// If used with the staking pallet it allows to force a new era in such case. pub fn disable(c: &T::ValidatorId) -> sp_std::result::Result { Self::validators() .iter() @@ -711,7 +752,7 @@ impl Module { /// /// Care should be taken that the raw versions of the /// added keys are unique for every `ValidatorId, KeyTypeId` combination. - /// This is an invariant that the session module typically maintains internally. + /// This is an invariant that the session pallet typically maintains internally. /// /// As the actual values of the keys are typically not known at runtime upgrade, /// it's recommended to initialize the keys to a (unique) dummy value with the expectation @@ -756,7 +797,7 @@ impl Module { /// /// This ensures that the reference counter in system is incremented appropriately and as such /// must accept an account ID, rather than a validator ID. - fn do_set_keys(account: &T::AccountId, keys: T::Keys) -> dispatch::DispatchResult { + fn do_set_keys(account: &T::AccountId, keys: T::Keys) -> DispatchResult { let who = T::ValidatorIdOf::convert(account.clone()) .ok_or(Error::::NoAssociatedValidatorId)?; @@ -850,16 +891,40 @@ impl Module { } } -impl ValidatorSet for Module { +impl ValidatorRegistration for Pallet { + fn is_registered(id: &T::ValidatorId) -> bool { + Self::load_keys(id).is_some() + } +} + +impl ValidatorSet for Pallet { type ValidatorId = T::ValidatorId; type ValidatorIdOf = T::ValidatorIdOf; fn session_index() -> sp_staking::SessionIndex { - Module::::current_index() + Pallet::::current_index() } fn validators() -> Vec { - Module::::validators() + Pallet::::validators() + } +} + +impl EstimateNextNewSession for Pallet { + fn average_session_length() -> T::BlockNumber { + T::NextSessionRotation::average_session_length() + } + + /// This session pallet always calls new_session and next_session at the same time, hence we + /// do a simple proxy and pass the function to next rotation. + fn estimate_next_new_session(now: T::BlockNumber) -> (Option, Weight) { + T::NextSessionRotation::estimate_next_session_rotation(now) + } +} + +impl frame_support::traits::DisabledValidators for Pallet { + fn is_disabled(index: u32) -> bool { + >::disabled_validators().binary_search(&index).is_ok() } } @@ -877,25 +942,7 @@ impl> FindAuthor { let i = Inner::find_author(digests)?; - let validators = >::validators(); + let validators = >::validators(); validators.get(i as usize).map(|k| k.clone()) } } - -impl EstimateNextNewSession for Module { - fn average_session_length() -> T::BlockNumber { - T::NextSessionRotation::average_session_length() - } - - /// This session module always calls new_session and next_session at the same time, hence we - /// do a simple proxy and pass the function to next rotation. - fn estimate_next_new_session(now: T::BlockNumber) -> (Option, Weight) { - T::NextSessionRotation::estimate_next_session_rotation(now) - } -} - -impl frame_support::traits::DisabledValidators for Module { - fn is_disabled(index: u32) -> bool { - >::disabled_validators().binary_search(&index).is_ok() - } -} diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index 449acaff5305d..c6b5f64448114 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -21,7 +21,9 @@ use super::*; use crate as pallet_session; #[cfg(feature = "historical")] use crate::historical as pallet_session_historical; -use frame_support::{parameter_types, BasicExternalities}; + +use std::cell::RefCell; + use sp_core::{crypto::key_types::DUMMY, H256}; use sp_runtime::{ impl_opaque_keys, @@ -30,7 +32,8 @@ use sp_runtime::{ Perbill, }; use sp_staking::SessionIndex; -use std::cell::RefCell; + +use frame_support::{parameter_types, traits::GenesisBuild, BasicExternalities}; impl_opaque_keys! { pub struct MockSessionKeys { diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index 23e1c6a993427..47152042d204f 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -18,17 +18,19 @@ // Tests for the Session Pallet use super::*; -use codec::Decode; -use frame_support::{assert_noop, assert_ok, traits::OnInitialize}; -use mock::{ +use crate::mock::{ authorities, before_session_end_called, force_new_session, new_test_ext, reset_before_session_end_called, session_changed, set_next_validators, set_session_length, Origin, PreUpgradeMockSessionKeys, Session, System, Test, SESSION_CHANGED, TEST_SESSION_CHANGED, }; + +use codec::Decode; use sp_core::crypto::key_types::DUMMY; use sp_runtime::testing::UintAuthorityId; +use frame_support::{assert_noop, assert_ok, traits::OnInitialize}; + fn initialize_block(block: u64) { SESSION_CHANGED.with(|l| *l.borrow_mut() = false); System::set_block_number(block); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index b3ce8e063cb61..06c9be9c01e11 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -22,8 +22,7 @@ use frame_election_provider_support::{onchain, SortedListProvider}; use frame_support::{ assert_ok, parameter_types, traits::{ - Currency, FindAuthor, GenesisBuild, Get, Hooks, Imbalance, OnInitialize, OnUnbalanced, - OneSessionHandler, + Currency, FindAuthor, GenesisBuild, Get, Hooks, Imbalance, OnUnbalanced, OneSessionHandler, }, weights::constants::RocksDbWeight, }; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 38b760896d7d8..6f024eb1e6b04 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -23,7 +23,7 @@ use frame_support::{ assert_noop, assert_ok, dispatch::WithPostDispatchInfo, pallet_prelude::*, - traits::{Currency, Get, OnInitialize, ReservableCurrency}, + traits::{Currency, Get, ReservableCurrency}, weights::{extract_actual_weight, GetDispatchInfo}, }; use mock::*; From 0f3db4ef32ad36b7c16c6d888413be3b1d6cb97e Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 28 Sep 2021 05:47:38 +0100 Subject: [PATCH 0036/1472] Point to nightly that can compile the code. (#9873) --- shell.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell.nix b/shell.nix index 9a2d30400631f..a86af005383f7 100644 --- a/shell.nix +++ b/shell.nix @@ -5,7 +5,7 @@ let rev = "4a07484cf0e49047f82d83fd119acffbad3b235f"; }); nixpkgs = import { overlays = [ mozillaOverlay ]; }; - rust-nightly = with nixpkgs; ((rustChannelOf { date = "2021-07-06"; channel = "nightly"; }).rust.override { + rust-nightly = with nixpkgs; ((rustChannelOf { date = "2021-09-10"; channel = "nightly"; }).rust.override { extensions = [ "rust-src" ]; targets = [ "wasm32-unknown-unknown" ]; }); From fa92eaf1eadc5b28b76d005031e9c86621c92217 Mon Sep 17 00:00:00 2001 From: Gautham Date: Tue, 28 Sep 2021 11:40:40 +0530 Subject: [PATCH 0037/1472] Add Polkadex to SS58 Registry (#9825) * Add PDEX to SS58 Registry. * Add PDEX to SS58 Registry. --- primitives/core/src/crypto.rs | 2 ++ ss58-registry.json | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 4764a0cac1b14..cf7be5f2166e8 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -597,6 +597,8 @@ ss58_address_format!( (77, "manta", "Manta Network, standard account (*25519).") CalamariAccount => (78, "calamari", "Manta Canary Network, standard account (*25519).") + Polkadex => + (88, "polkadex", "Polkadex Mainnet, standard account (*25519).") PolkaSmith => (98, "polkasmith", "PolkaSmith Canary Network, standard account (*25519).") PolkaFoundry => diff --git a/ss58-registry.json b/ss58-registry.json index 563cc248db9dd..7c95f421586a4 100644 --- a/ss58-registry.json +++ b/ss58-registry.json @@ -532,6 +532,15 @@ "standardAccount": "*25519", "website": "https://manta.network" }, + { + "prefix": 88, + "network": "polkadex", + "displayName": "Polkadex Mainnet", + "symbols": ["PDEX"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://polkadex.trade" + }, { "prefix": 98, "network": "polkasmith", From c11a0bf8537abde0cf843c770f481366b964ca6f Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Tue, 28 Sep 2021 02:35:33 -0700 Subject: [PATCH 0038/1472] Extend PalletInfoAccess with module_name and crate_version method (#9690) * Record pallet indices in CallMetadata * Resurrect PalletVersion infrastructure and rename as CrateVersion * cargo fmt * Add missing runtime generics to pallet struct * Fix path to instance * Fix test * Fix UI test expectations * Fix UI test expectations * Move crate_version function to PalletInfoAccess * Update UI test expectations * Add crate_name method to PalletInfo * Convert path to module name instead of exposing crate name * cargo fmt * Keep the double colons when constructing the module name * Remove unused import * Update UI test expectations * Update frame/support/src/traits/metadata.rs Co-authored-by: Guillaume Thiolliere * Update UI test expectations Co-authored-by: Guillaume Thiolliere --- .../procedural/src/construct_runtime/mod.rs | 43 +++++++++++++-- .../procedural/src/construct_runtime/parse.rs | 12 +++++ frame/support/procedural/src/crate_version.rs | 54 +++++++++++++++++++ frame/support/procedural/src/lib.rs | 20 ++++++- .../src/pallet/expand/pallet_struct.rs | 12 +++++ frame/support/src/dispatch.rs | 32 ++++++++++- frame/support/src/lib.rs | 22 ++++++++ frame/support/src/traits.rs | 4 +- frame/support/src/traits/metadata.rs | 43 +++++++++++++-- frame/support/test/src/lib.rs | 6 +++ frame/support/test/tests/construct_runtime.rs | 28 +++++++++- .../storage_info_unsatisfied_nmap.stderr | 4 +- test-utils/runtime/src/lib.rs | 35 +++++++++++- 13 files changed, 299 insertions(+), 16 deletions(-) create mode 100644 frame/support/procedural/src/crate_version.rs diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 8aacd8f0aa810..04bb2ead645d2 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -132,7 +132,7 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result( } fn decl_pallet_runtime_setup( + runtime: &Ident, pallet_declarations: &[Pallet], scrate: &TokenStream2, ) -> TokenStream2 { - let names = pallet_declarations.iter().map(|d| &d.name); - let names2 = pallet_declarations.iter().map(|d| &d.name); + let names = pallet_declarations.iter().map(|d| &d.name).collect::>(); let name_strings = pallet_declarations.iter().map(|d| d.name.to_string()); + let module_names = pallet_declarations.iter().map(|d| d.path.module_name()); let indices = pallet_declarations.iter().map(|pallet| pallet.index as usize); + let pallet_structs = pallet_declarations + .iter() + .map(|pallet| { + let path = &pallet.path; + match pallet.instance.as_ref() { + Some(inst) => quote!(#path::Pallet<#runtime, #path::#inst>), + None => quote!(#path::Pallet<#runtime>), + } + }) + .collect::>(); quote!( /// Provides an implementation of `PalletInfo` to provide information @@ -264,13 +275,37 @@ fn decl_pallet_runtime_setup( fn name() -> Option<&'static str> { let type_id = #scrate::sp_std::any::TypeId::of::

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

(); + #( + if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { + return Some(#module_names) + } + )* + + None + } + + fn crate_version() -> Option<#scrate::traits::CrateVersion> { + let type_id = #scrate::sp_std::any::TypeId::of::

(); + #( + if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { + return Some( + <#pallet_structs as #scrate::traits::PalletInfoAccess>::crate_version() + ) + } + )* + + None + } } ) } diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index 6f2fd82e73f4b..a0ec6dfa5803e 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -188,6 +188,18 @@ pub struct PalletPath { pub inner: Path, } +impl PalletPath { + pub fn module_name(&self) -> String { + self.inner.segments.iter().fold(String::new(), |mut acc, segment| { + if !acc.is_empty() { + acc.push_str("::"); + } + acc.push_str(&segment.ident.to_string()); + acc + }) + } +} + impl Parse for PalletPath { fn parse(input: ParseStream) -> Result { let mut lookahead = input.lookahead1(); diff --git a/frame/support/procedural/src/crate_version.rs b/frame/support/procedural/src/crate_version.rs new file mode 100644 index 0000000000000..cfa35c6190e15 --- /dev/null +++ b/frame/support/procedural/src/crate_version.rs @@ -0,0 +1,54 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of macros related to crate versioning. + +use super::get_cargo_env_var; +use frame_support_procedural_tools::generate_crate_access_2018; +use proc_macro2::{Span, TokenStream}; +use syn::{Error, Result}; + +/// Create an error that will be shown by rustc at the call site of the macro. +fn create_error(message: &str) -> Error { + Error::new(Span::call_site(), message) +} + +/// Implementation of the `crate_to_crate_version!` macro. +pub fn crate_to_crate_version(input: proc_macro::TokenStream) -> Result { + if !input.is_empty() { + return Err(create_error("No arguments expected!")) + } + + let major_version = get_cargo_env_var::("CARGO_PKG_VERSION_MAJOR") + .map_err(|_| create_error("Major version needs to fit into `u16`"))?; + + let minor_version = get_cargo_env_var::("CARGO_PKG_VERSION_MINOR") + .map_err(|_| create_error("Minor version needs to fit into `u8`"))?; + + let patch_version = get_cargo_env_var::("CARGO_PKG_VERSION_PATCH") + .map_err(|_| create_error("Patch version needs to fit into `u8`"))?; + + let crate_ = generate_crate_access_2018("frame-support")?; + + Ok(quote::quote! { + #crate_::traits::CrateVersion { + major: #major_version, + minor: #minor_version, + patch: #patch_version, + } + }) +} diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index a8ac022c35c6b..6987fc49b9a8c 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -21,6 +21,7 @@ mod clone_no_bound; mod construct_runtime; +mod crate_version; mod debug_no_bound; mod default_no_bound; mod dummy_part_checker; @@ -31,7 +32,7 @@ mod storage; mod transactional; use proc_macro::TokenStream; -use std::cell::RefCell; +use std::{cell::RefCell, str::FromStr}; pub(crate) use storage::INHERENT_INSTANCE_NAME; thread_local! { @@ -52,6 +53,16 @@ impl Counter { } } +/// Get the value from the given environment variable set by cargo. +/// +/// The value is parsed into the requested destination type. +fn get_cargo_env_var(version_env: &str) -> std::result::Result { + let version = std::env::var(version_env) + .unwrap_or_else(|_| panic!("`{}` is always set by cargo; qed", version_env)); + + T::from_str(&version).map_err(drop) +} + /// Declares strongly-typed wrappers around codec-compatible types in storage. /// /// ## Example @@ -462,6 +473,13 @@ pub fn require_transactional(attr: TokenStream, input: TokenStream) -> TokenStre .unwrap_or_else(|e| e.to_compile_error().into()) } +#[proc_macro] +pub fn crate_to_crate_version(input: TokenStream) -> TokenStream { + crate_version::crate_to_crate_version(input) + .unwrap_or_else(|e| e.to_compile_error()) + .into() +} + /// The number of module instances supported by the runtime, starting at index 1, /// and up to `NUMBER_OF_INSTANCE`. pub(crate) const NUMBER_OF_INSTANCE: u8 = 16; diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 0ad8a25b8e9a2..ea601f138ea05 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -219,6 +219,18 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { .expect("Pallet is part of the runtime because pallet `Config` trait is \ implemented by the runtime") } + + fn module_name() -> &'static str { + < + ::PalletInfo as #frame_support::traits::PalletInfo + >::module_name::() + .expect("Pallet is part of the runtime because pallet `Config` trait is \ + implemented by the runtime") + } + + fn crate_version() -> #frame_support::traits::CrateVersion { + #frame_support::crate_to_crate_version!() + } } #storage_info diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 2e6777fee2af2..b4e9071e361aa 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -2151,6 +2151,18 @@ macro_rules! decl_module { .expect("Pallet is part of the runtime because pallet `Config` trait is \ implemented by the runtime") } + + fn module_name() -> &'static str { + < + <$trait_instance as $system::Config>::PalletInfo as $crate::traits::PalletInfo + >::module_name::() + .expect("Pallet is part of the runtime because pallet `Config` trait is \ + implemented by the runtime") + } + + fn crate_version() -> $crate::traits::CrateVersion { + $crate::crate_to_crate_version!() + } } // Implement GetCallName for the Call. @@ -2529,8 +2541,8 @@ mod tests { use crate::{ metadata::*, traits::{ - Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, - PalletInfo, + CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize, + OnRuntimeUpgrade, PalletInfo, }, weights::{DispatchClass, DispatchInfo, Pays, RuntimeDbWeight}, }; @@ -2631,6 +2643,22 @@ mod tests { return Some("Test") } + None + } + fn module_name() -> Option<&'static str> { + let type_id = sp_std::any::TypeId::of::

(); + if type_id == sp_std::any::TypeId::of::() { + return Some("tests") + } + + None + } + fn crate_version() -> Option { + let type_id = sp_std::any::TypeId::of::

(); + if type_id == sp_std::any::TypeId::of::() { + return Some(frame_support::crate_to_crate_version!()) + } + None } } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index f56af036eb2a3..f3b00c764bb35 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -702,6 +702,21 @@ pub use frame_support_procedural::DefaultNoBound; /// ``` pub use frame_support_procedural::require_transactional; +/// Convert the current crate version into a [`CrateVersion`](crate::traits::CrateVersion). +/// +/// It uses the `CARGO_PKG_VERSION_MAJOR`, `CARGO_PKG_VERSION_MINOR` and +/// `CARGO_PKG_VERSION_PATCH` environment variables to fetch the crate version. +/// This means that the [`CrateVersion`](crate::traits::CrateVersion) +/// object will correspond to the version of the crate the macro is called in! +/// +/// # Example +/// +/// ``` +/// # use frame_support::{traits::CrateVersion, crate_to_crate_version}; +/// const Version: CrateVersion = crate_to_crate_version!(); +/// ``` +pub use frame_support_procedural::crate_to_crate_version; + /// Return Err of the expression: `return Err($expression);`. /// /// Used as `fail!(expression)`. @@ -819,6 +834,7 @@ pub mod tests { StorageHasher, }; use codec::{Codec, EncodeLike}; + use frame_support::traits::CrateVersion; use sp_io::TestExternalities; use sp_std::result; @@ -832,6 +848,12 @@ pub mod tests { fn name() -> Option<&'static str> { unimplemented!("PanicPalletInfo mustn't be triggered by tests"); } + fn module_name() -> Option<&'static str> { + unimplemented!("PanicPalletInfo mustn't be triggered by tests"); + } + fn crate_version() -> Option { + unimplemented!("PanicPalletInfo mustn't be triggered by tests"); + } } pub trait Config: 'static { diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index d5d0decd117eb..5ac0208dc2033 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -62,8 +62,8 @@ pub use randomness::Randomness; mod metadata; pub use metadata::{ - CallMetadata, GetCallMetadata, GetCallName, GetStorageVersion, PalletInfo, PalletInfoAccess, - StorageVersion, STORAGE_VERSION_STORAGE_KEY_POSTFIX, + CallMetadata, CrateVersion, GetCallMetadata, GetCallName, GetStorageVersion, PalletInfo, + PalletInfoAccess, StorageVersion, STORAGE_VERSION_STORAGE_KEY_POSTFIX, }; mod hooks; diff --git a/frame/support/src/traits/metadata.rs b/frame/support/src/traits/metadata.rs index e877f29e0a137..14b7e6d7355e2 100644 --- a/frame/support/src/traits/metadata.rs +++ b/frame/support/src/traits/metadata.rs @@ -20,7 +20,7 @@ use codec::{Decode, Encode}; use sp_runtime::RuntimeDebug; -/// Provides information about the pallet setup in the runtime. +/// Provides information about the pallet itself and its setup in the runtime. /// /// An implementor should be able to provide information about each pallet that /// is configured in `construct_runtime!`. @@ -29,16 +29,25 @@ pub trait PalletInfo { fn index() -> Option; /// Convert the given pallet `P` into its name as configured in the runtime. fn name() -> Option<&'static str>; + /// Convert the given pallet `P` into its Rust module name as used in `construct_runtime!`. + fn module_name() -> Option<&'static str>; + /// Convert the given pallet `P` into its containing crate version. + fn crate_version() -> Option; } -/// Provides information about the pallet setup in the runtime. +/// Provides information about the pallet itself and its setup in the runtime. /// -/// Access the information provided by [`PalletInfo`] for a specific pallet. +/// Declare some information and access the information provided by [`PalletInfo`] for a specific +/// pallet. pub trait PalletInfoAccess { /// Index of the pallet as configured in the runtime. fn index() -> usize; /// Name of the pallet as configured in the runtime. fn name() -> &'static str; + /// Name of the Rust module containing the pallet. + fn module_name() -> &'static str; + /// Version of the crate containing the pallet. + fn crate_version() -> CrateVersion; } /// The function and pallet name of the Call. @@ -68,6 +77,34 @@ pub trait GetCallMetadata { fn get_call_metadata(&self) -> CallMetadata; } +/// The version of a crate. +#[derive(RuntimeDebug, Eq, PartialEq, Encode, Decode, Ord, Clone, Copy, Default)] +pub struct CrateVersion { + /// The major version of the crate. + pub major: u16, + /// The minor version of the crate. + pub minor: u8, + /// The patch version of the crate. + pub patch: u8, +} + +impl CrateVersion { + pub const fn new(major: u16, minor: u8, patch: u8) -> Self { + Self { major, minor, patch } + } +} + +impl sp_std::cmp::PartialOrd for CrateVersion { + fn partial_cmp(&self, other: &Self) -> Option { + let res = self + .major + .cmp(&other.major) + .then_with(|| self.minor.cmp(&other.minor).then_with(|| self.patch.cmp(&other.patch))); + + Some(res) + } +} + /// The storage key postfix that is used to store the [`StorageVersion`] per pallet. /// /// The full storage key is built by using: diff --git a/frame/support/test/src/lib.rs b/frame/support/test/src/lib.rs index 52c0a6270d47f..073f8c9c19352 100644 --- a/frame/support/test/src/lib.rs +++ b/frame/support/test/src/lib.rs @@ -49,6 +49,12 @@ impl frame_support::traits::PalletInfo for PanicPalletInfo { fn name() -> Option<&'static str> { unimplemented!("PanicPalletInfo mustn't be triggered by tests"); } + fn module_name() -> Option<&'static str> { + unimplemented!("PanicPalletInfo mustn't be triggered by tests"); + } + fn crate_version() -> Option { + unimplemented!("PanicPalletInfo mustn't be triggered by tests"); + } } /// Provides an implementation of [`frame_support::traits::Randomness`] that should only be used in diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 062993fe10fbb..dd5538370449d 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -21,7 +21,7 @@ #![recursion_limit = "128"] -use frame_support::traits::PalletInfo as _; +use frame_support::traits::{CrateVersion, PalletInfo as _}; use scale_info::TypeInfo; use sp_core::{sr25519, H256}; use sp_runtime::{ @@ -739,40 +739,66 @@ fn test_metadata() { fn pallet_in_runtime_is_correct() { assert_eq!(PalletInfo::index::().unwrap(), 30); assert_eq!(PalletInfo::name::().unwrap(), "System"); + assert_eq!(PalletInfo::module_name::().unwrap(), "system"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 31); assert_eq!(PalletInfo::name::().unwrap(), "Module1_1"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 32); assert_eq!(PalletInfo::name::().unwrap(), "Module2"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module2"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 33); assert_eq!(PalletInfo::name::().unwrap(), "Module1_2"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 34); assert_eq!(PalletInfo::name::().unwrap(), "NestedModule3"); + assert_eq!(PalletInfo::module_name::().unwrap(), "nested::module3"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 35); assert_eq!(PalletInfo::name::().unwrap(), "Module3"); + assert_eq!(PalletInfo::module_name::().unwrap(), "self::module3"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 6); assert_eq!(PalletInfo::name::().unwrap(), "Module1_3"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 3); assert_eq!(PalletInfo::name::().unwrap(), "Module1_4"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 4); assert_eq!(PalletInfo::name::().unwrap(), "Module1_5"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 1); assert_eq!(PalletInfo::name::().unwrap(), "Module1_6"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 2); assert_eq!(PalletInfo::name::().unwrap(), "Module1_7"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 12); assert_eq!(PalletInfo::name::().unwrap(), "Module1_8"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); assert_eq!(PalletInfo::index::().unwrap(), 13); assert_eq!(PalletInfo::name::().unwrap(), "Module1_9"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert_eq!(PalletInfo::crate_version::().unwrap(), CrateVersion::new(3, 0, 0)); } diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index ffbc5aeea6b4f..2b70102fdac24 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -4,8 +4,8 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied 10 | #[pallet::generate_storage_info] | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | - = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `NMapKey` - = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>` + = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` + = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` note: required by `storage_info` --> $DIR/storage.rs:71:2 | diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 479d69c437567..943c41c247f75 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -36,7 +36,11 @@ use sp_trie::{ use trie_db::{Trie, TrieMut}; use cfg_if::cfg_if; -use frame_support::{parameter_types, traits::KeyOwnerProofSystem, weights::RuntimeDbWeight}; +use frame_support::{ + parameter_types, + traits::{CrateVersion, KeyOwnerProofSystem}, + weights::RuntimeDbWeight, +}; use frame_system::limits::{BlockLength, BlockWeights}; use sp_api::{decl_runtime_apis, impl_runtime_apis}; pub use sp_core::hash::H256; @@ -520,6 +524,35 @@ impl frame_support::traits::PalletInfo for Runtime { return Some("Babe") } + None + } + fn module_name() -> Option<&'static str> { + let type_id = sp_std::any::TypeId::of::

(); + if type_id == sp_std::any::TypeId::of::>() { + return Some("system") + } + if type_id == sp_std::any::TypeId::of::>() { + return Some("pallet_timestamp") + } + if type_id == sp_std::any::TypeId::of::>() { + return Some("pallet_babe") + } + + None + } + fn crate_version() -> Option { + use frame_support::traits::PalletInfoAccess as _; + let type_id = sp_std::any::TypeId::of::

(); + if type_id == sp_std::any::TypeId::of::>() { + return Some(system::Pallet::::crate_version()) + } + if type_id == sp_std::any::TypeId::of::>() { + return Some(pallet_timestamp::Pallet::::crate_version()) + } + if type_id == sp_std::any::TypeId::of::>() { + return Some(pallet_babe::Pallet::::crate_version()) + } + None } } From 7cf99b1a810324e8c6ce9113741d55905ee40b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 29 Sep 2021 09:10:20 +0200 Subject: [PATCH 0039/1472] Fix flaky sync tests (#9889) --- client/network/test/src/sync.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index c86ccfeac3ed1..f413b705e52c4 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -616,9 +616,10 @@ fn syncs_header_only_forks() { let small_hash = net.peer(0).client().info().best_hash; net.peer(1).push_blocks(4, false); - net.block_until_sync(); // Peer 1 will sync the small fork even though common block state is missing - assert!(net.peer(1).has_block(&small_hash)); + while !net.peer(1).has_block(&small_hash) { + net.block_until_idle(); + } } #[test] @@ -855,12 +856,19 @@ fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { net.block_until_idle(); // Connect another node that should now sync to the tip - net.add_full_peer_with_config(Default::default()); - net.block_until_connected(); + net.add_full_peer_with_config(FullPeerConfig { + connect_to_peers: Some(vec![0]), + ..Default::default() + }); - while !net.peer(2).has_block(&block_hash) { - net.block_until_idle(); - } + block_on(futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); + if net.peer(2).has_block(&block_hash) { + Poll::Ready(()) + } else { + Poll::Pending + } + })); // However peer 1 should still not have the block. assert!(!net.peer(1).has_block(&block_hash)); From 95c81d29f20268262783a5489a5151e8b25aeaf2 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Wed, 29 Sep 2021 09:48:26 +0200 Subject: [PATCH 0040/1472] Fix WrapperOpaque max encded len and type info (#9881) * fix wrapper opaque * fix compilation * improve more precise implementation * spacing * fmt --- frame/support/src/traits/misc.rs | 59 +++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 82c5512ac15c5..a040f8575abd2 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -17,10 +17,11 @@ //! Smaller traits used in FRAME which don't need their own file. -use crate::{dispatch::Parameter, TypeInfo}; +use crate::dispatch::Parameter; use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen}; +use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; use sp_runtime::{traits::Block as BlockT, DispatchError}; -use sp_std::vec::Vec; +use sp_std::prelude::*; /// Anything that can have a `::len()` method. pub trait Len { @@ -384,7 +385,7 @@ impl, const T: u32> EstimateCallFee for /// /// The encoding is the encoding of `T` prepended with the compact encoding of its size in bytes. /// Thus the encoded value can be decoded as a `Vec`. -#[derive(Debug, Eq, PartialEq, Default, Clone, MaxEncodedLen, TypeInfo)] +#[derive(Debug, Eq, PartialEq, Default, Clone)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct WrapperOpaque(pub T); @@ -392,8 +393,7 @@ impl EncodeLike for WrapperOpaque {} impl Encode for WrapperOpaque { fn size_hint(&self) -> usize { - // Compact usually takes at most 4 bytes - self.0.size_hint().saturating_add(4) + self.0.size_hint().saturating_add(>::max_encoded_len()) } fn encode_to(&self, dest: &mut O) { @@ -425,6 +425,37 @@ impl From for WrapperOpaque { } } +impl MaxEncodedLen for WrapperOpaque { + fn max_encoded_len() -> usize { + let t_max_len = T::max_encoded_len(); + + // See scale encoding https://substrate.dev/docs/en/knowledgebase/advanced/codec + if t_max_len < 64 { + t_max_len + 1 + } else if t_max_len < 2usize.pow(14) { + t_max_len + 2 + } else if t_max_len < 2usize.pow(30) { + t_max_len + 4 + } else { + >::max_encoded_len().saturating_add(T::max_encoded_len()) + } + } +} + +impl TypeInfo for WrapperOpaque { + type Identity = Self; + fn type_info() -> Type { + Type::builder() + .path(Path::new("WrapperOpaque", module_path!())) + .type_params(vec![TypeParameter::new("T", Some(meta_type::()))]) + .composite( + Fields::unnamed() + .field(|f| f.compact::().type_name("EncodedLengthOfT")) + .field(|f| f.ty::().type_name("T")), + ) + } +} + #[cfg(test)] mod test { use super::*; @@ -438,5 +469,23 @@ mod test { assert_eq!(decoded_from_vec_u8, 3u32); let decoded = >::decode(&mut &encoded[..]).unwrap(); assert_eq!(decoded.0, 3u32); + + assert_eq!(>::max_encoded_len(), 63 + 1); + assert_eq!( + >::max_encoded_len(), + WrapperOpaque([0u8; 63]).encode().len() + ); + + assert_eq!(>::max_encoded_len(), 64 + 2); + assert_eq!( + >::max_encoded_len(), + WrapperOpaque([0u8; 64]).encode().len() + ); + + assert_eq!( + >::max_encoded_len(), + 2usize.pow(14) - 1 + 2 + ); + assert_eq!(>::max_encoded_len(), 2usize.pow(14) + 4); } } From 5f750df2761eb5974ed2825170a2086494563516 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Sep 2021 10:53:15 +0200 Subject: [PATCH 0041/1472] Bump async-std from 1.9.0 to 1.10.0 (#9759) Bumps [async-std](https://github.com/async-rs/async-std) from 1.9.0 to 1.10.0. - [Release notes](https://github.com/async-rs/async-std/releases) - [Changelog](https://github.com/async-rs/async-std/blob/master/CHANGELOG.md) - [Commits](https://github.com/async-rs/async-std/compare/v1.9.0...v1.10.0) --- updated-dependencies: - dependency-name: async-std 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 | 4 ++-- bin/node/cli/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f740f4de4f59..166146005c8d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -291,9 +291,9 @@ dependencies = [ [[package]] name = "async-std" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341" +checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" dependencies = [ "async-attributes", "async-channel", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 6a12af4b278b7..67631b665b724 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -122,7 +122,7 @@ nix = "0.19" serde_json = "1.0" regex = "1" platforms = "1.1" -async-std = { version = "1.6.5", features = ["attributes"] } +async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" [build-dependencies] diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index c078e5b892fe2..b5fdcfd434300 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -26,6 +26,6 @@ sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } tracing = "0.1.25" [dev-dependencies] -async-std = "1.6.5" +async-std = "1.10.0" quickcheck = "1.0.3" substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 873c2a847a29a..cb825ce768b05 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -18,7 +18,7 @@ prost-build = "0.8" [dependencies] async-trait = "0.1" -async-std = "1.6.5" +async-std = "1.10.0" bitflags = "1.3.2" cid = "0.6.0" bytes = "1" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 88399ca54a436..b4c3a74607f65 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-std = "1.6.5" +async-std = "1.10.0" sc-network = { version = "0.10.0-dev", path = "../" } log = "0.4.8" parking_lot = "0.11.1" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 5120cc8f4dfaa..735f215c82b36 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -86,4 +86,4 @@ directories = "3.0.2" [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime/" } -async-std = { version = "1.6.5", default-features = false } +async-std = { version = "1.10.0", default-features = false } diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 4a6cec2cac774..8b647d6282fba 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -17,7 +17,7 @@ log = "0.4.8" prometheus = { version = "0.11.0", default-features = false } futures-util = { version = "0.3.17", default-features = false, features = ["io"] } derive_more = "0.99" -async-std = { version = "1.6.5", features = ["unstable"] } +async-std = { version = "1.10.0", features = ["unstable"] } tokio = "1.10" hyper = { version = "0.14.11", default-features = false, features = ["http1", "server", "tcp"] } From 63ac5215be59ee4c5b937925be98513e1664fa95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Sep 2021 09:54:10 +0000 Subject: [PATCH 0042/1472] Bump smallvec from 1.6.1 to 1.7.0 (#9894) Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.6.1 to 1.7.0. - [Release notes](https://github.com/servo/rust-smallvec/releases) - [Commits](https://github.com/servo/rust-smallvec/compare/v1.6.1...v1.7.0) --- updated-dependencies: - dependency-name: smallvec 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 | 78 ++++++++++++++-------------- client/network/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- 5 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 166146005c8d3..de94358739797 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1088,7 +1088,7 @@ dependencies = [ "gimli 0.22.0", "log 0.4.14", "regalloc", - "smallvec 1.6.1", + "smallvec 1.7.0", "target-lexicon 0.11.2", "thiserror", ] @@ -1107,7 +1107,7 @@ dependencies = [ "log 0.4.14", "regalloc", "serde", - "smallvec 1.6.1", + "smallvec 1.7.0", "target-lexicon 0.12.0", ] @@ -1172,7 +1172,7 @@ checksum = "b608bb7656c554d0a4cf8f50c7a10b857e80306f6ff829ad6d468a7e2323c8d8" dependencies = [ "cranelift-codegen 0.68.0", "log 0.4.14", - "smallvec 1.6.1", + "smallvec 1.7.0", "target-lexicon 0.11.2", ] @@ -1184,7 +1184,7 @@ checksum = "c31b783b351f966fce33e3c03498cb116d16d97a8f9978164a60920bd0d3a99c" dependencies = [ "cranelift-codegen 0.74.0", "log 0.4.14", - "smallvec 1.6.1", + "smallvec 1.7.0", "target-lexicon 0.12.0", ] @@ -1210,7 +1210,7 @@ dependencies = [ "itertools 0.10.0", "log 0.4.14", "serde", - "smallvec 1.6.1", + "smallvec 1.7.0", "thiserror", "wasmparser 0.78.2", ] @@ -2059,7 +2059,7 @@ dependencies = [ "pretty_assertions 0.6.1", "scale-info", "serde", - "smallvec 1.6.1", + "smallvec 1.7.0", "sp-arithmetic", "sp-core", "sp-inherents", @@ -3243,7 +3243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45a3f58dc069ec0e205a27f5b45920722a46faed802a0541538241af6228f512" dependencies = [ "parity-util-mem", - "smallvec 1.6.1", + "smallvec 1.7.0", ] [[package]] @@ -3272,7 +3272,7 @@ dependencies = [ "parking_lot 0.11.1", "regex", "rocksdb", - "smallvec 1.6.1", + "smallvec 1.7.0", ] [[package]] @@ -3388,7 +3388,7 @@ dependencies = [ "multiaddr", "parking_lot 0.11.1", "pin-project 1.0.5", - "smallvec 1.6.1", + "smallvec 1.7.0", "wasm-timer", ] @@ -3419,7 +3419,7 @@ dependencies = [ "ring", "rw-stream-sink", "sha2 0.9.3", - "smallvec 1.6.1", + "smallvec 1.7.0", "thiserror", "unsigned-varint 0.7.0", "void", @@ -3447,7 +3447,7 @@ dependencies = [ "futures 0.3.16", "libp2p-core", "log 0.4.14", - "smallvec 1.6.1", + "smallvec 1.7.0", "trust-dns-resolver", ] @@ -3466,7 +3466,7 @@ dependencies = [ "prost", "prost-build", "rand 0.7.3", - "smallvec 1.6.1", + "smallvec 1.7.0", ] [[package]] @@ -3490,7 +3490,7 @@ dependencies = [ "rand 0.7.3", "regex", "sha2 0.9.3", - "smallvec 1.6.1", + "smallvec 1.7.0", "unsigned-varint 0.7.0", "wasm-timer", ] @@ -3507,7 +3507,7 @@ dependencies = [ "log 0.4.14", "prost", "prost-build", - "smallvec 1.6.1", + "smallvec 1.7.0", "wasm-timer", ] @@ -3530,7 +3530,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "sha2 0.9.3", - "smallvec 1.6.1", + "smallvec 1.7.0", "uint", "unsigned-varint 0.7.0", "void", @@ -3553,7 +3553,7 @@ dependencies = [ "libp2p-swarm", "log 0.4.14", "rand 0.8.4", - "smallvec 1.6.1", + "smallvec 1.7.0", "socket2 0.4.0", "void", ] @@ -3572,7 +3572,7 @@ dependencies = [ "nohash-hasher", "parking_lot 0.11.1", "rand 0.7.3", - "smallvec 1.6.1", + "smallvec 1.7.0", "unsigned-varint 0.7.0", ] @@ -3661,7 +3661,7 @@ dependencies = [ "prost", "prost-build", "rand 0.7.3", - "smallvec 1.6.1", + "smallvec 1.7.0", "unsigned-varint 0.7.0", "void", "wasm-timer", @@ -3682,7 +3682,7 @@ dependencies = [ "lru", "minicbor", "rand 0.7.3", - "smallvec 1.6.1", + "smallvec 1.7.0", "unsigned-varint 0.7.0", "wasm-timer", ] @@ -3698,7 +3698,7 @@ dependencies = [ "libp2p-core", "log 0.4.14", "rand 0.7.3", - "smallvec 1.6.1", + "smallvec 1.7.0", "void", "wasm-timer", ] @@ -4372,7 +4372,7 @@ dependencies = [ "futures 0.3.16", "log 0.4.14", "pin-project 1.0.5", - "smallvec 1.6.1", + "smallvec 1.7.0", "unsigned-varint 0.7.0", ] @@ -5337,7 +5337,7 @@ dependencies = [ "rand_pcg 0.2.1", "scale-info", "serde", - "smallvec 1.6.1", + "smallvec 1.7.0", "sp-core", "sp-io", "sp-runtime", @@ -6068,7 +6068,7 @@ dependencies = [ "scale-info", "serde", "serde_json", - "smallvec 1.6.1", + "smallvec 1.7.0", "sp-core", "sp-io", "sp-runtime", @@ -6265,7 +6265,7 @@ dependencies = [ "parity-util-mem-derive", "parking_lot 0.11.1", "primitive-types", - "smallvec 1.6.1", + "smallvec 1.7.0", "winapi 0.3.9", ] @@ -6376,7 +6376,7 @@ dependencies = [ "cloudabi", "libc", "redox_syscall 0.1.57", - "smallvec 1.6.1", + "smallvec 1.7.0", "winapi 0.3.9", ] @@ -6390,7 +6390,7 @@ dependencies = [ "instant", "libc", "redox_syscall 0.2.5", - "smallvec 1.6.1", + "smallvec 1.7.0", "winapi 0.3.9", ] @@ -7243,7 +7243,7 @@ dependencies = [ "log 0.4.14", "rustc-hash", "serde", - "smallvec 1.6.1", + "smallvec 1.7.0", ] [[package]] @@ -8181,7 +8181,7 @@ dependencies = [ "sc-utils", "serde", "serde_json", - "smallvec 1.6.1", + "smallvec 1.7.0", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -8987,9 +8987,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "snap" @@ -9697,7 +9697,7 @@ dependencies = [ "parking_lot 0.11.1", "pretty_assertions 0.6.1", "rand 0.7.3", - "smallvec 1.6.1", + "smallvec 1.7.0", "sp-core", "sp-externalities", "sp-panic-handler", @@ -10732,7 +10732,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec 1.6.1", + "smallvec 1.7.0", "thread_local", "tracing", "tracing-core", @@ -10778,7 +10778,7 @@ dependencies = [ "hashbrown 0.11.2", "log 0.4.14", "rustc-hex", - "smallvec 1.6.1", + "smallvec 1.7.0", ] [[package]] @@ -10818,7 +10818,7 @@ dependencies = [ "lazy_static", "log 0.4.14", "rand 0.8.4", - "smallvec 1.6.1", + "smallvec 1.7.0", "thiserror", "tinyvec", "url 2.2.1", @@ -10838,7 +10838,7 @@ dependencies = [ "lru-cache", "parking_lot 0.11.1", "resolv-conf", - "smallvec 1.6.1", + "smallvec 1.7.0", "thiserror", "trust-dns-proto", ] @@ -11268,7 +11268,7 @@ dependencies = [ "enumset", "serde", "serde_bytes", - "smallvec 1.6.1", + "smallvec 1.7.0", "target-lexicon 0.11.2", "thiserror", "wasmer-types", @@ -11288,7 +11288,7 @@ dependencies = [ "more-asserts", "rayon", "serde", - "smallvec 1.6.1", + "smallvec 1.7.0", "tracing", "wasmer-compiler", "wasmer-types", @@ -11308,7 +11308,7 @@ dependencies = [ "more-asserts", "rayon", "serde", - "smallvec 1.6.1", + "smallvec 1.7.0", "wasmer-compiler", "wasmer-types", "wasmer-vm", @@ -11487,7 +11487,7 @@ dependencies = [ "region", "rustc-demangle", "serde", - "smallvec 1.6.1", + "smallvec 1.7.0", "target-lexicon 0.12.0", "wasmparser 0.78.2", "wasmtime-cache", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index cb825ce768b05..68b9595ae1908 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -48,7 +48,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } serde = { version = "1.0.126", features = ["derive"] } serde_json = "1.0.68" -smallvec = "1.5.0" +smallvec = "1.7.0" sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index b09ed65a114dc..f4af38db54e2d 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -31,7 +31,7 @@ once_cell = { version = "1", default-features = false, optional = true } sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../../primitives/state-machine" } bitflags = "1.3" impl-trait-for-tuples = "0.2.1" -smallvec = "1.4.1" +smallvec = "1.7.0" log = { version = "0.4.14", default-features = false } [dev-dependencies] diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 546939692bbaf..1dfeb0c2baa4b 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.126", optional = true } -smallvec = "1.4.1" +smallvec = "1.7.0" sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 457bbac5d2640..a63d1312044df 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -27,7 +27,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = num-traits = { version = "0.2.8", default-features = false } rand = { version = "0.7.2", optional = true } sp-externalities = { version = "0.10.0-dev", path = "../externalities", default-features = false } -smallvec = "1.4.1" +smallvec = "1.7.0" sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } tracing = { version = "0.1.22", optional = true } From c73e3c2a0621812d3f753ead6510e2fda2f986fa Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Wed, 29 Sep 2021 12:44:04 +0200 Subject: [PATCH 0043/1472] remove unidiomatic (#9895) --- frame/support/src/traits/misc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index a040f8575abd2..db6e0321005a5 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -450,7 +450,7 @@ impl TypeInfo for WrapperOpaque { .type_params(vec![TypeParameter::new("T", Some(meta_type::()))]) .composite( Fields::unnamed() - .field(|f| f.compact::().type_name("EncodedLengthOfT")) + .field(|f| f.compact::()) .field(|f| f.ty::().type_name("T")), ) } From 0a785f1221f5d143ae4487147183d66bad0f9837 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 29 Sep 2021 11:55:31 +0100 Subject: [PATCH 0044/1472] Less sleeps (#9848) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Less sleeps * No need to use tokio-test crate * Less sleep * Avoid leaving zombie substrates around (when panicing in tests) * Remove unused imports * Incorporating feedback * rename method * Use rpc_api * Update bin/node/cli/tests/temp_base_path_works.rs Co-authored-by: Bastian Köcher * Update bin/node/cli/tests/temp_base_path_works.rs Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- Cargo.lock | 8 +- bin/node-template/node/src/cli.rs | 2 +- bin/node/cli/Cargo.toml | 6 +- bin/node/cli/src/chain_spec.rs | 2 +- bin/node/cli/src/service.rs | 6 +- bin/node/cli/tests/check_block_works.rs | 6 +- bin/node/cli/tests/common.rs | 109 +++++++++++++----- .../tests/database_role_subdir_migration.rs | 7 +- bin/node/cli/tests/export_import_flow.rs | 6 +- bin/node/cli/tests/inspect_works.rs | 6 +- bin/node/cli/tests/purge_chain_works.rs | 6 +- .../tests/running_the_node_and_interrupt.rs | 67 ++++------- bin/node/cli/tests/temp_base_path_works.rs | 33 +++--- client/executor/src/native_executor.rs | 4 +- 14 files changed, 153 insertions(+), 115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index de94358739797..2213ae7c19988 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4512,6 +4512,7 @@ dependencies = [ "frame-system", "futures 0.3.16", "hex-literal", + "jsonrpsee-ws-client", "log 0.4.14", "nix", "node-executor", @@ -4525,6 +4526,7 @@ dependencies = [ "platforms", "rand 0.7.3", "regex", + "remote-externalities", "sc-authority-discovery", "sc-basic-authorship", "sc-chain-spec", @@ -4569,7 +4571,9 @@ dependencies = [ "substrate-build-script-utils", "substrate-frame-cli", "tempfile", + "tokio", "try-runtime-cli", + "wait-timeout", ] [[package]] @@ -10478,9 +10482,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cf844b23c6131f624accf65ce0e4e9956a8bb329400ea5bcc26ae3a5c20b0b" +checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" dependencies = [ "autocfg 1.0.1", "bytes 1.0.1", diff --git a/bin/node-template/node/src/cli.rs b/bin/node-template/node/src/cli.rs index 8b551051c1b19..8ed1d35ba5f92 100644 --- a/bin/node-template/node/src/cli.rs +++ b/bin/node-template/node/src/cli.rs @@ -35,7 +35,7 @@ pub enum Subcommand { /// Revert the chain to a previous state. Revert(sc_cli::RevertCmd), - /// The custom benchmark subcommmand benchmarking runtime pallets. + /// The custom benchmark subcommand benchmarking runtime pallets. #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] Benchmark(frame_benchmarking_cli::BenchmarkCmd), } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 67631b665b724..1fc7a38b23ca8 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -124,6 +124,10 @@ regex = "1" platforms = "1.1" async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" +jsonrpsee-ws-client = { version = "0.3.0", default-features = false, features = ["tokio1"] } +tokio = { version = "1.10", features = ["macros", "time"] } +wait-timeout = "0.2" +remote-externalities = { path = "../../../utils/frame/remote-externalities" } [build-dependencies] structopt = { version = "0.3.8", optional = true } @@ -135,7 +139,7 @@ try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../ut sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", optional = true } [features] -default = [ "cli" ] +default = ["cli"] cli = [ "node-executor/wasmi-errno", "node-inspect", diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 352e007a891ba..5e727afa304bb 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -265,7 +265,7 @@ pub fn testnet_genesis( .map(|x| &x.0) .chain(initial_nominators.iter()) .for_each(|x| { - if !endowed_accounts.contains(&x) { + if !endowed_accounts.contains(x) { endowed_accounts.push(x.clone()) } }); diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index acc7df5b1e5a3..b1a3bd4722597 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -86,7 +86,7 @@ pub fn new_partial( let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( - &config, + config, telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), executor, )?; @@ -277,7 +277,7 @@ pub fn new_full_base( let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { config, - backend: backend.clone(), + backend, client: client.clone(), keystore: keystore_container.sync_keystore(), network: network.clone(), @@ -507,7 +507,7 @@ pub fn new_light_base( babe_block_import, Some(Box::new(justification_import)), client.clone(), - select_chain.clone(), + select_chain, move |_, ()| async move { let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); diff --git a/bin/node/cli/tests/check_block_works.rs b/bin/node/cli/tests/check_block_works.rs index 707fd217e33e8..216bcc6d9fc13 100644 --- a/bin/node/cli/tests/check_block_works.rs +++ b/bin/node/cli/tests/check_block_works.rs @@ -24,11 +24,11 @@ use tempfile::tempdir; pub mod common; -#[test] -fn check_block_works() { +#[tokio::test] +async fn check_block_works() { let base_path = tempdir().expect("could not create a temp dir"); - common::run_node_for_a_while(base_path.path(), &["--dev"]); + common::run_node_for_a_while(base_path.path(), &["--dev"]).await; let status = Command::new(cargo_bin("substrate")) .args(&["check-block", "--dev", "--pruning", "archive", "-d"]) diff --git a/bin/node/cli/tests/common.rs b/bin/node/cli/tests/common.rs index 54b9c749bf1de..85effc858e155 100644 --- a/bin/node/cli/tests/common.rs +++ b/bin/node/cli/tests/common.rs @@ -23,58 +23,115 @@ use nix::{ sys::signal::{kill, Signal::SIGINT}, unistd::Pid, }; +use node_primitives::Block; +use remote_externalities::rpc_api; use std::{ convert::TryInto, + ops::{Deref, DerefMut}, path::Path, process::{Child, Command, ExitStatus}, - thread, time::Duration, }; +use tokio::time::timeout; + +static LOCALHOST_WS: &str = "ws://127.0.0.1:9944/"; /// Wait for the given `child` the given number of `secs`. /// /// Returns the `Some(exit status)` or `None` if the process did not finish in the given time. -pub fn wait_for(child: &mut Child, secs: usize) -> Option { - for i in 0..secs { - match child.try_wait().unwrap() { - Some(status) => { - if i > 5 { - eprintln!("Child process took {} seconds to exit gracefully", i); - } - return Some(status) - }, - None => thread::sleep(Duration::from_secs(1)), +pub fn wait_for(child: &mut Child, secs: u64) -> Result { + let result = wait_timeout::ChildExt::wait_timeout(child, Duration::from_secs(5.min(secs))) + .map_err(|_| ())?; + if let Some(exit_status) = result { + Ok(exit_status) + } else { + if secs > 5 { + eprintln!("Child process taking over 5 seconds to exit gracefully"); + let result = wait_timeout::ChildExt::wait_timeout(child, Duration::from_secs(secs - 5)) + .map_err(|_| ())?; + if let Some(exit_status) = result { + return Ok(exit_status) + } } + eprintln!("Took too long to exit (> {} seconds). Killing...", secs); + let _ = child.kill(); + child.wait().unwrap(); + Err(()) } - eprintln!("Took too long to exit (> {} seconds). Killing...", secs); - let _ = child.kill(); - child.wait().unwrap(); +} + +/// Wait for at least n blocks to be finalized within a specified time. +pub async fn wait_n_finalized_blocks( + n: usize, + timeout_secs: u64, +) -> Result<(), tokio::time::error::Elapsed> { + timeout(Duration::from_secs(timeout_secs), wait_n_finalized_blocks_from(n, LOCALHOST_WS)).await +} + +/// Wait for at least n blocks to be finalized from a specified node +pub async fn wait_n_finalized_blocks_from(n: usize, url: &str) { + let mut built_blocks = std::collections::HashSet::new(); + let mut interval = tokio::time::interval(Duration::from_secs(2)); - None + loop { + if let Ok(block) = rpc_api::get_finalized_head::(url.to_string()).await { + built_blocks.insert(block); + if built_blocks.len() > n { + break + } + }; + interval.tick().await; + } } -/// Run the node for a while (30 seconds) -pub fn run_node_for_a_while(base_path: &Path, args: &[&str]) { +/// Run the node for a while (3 blocks) +pub async fn run_node_for_a_while(base_path: &Path, args: &[&str]) { let mut cmd = Command::new(cargo_bin("substrate")); - let mut cmd = cmd.args(args).arg("-d").arg(base_path).spawn().unwrap(); + let mut child = KillChildOnDrop(cmd.args(args).arg("-d").arg(base_path).spawn().unwrap()); // Let it produce some blocks. - thread::sleep(Duration::from_secs(30)); - assert!(cmd.try_wait().unwrap().is_none(), "the process should still be running"); + let _ = wait_n_finalized_blocks(3, 30).await; + + assert!(child.try_wait().unwrap().is_none(), "the process should still be running"); // Stop the process - kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap(); - assert!(wait_for(&mut cmd, 40).map(|x| x.success()).unwrap_or_default()); + kill(Pid::from_raw(child.id().try_into().unwrap()), SIGINT).unwrap(); + assert!(wait_for(&mut child, 40).map(|x| x.success()).unwrap()); } /// Run the node asserting that it fails with an error pub fn run_node_assert_fail(base_path: &Path, args: &[&str]) { let mut cmd = Command::new(cargo_bin("substrate")); - let mut cmd = cmd.args(args).arg("-d").arg(base_path).spawn().unwrap(); + let mut child = KillChildOnDrop(cmd.args(args).arg("-d").arg(base_path).spawn().unwrap()); - // Let it produce some blocks. - thread::sleep(Duration::from_secs(10)); - assert!(cmd.try_wait().unwrap().is_some(), "the process should not be running anymore"); + // Let it produce some blocks, but it should die within 10 seconds. + assert_ne!( + wait_timeout::ChildExt::wait_timeout(&mut *child, Duration::from_secs(10)).unwrap(), + None, + "the process should not be running anymore" + ); +} + +pub struct KillChildOnDrop(pub Child); + +impl Drop for KillChildOnDrop { + fn drop(&mut self) { + let _ = self.0.kill(); + } +} + +impl Deref for KillChildOnDrop { + type Target = Child; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for KillChildOnDrop { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } } diff --git a/bin/node/cli/tests/database_role_subdir_migration.rs b/bin/node/cli/tests/database_role_subdir_migration.rs index 516908111ae72..9338d8a8e4f43 100644 --- a/bin/node/cli/tests/database_role_subdir_migration.rs +++ b/bin/node/cli/tests/database_role_subdir_migration.rs @@ -25,9 +25,9 @@ use tempfile::tempdir; pub mod common; -#[test] +#[tokio::test] #[cfg(unix)] -fn database_role_subdir_migration() { +async fn database_role_subdir_migration() { type Block = RawBlock>; let base_path = tempdir().expect("could not create a temp dir"); @@ -62,7 +62,8 @@ fn database_role_subdir_migration() { "44445", "--no-prometheus", ], - ); + ) + .await; // check if the database dir had been migrated assert!(!path.join("db_version").exists()); diff --git a/bin/node/cli/tests/export_import_flow.rs b/bin/node/cli/tests/export_import_flow.rs index 7cbaa152699b4..937f03b8e5dae 100644 --- a/bin/node/cli/tests/export_import_flow.rs +++ b/bin/node/cli/tests/export_import_flow.rs @@ -182,13 +182,13 @@ impl<'a> ExportImportRevertExecutor<'a> { } } -#[test] -fn export_import_revert() { +#[tokio::test] +async fn export_import_revert() { let base_path = tempdir().expect("could not create a temp dir"); let exported_blocks_file = base_path.path().join("exported_blocks"); let db_path = base_path.path().join("db"); - common::run_node_for_a_while(base_path.path(), &["--dev"]); + common::run_node_for_a_while(base_path.path(), &["--dev"]).await; let mut executor = ExportImportRevertExecutor::new(&base_path, &exported_blocks_file, &db_path); diff --git a/bin/node/cli/tests/inspect_works.rs b/bin/node/cli/tests/inspect_works.rs index 2a89801547a4b..6f980d2acbfcb 100644 --- a/bin/node/cli/tests/inspect_works.rs +++ b/bin/node/cli/tests/inspect_works.rs @@ -24,11 +24,11 @@ use tempfile::tempdir; pub mod common; -#[test] -fn inspect_works() { +#[tokio::test] +async fn inspect_works() { let base_path = tempdir().expect("could not create a temp dir"); - common::run_node_for_a_while(base_path.path(), &["--dev"]); + common::run_node_for_a_while(base_path.path(), &["--dev"]).await; let status = Command::new(cargo_bin("substrate")) .args(&["inspect", "--dev", "--pruning", "archive", "-d"]) diff --git a/bin/node/cli/tests/purge_chain_works.rs b/bin/node/cli/tests/purge_chain_works.rs index 0f16a51e5d0a4..8a8601c863d95 100644 --- a/bin/node/cli/tests/purge_chain_works.rs +++ b/bin/node/cli/tests/purge_chain_works.rs @@ -22,12 +22,12 @@ use tempfile::tempdir; pub mod common; -#[test] +#[tokio::test] #[cfg(unix)] -fn purge_chain_works() { +async fn purge_chain_works() { let base_path = tempdir().expect("could not create a temp dir"); - common::run_node_for_a_while(base_path.path(), &["--dev"]); + common::run_node_for_a_while(base_path.path(), &["--dev"]).await; let status = Command::new(cargo_bin("substrate")) .args(&["purge-chain", "--dev", "-d"]) diff --git a/bin/node/cli/tests/running_the_node_and_interrupt.rs b/bin/node/cli/tests/running_the_node_and_interrupt.rs index 03a1826f2f080..fc5094c2d722f 100644 --- a/bin/node/cli/tests/running_the_node_and_interrupt.rs +++ b/bin/node/cli/tests/running_the_node_and_interrupt.rs @@ -17,7 +17,6 @@ // along with this program. If not, see . #![cfg(unix)] - use assert_cmd::cargo::cargo_bin; use nix::{ sys::signal::{ @@ -26,67 +25,43 @@ use nix::{ }, unistd::Pid, }; -use sc_service::Deref; use std::{ convert::TryInto, - ops::DerefMut, process::{Child, Command}, - thread, - time::Duration, }; use tempfile::tempdir; pub mod common; -#[test] -fn running_the_node_works_and_can_be_interrupted() { - fn run_command_and_kill(signal: Signal) { +#[tokio::test] +async fn running_the_node_works_and_can_be_interrupted() { + async fn run_command_and_kill(signal: Signal) { let base_path = tempdir().expect("could not create a temp dir"); - let mut cmd = Command::new(cargo_bin("substrate")) - .args(&["--dev", "-d"]) - .arg(base_path.path()) - .spawn() - .unwrap(); + let mut cmd = common::KillChildOnDrop( + Command::new(cargo_bin("substrate")) + .args(&["--dev", "-d"]) + .arg(base_path.path()) + .spawn() + .unwrap(), + ); - thread::sleep(Duration::from_secs(20)); + common::wait_n_finalized_blocks(3, 30).await.unwrap(); assert!(cmd.try_wait().unwrap().is_none(), "the process should still be running"); kill(Pid::from_raw(cmd.id().try_into().unwrap()), signal).unwrap(); assert_eq!( common::wait_for(&mut cmd, 30).map(|x| x.success()), - Some(true), + Ok(true), "the process must exit gracefully after signal {}", signal, ); } - run_command_and_kill(SIGINT); - run_command_and_kill(SIGTERM); -} - -struct KillChildOnDrop(Child); - -impl Drop for KillChildOnDrop { - fn drop(&mut self) { - let _ = self.0.kill(); - } -} - -impl Deref for KillChildOnDrop { - type Target = Child; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for KillChildOnDrop { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } + run_command_and_kill(SIGINT).await; + run_command_and_kill(SIGTERM).await; } -#[test] -fn running_two_nodes_with_the_same_ws_port_should_work() { +#[tokio::test] +async fn running_two_nodes_with_the_same_ws_port_should_work() { fn start_node() -> Child { Command::new(cargo_bin("substrate")) .args(&["--dev", "--tmp", "--ws-port=45789"]) @@ -94,10 +69,10 @@ fn running_two_nodes_with_the_same_ws_port_should_work() { .unwrap() } - let mut first_node = KillChildOnDrop(start_node()); - let mut second_node = KillChildOnDrop(start_node()); + let mut first_node = common::KillChildOnDrop(start_node()); + let mut second_node = common::KillChildOnDrop(start_node()); - thread::sleep(Duration::from_secs(30)); + let _ = common::wait_n_finalized_blocks(3, 30).await; assert!(first_node.try_wait().unwrap().is_none(), "The first node should still be running"); assert!(second_node.try_wait().unwrap().is_none(), "The second node should still be running"); @@ -107,12 +82,12 @@ fn running_two_nodes_with_the_same_ws_port_should_work() { assert_eq!( common::wait_for(&mut first_node, 30).map(|x| x.success()), - Some(true), + Ok(true), "The first node must exit gracefully", ); assert_eq!( common::wait_for(&mut second_node, 30).map(|x| x.success()), - Some(true), + Ok(true), "The second node must exit gracefully", ); } diff --git a/bin/node/cli/tests/temp_base_path_works.rs b/bin/node/cli/tests/temp_base_path_works.rs index c107740b9b0a5..5d8e6c9ec4539 100644 --- a/bin/node/cli/tests/temp_base_path_works.rs +++ b/bin/node/cli/tests/temp_base_path_works.rs @@ -29,37 +29,34 @@ use std::{ io::Read, path::PathBuf, process::{Command, Stdio}, - thread, - time::Duration, }; pub mod common; -#[test] -fn temp_base_path_works() { +#[tokio::test] +async fn temp_base_path_works() { let mut cmd = Command::new(cargo_bin("substrate")); - - let mut cmd = cmd - .args(&["--dev", "--tmp"]) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .unwrap(); + let mut child = common::KillChildOnDrop( + cmd.args(&["--dev", "--tmp"]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .unwrap(), + ); // Let it produce some blocks. - thread::sleep(Duration::from_secs(30)); - assert!(cmd.try_wait().unwrap().is_none(), "the process should still be running"); + common::wait_n_finalized_blocks(3, 30).await.unwrap(); + assert!(child.try_wait().unwrap().is_none(), "the process should still be running"); // Stop the process - kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap(); - assert!(common::wait_for(&mut cmd, 40).map(|x| x.success()).unwrap_or_default()); + kill(Pid::from_raw(child.id().try_into().unwrap()), SIGINT).unwrap(); + assert!(common::wait_for(&mut child, 40).map(|x| x.success()).unwrap_or_default()); // Ensure the database has been deleted let mut stderr = String::new(); - cmd.stderr.unwrap().read_to_string(&mut stderr).unwrap(); + child.stderr.as_mut().unwrap().read_to_string(&mut stderr).unwrap(); let re = Regex::new(r"Database: .+ at (\S+)").unwrap(); - let db_path = - PathBuf::from(re.captures(stderr.as_str()).unwrap().get(1).unwrap().as_str().to_string()); + let db_path = PathBuf::from(re.captures(stderr.as_str()).unwrap().get(1).unwrap().as_str()); assert!(!db_path.exists()); } diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 77b1ec7abf4f2..979bcc072c88b 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -189,7 +189,7 @@ impl WasmExecutor { /// Perform a call into the given runtime. /// - /// The runtime is passed as a [`RuntimeBlob`]. The runtime will be isntantiated with the + /// The runtime is passed as a [`RuntimeBlob`]. The runtime will be instantiated with the /// parameters this `WasmExecutor` was initialized with. /// /// In case of problems with during creation of the runtime or instantation, a `Err` is @@ -247,7 +247,7 @@ impl sp_core::traits::ReadRuntimeVersion for WasmExecutor { } // If the blob didn't have embedded runtime version section, we fallback to the legacy - // way of fetching the verison: i.e. instantiating the given instance and calling + // way of fetching the version: i.e. instantiating the given instance and calling // `Core_version` on it. self.uncached_call( From 83ced6b2acb82cddf8ae7cef5bad90482712651f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 29 Sep 2021 14:30:46 +0200 Subject: [PATCH 0045/1472] Update wasmtime to 0.29.0 (#9552) * Start * Move to ctx * Make it compile for now * More work * Get rid off state-holder * Use less Refcells * :facepalm: * Don't use RefCell * Use names for parameters * Fixes after merge * Fixes after merge * Review feedback * FMT --- Cargo.lock | 207 +++++++------- .../src/runtime_blob/globals_snapshot.rs | 13 +- client/executor/common/src/util.rs | 2 +- client/executor/common/src/wasm_runtime.rs | 6 +- .../executor/src/integration_tests/linux.rs | 2 +- client/executor/src/integration_tests/mod.rs | 8 +- client/executor/src/native_executor.rs | 10 +- client/executor/src/wasm_runtime.rs | 12 +- client/executor/wasmi/src/lib.rs | 4 +- client/executor/wasmtime/Cargo.toml | 6 +- client/executor/wasmtime/src/host.rs | 83 ++++-- client/executor/wasmtime/src/imports.rs | 51 ++-- .../executor/wasmtime/src/instance_wrapper.rs | 256 ++++++++---------- client/executor/wasmtime/src/lib.rs | 1 - client/executor/wasmtime/src/runtime.rs | 169 +++++++++--- client/executor/wasmtime/src/state_holder.rs | 45 --- client/executor/wasmtime/src/tests.rs | 6 +- primitives/maybe-compressed-blob/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- 19 files changed, 453 insertions(+), 432 deletions(-) delete mode 100644 client/executor/wasmtime/src/state_holder.rs diff --git a/Cargo.lock b/Cargo.lock index 2213ae7c19988..cdde834261870 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,20 +14,11 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" -dependencies = [ - "gimli 0.23.0", -] - -[[package]] -name = "addr2line" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03345e98af8f3d786b6d9f656ccfa6ac316d954e92bc4841f0bba20789d5fb5a" +checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" dependencies = [ - "gimli 0.24.0", + "gimli 0.25.0", ] [[package]] @@ -415,15 +406,16 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.56" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc" +checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01" dependencies = [ - "addr2line 0.14.1", + "addr2line", + "cc", "cfg-if 1.0.0", "libc", "miniz_oxide", - "object 0.23.0", + "object 0.26.0", "rustc-demangle", ] @@ -1067,11 +1059,11 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.74.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ca3560686e7c9c7ed7e0fe77469f2410ba5d7781b1acaa9adc8d8deea28e3e" +checksum = "7e6bea67967505247f54fa2c85cf4f6e0e31c4e5692c9b70e4ae58e339067333" dependencies = [ - "cranelift-entity 0.74.0", + "cranelift-entity 0.76.0", ] [[package]] @@ -1095,15 +1087,15 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.74.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf9bf1ffffb6ce3d2e5ebc83549bd2436426c99b31cc550d521364cbe35d276" +checksum = "48194035d2752bdd5bdae429e3ab88676e95f52a2b1355a5d4e809f9e39b1d74" dependencies = [ - "cranelift-bforest 0.74.0", - "cranelift-codegen-meta 0.74.0", - "cranelift-codegen-shared 0.74.0", - "cranelift-entity 0.74.0", - "gimli 0.24.0", + "cranelift-bforest 0.76.0", + "cranelift-codegen-meta 0.76.0", + "cranelift-codegen-shared 0.76.0", + "cranelift-entity 0.76.0", + "gimli 0.25.0", "log 0.4.14", "regalloc", "serde", @@ -1123,12 +1115,12 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.74.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cc21936a5a6d07e23849ffe83e5c1f6f50305c074f4b2970ca50c13bf55b821" +checksum = "976efb22fcab4f2cd6bd4e9913764616a54d895c1a23530128d04e03633c555f" dependencies = [ - "cranelift-codegen-shared 0.74.0", - "cranelift-entity 0.74.0", + "cranelift-codegen-shared 0.76.0", + "cranelift-entity 0.76.0", ] [[package]] @@ -1139,9 +1131,9 @@ checksum = "6759012d6d19c4caec95793f052613e9d4113e925e7f14154defbac0f1d4c938" [[package]] name = "cranelift-codegen-shared" -version = "0.74.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5b6ffaa87560bebe69a5446449da18090b126037920b0c1c6d5945f72faf6b" +checksum = "9dabb5fe66e04d4652e434195b45ae65b5c8172d520247b8f66d8df42b2b45dc" dependencies = [ "serde", ] @@ -1157,9 +1149,9 @@ dependencies = [ [[package]] name = "cranelift-entity" -version = "0.74.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d6b4a8bef04f82e4296782646f733c641d09497df2fabf791323fefaa44c64c" +checksum = "3329733e4d4b8e91c809efcaa4faee80bf66f20164e3dd16d707346bd3494799" dependencies = [ "serde", ] @@ -1178,11 +1170,11 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.74.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b783b351f966fce33e3c03498cb116d16d97a8f9978164a60920bd0d3a99c" +checksum = "279afcc0d3e651b773f94837c3d581177b348c8d69e928104b2e9fccb226f921" dependencies = [ - "cranelift-codegen 0.74.0", + "cranelift-codegen 0.76.0", "log 0.4.14", "smallvec 1.7.0", "target-lexicon 0.12.0", @@ -1190,29 +1182,30 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.74.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c88d3dd48021ff1e37e978a00098524abd3513444ae252c08d37b310b3d2a" +checksum = "4c04d1fe6a5abb5bb0edc78baa8ef238370fb8e389cc88b6d153f7c3e9680425" dependencies = [ - "cranelift-codegen 0.74.0", + "cranelift-codegen 0.76.0", + "libc", "target-lexicon 0.12.0", ] [[package]] name = "cranelift-wasm" -version = "0.74.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb6d408e2da77cdbbd65466298d44c86ae71c1785d2ab0d8657753cdb4d9d89" +checksum = "e0d260ad44f6fd2c91f7f5097191a2a9e3edcbb36df1fb787b600dad5ea148ec" dependencies = [ - "cranelift-codegen 0.74.0", - "cranelift-entity 0.74.0", - "cranelift-frontend 0.74.0", + "cranelift-codegen 0.76.0", + "cranelift-entity 0.76.0", + "cranelift-frontend 0.76.0", "itertools 0.10.0", "log 0.4.14", "serde", "smallvec 1.7.0", "thiserror", - "wasmparser 0.78.2", + "wasmparser 0.79.0", ] [[package]] @@ -2469,15 +2462,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" - -[[package]] -name = "gimli" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" +checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" dependencies = [ "fallible-iterator", "indexmap", @@ -4111,9 +4098,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" [[package]] name = "memmap" @@ -4886,9 +4873,9 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "6.2.1" +version = "6.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" +checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" dependencies = [ "bitvec 0.19.5", "funty", @@ -5000,18 +4987,13 @@ dependencies = [ [[package]] name = "object" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" - -[[package]] -name = "object" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" +checksum = "c55827317fb4c08822499848a14237d2874d6f139828893017237e7ab93eb386" dependencies = [ "crc32fast", "indexmap", + "memchr", ] [[package]] @@ -8020,7 +8002,6 @@ dependencies = [ "sc-allocator", "sc-executor-common", "sc-runtime-test", - "scoped-tls", "sp-core", "sp-io", "sp-runtime-interface", @@ -11467,15 +11448,15 @@ checksum = "87cc2fe6350834b4e528ba0901e7aa405d78b89dc1fa3145359eb4de0e323fcf" [[package]] name = "wasmparser" -version = "0.78.2" +version = "0.79.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" +checksum = "5b5894be15a559c85779254700e1d35f02f843b5a69152e5c82c626d9fd66c0e" [[package]] name = "wasmtime" -version = "0.27.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b310b9d20fcf59385761d1ade7a3ef06aecc380e3d3172035b919eaf7465d9f7" +checksum = "8bbb8a082a8ef50f7eeb8b82dda9709ef1e68963ea3c94e45581644dd4041835" dependencies = [ "anyhow", "backtrace", @@ -11493,7 +11474,7 @@ dependencies = [ "serde", "smallvec 1.7.0", "target-lexicon 0.12.0", - "wasmparser 0.78.2", + "wasmparser 0.79.0", "wasmtime-cache", "wasmtime-environ", "wasmtime-jit", @@ -11504,9 +11485,9 @@ dependencies = [ [[package]] name = "wasmtime-cache" -version = "0.27.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d14d500d5c3dc5f5c097158feee123d64b3097f0d836a2a27dff9c761c73c843" +checksum = "d73391579ca7f24573138ef768b73b2aed5f9d542385c64979b65d60d0912399" dependencies = [ "anyhow", "base64 0.13.0", @@ -11525,78 +11506,78 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "0.27.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c525b39f062eada7db3c1298287b96dcb6e472b9f6b22501300b28d9fa7582f6" +checksum = "81c6f5ae9205382345c7cd7454932a906186836999a2161c385e38a15f52e1fe" dependencies = [ - "cranelift-codegen 0.74.0", - "cranelift-entity 0.74.0", - "cranelift-frontend 0.74.0", + "cranelift-codegen 0.76.0", + "cranelift-entity 0.76.0", + "cranelift-frontend 0.76.0", "cranelift-wasm", "target-lexicon 0.12.0", - "wasmparser 0.78.2", + "wasmparser 0.79.0", "wasmtime-environ", ] [[package]] name = "wasmtime-debug" -version = "0.27.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d2a763e7a6fc734218e0e463196762a4f409c483063d81e0e85f96343b2e0a" +checksum = "c69e08f55e12f15f50b1b533bc3626723e7224254a065de6576934c86258c9e8" dependencies = [ "anyhow", - "gimli 0.24.0", + "gimli 0.25.0", "more-asserts", - "object 0.24.0", + "object 0.26.0", "target-lexicon 0.12.0", "thiserror", - "wasmparser 0.78.2", + "wasmparser 0.79.0", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.27.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64d0c2d881c31b0d65c1f2695e022d71eb60b9fbdd336aacca28208b58eac90" +checksum = "005d93174040af37fb8625f891cd9827afdad314261f7ec4ee61ec497d6e9d3c" dependencies = [ "cfg-if 1.0.0", - "cranelift-codegen 0.74.0", - "cranelift-entity 0.74.0", + "cranelift-codegen 0.76.0", + "cranelift-entity 0.76.0", "cranelift-wasm", - "gimli 0.24.0", + "gimli 0.25.0", "indexmap", "log 0.4.14", "more-asserts", "serde", "thiserror", - "wasmparser 0.78.2", + "wasmparser 0.79.0", ] [[package]] name = "wasmtime-jit" -version = "0.27.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4539ea734422b7c868107e2187d7746d8affbcaa71916d72639f53757ad707" +checksum = "d0bf1dfb213a35d8f21aefae40e597fe72778a907011ffdff7affb029a02af9a" dependencies = [ - "addr2line 0.15.1", + "addr2line", "anyhow", "cfg-if 1.0.0", - "cranelift-codegen 0.74.0", - "cranelift-entity 0.74.0", - "cranelift-frontend 0.74.0", + "cranelift-codegen 0.76.0", + "cranelift-entity 0.76.0", + "cranelift-frontend 0.76.0", "cranelift-native", "cranelift-wasm", - "gimli 0.24.0", + "gimli 0.25.0", "log 0.4.14", "more-asserts", - "object 0.24.0", + "object 0.26.0", "rayon", "region", "serde", "target-lexicon 0.12.0", "thiserror", - "wasmparser 0.78.2", + "wasmparser 0.79.0", "wasmtime-cranelift", "wasmtime-debug", "wasmtime-environ", @@ -11608,13 +11589,13 @@ dependencies = [ [[package]] name = "wasmtime-obj" -version = "0.27.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1a8ff85246d091828e2225af521a6208ed28c997bb5c39eb697366dc2e2f2b" +checksum = "d231491878e710c68015228c9f9fc5955fe5c96dbf1485c15f7bed55b622c83c" dependencies = [ "anyhow", "more-asserts", - "object 0.24.0", + "object 0.26.0", "target-lexicon 0.12.0", "wasmtime-debug", "wasmtime-environ", @@ -11622,9 +11603,9 @@ dependencies = [ [[package]] name = "wasmtime-profiling" -version = "0.27.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24364d522dcd67c897c8fffc42e5bdfc57207bbb6d7eeade0da9d4a7d70105b" +checksum = "21486cfb5255c2069666c1f116f9e949d4e35c9a494f11112fa407879e42198d" dependencies = [ "anyhow", "cfg-if 1.0.0", @@ -11638,9 +11619,9 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "0.27.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51e57976e8a19a18a18e002c6eb12e5769554204238e47ff155fda1809ef0f7" +checksum = "d7ddfdf32e0a20d81f48be9dacd31612bc61de5a174d1356fef806d300f507de" dependencies = [ "anyhow", "backtrace", @@ -11889,18 +11870,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.6.1+zstd.1.4.9" +version = "0.9.0+zstd.1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de55e77f798f205d8561b8fe2ef57abfb6e0ff2abe7fd3c089e119cdb5631a3" +checksum = "07749a5dc2cb6b36661290245e350f15ec3bbb304e493db54a1d354480522ccd" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "3.0.1+zstd.1.4.9" +version = "4.1.1+zstd.1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1387cabcd938127b30ce78c4bf00b30387dddf704e3f0881dbc4ff62b5566f8c" +checksum = "c91c90f2c593b003603e5e0493c837088df4469da25aafff8bce42ba48caf079" dependencies = [ "libc", "zstd-sys", @@ -11908,9 +11889,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.4.20+zstd.1.4.9" +version = "1.6.1+zstd.1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd5b733d7cf2d9447e2c3e76a5589b4f5e5ae065c22a2bc0b023cbc331b6c8e" +checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33" dependencies = [ "cc", "libc", diff --git a/client/executor/common/src/runtime_blob/globals_snapshot.rs b/client/executor/common/src/runtime_blob/globals_snapshot.rs index 6a29ff8bae365..a25fa6f9fd639 100644 --- a/client/executor/common/src/runtime_blob/globals_snapshot.rs +++ b/client/executor/common/src/runtime_blob/globals_snapshot.rs @@ -34,14 +34,14 @@ pub trait InstanceGlobals { /// Get a handle to a global by it's export name. /// /// The requested export is must exist in the exported list, and it should be a mutable global. - fn get_global(&self, export_name: &str) -> Self::Global; + fn get_global(&mut self, export_name: &str) -> Self::Global; /// Get the current value of the global. - fn get_global_value(&self, global: &Self::Global) -> sp_wasm_interface::Value; + fn get_global_value(&mut self, global: &Self::Global) -> sp_wasm_interface::Value; /// Update the current value of the global. /// /// The global behind the handle is guaranteed to be mutable and the value to be the same type /// as the global. - fn set_global_value(&self, global: &Self::Global, value: sp_wasm_interface::Value); + fn set_global_value(&mut self, global: &Self::Global, value: sp_wasm_interface::Value); } /// A set of exposed mutable globals. @@ -79,7 +79,10 @@ impl GlobalsSnapshot { /// /// This function panics if the instance doesn't correspond to the module from which the /// [`ExposedMutableGlobalsSet`] was collected. - pub fn take(mutable_globals: &ExposedMutableGlobalsSet, instance: &Instance) -> Self + pub fn take( + mutable_globals: &ExposedMutableGlobalsSet, + instance: &mut Instance, + ) -> Self where Instance: InstanceGlobals, { @@ -98,7 +101,7 @@ impl GlobalsSnapshot { /// Apply the snapshot to the given instance. /// /// This instance must be the same that was used for creation of this snapshot. - pub fn apply(&self, instance: &Instance) + pub fn apply(&self, instance: &mut Instance) where Instance: InstanceGlobals, { diff --git a/client/executor/common/src/util.rs b/client/executor/common/src/util.rs index 3ea29540f98ee..ffbeb8c7ab533 100644 --- a/client/executor/common/src/util.rs +++ b/client/executor/common/src/util.rs @@ -233,7 +233,7 @@ pub mod wasmer { let range = checked_range(dest_addr.into(), source.len(), destination.len()) .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; - &mut destination[range].copy_from_slice(source); + destination[range].copy_from_slice(source); Ok(()) } } diff --git a/client/executor/common/src/wasm_runtime.rs b/client/executor/common/src/wasm_runtime.rs index eb73909d9234f..1e9f1225518a3 100644 --- a/client/executor/common/src/wasm_runtime.rs +++ b/client/executor/common/src/wasm_runtime.rs @@ -78,21 +78,21 @@ pub trait WasmInstance: Send { /// Before execution, instance is reset. /// /// Returns the encoded result on success. - fn call(&self, method: InvokeMethod, data: &[u8]) -> Result, Error>; + fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result, Error>; /// Call an exported method on this WASM instance. /// /// Before execution, instance is reset. /// /// Returns the encoded result on success. - fn call_export(&self, method: &str, data: &[u8]) -> Result, Error> { + fn call_export(&mut self, method: &str, data: &[u8]) -> Result, Error> { self.call(method.into(), data) } /// Get the value from a global with the given `name`. /// /// This method is only suitable for getting immutable globals. - fn get_global_const(&self, name: &str) -> Result, Error>; + fn get_global_const(&mut self, name: &str) -> Result, Error>; /// **Testing Only**. This function returns the base address of the linear memory. /// diff --git a/client/executor/src/integration_tests/linux.rs b/client/executor/src/integration_tests/linux.rs index 7e0696973dc77..38e57707e9e6b 100644 --- a/client/executor/src/integration_tests/linux.rs +++ b/client/executor/src/integration_tests/linux.rs @@ -40,7 +40,7 @@ fn memory_consumption_compiled() { let runtime = mk_test_runtime(WasmExecutionMethod::Compiled, 1024); - let instance = runtime.new_instance().unwrap(); + let mut instance = runtime.new_instance().unwrap(); let heap_base = instance .get_global_const("__heap_base") .expect("`__heap_base` is valid") diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index dabead4799dc8..fe964f47ba374 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -467,7 +467,7 @@ test_wasm_execution!(returns_mutable_static); fn returns_mutable_static(wasm_method: WasmExecutionMethod) { let runtime = mk_test_runtime(wasm_method, 1024); - let instance = runtime.new_instance().unwrap(); + let mut instance = runtime.new_instance().unwrap(); let res = instance.call_export("returns_mutable_static", &[0]).unwrap(); assert_eq!(33, u64::decode(&mut &res[..]).unwrap()); @@ -482,7 +482,7 @@ test_wasm_execution!(returns_mutable_static_bss); fn returns_mutable_static_bss(wasm_method: WasmExecutionMethod) { let runtime = mk_test_runtime(wasm_method, 1024); - let instance = runtime.new_instance().unwrap(); + let mut instance = runtime.new_instance().unwrap(); let res = instance.call_export("returns_mutable_static_bss", &[0]).unwrap(); assert_eq!(1, u64::decode(&mut &res[..]).unwrap()); @@ -508,7 +508,7 @@ fn restoration_of_globals(wasm_method: WasmExecutionMethod) { const REQUIRED_MEMORY_PAGES: u64 = 32; let runtime = mk_test_runtime(wasm_method, REQUIRED_MEMORY_PAGES); - let instance = runtime.new_instance().unwrap(); + let mut instance = runtime.new_instance().unwrap(); // On the first invocation we allocate approx. 768KB (75%) of stack and then trap. let res = instance.call_export("allocates_huge_stack_array", &true.encode()); @@ -522,7 +522,7 @@ fn restoration_of_globals(wasm_method: WasmExecutionMethod) { test_wasm_execution!(interpreted_only heap_is_reset_between_calls); fn heap_is_reset_between_calls(wasm_method: WasmExecutionMethod) { let runtime = mk_test_runtime(wasm_method, 1024); - let instance = runtime.new_instance().unwrap(); + let mut instance = runtime.new_instance().unwrap(); let heap_base = instance .get_global_const("__heap_base") diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 979bcc072c88b..d912fc0fd13c9 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -163,7 +163,7 @@ impl WasmExecutor { where F: FnOnce( AssertUnwindSafe<&Arc>, - AssertUnwindSafe<&dyn WasmInstance>, + AssertUnwindSafe<&mut dyn WasmInstance>, Option<&RuntimeVersion>, AssertUnwindSafe<&mut dyn Externalities>, ) -> Result>, @@ -217,7 +217,7 @@ impl WasmExecutor { .new_instance() .map_err(|e| format!("Failed to create instance: {:?}", e))?; - let instance = AssertUnwindSafe(instance); + let mut instance = AssertUnwindSafe(instance); let mut ext = AssertUnwindSafe(ext); let module = AssertUnwindSafe(module); @@ -283,7 +283,7 @@ impl CodeExecutor for WasmExecutor { runtime_code, ext, false, - |module, instance, _onchain_version, mut ext| { + |module, mut instance, _onchain_version, mut ext| { with_externalities_safe(&mut **ext, move || { preregister_builtin_ext(module.clone()); instance.call_export(method, data).map(NativeOrEncoded::Encoded) @@ -438,7 +438,7 @@ impl RuntimeSpawn for RuntimeInstanceSpawn { // pool of instances should be used. // // https://github.com/paritytech/substrate/issues/7354 - let instance = + let mut instance = module.new_instance().expect("Failed to create new instance from module"); instance @@ -525,7 +525,7 @@ impl CodeExecutor for NativeElseWasmExecut runtime_code, ext, false, - |module, instance, onchain_version, mut ext| { + |module, mut instance, onchain_version, mut ext| { let onchain_version = onchain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?; diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index b11e3958dbc81..b3a981d9e0821 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -76,7 +76,7 @@ impl VersionedRuntime { where F: FnOnce( &Arc, - &dyn WasmInstance, + &mut dyn WasmInstance, Option<&RuntimeVersion>, &mut dyn Externalities, ) -> Result, @@ -90,12 +90,12 @@ impl VersionedRuntime { match instance { Some((index, mut locked)) => { - let (instance, new_inst) = locked + let (mut instance, new_inst) = locked .take() .map(|r| Ok((r, false))) .unwrap_or_else(|| self.module.new_instance().map(|i| (i, true)))?; - let result = f(&self.module, &*instance, self.version.as_ref(), ext); + let result = f(&self.module, &mut *instance, self.version.as_ref(), ext); if let Err(e) = &result { if new_inst { log::warn!( @@ -129,9 +129,9 @@ impl VersionedRuntime { log::warn!(target: "wasm-runtime", "Ran out of free WASM instances"); // Allocate a new instance - let instance = self.module.new_instance()?; + let mut instance = self.module.new_instance()?; - f(&self.module, &*instance, self.version.as_ref(), ext) + f(&self.module, &mut *instance, self.version.as_ref(), ext) }, } } @@ -213,7 +213,7 @@ impl RuntimeCache { where F: FnOnce( &Arc, - &dyn WasmInstance, + &mut dyn WasmInstance, Option<&RuntimeVersion>, &mut dyn Externalities, ) -> Result, diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index 6052662fa7ccf..ceab07c2f71cb 100644 --- a/client/executor/wasmi/src/lib.rs +++ b/client/executor/wasmi/src/lib.rs @@ -736,7 +736,7 @@ pub struct WasmiInstance { unsafe impl Send for WasmiInstance {} impl WasmInstance for WasmiInstance { - fn call(&self, method: InvokeMethod, data: &[u8]) -> Result, Error> { + fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result, Error> { // We reuse a single wasm instance for multiple calls and a previous call (if any) // altered the state. Therefore, we need to restore the instance to original state. @@ -767,7 +767,7 @@ impl WasmInstance for WasmiInstance { ) } - fn get_global_const(&self, name: &str) -> Result, Error> { + fn get_global_const(&mut self, name: &str) -> Result, Error> { match self.instance.export_by_name(name) { Some(global) => Ok(Some( global diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 3158cdecc3263..edf1747524263 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -16,7 +16,6 @@ targets = ["x86_64-unknown-linux-gnu"] libc = "0.2.90" cfg-if = "1.0" log = "0.4.8" -scoped-tls = "1.0" parity-wasm = "0.42.0" codec = { package = "parity-scale-codec", version = "2.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } @@ -24,10 +23,7 @@ sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-in sp-runtime-interface = { version = "4.0.0-dev", path = "../../../primitives/runtime-interface" } sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } sc-allocator = { version = "4.0.0-dev", path = "../../allocator" } -wasmtime = { version = "0.27.0", default-features = false, features = [ - "cache", - "parallel-compilation", -] } +wasmtime = { version = "0.29.0", default-features = false, features = ["cache", "parallel-compilation"] } [dev-dependencies] sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index 8453ec3954354..4edb9f9c423f0 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -19,7 +19,7 @@ //! This module defines `HostState` and `HostContext` structs which provide logic and state //! required for execution of host. -use crate::instance_wrapper::InstanceWrapper; +use crate::{instance_wrapper::InstanceWrapper, runtime::StoreData}; use codec::{Decode, Encode}; use log::trace; use sc_allocator::FreeingBumpHeapAllocator; @@ -31,7 +31,7 @@ use sc_executor_common::{ use sp_core::sandbox as sandbox_primitives; use sp_wasm_interface::{FunctionContext, MemoryId, Pointer, Sandbox, WordSize}; use std::{cell::RefCell, rc::Rc}; -use wasmtime::{Func, Val}; +use wasmtime::{Caller, Func, Val}; /// The state required to construct a HostContext context. The context only lasts for one host /// call, whereas the state is maintained for the duration of a Wasm runtime call, which may make @@ -64,45 +64,67 @@ impl HostState { } /// Materialize `HostContext` that can be used to invoke a substrate host `dyn Function`. - pub fn materialize<'a>(&'a self) -> HostContext<'a> { - HostContext(self) + pub(crate) fn materialize<'a, 'b, 'c>( + &'a self, + caller: &'b mut Caller<'c, StoreData>, + ) -> HostContext<'a, 'b, 'c> { + HostContext { host_state: self, caller } } } /// A `HostContext` implements `FunctionContext` for making host calls from a Wasmtime /// runtime. The `HostContext` exists only for the lifetime of the call and borrows state from /// a longer-living `HostState`. -pub struct HostContext<'a>(&'a HostState); +pub(crate) struct HostContext<'a, 'b, 'c> { + host_state: &'a HostState, + caller: &'b mut Caller<'c, StoreData>, +} -impl<'a> std::ops::Deref for HostContext<'a> { +impl<'a, 'b, 'c> std::ops::Deref for HostContext<'a, 'b, 'c> { type Target = HostState; fn deref(&self) -> &HostState { - self.0 + self.host_state } } -impl<'a> sp_wasm_interface::FunctionContext for HostContext<'a> { +impl<'a, 'b, 'c> sp_wasm_interface::FunctionContext for HostContext<'a, 'b, 'c> { fn read_memory_into( &self, address: Pointer, dest: &mut [u8], ) -> sp_wasm_interface::Result<()> { - self.instance.read_memory_into(address, dest).map_err(|e| e.to_string()) + let ctx = &self.caller; + self.host_state + .instance + .read_memory_into(ctx, address, dest) + .map_err(|e| e.to_string()) } fn write_memory(&mut self, address: Pointer, data: &[u8]) -> sp_wasm_interface::Result<()> { - self.instance.write_memory_from(address, data).map_err(|e| e.to_string()) + let ctx = &mut self.caller; + self.host_state + .instance + .write_memory_from(ctx, address, data) + .map_err(|e| e.to_string()) } fn allocate_memory(&mut self, size: WordSize) -> sp_wasm_interface::Result> { - self.instance - .allocate(&mut *self.allocator.borrow_mut(), size) + let ctx = &mut self.caller; + let allocator = &self.host_state.allocator; + + self.host_state + .instance + .allocate(ctx, &mut *allocator.borrow_mut(), size) .map_err(|e| e.to_string()) } fn deallocate_memory(&mut self, ptr: Pointer) -> sp_wasm_interface::Result<()> { - self.instance - .deallocate(&mut *self.allocator.borrow_mut(), ptr) + let ctx = &mut self.caller; + let allocator = &self.host_state.allocator; + + self.host_state + .instance + .deallocate(ctx, &mut *allocator.borrow_mut(), ptr) .map_err(|e| e.to_string()) } @@ -111,7 +133,7 @@ impl<'a> sp_wasm_interface::FunctionContext for HostContext<'a> { } } -impl<'a> Sandbox for HostContext<'a> { +impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { fn memory_get( &mut self, memory_id: MemoryId, @@ -129,7 +151,8 @@ impl<'a> Sandbox for HostContext<'a> { Ok(buffer) => buffer, }; - if let Err(_) = self.instance.write_memory_from(buf_ptr, &buffer) { + let instance = self.instance.clone(); + if let Err(_) = instance.write_memory_from(&mut self.caller, buf_ptr, &buffer) { return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS) } @@ -148,7 +171,7 @@ impl<'a> Sandbox for HostContext<'a> { let len = val_len as usize; - let buffer = match self.instance.read_memory(val_ptr, len) { + let buffer = match self.instance.read_memory(&self.caller, val_ptr, len) { Err(_) => return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), Ok(buffer) => buffer, }; @@ -241,12 +264,14 @@ impl<'a> Sandbox for HostContext<'a> { ) -> sp_wasm_interface::Result { // Extract a dispatch thunk from the instance's table by the specified index. let dispatch_thunk = { + let ctx = &mut self.caller; let table_item = self + .host_state .instance .table() .as_ref() .ok_or_else(|| "Runtime doesn't have a table; sandbox is unavailable")? - .get(dispatch_thunk_id); + .get(ctx, dispatch_thunk_id); table_item .ok_or_else(|| "dispatch_thunk_id is out of bounds")? @@ -295,12 +320,12 @@ impl<'a> Sandbox for HostContext<'a> { } } -struct SandboxContext<'a, 'b> { - host_context: &'a mut HostContext<'b>, +struct SandboxContext<'a, 'b, 'c, 'd> { + host_context: &'a mut HostContext<'b, 'c, 'd>, dispatch_thunk: Func, } -impl<'a, 'b> sandbox::SandboxContext for SandboxContext<'a, 'b> { +impl<'a, 'b, 'c, 'd> sandbox::SandboxContext for SandboxContext<'a, 'b, 'c, 'd> { fn invoke( &mut self, invoke_args_ptr: Pointer, @@ -308,12 +333,16 @@ impl<'a, 'b> sandbox::SandboxContext for SandboxContext<'a, 'b> { state: u32, func_idx: SupervisorFuncIndex, ) -> Result { - let result = self.dispatch_thunk.call(&[ - Val::I32(u32::from(invoke_args_ptr) as i32), - Val::I32(invoke_args_len as i32), - Val::I32(state as i32), - Val::I32(usize::from(func_idx) as i32), - ]); + let result = self.dispatch_thunk.call( + &mut self.host_context.caller, + &[ + Val::I32(u32::from(invoke_args_ptr) as i32), + Val::I32(invoke_args_len as i32), + Val::I32(state as i32), + Val::I32(usize::from(func_idx) as i32), + ], + ); + match result { Ok(ret_vals) => { let ret_val = if ret_vals.len() != 1 { diff --git a/client/executor/wasmtime/src/imports.rs b/client/executor/wasmtime/src/imports.rs index b27fb944bc030..a9ef6e1f58a70 100644 --- a/client/executor/wasmtime/src/imports.rs +++ b/client/executor/wasmtime/src/imports.rs @@ -16,12 +16,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{state_holder, util}; +use crate::{ + runtime::{Store, StoreData}, + util, +}; use sc_executor_common::error::WasmError; use sp_wasm_interface::{Function, ValueType}; use std::any::Any; use wasmtime::{ - Extern, ExternType, Func, FuncType, ImportType, Limits, Memory, MemoryType, Module, Store, + Caller, Extern, ExternType, Func, FuncType, ImportType, Limits, Memory, MemoryType, Module, Trap, Val, }; @@ -34,8 +37,8 @@ pub struct Imports { /// Goes over all imports of a module and prepares a vector of `Extern`s that can be used for /// instantiation of the module. Returns an error if there are imports that cannot be satisfied. -pub fn resolve_imports( - store: &Store, +pub(crate) fn resolve_imports( + store: &mut Store, module: &Module, host_functions: &[&'static dyn Function], heap_pages: u32, @@ -78,7 +81,7 @@ fn import_name<'a, 'b: 'a>(import: &'a ImportType<'b>) -> Result<&'a str, WasmEr } fn resolve_memory_import( - store: &Store, + store: &mut Store, import_ty: &ImportType, heap_pages: u32, ) -> Result { @@ -117,7 +120,7 @@ fn resolve_memory_import( } fn resolve_func_import( - store: &Store, + store: &mut Store, import_ty: &ImportType, host_functions: &[&'static dyn Function], allow_missing_func_imports: bool, @@ -162,19 +165,27 @@ struct HostFuncHandler { host_func: &'static dyn Function, } -fn call_static( +fn call_static<'a>( static_func: &'static dyn Function, wasmtime_params: &[Val], wasmtime_results: &mut [Val], + mut caller: Caller<'a, StoreData>, ) -> Result<(), wasmtime::Trap> { - let unwind_result = state_holder::with_context(|host_ctx| { - let mut host_ctx = host_ctx.expect( - "host functions can be called only from wasm instance; - wasm instance is always called initializing context; - therefore host_ctx cannot be None; - qed - ", - ); + let unwind_result = { + let host_state = caller + .data() + .host_state() + .expect( + "host functions can be called only from wasm instance; + wasm instance is always called initializing context; + therefore host_ctx cannot be None; + qed + ", + ) + .clone(); + + let mut host_ctx = host_state.materialize(&mut caller); + // `from_wasmtime_val` panics if it encounters a value that doesn't fit into the values // available in substrate. // @@ -185,7 +196,7 @@ fn call_static( std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { static_func.execute(&mut host_ctx, &mut params) })) - }); + }; let execution_result = match unwind_result { Ok(execution_result) => execution_result, @@ -219,11 +230,11 @@ impl HostFuncHandler { Self { host_func } } - fn into_extern(self, store: &Store) -> Extern { + fn into_extern(self, store: &mut Store) -> Extern { let host_func = self.host_func; let func_ty = wasmtime_func_sig(self.host_func); - let func = Func::new(store, func_ty, move |_, params, result| { - call_static(host_func, params, result) + let func = Func::new(store, func_ty, move |caller, params, result| { + call_static(host_func, params, result, caller) }); Extern::Func(func) } @@ -243,7 +254,7 @@ impl MissingHostFuncHandler { }) } - fn into_extern(self, store: &Store, func_ty: &FuncType) -> Extern { + fn into_extern(self, store: &mut Store, func_ty: &FuncType) -> Extern { let Self { module, name } = self; let func = Func::new(store, func_ty.clone(), move |_, _, _| { Err(Trap::new(format!("call to a missing function {}:{}", module, name))) diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index f66d62f673d90..ccfbb912b9a69 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -19,20 +19,18 @@ //! Defines data and logic needed for interaction with an WebAssembly instance of a substrate //! runtime module. -use crate::{ - imports::Imports, - util::{from_wasmtime_val, into_wasmtime_val}, -}; +use crate::imports::Imports; use sc_executor_common::{ error::{Error, Result}, - runtime_blob, util::checked_range, wasm_runtime::InvokeMethod, }; use sp_wasm_interface::{Pointer, Value, WordSize}; -use std::{marker, slice}; -use wasmtime::{Extern, Func, Global, Instance, Memory, Module, Store, Table, Val}; +use std::marker; +use wasmtime::{ + AsContext, AsContextMut, Extern, Func, Global, Instance, Memory, Module, Table, Val, +}; /// Invoked entrypoint format. pub enum EntryPointType { @@ -58,7 +56,12 @@ pub struct EntryPoint { impl EntryPoint { /// Call this entry point. - pub fn call(&self, data_ptr: Pointer, data_len: WordSize) -> Result { + pub fn call( + &self, + ctx: impl AsContextMut, + data_ptr: Pointer, + data_len: WordSize, + ) -> Result { let data_ptr = u32::from(data_ptr); let data_len = u32::from(data_len); @@ -68,15 +71,18 @@ impl EntryPoint { match self.call_type { EntryPointType::Direct { ref entrypoint } => - entrypoint.call((data_ptr, data_len)).map_err(handle_trap), + entrypoint.call(ctx, (data_ptr, data_len)).map_err(handle_trap), EntryPointType::Wrapped { func, ref dispatcher } => - dispatcher.call((func, data_ptr, data_len)).map_err(handle_trap), + dispatcher.call(ctx, (func, data_ptr, data_len)).map_err(handle_trap), } } - pub fn direct(func: wasmtime::Func) -> std::result::Result { + pub fn direct( + func: wasmtime::Func, + ctx: impl AsContext, + ) -> std::result::Result { let entrypoint = func - .typed::<(u32, u32), u64>() + .typed::<(u32, u32), u64, _>(ctx) .map_err(|_| "Invalid signature for direct entry point")? .clone(); Ok(Self { call_type: EntryPointType::Direct { entrypoint } }) @@ -85,9 +91,10 @@ impl EntryPoint { pub fn wrapped( dispatcher: wasmtime::Func, func: u32, + ctx: impl AsContext, ) -> std::result::Result { let dispatcher = dispatcher - .typed::<(u32, u32, u32), u64>() + .typed::<(u32, u32, u32), u64, _>(ctx) .map_err(|_| "Invalid signature for wrapped entry point")? .clone(); Ok(Self { call_type: EntryPointType::Wrapped { func, dispatcher } }) @@ -144,8 +151,13 @@ fn extern_func(extern_: &Extern) -> Option<&Func> { impl InstanceWrapper { /// Create a new instance wrapper from the given wasm module. - pub fn new(store: &Store, module: &Module, imports: &Imports, heap_pages: u32) -> Result { - let instance = Instance::new(store, module, &imports.externs) + pub fn new( + module: &Module, + imports: &Imports, + heap_pages: u32, + mut ctx: impl AsContextMut, + ) -> Result { + let instance = Instance::new(&mut ctx, module, &imports.externs) .map_err(|e| Error::from(format!("cannot instantiate: {}", e)))?; let memory = match imports.memory_import_index { @@ -153,51 +165,55 @@ impl InstanceWrapper { .expect("only memory can be at the `memory_idx`; qed") .clone(), None => { - let memory = get_linear_memory(&instance)?; - if !memory.grow(heap_pages).is_ok() { - return Err("failed to increase the linear memory size".into()) + let memory = get_linear_memory(&instance, &mut ctx)?; + if !memory.grow(&mut ctx, heap_pages).is_ok() { + return Err("failed top increase the linear memory size".into()) } memory }, }; - Ok(Self { - table: get_table(&instance), - instance, - memory, - _not_send_nor_sync: marker::PhantomData, - }) + let table = get_table(&instance, ctx); + + Ok(Self { table, instance, memory, _not_send_nor_sync: marker::PhantomData }) } /// Resolves a substrate entrypoint by the given name. /// /// An entrypoint must have a signature `(i32, i32) -> i64`, otherwise this function will return /// an error. - pub fn resolve_entrypoint(&self, method: InvokeMethod) -> Result { + pub fn resolve_entrypoint( + &self, + method: InvokeMethod, + mut ctx: impl AsContextMut, + ) -> Result { Ok(match method { InvokeMethod::Export(method) => { // Resolve the requested method and verify that it has a proper signature. - let export = self.instance.get_export(method).ok_or_else(|| { + let export = self.instance.get_export(&mut ctx, method).ok_or_else(|| { Error::from(format!("Exported method {} is not found", method)) })?; let func = extern_func(&export) .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))? .clone(); - EntryPoint::direct(func).map_err(|_| { + EntryPoint::direct(func, ctx).map_err(|_| { Error::from(format!("Exported function '{}' has invalid signature.", method)) })? }, InvokeMethod::Table(func_ref) => { - let table = - self.instance.get_table("__indirect_function_table").ok_or(Error::NoTable)?; - let val = table.get(func_ref).ok_or(Error::NoTableEntryWithIndex(func_ref))?; + let table = self + .instance + .get_table(&mut ctx, "__indirect_function_table") + .ok_or(Error::NoTable)?; + let val = + table.get(&mut ctx, func_ref).ok_or(Error::NoTableEntryWithIndex(func_ref))?; let func = val .funcref() .ok_or(Error::TableElementIsNotAFunction(func_ref))? .ok_or(Error::FunctionRefIsNull(func_ref))? .clone(); - EntryPoint::direct(func).map_err(|_| { + EntryPoint::direct(func, ctx).map_err(|_| { Error::from(format!( "Function @{} in exported table has invalid signature for direct call.", func_ref, @@ -205,10 +221,12 @@ impl InstanceWrapper { })? }, InvokeMethod::TableWithWrapper { dispatcher_ref, func } => { - let table = - self.instance.get_table("__indirect_function_table").ok_or(Error::NoTable)?; + let table = self + .instance + .get_table(&mut ctx, "__indirect_function_table") + .ok_or(Error::NoTable)?; let val = table - .get(dispatcher_ref) + .get(&mut ctx, dispatcher_ref) .ok_or(Error::NoTableEntryWithIndex(dispatcher_ref))?; let dispatcher = val .funcref() @@ -216,7 +234,7 @@ impl InstanceWrapper { .ok_or(Error::FunctionRefIsNull(dispatcher_ref))? .clone(); - EntryPoint::wrapped(dispatcher, func).map_err(|_| { + EntryPoint::wrapped(dispatcher, func, ctx).map_err(|_| { Error::from(format!( "Function @{} in exported table has invalid signature for wrapped call.", dispatcher_ref, @@ -234,17 +252,17 @@ impl InstanceWrapper { /// Reads `__heap_base: i32` global variable and returns it. /// /// If it doesn't exist, not a global or of not i32 type returns an error. - pub fn extract_heap_base(&self) -> Result { + pub fn extract_heap_base(&self, mut ctx: impl AsContextMut) -> Result { let heap_base_export = self .instance - .get_export("__heap_base") + .get_export(&mut ctx, "__heap_base") .ok_or_else(|| Error::from("__heap_base is not found"))?; let heap_base_global = extern_global(&heap_base_export) .ok_or_else(|| Error::from("__heap_base is not a global"))?; let heap_base = heap_base_global - .get() + .get(&mut ctx) .i32() .ok_or_else(|| Error::from("__heap_base is not a i32"))?; @@ -252,15 +270,15 @@ impl InstanceWrapper { } /// Get the value from a global with the given `name`. - pub fn get_global_val(&self, name: &str) -> Result> { - let global = match self.instance.get_export(name) { + pub fn get_global_val(&self, mut ctx: impl AsContextMut, name: &str) -> Result> { + let global = match self.instance.get_export(&mut ctx, name) { Some(global) => global, None => return Ok(None), }; let global = extern_global(&global).ok_or_else(|| format!("`{}` is not a global", name))?; - match global.get() { + match global.get(ctx) { Val::I32(val) => Ok(Some(Value::I32(val))), Val::I64(val) => Ok(Some(Value::I64(val))), Val::F32(val) => Ok(Some(Value::F32(val))), @@ -268,12 +286,17 @@ impl InstanceWrapper { _ => Err("Unknown value type".into()), } } + + /// Get a global with the given `name`. + pub fn get_global(&self, ctx: impl AsContextMut, name: &str) -> Option { + self.instance.get_global(ctx, name) + } } /// Extract linear memory instance from the given instance. -fn get_linear_memory(instance: &Instance) -> Result { +fn get_linear_memory(instance: &Instance, ctx: impl AsContextMut) -> Result { let memory_export = instance - .get_export("memory") + .get_export(ctx, "memory") .ok_or_else(|| Error::from("memory is not exported under `memory` name"))?; let memory = extern_memory(&memory_export) @@ -284,9 +307,9 @@ fn get_linear_memory(instance: &Instance) -> Result { } /// Extract the table from the given instance if any. -fn get_table(instance: &Instance) -> Option { +fn get_table(instance: &Instance, ctx: impl AsContextMut) -> Option
{ instance - .get_export("__indirect_function_table") + .get_export(ctx, "__indirect_function_table") .as_ref() .and_then(extern_table) .cloned() @@ -297,12 +320,17 @@ impl InstanceWrapper { /// Read data from a slice of memory into a newly allocated buffer. /// /// Returns an error if the read would go out of the memory bounds. - pub fn read_memory(&self, source_addr: Pointer, size: usize) -> Result> { - let range = checked_range(source_addr.into(), size, self.memory.data_size()) + pub fn read_memory( + &self, + ctx: impl AsContext, + source_addr: Pointer, + size: usize, + ) -> Result> { + let range = checked_range(source_addr.into(), size, self.memory.data_size(&ctx)) .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; let mut buffer = vec![0; range.len()]; - self.read_memory_into(source_addr, &mut buffer)?; + self.read_memory_into(ctx, source_addr, &mut buffer)?; Ok(buffer) } @@ -310,33 +338,35 @@ impl InstanceWrapper { /// Read data from the instance memory into a slice. /// /// Returns an error if the read would go out of the memory bounds. - pub fn read_memory_into(&self, source_addr: Pointer, dest: &mut [u8]) -> Result<()> { - unsafe { - // This should be safe since we don't grow up memory while caching this reference and - // we give up the reference before returning from this function. - let memory = self.memory_as_slice(); - - let range = checked_range(source_addr.into(), dest.len(), memory.len()) - .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; - dest.copy_from_slice(&memory[range]); - Ok(()) - } + pub fn read_memory_into( + &self, + ctx: impl AsContext, + address: Pointer, + dest: &mut [u8], + ) -> Result<()> { + let memory = self.memory.data(ctx.as_context()); + + let range = checked_range(address.into(), dest.len(), memory.len()) + .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; + dest.copy_from_slice(&memory[range]); + Ok(()) } /// Write data to the instance memory from a slice. /// /// Returns an error if the write would go out of the memory bounds. - pub fn write_memory_from(&self, dest_addr: Pointer, data: &[u8]) -> Result<()> { - unsafe { - // This should be safe since we don't grow up memory while caching this reference and - // we give up the reference before returning from this function. - let memory = self.memory_as_slice_mut(); - - let range = checked_range(dest_addr.into(), data.len(), memory.len()) - .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; - memory[range].copy_from_slice(data); - Ok(()) - } + pub fn write_memory_from( + &self, + mut ctx: impl AsContextMut, + address: Pointer, + data: &[u8], + ) -> Result<()> { + let memory = self.memory.data_mut(ctx.as_context_mut()); + + let range = checked_range(address.into(), data.len(), memory.len()) + .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; + memory[range].copy_from_slice(data); + Ok(()) } /// Allocate some memory of the given size. Returns pointer to the allocated memory region. @@ -345,16 +375,13 @@ impl InstanceWrapper { /// to get more details. pub fn allocate( &self, + mut ctx: impl AsContextMut, allocator: &mut sc_allocator::FreeingBumpHeapAllocator, size: WordSize, ) -> Result> { - unsafe { - // This should be safe since we don't grow up memory while caching this reference and - // we give up the reference before returning from this function. - let memory = self.memory_as_slice_mut(); + let memory = self.memory.data_mut(ctx.as_context_mut()); - allocator.allocate(memory, size).map_err(Into::into) - } + allocator.allocate(memory, size).map_err(Into::into) } /// Deallocate the memory pointed by the given pointer. @@ -362,64 +389,25 @@ impl InstanceWrapper { /// Returns `Err` in case the given memory region cannot be deallocated. pub fn deallocate( &self, + mut ctx: impl AsContextMut, allocator: &mut sc_allocator::FreeingBumpHeapAllocator, ptr: Pointer, ) -> Result<()> { - unsafe { - // This should be safe since we don't grow up memory while caching this reference and - // we give up the reference before returning from this function. - let memory = self.memory_as_slice_mut(); + let memory = self.memory.data_mut(ctx.as_context_mut()); - allocator.deallocate(memory, ptr).map_err(Into::into) - } - } - - /// Returns linear memory of the wasm instance as a slice. - /// - /// # Safety - /// - /// Wasmtime doesn't provide comprehensive documentation about the exact behavior of the data - /// pointer. If a dynamic style heap is used the base pointer of the heap can change. Since - /// growing, we cannot guarantee the lifetime of the returned slice reference. - unsafe fn memory_as_slice(&self) -> &[u8] { - let ptr = self.memory.data_ptr() as *const _; - let len = self.memory.data_size(); - - if len == 0 { - &[] - } else { - slice::from_raw_parts(ptr, len) - } - } - - /// Returns linear memory of the wasm instance as a slice. - /// - /// # Safety - /// - /// See `[memory_as_slice]`. In addition to those requirements, since a mutable reference is - /// returned it must be ensured that only one mutable and no shared references to memory exists - /// at the same time. - unsafe fn memory_as_slice_mut(&self) -> &mut [u8] { - let ptr = self.memory.data_ptr(); - let len = self.memory.data_size(); - - if len == 0 { - &mut [] - } else { - slice::from_raw_parts_mut(ptr, len) - } + allocator.deallocate(memory, ptr).map_err(Into::into) } /// Returns the pointer to the first byte of the linear memory for this instance. - pub fn base_ptr(&self) -> *const u8 { - self.memory.data_ptr() + pub fn base_ptr(&self, ctx: impl AsContext) -> *const u8 { + self.memory.data_ptr(ctx) } /// Removes physical backing from the allocated linear memory. This leads to returning the /// memory back to the system. While the memory is zeroed this is considered as a side-effect /// and is not relied upon. Thus this function acts as a hint. - pub fn decommit(&self) { - if self.memory.data_size() == 0 { + pub fn decommit(&self, ctx: impl AsContext) { + if self.memory.data_size(&ctx) == 0 { return } @@ -428,8 +416,8 @@ impl InstanceWrapper { use std::sync::Once; unsafe { - let ptr = self.memory.data_ptr(); - let len = self.memory.data_size(); + let ptr = self.memory.data_ptr(&ctx); + let len = self.memory.data_size(ctx); // Linux handles MADV_DONTNEED reliably. The result is that the given area // is unmapped and will be zeroed on the next pagefault. @@ -447,23 +435,3 @@ impl InstanceWrapper { } } } - -impl runtime_blob::InstanceGlobals for InstanceWrapper { - type Global = wasmtime::Global; - - fn get_global(&self, export_name: &str) -> Self::Global { - self.instance - .get_global(export_name) - .expect("get_global is guaranteed to be called with an export name of a global; qed") - } - - fn get_global_value(&self, global: &Self::Global) -> Value { - from_wasmtime_val(global.get()) - } - - fn set_global_value(&self, global: &Self::Global, value: Value) { - global.set(into_wasmtime_val(value)).expect( - "the value is guaranteed to be of the same value; the global is guaranteed to be mutable; qed", - ); - } -} diff --git a/client/executor/wasmtime/src/lib.rs b/client/executor/wasmtime/src/lib.rs index 62b0b205f6de6..8d7f93fecb307 100644 --- a/client/executor/wasmtime/src/lib.rs +++ b/client/executor/wasmtime/src/lib.rs @@ -21,7 +21,6 @@ mod host; mod imports; mod instance_wrapper; mod runtime; -mod state_holder; mod util; #[cfg(test)] diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index f6878ec5ee6e1..006f102926ecb 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -22,13 +22,15 @@ use crate::{ host::HostState, imports::{resolve_imports, Imports}, instance_wrapper::{EntryPoint, InstanceWrapper}, - state_holder, + util, }; use sc_allocator::FreeingBumpHeapAllocator; use sc_executor_common::{ error::{Result, WasmError}, - runtime_blob::{DataSegmentsSnapshot, ExposedMutableGlobalsSet, GlobalsSnapshot, RuntimeBlob}, + runtime_blob::{ + self, DataSegmentsSnapshot, ExposedMutableGlobalsSet, GlobalsSnapshot, RuntimeBlob, + }, wasm_runtime::{InvokeMethod, WasmInstance, WasmModule}, }; use sp_runtime_interface::unpack_ptr_and_len; @@ -38,7 +40,24 @@ use std::{ rc::Rc, sync::Arc, }; -use wasmtime::{Engine, Store}; +use wasmtime::{AsContext, AsContextMut, Engine, StoreLimits}; + +pub(crate) struct StoreData { + /// The limits we aply to the store. We need to store it here to return a reference to this + /// object when we have the limits enabled. + limits: StoreLimits, + /// This will only be set when we call into the runtime. + host_state: Option>, +} + +impl StoreData { + /// Returns a reference to the host state. + pub fn host_state(&self) -> Option<&Rc> { + self.host_state.as_ref() + } +} + +pub(crate) type Store = wasmtime::Store; enum Strategy { FastInstanceReuse { @@ -46,6 +65,7 @@ enum Strategy { globals_snapshot: GlobalsSnapshot, data_segments_snapshot: Arc, heap_base: u32, + store: Store, }, RecreateInstance(InstanceCreator), } @@ -58,8 +78,33 @@ struct InstanceCreator { } impl InstanceCreator { - fn instantiate(&self) -> Result { - InstanceWrapper::new(&self.store, &*self.module, &*self.imports, self.heap_pages) + fn instantiate(&mut self) -> Result { + InstanceWrapper::new(&*self.module, &*self.imports, self.heap_pages, &mut self.store) + } +} + +struct InstanceGlobals<'a, C> { + ctx: &'a mut C, + instance: &'a InstanceWrapper, +} + +impl<'a, C: AsContextMut> runtime_blob::InstanceGlobals for InstanceGlobals<'a, C> { + type Global = wasmtime::Global; + + fn get_global(&mut self, export_name: &str) -> Self::Global { + self.instance + .get_global(&mut self.ctx, export_name) + .expect("get_global is guaranteed to be called with an export name of a global; qed") + } + + fn get_global_value(&mut self, global: &Self::Global) -> Value { + util::from_wasmtime_val(global.get(&mut self.ctx)) + } + + fn set_global_value(&mut self, global: &Self::Global, value: Value) { + global.set(&mut self.ctx, util::into_wasmtime_val(value)).expect( + "the value is guaranteed to be of the same value; the global is guaranteed to be mutable; qed", + ); } } @@ -82,19 +127,25 @@ pub struct WasmtimeRuntime { impl WasmtimeRuntime { /// Creates the store respecting the set limits. fn new_store(&self) -> Store { - match self.config.max_memory_pages { - Some(max_memory_pages) => Store::new_with_limits( - &self.engine, - wasmtime::StoreLimitsBuilder::new().memory_pages(max_memory_pages).build(), - ), - None => Store::new(&self.engine), + let limits = if let Some(max_memory_pages) = self.config.max_memory_pages { + wasmtime::StoreLimitsBuilder::new().memory_pages(max_memory_pages).build() + } else { + Default::default() + }; + + let mut store = Store::new(&self.engine, StoreData { limits, host_state: None }); + + if self.config.max_memory_pages.is_some() { + store.limiter(|s| &mut s.limits); } + + store } } impl WasmModule for WasmtimeRuntime { fn new_instance(&self) -> Result> { - let store = self.new_store(); + let mut store = self.new_store(); // Scan all imports, find the matching host functions, and create stubs that adapt arguments // and results. @@ -103,7 +154,7 @@ impl WasmModule for WasmtimeRuntime { // However, I am not sure if that's a good idea since it would be pushing our luck // further by assuming that `Store` not only `Send` but also `Sync`. let imports = resolve_imports( - &store, + &mut store, &self.module, &self.host_functions, self.config.heap_pages, @@ -112,21 +163,24 @@ impl WasmModule for WasmtimeRuntime { let strategy = if let Some(ref snapshot_data) = self.snapshot_data { let instance_wrapper = - InstanceWrapper::new(&store, &self.module, &imports, self.config.heap_pages)?; - let heap_base = instance_wrapper.extract_heap_base()?; + InstanceWrapper::new(&self.module, &imports, self.config.heap_pages, &mut store)?; + let heap_base = instance_wrapper.extract_heap_base(&mut store)?; // This function panics if the instance was created from a runtime blob different from // which the mutable globals were collected. Here, it is easy to see that there is only // a single runtime blob and thus it's the same that was used for both creating the // instance and collecting the mutable globals. - let globals_snapshot = - GlobalsSnapshot::take(&snapshot_data.mutable_globals, &instance_wrapper); + let globals_snapshot = GlobalsSnapshot::take( + &snapshot_data.mutable_globals, + &mut InstanceGlobals { ctx: &mut store, instance: &instance_wrapper }, + ); Strategy::FastInstanceReuse { instance_wrapper: Rc::new(instance_wrapper), globals_snapshot, data_segments_snapshot: snapshot_data.data_segments_snapshot.clone(), heap_base, + store, } } else { Strategy::RecreateInstance(InstanceCreator { @@ -152,48 +206,63 @@ pub struct WasmtimeInstance { unsafe impl Send for WasmtimeInstance {} impl WasmInstance for WasmtimeInstance { - fn call(&self, method: InvokeMethod, data: &[u8]) -> Result> { - match &self.strategy { + fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result> { + match &mut self.strategy { Strategy::FastInstanceReuse { instance_wrapper, globals_snapshot, data_segments_snapshot, heap_base, + ref mut store, } => { - let entrypoint = instance_wrapper.resolve_entrypoint(method)?; + let entrypoint = instance_wrapper.resolve_entrypoint(method, &mut *store)?; data_segments_snapshot.apply(|offset, contents| { - instance_wrapper.write_memory_from(Pointer::new(offset), contents) + instance_wrapper.write_memory_from(&mut *store, Pointer::new(offset), contents) })?; - globals_snapshot.apply(&**instance_wrapper); + globals_snapshot + .apply(&mut InstanceGlobals { ctx: &mut *store, instance: &*instance_wrapper }); let allocator = FreeingBumpHeapAllocator::new(*heap_base); - let result = - perform_call(data, Rc::clone(&instance_wrapper), entrypoint, allocator); + let result = perform_call( + &mut *store, + data, + instance_wrapper.clone(), + entrypoint, + allocator, + ); // Signal to the OS that we are done with the linear memory and that it can be // reclaimed. - instance_wrapper.decommit(); + instance_wrapper.decommit(&store); result }, - Strategy::RecreateInstance(instance_creator) => { + Strategy::RecreateInstance(ref mut instance_creator) => { let instance_wrapper = instance_creator.instantiate()?; - let heap_base = instance_wrapper.extract_heap_base()?; - let entrypoint = instance_wrapper.resolve_entrypoint(method)?; + let heap_base = instance_wrapper.extract_heap_base(&mut instance_creator.store)?; + let entrypoint = + instance_wrapper.resolve_entrypoint(method, &mut instance_creator.store)?; let allocator = FreeingBumpHeapAllocator::new(heap_base); - perform_call(data, Rc::new(instance_wrapper), entrypoint, allocator) + perform_call( + &mut instance_creator.store, + data, + Rc::new(instance_wrapper), + entrypoint, + allocator, + ) }, } } - fn get_global_const(&self, name: &str) -> Result> { - match &self.strategy { - Strategy::FastInstanceReuse { instance_wrapper, .. } => - instance_wrapper.get_global_val(name), - Strategy::RecreateInstance(instance_creator) => - instance_creator.instantiate()?.get_global_val(name), + fn get_global_const(&mut self, name: &str) -> Result> { + match &mut self.strategy { + Strategy::FastInstanceReuse { instance_wrapper, ref mut store, .. } => + instance_wrapper.get_global_val(&mut *store, name), + Strategy::RecreateInstance(ref mut instance_creator) => instance_creator + .instantiate()? + .get_global_val(&mut instance_creator.store, name), } } @@ -204,8 +273,8 @@ impl WasmInstance for WasmtimeInstance { // associated with it. None }, - Strategy::FastInstanceReuse { instance_wrapper, .. } => - Some(instance_wrapper.base_ptr()), + Strategy::FastInstanceReuse { instance_wrapper, store, .. } => + Some(instance_wrapper.base_ptr(&store)), } } } @@ -536,40 +605,50 @@ pub fn prepare_runtime_artifact( } fn perform_call( + mut ctx: impl AsContextMut, data: &[u8], instance_wrapper: Rc, entrypoint: EntryPoint, mut allocator: FreeingBumpHeapAllocator, ) -> Result> { - let (data_ptr, data_len) = inject_input_data(&instance_wrapper, &mut allocator, data)?; + let (data_ptr, data_len) = + inject_input_data(&mut ctx, &instance_wrapper, &mut allocator, data)?; let host_state = HostState::new(allocator, instance_wrapper.clone()); - let ret = state_holder::with_initialized_state(&host_state, || -> Result<_> { - Ok(unpack_ptr_and_len(entrypoint.call(data_ptr, data_len)?)) - }); + + // Set the host state before calling into wasm. + ctx.as_context_mut().data_mut().host_state = Some(Rc::new(host_state)); + + let ret = entrypoint.call(&mut ctx, data_ptr, data_len).map(unpack_ptr_and_len); + + // Reset the host state + ctx.as_context_mut().data_mut().host_state = None; + let (output_ptr, output_len) = ret?; - let output = extract_output_data(&instance_wrapper, output_ptr, output_len)?; + let output = extract_output_data(ctx, &instance_wrapper, output_ptr, output_len)?; Ok(output) } fn inject_input_data( + mut ctx: impl AsContextMut, instance: &InstanceWrapper, allocator: &mut FreeingBumpHeapAllocator, data: &[u8], ) -> Result<(Pointer, WordSize)> { let data_len = data.len() as WordSize; - let data_ptr = instance.allocate(allocator, data_len)?; - instance.write_memory_from(data_ptr, data)?; + let data_ptr = instance.allocate(&mut ctx, allocator, data_len)?; + instance.write_memory_from(ctx, data_ptr, data)?; Ok((data_ptr, data_len)) } fn extract_output_data( + ctx: impl AsContext, instance: &InstanceWrapper, output_ptr: u32, output_len: u32, ) -> Result> { let mut output = vec![0; output_len as usize]; - instance.read_memory_into(Pointer::new(output_ptr), &mut output)?; + instance.read_memory_into(ctx, Pointer::new(output_ptr), &mut output)?; Ok(output) } diff --git a/client/executor/wasmtime/src/state_holder.rs b/client/executor/wasmtime/src/state_holder.rs deleted file mode 100644 index 0e2684cd25130..0000000000000 --- a/client/executor/wasmtime/src/state_holder.rs +++ /dev/null @@ -1,45 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::host::{HostContext, HostState}; - -scoped_tls::scoped_thread_local!(static HOST_STATE: HostState); - -/// Provide `HostState` for the runtime method call and execute the given function `f`. -/// -/// During the execution of the provided function `with_context` will be callable. -pub fn with_initialized_state(s: &HostState, f: F) -> R -where - F: FnOnce() -> R, -{ - HOST_STATE.set(s, f) -} - -/// Create a `HostContext` from the contained `HostState` and execute the given function `f`. -/// -/// This function is only callable within closure passed to `init_state`. Otherwise, the passed -/// context will be `None`. -pub fn with_context(f: F) -> R -where - F: FnOnce(Option) -> R, -{ - if !HOST_STATE.is_set() { - return f(None) - } - HOST_STATE.with(|state| f(Some(state.materialize()))) -} diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index 366352d7f5c39..2a8bcc0b01b04 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -116,7 +116,7 @@ fn test_nan_canonicalization() { builder.build() }; - let instance = runtime.new_instance().expect("failed to instantiate a runtime"); + let mut instance = runtime.new_instance().expect("failed to instantiate a runtime"); /// A NaN with canonical payload bits. const CANONICAL_NAN_BITS: u32 = 0x7fc00000; @@ -159,7 +159,7 @@ fn test_stack_depth_reaching() { builder.deterministic_stack(true); builder.build() }; - let instance = runtime.new_instance().expect("failed to instantiate a runtime"); + let mut instance = runtime.new_instance().expect("failed to instantiate a runtime"); let err = instance.call_export("test-many-locals", &[]).unwrap_err(); @@ -180,7 +180,7 @@ fn test_max_memory_pages() { builder.max_memory_pages(max_memory_pages); builder.build() }; - let instance = runtime.new_instance()?; + let mut instance = runtime.new_instance()?; let _ = instance.call_export("main", &[])?; Ok(()) } diff --git a/primitives/maybe-compressed-blob/Cargo.toml b/primitives/maybe-compressed-blob/Cargo.toml index 8d47c89ea8ebe..6994ccf5486ba 100644 --- a/primitives/maybe-compressed-blob/Cargo.toml +++ b/primitives/maybe-compressed-blob/Cargo.toml @@ -11,4 +11,4 @@ documentation = "https://docs.rs/sp-maybe-compressed-blob" readme = "README.md" [dependencies] -zstd = { version = "0.6.0", default-features = false } +zstd = { version = "0.9.0", default-features = false } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index a63d1312044df..e444ae223a742 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -35,7 +35,7 @@ tracing = { version = "0.1.22", optional = true } hex-literal = "0.3.1" sp-runtime = { version = "4.0.0-dev", path = "../runtime" } pretty_assertions = "0.6.1" -rand = { version = "0.7.2" } +rand = "0.7.2" [features] default = ["std"] From 4ecbb1f724801d142d1c0cd30ac30f4a62dca364 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Wed, 29 Sep 2021 21:03:09 +0800 Subject: [PATCH 0046/1472] Return `target_hash` for finality_target instead of an Option (#9867) * . cargo +nightly fmt --all * Fix test * Simplify test * They are already imported * Needless clone() --- client/consensus/common/src/longest_chain.rs | 3 +- client/finality-grandpa/src/environment.rs | 6 +- client/finality-grandpa/src/import.rs | 4 +- client/service/test/src/client/mod.rs | 459 ++++-------------- .../consensus/common/src/select_chain.rs | 4 +- 5 files changed, 97 insertions(+), 379 deletions(-) diff --git a/client/consensus/common/src/longest_chain.rs b/client/consensus/common/src/longest_chain.rs index b1f7f94f9eb28..7ec91a5ad87e9 100644 --- a/client/consensus/common/src/longest_chain.rs +++ b/client/consensus/common/src/longest_chain.rs @@ -91,11 +91,12 @@ where &self, target_hash: Block::Hash, maybe_max_number: Option>, - ) -> Result, ConsensusError> { + ) -> Result { let import_lock = self.backend.get_import_lock(); self.backend .blockchain() .best_containing(target_hash, maybe_max_number, import_lock) + .map(|maybe_hash| maybe_hash.unwrap_or(target_hash)) .map_err(|e| ConsensusError::ChainLookup(e.to_string()).into()) } } diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index f27a530ed2f40..c79698902e975 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -1165,7 +1165,7 @@ where debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit); let result = match select_chain.finality_target(block, None).await { - Ok(Some(best_hash)) => { + Ok(best_hash) => { let best_header = client .header(BlockId::Hash(best_hash))? .expect("Header known to exist after `finality_target` call; qed"); @@ -1223,10 +1223,6 @@ where }) .or_else(|| Some((target_header.hash(), *target_header.number()))) }, - Ok(None) => { - debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find target block", block); - None - }, Err(e) => { debug!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e); None diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index f663bfe94afdf..1c4d1b4e97b88 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -118,10 +118,10 @@ where ) .await } else { - Ok(Some(pending_change.canon_hash)) + Ok(pending_change.canon_hash) }; - if let Ok(Some(hash)) = effective_block_hash { + if let Ok(hash) = effective_block_hash { if let Ok(Some(header)) = self.inner.header(BlockId::Hash(hash)) { if *header.number() == pending_change.effective_number() { out.push((header.hash(), *header.number())); diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 295e941f7ceb1..d82a839936d7d 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -481,25 +481,7 @@ fn best_containing_with_genesis_block() { assert_eq!( genesis_hash.clone(), - block_on(longest_chain_select.finality_target(genesis_hash.clone(), None)) - .unwrap() - .unwrap(), - ); -} - -#[test] -fn best_containing_with_hash_not_found() { - // block tree: - // G - - let (client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain(); - - let uninserted_block = client.new_block(Default::default()).unwrap().build().unwrap().block; - - assert_eq!( - None, - block_on(longest_chain_select.finality_target(uninserted_block.hash().clone(), None)) - .unwrap(), + block_on(longest_chain_select.finality_target(genesis_hash.clone(), None)).unwrap(), ); } @@ -675,22 +657,10 @@ fn best_containing_on_longest_chain_with_single_chain_3_blocks() { assert_eq!( a2.hash(), - block_on(longest_chain_select.finality_target(genesis_hash, None)) - .unwrap() - .unwrap() - ); - assert_eq!( - a2.hash(), - block_on(longest_chain_select.finality_target(a1.hash(), None)) - .unwrap() - .unwrap() - ); - assert_eq!( - a2.hash(), - block_on(longest_chain_select.finality_target(a2.hash(), None)) - .unwrap() - .unwrap() + block_on(longest_chain_select.finality_target(genesis_hash, None)).unwrap() ); + assert_eq!(a2.hash(), block_on(longest_chain_select.finality_target(a1.hash(), None)).unwrap()); + assert_eq!(a2.hash(), block_on(longest_chain_select.finality_target(a2.hash(), None)).unwrap()); } #[test] @@ -819,343 +789,101 @@ fn best_containing_on_longest_chain_with_multiple_forks() { assert!(leaves.contains(&d2.hash())); assert_eq!(leaves.len(), 4); + let finality_target = |target_hash, number| { + block_on(longest_chain_select.finality_target(target_hash, number)).unwrap() + }; + // search without restriction - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(genesis_hash, None)) - .unwrap() - .unwrap() - ); - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(a1.hash(), None)) - .unwrap() - .unwrap() - ); - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(a2.hash(), None)) - .unwrap() - .unwrap() - ); - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(a3.hash(), None)) - .unwrap() - .unwrap() - ); - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(a4.hash(), None)) - .unwrap() - .unwrap() - ); - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(a5.hash(), None)) - .unwrap() - .unwrap() - ); - assert_eq!( - b4.hash(), - block_on(longest_chain_select.finality_target(b2.hash(), None)) - .unwrap() - .unwrap() - ); - assert_eq!( - b4.hash(), - block_on(longest_chain_select.finality_target(b3.hash(), None)) - .unwrap() - .unwrap() - ); - assert_eq!( - b4.hash(), - block_on(longest_chain_select.finality_target(b4.hash(), None)) - .unwrap() - .unwrap() - ); - assert_eq!( - c3.hash(), - block_on(longest_chain_select.finality_target(c3.hash(), None)) - .unwrap() - .unwrap() - ); - assert_eq!( - d2.hash(), - block_on(longest_chain_select.finality_target(d2.hash(), None)) - .unwrap() - .unwrap() - ); + assert_eq!(a5.hash(), finality_target(genesis_hash, None)); + assert_eq!(a5.hash(), finality_target(a1.hash(), None)); + assert_eq!(a5.hash(), finality_target(a2.hash(), None)); + assert_eq!(a5.hash(), finality_target(a3.hash(), None)); + assert_eq!(a5.hash(), finality_target(a4.hash(), None)); + assert_eq!(a5.hash(), finality_target(a5.hash(), None)); + assert_eq!(b4.hash(), finality_target(b2.hash(), None)); + assert_eq!(b4.hash(), finality_target(b3.hash(), None)); + assert_eq!(b4.hash(), finality_target(b4.hash(), None)); + assert_eq!(c3.hash(), finality_target(c3.hash(), None)); + assert_eq!(d2.hash(), finality_target(d2.hash(), None)); // search only blocks with number <= 5. equivalent to without restriction for this scenario - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(genesis_hash, Some(5))) - .unwrap() - .unwrap() - ); - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(a1.hash(), Some(5))) - .unwrap() - .unwrap() - ); - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(a2.hash(), Some(5))) - .unwrap() - .unwrap() - ); - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(a3.hash(), Some(5))) - .unwrap() - .unwrap() - ); - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(a4.hash(), Some(5))) - .unwrap() - .unwrap() - ); - assert_eq!( - a5.hash(), - block_on(longest_chain_select.finality_target(a5.hash(), Some(5))) - .unwrap() - .unwrap() - ); - assert_eq!( - b4.hash(), - block_on(longest_chain_select.finality_target(b2.hash(), Some(5))) - .unwrap() - .unwrap() - ); - assert_eq!( - b4.hash(), - block_on(longest_chain_select.finality_target(b3.hash(), Some(5))) - .unwrap() - .unwrap() - ); - assert_eq!( - b4.hash(), - block_on(longest_chain_select.finality_target(b4.hash(), Some(5))) - .unwrap() - .unwrap() - ); - assert_eq!( - c3.hash(), - block_on(longest_chain_select.finality_target(c3.hash(), Some(5))) - .unwrap() - .unwrap() - ); - assert_eq!( - d2.hash(), - block_on(longest_chain_select.finality_target(d2.hash(), Some(5))) - .unwrap() - .unwrap() - ); + assert_eq!(a5.hash(), finality_target(genesis_hash, Some(5))); + assert_eq!(a5.hash(), finality_target(a1.hash(), Some(5))); + assert_eq!(a5.hash(), finality_target(a2.hash(), Some(5))); + assert_eq!(a5.hash(), finality_target(a3.hash(), Some(5))); + assert_eq!(a5.hash(), finality_target(a4.hash(), Some(5))); + assert_eq!(a5.hash(), finality_target(a5.hash(), Some(5))); + assert_eq!(b4.hash(), finality_target(b2.hash(), Some(5))); + assert_eq!(b4.hash(), finality_target(b3.hash(), Some(5))); + assert_eq!(b4.hash(), finality_target(b4.hash(), Some(5))); + assert_eq!(c3.hash(), finality_target(c3.hash(), Some(5))); + assert_eq!(d2.hash(), finality_target(d2.hash(), Some(5))); // search only blocks with number <= 4 - assert_eq!( - a4.hash(), - block_on(longest_chain_select.finality_target(genesis_hash, Some(4))) - .unwrap() - .unwrap() - ); - assert_eq!( - a4.hash(), - block_on(longest_chain_select.finality_target(a1.hash(), Some(4))) - .unwrap() - .unwrap() - ); - assert_eq!( - a4.hash(), - block_on(longest_chain_select.finality_target(a2.hash(), Some(4))) - .unwrap() - .unwrap() - ); - assert_eq!( - a4.hash(), - block_on(longest_chain_select.finality_target(a3.hash(), Some(4))) - .unwrap() - .unwrap() - ); - assert_eq!( - a4.hash(), - block_on(longest_chain_select.finality_target(a4.hash(), Some(4))) - .unwrap() - .unwrap() - ); - assert_eq!(None, block_on(longest_chain_select.finality_target(a5.hash(), Some(4))).unwrap()); - assert_eq!( - b4.hash(), - block_on(longest_chain_select.finality_target(b2.hash(), Some(4))) - .unwrap() - .unwrap() - ); - assert_eq!( - b4.hash(), - block_on(longest_chain_select.finality_target(b3.hash(), Some(4))) - .unwrap() - .unwrap() - ); - assert_eq!( - b4.hash(), - block_on(longest_chain_select.finality_target(b4.hash(), Some(4))) - .unwrap() - .unwrap() - ); - assert_eq!( - c3.hash(), - block_on(longest_chain_select.finality_target(c3.hash(), Some(4))) - .unwrap() - .unwrap() - ); - assert_eq!( - d2.hash(), - block_on(longest_chain_select.finality_target(d2.hash(), Some(4))) - .unwrap() - .unwrap() - ); + assert_eq!(a4.hash(), finality_target(genesis_hash, Some(4))); + assert_eq!(a4.hash(), finality_target(a1.hash(), Some(4))); + assert_eq!(a4.hash(), finality_target(a2.hash(), Some(4))); + assert_eq!(a4.hash(), finality_target(a3.hash(), Some(4))); + assert_eq!(a4.hash(), finality_target(a4.hash(), Some(4))); + assert_eq!(a5.hash(), finality_target(a5.hash(), Some(4))); + assert_eq!(b4.hash(), finality_target(b2.hash(), Some(4))); + assert_eq!(b4.hash(), finality_target(b3.hash(), Some(4))); + assert_eq!(b4.hash(), finality_target(b4.hash(), Some(4))); + assert_eq!(c3.hash(), finality_target(c3.hash(), Some(4))); + assert_eq!(d2.hash(), finality_target(d2.hash(), Some(4))); // search only blocks with number <= 3 - assert_eq!( - a3.hash(), - block_on(longest_chain_select.finality_target(genesis_hash, Some(3))) - .unwrap() - .unwrap() - ); - assert_eq!( - a3.hash(), - block_on(longest_chain_select.finality_target(a1.hash(), Some(3))) - .unwrap() - .unwrap() - ); - assert_eq!( - a3.hash(), - block_on(longest_chain_select.finality_target(a2.hash(), Some(3))) - .unwrap() - .unwrap() - ); - assert_eq!( - a3.hash(), - block_on(longest_chain_select.finality_target(a3.hash(), Some(3))) - .unwrap() - .unwrap() - ); - assert_eq!(None, block_on(longest_chain_select.finality_target(a4.hash(), Some(3))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(a5.hash(), Some(3))).unwrap()); - assert_eq!( - b3.hash(), - block_on(longest_chain_select.finality_target(b2.hash(), Some(3))) - .unwrap() - .unwrap() - ); - assert_eq!( - b3.hash(), - block_on(longest_chain_select.finality_target(b3.hash(), Some(3))) - .unwrap() - .unwrap() - ); - assert_eq!(None, block_on(longest_chain_select.finality_target(b4.hash(), Some(3))).unwrap()); - assert_eq!( - c3.hash(), - block_on(longest_chain_select.finality_target(c3.hash(), Some(3))) - .unwrap() - .unwrap() - ); - assert_eq!( - d2.hash(), - block_on(longest_chain_select.finality_target(d2.hash(), Some(3))) - .unwrap() - .unwrap() - ); + assert_eq!(a3.hash(), finality_target(genesis_hash, Some(3))); + assert_eq!(a3.hash(), finality_target(a1.hash(), Some(3))); + assert_eq!(a3.hash(), finality_target(a2.hash(), Some(3))); + assert_eq!(a3.hash(), finality_target(a3.hash(), Some(3))); + assert_eq!(a4.hash(), finality_target(a4.hash(), Some(3))); + assert_eq!(a5.hash(), finality_target(a5.hash(), Some(3))); + assert_eq!(b3.hash(), finality_target(b2.hash(), Some(3))); + assert_eq!(b3.hash(), finality_target(b3.hash(), Some(3))); + assert_eq!(b4.hash(), finality_target(b4.hash(), Some(3))); + assert_eq!(c3.hash(), finality_target(c3.hash(), Some(3))); + assert_eq!(d2.hash(), finality_target(d2.hash(), Some(3))); // search only blocks with number <= 2 - assert_eq!( - a2.hash(), - block_on(longest_chain_select.finality_target(genesis_hash, Some(2))) - .unwrap() - .unwrap() - ); - assert_eq!( - a2.hash(), - block_on(longest_chain_select.finality_target(a1.hash(), Some(2))) - .unwrap() - .unwrap() - ); - assert_eq!( - a2.hash(), - block_on(longest_chain_select.finality_target(a2.hash(), Some(2))) - .unwrap() - .unwrap() - ); - assert_eq!(None, block_on(longest_chain_select.finality_target(a3.hash(), Some(2))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(a4.hash(), Some(2))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(a5.hash(), Some(2))).unwrap()); - assert_eq!( - b2.hash(), - block_on(longest_chain_select.finality_target(b2.hash(), Some(2))) - .unwrap() - .unwrap() - ); - assert_eq!(None, block_on(longest_chain_select.finality_target(b3.hash(), Some(2))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(b4.hash(), Some(2))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(c3.hash(), Some(2))).unwrap()); - assert_eq!( - d2.hash(), - block_on(longest_chain_select.finality_target(d2.hash(), Some(2))) - .unwrap() - .unwrap() - ); + assert_eq!(a2.hash(), finality_target(genesis_hash, Some(2))); + assert_eq!(a2.hash(), finality_target(a1.hash(), Some(2))); + assert_eq!(a2.hash(), finality_target(a2.hash(), Some(2))); + assert_eq!(a3.hash(), finality_target(a3.hash(), Some(2))); + assert_eq!(a4.hash(), finality_target(a4.hash(), Some(2))); + assert_eq!(a5.hash(), finality_target(a5.hash(), Some(2))); + assert_eq!(b2.hash(), finality_target(b2.hash(), Some(2))); + assert_eq!(b3.hash(), finality_target(b3.hash(), Some(2))); + assert_eq!(b4.hash(), finality_target(b4.hash(), Some(2))); + assert_eq!(c3.hash(), finality_target(c3.hash(), Some(2))); + assert_eq!(d2.hash(), finality_target(d2.hash(), Some(2))); // search only blocks with number <= 1 - assert_eq!( - a1.hash(), - block_on(longest_chain_select.finality_target(genesis_hash, Some(1))) - .unwrap() - .unwrap() - ); - assert_eq!( - a1.hash(), - block_on(longest_chain_select.finality_target(a1.hash(), Some(1))) - .unwrap() - .unwrap() - ); - assert_eq!(None, block_on(longest_chain_select.finality_target(a2.hash(), Some(1))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(a3.hash(), Some(1))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(a4.hash(), Some(1))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(a5.hash(), Some(1))).unwrap()); - - assert_eq!(None, block_on(longest_chain_select.finality_target(b2.hash(), Some(1))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(b3.hash(), Some(1))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(b4.hash(), Some(1))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(c3.hash(), Some(1))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(d2.hash(), Some(1))).unwrap()); + assert_eq!(a1.hash(), finality_target(genesis_hash, Some(1))); + assert_eq!(a1.hash(), finality_target(a1.hash(), Some(1))); + assert_eq!(a2.hash(), finality_target(a2.hash(), Some(1))); + assert_eq!(a3.hash(), finality_target(a3.hash(), Some(1))); + assert_eq!(a4.hash(), finality_target(a4.hash(), Some(1))); + assert_eq!(a5.hash(), finality_target(a5.hash(), Some(1))); + + assert_eq!(b2.hash(), finality_target(b2.hash(), Some(1))); + assert_eq!(b3.hash(), finality_target(b3.hash(), Some(1))); + assert_eq!(b4.hash(), finality_target(b4.hash(), Some(1))); + assert_eq!(c3.hash(), finality_target(c3.hash(), Some(1))); + assert_eq!(d2.hash(), finality_target(d2.hash(), Some(1))); // search only blocks with number <= 0 - assert_eq!( - genesis_hash, - block_on(longest_chain_select.finality_target(genesis_hash, Some(0))) - .unwrap() - .unwrap() - ); - assert_eq!(None, block_on(longest_chain_select.finality_target(a1.hash(), Some(0))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(a2.hash(), Some(0))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(a3.hash(), Some(0))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(a4.hash(), Some(0))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(a5.hash(), Some(0))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(b2.hash(), Some(0))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(b3.hash(), Some(0))).unwrap()); - assert_eq!(None, block_on(longest_chain_select.finality_target(b4.hash(), Some(0))).unwrap()); - assert_eq!( - None, - block_on(longest_chain_select.finality_target(c3.hash().clone(), Some(0))).unwrap(), - ); - assert_eq!( - None, - block_on(longest_chain_select.finality_target(d2.hash().clone(), Some(0))).unwrap(), - ); + assert_eq!(genesis_hash, finality_target(genesis_hash, Some(0))); + assert_eq!(a1.hash(), finality_target(a1.hash(), Some(0))); + assert_eq!(a2.hash(), finality_target(a2.hash(), Some(0))); + assert_eq!(a3.hash(), finality_target(a3.hash(), Some(0))); + assert_eq!(a4.hash(), finality_target(a4.hash(), Some(0))); + assert_eq!(a5.hash(), finality_target(a5.hash(), Some(0))); + assert_eq!(b2.hash(), finality_target(b2.hash(), Some(0))); + assert_eq!(b3.hash(), finality_target(b3.hash(), Some(0))); + assert_eq!(b4.hash(), finality_target(b4.hash(), Some(0))); + assert_eq!(c3.hash(), finality_target(c3.hash(), Some(0))); + assert_eq!(d2.hash(), finality_target(d2.hash(), Some(0))); } #[test] @@ -1177,9 +905,7 @@ fn best_containing_on_longest_chain_with_max_depth_higher_than_best() { assert_eq!( a2.hash(), - block_on(longest_chain_select.finality_target(genesis_hash, Some(10))) - .unwrap() - .unwrap(), + block_on(longest_chain_select.finality_target(genesis_hash, Some(10))).unwrap(), ); } @@ -2085,12 +1811,7 @@ fn cleans_up_closed_notification_sinks_on_block_import() { // NOTE: we need to build the client here instead of using the client // provided by test_runtime_client otherwise we can't access the private // `import_notification_sinks` and `finality_notification_sinks` fields. - let mut client = new_in_mem::< - _, - substrate_test_runtime_client::runtime::Block, - _, - substrate_test_runtime_client::runtime::RuntimeApi, - >( + let mut client = new_in_mem::<_, Block, _, RuntimeApi>( substrate_test_runtime_client::new_native_executor(), &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), None, @@ -2108,8 +1829,8 @@ fn cleans_up_closed_notification_sinks_on_block_import() { in_mem::Backend, sc_executor::NativeElseWasmExecutor, >, - substrate_test_runtime_client::runtime::Block, - substrate_test_runtime_client::runtime::RuntimeApi, + Block, + RuntimeApi, >; let import_notif1 = client.import_notification_stream(); diff --git a/primitives/consensus/common/src/select_chain.rs b/primitives/consensus/common/src/select_chain.rs index 5408fc86b7bd4..fd8b06ecf8abb 100644 --- a/primitives/consensus/common/src/select_chain.rs +++ b/primitives/consensus/common/src/select_chain.rs @@ -50,7 +50,7 @@ pub trait SelectChain: Sync + Send + Clone { &self, target_hash: ::Hash, _maybe_max_number: Option>, - ) -> Result::Hash>, Error> { - Ok(Some(target_hash)) + ) -> Result<::Hash, Error> { + Ok(target_hash) } } From 0d44d83e619f6c45597c11b37f3e36e942d22cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lo=C3=AFs?= Date: Wed, 29 Sep 2021 22:10:12 +0200 Subject: [PATCH 0047/1472] add feature wasmtime-jitdump (#9871) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add feature wasmtime-jitdump * remove unwrap * always enable wasmtime/jitdump feature * env WASMTIME_PROFILING_STRATEGY: retun an error for unknown value * Add doc for env var WASMTIME_PROFILING_STRATEGY * Update client/executor/wasmtime/Cargo.toml Co-authored-by: Sergei Shulepov * warning instead of error * Update client/executor/wasmtime/src/runtime.rs Co-authored-by: Bastian Köcher * update doc: unknown value cause warning instead of error * log warning only once * static right next to the usage Co-authored-by: Sergei Shulepov Co-authored-by: Bastian Köcher --- Cargo.lock | 23 +++++++++++++++++++++++ client/executor/wasmtime/Cargo.toml | 6 +++++- client/executor/wasmtime/src/lib.rs | 12 +++++++++++- client/executor/wasmtime/src/runtime.rs | 22 +++++++++++++++++++++- 4 files changed, 60 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cdde834261870..0e3f3399dbf6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8691,6 +8691,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scroll" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sct" version = "0.6.0" @@ -11609,8 +11629,11 @@ checksum = "21486cfb5255c2069666c1f116f9e949d4e35c9a494f11112fa407879e42198d" dependencies = [ "anyhow", "cfg-if 1.0.0", + "gimli 0.25.0", "lazy_static", "libc", + "object 0.26.0", + "scroll", "serde", "target-lexicon 0.12.0", "wasmtime-environ", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index edf1747524263..c122b3ab0e696 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -23,7 +23,11 @@ sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-in sp-runtime-interface = { version = "4.0.0-dev", path = "../../../primitives/runtime-interface" } sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } sc-allocator = { version = "4.0.0-dev", path = "../../allocator" } -wasmtime = { version = "0.29.0", default-features = false, features = ["cache", "parallel-compilation"] } +wasmtime = { version = "0.29.0", default-features = false, features = [ + "cache", + "jitdump", + "parallel-compilation", +] } [dev-dependencies] sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } diff --git a/client/executor/wasmtime/src/lib.rs b/client/executor/wasmtime/src/lib.rs index 8d7f93fecb307..e0d6a262afda9 100644 --- a/client/executor/wasmtime/src/lib.rs +++ b/client/executor/wasmtime/src/lib.rs @@ -16,7 +16,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -/// ! Defines a `WasmRuntime` that uses the Wasmtime JIT to execute. +//! Defines a `WasmRuntime` that uses the Wasmtime JIT to execute. +//! +//! You can choose a profiling strategy at runtime with +//! environment variable `WASMTIME_PROFILING_STRATEGY`: +//! +//! | `WASMTIME_PROFILING_STRATEGY` | Effect | +//! |-------------|-------------------------| +//! | undefined | No profiling | +//! | `"jitdump"` | jitdump profiling | +//! | other value | No profiling (warning) | + mod host; mod imports; mod instance_wrapper; diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 006f102926ecb..a62356357b1f4 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -38,7 +38,10 @@ use sp_wasm_interface::{Function, Pointer, Value, WordSize}; use std::{ path::{Path, PathBuf}, rc::Rc, - sync::Arc, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, }; use wasmtime::{AsContext, AsContextMut, Engine, StoreLimits}; @@ -322,6 +325,23 @@ fn common_config(semantics: &Semantics) -> std::result::Result wasmtime::ProfilingStrategy::JitDump, + None => wasmtime::ProfilingStrategy::None, + Some(_) => { + // Remember if we have already logged a warning due to an unknown profiling strategy. + static UNKNOWN_PROFILING_STRATEGY: AtomicBool = AtomicBool::new(false); + // Make sure that the warning will not be relogged regularly. + if !UNKNOWN_PROFILING_STRATEGY.swap(true, Ordering::Relaxed) { + log::warn!("WASMTIME_PROFILING_STRATEGY is set to unknown value, ignored."); + } + wasmtime::ProfilingStrategy::None + }, + }; + config + .profiler(profiler) + .map_err(|e| WasmError::Instantiation(format!("fail to set profiler: {}", e)))?; + if let Some(DeterministicStackLimit { native_stack_max, .. }) = semantics.deterministic_stack_limit { From 1e28e61daf6c7687bb1899adfb1ea88ce9ab166d Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Wed, 29 Sep 2021 21:54:45 -0600 Subject: [PATCH 0048/1472] subkey readme update on install (#9900) Instructions are more detailed on devhub, ported to the README. --- bin/utils/subkey/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bin/utils/subkey/README.md b/bin/utils/subkey/README.md index fbb486247a770..2494bff3bc9ab 100644 --- a/bin/utils/subkey/README.md +++ b/bin/utils/subkey/README.md @@ -18,6 +18,19 @@ If you save any output of `subkey` into a file, make sure to apply proper permis The following guide explains *some* of the `subkey` commands. For the full list and the most up to date documentation, make sure to check the integrated help with `subkey --help`. +### Install with Cargo + +You will need to have the Substrate build dependencies to install Subkey. Use the following two commands to install the dependencies and Subkey, respectively: + +Command: + +```bash +# Use the `--fast` flag to get the dependencies without needing to install the Substrate and Subkey binary +curl https://getsubstrate.io -sSf | bash -s -- --fast +# Install only `subkey`, at a specific version of the this subkey crate +cargo install --force subkey --git https://github.com/paritytech/substrate --version --locked +``` + ### Generate a random account Generating a new key is as simple as running: From 0bc873d571cacd96959f652b27e6f5735720e305 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 30 Sep 2021 09:12:25 +0100 Subject: [PATCH 0049/1472] contracts: Add event field names (#9896) * Add struct variant fields to contract Event * Update comments and usages * Fmt --- frame/contracts/src/exec.rs | 25 ++++++++----- frame/contracts/src/lib.rs | 49 ++++++++++++-------------- frame/contracts/src/tests.rs | 24 ++++++++----- frame/contracts/src/wasm/code_cache.rs | 4 +-- 4 files changed, 57 insertions(+), 45 deletions(-) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index cc468466c2922..7fa0b0b274449 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -660,7 +660,10 @@ where } // Deposit an instantiation event. - deposit_event::(vec![], Event::Instantiated(self.caller().clone(), account_id)); + deposit_event::( + vec![], + Event::Instantiated { deployer: self.caller().clone(), contract: account_id }, + ); } Ok(output) @@ -942,10 +945,10 @@ where )?; ContractInfoOf::::remove(&frame.account_id); E::remove_user(info.code_hash, &mut frame.nested_meter)?; - Contracts::::deposit_event(Event::Terminated( - frame.account_id.clone(), - beneficiary.clone(), - )); + Contracts::::deposit_event(Event::Terminated { + contract: frame.account_id.clone(), + beneficiary: beneficiary.clone(), + }); Ok(()) } @@ -997,7 +1000,7 @@ where fn deposit_event(&mut self, topics: Vec, data: Vec) { deposit_event::( topics, - Event::ContractEmitted(self.top_frame().account_id.clone(), data), + Event::ContractEmitted { contract: self.top_frame().account_id.clone(), data }, ); } @@ -1662,7 +1665,10 @@ mod tests { Storage::::code_hash(&instantiated_contract_address).unwrap(), dummy_ch ); - assert_eq!(&events(), &[Event::Instantiated(ALICE, instantiated_contract_address)]); + assert_eq!( + &events(), + &[Event::Instantiated { deployer: ALICE, contract: instantiated_contract_address }] + ); }); } @@ -1751,7 +1757,10 @@ mod tests { Storage::::code_hash(&instantiated_contract_address).unwrap(), dummy_ch ); - assert_eq!(&events(), &[Event::Instantiated(BOB, instantiated_contract_address)]); + assert_eq!( + &events(), + &[Event::Instantiated { deployer: BOB, contract: instantiated_contract_address }] + ); }); } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 0d7e4cbf56474..62b74b9b7b954 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -369,49 +369,44 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Contract deployed by address at the specified address. \[deployer, contract\] - Instantiated(T::AccountId, T::AccountId), + /// Contract deployed by address at the specified address. + Instantiated { deployer: T::AccountId, contract: T::AccountId }, /// Contract has been removed. - /// \[contract, beneficiary\] - /// - /// # Params - /// - /// - `contract`: The contract that was terminated. - /// - `beneficiary`: The account that received the contracts remaining balance. /// /// # Note /// /// The only way for a contract to be removed and emitting this event is by calling /// `seal_terminate`. - Terminated(T::AccountId, T::AccountId), + Terminated { + /// The contract that was terminated. + contract: T::AccountId, + /// The account that received the contracts remaining balance + beneficiary: T::AccountId, + }, - /// Code with the specified hash has been stored. \[code_hash\] - CodeStored(T::Hash), + /// Code with the specified hash has been stored. + CodeStored { code_hash: T::Hash }, /// Triggered when the current schedule is updated. - /// \[version\] - /// - /// # Params - /// - /// - `version`: The version of the newly set schedule. - ScheduleUpdated(u32), + ScheduleUpdated { + /// The version of the newly set schedule. + version: u32, + }, /// A custom event emitted by the contract. - /// \[contract, data\] - /// - /// # Params - /// - /// - `contract`: The contract that emitted the event. - /// - `data`: Data supplied by the contract. Metadata generated during contract compilation - /// is needed to decode it. - ContractEmitted(T::AccountId, Vec), + ContractEmitted { + /// The contract that emitted the event. + contract: T::AccountId, + /// Data supplied by the contract. Metadata generated during contract compilation + /// is needed to decode it. + data: Vec, + }, /// A code with the specified hash was removed. - /// \[code_hash\] /// /// This happens when the last contract that uses this code hash was removed. - CodeRemoved(T::Hash), + CodeRemoved { code_hash: T::Hash }, } #[pallet::error] diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index f5b95c192c42e..b2141ca18b0b1 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -478,20 +478,25 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored(code_hash.into())), + event: Event::Contracts(crate::Event::CodeStored { + code_hash: code_hash.into() + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::ContractEmitted( - addr.clone(), - vec![1, 2, 3, 4] - )), + event: Event::Contracts(crate::Event::ContractEmitted { + contract: addr.clone(), + data: vec![1, 2, 3, 4] + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Instantiated(ALICE, addr.clone())), + event: Event::Contracts(crate::Event::Instantiated { + deployer: ALICE, + contract: addr.clone() + }), topics: vec![], }, ] @@ -764,12 +769,15 @@ fn self_destruct_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeRemoved(code_hash)), + event: Event::Contracts(crate::Event::CodeRemoved { code_hash }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Terminated(addr.clone(), DJANGO)), + event: Event::Contracts(crate::Event::Terminated { + contract: addr.clone(), + beneficiary: DJANGO + }), topics: vec![], }, ], diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 08a7449683ed6..afb68d4d81179 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -59,7 +59,7 @@ where Some(module) => increment_64(&mut module.refcount), None => { *existing = Some(prefab_module); - Contracts::::deposit_event(Event::CodeStored(code_hash)) + Contracts::::deposit_event(Event::CodeStored { code_hash }) }, }); } @@ -170,7 +170,7 @@ where T::AccountId: UncheckedFrom + AsRef<[u8]>, { >::remove(code_hash); - Contracts::::deposit_event(Event::CodeRemoved(code_hash)) + Contracts::::deposit_event(Event::CodeRemoved { code_hash }) } /// Increment the refcount panicking if it should ever overflow (which will not happen). From fb443761341790f1c6a2aca41088bef2daa33258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 30 Sep 2021 14:58:28 +0200 Subject: [PATCH 0050/1472] Fix basic authorship flaky test (#9906) The test is flaky because sometimes we hit the 9 seconds deadline when the CI was probably on high load. To "solve" this we just use an huge deadline that should never be triggered. The deadline isn't required anyway. --- client/basic-authorship/src/basic_authorship.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 144a3ab6850ff..e38bb11688f8b 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -718,7 +718,7 @@ mod tests { ); // when - let deadline = time::Duration::from_secs(9); + let deadline = time::Duration::from_secs(900); let block = block_on(proposer.propose(Default::default(), Default::default(), deadline, None)) .map(|r| r.block) From e6b015062e60cc713ed5b0158d8c540c231852dc Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Thu, 30 Sep 2021 21:22:54 +0800 Subject: [PATCH 0051/1472] Fix democracy on-initialize weight (#9890) * fix democracy on-initialize weight * fix tests * add base weight on LaunchPeriod * fix fmt check * trigger GitHub actions * trigger GitHub actions * update weights --- frame/democracy/src/benchmarking.rs | 34 ++++- frame/democracy/src/lib.rs | 25 +-- frame/democracy/src/weights.rs | 227 +++++++++++++++------------- 3 files changed, 173 insertions(+), 113 deletions(-) diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index a00e6f4686fd3..63d409dac25a7 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -422,7 +422,39 @@ benchmarks! { assert_eq!(Democracy::::referendum_count(), r, "referenda not created"); assert_eq!(Democracy::::lowest_unbaked(), 0, "invalid referenda init"); - }: { Democracy::::on_initialize(0u32.into()) } + }: { Democracy::::on_initialize(1u32.into()) } + verify { + // All should be on going + for i in 0 .. r { + if let Some(value) = ReferendumInfoOf::::get(i) { + match value { + ReferendumInfo::Finished { .. } => return Err("Referendum has been finished".into()), + ReferendumInfo::Ongoing(_) => (), + } + } + } + } + + on_initialize_base_with_launch_period { + let r in 1 .. MAX_REFERENDUMS; + + for i in 0..r { + add_referendum::(i)?; + } + + for (key, mut info) in ReferendumInfoOf::::iter() { + if let ReferendumInfo::Ongoing(ref mut status) = info { + status.end += 100u32.into(); + } + ReferendumInfoOf::::insert(key, info); + } + + assert_eq!(Democracy::::referendum_count(), r, "referenda not created"); + assert_eq!(Democracy::::lowest_unbaked(), 0, "invalid referenda init"); + + let block_number = T::LaunchPeriod::get(); + + }: { Democracy::::on_initialize(block_number) } verify { // All should be on going for i in 0 .. r { diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 8bc6921c4f8ad..24f823a17e10d 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1726,7 +1726,8 @@ impl Pallet { /// /// /// # - /// If a referendum is launched or maturing, this will take full block weight. Otherwise: + /// If a referendum is launched or maturing, this will take full block weight if queue is not + /// empty. Otherwise: /// - Complexity: `O(R)` where `R` is the number of unbaked referenda. /// - Db reads: `LastTabledWasExternal`, `NextExternal`, `PublicProps`, `account`, /// `ReferendumCount`, `LowestUnbaked` @@ -1737,18 +1738,24 @@ impl Pallet { let max_block_weight = T::BlockWeights::get().max_block; let mut weight = 0; + let next = Self::lowest_unbaked(); + let last = Self::referendum_count(); + let r = last.saturating_sub(next); + // pick out another public referendum if it's time. if (now % T::LaunchPeriod::get()).is_zero() { - // Errors come from the queue being empty. we don't really care about that, and even if - // we did, there is nothing we can do here. - let _ = Self::launch_next(now); - weight = max_block_weight; + // Errors come from the queue being empty. If the queue is not empty, it will take + // full block weight. + if Self::launch_next(now).is_ok() { + weight = max_block_weight; + } else { + weight = + weight.saturating_add(T::WeightInfo::on_initialize_base_with_launch_period(r)); + } + } else { + weight = weight.saturating_add(T::WeightInfo::on_initialize_base(r)); } - let next = Self::lowest_unbaked(); - let last = Self::referendum_count(); - let r = last.saturating_sub(next); - weight = weight.saturating_add(T::WeightInfo::on_initialize_base(r)); // tally up votes for any expiring referenda. for (index, info) in Self::maturing_referenda_at_inner(now, next..last).into_iter() { let approved = Self::bake_referendum(now, index, info)?; diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index e3f22f4fc0ab3..638852d3c7e19 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-09-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -60,6 +60,7 @@ pub trait WeightInfo { fn cancel_referendum() -> Weight; fn cancel_queued(r: u32, ) -> Weight; fn on_initialize_base(r: u32, ) -> Weight; + fn on_initialize_base_with_launch_period(r: u32, ) -> Weight; fn delegate(r: u32, ) -> Weight; fn undelegate(r: u32, ) -> Weight; fn clear_public_proposals() -> Weight; @@ -80,15 +81,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (65_665_000 as Weight) + (67_388_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (40_003_000 as Weight) - // Standard Error: 1_000 - .saturating_add((180_000 as Weight).saturating_mul(s as Weight)) + (41_157_000 as Weight) + // Standard Error: 0 + .saturating_add((157_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -96,9 +97,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (45_465_000 as Weight) + (46_406_000 as Weight) // Standard Error: 1_000 - .saturating_add((220_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((170_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -106,16 +107,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (45_112_000 as Weight) + (46_071_000 as Weight) // Standard Error: 1_000 - .saturating_add((222_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((166_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (26_651_000 as Weight) + (27_699_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -126,45 +127,45 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (77_737_000 as Weight) + (82_703_000 as Weight) // Standard Error: 4_000 - .saturating_add((512_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((500_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (13_126_000 as Weight) + (13_747_000 as Weight) // Standard Error: 0 - .saturating_add((89_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((76_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (2_923_000 as Weight) + (3_070_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (2_889_000 as Weight) + (3_080_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (27_598_000 as Weight) + (29_129_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (28_416_000 as Weight) + (30_105_000 as Weight) // Standard Error: 0 - .saturating_add((132_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((104_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -172,36 +173,46 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (52_836_000 as Weight) - // Standard Error: 2_000 - .saturating_add((478_000 as Weight).saturating_mul(p as Weight)) + (55_228_000 as Weight) + // Standard Error: 1_000 + .saturating_add((457_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (16_891_000 as Weight) + (17_319_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (30_504_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_480_000 as Weight).saturating_mul(r as Weight)) + (29_738_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_153_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - // Storage: Democracy LastTabledWasExternal (r:1 w:0) - // Storage: Democracy NextExternal (r:1 w:0) - // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy LowestUnbaked (r:1 w:0) // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (6_259_000 as Weight) + (2_165_000 as Weight) + // Standard Error: 3_000 + .saturating_add((5_577_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) + } + // Storage: Democracy LowestUnbaked (r:1 w:0) + // Storage: Democracy ReferendumCount (r:1 w:0) + // Storage: Democracy LastTabledWasExternal (r:1 w:0) + // Storage: Democracy NextExternal (r:1 w:0) + // Storage: Democracy PublicProps (r:1 w:0) + // Storage: Democracy ReferendumInfoOf (r:1 w:0) + fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { + (9_396_000 as Weight) // Standard Error: 4_000 - .saturating_add((5_032_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((5_604_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) } @@ -209,9 +220,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (51_719_000 as Weight) - // Standard Error: 5_000 - .saturating_add((7_210_000 as Weight).saturating_mul(r as Weight)) + (57_783_000 as Weight) + // Standard Error: 4_000 + .saturating_add((7_623_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(4 as Weight)) @@ -220,9 +231,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (23_203_000 as Weight) - // Standard Error: 5_000 - .saturating_add((7_206_000 as Weight).saturating_mul(r as Weight)) + (26_027_000 as Weight) + // Standard Error: 4_000 + .saturating_add((7_593_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -230,31 +241,31 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (3_127_000 as Weight) + (2_780_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (44_130_000 as Weight) + (46_416_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (28_756_000 as Weight) + (29_735_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (39_922_000 as Weight) + (41_276_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -262,9 +273,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (38_621_000 as Weight) + (40_348_000 as Weight) // Standard Error: 1_000 - .saturating_add((110_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((60_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -272,27 +283,27 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (36_631_000 as Weight) + (37_475_000 as Weight) // Standard Error: 1_000 - .saturating_add((214_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((151_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (21_025_000 as Weight) + (19_970_000 as Weight) // Standard Error: 1_000 - .saturating_add((195_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((153_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (20_628_000 as Weight) + (20_094_000 as Weight) // Standard Error: 1_000 - .saturating_add((214_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((157_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -305,15 +316,15 @@ impl WeightInfo for () { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (65_665_000 as Weight) + (67_388_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (40_003_000 as Weight) - // Standard Error: 1_000 - .saturating_add((180_000 as Weight).saturating_mul(s as Weight)) + (41_157_000 as Weight) + // Standard Error: 0 + .saturating_add((157_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -321,9 +332,9 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (45_465_000 as Weight) + (46_406_000 as Weight) // Standard Error: 1_000 - .saturating_add((220_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((170_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -331,16 +342,16 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (45_112_000 as Weight) + (46_071_000 as Weight) // Standard Error: 1_000 - .saturating_add((222_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((166_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (26_651_000 as Weight) + (27_699_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -351,45 +362,45 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (77_737_000 as Weight) + (82_703_000 as Weight) // Standard Error: 4_000 - .saturating_add((512_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((500_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (13_126_000 as Weight) + (13_747_000 as Weight) // Standard Error: 0 - .saturating_add((89_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((76_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (2_923_000 as Weight) + (3_070_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (2_889_000 as Weight) + (3_080_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (27_598_000 as Weight) + (29_129_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (28_416_000 as Weight) + (30_105_000 as Weight) // Standard Error: 0 - .saturating_add((132_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((104_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -397,36 +408,46 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (52_836_000 as Weight) - // Standard Error: 2_000 - .saturating_add((478_000 as Weight).saturating_mul(p as Weight)) + (55_228_000 as Weight) + // Standard Error: 1_000 + .saturating_add((457_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (16_891_000 as Weight) + (17_319_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (30_504_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_480_000 as Weight).saturating_mul(r as Weight)) + (29_738_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_153_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } - // Storage: Democracy LastTabledWasExternal (r:1 w:0) - // Storage: Democracy NextExternal (r:1 w:0) - // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy LowestUnbaked (r:1 w:0) // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (6_259_000 as Weight) + (2_165_000 as Weight) + // Standard Error: 3_000 + .saturating_add((5_577_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) + } + // Storage: Democracy LowestUnbaked (r:1 w:0) + // Storage: Democracy ReferendumCount (r:1 w:0) + // Storage: Democracy LastTabledWasExternal (r:1 w:0) + // Storage: Democracy NextExternal (r:1 w:0) + // Storage: Democracy PublicProps (r:1 w:0) + // Storage: Democracy ReferendumInfoOf (r:1 w:0) + fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { + (9_396_000 as Weight) // Standard Error: 4_000 - .saturating_add((5_032_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((5_604_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) } @@ -434,9 +455,9 @@ impl WeightInfo for () { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (51_719_000 as Weight) - // Standard Error: 5_000 - .saturating_add((7_210_000 as Weight).saturating_mul(r as Weight)) + (57_783_000 as Weight) + // Standard Error: 4_000 + .saturating_add((7_623_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) @@ -445,9 +466,9 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (23_203_000 as Weight) - // Standard Error: 5_000 - .saturating_add((7_206_000 as Weight).saturating_mul(r as Weight)) + (26_027_000 as Weight) + // Standard Error: 4_000 + .saturating_add((7_593_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -455,31 +476,31 @@ impl WeightInfo for () { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (3_127_000 as Weight) + (2_780_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (44_130_000 as Weight) + (46_416_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (28_756_000 as Weight) + (29_735_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (39_922_000 as Weight) + (41_276_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -487,9 +508,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (38_621_000 as Weight) + (40_348_000 as Weight) // Standard Error: 1_000 - .saturating_add((110_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((60_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -497,27 +518,27 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (36_631_000 as Weight) + (37_475_000 as Weight) // Standard Error: 1_000 - .saturating_add((214_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((151_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (21_025_000 as Weight) + (19_970_000 as Weight) // Standard Error: 1_000 - .saturating_add((195_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((153_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (20_628_000 as Weight) + (20_094_000 as Weight) // Standard Error: 1_000 - .saturating_add((214_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((157_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } From 70b4a8af2007a5ab6bb0f501cac393e343debb1e Mon Sep 17 00:00:00 2001 From: Robert Klotzner Date: Thu, 30 Sep 2021 16:42:08 +0200 Subject: [PATCH 0052/1472] Silence alert about large-statement-fetcher (#9882) * Silence alert about large-statement-fetcher That task is not continuous and behaving exactly as desired. * Get rid of rule completely - Pierre thinks it does not add any value - Basti rightly complains that Polkadot specific exceptions make little sense in the Substrate repo. --- .../monitoring/alerting-rules/alerting-rules.yaml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.maintain/monitoring/alerting-rules/alerting-rules.yaml b/.maintain/monitoring/alerting-rules/alerting-rules.yaml index 7a69cba66c3f3..2711610024330 100644 --- a/.maintain/monitoring/alerting-rules/alerting-rules.yaml +++ b/.maintain/monitoring/alerting-rules/alerting-rules.yaml @@ -133,16 +133,6 @@ groups: # Others ############################################################################## - - alert: ContinuousTaskEnded - expr: '(polkadot_tasks_spawned_total{task_name != "basic-authorship-proposer", task_name != "substrate-rpc-subscription"} == 1) - - on(instance, task_name) group_left() (polkadot_tasks_ended_total == 1)' - for: 5m - labels: - severity: warning - annotations: - message: 'Continuous task {{ $labels.task_name }} on node - {{ $labels.instance }} ended unexpectedly.' - - alert: AuthorityDiscoveryDiscoveryFailureHigh expr: 'polkadot_authority_discovery_handle_value_found_event_failure / ignoring(name) From 8b95e236582c209a1676d75a1db61a4916faabf5 Mon Sep 17 00:00:00 2001 From: Denis Pisarev Date: Thu, 30 Sep 2021 17:12:28 +0200 Subject: [PATCH 0053/1472] doc: subkey usage (#9905) * CI: md styling * CI: add container usage --- bin/utils/subkey/README.md | 101 ++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/bin/utils/subkey/README.md b/bin/utils/subkey/README.md index 2494bff3bc9ab..2310c59f4a283 100644 --- a/bin/utils/subkey/README.md +++ b/bin/utils/subkey/README.md @@ -27,19 +27,28 @@ Command: ```bash # Use the `--fast` flag to get the dependencies without needing to install the Substrate and Subkey binary curl https://getsubstrate.io -sSf | bash -s -- --fast -# Install only `subkey`, at a specific version of the this subkey crate +# Install only `subkey`, at a specific version of the subkey crate cargo install --force subkey --git https://github.com/paritytech/substrate --version --locked ``` +### Run in a container + +```bash +# Use `--pull=always` with the `latest` tag, or specify a version in a tag +docker run -it --pull=always docker.io/parity/subkey:latest +``` + ### Generate a random account Generating a new key is as simple as running: - subkey generate +```bash +subkey generate +``` The output looks similar to: -``` +```text Secret phrase `hotel forest jar hover kite book view eight stuff angle legend defense` is account: Secret seed: 0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d Public key (hex): 0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515 @@ -63,6 +72,7 @@ The **SS58 address** (or **Public Address**) of a new account is a reprensentati You can read more about the SS58 format in the [substrate wiki](https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)) and see the list of reserved prefixes in the [Polkadot wiki](https://wiki.polkadot.network/docs/build-ss58-registry). For instance, considering the previous seed `0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d` the SS58 addresses are: + - Polkadot: `16m4J167Mptt8UXL8aGSAi7U2FnPpPxZHPrCgMG9KJzVoFqM` - Kusama: `JLNozAv8QeLSbLFwe2UvWeKKE4yvmDbfGxTuiYkF2BUMx4M` @@ -71,12 +81,14 @@ For instance, considering the previous seed `0xa05c75731970cc7868a2fb7cb577353cd `subkey` can calso generate the output as *json*. This is useful for automation. command: -``` + +```bash subkey generate --output-type json ``` output: -``` + +```json { "accountId": "0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515", "publicKey": "0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515", @@ -89,12 +101,14 @@ output: So if you only want to get the `secretSeed` for instance, you can use: command: -``` + +```bash subkey generate --output-type json | jq -r .secretSeed ``` output: -``` + +```text 0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d ``` @@ -102,10 +116,13 @@ output: `subkey` supports an additional user-defined secret that will be appended to the seed. Let's see the following example: - subkey generate --password extra_secret +```bash +subkey generate --password extra_secret +``` output: -``` + +```text Secret phrase `soup lyrics media market way crouch elevator put moon useful question wide` is account: Secret seed: 0xe7cfd179d6537a676cb94bac3b5c5c9cb1550e846ac4541040d077dfbac2e7fd Public key (hex): 0xf6a233c3e1de1a2ae0486100b460b3ce3d7231ddfe9dadabbd35ab968c70905d @@ -115,11 +132,15 @@ Secret phrase `soup lyrics media market way crouch elevator put moon useful ques Using the `inspect` command (see more details below), we see that knowning only the **secret seed** is no longer sufficient to recover the account: - subkey inspect "soup lyrics media market way crouch elevator put moon useful question wide" +```bash +subkey inspect "soup lyrics media market way crouch elevator put moon useful question wide" +``` which recovers the account `5Fe4sqj2K4fRuzEGvToi4KATqZfiDU7TqynjXG6PZE2dxwyh` and not `5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6iaVC` as we expected. The additional user-defined **password** (`extra_secret` in our example) is now required to fully recover the account. Let's inspect the the previous mnemonic, this time passing also the required `password` as shown below: - subkey inspect --password extra_secret "soup lyrics media market way crouch elevator put moon useful question wide" +```bash +subkey inspect --password extra_secret "soup lyrics media market way crouch elevator put moon useful question wide" +``` This time, we properly recovered `5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6iaVC`. @@ -129,23 +150,29 @@ If you have *some data* about a key, `subkey inpsect` will help you discover mor If you have **secrets** that you would like to verify for instance, you can use: - subkey inspect < mnemonic | seed > +```bash +subkey inspect < mnemonic | seed > +``` If you have only **public data**, you can see a subset of the information: - subkey inspect --public < pubkey | address > +```bash +subkey inspect --public < pubkey | address > +``` **NOTE**: While you will be able to recover the secret seed from the mnemonic, the opposite is not possible. **NOTE**: For obvious reasons, the **secrets** cannot be recovered from passing **public data** such as `pubkey` or `address` as input. command: -``` + +```bash subkey inspect 0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d ``` output: -``` + +```text Secret Key URI `0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d` is account: Secret seed: 0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d Public key (hex): 0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515 @@ -157,17 +184,23 @@ Secret Key URI `0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c9 `subkey` allows using a **secret key** to sign a random message. The signature can then be verified by anyone using your **public key**: - echo -n | subkey sign --suri +```bash +echo -n | subkey sign --suri +``` example: - MESSAGE=hello - SURI=0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d - echo -n $MESSAGE | subkey sign --suri $SURI +```text +MESSAGE=hello +SURI=0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d +echo -n $MESSAGE | subkey sign --suri $SURI +``` output: - 9201af3788ad4f986b800853c79da47155f2e08fde2070d866be4c27ab060466fea0623dc2b51f4392f4c61f25381a62848dd66c5d8217fae3858e469ebd668c +```text +9201af3788ad4f986b800853c79da47155f2e08fde2070d866be4c27ab060466fea0623dc2b51f4392f4c61f25381a62848dd66c5d8217fae3858e469ebd668c +``` **NOTE**: Each run of the `sign` command will yield a different output. While each signature is different, they are all valid. @@ -175,34 +208,44 @@ output: Given a message, a signature and an address, `subkey` can verify whether the **message** has been digitally signed by the holder (or one of the holders) of the **private key** for the given **address**: - echo -n | subkey verify
+```bash +echo -n | subkey verify
+``` example: - MESSAGE=hello - URI=0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515 - SIGNATURE=9201af3788ad4f986b800853c79da47155f2e08fde2070d866be4c27ab060466fea0623dc2b51f4392f4c61f25381a62848dd66c5d8217fae3858e469ebd668c - echo -n $MESSAGE | subkey verify $SIGNATURE $URI +```bash +MESSAGE=hello +URI=0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515 +SIGNATURE=9201af3788ad4f986b800853c79da47155f2e08fde2070d866be4c27ab060466fea0623dc2b51f4392f4c61f25381a62848dd66c5d8217fae3858e469ebd668c +echo -n $MESSAGE | subkey verify $SIGNATURE $URI +``` output: - Signature verifies correctly. +```text +Signature verifies correctly. +``` A failure looks like: - Error: SignatureInvalid +```text +Error: SignatureInvalid +``` ### Using the vanity generator You can use the included vanity generator to find a seed that provides an address which includes the desired pattern. Be warned, depending on your hardware this may take a while. command: -``` + +```bash subkey vanity --network polkadot --pattern bob ``` output: -``` + +```text Generating key containing pattern 'bob' best: 190 == top: 189 Secret Key URI `0x8c9a73097f235b84021a446bc2826a00c690ea0be3e0d81a84931cb4146d6691` is account: From 3302199c6c8acdfbb4a5858b907048c2cec502d0 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Thu, 30 Sep 2021 18:32:29 +0200 Subject: [PATCH 0054/1472] Pallet Assets: Create new asset classes from genesis config (#9742) * Pallet Assets: Allow creating asset classes from genesis config * Add accounts and metadata to genesis config * whitespace fixes * Update more chainspecs * Run rustfmt over code * More formatting fixes * Update frame/assets/src/lib.rs Improve error message Co-authored-by: Shawn Tabrizi * Update frame/assets/src/lib.rs Improve error message Co-authored-by: Shawn Tabrizi Co-authored-by: Shawn Tabrizi --- bin/node/cli/src/chain_spec.rs | 1 + bin/node/runtime/src/lib.rs | 2 +- bin/node/testing/src/genesis.rs | 1 + frame/assets/src/lib.rs | 102 +++++++++++++++++++++++++++++++- frame/assets/src/mock.rs | 23 ++++++- frame/assets/src/tests.rs | 10 ++++ 6 files changed, 133 insertions(+), 6 deletions(-) diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 5e727afa304bb..b5e36d9b53629 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -361,6 +361,7 @@ pub fn testnet_genesis( max_members: 999, }, vesting: Default::default(), + assets: Default::default(), gilt: Default::default(), transaction_storage: Default::default(), } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 587a54ebd0d9b..881641e15136c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1280,7 +1280,7 @@ construct_runtime!( Multisig: pallet_multisig::{Pallet, Call, Storage, Event}, Bounties: pallet_bounties::{Pallet, Call, Storage, Event}, Tips: pallet_tips::{Pallet, Call, Storage, Event}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, + Assets: pallet_assets::{Pallet, Call, Storage, Event, Config}, Mmr: pallet_mmr::{Pallet, Storage}, Lottery: pallet_lottery::{Pallet, Call, Storage, Event}, Gilt: pallet_gilt::{Pallet, Call, Storage, Event, Config}, diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index 50c1e6f9d20be..845227c5acee9 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -98,6 +98,7 @@ pub fn config_endowed( treasury: Default::default(), society: SocietyConfig { members: vec![alice(), bob()], pot: 0, max_members: 999 }, vesting: Default::default(), + assets: Default::default(), gilt: Default::default(), transaction_storage: Default::default(), } diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 2c9f994b3fef8..c6f24e10a89f0 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -159,6 +159,9 @@ use sp_runtime::{ }; use sp_std::{borrow::Borrow, convert::TryInto, prelude::*}; +#[cfg(feature = "std")] +use frame_support::traits::GenesisBuild; + pub use pallet::*; pub use weights::WeightInfo; @@ -180,10 +183,22 @@ pub mod pallet { type Event: From> + IsType<::Event>; /// The units in which we record balances. - type Balance: Member + Parameter + AtLeast32BitUnsigned + Default + Copy + MaxEncodedLen; + type Balance: Member + + Parameter + + AtLeast32BitUnsigned + + Default + + Copy + + MaybeSerializeDeserialize + + MaxEncodedLen; /// Identifier for the class of asset. - type AssetId: Member + Parameter + Default + Copy + HasCompact + MaxEncodedLen; + type AssetId: Member + + Parameter + + Default + + Copy + + HasCompact + + MaybeSerializeDeserialize + + MaxEncodedLen; /// The currency mechanism. type Currency: ReservableCurrency; @@ -276,6 +291,89 @@ pub mod pallet { ConstU32<300_000>, >; + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + /// Genesis assets: id, owner, is_sufficient, min_balance + pub assets: Vec<(T::AssetId, T::AccountId, bool, T::Balance)>, + /// Genesis metadata: id, name, symbol, decimals + pub metadata: Vec<(T::AssetId, Vec, Vec, u8)>, + /// Genesis accounts: id, account_id, balance + pub accounts: Vec<(T::AssetId, T::AccountId, T::Balance)>, + } + + #[cfg(feature = "std")] + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + Self { + assets: Default::default(), + metadata: Default::default(), + accounts: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { + for (id, owner, is_sufficient, min_balance) in &self.assets { + assert!(!Asset::::contains_key(id), "Asset id already in use"); + assert!(!min_balance.is_zero(), "Min balance should not be zero"); + Asset::::insert( + id, + AssetDetails { + owner: owner.clone(), + issuer: owner.clone(), + admin: owner.clone(), + freezer: owner.clone(), + supply: Zero::zero(), + deposit: Zero::zero(), + min_balance: *min_balance, + is_sufficient: *is_sufficient, + accounts: 0, + sufficients: 0, + approvals: 0, + is_frozen: false, + }, + ); + } + + for (id, name, symbol, decimals) in &self.metadata { + assert!(Asset::::contains_key(id), "Asset does not exist"); + + let bounded_name: BoundedVec = + name.clone().try_into().expect("asset name is too long"); + let bounded_symbol: BoundedVec = + symbol.clone().try_into().expect("asset symbol is too long"); + + let metadata = AssetMetadata { + deposit: Zero::zero(), + name: bounded_name, + symbol: bounded_symbol, + decimals: *decimals, + is_frozen: false, + }; + Metadata::::insert(id, metadata); + } + + for (id, account_id, amount) in &self.accounts { + let result = >::increase_balance( + *id, + account_id, + *amount, + |details| -> DispatchResult { + debug_assert!( + T::Balance::max_value() - details.supply >= *amount, + "checked in prep; qed" + ); + details.supply = details.supply.saturating_add(*amount); + Ok(()) + }, + ); + assert!(result.is_ok()); + } + } + } + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 1b2602792d844..1e1ea8ba9a961 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -144,9 +144,26 @@ pub(crate) fn hooks() -> Vec { } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); + let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + let config: pallet_assets::GenesisConfig = pallet_assets::GenesisConfig { + assets: vec![ + // id, owner, is_sufficient, min_balance + (999, 0, true, 1), + ], + metadata: vec![ + // id, name, symbol, decimals + (999, "Token Name".into(), "TOKEN".into(), 10), + ], + accounts: vec![ + // id, account_id, balance + (999, 1, 100), + ], + }; + + config.assimilate_storage(&mut storage).unwrap(); + + let mut ext: sp_io::TestExternalities = storage.into(); ext.execute_with(|| System::set_block_number(1)); ext } diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index aab534a6e4efc..872bd7290133c 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -784,3 +784,13 @@ fn balance_conversion_should_work() { ); }); } + +#[test] +fn assets_from_genesis_should_exist() { + new_test_ext().execute_with(|| { + assert!(Asset::::contains_key(999)); + assert!(Metadata::::contains_key(999)); + assert_eq!(Assets::balance(999, 1), 100); + assert_eq!(Assets::total_supply(999), 100); + }); +} From bf9683eee40f82cc4e01a05cd375b0e8bba3c8ef Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 30 Sep 2021 12:46:48 -0400 Subject: [PATCH 0055/1472] Simple Trait to Inspect Metadata (#9893) * simple trait to inspect metadata * import vec --- frame/assets/src/impl_fungibles.rs | 19 +++++++++++++++++++ frame/support/src/traits/tokens/fungibles.rs | 13 +++++++++++++ 2 files changed, 32 insertions(+) diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 25e18bfd437bb..2e16a0910a4f0 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -60,6 +60,25 @@ impl, I: 'static> fungibles::Inspect<::AccountId } } +impl, I: 'static> fungibles::InspectMetadata<::AccountId> + for Pallet +{ + /// Return the name of an asset. + fn name(asset: &Self::AssetId) -> Vec { + Metadata::::get(asset).name.to_vec() + } + + /// Return the symbol of an asset. + fn symbol(asset: &Self::AssetId) -> Vec { + Metadata::::get(asset).symbol.to_vec() + } + + /// Return the decimals of an asset. + fn decimals(asset: &Self::AssetId) -> u8 { + Metadata::::get(asset).decimals + } +} + impl, I: 'static> fungibles::Mutate<::AccountId> for Pallet { fn mint_into( asset: Self::AssetId, diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 457ec4e8bf20f..2930853201d25 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -23,6 +23,7 @@ use super::{ }; use crate::dispatch::{DispatchError, DispatchResult}; use sp_runtime::traits::Saturating; +use sp_std::vec::Vec; mod balanced; pub use balanced::{Balanced, Unbalanced}; @@ -65,6 +66,18 @@ pub trait Inspect { ) -> WithdrawConsequence; } +/// Trait for reading metadata from a fungible asset. +pub trait InspectMetadata: Inspect { + /// Return the name of an asset. + fn name(asset: &Self::AssetId) -> Vec; + + /// Return the symbol of an asset. + fn symbol(asset: &Self::AssetId) -> Vec; + + /// Return the decimals of an asset. + fn decimals(asset: &Self::AssetId) -> u8; +} + /// Trait for providing a set of named fungible assets which can be created and destroyed. pub trait Mutate: Inspect { /// Attempt to increase the `asset` balance of `who` by `amount`. From a2e7ae3ae8bf58f899c2c8f57597d2694b8c6fae Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Fri, 1 Oct 2021 05:54:41 +0200 Subject: [PATCH 0056/1472] Add build with docker section to README (#9792) Co-authored-by: Shawn Tabrizi --- docs/README.adoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/README.adoc b/docs/README.adoc index 71052420b1aa9..05f81442d4ca8 100644 --- a/docs/README.adoc +++ b/docs/README.adoc @@ -250,6 +250,20 @@ If you are trying to set up Substrate on Windows, you should do the following: 7. Finally, you need to install `cmake`: https://cmake.org/download/ +==== Docker + +You can use https://github.com/paritytech/scripts/tree/master/dockerfiles/ci-linux[Parity CI docker image] with all necessary dependencies to build Substrate: + +[source, shell] +---- +#run it in the folder with the Substrate source code +docker run --rm -it -w /shellhere/substrate \ + -v $(pwd):/shellhere/substrate \ + paritytech/ci-linux:production +---- + +You can find necessary cargo commands in <> + ==== Shared Steps Then, grab the Substrate source code: From 3d0a91789a32087b29660496593533253c88460d Mon Sep 17 00:00:00 2001 From: ucover <91202993+ucover@users.noreply.github.com> Date: Fri, 1 Oct 2021 10:17:26 +0200 Subject: [PATCH 0057/1472] Test each benchmark case in own #[test] (#9860) * Generate one #[test] fn per bench case. * Update benchmark macro syntax in frame pallets. * Explain new benchmark macro syntax in example pallet. * support with and without a semicolon * update pallets to use individual tests * migrate staking too * migrate more pallets * fix up democracy and use individual tests * Fix comment * Put println message in panic * Remove `another_set_dummy` from doc `another_set_dummy` is not present in the benchmarking.rs (anymore). * Update doc for benchmarks macro * Update doc for impl_benchmark_test_suite macro Co-authored-by: Shawn Tabrizi --- .../pallets/template/src/benchmarking.rs | 6 +- frame/assets/src/benchmarking.rs | 7 +- frame/babe/src/benchmarking.rs | 12 +- frame/bags-list/src/benchmarks.rs | 13 +- frame/balances/src/benchmarking.rs | 16 +- frame/benchmarking/src/lib.rs | 348 +++++++++++++++++- frame/benchmarking/src/tests_instance.rs | 12 +- frame/bounties/src/benchmarking.rs | 6 +- frame/collective/src/benchmarking.rs | 8 +- frame/contracts/src/benchmarking/mod.rs | 14 +- frame/democracy/src/benchmarking.rs | 12 +- frame/democracy/src/lib.rs | 2 +- .../src/benchmarking.rs | 14 +- frame/elections-phragmen/src/benchmarking.rs | 18 +- frame/example/src/benchmarking.rs | 20 +- frame/gilt/src/benchmarking.rs | 6 +- frame/grandpa/src/benchmarking.rs | 12 +- frame/identity/src/benchmarking.rs | 5 +- frame/im-online/src/benchmarking.rs | 6 +- frame/indices/src/benchmarking.rs | 6 +- frame/lottery/src/benchmarking.rs | 6 +- frame/membership/src/lib.rs | 8 +- .../merkle-mountain-range/src/benchmarking.rs | 6 +- frame/multisig/src/benchmarking.rs | 6 +- frame/offences/benchmarking/src/lib.rs | 6 +- frame/proxy/Cargo.toml | 1 + frame/proxy/src/benchmarking.rs | 6 +- frame/scheduler/src/benchmarking.rs | 6 +- frame/session/benchmarking/src/lib.rs | 6 +- frame/staking/src/benchmarking.rs | 14 +- frame/staking/src/lib.rs | 1 + frame/system/benchmarking/src/lib.rs | 6 +- frame/timestamp/src/benchmarking.rs | 6 +- frame/tips/src/benchmarking.rs | 6 +- frame/transaction-storage/src/benchmarking.rs | 6 +- frame/treasury/src/benchmarking.rs | 6 +- frame/uniques/src/benchmarking.rs | 7 +- frame/utility/src/benchmarking.rs | 6 +- frame/vesting/src/benchmarking.rs | 14 +- 39 files changed, 496 insertions(+), 170 deletions(-) diff --git a/bin/node-template/pallets/template/src/benchmarking.rs b/bin/node-template/pallets/template/src/benchmarking.rs index 2117c048cfbdb..d496a9fc89b1a 100644 --- a/bin/node-template/pallets/template/src/benchmarking.rs +++ b/bin/node-template/pallets/template/src/benchmarking.rs @@ -4,7 +4,7 @@ use super::*; #[allow(unused)] use crate::Pallet as Template; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{benchmarks, whitelisted_caller}; use frame_system::RawOrigin; benchmarks! { @@ -15,6 +15,6 @@ benchmarks! { verify { assert_eq!(Something::::get(), Some(s)); } -} -impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 43eadffbe8497..d9de9ed3dedd4 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -21,8 +21,7 @@ use super::*; use frame_benchmarking::{ - account, benchmarks_instance_pallet, impl_benchmark_test_suite, whitelist_account, - whitelisted_caller, + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, }; use frame_support::{ dispatch::UnfilteredDispatchable, @@ -438,6 +437,6 @@ benchmarks_instance_pallet! { verify { assert_last_event::(Event::ApprovalCancelled(id, caller, delegate).into()); } -} -impl_benchmark_test_suite!(Assets, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Assets, crate::mock::new_test_ext(), crate::mock::Test) +} diff --git a/frame/babe/src/benchmarking.rs b/frame/babe/src/benchmarking.rs index 372dfa532a894..7747c9bd1fc8c 100644 --- a/frame/babe/src/benchmarking.rs +++ b/frame/babe/src/benchmarking.rs @@ -63,6 +63,12 @@ benchmarks! { } verify { assert!(sp_consensus_babe::check_equivocation_proof::
(equivocation_proof2)); } + + impl_benchmark_test_suite!( + Pallet, + crate::mock::new_test_ext(3), + crate::mock::Test, + ) } #[cfg(test)] @@ -70,12 +76,6 @@ mod tests { use super::*; use crate::mock::*; - frame_benchmarking::impl_benchmark_test_suite!( - Pallet, - crate::mock::new_test_ext(3), - crate::mock::Test, - ); - #[test] fn test_generate_equivocation_report_blob() { let (pairs, mut ext) = new_test_ext_with_pairs(3); diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index a820eeba13b12..d86adc674c44a 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -134,11 +134,10 @@ frame_benchmarking::benchmarks! { ] ); } -} -use frame_benchmarking::impl_benchmark_test_suite; -impl_benchmark_test_suite!( - Pallet, - crate::mock::ExtBuilder::default().build(), - crate::mock::Runtime, -); + impl_benchmark_test_suite!( + Pallet, + crate::mock::ExtBuilder::default().build(), + crate::mock::Runtime, + ) +} diff --git a/frame/balances/src/benchmarking.rs b/frame/balances/src/benchmarking.rs index 06d202ea37002..1c48820094187 100644 --- a/frame/balances/src/benchmarking.rs +++ b/frame/balances/src/benchmarking.rs @@ -21,9 +21,7 @@ use super::*; -use frame_benchmarking::{ - account, benchmarks_instance_pallet, impl_benchmark_test_suite, whitelisted_caller, -}; +use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -215,10 +213,10 @@ benchmarks_instance_pallet! { assert!(Balances::::reserved_balance(&user).is_zero()); assert_eq!(Balances::::free_balance(&user), balance); } -} -impl_benchmark_test_suite!( - Balances, - crate::tests_composite::ExtBuilder::default().build(), - crate::tests_composite::Test, -); + impl_benchmark_test_suite!( + Balances, + crate::tests_composite::ExtBuilder::default().build(), + crate::tests_composite::Test, + ) +} diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 4a6c5e15ae20c..1805424426f6e 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -155,6 +155,12 @@ macro_rules! whitelist { /// benchmark just like a regular benchmark, but only testing at the lowest and highest values for /// each component. The function will return `Ok(())` if the benchmarks return no errors. /// +/// It is also possible to generate one #[test] function per benchmark by calling the +/// `impl_benchmark_test_suite` macro inside the `benchmarks` block. The functions will be named +/// `bench_` and can be run via `cargo test`. +/// You will see one line of output per benchmark. This approach will give you more understandable +/// error messages and allows for parallel benchmark execution. +/// /// You can optionally add a `verify` code block at the end of a benchmark to test any final state /// of your benchmark in a unit test. For example: /// @@ -174,7 +180,8 @@ macro_rules! whitelist { /// /// These `verify` blocks will not affect your benchmark results! /// -/// You can construct benchmark tests like so: +/// You can construct benchmark by using the `impl_benchmark_test_suite` macro or +/// by manually implementing them like so: /// /// ```ignore /// #[test] @@ -193,6 +200,7 @@ macro_rules! benchmarks { $( $rest:tt )* ) => { $crate::benchmarks_iter!( + { } { } { } ( ) @@ -212,6 +220,7 @@ macro_rules! benchmarks_instance { $( $rest:tt )* ) => { $crate::benchmarks_iter!( + { } { I: Instance } { } ( ) @@ -231,6 +240,7 @@ macro_rules! benchmarks_instance_pallet { $( $rest:tt )* ) => { $crate::benchmarks_iter!( + { } { I: 'static } { } ( ) @@ -244,8 +254,60 @@ macro_rules! benchmarks_instance_pallet { #[macro_export] #[doc(hidden)] macro_rules! benchmarks_iter { + // detect and extract `impl_benchmark_test_suite` call: + // - with a semi-colon + ( + { } + { $( $instance:ident: $instance_bound:tt )? } + { $( $where_clause:tt )* } + ( $( $names:tt )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + impl_benchmark_test_suite!( + $bench_module:ident, + $new_test_ext:expr, + $test:path + $(, $( $args:tt )* )?); + $( $rest:tt )* + ) => { + $crate::benchmarks_iter! { + { $bench_module, $new_test_ext, $test $(, $( $args )* )? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + $( $rest )* + } + }; + // - without a semicolon + ( + { } + { $( $instance:ident: $instance_bound:tt )? } + { $( $where_clause:tt )* } + ( $( $names:tt )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + impl_benchmark_test_suite!( + $bench_module:ident, + $new_test_ext:expr, + $test:path + $(, $( $args:tt )* )?) + $( $rest:tt )* + ) => { + $crate::benchmarks_iter! { + { $bench_module, $new_test_ext, $test $(, $( $args )* )? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + $( $rest )* + } + }; // detect and extract where clause: ( + { $($bench_module:ident, $new_test_ext:expr, $test:path $(, $( $args:tt )* )?)? } { $( $instance:ident: $instance_bound:tt )? } { $( $where_clause:tt )* } ( $( $names:tt )* ) @@ -255,6 +317,7 @@ macro_rules! benchmarks_iter { $( $rest:tt )* ) => { $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } { $( $instance: $instance_bound)? } { $( $where_bound )* } ( $( $names )* ) @@ -265,6 +328,7 @@ macro_rules! benchmarks_iter { }; // detect and extract `#[skip_meta]` tag: ( + { $($bench_module:ident, $new_test_ext:expr, $test:path $(, $( $args:tt )* )?)? } { $( $instance:ident: $instance_bound:tt )? } { $( $where_clause:tt )* } ( $( $names:tt )* ) @@ -275,6 +339,7 @@ macro_rules! benchmarks_iter { $( $rest:tt )* ) => { $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } { $( $instance: $instance_bound )? } { $( $where_clause )* } ( $( $names )* ) @@ -284,8 +349,9 @@ macro_rules! benchmarks_iter { $( $rest )* } }; - // detect and extract `#[extra] tag: + // detect and extract `#[extra]` tag: ( + { $($bench_module:ident, $new_test_ext:expr, $test:path $(, $( $args:tt )* )?)? } { $( $instance:ident: $instance_bound:tt )? } { $( $where_clause:tt )* } ( $( $names:tt )* ) @@ -296,6 +362,7 @@ macro_rules! benchmarks_iter { $( $rest:tt )* ) => { $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } { $( $instance: $instance_bound )? } { $( $where_clause )* } ( $( $names )* ) @@ -307,6 +374,7 @@ macro_rules! benchmarks_iter { }; // mutation arm: ( + { $($bench_module:ident, $new_test_ext:expr, $test:path $(, $( $args:tt )* )?)? } { $( $instance:ident: $instance_bound:tt )? } { $( $where_clause:tt )* } ( $( $names:tt )* ) // This contains $( $( { $instance } )? $name:ident )* @@ -317,6 +385,7 @@ macro_rules! benchmarks_iter { $( $rest:tt )* ) => { $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } { $( $instance: $instance_bound )? } { $( $where_clause )* } ( $( $names )* ) @@ -329,6 +398,7 @@ macro_rules! benchmarks_iter { }; // mutation arm: ( + { $($bench_module:ident, $new_test_ext:expr, $test:path $(, $( $args:tt )* )?)? } { $( $instance:ident: $instance_bound:tt )? } { $( $where_clause:tt )* } ( $( $names:tt )* ) @@ -340,6 +410,7 @@ macro_rules! benchmarks_iter { ) => { $crate::paste::paste! { $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } { $( $instance: $instance_bound )? } { $( $where_clause )* } ( $( $names )* ) @@ -373,6 +444,7 @@ macro_rules! benchmarks_iter { }; // iteration arm: ( + { $($bench_module:ident, $new_test_ext:expr, $test:path $(, $( $args:tt )* )?)? } { $( $instance:ident: $instance_bound:tt )? } { $( $where_clause:tt )* } ( $( $names:tt )* ) @@ -400,6 +472,7 @@ macro_rules! benchmarks_iter { ); $crate::benchmarks_iter!( + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } { $( $instance: $instance_bound )? } { $( $where_clause )* } ( $( $names )* { $( $instance )? } $name ) @@ -408,8 +481,40 @@ macro_rules! benchmarks_iter { $( $rest )* ); }; - // iteration-exit arm + // iteration-exit arm which generates a #[test] function for each case. ( + { $bench_module:ident, $new_test_ext:expr, $test:path $(, $( $args:tt )* )? } + { $( $instance:ident: $instance_bound:tt )? } + { $( $where_clause:tt )* } + ( $( $names:tt )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + ) => { + $crate::selected_benchmark!( + { $( $where_clause)* } + { $( $instance: $instance_bound )? } + $( $names )* + ); + $crate::impl_benchmark!( + { $( $where_clause )* } + { $( $instance: $instance_bound )? } + ( $( $names )* ) + ( $( $names_extra ),* ) + ( $( $names_skip_meta ),* ) + ); + $crate::impl_test_function!( + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + $bench_module, + $new_test_ext, + $test + $(, $( $args )* )? + ); + }; + // iteration-exit arm which doesn't generate a #[test] function for all cases. + ( + { } { $( $instance:ident: $instance_bound:tt )? } { $( $where_clause:tt )* } ( $( $names:tt )* ) @@ -431,6 +536,7 @@ macro_rules! benchmarks_iter { }; // add verify block to _() format ( + { $($bench_module:ident, $new_test_ext:expr, $test:path $(, $( $args:tt )* )?)? } { $( $instance:ident: $instance_bound:tt )? } { $( $where_clause:tt )* } ( $( $names:tt )* ) @@ -440,6 +546,7 @@ macro_rules! benchmarks_iter { $( $rest:tt )* ) => { $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } { $( $instance: $instance_bound )? } { $( $where_clause )* } ( $( $names )* ) @@ -452,6 +559,7 @@ macro_rules! benchmarks_iter { }; // add verify block to name() format ( + { $($bench_module:ident, $new_test_ext:expr, $test:path $(, $( $args:tt )* )?)? } { $( $instance:ident: $instance_bound:tt )? } { $( $where_clause:tt )* } ( $( $names:tt )* ) @@ -461,6 +569,7 @@ macro_rules! benchmarks_iter { $( $rest:tt )* ) => { $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } { $( $instance: $instance_bound )? } { $( $where_clause )* } ( $( $names )* ) @@ -473,6 +582,7 @@ macro_rules! benchmarks_iter { }; // add verify block to {} format ( + { $($bench_module:ident, $new_test_ext:expr, $test:path $(, $( $args:tt )* )?)? } { $( $instance:ident: $instance_bound:tt )? } { $( $where_clause:tt )* } ( $( $names:tt )* ) @@ -482,6 +592,7 @@ macro_rules! benchmarks_iter { $( $rest:tt )* ) => { $crate::benchmarks_iter!( + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } { $( $instance: $instance_bound )? } { $( $where_clause )* } ( $( $names )* ) @@ -695,6 +806,100 @@ macro_rules! benchmark_backend { }; } +// Creates #[test] functions for the given bench cases. +#[macro_export] +#[doc(hidden)] +macro_rules! impl_bench_case_tests { + ( + { $module:ident, $new_test_exec:expr, $exec_name:ident, $test:path, $extra:expr } + { $( $names_extra:tt )* } + $( { $( $bench_inst:ident )? } $bench:ident )* + ) + => { + $crate::impl_bench_name_tests!( + $module, $new_test_exec, $exec_name, $test, $extra, + { $( $names_extra )* }, + $( { $bench } )+ + ); + } +} + +// Creates a #[test] function for the given bench name. +#[macro_export] +#[doc(hidden)] +macro_rules! impl_bench_name_tests { + // recursion anchor + ( + $module:ident, $new_test_exec:expr, $exec_name:ident, $test:path, $extra:expr, + { $( $names_extra:tt )* }, + { $name:ident } + ) => { + $crate::paste::paste! { + #[test] + fn [] () { + $new_test_exec.$exec_name(|| { + // Skip all #[extra] benchmarks if $extra is false. + if !($extra) { + let disabled = $crate::vec![ $( stringify!($names_extra).as_ref() ),* ]; + if disabled.contains(&stringify!($name)) { + $crate::log::error!( + "INFO: extra benchmark skipped - {}", + stringify!($name), + ); + return (); + } + } + + // Same per-case logic as when all cases are run in the + // same function. + match std::panic::catch_unwind(|| { + $module::<$test>::[< test_benchmark_ $name >] () + }) { + Err(err) => { + panic!("{}: {:?}", stringify!($name), err); + }, + Ok(Err(err)) => { + match err { + $crate::BenchmarkError::Stop(err) => { + panic!("{}: {:?}", stringify!($name), err); + }, + $crate::BenchmarkError::Override(_) => { + // This is still considered a success condition. + $crate::log::error!( + "WARNING: benchmark error overrided - {}", + stringify!($name), + ); + }, + $crate::BenchmarkError::Skip => { + // This is considered a success condition. + $crate::log::error!( + "WARNING: benchmark error skipped - {}", + stringify!($name), + ); + } + } + }, + Ok(Ok(())) => (), + } + }); + } + } + }; + // recursion tail + ( + $module:ident, $new_test_exec:expr, $exec_name:ident, $test:path, $extra:expr, + { $( $names_extra:tt )* }, + { $name:ident } $( { $rest:ident } )+ + ) => { + // car + $crate::impl_bench_name_tests!($module, $new_test_exec, $exec_name, $test, $extra, + { $( $names_extra )* }, { $name }); + // cdr + $crate::impl_bench_name_tests!($module, $new_test_exec, $exec_name, $test, $extra, + { $( $names_extra )* }, $( { $rest } )+); + }; +} + // Creates a `SelectedBenchmark` enum implementing `BenchmarkingSetup`. // // Every variant must implement [`BenchmarkingSetup`]. @@ -1030,13 +1235,54 @@ macro_rules! impl_benchmark_test { /// new_test_ext().execute_with(|| { /// assert_ok!(test_benchmark_accumulate_dummy::()); /// assert_ok!(test_benchmark_set_dummy::()); -/// assert_ok!(test_benchmark_another_set_dummy::()); /// assert_ok!(test_benchmark_sort_vector::()); /// }); /// } /// } /// ``` /// +/// When called inside the `benchmarks` macro of the `pallet_example` as +/// +/// ```rust,ignore +/// benchmarks! { +/// // Benchmarks omitted for brevity +/// +/// impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); +/// } +/// ``` +/// +/// It expands to the equivalent of: +/// +/// ```rust,ignore +/// #[cfg(test)] +/// mod benchmarking { +/// use super::*; +/// use crate::tests::{new_test_ext, Test}; +/// use frame_support::assert_ok; +/// +/// #[test] +/// fn bench_accumulate_dummy() { +/// new_test_ext().execute_with(|| { +/// assert_ok!(test_benchmark_accumulate_dummy::()); +/// } +/// } +/// +/// #[test] +/// fn bench_set_dummy() { +/// new_test_ext().execute_with(|| { +/// assert_ok!(test_benchmark_set_dummy::()); +/// } +/// } +/// +/// #[test] +/// fn bench_sort_vector() { +/// new_test_ext().execute_with(|| { +/// assert_ok!(test_benchmark_sort_vector::()); +/// } +/// } +/// } +/// ``` +/// /// ## Arguments /// /// The first argument, `module`, must be the path to this crate's module. @@ -1109,16 +1355,50 @@ macro_rules! impl_benchmark_test { // just iterate over the `Benchmarking::benchmarks` list to run the actual implementations. #[macro_export] macro_rules! impl_benchmark_test_suite { + ( + $bench_module:ident, + $new_test_ext:expr, + $test:path + $(, $( $rest:tt )* )? + ) => { + $crate::impl_test_function!( + () + () + () + $bench_module, + $new_test_ext, + $test + $(, $( $rest )* )? + ); + } +} + +// Takes all arguments from `impl_benchmark_test_suite` and three additional arguments. +// +// Can be configured to generate one #[test] fn per bench case or +// one #[test] fn for all bench cases. +// This depends on whether or not the first argument contains a non-empty list of bench names. +#[macro_export] +#[doc(hidden)] +macro_rules! impl_test_function { // user might or might not have set some keyword arguments; set the defaults // // The weird syntax indicates that `rest` comes only after a comma, which is otherwise optional ( + ( $( $names:tt )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + $bench_module:ident, $new_test_ext:expr, $test:path $(, $( $rest:tt )* )? ) => { - $crate::impl_benchmark_test_suite!( + $crate::impl_test_function!( + @cases: + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) @selected: $bench_module, $new_test_ext, @@ -1132,6 +1412,10 @@ macro_rules! impl_benchmark_test_suite { }; // pick off the benchmarks_path keyword argument ( + @cases: + ( $( $names:tt )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) @selected: $bench_module:ident, $new_test_ext:expr, @@ -1143,7 +1427,11 @@ macro_rules! impl_benchmark_test_suite { benchmarks_path = $benchmarks_path:ident $(, $( $rest:tt )* )? ) => { - $crate::impl_benchmark_test_suite!( + $crate::impl_test_function!( + @cases: + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) @selected: $bench_module, $new_test_ext, @@ -1157,6 +1445,10 @@ macro_rules! impl_benchmark_test_suite { }; // pick off the extra keyword argument ( + @cases: + ( $( $names:tt )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) @selected: $bench_module:ident, $new_test_ext:expr, @@ -1168,7 +1460,11 @@ macro_rules! impl_benchmark_test_suite { extra = $extra:expr $(, $( $rest:tt )* )? ) => { - $crate::impl_benchmark_test_suite!( + $crate::impl_test_function!( + @cases: + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) @selected: $bench_module, $new_test_ext, @@ -1182,6 +1478,10 @@ macro_rules! impl_benchmark_test_suite { }; // pick off the exec_name keyword argument ( + @cases: + ( $( $names:tt )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) @selected: $bench_module:ident, $new_test_ext:expr, @@ -1193,7 +1493,11 @@ macro_rules! impl_benchmark_test_suite { exec_name = $exec_name:ident $(, $( $rest:tt )* )? ) => { - $crate::impl_benchmark_test_suite!( + $crate::impl_test_function!( + @cases: + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) @selected: $bench_module, $new_test_ext, @@ -1205,8 +1509,34 @@ macro_rules! impl_benchmark_test_suite { $( $( $rest )* )? ); }; - // all options set; nothing else in user-provided keyword arguments + // iteration-exit arm which generates a #[test] function for each case. + ( + @cases: + ( $( $names:tt )+ ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + @selected: + $bench_module:ident, + $new_test_ext:expr, + $test:path, + benchmarks_path = $path_to_benchmarks_invocation:ident, + extra = $extra:expr, + exec_name = $exec_name:ident, + @user: + $(,)? + ) => { + $crate::impl_bench_case_tests!( + { $bench_module, $new_test_ext, $exec_name, $test, $extra } + { $( $names_extra:tt )* } + $($names)+ + ); + }; + // iteration-exit arm which generates one #[test] function for all cases. ( + @cases: + () + () + () @selected: $bench_module:ident, $new_test_ext:expr, diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index caccebd39c70b..0ad156ce5a88d 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -173,11 +173,11 @@ mod benchmarks { } verify { ensure!(m[0] == 0, "You forgot to sort!") } - } - crate::impl_benchmark_test_suite!( - Pallet, - crate::tests_instance::new_test_ext(), - crate::tests_instance::Test - ); + impl_benchmark_test_suite!( + Pallet, + crate::tests_instance::new_test_ext(), + crate::tests_instance::Test + ) + } } diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 1aa1eabdb5177..33af02fbb9ea0 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -209,6 +209,6 @@ benchmarks! { ensure!(missed_any == false, "Missed some"); assert_last_event::(Event::BountyBecameActive(b - 1).into()) } -} -impl_benchmark_test_suite!(Bounties, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Bounties, crate::tests::new_test_ext(), crate::tests::Test) +} diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index c7e695babf27d..c26a2b43f5b75 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -23,9 +23,7 @@ use crate::Pallet as Collective; use sp_runtime::traits::Bounded; use sp_std::mem::size_of; -use frame_benchmarking::{ - account, benchmarks_instance_pallet, impl_benchmark_test_suite, whitelisted_caller, -}; +use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller}; use frame_system::{Call as SystemCall, Pallet as System, RawOrigin as SystemOrigin}; const SEED: u32 = 0; @@ -638,6 +636,6 @@ benchmarks_instance_pallet! { assert_eq!(Collective::::proposals().len(), (p - 1) as usize); assert_last_event::(Event::Disapproved(last_hash).into()); } -} -impl_benchmark_test_suite!(Collective, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Collective, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 981af218ea5a2..e382e616f27fd 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -36,7 +36,7 @@ use crate::{ Pallet as Contracts, *, }; use codec::Encode; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_support::weights::Weight; use frame_system::RawOrigin; use pwasm_utils::parity_wasm::elements::{BlockType, BrTableData, Instruction, ValueType}; @@ -2325,10 +2325,10 @@ benchmarks! { ) .result?; } -} -impl_benchmark_test_suite!( - Contracts, - crate::tests::ExtBuilder::default().build(), - crate::tests::Test, -); + impl_benchmark_test_suite!( + Contracts, + crate::tests::ExtBuilder::default().build(), + crate::tests::Test, + ) +} diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index 63d409dac25a7..34bcb0da301e6 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -19,7 +19,7 @@ use super::*; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelist_account}; +use frame_benchmarking::{account, benchmarks, whitelist_account}; use frame_support::{ assert_noop, assert_ok, codec::Decode, @@ -70,7 +70,7 @@ fn add_referendum(n: u32) -> Result { let referendum_index: ReferendumIndex = ReferendumCount::::get() - 1; T::Scheduler::schedule_named( (DEMOCRACY_ID, referendum_index).encode(), - DispatchTime::At(1u32.into()), + DispatchTime::At(2u32.into()), None, 63, frame_system::RawOrigin::Root.into(), @@ -802,6 +802,10 @@ benchmarks! { Err(Error::::PreimageInvalid.into()) ); } -} -impl_benchmark_test_suite!(Democracy, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!( + Democracy, + crate::tests::new_test_ext(), + crate::tests::Test + ); +} diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 24f823a17e10d..50b245006fa24 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -149,7 +149,7 @@ //! - `cancel_queued` - Cancels a proposal that is queued for enactment. //! - `clear_public_proposal` - Removes all public proposals. -#![recursion_limit = "128"] +#![recursion_limit = "256"] #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode, Input}; diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index b8d7bc45c4487..9648b8e0f2465 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -19,7 +19,7 @@ use super::*; use crate::{unsigned::IndexAssignmentOf, Pallet as MultiPhase}; -use frame_benchmarking::{account, impl_benchmark_test_suite}; +use frame_benchmarking::account; use frame_support::{assert_ok, traits::Hooks}; use frame_system::RawOrigin; use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng}; @@ -497,10 +497,10 @@ frame_benchmarking::benchmarks! { log!(trace, "actual encoded size = {}", encoding.len()); assert!(encoding.len() <= desired_size); } -} -impl_benchmark_test_suite!( - MultiPhase, - crate::mock::ExtBuilder::default().build_offchainify(10).0, - crate::mock::Runtime, -); + impl_benchmark_test_suite!( + MultiPhase, + crate::mock::ExtBuilder::default().build_offchainify(10).0, + crate::mock::Runtime, + ); +} diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 6e3ce0234c4fb..9bc63848607ab 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -21,9 +21,7 @@ use super::*; -use frame_benchmarking::{ - account, benchmarks, impl_benchmark_test_suite, whitelist, BenchmarkError, BenchmarkResult, -}; +use frame_benchmarking::{account, benchmarks, whitelist, BenchmarkError, BenchmarkResult}; use frame_support::{ dispatch::{DispatchResultWithPostInfo, UnfilteredDispatchable}, traits::OnInitialize, @@ -549,11 +547,11 @@ benchmarks! { MEMBERS.with(|m| *m.borrow_mut() = vec![]); } } -} -impl_benchmark_test_suite!( - Elections, - crate::tests::ExtBuilder::default().desired_members(13).desired_runners_up(7), - crate::tests::Test, - exec_name = build_and_execute, -); + impl_benchmark_test_suite!( + Elections, + crate::tests::ExtBuilder::default().desired_members(13).desired_runners_up(7), + crate::tests::Test, + exec_name = build_and_execute, + ); +} diff --git a/frame/example/src/benchmarking.rs b/frame/example/src/benchmarking.rs index cdf6c152a4880..9f2bb20fe63ac 100644 --- a/frame/example/src/benchmarking.rs +++ b/frame/example/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use crate::*; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{benchmarks, whitelisted_caller}; use frame_system::RawOrigin; // To actually run this benchmark on pallet-example, we need to put this pallet into the @@ -65,12 +65,14 @@ benchmarks! { // The benchmark execution phase could also be a closure with custom code m.sort(); } -} -// This line generates test cases for benchmarking, and could be run by: -// `cargo test -p pallet-example --all-features`, you will see an additional line of: -// `test benchmarking::benchmark_tests::test_benchmarks ... ok` in the result. -// -// The line generates three steps per benchmark, with repeat=1 and the three steps are -// [low, mid, high] of the range. -impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); + // This line generates test cases for benchmarking, and could be run by: + // `cargo test -p pallet-example --all-features`, you will see one line per case: + // `test benchmarking::bench_sort_vector ... ok` + // `test benchmarking::bench_accumulate_dummy ... ok` + // `test benchmarking::bench_set_dummy_benchmark ... ok` in the result. + // + // The line generates three steps per benchmark, with repeat=1 and the three steps are + // [low, mid, high] of the range. + impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test) +} diff --git a/frame/gilt/src/benchmarking.rs b/frame/gilt/src/benchmarking.rs index cfc503cf897b4..9c6d22a48398d 100644 --- a/frame/gilt/src/benchmarking.rs +++ b/frame/gilt/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{benchmarks, whitelisted_caller}; use frame_support::{ dispatch::UnfilteredDispatchable, traits::{Currency, EnsureOrigin, Get}, @@ -126,6 +126,6 @@ benchmarks! { .dispatch_bypass_filter(T::AdminOrigin::successful_origin())?; }: { Gilt::::pursue_target(q) } -} -impl_benchmark_test_suite!(Gilt, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Gilt, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/grandpa/src/benchmarking.rs b/frame/grandpa/src/benchmarking.rs index 815a18d13531e..1e6be01ce8dbf 100644 --- a/frame/grandpa/src/benchmarking.rs +++ b/frame/grandpa/src/benchmarking.rs @@ -68,6 +68,12 @@ benchmarks! { verify { assert!(Grandpa::::stalled().is_some()); } + + impl_benchmark_test_suite!( + Pallet, + crate::mock::new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), + crate::mock::Test, + ); } #[cfg(test)] @@ -75,12 +81,6 @@ mod tests { use super::*; use crate::mock::*; - frame_benchmarking::impl_benchmark_test_suite!( - Pallet, - crate::mock::new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), - crate::mock::Test, - ); - #[test] fn test_generate_equivocation_report_blob() { let authorities = crate::tests::test_authorities(); diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 8bda24ddc73e1..68869a43992f9 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -22,7 +22,7 @@ use super::*; use crate::Pallet as Identity; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_support::{ensure, traits::Get}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -411,6 +411,5 @@ benchmarks! { ensure!(!SuperOf::::contains_key(&caller), "Sub not removed"); } + impl_benchmark_test_suite!(Identity, crate::tests::new_test_ext(), crate::tests::Test); } - -impl_benchmark_test_suite!(Identity, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/frame/im-online/src/benchmarking.rs b/frame/im-online/src/benchmarking.rs index b39b0057c48e8..012da53a183e5 100644 --- a/frame/im-online/src/benchmarking.rs +++ b/frame/im-online/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; +use frame_benchmarking::benchmarks; use frame_support::{traits::UnfilteredDispatchable, WeakBoundedVec}; use frame_system::RawOrigin; use sp_core::{offchain::OpaqueMultiaddr, OpaquePeerId}; @@ -100,6 +100,6 @@ benchmarks! { .expect("call is encoded above, encoding must be correct") .dispatch_bypass_filter(RawOrigin::None.into())?; } -} -impl_benchmark_test_suite!(ImOnline, crate::mock::new_test_ext(), crate::mock::Runtime); + impl_benchmark_test_suite!(ImOnline, crate::mock::new_test_ext(), crate::mock::Runtime); +} diff --git a/frame/indices/src/benchmarking.rs b/frame/indices/src/benchmarking.rs index ba0152008c41e..873dc18b20265 100644 --- a/frame/indices/src/benchmarking.rs +++ b/frame/indices/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -91,6 +91,6 @@ benchmarks! { } // TODO in another PR: lookup and unlookup trait weights (not critical) -} -impl_benchmark_test_suite!(Indices, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Indices, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index 7af20bbb0e11f..5407e16cd633f 100644 --- a/frame/lottery/src/benchmarking.rs +++ b/frame/lottery/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_support::traits::{EnsureOrigin, OnInitialize}; use frame_system::RawOrigin; use sp_runtime::traits::{Bounded, Zero}; @@ -163,6 +163,6 @@ benchmarks! { assert_eq!(Lottery::::pot().1, 0u32.into()); assert!(!T::Currency::free_balance(&winner).is_zero()) } -} -impl_benchmark_test_suite!(Lottery, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Lottery, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 57a12c7c8a453..8fa2abb0ad3f3 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -357,9 +357,7 @@ impl, I: 'static> SortedMembers for Pallet { #[cfg(feature = "runtime-benchmarks")] mod benchmark { use super::{Pallet as Membership, *}; - use frame_benchmarking::{ - account, benchmarks_instance_pallet, impl_benchmark_test_suite, whitelist, - }; + use frame_benchmarking::{account, benchmarks_instance_pallet, whitelist}; use frame_support::{assert_ok, traits::EnsureOrigin}; use frame_system::RawOrigin; @@ -494,9 +492,9 @@ mod benchmark { assert!(::get_prime().is_none()); #[cfg(test)] crate::tests::clean(); } - } - impl_benchmark_test_suite!(Membership, crate::tests::new_bench_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Membership, crate::tests::new_bench_ext(), crate::tests::Test); + } } #[cfg(test)] diff --git a/frame/merkle-mountain-range/src/benchmarking.rs b/frame/merkle-mountain-range/src/benchmarking.rs index c269afb75855c..d6ef76d01ac3a 100644 --- a/frame/merkle-mountain-range/src/benchmarking.rs +++ b/frame/merkle-mountain-range/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Benchmarks for the MMR pallet. use crate::*; -use frame_benchmarking::{benchmarks_instance_pallet, impl_benchmark_test_suite}; +use frame_benchmarking::benchmarks_instance_pallet; use frame_support::traits::OnInitialize; benchmarks_instance_pallet! { @@ -33,6 +33,6 @@ benchmarks_instance_pallet! { } verify { assert_eq!(crate::NumberOfLeaves::::get(), leaves); } -} -impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::mock::Test); +} diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index 2e23dff156e07..edfeba253e5f0 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use core::convert::TryInto; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite}; +use frame_benchmarking::{account, benchmarks}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -297,6 +297,6 @@ benchmarks! { assert!(!Multisigs::::contains_key(multi_account_id, call_hash)); assert!(!Calls::::contains_key(call_hash)); } -} -impl_benchmark_test_suite!(Multisig, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Multisig, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 35e3c1aec9403..dde8aa92c2405 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -23,7 +23,7 @@ mod mock; use sp_std::{prelude::*, vec}; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite}; +use frame_benchmarking::{account, benchmarks}; use frame_support::traits::{Currency, ValidatorSet, ValidatorSetWithIdentification}; use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; @@ -399,6 +399,6 @@ benchmarks! { + n // nominators slashed ); } -} -impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index 83db82990d105..4da712dadf27b 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -42,5 +42,6 @@ std = [ runtime-benchmarks = [ "frame-benchmarking", "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index e66f6782c19e1..1eb3ec5770544 100644 --- a/frame/proxy/src/benchmarking.rs +++ b/frame/proxy/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use crate::Pallet as Proxy; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -245,6 +245,6 @@ benchmarks! { verify { assert!(!Proxies::::contains_key(&anon)); } -} -impl_benchmark_test_suite!(Proxy, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Proxy, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 2c164eaede229..1065f17027744 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; +use frame_benchmarking::benchmarks; use frame_support::{ensure, traits::OnInitialize}; use frame_system::RawOrigin; use sp_std::{prelude::*, vec}; @@ -139,6 +139,6 @@ benchmarks! { "didn't append schedule" ); } -} -impl_benchmark_test_suite!(Scheduler, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Scheduler, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index c0131957c8732..8ca713b1bbf61 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -24,7 +24,7 @@ mod mock; use sp_std::{prelude::*, vec}; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; +use frame_benchmarking::benchmarks; use frame_support::{ codec::Decode, traits::{KeyOwnerProofSystem, OnInitialize}, @@ -115,6 +115,8 @@ benchmarks! { verify { assert!(Historical::::check_proof(key, key_owner_proof2).is_some()); } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test, extra = false); } /// Sets up the benchmark for checking a membership proof. It creates the given @@ -161,5 +163,3 @@ fn check_membership_proof_setup( (key, Historical::::prove(key).unwrap()) } - -impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test, extra = false); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index fe60d516e144c..220e8f1e6a24c 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -887,6 +887,13 @@ benchmarks! { verify { assert!(!T::SortedListProvider::contains(&stash)); } + + impl_benchmark_test_suite!( + Staking, + crate::mock::ExtBuilder::default().has_stakers(true), + crate::mock::Test, + exec_name = build_and_execute + ); } #[cfg(test)] @@ -1001,10 +1008,3 @@ mod tests { }); } } - -impl_benchmark_test_suite!( - Staking, - crate::mock::ExtBuilder::default().has_stakers(true), - crate::mock::Test, - exec_name = build_and_execute -); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index d8e72e267ea9a..582e9e49bd356 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -272,6 +272,7 @@ //! validators is stored in the Session pallet's `Validators` at the end of each era. #![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit = "256"] #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; diff --git a/frame/system/benchmarking/src/lib.rs b/frame/system/benchmarking/src/lib.rs index beb61829bce37..e7371b1099e5e 100644 --- a/frame/system/benchmarking/src/lib.rs +++ b/frame/system/benchmarking/src/lib.rs @@ -20,7 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::Encode; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{benchmarks, whitelisted_caller}; use frame_support::{storage, traits::Get, weights::DispatchClass}; use frame_system::{Call, DigestItemOf, Pallet as System, RawOrigin}; use sp_core::{storage::well_known_keys, ChangesTrieConfiguration}; @@ -140,6 +140,6 @@ benchmarks! { verify { assert_eq!(storage::unhashed::get_raw(&last_key), None); } -} -impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/timestamp/src/benchmarking.rs b/frame/timestamp/src/benchmarking.rs index 97ddd4cddd63f..98e05439df72b 100644 --- a/frame/timestamp/src/benchmarking.rs +++ b/frame/timestamp/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, TrackedStorageKey}; +use frame_benchmarking::{benchmarks, TrackedStorageKey}; use frame_support::{ensure, traits::OnFinalize}; use frame_system::RawOrigin; @@ -55,6 +55,6 @@ benchmarks! { verify { ensure!(!DidUpdate::::exists(), "Time was not removed."); } -} -impl_benchmark_test_suite!(Timestamp, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Timestamp, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 5e08121855210..d8227332bb334 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -19,7 +19,7 @@ #![cfg(feature = "runtime-benchmarks")] -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_support::ensure; use frame_system::RawOrigin; use sp_runtime::traits::Saturating; @@ -190,6 +190,6 @@ benchmarks! { let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary)); ensure!(Tips::::contains_key(hash), "tip does not exist"); }: _(RawOrigin::Root, hash) -} -impl_benchmark_test_suite!(TipsMod, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(TipsMod, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs index d5da6a42b46f0..6ca9b247f0228 100644 --- a/frame/transaction-storage/src/benchmarking.rs +++ b/frame/transaction-storage/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{benchmarks, whitelisted_caller}; use frame_support::traits::{Currency, OnFinalize, OnInitialize}; use frame_system::{EventRecord, Pallet as System, RawOrigin}; use sp_runtime::traits::{Bounded, One, Zero}; @@ -143,6 +143,6 @@ benchmarks! { verify { assert_last_event::(Event::ProofChecked.into()); } -} -impl_benchmark_test_suite!(TransactionStorage, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(TransactionStorage, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index 2fe0bad704f2b..8570b0efdb945 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::{Pallet as Treasury, *}; -use frame_benchmarking::{account, benchmarks_instance_pallet, impl_benchmark_test_suite}; +use frame_benchmarking::{account, benchmarks_instance_pallet}; use frame_support::{ensure, traits::OnInitialize}; use frame_system::RawOrigin; @@ -94,6 +94,6 @@ benchmarks_instance_pallet! { }: { Treasury::::on_initialize(T::BlockNumber::zero()); } -} -impl_benchmark_test_suite!(Treasury, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Treasury, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 5c777dc961e9e..0e161bf7bfe85 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -21,8 +21,7 @@ use super::*; use frame_benchmarking::{ - account, benchmarks_instance_pallet, impl_benchmark_test_suite, whitelist_account, - whitelisted_caller, + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, }; use frame_support::{ dispatch::UnfilteredDispatchable, @@ -379,6 +378,6 @@ benchmarks_instance_pallet! { verify { assert_last_event::(Event::ApprovalCancelled(class, instance, caller, delegate).into()); } -} -impl_benchmark_test_suite!(Uniques, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Uniques, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index 210a6156499cf..70cc61f87b9c9 100644 --- a/frame/utility/src/benchmarking.rs +++ b/frame/utility/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_system::RawOrigin; const SEED: u32 = 0; @@ -63,6 +63,6 @@ benchmarks! { verify { assert_last_event::(Event::BatchCompleted.into()) } -} -impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/frame/vesting/src/benchmarking.rs b/frame/vesting/src/benchmarking.rs index 5cdc14c8fdaca..b52ddac3e8857 100644 --- a/frame/vesting/src/benchmarking.rs +++ b/frame/vesting/src/benchmarking.rs @@ -19,7 +19,7 @@ #![cfg(feature = "runtime-benchmarks")] -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_support::assert_ok; use frame_system::{Pallet as System, RawOrigin}; use sp_runtime::traits::{Bounded, CheckedDiv, CheckedMul}; @@ -374,10 +374,10 @@ benchmarks! { T::Currency::transfer(&caller, &test_dest, expected_balance, ExistenceRequirement::AllowDeath) ); } -} -impl_benchmark_test_suite!( - Vesting, - crate::mock::ExtBuilder::default().existential_deposit(256).build(), - crate::mock::Test, -); + impl_benchmark_test_suite!( + Vesting, + crate::mock::ExtBuilder::default().existential_deposit(256).build(), + crate::mock::Test, + ); +} From c1e45a62103ce7f0b3db4926f40c38b4b1283fa9 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 1 Oct 2021 17:43:55 +0800 Subject: [PATCH 0058/1472] Clean up sc-peerset (#9806) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Clean up sc-peerset * cargo +nightly fmt --all * Nit * Nit * . * Nit * . * Apply suggestions from code review * . * Update client/peerset/src/peersstate.rs Co-authored-by: Bastian Köcher --- client/network/src/config.rs | 10 ++-- .../src/protocol/notifications/behaviour.rs | 4 +- client/network/src/transactions.rs | 17 +++--- client/peerset/Cargo.toml | 1 - client/peerset/src/lib.rs | 49 +++++++++-------- client/peerset/src/peersstate.rs | 53 +++++++++---------- 6 files changed, 62 insertions(+), 72 deletions(-) diff --git a/client/network/src/config.rs b/client/network/src/config.rs index d08e29ef8589f..76c806ccbf7b6 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -155,14 +155,14 @@ pub enum Role { } impl Role { - /// True for `Role::Authority` + /// True for [`Role::Authority`]. pub fn is_authority(&self) -> bool { - matches!(self, Role::Authority { .. }) + matches!(self, Self::Authority { .. }) } - /// True for `Role::Light` + /// True for [`Role::Light`]. pub fn is_light(&self) -> bool { - matches!(self, Role::Light { .. }) + matches!(self, Self::Light { .. }) } } @@ -329,7 +329,7 @@ impl FromStr for MultiaddrWithPeerId { fn from_str(s: &str) -> Result { let (peer_id, multiaddr) = parse_str_addr(s)?; - Ok(MultiaddrWithPeerId { peer_id, multiaddr }) + Ok(Self { peer_id, multiaddr }) } } diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index da2967d6f26eb..01138e3207570 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -417,7 +417,7 @@ impl Notifications { /// Returns true if we have an open substream to the given peer. pub fn is_open(&self, peer_id: &PeerId, set_id: sc_peerset::SetId) -> bool { - self.peers.get(&(peer_id.clone(), set_id)).map(|p| p.is_open()).unwrap_or(false) + self.peers.get(&(*peer_id, set_id)).map(|p| p.is_open()).unwrap_or(false) } /// Disconnects the given peer if we are connected to it. @@ -1777,7 +1777,7 @@ impl NetworkBehaviour for Notifications { "Handler({}, {:?}) => CloseResult({:?})", source, connection, set_id); - match self.peers.get_mut(&(source.clone(), set_id)) { + match self.peers.get_mut(&(source, set_id)) { // Move the connection from `Closing` to `Closed`. Some(PeerState::Incoming { connections, .. }) | Some(PeerState::DisabledPendingEnable { connections, .. }) | diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 82e7e8fe1714c..9565466ea1c07 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -92,7 +92,7 @@ struct Metrics { impl Metrics { fn register(r: &Registry) -> Result { - Ok(Metrics { + Ok(Self { propagated_transactions: register( Counter::new( "sync_propagated_transactions", @@ -133,7 +133,7 @@ pub struct TransactionsHandlerPrototype { impl TransactionsHandlerPrototype { /// Create a new instance. pub fn new(protocol_id: ProtocolId) -> Self { - TransactionsHandlerPrototype { + Self { protocol_name: Cow::from({ let mut proto = String::new(); proto.push_str("/"); @@ -401,7 +401,7 @@ impl TransactionsHandler { let hash = self.transaction_pool.hash_of(&t); peer.known_transactions.insert(hash.clone()); - self.service.report_peer(who.clone(), rep::ANY_TRANSACTION); + self.service.report_peer(who, rep::ANY_TRANSACTION); match self.pending_transactions_peers.entry(hash.clone()) { Entry::Vacant(entry) => { @@ -409,10 +409,10 @@ impl TransactionsHandler { validation: self.transaction_pool.import(t), tx_hash: hash, }); - entry.insert(vec![who.clone()]); + entry.insert(vec![who]); }, Entry::Occupied(mut entry) => { - entry.get_mut().push(who.clone()); + entry.get_mut().push(who); }, } } @@ -468,11 +468,8 @@ impl TransactionsHandler { propagated_to.entry(hash).or_default().push(who.to_base58()); } trace!(target: "sync", "Sending {} transactions to {}", to_send.len(), who); - self.service.write_notification( - who.clone(), - self.protocol_name.clone(), - to_send.encode(), - ); + self.service + .write_notification(*who, self.protocol_name.clone(), to_send.encode()); } } diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index 5962620d6e06e..a7e9130cfff1c 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -13,7 +13,6 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] futures = "0.3.9" libp2p = { version = "0.39.1", default-features = false } diff --git a/client/peerset/src/lib.rs b/client/peerset/src/lib.rs index 0775354befee4..7fbda1ba7b7f8 100644 --- a/client/peerset/src/lib.rs +++ b/client/peerset/src/lib.rs @@ -79,13 +79,13 @@ pub struct SetId(usize); impl SetId { pub const fn from(id: usize) -> Self { - SetId(id) + Self(id) } } impl From for SetId { fn from(id: usize) -> Self { - SetId(id) + Self(id) } } @@ -107,12 +107,12 @@ pub struct ReputationChange { impl ReputationChange { /// New reputation change with given delta and reason. pub const fn new(value: i32, reason: &'static str) -> ReputationChange { - ReputationChange { value, reason } + Self { value, reason } } /// New reputation change that forces minimum possible reputation. pub const fn new_fatal(reason: &'static str) -> ReputationChange { - ReputationChange { value: i32::MIN, reason } + Self { value: i32::MIN, reason } } } @@ -208,8 +208,8 @@ pub enum Message { pub struct IncomingIndex(pub u64); impl From for IncomingIndex { - fn from(val: u64) -> IncomingIndex { - IncomingIndex(val) + fn from(val: u64) -> Self { + Self(val) } } @@ -274,7 +274,7 @@ pub struct Peerset { impl Peerset { /// Builds a new peerset from the given configuration. - pub fn from_config(config: PeersetConfig) -> (Peerset, PeersetHandle) { + pub fn from_config(config: PeersetConfig) -> (Self, PeersetHandle) { let (tx, rx) = tracing_unbounded("mpsc_peerset_messages"); let handle = PeersetHandle { tx: tx.clone() }; @@ -282,7 +282,7 @@ impl Peerset { let mut peerset = { let now = Instant::now(); - Peerset { + Self { data: peersstate::PeersState::new(config.sets.iter().map(|set| { peersstate::SetConfig { in_peers: set.in_peers, out_peers: set.out_peers } })), @@ -322,7 +322,7 @@ impl Peerset { } fn on_add_reserved_peer(&mut self, set_id: SetId, peer_id: PeerId) { - let newly_inserted = self.reserved_nodes[set_id.0].0.insert(peer_id.clone()); + let newly_inserted = self.reserved_nodes[set_id.0].0.insert(peer_id); if !newly_inserted { return } @@ -422,8 +422,7 @@ impl Peerset { match self.data.peer(set_id.0, &peer_id) { peersstate::Peer::Connected(peer) => { - self.message_queue - .push_back(Message::Drop { set_id, peer_id: peer.peer_id().clone() }); + self.message_queue.push_back(Message::Drop { set_id, peer_id: *peer.peer_id() }); peer.disconnect().forget_peer(); }, peersstate::Peer::NotConnected(peer) => { @@ -819,8 +818,8 @@ mod tests { }; let (peerset, handle) = Peerset::from_config(config); - handle.add_reserved_peer(SetId::from(0), reserved_peer.clone()); - handle.add_reserved_peer(SetId::from(0), reserved_peer2.clone()); + handle.add_reserved_peer(SetId::from(0), reserved_peer); + handle.add_reserved_peer(SetId::from(0), reserved_peer2); assert_messages( peerset, @@ -845,22 +844,22 @@ mod tests { sets: vec![SetConfig { in_peers: 2, out_peers: 1, - bootnodes: vec![bootnode.clone()], + bootnodes: vec![bootnode], reserved_nodes: Default::default(), reserved_only: false, }], }; let (mut peerset, _handle) = Peerset::from_config(config); - peerset.incoming(SetId::from(0), incoming.clone(), ii); - peerset.incoming(SetId::from(0), incoming.clone(), ii4); - peerset.incoming(SetId::from(0), incoming2.clone(), ii2); - peerset.incoming(SetId::from(0), incoming3.clone(), ii3); + peerset.incoming(SetId::from(0), incoming, ii); + peerset.incoming(SetId::from(0), incoming, ii4); + peerset.incoming(SetId::from(0), incoming2, ii2); + peerset.incoming(SetId::from(0), incoming3, ii3); assert_messages( peerset, vec![ - Message::Connect { set_id: SetId::from(0), peer_id: bootnode.clone() }, + Message::Connect { set_id: SetId::from(0), peer_id: bootnode }, Message::Accept(ii), Message::Accept(ii2), Message::Reject(ii3), @@ -883,7 +882,7 @@ mod tests { }; let (mut peerset, _) = Peerset::from_config(config); - peerset.incoming(SetId::from(0), incoming.clone(), ii); + peerset.incoming(SetId::from(0), incoming, ii); assert_messages(peerset, vec![Message::Reject(ii)]); } @@ -897,15 +896,15 @@ mod tests { sets: vec![SetConfig { in_peers: 0, out_peers: 2, - bootnodes: vec![bootnode.clone()], + bootnodes: vec![bootnode], reserved_nodes: Default::default(), reserved_only: false, }], }; let (mut peerset, _handle) = Peerset::from_config(config); - peerset.add_to_peers_set(SetId::from(0), discovered.clone()); - peerset.add_to_peers_set(SetId::from(0), discovered.clone()); + peerset.add_to_peers_set(SetId::from(0), discovered); + peerset.add_to_peers_set(SetId::from(0), discovered); peerset.add_to_peers_set(SetId::from(0), discovered2); assert_messages( @@ -931,7 +930,7 @@ mod tests { // We ban a node by setting its reputation under the threshold. let peer_id = PeerId::random(); - handle.report_peer(peer_id.clone(), ReputationChange::new(BANNED_THRESHOLD - 1, "")); + handle.report_peer(peer_id, ReputationChange::new(BANNED_THRESHOLD - 1, "")); let fut = futures::future::poll_fn(move |cx| { // We need one polling for the message to be processed. @@ -974,7 +973,7 @@ mod tests { // We ban a node by setting its reputation under the threshold. let peer_id = PeerId::random(); - handle.report_peer(peer_id.clone(), ReputationChange::new(BANNED_THRESHOLD - 1, "")); + handle.report_peer(peer_id, ReputationChange::new(BANNED_THRESHOLD - 1, "")); let fut = futures::future::poll_fn(move |cx| { // We need one polling for the message to be processed. diff --git a/client/peerset/src/peersstate.rs b/client/peerset/src/peersstate.rs index 7717620eae3a7..d7a9ef9135876 100644 --- a/client/peerset/src/peersstate.rs +++ b/client/peerset/src/peersstate.rs @@ -105,8 +105,8 @@ struct Node { } impl Node { - fn new(num_sets: usize) -> Node { - Node { sets: (0..num_sets).map(|_| MembershipState::NotMember).collect(), reputation: 0 } + fn new(num_sets: usize) -> Self { + Self { sets: (0..num_sets).map(|_| MembershipState::NotMember).collect(), reputation: 0 } } } @@ -128,21 +128,24 @@ enum MembershipState { } impl MembershipState { - /// Returns `true` for `In` and `Out`. + /// Returns `true` for [`MembershipState::In`] and [`MembershipState::Out`]. fn is_connected(self) -> bool { match self { - MembershipState::NotMember => false, - MembershipState::In => true, - MembershipState::Out => true, - MembershipState::NotConnected { .. } => false, + Self::In | Self::Out => true, + Self::NotMember | Self::NotConnected { .. } => false, } } + + /// Returns `true` for [`MembershipState::NotConnected`]. + fn is_not_connected(self) -> bool { + matches!(self, Self::NotConnected { .. }) + } } impl PeersState { - /// Builds a new empty `PeersState`. + /// Builds a new empty [`PeersState`]. pub fn new(sets: impl IntoIterator) -> Self { - PeersState { + Self { nodes: HashMap::new(), sets: sets .into_iter() @@ -242,12 +245,7 @@ impl PeersState { let outcome = self .nodes .iter_mut() - .filter(|(_, Node { sets, .. })| match sets[set] { - MembershipState::NotMember => false, - MembershipState::In => false, - MembershipState::Out => false, - MembershipState::NotConnected { .. } => true, - }) + .filter(|(_, Node { sets, .. })| sets[set].is_not_connected()) .fold(None::<(&PeerId, &mut Node)>, |mut cur_node, to_try| { if let Some(cur_node) = cur_node.take() { if cur_node.1.reputation >= to_try.1.reputation { @@ -318,35 +316,32 @@ pub enum Peer<'a> { } impl<'a> Peer<'a> { - /// If we are the `Connected` variant, returns the inner `ConnectedPeer`. Returns `None` + /// If we are the `Connected` variant, returns the inner [`ConnectedPeer`]. Returns `None` /// otherwise. pub fn into_connected(self) -> Option> { match self { - Peer::Connected(peer) => Some(peer), - Peer::NotConnected(_) => None, - Peer::Unknown(_) => None, + Self::Connected(peer) => Some(peer), + Self::NotConnected(..) | Self::Unknown(..) => None, } } - /// If we are the `Unknown` variant, returns the inner `ConnectedPeer`. Returns `None` + /// If we are the `NotConnected` variant, returns the inner [`NotConnectedPeer`]. Returns `None` /// otherwise. #[cfg(test)] // Feel free to remove this if this function is needed outside of tests pub fn into_not_connected(self) -> Option> { match self { - Peer::Connected(_) => None, - Peer::NotConnected(peer) => Some(peer), - Peer::Unknown(_) => None, + Self::NotConnected(peer) => Some(peer), + Self::Connected(..) | Self::Unknown(..) => None, } } - /// If we are the `Unknown` variant, returns the inner `ConnectedPeer`. Returns `None` + /// If we are the `Unknown` variant, returns the inner [`UnknownPeer`]. Returns `None` /// otherwise. #[cfg(test)] // Feel free to remove this if this function is needed outside of tests pub fn into_unknown(self) -> Option> { match self { - Peer::Connected(_) => None, - Peer::NotConnected(_) => None, - Peer::Unknown(peer) => Some(peer), + Self::Unknown(peer) => Some(peer), + Self::Connected(..) | Self::NotConnected(..) => None, } } } @@ -473,7 +468,7 @@ impl<'a> NotConnectedPeer<'a> { /// the slots are full, the node stays "not connected" and we return `Err`. /// /// Non-slot-occupying nodes don't count towards the number of slots. - pub fn try_outgoing(self) -> Result, NotConnectedPeer<'a>> { + pub fn try_outgoing(self) -> Result, Self> { let is_no_slot_occupy = self.state.sets[self.set].no_slot_nodes.contains(&*self.peer_id); // Note that it is possible for num_out to be strictly superior to the max, in case we were @@ -500,7 +495,7 @@ impl<'a> NotConnectedPeer<'a> { /// the slots are full, the node stays "not connected" and we return `Err`. /// /// Non-slot-occupying nodes don't count towards the number of slots. - pub fn try_accept_incoming(self) -> Result, NotConnectedPeer<'a>> { + pub fn try_accept_incoming(self) -> Result, Self> { let is_no_slot_occupy = self.state.sets[self.set].no_slot_nodes.contains(&*self.peer_id); // Note that it is possible for num_in to be strictly superior to the max, in case we were From 540b4fd0f6bf8157f5402f0095f78f0ed893c57b Mon Sep 17 00:00:00 2001 From: RyuH1 <79819095+RyuH1@users.noreply.github.com> Date: Fri, 1 Oct 2021 19:22:13 +0800 Subject: [PATCH 0059/1472] Add SS58 prefix for Automata (#9805) --- primitives/core/src/crypto.rs | 4 ++++ ss58-registry.json | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index cf7be5f2166e8..a9f3e904a2a85 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -617,8 +617,12 @@ ss58_address_format!( (1284, "moonbeam", "Moonbeam, session key (*25519).") Moonriver => (1285, "moonriver", "Moonriver, session key (*25519).") + Automata => + (2349, "automata", "Automata mainnet standard account (*25519).") BasiliskAccount => (10041, "basilisk", "Basilisk standard account (*25519).") + ContextFree => + (11820, "contextfree", "Automata ContextFree standard account (*25519).") // Note: 16384 and above are reserved. ); diff --git a/ss58-registry.json b/ss58-registry.json index 7c95f421586a4..62602d829f6b8 100644 --- a/ss58-registry.json +++ b/ss58-registry.json @@ -640,6 +640,15 @@ "standardAccount": "secp256k1", "website": "https://moonbeam.network" }, + { + "prefix": 2349, + "network": "automata", + "displayName": "Automata Mainnet", + "symbols": ["ATA"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://ata.network" + }, { "prefix": 10041, "network": "basilisk", @@ -648,6 +657,15 @@ "decimals": [12], "standardAccount": "*25519", "website": "https://bsx.fi" + }, + { + "prefix": 11820, + "network": "contextfree", + "displayName": "Automata ContextFree", + "symbols": ["CTX"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://ata.network" } ] } From c60ccc0719ea2036d3878b94bd9257c9332f5606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 1 Oct 2021 16:25:13 +0200 Subject: [PATCH 0060/1472] Quickly skip invalid transactions during block authorship. (#9789) * Support skipping invalid transactions in the iterator. * Expose concrete iterator. * cargo +nightly fmt --all * More consistent placement. * Update Cargo.lock * Pass transaction to 'report_invalid' --- bin/node/bench/src/construct.rs | 28 +++-- .../basic-authorship/src/basic_authorship.rs | 8 +- client/transaction-pool/api/src/lib.rs | 28 ++++- client/transaction-pool/graph/Cargo.toml | 39 ------ .../transaction-pool/src/graph/base_pool.rs | 4 +- client/transaction-pool/src/graph/ready.rs | 114 +++++++++++++++--- .../src/graph/validated_pool.rs | 4 +- client/transaction-pool/src/lib.rs | 5 +- 8 files changed, 159 insertions(+), 71 deletions(-) delete mode 100644 client/transaction-pool/graph/Cargo.toml diff --git a/bin/node/bench/src/construct.rs b/bin/node/bench/src/construct.rs index 1532e02bd3ef6..ca1a1c18f9ea9 100644 --- a/bin/node/bench/src/construct.rs +++ b/bin/node/bench/src/construct.rs @@ -30,8 +30,8 @@ use std::{borrow::Cow, collections::HashMap, pin::Pin, sync::Arc}; use node_primitives::Block; use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile}; use sc_transaction_pool_api::{ - ImportNotificationStream, PoolFuture, PoolStatus, TransactionFor, TransactionSource, - TransactionStatusStreamFor, TxHash, + ImportNotificationStream, PoolFuture, PoolStatus, ReadyTransactions, TransactionFor, + TransactionSource, TransactionStatusStreamFor, TxHash, }; use sp_consensus::{Environment, Proposer}; use sp_inherents::InherentDataProvider; @@ -216,6 +216,19 @@ impl sc_transaction_pool_api::InPoolTransaction for PoolTransaction { #[derive(Clone, Debug)] pub struct Transactions(Vec>); +pub struct TransactionsIterator(std::vec::IntoIter>); + +impl Iterator for TransactionsIterator { + type Item = Arc; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +impl ReadyTransactions for TransactionsIterator { + fn report_invalid(&mut self, _tx: &Self::Item) {} +} impl sc_transaction_pool_api::TransactionPool for Transactions { type Block = Block; @@ -257,16 +270,17 @@ impl sc_transaction_pool_api::TransactionPool for Transactions { _at: NumberFor, ) -> Pin< Box< - dyn Future> + Send>> - + Send, + dyn Future< + Output = Box> + Send>, + > + Send, >, > { - let iter: Box> + Send> = - Box::new(self.0.clone().into_iter()); + let iter: Box> + Send> = + Box::new(TransactionsIterator(self.0.clone().into_iter())); Box::pin(futures::future::ready(iter)) } - fn ready(&self) -> Box> + Send> { + fn ready(&self) -> Box> + Send> { unimplemented!() } diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index e38bb11688f8b..bbee60ae98dcf 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -344,7 +344,7 @@ where let mut t2 = futures_timer::Delay::new(deadline.saturating_duration_since((self.now)()) / 8).fuse(); - let pending_iterator = select! { + let mut pending_iterator = select! { res = t1 => res, _ = t2 => { log::warn!( @@ -363,7 +363,7 @@ where let mut transaction_pushed = false; let mut hit_block_size_limit = false; - for pending_tx in pending_iterator { + while let Some(pending_tx) = pending_iterator.next() { if (self.now)() > deadline { debug!( "Consensus deadline reached when pushing block transactions, \ @@ -378,6 +378,7 @@ where let block_size = block_builder.estimate_block_size(self.include_proof_in_block_size_estimation); if block_size + pending_tx_data.encoded_size() > block_size_limit { + pending_iterator.report_invalid(&pending_tx); if skipped < MAX_SKIPPED_TRANSACTIONS { skipped += 1; debug!( @@ -400,6 +401,7 @@ where debug!("[{:?}] Pushed to the block.", pending_tx_hash); }, Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() => { + pending_iterator.report_invalid(&pending_tx); if skipped < MAX_SKIPPED_TRANSACTIONS { skipped += 1; debug!( @@ -412,6 +414,7 @@ where } }, Err(e) if skipped > 0 => { + pending_iterator.report_invalid(&pending_tx); trace!( "[{:?}] Ignoring invalid transaction when skipping: {}", pending_tx_hash, @@ -419,6 +422,7 @@ where ); }, Err(e) => { + pending_iterator.report_invalid(&pending_tx); debug!("[{:?}] Invalid transaction: {}", pending_tx_hash, e); unqueue_invalid.push(pending_tx_hash); }, diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index a6252f1373c5d..cd8784bfc83e2 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -223,13 +223,14 @@ pub trait TransactionPool: Send + Sync { at: NumberFor, ) -> Pin< Box< - dyn Future> + Send>> - + Send, + dyn Future< + Output = Box> + Send>, + > + Send, >, >; /// Get an iterator for ready transactions ordered by priority. - fn ready(&self) -> Box> + Send>; + fn ready(&self) -> Box> + Send>; // *** Block production /// Remove transactions identified by given hashes (and dependent transactions) from the pool. @@ -254,6 +255,27 @@ pub trait TransactionPool: Send + Sync { fn ready_transaction(&self, hash: &TxHash) -> Option>; } +/// An iterator of ready transactions. +/// +/// The trait extends regular [`std::iter::Iterator`] trait and allows reporting +/// last-returned element as invalid. +/// +/// The implementation is then allowed, for performance reasons, to change the elements +/// returned next, by e.g. skipping elements that are known to depend on the reported +/// transaction, which yields them invalid as well. +pub trait ReadyTransactions: Iterator { + /// Report given transaction as invalid. + /// + /// This might affect subsequent elements returned by the iterator, so dependent transactions + /// are skipped for performance reasons. + fn report_invalid(&mut self, _tx: &Self::Item); +} + +/// A no-op implementation for an empty iterator. +impl ReadyTransactions for std::iter::Empty { + fn report_invalid(&mut self, _tx: &T) {} +} + /// Events that the transaction pool listens for. pub enum ChainEvent { /// New best block have been added to the chain diff --git a/client/transaction-pool/graph/Cargo.toml b/client/transaction-pool/graph/Cargo.toml deleted file mode 100644 index b49cadc51c33c..0000000000000 --- a/client/transaction-pool/graph/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "sc-transaction-graph" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2018" -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" -repository = "https://github.com/paritytech/substrate/" -description = "Generic Transaction Pool" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -derive_more = "0.99.2" -thiserror = "1.0.21" -futures = "0.3.9" -log = "0.4.8" -parking_lot = "0.11.1" -serde = { version = "1.0.101", features = ["derive"] } -sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sc-utils = { version = "4.0.0-dev", path = "../../utils" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -sp-transaction-pool = { version = "4.0.0-dev", path = "../../../primitives/transaction-pool" } -parity-util-mem = { version = "0.10.0", default-features = false, features = ["primitive-types"] } -linked-hash-map = "0.5.4" -retain_mut = "0.1.3" - -[dev-dependencies] -assert_matches = "1.3.0" -codec = { package = "parity-scale-codec", version = "2.0.0" } -substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } -criterion = "0.3" - -[[bench]] -name = "basics" -harness = false diff --git a/client/transaction-pool/src/graph/base_pool.rs b/client/transaction-pool/src/graph/base_pool.rs index 890a87e82929d..2c8becdfb2f0b 100644 --- a/client/transaction-pool/src/graph/base_pool.rs +++ b/client/transaction-pool/src/graph/base_pool.rs @@ -36,7 +36,7 @@ use sp_runtime::{ use super::{ future::{FutureTransactions, WaitingTransaction}, - ready::ReadyTransactions, + ready::{BestIterator, ReadyTransactions}, }; /// Successful import result. @@ -355,7 +355,7 @@ impl BasePool impl Iterator>> { + pub fn ready(&self) -> BestIterator { self.ready.get() } diff --git a/client/transaction-pool/src/graph/ready.rs b/client/transaction-pool/src/graph/ready.rs index 03689aeb32e6d..99a034689ccd0 100644 --- a/client/transaction-pool/src/graph/ready.rs +++ b/client/transaction-pool/src/graph/ready.rs @@ -23,7 +23,7 @@ use std::{ sync::Arc, }; -use log::trace; +use log::{debug, trace}; use sc_transaction_pool_api::error; use serde::Serialize; use sp_runtime::{traits::Member, transaction_validity::TransactionTag as Tag}; @@ -156,11 +156,16 @@ impl ReadyTransactions { /// - transactions that are valid for a shorter time go first /// 4. Lastly we sort by the time in the queue /// - transactions that are longer in the queue go first - pub fn get(&self) -> impl Iterator>> { + /// + /// The iterator is providing a way to report transactions that the receiver considers invalid. + /// In such case the entire subgraph of transactions that depend on the reported one will be + /// skipped. + pub fn get(&self) -> BestIterator { BestIterator { all: self.ready.clone(), best: self.best.clone(), awaiting: Default::default(), + invalid: Default::default(), } } @@ -482,6 +487,7 @@ pub struct BestIterator { all: ReadOnlyTrackedMap>, awaiting: HashMap)>, best: BTreeSet>, + invalid: HashSet, } impl BestIterator { @@ -498,6 +504,34 @@ impl BestIterator { } } +impl sc_transaction_pool_api::ReadyTransactions + for BestIterator +{ + fn report_invalid(&mut self, tx: &Self::Item) { + BestIterator::report_invalid(self, tx) + } +} + +impl BestIterator { + /// Report given transaction as invalid. + /// + /// As a consequence, all values that depend on the invalid one will be skipped. + /// When given transaction is not in the pool it has no effect. + /// When invoked on a fully drained iterator it has no effect either. + pub fn report_invalid(&mut self, tx: &Arc>) { + if let Some(to_report) = self.all.read().get(&tx.hash) { + debug!( + target: "txpool", + "[{:?}] Reported as invalid. Will skip sub-chains while iterating.", + to_report.transaction.transaction.hash + ); + for hash in &to_report.unlocks { + self.invalid.insert(hash.clone()); + } + } + } +} + impl Iterator for BestIterator { type Item = Arc>; @@ -505,8 +539,19 @@ impl Iterator for BestIterator { loop { let best = self.best.iter().next_back()?.clone(); let best = self.best.take(&best)?; + let hash = &best.transaction.hash; + + // Check if the transaction was marked invalid. + if self.invalid.contains(hash) { + debug!( + target: "txpool", + "[{:?}] Skipping invalid child transaction while iterating.", + hash + ); + continue + } - let next = self.all.read().get(&best.transaction.hash).cloned(); + let next = self.all.read().get(hash).cloned(); let ready = match next { Some(ready) => ready, // The transaction is not in all, maybe it was removed in the meantime? @@ -635,10 +680,13 @@ mod tests { assert_eq!(ready.get().count(), 3); } - #[test] - fn should_return_best_transactions_in_correct_order() { - // given - let mut ready = ReadyTransactions::default(); + /// Populate the pool, with a graph that looks like so: + /// + /// tx1 -> tx2 \ + /// -> -> tx3 + /// -> tx4 -> tx5 -> tx6 + /// -> tx7 + fn populate_pool(ready: &mut ReadyTransactions>) { let mut tx1 = tx(1); tx1.requires.clear(); let mut tx2 = tx(2); @@ -649,11 +697,17 @@ mod tests { tx3.provides = vec![]; let mut tx4 = tx(4); tx4.requires = vec![tx1.provides[0].clone()]; - tx4.provides = vec![]; - let tx5 = Transaction { - data: vec![5], + tx4.provides = vec![vec![107]]; + let mut tx5 = tx(5); + tx5.requires = vec![tx4.provides[0].clone()]; + tx5.provides = vec![vec![108]]; + let mut tx6 = tx(6); + tx6.requires = vec![tx5.provides[0].clone()]; + tx6.provides = vec![]; + let tx7 = Transaction { + data: vec![7], bytes: 1, - hash: 5, + hash: 7, priority: 1, valid_till: u64::MAX, // use the max here for testing. requires: vec![tx1.provides[0].clone()], @@ -663,20 +717,30 @@ mod tests { }; // when - for tx in vec![tx1, tx2, tx3, tx4, tx5] { - import(&mut ready, tx).unwrap(); + for tx in vec![tx1, tx2, tx3, tx7, tx4, tx5, tx6] { + import(ready, tx).unwrap(); } - // then assert_eq!(ready.best.len(), 1); + } + + #[test] + fn should_return_best_transactions_in_correct_order() { + // given + let mut ready = ReadyTransactions::default(); + populate_pool(&mut ready); + // when let mut it = ready.get().map(|tx| tx.data[0]); + // then assert_eq!(it.next(), Some(1)); assert_eq!(it.next(), Some(2)); assert_eq!(it.next(), Some(3)); assert_eq!(it.next(), Some(4)); assert_eq!(it.next(), Some(5)); + assert_eq!(it.next(), Some(6)); + assert_eq!(it.next(), Some(7)); assert_eq!(it.next(), None); } @@ -725,4 +789,26 @@ mod tests { TransactionRef { transaction: Arc::new(with_priority(3, 3)), insertion_id: 2 } ); } + + #[test] + fn should_skip_invalid_transactions_while_iterating() { + // given + let mut ready = ReadyTransactions::default(); + populate_pool(&mut ready); + + // when + let mut it = ready.get(); + let data = |tx: &Arc>>| tx.data[0]; + + // then + assert_eq!(it.next().as_ref().map(data), Some(1)); + assert_eq!(it.next().as_ref().map(data), Some(2)); + assert_eq!(it.next().as_ref().map(data), Some(3)); + let tx4 = it.next(); + assert_eq!(tx4.as_ref().map(data), Some(4)); + // report 4 as invalid, which should skip 5 & 6. + it.report_invalid(&tx4.unwrap()); + assert_eq!(it.next().as_ref().map(data), Some(7)); + assert_eq!(it.next().as_ref().map(data), None); + } } diff --git a/client/transaction-pool/src/graph/validated_pool.rs b/client/transaction-pool/src/graph/validated_pool.rs index e4aad7f342b5b..dba586adc846c 100644 --- a/client/transaction-pool/src/graph/validated_pool.rs +++ b/client/transaction-pool/src/graph/validated_pool.rs @@ -25,7 +25,7 @@ use std::{ use futures::channel::mpsc::{channel, Sender}; use parking_lot::{Mutex, RwLock}; use retain_mut::RetainMut; -use sc_transaction_pool_api::{error, PoolStatus}; +use sc_transaction_pool_api::{error, PoolStatus, ReadyTransactions}; use serde::Serialize; use sp_runtime::{ generic::BlockId, @@ -630,7 +630,7 @@ impl ValidatedPool { } /// Get an iterator for ready transactions ordered by priority - pub fn ready(&self) -> impl Iterator> + Send { + pub fn ready(&self) -> impl ReadyTransactions> + Send { self.pool.read().ready() } diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 6eb5bd2f332ec..4d355df22d821 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -56,7 +56,8 @@ use std::{ use graph::{ExtrinsicHash, IsValidator}; use sc_transaction_pool_api::{ ChainEvent, ImportNotificationStream, MaintainedTransactionPool, PoolFuture, PoolStatus, - TransactionFor, TransactionPool, TransactionSource, TransactionStatusStreamFor, TxHash, + ReadyTransactions, TransactionFor, TransactionPool, TransactionSource, + TransactionStatusStreamFor, TxHash, }; use sp_core::traits::SpawnEssentialNamed; use sp_runtime::{ @@ -69,7 +70,7 @@ use crate::metrics::MetricsLink as PrometheusMetrics; use prometheus_endpoint::Registry as PrometheusRegistry; type BoxedReadyIterator = - Box>> + Send>; + Box>> + Send>; type ReadyIteratorFor = BoxedReadyIterator, graph::ExtrinsicFor>; From fdce20c70e0e12f1e9011f6d253a47421014131b Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Sat, 2 Oct 2021 03:11:37 -0500 Subject: [PATCH 0061/1472] Implement core::fmt::Debug for BoundedVec (#9914) --- frame/support/src/storage/bounded_vec.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 44eaab905423b..f353127969c5b 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -200,13 +200,12 @@ impl Default for BoundedVec { } } -#[cfg(feature = "std")] -impl std::fmt::Debug for BoundedVec +impl sp_std::fmt::Debug for BoundedVec where - T: std::fmt::Debug, + T: sp_std::fmt::Debug, S: Get, { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { f.debug_tuple("BoundedVec").field(&self.0).field(&Self::bound()).finish() } } From df6a1ad92a066a8af0f6a1b327cbb26b3f0c89c1 Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Sat, 2 Oct 2021 02:27:06 -0600 Subject: [PATCH 0062/1472] Downstream `node-template` pull (#9915) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * downstream node template pull: README updated, add shell.nix * consistant cargo.toml style * Update bin/node-template/shell.nix Co-authored-by: Bastian Köcher --- .maintain/node-template-release/Cargo.lock | 616 ++++++++++++++++++ bin/node-template/README.md | 113 ++-- bin/node-template/node/Cargo.toml | 8 +- bin/node-template/pallets/template/Cargo.toml | 11 +- bin/node-template/runtime/Cargo.toml | 5 +- bin/node-template/shell.nix | 35 + 6 files changed, 729 insertions(+), 59 deletions(-) create mode 100644 .maintain/node-template-release/Cargo.lock create mode 100644 bin/node-template/shell.nix diff --git a/.maintain/node-template-release/Cargo.lock b/.maintain/node-template-release/Cargo.lock new file mode 100644 index 0000000000000..ee562498c811c --- /dev/null +++ b/.maintain/node-template-release/Cargo.lock @@ -0,0 +1,616 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "curl-sys" +version = "0.4.48+curl-7.79.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a77a741f832116da66aeb126b4f19190ecf46144a74a9bde43c2086f38da0e" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "winapi", +] + +[[package]] +name = "filetime" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi", +] + +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + +[[package]] +name = "fs_extra" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "git2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7339329bfa14a00223244311560d11f8f489b453fb90092af97f267a6090ab0" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "glob" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[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.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" + +[[package]] +name = "libgit2-sys" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48441cb35dc255da8ae72825689a95368bf510659ae1ad55dc4aa88cb1789bf1" +dependencies = [ + "cc", + "curl-sys", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libssh2-sys" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0186af0d8f171ae6b9c4c90ec51898bad5d08a2d5e470903a50d9ad8959cbee" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "node-template-release" +version = "3.0.0" +dependencies = [ + "flate2", + "fs_extra", + "git2", + "glob", + "structopt", + "tar", + "tempfile", + "toml", +] + +[[package]] +name = "openssl-probe" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" + +[[package]] +name = "openssl-sys" +version = "0.9.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" + +[[package]] +name = "pkg-config" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[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", + "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.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[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", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tar" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f5515d3add52e0bbdcad7b83c388bb36ba7b754dda3b5f5bc2d38640cdba5c" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tinyvec" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" +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.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +dependencies = [ + "idna", + "matches", + "percent-encoding", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +dependencies = [ + "libc", +] diff --git a/bin/node-template/README.md b/bin/node-template/README.md index cd977fac84493..e618b13c2a2f0 100644 --- a/bin/node-template/README.md +++ b/bin/node-template/README.md @@ -1,10 +1,21 @@ # Substrate Node Template +[![Try on playground](https://img.shields.io/badge/Playground-Node_Template-brightgreen?logo=Parity%20Substrate)](https://playground.substrate.dev/?deploy=node-template) [![Matrix](https://img.shields.io/matrix/substrate-technical:matrix.org)](https://matrix.to/#/#substrate-technical:matrix.org) + A fresh FRAME-based [Substrate](https://www.substrate.io/) node, ready for hacking :rocket: ## Getting Started -Follow these steps to get started with the Node Template :hammer_and_wrench: +Follow the steps below to get started with the Node Template, or get it up and running right from +your browser in just a few clicks using [Playground](https://playground.substrate.dev/) +:hammer_and_wrench: + +### Using Nix + +Install [nix](https://nixos.org/) and optionally [direnv](https://github.com/direnv/direnv) and +[lorri](https://github.com/target/lorri) for a fully plug and play experience for setting up the +development environment. To get all the correct dependencies activate direnv `direnv allow` and +lorri `lorri shell`. ### Rust Setup @@ -62,10 +73,17 @@ Start the development chain with detailed logging: RUST_BACKTRACE=1 ./target/release/node-template -ldebug --dev ``` +### Connect with Polkadot-JS Apps Front-end + +Once the node template is running locally, you can connect it with **Polkadot-JS Apps** front-end +to interact with your chain. [Click +here](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944) connecting the Apps to your +local node template. + ### Multi-Node Local Testnet -If you want to see the multi-node consensus algorithm in action, refer to -[our Start a Private Network tutorial](https://substrate.dev/docs/en/tutorials/start-a-private-network/). +If you want to see the multi-node consensus algorithm in action, refer to our +[Start a Private Network tutorial](https://substrate.dev/docs/en/tutorials/start-a-private-network/). ## Template Structure @@ -77,34 +95,34 @@ directories. A blockchain node is an application that allows users to participate in a blockchain network. Substrate-based blockchain nodes expose a number of capabilities: -- Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking stack to allow the - nodes in the network to communicate with one another. -- Consensus: Blockchains must have a way to come to - [consensus](https://substrate.dev/docs/en/knowledgebase/advanced/consensus) on the state of the - network. Substrate makes it possible to supply custom consensus engines and also ships with - several consensus mechanisms that have been built on top of - [Web3 Foundation research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html). -- RPC Server: A remote procedure call (RPC) server is used to interact with Substrate nodes. +- Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking stack to allow the + nodes in the network to communicate with one another. +- Consensus: Blockchains must have a way to come to + [consensus](https://substrate.dev/docs/en/knowledgebase/advanced/consensus) on the state of the + network. Substrate makes it possible to supply custom consensus engines and also ships with + several consensus mechanisms that have been built on top of + [Web3 Foundation research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html). +- RPC Server: A remote procedure call (RPC) server is used to interact with Substrate nodes. There are several files in the `node` directory - take special note of the following: -- [`chain_spec.rs`](./node/src/chain_spec.rs): A - [chain specification](https://substrate.dev/docs/en/knowledgebase/integrate/chain-spec) is a - source code file that defines a Substrate chain's initial (genesis) state. Chain specifications - are useful for development and testing, and critical when architecting the launch of a - production chain. Take note of the `development_config` and `testnet_genesis` functions, which - are used to define the genesis state for the local development chain configuration. These - functions identify some - [well-known accounts](https://substrate.dev/docs/en/knowledgebase/integrate/subkey#well-known-keys) - and use them to configure the blockchain's initial state. -- [`service.rs`](./node/src/service.rs): This file defines the node implementation. Take note of - the libraries that this file imports and the names of the functions it invokes. In particular, - there are references to consensus-related topics, such as the - [longest chain rule](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#longest-chain-rule), - the [Aura](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#aura) block authoring - mechanism and the - [GRANDPA](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#grandpa) finality - gadget. +- [`chain_spec.rs`](./node/src/chain_spec.rs): A + [chain specification](https://substrate.dev/docs/en/knowledgebase/integrate/chain-spec) is a + source code file that defines a Substrate chain's initial (genesis) state. Chain specifications + are useful for development and testing, and critical when architecting the launch of a + production chain. Take note of the `development_config` and `testnet_genesis` functions, which + are used to define the genesis state for the local development chain configuration. These + functions identify some + [well-known accounts](https://substrate.dev/docs/en/knowledgebase/integrate/subkey#well-known-keys) + and use them to configure the blockchain's initial state. +- [`service.rs`](./node/src/service.rs): This file defines the node implementation. Take note of + the libraries that this file imports and the names of the functions it invokes. In particular, + there are references to consensus-related topics, such as the + [longest chain rule](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#longest-chain-rule), + the [Aura](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#aura) block authoring + mechanism and the + [GRANDPA](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#grandpa) finality + gadget. After the node has been [built](#build), refer to the embedded documentation to learn more about the capabilities and configuration parameters that it exposes: @@ -130,13 +148,13 @@ create pallets and flexibly compose them to create blockchains that can address Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this template and note the following: -- This file configures several pallets to include in the runtime. Each pallet configuration is - defined by a code block that begins with `impl $PALLET_NAME::Config for Runtime`. -- The pallets are composed into a single runtime by way of the - [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html) - macro, which is part of the core - [FRAME Support](https://substrate.dev/docs/en/knowledgebase/runtime/frame#support-library) - library. +- This file configures several pallets to include in the runtime. Each pallet configuration is + defined by a code block that begins with `impl $PALLET_NAME::Config for Runtime`. +- The pallets are composed into a single runtime by way of the + [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html) + macro, which is part of the core + [FRAME Support](https://substrate.dev/docs/en/knowledgebase/runtime/frame#support-library) + library. ### Pallets @@ -146,17 +164,17 @@ template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs A FRAME pallet is compromised of a number of blockchain primitives: -- Storage: FRAME defines a rich set of powerful - [storage abstractions](https://substrate.dev/docs/en/knowledgebase/runtime/storage) that makes - it easy to use Substrate's efficient key-value database to manage the evolving state of a - blockchain. -- Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched) - from outside of the runtime in order to update its state. -- Events: Substrate uses [events](https://substrate.dev/docs/en/knowledgebase/runtime/events) to - notify users of important changes in the runtime. -- Errors: When a dispatchable fails, it returns an error. -- Config: The `Config` configuration interface is used to define the types and parameters upon - which a FRAME pallet depends. +- Storage: FRAME defines a rich set of powerful + [storage abstractions](https://substrate.dev/docs/en/knowledgebase/runtime/storage) that makes + it easy to use Substrate's efficient key-value database to manage the evolving state of a + blockchain. +- Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched) + from outside of the runtime in order to update its state. +- Events: Substrate uses [events](https://substrate.dev/docs/en/knowledgebase/runtime/events) to + notify users of important changes in the runtime. +- Errors: When a dispatchable fails, it returns an error. +- Config: The `Config` configuration interface is used to define the types and parameters upon + which a FRAME pallet depends. ### Run in Docker @@ -170,7 +188,8 @@ Then run the following command to start a single node development chain. ``` This command will firstly compile your code, and then start a local development network. You can -also replace the default command (`cargo build --release && ./target/release/node-template --dev --ws-external`) +also replace the default command +(`cargo build --release && ./target/release/node-template --dev --ws-external`) by appending your own. A few useful ones are as follow. ```bash diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 04d70b338ac04..c8f2b52f112f5 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "node-template" version = "3.0.0" -authors = ["Substrate DevHub "] description = "A fresh FRAME-based Substrate node, ready for hacking." +authors = ["Substrate DevHub "] +homepage = "https://substrate.dev" edition = "2018" license = "Unlicense" -build = "build.rs" -homepage = "https://substrate.dev" -repository = "https://github.com/substrate-developer-hub/substrate-node-template/" publish = false +repository = "https://github.com/substrate-developer-hub/substrate-node-template/" +build = "build.rs" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index b3eb747625b4f..dccb37c6540c3 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -1,14 +1,13 @@ [package] -authors = ['Substrate DevHub '] -edition = '2018' name = 'pallet-template' version = "3.0.0" -license = "Unlicense" -homepage = "https://substrate.dev" -repository = "https://github.com/substrate-developer-hub/substrate-node-template/" description = "FRAME pallet template for defining custom runtime logic." -readme = "README.md" +authors = ['Substrate DevHub '] +homepage = "https://substrate.dev" +edition = '2018' +license = "Unlicense" publish = false +repository = "https://github.com/substrate-developer-hub/substrate-node-template/" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 47e67af2b9ae1..081e458b18e08 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "node-template-runtime" version = "3.0.0" +description = 'A fresh FRAME-based Substrate runtime, ready for hacking.' authors = ["Substrate DevHub "] +homepage = "https://substrate.dev" edition = "2018" license = "Unlicense" -homepage = "https://substrate.dev" -repository = "https://github.com/substrate-developer-hub/substrate-node-template/" publish = false +repository = "https://github.com/substrate-developer-hub/substrate-node-template/" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/bin/node-template/shell.nix b/bin/node-template/shell.nix new file mode 100644 index 0000000000000..c08005c1630e9 --- /dev/null +++ b/bin/node-template/shell.nix @@ -0,0 +1,35 @@ +let + mozillaOverlay = + import (builtins.fetchGit { + url = "https://github.com/mozilla/nixpkgs-mozilla.git"; + rev = "57c8084c7ef41366993909c20491e359bbb90f54"; + }); + pinned = builtins.fetchGit { + # Descriptive name to make the store path easier to identify + url = "https://github.com/nixos/nixpkgs/"; + # Commit hash for nixos-unstable as of 2020-04-26 + # `git ls-remote https://github.com/nixos/nixpkgs nixos-unstable` + ref = "refs/heads/nixos-unstable"; + rev = "1fe6ed37fd9beb92afe90671c0c2a662a03463dd"; + }; + nixpkgs = import pinned { overlays = [ mozillaOverlay ]; }; + toolchain = with nixpkgs; (rustChannelOf { date = "2021-09-14"; channel = "nightly"; }); + rust-wasm = toolchain.rust.override { + targets = [ "wasm32-unknown-unknown" ]; + }; +in +with nixpkgs; pkgs.mkShell { + buildInputs = [ + clang + pkg-config + rust-wasm + ] ++ stdenv.lib.optionals stdenv.isDarwin [ + darwin.apple_sdk.frameworks.Security + ]; + + LIBCLANG_PATH = "${llvmPackages.libclang}/lib"; + PROTOC = "${protobuf}/bin/protoc"; + RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library/"; + ROCKSDB_LIB_DIR = "${rocksdb}/lib"; + +} From c775344b5a27ccdb5b1f17ef553a195411f7ae83 Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Sat, 2 Oct 2021 13:01:07 -0600 Subject: [PATCH 0063/1472] rm `.maintain` lock (#9919) * rm maintain lock * ignore template gen lockfile --- .gitignore | 1 + .maintain/node-template-release/Cargo.lock | 616 --------------------- 2 files changed, 1 insertion(+), 616 deletions(-) delete mode 100644 .maintain/node-template-release/Cargo.lock diff --git a/.gitignore b/.gitignore index 0486a1a716e5c..07aa596f6df24 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ rls*.log .cargo-remote.toml *.bin *.iml +.maintain/node-template-release/Cargo.lock diff --git a/.maintain/node-template-release/Cargo.lock b/.maintain/node-template-release/Cargo.lock deleted file mode 100644 index ee562498c811c..0000000000000 --- a/.maintain/node-template-release/Cargo.lock +++ /dev/null @@ -1,616 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "cc" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "2.33.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - -[[package]] -name = "crc32fast" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "curl-sys" -version = "0.4.48+curl-7.79.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a77a741f832116da66aeb126b4f19190ecf46144a74a9bde43c2086f38da0e" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "winapi", -] - -[[package]] -name = "filetime" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "winapi", -] - -[[package]] -name = "flate2" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" -dependencies = [ - "cfg-if", - "crc32fast", - "libc", - "miniz_oxide", -] - -[[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - -[[package]] -name = "getrandom" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "git2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7339329bfa14a00223244311560d11f8f489b453fb90092af97f267a6090ab0" -dependencies = [ - "bitflags", - "libc", - "libgit2-sys", - "log", - "openssl-probe", - "openssl-sys", - "url", -] - -[[package]] -name = "glob" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[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.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" - -[[package]] -name = "libgit2-sys" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48441cb35dc255da8ae72825689a95368bf510659ae1ad55dc4aa88cb1789bf1" -dependencies = [ - "cc", - "curl-sys", - "libc", - "libssh2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", -] - -[[package]] -name = "libssh2-sys" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0186af0d8f171ae6b9c4c90ec51898bad5d08a2d5e470903a50d9ad8959cbee" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libz-sys" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - -[[package]] -name = "node-template-release" -version = "3.0.0" -dependencies = [ - "flate2", - "fs_extra", - "git2", - "glob", - "structopt", - "tar", - "tempfile", - "toml", -] - -[[package]] -name = "openssl-probe" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" - -[[package]] -name = "openssl-sys" -version = "0.9.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - -[[package]] -name = "pkg-config" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb" - -[[package]] -name = "ppv-lite86" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" - -[[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", - "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.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[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", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redox_syscall" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" -dependencies = [ - "bitflags", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "serde" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "structopt" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "syn" -version = "1.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "tar" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f5515d3add52e0bbdcad7b83c388bb36ba7b754dda3b5f5bc2d38640cdba5c" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "tempfile" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" -dependencies = [ - "cfg-if", - "libc", - "rand", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "tinyvec" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" -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.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -dependencies = [ - "serde", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" - -[[package]] -name = "unicode-normalization" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna", - "matches", - "percent-encoding", -] - -[[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.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - -[[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-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "xattr" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" -dependencies = [ - "libc", -] From 9be8fdd36a70e19cd286bec00df740331b637546 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 3 Oct 2021 15:15:30 +0200 Subject: [PATCH 0064/1472] Ensure BeforeBestBlockBy voting rule accounts for base (#9920) * Ensure BeforeBestBlockBy voting rule accounts for base * fmt Co-authored-by: Andronik Ordian --- client/finality-grandpa/src/voting_rule.rs | 48 ++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/client/finality-grandpa/src/voting_rule.rs b/client/finality-grandpa/src/voting_rule.rs index b974afe0d352e..7c8d94d970f86 100644 --- a/client/finality-grandpa/src/voting_rule.rs +++ b/client/finality-grandpa/src/voting_rule.rs @@ -80,8 +80,14 @@ where } /// A custom voting rule that guarantees that our vote is always behind the best -/// block by at least N blocks. In the best case our vote is exactly N blocks -/// behind the best block. +/// block by at least N blocks, unless the base number is < N blocks behind the +/// best, in which case it votes for the base. +/// +/// In the best case our vote is exactly N blocks +/// behind the best block, but if there is a scenario where either +/// >34% of validators run without this rule or the fork-choice rule +/// can prioritize shorter chains over longer ones, the vote may be +/// closer to the best block than N. #[derive(Clone)] pub struct BeforeBestBlockBy(N); impl VotingRule for BeforeBestBlockBy> @@ -92,7 +98,7 @@ where fn restrict_vote( &self, backend: Arc, - _base: &Block::Header, + base: &Block::Header, best_target: &Block::Header, current_target: &Block::Header, ) -> VotingRuleResult { @@ -102,6 +108,12 @@ where return Box::pin(async { None }) } + // Constrain to the base number, if that's the minimal + // vote that can be placed. + if *base.number() + self.0 > *best_target.number() { + return Box::pin(std::future::ready(Some((base.hash(), *base.number())))) + } + // find the target number restricted by this rule let target_number = best_target.number().saturating_sub(self.0); @@ -393,4 +405,34 @@ mod tests { // only one of the rules is applied. assert_eq!(number, 150); } + + #[test] + fn before_best_by_has_cutoff_at_base() { + let rule = BeforeBestBlockBy(2); + + let mut client = Arc::new(TestClientBuilder::new().build()); + + for _ in 0..5 { + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + + futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); + } + + let best = client.header(&BlockId::Hash(client.info().best_hash)).unwrap().unwrap(); + let best_number = best.number().clone(); + + for i in 0u32..5 { + let base = client.header(&BlockId::Number(i.into())).unwrap().unwrap(); + let (_, number) = futures::executor::block_on(rule.restrict_vote( + client.clone(), + &base, + &best, + &best, + )) + .unwrap(); + + let expected = std::cmp::max(best_number - 2, *base.number()); + assert_eq!(number, expected, "best = {}, lag = 2, base = {}", best_number, i); + } + } } From 5413a1f0d996874b97032fafd3284854df14b4d1 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Sun, 3 Oct 2021 17:09:26 +0100 Subject: [PATCH 0065/1472] add clippy to CI (#9694) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Focus on correctness lints. This relies on a compiler patch that landed 8th July 2021. If people are using an earlier version of the compiler everything will still work unless they try and run clippy. Co-authored-by: Bastian Köcher Co-authored-by: Denis Pisarev --- .cargo/config.toml | 14 ++++++++++++++ .gitignore | 1 - .gitlab-ci.yml | 9 ++++++++- client/executor/src/wasm_runtime.rs | 2 +- client/network/src/block_request_handler.rs | 3 ++- client/network/src/state_request_handler.rs | 1 + frame/support/src/traits/metadata.rs | 17 ++++++++++------- 7 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000000000..06328af71459c --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,14 @@ +# +# An auto defined `clippy` feature was introduced, +# but it was found to clash with user defined features, +# so was renamed to `cargo-clippy`. +# +# If you want standard clippy run: +# RUSTFLAGS= cargo clippy +[target.'cfg(feature = "cargo-clippy")'] +rustflags = [ + "-Aclippy::all", + "-Dclippy::correctness", + "-Aclippy::if-same-then-else", + "-Aclippy::clone-double-ref" +] diff --git a/.gitignore b/.gitignore index 07aa596f6df24..f1103fdab93a5 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,6 @@ rls*.log .local **/hfuzz_target/ **/hfuzz_workspace/ -.cargo/ .cargo-remote.toml *.bin *.iml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fa986923708d3..0d150d96deedc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -311,7 +311,7 @@ cargo-deny: when: always paths: - deny.log - # FIXME: Temorarily allow to fail. + # FIXME: Temporarily allow to fail. allow_failure: true cargo-fmt: @@ -321,6 +321,13 @@ cargo-fmt: script: - cargo +nightly fmt --all -- --check +cargo-clippy: + stage: test + <<: *docker-env + <<: *test-refs + script: + - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo +nightly clippy + cargo-check-benches: stage: test <<: *docker-env diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index b3a981d9e0821..4c768b7f9c613 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -304,7 +304,7 @@ pub fn create_wasm_runtime_with_code( // // We drop the cache_path here to silence warnings that cache_path is not used if // compiling without the `wasmtime` flag. - drop(cache_path); + let _ = cache_path; sc_executor_wasmi::create_runtime( blob, diff --git a/client/network/src/block_request_handler.rs b/client/network/src/block_request_handler.rs index 9411ca71fd009..3ea7833970d9e 100644 --- a/client/network/src/block_request_handler.rs +++ b/client/network/src/block_request_handler.rs @@ -85,13 +85,14 @@ struct SeenRequestsKey { support_multiple_justifications: bool, } +#[allow(clippy::derive_hash_xor_eq)] impl Hash for SeenRequestsKey { fn hash(&self, state: &mut H) { self.peer.hash(state); self.max_blocks.hash(state); self.direction.hash(state); self.attributes.hash(state); - + self.support_multiple_justifications.hash(state); match self.from { BlockId::Hash(h) => h.hash(state), BlockId::Number(n) => n.hash(state), diff --git a/client/network/src/state_request_handler.rs b/client/network/src/state_request_handler.rs index b4e5320ebfda8..d2e58ce955197 100644 --- a/client/network/src/state_request_handler.rs +++ b/client/network/src/state_request_handler.rs @@ -78,6 +78,7 @@ struct SeenRequestsKey { start: Vec, } +#[allow(clippy::derive_hash_xor_eq)] impl Hash for SeenRequestsKey { fn hash(&self, state: &mut H) { self.peer.hash(state); diff --git a/frame/support/src/traits/metadata.rs b/frame/support/src/traits/metadata.rs index 14b7e6d7355e2..e60cf8be8a41c 100644 --- a/frame/support/src/traits/metadata.rs +++ b/frame/support/src/traits/metadata.rs @@ -78,7 +78,7 @@ pub trait GetCallMetadata { } /// The version of a crate. -#[derive(RuntimeDebug, Eq, PartialEq, Encode, Decode, Ord, Clone, Copy, Default)] +#[derive(RuntimeDebug, Eq, PartialEq, Encode, Decode, Clone, Copy, Default)] pub struct CrateVersion { /// The major version of the crate. pub major: u16, @@ -94,14 +94,17 @@ impl CrateVersion { } } -impl sp_std::cmp::PartialOrd for CrateVersion { - fn partial_cmp(&self, other: &Self) -> Option { - let res = self - .major +impl sp_std::cmp::Ord for CrateVersion { + fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + self.major .cmp(&other.major) - .then_with(|| self.minor.cmp(&other.minor).then_with(|| self.patch.cmp(&other.patch))); + .then_with(|| self.minor.cmp(&other.minor).then_with(|| self.patch.cmp(&other.patch))) + } +} - Some(res) +impl sp_std::cmp::PartialOrd for CrateVersion { + fn partial_cmp(&self, other: &Self) -> Option { + Some(::cmp(&self, other)) } } From ca90ea736c049798868055e2a6ad9ccdd737da23 Mon Sep 17 00:00:00 2001 From: Jaco Date: Mon, 4 Oct 2021 14:56:06 +0300 Subject: [PATCH 0066/1472] Small quoting comment fix (#9927) Tiny quotes fix that snuck in lately (something I picked up elsewhere in document generation) --- frame/im-online/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 2fcaed1820ff9..559c5edcf4d11 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -412,7 +412,7 @@ pub mod pallet { pub(crate) type Keys = StorageValue<_, WeakBoundedVec, ValueQuery>; - /// For each session index, we keep a mapping of 'SessionIndex` and `AuthIndex` to + /// For each session index, we keep a mapping of `SessionIndex` and `AuthIndex` to /// `WrapperOpaque`. #[pallet::storage] #[pallet::getter(fn received_heartbeats)] From 6c0c9c9aaaa3ebe4ccc4dfb3d61f721723885ac7 Mon Sep 17 00:00:00 2001 From: Koute Date: Mon, 4 Oct 2021 22:28:51 +0900 Subject: [PATCH 0067/1472] Do not propagate host RUSTFLAGS when checking for WASM toolchain (#9926) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Do not propagate host RUSTFLAGS when checking for WASM toolchain * Update utils/wasm-builder/src/prerequisites.rs * Update utils/wasm-builder/src/prerequisites.rs Co-authored-by: Bastian Köcher --- utils/wasm-builder/src/prerequisites.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/utils/wasm-builder/src/prerequisites.rs b/utils/wasm-builder/src/prerequisites.rs index 0dad8b781ae5a..c45f7933a1de3 100644 --- a/utils/wasm-builder/src/prerequisites.rs +++ b/utils/wasm-builder/src/prerequisites.rs @@ -138,6 +138,13 @@ fn check_wasm_toolchain_installed( build_cmd.env_remove("CARGO_TARGET_DIR"); run_cmd.env_remove("CARGO_TARGET_DIR"); + // Make sure the host's flags aren't used here, e.g. if an alternative linker is specified + // in the RUSTFLAGS then the check we do here will break unless we clear these. + build_cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); + run_cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); + build_cmd.env_remove("RUSTFLAGS"); + run_cmd.env_remove("RUSTFLAGS"); + build_cmd.output().map_err(|_| err_msg.clone()).and_then(|s| { if s.status.success() { let version = run_cmd.output().ok().and_then(|o| String::from_utf8(o.stdout).ok()); From a30e1b2206b0ff23ebf21b24cad8595342e96b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 4 Oct 2021 16:25:18 +0200 Subject: [PATCH 0068/1472] Rework Transaction Priority calculation (#9834) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add transaction validity docs. * Re-work priority calculation. * Fix tests. * Update frame/transaction-payment/src/lib.rs Co-authored-by: Alexander Popiak * cargo +nightly fmt --all * Fix an obvious mistake :) * Re-work again. * Fix test. * cargo +nightly fmt --all * Make VirtualTip dependent on the transaction size. * cargo +nightly fmt --all * Update frame/transaction-payment/src/lib.rs Co-authored-by: Alexander Popiak * Fix compilation. * Update bin/node/runtime/src/lib.rs Co-authored-by: Bastian Köcher Co-authored-by: Alexander Popiak Co-authored-by: Bastian Köcher --- Cargo.lock | 8 +- bin/node-template/runtime/src/lib.rs | 2 + bin/node/runtime/src/lib.rs | 2 + frame/balances/src/tests_composite.rs | 2 + frame/balances/src/tests_local.rs | 2 + frame/balances/src/tests_reentrancy.rs | 2 + frame/executive/src/lib.rs | 6 +- frame/support/src/weights.rs | 24 --- frame/system/src/extensions/check_genesis.rs | 5 + .../system/src/extensions/check_mortality.rs | 4 + frame/system/src/extensions/check_nonce.rs | 7 +- .../src/extensions/check_spec_version.rs | 5 + .../system/src/extensions/check_tx_version.rs | 5 + frame/system/src/extensions/check_weight.rs | 63 +----- frame/transaction-payment/src/lib.rs | 193 ++++++++++++++++-- 15 files changed, 225 insertions(+), 105 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e3f3399dbf6c..5e8932fd5652d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2473,9 +2473,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.21" +version = "0.13.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659cd14835e75b64d9dba5b660463506763cf0aa6cb640aeeb0e98d841093490" +checksum = "9c1cbbfc9a1996c6af82c2b4caf828d2c653af4fcdbb0e5674cc966eee5a4197" dependencies = [ "bitflags", "libc", @@ -3294,9 +3294,9 @@ checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" [[package]] name = "libgit2-sys" -version = "0.12.22+1.1.0" +version = "0.12.23+1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89c53ac117c44f7042ad8d8f5681378dfbc6010e49ec2c0d1f11dfedc7a4a1c3" +checksum = "29730a445bae719db3107078b46808cc45a5b7a6bae3f31272923af969453356" dependencies = [ "cc", "libc", diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index ca6e6b1822d45..5d3ea603265fe 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -258,11 +258,13 @@ impl pallet_balances::Config for Runtime { parameter_types! { pub const TransactionByteFee: Balance = 1; + pub OperationalFeeMultiplier: u8 = 5; } impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; type TransactionByteFee = TransactionByteFee; + type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 881641e15136c..f2d3175f094d7 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -413,6 +413,7 @@ impl pallet_balances::Config for Runtime { parameter_types! { pub const TransactionByteFee: Balance = 10 * MILLICENTS; + pub const OperationalFeeMultiplier: u8 = 5; pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(1, 100_000); pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000_000u128); @@ -421,6 +422,7 @@ parameter_types! { impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; type TransactionByteFee = TransactionByteFee; + type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = TargetedFeeAdjustment; diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index f6faebed39316..60feedb326d8a 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -76,10 +76,12 @@ impl frame_system::Config for Test { } parameter_types! { pub const TransactionByteFee: u64 = 1; + pub const OperationalFeeMultiplier: u8 = 5; } impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; type TransactionByteFee = TransactionByteFee; + type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index d8c07aa9c42e5..1d758ce4e980b 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -78,10 +78,12 @@ impl frame_system::Config for Test { } parameter_types! { pub const TransactionByteFee: u64 = 1; + pub const OperationalFeeMultiplier: u8 = 5; } impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; type TransactionByteFee = TransactionByteFee; + type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 9c7ba3e1ec824..25b8fb34f20ba 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -80,10 +80,12 @@ impl frame_system::Config for Test { } parameter_types! { pub const TransactionByteFee: u64 = 1; + pub const OperationalFeeMultiplier: u8 = 5; } impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; type TransactionByteFee = TransactionByteFee; + type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 41f679909e6fd..b1bdf357ec07d 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -800,10 +800,12 @@ mod tests { parameter_types! { pub const TransactionByteFee: Balance = 0; + pub const OperationalFeeMultiplier: u8 = 5; } impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; type TransactionByteFee = TransactionByteFee; + type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } @@ -1110,8 +1112,6 @@ mod tests { let invalid = TestXt::new(Call::Custom(custom::Call::unallowed_unsigned {}), None); let mut t = new_test_ext(1); - let mut default_with_prio_3 = ValidTransaction::default(); - default_with_prio_3.priority = 3; t.execute_with(|| { assert_eq!( Executive::validate_transaction( @@ -1119,7 +1119,7 @@ mod tests { valid.clone(), Default::default(), ), - Ok(default_with_prio_3), + Ok(ValidTransaction::default()), ); assert_eq!( Executive::validate_transaction( diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index 115470a9bf034..ec5f37823ad47 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -287,30 +287,6 @@ impl<'a> OneOrMany for &'a [DispatchClass] { } } -/// Primitives related to priority management of Frame. -pub mod priority { - /// The starting point of all Operational transactions. 3/4 of u64::MAX. - pub const LIMIT: u64 = 13_835_058_055_282_163_711_u64; - - /// Wrapper for priority of different dispatch classes. - /// - /// This only makes sure that any value created for the operational dispatch class is - /// incremented by [`LIMIT`]. - pub enum FrameTransactionPriority { - Normal(u64), - Operational(u64), - } - - impl From for u64 { - fn from(priority: FrameTransactionPriority) -> Self { - match priority { - FrameTransactionPriority::Normal(inner) => inner, - FrameTransactionPriority::Operational(inner) => inner.saturating_add(LIMIT), - } - } - } -} - /// A bundle of static information collected from the `#[weight = $x]` attributes. #[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] pub struct DispatchInfo { diff --git a/frame/system/src/extensions/check_genesis.rs b/frame/system/src/extensions/check_genesis.rs index 6f409d5d3d4ad..9c5c890ee6098 100644 --- a/frame/system/src/extensions/check_genesis.rs +++ b/frame/system/src/extensions/check_genesis.rs @@ -24,6 +24,11 @@ use sp_runtime::{ }; /// Genesis hash check to provide replay protection between different networks. +/// +/// # Transaction Validity +/// +/// Note that while a transaction with invalid `genesis_hash` will fail to be decoded, +/// the extension does not affect any other fields of `TransactionValidity` directly. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct CheckGenesis(sp_std::marker::PhantomData); diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index 69cca765efea9..941f28dc6fc63 100644 --- a/frame/system/src/extensions/check_mortality.rs +++ b/frame/system/src/extensions/check_mortality.rs @@ -27,6 +27,10 @@ use sp_runtime::{ }; /// Check for transaction mortality. +/// +/// # Transaction Validity +/// +/// The extension affects `longevity` of the transaction according to the [`Era`] definition. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct CheckMortality(Era, sp_std::marker::PhantomData); diff --git a/frame/system/src/extensions/check_nonce.rs b/frame/system/src/extensions/check_nonce.rs index 74be83398421e..3c6f9a1b4dbd1 100644 --- a/frame/system/src/extensions/check_nonce.rs +++ b/frame/system/src/extensions/check_nonce.rs @@ -30,8 +30,11 @@ use sp_std::vec; /// Nonce check and increment to give replay protection for transactions. /// -/// Note that this does not set any priority by default. Make sure that AT LEAST one of the signed -/// extension sets some kind of priority upon validating transactions. +/// # Transaction Validity +/// +/// This extension affects `requires` and `provides` tags of validity, but DOES NOT +/// set the `priority` field. Make sure that AT LEAST one of the signed extension sets +/// some kind of priority upon validating transactions. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct CheckNonce(#[codec(compact)] pub T::Index); diff --git a/frame/system/src/extensions/check_spec_version.rs b/frame/system/src/extensions/check_spec_version.rs index 0217aefae6b9d..688abe99763a2 100644 --- a/frame/system/src/extensions/check_spec_version.rs +++ b/frame/system/src/extensions/check_spec_version.rs @@ -21,6 +21,11 @@ use scale_info::TypeInfo; use sp_runtime::{traits::SignedExtension, transaction_validity::TransactionValidityError}; /// Ensure the runtime version registered in the transaction is the same as at present. +/// +/// # Transaction Validity +/// +/// The transaction with incorrect `spec_version` are considered invalid. The validity +/// is not affected in any other way. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct CheckSpecVersion(sp_std::marker::PhantomData); diff --git a/frame/system/src/extensions/check_tx_version.rs b/frame/system/src/extensions/check_tx_version.rs index 9418d3ff5d937..f6bb53e1cba34 100644 --- a/frame/system/src/extensions/check_tx_version.rs +++ b/frame/system/src/extensions/check_tx_version.rs @@ -21,6 +21,11 @@ use scale_info::TypeInfo; use sp_runtime::{traits::SignedExtension, transaction_validity::TransactionValidityError}; /// Ensure the transaction version registered in the transaction is the same as at present. +/// +/// # Transaction Validity +/// +/// The transaction with incorrect `transaction_version` are considered invalid. The validity +/// is not affected in any other way. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct CheckTxVersion(sp_std::marker::PhantomData); diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index 92dc7382fa2d5..ca885accd660f 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -19,19 +19,21 @@ use crate::{limits::BlockWeights, Config, Pallet}; use codec::{Decode, Encode}; use frame_support::{ traits::Get, - weights::{priority::FrameTransactionPriority, DispatchClass, DispatchInfo, PostDispatchInfo}, + weights::{DispatchClass, DispatchInfo, PostDispatchInfo}, }; use scale_info::TypeInfo; use sp_runtime::{ traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension}, - transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError, - ValidTransaction, - }, + transaction_validity::{InvalidTransaction, TransactionValidity, TransactionValidityError}, DispatchResult, }; /// Block resource (weight) limit check. +/// +/// # Transaction Validity +/// +/// This extension does not influence any fields of `TransactionValidity` in case the +/// transaction is valid. #[derive(Encode, Decode, Clone, Eq, PartialEq, Default, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct CheckWeight(sp_std::marker::PhantomData); @@ -81,23 +83,6 @@ where } } - /// Get the priority of an extrinsic denoted by `info`. - /// - /// Operational transaction will be given a fixed initial amount to be fairly distinguished from - /// the normal ones. - fn get_priority(info: &DispatchInfoOf) -> TransactionPriority { - match info.class { - // Normal transaction. - DispatchClass::Normal => FrameTransactionPriority::Normal(info.weight.into()).into(), - // Don't use up the whole priority space, to allow things like `tip` to be taken into - // account as well. - DispatchClass::Operational => - FrameTransactionPriority::Operational(info.weight.into()).into(), - // Mandatory extrinsics are only for inherents; never transactions. - DispatchClass::Mandatory => TransactionPriority::min_value(), - } - } - /// Creates new `SignedExtension` to check weight of the extrinsic. pub fn new() -> Self { Self(Default::default()) @@ -130,7 +115,7 @@ where // consumption from causing false negatives. Self::check_extrinsic_weight(info)?; - Ok(ValidTransaction { priority: Self::get_priority(info), ..Default::default() }) + Ok(Default::default()) } } @@ -368,13 +353,7 @@ mod tests { }; let len = 0_usize; - assert_eq!( - CheckWeight::::do_validate(&okay, len), - Ok(ValidTransaction { - priority: CheckWeight::::get_priority(&okay), - ..Default::default() - }) - ); + assert_eq!(CheckWeight::::do_validate(&okay, len), Ok(Default::default())); assert_err!( CheckWeight::::do_validate(&max, len), InvalidTransaction::ExhaustsResources @@ -506,30 +485,6 @@ mod tests { }) } - #[test] - fn signed_ext_check_weight_works() { - new_test_ext().execute_with(|| { - let normal = - DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; - let op = DispatchInfo { - weight: 100, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - let len = 0_usize; - - let priority = CheckWeight::(PhantomData) - .validate(&1, CALL, &normal, len) - .unwrap() - .priority; - assert_eq!(priority, 100); - - let priority = - CheckWeight::(PhantomData).validate(&1, CALL, &op, len).unwrap().priority; - assert_eq!(priority, frame_support::weights::priority::LIMIT + 100); - }) - } - #[test] fn signed_ext_check_weight_block_size_works() { new_test_ext().execute_with(|| { diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 11dbcc010f67c..28200bee7054f 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -264,6 +264,30 @@ pub mod pallet { #[pallet::constant] type TransactionByteFee: Get>; + /// A fee mulitplier for `Operational` extrinsics to compute "virtual tip" to boost their + /// `priority` + /// + /// This value is multipled by the `final_fee` to obtain a "virtual tip" that is later + /// added to a tip component in regular `priority` calculations. + /// It means that a `Normal` transaction can front-run a similarly-sized `Operational` + /// extrinsic (with no tip), by including a tip value greater than the virtual tip. + /// + /// ```rust,ignore + /// // For `Normal` + /// let priority = priority_calc(tip); + /// + /// // For `Operational` + /// let virtual_tip = (inclusion_fee + tip) * OperationalFeeMultiplier; + /// let priority = priority_calc(tip + virtual_tip); + /// ``` + /// + /// Note that since we use `final_fee` the multiplier applies also to the regular `tip` + /// sent with the transaction. So, not only does the transaction get a priority bump based + /// on the `inclusion_fee`, but we also amplify the impact of tips applied to `Operational` + /// transactions. + #[pallet::constant] + type OperationalFeeMultiplier: Get; + /// Convert a weight value into a deductible fee based on the currency type. type WeightToFee: WeightToFeePolynomial>; @@ -525,6 +549,14 @@ where /// Require the transactor pay for themselves and maybe include a tip to gain additional priority /// in the queue. +/// +/// # Transaction Validity +/// +/// This extension sets the `priority` field of `TransactionValidity` depending on the amount +/// of tip being paid per weight unit. +/// +/// Operational transactions will receive an additional priority bump, so that they are normally +/// considered before regular transactions. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct ChargeTransactionPayment(#[codec(compact)] BalanceOf); @@ -566,27 +598,73 @@ where .map(|i| (fee, i)) } - /// Get an appropriate priority for a transaction with the given length and info. + /// Get an appropriate priority for a transaction with the given `DispatchInfo`, encoded length + /// and user-included tip. /// - /// This will try and optimise the `fee/weight` `fee/length`, whichever is consuming more of the - /// maximum corresponding limit. + /// The priority is based on the amount of `tip` the user is willing to pay per unit of either + /// `weight` or `length`, depending which one is more limitting. For `Operational` extrinsics + /// we add a "virtual tip" to the calculations. /// - /// For example, if a transaction consumed 1/4th of the block length and half of the weight, its - /// final priority is `fee * min(2, 4) = fee * 2`. If it consumed `1/4th` of the block length - /// and the entire block weight `(1/1)`, its priority is `fee * min(1, 4) = fee * 1`. This means - /// that the transaction which consumes more resources (either length or weight) with the same - /// `fee` ends up having lower priority. - fn get_priority( - len: usize, + /// The formula should simply be `tip / bounded_{weight|length}`, but since we are using + /// integer division, we have no guarantees it's going to give results in any reasonable + /// range (might simply end up being zero). Hence we use a scaling factor: + /// `tip * (max_block_{weight|length} / bounded_{weight|length})`, since given current + /// state of-the-art blockchains, number of per-block transactions is expected to be in a + /// range reasonable enough to not saturate the `Balance` type while multiplying by the tip. + pub fn get_priority( info: &DispatchInfoOf, + len: usize, + tip: BalanceOf, final_fee: BalanceOf, ) -> TransactionPriority { - let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1); - let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal); - let len_saturation = max_block_length as u64 / (len as u64).max(1); - let coefficient: BalanceOf = - weight_saturation.min(len_saturation).saturated_into::>(); - final_fee.saturating_mul(coefficient).saturated_into::() + // Calculate how many such extrinsics we could fit into an empty block and take + // the limitting factor. + let max_block_weight = T::BlockWeights::get().max_block; + let max_block_length = *T::BlockLength::get().max.get(info.class) as u64; + + let bounded_weight = info.weight.max(1).min(max_block_weight); + let bounded_length = (len as u64).max(1).min(max_block_length); + + let max_tx_per_block_weight = max_block_weight / bounded_weight; + let max_tx_per_block_length = max_block_length / bounded_length; + // Given our current knowledge this value is going to be in a reasonable range - i.e. + // less than 10^9 (2^30), so multiplying by the `tip` value is unlikely to overflow the + // balance type. We still use saturating ops obviously, but the point is to end up with some + // `priority` distribution instead of having all transactions saturate the priority. + let max_tx_per_block = max_tx_per_block_length + .min(max_tx_per_block_weight) + .saturated_into::>(); + let max_reward = |val: BalanceOf| val.saturating_mul(max_tx_per_block); + + // To distribute no-tip transactions a little bit, we set the minimal tip as `1`. + // This means that given two transactions without a tip, smaller one will be preferred. + let tip = tip.max(1.saturated_into()); + let scaled_tip = max_reward(tip); + + match info.class { + DispatchClass::Normal => { + // For normal class we simply take the `tip_per_weight`. + scaled_tip + }, + DispatchClass::Mandatory => { + // Mandatory extrinsics should be prohibited (e.g. by the [`CheckWeight`] + // extensions), but just to be safe let's return the same priority as `Normal` here. + scaled_tip + }, + DispatchClass::Operational => { + // A "virtual tip" value added to an `Operational` extrinsic. + // This value should be kept high enough to allow `Operational` extrinsics + // to get in even during congestion period, but at the same time low + // enough to prevent a possible spam attack by sending invalid operational + // extrinsics which push away regular transactions from the pool. + let fee_multiplier = T::OperationalFeeMultiplier::get().saturated_into(); + let virtual_tip = final_fee.saturating_mul(fee_multiplier); + let scaled_virtual_tip = max_reward(virtual_tip); + + scaled_tip.saturating_add(scaled_virtual_tip) + }, + } + .saturated_into::() } } @@ -629,8 +707,12 @@ where info: &DispatchInfoOf, len: usize, ) -> TransactionValidity { - let (fee, _) = self.withdraw_fee(who, call, info, len)?; - Ok(ValidTransaction { priority: Self::get_priority(len, info, fee), ..Default::default() }) + let (final_fee, _) = self.withdraw_fee(who, call, info, len)?; + let tip = self.0; + Ok(ValidTransaction { + priority: Self::get_priority(info, len, tip, final_fee), + ..Default::default() + }) } fn pre_dispatch( @@ -743,6 +825,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub static TransactionByteFee: u64 = 1; pub static WeightToFee: u64 = 1; + pub static OperationalFeeMultiplier: u8 = 5; } impl frame_system::Config for Runtime { @@ -822,6 +905,7 @@ mod tests { impl Config for Runtime { type OnChargeTransaction = CurrencyAdapter; type TransactionByteFee = TransactionByteFee; + type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = WeightToFee; type FeeMultiplierUpdate = (); } @@ -1335,6 +1419,79 @@ mod tests { }); } + #[test] + fn should_alter_operational_priority() { + let tip = 5; + let len = 10; + + ExtBuilder::default().balance_factor(100).build().execute_with(|| { + let normal = + DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; + let priority = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &normal, len) + .unwrap() + .priority; + + assert_eq!(priority, 50); + + let priority = ChargeTransactionPayment::(2 * tip) + .validate(&2, CALL, &normal, len) + .unwrap() + .priority; + + assert_eq!(priority, 100); + }); + + ExtBuilder::default().balance_factor(100).build().execute_with(|| { + let op = DispatchInfo { + weight: 100, + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + let priority = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &op, len) + .unwrap() + .priority; + assert_eq!(priority, 5800); + + let priority = ChargeTransactionPayment::(2 * tip) + .validate(&2, CALL, &op, len) + .unwrap() + .priority; + assert_eq!(priority, 6100); + }); + } + + #[test] + fn no_tip_has_some_priority() { + let tip = 0; + let len = 10; + + ExtBuilder::default().balance_factor(100).build().execute_with(|| { + let normal = + DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; + let priority = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &normal, len) + .unwrap() + .priority; + + assert_eq!(priority, 10); + }); + + ExtBuilder::default().balance_factor(100).build().execute_with(|| { + let op = DispatchInfo { + weight: 100, + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + let priority = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &op, len) + .unwrap() + .priority; + assert_eq!(priority, 5510); + }); + } + #[test] fn post_info_can_change_pays_fee() { ExtBuilder::default() From 125092f355c11166c57deeef0e1841301a351889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 4 Oct 2021 16:30:46 +0200 Subject: [PATCH 0069/1472] Introduce block authorship soft deadline (#9663) * Soft limit. * Add soft deadline tests. * cargo +nightly fmt --all * Fix sc-service test. * Improving tests --- Cargo.lock | 1 + .../basic-authorship/src/basic_authorship.rs | 186 +++++++++++++++++- client/service/test/Cargo.toml | 1 + client/service/test/src/client/mod.rs | 41 ++-- primitives/keyring/src/sr25519.rs | 11 ++ test-utils/runtime/client/src/lib.rs | 16 +- 6 files changed, 231 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e8932fd5652d..622b52591b90d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8449,6 +8449,7 @@ version = "2.0.0" dependencies = [ "fdlimit", "futures 0.3.16", + "hex", "hex-literal", "log 0.4.14", "parity-scale-codec", diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index bbee60ae98dcf..0055254b67091 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -286,6 +286,11 @@ where } } +/// If the block is full we will attempt to push at most +/// this number of transactions before quitting for real. +/// It allows us to increase block utilization. +const MAX_SKIPPED_TRANSACTIONS: usize = 8; + impl Proposer where A: TransactionPool, @@ -309,11 +314,6 @@ where block_size_limit: Option, ) -> Result, PR::Proof>, sp_blockchain::Error> { - /// If the block is full we will attempt to push at most - /// this number of transactions before quitting for real. - /// It allows us to increase block utilization. - const MAX_SKIPPED_TRANSACTIONS: usize = 8; - let mut block_builder = self.client.new_block_at(&self.parent_id, inherent_digests, PR::ENABLED)?; @@ -336,6 +336,9 @@ where } // proceed with transactions + // We calculate soft deadline used only in case we start skipping transactions. + let now = (self.now)(); + let soft_deadline = now + deadline.saturating_duration_since(now) / 2; let block_timer = time::Instant::now(); let mut skipped = 0; let mut unqueue_invalid = Vec::new(); @@ -364,7 +367,8 @@ where let mut hit_block_size_limit = false; while let Some(pending_tx) = pending_iterator.next() { - if (self.now)() > deadline { + let now = (self.now)(); + if now > deadline { debug!( "Consensus deadline reached when pushing block transactions, \ proceeding with proposing." @@ -387,6 +391,13 @@ where MAX_SKIPPED_TRANSACTIONS - skipped, ); continue + } else if now < soft_deadline { + debug!( + "Transaction would overflow the block size limit, \ + but we still have time before the soft deadline, so \ + we will try a bit more." + ); + continue } else { debug!("Reached block size limit, proceeding with proposing."); hit_block_size_limit = true; @@ -408,6 +419,11 @@ where "Block seems full, but will try {} more transactions before quitting.", MAX_SKIPPED_TRANSACTIONS - skipped, ); + } else if (self.now)() < soft_deadline { + debug!( + "Block seems full, but we still have time before the soft deadline, \ + so we will try a bit more before quitting." + ); } else { debug!("Block is full, proceed with proposing."); break @@ -493,6 +509,7 @@ mod tests { use sp_api::Core; use sp_blockchain::HeaderBackend; use sp_consensus::{BlockOrigin, Environment, Proposer}; + use sp_core::Pair; use sp_runtime::traits::NumberFor; use substrate_test_runtime_client::{ prelude::*, @@ -512,6 +529,19 @@ mod tests { .into_signed_tx() } + fn exhausts_resources_extrinsic_from(who: usize) -> Extrinsic { + let pair = AccountKeyring::numeric(who); + let transfer = Transfer { + // increase the amount to bump priority + amount: 1, + nonce: 0, + from: pair.public(), + to: Default::default(), + }; + let signature = pair.sign(&transfer.encode()).into(); + Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: true } + } + fn chain_event(header: B::Header) -> ChainEvent where NumberFor: From, @@ -557,7 +587,7 @@ mod tests { return value.1 } let old = value.1; - let new = old + time::Duration::from_secs(2); + let new = old + time::Duration::from_secs(1); *value = (true, new); old }), @@ -730,8 +760,8 @@ mod tests { // then // block should have some extrinsics although we have some more in the pool. - assert_eq!(block.extrinsics().len(), expected_block_extrinsics); assert_eq!(txpool.ready().count(), expected_pool_transactions); + assert_eq!(block.extrinsics().len(), expected_block_extrinsics); block }; @@ -744,6 +774,7 @@ mod tests { .expect("there should be header"), )), ); + assert_eq!(txpool.ready().count(), 7); // let's create one block and import it let block = propose_block(&client, 0, 2, 7); @@ -757,6 +788,7 @@ mod tests { .expect("there should be header"), )), ); + assert_eq!(txpool.ready().count(), 5); // now let's make sure that we can still make some progress let block = propose_block(&client, 1, 2, 5); @@ -849,4 +881,142 @@ mod tests { // block size and thus, one less transaction should fit into the limit. assert_eq!(block.extrinsics().len(), extrinsics_num - 2); } + + #[test] + fn should_keep_adding_transactions_after_exhausts_resources_before_soft_deadline() { + // given + let client = Arc::new(substrate_test_runtime_client::new()); + let spawner = sp_core::testing::TaskExecutor::new(); + let txpool = BasicPool::new_full( + Default::default(), + true.into(), + None, + spawner.clone(), + client.clone(), + ); + + block_on( + txpool.submit_at( + &BlockId::number(0), + SOURCE, + // add 2 * MAX_SKIPPED_TRANSACTIONS that exhaust resources + (0..MAX_SKIPPED_TRANSACTIONS * 2) + .into_iter() + .map(|i| exhausts_resources_extrinsic_from(i)) + // and some transactions that are okay. + .chain((0..MAX_SKIPPED_TRANSACTIONS).into_iter().map(|i| extrinsic(i as _))) + .collect(), + ), + ) + .unwrap(); + + block_on( + txpool.maintain(chain_event( + client + .header(&BlockId::Number(0u64)) + .expect("header get error") + .expect("there should be header"), + )), + ); + assert_eq!(txpool.ready().count(), MAX_SKIPPED_TRANSACTIONS * 3); + + let mut proposer_factory = + ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None); + + let cell = Mutex::new(time::Instant::now()); + let proposer = proposer_factory.init_with_now( + &client.header(&BlockId::number(0)).unwrap().unwrap(), + Box::new(move || { + let mut value = cell.lock(); + let old = *value; + *value = old + time::Duration::from_secs(1); + old + }), + ); + + // when + // give it enough time so that deadline is never triggered. + let deadline = time::Duration::from_secs(900); + let block = + block_on(proposer.propose(Default::default(), Default::default(), deadline, None)) + .map(|r| r.block) + .unwrap(); + + // then block should have all non-exhaust resources extrinsics (+ the first one). + assert_eq!(block.extrinsics().len(), MAX_SKIPPED_TRANSACTIONS + 1); + } + + #[test] + fn should_only_skip_up_to_some_limit_after_soft_deadline() { + // given + let client = Arc::new(substrate_test_runtime_client::new()); + let spawner = sp_core::testing::TaskExecutor::new(); + let txpool = BasicPool::new_full( + Default::default(), + true.into(), + None, + spawner.clone(), + client.clone(), + ); + + block_on( + txpool.submit_at( + &BlockId::number(0), + SOURCE, + (0..MAX_SKIPPED_TRANSACTIONS + 2) + .into_iter() + .map(|i| exhausts_resources_extrinsic_from(i)) + // and some transactions that are okay. + .chain((0..MAX_SKIPPED_TRANSACTIONS).into_iter().map(|i| extrinsic(i as _))) + .collect(), + ), + ) + .unwrap(); + + block_on( + txpool.maintain(chain_event( + client + .header(&BlockId::Number(0u64)) + .expect("header get error") + .expect("there should be header"), + )), + ); + assert_eq!(txpool.ready().count(), MAX_SKIPPED_TRANSACTIONS * 2 + 2); + + let mut proposer_factory = + ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None); + + let deadline = time::Duration::from_secs(600); + let cell = Arc::new(Mutex::new((0, time::Instant::now()))); + let cell2 = cell.clone(); + let proposer = proposer_factory.init_with_now( + &client.header(&BlockId::number(0)).unwrap().unwrap(), + Box::new(move || { + let mut value = cell.lock(); + let (called, old) = *value; + // add time after deadline is calculated internally (hence 1) + let increase = if called == 1 { + // we start after the soft_deadline should have already been reached. + deadline / 2 + } else { + // but we make sure to never reach the actual deadline + time::Duration::from_millis(0) + }; + *value = (called + 1, old + increase); + old + }), + ); + + let block = + block_on(proposer.propose(Default::default(), Default::default(), deadline, None)) + .map(|r| r.block) + .unwrap(); + + // then the block should have no transactions despite some in the pool + assert_eq!(block.extrinsics().len(), 1); + assert!( + cell2.lock().0 > MAX_SKIPPED_TRANSACTIONS, + "Not enough calls to current time, which indicates the test might have ended because of deadline, not soft deadline" + ); + } } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 85a6dcc9e8b29..9e66e9ca381d3 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -12,6 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +hex = "0.4" hex-literal = "0.3.1" tempfile = "3.1.0" tokio = { version = "1.10.0", features = ["time"] } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index d82a839936d7d..8ea605c0ea5be 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1759,12 +1759,21 @@ fn storage_keys_iter_works() { let res: Vec<_> = client .storage_keys_iter(&BlockId::Number(0), Some(&prefix), None) .unwrap() - .take(2) - .map(|x| x.0) + .take(8) + .map(|x| hex::encode(&x.0)) .collect(); assert_eq!( res, - [hex!("0befda6e1ca4ef40219d588a727f1271").to_vec(), hex!("3a636f6465").to_vec()] + [ + "00c232cf4e70a5e343317016dc805bf80a6a8cd8ad39958d56f99891b07851e0", + "085b2407916e53a86efeb8b72dbe338c4b341dab135252f96b6ed8022209b6cb", + "0befda6e1ca4ef40219d588a727f1271", + "1a560ecfd2a62c2b8521ef149d0804eb621050e3988ed97dca55f0d7c3e6aa34", + "1d66850d32002979d67dd29dc583af5b2ae2a1f71c1f35ad90fff122be7a3824", + "237498b98d8803334286e9f0483ef513098dd3c1c22ca21c4dc155b4ef6cc204", + "29b9db10ec5bf7907d8f74b5e60aa8140c4fbdd8127a1ee5600cb98e5ec01729", + "3a636f6465", + ] ); let res: Vec<_> = client @@ -1774,15 +1783,19 @@ fn storage_keys_iter_works() { Some(&StorageKey(hex!("3a636f6465").to_vec())), ) .unwrap() - .take(3) - .map(|x| x.0) + .take(7) + .map(|x| hex::encode(&x.0)) .collect(); assert_eq!( res, [ - hex!("3a686561707061676573").to_vec(), - hex!("6644b9b8bc315888ac8e41a7968dc2b4141a5403c58acdf70b7e8f7e07bf5081").to_vec(), - hex!("79c07e2b1d2e2abfd4855b936617eeff5e0621c4869aa60c02be9adcc98a0d1d").to_vec(), + "3a686561707061676573", + "52008686cc27f6e5ed83a216929942f8bcd32a396f09664a5698f81371934b56", + "5348d72ac6cc66e5d8cbecc27b0e0677503b845fe2382d819f83001781788fd5", + "5c2d5fda66373dabf970e4fb13d277ce91c5233473321129d32b5a8085fa8133", + "6644b9b8bc315888ac8e41a7968dc2b4141a5403c58acdf70b7e8f7e07bf5081", + "66484000ed3f75c95fc7b03f39c20ca1e1011e5999278247d3b2f5e3c3273808", + "79c07e2b1d2e2abfd4855b936617eeff5e0621c4869aa60c02be9adcc98a0d1d", ] ); @@ -1795,12 +1808,18 @@ fn storage_keys_iter_works() { )), ) .unwrap() - .take(1) - .map(|x| x.0) + .take(5) + .map(|x| hex::encode(x.0)) .collect(); assert_eq!( res, - [hex!("cf722c0832b5231d35e29f319ff27389f5032bfc7bfc3ba5ed7839f2042fb99f").to_vec()] + [ + "7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa", + "811ecfaadcf5f2ee1d67393247e2f71a1662d433e8ce7ff89fb0d4aa9561820b", + "a93d74caa7ec34ea1b04ce1e5c090245f867d333f0f88278a451e45299654dc5", + "a9ee1403384afbfc13f13be91ff70bfac057436212e53b9733914382ac942892", + "cf722c0832b5231d35e29f319ff27389f5032bfc7bfc3ba5ed7839f2042fb99f", + ] ); } diff --git a/primitives/keyring/src/sr25519.rs b/primitives/keyring/src/sr25519.rs index 6a7aa3635a43a..604c330b1ea1b 100644 --- a/primitives/keyring/src/sr25519.rs +++ b/primitives/keyring/src/sr25519.rs @@ -89,9 +89,20 @@ impl Keyring { pub fn public(self) -> Public { self.pair().public() } + pub fn to_seed(self) -> String { format!("//{}", self) } + + /// Create a crypto `Pair` from a numeric value. + pub fn numeric(idx: usize) -> Pair { + Pair::from_string(&format!("//{}", idx), None).expect("numeric values are known good; qed") + } + + /// Get account id of a `numeric` account. + pub fn numeric_id(idx: usize) -> AccountId32 { + (*Self::numeric(idx).public().as_array_ref()).into() + } } impl From for &'static str { diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index dc5ccadc4574f..bcfe93b6f7975 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -37,7 +37,7 @@ use sc_client_api::light::{ use sp_core::{ sr25519, storage::{ChildInfo, Storage, StorageChild}, - ChangesTrieConfiguration, + ChangesTrieConfiguration, Pair, }; use sp_runtime::traits::{Block as BlockT, Hash as HashT, HashFor, Header as HeaderT, NumberFor}; use substrate_test_runtime::genesismap::{additional_storage_with_genesis, GenesisConfig}; @@ -118,11 +118,15 @@ impl GenesisParameters { sr25519::Public::from(Sr25519Keyring::Bob).into(), sr25519::Public::from(Sr25519Keyring::Charlie).into(), ], - vec![ - AccountKeyring::Alice.into(), - AccountKeyring::Bob.into(), - AccountKeyring::Charlie.into(), - ], + (0..16_usize) + .into_iter() + .map(|i| AccountKeyring::numeric(i).public()) + .chain(vec![ + AccountKeyring::Alice.into(), + AccountKeyring::Bob.into(), + AccountKeyring::Charlie.into(), + ]) + .collect(), 1000, self.heap_pages_override, self.extra_storage.clone(), From ddc2c6e7efa16f9820944cb052be94dc38d55e26 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Mon, 4 Oct 2021 21:19:17 +0200 Subject: [PATCH 0070/1472] chore: refresh of the substrate_builder image (#9808) * chore: refresh of the substrate_builder image fix #9715 * chore: renaming + build script * Fix spaces/tabs * Add doc * Remove non binary * Update docker/substrate_builder.Dockerfile Co-authored-by: Denis Pisarev --- .dockerignore | 1 + .maintain/Dockerfile | 59 ----------------------------- docker/README.md | 22 +++++++++++ docker/build.sh | 24 ++++++++++++ docker/substrate_builder.Dockerfile | 35 +++++++++++++++++ 5 files changed, 82 insertions(+), 59 deletions(-) delete mode 100644 .maintain/Dockerfile create mode 100644 docker/README.md create mode 100755 docker/build.sh create mode 100644 docker/substrate_builder.Dockerfile diff --git a/.dockerignore b/.dockerignore index 39dbc05c97e16..c58599e3fb72b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,3 +4,4 @@ doc Dockerfile .dockerignore .local +.env* diff --git a/.maintain/Dockerfile b/.maintain/Dockerfile deleted file mode 100644 index 21a41720f7d65..0000000000000 --- a/.maintain/Dockerfile +++ /dev/null @@ -1,59 +0,0 @@ -# Note: We don't use Alpine and its packaged Rust/Cargo because they're too often out of date, -# preventing them from being used to build Substrate/Polkadot. - -FROM phusion/baseimage:0.11 as builder -LABEL maintainer="chevdor@gmail.com" -LABEL description="This is the build stage for Substrate. Here we create the binary." - -ENV DEBIAN_FRONTEND=noninteractive - -ARG PROFILE=release -WORKDIR /substrate - -COPY . /substrate - -RUN apt-get update && \ - apt-get dist-upgrade -y -o Dpkg::Options::="--force-confold" && \ - apt-get install -y cmake pkg-config libssl-dev git clang - -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \ - export PATH="$PATH:$HOME/.cargo/bin" && \ - rustup toolchain install nightly && \ - rustup target add wasm32-unknown-unknown --toolchain nightly && \ - rustup default stable && \ - cargo build "--$PROFILE" - -# ===== SECOND STAGE ====== - -FROM phusion/baseimage:0.11 -LABEL maintainer="chevdor@gmail.com" -LABEL description="This is the 2nd stage: a very small image where we copy the Substrate binary." -ARG PROFILE=release - -RUN mv /usr/share/ca* /tmp && \ - rm -rf /usr/share/* && \ - mv /tmp/ca-certificates /usr/share/ && \ - useradd -m -u 1000 -U -s /bin/sh -d /substrate substrate && \ - mkdir -p /substrate/.local/share/substrate && \ - chown -R substrate:substrate /substrate/.local && \ - ln -s /substrate/.local/share/substrate /data - -COPY --from=builder /substrate/target/$PROFILE/substrate /usr/local/bin -COPY --from=builder /substrate/target/$PROFILE/subkey /usr/local/bin -COPY --from=builder /substrate/target/$PROFILE/node-rpc-client /usr/local/bin -COPY --from=builder /substrate/target/$PROFILE/node-template /usr/local/bin -COPY --from=builder /substrate/target/$PROFILE/chain-spec-builder /usr/local/bin - -# checks -RUN ldd /usr/local/bin/substrate && \ - /usr/local/bin/substrate --version - -# Shrinking -RUN rm -rf /usr/lib/python* && \ - rm -rf /usr/bin /usr/sbin /usr/share/man - -USER substrate -EXPOSE 30333 9933 9944 9615 -VOLUME ["/data"] - -CMD ["/usr/local/bin/substrate"] diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000000000..ca3c1bde4e321 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,22 @@ +# Substrate Builder Docker Image + +The Docker image in this folder is a `builder` image. It is self contained and allow users to build the binaries themselves. +There is no requirement on having Rust or any other toolchain installed but a working Docker environment. + +Unlike the `parity/polkadot` image which contains a single binary (`polkadot`!) used by default, the image in this folder builds and contains several binaries and you need to provide the name of the binary to be called. + +You should refer to the .Dockerfile for the actual list. At the time of editing, the list of included binaries is: + +- substrate +- subkey +- node-template +- chain-spec-builder + +The image can be used by passing the selected binary followed by the appropriate tags for this binary. + +Your best guess to get started is to pass the `--help flag`. Here are a few examples: + +- `docker run --rm -it parity/substrate substrate --version` +- `docker run --rm -it parity/substrate subkey --help` +- `docker run --rm -it parity/substrate node-template --version` +- `docker run --rm -it parity/substrate chain-spec-builder --help` diff --git a/docker/build.sh b/docker/build.sh new file mode 100755 index 0000000000000..f0a4560ff8fea --- /dev/null +++ b/docker/build.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -e + +pushd . + +# The following line ensure we run from the project root +PROJECT_ROOT=`git rev-parse --show-toplevel` +cd $PROJECT_ROOT + +# Find the current version from Cargo.toml +VERSION=`grep "^version" ./bin/node/cli/Cargo.toml | egrep -o "([0-9\.]+)"` +GITUSER=parity +GITREPO=substrate + +# Build the image +echo "Building ${GITUSER}/${GITREPO}:latest docker image, hang on!" +time docker build -f ./docker/substrate_builder.Dockerfile -t ${GITUSER}/${GITREPO}:latest . +docker tag ${GITUSER}/${GITREPO}:latest ${GITUSER}/${GITREPO}:v${VERSION} + +# Show the list of available images for this repo +echo "Image is ready" +docker images | grep ${GITREPO} + +popd diff --git a/docker/substrate_builder.Dockerfile b/docker/substrate_builder.Dockerfile new file mode 100644 index 0000000000000..d0812c1a80c40 --- /dev/null +++ b/docker/substrate_builder.Dockerfile @@ -0,0 +1,35 @@ +# This is the build stage for Substrate. Here we create the binary. +FROM docker.io/paritytech/ci-linux:production as builder + +WORKDIR /substrate +COPY . /substrate +RUN cargo build --locked --release + +# This is the 2nd stage: a very small image where we copy the Substrate binary." +FROM docker.io/library/ubuntu:20.04 +LABEL description="Multistage Docker image for Substrate: a platform for web3" \ + io.parity.image.type="builder" \ + io.parity.image.authors="chevdor@gmail.com, devops-team@parity.io" \ + io.parity.image.vendor="Parity Technologies" \ + io.parity.image.description="Substrate is a next-generation framework for blockchain innovation 🚀" \ + io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/docker/substrate_builder.Dockerfile" \ + io.parity.image.documentation="https://github.com/paritytech/polkadot/" + +COPY --from=builder /substrate/target/release/substrate /usr/local/bin +COPY --from=builder /substrate/target/release/subkey /usr/local/bin +COPY --from=builder /substrate/target/release/node-template /usr/local/bin +COPY --from=builder /substrate/target/release/chain-spec-builder /usr/local/bin + +RUN useradd -m -u 1000 -U -s /bin/sh -d /substrate substrate && \ + mkdir -p /data /substrate/.local/share/substrate && \ + chown -R substrate:substrate /data && \ + ln -s /data /substrate/.local/share/substrate && \ +# unclutter and minimize the attack surface + rm -rf /usr/bin /usr/sbin && \ +# Sanity checks + ldd /usr/local/bin/substrate && \ + /usr/local/bin/substrate --version + +USER substrate +EXPOSE 30333 9933 9944 9615 +VOLUME ["/data"] From 1d356ce61f12fbb35ea471c48c1b3fea6ef0795c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 4 Oct 2021 22:55:36 +0200 Subject: [PATCH 0071/1472] Require crypto scheme for `insert-key` (#9909) * Require crypto scheme for `insert-key` We should not "guess" the scheme as this can depend on the implementation of the runtime etc. * FMT --- client/cli/src/commands/insert_key.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index 05055dc53c1e2..081c319081607 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -18,7 +18,7 @@ //! Implementation of the `insert` subcommand use crate::{ - utils, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, SharedParams, SubstrateCli, + utils, with_crypto_scheme, CryptoScheme, Error, KeystoreParams, SharedParams, SubstrateCli, }; use sc_keystore::LocalKeystore; use sc_service::config::{BasePath, KeystoreConfig}; @@ -49,9 +49,14 @@ pub struct InsertKeyCmd { #[structopt(flatten)] pub keystore_params: KeystoreParams, - #[allow(missing_docs)] - #[structopt(flatten)] - pub crypto_scheme: CryptoSchemeFlag, + /// The cryptography scheme that should be used to generate the key out of the given URI. + #[structopt( + long, + value_name = "SCHEME", + possible_values = &CryptoScheme::variants(), + case_insensitive = true, + )] + pub scheme: CryptoScheme, } impl InsertKeyCmd { @@ -68,10 +73,7 @@ impl InsertKeyCmd { let (keystore, public) = match self.keystore_params.keystore_config(&config_dir)? { (_, KeystoreConfig::Path { path, password }) => { - let public = with_crypto_scheme!( - self.crypto_scheme.scheme, - to_vec(&suri, password.clone()) - )?; + let public = with_crypto_scheme!(self.scheme, to_vec(&suri, password.clone()))?; let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(path, password)?); (keystore, public) }, @@ -161,6 +163,7 @@ mod tests { "test", "--suri", &uri, + "--scheme=sr25519", ]); assert!(inspect.run(&Cli).is_ok()); From 1c2e9a8c6d073d924f867cd883138630c9dff9f7 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Mon, 4 Oct 2021 18:19:21 -0400 Subject: [PATCH 0072/1472] Remove incorrect sanity check (#9924) * causes issue * remove the bad error check --- bin/node-template/runtime/src/lib.rs | 1 - bin/node/runtime/src/lib.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 5d3ea603265fe..e11840b5813d4 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -508,7 +508,6 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_timestamp, Timestamp); add_benchmark!(params, batches, pallet_template, TemplateModule); - if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) } } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f2d3175f094d7..b115087d514d0 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1728,7 +1728,6 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_utility, Utility); add_benchmark!(params, batches, pallet_vesting, Vesting); - if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) } } From 8f5b446ee4c1cff407a2888985178cf692166428 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:23:09 +0200 Subject: [PATCH 0073/1472] don't read events in elections anymore. (#9898) * dont read events in elections anymore. * Update frame/election-provider-multi-phase/src/lib.rs * Fix test for Substrate#9898 (#9907) Co-authored-by: Shawn Tabrizi Co-authored-by: Zeke Mostov <32168567+emostov@users.noreply.github.com> --- .../election-provider-multi-phase/src/lib.rs | 22 ++------ .../src/unsigned.rs | 55 ++++++++++++++----- 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 6b0329afc0d77..9508b3a7c83fe 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1201,8 +1201,12 @@ impl Pallet { match current_phase { Phase::Unsigned((true, opened)) if opened == now => { // Mine a new solution, cache it, and attempt to submit it - let initial_output = Self::ensure_offchain_repeat_frequency(now) - .and_then(|_| Self::mine_check_save_submit()); + let initial_output = Self::ensure_offchain_repeat_frequency(now).and_then(|_| { + // This is executed at the beginning of each round. Any cache is now invalid. + // Clear it. + unsigned::kill_ocw_solution::(); + Self::mine_check_save_submit() + }); log!(debug, "initial offchain thread output: {:?}", initial_output); }, Phase::Unsigned((true, opened)) if opened < now => { @@ -1214,20 +1218,6 @@ impl Pallet { }, _ => {}, } - - // After election finalization, clear OCW solution storage. - // - // We can read the events here because offchain worker doesn't affect PoV. - if >::read_events_no_consensus() - .into_iter() - .filter_map(|event_record| { - let local_event = ::Event::from(event_record.event); - local_event.try_into().ok() - }) - .any(|event| matches!(event, Event::ElectionFinalized(_))) - { - unsigned::kill_ocw_solution::(); - } } /// Logic for [`::on_initialize`] when signed phase is being opened. diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 31ad502ac076e..0ed9b5427b1ec 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -1241,35 +1241,62 @@ mod tests { } #[test] - fn ocw_clears_cache_after_election() { - let (mut ext, _pool) = ExtBuilder::default().build_offchainify(0); + fn ocw_clears_cache_on_unsigned_phase_open() { + let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); ext.execute_with(|| { - roll_to(25); - assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); + const BLOCK: u64 = 25; + let block_plus = |delta: u64| BLOCK + delta; + let offchain_repeat = ::OffchainRepeat::get(); - // we must clear the offchain storage to ensure the offchain execution check doesn't get - // in the way. - let mut storage = StorageValueRef::persistent(&OFFCHAIN_LAST_BLOCK); - storage.clear(); + roll_to(BLOCK); + // we are on the first block of the unsigned phase + assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, BLOCK))); assert!( !ocw_solution_exists::(), "no solution should be present before we mine one", ); - // creates and cache a solution - MultiPhase::offchain_worker(25); + // create and cache a solution on the first block of the unsigned phase + MultiPhase::offchain_worker(BLOCK); assert!( ocw_solution_exists::(), "a solution must be cached after running the worker", ); - // after an election, the solution must be cleared + // record the submitted tx, + let tx_cache_1 = pool.read().transactions[0].clone(); + // and assume it has been processed. + pool.try_write().unwrap().transactions.clear(); + + // after an election, the solution is not cleared // we don't actually care about the result of the election - roll_to(26); let _ = MultiPhase::do_elect(); - MultiPhase::offchain_worker(26); - assert!(!ocw_solution_exists::(), "elections must clear the ocw cache"); + MultiPhase::offchain_worker(block_plus(1)); + assert!(ocw_solution_exists::(), "elections does not clear the ocw cache"); + + // submit a solution with the offchain worker after the repeat interval + MultiPhase::offchain_worker(block_plus(offchain_repeat + 1)); + + // record the submitted tx, + let tx_cache_2 = pool.read().transactions[0].clone(); + // and assume it has been processed. + pool.try_write().unwrap().transactions.clear(); + + // the OCW submitted the same solution twice since the cache was not cleared. + assert_eq!(tx_cache_1, tx_cache_2); + + let current_block = block_plus(offchain_repeat * 2 + 2); + // force the unsigned phase to start on the current block. + CurrentPhase::::set(Phase::Unsigned((true, current_block))); + + // clear the cache and create a solution since we are on the first block of the unsigned + // phase. + MultiPhase::offchain_worker(current_block); + let tx_cache_3 = pool.read().transactions[0].clone(); + + // the submitted solution changes because the cache was cleared. + assert_eq!(tx_cache_1, tx_cache_3); }) } From 9379b2368469b4214ae44e4b3bdc374dd3eb0f28 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 5 Oct 2021 09:42:33 +0100 Subject: [PATCH 0074/1472] Improved file not found error message (#9931) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Say where you looked for the file Co-authored-by: Bastian Köcher --- client/chain-spec/src/chain_spec.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index ff3a99760bd28..c4db6158125b1 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -58,8 +58,9 @@ impl GenesisSource { match self { Self::File(path) => { - let file = - File::open(path).map_err(|e| format!("Error opening spec file: {}", e))?; + let file = File::open(path).map_err(|e| { + format!("Error opening spec file at `{}`: {}", path.display(), e) + })?; let genesis: GenesisContainer = json::from_reader(file) .map_err(|e| format!("Error parsing spec file: {}", e))?; Ok(genesis.genesis) @@ -284,7 +285,8 @@ impl ChainSpec { /// Parse json file into a `ChainSpec` pub fn from_json_file(path: PathBuf) -> Result { - let file = File::open(&path).map_err(|e| format!("Error opening spec file: {}", e))?; + let file = File::open(&path) + .map_err(|e| format!("Error opening spec file `{}`: {}", path.display(), e))?; let client_spec = json::from_reader(file).map_err(|e| format!("Error parsing spec file: {}", e))?; Ok(ChainSpec { client_spec, genesis: GenesisSource::File(path) }) From a30f0d1ca2efca6d13340d5f7fd480d9646cca3d Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 5 Oct 2021 12:26:34 +0100 Subject: [PATCH 0075/1472] First word should be Substrate not Polkadot (#9935) (if we want something put in the substrate PR.) --- docs/CONTRIBUTING.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CONTRIBUTING.adoc b/docs/CONTRIBUTING.adoc index 0a9a7ebacff5b..103b318a169d7 100644 --- a/docs/CONTRIBUTING.adoc +++ b/docs/CONTRIBUTING.adoc @@ -79,7 +79,7 @@ To create a Polkadot companion PR: . Override substrate deps to point to your local path or branch using https://github.com/bkchr/diener. (E.g. from the polkadot clone dir run `diener patch --crates-to-patch ../substrate --substrate` assuming substrate clone is in a sibling dir. If you do use diener, ensure that you _do not_ commit the changes diener makes to the Cargo.tomls.) . Make the changes required and build polkadot locally. . Submit all this as a PR against the Polkadot Repo. -. Link to your Polkadot PR in the _description_ of your _Substrate_ PR as "polkadot companion: [URL]" +. In the _description_ of your _Substrate_ PR add "polkadot companion: [Polkadot_PR_URL]" . Now you should see that the `check_polkadot` CI job will build your Substrate PR agains the mentioned Polkadot branch in your PR description. . Someone will need to approve the Polkadot PR before the Substrate CI will go green. (The Polkadot CI failing can be ignored as long as the polkadot job in the _substrate_ PR is green). . Wait for reviews on both the Substrate and the Polkadot PRs. From ddf89923133ed1a7cbb33dfb84c3ed86efd18239 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 5 Oct 2021 21:15:18 +0900 Subject: [PATCH 0076/1472] Speed up timestamp generation when logging (#9933) * Speed up timestamp generation when logging * Align to review comments. * Correct a typo --- Cargo.lock | 2 + client/tracing/Cargo.toml | 8 + client/tracing/benches/bench.rs | 49 ++++++ client/tracing/src/logging/directives.rs | 5 +- client/tracing/src/logging/event_format.rs | 8 +- client/tracing/src/logging/fast_local_time.rs | 160 ++++++++++++++++++ client/tracing/src/logging/mod.rs | 19 +-- 7 files changed, 230 insertions(+), 21 deletions(-) create mode 100644 client/tracing/benches/bench.rs create mode 100644 client/tracing/src/logging/fast_local_time.rs diff --git a/Cargo.lock b/Cargo.lock index 622b52591b90d..1d23e8814bb04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8537,6 +8537,8 @@ version = "4.0.0-dev" dependencies = [ "ansi_term 0.12.1", "atty", + "chrono", + "criterion", "lazy_static", "log 0.4.14", "once_cell", diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 3e314a82aa583..445718d6306f8 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" atty = "0.2.13" +chrono = "0.4.19" lazy_static = "1.4.0" log = { version = "0.4.8" } once_cell = "1.4.1" @@ -35,3 +36,10 @@ sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-tracing-proc-macro = { version = "4.0.0-dev", path = "./proc-macro" } sc-rpc-server = { version = "4.0.0-dev", path = "../rpc-servers" } + +[dev-dependencies] +criterion = "0.3" + +[[bench]] +name = "bench" +harness = false diff --git a/client/tracing/benches/bench.rs b/client/tracing/benches/bench.rs new file mode 100644 index 0000000000000..ee218958be9b3 --- /dev/null +++ b/client/tracing/benches/bench.rs @@ -0,0 +1,49 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use criterion::{criterion_group, criterion_main, Criterion}; +use tracing_subscriber::fmt::time::{ChronoLocal, FormatTime}; + +fn bench_fast_local_time(c: &mut Criterion) { + c.bench_function("fast_local_time", |b| { + let mut buffer = String::new(); + let t = sc_tracing::logging::FastLocalTime { with_fractional: true }; + b.iter(|| { + buffer.clear(); + t.format_time(&mut buffer).unwrap(); + }) + }); +} + +// This is here just as a point of comparison. +fn bench_chrono_local(c: &mut Criterion) { + c.bench_function("chrono_local", |b| { + let mut buffer = String::new(); + let t = ChronoLocal::with_format("%Y-%m-%d %H:%M:%S%.3f".to_string()); + b.iter(|| { + buffer.clear(); + t.format_time(&mut buffer).unwrap(); + }) + }); +} + +criterion_group! { + name = benches; + config = Criterion::default(); + targets = bench_fast_local_time, bench_chrono_local +} +criterion_main!(benches); diff --git a/client/tracing/src/logging/directives.rs b/client/tracing/src/logging/directives.rs index 5aaeb4d17e7d3..16f68654de1eb 100644 --- a/client/tracing/src/logging/directives.rs +++ b/client/tracing/src/logging/directives.rs @@ -17,8 +17,7 @@ use once_cell::sync::OnceCell; use parking_lot::Mutex; use tracing_subscriber::{ - filter::Directive, fmt as tracing_fmt, fmt::time::ChronoLocal, layer, reload::Handle, - EnvFilter, Registry, + filter::Directive, fmt as tracing_fmt, layer, reload::Handle, EnvFilter, Registry, }; // Handle to reload the tracing log filter @@ -109,6 +108,6 @@ pub(crate) fn set_reload_handle(handle: Handle) { // Used in the reload `Handle`. type SCSubscriber< N = tracing_fmt::format::DefaultFields, - E = crate::logging::EventFormat, + E = crate::logging::EventFormat, W = fn() -> std::io::Stderr, > = layer::Layered, Registry>; diff --git a/client/tracing/src/logging/event_format.rs b/client/tracing/src/logging/event_format.rs index 61d7fe77aec68..5a21192d69c4d 100644 --- a/client/tracing/src/logging/event_format.rs +++ b/client/tracing/src/logging/event_format.rs @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::logging::fast_local_time::FastLocalTime; use ansi_term::Colour; use regex::Regex; use std::fmt::{self, Write}; @@ -23,16 +24,13 @@ use tracing::{Event, Level, Subscriber}; use tracing_log::NormalizeEvent; use tracing_subscriber::{ field::RecordFields, - fmt::{ - time::{FormatTime, SystemTime}, - FmtContext, FormatEvent, FormatFields, - }, + fmt::{time::FormatTime, FmtContext, FormatEvent, FormatFields}, layer::Context, registry::{LookupSpan, SpanRef}, }; /// A pre-configured event formatter. -pub struct EventFormat { +pub struct EventFormat { /// Use the given timer for log message timestamps. pub timer: T, /// Sets whether or not an event's target is displayed. diff --git a/client/tracing/src/logging/fast_local_time.rs b/client/tracing/src/logging/fast_local_time.rs new file mode 100644 index 0000000000000..288e44aa5e3af --- /dev/null +++ b/client/tracing/src/logging/fast_local_time.rs @@ -0,0 +1,160 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use chrono::{Datelike, Timelike}; +use std::{cell::RefCell, fmt::Write, time::SystemTime}; +use tracing_subscriber::fmt::time::FormatTime; + +/// A structure which, when `Display`d, will print out the current local time. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] +pub struct FastLocalTime { + /// Decides whenever the fractional timestamp with be included in the output. + /// + /// If `false` the output will match the following `chrono` format string: + /// `%Y-%m-%d %H:%M:%S` + /// + /// If `true` the output will match the following `chrono` format string: + /// `%Y-%m-%d %H:%M:%S%.3f` + pub with_fractional: bool, +} + +// This is deliberately slightly larger than we actually need, just in case. +const TIMESTAMP_MAXIMUM_LENGTH: usize = 32; + +#[derive(Default)] +struct InlineString { + buffer: [u8; TIMESTAMP_MAXIMUM_LENGTH], + length: usize, +} + +impl Write for InlineString { + fn write_str(&mut self, s: &str) -> std::fmt::Result { + let new_length = self.length + s.len(); + assert!( + new_length <= TIMESTAMP_MAXIMUM_LENGTH, + "buffer overflow when formatting the current timestamp" + ); + + self.buffer[self.length..new_length].copy_from_slice(s.as_bytes()); + self.length = new_length; + Ok(()) + } +} + +impl InlineString { + fn as_str(&self) -> &str { + // SAFETY: this is safe since the only place we append to the buffer + // is in `write_str` from an `&str` + unsafe { std::str::from_utf8_unchecked(&self.buffer[..self.length]) } + } +} + +#[derive(Default)] +struct CachedTimestamp { + buffer: InlineString, + last_regenerated_at: u64, + last_fractional: u32, +} + +thread_local! { + static TIMESTAMP: RefCell = Default::default(); +} + +impl FormatTime for FastLocalTime { + fn format_time(&self, w: &mut dyn Write) -> std::fmt::Result { + const TIMESTAMP_PARTIAL_LENGTH: usize = "0000-00-00 00:00:00".len(); + + let elapsed = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("system time is never before UNIX epoch; qed"); + let unix_time = elapsed.as_secs(); + + TIMESTAMP.with(|cache| { + let mut cache = cache.borrow_mut(); + + // Regenerate the timestamp only at most once each second. + if cache.last_regenerated_at != unix_time { + let ts = chrono::Local::now(); + let fractional = (ts.nanosecond() % 1_000_000_000) / 1_000_000; + cache.last_regenerated_at = unix_time; + cache.last_fractional = fractional; + cache.buffer.length = 0; + + write!( + &mut cache.buffer, + "{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}", + ts.year(), + ts.month(), + ts.day(), + ts.hour(), + ts.minute(), + ts.second(), + fractional + )?; + } else if self.with_fractional { + let fractional = elapsed.subsec_millis(); + + // Regenerate the fractional part at most once each millisecond. + if cache.last_fractional != fractional { + cache.last_fractional = fractional; + cache.buffer.length = TIMESTAMP_PARTIAL_LENGTH + 1; + write!(&mut cache.buffer, "{:03}", fractional)?; + } + } + + let mut slice = cache.buffer.as_str(); + if !self.with_fractional { + slice = &slice[..TIMESTAMP_PARTIAL_LENGTH]; + } + + w.write_str(slice) + }) + } +} + +impl std::fmt::Display for FastLocalTime { + fn fmt(&self, w: &mut std::fmt::Formatter) -> std::fmt::Result { + self.format_time(w) + } +} + +#[test] +fn test_format_fast_local_time() { + assert_eq!( + chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string().len(), + FastLocalTime { with_fractional: false }.to_string().len() + ); + assert_eq!( + chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f").to_string().len(), + FastLocalTime { with_fractional: true }.to_string().len() + ); + + // A simple trick to make sure this test won't randomly fail if we so happen + // to land on the exact moment when we tick over to the next second. + let now_1 = FastLocalTime { with_fractional: false }.to_string(); + let expected = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); + let now_2 = FastLocalTime { with_fractional: false }.to_string(); + + assert!( + now_1 == expected || now_2 == expected, + "'{}' or '{}' should have been equal to '{}'", + now_1, + now_2, + expected + ); +} diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index dd4830fe89752..dd0f7a5d8ae49 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -24,6 +24,7 @@ mod directives; mod event_format; +mod fast_local_time; mod layers; pub use directives::*; @@ -34,8 +35,8 @@ use tracing::Subscriber; use tracing_subscriber::{ filter::LevelFilter, fmt::{ - format, time::ChronoLocal, FormatEvent, FormatFields, Formatter, Layer as FmtLayer, - MakeWriter, SubscriberBuilder, + format, FormatEvent, FormatFields, Formatter, Layer as FmtLayer, MakeWriter, + SubscriberBuilder, }, layer::{self, SubscriberExt}, registry::LookupSpan, @@ -43,6 +44,7 @@ use tracing_subscriber::{ }; pub use event_format::*; +pub use fast_local_time::FastLocalTime; pub use layers::*; /// Logging Result typedef. @@ -89,12 +91,7 @@ fn prepare_subscriber( profiling_targets: Option<&str>, force_colors: Option, builder_hook: impl Fn( - SubscriberBuilder< - format::DefaultFields, - EventFormat, - EnvFilter, - fn() -> std::io::Stderr, - >, + SubscriberBuilder std::io::Stderr>, ) -> SubscriberBuilder, ) -> Result LookupSpan<'a>> where @@ -161,11 +158,7 @@ where }; let enable_color = force_colors.unwrap_or_else(|| atty::is(atty::Stream::Stderr)); - let timer = ChronoLocal::with_format(if simple { - "%Y-%m-%d %H:%M:%S".to_string() - } else { - "%Y-%m-%d %H:%M:%S%.3f".to_string() - }); + let timer = fast_local_time::FastLocalTime { with_fractional: !simple }; let event_format = EventFormat { timer, From 4930977ae1ecc23030cf86466e1960defc2f0a30 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 5 Oct 2021 23:22:28 +0900 Subject: [PATCH 0077/1472] Update multiple dependencies (#9936) --- Cargo.lock | 51 +++++++++++++++++++------------------- client/cli/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- primitives/core/Cargo.toml | 6 ++--- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d23e8814bb04..d47ef8a2cac59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,7 +292,7 @@ dependencies = [ "async-io", "async-lock", "async-process", - "crossbeam-utils 0.8.3", + "crossbeam-utils 0.8.5", "futures-channel", "futures-core", "futures-io", @@ -1260,28 +1260,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.3", + "crossbeam-utils 0.8.5", ] [[package]] name = "crossbeam-deque" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", - "crossbeam-utils 0.8.3", + "crossbeam-utils 0.8.5", ] [[package]] name = "crossbeam-epoch" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.3", + "crossbeam-utils 0.8.5", "lazy_static", "memoffset", "scopeguard", @@ -1300,11 +1300,10 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "autocfg 1.0.1", "cfg-if 1.0.0", "lazy_static", ] @@ -2422,8 +2421,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -4998,12 +4999,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" -dependencies = [ - "parking_lot 0.11.1", -] +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "oorandom" @@ -7161,7 +7159,7 @@ checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ "crossbeam-channel", "crossbeam-deque", - "crossbeam-utils 0.8.3", + "crossbeam-utils 0.8.5", "lazy_static", "num_cpus", ] @@ -10434,9 +10432,9 @@ dependencies = [ [[package]] name = "tiny-bip39" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9e44c4759bae7f1032e286a7ef990bd9ed23fe831b7eeba0beb97484c2e59b8" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" dependencies = [ "anyhow", "hmac 0.8.1", @@ -10447,6 +10445,7 @@ dependencies = [ "sha2 0.9.3", "thiserror", "unicode-normalization", + "wasm-bindgen", "zeroize", ] @@ -10897,11 +10896,11 @@ dependencies = [ [[package]] name = "twox-hash" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59" +checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "rand 0.7.3", "static_assertions", ] @@ -11875,18 +11874,18 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "377db0846015f7ae377174787dd452e1c5f5a9050bc6f954911d01f116daa0cd" +checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.0.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" +checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7" dependencies = [ "proc-macro2", "quote", diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index e7a0330e76e0c..963d5b3d0a905 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -22,7 +22,7 @@ libp2p = "0.39.1" parity-scale-codec = "2.0.0" hex = "0.4.2" rand = "0.7.3" -tiny-bip39 = "0.8.0" +tiny-bip39 = "0.8.2" serde_json = "1.0.68" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-panic-handler = { version = "3.0.0", path = "../../primitives/panic-handler" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 68b9595ae1908..1725e4f5abcff 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -63,7 +63,7 @@ unsigned-varint = { version = "0.6.0", features = [ "asynchronous_codec", ] } void = "1.0.2" -zeroize = "1.4.1" +zeroize = "1.4.2" libp2p = "0.39.1" [dev-dependencies] diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 445718d6306f8..5cac4dccfd6e7 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -18,7 +18,7 @@ atty = "0.2.13" chrono = "0.4.19" lazy_static = "1.4.0" log = { version = "0.4.8" } -once_cell = "1.4.1" +once_cell = "1.8.0" parking_lot = "0.11.1" regex = "1.4.2" rustc-hash = "1.1.0" diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 73c3d454ed584..4e6d6e9960114 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -33,10 +33,10 @@ hash256-std-hasher = { version = "0.15.2", default-features = false } base58 = { version = "0.1.0", optional = true } rand = { version = "0.7.3", optional = true, features = ["small_rng"] } substrate-bip39 = { version = "0.4.2", optional = true } -tiny-bip39 = { version = "0.8", optional = true } +tiny-bip39 = { version = "0.8.2", optional = true } regex = { version = "1.4.2", optional = true } num-traits = { version = "0.2.8", default-features = false } -zeroize = { version = "1.4.1", default-features = false } +zeroize = { version = "1.4.2", default-features = false } secrecy = { version = "0.7.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.11.1", optional = true } @@ -63,7 +63,7 @@ schnorrkel = { version = "0.9.1", features = [ ], default-features = false, optional = true } sha2 = { version = "0.9.2", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } -twox-hash = { version = "1.5.0", default-features = false, optional = true } +twox-hash = { version = "1.6.1", default-features = false, optional = true } libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } From d6a636f5752a0520bc4d4d2325c1d85f8e892ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 5 Oct 2021 23:10:25 +0200 Subject: [PATCH 0078/1472] Remove `IgnoredIssuance` from metadata constants (#9937) This value is not really meant to be "constant". --- frame/gilt/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index de114e4bb87de..393b3acb41a36 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -128,7 +128,6 @@ pub mod pallet { /// The issuance to ignore. This is subtracted from the `Currency`'s `total_issuance` to get /// the issuance by which we inflate or deflate the gilt. - #[pallet::constant] type IgnoredIssuance: Get>; /// Number of duration queues in total. This sets the maximum duration supported, which is From 2a6e82650e6b9dbac4cde6183fb3816193049135 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 21:16:37 +0000 Subject: [PATCH 0079/1472] Bump secrecy from 0.7.0 to 0.8.0 (#9897) Bumps [secrecy](https://github.com/iqlusioninc/crates) from 0.7.0 to 0.8.0. - [Release notes](https://github.com/iqlusioninc/crates/releases) - [Commits](https://github.com/iqlusioninc/crates/compare/secrecy/v0.7.0...secrecy/v0.8.0) --- updated-dependencies: - dependency-name: secrecy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- primitives/core/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d47ef8a2cac59..1beacc1313a73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8724,9 +8724,9 @@ dependencies = [ [[package]] name = "secrecy" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0673d6a6449f5e7d12a1caf424fd9363e2af3a4953023ed455e3c4beef4597c0" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" dependencies = [ "zeroize", ] @@ -10901,7 +10901,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e" dependencies = [ "cfg-if 1.0.0", - "rand 0.7.3", + "rand 0.8.4", "static_assertions", ] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 4e6d6e9960114..ab7d8e3df19a1 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -37,7 +37,7 @@ tiny-bip39 = { version = "0.8.2", optional = true } regex = { version = "1.4.2", optional = true } num-traits = { version = "0.2.8", default-features = false } zeroize = { version = "1.4.2", default-features = false } -secrecy = { version = "0.7.0", default-features = false } +secrecy = { version = "0.8.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.11.1", optional = true } sp-debug-derive = { version = "3.0.0", path = "../debug-derive" } From 669045f6e47249b9c83b81b9432603430cd8109d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 6 Oct 2021 11:20:21 +0200 Subject: [PATCH 0080/1472] `--dev` implies `--tmp` (#9938) * `--dev` implies `--tmp` This changes `--dev` to imply `--tmp` when no explicit `--base-path` is provided. * Update client/cli/src/commands/run_cmd.rs Co-authored-by: Alexander Popiak --- client/cli/src/commands/run_cmd.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 98f2090c6f446..b43135f109735 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -241,6 +241,8 @@ pub struct RunCmd { /// /// Note: the directory is random per process execution. This directory is used as base path /// which includes: database, node key and keystore. + /// + /// When `--dev` is given and no explicit `--base-path`, this option is implied. #[structopt(long, conflicts_with = "base-path")] pub tmp: bool, } @@ -444,7 +446,12 @@ impl CliConfiguration for RunCmd { Ok(if self.tmp { Some(BasePath::new_temp_dir()?) } else { - self.shared_params().base_path() + match self.shared_params().base_path() { + Some(r) => Some(r), + // If `dev` is enabled, we use the temp base path. + None if self.shared_params().is_dev() => Some(BasePath::new_temp_dir()?), + None => None, + } }) } } From b15a15e74b60ce19d8ac94da6dfeeef671a0a49d Mon Sep 17 00:00:00 2001 From: Albrecht <14820950+weichweich@users.noreply.github.com> Date: Wed, 6 Oct 2021 11:22:49 +0200 Subject: [PATCH 0081/1472] disambiguate Config trait in #[pallet::constant] (#9942) * fix: use fully qualified syntax to disambiguate * add instance generic * line length < 100 --- frame/support/procedural/src/pallet/expand/constants.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frame/support/procedural/src/pallet/expand/constants.rs b/frame/support/procedural/src/pallet/expand/constants.rs index 7cc245e8089df..db47bf552ac16 100644 --- a/frame/support/procedural/src/pallet/expand/constants.rs +++ b/frame/support/procedural/src/pallet/expand/constants.rs @@ -35,6 +35,7 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site()); let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site()); let pallet_ident = &def.pallet_struct.pallet; + let trait_use_gen = &def.trait_use_generics(proc_macro2::Span::call_site()); let mut where_clauses = vec![&def.config.where_clause]; where_clauses.extend(def.extra_constants.iter().map(|d| &d.where_clause)); @@ -49,7 +50,8 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { type_: const_.type_.clone(), doc: const_.doc.clone(), default_byte_impl: quote::quote!( - let value = >::get(); + let value = <::#ident as + #frame_support::traits::Get<#const_type>>::get(); #frame_support::codec::Encode::encode(&value) ), } From 4e5b971771eb9b8a10a95c5540292b1b47874ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Wed, 6 Oct 2021 17:22:34 +0100 Subject: [PATCH 0082/1472] staking: only disable slashed validators and keep them disabled for whole era (#9448) * session: remove disabled validators threshold logic * staking: add logic to track offending validators * staking: disable validators for the whole era * frame: fix tests * staking: add tests for disabling validators handling * staking: fix adding offending validator when already slashed in era * address review comments * session, staking: add comments about sorted vecs Co-authored-by: Andronik Ordian --- bin/node/runtime/src/lib.rs | 7 +- frame/aura/src/lib.rs | 2 +- frame/authority-discovery/src/lib.rs | 5 +- frame/babe/src/lib.rs | 4 +- frame/babe/src/mock.rs | 4 +- frame/beefy-mmr/src/mock.rs | 3 - frame/beefy/src/lib.rs | 2 +- frame/beefy/src/mock.rs | 1 - frame/grandpa/src/lib.rs | 2 +- frame/grandpa/src/mock.rs | 4 +- frame/im-online/src/lib.rs | 2 +- frame/im-online/src/mock.rs | 7 +- frame/offences/benchmarking/src/mock.rs | 4 +- frame/session/benchmarking/src/mock.rs | 4 +- frame/session/src/lib.rs | 58 ++++------ frame/session/src/mock.rs | 8 +- frame/session/src/tests.rs | 7 +- frame/staking/fuzzer/src/mock.rs | 2 +- frame/staking/src/lib.rs | 13 +-- frame/staking/src/mock.rs | 34 ++---- frame/staking/src/pallet/impls.rs | 10 ++ frame/staking/src/pallet/mod.rs | 17 +++ frame/staking/src/slashing.rs | 62 ++++++++-- frame/staking/src/tests.rs | 146 ++++++++++++++++++++++-- frame/support/src/traits/validation.rs | 2 +- 25 files changed, 279 insertions(+), 131 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index b115087d514d0..9fac468519a07 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -459,10 +459,6 @@ impl_opaque_keys! { } } -parameter_types! { - pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17); -} - impl pallet_session::Config for Runtime { type Event = Event; type ValidatorId = ::AccountId; @@ -472,7 +468,6 @@ impl pallet_session::Config for Runtime { type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = SessionKeys; - type DisabledValidatorsThreshold = DisabledValidatorsThreshold; type WeightInfo = pallet_session::weights::SubstrateWeight; } @@ -498,6 +493,7 @@ parameter_types! { pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominatorRewardedPerValidator: u32 = 256; + pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub OffchainRepeat: BlockNumber = 5; } @@ -529,6 +525,7 @@ impl pallet_staking::Config for Runtime { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainSequentialPhragmen; // Alternatively, use pallet_staking::UseNominatorsMap to just use the nominators map. diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index e8b68f928e087..4b5294835403a 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -221,7 +221,7 @@ impl OneSessionHandler for Pallet { } } - fn on_disabled(i: usize) { + fn on_disabled(i: u32) { let log: DigestItem = DigestItem::Consensus( AURA_ENGINE_ID, ConsensusLog::::OnDisabled(i as AuthorityIndex).encode(), diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index d093b1533c693..8fced0d18cff1 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -166,7 +166,7 @@ impl OneSessionHandler for Pallet { } } - fn on_disabled(_i: usize) { + fn on_disabled(_i: u32) { // ignore } } @@ -218,7 +218,6 @@ mod tests { type Event = Event; type ValidatorId = AuthorityId; type ValidatorIdOf = ConvertInto; - type DisabledValidatorsThreshold = DisabledValidatorsThreshold; type NextSessionRotation = pallet_session::PeriodicSessions; type WeightInfo = (); } @@ -276,7 +275,7 @@ mod tests { ) { } - fn on_disabled(_validator_index: usize) {} + fn on_disabled(_validator_index: u32) {} fn on_genesis_session(_validators: &[(AuthorityId, Ks)]) {} } diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 4ccfdf6c13fe0..9c755eea6c446 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -926,8 +926,8 @@ impl OneSessionHandler for Pallet { Self::enact_epoch_change(bounded_authorities, next_bounded_authorities) } - fn on_disabled(i: usize) { - Self::deposit_consensus(ConsensusLog::OnDisabled(i as u32)) + fn on_disabled(i: u32) { + Self::deposit_consensus(ConsensusLog::OnDisabled(i)) } } diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index b504a26f60421..e7ec692689032 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -68,7 +68,6 @@ frame_support::construct_runtime!( parameter_types! { pub const BlockHashCount: u64 = 250; - pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(16); pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -122,7 +121,6 @@ impl pallet_session::Config for Test { type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = MockSessionKeys; - type DisabledValidatorsThreshold = DisabledValidatorsThreshold; type WeightInfo = (); } @@ -189,6 +187,7 @@ parameter_types! { pub const MaxNominatorRewardedPerValidator: u32 = 64; pub const ElectionLookahead: u64 = 0; pub const StakingUnsignedPriority: u64 = u64::MAX / 2; + pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(16); } impl onchain::Config for Test { @@ -212,6 +211,7 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 4c9e103eb7b82..95b87c360510a 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -28,7 +28,6 @@ use sp_runtime::{ impl_opaque_keys, testing::Header, traits::{BlakeTwo256, ConvertInto, IdentityLookup, Keccak256, OpaqueKeys}, - Perbill, }; use crate as pallet_beefy_mmr; @@ -92,7 +91,6 @@ impl frame_system::Config for Test { parameter_types! { pub const Period: u64 = 1; pub const Offset: u64 = 0; - pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); } impl pallet_session::Config for Test { @@ -104,7 +102,6 @@ impl pallet_session::Config for Test { type SessionManager = MockSessionManager; type SessionHandler = ::KeyTypeIdProviders; type Keys = MockSessionKeys; - type DisabledValidatorsThreshold = DisabledValidatorsThreshold; type WeightInfo = (); } diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 32f3133373432..3b28d454849cf 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -162,7 +162,7 @@ impl OneSessionHandler for Pallet { } } - fn on_disabled(i: usize) { + fn on_disabled(i: u32) { let log: DigestItem = DigestItem::Consensus( BEEFY_ENGINE_ID, ConsensusLog::::OnDisabled(i as AuthorityIndex).encode(), diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index baa2fae746fe3..a1fbeda4ab35c 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -105,7 +105,6 @@ impl pallet_session::Config for Test { type SessionManager = MockSessionManager; type SessionHandler = ::KeyTypeIdProviders; type Keys = MockSessionKeys; - type DisabledValidatorsThreshold = DisabledValidatorsThreshold; type WeightInfo = (); } diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 687207151f4f4..9f6967a7d3c85 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -674,7 +674,7 @@ where SetIdSession::::insert(current_set_id, &session_index); } - fn on_disabled(i: usize) { + fn on_disabled(i: u32) { Self::deposit_log(ConsensusLog::OnDisabled(i as u64)) } } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 4e5e44ce36e7a..f1996553f02eb 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -111,7 +111,6 @@ where parameter_types! { pub const Period: u64 = 1; pub const Offset: u64 = 0; - pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17); } /// Custom `SessionHandler` since we use `TestSessionKeys` as `Keys`. @@ -124,7 +123,6 @@ impl pallet_session::Config for Test { type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = TestSessionKeys; - type DisabledValidatorsThreshold = DisabledValidatorsThreshold; type WeightInfo = (); } @@ -191,6 +189,7 @@ parameter_types! { pub const MaxNominatorRewardedPerValidator: u32 = 64; pub const ElectionLookahead: u64 = 0; pub const StakingUnsignedPriority: u64 = u64::MAX / 2; + pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); } impl onchain::Config for Test { @@ -214,6 +213,7 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 559c5edcf4d11..d76bbaaa2fd14 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -919,7 +919,7 @@ impl OneSessionHandler for Pallet { } } - fn on_disabled(_i: usize) { + fn on_disabled(_i: u32) { // ignore } } diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 92d1fe8e3f8b9..1e4d4b43d5789 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -27,7 +27,7 @@ use sp_core::H256; use sp_runtime::{ testing::{Header, TestXt, UintAuthorityId}, traits::{BlakeTwo256, ConvertInto, IdentityLookup}, - Perbill, Permill, + Permill, }; use sp_staking::{ offence::{OffenceError, ReportOffence}, @@ -146,10 +146,6 @@ parameter_types! { pub const Offset: u64 = 0; } -parameter_types! { - pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); -} - impl pallet_session::Config for Runtime { type ShouldEndSession = pallet_session::PeriodicSessions; type SessionManager = @@ -159,7 +155,6 @@ impl pallet_session::Config for Runtime { type ValidatorIdOf = ConvertInto; type Keys = UintAuthorityId; type Event = Event; - type DisabledValidatorsThreshold = DisabledValidatorsThreshold; type NextSessionRotation = pallet_session::PeriodicSessions; type WeightInfo = (); } diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 6973e25371d4f..3097f9b95be3f 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -112,7 +112,7 @@ impl pallet_session::SessionHandler for TestSessionHandler { ) { } - fn on_disabled(_: usize) {} + fn on_disabled(_: u32) {} } parameter_types! { @@ -129,7 +129,6 @@ impl pallet_session::Config for Test { type Event = Event; type ValidatorId = AccountId; type ValidatorIdOf = pallet_staking::StashOf; - type DisabledValidatorsThreshold = (); type WeightInfo = (); } @@ -175,6 +174,7 @@ impl pallet_staking::Config for Test { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 4d3a1a2d8689d..f534cc097e8a0 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -117,7 +117,7 @@ impl pallet_session::SessionHandler for TestSessionHandler { ) { } - fn on_disabled(_: usize) {} + fn on_disabled(_: u32) {} } impl pallet_session::Config for Test { @@ -129,7 +129,6 @@ impl pallet_session::Config for Test { type Event = Event; type ValidatorId = AccountId; type ValidatorIdOf = pallet_staking::StashOf; - type DisabledValidatorsThreshold = (); type WeightInfo = (); } pallet_staking_reward_curve::build! { @@ -180,6 +179,7 @@ impl pallet_staking::Config for Test { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 2742d302ce439..10c7ea42b3e9b 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -116,7 +116,7 @@ pub mod weights; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Convert, Member, One, OpaqueKeys, Zero}, - ConsensusEngineId, KeyTypeId, Perbill, Permill, RuntimeAppPublic, + ConsensusEngineId, KeyTypeId, Permill, RuntimeAppPublic, }; use sp_staking::SessionIndex; use sp_std::{ @@ -298,7 +298,7 @@ pub trait SessionHandler { fn on_before_session_ending() {} /// A validator got disabled. Act accordingly until a new session begins. - fn on_disabled(validator_index: usize); + fn on_disabled(validator_index: u32); } #[impl_trait_for_tuples::impl_for_tuples(1, 30)] @@ -342,7 +342,7 @@ impl SessionHandler for Tuple { for_tuples!( #( Tuple::on_before_session_ending(); )* ) } - fn on_disabled(i: usize) { + fn on_disabled(i: u32) { for_tuples!( #( Tuple::on_disabled(i); )* ) } } @@ -354,7 +354,7 @@ impl SessionHandler for TestSessionHandler { fn on_genesis_session(_: &[(AId, Ks)]) {} fn on_new_session(_: bool, _: &[(AId, Ks)], _: &[(AId, Ks)]) {} fn on_before_session_ending() {} - fn on_disabled(_: usize) {} + fn on_disabled(_: u32) {} } #[frame_support::pallet] @@ -401,12 +401,6 @@ pub mod pallet { /// The keys. type Keys: OpaqueKeys + Member + Parameter + Default + MaybeSerializeDeserialize; - /// The fraction of validators set that is safe to be disabled. - /// - /// After the threshold is reached `disabled` method starts to return true, - /// which in combination with `pallet_staking` forces a new era. - type DisabledValidatorsThreshold: Get; - /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -514,7 +508,9 @@ pub mod pallet { /// Indices of disabled validators. /// - /// The set is cleared when `on_session_ending` returns a new set of identities. + /// The vec is always kept sorted so that we can find whether a given validator is + /// disabled using binary search. It gets cleared when `on_session_ending` returns + /// a new set of identities. #[pallet::storage] #[pallet::getter(fn disabled_validators)] pub type DisabledValidators = StorageValue<_, Vec, ValueQuery>; @@ -705,42 +701,34 @@ impl Pallet { T::SessionHandler::on_new_session::(changed, &session_keys, &queued_amalgamated); } - /// Disable the validator of index `i`. - /// - /// Returns `true` if this causes a `DisabledValidatorsThreshold` of validators - /// to be already disabled. - pub fn disable_index(i: usize) -> bool { - let (fire_event, threshold_reached) = >::mutate(|disabled| { - let i = i as u32; + /// Disable the validator of index `i`, returns `false` if the validator was already disabled. + pub fn disable_index(i: u32) -> bool { + if i >= Validators::::decode_len().unwrap_or(0) as u32 { + return false + } + + >::mutate(|disabled| { if let Err(index) = disabled.binary_search(&i) { - let count = >::decode_len().unwrap_or(0) as u32; - let threshold = T::DisabledValidatorsThreshold::get() * count; disabled.insert(index, i); - (true, disabled.len() as u32 > threshold) - } else { - (false, false) + T::SessionHandler::on_disabled(i); + return true } - }); - - if fire_event { - T::SessionHandler::on_disabled(i); - } - threshold_reached + false + }) } /// Disable the validator identified by `c`. (If using with the staking pallet, /// this would be their *stash* account.) /// - /// Returns `Ok(true)` if more than `DisabledValidatorsThreshold` validators in current - /// session is already disabled. - /// If used with the staking pallet it allows to force a new era in such case. - pub fn disable(c: &T::ValidatorId) -> sp_std::result::Result { + /// Returns `false` either if the validator could not be found or it was already + /// disabled. + pub fn disable(c: &T::ValidatorId) -> bool { Self::validators() .iter() .position(|i| i == c) - .map(Self::disable_index) - .ok_or(()) + .map(|i| Self::disable_index(i as u32)) + .unwrap_or(false) } /// Upgrade the key type from some old type to a new type. Supports adding diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index c6b5f64448114..277dec610659b 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -29,7 +29,6 @@ use sp_runtime::{ impl_opaque_keys, testing::{Header, UintAuthorityId}, traits::{BlakeTwo256, ConvertInto, IdentityLookup}, - Perbill, }; use sp_staking::SessionIndex; @@ -144,7 +143,7 @@ impl SessionHandler for TestSessionHandler { .collect() }); } - fn on_disabled(_validator_index: usize) { + fn on_disabled(_validator_index: u32) { DISABLED.with(|l| *l.borrow_mut() = true) } fn on_before_session_ending() { @@ -269,10 +268,6 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } -parameter_types! { - pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); -} - impl Config for Test { type ShouldEndSession = TestShouldEndSession; #[cfg(feature = "historical")] @@ -284,7 +279,6 @@ impl Config for Test { type ValidatorIdOf = ConvertInto; type Keys = MockSessionKeys; type Event = Event; - type DisabledValidatorsThreshold = DisabledValidatorsThreshold; type NextSessionRotation = (); type WeightInfo = (); } diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index 47152042d204f..42a2dd74fd96c 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -338,7 +338,7 @@ fn session_keys_generate_output_works_as_set_keys_input() { } #[test] -fn return_true_if_more_than_third_is_disabled() { +fn disable_index_returns_false_if_already_disabled() { new_test_ext().execute_with(|| { set_next_validators(vec![1, 2, 3, 4, 5, 6, 7]); force_new_session(); @@ -347,10 +347,9 @@ fn return_true_if_more_than_third_is_disabled() { force_new_session(); initialize_block(2); + assert_eq!(Session::disable_index(0), true); assert_eq!(Session::disable_index(0), false); - assert_eq!(Session::disable_index(1), false); - assert_eq!(Session::disable_index(2), true); - assert_eq!(Session::disable_index(3), true); + assert_eq!(Session::disable_index(1), true); }); } diff --git a/frame/staking/fuzzer/src/mock.rs b/frame/staking/fuzzer/src/mock.rs index 921e0d3b48d7d..d5ca78193b0c0 100644 --- a/frame/staking/fuzzer/src/mock.rs +++ b/frame/staking/fuzzer/src/mock.rs @@ -119,7 +119,7 @@ impl pallet_session::SessionHandler for TestSessionHandler { _: &[(AccountId, Ks)], ) {} - fn on_disabled(_: usize) {} + fn on_disabled(_: u32) {} } impl pallet_session::Config for Test { diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 582e9e49bd356..be02e8d91d326 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -619,12 +619,9 @@ pub struct UnappliedSlash { /// /// This is needed because `Staking` sets the `ValidatorIdOf` of the `pallet_session::Config` pub trait SessionInterface: frame_system::Config { - /// Disable a given validator by stash ID. - /// - /// Returns `true` if new era should be forced at the end of this session. - /// This allows preventing a situation where there is too many validators - /// disabled and block production stalls. - fn disable_validator(validator: &AccountId) -> Result; + /// Disable the validator at the given index, returns `false` if the validator was already + /// disabled or the index is out of bounds. + fn disable_validator(validator_index: u32) -> bool; /// Get the validators from session. fn validators() -> Vec; /// Prune historical session tries up to but not including the given index. @@ -645,8 +642,8 @@ where Option<::AccountId>, >, { - fn disable_validator(validator: &::AccountId) -> Result { - >::disable(validator) + fn disable_validator(validator_index: u32) -> bool { + >::disable_index(validator_index) } fn validators() -> Vec<::AccountId> { diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 06c9be9c01e11..95d397359f8d6 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -34,7 +34,7 @@ use sp_runtime::{ traits::{IdentityLookup, Zero}, }; use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; -use std::{cell::RefCell, collections::HashSet}; +use std::cell::RefCell; pub const INIT_TIMESTAMP: u64 = 30_000; pub const BLOCK_TIME: u64 = 1000; @@ -45,10 +45,6 @@ pub(crate) type AccountIndex = u64; pub(crate) type BlockNumber = u64; pub(crate) type Balance = u128; -thread_local! { - static SESSION: RefCell<(Vec, HashSet)> = RefCell::new(Default::default()); -} - /// Another session handler struct to test on_disabled. pub struct OtherSessionHandler; impl OneSessionHandler for OtherSessionHandler { @@ -61,23 +57,14 @@ impl OneSessionHandler for OtherSessionHandler { { } - fn on_new_session<'a, I: 'a>(_: bool, validators: I, _: I) + fn on_new_session<'a, I: 'a>(_: bool, _: I, _: I) where I: Iterator, AccountId: 'a, { - SESSION.with(|x| { - *x.borrow_mut() = (validators.map(|x| x.0.clone()).collect(), HashSet::new()) - }); } - fn on_disabled(validator_index: usize) { - SESSION.with(|d| { - let mut d = d.borrow_mut(); - let value = d.0[validator_index]; - d.1.insert(value); - }) - } + fn on_disabled(_validator_index: u32) {} } impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { @@ -86,7 +73,12 @@ impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { pub fn is_disabled(controller: AccountId) -> bool { let stash = Staking::ledger(&controller).unwrap().stash; - SESSION.with(|d| d.borrow().1.contains(&stash)) + let validator_index = match Session::validators().iter().position(|v| *v == stash) { + Some(index) => index as u32, + None => return false, + }; + + Session::disabled_validators().contains(&validator_index) } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -171,7 +163,6 @@ impl pallet_balances::Config for Test { } parameter_types! { pub const UncleGenerations: u64 = 0; - pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(25); } sp_runtime::impl_opaque_keys! { pub struct SessionKeys { @@ -186,7 +177,6 @@ impl pallet_session::Config for Test { type Event = Event; type ValidatorId = AccountId; type ValidatorIdOf = crate::StashOf; - type DisabledValidatorsThreshold = DisabledValidatorsThreshold; type NextSessionRotation = pallet_session::PeriodicSessions; type WeightInfo = (); } @@ -224,6 +214,7 @@ parameter_types! { pub const BondingDuration: EraIndex = 3; pub const RewardCurve: &'static PiecewiseLinear<'static> = &I_NPOS; pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(75); } thread_local! { @@ -277,6 +268,7 @@ impl crate::pallet::pallet::Config for Test { type EraPayout = ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type WeightInfo = (); @@ -510,10 +502,6 @@ impl ExtBuilder { .assimilate_storage(&mut storage); let mut ext = sp_io::TestExternalities::from(storage); - ext.execute_with(|| { - let validators = Session::validators(); - SESSION.with(|x| *x.borrow_mut() = (validators.clone(), HashSet::new())); - }); if self.initialize_first_session { // We consider all test to start after timestamp is initialized This must be ensured by diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 3ae520872f278..02099d8543d4c 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -302,6 +302,13 @@ impl Pallet { Self::start_era(start_session); } } + + // disable all offending validators that have been disabled for the whole era + for (index, disabled) in >::get() { + if disabled { + T::SessionInterface::disable_validator(index); + } + } } /// End a session potentially ending an era. @@ -374,6 +381,9 @@ impl Pallet { // Set ending era reward. >::insert(&active_era.index, validator_payout); T::RewardRemainder::on_unbalanced(T::Currency::issue(rest)); + + // Clear offending validators. + >::kill(); } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index dad958ccaea2f..8e97a90e07544 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -141,6 +141,10 @@ pub mod pallet { #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; + /// The fraction of the validator set that is safe to be offending. + /// After the threshold is reached a new era will be forced. + type OffendingValidatorsThreshold: Get; + /// Something that can provide a sorted list of voters in a somewhat sorted way. The /// original use case for this was designed with [`pallet_bags_list::Pallet`] in mind. If /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. @@ -437,6 +441,19 @@ pub mod pallet { #[pallet::getter(fn current_planned_session)] pub type CurrentPlannedSession = StorageValue<_, SessionIndex, ValueQuery>; + /// Indices of validators that have offended in the active era and whether they are currently + /// disabled. + /// + /// This value should be a superset of disabled validators since not all offences lead to the + /// validator being disabled (if there was no slash). This is needed to track the percentage of + /// validators that have offended in the current era, ensuring a new era is forced if + /// `OffendingValidatorsThreshold` is reached. The vec is always kept sorted so that we can find + /// whether a given validator has previously offended using binary search. It gets cleared when + /// the era ends. + #[pallet::storage] + #[pallet::getter(fn offending_validators)] + pub type OffendingValidators = StorageValue<_, Vec<(u32, bool)>, ValueQuery>; + /// True if network has been upgraded to this version. /// Storage version of the pallet. /// diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 15ca85b4d046f..68088d0e0d777 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -56,7 +56,7 @@ use crate::{ use codec::{Decode, Encode}; use frame_support::{ ensure, - traits::{Currency, Imbalance, OnUnbalanced}, + traits::{Currency, Get, Imbalance, OnUnbalanced}, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -278,15 +278,13 @@ pub(crate) fn compute_slash( // not continue in the next election. also end the slashing span. spans.end_span(now); >::chill_stash(stash); - - // make sure to disable validator till the end of this session - if T::SessionInterface::disable_validator(stash).unwrap_or(false) { - // force a new era, to select a new validator set - >::ensure_new_era() - } } } + // add the validator to the offenders list and make sure it is disabled for + // the duration of the era + add_offending_validator::(params.stash, true); + let mut nominators_slashed = Vec::new(); reward_payout += slash_nominators::(params, prior_slash_p, &mut nominators_slashed); @@ -316,13 +314,53 @@ fn kick_out_if_recent(params: SlashParams) { if spans.era_span(params.slash_era).map(|s| s.index) == Some(spans.span_index()) { spans.end_span(params.now); >::chill_stash(params.stash); + } + + // add the validator to the offenders list but since there's no slash being + // applied there's no need to disable the validator + add_offending_validator::(params.stash, false); +} + +/// Add the given validator to the offenders list and optionally disable it. +/// If after adding the validator `OffendingValidatorsThreshold` is reached +/// a new era will be forced. +fn add_offending_validator(stash: &T::AccountId, disable: bool) { + as Store>::OffendingValidators::mutate(|offending| { + let validators = T::SessionInterface::validators(); + let validator_index = match validators.iter().position(|i| i == stash) { + Some(index) => index, + None => return, + }; - // make sure to disable validator till the end of this session - if T::SessionInterface::disable_validator(params.stash).unwrap_or(false) { - // force a new era, to select a new validator set - >::ensure_new_era() + let validator_index_u32 = validator_index as u32; + + match offending.binary_search_by_key(&validator_index_u32, |(index, _)| *index) { + // this is a new offending validator + Err(index) => { + offending.insert(index, (validator_index_u32, disable)); + + let offending_threshold = + T::OffendingValidatorsThreshold::get() * validators.len() as u32; + + if offending.len() >= offending_threshold as usize { + // force a new era, to select a new validator set + >::ensure_new_era() + } + + if disable { + T::SessionInterface::disable_validator(validator_index_u32); + } + }, + Ok(index) => { + if disable && !offending[index].1 { + // the validator had previously offended without being disabled, + // let's make sure we disable it now + offending[index].1 = true; + T::SessionInterface::disable_validator(validator_index_u32); + } + }, } - } + }); } /// Slash nominators. Accepts general parameters and the prior slash percentage of the validator. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 6f024eb1e6b04..d6d92d5bd57fc 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2318,10 +2318,11 @@ fn slash_in_old_span_does_not_deselect() { 1, ); - // not forcing for zero-slash and previous span. - assert_eq!(Staking::force_era(), Forcing::NotForcing); - assert!(>::contains_key(11)); - assert!(Session::validators().contains(&11)); + // the validator doesn't get chilled again + assert!(::Validators::iter().find(|(stash, _)| *stash == 11).is_some()); + + // but we are still forcing a new era + assert_eq!(Staking::force_era(), Forcing::ForceNew); on_offence_in_era( &[OffenceDetails { @@ -2333,10 +2334,13 @@ fn slash_in_old_span_does_not_deselect() { 1, ); - // or non-zero. - assert_eq!(Staking::force_era(), Forcing::NotForcing); - assert!(>::contains_key(11)); - assert!(Session::validators().contains(&11)); + // the validator doesn't get chilled again + assert!(::Validators::iter().find(|(stash, _)| *stash == 11).is_some()); + + // but it's disabled + assert!(is_disabled(10)); + // and we are still forcing a new era + assert_eq!(Staking::force_era(), Forcing::ForceNew); }); } @@ -2967,6 +2971,132 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid }); } +#[test] +fn non_slashable_offence_doesnt_disable_validator() { + ExtBuilder::default().build_and_execute(|| { + mock::start_active_era(1); + assert_eq_uvec!(Session::validators(), vec![11, 21]); + + let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + + // offence with no slash associated + on_offence_now( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::zero()], + ); + + // offence that slashes 25% of the bond + on_offence_now( + &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[Perbill::from_percent(25)], + ); + + // the offence for validator 10 wasn't slashable so it wasn't disabled + assert!(!is_disabled(10)); + // whereas validator 20 gets disabled + assert!(is_disabled(20)); + }); +} + +#[test] +fn offence_threshold_triggers_new_era() { + ExtBuilder::default() + .validator_count(4) + .set_status(41, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); + assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41]); + + assert_eq!( + ::OffendingValidatorsThreshold::get(), + Perbill::from_percent(75), + ); + + // we have 4 validators and an offending validator threshold of 75%, + // once the third validator commits an offence a new era should be forced + + let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + let exposure_31 = Staking::eras_stakers(Staking::active_era().unwrap().index, &31); + + on_offence_now( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::zero()], + ); + + assert_eq!(ForceEra::::get(), Forcing::NotForcing); + + on_offence_now( + &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[Perbill::zero()], + ); + + assert_eq!(ForceEra::::get(), Forcing::NotForcing); + + on_offence_now( + &[OffenceDetails { offender: (31, exposure_31.clone()), reporters: vec![] }], + &[Perbill::zero()], + ); + + assert_eq!(ForceEra::::get(), Forcing::ForceNew); + }); +} + +#[test] +fn disabled_validators_are_kept_disabled_for_whole_era() { + ExtBuilder::default() + .validator_count(4) + .set_status(41, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); + assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41]); + assert_eq!(::SessionsPerEra::get(), 3); + + let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + + on_offence_now( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::zero()], + ); + + on_offence_now( + &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[Perbill::from_percent(25)], + ); + + // validator 10 should not be disabled since the offence wasn't slashable + assert!(!is_disabled(10)); + // validator 20 gets disabled since it got slashed + assert!(is_disabled(20)); + + advance_session(); + + // disabled validators should carry-on through all sessions in the era + assert!(!is_disabled(10)); + assert!(is_disabled(20)); + + // validator 10 should now get disabled + on_offence_now( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::from_percent(25)], + ); + + advance_session(); + + // and both are disabled in the last session of the era + assert!(is_disabled(10)); + assert!(is_disabled(20)); + + mock::start_active_era(2); + + // when a new era starts disabled validators get cleared + assert!(!is_disabled(10)); + assert!(!is_disabled(20)); + }); +} + #[test] fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // should check that: diff --git a/frame/support/src/traits/validation.rs b/frame/support/src/traits/validation.rs index 11ea5a79f67ba..674f2d718fffa 100644 --- a/frame/support/src/traits/validation.rs +++ b/frame/support/src/traits/validation.rs @@ -109,7 +109,7 @@ pub trait OneSessionHandler: BoundToRuntimeAppPublic { fn on_before_session_ending() {} /// A validator got disabled. Act accordingly until a new session begins. - fn on_disabled(_validator_index: usize); + fn on_disabled(_validator_index: u32); } /// Something that can estimate at which block the next session rotation will happen (i.e. a new From e904d2ad151670f3d84d98bec1a4d45df8460b2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Oct 2021 18:45:25 +0200 Subject: [PATCH 0083/1472] Bump parity-db from 0.3.1 to 0.3.2 (#9944) Bumps [parity-db](https://github.com/paritytech/parity-db) from 0.3.1 to 0.3.2. - [Release notes](https://github.com/paritytech/parity-db/releases) - [Commits](https://github.com/paritytech/parity-db/commits) --- updated-dependencies: - dependency-name: parity-db 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/db/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1beacc1313a73..f5ae40784281a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6174,9 +6174,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241f9c5d25063080f2c02846221f13e1d0e5e18fa00c32c234aad585b744ee55" +checksum = "91b679c6acc14fac74382942e2b73bea441686a33430b951ea03b5aeb6a7f254" dependencies = [ "blake2-rfc", "crc32fast", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 1d3d76ee7a55a..f9a81d6ce7ea2 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -33,7 +33,7 @@ sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -parity-db = { version = "0.3.1", optional = true } +parity-db = { version = "0.3.2", optional = true } [dev-dependencies] sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } From 56e513364ddef0317c019cdf1251ba251e9cae0b Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 6 Oct 2021 17:56:37 +0100 Subject: [PATCH 0084/1472] remove dep on unmaintained difference crate (#9946) --- Cargo.lock | 41 +++++++++++------------------ bin/node/cli/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/test/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- 6 files changed, 20 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f5ae40784281a..c3de1d3f7414e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,9 +156,9 @@ checksum = "9d6e24d2cce90c53b948c46271bfb053e4bdc2db9b5d3f65e20f8cf28a1b7fc3" [[package]] name = "assert_cmd" -version = "1.0.3" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2475b58cd94eb4f70159f4fd8844ba3b807532fe3131b3373fae060bbe30396" +checksum = "b800c4403e8105d959595e1f88119e78bc12bc874c4336973658b648a746ba93" dependencies = [ "bstr", "doc-comment", @@ -1500,10 +1500,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] -name = "difference" -version = "2.0.0" +name = "difflib" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "digest" @@ -2048,7 +2048,7 @@ dependencies = [ "parity-scale-codec", "parity-util-mem", "paste 1.0.4", - "pretty_assertions 0.6.1", + "pretty_assertions", "scale-info", "serde", "smallvec 1.7.0", @@ -2102,7 +2102,7 @@ dependencies = [ "frame-support-test-pallet", "frame-system", "parity-scale-codec", - "pretty_assertions 0.6.1", + "pretty_assertions", "rustversion", "scale-info", "serde", @@ -5315,7 +5315,7 @@ dependencies = [ "pallet-timestamp", "pallet-utility", "parity-scale-codec", - "pretty_assertions 0.7.2", + "pretty_assertions", "pwasm-utils", "rand 0.7.3", "rand_pcg 0.2.1", @@ -6635,11 +6635,12 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "predicates" -version = "1.0.7" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb433456c1a57cc93554dea3ce40b4c19c4057e41c55d4a0f3d84ea71c325aa" +checksum = "c143348f141cc87aab5b950021bac6145d0e5ae754b0591de23244cee42c9308" dependencies = [ - "difference", + "difflib", + "itertools 0.10.0", "predicates-core", ] @@ -6661,21 +6662,9 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" -dependencies = [ - "ansi_term 0.11.0", - "ctor", - "difference", - "output_vt100", -] - -[[package]] -name = "pretty_assertions" -version = "0.7.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cab0e7c02cf376875e9335e0ba1da535775beb5450d21e1dffca068818ed98b" +checksum = "ec0cfe1b2403f172ba0f234e500906ee0a3e493fb81092dac23ebefe129301cc" dependencies = [ "ansi_term 0.12.1", "ctor", @@ -9701,7 +9690,7 @@ dependencies = [ "num-traits", "parity-scale-codec", "parking_lot 0.11.1", - "pretty_assertions 0.6.1", + "pretty_assertions", "rand 0.7.3", "smallvec 1.7.0", "sp-core", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 1fc7a38b23ca8..42bc48e824c6e 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -117,7 +117,7 @@ sc-service-test = { version = "2.0.0", path = "../../../client/service/test" } sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } futures = "0.3.16" tempfile = "3.1.0" -assert_cmd = "1.0" +assert_cmd = "2.0.1" nix = "0.19" serde_json = "1.0" regex = "1" diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 80dc0b05e7511..08fd416496897 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -47,7 +47,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primit [dev-dependencies] assert_matches = "1" hex-literal = "0.3" -pretty_assertions = "0.7" +pretty_assertions = "1.0.0" wat = "1" # Substrate Dependencies diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index f4af38db54e2d..5f1b24d90a499 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -36,7 +36,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] assert_matches = "1.3.0" -pretty_assertions = "0.6.1" +pretty_assertions = "1.0.0" frame-system = { version = "4.0.0-dev", path = "../system" } parity-util-mem = { version = "0.10.0", default-features = false, features = ["primitive-types"] } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 863afceac4a98..594ed6349e745 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -24,7 +24,7 @@ sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../pr sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } trybuild = "1.0.43" -pretty_assertions = "0.6.1" +pretty_assertions = "1.0.0" rustversion = "1.0.0" frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } # The "std" feature for this pallet is never activated on purpose, in order to test construct_runtime error message diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index e444ae223a742..903db18a38ca5 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -34,7 +34,7 @@ tracing = { version = "0.1.22", optional = true } [dev-dependencies] hex-literal = "0.3.1" sp-runtime = { version = "4.0.0-dev", path = "../runtime" } -pretty_assertions = "0.6.1" +pretty_assertions = "1.0.0" rand = "0.7.2" [features] From aed8d689c861c9b26e3eb59621320f43e0875cb3 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Thu, 7 Oct 2021 07:15:33 +0100 Subject: [PATCH 0085/1472] Less deps: Stop using old version of libsecp256k1 (#9947) (Moving further to 0.7 would require upgrading rand first) --- Cargo.lock | 33 +++---------------------- frame/contracts/Cargo.toml | 2 +- frame/contracts/src/benchmarking/mod.rs | 2 +- 3 files changed, 5 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3de1d3f7414e..0a502439b7254 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2623,17 +2623,6 @@ dependencies = [ "digest 0.9.0", ] -[[package]] -name = "hmac-drbg" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" -dependencies = [ - "digest 0.8.1", - "generic-array 0.12.4", - "hmac 0.7.1", -] - [[package]] name = "hmac-drbg" version = "0.3.0" @@ -3787,22 +3776,6 @@ dependencies = [ "libc", ] -[[package]] -name = "libsecp256k1" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" -dependencies = [ - "arrayref", - "crunchy", - "digest 0.8.1", - "hmac-drbg 0.2.0", - "rand 0.7.3", - "sha2 0.8.2", - "subtle 2.4.0", - "typenum", -] - [[package]] name = "libsecp256k1" version = "0.5.0" @@ -3812,7 +3785,7 @@ dependencies = [ "arrayref", "base64 0.12.3", "digest 0.9.0", - "hmac-drbg 0.3.0", + "hmac-drbg", "libsecp256k1-core 0.2.2", "libsecp256k1-gen-ecmult 0.2.1", "libsecp256k1-gen-genmult 0.2.1", @@ -3831,7 +3804,7 @@ dependencies = [ "arrayref", "base64 0.12.3", "digest 0.9.0", - "hmac-drbg 0.3.0", + "hmac-drbg", "libsecp256k1-core 0.2.2", "libsecp256k1-gen-ecmult 0.2.1", "libsecp256k1-gen-genmult 0.2.1", @@ -5306,7 +5279,7 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", - "libsecp256k1 0.3.5", + "libsecp256k1 0.6.0", "log 0.4.14", "pallet-balances", "pallet-contracts-primitives", diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 08fd416496897..c094e01507712 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -28,7 +28,7 @@ smallvec = { version = "1", default-features = false, features = [ wasmi-validation = { version = "0.4", default-features = false } # Only used in benchmarking to generate random contract code -libsecp256k1 = { version = "0.3.5", optional = true, default-features = false, features = ["hmac"] } +libsecp256k1 = { version = "0.6.0", optional = true, default-features = false, features = ["hmac", "static-context"] } rand = { version = "0.7.3", optional = true, default-features = false } rand_pcg = { version = "0.2", optional = true } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index e382e616f27fd..5c753c2d95558 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1425,7 +1425,7 @@ benchmarks! { let message_hash = sp_io::hashing::blake2_256("Hello world".as_bytes()); let signatures = (0..r * API_BENCHMARK_BATCH_SIZE) .map(|i| { - use secp256k1::{SecretKey, Message, sign}; + use libsecp256k1::{SecretKey, Message, sign}; let private_key = SecretKey::random(&mut rng); let (signature, recovery_id) = sign(&Message::parse(&message_hash), &private_key); From f494bf62d1af52c04bbb2b53aa03f726b42998e0 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Thu, 7 Oct 2021 10:08:57 +0100 Subject: [PATCH 0086/1472] Avoid hangs in tests (#9949) * Avoid hangs in tests * set timeout for 10 mins. --- client/network/test/src/lib.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index bb49cef8c642c..e547fa376b3fc 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -28,8 +28,10 @@ use std::{ pin::Pin, sync::Arc, task::{Context as FutureContext, Poll}, + time::Duration, }; +use async_std::future::timeout; use futures::{future::BoxFuture, prelude::*}; use libp2p::{build_multiaddr, PeerId}; use log::trace; @@ -1017,10 +1019,13 @@ where /// Blocks the current thread until we are sync'ed. /// /// Calls `poll_until_sync` repeatedly. + /// (If we've not synced within 10 mins then panic rather than hang.) fn block_until_sync(&mut self) { - futures::executor::block_on(futures::future::poll_fn::<(), _>(|cx| { - self.poll_until_sync(cx) - })); + futures::executor::block_on(timeout( + Duration::from_secs(10 * 60), + futures::future::poll_fn::<(), _>(|cx| self.poll_until_sync(cx)), + )) + .expect("sync didn't happen within 10 mins"); } /// Blocks the current thread until there are no pending packets. From 97818e44c6d3f829fa65e8ab5fc06a8ca9d266c0 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Thu, 7 Oct 2021 11:31:39 +0200 Subject: [PATCH 0087/1472] Warp sync part II (#9284) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Gap sync * Gap epoch test * Simplified network requests * Update client/db/src/utils.rs Co-authored-by: cheme * Fixed v1 migration and added some comments * Next epoch is always regular * Removed fork tree change * Apply suggestions from code review Co-authored-by: Bastian Köcher * Added a comment and converted assert to error Co-authored-by: cheme Co-authored-by: Bastian Köcher --- bin/node-template/node/src/service.rs | 2 + bin/node/cli/src/service.rs | 2 + client/api/src/in_mem.rs | 1 + .../authority-discovery/src/worker/tests.rs | 1 + client/cli/src/commands/check_block_cmd.rs | 4 +- client/cli/src/commands/import_blocks_cmd.rs | 4 +- client/consensus/babe/src/aux_schema.rs | 22 +- client/consensus/babe/src/lib.rs | 11 +- client/consensus/epochs/src/lib.rs | 326 ++++++++++++++++-- client/consensus/epochs/src/migration.rs | 27 +- client/db/src/lib.rs | 49 ++- client/db/src/light.rs | 1 + client/db/src/utils.rs | 12 +- client/finality-grandpa/src/authorities.rs | 25 +- client/finality-grandpa/src/import.rs | 26 ++ client/finality-grandpa/src/warp_proof.rs | 62 ++-- client/informant/src/display.rs | 12 +- client/network/src/lib.rs | 2 +- client/network/src/protocol.rs | 8 +- client/network/src/protocol/sync.rs | 222 +++++++++--- client/network/src/protocol/sync/state.rs | 6 +- client/network/src/protocol/sync/warp.rs | 29 +- client/network/src/warp_request_handler.rs | 5 +- client/network/test/src/lib.rs | 43 ++- client/network/test/src/sync.rs | 32 ++ client/service/src/chain_ops/check_block.rs | 4 +- client/service/src/chain_ops/import_blocks.rs | 8 +- client/service/src/client/client.rs | 23 +- primitives/blockchain/src/backend.rs | 2 + 29 files changed, 801 insertions(+), 170 deletions(-) diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 0f09ef436acad..a70dd877ff35a 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -179,6 +179,7 @@ pub fn new_full(mut config: Configuration) -> Result let warp_sync = Arc::new(sc_finality_grandpa::warp_proof::NetworkProvider::new( backend.clone(), grandpa_link.shared_authority_set().clone(), + Vec::default(), )); let (network, system_rpc_tx, network_starter) = @@ -409,6 +410,7 @@ pub fn new_light(mut config: Configuration) -> Result let warp_sync = Arc::new(sc_finality_grandpa::warp_proof::NetworkProvider::new( backend.clone(), grandpa_link.shared_authority_set().clone(), + Vec::default(), )); let (network, system_rpc_tx, network_starter) = diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index b1a3bd4722597..ec5497ab47d91 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -244,6 +244,7 @@ pub fn new_full_base( let warp_sync = Arc::new(grandpa::warp_proof::NetworkProvider::new( backend.clone(), import_setup.1.shared_authority_set().clone(), + Vec::default(), )); let (network, system_rpc_tx, network_starter) = @@ -531,6 +532,7 @@ pub fn new_light_base( let warp_sync = Arc::new(grandpa::warp_proof::NetworkProvider::new( backend.clone(), grandpa_link.shared_authority_set().clone(), + Vec::default(), )); let (network, system_rpc_tx, network_starter) = diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index e8fce19f8124e..2f4327dfc4e4a 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -369,6 +369,7 @@ impl HeaderBackend for Blockchain { None }, number_leaves: storage.leaves.count(), + block_gap: None, } } diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index f10d2751ccd35..3c1610256f5bc 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -73,6 +73,7 @@ impl HeaderBackend for TestApi { genesis_hash: Default::default(), number_leaves: Default::default(), finalized_state: None, + block_gap: None, } } diff --git a/client/cli/src/commands/check_block_cmd.rs b/client/cli/src/commands/check_block_cmd.rs index 07a76319dca3f..de0d1132ce8be 100644 --- a/client/cli/src/commands/check_block_cmd.rs +++ b/client/cli/src/commands/check_block_cmd.rs @@ -21,7 +21,7 @@ use crate::{ params::{BlockNumberOrHash, ImportParams, SharedParams}, CliConfiguration, }; -use sc_client_api::{BlockBackend, UsageProvider}; +use sc_client_api::{BlockBackend, HeaderBackend}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::{fmt::Debug, str::FromStr, sync::Arc}; use structopt::StructOpt; @@ -53,7 +53,7 @@ impl CheckBlockCmd { pub async fn run(&self, client: Arc, import_queue: IQ) -> error::Result<()> where B: BlockT + for<'de> serde::Deserialize<'de>, - C: BlockBackend + UsageProvider + Send + Sync + 'static, + C: BlockBackend + HeaderBackend + Send + Sync + 'static, IQ: sc_service::ImportQueue + 'static, B::Hash: FromStr, ::Err: Debug, diff --git a/client/cli/src/commands/import_blocks_cmd.rs b/client/cli/src/commands/import_blocks_cmd.rs index 9b211b88d5563..19187f2859621 100644 --- a/client/cli/src/commands/import_blocks_cmd.rs +++ b/client/cli/src/commands/import_blocks_cmd.rs @@ -21,7 +21,7 @@ use crate::{ params::{ImportParams, SharedParams}, CliConfiguration, }; -use sc_client_api::UsageProvider; +use sc_client_api::HeaderBackend; use sc_service::chain_ops::import_blocks; use sp_runtime::traits::Block as BlockT; use std::{ @@ -68,7 +68,7 @@ impl ImportBlocksCmd { /// Run the import-blocks command pub async fn run(&self, client: Arc, import_queue: IQ) -> error::Result<()> where - C: UsageProvider + Send + Sync + 'static, + C: HeaderBackend + Send + Sync + 'static, B: BlockT + for<'de> serde::Deserialize<'de>, IQ: sc_service::ImportQueue + 'static, { diff --git a/client/consensus/babe/src/aux_schema.rs b/client/consensus/babe/src/aux_schema.rs index b18220c3e360a..d5b8a218a5a3f 100644 --- a/client/consensus/babe/src/aux_schema.rs +++ b/client/consensus/babe/src/aux_schema.rs @@ -23,14 +23,17 @@ use log::info; use crate::{migration::EpochV0, Epoch}; use sc_client_api::backend::AuxStore; -use sc_consensus_epochs::{migration::EpochChangesForV0, EpochChangesFor, SharedEpochChanges}; +use sc_consensus_epochs::{ + migration::{EpochChangesV0For, EpochChangesV1For}, + EpochChangesFor, SharedEpochChanges, +}; use sp_blockchain::{Error as ClientError, Result as ClientResult}; use sp_consensus_babe::{BabeBlockWeight, BabeGenesisConfiguration}; use sp_runtime::traits::Block as BlockT; const BABE_EPOCH_CHANGES_VERSION: &[u8] = b"babe_epoch_changes_version"; const BABE_EPOCH_CHANGES_KEY: &[u8] = b"babe_epoch_changes"; -const BABE_EPOCH_CHANGES_CURRENT_VERSION: u32 = 2; +const BABE_EPOCH_CHANGES_CURRENT_VERSION: u32 = 3; /// The aux storage key used to store the block weight of the given block hash. pub fn block_weight_key(block_hash: H) -> Vec { @@ -60,11 +63,16 @@ pub fn load_epoch_changes( let maybe_epoch_changes = match version { None => - load_decode::<_, EpochChangesForV0>(backend, BABE_EPOCH_CHANGES_KEY)? + load_decode::<_, EpochChangesV0For>(backend, BABE_EPOCH_CHANGES_KEY)? .map(|v0| v0.migrate().map(|_, _, epoch| epoch.migrate(config))), Some(1) => - load_decode::<_, EpochChangesFor>(backend, BABE_EPOCH_CHANGES_KEY)? - .map(|v1| v1.map(|_, _, epoch| epoch.migrate(config))), + load_decode::<_, EpochChangesV1For>(backend, BABE_EPOCH_CHANGES_KEY)? + .map(|v1| v1.migrate().map(|_, _, epoch| epoch.migrate(config))), + Some(2) => { + // v2 still uses `EpochChanges` v1 format but with a different `Epoch` type. + load_decode::<_, EpochChangesV1For>(backend, BABE_EPOCH_CHANGES_KEY)? + .map(|v2| v2.migrate()) + }, Some(BABE_EPOCH_CHANGES_CURRENT_VERSION) => load_decode::<_, EpochChangesFor>(backend, BABE_EPOCH_CHANGES_KEY)?, Some(other) => @@ -164,7 +172,7 @@ mod test { .insert_aux( &[( BABE_EPOCH_CHANGES_KEY, - &EpochChangesForV0::::from_raw(v0_tree).encode()[..], + &EpochChangesV0For::::from_raw(v0_tree).encode()[..], )], &[], ) @@ -202,6 +210,6 @@ mod test { client.insert_aux(values, &[]).unwrap(); }); - assert_eq!(load_decode::<_, u32>(&client, BABE_EPOCH_CHANGES_VERSION).unwrap(), Some(2)); + assert_eq!(load_decode::<_, u32>(&client, BABE_EPOCH_CHANGES_VERSION).unwrap(), Some(3)); } } diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index a0b6bde025b3f..1fde788041155 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1578,8 +1578,12 @@ where *block.header.parent_hash(), next_epoch, ) - .map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))?; - + .map_err(|e| { + ConsensusError::ClientImport(format!( + "Error importing epoch changes: {:?}", + e + )) + })?; Ok(()) }; @@ -1667,6 +1671,9 @@ where Client: HeaderBackend + HeaderMetadata, { let info = client.info(); + if info.block_gap.is_none() { + epoch_changes.clear_gap(); + } let finalized_slot = { let finalized_header = client diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index f3cfc55bae69b..661cb900ae6e9 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -78,11 +78,11 @@ where /// /// Once an epoch is created, it must have a known `start_slot` and `end_slot`, which cannot be /// changed. Consensus engine may modify any other data in the epoch, if needed. -pub trait Epoch { +pub trait Epoch: std::fmt::Debug { /// Descriptor for the next epoch. type NextEpochDescriptor; /// Type of the slot number. - type Slot: Ord + Copy; + type Slot: Ord + Copy + std::fmt::Debug; /// The starting slot of the epoch. fn start_slot(&self) -> Self::Slot; @@ -228,7 +228,7 @@ impl ViableEpochDescriptor { } /// Persisted epoch stored in EpochChanges. -#[derive(Clone, Encode, Decode)] +#[derive(Clone, Encode, Decode, Debug)] pub enum PersistedEpoch { /// Genesis persisted epoch data. epoch_0, epoch_1. Genesis(E, E), @@ -246,8 +246,23 @@ impl<'a, E: Epoch> From<&'a PersistedEpoch> for PersistedEpochHeader { } } +impl PersistedEpoch { + /// Map the epoch to a different type using a conversion function. + pub fn map(self, h: &Hash, n: &Number, f: &mut F) -> PersistedEpoch + where + B: Epoch, + F: FnMut(&Hash, &Number, E) -> B, + { + match self { + PersistedEpoch::Genesis(epoch_0, epoch_1) => + PersistedEpoch::Genesis(f(h, n, epoch_0), f(h, n, epoch_1)), + PersistedEpoch::Regular(epoch_n) => PersistedEpoch::Regular(f(h, n, epoch_n)), + } + } +} + /// Persisted epoch header stored in ForkTree. -#[derive(Encode, Decode, PartialEq, Eq)] +#[derive(Encode, Decode, PartialEq, Eq, Debug)] pub enum PersistedEpochHeader { /// Genesis persisted epoch header. epoch_0, epoch_1. Genesis(EpochHeader, EpochHeader), @@ -264,6 +279,25 @@ impl Clone for PersistedEpochHeader { } } +impl PersistedEpochHeader { + /// Map the epoch header to a different type. + pub fn map(self) -> PersistedEpochHeader + where + B: Epoch, + { + match self { + PersistedEpochHeader::Genesis(epoch_0, epoch_1) => PersistedEpochHeader::Genesis( + EpochHeader { start_slot: epoch_0.start_slot, end_slot: epoch_0.end_slot }, + EpochHeader { start_slot: epoch_1.start_slot, end_slot: epoch_1.end_slot }, + ), + PersistedEpochHeader::Regular(epoch_n) => PersistedEpochHeader::Regular(EpochHeader { + start_slot: epoch_n.start_slot, + end_slot: epoch_n.end_slot, + }), + } + } +} + /// A fresh, incremented epoch to import into the underlying fork-tree. /// /// Create this with `ViableEpoch::increment`. @@ -279,6 +313,106 @@ impl AsRef for IncrementedEpoch { } } +/// A pair of epochs for the gap block download validation. +/// Block gap is created after the warp sync is complete. Blocks +/// are imported both at the tip of the chain and at the start of the gap. +/// This holds a pair of epochs that are required to validate headers +/// at the start of the gap. Since gap download does not allow forks we don't +/// need to keep a tree of epochs. +#[derive(Clone, Encode, Decode, Debug)] +pub struct GapEpochs { + current: (Hash, Number, PersistedEpoch), + next: Option<(Hash, Number, E)>, +} + +impl GapEpochs +where + Hash: Copy + PartialEq + std::fmt::Debug, + Number: Copy + PartialEq + std::fmt::Debug, + E: Epoch, +{ + /// Check if given slot matches one of the gap epochs. + /// Returns epoch identifier if it does. + fn matches( + &self, + slot: E::Slot, + ) -> Option<(Hash, Number, EpochHeader, EpochIdentifierPosition)> { + match &self.current { + (_, _, PersistedEpoch::Genesis(epoch_0, _)) + if slot >= epoch_0.start_slot() && slot < epoch_0.end_slot() => + return Some(( + self.current.0, + self.current.1, + epoch_0.into(), + EpochIdentifierPosition::Genesis0, + )), + (_, _, PersistedEpoch::Genesis(_, epoch_1)) + if slot >= epoch_1.start_slot() && slot < epoch_1.end_slot() => + return Some(( + self.current.0, + self.current.1, + epoch_1.into(), + EpochIdentifierPosition::Genesis1, + )), + (_, _, PersistedEpoch::Regular(epoch_n)) + if slot >= epoch_n.start_slot() && slot < epoch_n.end_slot() => + return Some(( + self.current.0, + self.current.1, + epoch_n.into(), + EpochIdentifierPosition::Regular, + )), + _ => {}, + }; + match &self.next { + Some((h, n, epoch_n)) if slot >= epoch_n.start_slot() && slot < epoch_n.end_slot() => + Some((*h, *n, epoch_n.into(), EpochIdentifierPosition::Regular)), + _ => None, + } + } + + /// Returns epoch data if it matches given identifier. + pub fn epoch(&self, id: &EpochIdentifier) -> Option<&E> { + match (&self.current, &self.next) { + ((h, n, e), _) if h == &id.hash && n == &id.number => match e { + PersistedEpoch::Genesis(ref epoch_0, _) + if id.position == EpochIdentifierPosition::Genesis0 => + Some(epoch_0), + PersistedEpoch::Genesis(_, ref epoch_1) + if id.position == EpochIdentifierPosition::Genesis1 => + Some(epoch_1), + PersistedEpoch::Regular(ref epoch_n) + if id.position == EpochIdentifierPosition::Regular => + Some(epoch_n), + _ => None, + }, + (_, Some((h, n, e))) + if h == &id.hash && + n == &id.number && id.position == EpochIdentifierPosition::Regular => + Some(e), + _ => None, + } + } + + /// Import a new gap epoch, potentially replacing an old epoch. + fn import(&mut self, slot: E::Slot, hash: Hash, number: Number, epoch: E) -> Result<(), E> { + match (&mut self.current, &mut self.next) { + ((_, _, PersistedEpoch::Genesis(_, epoch_1)), _) if slot == epoch_1.end_slot() => { + self.next = Some((hash, number, epoch)); + Ok(()) + }, + (_, Some((_, _, epoch_n))) if slot == epoch_n.end_slot() => { + let (cur_h, cur_n, cur_epoch) = + self.next.take().expect("Already matched as `Some`"); + self.current = (cur_h, cur_n, PersistedEpoch::Regular(cur_epoch)); + self.next = Some((hash, number, epoch)); + Ok(()) + }, + _ => Err(epoch), + } + } +} + /// Tree of all epoch changes across all *seen* forks. Data stored in tree is /// the hash and block number of the block signaling the epoch change, and the /// epoch that was signalled at that block. @@ -294,10 +428,14 @@ impl AsRef for IncrementedEpoch { /// same DAG entry, pinned to a specific block #1. /// /// Further epochs (epoch_2, ..., epoch_n) each get their own entry. -#[derive(Clone, Encode, Decode)] +/// +/// Also maintains a pair of epochs for the start of the gap, +/// as long as there's an active gap download after a warp sync. +#[derive(Clone, Encode, Decode, Debug)] pub struct EpochChanges { inner: ForkTree>, epochs: BTreeMap<(Hash, Number), PersistedEpoch>, + gap: Option>, } // create a fake header hash which hasn't been included in the chain. @@ -315,14 +453,14 @@ where Number: Ord, { fn default() -> Self { - EpochChanges { inner: ForkTree::new(), epochs: BTreeMap::new() } + EpochChanges { inner: ForkTree::new(), epochs: BTreeMap::new(), gap: None } } } impl EpochChanges where - Hash: PartialEq + Ord + AsRef<[u8]> + AsMut<[u8]> + Copy, - Number: Ord + One + Zero + Add + Sub + Copy, + Hash: PartialEq + Ord + AsRef<[u8]> + AsMut<[u8]> + Copy + std::fmt::Debug, + Number: Ord + One + Zero + Add + Sub + Copy + std::fmt::Debug, { /// Create a new epoch change. pub fn new() -> Self { @@ -335,6 +473,11 @@ where self.inner.rebalance() } + /// Clear gap epochs if any. + pub fn clear_gap(&mut self) { + self.gap = None; + } + /// Map the epoch changes from one storing data to a different one. pub fn map(self, mut f: F) -> EpochChanges where @@ -342,31 +485,15 @@ where F: FnMut(&Hash, &Number, E) -> B, { EpochChanges { - inner: self.inner.map(&mut |_, _, header| match header { - PersistedEpochHeader::Genesis(epoch_0, epoch_1) => PersistedEpochHeader::Genesis( - EpochHeader { start_slot: epoch_0.start_slot, end_slot: epoch_0.end_slot }, - EpochHeader { start_slot: epoch_1.start_slot, end_slot: epoch_1.end_slot }, - ), - PersistedEpochHeader::Regular(epoch_n) => - PersistedEpochHeader::Regular(EpochHeader { - start_slot: epoch_n.start_slot, - end_slot: epoch_n.end_slot, - }), + inner: self.inner.map(&mut |_, _, header: PersistedEpochHeader| header.map()), + gap: self.gap.map(|GapEpochs { current: (h, n, header), next }| GapEpochs { + current: (h, n, header.map(&h, &n, &mut f)), + next: next.map(|(h, n, e)| (h, n, f(&h, &n, e))), }), epochs: self .epochs .into_iter() - .map(|((hash, number), epoch)| { - let bepoch = match epoch { - PersistedEpoch::Genesis(epoch_0, epoch_1) => PersistedEpoch::Genesis( - f(&hash, &number, epoch_0), - f(&hash, &number, epoch_1), - ), - PersistedEpoch::Regular(epoch_n) => - PersistedEpoch::Regular(f(&hash, &number, epoch_n)), - }; - ((hash, number), bepoch) - }) + .map(|((hash, number), epoch)| ((hash, number), epoch.map(&hash, &number, &mut f))) .collect(), } } @@ -402,6 +529,9 @@ where /// Get a reference to an epoch with given identifier. pub fn epoch(&self, id: &EpochIdentifier) -> Option<&E> { + if let Some(e) = &self.gap.as_ref().and_then(|gap| gap.epoch(id)) { + return Some(e) + } self.epochs.get(&(id.hash, id.number)).and_then(|v| match v { PersistedEpoch::Genesis(ref epoch_0, _) if id.position == EpochIdentifierPosition::Genesis0 => @@ -537,6 +667,15 @@ where return Ok(Some(ViableEpochDescriptor::UnimportedGenesis(slot))) } + if let Some(gap) = &self.gap { + if let Some((hash, number, hdr, position)) = gap.matches(slot) { + return Ok(Some(ViableEpochDescriptor::Signaled( + EpochIdentifier { position, hash, number }, + hdr, + ))) + } + } + // We want to find the deepest node in the tree which is an ancestor // of our block and where the start slot of the epoch was before the // slot of our block. The genesis special-case doesn't need to look @@ -598,13 +737,30 @@ where ) -> Result<(), fork_tree::Error> { let is_descendent_of = descendent_of_builder.build_is_descendent_of(Some((hash, parent_hash))); - let header = PersistedEpochHeader::::from(&epoch.0); + let slot = epoch.as_ref().start_slot(); + let IncrementedEpoch(mut epoch) = epoch; + let header = PersistedEpochHeader::::from(&epoch); + + if let Some(gap) = &mut self.gap { + if let PersistedEpoch::Regular(e) = epoch { + epoch = match gap.import(slot, hash.clone(), number.clone(), e) { + Ok(()) => return Ok(()), + Err(e) => PersistedEpoch::Regular(e), + } + } + } else if !self.epochs.is_empty() && matches!(epoch, PersistedEpoch::Genesis(_, _)) { + // There's a genesis epoch imported when we already have an active epoch. + // This happens after the warp sync as the ancient blocks download start. + // We need to start tracking gap epochs here. + self.gap = Some(GapEpochs { current: (hash, number, epoch), next: None }); + return Ok(()) + } let res = self.inner.import(hash, number, header, &is_descendent_of); match res { Ok(_) | Err(fork_tree::Error::Duplicate) => { - self.epochs.insert((hash, number), epoch.0); + self.epochs.insert((hash, number), epoch); Ok(()) }, Err(e) => Err(e), @@ -916,4 +1072,112 @@ mod tests { assert!(epoch_for_x_child_before_genesis.is_none()); } } + + #[test] + fn gap_epochs_advance() { + // 0 - 1 - 2 - 3 - .... 42 - 43 + let is_descendent_of = |base: &Hash, block: &Hash| -> Result { + match (base, *block) { + (b"0", _) => Ok(true), + (b"1", b) => Ok(b == *b"0"), + (b"2", b) => Ok(b == *b"1"), + (b"3", b) => Ok(b == *b"2"), + _ => Ok(false), + } + }; + + let duration = 100; + + let make_genesis = |slot| Epoch { start_slot: slot, duration }; + + let mut epoch_changes = EpochChanges::new(); + let next_descriptor = (); + + let epoch42 = Epoch { start_slot: 42, duration: 100 }; + let epoch43 = Epoch { start_slot: 43, duration: 100 }; + epoch_changes.reset(*b"0", *b"1", 4200, epoch42, epoch43); + assert!(epoch_changes.gap.is_none()); + + // Import a new genesis epoch, this should crate the gap. + let genesis_epoch_a_descriptor = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 100) + .unwrap() + .unwrap(); + + let incremented_epoch = epoch_changes + .viable_epoch(&genesis_epoch_a_descriptor, &make_genesis) + .unwrap() + .increment(next_descriptor.clone()); + + epoch_changes + .import(&is_descendent_of, *b"1", 1, *b"0", incremented_epoch) + .unwrap(); + assert!(epoch_changes.gap.is_some()); + + let genesis_epoch = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 100) + .unwrap() + .unwrap(); + + assert_eq!(genesis_epoch, ViableEpochDescriptor::UnimportedGenesis(100)); + + // Import more epochs and check that gap advances. + let import_epoch_1 = + epoch_changes.viable_epoch(&genesis_epoch, &make_genesis).unwrap().increment(()); + + let epoch_1 = import_epoch_1.as_ref().clone(); + epoch_changes + .import(&is_descendent_of, *b"1", 1, *b"0", import_epoch_1) + .unwrap(); + let genesis_epoch_data = epoch_changes.epoch_data(&genesis_epoch, &make_genesis).unwrap(); + let end_slot = genesis_epoch_data.end_slot(); + let x = epoch_changes + .epoch_data_for_child_of(&is_descendent_of, b"1", 1, end_slot, &make_genesis) + .unwrap() + .unwrap(); + + assert_eq!(x, epoch_1); + assert_eq!(epoch_changes.gap.as_ref().unwrap().current.0, *b"1"); + assert!(epoch_changes.gap.as_ref().unwrap().next.is_none()); + + let epoch_1_desriptor = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, b"1", 1, end_slot) + .unwrap() + .unwrap(); + let epoch_1 = epoch_changes.epoch_data(&epoch_1_desriptor, &make_genesis).unwrap(); + let import_epoch_2 = epoch_changes + .viable_epoch(&epoch_1_desriptor, &make_genesis) + .unwrap() + .increment(()); + let epoch_2 = import_epoch_2.as_ref().clone(); + epoch_changes + .import(&is_descendent_of, *b"2", 2, *b"1", import_epoch_2) + .unwrap(); + + let end_slot = epoch_1.end_slot(); + let x = epoch_changes + .epoch_data_for_child_of(&is_descendent_of, b"2", 2, end_slot, &make_genesis) + .unwrap() + .unwrap(); + assert_eq!(epoch_changes.gap.as_ref().unwrap().current.0, *b"1"); + assert_eq!(epoch_changes.gap.as_ref().unwrap().next.as_ref().unwrap().0, *b"2"); + assert_eq!(x, epoch_2); + + let epoch_2_desriptor = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, b"2", 2, end_slot) + .unwrap() + .unwrap(); + let import_epoch_3 = epoch_changes + .viable_epoch(&epoch_2_desriptor, &make_genesis) + .unwrap() + .increment(()); + epoch_changes + .import(&is_descendent_of, *b"3", 3, *b"2", import_epoch_3) + .unwrap(); + + assert_eq!(epoch_changes.gap.as_ref().unwrap().current.0, *b"2"); + + epoch_changes.clear_gap(); + assert!(epoch_changes.gap.is_none()); + } } diff --git a/client/consensus/epochs/src/migration.rs b/client/consensus/epochs/src/migration.rs index 49e08240df8c3..e4b685c6ffb18 100644 --- a/client/consensus/epochs/src/migration.rs +++ b/client/consensus/epochs/src/migration.rs @@ -30,9 +30,19 @@ pub struct EpochChangesV0 { inner: ForkTree>, } -/// Type alias for legacy definition of epoch changes. -pub type EpochChangesForV0 = +/// Legacy definition of epoch changes. +#[derive(Clone, Encode, Decode)] +pub struct EpochChangesV1 { + inner: ForkTree>, + epochs: BTreeMap<(Hash, Number), PersistedEpoch>, +} + +/// Type alias for v0 definition of epoch changes. +pub type EpochChangesV0For = EpochChangesV0<::Hash, NumberFor, Epoch>; +/// Type alias for v1 and v2 definition of epoch changes. +pub type EpochChangesV1For = + EpochChangesV1<::Hash, NumberFor, Epoch>; impl EpochChangesV0 where @@ -54,6 +64,17 @@ where header }); - EpochChanges { inner, epochs } + EpochChanges { inner, epochs, gap: None } + } +} + +impl EpochChangesV1 +where + Hash: PartialEq + Ord + Copy, + Number: Ord + Copy, +{ + /// Migrate the type into current epoch changes definition. + pub fn migrate(self) -> EpochChanges { + EpochChanges { inner: self.inner, epochs: self.epochs, gap: None } } } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 66adb64c0109e..549ef4012a739 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -502,6 +502,11 @@ impl BlockchainDb { } } + fn update_block_gap(&self, gap: Option<(NumberFor, NumberFor)>) { + let mut meta = self.meta.write(); + meta.block_gap = gap; + } + // Get block changes trie root, if available. fn changes_trie_root(&self, block: BlockId) -> ClientResult> { self.header(block).map(|header| { @@ -538,6 +543,7 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha finalized_number: meta.finalized_number, finalized_state: meta.finalized_state.clone(), number_leaves: self.leaves.read().count(), + block_gap: meta.block_gap, } } @@ -1388,9 +1394,10 @@ impl Backend { operation.apply_offchain(&mut transaction); let mut meta_updates = Vec::with_capacity(operation.finalized_blocks.len()); - let mut last_finalized_hash = self.blockchain.meta.read().finalized_hash; - let mut last_finalized_num = self.blockchain.meta.read().finalized_number; - let best_num = self.blockchain.meta.read().best_number; + let (best_num, mut last_finalized_hash, mut last_finalized_num, mut block_gap) = { + let meta = self.blockchain.meta.read(); + (meta.best_number, meta.finalized_hash, meta.finalized_number, meta.block_gap.clone()) + }; let mut changes_trie_cache_ops = None; for (block, justification) in operation.finalized_blocks { @@ -1639,6 +1646,41 @@ impl Backend { children, ); } + + if let Some((mut start, end)) = block_gap { + if number == start { + start += One::one(); + utils::insert_number_to_key_mapping( + &mut transaction, + columns::KEY_LOOKUP, + number, + hash, + )?; + } + if start > end { + transaction.remove(columns::META, meta_keys::BLOCK_GAP); + block_gap = None; + debug!(target: "db", "Removed block gap."); + } else { + block_gap = Some((start, end)); + debug!(target: "db", "Update block gap. {:?}", block_gap); + transaction.set( + columns::META, + meta_keys::BLOCK_GAP, + &(start, end).encode(), + ); + } + } else if number > best_num + One::one() && + number > One::one() && self + .blockchain + .header(BlockId::hash(parent_hash))? + .is_none() + { + let gap = (best_num + One::one(), number - One::one()); + transaction.set(columns::META, meta_keys::BLOCK_GAP, &gap.encode()); + block_gap = Some(gap); + debug!(target: "db", "Detected block gap {:?}", block_gap); + } } meta_updates.push(MetaUpdate { @@ -1716,6 +1758,7 @@ impl Backend { for m in meta_updates { self.blockchain.update_meta(m); } + self.blockchain.update_block_gap(block_gap); Ok(()) } diff --git a/client/db/src/light.rs b/client/db/src/light.rs index bf2da5c61d058..48cf0489cf2a0 100644 --- a/client/db/src/light.rs +++ b/client/db/src/light.rs @@ -157,6 +157,7 @@ where None }, number_leaves: 1, + block_gap: None, } } diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index ea22c774f463e..0e895eaaf3851 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -54,6 +54,8 @@ pub mod meta_keys { pub const FINALIZED_BLOCK: &[u8; 5] = b"final"; /// Last finalized state key. pub const FINALIZED_STATE: &[u8; 6] = b"fstate"; + /// Block gap. + pub const BLOCK_GAP: &[u8; 3] = b"gap"; /// Meta information prefix for list-based caches. pub const CACHE_META_PREFIX: &[u8; 5] = b"cache"; /// Meta information for changes tries key. @@ -81,6 +83,8 @@ pub struct Meta { pub genesis_hash: H, /// Finalized state, if any pub finalized_state: Option<(H, N)>, + /// Block gap, start and end inclusive, if any. + pub block_gap: Option<(N, N)>, } /// A block lookup key: used for canonical lookup from block number to hash @@ -527,6 +531,7 @@ where finalized_number: Zero::zero(), genesis_hash: Default::default(), finalized_state: None, + block_gap: None, }), }; @@ -541,7 +546,7 @@ where "Opened blockchain db, fetched {} = {:?} ({})", desc, hash, - header.number() + header.number(), ); Ok((hash, *header.number())) } else { @@ -558,6 +563,10 @@ where } else { None }; + let block_gap = db + .get(COLUMN_META, meta_keys::BLOCK_GAP) + .and_then(|d| Decode::decode(&mut d.as_slice()).ok()); + debug!(target: "db", "block_gap={:?}", block_gap); Ok(Meta { best_hash, @@ -566,6 +575,7 @@ where finalized_number, genesis_hash, finalized_state, + block_gap, }) } diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 6e5dfdd05e624..6eb13099aa202 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -168,7 +168,7 @@ pub struct AuthoritySet { /// Track at which blocks the set id changed. This is useful when we need to prove finality for /// a given block since we can figure out what set the block belongs to and when the set /// started/ended. - authority_set_changes: AuthoritySetChanges, + pub(crate) authority_set_changes: AuthoritySetChanges, } impl AuthoritySet @@ -714,6 +714,17 @@ impl AuthoritySetChanges { } } + pub(crate) fn insert(&mut self, block_number: N) { + let idx = self + .0 + .binary_search_by_key(&block_number, |(_, n)| n.clone()) + .unwrap_or_else(|b| b); + + let set_id = if idx == 0 { 0 } else { self.0[idx - 1].0 + 1 }; + assert!(idx == self.0.len() || self.0[idx].0 != set_id); + self.0.insert(idx, (set_id, block_number)); + } + /// Returns an iterator over all historical authority set changes starting at the given block /// number (excluded). The iterator yields a tuple representing the set id and the block number /// of the last block in that set. @@ -1632,6 +1643,18 @@ mod tests { assert_eq!(authorities.pending_forced_changes.first().unwrap().canon_hash, "D"); } + #[test] + fn authority_set_changes_insert() { + let mut authority_set_changes = AuthoritySetChanges::empty(); + authority_set_changes.append(0, 41); + authority_set_changes.append(1, 81); + authority_set_changes.append(4, 121); + + authority_set_changes.insert(101); + assert_eq!(authority_set_changes.get_set_id(100), AuthoritySetChangeId::Set(2, 101)); + assert_eq!(authority_set_changes.get_set_id(101), AuthoritySetChangeId::Set(2, 101)); + } + #[test] fn authority_set_changes_for_complete_data() { let mut authority_set_changes = AuthoritySetChanges::empty(); diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index 1c4d1b4e97b88..d54f7234b44b4 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -551,6 +551,32 @@ where return self.import_state(block, new_cache).await } + if number <= self.inner.info().finalized_number { + // Importing an old block. Just save justifications and authority set changes + if self.check_new_change(&block.header, hash).is_some() { + if block.justifications.is_none() { + return Err(ConsensusError::ClientImport( + "Justification required when importing \ + an old block with authority set change." + .into(), + )) + } + assert!(block.justifications.is_some()); + let mut authority_set = self.authority_set.inner_locked(); + authority_set.authority_set_changes.insert(number); + crate::aux_schema::update_authority_set::( + &authority_set, + None, + |insert| { + block + .auxiliary + .extend(insert.iter().map(|(k, v)| (k.to_vec(), Some(v.to_vec())))) + }, + ); + } + return (&*self.inner).import_block(block, new_cache).await + } + // on initial sync we will restrict logging under info to avoid spam. let initial_sync = block.origin == BlockOrigin::NetworkInitialSync; diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index 34eaa49cdf360..3c1fa4892f8a3 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -31,7 +31,7 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT, NumberFor, One}, }; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; /// Warp proof processing error. #[derive(Debug, derive_more::Display, derive_more::From)] @@ -194,6 +194,7 @@ impl WarpSyncProof { &self, set_id: SetId, authorities: AuthorityList, + hard_forks: &HashMap<(Block::Hash, NumberFor), (SetId, AuthorityList)>, ) -> Result<(SetId, AuthorityList), Error> where NumberFor: BlockNumberOps, @@ -202,26 +203,34 @@ impl WarpSyncProof { let mut current_authorities = authorities; for (fragment_num, proof) in self.proofs.iter().enumerate() { - proof - .justification - .verify(current_set_id, ¤t_authorities) - .map_err(|err| Error::InvalidProof(err.to_string()))?; - - if proof.justification.target().1 != proof.header.hash() { - return Err(Error::InvalidProof( - "Mismatch between header and justification".to_owned(), - )) - } + let hash = proof.header.hash(); + let number = *proof.header.number(); + + if let Some((set_id, list)) = hard_forks.get(&(hash.clone(), number)) { + current_set_id = *set_id; + current_authorities = list.clone(); + } else { + proof + .justification + .verify(current_set_id, ¤t_authorities) + .map_err(|err| Error::InvalidProof(err.to_string()))?; + + if proof.justification.target().1 != hash { + return Err(Error::InvalidProof( + "Mismatch between header and justification".to_owned(), + )) + } - if let Some(scheduled_change) = find_scheduled_change::(&proof.header) { - current_authorities = scheduled_change.next_authorities; - current_set_id += 1; - } else if fragment_num != self.proofs.len() - 1 || !self.is_finished { - // Only the last fragment of the last proof message is allowed to be missing - // the authority set change. - return Err(Error::InvalidProof( - "Header is missing authority set change digest".to_string(), - )) + if let Some(scheduled_change) = find_scheduled_change::(&proof.header) { + current_authorities = scheduled_change.next_authorities; + current_set_id += 1; + } else if fragment_num != self.proofs.len() - 1 || !self.is_finished { + // Only the last fragment of the last proof message is allowed to be missing the + // authority set change. + return Err(Error::InvalidProof( + "Header is missing authority set change digest".to_string(), + )) + } } } Ok((current_set_id, current_authorities)) @@ -235,6 +244,7 @@ where { backend: Arc, authority_set: SharedAuthoritySet>, + hard_forks: HashMap<(Block::Hash, NumberFor), (SetId, AuthorityList)>, } impl> NetworkProvider @@ -245,8 +255,13 @@ where pub fn new( backend: Arc, authority_set: SharedAuthoritySet>, + hard_forks: Vec<(SetId, (Block::Hash, NumberFor), AuthorityList)>, ) -> Self { - NetworkProvider { backend, authority_set } + NetworkProvider { + backend, + authority_set, + hard_forks: hard_forks.into_iter().map(|(s, hn, list)| (hn, (s, list))).collect(), + } } } @@ -283,7 +298,7 @@ where .map(|p| p.header.clone()) .ok_or_else(|| "Empty proof".to_string())?; let (next_set_id, next_authorities) = - proof.verify(set_id, authorities).map_err(Box::new)?; + proof.verify(set_id, authorities, &self.hard_forks).map_err(Box::new)?; if proof.is_finished { Ok(VerificationResult::::Complete(next_set_id, next_authorities, last_header)) } else { @@ -417,7 +432,8 @@ mod tests { WarpSyncProof::generate(&*backend, genesis_hash, &authority_set_changes).unwrap(); // verifying the proof should yield the last set id and authorities - let (new_set_id, new_authorities) = warp_sync_proof.verify(0, genesis_authorities).unwrap(); + let (new_set_id, new_authorities) = + warp_sync_proof.verify(0, genesis_authorities, &Default::default()).unwrap(); let expected_authorities = current_authorities .iter() diff --git a/client/informant/src/display.rs b/client/informant/src/display.rs index 1f23856101aa3..6496172b80891 100644 --- a/client/informant/src/display.rs +++ b/client/informant/src/display.rs @@ -20,7 +20,7 @@ use crate::OutputFormat; use ansi_term::Colour; use log::info; use sc_client_api::ClientInfo; -use sc_network::{NetworkStatus, SyncState}; +use sc_network::{NetworkStatus, SyncState, WarpSyncPhase, WarpSyncProgress}; use sp_runtime::traits::{Block as BlockT, CheckedDiv, NumberFor, Saturating, Zero}; use std::{ convert::{TryFrom, TryInto}, @@ -97,11 +97,17 @@ impl InformantDisplay { net_status.state_sync, net_status.warp_sync, ) { + ( + _, + _, + _, + Some(WarpSyncProgress { phase: WarpSyncPhase::DownloadingBlocks(n), .. }), + ) => ("⏩", "Block history".into(), format!(", #{}", n)), (_, _, _, Some(warp)) => ( "⏩", "Warping".into(), format!( - ", {}, ({:.2}) Mib", + ", {}, {:.2} Mib", warp.phase, (warp.total_bytes as f32) / (1024f32 * 1024f32) ), @@ -110,7 +116,7 @@ impl InformantDisplay { "⚙️ ", "Downloading state".into(), format!( - ", {}%, ({:.2}) Mib", + ", {}%, {:.2} Mib", state.percentage, (state.size as f32) / (1024f32 * 1024f32) ), diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 51bc370265ef0..2f81ddfa1fb13 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -328,5 +328,5 @@ pub struct NetworkStatus { /// State sync in progress. pub state_sync: Option, /// Warp sync in progress. - pub warp_sync: Option, + pub warp_sync: Option>, } diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index e22d96f32aeb8..70a17dc44b16d 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -710,8 +710,7 @@ impl Protocol { match self.sync.on_state_data(&peer_id, response) { Ok(sync::OnStateData::Import(origin, block)) => CustomMessageOutcome::BlockImport(origin, vec![block]), - Ok(sync::OnStateData::Request(peer, req)) => - prepare_state_request::(&mut self.peers, peer, req), + Ok(sync::OnStateData::Continue) => CustomMessageOutcome::None, Err(sync::BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); @@ -728,10 +727,7 @@ impl Protocol { response: crate::warp_request_handler::EncodedProof, ) -> CustomMessageOutcome { match self.sync.on_warp_sync_data(&peer_id, response) { - Ok(sync::OnWarpSyncData::WarpProofRequest(peer, req)) => - prepare_warp_sync_request::(&mut self.peers, peer, req), - Ok(sync::OnWarpSyncData::StateRequest(peer, req)) => - prepare_state_request::(&mut self.peers, peer, req), + Ok(()) => CustomMessageOutcome::None, Err(sync::BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index 07f5f76fce7f2..7f85c2b637826 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -182,6 +182,12 @@ impl Default for PendingRequests { } } +struct GapSync { + blocks: BlockCollection, + best_queued_number: NumberFor, + target: NumberFor, +} + /// The main data structure which contains all the state for a chains /// active syncing strategy. pub struct ChainSync { @@ -226,6 +232,8 @@ pub struct ChainSync { /// Enable importing existing blocks. This is used used after the state download to /// catch up to the latest state while re-importing blocks. import_existing: bool, + /// Gap download process. + gap_sync: Option>, } /// All the data we have about a Peer that we are trying to sync with @@ -298,6 +306,8 @@ pub enum PeerSyncState { DownloadingState, /// Downloading warp proof. DownloadingWarpProof, + /// Actively downloading block history after warp sync. + DownloadingGap(NumberFor), } impl PeerSyncState { @@ -326,7 +336,7 @@ pub struct StateDownloadProgress { /// Reported warp sync phase. #[derive(Clone, Eq, PartialEq, Debug)] -pub enum WarpSyncPhase { +pub enum WarpSyncPhase { /// Waiting for peers to connect. AwaitingPeers, /// Downloading and verifying grandpa warp proofs. @@ -335,24 +345,27 @@ pub enum WarpSyncPhase { DownloadingState, /// Importing state. ImportingState, + /// Downloading block history. + DownloadingBlocks(NumberFor), } -impl fmt::Display for WarpSyncPhase { +impl fmt::Display for WarpSyncPhase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::AwaitingPeers => write!(f, "Waiting for peers"), Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"), Self::DownloadingState => write!(f, "Downloading state"), Self::ImportingState => write!(f, "Importing state"), + Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n), } } } /// Reported warp sync progress. #[derive(Clone, Eq, PartialEq, Debug)] -pub struct WarpSyncProgress { +pub struct WarpSyncProgress { /// Estimated download percentage. - pub phase: WarpSyncPhase, + pub phase: WarpSyncPhase, /// Total bytes downloaded so far. pub total_bytes: u64, } @@ -371,7 +384,7 @@ pub struct Status { /// State sync status in progress, if any. pub state_sync: Option, /// Warp sync in progress, if any. - pub warp_sync: Option, + pub warp_sync: Option>, } /// A peer did not behave as expected and should be reported. @@ -413,16 +426,7 @@ pub enum OnStateData { /// The block and state that should be imported. Import(BlockOrigin, IncomingBlock), /// A new state request needs to be made to the given peer. - Request(PeerId, StateRequest), -} - -/// Result of [`ChainSync::on_warp_sync_data`]. -#[derive(Debug)] -pub enum OnWarpSyncData { - /// Warp proof request is issued. - WarpProofRequest(PeerId, warp::WarpProofRequest), - /// A new state request needs to be made to the given peer. - StateRequest(PeerId, StateRequest), + Continue, } /// Result of [`ChainSync::poll_block_announce_validation`]. @@ -555,6 +559,7 @@ impl ChainSync { warp_sync: None, warp_sync_provider, import_existing: false, + gap_sync: None, }; sync.reset_sync_start_point()?; Ok(sync) @@ -608,10 +613,14 @@ impl ChainSync { SyncState::Idle }; - let warp_sync_progress = match (&self.warp_sync, &self.mode) { - (None, SyncMode::Warp) => + let warp_sync_progress = match (&self.warp_sync, &self.mode, &self.gap_sync) { + (_, _, Some(gap_sync)) => Some(WarpSyncProgress { + phase: WarpSyncPhase::DownloadingBlocks(gap_sync.best_queued_number), + total_bytes: 0, + }), + (None, SyncMode::Warp, _) => Some(WarpSyncProgress { phase: WarpSyncPhase::AwaitingPeers, total_bytes: 0 }), - (Some(sync), _) => Some(sync.progress()), + (Some(sync), _, _) => Some(sync.progress()), _ => None, }; @@ -686,17 +695,6 @@ impl ChainSync { return Ok(None) } - if let SyncMode::Warp = &self.mode { - if self.peers.len() >= MIN_PEERS_TO_START_WARP_SYNC && self.warp_sync.is_none() - { - log::debug!(target: "sync", "Starting warp state sync."); - if let Some(provider) = &self.warp_sync_provider { - self.warp_sync = - Some(WarpSync::new(self.client.clone(), provider.clone())); - } - } - } - // If we are at genesis, just start downloading. let (state, req) = if self.best_queued_number.is_zero() { debug!( @@ -739,6 +737,17 @@ impl ChainSync { }, ); + if let SyncMode::Warp = &self.mode { + if self.peers.len() >= MIN_PEERS_TO_START_WARP_SYNC && self.warp_sync.is_none() + { + log::debug!(target: "sync", "Starting warp state sync."); + if let Some(provider) = &self.warp_sync_provider { + self.warp_sync = + Some(WarpSync::new(self.client.clone(), provider.clone())); + } + } + } + Ok(req) }, Ok(BlockStatus::Queued) | @@ -869,10 +878,13 @@ impl ChainSync { /// Get an iterator over all block requests of all peers. pub fn block_requests(&mut self) -> impl Iterator)> + '_ { - if self.pending_requests.is_empty() || self.state_sync.is_some() || self.warp_sync.is_some() + if self.pending_requests.is_empty() || + self.state_sync.is_some() || + self.mode == SyncMode::Warp { return Either::Left(std::iter::empty()) } + if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS { trace!(target: "sync", "Too many blocks in the queue."); return Either::Left(std::iter::empty()) @@ -888,6 +900,7 @@ impl ChainSync { let queue = &self.queue_blocks; let pending_requests = self.pending_requests.take(); let max_parallel = if major_sync { 1 } else { self.max_parallel_downloads }; + let gap_sync = &mut self.gap_sync; let iter = self.peers.iter_mut().filter_map(move |(id, peer)| { if !peer.state.is_available() || !pending_requests.contains(id) { return None @@ -947,6 +960,26 @@ impl ChainSync { trace!(target: "sync", "Downloading fork {:?} from {}", hash, id); peer.state = PeerSyncState::DownloadingStale(hash); Some((id, req)) + } else if let Some((range, req)) = gap_sync.as_mut().and_then(|sync| { + peer_gap_block_request( + id, + peer, + &mut sync.blocks, + attrs, + sync.target, + sync.best_queued_number, + ) + }) { + peer.state = PeerSyncState::DownloadingGap(range.start); + trace!( + target: "sync", + "New gap block request for {}, (best:{}, common:{}) {:?}", + id, + peer.best_number, + peer.common_number, + req, + ); + Some((id, req)) } else { None } @@ -966,9 +999,9 @@ impl ChainSync { } for (id, peer) in self.peers.iter_mut() { if peer.state.is_available() && peer.common_number >= sync.target_block_num() { - trace!(target: "sync", "New StateRequest for {}", id); peer.state = PeerSyncState::DownloadingState; let request = sync.next_request(); + trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); return Some((*id, request)) } } @@ -982,7 +1015,7 @@ impl ChainSync { { for (id, peer) in self.peers.iter_mut() { if peer.state.is_available() && peer.best_number >= target { - trace!(target: "sync", "New StateRequest for {}", id); + trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); peer.state = PeerSyncState::DownloadingState; return Some((*id, request)) } @@ -1039,6 +1072,7 @@ impl ChainSync { response: BlockResponse, ) -> Result, BadPeer> { self.downloaded_blocks += response.blocks.len(); + let mut gap = false; let new_blocks: Vec> = if let Some(peer) = self.peers.get_mut(who) { let mut blocks = response.blocks; if request @@ -1061,6 +1095,43 @@ impl ChainSync { } self.drain_blocks() }, + PeerSyncState::DownloadingGap(start_block) => { + let start_block = *start_block; + peer.state = PeerSyncState::Available; + if let Some(gap_sync) = &mut self.gap_sync { + gap_sync.blocks.clear_peer_download(who); + validate_blocks::(&blocks, who, Some(request))?; + gap_sync.blocks.insert(start_block, blocks, who.clone()); + gap = true; + gap_sync + .blocks + .drain(gap_sync.best_queued_number + One::one()) + .into_iter() + .map(|block_data| { + let justifications = block_data.block.justifications.or( + legacy_justification_mapping( + block_data.block.justification, + ), + ); + IncomingBlock { + hash: block_data.block.hash, + header: block_data.block.header, + body: block_data.block.body, + indexed_body: block_data.block.indexed_body, + justifications, + origin: block_data.origin, + allow_missing_state: true, + import_existing: self.import_existing, + skip_execution: true, + state: None, + } + }) + .collect() + } else { + debug!(target: "sync", "Unexpected gap block response from {}", who); + return Err(BadPeer(who.clone(), rep::NO_BLOCK)) + } + }, PeerSyncState::DownloadingStale(_) => { peer.state = PeerSyncState::Available; if blocks.is_empty() { @@ -1212,7 +1283,7 @@ impl ChainSync { return Err(BadPeer(*who, rep::NOT_REQUESTED)) }; - Ok(self.validate_and_queue_blocks(new_blocks)) + Ok(self.validate_and_queue_blocks(new_blocks, gap)) } /// Handle a response from the remote to a state request that we made. @@ -1223,6 +1294,11 @@ impl ChainSync { who: &PeerId, response: StateResponse, ) -> Result, BadPeer> { + if let Some(peer) = self.peers.get_mut(&who) { + if let PeerSyncState::DownloadingState = peer.state { + peer.state = PeerSyncState::Available; + } + } let import_result = if let Some(sync) = &mut self.state_sync { debug!( target: "sync", @@ -1261,11 +1337,10 @@ impl ChainSync { skip_execution: self.skip_execution(), state: Some(state), }; - debug!(target: "sync", "State sync is complete. Import is queued"); + debug!(target: "sync", "State download is complete. Import is queued"); Ok(OnStateData::Import(origin, block)) }, - state::ImportResult::Continue(request) => - Ok(OnStateData::Request(who.clone(), request)), + state::ImportResult::Continue => Ok(OnStateData::Continue), state::ImportResult::BadResponse => { debug!(target: "sync", "Bad state data received from {}", who); Err(BadPeer(*who, rep::BAD_BLOCK)) @@ -1280,7 +1355,12 @@ impl ChainSync { &mut self, who: &PeerId, response: warp::EncodedProof, - ) -> Result, BadPeer> { + ) -> Result<(), BadPeer> { + if let Some(peer) = self.peers.get_mut(&who) { + if let PeerSyncState::DownloadingWarpProof = peer.state { + peer.state = PeerSyncState::Available; + } + } let import_result = if let Some(sync) = &mut self.warp_sync { debug!( target: "sync", @@ -1295,10 +1375,7 @@ impl ChainSync { }; match import_result { - warp::WarpProofImportResult::StateRequest(request) => - Ok(OnWarpSyncData::StateRequest(*who, request)), - warp::WarpProofImportResult::WarpProofRequest(request) => - Ok(OnWarpSyncData::WarpProofRequest(*who, request)), + warp::WarpProofImportResult::Success => Ok(()), warp::WarpProofImportResult::BadResponse => { debug!(target: "sync", "Bad proof data received from {}", who); Err(BadPeer(*who, rep::BAD_BLOCK)) @@ -1309,6 +1386,7 @@ impl ChainSync { fn validate_and_queue_blocks( &mut self, mut new_blocks: Vec>, + gap: bool, ) -> OnBlockData { let orig_len = new_blocks.len(); new_blocks.retain(|b| !self.queue_blocks.contains(&b.hash)); @@ -1320,7 +1398,7 @@ impl ChainSync { ); } - let origin = if self.status().state != SyncState::Downloading { + let origin = if !gap && self.status().state != SyncState::Downloading { BlockOrigin::NetworkBroadcast } else { BlockOrigin::NetworkInitialSync @@ -1494,6 +1572,15 @@ impl ChainSync { self.mode = SyncMode::Full; output.extend(self.restart()); } + let gap_sync_complete = + self.gap_sync.as_ref().map_or(false, |s| s.target == number); + if gap_sync_complete { + info!( + target: "sync", + "Block history download is complete." + ); + self.gap_sync = None; + } }, Err(BlockImportError::IncompleteHeader(who)) => if let Some(peer) = who { @@ -1601,6 +1688,11 @@ impl ChainSync { if self.fork_targets.remove(&hash).is_some() { trace!(target: "sync", "Completed fork sync {:?}", hash); } + if let Some(gap_sync) = &mut self.gap_sync { + if number > gap_sync.best_queued_number && number <= gap_sync.target { + gap_sync.best_queued_number = number; + } + } if number > self.best_queued_number { self.best_queued_number = number; self.best_queued_hash = *hash; @@ -1954,6 +2046,9 @@ impl ChainSync { /// import, so this functions checks for such blocks and returns them. pub fn peer_disconnected(&mut self, who: &PeerId) -> Option> { self.blocks.clear_peer_download(who); + if let Some(gap_sync) = &mut self.gap_sync { + gap_sync.blocks.clear_peer_download(who) + } self.peers.remove(who); self.extra_justifications.peer_disconnected(who); self.pending_requests.set_all(); @@ -1963,7 +2058,7 @@ impl ChainSync { }); let blocks = self.drain_blocks(); if !blocks.is_empty() { - Some(self.validate_and_queue_blocks(blocks)) + Some(self.validate_and_queue_blocks(blocks, false)) } else { None } @@ -2043,6 +2138,14 @@ impl ChainSync { } } } + if let Some((start, end)) = info.block_gap { + debug!(target: "sync", "Starting gap sync #{} - #{}", start, end); + self.gap_sync = Some(GapSync { + best_queued_number: start - One::one(), + target: end, + blocks: BlockCollection::new(), + }); + } trace!(target: "sync", "Restarted sync at #{} ({:?})", self.best_queued_number, self.best_queued_hash); Ok(()) } @@ -2250,6 +2353,39 @@ fn peer_block_request( Some((range, request)) } +/// Get a new block request for the peer if any. +fn peer_gap_block_request( + id: &PeerId, + peer: &PeerSync, + blocks: &mut BlockCollection, + attrs: message::BlockAttributes, + target: NumberFor, + common_number: NumberFor, +) -> Option<(Range>, BlockRequest)> { + let range = blocks.needed_blocks( + id.clone(), + MAX_BLOCKS_TO_REQUEST, + std::cmp::min(peer.best_number, target), + common_number, + 1, + MAX_DOWNLOAD_AHEAD, + )?; + + // The end is not part of the range. + let last = range.end.saturating_sub(One::one()); + let from = message::FromBlock::Number(last); + + let request = message::generic::BlockRequest { + id: 0, + fields: attrs.clone(), + from, + to: None, + direction: message::Direction::Descending, + max: Some((range.end - range.start).saturated_into::()), + }; + Some((range, request)) +} + /// Get pending fork sync targets for a peer. fn fork_sync_request( id: &PeerId, diff --git a/client/network/src/protocol/sync/state.rs b/client/network/src/protocol/sync/state.rs index d2e4463f98912..e644ba1013e4d 100644 --- a/client/network/src/protocol/sync/state.rs +++ b/client/network/src/protocol/sync/state.rs @@ -47,8 +47,8 @@ pub struct StateSync { pub enum ImportResult { /// State is complete and ready for import. Import(B::Hash, B::Header, ImportedState), - /// Continue dowloading. - Continue(StateRequest), + /// Continue downloading. + Continue, /// Bad state chunk. BadResponse, } @@ -134,7 +134,7 @@ impl StateSync { ImportedState { block: self.target_block, state: std::mem::take(&mut self.state) }, ) } else { - ImportResult::Continue(self.next_request()) + ImportResult::Continue } } diff --git a/client/network/src/protocol/sync/warp.rs b/client/network/src/protocol/sync/warp.rs index 32bd5cb9ed798..bbf8a28da14a6 100644 --- a/client/network/src/protocol/sync/warp.rs +++ b/client/network/src/protocol/sync/warp.rs @@ -37,11 +37,9 @@ enum Phase { } /// Import warp proof result. -pub enum WarpProofImportResult { - /// Start downloading state data. - StateRequest(StateRequest), - /// Continue dowloading warp sync proofs. - WarpProofRequest(WarpProofRequest), +pub enum WarpProofImportResult { + /// Import was successful. + Success, /// Bad proof. BadResponse, } @@ -69,7 +67,7 @@ impl WarpSync { Self { client, warp_sync_provider, phase, total_proof_bytes: 0 } } - /// Validate and import a state reponse. + /// Validate and import a state response. pub fn import_state(&mut self, response: StateResponse) -> ImportResult { match &mut self.phase { Phase::WarpProof { .. } => { @@ -80,19 +78,15 @@ impl WarpSync { } } - /// Validate and import a warp proof reponse. - pub fn import_warp_proof(&mut self, response: EncodedProof) -> WarpProofImportResult { + /// Validate and import a warp proof response. + pub fn import_warp_proof(&mut self, response: EncodedProof) -> WarpProofImportResult { match &mut self.phase { Phase::State(_) => { log::debug!(target: "sync", "Unexpected warp proof response"); WarpProofImportResult::BadResponse }, Phase::WarpProof { set_id, authorities, last_hash } => { - match self.warp_sync_provider.verify( - &response, - *set_id, - std::mem::take(authorities), - ) { + match self.warp_sync_provider.verify(&response, *set_id, authorities.clone()) { Err(e) => { log::debug!(target: "sync", "Bad warp proof response: {:?}", e); return WarpProofImportResult::BadResponse @@ -103,17 +97,14 @@ impl WarpSync { *authorities = new_authorities; *last_hash = new_last_hash.clone(); self.total_proof_bytes += response.0.len() as u64; - WarpProofImportResult::WarpProofRequest(WarpProofRequest { - begin: new_last_hash, - }) + WarpProofImportResult::Success }, Ok(VerificationResult::Complete(new_set_id, _, header)) => { log::debug!(target: "sync", "Verified complete proof, set_id={:?}", new_set_id); self.total_proof_bytes += response.0.len() as u64; let state_sync = StateSync::new(self.client.clone(), header, false); - let request = state_sync.next_request(); self.phase = Phase::State(state_sync); - WarpProofImportResult::StateRequest(request) + WarpProofImportResult::Success }, } }, @@ -161,7 +152,7 @@ impl WarpSync { } /// Returns state sync estimated progress (percentage, bytes) - pub fn progress(&self) -> WarpSyncProgress { + pub fn progress(&self) -> WarpSyncProgress { match &self.phase { Phase::WarpProof { .. } => WarpSyncProgress { phase: WarpSyncPhase::DownloadingWarpProofs, diff --git a/client/network/src/warp_request_handler.rs b/client/network/src/warp_request_handler.rs index 2ab95bb3853ba..ca5a93b752b62 100644 --- a/client/network/src/warp_request_handler.rs +++ b/client/network/src/warp_request_handler.rs @@ -23,10 +23,11 @@ use futures::{ stream::StreamExt, }; use log::debug; -use sp_finality_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::Block as BlockT; use std::{sync::Arc, time::Duration}; +pub use sp_finality_grandpa::{AuthorityList, SetId}; + /// Scale-encoded warp sync proof response. pub struct EncodedProof(pub Vec); @@ -55,7 +56,7 @@ pub trait WarpSyncProvider: Send + Sync { &self, start: B::Hash, ) -> Result>; - /// Verify warp proof agains current set of authorities. + /// Verify warp proof against current set of authorities. fn verify( &self, proof: &EncodedProof, diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index e547fa376b3fc..fb0012aaf5baf 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -55,7 +55,7 @@ use sc_network::{ }, light_client_requests::{self, handler::LightClientRequestHandler}, state_request_handler::{self, StateRequestHandler}, - Multiaddr, NetworkService, NetworkWorker, + warp_request_handler, Multiaddr, NetworkService, NetworkWorker, }; use sc_service::client::Client; use sp_blockchain::{ @@ -68,6 +68,7 @@ use sp_consensus::{ }; use sp_core::H256; use sp_runtime::{ + codec::{Decode, Encode}, generic::{BlockId, OpaqueDigestItemId}, traits::{Block as BlockT, Header as HeaderT, NumberFor}, Justification, Justifications, @@ -652,6 +653,33 @@ impl VerifierAdapter { } } +struct TestWarpSyncProvider(Arc>); + +impl warp_request_handler::WarpSyncProvider for TestWarpSyncProvider { + fn generate( + &self, + _start: B::Hash, + ) -> Result> { + let info = self.0.info(); + let best_header = self.0.header(BlockId::hash(info.best_hash)).unwrap().unwrap(); + Ok(warp_request_handler::EncodedProof(best_header.encode())) + } + fn verify( + &self, + proof: &warp_request_handler::EncodedProof, + _set_id: warp_request_handler::SetId, + _authorities: warp_request_handler::AuthorityList, + ) -> Result, Box> + { + let warp_request_handler::EncodedProof(encoded) = proof; + let header = B::Header::decode(&mut encoded.as_slice()).unwrap(); + Ok(warp_request_handler::VerificationResult::Complete(0, Default::default(), header)) + } + fn current_authorities(&self) -> warp_request_handler::AuthorityList { + Default::default() + } +} + /// Configuration for a full peer. #[derive(Default)] pub struct FullPeerConfig { @@ -737,7 +765,7 @@ where (Some(keep_blocks), false) => TestClientBuilder::with_pruning_window(keep_blocks), (None, false) => TestClientBuilder::with_default_backend(), }; - if matches!(config.sync_mode, SyncMode::Fast { .. }) { + if matches!(config.sync_mode, SyncMode::Fast { .. } | SyncMode::Warp) { test_client_builder = test_client_builder.set_no_genesis(); } let backend = test_client_builder.backend(); @@ -816,6 +844,15 @@ where protocol_config }; + let warp_sync = Arc::new(TestWarpSyncProvider(client.clone())); + + let warp_protocol_config = { + let (handler, protocol_config) = + warp_request_handler::RequestHandler::new(protocol_id.clone(), warp_sync.clone()); + self.spawn_task(handler.run().boxed()); + protocol_config + }; + let network = NetworkWorker::new(sc_network::config::Params { role: if config.is_authority { Role::Authority } else { Role::Full }, executor: None, @@ -835,7 +872,7 @@ where block_request_protocol_config, state_request_protocol_config, light_client_request_protocol_config, - warp_sync: None, + warp_sync: Some((warp_sync, warp_protocol_config)), }) .unwrap(); diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index f413b705e52c4..f3af7f8ff6fc3 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -1202,6 +1202,38 @@ fn syncs_indexed_blocks() { .is_some()); } +#[test] +fn warp_sync() { + sp_tracing::try_init_simple(); + let mut net = TestNet::new(0); + // Create 3 synced peers and 1 peer trying to warp sync. + net.add_full_peer_with_config(Default::default()); + net.add_full_peer_with_config(Default::default()); + net.add_full_peer_with_config(Default::default()); + net.add_full_peer_with_config(FullPeerConfig { + sync_mode: SyncMode::Warp, + ..Default::default() + }); + let gap_end = net.peer(0).push_blocks(63, false); + net.peer(0).push_blocks(1, false); + net.peer(1).push_blocks(64, false); + net.peer(2).push_blocks(64, false); + // Wait for peer 1 to sync state. + net.block_until_sync(); + assert!(!net.peer(3).client().has_state_at(&BlockId::Number(1))); + assert!(net.peer(3).client().has_state_at(&BlockId::Number(64))); + + // Wait for peer 1 download block history + block_on(futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); + if net.peer(3).has_block(&gap_end) { + Poll::Ready(()) + } else { + Poll::Pending + } + })); +} + #[test] fn syncs_huge_blocks() { use sp_core::storage::well_known_keys::HEAP_PAGES; diff --git a/client/service/src/chain_ops/check_block.rs b/client/service/src/chain_ops/check_block.rs index 4728e014540ee..5e2a9faaf0c4f 100644 --- a/client/service/src/chain_ops/check_block.rs +++ b/client/service/src/chain_ops/check_block.rs @@ -19,7 +19,7 @@ use crate::error::Error; use codec::Encode; use futures::{future, prelude::*}; -use sc_client_api::{BlockBackend, UsageProvider}; +use sc_client_api::{BlockBackend, HeaderBackend}; use sc_consensus::import_queue::ImportQueue; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; @@ -33,7 +33,7 @@ pub fn check_block( block_id: BlockId, ) -> Pin> + Send>> where - C: BlockBackend + UsageProvider + Send + Sync + 'static, + C: BlockBackend + HeaderBackend + Send + Sync + 'static, B: BlockT + for<'de> serde::Deserialize<'de>, IQ: ImportQueue + 'static, { diff --git a/client/service/src/chain_ops/import_blocks.rs b/client/service/src/chain_ops/import_blocks.rs index 1ba9e0bd61444..a408a06a8170e 100644 --- a/client/service/src/chain_ops/import_blocks.rs +++ b/client/service/src/chain_ops/import_blocks.rs @@ -22,7 +22,7 @@ use futures::{future, prelude::*}; use futures_timer::Delay; use log::{info, warn}; use sc_chain_spec::ChainSpec; -use sc_client_api::UsageProvider; +use sc_client_api::HeaderBackend; use sc_consensus::import_queue::{ BlockImportError, BlockImportStatus, ImportQueue, IncomingBlock, Link, }; @@ -296,7 +296,7 @@ pub fn import_blocks( binary: bool, ) -> Pin> + Send>> where - C: UsageProvider + Send + Sync + 'static, + C: HeaderBackend + Send + Sync + 'static, B: BlockT + for<'de> serde::Deserialize<'de>, IQ: ImportQueue + 'static, { @@ -438,7 +438,7 @@ where info!( "🎉 Imported {} blocks. Best: #{}", read_block_count, - client.usage_info().chain.best_number + client.info().best_number ); return Poll::Ready(Ok(())) } else { @@ -469,7 +469,7 @@ where queue.poll_actions(cx, &mut link); - let best_number = client.usage_info().chain.best_number; + let best_number = client.info().best_number; speedometer.notify_user(best_number); if link.has_error { diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index f7d93d036a3fa..d35c0462b8b05 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -684,8 +684,6 @@ where .. } = import_block; - assert!(justifications.is_some() && finalized || justifications.is_none()); - if !intermediates.is_empty() { return Err(Error::IncompletePipeline) } @@ -779,11 +777,17 @@ where } let info = self.backend.blockchain().info(); + let gap_block = info + .block_gap + .map_or(false, |(start, _)| *import_headers.post().number() == start); + + assert!(justifications.is_some() && finalized || justifications.is_none() || gap_block); // the block is lower than our last finalized block so it must revert // finality, refusing import. if status == blockchain::BlockStatus::Unknown && - *import_headers.post().number() <= info.finalized_number + *import_headers.post().number() <= info.finalized_number && + !gap_block { return Err(sp_blockchain::Error::NotInFinalizedChain) } @@ -854,12 +858,13 @@ where None => None, }; - let is_new_best = finalized || - match fork_choice { - ForkChoiceStrategy::LongestChain => - import_headers.post().number() > &info.best_number, - ForkChoiceStrategy::Custom(v) => v, - }; + let is_new_best = !gap_block && + (finalized || + match fork_choice { + ForkChoiceStrategy::LongestChain => + import_headers.post().number() > &info.best_number, + ForkChoiceStrategy::Custom(v) => v, + }); let leaf_state = if finalized { NewBlockState::Final diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index bb34a0449b5f7..fc70ce845dc98 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -281,6 +281,8 @@ pub struct Info { pub finalized_state: Option<(Block::Hash, <::Header as HeaderT>::Number)>, /// Number of concurrent leave forks. pub number_leaves: usize, + /// Missing blocks after warp sync. (start, end). + pub block_gap: Option<(NumberFor, NumberFor)>, } /// Block status. From 53558132826db8572bc142685ed0b8b615cf8bd1 Mon Sep 17 00:00:00 2001 From: Davide Gessa Date: Thu, 7 Oct 2021 11:51:01 +0200 Subject: [PATCH 0088/1472] Replace is_global to is_private, maybe fixing #9922 (#9943) * replace is_global to is_private, maybe fixing #9922 * use of ip_network for private_ipv4 filtering * check is_global for both ip4 and ip6 * fix for rustfmt --- client/network/src/discovery.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 431de50c0f192..1ed08cd671d4e 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -512,14 +512,10 @@ impl NetworkBehaviour for DiscoveryBehaviour { list_to_filter.extend(self.mdns.addresses_of_peer(peer_id)); if !self.allow_private_ipv4 { - list_to_filter.retain(|addr| { - if let Some(Protocol::Ip4(addr)) = addr.iter().next() { - if addr.is_private() { - return false - } - } - - true + list_to_filter.retain(|addr| match addr.iter().next() { + Some(Protocol::Ip4(addr)) if !IpNetwork::from(addr).is_global() => false, + Some(Protocol::Ip6(addr)) if !IpNetwork::from(addr).is_global() => false, + _ => true, }); } From 5636a44a8edd029f25f1549148e02a1866b71d1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 10:19:37 +0000 Subject: [PATCH 0089/1472] Bump sha2 from 0.9.3 to 0.9.5 (#9955) Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.9.3 to 0.9.5. - [Release notes](https://github.com/RustCrypto/hashes/releases) - [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.9.3...sha2-v0.9.5) --- updated-dependencies: - dependency-name: sha2 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 | 34 +++++++++++++++++----------------- primitives/core/Cargo.toml | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a502439b7254..77f257fad4db1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1664,7 +1664,7 @@ dependencies = [ "ed25519", "rand 0.7.3", "serde", - "sha2 0.9.3", + "sha2 0.9.5", "zeroize", ] @@ -3395,7 +3395,7 @@ dependencies = [ "rand 0.7.3", "ring", "rw-stream-sink", - "sha2 0.9.3", + "sha2 0.9.5", "smallvec 1.7.0", "thiserror", "unsigned-varint 0.7.0", @@ -3466,7 +3466,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "regex", - "sha2 0.9.3", + "sha2 0.9.5", "smallvec 1.7.0", "unsigned-varint 0.7.0", "wasm-timer", @@ -3506,7 +3506,7 @@ dependencies = [ "prost", "prost-build", "rand 0.7.3", - "sha2 0.9.3", + "sha2 0.9.5", "smallvec 1.7.0", "uint", "unsigned-varint 0.7.0", @@ -3568,7 +3568,7 @@ dependencies = [ "prost", "prost-build", "rand 0.8.4", - "sha2 0.9.3", + "sha2 0.9.5", "snow", "static_assertions", "x25519-dalek", @@ -3791,7 +3791,7 @@ dependencies = [ "libsecp256k1-gen-genmult 0.2.1", "rand 0.7.3", "serde", - "sha2 0.9.3", + "sha2 0.9.5", "typenum", ] @@ -3810,7 +3810,7 @@ dependencies = [ "libsecp256k1-gen-genmult 0.2.1", "rand 0.7.3", "serde", - "sha2 0.9.3", + "sha2 0.9.5", "typenum", ] @@ -3828,7 +3828,7 @@ dependencies = [ "libsecp256k1-gen-genmult 0.3.0", "rand 0.8.4", "serde", - "sha2 0.9.3", + "sha2 0.9.5", ] [[package]] @@ -4285,7 +4285,7 @@ dependencies = [ "digest 0.9.0", "generic-array 0.14.4", "multihash-derive", - "sha2 0.9.3", + "sha2 0.9.5", "sha3", "unsigned-varint 0.5.1", ] @@ -4299,7 +4299,7 @@ dependencies = [ "digest 0.9.0", "generic-array 0.14.4", "multihash-derive", - "sha2 0.9.3", + "sha2 0.9.5", "unsigned-varint 0.7.0", ] @@ -8854,13 +8854,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" +checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpuid-bool", + "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -8978,7 +8978,7 @@ dependencies = [ "rand_core 0.6.2", "ring", "rustc_version 0.3.3", - "sha2 0.9.3", + "sha2 0.9.5", "subtle 2.4.0", "x25519-dalek", ] @@ -9308,7 +9308,7 @@ dependencies = [ "secrecy", "serde", "serde_json", - "sha2 0.9.3", + "sha2 0.9.5", "sp-debug-derive", "sp-externalities", "sp-runtime-interface", @@ -10404,7 +10404,7 @@ dependencies = [ "pbkdf2 0.4.0", "rand 0.7.3", "rustc-hash", - "sha2 0.9.3", + "sha2 0.9.5", "thiserror", "unicode-normalization", "wasm-bindgen", @@ -11482,7 +11482,7 @@ dependencies = [ "libc", "log 0.4.14", "serde", - "sha2 0.9.3", + "sha2 0.9.5", "toml", "winapi 0.3.9", "zstd", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index ab7d8e3df19a1..9727d1e4f2785 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -61,7 +61,7 @@ schnorrkel = { version = "0.9.1", features = [ "preaudit_deprecated", "u64_backend", ], default-features = false, optional = true } -sha2 = { version = "0.9.2", default-features = false, optional = true } +sha2 = { version = "0.9.5", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } twox-hash = { version = "1.6.1", default-features = false, optional = true } libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"], optional = true } From 4b6635cf136a9fe2226f3152b4633afc6269912c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 12:13:29 +0000 Subject: [PATCH 0090/1472] Bump prometheus from 0.11.0 to 0.12.0 (#9454) Bumps [prometheus](https://github.com/tikv/rust-prometheus) from 0.11.0 to 0.12.0. - [Release notes](https://github.com/tikv/rust-prometheus/releases) - [Changelog](https://github.com/tikv/rust-prometheus/blob/master/CHANGELOG.md) - [Commits](https://github.com/tikv/rust-prometheus/compare/v0.11.0...v0.12.0) --- updated-dependencies: - dependency-name: prometheus dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- client/utils/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 77f257fad4db1..44d285b232b8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6750,15 +6750,15 @@ dependencies = [ [[package]] name = "prometheus" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8425533e7122f0c3cc7a37e6244b16ad3a2cc32ae7ac6276e2a75da0d9c200d" +checksum = "5986aa8d62380092d2f50f8b1cdba9cb9b6731ffd4b25b51fd126b6c3e05b99c" dependencies = [ "cfg-if 1.0.0", "fnv", "lazy_static", + "memchr", "parking_lot 0.11.1", - "regex", "thiserror", ] diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index 99765dd501dd5..9b3c54974a767 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" [dependencies] futures = "0.3.9" lazy_static = "1.4.0" -prometheus = { version = "0.11.0", default-features = false } +prometheus = { version = "0.12.0", default-features = false } futures-timer = "3.0.2" [features] diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 8b647d6282fba..43de76eee2120 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.8" -prometheus = { version = "0.11.0", default-features = false } +prometheus = { version = "0.12.0", default-features = false } futures-util = { version = "0.3.17", default-features = false, features = ["io"] } derive_more = "0.99" async-std = { version = "1.10.0", features = ["unstable"] } From 5e2b0f041c8a10c3ceb06721389e1d5c95380e65 Mon Sep 17 00:00:00 2001 From: Robert Klotzner Date: Thu, 7 Oct 2021 16:03:47 +0200 Subject: [PATCH 0091/1472] Expose `set_reserved_peers` (#9960) --- client/network/src/protocol.rs | 20 +++++++++++++--- client/network/src/service.rs | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 70a17dc44b16d..a0c52d14fa62f 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -1102,7 +1102,7 @@ impl Protocol { /// Removes a `PeerId` from the list of reserved peers for syncing purposes. pub fn remove_reserved_peer(&self, peer: PeerId) { - self.peerset_handle.remove_reserved_peer(HARDCODED_PEERSETS_SYNC, peer.clone()); + self.peerset_handle.remove_reserved_peer(HARDCODED_PEERSETS_SYNC, peer); } /// Returns the list of reserved peers. @@ -1112,12 +1112,26 @@ impl Protocol { /// Adds a `PeerId` to the list of reserved peers for syncing purposes. pub fn add_reserved_peer(&self, peer: PeerId) { - self.peerset_handle.add_reserved_peer(HARDCODED_PEERSETS_SYNC, peer.clone()); + self.peerset_handle.add_reserved_peer(HARDCODED_PEERSETS_SYNC, peer); } /// Sets the list of reserved peers for syncing purposes. pub fn set_reserved_peers(&self, peers: HashSet) { - self.peerset_handle.set_reserved_peers(HARDCODED_PEERSETS_SYNC, peers.clone()); + self.peerset_handle.set_reserved_peers(HARDCODED_PEERSETS_SYNC, peers); + } + + /// Sets the list of reserved peers for the given protocol/peerset. + pub fn set_reserved_peerset_peers(&self, protocol: Cow<'static, str>, peers: HashSet) { + if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { + self.peerset_handle + .set_reserved_peers(sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), peers); + } else { + error!( + target: "sub-libp2p", + "set_reserved_peerset_peers with unknown protocol: {}", + protocol + ); + } } /// Removes a `PeerId` from the list of reserved peers. diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 23f9c614d9069..72b382c990543 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -1092,6 +1092,44 @@ impl NetworkService { let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::RemoveReserved(peer_id)); } + /// Sets the reserved set of a protocol to the given set of peers. + /// + /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also + /// consist of only `/p2p/`. + /// + /// Returns an `Err` if one of the given addresses is invalid or contains an + /// invalid peer ID (which includes the local peer ID). + pub fn set_reserved_peers( + &self, + protocol: Cow<'static, str>, + peers: HashSet, + ) -> Result<(), String> { + let peers_addrs = self.split_multiaddr_and_peer_id(peers)?; + + let mut peers: HashSet = HashSet::with_capacity(peers_addrs.len()); + + for (peer_id, addr) in peers_addrs.into_iter() { + // Make sure the local peer ID is never added to the PSM. + if peer_id == self.local_peer_id { + return Err("Local peer ID cannot be added as a reserved peer.".to_string()) + } + + peers.insert(peer_id); + + if !addr.is_empty() { + let _ = self + .to_worker + .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id, addr)); + } + } + + let _ = self + .to_worker + .unbounded_send(ServiceToWorkerMsg::SetPeersetReserved(protocol, peers)); + + Ok(()) + } + /// Add peers to a peer set. /// /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also @@ -1400,6 +1438,7 @@ enum ServiceToWorkerMsg { AddReserved(PeerId), RemoveReserved(PeerId), SetReserved(HashSet), + SetPeersetReserved(Cow<'static, str>, HashSet), AddSetReserved(Cow<'static, str>, PeerId), RemoveSetReserved(Cow<'static, str>, PeerId), AddToPeersSet(Cow<'static, str>, PeerId), @@ -1541,6 +1580,11 @@ impl Future for NetworkWorker { .behaviour_mut() .user_protocol_mut() .set_reserved_peers(peers), + ServiceToWorkerMsg::SetPeersetReserved(protocol, peers) => this + .network_service + .behaviour_mut() + .user_protocol_mut() + .set_reserved_peerset_peers(protocol, peers), ServiceToWorkerMsg::AddReserved(peer_id) => this .network_service .behaviour_mut() From 62f011ca8d0491f6be77b3dbe0074eb060245d08 Mon Sep 17 00:00:00 2001 From: girazoki Date: Thu, 7 Oct 2021 16:29:48 +0200 Subject: [PATCH 0092/1472] Add low level traits to retrieve name, symbol, decimals and allowance in pallet-assets (#9757) * Add ERC20 compatible trait to retrieve name, symbol, decimals and allowance * delegate instead of spender * Remove erc20 trait and divide it into lower level traits * add import * approvals and metadata depend on fungibles Co-authored-by: Shawn Tabrizi --- frame/assets/src/functions.rs | 125 ++++++++++++++++++ frame/assets/src/impl_fungibles.rs | 69 ++++++++++ frame/assets/src/lib.rs | 96 +------------- frame/assets/src/tests.rs | 34 +++++ frame/support/src/traits/tokens/fungibles.rs | 2 + .../src/traits/tokens/fungibles/approvals.rs | 43 ++++++ .../src/traits/tokens/fungibles/metadata.rs | 41 ++++++ 7 files changed, 317 insertions(+), 93 deletions(-) create mode 100644 frame/support/src/traits/tokens/fungibles/approvals.rs create mode 100644 frame/support/src/traits/tokens/fungibles/metadata.rs diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index ae31b8e395194..a4685d88d0497 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -18,6 +18,7 @@ //! Functions for the Assets pallet. use super::*; +use frame_support::{traits::Get, BoundedVec}; // The main implementation block for the module. impl, I: 'static> Pallet { @@ -562,4 +563,128 @@ impl, I: 'static> Pallet { }) }) } + + /// Creates an approval from `owner` to spend `amount` of asset `id` tokens by 'delegate' + /// while reserving `T::ApprovalDeposit` from owner + /// + /// If an approval already exists, the new amount is added to such existing approval + pub(super) fn do_approve_transfer( + id: T::AssetId, + owner: &T::AccountId, + delegate: &T::AccountId, + amount: T::Balance, + ) -> DispatchResult { + let mut d = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!(!d.is_frozen, Error::::Frozen); + Approvals::::try_mutate( + (id, &owner, &delegate), + |maybe_approved| -> DispatchResult { + let mut approved = match maybe_approved.take() { + // an approval already exists and is being updated + Some(a) => a, + // a new approval is created + None => { + d.approvals.saturating_inc(); + Default::default() + }, + }; + let deposit_required = T::ApprovalDeposit::get(); + if approved.deposit < deposit_required { + T::Currency::reserve(&owner, deposit_required - approved.deposit)?; + approved.deposit = deposit_required; + } + approved.amount = approved.amount.saturating_add(amount); + *maybe_approved = Some(approved); + Ok(()) + }, + )?; + Asset::::insert(id, d); + Self::deposit_event(Event::ApprovedTransfer(id, owner.clone(), delegate.clone(), amount)); + + Ok(()) + } + + /// Reduces the asset `id` balance of `owner` by some `amount` and increases the balance of + /// `dest` by (similar) amount, checking that 'delegate' has an existing approval from `owner` + /// to spend`amount`. + /// + /// Will fail if `amount` is greater than the approval from `owner` to 'delegate' + /// Will unreserve the deposit from `owner` if the entire approved `amount` is spent by + /// 'delegate' + pub(super) fn do_transfer_approved( + id: T::AssetId, + owner: &T::AccountId, + delegate: &T::AccountId, + destination: &T::AccountId, + amount: T::Balance, + ) -> DispatchResult { + Approvals::::try_mutate_exists( + (id, &owner, delegate), + |maybe_approved| -> DispatchResult { + let mut approved = maybe_approved.take().ok_or(Error::::Unapproved)?; + let remaining = + approved.amount.checked_sub(&amount).ok_or(Error::::Unapproved)?; + + let f = TransferFlags { keep_alive: false, best_effort: false, burn_dust: false }; + Self::do_transfer(id, &owner, &destination, amount, None, f)?; + + if remaining.is_zero() { + T::Currency::unreserve(&owner, approved.deposit); + Asset::::mutate(id, |maybe_details| { + if let Some(details) = maybe_details { + details.approvals.saturating_dec(); + } + }); + } else { + approved.amount = remaining; + *maybe_approved = Some(approved); + } + Ok(()) + }, + )?; + Ok(()) + } + + /// Do set metadata + pub(super) fn do_set_metadata( + id: T::AssetId, + from: &T::AccountId, + name: Vec, + symbol: Vec, + decimals: u8, + ) -> DispatchResult { + let bounded_name: BoundedVec = + name.clone().try_into().map_err(|_| Error::::BadMetadata)?; + let bounded_symbol: BoundedVec = + symbol.clone().try_into().map_err(|_| Error::::BadMetadata)?; + + let d = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!(from == &d.owner, Error::::NoPermission); + + Metadata::::try_mutate_exists(id, |metadata| { + ensure!(metadata.as_ref().map_or(true, |m| !m.is_frozen), Error::::NoPermission); + + let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit); + let new_deposit = T::MetadataDepositPerByte::get() + .saturating_mul(((name.len() + symbol.len()) as u32).into()) + .saturating_add(T::MetadataDepositBase::get()); + + if new_deposit > old_deposit { + T::Currency::reserve(from, new_deposit - old_deposit)?; + } else { + T::Currency::unreserve(from, old_deposit - new_deposit); + } + + *metadata = Some(AssetMetadata { + deposit: new_deposit, + name: bounded_name, + symbol: bounded_symbol, + decimals, + is_frozen: false, + }); + + Self::deposit_event(Event::MetadataSet(id, name, symbol, decimals, false)); + Ok(()) + }) + } } diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 2e16a0910a4f0..be534bfad57ab 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -193,3 +193,72 @@ impl, I: 'static> fungibles::Destroy for Pallet Self::do_destroy(id, witness, maybe_check_owner) } } + +impl, I: 'static> fungibles::metadata::Inspect<::AccountId> + for Pallet +{ + fn name(asset: T::AssetId) -> Vec { + Metadata::::get(asset).name.to_vec() + } + + fn symbol(asset: T::AssetId) -> Vec { + Metadata::::get(asset).symbol.to_vec() + } + + fn decimals(asset: T::AssetId) -> u8 { + Metadata::::get(asset).decimals + } +} + +impl, I: 'static> fungibles::metadata::Mutate<::AccountId> + for Pallet +{ + fn set( + asset: T::AssetId, + from: &::AccountId, + name: Vec, + symbol: Vec, + decimals: u8, + ) -> DispatchResult { + Self::do_set_metadata(asset, from, name, symbol, decimals) + } +} + +impl, I: 'static> fungibles::approvals::Inspect<::AccountId> + for Pallet +{ + // Check the amount approved to be spent by an owner to a delegate + fn allowance( + asset: T::AssetId, + owner: &::AccountId, + delegate: &::AccountId, + ) -> T::Balance { + Approvals::::get((asset, &owner, &delegate)) + .map(|x| x.amount) + .unwrap_or_else(Zero::zero) + } +} + +impl, I: 'static> fungibles::approvals::Mutate<::AccountId> + for Pallet +{ + fn approve( + asset: T::AssetId, + owner: &::AccountId, + delegate: &::AccountId, + amount: T::Balance, + ) -> DispatchResult { + Self::do_approve_transfer(asset, owner, delegate, amount) + } + + // Aprove spending tokens from a given account + fn transfer_from( + asset: T::AssetId, + owner: &::AccountId, + delegate: &::AccountId, + dest: &::AccountId, + amount: T::Balance, + ) -> DispatchResult { + Self::do_transfer_approved(asset, owner, delegate, dest, amount) + } +} diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index c6f24e10a89f0..1ae729d7774d6 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -948,43 +948,7 @@ pub mod pallet { decimals: u8, ) -> DispatchResult { let origin = ensure_signed(origin)?; - - let bounded_name: BoundedVec = - name.clone().try_into().map_err(|_| Error::::BadMetadata)?; - let bounded_symbol: BoundedVec = - symbol.clone().try_into().map_err(|_| Error::::BadMetadata)?; - - let d = Asset::::get(id).ok_or(Error::::Unknown)?; - ensure!(&origin == &d.owner, Error::::NoPermission); - - Metadata::::try_mutate_exists(id, |metadata| { - ensure!( - metadata.as_ref().map_or(true, |m| !m.is_frozen), - Error::::NoPermission - ); - - let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit); - let new_deposit = T::MetadataDepositPerByte::get() - .saturating_mul(((name.len() + symbol.len()) as u32).into()) - .saturating_add(T::MetadataDepositBase::get()); - - if new_deposit > old_deposit { - T::Currency::reserve(&origin, new_deposit - old_deposit)?; - } else { - T::Currency::unreserve(&origin, old_deposit - new_deposit); - } - - *metadata = Some(AssetMetadata { - deposit: new_deposit, - name: bounded_name, - symbol: bounded_symbol, - decimals, - is_frozen: false, - }); - - Self::deposit_event(Event::MetadataSet(id, name, symbol, decimals, false)); - Ok(()) - }) + Self::do_set_metadata(id, &origin, name, symbol, decimals) } /// Clear the metadata for an asset. @@ -1171,35 +1135,7 @@ pub mod pallet { ) -> DispatchResult { let owner = ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; - - let mut d = Asset::::get(id).ok_or(Error::::Unknown)?; - ensure!(!d.is_frozen, Error::::Frozen); - Approvals::::try_mutate( - (id, &owner, &delegate), - |maybe_approved| -> DispatchResult { - let mut approved = match maybe_approved.take() { - // an approval already exists and is being updated - Some(a) => a, - // a new approval is created - None => { - d.approvals.saturating_inc(); - Default::default() - }, - }; - let deposit_required = T::ApprovalDeposit::get(); - if approved.deposit < deposit_required { - T::Currency::reserve(&owner, deposit_required - approved.deposit)?; - approved.deposit = deposit_required; - } - approved.amount = approved.amount.saturating_add(amount); - *maybe_approved = Some(approved); - Ok(()) - }, - )?; - Asset::::insert(id, d); - Self::deposit_event(Event::ApprovedTransfer(id, owner, delegate, amount)); - - Ok(()) + Self::do_approve_transfer(id, &owner, &delegate, amount) } /// Cancel all of some asset approved for delegated transfer by a third-party account. @@ -1306,33 +1242,7 @@ pub mod pallet { let delegate = ensure_signed(origin)?; let owner = T::Lookup::lookup(owner)?; let destination = T::Lookup::lookup(destination)?; - - Approvals::::try_mutate_exists( - (id, &owner, delegate), - |maybe_approved| -> DispatchResult { - let mut approved = maybe_approved.take().ok_or(Error::::Unapproved)?; - let remaining = - approved.amount.checked_sub(&amount).ok_or(Error::::Unapproved)?; - - let f = - TransferFlags { keep_alive: false, best_effort: false, burn_dust: false }; - Self::do_transfer(id, &owner, &destination, amount, None, f)?; - - if remaining.is_zero() { - T::Currency::unreserve(&owner, approved.deposit); - Asset::::mutate(id, |maybe_details| { - if let Some(details) = maybe_details { - details.approvals.saturating_dec(); - } - }); - } else { - approved.amount = remaining; - *maybe_approved = Some(approved); - } - Ok(()) - }, - )?; - Ok(()) + Self::do_transfer_approved(id, &owner, &delegate, &destination, amount) } } } diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 872bd7290133c..5250fafaa8f9a 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -794,3 +794,37 @@ fn assets_from_genesis_should_exist() { assert_eq!(Assets::total_supply(999), 100); }); } + +#[test] +fn querying_name_symbol_and_decimals_should_work() { + new_test_ext().execute_with(|| { + use frame_support::traits::tokens::fungibles::metadata::Inspect; + assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_set_metadata( + Origin::root(), + 0, + vec![0u8; 10], + vec![1u8; 10], + 12, + false + )); + assert_eq!(Assets::name(0), vec![0u8; 10]); + assert_eq!(Assets::symbol(0), vec![1u8; 10]); + assert_eq!(Assets::decimals(0), 12); + }); +} + +#[test] +fn querying_allowance_should_work() { + new_test_ext().execute_with(|| { + use frame_support::traits::tokens::fungibles::approvals::{Inspect, Mutate}; + assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + Balances::make_free_balance_be(&1, 1); + assert_ok!(Assets::approve(0, &1, &2, 50)); + assert_eq!(Assets::allowance(0, &1, &2), 50); + // Transfer asset 0, from owner 1 and delegate 2 to destination 3 + assert_ok!(Assets::transfer_from(0, &1, &2, &3, 50)); + assert_eq!(Assets::allowance(0, &1, &2), 0); + }); +} diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 2930853201d25..b164a99671658 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -25,7 +25,9 @@ use crate::dispatch::{DispatchError, DispatchResult}; use sp_runtime::traits::Saturating; use sp_std::vec::Vec; +pub mod approvals; mod balanced; +pub mod metadata; pub use balanced::{Balanced, Unbalanced}; mod imbalance; pub use imbalance::{CreditOf, DebtOf, HandleImbalanceDrop, Imbalance}; diff --git a/frame/support/src/traits/tokens/fungibles/approvals.rs b/frame/support/src/traits/tokens/fungibles/approvals.rs new file mode 100644 index 0000000000000..06e81b8591a80 --- /dev/null +++ b/frame/support/src/traits/tokens/fungibles/approvals.rs @@ -0,0 +1,43 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Inspect and Mutate traits for Asset approvals + +use crate::dispatch::DispatchResult; +pub trait Inspect: super::Inspect { + // Check the amount approved by an owner to be spent by a delegate + fn allowance(asset: Self::AssetId, owner: &AccountId, delegate: &AccountId) -> Self::Balance; +} + +pub trait Mutate: Inspect { + // Aprove a delegate account to spend an amount of tokens owned by an owner + fn approve( + asset: Self::AssetId, + owner: &AccountId, + delegate: &AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + // Transfer from a delegate account an amount approved by the owner of the asset + fn transfer_from( + asset: Self::AssetId, + owner: &AccountId, + delegate: &AccountId, + dest: &AccountId, + amount: Self::Balance, + ) -> DispatchResult; +} diff --git a/frame/support/src/traits/tokens/fungibles/metadata.rs b/frame/support/src/traits/tokens/fungibles/metadata.rs new file mode 100644 index 0000000000000..08bf5c4710a7d --- /dev/null +++ b/frame/support/src/traits/tokens/fungibles/metadata.rs @@ -0,0 +1,41 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Inspect and Mutate traits for Asset metadata + +use crate::dispatch::DispatchResult; +use sp_std::vec::Vec; + +pub trait Inspect: super::Inspect { + // Get name for an AssetId. + fn name(asset: Self::AssetId) -> Vec; + // Get symbol for an AssetId. + fn symbol(asset: Self::AssetId) -> Vec; + // Get decimals for an AssetId. + fn decimals(asset: Self::AssetId) -> u8; +} + +pub trait Mutate: Inspect { + // Set name, symbol and decimals for a given assetId. + fn set( + asset: Self::AssetId, + from: &AccountId, + name: Vec, + symbol: Vec, + decimals: u8, + ) -> DispatchResult; +} From eb5cba0ce4d300b5c202819c38fbde4ecce25281 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 17:18:13 +0200 Subject: [PATCH 0093/1472] Bump tracing from 0.1.25 to 0.1.29 (#9956) Bumps [tracing](https://github.com/tokio-rs/tracing) from 0.1.25 to 0.1.29. - [Release notes](https://github.com/tokio-rs/tracing/releases) - [Commits](https://github.com/tokio-rs/tracing/compare/tracing-0.1.25...tracing-0.1.29) --- updated-dependencies: - dependency-name: tracing 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 | 12 ++++++------ client/executor/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/runtime-interface/test/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/tracing/Cargo.toml | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44d285b232b8c..1c518cd064899 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10626,9 +10626,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.25" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" +checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ "cfg-if 1.0.0", "pin-project-lite 0.2.6", @@ -10638,9 +10638,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" dependencies = [ "proc-macro2", "quote", @@ -10649,9 +10649,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" dependencies = [ "lazy_static", ] diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index b7e2595b8e169..b7eb31a37593f 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -43,7 +43,7 @@ sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-mach sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-maybe-compressed-blob = { version = "4.0.0-dev", path = "../../primitives/maybe-compressed-blob" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } -tracing = "0.1.25" +tracing = "0.1.29" tracing-subscriber = "0.2.19" paste = "1.0" regex = "1" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index b5fdcfd434300..a73bfb0c2657b 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -23,7 +23,7 @@ lru = "0.6.6" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.9.0", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } -tracing = "0.1.25" +tracing = "0.1.29" [dev-dependencies] async-std = "1.10.0" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 735f215c82b36..6f63a249a7c8f 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -73,7 +73,7 @@ sc-offchain = { version = "4.0.0-dev", path = "../offchain" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.9.0" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } -tracing = "0.1.25" +tracing = "0.1.29" tracing-futures = { version = "0.2.4" } parity-util-mem = { version = "0.10.0", default-features = false, features = [ "primitive-types", diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 5cac4dccfd6e7..2d05f80be42b4 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -24,7 +24,7 @@ regex = "1.4.2" rustc-hash = "1.1.0" serde = "1.0.126" thiserror = "1.0.21" -tracing = "0.1.25" +tracing = "0.1.29" tracing-log = "0.1.2" tracing-subscriber = "0.2.19" sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 5a8c1c4af4f99..2323b5281d59a 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -30,7 +30,7 @@ sp-tracing = { version = "4.0.0-dev", default-features = false, path = "../traci log = { version = "0.4.8", optional = true } futures = { version = "0.3.1", features = ["thread-pool"], optional = true } parking_lot = { version = "0.11.1", optional = true } -tracing = { version = "0.1.25", default-features = false } +tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.17", default-features = false} [features] diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 377729521fcfe..383df494120aa 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -20,5 +20,5 @@ sp-runtime-interface-test-wasm-deprecated = { version = "2.0.0", path = "../test sp-state-machine = { version = "0.10.0-dev", path = "../../state-machine" } sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } sp-io = { version = "4.0.0-dev", path = "../../io" } -tracing = "0.1.25" +tracing = "0.1.29" tracing-core = "0.1.17" diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 903db18a38ca5..d62b598fdc3a3 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -29,7 +29,7 @@ rand = { version = "0.7.2", optional = true } sp-externalities = { version = "0.10.0-dev", path = "../externalities", default-features = false } smallvec = "1.7.0" sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } -tracing = { version = "0.1.22", optional = true } +tracing = { version = "0.1.29", optional = true } [dev-dependencies] hex-literal = "0.3.1" diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index 3be09dcd576df..ebcddb1477d34 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -22,7 +22,7 @@ sp-std = { version = "4.0.0-dev", path = "../std", default-features = false } codec = { version = "2.0.0", package = "parity-scale-codec", default-features = false, features = [ "derive", ] } -tracing = { version = "0.1.25", default-features = false } +tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.17", default-features = false } log = { version = "0.4.8", optional = true } tracing-subscriber = { version = "0.2.19", optional = true, features = [ From 7dbcd4f4418dd8287fbc822c444076ead6c91564 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Thu, 7 Oct 2021 17:46:06 +0200 Subject: [PATCH 0094/1472] Root origin always bypass all filter, other origin cannot bypass BaseCallFilter even when constructed from Root origin (#9948) * improve root filter bypass * improve doc * fmt * refactor test for more understandable flow * Update frame/support/procedural/src/construct_runtime/expand/origin.rs Co-authored-by: Keith Yeung * match Co-authored-by: Keith Yeung --- .../src/construct_runtime/expand/origin.rs | 27 +++++++++---------- frame/support/src/traits/dispatch.rs | 11 +++++--- frame/support/test/tests/construct_runtime.rs | 18 ++++++++++--- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index a65ad78527ff7..57adf86a9fe18 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -82,8 +82,9 @@ pub fn expand_outer_origin( Ok(quote! { #( #query_origin_part_macros )* - // WARNING: All instance must hold the filter `frame_system::Config::BaseCallFilter`, except - // when caller is system Root. One can use `OriginTrait::reset_filter` to do so. + /// The runtime origin type represanting the origin of a call. + /// + /// Origin is always created with the base filter configured in `frame_system::Config::BaseCallFilter`. #[derive(Clone)] pub struct Origin { caller: OriginCaller, @@ -140,7 +141,11 @@ pub fn expand_outer_origin( } fn filter_call(&self, call: &Self::Call) -> bool { - (self.filter)(call) + match self.caller { + // Root bypasses all filters + OriginCaller::system(#system_path::Origin::<#runtime>::Root) => true, + _ => (self.filter)(call), + } } fn caller(&self) -> &Self::PalletsOrigin { @@ -157,15 +162,14 @@ pub fn expand_outer_origin( } } - /// Create with system none origin and `frame-system::Config::BaseCallFilter`. fn none() -> Self { #system_path::RawOrigin::None.into() } - /// Create with system root origin and no filter. + fn root() -> Self { #system_path::RawOrigin::Root.into() } - /// Create with system signed origin and `frame-system::Config::BaseCallFilter`. + fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self { #system_path::RawOrigin::Signed(by).into() } @@ -191,7 +195,7 @@ pub fn expand_outer_origin( pub fn none() -> Self { ::none() } - /// Create with system root origin and no filter. + /// Create with system root origin and `frame-system::Config::BaseCallFilter`. pub fn root() -> Self { ::root() } @@ -221,9 +225,7 @@ pub fn expand_outer_origin( } impl From<#system_path::Origin<#runtime>> for Origin { - /// Convert to runtime origin: - /// * root origin is built with no filter - /// * others use `frame-system::Config::BaseCallFilter` + /// Convert to runtime origin, using as filter: `frame-system::Config::BaseCallFilter`. fn from(x: #system_path::Origin<#runtime>) -> Self { let o: OriginCaller = x.into(); o.into() @@ -237,10 +239,7 @@ pub fn expand_outer_origin( filter: #scrate::sp_std::rc::Rc::new(Box::new(|_| true)), }; - // Root has no filter - if !matches!(o.caller, OriginCaller::system(#system_path::Origin::<#runtime>::Root)) { - #scrate::traits::OriginTrait::reset_filter(&mut o); - } + #scrate::traits::OriginTrait::reset_filter(&mut o); o } diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index f82628ede18cc..92b832ba32961 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -70,7 +70,10 @@ pub trait OriginTrait: Sized { /// Replace the caller with caller from the other origin fn set_caller_from(&mut self, other: impl Into); - /// Filter the call, if false then call is filtered out. + /// Filter the call if caller is not root, if false is returned then the call must be filtered + /// out. + /// + /// For root origin caller, the filters are bypassed and true is returned. fn filter_call(&self, call: &Self::Call) -> bool; /// Get the caller. @@ -82,12 +85,12 @@ pub trait OriginTrait: Sized { f: impl FnOnce(Self::PalletsOrigin) -> Result, ) -> Result; - /// Create with system none origin and `frame-system::Config::BaseCallFilter`. + /// Create with system none origin and `frame_system::Config::BaseCallFilter`. fn none() -> Self; - /// Create with system root origin and no filter. + /// Create with system root origin and `frame_system::Config::BaseCallFilter`. fn root() -> Self; - /// Create with system signed origin and `frame-system::Config::BaseCallFilter`. + /// Create with system signed origin and `frame_system::Config::BaseCallFilter`. fn signed(by: Self::AccountId) -> Self; } diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index dd5538370449d..2d14da04f64b7 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -327,19 +327,31 @@ mod origin_test { assert_eq!(Origin::from(super::nested::module3::Origin).filter_call(&rejected_call), false); let mut origin = Origin::from(Some(0)); - origin.add_filter(|c| matches!(c, Call::Module3(_))); assert_eq!(origin.filter_call(&accepted_call), false); assert_eq!(origin.filter_call(&rejected_call), false); + // Now test for root origin and filters: + let mut origin = Origin::from(Some(0)); origin.set_caller_from(Origin::root()); assert!(matches!(origin.caller, OriginCaller::system(super::system::RawOrigin::Root))); - assert_eq!(origin.filter_call(&accepted_call), false); + + // Root origin bypass all filter. + assert_eq!(origin.filter_call(&accepted_call), true); + assert_eq!(origin.filter_call(&rejected_call), true); + + origin.set_caller_from(Origin::from(Some(0))); + + // Back to another signed origin, the filtered are now effective again + assert_eq!(origin.filter_call(&accepted_call), true); assert_eq!(origin.filter_call(&rejected_call), false); + origin.set_caller_from(Origin::root()); origin.reset_filter(); + + // Root origin bypass all filter, even when they are reset. assert_eq!(origin.filter_call(&accepted_call), true); - assert_eq!(origin.filter_call(&rejected_call), false); + assert_eq!(origin.filter_call(&rejected_call), true); } } From 48f3cdd8f9720efd488a0f44cf6d923feb17ef03 Mon Sep 17 00:00:00 2001 From: Eric Miller Date: Thu, 7 Oct 2021 19:02:09 -0400 Subject: [PATCH 0095/1472] Support extra constant renaming (#9814) * Rebased with master. Resolved merge conflict in frame/support/test/tests/pallet.rs * Switching Account ID to SomeType1, as SomeType3 was giving me conversion error. * Wrong indent config. Fixed. * These tabs look fine locally, but look different on Github. Trying to get the style config right. * Parsing pallet::constant_name. Passing unit tests, which is confusing because I didn't change `ident` in the ExtraConstantDef initialization. * Finalized parsing of extra constant name by adding optional metadata field. Added expansion logic that replaces respective `idents` where they exist. * Erasing this to try to keep the format the same across the source code. * Another formatting change for consistency. * Update frame/support/procedural/src/pallet/expand/constants.rs strictly more idiomatic. Co-authored-by: Guillaume Thiolliere * Update frame/support/procedural/src/pallet/parse/extra_constants.rs strictly idiomatic change. Co-authored-by: Guillaume Thiolliere * Fixing formatting and CI warnings. * switched to nightly compiler to use rustfmt.toml Co-authored-by: Eric Miller Co-authored-by: Guillaume Thiolliere --- .../procedural/src/pallet/expand/constants.rs | 8 +++- .../src/pallet/parse/extra_constants.rs | 42 ++++++++++++++++++- .../procedural/src/pallet/parse/helper.rs | 6 +++ frame/support/test/tests/pallet.rs | 12 ++++++ 4 files changed, 65 insertions(+), 3 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/constants.rs b/frame/support/procedural/src/pallet/expand/constants.rs index db47bf552ac16..20106c71cbf07 100644 --- a/frame/support/procedural/src/pallet/expand/constants.rs +++ b/frame/support/procedural/src/pallet/expand/constants.rs @@ -26,6 +26,8 @@ struct ConstDef { pub doc: Vec, /// default_byte implementation pub default_byte_impl: proc_macro2::TokenStream, + /// Constant name for Metadata (optional) + pub metadata_name: Option, } /// @@ -54,6 +56,7 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::traits::Get<#const_type>>::get(); #frame_support::codec::Encode::encode(&value) ), + metadata_name: None, } }); @@ -68,13 +71,14 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { let value = >::#ident(); #frame_support::codec::Encode::encode(&value) ), + metadata_name: const_.metadata_name.clone(), } }); let consts = config_consts.chain(extra_consts).map(|const_| { let const_type = &const_.type_; - let ident = &const_.ident; - let ident_str = format!("{}", ident); + let ident_str = format!("{}", const_.metadata_name.unwrap_or(const_.ident)); + let doc = const_.doc.clone().into_iter(); let default_byte_impl = &const_.default_byte_impl; diff --git a/frame/support/procedural/src/pallet/parse/extra_constants.rs b/frame/support/procedural/src/pallet/parse/extra_constants.rs index c1324df6c22f1..a5f3c0a8c2dab 100644 --- a/frame/support/procedural/src/pallet/parse/extra_constants.rs +++ b/frame/support/procedural/src/pallet/parse/extra_constants.rs @@ -28,6 +28,7 @@ mod keyword { syn::custom_keyword!(compact); syn::custom_keyword!(T); syn::custom_keyword!(pallet); + syn::custom_keyword!(constant_name); } /// Definition of extra constants typically `impl Pallet { ... }` @@ -50,6 +51,29 @@ pub struct ExtraConstantDef { pub type_: syn::Type, /// The doc associated pub doc: Vec, + /// Optional MetaData Name + pub metadata_name: Option, +} + +/// Attributes for functions in extra_constants impl block. +/// Parse for `#[pallet::constant_name(ConstantName)]` +pub struct ExtraConstAttr { + metadata_name: syn::Ident, +} + +impl syn::parse::Parse for ExtraConstAttr { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + let content; + syn::bracketed!(content in input); + content.parse::()?; + content.parse::()?; + content.parse::()?; + + let metadata_name; + syn::parenthesized!(metadata_name in content); + Ok(ExtraConstAttr { metadata_name: metadata_name.parse::()? }) + } } impl ExtraConstantsDef { @@ -57,7 +81,10 @@ impl ExtraConstantsDef { let item = if let syn::Item::Impl(item) = item { item } else { - return Err(syn::Error::new(item.span(), "Invalid pallet::call, expected item impl")) + return Err(syn::Error::new( + item.span(), + "Invalid pallet::extra_constants, expected item impl", + )) }; let mut instances = vec![]; @@ -102,10 +129,23 @@ impl ExtraConstantsDef { syn::ReturnType::Type(_, type_) => *type_.clone(), }; + // parse metadata_name + let mut extra_constant_attrs: Vec = + helper::take_item_pallet_attrs(method)?; + + if extra_constant_attrs.len() > 1 { + let msg = + "Invalid attribute in pallet::constant_name, only one attribute is expected"; + return Err(syn::Error::new(extra_constant_attrs[1].metadata_name.span(), msg)) + } + + let metadata_name = extra_constant_attrs.pop().map(|attr| attr.metadata_name); + extra_constants.push(ExtraConstantDef { ident: method.sig.ident.clone(), type_, doc: get_doc_literals(&method.attrs), + metadata_name, }); } diff --git a/frame/support/procedural/src/pallet/parse/helper.rs b/frame/support/procedural/src/pallet/parse/helper.rs index 2590e86b58b0e..f5a7dc233cacb 100644 --- a/frame/support/procedural/src/pallet/parse/helper.rs +++ b/frame/support/procedural/src/pallet/parse/helper.rs @@ -139,6 +139,12 @@ impl MutItemAttrs for syn::ItemMod { } } +impl MutItemAttrs for syn::ImplItemMethod { + fn mut_item_attrs(&mut self) -> Option<&mut Vec> { + Some(&mut self.attrs) + } +} + /// Parse for `()` struct Unit; impl syn::parse::Parse for Unit { diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 25fc2d46d2560..dc72be3ebdd49 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -146,6 +146,12 @@ pub mod pallet { fn some_extra_extra() -> T::AccountId { SomeType1.into() } + + /// Some doc + #[pallet::constant_name(SomeExtraRename)] + fn some_extra_rename() -> T::AccountId { + SomeType1.into() + } } #[pallet::pallet] @@ -1220,6 +1226,12 @@ fn metadata() { value: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![" Some doc"], }, + PalletConstantMetadata { + name: "SomeExtraRename", + ty: meta_type::(), + value: vec![0, 0, 0, 0, 0, 0, 0, 0], + docs: vec![" Some doc"], + }, ], error: Some(PalletErrorMetadata { ty: meta_type::>() }), }, From 4a9b8d1977ff5844ef07be76337de7034d1d50d3 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 8 Oct 2021 04:44:24 +0200 Subject: [PATCH 0096/1472] Remove unnecessary mut reference in `handle_justification` (#9968) --- client/consensus/common/src/block_import.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index 6d411dd9afbf1..d828e54bc7e3e 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -74,7 +74,7 @@ impl ImportResult { &self, hash: &B::Hash, number: NumberFor, - justification_sync_link: &mut dyn JustificationSyncLink, + justification_sync_link: &dyn JustificationSyncLink, ) where B: BlockT, { From 911c1889ce8bb4d6ec88def60496b1c651a554d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Oct 2021 09:38:58 +0200 Subject: [PATCH 0097/1472] Bump jsonrpsee-proc-macros from 0.3.0 to 0.3.1 (#9957) Bumps [jsonrpsee-proc-macros](https://github.com/paritytech/jsonrpsee) from 0.3.0 to 0.3.1. - [Release notes](https://github.com/paritytech/jsonrpsee/releases) - [Changelog](https://github.com/paritytech/jsonrpsee/blob/master/CHANGELOG.md) - [Commits](https://github.com/paritytech/jsonrpsee/compare/v0.3.0...v0.3.1) --- updated-dependencies: - dependency-name: jsonrpsee-proc-macros 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 ++-- utils/frame/remote-externalities/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c518cd064899..ce65894b13aec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3123,9 +3123,9 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f37924e16300e249a52a22cabb5632f846dc9760b39355f5e8bc70cd23dc6300" +checksum = "8edb341d35279b59c79d7fe9e060a51aec29d45af99cc7c72ea7caa350fa71a4" dependencies = [ "Inflector", "bae", diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index ce774679f94c2..1fbe1a7ea1d82 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] jsonrpsee-ws-client = { version = "0.3.0", default-features = false, features = [ "tokio1", ]} -jsonrpsee-proc-macros = "0.3.0" +jsonrpsee-proc-macros = "0.3.1" env_logger = "0.9" log = "0.4.11" From d9944b0a9aa62c2ebc1953fc7d7725f0bbc48de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 8 Oct 2021 10:02:25 +0200 Subject: [PATCH 0098/1472] Transaction pool: Adds benchmark and improves performance (#9958) * Yep * Make it compile * Make the benchmark work * Some stuff * Optimize transaction pool `BestIterator` * Some docs * Fix more warnings * Fix compilation * FMT --- Cargo.lock | 65 ++--- bin/node/cli/Cargo.toml | 10 +- bin/node/cli/benches/transaction_pool.rs | 274 ++++++++++++++++++ bin/node/cli/src/lib.rs | 2 +- bin/node/cli/src/service.rs | 92 +++++- bin/node/runtime/src/lib.rs | 2 + client/transaction-pool/src/graph/ready.rs | 12 +- .../transaction-pool/src/graph/tracked_map.rs | 21 +- client/transaction-pool/src/lib.rs | 2 +- 9 files changed, 415 insertions(+), 65 deletions(-) create mode 100644 bin/node/cli/benches/transaction_pool.rs diff --git a/Cargo.lock b/Cargo.lock index ce65894b13aec..8194c0a1b12df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1200,7 +1200,7 @@ dependencies = [ "cranelift-codegen 0.76.0", "cranelift-entity 0.76.0", "cranelift-frontend 0.76.0", - "itertools 0.10.0", + "itertools", "log 0.4.14", "serde", "smallvec 1.7.0", @@ -1219,16 +1219,17 @@ dependencies = [ [[package]] name = "criterion" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23" +checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ "atty", "cast", "clap", "criterion-plot", "csv", - "itertools 0.10.0", + "futures 0.3.16", + "itertools", "lazy_static", "num-traits", "oorandom", @@ -1240,17 +1241,18 @@ dependencies = [ "serde_derive", "serde_json", "tinytemplate", + "tokio", "walkdir", ] [[package]] name = "criterion-plot" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" +checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" dependencies = [ "cast", - "itertools 0.9.0", + "itertools", ] [[package]] @@ -2943,15 +2945,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.10.0" @@ -2978,9 +2971,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.50" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" +checksum = "1866b355d9c878e5e607473cbe3f63282c0b7aad2db1dbebf55076c686918254" dependencies = [ "wasm-bindgen", ] @@ -4469,8 +4462,10 @@ version = "3.0.0-dev" dependencies = [ "assert_cmd", "async-std", + "criterion", "frame-benchmarking-cli", "frame-system", + "frame-system-rpc-runtime-api", "futures 0.3.16", "hex-literal", "jsonrpsee-ws-client", @@ -4481,6 +4476,7 @@ dependencies = [ "node-primitives", "node-rpc", "node-runtime", + "pallet-balances", "pallet-im-online", "pallet-transaction-payment", "parity-scale-codec", @@ -4513,6 +4509,7 @@ dependencies = [ "serde", "serde_json", "soketto 0.4.2", + "sp-api", "sp-authority-discovery", "sp-authorship", "sp-consensus", @@ -6538,9 +6535,9 @@ checksum = "989d43012e2ca1c4a02507c67282691a0a3207f9dc67cec596b43fe925b3d325" [[package]] name = "plotters" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ca0ae5f169d0917a7c7f5a9c1a3d3d9598f18f529dd2b8373ed988efea307a" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" dependencies = [ "num-traits", "plotters-backend", @@ -6780,7 +6777,7 @@ checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603" dependencies = [ "bytes 1.0.1", "heck", - "itertools 0.10.0", + "itertools", "log 0.4.14", "multimap", "petgraph", @@ -6797,7 +6794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba" dependencies = [ "anyhow", - "itertools 0.10.0", + "itertools", "proc-macro2", "quote", "syn", @@ -11115,9 +11112,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.73" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" +checksum = "5e68338db6becec24d3c7977b5bf8a48be992c934b5d07177e3931f5dc9b076c" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -11125,9 +11122,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.73" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" +checksum = "f34c405b4f0658583dba0c1c7c9b694f3cac32655db463b56c254a1c75269523" dependencies = [ "bumpalo", "lazy_static", @@ -11152,9 +11149,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.73" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" +checksum = "b9d5a6580be83b19dc570a8f9c324251687ab2184e57086f71625feb57ec77c8" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -11162,9 +11159,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.73" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" +checksum = "e3775a030dc6f5a0afd8a84981a21cc92a781eb429acef9ecce476d0c9113e92" dependencies = [ "proc-macro2", "quote", @@ -11175,9 +11172,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.73" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" +checksum = "c279e376c7a8e8752a8f1eaa35b7b0bee6bb9fb0cdacfa97cc3f1f289c87e2b4" [[package]] name = "wasm-gc-api" @@ -11648,9 +11645,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.47" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" +checksum = "0a84d70d1ec7d2da2d26a5bd78f4bca1b8c3254805363ce743b7a05bc30d195a" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 42bc48e824c6e..8b14f1cbeeb83 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -46,6 +46,7 @@ structopt = { version = "0.3.8", optional = true } sp-authority-discovery = { version = "4.0.0-dev", path = "../../../primitives/authority-discovery" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } grandpa-primitives = { version = "4.0.0-dev", package = "sp-finality-grandpa", path = "../../../primitives/finality-grandpa" } +sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } @@ -78,6 +79,7 @@ sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state # frame dependencies frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } +frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../frame/system/rpc/runtime-api" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } pallet-im-online = { version = "4.0.0-dev", default-features = false, path = "../../../frame/im-online" } @@ -124,8 +126,9 @@ regex = "1" platforms = "1.1" async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" -jsonrpsee-ws-client = { version = "0.3.0", default-features = false, features = ["tokio1"] } +criterion = { version = "0.3.5", features = [ "async_tokio" ] } tokio = { version = "1.10", features = ["macros", "time"] } +jsonrpsee-ws-client = { version = "0.3.0", default-features = false, features = ["tokio1"] } wait-timeout = "0.2" remote-externalities = { path = "../../../utils/frame/remote-externalities" } @@ -137,6 +140,7 @@ substrate-build-script-utils = { version = "3.0.0", optional = true, path = "../ substrate-frame-cli = { version = "4.0.0-dev", optional = true, path = "../../../utils/frame/frame-utilities-cli" } try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../utils/frame/try-runtime/cli" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", optional = true } +pallet-balances = { version = "4.0.0-dev", path = "../../../frame/balances" } [features] default = ["cli"] @@ -158,3 +162,7 @@ runtime-benchmarks = [ # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. try-runtime = ["node-runtime/try-runtime", "try-runtime-cli"] + +[[bench]] +name = "transaction_pool" +harness = false diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs new file mode 100644 index 0000000000000..c435012e9f86f --- /dev/null +++ b/bin/node/cli/benches/transaction_pool.rs @@ -0,0 +1,274 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; +use futures::{future, StreamExt}; +use node_cli::service::{create_extrinsic, fetch_nonce, FullClient, TransactionPool}; +use node_primitives::AccountId; +use node_runtime::{constants::currency::*, BalancesCall, SudoCall}; +use sc_client_api::execution_extensions::ExecutionStrategies; +use sc_service::{ + config::{ + DatabaseSource, KeepBlocks, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, + PruningMode, TransactionPoolOptions, TransactionStorageMode, WasmExecutionMethod, + }, + BasePath, Configuration, Role, +}; +use sc_transaction_pool::PoolLimit; +use sc_transaction_pool_api::{TransactionPool as _, TransactionSource, TransactionStatus}; +use sp_core::{crypto::Pair, sr25519}; +use sp_keyring::Sr25519Keyring; +use sp_runtime::{generic::BlockId, OpaqueExtrinsic}; +use tokio::runtime::Handle; + +fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { + let base_path = BasePath::new_temp_dir().expect("Creates base path"); + let root = base_path.path().to_path_buf(); + + let network_config = NetworkConfiguration::new( + Sr25519Keyring::Alice.to_seed(), + "network/test/0.1", + Default::default(), + None, + ); + + let spec = Box::new(node_cli::chain_spec::development_config()); + + let config = Configuration { + impl_name: "BenchmarkImpl".into(), + impl_version: "1.0".into(), + role: Role::Authority, + tokio_handle, + transaction_pool: TransactionPoolOptions { + ready: PoolLimit { count: 100_000, total_bytes: 100 * 1024 * 1024 }, + future: PoolLimit { count: 100_000, total_bytes: 100 * 1024 * 1024 }, + reject_future_transactions: false, + }, + network: network_config, + keystore: KeystoreConfig::InMemory, + keystore_remote: Default::default(), + database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, + state_cache_size: 67108864, + state_cache_child_ratio: None, + state_pruning: PruningMode::ArchiveAll, + keep_blocks: KeepBlocks::All, + transaction_storage: TransactionStorageMode::BlockBody, + chain_spec: spec, + wasm_method: WasmExecutionMethod::Interpreted, + // NOTE: we enforce the use of the native runtime to make the errors more debuggable + execution_strategies: ExecutionStrategies { + syncing: sc_client_api::ExecutionStrategy::NativeWhenPossible, + importing: sc_client_api::ExecutionStrategy::NativeWhenPossible, + block_construction: sc_client_api::ExecutionStrategy::NativeWhenPossible, + offchain_worker: sc_client_api::ExecutionStrategy::NativeWhenPossible, + other: sc_client_api::ExecutionStrategy::NativeWhenPossible, + }, + rpc_http: None, + rpc_ws: None, + rpc_ipc: None, + rpc_ws_max_connections: None, + rpc_cors: None, + rpc_methods: Default::default(), + rpc_max_payload: None, + prometheus_config: None, + telemetry_endpoints: None, + default_heap_pages: None, + offchain_worker: OffchainWorkerConfig { enabled: true, indexing_enabled: false }, + force_authoring: false, + disable_grandpa: false, + dev_key_seed: Some(Sr25519Keyring::Alice.to_seed()), + tracing_targets: None, + tracing_receiver: Default::default(), + max_runtime_instances: 8, + announce_block: true, + base_path: Some(base_path), + informant_output_format: Default::default(), + wasm_runtime_overrides: None, + disable_log_reloading: false, + }; + + node_cli::service::new_full_base(config, |_, _| ()).expect("Creates node") +} + +fn create_accounts(num: usize) -> Vec { + (0..num) + .map(|i| { + Pair::from_string(&format!("{}/{}", Sr25519Keyring::Alice.to_seed(), i), None) + .expect("Creates account pair") + }) + .collect() +} + +/// Create the extrinsics that will initialize the accounts from the sudo account (Alice). +/// +/// `start_nonce` is the current nonce of Alice. +fn create_account_extrinsics( + client: &FullClient, + accounts: &[sr25519::Pair], +) -> Vec { + let start_nonce = fetch_nonce(client, Sr25519Keyring::Alice.pair()); + + accounts + .iter() + .enumerate() + .map(|(i, a)| { + vec![ + // Reset the nonce by removing any funds + create_extrinsic( + client, + Sr25519Keyring::Alice.pair(), + SudoCall::sudo { + call: Box::new( + BalancesCall::set_balance { + who: AccountId::from(a.public()).into(), + new_free: 0, + new_reserved: 0, + } + .into(), + ), + }, + Some(start_nonce + (i as u32) * 2), + ), + // Give back funds + create_extrinsic( + client, + Sr25519Keyring::Alice.pair(), + SudoCall::sudo { + call: Box::new( + BalancesCall::set_balance { + who: AccountId::from(a.public()).into(), + new_free: 1_000_000 * DOLLARS, + new_reserved: 0, + } + .into(), + ), + }, + Some(start_nonce + (i as u32) * 2 + 1), + ), + ] + }) + .flatten() + .map(OpaqueExtrinsic::from) + .collect() +} + +fn create_benchmark_extrinsics( + client: &FullClient, + accounts: &[sr25519::Pair], + extrinsics_per_account: usize, +) -> Vec { + accounts + .iter() + .map(|account| { + (0..extrinsics_per_account).map(move |nonce| { + create_extrinsic( + client, + account.clone(), + BalancesCall::transfer { + dest: Sr25519Keyring::Bob.to_account_id().into(), + value: 1 * DOLLARS, + }, + Some(nonce as u32), + ) + }) + }) + .flatten() + .map(OpaqueExtrinsic::from) + .collect() +} + +async fn submit_tx_and_wait_for_inclusion( + tx_pool: &TransactionPool, + tx: OpaqueExtrinsic, + client: &FullClient, + wait_for_finalized: bool, +) { + let best_hash = client.chain_info().best_hash; + + let mut watch = tx_pool + .submit_and_watch(&BlockId::Hash(best_hash), TransactionSource::External, tx.clone()) + .await + .expect("Submits tx to pool") + .fuse(); + + loop { + match watch.select_next_some().await { + TransactionStatus::Finalized(_) => break, + TransactionStatus::InBlock(_) if !wait_for_finalized => break, + _ => {}, + } + } +} + +fn transaction_pool_benchmarks(c: &mut Criterion) { + sp_tracing::try_init_simple(); + + let runtime = tokio::runtime::Runtime::new().expect("Creates tokio runtime"); + let tokio_handle = runtime.handle().clone(); + + let node = new_node(tokio_handle.clone()); + + let account_num = 10; + let extrinsics_per_account = 2000; + let accounts = create_accounts(account_num); + + let mut group = c.benchmark_group("Transaction pool"); + + group.sample_size(10); + group.throughput(Throughput::Elements(account_num as u64 * extrinsics_per_account as u64)); + + let mut counter = 1; + group.bench_function( + format!("{} transfers from {} accounts", account_num * extrinsics_per_account, account_num), + move |b| { + b.iter_batched( + || { + let prepare_extrinsics = create_account_extrinsics(&*node.client, &accounts); + + runtime.block_on(future::join_all(prepare_extrinsics.into_iter().map(|tx| { + submit_tx_and_wait_for_inclusion( + &node.transaction_pool, + tx, + &*node.client, + true, + ) + }))); + + create_benchmark_extrinsics(&*node.client, &accounts, extrinsics_per_account) + }, + |extrinsics| { + runtime.block_on(future::join_all(extrinsics.into_iter().map(|tx| { + submit_tx_and_wait_for_inclusion( + &node.transaction_pool, + tx, + &*node.client, + false, + ) + }))); + + println!("Finished {}", counter); + counter += 1; + }, + BatchSize::SmallInput, + ) + }, + ); +} + +criterion_group!(benches, transaction_pool_benchmarks); +criterion_main!(benches); diff --git a/bin/node/cli/src/lib.rs b/bin/node/cli/src/lib.rs index 1a4c1b0eab8db..ae851c6cdf628 100644 --- a/bin/node/cli/src/lib.rs +++ b/bin/node/cli/src/lib.rs @@ -33,7 +33,7 @@ pub mod chain_spec; #[macro_use] -mod service; +pub mod service; #[cfg(feature = "cli")] mod cli; #[cfg(feature = "cli")] diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index ec5497ab47d91..938f359368181 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -20,20 +20,25 @@ //! Service implementation. Specialized wrapper over substrate service. +use codec::Encode; +use frame_system_rpc_runtime_api::AccountNonceApi; use futures::prelude::*; use node_executor::ExecutorDispatch; use node_primitives::Block; use node_runtime::RuntimeApi; -use sc_client_api::{ExecutorProvider, RemoteBackend}; +use sc_client_api::{BlockBackend, ExecutorProvider, RemoteBackend}; use sc_consensus_babe::{self, SlotProportion}; use sc_executor::NativeElseWasmExecutor; use sc_network::{Event, NetworkService}; use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager}; use sc_telemetry::{Telemetry, TelemetryWorker}; -use sp_runtime::traits::Block as BlockT; +use sp_api::ProvideRuntimeApi; +use sp_core::crypto::Pair; +use sp_runtime::{generic, traits::Block as BlockT, SaturatedConversion}; use std::sync::Arc; -type FullClient = +/// The full client type definition. +pub type FullClient = sc_service::TFullClient>; type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; @@ -41,7 +46,80 @@ type FullGrandpaBlockImport = grandpa::GrandpaBlockImport; type LightClient = sc_service::TLightClient>; +/// The transaction pool type defintion. +pub type TransactionPool = sc_transaction_pool::FullPool; + +/// Fetch the nonce of the given `account` from the chain state. +/// +/// Note: Should only be used for tests. +pub fn fetch_nonce(client: &FullClient, account: sp_core::sr25519::Pair) -> u32 { + let best_hash = client.chain_info().best_hash; + client + .runtime_api() + .account_nonce(&generic::BlockId::Hash(best_hash), account.public().into()) + .expect("Fetching account nonce works; qed") +} + +/// Create a transaction using the given `call`. +/// +/// The transaction will be signed by `sender`. If `nonce` is `None` it will be fetched from the +/// state of the best block. +/// +/// Note: Should only be used for tests. +pub fn create_extrinsic( + client: &FullClient, + sender: sp_core::sr25519::Pair, + function: impl Into, + nonce: Option, +) -> node_runtime::UncheckedExtrinsic { + let function = function.into(); + let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); + let best_hash = client.chain_info().best_hash; + let best_block = client.chain_info().best_number; + let nonce = nonce.unwrap_or_else(|| fetch_nonce(client, sender.clone())); + + let period = node_runtime::BlockHashCount::get() + .checked_next_power_of_two() + .map(|c| c / 2) + .unwrap_or(2) as u64; + let tip = 0; + let extra: node_runtime::SignedExtra = ( + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(generic::Era::mortal( + period, + best_block.saturated_into(), + )), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(tip), + ); + + let raw_payload = node_runtime::SignedPayload::from_raw( + function.clone(), + extra.clone(), + ( + node_runtime::VERSION.spec_version, + node_runtime::VERSION.transaction_version, + genesis_hash, + best_hash, + (), + (), + (), + ), + ); + let signature = raw_payload.using_encoded(|e| sender.sign(e)); + + node_runtime::UncheckedExtrinsic::new_signed( + function.clone(), + sp_runtime::AccountId32::from(sender.public()).into(), + node_runtime::Signature::Sr25519(signature.clone()), + extra.clone(), + ) +} +/// Creates a new partial node. pub fn new_partial( config: &Configuration, ) -> Result< @@ -211,11 +289,16 @@ pub fn new_partial( }) } +/// Result of [`new_full_base`]. pub struct NewFullBase { + /// The task manager of the node. pub task_manager: TaskManager, + /// The client instance of the node. pub client: Arc, + /// The networking service of the node. pub network: Arc::Hash>>, - pub transaction_pool: Arc>, + /// The transaction pool of the node. + pub transaction_pool: Arc, } /// Creates a full service from the configuration. @@ -433,6 +516,7 @@ pub fn new_full(config: Configuration) -> Result { new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| task_manager) } +/// Creates a light service from the configuration. pub fn new_light_base( mut config: Configuration, ) -> Result< diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 9fac468519a07..4f620976c3abc 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -81,6 +81,8 @@ pub use pallet_balances::Call as BalancesCall; #[cfg(any(feature = "std", test))] pub use pallet_staking::StakerStatus; #[cfg(any(feature = "std", test))] +pub use pallet_sudo::Call as SudoCall; +#[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; /// Implementations of some helper traits passed into runtime modules as associated types. diff --git a/client/transaction-pool/src/graph/ready.rs b/client/transaction-pool/src/graph/ready.rs index 99a034689ccd0..92adf2e62d623 100644 --- a/client/transaction-pool/src/graph/ready.rs +++ b/client/transaction-pool/src/graph/ready.rs @@ -31,7 +31,7 @@ use sp_runtime::{traits::Member, transaction_validity::TransactionTag as Tag}; use super::{ base_pool::Transaction, future::WaitingTransaction, - tracked_map::{self, ReadOnlyTrackedMap, TrackedMap}, + tracked_map::{self, TrackedMap}, }; /// An in-pool transaction reference. @@ -162,7 +162,7 @@ impl ReadyTransactions { /// skipped. pub fn get(&self) -> BestIterator { BestIterator { - all: self.ready.clone(), + all: self.ready.clone_map(), best: self.best.clone(), awaiting: Default::default(), invalid: Default::default(), @@ -484,7 +484,7 @@ impl ReadyTransactions { /// Iterator of ready transactions ordered by priority. pub struct BestIterator { - all: ReadOnlyTrackedMap>, + all: HashMap>, awaiting: HashMap)>, best: BTreeSet>, invalid: HashSet, @@ -519,7 +519,7 @@ impl BestIterator { /// When given transaction is not in the pool it has no effect. /// When invoked on a fully drained iterator it has no effect either. pub fn report_invalid(&mut self, tx: &Arc>) { - if let Some(to_report) = self.all.read().get(&tx.hash) { + if let Some(to_report) = self.all.get(&tx.hash) { debug!( target: "txpool", "[{:?}] Reported as invalid. Will skip sub-chains while iterating.", @@ -551,8 +551,7 @@ impl Iterator for BestIterator { continue } - let next = self.all.read().get(hash).cloned(); - let ready = match next { + let ready = match self.all.get(&hash).cloned() { Some(ready) => ready, // The transaction is not in all, maybe it was removed in the meantime? None => continue, @@ -567,7 +566,6 @@ impl Iterator for BestIterator { // then get from the pool } else { self.all - .read() .get(hash) .map(|next| (next.requires_offset + 1, next.transaction.clone())) }; diff --git a/client/transaction-pool/src/graph/tracked_map.rs b/client/transaction-pool/src/graph/tracked_map.rs index c1fdda227c6ae..2f560d1c56245 100644 --- a/client/transaction-pool/src/graph/tracked_map.rs +++ b/client/transaction-pool/src/graph/tracked_map.rs @@ -57,11 +57,6 @@ impl TrackedMap { std::cmp::max(self.bytes.load(AtomicOrdering::Relaxed), 0) as usize } - /// Read-only clone of the interior. - pub fn clone(&self) -> ReadOnlyTrackedMap { - ReadOnlyTrackedMap(self.index.clone()) - } - /// Lock map for read. pub fn read(&self) -> TrackedMapReadAccess { TrackedMapReadAccess { inner_guard: self.index.read() } @@ -77,18 +72,10 @@ impl TrackedMap { } } -/// Read-only access to map. -/// -/// The only thing can be done is .read(). -pub struct ReadOnlyTrackedMap(Arc>>); - -impl ReadOnlyTrackedMap -where - K: Eq + std::hash::Hash, -{ - /// Lock map for read. - pub fn read(&self) -> TrackedMapReadAccess { - TrackedMapReadAccess { inner_guard: self.0.read() } +impl TrackedMap { + /// Clone the inner map. + pub fn clone_map(&self) -> HashMap { + self.index.read().clone() } } diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 4d355df22d821..8af73c3fe5b48 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -44,7 +44,7 @@ use futures::{ future::{self, ready}, prelude::*, }; -pub use graph::{ChainApi, Options, Pool, Transaction}; +pub use graph::{base_pool::Limit as PoolLimit, ChainApi, Options, Pool, Transaction}; use parking_lot::Mutex; use std::{ collections::{HashMap, HashSet}, From 89cf23d5240d6d8fec3469b985e55ba30652775d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Oct 2021 09:01:04 +0000 Subject: [PATCH 0099/1472] Bump jsonrpsee-ws-client from 0.3.0 to 0.3.1 (#9963) Bumps [jsonrpsee-ws-client](https://github.com/paritytech/jsonrpsee) from 0.3.0 to 0.3.1. - [Release notes](https://github.com/paritytech/jsonrpsee/releases) - [Changelog](https://github.com/paritytech/jsonrpsee/blob/master/CHANGELOG.md) - [Commits](https://github.com/paritytech/jsonrpsee/compare/v0.3.0...v0.3.1) --- updated-dependencies: - dependency-name: jsonrpsee-ws-client 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 +++++----- bin/node/cli/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8194c0a1b12df..2bae84429d19c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3130,9 +3130,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d67724d368c59e08b557a516cf8fcc51100e7a708850f502e1044b151fe89788" +checksum = "4cc738fd55b676ada3271ef7c383a14a0867a2a88b0fa941311bf5fc0a29d498" dependencies = [ "async-trait", "beef", @@ -3148,9 +3148,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2834b6e7f57ce9a4412ed4d6dc95125d2c8612e68f86b9d9a07369164e4198" +checksum = "9841352dbecf4c2ed5dc71698df9f1660262ae4e0b610e968602529bdbcf7b30" dependencies = [ "async-trait", "fnv", @@ -6610,7 +6610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c143348f141cc87aab5b950021bac6145d0e5ae754b0591de23244cee42c9308" dependencies = [ "difflib", - "itertools 0.10.0", + "itertools", "predicates-core", ] diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 8b14f1cbeeb83..a241719fb70f3 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -128,7 +128,7 @@ async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" criterion = { version = "0.3.5", features = [ "async_tokio" ] } tokio = { version = "1.10", features = ["macros", "time"] } -jsonrpsee-ws-client = { version = "0.3.0", default-features = false, features = ["tokio1"] } +jsonrpsee-ws-client = { version = "0.3.1", default-features = false, features = ["tokio1"] } wait-timeout = "0.2" remote-externalities = { path = "../../../utils/frame/remote-externalities" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 1fbe1a7ea1d82..e1fffcfd567a0 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee-ws-client = { version = "0.3.0", default-features = false, features = [ +jsonrpsee-ws-client = { version = "0.3.1", default-features = false, features = [ "tokio1", ]} jsonrpsee-proc-macros = "0.3.1" diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 11b899db4ca47..b20915335b976 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -31,6 +31,6 @@ sp-externalities = { version = "0.10.0-dev", path = "../../../../primitives/exte sp-version = { version = "4.0.0-dev", path = "../../../../primitives/version" } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } -jsonrpsee-ws-client = { version = "0.3.0", default-features = false, features = [ +jsonrpsee-ws-client = { version = "0.3.1", default-features = false, features = [ "tokio1", ]} From d0f6c1c60da22e04dd25c2eca46ebfe6f1571af0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Oct 2021 09:40:16 +0000 Subject: [PATCH 0100/1472] Bump regex from 1.4.3 to 1.5.4 (#9969) Bumps [regex](https://github.com/rust-lang/regex) from 1.4.3 to 1.5.4. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.4.3...1.5.4) --- updated-dependencies: - dependency-name: regex 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 | 13 ++++++------- client/cli/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2bae84429d19c..1e71c25da9ac2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,9 +75,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] @@ -7191,14 +7191,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.4.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] @@ -7213,9 +7212,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.22" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "region" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 963d5b3d0a905..ee72958f74d89 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.11" -regex = "1.4.2" +regex = "1.5.4" tokio = { version = "1.10", features = [ "signal", "rt-multi-thread" ] } futures = "0.3.9" fdlimit = "0.2.1" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 2d05f80be42b4..5dfa3efa779e3 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -20,7 +20,7 @@ lazy_static = "1.4.0" log = { version = "0.4.8" } once_cell = "1.8.0" parking_lot = "0.11.1" -regex = "1.4.2" +regex = "1.5.4" rustc-hash = "1.1.0" serde = "1.0.126" thiserror = "1.0.21" diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 9727d1e4f2785..902aa2f655e2c 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -34,7 +34,7 @@ base58 = { version = "0.1.0", optional = true } rand = { version = "0.7.3", optional = true, features = ["small_rng"] } substrate-bip39 = { version = "0.4.2", optional = true } tiny-bip39 = { version = "0.8.2", optional = true } -regex = { version = "1.4.2", optional = true } +regex = { version = "1.5.4", optional = true } num-traits = { version = "0.2.8", default-features = false } zeroize = { version = "1.4.2", default-features = false } secrecy = { version = "0.8.0", default-features = false } From 0e220090f61233db76bb2f705849e1773b62498c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 8 Oct 2021 12:05:07 +0200 Subject: [PATCH 0101/1472] Use correct db path for parity-db (#9971) This was overseen in: https://github.com/paritytech/substrate/pull/9500 --- client/cli/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 59fc6bd438a1c..e83cf07449e28 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -229,7 +229,7 @@ pub trait CliConfiguration: Sized { let paritydb_path = base_path.join("paritydb").join(role_dir); Ok(match database { Database::RocksDb => DatabaseSource::RocksDb { path: rocksdb_path, cache_size }, - Database::ParityDb => DatabaseSource::ParityDb { path: rocksdb_path }, + Database::ParityDb => DatabaseSource::ParityDb { path: paritydb_path }, Database::Auto => DatabaseSource::Auto { paritydb_path, rocksdb_path, cache_size }, }) } From 829133f5510e95fe7a9b235fa0f439114d84f1bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Oct 2021 11:18:05 +0000 Subject: [PATCH 0102/1472] Bump assert_cmd from 2.0.1 to 2.0.2 (#9972) Bumps [assert_cmd](https://github.com/assert-rs/assert_cmd) from 2.0.1 to 2.0.2. - [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.1...v2.0.2) --- 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 | 4 ++-- bin/node/cli/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e71c25da9ac2..a3cc547dfa4e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,9 +156,9 @@ checksum = "9d6e24d2cce90c53b948c46271bfb053e4bdc2db9b5d3f65e20f8cf28a1b7fc3" [[package]] name = "assert_cmd" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b800c4403e8105d959595e1f88119e78bc12bc874c4336973658b648a746ba93" +checksum = "e996dc7940838b7ef1096b882e29ec30a3149a3a443cdc8dba19ed382eca1fe2" dependencies = [ "bstr", "doc-comment", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index a241719fb70f3..f08d94c0399a7 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -119,7 +119,7 @@ sc-service-test = { version = "2.0.0", path = "../../../client/service/test" } sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } futures = "0.3.16" tempfile = "3.1.0" -assert_cmd = "2.0.1" +assert_cmd = "2.0.2" nix = "0.19" serde_json = "1.0" regex = "1" From b535922ae71c8cd68741ed26d042ba159725fddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 8 Oct 2021 13:46:08 +0200 Subject: [PATCH 0103/1472] Disable log reloading by default (#9966) * Disable log reloading by default This disables the log reloading that was enabled by default. The problem is that the log reload implementation of `tracing` is using a lock to make the layer replaceable. This lock needs to be locked every time we need to check if a particular target is enabled (assuming the log level is high enough). This kills the performance when for example `sometarget=trace` logging is enabled. * :facepalm: * Remove unused parameter * Fix test * Fix --- bin/node/cli/benches/transaction_pool.rs | 1 - client/cli/src/config.rs | 9 ++++----- client/cli/src/params/shared_params.rs | 18 ++++++++++-------- client/rpc/src/system/tests.rs | 5 ++++- client/service/src/config.rs | 2 -- client/service/test/src/lib.rs | 1 - client/tracing/src/logging/mod.rs | 2 +- test-utils/test-runner/src/utils.rs | 1 - 8 files changed, 19 insertions(+), 20 deletions(-) diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index c435012e9f86f..3b0ee26d7d597 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -99,7 +99,6 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { base_path: Some(base_path), informant_output_format: Default::default(), wasm_runtime_overrides: None, - disable_log_reloading: false, }; node_cli::service::new_full_base(config, |_, _| ()).expect("Creates node") diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index e83cf07449e28..f79405bd6132a 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -522,7 +522,6 @@ pub trait CliConfiguration: Sized { dev_key_seed: self.dev_key_seed(is_dev)?, tracing_targets: self.tracing_targets()?, tracing_receiver: self.tracing_receiver()?, - disable_log_reloading: self.is_log_filter_reloading_disabled()?, chain_spec, max_runtime_instances, announce_block: self.announce_block()?, @@ -542,9 +541,9 @@ pub trait CliConfiguration: Sized { Ok(self.shared_params().log_filters().join(",")) } - /// Is log reloading disabled (enabled by default) - fn is_log_filter_reloading_disabled(&self) -> Result { - Ok(self.shared_params().is_log_filter_reloading_disabled()) + /// Is log reloading enabled? + fn enable_log_reloading(&self) -> Result { + Ok(self.shared_params().enable_log_reloading()) } /// Should the log color output be disabled? @@ -563,7 +562,7 @@ pub trait CliConfiguration: Sized { sp_panic_handler::set(&C::support_url(), &C::impl_version()); let mut logger = LoggerBuilder::new(self.log_filters()?); - logger.with_log_reloading(!self.is_log_filter_reloading_disabled()?); + logger.with_log_reloading(self.enable_log_reloading()?); if let Some(tracing_targets) = self.tracing_targets()? { let tracing_receiver = self.tracing_receiver()?; diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 41472387d2639..8f22070800fc0 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -50,13 +50,15 @@ pub struct SharedParams { #[structopt(long)] pub disable_log_color: bool, - /// Disable feature to dynamically update and reload the log filter. + /// Enable feature to dynamically update and reload the log filter. + /// + /// Be aware that enabling this feature can lead to a performance decrease up to factor six or + /// more. Depending on the global logging level the performance decrease changes. /// - /// By default this feature is enabled, however it leads to a small performance decrease. /// The `system_addLogFilter` and `system_resetLogFilter` RPCs will have no effect with this - /// option set. - #[structopt(long = "disable-log-reloading")] - pub disable_log_reloading: bool, + /// option not being set. + #[structopt(long)] + pub enable_log_reloading: bool, /// Sets a custom profiling filter. Syntax is the same as for logging: = #[structopt(long = "tracing-targets", value_name = "TARGETS")] @@ -107,9 +109,9 @@ impl SharedParams { self.disable_log_color } - /// Is log reloading disabled - pub fn is_log_filter_reloading_disabled(&self) -> bool { - self.disable_log_reloading + /// Is log reloading enabled + pub fn enable_log_reloading(&self) -> bool { + self.enable_log_reloading } /// Receiver to process tracing messages. diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index 14997545031df..c64449ff13aa2 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -308,7 +308,10 @@ fn test_add_reset_log_filter() { // Enter log generation / filter reload if std::env::var("TEST_LOG_FILTER").is_ok() { - sc_tracing::logging::LoggerBuilder::new("test_before_add=debug").init().unwrap(); + let mut builder = sc_tracing::logging::LoggerBuilder::new("test_before_add=debug"); + builder.with_log_reloading(true); + builder.init().unwrap(); + for line in std::io::stdin().lock().lines() { let line = line.expect("Failed to read bytes"); if line.contains("add_reload") { diff --git a/client/service/src/config.rs b/client/service/src/config.rs index a98a34b473cee..b4f6bf70e05b0 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -118,8 +118,6 @@ pub struct Configuration { pub dev_key_seed: Option, /// Tracing targets pub tracing_targets: Option, - /// Is log filter reloading disabled - pub disable_log_reloading: bool, /// Tracing receiver pub tracing_receiver: sc_tracing::TracingReceiver, /// The size of the instances cache. diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 8000c536cdf93..d85ad8d36111b 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -274,7 +274,6 @@ fn node_config< announce_block: true, base_path: Some(BasePath::new(root)), informant_output_format: Default::default(), - disable_log_reloading: false, } } diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index dd0f7a5d8ae49..c6a4f070176e8 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -197,7 +197,7 @@ impl LoggerBuilder { Self { directives: directives.into(), profiling: None, - log_reloading: true, + log_reloading: false, force_colors: None, } } diff --git a/test-utils/test-runner/src/utils.rs b/test-utils/test-runner/src/utils.rs index 8e8c84e6b4f8a..3ab77af96c16c 100644 --- a/test-utils/test-runner/src/utils.rs +++ b/test-utils/test-runner/src/utils.rs @@ -108,7 +108,6 @@ pub fn default_config(tokio_handle: Handle, mut chain_spec: Box) base_path: Some(base_path), wasm_runtime_overrides: None, informant_output_format, - disable_log_reloading: false, keystore_remote: None, keep_blocks: KeepBlocks::All, state_pruning: Default::default(), From 66fd76181742a1fa27b4ab5c41eb15d9765e6774 Mon Sep 17 00:00:00 2001 From: Andronik Ordian Date: Fri, 8 Oct 2021 17:31:18 +0200 Subject: [PATCH 0104/1472] NetworkService: change `remove_from_peers_set` to accept `PeerId`s (#9964) * NetworkService: expose split_multiaddr_and_peer_id * Revert "NetworkService: expose split_multiaddr_and_peer_id" This reverts commit 47b9a0d57c3617e64d01c449afca8896bd4bb6b6. * change remove_from_peer_set to accets PeerIds * fixes * try fixing it * try fixing it again * FMT * revert me * Revert "revert me" This reverts commit 1ea34f473f1aedc8b3e6e888d1ad2e1b45eaa1e0. --- client/network-gossip/src/lib.rs | 11 +--------- client/network/src/service.rs | 34 ++++-------------------------- client/network/src/transactions.rs | 9 ++------ 3 files changed, 7 insertions(+), 47 deletions(-) diff --git a/client/network-gossip/src/lib.rs b/client/network-gossip/src/lib.rs index 55c2fc820637e..5dc40471f138f 100644 --- a/client/network-gossip/src/lib.rs +++ b/client/network-gossip/src/lib.rs @@ -123,16 +123,7 @@ impl Network for Arc> { } fn remove_set_reserved(&self, who: PeerId, protocol: Cow<'static, str>) { - let addr = - iter::once(multiaddr::Protocol::P2p(who.into())).collect::(); - let result = NetworkService::remove_peers_from_reserved_set( - self, - protocol, - iter::once(addr).collect(), - ); - if let Err(err) = result { - log::error!(target: "gossip", "remove_set_reserved failed: {}", err); - } + NetworkService::remove_peers_from_reserved_set(self, protocol, iter::once(who).collect()); } fn disconnect_peer(&self, who: PeerId, protocol: Cow<'static, str>) { diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 72b382c990543..be19b44f3a59a 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -1164,25 +1164,12 @@ impl NetworkService { } /// Remove peers from a peer set. - /// - /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. - /// - /// Returns an `Err` if one of the given addresses is invalid or contains an - /// invalid peer ID (which includes the local peer ID). - // NOTE: technically, this function only needs `Vec`, but we use `Multiaddr` here for - // convenience. - pub fn remove_peers_from_reserved_set( - &self, - protocol: Cow<'static, str>, - peers: HashSet, - ) -> Result<(), String> { - let peers = self.split_multiaddr_and_peer_id(peers)?; - for (peer_id, _) in peers.into_iter() { + pub fn remove_peers_from_reserved_set(&self, protocol: Cow<'static, str>, peers: Vec) { + for peer_id in peers.into_iter() { let _ = self .to_worker .unbounded_send(ServiceToWorkerMsg::RemoveSetReserved(protocol.clone(), peer_id)); } - Ok(()) } /// Configure an explicit fork sync request. @@ -1233,25 +1220,12 @@ impl NetworkService { /// Remove peers from a peer set. /// /// If we currently have an open substream with this peer, it will soon be closed. - /// - /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. - /// - /// Returns an `Err` if one of the given addresses is invalid or contains an - /// invalid peer ID (which includes the local peer ID). - // NOTE: technically, this function only needs `Vec`, but we use `Multiaddr` here for - // convenience. - pub fn remove_from_peers_set( - &self, - protocol: Cow<'static, str>, - peers: HashSet, - ) -> Result<(), String> { - let peers = self.split_multiaddr_and_peer_id(peers)?; - for (peer_id, _) in peers.into_iter() { + pub fn remove_from_peers_set(&self, protocol: Cow<'static, str>, peers: Vec) { + for peer_id in peers.into_iter() { let _ = self .to_worker .unbounded_send(ServiceToWorkerMsg::RemoveFromPeersSet(protocol.clone(), peer_id)); } - Ok(()) } /// Returns the number of peers we're connected to. diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 9565466ea1c07..99350f603a375 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -317,15 +317,10 @@ impl TransactionsHandler { } }, Event::SyncDisconnected { remote } => { - let addr = iter::once(multiaddr::Protocol::P2p(remote.into())) - .collect::(); - let result = self.service.remove_peers_from_reserved_set( + self.service.remove_peers_from_reserved_set( self.protocol_name.clone(), - iter::once(addr).collect(), + iter::once(remote).collect(), ); - if let Err(err) = result { - log::error!(target: "sync", "Removing reserved peer failed: {}", err); - } }, Event::NotificationStreamOpened { remote, protocol, role, .. } From efd3f7f301b526c59a616a59fe1139fe7bfb210e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 8 Oct 2021 23:54:46 +0200 Subject: [PATCH 0105/1472] Remove unused deps from `sp-tracing` (#9979) --- Cargo.lock | 48 ----------------------------------- primitives/tracing/Cargo.toml | 12 --------- 2 files changed, 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3cc547dfa4e7..320501b0585ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1771,15 +1771,6 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b91989ae21441195d7d9b9993a2f9295c7e1a8c96255d8b729accddc124797" -[[package]] -name = "erased-serde" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0465971a8cc1fa2455c8465aaa377131e1f1cf4983280f474a13e68793aa770c" -dependencies = [ - "serde", -] - [[package]] name = "errno" version = "0.2.7" @@ -6284,16 +6275,6 @@ dependencies = [ "rustc_version 0.2.3", ] -[[package]] -name = "parking_lot" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" -dependencies = [ - "lock_api 0.3.4", - "parking_lot_core 0.7.2", -] - [[package]] name = "parking_lot" version = "0.11.1" @@ -6320,20 +6301,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "parking_lot_core" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" -dependencies = [ - "cfg-if 0.1.10", - "cloudabi", - "libc", - "redox_syscall 0.1.57", - "smallvec 1.7.0", - "winapi 0.3.9", -] - [[package]] name = "parking_lot_core" version = "0.8.3" @@ -8931,15 +8898,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -[[package]] -name = "slog" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" -dependencies = [ - "erased-serde", -] - [[package]] name = "smallvec" version = "0.6.14" @@ -9734,13 +9692,7 @@ dependencies = [ name = "sp-tracing" version = "4.0.0-dev" dependencies = [ - "erased-serde", - "log 0.4.14", "parity-scale-codec", - "parking_lot 0.10.2", - "serde", - "serde_json", - "slog", "sp-std", "tracing", "tracing-core", diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index ebcddb1477d34..806205dae8ddb 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -24,15 +24,9 @@ codec = { version = "2.0.0", package = "parity-scale-codec", default-features = ] } tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.17", default-features = false } -log = { version = "0.4.8", optional = true } tracing-subscriber = { version = "0.2.19", optional = true, features = [ "tracing-log", ] } -parking_lot = { version = "0.10.0", optional = true } -erased-serde = { version = "0.3.9", optional = true } -serde = { version = "1.0.126", optional = true } -serde_json = { version = "1.0.68", optional = true } -slog = { version = "2.5.2", features = ["nested-values"], optional = true } [features] default = ["std"] @@ -43,11 +37,5 @@ std = [ "tracing-core/std", "codec/std", "sp-std/std", - "log", "tracing-subscriber", - "parking_lot", - "erased-serde", - "serde", - "serde_json", - "slog", ] From 0e0cdd84227bde26aa2825cc315e3c1317775a8d Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Sat, 9 Oct 2021 00:16:27 -0600 Subject: [PATCH 0106/1472] add note on `--dev` behavior (#9953) * add note on `--dev` behavior * Update client/cli/src/params/shared_params.rs * Update client/cli/src/params/shared_params.rs * clippy fmt * Update client/cli/src/params/shared_params.rs Co-authored-by: Alexander Popiak * Update client/cli/src/params/shared_params.rs Co-authored-by: adoerr <0xad@gmx.net> Co-authored-by: Alexander Popiak --- client/cli/src/params/shared_params.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 8f22070800fc0..58aabb3148dd2 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -32,6 +32,9 @@ pub struct SharedParams { pub chain: Option, /// Specify the development chain. + /// + /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, + /// `--alice`, and `--tmp` flags, unless explicitly overridden. #[structopt(long, conflicts_with_all = &["chain"])] pub dev: bool, From bdf1788e9f37a51da97f7a1df2359a54022e85f0 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Sat, 9 Oct 2021 21:42:15 +0800 Subject: [PATCH 0107/1472] add TypeInfo for DispatchTime (#9987) --- frame/support/src/traits/schedule.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index a4a4f9c03ab12..19f50a93c0681 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -18,6 +18,7 @@ //! Traits and associated utilities for scheduling dispatchables in FRAME. use codec::{Codec, Decode, Encode, EncodeLike}; +use scale_info::TypeInfo; use sp_runtime::{DispatchError, RuntimeDebug}; use sp_std::{fmt::Debug, prelude::*}; @@ -31,7 +32,7 @@ pub type Period = (BlockNumber, u32); pub type Priority = u8; /// The dispatch time of a scheduled task. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub enum DispatchTime { /// At specified block. At(BlockNumber), From 13c30b92fdfe3d04c0e1ef517458939767780967 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Oct 2021 14:23:57 +0000 Subject: [PATCH 0108/1472] Bump hex-literal from 0.3.1 to 0.3.3 (#9974) Bumps [hex-literal](https://github.com/RustCrypto/utils) from 0.3.1 to 0.3.3. - [Release notes](https://github.com/RustCrypto/utils/releases) - [Commits](https://github.com/RustCrypto/utils/compare/hex-literal-v0.3.1...hex-literal-v0.3.3) --- 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 | 4 ++-- bin/node-template/runtime/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 2 +- frame/executive/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 320501b0585ea..a1610fa57bc28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2586,9 +2586,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-literal" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5af1f635ef1bc545d78392b136bfe1c9809e029023c84a3638a864a10b8819c8" +checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b" [[package]] name = "hex_fmt" diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 081e458b18e08..3179a2cc4ff53 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -45,7 +45,7 @@ pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", default-fe # Used for runtime benchmarking frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/benchmarking", optional = true } frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system/benchmarking", optional = true } -hex-literal = { version = "0.3.1", optional = true } +hex-literal = { version = "0.3.3", optional = true } pallet-template = { version = "3.0.0", default-features = false, path = "../pallets/template" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index f08d94c0399a7..a92c7a185b7ad 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -37,7 +37,7 @@ crate-type = ["cdylib", "rlib"] codec = { package = "parity-scale-codec", version = "2.0.0" } serde = { version = "1.0.126", features = ["derive"] } futures = "0.3.16" -hex-literal = "0.3.1" +hex-literal = "0.3.3" log = "0.4.8" rand = "0.7.2" structopt = { version = "0.3.8", optional = true } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index d434be8f3c609..b4e84aafec132 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } static_assertions = "1.1.0" -hex-literal = { version = "0.3.1", optional = true } +hex-literal = { version = "0.3.3", optional = true } log = { version = "0.4.14", default-features = false } # primitives diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index b7eb31a37593f..eeea57d839808 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -36,7 +36,7 @@ libsecp256k1 = "0.6" [dev-dependencies] wat = "1.0" -hex-literal = "0.3.1" +hex-literal = "0.3.3" sc-runtime-test = { version = "2.0.0", path = "runtime-test" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 9e66e9ca381d3..d267d2535f8c2 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] hex = "0.4" -hex-literal = "0.3.1" +hex-literal = "0.3.3" tempfile = "3.1.0" tokio = { version = "1.10.0", features = ["time"] } log = "0.4.8" diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index ea690d966c979..6a605707caa8b 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -28,7 +28,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys log = { version = "0.4.14", default-features = false } [dev-dependencies] -hex-literal = "0.3.1" +hex-literal = "0.3.3" [features] default = ["std"] diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 1abbf50e6a4c4..15c8a1bd14f1e 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -26,7 +26,7 @@ sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primiti sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } [dev-dependencies] -hex-literal = "0.3.1" +hex-literal = "0.3.3" sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index a4ebd5cfbc876..9daf706b0ce33 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.126", optional = true } -hex-literal = { version = "0.3.1", optional = true } +hex-literal = { version = "0.3.3", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 902aa2f655e2c..31223ff1ccf76 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -71,7 +71,7 @@ sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = [dev-dependencies] sp-serializer = { version = "3.0.0", path = "../serializer" } -hex-literal = "0.3.1" +hex-literal = "0.3.3" rand = "0.7.2" criterion = "0.3.3" serde_json = "1.0" diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index d62b598fdc3a3..bafe34bbd5afd 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -32,7 +32,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } tracing = { version = "0.1.29", optional = true } [dev-dependencies] -hex-literal = "0.3.1" +hex-literal = "0.3.3" sp-runtime = { version = "4.0.0-dev", path = "../runtime" } pretty_assertions = "1.0.0" rand = "0.7.2" diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 5a2de4f16f9a4..297040d09eecf 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -31,7 +31,7 @@ sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } trie-bench = "0.28.0" trie-standardmap = "0.15.2" criterion = "0.3.3" -hex-literal = "0.3.1" +hex-literal = "0.3.3" sp-runtime = { version = "4.0.0-dev", path = "../runtime" } [features] From ecc14d87afde4bf59bbc7c57945d7f8293a4bfee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Oct 2021 04:25:52 +0000 Subject: [PATCH 0109/1472] Bump quote from 1.0.9 to 1.0.10 (#9980) Bumps [quote](https://github.com/dtolnay/quote) from 1.0.9 to 1.0.10. - [Release notes](https://github.com/dtolnay/quote/releases) - [Commits](https://github.com/dtolnay/quote/compare/1.0.9...1.0.10) --- updated-dependencies: - dependency-name: quote 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/chain-spec/derive/Cargo.toml | 2 +- client/tracing/proc-macro/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/tools/Cargo.toml | 2 +- frame/support/procedural/tools/derive/Cargo.toml | 2 +- primitives/api/proc-macro/Cargo.toml | 2 +- primitives/debug-derive/Cargo.toml | 2 +- primitives/runtime-interface/proc-macro/Cargo.toml | 2 +- primitives/version/proc-macro/Cargo.toml | 2 +- test-utils/derive/Cargo.toml | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1610fa57bc28..93635b79c86c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6833,9 +6833,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index b210fa1320e04..76525ebf462ad 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] proc-macro-crate = "1.0.0" proc-macro2 = "1.0.29" -quote = "1.0.3" +quote = "1.0.10" syn = "1.0.58" [dev-dependencies] diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index 002370b515f28..e13efdfcc5875 100644 --- a/client/tracing/proc-macro/Cargo.toml +++ b/client/tracing/proc-macro/Cargo.toml @@ -17,5 +17,5 @@ proc-macro = true [dependencies] proc-macro-crate = "1.0.0" proc-macro2 = "1.0.29" -quote = { version = "1.0.3", features = ["proc-macro"] } +quote = { version = "1.0.10", features = ["proc-macro"] } syn = { version = "1.0.58", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index 4cbc2473cb526..d7f00d4f70f98 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -16,7 +16,7 @@ proc-macro = true [dependencies] syn = { version = "1.0.58", features = ["full", "visit"] } -quote = "1.0.3" +quote = "1.0.10" proc-macro2 = "1.0.29" proc-macro-crate = "1.0.0" diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index e1ff6dcf39b7e..ce2e9907add5e 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } proc-macro2 = "1.0.29" -quote = "1.0.3" +quote = "1.0.10" Inflector = "0.11.4" syn = { version = "1.0.58", features = ["full"] } diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index ee59f53287efa..106d552b177ab 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -14,6 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" } proc-macro2 = "1.0.29" -quote = "1.0.3" +quote = "1.0.10" syn = { version = "1.0.58", features = ["full", "visit", "extra-traits"] } proc-macro-crate = "1.0.0" diff --git a/frame/support/procedural/tools/derive/Cargo.toml b/frame/support/procedural/tools/derive/Cargo.toml index 12ec6a69f3967..4e15519c6ed5b 100644 --- a/frame/support/procedural/tools/derive/Cargo.toml +++ b/frame/support/procedural/tools/derive/Cargo.toml @@ -16,5 +16,5 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.29" -quote = { version = "1.0.3", features = ["proc-macro"] } +quote = { version = "1.0.10", features = ["proc-macro"] } syn = { version = "1.0.58", features = ["proc-macro" ,"full", "extra-traits", "parsing"] } diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index d5909967ac5a4..1066b38b55a25 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -quote = "1.0.3" +quote = "1.0.10" syn = { version = "1.0.58", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.29" blake2-rfc = { version = "0.2.18", default-features = false } diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml index 0d3ba805100c4..0f180dade0252 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -quote = "1.0.3" +quote = "1.0.10" syn = "1.0.58" proc-macro2 = "1.0" diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 1eb3bdd9039d9..0cd709083e369 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] syn = { version = "1.0.58", features = ["full", "visit", "fold", "extra-traits"] } -quote = "1.0.3" +quote = "1.0.10" proc-macro2 = "1.0.29" Inflector = "0.11.4" proc-macro-crate = "1.0.0" diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index c3c801431434a..33f780169fae6 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -quote = "1.0.3" +quote = "1.0.10" syn = { version = "1.0.58", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.29" codec = { package = "parity-scale-codec", version = "2.0.0", features = [ "derive" ] } diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index 545e8cf332618..49eaca4cd982a 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/paritytech/substrate/" description = "Substrate test utilities macros" [dependencies] -quote = "1.0.6" +quote = "1.0.10" syn = { version = "1.0.58", features = ["full"] } proc-macro-crate = "1.0.0" proc-macro2 = "1.0.29" From 582db90ce647d888af62c7c96772f3305a36ee74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Oct 2021 12:23:02 +0000 Subject: [PATCH 0110/1472] Bump syn from 1.0.76 to 1.0.80 (#9995) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.76 to 1.0.80. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.76...1.0.80) --- 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 | 4 ++-- client/chain-spec/derive/Cargo.toml | 2 +- client/tracing/proc-macro/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/tools/Cargo.toml | 2 +- frame/support/procedural/tools/derive/Cargo.toml | 2 +- primitives/api/proc-macro/Cargo.toml | 2 +- primitives/debug-derive/Cargo.toml | 2 +- primitives/npos-elections/solution-type/Cargo.toml | 2 +- primitives/runtime-interface/proc-macro/Cargo.toml | 2 +- primitives/version/proc-macro/Cargo.toml | 2 +- test-utils/derive/Cargo.toml | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93635b79c86c5..7af65c8bcf793 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10143,9 +10143,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.76" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" +checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" dependencies = [ "proc-macro2", "quote", diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index 76525ebf462ad..89a51d95079a0 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -18,6 +18,6 @@ proc-macro = true proc-macro-crate = "1.0.0" proc-macro2 = "1.0.29" quote = "1.0.10" -syn = "1.0.58" +syn = "1.0.80" [dev-dependencies] diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index e13efdfcc5875..42a0c739cd522 100644 --- a/client/tracing/proc-macro/Cargo.toml +++ b/client/tracing/proc-macro/Cargo.toml @@ -18,4 +18,4 @@ proc-macro = true proc-macro-crate = "1.0.0" proc-macro2 = "1.0.29" quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.58", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "1.0.80", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index d7f00d4f70f98..aaa45e623109f 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.58", features = ["full", "visit"] } +syn = { version = "1.0.80", features = ["full", "visit"] } quote = "1.0.10" proc-macro2 = "1.0.29" proc-macro-crate = "1.0.0" diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index ce2e9907add5e..6113c6613be03 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -19,7 +19,7 @@ frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } proc-macro2 = "1.0.29" quote = "1.0.10" Inflector = "0.11.4" -syn = { version = "1.0.58", features = ["full"] } +syn = { version = "1.0.80", features = ["full"] } [features] default = ["std"] diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index 106d552b177ab..d6894b78133e4 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -15,5 +15,5 @@ targets = ["x86_64-unknown-linux-gnu"] frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" } proc-macro2 = "1.0.29" quote = "1.0.10" -syn = { version = "1.0.58", features = ["full", "visit", "extra-traits"] } +syn = { version = "1.0.80", features = ["full", "visit", "extra-traits"] } proc-macro-crate = "1.0.0" diff --git a/frame/support/procedural/tools/derive/Cargo.toml b/frame/support/procedural/tools/derive/Cargo.toml index 4e15519c6ed5b..14c56b1b819a3 100644 --- a/frame/support/procedural/tools/derive/Cargo.toml +++ b/frame/support/procedural/tools/derive/Cargo.toml @@ -17,4 +17,4 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.29" quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.58", features = ["proc-macro" ,"full", "extra-traits", "parsing"] } +syn = { version = "1.0.80", features = ["proc-macro" ,"full", "extra-traits", "parsing"] } diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index 1066b38b55a25..dc0f2bd98d468 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = { version = "1.0.58", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "1.0.80", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.29" blake2-rfc = { version = "0.2.18", default-features = false } proc-macro-crate = "1.0.0" diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml index 0f180dade0252..2e5ef93e41f5e 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = "1.0.58" +syn = "1.0.80" proc-macro2 = "1.0" [features] diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index cbe6750266f01..5cbf0b6481816 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.58", features = ["full", "visit"] } +syn = { version = "1.0.80", features = ["full", "visit"] } quote = "1.0" proc-macro2 = "1.0.29" proc-macro-crate = "1.0.0" diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 0cd709083e369..1f77caf7e4160 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.58", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "1.0.80", features = ["full", "visit", "fold", "extra-traits"] } quote = "1.0.10" proc-macro2 = "1.0.29" Inflector = "0.11.4" diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index 33f780169fae6..4984961fb9f77 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = { version = "1.0.58", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "1.0.80", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.29" codec = { package = "parity-scale-codec", version = "2.0.0", features = [ "derive" ] } diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index 49eaca4cd982a..68bcbdaa4700f 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -10,7 +10,7 @@ description = "Substrate test utilities macros" [dependencies] quote = "1.0.10" -syn = { version = "1.0.58", features = ["full"] } +syn = { version = "1.0.80", features = ["full"] } proc-macro-crate = "1.0.0" proc-macro2 = "1.0.29" From 85d881bfc28a6926c2f7c1d0fa3a7b84d2cac06d Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 11 Oct 2021 15:46:31 +0200 Subject: [PATCH 0111/1472] Add quick simnet tests to .gitlab-ci.yml (#9959) * remove spaces * add simnet quick test * debug simnet test * add jobs for quick simnet tests * fix typo * test simnet-quick * remove debug * fix ci * change tag for simnet tests * Add new line to readme --- .gitlab-ci.yml | 69 +++++++++++++++++++++++++++++++++++++++++++++++--- README.md | 1 + 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0d150d96deedc..ae6a81611f2dd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,6 +45,7 @@ variables: &default-vars VAULT_SERVER_URL: "https://vault.parity-mgmt-vault.parity.io" VAULT_AUTH_PATH: "gitlab-parity-io-jwt" VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" + SIMNET_FEATURES_PATH: "simnet_tests/tests" default: cache: {} @@ -57,6 +58,14 @@ default: paths: - artifacts/ +.collect-artifacts-short: &collect-artifacts-short + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + when: on_success + expire_in: 3 hours + paths: + - artifacts/ + .kubernetes-env: &kubernetes-env retry: max: 2 @@ -188,13 +197,13 @@ default: file: false AWX_TOKEN: vault: cicd/gitlab/$CI_PROJECT_PATH/AWX_TOKEN@kv - file: false + file: false CRATES_TOKEN: vault: cicd/gitlab/$CI_PROJECT_PATH/CRATES_TOKEN@kv file: false DOCKER_CHAOS_TOKEN: vault: cicd/gitlab/$CI_PROJECT_PATH/DOCKER_CHAOS_TOKEN@kv - file: false + file: false DOCKER_CHAOS_USER: vault: cicd/gitlab/$CI_PROJECT_PATH/DOCKER_CHAOS_USER@kv file: false @@ -580,6 +589,12 @@ build-linux-substrate: &build-binary - cp -r .maintain/docker/substrate.Dockerfile ./artifacts/substrate/ - sccache -s +#Build binary for simnet quick tests. +build-linux-substrate-simnet: + <<: *build-binary + <<: *collect-artifacts-short + <<: *test-refs-no-trigger-prs-only + build-linux-subkey: &build-subkey stage: build <<: *collect-artifacts @@ -689,6 +704,25 @@ publish-docker-substrate: # https://docs.gitlab.com/ee/ci/multi_project_pipelines.html#with-variable-inheritance dotenv: ./artifacts/substrate/build.env +#publish artifact for quick simnet tests +publish-docker-substrate-simnet: + stage: publish + <<: *build-push-docker-image + <<: *test-refs-no-trigger-prs-only + needs: + - job: build-linux-substrate-simnet + artifacts: true + variables: + <<: *default-vars + GIT_STRATEGY: none + DOCKERFILE: $PRODUCT.Dockerfile + PRODUCT: substrate + IMAGE_NAME: docker.io/paritypr/$PRODUCT + artifacts: + reports: + # this artifact is used in simnet-tests-quick job + dotenv: ./artifacts/substrate/build.env + publish-docker-subkey: stage: publish <<: *build-push-docker-image @@ -871,7 +905,7 @@ simnet-tests: before_script: - echo "Simnet Tests Config docker.io/paritytech/simnet:${SIMNET_REF} - ${SUBSTRATE_IMAGE_NAME} ${SUBSTRATE_IAMGE_TAG}" + ${SUBSTRATE_IMAGE_NAME} ${SUBSTRATE_IMAGE_TAG}" script: - /home/nonroot/simnet/gurke/scripts/run-test-environment-manager.sh --github-remote-dir="https://github.com/paritytech/substrate/tree/master/simnet_tests" @@ -879,4 +913,31 @@ simnet-tests: --image="${SUBSTRATE_IMAGE_NAME}:${SUBSTRATE_IMAGE_TAG}" retry: 2 tags: - - parity-simnet + - substrate-simnet + +#run quick simnet-tests for each PR +simnet-tests-quick: + stage: deploy + image: docker.io/paritytech/simnet:${SIMNET_REF} + <<: *kubernetes-env + <<: *vault-secrets + <<: *test-refs-no-trigger-prs-only + variables: + SIMNET_FEATURES: "${SIMNET_FEATURES_PATH}/quick" + needs: + - job: publish-docker-substrate-simnet + before_script: + - echo "Simnet Tests Config + docker.io/paritytech/simnet:${SIMNET_REF} + ${SUBSTRATE_IMAGE_NAME} ${SUBSTRATE_IMAGE_TAG}" + script: + - echo "Image=${SUBSTRATE_IMAGE_NAME}:${SUBSTRATE_IMAGE_TAG}" + - echo "Features=${SIMNET_FEATURES}" + - /home/nonroot/simnet/gurke/scripts/run-test-environment-manager.sh + --github-remote-dir="https://github.com/paritytech/substrate/tree/master/simnet_tests" + --config="simnet_tests/configs/default_local_testnet.toml" + --image="${SUBSTRATE_IMAGE_NAME}:${SUBSTRATE_IMAGE_TAG}" + --features="${SIMNET_FEATURES}" + tags: + - substrate-simnet + diff --git a/README.md b/README.md index 6288540548a0d..a4d0b9c683575 100644 --- a/README.md +++ b/README.md @@ -28,3 +28,4 @@ The security policy and procedures can be found in [`docs/SECURITY.md`](docs/SEC The reason for the split-licensing is to ensure that for the vast majority of teams using Substrate to create feature-chains, then all changes can be made entirely in Apache2-licensed code, allowing teams full freedom over what and how they release and giving licensing clarity to commercial teams. In the interests of the community, we require any deeper improvements made to Substrate's core logic (e.g. Substrate's internal consensus, crypto or database code) to be contributed back so everyone can benefit. + From 12b6441ef138303f50fa2fb20895fbf57c8e4735 Mon Sep 17 00:00:00 2001 From: Alexander Popiak Date: Mon, 11 Oct 2021 16:23:10 +0200 Subject: [PATCH 0112/1472] Add Deposit and Withdraw Events to Balances Pallet (#9425) * add Deposit and Withdraw events to balances + add deposit_event() calls where appropriate to signal fund movement + adjust and extend tests * line length * move events to the end to avoid changing indices * bump spec_version * cargo fmt * adjust block import bench to new event count * fix node executor tests * adjust import bench comment * fix typo and formatting * adjust event number * fix copy pasta * fix contracts pallets tests * cargo fmt * WIP fix events in tests * fix offences tests * fix tests * cargo +nightly fmt * fix contracts pallets tests * cargo +nightly fmt * fix offences tests * formatting and compile fixes Co-authored-by: Shawn Tabrizi --- bin/node/bench/src/import.rs | 18 +-- bin/node/executor/tests/basic.rs | 39 +++++++ bin/node/runtime/src/lib.rs | 4 +- frame/balances/src/lib.rs | 38 ++++++- frame/balances/src/tests.rs | 20 +++- frame/balances/src/tests_local.rs | 3 +- frame/balances/src/tests_reentrancy.rs | 15 ++- frame/contracts/src/tests.rs | 5 + frame/offences/benchmarking/src/lib.rs | 152 ++++++++++++++++--------- 9 files changed, 218 insertions(+), 76 deletions(-) diff --git a/bin/node/bench/src/import.rs b/bin/node/bench/src/import.rs index 5bbf1ddf3b73e..da9d0cdaf85b8 100644 --- a/bin/node/bench/src/import.rs +++ b/bin/node/bench/src/import.rs @@ -135,18 +135,20 @@ impl core::Benchmark for ImportBenchmark { .inspect_state(|| { match self.block_type { BlockType::RandomTransfersKeepAlive => { - // should be 5 per signed extrinsic + 1 per unsigned + // should be 7 per signed extrinsic + 1 per unsigned // we have 1 unsigned and the rest are signed in the block - // those 5 events per signed are: - // - new account (RawEvent::NewAccount) as we always transfer fund to - // non-existant account - // - endowed (RawEvent::Endowed) for this new account - // - successful transfer (RawEvent::Transfer) for this transfer operation - // - deposit event for charging transaction fee + // those 7 events per signed are: + // - withdraw (Balances::Withdraw) for charging the transaction fee + // - new account (System::NewAccount) as we always transfer fund to + // non-existent account + // - endowed (Balances::Endowed) for this new account + // - successful transfer (Event::Transfer) for this transfer operation + // - 2x deposit (Balances::Deposit and Treasury::Deposit) for depositing + // the transaction fee into the treasury // - extrinsic success assert_eq!( node_runtime::System::events().len(), - (self.block.extrinsics.len() - 1) * 5 + 1, + (self.block.extrinsics.len() - 1) * 7 + 1, ); }, BlockType::Noop => { diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index c1ab5e5a0fe13..bbb9339189b06 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -385,6 +385,11 @@ fn full_native_block_import_works() { })), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: Event::Balances(pallet_balances::Event::Withdraw(alice().into(), fees)), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: Event::Balances(pallet_balances::Event::Transfer( @@ -394,6 +399,14 @@ fn full_native_block_import_works() { )), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: Event::Balances(pallet_balances::Event::Deposit( + pallet_treasury::Pallet::::account_id(), + fees * 8 / 10, + )), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: Event::Treasury(pallet_treasury::Event::Deposit(fees * 8 / 10)), @@ -439,6 +452,11 @@ fn full_native_block_import_works() { })), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: Event::Balances(pallet_balances::Event::Withdraw(bob().into(), fees)), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: Event::Balances(pallet_balances::Event::Transfer( @@ -448,6 +466,14 @@ fn full_native_block_import_works() { )), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: Event::Balances(pallet_balances::Event::Deposit( + pallet_treasury::Pallet::::account_id(), + fees * 8 / 10, + )), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: Event::Treasury(pallet_treasury::Event::Deposit(fees * 8 / 10)), @@ -461,6 +487,11 @@ fn full_native_block_import_works() { })), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(2), + event: Event::Balances(pallet_balances::Event::Withdraw(alice().into(), fees)), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(2), event: Event::Balances(pallet_balances::Event::Transfer( @@ -470,6 +501,14 @@ fn full_native_block_import_works() { )), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(2), + event: Event::Balances(pallet_balances::Event::Deposit( + pallet_treasury::Pallet::::account_id(), + fees * 8 / 10, + )), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(2), event: Event::Treasury(pallet_treasury::Event::Deposit(fees * 8 / 10)), diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4f620976c3abc..c7920629bf356 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -121,8 +121,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to 0. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 267, - impl_version: 1, + spec_version: 268, + impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, }; diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index afd2331c8e3cf..da8019583c3be 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -463,8 +463,6 @@ pub mod pallet { Transfer(T::AccountId, T::AccountId, T::Balance), /// A balance was set by root. \[who, free, reserved\] BalanceSet(T::AccountId, T::Balance, T::Balance), - /// Some amount was deposited (e.g. for transaction fees). \[who, deposit\] - Deposit(T::AccountId, T::Balance), /// Some balance was reserved (moved from free to reserved). \[who, value\] Reserved(T::AccountId, T::Balance), /// Some balance was unreserved (moved from reserved to free). \[who, value\] @@ -473,6 +471,14 @@ pub mod pallet { /// Final argument indicates the destination balance type. /// \[from, to, balance, destination_status\] ReserveRepatriated(T::AccountId, T::AccountId, T::Balance, Status), + /// Some amount was deposited into the account (e.g. for transaction fees). \[who, + /// deposit\] + Deposit(T::AccountId, T::Balance), + /// Some amount was withdrawn from the account (e.g. for transaction fees). \[who, value\] + Withdraw(T::AccountId, T::Balance), + /// Some amount was removed from the account (e.g. for misbehavior). \[who, + /// amount_slashed\] + Slashed(T::AccountId, T::Balance), } /// Old name generated by `decl_event`. @@ -1103,6 +1109,7 @@ impl, I: 'static> fungible::Mutate for Pallet { Ok(()) })?; TotalIssuance::::mutate(|t| *t += amount); + Self::deposit_event(Event::Deposit(who.clone(), amount)); Ok(()) } @@ -1123,6 +1130,7 @@ impl, I: 'static> fungible::Mutate for Pallet { }, )?; TotalIssuance::::mutate(|t| *t -= actual); + Self::deposit_event(Event::Withdraw(who.clone(), amount)); Ok(actual) } } @@ -1141,7 +1149,10 @@ impl, I: 'static> fungible::Transfer for Pallet impl, I: 'static> fungible::Unbalanced for Pallet { fn set_balance(who: &T::AccountId, amount: Self::Balance) -> DispatchResult { - Self::mutate_account(who, |account| account.free = amount)?; + Self::mutate_account(who, |account| { + account.free = amount; + Self::deposit_event(Event::BalanceSet(who.clone(), account.free, account.reserved)); + })?; Ok(()) } @@ -1583,7 +1594,13 @@ where } }, ) { - Ok(r) => return r, + Ok((imbalance, not_slashed)) => { + Self::deposit_event(Event::Slashed( + who.clone(), + value.saturating_sub(not_slashed), + )); + return (imbalance, not_slashed) + }, Err(_) => (), } } @@ -1608,6 +1625,7 @@ where |account, is_new| -> Result { ensure!(!is_new, Error::::DeadAccount); account.free = account.free.checked_add(&value).ok_or(ArithmeticError::Overflow)?; + Self::deposit_event(Event::Deposit(who.clone(), value)); Ok(PositiveImbalance::new(value)) }, ) @@ -1640,6 +1658,7 @@ where None => return Ok(Self::PositiveImbalance::zero()), }; + Self::deposit_event(Event::Deposit(who.clone(), value)); Ok(PositiveImbalance::new(value)) }, ) @@ -1677,6 +1696,7 @@ where account.free = new_free_account; + Self::deposit_event(Event::Withdraw(who.clone(), value)); Ok(NegativeImbalance::new(value)) }, ) @@ -1709,6 +1729,7 @@ where SignedImbalance::Negative(NegativeImbalance::new(account.free - value)) }; account.free = value; + Self::deposit_event(Event::BalanceSet(who.clone(), account.free, account.reserved)); Ok(imbalance) }, ) @@ -1824,7 +1845,13 @@ where // underflow should never happen, but it if does, there's nothing to be done here. (NegativeImbalance::new(actual), value - actual) }) { - Ok(r) => return r, + Ok((imbalance, not_slashed)) => { + Self::deposit_event(Event::Slashed( + who.clone(), + value.saturating_sub(not_slashed), + )); + return (imbalance, not_slashed) + }, Err(_) => (), } } @@ -1965,6 +1992,7 @@ where // `actual <= to_change` and `to_change <= amount`; qed; reserves[index].amount -= actual; + Self::deposit_event(Event::Slashed(who.clone(), actual)); (imb, value - actual) }, Err(_) => (NegativeImbalance::zero(), value), diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index a08643821eba8..6a6ebc692c34a 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -314,6 +314,7 @@ macro_rules! decl_tests { <$ext_builder>::default().monied(true).build().execute_with(|| { assert_eq!(Balances::total_balance(&1), 10); assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop)); + System::assert_last_event(Event::Balances(crate::Event::Deposit(1, 10))); assert_eq!(Balances::total_balance(&1), 20); assert_eq!(>::get(), 120); }); @@ -341,6 +342,7 @@ macro_rules! decl_tests { fn balance_works() { <$ext_builder>::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 42); + System::assert_has_event(Event::Balances(crate::Event::Deposit(1, 42))); assert_eq!(Balances::free_balance(1), 42); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::total_balance(&1), 42); @@ -435,6 +437,19 @@ macro_rules! decl_tests { }); } + #[test] + fn withdrawing_balance_should_work() { + <$ext_builder>::default().build().execute_with(|| { + let _ = Balances::deposit_creating(&2, 111); + let _ = Balances::withdraw( + &2, 11, WithdrawReasons::TRANSFER, ExistenceRequirement::KeepAlive + ); + System::assert_last_event(Event::Balances(crate::Event::Withdraw(2, 11))); + assert_eq!(Balances::free_balance(2), 100); + assert_eq!(>::get(), 100); + }); + } + #[test] fn slashing_incomplete_balance_should_work() { <$ext_builder>::default().build().execute_with(|| { @@ -749,6 +764,7 @@ macro_rules! decl_tests { [ Event::System(system::Event::KilledAccount(1)), Event::Balances(crate::Event::DustLost(1, 99)), + Event::Balances(crate::Event::Slashed(1, 1)), ] ); }); @@ -777,7 +793,8 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::KilledAccount(1)) + Event::System(system::Event::KilledAccount(1)), + Event::Balances(crate::Event::Slashed(1, 100)), ] ); }); @@ -797,6 +814,7 @@ macro_rules! decl_tests { assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0)); // Account is still alive assert!(System::account_exists(&1)); + System::assert_last_event(Event::Balances(crate::Event::Slashed(1, 900))); // SCENARIO: Slash will kill account because not enough balance left. assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index 1d758ce4e980b..b2113a916caa5 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -173,7 +173,7 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { assert_eq!(res, (NegativeImbalance::new(98), 0)); // no events - assert_eq!(events(), []); + assert_eq!(events(), [Event::Balances(crate::Event::Slashed(1, 98))]); let res = Balances::slash(&1, 1); assert_eq!(res, (NegativeImbalance::new(1), 0)); @@ -183,6 +183,7 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { [ Event::System(system::Event::KilledAccount(1)), Event::Balances(crate::Event::DustLost(1, 1)), + Event::Balances(crate::Event::Slashed(1, 1)), ] ); }); diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 25b8fb34f20ba..9a5ebb003af2c 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -167,11 +167,11 @@ fn transfer_dust_removal_tst1_should_work() { assert_eq!(Balances::free_balance(&1), 1050); // Verify the events - // Number of events expected is 8 - assert_eq!(System::events().len(), 11); + assert_eq!(System::events().len(), 12); System::assert_has_event(Event::Balances(crate::Event::Transfer(2, 3, 450))); System::assert_has_event(Event::Balances(crate::Event::DustLost(2, 50))); + System::assert_has_event(Event::Balances(crate::Event::Deposit(1, 50))); }); } @@ -195,11 +195,11 @@ fn transfer_dust_removal_tst2_should_work() { assert_eq!(Balances::free_balance(&1), 1500); // Verify the events - // Number of events expected is 8 - assert_eq!(System::events().len(), 9); + assert_eq!(System::events().len(), 10); System::assert_has_event(Event::Balances(crate::Event::Transfer(2, 1, 450))); System::assert_has_event(Event::Balances(crate::Event::DustLost(2, 50))); + System::assert_has_event(Event::Balances(crate::Event::Deposit(1, 50))); }); } @@ -232,8 +232,7 @@ fn repatriating_reserved_balance_dust_removal_should_work() { assert_eq!(Balances::free_balance(1), 1500); // Verify the events - // Number of events expected is 10 - assert_eq!(System::events().len(), 10); + assert_eq!(System::events().len(), 11); System::assert_has_event(Event::Balances(crate::Event::ReserveRepatriated( 2, @@ -241,7 +240,7 @@ fn repatriating_reserved_balance_dust_removal_should_work() { 450, Status::Free, ))); - - System::assert_last_event(Event::Balances(crate::Event::DustLost(2, 50))); + System::assert_has_event(Event::Balances(crate::Event::DustLost(2, 50))); + System::assert_last_event(Event::Balances(crate::Event::Deposit(1, 50))); }); } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index b2141ca18b0b1..310c1d4cb2dd9 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -444,6 +444,11 @@ fn instantiate_and_call_and_deposit_event() { assert_eq!( System::events(), vec![ + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Deposit(ALICE, 1_000_000)), + topics: vec![], + }, EventRecord { phase: Phase::Initialization, event: Event::System(frame_system::Event::NewAccount(ALICE.clone())), diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index dde8aa92c2405..c920b0b900dff 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -224,27 +224,49 @@ fn check_events::Event>>(expec .map(|frame_system::EventRecord { event, .. }| event) .collect::>(); let expected = expected.collect::>(); - let lengths = (events.len(), expected.len()); - let length_mismatch = if lengths.0 != lengths.1 { - fn pretty(header: &str, ev: &[D]) { - println!("{}", header); - for (idx, ev) in ev.iter().enumerate() { - println!("\t[{:04}] {:?}", idx, ev); - } + + fn pretty(header: &str, ev: &[D], offset: usize) { + println!("{}", header); + for (idx, ev) in ev.iter().enumerate() { + println!("\t[{:04}] {:?}", idx + offset, ev); } - pretty("--Got:", &events); - pretty("--Expected:", &expected); - format!("Mismatching length. Got: {}, expected: {}", lengths.0, lengths.1) - } else { - Default::default() - }; + } + fn print_events(idx: usize, events: &[D], expected: &[D]) { + let window = 10; + let start = idx.saturating_sub(window / 2); + let end_got = (idx + window / 2).min(events.len()); + pretty("Got(window):", &events[start..end_got], start); + let end_expected = (idx + window / 2).min(expected.len()); + pretty("Expected(window):", &expected[start..end_expected], start); + println!("---------------"); + let start_got = events.len().saturating_sub(window); + pretty("Got(end):", &events[start_got..], start_got); + let start_expected = expected.len().saturating_sub(window); + pretty("Expected(end):", &expected[start_expected..], start_expected); + } + let events_copy = events.clone(); + let expected_copy = expected.clone(); for (idx, (a, b)) in events.into_iter().zip(expected).enumerate() { - assert_eq!(a, b, "Mismatch at: {}. {}", idx, length_mismatch); + if a != b { + print_events(idx, &events_copy, &expected_copy); + println!("Mismatch at: {}", idx); + println!(" Got: {:?}", b); + println!("Expected: {:?}", a); + if events_copy.len() != expected_copy.len() { + println!( + "Mismatching lengths. Got: {}, Expected: {}", + events_copy.len(), + expected_copy.len() + ) + } + panic!("Mismatching events."); + } } - if !length_mismatch.is_empty() { - panic!("{}", length_mismatch); + if events_copy.len() != expected_copy.len() { + print_events(0, &events_copy, &expected_copy); + panic!("Mismatching lengths. Got: {}, Expected: {}", events_copy.len(), expected_copy.len()) } } @@ -288,46 +310,74 @@ benchmarks! { let bond_amount: u32 = UniqueSaturatedInto::::unique_saturated_into(bond_amount::()); let slash_amount = slash_fraction * bond_amount; let reward_amount = slash_amount * (1 + n) / 2; + let reward = reward_amount / r; let slash = |id| core::iter::once( ::Event::from(StakingEvent::::Slashed(id, BalanceOf::::from(slash_amount))) ); + let balance_slash = |id| core::iter::once( + ::Event::from(pallet_balances::Event::::Slashed(id, slash_amount.into())) + ); let chill = |id| core::iter::once( ::Event::from(StakingEvent::::Chilled(id)) ); - let mut slash_events = raw_offenders.into_iter() + let balance_deposit = |id, amount: u32| + ::Event::from(pallet_balances::Event::::Deposit(id, amount.into())); + let mut first = true; + let slash_events = raw_offenders.into_iter() .flat_map(|offender| { - let nom_slashes = offender.nominator_stashes.into_iter().flat_map(|nom| slash(nom)); - chill(offender.stash.clone()) - .chain(slash(offender.stash)) - .chain(nom_slashes) + let nom_slashes = offender.nominator_stashes.into_iter().flat_map(|nom| { + balance_slash(nom.clone()).map(Into::into) + .chain(slash(nom.clone()).map(Into::into)) + }).collect::>(); + + let mut events = chill(offender.stash.clone()).map(Into::into) + .chain(balance_slash(offender.stash.clone()).map(Into::into)) + .chain(slash(offender.stash.clone()).map(Into::into)) + .chain(nom_slashes.into_iter()) + .collect::>(); + + // the first deposit creates endowed events, see `endowed_reward_events` + if first { + first = false; + let mut reward_events = reporters.clone().into_iter() + .flat_map(|reporter| vec![ + balance_deposit(reporter.clone(), reward.into()).into(), + frame_system::Event::::NewAccount(reporter.clone()).into(), + ::Event::from( + pallet_balances::Event::::Endowed(reporter.clone(), reward.into()) + ).into(), + ]) + .collect::>(); + events.append(&mut reward_events); + events.into_iter() + } else { + let mut reward_events = reporters.clone().into_iter() + .map(|reporter| balance_deposit(reporter, reward.into()).into()) + .collect::>(); + events.append(&mut reward_events); + events.into_iter() + } }) .collect::>(); - let reward_events = reporters.into_iter() - .flat_map(|reporter| vec![ - frame_system::Event::::NewAccount(reporter.clone()).into(), - ::Event::from( - pallet_balances::Event::::Endowed(reporter, (reward_amount / r).into()) - ).into() - ]); - - // Rewards are applied after first offender and it's nominators. - // We split after: offender slash + offender chill + nominator slashes. - let slash_rest = slash_events.split_off(2 + n as usize); - // make sure that all slashes have been applied + + #[cfg(test)] - check_events::( - std::iter::empty() - .chain(slash_events.into_iter().map(Into::into)) - .chain(reward_events) - .chain(slash_rest.into_iter().map(Into::into)) - .chain(std::iter::once(::Event::from( - pallet_offences::Event::Offence( - UnresponsivenessOffence::::ID, - 0_u32.to_le_bytes().to_vec(), - ) - ).into())) - ); + { + // In case of error it's useful to see the inputs + println!("Inputs: r: {}, o: {}, n: {}", r, o, n); + // make sure that all slashes have been applied + check_events::( + std::iter::empty() + .chain(slash_events.into_iter().map(Into::into)) + .chain(std::iter::once(::Event::from( + pallet_offences::Event::Offence( + UnresponsivenessOffence::::ID, + 0_u32.to_le_bytes().to_vec(), + ) + ).into())) + ); + } } report_offence_grandpa { @@ -358,10 +408,10 @@ benchmarks! { assert_eq!( System::::event_count(), 0 + 1 // offence - + 2 // reporter (reward + endowment) - + 1 // offenders slashed + + 3 // reporter (reward + endowment) + + 2 // offenders slashed + 1 // offenders chilled - + n // nominators slashed + + 2 * n // nominators slashed ); } @@ -393,10 +443,10 @@ benchmarks! { assert_eq!( System::::event_count(), 0 + 1 // offence - + 2 // reporter (reward + endowment) - + 1 // offenders slashed + + 3 // reporter (reward + endowment) + + 2 // offenders slashed + 1 // offenders chilled - + n // nominators slashed + + 2 * n // nominators slashed ); } From d6a095ad3149b76e8a8cba340d9c295790aa3354 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Oct 2021 15:24:24 +0000 Subject: [PATCH 0113/1472] Bump pin-project from 1.0.5 to 1.0.8 (#9999) Bumps [pin-project](https://github.com/taiki-e/pin-project) from 1.0.5 to 1.0.8. - [Release notes](https://github.com/taiki-e/pin-project/releases) - [Changelog](https://github.com/taiki-e/pin-project/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/pin-project/compare/v1.0.5...v1.0.8) --- updated-dependencies: - dependency-name: pin-project 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 | 30 +++++++++++++++--------------- client/network/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7af65c8bcf793..74c0cfe68df66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3148,7 +3148,7 @@ dependencies = [ "futures 0.3.16", "jsonrpsee-types", "log 0.4.14", - "pin-project 1.0.5", + "pin-project 1.0.8", "rustls", "rustls-native-certs", "serde", @@ -3348,7 +3348,7 @@ dependencies = [ "libp2p-yamux", "multiaddr", "parking_lot 0.11.1", - "pin-project 1.0.5", + "pin-project 1.0.8", "smallvec 1.7.0", "wasm-timer", ] @@ -3373,7 +3373,7 @@ dependencies = [ "multihash 0.14.0", "multistream-select", "parking_lot 0.11.1", - "pin-project 1.0.5", + "pin-project 1.0.8", "prost", "prost-build", "rand 0.7.3", @@ -3599,7 +3599,7 @@ checksum = "07cb4dd4b917e5b40ddefe49b96b07adcd8d342e0317011d175b7b2bb1dcc974" dependencies = [ "futures 0.3.16", "log 0.4.14", - "pin-project 1.0.5", + "pin-project 1.0.8", "rand 0.7.3", "salsa20", "sha3", @@ -3618,7 +3618,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "pin-project 1.0.5", + "pin-project 1.0.8", "prost", "prost-build", "rand 0.7.3", @@ -4316,7 +4316,7 @@ dependencies = [ "bytes 1.0.1", "futures 0.3.16", "log 0.4.14", - "pin-project 1.0.5", + "pin-project 1.0.8", "smallvec 1.7.0", "unsigned-varint 0.7.0", ] @@ -6441,11 +6441,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63" +checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" dependencies = [ - "pin-project-internal 1.0.5", + "pin-project-internal 1.0.8", ] [[package]] @@ -6461,9 +6461,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b" +checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" dependencies = [ "proc-macro2", "quote", @@ -8077,7 +8077,7 @@ dependencies = [ "lru", "parity-scale-codec", "parking_lot 0.11.1", - "pin-project 1.0.5", + "pin-project 1.0.8", "prost", "prost-build", "quickcheck", @@ -8316,7 +8316,7 @@ dependencies = [ "parity-scale-codec", "parity-util-mem", "parking_lot 0.11.1", - "pin-project 1.0.5", + "pin-project 1.0.8", "rand 0.7.3", "sc-block-builder", "sc-chain-spec", @@ -8446,7 +8446,7 @@ dependencies = [ "libp2p", "log 0.4.14", "parking_lot 0.11.1", - "pin-project 1.0.5", + "pin-project 1.0.8", "rand 0.7.3", "serde", "serde_json", @@ -10610,7 +10610,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project 1.0.5", + "pin-project 1.0.8", "tracing", ] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 1725e4f5abcff..319bce4d0e6b6 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -39,7 +39,7 @@ linked_hash_set = "0.1.3" lru = "0.6.6" log = "0.4.8" parking_lot = "0.11.1" -pin-project = "1.0.4" +pin-project = "1.0.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.9.0", path = "../../utils/prometheus" } prost = "0.8" rand = "0.7.2" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 6f63a249a7c8f..0a496a55adc49 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -31,7 +31,7 @@ parking_lot = "0.11.1" log = "0.4.11" futures-timer = "3.0.1" exit-future = "0.2.0" -pin-project = "1.0.4" +pin-project = "1.0.8" hash-db = "0.15.2" serde = "1.0.126" serde_json = "1.0.68" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index f115017f09701..0c5e2db6c7760 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3.9" wasm-timer = "0.2.5" libp2p = { version = "0.39.1", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.8" -pin-project = "1.0.4" +pin-project = "1.0.8" rand = "0.7.2" serde = { version = "1.0.126", features = ["derive"] } serde_json = "1.0.68" From 66ba332eb34a82c60332a3f713375601df4e4f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 11 Oct 2021 19:50:12 +0200 Subject: [PATCH 0114/1472] sc-offchain: Fix flaky http tests (#10000) --- client/offchain/src/api/http.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index ce9fb298d1b0c..31f7d60e34ff9 100644 --- a/client/offchain/src/api/http.rs +++ b/client/offchain/src/api/http.rs @@ -700,7 +700,7 @@ mod tests { use super::{http, SharedClient}; use crate::api::timestamp; use core::convert::Infallible; - use futures::future; + use futures::{future, StreamExt}; use lazy_static::lazy_static; use sp_core::offchain::{Duration, HttpError, HttpRequestId, HttpRequestStatus}; @@ -725,7 +725,11 @@ mod tests { let server = hyper::Server::bind(&"127.0.0.1:0".parse().unwrap()).serve( hyper::service::make_service_fn(|_| async move { Ok::<_, Infallible>(hyper::service::service_fn( - move |_req| async move { + move |req: hyper::Request| async move { + // Wait until the complete request was received and processed, + // otherwise the tests are flaky. + let _ = req.into_body().collect::>().await; + Ok::<_, Infallible>(hyper::Response::new(hyper::Body::from( "Hello World!", ))) From e308d0fdc0acb8ec76eeef2c02e09bcafc5e46c2 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 12 Oct 2021 05:50:21 +0200 Subject: [PATCH 0115/1472] pow: add Version for quick-check of metadata state and refactor lock handling (#9698) * pow: add Version for quick-check of metadata state and refactor lock handling * typo: mut self -> self * Run rustfmt * typo: grammar --- client/consensus/pow/src/lib.rs | 18 +-- client/consensus/pow/src/worker.rs | 210 ++++++++++++++++++++--------- 2 files changed, 152 insertions(+), 76 deletions(-) diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 1f5781434ef71..7b1012888e869 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -41,13 +41,12 @@ mod worker; -pub use crate::worker::{MiningBuild, MiningMetadata, MiningWorker}; +pub use crate::worker::{MiningBuild, MiningHandle, MiningMetadata}; use crate::worker::UntilImportedOrTimeout; use codec::{Decode, Encode}; use futures::{Future, StreamExt}; use log::*; -use parking_lot::Mutex; use prometheus_endpoint::Registry; use sc_client_api::{self, backend::AuxStore, BlockOf, BlockchainEvents}; use sc_consensus::{ @@ -525,7 +524,7 @@ pub fn start_mining_worker( build_time: Duration, can_author_with: CAW, ) -> ( - Arc>::Proof>>>, + MiningHandle>::Proof>, impl Future, ) where @@ -543,12 +542,7 @@ where CAW: CanAuthorWith + Clone + Send + 'static, { let mut timer = UntilImportedOrTimeout::new(client.import_notification_stream(), timeout); - let worker = Arc::new(Mutex::new(MiningWorker { - build: None, - algorithm: algorithm.clone(), - block_import, - justification_sync_link, - })); + let worker = MiningHandle::new(algorithm.clone(), block_import, justification_sync_link); let worker_ret = worker.clone(); let task = async move { @@ -559,7 +553,7 @@ where if sync_oracle.is_major_syncing() { debug!(target: "pow", "Skipping proposal due to sync."); - worker.lock().on_major_syncing(); + worker.on_major_syncing(); continue } @@ -587,7 +581,7 @@ where continue } - if worker.lock().best_hash() == Some(best_hash) { + if worker.best_hash() == Some(best_hash) { continue } @@ -682,7 +676,7 @@ where proposal, }; - worker.lock().on_build(build); + worker.on_build(build); } }; diff --git a/client/consensus/pow/src/worker.rs b/client/consensus/pow/src/worker.rs index c0ca16ccad3aa..3faa18ece3188 100644 --- a/client/consensus/pow/src/worker.rs +++ b/client/consensus/pow/src/worker.rs @@ -22,6 +22,7 @@ use futures::{ }; use futures_timer::Delay; use log::*; +use parking_lot::Mutex; use sc_client_api::ImportNotifications; use sc_consensus::{BlockImportParams, BoxBlockImport, StateAction, StorageChanges}; use sp_consensus::{BlockOrigin, Proposal}; @@ -30,7 +31,16 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT}, DigestItem, }; -use std::{borrow::Cow, collections::HashMap, pin::Pin, time::Duration}; +use std::{ + borrow::Cow, + collections::HashMap, + pin::Pin, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }, + time::Duration, +}; use crate::{PowAlgorithm, PowIntermediate, Seal, INTERMEDIATE_KEY, POW_ENGINE_ID}; @@ -60,21 +70,26 @@ pub struct MiningBuild< pub proposal: Proposal, Proof>, } +/// Version of the mining worker. +#[derive(Eq, PartialEq, Clone, Copy)] +pub struct Version(usize); + /// Mining worker that exposes structs to query the current mining build and submit mined blocks. -pub struct MiningWorker< +pub struct MiningHandle< Block: BlockT, Algorithm: PowAlgorithm, C: sp_api::ProvideRuntimeApi, L: sc_consensus::JustificationSyncLink, Proof, > { - pub(crate) build: Option>, - pub(crate) algorithm: Algorithm, - pub(crate) block_import: BoxBlockImport>, - pub(crate) justification_sync_link: L, + version: Arc, + algorithm: Arc, + justification_sync_link: Arc, + build: Arc>>>, + block_import: Arc>>>, } -impl MiningWorker +impl MiningHandle where Block: BlockT, C: sp_api::ProvideRuntimeApi, @@ -83,35 +98,65 @@ where L: sc_consensus::JustificationSyncLink, sp_api::TransactionFor: Send + 'static, { - /// Get the current best hash. `None` if the worker has just started or the client is doing - /// major syncing. - pub fn best_hash(&self) -> Option { - self.build.as_ref().map(|b| b.metadata.best_hash) + fn increment_version(&self) { + self.version.fetch_add(1, Ordering::SeqCst); } - pub(crate) fn on_major_syncing(&mut self) { - self.build = None; + pub(crate) fn new( + algorithm: Algorithm, + block_import: BoxBlockImport>, + justification_sync_link: L, + ) -> Self { + Self { + version: Arc::new(AtomicUsize::new(0)), + algorithm: Arc::new(algorithm), + justification_sync_link: Arc::new(justification_sync_link), + build: Arc::new(Mutex::new(None)), + block_import: Arc::new(Mutex::new(block_import)), + } } - pub(crate) fn on_build(&mut self, build: MiningBuild) { - self.build = Some(build); + pub(crate) fn on_major_syncing(&self) { + let mut build = self.build.lock(); + *build = None; + self.increment_version(); + } + + pub(crate) fn on_build(&self, value: MiningBuild) { + let mut build = self.build.lock(); + *build = Some(value); + self.increment_version(); + } + + /// Get the version of the mining worker. + /// + /// This returns type `Version` which can only compare equality. If `Version` is unchanged, then + /// it can be certain that `best_hash` and `metadata` were not changed. + pub fn version(&self) -> Version { + Version(self.version.load(Ordering::SeqCst)) + } + + /// Get the current best hash. `None` if the worker has just started or the client is doing + /// major syncing. + pub fn best_hash(&self) -> Option { + self.build.lock().as_ref().map(|b| b.metadata.best_hash) } /// Get a copy of the current mining metadata, if available. pub fn metadata(&self) -> Option> { - self.build.as_ref().map(|b| b.metadata.clone()) + self.build.lock().as_ref().map(|b| b.metadata.clone()) } /// Submit a mined seal. The seal will be validated again. Returns true if the submission is /// successful. - pub async fn submit(&mut self, seal: Seal) -> bool { - if let Some(build) = self.build.take() { + pub async fn submit(&self, seal: Seal) -> bool { + if let Some(metadata) = self.metadata() { match self.algorithm.verify( - &BlockId::Hash(build.metadata.best_hash), - &build.metadata.pre_hash, - build.metadata.pre_runtime.as_ref().map(|v| &v[..]), + &BlockId::Hash(metadata.best_hash), + &metadata.pre_hash, + metadata.pre_runtime.as_ref().map(|v| &v[..]), &seal, - build.metadata.difficulty, + metadata.difficulty, ) { Ok(true) => (), Ok(false) => { @@ -130,55 +175,92 @@ where return false }, } + } else { + warn!( + target: "pow", + "Unable to import mined block: metadata does not exist", + ); + return false + } - let seal = DigestItem::Seal(POW_ENGINE_ID, seal); - let (header, body) = build.proposal.block.deconstruct(); - - let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); - import_block.post_digests.push(seal); - import_block.body = Some(body); - import_block.state_action = - StateAction::ApplyChanges(StorageChanges::Changes(build.proposal.storage_changes)); - - let intermediate = PowIntermediate:: { - difficulty: Some(build.metadata.difficulty), - }; - - import_block - .intermediates - .insert(Cow::from(INTERMEDIATE_KEY), Box::new(intermediate) as Box<_>); - - let header = import_block.post_header(); - match self.block_import.import_block(import_block, HashMap::default()).await { - Ok(res) => { - res.handle_justification( - &header.hash(), - *header.number(), - &mut self.justification_sync_link, - ); - - info!( - target: "pow", - "✅ Successfully mined block on top of: {}", - build.metadata.best_hash - ); - true - }, - Err(err) => { - warn!( - target: "pow", - "Unable to import mined block: {:?}", - err, - ); - false - }, + let build = if let Some(build) = { + let mut build = self.build.lock(); + let value = build.take(); + if value.is_some() { + self.increment_version(); } + value + } { + build } else { warn!( target: "pow", "Unable to import mined block: build does not exist", ); - false + return false + }; + + let seal = DigestItem::Seal(POW_ENGINE_ID, seal); + let (header, body) = build.proposal.block.deconstruct(); + + let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); + import_block.post_digests.push(seal); + import_block.body = Some(body); + import_block.state_action = + StateAction::ApplyChanges(StorageChanges::Changes(build.proposal.storage_changes)); + + let intermediate = PowIntermediate:: { + difficulty: Some(build.metadata.difficulty), + }; + + import_block + .intermediates + .insert(Cow::from(INTERMEDIATE_KEY), Box::new(intermediate) as Box<_>); + + let header = import_block.post_header(); + let mut block_import = self.block_import.lock(); + + match block_import.import_block(import_block, HashMap::default()).await { + Ok(res) => { + res.handle_justification( + &header.hash(), + *header.number(), + &self.justification_sync_link, + ); + + info!( + target: "pow", + "✅ Successfully mined block on top of: {}", + build.metadata.best_hash + ); + true + }, + Err(err) => { + warn!( + target: "pow", + "Unable to import mined block: {:?}", + err, + ); + false + }, + } + } +} + +impl Clone for MiningHandle +where + Block: BlockT, + Algorithm: PowAlgorithm, + C: sp_api::ProvideRuntimeApi, + L: sc_consensus::JustificationSyncLink, +{ + fn clone(&self) -> Self { + Self { + version: self.version.clone(), + algorithm: self.algorithm.clone(), + justification_sync_link: self.justification_sync_link.clone(), + build: self.build.clone(), + block_import: self.block_import.clone(), } } } From 1403b3793fa48f68fb81aef11fb2b4500aa096db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 12 Oct 2021 06:12:29 +0200 Subject: [PATCH 0116/1472] node-template: Do not provide benchmarking host functions by default (#10005) --- bin/node-template/node/src/service.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index a70dd877ff35a..2286ad3bd654f 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -16,7 +16,12 @@ use std::{sync::Arc, time::Duration}; pub struct ExecutorDispatch; impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { + /// Only enable the benchmarking host functions when we actually want to benchmark. + #[cfg(feature = "runtime-benchmarks")] type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + /// Otherwise we only use the default Substrate host functions. + #[cfg(not(feature = "runtime-benchmarks"))] + type ExtendHostFunctions = (); fn dispatch(method: &str, data: &[u8]) -> Option> { node_template_runtime::api::dispatch(method, data) From cafe12e7785bf92e5dc04780c10e7f8330a15a4c Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 12 Oct 2021 09:54:40 +0100 Subject: [PATCH 0117/1472] Switch to using ss58-registry crate (#9755) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Switch to using ss58-registry crate * Custom(42) is now eq to Substrate Co-authored-by: Bastian Köcher Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- Cargo.lock | 15 + client/cli/src/commands/utils.rs | 11 +- client/cli/src/commands/vanity.rs | 20 +- primitives/core/Cargo.toml | 2 +- primitives/core/src/crypto.rs | 305 ++---------------- primitives/core/src/ecdsa.rs | 17 +- .../frame-utilities-cli/src/pallet_id.rs | 4 +- 7 files changed, 72 insertions(+), 302 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74c0cfe68df66..7fdb4cf6fe19c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9269,6 +9269,7 @@ dependencies = [ "sp-serializer", "sp-std", "sp-storage", + "ss58-registry", "substrate-bip39", "thiserror", "tiny-bip39", @@ -9783,6 +9784,20 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "ss58-registry" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2413ecc7946ca99368862851dc1359f1477bc654ecfb135cf3efcb85ceca5f" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "serde", + "serde_json", + "unicode-xid", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" diff --git a/client/cli/src/commands/utils.rs b/client/cli/src/commands/utils.rs index 864d7e920f81a..39e5149404b29 100644 --- a/client/cli/src/commands/utils.rs +++ b/client/cli/src/commands/utils.rs @@ -23,7 +23,10 @@ use crate::{ }; use serde_json::json; use sp_core::{ - crypto::{ExposeSecret, SecretString, Ss58AddressFormat, Ss58Codec, Zeroize}, + crypto::{ + unwrap_or_default_ss58_version, ExposeSecret, SecretString, Ss58AddressFormat, Ss58Codec, + Zeroize, + }, hexdisplay::HexDisplay, Pair, }; @@ -72,7 +75,7 @@ pub fn print_from_uri( let password = password.as_ref().map(|s| s.expose_secret().as_str()); if let Ok((pair, seed)) = Pair::from_phrase(uri, password.clone()) { let public_key = pair.public(); - let network_override = network_override.unwrap_or_default(); + let network_override = unwrap_or_default_ss58_version(network_override); match output { OutputType::Json => { @@ -108,7 +111,7 @@ pub fn print_from_uri( } } else if let Ok((pair, seed)) = Pair::from_string_with_seed(uri, password.clone()) { let public_key = pair.public(); - let network_override = network_override.unwrap_or_default(); + let network_override = unwrap_or_default_ss58_version(network_override); match output { OutputType::Json => { @@ -198,7 +201,7 @@ where let public_key = Pair::Public::try_from(&public) .map_err(|_| "Failed to construct public key from given hex")?; - let network_override = network_override.unwrap_or_default(); + let network_override = unwrap_or_default_ss58_version(network_override); match output { OutputType::Json => { diff --git a/client/cli/src/commands/vanity.rs b/client/cli/src/commands/vanity.rs index daeb81e86a1a1..d2953c8396079 100644 --- a/client/cli/src/commands/vanity.rs +++ b/client/cli/src/commands/vanity.rs @@ -22,7 +22,7 @@ use crate::{ error, utils, with_crypto_scheme, CryptoSchemeFlag, NetworkSchemeFlag, OutputTypeFlag, }; use rand::{rngs::OsRng, RngCore}; -use sp_core::crypto::{Ss58AddressFormat, Ss58Codec}; +use sp_core::crypto::{unwrap_or_default_ss58_version, Ss58AddressFormat, Ss58Codec}; use sp_runtime::traits::IdentifyAccount; use structopt::StructOpt; use utils::print_from_uri; @@ -53,7 +53,10 @@ impl VanityCmd { pub fn run(&self) -> error::Result<()> { let formated_seed = with_crypto_scheme!( self.crypto_scheme.scheme, - generate_key(&self.pattern, self.network_scheme.network.clone().unwrap_or_default()), + generate_key( + &self.pattern, + unwrap_or_default_ss58_version(self.network_scheme.network) + ), )?; with_crypto_scheme!( @@ -159,7 +162,10 @@ fn assert_non_empty_string(pattern: &str) -> Result { #[cfg(test)] mod tests { use super::*; - use sp_core::{crypto::Ss58Codec, sr25519, Pair}; + use sp_core::{ + crypto::{default_ss58_version, Ss58AddressFormatRegistry, Ss58Codec}, + sr25519, Pair, + }; use structopt::StructOpt; #[cfg(feature = "bench")] use test::Bencher; @@ -172,7 +178,7 @@ mod tests { #[test] fn test_generation_with_single_char() { - let seed = generate_key::("ab", Default::default()).unwrap(); + let seed = generate_key::("ab", default_ss58_version()).unwrap(); assert!(sr25519::Pair::from_seed_slice(&hex::decode(&seed[2..]).unwrap()) .unwrap() .public() @@ -182,11 +188,13 @@ mod tests { #[test] fn generate_key_respects_network_override() { - let seed = generate_key::("ab", Ss58AddressFormat::PolkadotAccount).unwrap(); + let seed = + generate_key::("ab", Ss58AddressFormatRegistry::PolkadotAccount.into()) + .unwrap(); assert!(sr25519::Pair::from_seed_slice(&hex::decode(&seed[2..]).unwrap()) .unwrap() .public() - .to_ss58check_with_version(Ss58AddressFormat::PolkadotAccount) + .to_ss58check_with_version(Ss58AddressFormatRegistry::PolkadotAccount.into()) .contains("ab")); } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 31223ff1ccf76..f063b65c97e04 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -66,7 +66,7 @@ hex = { version = "0.4", default-features = false, optional = true } twox-hash = { version = "1.6.1", default-features = false, optional = true } libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } - +ss58-registry = "1.0.0" sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" } [dev-dependencies] diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index a9f3e904a2a85..21b8520c7780f 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -26,8 +26,6 @@ use crate::{ed25519, sr25519}; use base58::{FromBase58, ToBase58}; use codec::{Decode, Encode, MaxEncodedLen}; #[cfg(feature = "std")] -use parking_lot::Mutex; -#[cfg(feature = "std")] use rand::{rngs::OsRng, RngCore}; #[cfg(feature = "std")] use regex::Regex; @@ -38,14 +36,15 @@ pub use secrecy::ExposeSecret; #[cfg(feature = "std")] pub use secrecy::SecretString; use sp_runtime_interface::pass_by::PassByInner; -#[cfg(feature = "std")] -use sp_std::convert::TryInto; #[doc(hidden)] pub use sp_std::ops::Deref; use sp_std::{convert::TryFrom, hash::Hash, str, vec::Vec}; /// Trait to zeroize a memory buffer. pub use zeroize::Zeroize; +#[cfg(feature = "full_crypto")] +pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58AddressFormatRegistry}; + /// The root phrase for our publicly known keys. pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk"; @@ -227,7 +226,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { /// A format filterer, can be used to ensure that `from_ss58check` family only decode for /// allowed identifiers. By default just refuses the two reserved identifiers. fn format_is_allowed(f: Ss58AddressFormat) -> bool { - !matches!(f, Ss58AddressFormat::Reserved46 | Ss58AddressFormat::Reserved47) + !f.is_reserved() } /// Some if the string is a properly encoded SS58Check address. @@ -235,7 +234,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { fn from_ss58check(s: &str) -> Result { Self::from_ss58check_with_version(s).and_then(|(r, v)| match v { v if !v.is_custom() => Ok(r), - v if v == *DEFAULT_VERSION.lock() => Ok(r), + v if v == default_ss58_version() => Ok(r), _ => Err(PublicError::UnknownVersion), }) } @@ -270,7 +269,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { if data.len() != prefix_len + body_len + CHECKSUM_LEN { return Err(PublicError::BadLength) } - let format = ident.try_into().map_err(|_: ()| PublicError::UnknownVersion)?; + let format = ident.into(); if !Self::format_is_allowed(format) { return Err(PublicError::FormatNotAllowed) } @@ -291,7 +290,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { fn from_string(s: &str) -> Result { Self::from_string_with_version(s).and_then(|(r, v)| match v { v if !v.is_custom() => Ok(r), - v if v == *DEFAULT_VERSION.lock() => Ok(r), + v if v == default_ss58_version() => Ok(r), _ => Err(PublicError::UnknownVersion), }) } @@ -322,7 +321,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { /// Return the ss58-check string for this key. #[cfg(feature = "std")] fn to_ss58check(&self) -> String { - self.to_ss58check_with_version(*DEFAULT_VERSION.lock()) + self.to_ss58check_with_version(default_ss58_version()) } /// Some if the string is a properly encoded SS58Check address, optionally with @@ -355,286 +354,30 @@ fn ss58hash(data: &[u8]) -> blake2_rfc::blake2b::Blake2bResult { context.finalize() } +/// Default prefix number #[cfg(feature = "std")] -lazy_static::lazy_static! { - static ref DEFAULT_VERSION: Mutex - = Mutex::new(Ss58AddressFormat::SubstrateAccount); -} - -#[cfg(feature = "full_crypto")] -macro_rules! ss58_address_format { - ( $( $identifier:tt => ($number:expr, $name:expr, $desc:tt) )* ) => ( - /// A known address (sub)format/network ID for SS58. - #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] - pub enum Ss58AddressFormat { - $(#[doc = $desc] $identifier),*, - /// Use a manually provided numeric value as a standard identifier - Custom(u16), - } - - #[cfg(feature = "std")] - impl std::fmt::Display for Ss58AddressFormat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - $( - Ss58AddressFormat::$identifier => write!(f, "{}", $name), - )* - Ss58AddressFormat::Custom(x) => write!(f, "{}", x), - } - - } - } - - static ALL_SS58_ADDRESS_FORMATS: [Ss58AddressFormat; 0 $(+ { let _ = $number; 1})*] = [ - $(Ss58AddressFormat::$identifier),*, - ]; - - impl Ss58AddressFormat { - /// names of all address formats - pub fn all_names() -> &'static [&'static str] { - &[ - $($name),*, - ] - } - /// All known address formats. - pub fn all() -> &'static [Ss58AddressFormat] { - &ALL_SS58_ADDRESS_FORMATS - } - - /// Whether the address is custom. - pub fn is_custom(&self) -> bool { - matches!(self, Self::Custom(_)) - } - } - - impl TryFrom for Ss58AddressFormat { - type Error = (); - - fn try_from(x: u8) -> Result { - Ss58AddressFormat::try_from(x as u16) - } - } - - impl From for u16 { - fn from(x: Ss58AddressFormat) -> u16 { - match x { - $(Ss58AddressFormat::$identifier => $number),*, - Ss58AddressFormat::Custom(n) => n, - } - } - } - - impl TryFrom for Ss58AddressFormat { - type Error = (); - - fn try_from(x: u16) -> Result { - match x { - $($number => Ok(Ss58AddressFormat::$identifier)),*, - _ => Ok(Ss58AddressFormat::Custom(x)), - } - } - } - - /// Error encountered while parsing `Ss58AddressFormat` from &'_ str - /// unit struct for now. - #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] - pub struct ParseError; - - impl<'a> TryFrom<&'a str> for Ss58AddressFormat { - type Error = ParseError; - - fn try_from(x: &'a str) -> Result { - match x { - $($name => Ok(Ss58AddressFormat::$identifier)),*, - a => a.parse::().map(Ss58AddressFormat::Custom).map_err(|_| ParseError), - } - } - } - - #[cfg(feature = "std")] - impl std::str::FromStr for Ss58AddressFormat { - type Err = ParseError; - - fn from_str(data: &str) -> Result { - Self::try_from(data) - } - } - - #[cfg(feature = "std")] - impl std::fmt::Display for ParseError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "failed to parse network value as u8") - } - } - - #[cfg(feature = "std")] - impl Default for Ss58AddressFormat { - fn default() -> Self { - *DEFAULT_VERSION.lock() - } - } +static DEFAULT_VERSION: core::sync::atomic::AtomicU16 = std::sync::atomic::AtomicU16::new( + from_known_address_format(Ss58AddressFormatRegistry::SubstrateAccount), +); - #[cfg(feature = "std")] - impl From for String { - fn from(x: Ss58AddressFormat) -> String { - x.to_string() - } - } - ) +/// Returns default ss58 format used by the current active process. +#[cfg(feature = "std")] +pub fn default_ss58_version() -> Ss58AddressFormat { + DEFAULT_VERSION.load(std::sync::atomic::Ordering::Relaxed).into() } -#[cfg(feature = "full_crypto")] -ss58_address_format!( - PolkadotAccount => - (0, "polkadot", "Polkadot Relay-chain, standard account (*25519).") - BareSr25519 => - (1, "sr25519", "Bare 32-bit Schnorr/Ristretto 25519 (S/R 25519) key.") - KusamaAccount => - (2, "kusama", "Kusama Relay-chain, standard account (*25519).") - BareEd25519 => - (3, "ed25519", "Bare 32-bit Edwards Ed25519 key.") - KatalChainAccount => - (4, "katalchain", "Katal Chain, standard account (*25519).") - PlasmAccount => - (5, "plasm", "Plasm Network, standard account (*25519).") - BifrostAccount => - (6, "bifrost", "Bifrost mainnet, direct checksum, standard account (*25519).") - EdgewareAccount => - (7, "edgeware", "Edgeware mainnet, standard account (*25519).") - KaruraAccount => - (8, "karura", "Acala Karura canary network, standard account (*25519).") - ReynoldsAccount => - (9, "reynolds", "Laminar Reynolds canary network, standard account (*25519).") - AcalaAccount => - (10, "acala", "Acala mainnet, standard account (*25519).") - LaminarAccount => - (11, "laminar", "Laminar mainnet, standard account (*25519).") - PolymathAccount => - (12, "polymath", "Polymath network, standard account (*25519).") - SubstraTeeAccount => - (13, "substratee", "Any SubstraTEE off-chain network private account (*25519).") - TotemAccount => - (14, "totem", "Any Totem Live Accounting network standard account (*25519).") - SynesthesiaAccount => - (15, "synesthesia", "Synesthesia mainnet, standard account (*25519).") - KulupuAccount => - (16, "kulupu", "Kulupu mainnet, standard account (*25519).") - DarkAccount => - (17, "dark", "Dark mainnet, standard account (*25519).") - DarwiniaAccount => - (18, "darwinia", "Darwinia Chain mainnet, standard account (*25519).") - GeekAccount => - (19, "geek", "GeekCash mainnet, standard account (*25519).") - StafiAccount => - (20, "stafi", "Stafi mainnet, standard account (*25519).") - DockTestAccount => - (21, "dock-testnet", "Dock testnet, standard account (*25519).") - DockMainAccount => - (22, "dock-mainnet", "Dock mainnet, standard account (*25519).") - ShiftNrg => - (23, "shift", "ShiftNrg mainnet, standard account (*25519).") - ZeroAccount => - (24, "zero", "ZERO mainnet, standard account (*25519).") - AlphavilleAccount => - (25, "alphaville", "ZERO testnet, standard account (*25519).") - JupiterAccount => - (26, "jupiter", "Jupiter testnet, standard account (*25519).") - SubsocialAccount => - (28, "subsocial", "Subsocial network, standard account (*25519).") - DhiwayAccount => - (29, "cord", "Dhiway CORD network, standard account (*25519).") - PhalaAccount => - (30, "phala", "Phala Network, standard account (*25519).") - LitentryAccount => - (31, "litentry", "Litentry Network, standard account (*25519).") - RobonomicsAccount => - (32, "robonomics", "Any Robonomics network standard account (*25519).") - DataHighwayAccount => - (33, "datahighway", "DataHighway mainnet, standard account (*25519).") - AresAccount => - (34, "ares", "Ares Protocol, standard account (*25519).") - ValiuAccount => - (35, "vln", "Valiu Liquidity Network mainnet, standard account (*25519).") - CentrifugeAccount => - (36, "centrifuge", "Centrifuge Chain mainnet, standard account (*25519).") - NodleAccount => - (37, "nodle", "Nodle Chain mainnet, standard account (*25519).") - KiltAccount => - (38, "kilt", "KILT Chain mainnet, standard account (*25519).") - PolimecAccount => - (41, "poli", "Polimec Chain mainnet, standard account (*25519).") - SubstrateAccount => - (42, "substrate", "Any Substrate network, standard account (*25519).") - BareSecp256k1 => - (43, "secp256k1", "Bare ECDSA SECP256k1 key.") - ChainXAccount => - (44, "chainx", "ChainX mainnet, standard account (*25519).") - UniartsAccount => - (45, "uniarts", "UniArts Chain mainnet, standard account (*25519).") - Reserved46 => - (46, "reserved46", "Reserved for future use (46).") - Reserved47 => - (47, "reserved47", "Reserved for future use (47).") - NeatcoinAccount => - (48, "neatcoin", "Neatcoin mainnet, standard account (*25519).") - PicassoAccount => - (49, "picasso", "Composable Canary Network, standard account (*25519).") - ComposableAccount => - (50, "composable", "Composable mainnet, standard account (*25519).") - HydraDXAccount => - (63, "hydradx", "HydraDX standard account (*25519).") - AventusAccount => - (65, "aventus", "Aventus Chain mainnet, standard account (*25519).") - CrustAccount => - (66, "crust", "Crust Network, standard account (*25519).") - EquilibriumAccount => - (67, "equilibrium", "Equilibrium Network, standard account (*25519).") - SoraAccount => - (69, "sora", "SORA Network, standard account (*25519).") - ZeitgeistAccount => - (73, "zeitgeist", "Zeitgeist network, standard account (*25519).") - MantaAccount => - (77, "manta", "Manta Network, standard account (*25519).") - CalamariAccount => - (78, "calamari", "Manta Canary Network, standard account (*25519).") - Polkadex => - (88, "polkadex", "Polkadex Mainnet, standard account (*25519).") - PolkaSmith => - (98, "polkasmith", "PolkaSmith Canary Network, standard account (*25519).") - PolkaFoundry => - (99, "polkafoundry", "PolkaFoundry Network, standard account (*25519).") - OriginTrailAccount => - (101, "origintrail-parachain", "OriginTrail Parachain, ethereumm account (ECDSA).") - HeikoAccount => - (110, "heiko", "Heiko, session key (*25519).") - CloverAccount => - (128, "clover", "Clover Finance, standard account (*25519).") - ParallelAccount => - (172, "parallel", "Parallel, session key (*25519).") - SocialAccount => - (252, "social-network", "Social Network, standard account (*25519).") - Moonbeam => - (1284, "moonbeam", "Moonbeam, session key (*25519).") - Moonriver => - (1285, "moonriver", "Moonriver, session key (*25519).") - Automata => - (2349, "automata", "Automata mainnet standard account (*25519).") - BasiliskAccount => - (10041, "basilisk", "Basilisk standard account (*25519).") - ContextFree => - (11820, "contextfree", "Automata ContextFree standard account (*25519).") - - // Note: 16384 and above are reserved. -); +/// Returns either the input address format or the default. +#[cfg(feature = "std")] +pub fn unwrap_or_default_ss58_version(network: Option) -> Ss58AddressFormat { + network.unwrap_or_else(default_ss58_version) +} /// Set the default "version" (actually, this is a bit of a misnomer and the version byte is /// typically used not just to encode format/version but also network identity) that is used for -/// encoding and decoding SS58 addresses. If an unknown version is provided then it fails. -/// -/// See `ss58_address_format!` for all current known "versions". +/// encoding and decoding SS58 addresses. #[cfg(feature = "std")] -pub fn set_default_ss58_version(version: Ss58AddressFormat) { - *DEFAULT_VERSION.lock() = version +pub fn set_default_ss58_version(new_default: Ss58AddressFormat) { + DEFAULT_VERSION.store(new_default.into(), std::sync::atomic::Ordering::Relaxed); } #[cfg(feature = "std")] diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 11e9b9d71d80e..2751a0c40e3e5 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -640,7 +640,10 @@ impl CryptoType for Pair { mod test { use super::*; use crate::{ - crypto::{set_default_ss58_version, PublicError, DEV_PHRASE}, + crypto::{ + set_default_ss58_version, PublicError, Ss58AddressFormat, Ss58AddressFormatRegistry, + DEV_PHRASE, + }, keccak_256, }; use hex_literal::hex; @@ -772,26 +775,24 @@ mod test { #[test] fn ss58check_format_check_works() { - use crate::crypto::Ss58AddressFormat; let pair = Pair::from_seed(b"12345678901234567890123456789012"); let public = pair.public(); - let format = Ss58AddressFormat::Reserved46; + let format = Ss58AddressFormatRegistry::Reserved46Account.into(); let s = public.to_ss58check_with_version(format); assert_eq!(Public::from_ss58check_with_version(&s), Err(PublicError::FormatNotAllowed)); } #[test] fn ss58check_full_roundtrip_works() { - use crate::crypto::Ss58AddressFormat; let pair = Pair::from_seed(b"12345678901234567890123456789012"); let public = pair.public(); - let format = Ss58AddressFormat::PolkadotAccount; + let format = Ss58AddressFormatRegistry::PolkadotAccount.into(); let s = public.to_ss58check_with_version(format); let (k, f) = Public::from_ss58check_with_version(&s).unwrap(); assert_eq!(k, public); assert_eq!(f, format); - let format = Ss58AddressFormat::Custom(64); + let format = Ss58AddressFormat::custom(64); let s = public.to_ss58check_with_version(format); let (k, f) = Public::from_ss58check_with_version(&s).unwrap(); assert_eq!(k, public); @@ -805,10 +806,10 @@ mod test { if std::env::var("RUN_CUSTOM_FORMAT_TEST") == Ok("1".into()) { use crate::crypto::Ss58AddressFormat; // temp save default format version - let default_format = Ss58AddressFormat::default(); + let default_format = crate::crypto::default_ss58_version(); // set current ss58 version is custom "200" `Ss58AddressFormat::Custom(200)` - set_default_ss58_version(Ss58AddressFormat::Custom(200)); + set_default_ss58_version(Ss58AddressFormat::custom(200)); // custom addr encoded by version 200 let addr = "4pbsSkWcBaYoFHrKJZp5fDVUKbqSYD9dhZZGvpp3vQ5ysVs5ybV"; Public::from_ss58check(&addr).unwrap(); diff --git a/utils/frame/frame-utilities-cli/src/pallet_id.rs b/utils/frame/frame-utilities-cli/src/pallet_id.rs index 2caac7db588a9..d173f52b39cd8 100644 --- a/utils/frame/frame-utilities-cli/src/pallet_id.rs +++ b/utils/frame/frame-utilities-cli/src/pallet_id.rs @@ -22,7 +22,7 @@ use sc_cli::{ utils::print_from_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, OutputTypeFlag, }; -use sp_core::crypto::{Ss58AddressFormat, Ss58Codec}; +use sp_core::crypto::{unwrap_or_default_ss58_version, Ss58AddressFormat, Ss58Codec}; use sp_runtime::traits::AccountIdConversion; use std::convert::{TryFrom, TryInto}; use structopt::StructOpt; @@ -78,7 +78,7 @@ impl PalletIdCmd { with_crypto_scheme!( self.crypto_scheme.scheme, print_from_uri( - &account_id.to_ss58check_with_version(self.network.clone().unwrap_or_default()), + &account_id.to_ss58check_with_version(unwrap_or_default_ss58_version(self.network)), password, self.network, self.output_scheme.output_type.clone() From 98ef7691c37e2638c8ca93586d14d2b102d4e43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 12 Oct 2021 12:33:43 +0200 Subject: [PATCH 0118/1472] sp-debug-derive: Add `force-debug` feature (#9996) * sp-debug-derive: Add `force-debug` feature Sometimes users want to have proper debug information even inside the wasm runtime, when they use `RuntimeDebug`. To not fork Substrate to change a type to a normal `Debug` derive, this pr introduces the `force-debug` feature. This feature can be enabled by the user in their runtime and then the types will use the normal Debug derive instead of printing `wasm:stripped`. * Fixes --- primitives/core/Cargo.toml | 2 +- primitives/debug-derive/Cargo.toml | 6 ++++++ primitives/debug-derive/src/impls.rs | 4 ++-- primitives/storage/Cargo.toml | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index f063b65c97e04..631bf3fc122e0 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -40,7 +40,7 @@ zeroize = { version = "1.4.2", default-features = false } secrecy = { version = "0.8.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.11.1", optional = true } -sp-debug-derive = { version = "3.0.0", path = "../debug-derive" } +sp-debug-derive = { version = "3.0.0", default-features = false, path = "../debug-derive" } sp-externalities = { version = "0.10.0-dev", optional = true, path = "../externalities" } sp-storage = { version = "4.0.0-dev", default-features = false, path = "../storage" } parity-util-mem = { version = "0.10.0", default-features = false, features = [ diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml index 2e5ef93e41f5e..ce49c54b46fbe 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -22,6 +22,12 @@ syn = "1.0.80" proc-macro2 = "1.0" [features] +default = [ "std" ] std = [] +# By default `RuntimeDebug` implements `Debug` that outputs `` when `std` is +# disabled. However, sometimes downstream users need to have the real `Debug` implementation for +# debugging purposes. If this is required, a user only needs to add this crate as a dependency of +# their runtime and enable the `force-debug` feature. +force-debug = [] [dev-dependencies] diff --git a/primitives/debug-derive/src/impls.rs b/primitives/debug-derive/src/impls.rs index 4d79ee9880160..0e67ef81bc853 100644 --- a/primitives/debug-derive/src/impls.rs +++ b/primitives/debug-derive/src/impls.rs @@ -43,7 +43,7 @@ pub fn debug_derive(ast: DeriveInput) -> proc_macro::TokenStream { gen.into() } -#[cfg(not(feature = "std"))] +#[cfg(all(not(feature = "std"), not(feature = "force-debug")))] mod implementation { use super::*; @@ -58,7 +58,7 @@ mod implementation { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", feature = "force-debug"))] mod implementation { use super::*; use proc_macro2::Span; diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index 1a05fb9969197..078e0fff12ef8 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -18,9 +18,9 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } serde = { version = "1.0.126", optional = true, features = ["derive"] } impl-serde = { version = "0.3.1", optional = true } ref-cast = "1.0.0" -sp-debug-derive = { version = "3.0.0", path = "../debug-derive" } +sp-debug-derive = { version = "3.0.0", default-features = false, path = "../debug-derive" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } [features] default = [ "std" ] -std = [ "sp-std/std", "serde", "impl-serde", "codec/std" ] +std = [ "sp-std/std", "serde", "impl-serde", "codec/std", "sp-debug-derive/std" ] From 508c5a746ae7eedd9170b213ca98e3ce857f5790 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 12 Oct 2021 11:36:09 +0100 Subject: [PATCH 0119/1472] hint what to do if you didn't use bot merge (#10009) --- docs/CONTRIBUTING.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTING.adoc b/docs/CONTRIBUTING.adoc index 103b318a169d7..5b1920e775bbd 100644 --- a/docs/CONTRIBUTING.adoc +++ b/docs/CONTRIBUTING.adoc @@ -85,10 +85,11 @@ To create a Polkadot companion PR: . Wait for reviews on both the Substrate and the Polkadot PRs. . Once the Substrate PR runs green, a member of the `parity` github group can comment on the Substrate PR with `bot merge` which will: - Merge the Substrate PR. - - The bot will push a commit to the Polkadot PR updating its Substrate reference. + - The bot will push a commit to the Polkadot PR updating its Substrate reference. (effecively doing `cargo update -p sp-io`) - If the polkadot PR origins from a fork then a project member may need to press `approve run` on the polkadot PR. - The bot will merge the Polkadot PR once all its CI `{"build_allow_failure":false}` checks are green. Note: The merge-bot currently doesn't work with forks on org accounts, only individual accounts. + (Hint: it's recommended to use `bot merge` to merge all substrate PRs, not just ones with a polkadot companion.) If your PR is reviewed well, but a Polkadot PR is missing, signal it with https://github.com/paritytech/substrate/labels/A7-needspolkadotpr[`A7-needspolkadotpr`] to prevent it from getting automatically merged. From f92e9780372b777b743d3a1dc50f4248b70abfb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Oct 2021 12:15:12 +0100 Subject: [PATCH 0120/1472] Bump sha2 from 0.9.5 to 0.9.8 (#10008) Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.9.5 to 0.9.8. - [Release notes](https://github.com/RustCrypto/hashes/releases) - [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.9.5...sha2-v0.9.8) --- updated-dependencies: - dependency-name: sha2 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 | 55 ++++++++++++++++++++++---------------- primitives/core/Cargo.toml | 2 +- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fdb4cf6fe19c..868ed2b46a77f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ checksum = "495ee669413bfbe9e8cace80f4d3d78e6d8c8d99579f97fb93bde351b185f2d4" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures", + "cpufeatures 0.1.5", "opaque-debug 0.3.0", ] @@ -884,7 +884,7 @@ checksum = "fee7ad89dc1128635074c268ee661f90c3f7e83d9fd12910608c36b47d6c3412" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures", + "cpufeatures 0.1.5", "zeroize", ] @@ -1042,6 +1042,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + [[package]] name = "cpuid-bool" version = "0.1.2" @@ -1666,7 +1675,7 @@ dependencies = [ "ed25519", "rand 0.7.3", "serde", - "sha2 0.9.5", + "sha2 0.9.8", "zeroize", ] @@ -3262,9 +3271,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.95" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" [[package]] name = "libgit2-sys" @@ -3379,7 +3388,7 @@ dependencies = [ "rand 0.7.3", "ring", "rw-stream-sink", - "sha2 0.9.5", + "sha2 0.9.8", "smallvec 1.7.0", "thiserror", "unsigned-varint 0.7.0", @@ -3450,7 +3459,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "regex", - "sha2 0.9.5", + "sha2 0.9.8", "smallvec 1.7.0", "unsigned-varint 0.7.0", "wasm-timer", @@ -3490,7 +3499,7 @@ dependencies = [ "prost", "prost-build", "rand 0.7.3", - "sha2 0.9.5", + "sha2 0.9.8", "smallvec 1.7.0", "uint", "unsigned-varint 0.7.0", @@ -3552,7 +3561,7 @@ dependencies = [ "prost", "prost-build", "rand 0.8.4", - "sha2 0.9.5", + "sha2 0.9.8", "snow", "static_assertions", "x25519-dalek", @@ -3775,7 +3784,7 @@ dependencies = [ "libsecp256k1-gen-genmult 0.2.1", "rand 0.7.3", "serde", - "sha2 0.9.5", + "sha2 0.9.8", "typenum", ] @@ -3794,7 +3803,7 @@ dependencies = [ "libsecp256k1-gen-genmult 0.2.1", "rand 0.7.3", "serde", - "sha2 0.9.5", + "sha2 0.9.8", "typenum", ] @@ -3812,7 +3821,7 @@ dependencies = [ "libsecp256k1-gen-genmult 0.3.0", "rand 0.8.4", "serde", - "sha2 0.9.5", + "sha2 0.9.8", ] [[package]] @@ -4269,7 +4278,7 @@ dependencies = [ "digest 0.9.0", "generic-array 0.14.4", "multihash-derive", - "sha2 0.9.5", + "sha2 0.9.8", "sha3", "unsigned-varint 0.5.1", ] @@ -4283,7 +4292,7 @@ dependencies = [ "digest 0.9.0", "generic-array 0.14.4", "multihash-derive", - "sha2 0.9.5", + "sha2 0.9.8", "unsigned-varint 0.7.0", ] @@ -6547,7 +6556,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fcffab1f78ebbdf4b93b68c1ffebc24037eedf271edaca795732b24e5e4e349" dependencies = [ - "cpufeatures", + "cpufeatures 0.1.5", "opaque-debug 0.3.0", "universal-hash", ] @@ -6559,7 +6568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ba6a405ef63530d6cb12802014b22f9c5751bd17cdcddbe9e46d5c8ae83287" dependencies = [ "cfg-if 1.0.0", - "cpufeatures", + "cpufeatures 0.1.5", "opaque-debug 0.3.0", "universal-hash", ] @@ -8817,13 +8826,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpufeatures", + "cpufeatures 0.2.1", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -8932,7 +8941,7 @@ dependencies = [ "rand_core 0.6.2", "ring", "rustc_version 0.3.3", - "sha2 0.9.5", + "sha2 0.9.8", "subtle 2.4.0", "x25519-dalek", ] @@ -9262,7 +9271,7 @@ dependencies = [ "secrecy", "serde", "serde_json", - "sha2 0.9.5", + "sha2 0.9.8", "sp-debug-derive", "sp-externalities", "sp-runtime-interface", @@ -10367,7 +10376,7 @@ dependencies = [ "pbkdf2 0.4.0", "rand 0.7.3", "rustc-hash", - "sha2 0.9.5", + "sha2 0.9.8", "thiserror", "unicode-normalization", "wasm-bindgen", @@ -11445,7 +11454,7 @@ dependencies = [ "libc", "log 0.4.14", "serde", - "sha2 0.9.5", + "sha2 0.9.8", "toml", "winapi 0.3.9", "zstd", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 631bf3fc122e0..0944fbef23349 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -61,7 +61,7 @@ schnorrkel = { version = "0.9.1", features = [ "preaudit_deprecated", "u64_backend", ], default-features = false, optional = true } -sha2 = { version = "0.9.5", default-features = false, optional = true } +sha2 = { version = "0.9.8", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } twox-hash = { version = "1.6.1", default-features = false, optional = true } libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"], optional = true } From 66f0008af39054d1457ad7eac78a47efa6bc39a3 Mon Sep 17 00:00:00 2001 From: Chris Sosnin <48099298+slumber@users.noreply.github.com> Date: Tue, 12 Oct 2021 18:15:23 +0300 Subject: [PATCH 0121/1472] sc-executor-wasmtime: upgrade wasmtime to 0.30.0 (#10003) * sc-executor-wasmtime: upgrade wasmtime to 0.30.0 Changes related to memory64 proposal implementation, for additional details see bytecodealliance/wasmtime#3153 * sc-executor-wasmtime: introduce parallel_compilation flag * typos --- Cargo.lock | 212 +++++++----------- client/executor/src/wasm_runtime.rs | 5 +- client/executor/wasmtime/Cargo.toml | 3 +- client/executor/wasmtime/src/imports.rs | 35 ++- .../executor/wasmtime/src/instance_wrapper.rs | 2 +- client/executor/wasmtime/src/runtime.rs | 36 +-- client/executor/wasmtime/src/tests.rs | 29 +-- 7 files changed, 145 insertions(+), 177 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 868ed2b46a77f..d9f7339588742 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1068,11 +1068,11 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.76.0" +version = "0.77.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e6bea67967505247f54fa2c85cf4f6e0e31c4e5692c9b70e4ae58e339067333" +checksum = "15013642ddda44eebcf61365b2052a23fd8b7314f90ba44aa059ec02643c5139" dependencies = [ - "cranelift-entity 0.76.0", + "cranelift-entity 0.77.0", ] [[package]] @@ -1096,18 +1096,17 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.76.0" +version = "0.77.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48194035d2752bdd5bdae429e3ab88676e95f52a2b1355a5d4e809f9e39b1d74" +checksum = "298f2a7ed5fdcb062d8e78b7496b0f4b95265d20245f2d0ca88f846dd192a3a3" dependencies = [ - "cranelift-bforest 0.76.0", - "cranelift-codegen-meta 0.76.0", - "cranelift-codegen-shared 0.76.0", - "cranelift-entity 0.76.0", + "cranelift-bforest 0.77.0", + "cranelift-codegen-meta 0.77.0", + "cranelift-codegen-shared 0.77.0", + "cranelift-entity 0.77.0", "gimli 0.25.0", "log 0.4.14", "regalloc", - "serde", "smallvec 1.7.0", "target-lexicon 0.12.0", ] @@ -1124,12 +1123,12 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.76.0" +version = "0.77.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976efb22fcab4f2cd6bd4e9913764616a54d895c1a23530128d04e03633c555f" +checksum = "5cf504261ac62dfaf4ffb3f41d88fd885e81aba947c1241275043885bc5f0bac" dependencies = [ - "cranelift-codegen-shared 0.76.0", - "cranelift-entity 0.76.0", + "cranelift-codegen-shared 0.77.0", + "cranelift-entity 0.77.0", ] [[package]] @@ -1140,12 +1139,9 @@ checksum = "6759012d6d19c4caec95793f052613e9d4113e925e7f14154defbac0f1d4c938" [[package]] name = "cranelift-codegen-shared" -version = "0.76.0" +version = "0.77.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dabb5fe66e04d4652e434195b45ae65b5c8172d520247b8f66d8df42b2b45dc" -dependencies = [ - "serde", -] +checksum = "1cd2a72db4301dbe7e5a4499035eedc1e82720009fb60603e20504d8691fa9cd" [[package]] name = "cranelift-entity" @@ -1158,9 +1154,9 @@ dependencies = [ [[package]] name = "cranelift-entity" -version = "0.76.0" +version = "0.77.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3329733e4d4b8e91c809efcaa4faee80bf66f20164e3dd16d707346bd3494799" +checksum = "48868faa07cacf948dc4a1773648813c0e453ff9467e800ff10f6a78c021b546" dependencies = [ "serde", ] @@ -1179,11 +1175,11 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.76.0" +version = "0.77.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279afcc0d3e651b773f94837c3d581177b348c8d69e928104b2e9fccb226f921" +checksum = "351c9d13b4ecd1a536215ec2fd1c3ee9ee8bc31af172abf1e45ed0adb7a931df" dependencies = [ - "cranelift-codegen 0.76.0", + "cranelift-codegen 0.77.0", "log 0.4.14", "smallvec 1.7.0", "target-lexicon 0.12.0", @@ -1191,30 +1187,29 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.76.0" +version = "0.77.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c04d1fe6a5abb5bb0edc78baa8ef238370fb8e389cc88b6d153f7c3e9680425" +checksum = "6df8b556663d7611b137b24db7f6c8d9a8a27d7f29c7ea7835795152c94c1b75" dependencies = [ - "cranelift-codegen 0.76.0", + "cranelift-codegen 0.77.0", "libc", "target-lexicon 0.12.0", ] [[package]] name = "cranelift-wasm" -version = "0.76.0" +version = "0.77.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d260ad44f6fd2c91f7f5097191a2a9e3edcbb36df1fb787b600dad5ea148ec" +checksum = "7a69816d90db694fa79aa39b89dda7208a4ac74b6f2b8f3c4da26ee1c8bdfc5e" dependencies = [ - "cranelift-codegen 0.76.0", - "cranelift-entity 0.76.0", - "cranelift-frontend 0.76.0", + "cranelift-codegen 0.77.0", + "cranelift-entity 0.77.0", + "cranelift-frontend 0.77.0", "itertools", "log 0.4.14", - "serde", "smallvec 1.7.0", - "thiserror", - "wasmparser 0.79.0", + "wasmparser 0.80.2", + "wasmtime-types", ] [[package]] @@ -7161,7 +7156,6 @@ checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" dependencies = [ "log 0.4.14", "rustc-hash", - "serde", "smallvec 1.7.0", ] @@ -8626,26 +8620,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scroll" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "sct" version = "0.6.0" @@ -11404,15 +11378,15 @@ checksum = "87cc2fe6350834b4e528ba0901e7aa405d78b89dc1fa3145359eb4de0e323fcf" [[package]] name = "wasmparser" -version = "0.79.0" +version = "0.80.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b5894be15a559c85779254700e1d35f02f843b5a69152e5c82c626d9fd66c0e" +checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b" [[package]] name = "wasmtime" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bbb8a082a8ef50f7eeb8b82dda9709ef1e68963ea3c94e45581644dd4041835" +checksum = "899b1e5261e3d3420860dacfb952871ace9d7ba9f953b314f67aaf9f8e2a4d89" dependencies = [ "anyhow", "backtrace", @@ -11423,27 +11397,28 @@ dependencies = [ "lazy_static", "libc", "log 0.4.14", + "object 0.26.0", "paste 1.0.4", "psm", + "rayon", "region", "rustc-demangle", "serde", - "smallvec 1.7.0", "target-lexicon 0.12.0", - "wasmparser 0.79.0", + "wasmparser 0.80.2", "wasmtime-cache", + "wasmtime-cranelift", "wasmtime-environ", "wasmtime-jit", - "wasmtime-profiling", "wasmtime-runtime", "winapi 0.3.9", ] [[package]] name = "wasmtime-cache" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d73391579ca7f24573138ef768b73b2aed5f9d542385c64979b65d60d0912399" +checksum = "e2493b81d7a9935f7af15e06beec806f256bc974a90a843685f3d61f2fc97058" dependencies = [ "anyhow", "base64 0.13.0", @@ -11462,125 +11437,76 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81c6f5ae9205382345c7cd7454932a906186836999a2161c385e38a15f52e1fe" -dependencies = [ - "cranelift-codegen 0.76.0", - "cranelift-entity 0.76.0", - "cranelift-frontend 0.76.0", - "cranelift-wasm", - "target-lexicon 0.12.0", - "wasmparser 0.79.0", - "wasmtime-environ", -] - -[[package]] -name = "wasmtime-debug" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c69e08f55e12f15f50b1b533bc3626723e7224254a065de6576934c86258c9e8" +checksum = "99706bacdf5143f7f967d417f0437cce83a724cf4518cb1a3ff40e519d793021" dependencies = [ "anyhow", + "cranelift-codegen 0.77.0", + "cranelift-entity 0.77.0", + "cranelift-frontend 0.77.0", + "cranelift-native", + "cranelift-wasm", "gimli 0.25.0", "more-asserts", "object 0.26.0", "target-lexicon 0.12.0", "thiserror", - "wasmparser 0.79.0", + "wasmparser 0.80.2", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "005d93174040af37fb8625f891cd9827afdad314261f7ec4ee61ec497d6e9d3c" +checksum = "ac42cb562a2f98163857605f02581d719a410c5abe93606128c59a10e84de85b" dependencies = [ + "anyhow", "cfg-if 1.0.0", - "cranelift-codegen 0.76.0", - "cranelift-entity 0.76.0", - "cranelift-wasm", + "cranelift-entity 0.77.0", "gimli 0.25.0", "indexmap", "log 0.4.14", "more-asserts", + "object 0.26.0", "serde", + "target-lexicon 0.12.0", "thiserror", - "wasmparser 0.79.0", + "wasmparser 0.80.2", + "wasmtime-types", ] [[package]] name = "wasmtime-jit" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0bf1dfb213a35d8f21aefae40e597fe72778a907011ffdff7affb029a02af9a" +checksum = "24f46dd757225f29a419be415ea6fb8558df9b0194f07e3a6a9c99d0e14dd534" dependencies = [ "addr2line", "anyhow", + "bincode", "cfg-if 1.0.0", - "cranelift-codegen 0.76.0", - "cranelift-entity 0.76.0", - "cranelift-frontend 0.76.0", - "cranelift-native", - "cranelift-wasm", "gimli 0.25.0", + "libc", "log 0.4.14", "more-asserts", "object 0.26.0", - "rayon", "region", "serde", "target-lexicon 0.12.0", "thiserror", - "wasmparser 0.79.0", - "wasmtime-cranelift", - "wasmtime-debug", + "wasmparser 0.80.2", "wasmtime-environ", - "wasmtime-obj", - "wasmtime-profiling", "wasmtime-runtime", "winapi 0.3.9", ] -[[package]] -name = "wasmtime-obj" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231491878e710c68015228c9f9fc5955fe5c96dbf1485c15f7bed55b622c83c" -dependencies = [ - "anyhow", - "more-asserts", - "object 0.26.0", - "target-lexicon 0.12.0", - "wasmtime-debug", - "wasmtime-environ", -] - -[[package]] -name = "wasmtime-profiling" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21486cfb5255c2069666c1f116f9e949d4e35c9a494f11112fa407879e42198d" -dependencies = [ - "anyhow", - "cfg-if 1.0.0", - "gimli 0.25.0", - "lazy_static", - "libc", - "object 0.26.0", - "scroll", - "serde", - "target-lexicon 0.12.0", - "wasmtime-environ", - "wasmtime-runtime", -] - [[package]] name = "wasmtime-runtime" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ddfdf32e0a20d81f48be9dacd31612bc61de5a174d1356fef806d300f507de" +checksum = "0122215a44923f395487048cb0a1d60b5b32c73aab15cf9364b798dbaff0996f" dependencies = [ "anyhow", "backtrace", @@ -11600,6 +11526,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "wasmtime-types" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9b01caf8a204ef634ebac99700e77ba716d3ebbb68a1abbc2ceb6b16dbec9e4" +dependencies = [ + "cranelift-entity 0.77.0", + "serde", + "thiserror", + "wasmparser 0.80.2", +] + [[package]] name = "wast" version = "38.0.0" diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 4c768b7f9c613..c7aa1200719de 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -318,14 +318,15 @@ pub fn create_wasm_runtime_with_code( WasmExecutionMethod::Compiled => sc_executor_wasmtime::create_runtime( blob, sc_executor_wasmtime::Config { - heap_pages: heap_pages as u32, - max_memory_pages: None, + heap_pages, + max_memory_size: None, allow_missing_func_imports, cache_path: cache_path.map(ToOwned::to_owned), semantics: sc_executor_wasmtime::Semantics { fast_instance_reuse: true, deterministic_stack_limit: None, canonicalize_nans: false, + parallel_compilation: true, }, }, host_functions, diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index c122b3ab0e696..a8ed01c203e33 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -23,8 +23,9 @@ sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-in sp-runtime-interface = { version = "4.0.0-dev", path = "../../../primitives/runtime-interface" } sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } sc-allocator = { version = "4.0.0-dev", path = "../../allocator" } -wasmtime = { version = "0.29.0", default-features = false, features = [ +wasmtime = { version = "0.30.0", default-features = false, features = [ "cache", + "cranelift", "jitdump", "parallel-compilation", ] } diff --git a/client/executor/wasmtime/src/imports.rs b/client/executor/wasmtime/src/imports.rs index a9ef6e1f58a70..a00ab14263e7f 100644 --- a/client/executor/wasmtime/src/imports.rs +++ b/client/executor/wasmtime/src/imports.rs @@ -22,10 +22,9 @@ use crate::{ }; use sc_executor_common::error::WasmError; use sp_wasm_interface::{Function, ValueType}; -use std::any::Any; +use std::{any::Any, convert::TryInto}; use wasmtime::{ - Caller, Extern, ExternType, Func, FuncType, ImportType, Limits, Memory, MemoryType, Module, - Trap, Val, + Caller, Extern, ExternType, Func, FuncType, ImportType, Memory, MemoryType, Module, Trap, Val, }; pub struct Imports { @@ -41,7 +40,7 @@ pub(crate) fn resolve_imports( store: &mut Store, module: &Module, host_functions: &[&'static dyn Function], - heap_pages: u32, + heap_pages: u64, allow_missing_func_imports: bool, ) -> Result { let mut externs = vec![]; @@ -83,7 +82,7 @@ fn import_name<'a, 'b: 'a>(import: &'a ImportType<'b>) -> Result<&'a str, WasmEr fn resolve_memory_import( store: &mut Store, import_ty: &ImportType, - heap_pages: u32, + heap_pages: u64, ) -> Result { let requested_memory_ty = match import_ty.ty() { ExternType::Memory(memory_ty) => memory_ty, @@ -97,8 +96,8 @@ fn resolve_memory_import( // Increment the min (a.k.a initial) number of pages by `heap_pages` and check if it exceeds the // maximum specified by the import. - let initial = requested_memory_ty.limits().min().saturating_add(heap_pages); - if let Some(max) = requested_memory_ty.limits().max() { + let initial = requested_memory_ty.minimum().saturating_add(heap_pages); + if let Some(max) = requested_memory_ty.maximum() { if initial > max { return Err(WasmError::Other(format!( "incremented number of pages by heap_pages (total={}) is more than maximum requested\ @@ -109,7 +108,27 @@ fn resolve_memory_import( } } - let memory_ty = MemoryType::new(Limits::new(initial, requested_memory_ty.limits().max())); + // Note that the return value of `maximum` and `minimum`, while a u64, + // will always fit into a u32 for 32-bit memories. + // 64-bit memories are part of the memory64 proposal for WebAssembly which is not standardized + // yet. + let minimum: u32 = initial.try_into().map_err(|_| { + WasmError::Other(format!( + "minimum number of memory pages ({}) doesn't fit into u32", + initial + )) + })?; + let maximum: Option = match requested_memory_ty.maximum() { + Some(max) => Some(max.try_into().map_err(|_| { + WasmError::Other(format!( + "maximum number of memory pages ({}) doesn't fit into u32", + max + )) + })?), + None => None, + }; + + let memory_ty = MemoryType::new(minimum, maximum); let memory = Memory::new(store, memory_ty).map_err(|e| { WasmError::Other(format!( "failed to create a memory during resolving of memory import: {}", diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index ccfbb912b9a69..2b8508ee2b07f 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -154,7 +154,7 @@ impl InstanceWrapper { pub fn new( module: &Module, imports: &Imports, - heap_pages: u32, + heap_pages: u64, mut ctx: impl AsContextMut, ) -> Result { let instance = Instance::new(&mut ctx, module, &imports.externs) diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index a62356357b1f4..bd113c3383838 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -77,7 +77,7 @@ struct InstanceCreator { store: Store, module: Arc, imports: Arc, - heap_pages: u32, + heap_pages: u64, } impl InstanceCreator { @@ -130,15 +130,15 @@ pub struct WasmtimeRuntime { impl WasmtimeRuntime { /// Creates the store respecting the set limits. fn new_store(&self) -> Store { - let limits = if let Some(max_memory_pages) = self.config.max_memory_pages { - wasmtime::StoreLimitsBuilder::new().memory_pages(max_memory_pages).build() + let limits = if let Some(max_memory_size) = self.config.max_memory_size { + wasmtime::StoreLimitsBuilder::new().memory_size(max_memory_size).build() } else { Default::default() }; let mut store = Store::new(&self.engine, StoreData { limits, host_state: None }); - if self.config.max_memory_pages.is_some() { + if self.config.max_memory_size.is_some() { store.limiter(|s| &mut s.limits); } @@ -350,6 +350,8 @@ fn common_config(semantics: &Semantics) -> std::result::Result std::result::Result, + pub max_memory_size: Option, /// The WebAssembly standard requires all imports of an instantiated module to be resolved, - /// othewise, the instantiation fails. If this option is set to `true`, then this behavior is + /// otherwise, the instantiation fails. If this option is set to `true`, then this behavior is /// overriden and imports that are requested by the module and not provided by the host /// functions will be resolved using stubs. These stubs will trap upon a call. pub allow_missing_func_imports: bool, diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index 2a8bcc0b01b04..261afba0c6bc9 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -28,8 +28,8 @@ struct RuntimeBuilder { fast_instance_reuse: bool, canonicalize_nans: bool, deterministic_stack: bool, - heap_pages: u32, - max_memory_pages: Option, + heap_pages: u64, + max_memory_size: Option, } impl RuntimeBuilder { @@ -42,7 +42,7 @@ impl RuntimeBuilder { canonicalize_nans: false, deterministic_stack: false, heap_pages: 1024, - max_memory_pages: None, + max_memory_size: None, } } @@ -58,8 +58,8 @@ impl RuntimeBuilder { self.deterministic_stack = deterministic_stack; } - fn max_memory_pages(&mut self, max_memory_pages: Option) { - self.max_memory_pages = max_memory_pages; + fn max_memory_size(&mut self, max_memory_size: Option) { + self.max_memory_size = max_memory_size; } fn build(self) -> Arc { @@ -82,7 +82,7 @@ impl RuntimeBuilder { blob, crate::Config { heap_pages: self.heap_pages, - max_memory_pages: self.max_memory_pages, + max_memory_size: self.max_memory_size, allow_missing_func_imports: true, cache_path: None, semantics: crate::Semantics { @@ -95,6 +95,7 @@ impl RuntimeBuilder { false => None, }, canonicalize_nans: self.canonicalize_nans, + parallel_compilation: true, }, }, { @@ -171,13 +172,13 @@ fn test_stack_depth_reaching() { #[test] fn test_max_memory_pages() { fn try_instantiate( - max_memory_pages: Option, + max_memory_size: Option, wat: &'static str, ) -> Result<(), Box> { let runtime = { let mut builder = RuntimeBuilder::new_on_demand(); builder.use_wat(wat); - builder.max_memory_pages(max_memory_pages); + builder.max_memory_size(max_memory_size); builder.build() }; let mut instance = runtime.new_instance()?; @@ -185,6 +186,8 @@ fn test_max_memory_pages() { Ok(()) } + const WASM_PAGE_SIZE: usize = 65536; + // check the old behavior if preserved. That is, if no limit is set we allow 4 GiB of memory. try_instantiate( None, @@ -213,9 +216,9 @@ fn test_max_memory_pages() { // max is not specified, therefore it's implied to be 65536 pages (4 GiB). // - // max_memory_pages = 1 (initial) + 1024 (heap_pages) + // max_memory_size = (1 (initial) + 1024 (heap_pages)) * WASM_PAGE_SIZE try_instantiate( - Some(1 + 1024), + Some((1 + 1024) * WASM_PAGE_SIZE), r#" (module @@ -233,7 +236,7 @@ fn test_max_memory_pages() { // max is specified explicitly to 2048 pages. try_instantiate( - Some(1 + 1024), + Some((1 + 1024) * WASM_PAGE_SIZE), r#" (module @@ -251,7 +254,7 @@ fn test_max_memory_pages() { // memory grow should work as long as it doesn't exceed 1025 pages in total. try_instantiate( - Some(0 + 1024 + 25), + Some((0 + 1024 + 25) * WASM_PAGE_SIZE), r#" (module (import "env" "memory" (memory 0)) ;; <- zero starting pages. @@ -280,7 +283,7 @@ fn test_max_memory_pages() { // We start with 1025 pages and try to grow at least one. try_instantiate( - Some(1 + 1024), + Some((1 + 1024) * WASM_PAGE_SIZE), r#" (module (import "env" "memory" (memory 1)) ;; <- initial=1, meaning after heap pages mount the From 90dd23e78851605180f3dc3bfcf43e2800354f79 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 12 Oct 2021 20:28:11 +0100 Subject: [PATCH 0122/1472] documentation for recovery of emergency phase (#9989) * documentation for recovery of emergency phase * Update frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Alexander Popiak * Update frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Alexander Popiak Co-authored-by: Alexander Popiak --- .../election-provider-multi-phase/src/lib.rs | 51 +++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 9508b3a7c83fe..a7863fafa7747 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -67,11 +67,11 @@ //! origin can not bail out in any way, if their solution is queued. //! //! Upon the end of the signed phase, the solutions are examined from best to worse (i.e. `pop()`ed -//! until drained). Each solution undergoes an expensive `Pallet::feasibility_check`, which -//! ensures the score claimed by this score was correct, and it is valid based on the election data -//! (i.e. votes and candidates). At each step, if the current best solution passes the feasibility -//! check, it is considered to be the best one. The sender of the origin is rewarded, and the rest -//! of the queued solutions get their deposit back and are discarded, without being checked. +//! until drained). Each solution undergoes an expensive `Pallet::feasibility_check`, which ensures +//! the score claimed by this score was correct, and it is valid based on the election data (i.e. +//! votes and candidates). At each step, if the current best solution passes the feasibility check, +//! it is considered to be the best one. The sender of the origin is rewarded, and the rest of the +//! queued solutions get their deposit back and are discarded, without being checked. //! //! The following example covers all of the cases at the end of the signed phase: //! @@ -121,17 +121,35 @@ //! //! If, for any of the below reasons: //! -//! 1. No signed or unsigned solution submitted & Fallback is `None` or failed -//! 2. Internal error +//! 1. No **signed** or **unsigned** solution submitted, and no successful [`Config::Fallback`] is +//! provided +//! 2. Any other unforeseen internal error //! //! A call to `T::ElectionProvider::elect` is made, and `Ok(_)` cannot be returned, then the pallet //! proceeds to the [`Phase::Emergency`]. During this phase, any solution can be submitted from -//! [`Config::ForceOrigin`], without any checking. Once submitted, the forced solution is kept in -//! [`QueuedSolution`] until the next call to `T::ElectionProvider::elect`, where it is returned and -//! [`Phase`] goes back to `Off`. +//! [`Config::ForceOrigin`], without any checking, via [`Pallet::set_emergency_election_result`] +//! transaction. Hence, `[`Config::ForceOrigin`]` should only be set to a trusted origin, such as +//! the council or root. Once submitted, the forced solution is kept in [`QueuedSolution`] until the +//! next call to `T::ElectionProvider::elect`, where it is returned and [`Phase`] goes back to +//! `Off`. //! //! This implies that the user of this pallet (i.e. a staking pallet) should re-try calling -//! `T::ElectionProvider::elect` in case of error until `OK(_)` is returned. +//! `T::ElectionProvider::elect` in case of error, until `OK(_)` is returned. +//! +//! To generate an emergency solution, one must only provide one argument: [`Supports`]. This is +//! essentially a collection of elected winners for the election, and voters who support them. The +//! supports can be generated by any means. In the simplest case, it could be manual. For example, +//! in the case of massive network failure or misbehaviour, [`Config::ForceOrigin`] might decide to +//! select only a small number of emergency winners (which would greatly restrict the next validator +//! set, if this pallet is used with `pallet-staking`). If the failure is for other technical +//! reasons, then a simple and safe way to generate supports is using the staking-miner binary +//! provided in the Polkadot repository. This binary has a subcommand named `emergency-solution` +//! which is capable of connecting to a live network, and generating appropriate `supports` using a +//! standard algorithm, and outputting the `supports` in hex format, ready for submission. Note that +//! while this binary lives in the Polkadot repository, this particular subcommand of it can work +//! against any substrate based-chain. +//! +//! See the `staking-miner` documentation in the Polkadot repository for more information. //! //! ## Feasible Solution (correct solution) //! @@ -146,16 +164,16 @@ //! //! ## Accuracy //! -//! The accuracy of the election is configured via -//! [`SolutionAccuracyOf`] which is the accuracy that the submitted solutions must adhere to. +//! The accuracy of the election is configured via [`SolutionAccuracyOf`] which is the accuracy that +//! the submitted solutions must adhere to. //! //! Note that the accuracy is of great importance. The offchain solution should be as small as //! possible, reducing solutions size/weight. //! //! ## Error types //! -//! This pallet provides a verbose error system to ease future debugging and debugging. The -//! overall hierarchy of errors is as follows: +//! This pallet provides a verbose error system to ease future debugging and debugging. The overall +//! hierarchy of errors is as follows: //! //! 1. [`pallet::Error`]: These are the errors that can be returned in the dispatchables of the //! pallet, either signed or unsigned. Since decomposition with nested enums is not possible @@ -173,6 +191,9 @@ //! //! ## Future Plans //! +//! **Emergency-phase recovery script**: This script should be taken out of staking-miner in +//! polkadot and ideally live in `substrate/utils/frame/elections`. +//! //! **Challenge Phase**. We plan on adding a third phase to the pallet, called the challenge phase. //! This is a phase in which no further solutions are processed, and the current best solution might //! be challenged by anyone (signed or unsigned). The main plan here is to enforce the solution to From 51361fd3ef16f5df28e8af9ba04078246f13fbfe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Oct 2021 06:49:17 +0000 Subject: [PATCH 0123/1472] Bump parity-scale-codec from 2.2.0 to 2.3.1 (#9998) * Bump parity-scale-codec from 2.2.0 to 2.3.1 Bumps [parity-scale-codec](https://github.com/paritytech/parity-scale-codec) from 2.2.0 to 2.3.1. - [Release notes](https://github.com/paritytech/parity-scale-codec/releases) - [Changelog](https://github.com/paritytech/parity-scale-codec/blob/master/CHANGELOG.md) - [Commits](https://github.com/paritytech/parity-scale-codec/compare/v2.2...parity-scale-codec-v2.3.1) --- updated-dependencies: - dependency-name: parity-scale-codec dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update UI test expectations * Update UI test expectations Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Keith Yeung --- Cargo.lock | 8 +++--- client/cli/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- .../call_argument_invalid_bound_2.stderr | 27 +++++++++++++------ .../npos-elections/solution-type/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 7 files changed, 28 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d9f7339588742..50a962983f281 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6158,9 +6158,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8975095a2a03bbbdc70a74ab11a4f76a6d0b84680d87c68d722531b0ac28e8a9" +checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" dependencies = [ "arrayvec 0.7.0", "bitvec 0.20.2", @@ -6172,9 +6172,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40dbbfef7f0a1143c5b06e0d76a6278e25dac0bc1af4be51a0fbb73f07e7ad09" +checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" dependencies = [ "proc-macro-crate 1.0.0", "proc-macro2", diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index ee72958f74d89..b32e985b518c0 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -19,7 +19,7 @@ tokio = { version = "1.10", features = [ "signal", "rt-multi-thread" ] } futures = "0.3.9" fdlimit = "0.2.1" libp2p = "0.39.1" -parity-scale-codec = "2.0.0" +parity-scale-codec = "2.3.1" hex = "0.4.2" rand = "0.7.3" tiny-bip39 = "0.8.2" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 7fdd91e557ab7..45f85f46ddffd 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -23,7 +23,7 @@ futures-timer = "3.0.1" log = "0.4.8" parking_lot = "0.11.1" rand = "0.8.4" -parity-scale-codec = { version = "2.0.0", features = ["derive"] } +parity-scale-codec = { version = "2.3.1", features = ["derive"] } sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index d267d2535f8c2..fc42368a10aea 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -41,5 +41,5 @@ sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-executor = { version = "0.10.0-dev", path = "../../executor" } sp-panic-handler = { version = "3.0.0", path = "../../../primitives/panic-handler" } -parity-scale-codec = "2.0.0" +parity-scale-codec = "2.3.1" sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index c9ff843103b3b..15c611f4918d0 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -32,17 +32,28 @@ help: consider further restricting this bound | ^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is not satisfied - --> $DIR/call_argument_invalid_bound_2.rs:20:36 + --> $DIR/call_argument_invalid_bound_2.rs:1:1 | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar` +1 | #[frame_support::pallet] + | ^----------------------- + | | + | _in this procedural macro expansion + | | +2 | | mod pallet { +3 | | use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; +4 | | use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; +... | +16 | | +17 | | #[pallet::call] + | |__________________^ the trait `WrapperTypeEncode` is not implemented for `::Bar` | - ::: $CARGO/parity-scale-codec-2.2.0/src/codec.rs + ::: $CARGO/parity-scale-codec-2.3.1/src/codec.rs | - | fn encode_to(&self, dest: &mut T) { - | ------ required by this bound in `encode_to` + | fn encode_to(&self, dest: &mut T) { + | ------ required by this bound in `encode_to` | = note: required because of the requirements on the impl of `Encode` for `::Bar` + = note: this error originates in the derive macro `frame_support::codec::Encode` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied --> $DIR/call_argument_invalid_bound_2.rs:20:36 @@ -50,9 +61,9 @@ error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is 20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` | - ::: $CARGO/parity-scale-codec-2.2.0/src/codec.rs + ::: $CARGO/parity-scale-codec-2.3.1/src/codec.rs | | fn decode(input: &mut I) -> Result; - | ----- required by this bound in `pallet::_::_parity_scale_codec::Decode::decode` + | ----- required by this bound in `parity_scale_codec::Decode::decode` | = note: required because of the requirements on the impl of `Decode` for `::Bar` diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index 5cbf0b6481816..8eb9c26564f51 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -21,7 +21,7 @@ proc-macro2 = "1.0.29" proc-macro-crate = "1.0.0" [dev-dependencies] -parity-scale-codec = "2.0.1" +parity-scale-codec = "2.3.1" scale-info = "1.0" sp-arithmetic = { path = "../../arithmetic", version = "4.0.0-dev" } # used by generate_solution_type: diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index b20915335b976..6f4fd91126fb3 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.8" -parity-scale-codec = { version = "2.0.0" } +parity-scale-codec = { version = "2.3.1" } serde = "1.0.126" structopt = "0.3.8" From dc887374ba3c3d4acfd35cd7fa10263acadd3333 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 13 Oct 2021 18:49:34 +0800 Subject: [PATCH 0124/1472] Add TypeInfo (#10010) * add TypeInfo for DispatchTime * add TypeInfo for BoundedBTreeSet * add skip_type_params * add TypeInfo for BoundedSlice * add skip_type_params --- frame/support/src/storage/bounded_btree_set.rs | 3 ++- frame/support/src/storage/bounded_vec.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index f74ff12854a58..ecfb0bdbd261f 100644 --- a/frame/support/src/storage/bounded_btree_set.rs +++ b/frame/support/src/storage/bounded_btree_set.rs @@ -31,7 +31,8 @@ use sp_std::{ /// /// Unlike a standard `BTreeSet`, there is an enforced upper limit to the number of items in the /// set. All internal operations ensure this bound is respected. -#[derive(Encode)] +#[derive(Encode, scale_info::TypeInfo)] +#[scale_info(skip_type_params(S))] pub struct BoundedBTreeSet(BTreeSet, PhantomData); impl Decode for BoundedBTreeSet diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index f353127969c5b..a60ed57cf2b9f 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -44,7 +44,8 @@ pub struct BoundedVec(Vec, PhantomData); /// A bounded slice. /// /// Similar to a `BoundedVec`, but not owned and cannot be decoded. -#[derive(Encode)] +#[derive(Encode, scale_info::TypeInfo)] +#[scale_info(skip_type_params(S))] pub struct BoundedSlice<'a, T, S>(&'a [T], PhantomData); // `BoundedSlice`s encode to something which will always decode into a `BoundedVec`, From c5c908795c80b223c7190d4c6f1bbdf3a9a10cbc Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 13 Oct 2021 12:12:26 +0100 Subject: [PATCH 0125/1472] allow remote-ext to exclude some keys (#10020) * allow remote-ext to exclude some keys * don't use deprecated, just remove. * rename --- utils/frame/remote-externalities/src/lib.rs | 90 +++++++++++++++---- .../cli/src/commands/execute_block.rs | 2 +- .../cli/src/commands/follow_chain.rs | 6 +- .../cli/src/commands/offchain_worker.rs | 2 +- .../cli/src/commands/on_runtime_upgrade.rs | 2 +- 5 files changed, 80 insertions(+), 22 deletions(-) diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 2052780286c66..733ec7c3200ad 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -160,13 +160,16 @@ impl Default for SnapshotConfig { /// Builder for remote-externalities. pub struct Builder { - /// Custom key-pairs to be injected into the externalities. - inject: Vec, + /// Custom key-pairs to be injected into the externalities. The *hashed* keys and values must + /// be given. + hashed_key_values: Vec, /// Storage entry key prefixes to be injected into the externalities. The *hashed* prefix must /// be given. hashed_prefixes: Vec>, /// Storage entry keys to be injected into the externalities. The *hashed* key must be given. hashed_keys: Vec>, + /// The keys that will be excluded from the final externality. The *hashed* key must be given. + hashed_blacklist: Vec>, /// connectivity mode, online or offline. mode: Mode, } @@ -176,10 +179,11 @@ pub struct Builder { impl Default for Builder { fn default() -> Self { Self { - inject: Default::default(), mode: Default::default(), + hashed_key_values: Default::default(), hashed_prefixes: Default::default(), hashed_keys: Default::default(), + hashed_blacklist: Default::default(), } } } @@ -435,12 +439,26 @@ impl Builder { }, }; - debug!( - target: LOG_TARGET, - "extending externalities with {} manually injected key-values", - self.inject.len() - ); - base_kv.extend(self.inject.clone()); + // inject manual key values. + if !self.hashed_key_values.is_empty() { + debug!( + target: LOG_TARGET, + "extending externalities with {} manually injected key-values", + self.hashed_key_values.len() + ); + base_kv.extend(self.hashed_key_values.clone()); + } + + // exclude manual key values. + if !self.hashed_blacklist.is_empty() { + debug!( + target: LOG_TARGET, + "excluding externalities from {} keys", + self.hashed_blacklist.len() + ); + base_kv.retain(|(k, _)| !self.hashed_blacklist.contains(&k.0)) + } + Ok(base_kv) } } @@ -453,13 +471,12 @@ impl Builder { } /// Inject a manual list of key and values to the storage. - pub fn inject_key_value(mut self, injections: &[KeyPair]) -> Self { + pub fn inject_hashed_key_value(mut self, injections: &[KeyPair]) -> Self { for i in injections { - self.inject.push(i.clone()); + self.hashed_key_values.push(i.clone()); } self } - /// Inject a hashed prefix. This is treated as-is, and should be pre-hashed. /// /// This should be used to inject a "PREFIX", like a storage (double) map. @@ -476,6 +493,13 @@ impl Builder { self } + /// Blacklist this hashed key from the final externalities. This is treated as-is, and should be + /// pre-hashed. + pub fn blacklist_hashed_key(mut self, hashed: &[u8]) -> Self { + self.hashed_blacklist.push(hashed.to_vec()); + self + } + /// Configure a state snapshot to be used. pub fn mode(mut self, mode: Mode) -> Self { self.mode = mode; @@ -541,12 +565,44 @@ mod tests { .expect("Can't read state snapshot file") .execute_with(|| {}); } + + #[tokio::test] + async fn can_exclude_from_cache() { + init_logger(); + + // get the first key from the cache file. + let some_key = Builder::::new() + .mode(Mode::Offline(OfflineConfig { + state_snapshot: SnapshotConfig::new("test_data/proxy_test"), + })) + .build() + .await + .expect("Can't read state snapshot file") + .execute_with(|| { + let key = + sp_io::storage::next_key(&[]).expect("some key must exist in the snapshot"); + assert!(sp_io::storage::get(&key).is_some()); + key + }); + + Builder::::new() + .mode(Mode::Offline(OfflineConfig { + state_snapshot: SnapshotConfig::new("test_data/proxy_test"), + })) + .blacklist_hashed_key(&some_key) + .build() + .await + .expect("Can't read state snapshot file") + .execute_with(|| assert!(sp_io::storage::get(&some_key).is_none())); + } } #[cfg(all(test, feature = "remote-test"))] mod remote_tests { use super::test_prelude::*; + const REMOTE_INACCESSIBLE: &'static str = "Can't reach the remote node. Is it running?"; + #[tokio::test] async fn can_build_one_pallet() { init_logger(); @@ -557,7 +613,7 @@ mod remote_tests { })) .build() .await - .expect("Can't reach the remote node. Is it running?") + .expect(REMOTE_INACCESSIBLE) .execute_with(|| {}); } @@ -575,7 +631,7 @@ mod remote_tests { })) .build() .await - .expect("Can't reach the remote node. Is it running?") + .expect(REMOTE_INACCESSIBLE) .execute_with(|| {}); } @@ -599,7 +655,7 @@ mod remote_tests { })) .build() .await - .expect("Can't reach the remote node. Is it running?") + .expect(REMOTE_INACCESSIBLE) .execute_with(|| { // Gav's polkadot account. 99% this will be in the council. let gav_polkadot = @@ -625,7 +681,7 @@ mod remote_tests { })) .build() .await - .expect("Can't reach the remote node. Is it running?") + .expect(REMOTE_INACCESSIBLE) .execute_with(|| {}); let to_delete = std::fs::read_dir(SnapshotConfig::default().path) @@ -648,7 +704,7 @@ mod remote_tests { Builder::::new() .build() .await - .expect("Can't reach the remote node. Is it running?") + .expect(REMOTE_INACCESSIBLE) .execute_with(|| {}); } } diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index 19422db90119f..216c63d00525d 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -143,7 +143,7 @@ where let builder = if command.overwrite_wasm_code { let (code_key, code) = extract_code(&config.chain_spec)?; - builder.inject_key_value(&[(code_key, code)]) + builder.inject_hashed_key_value(&[(code_key, code)]) } else { builder.inject_hashed_key(well_known_keys::CODE) }; diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index 0526f5d327fb2..9125db13c78f9 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -112,8 +112,10 @@ where ..Default::default() })); - let new_ext = - builder.inject_key_value(&[(code_key.clone(), code.clone())]).build().await?; + let new_ext = builder + .inject_hashed_key_value(&[(code_key.clone(), code.clone())]) + .build() + .await?; log::info!( target: LOG_TARGET, "initialized state externalities at {:?}, storage root {:?}", diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index 6f37e4b3849fa..22120ef4b5fe4 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -132,7 +132,7 @@ where let builder = if command.overwrite_wasm_code { let (code_key, code) = extract_code(&config.chain_spec)?; - builder.inject_key_value(&[(code_key, code)]) + builder.inject_hashed_key_value(&[(code_key, code)]) } else { builder.inject_hashed_key(well_known_keys::CODE) }; diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 86f5548b8aafa..8de3cb3a32005 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -54,7 +54,7 @@ where let ext = { let builder = command.state.builder::()?; let (code_key, code) = extract_code(&config.chain_spec)?; - builder.inject_key_value(&[(code_key, code)]).build().await? + builder.inject_hashed_key_value(&[(code_key, code)]).build().await? }; if let Some(uri) = command.state.live_uri() { From 9689a131a595b99e60f134d7634f5f4d71969410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 13 Oct 2021 13:31:36 +0200 Subject: [PATCH 0126/1472] Ensure we don't create gap epochs when importing multiple genesis epochs (#10019) The babe `authoring_blocks` test was flaky because it could happen that we imported the first block multiple times. This lead to import the genesis epoch multiples times. `EpochChanges` was assuming that importing a genesis epoch while there was already an imported epoch means that there is a "gap". However, this wasn't true as we just imported 2 genesis epochs. The bug is solved by checking that the already imported epochs are not all genesis epochs. --- client/consensus/epochs/src/lib.rs | 81 +++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index 661cb900ae6e9..c1d0bd1d04050 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -229,13 +229,20 @@ impl ViableEpochDescriptor { /// Persisted epoch stored in EpochChanges. #[derive(Clone, Encode, Decode, Debug)] -pub enum PersistedEpoch { +pub enum PersistedEpoch { /// Genesis persisted epoch data. epoch_0, epoch_1. Genesis(E, E), /// Regular persisted epoch data. epoch_n. Regular(E), } +impl PersistedEpoch { + /// Returns if this is a genesis epoch. + pub fn is_genesis(&self) -> bool { + matches!(self, Self::Genesis(_, _)) + } +} + impl<'a, E: Epoch> From<&'a PersistedEpoch> for PersistedEpochHeader { fn from(epoch: &'a PersistedEpoch) -> Self { match epoch { @@ -748,7 +755,7 @@ where Err(e) => PersistedEpoch::Regular(e), } } - } else if !self.epochs.is_empty() && matches!(epoch, PersistedEpoch::Genesis(_, _)) { + } else if epoch.is_genesis() && !self.epochs.values().all(|e| e.is_genesis()) { // There's a genesis epoch imported when we already have an active epoch. // This happens after the warp sync as the ancient blocks download start. // We need to start tracking gap epochs here. @@ -1073,6 +1080,76 @@ mod tests { } } + /// Test that ensures that the gap is not enabled when we import multiple genesis blocks. + #[test] + fn gap_is_not_enabled_when_multiple_genesis_epochs_are_imported() { + // X + // / + // 0 - A + // + let is_descendent_of = |base: &Hash, block: &Hash| -> Result { + match (base, *block) { + (b"0", _) => Ok(true), + _ => Ok(false), + } + }; + + let duration = 100; + + let make_genesis = |slot| Epoch { start_slot: slot, duration }; + + let mut epoch_changes = EpochChanges::new(); + let next_descriptor = (); + + // insert genesis epoch for A + { + let genesis_epoch_a_descriptor = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 100) + .unwrap() + .unwrap(); + + let incremented_epoch = epoch_changes + .viable_epoch(&genesis_epoch_a_descriptor, &make_genesis) + .unwrap() + .increment(next_descriptor.clone()); + + epoch_changes + .import(&is_descendent_of, *b"A", 1, *b"0", incremented_epoch) + .unwrap(); + } + + // insert genesis epoch for X + { + let genesis_epoch_x_descriptor = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 1000) + .unwrap() + .unwrap(); + + let incremented_epoch = epoch_changes + .viable_epoch(&genesis_epoch_x_descriptor, &make_genesis) + .unwrap() + .increment(next_descriptor.clone()); + + epoch_changes + .import(&is_descendent_of, *b"X", 1, *b"0", incremented_epoch) + .unwrap(); + } + + // Clearing the gap should be a no-op. + epoch_changes.clear_gap(); + + // Check that both epochs are available. + epoch_changes + .epoch_data_for_child_of(&is_descendent_of, b"A", 1, 101, &make_genesis) + .unwrap() + .unwrap(); + + epoch_changes + .epoch_data_for_child_of(&is_descendent_of, b"X", 1, 1001, &make_genesis) + .unwrap() + .unwrap(); + } + #[test] fn gap_epochs_advance() { // 0 - 1 - 2 - 3 - .... 42 - 43 From 9d01cac45bb4db09f60eef98a26e28a408f5e0ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Oct 2021 19:17:15 +0200 Subject: [PATCH 0127/1472] Bump retain_mut from 0.1.3 to 0.1.4 (#10021) Bumps [retain_mut](https://github.com/upsuper/retain_mut) from 0.1.3 to 0.1.4. - [Release notes](https://github.com/upsuper/retain_mut/releases) - [Commits](https://github.com/upsuper/retain_mut/commits) --- updated-dependencies: - dependency-name: retain_mut 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/consensus/babe/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50a962983f281..74aa1e23a1716 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7238,9 +7238,9 @@ dependencies = [ [[package]] name = "retain_mut" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c17925a9027d298a4603d286befe3f9dc0e8ed02523141914eb628798d6e5b" +checksum = "448296241d034b96c11173591deaa1302f2c17b56092106c1f92c1bc0183a8c9" [[package]] name = "ring" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 65dfc57133206..dc937f1e3dbca 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -50,7 +50,7 @@ schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } rand = "0.7.2" merlin = "2.0" derive_more = "0.99.2" -retain_mut = "0.1.3" +retain_mut = "0.1.4" async-trait = "0.1.50" [dev-dependencies] diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 2184af819adf7..0871cadd5a02b 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -32,7 +32,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-utils = { version = "4.0.0-dev", path = "../utils" } serde = { version = "1.0.126", features = ["derive"] } linked-hash-map = "0.5.4" -retain_mut = "0.1.3" +retain_mut = "0.1.4" [dev-dependencies] assert_matches = "1.3.0" From 30ee840367cae0b965ad9f3d0714cfafbe8d8511 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Oct 2021 18:36:29 +0000 Subject: [PATCH 0128/1472] Bump base58 from 0.1.0 to 0.2.0 (#10018) Bumps [base58](https://github.com/debris/base58) from 0.1.0 to 0.2.0. - [Release notes](https://github.com/debris/base58/releases) - [Commits](https://github.com/debris/base58/commits) --- updated-dependencies: - dependency-name: base58 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 | 4 ++-- primitives/core/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74aa1e23a1716..f15e363bfd6ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -440,9 +440,9 @@ checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" [[package]] name = "base58" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" [[package]] name = "base64" diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 0944fbef23349..4071dab71be5a 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -30,7 +30,7 @@ impl-serde = { version = "0.3.0", optional = true } wasmi = { version = "0.9.0", optional = true } hash-db = { version = "0.15.2", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } -base58 = { version = "0.1.0", optional = true } +base58 = { version = "0.2.0", optional = true } rand = { version = "0.7.3", optional = true, features = ["small_rng"] } substrate-bip39 = { version = "0.4.2", optional = true } tiny-bip39 = { version = "0.8.2", optional = true } From 383a26c15058efcb6c0fe27fdd101efebefd3860 Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Wed, 13 Oct 2021 12:55:51 -0600 Subject: [PATCH 0129/1472] Move template to `homepage = "https://substrate.io/"` , correct links (#10006) * move to https://docs.substrate.io/ * cargo to https://docs.substrate.io/ homepage * Update bin/node-template/pallets/template/src/lib.rs Co-authored-by: Squirrel * homepage = "https://docs.substrate.io/" Co-authored-by: Squirrel --- bin/node-template/README.md | 38 +++++++++---------- bin/node-template/docs/rust-setup.md | 5 ++- bin/node-template/node/Cargo.toml | 2 +- bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/pallets/template/src/lib.rs | 10 ++--- bin/node-template/runtime/Cargo.toml | 2 +- bin/node-template/runtime/src/lib.rs | 2 +- 7 files changed, 31 insertions(+), 30 deletions(-) diff --git a/bin/node-template/README.md b/bin/node-template/README.md index e618b13c2a2f0..2397c57363b77 100644 --- a/bin/node-template/README.md +++ b/bin/node-template/README.md @@ -1,14 +1,14 @@ # Substrate Node Template -[![Try on playground](https://img.shields.io/badge/Playground-Node_Template-brightgreen?logo=Parity%20Substrate)](https://playground.substrate.dev/?deploy=node-template) [![Matrix](https://img.shields.io/matrix/substrate-technical:matrix.org)](https://matrix.to/#/#substrate-technical:matrix.org) +[![Try on playground](https://img.shields.io/badge/Playground-Node_Template-brightgreen?logo=Parity%20Substrate)](https://docs.substrate.io/playground/) [![Matrix](https://img.shields.io/matrix/substrate-technical:matrix.org)](https://matrix.to/#/#substrate-technical:matrix.org) A fresh FRAME-based [Substrate](https://www.substrate.io/) node, ready for hacking :rocket: ## Getting Started Follow the steps below to get started with the Node Template, or get it up and running right from -your browser in just a few clicks using [Playground](https://playground.substrate.dev/) -:hammer_and_wrench: +your browser in just a few clicks using +the [Substrate Playground](https://docs.substrate.io/playground/) :hammer_and_wrench: ### Using Nix @@ -19,7 +19,7 @@ lorri `lorri shell`. ### Rust Setup -First, complete the [basic Rust setup instructions](./doc/rust-setup.md). +First, complete the [basic Rust setup instructions](./docs/rust-setup.md). ### Run @@ -83,7 +83,7 @@ local node template. ### Multi-Node Local Testnet If you want to see the multi-node consensus algorithm in action, refer to our -[Start a Private Network tutorial](https://substrate.dev/docs/en/tutorials/start-a-private-network/). +[Start a Private Network tutorial](https://docs.substrate.io/tutorials/v3/private-network). ## Template Structure @@ -98,7 +98,7 @@ Substrate-based blockchain nodes expose a number of capabilities: - Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking stack to allow the nodes in the network to communicate with one another. - Consensus: Blockchains must have a way to come to - [consensus](https://substrate.dev/docs/en/knowledgebase/advanced/consensus) on the state of the + [consensus](https://docs.substrate.io/v3/advanced/consensus) on the state of the network. Substrate makes it possible to supply custom consensus engines and also ships with several consensus mechanisms that have been built on top of [Web3 Foundation research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html). @@ -107,21 +107,21 @@ Substrate-based blockchain nodes expose a number of capabilities: There are several files in the `node` directory - take special note of the following: - [`chain_spec.rs`](./node/src/chain_spec.rs): A - [chain specification](https://substrate.dev/docs/en/knowledgebase/integrate/chain-spec) is a + [chain specification](https://docs.substrate.io/v3/runtime/chain-specs) is a source code file that defines a Substrate chain's initial (genesis) state. Chain specifications are useful for development and testing, and critical when architecting the launch of a production chain. Take note of the `development_config` and `testnet_genesis` functions, which are used to define the genesis state for the local development chain configuration. These functions identify some - [well-known accounts](https://substrate.dev/docs/en/knowledgebase/integrate/subkey#well-known-keys) + [well-known accounts](https://docs.substrate.io/v3/tools/subkey#well-known-keys) and use them to configure the blockchain's initial state. - [`service.rs`](./node/src/service.rs): This file defines the node implementation. Take note of the libraries that this file imports and the names of the functions it invokes. In particular, there are references to consensus-related topics, such as the - [longest chain rule](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#longest-chain-rule), - the [Aura](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#aura) block authoring + [longest chain rule](https://docs.substrate.io/v3/advanced/consensus#longest-chain-rule), + the [Aura](https://docs.substrate.io/v3/advanced/consensus#aura) block authoring mechanism and the - [GRANDPA](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#grandpa) finality + [GRANDPA](https://docs.substrate.io/v3/advanced/consensus#grandpa) finality gadget. After the node has been [built](#build), refer to the embedded documentation to learn more about the @@ -134,14 +134,14 @@ capabilities and configuration parameters that it exposes: ### Runtime In Substrate, the terms -"[runtime](https://substrate.dev/docs/en/knowledgebase/getting-started/glossary#runtime)" and -"[state transition function](https://substrate.dev/docs/en/knowledgebase/getting-started/glossary#stf-state-transition-function)" +"[runtime](https://docs.substrate.io/v3/getting-started/glossary#runtime)" and +"[state transition function](https://docs.substrate.io/v3/getting-started/glossary#state-transition-function-stf)" are analogous - they refer to the core logic of the blockchain that is responsible for validating blocks and executing the state changes they define. The Substrate project in this repository uses -the [FRAME](https://substrate.dev/docs/en/knowledgebase/runtime/frame) framework to construct a +the [FRAME](https://docs.substrate.io/v3/runtime/frame) framework to construct a blockchain runtime. FRAME allows runtime developers to declare domain-specific logic in modules called "pallets". At the heart of FRAME is a helpful -[macro language](https://substrate.dev/docs/en/knowledgebase/runtime/macros) that makes it easy to +[macro language](https://docs.substrate.io/v3/runtime/macros) that makes it easy to create pallets and flexibly compose them to create blockchains that can address [a variety of needs](https://www.substrate.io/substrate-users/). @@ -153,7 +153,7 @@ the following: - The pallets are composed into a single runtime by way of the [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html) macro, which is part of the core - [FRAME Support](https://substrate.dev/docs/en/knowledgebase/runtime/frame#support-library) + [FRAME Support](https://docs.substrate.io/v3/runtime/frame#support-crate) library. ### Pallets @@ -165,13 +165,13 @@ template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs A FRAME pallet is compromised of a number of blockchain primitives: - Storage: FRAME defines a rich set of powerful - [storage abstractions](https://substrate.dev/docs/en/knowledgebase/runtime/storage) that makes + [storage abstractions](https://docs.substrate.io/v3/runtime/storage) that makes it easy to use Substrate's efficient key-value database to manage the evolving state of a blockchain. - Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched) from outside of the runtime in order to update its state. -- Events: Substrate uses [events](https://substrate.dev/docs/en/knowledgebase/runtime/events) to - notify users of important changes in the runtime. +- Events: Substrate uses [events and errors](https://docs.substrate.io/v3/runtime/events-and-errors) + to notify users of important changes in the runtime. - Errors: When a dispatchable fails, it returns an error. - Config: The `Config` configuration interface is used to define the types and parameters upon which a FRAME pallet depends. diff --git a/bin/node-template/docs/rust-setup.md b/bin/node-template/docs/rust-setup.md index 34f6e43e7f0dd..4b96da1146b8e 100644 --- a/bin/node-template/docs/rust-setup.md +++ b/bin/node-template/docs/rust-setup.md @@ -12,8 +12,9 @@ commands for Rust's toolchains will be the same for all supported, Unix-based op ## Unix-Based Operating Systems Substrate development is easiest on Unix-based operating systems like macOS or Linux. The examples -in the Substrate [Tutorials](https://substrate.dev/tutorials) and [Recipes](https://substrate.dev/recipes/) -use Unix-style terminals to demonstrate how to interact with Substrate from the command line. +in the Substrate [Tutorials](https://docs.substrate.io/tutorials/v3) and +[How-to Guides](https://docs.substrate.io/how-to-guides/v3) use Unix-style terminals to demonstrate +how to interact with Substrate from the command line. ### macOS diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index c8f2b52f112f5..57d9c5f3f71e0 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -3,7 +3,7 @@ name = "node-template" version = "3.0.0" description = "A fresh FRAME-based Substrate node, ready for hacking." authors = ["Substrate DevHub "] -homepage = "https://substrate.dev" +homepage = "https://substrate.io/" edition = "2018" license = "Unlicense" publish = false diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index dccb37c6540c3..7ea5628b97c1e 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -3,7 +3,7 @@ name = 'pallet-template' version = "3.0.0" description = "FRAME pallet template for defining custom runtime logic." authors = ['Substrate DevHub '] -homepage = "https://substrate.dev" +homepage = "https://substrate.io/" edition = '2018' license = "Unlicense" publish = false diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index ee3ca695b64da..18599168f1a63 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -2,7 +2,7 @@ /// Edit this file to define custom logic or remove it if it is not needed. /// Learn more about FRAME and the core library of Substrate FRAME pallets: -/// +/// pub use pallet::*; #[cfg(test)] @@ -31,15 +31,15 @@ pub mod pallet { pub struct Pallet(_); // The pallet's runtime storage items. - // https://substrate.dev/docs/en/knowledgebase/runtime/storage + // https://docs.substrate.io/v3/runtime/storage #[pallet::storage] #[pallet::getter(fn something)] // Learn more about declaring storage items: - // https://substrate.dev/docs/en/knowledgebase/runtime/storage#declaring-storage-items + // https://docs.substrate.io/v3/runtime/storage#declaring-storage-items pub type Something = StorageValue<_, u32>; // Pallets use events to inform users when important changes are made. - // https://substrate.dev/docs/en/knowledgebase/runtime/events + // https://docs.substrate.io/v3/runtime/events-and-errors #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -68,7 +68,7 @@ pub mod pallet { pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { // Check that the extrinsic was signed and get the signer. // This function will return an error if the extrinsic is not signed. - // https://substrate.dev/docs/en/knowledgebase/runtime/origin + // https://docs.substrate.io/v3/runtime/origins let who = ensure_signed(origin)?; // Update storage. diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 3179a2cc4ff53..e9f557f3fb5a4 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -3,7 +3,7 @@ name = "node-template-runtime" version = "3.0.0" description = 'A fresh FRAME-based Substrate runtime, ready for hacking.' authors = ["Substrate DevHub "] -homepage = "https://substrate.dev" +homepage = "https://substrate.io/" edition = "2018" license = "Unlicense" publish = false diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index e11840b5813d4..4b49cb48ef352 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -87,7 +87,7 @@ pub mod opaque { } // To learn more about runtime versioning and what each of the following value means: -// https://substrate.dev/docs/en/knowledgebase/runtime/upgrades#runtime-versioning +// https://docs.substrate.io/v3/runtime/upgrades#runtime-versioning #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node-template"), From 66296a0af0aede07c27104e6174a3534b15f14aa Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Wed, 13 Oct 2021 12:56:56 -0600 Subject: [PATCH 0130/1472] Migrate to `docs.substrate.io` throughout (#10007) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * all reverences of substrate.dev replaced with *correct* docs.substrate.io links * fix links in non-cargo files, errors in replace * homepage https://substrate.io * cargo +nightly fmt * FMT Co-authored-by: Bastian Köcher --- README.md | 6 +++--- bin/node/cli/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- bin/node/inspect/Cargo.toml | 2 +- bin/node/primitives/Cargo.toml | 2 +- bin/node/rpc-client/Cargo.toml | 2 +- bin/node/rpc/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- bin/utils/chain-spec-builder/Cargo.toml | 2 +- bin/utils/subkey/Cargo.toml | 2 +- client/allocator/Cargo.toml | 2 +- client/api/Cargo.toml | 2 +- client/authority-discovery/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 2 +- client/block-builder/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/chain-spec/derive/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/epochs/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 2 +- client/consensus/uncles/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/executor/common/Cargo.toml | 2 +- client/executor/runtime-test/Cargo.toml | 2 +- client/executor/wasmi/Cargo.toml | 2 +- client/executor/wasmtime/Cargo.toml | 2 +- client/finality-grandpa-warp-sync/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/informant/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/light/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/src/service.rs | 5 +++-- client/network/test/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/proposer-metrics/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-api/src/state/mod.rs | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- client/state-db/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/tracing/proc-macro/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- client/utils/Cargo.toml | 2 +- frame/assets/Cargo.toml | 2 +- frame/atomic-swap/Cargo.toml | 2 +- frame/aura/Cargo.toml | 2 +- frame/authority-discovery/Cargo.toml | 2 +- frame/authorship/Cargo.toml | 2 +- frame/babe/Cargo.toml | 2 +- frame/bags-list/Cargo.toml | 2 +- frame/balances/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 2 +- frame/bounties/Cargo.toml | 2 +- frame/collective/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/README.md | 2 +- frame/contracts/common/Cargo.toml | 2 +- frame/contracts/proc-macro/Cargo.toml | 2 +- frame/contracts/rpc/Cargo.toml | 2 +- frame/contracts/rpc/runtime-api/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- frame/election-provider-multi-phase/Cargo.toml | 2 +- frame/election-provider-support/Cargo.toml | 2 +- frame/elections-phragmen/Cargo.toml | 2 +- frame/elections/Cargo.toml | 2 +- frame/example-offchain-worker/Cargo.toml | 2 +- frame/example-parallel/Cargo.toml | 2 +- frame/example/Cargo.toml | 2 +- frame/example/src/benchmarking.rs | 4 ++-- frame/example/src/lib.rs | 6 +++--- frame/executive/Cargo.toml | 2 +- frame/gilt/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/identity/Cargo.toml | 2 +- frame/im-online/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- frame/lottery/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- frame/merkle-mountain-range/primitives/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 2 +- frame/nicks/Cargo.toml | 2 +- frame/node-authorization/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/offences/benchmarking/Cargo.toml | 2 +- frame/proxy/Cargo.toml | 2 +- frame/randomness-collective-flip/Cargo.toml | 2 +- frame/recovery/Cargo.toml | 2 +- frame/scheduler/Cargo.toml | 2 +- frame/scored-pool/Cargo.toml | 2 +- frame/session/Cargo.toml | 2 +- frame/session/benchmarking/Cargo.toml | 2 +- frame/society/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/staking/reward-fn/Cargo.toml | 2 +- frame/sudo/Cargo.toml | 2 +- frame/sudo/README.md | 2 +- frame/sudo/src/lib.rs | 2 +- frame/support/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/src/pallet/expand/error.rs | 2 +- frame/support/procedural/src/pallet/expand/event.rs | 2 +- .../support/procedural/src/pallet/expand/genesis_config.rs | 2 +- frame/support/procedural/src/pallet/expand/mod.rs | 4 ++-- frame/support/procedural/src/pallet/expand/pallet_struct.rs | 2 +- frame/support/procedural/tools/Cargo.toml | 2 +- frame/support/procedural/tools/derive/Cargo.toml | 2 +- frame/support/src/dispatch.rs | 2 +- frame/support/src/storage/bounded_vec.rs | 2 +- frame/support/src/storage/weak_bounded_vec.rs | 2 +- frame/support/src/traits/misc.rs | 2 +- frame/support/test/Cargo.toml | 2 +- frame/support/test/pallet/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- frame/system/benchmarking/Cargo.toml | 2 +- frame/system/rpc/runtime-api/Cargo.toml | 2 +- frame/timestamp/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- frame/transaction-payment/rpc/Cargo.toml | 2 +- frame/transaction-payment/rpc/runtime-api/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- frame/try-runtime/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 2 +- frame/utility/Cargo.toml | 2 +- frame/vesting/Cargo.toml | 2 +- primitives/api/Cargo.toml | 2 +- primitives/api/proc-macro/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/application-crypto/Cargo.toml | 2 +- primitives/application-crypto/test/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/arithmetic/fuzzer/Cargo.toml | 2 +- primitives/authority-discovery/Cargo.toml | 2 +- primitives/authorship/Cargo.toml | 2 +- primitives/block-builder/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/consensus/aura/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/consensus/common/Cargo.toml | 2 +- primitives/consensus/pow/Cargo.toml | 2 +- primitives/consensus/slots/Cargo.toml | 2 +- primitives/consensus/vrf/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/database/Cargo.toml | 2 +- primitives/debug-derive/Cargo.toml | 2 +- primitives/externalities/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/inherents/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/keyring/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- primitives/maybe-compressed-blob/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- primitives/npos-elections/solution-type/Cargo.toml | 2 +- primitives/offchain/Cargo.toml | 2 +- primitives/panic-handler/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 2 +- primitives/runtime-interface/proc-macro/Cargo.toml | 2 +- .../runtime-interface/test-wasm-deprecated/Cargo.toml | 2 +- primitives/runtime-interface/test-wasm/Cargo.toml | 2 +- primitives/runtime-interface/test/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/sandbox/Cargo.toml | 2 +- primitives/serializer/Cargo.toml | 2 +- primitives/session/Cargo.toml | 2 +- primitives/staking/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/std/Cargo.toml | 2 +- primitives/storage/Cargo.toml | 2 +- primitives/tasks/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 2 +- primitives/timestamp/Cargo.toml | 2 +- primitives/tracing/Cargo.toml | 2 +- primitives/transaction-pool/Cargo.toml | 2 +- primitives/transaction-storage-proof/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 2 +- primitives/version/Cargo.toml | 2 +- primitives/version/proc-macro/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- ss58-registry.json | 2 +- test-utils/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/derive/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- test-utils/runtime/client/Cargo.toml | 2 +- test-utils/runtime/transaction-pool/Cargo.toml | 2 +- test-utils/test-crate/Cargo.toml | 2 +- utils/build-script-utils/Cargo.toml | 2 +- utils/fork-tree/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/frame-utilities-cli/Cargo.toml | 2 +- utils/frame/generate-bags/Cargo.toml | 2 +- utils/frame/generate-bags/node-runtime/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- utils/frame/try-runtime/cli/src/lib.rs | 4 ++-- utils/prometheus/Cargo.toml | 2 +- utils/wasm-builder/Cargo.toml | 2 +- 222 files changed, 231 insertions(+), 230 deletions(-) diff --git a/README.md b/README.md index a4d0b9c683575..b716794428a00 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ Substrate is a next-generation framework for blockchain innovation 🚀. ## Trying it out -Simply go to [substrate.dev](https://substrate.dev) and follow the -[installation](https://substrate.dev/docs/en/knowledgebase/getting-started/) instructions. You can -also try out one of the [tutorials](https://substrate.dev/en/tutorials). +Simply go to [docs.substrate.io](https://docs.substrate.io) and follow the +[installation](https://docs.substrate.io/v3/getting-started/overview) instructions. You can +also try out one of the [tutorials](https://docs.substrate.io/tutorials/). ## Contributions & Code of Conduct diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index a92c7a185b7ad..1d394dd952db0 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -7,7 +7,7 @@ build = "build.rs" edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" default-run = "substrate" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.wasm-pack.profile.release] diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index f283a913915f3..462bb034610e9 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Substrate node implementation in Rust." edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index 1570e5dbf8e44..6f526b896ba76 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -4,7 +4,7 @@ version = "0.9.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 12ec57e4d55b6..07c3aca6059f6 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -4,7 +4,7 @@ version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/bin/node/rpc-client/Cargo.toml b/bin/node/rpc-client/Cargo.toml index a5255769158a4..59695edb6fa26 100644 --- a/bin/node/rpc-client/Cargo.toml +++ b/bin/node/rpc-client/Cargo.toml @@ -4,7 +4,7 @@ version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 0cb606f79f086..4c7b15459cea9 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index b4e84aafec132..22ff0954e2458 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" build = "build.rs" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index d05d815121f88..e5d13189ac2fe 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Test utilities for Substrate node." edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" publish = true diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index 5bdf01badc3f4..bfbf2da57a6a0 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" publish = false diff --git a/bin/utils/subkey/Cargo.toml b/bin/utils/subkey/Cargo.toml index 9bd38a21a664b..5e7615f60d628 100644 --- a/bin/utils/subkey/Cargo.toml +++ b/bin/utils/subkey/Cargo.toml @@ -4,7 +4,7 @@ version = "2.0.1" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" publish = false diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index 5ebab6cf9d61a..9383b88f756cb 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Collection of allocator implementations." documentation = "https://docs.rs/sc-allocator" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index 772f22e822eb2..af8704058b660 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate client interfaces." documentation = "https://docs.rs/sc-client-api" diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 8d5ed20730f0c..cee35a43df2f6 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate authority discovery." readme = "README.md" diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 469df55cf0233..1ecdb08eba489 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Basic implementation of block-authoring logic." readme = "README.md" diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 6fef8498134eb..9d2703fc2ed2a 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate block builder" readme = "README.md" diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 8af2996e968d8..78062e600c3f5 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate chain configurations." readme = "README.md" diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index 89a51d95079a0..73083e4a6e0ba 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Macros to derive chain spec extension traits implementation." diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index b32e985b518c0..0cee37f25e797 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Substrate CLI interface." edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 75595779427bb..1c767319b1229 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Aura consensus algorithm for substrate" edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index dc937f1e3dbca..66ad6287f40df 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "BABE consensus algorithm for substrate" edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-consensus-babe" readme = "README.md" diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 8d5625705a48c..7ef9b1c1de3c4 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "RPC extensions for the BABE consensus algorithm" edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 6829bd2c6d8b5..30840a974f9aa 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Collection of common consensus specific imlementations for Substrate (client)" readme = "README.md" diff --git a/client/consensus/epochs/Cargo.toml b/client/consensus/epochs/Cargo.toml index 78e5cc31ea07e..90a708d07e2a2 100644 --- a/client/consensus/epochs/Cargo.toml +++ b/client/consensus/epochs/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Generic epochs-based utilities for consensus" edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index d9ae8521c12f6..9b29bb3dc71c7 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Manual sealing engine for Substrate" edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index c71e11aef275e..c570c1ccbad27 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "PoW consensus algorithm for substrate" edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 4c0142829bb5c..6c1f865c62cb0 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -6,7 +6,7 @@ description = "Generic slots-based utilities for consensus" edition = "2018" build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml index 7e821db197b3c..73768f0d09411 100644 --- a/client/consensus/uncles/Cargo.toml +++ b/client/consensus/uncles/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Generic uncle inclusion utilities for consensus" edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index f9a81d6ce7ea2..53af082d3b91d 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Client backend that uses RocksDB database as storage." readme = "README.md" diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index eeea57d839808..c8246d43a0f89 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "A crate that provides means of executing/dispatching calls into the runtime." documentation = "https://docs.rs/sc-executor" diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index c4fc8c27f7544..622baa6c0dcab 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "A set of common definitions that are needed for defining execution engines." documentation = "https://docs.rs/sc-executor-common/" diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index a4fbc88cf5662..ac1e3413491d9 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" publish = false -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 324b2bdd0baeb..307ba908e23b6 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "This crate provides an implementation of `WasmRuntime` that is baked by wasmi." documentation = "https://docs.rs/sc-executor-wasmi" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index a8ed01c203e33..9fb76ed08fd9a 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Defines a `WasmRuntime` that uses the Wasmtime JIT to execute." readme = "README.md" diff --git a/client/finality-grandpa-warp-sync/Cargo.toml b/client/finality-grandpa-warp-sync/Cargo.toml index a444125fdfa11..9736b25ccac55 100644 --- a/client/finality-grandpa-warp-sync/Cargo.toml +++ b/client/finality-grandpa-warp-sync/Cargo.toml @@ -5,7 +5,7 @@ version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 45f85f46ddffd..2d45fa100f79d 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Integration of the GRANDPA finality gadget into substrate." documentation = "https://docs.rs/sc-finality-grandpa" diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index 88d02f81ad5b3..c28dd4e011945 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Substrate informant." edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 17c651a91decd..74fd85c184c6f 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Keystore (and session key management) for ed25519 based chains like Polkadot." documentation = "https://docs.rs/sc-keystore" diff --git a/client/light/Cargo.toml b/client/light/Cargo.toml index b10f7646bf9bd..cc567c60524a1 100644 --- a/client/light/Cargo.toml +++ b/client/light/Cargo.toml @@ -5,7 +5,7 @@ version = "4.0.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-light" readme = "README.md" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index a73bfb0c2657b..b4907ade834aa 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -5,7 +5,7 @@ version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-network-gossip" readme = "README.md" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 319bce4d0e6b6..d6d054504369b 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -5,7 +5,7 @@ version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-network" readme = "README.md" diff --git a/client/network/src/service.rs b/client/network/src/service.rs index be19b44f3a59a..9b6e54f37a663 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -2023,8 +2023,9 @@ impl Future for NetworkWorker { .inc(); } }, - Poll::Ready(SwarmEvent::UnknownPeerUnreachableAddr { address, error }) => - trace!(target: "sub-libp2p", "Libp2p => UnknownPeerUnreachableAddr({}): {}", address, error), + Poll::Ready(SwarmEvent::UnknownPeerUnreachableAddr { address, error }) => { + trace!(target: "sub-libp2p", "Libp2p => UnknownPeerUnreachableAddr({}): {}", address, error) + }, Poll::Ready(SwarmEvent::ListenerClosed { reason, addresses, .. }) => { if let Some(metrics) = this.metrics.as_ref() { metrics.listeners_local_addresses.sub(addresses.len() as u64); diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index b4c3a74607f65..13555952cffd5 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -6,7 +6,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] edition = "2018" publish = false -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 641a1e55063d0..146ce07e1303b 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -5,7 +5,7 @@ version = "4.0.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/proposer-metrics/Cargo.toml b/client/proposer-metrics/Cargo.toml index ffe5045461f77..296329a5fda77 100644 --- a/client/proposer-metrics/Cargo.toml +++ b/client/proposer-metrics/Cargo.toml @@ -4,7 +4,7 @@ version = "0.9.0" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Basic metrics for block production." readme = "README.md" diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 6342abb1a3c41..192cf02e7ce17 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate RPC interfaces." readme = "README.md" diff --git a/client/rpc-api/src/state/mod.rs b/client/rpc-api/src/state/mod.rs index 620a000c500f4..1cc191197232b 100644 --- a/client/rpc-api/src/state/mod.rs +++ b/client/rpc-api/src/state/mod.rs @@ -301,7 +301,7 @@ pub trait StateApi { /// [substrate storage][1], [transparent keys in substrate][2], /// [querying substrate storage via rpc][3]. /// - /// [1]: https://substrate.dev/docs/en/knowledgebase/advanced/storage#storage-map-key + /// [1]: https://docs.substrate.io/v3/advanced/storage#storage-map-keys /// [2]: https://www.shawntabrizi.com/substrate/transparent-keys-in-substrate/ /// [3]: https://www.shawntabrizi.com/substrate/querying-substrate-storage-via-rpc/ /// diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index 26a05a8263dc4..cbbea00d6f576 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate RPC servers." readme = "README.md" diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 427800f74ddf2..f5c7f99ff7435 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate Client RPC" readme = "README.md" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 0a496a55adc49..589d7848a5b28 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate service. Starts a thread that spins up the network, client, and extrinsic pool. Manages communication between them." readme = "README.md" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index fc42368a10aea..aeee4a5f90728 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" publish = false -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 93d5e1464b39b..136fe7a199f0c 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "State database maintenance. Handles canonicalization and pruning in the database." readme = "README.md" diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index b81fd1fd5c611..4166929ff0317 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "A RPC handler to create sync states for light clients." edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 0c5e2db6c7760..502c7fc20781f 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Telemetry utils" edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-telemetry" readme = "README.md" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 5dfa3efa779e3..b4049fa097ff8 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Instrumentation implementation for substrate." readme = "README.md" diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index 42a0c739cd522..5cc2d836dcada 100644 --- a/client/tracing/proc-macro/Cargo.toml +++ b/client/tracing/proc-macro/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Helper macros for Substrate's client CLI" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 0871cadd5a02b..12642559a3b8d 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate transaction pool implementation." readme = "README.md" diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index efef36071f083..7dd1a6724ce59 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Transaction pool client facing API." diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index 9b3c54974a767..546232cf60708 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "I/O for Substrate runtimes" readme = "README.md" diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 05e7912dd07c6..65162430a2ac1 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME asset management pallet" readme = "README.md" diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 53a8c3a81165b..60e8fa613f06b 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME atomic swap pallet" readme = "README.md" diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index 8f5c42bc3c465..1761f78edeca2 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME AURA consensus pallet" readme = "README.md" diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index 80a320c31e77f..7e64509ce6b45 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for authority discovery" readme = "README.md" diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 120b72f8e6511..6ac91970712d7 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -5,7 +5,7 @@ description = "Block and Uncle Author tracking for the FRAME" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index d95f1419fd035..6b0dc71b5e29a 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Consensus extension module for BABE consensus. Collects on-chain randomness from VRF outputs and manages epoch transitions." readme = "README.md" diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 860a6edc42143..cd06ce4a69983 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet bags list" readme = "README.md" diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 2263387d6d8ef..f6e6e97850a72 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet to manage balances" readme = "README.md" diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 6a605707caa8b..0600b934d44e2 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Macro for benchmarking a FRAME runtime." readme = "README.md" diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 93a7ababb2ebd..d949d0fb1d58e 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet to manage bounties" readme = "README.md" diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index e88f28d417730..3e3d167522e81 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Collective system: Members of a set of account IDs can make their collective feelings known through dispatched calls from one of two specialized origins." readme = "README.md" diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index c094e01507712..5967600bf68f5 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for WASM contracts" readme = "README.md" diff --git a/frame/contracts/README.md b/frame/contracts/README.md index f3a8d13f6e77d..978ee25fcb109 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -34,7 +34,7 @@ reverted at the current call's contract level. For example, if contract A calls then all of B's calls are reverted. Assuming correct error handling by contract A, A's other calls and state changes still persist. -One gas is equivalent to one [weight](https://substrate.dev/docs/en/knowledgebase/learn-substrate/weight) +One gas is equivalent to one [weight](https://docs.substrate.io/v3/runtime/weights-and-fees) which is defined as one picosecond of execution time on the runtime's reference machine. ### Notable Scenarios diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/common/Cargo.toml index b441d88453ae2..48baf23d3aee8 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/common/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "A crate that hosts a common definitions that are relevant for the pallet-contracts." readme = "README.md" diff --git a/frame/contracts/proc-macro/Cargo.toml b/frame/contracts/proc-macro/Cargo.toml index 605c69fe73e25..63d05bcc2f05e 100644 --- a/frame/contracts/proc-macro/Cargo.toml +++ b/frame/contracts/proc-macro/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Procedural macros used in pallet_contracts" diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index b73039ba7191e..eec02b03aaa0e 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Node-specific RPC methods for interaction with contracts." readme = "README.md" diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml index e5f6d1ec7eb8e..e41aa5aaec9b5 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/rpc/runtime-api/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Runtime API definition required by Contracts RPC extensions." readme = "README.md" diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 94719553e28aa..f0bf2109be065 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for democracy" readme = "README.md" diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index b2d50321e8cd3..3c6b405c331f0 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "PALLET two phase election providers" readme = "README.md" diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index dfe2b11024334..46e6500cac33a 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "election provider supporting traits" readme = "README.md" diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index f2771a9f72783..80afc3f5d8b00 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -4,7 +4,7 @@ version = "5.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet based on seq-Phragmén election method." readme = "README.md" diff --git a/frame/elections/Cargo.toml b/frame/elections/Cargo.toml index 8557cfba6b58c..f5c7acb1cd5d5 100644 --- a/frame/elections/Cargo.toml +++ b/frame/elections/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for elections" readme = "README.md" diff --git a/frame/example-offchain-worker/Cargo.toml b/frame/example-offchain-worker/Cargo.toml index 1ccd9f33f0318..2759664d6e653 100644 --- a/frame/example-offchain-worker/Cargo.toml +++ b/frame/example-offchain-worker/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Unlicense" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME example pallet for offchain worker" readme = "README.md" diff --git a/frame/example-parallel/Cargo.toml b/frame/example-parallel/Cargo.toml index 5e0f6d4bc255a..6511a1cd369bf 100644 --- a/frame/example-parallel/Cargo.toml +++ b/frame/example-parallel/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Unlicense" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME example pallet using runtime worker threads" diff --git a/frame/example/Cargo.toml b/frame/example/Cargo.toml index 58daaf1c75558..e144f1e927d36 100644 --- a/frame/example/Cargo.toml +++ b/frame/example/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Unlicense" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME example pallet" readme = "README.md" diff --git a/frame/example/src/benchmarking.rs b/frame/example/src/benchmarking.rs index 9f2bb20fe63ac..e89c646e03f1a 100644 --- a/frame/example/src/benchmarking.rs +++ b/frame/example/src/benchmarking.rs @@ -26,13 +26,13 @@ use frame_system::RawOrigin; // To actually run this benchmark on pallet-example, we need to put this pallet into the // runtime and compile it with `runtime-benchmarks` feature. The detail procedures are // documented at: -// https://substrate.dev/docs/en/knowledgebase/runtime/benchmarking#how-to-benchmark +// https://docs.substrate.io/v3/runtime/benchmarking#how-to-benchmark // // The auto-generated weight estimate of this pallet is copied over to the `weights.rs` file. // The exact command of how the estimate generated is printed at the top of the file. // Details on using the benchmarks macro can be seen at: -// https://substrate.dev/rustdocs/v3.0.0/frame_benchmarking/macro.benchmarks.html +// https://paritytech.github.io/substrate/master/frame_benchmarking/trait.Benchmarking.html#tymethod.benchmarks benchmarks! { // This will measure the execution time of `set_dummy` for b in [1..1000] range. set_dummy_benchmark { diff --git a/frame/example/src/lib.rs b/frame/example/src/lib.rs index 23c4951c1a603..f0b58e9aec153 100644 --- a/frame/example/src/lib.rs +++ b/frame/example/src/lib.rs @@ -316,8 +316,7 @@ const MILLICENTS: u32 = 1_000_000_000; // - assigns a dispatch class `operational` if the argument of the call is more than 1000. // // More information can be read at: -// - https://substrate.dev/docs/en/knowledgebase/learn-substrate/weight -// - https://substrate.dev/docs/en/knowledgebase/runtime/fees#default-weight-annotations +// - https://docs.substrate.io/v3/runtime/weights-and-fees // // Manually configuring weight is an advanced operation and what you really need may well be // fulfilled by running the benchmarking toolchain. Refer to `benchmarking.rs` file. @@ -548,7 +547,8 @@ pub mod pallet { // Print out log or debug message in the console via log::{error, warn, info, debug, // trace}, accepting format strings similar to `println!`. - // https://substrate.dev/rustdocs/v3.0.0/log/index.html + // https://paritytech.github.io/substrate/master/sp_io/logging/fn.log.html + // https://paritytech.github.io/substrate/master/frame_support/constant.LOG_TARGET.html info!("New value is now: {:?}", new_value); // Put the new value into storage. diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 15c8a1bd14f1e..44b4dbcf2bd30 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME executives engine" readme = "README.md" diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index c275b693d8f27..c7dc384662f97 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for rewarding account freezing." readme = "README.md" diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 53ab443783e5d..36cc43fc3443e 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for GRANDPA finality gadget" readme = "README.md" diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 598be25c5ef38..e6d1fa3e9dfbc 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME identity management pallet" readme = "README.md" diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index a1efd626c0690..ef2fe54a8ceef 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME's I'm online pallet" readme = "README.md" diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index 17d04c43fa5d9..bf5a82fbb1da7 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME indices management pallet" readme = "README.md" diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index f14d65310cc70..854b6f52470d7 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME Participation Lottery Pallet" readme = "README.md" diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index acc82f7678de6..9fdfaa4731729 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME membership management pallet" readme = "README.md" diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 02b4be182ef82..942067ebde3ed 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME Merkle Mountain Range pallet." diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index 07b2f8ae3a3a4..bbf55a2b7089e 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME Merkle Mountain Range primitives." diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 5a0f114e50173..926cfd602f673 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Node-specific RPC methods for interaction with Merkle Mountain Range pallet." publish = false diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index 177334d4ccf8d..d1bd23dcab581 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME multi-signature dispatch pallet" readme = "README.md" diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 431ee2c84157c..dacec5567ede4 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for nick management" readme = "README.md" diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 635e72e3a8b8a..960f7e04688dd 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for node authorization" diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 8fdcbf46fa3e1..97f4644a83ca0 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME offences pallet" readme = "README.md" diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index b21e6cf9b7e13..f8459087cb7fb 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME offences pallet benchmarking" readme = "README.md" diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index 4da712dadf27b..4f4cf2bf9d56d 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME proxying pallet" readme = "README.md" diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index 5e8eb6b082879..ba77312699172 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME randomness collective flip pallet" readme = "README.md" diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 40a89e9b59f89..092940f5173f8 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME account recovery pallet" readme = "README.md" diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 62b21fe04c9df..862321dfa6f26 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Unlicense" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME example pallet" readme = "README.md" diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index 9d5f156c175d5..a7d75ccacb96e 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for scored pools" readme = "README.md" diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 3d2de5339543e..32d298d3917c3 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME sessions pallet" readme = "README.md" diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index a24d4a1173ab1..0d0868d439215 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME sessions pallet benchmarking" readme = "README.md" diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index 942b2844195f2..ab2c379c51b5c 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME society pallet" readme = "README.md" diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 70637bcd7726f..4b608bd91dc76 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet staking" readme = "README.md" diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index aaa45e623109f..e44188bf7894e 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Reward Curve for FRAME staking pallet" diff --git a/frame/staking/reward-fn/Cargo.toml b/frame/staking/reward-fn/Cargo.toml index 076e05bf2a61e..ae0b7f50c994c 100644 --- a/frame/staking/reward-fn/Cargo.toml +++ b/frame/staking/reward-fn/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Reward function for FRAME staking pallet" diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index baacb66d5c751..3587a234566ec 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for sudo" readme = "README.md" diff --git a/frame/sudo/README.md b/frame/sudo/README.md index ac7de01615f3f..60090db46a4fc 100644 --- a/frame/sudo/README.md +++ b/frame/sudo/README.md @@ -65,6 +65,6 @@ You need to set an initial superuser account as the sudo `key`. [`Call`]: ./enum.Call.html [`Config`]: ./trait.Config.html -[`Origin`]: https://docs.substrate.dev/docs/substrate-types +[`Origin`]: https://docs.substrate.io/v3/runtime/origins License: Apache-2.0 diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index bab93ffcee162..427455849bb00 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -89,7 +89,7 @@ //! //! * [Democracy](../pallet_democracy/index.html) //! -//! [`Origin`]: https://docs.substrate.dev/docs/substrate-types +//! [`Origin`]: https://docs.substrate.io/v3/runtime/origins #![cfg_attr(not(feature = "std"), no_std)] diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 5f1b24d90a499..edb0ecd6442e8 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Support code for the runtime." readme = "README.md" diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 6113c6613be03..ed152c25fc3b7 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Proc macro of Support code for the runtime." diff --git a/frame/support/procedural/src/pallet/expand/error.rs b/frame/support/procedural/src/pallet/expand/error.rs index 7a058bb32c922..c6925db07a26f 100644 --- a/frame/support/procedural/src/pallet/expand/error.rs +++ b/frame/support/procedural/src/pallet/expand/error.rs @@ -69,7 +69,7 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { if get_doc_literals(&error_item.attrs).is_empty() { error_item.attrs.push(syn::parse_quote!( #[doc = r" - Custom [dispatch errors](https://substrate.dev/docs/en/knowledgebase/runtime/errors) + Custom [dispatch errors](https://docs.substrate.io/v3/runtime/events-and-errors) of this pallet. "] )); diff --git a/frame/support/procedural/src/pallet/expand/event.rs b/frame/support/procedural/src/pallet/expand/event.rs index ebd2d7aeabaff..625c2d98baac5 100644 --- a/frame/support/procedural/src/pallet/expand/event.rs +++ b/frame/support/procedural/src/pallet/expand/event.rs @@ -98,7 +98,7 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { if get_doc_literals(&event_item.attrs).is_empty() { event_item.attrs.push(syn::parse_quote!( #[doc = r" - The [event](https://substrate.dev/docs/en/knowledgebase/runtime/events) emitted + The [event](https://docs.substrate.io/v3/runtime/events-and-errors) emitted by this pallet. "] )); diff --git a/frame/support/procedural/src/pallet/expand/genesis_config.rs b/frame/support/procedural/src/pallet/expand/genesis_config.rs index 4bbba2c05908e..b2eb2166165cb 100644 --- a/frame/support/procedural/src/pallet/expand/genesis_config.rs +++ b/frame/support/procedural/src/pallet/expand/genesis_config.rs @@ -89,7 +89,7 @@ pub fn expand_genesis_config(def: &mut Def) -> proc_macro2::TokenStream { attrs.push(syn::parse_quote!( #[doc = r" Can be used to configure the - [genesis state](https://substrate.dev/docs/en/knowledgebase/integrate/chain-spec#the-genesis-state) + [genesis state](https://docs.substrate.io/v3/runtime/chain-specs#the-genesis-state) of this pallet. "] )); diff --git a/frame/support/procedural/src/pallet/expand/mod.rs b/frame/support/procedural/src/pallet/expand/mod.rs index 1c8883977c765..083ad61fc5239 100644 --- a/frame/support/procedural/src/pallet/expand/mod.rs +++ b/frame/support/procedural/src/pallet/expand/mod.rs @@ -72,9 +72,9 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { def.item.attrs.push(syn::parse_quote!( #[doc = r" The module that hosts all the - [FRAME](https://substrate.dev/docs/en/knowledgebase/runtime/frame) + [FRAME](https://docs.substrate.io/v3/runtime/frame) types needed to add this pallet to a - [runtime](https://substrate.dev/docs/en/knowledgebase/runtime/). + runtime. "] )); } diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index ea601f138ea05..57e814b6b8438 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -62,7 +62,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { if get_doc_literals(&pallet_item.attrs).is_empty() { pallet_item.attrs.push(syn::parse_quote!( #[doc = r" - The [pallet](https://substrate.dev/docs/en/knowledgebase/runtime/pallets) implementing + The [pallet](https://docs.substrate.io/v3/runtime/frame#pallets) implementing the on-chain logic. "] )); diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index d6894b78133e4..6a8fb57b39bda 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Proc macro helpers for procedural macros" diff --git a/frame/support/procedural/tools/derive/Cargo.toml b/frame/support/procedural/tools/derive/Cargo.toml index 14c56b1b819a3..9f4e2d9dca2a5 100644 --- a/frame/support/procedural/tools/derive/Cargo.toml +++ b/frame/support/procedural/tools/derive/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Use to derive parsing for parsing struct." diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index b4e9071e361aa..6dc7fb8a94cae 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -280,7 +280,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// /// The following are reserved function signatures: /// -/// * `deposit_event`: Helper function for depositing an [event](https://docs.substrate.dev/docs/event-enum). +/// * `deposit_event`: Helper function for depositing an [event](https://docs.substrate.io/v3/runtime/events-and-errors). /// The default behavior is to call `deposit_event` from the [System /// module](../frame_system/index.html). However, you can write your own implementation for events /// in your runtime. To use the default behavior, add `fn deposit_event() = default;` to your diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index a60ed57cf2b9f..e51c6cd734113 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -337,7 +337,7 @@ where fn max_encoded_len() -> usize { // BoundedVec encodes like Vec which encodes like [T], which is a compact u32 // plus each item in the slice: - // https://substrate.dev/rustdocs/v3.0.0/src/parity_scale_codec/codec.rs.html#798-808 + // https://docs.substrate.io/v3/advanced/scale-codec codec::Compact(S::get()) .encoded_size() .saturating_add(Self::bound().saturating_mul(T::max_encoded_len())) diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 4655c809e014b..823c50c55d0b9 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -307,7 +307,7 @@ where fn max_encoded_len() -> usize { // WeakBoundedVec encodes like Vec which encodes like [T], which is a compact u32 // plus each item in the slice: - // https://substrate.dev/rustdocs/v3.0.0/src/parity_scale_codec/codec.rs.html#798-808 + // https://docs.substrate.io/v3/advanced/scale-codec codec::Compact(S::get()) .encoded_size() .saturating_add(Self::bound().saturating_mul(T::max_encoded_len())) diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index db6e0321005a5..9109bfeeae722 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -429,7 +429,7 @@ impl MaxEncodedLen for WrapperOpaque { fn max_encoded_len() -> usize { let t_max_len = T::max_encoded_len(); - // See scale encoding https://substrate.dev/docs/en/knowledgebase/advanced/codec + // See scale encoding https://docs.substrate.io/v3/advanced/scale-codec if t_max_len < 64 { t_max_len + 1 } else if t_max_len < 2usize.pow(14) { diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 594ed6349e745..77fd4f5620969 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" publish = false -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/frame/support/test/pallet/Cargo.toml b/frame/support/test/pallet/Cargo.toml index 35eb4f34acae1..a3d101967ae65 100644 --- a/frame/support/test/pallet/Cargo.toml +++ b/frame/support/test/pallet/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" publish = false -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 389730107b439..dc69bd2d5e85f 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME system module" readme = "README.md" diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 29bcccfd7d830..6aa2251f287d9 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME System benchmarking" readme = "README.md" diff --git a/frame/system/rpc/runtime-api/Cargo.toml b/frame/system/rpc/runtime-api/Cargo.toml index fce29612b4d8c..b5e569e1298ca 100644 --- a/frame/system/rpc/runtime-api/Cargo.toml +++ b/frame/system/rpc/runtime-api/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Runtime API definition required by System RPC extensions." readme = "README.md" diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 1c95c4782b5c4..cd636ec6c23b5 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME Timestamp Module" documentation = "https://docs.rs/pallet-timestamp" diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 8ca395e1c5416..a3f268169b784 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet to manage tips" readme = "README.md" diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 1dfeb0c2baa4b..bea263cbef6f1 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet to manage transaction payments" readme = "README.md" diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 3858c41a38763..1a2c68227c11f 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "RPC interface for the transaction payment pallet." readme = "README.md" diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 2f78f2439c604..7bdca2f658293 100644 --- a/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "RPC runtime API for transaction payment FRAME pallet" readme = "README.md" diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 9daf706b0ce33..bcd3fd145f575 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Unlicense" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Storage chain pallet" readme = "README.md" diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index b2991f3febcad..bcbe41985c655 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet to manage treasury" readme = "README.md" diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index 0ff534767607d..611a844278269 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for democracy" readme = "README.md" diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 4f664ecc2b6a9..f240bb98afab7 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME NFT asset management pallet" readme = "README.md" diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index b5b8eab9cdbf3..0a0a9eafd845b 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME utilities pallet" readme = "README.md" diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 806e0e6036862..3179607b3f6d7 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for manage vesting" readme = "README.md" diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index 7e751232acb50..c57c3730fc7b6 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate runtime api primitives" readme = "README.md" diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index dc0f2bd98d468..d9dd0bf9020c7 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Macros for declaring and implementing runtime apis." documentation = "https://docs.rs/sp-api-proc-macro" diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index b78c9abb80dc6..faee5ebdc77db 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" publish = false -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index 6849dc25f8561..88411d86392af 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" description = "Provides facilities for generating application specific crypto wrapper types." license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sp-application-crypto" readme = "README.md" diff --git a/primitives/application-crypto/test/Cargo.toml b/primitives/application-crypto/test/Cargo.toml index 468bfee3cc010..d10f011c4c603 100644 --- a/primitives/application-crypto/test/Cargo.toml +++ b/primitives/application-crypto/test/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" description = "Integration tests for application-crypto" license = "Apache-2.0" publish = false -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index abdbd4e60d041..92b16b895e3b5 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Minimal fixed point arithmetic primitives and types for runtime." documentation = "https://docs.rs/sp-arithmetic" diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index d10eccfc7c74a..5f2d5801ff995 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -4,7 +4,7 @@ version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Fuzzer for fixed point arithmetic primitives." documentation = "https://docs.rs/sp-arithmetic-fuzzer" diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index 6638e478b4cd7..d4c75dda352ca 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Authority discovery primitives" edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index 15e4dc57ff5ab..cee82ca77c375 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Authorship primitives" edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index d7fa0f2ef85cf..8499bdf8e1c70 100644 --- a/primitives/block-builder/Cargo.toml +++ b/primitives/block-builder/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "The block builder runtime api." readme = "README.md" diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 66d9152c230df..93daef5fa1a27 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate blockchain traits and primitives." documentation = "https://docs.rs/sp-blockchain" diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index c228b88fd6570..ca73cf206de02 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Primitives for Aura consensus" edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 5f6bfec219739..1690b7c9a02d3 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Primitives for BABE consensus" edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index ecfc1c1b31826..9a5488abba653 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Common utilities for building and using consensus engines in substrate." documentation = "https://docs.rs/sp-consensus/" diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index f93eeca2fb24e..406ed3dea46a5 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Primitives for Aura consensus" edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index 3ad204f973961..014ee9b93e6e8 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Primitives for slots-based consensus" edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 124cbf423f068..c103e68eb66b2 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -6,7 +6,7 @@ description = "Primitives for VRF based consensus" edition = "2018" license = "Apache-2.0" repository = "https://github.com/paritytech/substrate/" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" readme = "README.md" [package.metadata.docs.rs] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 4071dab71be5a..dd721d744f573 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Shareable Substrate types." documentation = "https://docs.rs/sp-core" diff --git a/primitives/database/Cargo.toml b/primitives/database/Cargo.toml index c99651d4ef042..c3d2d8ce99df9 100644 --- a/primitives/database/Cargo.toml +++ b/primitives/database/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate database trait." documentation = "https://docs.rs/sp-database" diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml index ce49c54b46fbe..954d0f89663fe 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Macros to derive runtime debug implementation." documentation = "https://docs.rs/sp-debug-derive" diff --git a/primitives/externalities/Cargo.toml b/primitives/externalities/Cargo.toml index 52a6300688cd9..5a1b6b5e73734 100644 --- a/primitives/externalities/Cargo.toml +++ b/primitives/externalities/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate externalities abstraction" documentation = "https://docs.rs/sp-externalities" diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index c0c2a654270f7..5cf7ac6711a70 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Primitives for GRANDPA integration, suitable for WASM compilation." documentation = "https://docs.rs/sp-finality-grandpa" diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 23558750b5cf8..04b662fb059f0 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Provides types and traits for creating and checking inherents." documentation = "https://docs.rs/sp-inherents" diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 2323b5281d59a..df9a496a914be 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "I/O for Substrate runtimes" documentation = "https://docs.rs/sp-io" diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index a14e98d3d8059..464abdb6cb1aa 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Keyring support code for the runtime. A set of test accounts." documentation = "https://docs.rs/sp-keyring" diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 35c66ef93f7aa..3a0532f1db313 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Keystore primitives." documentation = "https://docs.rs/sp-core" diff --git a/primitives/maybe-compressed-blob/Cargo.toml b/primitives/maybe-compressed-blob/Cargo.toml index 6994ccf5486ba..cd124580ef19c 100644 --- a/primitives/maybe-compressed-blob/Cargo.toml +++ b/primitives/maybe-compressed-blob/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Handling of blobs, usually Wasm code, which may be compresed" documentation = "https://docs.rs/sp-maybe-compressed-blob" diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index b277df8f58f12..5ffaf76379bda 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "NPoS election algorithm primitives" readme = "README.md" diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index d6fcc09c8b586..1d13d33a35e80 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -4,7 +4,7 @@ version = "2.0.0-alpha.5" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Fuzzer for phragmén implementation." documentation = "https://docs.rs/sp-npos-elections-fuzzer" diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index 8eb9c26564f51..27d5d0bb1231c 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "NPoS Solution Type" diff --git a/primitives/offchain/Cargo.toml b/primitives/offchain/Cargo.toml index dd54147b6c629..c1e891acba955 100644 --- a/primitives/offchain/Cargo.toml +++ b/primitives/offchain/Cargo.toml @@ -5,7 +5,7 @@ version = "4.0.0-dev" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml index ad03baca24ebb..c961d5b089abb 100644 --- a/primitives/panic-handler/Cargo.toml +++ b/primitives/panic-handler/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Custom panic hook with bug report link" documentation = "https://docs.rs/sp-panic-handler" diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index 8e1b91a9acb21..af883e2199415 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate RPC primitives and utilities." readme = "README.md" diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index dd1b84eabfe93..fc8923cdb80a3 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate runtime interface" documentation = "https://docs.rs/sp-runtime-interface/" diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 1f77caf7e4160..dd08d03313396 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "This crate provides procedural macros for usage within the context of the Substrate runtime interface." documentation = "https://docs.rs/sp-runtime-interface-proc-macro" diff --git a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 3ae5d78b0ef95..a3c82de473abd 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" build = "build.rs" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" publish = false diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index 7c7d3e10b2d0c..557b5b9bee89f 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" build = "build.rs" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" publish = false diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 383df494120aa..26884d5cb729f 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" publish = false -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 5ac5bcf1963e0..475d2b769de39 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Runtime Modules shared primitive types." documentation = "https://docs.rs/sp-runtime" diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index a4d4a4d5d031a..80cd195c6f406 100755 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "This crate provides means to instantiate and execute wasm modules." readme = "README.md" diff --git a/primitives/serializer/Cargo.toml b/primitives/serializer/Cargo.toml index 2200274e0628d..cc438e9a1c148 100644 --- a/primitives/serializer/Cargo.toml +++ b/primitives/serializer/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate customizable serde serializer." documentation = "https://docs.rs/sp-serializer" diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index 8e1e2464e49ec..1e9ed6ec9b651 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Primitives for sessions" readme = "README.md" diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 9e852319ede42..8ea24760e2b8b 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "A crate which contains primitives that are useful for implementation that uses staking approaches in general. Definitions related to sessions, slashing, etc go here." readme = "README.md" diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index bafe34bbd5afd..bbe9728befd80 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Substrate State Machine" edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sp-state-machine" readme = "README.md" diff --git a/primitives/std/Cargo.toml b/primitives/std/Cargo.toml index bf815c1c80c56..e4cacf60cc36f 100644 --- a/primitives/std/Cargo.toml +++ b/primitives/std/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Lowest-abstraction level for the Substrate runtime: just exports useful primitives from std or client/alloc to be used with any code that depends on the runtime." diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index 078e0fff12ef8..c7d23fcf70103 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" description = "Storage related primitives" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sp-storage/" readme = "README.md" diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index ee503ae9b855f..f91d15d2d40b3 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Runtime asynchronous, pure computational tasks" documentation = "https://docs.rs/sp-tasks" diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 5aed5d679dd49..75ce8b752d3ca 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -4,7 +4,7 @@ version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" publish = false diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 60daf9642df6b..32f4c53083435 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate core types and inherents for timestamps." readme = "README.md" diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index 806205dae8ddb..85eb22d6df072 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Instrumentation primitives and macros for Substrate." readme = "README.md" diff --git a/primitives/transaction-pool/Cargo.toml b/primitives/transaction-pool/Cargo.toml index 3f77014ac53b0..f74fcb44fee2d 100644 --- a/primitives/transaction-pool/Cargo.toml +++ b/primitives/transaction-pool/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Transaction pool runtime facing API." documentation = "https://docs.rs/sp-transaction-pool" diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index 8a41105b20b74..536e2f201a104 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Transaction storage proof primitives" edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 297040d09eecf..66d8a1e47276e 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -6,7 +6,7 @@ description = "Patricia trie stuff using a parity-scale-codec node format" repository = "https://github.com/paritytech/substrate/" license = "Apache-2.0" edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" documentation = "https://docs.rs/sp-trie" readme = "README.md" diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index fcab1eeabcaf4..2a2c2698c74c3 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Version module for the Substrate runtime; Provides a function that returns the runtime version." documentation = "https://docs.rs/sp-version" diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index 4984961fb9f77..587ca06bdc179 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Macro for defining a runtime version." documentation = "https://docs.rs/sp-api-proc-macro" diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index ba8a7b4e4b466..73b47e563a5b5 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Types and traits for interfacing between the host and the wasm runtime." documentation = "https://docs.rs/sp-wasm-interface" diff --git a/ss58-registry.json b/ss58-registry.json index 62602d829f6b8..fdae23a5a6f21 100644 --- a/ss58-registry.json +++ b/ss58-registry.json @@ -386,7 +386,7 @@ "symbols": null, "decimals": null, "standardAccount": "*25519", - "website": "https://substrate.dev/" + "website": "https://docs.substrate.io/" }, { "prefix": 43, diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index 4eed6e5e29133..a9ffefa05df7f 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate test utilities" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 34238872cad84..204b6ac435e07 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -4,7 +4,7 @@ version = "2.0.1" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" publish = false diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index 68bcbdaa4700f..2a1f52346840f 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate test utilities macros" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 24f4d404c18bd..eb6ca51ce2e5a 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" build = "build.rs" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" publish = false diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index 3561697042f2a..75ebb8f23326c 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -4,7 +4,7 @@ version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" publish = false diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index 09839ebae6ffe..5a2983b058b04 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -4,7 +4,7 @@ version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" publish = false diff --git a/test-utils/test-crate/Cargo.toml b/test-utils/test-crate/Cargo.toml index fff39c3964ad8..9c9672fe8f5d8 100644 --- a/test-utils/test-crate/Cargo.toml +++ b/test-utils/test-crate/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" publish = false diff --git a/utils/build-script-utils/Cargo.toml b/utils/build-script-utils/Cargo.toml index fbef70db93bfd..786e6f9002914 100644 --- a/utils/build-script-utils/Cargo.toml +++ b/utils/build-script-utils/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Crate with utility functions for `build.rs` scripts." readme = "README.md" diff --git a/utils/fork-tree/Cargo.toml b/utils/fork-tree/Cargo.toml index 11c269bc3cba8..81fa1747a84d7 100644 --- a/utils/fork-tree/Cargo.toml +++ b/utils/fork-tree/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Utility library for managing tree-like ordered data with logic for pruning the tree while finalizing nodes." documentation = "https://docs.rs/fork-tree" diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 93616b590f61e..ccca30849f919 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "CLI for benchmarking FRAME" readme = "README.md" diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index 1b6597fc9f2fc..fcdbb215f91b2 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "cli interface for FRAME" documentation = "https://docs.rs/substrate-frame-cli" diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 384307fbec9e5..1bb53207f7d4c 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Bag threshold generation script for pallet-bag-list" readme = "README.md" diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml index 7fcd981a6bbd6..68d3cad16de47 100644 --- a/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Bag threshold generation script for pallet-bag-list and node-runtime." readme = "README.md" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index e1fffcfd567a0..2b35402f8f63f 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "An externalities provided environemnt that can load itself from remote nodes or cache files" readme = "README.md" diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index a94f18d0e8925..2010d1e02f73f 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -7,7 +7,7 @@ authors = [ ] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate RPC for FRAME's support" diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index e9ae506ef6b06..85868836f0456 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME's system exposed over Substrate RPC" readme = "README.md" diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 6f4fd91126fb3..e922af971044c 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Cli command runtime testing and dry-running" readme = "README.md" diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index d5ccca9560252..28e51b38f2ace 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -29,9 +29,9 @@ //! //! Some resources about the above: //! -//! 1. +//! 1. //! 2. -//! 3. +//! 3. //! //! --- //! diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 43de76eee2120..4d218e233bcbc 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -5,7 +5,7 @@ version = "0.9.0" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2018" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index 721f332e130f0..92b1af753ef60 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" readme = "README.md" repository = "https://github.com/paritytech/substrate/" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] From 00629de9b7aae97e041b21b081f469eb834169a7 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 14 Oct 2021 12:44:07 +0100 Subject: [PATCH 0131/1472] make the ws buffer size configurable (#10013) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * make the ws buffer size configurable * Update client/cli/src/commands/run_cmd.rs Co-authored-by: Tomasz Drwięga * Update client/cli/src/commands/run_cmd.rs Co-authored-by: Tomasz Drwięga * Update client/cli/src/commands/run_cmd.rs Co-authored-by: Bastian Köcher * Final touches * Apply suggestions from code review * fix bench * remove in buffer * Apply suggestions from code review Co-authored-by: Tomasz Drwięga Co-authored-by: Tomasz Drwięga Co-authored-by: Bastian Köcher --- bin/node/cli/benches/transaction_pool.rs | 1 + client/cli/src/commands/run_cmd.rs | 8 ++++++++ client/cli/src/config.rs | 6 ++++++ client/rpc-servers/src/lib.rs | 21 +++++++++++++++++++-- client/service/src/config.rs | 2 ++ client/service/src/lib.rs | 1 + client/service/test/src/lib.rs | 1 + test-utils/test-runner/src/utils.rs | 1 + 8 files changed, 39 insertions(+), 2 deletions(-) diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index 3b0ee26d7d597..4f5ccd6ea912f 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -85,6 +85,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { rpc_cors: None, rpc_methods: Default::default(), rpc_max_payload: None, + ws_max_out_buffer_capacity: None, prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index b43135f109735..d6c0133a7c145 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -127,6 +127,10 @@ pub struct RunCmd { #[structopt(long = "ws-max-connections", value_name = "COUNT")] pub ws_max_connections: Option, + /// Set the the maximum WebSocket output buffer size in MiB. Default is 16. + #[structopt(long = "ws-max-out-buffer-capacity")] + pub ws_max_out_buffer_capacity: Option, + /// Specify browser Origins allowed to access the HTTP & WS RPC servers. /// /// A comma-separated list of origins (protocol://domain or special `null` @@ -434,6 +438,10 @@ impl CliConfiguration for RunCmd { Ok(self.rpc_max_payload) } + fn ws_max_out_buffer_capacity(&self) -> Result> { + Ok(self.ws_max_out_buffer_capacity) + } + fn transaction_pool(&self) -> Result { Ok(self.pool_config.transaction_pool()) } diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index f79405bd6132a..86eeed5b40237 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -360,6 +360,11 @@ pub trait CliConfiguration: Sized { Ok(None) } + /// Get maximum WS output buffer capacity. + fn ws_max_out_buffer_capacity(&self) -> Result> { + Ok(None) + } + /// Get the prometheus configuration (`None` if disabled) /// /// By default this is `None`. @@ -513,6 +518,7 @@ pub trait CliConfiguration: Sized { rpc_ws_max_connections: self.rpc_ws_max_connections()?, rpc_cors: self.rpc_cors(is_dev)?, rpc_max_payload: self.rpc_max_payload()?, + ws_max_out_buffer_capacity: self.ws_max_out_buffer_capacity()?, prometheus_config: self.prometheus_config(DCV::prometheus_listen_port())?, telemetry_endpoints, default_heap_pages: self.default_heap_pages()?, diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 65ed6a914b19a..1ac409d6ba89f 100644 --- a/client/rpc-servers/src/lib.rs +++ b/client/rpc-servers/src/lib.rs @@ -33,6 +33,9 @@ const MEGABYTE: usize = 1024 * 1024; /// Maximal payload accepted by RPC servers. pub const RPC_MAX_PAYLOAD_DEFAULT: usize = 15 * MEGABYTE; +/// Maximal buffer size in WS server. +pub const WS_MAX_BUFFER_CAPACITY_DEFAULT: usize = 16 * MEGABYTE; + /// Default maximum number of connections for WS RPC servers. const WS_MAX_CONNECTIONS: usize = 100; @@ -172,18 +175,32 @@ pub fn start_ws< cors: Option<&Vec>, io: RpcHandler, maybe_max_payload_mb: Option, + maybe_max_out_buffer_capacity_mb: Option, server_metrics: ServerMetrics, tokio_handle: tokio::runtime::Handle, ) -> io::Result { - let rpc_max_payload = maybe_max_payload_mb + let max_payload = maybe_max_payload_mb .map(|mb| mb.saturating_mul(MEGABYTE)) .unwrap_or(RPC_MAX_PAYLOAD_DEFAULT); + let max_out_buffer_capacity = maybe_max_out_buffer_capacity_mb + .map(|mb| mb.saturating_mul(MEGABYTE)) + .unwrap_or(WS_MAX_BUFFER_CAPACITY_DEFAULT); + + if max_payload > max_out_buffer_capacity { + log::warn!( + "maximum payload ({}) is more than maximum output buffer ({}) size in ws server, the payload will actually be limited by the buffer size", + max_payload, + max_out_buffer_capacity, + ) + } + ws::ServerBuilder::with_meta_extractor(io, |context: &ws::RequestContext| { context.sender().into() }) .event_loop_executor(tokio_handle) - .max_payload(rpc_max_payload) + .max_payload(max_payload) .max_connections(max_connections.unwrap_or(WS_MAX_CONNECTIONS)) + .max_out_buffer_capacity(max_out_buffer_capacity) .allowed_origins(map_cors(cors)) .allowed_hosts(hosts_filtering(cors.is_some())) .session_stats(server_metrics) diff --git a/client/service/src/config.rs b/client/service/src/config.rs index b4f6bf70e05b0..d3bd4e4e48793 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -97,6 +97,8 @@ pub struct Configuration { pub rpc_methods: RpcMethods, /// Maximum payload of rpc request/responses. pub rpc_max_payload: Option, + /// Maximum size of the output buffer capacity for websocket connections. + pub ws_max_out_buffer_capacity: Option, /// Prometheus endpoint configuration. `None` if disabled. pub prometheus_config: Option, /// Telemetry service URL. `None` if disabled. diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 7284747424aa9..8d8c54cc25f29 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -424,6 +424,7 @@ fn start_rpc_servers< ), )?, config.rpc_max_payload, + config.ws_max_out_buffer_capacity, server_metrics.clone(), config.tokio_handle.clone(), ) diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index d85ad8d36111b..a4e740aabc18e 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -261,6 +261,7 @@ fn node_config< rpc_cors: None, rpc_methods: Default::default(), rpc_max_payload: None, + ws_max_out_buffer_capacity: None, prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/test-utils/test-runner/src/utils.rs b/test-utils/test-runner/src/utils.rs index 3ab77af96c16c..a4c45c25f969b 100644 --- a/test-utils/test-runner/src/utils.rs +++ b/test-utils/test-runner/src/utils.rs @@ -94,6 +94,7 @@ pub fn default_config(tokio_handle: Handle, mut chain_spec: Box) rpc_cors: None, rpc_methods: Default::default(), rpc_max_payload: None, + ws_max_out_buffer_capacity: None, prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, From f87ea7d934f76afba458c75efb6dde9d636a2a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Thu, 14 Oct 2021 09:29:50 -0300 Subject: [PATCH 0132/1472] use pipeline-scripts for dependent projects script (#9749) --- .gitlab-ci.yml | 47 ++++---- .../gitlab/check_polkadot_companion_build.sh | 99 ----------------- .../gitlab/check_polkadot_companion_status.sh | 102 ------------------ 3 files changed, 28 insertions(+), 220 deletions(-) delete mode 100755 .maintain/gitlab/check_polkadot_companion_build.sh delete mode 100755 .maintain/gitlab/check_polkadot_companion_status.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ae6a81611f2dd..d36fe2b57add7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,6 +46,7 @@ variables: &default-vars VAULT_AUTH_PATH: "gitlab-parity-io-jwt" VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" SIMNET_FEATURES_PATH: "simnet_tests/tests" + PIPELINE_SCRIPTS_TAG: "v0.1" default: cache: {} @@ -538,29 +539,37 @@ cargo-check-macos: #### stage: build -check-polkadot-companion-status: - stage: build - image: paritytech/tools:latest - <<: *kubernetes-env - <<: *vault-secrets - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - script: - - ./.maintain/gitlab/check_polkadot_companion_status.sh - -check-polkadot-companion-build: +.check-dependent-project: &check-dependent-project stage: build <<: *docker-env <<: *test-refs-no-trigger <<: *vault-secrets - needs: - - job: test-linux-stable-int - artifacts: false script: - - ./.maintain/gitlab/check_polkadot_companion_build.sh - after_script: - - cd polkadot && git rev-parse --abbrev-ref HEAD - allow_failure: true + - git clone + --depth=1 + "--branch=$PIPELINE_SCRIPTS_TAG" + https://github.com/paritytech/pipeline-scripts + - ./pipeline-scripts/check_dependent_project.sh + paritytech + substrate + --substrate + "$DEPENDENT_REPO" + "$GITHUB_PR_TOKEN" + - cd "$DEPENDENT_REPO" && git rev-parse --abbrev-ref HEAD + +# Individual jobs are set up for each dependent project so that they can be ran in parallel. +# Arguably we could generate a job for each companion in the PR's description using Gitlab's +# parent-child pipelines but that's more complicated. + +check-dependent-polkadot: + <<: *check-dependent-project + variables: + DEPENDENT_REPO: polkadot + +check-dependent-cumulus: + <<: *check-dependent-project + variables: + DEPENDENT_REPO: cumulus build-linux-substrate: &build-binary stage: build @@ -884,7 +893,7 @@ deploy-prometheus-alerting-rules: # Runs "quick" and "long" tests on nightly schedule and on commit / merge to master # A "quick" test is a smoke test where basic check-expect tests run by # checking values from metrics exposed by the app. -# A "long" test is the load testing where we send 50K transactions into the +# A "long" test is the load testing where we send 50K transactions into the # network and check if all completed successfully simnet-tests: stage: deploy diff --git a/.maintain/gitlab/check_polkadot_companion_build.sh b/.maintain/gitlab/check_polkadot_companion_build.sh deleted file mode 100755 index 72bfaf7151522..0000000000000 --- a/.maintain/gitlab/check_polkadot_companion_build.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env sh -# -# check if a pr is compatible with polkadot companion pr or master if not -# available -# -# to override one that was just mentioned mark companion pr in the body of the -# polkadot pr like -# -# polkadot companion: paritytech/polkadot#567 -# - -set -e - -github_api_substrate_pull_url="https://api.github.com/repos/paritytech/substrate/pulls" -# use github api v3 in order to access the data without authentication -github_header="Authorization: token ${GITHUB_PR_TOKEN}" - -boldprint () { printf "|\n| \033[1m${@}\033[0m\n|\n" ; } -boldcat () { printf "|\n"; while read l; do printf "| \033[1m${l}\033[0m\n"; done; printf "|\n" ; } - - - -boldcat <<-EOT - - -check_polkadot_companion_build -============================== - -this job checks if there is a string in the description of the pr like - -polkadot companion: paritytech/polkadot#567 - - -it will then run cargo check from this polkadot's branch with substrate code -from this pull request. otherwise, it will uses master instead - - -EOT - -# Set the user name and email to make merging work -git config --global user.name 'CI system' -git config --global user.email '<>' - -# Merge master into our branch before building Polkadot to make sure we don't miss -# any commits that are required by Polkadot. -git fetch --depth 100 origin -git merge origin/master - -# Clone the current Polkadot master branch into ./polkadot. -# NOTE: we need to pull enough commits to be able to find a common -# ancestor for successfully performing merges below. -git clone --depth 20 https://github.com/paritytech/polkadot.git - -cd polkadot - -# either it's a pull request then check for a companion otherwise use -# polkadot:master -if expr match "${CI_COMMIT_REF_NAME}" '^[0-9]\+$' >/dev/null -then - boldprint "this is pull request no ${CI_COMMIT_REF_NAME}" - - pr_data_file="$(mktemp)" - # get the last reference to a pr in polkadot - curl -sSL -H "${github_header}" -o "${pr_data_file}" \ - "${github_api_substrate_pull_url}/${CI_COMMIT_REF_NAME}" - - pr_body="$(sed -n -r 's/^[[:space:]]+"body": (".*")[^"]+$/\1/p' "${pr_data_file}")" - - pr_companion="$(echo "${pr_body}" | sed -n -r \ - -e 's;^.*[Cc]ompanion.*paritytech/polkadot#([0-9]+).*$;\1;p' \ - -e 's;^.*[Cc]ompanion.*https://github.com/paritytech/polkadot/pull/([0-9]+).*$;\1;p' \ - | tail -n 1)" - - if [ "${pr_companion}" ] - then - boldprint "companion pr specified/detected: #${pr_companion}" - git fetch origin refs/pull/${pr_companion}/head:pr/${pr_companion} - git checkout pr/${pr_companion} - git merge origin/master - else - boldprint "no companion branch found - building polkadot:master" - fi - rm -f "${pr_data_file}" -else - boldprint "this is not a pull request - building polkadot:master" -fi - -# Patch all Substrate crates in Polkadot -diener patch --crates-to-patch ../ --substrate --path Cargo.toml - -# We need to update specifically our patched Substrate crates so that other -# crates that depend on them (e.g. Polkadot, BEEFY) use this unified version -# NOTE: There's no way to only update patched crates, so we use a heuristic -# of updating a crucial Substrate crate (`sp-core`) to minimize the impact of -# updating unrelated dependencies -cargo update -p sp-core - -# Test Polkadot pr or master branch with this Substrate commit. -time cargo test --workspace --release --verbose --features=runtime-benchmarks diff --git a/.maintain/gitlab/check_polkadot_companion_status.sh b/.maintain/gitlab/check_polkadot_companion_status.sh deleted file mode 100755 index e0412c7b7bec7..0000000000000 --- a/.maintain/gitlab/check_polkadot_companion_status.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/sh -# -# check for a polkadot companion pr and ensure it has approvals and is -# mergeable -# - -github_api_substrate_pull_url="https://api.github.com/repos/paritytech/substrate/pulls" -github_api_polkadot_pull_url="https://api.github.com/repos/paritytech/polkadot/pulls" -# use github api v3 in order to access the data without authentication -github_header="Authorization: token ${GITHUB_PR_TOKEN}" - -boldprint () { printf "|\n| \033[1m${@}\033[0m\n|\n" ; } -boldcat () { printf "|\n"; while read l; do printf "| \033[1m${l}\033[0m\n"; done; printf "|\n" ; } - - - -boldcat <<-EOT - - -check_polkadot_companion_status -=============================== - -this job checks if there is a string in the description of the pr like - -polkadot companion: paritytech/polkadot#567 - -and checks its status. - - -EOT - - -if ! [ "${CI_COMMIT_REF_NAME}" -gt 0 2>/dev/null ] -then - boldprint "this doesn't seem to be a pull request" - exit 1 -fi - -boldprint "this is pull request no ${CI_COMMIT_REF_NAME}" - -pr_body="$(curl -H "${github_header}" -s ${github_api_substrate_pull_url}/${CI_COMMIT_REF_NAME} \ - | sed -n -r 's/^[[:space:]]+"body": (".*")[^"]+$/\1/p')" - -# get companion if explicitly specified -pr_companion="$(echo "${pr_body}" | sed -n -r \ - -e 's;^.*[Cc]ompanion.*paritytech/polkadot#([0-9]+).*$;\1;p' \ - -e 's;^.*[Cc]ompanion.*https://github.com/paritytech/polkadot/pull/([0-9]+).*$;\1;p' \ - | tail -n 1)" - -if [ -z "${pr_companion}" ] -then - boldprint "no companion pr found" - exit 0 -fi - -boldprint "companion pr: #${pr_companion}" - -# check the status of that pull request - needs to be -# approved and mergable - -curl -H "${github_header}" -sS -o companion_pr.json \ - ${github_api_polkadot_pull_url}/${pr_companion} - -pr_head_sha=$(jq -r -e '.head.sha' < companion_pr.json) -boldprint "Polkadot PR's HEAD SHA: $pr_head_sha" - -curl -H "${github_header}" -sS -o companion_pr_reviews.json \ - ${github_api_polkadot_pull_url}/${pr_companion}/reviews - -# If there are any 'CHANGES_REQUESTED' reviews for the *current* review -jq -r -e '.[] | select(.state == "CHANGES_REQUESTED").commit_id' \ - < companion_pr_reviews.json > companion_pr_reviews_current.json -while IFS= read -r line; do - if [ "$line" = "$pr_head_sha" ]; then - boldprint "polkadot pr #${pr_companion} has CHANGES_REQUESTED for the latest commit" - exit 1 - fi -done < companion_pr_reviews_current.json - -# Then we check for at least 1 APPROVED -if [ -z "$(jq -r -e '.[].state | select(. == "APPROVED")' < companion_pr_reviews.json)" ]; then - boldprint "polkadot pr #${pr_companion} not APPROVED" - exit 1 -fi - -boldprint "polkadot pr #${pr_companion} state APPROVED" - -if jq -e .merged < companion_pr.json >/dev/null -then - boldprint "polkadot pr #${pr_companion} already merged" - exit 0 -fi - -if jq -e '.mergeable' < companion_pr.json >/dev/null -then - boldprint "polkadot pr #${pr_companion} mergeable" -else - boldprint "polkadot pr #${pr_companion} not mergeable" - exit 1 -fi - -exit 0 From f70b1ca1f7249d557b622be2640a6bc9d7ec4f84 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 14 Oct 2021 16:45:49 +0200 Subject: [PATCH 0133/1472] More lenient mechanism for identifying stash accounts in purge_keys (#10004) * More lenient StashOf finder * Slightly safer version of the change * Slightly safer version of the change * Tests * Formatting --- frame/session/src/lib.rs | 38 +++++++++++++++++++++++++------------- frame/session/src/mock.rs | 23 ++++++++++++++++++++--- frame/session/src/tests.rs | 29 ++++++++++++++++++++++++++++- 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 10c7ea42b3e9b..7fe163e0dfeac 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -114,17 +114,6 @@ mod mock; mod tests; pub mod weights; -use sp_runtime::{ - traits::{AtLeast32BitUnsigned, Convert, Member, One, OpaqueKeys, Zero}, - ConsensusEngineId, KeyTypeId, Permill, RuntimeAppPublic, -}; -use sp_staking::SessionIndex; -use sp_std::{ - marker::PhantomData, - ops::{Rem, Sub}, - prelude::*, -}; - use frame_support::{ codec::{Decode, MaxEncodedLen}, dispatch::{DispatchError, DispatchResult}, @@ -136,6 +125,17 @@ use frame_support::{ weights::Weight, Parameter, }; +use sp_runtime::{ + traits::{AtLeast32BitUnsigned, Convert, Member, One, OpaqueKeys, Zero}, + ConsensusEngineId, KeyTypeId, Permill, RuntimeAppPublic, +}; +use sp_staking::SessionIndex; +use sp_std::{ + convert::TryFrom, + marker::PhantomData, + ops::{Rem, Sub}, + prelude::*, +}; pub use pallet::*; pub use weights::WeightInfo; @@ -377,7 +377,11 @@ pub mod pallet { type Event: From + IsType<::Event>; /// A stable ID for a validator. - type ValidatorId: Member + Parameter + MaybeSerializeDeserialize + MaxEncodedLen; + type ValidatorId: Member + + Parameter + + MaybeSerializeDeserialize + + MaxEncodedLen + + TryFrom; /// A conversion from account ID to validator ID. /// @@ -595,9 +599,13 @@ pub mod pallet { } /// Removes any session key(s) of the function caller. + /// /// This doesn't take effect until the next session. /// - /// The dispatch origin of this function must be signed. + /// The dispatch origin of this function must be Signed and the account must be either be + /// convertible to a validator ID using the chain's typical addressing system (this usually + /// means being a controller account) or directly convertible into a validator ID (which + /// usually means being a stash account). /// /// # /// - Complexity: `O(1)` in number of key types. Actual cost depends on the number of length @@ -841,6 +849,10 @@ impl Pallet { fn do_purge_keys(account: &T::AccountId) -> DispatchResult { let who = T::ValidatorIdOf::convert(account.clone()) + // `purge_keys` may not have a controller-stash pair any more. If so then we expect the + // stash account to be passed in directly and convert that to a `ValidatorId` using the + // `TryFrom` trait if supported. + .or_else(|| T::ValidatorId::try_from(account.clone()).ok()) .ok_or(Error::::NoAssociatedValidatorId)?; let old_keys = Self::take_keys(&who).ok_or(Error::::NoKeys)?; diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index 277dec610659b..6db7727fa5391 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -22,13 +22,13 @@ use crate as pallet_session; #[cfg(feature = "historical")] use crate::historical as pallet_session_historical; -use std::cell::RefCell; +use std::{cell::RefCell, collections::BTreeMap}; use sp_core::{crypto::key_types::DUMMY, H256}; use sp_runtime::{ impl_opaque_keys, testing::{Header, UintAuthorityId}, - traits::{BlakeTwo256, ConvertInto, IdentityLookup}, + traits::{BlakeTwo256, IdentityLookup}, }; use sp_staking::SessionIndex; @@ -111,6 +111,7 @@ thread_local! { pub static DISABLED: RefCell = RefCell::new(false); // Stores if `on_before_session_end` was called pub static BEFORE_SESSION_END_CALLED: RefCell = RefCell::new(false); + pub static VALIDATOR_ACCOUNTS: RefCell> = RefCell::new(BTreeMap::new()); } pub struct TestShouldEndSession; @@ -225,6 +226,10 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pallet_session::GenesisConfig:: { keys } .assimilate_storage(&mut t) .unwrap(); + NEXT_VALIDATORS.with(|l| { + let v = l.borrow().iter().map(|&i| (i, i)).collect(); + VALIDATOR_ACCOUNTS.with(|m| *m.borrow_mut() = v); + }); sp_io::TestExternalities::new(t) } @@ -268,6 +273,18 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } +pub struct TestValidatorIdOf; +impl TestValidatorIdOf { + pub fn set(v: BTreeMap) { + VALIDATOR_ACCOUNTS.with(|m| *m.borrow_mut() = v); + } +} +impl Convert> for TestValidatorIdOf { + fn convert(x: u64) -> Option { + VALIDATOR_ACCOUNTS.with(|m| m.borrow().get(&x).cloned()) + } +} + impl Config for Test { type ShouldEndSession = TestShouldEndSession; #[cfg(feature = "historical")] @@ -276,7 +293,7 @@ impl Config for Test { type SessionManager = TestSessionManager; type SessionHandler = TestSessionHandler; type ValidatorId = u64; - type ValidatorIdOf = ConvertInto; + type ValidatorIdOf = TestValidatorIdOf; type Keys = MockSessionKeys; type Event = Event; type NextSessionRotation = (); diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index 42a2dd74fd96c..308ed7c5e5487 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -21,7 +21,7 @@ use super::*; use crate::mock::{ authorities, before_session_end_called, force_new_session, new_test_ext, reset_before_session_end_called, session_changed, set_next_validators, set_session_length, - Origin, PreUpgradeMockSessionKeys, Session, System, Test, SESSION_CHANGED, + Origin, PreUpgradeMockSessionKeys, Session, System, Test, TestValidatorIdOf, SESSION_CHANGED, TEST_SESSION_CHANGED, }; @@ -72,11 +72,35 @@ fn keys_cleared_on_kill() { }) } +#[test] +fn purge_keys_works_for_stash_id() { + let mut ext = new_test_ext(); + ext.execute_with(|| { + assert_eq!(Session::validators(), vec![1, 2, 3]); + TestValidatorIdOf::set(vec![(10, 1), (20, 2), (3, 3)].into_iter().collect()); + assert_eq!(Session::load_keys(&1), Some(UintAuthorityId(1).into())); + assert_eq!(Session::load_keys(&2), Some(UintAuthorityId(2).into())); + + let id = DUMMY; + assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); + + assert_ok!(Session::purge_keys(Origin::signed(10))); + assert_ok!(Session::purge_keys(Origin::signed(2))); + + assert_eq!(Session::load_keys(&10), None); + assert_eq!(Session::load_keys(&20), None); + assert_eq!(Session::key_owner(id, UintAuthorityId(10).get_raw(id)), None); + assert_eq!(Session::key_owner(id, UintAuthorityId(20).get_raw(id)), None); + }) +} + #[test] fn authorities_should_track_validators() { reset_before_session_end_called(); new_test_ext().execute_with(|| { + TestValidatorIdOf::set(vec![(1, 1), (2, 2), (3, 3), (4, 4)].into_iter().collect()); + set_next_validators(vec![1, 2]); force_new_session(); initialize_block(1); @@ -187,6 +211,8 @@ fn session_change_should_work() { #[test] fn duplicates_are_not_allowed() { new_test_ext().execute_with(|| { + TestValidatorIdOf::set(vec![(1, 1), (2, 2), (3, 3), (4, 4)].into_iter().collect()); + System::set_block_number(1); Session::on_initialize(1); assert_noop!( @@ -205,6 +231,7 @@ fn session_changed_flag_works() { reset_before_session_end_called(); new_test_ext().execute_with(|| { + TestValidatorIdOf::set(vec![(1, 1), (2, 2), (3, 3), (69, 69)].into_iter().collect()); TEST_SESSION_CHANGED.with(|l| *l.borrow_mut() = true); force_new_session(); From afd572f208b25312f984987b7bb752e71fbf86d7 Mon Sep 17 00:00:00 2001 From: Cheng JIANG Date: Fri, 15 Oct 2021 18:22:51 +0800 Subject: [PATCH 0134/1472] add TypeInfo trait bound (#10031) --- frame/assets/src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 1ae729d7774d6..4176242c8394a 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -170,6 +170,7 @@ pub mod pallet { use super::*; use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; + use scale_info::TypeInfo; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] @@ -189,7 +190,8 @@ pub mod pallet { + Default + Copy + MaybeSerializeDeserialize - + MaxEncodedLen; + + MaxEncodedLen + + TypeInfo; /// Identifier for the class of asset. type AssetId: Member @@ -198,7 +200,8 @@ pub mod pallet { + Copy + HasCompact + MaybeSerializeDeserialize - + MaxEncodedLen; + + MaxEncodedLen + + TypeInfo; /// The currency mechanism. type Currency: ReservableCurrency; From 09c916c6272abde6ada166a8838d450038ec1284 Mon Sep 17 00:00:00 2001 From: Cheng JIANG Date: Mon, 18 Oct 2021 14:37:22 +0800 Subject: [PATCH 0135/1472] AssetId trait should also contain TypeInfo bound (#10038) --- frame/support/src/traits/tokens/misc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index 214c28708a196..100138171abe7 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -161,8 +161,8 @@ impl WithdrawReasons { } /// Simple amalgamation trait to collect together properties for an AssetId under one roof. -pub trait AssetId: FullCodec + Copy + Eq + PartialEq + Debug {} -impl AssetId for T {} +pub trait AssetId: FullCodec + Copy + Eq + PartialEq + Debug + scale_info::TypeInfo {} +impl AssetId for T {} /// Simple amalgamation trait to collect together properties for a Balance under one roof. pub trait Balance: From 129c16b294f9bb904ce04da78ada98bf168421be Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 18 Oct 2021 09:12:22 +0200 Subject: [PATCH 0136/1472] CI: remove node-template from build-linux-substrate-simnet job (#10034) * ci: remove node-template from build-linux-substrate-simnet * build-linux-substrate job impovements * small fix --- .gitlab-ci.yml | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d36fe2b57add7..6d4362ea93629 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -178,6 +178,21 @@ default: | tee artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json' - sccache -s +.build-linux-substrate-script: &build-linux-substrate-script + - WASM_BUILD_NO_COLOR=1 time cargo build --release --verbose + - mv ./target/release/substrate ./artifacts/substrate/. + - echo -n "Substrate version = " + - if [ "${CI_COMMIT_TAG}" ]; then + echo "${CI_COMMIT_TAG}" | tee ./artifacts/substrate/VERSION; + else + ./artifacts/substrate/substrate --version | + sed -n -E 's/^substrate ([0-9.]+.*-[0-9a-f]{7,13})-.*$/\1/p' | + tee ./artifacts/substrate/VERSION; + fi + - sha256sum ./artifacts/substrate/substrate | tee ./artifacts/substrate/substrate.sha256 + - cp -r .maintain/docker/substrate.Dockerfile ./artifacts/substrate/ + - sccache -s + #### Vault secrets .vault-secrets: &vault-secrets secrets: @@ -571,7 +586,8 @@ check-dependent-cumulus: variables: DEPENDENT_REPO: cumulus -build-linux-substrate: &build-binary + +build-linux-substrate: stage: build <<: *collect-artifacts <<: *docker-env @@ -582,27 +598,21 @@ build-linux-substrate: &build-binary before_script: - mkdir -p ./artifacts/substrate/ script: - - WASM_BUILD_NO_COLOR=1 time cargo build --release --verbose - - mv ./target/release/substrate ./artifacts/substrate/. - - echo -n "Substrate version = " - - if [ "${CI_COMMIT_TAG}" ]; then - echo "${CI_COMMIT_TAG}" | tee ./artifacts/substrate/VERSION; - else - ./artifacts/substrate/substrate --version | - sed -n -E 's/^substrate ([0-9.]+.*-[0-9a-f]{7,13})-.*$/\1/p' | - tee ./artifacts/substrate/VERSION; - fi - - sha256sum ./artifacts/substrate/substrate | tee ./artifacts/substrate/substrate.sha256 + - *build-linux-substrate-script - printf '\n# building node-template\n\n' - ./.maintain/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz - - cp -r .maintain/docker/substrate.Dockerfile ./artifacts/substrate/ - - sccache -s + #Build binary for simnet quick tests. build-linux-substrate-simnet: - <<: *build-binary + stage: build <<: *collect-artifacts-short + <<: *docker-env <<: *test-refs-no-trigger-prs-only + before_script: + - mkdir -p ./artifacts/substrate/ + script: + - *build-linux-substrate-script build-linux-subkey: &build-subkey stage: build From 4a99c091a97bf829e17a53e1a22a87ddc7b4df22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 18 Oct 2021 10:18:13 +0200 Subject: [PATCH 0137/1472] Make duration calculation robust against clock drift (#10042) It is possible that `Instant::now()` is returning an earlier clock time when being called a second time. To guard against this, we should use `saturating_duration_since`. --- client/db/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 549ef4012a739..3b8936c0f7bac 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1076,13 +1076,14 @@ impl FrozenForDuration { F: FnOnce() -> T, { let mut lock = self.value.lock(); - if lock.at.elapsed() > self.duration || lock.value.is_none() { + let now = std::time::Instant::now(); + if now.saturating_duration_since(lock.at) > self.duration || lock.value.is_none() { let new_value = f(); - lock.at = std::time::Instant::now(); + lock.at = now; lock.value = Some(new_value.clone()); new_value } else { - lock.value.as_ref().expect("checked with lock above").clone() + lock.value.as_ref().expect("Checked with in branch above; qed").clone() } } } From abeea6d04d72eddb136ec494298035977c9cdbe4 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Mon, 18 Oct 2021 11:19:35 +0200 Subject: [PATCH 0138/1472] Update lowest unbaked storage. (#9750) * update lowest unbaked * fix format * add note * fmt --- frame/democracy/src/lib.rs | 32 ++++++++++++----- frame/democracy/src/tests.rs | 2 +- frame/democracy/src/tests/cancellation.rs | 4 +++ frame/democracy/src/tests/scheduling.rs | 44 +++++++++++++++++++++++ 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 50b245006fa24..893e4676bef7b 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -613,10 +613,7 @@ pub mod pallet { impl Hooks> for Pallet { /// Weight: see `begin_block` fn on_initialize(n: T::BlockNumber) -> Weight { - Self::begin_block(n).unwrap_or_else(|e| { - sp_runtime::print(e); - 0 - }) + Self::begin_block(n) } } @@ -1682,7 +1679,7 @@ impl Pallet { now: T::BlockNumber, index: ReferendumIndex, status: ReferendumStatus>, - ) -> Result { + ) -> bool { let total_issuance = T::Currency::total_issuance(); let approved = status.threshold.approved(status.tally, total_issuance); @@ -1719,7 +1716,7 @@ impl Pallet { Self::deposit_event(Event::::NotPassed(index)); } - Ok(approved) + approved } /// Current era is ending; we should finish up any proposals. @@ -1734,7 +1731,7 @@ impl Pallet { /// - Db writes: `PublicProps`, `account`, `ReferendumCount`, `DepositOf`, `ReferendumInfoOf` /// - Db reads per R: `DepositOf`, `ReferendumInfoOf` /// # - fn begin_block(now: T::BlockNumber) -> Result { + fn begin_block(now: T::BlockNumber) -> Weight { let max_block_weight = T::BlockWeights::get().max_block; let mut weight = 0; @@ -1758,12 +1755,29 @@ impl Pallet { // tally up votes for any expiring referenda. for (index, info) in Self::maturing_referenda_at_inner(now, next..last).into_iter() { - let approved = Self::bake_referendum(now, index, info)?; + let approved = Self::bake_referendum(now, index, info); ReferendumInfoOf::::insert(index, ReferendumInfo::Finished { end: now, approved }); weight = max_block_weight; } - Ok(weight) + // Notes: + // * We don't consider the lowest unbaked to be the last maturing in case some refendum have + // longer voting period than others. + // * The iteration here shouldn't trigger any storage read that are not in cache, due to + // `maturing_referenda_at_inner` having already read them. + // * We shouldn't iterate more than `LaunchPeriod/VotingPeriod + 1` times because the number + // of unbaked referendum is bounded by this number. In case those number have changed in a + // runtime upgrade the formula should be adjusted but the bound should still be sensible. + >::mutate(|ref_index| { + while *ref_index < last && + Self::referendum_info(*ref_index) + .map_or(true, |info| matches!(info, ReferendumInfo::Finished { .. })) + { + *ref_index += 1 + } + }); + + weight } /// Reads the length of account in DepositOf without getting the complete value in the runtime. diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 75104db51b971..f56667e9094b3 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -264,7 +264,7 @@ fn propose_set_balance_and_note(who: u64, value: u64, delay: u64) -> DispatchRes fn next_block() { System::set_block_number(System::block_number() + 1); Scheduler::on_initialize(System::block_number()); - assert!(Democracy::begin_block(System::block_number()).is_ok()); + Democracy::begin_block(System::block_number()); } fn fast_forward_to(n: u64) { diff --git a/frame/democracy/src/tests/cancellation.rs b/frame/democracy/src/tests/cancellation.rs index c2bd725ce934a..83822bf51829f 100644 --- a/frame/democracy/src/tests/cancellation.rs +++ b/frame/democracy/src/tests/cancellation.rs @@ -30,10 +30,14 @@ fn cancel_referendum_should_work() { ); assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); assert_ok!(Democracy::cancel_referendum(Origin::root(), r.into())); + assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); + next_block(); + assert_eq!(Democracy::lowest_unbaked(), 1); + assert_eq!(Democracy::lowest_unbaked(), Democracy::referendum_count()); assert_eq!(Balances::free_balance(42), 0); }); } diff --git a/frame/democracy/src/tests/scheduling.rs b/frame/democracy/src/tests/scheduling.rs index 06b492bc6093c..5c857a632b97b 100644 --- a/frame/democracy/src/tests/scheduling.rs +++ b/frame/democracy/src/tests/scheduling.rs @@ -30,8 +30,10 @@ fn simple_passing_should_work() { ); assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); assert_eq!(tally(r), Tally { ayes: 1, nays: 0, turnout: 10 }); + assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); next_block(); + assert_eq!(Democracy::lowest_unbaked(), 1); assert_eq!(Balances::free_balance(42), 2); }); } @@ -110,3 +112,45 @@ fn delayed_enactment_should_work() { assert_eq!(Balances::free_balance(42), 2); }); } + +#[test] +fn lowest_unbaked_should_be_sensible() { + new_test_ext().execute_with(|| { + let r1 = Democracy::inject_referendum( + 3, + set_balance_proposal_hash_and_note(1), + VoteThreshold::SuperMajorityApprove, + 0, + ); + let r2 = Democracy::inject_referendum( + 2, + set_balance_proposal_hash_and_note(2), + VoteThreshold::SuperMajorityApprove, + 0, + ); + let r3 = Democracy::inject_referendum( + 10, + set_balance_proposal_hash_and_note(3), + VoteThreshold::SuperMajorityApprove, + 0, + ); + assert_ok!(Democracy::vote(Origin::signed(1), r1, aye(1))); + assert_ok!(Democracy::vote(Origin::signed(1), r2, aye(1))); + // r3 is canceled + assert_ok!(Democracy::cancel_referendum(Origin::root(), r3.into())); + assert_eq!(Democracy::lowest_unbaked(), 0); + + next_block(); + + // r2 is approved + assert_eq!(Balances::free_balance(42), 2); + assert_eq!(Democracy::lowest_unbaked(), 0); + + next_block(); + + // r1 is approved + assert_eq!(Balances::free_balance(42), 1); + assert_eq!(Democracy::lowest_unbaked(), 3); + assert_eq!(Democracy::lowest_unbaked(), Democracy::referendum_count()); + }); +} From d1ec40b49847fdb6dae8f00ab7ab08cef7dd10fc Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Mon, 18 Oct 2021 04:42:56 -0600 Subject: [PATCH 0139/1472] Clarify wieght traits needed to impl in example (#9842) * Clarify wieght traits needed to impl in example * Update frame/example/src/lib.rs * Update frame/example/src/lib.rs Co-authored-by: Guillaume Thiolliere * fmt Co-authored-by: Squirrel Co-authored-by: Guillaume Thiolliere --- frame/example/src/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/frame/example/src/lib.rs b/frame/example/src/lib.rs index f0b58e9aec153..981274b1ba739 100644 --- a/frame/example/src/lib.rs +++ b/frame/example/src/lib.rs @@ -486,11 +486,12 @@ pub mod pallet { // the chain in a moderate rate. // // The parenthesized value of the `#[pallet::weight(..)]` attribute can be any type that - // implements a set of traits, namely [`WeighData`] and [`ClassifyDispatch`]. - // The former conveys the weight (a numeric representation of pure execution time and - // difficulty) of the transaction and the latter demonstrates the [`DispatchClass`] of the - // call. A higher weight means a larger transaction (less of which can be placed in a - // single block). + // implements a set of traits, namely [`WeighData`], [`ClassifyDispatch`], and + // [`PaysFee`]. The first conveys the weight (a numeric representation of pure + // execution time and difficulty) of the transaction and the second demonstrates the + // [`DispatchClass`] of the call, the third gives whereas extrinsic must pay fees or not. + // A higher weight means a larger transaction (less of which can be placed in a single + // block). // // The weight for this extrinsic we rely on the auto-generated `WeightInfo` from the // benchmark toolchain. From 781454d981a144d31f6cd1628cccd233b34d468a Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 19 Oct 2021 13:56:09 +0200 Subject: [PATCH 0140/1472] Don't print "Discovered new external" line for private IPs (#10055) --- client/network/src/discovery.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 1ed08cd671d4e..2a4b25a621e04 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -599,14 +599,16 @@ impl NetworkBehaviour for DiscoveryBehaviour { fn inject_new_external_addr(&mut self, addr: &Multiaddr) { let new_addr = addr.clone().with(Protocol::P2p(self.local_peer_id.into())); - // NOTE: we might re-discover the same address multiple times - // in which case we just want to refrain from logging. - if self.known_external_addresses.insert(new_addr.clone()) { - info!( - target: "sub-libp2p", - "🔍 Discovered new external address for our node: {}", - new_addr, - ); + if self.can_add_to_dht(addr) { + // NOTE: we might re-discover the same address multiple times + // in which case we just want to refrain from logging. + if self.known_external_addresses.insert(new_addr.clone()) { + info!( + target: "sub-libp2p", + "🔍 Discovered new external address for our node: {}", + new_addr, + ); + } } for k in self.kademlias.values_mut() { From 29938120830e13a7a9f0f4daa71ca96e03c3002a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Tue, 19 Oct 2021 14:05:05 -0300 Subject: [PATCH 0141/1472] remove hardcoded pipeline scripts tag (#10061) the tag will be moved to Gitlab CI/CD variables --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6d4362ea93629..75fdf024d5bdf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,7 +46,6 @@ variables: &default-vars VAULT_AUTH_PATH: "gitlab-parity-io-jwt" VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" SIMNET_FEATURES_PATH: "simnet_tests/tests" - PIPELINE_SCRIPTS_TAG: "v0.1" default: cache: {} From 72a8f9fc6e25a82636b7d4b35ce98f79ec29ec38 Mon Sep 17 00:00:00 2001 From: Robert Klotzner Date: Tue, 19 Oct 2021 19:52:50 +0200 Subject: [PATCH 0142/1472] Slightly improved documentation. (#9976) Co-authored-by: Pierre Krieger Co-authored-by: Giles Cope --- client/network/src/service.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 9b6e54f37a663..90e647505fa1f 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -1097,6 +1097,15 @@ impl NetworkService { /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also /// consist of only `/p2p/`. /// + /// The node will start establishing/accepting connections and substreams to/from peers in this + /// set, if it doesn't have any substream open with them yet. + /// + /// Note however, if a call to this function results in less peers on the reserved set, they + /// will not necessarily get disconnected (depending on available free slots in the peer set). + /// If you want to also disconnect those removed peers, you will have to call + /// `remove_from_peers_set` on those in addition to updating the reserved set. You can omit + /// this step if the peer set is in reserved only mode. + /// /// Returns an `Err` if one of the given addresses is invalid or contains an /// invalid peer ID (which includes the local peer ID). pub fn set_reserved_peers( From dcad42f9b51130621e24c3a93ca1075cd1bb9d15 Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Tue, 19 Oct 2021 17:30:46 -0500 Subject: [PATCH 0143/1472] Derive Encode/Decode for BlockId (#10063) --- primitives/runtime/src/generic/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/runtime/src/generic/block.rs b/primitives/runtime/src/generic/block.rs index 21a01933bc691..68959cc514d94 100644 --- a/primitives/runtime/src/generic/block.rs +++ b/primitives/runtime/src/generic/block.rs @@ -35,7 +35,7 @@ use sp_core::RuntimeDebug; use sp_std::prelude::*; /// Something to identify a block. -#[derive(PartialEq, Eq, Clone, RuntimeDebug)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Serialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))] From 11754462c426c782bd7eb0416b4eddee5c475439 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 21 Oct 2021 10:29:10 +0200 Subject: [PATCH 0144/1472] Allow pallet's info to be enumerated (#10053) * Allow pallet's info to be enumerated * Fixes * Formatting * Flat tuple for getting all pallet instances * Renaming and fixing reversedness * Formatting * Fixes * Back to nesting * Back to nestingx * Revert executive lib * Reversions * Reversions * Fixes * Fixes * Formatting * Fixes * Spelling * Comments --- frame/executive/README.md | 17 +++- .../procedural/src/construct_runtime/mod.rs | 1 + .../src/pallet/expand/pallet_struct.rs | 19 ++++ frame/support/src/dispatch.rs | 16 ++++ frame/support/src/lib.rs | 4 +- frame/support/src/migrations.rs | 4 +- frame/support/src/traits.rs | 3 +- frame/support/src/traits/metadata.rs | 88 +++++++++++++++++++ frame/support/test/tests/pallet_instance.rs | 42 +++++++++ 9 files changed, 187 insertions(+), 7 deletions(-) diff --git a/frame/executive/README.md b/frame/executive/README.md index ae3bbf1a9d994..e96d07b0843f2 100644 --- a/frame/executive/README.md +++ b/frame/executive/README.md @@ -35,7 +35,13 @@ The default Substrate node template declares the [`Executive`](https://docs.rs/f ```rust # /// Executive: handles dispatch to the various modules. -pub type Executive = executive::Executive; +pub type Executive = executive::Executive< + Runtime, + Block, + Context, + Runtime, + AllPallets, +>; ``` ### Custom `OnRuntimeUpgrade` logic @@ -54,7 +60,14 @@ impl frame_support::traits::OnRuntimeUpgrade for CustomOnRuntimeUpgrade { } } -pub type Executive = executive::Executive; +pub type Executive = executive::Executive< + Runtime, + Block, + Context, + Runtime, + AllPallets, + CustomOnRuntimeUpgrade, +>; ``` License: Apache-2.0 diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 04bb2ead645d2..863df34266591 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -217,6 +217,7 @@ fn decl_all_pallets<'a>( quote!( #types + /// All pallets included in the runtime as a nested tuple of types. /// Excludes the System pallet. pub type AllPallets = ( #all_pallets ); diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 57e814b6b8438..96dfdbb4b6f2d 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -233,6 +233,25 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { } } + impl<#type_impl_gen> #frame_support::traits::PalletsInfoAccess + for #pallet_ident<#type_use_gen> + #config_where_clause + { + fn count() -> usize { 1 } + fn accumulate( + acc: &mut #frame_support::sp_std::vec::Vec<#frame_support::traits::PalletInfoData> + ) { + use #frame_support::traits::PalletInfoAccess; + let item = #frame_support::traits::PalletInfoData { + index: Self::index(), + name: Self::name(), + module_name: Self::module_name(), + crate_version: Self::crate_version(), + }; + acc.push(item); + } + } + #storage_info ) } diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 6dc7fb8a94cae..a492bc12f6a38 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -2165,6 +2165,22 @@ macro_rules! decl_module { } } + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::traits::PalletsInfoAccess + for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* + { + fn count() -> usize { 1 } + fn accumulate(acc: &mut $crate::sp_std::vec::Vec<$crate::traits::PalletInfoData>) { + use $crate::traits::PalletInfoAccess; + let item = $crate::traits::PalletInfoData { + index: Self::index(), + name: Self::name(), + module_name: Self::module_name(), + crate_version: Self::crate_version(), + }; + acc.push(item); + } + } + // Implement GetCallName for the Call. impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::GetCallName for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index f3b00c764bb35..1b93b5fb5975e 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1476,11 +1476,11 @@ pub mod pallet_prelude { /// * [`traits::OnGenesis`]: contains some logic to write pallet version into storage. /// * `PalletErrorTypeInfo`: provides the type information for the pallet error, if defined. /// -/// It declare `type Module` type alias for `Pallet`, used by [`construct_runtime`]. +/// It declares `type Module` type alias for `Pallet`, used by [`construct_runtime`]. /// /// It implements [`traits::PalletInfoAccess`] on `Pallet` to ease access to pallet /// informations given by [`frame_support::traits::PalletInfo`]. -/// (The implementation use the associated type `frame_system::Config::PalletInfo`). +/// (The implementation uses the associated type `frame_system::Config::PalletInfo`). /// /// It implements [`traits::StorageInfoTrait`] on `Pallet` which give information about all /// storages. diff --git a/frame/support/src/migrations.rs b/frame/support/src/migrations.rs index dc3402440fdd4..c61cbac62a16b 100644 --- a/frame/support/src/migrations.rs +++ b/frame/support/src/migrations.rs @@ -58,9 +58,9 @@ impl PalletVersionToStorageVersionHelper for T { /// /// This will remove all `PalletVersion's` from the state and insert the current storage version. pub fn migrate_from_pallet_version_to_storage_version< - AllPallets: PalletVersionToStorageVersionHelper, + Pallets: PalletVersionToStorageVersionHelper, >( db_weight: &RuntimeDbWeight, ) -> Weight { - AllPallets::migrate(db_weight) + Pallets::migrate(db_weight) } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 5ac0208dc2033..513267c5c8ba6 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -63,7 +63,8 @@ pub use randomness::Randomness; mod metadata; pub use metadata::{ CallMetadata, CrateVersion, GetCallMetadata, GetCallName, GetStorageVersion, PalletInfo, - PalletInfoAccess, StorageVersion, STORAGE_VERSION_STORAGE_KEY_POSTFIX, + PalletInfoAccess, PalletInfoData, PalletsInfoAccess, StorageVersion, + STORAGE_VERSION_STORAGE_KEY_POSTFIX, }; mod hooks; diff --git a/frame/support/src/traits/metadata.rs b/frame/support/src/traits/metadata.rs index e60cf8be8a41c..0da76f7585aca 100644 --- a/frame/support/src/traits/metadata.rs +++ b/frame/support/src/traits/metadata.rs @@ -19,6 +19,7 @@ use codec::{Decode, Encode}; use sp_runtime::RuntimeDebug; +use sp_std::prelude::*; /// Provides information about the pallet itself and its setup in the runtime. /// @@ -35,6 +36,19 @@ pub trait PalletInfo { fn crate_version() -> Option; } +/// Information regarding an instance of a pallet. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)] +pub struct PalletInfoData { + /// Index of the pallet as configured in the runtime. + pub index: usize, + /// Name of the pallet as configured in the runtime. + pub name: &'static str, + /// Name of the Rust module containing the pallet. + pub module_name: &'static str, + /// Version of the crate containing the pallet. + pub crate_version: CrateVersion, +} + /// Provides information about the pallet itself and its setup in the runtime. /// /// Declare some information and access the information provided by [`PalletInfo`] for a specific @@ -50,6 +64,49 @@ pub trait PalletInfoAccess { fn crate_version() -> CrateVersion; } +/// Provide information about a bunch of pallets. +pub trait PalletsInfoAccess { + /// The number of pallets' information that this type represents. + /// + /// You probably don't want this function but `infos()` instead. + fn count() -> usize { + 0 + } + + /// Extend the given vector by all of the pallets' information that this type represents. + /// + /// You probably don't want this function but `infos()` instead. + fn accumulate(_accumulator: &mut Vec) {} + + /// All of the pallets' information that this type represents. + fn infos() -> Vec { + let mut result = Vec::with_capacity(Self::count()); + Self::accumulate(&mut result); + result + } +} + +impl PalletsInfoAccess for () {} +impl PalletsInfoAccess for (T,) { + fn count() -> usize { + T::count() + } + fn accumulate(acc: &mut Vec) { + T::accumulate(acc) + } +} + +impl PalletsInfoAccess for (T1, T2) { + fn count() -> usize { + T1::count() + T2::count() + } + fn accumulate(acc: &mut Vec) { + // The AllPallets type tuplises the pallets in reverse order, so we unreverse them here. + T2::accumulate(acc); + T1::accumulate(acc); + } +} + /// The function and pallet name of the Call. #[derive(Clone, Eq, PartialEq, Default, RuntimeDebug)] pub struct CallMetadata { @@ -206,6 +263,37 @@ pub trait GetStorageVersion { mod tests { use super::*; + struct Pallet1; + impl PalletInfoAccess for Pallet1 { + fn index() -> usize { + 1 + } + fn name() -> &'static str { + "Pallet1" + } + fn module_name() -> &'static str { + "pallet1" + } + fn crate_version() -> CrateVersion { + CrateVersion::new(1, 0, 0) + } + } + struct Pallet2; + impl PalletInfoAccess for Pallet2 { + fn index() -> usize { + 2 + } + fn name() -> &'static str { + "Pallet2" + } + fn module_name() -> &'static str { + "pallet2" + } + fn crate_version() -> CrateVersion { + CrateVersion::new(1, 0, 0) + } + } + #[test] fn check_storage_version_ordering() { let version = StorageVersion::new(1); diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 34586e8414216..3a1009402d6f2 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -505,6 +505,48 @@ fn storage_expand() { }); } +#[test] +fn pallet_metadata_expands() { + use frame_support::traits::{CrateVersion, PalletInfoData, PalletsInfoAccess}; + let mut infos = AllPalletsWithSystem::infos(); + infos.sort_by_key(|x| x.index); + assert_eq!( + infos, + vec![ + PalletInfoData { + index: 0, + name: "System", + module_name: "frame_system", + crate_version: CrateVersion { major: 4, minor: 0, patch: 0 }, + }, + PalletInfoData { + index: 1, + name: "Example", + module_name: "pallet", + crate_version: CrateVersion { major: 3, minor: 0, patch: 0 }, + }, + PalletInfoData { + index: 2, + name: "Instance1Example", + module_name: "pallet", + crate_version: CrateVersion { major: 3, minor: 0, patch: 0 }, + }, + PalletInfoData { + index: 3, + name: "Example2", + module_name: "pallet2", + crate_version: CrateVersion { major: 3, minor: 0, patch: 0 }, + }, + PalletInfoData { + index: 4, + name: "Instance1Example2", + module_name: "pallet2", + crate_version: CrateVersion { major: 3, minor: 0, patch: 0 }, + }, + ] + ); +} + #[test] fn pallet_hooks_expand() { TestExternalities::default().execute_with(|| { From 05af3c2c06caa85485e0c8eaa1c829da1a379c84 Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Thu, 21 Oct 2021 15:44:46 +0300 Subject: [PATCH 0145/1472] Temporarily disable `node-bench-regression-guard` (#10075) --- .gitlab-ci.yml | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 75fdf024d5bdf..f49211c238c0c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -364,28 +364,29 @@ cargo-check-benches: script: - *cargo-check-benches-script -node-bench-regression-guard: - # it's not belong to `build` semantically, but dag jobs can't depend on each other - # within the single stage - https://gitlab.com/gitlab-org/gitlab/-/issues/30632 - # more: https://github.com/paritytech/substrate/pull/8519#discussion_r608012402 - stage: build - <<: *docker-env - <<: *test-refs-no-trigger-prs-only - needs: - # this is a DAG - - job: cargo-check-benches - artifacts: true - # this does not like a DAG, just polls the artifact - - project: $CI_PROJECT_PATH - job: cargo-check-benches - ref: master - artifacts: true - variables: - CI_IMAGE: "paritytech/node-bench-regression-guard:latest" - before_script: [""] - script: - - 'node-bench-regression-guard --reference artifacts/benches/master-* - --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA' +# TODO: re-enable after dedicated bench hosts provisioning +# node-bench-regression-guard: +# # it's not belong to `build` semantically, but dag jobs can't depend on each other +# # within the single stage - https://gitlab.com/gitlab-org/gitlab/-/issues/30632 +# # more: https://github.com/paritytech/substrate/pull/8519#discussion_r608012402 +# stage: build +# <<: *docker-env +# <<: *test-refs-no-trigger-prs-only +# needs: +# # this is a DAG +# - job: cargo-check-benches +# artifacts: true +# # this does not like a DAG, just polls the artifact +# - project: $CI_PROJECT_PATH +# job: cargo-check-benches +# ref: master +# artifacts: true +# variables: +# CI_IMAGE: "paritytech/node-bench-regression-guard:latest" +# before_script: [""] +# script: +# - 'node-bench-regression-guard --reference artifacts/benches/master-* +# --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA' cargo-check-subkey: stage: test From 485e592ee2ef4db499134e9a903c02574d731593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Thu, 21 Oct 2021 10:03:50 -0300 Subject: [PATCH 0146/1472] remove logging from the check-dependent-* job (#10076) such command should belong to the script rather than the job --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f49211c238c0c..6ad2ff1a46d8f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -570,7 +570,6 @@ cargo-check-macos: --substrate "$DEPENDENT_REPO" "$GITHUB_PR_TOKEN" - - cd "$DEPENDENT_REPO" && git rev-parse --abbrev-ref HEAD # Individual jobs are set up for each dependent project so that they can be ran in parallel. # Arguably we could generate a job for each companion in the PR's description using Gitlab's From 632b32300eb9376767c2ae7b38e79b3f7f5329b1 Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 22 Oct 2021 01:54:15 +0900 Subject: [PATCH 0147/1472] Speed up logging once again (#9981) * Update `tracing`-related dependencies * Enable `parking_lot` feature in `tracing-subscriber` * Add an asynchronous stderr logger * Make clippy happy * Add an integration test for the logger * Refactor `test_logger_filters`'s subprocess machinery into a separate function * Use a child process instead of hooking into stderr for the test * Add a doc comment for `MakeStderrWriter` * Move the initialization into the `MakeStderrWriter`'s constructor * Add an extra test case to trigger the logger's emergency flush mechanism * Use the buffer's mutex for asynchronous flushes * Remove vestigial `nix` dependency from one of the previous commits --- Cargo.lock | 10 +- client/tracing/Cargo.toml | 3 +- client/tracing/src/logging/directives.rs | 2 +- client/tracing/src/logging/mod.rs | 147 +++++++++++-- client/tracing/src/logging/stderr_writer.rs | 228 ++++++++++++++++++++ primitives/tracing/Cargo.toml | 4 +- 6 files changed, 373 insertions(+), 21 deletions(-) create mode 100644 client/tracing/src/logging/stderr_writer.rs diff --git a/Cargo.lock b/Cargo.lock index f15e363bfd6ae..6325304bfceec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4085,9 +4085,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.6.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" dependencies = [ "autocfg 1.0.1", ] @@ -8466,6 +8466,7 @@ dependencies = [ "chrono", "criterion", "lazy_static", + "libc", "log 0.4.14", "once_cell", "parking_lot 0.11.1", @@ -10635,14 +10636,15 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.19" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab69019741fca4d98be3c62d2b75254528b5432233fd8a4d2739fec20278de48" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" dependencies = [ "ansi_term 0.12.1", "chrono", "lazy_static", "matchers", + "parking_lot 0.11.1", "regex", "serde", "serde_json", diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index b4049fa097ff8..4939e6a73110c 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -17,6 +17,7 @@ ansi_term = "0.12.1" atty = "0.2.13" chrono = "0.4.19" lazy_static = "1.4.0" +libc = "0.2.95" log = { version = "0.4.8" } once_cell = "1.8.0" parking_lot = "0.11.1" @@ -26,7 +27,7 @@ serde = "1.0.126" thiserror = "1.0.21" tracing = "0.1.29" tracing-log = "0.1.2" -tracing-subscriber = "0.2.19" +tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } diff --git a/client/tracing/src/logging/directives.rs b/client/tracing/src/logging/directives.rs index 16f68654de1eb..fe7d6a780dbf0 100644 --- a/client/tracing/src/logging/directives.rs +++ b/client/tracing/src/logging/directives.rs @@ -109,5 +109,5 @@ pub(crate) fn set_reload_handle(handle: Handle) { type SCSubscriber< N = tracing_fmt::format::DefaultFields, E = crate::logging::EventFormat, - W = fn() -> std::io::Stderr, + W = crate::logging::DefaultLogger, > = layer::Layered, Registry>; diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index c6a4f070176e8..7f995615a223b 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -26,6 +26,9 @@ mod directives; mod event_format; mod fast_local_time; mod layers; +mod stderr_writer; + +pub(crate) type DefaultLogger = stderr_writer::MakeStderrWriter; pub use directives::*; pub use sc_tracing_proc_macro::*; @@ -47,6 +50,8 @@ pub use event_format::*; pub use fast_local_time::FastLocalTime; pub use layers::*; +use stderr_writer::MakeStderrWriter; + /// Logging Result typedef. pub type Result = std::result::Result; @@ -91,7 +96,7 @@ fn prepare_subscriber( profiling_targets: Option<&str>, force_colors: Option, builder_hook: impl Fn( - SubscriberBuilder std::io::Stderr>, + SubscriberBuilder, ) -> SubscriberBuilder, ) -> Result LookupSpan<'a>> where @@ -172,7 +177,7 @@ where let builder = builder.with_span_events(format::FmtSpan::NONE); - let builder = builder.with_writer(std::io::stderr as _); + let builder = builder.with_writer(MakeStderrWriter::default()); let builder = builder.event_format(event_format); @@ -282,7 +287,16 @@ impl LoggerBuilder { mod tests { use super::*; use crate as sc_tracing; - use std::{env, process::Command}; + use log::info; + use std::{ + collections::BTreeMap, + env, + process::Command, + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, + }, + }; use tracing::{metadata::Kind, subscriber::Interest, Callsite, Level, Metadata}; const EXPECTED_LOG_MESSAGE: &'static str = "yeah logging works as expected"; @@ -292,9 +306,28 @@ mod tests { let _ = LoggerBuilder::new(directives).init().unwrap(); } + fn run_test_in_another_process( + test_name: &str, + test_body: impl FnOnce(), + ) -> Option { + if env::var("RUN_FORKED_TEST").is_ok() { + test_body(); + None + } else { + let output = Command::new(env::current_exe().unwrap()) + .arg(test_name) + .env("RUN_FORKED_TEST", "1") + .output() + .unwrap(); + + assert!(output.status.success()); + Some(output) + } + } + #[test] fn test_logger_filters() { - if env::var("RUN_TEST_LOGGER_FILTERS").is_ok() { + run_test_in_another_process("test_logger_filters", || { let test_directives = "afg=debug,sync=trace,client=warn,telemetry,something-with-dash=error"; init_logger(&test_directives); @@ -331,15 +364,7 @@ mod tests { assert!(test_filter("telemetry", Level::TRACE)); assert!(test_filter("something-with-dash", Level::ERROR)); }); - } else { - let status = Command::new(env::current_exe().unwrap()) - .arg("test_logger_filters") - .env("RUN_TEST_LOGGER_FILTERS", "1") - .output() - .unwrap() - .status; - assert!(status.success()); - } + }); } /// This test ensures that using dash (`-`) in the target name in logs and directives actually @@ -474,4 +499,100 @@ mod tests { assert_eq!("MAX_LOG_LEVEL=Trace", run_test(None, Some("test=info".into()))); } } + + // This creates a bunch of threads and makes sure they start executing + // a given callback almost exactly at the same time. + fn run_on_many_threads(thread_count: usize, callback: impl Fn(usize) + 'static + Send + Clone) { + let started_count = Arc::new(AtomicUsize::new(0)); + let barrier = Arc::new(AtomicBool::new(false)); + let threads: Vec<_> = (0..thread_count) + .map(|nth_thread| { + let started_count = started_count.clone(); + let barrier = barrier.clone(); + let callback = callback.clone(); + + std::thread::spawn(move || { + started_count.fetch_add(1, Ordering::SeqCst); + while !barrier.load(Ordering::SeqCst) { + std::thread::yield_now(); + } + + callback(nth_thread); + }) + }) + .collect(); + + while started_count.load(Ordering::SeqCst) != thread_count { + std::thread::yield_now(); + } + barrier.store(true, Ordering::SeqCst); + + for thread in threads { + if let Err(error) = thread.join() { + println!("error: failed to join thread: {:?}", error); + unsafe { libc::abort() } + } + } + } + + #[test] + fn parallel_logs_from_multiple_threads_are_properly_gathered() { + const THREAD_COUNT: usize = 128; + const LOGS_PER_THREAD: usize = 1024; + + let output = run_test_in_another_process( + "parallel_logs_from_multiple_threads_are_properly_gathered", + || { + let builder = LoggerBuilder::new(""); + builder.init().unwrap(); + + run_on_many_threads(THREAD_COUNT, |nth_thread| { + for _ in 0..LOGS_PER_THREAD { + info!("Thread <<{}>>", nth_thread); + } + }); + }, + ); + + if let Some(output) = output { + let stderr = String::from_utf8(output.stderr).unwrap(); + let mut count_per_thread = BTreeMap::new(); + for line in stderr.split("\n") { + if let Some(index_s) = line.find("Thread <<") { + let index_s = index_s + "Thread <<".len(); + let index_e = line.find(">>").unwrap(); + let nth_thread: usize = line[index_s..index_e].parse().unwrap(); + *count_per_thread.entry(nth_thread).or_insert(0) += 1; + } + } + + assert_eq!(count_per_thread.len(), THREAD_COUNT); + for (_, count) in count_per_thread { + assert_eq!(count, LOGS_PER_THREAD); + } + } + } + + #[test] + fn huge_single_line_log_is_properly_printed_out() { + let mut line = String::new(); + line.push_str("$$START$$"); + for n in 0..16 * 1024 * 1024 { + let ch = b'a' + (n as u8 % (b'z' - b'a')); + line.push(char::from(ch)); + } + line.push_str("$$END$$"); + + let output = + run_test_in_another_process("huge_single_line_log_is_properly_printed_out", || { + let builder = LoggerBuilder::new(""); + builder.init().unwrap(); + info!("{}", line); + }); + + if let Some(output) = output { + let stderr = String::from_utf8(output.stderr).unwrap(); + assert!(stderr.contains(&line)); + } + } } diff --git a/client/tracing/src/logging/stderr_writer.rs b/client/tracing/src/logging/stderr_writer.rs new file mode 100644 index 0000000000000..9aab2491fb872 --- /dev/null +++ b/client/tracing/src/logging/stderr_writer.rs @@ -0,0 +1,228 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! This module contains a buffered semi-asynchronous stderr writer. +//! +//! Depending on how we were started writing to stderr can take a surprisingly long time. +//! +//! If the other side takes their sweet sweet time reading whatever we send them then writing +//! to stderr might block for a long time, since it is effectively a synchronous operation. +//! And every time we write to stderr we need to grab a global lock, which affects every thread +//! which also tries to log something at the same time. +//! +//! Of course we *will* be ultimately limited by how fast the recipient can ingest our logs, +//! but it's not like logging is the only thing we're doing. And we still can't entirely +//! avoid the problem of multiple threads contending for the same lock. (Well, technically +//! we could employ something like a lock-free circular buffer, but that might be like +//! killing a fly with a sledgehammer considering the complexity involved; this is only +//! a logger after all.) +//! +//! But we can try to make things a little better. We can offload actually writing to stderr +//! to another thread and flush the logs in bulk instead of doing it per-line, which should +//! reduce the amount of CPU time we waste on making syscalls and on spinning waiting for locks. +//! +//! How much this helps depends on a multitude of factors, including the hardware we're running on, +//! how much we're logging, from how many threads, which exact set of threads are logging, to what +//! stderr is actually connected to (is it a terminal emulator? a file? an UDP socket?), etc. +//! +//! In general this can reduce the real time execution time as much as 75% in certain cases, or it +//! can make absolutely no difference in others. + +use parking_lot::{Condvar, Mutex, Once}; +use std::{ + io::Write, + sync::atomic::{AtomicBool, Ordering}, + time::Duration, +}; +use tracing::{Level, Metadata}; + +/// How many bytes of buffered logs will trigger an async flush on another thread? +const ASYNC_FLUSH_THRESHOLD: usize = 16 * 1024; + +/// How many bytes of buffered logs will trigger a sync flush on the current thread? +const SYNC_FLUSH_THRESHOLD: usize = 768 * 1024; + +/// How many bytes can be buffered at maximum? +const EMERGENCY_FLUSH_THRESHOLD: usize = 2 * 1024 * 1024; + +/// If there isn't enough printed out this is how often the logs will be automatically flushed. +const AUTOFLUSH_EVERY: Duration = Duration::from_millis(50); + +/// The least serious level at which a synchronous flush will be triggered. +const SYNC_FLUSH_LEVEL_THRESHOLD: Level = Level::ERROR; + +/// The amount of time we'll block until the buffer is fully flushed on exit. +/// +/// This should be completely unnecessary in normal circumstances. +const ON_EXIT_FLUSH_TIMEOUT: Duration = Duration::from_secs(5); + +/// A global buffer to which we'll append all of our logs before flushing them out to stderr. +static BUFFER: Mutex> = parking_lot::const_mutex(Vec::new()); + +/// A spare buffer which we'll swap with the main buffer on each flush to minimize lock contention. +static SPARE_BUFFER: Mutex> = parking_lot::const_mutex(Vec::new()); + +/// A conditional variable used to forcefully trigger asynchronous flushes. +static ASYNC_FLUSH_CONDVAR: Condvar = Condvar::new(); + +static ENABLE_ASYNC_LOGGING: AtomicBool = AtomicBool::new(true); + +fn flush_logs(mut buffer: parking_lot::lock_api::MutexGuard>) { + let mut spare_buffer = SPARE_BUFFER.lock(); + std::mem::swap(&mut *spare_buffer, &mut *buffer); + std::mem::drop(buffer); + + let stderr = std::io::stderr(); + let mut stderr_lock = stderr.lock(); + let _ = stderr_lock.write_all(&*spare_buffer); + std::mem::drop(stderr_lock); + + spare_buffer.clear(); +} + +fn log_autoflush_thread() { + let mut buffer = BUFFER.lock(); + loop { + ASYNC_FLUSH_CONDVAR.wait_for(&mut buffer, AUTOFLUSH_EVERY); + loop { + flush_logs(buffer); + + buffer = BUFFER.lock(); + if buffer.len() >= ASYNC_FLUSH_THRESHOLD { + // While we were busy flushing we picked up enough logs to do another flush. + continue + } else { + break + } + } + } +} + +#[cold] +fn initialize() { + std::thread::Builder::new() + .name("log-autoflush".to_owned()) + .spawn(log_autoflush_thread) + .expect("thread spawning doesn't normally fail; qed"); + + // SAFETY: This is safe since we pass a valid pointer to `atexit`. + let errcode = unsafe { libc::atexit(on_exit) }; + assert_eq!(errcode, 0, "atexit failed while setting up the logger: {}", errcode); +} + +extern "C" fn on_exit() { + ENABLE_ASYNC_LOGGING.store(false, Ordering::SeqCst); + + if let Some(buffer) = BUFFER.try_lock_for(ON_EXIT_FLUSH_TIMEOUT) { + flush_logs(buffer); + } +} + +/// A drop-in replacement for [`std::io::stderr`] for use anywhere +/// a [`tracing_subscriber::fmt::MakeWriter`] is accepted. +pub struct MakeStderrWriter { + // A dummy field so that the structure is not publicly constructible. + _dummy: (), +} + +impl Default for MakeStderrWriter { + fn default() -> Self { + static ONCE: Once = Once::new(); + ONCE.call_once(initialize); + MakeStderrWriter { _dummy: () } + } +} + +impl tracing_subscriber::fmt::MakeWriter for MakeStderrWriter { + type Writer = StderrWriter; + + fn make_writer(&self) -> Self::Writer { + StderrWriter::new(false) + } + + // The `tracing-subscriber` crate calls this for every line logged. + fn make_writer_for(&self, meta: &Metadata<'_>) -> Self::Writer { + StderrWriter::new(*meta.level() <= SYNC_FLUSH_LEVEL_THRESHOLD) + } +} + +pub struct StderrWriter { + buffer: Option>>, + sync_flush_on_drop: bool, + original_len: usize, +} + +impl StderrWriter { + fn new(mut sync_flush_on_drop: bool) -> Self { + if !ENABLE_ASYNC_LOGGING.load(Ordering::Relaxed) { + sync_flush_on_drop = true; + } + + // This lock isn't as expensive as it might look, since this is only called once the full + // line to be logged is already serialized into a thread-local buffer inside of the + // `tracing-subscriber` crate, and basically the only thing we'll do when holding this lock + // is to copy that over to our global shared buffer in one go in `Write::write_all` and be + // immediately dropped. + let buffer = BUFFER.lock(); + StderrWriter { original_len: buffer.len(), buffer: Some(buffer), sync_flush_on_drop } + } +} + +#[cold] +fn emergency_flush(buffer: &mut Vec, input: &[u8]) { + let stderr = std::io::stderr(); + let mut stderr_lock = stderr.lock(); + let _ = stderr_lock.write_all(buffer); + buffer.clear(); + + let _ = stderr_lock.write_all(input); +} + +impl Write for StderrWriter { + fn write(&mut self, input: &[u8]) -> Result { + let buffer = self.buffer.as_mut().expect("buffer is only None after `drop`; qed"); + if buffer.len() + input.len() >= EMERGENCY_FLUSH_THRESHOLD { + // Make sure we don't blow our memory budget. Normally this should never happen, + // but there are cases where we directly print out untrusted user input which + // can potentially be megabytes in size. + emergency_flush(buffer, input); + } else { + buffer.extend_from_slice(input); + } + Ok(input.len()) + } + + fn write_all(&mut self, input: &[u8]) -> Result<(), std::io::Error> { + self.write(input).map(|_| ()) + } + + fn flush(&mut self) -> Result<(), std::io::Error> { + Ok(()) + } +} + +impl Drop for StderrWriter { + fn drop(&mut self) { + let buf = self.buffer.take().expect("buffer is only None after `drop`; qed"); + if self.sync_flush_on_drop || buf.len() >= SYNC_FLUSH_THRESHOLD { + flush_logs(buf); + } else if self.original_len < ASYNC_FLUSH_THRESHOLD && buf.len() >= ASYNC_FLUSH_THRESHOLD { + ASYNC_FLUSH_CONDVAR.notify_one(); + } + } +} diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index 85eb22d6df072..46930a674f2c9 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -23,8 +23,8 @@ codec = { version = "2.0.0", package = "parity-scale-codec", default-features = "derive", ] } tracing = { version = "0.1.29", default-features = false } -tracing-core = { version = "0.1.17", default-features = false } -tracing-subscriber = { version = "0.2.19", optional = true, features = [ +tracing-core = { version = "0.1.21", default-features = false } +tracing-subscriber = { version = "0.2.25", optional = true, features = [ "tracing-log", ] } From 6725823035c7926000e0a44055126977d868560b Mon Sep 17 00:00:00 2001 From: Grachev Mikhail Date: Fri, 22 Oct 2021 22:27:09 +0300 Subject: [PATCH 0148/1472] Remove broken links in Nicks Pallet (#10086) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix broken links in Nicks Pallet * Update frame/nicks/src/lib.rs * Update frame/nicks/src/lib.rs Co-authored-by: Bastian Köcher --- frame/nicks/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 16c7e2042dda0..f502a683f633c 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -35,9 +35,6 @@ //! taken. //! * `clear_name` - Remove an account's associated name; the deposit is returned. //! * `kill_name` - Forcibly remove the associated name; the deposit is lost. -//! -//! [`Call`]: ./enum.Call.html -//! [`Config`]: ./trait.Config.html #![cfg_attr(not(feature = "std"), no_std)] From 969a70d1864fc5d5f6c378bcfd03f1b3ea434049 Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Sat, 23 Oct 2021 00:54:12 +0300 Subject: [PATCH 0149/1472] Introduce `linux-docker-benches` (#10085) * Introduce `linux-docker-benches` * Add additional info to `node-bench-regression-guard` job's run --- .gitlab-ci.yml | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6ad2ff1a46d8f..87efc43af2898 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -363,30 +363,34 @@ cargo-check-benches: - *rust-info-script script: - *cargo-check-benches-script + tags: + - linux-docker-benches -# TODO: re-enable after dedicated bench hosts provisioning -# node-bench-regression-guard: -# # it's not belong to `build` semantically, but dag jobs can't depend on each other -# # within the single stage - https://gitlab.com/gitlab-org/gitlab/-/issues/30632 -# # more: https://github.com/paritytech/substrate/pull/8519#discussion_r608012402 -# stage: build -# <<: *docker-env -# <<: *test-refs-no-trigger-prs-only -# needs: -# # this is a DAG -# - job: cargo-check-benches -# artifacts: true -# # this does not like a DAG, just polls the artifact -# - project: $CI_PROJECT_PATH -# job: cargo-check-benches -# ref: master -# artifacts: true -# variables: -# CI_IMAGE: "paritytech/node-bench-regression-guard:latest" -# before_script: [""] -# script: -# - 'node-bench-regression-guard --reference artifacts/benches/master-* -# --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA' +node-bench-regression-guard: + # it's not belong to `build` semantically, but dag jobs can't depend on each other + # within the single stage - https://gitlab.com/gitlab-org/gitlab/-/issues/30632 + # more: https://github.com/paritytech/substrate/pull/8519#discussion_r608012402 + stage: build + <<: *docker-env + <<: *test-refs-no-trigger-prs-only + needs: + # this is a DAG + - job: cargo-check-benches + artifacts: true + # this does not like a DAG, just polls the artifact + - project: $CI_PROJECT_PATH + job: cargo-check-benches + ref: master + artifacts: true + variables: + CI_IMAGE: "paritytech/node-bench-regression-guard:latest" + before_script: [""] + script: + - echo "------- IMPORTANT -------" + - echo "node-bench-regression-guard depends on the results of a cargo-check-benches job" + - echo "In case of this job failure, check your pipeline's cargo-check-benches" + - 'node-bench-regression-guard --reference artifacts/benches/master-* + --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA' cargo-check-subkey: stage: test From 456509d038c9535dfe6b4fc829ed1004af25a47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 25 Oct 2021 13:29:38 +0200 Subject: [PATCH 0150/1472] pallet-multisig: Improve opaque call handling (#10060) * pallet-multisig: Improve opaque call handling Before the opaque call was just a type redefinition of `Vec`. With metadata v14 that was breaking external tools, as they stopped looking at the type name. To improve the situation the `WrapperKeepOpaque` type is introduced that communicates to the outside the correct type info. * Cleanup * Fix benchmarks * FMT --- frame/multisig/src/benchmarking.rs | 25 +++--- frame/multisig/src/lib.rs | 44 +++++----- frame/multisig/src/tests.rs | 129 ++++++++++++++++++++++------- frame/support/src/traits.rs | 3 +- frame/support/src/traits/misc.rs | 103 ++++++++++++++++++++++- 5 files changed, 241 insertions(+), 63 deletions(-) diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index edfeba253e5f0..1390b6eebbe34 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -29,7 +29,10 @@ use crate::Pallet as Multisig; const SEED: u32 = 0; -fn setup_multi(s: u32, z: u32) -> Result<(Vec, Vec), &'static str> { +fn setup_multi( + s: u32, + z: u32, +) -> Result<(Vec, OpaqueCall), &'static str> { let mut signatories: Vec = Vec::new(); for i in 0..s { let signatory = account("signatory", i, SEED); @@ -42,7 +45,7 @@ fn setup_multi(s: u32, z: u32) -> Result<(Vec, Vec) // Must first convert to outer call type. let call: ::Call = frame_system::Call::::remark { remark: vec![0; z as usize] }.into(); - let call_data = call.encode(); + let call_data = OpaqueCall::::from_encoded(call.encode()); return Ok((signatories, call_data)) } @@ -72,7 +75,7 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(&call); + let call_hash = blake2_256(&call.encoded()); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; // Whitelist caller account from further DB operations. @@ -90,7 +93,7 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(&call); + let call_hash = blake2_256(&call.encoded()); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -109,7 +112,7 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(&call); + let call_hash = blake2_256(&call.encoded()); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; @@ -134,7 +137,7 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(&call); + let call_hash = blake2_256(&call.encoded()); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; @@ -160,7 +163,7 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(&call); + let call_hash = blake2_256(&call.encoded()); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; @@ -193,7 +196,7 @@ benchmarks! { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(&call); + let call_hash = blake2_256(&call.encoded()); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); @@ -212,7 +215,7 @@ benchmarks! { let mut signatories2 = signatories.clone(); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(&call); + let call_hash = blake2_256(&call.encoded()); // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi @@ -245,7 +248,7 @@ benchmarks! { let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let call_hash = blake2_256(&call); + let call_hash = blake2_256(&call.encoded()); // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi @@ -282,7 +285,7 @@ benchmarks! { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(&call); + let call_hash = blake2_256(&call.encoded()); let timepoint = Multisig::::timepoint(); // Create the multi let o = RawOrigin::Signed(caller.clone()).into(); diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 43040ada45a98..53567cc212afd 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -56,7 +56,7 @@ use frame_support::{ DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, PostDispatchInfo, }, ensure, - traits::{Currency, Get, ReservableCurrency}, + traits::{Currency, Get, ReservableCurrency, WrapperKeepOpaque}, weights::{GetDispatchInfo, Weight}, RuntimeDebug, }; @@ -74,8 +74,6 @@ pub use pallet::*; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -/// Just a bunch of bytes, but they should decode to a valid `Call`. -pub type OpaqueCall = Vec; /// A global extrinsic index, formed as the extrinsic index within a block, together with that /// block's height. This allows a transaction in which a multisig operation of a particular @@ -101,10 +99,12 @@ pub struct Multisig { approvals: Vec, } +type OpaqueCall = WrapperKeepOpaque<::Call>; + type CallHash = [u8; 32]; -enum CallOrHash { - Call(OpaqueCall, bool), +enum CallOrHash { + Call(OpaqueCall, bool), Hash([u8; 32]), } @@ -168,7 +168,7 @@ pub mod pallet { #[pallet::storage] pub type Calls = - StorageMap<_, Identity, [u8; 32], (OpaqueCall, T::AccountId, BalanceOf)>; + StorageMap<_, Identity, [u8; 32], (OpaqueCall, T::AccountId, BalanceOf)>; #[pallet::error] pub enum Error { @@ -339,7 +339,7 @@ pub mod pallet { /// # #[pallet::weight({ let s = other_signatories.len() as u32; - let z = call.len() as u32; + let z = call.encoded_len() as u32; T::WeightInfo::as_multi_create(s, z) .max(T::WeightInfo::as_multi_create_store(s, z)) @@ -352,7 +352,7 @@ pub mod pallet { threshold: u16, other_signatories: Vec, maybe_timepoint: Option>, - call: OpaqueCall, + call: OpaqueCall, store_call: bool, max_weight: Weight, ) -> DispatchResultWithPostInfo { @@ -406,9 +406,9 @@ pub mod pallet { let s = other_signatories.len() as u32; T::WeightInfo::approve_as_multi_create(s) - .max(T::WeightInfo::approve_as_multi_approve(s)) - .max(T::WeightInfo::approve_as_multi_complete(s)) - .saturating_add(*max_weight) + .max(T::WeightInfo::approve_as_multi_approve(s)) + .max(T::WeightInfo::approve_as_multi_complete(s)) + .saturating_add(*max_weight) })] pub fn approve_as_multi( origin: OriginFor, @@ -502,7 +502,7 @@ impl Pallet { threshold: u16, other_signatories: Vec, maybe_timepoint: Option>, - call_or_hash: CallOrHash, + call_or_hash: CallOrHash, max_weight: Weight, ) -> DispatchResultWithPostInfo { ensure!(threshold >= 2, Error::::MinimumThreshold); @@ -517,8 +517,8 @@ impl Pallet { // Threshold > 1; this means it's a multi-step operation. We extract the `call_hash`. let (call_hash, call_len, maybe_call, store) = match call_or_hash { CallOrHash::Call(call, should_store) => { - let call_hash = blake2_256(&call); - let call_len = call.len(); + let call_hash = blake2_256(call.encoded()); + let call_len = call.encoded_len(); (call_hash, call_len, Some(call), should_store) }, CallOrHash::Hash(h) => (h, 0, None, false), @@ -541,7 +541,7 @@ impl Pallet { // We only bother fetching/decoding call if we know that we're ready to execute. let maybe_approved_call = if approvals >= threshold { - Self::get_call(&call_hash, maybe_call.as_ref().map(|c| c.as_ref())) + Self::get_call(&call_hash, maybe_call.as_ref()) } else { None }; @@ -658,13 +658,14 @@ impl Pallet { fn store_call_and_reserve( who: T::AccountId, hash: &[u8; 32], - data: OpaqueCall, + data: OpaqueCall, other_deposit: BalanceOf, ) -> DispatchResult { ensure!(!Calls::::contains_key(hash), Error::::AlreadyStored); let deposit = other_deposit + T::DepositBase::get() + - T::DepositFactor::get() * BalanceOf::::from(((data.len() + 31) / 32) as u32); + T::DepositFactor::get() * + BalanceOf::::from(((data.encoded_len() + 31) / 32) as u32); T::Currency::reserve(&who, deposit)?; Calls::::insert(&hash, (data, who, deposit)); Ok(()) @@ -673,15 +674,14 @@ impl Pallet { /// Attempt to decode and return the call, provided by the user or from storage. fn get_call( hash: &[u8; 32], - maybe_known: Option<&[u8]>, + maybe_known: Option<&OpaqueCall>, ) -> Option<(::Call, usize)> { maybe_known.map_or_else( || { - Calls::::get(hash).and_then(|(data, ..)| { - Decode::decode(&mut &data[..]).ok().map(|d| (d, data.len())) - }) + Calls::::get(hash) + .and_then(|(data, ..)| Some((data.try_decode()?, data.encoded_len()))) }, - |data| Decode::decode(&mut &data[..]).ok().map(|d| (d, data.len())), + |data| Some((data.try_decode()?, data.encoded_len())), ) } diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index 3d311cf5d3dc8..d46c22ec73d09 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -31,6 +31,7 @@ use sp_runtime::{ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; +type OpaqueCall = super::OpaqueCall; frame_support::construct_runtime!( pub enum Test where @@ -152,7 +153,7 @@ fn multisig_deposit_is_taken_and_returned() { 2, vec![2, 3], None, - data.clone(), + OpaqueCall::from_encoded(data.clone()), false, 0 )); @@ -164,7 +165,7 @@ fn multisig_deposit_is_taken_and_returned() { 2, vec![1, 3], Some(now()), - data, + OpaqueCall::from_encoded(data), false, call_weight )); @@ -185,7 +186,15 @@ fn multisig_deposit_is_taken_and_returned_with_call_storage() { let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); - assert_ok!(Multisig::as_multi(Origin::signed(1), 2, vec![2, 3], None, data, true, 0)); + assert_ok!(Multisig::as_multi( + Origin::signed(1), + 2, + vec![2, 3], + None, + OpaqueCall::from_encoded(data), + true, + 0 + )); assert_eq!(Balances::free_balance(1), 0); assert_eq!(Balances::reserved_balance(1), 5); @@ -231,7 +240,7 @@ fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() { 3, vec![1, 3], Some(now()), - data, + OpaqueCall::from_encoded(data), true, 0 )); @@ -316,7 +325,15 @@ fn timepoint_checking_works() { assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 2, vec![2, 3], None, hash, 0)); assert_noop!( - Multisig::as_multi(Origin::signed(2), 2, vec![1, 3], None, call.clone(), false, 0), + Multisig::as_multi( + Origin::signed(2), + 2, + vec![1, 3], + None, + OpaqueCall::from_encoded(call.clone()), + false, + 0 + ), Error::::NoTimepoint, ); let later = Timepoint { index: 1, ..now() }; @@ -326,7 +343,7 @@ fn timepoint_checking_works() { 2, vec![1, 3], Some(later), - call.clone(), + OpaqueCall::from_encoded(call), false, 0 ), @@ -347,7 +364,15 @@ fn multisig_2_of_3_works_with_call_storing() { let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); - assert_ok!(Multisig::as_multi(Origin::signed(1), 2, vec![2, 3], None, data, true, 0)); + assert_ok!(Multisig::as_multi( + Origin::signed(1), + 2, + vec![2, 3], + None, + OpaqueCall::from_encoded(data), + true, + 0 + )); assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::approve_as_multi( @@ -382,7 +407,7 @@ fn multisig_2_of_3_works() { 2, vec![1, 3], Some(now()), - data, + OpaqueCall::from_encoded(data), false, call_weight )); @@ -425,7 +450,7 @@ fn multisig_3_of_3_works() { 3, vec![1, 2], Some(now()), - data, + OpaqueCall::from_encoded(data), false, call_weight )); @@ -473,7 +498,15 @@ fn cancel_multisig_with_call_storage_works() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); - assert_ok!(Multisig::as_multi(Origin::signed(1), 3, vec![2, 3], None, call, true, 0)); + assert_ok!(Multisig::as_multi( + Origin::signed(1), + 3, + vec![2, 3], + None, + OpaqueCall::from_encoded(call), + true, + 0 + )); assert_eq!(Balances::free_balance(1), 4); assert_ok!(Multisig::approve_as_multi( Origin::signed(2), @@ -517,7 +550,7 @@ fn cancel_multisig_with_alt_call_storage_works() { 3, vec![1, 3], Some(now()), - call, + OpaqueCall::from_encoded(call), true, 0 )); @@ -544,7 +577,7 @@ fn multisig_2_of_3_as_multi_works() { 2, vec![2, 3], None, - data.clone(), + OpaqueCall::from_encoded(data.clone()), false, 0 )); @@ -555,7 +588,7 @@ fn multisig_2_of_3_as_multi_works() { 2, vec![1, 3], Some(now()), - data, + OpaqueCall::from_encoded(data), false, call_weight )); @@ -583,7 +616,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { 2, vec![2, 3], None, - data1.clone(), + OpaqueCall::from_encoded(data1.clone()), false, 0 )); @@ -592,7 +625,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { 2, vec![1, 3], None, - data2.clone(), + OpaqueCall::from_encoded(data2.clone()), false, 0 )); @@ -601,7 +634,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { 2, vec![1, 2], Some(now()), - data1, + OpaqueCall::from_encoded(data1), false, call1_weight )); @@ -610,7 +643,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { 2, vec![1, 2], Some(now()), - data2, + OpaqueCall::from_encoded(data2), false, call2_weight )); @@ -637,7 +670,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { 2, vec![2, 3], None, - data.clone(), + OpaqueCall::from_encoded(data.clone()), false, 0 )); @@ -646,7 +679,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { 2, vec![1, 3], Some(now()), - data.clone(), + OpaqueCall::from_encoded(data.clone()), false, call_weight )); @@ -657,7 +690,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { 2, vec![2, 3], None, - data.clone(), + OpaqueCall::from_encoded(data.clone()), false, 0 )); @@ -666,7 +699,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { 2, vec![1, 2], Some(now()), - data.clone(), + OpaqueCall::from_encoded(data), false, call_weight )); @@ -683,11 +716,27 @@ fn minimum_threshold_check_works() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); assert_noop!( - Multisig::as_multi(Origin::signed(1), 0, vec![2], None, call.clone(), false, 0), + Multisig::as_multi( + Origin::signed(1), + 0, + vec![2], + None, + OpaqueCall::from_encoded(call.clone()), + false, + 0 + ), Error::::MinimumThreshold, ); assert_noop!( - Multisig::as_multi(Origin::signed(1), 1, vec![2], None, call.clone(), false, 0), + Multisig::as_multi( + Origin::signed(1), + 1, + vec![2], + None, + OpaqueCall::from_encoded(call.clone()), + false, + 0 + ), Error::::MinimumThreshold, ); }); @@ -698,7 +747,15 @@ fn too_many_signatories_fails() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); assert_noop!( - Multisig::as_multi(Origin::signed(1), 2, vec![2, 3, 4], None, call.clone(), false, 0), + Multisig::as_multi( + Origin::signed(1), + 2, + vec![2, 3, 4], + None, + OpaqueCall::from_encoded(call), + false, + 0 + ), Error::::TooManySignatories, ); }); @@ -765,7 +822,15 @@ fn multisig_1_of_3_works() { Error::::MinimumThreshold, ); assert_noop!( - Multisig::as_multi(Origin::signed(1), 1, vec![2, 3], None, call.clone(), false, 0), + Multisig::as_multi( + Origin::signed(1), + 1, + vec![2, 3], + None, + OpaqueCall::from_encoded(call), + false, + 0 + ), Error::::MinimumThreshold, ); let boxed_call = Box::new(call_transfer(6, 15)); @@ -801,14 +866,22 @@ fn weight_check_works() { 2, vec![2, 3], None, - data.clone(), + OpaqueCall::from_encoded(data.clone()), false, 0 )); assert_eq!(Balances::free_balance(6), 0); assert_noop!( - Multisig::as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), data, false, 0), + Multisig::as_multi( + Origin::signed(2), + 2, + vec![1, 3], + Some(now()), + OpaqueCall::from_encoded(data), + false, + 0 + ), Error::::MaxWeightTooLow, ); }); @@ -860,7 +933,7 @@ fn multisig_handles_no_preimage_after_all_approve() { 3, vec![1, 2], Some(now()), - data, + OpaqueCall::from_encoded(data), false, call_weight )); diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 513267c5c8ba6..43eadb3a05073 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -52,7 +52,8 @@ mod misc; pub use misc::{ Backing, ConstU32, EnsureInherentsAreFirst, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, - OnKilledAccount, OnNewAccount, SameOrOther, Time, TryDrop, UnixTime, WrapperOpaque, + OnKilledAccount, OnNewAccount, SameOrOther, Time, TryDrop, UnixTime, WrapperKeepOpaque, + WrapperOpaque, }; mod stored_map; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 9109bfeeae722..6587945604d0b 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -18,7 +18,7 @@ //! Smaller traits used in FRAME which don't need their own file. use crate::dispatch::Parameter; -use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen}; +use codec::{CompactLen, Decode, DecodeAll, Encode, EncodeLike, Input, MaxEncodedLen}; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; use sp_runtime::{traits::Block as BlockT, DispatchError}; use sp_std::prelude::*; @@ -390,6 +390,7 @@ impl, const T: u32> EstimateCallFee for pub struct WrapperOpaque(pub T); impl EncodeLike for WrapperOpaque {} +impl EncodeLike> for WrapperOpaque {} impl Encode for WrapperOpaque { fn size_hint(&self) -> usize { @@ -456,6 +457,93 @@ impl TypeInfo for WrapperOpaque { } } +/// A wrapper for any type `T` which implement encode/decode in a way compatible with `Vec`. +/// +/// This type is similar to [`WrapperOpaque`], but it differs in the way it stores the type `T`. +/// While [`WrapperOpaque`] stores the decoded type, the [`WrapperKeepOpaque`] stores the type only +/// in its opaque format, aka as a `Vec`. To access the real type `T` [`Self::try_decode`] needs +/// to be used. +#[derive(Debug, Eq, PartialEq, Default, Clone)] +pub struct WrapperKeepOpaque { + data: Vec, + _phantom: sp_std::marker::PhantomData, +} + +impl WrapperKeepOpaque { + /// Try to decode the wrapped type from the inner `data`. + /// + /// Returns `None` if the decoding failed. + pub fn try_decode(&self) -> Option { + T::decode_all(&mut &self.data[..]).ok() + } + + /// Returns the length of the encoded `T`. + pub fn encoded_len(&self) -> usize { + self.data.len() + } + + /// Returns the encoded data. + pub fn encoded(&self) -> &[u8] { + &self.data + } + + /// Create from the given encoded `data`. + pub fn from_encoded(data: Vec) -> Self { + Self { data, _phantom: sp_std::marker::PhantomData } + } +} + +impl EncodeLike for WrapperKeepOpaque {} +impl EncodeLike> for WrapperKeepOpaque {} + +impl Encode for WrapperKeepOpaque { + fn size_hint(&self) -> usize { + self.data.len() + codec::Compact::::compact_len(&(self.data.len() as u32)) + } + + fn encode_to(&self, dest: &mut O) { + self.data.encode_to(dest); + } + + fn encode(&self) -> Vec { + self.data.encode() + } + + fn using_encoded R>(&self, f: F) -> R { + self.data.using_encoded(f) + } +} + +impl Decode for WrapperKeepOpaque { + fn decode(input: &mut I) -> Result { + Ok(Self { data: Vec::::decode(input)?, _phantom: sp_std::marker::PhantomData }) + } + + fn skip(input: &mut I) -> Result<(), codec::Error> { + >::skip(input) + } +} + +impl MaxEncodedLen for WrapperKeepOpaque { + fn max_encoded_len() -> usize { + WrapperOpaque::::max_encoded_len() + } +} + +impl TypeInfo for WrapperKeepOpaque { + type Identity = Self; + fn type_info() -> Type { + Type::builder() + .path(Path::new("WrapperKeepOpaque", module_path!())) + .type_params(vec![TypeParameter::new("T", Some(meta_type::()))]) + .composite( + Fields::unnamed() + .field(|f| f.compact::()) + .field(|f| f.ty::().type_name("T")), + ) + } +} + #[cfg(test)] mod test { use super::*; @@ -488,4 +576,17 @@ mod test { ); assert_eq!(>::max_encoded_len(), 2usize.pow(14) + 4); } + + #[test] + fn test_keep_opaque_wrapper() { + let data = 3u32.encode().encode(); + + let keep_opaque = WrapperKeepOpaque::::decode(&mut &data[..]).unwrap(); + keep_opaque.try_decode().unwrap(); + + let data = WrapperOpaque(50u32).encode(); + let decoded = WrapperKeepOpaque::::decode(&mut &data[..]).unwrap(); + let data = decoded.encode(); + WrapperOpaque::::decode(&mut &data[..]).unwrap(); + } } From 732f0371c2d4da7b0ec326c681e0c1d360fc1bd8 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 25 Oct 2021 23:49:43 +1100 Subject: [PATCH 0151/1472] Offchain-worker: Update example-offchain-worker with implementation for TestAuthId (#10096) * Update example-offchain-worker to include missing implementation for TestAuthId i tried to incorporate the off-chain worker callback demo as a custom pallet of my own Substrate-based blockchain implementation that's provided at the following links * https://www.parity.io/blog/substrate-off-chain-workers-secure-and-efficient-computing-intensive-tasks/ * https://gnunicorn.github.io/substrate-offchain-cb/ but when i build the code with `cargo build --release`, it gave me an error: ``` error[E0277]: the trait bound `AuthorityId: AppCrypto` is not satisfied --> /Users/me/my_repo/node/runtime/src/lib.rs:1172:5 | 1172 | type AuthorityId = AuthorityId; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AppCrypto` is not implemented for `AuthorityId` | note: required by a bound in `offchaincb::Config::AuthorityId` --> /Users/me/my_repo/node/pallets/offchaincb/src/lib.rs:169:21 | 169 | type AuthorityId: AppCrypto; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `offchaincb::Config::AuthorityId` ``` where in my custom pallet i have: pallets/offchaincb/src/lib.rs ``` ... use offchaincb::{ crypto::{ TestAuthId, }, }; ... parameter_types! { pub const GracePeriod: BlockNumber = 1 * MINUTES; pub const UnsignedInterval: BlockNumber = 1 * MINUTES; pub const UnsignedPriority: BlockNumber = 1 * MINUTES; } impl offchaincb::Config for Runtime { type AuthorityId = TestAuthId; type Call = Call; type Currency = Balances; type Event = Event; type GracePeriod = GracePeriod; type UnsignedInterval = UnsignedInterval; type UnsignedPriority = UnsignedPriority; } ... ``` then i found another different off-chain workers Substrate Recipe demo from Jimmy Chu https://github.com/jimmychu0807/recipes/blob/master/pallets/ocw-demo/src/lib.rs#L73 which had an extra implementation for TestAuthId here https://github.com/jimmychu0807/recipes/blob/master/pallets/ocw-demo/src/lib.rs#L73, and when i added that it overcame the error. so i think this change should be included in the Substrate repository * Fix indentation * Fix formatting * Swap order --- frame/example-offchain-worker/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frame/example-offchain-worker/src/lib.rs b/frame/example-offchain-worker/src/lib.rs index 644e1ca299a3c..9b63ffa663ee2 100644 --- a/frame/example-offchain-worker/src/lib.rs +++ b/frame/example-offchain-worker/src/lib.rs @@ -86,10 +86,19 @@ pub mod crypto { use sp_runtime::{ app_crypto::{app_crypto, sr25519}, traits::Verify, + MultiSignature, MultiSigner, }; app_crypto!(sr25519, KEY_TYPE); pub struct TestAuthId; + + impl frame_system::offchain::AppCrypto for TestAuthId { + type RuntimeAppPublic = Public; + type GenericSignature = sp_core::sr25519::Signature; + type GenericPublic = sp_core::sr25519::Public; + } + + // implemented for mock runtime in test impl frame_system::offchain::AppCrypto<::Signer, Sr25519Signature> for TestAuthId { From f37f1c84fd22e3ae91f19e09367d4f44f47a65d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 26 Oct 2021 19:10:45 +0200 Subject: [PATCH 0152/1472] Remove `ss58-registry.json` (#10094) This file shouldn't exist anymore, maybe it was added accidentally by some pr. People should move over to https://github.com/paritytech/ss58-registry now. --- ss58-registry.json | 671 --------------------------------------------- 1 file changed, 671 deletions(-) delete mode 100644 ss58-registry.json diff --git a/ss58-registry.json b/ss58-registry.json deleted file mode 100644 index fdae23a5a6f21..0000000000000 --- a/ss58-registry.json +++ /dev/null @@ -1,671 +0,0 @@ -{ - "specification": "https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)", - "schema": { - "prefix": "The address prefix. Must be an integer and unique.", - "network": "Unique identifier for the network that will use this prefix, string, no spaces. To integrate with CLI tools, e.g. `--network polkadot`.", - "displayName": "The name of the network that will use this prefix, in a format friendly for display.", - "symbols": "Array of symbols of any tokens the chain uses, usually 2-5 characters. Most chains will only have one. Chains that have multiple instances of the Balances pallet should order the array by instance.", - "decimals": "Array of integers representing the number of decimals that represent a single unit to the end user. Must be same length as `symbols` to represent each token's denomination.", - "standardAccount": "Signing curve for standard account. Substrate supports ed25519, sr25519, and secp256k1.", - "website": "A website or Github repo associated with the network." - }, - "registry": [ - { - "prefix": 0, - "network": "polkadot", - "displayName": "Polkadot Relay Chain", - "symbols": ["DOT"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://polkadot.network" - }, - { - "prefix": 1, - "network": null, - "displayName": "Bare 32-bit Schnorr/Ristretto (S/R 25519) public key.", - "symbols": null, - "decimals": null, - "standardAccount": null, - "website": null - }, - { - "prefix": 2, - "network": "kusama", - "displayName": "Kusama Relay Chain", - "symbols": ["KSM"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://kusama.network" - }, - { - "prefix": 3, - "network": null, - "displayName": "Bare 32-bit Ed25519 public key.", - "symbols": null, - "decimals": null, - "standardAccount": null, - "website": null - }, - { - "prefix": 4, - "network": "katalchain", - "displayName": "Katal Chain", - "symbols": null, - "decimals": null, - "standardAccount": "*25519", - "website": null - }, - { - "prefix": 5, - "network": "plasm", - "displayName": "Plasm Network", - "symbols": ["PLM"], - "decimals": [15], - "standardAccount": "*25519", - "website": "https://plasmnet.io" - }, - { - "prefix": 6, - "network": "bifrost", - "displayName": "Bifrost", - "symbols": ["BNC"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://bifrost.finance/" - }, - { - "prefix": 7, - "network": "edgeware", - "displayName": "Edgeware", - "symbols": ["EDG"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://edgewa.re" - }, - { - "prefix": 8, - "network": "karura", - "displayName": "Karura", - "symbols": ["KAR"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://karura.network/" - }, - { - "prefix": 9, - "network": "reynolds", - "displayName": "Laminar Reynolds Canary", - "symbols": ["REY"], - "decimals": [18], - "standardAccount": "*25519", - "website": "http://laminar.network/" - }, - { - "prefix": 10, - "network": "acala", - "displayName": "Acala", - "symbols": ["ACA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://acala.network/" - }, - { - "prefix": 11, - "network": "laminar", - "displayName": "Laminar", - "symbols": ["LAMI"], - "decimals": [18], - "standardAccount": "*25519", - "website": "http://laminar.network/" - }, - { - "prefix": 12, - "network": "polymesh", - "displayName": "Polymesh", - "symbols": ["POLYX"], - "decimals": [6], - "standardAccount": "*25519", - "website": "https://polymath.network/" - }, - { - "prefix": 13, - "network": "integritee", - "displayName": "Integritee", - "symbols": ["TEER"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://integritee.network" - }, - { - "prefix": 14, - "network": "totem", - "displayName": "Totem", - "symbols": ["XTX"], - "decimals": [0], - "standardAccount": "*25519", - "website": "https://totemaccounting.com" - }, - { - "prefix": 15, - "network": "synesthesia", - "displayName": "Synesthesia", - "symbols": ["SYN"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://synesthesia.network/" - }, - { - "prefix": 16, - "network": "kulupu", - "displayName": "Kulupu", - "symbols": ["KLP"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://kulupu.network/" - }, - { - "prefix": 17, - "network": "dark", - "displayName": "Dark Mainnet", - "symbols": null, - "decimals": null, - "standardAccount": "*25519", - "website": null - }, - { - "prefix": 18, - "network": "darwinia", - "displayName": "Darwinia Network", - "symbols": ["RING", "KTON"], - "decimals": [9, 9], - "standardAccount": "*25519", - "website": "https://darwinia.network/" - }, - { - "prefix": 19, - "network": "geek", - "displayName": "GeekCash", - "symbols": ["GEEK"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://geekcash.org" - }, - { - "prefix": 20, - "network": "stafi", - "displayName": "Stafi", - "symbols": ["FIS"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://stafi.io" - }, - { - "prefix": 21, - "network": "dock-testnet", - "displayName": "Dock Testnet", - "symbols": ["DCK"], - "decimals": [6], - "standardAccount": "*25519", - "website": "https://dock.io" - }, - { - "prefix": 22, - "network": "dock-mainnet", - "displayName": "Dock Mainnet", - "symbols": ["DCK"], - "decimals": [6], - "standardAccount": "*25519", - "website": "https://dock.io" - }, - { - "prefix": 23, - "network": "shift", - "displayName": "ShiftNrg", - "symbols": null, - "decimals": null, - "standardAccount": "*25519", - "website": null - }, - { - "prefix": 24, - "network": "zero", - "displayName": "ZERO", - "symbols": ["PLAY"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://zero.io" - }, - { - "prefix": 25, - "network": "zero-alphaville", - "displayName": "ZERO Alphaville", - "symbols": ["PLAY"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://zero.io" - }, - { - "prefix": 26, - "network": "jupiter", - "displayName": "Jupiter", - "symbols": ["jDOT"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://jupiter.patract.io" - }, - { - "prefix": 28, - "network": "subsocial", - "displayName": "Subsocial", - "symbols": null, - "decimals": null, - "standardAccount": "*25519", - "website": null - }, - { - "prefix": 29, - "network": "cord", - "displayName": "Dhiway CORD Network", - "symbols": ["DCU"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://dhiway.com/" - }, - { - "prefix": 30, - "network": "phala", - "displayName": "Phala Network", - "symbols": ["PHA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://phala.network" - }, - { - "prefix": 31, - "network": "litentry", - "displayName": "Litentry Network", - "symbols": ["LIT"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://litentry.com/" - }, - { - "prefix": 32, - "network": "robonomics", - "displayName": "Robonomics", - "symbols": ["XRT"], - "decimals": [9], - "standardAccount": "*25519", - "website": "https://robonomics.network" - }, - { - "prefix": 33, - "network": "datahighway", - "displayName": "DataHighway", - "symbols": null, - "decimals": null, - "standardAccount": "*25519", - "website": null - }, - { - "prefix": 34, - "network": "ares", - "displayName": "Ares Protocol", - "symbols": ["ARES"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://www.aresprotocol.com/" - }, - { - "prefix": 35, - "network": "vln", - "displayName": "Valiu Liquidity Network", - "symbols": ["USDv"], - "decimals": [15], - "standardAccount": "*25519", - "website": "https://valiu.com/" - }, - { - "prefix": 36, - "network": "centrifuge", - "displayName": "Centrifuge Chain", - "symbols": ["CFG"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://centrifuge.io/" - }, - { - "prefix": 37, - "network": "nodle", - "displayName": "Nodle Chain", - "symbols": ["NODL"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://nodle.io/" - }, - { - "prefix": 38, - "network": "kilt", - "displayName": "KILT Chain", - "symbols": ["KILT"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://kilt.io/" - }, - { - "prefix": 39, - "network": "mathchain", - "displayName": "MathChain mainnet", - "symbols": ["MATH"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://mathwallet.org" - }, - { - "prefix": 40, - "network": "mathchain-testnet", - "displayName": "MathChain testnet", - "symbols": ["MATH"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://mathwallet.org" - }, - { - "prefix": 41, - "network": "poli", - "displayName": "Polimec Chain", - "symbols": null, - "decimals": null, - "standardAccount": "*25519", - "website": "https://polimec.io/" - }, - { - "prefix": 42, - "network": "substrate", - "displayName": "Substrate", - "symbols": null, - "decimals": null, - "standardAccount": "*25519", - "website": "https://docs.substrate.io/" - }, - { - "prefix": 43, - "network": null, - "displayName": "Bare 32-bit ECDSA SECP-256k1 public key.", - "symbols": null, - "decimals": null, - "standardAccount": null, - "website": null - }, - { - "prefix": 44, - "network": "chainx", - "displayName": "ChainX", - "symbols": ["PCX"], - "decimals": [8], - "standardAccount": "*25519", - "website": "https://chainx.org/" - }, - { - "prefix": 45, - "network": "uniarts", - "displayName": "UniArts Network", - "symbols": ["UART", "UINK"], - "decimals": [12, 12], - "standardAccount": "*25519", - "website": "https://uniarts.me" - }, - { - "prefix": 46, - "network": "reserved46", - "displayName": "This prefix is reserved.", - "symbols": null, - "decimals": null, - "standardAccount": null, - "website": null - }, - { - "prefix": 47, - "network": "reserved47", - "displayName": "This prefix is reserved.", - "symbols": null, - "decimals": null, - "standardAccount": null, - "website": null - }, - { - "prefix": 48, - "network": "neatcoin", - "displayName": "Neatcoin Mainnet", - "symbols": ["NEAT"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://neatcoin.org" - }, - { - "prefix": 49, - "network": "picasso", - "displayName": "Picasso", - "symbols": ["PICA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://picasso.composable.finance" - }, - { - "prefix": 50, - "network": "composable", - "displayName": "Composable", - "symbols": ["LAYR"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://composable.finance" - }, - { - "prefix": 63, - "network": "hydradx", - "displayName": "HydraDX", - "symbols": ["HDX"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://hydradx.io" - }, - { - "prefix": 65, - "network": "aventus", - "displayName": "AvN Mainnet", - "symbols": ["AVT"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://aventus.io" - }, - { - "prefix": 66, - "network": "crust", - "displayName": "Crust Network", - "symbols": ["CRU"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://crust.network" - }, - { - "prefix": 67, - "network": "equilibrium", - "displayName": "Equilibrium Network", - "symbols": ["Unknown", "USD", "EQ", "ETH", "BTC", "EOS", "DOT", "CRV"], - "decimals": [0,9,9,9,9,9,9,9], - "standardAccount": "*25519", - "website": "https://equilibrium.io" - }, - { - "prefix": 69, - "network": "sora", - "displayName": "SORA Network", - "symbols": ["XOR"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://sora.org" - }, - { - "prefix": 73, - "network": "zeitgeist", - "displayName": "Zeitgeist", - "symbols": ["ZTG"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://zeitgeist.pm" - }, - { - "prefix": 77, - "network": "manta", - "displayName": "Manta network", - "symbols": ["MA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://manta.network" - }, - { - "prefix": 78, - "network": "calamari", - "displayName": "Calamari: Manta Canary Network", - "symbols": ["KMA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://manta.network" - }, - { - "prefix": 88, - "network": "polkadex", - "displayName": "Polkadex Mainnet", - "symbols": ["PDEX"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://polkadex.trade" - }, - { - "prefix": 98, - "network": "polkasmith", - "displayName": "PolkaSmith Canary Network", - "symbols": ["PKS"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://polkafoundry.com" - }, - { - "prefix": 99, - "network": "polkafoundry", - "displayName": "PolkaFoundry Network", - "symbols": ["PKF"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://polkafoundry.com" - }, - { - "prefix": 101, - "network": "origintrail-parachain", - "displayName": "OriginTrail Parachain", - "symbols": ["TRAC"], - "decimals": [18], - "standardAccount": "secp256k1", - "website": "https://origintrail.io" - }, - { - "prefix": 110, - "network": "heiko", - "displayName": "Heiko", - "symbols": ["HKO"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://parallel.fi/" - }, - { - "prefix": 113, - "network": "integritee-incognito", - "displayName": "Integritee Incognito", - "symbols": null, - "decimals": null, - "standardAccount": "*25519", - "website": "https://integritee.network" - }, - { - "prefix": 128, - "network": "clover", - "displayName": "Clover Finance", - "symbols": ["CLV"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://clover.finance" - }, - { - "prefix": 136, - "network": "altair", - "displayName": "Altair", - "symbols": ["AIR"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://centrifuge.io/" - }, - { - "prefix": 172, - "network": "parallel", - "displayName": "Parallel", - "symbols": ["PARA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://parallel.fi/" - }, - { - "prefix": 252, - "network": "social-network", - "displayName": "Social Network", - "symbols": ["NET"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://social.network" - }, - { - "prefix": 1284, - "network": "moonbeam", - "displayName": "Moonbeam", - "symbols": ["GLMR"], - "decimals": [18], - "standardAccount": "secp256k1", - "website": "https://moonbeam.network" - }, - { - "prefix": 1285, - "network": "moonriver", - "displayName": "Moonriver", - "symbols": ["MOVR"], - "decimals": [18], - "standardAccount": "secp256k1", - "website": "https://moonbeam.network" - }, - { - "prefix": 2349, - "network": "automata", - "displayName": "Automata Mainnet", - "symbols": ["ATA"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://ata.network" - }, - { - "prefix": 10041, - "network": "basilisk", - "displayName": "Basilisk", - "symbols": ["BSX"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://bsx.fi" - }, - { - "prefix": 11820, - "network": "contextfree", - "displayName": "Automata ContextFree", - "symbols": ["CTX"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://ata.network" - } - ] -} From c5450ed3d85b150ddc7fb40a68d683887dac43c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Oct 2021 10:18:33 +0000 Subject: [PATCH 0153/1472] Bump libc from 0.2.103 to 0.2.105 (#10115) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.103 to 0.2.105. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.103...0.2.105) --- updated-dependencies: - dependency-name: libc 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/executor/wasmtime/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6325304bfceec..ed10002bd5489 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3266,9 +3266,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.103" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" +checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" [[package]] name = "libgit2-sys" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 9fb76ed08fd9a..7a877bd9578f5 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -libc = "0.2.90" +libc = "0.2.105" cfg-if = "1.0" log = "0.4.8" parity-wasm = "0.42.0" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 4939e6a73110c..8093420dc5b95 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -17,7 +17,7 @@ ansi_term = "0.12.1" atty = "0.2.13" chrono = "0.4.19" lazy_static = "1.4.0" -libc = "0.2.95" +libc = "0.2.105" log = { version = "0.4.8" } once_cell = "1.8.0" parking_lot = "0.11.1" From 69fa67d0a7647f3b33f679494684859e56161197 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 29 Oct 2021 20:42:51 +0800 Subject: [PATCH 0154/1472] Remove useless WeightInfo in pallet-offences (#10114) --- frame/offences/src/lib.rs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index 3392cd6e4a884..d50bc55f88357 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -43,28 +43,6 @@ type OpaqueTimeSlot = Vec; /// A type alias for a report identifier. type ReportIdOf = ::Hash; -pub trait WeightInfo { - fn report_offence_im_online(r: u32, o: u32, n: u32) -> Weight; - fn report_offence_grandpa(r: u32, n: u32) -> Weight; - fn report_offence_babe(r: u32, n: u32) -> Weight; - fn on_initialize(d: u32) -> Weight; -} - -impl WeightInfo for () { - fn report_offence_im_online(_r: u32, _o: u32, _n: u32) -> Weight { - 1_000_000_000 - } - fn report_offence_grandpa(_r: u32, _n: u32) -> Weight { - 1_000_000_000 - } - fn report_offence_babe(_r: u32, _n: u32) -> Weight { - 1_000_000_000 - } - fn on_initialize(_d: u32) -> Weight { - 1_000_000_000 - } -} - #[frame_support::pallet] pub mod pallet { use super::*; From 945377f35fd6ba265d6bd2b808e97749471dec0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 29 Oct 2021 18:00:49 +0200 Subject: [PATCH 0155/1472] pallet-scheduler: Introduce `OriginPrivilegeCmp` (#10078) * pallet-scheduler: Introduce `OriginPrivilegeCmp` When a scheduled task should be canceled, the origin that tries to cancel the task is compared to the origin the task should be executed with. Before this pr this check only allowed that both origins are equal. However, this is problematic as this means that for example a council origin it needs to be have the same amount of yes votes to cancel the scheduled task. While a council origin with more yes votes should be able to cancel this task. This happened recently on Kusama and lead to a failed cancelation of a scheduled task. With this pr the two origins are compared and the cancelling origin needs to have greater or equal privileges as the origin that scheduled the task. What a greater, equal or less privilege is, can be configured in the runtime. For simplicity, a `EqualPrivilegeOnly` implementation is provided that only checks if two origins are equal. So, this mimics the old behaviour. * FMT * fix import * Small optimizations Co-authored-by: Shawn Tabrizi --- bin/node/runtime/src/lib.rs | 5 +++-- frame/democracy/src/tests.rs | 3 ++- frame/scheduler/src/lib.rs | 26 +++++++++++++++++++++----- frame/support/src/traits.rs | 8 ++++---- frame/support/src/traits/misc.rs | 22 +++++++++++++++++++++- 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index c7920629bf356..0638e62faa362 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -26,8 +26,8 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ construct_runtime, parameter_types, traits::{ - Currency, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, - Nothing, OnUnbalanced, U128CurrencyToVote, + Currency, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, + LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, @@ -345,6 +345,7 @@ impl pallet_scheduler::Config for Runtime { type ScheduleOrigin = EnsureRoot; type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = pallet_scheduler::weights::SubstrateWeight; + type OriginPrivilegeCmp = EqualPrivilegeOnly; } parameter_types! { diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index f56667e9094b3..06c4ac666cfba 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -22,7 +22,7 @@ use crate as pallet_democracy; use codec::Encode; use frame_support::{ assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{Contains, GenesisBuild, OnInitialize, SortedMembers}, + traits::{Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize, SortedMembers}, weights::Weight, }; use frame_system::{EnsureRoot, EnsureSignedBy}; @@ -118,6 +118,7 @@ impl pallet_scheduler::Config for Test { type ScheduleOrigin = EnsureRoot; type MaxScheduledPerBlock = (); type WeightInfo = (); + type OriginPrivilegeCmp = EqualPrivilegeOnly; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index ca9e15812a76d..d59c42cc850dd 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -58,7 +58,7 @@ use frame_support::{ dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter}, traits::{ schedule::{self, DispatchTime}, - EnsureOrigin, Get, IsType, OriginTrait, + EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp, }, weights::{GetDispatchInfo, Weight}, }; @@ -69,7 +69,7 @@ use sp_runtime::{ traits::{BadOrigin, One, Saturating, Zero}, RuntimeDebug, }; -use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*}; +use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*}; pub use weights::WeightInfo; /// Just a simple index for naming period tasks. @@ -160,6 +160,15 @@ pub mod pallet { /// Required origin to schedule or cancel calls. type ScheduleOrigin: EnsureOrigin<::Origin>; + /// Compare the privileges of origins. + /// + /// This will be used when canceling a task, to ensure that the origin that tries + /// to cancel has greater or equal privileges as the origin that created the scheduled task. + /// + /// For simplicity the [`EqualPrivilegeOnly`](frame_support::traits::EqualPrivilegeOnly) can + /// be used. This will only check if two given origins are equal. + type OriginPrivilegeCmp: PrivilegeCmp; + /// The maximum number of scheduled calls in the queue for a single block. /// Not strictly enforced, but used for weight estimation. #[pallet::constant] @@ -614,7 +623,10 @@ impl Pallet { Ok(None), |s| -> Result>, DispatchError> { if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) { - if *o != s.origin { + if matches!( + T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin), + Some(Ordering::Less) | None + ) { return Err(BadOrigin.into()) } }; @@ -709,7 +721,10 @@ impl Pallet { Agenda::::try_mutate(when, |agenda| -> DispatchResult { if let Some(s) = agenda.get_mut(i) { if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) { - if *o != s.origin { + if matches!( + T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin), + Some(Ordering::Less) | None + ) { return Err(BadOrigin.into()) } } @@ -832,7 +847,7 @@ mod tests { use crate as scheduler; use frame_support::{ assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{Contains, OnFinalize, OnInitialize}, + traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, weights::constants::RocksDbWeight, Hashable, }; @@ -980,6 +995,7 @@ mod tests { type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = (); + type OriginPrivilegeCmp = EqualPrivilegeOnly; } pub type LoggerCall = logger::Call; diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 43eadb3a05073..bb990e25646db 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -50,10 +50,10 @@ pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter mod misc; pub use misc::{ - Backing, ConstU32, EnsureInherentsAreFirst, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, - GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, - OnKilledAccount, OnNewAccount, SameOrOther, Time, TryDrop, UnixTime, WrapperKeepOpaque, - WrapperOpaque, + Backing, ConstU32, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, + ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, + OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, TryDrop, + UnixTime, WrapperKeepOpaque, WrapperOpaque, }; mod stored_map; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 6587945604d0b..0a3fb045d6c1d 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -21,7 +21,7 @@ use crate::dispatch::Parameter; use codec::{CompactLen, Decode, DecodeAll, Encode, EncodeLike, Input, MaxEncodedLen}; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; use sp_runtime::{traits::Block as BlockT, DispatchError}; -use sp_std::prelude::*; +use sp_std::{cmp::Ordering, prelude::*}; /// Anything that can have a `::len()` method. pub trait Len { @@ -289,6 +289,26 @@ pub trait ExecuteBlock { fn execute_block(block: Block); } +/// Something that can compare privileges of two origins. +pub trait PrivilegeCmp { + /// Compare the `left` to the `right` origin. + /// + /// The returned ordering should be from the pov of the `left` origin. + /// + /// Should return `None` when it can not compare the given origins. + fn cmp_privilege(left: &Origin, right: &Origin) -> Option; +} + +/// Implementation of [`PrivilegeCmp`] that only checks for equal origins. +/// +/// This means it will either return [`Origin::Equal`] or `None`. +pub struct EqualPrivilegeOnly; +impl PrivilegeCmp for EqualPrivilegeOnly { + fn cmp_privilege(left: &Origin, right: &Origin) -> Option { + (left == right).then(|| Ordering::Equal) + } +} + /// Off-chain computation trait. /// /// Implementing this trait on a module allows you to perform long-running tasks From a7cc69f386eaf567fbf667b8c930da87cac1ce7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Sat, 30 Oct 2021 11:13:18 +0200 Subject: [PATCH 0156/1472] contracts: Fix account counter isn't persisted (#10112) * Add test to check account counter persistence * Fix bug that account counter wasn't properly persited * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- frame/contracts/src/exec.rs | 107 +++- frame/contracts/src/weights.rs | 1090 ++++++++++++++++---------------- 2 files changed, 643 insertions(+), 554 deletions(-) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 7fa0b0b274449..c28490dfacccf 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -538,14 +538,15 @@ where value: BalanceOf, debug_message: Option<&'a mut Vec>, ) -> Result<(Self, E), ExecError> { - let (first_frame, executable) = Self::new_frame(args, value, gas_meter, 0, &schedule)?; + let (first_frame, executable, account_counter) = + Self::new_frame(args, value, gas_meter, 0, &schedule)?; let stack = Self { origin, schedule, gas_meter, timestamp: T::Time::now(), block_number: >::block_number(), - account_counter: None, + account_counter, first_frame, frames: Default::default(), debug_message, @@ -565,8 +566,9 @@ where gas_meter: &mut GasMeter, gas_limit: Weight, schedule: &Schedule, - ) -> Result<(Frame, E), ExecError> { - let (account_id, contract_info, executable, entry_point) = match frame_args { + ) -> Result<(Frame, E, Option), ExecError> { + let (account_id, contract_info, executable, entry_point, account_counter) = match frame_args + { FrameArgs::Call { dest, cached_info } => { let contract = if let Some(contract) = cached_info { contract @@ -576,7 +578,7 @@ where let executable = E::from_storage(contract.code_hash, schedule, gas_meter)?; - (dest, contract, executable, ExportedFunction::Call) + (dest, contract, executable, ExportedFunction::Call, None) }, FrameArgs::Instantiate { sender, trie_seed, executable, salt } => { let account_id = @@ -587,7 +589,7 @@ where trie_id, executable.code_hash().clone(), )?; - (account_id, contract, executable, ExportedFunction::Constructor) + (account_id, contract, executable, ExportedFunction::Constructor, Some(trie_seed)) }, }; @@ -600,7 +602,7 @@ where allows_reentry: true, }; - Ok((frame, executable)) + Ok((frame, executable, account_counter)) } /// Create a subsequent nested frame. @@ -629,7 +631,7 @@ where let nested_meter = &mut self.frames.last_mut().unwrap_or(&mut self.first_frame).nested_meter; - let (frame, executable) = + let (frame, executable, _) = Self::new_frame(frame_args, value_transferred, nested_meter, gas_limit, self.schedule)?; self.frames.push(frame); Ok(executable) @@ -842,7 +844,7 @@ where /// Increments the cached account id and returns the value to be used for the trie_id. fn next_trie_seed(&mut self) -> u64 { let next = if let Some(current) = self.account_counter { - current + 1 + current.wrapping_add(1) } else { Self::initial_trie_seed() }; @@ -2165,4 +2167,91 @@ mod tests { ); }); } + + #[test] + fn account_counter() { + let fail_code = MockLoader::insert(Constructor, |_, _| exec_trapped()); + let success_code = MockLoader::insert(Constructor, |_, _| exec_success()); + let succ_fail_code = MockLoader::insert(Constructor, move |ctx, _| { + ctx.ext + .instantiate(0, fail_code, ctx.ext.minimum_balance() * 100, vec![], &[]) + .ok(); + exec_success() + }); + let succ_succ_code = MockLoader::insert(Constructor, move |ctx, _| { + let (account_id, _) = ctx + .ext + .instantiate(0, success_code, ctx.ext.minimum_balance() * 100, vec![], &[]) + .unwrap(); + + // a plain call should not influence the account counter + ctx.ext.call(0, account_id, 0, vec![], false).unwrap(); + + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let schedule = ::Schedule::get(); + let min_balance = ::Currency::minimum_balance(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let fail_executable = + MockExecutable::from_storage(fail_code, &schedule, &mut gas_meter).unwrap(); + let success_executable = + MockExecutable::from_storage(success_code, &schedule, &mut gas_meter).unwrap(); + let succ_fail_executable = + MockExecutable::from_storage(succ_fail_code, &schedule, &mut gas_meter).unwrap(); + let succ_succ_executable = + MockExecutable::from_storage(succ_succ_code, &schedule, &mut gas_meter).unwrap(); + set_balance(&ALICE, min_balance * 1000); + + MockStack::run_instantiate( + ALICE, + fail_executable, + &mut gas_meter, + &schedule, + min_balance * 100, + vec![], + &[], + None, + ) + .ok(); + assert_eq!(>::get(), 0); + + assert_ok!(MockStack::run_instantiate( + ALICE, + success_executable, + &mut gas_meter, + &schedule, + min_balance * 100, + vec![], + &[], + None, + )); + assert_eq!(>::get(), 1); + + assert_ok!(MockStack::run_instantiate( + ALICE, + succ_fail_executable, + &mut gas_meter, + &schedule, + min_balance * 200, + vec![], + &[], + None, + )); + assert_eq!(>::get(), 2); + + assert_ok!(MockStack::run_instantiate( + ALICE, + succ_succ_executable, + &mut gas_meter, + &schedule, + min_balance * 200, + vec![], + &[], + None, + )); + assert_eq!(>::get(), 4); + }); + } } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 1cebcb3b5d9a0..4b6c40764ad0a 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-09-09, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-10-28, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -151,83 +151,83 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (3_226_000 as Weight) + (2_987_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { (0 as Weight) // Standard Error: 2_000 - .saturating_add((2_178_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((2_201_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (78_329_000 as Weight) - // Standard Error: 1_000 - .saturating_add((353_000 as Weight).saturating_mul(q as Weight)) + (97_470_000 as Weight) + // Standard Error: 2_000 + .saturating_add((322_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn instrument(c: u32, ) -> Weight { - (37_190_000 as Weight) - // Standard Error: 80_000 - .saturating_add((72_791_000 as Weight).saturating_mul(c as Weight)) + (28_804_000 as Weight) + // Standard Error: 84_000 + .saturating_add((71_838_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:0) fn code_load(c: u32, ) -> Weight { - (6_191_000 as Weight) + (5_658_000 as Weight) // Standard Error: 0 - .saturating_add((1_426_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((1_425_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) fn code_refcount(c: u32, ) -> Weight { - (10_333_000 as Weight) + (9_001_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_275_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_281_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: Contracts AccountCounter (r:1 w:0) + // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (438_556_000 as Weight) - // Standard Error: 147_000 - .saturating_add((179_307_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 9_000 - .saturating_add((2_159_000 as Weight).saturating_mul(s as Weight)) + (499_349_000 as Weight) + // Standard Error: 199_000 + .saturating_add((174_439_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 13_000 + .saturating_add((2_096_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) - // Storage: Contracts AccountCounter (r:1 w:0) + // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (186_776_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_033_000 as Weight).saturating_mul(s as Weight)) + (181_151_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_025_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (159_247_000 as Weight) + (153_830_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -235,9 +235,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (422_263_000 as Weight) - // Standard Error: 159_000 - .saturating_add((125_490_000 as Weight).saturating_mul(r as Weight)) + (423_222_000 as Weight) + // Standard Error: 169_000 + .saturating_add((114_763_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -245,9 +245,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (423_009_000 as Weight) - // Standard Error: 183_000 - .saturating_add((125_795_000 as Weight).saturating_mul(r as Weight)) + (420_731_000 as Weight) + // Standard Error: 165_000 + .saturating_add((115_213_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -255,9 +255,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (429_297_000 as Weight) - // Standard Error: 164_000 - .saturating_add((124_324_000 as Weight).saturating_mul(r as Weight)) + (422_407_000 as Weight) + // Standard Error: 176_000 + .saturating_add((113_935_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -266,9 +266,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (442_330_000 as Weight) - // Standard Error: 187_000 - .saturating_add((354_665_000 as Weight).saturating_mul(r as Weight)) + (425_698_000 as Weight) + // Standard Error: 210_000 + .saturating_add((335_171_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -276,9 +276,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (411_893_000 as Weight) - // Standard Error: 178_000 - .saturating_add((125_971_000 as Weight).saturating_mul(r as Weight)) + (410_218_000 as Weight) + // Standard Error: 187_000 + .saturating_add((115_360_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -286,9 +286,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (413_273_000 as Weight) - // Standard Error: 180_000 - .saturating_add((125_103_000 as Weight).saturating_mul(r as Weight)) + (402_765_000 as Weight) + // Standard Error: 169_000 + .saturating_add((116_553_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -296,9 +296,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_tombstone_deposit(r: u32, ) -> Weight { - (415_613_000 as Weight) - // Standard Error: 192_000 - .saturating_add((126_106_000 as Weight).saturating_mul(r as Weight)) + (404_817_000 as Weight) + // Standard Error: 173_000 + .saturating_add((115_894_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -306,9 +306,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (414_718_000 as Weight) - // Standard Error: 170_000 - .saturating_add((124_962_000 as Weight).saturating_mul(r as Weight)) + (405_604_000 as Weight) + // Standard Error: 193_000 + .saturating_add((115_757_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -316,9 +316,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (419_120_000 as Weight) - // Standard Error: 178_000 - .saturating_add((125_188_000 as Weight).saturating_mul(r as Weight)) + (413_577_000 as Weight) + // Standard Error: 166_000 + .saturating_add((115_115_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -327,9 +327,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (419_125_000 as Weight) - // Standard Error: 216_000 - .saturating_add((290_592_000 as Weight).saturating_mul(r as Weight)) + (413_932_000 as Weight) + // Standard Error: 201_000 + .saturating_add((272_742_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -337,9 +337,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (149_609_000 as Weight) - // Standard Error: 117_000 - .saturating_add((56_860_000 as Weight).saturating_mul(r as Weight)) + (144_109_000 as Weight) + // Standard Error: 96_000 + .saturating_add((52_461_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -347,9 +347,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (423_570_000 as Weight) - // Standard Error: 151_000 - .saturating_add((106_985_000 as Weight).saturating_mul(r as Weight)) + (422_584_000 as Weight) + // Standard Error: 158_000 + .saturating_add((98_316_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -357,9 +357,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (566_496_000 as Weight) - // Standard Error: 6_000 - .saturating_add((38_091_000 as Weight).saturating_mul(n as Weight)) + (549_530_000 as Weight) + // Standard Error: 8_000 + .saturating_add((38_025_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -367,9 +367,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (406_811_000 as Weight) - // Standard Error: 1_833_000 - .saturating_add((6_551_000 as Weight).saturating_mul(r as Weight)) + (403_711_000 as Weight) + // Standard Error: 114_000 + .saturating_add((2_996_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -377,9 +377,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (412_094_000 as Weight) + (408_252_000 as Weight) // Standard Error: 1_000 - .saturating_add((631_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((630_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -389,9 +389,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: System Account (r:2 w:2) fn seal_terminate(r: u32, ) -> Weight { - (415_716_000 as Weight) - // Standard Error: 1_608_000 - .saturating_add((72_648_000 as Weight).saturating_mul(r as Weight)) + (412_619_000 as Weight) + // Standard Error: 896_000 + .saturating_add((66_155_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -402,9 +402,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (421_387_000 as Weight) - // Standard Error: 275_000 - .saturating_add((393_452_000 as Weight).saturating_mul(r as Weight)) + (416_604_000 as Weight) + // Standard Error: 274_000 + .saturating_add((366_304_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -412,9 +412,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (428_591_000 as Weight) - // Standard Error: 293_000 - .saturating_add((690_833_000 as Weight).saturating_mul(r as Weight)) + (417_326_000 as Weight) + // Standard Error: 457_000 + .saturating_add((640_211_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -423,11 +423,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_245_676_000 as Weight) - // Standard Error: 2_636_000 - .saturating_add((484_691_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 519_000 - .saturating_add((165_836_000 as Weight).saturating_mul(n as Weight)) + (1_121_348_000 as Weight) + // Standard Error: 2_483_000 + .saturating_add((463_498_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 489_000 + .saturating_add((167_147_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -437,17 +437,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (162_162_000 as Weight) - // Standard Error: 127_000 - .saturating_add((72_828_000 as Weight).saturating_mul(r as Weight)) + (159_880_000 as Weight) + // Standard Error: 138_000 + .saturating_add((67_837_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (399_301_000 as Weight) - // Standard Error: 221_000 - .saturating_add((245_222_000 as Weight).saturating_mul(r as Weight)) + (389_400_000 as Weight) + // Standard Error: 239_000 + .saturating_add((238_933_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) @@ -457,26 +457,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:0 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (623_011_000 as Weight) - // Standard Error: 246_000 - .saturating_add((72_051_000 as Weight).saturating_mul(n as Weight)) + (611_980_000 as Weight) + // Standard Error: 234_000 + .saturating_add((72_047_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (445_102_000 as Weight) - // Standard Error: 247_000 - .saturating_add((224_384_000 as Weight).saturating_mul(r as Weight)) + (436_588_000 as Weight) + // Standard Error: 222_000 + .saturating_add((209_734_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (290_227_000 as Weight) - // Standard Error: 694_000 - .saturating_add((547_193_000 as Weight).saturating_mul(r as Weight)) + (285_689_000 as Weight) + // Standard Error: 742_000 + .saturating_add((496_745_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -486,9 +486,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (737_772_000 as Weight) - // Standard Error: 267_000 - .saturating_add((112_216_000 as Weight).saturating_mul(n as Weight)) + (693_967_000 as Weight) + // Standard Error: 226_000 + .saturating_add((111_370_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -497,9 +497,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:101 w:101) fn seal_transfer(r: u32, ) -> Weight { - (383_402_000 as Weight) - // Standard Error: 2_184_000 - .saturating_add((4_335_681_000 as Weight).saturating_mul(r as Weight)) + (332_032_000 as Weight) + // Standard Error: 2_537_000 + .saturating_add((4_071_041_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -510,8 +510,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_019_000 - .saturating_add((39_806_777_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 10_806_000 + .saturating_add((39_442_275_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -522,13 +522,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:101 w:101) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (38_662_592_000 as Weight) - // Standard Error: 52_762_000 - .saturating_add((3_888_801_000 as Weight).saturating_mul(t as Weight)) + (38_600_435_000 as Weight) + // Standard Error: 53_014_000 + .saturating_add((3_392_887_000 as Weight).saturating_mul(t as Weight)) // Standard Error: 18_000 - .saturating_add((63_571_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((63_348_000 as Weight).saturating_mul(i as Weight)) // Standard Error: 20_000 - .saturating_add((101_610_000 as Weight).saturating_mul(o as Weight)) + .saturating_add((101_366_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -540,9 +540,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: System Account (r:101 w:101) fn seal_instantiate(r: u32, ) -> Weight { - (626_132_000 as Weight) - // Standard Error: 39_245_000 - .saturating_add((46_398_859_000 as Weight).saturating_mul(r as Weight)) + (643_999_000 as Weight) + // Standard Error: 37_244_000 + .saturating_add((45_559_839_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((300 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -554,13 +554,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: System Account (r:101 w:101) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (46_649_369_000 as Weight) - // Standard Error: 26_000 - .saturating_add((63_469_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 26_000 - .saturating_add((100_694_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 26_000 - .saturating_add((201_705_000 as Weight).saturating_mul(s as Weight)) + (45_415_035_000 as Weight) + // Standard Error: 30_000 + .saturating_add((63_567_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 30_000 + .saturating_add((100_900_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 30_000 + .saturating_add((201_139_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(206 as Weight)) .saturating_add(T::DbWeight::get().writes(204 as Weight)) } @@ -568,9 +568,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (417_820_000 as Weight) - // Standard Error: 160_000 - .saturating_add((133_795_000 as Weight).saturating_mul(r as Weight)) + (417_335_000 as Weight) + // Standard Error: 174_000 + .saturating_add((126_268_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -578,9 +578,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (609_012_000 as Weight) - // Standard Error: 23_000 - .saturating_add((499_227_000 as Weight).saturating_mul(n as Weight)) + (700_565_000 as Weight) + // Standard Error: 68_000 + .saturating_add((499_898_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -588,9 +588,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (419_043_000 as Weight) - // Standard Error: 177_000 - .saturating_add((140_704_000 as Weight).saturating_mul(r as Weight)) + (416_014_000 as Weight) + // Standard Error: 168_000 + .saturating_add((134_320_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -598,9 +598,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (564_451_000 as Weight) + (534_466_000 as Weight) // Standard Error: 19_000 - .saturating_add((346_948_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((346_588_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -608,9 +608,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (420_951_000 as Weight) - // Standard Error: 163_000 - .saturating_add((113_596_000 as Weight).saturating_mul(r as Weight)) + (414_278_000 as Weight) + // Standard Error: 164_000 + .saturating_add((106_210_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -618,9 +618,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (563_168_000 as Weight) - // Standard Error: 17_000 - .saturating_add((164_114_000 as Weight).saturating_mul(n as Weight)) + (569_659_000 as Weight) + // Standard Error: 16_000 + .saturating_add((163_989_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -628,9 +628,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (418_794_000 as Weight) - // Standard Error: 167_000 - .saturating_add((113_205_000 as Weight).saturating_mul(r as Weight)) + (421_251_000 as Weight) + // Standard Error: 166_000 + .saturating_add((104_678_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -638,9 +638,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (584_668_000 as Weight) - // Standard Error: 15_000 - .saturating_add((164_127_000 as Weight).saturating_mul(n as Weight)) + (568_490_000 as Weight) + // Standard Error: 21_000 + .saturating_add((163_999_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -648,264 +648,264 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (435_443_000 as Weight) - // Standard Error: 1_408_000 - .saturating_add((15_624_877_000 as Weight).saturating_mul(r as Weight)) + (361_122_000 as Weight) + // Standard Error: 1_172_000 + .saturating_add((15_591_590_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (45_937_000 as Weight) + (46_003_000 as Weight) // Standard Error: 10_000 - .saturating_add((1_108_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_185_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (44_001_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_412_000 as Weight).saturating_mul(r as Weight)) + (42_908_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_570_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (43_157_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_677_000 as Weight).saturating_mul(r as Weight)) + (42_739_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_791_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (48_475_000 as Weight) + (47_543_000 as Weight) // Standard Error: 8_000 - .saturating_add((2_604_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_834_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (50_649_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_553_000 as Weight).saturating_mul(r as Weight)) + (50_540_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_663_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (48_433_000 as Weight) + (47_732_000 as Weight) // Standard Error: 8_000 - .saturating_add((1_670_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_771_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (49_244_000 as Weight) - // Standard Error: 16_000 - .saturating_add((1_946_000 as Weight).saturating_mul(r as Weight)) + (49_005_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_072_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (46_117_000 as Weight) + (45_975_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_387_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(_e: u32, ) -> Weight { - (55_204_000 as Weight) + (55_461_000 as Weight) } fn instr_call(r: u32, ) -> Weight { - (43_651_000 as Weight) - // Standard Error: 26_000 - .saturating_add((19_163_000 as Weight).saturating_mul(r as Weight)) + (41_932_000 as Weight) + // Standard Error: 29_000 + .saturating_add((19_800_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (54_063_000 as Weight) - // Standard Error: 32_000 - .saturating_add((27_970_000 as Weight).saturating_mul(r as Weight)) + (56_550_000 as Weight) + // Standard Error: 34_000 + .saturating_add((28_414_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (88_527_000 as Weight) + (93_172_000 as Weight) // Standard Error: 6_000 - .saturating_add((958_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_018_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (55_066_000 as Weight) - // Standard Error: 12_000 - .saturating_add((682_000 as Weight).saturating_mul(r as Weight)) + (54_603_000 as Weight) + // Standard Error: 14_000 + .saturating_add((764_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (55_298_000 as Weight) - // Standard Error: 13_000 - .saturating_add((778_000 as Weight).saturating_mul(r as Weight)) + (54_763_000 as Weight) + // Standard Error: 14_000 + .saturating_add((878_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (56_302_000 as Weight) + (56_137_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_079_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_194_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (71_567_000 as Weight) + (69_513_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_107_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_125_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (71_186_000 as Weight) + (69_120_000 as Weight) // Standard Error: 12_000 - .saturating_add((1_151_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_215_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (46_240_000 as Weight) + (46_021_000 as Weight) // Standard Error: 10_000 - .saturating_add((1_044_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_103_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (52_369_000 as Weight) - // Standard Error: 2_508_000 - .saturating_add((615_448_000 as Weight).saturating_mul(r as Weight)) + (52_245_000 as Weight) + // Standard Error: 4_119_000 + .saturating_add((619_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (47_623_000 as Weight) + (47_314_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_583_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_720_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (47_670_000 as Weight) + (47_855_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_583_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_701_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (47_508_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_583_000 as Weight).saturating_mul(r as Weight)) + (47_704_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_708_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (48_109_000 as Weight) + (47_656_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_580_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_705_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (55_270_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_102_000 as Weight).saturating_mul(r as Weight)) + (55_202_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_229_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (55_093_000 as Weight) + (55_193_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_108_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_223_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (48_265_000 as Weight) + (48_125_000 as Weight) // Standard Error: 10_000 - .saturating_add((1_573_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_704_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (48_733_000 as Weight) + (49_162_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_088_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_241_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (48_831_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_085_000 as Weight).saturating_mul(r as Weight)) + (48_635_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_262_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (49_147_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_056_000 as Weight).saturating_mul(r as Weight)) + (48_550_000 as Weight) + // Standard Error: 9_000 + .saturating_add((2_267_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (49_596_000 as Weight) + (49_135_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_049_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_219_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (49_872_000 as Weight) + (49_638_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_038_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_206_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (48_843_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_081_000 as Weight).saturating_mul(r as Weight)) + (49_889_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_201_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (48_765_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_089_000 as Weight).saturating_mul(r as Weight)) + (49_763_000 as Weight) + // Standard Error: 9_000 + .saturating_add((2_210_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (48_720_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_083_000 as Weight).saturating_mul(r as Weight)) + (49_607_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_207_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (48_736_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_097_000 as Weight).saturating_mul(r as Weight)) + (49_664_000 as Weight) + // Standard Error: 9_000 + .saturating_add((2_213_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (48_772_000 as Weight) + (49_718_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_093_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_206_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (48_827_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_082_000 as Weight).saturating_mul(r as Weight)) + (49_513_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_208_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (48_961_000 as Weight) + (49_837_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_072_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_201_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (49_069_000 as Weight) + (49_684_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_067_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_210_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (49_035_000 as Weight) + (48_749_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_677_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_872_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (48_842_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_449_000 as Weight).saturating_mul(r as Weight)) + (49_134_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_630_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (48_536_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_723_000 as Weight).saturating_mul(r as Weight)) + (48_981_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_861_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (48_851_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_432_000 as Weight).saturating_mul(r as Weight)) + (49_195_000 as Weight) + // Standard Error: 8_000 + .saturating_add((2_593_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (48_624_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_093_000 as Weight).saturating_mul(r as Weight)) + (49_304_000 as Weight) + // Standard Error: 8_000 + .saturating_add((2_238_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (49_348_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_073_000 as Weight).saturating_mul(r as Weight)) + (48_636_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_259_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (49_112_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_055_000 as Weight).saturating_mul(r as Weight)) + (48_761_000 as Weight) + // Standard Error: 8_000 + .saturating_add((2_262_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (49_654_000 as Weight) + (48_492_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_051_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_263_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (48_848_000 as Weight) + (48_736_000 as Weight) // Standard Error: 8_000 - .saturating_add((2_089_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_256_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (49_455_000 as Weight) + (48_675_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_054_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_256_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (49_640_000 as Weight) + (48_703_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_048_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_257_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (49_498_000 as Weight) + (48_758_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_068_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_259_000 as Weight).saturating_mul(r as Weight)) } } @@ -913,83 +913,83 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (3_226_000 as Weight) + (2_987_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { (0 as Weight) // Standard Error: 2_000 - .saturating_add((2_178_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((2_201_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (78_329_000 as Weight) - // Standard Error: 1_000 - .saturating_add((353_000 as Weight).saturating_mul(q as Weight)) + (97_470_000 as Weight) + // Standard Error: 2_000 + .saturating_add((322_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn instrument(c: u32, ) -> Weight { - (37_190_000 as Weight) - // Standard Error: 80_000 - .saturating_add((72_791_000 as Weight).saturating_mul(c as Weight)) + (28_804_000 as Weight) + // Standard Error: 84_000 + .saturating_add((71_838_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:0) fn code_load(c: u32, ) -> Weight { - (6_191_000 as Weight) + (5_658_000 as Weight) // Standard Error: 0 - .saturating_add((1_426_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((1_425_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) fn code_refcount(c: u32, ) -> Weight { - (10_333_000 as Weight) + (9_001_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_275_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_281_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: Contracts AccountCounter (r:1 w:0) + // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (438_556_000 as Weight) - // Standard Error: 147_000 - .saturating_add((179_307_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 9_000 - .saturating_add((2_159_000 as Weight).saturating_mul(s as Weight)) + (499_349_000 as Weight) + // Standard Error: 199_000 + .saturating_add((174_439_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 13_000 + .saturating_add((2_096_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) - // Storage: Contracts AccountCounter (r:1 w:0) + // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (186_776_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_033_000 as Weight).saturating_mul(s as Weight)) + (181_151_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_025_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (159_247_000 as Weight) + (153_830_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -997,9 +997,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (422_263_000 as Weight) - // Standard Error: 159_000 - .saturating_add((125_490_000 as Weight).saturating_mul(r as Weight)) + (423_222_000 as Weight) + // Standard Error: 169_000 + .saturating_add((114_763_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1007,9 +1007,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (423_009_000 as Weight) - // Standard Error: 183_000 - .saturating_add((125_795_000 as Weight).saturating_mul(r as Weight)) + (420_731_000 as Weight) + // Standard Error: 165_000 + .saturating_add((115_213_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1017,9 +1017,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (429_297_000 as Weight) - // Standard Error: 164_000 - .saturating_add((124_324_000 as Weight).saturating_mul(r as Weight)) + (422_407_000 as Weight) + // Standard Error: 176_000 + .saturating_add((113_935_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1028,9 +1028,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (442_330_000 as Weight) - // Standard Error: 187_000 - .saturating_add((354_665_000 as Weight).saturating_mul(r as Weight)) + (425_698_000 as Weight) + // Standard Error: 210_000 + .saturating_add((335_171_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1038,9 +1038,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (411_893_000 as Weight) - // Standard Error: 178_000 - .saturating_add((125_971_000 as Weight).saturating_mul(r as Weight)) + (410_218_000 as Weight) + // Standard Error: 187_000 + .saturating_add((115_360_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1048,9 +1048,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (413_273_000 as Weight) - // Standard Error: 180_000 - .saturating_add((125_103_000 as Weight).saturating_mul(r as Weight)) + (402_765_000 as Weight) + // Standard Error: 169_000 + .saturating_add((116_553_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1058,9 +1058,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_tombstone_deposit(r: u32, ) -> Weight { - (415_613_000 as Weight) - // Standard Error: 192_000 - .saturating_add((126_106_000 as Weight).saturating_mul(r as Weight)) + (404_817_000 as Weight) + // Standard Error: 173_000 + .saturating_add((115_894_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1068,9 +1068,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (414_718_000 as Weight) - // Standard Error: 170_000 - .saturating_add((124_962_000 as Weight).saturating_mul(r as Weight)) + (405_604_000 as Weight) + // Standard Error: 193_000 + .saturating_add((115_757_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1078,9 +1078,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (419_120_000 as Weight) - // Standard Error: 178_000 - .saturating_add((125_188_000 as Weight).saturating_mul(r as Weight)) + (413_577_000 as Weight) + // Standard Error: 166_000 + .saturating_add((115_115_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1089,9 +1089,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (419_125_000 as Weight) - // Standard Error: 216_000 - .saturating_add((290_592_000 as Weight).saturating_mul(r as Weight)) + (413_932_000 as Weight) + // Standard Error: 201_000 + .saturating_add((272_742_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1099,9 +1099,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (149_609_000 as Weight) - // Standard Error: 117_000 - .saturating_add((56_860_000 as Weight).saturating_mul(r as Weight)) + (144_109_000 as Weight) + // Standard Error: 96_000 + .saturating_add((52_461_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1109,9 +1109,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (423_570_000 as Weight) - // Standard Error: 151_000 - .saturating_add((106_985_000 as Weight).saturating_mul(r as Weight)) + (422_584_000 as Weight) + // Standard Error: 158_000 + .saturating_add((98_316_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1119,9 +1119,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (566_496_000 as Weight) - // Standard Error: 6_000 - .saturating_add((38_091_000 as Weight).saturating_mul(n as Weight)) + (549_530_000 as Weight) + // Standard Error: 8_000 + .saturating_add((38_025_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1129,9 +1129,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (406_811_000 as Weight) - // Standard Error: 1_833_000 - .saturating_add((6_551_000 as Weight).saturating_mul(r as Weight)) + (403_711_000 as Weight) + // Standard Error: 114_000 + .saturating_add((2_996_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1139,9 +1139,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (412_094_000 as Weight) + (408_252_000 as Weight) // Standard Error: 1_000 - .saturating_add((631_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((630_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1151,9 +1151,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: System Account (r:2 w:2) fn seal_terminate(r: u32, ) -> Weight { - (415_716_000 as Weight) - // Standard Error: 1_608_000 - .saturating_add((72_648_000 as Weight).saturating_mul(r as Weight)) + (412_619_000 as Weight) + // Standard Error: 896_000 + .saturating_add((66_155_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1164,9 +1164,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (421_387_000 as Weight) - // Standard Error: 275_000 - .saturating_add((393_452_000 as Weight).saturating_mul(r as Weight)) + (416_604_000 as Weight) + // Standard Error: 274_000 + .saturating_add((366_304_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1174,9 +1174,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (428_591_000 as Weight) - // Standard Error: 293_000 - .saturating_add((690_833_000 as Weight).saturating_mul(r as Weight)) + (417_326_000 as Weight) + // Standard Error: 457_000 + .saturating_add((640_211_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1185,11 +1185,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_245_676_000 as Weight) - // Standard Error: 2_636_000 - .saturating_add((484_691_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 519_000 - .saturating_add((165_836_000 as Weight).saturating_mul(n as Weight)) + (1_121_348_000 as Weight) + // Standard Error: 2_483_000 + .saturating_add((463_498_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 489_000 + .saturating_add((167_147_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1199,17 +1199,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (162_162_000 as Weight) - // Standard Error: 127_000 - .saturating_add((72_828_000 as Weight).saturating_mul(r as Weight)) + (159_880_000 as Weight) + // Standard Error: 138_000 + .saturating_add((67_837_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (399_301_000 as Weight) - // Standard Error: 221_000 - .saturating_add((245_222_000 as Weight).saturating_mul(r as Weight)) + (389_400_000 as Weight) + // Standard Error: 239_000 + .saturating_add((238_933_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) @@ -1219,26 +1219,26 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:0 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (623_011_000 as Weight) - // Standard Error: 246_000 - .saturating_add((72_051_000 as Weight).saturating_mul(n as Weight)) + (611_980_000 as Weight) + // Standard Error: 234_000 + .saturating_add((72_047_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (445_102_000 as Weight) - // Standard Error: 247_000 - .saturating_add((224_384_000 as Weight).saturating_mul(r as Weight)) + (436_588_000 as Weight) + // Standard Error: 222_000 + .saturating_add((209_734_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (290_227_000 as Weight) - // Standard Error: 694_000 - .saturating_add((547_193_000 as Weight).saturating_mul(r as Weight)) + (285_689_000 as Weight) + // Standard Error: 742_000 + .saturating_add((496_745_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1248,9 +1248,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (737_772_000 as Weight) - // Standard Error: 267_000 - .saturating_add((112_216_000 as Weight).saturating_mul(n as Weight)) + (693_967_000 as Weight) + // Standard Error: 226_000 + .saturating_add((111_370_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1259,9 +1259,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:101 w:101) fn seal_transfer(r: u32, ) -> Weight { - (383_402_000 as Weight) - // Standard Error: 2_184_000 - .saturating_add((4_335_681_000 as Weight).saturating_mul(r as Weight)) + (332_032_000 as Weight) + // Standard Error: 2_537_000 + .saturating_add((4_071_041_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1272,8 +1272,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_019_000 - .saturating_add((39_806_777_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 10_806_000 + .saturating_add((39_442_275_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1284,13 +1284,13 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:101 w:101) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (38_662_592_000 as Weight) - // Standard Error: 52_762_000 - .saturating_add((3_888_801_000 as Weight).saturating_mul(t as Weight)) + (38_600_435_000 as Weight) + // Standard Error: 53_014_000 + .saturating_add((3_392_887_000 as Weight).saturating_mul(t as Weight)) // Standard Error: 18_000 - .saturating_add((63_571_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((63_348_000 as Weight).saturating_mul(i as Weight)) // Standard Error: 20_000 - .saturating_add((101_610_000 as Weight).saturating_mul(o as Weight)) + .saturating_add((101_366_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1302,9 +1302,9 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: System Account (r:101 w:101) fn seal_instantiate(r: u32, ) -> Weight { - (626_132_000 as Weight) - // Standard Error: 39_245_000 - .saturating_add((46_398_859_000 as Weight).saturating_mul(r as Weight)) + (643_999_000 as Weight) + // Standard Error: 37_244_000 + .saturating_add((45_559_839_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((300 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1316,13 +1316,13 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: System Account (r:101 w:101) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (46_649_369_000 as Weight) - // Standard Error: 26_000 - .saturating_add((63_469_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 26_000 - .saturating_add((100_694_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 26_000 - .saturating_add((201_705_000 as Weight).saturating_mul(s as Weight)) + (45_415_035_000 as Weight) + // Standard Error: 30_000 + .saturating_add((63_567_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 30_000 + .saturating_add((100_900_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 30_000 + .saturating_add((201_139_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(206 as Weight)) .saturating_add(RocksDbWeight::get().writes(204 as Weight)) } @@ -1330,9 +1330,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (417_820_000 as Weight) - // Standard Error: 160_000 - .saturating_add((133_795_000 as Weight).saturating_mul(r as Weight)) + (417_335_000 as Weight) + // Standard Error: 174_000 + .saturating_add((126_268_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1340,9 +1340,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (609_012_000 as Weight) - // Standard Error: 23_000 - .saturating_add((499_227_000 as Weight).saturating_mul(n as Weight)) + (700_565_000 as Weight) + // Standard Error: 68_000 + .saturating_add((499_898_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1350,9 +1350,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (419_043_000 as Weight) - // Standard Error: 177_000 - .saturating_add((140_704_000 as Weight).saturating_mul(r as Weight)) + (416_014_000 as Weight) + // Standard Error: 168_000 + .saturating_add((134_320_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1360,9 +1360,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (564_451_000 as Weight) + (534_466_000 as Weight) // Standard Error: 19_000 - .saturating_add((346_948_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((346_588_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1370,9 +1370,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (420_951_000 as Weight) - // Standard Error: 163_000 - .saturating_add((113_596_000 as Weight).saturating_mul(r as Weight)) + (414_278_000 as Weight) + // Standard Error: 164_000 + .saturating_add((106_210_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1380,9 +1380,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (563_168_000 as Weight) - // Standard Error: 17_000 - .saturating_add((164_114_000 as Weight).saturating_mul(n as Weight)) + (569_659_000 as Weight) + // Standard Error: 16_000 + .saturating_add((163_989_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1390,9 +1390,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (418_794_000 as Weight) - // Standard Error: 167_000 - .saturating_add((113_205_000 as Weight).saturating_mul(r as Weight)) + (421_251_000 as Weight) + // Standard Error: 166_000 + .saturating_add((104_678_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1400,9 +1400,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (584_668_000 as Weight) - // Standard Error: 15_000 - .saturating_add((164_127_000 as Weight).saturating_mul(n as Weight)) + (568_490_000 as Weight) + // Standard Error: 21_000 + .saturating_add((163_999_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1410,263 +1410,263 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (435_443_000 as Weight) - // Standard Error: 1_408_000 - .saturating_add((15_624_877_000 as Weight).saturating_mul(r as Weight)) + (361_122_000 as Weight) + // Standard Error: 1_172_000 + .saturating_add((15_591_590_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (45_937_000 as Weight) + (46_003_000 as Weight) // Standard Error: 10_000 - .saturating_add((1_108_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_185_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (44_001_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_412_000 as Weight).saturating_mul(r as Weight)) + (42_908_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_570_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (43_157_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_677_000 as Weight).saturating_mul(r as Weight)) + (42_739_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_791_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (48_475_000 as Weight) + (47_543_000 as Weight) // Standard Error: 8_000 - .saturating_add((2_604_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_834_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (50_649_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_553_000 as Weight).saturating_mul(r as Weight)) + (50_540_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_663_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (48_433_000 as Weight) + (47_732_000 as Weight) // Standard Error: 8_000 - .saturating_add((1_670_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_771_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (49_244_000 as Weight) - // Standard Error: 16_000 - .saturating_add((1_946_000 as Weight).saturating_mul(r as Weight)) + (49_005_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_072_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (46_117_000 as Weight) + (45_975_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_387_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(_e: u32, ) -> Weight { - (55_204_000 as Weight) + (55_461_000 as Weight) } fn instr_call(r: u32, ) -> Weight { - (43_651_000 as Weight) - // Standard Error: 26_000 - .saturating_add((19_163_000 as Weight).saturating_mul(r as Weight)) + (41_932_000 as Weight) + // Standard Error: 29_000 + .saturating_add((19_800_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (54_063_000 as Weight) - // Standard Error: 32_000 - .saturating_add((27_970_000 as Weight).saturating_mul(r as Weight)) + (56_550_000 as Weight) + // Standard Error: 34_000 + .saturating_add((28_414_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (88_527_000 as Weight) + (93_172_000 as Weight) // Standard Error: 6_000 - .saturating_add((958_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_018_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (55_066_000 as Weight) - // Standard Error: 12_000 - .saturating_add((682_000 as Weight).saturating_mul(r as Weight)) + (54_603_000 as Weight) + // Standard Error: 14_000 + .saturating_add((764_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (55_298_000 as Weight) - // Standard Error: 13_000 - .saturating_add((778_000 as Weight).saturating_mul(r as Weight)) + (54_763_000 as Weight) + // Standard Error: 14_000 + .saturating_add((878_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (56_302_000 as Weight) + (56_137_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_079_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_194_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (71_567_000 as Weight) + (69_513_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_107_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_125_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (71_186_000 as Weight) + (69_120_000 as Weight) // Standard Error: 12_000 - .saturating_add((1_151_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_215_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (46_240_000 as Weight) + (46_021_000 as Weight) // Standard Error: 10_000 - .saturating_add((1_044_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_103_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (52_369_000 as Weight) - // Standard Error: 2_508_000 - .saturating_add((615_448_000 as Weight).saturating_mul(r as Weight)) + (52_245_000 as Weight) + // Standard Error: 4_119_000 + .saturating_add((619_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (47_623_000 as Weight) + (47_314_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_583_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_720_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (47_670_000 as Weight) + (47_855_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_583_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_701_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (47_508_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_583_000 as Weight).saturating_mul(r as Weight)) + (47_704_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_708_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (48_109_000 as Weight) + (47_656_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_580_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_705_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (55_270_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_102_000 as Weight).saturating_mul(r as Weight)) + (55_202_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_229_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (55_093_000 as Weight) + (55_193_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_108_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_223_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (48_265_000 as Weight) + (48_125_000 as Weight) // Standard Error: 10_000 - .saturating_add((1_573_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_704_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (48_733_000 as Weight) + (49_162_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_088_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_241_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (48_831_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_085_000 as Weight).saturating_mul(r as Weight)) + (48_635_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_262_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (49_147_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_056_000 as Weight).saturating_mul(r as Weight)) + (48_550_000 as Weight) + // Standard Error: 9_000 + .saturating_add((2_267_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (49_596_000 as Weight) + (49_135_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_049_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_219_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (49_872_000 as Weight) + (49_638_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_038_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_206_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (48_843_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_081_000 as Weight).saturating_mul(r as Weight)) + (49_889_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_201_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (48_765_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_089_000 as Weight).saturating_mul(r as Weight)) + (49_763_000 as Weight) + // Standard Error: 9_000 + .saturating_add((2_210_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (48_720_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_083_000 as Weight).saturating_mul(r as Weight)) + (49_607_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_207_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (48_736_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_097_000 as Weight).saturating_mul(r as Weight)) + (49_664_000 as Weight) + // Standard Error: 9_000 + .saturating_add((2_213_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (48_772_000 as Weight) + (49_718_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_093_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_206_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (48_827_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_082_000 as Weight).saturating_mul(r as Weight)) + (49_513_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_208_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (48_961_000 as Weight) + (49_837_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_072_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_201_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (49_069_000 as Weight) + (49_684_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_067_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_210_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (49_035_000 as Weight) + (48_749_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_677_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_872_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (48_842_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_449_000 as Weight).saturating_mul(r as Weight)) + (49_134_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_630_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (48_536_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_723_000 as Weight).saturating_mul(r as Weight)) + (48_981_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_861_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (48_851_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_432_000 as Weight).saturating_mul(r as Weight)) + (49_195_000 as Weight) + // Standard Error: 8_000 + .saturating_add((2_593_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (48_624_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_093_000 as Weight).saturating_mul(r as Weight)) + (49_304_000 as Weight) + // Standard Error: 8_000 + .saturating_add((2_238_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (49_348_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_073_000 as Weight).saturating_mul(r as Weight)) + (48_636_000 as Weight) + // Standard Error: 7_000 + .saturating_add((2_259_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (49_112_000 as Weight) - // Standard Error: 6_000 - .saturating_add((2_055_000 as Weight).saturating_mul(r as Weight)) + (48_761_000 as Weight) + // Standard Error: 8_000 + .saturating_add((2_262_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (49_654_000 as Weight) + (48_492_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_051_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_263_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (48_848_000 as Weight) + (48_736_000 as Weight) // Standard Error: 8_000 - .saturating_add((2_089_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_256_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (49_455_000 as Weight) + (48_675_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_054_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_256_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (49_640_000 as Weight) + (48_703_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_048_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_257_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (49_498_000 as Weight) + (48_758_000 as Weight) // Standard Error: 7_000 - .saturating_add((2_068_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_259_000 as Weight).saturating_mul(r as Weight)) } } From 1d818f38a3198f21b4ae68bac3dc98219fccc669 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Sat, 30 Oct 2021 14:38:27 +0200 Subject: [PATCH 0157/1472] Removal of light client from substrate (#9684) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Removal of light client from substrate * add missing import * These tests relate to there being light and non light clients. * removing lightnodes from test * cargo fmt * not needed * LightDataChecker not needed any longer * cargo fmt * Update client/service/test/src/lib.rs Co-authored-by: Bastian Köcher * Update client/service/test/src/lib.rs Co-authored-by: Bastian Köcher * cargo fmt Co-authored-by: Bastian Köcher --- Cargo.lock | 1 - bin/node-template/node/src/command.rs | 8 +- bin/node-template/node/src/service.rs | 143 +-- bin/node/cli/src/chain_spec.rs | 34 +- bin/node/cli/src/command.rs | 8 +- bin/node/cli/src/service.rs | 204 +--- .../tests/database_role_subdir_migration.rs | 116 --- client/light/src/blockchain.rs | 2 +- client/light/src/fetcher.rs | 366 ------- client/light/src/lib.rs | 20 +- client/rpc/src/state/mod.rs | 41 - client/rpc/src/state/state_light.rs | 873 ---------------- client/service/Cargo.toml | 1 - client/service/src/builder.rs | 136 +-- client/service/src/client/client.rs | 2 +- client/service/src/client/light.rs | 82 -- client/service/src/client/mod.rs | 1 - client/service/src/lib.rs | 7 +- client/service/test/src/client/db.rs | 1 + client/service/test/src/client/light.rs | 981 ------------------ client/service/test/src/client/mod.rs | 3 - client/service/test/src/lib.rs | 194 +--- 22 files changed, 83 insertions(+), 3141 deletions(-) delete mode 100644 bin/node/cli/tests/database_role_subdir_migration.rs delete mode 100644 client/light/src/fetcher.rs delete mode 100644 client/rpc/src/state/state_light.rs delete mode 100644 client/service/src/client/light.rs delete mode 100644 client/service/test/src/client/light.rs diff --git a/Cargo.lock b/Cargo.lock index ed10002bd5489..c3cfaec19532e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8329,7 +8329,6 @@ dependencies = [ "sc-executor", "sc-informant", "sc-keystore", - "sc-light", "sc-network", "sc-offchain", "sc-rpc", diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index e948c3f53b716..e1cfeaeb801e3 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -4,7 +4,7 @@ use crate::{ service, }; use node_template_runtime::Block; -use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli}; +use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; impl SubstrateCli for Cli { @@ -111,11 +111,7 @@ pub fn run() -> sc_cli::Result<()> { None => { let runner = cli.create_runner(&cli.run)?; runner.run_node_until_exit(|config| async move { - match config.role { - Role::Light => service::new_light(config), - _ => service::new_full(config), - } - .map_err(sc_cli::Error::Service) + service::new_full(config).map_err(sc_cli::Error::Service) }) }, } diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 2286ad3bd654f..d673a54a94882 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -1,7 +1,7 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. use node_template_runtime::{self, opaque::Block, RuntimeApi}; -use sc_client_api::{ExecutorProvider, RemoteBackend}; +use sc_client_api::ExecutorProvider; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; pub use sc_executor::NativeElseWasmExecutor; use sc_finality_grandpa::SharedVoterState; @@ -336,144 +336,3 @@ pub fn new_full(mut config: Configuration) -> Result network_starter.start_network(); Ok(task_manager) } - -/// Builds a new service for a light client. -pub fn new_light(mut config: Configuration) -> Result { - let telemetry = config - .telemetry_endpoints - .clone() - .filter(|x| !x.is_empty()) - .map(|endpoints| -> Result<_, sc_telemetry::Error> { - let worker = TelemetryWorker::new(16)?; - let telemetry = worker.handle().new_telemetry(endpoints); - Ok((worker, telemetry)) - }) - .transpose()?; - - let executor = NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - ); - - let (client, backend, keystore_container, mut task_manager, on_demand) = - sc_service::new_light_parts::( - &config, - telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), - executor, - )?; - - let mut telemetry = telemetry.map(|(worker, telemetry)| { - task_manager.spawn_handle().spawn("telemetry", worker.run()); - telemetry - }); - - config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config()); - - let select_chain = sc_consensus::LongestChain::new(backend.clone()); - - let transaction_pool = Arc::new(sc_transaction_pool::BasicPool::new_light( - config.transaction_pool.clone(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), - on_demand.clone(), - )); - - let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import( - client.clone(), - &(client.clone() as Arc<_>), - select_chain.clone(), - telemetry.as_ref().map(|x| x.handle()), - )?; - - let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration(); - - let import_queue = - sc_consensus_aura::import_queue::(ImportQueueParams { - block_import: grandpa_block_import.clone(), - justification_import: Some(Box::new(grandpa_block_import.clone())), - client: client.clone(), - create_inherent_data_providers: move |_, ()| async move { - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration( - *timestamp, - slot_duration, - ); - - Ok((timestamp, slot)) - }, - spawner: &task_manager.spawn_essential_handle(), - can_author_with: sp_consensus::NeverCanAuthor, - registry: config.prometheus_registry(), - check_for_equivocation: Default::default(), - telemetry: telemetry.as_ref().map(|x| x.handle()), - })?; - - let warp_sync = Arc::new(sc_finality_grandpa::warp_proof::NetworkProvider::new( - backend.clone(), - grandpa_link.shared_authority_set().clone(), - Vec::default(), - )); - - let (network, system_rpc_tx, network_starter) = - 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, - on_demand: Some(on_demand.clone()), - block_announce_validator_builder: None, - warp_sync: Some(warp_sync), - })?; - - if config.offchain_worker.enabled { - sc_service::build_offchain_workers( - &config, - task_manager.spawn_handle(), - client.clone(), - network.clone(), - ); - } - - let enable_grandpa = !config.disable_grandpa; - if enable_grandpa { - let name = config.network.node_name.clone(); - - let config = sc_finality_grandpa::Config { - gossip_duration: std::time::Duration::from_millis(333), - justification_period: 512, - name: Some(name), - observer_enabled: false, - keystore: None, - local_role: config.role.clone(), - telemetry: telemetry.as_ref().map(|x| x.handle()), - }; - - task_manager.spawn_handle().spawn_blocking( - "grandpa-observer", - sc_finality_grandpa::run_grandpa_observer(config, grandpa_link, network.clone())?, - ); - } - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - remote_blockchain: Some(backend.remote_blockchain()), - transaction_pool, - task_manager: &mut task_manager, - on_demand: Some(on_demand), - rpc_extensions_builder: Box::new(|_, _| Ok(())), - config, - client, - keystore: keystore_container.sync_keystore(), - backend, - network, - system_rpc_tx, - telemetry: telemetry.as_mut(), - })?; - - network_starter.start_network(); - Ok(task_manager) -} diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index b5e36d9b53629..8499c66e0c9dc 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -418,7 +418,7 @@ pub fn local_testnet_config() -> ChainSpec { #[cfg(test)] pub(crate) mod tests { use super::*; - use crate::service::{new_full_base, new_light_base, NewFullBase}; + use crate::service::{new_full_base, NewFullBase}; use sc_service_test; use sp_runtime::BuildStorage; @@ -466,28 +466,16 @@ pub(crate) mod tests { fn test_connectivity() { sp_tracing::try_init_simple(); - sc_service_test::connectivity( - integration_test_config_with_two_authorities(), - |config| { - let NewFullBase { task_manager, client, network, transaction_pool, .. } = - new_full_base(config, |_, _| ())?; - Ok(sc_service_test::TestNetComponents::new( - task_manager, - client, - network, - transaction_pool, - )) - }, - |config| { - let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?; - Ok(sc_service_test::TestNetComponents::new( - keep_alive, - client, - network, - transaction_pool, - )) - }, - ); + sc_service_test::connectivity(integration_test_config_with_two_authorities(), |config| { + let NewFullBase { task_manager, client, network, transaction_pool, .. } = + new_full_base(config, |_, _| ())?; + Ok(sc_service_test::TestNetComponents::new( + task_manager, + client, + network, + transaction_pool, + )) + }); } #[test] diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 17375094f2a1b..dd8202eb71aac 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -19,7 +19,7 @@ use crate::{chain_spec, service, service::new_partial, Cli, Subcommand}; use node_executor::ExecutorDispatch; use node_runtime::{Block, RuntimeApi}; -use sc_cli::{ChainSpec, Result, Role, RuntimeVersion, SubstrateCli}; +use sc_cli::{ChainSpec, Result, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; impl SubstrateCli for Cli { @@ -77,11 +77,7 @@ pub fn run() -> Result<()> { None => { let runner = cli.create_runner(&cli.run)?; runner.run_node_until_exit(|config| async move { - match config.role { - Role::Light => service::new_light(config), - _ => service::new_full(config), - } - .map_err(sc_cli::Error::Service) + service::new_full(config).map_err(sc_cli::Error::Service) }) }, Some(Subcommand::Inspect(cmd)) => { diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 938f359368181..2220614ebaf2a 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -26,11 +26,11 @@ use futures::prelude::*; use node_executor::ExecutorDispatch; use node_primitives::Block; use node_runtime::RuntimeApi; -use sc_client_api::{BlockBackend, ExecutorProvider, RemoteBackend}; +use sc_client_api::{BlockBackend, ExecutorProvider}; use sc_consensus_babe::{self, SlotProportion}; use sc_executor::NativeElseWasmExecutor; use sc_network::{Event, NetworkService}; -use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager}; +use sc_service::{config::Configuration, error::Error as ServiceError, TaskManager}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sp_api::ProvideRuntimeApi; use sp_core::crypto::Pair; @@ -44,8 +44,7 @@ type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; type FullGrandpaBlockImport = grandpa::GrandpaBlockImport; -type LightClient = - sc_service::TLightClient>; + /// The transaction pool type defintion. pub type TransactionPool = sc_transaction_pool::FullPool; @@ -516,186 +515,9 @@ pub fn new_full(config: Configuration) -> Result { new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| task_manager) } -/// Creates a light service from the configuration. -pub fn new_light_base( - mut config: Configuration, -) -> Result< - ( - TaskManager, - RpcHandlers, - Arc, - Arc::Hash>>, - Arc< - sc_transaction_pool::LightPool>, - >, - ), - ServiceError, -> { - let telemetry = config - .telemetry_endpoints - .clone() - .filter(|x| !x.is_empty()) - .map(|endpoints| -> Result<_, sc_telemetry::Error> { - let worker = TelemetryWorker::new(16)?; - let telemetry = worker.handle().new_telemetry(endpoints); - Ok((worker, telemetry)) - }) - .transpose()?; - - let executor = NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - ); - - let (client, backend, keystore_container, mut task_manager, on_demand) = - sc_service::new_light_parts::( - &config, - telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), - executor, - )?; - - let mut telemetry = telemetry.map(|(worker, telemetry)| { - task_manager.spawn_handle().spawn("telemetry", worker.run()); - telemetry - }); - - config.network.extra_sets.push(grandpa::grandpa_peers_set_config()); - - let select_chain = sc_consensus::LongestChain::new(backend.clone()); - - let transaction_pool = Arc::new(sc_transaction_pool::BasicPool::new_light( - config.transaction_pool.clone(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), - on_demand.clone(), - )); - - let (grandpa_block_import, grandpa_link) = grandpa::block_import( - client.clone(), - &(client.clone() as Arc<_>), - select_chain.clone(), - telemetry.as_ref().map(|x| x.handle()), - )?; - let justification_import = grandpa_block_import.clone(); - - let (babe_block_import, babe_link) = sc_consensus_babe::block_import( - sc_consensus_babe::Config::get_or_compute(&*client)?, - grandpa_block_import, - client.clone(), - )?; - - let slot_duration = babe_link.config().slot_duration(); - let import_queue = sc_consensus_babe::import_queue( - babe_link, - babe_block_import, - Some(Box::new(justification_import)), - client.clone(), - select_chain, - move |_, ()| async move { - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration( - *timestamp, - slot_duration, - ); - - let uncles = - sp_authorship::InherentDataProvider::<::Header>::check_inherents(); - - Ok((timestamp, slot, uncles)) - }, - &task_manager.spawn_essential_handle(), - config.prometheus_registry(), - sp_consensus::NeverCanAuthor, - telemetry.as_ref().map(|x| x.handle()), - )?; - - let warp_sync = Arc::new(grandpa::warp_proof::NetworkProvider::new( - backend.clone(), - grandpa_link.shared_authority_set().clone(), - Vec::default(), - )); - - let (network, system_rpc_tx, network_starter) = - 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, - on_demand: Some(on_demand.clone()), - block_announce_validator_builder: None, - warp_sync: Some(warp_sync), - })?; - - let enable_grandpa = !config.disable_grandpa; - if enable_grandpa { - let name = config.network.node_name.clone(); - - let config = grandpa::Config { - gossip_duration: std::time::Duration::from_millis(333), - justification_period: 512, - name: Some(name), - observer_enabled: false, - keystore: None, - local_role: config.role.clone(), - telemetry: telemetry.as_ref().map(|x| x.handle()), - }; - - task_manager.spawn_handle().spawn_blocking( - "grandpa-observer", - grandpa::run_grandpa_observer(config, grandpa_link, network.clone())?, - ); - } - - if config.offchain_worker.enabled { - sc_service::build_offchain_workers( - &config, - task_manager.spawn_handle(), - client.clone(), - network.clone(), - ); - } - - let light_deps = node_rpc::LightDeps { - remote_blockchain: backend.remote_blockchain(), - fetcher: on_demand.clone(), - client: client.clone(), - pool: transaction_pool.clone(), - }; - - let rpc_extensions = node_rpc::create_light(light_deps); - - let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { - on_demand: Some(on_demand), - remote_blockchain: Some(backend.remote_blockchain()), - rpc_extensions_builder: Box::new(sc_service::NoopRpcExtensionBuilder(rpc_extensions)), - client: client.clone(), - transaction_pool: transaction_pool.clone(), - keystore: keystore_container.sync_keystore(), - config, - backend, - system_rpc_tx, - network: network.clone(), - task_manager: &mut task_manager, - telemetry: telemetry.as_mut(), - })?; - - network_starter.start_network(); - Ok((task_manager, rpc_handlers, client, network, transaction_pool)) -} - -/// Builds a new service for a light client. -pub fn new_light(config: Configuration) -> Result { - new_light_base(config).map(|(task_manager, _, _, _, _)| task_manager) -} - #[cfg(test)] mod tests { - use crate::service::{new_full_base, new_light_base, NewFullBase}; + use crate::service::{new_full_base, NewFullBase}; use codec::Encode; use node_primitives::{Block, DigestItem, Signature}; use node_runtime::{ @@ -771,15 +593,6 @@ mod tests { ); Ok((node, setup_handles.unwrap())) }, - |config| { - let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?; - Ok(sc_service_test::TestNetComponents::new( - keep_alive, - client, - network, - transaction_pool, - )) - }, |service, &mut (ref mut block_import, ref babe_link)| { let parent_id = BlockId::number(service.client().chain_info().best_number); let parent_header = service.client().header(&parent_id).unwrap().unwrap(); @@ -946,15 +759,6 @@ mod tests { transaction_pool, )) }, - |config| { - let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?; - Ok(sc_service_test::TestNetComponents::new( - keep_alive, - client, - network, - transaction_pool, - )) - }, vec!["//Alice".into(), "//Bob".into()], ) } diff --git a/bin/node/cli/tests/database_role_subdir_migration.rs b/bin/node/cli/tests/database_role_subdir_migration.rs deleted file mode 100644 index 9338d8a8e4f43..0000000000000 --- a/bin/node/cli/tests/database_role_subdir_migration.rs +++ /dev/null @@ -1,116 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use sc_client_db::{ - light::LightStorage, DatabaseSettings, DatabaseSource, KeepBlocks, PruningMode, - TransactionStorageMode, -}; -use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; -use tempfile::tempdir; - -pub mod common; - -#[tokio::test] -#[cfg(unix)] -async fn database_role_subdir_migration() { - type Block = RawBlock>; - - let base_path = tempdir().expect("could not create a temp dir"); - let path = base_path.path().join("chains/dev/db"); - // create a dummy database dir - { - let _old_db = LightStorage::::new(DatabaseSettings { - state_cache_size: 0, - state_cache_child_ratio: None, - state_pruning: PruningMode::ArchiveAll, - source: DatabaseSource::RocksDb { path: path.to_path_buf(), cache_size: 128 }, - keep_blocks: KeepBlocks::All, - transaction_storage: TransactionStorageMode::BlockBody, - }) - .unwrap(); - } - - assert!(path.join("db_version").exists()); - assert!(!path.join("light").exists()); - - // start a light client - common::run_node_for_a_while( - base_path.path(), - &[ - "--dev", - "--light", - "--port", - "30335", - "--rpc-port", - "44444", - "--ws-port", - "44445", - "--no-prometheus", - ], - ) - .await; - - // check if the database dir had been migrated - assert!(!path.join("db_version").exists()); - assert!(path.join("light/db_version").exists()); -} - -#[test] -#[cfg(unix)] -fn database_role_subdir_migration_fail_on_different_role() { - type Block = RawBlock>; - - let base_path = tempdir().expect("could not create a temp dir"); - let path = base_path.path().join("chains/dev/db"); - - // create a database with the old layout - { - let _old_db = LightStorage::::new(DatabaseSettings { - state_cache_size: 0, - state_cache_child_ratio: None, - state_pruning: PruningMode::ArchiveAll, - source: DatabaseSource::RocksDb { path: path.to_path_buf(), cache_size: 128 }, - keep_blocks: KeepBlocks::All, - transaction_storage: TransactionStorageMode::BlockBody, - }) - .unwrap(); - } - - assert!(path.join("db_version").exists()); - assert!(!path.join("light/db_version").exists()); - - // start a client with a different role (full), it should fail and not change any files on disk - common::run_node_assert_fail( - &base_path.path(), - &[ - "--dev", - "--port", - "30334", - "--rpc-port", - "44446", - "--ws-port", - "44447", - "--no-prometheus", - ], - ); - - // check if the files are unchanged - assert!(path.join("db_version").exists()); - assert!(!path.join("light/db_version").exists()); - assert!(!path.join("full/db_version").exists()); -} diff --git a/client/light/src/blockchain.rs b/client/light/src/blockchain.rs index e88c724193697..24d9ef4fd4b95 100644 --- a/client/light/src/blockchain.rs +++ b/client/light/src/blockchain.rs @@ -27,7 +27,7 @@ use sp_runtime::{ Justifications, }; -use crate::fetcher::RemoteHeaderRequest; +use sc_client_api::light::RemoteHeaderRequest; pub use sc_client_api::{ backend::{AuxStore, NewBlockState, ProvideChtRoots}, blockchain::{ diff --git a/client/light/src/fetcher.rs b/client/light/src/fetcher.rs deleted file mode 100644 index 5740e407a5e89..0000000000000 --- a/client/light/src/fetcher.rs +++ /dev/null @@ -1,366 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Light client data fetcher. Fetches requested data from remote full nodes. - -use std::{ - collections::{BTreeMap, HashMap}, - marker::PhantomData, - sync::Arc, -}; - -use codec::{Decode, Encode}; -use hash_db::{HashDB, Hasher, EMPTY_PREFIX}; -use sp_blockchain::{Error as ClientError, Result as ClientResult}; -use sp_core::{ - convert_hash, - storage::{ChildInfo, ChildType}, - traits::{CodeExecutor, SpawnNamed}, -}; -use sp_runtime::traits::{ - AtLeast32Bit, Block as BlockT, CheckedConversion, Hash, HashFor, Header as HeaderT, NumberFor, -}; -pub use sp_state_machine::StorageProof; -use sp_state_machine::{ - key_changes_proof_check_with_db, read_child_proof_check, read_proof_check, - ChangesTrieAnchorBlockId, ChangesTrieConfigurationRange, ChangesTrieRootsStorage, - InMemoryChangesTrieStorage, TrieBackend, -}; - -use crate::{blockchain::Blockchain, call_executor::check_execution_proof}; -pub use sc_client_api::{ - cht, - light::{ - ChangesProof, FetchChecker, Fetcher, RemoteBodyRequest, RemoteCallRequest, - RemoteChangesRequest, RemoteHeaderRequest, RemoteReadChildRequest, RemoteReadRequest, - Storage as BlockchainStorage, - }, -}; - -/// Remote data checker. -pub struct LightDataChecker> { - blockchain: Arc>, - executor: E, - spawn_handle: Box, - _marker: PhantomData, -} - -impl> LightDataChecker { - /// Create new light data checker. - pub fn new( - blockchain: Arc>, - executor: E, - spawn_handle: Box, - ) -> Self { - Self { blockchain, executor, spawn_handle, _marker: PhantomData } - } - - /// Check remote changes query proof assuming that CHT-s are of given size. - pub fn check_changes_proof_with_cht_size( - &self, - request: &RemoteChangesRequest, - remote_proof: ChangesProof, - cht_size: NumberFor, - ) -> ClientResult, u32)>> { - // since we need roots of all changes tries for the range begin..max - // => remote node can't use max block greater that one that we have passed - if remote_proof.max_block > request.max_block.0 || - remote_proof.max_block < request.last_block.0 - { - return Err(ClientError::ChangesTrieAccessFailed(format!( - "Invalid max_block used by the remote node: {}. Local: {}..{}..{}", - remote_proof.max_block, - request.first_block.0, - request.last_block.0, - request.max_block.0, - )) - .into()) - } - - // check if remote node has responded with extra changes trie roots proofs - // all changes tries roots must be in range [request.first_block.0; request.tries_roots.0) - let is_extra_first_root = remote_proof - .roots - .keys() - .next() - .map(|first_root| { - *first_root < request.first_block.0 || *first_root >= request.tries_roots.0 - }) - .unwrap_or(false); - let is_extra_last_root = remote_proof - .roots - .keys() - .next_back() - .map(|last_root| *last_root >= request.tries_roots.0) - .unwrap_or(false); - if is_extra_first_root || is_extra_last_root { - return Err(ClientError::ChangesTrieAccessFailed(format!( - "Extra changes tries roots proofs provided by the remote node: [{:?}..{:?}]. Expected in range: [{}; {})", - remote_proof.roots.keys().next(), remote_proof.roots.keys().next_back(), - request.first_block.0, request.tries_roots.0, - )).into()); - } - - // if request has been composed when some required headers were already pruned - // => remote node has sent us CHT-based proof of required changes tries roots - // => check that this proof is correct before proceeding with changes proof - let remote_max_block = remote_proof.max_block; - let remote_roots = remote_proof.roots; - let remote_roots_proof = remote_proof.roots_proof; - let remote_proof = remote_proof.proof; - if !remote_roots.is_empty() { - self.check_changes_tries_proof(cht_size, &remote_roots, remote_roots_proof)?; - } - - // and now check the key changes proof + get the changes - let mut result = Vec::new(); - let proof_storage = InMemoryChangesTrieStorage::with_proof(remote_proof); - for config_range in &request.changes_trie_configs { - let result_range = key_changes_proof_check_with_db::, _>( - ChangesTrieConfigurationRange { - config: config_range - .config - .as_ref() - .ok_or(ClientError::ChangesTriesNotSupported)?, - zero: config_range.zero.0, - end: config_range.end.map(|(n, _)| n), - }, - &RootsStorage { - roots: (request.tries_roots.0, &request.tries_roots.2), - prev_roots: &remote_roots, - }, - &proof_storage, - request.first_block.0, - &ChangesTrieAnchorBlockId { - hash: convert_hash(&request.last_block.1), - number: request.last_block.0, - }, - remote_max_block, - request.storage_key.as_ref(), - &request.key, - ) - .map_err(|err| ClientError::ChangesTrieAccessFailed(err))?; - result.extend(result_range); - } - - Ok(result) - } - - /// Check CHT-based proof for changes tries roots. - pub fn check_changes_tries_proof( - &self, - cht_size: NumberFor, - remote_roots: &BTreeMap, B::Hash>, - remote_roots_proof: StorageProof, - ) -> ClientResult<()> { - // all the checks are sharing the same storage - let storage = remote_roots_proof.into_memory_db(); - - // remote_roots.keys() are sorted => we can use this to group changes tries roots - // that are belongs to the same CHT - let blocks = remote_roots.keys().cloned(); - cht::for_each_cht_group::( - cht_size, - blocks, - |mut storage, _, cht_blocks| { - // get local changes trie CHT root for given CHT - // it should be there, because it is never pruned AND request has been composed - // when required header has been pruned (=> replaced with CHT) - let first_block = cht_blocks - .first() - .cloned() - .expect("for_each_cht_group never calls callback with empty groups"); - let local_cht_root = self - .blockchain - .storage() - .changes_trie_cht_root(cht_size, first_block)? - .ok_or(ClientError::InvalidCHTProof)?; - - // check changes trie root for every block within CHT range - for block in cht_blocks { - // check if the proofs storage contains the root - // normally this happens in when the proving backend is created, but since - // we share the storage for multiple checks, do it here - if !storage.contains(&local_cht_root, EMPTY_PREFIX) { - return Err(ClientError::InvalidCHTProof.into()) - } - - // check proof for single changes trie root - let proving_backend = TrieBackend::new(storage, local_cht_root); - let remote_changes_trie_root = remote_roots[&block]; - cht::check_proof_on_proving_backend::>( - local_cht_root, - block, - remote_changes_trie_root, - &proving_backend, - )?; - - // and return the storage to use in following checks - storage = proving_backend.into_storage(); - } - - Ok(storage) - }, - storage, - ) - } -} - -impl FetchChecker for LightDataChecker -where - Block: BlockT, - E: CodeExecutor + Clone + 'static, - S: BlockchainStorage, -{ - fn check_header_proof( - &self, - request: &RemoteHeaderRequest, - remote_header: Option, - remote_proof: StorageProof, - ) -> ClientResult { - let remote_header = - remote_header.ok_or_else(|| ClientError::from(ClientError::InvalidCHTProof))?; - let remote_header_hash = remote_header.hash(); - cht::check_proof::>( - request.cht_root, - request.block, - remote_header_hash, - remote_proof, - ) - .map(|_| remote_header) - } - - fn check_read_proof( - &self, - request: &RemoteReadRequest, - remote_proof: StorageProof, - ) -> ClientResult, Option>>> { - read_proof_check::, _>( - convert_hash(request.header.state_root()), - remote_proof, - request.keys.iter(), - ) - .map_err(|e| ClientError::from(e)) - } - - fn check_read_child_proof( - &self, - request: &RemoteReadChildRequest, - remote_proof: StorageProof, - ) -> ClientResult, Option>>> { - let child_info = match ChildType::from_prefixed_key(&request.storage_key) { - Some((ChildType::ParentKeyId, storage_key)) => ChildInfo::new_default(storage_key), - None => return Err(ClientError::InvalidChildType), - }; - read_child_proof_check::, _>( - convert_hash(request.header.state_root()), - remote_proof, - &child_info, - request.keys.iter(), - ) - .map_err(|e| ClientError::from(e)) - } - - fn check_execution_proof( - &self, - request: &RemoteCallRequest, - remote_proof: StorageProof, - ) -> ClientResult> { - check_execution_proof::<_, _, HashFor>( - &self.executor, - self.spawn_handle.clone(), - request, - remote_proof, - ) - } - - fn check_changes_proof( - &self, - request: &RemoteChangesRequest, - remote_proof: ChangesProof, - ) -> ClientResult, u32)>> { - self.check_changes_proof_with_cht_size(request, remote_proof, cht::size()) - } - - fn check_body_proof( - &self, - request: &RemoteBodyRequest, - body: Vec, - ) -> ClientResult> { - // TODO: #2621 - let extrinsics_root = - HashFor::::ordered_trie_root(body.iter().map(Encode::encode).collect()); - if *request.header.extrinsics_root() == extrinsics_root { - Ok(body) - } else { - Err(ClientError::ExtrinsicRootInvalid { - received: request.header.extrinsics_root().to_string(), - expected: extrinsics_root.to_string(), - }) - } - } -} - -/// A view of BTreeMap as a changes trie roots storage. -struct RootsStorage<'a, Number: AtLeast32Bit, Hash: 'a> { - roots: (Number, &'a [Hash]), - prev_roots: &'a BTreeMap, -} - -impl<'a, H, Number, Hash> ChangesTrieRootsStorage for RootsStorage<'a, Number, Hash> -where - H: Hasher, - Number: std::fmt::Display - + std::hash::Hash - + Clone - + AtLeast32Bit - + Encode - + Decode - + Send - + Sync - + 'static, - Hash: 'a + Send + Sync + Clone + AsRef<[u8]>, -{ - fn build_anchor( - &self, - _hash: H::Out, - ) -> Result, String> { - Err("build_anchor is only called when building block".into()) - } - - fn root( - &self, - _anchor: &ChangesTrieAnchorBlockId, - block: Number, - ) -> Result, String> { - // we can't ask for roots from parallel forks here => ignore anchor - let root = if block < self.roots.0 { - self.prev_roots.get(&Number::unique_saturated_from(block)).cloned() - } else { - let index: Option = - block.checked_sub(&self.roots.0).and_then(|index| index.checked_into()); - index.and_then(|index| self.roots.1.get(index as usize).cloned()) - }; - - Ok(root.map(|root| { - let mut hasher_root: H::Out = Default::default(); - hasher_root.as_mut().copy_from_slice(root.as_ref()); - hasher_root - })) - } -} diff --git a/client/light/src/lib.rs b/client/light/src/lib.rs index 0c874326ef2e0..4b084cda0f8b1 100644 --- a/client/light/src/lib.rs +++ b/client/light/src/lib.rs @@ -18,36 +18,18 @@ //! Light client components. -use sp_core::traits::{CodeExecutor, SpawnNamed}; use sp_runtime::traits::{Block as BlockT, HashFor}; use std::sync::Arc; pub mod backend; pub mod blockchain; pub mod call_executor; -pub mod fetcher; pub use backend::*; pub use blockchain::*; pub use call_executor::*; -pub use fetcher::*; - -/// Create an instance of fetch data checker. -pub fn new_fetch_checker>( - blockchain: Arc>, - executor: E, - spawn_handle: Box, -) -> LightDataChecker -where - E: CodeExecutor, -{ - LightDataChecker::new(blockchain, executor, spawn_handle) -} -/// Create an instance of light client blockchain backend. -pub fn new_light_blockchain>(storage: S) -> Arc> { - Arc::new(Blockchain::new(storage)) -} +use sc_client_api::light::Storage as BlockchainStorage; /// Create an instance of light client backend. pub fn new_light_backend(blockchain: Arc>) -> Arc>> diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index 80eccc2c97deb..bacf39124abc1 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -19,7 +19,6 @@ //! Substrate state API. mod state_full; -mod state_light; #[cfg(test)] mod tests; @@ -29,7 +28,6 @@ use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, Subscripti use rpc::Result as RpcResult; use std::sync::Arc; -use sc_client_api::light::{Fetcher, RemoteBlockchain}; use sc_rpc_api::{state::ReadProof, DenyUnsafe}; use sp_core::{ storage::{PrefixedStorageKey, StorageChangeSet, StorageData, StorageKey}, @@ -217,45 +215,6 @@ where (State { backend, deny_unsafe }, ChildState { backend: child_backend }) } -/// Create new state API that works on light node. -pub fn new_light>( - client: Arc, - subscriptions: SubscriptionManager, - remote_blockchain: Arc>, - fetcher: Arc, - deny_unsafe: DenyUnsafe, -) -> (State, ChildState) -where - Block: BlockT + 'static, - Block::Hash: Unpin, - BE: Backend + 'static, - Client: ExecutorProvider - + StorageProvider - + HeaderMetadata - + ProvideRuntimeApi - + HeaderBackend - + BlockchainEvents - + Send - + Sync - + 'static, - F: Send + Sync + 'static, -{ - let child_backend = Box::new(self::state_light::LightState::new( - client.clone(), - subscriptions.clone(), - remote_blockchain.clone(), - fetcher.clone(), - )); - - let backend = Box::new(self::state_light::LightState::new( - client, - subscriptions, - remote_blockchain, - fetcher, - )); - (State { backend, deny_unsafe }, ChildState { backend: child_backend }) -} - /// State API with subscriptions support. pub struct State { backend: Box>, diff --git a/client/rpc/src/state/state_light.rs b/client/rpc/src/state/state_light.rs deleted file mode 100644 index 749e57c365cc0..0000000000000 --- a/client/rpc/src/state/state_light.rs +++ /dev/null @@ -1,873 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! State API backend for light nodes. - -use codec::Decode; -use futures::{ - channel::oneshot::{channel, Sender}, - future::{ready, Either}, - Future, FutureExt, SinkExt, Stream, StreamExt as _, TryFutureExt, TryStreamExt as _, -}; -use hash_db::Hasher; -use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; -use log::warn; -use parking_lot::Mutex; -use rpc::Result as RpcResult; -use std::{ - collections::{hash_map::Entry, HashMap, HashSet}, - sync::Arc, -}; - -use sc_client_api::{ - light::{ - future_header, Fetcher, RemoteBlockchain, RemoteCallRequest, RemoteReadChildRequest, - RemoteReadRequest, - }, - BlockchainEvents, -}; -use sc_rpc_api::state::ReadProof; -use sp_blockchain::{Error as ClientError, HeaderBackend}; -use sp_core::{ - storage::{PrefixedStorageKey, StorageChangeSet, StorageData, StorageKey}, - Bytes, OpaqueMetadata, -}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, HashFor}, -}; -use sp_version::RuntimeVersion; - -use super::{ - client_err, - error::{Error, FutureResult}, - ChildStateBackend, StateBackend, -}; - -/// Storage data map of storage keys => (optional) storage value. -type StorageMap = HashMap>; - -/// State API backend for light nodes. -#[derive(Clone)] -pub struct LightState, Client> { - client: Arc, - subscriptions: SubscriptionManager, - version_subscriptions: SimpleSubscriptions, - storage_subscriptions: Arc>>, - remote_blockchain: Arc>, - fetcher: Arc, -} - -/// Shared requests container. -trait SharedRequests: Clone + Send + Sync { - /// Tries to listen for already issued request, or issues request. - /// - /// Returns true if requests has been issued. - fn listen_request(&self, block: Hash, sender: Sender>) -> bool; - - /// Returns (and forgets) all listeners for given request. - fn on_response_received(&self, block: Hash) -> Vec>>; -} - -/// Storage subscriptions data. -struct StorageSubscriptions { - /// Active storage requests. - active_requests: HashMap>>>, - /// Map of subscription => keys that this subscription watch for. - keys_by_subscription: HashMap>, - /// Map of key => set of subscriptions that watch this key. - subscriptions_by_key: HashMap>, -} - -impl SharedRequests - for Arc>> -{ - fn listen_request(&self, block: Block::Hash, sender: Sender>) -> bool { - let mut subscriptions = self.lock(); - let active_requests_at = subscriptions.active_requests.entry(block).or_default(); - active_requests_at.push(sender); - active_requests_at.len() == 1 - } - - fn on_response_received(&self, block: Block::Hash) -> Vec>> { - self.lock().active_requests.remove(&block).unwrap_or_default() - } -} - -/// Simple, maybe shared, subscription data that shares per block requests. -type SimpleSubscriptions = Arc>>>>>; - -impl SharedRequests for SimpleSubscriptions -where - Hash: Send + Eq + std::hash::Hash, - V: Send, -{ - fn listen_request(&self, block: Hash, sender: Sender>) -> bool { - let mut subscriptions = self.lock(); - let active_requests_at = subscriptions.entry(block).or_default(); - active_requests_at.push(sender); - active_requests_at.len() == 1 - } - - fn on_response_received(&self, block: Hash) -> Vec>> { - self.lock().remove(&block).unwrap_or_default() - } -} - -impl + 'static, Client> LightState -where - Block: BlockT, - Client: HeaderBackend + Send + Sync + 'static, -{ - /// Create new state API backend for light nodes. - pub fn new( - client: Arc, - subscriptions: SubscriptionManager, - remote_blockchain: Arc>, - fetcher: Arc, - ) -> Self { - Self { - client, - subscriptions, - version_subscriptions: Arc::new(Mutex::new(HashMap::new())), - storage_subscriptions: Arc::new(Mutex::new(StorageSubscriptions { - active_requests: HashMap::new(), - keys_by_subscription: HashMap::new(), - subscriptions_by_key: HashMap::new(), - })), - remote_blockchain, - fetcher, - } - } - - /// Returns given block hash or best block hash if None is passed. - fn block_or_best(&self, hash: Option) -> Block::Hash { - hash.unwrap_or_else(|| self.client.info().best_hash) - } -} - -impl StateBackend for LightState -where - Block: BlockT, - Block::Hash: Unpin, - Client: BlockchainEvents + HeaderBackend + Send + Sync + 'static, - F: Fetcher + 'static, -{ - fn call( - &self, - block: Option, - method: String, - call_data: Bytes, - ) -> FutureResult { - call( - &*self.remote_blockchain, - self.fetcher.clone(), - self.block_or_best(block), - method, - call_data, - ) - .boxed() - } - - fn storage_keys( - &self, - _block: Option, - _prefix: StorageKey, - ) -> FutureResult> { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } - - fn storage_pairs( - &self, - _block: Option, - _prefix: StorageKey, - ) -> FutureResult> { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } - - fn storage_keys_paged( - &self, - _block: Option, - _prefix: Option, - _count: u32, - _start_key: Option, - ) -> FutureResult> { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } - - fn storage_size(&self, _: Option, _: StorageKey) -> FutureResult> { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } - - fn storage( - &self, - block: Option, - key: StorageKey, - ) -> FutureResult> { - storage( - &*self.remote_blockchain, - self.fetcher.clone(), - self.block_or_best(block), - vec![key.0.clone()], - ) - .map_ok(move |mut values| { - values - .remove(&key) - .expect("successful request has entries for all requested keys; qed") - }) - .boxed() - } - - fn storage_hash( - &self, - block: Option, - key: StorageKey, - ) -> FutureResult> { - let res = StateBackend::storage(self, block, key); - async move { res.await.map(|r| r.map(|s| HashFor::::hash(&s.0))) }.boxed() - } - - fn metadata(&self, block: Option) -> FutureResult { - self.call(block, "Metadata_metadata".into(), Bytes(Vec::new())) - .and_then(|metadata| async move { - OpaqueMetadata::decode(&mut &metadata.0[..]) - .map(Into::into) - .map_err(|decode_err| { - client_err(ClientError::CallResultDecode( - "Unable to decode metadata", - decode_err, - )) - }) - }) - .boxed() - } - - fn runtime_version(&self, block: Option) -> FutureResult { - runtime_version(&*self.remote_blockchain, self.fetcher.clone(), self.block_or_best(block)) - .boxed() - } - - fn query_storage( - &self, - _from: Block::Hash, - _to: Option, - _keys: Vec, - ) -> FutureResult>> { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } - - fn query_storage_at( - &self, - _keys: Vec, - _at: Option, - ) -> FutureResult>> { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } - - fn read_proof( - &self, - _block: Option, - _keys: Vec, - ) -> FutureResult> { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } - - fn subscribe_storage( - &self, - _meta: crate::Metadata, - subscriber: Subscriber>, - keys: Option>, - ) { - let keys = match keys { - Some(keys) if !keys.is_empty() => keys, - _ => { - warn!("Cannot subscribe to all keys on light client. Subscription rejected."); - return - }, - }; - - let keys = keys.iter().cloned().collect::>(); - let keys_to_check = keys.iter().map(|k| k.0.clone()).collect::>(); - let subscription_id = self.subscriptions.add(subscriber, move |sink| { - let fetcher = self.fetcher.clone(); - let remote_blockchain = self.remote_blockchain.clone(); - let storage_subscriptions = self.storage_subscriptions.clone(); - let initial_block = self.block_or_best(None); - let initial_keys = keys_to_check.iter().cloned().collect::>(); - - let changes_stream = subscription_stream::( - storage_subscriptions.clone(), - self.client.import_notification_stream().map(|notification| notification.hash), - display_error( - storage(&*remote_blockchain, fetcher.clone(), initial_block, initial_keys) - .map(move |r| r.map(|r| (initial_block, r))), - ), - move |block| { - // there'll be single request per block for all active subscriptions - // with all subscribed keys - let keys = storage_subscriptions - .lock() - .subscriptions_by_key - .keys() - .map(|k| k.0.clone()) - .collect(); - - storage(&*remote_blockchain, fetcher.clone(), block, keys) - }, - move |block, old_value, new_value| { - // let's only select keys which are valid for this subscription - let new_value = new_value - .iter() - .filter(|(k, _)| keys_to_check.contains(&k.0)) - .map(|(k, v)| (k.clone(), v.clone())) - .collect::>(); - let value_differs = old_value - .as_ref() - .map(|old_value| **old_value != new_value) - .unwrap_or(true); - - value_differs.then(|| StorageChangeSet { - block, - changes: new_value.iter().map(|(k, v)| (k.clone(), v.clone())).collect(), - }) - }, - ); - - changes_stream - .map_ok(Ok) - .forward(sink.sink_map_err(|e| warn!("Error sending notifications: {:?}", e))) - // we ignore the resulting Stream (if the first stream is over we are unsubscribed) - .map(|_| ()) - }); - - // remember keys associated with this subscription - let mut storage_subscriptions = self.storage_subscriptions.lock(); - storage_subscriptions - .keys_by_subscription - .insert(subscription_id.clone(), keys.clone()); - for key in keys { - storage_subscriptions - .subscriptions_by_key - .entry(key) - .or_default() - .insert(subscription_id.clone()); - } - } - - fn unsubscribe_storage( - &self, - _meta: Option, - id: SubscriptionId, - ) -> RpcResult { - if !self.subscriptions.cancel(id.clone()) { - return Ok(false) - } - - // forget subscription keys - let mut storage_subscriptions = self.storage_subscriptions.lock(); - let keys = storage_subscriptions.keys_by_subscription.remove(&id); - for key in keys.into_iter().flat_map(|keys| keys.into_iter()) { - match storage_subscriptions.subscriptions_by_key.entry(key) { - Entry::Vacant(_) => unreachable!( - "every key from keys_by_subscription has\ - corresponding entry in subscriptions_by_key; qed" - ), - Entry::Occupied(mut entry) => { - entry.get_mut().remove(&id); - if entry.get().is_empty() { - entry.remove(); - } - }, - } - } - - Ok(true) - } - - fn subscribe_runtime_version( - &self, - _meta: crate::Metadata, - subscriber: Subscriber, - ) { - self.subscriptions.add(subscriber, move |sink| { - let fetcher = self.fetcher.clone(); - let remote_blockchain = self.remote_blockchain.clone(); - let version_subscriptions = self.version_subscriptions.clone(); - let initial_block = self.block_or_best(None); - - let versions_stream = subscription_stream::( - version_subscriptions, - self.client.import_notification_stream().map(|notification| notification.hash), - display_error( - runtime_version(&*remote_blockchain, fetcher.clone(), initial_block) - .map(move |r| r.map(|r| (initial_block, r))), - ), - move |block| runtime_version(&*remote_blockchain, fetcher.clone(), block), - |_, old_version, new_version| { - let version_differs = old_version - .as_ref() - .map(|old_version| *old_version != new_version) - .unwrap_or(true); - - version_differs.then(|| new_version.clone()) - }, - ); - - versions_stream - .map_ok(Ok) - .forward(sink.sink_map_err(|e| warn!("Error sending notifications: {:?}", e))) - // we ignore the resulting Stream (if the first stream is over we are unsubscribed) - .map(|_| ()) - }); - } - - fn unsubscribe_runtime_version( - &self, - _meta: Option, - id: SubscriptionId, - ) -> RpcResult { - Ok(self.subscriptions.cancel(id)) - } - - fn trace_block( - &self, - _block: Block::Hash, - _targets: Option, - _storage_keys: Option, - _methods: Option, - ) -> FutureResult { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } -} - -impl ChildStateBackend for LightState -where - Block: BlockT, - Client: BlockchainEvents + HeaderBackend + Send + Sync + 'static, - F: Fetcher + 'static, -{ - fn read_child_proof( - &self, - _block: Option, - _storage_key: PrefixedStorageKey, - _keys: Vec, - ) -> FutureResult> { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } - - fn storage_keys( - &self, - _block: Option, - _storage_key: PrefixedStorageKey, - _prefix: StorageKey, - ) -> FutureResult> { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } - - fn storage_keys_paged( - &self, - _block: Option, - _storage_key: PrefixedStorageKey, - _prefix: Option, - _count: u32, - _start_key: Option, - ) -> FutureResult> { - async move { Err(client_err(ClientError::NotAvailableOnLightClient)) }.boxed() - } - - fn storage( - &self, - block: Option, - storage_key: PrefixedStorageKey, - key: StorageKey, - ) -> FutureResult> { - let block = self.block_or_best(block); - let fetcher = self.fetcher.clone(); - let child_storage = - resolve_header(&*self.remote_blockchain, &*self.fetcher, block).then(move |result| { - match result { - Ok(header) => Either::Left( - fetcher - .remote_read_child(RemoteReadChildRequest { - block, - header, - storage_key, - keys: vec![key.0.clone()], - retry_count: Default::default(), - }) - .then(move |result| { - ready( - result - .map(|mut data| { - data.remove(&key.0) - .expect( - "successful result has entry for all keys; qed", - ) - .map(StorageData) - }) - .map_err(client_err), - ) - }), - ), - Err(error) => Either::Right(ready(Err(error))), - } - }); - - child_storage.boxed() - } - - fn storage_entries( - &self, - block: Option, - storage_key: PrefixedStorageKey, - keys: Vec, - ) -> FutureResult>> { - let block = self.block_or_best(block); - let fetcher = self.fetcher.clone(); - let keys = keys.iter().map(|k| k.0.clone()).collect::>(); - let child_storage = - resolve_header(&*self.remote_blockchain, &*self.fetcher, block).then(move |result| { - match result { - Ok(header) => Either::Left( - fetcher - .remote_read_child(RemoteReadChildRequest { - block, - header, - storage_key, - keys: keys.clone(), - retry_count: Default::default(), - }) - .then(move |result| { - ready( - result - .map(|data| { - data.iter() - .filter_map(|(k, d)| { - keys.contains(k).then(|| { - d.as_ref().map(|v| StorageData(v.to_vec())) - }) - }) - .collect::>() - }) - .map_err(client_err), - ) - }), - ), - Err(error) => Either::Right(ready(Err(error))), - } - }); - - child_storage.boxed() - } - - fn storage_hash( - &self, - block: Option, - storage_key: PrefixedStorageKey, - key: StorageKey, - ) -> FutureResult> { - let child_storage = ChildStateBackend::storage(self, block, storage_key, key); - - async move { child_storage.await.map(|r| r.map(|s| HashFor::::hash(&s.0))) }.boxed() - } -} - -/// Resolve header by hash. -fn resolve_header>( - remote_blockchain: &dyn RemoteBlockchain, - fetcher: &F, - block: Block::Hash, -) -> impl std::future::Future> { - let maybe_header = future_header(remote_blockchain, fetcher, BlockId::Hash(block)); - - maybe_header.then(move |result| { - ready( - result - .and_then(|maybe_header| { - maybe_header.ok_or_else(|| ClientError::UnknownBlock(format!("{}", block))) - }) - .map_err(client_err), - ) - }) -} - -/// Call runtime method at given block -fn call>( - remote_blockchain: &dyn RemoteBlockchain, - fetcher: Arc, - block: Block::Hash, - method: String, - call_data: Bytes, -) -> impl std::future::Future> { - resolve_header(remote_blockchain, &*fetcher, block).then(move |result| match result { - Ok(header) => Either::Left( - fetcher - .remote_call(RemoteCallRequest { - block, - header, - method, - call_data: call_data.0, - retry_count: Default::default(), - }) - .then(|result| ready(result.map(Bytes).map_err(client_err))), - ), - Err(error) => Either::Right(ready(Err(error))), - }) -} - -/// Get runtime version at given block. -fn runtime_version>( - remote_blockchain: &dyn RemoteBlockchain, - fetcher: Arc, - block: Block::Hash, -) -> impl std::future::Future> { - call(remote_blockchain, fetcher, block, "Core_version".into(), Bytes(Vec::new())).then( - |version| { - ready(version.and_then(|version| { - Decode::decode(&mut &version.0[..]) - .map_err(|e| client_err(ClientError::VersionInvalid(e.to_string()))) - })) - }, - ) -} - -/// Get storage value at given key at given block. -fn storage>( - remote_blockchain: &dyn RemoteBlockchain, - fetcher: Arc, - block: Block::Hash, - keys: Vec>, -) -> impl std::future::Future>, Error>> { - resolve_header(remote_blockchain, &*fetcher, block).then(move |result| match result { - Ok(header) => Either::Left( - fetcher - .remote_read(RemoteReadRequest { - block, - header, - keys, - retry_count: Default::default(), - }) - .then(|result| { - ready( - result - .map(|result| { - result - .into_iter() - .map(|(key, value)| (StorageKey(key), value.map(StorageData))) - .collect() - }) - .map_err(client_err), - ) - }), - ), - Err(error) => Either::Right(ready(Err(error))), - }) -} - -/// Returns subscription stream that issues request on every imported block and -/// if value has changed from previous block, emits (stream) item. -fn subscription_stream< - Block, - Requests, - FutureBlocksStream, - V, - N, - InitialRequestFuture, - IssueRequest, - IssueRequestFuture, - CompareValues, ->( - shared_requests: Requests, - future_blocks_stream: FutureBlocksStream, - initial_request: InitialRequestFuture, - issue_request: IssueRequest, - compare_values: CompareValues, -) -> impl Stream> -where - Block: BlockT, - Requests: 'static + SharedRequests, - FutureBlocksStream: Stream, - V: Send + 'static + Clone, - InitialRequestFuture: Future> + Send + 'static, - IssueRequest: 'static + Fn(Block::Hash) -> IssueRequestFuture, - IssueRequestFuture: Future> + Send + 'static, - CompareValues: Fn(Block::Hash, Option<&V>, &V) -> Option, -{ - // we need to send initial value first, then we'll only be sending if value has changed - let previous_value = Arc::new(Mutex::new(None)); - - // prepare 'stream' of initial values - let initial_value_stream = initial_request.into_stream(); - - // prepare stream of future values - // - // we do not want to stop stream if single request fails - // (the warning should have been already issued by the request issuer) - let future_values_stream = future_blocks_stream - .then(move |block| { - maybe_share_remote_request::( - shared_requests.clone(), - block, - &issue_request, - ) - .map(move |r| r.map(|v| (block, v))) - }) - .filter(|r| ready(r.is_ok())); - - // now let's return changed values for selected blocks - initial_value_stream - .chain(future_values_stream) - .try_filter_map(move |(block, new_value)| { - let mut previous_value = previous_value.lock(); - let res = compare_values(block, previous_value.as_ref(), &new_value).map( - |notification_value| { - *previous_value = Some(new_value); - notification_value - }, - ); - async move { Ok(res) } - }) - .map_err(|_| ()) -} - -/// Request some data from remote node, probably reusing response from already -/// (in-progress) existing request. -fn maybe_share_remote_request( - shared_requests: Requests, - block: Block::Hash, - issue_request: &IssueRequest, -) -> impl std::future::Future> -where - V: Clone, - Requests: SharedRequests, - IssueRequest: Fn(Block::Hash) -> IssueRequestFuture, - IssueRequestFuture: std::future::Future>, -{ - let (sender, receiver) = channel(); - let need_issue_request = shared_requests.listen_request(block, sender); - - // if that isn't the first request - just listen for existing request' response - if !need_issue_request { - return Either::Right(receiver.then(|r| ready(r.unwrap_or(Err(()))))) - } - - // that is the first request - issue remote request + notify all listeners on - // completion - Either::Left(display_error(issue_request(block)).then(move |remote_result| { - let listeners = shared_requests.on_response_received(block); - // skip first element, because this future is the first element - for receiver in listeners.into_iter().skip(1) { - if let Err(_) = receiver.send(remote_result.clone()) { - // we don't care if receiver has been dropped already - } - } - - ready(remote_result) - })) -} - -/// Convert successful future result into Ok(result) and error into Err(()), -/// displaying warning. -fn display_error(future: F) -> impl std::future::Future> -where - F: std::future::Future>, -{ - future.then(|result| { - ready(result.or_else(|err| { - warn!("Remote request for subscription data has failed with: {:?}", err); - Err(()) - })) - }) -} - -#[cfg(test)] -mod tests { - use super::*; - use futures::{executor, stream}; - use sp_core::H256; - use substrate_test_runtime_client::runtime::Block; - - #[test] - fn subscription_stream_works() { - let stream = subscription_stream::( - SimpleSubscriptions::default(), - stream::iter(vec![H256::from([2; 32]), H256::from([3; 32])]), - ready(Ok((H256::from([1; 32]), 100))), - |block| match block[0] { - 2 => ready(Ok(100)), - 3 => ready(Ok(200)), - _ => unreachable!("should not issue additional requests"), - }, - |_, old_value, new_value| match old_value == Some(new_value) { - true => None, - false => Some(new_value.clone()), - }, - ); - - assert_eq!(executor::block_on(stream.collect::>()), vec![Ok(100), Ok(200)]); - } - - #[test] - fn subscription_stream_ignores_failed_requests() { - let stream = subscription_stream::( - SimpleSubscriptions::default(), - stream::iter(vec![H256::from([2; 32]), H256::from([3; 32])]), - ready(Ok((H256::from([1; 32]), 100))), - |block| match block[0] { - 2 => ready(Err(client_err(ClientError::NotAvailableOnLightClient))), - 3 => ready(Ok(200)), - _ => unreachable!("should not issue additional requests"), - }, - |_, old_value, new_value| match old_value == Some(new_value) { - true => None, - false => Some(new_value.clone()), - }, - ); - - assert_eq!(executor::block_on(stream.collect::>()), vec![Ok(100), Ok(200)]); - } - - #[test] - fn maybe_share_remote_request_shares_request() { - type UnreachableFuture = futures::future::Ready>; - - let shared_requests = SimpleSubscriptions::default(); - - // let's 'issue' requests for B1 - shared_requests.lock().insert(H256::from([1; 32]), vec![channel().0]); - - // make sure that no additional requests are issued when we're asking for B1 - let _ = maybe_share_remote_request::( - shared_requests.clone(), - H256::from([1; 32]), - &|_| unreachable!("no duplicate requests issued"), - ); - - // make sure that additional requests is issued when we're asking for B2 - let request_issued = Arc::new(Mutex::new(false)); - let _ = maybe_share_remote_request::( - shared_requests.clone(), - H256::from([2; 32]), - &|_| { - *request_issued.lock() = true; - ready(Ok(Default::default())) - }, - ); - assert!(*request_issued.lock()); - } -} diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 589d7848a5b28..c3ae1452042f4 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -53,7 +53,6 @@ sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sp-storage = { version = "4.0.0-dev", path = "../../primitives/storage" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } -sc-light = { version = "4.0.0-dev", path = "../light" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../db" } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index e01a85878817c..bcb05ce743701 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -18,7 +18,7 @@ use crate::{ build_network_future, - client::{light, Client, ClientConfig}, + client::{Client, ClientConfig}, config::{Configuration, KeystoreConfig, PrometheusConfig, TransactionStorageMode}, error::Error, metrics::MetricsService, @@ -58,7 +58,7 @@ use sp_core::traits::{CodeExecutor, SpawnNamed}; use sp_keystore::{CryptoStore, SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, BlockIdTo, HashFor, Zero}, + traits::{Block as BlockT, BlockIdTo, Zero}, BuildStorage, }; use std::{str::FromStr, sync::Arc, time::SystemTime}; @@ -137,47 +137,9 @@ pub type TFullBackend = sc_client_db::Backend; pub type TFullCallExecutor = crate::client::LocalCallExecutor, TExec>; -/// Light client type. -pub type TLightClient = - TLightClientWithBackend>; - -/// Light client backend type. -pub type TLightBackend = - sc_light::Backend, HashFor>; - -/// Light call executor type. -pub type TLightCallExecutor = sc_light::GenesisCallExecutor< - sc_light::Backend, HashFor>, - crate::client::LocalCallExecutor< - TBl, - sc_light::Backend, HashFor>, - TExec, - >, ->; - type TFullParts = (TFullClient, Arc>, KeystoreContainer, TaskManager); -type TLightParts = ( - Arc>, - Arc>, - KeystoreContainer, - TaskManager, - Arc>, -); - -/// Light client backend type with a specific hash type. -pub type TLightBackendWithHash = - sc_light::Backend, THash>; - -/// Light client type with a specific backend. -pub type TLightClientWithBackend = Client< - TBackend, - sc_light::GenesisCallExecutor>, - TBl, - TRtApi, ->; - trait AsCryptoStoreRef { fn keystore_ref(&self) -> Arc; fn sync_keystore_ref(&self) -> Arc; @@ -359,53 +321,6 @@ where Ok((client, backend, keystore_container, task_manager)) } -/// Create the initial parts of a light node. -pub fn new_light_parts( - config: &Configuration, - telemetry: Option, - executor: TExec, -) -> Result, Error> -where - TBl: BlockT, - TExec: CodeExecutor + RuntimeVersionOf + Clone, -{ - let keystore_container = KeystoreContainer::new(&config.keystore)?; - let task_manager = { - let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry); - TaskManager::new(config.tokio_handle.clone(), registry)? - }; - - let db_storage = { - let db_settings = sc_client_db::DatabaseSettings { - state_cache_size: config.state_cache_size, - state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), - state_pruning: config.state_pruning.clone(), - source: config.database.clone(), - keep_blocks: config.keep_blocks.clone(), - transaction_storage: config.transaction_storage.clone(), - }; - sc_client_db::light::LightStorage::new(db_settings)? - }; - let light_blockchain = sc_light::new_light_blockchain(db_storage); - let fetch_checker = Arc::new(sc_light::new_fetch_checker::<_, TBl, _>( - light_blockchain.clone(), - executor.clone(), - Box::new(task_manager.spawn_handle()), - )); - let on_demand = Arc::new(sc_network::config::OnDemand::new(fetch_checker)); - let backend = sc_light::new_light_backend(light_blockchain); - let client = Arc::new(light::new_light( - backend.clone(), - config.chain_spec.as_storage_builder(), - executor, - Box::new(task_manager.spawn_handle()), - config.prometheus_config.as_ref().map(|config| config.registry.clone()), - telemetry, - )?); - - Ok((client, backend, keystore_container, task_manager, on_demand)) -} - /// Create an instance of default DB-backend backend. pub fn new_db_backend( settings: DatabaseSettings, @@ -559,12 +474,12 @@ where mut config, task_manager, client, - on_demand, + on_demand: _, backend, keystore, transaction_pool, rpc_extensions_builder, - remote_blockchain, + remote_blockchain: _, network, system_rpc_tx, telemetry, @@ -630,8 +545,6 @@ where client.clone(), transaction_pool.clone(), keystore.clone(), - on_demand.clone(), - remote_blockchain.clone(), &*rpc_extensions_builder, backend.offchain_storage(), system_rpc_tx.clone(), @@ -729,8 +642,6 @@ fn gen_handler( client: Arc, transaction_pool: Arc, keystore: SyncCryptoStorePtr, - on_demand: Option>>, - remote_blockchain: Option>>, rpc_extensions_builder: &(dyn RpcExtensionBuilder + Send), offchain_storage: Option<>::OffchainStorage>, system_rpc_tx: TracingUnboundedSender>, @@ -769,34 +680,17 @@ where let task_executor = sc_rpc::SubscriptionTaskExecutor::new(spawn_handle); let subscriptions = SubscriptionManager::new(Arc::new(task_executor.clone())); - let (chain, state, child_state) = - if let (Some(remote_blockchain), Some(on_demand)) = (remote_blockchain, on_demand) { - // Light clients - let chain = sc_rpc::chain::new_light( - client.clone(), - subscriptions.clone(), - remote_blockchain.clone(), - on_demand.clone(), - ); - let (state, child_state) = sc_rpc::state::new_light( - client.clone(), - subscriptions.clone(), - remote_blockchain.clone(), - on_demand, - deny_unsafe, - ); - (chain, state, child_state) - } else { - // Full nodes - let chain = sc_rpc::chain::new_full(client.clone(), subscriptions.clone()); - let (state, child_state) = sc_rpc::state::new_full( - client.clone(), - subscriptions.clone(), - deny_unsafe, - config.rpc_max_payload, - ); - (chain, state, child_state) - }; + let (chain, state, child_state) = { + // Full nodes + let chain = sc_rpc::chain::new_full(client.clone(), subscriptions.clone()); + let (state, child_state) = sc_rpc::state::new_full( + client.clone(), + subscriptions.clone(), + deny_unsafe, + config.rpc_max_payload, + ); + (chain, state, child_state) + }; let author = sc_rpc::author::Author::new(client, transaction_pool, subscriptions, keystore, deny_unsafe); diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index d35c0462b8b05..4e3cb0aaf234b 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -42,6 +42,7 @@ use sc_client_api::{ ProvideUncles, }, execution_extensions::ExecutionExtensions, + light::ChangesProof, notifications::{StorageEventStream, StorageNotifications}, CallExecutor, ExecutorProvider, KeyIterator, ProofProvider, UsageProvider, }; @@ -49,7 +50,6 @@ use sc_consensus::{ BlockCheckParams, BlockImportParams, ForkChoiceStrategy, ImportResult, StateAction, }; use sc_executor::RuntimeVersion; -use sc_light::fetcher::ChangesProof; use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sp_api::{ ApiExt, ApiRef, CallApiAt, CallApiAtParams, ConstructRuntimeApi, Core as CoreApi, diff --git a/client/service/src/client/light.rs b/client/service/src/client/light.rs deleted file mode 100644 index 7c13b98843e05..0000000000000 --- a/client/service/src/client/light.rs +++ /dev/null @@ -1,82 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Light client utilities. - -use std::sync::Arc; - -use prometheus_endpoint::Registry; -use sc_executor::RuntimeVersionOf; -use sc_telemetry::TelemetryHandle; -use sp_blockchain::Result as ClientResult; -use sp_core::traits::{CodeExecutor, SpawnNamed}; -use sp_runtime::{ - traits::{Block as BlockT, HashFor}, - BuildStorage, -}; - -use super::{ - call_executor::LocalCallExecutor, - client::{Client, ClientConfig}, -}; -use sc_client_api::light::Storage as BlockchainStorage; -use sc_light::{Backend, GenesisCallExecutor}; - -/// Create an instance of light client. -pub fn new_light( - backend: Arc>>, - genesis_storage: &dyn BuildStorage, - code_executor: E, - spawn_handle: Box, - prometheus_registry: Option, - telemetry: Option, -) -> ClientResult< - Client< - Backend>, - GenesisCallExecutor< - Backend>, - LocalCallExecutor>, E>, - >, - B, - RA, - >, -> -where - B: BlockT, - S: BlockchainStorage + 'static, - E: CodeExecutor + RuntimeVersionOf + Clone + 'static, -{ - let local_executor = LocalCallExecutor::new( - backend.clone(), - code_executor, - spawn_handle.clone(), - ClientConfig::default(), - )?; - let executor = GenesisCallExecutor::new(backend.clone(), local_executor); - Client::new( - backend, - executor, - genesis_storage, - Default::default(), - Default::default(), - Default::default(), - prometheus_registry, - telemetry, - ClientConfig::default(), - ) -} diff --git a/client/service/src/client/mod.rs b/client/service/src/client/mod.rs index 754309e864ebd..7743f479a1713 100644 --- a/client/service/src/client/mod.rs +++ b/client/service/src/client/mod.rs @@ -49,7 +49,6 @@ mod block_rules; mod call_executor; mod client; pub mod genesis; -pub mod light; mod wasm_override; mod wasm_substitutes; diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 8d8c54cc25f29..a1ff8da4085c9 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -49,10 +49,9 @@ use sp_runtime::{ pub use self::{ builder::{ build_network, build_offchain_workers, new_client, new_db_backend, new_full_client, - new_full_parts, new_light_parts, spawn_tasks, BuildNetworkParams, KeystoreContainer, - NetworkStarter, NoopRpcExtensionBuilder, RpcExtensionBuilder, SpawnTasksParams, - TFullBackend, TFullCallExecutor, TFullClient, TLightBackend, TLightBackendWithHash, - TLightCallExecutor, TLightClient, TLightClientWithBackend, + new_full_parts, spawn_tasks, BuildNetworkParams, KeystoreContainer, NetworkStarter, + NoopRpcExtensionBuilder, RpcExtensionBuilder, SpawnTasksParams, TFullBackend, + TFullCallExecutor, TFullClient, }, client::{ClientConfig, LocalCallExecutor}, error::Error, diff --git a/client/service/test/src/client/db.rs b/client/service/test/src/client/db.rs index 5278c9a13a4d7..772fdcada72ef 100644 --- a/client/service/test/src/client/db.rs +++ b/client/service/test/src/client/db.rs @@ -21,6 +21,7 @@ use std::sync::Arc; type TestBackend = sc_client_api::in_mem::Backend; + #[test] fn test_leaves_with_complex_block_tree() { let backend = Arc::new(TestBackend::new()); diff --git a/client/service/test/src/client/light.rs b/client/service/test/src/client/light.rs deleted file mode 100644 index fb9566d208f76..0000000000000 --- a/client/service/test/src/client/light.rs +++ /dev/null @@ -1,981 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::prepare_client_with_key_changes; -use parity_scale_codec::{Decode, Encode}; -use parking_lot::Mutex; -use sc_block_builder::BlockBuilderProvider; -use sc_client_api::{ - backend::NewBlockState, - blockchain::Info, - cht, - in_mem::{Backend as InMemBackend, Blockchain as InMemoryBlockchain}, - AuxStore, Backend as ClientBackend, BlockBackend, BlockImportOperation, CallExecutor, - ChangesProof, ExecutionStrategy, FetchChecker, ProofProvider, ProvideChtRoots, - RemoteBodyRequest, RemoteCallRequest, RemoteChangesRequest, RemoteHeaderRequest, - RemoteReadChildRequest, RemoteReadRequest, Storage, StorageProof, StorageProvider, -}; -use sc_executor::{NativeElseWasmExecutor, RuntimeVersion, WasmExecutionMethod}; -use sc_light::{ - backend::{Backend, GenesisOrUnavailableState}, - blockchain::{Blockchain, BlockchainCache}, - call_executor::{check_execution_proof, GenesisCallExecutor}, - fetcher::LightDataChecker, -}; -use sp_api::{ProofRecorder, StorageTransactionCache}; -use sp_blockchain::{ - well_known_cache_keys, BlockStatus, CachedHeaderMetadata, Error as ClientError, HeaderBackend, - Result as ClientResult, -}; -use sp_consensus::BlockOrigin; -use sp_core::{testing::TaskExecutor, NativeOrEncoded, H256}; -use sp_externalities::Extensions; -use sp_runtime::{ - generic::BlockId, - traits::{BlakeTwo256, Block as _, Header as HeaderT, NumberFor}, - Digest, Justifications, -}; -use sp_state_machine::{ExecutionManager, OverlayedChanges}; -use std::{cell::RefCell, collections::HashMap, panic::UnwindSafe, sync::Arc}; -use substrate_test_runtime_client::{ - runtime::{self, Block, Extrinsic, Hash, Header}, - AccountKeyring, ClientBlockImportExt, TestClient, -}; - -use sp_core::{ - blake2_256, - storage::{well_known_keys, ChildInfo, StorageKey}, - ChangesTrieConfiguration, -}; -use sp_state_machine::Backend as _; - -pub type DummyBlockchain = Blockchain; - -pub struct DummyStorage { - pub changes_tries_cht_roots: HashMap, - pub aux_store: Mutex, Vec>>, -} - -impl DummyStorage { - pub fn new() -> Self { - DummyStorage { - changes_tries_cht_roots: HashMap::new(), - aux_store: Mutex::new(HashMap::new()), - } - } -} - -impl sp_blockchain::HeaderBackend for DummyStorage { - fn header(&self, _id: BlockId) -> ClientResult> { - Err(ClientError::Backend("Test error".into())) - } - - fn info(&self) -> Info { - panic!("Test error") - } - - fn status(&self, _id: BlockId) -> ClientResult { - Err(ClientError::Backend("Test error".into())) - } - - fn number(&self, hash: Hash) -> ClientResult>> { - if hash == Default::default() { - Ok(Some(Default::default())) - } else { - Err(ClientError::Backend("Test error".into())) - } - } - - fn hash(&self, number: u64) -> ClientResult> { - if number == 0 { - Ok(Some(Default::default())) - } else { - Err(ClientError::Backend("Test error".into())) - } - } -} - -impl sp_blockchain::HeaderMetadata for DummyStorage { - type Error = ClientError; - - fn header_metadata(&self, hash: Hash) -> Result, Self::Error> { - self.header(BlockId::hash(hash))? - .map(|header| CachedHeaderMetadata::from(&header)) - .ok_or(ClientError::UnknownBlock("header not found".to_owned())) - } - fn insert_header_metadata(&self, _hash: Hash, _metadata: CachedHeaderMetadata) {} - fn remove_header_metadata(&self, _hash: Hash) {} -} - -impl AuxStore for DummyStorage { - fn insert_aux< - 'a, - 'b: 'a, - 'c: 'a, - I: IntoIterator, - D: IntoIterator, - >( - &self, - insert: I, - _delete: D, - ) -> ClientResult<()> { - for (k, v) in insert.into_iter() { - self.aux_store.lock().insert(k.to_vec(), v.to_vec()); - } - Ok(()) - } - - fn get_aux(&self, key: &[u8]) -> ClientResult>> { - Ok(self.aux_store.lock().get(key).cloned()) - } -} - -impl Storage for DummyStorage { - fn import_header( - &self, - _header: Header, - _cache: HashMap>, - _state: NewBlockState, - _aux_ops: Vec<(Vec, Option>)>, - ) -> ClientResult<()> { - Ok(()) - } - - fn set_head(&self, _block: BlockId) -> ClientResult<()> { - Err(ClientError::Backend("Test error".into())) - } - - fn finalize_header(&self, _block: BlockId) -> ClientResult<()> { - Err(ClientError::Backend("Test error".into())) - } - - fn last_finalized(&self) -> ClientResult { - Err(ClientError::Backend("Test error".into())) - } - - fn cache(&self) -> Option>> { - None - } - - fn usage_info(&self) -> Option { - None - } -} - -impl ProvideChtRoots for DummyStorage { - fn header_cht_root(&self, _cht_size: u64, _block: u64) -> ClientResult> { - Err(ClientError::Backend("Test error".into())) - } - - fn changes_trie_cht_root(&self, cht_size: u64, block: u64) -> ClientResult> { - cht::block_to_cht_number(cht_size, block) - .and_then(|cht_num| self.changes_tries_cht_roots.get(&cht_num)) - .cloned() - .ok_or_else(|| { - ClientError::Backend(format!("Test error: CHT for block #{} not found", block)) - .into() - }) - .map(Some) - } -} - -struct DummyCallExecutor; - -impl CallExecutor for DummyCallExecutor { - type Error = ClientError; - - type Backend = substrate_test_runtime_client::Backend; - - fn call( - &self, - _id: &BlockId, - _method: &str, - _call_data: &[u8], - _strategy: ExecutionStrategy, - _extensions: Option, - ) -> Result, ClientError> { - Ok(vec![42]) - } - - fn contextual_call< - EM: Fn( - Result, Self::Error>, - Result, Self::Error>, - ) -> Result, Self::Error>, - R: Encode + Decode + PartialEq, - NC: FnOnce() -> Result + UnwindSafe, - >( - &self, - _at: &BlockId, - _method: &str, - _call_data: &[u8], - _changes: &RefCell, - _storage_transaction_cache: Option< - &RefCell< - StorageTransactionCache< - Block, - >::State, - >, - >, - >, - _execution_manager: ExecutionManager, - _native_call: Option, - _proof_recorder: &Option>, - _extensions: Option, - ) -> ClientResult> - where - ExecutionManager: Clone, - { - unreachable!() - } - - fn runtime_version(&self, _id: &BlockId) -> Result { - unreachable!() - } - - fn prove_execution( - &self, - _: &BlockId, - _: &str, - _: &[u8], - ) -> Result<(Vec, StorageProof), ClientError> { - unreachable!() - } -} - -fn local_executor() -> NativeElseWasmExecutor -{ - NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8) -} - -#[test] -fn local_state_is_created_when_genesis_state_is_available() { - let def = Default::default(); - let header0 = - substrate_test_runtime_client::runtime::Header::new(0, def, def, def, Default::default()); - - let backend: Backend<_, BlakeTwo256> = - Backend::new(Arc::new(DummyBlockchain::new(DummyStorage::new()))); - let mut op = backend.begin_operation().unwrap(); - op.set_block_data(header0, None, None, None, NewBlockState::Final).unwrap(); - op.set_genesis_state(Default::default(), true).unwrap(); - backend.commit_operation(op).unwrap(); - - match backend.state_at(BlockId::Number(0)).unwrap() { - GenesisOrUnavailableState::Genesis(_) => (), - _ => panic!("unexpected state"), - } -} - -#[test] -fn unavailable_state_is_created_when_genesis_state_is_unavailable() { - let backend: Backend<_, BlakeTwo256> = - Backend::new(Arc::new(DummyBlockchain::new(DummyStorage::new()))); - - match backend.state_at(BlockId::Number(0)).unwrap() { - GenesisOrUnavailableState::Unavailable => (), - _ => panic!("unexpected state"), - } -} - -#[test] -fn light_aux_store_is_updated_via_non_importing_op() { - let backend = Backend::new(Arc::new(DummyBlockchain::new(DummyStorage::new()))); - let mut op = ClientBackend::::begin_operation(&backend).unwrap(); - BlockImportOperation::::insert_aux(&mut op, vec![(vec![1], Some(vec![2]))]).unwrap(); - ClientBackend::::commit_operation(&backend, op).unwrap(); - - assert_eq!(AuxStore::get_aux(&backend, &[1]).unwrap(), Some(vec![2])); -} - -#[test] -fn execution_proof_is_generated_and_checked() { - fn execute(remote_client: &TestClient, at: u64, method: &'static str) -> (Vec, Vec) { - let remote_block_id = BlockId::Number(at); - let remote_header = remote_client.header(&remote_block_id).unwrap().unwrap(); - - // 'fetch' execution proof from remote node - let (remote_result, remote_execution_proof) = - remote_client.execution_proof(&remote_block_id, method, &[]).unwrap(); - - // check remote execution proof locally - let local_result = check_execution_proof::<_, _, BlakeTwo256>( - &local_executor(), - Box::new(TaskExecutor::new()), - &RemoteCallRequest { - block: substrate_test_runtime_client::runtime::Hash::default(), - header: remote_header, - method: method.into(), - call_data: vec![], - retry_count: None, - }, - remote_execution_proof, - ) - .unwrap(); - - (remote_result, local_result) - } - - fn execute_with_proof_failure(remote_client: &TestClient, at: u64) { - let remote_block_id = BlockId::Number(at); - let remote_header = remote_client.header(&remote_block_id).unwrap().unwrap(); - - // 'fetch' execution proof from remote node - let (_, remote_execution_proof) = remote_client - .execution_proof( - &remote_block_id, - "Core_initialize_block", - &Header::new( - at, - Default::default(), - Default::default(), - Default::default(), - Default::default(), - ) - .encode(), - ) - .unwrap(); - - // check remote execution proof locally - let execution_result = check_execution_proof::<_, _, BlakeTwo256>( - &local_executor(), - Box::new(TaskExecutor::new()), - &RemoteCallRequest { - block: substrate_test_runtime_client::runtime::Hash::default(), - header: remote_header.clone(), - method: "Core_initialize_block".into(), - call_data: Header::new( - at + 1, - Default::default(), - Default::default(), - remote_header.hash(), - remote_header.digest().clone(), // this makes next header wrong - ) - .encode(), - retry_count: None, - }, - remote_execution_proof, - ); - match execution_result { - Err(sp_blockchain::Error::Execution(_)) => (), - _ => panic!("Unexpected execution result: {:?}", execution_result), - } - } - - // prepare remote client - let mut remote_client = substrate_test_runtime_client::new(); - for i in 1u32..3u32 { - let mut digest = Digest::default(); - digest.push(sp_runtime::generic::DigestItem::Other::(i.to_le_bytes().to_vec())); - futures::executor::block_on(remote_client.import_justified( - BlockOrigin::Own, - remote_client.new_block(digest).unwrap().build().unwrap().block, - Justifications::from((*b"TEST", Default::default())), - )) - .unwrap(); - } - - // check method that doesn't requires environment - let (remote, local) = execute(&remote_client, 0, "Core_version"); - assert_eq!(remote, local); - - let (remote, local) = execute(&remote_client, 2, "Core_version"); - assert_eq!(remote, local); - - // check that proof check doesn't panic even if proof is incorrect AND no panic handler is set - execute_with_proof_failure(&remote_client, 2); - - // check that proof check doesn't panic even if proof is incorrect AND panic handler is set - sp_panic_handler::set("TEST", "1.2.3"); - execute_with_proof_failure(&remote_client, 2); -} - -#[test] -fn code_is_executed_at_genesis_only() { - let backend = Arc::new(InMemBackend::::new()); - let def = H256::default(); - let header0 = - substrate_test_runtime_client::runtime::Header::new(0, def, def, def, Default::default()); - let hash0 = header0.hash(); - let header1 = - substrate_test_runtime_client::runtime::Header::new(1, def, def, hash0, Default::default()); - let hash1 = header1.hash(); - backend - .blockchain() - .insert(hash0, header0, None, None, NewBlockState::Final) - .unwrap(); - backend - .blockchain() - .insert(hash1, header1, None, None, NewBlockState::Final) - .unwrap(); - - let genesis_executor = GenesisCallExecutor::new(backend, DummyCallExecutor); - assert_eq!( - genesis_executor - .call(&BlockId::Number(0), "test_method", &[], ExecutionStrategy::NativeElseWasm, None,) - .unwrap(), - vec![42], - ); - - let call_on_unavailable = genesis_executor.call( - &BlockId::Number(1), - "test_method", - &[], - ExecutionStrategy::NativeElseWasm, - None, - ); - - match call_on_unavailable { - Err(ClientError::NotAvailableOnLightClient) => (), - _ => unreachable!("unexpected result: {:?}", call_on_unavailable), - } -} - -type TestChecker = LightDataChecker< - NativeElseWasmExecutor, - Block, - DummyStorage, ->; - -fn prepare_for_read_proof_check() -> (TestChecker, Header, StorageProof, u32) { - // prepare remote client - let remote_client = substrate_test_runtime_client::new(); - let remote_block_id = BlockId::Number(0); - let remote_block_hash = remote_client.block_hash(0).unwrap().unwrap(); - let mut remote_block_header = remote_client.header(&remote_block_id).unwrap().unwrap(); - remote_block_header.state_root = remote_client - .state_at(&remote_block_id) - .unwrap() - .storage_root(::std::iter::empty()) - .0 - .into(); - - // 'fetch' read proof from remote node - let heap_pages = remote_client - .storage(&remote_block_id, &StorageKey(well_known_keys::HEAP_PAGES.to_vec())) - .unwrap() - .and_then(|v| Decode::decode(&mut &v.0[..]).ok()) - .unwrap(); - let remote_read_proof = remote_client - .read_proof(&remote_block_id, &mut std::iter::once(well_known_keys::HEAP_PAGES)) - .unwrap(); - - // check remote read proof locally - let local_storage = InMemoryBlockchain::::new(); - local_storage - .insert(remote_block_hash, remote_block_header.clone(), None, None, NewBlockState::Final) - .unwrap(); - let local_checker = LightDataChecker::new( - Arc::new(DummyBlockchain::new(DummyStorage::new())), - local_executor(), - Box::new(TaskExecutor::new()), - ); - (local_checker, remote_block_header, remote_read_proof, heap_pages) -} - -fn prepare_for_read_child_proof_check() -> (TestChecker, Header, StorageProof, Vec) { - use substrate_test_runtime_client::{DefaultTestClientBuilderExt, TestClientBuilderExt}; - let child_info = ChildInfo::new_default(b"child1"); - let child_info = &child_info; - // prepare remote client - let remote_client = substrate_test_runtime_client::TestClientBuilder::new() - .add_extra_child_storage(child_info, b"key1".to_vec(), b"value1".to_vec()) - .build(); - let remote_block_id = BlockId::Number(0); - let remote_block_hash = remote_client.block_hash(0).unwrap().unwrap(); - let mut remote_block_header = remote_client.header(&remote_block_id).unwrap().unwrap(); - remote_block_header.state_root = remote_client - .state_at(&remote_block_id) - .unwrap() - .storage_root(::std::iter::empty()) - .0 - .into(); - - // 'fetch' child read proof from remote node - let child_value = remote_client - .child_storage(&remote_block_id, child_info, &StorageKey(b"key1".to_vec())) - .unwrap() - .unwrap() - .0; - assert_eq!(b"value1"[..], child_value[..]); - let remote_read_proof = remote_client - .read_child_proof(&remote_block_id, child_info, &mut std::iter::once("key1".as_bytes())) - .unwrap(); - - // check locally - let local_storage = InMemoryBlockchain::::new(); - local_storage - .insert(remote_block_hash, remote_block_header.clone(), None, None, NewBlockState::Final) - .unwrap(); - let local_checker = LightDataChecker::new( - Arc::new(DummyBlockchain::new(DummyStorage::new())), - local_executor(), - Box::new(TaskExecutor::new()), - ); - (local_checker, remote_block_header, remote_read_proof, child_value) -} - -fn prepare_for_header_proof_check(insert_cht: bool) -> (TestChecker, Hash, Header, StorageProof) { - // prepare remote client - let mut remote_client = substrate_test_runtime_client::new(); - let mut local_headers_hashes = Vec::new(); - for i in 0..4 { - let block = remote_client.new_block(Default::default()).unwrap().build().unwrap().block; - futures::executor::block_on(remote_client.import(BlockOrigin::Own, block)).unwrap(); - local_headers_hashes.push( - remote_client - .block_hash(i + 1) - .map_err(|_| ClientError::Backend("TestError".into())), - ); - } - - // 'fetch' header proof from remote node - let remote_block_id = BlockId::Number(1); - let (remote_block_header, remote_header_proof) = - remote_client.header_proof_with_cht_size(&remote_block_id, 4).unwrap(); - - // check remote read proof locally - let local_storage = InMemoryBlockchain::::new(); - let local_cht_root = - cht::compute_root::(4, 0, local_headers_hashes).unwrap(); - if insert_cht { - local_storage.insert_cht_root(1, local_cht_root); - } - let local_checker = LightDataChecker::new( - Arc::new(DummyBlockchain::new(DummyStorage::new())), - local_executor(), - Box::new(TaskExecutor::new()), - ); - (local_checker, local_cht_root, remote_block_header, remote_header_proof) -} - -fn header_with_computed_extrinsics_root(extrinsics: Vec) -> Header { - use sp_trie::{trie_types::Layout, TrieConfiguration}; - let iter = extrinsics.iter().map(Encode::encode); - let extrinsics_root = Layout::::ordered_trie_root(iter); - - // only care about `extrinsics_root` - Header::new(0, extrinsics_root, H256::zero(), H256::zero(), Default::default()) -} - -#[test] -fn storage_read_proof_is_generated_and_checked() { - let (local_checker, remote_block_header, remote_read_proof, heap_pages) = - prepare_for_read_proof_check(); - assert_eq!( - (&local_checker as &dyn FetchChecker) - .check_read_proof( - &RemoteReadRequest::
{ - block: remote_block_header.hash(), - header: remote_block_header, - keys: vec![well_known_keys::HEAP_PAGES.to_vec()], - retry_count: None, - }, - remote_read_proof - ) - .unwrap() - .remove(well_known_keys::HEAP_PAGES) - .unwrap() - .unwrap()[0], - heap_pages as u8 - ); -} - -#[test] -fn storage_child_read_proof_is_generated_and_checked() { - let child_info = ChildInfo::new_default(&b"child1"[..]); - let (local_checker, remote_block_header, remote_read_proof, result) = - prepare_for_read_child_proof_check(); - assert_eq!( - (&local_checker as &dyn FetchChecker) - .check_read_child_proof( - &RemoteReadChildRequest::
{ - block: remote_block_header.hash(), - header: remote_block_header, - storage_key: child_info.prefixed_storage_key(), - keys: vec![b"key1".to_vec()], - retry_count: None, - }, - remote_read_proof - ) - .unwrap() - .remove(b"key1".as_ref()) - .unwrap() - .unwrap(), - result - ); -} - -#[test] -fn header_proof_is_generated_and_checked() { - let (local_checker, local_cht_root, remote_block_header, remote_header_proof) = - prepare_for_header_proof_check(true); - assert_eq!( - (&local_checker as &dyn FetchChecker) - .check_header_proof( - &RemoteHeaderRequest::
{ - cht_root: local_cht_root, - block: 1, - retry_count: None, - }, - Some(remote_block_header.clone()), - remote_header_proof - ) - .unwrap(), - remote_block_header - ); -} - -#[test] -fn check_header_proof_fails_if_cht_root_is_invalid() { - let (local_checker, _, mut remote_block_header, remote_header_proof) = - prepare_for_header_proof_check(true); - remote_block_header.number = 100; - assert!((&local_checker as &dyn FetchChecker) - .check_header_proof( - &RemoteHeaderRequest::
{ - cht_root: Default::default(), - block: 1, - retry_count: None, - }, - Some(remote_block_header.clone()), - remote_header_proof - ) - .is_err()); -} - -#[test] -fn check_header_proof_fails_if_invalid_header_provided() { - let (local_checker, local_cht_root, mut remote_block_header, remote_header_proof) = - prepare_for_header_proof_check(true); - remote_block_header.number = 100; - assert!((&local_checker as &dyn FetchChecker) - .check_header_proof( - &RemoteHeaderRequest::
{ - cht_root: local_cht_root, - block: 1, - retry_count: None, - }, - Some(remote_block_header.clone()), - remote_header_proof - ) - .is_err()); -} - -#[test] -fn changes_proof_is_generated_and_checked_when_headers_are_not_pruned() { - let (remote_client, local_roots, test_cases) = prepare_client_with_key_changes(); - let local_checker = TestChecker::new( - Arc::new(DummyBlockchain::new(DummyStorage::new())), - local_executor(), - Box::new(TaskExecutor::new()), - ); - let local_checker = &local_checker as &dyn FetchChecker; - let max = remote_client.chain_info().best_number; - let max_hash = remote_client.chain_info().best_hash; - - for (index, (begin, end, key, expected_result)) in test_cases.into_iter().enumerate() { - let begin_hash = remote_client.block_hash(begin).unwrap().unwrap(); - let end_hash = remote_client.block_hash(end).unwrap().unwrap(); - - // 'fetch' changes proof from remote node - let key = StorageKey(key); - let remote_proof = remote_client - .key_changes_proof(begin_hash, end_hash, begin_hash, max_hash, None, &key) - .unwrap(); - - // check proof on local client - let local_roots_range = local_roots.clone()[(begin - 1) as usize..].to_vec(); - let config = ChangesTrieConfiguration::new(4, 2); - let request = RemoteChangesRequest::
{ - changes_trie_configs: vec![sp_core::ChangesTrieConfigurationRange { - zero: (0, Default::default()), - end: None, - config: Some(config), - }], - first_block: (begin, begin_hash), - last_block: (end, end_hash), - max_block: (max, max_hash), - tries_roots: (begin, begin_hash, local_roots_range), - key: key.0, - storage_key: None, - retry_count: None, - }; - let local_result = local_checker - .check_changes_proof( - &request, - ChangesProof { - max_block: remote_proof.max_block, - proof: remote_proof.proof, - roots: remote_proof.roots, - roots_proof: remote_proof.roots_proof, - }, - ) - .unwrap(); - - // ..and ensure that result is the same as on remote node - if local_result != expected_result { - panic!( - "Failed test {}: local = {:?}, expected = {:?}", - index, local_result, expected_result, - ); - } - } -} - -#[test] -fn changes_proof_is_generated_and_checked_when_headers_are_pruned() { - // we're testing this test case here: - // (1, 4, dave.clone(), vec![(4, 0), (1, 1), (1, 0)]), - let (remote_client, remote_roots, _) = prepare_client_with_key_changes(); - let dave = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec(); - let dave = StorageKey(dave); - - // 'fetch' changes proof from remote node: - // we're fetching changes for range b1..b4 - // we do not know changes trie roots before b3 (i.e. we only know b3+b4) - // but we have changes trie CHT root for b1...b4 - let b1 = remote_client.block_hash_from_id(&BlockId::Number(1)).unwrap().unwrap(); - let b3 = remote_client.block_hash_from_id(&BlockId::Number(3)).unwrap().unwrap(); - let b4 = remote_client.block_hash_from_id(&BlockId::Number(4)).unwrap().unwrap(); - let remote_proof = remote_client - .key_changes_proof_with_cht_size(b1, b4, b3, b4, None, &dave, 4) - .unwrap(); - - // prepare local checker, having a root of changes trie CHT#0 - let local_cht_root = cht::compute_root::( - 4, - 0, - remote_roots.iter().cloned().map(|ct| Ok(Some(ct))), - ) - .unwrap(); - let mut local_storage = DummyStorage::new(); - local_storage.changes_tries_cht_roots.insert(0, local_cht_root); - let local_checker = TestChecker::new( - Arc::new(DummyBlockchain::new(local_storage)), - local_executor(), - Box::new(TaskExecutor::new()), - ); - - // check proof on local client - let config = ChangesTrieConfiguration::new(4, 2); - let request = RemoteChangesRequest::
{ - changes_trie_configs: vec![sp_core::ChangesTrieConfigurationRange { - zero: (0, Default::default()), - end: None, - config: Some(config), - }], - first_block: (1, b1), - last_block: (4, b4), - max_block: (4, b4), - tries_roots: (3, b3, vec![remote_roots[2].clone(), remote_roots[3].clone()]), - storage_key: None, - key: dave.0, - retry_count: None, - }; - let local_result = local_checker - .check_changes_proof_with_cht_size( - &request, - ChangesProof { - max_block: remote_proof.max_block, - proof: remote_proof.proof, - roots: remote_proof.roots, - roots_proof: remote_proof.roots_proof, - }, - 4, - ) - .unwrap(); - - assert_eq!(local_result, vec![(4, 0), (1, 1), (1, 0)]); -} - -#[test] -fn check_changes_proof_fails_if_proof_is_wrong() { - let (remote_client, local_roots, test_cases) = prepare_client_with_key_changes(); - let local_checker = TestChecker::new( - Arc::new(DummyBlockchain::new(DummyStorage::new())), - local_executor(), - Box::new(TaskExecutor::new()), - ); - let local_checker = &local_checker as &dyn FetchChecker; - let max = remote_client.chain_info().best_number; - let max_hash = remote_client.chain_info().best_hash; - - let (begin, end, key, _) = test_cases[0].clone(); - let begin_hash = remote_client.block_hash(begin).unwrap().unwrap(); - let end_hash = remote_client.block_hash(end).unwrap().unwrap(); - - // 'fetch' changes proof from remote node - let key = StorageKey(key); - let remote_proof = remote_client - .key_changes_proof(begin_hash, end_hash, begin_hash, max_hash, None, &key) - .unwrap(); - - let local_roots_range = local_roots.clone()[(begin - 1) as usize..].to_vec(); - let config = ChangesTrieConfiguration::new(4, 2); - let request = RemoteChangesRequest::
{ - changes_trie_configs: vec![sp_core::ChangesTrieConfigurationRange { - zero: (0, Default::default()), - end: None, - config: Some(config), - }], - first_block: (begin, begin_hash), - last_block: (end, end_hash), - max_block: (max, max_hash), - tries_roots: (begin, begin_hash, local_roots_range.clone()), - storage_key: None, - key: key.0, - retry_count: None, - }; - - // check proof on local client using max from the future - assert!(local_checker - .check_changes_proof( - &request, - ChangesProof { - max_block: remote_proof.max_block + 1, - proof: remote_proof.proof.clone(), - roots: remote_proof.roots.clone(), - roots_proof: remote_proof.roots_proof.clone(), - } - ) - .is_err()); - - // check proof on local client using broken proof - assert!(local_checker - .check_changes_proof( - &request, - ChangesProof { - max_block: remote_proof.max_block, - proof: local_roots_range.clone().into_iter().map(|v| v.as_ref().to_vec()).collect(), - roots: remote_proof.roots, - roots_proof: remote_proof.roots_proof, - } - ) - .is_err()); - - // extra roots proofs are provided - assert!(local_checker - .check_changes_proof( - &request, - ChangesProof { - max_block: remote_proof.max_block, - proof: remote_proof.proof.clone(), - roots: vec![(begin - 1, Default::default())].into_iter().collect(), - roots_proof: StorageProof::empty(), - } - ) - .is_err()); - assert!(local_checker - .check_changes_proof( - &request, - ChangesProof { - max_block: remote_proof.max_block, - proof: remote_proof.proof.clone(), - roots: vec![(end + 1, Default::default())].into_iter().collect(), - roots_proof: StorageProof::empty(), - } - ) - .is_err()); -} - -#[test] -fn check_changes_tries_proof_fails_if_proof_is_wrong() { - // we're testing this test case here: - // (1, 4, dave.clone(), vec![(4, 0), (1, 1), (1, 0)]), - let (remote_client, remote_roots, _) = prepare_client_with_key_changes(); - let local_cht_root = cht::compute_root::( - 4, - 0, - remote_roots.iter().cloned().map(|ct| Ok(Some(ct))), - ) - .unwrap(); - let dave = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec(); - let dave = StorageKey(dave); - - // 'fetch' changes proof from remote node: - // we're fetching changes for range b1..b4 - // we do not know changes trie roots before b3 (i.e. we only know b3+b4) - // but we have changes trie CHT root for b1...b4 - let b1 = remote_client.block_hash_from_id(&BlockId::Number(1)).unwrap().unwrap(); - let b3 = remote_client.block_hash_from_id(&BlockId::Number(3)).unwrap().unwrap(); - let b4 = remote_client.block_hash_from_id(&BlockId::Number(4)).unwrap().unwrap(); - let remote_proof = remote_client - .key_changes_proof_with_cht_size(b1, b4, b3, b4, None, &dave, 4) - .unwrap(); - - // fails when changes trie CHT is missing from the local db - let local_checker = TestChecker::new( - Arc::new(DummyBlockchain::new(DummyStorage::new())), - local_executor(), - Box::new(TaskExecutor::new()), - ); - assert!(local_checker - .check_changes_tries_proof(4, &remote_proof.roots, remote_proof.roots_proof.clone()) - .is_err()); - - // fails when proof is broken - let mut local_storage = DummyStorage::new(); - local_storage.changes_tries_cht_roots.insert(0, local_cht_root); - let local_checker = TestChecker::new( - Arc::new(DummyBlockchain::new(local_storage)), - local_executor(), - Box::new(TaskExecutor::new()), - ); - let result = - local_checker.check_changes_tries_proof(4, &remote_proof.roots, StorageProof::empty()); - assert!(result.is_err()); -} - -#[test] -fn check_body_proof_faulty() { - let header = - header_with_computed_extrinsics_root(vec![Extrinsic::IncludeData(vec![1, 2, 3, 4])]); - let block = Block::new(header.clone(), Vec::new()); - - let local_checker = TestChecker::new( - Arc::new(DummyBlockchain::new(DummyStorage::new())), - local_executor(), - Box::new(TaskExecutor::new()), - ); - - let body_request = RemoteBodyRequest { header: header.clone(), retry_count: None }; - - assert!( - local_checker.check_body_proof(&body_request, block.extrinsics).is_err(), - "vec![1, 2, 3, 4] != vec![]" - ); -} - -#[test] -fn check_body_proof_of_same_data_should_succeed() { - let extrinsics = vec![Extrinsic::IncludeData(vec![1, 2, 3, 4, 5, 6, 7, 8, 255])]; - - let header = header_with_computed_extrinsics_root(extrinsics.clone()); - let block = Block::new(header.clone(), extrinsics); - - let local_checker = TestChecker::new( - Arc::new(DummyBlockchain::new(DummyStorage::new())), - local_executor(), - Box::new(TaskExecutor::new()), - ); - - let body_request = RemoteBodyRequest { header: header.clone(), retry_count: None }; - - assert!(local_checker.check_body_proof(&body_request, block.extrinsics).is_ok()); -} diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 8ea605c0ea5be..33cbefbb06a95 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -57,9 +57,6 @@ use substrate_test_runtime_client::{ Sr25519Keyring, TestClientBuilder, TestClientBuilderExt, }; -mod db; -mod light; - const TEST_ENGINE_ID: ConsensusEngineId = *b"TEST"; pub struct ExecutorDispatch; diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index a4e740aabc18e..c44a5cdb97431 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -33,8 +33,9 @@ use sc_service::{ SpawnTaskHandle, TaskManager, TransactionStorageMode, }; use sc_transaction_pool_api::TransactionPool; +use sp_api::BlockId; use sp_blockchain::HeaderBackend; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use std::{iter, net::Ipv4Addr, pin::Pin, sync::Arc, task::Context, time::Duration}; use tempfile::TempDir; use tokio::{runtime::Runtime, time}; @@ -45,22 +46,20 @@ mod client; /// Maximum duration of single wait call. const MAX_WAIT_TIME: Duration = Duration::from_secs(60 * 3); -struct TestNet { +struct TestNet { runtime: Runtime, authority_nodes: Vec<(usize, F, U, Multiaddr)>, full_nodes: Vec<(usize, F, U, Multiaddr)>, - light_nodes: Vec<(usize, L, Multiaddr)>, chain_spec: GenericChainSpec, base_port: u16, nodes: usize, } -impl Drop for TestNet { +impl Drop for TestNet { fn drop(&mut self) { // Drop the nodes before dropping the runtime, as the runtime otherwise waits for all // futures to be ended and we run into a dead lock. self.full_nodes.drain(..); - self.light_nodes.drain(..); self.authority_nodes.drain(..); } } @@ -156,39 +155,26 @@ where } } -impl TestNet +impl TestNet where F: Clone + Send + 'static, - L: Clone + Send + 'static, U: Clone + Send + 'static, { - pub fn run_until_all_full(&mut self, full_predicate: FP, light_predicate: LP) + pub fn run_until_all_full(&mut self, full_predicate: FP) where FP: Send + Fn(usize, &F) -> bool + 'static, - LP: Send + Fn(usize, &L) -> bool + 'static, { let full_nodes = self.full_nodes.clone(); - let light_nodes = self.light_nodes.clone(); let future = async move { let mut interval = time::interval(Duration::from_millis(100)); - loop { interval.tick().await; - let full_ready = full_nodes + if full_nodes .iter() - .all(|&(ref id, ref service, _, _)| full_predicate(*id, service)); - - if !full_ready { - continue - } - - let light_ready = light_nodes - .iter() - .all(|&(ref id, ref service, _)| light_predicate(*id, service)); - - if light_ready { - return + .all(|&(ref id, ref service, _, _)| full_predicate(*id, service)) + { + break } } }; @@ -278,10 +264,9 @@ fn node_config< } } -impl TestNet +impl TestNet where F: TestNetNode, - L: TestNetNode, E: ChainSpecExtension + Clone + 'static + Send + Sync, G: RuntimeGenesis + 'static, { @@ -289,10 +274,9 @@ where temp: &TempDir, spec: GenericChainSpec, full: impl Iterator Result<(F, U), Error>>, - light: impl Iterator Result>, authorities: impl Iterator Result<(F, U), Error>)>, base_port: u16, - ) -> TestNet { + ) -> TestNet { sp_tracing::try_init_simple(); fdlimit::raise_fd_limit(); let runtime = Runtime::new().expect("Error creating tokio runtime"); @@ -300,12 +284,11 @@ where runtime, authority_nodes: Default::default(), full_nodes: Default::default(), - light_nodes: Default::default(), chain_spec: spec, base_port, nodes: 0, }; - net.insert_nodes(temp, full, light, authorities); + net.insert_nodes(temp, full, authorities); net } @@ -313,7 +296,6 @@ where &mut self, temp: &TempDir, full: impl Iterator Result<(F, U), Error>>, - light: impl Iterator Result>, authorities: impl Iterator Result<(F, U), Error>)>, ) { let handle = self.runtime.handle().clone(); @@ -358,26 +340,6 @@ where self.full_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; } - - for light in light { - let node_config = node_config( - self.nodes, - &self.chain_spec, - Role::Light, - handle.clone(), - None, - self.base_port, - &temp, - ); - let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); - let service = light(node_config).expect("Error creating test node service"); - - handle.spawn(service.clone().map_err(|_| ())); - let addr = addr - .with(multiaddr::Protocol::P2p(service.network().local_peer_id().clone().into())); - self.light_nodes.push((self.nodes, service, addr)); - self.nodes += 1; - } } } @@ -388,23 +350,16 @@ fn tempdir_with_prefix(prefix: &str) -> TempDir { .expect("Error creating test dir") } -pub fn connectivity( - spec: GenericChainSpec, - full_builder: Fb, - light_builder: Lb, -) where +pub fn connectivity(spec: GenericChainSpec, full_builder: Fb) +where E: ChainSpecExtension + Clone + 'static + Send + Sync, G: RuntimeGenesis + 'static, Fb: Fn(Configuration) -> Result, F: TestNetNode, - Lb: Fn(Configuration) -> Result, - L: TestNetNode, { const NUM_FULL_NODES: usize = 5; - const NUM_LIGHT_NODES: usize = 5; - let expected_full_connections = NUM_FULL_NODES - 1 + NUM_LIGHT_NODES; - let expected_light_connections = NUM_FULL_NODES; + let expected_full_connections = NUM_FULL_NODES - 1; { let temp = tempdir_with_prefix("substrate-connectivity-test"); @@ -413,7 +368,6 @@ pub fn connectivity( &temp, spec.clone(), (0..NUM_FULL_NODES).map(|_| |cfg| full_builder(cfg).map(|s| (s, ()))), - (0..NUM_LIGHT_NODES).map(|_| |cfg| light_builder(cfg)), // Note: this iterator is empty but we can't just use `iter::empty()`, otherwise // the type of the closure cannot be inferred. (0..0).map(|_| (String::new(), { |cfg| full_builder(cfg).map(|s| (s, ())) })), @@ -427,25 +381,12 @@ pub fn connectivity( .add_reserved_peer(first_address.to_string()) .expect("Error adding reserved peer"); } - for (_, service, _) in network.light_nodes.iter() { - service - .network() - .add_reserved_peer(first_address.to_string()) - .expect("Error adding reserved peer"); - } - network.run_until_all_full( - move |_index, service| { - let connected = service.network().num_connected(); - debug!("Got {}/{} full connections...", connected, expected_full_connections); - connected == expected_full_connections - }, - move |_index, service| { - let connected = service.network().num_connected(); - debug!("Got {}/{} light connections...", connected, expected_light_connections); - connected == expected_light_connections - }, - ); + network.run_until_all_full(move |_index, service| { + let connected = service.network().num_connected(); + debug!("Got {}/{} full connections...", connected, expected_full_connections); + connected == expected_full_connections + }); }; temp.close().expect("Error removing temp dir"); @@ -457,7 +398,6 @@ pub fn connectivity( &temp, spec, (0..NUM_FULL_NODES).map(|_| |cfg| full_builder(cfg).map(|s| (s, ()))), - (0..NUM_LIGHT_NODES).map(|_| |cfg| light_builder(cfg)), // Note: this iterator is empty but we can't just use `iter::empty()`, otherwise // the type of the closure cannot be inferred. (0..0).map(|_| (String::new(), { |cfg| full_builder(cfg).map(|s| (s, ())) })), @@ -465,8 +405,7 @@ pub fn connectivity( ); info!("Checking linked topology"); let mut address = network.full_nodes[0].3.clone(); - let max_nodes = std::cmp::max(NUM_FULL_NODES, NUM_LIGHT_NODES); - for i in 0..max_nodes { + for i in 0..NUM_FULL_NODES { if i != 0 { if let Some((_, service, _, node_id)) = network.full_nodes.get(i) { service @@ -476,44 +415,26 @@ pub fn connectivity( address = node_id.clone(); } } - - if let Some((_, service, node_id)) = network.light_nodes.get(i) { - service - .network() - .add_reserved_peer(address.to_string()) - .expect("Error adding reserved peer"); - address = node_id.clone(); - } } - network.run_until_all_full( - move |_index, service| { - let connected = service.network().num_connected(); - debug!("Got {}/{} full connections...", connected, expected_full_connections); - connected == expected_full_connections - }, - move |_index, service| { - let connected = service.network().num_connected(); - debug!("Got {}/{} light connections...", connected, expected_light_connections); - connected == expected_light_connections - }, - ); + network.run_until_all_full(move |_index, service| { + let connected = service.network().num_connected(); + debug!("Got {}/{} full connections...", connected, expected_full_connections); + connected == expected_full_connections + }); } temp.close().expect("Error removing temp dir"); } } -pub fn sync( +pub fn sync( spec: GenericChainSpec, full_builder: Fb, - light_builder: Lb, mut make_block_and_import: B, mut extrinsic_factory: ExF, ) where Fb: Fn(Configuration) -> Result<(F, U), Error>, F: TestNetNode, - Lb: Fn(Configuration) -> Result, - L: TestNetNode, B: FnMut(&F, &mut U), ExF: FnMut(&F, &U) -> ::Extrinsic, U: Clone + Send + 'static, @@ -521,15 +442,12 @@ pub fn sync( G: RuntimeGenesis + 'static, { const NUM_FULL_NODES: usize = 10; - // FIXME: BABE light client support is currently not working. - const NUM_LIGHT_NODES: usize = 10; const NUM_BLOCKS: usize = 512; let temp = tempdir_with_prefix("substrate-sync-test"); let mut network = TestNet::new( &temp, spec, (0..NUM_FULL_NODES).map(|_| |cfg| full_builder(cfg)), - (0..NUM_LIGHT_NODES).map(|_| |cfg| light_builder(cfg)), // Note: this iterator is empty but we can't just use `iter::empty()`, otherwise // the type of the closure cannot be inferred. (0..0).map(|_| (String::new(), { |cfg| full_builder(cfg) })), @@ -560,16 +478,10 @@ pub fn sync( .add_reserved_peer(first_address.to_string()) .expect("Error adding reserved peer"); } - for (_, service, _) in network.light_nodes.iter() { - service - .network() - .add_reserved_peer(first_address.to_string()) - .expect("Error adding reserved peer"); - } - network.run_until_all_full( - |_index, service| service.client().info().best_number == (NUM_BLOCKS as u32).into(), - |_index, service| service.client().info().best_number == (NUM_BLOCKS as u32).into(), - ); + + network.run_until_all_full(|_index, service| { + service.client().info().best_number == (NUM_BLOCKS as u32).into() + }); info!("Checking extrinsic propagation"); let first_service = network.full_nodes[0].1.clone(); @@ -585,34 +497,26 @@ pub fn sync( )) .expect("failed to submit extrinsic"); - network.run_until_all_full( - |_index, service| service.transaction_pool().ready().count() == 1, - |_index, _service| true, - ); + network.run_until_all_full(|_index, service| service.transaction_pool().ready().count() == 1); } -pub fn consensus( +pub fn consensus( spec: GenericChainSpec, full_builder: Fb, - light_builder: Lb, authorities: impl IntoIterator, ) where Fb: Fn(Configuration) -> Result, F: TestNetNode, - Lb: Fn(Configuration) -> Result, - L: TestNetNode, E: ChainSpecExtension + Clone + 'static + Send + Sync, G: RuntimeGenesis + 'static, { const NUM_FULL_NODES: usize = 10; - const NUM_LIGHT_NODES: usize = 10; const NUM_BLOCKS: usize = 10; // 10 * 2 sec block production time = ~20 seconds let temp = tempdir_with_prefix("substrate-consensus-test"); let mut network = TestNet::new( &temp, spec, (0..NUM_FULL_NODES / 2).map(|_| |cfg| full_builder(cfg).map(|s| (s, ()))), - (0..NUM_LIGHT_NODES / 2).map(|_| |cfg| light_builder(cfg)), authorities .into_iter() .map(|key| (key, { |cfg| full_builder(cfg).map(|s| (s, ())) })), @@ -627,30 +531,20 @@ pub fn consensus( .add_reserved_peer(first_address.to_string()) .expect("Error adding reserved peer"); } - for (_, service, _) in network.light_nodes.iter() { - service - .network() - .add_reserved_peer(first_address.to_string()) - .expect("Error adding reserved peer"); - } for (_, service, _, _) in network.authority_nodes.iter().skip(1) { service .network() .add_reserved_peer(first_address.to_string()) .expect("Error adding reserved peer"); } - network.run_until_all_full( - |_index, service| { - service.client().info().finalized_number >= (NUM_BLOCKS as u32 / 2).into() - }, - |_index, service| service.client().info().best_number >= (NUM_BLOCKS as u32 / 2).into(), - ); + network.run_until_all_full(|_index, service| { + service.client().info().finalized_number >= (NUM_BLOCKS as u32 / 2).into() + }); info!("Adding more peers"); network.insert_nodes( &temp, (0..NUM_FULL_NODES / 2).map(|_| |cfg| full_builder(cfg).map(|s| (s, ()))), - (0..NUM_LIGHT_NODES / 2).map(|_| |cfg| light_builder(cfg)), // Note: this iterator is empty but we can't just use `iter::empty()`, otherwise // the type of the closure cannot be inferred. (0..0).map(|_| (String::new(), { |cfg| full_builder(cfg).map(|s| (s, ())) })), @@ -661,14 +555,8 @@ pub fn consensus( .add_reserved_peer(first_address.to_string()) .expect("Error adding reserved peer"); } - for (_, service, _) in network.light_nodes.iter() { - service - .network() - .add_reserved_peer(first_address.to_string()) - .expect("Error adding reserved peer"); - } - network.run_until_all_full( - |_index, service| service.client().info().finalized_number >= (NUM_BLOCKS as u32).into(), - |_index, service| service.client().info().best_number >= (NUM_BLOCKS as u32).into(), - ); + + network.run_until_all_full(|_index, service| { + service.client().info().finalized_number >= (NUM_BLOCKS as u32).into() + }); } From 040ab4027e40fdeb607a31cf4d30eefd10f1aa0f Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sat, 30 Oct 2021 15:02:09 +0200 Subject: [PATCH 0158/1472] Add Baseline FRAME Benchmarks (#9691) * create and add baseline * fix import * try a different name * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * increase repeats * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update baseline.rs * Update baseline.rs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * improve hash benchmark * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- bin/node-template/runtime/src/lib.rs | 10 +- bin/node/runtime/src/lib.rs | 9 +- frame/benchmarking/src/baseline.rs | 173 +++++++++++++++++++++++++++ frame/benchmarking/src/lib.rs | 2 + frame/benchmarking/src/weights.rs | 122 +++++++++++++++++++ 5 files changed, 312 insertions(+), 4 deletions(-) create mode 100644 frame/benchmarking/src/baseline.rs create mode 100644 frame/benchmarking/src/weights.rs diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 4b49cb48ef352..dbea698002c60 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -463,12 +463,14 @@ impl_runtime_apis! { Vec, Vec, ) { - use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList}; + use frame_benchmarking::{list_benchmark, baseline, Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use baseline::Pallet as BaselineBench; let mut list = Vec::::new(); + list_benchmark!(list, extra, frame_benchmarking, BaselineBench::); list_benchmark!(list, extra, frame_system, SystemBench::); list_benchmark!(list, extra, pallet_balances, Balances); list_benchmark!(list, extra, pallet_timestamp, Timestamp); @@ -482,10 +484,13 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig ) -> Result, sp_runtime::RuntimeString> { - use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; + use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; use frame_system_benchmarking::Pallet as SystemBench; + use baseline::Pallet as BaselineBench; + impl frame_system_benchmarking::Config for Runtime {} + impl baseline::Config for Runtime {} let whitelist: Vec = vec![ // Block Number @@ -503,6 +508,7 @@ impl_runtime_apis! { let mut batches = Vec::::new(); let params = (&config, &whitelist); + add_benchmark!(params, batches, frame_benchmarking, BaselineBench::); add_benchmark!(params, batches, frame_system, SystemBench::); add_benchmark!(params, batches, pallet_balances, Balances); add_benchmark!(params, batches, pallet_timestamp, Timestamp); diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0638e62faa362..9154ef6ca53df 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1609,7 +1609,7 @@ impl_runtime_apis! { Vec, Vec, ) { - use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList}; + use frame_benchmarking::{list_benchmark, baseline, Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; // Trying to add benchmarks directly to the Session Pallet caused cyclic dependency @@ -1618,9 +1618,11 @@ impl_runtime_apis! { use pallet_session_benchmarking::Pallet as SessionBench; use pallet_offences_benchmarking::Pallet as OffencesBench; use frame_system_benchmarking::Pallet as SystemBench; + use baseline::Pallet as BaselineBench; let mut list = Vec::::new(); + list_benchmark!(list, extra, frame_benchmarking, BaselineBench::); list_benchmark!(list, extra, pallet_assets, Assets); list_benchmark!(list, extra, pallet_babe, Babe); list_benchmark!(list, extra, pallet_bags_list, BagsList); @@ -1662,7 +1664,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig ) -> Result, sp_runtime::RuntimeString> { - use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; + use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; // Trying to add benchmarks directly to the Session Pallet caused cyclic dependency // issues. To get around that, we separated the Session benchmarks into its own crate, @@ -1670,10 +1672,12 @@ impl_runtime_apis! { use pallet_session_benchmarking::Pallet as SessionBench; use pallet_offences_benchmarking::Pallet as OffencesBench; use frame_system_benchmarking::Pallet as SystemBench; + use baseline::Pallet as BaselineBench; impl pallet_session_benchmarking::Config for Runtime {} impl pallet_offences_benchmarking::Config for Runtime {} impl frame_system_benchmarking::Config for Runtime {} + impl baseline::Config for Runtime {} let whitelist: Vec = vec![ // Block Number @@ -1695,6 +1699,7 @@ impl_runtime_apis! { let mut batches = Vec::::new(); let params = (&config, &whitelist); + add_benchmark!(params, batches, frame_benchmarking, BaselineBench::); add_benchmark!(params, batches, pallet_assets, Assets); add_benchmark!(params, batches, pallet_babe, Babe); add_benchmark!(params, batches, pallet_balances, Balances); diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs new file mode 100644 index 0000000000000..a2ffca60c5cf1 --- /dev/null +++ b/frame/benchmarking/src/baseline.rs @@ -0,0 +1,173 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A set of benchmarks which can establish a global baseline for all other +//! benchmarking. + +use crate::benchmarks; +use codec::Encode; +use frame_system::Pallet as System; +use sp_runtime::traits::Hash; +use sp_std::prelude::*; + +pub struct Pallet(System); +pub trait Config: frame_system::Config {} + +benchmarks! { + addition { + let i in 0 .. 1_000_000; + let mut start = 0; + }: { + (0..i).for_each(|_| start += 1); + } verify { + assert_eq!(start, i); + } + + subtraction { + let i in 0 .. 1_000_000; + let mut start = u32::MAX; + }: { + (0..i).for_each(|_| start -= 1); + } verify { + assert_eq!(start, u32::MAX - i); + } + + multiplication { + let i in 0 .. 1_000_000; + let mut out = 0; + }: { + (1..=i).for_each(|j| out = 2 * j); + } verify { + assert_eq!(out, 2 * i); + } + + division { + let i in 0 .. 1_000_000; + let mut out = 0; + }: { + (0..=i).for_each(|j| out = j / 2); + } verify { + assert_eq!(out, i / 2); + } + + hashing { + let i in 0 .. 100; + let mut hash = T::Hash::default(); + }: { + (0..=100_000u32).for_each(|j| hash = T::Hashing::hash(&j.to_be_bytes())); + } verify { + assert!(hash != T::Hash::default()); + } + + #[skip_meta] + storage_read { + let i in 0 .. 1_000; + let mut people = Vec::new(); + (0..i).for_each(|j| { + let hash = T::Hashing::hash(&j.to_be_bytes()).encode(); + frame_support::storage::unhashed::put(&hash, &hash); + people.push(hash); + }); + }: { + people.iter().for_each(|hash| { + // This does a storage read + let value = frame_support::storage::unhashed::get(hash); + assert_eq!(value, Some(hash.to_vec())); + }); + } + + #[skip_meta] + storage_write { + let i in 0 .. 1_000; + let mut hashes = Vec::new(); + (0..i).for_each(|j| { + let hash = T::Hashing::hash(&j.to_be_bytes()); + hashes.push(hash.encode()); + }); + }: { + hashes.iter().for_each(|hash| { + // This does a storage write + frame_support::storage::unhashed::put(hash, hash); + }); + } verify { + hashes.iter().for_each(|hash| { + let value = frame_support::storage::unhashed::get(hash); + assert_eq!(value, Some(hash.to_vec())); + }); + } + + impl_benchmark_test_suite!( + Pallet, + crate::baseline::mock::new_test_ext(), + crate::baseline::mock::Test, + ); +} + +#[cfg(test)] +pub mod mock { + use sp_runtime::{testing::H256, traits::IdentityLookup}; + + type AccountId = u64; + type AccountIndex = u32; + type BlockNumber = u64; + + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + type Block = frame_system::mocking::MockBlock; + + frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + } + ); + + impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = AccountIndex; + type BlockNumber = BlockNumber; + type Call = Call; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = sp_runtime::testing::Header; + type Event = Event; + type BlockHashCount = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + } + + impl super::Config for Test {} + + pub fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + sp_io::TestExternalities::new(t) + } +} diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 1805424426f6e..258b40cbe6f0b 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -27,6 +27,8 @@ mod tests; mod tests_instance; mod utils; +pub mod baseline; + #[cfg(feature = "std")] pub use analysis::{Analysis, AnalysisChoice, BenchmarkSelector, RegressionModel}; #[doc(hidden)] diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs new file mode 100644 index 0000000000000..807ff697fdcaa --- /dev/null +++ b/frame/benchmarking/src/weights.rs @@ -0,0 +1,122 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for frame_benchmarking +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// target/release/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=frame_benchmarking +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/benchmarking/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for frame_benchmarking. +pub trait WeightInfo { + fn addition(i: u32, ) -> Weight; + fn subtraction(i: u32, ) -> Weight; + fn multiplication(i: u32, ) -> Weight; + fn division(i: u32, ) -> Weight; + fn hashing(i: u32, ) -> Weight; + fn storage_read(i: u32, ) -> Weight; + fn storage_write(i: u32, ) -> Weight; +} + +/// Weights for frame_benchmarking using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn addition(_i: u32, ) -> Weight { + (337_000 as Weight) + } + fn subtraction(_i: u32, ) -> Weight { + (343_000 as Weight) + } + fn multiplication(_i: u32, ) -> Weight { + (340_000 as Weight) + } + fn division(_i: u32, ) -> Weight { + (346_000 as Weight) + } + fn hashing(_i: u32, ) -> Weight { + (35_449_143_000 as Weight) + } + // Storage: Skipped Metadata (r:0 w:0) + fn storage_read(i: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 3_000 + .saturating_add((2_851_000 as Weight).saturating_mul(i as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) + } + // Storage: Skipped Metadata (r:0 w:0) + fn storage_write(i: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((662_000 as Weight).saturating_mul(i as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn addition(_i: u32, ) -> Weight { + (337_000 as Weight) + } + fn subtraction(_i: u32, ) -> Weight { + (343_000 as Weight) + } + fn multiplication(_i: u32, ) -> Weight { + (340_000 as Weight) + } + fn division(_i: u32, ) -> Weight { + (346_000 as Weight) + } + fn hashing(_i: u32, ) -> Weight { + (35_449_143_000 as Weight) + } + // Storage: Skipped Metadata (r:0 w:0) + fn storage_read(i: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 3_000 + .saturating_add((2_851_000 as Weight).saturating_mul(i as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) + } + // Storage: Skipped Metadata (r:0 w:0) + fn storage_write(i: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((662_000 as Weight).saturating_mul(i as Weight)) + .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) + } +} From e11a670b0310130c329ab32a6e16608f5712113d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 30 Oct 2021 15:09:56 +0200 Subject: [PATCH 0159/1472] pallet-utility: Fix possible mismatch between native/wasm (#10121) * pallet-utility: Fix possible mismatch between native/wasm The `batched_calls_limit` constant value includes the `size_of` of the runtime `Call`. As we compile the runtime for native/wasm, we need to align the call size to ensure that it is the same on wasm/native. This also solves the problem of different metadata outputs for the same runtime. * Review feedback --- frame/utility/src/lib.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 54de87c4740c8..8712cf74f451b 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -112,12 +112,19 @@ pub mod pallet { ItemCompleted, } + // Align the call size to 1KB. As we are currently compiling the runtime for native/wasm + // the `size_of` of the `Call` can be different. To ensure that this don't leads to + // mismatches between native/wasm or to different metadata for the same runtime, we + // algin the call size. The value is choosen big enough to hopefully never reach it. + const CALL_ALIGN: u32 = 1024; + #[pallet::extra_constants] impl Pallet { /// The limit on the number of batched calls. fn batched_calls_limit() -> u32 { let allocator_limit = sp_core::MAX_POSSIBLE_ALLOCATION; - let call_size = core::mem::size_of::<::Call>() as u32; + let call_size = ((sp_std::mem::size_of::<::Call>() as u32 + CALL_ALIGN - + 1) / CALL_ALIGN) * CALL_ALIGN; // The margin to take into account vec doubling capacity. let margin_factor = 3; @@ -125,6 +132,18 @@ pub mod pallet { } } + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + // If you hit this error, you need to try to `Box` big dispatchable parameters. + assert!( + sp_std::mem::size_of::<::Call>() as u32 <= CALL_ALIGN, + "Call enum size should be smaller than {} bytes.", + CALL_ALIGN, + ); + } + } + #[pallet::error] pub enum Error { /// Too many calls batched. From 794e9a91927dda5ffa6b29b1771ccdde947af7a2 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Sun, 31 Oct 2021 11:36:26 +0100 Subject: [PATCH 0160/1472] fix query details (#10107) --- frame/transaction-payment/src/lib.rs | 59 ++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 28200bee7054f..59d94a823723b 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -403,7 +403,7 @@ where /// /// All dispatchables must be annotated with weight and will have some fee info. This function /// always returns. - pub fn query_info( + pub fn query_info( unchecked_extrinsic: Extrinsic, len: u32, ) -> RuntimeDispatchInfo> @@ -417,14 +417,20 @@ where // a very very little potential gain in the future. let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); - let partial_fee = Self::compute_fee(len, &dispatch_info, 0u32.into()); + let partial_fee = if unchecked_extrinsic.is_signed().unwrap_or(false) { + Self::compute_fee(len, &dispatch_info, 0u32.into()) + } else { + // Unsigned extrinsics have no partial fee. + 0u32.into() + }; + let DispatchInfo { weight, class, .. } = dispatch_info; RuntimeDispatchInfo { weight, class, partial_fee } } /// Query the detailed fee of a given `call`. - pub fn query_fee_details( + pub fn query_fee_details( unchecked_extrinsic: Extrinsic, len: u32, ) -> FeeDetails> @@ -432,7 +438,15 @@ where T::Call: Dispatchable, { let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); - Self::compute_fee_details(len, &dispatch_info, 0u32.into()) + + let tip = 0u32.into(); + + if unchecked_extrinsic.is_signed().unwrap_or(false) { + Self::compute_fee_details(len, &dispatch_info, tip) + } else { + // Unsigned extrinsics have no inclusion fee. + FeeDetails { inclusion_fee: None, tip } + } } /// Compute the final fee value for a particular transaction. @@ -1141,20 +1155,24 @@ mod tests { } #[test] - fn query_info_works() { + fn query_info_and_fee_details_works() { let call = Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); let origin = 111111; let extra = (); - let xt = TestXt::new(call, Some((origin, extra))); + let xt = TestXt::new(call.clone(), Some((origin, extra))); let info = xt.get_dispatch_info(); let ext = xt.encode(); let len = ext.len() as u32; + + let unsigned_xt = TestXt::<_, ()>::new(call, None); + let unsigned_xt_info = unsigned_xt.get_dispatch_info(); + ExtBuilder::default().base_weight(5).weight_fee(2).build().execute_with(|| { // all fees should be x1.5 >::put(Multiplier::saturating_from_rational(3, 2)); assert_eq!( - TransactionPayment::query_info(xt, len), + TransactionPayment::query_info(xt.clone(), len), RuntimeDispatchInfo { weight: info.weight, class: info.class, @@ -1163,6 +1181,33 @@ mod tests { + info.weight.min(BlockWeights::get().max_block) as u64 * 2 * 3 / 2 /* weight */ }, ); + + assert_eq!( + TransactionPayment::query_info(unsigned_xt.clone(), len), + RuntimeDispatchInfo { + weight: unsigned_xt_info.weight, + class: unsigned_xt_info.class, + partial_fee: 0, + }, + ); + + assert_eq!( + TransactionPayment::query_fee_details(xt, len), + FeeDetails { + inclusion_fee: Some(InclusionFee { + base_fee: 5 * 2, + len_fee: len as u64, + adjusted_weight_fee: info.weight.min(BlockWeights::get().max_block) as u64 * + 2 * 3 / 2 + }), + tip: 0, + }, + ); + + assert_eq!( + TransactionPayment::query_fee_details(unsigned_xt, len), + FeeDetails { inclusion_fee: None, tip: 0 }, + ); }); } From 1f1fc455d17f3640be562fc4639a6b74da71f655 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Sun, 31 Oct 2021 14:55:10 +0100 Subject: [PATCH 0161/1472] Automatic pallet parts in construct_runtime (#9681) * implement automatic parts * ui tests * rename * remove unnecessary exclude * better doc * better doc * fix genesis config * fix UI tests * fix UI test * Revert "fix UI test" This reverts commit a910351c0b24cfe42195cfd97d83a416640e3259. * implemented used_parts * Update frame/support/procedural/src/construct_runtime/mod.rs Co-authored-by: Keith Yeung * doc + fmt * Update frame/support/procedural/src/construct_runtime/parse.rs Co-authored-by: Keith Yeung * add doc in the macro * remove yet some more parts * fix ui test * more determnistic error message + fix ui tests * fix ui test * Apply suggestions from code review Co-authored-by: Keith Yeung * do refactor + fix ui tests * fmt * fix test * fix test * fix ui test * Apply suggestions from code review Co-authored-by: Keith Yeung * refactor * remove even more part in node-runtime * fix test * Add flow chart for the construct_runtime! execution flow * Fix typo * Ignore snippets that don't contain code * Refactor some code in expand_after * Rename expand_after to match_and_insert * cargo fmt * Fix rename * Remove frame_support argument to construct_runtime_parts * Make use of tt-call to simplify intermediate expansions * cargo fmt * Update match_and_insert documentation * Reset cursor to 0 when no matching patterns are found * Reorder struct fields on MatchAndInsertDef * Add test for dependency renames and fix frame-support import * Add more doc comments * Update frame/support/test/compile_pass/src/lib.rs Co-authored-by: Guillaume Thiolliere Co-authored-by: Keith Yeung Co-authored-by: Shawn Tabrizi --- Cargo.lock | 20 + Cargo.toml | 3 +- bin/node/cli/src/chain_spec.rs | 2 + bin/node/runtime/src/lib.rs | 80 ++-- bin/node/testing/src/genesis.rs | 2 + frame/support/Cargo.toml | 1 + .../procedural/src/construct_runtime/mod.rs | 262 +++++++++----- .../procedural/src/construct_runtime/parse.rs | 341 ++++++++++++++++-- frame/support/procedural/src/lib.rs | 128 +++++-- .../procedural/src/match_and_insert.rs | 159 ++++++++ .../procedural/src/pallet/expand/mod.rs | 3 + .../src/pallet/expand/tt_default_parts.rs | 82 +++++ frame/support/src/lib.rs | 4 +- frame/support/test/compile_pass/Cargo.toml | 30 ++ frame/support/test/compile_pass/src/lib.rs | 92 +++++ .../both_use_and_excluded_parts.rs | 33 ++ .../both_use_and_excluded_parts.stderr | 28 ++ .../construct_runtime_ui/duplicate_exclude.rs | 13 + .../duplicate_exclude.stderr | 5 + .../construct_runtime_ui/exclude_missspell.rs | 13 + .../exclude_missspell.stderr | 5 + .../exclude_undefined_part.rs | 38 ++ .../exclude_undefined_part.stderr | 28 ++ .../invalid_module_details.stderr | 6 +- .../invalid_token_after_module.stderr | 2 +- .../old_unsupported_pallet_decl.rs | 26 ++ .../old_unsupported_pallet_decl.stderr | 31 ++ .../use_undefined_part.rs | 38 ++ .../use_undefined_part.stderr | 28 ++ frame/support/test/tests/pallet.rs | 35 +- frame/support/test/tests/pallet_instance.rs | 15 +- 31 files changed, 1335 insertions(+), 218 deletions(-) create mode 100644 frame/support/procedural/src/match_and_insert.rs create mode 100644 frame/support/procedural/src/pallet/expand/tt_default_parts.rs create mode 100644 frame/support/test/compile_pass/Cargo.toml create mode 100644 frame/support/test/compile_pass/src/lib.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr create mode 100644 frame/support/test/tests/construct_runtime_ui/duplicate_exclude.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/duplicate_exclude.stderr create mode 100644 frame/support/test/tests/construct_runtime_ui/exclude_missspell.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/exclude_missspell.stderr create mode 100644 frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr create mode 100644 frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.stderr create mode 100644 frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr diff --git a/Cargo.lock b/Cargo.lock index c3cfaec19532e..84ad0c0a563c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2058,6 +2058,7 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-tracing", + "tt-call", ] [[package]] @@ -2113,6 +2114,19 @@ dependencies = [ "trybuild", ] +[[package]] +name = "frame-support-test-compile-pass" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-version", +] + [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" @@ -10803,6 +10817,12 @@ dependencies = [ "toml", ] +[[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.1" diff --git a/Cargo.toml b/Cargo.toml index 71473a4bc5689..4a228203159eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -120,6 +120,7 @@ members = [ "frame/support/procedural/tools", "frame/support/procedural/tools/derive", "frame/support/test", + "frame/support/test/compile_pass", "frame/system", "frame/system/benchmarking", "frame/system/rpc/runtime-api", @@ -271,4 +272,4 @@ yamux = { opt-level = 3 } zeroize = { opt-level = 3 } [profile.release] # Substrate runtime requires unwinding. -panic = "unwind" \ No newline at end of file +panic = "unwind" diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 8499c66e0c9dc..7b1ed90017c36 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -364,6 +364,8 @@ pub fn testnet_genesis( assets: Default::default(), gilt: Default::default(), transaction_storage: Default::default(), + scheduler: Default::default(), + transaction_payment: Default::default(), } } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 9154ef6ca53df..c0ad9bb006c92 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1248,47 +1248,47 @@ construct_runtime!( NodeBlock = node_primitives::Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Utility: pallet_utility::{Pallet, Call, Event}, - Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, - Indices: pallet_indices::{Pallet, Call, Storage, Config, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, - ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event, ValidateUnsigned}, - Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, - Session: pallet_session::{Pallet, Call, Storage, Event, Config}, - Democracy: pallet_democracy::{Pallet, Call, Storage, Config, Event}, - Council: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config}, - TechnicalCommittee: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config}, - Elections: pallet_elections_phragmen::{Pallet, Call, Storage, Event, Config}, - TechnicalMembership: pallet_membership::::{Pallet, Call, Storage, Event, Config}, - Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned}, - Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event}, - Contracts: pallet_contracts::{Pallet, Call, Storage, Event}, - Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event}, - ImOnline: pallet_im_online::{Pallet, Call, Storage, Event, ValidateUnsigned, Config}, - AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config}, - Offences: pallet_offences::{Pallet, Storage, Event}, + System: frame_system, + Utility: pallet_utility, + Babe: pallet_babe, + Timestamp: pallet_timestamp, + Authorship: pallet_authorship, + Indices: pallet_indices, + Balances: pallet_balances, + TransactionPayment: pallet_transaction_payment, + ElectionProviderMultiPhase: pallet_election_provider_multi_phase, + Staking: pallet_staking, + Session: pallet_session, + Democracy: pallet_democracy, + Council: pallet_collective::, + TechnicalCommittee: pallet_collective::, + Elections: pallet_elections_phragmen, + TechnicalMembership: pallet_membership::, + Grandpa: pallet_grandpa, + Treasury: pallet_treasury, + Contracts: pallet_contracts, + Sudo: pallet_sudo, + ImOnline: pallet_im_online, + AuthorityDiscovery: pallet_authority_discovery, + Offences: pallet_offences, Historical: pallet_session_historical::{Pallet}, - RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage}, - Identity: pallet_identity::{Pallet, Call, Storage, Event}, - Society: pallet_society::{Pallet, Call, Storage, Event, Config}, - Recovery: pallet_recovery::{Pallet, Call, Storage, Event}, - Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config}, - Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event}, - Proxy: pallet_proxy::{Pallet, Call, Storage, Event}, - Multisig: pallet_multisig::{Pallet, Call, Storage, Event}, - Bounties: pallet_bounties::{Pallet, Call, Storage, Event}, - Tips: pallet_tips::{Pallet, Call, Storage, Event}, - Assets: pallet_assets::{Pallet, Call, Storage, Event, Config}, - Mmr: pallet_mmr::{Pallet, Storage}, - Lottery: pallet_lottery::{Pallet, Call, Storage, Event}, - Gilt: pallet_gilt::{Pallet, Call, Storage, Event, Config}, - Uniques: pallet_uniques::{Pallet, Call, Storage, Event}, - TransactionStorage: pallet_transaction_storage::{Pallet, Call, Storage, Inherent, Config, Event}, - BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, + RandomnessCollectiveFlip: pallet_randomness_collective_flip, + Identity: pallet_identity, + Society: pallet_society, + Recovery: pallet_recovery, + Vesting: pallet_vesting, + Scheduler: pallet_scheduler, + Proxy: pallet_proxy, + Multisig: pallet_multisig, + Bounties: pallet_bounties, + Tips: pallet_tips, + Assets: pallet_assets, + Mmr: pallet_mmr, + Lottery: pallet_lottery, + Gilt: pallet_gilt, + Uniques: pallet_uniques, + TransactionStorage: pallet_transaction_storage, + BagsList: pallet_bags_list, } ); diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index 845227c5acee9..80399a6670e86 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -101,5 +101,7 @@ pub fn config_endowed( assets: Default::default(), gilt: Default::default(), transaction_storage: Default::default(), + scheduler: Default::default(), + transaction_payment: Default::default(), } } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index edb0ecd6442e8..4bc64d8b8e73a 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -25,6 +25,7 @@ sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primi sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } +tt-call = "1.0.8" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 863df34266591..4315d4278183a 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -15,115 +15,205 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Implementation of `construct_runtime`. +//! +//! `construct_runtime` implementation is recursive and can generate code which will call itself in +//! order to get all the pallet parts for each pallet. +//! +//! Pallets define their parts (`Call`, `Storage`, ..) either explicitly with the syntax +//! `::{Call, ...}` or implicitly. +//! +//! In case a pallet defines its parts implicitly, then the pallet must provide the +//! `tt_default_parts` macro. `construct_rutime` will generate some code which utilizes `tt_call` +//! to call the `tt_default_parts` macro of the pallet. `tt_default_parts` will then return the +//! default pallet parts as input tokens to the `match_and_replace` macro, which ultimately +//! generates a call to `construct_runtime` again, this time with all the pallet parts explicitly +//! defined. +//! +//! E.g. +//! ```ignore +//! construct_runtime!( +//! //... +//! { +//! System: frame_system = 0, // Implicit definition of parts +//! Balances: pallet_balances = 1, // Implicit definition of parts +//! } +//! ); +//! ``` +//! This call has some implicit pallet parts, thus it will expand to: +//! ```ignore +//! frame_support::tt_call! { +//! macro = [{ pallet_balances::tt_default_parts }] +//! ~~> frame_support::match_and_insert! { +//! target = [{ +//! frame_support::tt_call! { +//! macro = [{ frame_system::tt_default_parts }] +//! ~~> frame_support::match_and_insert! { +//! target = [{ +//! construct_runtime!( +//! //... +//! { +//! System: frame_system = 0, +//! Balances: pallet_balances = 1, +//! } +//! ); +//! }] +//! pattern = [{ System: frame_system }] +//! } +//! } +//! }] +//! pattern = [{ Balances: pallet_balances }] +//! } +//! } +//! ``` +//! `tt_default_parts` must be defined. It returns the pallet parts inside some tokens, and +//! then `tt_call` will pipe the returned pallet parts into the input of `match_and_insert`. +//! Thus `match_and_insert` will initially receive the following inputs: +//! ```ignore +//! frame_support::match_and_insert! { +//! target = [{ +//! frame_support::match_and_insert! { +//! target = [{ +//! construct_runtime!( +//! //... +//! { +//! System: frame_system = 0, +//! Balances: pallet_balances = 1, +//! } +//! ) +//! }] +//! pattern = [{ System: frame_system }] +//! tokens = [{ ::{Pallet, Call} }] +//! }] +//! pattern = [{ Balances: pallet_balances }] +//! tokens = [{ ::{Pallet, Call} }] +//! } +//! ``` +//! After dealing with `pallet_balances`, the inner `match_and_insert` will expand to: +//! ```ignore +//! frame_support::match_and_insert! { +//! target = [{ +//! construct_runtime!( +//! //... +//! { +//! System: frame_system = 0, // Implicit definition of parts +//! Balances: pallet_balances::{Pallet, Call} = 1, // Explicit definition of parts +//! } +//! ) +//! }] +//! pattern = [{ System: frame_system }] +//! tokens = [{ ::{Pallet, Call} }] +//! } +//! ``` +//! Which will then finally expand to the following: +//! ```ignore +//! construct_runtime!( +//! //... +//! { +//! System: frame_system::{Pallet, Call}, +//! Balances: pallet_balances::{Pallet, Call}, +//! } +//! ) +//! ``` +//! This call has no implicit pallet parts, thus it will expand to the runtime construction: +//! ```ignore +//! pub struct Runtime { ... } +//! pub struct Call { ... } +//! impl Call ... +//! pub enum Origin { ... } +//! ... +//! ``` +//! +//! Visualizing the entire flow of `construct_runtime!`, it would look like the following: +//! +//! ```ignore +//! +--------------------+ +---------------------+ +-------------------+ +//! | | | (defined in pallet) | | | +//! | construct_runtime! | --> | tt_default_parts! | --> | match_and_insert! | +//! | w/ no pallet parts | | | | | +//! +--------------------+ +---------------------+ +-------------------+ +//! +//! +--------------------+ +//! | | +//! --> | construct_runtime! | +//! | w/ pallet parts | +//! +--------------------+ +//! ``` + mod expand; mod parse; use frame_support_procedural_tools::{ - generate_crate_access, generate_hidden_includes, syn_ext as ext, + generate_crate_access, generate_crate_access_2018, generate_hidden_includes, +}; +use parse::{ + ExplicitRuntimeDeclaration, ImplicitRuntimeDeclaration, Pallet, RuntimeDeclaration, + WhereSection, }; -use parse::{PalletDeclaration, PalletPart, PalletPath, RuntimeDefinition, WhereSection}; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use std::collections::HashMap; use syn::{Ident, Result}; /// The fixed name of the system pallet. const SYSTEM_PALLET_NAME: &str = "System"; -/// The complete definition of a pallet with the resulting fixed index. -#[derive(Debug, Clone)] -pub struct Pallet { - pub name: Ident, - pub index: u8, - pub path: PalletPath, - pub instance: Option, - pub pallet_parts: Vec, -} - -impl Pallet { - /// Get resolved pallet parts - fn pallet_parts(&self) -> &[PalletPart] { - &self.pallet_parts - } +/// Implementation of `construct_runtime` macro. Either expand to some code which will call +/// `construct_runtime` again, or expand to the final runtime definition. +pub fn construct_runtime(input: TokenStream) -> TokenStream { + let input_copy = input.clone(); + let definition = syn::parse_macro_input!(input as RuntimeDeclaration); - /// Find matching parts - fn find_part(&self, name: &str) -> Option<&PalletPart> { - self.pallet_parts.iter().find(|part| part.name() == name) - } + let res = match definition { + RuntimeDeclaration::Implicit(implicit_def) => + construct_runtime_intermediary_expansion(input_copy.into(), implicit_def), + RuntimeDeclaration::Explicit(explicit_decl) => + construct_runtime_final_expansion(explicit_decl), + }; - /// Return whether pallet contains part - fn exists_part(&self, name: &str) -> bool { - self.find_part(name).is_some() - } + res.unwrap_or_else(|e| e.to_compile_error()).into() } -/// Convert from the parsed pallet to their final information. -/// Assign index to each pallet using same rules as rust for fieldless enum. -/// I.e. implicit are assigned number incrementedly from last explicit or 0. -fn complete_pallets(decl: impl Iterator) -> syn::Result> { - let mut indices = HashMap::new(); - let mut last_index: Option = None; - let mut names = HashMap::new(); - - decl.map(|pallet| { - let final_index = match pallet.index { - Some(i) => i, - None => last_index.map_or(Some(0), |i| i.checked_add(1)).ok_or_else(|| { - let msg = "Pallet index doesn't fit into u8, index is 256"; - syn::Error::new(pallet.name.span(), msg) - })?, - }; - - last_index = Some(final_index); - - if let Some(used_pallet) = indices.insert(final_index, pallet.name.clone()) { - let msg = format!( - "Pallet indices are conflicting: Both pallets {} and {} are at index {}", - used_pallet, pallet.name, final_index, - ); - let mut err = syn::Error::new(used_pallet.span(), &msg); - err.combine(syn::Error::new(pallet.name.span(), msg)); - return Err(err) - } - - if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) { - let msg = "Two pallets with the same name!"; - - let mut err = syn::Error::new(used_pallet, &msg); - err.combine(syn::Error::new(pallet.name.span(), &msg)); - return Err(err) - } - - Ok(Pallet { - name: pallet.name, - index: final_index, - path: pallet.path, - instance: pallet.instance, - pallet_parts: pallet.pallet_parts, - }) - }) - .collect() -} +/// When some pallet have implicit parts definition then the macro will expand into a macro call to +/// `construct_runtime_args` of each pallets, see root documentation. +fn construct_runtime_intermediary_expansion( + input: TokenStream2, + definition: ImplicitRuntimeDeclaration, +) -> Result { + let frame_support = generate_crate_access_2018("frame-support")?; + let mut expansion = quote::quote!( + #frame_support::construct_runtime! { #input } + ); + for pallet in definition.pallets.iter().filter(|pallet| pallet.pallet_parts.is_none()) { + let pallet_path = &pallet.path; + let pallet_name = &pallet.name; + let pallet_instance = pallet.instance.as_ref().map(|instance| quote::quote!(::<#instance>)); + expansion = quote::quote!( + #frame_support::tt_call! { + macro = [{ #pallet_path::tt_default_parts }] + frame_support = [{ #frame_support }] + ~~> #frame_support::match_and_insert! { + target = [{ #expansion }] + pattern = [{ #pallet_name: #pallet_path #pallet_instance }] + } + } + ); + } -pub fn construct_runtime(input: TokenStream) -> TokenStream { - let definition = syn::parse_macro_input!(input as RuntimeDefinition); - construct_runtime_parsed(definition) - .unwrap_or_else(|e| e.to_compile_error()) - .into() + Ok(expansion.into()) } -fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result { - let RuntimeDefinition { +/// All pallets have explicit definition of parts, this will expand to the runtime declaration. +fn construct_runtime_final_expansion( + definition: ExplicitRuntimeDeclaration, +) -> Result { + let ExplicitRuntimeDeclaration { name, - where_section: WhereSection { block, node_block, unchecked_extrinsic, .. }, - pallets: - ext::Braces { content: ext::Punctuated { inner: pallets, .. }, token: pallets_token }, - .. + where_section: WhereSection { block, node_block, unchecked_extrinsic }, + pallets, + pallets_token, } = definition; - let pallets = complete_pallets(pallets.into_iter())?; - let hidden_crate_name = "construct_runtime"; let scrate = generate_crate_access(&hidden_crate_name, "frame-support"); let scrate_decl = generate_hidden_includes(&hidden_crate_name, "frame-support"); diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index a0ec6dfa5803e..f80b7b1ac554c 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -17,13 +17,13 @@ use frame_support_procedural_tools::syn_ext as ext; use proc_macro2::{Span, TokenStream}; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use syn::{ ext::IdentExt, parse::{Parse, ParseStream}, punctuated::Punctuated, spanned::Spanned, - token, Error, Ident, Path, PathArguments, PathSegment, Result, Token, + token, Error, Ident, Path, Result, Token, }; mod keyword { @@ -38,26 +38,63 @@ mod keyword { syn::custom_keyword!(Origin); syn::custom_keyword!(Inherent); syn::custom_keyword!(ValidateUnsigned); + syn::custom_keyword!(exclude_parts); + syn::custom_keyword!(use_parts); } +/// Declaration of a runtime. +/// +/// Pallet declare their part either explicitly or implicitly (using no part declaration) +/// If all pallet have explicit parts then the runtime declaration is explicit, otherwise it is +/// implicit. +#[derive(Debug)] +pub enum RuntimeDeclaration { + Implicit(ImplicitRuntimeDeclaration), + Explicit(ExplicitRuntimeDeclaration), +} + +/// Declaration of a runtime with some pallet with implicit declaration of parts. +#[derive(Debug)] +pub struct ImplicitRuntimeDeclaration { + pub name: Ident, + pub where_section: WhereSection, + pub pallets: Vec, +} + +/// Declaration of a runtime with all pallet having explicit declaration of parts. #[derive(Debug)] -pub struct RuntimeDefinition { - pub visibility_token: Token![pub], - pub enum_token: Token![enum], +pub struct ExplicitRuntimeDeclaration { pub name: Ident, pub where_section: WhereSection, - pub pallets: ext::Braces>, + pub pallets: Vec, + pub pallets_token: token::Brace, } -impl Parse for RuntimeDefinition { +impl Parse for RuntimeDeclaration { fn parse(input: ParseStream) -> Result { - Ok(Self { - visibility_token: input.parse()?, - enum_token: input.parse()?, - name: input.parse()?, - where_section: input.parse()?, - pallets: input.parse()?, - }) + input.parse::()?; + input.parse::()?; + let name = input.parse::()?; + let where_section = input.parse()?; + let pallets = + input.parse::>>()?; + let pallets_token = pallets.token; + + match convert_pallets(pallets.content.inner.into_iter().collect())? { + PalletsConversion::Implicit(pallets) => + Ok(RuntimeDeclaration::Implicit(ImplicitRuntimeDeclaration { + name, + where_section, + pallets, + })), + PalletsConversion::Explicit(pallets) => + Ok(RuntimeDeclaration::Explicit(ExplicitRuntimeDeclaration { + name, + where_section, + pallets, + pallets_token, + })), + } } } @@ -136,14 +173,34 @@ impl Parse for WhereDefinition { } } +/// The declaration of a pallet. #[derive(Debug, Clone)] pub struct PalletDeclaration { + /// The name of the pallet, e.g.`System` in `System: frame_system`. pub name: Ident, - /// Optional fixed index (e.g. `MyPallet ... = 3,`) + /// Optional fixed index, e.g. `MyPallet ... = 3,`. pub index: Option, + /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. pub path: PalletPath, + /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. pub instance: Option, - pub pallet_parts: Vec, + /// The declared pallet parts, + /// e.g. `Some([Pallet, Call])` for `System: system::{Pallet, Call}` + /// or `None` for `System: system`. + pub pallet_parts: Option>, + /// The specified parts, either use_parts or exclude_parts. + pub specified_parts: SpecifiedParts, +} + +/// The possible declaration of pallet parts to use. +#[derive(Debug, Clone)] +pub enum SpecifiedParts { + /// Use all the pallet parts except those specified. + Exclude(Vec), + /// Use only the specified pallet parts. + Use(Vec), + /// Use the all the pallet parts. + All, } impl Parse for PalletDeclaration { @@ -151,38 +208,78 @@ impl Parse for PalletDeclaration { let name = input.parse()?; let _: Token![:] = input.parse()?; let path = input.parse()?; - let instance = if input.peek(Token![<]) { + + // Parse for instance. + let instance = if input.peek(Token![::]) && input.peek3(Token![<]) { + let _: Token![::] = input.parse()?; let _: Token![<] = input.parse()?; let res = Some(input.parse()?); let _: Token![>] = input.parse()?; - let _: Token![::] = input.parse()?; res + } else if !(input.peek(Token![::]) && input.peek3(token::Brace)) && + !input.peek(keyword::exclude_parts) && + !input.peek(keyword::use_parts) && + !input.peek(Token![=]) && + !input.peek(Token![,]) && + !input.is_empty() + { + return Err(input.error( + "Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`", + )) } else { None }; - let pallet_parts = parse_pallet_parts(input)?; + // Parse for explicit parts + let pallet_parts = if input.peek(Token![::]) && input.peek3(token::Brace) { + let _: Token![::] = input.parse()?; + Some(parse_pallet_parts(input)?) + } else if !input.peek(keyword::exclude_parts) && + !input.peek(keyword::use_parts) && + !input.peek(Token![=]) && + !input.peek(Token![,]) && + !input.is_empty() + { + return Err(input.error( + "Unexpected tokens, expected one of `::{`, `exclude_parts`, `use_parts`, `=`, `,`", + )) + } else { + None + }; + + // Parse for specified parts + let specified_parts = if input.peek(keyword::exclude_parts) { + let _: keyword::exclude_parts = input.parse()?; + SpecifiedParts::Exclude(parse_pallet_parts_no_generic(input)?) + } else if input.peek(keyword::use_parts) { + let _: keyword::use_parts = input.parse()?; + SpecifiedParts::Use(parse_pallet_parts_no_generic(input)?) + } else if !input.peek(Token![=]) && !input.peek(Token![,]) && !input.is_empty() { + return Err(input.error("Unexpected tokens, expected one of `exclude_parts`, `=`, `,`")) + } else { + SpecifiedParts::All + }; + // Parse for pallet index let index = if input.peek(Token![=]) { input.parse::()?; let index = input.parse::()?; let index = index.base10_parse::()?; Some(index) + } else if !input.peek(Token![,]) && !input.is_empty() { + return Err(input.error("Unexpected tokens, expected one of `=`, `,`")) } else { None }; - let parsed = Self { name, path, instance, pallet_parts, index }; - - Ok(parsed) + Ok(Self { name, path, instance, pallet_parts, specified_parts, index }) } } /// A struct representing a path to a pallet. `PalletPath` is almost identical to the standard /// Rust path with a few restrictions: /// - No leading colons allowed -/// - Path segments can only consist of identifers; angle-bracketed or parenthesized segments will -/// result in a parsing error (except when specifying instances) +/// - Path segments can only consist of identifers separated by colons #[derive(Debug, Clone)] pub struct PalletPath { pub inner: Path, @@ -202,34 +299,27 @@ impl PalletPath { impl Parse for PalletPath { fn parse(input: ParseStream) -> Result { - let mut lookahead = input.lookahead1(); - let mut segments = Punctuated::new(); + let mut res = + PalletPath { inner: Path { leading_colon: None, segments: Punctuated::new() } }; + let lookahead = input.lookahead1(); if lookahead.peek(Token![crate]) || lookahead.peek(Token![self]) || lookahead.peek(Token![super]) || lookahead.peek(Ident) { let ident = input.call(Ident::parse_any)?; - segments.push(PathSegment { ident, arguments: PathArguments::None }); - let _: Token![::] = input.parse()?; - lookahead = input.lookahead1(); + res.inner.segments.push(ident.into()); } else { return Err(lookahead.error()) } - while lookahead.peek(Ident) { - let ident = input.parse()?; - segments.push(PathSegment { ident, arguments: PathArguments::None }); - let _: Token![::] = input.parse()?; - lookahead = input.lookahead1(); - } - - if !lookahead.peek(token::Brace) && !lookahead.peek(Token![<]) { - return Err(lookahead.error()) + while input.peek(Token![::]) && input.peek3(Ident) { + input.parse::()?; + let ident = input.parse::()?; + res.inner.segments.push(ident.into()); } - - Ok(Self { inner: Path { leading_colon: None, segments } }) + Ok(res) } } @@ -391,3 +481,174 @@ fn remove_kind( Err(input.error(msg)) } } + +/// The declaration of a part without its generics +#[derive(Debug, Clone)] +pub struct PalletPartNoGeneric { + keyword: PalletPartKeyword, +} + +impl Parse for PalletPartNoGeneric { + fn parse(input: ParseStream) -> Result { + Ok(Self { keyword: input.parse()? }) + } +} + +/// Parse [`PalletPartNoGeneric`]'s from a braces enclosed list that is split by commas, e.g. +/// +/// `{ Call, Event }` +fn parse_pallet_parts_no_generic(input: ParseStream) -> Result> { + let pallet_parts: ext::Braces> = + input.parse()?; + + let mut resolved = HashSet::new(); + for part in pallet_parts.content.inner.iter() { + if !resolved.insert(part.keyword.name()) { + let msg = format!( + "`{}` was already declared before. Please remove the duplicate declaration", + part.keyword.name(), + ); + return Err(Error::new(part.keyword.span(), msg)) + } + } + + Ok(pallet_parts.content.inner.into_iter().collect()) +} + +/// The final definition of a pallet with the resulting fixed index and explicit parts. +#[derive(Debug, Clone)] +pub struct Pallet { + /// The name of the pallet, e.g.`System` in `System: frame_system`. + pub name: Ident, + /// Either automatically infered, or defined (e.g. `MyPallet ... = 3,`). + pub index: u8, + /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. + pub path: PalletPath, + /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. + pub instance: Option, + /// The pallet parts to use for the pallet. + pub pallet_parts: Vec, +} + +impl Pallet { + /// Get resolved pallet parts + pub fn pallet_parts(&self) -> &[PalletPart] { + &self.pallet_parts + } + + /// Find matching parts + pub fn find_part(&self, name: &str) -> Option<&PalletPart> { + self.pallet_parts.iter().find(|part| part.name() == name) + } + + /// Return whether pallet contains part + pub fn exists_part(&self, name: &str) -> bool { + self.find_part(name).is_some() + } +} + +/// Result of a conversion of a declaration of pallets. +enum PalletsConversion { + Implicit(Vec), + Explicit(Vec), +} + +/// Convert from the parsed pallet declaration to their final information. +/// +/// Check if all pallet have explicit declaration of their parts, if so then assign index to each +/// pallet using same rules as rust for fieldless enum. I.e. implicit are assigned number +/// incrementedly from last explicit or 0. +fn convert_pallets(pallets: Vec) -> syn::Result { + if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) { + return Ok(PalletsConversion::Implicit(pallets)) + } + + let mut indices = HashMap::new(); + let mut last_index: Option = None; + let mut names = HashMap::new(); + + let pallets = pallets + .into_iter() + .map(|pallet| { + let final_index = match pallet.index { + Some(i) => i, + None => last_index.map_or(Some(0), |i| i.checked_add(1)).ok_or_else(|| { + let msg = "Pallet index doesn't fit into u8, index is 256"; + syn::Error::new(pallet.name.span(), msg) + })?, + }; + + last_index = Some(final_index); + + if let Some(used_pallet) = indices.insert(final_index, pallet.name.clone()) { + let msg = format!( + "Pallet indices are conflicting: Both pallets {} and {} are at index {}", + used_pallet, pallet.name, final_index, + ); + let mut err = syn::Error::new(used_pallet.span(), &msg); + err.combine(syn::Error::new(pallet.name.span(), msg)); + return Err(err) + } + + if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) { + let msg = "Two pallets with the same name!"; + + let mut err = syn::Error::new(used_pallet, &msg); + err.combine(syn::Error::new(pallet.name.span(), &msg)); + return Err(err) + } + + let mut pallet_parts = pallet.pallet_parts.expect("Checked above"); + + let available_parts = + pallet_parts.iter().map(|part| part.keyword.name()).collect::>(); + + // Check parts are correctly specified + match &pallet.specified_parts { + SpecifiedParts::Exclude(parts) | SpecifiedParts::Use(parts) => + for part in parts { + if !available_parts.contains(part.keyword.name()) { + let msg = format!( + "Invalid pallet part specified, the pallet `{}` doesn't have the \ + `{}` part. Available parts are: {}.", + pallet.name, + part.keyword.name(), + pallet_parts.iter().fold(String::new(), |fold, part| { + if fold.is_empty() { + format!("`{}`", part.keyword.name()) + } else { + format!("{}, `{}`", fold, part.keyword.name()) + } + }) + ); + return Err(syn::Error::new(part.keyword.span(), msg)) + } + }, + SpecifiedParts::All => (), + } + + // Set only specified parts. + match pallet.specified_parts { + SpecifiedParts::Exclude(excluded_parts) => pallet_parts.retain(|part| { + !excluded_parts + .iter() + .any(|excluded_part| excluded_part.keyword.name() == part.keyword.name()) + }), + SpecifiedParts::Use(used_parts) => pallet_parts.retain(|part| { + used_parts.iter().any(|use_part| use_part.keyword.name() == part.keyword.name()) + }), + SpecifiedParts::All => (), + } + + Ok(Pallet { + name: pallet.name, + index: final_index, + path: pallet.path, + instance: pallet.instance, + pallet_parts, + }) + }) + .collect::>>()?; + + Ok(PalletsConversion::Explicit(pallets)) +} diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 6987fc49b9a8c..d01bbf6ace526 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -26,6 +26,7 @@ mod debug_no_bound; mod default_no_bound; mod dummy_part_checker; mod key_prefix; +mod match_and_insert; mod pallet; mod partial_eq_no_bound; mod storage; @@ -297,52 +298,91 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { /// /// # Example: /// -/// ```nocompile +/// ```ignore /// construct_runtime!( /// pub enum Runtime where /// Block = Block, /// NodeBlock = node::Block, /// UncheckedExtrinsic = UncheckedExtrinsic /// { -/// System: system::{Pallet, Call, Event, Config} = 0, -/// Test: test::{Pallet, Call} = 1, -/// Test2: test_with_long_module::{Pallet, Event}, +/// System: frame_system::{Pallet, Call, Event, Config} = 0, +/// Test: path::to::test::{Pallet, Call} = 1, /// /// // Pallets with instances -/// Test3_Instance1: test3::::{Pallet, Call, Storage, Event, Config, Origin}, -/// Test3_DefaultInstance: test3::{Pallet, Call, Storage, Event, Config, Origin} = 4, +/// Test2_Instance1: test2::::{Pallet, Call, Storage, Event, Config, Origin}, +/// Test2_DefaultInstance: test2::{Pallet, Call, Storage, Event, Config, Origin} = 4, +/// +/// // Pallets declared with `pallet` attribute macro: no need to define the parts +/// Test3_Instance1: test3::, +/// Test3_DefaultInstance: test3, +/// +/// // with `exclude_parts` keyword some part can be excluded. +/// Test4_Instance1: test4:: exclude_parts { Call, Origin }, +/// Test4_DefaultInstance: test4 exclude_parts { Storage }, +/// +/// // with `use_parts` keyword, a subset of the pallet parts can be specified. +/// Test4_Instance1: test4:: use_parts { Pallet, Call}, +/// Test4_DefaultInstance: test4 use_parts { Pallet }, /// } /// ) /// ``` /// -/// The identifier `System` is the name of the pallet and the lower case identifier `system` is the -/// name of the Rust module/crate for this Substrate pallet. The identifiers between the braces are -/// the pallet parts provided by the pallet. It is important to list these parts here to export -/// them correctly in the metadata or to make the pallet usable in the runtime. +/// Each pallet is declared as such: +/// * `Identifier`: name given to the pallet that uniquely identifies it. /// -/// We provide support for the following module parts in a pallet: +/// * `:`: colon separator /// -/// - `Pallet` - Required for all pallets -/// - `Call` - If the pallet has callable functions -/// - `Storage` - If the pallet uses storage -/// - `Event` or `Event` (if the event is generic) - If the pallet emits events -/// - `Origin` or `Origin` (if the origin is generic) - If the pallet has instanciable origins -/// - `Config` or `Config` (if the config is generic) - If the pallet builds the genesis storage -/// with `GenesisConfig` -/// - `Inherent` - If the pallet provides/can check inherents. -/// - `ValidateUnsigned` - If the pallet validates unsigned extrinsics. +/// * `path::to::pallet`: identifiers separated by colons which declare the path to a pallet +/// definition. /// -/// `= $n` is an optional part allowing to define at which index the pallet variants in -/// `OriginCaller`, `Call` and `Event` are encoded, and to define the ModuleToIndex value. +/// * `::` optional: specify the instance of the pallet to use. If not specified it will +/// use the default instance (or the only instance in case of non-instantiable pallets). /// -/// if `= $n` is not given, then index is resolved same as fieldless enum in Rust -/// (i.e. incrementedly from previous index): -/// ```nocompile -/// pallet1 .. = 2, -/// pallet2 .., // Here pallet2 is given index 3 -/// pallet3 .. = 0, -/// pallet4 .., // Here pallet4 is given index 1 -/// ``` +/// * `::{ Part1, Part2, .. }` optional if pallet declared with `frame_support::pallet`: Comma +/// separated parts declared with their generic. If a pallet is declared with +/// `frame_support::pallet` macro then the parts can be automatically derived if not explicitly +/// provided. We provide support for the following module parts in a pallet: +/// +/// - `Pallet` - Required for all pallets +/// - `Call` - If the pallet has callable functions +/// - `Storage` - If the pallet uses storage +/// - `Event` or `Event` (if the event is generic) - If the pallet emits events +/// - `Origin` or `Origin` (if the origin is generic) - If the pallet has instanciable origins +/// - `Config` or `Config` (if the config is generic) - If the pallet builds the genesis +/// storage with `GenesisConfig` +/// - `Inherent` - If the pallet provides/can check inherents. +/// - `ValidateUnsigned` - If the pallet validates unsigned extrinsics. +/// +/// It is important to list these parts here to export them correctly in the metadata or to make +/// the pallet usable in the runtime. +/// +/// * `exclude_parts { Part1, Part2 }` optional: comma separated parts without generics. I.e. one of +/// `Pallet`, `Call`, `Storage`, `Event`, `Origin`, `Config`, `Inherent`, `ValidateUnsigned`. It +/// is incompatible with `use_parts`. This specifies the part to exclude. In order to select +/// subset of the pallet parts. +/// +/// For example excluding the part `Call` can be useful if the runtime doesn't want to make the +/// pallet calls available. +/// +/// * `use_parts { Part1, Part2 }` optional: comma separated parts without generics. I.e. one of +/// `Pallet`, `Call`, `Storage`, `Event`, `Origin`, `Config`, `Inherent`, `ValidateUnsigned`. It +/// is incompatible with `exclude_parts`. This specifies the part to use. In order to select a +/// subset of the pallet parts. +/// +/// For example not using the part `Call` can be useful if the runtime doesn't want to make the +/// pallet calls available. +/// +/// * `= $n` optional: number to define at which index the pallet variants in `OriginCaller`, `Call` +/// and `Event` are encoded, and to define the ModuleToIndex value. +/// +/// if `= $n` is not given, then index is resolved in the same way as fieldless enum in Rust +/// (i.e. incrementedly from previous index): +/// ```nocompile +/// pallet1 .. = 2, +/// pallet2 .., // Here pallet2 is given index 3 +/// pallet3 .. = 0, +/// pallet4 .., // Here pallet4 is given index 1 +/// ``` /// /// # Note /// @@ -352,8 +392,8 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { /// /// # Type definitions /// -/// * The macro generates a type alias for each pallet to their `Module` (or `Pallet`). E.g. `type -/// System = frame_system::Pallet` +/// * The macro generates a type alias for each pallet to their `Pallet`. E.g. `type System = +/// frame_system::Pallet` #[proc_macro] pub fn construct_runtime(input: TokenStream) -> TokenStream { construct_runtime::construct_runtime(input) @@ -498,3 +538,27 @@ pub fn impl_key_prefix_for_tuples(input: TokenStream) -> TokenStream { pub fn __generate_dummy_part_checker(input: TokenStream) -> TokenStream { dummy_part_checker::generate_dummy_part_checker(input) } + +/// Macro that inserts some tokens after the first match of some pattern. +/// +/// # Example: +/// +/// ```nocompile +/// match_and_insert!( +/// target = [{ Some content with { at some point match pattern } other match pattern are ignored }] +/// pattern = [{ match pattern }] // the match pattern cannot contain any group: `[]`, `()`, `{}` +/// // can relax this constraint, but will require modifying the match logic in code +/// tokens = [{ expansion tokens }] // content inside braces can be anything including groups +/// ); +/// ``` +/// +/// will generate: +/// +/// ```nocompile +/// Some content with { at some point match pattern expansion tokens } other match patterns are +/// ignored +/// ``` +#[proc_macro] +pub fn match_and_insert(input: TokenStream) -> TokenStream { + match_and_insert::match_and_insert(input) +} diff --git a/frame/support/procedural/src/match_and_insert.rs b/frame/support/procedural/src/match_and_insert.rs new file mode 100644 index 0000000000000..4ffc596e6dca0 --- /dev/null +++ b/frame/support/procedural/src/match_and_insert.rs @@ -0,0 +1,159 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of the `match_and_insert` macro. + +use proc_macro2::{Group, Span, TokenStream, TokenTree}; +use std::iter::once; +use syn::spanned::Spanned; + +mod keyword { + syn::custom_keyword!(target); + syn::custom_keyword!(pattern); + syn::custom_keyword!(tokens); +} + +pub fn match_and_insert(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let MatchAndInsertDef { pattern, tokens, target } = + syn::parse_macro_input!(input as MatchAndInsertDef); + + match expand_in_stream(&pattern, &mut Some(tokens), target) { + Ok(stream) => stream.into(), + Err(err) => err.to_compile_error().into(), + } +} + +struct MatchAndInsertDef { + // Token stream to search and insert tokens into. + target: TokenStream, + // Pattern to match against, this is ensured to have no TokenTree::Group nor TokenTree::Literal + // (i.e. contains only Punct or Ident), and not being empty. + pattern: Vec, + // Token stream to insert after the match pattern. + tokens: TokenStream, +} + +impl syn::parse::Parse for MatchAndInsertDef { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let mut target; + let _ = input.parse::()?; + let _ = input.parse::()?; + let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(target in input); + let _replace_with_brace: syn::token::Brace = syn::braced!(target in target); + let target = target.parse()?; + + let mut pattern; + let _ = input.parse::()?; + let _ = input.parse::()?; + let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(pattern in input); + let _replace_with_brace: syn::token::Brace = syn::braced!(pattern in pattern); + let pattern = pattern.parse::()?.into_iter().collect::>(); + + if let Some(t) = pattern.iter().find(|t| matches!(t, TokenTree::Group(_))) { + return Err(syn::Error::new(t.span(), "Unexpected group token tree")) + } + if let Some(t) = pattern.iter().find(|t| matches!(t, TokenTree::Literal(_))) { + return Err(syn::Error::new(t.span(), "Unexpected literal token tree")) + } + + if pattern.is_empty() { + return Err(syn::Error::new(Span::call_site(), "empty match pattern is invalid")) + } + + let mut tokens; + let _ = input.parse::()?; + let _ = input.parse::()?; + let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(tokens in input); + let _replace_with_brace: syn::token::Brace = syn::braced!(tokens in tokens); + let tokens = tokens.parse()?; + + Ok(Self { tokens, pattern, target }) + } +} + +// Insert `tokens` after the first matching `pattern`. +// `tokens` must be some (Option is used for internal simplification). +// `pattern` must not be empty and should only contain Ident or Punct. +fn expand_in_stream( + pattern: &[TokenTree], + tokens: &mut Option, + stream: TokenStream, +) -> syn::Result { + assert!( + tokens.is_some(), + "`tokens` must be some, Option is used because `tokens` is used only once" + ); + assert!( + !pattern.is_empty(), + "`pattern` must not be empty, otherwise there is nothing to match against" + ); + + let stream_span = stream.span(); + let mut stream = stream.into_iter(); + let mut extended = TokenStream::new(); + let mut match_cursor = 0; + + while let Some(token) = stream.next() { + match token { + TokenTree::Group(group) => { + match_cursor = 0; + let group_stream = group.stream(); + match expand_in_stream(pattern, tokens, group_stream) { + Ok(s) => { + extended.extend(once(TokenTree::Group(Group::new(group.delimiter(), s)))); + extended.extend(stream); + return Ok(extended) + }, + Err(_) => { + extended.extend(once(TokenTree::Group(group))); + }, + } + }, + other => { + advance_match_cursor(&other, pattern, &mut match_cursor); + + extended.extend(once(other)); + + if match_cursor == pattern.len() { + extended + .extend(once(tokens.take().expect("tokens is used to replace only once"))); + extended.extend(stream); + return Ok(extended) + } + }, + } + } + // if we reach this point, it means the stream is empty and we haven't found a matching pattern + let msg = format!("Cannot find pattern `{:?}` in given token stream", pattern); + Err(syn::Error::new(stream_span, msg)) +} + +fn advance_match_cursor(other: &TokenTree, pattern: &[TokenTree], match_cursor: &mut usize) { + use TokenTree::{Ident, Punct}; + + let does_match_other_pattern = match (other, &pattern[*match_cursor]) { + (Ident(i1), Ident(i2)) => i1 == i2, + (Punct(p1), Punct(p2)) => p1.as_char() == p2.as_char(), + _ => false, + }; + + if does_match_other_pattern { + *match_cursor += 1; + } else { + *match_cursor = 0; + } +} diff --git a/frame/support/procedural/src/pallet/expand/mod.rs b/frame/support/procedural/src/pallet/expand/mod.rs index 083ad61fc5239..21acd3c0dd32e 100644 --- a/frame/support/procedural/src/pallet/expand/mod.rs +++ b/frame/support/procedural/src/pallet/expand/mod.rs @@ -29,6 +29,7 @@ mod origin; mod pallet_struct; mod storage; mod store_trait; +mod tt_default_parts; mod type_value; mod validate_unsigned; @@ -67,6 +68,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { let type_values = type_value::expand_type_values(&mut def); let origins = origin::expand_origins(&mut def); let validate_unsigned = validate_unsigned::expand_validate_unsigned(&mut def); + let tt_default_parts = tt_default_parts::expand_tt_default_parts(&mut def); if get_doc_literals(&def.item.attrs).is_empty() { def.item.attrs.push(syn::parse_quote!( @@ -96,6 +98,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { #type_values #origins #validate_unsigned + #tt_default_parts ); def.item diff --git a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs new file mode 100644 index 0000000000000..cfab7982bfdc9 --- /dev/null +++ b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -0,0 +1,82 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{pallet::Def, COUNTER}; +use syn::spanned::Spanned; + +/// Generate the `tt_default_parts` macro. +pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { + let count = COUNTER.with(|counter| counter.borrow_mut().inc()); + let default_parts_unique_id = + syn::Ident::new(&format!("__tt_default_parts_{}", count), def.item.span()); + + let call_part = def.call.as_ref().map(|_| quote::quote!(Call,)); + + let storage_part = (!def.storages.is_empty()).then(|| quote::quote!(Storage,)); + + let event_part = def.event.as_ref().map(|event| { + let gen = event.gen_kind.is_generic().then(|| quote::quote!( )); + quote::quote!( Event #gen , ) + }); + + let origin_part = def.origin.as_ref().map(|origin| { + let gen = origin.is_generic.then(|| quote::quote!( )); + quote::quote!( Origin #gen , ) + }); + + let config_part = def.genesis_config.as_ref().map(|genesis_config| { + let gen = genesis_config.gen_kind.is_generic().then(|| quote::quote!( )); + quote::quote!( Config #gen , ) + }); + + let inherent_part = def.inherent.as_ref().map(|_| quote::quote!(Inherent,)); + + let validate_unsigned_part = + def.validate_unsigned.as_ref().map(|_| quote::quote!(ValidateUnsigned,)); + + quote::quote!( + // This macro follows the conventions as laid out by the `tt-call` crate. It does not + // accept any arguments and simply returns the pallet parts, separated by commas, then + // wrapped inside of braces and finally prepended with double colons, to the caller inside + // of a key named `tokens`. + // + // We need to accept a frame_support argument here, because this macro gets expanded on the + // crate that called the `construct_runtime!` macro, and said crate may have renamed + // frame-support, and so we need to pass in the frame-support path that said crate + // recognizes. + #[macro_export] + #[doc(hidden)] + macro_rules! #default_parts_unique_id { + { + $caller:tt + frame_support = [{ $($frame_support:ident)::* }] + } => { + $($frame_support)*::tt_return! { + $caller + tokens = [{ + ::{ + Pallet, #call_part #storage_part #event_part #origin_part #config_part + #inherent_part #validate_unsigned_part + } + }] + } + }; + } + + pub use #default_parts_unique_id as tt_default_parts; + ) +} diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 1b93b5fb5975e..d81300a404c4f 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -50,6 +50,8 @@ pub use sp_runtime::RuntimeDebug; pub use sp_state_machine::BasicExternalities; #[doc(hidden)] pub use sp_std; +#[doc(hidden)] +pub use tt_call::*; #[macro_use] pub mod dispatch; @@ -573,7 +575,7 @@ pub fn debug(data: &impl sp_std::fmt::Debug) { #[doc(inline)] pub use frame_support_procedural::{ - construct_runtime, decl_storage, transactional, RuntimeDebugNoBound, + construct_runtime, decl_storage, match_and_insert, transactional, RuntimeDebugNoBound, }; #[doc(hidden)] diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml new file mode 100644 index 0000000000000..bca833200d444 --- /dev/null +++ b/frame/support/test/compile_pass/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "frame-support-test-compile-pass" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +publish = false +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/core" } +sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" } +sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" } +support = { package = "frame-support", version = "4.0.0-dev", default-features = false, path = "../../" } +system = { package = "frame-system", version = "4.0.0-dev", default-features = false, path = "../../../system" } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "support/std", + "system/std", +] diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs new file mode 100644 index 0000000000000..17ba40574adf7 --- /dev/null +++ b/frame/support/test/compile_pass/src/lib.rs @@ -0,0 +1,92 @@ +// This file is part of Substrate. + +// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit = "256"] +//! This crate tests that `construct_runtime!` expands the pallet parts +//! correctly even when frame-support is renamed in Cargo.toml + +use sp_core::{sr25519, H256}; +use sp_runtime::{ + create_runtime_str, generic, + traits::{BlakeTwo256, IdentityLookup, Verify}, +}; +use sp_version::RuntimeVersion; +use support::{construct_runtime, parameter_types}; + +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("frame-support-test-compile-pass"), + impl_name: create_runtime_str!("substrate-frame-support-test-compile-pass-runtime"), + authoring_version: 0, + spec_version: 0, + impl_version: 0, + apis: sp_version::create_apis_vec!([]), + transaction_version: 0, +}; + +pub type Signature = sr25519::Signature; +pub type AccountId = ::Signer; +pub type BlockNumber = u64; +pub type Index = u64; + +parameter_types! { + pub const BlockHashCount: BlockNumber = 2400; + pub const Version: RuntimeVersion = VERSION; + pub const SS58Prefix: u8 = 0; +} + +impl system::Config for Runtime { + type BaseCallFilter = support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type Index = u128; + type Hash = H256; + type Hashing = BlakeTwo256; + type Header = Header; + type Lookup = IdentityLookup; + type BlockHashCount = BlockHashCount; + type Version = Version; + type AccountData = (); + type Origin = Origin; + type BlockNumber = BlockNumber; + type AccountId = AccountId; + type Event = Event; + type PalletInfo = PalletInfo; + type Call = Call; + type DbWeight = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type OnSetCode = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; +} + +pub type Header = generic::Header; +pub type Block = generic::Block; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + +construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system, + } +); diff --git a/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs new file mode 100644 index 0000000000000..98cd1f197f619 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs @@ -0,0 +1,33 @@ +use frame_support::construct_runtime; +use sp_runtime::{generic, traits::BlakeTwo256}; +use sp_core::sr25519; + +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); +} + +pub type Signature = sr25519::Signature; +pub type BlockNumber = u64; +pub type Header = generic::Header; +pub type Block = generic::Block; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + +impl pallet::Config for Runtime {} + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Pallet, Call, Storage, Config, Event}, + Pallet: pallet exclude_parts { Pallet } use_parts { Pallet }, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr new file mode 100644 index 0000000000000..608d57d6a97fc --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr @@ -0,0 +1,28 @@ +error: Unexpected tokens, expected one of `=`, `,` + --> $DIR/both_use_and_excluded_parts.rs:29:43 + | +29 | Pallet: pallet exclude_parts { Pallet } use_parts { Pallet }, + | ^^^^^^^^^ + +error[E0412]: cannot find type `Call` in this scope + --> $DIR/both_use_and_excluded_parts.rs:18:64 + | +18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | ^^^^ not found in this scope + | +help: consider importing one of these items + | +1 | use crate::pallet::Call; + | +1 | use frame_support_test::Call; + | +1 | use frame_system::Call; + | +1 | use test_pallet::Call; + | + +error[E0412]: cannot find type `Runtime` in this scope + --> $DIR/both_use_and_excluded_parts.rs:20:25 + | +20 | impl pallet::Config for Runtime {} + | ^^^^^^^ not found in this scope diff --git a/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.rs b/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.rs new file mode 100644 index 0000000000000..6d21c2a6e170a --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.rs @@ -0,0 +1,13 @@ +use frame_support::construct_runtime; + +construct_runtime! { + pub enum Runtime where + UncheckedExtrinsic = UncheckedExtrinsic, + Block = Block, + NodeBlock = Block, + { + System: frame_system exclude_parts { Call, Call }, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.stderr b/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.stderr new file mode 100644 index 0000000000000..75de56076528b --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/duplicate_exclude.stderr @@ -0,0 +1,5 @@ +error: `Call` was already declared before. Please remove the duplicate declaration + --> $DIR/duplicate_exclude.rs:9:46 + | +9 | System: frame_system exclude_parts { Call, Call }, + | ^^^^ diff --git a/frame/support/test/tests/construct_runtime_ui/exclude_missspell.rs b/frame/support/test/tests/construct_runtime_ui/exclude_missspell.rs new file mode 100644 index 0000000000000..16cbf1e82cf89 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/exclude_missspell.rs @@ -0,0 +1,13 @@ +use frame_support::construct_runtime; + +construct_runtime! { + pub enum Runtime where + UncheckedExtrinsic = UncheckedExtrinsic, + Block = Block, + NodeBlock = Block, + { + System: frame_system exclude_part { Call }, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/exclude_missspell.stderr b/frame/support/test/tests/construct_runtime_ui/exclude_missspell.stderr new file mode 100644 index 0000000000000..82e6aa6c8e308 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/exclude_missspell.stderr @@ -0,0 +1,5 @@ +error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,` + --> $DIR/exclude_missspell.rs:9:24 + | +9 | System: frame_system exclude_part { Call }, + | ^^^^^^^^^^^^ diff --git a/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs new file mode 100644 index 0000000000000..51be7e30bd3eb --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs @@ -0,0 +1,38 @@ +use frame_support::construct_runtime; +use sp_runtime::{generic, traits::BlakeTwo256}; +use sp_core::sr25519; + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + type Foo = StorageValue; +} + +pub type Signature = sr25519::Signature; +pub type BlockNumber = u64; +pub type Header = generic::Header; +pub type Block = generic::Block; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + +impl pallet::Config for Runtime {} + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Pallet, Call, Storage, Config, Event}, + Pallet: pallet exclude_parts { Call }, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr new file mode 100644 index 0000000000000..4e31cfb75c074 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr @@ -0,0 +1,28 @@ +error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`. + --> $DIR/exclude_undefined_part.rs:34:34 + | +34 | Pallet: pallet exclude_parts { Call }, + | ^^^^ + +error[E0412]: cannot find type `Call` in this scope + --> $DIR/exclude_undefined_part.rs:23:64 + | +23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | ^^^^ not found in this scope + | +help: consider importing one of these items + | +1 | use crate::pallet::Call; + | +1 | use frame_support_test::Call; + | +1 | use frame_system::Call; + | +1 | use test_pallet::Call; + | + +error[E0412]: cannot find type `Runtime` in this scope + --> $DIR/exclude_undefined_part.rs:25:25 + | +25 | impl pallet::Config for Runtime {} + | ^^^^^^^ not found in this scope diff --git a/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr b/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr index 50505b9130cbe..db96b8749ca11 100644 --- a/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr +++ b/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr @@ -1,5 +1,5 @@ -error: expected one of: identifier, curly braces, `<` - --> $DIR/invalid_module_details.rs:9:19 +error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,` + --> $DIR/invalid_module_details.rs:9:17 | 9 | system: System::(), - | ^^ + | ^^ diff --git a/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr b/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr index 3b967f96d7b4e..6025de82bd206 100644 --- a/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr +++ b/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr @@ -1,4 +1,4 @@ -error: expected `::` +error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,` --> $DIR/invalid_token_after_module.rs:9:18 | 9 | system: System ? diff --git a/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs b/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs new file mode 100644 index 0000000000000..706d444f23590 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs @@ -0,0 +1,26 @@ +use frame_support::construct_runtime; + +mod pallet_old { + pub trait Config: frame_system::Config {} + + decl_storage! { + trait Store for Module as Example {} + } + + decl_module! { + pub struct Module for enum Call where origin: T::Origin {} + } + +} +construct_runtime! { + pub enum Runtime where + UncheckedExtrinsic = UncheckedExtrinsic, + Block = Block, + NodeBlock = Block, + { + System: frame_system, + OldPallet: pallet_old, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.stderr b/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.stderr new file mode 100644 index 0000000000000..f8ec07e00106f --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.stderr @@ -0,0 +1,31 @@ +error[E0433]: failed to resolve: could not find `tt_default_parts` in `pallet_old` + --> $DIR/old_unsupported_pallet_decl.rs:15:1 + | +15 | / construct_runtime! { +16 | | pub enum Runtime where +17 | | UncheckedExtrinsic = UncheckedExtrinsic, +18 | | Block = Block, +... | +23 | | } +24 | | } + | |_^ could not find `tt_default_parts` in `pallet_old` + | + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot find macro `decl_storage` in this scope + --> $DIR/old_unsupported_pallet_decl.rs:6:2 + | +6 | decl_storage! { + | ^^^^^^^^^^^^ + | + = note: consider importing this macro: + frame_support::decl_storage + +error: cannot find macro `decl_module` in this scope + --> $DIR/old_unsupported_pallet_decl.rs:10:2 + | +10 | decl_module! { + | ^^^^^^^^^^^ + | + = note: consider importing this macro: + frame_support::decl_module diff --git a/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs new file mode 100644 index 0000000000000..1664dcc42b755 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs @@ -0,0 +1,38 @@ +use frame_support::construct_runtime; +use sp_runtime::{generic, traits::BlakeTwo256}; +use sp_core::sr25519; + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + type Foo = StorageValue; +} + +pub type Signature = sr25519::Signature; +pub type BlockNumber = u64; +pub type Header = generic::Header; +pub type Block = generic::Block; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + +impl pallet::Config for Runtime {} + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Pallet, Call, Storage, Config, Event}, + Pallet: pallet use_parts { Call }, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr new file mode 100644 index 0000000000000..ed41f0ce673a4 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr @@ -0,0 +1,28 @@ +error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`. + --> $DIR/use_undefined_part.rs:34:30 + | +34 | Pallet: pallet use_parts { Call }, + | ^^^^ + +error[E0412]: cannot find type `Call` in this scope + --> $DIR/use_undefined_part.rs:23:64 + | +23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | ^^^^ not found in this scope + | +help: consider importing one of these items + | +1 | use crate::pallet::Call; + | +1 | use frame_support_test::Call; + | +1 | use frame_system::Call; + | +1 | use test_pallet::Call; + | + +error[E0412]: cannot find type `Runtime` in this scope + --> $DIR/use_undefined_part.rs:25:25 + | +25 | impl pallet::Config for Runtime {} + | ^^^^^^^ not found in this scope diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index dc72be3ebdd49..a314f576187dc 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -509,6 +509,18 @@ pub mod pallet3 { pub struct Pallet(_); } +#[frame_support::pallet] +pub mod pallet4 { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet {} +} + frame_support::parameter_types!( pub const MyGetParam: u32 = 10; pub const MyGetParam2: u32 = 11; @@ -553,6 +565,8 @@ impl pallet2::Config for Runtime { type Event = Event; } +impl pallet4::Config for Runtime {} + pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; @@ -563,12 +577,21 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: frame_system::{Call, Event}, - Example: pallet::{Pallet, Call, Event, Config, Storage, Inherent, Origin, ValidateUnsigned}, - Example2: pallet2::{Pallet, Call, Event, Config, Storage}, + // Exclude part `Storage` in order not to check its metadata in tests. + System: frame_system exclude_parts { Pallet, Storage }, + Example: pallet, + Example2: pallet2 exclude_parts { Call }, + Example4: pallet4 use_parts { Call }, } ); +// Test that the part `Call` is excluded from Example2 and included in Example4. +fn _ensure_call_is_correctly_excluded_and_included(call: Call) { + match call { + Call::System(_) | Call::Example(_) | Call::Example4(_) => (), + } +} + #[test] fn transactional_works() { TestExternalities::default().execute_with(|| { @@ -995,8 +1018,8 @@ fn migrate_from_pallet_version_to_storage_version() { AllPalletsWithSystem, >(&db_weight); - // 3 pallets, 2 writes and every write costs 5 weight. - assert_eq!(3 * 2 * 5, weight); + // 4 pallets, 2 writes and every write costs 5 weight. + assert_eq!(4 * 2 * 5, weight); // All pallet versions should be removed assert!(sp_io::storage::get(&pallet_version_key(Example::name())).is_none()); @@ -1268,7 +1291,7 @@ fn metadata() { }, ], }), - calls: Some(meta_type::>().into()), + calls: None, event: Some(PalletEventMetadata { ty: meta_type::() }), constants: vec![], error: None, diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 3a1009402d6f2..c031ac9fe1bf5 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -302,13 +302,12 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: frame_system::{Pallet, Call, Event}, - Example: pallet::{Pallet, Call, Event, Config, Storage, Inherent, Origin, ValidateUnsigned}, - Instance1Example: pallet::::{ - Pallet, Call, Event, Config, Storage, Inherent, Origin, ValidateUnsigned - }, - Example2: pallet2::{Pallet, Event, Config, Storage}, - Instance1Example2: pallet2::::{Pallet, Event, Config, Storage}, + // Exclude part `Storage` in order not to check its metadata in tests. + System: frame_system exclude_parts { Storage }, + Example: pallet, + Instance1Example: pallet::, + Example2: pallet2, + Instance1Example2: pallet2::, } ); @@ -601,7 +600,7 @@ fn metadata() { let system_pallet_metadata = PalletMetadata { index: 0, name: "System", - storage: None, + storage: None, // The storage metadatas have been excluded. calls: Some(scale_info::meta_type::>().into()), event: Some(PalletEventMetadata { ty: scale_info::meta_type::>(), From b63e1c525baa33097ceccbd2ca828acbd36b0262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 31 Oct 2021 19:13:19 +0100 Subject: [PATCH 0162/1472] Offchain-worker: Make it possible to disable http support (#10087) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Offchain-worker: Make it possible to disable http support If a chain doesn't require http support in its offchain workers, this pr enables them to disable the http support. * Switch to bitflags * Use Capabilities * Update client/offchain/src/lib.rs Co-authored-by: Tomasz Drwięga * Fix test * Update client/offchain/src/lib.rs Co-authored-by: Tomasz Drwięga Co-authored-by: Tomasz Drwięga --- Cargo.lock | 2 + client/api/src/execution_extensions.rs | 10 +- client/offchain/Cargo.toml | 1 + client/offchain/src/api.rs | 12 +-- client/offchain/src/api/http.rs | 49 +++++++++- client/offchain/src/lib.rs | 43 ++++++--- primitives/core/Cargo.toml | 1 + primitives/core/src/lib.rs | 12 +-- primitives/core/src/offchain/mod.rs | 128 ++++++++++--------------- 9 files changed, 144 insertions(+), 114 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84ad0c0a563c0..666fe6e451831 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8184,6 +8184,7 @@ dependencies = [ "lazy_static", "log 0.4.14", "num_cpus", + "once_cell", "parity-scale-codec", "parking_lot 0.11.1", "rand 0.7.3", @@ -9232,6 +9233,7 @@ name = "sp-core" version = "4.0.0-dev" dependencies = [ "base58", + "bitflags", "blake2-rfc", "byteorder", "criterion", diff --git a/client/api/src/execution_extensions.rs b/client/api/src/execution_extensions.rs index ec44294b8a96c..56e70cc2b6a62 100644 --- a/client/api/src/execution_extensions.rs +++ b/client/api/src/execution_extensions.rs @@ -161,13 +161,13 @@ impl ExecutionExtensions { let mut extensions = self.extensions_factory.read().extensions_for(capabilities); - if capabilities.has(offchain::Capability::Keystore) { + if capabilities.contains(offchain::Capabilities::KEYSTORE) { if let Some(ref keystore) = self.keystore { extensions.register(KeystoreExt(keystore.clone())); } } - if capabilities.has(offchain::Capability::TransactionPool) { + if capabilities.contains(offchain::Capabilities::TRANSACTION_POOL) { if let Some(pool) = self.transaction_pool.read().as_ref().and_then(|x| x.upgrade()) { extensions .register(TransactionPoolExt( @@ -176,8 +176,8 @@ impl ExecutionExtensions { } } - if capabilities.has(offchain::Capability::OffchainDbRead) || - capabilities.has(offchain::Capability::OffchainDbWrite) + if capabilities.contains(offchain::Capabilities::OFFCHAIN_DB_READ) || + capabilities.contains(offchain::Capabilities::OFFCHAIN_DB_WRITE) { if let Some(offchain_db) = self.offchain_db.as_ref() { extensions.register(OffchainDbExt::new(offchain::LimitedExternalities::new( @@ -210,7 +210,7 @@ impl ExecutionExtensions { ExecutionContext::BlockConstruction => self.strategies.block_construction.get_manager(), ExecutionContext::Syncing => self.strategies.syncing.get_manager(), ExecutionContext::Importing => self.strategies.importing.get_manager(), - ExecutionContext::OffchainCall(Some((_, capabilities))) if capabilities.has_all() => + ExecutionContext::OffchainCall(Some((_, capabilities))) if capabilities.is_all() => self.strategies.offchain_worker.get_manager(), ExecutionContext::OffchainCall(_) => self.strategies.other.get_manager(), }; diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 146ce07e1303b..104a0e61f3180 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -33,6 +33,7 @@ sc-utils = { version = "4.0.0-dev", path = "../utils" } threadpool = "1.7" hyper = "0.14.11" hyper-rustls = "0.22.1" +once_cell = "1.8" [dev-dependencies] sc-client-db = { version = "0.10.0-dev", default-features = true, path = "../db" } diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index b2276a852372f..07136d1815b91 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -298,9 +298,9 @@ impl AsyncApi { pub fn new( network_provider: Arc, is_validator: bool, - shared_client: SharedClient, + shared_http_client: SharedClient, ) -> (Api, Self) { - let (http_api, http_worker) = http::http(shared_client); + let (http_api, http_worker) = http::http(shared_http_client); let api = Api { network_provider, is_validator, http: http_api }; @@ -310,10 +310,8 @@ impl AsyncApi { } /// Run a processing task for the API - pub fn process(mut self) -> impl Future { - let http = self.http.take().expect("Take invoked only once."); - - http + pub fn process(self) -> impl Future { + self.http.expect("`process` is only called once; qed") } } @@ -328,7 +326,7 @@ mod tests { time::SystemTime, }; - struct TestNetwork(); + pub(super) struct TestNetwork(); impl NetworkProvider for TestNetwork { fn set_authorized_peers(&self, _peers: HashSet) { diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index 31f7d60e34ff9..a2975bad16528 100644 --- a/client/offchain/src/api/http.rs +++ b/client/offchain/src/api/http.rs @@ -34,6 +34,7 @@ use futures::{channel::mpsc, future, prelude::*}; use hyper::{client, Body, Client as HyperClient}; use hyper_rustls::HttpsConnector; use log::error; +use once_cell::sync::Lazy; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_core::offchain::{HttpError, HttpRequestId, HttpRequestStatus, Timestamp}; use std::{ @@ -47,11 +48,13 @@ use std::{ /// Wrapper struct used for keeping the hyper_rustls client running. #[derive(Clone)] -pub struct SharedClient(Arc, Body>>); +pub struct SharedClient(Arc, Body>>>); impl SharedClient { pub fn new() -> Self { - Self(Arc::new(HyperClient::builder().build(HttpsConnector::with_native_roots()))) + Self(Arc::new(Lazy::new(|| { + HyperClient::builder().build(HttpsConnector::with_native_roots()) + }))) } } @@ -567,7 +570,7 @@ pub struct HttpWorker { /// Used to receive messages from the `HttpApi`. from_api: TracingUnboundedReceiver, /// The engine that runs HTTP requests. - http_client: Arc, Body>>, + http_client: Arc, Body>>>, /// HTTP requests that are being worked on by the engine. requests: Vec<(HttpRequestId, HttpWorkerRequest)>, } @@ -697,12 +700,15 @@ impl fmt::Debug for HttpWorkerRequest { #[cfg(test)] mod tests { - use super::{http, SharedClient}; + use super::{ + super::{tests::TestNetwork, AsyncApi}, + *, + }; use crate::api::timestamp; use core::convert::Infallible; use futures::{future, StreamExt}; use lazy_static::lazy_static; - use sp_core::offchain::{Duration, HttpError, HttpRequestId, HttpRequestStatus}; + use sp_core::offchain::{Duration, Externalities, HttpError, HttpRequestId, HttpRequestStatus}; // Using lazy_static to avoid spawning lots of different SharedClients, // as spawning a SharedClient is CPU-intensive and opens lots of fds. @@ -1006,4 +1012,37 @@ mod tests { } } } + + #[test] + fn shared_http_client_is_only_initialized_on_access() { + let shared_client = SharedClient::new(); + + { + let mock = Arc::new(TestNetwork()); + let (mut api, async_api) = AsyncApi::new(mock, false, shared_client.clone()); + api.timestamp(); + + futures::executor::block_on(async move { + assert!(futures::poll!(async_api.process()).is_pending()); + }); + } + + // Check that the http client wasn't initialized, because it wasn't used. + assert!(Lazy::into_value(Arc::try_unwrap(shared_client.0).unwrap()).is_err()); + + let shared_client = SharedClient::new(); + + { + let mock = Arc::new(TestNetwork()); + let (mut api, async_api) = AsyncApi::new(mock, false, shared_client.clone()); + let id = api.http_request_start("lol", "nope", &[]).unwrap(); + api.http_request_write_body(id, &[], None).unwrap(); + futures::executor::block_on(async move { + assert!(futures::poll!(async_api.process()).is_pending()); + }); + } + + // Check that the http client initialized, because it was used. + assert!(Lazy::into_value(Arc::try_unwrap(shared_client.0).unwrap()).is_ok()); + } } diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index be6e4238ca5f1..a77fd17a2c8b8 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -81,18 +81,31 @@ where } } +/// Options for [`OffchainWorkers`] +pub struct OffchainWorkerOptions { + /// Enable http requests from offchain workers? + /// + /// If not enabled, any http request will panic. + pub enable_http_requests: bool, +} + /// An offchain workers manager. pub struct OffchainWorkers { client: Arc, _block: PhantomData, thread_pool: Mutex, - shared_client: api::SharedClient, + shared_http_client: api::SharedClient, + enable_http: bool, } impl OffchainWorkers { - /// Creates new `OffchainWorkers`. + /// Creates new [`OffchainWorkers`]. pub fn new(client: Arc) -> Self { - let shared_client = api::SharedClient::new(); + Self::new_with_options(client, OffchainWorkerOptions { enable_http_requests: true }) + } + + /// Creates new [`OffchainWorkers`] using the given `options`. + pub fn new_with_options(client: Arc, options: OffchainWorkerOptions) -> Self { Self { client, _block: PhantomData, @@ -100,7 +113,8 @@ impl OffchainWorkers { "offchain-worker".into(), num_cpus::get(), )), - shared_client, + shared_http_client: api::SharedClient::new(), + enable_http: options.enable_http_requests, } } } @@ -140,18 +154,22 @@ where }, }; debug!("Checking offchain workers at {:?}: version:{}", at, version); - if version > 0 { + let process = (version > 0).then(|| { let (api, runner) = - api::AsyncApi::new(network_provider, is_validator, self.shared_client.clone()); + api::AsyncApi::new(network_provider, is_validator, self.shared_http_client.clone()); debug!("Spawning offchain workers at {:?}", at); let header = header.clone(); let client = self.client.clone(); + + let mut capabilities = offchain::Capabilities::all(); + + capabilities.set(offchain::Capabilities::HTTP, self.enable_http); self.spawn_worker(move || { let runtime = client.runtime_api(); let api = Box::new(api); debug!("Running offchain workers at {:?}", at); - let context = - ExecutionContext::OffchainCall(Some((api, offchain::Capabilities::all()))); + + let context = ExecutionContext::OffchainCall(Some((api, capabilities))); let run = if version == 2 { runtime.offchain_worker_with_context(&at, context, &header) } else { @@ -166,9 +184,12 @@ where log::error!("Error running offchain workers at {:?}: {:?}", at, e); } }); - futures::future::Either::Left(runner.process()) - } else { - futures::future::Either::Right(futures::future::ready(())) + + runner.process() + }); + + async move { + futures::future::OptionFuture::from(process).await; } } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index dd721d744f573..14a76e2482444 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -49,6 +49,7 @@ parity-util-mem = { version = "0.10.0", default-features = false, features = [ futures = { version = "0.3.1", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.21", optional = true } +bitflags = "1.3" # full crypto ed25519-dalek = { version = "1.0.1", default-features = false, features = [ diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index a6229fe43a1a5..fd752397cd9a9 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -118,15 +118,13 @@ impl ExecutionContext { use ExecutionContext::*; match self { - Importing | Syncing | BlockConstruction => offchain::Capabilities::none(), + Importing | Syncing | BlockConstruction => offchain::Capabilities::empty(), // Enable keystore, transaction pool and Offchain DB reads by default for offchain // calls. - OffchainCall(None) => [ - offchain::Capability::Keystore, - offchain::Capability::OffchainDbRead, - offchain::Capability::TransactionPool, - ][..] - .into(), + OffchainCall(None) => + offchain::Capabilities::KEYSTORE | + offchain::Capabilities::OFFCHAIN_DB_READ | + offchain::Capabilities::TRANSACTION_POOL, OffchainCall(Some((_, capabilities))) => *capabilities, } } diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 640f4d2583b79..dfe23c1ff8f18 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -258,65 +258,35 @@ impl Timestamp { } } -/// Execution context extra capabilities. -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -#[repr(u8)] -pub enum Capability { - /// Access to transaction pool. - TransactionPool = 1, - /// External http calls. - Http = 2, - /// Keystore access. - Keystore = 4, - /// Randomness source. - Randomness = 8, - /// Access to opaque network state. - NetworkState = 16, - /// Access to offchain worker DB (read only). - OffchainDbRead = 32, - /// Access to offchain worker DB (writes). - OffchainDbWrite = 64, - /// Manage the authorized nodes - NodeAuthorization = 128, -} - -/// A set of capabilities -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct Capabilities(u8); - -impl Capabilities { - /// Return an object representing an empty set of capabilities. - pub fn none() -> Self { - Self(0) - } - - /// Return an object representing all capabilities enabled. - pub fn all() -> Self { - Self(u8::MAX) +bitflags::bitflags! { + /// Execution context extra capabilities. + pub struct Capabilities: u32 { + /// Access to transaction pool. + const TRANSACTION_POOL = 0b0000_0001; + /// External http calls. + const HTTP = 0b0000_0010; + /// Keystore access. + const KEYSTORE = 0b0000_0100; + /// Randomness source. + const RANDOMNESS = 0b0000_1000; + /// Access to opaque network state. + const NETWORK_STATE = 0b0001_0000; + /// Access to offchain worker DB (read only). + const OFFCHAIN_DB_READ = 0b0010_0000; + /// Access to offchain worker DB (writes). + const OFFCHAIN_DB_WRITE = 0b0100_0000; + /// Manage the authorized nodes + const NODE_AUTHORIZATION = 0b1000_0000; } +} +impl Capabilities { /// Return capabilities for rich offchain calls. /// /// Those calls should be allowed to sign and submit transactions /// and access offchain workers database (but read only!). pub fn rich_offchain_call() -> Self { - [Capability::TransactionPool, Capability::Keystore, Capability::OffchainDbRead][..].into() - } - - /// Check if particular capability is enabled. - pub fn has(&self, capability: Capability) -> bool { - self.0 & capability as u8 != 0 - } - - /// Check if this capability object represents all capabilities. - pub fn has_all(&self) -> bool { - self == &Capabilities::all() - } -} - -impl<'a> From<&'a [Capability]> for Capabilities { - fn from(list: &'a [Capability]) -> Self { - Capabilities(list.iter().fold(0_u8, |a, b| a | *b as u8)) + Capabilities::TRANSACTION_POOL | Capabilities::KEYSTORE | Capabilities::OFFCHAIN_DB_READ } } @@ -552,8 +522,8 @@ impl LimitedExternalities { /// Check if given capability is allowed. /// /// Panics in case it is not. - fn check(&self, capability: Capability, name: &'static str) { - if !self.capabilities.has(capability) { + fn check(&self, capability: Capabilities, name: &'static str) { + if !self.capabilities.contains(capability) { panic!("Accessing a forbidden API: {}. No: {:?} capability.", name, capability); } } @@ -561,27 +531,27 @@ impl LimitedExternalities { impl Externalities for LimitedExternalities { fn is_validator(&self) -> bool { - self.check(Capability::Keystore, "is_validator"); + self.check(Capabilities::KEYSTORE, "is_validator"); self.externalities.is_validator() } fn network_state(&self) -> Result { - self.check(Capability::NetworkState, "network_state"); + self.check(Capabilities::NETWORK_STATE, "network_state"); self.externalities.network_state() } fn timestamp(&mut self) -> Timestamp { - self.check(Capability::Http, "timestamp"); + self.check(Capabilities::HTTP, "timestamp"); self.externalities.timestamp() } fn sleep_until(&mut self, deadline: Timestamp) { - self.check(Capability::Http, "sleep_until"); + self.check(Capabilities::HTTP, "sleep_until"); self.externalities.sleep_until(deadline) } fn random_seed(&mut self) -> [u8; 32] { - self.check(Capability::Randomness, "random_seed"); + self.check(Capabilities::RANDOMNESS, "random_seed"); self.externalities.random_seed() } @@ -591,7 +561,7 @@ impl Externalities for LimitedExternalities { uri: &str, meta: &[u8], ) -> Result { - self.check(Capability::Http, "http_request_start"); + self.check(Capabilities::HTTP, "http_request_start"); self.externalities.http_request_start(method, uri, meta) } @@ -601,7 +571,7 @@ impl Externalities for LimitedExternalities { name: &str, value: &str, ) -> Result<(), ()> { - self.check(Capability::Http, "http_request_add_header"); + self.check(Capabilities::HTTP, "http_request_add_header"); self.externalities.http_request_add_header(request_id, name, value) } @@ -611,7 +581,7 @@ impl Externalities for LimitedExternalities { chunk: &[u8], deadline: Option, ) -> Result<(), HttpError> { - self.check(Capability::Http, "http_request_write_body"); + self.check(Capabilities::HTTP, "http_request_write_body"); self.externalities.http_request_write_body(request_id, chunk, deadline) } @@ -620,12 +590,12 @@ impl Externalities for LimitedExternalities { ids: &[HttpRequestId], deadline: Option, ) -> Vec { - self.check(Capability::Http, "http_response_wait"); + self.check(Capabilities::HTTP, "http_response_wait"); self.externalities.http_response_wait(ids, deadline) } fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec, Vec)> { - self.check(Capability::Http, "http_response_headers"); + self.check(Capabilities::HTTP, "http_response_headers"); self.externalities.http_response_headers(request_id) } @@ -635,12 +605,12 @@ impl Externalities for LimitedExternalities { buffer: &mut [u8], deadline: Option, ) -> Result { - self.check(Capability::Http, "http_response_read_body"); + self.check(Capabilities::HTTP, "http_response_read_body"); self.externalities.http_response_read_body(request_id, buffer, deadline) } fn set_authorized_nodes(&mut self, nodes: Vec, authorized_only: bool) { - self.check(Capability::NodeAuthorization, "set_authorized_nodes"); + self.check(Capabilities::NODE_AUTHORIZATION, "set_authorized_nodes"); self.externalities.set_authorized_nodes(nodes, authorized_only) } } @@ -724,12 +694,12 @@ impl DbExternalities for Box { impl DbExternalities for LimitedExternalities { fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) { - self.check(Capability::OffchainDbWrite, "local_storage_set"); + self.check(Capabilities::OFFCHAIN_DB_WRITE, "local_storage_set"); self.externalities.local_storage_set(kind, key, value) } fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) { - self.check(Capability::OffchainDbWrite, "local_storage_clear"); + self.check(Capabilities::OFFCHAIN_DB_WRITE, "local_storage_clear"); self.externalities.local_storage_clear(kind, key) } @@ -740,13 +710,13 @@ impl DbExternalities for LimitedExternalities { old_value: Option<&[u8]>, new_value: &[u8], ) -> bool { - self.check(Capability::OffchainDbWrite, "local_storage_compare_and_set"); + self.check(Capabilities::OFFCHAIN_DB_WRITE, "local_storage_compare_and_set"); self.externalities .local_storage_compare_and_set(kind, key, old_value, new_value) } fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option> { - self.check(Capability::OffchainDbRead, "local_storage_get"); + self.check(Capabilities::OFFCHAIN_DB_READ, "local_storage_get"); self.externalities.local_storage_get(kind, key) } } @@ -815,15 +785,15 @@ mod tests { #[test] fn capabilities() { - let none = Capabilities::none(); + let none = Capabilities::empty(); let all = Capabilities::all(); - let some = Capabilities::from(&[Capability::Keystore, Capability::Randomness][..]); - - assert!(!none.has(Capability::Keystore)); - assert!(all.has(Capability::Keystore)); - assert!(some.has(Capability::Keystore)); - assert!(!none.has(Capability::TransactionPool)); - assert!(all.has(Capability::TransactionPool)); - assert!(!some.has(Capability::TransactionPool)); + let some = Capabilities::KEYSTORE | Capabilities::RANDOMNESS; + + assert!(!none.contains(Capabilities::KEYSTORE)); + assert!(all.contains(Capabilities::KEYSTORE)); + assert!(some.contains(Capabilities::KEYSTORE)); + assert!(!none.contains(Capabilities::TRANSACTION_POOL)); + assert!(all.contains(Capabilities::TRANSACTION_POOL)); + assert!(!some.contains(Capabilities::TRANSACTION_POOL)); } } From 26d69bcbe26f6b463e9374e1b1c54c3067fb6131 Mon Sep 17 00:00:00 2001 From: Zeke Mostov <32168567+emostov@users.noreply.github.com> Date: Sun, 31 Oct 2021 22:10:13 +0100 Subject: [PATCH 0163/1472] Fuzzer for Pallet Bags List (#9851) * Fuzzer for Pallet Bags List * Some small updates * Fuzzer for Pallet Bags List This PR adds a fuzzer for the `SortedListProvider` API exposed by pallet-bags-list. * Feature gate code NOT used by fuzz feature * Create Enum for list actions * fix some small mistakes * try and make CI happy * fmt * Do not insert before updating * clean up some misc. comments * marginally improve Node::sanity_check * Change ID_RANGE to 25_000 * comma * try improve correct feature gating so no unused code Co-authored-by: thiolliere --- Cargo.lock | 10 ++++ Cargo.toml | 1 + frame/bags-list/Cargo.toml | 6 ++ frame/bags-list/fuzzer/.gitignore | 2 + frame/bags-list/fuzzer/Cargo.toml | 22 ++++++++ frame/bags-list/fuzzer/src/main.rs | 88 ++++++++++++++++++++++++++++++ frame/bags-list/src/lib.rs | 4 +- frame/bags-list/src/list/mod.rs | 14 +++-- frame/bags-list/src/mock.rs | 7 ++- 9 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 frame/bags-list/fuzzer/.gitignore create mode 100644 frame/bags-list/fuzzer/Cargo.toml create mode 100644 frame/bags-list/fuzzer/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 666fe6e451831..3434e01d13cd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5180,6 +5180,16 @@ dependencies = [ "sp-tracing", ] +[[package]] +name = "pallet-bags-list-fuzzer" +version = "4.0.0-dev" +dependencies = [ + "frame-election-provider-support", + "honggfuzz", + "pallet-bags-list", + "rand 0.8.4", +] + [[package]] name = "pallet-balances" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 4a228203159eb..743e0f7066647 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -135,6 +135,7 @@ members = [ "frame/utility", "frame/vesting", "frame/bags-list", + "frame/bags-list/fuzzer", "primitives/api", "primitives/api/proc-macro", "primitives/api/test", diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index cd06ce4a69983..372dc87e212e2 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -63,4 +63,10 @@ runtime-benchmarks = [ "sp-tracing", "frame-election-provider-support/runtime-benchmarks", ] +fuzz = [ + "sp-core", + "sp-io", + "pallet-balances", + "sp-tracing", +] diff --git a/frame/bags-list/fuzzer/.gitignore b/frame/bags-list/fuzzer/.gitignore new file mode 100644 index 0000000000000..3ebcb104d4a50 --- /dev/null +++ b/frame/bags-list/fuzzer/.gitignore @@ -0,0 +1,2 @@ +hfuzz_target +hfuzz_workspace diff --git a/frame/bags-list/fuzzer/Cargo.toml b/frame/bags-list/fuzzer/Cargo.toml new file mode 100644 index 0000000000000..171e0e7af70cd --- /dev/null +++ b/frame/bags-list/fuzzer/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "pallet-bags-list-fuzzer" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "Fuzzer for FRAME pallet bags list" +readme = "README.md" +publish = false + +[dependencies] +honggfuzz = "0.5" +rand = { version = "0.8", features = ["std", "small_rng"] } + +pallet-bags-list = { version = "4.0.0-dev", features = ["fuzz"], path = ".." } +frame-election-provider-support = { version = "4.0.0-dev", path = "../../election-provider-support", features = ["runtime-benchmarks"] } + +[[bin]] +name = "bags-list" +path = "src/main.rs" diff --git a/frame/bags-list/fuzzer/src/main.rs b/frame/bags-list/fuzzer/src/main.rs new file mode 100644 index 0000000000000..02a2003b9a71f --- /dev/null +++ b/frame/bags-list/fuzzer/src/main.rs @@ -0,0 +1,88 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Running +//! Running this fuzzer can be done with `cargo hfuzz run bags-list`. `honggfuzz` CLI options can +//! be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads. +//! +//! # Debugging a panic +//! Once a panic is found, it can be debugged with +//! `cargo hfuzz run-debug fixed_point hfuzz_workspace/bags_list/*.fuzz`. +//! +//! # More information +//! More information about `honggfuzz` can be found +//! [here](https://docs.rs/honggfuzz/). + +use frame_election_provider_support::{SortedListProvider, VoteWeight}; +use honggfuzz::fuzz; +use pallet_bags_list::mock::{AccountId, BagsList, ExtBuilder}; +use std::convert::From; + +const ID_RANGE: AccountId = 25_000; + +/// Actions of a `SortedListProvider` that we fuzz. +enum Action { + Insert, + Update, + Remove, +} + +impl From for Action { + fn from(v: u32) -> Self { + let num_variants = Self::Remove as u32 + 1; + match v % num_variants { + _x if _x == Action::Insert as u32 => Action::Insert, + _x if _x == Action::Update as u32 => Action::Update, + _x if _x == Action::Remove as u32 => Action::Remove, + _ => unreachable!(), + } + } +} + +fn main() { + ExtBuilder::default().build_and_execute(|| loop { + fuzz!(|data: (AccountId, VoteWeight, u32)| { + let (account_id_seed, vote_weight, action_seed) = data; + + let id = account_id_seed % ID_RANGE; + let action = Action::from(action_seed); + + match action { + Action::Insert => { + if BagsList::on_insert(id.clone(), vote_weight).is_err() { + // this was a duplicate id, which is ok. We can just update it. + BagsList::on_update(&id, vote_weight); + } + assert!(BagsList::contains(&id)); + }, + Action::Update => { + let already_contains = BagsList::contains(&id); + BagsList::on_update(&id, vote_weight); + if already_contains { + assert!(BagsList::contains(&id)); + } + }, + Action::Remove => { + BagsList::on_remove(&id); + assert!(!BagsList::contains(&id)); + }, + } + + assert!(BagsList::sanity_check().is_ok()); + }) + }); +} diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 4202a4d499895..10a692e8b3f95 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -59,8 +59,8 @@ use sp_std::prelude::*; mod benchmarks; mod list; -#[cfg(test)] -mod mock; +#[cfg(any(test, feature = "fuzz"))] +pub mod mock; #[cfg(test)] mod tests; pub mod weights; diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 3f55f22271910..057565e645f90 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -391,8 +391,8 @@ impl List { /// /// * there are no duplicate ids, /// * length of this list is in sync with `CounterForListNodes`, - /// * and sanity-checks all bags. This will cascade down all the checks and makes sure all bags - /// are checked per *any* update to `List`. + /// * and sanity-checks all bags and nodes. This will cascade down all the checks and makes sure + /// all bags and nodes are checked per *any* update to `List`. #[cfg(feature = "std")] pub(crate) fn sanity_check() -> Result<(), &'static str> { use frame_support::ensure; @@ -414,7 +414,6 @@ impl List { let thresholds = T::BagThresholds::get().iter().copied(); let thresholds: Vec = if thresholds.clone().last() == Some(VoteWeight::MAX) { // in the event that they included it, we don't need to make any changes - // Box::new(thresholds.collect() thresholds.collect() } else { // otherwise, insert it here. @@ -774,10 +773,13 @@ impl Node { "node does not exist in the expected bag" ); + let non_terminal_check = !self.is_terminal() && + expected_bag.head.as_ref() != Some(id) && + expected_bag.tail.as_ref() != Some(id); + let terminal_check = + expected_bag.head.as_ref() == Some(id) || expected_bag.tail.as_ref() == Some(id); frame_support::ensure!( - !self.is_terminal() || - expected_bag.head.as_ref() == Some(id) || - expected_bag.tail.as_ref() == Some(id), + non_terminal_check || terminal_check, "a terminal node is neither its bag head or tail" ); diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index a6ab35896b1e7..45eb1d85abe3c 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -101,12 +101,13 @@ pub(crate) const GENESIS_IDS: [(AccountId, VoteWeight); 4] = [(1, 10), (2, 1_000), (3, 1_000), (4, 1_000)]; #[derive(Default)] -pub(crate) struct ExtBuilder { +pub struct ExtBuilder { ids: Vec<(AccountId, VoteWeight)>, } impl ExtBuilder { /// Add some AccountIds to insert into `List`. + #[cfg(test)] pub(crate) fn add_ids(mut self, ids: Vec<(AccountId, VoteWeight)>) -> Self { self.ids = ids; self @@ -126,18 +127,20 @@ impl ExtBuilder { ext } - pub(crate) fn build_and_execute(self, test: impl FnOnce() -> ()) { + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { self.build().execute_with(|| { test(); List::::sanity_check().expect("Sanity check post condition failed") }) } + #[cfg(test)] pub(crate) fn build_and_execute_no_post_check(self, test: impl FnOnce() -> ()) { self.build().execute_with(test) } } +#[cfg(test)] pub(crate) mod test_utils { use super::*; use list::Bag; From dc29596e7c90e84e90198dee24c296e930b58c33 Mon Sep 17 00:00:00 2001 From: Koute Date: Mon, 1 Nov 2021 17:46:32 +0900 Subject: [PATCH 0164/1472] Strip out control codes from the logged messages (#10081) * Strip out control codes from the logged messages * Also strip away C1 control codes * Add extra comments * Clear the buffer after flushing; rename `write` to `flush` * Move control code stripping into its own function * Also strip out control codes from panic messages * Also strip out Unicode left-to-right/right-to-left control codes --- Cargo.lock | 2 + client/tracing/src/logging/event_format.rs | 65 +++++++++++++++------- client/tracing/src/logging/mod.rs | 32 +++++++++++ primitives/panic-handler/Cargo.toml | 2 + primitives/panic-handler/src/lib.rs | 61 ++++++++++++++++++++ 5 files changed, 142 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3434e01d13cd2..1ddf355c890d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9462,6 +9462,8 @@ name = "sp-panic-handler" version = "3.0.0" dependencies = [ "backtrace", + "lazy_static", + "regex", ] [[package]] diff --git a/client/tracing/src/logging/event_format.rs b/client/tracing/src/logging/event_format.rs index 5a21192d69c4d..944901d803bda 100644 --- a/client/tracing/src/logging/event_format.rs +++ b/client/tracing/src/logging/event_format.rs @@ -62,7 +62,7 @@ where S: Subscriber + for<'a> LookupSpan<'a>, N: for<'a> FormatFields<'a> + 'static, { - let writer = &mut MaybeColorWriter::new(self.enable_color, writer); + let writer = &mut ControlCodeSanitizer::new(!self.enable_color, writer); let normalized_meta = event.normalized_metadata(); let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata()); time::write(&self.timer, writer, self.enable_color)?; @@ -100,10 +100,18 @@ where } } + // The writer only sanitizes its output once it's flushed, so if we don't actually need + // to sanitize everything we need to flush out what was already buffered as-is and only + // force-sanitize what follows. + if !writer.sanitize { + writer.flush()?; + writer.sanitize = true; + } + ctx.format_fields(writer, event)?; writeln!(writer)?; - writer.write() + writer.flush() } } @@ -294,43 +302,60 @@ where } } -/// A writer that may write to `inner_writer` with colors. +/// A writer which (optionally) strips out terminal control codes from the logs. /// -/// This is used by [`EventFormat`] to kill colors when `enable_color` is `false`. +/// This is used by [`EventFormat`] to sanitize the log messages. /// -/// It is required to call [`MaybeColorWriter::write`] after all writes are done, +/// It is required to call [`ControlCodeSanitizer::flush`] after all writes are done, /// because the content of these writes is buffered and will only be written to the /// `inner_writer` at that point. -struct MaybeColorWriter<'a> { - enable_color: bool, +struct ControlCodeSanitizer<'a> { + sanitize: bool, buffer: String, inner_writer: &'a mut dyn fmt::Write, } -impl<'a> fmt::Write for MaybeColorWriter<'a> { +impl<'a> fmt::Write for ControlCodeSanitizer<'a> { fn write_str(&mut self, buf: &str) -> fmt::Result { self.buffer.push_str(buf); Ok(()) } } -impl<'a> MaybeColorWriter<'a> { +// NOTE: When making any changes here make sure to also change this function in `sp-panic-handler`. +fn strip_control_codes(input: &str) -> std::borrow::Cow { + lazy_static::lazy_static! { + static ref RE: Regex = Regex::new(r#"(?x) + \x1b\[[^m]+m| # VT100 escape codes + [ + \x00-\x09\x0B-\x1F # ASCII control codes / Unicode C0 control codes, except \n + \x7F # ASCII delete + \u{80}-\u{9F} # Unicode C1 control codes + \u{202A}-\u{202E} # Unicode left-to-right / right-to-left control characters + \u{2066}-\u{2069} # Same as above + ] + "#).expect("regex parsing doesn't fail; qed"); + } + + RE.replace_all(input, "") +} + +impl<'a> ControlCodeSanitizer<'a> { /// Creates a new instance. - fn new(enable_color: bool, inner_writer: &'a mut dyn fmt::Write) -> Self { - Self { enable_color, inner_writer, buffer: String::new() } + fn new(sanitize: bool, inner_writer: &'a mut dyn fmt::Write) -> Self { + Self { sanitize, inner_writer, buffer: String::new() } } /// Write the buffered content to the `inner_writer`. - fn write(&mut self) -> fmt::Result { - lazy_static::lazy_static! { - static ref RE: Regex = Regex::new("\x1b\\[[^m]+m").expect("Error initializing color regex"); - } - - if !self.enable_color { - let replaced = RE.replace_all(&self.buffer, ""); - self.inner_writer.write_str(&replaced) + fn flush(&mut self) -> fmt::Result { + if self.sanitize { + let replaced = strip_control_codes(&self.buffer); + self.inner_writer.write_str(&replaced)? } else { - self.inner_writer.write_str(&self.buffer) + self.inner_writer.write_str(&self.buffer)? } + + self.buffer.clear(); + Ok(()) } } diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index 7f995615a223b..49807098d1cf4 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -595,4 +595,36 @@ mod tests { assert!(stderr.contains(&line)); } } + + #[test] + fn control_characters_are_always_stripped_out_from_the_log_messages() { + const RAW_LINE: &str = "$$START$$\x1B[1;32mIn\u{202a}\u{202e}\u{2066}\u{2069}ner\n\r\x7ftext!\u{80}\u{9f}\x1B[0m$$END$$"; + const SANITIZED_LINE: &str = "$$START$$Inner\ntext!$$END$$"; + + let output = run_test_in_another_process( + "control_characters_are_always_stripped_out_from_the_log_messages", + || { + std::env::set_var("RUST_LOG", "trace"); + let mut builder = LoggerBuilder::new(""); + builder.with_colors(true); + builder.init().unwrap(); + log::error!("{}", RAW_LINE); + }, + ); + + if let Some(output) = output { + let stderr = String::from_utf8(output.stderr).unwrap(); + // The log messages should always be sanitized. + assert!(!stderr.contains(RAW_LINE)); + assert!(stderr.contains(SANITIZED_LINE)); + + // The part where the timestamp, the logging level, etc. is printed out doesn't + // always have to be sanitized unless it's necessary, and here it shouldn't be. + assert!(stderr.contains("\x1B[31mERROR\x1B[0m")); + + // Make sure the logs aren't being duplicated. + assert_eq!(stderr.find("ERROR"), stderr.rfind("ERROR")); + assert_eq!(stderr.find(SANITIZED_LINE), stderr.rfind(SANITIZED_LINE)); + } + } } diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml index c961d5b089abb..890cc277bd849 100644 --- a/primitives/panic-handler/Cargo.toml +++ b/primitives/panic-handler/Cargo.toml @@ -15,3 +15,5 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] backtrace = "0.3.38" +regex = "1.5.4" +lazy_static = "1.4.0" diff --git a/primitives/panic-handler/src/lib.rs b/primitives/panic-handler/src/lib.rs index 75b057cebf3e4..eddb31a7f22ff 100644 --- a/primitives/panic-handler/src/lib.rs +++ b/primitives/panic-handler/src/lib.rs @@ -25,6 +25,7 @@ //! temporarily be disabled by using an [`AbortGuard`]. use backtrace::Backtrace; +use regex::Regex; use std::{ cell::Cell, io::{self, Write}, @@ -125,6 +126,24 @@ impl Drop for AbortGuard { } } +// NOTE: When making any changes here make sure to also change this function in `sc-tracing`. +fn strip_control_codes(input: &str) -> std::borrow::Cow { + lazy_static::lazy_static! { + static ref RE: Regex = Regex::new(r#"(?x) + \x1b\[[^m]+m| # VT100 escape codes + [ + \x00-\x09\x0B-\x1F # ASCII control codes / Unicode C0 control codes, except \n + \x7F # ASCII delete + \u{80}-\u{9F} # Unicode C1 control codes + \u{202A}-\u{202E} # Unicode left-to-right / right-to-left control characters + \u{2066}-\u{2069} # Same as above + ] + "#).expect("regex parsing doesn't fail; qed"); + } + + RE.replace_all(input, "") +} + /// Function being called when a panic happens. fn panic_hook(info: &PanicInfo, report_url: &str, version: &str) { let location = info.location(); @@ -139,6 +158,8 @@ fn panic_hook(info: &PanicInfo, report_url: &str, version: &str) { }, }; + let msg = strip_control_codes(&msg); + let thread = thread::current(); let name = thread.name().unwrap_or(""); @@ -181,4 +202,44 @@ mod tests { let _guard = AbortGuard::force_abort(); std::panic::catch_unwind(|| panic!()).ok(); } + + fn run_test_in_another_process( + test_name: &str, + test_body: impl FnOnce(), + ) -> Option { + if std::env::var("RUN_FORKED_TEST").is_ok() { + test_body(); + None + } else { + let output = std::process::Command::new(std::env::current_exe().unwrap()) + .arg(test_name) + .env("RUN_FORKED_TEST", "1") + .output() + .unwrap(); + + assert!(output.status.success()); + Some(output) + } + } + + #[test] + fn control_characters_are_always_stripped_out_from_the_panic_messages() { + const RAW_LINE: &str = "$$START$$\x1B[1;32mIn\u{202a}\u{202e}\u{2066}\u{2069}ner\n\r\x7ftext!\u{80}\u{9f}\x1B[0m$$END$$"; + const SANITIZED_LINE: &str = "$$START$$Inner\ntext!$$END$$"; + + let output = run_test_in_another_process( + "control_characters_are_always_stripped_out_from_the_panic_messages", + || { + set("test", "1.2.3"); + let _guard = AbortGuard::force_unwind(); + let _ = std::panic::catch_unwind(|| panic!("{}", RAW_LINE)); + }, + ); + + if let Some(output) = output { + let stderr = String::from_utf8(output.stderr).unwrap(); + assert!(!stderr.contains(RAW_LINE)); + assert!(stderr.contains(SANITIZED_LINE)); + } + } } From efb72f6306e693ef3b653a52a354e048409baa26 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Mon, 1 Nov 2021 10:17:50 +0100 Subject: [PATCH 0165/1472] Fix transaction pool rejection (#10138) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix transaction rejection * Update client/service/src/lib.rs Co-authored-by: Bastian Köcher --- client/service/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index a1ff8da4085c9..ce77be5a7c1d9 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -498,7 +498,7 @@ where fn import(&self, transaction: B::Extrinsic) -> TransactionImportFuture { if !self.imports_external_transactions { debug!("Transaction rejected"); - Box::pin(futures::future::ready(TransactionImport::None)); + return Box::pin(futures::future::ready(TransactionImport::None)) } let encoded = transaction.encode(); From 5fa8dc0f126a4e3c9d5bf02db0fd4206f953403d Mon Sep 17 00:00:00 2001 From: icodezjb <8869892+icodezjb@users.noreply.github.com> Date: Mon, 1 Nov 2021 20:58:18 +0800 Subject: [PATCH 0166/1472] Speed up big chainspec json(~1.5 GB) load (#10137) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Speed up chainspec json load * Update client/chain-spec/src/chain_spec.rs * Update client/chain-spec/src/chain_spec.rs * Update client/chain-spec/src/chain_spec.rs * Load the chainspec through `mmap` Co-authored-by: icodezjb Co-authored-by: Bastian Köcher Co-authored-by: Jan Bujak --- Cargo.lock | 16 +++++++++++++--- client/chain-spec/Cargo.toml | 1 + client/chain-spec/src/chain_spec.rs | 12 +++++++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ddf355c890d1..4774bfda1f7a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1648,7 +1648,7 @@ checksum = "42276e3f205fe63887cca255aa9a65a63fb72764c30b9a6252a7c7e46994f689" dependencies = [ "byteorder", "dynasm", - "memmap2", + "memmap2 0.2.1", ] [[package]] @@ -4097,6 +4097,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memmap2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4647a11b578fead29cdbb34d4adef8dd3dc35b876c9c6d5240d83f205abfe96e" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.6.4" @@ -6174,7 +6183,7 @@ dependencies = [ "libc", "log 0.4.14", "lz4", - "memmap2", + "memmap2 0.2.1", "parking_lot 0.11.1", "rand 0.8.4", "snap", @@ -7503,6 +7512,7 @@ name = "sc-chain-spec" version = "4.0.0-dev" dependencies = [ "impl-trait-for-tuples", + "memmap2 0.5.0", "parity-scale-codec", "sc-chain-spec-derive", "sc-network", @@ -11285,7 +11295,7 @@ dependencies = [ "backtrace", "bincode", "lazy_static", - "memmap2", + "memmap2 0.2.1", "more-asserts", "rustc-demangle", "serde", diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 78062e600c3f5..ba9655261923b 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -22,3 +22,4 @@ serde_json = "1.0.68" sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "2.0.0" } +memmap2 = "0.5.0" diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index c4db6158125b1..2ddb56a0df845 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -285,10 +285,20 @@ impl ChainSpec { /// Parse json file into a `ChainSpec` pub fn from_json_file(path: PathBuf) -> Result { + // We mmap the file into memory first, as this is *a lot* faster than using + // `serde_json::from_reader`. See https://github.com/serde-rs/json/issues/160 let file = File::open(&path) .map_err(|e| format!("Error opening spec file `{}`: {}", path.display(), e))?; + + // SAFETY: `mmap` is fundamentally unsafe since technically the file can change + // underneath us while it is mapped; in practice it's unlikely to be a problem + let bytes = unsafe { + memmap2::Mmap::map(&file) + .map_err(|e| format!("Error mmaping spec file `{}`: {}", path.display(), e))? + }; + let client_spec = - json::from_reader(file).map_err(|e| format!("Error parsing spec file: {}", e))?; + json::from_slice(&bytes).map_err(|e| format!("Error parsing spec file: {}", e))?; Ok(ChainSpec { client_spec, genesis: GenesisSource::File(path) }) } } From 4b40c2aa05930a0aae5a7eb0c50a596a44eb6fb1 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:41:38 +0000 Subject: [PATCH 0167/1472] introduce remote-tests for pallet-bags-list (#10036) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * make a few primitives in bags-list public * push new stuff * update * update log target * bring remote tests here * revert pub * Update frame/bags-list/remote-tests/Cargo.toml Co-authored-by: Bastian Köcher * some rev commnets * Fix * cleanup * Update Cargo.lock Co-authored-by: Bastian Köcher Co-authored-by: Shawn Tabrizi --- Cargo.lock | 29 +++- Cargo.toml | 1 + frame/bags-list/remote-tests/Cargo.toml | 37 +++++ frame/bags-list/remote-tests/src/lib.rs | 134 ++++++++++++++++++ frame/bags-list/remote-tests/src/migration.rs | 65 +++++++++ .../remote-tests/src/sanity_check.rs | 54 +++++++ frame/bags-list/remote-tests/src/snapshot.rs | 86 +++++++++++ frame/bags-list/src/lib.rs | 6 +- frame/bags-list/src/list/mod.rs | 6 +- frame/staking/src/pallet/impls.rs | 13 +- utils/frame/remote-externalities/src/lib.rs | 4 +- 11 files changed, 420 insertions(+), 15 deletions(-) create mode 100644 frame/bags-list/remote-tests/Cargo.toml create mode 100644 frame/bags-list/remote-tests/src/lib.rs create mode 100644 frame/bags-list/remote-tests/src/migration.rs create mode 100644 frame/bags-list/remote-tests/src/sanity_check.rs create mode 100644 frame/bags-list/remote-tests/src/snapshot.rs diff --git a/Cargo.lock b/Cargo.lock index 4774bfda1f7a7..9686bf426fd26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5199,6 +5199,27 @@ dependencies = [ "rand 0.8.4", ] +[[package]] +name = "pallet-bags-list-remote-tests" +version = "4.0.0-dev" +dependencies = [ + "clap", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log 0.4.14", + "pallet-bags-list", + "pallet-staking", + "remote-externalities", + "sp-core", + "sp-runtime", + "sp-std", + "sp-storage", + "sp-tracing", + "structopt", + "tokio", +] + [[package]] name = "pallet-balances" version = "4.0.0-dev" @@ -9858,9 +9879,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "structopt" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa" dependencies = [ "clap", "lazy_static", @@ -9869,9 +9890,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba" dependencies = [ "heck", "proc-macro-error 1.0.4", diff --git a/Cargo.toml b/Cargo.toml index 743e0f7066647..197b156dea2ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -135,6 +135,7 @@ members = [ "frame/utility", "frame/vesting", "frame/bags-list", + "frame/bags-list/remote-tests", "frame/bags-list/fuzzer", "primitives/api", "primitives/api/proc-macro", diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml new file mode 100644 index 0000000000000..c670178c6188a --- /dev/null +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "pallet-bags-list-remote-tests" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet bags list remote test" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +# frame +pallet-staking = { path = "../../staking" } +pallet-bags-list = { path = "../../bags-list" } +frame-election-provider-support = { path = "../../election-provider-support" } +frame-system = { path = "../../system" } +frame-support = { path = "../../support" } + +# core +sp-storage = { path = "../../../primitives/storage" } +sp-core = { path = "../../../primitives/core" } +sp-tracing = { path = "../../../primitives/tracing" } +sp-runtime = { path = "../../../primitives/runtime" } +sp-std = { path = "../../../primitives/std" } + +# utils +remote-externalities = { path = "../../../utils/frame/remote-externalities" } + +# others +tokio = { version = "1", features = ["macros"] } +log = "0.4.14" +structopt = "0.3.23" +clap = "2.33.3" diff --git a/frame/bags-list/remote-tests/src/lib.rs b/frame/bags-list/remote-tests/src/lib.rs new file mode 100644 index 0000000000000..e471c4c95bdbc --- /dev/null +++ b/frame/bags-list/remote-tests/src/lib.rs @@ -0,0 +1,134 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Utilities for remote-testing pallet-bags-list. + +use sp_std::convert::TryInto; + +/// A common log target to use. +pub const LOG_TARGET: &'static str = "runtime::bags-list::remote-tests"; + +pub mod migration; +pub mod sanity_check; +pub mod snapshot; + +/// A wrapper for a runtime that the functions of this crate expect. +/// +/// For example, this can be the `Runtime` type of the Polkadot runtime. +pub trait RuntimeT: + pallet_staking::Config + pallet_bags_list::Config + frame_system::Config +{ +} +impl RuntimeT for T {} + +fn percent(portion: u32, total: u32) -> f64 { + (portion as f64 / total as f64) * 100f64 +} + +/// Display the number of nodes in each bag, while identifying those that need a rebag. +pub fn display_and_check_bags(currency_unit: u64, currency_name: &'static str) { + use frame_election_provider_support::SortedListProvider; + use frame_support::traits::Get; + + let min_nominator_bond = >::get(); + log::info!(target: LOG_TARGET, "min nominator bond is {:?}", min_nominator_bond); + + let voter_list_count = ::SortedListProvider::count(); + + // go through every bag to track the total number of voters within bags and log some info about + // how voters are distributed within the bags. + let mut seen_in_bags = 0; + let mut rebaggable = 0; + let mut active_bags = 0; + for vote_weight_thresh in ::BagThresholds::get() { + // threshold in terms of UNITS (e.g. KSM, DOT etc) + let vote_weight_thresh_as_unit = *vote_weight_thresh as f64 / currency_unit as f64; + let pretty_thresh = format!("Threshold: {}. {}", vote_weight_thresh_as_unit, currency_name); + + let bag = match pallet_bags_list::Pallet::::list_bags_get(*vote_weight_thresh) { + Some(bag) => bag, + None => { + log::info!(target: LOG_TARGET, "{} NO VOTERS.", pretty_thresh); + continue + }, + }; + + active_bags += 1; + + for id in bag.std_iter().map(|node| node.std_id().clone()) { + let vote_weight = pallet_staking::Pallet::::weight_of(&id); + let vote_weight_as_balance: pallet_staking::BalanceOf = + vote_weight.try_into().map_err(|_| "can't convert").unwrap(); + + if vote_weight_as_balance < min_nominator_bond { + log::trace!( + target: LOG_TARGET, + "⚠️ {} Account found below min bond: {:?}.", + pretty_thresh, + id + ); + } + + let node = + pallet_bags_list::Node::::get(&id).expect("node in bag must exist."); + if node.is_misplaced(vote_weight) { + rebaggable += 1; + log::trace!( + target: LOG_TARGET, + "Account {:?} can be rebagged from {:?} to {:?}", + id, + vote_weight_thresh_as_unit, + pallet_bags_list::notional_bag_for::(vote_weight) as f64 / + currency_unit as f64 + ); + } + } + + // update our overall counter + let voters_in_bag = bag.std_iter().count() as u32; + seen_in_bags += voters_in_bag; + + // percentage of all nominators + let percent_of_voters = percent(voters_in_bag, voter_list_count); + + log::info!( + target: LOG_TARGET, + "{} Nominators: {} [%{:.3}]", + pretty_thresh, + voters_in_bag, + percent_of_voters, + ); + } + + if seen_in_bags != voter_list_count { + log::error!( + target: LOG_TARGET, + "bags list population ({}) not on par whoever is voter_list ({})", + seen_in_bags, + voter_list_count, + ) + } + + log::info!( + target: LOG_TARGET, + "a total of {} nodes are in {} active bags [{} total bags], {} of which can be rebagged.", + voter_list_count, + active_bags, + ::BagThresholds::get().len(), + rebaggable, + ); +} diff --git a/frame/bags-list/remote-tests/src/migration.rs b/frame/bags-list/remote-tests/src/migration.rs new file mode 100644 index 0000000000000..1e977011f1439 --- /dev/null +++ b/frame/bags-list/remote-tests/src/migration.rs @@ -0,0 +1,65 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test to check the migration of the voter bag. + +use crate::{RuntimeT, LOG_TARGET}; +use frame_election_provider_support::SortedListProvider; +use frame_support::traits::PalletInfoAccess; +use pallet_staking::Nominators; +use remote_externalities::{Builder, Mode, OnlineConfig}; +use sp_runtime::traits::Block as BlockT; + +/// Test voter bags migration. `currency_unit` is the number of planks per the the runtimes `UNITS` +/// (i.e. number of decimal places per DOT, KSM etc) +pub async fn execute( + currency_unit: u64, + currency_name: &'static str, + ws_url: String, +) { + let mut ext = Builder::::new() + .mode(Mode::Online(OnlineConfig { + transport: ws_url.to_string().into(), + pallets: vec![pallet_staking::Pallet::::name().to_string()], + at: None, + state_snapshot: None, + })) + .build() + .await + .unwrap(); + + ext.execute_with(|| { + // get the nominator & validator count prior to migrating; these should be invariant. + let pre_migrate_nominator_count = >::iter().count() as u32; + log::info!(target: LOG_TARGET, "Nominator count: {}", pre_migrate_nominator_count); + + // run the actual migration, + let moved = ::SortedListProvider::regenerate( + pallet_staking::Nominators::::iter().map(|(n, _)| n), + pallet_staking::Pallet::::weight_of_fn(), + ); + log::info!(target: LOG_TARGET, "Moved {} nominators", moved); + + let voter_list_len = + ::SortedListProvider::iter().count() as u32; + let voter_list_count = ::SortedListProvider::count(); + // and confirm it is equal to the length of the `VoterList`. + assert_eq!(pre_migrate_nominator_count, voter_list_len); + assert_eq!(pre_migrate_nominator_count, voter_list_count); + + crate::display_and_check_bags::(currency_unit, currency_name); + }); +} diff --git a/frame/bags-list/remote-tests/src/sanity_check.rs b/frame/bags-list/remote-tests/src/sanity_check.rs new file mode 100644 index 0000000000000..e5e9f45bac5f4 --- /dev/null +++ b/frame/bags-list/remote-tests/src/sanity_check.rs @@ -0,0 +1,54 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test to execute the sanity-check of the voter bag. + +use frame_election_provider_support::SortedListProvider; +use frame_support::{ + storage::generator::StorageMap, + traits::{Get, PalletInfoAccess}, +}; +use remote_externalities::{Builder, Mode, OnlineConfig}; +use sp_runtime::traits::Block as BlockT; +use sp_std::convert::TryInto; + +/// Execute the sanity check of the bags-list. +pub async fn execute( + currency_unit: u64, + currency_name: &'static str, + ws_url: String, +) { + let mut ext = Builder::::new() + .mode(Mode::Online(OnlineConfig { + transport: ws_url.to_string().into(), + pallets: vec![pallet_bags_list::Pallet::::name().to_string()], + at: None, + state_snapshot: None, + })) + .inject_hashed_prefix(&>::prefix_hash()) + .inject_hashed_prefix(&>::prefix_hash()) + .build() + .await + .unwrap(); + + ext.execute_with(|| { + sp_core::crypto::set_default_ss58_version(Runtime::SS58Prefix::get().try_into().unwrap()); + pallet_bags_list::Pallet::::sanity_check().unwrap(); + log::info!(target: crate::LOG_TARGET, "executed bags-list sanity check with no errors."); + + crate::display_and_check_bags::(currency_unit, currency_name); + }); +} diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs new file mode 100644 index 0000000000000..6e186a65cb2b9 --- /dev/null +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -0,0 +1,86 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test to execute the snapshot using the voter bag. + +use frame_support::traits::PalletInfoAccess; +use remote_externalities::{Builder, Mode, OnlineConfig}; +use sp_runtime::traits::Block as BlockT; + +/// Execute create a snapshot from pallet-staking. +pub async fn execute( + voter_limit: Option, + currency_unit: u64, + ws_url: String, +) { + use frame_support::storage::generator::StorageMap; + let mut ext = Builder::::new() + .mode(Mode::Online(OnlineConfig { + transport: ws_url.to_string().into(), + // NOTE: we don't scrape pallet-staking, this kinda ensures that the source of the data + // is bags-list. + pallets: vec![pallet_bags_list::Pallet::::name().to_string()], + at: None, + state_snapshot: None, + })) + .inject_hashed_prefix(&>::prefix_hash()) + .inject_hashed_prefix(&>::prefix_hash()) + .inject_hashed_prefix(&>::prefix_hash()) + .inject_hashed_prefix(&>::prefix_hash()) + .inject_hashed_key(&>::hashed_key()) + .inject_hashed_key(&>::hashed_key()) + .build() + .await + .unwrap(); + + ext.execute_with(|| { + use frame_election_provider_support::{ElectionDataProvider, SortedListProvider}; + log::info!( + target: crate::LOG_TARGET, + "{} nodes in bags list.", + ::SortedListProvider::count(), + ); + + let voters = as ElectionDataProvider< + Runtime::AccountId, + Runtime::BlockNumber, + >>::voters(voter_limit) + .unwrap(); + + let mut voters_nominator_only = voters + .iter() + .filter(|(v, _, _)| pallet_staking::Nominators::::contains_key(v)) + .cloned() + .collect::>(); + voters_nominator_only.sort_by_key(|(_, w, _)| *w); + + let currency_unit = currency_unit as f64; + let min_voter = voters_nominator_only + .first() + .map(|(x, y, _)| (x.clone(), *y as f64 / currency_unit)); + let max_voter = voters_nominator_only + .last() + .map(|(x, y, _)| (x.clone(), *y as f64 / currency_unit)); + log::info!( + target: crate::LOG_TARGET, + "a snapshot with limit {:?} has been created, {} voters are taken. min nominator: {:?}, max: {:?}", + voter_limit, + voters.len(), + min_voter, + max_voter + ); + }); +} diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 10a692e8b3f95..b7f96799e459f 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -65,12 +65,10 @@ pub mod mock; mod tests; pub mod weights; +pub use list::{notional_bag_for, Bag, Error, List, Node}; pub use pallet::*; pub use weights::WeightInfo; -pub use list::Error; -use list::List; - pub(crate) const LOG_TARGET: &'static str = "runtime::bags_list"; // syntactic sugar for logging. @@ -155,7 +153,7 @@ pub mod pallet { /// How many ids are registered. // NOTE: This is merely a counter for `ListNodes`. It should someday be replaced by the - // `CountedMaop` storage. + // `CountedMap` storage. #[pallet::storage] pub(crate) type CounterForListNodes = StorageValue<_, u32, ValueQuery>; diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 057565e645f90..4efc3163816ff 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -53,7 +53,7 @@ mod tests; /// /// Note that even if the thresholds list does not have `VoteWeight::MAX` as its final member, this /// function behaves as if it does. -pub(crate) fn notional_bag_for(weight: VoteWeight) -> VoteWeight { +pub fn notional_bag_for(weight: VoteWeight) -> VoteWeight { let thresholds = T::BagThresholds::get(); let idx = thresholds.partition_point(|&threshold| weight > threshold); thresholds.get(idx).copied().unwrap_or(VoteWeight::MAX) @@ -690,7 +690,7 @@ pub struct Node { impl Node { /// Get a node by id. - pub(crate) fn get(id: &T::AccountId) -> Option> { + pub fn get(id: &T::AccountId) -> Option> { crate::ListNodes::::try_get(id).ok() } @@ -734,7 +734,7 @@ impl Node { } /// `true` when this voter is in the wrong bag. - pub(crate) fn is_misplaced(&self, current_weight: VoteWeight) -> bool { + pub fn is_misplaced(&self, current_weight: VoteWeight) -> bool { notional_bag_for::(current_weight) != self.bag_upper } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 02099d8543d4c..ec34efe397f5a 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -692,6 +692,9 @@ impl Pallet { // track every nominator iterated over, but not necessarily added to `all_voters` let mut nominators_seen = 0u32; + // cache the total-issuance once in this function + let weight_of = Self::weight_of_fn(); + let mut nominators_iter = T::SortedListProvider::iter(); while nominators_taken < nominators_quota && nominators_seen < nominators_quota * 2 { let nominator = match nominators_iter.next() { @@ -705,17 +708,23 @@ impl Pallet { if let Some(Nominations { submitted_in, mut targets, suppressed: _ }) = >::get(&nominator) { + log!( + trace, + "fetched nominator {:?} with weight {:?}", + nominator, + weight_of(&nominator) + ); targets.retain(|stash| { slashing_spans .get(stash) .map_or(true, |spans| submitted_in >= spans.last_nonzero_slash()) }); if !targets.len().is_zero() { - all_voters.push((nominator.clone(), Self::weight_of(&nominator), targets)); + all_voters.push((nominator.clone(), weight_of(&nominator), targets)); nominators_taken.saturating_inc(); } } else { - log!(error, "invalid item in `SortedListProvider`: {:?}", nominator) + log!(error, "DEFENSIVE: invalid item in `SortedListProvider`: {:?}", nominator) } } diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 733ec7c3200ad..3b9e08f75da85 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -385,7 +385,7 @@ impl Builder { }; for prefix in &self.hashed_prefixes { - debug!( + info!( target: LOG_TARGET, "adding data for hashed prefix: {:?}", HexDisplay::from(prefix) @@ -397,7 +397,7 @@ impl Builder { for key in &self.hashed_keys { let key = StorageKey(key.to_vec()); - debug!(target: LOG_TARGET, "adding data for hashed key: {:?}", HexDisplay::from(&key)); + info!(target: LOG_TARGET, "adding data for hashed key: {:?}", HexDisplay::from(&key)); let value = self.rpc_get_storage(key.clone(), Some(at)).await?; keys_and_values.push((key, value)); } From 0210ea04921021fea86f441ecad5275c487f6a78 Mon Sep 17 00:00:00 2001 From: Albrecht <14820950+weichweich@users.noreply.github.com> Date: Tue, 2 Nov 2021 10:27:44 +0100 Subject: [PATCH 0168/1472] don't panic if already migrated (#10141) * don't panic if already migrated * remove condition --- frame/vesting/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 27862a5ca4b72..654723d009fab 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -181,7 +181,11 @@ pub mod pallet { impl Hooks> for Pallet { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result<(), &'static str> { - migrations::v1::pre_migrate::() + if StorageVersion::::get() == Releases::V0 { + migrations::v1::pre_migrate::() + } else { + Ok(()) + } } fn on_runtime_upgrade() -> Weight { From 0465b0bb407fe36ea03ae35d5138633e23119aac Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 2 Nov 2021 10:35:23 +0100 Subject: [PATCH 0169/1472] Hashing proc macro utils (#9875) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * hashing macro * fmt * use in easy place, and fix blake sizes * fix * Fixes, docs. Allow ident as input. * fix doc tests * update error in test (nmapkey and key are same type). * hashing crates under sp_core * Doc updates and format. * use all existing hashing functions. * return array of u8 * Update primitives/core/hashing/proc-macro/src/impls.rs Co-authored-by: Bastian Köcher * ToTokeen for an array of u8 * fix * re * Improve impls * complete doc tests * fmt * fix doctest format * fix ui test (nmap key type alias) Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- Cargo.lock | 26 +++ Cargo.toml | 2 + client/executor/Cargo.toml | 1 + client/executor/src/wasm_runtime.rs | 2 +- frame/support/Cargo.toml | 1 + frame/support/src/lib.rs | 6 +- .../storage_info_unsatisfied_nmap.stderr | 4 +- primitives/core/Cargo.toml | 4 + primitives/core/hashing/Cargo.toml | 31 +++ primitives/core/hashing/proc-macro/Cargo.toml | 22 +++ .../core/hashing/proc-macro/src/impls.rs | 124 ++++++++++++ primitives/core/hashing/proc-macro/src/lib.rs | 129 ++++++++++++ primitives/core/hashing/src/lib.rs | 166 ++++++++++++++++ primitives/core/src/hashing.rs | 184 ++++-------------- 14 files changed, 553 insertions(+), 149 deletions(-) create mode 100644 primitives/core/hashing/Cargo.toml create mode 100644 primitives/core/hashing/proc-macro/Cargo.toml create mode 100644 primitives/core/hashing/proc-macro/src/impls.rs create mode 100644 primitives/core/hashing/proc-macro/src/lib.rs create mode 100644 primitives/core/hashing/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 9686bf426fd26..20499facb5b71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2051,6 +2051,7 @@ dependencies = [ "smallvec 1.7.0", "sp-arithmetic", "sp-core", + "sp-core-hashing-proc-macro", "sp-inherents", "sp-io", "sp-runtime", @@ -7919,6 +7920,7 @@ dependencies = [ "sc-tracing", "sp-api", "sp-core", + "sp-core-hashing-proc-macro", "sp-externalities", "sp-io", "sp-maybe-compressed-blob", @@ -9303,6 +9305,8 @@ dependencies = [ "serde", "serde_json", "sha2 0.9.8", + "sp-core-hashing", + "sp-core-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-runtime-interface", @@ -9319,6 +9323,28 @@ dependencies = [ "zeroize", ] +[[package]] +name = "sp-core-hashing" +version = "4.0.0-dev" +dependencies = [ + "blake2-rfc", + "byteorder", + "sha2 0.9.8", + "sp-std", + "tiny-keccak", + "twox-hash", +] + +[[package]] +name = "sp-core-hashing-proc-macro" +version = "4.0.0-dev" +dependencies = [ + "proc-macro2", + "quote", + "sp-core-hashing", + "syn", +] + [[package]] name = "sp-database" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 197b156dea2ec..32d10ca8978dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -155,6 +155,8 @@ members = [ "primitives/consensus/pow", "primitives/consensus/vrf", "primitives/core", + "primitives/core/hashing", + "primitives/core/hashing/proc-macro", "primitives/database", "primitives/debug-derive", "primitives/externalities", diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index c8246d43a0f89..bc55172bc33ef 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -33,6 +33,7 @@ sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = t parking_lot = "0.11.1" log = "0.4.8" libsecp256k1 = "0.6" +sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } [dev-dependencies] wat = "1.0" diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index c7aa1200719de..204a095717fc4 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -344,7 +344,7 @@ fn decode_version(mut version: &[u8]) -> Result { })? .into(); - let core_api_id = sp_core::hashing::blake2_64(b"Core"); + let core_api_id = sp_core_hashing_proc_macro::blake2b_64!(b"Core"); if v.has_api_with(&core_api_id, |v| v >= 3) { sp_api::RuntimeVersion::decode(&mut version).map_err(|_| { WasmError::Instantiation("failed to decode \"Core_version\" result".into()) diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 4bc64d8b8e73a..b62ae3384fe42 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -34,6 +34,7 @@ bitflags = "1.3" impl-trait-for-tuples = "0.2.1" smallvec = "1.7.0" log = { version = "0.4.14", default-features = false } +sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } [dev-dependencies] assert_matches = "1.3.0" diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index d81300a404c4f..6e60988a4ca23 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -42,6 +42,8 @@ pub use scale_info; pub use serde; pub use sp_core::Void; #[doc(hidden)] +pub use sp_core_hashing_proc_macro; +#[doc(hidden)] pub use sp_io::{self, storage::root as storage_root}; #[doc(hidden)] pub use sp_runtime::RuntimeDebug; @@ -427,9 +429,7 @@ macro_rules! parameter_types { /// Returns the key for this parameter type. #[allow(unused)] pub fn key() -> [u8; 16] { - $crate::sp_io::hashing::twox_128( - concat!(":", stringify!($name), ":").as_bytes() - ) + $crate::sp_core_hashing_proc_macro::twox_128!(b":", $name, b":") } /// Set the value of this parameter type in the storage. diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 2b70102fdac24..ffbc5aeea6b4f 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -4,8 +4,8 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied 10 | #[pallet::generate_storage_info] | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | - = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` - = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` + = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `NMapKey` + = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>` note: required by `storage_info` --> $DIR/storage.rs:71:2 | diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 14a76e2482444..148f2343ee2b7 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -66,6 +66,7 @@ sha2 = { version = "0.9.8", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } twox-hash = { version = "1.6.1", default-features = false, optional = true } libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"], optional = true } +sp-core-hashing = { version = "4.0.0-dev", path = "./hashing", default-features = false, optional = true } merlin = { version = "2.0", default-features = false, optional = true } ss58-registry = "1.0.0" sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" } @@ -76,6 +77,7 @@ hex-literal = "0.3.3" rand = "0.7.2" criterion = "0.3.3" serde_json = "1.0" +sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "./hashing/proc-macro" } [[bench]] name = "bench" @@ -118,6 +120,7 @@ std = [ "regex", "num-traits/std", "tiny-keccak", + "sp-core-hashing/std", "sp-debug-derive/std", "sp-externalities", "sp-storage/std", @@ -142,6 +145,7 @@ full_crypto = [ "sha2", "twox-hash", "libsecp256k1", + "sp-core-hashing", "sp-runtime-interface/disable_target_static_assertions", "merlin", ] diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml new file mode 100644 index 0000000000000..43c670b59b0a7 --- /dev/null +++ b/primitives/core/hashing/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "sp-core-hashing" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "Primitive core crate hashing implementation." +documentation = "https://docs.rs/sp-core-hashing" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../std" } +byteorder = { version = "1.3.2", default-features = false } + +blake2-rfc = { version = "0.2.18", default-features = false } +tiny-keccak = { version = "2.0.1", features = ["keccak"] } +sha2 = { version = "0.9.2", default-features = false } +twox-hash = { version = "1.5.0", default-features = false } + +[features] +default = ["std"] +std = [ + "blake2-rfc/std", + "sha2/std", + "sp-std/std", + "twox-hash/std", +] diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml new file mode 100644 index 0000000000000..6d83b50b8a296 --- /dev/null +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "sp-core-hashing-proc-macro" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "This crate provides procedural macros for calculating static hash." +documentation = "https://docs.rs/sp-core-hashing-proc-macro" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1.0.77", features = ["full", "parsing"] } +quote = "1.0.6" +proc-macro2 = "1.0.29" +sp-core-hashing = { version = "4.0.0-dev", path = "../", default-features = false } diff --git a/primitives/core/hashing/proc-macro/src/impls.rs b/primitives/core/hashing/proc-macro/src/impls.rs new file mode 100644 index 0000000000000..0ce388762aa30 --- /dev/null +++ b/primitives/core/hashing/proc-macro/src/impls.rs @@ -0,0 +1,124 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use quote::quote; +use syn::parse::{Parse, ParseStream}; + +use proc_macro::TokenStream; + +pub(super) struct InputBytes(pub Vec); + +pub(super) struct MultipleInputBytes(pub Vec>); + +impl MultipleInputBytes { + pub(super) fn concatenated(mut self) -> Vec { + if self.0.len() == 0 { + Vec::new() + } else { + let mut result = core::mem::take(&mut self.0[0]); + for other in self.0[1..].iter_mut() { + result.append(other); + } + result + } + } +} + +impl Parse for InputBytes { + fn parse(input: ParseStream) -> syn::Result { + match syn::ExprArray::parse(input) { + Ok(array) => { + let mut bytes = Vec::::new(); + for expr in array.elems.iter() { + match expr { + syn::Expr::Lit(lit) => match &lit.lit { + syn::Lit::Int(b) => bytes.push(b.base10_parse()?), + syn::Lit::Byte(b) => bytes.push(b.value()), + _ => + return Err(syn::Error::new( + input.span(), + "Expected array of u8 elements.".to_string(), + )), + }, + _ => + return Err(syn::Error::new( + input.span(), + "Expected array of u8 elements.".to_string(), + )), + } + } + return Ok(InputBytes(bytes)) + }, + Err(_e) => (), + } + // use rust names as a vec of their utf8 bytecode. + match syn::Ident::parse(input) { + Ok(ident) => return Ok(InputBytes(ident.to_string().as_bytes().to_vec())), + Err(_e) => (), + } + Ok(InputBytes(syn::LitByteStr::parse(input)?.value())) + } +} + +impl Parse for MultipleInputBytes { + fn parse(input: ParseStream) -> syn::Result { + let elts = + syn::punctuated::Punctuated::::parse_terminated(input)?; + Ok(MultipleInputBytes(elts.into_iter().map(|elt| elt.0).collect())) + } +} + +pub(super) fn twox_64(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::twox_64(bytes.as_slice())) +} + +pub(super) fn twox_128(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::twox_128(bytes.as_slice())) +} + +pub(super) fn blake2b_512(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::blake2_512(bytes.as_slice())) +} + +pub(super) fn blake2b_256(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::blake2_256(bytes.as_slice())) +} + +pub(super) fn blake2b_64(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::blake2_64(bytes.as_slice())) +} + +pub(super) fn keccak_256(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::keccak_256(bytes.as_slice())) +} + +pub(super) fn keccak_512(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::keccak_512(bytes.as_slice())) +} + +pub(super) fn sha2_256(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::sha2_256(bytes.as_slice())) +} + +fn bytes_to_array(bytes: impl IntoIterator) -> TokenStream { + let bytes = bytes.into_iter(); + + quote!( + [ #( #bytes ),* ] + ) + .into() +} diff --git a/primitives/core/hashing/proc-macro/src/lib.rs b/primitives/core/hashing/proc-macro/src/lib.rs new file mode 100644 index 0000000000000..2af8554f4ece9 --- /dev/null +++ b/primitives/core/hashing/proc-macro/src/lib.rs @@ -0,0 +1,129 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Macros to calculate constant hash bytes result. +//! +//! Macros from this crate does apply a specific hash function on input. +//! Input can be literal byte array as `b"content"` or array of bytes +//! as `[1, 2, 3]`. +//! Rust identifier can also be use, in this case we use their utf8 string +//! byte representation, for instance if the ident is `MyStruct`, then +//! `b"MyStruct"` will be hashed. +//! If multiple arguments comma separated are passed, they are concatenated +//! then hashed. +//! +//! Examples: +//! +//! ```rust +//! assert_eq!( +//! sp_core_hashing_proc_macro::blake2b_256!(b"test"), +//! sp_core_hashing::blake2_256(b"test"), +//! ); +//! assert_eq!( +//! sp_core_hashing_proc_macro::blake2b_256!([1u8]), +//! sp_core_hashing::blake2_256(&[1u8]), +//! ); +//! assert_eq!( +//! sp_core_hashing_proc_macro::blake2b_256!([1, 2, 3]), +//! sp_core_hashing::blake2_256(&[1, 2, 3]), +//! ); +//! assert_eq!( +//! sp_core_hashing_proc_macro::blake2b_256!(identifier), +//! sp_core_hashing::blake2_256(b"identifier"), +//! ); +//! assert_eq!( +//! sp_core_hashing_proc_macro::blake2b_256!(identifier, b"/string"), +//! sp_core_hashing::blake2_256(b"identifier/string"), +//! ); +//! ``` + +mod impls; + +use impls::MultipleInputBytes; +use proc_macro::TokenStream; + +/// Process a Blake2 64-bit hash of bytes parameter outputs a `[u8; 8]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn blake2b_64(input: TokenStream) -> TokenStream { + impls::blake2b_64(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a Blake2 256-bit hash of bytes parameter, outputs a `[u8; 32]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn blake2b_256(input: TokenStream) -> TokenStream { + impls::blake2b_256(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a Blake2 512-bit hash of bytes parameter, outputs a `[u8; 64]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn blake2b_512(input: TokenStream) -> TokenStream { + impls::blake2b_512(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a XX 64-bit hash on its bytes parameter, outputs a `[u8; 8]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn twox_64(input: TokenStream) -> TokenStream { + impls::twox_64(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a XX 128-bit hash on its bytes parameter, outputs a `[u8; 16]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn twox_128(input: TokenStream) -> TokenStream { + impls::twox_128(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a keccak 256-bit hash on its bytes parameter, outputs a `[u8; 32]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn keccak_256(input: TokenStream) -> TokenStream { + impls::keccak_256(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a keccak 512-bit hash on its bytes parameter, outputs a `[u8; 64]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn keccak_512(input: TokenStream) -> TokenStream { + impls::keccak_512(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a sha2 256-bit hash on its bytes parameter, outputs a `[u8; 32]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn sha2_256(input: TokenStream) -> TokenStream { + impls::sha2_256(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} diff --git a/primitives/core/hashing/src/lib.rs b/primitives/core/hashing/src/lib.rs new file mode 100644 index 0000000000000..f806613c5b545 --- /dev/null +++ b/primitives/core/hashing/src/lib.rs @@ -0,0 +1,166 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Hashing Functions. + +#![warn(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +use sha2::{Digest, Sha256}; +use tiny_keccak::{Hasher, Keccak}; + +/// Do a Blake2 512-bit hash and place result in `dest`. +pub fn blake2_512_into(data: &[u8], dest: &mut [u8; 64]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(64, &[], data).as_bytes()); +} + +/// Do a Blake2 512-bit hash and return result. +pub fn blake2_512(data: &[u8]) -> [u8; 64] { + let mut r = [0; 64]; + blake2_512_into(data, &mut r); + r +} + +/// Do a Blake2 256-bit hash and place result in `dest`. +pub fn blake2_256_into(data: &[u8], dest: &mut [u8; 32]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes()); +} + +/// Do a Blake2 256-bit hash and return result. +pub fn blake2_256(data: &[u8]) -> [u8; 32] { + let mut r = [0; 32]; + blake2_256_into(data, &mut r); + r +} + +/// Do a Blake2 128-bit hash and place result in `dest`. +pub fn blake2_128_into(data: &[u8], dest: &mut [u8; 16]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(16, &[], data).as_bytes()); +} + +/// Do a Blake2 128-bit hash and return result. +pub fn blake2_128(data: &[u8]) -> [u8; 16] { + let mut r = [0; 16]; + blake2_128_into(data, &mut r); + r +} + +/// Do a Blake2 64-bit hash and place result in `dest`. +pub fn blake2_64_into(data: &[u8], dest: &mut [u8; 8]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(8, &[], data).as_bytes()); +} + +/// Do a Blake2 64-bit hash and return result. +pub fn blake2_64(data: &[u8]) -> [u8; 8] { + let mut r = [0; 8]; + blake2_64_into(data, &mut r); + r +} + +/// Do a XX 64-bit hash and place result in `dest`. +pub fn twox_64_into(data: &[u8], dest: &mut [u8; 8]) { + use core::hash::Hasher; + let mut h0 = twox_hash::XxHash::with_seed(0); + h0.write(data); + let r0 = h0.finish(); + use byteorder::{ByteOrder, LittleEndian}; + LittleEndian::write_u64(&mut dest[0..8], r0); +} + +/// Do a XX 64-bit hash and return result. +pub fn twox_64(data: &[u8]) -> [u8; 8] { + let mut r: [u8; 8] = [0; 8]; + twox_64_into(data, &mut r); + r +} + +/// Do a XX 128-bit hash and place result in `dest`. +pub fn twox_128_into(data: &[u8], dest: &mut [u8; 16]) { + use core::hash::Hasher; + let mut h0 = twox_hash::XxHash::with_seed(0); + let mut h1 = twox_hash::XxHash::with_seed(1); + h0.write(data); + h1.write(data); + let r0 = h0.finish(); + let r1 = h1.finish(); + use byteorder::{ByteOrder, LittleEndian}; + LittleEndian::write_u64(&mut dest[0..8], r0); + LittleEndian::write_u64(&mut dest[8..16], r1); +} + +/// Do a XX 128-bit hash and return result. +pub fn twox_128(data: &[u8]) -> [u8; 16] { + let mut r: [u8; 16] = [0; 16]; + twox_128_into(data, &mut r); + r +} + +/// Do a XX 256-bit hash and place result in `dest`. +pub fn twox_256_into(data: &[u8], dest: &mut [u8; 32]) { + use ::core::hash::Hasher; + use byteorder::{ByteOrder, LittleEndian}; + let mut h0 = twox_hash::XxHash::with_seed(0); + let mut h1 = twox_hash::XxHash::with_seed(1); + let mut h2 = twox_hash::XxHash::with_seed(2); + let mut h3 = twox_hash::XxHash::with_seed(3); + h0.write(data); + h1.write(data); + h2.write(data); + h3.write(data); + let r0 = h0.finish(); + let r1 = h1.finish(); + let r2 = h2.finish(); + let r3 = h3.finish(); + LittleEndian::write_u64(&mut dest[0..8], r0); + LittleEndian::write_u64(&mut dest[8..16], r1); + LittleEndian::write_u64(&mut dest[16..24], r2); + LittleEndian::write_u64(&mut dest[24..32], r3); +} + +/// Do a XX 256-bit hash and return result. +pub fn twox_256(data: &[u8]) -> [u8; 32] { + let mut r: [u8; 32] = [0; 32]; + twox_256_into(data, &mut r); + r +} + +/// Do a keccak 256-bit hash and return result. +pub fn keccak_256(data: &[u8]) -> [u8; 32] { + let mut keccak = Keccak::v256(); + keccak.update(data); + let mut output = [0u8; 32]; + keccak.finalize(&mut output); + output +} + +/// Do a keccak 512-bit hash and return result. +pub fn keccak_512(data: &[u8]) -> [u8; 64] { + let mut keccak = Keccak::v512(); + keccak.update(data); + let mut output = [0u8; 64]; + keccak.finalize(&mut output); + output +} + +/// Do a sha2 256-bit hash and return result. +pub fn sha2_256(data: &[u8]) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(data); + let mut output = [0u8; 32]; + output.copy_from_slice(&hasher.finalize()); + output +} diff --git a/primitives/core/src/hashing.rs b/primitives/core/src/hashing.rs index 4c719f7c69832..092cfc51b9508 100644 --- a/primitives/core/src/hashing.rs +++ b/primitives/core/src/hashing.rs @@ -22,147 +22,45 @@ //! unless you know what you're doing. Using `sp_io` will be more performant, since instead of //! computing the hash in WASM it delegates that computation to the host client. -use sha2::{Digest, Sha256}; -use tiny_keccak::{Hasher, Keccak}; - -/// Do a Blake2 512-bit hash and place result in `dest`. -pub fn blake2_512_into(data: &[u8], dest: &mut [u8; 64]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(64, &[], data).as_bytes()); -} - -/// Do a Blake2 512-bit hash and return result. -pub fn blake2_512(data: &[u8]) -> [u8; 64] { - let mut r = [0; 64]; - blake2_512_into(data, &mut r); - r -} - -/// Do a Blake2 256-bit hash and place result in `dest`. -pub fn blake2_256_into(data: &[u8], dest: &mut [u8; 32]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes()); -} - -/// Do a Blake2 256-bit hash and return result. -pub fn blake2_256(data: &[u8]) -> [u8; 32] { - let mut r = [0; 32]; - blake2_256_into(data, &mut r); - r -} - -/// Do a Blake2 128-bit hash and place result in `dest`. -pub fn blake2_128_into(data: &[u8], dest: &mut [u8; 16]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(16, &[], data).as_bytes()); -} - -/// Do a Blake2 128-bit hash and return result. -pub fn blake2_128(data: &[u8]) -> [u8; 16] { - let mut r = [0; 16]; - blake2_128_into(data, &mut r); - r -} - -/// Do a Blake2 64-bit hash and place result in `dest`. -pub fn blake2_64_into(data: &[u8], dest: &mut [u8; 8]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(8, &[], data).as_bytes()); -} - -/// Do a Blake2 64-bit hash and return result. -pub fn blake2_64(data: &[u8]) -> [u8; 8] { - let mut r = [0; 8]; - blake2_64_into(data, &mut r); - r -} - -/// Do a XX 64-bit hash and place result in `dest`. -pub fn twox_64_into(data: &[u8], dest: &mut [u8; 8]) { - use core::hash::Hasher; - let mut h0 = twox_hash::XxHash::with_seed(0); - h0.write(data); - let r0 = h0.finish(); - use byteorder::{ByteOrder, LittleEndian}; - LittleEndian::write_u64(&mut dest[0..8], r0); -} - -/// Do a XX 64-bit hash and return result. -pub fn twox_64(data: &[u8]) -> [u8; 8] { - let mut r: [u8; 8] = [0; 8]; - twox_64_into(data, &mut r); - r -} - -/// Do a XX 128-bit hash and place result in `dest`. -pub fn twox_128_into(data: &[u8], dest: &mut [u8; 16]) { - use core::hash::Hasher; - let mut h0 = twox_hash::XxHash::with_seed(0); - let mut h1 = twox_hash::XxHash::with_seed(1); - h0.write(data); - h1.write(data); - let r0 = h0.finish(); - let r1 = h1.finish(); - use byteorder::{ByteOrder, LittleEndian}; - LittleEndian::write_u64(&mut dest[0..8], r0); - LittleEndian::write_u64(&mut dest[8..16], r1); -} - -/// Do a XX 128-bit hash and return result. -pub fn twox_128(data: &[u8]) -> [u8; 16] { - let mut r: [u8; 16] = [0; 16]; - twox_128_into(data, &mut r); - r -} - -/// Do a XX 256-bit hash and place result in `dest`. -pub fn twox_256_into(data: &[u8], dest: &mut [u8; 32]) { - use ::core::hash::Hasher; - use byteorder::{ByteOrder, LittleEndian}; - let mut h0 = twox_hash::XxHash::with_seed(0); - let mut h1 = twox_hash::XxHash::with_seed(1); - let mut h2 = twox_hash::XxHash::with_seed(2); - let mut h3 = twox_hash::XxHash::with_seed(3); - h0.write(data); - h1.write(data); - h2.write(data); - h3.write(data); - let r0 = h0.finish(); - let r1 = h1.finish(); - let r2 = h2.finish(); - let r3 = h3.finish(); - LittleEndian::write_u64(&mut dest[0..8], r0); - LittleEndian::write_u64(&mut dest[8..16], r1); - LittleEndian::write_u64(&mut dest[16..24], r2); - LittleEndian::write_u64(&mut dest[24..32], r3); -} - -/// Do a XX 256-bit hash and return result. -pub fn twox_256(data: &[u8]) -> [u8; 32] { - let mut r: [u8; 32] = [0; 32]; - twox_256_into(data, &mut r); - r -} - -/// Do a keccak 256-bit hash and return result. -pub fn keccak_256(data: &[u8]) -> [u8; 32] { - let mut keccak = Keccak::v256(); - keccak.update(data); - let mut output = [0u8; 32]; - keccak.finalize(&mut output); - output -} - -/// Do a keccak 512-bit hash and return result. -pub fn keccak_512(data: &[u8]) -> [u8; 64] { - let mut keccak = Keccak::v512(); - keccak.update(data); - let mut output = [0u8; 64]; - keccak.finalize(&mut output); - output -} - -/// Do a sha2 256-bit hash and return result. -pub fn sha2_256(data: &[u8]) -> [u8; 32] { - let mut hasher = Sha256::new(); - hasher.update(data); - let mut output = [0u8; 32]; - output.copy_from_slice(&hasher.finalize()); - output +pub use sp_core_hashing::*; + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn blake2b() { + assert_eq!(sp_core_hashing_proc_macro::blake2b_64!(b""), blake2_64(b"")[..]); + assert_eq!(sp_core_hashing_proc_macro::blake2b_256!(b"test"), blake2_256(b"test")[..]); + assert_eq!(sp_core_hashing_proc_macro::blake2b_512!(b""), blake2_512(b"")[..]); + } + + #[test] + fn keccak() { + assert_eq!(sp_core_hashing_proc_macro::keccak_256!(b"test"), keccak_256(b"test")[..]); + assert_eq!(sp_core_hashing_proc_macro::keccak_512!(b"test"), keccak_512(b"test")[..]); + } + + #[test] + fn sha2() { + assert_eq!(sp_core_hashing_proc_macro::sha2_256!(b"test"), sha2_256(b"test")[..]); + } + + #[test] + fn twox() { + assert_eq!(sp_core_hashing_proc_macro::twox_128!(b"test"), twox_128(b"test")[..]); + assert_eq!(sp_core_hashing_proc_macro::twox_64!(b""), twox_64(b"")[..]); + } + + #[test] + fn twox_concats() { + assert_eq!( + sp_core_hashing_proc_macro::twox_128!(b"test", b"123", b"45", b"", b"67890"), + super::twox_128(&b"test1234567890"[..]), + ); + assert_eq!( + sp_core_hashing_proc_macro::twox_128!(b"test", test, b"45", b"", b"67890"), + super::twox_128(&b"testtest4567890"[..]), + ); + } } From 9d8e5c468e252f0773c7bae60a631a139969b046 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Tue, 2 Nov 2021 15:09:40 +0100 Subject: [PATCH 0170/1472] Spelling (#10154) --- docs/STYLE_GUIDE.md | 4 ++-- frame/babe/src/lib.rs | 2 +- frame/multisig/src/lib.rs | 2 +- primitives/state-machine/src/lib.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/STYLE_GUIDE.md b/docs/STYLE_GUIDE.md index ea070cdbc59f3..8854f885a4b22 100644 --- a/docs/STYLE_GUIDE.md +++ b/docs/STYLE_GUIDE.md @@ -140,8 +140,8 @@ let mut target_path = ``` - Unsafe code requires explicit proofs just as panickers do. When introducing unsafe code, - consider tradeoffs between efficiency on one hand and reliability, maintenance costs, and - security on the other. Here is a list of questions that may help evaluating the tradeoff while + consider trade-offs between efficiency on one hand and reliability, maintenance costs, and + security on the other. Here is a list of questions that may help evaluating the trade-off while preparing or reviewing a PR: - how much more performant or compact the resulting code will be using unsafe code, - how likely is it that invariants could be violated, diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 9c755eea6c446..c74bbf897ac7f 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -248,7 +248,7 @@ pub mod pallet { /// Randomness under construction. /// - /// We make a tradeoff between storage accesses and list length. + /// We make a trade-off between storage accesses and list length. /// We store the under-construction randomness in segments of up to /// `UNDER_CONSTRUCTION_SEGMENT_LENGTH`. /// diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 53567cc212afd..c38ddf1793ee1 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -218,7 +218,7 @@ pub mod pallet { CallHash, DispatchResult, ), - /// A multisig operation has been cancelled. \[cancelling, timepoint, multisig, call_hash\] + /// A multisig operation has been cancelled. \[canceling, timepoint, multisig, call_hash\] MultisigCancelled(T::AccountId, Timepoint, T::AccountId, CallHash), } diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 7bd0c645f3c00..a724cf5c9a0b4 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -1496,7 +1496,7 @@ mod tests { } overlay.start_transaction(); - // Then only initlaization item and second (commited) item should persist. + // Then only initlaization item and second (committed) item should persist. { let ext = Ext::new( &mut overlay, From 635c187e8f92a239772ffd70d7a445e073f8920f Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Tue, 2 Nov 2021 15:20:00 +0100 Subject: [PATCH 0171/1472] Better error for when origin filter prevent the call to be dispatched (#10134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * better error * Apply suggestions from code review Co-authored-by: Bastian Köcher * remove unused * fix error * fmt * fix tests * fmt * Update frame/contracts/src/exec.rs Co-authored-by: Alexander Theißen * fix typo Co-authored-by: Bastian Köcher Co-authored-by: Alexander Theißen --- frame/contracts/src/exec.rs | 12 +++--- frame/multisig/src/tests.rs | 2 +- frame/proxy/src/tests.rs | 42 ++++++++++++++----- .../src/construct_runtime/expand/call.rs | 6 ++- .../src/construct_runtime/expand/origin.rs | 13 +----- .../procedural/src/construct_runtime/mod.rs | 13 +++++- frame/support/test/tests/system.rs | 4 +- frame/system/src/lib.rs | 2 + frame/utility/src/tests.rs | 10 +++-- 9 files changed, 67 insertions(+), 37 deletions(-) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index c28490dfacccf..7ef1aec2dfc60 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1094,10 +1094,7 @@ mod tests { use pallet_contracts_primitives::ReturnFlags; use pretty_assertions::assert_eq; use sp_core::Bytes; - use sp_runtime::{ - traits::{BadOrigin, Hash}, - DispatchError, - }; + use sp_runtime::{traits::Hash, DispatchError}; use std::{cell::RefCell, collections::HashMap, rc::Rc}; type System = frame_system::Pallet; @@ -2114,7 +2111,10 @@ mod tests { let forbidden_call = Call::Balances(BalanceCall::transfer { dest: CHARLIE, value: 22 }); // simple cases: direct call - assert_err!(ctx.ext.call_runtime(forbidden_call.clone()), BadOrigin); + assert_err!( + ctx.ext.call_runtime(forbidden_call.clone()), + frame_system::Error::::CallFiltered + ); // as part of a patch: return is OK (but it interrupted the batch) assert_ok!(ctx.ext.call_runtime(Call::Utility(UtilCall::batch { @@ -2159,7 +2159,7 @@ mod tests { phase: Phase::Initialization, event: MetaEvent::Utility(pallet_utility::Event::BatchInterrupted( 1, - BadOrigin.into() + frame_system::Error::::CallFiltered.into() ),), topics: vec![], }, diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index d46c22ec73d09..c5607c80abce4 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -846,7 +846,7 @@ fn multisig_filters() { let call = Box::new(Call::System(frame_system::Call::set_code { code: vec![] })); assert_noop!( Multisig::as_multi_threshold_1(Origin::signed(1), vec![2], call.clone()), - DispatchError::BadOrigin, + DispatchError::from(frame_system::Error::::CallFiltered), ); }); } diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index d319ebb1a5ab0..20efd085fe882 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -174,6 +174,8 @@ use frame_system::Call as SystemCall; use pallet_balances::{Call as BalancesCall, Error as BalancesError, Event as BalancesEvent}; use pallet_utility::{Call as UtilityCall, Event as UtilityEvent}; +type SystemError = frame_system::Error; + pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { @@ -333,7 +335,9 @@ fn filtering_works() { assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted(Ok(())).into()); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Err(DispatchError::BadOrigin)).into()); + System::assert_last_event( + ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ); let derivative_id = Utility::derivative_account_id(1, 0); assert!(Balances::mutate_account(&derivative_id, |a| a.free = 1000).is_ok()); @@ -344,9 +348,13 @@ fn filtering_works() { assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted(Ok(())).into()); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Err(DispatchError::BadOrigin)).into()); + System::assert_last_event( + ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Err(DispatchError::BadOrigin)).into()); + System::assert_last_event( + ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ); let call = Box::new(Call::Utility(UtilityCall::batch { calls: vec![*inner] })); assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); @@ -355,10 +363,12 @@ fn filtering_works() { ProxyEvent::ProxyExecuted(Ok(())).into(), ]); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Err(DispatchError::BadOrigin)).into()); + System::assert_last_event( + ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); expect_events(vec![ - UtilityEvent::BatchInterrupted(0, DispatchError::BadOrigin).into(), + UtilityEvent::BatchInterrupted(0, SystemError::CallFiltered.into()).into(), ProxyEvent::ProxyExecuted(Ok(())).into(), ]); @@ -371,18 +381,24 @@ fn filtering_works() { ProxyEvent::ProxyExecuted(Ok(())).into(), ]); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Err(DispatchError::BadOrigin)).into()); + System::assert_last_event( + ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); expect_events(vec![ - UtilityEvent::BatchInterrupted(0, DispatchError::BadOrigin).into(), + UtilityEvent::BatchInterrupted(0, SystemError::CallFiltered.into()).into(), ProxyEvent::ProxyExecuted(Ok(())).into(), ]); let call = Box::new(Call::Proxy(ProxyCall::remove_proxies {})); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Err(DispatchError::BadOrigin)).into()); + System::assert_last_event( + ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Err(DispatchError::BadOrigin)).into()); + System::assert_last_event( + ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ); assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); expect_events(vec![ BalancesEvent::::Unreserved(1, 5).into(), @@ -462,13 +478,17 @@ fn proxying_works() { let call = Box::new(Call::System(SystemCall::set_code { code: vec![] })); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Err(DispatchError::BadOrigin)).into()); + System::assert_last_event( + ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ); let call = Box::new(Call::Balances(BalancesCall::transfer_keep_alive { dest: 6, value: 1 })); assert_ok!(Call::Proxy(super::Call::new_call_variant_proxy(1, None, call.clone())) .dispatch(Origin::signed(2))); - System::assert_last_event(ProxyEvent::ProxyExecuted(Err(DispatchError::BadOrigin)).into()); + System::assert_last_event( + ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted(Ok(())).into()); assert_eq!(Balances::free_balance(6), 2); diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index 2532a680e21be..5658ec045433a 100644 --- a/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -22,6 +22,7 @@ use syn::Ident; pub fn expand_outer_dispatch( runtime: &Ident, + system_pallet: &Pallet, pallet_decls: &[Pallet], scrate: &TokenStream, ) -> TokenStream { @@ -29,6 +30,7 @@ pub fn expand_outer_dispatch( let mut variant_patterns = Vec::new(); let mut query_call_part_macros = Vec::new(); let mut pallet_names = Vec::new(); + let system_path = &system_pallet.path; let pallets_with_call = pallet_decls.iter().filter(|decl| decl.exists_part("Call")); @@ -106,7 +108,9 @@ pub fn expand_outer_dispatch( type PostInfo = #scrate::weights::PostDispatchInfo; fn dispatch(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { if !::filter_call(&origin, &self) { - return #scrate::sp_std::result::Result::Err(#scrate::dispatch::DispatchError::BadOrigin.into()); + return #scrate::sp_std::result::Result::Err( + #system_path::Error::<#runtime>::CallFiltered.into() + ); } #scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(self, origin) diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index 57adf86a9fe18..eb0212c3efee3 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -18,23 +18,14 @@ use crate::construct_runtime::{Pallet, SYSTEM_PALLET_NAME}; use proc_macro2::TokenStream; use quote::quote; -use syn::{token, Generics, Ident}; +use syn::{Generics, Ident}; pub fn expand_outer_origin( runtime: &Ident, + system_pallet: &Pallet, pallets: &[Pallet], - pallets_token: token::Brace, scrate: &TokenStream, ) -> syn::Result { - let system_pallet = - pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| { - syn::Error::new( - pallets_token.span, - "`System` pallet declaration is missing. \ - Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},`", - ) - })?; - let mut caller_variants = TokenStream::new(); let mut pallet_conversions = TokenStream::new(); let mut query_origin_part_macros = Vec::new(); diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 4315d4278183a..f54fa79ce609b 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -214,17 +214,26 @@ fn construct_runtime_final_expansion( pallets_token, } = definition; + let system_pallet = + pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| { + syn::Error::new( + pallets_token.span, + "`System` pallet declaration is missing. \ + Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},`", + ) + })?; + let hidden_crate_name = "construct_runtime"; let scrate = generate_crate_access(&hidden_crate_name, "frame-support"); let scrate_decl = generate_hidden_includes(&hidden_crate_name, "frame-support"); let outer_event = expand::expand_outer_event(&name, &pallets, &scrate)?; - let outer_origin = expand::expand_outer_origin(&name, &pallets, pallets_token, &scrate)?; + let outer_origin = expand::expand_outer_origin(&name, &system_pallet, &pallets, &scrate)?; let all_pallets = decl_all_pallets(&name, pallets.iter()); let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate); - let dispatch = expand::expand_outer_dispatch(&name, &pallets, &scrate); + let dispatch = expand::expand_outer_dispatch(&name, &system_pallet, &pallets, &scrate); let metadata = expand::expand_runtime_metadata(&name, &pallets, &scrate, &unchecked_extrinsic); let outer_config = expand::expand_outer_config(&name, &pallets, &scrate); let inherent = diff --git a/frame/support/test/tests/system.rs b/frame/support/test/tests/system.rs index 4acc248d25f20..9def12131dd19 100644 --- a/frame/support/test/tests/system.rs +++ b/frame/support/test/tests/system.rs @@ -63,7 +63,9 @@ frame_support::decl_error! { TestError, /// Error documentation /// with multiple lines - AnotherError + AnotherError, + // Required by construct_runtime + CallFiltered, } } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 2e7f26eef16f4..41e1738c034f1 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -560,6 +560,8 @@ pub mod pallet { NonDefaultComposite, /// There is a non-zero reference count preventing the account from being purged. NonZeroRefCount, + /// The origin filter prevent the call to be dispatched. + CallFiltered, } /// Exposed trait-generic origin type. diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index bbfbb417e23d1..cb7a3d9a21e29 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -288,7 +288,7 @@ fn as_derivative_filters() { value: 1 })), ), - DispatchError::BadOrigin + DispatchError::from(frame_system::Error::::CallFiltered), ); }); } @@ -338,7 +338,8 @@ fn batch_with_signed_filters() { vec![Call::Balances(pallet_balances::Call::transfer_keep_alive { dest: 2, value: 1 })] ),); System::assert_last_event( - utility::Event::BatchInterrupted(0, DispatchError::BadOrigin).into(), + utility::Event::BatchInterrupted(0, frame_system::Error::::CallFiltered.into()) + .into(), ); }); } @@ -573,7 +574,7 @@ fn batch_all_does_not_nest() { actual_weight: Some(::WeightInfo::batch_all(1) + info.weight), pays_fee: Pays::Yes }, - error: DispatchError::BadOrigin, + error: frame_system::Error::::CallFiltered.into(), } ); @@ -585,7 +586,8 @@ fn batch_all_does_not_nest() { // and balances. assert_ok!(Utility::batch_all(Origin::signed(1), vec![batch_nested])); System::assert_has_event( - utility::Event::BatchInterrupted(0, DispatchError::BadOrigin).into(), + utility::Event::BatchInterrupted(0, frame_system::Error::::CallFiltered.into()) + .into(), ); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); From 079889e54ddd18c16e0ff90221fbf8b5b76e5275 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 2 Nov 2021 20:24:00 +0000 Subject: [PATCH 0172/1472] add missing version to dependencies (#10148) --- frame/bags-list/remote-tests/Cargo.toml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index c670178c6188a..ee5b8c7c3f6e7 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -14,21 +14,21 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # frame -pallet-staking = { path = "../../staking" } -pallet-bags-list = { path = "../../bags-list" } -frame-election-provider-support = { path = "../../election-provider-support" } -frame-system = { path = "../../system" } -frame-support = { path = "../../support" } +pallet-staking = { path = "../../staking", version = "4.0.0-dev" } +pallet-bags-list = { path = "../../bags-list", version = "4.0.0-dev" } +frame-election-provider-support = { path = "../../election-provider-support", version = "4.0.0-dev" } +frame-system = { path = "../../system", version = "4.0.0-dev" } +frame-support = { path = "../../support", version = "4.0.0-dev" } # core -sp-storage = { path = "../../../primitives/storage" } -sp-core = { path = "../../../primitives/core" } -sp-tracing = { path = "../../../primitives/tracing" } -sp-runtime = { path = "../../../primitives/runtime" } -sp-std = { path = "../../../primitives/std" } +sp-storage = { path = "../../../primitives/storage", version = "4.0.0-dev" } +sp-core = { path = "../../../primitives/core", version = "4.0.0-dev" } +sp-tracing = { path = "../../../primitives/tracing", version = "4.0.0-dev" } +sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0-dev" } +sp-std = { path = "../../../primitives/std", version = "4.0.0-dev" } # utils -remote-externalities = { path = "../../../utils/frame/remote-externalities" } +remote-externalities = { path = "../../../utils/frame/remote-externalities", version = "0.10.0-dev" } # others tokio = { version = "1", features = ["macros"] } From 7e42d7788002eadd94d3ce7782986a3fc6924e19 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 2 Nov 2021 22:21:39 +0100 Subject: [PATCH 0173/1472] Bump parity-db (#10151) --- Cargo.lock | 4 ++-- client/db/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20499facb5b71..a6f808ac00f03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6194,9 +6194,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91b679c6acc14fac74382942e2b73bea441686a33430b951ea03b5aeb6a7f254" +checksum = "e7ccc4a8687027deb53d45c5434a1f1b330c9d1069a59cfe80a62aa9a1da25ae" dependencies = [ "blake2-rfc", "crc32fast", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 53af082d3b91d..165d01d555116 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -33,7 +33,7 @@ sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -parity-db = { version = "0.3.2", optional = true } +parity-db = { version = "0.3.3", optional = true } [dev-dependencies] sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } From 85a2a7a2820c0d1032903ac5584eda81461bad30 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 3 Nov 2021 10:12:50 +0100 Subject: [PATCH 0174/1472] Add a `trie_root_hash` variant for chain specs genesis (#10140) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add a `hash` variant for chain specs * Add doc * Rename to TrieRootHash * Apply suggestions from code review Co-authored-by: Bastian Köcher * Rustfmt * More cargo fmt I guess * Ok I have to use nightly cargo fmt Co-authored-by: Bastian Köcher --- client/chain-spec/src/chain_spec.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 2ddb56a0df845..4aa0aa74630e0 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -119,6 +119,10 @@ impl BuildStorage for ChainSpec { }) .collect(), }), + // The `StateRootHash` variant exists as a way to keep note that other clients support + // it, but Substrate itself isn't capable of loading chain specs with just a hash at the + // moment. + Genesis::StateRootHash(_) => Err("Genesis storage in hash format not supported".into()), } } @@ -144,6 +148,8 @@ pub struct RawGenesis { enum Genesis { Runtime(G), Raw(RawGenesis), + /// State root hash of the genesis storage. + StateRootHash(StorageData), } /// A configuration of a client. Does not include runtime storage initialization. From 26e5f5f526ced19dfe649010e8f19e2c3f957b12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Nov 2021 10:29:16 +0000 Subject: [PATCH 0175/1472] Bump prost-build from 0.8.0 to 0.9.0 (#10162) Bumps [prost-build](https://github.com/tokio-rs/prost) from 0.8.0 to 0.9.0. - [Release notes](https://github.com/tokio-rs/prost/releases) - [Commits](https://github.com/tokio-rs/prost/compare/v0.8.0...v0.9.0) --- updated-dependencies: - dependency-name: prost-build 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 | 121 ++++++++++++++++++++------ client/authority-discovery/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- 3 files changed, 97 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a6f808ac00f03..39dedb31839dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1886,6 +1886,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" +[[package]] +name = "fixedbitset" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "398ea4fabe40b9b0d885340a2a991a44c8a645624075ad966d21f88688e2b69e" + [[package]] name = "flate2" version = "1.0.20" @@ -3393,8 +3399,8 @@ dependencies = [ "multistream-select", "parking_lot 0.11.1", "pin-project 1.0.8", - "prost", - "prost-build", + "prost 0.8.0", + "prost-build 0.8.0", "rand 0.7.3", "ring", "rw-stream-sink", @@ -3443,8 +3449,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "prost", - "prost-build", + "prost 0.8.0", + "prost-build 0.8.0", "rand 0.7.3", "smallvec 1.7.0", ] @@ -3465,8 +3471,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "prost", - "prost-build", + "prost 0.8.0", + "prost-build 0.8.0", "rand 0.7.3", "regex", "sha2 0.9.8", @@ -3485,8 +3491,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "prost", - "prost-build", + "prost 0.8.0", + "prost-build 0.8.0", "smallvec 1.7.0", "wasm-timer", ] @@ -3506,8 +3512,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "prost", - "prost-build", + "prost 0.8.0", + "prost-build 0.8.0", "rand 0.7.3", "sha2 0.9.8", "smallvec 1.7.0", @@ -3568,8 +3574,8 @@ dependencies = [ "lazy_static", "libp2p-core", "log 0.4.14", - "prost", - "prost-build", + "prost 0.8.0", + "prost-build 0.8.0", "rand 0.8.4", "sha2 0.9.8", "snow", @@ -3604,8 +3610,8 @@ dependencies = [ "futures 0.3.16", "libp2p-core", "log 0.4.14", - "prost", - "prost-build", + "prost 0.8.0", + "prost-build 0.8.0", "unsigned-varint 0.7.0", "void", ] @@ -3638,8 +3644,8 @@ dependencies = [ "libp2p-swarm", "log 0.4.14", "pin-project 1.0.8", - "prost", - "prost-build", + "prost 0.8.0", + "prost-build 0.8.0", "rand 0.7.3", "smallvec 1.7.0", "unsigned-varint 0.7.0", @@ -6485,7 +6491,17 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" dependencies = [ - "fixedbitset", + "fixedbitset 0.2.0", + "indexmap", +] + +[[package]] +name = "petgraph" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +dependencies = [ + "fixedbitset 0.4.0", "indexmap", ] @@ -6792,7 +6808,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020" dependencies = [ "bytes 1.0.1", - "prost-derive", + "prost-derive 0.8.0", +] + +[[package]] +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes 1.0.1", + "prost-derive 0.9.0", ] [[package]] @@ -6806,9 +6832,29 @@ dependencies = [ "itertools", "log 0.4.14", "multimap", - "petgraph", - "prost", - "prost-types", + "petgraph 0.5.1", + "prost 0.8.0", + "prost-types 0.8.0", + "tempfile", + "which", +] + +[[package]] +name = "prost-build" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" +dependencies = [ + "bytes 1.0.1", + "heck", + "itertools", + "lazy_static", + "log 0.4.14", + "multimap", + "petgraph 0.6.0", + "prost 0.9.0", + "prost-types 0.9.0", + "regex", "tempfile", "which", ] @@ -6826,6 +6872,19 @@ dependencies = [ "syn", ] +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "prost-types" version = "0.8.0" @@ -6833,7 +6892,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b" dependencies = [ "bytes 1.0.1", - "prost", + "prost 0.8.0", +] + +[[package]] +name = "prost-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" +dependencies = [ + "bytes 1.0.1", + "prost 0.9.0", ] [[package]] @@ -7471,8 +7540,8 @@ dependencies = [ "libp2p", "log 0.4.14", "parity-scale-codec", - "prost", - "prost-build", + "prost 0.8.0", + "prost-build 0.9.0", "quickcheck", "rand 0.7.3", "sc-client-api", @@ -8138,8 +8207,8 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.11.1", "pin-project 1.0.8", - "prost", - "prost-build", + "prost 0.8.0", + "prost-build 0.9.0", "quickcheck", "rand 0.7.3", "sc-block-builder", diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index cee35a43df2f6..dca365981984d 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.8" +prost-build = "0.9" [dependencies] async-trait = "0.1" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index d6d054504369b..7b4b30c593855 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.8" +prost-build = "0.9" [dependencies] async-trait = "0.1" From bdf97a350054b882dbe0c1cdcb377b3a9bf2e411 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 3 Nov 2021 13:23:32 +0100 Subject: [PATCH 0176/1472] Update CI image to the latest rustc (#10142) * Update CI image to the latest rustc * Update rustc error messages * whitespace * update test output * updating compiler errors * kid's finally learning to read and spots the TRYBUILD=overwrite message. * undoing a little blessing * imperfect error msg * revert ci image to production Co-authored-by: gilescope --- .../no_std_genesis_config.stderr | 7 +- .../undefined_call_part.stderr | 9 +- .../undefined_event_part.stderr | 9 +- .../undefined_genesis_config_part.stderr | 9 +- .../undefined_inherent_part.stderr | 9 +- .../undefined_origin_part.stderr | 9 +- .../undefined_validate_unsigned_part.stderr | 9 +- .../test/tests/derive_no_bound_ui/eq.stderr | 10 +- .../call_argument_invalid_bound.stderr | 2 +- .../call_argument_invalid_bound_2.stderr | 22 ++--- .../pallet_ui/event_field_not_member.stderr | 2 +- .../genesis_default_not_satisfied.stderr | 7 +- .../tests/pallet_ui/hooks_invalid_item.stderr | 2 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 92 +++++++++---------- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 92 +++++++++---------- .../type_value_forgotten_where_clause.stderr | 42 +++++---- ...reference_in_impl_runtime_apis_call.stderr | 11 ++- 17 files changed, 186 insertions(+), 157 deletions(-) diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr index 3dc7fcda9f18a..e458265a07cab 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr @@ -82,7 +82,8 @@ error[E0277]: the trait bound `Runtime: frame_system::pallet::Config` is not sat 11 | impl test_pallet::Config for Runtime {} | ^^^^^^^^^^^^^^^^^^^ the trait `frame_system::pallet::Config` is not implemented for `Runtime` | - ::: $WORKSPACE/frame/support/test/pallet/src/lib.rs +note: required by a bound in `Config` + --> $DIR/lib.rs:30:20 | - | pub trait Config: frame_system::Config {} - | -------------------- required by this bound in `Config` +30 | pub trait Config: frame_system::Config {} + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Config` diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr index 2629cf4101923..c4e567102a892 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr @@ -66,8 +66,11 @@ help: consider importing one of these items error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied --> $DIR/undefined_call_part.rs:20:6 | -8 | pub trait Config: frame_system::Config {} - | -------------------- required by this bound in `pallet::Config` -... 20 | impl pallet::Config for Runtime {} | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` + | +note: required by a bound in `pallet::Config` + --> $DIR/undefined_call_part.rs:8:20 + | +8 | pub trait Config: frame_system::Config {} + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index af69b79ed1a64..da972f6f4b2f4 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -104,8 +104,11 @@ help: consider importing one of these items error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied --> $DIR/undefined_event_part.rs:20:6 | -8 | pub trait Config: frame_system::Config {} - | -------------------- required by this bound in `pallet::Config` -... 20 | impl pallet::Config for Runtime {} | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` + | +note: required by a bound in `pallet::Config` + --> $DIR/undefined_event_part.rs:8:20 + | +8 | pub trait Config: frame_system::Config {} + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr index bfedb921bca44..8e40773b65736 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr @@ -84,8 +84,11 @@ help: consider importing this struct error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied --> $DIR/undefined_genesis_config_part.rs:20:6 | -8 | pub trait Config: frame_system::Config {} - | -------------------- required by this bound in `pallet::Config` -... 20 | impl pallet::Config for Runtime {} | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` + | +note: required by a bound in `pallet::Config` + --> $DIR/undefined_genesis_config_part.rs:8:20 + | +8 | pub trait Config: frame_system::Config {} + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr index 50dde1108263b..ae461473c3b11 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr @@ -66,8 +66,11 @@ help: consider importing one of these items error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied --> $DIR/undefined_inherent_part.rs:20:6 | -8 | pub trait Config: frame_system::Config {} - | -------------------- required by this bound in `pallet::Config` -... 20 | impl pallet::Config for Runtime {} | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` + | +note: required by a bound in `pallet::Config` + --> $DIR/undefined_inherent_part.rs:8:20 + | +8 | pub trait Config: frame_system::Config {} + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr index b5f3ec4d381bc..dbdd9f869a2e3 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr @@ -104,8 +104,11 @@ help: consider importing one of these items error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied --> $DIR/undefined_origin_part.rs:20:6 | -8 | pub trait Config: frame_system::Config {} - | -------------------- required by this bound in `pallet::Config` -... 20 | impl pallet::Config for Runtime {} | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` + | +note: required by a bound in `pallet::Config` + --> $DIR/undefined_origin_part.rs:8:20 + | +8 | pub trait Config: frame_system::Config {} + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr index 12bdce67cf038..8126d2f9a3e0f 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr @@ -66,8 +66,11 @@ help: consider importing one of these items error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied --> $DIR/undefined_validate_unsigned_part.rs:20:6 | -8 | pub trait Config: frame_system::Config {} - | -------------------- required by this bound in `pallet::Config` -... 20 | impl pallet::Config for Runtime {} | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` + | +note: required by a bound in `pallet::Config` + --> $DIR/undefined_validate_unsigned_part.rs:8:20 + | +8 | pub trait Config: frame_system::Config {} + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` diff --git a/frame/support/test/tests/derive_no_bound_ui/eq.stderr b/frame/support/test/tests/derive_no_bound_ui/eq.stderr index fce13d6f17f06..19fb3ac248b81 100644 --- a/frame/support/test/tests/derive_no_bound_ui/eq.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/eq.stderr @@ -4,9 +4,9 @@ error[E0277]: can't compare `Foo` with `Foo` 6 | struct Foo { | ^^^ no implementation for `Foo == Foo` | - ::: $RUST/core/src/cmp.rs - | - | pub trait Eq: PartialEq { - | --------------- required by this bound in `std::cmp::Eq` - | = help: the trait `PartialEq` is not implemented for `Foo` +note: required by a bound in `std::cmp::Eq` + --> $DIR/cmp.rs:272:15 + | +272 | pub trait Eq: PartialEq { + | ^^^^^^^^^^^^^^^ required by this bound in `std::cmp::Eq` diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index 3d1ea1adc9862..b7a8e40e69a14 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -29,4 +29,4 @@ error[E0369]: binary operation `==` cannot be applied to type `&::Bar: WrapperTypeEncode` is not satisfied --> $DIR/call_argument_invalid_bound_2.rs:1:1 @@ -47,12 +47,12 @@ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is 17 | | #[pallet::call] | |__________________^ the trait `WrapperTypeEncode` is not implemented for `::Bar` | - ::: $CARGO/parity-scale-codec-2.3.1/src/codec.rs - | - | fn encode_to(&self, dest: &mut T) { - | ------ required by this bound in `encode_to` - | = note: required because of the requirements on the impl of `Encode` for `::Bar` +note: required by a bound in `encode_to` + --> $DIR/codec.rs:223:18 + | +223 | fn encode_to(&self, dest: &mut T) { + | ^^^^^^ required by this bound in `encode_to` = note: this error originates in the derive macro `frame_support::codec::Encode` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied @@ -61,9 +61,9 @@ error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is 20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` | - ::: $CARGO/parity-scale-codec-2.3.1/src/codec.rs - | - | fn decode(input: &mut I) -> Result; - | ----- required by this bound in `parity_scale_codec::Decode::decode` - | = note: required because of the requirements on the impl of `Decode` for `::Bar` +note: required by a bound in `parity_scale_codec::Decode::decode` + --> $DIR/codec.rs:284:15 + | +284 | fn decode(input: &mut I) -> Result; + | ^^^^^ required by this bound in `parity_scale_codec::Decode::decode` diff --git a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr index bf4c05bb4e5b5..06384b0b66b84 100644 --- a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr +++ b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr @@ -19,7 +19,7 @@ error[E0369]: binary operation `==` cannot be applied to type `& { - | ^^^^^^^^^^^^^^^^^^^^^ + | +++++++++++++++++++++ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` --> $DIR/event_field_not_member.rs:23:7 diff --git a/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr b/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr index ad8300b8d89b8..057611367fe5f 100644 --- a/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr +++ b/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr @@ -4,7 +4,8 @@ error[E0277]: the trait bound `pallet::GenesisConfig: std::default::Default` is 22 | impl GenesisBuild for GenesisConfig {} | ^^^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `pallet::GenesisConfig` | - ::: $WORKSPACE/frame/support/src/traits/hooks.rs +note: required by a bound in `GenesisBuild` + --> $DIR/hooks.rs:297:36 | - | pub trait GenesisBuild: Default + sp_runtime::traits::MaybeSerializeDeserialize { - | ------- required by this bound in `GenesisBuild` +297 | pub trait GenesisBuild: Default + sp_runtime::traits::MaybeSerializeDeserialize { + | ^^^^^^^ required by this bound in `GenesisBuild` diff --git a/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr b/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr index ecb57bec37a7b..d1a89fbb850e9 100644 --- a/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr +++ b/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr @@ -12,4 +12,4 @@ note: trait defined here, with 1 generic parameter: `BlockNumber` help: add missing generic argument | 12 | impl Hooks for Pallet {} - | ^^^^^^^^^^^^^^^^^^ + | ~~~~~~~~~~~~~~~~~~ diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index cd3032c49735a..82fd3ad884f90 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -1,3 +1,49 @@ +error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Decode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Encode` for `Bar` + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 | @@ -57,49 +103,3 @@ note: required by `build_metadata` | 113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Decode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 - | -88 | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 - | -88 | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Encode` for `Bar` - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 - | -88 | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 3d03af836986a..eb1404fc62c38 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -1,3 +1,49 @@ +error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Decode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied + --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Encode` for `Bar` + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` +note: required by `partial_storage_info` + --> $DIR/storage.rs:88:2 + | +88 | fn partial_storage_info() -> Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 | @@ -57,49 +103,3 @@ note: required by `build_metadata` | 113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Decode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 - | -88 | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 - | -88 | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Encode` for `Bar` - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 - | -88 | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.stderr b/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.stderr index 85d7342b253d4..6288dcd534b60 100644 --- a/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.stderr +++ b/frame/support/test/tests/pallet_ui/type_value_forgotten_where_clause.stderr @@ -1,47 +1,53 @@ error[E0277]: the trait bound `::AccountId: From` is not satisfied --> $DIR/type_value_forgotten_where_clause.rs:24:34 | -7 | pub trait Config: frame_system::Config - | ------ required by a bound in this -8 | where ::AccountId: From - | --------- required by this bound in `pallet::Config` -... 24 | #[pallet::type_value] fn Foo() -> u32 { 3u32 } | ^^^^^^ the trait `From` is not implemented for `::AccountId` | +note: required by a bound in `pallet::Config` + --> $DIR/type_value_forgotten_where_clause.rs:8:51 + | +7 | pub trait Config: frame_system::Config + | ------ required by a bound in this +8 | where ::AccountId: From + | ^^^^^^^^^ required by this bound in `pallet::Config` help: consider further restricting the associated type | 24 | #[pallet::type_value] fn Foo() -> u32 where ::AccountId: From { 3u32 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0277]: the trait bound `::AccountId: From` is not satisfied --> $DIR/type_value_forgotten_where_clause.rs:24:12 | -7 | pub trait Config: frame_system::Config - | ------ required by a bound in this -8 | where ::AccountId: From - | --------- required by this bound in `pallet::Config` -... 24 | #[pallet::type_value] fn Foo() -> u32 { 3u32 } | ^^^^^^^^^^ the trait `From` is not implemented for `::AccountId` | +note: required by a bound in `pallet::Config` + --> $DIR/type_value_forgotten_where_clause.rs:8:51 + | +7 | pub trait Config: frame_system::Config + | ------ required by a bound in this +8 | where ::AccountId: From + | ^^^^^^^^^ required by this bound in `pallet::Config` help: consider further restricting the associated type | 24 | #[pallet::type_value where ::AccountId: From] fn Foo() -> u32 { 3u32 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0277]: the trait bound `::AccountId: From` is not satisfied --> $DIR/type_value_forgotten_where_clause.rs:24:12 | -7 | pub trait Config: frame_system::Config - | ------ required by a bound in this -8 | where ::AccountId: From - | --------- required by this bound in `pallet::Config` -... 24 | #[pallet::type_value] fn Foo() -> u32 { 3u32 } | ^^^^^^^^^^ the trait `From` is not implemented for `::AccountId` | +note: required by a bound in `pallet::Config` + --> $DIR/type_value_forgotten_where_clause.rs:8:51 + | +7 | pub trait Config: frame_system::Config + | ------ required by a bound in this +8 | where ::AccountId: From + | ^^^^^^^^^ required by this bound in `pallet::Config` help: consider further restricting the associated type | 24 | #[pallet::type_value] fn Foo() -> u32 where ::AccountId: From { 3u32 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index 063cbff60f81e..d11aebbf149bb 100644 --- a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -58,7 +58,10 @@ error[E0308]: mismatched types --> $DIR/type_reference_in_impl_runtime_apis_call.rs:19:11 | 19 | fn test(data: &u64) { - | ^^^^^^^ - | | - | expected `u64`, found `&u64` - | help: consider removing the borrow: `data` + | ^^^^^^^ expected `u64`, found `&u64` + | +help: consider removing the borrow + | +19 - fn test(data: &u64) { +19 + fn test(data: &u64) { + | From 45f0007c262b4e51f82d02f13aece1a0401028b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Nov 2021 19:52:41 +0000 Subject: [PATCH 0177/1472] Bump directories from 3.0.2 to 4.0.1 (#10163) Bumps [directories](https://github.com/soc/directories-rs) from 3.0.2 to 4.0.1. - [Release notes](https://github.com/soc/directories-rs/releases) - [Commits](https://github.com/soc/directories-rs/commits) --- updated-dependencies: - dependency-name: directories 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 | 4 ++-- client/service/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39dedb31839dd..307274395cc3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1531,9 +1531,9 @@ dependencies = [ [[package]] name = "directories" -version = "3.0.2" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69600ff1703123957937708eb27f7a564e48885c537782722ed0ba3189ce1d7" +checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" dependencies = [ "dirs-sys", ] diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index c3ae1452042f4..bb8c9ecf6a0cb 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -80,7 +80,7 @@ parity-util-mem = { version = "0.10.0", default-features = false, features = [ async-trait = "0.1.50" tokio = { version = "1.10", features = ["time", "rt-multi-thread"] } tempfile = "3.1.0" -directories = "3.0.2" +directories = "4.0.1" [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } From 4f3b9c318551ecd88d3af6074bc05a20b060fe1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Nov 2021 22:43:23 +0000 Subject: [PATCH 0178/1472] Bump linregress from 0.4.3 to 0.4.4 (#10124) Bumps [linregress](https://github.com/n1m3/linregress) from 0.4.3 to 0.4.4. - [Release notes](https://github.com/n1m3/linregress/releases) - [Changelog](https://github.com/n1m3/linregress/blob/master/CHANGELOG.md) - [Commits](https://github.com/n1m3/linregress/compare/0.4.3...0.4.4) --- updated-dependencies: - dependency-name: linregress 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 ++-- frame/benchmarking/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 307274395cc3c..7ade00bc40040 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3927,9 +3927,9 @@ dependencies = [ [[package]] name = "linregress" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6e407dadb4ca4b31bc69c27aff00e7ca4534fdcee855159b039a7cebb5f395" +checksum = "d6c601a85f5ecd1aba625247bca0031585fb1c446461b142878a16f8245ddeb8" dependencies = [ "nalgebra", "statrs", diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 0600b934d44e2..dffada428248a 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -linregress = { version = "0.4.3", optional = true } +linregress = { version = "0.4.4", optional = true } paste = "1.0" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } From e40710abffde7dffcd30eb51756a7a1e9eb0e249 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Thu, 4 Nov 2021 11:11:39 +0100 Subject: [PATCH 0179/1472] handle doc on type_value (#10132) --- .../procedural/src/pallet/expand/type_value.rs | 3 +++ .../procedural/src/pallet/parse/type_value.rs | 18 +++++++++++++++--- frame/support/test/tests/pallet.rs | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/type_value.rs b/frame/support/procedural/src/pallet/expand/type_value.rs index 535a187773807..af4f0b3a67947 100644 --- a/frame/support/procedural/src/pallet/expand/type_value.rs +++ b/frame/support/procedural/src/pallet/expand/type_value.rs @@ -59,7 +59,10 @@ pub fn expand_type_values(def: &mut Def) -> proc_macro2::TokenStream { (Default::default(), Default::default()) }; + let docs = &type_value.docs; + expand.extend(quote::quote_spanned!(type_value.attr_span => + #( #[doc = #docs] )* #vis struct #ident<#struct_use_gen>(core::marker::PhantomData<((), #struct_use_gen)>); impl<#struct_impl_gen> #frame_support::traits::Get<#type_> for #ident<#struct_use_gen> #where_clause diff --git a/frame/support/procedural/src/pallet/parse/type_value.rs b/frame/support/procedural/src/pallet/parse/type_value.rs index 7b9d57472db4b..d6cd4d02df8bd 100644 --- a/frame/support/procedural/src/pallet/parse/type_value.rs +++ b/frame/support/procedural/src/pallet/parse/type_value.rs @@ -38,6 +38,8 @@ pub struct TypeValueDef { pub where_clause: Option, /// The span of the pallet::type_value attribute. pub attr_span: proc_macro2::Span, + /// Docs on the item. + pub docs: Vec, } impl TypeValueDef { @@ -53,9 +55,18 @@ impl TypeValueDef { return Err(syn::Error::new(item.span(), msg)) }; - if !item.attrs.is_empty() { - let msg = "Invalid pallet::type_value, unexpected attribute"; - return Err(syn::Error::new(item.attrs[0].span(), msg)) + let mut docs = vec![]; + for attr in &item.attrs { + if let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() { + if meta.path.get_ident().map_or(false, |ident| ident == "doc") { + docs.push(meta.lit); + continue + } + } + + let msg = "Invalid pallet::type_value, unexpected attribute, only doc attribute are \ + allowed"; + return Err(syn::Error::new(attr.span(), msg)) } if let Some(span) = item @@ -106,6 +117,7 @@ impl TypeValueDef { type_, instances, where_clause, + docs, }) } } diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index a314f576187dc..dd171c5b12ec2 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -262,6 +262,7 @@ pub mod pallet { #[pallet::storage_prefix = "Value2"] pub type RenamedValue = StorageValue; + /// Test some doc #[pallet::type_value] pub fn MyDefault() -> u16 where From 6af19fdc47f16bee2901908e34b70d6d7ba80c59 Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Thu, 4 Nov 2021 14:37:26 +0100 Subject: [PATCH 0180/1472] Update node-template `construct_runtime!` syntax (#10155) * update `construct_runtime!` syntax * fix build --- bin/node-template/node/src/chain_spec.rs | 1 + bin/node-template/runtime/src/lib.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/bin/node-template/node/src/chain_spec.rs b/bin/node-template/node/src/chain_spec.rs index 7009b3be5c279..baf5e5d41ab85 100644 --- a/bin/node-template/node/src/chain_spec.rs +++ b/bin/node-template/node/src/chain_spec.rs @@ -150,5 +150,6 @@ fn testnet_genesis( // Assign network admin rights. key: root_key, }, + transaction_payment: Default::default(), } } diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index dbea698002c60..8ecb2199dda71 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -286,16 +286,16 @@ construct_runtime!( NodeBlock = opaque::Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - Aura: pallet_aura::{Pallet, Config}, - Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, - Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event}, + System: frame_system, + RandomnessCollectiveFlip: pallet_randomness_collective_flip, + Timestamp: pallet_timestamp, + Aura: pallet_aura, + Grandpa: pallet_grandpa, + Balances: pallet_balances, + TransactionPayment: pallet_transaction_payment, + Sudo: pallet_sudo, // Include the custom logic from the pallet-template in the runtime. - TemplateModule: pallet_template::{Pallet, Call, Storage, Event}, + TemplateModule: pallet_template, } ); From a9465729e2c5d2ef8d87ac404da27e5e10adde8a Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Fri, 5 Nov 2021 03:34:29 +1300 Subject: [PATCH 0181/1472] implement dispatch_as (#9934) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * implement dispatch_as * fix * fix * weight for dispatch_as * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_utility --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/utility/src/weights.rs --template=./.maintain/frame-weight-template.hbs * fix * Update frame/utility/src/benchmarking.rs Co-authored-by: Alexander Theißen * fix issues Co-authored-by: Parity Bot Co-authored-by: Alexander Theißen Co-authored-by: Shawn Tabrizi --- bin/node/runtime/src/lib.rs | 1 + frame/contracts/src/tests.rs | 1 + frame/proxy/src/tests.rs | 1 + frame/utility/src/benchmarking.rs | 9 ++++++++ frame/utility/src/lib.rs | 38 +++++++++++++++++++++++++++++++ frame/utility/src/tests.rs | 1 + frame/utility/src/weights.rs | 33 ++++++++++++++++----------- 7 files changed, 71 insertions(+), 13 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index c0ad9bb006c92..570abe53ed01f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -226,6 +226,7 @@ impl pallet_randomness_collective_flip::Config for Runtime {} impl pallet_utility::Config for Runtime { type Event = Event; type Call = Call; + type PalletsOrigin = OriginCaller; type WeightInfo = pallet_utility::weights::SubstrateWeight; } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 310c1d4cb2dd9..bd5dbae5b34a6 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -244,6 +244,7 @@ impl pallet_timestamp::Config for Test { impl pallet_utility::Config for Test { type Event = Event; type Call = Call; + type PalletsOrigin = OriginCaller; type WeightInfo = (); } parameter_types! { diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 20efd085fe882..93a0e4ce7d622 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -96,6 +96,7 @@ impl pallet_balances::Config for Test { impl pallet_utility::Config for Test { type Event = Event; type Call = Call; + type PalletsOrigin = OriginCaller; type WeightInfo = (); } parameter_types! { diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index 70cc61f87b9c9..ce59d7e898eb1 100644 --- a/frame/utility/src/benchmarking.rs +++ b/frame/utility/src/benchmarking.rs @@ -30,6 +30,7 @@ fn assert_last_event(generic_event: ::Event) { } benchmarks! { + where_clause { where ::PalletsOrigin: Clone } batch { let c in 0 .. 1000; let mut calls: Vec<::Call> = Vec::new(); @@ -64,5 +65,13 @@ benchmarks! { assert_last_event::(Event::BatchCompleted.into()) } + dispatch_as { + let caller = account("caller", SEED, SEED); + let call = Box::new(frame_system::Call::remark { remark: vec![] }.into()); + let origin: T::Origin = RawOrigin::Signed(caller).into(); + let pallets_origin: ::PalletsOrigin = origin.caller().clone(); + let pallets_origin = Into::::into(pallets_origin.clone()); + }: _(RawOrigin::Root, Box::new(pallets_origin), call) + impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 8712cf74f451b..241526cef2230 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -96,6 +96,11 @@ pub mod pallet { + IsSubType> + IsType<::Call>; + /// The caller origin, overarching type of all pallets origins. + type PalletsOrigin: Parameter + + Into<::Origin> + + IsType<<::Origin as frame_support::traits::OriginTrait>::PalletsOrigin>; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -110,6 +115,8 @@ pub mod pallet { BatchCompleted, /// A single item within a Batch of dispatches has completed with no error. ItemCompleted, + /// A call was dispatched. \[result\] + DispatchedAs(DispatchResult), } // Align the call size to 1KB. As we are currently compiling the runtime for native/wasm @@ -342,6 +349,37 @@ pub mod pallet { let base_weight = T::WeightInfo::batch_all(calls_len as u32); Ok(Some(base_weight + weight).into()) } + + /// Dispatches a function call with a provided origin. + /// + /// The dispatch origin for this call must be _Root_. + /// + /// # + /// - O(1). + /// - Limited storage reads. + /// - One DB write (event). + /// - Weight of derivative `call` execution + T::WeightInfo::dispatch_as(). + /// # + #[pallet::weight({ + let dispatch_info = call.get_dispatch_info(); + ( + T::WeightInfo::dispatch_as() + .saturating_add(dispatch_info.weight), + dispatch_info.class, + ) + })] + pub fn dispatch_as( + origin: OriginFor, + as_origin: Box, + call: Box<::Call>, + ) -> DispatchResult { + ensure_root(origin)?; + + let res = call.dispatch_bypass_filter((*as_origin).into()); + + Self::deposit_event(Event::DispatchedAs(res.map(|_| ()).map_err(|e| e.error))); + Ok(()) + } } } diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index cb7a3d9a21e29..f4d09a30ec078 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -168,6 +168,7 @@ impl Contains for TestBaseCallFilter { impl Config for Test { type Event = Event; type Call = Call; + type PalletsOrigin = OriginCaller; type WeightInfo = (); } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 6ac23419e3ef7..bce18271684bc 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_utility //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-10-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -48,39 +48,46 @@ pub trait WeightInfo { fn batch(c: u32, ) -> Weight; fn as_derivative() -> Weight; fn batch_all(c: u32, ) -> Weight; + fn dispatch_as() -> Weight; } /// Weights for pallet_utility using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn batch(c: u32, ) -> Weight { - (30_319_000 as Weight) + (18_293_000 as Weight) // Standard Error: 3_000 - .saturating_add((6_759_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((5_530_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (4_030_000 as Weight) + (3_387_000 as Weight) } fn batch_all(c: u32, ) -> Weight { - (26_621_000 as Weight) - // Standard Error: 3_000 - .saturating_add((7_251_000 as Weight).saturating_mul(c as Weight)) + (19_223_000 as Weight) + // Standard Error: 4_000 + .saturating_add((5_998_000 as Weight).saturating_mul(c as Weight)) + } + fn dispatch_as() -> Weight { + (14_340_000 as Weight) } } // For backwards compatibility and tests impl WeightInfo for () { fn batch(c: u32, ) -> Weight { - (30_319_000 as Weight) + (18_293_000 as Weight) // Standard Error: 3_000 - .saturating_add((6_759_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((5_530_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (4_030_000 as Weight) + (3_387_000 as Weight) } fn batch_all(c: u32, ) -> Weight { - (26_621_000 as Weight) - // Standard Error: 3_000 - .saturating_add((7_251_000 as Weight).saturating_mul(c as Weight)) + (19_223_000 as Weight) + // Standard Error: 4_000 + .saturating_add((5_998_000 as Weight).saturating_mul(c as Weight)) + } + fn dispatch_as() -> Weight { + (14_340_000 as Weight) } } From b89bb4c969895738ee7d76dca8811e12317a7f52 Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Thu, 4 Nov 2021 19:54:31 +0100 Subject: [PATCH 0182/1472] rm broken rustdoc-header.html (#10091) --- .gitlab-ci.yml | 3 +-- .maintain/rustdoc-header.html | 10 ---------- 2 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 .maintain/rustdoc-header.html diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 87efc43af2898..5e406b36c5c5b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -661,8 +661,7 @@ build-rustdoc: - ./crate-docs/ script: # FIXME: it fails with `RUSTDOCFLAGS="-Dwarnings"` - - RUSTDOCFLAGS="--html-in-header $(pwd)/.maintain/rustdoc-header.html" - time cargo +nightly doc --no-deps --workspace --all-features --verbose + - time cargo +nightly doc --no-deps --workspace --all-features --verbose - rm -f ./target/doc/.lock - mv ./target/doc ./crate-docs # FIXME: remove me after CI image gets nonroot diff --git a/.maintain/rustdoc-header.html b/.maintain/rustdoc-header.html deleted file mode 100644 index a679d5e299da7..0000000000000 --- a/.maintain/rustdoc-header.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - From 75458291756cad3b51346cd098a3dfcd53b5d475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 4 Nov 2021 19:54:48 +0100 Subject: [PATCH 0183/1472] Switch to Rust 2021 (#10170) * Switch to Rust 2021 * Update trybuild to fix errors --- .maintain/node-template-release/Cargo.toml | 2 +- Cargo.lock | 4 +-- bin/node-template/node/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 2 +- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- bin/node/inspect/Cargo.toml | 2 +- bin/node/primitives/Cargo.toml | 2 +- bin/node/rpc-client/Cargo.toml | 2 +- bin/node/rpc/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- bin/node/test-runner-example/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- bin/utils/chain-spec-builder/Cargo.toml | 2 +- bin/utils/subkey/Cargo.toml | 2 +- client/allocator/Cargo.toml | 2 +- client/api/Cargo.toml | 2 +- client/authority-discovery/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 2 +- client/beefy/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/block-builder/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/chain-spec/derive/Cargo.toml | 2 +- client/chain-spec/derive/src/impls.rs | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/epochs/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 2 +- client/consensus/uncles/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/executor/common/Cargo.toml | 2 +- client/executor/runtime-test/Cargo.toml | 2 +- client/executor/src/wasm_runtime.rs | 1 - client/executor/wasmi/Cargo.toml | 2 +- client/executor/wasmtime/Cargo.toml | 2 +- client/finality-grandpa-warp-sync/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/finality-grandpa/rpc/src/report.rs | 4 --- client/informant/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/light/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/src/protocol/sync.rs | 1 - .../src/protocol/sync/extra_requests.rs | 1 - client/network/test/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/proposer-metrics/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/rpc/src/chain/mod.rs | 2 -- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- client/state-db/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/tracing/proc-macro/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- client/utils/Cargo.toml | 2 +- frame/assets/Cargo.toml | 2 +- frame/atomic-swap/Cargo.toml | 2 +- frame/aura/Cargo.toml | 2 +- frame/authority-discovery/Cargo.toml | 2 +- frame/authorship/Cargo.toml | 2 +- frame/babe/Cargo.toml | 2 +- frame/bags-list/Cargo.toml | 2 +- frame/bags-list/fuzzer/Cargo.toml | 2 +- frame/bags-list/remote-tests/Cargo.toml | 2 +- frame/balances/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/beefy-mmr/primitives/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 2 +- frame/bounties/Cargo.toml | 2 +- frame/collective/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/common/Cargo.toml | 2 +- frame/contracts/proc-macro/Cargo.toml | 2 +- frame/contracts/rpc/Cargo.toml | 2 +- frame/contracts/rpc/runtime-api/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 2 +- frame/election-provider-support/Cargo.toml | 2 +- frame/elections-phragmen/Cargo.toml | 2 +- frame/elections/Cargo.toml | 2 +- frame/example-offchain-worker/Cargo.toml | 2 +- frame/example-parallel/Cargo.toml | 2 +- frame/example-parallel/src/lib.rs | 1 - frame/example/Cargo.toml | 2 +- frame/executive/Cargo.toml | 2 +- frame/gilt/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/identity/Cargo.toml | 2 +- frame/im-online/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- frame/lottery/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- .../primitives/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 2 +- frame/nicks/Cargo.toml | 2 +- frame/node-authorization/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/offences/benchmarking/Cargo.toml | 2 +- frame/proxy/Cargo.toml | 2 +- frame/randomness-collective-flip/Cargo.toml | 2 +- frame/recovery/Cargo.toml | 2 +- frame/scheduler/Cargo.toml | 2 +- frame/scored-pool/Cargo.toml | 2 +- frame/session/Cargo.toml | 2 +- frame/session/benchmarking/Cargo.toml | 2 +- frame/society/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/staking/reward-fn/Cargo.toml | 2 +- frame/staking/src/pallet/impls.rs | 3 -- frame/sudo/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- .../procedural/src/pallet/expand/constants.rs | 2 +- .../procedural/src/pallet/expand/event.rs | 4 +-- .../src/storage/genesis_config/mod.rs | 8 ++--- .../support/procedural/src/storage/getters.rs | 2 +- .../procedural/src/storage/metadata.rs | 2 +- .../procedural/src/storage/storage_info.rs | 2 +- .../procedural/src/storage/store_trait.rs | 2 +- frame/support/procedural/tools/Cargo.toml | 2 +- .../procedural/tools/derive/Cargo.toml | 2 +- .../procedural/tools/derive/src/lib.rs | 2 +- frame/support/src/traits/members.rs | 2 +- frame/support/test/Cargo.toml | 8 +++-- frame/support/test/compile_pass/Cargo.toml | 2 +- frame/support/test/pallet/Cargo.toml | 2 +- frame/support/test/tests/pallet.rs | 34 +++++++++---------- frame/system/Cargo.toml | 2 +- frame/system/benchmarking/Cargo.toml | 2 +- frame/system/rpc/runtime-api/Cargo.toml | 2 +- frame/timestamp/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- frame/transaction-payment/rpc/Cargo.toml | 2 +- .../rpc/runtime-api/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- frame/try-runtime/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 2 +- frame/utility/Cargo.toml | 2 +- frame/vesting/Cargo.toml | 2 +- primitives/api/Cargo.toml | 2 +- primitives/api/proc-macro/Cargo.toml | 2 +- .../api/proc-macro/src/decl_runtime_apis.rs | 2 +- primitives/api/src/lib.rs | 2 -- primitives/api/test/Cargo.toml | 4 +-- primitives/application-crypto/Cargo.toml | 2 +- primitives/application-crypto/test/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/arithmetic/fuzzer/Cargo.toml | 2 +- primitives/authority-discovery/Cargo.toml | 2 +- primitives/authorship/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 2 +- primitives/block-builder/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/consensus/aura/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/consensus/common/Cargo.toml | 2 +- primitives/consensus/pow/Cargo.toml | 2 +- primitives/consensus/slots/Cargo.toml | 2 +- primitives/consensus/vrf/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/core/hashing/Cargo.toml | 2 +- primitives/core/hashing/proc-macro/Cargo.toml | 2 +- primitives/database/Cargo.toml | 2 +- primitives/debug-derive/Cargo.toml | 2 +- primitives/externalities/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/finality-grandpa/src/lib.rs | 1 - primitives/inherents/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/keyring/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- primitives/maybe-compressed-blob/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- .../npos-elections/solution-type/Cargo.toml | 4 +-- primitives/offchain/Cargo.toml | 2 +- primitives/panic-handler/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 4 +-- .../runtime-interface/proc-macro/Cargo.toml | 2 +- .../test-wasm-deprecated/Cargo.toml | 2 +- .../runtime-interface/test-wasm/Cargo.toml | 2 +- primitives/runtime-interface/test/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/sandbox/Cargo.toml | 2 +- primitives/serializer/Cargo.toml | 2 +- primitives/session/Cargo.toml | 2 +- primitives/staking/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/std/Cargo.toml | 2 +- primitives/storage/Cargo.toml | 2 +- primitives/tasks/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 2 +- primitives/timestamp/Cargo.toml | 2 +- primitives/tracing/Cargo.toml | 2 +- primitives/transaction-pool/Cargo.toml | 2 +- .../transaction-storage-proof/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 2 +- primitives/version/Cargo.toml | 2 +- primitives/version/proc-macro/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- test-utils/Cargo.toml | 4 +-- test-utils/client/Cargo.toml | 2 +- test-utils/derive/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- test-utils/runtime/client/Cargo.toml | 2 +- .../runtime/transaction-pool/Cargo.toml | 2 +- test-utils/test-crate/Cargo.toml | 2 +- test-utils/test-runner/Cargo.toml | 2 +- utils/build-script-utils/Cargo.toml | 2 +- utils/fork-tree/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/frame-utilities-cli/Cargo.toml | 2 +- utils/frame/generate-bags/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- utils/frame/generate-bags/src/lib.rs | 1 - utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 2 +- utils/wasm-builder/Cargo.toml | 2 +- 245 files changed, 264 insertions(+), 279 deletions(-) diff --git a/.maintain/node-template-release/Cargo.toml b/.maintain/node-template-release/Cargo.toml index c1d9f2da7faea..26256e8363301 100644 --- a/.maintain/node-template-release/Cargo.toml +++ b/.maintain/node-template-release/Cargo.toml @@ -2,7 +2,7 @@ name = "node-template-release" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0" [dependencies] diff --git a/Cargo.lock b/Cargo.lock index 7ade00bc40040..4a50fe3565715 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10944,9 +10944,9 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.43" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02c413315329fc96167f922b46fd0caa3a43f4697b7a7896b183c7142635832" +checksum = "150e726dc059e6fbd4fce3288f5bb3cf70128cf63b0dde23b938a3cad810fb23" dependencies = [ "dissimilar", "glob", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 57d9c5f3f71e0..1d8abad406a14 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" description = "A fresh FRAME-based Substrate node, ready for hacking." authors = ["Substrate DevHub "] homepage = "https://substrate.io/" -edition = "2018" +edition = "2021" license = "Unlicense" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index e9f557f3fb5a4..e4e2039866b46 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0" description = 'A fresh FRAME-based Substrate runtime, ready for hacking.' authors = ["Substrate DevHub "] homepage = "https://substrate.io/" -edition = "2018" +edition = "2021" license = "Unlicense" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index b19a71966fb87..f59ea2361186c 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -3,7 +3,7 @@ name = "node-bench" version = "0.9.0-dev" authors = ["Parity Technologies "] description = "Substrate node integration benchmarks." -edition = "2018" +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 diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 1d394dd952db0..38c161a81ef06 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -4,7 +4,7 @@ version = "3.0.0-dev" authors = ["Parity Technologies "] description = "Generic Substrate node implementation in Rust." build = "build.rs" -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" default-run = "substrate" homepage = "https://substrate.io" diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 462bb034610e9..21785079c6c54 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -3,7 +3,7 @@ name = "node-executor" version = "3.0.0-dev" authors = ["Parity Technologies "] description = "Substrate node implementation in Rust." -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index 6f526b896ba76..6504f39a05822 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -2,7 +2,7 @@ name = "node-inspect" version = "0.9.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 07c3aca6059f6..2c8185d5c9c47 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -2,7 +2,7 @@ name = "node-primitives" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/bin/node/rpc-client/Cargo.toml b/bin/node/rpc-client/Cargo.toml index 59695edb6fa26..5c822ef3ad31a 100644 --- a/bin/node/rpc-client/Cargo.toml +++ b/bin/node/rpc-client/Cargo.toml @@ -2,7 +2,7 @@ name = "node-rpc-client" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 4c7b15459cea9..ef111e3f1949c 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -2,7 +2,7 @@ name = "node-rpc" version = "3.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 22ff0954e2458..c0b888e55b1f6 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -2,7 +2,7 @@ name = "node-runtime" version = "3.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" build = "build.rs" license = "Apache-2.0" homepage = "https://substrate.io" diff --git a/bin/node/test-runner-example/Cargo.toml b/bin/node/test-runner-example/Cargo.toml index 96c4c2047ac4f..b664cdb8e50e2 100644 --- a/bin/node/test-runner-example/Cargo.toml +++ b/bin/node/test-runner-example/Cargo.toml @@ -2,7 +2,7 @@ name = "test-runner-example" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" publish = false [dependencies] diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index e5d13189ac2fe..1854029b0709e 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -3,7 +3,7 @@ name = "node-testing" version = "3.0.0-dev" authors = ["Parity Technologies "] description = "Test utilities for Substrate node." -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index bfbf2da57a6a0..a35fbba5cdc46 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -2,7 +2,7 @@ name = "chain-spec-builder" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" diff --git a/bin/utils/subkey/Cargo.toml b/bin/utils/subkey/Cargo.toml index 5e7615f60d628..14ba673b33be2 100644 --- a/bin/utils/subkey/Cargo.toml +++ b/bin/utils/subkey/Cargo.toml @@ -2,7 +2,7 @@ name = "subkey" version = "2.0.1" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index 9383b88f756cb..2b37c192c6e3e 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-allocator" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index af8704058b660..7b2952552a3d0 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-client-api" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index dca365981984d..dc4b929756810 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-authority-discovery" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 1ecdb08eba489..96ab698f36213 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-basic-authorship" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index d4541288a6287..37dc4491e21d4 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -2,7 +2,7 @@ name = "beefy-gadget" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 8af2fa3eac867..47fd2b740370c 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -2,7 +2,7 @@ name = "beefy-gadget-rpc" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 9d2703fc2ed2a..25950a9e9061f 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-block-builder" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index ba9655261923b..d7557e2062ac4 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-chain-spec" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index 73083e4a6e0ba..386137d0667ad 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-chain-spec-derive" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/chain-spec/derive/src/impls.rs b/client/chain-spec/derive/src/impls.rs index 8c56430e81d02..87a3db063c782 100644 --- a/client/chain-spec/derive/src/impls.rs +++ b/client/chain-spec/derive/src/impls.rs @@ -52,7 +52,7 @@ pub fn extension_derive(ast: &DeriveInput) -> proc_macro::TokenStream { use std::any::{Any, TypeId}; match TypeId::of::() { - #( x if x == TypeId::of::<#field_types>() => Any::downcast_ref(&self.#field_names) ),*, + #( x if x == TypeId::of::<#field_types>() => ::downcast_ref(&self.#field_names) ),*, _ => None, } } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 0cee37f25e797..4b6ef3bab9505 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-cli" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Substrate CLI interface." -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 1c767319b1229..62d7b3d5327ad 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-consensus-aura" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Aura consensus algorithm for substrate" -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 66ad6287f40df..8430ca39c9cb7 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-consensus-babe" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "BABE consensus algorithm for substrate" -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 7ef9b1c1de3c4..bc57092d34001 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-consensus-babe-rpc" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "RPC extensions for the BABE consensus algorithm" -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 30840a974f9aa..d63d124ed60e5 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-consensus" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/consensus/epochs/Cargo.toml b/client/consensus/epochs/Cargo.toml index 90a708d07e2a2..4cac4a24d1879 100644 --- a/client/consensus/epochs/Cargo.toml +++ b/client/consensus/epochs/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-consensus-epochs" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Generic epochs-based utilities for consensus" -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 9b29bb3dc71c7..a662ebf01011d 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-consensus-manual-seal" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Manual sealing engine for Substrate" -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index c570c1ccbad27..bc7c01181e41b 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-consensus-pow" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "PoW consensus algorithm for substrate" -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 6c1f865c62cb0..5c5f1bdfa68cd 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-consensus-slots" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Generic slots-based utilities for consensus" -edition = "2018" +edition = "2021" build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml index 73768f0d09411..f644d64c7bbeb 100644 --- a/client/consensus/uncles/Cargo.toml +++ b/client/consensus/uncles/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-consensus-uncles" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Generic uncle inclusion utilities for consensus" -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 165d01d555116..19bf7ad248fe5 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-client-db" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index bc55172bc33ef..028854992a094 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-executor" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 622baa6c0dcab..fc7d5a1528470 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-executor-common" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index ac1e3413491d9..1e3b5e926b964 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-runtime-test" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" publish = false diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 204a095717fc4..88c033814ed6a 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -356,7 +356,6 @@ fn decode_version(mut version: &[u8]) -> Result { fn decode_runtime_apis(apis: &[u8]) -> Result, WasmError> { use sp_api::RUNTIME_API_INFO_SIZE; - use std::convert::TryFrom; apis.chunks(RUNTIME_API_INFO_SIZE) .map(|chunk| { diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 307ba908e23b6..6311b0234866f 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-executor-wasmi" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 7a877bd9578f5..741898b8282c2 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-executor-wasmtime" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/finality-grandpa-warp-sync/Cargo.toml b/client/finality-grandpa-warp-sync/Cargo.toml index 9736b25ccac55..6280add275628 100644 --- a/client/finality-grandpa-warp-sync/Cargo.toml +++ b/client/finality-grandpa-warp-sync/Cargo.toml @@ -4,7 +4,7 @@ name = "sc-finality-grandpa-warp-sync" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 2d45fa100f79d..fd0b52cd1f70b 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-finality-grandpa" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index d2976ee71275f..ad39ad6ba95b3 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -4,7 +4,7 @@ version = "0.10.0-dev" authors = ["Parity Technologies "] description = "RPC extensions for the GRANDPA finality gadget" repository = "https://github.com/paritytech/substrate/" -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" readme = "README.md" diff --git a/client/finality-grandpa/rpc/src/report.rs b/client/finality-grandpa/rpc/src/report.rs index fef8f22659953..fc97c176f34f0 100644 --- a/client/finality-grandpa/rpc/src/report.rs +++ b/client/finality-grandpa/rpc/src/report.rs @@ -87,8 +87,6 @@ impl RoundState { round_state: &report::RoundState, voters: &HashSet, ) -> Result { - use std::convert::TryInto; - let prevotes = &round_state.prevote_ids; let missing_prevotes = voters.difference(&prevotes).cloned().collect(); @@ -130,8 +128,6 @@ impl ReportedRoundStates { AuthoritySet: ReportAuthoritySet, VoterState: ReportVoterState, { - use std::convert::TryFrom; - let voter_state = voter_state.get().ok_or(Error::EndpointNotReady)?; let (set_id, current_voters) = authority_set.get(); diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index c28dd4e011945..7d92e14e5d471 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-informant" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Substrate informant." -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 74fd85c184c6f..bd158091e747c 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-keystore" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/light/Cargo.toml b/client/light/Cargo.toml index cc567c60524a1..1b83bf5be42f4 100644 --- a/client/light/Cargo.toml +++ b/client/light/Cargo.toml @@ -4,7 +4,7 @@ name = "sc-light" version = "4.0.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-light" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index b4907ade834aa..1f0b5c313294d 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -4,7 +4,7 @@ name = "sc-network-gossip" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-network-gossip" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 7b4b30c593855..7c2905d5fe03a 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -4,7 +4,7 @@ name = "sc-network" version = "0.10.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-network" diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index 7f85c2b637826..37646875e3b16 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -2172,7 +2172,6 @@ impl ChainSync { /// Return some key metrics. pub(crate) fn metrics(&self) -> Metrics { - use std::convert::TryInto; Metrics { queued_blocks: self.queue_blocks.len().try_into().unwrap_or(std::u32::MAX), fork_targets: self.fork_targets.len().try_into().unwrap_or(std::u32::MAX), diff --git a/client/network/src/protocol/sync/extra_requests.rs b/client/network/src/protocol/sync/extra_requests.rs index 226762b9658d2..c00837169598b 100644 --- a/client/network/src/protocol/sync/extra_requests.rs +++ b/client/network/src/protocol/sync/extra_requests.rs @@ -255,7 +255,6 @@ impl ExtraRequests { /// Get some key metrics. pub(crate) fn metrics(&self) -> Metrics { - use std::convert::TryInto; Metrics { pending_requests: self.pending_requests.len().try_into().unwrap_or(std::u32::MAX), active_requests: self.active_requests.len().try_into().unwrap_or(std::u32::MAX), diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 13555952cffd5..539c57fe4cb91 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -4,7 +4,7 @@ name = "sc-network-test" version = "0.8.0" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" publish = false homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 104a0e61f3180..ee697b32e1e4b 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -4,7 +4,7 @@ name = "sc-offchain" version = "4.0.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index a7e9130cfff1c..01b75f1094ff4 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -5,7 +5,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" name = "sc-peerset" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-peerset" readme = "README.md" diff --git a/client/proposer-metrics/Cargo.toml b/client/proposer-metrics/Cargo.toml index 296329a5fda77..93c4cce93ca65 100644 --- a/client/proposer-metrics/Cargo.toml +++ b/client/proposer-metrics/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-proposer-metrics" version = "0.9.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 192cf02e7ce17..532a5cf6294ce 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-rpc-api" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index cbbea00d6f576..b3f408cc59806 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-rpc-server" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index f5c7f99ff7435..d8aecfe9fd354 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-rpc" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index a06c3a094b40f..9428ac3248f32 100644 --- a/client/rpc/src/chain/mod.rs +++ b/client/rpc/src/chain/mod.rs @@ -83,8 +83,6 @@ where match number { None => Ok(Some(self.client().info().best_hash)), Some(num_or_hex) => { - use std::convert::TryInto; - // FIXME <2329>: Database seems to limit the block number to u32 for no reason let block_num: u32 = num_or_hex.try_into().map_err(|_| { Error::Other(format!( diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index bb8c9ecf6a0cb..5c22c1e4fca1c 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-service" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index aeee4a5f90728..49eca272ac75c 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-service-test" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" publish = false homepage = "https://substrate.io" diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 136fe7a199f0c..abd378c6fff38 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-state-db" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 4166929ff0317..a9503b992ab37 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-sync-state-rpc" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "A RPC handler to create sync states for light clients." -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 502c7fc20781f..5a25aca29b60b 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-telemetry" version = "4.0.0-dev" authors = ["Parity Technologies "] description = "Telemetry utils" -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 8093420dc5b95..8640208ad3427 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -3,7 +3,7 @@ name = "sc-tracing" version = "4.0.0-dev" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Instrumentation implementation for substrate." diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index 5cc2d836dcada..9c8579ee66a45 100644 --- a/client/tracing/proc-macro/Cargo.toml +++ b/client/tracing/proc-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-tracing-proc-macro" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 12642559a3b8d..6d05125002f2e 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-transaction-pool" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 7dd1a6724ce59..176624611fbf5 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-transaction-pool-api" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index 546232cf60708..6d04fd4e9acdf 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -2,7 +2,7 @@ name = "sc-utils" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 65162430a2ac1..08cadb527750b 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-assets" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 60e8fa613f06b..303116161a2dc 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-atomic-swap" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index 1761f78edeca2..cb5903048ff8b 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-aura" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index 7e64509ce6b45..06a4e92270b2b 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-authority-discovery" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 6ac91970712d7..a24b578fc250e 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-authorship" version = "4.0.0-dev" description = "Block and Uncle Author tracking for the FRAME" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 6b0dc71b5e29a..9ae942486d627 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-babe" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 372dc87e212e2..fa47b9bad5692 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-bags-list" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/bags-list/fuzzer/Cargo.toml b/frame/bags-list/fuzzer/Cargo.toml index 171e0e7af70cd..510000f631adc 100644 --- a/frame/bags-list/fuzzer/Cargo.toml +++ b/frame/bags-list/fuzzer/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-bags-list-fuzzer" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.dev" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index ee5b8c7c3f6e7..37f351f0d27ef 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index f6e6e97850a72..4ea2e9cbe8a31 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-balances" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 3d4a9a72ddf86..0a72ee193b3a7 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-beefy-mmr" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" description = "BEEFY + MMR runtime utilities" diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/frame/beefy-mmr/primitives/Cargo.toml index d5dcc0eed3350..3669ba4c2286c 100644 --- a/frame/beefy-mmr/primitives/Cargo.toml +++ b/frame/beefy-mmr/primitives/Cargo.toml @@ -2,7 +2,7 @@ name = "beefy-merkle-tree" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" description = "A no-std/Substrate compatible library to construct binary merkle tree." diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index e5af666e7ca54..a8b516aac66ca 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-beefy" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index dffada428248a..fdc386978dee5 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-benchmarking" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index d949d0fb1d58e..cce6ed69a25ba 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-bounties" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index 3e3d167522e81..6d4567a7851e2 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-collective" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 5967600bf68f5..dec33768a0426 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-contracts" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/common/Cargo.toml index 48baf23d3aee8..c30efc6869403 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/common/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-contracts-primitives" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/contracts/proc-macro/Cargo.toml b/frame/contracts/proc-macro/Cargo.toml index 63d05bcc2f05e..db3c620397771 100644 --- a/frame/contracts/proc-macro/Cargo.toml +++ b/frame/contracts/proc-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-contracts-proc-macro" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index eec02b03aaa0e..82ce4bedb4985 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-contracts-rpc" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml index e41aa5aaec9b5..b65fbf9aba0c7 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/rpc/runtime-api/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-contracts-rpc-runtime-api" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index f0bf2109be065..1973677531e9a 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-democracy" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 3c6b405c331f0..8a0f80da10829 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 46e6500cac33a..e22338f456c44 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-election-provider-support" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index 80afc3f5d8b00..6c87be7b6d589 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-elections-phragmen" version = "5.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/elections/Cargo.toml b/frame/elections/Cargo.toml index f5c7acb1cd5d5..2ca2e584d2f43 100644 --- a/frame/elections/Cargo.toml +++ b/frame/elections/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-elections" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/example-offchain-worker/Cargo.toml b/frame/example-offchain-worker/Cargo.toml index 2759664d6e653..ffcadca26e11e 100644 --- a/frame/example-offchain-worker/Cargo.toml +++ b/frame/example-offchain-worker/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-example-offchain-worker" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Unlicense" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/example-parallel/Cargo.toml b/frame/example-parallel/Cargo.toml index 6511a1cd369bf..169db35e65f1c 100644 --- a/frame/example-parallel/Cargo.toml +++ b/frame/example-parallel/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-example-parallel" version = "3.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Unlicense" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/example-parallel/src/lib.rs b/frame/example-parallel/src/lib.rs index c86cac4295684..9d191525f631e 100644 --- a/frame/example-parallel/src/lib.rs +++ b/frame/example-parallel/src/lib.rs @@ -105,7 +105,6 @@ impl EnlistedParticipant { fn verify(&self, event_id: &[u8]) -> bool { use sp_core::Public; use sp_runtime::traits::Verify; - use std::convert::TryFrom; match sp_core::sr25519::Signature::try_from(&self.signature[..]) { Ok(signature) => { diff --git a/frame/example/Cargo.toml b/frame/example/Cargo.toml index e144f1e927d36..0b3a742de0dd7 100644 --- a/frame/example/Cargo.toml +++ b/frame/example/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-example" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Unlicense" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 44b4dbcf2bd30..52d2f41cb1e34 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-executive" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index c7dc384662f97..6b2eae1156a89 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-gilt" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 36cc43fc3443e..af125d64ea218 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-grandpa" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index e6d1fa3e9dfbc..9a370674e5876 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-identity" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index ef2fe54a8ceef..f4cf5a9077c9b 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-im-online" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index bf5a82fbb1da7..f1913d4138be0 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-indices" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 854b6f52470d7..d4ee5b8008f19 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-lottery" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 9fdfaa4731729..a3747ca0576f5 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-membership" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 942067ebde3ed..ca09725769ab2 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-mmr" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index bbf55a2b7089e..0531a295fafe3 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-mmr-primitives" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 926cfd602f673..881cbb3c8ebfe 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-mmr-rpc" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index d1bd23dcab581..2b0d8f5cee792 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-multisig" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index dacec5567ede4..039fd7f97c851 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-nicks" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 960f7e04688dd..450da1325f67e 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-node-authorization" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 97f4644a83ca0..15939027d3be1 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-offences" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index f8459087cb7fb..cf628b6967ce0 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-offences-benchmarking" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index 4f4cf2bf9d56d..030209b83cc6c 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-proxy" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index ba77312699172..38fe2f73bc71b 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-randomness-collective-flip" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 092940f5173f8..12198c135e536 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-recovery" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 862321dfa6f26..fab2bc2c635ca 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-scheduler" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Unlicense" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index a7d75ccacb96e..d60e55ae98963 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-scored-pool" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 32d298d3917c3..90de15632a0ea 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-session" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 0d0868d439215..31a028679cfb9 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-session-benchmarking" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index ab2c379c51b5c..8a817f7e0060b 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-society" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 4b608bd91dc76..d9461ab454f39 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-staking" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index e44188bf7894e..15ff3a8727305 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-staking-reward-curve" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/staking/reward-fn/Cargo.toml b/frame/staking/reward-fn/Cargo.toml index ae0b7f50c994c..4e3be2a1bc719 100644 --- a/frame/staking/reward-fn/Cargo.toml +++ b/frame/staking/reward-fn/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-staking-reward-fn" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index ec34efe397f5a..7ca1cb1a4a61b 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -926,7 +926,6 @@ impl ElectionDataProvider> for Pallet #[cfg(feature = "runtime-benchmarks")] fn add_voter(voter: T::AccountId, weight: VoteWeight, targets: Vec) { - use sp_std::convert::TryFrom; let stake = >::try_from(weight).unwrap_or_else(|_| { panic!("cannot convert a VoteWeight into BalanceOf, benchmark needs reconfiguring.") }); @@ -981,7 +980,6 @@ impl ElectionDataProvider> for Pallet targets: Vec, target_stake: Option, ) { - use sp_std::convert::TryFrom; targets.into_iter().for_each(|v| { let stake: BalanceOf = target_stake .and_then(|w| >::try_from(w).ok()) @@ -1256,7 +1254,6 @@ impl VoteWeightProvider for Pallet { fn set_vote_weight_of(who: &T::AccountId, weight: VoteWeight) { // this will clearly results in an inconsistent state, but it should not matter for a // benchmark. - use sp_std::convert::TryInto; let active: BalanceOf = weight.try_into().map_err(|_| ()).unwrap(); let mut ledger = Self::ledger(who).unwrap_or_default(); ledger.active = active; diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index 3587a234566ec..969dc11dbb6c5 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-sudo" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index b62ae3384fe42..42981dc160a4b 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-support" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index ed152c25fc3b7..17128388874a8 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-support-procedural" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/support/procedural/src/pallet/expand/constants.rs b/frame/support/procedural/src/pallet/expand/constants.rs index 20106c71cbf07..0fe8e467c10da 100644 --- a/frame/support/procedural/src/pallet/expand/constants.rs +++ b/frame/support/procedural/src/pallet/expand/constants.rs @@ -52,7 +52,7 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { type_: const_.type_.clone(), doc: const_.doc.clone(), default_byte_impl: quote::quote!( - let value = <::#ident as + let value = <::#ident as #frame_support::traits::Get<#const_type>>::get(); #frame_support::codec::Encode::encode(&value) ), diff --git a/frame/support/procedural/src/pallet/expand/event.rs b/frame/support/procedural/src/pallet/expand/event.rs index 625c2d98baac5..69d6b461206c9 100644 --- a/frame/support/procedural/src/pallet/expand/event.rs +++ b/frame/support/procedural/src/pallet/expand/event.rs @@ -134,12 +134,12 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { impl<#type_impl_gen> Pallet<#type_use_gen> #completed_where_clause { #fn_vis fn deposit_event(event: Event<#event_use_gen>) { let event = < - ::Event as + ::Event as From> >::from(event); let event = < - ::Event as + ::Event as Into<::Event> >::into(event); diff --git a/frame/support/procedural/src/storage/genesis_config/mod.rs b/frame/support/procedural/src/storage/genesis_config/mod.rs index d2d1afb017736..daff8848364ee 100644 --- a/frame/support/procedural/src/storage/genesis_config/mod.rs +++ b/frame/support/procedural/src/storage/genesis_config/mod.rs @@ -75,12 +75,12 @@ fn decl_genesis_config_and_impl_default( #[serde(deny_unknown_fields)] #[serde(crate = #serde_crate)] #serde_bug_bound - pub struct GenesisConfig#genesis_struct_decl #genesis_where_clause { + pub struct GenesisConfig #genesis_struct_decl #genesis_where_clause { #( #config_fields )* } #[cfg(feature = "std")] - impl#genesis_impl Default for GenesisConfig#genesis_struct #genesis_where_clause { + impl #genesis_impl Default for GenesisConfig #genesis_struct #genesis_where_clause { fn default() -> Self { GenesisConfig { #( #config_field_defaults )* @@ -137,7 +137,7 @@ fn impl_build_storage( quote! { #[cfg(feature = "std")] - impl#genesis_impl GenesisConfig#genesis_struct #genesis_where_clause { + impl #genesis_impl GenesisConfig #genesis_struct #genesis_where_clause { /// Build the storage for this module. pub fn build_storage #fn_generic (&self) -> std::result::Result< #scrate::sp_runtime::Storage, @@ -161,7 +161,7 @@ fn impl_build_storage( } #[cfg(feature = "std")] - impl#build_storage_impl #build_storage_impl_trait for GenesisConfig#genesis_struct + impl #build_storage_impl #build_storage_impl_trait for GenesisConfig #genesis_struct #where_clause { fn build_module_genesis_storage( diff --git a/frame/support/procedural/src/storage/getters.rs b/frame/support/procedural/src/storage/getters.rs index 988e6fa096243..d877969232f84 100644 --- a/frame/support/procedural/src/storage/getters.rs +++ b/frame/support/procedural/src/storage/getters.rs @@ -92,7 +92,7 @@ pub fn impl_getters(def: &DeclStorageDefExt) -> TokenStream { let where_clause = &def.where_clause; quote!( - impl#module_impl #module_struct #where_clause { + impl #module_impl #module_struct #where_clause { #getters } ) diff --git a/frame/support/procedural/src/storage/metadata.rs b/frame/support/procedural/src/storage/metadata.rs index a90e5051c5b2e..c49a0dafdf5d0 100644 --- a/frame/support/procedural/src/storage/metadata.rs +++ b/frame/support/procedural/src/storage/metadata.rs @@ -207,7 +207,7 @@ pub fn impl_metadata(def: &DeclStorageDefExt) -> TokenStream { quote!( #default_byte_getter_struct_defs - impl#module_impl #module_struct #where_clause { + impl #module_impl #module_struct #where_clause { #[doc(hidden)] pub fn storage_metadata() -> #scrate::metadata::PalletStorageMetadata { #store_metadata diff --git a/frame/support/procedural/src/storage/storage_info.rs b/frame/support/procedural/src/storage/storage_info.rs index 844896409f851..4b1d3347b4a43 100644 --- a/frame/support/procedural/src/storage/storage_info.rs +++ b/frame/support/procedural/src/storage/storage_info.rs @@ -48,7 +48,7 @@ pub fn impl_storage_info(def: &DeclStorageDefExt) -> TokenStream { let where_clause = &def.where_clause; quote!( - impl#module_impl #scrate::traits::StorageInfoTrait for #module_struct #where_clause { + impl #module_impl #scrate::traits::StorageInfoTrait for #module_struct #where_clause { fn storage_info() -> #scrate::sp_std::vec::Vec<#scrate::traits::StorageInfo> { let mut res = #scrate::sp_std::vec![]; #res_append_storage diff --git a/frame/support/procedural/src/storage/store_trait.rs b/frame/support/procedural/src/storage/store_trait.rs index 7dde92cf9a75d..5794c72d22c8d 100644 --- a/frame/support/procedural/src/storage/store_trait.rs +++ b/frame/support/procedural/src/storage/store_trait.rs @@ -48,7 +48,7 @@ pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { #visibility trait #store_trait { #decl_store_items } - impl#module_impl #store_trait for #module_struct #where_clause { + impl #module_impl #store_trait for #module_struct #where_clause { #impl_store_items } ) diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index 6a8fb57b39bda..1207d06e6d591 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-support-procedural-tools" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/support/procedural/tools/derive/Cargo.toml b/frame/support/procedural/tools/derive/Cargo.toml index 9f4e2d9dca2a5..f0c27b5397d5d 100644 --- a/frame/support/procedural/tools/derive/Cargo.toml +++ b/frame/support/procedural/tools/derive/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-support-procedural-tools-derive" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/support/procedural/tools/derive/src/lib.rs b/frame/support/procedural/tools/derive/src/lib.rs index 7922105895608..9ce88e7c47937 100644 --- a/frame/support/procedural/tools/derive/src/lib.rs +++ b/frame/support/procedural/tools/derive/src/lib.rs @@ -131,7 +131,7 @@ fn derive_totokens_enum(input: syn::ItemEnum) -> TokenStream { }; let field = fields_idents(v.fields.iter().map(Clone::clone)); quote! { - #ident::#v_ident#fields_build => { + #ident::#v_ident #fields_build => { #( #field.to_tokens(tokens); )* diff --git a/frame/support/src/traits/members.rs b/frame/support/src/traits/members.rs index a59869c2fc9a3..06a4c759c46db 100644 --- a/frame/support/src/traits/members.rs +++ b/frame/support/src/traits/members.rs @@ -70,7 +70,7 @@ impl Contains for Tuple { /// to `matches!`. #[macro_export] macro_rules! match_type { - ( pub type $n:ident: impl Contains<$t:ty> = { $phead:pat $( | $ptail:pat )* } ; ) => { + ( pub type $n:ident: impl Contains<$t:ty> = { $phead:pat_param $( | $ptail:pat )* } ; ) => { pub struct $n; impl $crate::traits::Contains<$t> for $n { fn contains(l: &$t) -> bool { diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 77fd4f5620969..762c85f75c363 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-support-test" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" publish = false homepage = "https://substrate.io" @@ -23,7 +23,7 @@ sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../.. sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } -trybuild = "1.0.43" +trybuild = "1.0.52" pretty_assertions = "1.0.0" rustversion = "1.0.0" frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } @@ -36,13 +36,15 @@ std = [ "serde/std", "codec/std", "scale-info/std", - "sp-io/std", "frame-support/std", "frame-system/std", "sp-core/std", "sp-std/std", + "sp-io/std", "sp-runtime/std", "sp-state-machine", + "sp-arithmetic/std", + "sp-version/std", ] try-runtime = ["frame-support/try-runtime"] # WARNING: CI only execute pallet test with this feature, diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index bca833200d444..b8a64f4e7022a 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-support-test-compile-pass" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" publish = false homepage = "https://substrate.dev" diff --git a/frame/support/test/pallet/Cargo.toml b/frame/support/test/pallet/Cargo.toml index a3d101967ae65..c26fdda4e9624 100644 --- a/frame/support/test/pallet/Cargo.toml +++ b/frame/support/test/pallet/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-support-test-pallet" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" publish = false homepage = "https://substrate.io" diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index dd171c5b12ec2..dcf739af614b8 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -166,25 +166,25 @@ pub mod pallet { T::AccountId: From + From + SomeAssociation1, { fn on_initialize(_: BlockNumberFor) -> Weight { - T::AccountId::from(SomeType1); // Test for where clause - T::AccountId::from(SomeType2); // Test for where clause + let _ = T::AccountId::from(SomeType1); // Test for where clause + let _ = T::AccountId::from(SomeType2); // Test for where clause Self::deposit_event(Event::Something(10)); 10 } fn on_finalize(_: BlockNumberFor) { - T::AccountId::from(SomeType1); // Test for where clause - T::AccountId::from(SomeType2); // Test for where clause + let _ = T::AccountId::from(SomeType1); // Test for where clause + let _ = T::AccountId::from(SomeType2); // Test for where clause Self::deposit_event(Event::Something(20)); } fn on_runtime_upgrade() -> Weight { - T::AccountId::from(SomeType1); // Test for where clause - T::AccountId::from(SomeType2); // Test for where clause + let _ = T::AccountId::from(SomeType1); // Test for where clause + let _ = T::AccountId::from(SomeType2); // Test for where clause Self::deposit_event(Event::Something(30)); 30 } fn integrity_test() { - T::AccountId::from(SomeType1); // Test for where clause - T::AccountId::from(SomeType2); // Test for where clause + let _ = T::AccountId::from(SomeType1); // Test for where clause + let _ = T::AccountId::from(SomeType2); // Test for where clause } } @@ -200,8 +200,8 @@ pub mod pallet { #[pallet::compact] _foo: u32, _bar: u32, ) -> DispatchResultWithPostInfo { - T::AccountId::from(SomeType1); // Test for where clause - T::AccountId::from(SomeType3); // Test for where clause + let _ = T::AccountId::from(SomeType1); // Test for where clause + let _ = T::AccountId::from(SomeType3); // Test for where clause let _ = origin; Self::deposit_event(Event::Something(3)); Ok(().into()) @@ -268,7 +268,7 @@ pub mod pallet { where T::AccountId: From + From + SomeAssociation1, { - T::AccountId::from(SomeType7); // Test where clause works + let _ = T::AccountId::from(SomeType7); // Test where clause works 4u16 } @@ -352,8 +352,8 @@ pub mod pallet { T::AccountId: From + SomeAssociation1 + From, { fn build(&self) { - T::AccountId::from(SomeType1); // Test for where clause - T::AccountId::from(SomeType4); // Test for where clause + let _ = T::AccountId::from(SomeType1); // Test for where clause + let _ = T::AccountId::from(SomeType4); // Test for where clause } } @@ -370,8 +370,8 @@ pub mod pallet { { type Call = Call; fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { - T::AccountId::from(SomeType1); // Test for where clause - T::AccountId::from(SomeType5); // Test for where clause + let _ = T::AccountId::from(SomeType1); // Test for where clause + let _ = T::AccountId::from(SomeType5); // Test for where clause if matches!(call, Call::foo_transactional { .. }) { return Ok(ValidTransaction::default()) } @@ -390,8 +390,8 @@ pub mod pallet { const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; fn create_inherent(_data: &InherentData) -> Option { - T::AccountId::from(SomeType1); // Test for where clause - T::AccountId::from(SomeType6); // Test for where clause + let _ = T::AccountId::from(SomeType1); // Test for where clause + let _ = T::AccountId::from(SomeType6); // Test for where clause Some(Call::foo_no_post_info {}) } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index dc69bd2d5e85f..c5d2144e28dd0 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-system" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 6aa2251f287d9..7e7c2f6e69f20 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-system-benchmarking" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/system/rpc/runtime-api/Cargo.toml b/frame/system/rpc/runtime-api/Cargo.toml index b5e569e1298ca..67e627f7dcf98 100644 --- a/frame/system/rpc/runtime-api/Cargo.toml +++ b/frame/system/rpc/runtime-api/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index cd636ec6c23b5..2f07b2a0975a5 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-timestamp" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index a3f268169b784..805f1663d1ae3 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-tips" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index bea263cbef6f1..1d3066e39fbda 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-transaction-payment" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 1a2c68227c11f..8ce2e4991568c 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 7bdca2f658293..315f140fc4f23 100644 --- a/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index bcd3fd145f575..7167ae7424571 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-transaction-storage" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Unlicense" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index bcbe41985c655..d375e22df949b 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-treasury" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index 611a844278269..c947717953192 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-try-runtime" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index f240bb98afab7..4b6d0485567c2 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-uniques" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 0a0a9eafd845b..c55b20df27855 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-utility" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 3179607b3f6d7..035124f7d0de3 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-vesting" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index c57c3730fc7b6..65da54b87753d 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-api" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index d9dd0bf9020c7..7b0b55c8c3b53 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-api-proc-macro" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index 510a2eeaa530a..34907d6197285 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -786,7 +786,7 @@ fn generate_runtime_info_impl(trait_: &ItemTrait, version: u64) -> TokenStream { quote!( #[cfg(any(feature = "std", test))] impl < #( #impl_generics, )* > #crate_::RuntimeApiInfo - for #trait_name < #( #ty_generics, )* > + for dyn #trait_name < #( #ty_generics, )* > { #id #version diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index 82954d193e605..cb74f95d21b09 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -644,8 +644,6 @@ pub const fn serialize_runtime_api_info(id: [u8; 8], version: u32) -> [u8; RUNTI /// Deserialize the runtime API info serialized by [`serialize_runtime_api_info`]. pub fn deserialize_runtime_api_info(bytes: [u8; RUNTIME_API_INFO_SIZE]) -> ([u8; 8], u32) { - use sp_std::convert::TryInto; - let id: [u8; 8] = bytes[0..8] .try_into() .expect("the source slice size is equal to the dest array length; qed"); diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index faee5ebdc77db..8c274b386470a 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-api-test" version = "2.0.1" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" publish = false homepage = "https://substrate.io" @@ -21,7 +21,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } codec = { package = "parity-scale-codec", version = "2.0.0" } sp-state-machine = { version = "0.10.0-dev", path = "../../state-machine" } -trybuild = "1.0.43" +trybuild = "1.0.52" rustversion = "1.0.0" [dev-dependencies] diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index 88411d86392af..e715d2ed3d31c 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-application-crypto" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" description = "Provides facilities for generating application specific crypto wrapper types." license = "Apache-2.0" homepage = "https://substrate.io" diff --git a/primitives/application-crypto/test/Cargo.toml b/primitives/application-crypto/test/Cargo.toml index d10f011c4c603..f59f5d9a249cb 100644 --- a/primitives/application-crypto/test/Cargo.toml +++ b/primitives/application-crypto/test/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-application-crypto-test" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" description = "Integration tests for application-crypto" license = "Apache-2.0" publish = false diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 92b16b895e3b5..e6fa1759774ed 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-arithmetic" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index 5f2d5801ff995..d6b2088523773 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-arithmetic-fuzzer" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index d4c75dda352ca..22f3884b55021 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-authority-discovery" version = "4.0.0-dev" authors = ["Parity Technologies "] description = "Authority discovery primitives" -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index cee82ca77c375..a31a349611163 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-authorship" version = "4.0.0-dev" authors = ["Parity Technologies "] description = "Authorship primitives" -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 633ac0e8fbcd1..83472f54c5135 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -2,7 +2,7 @@ name = "beefy-primitives" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index 8499bdf8e1c70..6c6579c353298 100644 --- a/primitives/block-builder/Cargo.toml +++ b/primitives/block-builder/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-block-builder" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 93daef5fa1a27..7af7807954ef1 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-blockchain" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index ca73cf206de02..361095c6218ff 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-consensus-aura" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Primitives for Aura consensus" -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 1690b7c9a02d3..d942f72909453 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-consensus-babe" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Primitives for BABE consensus" -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 9a5488abba653..735b1e8eb095d 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-consensus" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index 406ed3dea46a5..07863850a8f87 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-consensus-pow" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Primitives for Aura consensus" -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index 014ee9b93e6e8..ad83835e02706 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-consensus-slots" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Primitives for slots-based consensus" -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index c103e68eb66b2..8a99dc9432a0b 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-consensus-vrf" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Primitives for VRF based consensus" -edition = "2018" +edition = "2021" license = "Apache-2.0" repository = "https://github.com/paritytech/substrate/" homepage = "https://substrate.io" diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 148f2343ee2b7..63ca358e68101 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-core" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index 43c670b59b0a7..eeee40405344c 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-core-hashing" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.dev" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index 6d83b50b8a296..452165b31cb90 100644 --- a/primitives/core/hashing/proc-macro/Cargo.toml +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-core-hashing-proc-macro" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.dev" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/database/Cargo.toml b/primitives/database/Cargo.toml index c3d2d8ce99df9..94e16f3cfb3d5 100644 --- a/primitives/database/Cargo.toml +++ b/primitives/database/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-database" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml index 954d0f89663fe..d1f1f81a9f143 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-debug-derive" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/externalities/Cargo.toml b/primitives/externalities/Cargo.toml index 5a1b6b5e73734..96199c5b4d222 100644 --- a/primitives/externalities/Cargo.toml +++ b/primitives/externalities/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-externalities" version = "0.10.0-dev" license = "Apache-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate externalities abstraction" diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index 5cf7ac6711a70..4b9fde85147ea 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-finality-grandpa" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index d99a4c1882222..b762a1596bf82 100644 --- a/primitives/finality-grandpa/src/lib.rs +++ b/primitives/finality-grandpa/src/lib.rs @@ -389,7 +389,6 @@ where { use sp_application_crypto::AppKey; use sp_core::crypto::Public; - use sp_std::convert::TryInto; let encoded = localized_payload(round, set_id, &message); let signature = SyncCryptoStore::sign_with( diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 04b662fb059f0..d52140d94ed31 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-inherents" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index df9a496a914be..2d7c50bdc25e4 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-io" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 464abdb6cb1aa..3b5d916b47b64 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-keyring" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 3a0532f1db313..e16ff4676c3b1 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-keystore" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/maybe-compressed-blob/Cargo.toml b/primitives/maybe-compressed-blob/Cargo.toml index cd124580ef19c..95ba9b3324127 100644 --- a/primitives/maybe-compressed-blob/Cargo.toml +++ b/primitives/maybe-compressed-blob/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-maybe-compressed-blob" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 5ffaf76379bda..95f303a382526 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-npos-elections" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 1d13d33a35e80..f9fce9d8744da 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index 27d5d0bb1231c..f50150bdbd58b 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-npos-elections-solution-type" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" @@ -26,4 +26,4 @@ scale-info = "1.0" sp-arithmetic = { path = "../../arithmetic", version = "4.0.0-dev" } # used by generate_solution_type: sp-npos-elections = { path = "..", version = "4.0.0-dev" } -trybuild = "1.0.43" +trybuild = "1.0.52" diff --git a/primitives/offchain/Cargo.toml b/primitives/offchain/Cargo.toml index c1e891acba955..c4da2b4f88921 100644 --- a/primitives/offchain/Cargo.toml +++ b/primitives/offchain/Cargo.toml @@ -4,7 +4,7 @@ name = "sp-offchain" version = "4.0.0-dev" license = "Apache-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml index 890cc277bd849..0845e175c2377 100644 --- a/primitives/panic-handler/Cargo.toml +++ b/primitives/panic-handler/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-panic-handler" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index af883e2199415..15f7aa2b3b896 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-rpc" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index fc8923cdb80a3..c640f02824f24 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-runtime-interface" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" @@ -31,7 +31,7 @@ sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } sp-core = { version = "4.0.0-dev", path = "../core" } sp-io = { version = "4.0.0-dev", path = "../io" } rustversion = "1.0.0" -trybuild = "1.0.43" +trybuild = "1.0.52" [features] default = [ "std" ] diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index dd08d03313396..958a95ceb3fcf 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-runtime-interface-proc-macro" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index a3c82de473abd..60ece9d78795f 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-runtime-interface-test-wasm-deprecated" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" build = "build.rs" license = "Apache-2.0" homepage = "https://substrate.io" diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index 557b5b9bee89f..d8dcc8a470530 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-runtime-interface-test-wasm" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" build = "build.rs" license = "Apache-2.0" homepage = "https://substrate.io" diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 26884d5cb729f..4c88438f08c66 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-runtime-interface-test" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" publish = false homepage = "https://substrate.io" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 475d2b769de39..9d2957e7aed1a 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-runtime" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index 80cd195c6f406..b1ee431042e7a 100755 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-sandbox" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/serializer/Cargo.toml b/primitives/serializer/Cargo.toml index cc438e9a1c148..5b2d499279a47 100644 --- a/primitives/serializer/Cargo.toml +++ b/primitives/serializer/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-serializer" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index 1e9ed6ec9b651..01b299091ed1c 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-session" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 8ea24760e2b8b..3be8f4aba1428 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-staking" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index bbe9728befd80..343151a50a927 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-state-machine" version = "0.10.0-dev" authors = ["Parity Technologies "] description = "Substrate State Machine" -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/std/Cargo.toml b/primitives/std/Cargo.toml index e4cacf60cc36f..34f27ae7256d1 100644 --- a/primitives/std/Cargo.toml +++ b/primitives/std/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-std" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index c7d23fcf70103..2413c45a7312e 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-storage" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" description = "Storage related primitives" license = "Apache-2.0" homepage = "https://substrate.io" diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index f91d15d2d40b3..f472ec88ea189 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-tasks" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 75ce8b752d3ca..4d184c7d02e7f 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-test-primitives" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 32f4c53083435..552a3cb5e8d63 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-timestamp" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index 46930a674f2c9..f4bfb1f15dad3 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-tracing" version = "4.0.0-dev" license = "Apache-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Instrumentation primitives and macros for Substrate." diff --git a/primitives/transaction-pool/Cargo.toml b/primitives/transaction-pool/Cargo.toml index f74fcb44fee2d..e4a407547971a 100644 --- a/primitives/transaction-pool/Cargo.toml +++ b/primitives/transaction-pool/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-transaction-pool" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index 536e2f201a104..c967497f4ff96 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-transaction-storage-proof" version = "4.0.0-dev" authors = ["Parity Technologies "] description = "Transaction storage proof primitives" -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 66d8a1e47276e..6190df210403c 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] description = "Patricia trie stuff using a parity-scale-codec node format" repository = "https://github.com/paritytech/substrate/" license = "Apache-2.0" -edition = "2018" +edition = "2021" homepage = "https://substrate.io" documentation = "https://docs.rs/sp-trie" readme = "README.md" diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 2a2c2698c74c3..af44aed6c5b21 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-version" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index 587ca06bdc179..bf6e0bdec7a6e 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-version-proc-macro" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 73b47e563a5b5..339c4cf8bc8bd 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-wasm-interface" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index a9ffefa05df7f..6cb91bb589c6d 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -2,7 +2,7 @@ name = "substrate-test-utils" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" @@ -18,4 +18,4 @@ tokio = { version = "1.10", features = ["macros", "time"] } [dev-dependencies] sc-service = { version = "0.10.0-dev", path = "../client/service" } -trybuild = { version = "1.0.43", features = [ "diff" ] } +trybuild = { version = "1.0.52", features = [ "diff" ] } diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 204b6ac435e07..a8b2e8f57ac52 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -2,7 +2,7 @@ name = "substrate-test-client" version = "2.0.1" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index 2a1f52346840f..f195c0e419eac 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -2,7 +2,7 @@ name = "substrate-test-utils-derive" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index eb6ca51ce2e5a..f02e079046336 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -2,7 +2,7 @@ name = "substrate-test-runtime" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" build = "build.rs" license = "Apache-2.0" homepage = "https://substrate.io" diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index 75ebb8f23326c..fbc6aefdb850c 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -2,7 +2,7 @@ name = "substrate-test-runtime-client" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index 5a2983b058b04..402caa93d10d8 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -2,7 +2,7 @@ name = "substrate-test-runtime-transaction-pool" version = "2.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/test-utils/test-crate/Cargo.toml b/test-utils/test-crate/Cargo.toml index 9c9672fe8f5d8..071a82f3c769f 100644 --- a/test-utils/test-crate/Cargo.toml +++ b/test-utils/test-crate/Cargo.toml @@ -2,7 +2,7 @@ name = "substrate-test-utils-test-crate" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/test-utils/test-runner/Cargo.toml b/test-utils/test-runner/Cargo.toml index b5b115771b539..9299076bb1f68 100644 --- a/test-utils/test-runner/Cargo.toml +++ b/test-utils/test-runner/Cargo.toml @@ -2,7 +2,7 @@ name = "test-runner" version = "0.9.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" publish = false [dependencies] diff --git a/utils/build-script-utils/Cargo.toml b/utils/build-script-utils/Cargo.toml index 786e6f9002914..93611c7b5b017 100644 --- a/utils/build-script-utils/Cargo.toml +++ b/utils/build-script-utils/Cargo.toml @@ -2,7 +2,7 @@ name = "substrate-build-script-utils" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/utils/fork-tree/Cargo.toml b/utils/fork-tree/Cargo.toml index 81fa1747a84d7..cdfce5592f2fa 100644 --- a/utils/fork-tree/Cargo.toml +++ b/utils/fork-tree/Cargo.toml @@ -2,7 +2,7 @@ name = "fork-tree" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index ccca30849f919..605a14e3adff7 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -2,7 +2,7 @@ name = "frame-benchmarking-cli" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index fcdbb215f91b2..9d14819337419 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -2,7 +2,7 @@ name = "substrate-frame-cli" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 1bb53207f7d4c..03382878710b7 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -2,7 +2,7 @@ name = "generate-bags" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml index 68d3cad16de47..5029e049361c9 100644 --- a/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -2,7 +2,7 @@ name = "node-runtime-generate-bags" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/utils/frame/generate-bags/src/lib.rs b/utils/frame/generate-bags/src/lib.rs index af9df4435bcab..540412ef04c4c 100644 --- a/utils/frame/generate-bags/src/lib.rs +++ b/utils/frame/generate-bags/src/lib.rs @@ -71,7 +71,6 @@ fn existential_weight( minimum_balance: u128, ) -> VoteWeight { use frame_support::traits::CurrencyToVote; - use std::convert::TryInto; T::CurrencyToVote::to_vote( minimum_balance diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 2b35402f8f63f..3e7c229ec4d65 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -2,7 +2,7 @@ name = "remote-externalities" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 2010d1e02f73f..0d21bdd6c0181 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -5,7 +5,7 @@ authors = [ "Parity Technologies ", "Andrew Dirksen ", ] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 85868836f0456..31a46b3902106 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -2,7 +2,7 @@ name = "substrate-frame-rpc-system" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index e922af971044c..154c522c1dfd0 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -2,7 +2,7 @@ name = "try-runtime-cli" version = "0.10.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 4d218e233bcbc..78bd68ac9e3a5 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -4,7 +4,7 @@ name = "substrate-prometheus-endpoint" version = "0.9.0" license = "Apache-2.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index 92b1af753ef60..d8802c432f55d 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -3,7 +3,7 @@ name = "substrate-wasm-builder" version = "5.0.0-dev" authors = ["Parity Technologies "] description = "Utility for building WASM binaries" -edition = "2018" +edition = "2021" readme = "README.md" repository = "https://github.com/paritytech/substrate/" license = "Apache-2.0" From 3524f6e692d568fae60c26ec8156f3fb585532ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Nov 2021 19:58:49 +0000 Subject: [PATCH 0184/1472] Bump strum from 0.21.0 to 0.22.0 (#10045) Bumps [strum](https://github.com/Peternator7/strum) from 0.21.0 to 0.22.0. - [Release notes](https://github.com/Peternator7/strum/releases) - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/commits) --- updated-dependencies: - dependency-name: strum 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 | 29 +++++++------------ client/beefy/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 2 +- primitives/keyring/Cargo.toml | 2 +- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a50fe3565715..ea54adf99e458 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -507,7 +507,7 @@ dependencies = [ "sp-core", "sp-keystore", "sp-runtime", - "strum 0.21.0", + "strum", "substrate-prometheus-endpoint", "thiserror", "wasm-timer", @@ -5450,7 +5450,7 @@ dependencies = [ "sp-std", "sp-tracing", "static_assertions", - "strum 0.21.0", + "strum", "strum_macros 0.21.1", ] @@ -9502,7 +9502,7 @@ dependencies = [ "lazy_static", "sp-core", "sp-runtime", - "strum 0.20.0", + "strum", ] [[package]] @@ -9998,27 +9998,18 @@ dependencies = [ [[package]] name = "strum" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" +checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" dependencies = [ - "strum_macros 0.20.1", -] - -[[package]] -name = "strum" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" -dependencies = [ - "strum_macros 0.21.1", + "strum_macros 0.22.0", ] [[package]] name = "strum_macros" -version = "0.20.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" dependencies = [ "heck", "proc-macro2", @@ -10028,9 +10019,9 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" +checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb" dependencies = [ "heck", "proc-macro2", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 37dc4491e21d4..60f9fde030800 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -35,4 +35,4 @@ beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } [dev-dependencies] sc-network-test = { version = "0.8.0", path = "../network/test" } -strum = { version = "0.21", features = ["derive"] } +strum = { version = "0.22", features = ["derive"] } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 8a0f80da10829..63111f89e5d39 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -37,7 +37,7 @@ rand = { version = "0.7.3", default-features = false, optional = true, features "alloc", "small_rng", ] } -strum = { optional = true, version = "0.21.0" } +strum = { optional = true, version = "0.22.0" } strum_macros = { optional = true, version = "0.21.1" } [dev-dependencies] diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 3b5d916b47b64..249e7d766e39e 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -18,4 +18,4 @@ targets = ["x86_64-unknown-linux-gnu"] sp-core = { version = "4.0.0-dev", path = "../core" } sp-runtime = { version = "4.0.0-dev", path = "../runtime" } lazy_static = "1.4.0" -strum = { version = "0.20.0", features = ["derive"] } +strum = { version = "0.22.0", features = ["derive"] } From 5ba810c93203487ac58cffc6e0d34cdda18e362c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Nov 2021 11:11:28 +0000 Subject: [PATCH 0185/1472] Bump wasmi from 0.9.0 to 0.9.1 (#10116) Bumps [wasmi](https://github.com/paritytech/wasmi) from 0.9.0 to 0.9.1. - [Release notes](https://github.com/paritytech/wasmi/releases) - [Commits](https://github.com/paritytech/wasmi/compare/v0.9.0...v0.9.1) --- updated-dependencies: - dependency-name: wasmi 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/executor/Cargo.toml | 2 +- client/executor/common/Cargo.toml | 2 +- client/executor/wasmi/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/sandbox/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) mode change 100755 => 100644 primitives/sandbox/Cargo.toml diff --git a/Cargo.lock b/Cargo.lock index ea54adf99e458..2257fa0a5b005 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11498,9 +11498,9 @@ dependencies = [ [[package]] name = "wasmi" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ee05bba3d1d994652079893941a2ef9324d2b58a63c31b40678fb7eddd7a5a" +checksum = "ca00c5147c319a8ec91ec1a0edbec31e566ce2c9cc93b3f9bb86a9efd0eb795d" dependencies = [ "downcast-rs", "errno", diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 028854992a094..ef66d8072b537 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -21,7 +21,7 @@ sp-tasks = { version = "4.0.0-dev", path = "../../primitives/tasks" } sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-panic-handler = { version = "3.0.0", path = "../../primitives/panic-handler" } -wasmi = "0.9.0" +wasmi = "0.9.1" lazy_static = "1.4.0" sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-wasm-interface = { version = "4.0.0-dev", path = "../../primitives/wasm-interface" } diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index fc7d5a1528470..7ac747bf967bd 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] derive_more = "0.99.2" pwasm-utils = "0.18.0" codec = { package = "parity-scale-codec", version = "2.0.0" } -wasmi = "0.9.0" +wasmi = "0.9.1" sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } sc-allocator = { version = "4.0.0-dev", path = "../../allocator" } sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-interface" } diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 6311b0234866f..255a470b374da 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.8" -wasmi = "0.9.0" +wasmi = "0.9.1" codec = { package = "parity-scale-codec", version = "2.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sc-allocator = { version = "4.0.0-dev", path = "../../allocator" } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 63ca358e68101..8262393e653fe 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -27,7 +27,7 @@ primitive-types = { version = "0.10.1", default-features = false, features = [ "scale-info" ] } impl-serde = { version = "0.3.0", optional = true } -wasmi = { version = "0.9.0", optional = true } +wasmi = { version = "0.9.1", optional = true } hash-db = { version = "0.15.2", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } base58 = { version = "0.2.0", optional = true } diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml old mode 100755 new mode 100644 index b1ee431042e7a..8e7acff4ff7e8 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [target.'cfg(target_arch = "wasm32")'.dependencies] -wasmi = { version = "0.9.0", default-features = false, features = ["core"] } +wasmi = { version = "0.9.1", default-features = false, features = ["core"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] wasmi = "0.9.0" diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 339c4cf8bc8bd..c378b185e392c 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -wasmi = { version = "0.9.0", optional = true } +wasmi = { version = "0.9.1", optional = true } impl-trait-for-tuples = "0.2.1" sp-std = { version = "4.0.0-dev", path = "../std", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } From 6873fc69e2140f554b75242b7e66a5d6a846e772 Mon Sep 17 00:00:00 2001 From: Florian Franzen Date: Fri, 5 Nov 2021 12:26:49 +0100 Subject: [PATCH 0186/1472] Remove old Cargo.toml (#10188) --- client/finality-grandpa-warp-sync/Cargo.toml | 35 -------------------- 1 file changed, 35 deletions(-) delete mode 100644 client/finality-grandpa-warp-sync/Cargo.toml diff --git a/client/finality-grandpa-warp-sync/Cargo.toml b/client/finality-grandpa-warp-sync/Cargo.toml deleted file mode 100644 index 6280add275628..0000000000000 --- a/client/finality-grandpa-warp-sync/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -description = "A request-response protocol for handling grandpa warp sync requests" -name = "sc-finality-grandpa-warp-sync" -version = "0.10.0-dev" -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0" } -derive_more = "0.99.11" -futures = "0.3.8" -log = "0.4.11" -prost = "0.8" -sc-client-api = { version = "4.0.0-dev", path = "../api" } -sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } -sc-network = { version = "0.10.0-dev", path = "../network" } -sc-service = { version = "0.10.0-dev", path = "../service" } -sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } - -[dev-dependencies] -finality-grandpa = { version = "0.14.4" } -rand = "0.8" -sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } -sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } -sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } -substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } From 8439a0bba4aeb69669510061e6aeeb106da9d651 Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 5 Nov 2021 21:52:34 +0900 Subject: [PATCH 0187/1472] Remove unnecessary allocations when crossing WASM FFI boundary (#10191) --- primitives/runtime-interface/src/impls.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/primitives/runtime-interface/src/impls.rs b/primitives/runtime-interface/src/impls.rs index 40f8e90479f95..0b9cdc26f4650 100644 --- a/primitives/runtime-interface/src/impls.rs +++ b/primitives/runtime-interface/src/impls.rs @@ -318,9 +318,8 @@ macro_rules! impl_traits_for_arrays { type SelfInstance = [u8; $n]; fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<[u8; $n]> { - let data = context.read_memory(Pointer::new(arg), $n)?; let mut res = [0u8; $n]; - res.copy_from_slice(&data); + context.read_memory_into(Pointer::new(arg), &mut res)?; Ok(res) } } @@ -514,10 +513,8 @@ macro_rules! for_u128_i128 { type SelfInstance = $type; fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<$type> { - let data = - context.read_memory(Pointer::new(arg), mem::size_of::<$type>() as u32)?; let mut res = [0u8; mem::size_of::<$type>()]; - res.copy_from_slice(&data); + context.read_memory_into(Pointer::new(arg), &mut res)?; Ok(<$type>::from_le_bytes(res)) } } From 7b8f8efde025c6ac8daed492d4d96dea3c563334 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Nov 2021 15:51:54 +0100 Subject: [PATCH 0188/1472] Bump syn from 1.0.80 to 1.0.81 (#10182) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.80 to 1.0.81. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.80...1.0.81) --- 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 | 8 ++++---- client/chain-spec/derive/Cargo.toml | 2 +- client/tracing/proc-macro/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/tools/Cargo.toml | 2 +- frame/support/procedural/tools/derive/Cargo.toml | 2 +- primitives/api/proc-macro/Cargo.toml | 2 +- primitives/core/hashing/proc-macro/Cargo.toml | 2 +- primitives/debug-derive/Cargo.toml | 2 +- primitives/npos-elections/solution-type/Cargo.toml | 2 +- primitives/runtime-interface/proc-macro/Cargo.toml | 2 +- primitives/version/proc-macro/Cargo.toml | 2 +- test-utils/derive/Cargo.toml | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2257fa0a5b005..8d168230b528e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6780,9 +6780,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid", ] @@ -10286,9 +10286,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ "proc-macro2", "quote", diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index 386137d0667ad..25339eea14f12 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -18,6 +18,6 @@ proc-macro = true proc-macro-crate = "1.0.0" proc-macro2 = "1.0.29" quote = "1.0.10" -syn = "1.0.80" +syn = "1.0.81" [dev-dependencies] diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index 9c8579ee66a45..c51c8764e6772 100644 --- a/client/tracing/proc-macro/Cargo.toml +++ b/client/tracing/proc-macro/Cargo.toml @@ -18,4 +18,4 @@ proc-macro = true proc-macro-crate = "1.0.0" proc-macro2 = "1.0.29" quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.80", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "1.0.81", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index 15ff3a8727305..1250bbcd39056 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.80", features = ["full", "visit"] } +syn = { version = "1.0.81", features = ["full", "visit"] } quote = "1.0.10" proc-macro2 = "1.0.29" proc-macro-crate = "1.0.0" diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 17128388874a8..b47cf7f97956a 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -19,7 +19,7 @@ frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } proc-macro2 = "1.0.29" quote = "1.0.10" Inflector = "0.11.4" -syn = { version = "1.0.80", features = ["full"] } +syn = { version = "1.0.81", features = ["full"] } [features] default = ["std"] diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index 1207d06e6d591..7b957be184014 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -15,5 +15,5 @@ targets = ["x86_64-unknown-linux-gnu"] frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" } proc-macro2 = "1.0.29" quote = "1.0.10" -syn = { version = "1.0.80", features = ["full", "visit", "extra-traits"] } +syn = { version = "1.0.81", features = ["full", "visit", "extra-traits"] } proc-macro-crate = "1.0.0" diff --git a/frame/support/procedural/tools/derive/Cargo.toml b/frame/support/procedural/tools/derive/Cargo.toml index f0c27b5397d5d..8327134b3fb40 100644 --- a/frame/support/procedural/tools/derive/Cargo.toml +++ b/frame/support/procedural/tools/derive/Cargo.toml @@ -17,4 +17,4 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.29" quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.80", features = ["proc-macro" ,"full", "extra-traits", "parsing"] } +syn = { version = "1.0.81", features = ["proc-macro" ,"full", "extra-traits", "parsing"] } diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index 7b0b55c8c3b53..a5df7aef322ab 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = { version = "1.0.80", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "1.0.81", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.29" blake2-rfc = { version = "0.2.18", default-features = false } proc-macro-crate = "1.0.0" diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index 452165b31cb90..89b225e6aaa5f 100644 --- a/primitives/core/hashing/proc-macro/Cargo.toml +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.77", features = ["full", "parsing"] } +syn = { version = "1.0.81", features = ["full", "parsing"] } quote = "1.0.6" proc-macro2 = "1.0.29" sp-core-hashing = { version = "4.0.0-dev", path = "../", default-features = false } diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml index d1f1f81a9f143..a2f77b7591fe1 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = "1.0.80" +syn = "1.0.81" proc-macro2 = "1.0" [features] diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index f50150bdbd58b..5d8d3890577a7 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.80", features = ["full", "visit"] } +syn = { version = "1.0.81", features = ["full", "visit"] } quote = "1.0" proc-macro2 = "1.0.29" proc-macro-crate = "1.0.0" diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 958a95ceb3fcf..cc5daa695bb0f 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.80", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "1.0.81", features = ["full", "visit", "fold", "extra-traits"] } quote = "1.0.10" proc-macro2 = "1.0.29" Inflector = "0.11.4" diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index bf6e0bdec7a6e..79fb9b18a2381 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = { version = "1.0.80", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "1.0.81", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.29" codec = { package = "parity-scale-codec", version = "2.0.0", features = [ "derive" ] } diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index f195c0e419eac..967fc1e87a36e 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -10,7 +10,7 @@ description = "Substrate test utilities macros" [dependencies] quote = "1.0.10" -syn = { version = "1.0.80", features = ["full"] } +syn = { version = "1.0.81", features = ["full"] } proc-macro-crate = "1.0.0" proc-macro2 = "1.0.29" From abca10f32a1844d4d05884c92ea2e08b17c6b8c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 6 Nov 2021 05:48:41 +0000 Subject: [PATCH 0189/1472] Bump strum_macros from 0.21.1 to 0.22.0 (#10200) Bumps [strum_macros](https://github.com/Peternator7/strum) from 0.21.1 to 0.22.0. - [Release notes](https://github.com/Peternator7/strum/releases) - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/commits) --- updated-dependencies: - dependency-name: strum_macros 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 | 16 ++-------------- frame/election-provider-multi-phase/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d168230b528e..eeb1012b1d1d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5451,7 +5451,7 @@ dependencies = [ "sp-tracing", "static_assertions", "strum", - "strum_macros 0.21.1", + "strum_macros", ] [[package]] @@ -10002,19 +10002,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" dependencies = [ - "strum_macros 0.22.0", -] - -[[package]] -name = "strum_macros" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", + "strum_macros", ] [[package]] diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 63111f89e5d39..b37054a7bbddf 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -38,7 +38,7 @@ rand = { version = "0.7.3", default-features = false, optional = true, features "small_rng", ] } strum = { optional = true, version = "0.22.0" } -strum_macros = { optional = true, version = "0.21.1" } +strum_macros = { optional = true, version = "0.22.0" } [dev-dependencies] parking_lot = "0.11.0" From 0397c5bd745574c587ea853ae9472e8dd0a2d9fe Mon Sep 17 00:00:00 2001 From: Alan Sapede Date: Sat, 6 Nov 2021 12:49:53 -0400 Subject: [PATCH 0190/1472] Adds block production time in logs (#10205) --- client/basic-authorship/src/basic_authorship.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 0055254b67091..573601a9102c5 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -462,8 +462,9 @@ where }); info!( - "🎁 Prepared block for proposing at {} [hash: {:?}; parent_hash: {}; extrinsics ({}): [{}]]", + "🎁 Prepared block for proposing at {} ({} ms) [hash: {:?}; parent_hash: {}; extrinsics ({}): [{}]]", block.header().number(), + block_timer.elapsed().as_millis(), ::Hash::from(block.header().hash()), block.header().parent_hash(), block.extrinsics().len(), From 702fd839917f7b197770917ae5a64df0fc9593eb Mon Sep 17 00:00:00 2001 From: cheme Date: Sun, 7 Nov 2021 14:13:02 +0100 Subject: [PATCH 0191/1472] Fast sync child trie support. (#9239) * state machine proofs. * initial implementation * Remove todo. * Extend test and fix import. * fix no proof, with proof ko. * fix start at logic. * Restore response size. * Rework comments. * Add explicit ref * Use compact proof. * ref change * elaborato on empty change set condition. * KeyValueState renaming. * Do not add two time child trie with same root to sync reply. * rust format * Fix merge. * fix warnings and fmt * fmt * update protocol id to V2 --- client/api/src/backend.rs | 2 +- client/api/src/lib.rs | 2 +- client/api/src/proof_provider.rs | 37 +- client/consensus/common/src/block_import.rs | 2 +- client/network/src/protocol/sync/state.rs | 158 +++++-- client/network/src/schema/api.v1.proto | 20 +- client/network/src/state_request_handler.rs | 49 +- client/network/test/src/lib.rs | 7 + client/network/test/src/sync.rs | 43 +- client/service/src/client/client.rs | 216 +++++++-- primitives/state-machine/src/lib.rs | 448 ++++++++++++++++++- primitives/state-machine/src/trie_backend.rs | 6 +- test-utils/runtime/client/src/lib.rs | 5 + 13 files changed, 855 insertions(+), 140 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 8b5bd50ffa614..9dfe82a57ab3b 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -42,7 +42,7 @@ use std::{ sync::Arc, }; -pub use sp_state_machine::Backend as StateBackend; +pub use sp_state_machine::{Backend as StateBackend, KeyValueStates}; use std::marker::PhantomData; /// Extracts the state backend type for the given backend. diff --git a/client/api/src/lib.rs b/client/api/src/lib.rs index 16935b1e846cf..f1c78f6603eb8 100644 --- a/client/api/src/lib.rs +++ b/client/api/src/lib.rs @@ -39,7 +39,7 @@ pub use proof_provider::*; pub use sp_blockchain as blockchain; pub use sp_blockchain::HeaderBackend; -pub use sp_state_machine::{ExecutionStrategy, StorageProof}; +pub use sp_state_machine::{CompactProof, ExecutionStrategy, StorageProof}; pub use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey}; /// Usage Information Provider interface diff --git a/client/api/src/proof_provider.rs b/client/api/src/proof_provider.rs index 79444f0069232..75f9c55e134d2 100644 --- a/client/api/src/proof_provider.rs +++ b/client/api/src/proof_provider.rs @@ -17,8 +17,9 @@ // along with this program. If not, see . //! Proof utilities -use crate::{ChangesProof, StorageProof}; +use crate::{ChangesProof, CompactProof, StorageProof}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_state_machine::{KeyValueStates, KeyValueStorageLevel}; use sp_storage::{ChildInfo, PrefixedStorageKey, StorageKey}; /// Interface for providing block proving utilities. @@ -71,31 +72,43 @@ pub trait ProofProvider { key: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` iterate over all storage values starting at `start_key` exclusively, - /// building proofs until size limit is reached. Returns combined proof and the number of - /// collected keys. + /// Given a `BlockId` iterate over all storage values starting at `start_keys`. + /// Last `start_keys` element contains last accessed key value. + /// With multiple `start_keys`, first `start_keys` element is + /// the current storage key of of the last accessed child trie. + /// at last level the value to start at exclusively. + /// Proofs is build until size limit is reached and always include at + /// least one key following `start_keys`. + /// Returns combined proof and the numbers of collected keys. fn read_proof_collection( &self, id: &BlockId, - start_key: &[u8], + start_keys: &[Vec], size_limit: usize, - ) -> sp_blockchain::Result<(StorageProof, u32)>; + ) -> sp_blockchain::Result<(CompactProof, u32)>; /// Given a `BlockId` iterate over all storage values starting at `start_key`. /// Returns collected keys and values. + /// Returns the collected keys values content of the top trie followed by the + /// collected keys values of child tries. + /// Only child tries with their root part of the collected content or + /// related to `start_key` are attached. + /// For each collected state a boolean indicates if state reach + /// end. fn storage_collection( &self, id: &BlockId, - start_key: &[u8], + start_key: &[Vec], size_limit: usize, - ) -> sp_blockchain::Result, Vec)>>; + ) -> sp_blockchain::Result>; /// Verify read storage proof for a set of keys. - /// Returns collected key-value pairs and a flag indicating if iteration is complete. + /// Returns collected key-value pairs and a the nested state + /// depth of current iteration or 0 if completed. fn verify_range_proof( &self, root: Block::Hash, - proof: StorageProof, - start_key: &[u8], - ) -> sp_blockchain::Result<(Vec<(Vec, Vec)>, bool)>; + proof: CompactProof, + start_keys: &[Vec], + ) -> sp_blockchain::Result<(KeyValueStates, usize)>; } diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index d828e54bc7e3e..5294db2396042 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -133,7 +133,7 @@ pub struct ImportedState { /// Target block hash. pub block: B::Hash, /// State keys and values. - pub state: Vec<(Vec, Vec)>, + pub state: sp_state_machine::KeyValueStates, } impl std::fmt::Debug for ImportedState { diff --git a/client/network/src/protocol/sync/state.rs b/client/network/src/protocol/sync/state.rs index e644ba1013e4d..43aa1c4629f0e 100644 --- a/client/network/src/protocol/sync/state.rs +++ b/client/network/src/protocol/sync/state.rs @@ -23,9 +23,11 @@ use crate::{ }; use codec::{Decode, Encode}; use log::debug; -use sc_client_api::StorageProof; +use sc_client_api::CompactProof; +use smallvec::SmallVec; +use sp_core::storage::well_known_keys; use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; /// State sync support. @@ -35,8 +37,8 @@ pub struct StateSync { target_block: B::Hash, target_header: B::Header, target_root: B::Hash, - last_key: Vec, - state: Vec<(Vec, Vec)>, + last_key: SmallVec<[Vec; 2]>, + state: HashMap, (Vec<(Vec, Vec)>, Vec>)>, complete: bool, client: Arc>, imported_bytes: u64, @@ -61,8 +63,8 @@ impl StateSync { target_block: target.hash(), target_root: target.state_root().clone(), target_header: target, - last_key: Vec::default(), - state: Vec::default(), + last_key: SmallVec::default(), + state: HashMap::default(), complete: false, imported_bytes: 0, skip_proof, @@ -71,7 +73,7 @@ impl StateSync { /// Validate and import a state reponse. pub fn import(&mut self, response: StateResponse) -> ImportResult { - if response.entries.is_empty() && response.proof.is_empty() && !response.complete { + if response.entries.is_empty() && response.proof.is_empty() { debug!(target: "sync", "Bad state response"); return ImportResult::BadResponse } @@ -82,56 +84,135 @@ impl StateSync { let complete = if !self.skip_proof { debug!(target: "sync", "Importing state from {} trie nodes", response.proof.len()); let proof_size = response.proof.len() as u64; - let proof = match StorageProof::decode(&mut response.proof.as_ref()) { + let proof = match CompactProof::decode(&mut response.proof.as_ref()) { Ok(proof) => proof, Err(e) => { debug!(target: "sync", "Error decoding proof: {:?}", e); return ImportResult::BadResponse }, }; - let (values, complete) = - match self.client.verify_range_proof(self.target_root, proof, &self.last_key) { - Err(e) => { - debug!(target: "sync", "StateResponse failed proof verification: {:?}", e); - return ImportResult::BadResponse - }, - Ok(values) => values, - }; + let (values, completed) = match self.client.verify_range_proof( + self.target_root, + proof, + self.last_key.as_slice(), + ) { + Err(e) => { + debug!( + target: "sync", + "StateResponse failed proof verification: {:?}", + e, + ); + return ImportResult::BadResponse + }, + Ok(values) => values, + }; debug!(target: "sync", "Imported with {} keys", values.len()); - if let Some(last) = values.last().map(|(k, _)| k) { - self.last_key = last.clone(); - } + let complete = completed == 0; + if !complete && !values.update_last_key(completed, &mut self.last_key) { + debug!(target: "sync", "Error updating key cursor, depth: {}", completed); + }; - for (key, value) in values { - self.imported_bytes += key.len() as u64; - self.state.push((key, value)) + for values in values.0 { + let key_values = if values.state_root.is_empty() { + // Read child trie roots. + values + .key_values + .into_iter() + .filter(|key_value| { + if well_known_keys::is_child_storage_key(key_value.0.as_slice()) { + self.state + .entry(key_value.1.clone()) + .or_default() + .1 + .push(key_value.0.clone()); + false + } else { + true + } + }) + .collect() + } else { + values.key_values + }; + let mut entry = self.state.entry(values.state_root).or_default(); + if entry.0.len() > 0 && entry.1.len() > 1 { + // Already imported child_trie with same root. + // Warning this will not work with parallel download. + } else { + if entry.0.is_empty() { + for (key, _value) in key_values.iter() { + self.imported_bytes += key.len() as u64; + } + + entry.0 = key_values; + } else { + for (key, value) in key_values { + self.imported_bytes += key.len() as u64; + entry.0.push((key, value)) + } + } + } } self.imported_bytes += proof_size; complete } else { - debug!( - target: "sync", - "Importing state from {:?} to {:?}", - response.entries.last().map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key)), - response.entries.first().map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key)), - ); - - if let Some(e) = response.entries.last() { - self.last_key = e.key.clone(); + let mut complete = true; + // if the trie is a child trie and one of its parent trie is empty, + // the parent cursor stays valid. + // Empty parent trie content only happens when all the response content + // is part of a single child trie. + if self.last_key.len() == 2 && response.entries[0].entries.len() == 0 { + // Do not remove the parent trie position. + self.last_key.pop(); + } else { + self.last_key.clear(); } - for StateEntry { key, value } in response.entries { - self.imported_bytes += (key.len() + value.len()) as u64; - self.state.push((key, value)) + for state in response.entries { + debug!( + target: "sync", + "Importing state from {:?} to {:?}", + state.entries.last().map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key)), + state.entries.first().map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key)), + ); + + if !state.complete { + if let Some(e) = state.entries.last() { + self.last_key.push(e.key.clone()); + } + complete = false; + } + let is_top = state.state_root.is_empty(); + let entry = self.state.entry(state.state_root).or_default(); + if entry.0.len() > 0 && entry.1.len() > 1 { + // Already imported child trie with same root. + } else { + let mut child_roots = Vec::new(); + for StateEntry { key, value } in state.entries { + // Skip all child key root (will be recalculated on import). + if is_top && well_known_keys::is_child_storage_key(key.as_slice()) { + child_roots.push((value, key)); + } else { + self.imported_bytes += key.len() as u64; + entry.0.push((key, value)) + } + } + for (root, storage_key) in child_roots { + self.state.entry(root).or_default().1.push(storage_key); + } + } } - response.complete + complete }; if complete { self.complete = true; ImportResult::Import( self.target_block, self.target_header.clone(), - ImportedState { block: self.target_block, state: std::mem::take(&mut self.state) }, + ImportedState { + block: self.target_block.clone(), + state: std::mem::take(&mut self.state).into(), + }, ) } else { ImportResult::Continue @@ -142,7 +223,7 @@ impl StateSync { pub fn next_request(&self) -> StateRequest { StateRequest { block: self.target_block.encode(), - start: self.last_key.clone(), + start: self.last_key.clone().into_vec(), no_proof: self.skip_proof, } } @@ -164,7 +245,8 @@ impl StateSync { /// Returns state sync estimated progress. pub fn progress(&self) -> StateDownloadProgress { - let percent_done = (*self.last_key.get(0).unwrap_or(&0u8) as u32) * 100 / 256; + let cursor = *self.last_key.get(0).and_then(|last| last.get(0)).unwrap_or(&0u8); + let percent_done = cursor as u32 * 100 / 256; StateDownloadProgress { percentage: percent_done, size: self.imported_bytes } } } diff --git a/client/network/src/schema/api.v1.proto b/client/network/src/schema/api.v1.proto index c5333c7dcdbf1..b51137d1d51d4 100644 --- a/client/network/src/schema/api.v1.proto +++ b/client/network/src/schema/api.v1.proto @@ -74,22 +74,32 @@ message BlockData { message StateRequest { // Block header hash. bytes block = 1; - // Start from this key. Equivalent to if omitted. - bytes start = 2; // optional + // Start from this key. + // Multiple keys used for nested state start. + repeated bytes start = 2; // optional // if 'true' indicates that response should contain raw key-values, rather than proof. bool no_proof = 3; } message StateResponse { - // A collection of keys-values. Only populated if `no_proof` is `true` - repeated StateEntry entries = 1; + // A collection of keys-values states. Only populated if `no_proof` is `true` + repeated KeyValueStateEntry entries = 1; // If `no_proof` is false in request, this contains proof nodes. bytes proof = 2; +} + +// A key value state. +message KeyValueStateEntry { + // Root of for this level, empty length bytes + // if top level. + bytes state_root = 1; + // A collection of keys-values. + repeated StateEntry entries = 2; // Set to true when there are no more keys to return. bool complete = 3; } -// A key-value pair +// A key-value pair. message StateEntry { bytes key = 1; bytes value = 2; diff --git a/client/network/src/state_request_handler.rs b/client/network/src/state_request_handler.rs index d2e58ce955197..0d710c13af607 100644 --- a/client/network/src/state_request_handler.rs +++ b/client/network/src/state_request_handler.rs @@ -21,7 +21,7 @@ use crate::{ chain::Client, config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, - schema::v1::{StateEntry, StateRequest, StateResponse}, + schema::v1::{KeyValueStateEntry, StateEntry, StateRequest, StateResponse}, PeerId, ReputationChange, }; use codec::{Decode, Encode}; @@ -66,7 +66,7 @@ fn generate_protocol_name(protocol_id: &ProtocolId) -> String { let mut s = String::new(); s.push_str("/"); s.push_str(protocol_id.as_ref()); - s.push_str("/state/1"); + s.push_str("/state/2"); s } @@ -75,7 +75,7 @@ fn generate_protocol_name(protocol_id: &ProtocolId) -> String { struct SeenRequestsKey { peer: PeerId, block: B::Hash, - start: Vec, + start: Vec>, } #[allow(clippy::derive_hash_xor_eq)] @@ -169,10 +169,10 @@ impl StateRequestHandler { trace!( target: LOG_TARGET, - "Handling state request from {}: Block {:?}, Starting at {:?}, no_proof={}", + "Handling state request from {}: Block {:?}, Starting at {:x?}, no_proof={}", peer, request.block, - sp_core::hexdisplay::HexDisplay::from(&request.start), + &request.start, request.no_proof, ); @@ -180,36 +180,45 @@ impl StateRequestHandler { let mut response = StateResponse::default(); if !request.no_proof { - let (proof, count) = self.client.read_proof_collection( + let (proof, _count) = self.client.read_proof_collection( &BlockId::hash(block), - &request.start, + request.start.as_slice(), MAX_RESPONSE_BYTES, )?; response.proof = proof.encode(); - if count == 0 { - response.complete = true; - } } else { let entries = self.client.storage_collection( &BlockId::hash(block), - &request.start, + request.start.as_slice(), MAX_RESPONSE_BYTES, )?; - response.entries = - entries.into_iter().map(|(key, value)| StateEntry { key, value }).collect(); - if response.entries.is_empty() { - response.complete = true; - } + response.entries = entries + .into_iter() + .map(|(state, complete)| KeyValueStateEntry { + state_root: state.state_root, + entries: state + .key_values + .into_iter() + .map(|(key, value)| StateEntry { key, value }) + .collect(), + complete, + }) + .collect(); } trace!( target: LOG_TARGET, - "StateResponse contains {} keys, {}, proof nodes, complete={}, from {:?} to {:?}", + "StateResponse contains {} keys, {}, proof nodes, from {:?} to {:?}", response.entries.len(), response.proof.len(), - response.complete, - response.entries.first().map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key)), - response.entries.last().map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key)), + response.entries.get(0).and_then(|top| top + .entries + .first() + .map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key))), + response.entries.get(0).and_then(|top| top + .entries + .last() + .map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key))), ); if let Some(value) = self.seen_requests.get_mut(&key) { // If this is the first time we have processed this request, we need to change diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index fb0012aaf5baf..084b09fd65f8f 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -697,6 +697,8 @@ pub struct FullPeerConfig { pub is_authority: bool, /// Syncing mode pub sync_mode: SyncMode, + /// Extra genesis storage. + pub extra_storage: Option, /// Enable transaction indexing. pub storage_chain: bool, } @@ -765,6 +767,11 @@ where (Some(keep_blocks), false) => TestClientBuilder::with_pruning_window(keep_blocks), (None, false) => TestClientBuilder::with_default_backend(), }; + if let Some(storage) = config.extra_storage { + let genesis_extra_storage = test_client_builder.genesis_init_mut().extra_storage(); + *genesis_extra_storage = storage; + } + if matches!(config.sync_mode, SyncMode::Fast { .. } | SyncMode::Warp) { test_client_builder = test_client_builder.set_no_genesis(); } diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index f3af7f8ff6fc3..ff62b5476d1e6 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -1110,11 +1110,44 @@ fn syncs_state() { sp_tracing::try_init_simple(); for skip_proofs in &[false, true] { let mut net = TestNet::new(0); - net.add_full_peer_with_config(Default::default()); - net.add_full_peer_with_config(FullPeerConfig { - sync_mode: SyncMode::Fast { skip_proofs: *skip_proofs, storage_chain_mode: false }, - ..Default::default() - }); + let mut genesis_storage: sp_core::storage::Storage = Default::default(); + genesis_storage.top.insert(b"additional_key".to_vec(), vec![1]); + let mut child_data: std::collections::BTreeMap, Vec> = Default::default(); + for i in 0u8..16 { + child_data.insert(vec![i; 5], vec![i; 33]); + } + let child1 = sp_core::storage::StorageChild { + data: child_data.clone(), + child_info: sp_core::storage::ChildInfo::new_default(b"child1"), + }; + let child3 = sp_core::storage::StorageChild { + data: child_data.clone(), + child_info: sp_core::storage::ChildInfo::new_default(b"child3"), + }; + for i in 22u8..33 { + child_data.insert(vec![i; 5], vec![i; 33]); + } + let child2 = sp_core::storage::StorageChild { + data: child_data.clone(), + child_info: sp_core::storage::ChildInfo::new_default(b"child2"), + }; + genesis_storage + .children_default + .insert(child1.child_info.storage_key().to_vec(), child1); + genesis_storage + .children_default + .insert(child2.child_info.storage_key().to_vec(), child2); + genesis_storage + .children_default + .insert(child3.child_info.storage_key().to_vec(), child3); + let mut config_one = FullPeerConfig::default(); + config_one.extra_storage = Some(genesis_storage.clone()); + net.add_full_peer_with_config(config_one); + let mut config_two = FullPeerConfig::default(); + config_two.extra_storage = Some(genesis_storage); + config_two.sync_mode = + SyncMode::Fast { skip_proofs: *skip_proofs, storage_chain_mode: false }; + net.add_full_peer_with_config(config_two); net.peer(0).push_blocks(64, false); // Wait for peer 1 to sync header chain. net.block_until_sync(); diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 4e3cb0aaf234b..6ce2feb050759 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -64,7 +64,10 @@ use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sp_core::{ convert_hash, - storage::{well_known_keys, ChildInfo, PrefixedStorageKey, StorageData, StorageKey}, + storage::{ + well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, StorageChild, StorageData, + StorageKey, + }, ChangesTrieConfiguration, NativeOrEncoded, }; #[cfg(feature = "test-helpers")] @@ -78,11 +81,12 @@ use sp_runtime::{ BuildStorage, Justification, Justifications, }; use sp_state_machine::{ - key_changes, key_changes_proof, prove_child_read, prove_range_read_with_size, prove_read, - read_range_proof_check, Backend as StateBackend, ChangesTrieAnchorBlockId, - ChangesTrieConfigurationRange, ChangesTrieRootsStorage, ChangesTrieStorage, DBValue, + key_changes, key_changes_proof, prove_child_read, prove_range_read_with_child_with_size, + prove_read, read_range_proof_check_with_child_on_proving_backend, Backend as StateBackend, + ChangesTrieAnchorBlockId, ChangesTrieConfigurationRange, ChangesTrieRootsStorage, + ChangesTrieStorage, DBValue, KeyValueStates, KeyValueStorageLevel, MAX_NESTED_TRIE_DEPTH, }; -use sp_trie::StorageProof; +use sp_trie::{CompactProof, StorageProof}; use std::{ collections::{BTreeMap, HashMap, HashSet}, marker::PhantomData, @@ -824,10 +828,37 @@ where Some((main_sc, child_sc)) }, sc_consensus::StorageChanges::Import(changes) => { - let storage = sp_storage::Storage { - top: changes.state.into_iter().collect(), - children_default: Default::default(), - }; + let mut storage = sp_storage::Storage::default(); + for state in changes.state.0.into_iter() { + if state.parent_storage_keys.len() == 0 && state.state_root.len() == 0 { + for (key, value) in state.key_values.into_iter() { + storage.top.insert(key, value); + } + } else { + for parent_storage in state.parent_storage_keys { + let storage_key = PrefixedStorageKey::new_ref(&parent_storage); + let storage_key = + match ChildType::from_prefixed_key(&storage_key) { + Some((ChildType::ParentKeyId, storage_key)) => + storage_key, + None => + return Err(Error::Backend( + "Invalid child storage key.".to_string(), + )), + }; + let entry = storage + .children_default + .entry(storage_key.to_vec()) + .or_insert_with(|| StorageChild { + data: Default::default(), + child_info: ChildInfo::new_default(storage_key), + }); + for (key, value) in state.key_values.iter() { + entry.data.insert(key.clone(), value.clone()); + } + } + } + } let state_root = operation.op.reset_storage(storage)?; if state_root != *import_headers.post().state_root() { @@ -1347,62 +1378,153 @@ where fn read_proof_collection( &self, id: &BlockId, - start_key: &[u8], + start_key: &[Vec], size_limit: usize, - ) -> sp_blockchain::Result<(StorageProof, u32)> { + ) -> sp_blockchain::Result<(CompactProof, u32)> { let state = self.state_at(id)?; - Ok(prove_range_read_with_size::<_, HashFor>( - state, - None, - None, - size_limit, - Some(start_key), - )?) + let root = state.storage_root(std::iter::empty()).0; + + let (proof, count) = prove_range_read_with_child_with_size::<_, HashFor>( + state, size_limit, start_key, + )?; + let proof = sp_trie::encode_compact::>>(proof, root) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?; + Ok((proof, count)) } fn storage_collection( &self, id: &BlockId, - start_key: &[u8], + start_key: &[Vec], size_limit: usize, - ) -> sp_blockchain::Result, Vec)>> { + ) -> sp_blockchain::Result> { + if start_key.len() > MAX_NESTED_TRIE_DEPTH { + return Err(Error::Backend("Invalid start key.".to_string())) + } let state = self.state_at(id)?; - let mut current_key = start_key.to_vec(); - let mut total_size = 0; - let mut entries = Vec::new(); - while let Some(next_key) = state - .next_storage_key(¤t_key) - .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? - { - let value = state - .storage(next_key.as_ref()) + let child_info = |storage_key: &Vec| -> sp_blockchain::Result { + let storage_key = PrefixedStorageKey::new_ref(&storage_key); + match ChildType::from_prefixed_key(&storage_key) { + Some((ChildType::ParentKeyId, storage_key)) => + Ok(ChildInfo::new_default(storage_key)), + None => Err(Error::Backend("Invalid child storage key.".to_string())), + } + }; + let mut current_child = if start_key.len() == 2 { + let start_key = start_key.get(0).expect("checked len"); + if let Some(child_root) = state + .storage(&start_key) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? - .unwrap_or_default(); - let size = value.len() + next_key.len(); - if total_size + size > size_limit && !entries.is_empty() { + { + Some((child_info(start_key)?, child_root)) + } else { + return Err(Error::Backend("Invalid root start key.".to_string())) + } + } else { + None + }; + let mut current_key = start_key.last().map(Clone::clone).unwrap_or(Vec::new()); + let mut total_size = 0; + let mut result = vec![( + KeyValueStorageLevel { + state_root: Vec::new(), + key_values: Vec::new(), + parent_storage_keys: Vec::new(), + }, + false, + )]; + + let mut child_roots = HashSet::new(); + loop { + let mut entries = Vec::new(); + let mut complete = true; + let mut switch_child_key = None; + while let Some(next_key) = if let Some(child) = current_child.as_ref() { + state + .next_child_storage_key(&child.0, ¤t_key) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? + } else { + state + .next_storage_key(¤t_key) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? + } { + let value = if let Some(child) = current_child.as_ref() { + state + .child_storage(&child.0, next_key.as_ref()) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? + .unwrap_or_default() + } else { + state + .storage(next_key.as_ref()) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? + .unwrap_or_default() + }; + let size = value.len() + next_key.len(); + if total_size + size > size_limit && !entries.is_empty() { + complete = false; + break + } + total_size += size; + + if current_child.is_none() && + sp_core::storage::well_known_keys::is_child_storage_key(next_key.as_slice()) + { + if !child_roots.contains(value.as_slice()) { + child_roots.insert(value.clone()); + switch_child_key = Some((next_key.clone(), value.clone())); + entries.push((next_key.clone(), value)); + break + } + } + entries.push((next_key.clone(), value)); + current_key = next_key; + } + if let Some((child, child_root)) = switch_child_key.take() { + result[0].0.key_values.extend(entries.into_iter()); + current_child = Some((child_info(&child)?, child_root)); + current_key = Vec::new(); + } else if let Some((child, child_root)) = current_child.take() { + current_key = child.into_prefixed_storage_key().into_inner(); + result.push(( + KeyValueStorageLevel { + state_root: child_root, + key_values: entries, + parent_storage_keys: Vec::new(), + }, + complete, + )); + if !complete { + break + } + } else { + result[0].0.key_values.extend(entries.into_iter()); + result[0].1 = complete; break } - total_size += size; - entries.push((next_key.clone(), value)); - current_key = next_key; } - Ok(entries) + Ok(result) } fn verify_range_proof( &self, root: Block::Hash, - proof: StorageProof, - start_key: &[u8], - ) -> sp_blockchain::Result<(Vec<(Vec, Vec)>, bool)> { - Ok(read_range_proof_check::>( - root, - proof, - None, - None, - None, - Some(start_key), - )?) + proof: CompactProof, + start_key: &[Vec], + ) -> sp_blockchain::Result<(KeyValueStates, usize)> { + let mut db = sp_state_machine::MemoryDB::>::new(&[]); + let _ = sp_trie::decode_compact::>, _, _>( + &mut db, + proof.iter_compact_encoded_nodes(), + Some(&root), + ) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?; + let proving_backend = sp_state_machine::TrieBackend::new(db, root); + let state = read_range_proof_check_with_child_on_proving_backend::>( + &proving_backend, + start_key, + )?; + + Ok(state) } } diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index a724cf5c9a0b4..b0178021f3130 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -172,7 +172,7 @@ mod std_reexport { }; pub use sp_trie::{ trie_types::{Layout, TrieDBMut}, - DBValue, MemoryDB, StorageProof, TrieMut, + CompactProof, DBValue, MemoryDB, StorageProof, TrieMut, }; } @@ -181,15 +181,20 @@ mod execution { use super::*; use codec::{Codec, Decode, Encode}; use hash_db::Hasher; + use smallvec::SmallVec; use sp_core::{ hexdisplay::HexDisplay, - storage::ChildInfo, + storage::{ChildInfo, ChildType, PrefixedStorageKey}, traits::{CodeExecutor, ReadRuntimeVersionExt, RuntimeCode, SpawnNamed}, NativeOrEncoded, NeverNativeValue, }; use sp_externalities::Extensions; - use std::{collections::HashMap, fmt, panic::UnwindSafe, result}; - use tracing::{trace, warn}; + use std::{ + collections::{HashMap, HashSet}, + fmt, + panic::UnwindSafe, + result, + }; const PROOF_CLOSE_TRANSACTION: &str = "\ Closing a transaction that was started in this function. Client initiated transactions @@ -742,6 +747,254 @@ mod execution { prove_read_on_trie_backend(trie_backend, keys) } + /// State machine only allows a single level + /// of child trie. + pub const MAX_NESTED_TRIE_DEPTH: usize = 2; + + /// Multiple key value state. + /// States are ordered by root storage key. + #[derive(PartialEq, Eq, Clone)] + pub struct KeyValueStates(pub Vec); + + /// A key value state at any storage level. + #[derive(PartialEq, Eq, Clone)] + pub struct KeyValueStorageLevel { + /// State root of the level, for + /// top trie it is as an empty byte array. + pub state_root: Vec, + /// Storage of parents, empty for top root or + /// when exporting (building proof). + pub parent_storage_keys: Vec>, + /// Pair of key and values from this state. + pub key_values: Vec<(Vec, Vec)>, + } + + impl From for KeyValueStates + where + I: IntoIterator, (Vec<(Vec, Vec)>, Vec>))>, + { + fn from(b: I) -> Self { + let mut result = Vec::new(); + for (state_root, (key_values, storage_paths)) in b.into_iter() { + result.push(KeyValueStorageLevel { + state_root, + key_values, + parent_storage_keys: storage_paths, + }) + } + KeyValueStates(result) + } + } + + impl KeyValueStates { + /// Return total number of key values in states. + pub fn len(&self) -> usize { + self.0.iter().fold(0, |nb, state| nb + state.key_values.len()) + } + + /// Update last keys accessed from this state. + pub fn update_last_key( + &self, + stopped_at: usize, + last: &mut SmallVec<[Vec; 2]>, + ) -> bool { + if stopped_at == 0 || stopped_at > MAX_NESTED_TRIE_DEPTH { + return false + } + match stopped_at { + 1 => { + let top_last = + self.0.get(0).and_then(|s| s.key_values.last().map(|kv| kv.0.clone())); + if let Some(top_last) = top_last { + match last.len() { + 0 => { + last.push(top_last); + return true + }, + 2 => { + last.pop(); + }, + _ => (), + } + // update top trie access. + last[0] = top_last; + return true + } else { + // No change in top trie accesses. + // Indicates end of reading of a child trie. + last.truncate(1); + return true + } + }, + 2 => { + let top_last = + self.0.get(0).and_then(|s| s.key_values.last().map(|kv| kv.0.clone())); + let child_last = + self.0.last().and_then(|s| s.key_values.last().map(|kv| kv.0.clone())); + + if let Some(child_last) = child_last { + if last.len() == 0 { + if let Some(top_last) = top_last { + last.push(top_last) + } else { + return false + } + } else if let Some(top_last) = top_last { + last[0] = top_last; + } + if last.len() == 2 { + last.pop(); + } + last.push(child_last); + return true + } else { + // stopped at level 2 so child last is define. + return false + } + }, + _ => (), + } + false + } + } + + /// Generate range storage read proof, with child tries + /// content. + /// A size limit is applied to the proof with the + /// exception that `start_at` and its following element + /// are always part of the proof. + /// If a key different than `start_at` is a child trie root, + /// the child trie content will be included in the proof. + pub fn prove_range_read_with_child_with_size( + backend: B, + size_limit: usize, + start_at: &[Vec], + ) -> Result<(StorageProof, u32), Box> + where + B: Backend, + H: Hasher, + H::Out: Ord + Codec, + { + let trie_backend = backend + .as_trie_backend() + .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; + prove_range_read_with_child_with_size_on_trie_backend(trie_backend, size_limit, start_at) + } + + /// Generate range storage read proof, with child tries + /// content. + /// See `prove_range_read_with_child_with_size`. + pub fn prove_range_read_with_child_with_size_on_trie_backend( + trie_backend: &TrieBackend, + size_limit: usize, + start_at: &[Vec], + ) -> Result<(StorageProof, u32), Box> + where + S: trie_backend_essence::TrieBackendStorage, + H: Hasher, + H::Out: Ord + Codec, + { + if start_at.len() > MAX_NESTED_TRIE_DEPTH { + return Err(Box::new("Invalid start of range.")) + } + + let proving_backend = proving_backend::ProvingBackend::::new(trie_backend); + let mut count = 0; + + let mut child_roots = HashSet::new(); + let (mut child_key, mut start_at) = if start_at.len() == 2 { + let storage_key = start_at.get(0).expect("Checked length.").clone(); + if let Some(state_root) = proving_backend + .storage(&storage_key) + .map_err(|e| Box::new(e) as Box)? + { + child_roots.insert(state_root.clone()); + } else { + return Err(Box::new("Invalid range start child trie key.")) + } + + (Some(storage_key), start_at.get(1).cloned()) + } else { + (None, start_at.get(0).cloned()) + }; + + loop { + let (child_info, depth) = if let Some(storage_key) = child_key.as_ref() { + let storage_key = PrefixedStorageKey::new_ref(storage_key); + ( + Some(match ChildType::from_prefixed_key(&storage_key) { + Some((ChildType::ParentKeyId, storage_key)) => + ChildInfo::new_default(storage_key), + None => return Err(Box::new("Invalid range start child trie key.")), + }), + 2, + ) + } else { + (None, 1) + }; + + let start_at_ref = start_at.as_ref().map(AsRef::as_ref); + let mut switch_child_key = None; + let mut first = start_at.is_some(); + let completed = proving_backend + .apply_to_key_values_while( + child_info.as_ref(), + None, + start_at_ref, + |key, value| { + if first { + if start_at_ref + .as_ref() + .map(|start| &key.as_slice() > start) + .unwrap_or(true) + { + first = false; + } + } + if first { + true + } else if depth < MAX_NESTED_TRIE_DEPTH && + sp_core::storage::well_known_keys::is_child_storage_key( + key.as_slice(), + ) { + count += 1; + if !child_roots.contains(value.as_slice()) { + child_roots.insert(value); + switch_child_key = Some(key); + false + } else { + // do not add two child trie with same root + true + } + } else if proving_backend.estimate_encoded_size() <= size_limit { + count += 1; + true + } else { + false + } + }, + false, + ) + .map_err(|e| Box::new(e) as Box)?; + + if switch_child_key.is_none() { + if depth == 1 { + break + } else { + if completed { + start_at = child_key.take(); + } else { + break + } + } + } else { + child_key = switch_child_key; + start_at = None; + } + } + Ok((proving_backend.extract_proof(), count)) + } + /// Generate range storage read proof. pub fn prove_range_read_with_size( backend: B, @@ -884,7 +1137,25 @@ mod execution { Ok(result) } - /// Check child storage range proof, generated by `prove_range_read` call. + /// Check storage range proof with child trie included, generated by + /// `prove_range_read_with_child_with_size` call. + /// + /// Returns key values contents and the depth of the pending state iteration + /// (0 if completed). + pub fn read_range_proof_check_with_child( + root: H::Out, + proof: StorageProof, + start_at: &[Vec], + ) -> Result<(KeyValueStates, usize), Box> + where + H: Hasher, + H::Out: Ord + Codec, + { + let proving_backend = create_proof_check_backend::(root, proof)?; + read_range_proof_check_with_child_on_proving_backend(&proving_backend, start_at) + } + + /// Check child storage range proof, generated by `prove_range_read_with_size` call. pub fn read_range_proof_check( root: H::Out, proof: StorageProof, @@ -991,6 +1262,130 @@ mod execution { Err(e) => Err(Box::new(e) as Box), } } + + /// Check storage range proof on pre-created proving backend. + /// + /// See `read_range_proof_check_with_child`. + pub fn read_range_proof_check_with_child_on_proving_backend( + proving_backend: &TrieBackend, H>, + start_at: &[Vec], + ) -> Result<(KeyValueStates, usize), Box> + where + H: Hasher, + H::Out: Ord + Codec, + { + let mut result = vec![KeyValueStorageLevel { + state_root: Default::default(), + key_values: Default::default(), + parent_storage_keys: Default::default(), + }]; + if start_at.len() > MAX_NESTED_TRIE_DEPTH { + return Err(Box::new("Invalid start of range.")) + } + + let mut child_roots = HashSet::new(); + let (mut child_key, mut start_at) = if start_at.len() == 2 { + let storage_key = start_at.get(0).expect("Checked length.").clone(); + let child_key = if let Some(state_root) = proving_backend + .storage(&storage_key) + .map_err(|e| Box::new(e) as Box)? + { + child_roots.insert(state_root.clone()); + Some((storage_key, state_root)) + } else { + return Err(Box::new("Invalid range start child trie key.")) + }; + + (child_key, start_at.get(1).cloned()) + } else { + (None, start_at.get(0).cloned()) + }; + + let completed = loop { + let (child_info, depth) = if let Some((storage_key, state_root)) = child_key.as_ref() { + result.push(KeyValueStorageLevel { + state_root: state_root.clone(), + key_values: Default::default(), + parent_storage_keys: Default::default(), + }); + + let storage_key = PrefixedStorageKey::new_ref(storage_key); + ( + Some(match ChildType::from_prefixed_key(&storage_key) { + Some((ChildType::ParentKeyId, storage_key)) => + ChildInfo::new_default(storage_key), + None => return Err(Box::new("Invalid range start child trie key.")), + }), + 2, + ) + } else { + (None, 1) + }; + + let values = if child_info.is_some() { + &mut result.last_mut().expect("Added above").key_values + } else { + &mut result[0].key_values + }; + let start_at_ref = start_at.as_ref().map(AsRef::as_ref); + let mut switch_child_key = None; + let mut first = start_at.is_some(); + let completed = proving_backend + .apply_to_key_values_while( + child_info.as_ref(), + None, + start_at_ref, + |key, value| { + if first { + if start_at_ref + .as_ref() + .map(|start| &key.as_slice() > start) + .unwrap_or(true) + { + first = false; + } + } + if !first { + values.push((key.to_vec(), value.to_vec())); + } + if first { + true + } else if depth < MAX_NESTED_TRIE_DEPTH && + sp_core::storage::well_known_keys::is_child_storage_key( + key.as_slice(), + ) { + if child_roots.contains(value.as_slice()) { + // Do not add two chid trie with same root. + true + } else { + child_roots.insert(value.clone()); + switch_child_key = Some((key, value)); + false + } + } else { + true + } + }, + true, + ) + .map_err(|e| Box::new(e) as Box)?; + + if switch_child_key.is_none() { + if !completed { + break depth + } + if depth == 1 { + break 0 + } else { + start_at = child_key.take().map(|entry| entry.0); + } + } else { + child_key = switch_child_key; + start_at = None; + } + }; + Ok((KeyValueStates(result), completed)) + } } #[cfg(test)] @@ -1574,7 +1969,7 @@ mod tests { assert_eq!( local_result1.into_iter().collect::>(), - vec![(b"value3".to_vec(), Some(vec![142]))], + vec![(b"value3".to_vec(), Some(vec![142; 33]))], ); assert_eq!(local_result2.into_iter().collect::>(), vec![(b"value2".to_vec(), None)]); assert_eq!(local_result3.into_iter().collect::>(), vec![(b"dummy".to_vec(), None)]); @@ -1678,7 +2073,7 @@ mod tests { let remote_root = remote_backend.storage_root(::std::iter::empty()).0; let (proof, count) = prove_range_read_with_size(remote_backend, None, None, 0, None).unwrap(); - // Alwasys contains at least some nodes. + // Always contains at least some nodes. assert_eq!(proof.into_memory_db::().drain().len(), 3); assert_eq!(count, 1); @@ -1723,6 +2118,45 @@ mod tests { assert_eq!(completed, true); } + #[test] + fn prove_range_with_child_works() { + let remote_backend = trie_backend::tests::test_trie(); + let remote_root = remote_backend.storage_root(::std::iter::empty()).0; + let mut start_at = smallvec::SmallVec::<[Vec; 2]>::new(); + let trie_backend = remote_backend.as_trie_backend().unwrap(); + let max_iter = 1000; + let mut nb_loop = 0; + loop { + nb_loop += 1; + if max_iter == nb_loop { + panic!("Too many loop in prove range"); + } + let (proof, count) = prove_range_read_with_child_with_size_on_trie_backend( + trie_backend, + 1, + start_at.as_slice(), + ) + .unwrap(); + // Always contains at least some nodes. + assert!(proof.clone().into_memory_db::().drain().len() > 0); + assert!(count < 3); // when doing child we include parent and first child key. + + let (result, completed_depth) = read_range_proof_check_with_child::( + remote_root, + proof.clone(), + start_at.as_slice(), + ) + .unwrap(); + + if completed_depth == 0 { + break + } + assert!(result.update_last_key(completed_depth, &mut start_at)); + } + + assert_eq!(nb_loop, 10); + } + #[test] fn compact_multiple_child_trie() { // this root will be queried diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index 7cb725a80503d..7f9a02e055251 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -281,8 +281,8 @@ pub mod tests { { let mut mdb = KeySpacedDBMut::new(&mut mdb, child_info.keyspace()); let mut trie = TrieDBMut::new(&mut mdb, &mut root); - trie.insert(b"value3", &[142]).expect("insert failed"); - trie.insert(b"value4", &[124]).expect("insert failed"); + trie.insert(b"value3", &[142; 33]).expect("insert failed"); + trie.insert(b"value4", &[124; 33]).expect("insert failed"); }; { @@ -319,7 +319,7 @@ pub mod tests { test_trie .child_storage(&ChildInfo::new_default(CHILD_KEY_1), b"value3") .unwrap(), - Some(vec![142u8]), + Some(vec![142u8; 33]), ); // Change cache entry to check that caching is active. test_trie diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index bcfe93b6f7975..da92e0f37983c 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -137,6 +137,11 @@ impl GenesisParameters { pub fn set_wasm_code(&mut self, code: Vec) { self.wasm_code = Some(code); } + + /// Access extra genesis storage. + pub fn extra_storage(&mut self) -> &mut Storage { + &mut self.extra_storage + } } impl substrate_test_client::GenesisInit for GenesisParameters { From 2e8bb09da2dfbc1a21c159e777dc1cf0bceba56d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sun, 7 Nov 2021 23:24:53 +0000 Subject: [PATCH 0192/1472] put `TryInto` and `TryFrom` in `sp_std::prelude` (#10183) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Switch to Rust 2021 * Update trybuild to fix errors * half baked * fix * remove unused import * remove more warnings Co-authored-by: Bastian Köcher --- frame/assets/src/lib.rs | 2 +- frame/aura/src/lib.rs | 2 +- frame/authority-discovery/src/lib.rs | 2 -- frame/babe/src/lib.rs | 2 +- frame/bags-list/remote-tests/src/lib.rs | 2 +- frame/bags-list/remote-tests/src/sanity_check.rs | 2 +- frame/benchmarking/src/analysis.rs | 1 - frame/contracts/rpc/src/lib.rs | 1 - frame/contracts/src/benchmarking/code.rs | 2 +- frame/contracts/src/benchmarking/mod.rs | 2 +- frame/contracts/src/wasm/mod.rs | 1 - frame/democracy/src/conviction.rs | 2 +- frame/democracy/src/tests/lock_voting.rs | 1 - frame/democracy/src/vote.rs | 2 +- frame/election-provider-multi-phase/src/benchmarking.rs | 4 ---- frame/election-provider-multi-phase/src/helpers.rs | 2 +- frame/election-provider-multi-phase/src/lib.rs | 2 +- frame/election-provider-multi-phase/src/mock.rs | 2 +- frame/election-provider-multi-phase/src/unsigned.rs | 2 +- frame/identity/src/lib.rs | 2 +- frame/im-online/src/lib.rs | 1 - frame/multisig/src/benchmarking.rs | 1 - frame/randomness-collective-flip/src/lib.rs | 2 +- frame/session/src/lib.rs | 1 - frame/staking/reward-curve/src/log.rs | 2 -- frame/staking/reward-fn/src/lib.rs | 1 - frame/staking/src/benchmarking.rs | 1 - frame/support/procedural/src/pallet/parse/config.rs | 1 - frame/support/src/storage/bounded_btree_map.rs | 1 - frame/support/src/storage/bounded_vec.rs | 3 +-- frame/support/src/storage/mod.rs | 1 - frame/system/src/offchain.rs | 6 +----- frame/transaction-payment/rpc/src/lib.rs | 2 +- frame/transaction-payment/src/lib.rs | 1 - frame/uniques/src/impl_nonfungibles.rs | 2 +- frame/uniques/src/tests.rs | 2 +- primitives/std/src/lib.rs | 2 ++ utils/frame/benchmarking-cli/src/writer.rs | 1 - utils/frame/frame-utilities-cli/src/pallet_id.rs | 1 - 39 files changed, 22 insertions(+), 48 deletions(-) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 4176242c8394a..dfc81eadeb530 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -157,7 +157,7 @@ use sp_runtime::{ }, ArithmeticError, TokenError, }; -use sp_std::{borrow::Borrow, convert::TryInto, prelude::*}; +use sp_std::{borrow::Borrow, prelude::*}; #[cfg(feature = "std")] use frame_support::traits::GenesisBuild; diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 4b5294835403a..a4e55f25df5f6 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -49,7 +49,7 @@ use sp_runtime::{ traits::{IsMember, Member, SaturatedConversion, Saturating, Zero}, RuntimeAppPublic, }; -use sp_std::{convert::TryFrom, vec::Vec}; +use sp_std::prelude::*; pub mod migrations; mod mock; diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index 8fced0d18cff1..a6609860d7cf1 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -30,8 +30,6 @@ use frame_support::{ use sp_authority_discovery::AuthorityId; use sp_std::prelude::*; -use core::convert::TryFrom; - pub use pallet::*; #[frame_support::pallet] diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index c74bbf897ac7f..033d993f4e26d 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -31,7 +31,7 @@ use frame_support::{ weights::{Pays, Weight}, BoundedVec, WeakBoundedVec, }; -use sp_application_crypto::{Public, TryFrom}; +use sp_application_crypto::Public; use sp_runtime::{ generic::DigestItem, traits::{IsMember, One, SaturatedConversion, Saturating, Zero}, diff --git a/frame/bags-list/remote-tests/src/lib.rs b/frame/bags-list/remote-tests/src/lib.rs index e471c4c95bdbc..3d555eb1f1e35 100644 --- a/frame/bags-list/remote-tests/src/lib.rs +++ b/frame/bags-list/remote-tests/src/lib.rs @@ -17,7 +17,7 @@ //! Utilities for remote-testing pallet-bags-list. -use sp_std::convert::TryInto; +use sp_std::prelude::*; /// A common log target to use. pub const LOG_TARGET: &'static str = "runtime::bags-list::remote-tests"; diff --git a/frame/bags-list/remote-tests/src/sanity_check.rs b/frame/bags-list/remote-tests/src/sanity_check.rs index e5e9f45bac5f4..7282e7bad5e32 100644 --- a/frame/bags-list/remote-tests/src/sanity_check.rs +++ b/frame/bags-list/remote-tests/src/sanity_check.rs @@ -23,7 +23,7 @@ use frame_support::{ }; use remote_externalities::{Builder, Mode, OnlineConfig}; use sp_runtime::traits::Block as BlockT; -use sp_std::convert::TryInto; +use sp_std::prelude::*; /// Execute the sanity check of the bags-list. pub async fn execute( diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index 2bb20ebe2e7f8..5ffb6e93c8fc3 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -18,7 +18,6 @@ //! Tools for analyzing the benchmark results. use crate::BenchmarkResult; -use core::convert::TryFrom; use linregress::{FormulaRegressionBuilder, RegressionDataBuilder}; use std::collections::BTreeMap; diff --git a/frame/contracts/rpc/src/lib.rs b/frame/contracts/rpc/src/lib.rs index e0796af056540..c82cf44d97c7f 100644 --- a/frame/contracts/rpc/src/lib.rs +++ b/frame/contracts/rpc/src/lib.rs @@ -32,7 +32,6 @@ use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header as HeaderT}, }; -use std::convert::{TryFrom, TryInto}; pub use pallet_contracts_rpc_runtime_api::ContractsApi as ContractsRuntimeApi; diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index b24005ec58699..6b90381e7d353 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -36,7 +36,7 @@ use pwasm_utils::parity_wasm::{ use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::Hash; use sp_sandbox::{EnvironmentDefinitionBuilder, Memory}; -use sp_std::{borrow::ToOwned, convert::TryFrom, prelude::*}; +use sp_std::{borrow::ToOwned, prelude::*}; /// Pass to `create_code` in order to create a compiled `WasmModule`. /// diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 5c753c2d95558..665ec565c8e65 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -44,7 +44,7 @@ use sp_runtime::{ traits::{Bounded, Hash}, Perbill, }; -use sp_std::{convert::TryInto, default::Default, vec, vec::Vec}; +use sp_std::prelude::*; /// How many batches we do per API benchmark. const API_BENCHMARK_BATCHES: u32 = 20; diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 855cb6e45091f..565a424323ac6 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -1967,7 +1967,6 @@ mod tests { #[test] #[cfg(feature = "unstable-interface")] fn call_runtime_works() { - use std::convert::TryInto; let call = Call::System(frame_system::Call::remark { remark: b"Hello World".to_vec() }); let mut ext = MockExt::default(); let result = execute(CODE_CALL_RUNTIME, call.encode(), &mut ext).unwrap(); diff --git a/frame/democracy/src/conviction.rs b/frame/democracy/src/conviction.rs index b4f24c93bb40f..59a5eccc616c3 100644 --- a/frame/democracy/src/conviction.rs +++ b/frame/democracy/src/conviction.rs @@ -24,7 +24,7 @@ use sp_runtime::{ traits::{Bounded, CheckedDiv, CheckedMul, Zero}, RuntimeDebug, }; -use sp_std::{convert::TryFrom, result::Result}; +use sp_std::{prelude::*, result::Result}; /// A value denoting the strength of conviction of a vote. #[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo)] diff --git a/frame/democracy/src/tests/lock_voting.rs b/frame/democracy/src/tests/lock_voting.rs index 8b80b39c14aab..2e1440d8f44bb 100644 --- a/frame/democracy/src/tests/lock_voting.rs +++ b/frame/democracy/src/tests/lock_voting.rs @@ -18,7 +18,6 @@ //! The tests for functionality concerning locking and lock-voting. use super::*; -use std::convert::TryFrom; fn aye(x: u8, balance: u64) -> AccountVote { AccountVote::Standard { diff --git a/frame/democracy/src/vote.rs b/frame/democracy/src/vote.rs index 03ca020ca0949..da74f7bd2fb64 100644 --- a/frame/democracy/src/vote.rs +++ b/frame/democracy/src/vote.rs @@ -24,7 +24,7 @@ use sp_runtime::{ traits::{Saturating, Zero}, RuntimeDebug, }; -use sp_std::{convert::TryFrom, prelude::*, result::Result}; +use sp_std::prelude::*; /// A number of lock periods, plus a vote, one way or the other. #[derive(Copy, Clone, Eq, PartialEq, Default, RuntimeDebug)] diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 9648b8e0f2465..d9db6c3090994 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -26,10 +26,6 @@ use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng}; use sp_arithmetic::{per_things::Percent, traits::One}; use sp_npos_elections::IndexAssignment; use sp_runtime::InnerOf; -use sp_std::{ - boxed::Box, - convert::{TryFrom, TryInto}, -}; const SEED: u32 = 999; diff --git a/frame/election-provider-multi-phase/src/helpers.rs b/frame/election-provider-multi-phase/src/helpers.rs index 72b1b23f27f3c..98a14a93a25e0 100644 --- a/frame/election-provider-multi-phase/src/helpers.rs +++ b/frame/election-provider-multi-phase/src/helpers.rs @@ -18,7 +18,7 @@ //! Some helper functions/macros for this crate. use super::{Config, SolutionTargetIndexOf, SolutionVoterIndexOf, VoteWeight}; -use sp_std::{collections::btree_map::BTreeMap, convert::TryInto, prelude::*}; +use sp_std::{collections::btree_map::BTreeMap, prelude::*}; #[macro_export] macro_rules! log { diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index a7863fafa7747..80a13aa99fb70 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -255,7 +255,7 @@ use sp_runtime::{ }, DispatchError, PerThing, Perbill, RuntimeDebug, SaturatedConversion, }; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 1a65316be1f10..fbde6ad991706 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -40,7 +40,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, PerU16, }; -use std::{convert::TryFrom, sync::Arc}; +use std::sync::Arc; pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 0ed9b5427b1ec..1770f4343a0a4 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -35,7 +35,7 @@ use sp_runtime::{ offchain::storage::{MutateStorageError, StorageValueRef}, DispatchError, SaturatedConversion, }; -use sp_std::{boxed::Box, cmp::Ordering, convert::TryFrom, vec::Vec}; +use sp_std::{cmp::Ordering, prelude::*}; /// Storage key used to store the last block number at which offchain worker ran. pub(crate) const OFFCHAIN_LAST_BLOCK: &[u8] = b"parity/multi-phase-unsigned-election"; diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index a91381f1edd8b..4d86efd27e534 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -80,7 +80,7 @@ pub mod weights; use frame_support::traits::{BalanceStatus, Currency, OnUnbalanced, ReservableCurrency}; use sp_runtime::traits::{AppendZerosInput, Saturating, StaticLookup, Zero}; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; pub use weights::WeightInfo; pub use pallet::*; diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index d76bbaaa2fd14..2c5a7633c3b4a 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -75,7 +75,6 @@ mod tests; pub mod weights; use codec::{Decode, Encode, MaxEncodedLen}; -use core::convert::TryFrom; use frame_support::{ traits::{ EstimateNextSessionRotation, Get, OneSessionHandler, ValidatorSet, diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index 1390b6eebbe34..cb98d8954030d 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -20,7 +20,6 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use core::convert::TryInto; use frame_benchmarking::{account, benchmarks}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index 1b1d5cb5cd823..a9abb2c9564df 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -71,7 +71,7 @@ use safe_mix::TripletMix; use codec::Encode; use frame_support::traits::Randomness; use sp_runtime::traits::{Hash, Saturating}; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; const RANDOM_MATERIAL_LEN: u32 = 81; diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 7fe163e0dfeac..6779285ee3187 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -131,7 +131,6 @@ use sp_runtime::{ }; use sp_staking::SessionIndex; use sp_std::{ - convert::TryFrom, marker::PhantomData, ops::{Rem, Sub}, prelude::*, diff --git a/frame/staking/reward-curve/src/log.rs b/frame/staking/reward-curve/src/log.rs index c196aaaa31a93..248a1e3c36a6e 100644 --- a/frame/staking/reward-curve/src/log.rs +++ b/frame/staking/reward-curve/src/log.rs @@ -1,5 +1,3 @@ -use std::convert::TryInto; - /// Simple u32 power of 2 function - simply uses a bit shift macro_rules! pow2 { ($n:expr) => { diff --git a/frame/staking/reward-fn/src/lib.rs b/frame/staking/reward-fn/src/lib.rs index dd5e629b3984c..25e52051effa5 100644 --- a/frame/staking/reward-fn/src/lib.rs +++ b/frame/staking/reward-fn/src/lib.rs @@ -19,7 +19,6 @@ //! Useful function for inflation for nominated proof of stake. -use core::convert::TryFrom; use sp_arithmetic::{ biguint::BigUint, traits::{SaturatedConversion, Zero}, diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 220e8f1e6a24c..80630818de7e6 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -256,7 +256,6 @@ benchmarks! { } unbond { - use sp_std::convert::TryFrom; // clean up any existing state. clear_validators_and_nominators::(); diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 712c20ffc7b4c..9e0a0fd52cbfc 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -16,7 +16,6 @@ // limitations under the License. use super::helper; -use core::convert::TryFrom; use frame_support_procedural_tools::get_doc_literals; use quote::ToTokens; use syn::spanned::Spanned; diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index 404814cb81693..7a59206aeba0e 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -307,7 +307,6 @@ pub mod test { use super::*; use crate::Twox128; use sp_io::TestExternalities; - use sp_std::convert::TryInto; crate::parameter_types! { pub const Seven: u32 = 7; diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index e51c6cd734113..3b5e7bda1651c 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -28,7 +28,7 @@ use core::{ ops::{Deref, Index, IndexMut}, slice::SliceIndex, }; -use sp_std::{convert::TryFrom, marker::PhantomData, prelude::*}; +use sp_std::{marker::PhantomData, prelude::*}; /// A bounded vector. /// @@ -349,7 +349,6 @@ pub mod test { use super::*; use crate::Twox128; use sp_io::TestExternalities; - use sp_std::convert::TryInto; crate::parameter_types! { pub const Seven: u32 = 7; diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 35552e08fef1e..69445932b869e 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -1400,7 +1400,6 @@ mod test { use super::*; use crate::{assert_ok, hash::Identity, Twox128}; use bounded_vec::BoundedVec; - use core::convert::{TryFrom, TryInto}; use generator::StorageValue as _; use sp_core::hashing::twox_128; use sp_io::TestExternalities; diff --git a/frame/system/src/offchain.rs b/frame/system/src/offchain.rs index ed758a2556b77..c4986e67319f0 100644 --- a/frame/system/src/offchain.rs +++ b/frame/system/src/offchain.rs @@ -62,11 +62,7 @@ use sp_runtime::{ app_crypto::RuntimeAppPublic, traits::{Extrinsic as ExtrinsicT, IdentifyAccount, One}, }; -use sp_std::{ - collections::btree_set::BTreeSet, - convert::{TryFrom, TryInto}, - prelude::{Box, Vec}, -}; +use sp_std::{collections::btree_set::BTreeSet, prelude::*}; /// Marker struct used to flag using all supported keys to sign a payload. pub struct ForAll {} diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index 945156d12a6a4..78230ee6e468f 100644 --- a/frame/transaction-payment/rpc/src/lib.rs +++ b/frame/transaction-payment/rpc/src/lib.rs @@ -31,7 +31,7 @@ use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, MaybeDisplay}, }; -use std::{convert::TryInto, sync::Arc}; +use std::sync::Arc; #[rpc] pub trait TransactionPaymentApi { diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 59d94a823723b..64cd5d5290635 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -347,7 +347,6 @@ pub mod pallet { // given weight == u64, we build multipliers from `diff` of two weight values, which can // at most be maximum block weight. Make sure that this can fit in a multiplier without // loss. - use sp_std::convert::TryInto; assert!( ::max_value() >= Multiplier::checked_from_integer( diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index e68d2d4deecda..5394f02160e3c 100644 --- a/frame/uniques/src/impl_nonfungibles.rs +++ b/frame/uniques/src/impl_nonfungibles.rs @@ -23,7 +23,7 @@ use frame_support::{ BoundedSlice, }; use sp_runtime::{DispatchError, DispatchResult}; -use sp_std::convert::TryFrom; +use sp_std::prelude::*; impl, I: 'static> Inspect<::AccountId> for Pallet { type InstanceId = T::InstanceId; diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 8a4f978b7f4f5..d23d694e949e2 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -21,7 +21,7 @@ use super::*; use crate::mock::*; use frame_support::{assert_noop, assert_ok, traits::Currency}; use pallet_balances::Error as BalancesError; -use sp_std::convert::TryInto; +use sp_std::prelude::*; fn assets() -> Vec<(u64, u32, u32)> { let mut r: Vec<_> = Account::::iter().map(|x| x.0).collect(); diff --git a/primitives/std/src/lib.rs b/primitives/std/src/lib.rs index 3af4d07ac6297..3d112a18edd0f 100644 --- a/primitives/std/src/lib.rs +++ b/primitives/std/src/lib.rs @@ -98,6 +98,8 @@ pub mod prelude { boxed::Box, clone::Clone, cmp::{Eq, PartialEq, Reverse}, + convert::{TryFrom, TryInto}, + iter::IntoIterator, vec::Vec, }; diff --git a/utils/frame/benchmarking-cli/src/writer.rs b/utils/frame/benchmarking-cli/src/writer.rs index ede5b2d1355a7..e7e8b42fd8a6d 100644 --- a/utils/frame/benchmarking-cli/src/writer.rs +++ b/utils/frame/benchmarking-cli/src/writer.rs @@ -17,7 +17,6 @@ // Outputs benchmark results to Rust files that can be ingested by the runtime. -use core::convert::TryInto; use std::{ collections::{HashMap, HashSet}, fs, diff --git a/utils/frame/frame-utilities-cli/src/pallet_id.rs b/utils/frame/frame-utilities-cli/src/pallet_id.rs index d173f52b39cd8..e4acdb2182f03 100644 --- a/utils/frame/frame-utilities-cli/src/pallet_id.rs +++ b/utils/frame/frame-utilities-cli/src/pallet_id.rs @@ -24,7 +24,6 @@ use sc_cli::{ }; use sp_core::crypto::{unwrap_or_default_ss58_version, Ss58AddressFormat, Ss58Codec}; use sp_runtime::traits::AccountIdConversion; -use std::convert::{TryFrom, TryInto}; use structopt::StructOpt; /// The `palletid` command From 2cc0e23254acaa81c0890dd3fee734131aa7da82 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Mon, 8 Nov 2021 07:29:51 +0800 Subject: [PATCH 0193/1472] Add serde support for `Slot` type (#10204) Add serde support for the `Slot` type as we'd like to use it directly in our RPC. --- Cargo.lock | 1 + primitives/consensus/slots/Cargo.toml | 2 ++ primitives/consensus/slots/src/lib.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index eeb1012b1d1d3..63a2d26db34e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9325,6 +9325,7 @@ version = "0.10.0-dev" dependencies = [ "parity-scale-codec", "scale-info", + "serde", "sp-arithmetic", "sp-runtime", ] diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index ad83835e02706..9177157bd5ed7 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } +serde = { version = "1.0", features = ["derive"], optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../arithmetic" } @@ -23,6 +24,7 @@ default = ["std"] std = [ "codec/std", "scale-info/std", + "serde", "sp-runtime/std", "sp-arithmetic/std", ] diff --git a/primitives/consensus/slots/src/lib.rs b/primitives/consensus/slots/src/lib.rs index 89b57dca83082..72b3c95068e39 100644 --- a/primitives/consensus/slots/src/lib.rs +++ b/primitives/consensus/slots/src/lib.rs @@ -24,6 +24,7 @@ use scale_info::TypeInfo; /// Unit type wrapper that represents a slot. #[derive(Debug, Encode, MaxEncodedLen, Decode, Eq, Clone, Copy, Default, Ord, TypeInfo)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct Slot(u64); impl core::ops::Deref for Slot { From a524cfd579b5cfa00ee7aea475a3a08cb42dc160 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Nov 2021 00:31:11 +0100 Subject: [PATCH 0194/1472] Bump lru from 0.6.6 to 0.7.0 (#10194) Bumps [lru](https://github.com/jeromefroe/lru-rs) from 0.6.6 to 0.7.0. - [Release notes](https://github.com/jeromefroe/lru-rs/releases) - [Changelog](https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/jeromefroe/lru-rs/compare/0.6.6...0.7.0) --- updated-dependencies: - dependency-name: lru 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 | 17 +++++++++++++---- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63a2d26db34e8..4794c1c0f5c41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3665,7 +3665,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "lru", + "lru 0.6.6", "minicbor", "rand 0.7.3", "smallvec 1.7.0", @@ -3999,6 +3999,15 @@ dependencies = [ "hashbrown 0.11.2", ] +[[package]] +name = "lru" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c748cfe47cb8da225c37595b3108bea1c198c84aaae8ea0ba76d01dda9fc803" +dependencies = [ + "hashbrown 0.11.2", +] + [[package]] name = "lru-cache" version = "0.1.2" @@ -8203,7 +8212,7 @@ dependencies = [ "linked-hash-map", "linked_hash_set", "log 0.4.14", - "lru", + "lru 0.7.0", "parity-scale-codec", "parking_lot 0.11.1", "pin-project 1.0.8", @@ -8246,7 +8255,7 @@ dependencies = [ "futures-timer 3.0.2", "libp2p", "log 0.4.14", - "lru", + "lru 0.7.0", "quickcheck", "sc-network", "sp-runtime", @@ -9239,7 +9248,7 @@ version = "4.0.0-dev" dependencies = [ "futures 0.3.16", "log 0.4.14", - "lru", + "lru 0.7.0", "parity-scale-codec", "parking_lot 0.11.1", "sp-api", diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 1f0b5c313294d..e17d9601eafc3 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.9" futures-timer = "3.0.1" libp2p = { version = "0.39.1", default-features = false } log = "0.4.8" -lru = "0.6.6" +lru = "0.7.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.9.0", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 7c2905d5fe03a..19ae5dd97e425 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -36,7 +36,7 @@ hex = "0.4.0" ip_network = "0.4.0" linked-hash-map = "0.5.4" linked_hash_set = "0.1.3" -lru = "0.6.6" +lru = "0.7.0" log = "0.4.8" parking_lot = "0.11.1" pin-project = "1.0.8" diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 7af7807954ef1..de73af10966e1 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.11" -lru = "0.6.6" +lru = "0.7.0" parking_lot = "0.11.1" thiserror = "1.0.21" futures = "0.3.9" From e1c30d92f5bda94a44ba461d914fd4b21fa7c07e Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Mon, 8 Nov 2021 10:42:48 +0100 Subject: [PATCH 0195/1472] Speedup block import (#10211) --- client/service/src/chain_ops/import_blocks.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/service/src/chain_ops/import_blocks.rs b/client/service/src/chain_ops/import_blocks.rs index a408a06a8170e..e4096afacdd3b 100644 --- a/client/service/src/chain_ops/import_blocks.rs +++ b/client/service/src/chain_ops/import_blocks.rs @@ -43,10 +43,10 @@ use std::{ }; /// Number of blocks we will add to the queue before waiting for the queue to catch up. -const MAX_PENDING_BLOCKS: u64 = 1_024; +const MAX_PENDING_BLOCKS: u64 = 10_000; /// Number of milliseconds to wait until next poll. -const DELAY_TIME: u64 = 2_000; +const DELAY_TIME: u64 = 200; /// Number of milliseconds that must have passed between two updates. const TIME_BETWEEN_UPDATES: u64 = 3_000; From 3b2ce548c6e00183ab12ab086859325164263584 Mon Sep 17 00:00:00 2001 From: Koute Date: Mon, 8 Nov 2021 21:52:11 +0900 Subject: [PATCH 0196/1472] Refactor `sp-sandbox`; make sure both sandbox executors are always tested (#10173) * sp-sandbox: convert executors into normal `mod`s instead of using `include!` * sp-sandbox: run `cargo fmt` on `host_executor.rs` * sp-sandbox: abstract away the executors behind traits * sp_sandbox: always compile both executors when possible * sc-executor: make sure all sandbox tests run on both sandbox executors * sc-executor: fix brainfart: actually call into the sandbox through the trait * sc-runtime-test: fix cargo fmt * sc-runtime-test: deduplicate executor-specific sandbox test entrypoints * sc-executor: test each sandbox executor in a separate test * cargo fmt (Github's conflict resolving thingy broke indentation) --- Cargo.lock | 1 + client/executor/runtime-test/Cargo.toml | 1 + client/executor/runtime-test/src/lib.rs | 172 +++++++++++------- client/executor/src/integration_tests/mod.rs | 47 +++++ .../executor/src/integration_tests/sandbox.rs | 108 +++++++---- frame/contracts/src/benchmarking/code.rs | 5 +- frame/contracts/src/benchmarking/sandbox.rs | 5 +- frame/contracts/src/wasm/mod.rs | 9 +- frame/contracts/src/wasm/runtime.rs | 9 +- .../sandbox/{ => src}/embedded_executor.rs | 40 ++-- primitives/sandbox/{ => src}/host_executor.rs | 91 +++++---- primitives/sandbox/src/lib.rs | 89 ++++----- 12 files changed, 350 insertions(+), 227 deletions(-) rename primitives/sandbox/{ => src}/embedded_executor.rs (90%) rename primitives/sandbox/{ => src}/host_executor.rs (78%) diff --git a/Cargo.lock b/Cargo.lock index 4794c1c0f5c41..4b6cc99426b1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8429,6 +8429,7 @@ dependencies = [ name = "sc-runtime-test" version = "2.0.0" dependencies = [ + "paste 1.0.4", "sp-core", "sp-io", "sp-runtime", diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index 1e3b5e926b964..2c82a9705ceeb 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -19,6 +19,7 @@ sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../.. sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } +paste = "1.0.4" [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 2b5699fa3f77a..3ea6e2d7ed1aa 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -30,7 +30,7 @@ use sp_runtime::{ traits::{BlakeTwo256, Hash}, }; #[cfg(not(feature = "std"))] -use sp_sandbox::Value; +use sp_sandbox::{SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory, Value}; extern "C" { #[allow(dead_code)] @@ -183,61 +183,6 @@ sp_core::wasm_export_functions! { ).as_ref().to_vec() } - fn test_sandbox(code: Vec) -> bool { - execute_sandboxed(&code, &[]).is_ok() - } - - fn test_sandbox_args(code: Vec) -> bool { - execute_sandboxed( - &code, - &[ - Value::I32(0x12345678), - Value::I64(0x1234567887654321), - ], - ).is_ok() - } - - fn test_sandbox_return_val(code: Vec) -> bool { - let ok = match execute_sandboxed( - &code, - &[ - Value::I32(0x1336), - ] - ) { - Ok(sp_sandbox::ReturnValue::Value(Value::I32(0x1337))) => true, - _ => false, - }; - - ok - } - - fn test_sandbox_instantiate(code: Vec) -> u8 { - let env_builder = sp_sandbox::EnvironmentDefinitionBuilder::new(); - let code = match sp_sandbox::Instance::new(&code, &env_builder, &mut ()) { - Ok(_) => 0, - Err(sp_sandbox::Error::Module) => 1, - Err(sp_sandbox::Error::Execution) => 2, - Err(sp_sandbox::Error::OutOfBounds) => 3, - }; - - code - } - - fn test_sandbox_get_global_val(code: Vec) -> i64 { - let env_builder = sp_sandbox::EnvironmentDefinitionBuilder::new(); - let instance = if let Ok(i) = sp_sandbox::Instance::new(&code, &env_builder, &mut ()) { - i - } else { - return 20; - }; - - match instance.get_global_val("test_global") { - Some(sp_sandbox::Value::I64(val)) => val, - None => 30, - _ => 40, - } - } - fn test_offchain_index_set() { sp_io::offchain_index::set(b"k", b"v"); } @@ -408,15 +353,112 @@ mod tasks { } } +/// A macro to define a test entrypoint for each available sandbox executor. +macro_rules! wasm_export_sandbox_test_functions { + ( + $( + fn $name:ident( + $( $arg_name:ident: $arg_ty:ty ),* $(,)? + ) $( -> $ret_ty:ty )? where T: SandboxInstance<$state:ty> $(,)? + { $( $fn_impl:tt )* } + )* + ) => { + $( + #[cfg(not(feature = "std"))] + fn $name( $($arg_name: $arg_ty),* ) $( -> $ret_ty )? where T: SandboxInstance<$state> { + $( $fn_impl )* + } + + paste::paste! { + sp_core::wasm_export_functions! { + fn [<$name _host>]( $($arg_name: $arg_ty),* ) $( -> $ret_ty )? { + $name::>( $( $arg_name ),* ) + } + + fn [<$name _embedded>]( $($arg_name: $arg_ty),* ) $( -> $ret_ty )? { + $name::>( $( $arg_name ),* ) + } + } + } + )* + }; +} + +wasm_export_sandbox_test_functions! { + fn test_sandbox(code: Vec) -> bool + where + T: SandboxInstance, + { + execute_sandboxed::(&code, &[]).is_ok() + } + + fn test_sandbox_args(code: Vec) -> bool + where + T: SandboxInstance, + { + execute_sandboxed::(&code, &[Value::I32(0x12345678), Value::I64(0x1234567887654321)]) + .is_ok() + } + + fn test_sandbox_return_val(code: Vec) -> bool + where + T: SandboxInstance, + { + let ok = match execute_sandboxed::(&code, &[Value::I32(0x1336)]) { + Ok(sp_sandbox::ReturnValue::Value(Value::I32(0x1337))) => true, + _ => false, + }; + + ok + } + + fn test_sandbox_instantiate(code: Vec) -> u8 + where + T: SandboxInstance<()>, + { + let env_builder = T::EnvironmentBuilder::new(); + let code = match T::new(&code, &env_builder, &mut ()) { + Ok(_) => 0, + Err(sp_sandbox::Error::Module) => 1, + Err(sp_sandbox::Error::Execution) => 2, + Err(sp_sandbox::Error::OutOfBounds) => 3, + }; + + code + } + + fn test_sandbox_get_global_val(code: Vec) -> i64 + where + T: SandboxInstance<()>, + { + let env_builder = T::EnvironmentBuilder::new(); + let instance = if let Ok(i) = T::new(&code, &env_builder, &mut ()) { + i + } else { + return 20 + }; + + match instance.get_global_val("test_global") { + Some(sp_sandbox::Value::I64(val)) => val, + None => 30, + _ => 40, + } + } +} + #[cfg(not(feature = "std"))] -fn execute_sandboxed( +struct State { + counter: u32, +} + +#[cfg(not(feature = "std"))] +fn execute_sandboxed( code: &[u8], args: &[Value], -) -> Result { - struct State { - counter: u32, - } - +) -> Result +where + T: sp_sandbox::SandboxInstance, +{ fn env_assert( _e: &mut State, args: &[Value], @@ -446,10 +488,10 @@ fn execute_sandboxed( let mut state = State { counter: 0 }; let env_builder = { - let mut env_builder = sp_sandbox::EnvironmentDefinitionBuilder::new(); + let mut env_builder = T::EnvironmentBuilder::new(); env_builder.add_host_func("env", "assert", env_assert); env_builder.add_host_func("env", "inc_counter", env_inc_counter); - let memory = match sp_sandbox::Memory::new(1, Some(16)) { + let memory = match T::Memory::new(1, Some(16)) { Ok(m) => m, Err(_) => unreachable!( " @@ -462,7 +504,7 @@ fn execute_sandboxed( env_builder }; - let mut instance = sp_sandbox::Instance::new(code, &env_builder, &mut state)?; + let mut instance = T::new(code, &env_builder, &mut state)?; let result = instance.invoke("call", args, &mut state); result.map_err(|_| sp_sandbox::HostError) diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index fe964f47ba374..1cded769c6856 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -71,6 +71,53 @@ macro_rules! test_wasm_execution { }; } +/// A macro to run a given test for each available WASM execution method *and* for each +/// sandbox execution method. +#[macro_export] +macro_rules! test_wasm_execution_sandbox { + ($method_name:ident) => { + paste::item! { + #[test] + fn [<$method_name _interpreted_host_executor>]() { + $method_name(WasmExecutionMethod::Interpreted, "_host"); + } + + #[test] + fn [<$method_name _interpreted_embedded_executor>]() { + $method_name(WasmExecutionMethod::Interpreted, "_embedded"); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_host_executor>]() { + $method_name(WasmExecutionMethod::Compiled, "_host"); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_embedded_executor>]() { + $method_name(WasmExecutionMethod::Compiled, "_embedded"); + } + } + }; + + (interpreted_only $method_name:ident) => { + paste::item! { + #[test] + fn [<$method_name _interpreted_host_executor>]() { + $method_name(WasmExecutionMethod::Interpreted, "_host"); + } + } + + paste::item! { + #[test] + fn [<$method_name _interpreted_embedded_executor>]() { + $method_name(WasmExecutionMethod::Interpreted, "_embedded"); + } + } + }; +} + fn call_in_wasm( function: &str, call_data: &[u8], diff --git a/client/executor/src/integration_tests/sandbox.rs b/client/executor/src/integration_tests/sandbox.rs index aacd493297cc8..2b536f541f088 100644 --- a/client/executor/src/integration_tests/sandbox.rs +++ b/client/executor/src/integration_tests/sandbox.rs @@ -17,12 +17,12 @@ // along with this program. If not, see . use super::{call_in_wasm, TestExternalities}; -use crate::{test_wasm_execution, WasmExecutionMethod}; +use crate::{test_wasm_execution_sandbox, WasmExecutionMethod}; use codec::Encode; -test_wasm_execution!(sandbox_should_work); -fn sandbox_should_work(wasm_method: WasmExecutionMethod) { +test_wasm_execution_sandbox!(sandbox_should_work); +fn sandbox_should_work(wasm_method: WasmExecutionMethod, fn_suffix: &str) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -51,11 +51,14 @@ fn sandbox_should_work(wasm_method: WasmExecutionMethod) { .unwrap() .encode(); - assert_eq!(call_in_wasm("test_sandbox", &code, wasm_method, &mut ext).unwrap(), true.encode()); + assert_eq!( + call_in_wasm(&format!("test_sandbox{}", fn_suffix), &code, wasm_method, &mut ext).unwrap(), + true.encode() + ); } -test_wasm_execution!(sandbox_trap); -fn sandbox_trap(wasm_method: WasmExecutionMethod) { +test_wasm_execution_sandbox!(sandbox_trap); +fn sandbox_trap(wasm_method: WasmExecutionMethod, fn_suffix: &str) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -72,11 +75,14 @@ fn sandbox_trap(wasm_method: WasmExecutionMethod) { ) .unwrap(); - assert_eq!(call_in_wasm("test_sandbox", &code, wasm_method, &mut ext).unwrap(), vec![0]); + assert_eq!( + call_in_wasm(&format!("test_sandbox{}", fn_suffix), &code, wasm_method, &mut ext).unwrap(), + vec![0] + ); } -test_wasm_execution!(start_called); -fn start_called(wasm_method: WasmExecutionMethod) { +test_wasm_execution_sandbox!(start_called); +fn start_called(wasm_method: WasmExecutionMethod, fn_suffix: &str) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -111,11 +117,14 @@ fn start_called(wasm_method: WasmExecutionMethod) { .unwrap() .encode(); - assert_eq!(call_in_wasm("test_sandbox", &code, wasm_method, &mut ext).unwrap(), true.encode()); + assert_eq!( + call_in_wasm(&format!("test_sandbox{}", fn_suffix), &code, wasm_method, &mut ext).unwrap(), + true.encode() + ); } -test_wasm_execution!(invoke_args); -fn invoke_args(wasm_method: WasmExecutionMethod) { +test_wasm_execution_sandbox!(invoke_args); +fn invoke_args(wasm_method: WasmExecutionMethod, fn_suffix: &str) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -147,13 +156,14 @@ fn invoke_args(wasm_method: WasmExecutionMethod) { .encode(); assert_eq!( - call_in_wasm("test_sandbox_args", &code, wasm_method, &mut ext,).unwrap(), + call_in_wasm(&format!("test_sandbox_args{}", fn_suffix), &code, wasm_method, &mut ext,) + .unwrap(), true.encode(), ); } -test_wasm_execution!(return_val); -fn return_val(wasm_method: WasmExecutionMethod) { +test_wasm_execution_sandbox!(return_val); +fn return_val(wasm_method: WasmExecutionMethod, fn_suffix: &str) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -173,13 +183,19 @@ fn return_val(wasm_method: WasmExecutionMethod) { .encode(); assert_eq!( - call_in_wasm("test_sandbox_return_val", &code, wasm_method, &mut ext,).unwrap(), + call_in_wasm( + &format!("test_sandbox_return_val{}", fn_suffix), + &code, + wasm_method, + &mut ext, + ) + .unwrap(), true.encode(), ); } -test_wasm_execution!(unlinkable_module); -fn unlinkable_module(wasm_method: WasmExecutionMethod) { +test_wasm_execution_sandbox!(unlinkable_module); +fn unlinkable_module(wasm_method: WasmExecutionMethod, fn_suffix: &str) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -197,13 +213,19 @@ fn unlinkable_module(wasm_method: WasmExecutionMethod) { .encode(); assert_eq!( - call_in_wasm("test_sandbox_instantiate", &code, wasm_method, &mut ext,).unwrap(), + call_in_wasm( + &format!("test_sandbox_instantiate{}", fn_suffix), + &code, + wasm_method, + &mut ext, + ) + .unwrap(), 1u8.encode(), ); } -test_wasm_execution!(corrupted_module); -fn corrupted_module(wasm_method: WasmExecutionMethod) { +test_wasm_execution_sandbox!(corrupted_module); +fn corrupted_module(wasm_method: WasmExecutionMethod, fn_suffix: &str) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -211,13 +233,19 @@ fn corrupted_module(wasm_method: WasmExecutionMethod) { let code = vec![0u8, 0, 0, 0, 1, 0, 0, 0].encode(); assert_eq!( - call_in_wasm("test_sandbox_instantiate", &code, wasm_method, &mut ext,).unwrap(), + call_in_wasm( + &format!("test_sandbox_instantiate{}", fn_suffix), + &code, + wasm_method, + &mut ext, + ) + .unwrap(), 1u8.encode(), ); } -test_wasm_execution!(start_fn_ok); -fn start_fn_ok(wasm_method: WasmExecutionMethod) { +test_wasm_execution_sandbox!(start_fn_ok); +fn start_fn_ok(wasm_method: WasmExecutionMethod, fn_suffix: &str) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -238,13 +266,19 @@ fn start_fn_ok(wasm_method: WasmExecutionMethod) { .encode(); assert_eq!( - call_in_wasm("test_sandbox_instantiate", &code, wasm_method, &mut ext,).unwrap(), + call_in_wasm( + &format!("test_sandbox_instantiate{}", fn_suffix), + &code, + wasm_method, + &mut ext, + ) + .unwrap(), 0u8.encode(), ); } -test_wasm_execution!(start_fn_traps); -fn start_fn_traps(wasm_method: WasmExecutionMethod) { +test_wasm_execution_sandbox!(start_fn_traps); +fn start_fn_traps(wasm_method: WasmExecutionMethod, fn_suffix: &str) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -266,13 +300,19 @@ fn start_fn_traps(wasm_method: WasmExecutionMethod) { .encode(); assert_eq!( - call_in_wasm("test_sandbox_instantiate", &code, wasm_method, &mut ext,).unwrap(), + call_in_wasm( + &format!("test_sandbox_instantiate{}", fn_suffix), + &code, + wasm_method, + &mut ext, + ) + .unwrap(), 2u8.encode(), ); } -test_wasm_execution!(get_global_val_works); -fn get_global_val_works(wasm_method: WasmExecutionMethod) { +test_wasm_execution_sandbox!(get_global_val_works); +fn get_global_val_works(wasm_method: WasmExecutionMethod, fn_suffix: &str) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -287,7 +327,13 @@ fn get_global_val_works(wasm_method: WasmExecutionMethod) { .encode(); assert_eq!( - call_in_wasm("test_sandbox_get_global_val", &code, wasm_method, &mut ext,).unwrap(), + call_in_wasm( + &format!("test_sandbox_get_global_val{}", fn_suffix), + &code, + wasm_method, + &mut ext, + ) + .unwrap(), 500i64.encode(), ); } diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 6b90381e7d353..98f52f4719a61 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -35,7 +35,10 @@ use pwasm_utils::parity_wasm::{ }; use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::Hash; -use sp_sandbox::{EnvironmentDefinitionBuilder, Memory}; +use sp_sandbox::{ + default_executor::{EnvironmentDefinitionBuilder, Memory}, + SandboxEnvironmentBuilder, SandboxMemory, +}; use sp_std::{borrow::ToOwned, prelude::*}; /// Pass to `create_code` in order to create a compiled `WasmModule`. diff --git a/frame/contracts/src/benchmarking/sandbox.rs b/frame/contracts/src/benchmarking/sandbox.rs index 320ac90cce64e..4412542b547df 100644 --- a/frame/contracts/src/benchmarking/sandbox.rs +++ b/frame/contracts/src/benchmarking/sandbox.rs @@ -20,7 +20,10 @@ /// ! environment that provides the seal interface as imported functions. use super::{code::WasmModule, Config}; use sp_core::crypto::UncheckedFrom; -use sp_sandbox::{EnvironmentDefinitionBuilder, Instance, Memory}; +use sp_sandbox::{ + default_executor::{EnvironmentDefinitionBuilder, Instance, Memory}, + SandboxEnvironmentBuilder, SandboxInstance, +}; /// Minimal execution environment without any exported functions. pub struct Sandbox { diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 565a424323ac6..10aa0d19a04f7 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -36,6 +36,7 @@ use crate::{ use codec::{Decode, Encode}; use frame_support::dispatch::DispatchError; use sp_core::crypto::UncheckedFrom; +use sp_sandbox::{SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory}; use sp_std::prelude::*; #[cfg(test)] pub use tests::MockExt; @@ -182,8 +183,8 @@ where function: &ExportedFunction, input_data: Vec, ) -> ExecResult { - let memory = - sp_sandbox::Memory::new(self.initial, Some(self.maximum)).unwrap_or_else(|_| { + let memory = sp_sandbox::default_executor::Memory::new(self.initial, Some(self.maximum)) + .unwrap_or_else(|_| { // unlike `.expect`, explicit panic preserves the source location. // Needed as we can't use `RUST_BACKTRACE` in here. panic!( @@ -193,7 +194,7 @@ where ) }); - let mut imports = sp_sandbox::EnvironmentDefinitionBuilder::new(); + let mut imports = sp_sandbox::default_executor::EnvironmentDefinitionBuilder::new(); imports.add_memory(self::prepare::IMPORT_MODULE_MEMORY, "memory", memory.clone()); runtime::Env::impls(&mut |module, name, func_ptr| { imports.add_host_func(module, name, func_ptr); @@ -209,7 +210,7 @@ where // Instantiate the instance from the instrumented module code and invoke the contract // entrypoint. - let result = sp_sandbox::Instance::new(&code, &imports, &mut runtime) + let result = sp_sandbox::default_executor::Instance::new(&code, &imports, &mut runtime) .and_then(|mut instance| instance.invoke(function.identifier(), &[], &mut runtime)); runtime.to_execution_result(result) diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 52b864bf18eac..883dfd0802483 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -32,6 +32,7 @@ use pwasm_utils::parity_wasm::elements::ValueType; use sp_core::{crypto::UncheckedFrom, Bytes}; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; use sp_runtime::traits::Bounded; +use sp_sandbox::SandboxMemory; use sp_std::prelude::*; /// Every error that can be returned to a contract when it calls any of the host functions. @@ -357,7 +358,7 @@ fn already_charged(_: u32) -> Option { pub struct Runtime<'a, E: Ext + 'a> { ext: &'a mut E, input_data: Option>, - memory: sp_sandbox::Memory, + memory: sp_sandbox::default_executor::Memory, trap_reason: Option, } @@ -367,7 +368,11 @@ where ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { - pub fn new(ext: &'a mut E, input_data: Vec, memory: sp_sandbox::Memory) -> Self { + pub fn new( + ext: &'a mut E, + input_data: Vec, + memory: sp_sandbox::default_executor::Memory, + ) -> Self { Runtime { ext, input_data: Some(input_data), memory, trap_reason: None } } diff --git a/primitives/sandbox/embedded_executor.rs b/primitives/sandbox/src/embedded_executor.rs similarity index 90% rename from primitives/sandbox/embedded_executor.rs rename to primitives/sandbox/src/embedded_executor.rs index 678da3c3aeaf5..c521ff2cb63fb 100755 --- a/primitives/sandbox/embedded_executor.rs +++ b/primitives/sandbox/src/embedded_executor.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! An embedded WASM executor utilizing `wasmi`. + use super::{Error, HostError, HostFuncType, ReturnValue, Value, TARGET}; use alloc::string::String; use log::debug; @@ -27,13 +29,14 @@ use wasmi::{ RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableRef, Trap, TrapKind, }; +/// The linear memory used by the sandbox. #[derive(Clone)] pub struct Memory { memref: MemoryRef, } -impl Memory { - pub fn new(initial: u32, maximum: Option) -> Result { +impl super::SandboxMemory for Memory { + fn new(initial: u32, maximum: Option) -> Result { Ok(Memory { memref: MemoryInstance::alloc( Pages(initial as usize), @@ -43,12 +46,12 @@ impl Memory { }) } - pub fn get(&self, ptr: u32, buf: &mut [u8]) -> Result<(), Error> { + fn get(&self, ptr: u32, buf: &mut [u8]) -> Result<(), Error> { self.memref.get_into(ptr, buf).map_err(|_| Error::OutOfBounds)?; Ok(()) } - pub fn set(&self, ptr: u32, value: &[u8]) -> Result<(), Error> { + fn set(&self, ptr: u32, value: &[u8]) -> Result<(), Error> { self.memref.set(ptr, value).map_err(|_| Error::OutOfBounds)?; Ok(()) } @@ -118,20 +121,21 @@ enum ExternVal { Memory(Memory), } +/// A builder for the environment of the sandboxed WASM module. pub struct EnvironmentDefinitionBuilder { map: BTreeMap<(Vec, Vec), ExternVal>, defined_host_functions: DefinedHostFunctions, } -impl EnvironmentDefinitionBuilder { - pub fn new() -> EnvironmentDefinitionBuilder { +impl super::SandboxEnvironmentBuilder for EnvironmentDefinitionBuilder { + fn new() -> EnvironmentDefinitionBuilder { EnvironmentDefinitionBuilder { map: BTreeMap::new(), defined_host_functions: DefinedHostFunctions::new(), } } - pub fn add_host_func(&mut self, module: N1, field: N2, f: HostFuncType) + fn add_host_func(&mut self, module: N1, field: N2, f: HostFuncType) where N1: Into>, N2: Into>, @@ -140,7 +144,7 @@ impl EnvironmentDefinitionBuilder { self.map.insert((module.into(), field.into()), ExternVal::HostFunc(idx)); } - pub fn add_memory(&mut self, module: N1, field: N2, mem: Memory) + fn add_memory(&mut self, module: N1, field: N2, mem: Memory) where N1: Into>, N2: Into>, @@ -213,14 +217,18 @@ impl ImportResolver for EnvironmentDefinitionBuilder { } } +/// Sandboxed instance of a WASM module. pub struct Instance { instance: ModuleRef, defined_host_functions: DefinedHostFunctions, _marker: PhantomData, } -impl Instance { - pub fn new( +impl super::SandboxInstance for Instance { + type Memory = Memory; + type EnvironmentBuilder = EnvironmentDefinitionBuilder; + + fn new( code: &[u8], env_def_builder: &EnvironmentDefinitionBuilder, state: &mut T, @@ -241,12 +249,7 @@ impl Instance { Ok(Instance { instance, defined_host_functions, _marker: PhantomData:: }) } - pub fn invoke( - &mut self, - name: &str, - args: &[Value], - state: &mut T, - ) -> Result { + fn invoke(&mut self, name: &str, args: &[Value], state: &mut T) -> Result { let args = args.iter().cloned().map(to_wasmi).collect::>(); let mut externals = @@ -260,7 +263,7 @@ impl Instance { } } - pub fn get_global_val(&self, name: &str) -> Option { + fn get_global_val(&self, name: &str) -> Option { let global = self.instance.export_by_name(name)?.as_global()?.get(); Some(to_interface(global)) @@ -289,7 +292,8 @@ fn to_interface(value: RuntimeValue) -> Value { #[cfg(test)] mod tests { - use crate::{EnvironmentDefinitionBuilder, Error, HostError, Instance, ReturnValue, Value}; + use super::{EnvironmentDefinitionBuilder, Instance}; + use crate::{Error, HostError, ReturnValue, SandboxEnvironmentBuilder, SandboxInstance, Value}; use assert_matches::assert_matches; fn execute_sandboxed(code: &[u8], args: &[Value]) -> Result { diff --git a/primitives/sandbox/host_executor.rs b/primitives/sandbox/src/host_executor.rs similarity index 78% rename from primitives/sandbox/host_executor.rs rename to primitives/sandbox/src/host_executor.rs index d2836e2ffd1eb..43484dd66a00d 100755 --- a/primitives/sandbox/host_executor.rs +++ b/primitives/sandbox/src/host_executor.rs @@ -15,15 +15,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! A WASM executor utilizing the sandbox runtime interface of the host. + +use super::{Error, HostFuncType, ReturnValue, Value}; use codec::{Decode, Encode}; use sp_core::sandbox as sandbox_primitives; use sp_io::sandbox; -use sp_std::{prelude::*, slice, marker, mem, vec, rc::Rc}; -use super::{Error, Value, ReturnValue, HostFuncType}; +use sp_std::{marker, mem, prelude::*, rc::Rc, slice, vec}; mod ffi { - use sp_std::mem; use super::HostFuncType; + use sp_std::mem; /// Index into the default table that points to a `HostFuncType`. pub type HostFuncIndex = usize; @@ -38,8 +40,9 @@ mod ffi { pub unsafe fn coerce_host_index_to_func(idx: HostFuncIndex) -> HostFuncType { // We need to ensure that sizes of a callable function pointer and host function index is // indeed equal. - // We can't use `static_assertions` create because it makes compiler panic, fallback to runtime assert. - // const_assert!(mem::size_of::() == mem::size_of::>()); + // We can't use `static_assertions` create because it makes compiler panic, fallback to + // runtime assert. const_assert!(mem::size_of::() == + // mem::size_of::>()); assert!(mem::size_of::() == mem::size_of::>()); mem::transmute::>(idx) } @@ -55,6 +58,7 @@ impl Drop for MemoryHandle { } } +/// The linear memory used by the sandbox. #[derive(Clone)] pub struct Memory { // Handle to memory instance is wrapped to add reference-counting semantics @@ -62,29 +66,20 @@ pub struct Memory { handle: Rc, } -impl Memory { - pub fn new(initial: u32, maximum: Option) -> Result { - let maximum = if let Some(maximum) = maximum { - maximum - } else { - sandbox_primitives::MEM_UNLIMITED - }; +impl super::SandboxMemory for Memory { + fn new(initial: u32, maximum: Option) -> Result { + let maximum = + if let Some(maximum) = maximum { maximum } else { sandbox_primitives::MEM_UNLIMITED }; match sandbox::memory_new(initial, maximum) { sandbox_primitives::ERR_MODULE => Err(Error::Module), - memory_idx => Ok(Memory { - handle: Rc::new(MemoryHandle { memory_idx, }), - }), + memory_idx => Ok(Memory { handle: Rc::new(MemoryHandle { memory_idx }) }), } } - pub fn get(&self, offset: u32, buf: &mut [u8]) -> Result<(), Error> { - let result = sandbox::memory_get( - self.handle.memory_idx, - offset, - buf.as_mut_ptr(), - buf.len() as u32, - ); + fn get(&self, offset: u32, buf: &mut [u8]) -> Result<(), Error> { + let result = + sandbox::memory_get(self.handle.memory_idx, offset, buf.as_mut_ptr(), buf.len() as u32); match result { sandbox_primitives::ERR_OK => Ok(()), sandbox_primitives::ERR_OUT_OF_BOUNDS => Err(Error::OutOfBounds), @@ -92,11 +87,11 @@ impl Memory { } } - pub fn set(&self, offset: u32, val: &[u8]) -> Result<(), Error> { + fn set(&self, offset: u32, val: &[u8]) -> Result<(), Error> { let result = sandbox::memory_set( self.handle.memory_idx, offset, - val.as_ptr() as _ , + val.as_ptr() as _, val.len() as u32, ); match result { @@ -107,6 +102,7 @@ impl Memory { } } +/// A builder for the environment of the sandboxed WASM module. pub struct EnvironmentDefinitionBuilder { env_def: sandbox_primitives::EnvironmentDefinition, retained_memories: Vec, @@ -114,16 +110,6 @@ pub struct EnvironmentDefinitionBuilder { } impl EnvironmentDefinitionBuilder { - pub fn new() -> EnvironmentDefinitionBuilder { - EnvironmentDefinitionBuilder { - env_def: sandbox_primitives::EnvironmentDefinition { - entries: Vec::new(), - }, - retained_memories: Vec::new(), - _marker: marker::PhantomData::, - } - } - fn add_entry( &mut self, module: N1, @@ -140,8 +126,18 @@ impl EnvironmentDefinitionBuilder { }; self.env_def.entries.push(entry); } +} - pub fn add_host_func(&mut self, module: N1, field: N2, f: HostFuncType) +impl super::SandboxEnvironmentBuilder for EnvironmentDefinitionBuilder { + fn new() -> EnvironmentDefinitionBuilder { + EnvironmentDefinitionBuilder { + env_def: sandbox_primitives::EnvironmentDefinition { entries: Vec::new() }, + retained_memories: Vec::new(), + _marker: marker::PhantomData::, + } + } + + fn add_host_func(&mut self, module: N1, field: N2, f: HostFuncType) where N1: Into>, N2: Into>, @@ -150,7 +146,7 @@ impl EnvironmentDefinitionBuilder { self.add_entry(module, field, f); } - pub fn add_memory(&mut self, module: N1, field: N2, mem: Memory) + fn add_memory(&mut self, module: N1, field: N2, mem: Memory) where N1: Into>, N2: Into>, @@ -163,6 +159,7 @@ impl EnvironmentDefinitionBuilder { } } +/// Sandboxed instance of a WASM module. pub struct Instance { instance_idx: u32, _retained_memories: Vec, @@ -211,8 +208,11 @@ extern "C" fn dispatch_thunk( } } -impl Instance { - pub fn new( +impl super::SandboxInstance for Instance { + type Memory = Memory; + type EnvironmentBuilder = EnvironmentDefinitionBuilder; + + fn new( code: &[u8], env_def_builder: &EnvironmentDefinitionBuilder, state: &mut T, @@ -242,12 +242,7 @@ impl Instance { }) } - pub fn invoke( - &mut self, - name: &str, - args: &[Value], - state: &mut T, - ) -> Result { + fn invoke(&mut self, name: &str, args: &[Value], state: &mut T) -> Result { let serialized_args = args.to_vec().encode(); let mut return_val = vec![0u8; ReturnValue::ENCODED_MAX_SIZE]; @@ -262,16 +257,16 @@ impl Instance { match result { sandbox_primitives::ERR_OK => { - let return_val = ReturnValue::decode(&mut &return_val[..]) - .map_err(|_| Error::Execution)?; + let return_val = + ReturnValue::decode(&mut &return_val[..]).map_err(|_| Error::Execution)?; Ok(return_val) - } + }, sandbox_primitives::ERR_EXECUTION => Err(Error::Execution), _ => unreachable!(), } } - pub fn get_global_val(&self, name: &str) -> Option { + fn get_global_val(&self, name: &str) -> Option { sandbox::get_global_val(self.instance_idx, name) } } diff --git a/primitives/sandbox/src/lib.rs b/primitives/sandbox/src/lib.rs index 1724b4152ff3d..f1a24732b7a0a 100755 --- a/primitives/sandbox/src/lib.rs +++ b/primitives/sandbox/src/lib.rs @@ -48,13 +48,15 @@ pub use sp_wasm_interface::{ReturnValue, Value}; /// The target used for logging. const TARGET: &str = "runtime::sandbox"; -mod imp { - #[cfg(all(feature = "wasmer-sandbox", not(feature = "std")))] - include!("../host_executor.rs"); +pub mod embedded_executor; +#[cfg(not(feature = "std"))] +pub mod host_executor; - #[cfg(not(all(feature = "wasmer-sandbox", not(feature = "std"))))] - include!("../embedded_executor.rs"); -} +#[cfg(all(feature = "wasmer-sandbox", not(feature = "std")))] +pub use host_executor as default_executor; + +#[cfg(not(all(feature = "wasmer-sandbox", not(feature = "std"))))] +pub use embedded_executor as default_executor; /// Error that can occur while using this crate. #[derive(sp_core::RuntimeDebug)] @@ -88,12 +90,7 @@ pub type HostFuncType = fn(&mut T, &[Value]) -> Result) -> Result { - Ok(Memory { inner: imp::Memory::new(initial, maximum)? }) - } + fn new(initial: u32, maximum: Option) -> Result; /// Read a memory area at the address `ptr` with the size of the provided slice `buf`. /// /// Returns `Err` if the range is out-of-bounds. - pub fn get(&self, ptr: u32, buf: &mut [u8]) -> Result<(), Error> { - self.inner.get(ptr, buf) - } + fn get(&self, ptr: u32, buf: &mut [u8]) -> Result<(), Error>; /// Write a memory area at the address `ptr` with contents of the provided slice `buf`. /// /// Returns `Err` if the range is out-of-bounds. - pub fn set(&self, ptr: u32, value: &[u8]) -> Result<(), Error> { - self.inner.set(ptr, value) - } + fn set(&self, ptr: u32, value: &[u8]) -> Result<(), Error>; } /// Struct that can be used for defining an environment for a sandboxed module. /// /// The sandboxed module can access only the entities which were defined and passed /// to the module at the instantiation time. -pub struct EnvironmentDefinitionBuilder { - inner: imp::EnvironmentDefinitionBuilder, -} - -impl EnvironmentDefinitionBuilder { +pub trait SandboxEnvironmentBuilder: Sized { /// Construct a new `EnvironmentDefinitionBuilder`. - pub fn new() -> EnvironmentDefinitionBuilder { - EnvironmentDefinitionBuilder { inner: imp::EnvironmentDefinitionBuilder::new() } - } + fn new() -> Self; /// Register a host function in this environment definition. /// @@ -143,32 +128,28 @@ impl EnvironmentDefinitionBuilder { /// can import function passed here with any signature it wants. It can even import /// the same function (i.e. with same `module` and `field`) several times. It's up to /// the user code to check or constrain the types of signatures. - pub fn add_host_func(&mut self, module: N1, field: N2, f: HostFuncType) + fn add_host_func(&mut self, module: N1, field: N2, f: HostFuncType) where N1: Into>, - N2: Into>, - { - self.inner.add_host_func(module, field, f); - } + N2: Into>; /// Register a memory in this environment definition. - pub fn add_memory(&mut self, module: N1, field: N2, mem: Memory) + fn add_memory(&mut self, module: N1, field: N2, mem: Memory) where N1: Into>, - N2: Into>, - { - self.inner.add_memory(module, field, mem.inner); - } + N2: Into>; } /// Sandboxed instance of a wasm module. /// /// This instance can be used for invoking exported functions. -pub struct Instance { - inner: imp::Instance, -} +pub trait SandboxInstance: Sized { + /// The memory type used for this sandbox. + type Memory: SandboxMemory; + + /// The environment builder used to construct this sandbox. + type EnvironmentBuilder: SandboxEnvironmentBuilder; -impl Instance { /// Instantiate a module with the given [`EnvironmentDefinitionBuilder`]. It will /// run the `start` function (if it is present in the module) with the given `state`. /// @@ -177,13 +158,11 @@ impl Instance { /// will be returned. /// /// [`EnvironmentDefinitionBuilder`]: struct.EnvironmentDefinitionBuilder.html - pub fn new( + fn new( code: &[u8], - env_def_builder: &EnvironmentDefinitionBuilder, - state: &mut T, - ) -> Result, Error> { - Ok(Instance { inner: imp::Instance::new(code, &env_def_builder.inner, state)? }) - } + env_def_builder: &Self::EnvironmentBuilder, + state: &mut State, + ) -> Result; /// Invoke an exported function with the given name. /// @@ -196,19 +175,15 @@ impl Instance { /// - If types of the arguments passed to the function doesn't match function signature then /// trap occurs (as if the exported function was called via call_indirect), /// - Trap occurred at the execution time. - pub fn invoke( + fn invoke( &mut self, name: &str, args: &[Value], - state: &mut T, - ) -> Result { - self.inner.invoke(name, args, state) - } + state: &mut State, + ) -> Result; /// Get the value from a global with the given `name`. /// /// Returns `Some(_)` if the global could be found. - pub fn get_global_val(&self, name: &str) -> Option { - self.inner.get_global_val(name) - } + fn get_global_val(&self, name: &str) -> Option; } From c6a9f648cfb432193c5df09e89ac06176c318971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 8 Nov 2021 22:03:37 +0100 Subject: [PATCH 0197/1472] Offchain-worker: Accessing time is not HTTP (#10220) Accessing time related functionality is clearly not related to HTTP. So, this pr introduces a `TIME` capability. --- primitives/core/src/offchain/mod.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index dfe23c1ff8f18..8058d4d05d6ad 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -262,21 +262,23 @@ bitflags::bitflags! { /// Execution context extra capabilities. pub struct Capabilities: u32 { /// Access to transaction pool. - const TRANSACTION_POOL = 0b0000_0001; + const TRANSACTION_POOL = 0b0000_0000_0001; /// External http calls. - const HTTP = 0b0000_0010; + const HTTP = 0b0000_0000_0010; /// Keystore access. - const KEYSTORE = 0b0000_0100; + const KEYSTORE = 0b0000_0000_0100; /// Randomness source. - const RANDOMNESS = 0b0000_1000; + const RANDOMNESS = 0b0000_0000_1000; /// Access to opaque network state. - const NETWORK_STATE = 0b0001_0000; + const NETWORK_STATE = 0b0000_0001_0000; /// Access to offchain worker DB (read only). - const OFFCHAIN_DB_READ = 0b0010_0000; + const OFFCHAIN_DB_READ = 0b0000_0010_0000; /// Access to offchain worker DB (writes). - const OFFCHAIN_DB_WRITE = 0b0100_0000; + const OFFCHAIN_DB_WRITE = 0b0000_0100_0000; /// Manage the authorized nodes - const NODE_AUTHORIZATION = 0b1000_0000; + const NODE_AUTHORIZATION = 0b0000_1000_0000; + /// Access time related functionality + const TIME = 0b0001_0000_0000; } } @@ -541,12 +543,12 @@ impl Externalities for LimitedExternalities { } fn timestamp(&mut self) -> Timestamp { - self.check(Capabilities::HTTP, "timestamp"); + self.check(Capabilities::TIME, "timestamp"); self.externalities.timestamp() } fn sleep_until(&mut self, deadline: Timestamp) { - self.check(Capabilities::HTTP, "sleep_until"); + self.check(Capabilities::TIME, "sleep_until"); self.externalities.sleep_until(deadline) } From 2a601506cd4c53c3c526c61745c8887116e491be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 8 Nov 2021 22:05:39 +0100 Subject: [PATCH 0198/1472] Fix polkadot companion label CI check (#10198) * Fix polkadot companion label CI check * Update .github/workflows/polkadot-companion-labels.yml --- .github/workflows/polkadot-companion-labels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/polkadot-companion-labels.yml b/.github/workflows/polkadot-companion-labels.yml index 3c3987b5f4d56..0a5af09358524 100644 --- a/.github/workflows/polkadot-companion-labels.yml +++ b/.github/workflows/polkadot-companion-labels.yml @@ -14,7 +14,7 @@ jobs: with: authToken: ${{ secrets.GITHUB_TOKEN }} ref: ${{ github.event.pull_request.head.sha }} - contexts: 'continuous-integration/gitlab-check-polkadot-companion-build' + contexts: 'continuous-integration/gitlab-check-dependent-polkadot' timeout: 1800 notPresentTimeout: 3600 # It can take quite a while before the job starts on Gitlab when the CI queue is large failureStates: failure From 60b51e3f0365799e5ae0d4f8a89c7b0126a5f905 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 8 Nov 2021 22:06:53 +0100 Subject: [PATCH 0199/1472] Remove the RPC client example (#10217) * Remove the RPC client example Might be slightly contentious but I think we want to migrate this example to `subxt` and redirect the community to use that for things like this. * Remove rpc-client example code from workspace --- Cargo.lock | 11 ------ Cargo.toml | 1 - bin/node/rpc-client/Cargo.toml | 20 ----------- bin/node/rpc-client/src/main.rs | 63 --------------------------------- 4 files changed, 95 deletions(-) delete mode 100644 bin/node/rpc-client/Cargo.toml delete mode 100644 bin/node/rpc-client/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 4b6cc99426b1c..ae8216ae3c722 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4657,17 +4657,6 @@ dependencies = [ "substrate-frame-rpc-system", ] -[[package]] -name = "node-rpc-client" -version = "2.0.0" -dependencies = [ - "futures 0.3.16", - "jsonrpc-core-client", - "node-primitives", - "sc-rpc", - "sp-tracing", -] - [[package]] name = "node-runtime" version = "3.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 32d10ca8978dd..07053a0ef3162 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ members = [ "bin/node/executor", "bin/node/primitives", "bin/node/rpc", - "bin/node/rpc-client", "bin/node/runtime", "bin/node/testing", "bin/utils/chain-spec-builder", diff --git a/bin/node/rpc-client/Cargo.toml b/bin/node/rpc-client/Cargo.toml deleted file mode 100644 index 5c822ef3ad31a..0000000000000 --- a/bin/node/rpc-client/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "node-rpc-client" -version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -futures = "0.3.16" -jsonrpc-core-client = { version = "18.0.0", default-features = false, features = [ - "http", -] } -node-primitives = { version = "2.0.0", path = "../primitives" } -sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } -sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } diff --git a/bin/node/rpc-client/src/main.rs b/bin/node/rpc-client/src/main.rs deleted file mode 100644 index 6d0b88799f54c..0000000000000 --- a/bin/node/rpc-client/src/main.rs +++ /dev/null @@ -1,63 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![warn(missing_docs)] - -//! Example substrate RPC client code. -//! -//! This module shows how you can write a Rust RPC client that connects to a running -//! substrate node and use statically typed RPC wrappers. - -use futures::{Future, TryFutureExt}; -use jsonrpc_core_client::{transports::http, RpcError}; -use node_primitives::Hash; -use sc_rpc::author::{hash::ExtrinsicOrHash, AuthorClient}; - -fn main() -> Result<(), RpcError> { - sp_tracing::try_init_simple(); - - futures::executor::block_on(async { - let uri = "http://localhost:9933"; - - http::connect(uri) - .and_then(|client: AuthorClient| remove_all_extrinsics(client)) - .await - }) -} - -/// Remove all pending extrinsics from the node. -/// -/// The example code takes `AuthorClient` and first: -/// 1. Calls the `pending_extrinsics` method to get all extrinsics in the pool. -/// 2. Then calls `remove_extrinsic` passing the obtained raw extrinsics. -/// -/// As the result of running the code the entire content of the transaction pool is going -/// to be removed and the extrinsics are going to be temporarily banned. -fn remove_all_extrinsics( - client: AuthorClient, -) -> impl Future> { - client - .pending_extrinsics() - .and_then(move |pending| { - client.remove_extrinsic( - pending.into_iter().map(|tx| ExtrinsicOrHash::Extrinsic(tx.into())).collect(), - ) - }) - .map_ok(|removed| { - println!("Removed extrinsics: {:?}", removed); - }) -} From fae2ac6a92656a0006da3aca4bf19e4a0545946f Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Tue, 9 Nov 2021 19:59:55 +0800 Subject: [PATCH 0200/1472] frame_support::pallet_prelude: Add scale_info::TypeInfo (#10221) Signed-off-by: koushiro --- frame/assets/src/lib.rs | 1 - frame/assets/src/types.rs | 8 ++++---- frame/gilt/src/lib.rs | 1 - frame/support/src/lib.rs | 1 + 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index dfc81eadeb530..b89d411e41db8 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -170,7 +170,6 @@ pub mod pallet { use super::*; use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; - use scale_info::TypeInfo; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index bc2edce848a64..879e9d5cdcb96 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -18,10 +18,10 @@ //! Various basic types for use in the assets pallet. use super::*; -use frame_support::pallet_prelude::*; -use scale_info::TypeInfo; - -use frame_support::traits::{fungible, tokens::BalanceConversion}; +use frame_support::{ + pallet_prelude::*, + traits::{fungible, tokens::BalanceConversion}, +}; use sp_runtime::{traits::Convert, FixedPointNumber, FixedPointOperand, FixedU128}; pub(super) type DepositBalanceOf = diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index 393b3acb41a36..1594601b457cb 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -82,7 +82,6 @@ pub mod pallet { traits::{Currency, OnUnbalanced, ReservableCurrency}, }; use frame_system::pallet_prelude::*; - use scale_info::TypeInfo; use sp_arithmetic::{PerThing, Perquintill}; use sp_runtime::traits::{Saturating, Zero}; use sp_std::prelude::*; diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 6e60988a4ca23..af9192f6ea836 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1330,6 +1330,7 @@ pub mod pallet_prelude { PartialEqNoBound, RuntimeDebug, RuntimeDebugNoBound, Twox128, Twox256, Twox64Concat, }; pub use codec::{Decode, Encode, MaxEncodedLen}; + pub use scale_info::TypeInfo; pub use sp_runtime::{ traits::{MaybeSerializeDeserialize, Member, ValidateUnsigned}, transaction_validity::{ From 5cb8a6d1e0b5a542667ce9220ec6c7cace76aeb8 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 9 Nov 2021 21:08:02 +0900 Subject: [PATCH 0201/1472] Bump `wasmtime` to 0.31.0 (#10149) * Bump `wasmtime` to 0.31.0 * Bump `itoa` to 0.4.8 * sc-executor-wasmtime: fix `SandboxContext::invoke` which I've broke * sc-executor-wasmtime: cargo fmt --- Cargo.lock | 209 ++++++++++++++++++--------- client/executor/wasmtime/Cargo.toml | 2 +- client/executor/wasmtime/src/host.rs | 19 +-- 3 files changed, 145 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae8216ae3c722..8170b096de9dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -848,9 +848,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.67" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" dependencies = [ "jobserver", ] @@ -1068,11 +1068,11 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15013642ddda44eebcf61365b2052a23fd8b7314f90ba44aa059ec02643c5139" +checksum = "cc0cb7df82c8cf8f2e6a8dd394a0932a71369c160cc9b027dca414fced242513" dependencies = [ - "cranelift-entity 0.77.0", + "cranelift-entity 0.78.0", ] [[package]] @@ -1088,7 +1088,7 @@ dependencies = [ "cranelift-entity 0.68.0", "gimli 0.22.0", "log 0.4.14", - "regalloc", + "regalloc 0.0.31", "smallvec 1.7.0", "target-lexicon 0.11.2", "thiserror", @@ -1096,17 +1096,17 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298f2a7ed5fdcb062d8e78b7496b0f4b95265d20245f2d0ca88f846dd192a3a3" +checksum = "fe4463c15fa42eee909e61e5eac4866b7c6d22d0d8c621e57a0c5380753bfa8c" dependencies = [ - "cranelift-bforest 0.77.0", - "cranelift-codegen-meta 0.77.0", - "cranelift-codegen-shared 0.77.0", - "cranelift-entity 0.77.0", + "cranelift-bforest 0.78.0", + "cranelift-codegen-meta 0.78.0", + "cranelift-codegen-shared 0.78.0", + "cranelift-entity 0.78.0", "gimli 0.25.0", "log 0.4.14", - "regalloc", + "regalloc 0.0.32", "smallvec 1.7.0", "target-lexicon 0.12.0", ] @@ -1123,12 +1123,12 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf504261ac62dfaf4ffb3f41d88fd885e81aba947c1241275043885bc5f0bac" +checksum = "793f6a94a053a55404ea16e1700202a88101672b8cd6b4df63e13cde950852bf" dependencies = [ - "cranelift-codegen-shared 0.77.0", - "cranelift-entity 0.77.0", + "cranelift-codegen-shared 0.78.0", + "cranelift-entity 0.78.0", ] [[package]] @@ -1139,9 +1139,9 @@ checksum = "6759012d6d19c4caec95793f052613e9d4113e925e7f14154defbac0f1d4c938" [[package]] name = "cranelift-codegen-shared" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd2a72db4301dbe7e5a4499035eedc1e82720009fb60603e20504d8691fa9cd" +checksum = "44aa1846df275bce5eb30379d65964c7afc63c05a117076e62a119c25fe174be" [[package]] name = "cranelift-entity" @@ -1154,9 +1154,9 @@ dependencies = [ [[package]] name = "cranelift-entity" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48868faa07cacf948dc4a1773648813c0e453ff9467e800ff10f6a78c021b546" +checksum = "a3a45d8d6318bf8fc518154d9298eab2a8154ec068a8885ff113f6db8d69bb3a" dependencies = [ "serde", ] @@ -1175,11 +1175,11 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "351c9d13b4ecd1a536215ec2fd1c3ee9ee8bc31af172abf1e45ed0adb7a931df" +checksum = "e07339bd461766deb7605169de039e01954768ff730fa1254e149001884a8525" dependencies = [ - "cranelift-codegen 0.77.0", + "cranelift-codegen 0.78.0", "log 0.4.14", "smallvec 1.7.0", "target-lexicon 0.12.0", @@ -1187,28 +1187,28 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df8b556663d7611b137b24db7f6c8d9a8a27d7f29c7ea7835795152c94c1b75" +checksum = "03e2fca76ff57e0532936a71e3fc267eae6a19a86656716479c66e7f912e3d7b" dependencies = [ - "cranelift-codegen 0.77.0", + "cranelift-codegen 0.78.0", "libc", "target-lexicon 0.12.0", ] [[package]] name = "cranelift-wasm" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a69816d90db694fa79aa39b89dda7208a4ac74b6f2b8f3c4da26ee1c8bdfc5e" +checksum = "1f46fec547a1f8a32c54ea61c28be4f4ad234ad95342b718a9a9adcaadb0c778" dependencies = [ - "cranelift-codegen 0.77.0", - "cranelift-entity 0.77.0", - "cranelift-frontend 0.77.0", + "cranelift-codegen 0.78.0", + "cranelift-entity 0.78.0", + "cranelift-frontend 0.78.0", "itertools", "log 0.4.14", "smallvec 1.7.0", - "wasmparser 0.80.2", + "wasmparser 0.81.0", "wasmtime-types", ] @@ -2928,6 +2928,16 @@ dependencies = [ "futures-timer 2.0.2", ] +[[package]] +name = "io-lifetimes" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47f5ce4afb9bf504b9f496a3307676bc232122f91a93c4da6d540aa99a0a0e0b" +dependencies = [ + "rustc_version 0.4.0", + "winapi 0.3.9", +] + [[package]] name = "iovec" version = "0.1.4" @@ -2972,9 +2982,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "jobserver" @@ -3935,6 +3945,12 @@ dependencies = [ "statrs", ] +[[package]] +name = "linux-raw-sys" +version = "0.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687387ff42ec7ea4f2149035a5675fedb675d26f98db90a1846ac63d3addb5f5" + [[package]] name = "lite-json" version = "0.1.3" @@ -4090,9 +4106,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memmap" @@ -4984,6 +5000,15 @@ name = "object" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c55827317fb4c08822499848a14237d2874d6f139828893017237e7ab93eb386" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" dependencies = [ "crc32fast", "indexmap", @@ -7281,6 +7306,17 @@ dependencies = [ "smallvec 1.7.0", ] +[[package]] +name = "regalloc" +version = "0.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6304468554ed921da3d32c355ea107b8d13d7b8996c3adfb7aab48d3bc321f4" +dependencies = [ + "log 0.4.14", + "rustc-hash", + "smallvec 1.7.0", +] + [[package]] name = "regex" version = "1.5.4" @@ -7399,6 +7435,23 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rsix" +version = "0.23.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f64c5788d5aab8b75441499d99576a24eb09f76fb267b36fec7e3d970c66431" +dependencies = [ + "bitflags", + "cc", + "errno", + "io-lifetimes", + "itoa", + "libc", + "linux-raw-sys", + "once_cell", + "rustc_version 0.4.0", +] + [[package]] name = "rustc-demangle" version = "0.1.18" @@ -7435,6 +7488,15 @@ dependencies = [ "semver 0.11.0", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.4", +] + [[package]] name = "rustls" version = "0.19.1" @@ -8816,6 +8878,12 @@ dependencies = [ "serde", ] +[[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + [[package]] name = "semver-parser" version = "0.7.0" @@ -11518,15 +11586,15 @@ checksum = "87cc2fe6350834b4e528ba0901e7aa405d78b89dc1fa3145359eb4de0e323fcf" [[package]] name = "wasmparser" -version = "0.80.2" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b" +checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc" [[package]] name = "wasmtime" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899b1e5261e3d3420860dacfb952871ace9d7ba9f953b314f67aaf9f8e2a4d89" +checksum = "311d06b0c49346d1fbf48a17052e844036b95a7753c1afb34e8c0af3f6b5bb13" dependencies = [ "anyhow", "backtrace", @@ -11537,7 +11605,7 @@ dependencies = [ "lazy_static", "libc", "log 0.4.14", - "object 0.26.0", + "object 0.27.1", "paste 1.0.4", "psm", "rayon", @@ -11545,7 +11613,7 @@ dependencies = [ "rustc-demangle", "serde", "target-lexicon 0.12.0", - "wasmparser 0.80.2", + "wasmparser 0.81.0", "wasmtime-cache", "wasmtime-cranelift", "wasmtime-environ", @@ -11556,18 +11624,17 @@ dependencies = [ [[package]] name = "wasmtime-cache" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2493b81d7a9935f7af15e06beec806f256bc974a90a843685f3d61f2fc97058" +checksum = "36147930a4995137dc096e5b17a573b446799be2bbaea433e821ce6a80abe2c5" dependencies = [ "anyhow", "base64 0.13.0", "bincode", "directories-next", - "errno", "file-per-thread-logger", - "libc", "log 0.4.14", + "rsix", "serde", "sha2 0.9.8", "toml", @@ -11577,66 +11644,67 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99706bacdf5143f7f967d417f0437cce83a724cf4518cb1a3ff40e519d793021" +checksum = "ab3083a47e1ede38aac06a1d9831640d673f9aeda0b82a64e4ce002f3432e2e7" dependencies = [ "anyhow", - "cranelift-codegen 0.77.0", - "cranelift-entity 0.77.0", - "cranelift-frontend 0.77.0", + "cranelift-codegen 0.78.0", + "cranelift-entity 0.78.0", + "cranelift-frontend 0.78.0", "cranelift-native", "cranelift-wasm", "gimli 0.25.0", + "log 0.4.14", "more-asserts", - "object 0.26.0", + "object 0.27.1", "target-lexicon 0.12.0", "thiserror", - "wasmparser 0.80.2", + "wasmparser 0.81.0", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac42cb562a2f98163857605f02581d719a410c5abe93606128c59a10e84de85b" +checksum = "1c2d194b655321053bc4111a1aa4ead552655c8a17d17264bc97766e70073510" dependencies = [ "anyhow", "cfg-if 1.0.0", - "cranelift-entity 0.77.0", + "cranelift-entity 0.78.0", "gimli 0.25.0", "indexmap", "log 0.4.14", "more-asserts", - "object 0.26.0", + "object 0.27.1", "serde", "target-lexicon 0.12.0", "thiserror", - "wasmparser 0.80.2", + "wasmparser 0.81.0", "wasmtime-types", ] [[package]] name = "wasmtime-jit" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f46dd757225f29a419be415ea6fb8558df9b0194f07e3a6a9c99d0e14dd534" +checksum = "864ac8dfe4ce310ac59f16fdbd560c257389cb009ee5d030ac6e30523b023d11" dependencies = [ "addr2line", "anyhow", "bincode", "cfg-if 1.0.0", "gimli 0.25.0", - "libc", "log 0.4.14", "more-asserts", - "object 0.26.0", + "object 0.27.1", "region", + "rsix", "serde", "target-lexicon 0.12.0", "thiserror", - "wasmparser 0.80.2", + "wasmparser 0.81.0", "wasmtime-environ", "wasmtime-runtime", "winapi 0.3.9", @@ -11644,9 +11712,9 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0122215a44923f395487048cb0a1d60b5b32c73aab15cf9364b798dbaff0996f" +checksum = "ab97da813a26b98c9abfd3b0c2d99e42f6b78b749c0646344e2e262d212d8c8b" dependencies = [ "anyhow", "backtrace", @@ -11661,6 +11729,7 @@ dependencies = [ "more-asserts", "rand 0.8.4", "region", + "rsix", "thiserror", "wasmtime-environ", "winapi 0.3.9", @@ -11668,14 +11737,14 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b01caf8a204ef634ebac99700e77ba716d3ebbb68a1abbc2ceb6b16dbec9e4" +checksum = "ff94409cc3557bfbbcce6b14520ccd6bd3727e965c0fe68d63ef2c185bf379c6" dependencies = [ - "cranelift-entity 0.77.0", + "cranelift-entity 0.78.0", "serde", "thiserror", - "wasmparser 0.80.2", + "wasmparser 0.81.0", ] [[package]] diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 741898b8282c2..e52a53f71c06e 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -23,7 +23,7 @@ sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-in sp-runtime-interface = { version = "4.0.0-dev", path = "../../../primitives/runtime-interface" } sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } sc-allocator = { version = "4.0.0-dev", path = "../../allocator" } -wasmtime = { version = "0.30.0", default-features = false, features = [ +wasmtime = { version = "0.31.0", default-features = false, features = [ "cache", "cranelift", "jitdump", diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index 4edb9f9c423f0..fcb4c4cae3b8a 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -333,6 +333,7 @@ impl<'a, 'b, 'c, 'd> sandbox::SandboxContext for SandboxContext<'a, 'b, 'c, 'd> state: u32, func_idx: SupervisorFuncIndex, ) -> Result { + let mut ret_vals = [Val::null()]; let result = self.dispatch_thunk.call( &mut self.host_context.caller, &[ @@ -341,26 +342,16 @@ impl<'a, 'b, 'c, 'd> sandbox::SandboxContext for SandboxContext<'a, 'b, 'c, 'd> Val::I32(state as i32), Val::I32(usize::from(func_idx) as i32), ], + &mut ret_vals, ); match result { - Ok(ret_vals) => { - let ret_val = if ret_vals.len() != 1 { - return Err(format!( - "Supervisor function returned {} results, expected 1", - ret_vals.len() - ) - .into()) - } else { - &ret_vals[0] - }; - - if let Some(ret_val) = ret_val.i64() { + Ok(()) => + if let Some(ret_val) = ret_vals[0].i64() { Ok(ret_val) } else { return Err("Supervisor function returned unexpected result!".into()) - } - }, + }, Err(err) => Err(err.to_string().into()), } } From 7adee13ddc48a9d715eb2f9caa37d99713fa0102 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 9 Nov 2021 13:08:34 +0100 Subject: [PATCH 0202/1472] Bump parity-db (#10218) * Bump parity-db * Update cargo.lock --- Cargo.lock | 4 ++-- client/db/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8170b096de9dc..8985b5fb89338 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6223,9 +6223,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ccc4a8687027deb53d45c5434a1f1b330c9d1069a59cfe80a62aa9a1da25ae" +checksum = "7cb5195cb862b13055cf7f7a76c55073dc73885c2a61511e322b8c1666be7332" dependencies = [ "blake2-rfc", "crc32fast", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 19bf7ad248fe5..437431a50883f 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -33,7 +33,7 @@ sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -parity-db = { version = "0.3.3", optional = true } +parity-db = { version = "0.3.4", optional = true } [dev-dependencies] sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } From 800fac14306a77c3dd7fa178c8d4a6a77d52d3bd Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 9 Nov 2021 22:38:31 +0900 Subject: [PATCH 0203/1472] Add a block production benchmark (#10104) * Add a block production benchmark * Simplify the block production benchmark * Cleanups; switch execution strategy to WASM * Switch WASM execution to `Compiled` * Reduce the setup cost of the benchmark Creating all of those extrinsics takes up *a lot* of time, up to the point where the majority of the time is actually spent *outside* of the code which we want to benchmark here. So let's only do it once. * Add a variant of the block production benchmark with proof recording --- Cargo.lock | 3 + bin/node/cli/Cargo.toml | 7 + bin/node/cli/benches/block_production.rs | 237 +++++++++++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 bin/node/cli/benches/block_production.rs diff --git a/Cargo.lock b/Cargo.lock index 8985b5fb89338..b164a74f94a55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4528,6 +4528,7 @@ dependencies = [ "node-runtime", "pallet-balances", "pallet-im-online", + "pallet-timestamp", "pallet-transaction-payment", "parity-scale-codec", "platforms", @@ -4536,6 +4537,7 @@ dependencies = [ "remote-externalities", "sc-authority-discovery", "sc-basic-authorship", + "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", @@ -4562,6 +4564,7 @@ dependencies = [ "sp-api", "sp-authority-discovery", "sp-authorship", + "sp-blockchain", "sp-consensus", "sp-consensus-babe", "sp-core", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 38c161a81ef06..15760c5a9abb4 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -116,7 +116,9 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo sc-consensus-babe = { version = "0.10.0-dev", path = "../../../client/consensus/babe" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../../client/consensus/epochs" } sc-service-test = { version = "2.0.0", path = "../../../client/service/test" } +sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } futures = "0.3.16" tempfile = "3.1.0" assert_cmd = "2.0.2" @@ -131,6 +133,7 @@ tokio = { version = "1.10", features = ["macros", "time"] } jsonrpsee-ws-client = { version = "0.3.1", default-features = false, features = ["tokio1"] } wait-timeout = "0.2" remote-externalities = { path = "../../../utils/frame/remote-externalities" } +pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } [build-dependencies] structopt = { version = "0.3.8", optional = true } @@ -166,3 +169,7 @@ try-runtime = ["node-runtime/try-runtime", "try-runtime-cli"] [[bench]] name = "transaction_pool" harness = false + +[[bench]] +name = "block_production" +harness = false diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs new file mode 100644 index 0000000000000..5a520e7b63397 --- /dev/null +++ b/bin/node/cli/benches/block_production.rs @@ -0,0 +1,237 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; + +use node_cli::service::{create_extrinsic, FullClient}; +use node_runtime::{constants::currency::*, BalancesCall}; +use sc_block_builder::{BlockBuilderProvider, BuiltBlock, RecordProof}; +use sc_client_api::execution_extensions::ExecutionStrategies; +use sc_consensus::{ + block_import::{BlockImportParams, ForkChoiceStrategy}, + BlockImport, StateAction, +}; +use sc_service::{ + config::{ + DatabaseSource, KeepBlocks, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, + PruningMode, TransactionStorageMode, WasmExecutionMethod, + }, + BasePath, Configuration, Role, +}; +use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed}; +use sp_consensus::BlockOrigin; +use sp_keyring::Sr25519Keyring; +use sp_runtime::{ + generic::BlockId, + transaction_validity::{InvalidTransaction, TransactionValidityError}, + AccountId32, MultiAddress, OpaqueExtrinsic, +}; +use tokio::runtime::Handle; + +fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { + let base_path = BasePath::new_temp_dir() + .expect("getting the base path of a temporary path doesn't fail; qed"); + let root = base_path.path().to_path_buf(); + + let network_config = NetworkConfiguration::new( + Sr25519Keyring::Alice.to_seed(), + "network/test/0.1", + Default::default(), + None, + ); + + let spec = Box::new(node_cli::chain_spec::development_config()); + + // NOTE: We enforce the use of the WASM runtime to benchmark block production using WASM. + let execution_strategy = sc_client_api::ExecutionStrategy::AlwaysWasm; + + let config = Configuration { + impl_name: "BenchmarkImpl".into(), + impl_version: "1.0".into(), + // We don't use the authority role since that would start producing blocks + // in the background which would mess with our benchmark. + role: Role::Full, + tokio_handle, + transaction_pool: Default::default(), + network: network_config, + keystore: KeystoreConfig::InMemory, + keystore_remote: Default::default(), + database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, + state_cache_size: 67108864, + state_cache_child_ratio: None, + state_pruning: PruningMode::ArchiveAll, + keep_blocks: KeepBlocks::All, + transaction_storage: TransactionStorageMode::BlockBody, + chain_spec: spec, + wasm_method: WasmExecutionMethod::Compiled, + execution_strategies: ExecutionStrategies { + syncing: execution_strategy, + importing: execution_strategy, + block_construction: execution_strategy, + offchain_worker: execution_strategy, + other: execution_strategy, + }, + rpc_http: None, + rpc_ws: None, + rpc_ipc: None, + rpc_ws_max_connections: None, + rpc_cors: None, + rpc_methods: Default::default(), + rpc_max_payload: None, + ws_max_out_buffer_capacity: None, + prometheus_config: None, + telemetry_endpoints: None, + default_heap_pages: None, + offchain_worker: OffchainWorkerConfig { enabled: true, indexing_enabled: false }, + force_authoring: false, + disable_grandpa: false, + dev_key_seed: Some(Sr25519Keyring::Alice.to_seed()), + tracing_targets: None, + tracing_receiver: Default::default(), + max_runtime_instances: 8, + announce_block: true, + base_path: Some(base_path), + informant_output_format: Default::default(), + wasm_runtime_overrides: None, + }; + + node_cli::service::new_full_base(config, |_, _| ()).expect("creating a full node doesn't fail") +} + +fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { + node_runtime::UncheckedExtrinsic { + signature: None, + function: node_runtime::Call::Timestamp(pallet_timestamp::Call::set { now }), + } + .into() +} + +fn import_block( + mut client: &FullClient, + built: BuiltBlock< + node_primitives::Block, + >::StateBackend, + >, +) { + let mut params = BlockImportParams::new(BlockOrigin::File, built.block.header); + params.state_action = + StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes(built.storage_changes)); + params.fork_choice = Some(ForkChoiceStrategy::LongestChain); + futures::executor::block_on(client.import_block(params, Default::default())) + .expect("importing a block doesn't fail"); +} + +fn prepare_benchmark(client: &FullClient) -> (usize, Vec) { + const MINIMUM_PERIOD_FOR_BLOCKS: u64 = 1500; + + let mut max_transfer_count = 0; + let mut extrinsics = Vec::new(); + let mut block_builder = client.new_block(Default::default()).unwrap(); + + // Every block needs one timestamp extrinsic. + let extrinsic_set_time = extrinsic_set_time(1 + MINIMUM_PERIOD_FOR_BLOCKS); + block_builder.push(extrinsic_set_time.clone()).unwrap(); + extrinsics.push(extrinsic_set_time); + + // Creating those is surprisingly costly, so let's only do it once and later just `clone` them. + let src = Sr25519Keyring::Alice.pair(); + let dst: MultiAddress = Sr25519Keyring::Bob.to_account_id().into(); + + // Add as many tranfer extrinsics as possible into a single block. + for nonce in 0.. { + let extrinsic: OpaqueExtrinsic = create_extrinsic( + client, + src.clone(), + BalancesCall::transfer { dest: dst.clone(), value: 1 * DOLLARS }, + Some(nonce), + ) + .into(); + + match block_builder.push(extrinsic.clone()) { + Ok(_) => {}, + Err(ApplyExtrinsicFailed(Validity(TransactionValidityError::Invalid( + InvalidTransaction::ExhaustsResources, + )))) => break, + Err(error) => panic!("{}", error), + } + + extrinsics.push(extrinsic); + max_transfer_count += 1; + } + + (max_transfer_count, extrinsics) +} + +fn block_production(c: &mut Criterion) { + sp_tracing::try_init_simple(); + + let runtime = tokio::runtime::Runtime::new().expect("creating tokio runtime doesn't fail; qed"); + let tokio_handle = runtime.handle().clone(); + + let node = new_node(tokio_handle.clone()); + let client = &*node.client; + + // Buliding the very first block is around ~30x slower than any subsequent one, + // so let's make sure it's built and imported before we benchmark anything. + let mut block_builder = client.new_block(Default::default()).unwrap(); + block_builder.push(extrinsic_set_time(1)).unwrap(); + import_block(client, block_builder.build().unwrap()); + + let (max_transfer_count, extrinsics) = prepare_benchmark(&client); + log::info!("Maximum transfer count: {}", max_transfer_count); + + let mut group = c.benchmark_group("Block production"); + + group.sample_size(10); + group.throughput(Throughput::Elements(max_transfer_count as u64)); + + let block_id = BlockId::Hash(client.chain_info().best_hash); + + group.bench_function(format!("{} transfers (no proof)", max_transfer_count), |b| { + b.iter_batched( + || extrinsics.clone(), + |extrinsics| { + let mut block_builder = + client.new_block_at(&block_id, Default::default(), RecordProof::No).unwrap(); + for extrinsic in extrinsics { + block_builder.push(extrinsic).unwrap(); + } + block_builder.build().unwrap() + }, + BatchSize::SmallInput, + ) + }); + + group.bench_function(format!("{} transfers (with proof)", max_transfer_count), |b| { + b.iter_batched( + || extrinsics.clone(), + |extrinsics| { + let mut block_builder = + client.new_block_at(&block_id, Default::default(), RecordProof::Yes).unwrap(); + for extrinsic in extrinsics { + block_builder.push(extrinsic).unwrap(); + } + block_builder.build().unwrap() + }, + BatchSize::SmallInput, + ) + }); +} + +criterion_group!(benches, block_production); +criterion_main!(benches); From dfe12bf772bfae862884af5ed4dd0b73011f5c84 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 9 Nov 2021 21:26:39 +0000 Subject: [PATCH 0204/1472] new remote-ext mode: (#10192) --- Cargo.lock | 1 + utils/frame/remote-externalities/Cargo.toml | 1 + utils/frame/remote-externalities/src/lib.rs | 122 +++++++++++++++----- 3 files changed, 94 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b164a74f94a55..b72f8ece09a4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7364,6 +7364,7 @@ name = "remote-externalities" version = "0.10.0-dev" dependencies = [ "env_logger 0.9.0", + "frame-support", "jsonrpsee-proc-macros", "jsonrpsee-ws-client", "log 0.4.14", diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 3e7c229ec4d65..9c9025d934aab 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -32,6 +32,7 @@ sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } [dev-dependencies] tokio = { version = "1.10", features = ["macros", "rt-multi-thread"] } pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", version = "5.0.0-dev" } +frame-support = { path = "../../../frame/support", version = "4.0.0-dev" } [features] remote-test = [] diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 3b9e08f75da85..bf8c57ae14ee6 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -22,7 +22,6 @@ use codec::{Decode, Encode}; use jsonrpsee_ws_client::{types::v2::params::JsonRpcParams, WsClient, WsClientBuilder}; -use log::*; use sp_core::{ hashing::twox_128, hexdisplay::HexDisplay, @@ -62,10 +61,12 @@ jsonrpsee_proc_macros::rpc_client_api! { /// The execution mode. #[derive(Clone)] pub enum Mode { - /// Online. + /// Online. Potentially writes to a cache file. Online(OnlineConfig), /// Offline. Uses a state snapshot file and needs not any client config. Offline(OfflineConfig), + /// Prefer using a cache file if it exists, else use a remote server. + OfflineOrElseOnline(OfflineConfig, OnlineConfig), } impl Default for Mode { @@ -83,6 +84,12 @@ pub struct OfflineConfig { pub state_snapshot: SnapshotConfig, } +impl> From

for SnapshotConfig { + fn from(p: P) -> Self { + Self { path: p.into() } + } +} + /// Description of the transport protocol (for online execution). #[derive(Debug)] pub struct Transport { @@ -193,6 +200,7 @@ impl Builder { fn as_online(&self) -> &OnlineConfig { match &self.mode { Mode::Online(config) => &config, + Mode::OfflineOrElseOnline(_, config) => &config, _ => panic!("Unexpected mode: Online"), } } @@ -200,6 +208,7 @@ impl Builder { fn as_online_mut(&mut self) -> &mut OnlineConfig { match &mut self.mode { Mode::Online(config) => config, + Mode::OfflineOrElseOnline(_, config) => config, _ => panic!("Unexpected mode: Online"), } } @@ -212,19 +221,19 @@ impl Builder { key: StorageKey, maybe_at: Option, ) -> Result { - trace!(target: LOG_TARGET, "rpc: get_storage"); + log::trace!(target: LOG_TARGET, "rpc: get_storage"); RpcApi::::get_storage(self.as_online().rpc_client(), key, maybe_at) .await .map_err(|e| { - error!("Error = {:?}", e); + log::error!(target: LOG_TARGET, "Error = {:?}", e); "rpc get_storage failed." }) } /// Get the latest finalized head. async fn rpc_get_head(&self) -> Result { - trace!(target: LOG_TARGET, "rpc: finalized_head"); + log::trace!(target: LOG_TARGET, "rpc: finalized_head"); RpcApi::::finalized_head(self.as_online().rpc_client()).await.map_err(|e| { - error!("Error = {:?}", e); + log::error!(target: LOG_TARGET, "Error = {:?}", e); "rpc finalized_head failed." }) } @@ -248,19 +257,19 @@ impl Builder { ) .await .map_err(|e| { - error!(target: LOG_TARGET, "Error = {:?}", e); + log::error!(target: LOG_TARGET, "Error = {:?}", e); "rpc get_keys failed" })?; let page_len = page.len(); all_keys.extend(page); if page_len < PAGE as usize { - debug!(target: LOG_TARGET, "last page received: {}", page_len); + log::debug!(target: LOG_TARGET, "last page received: {}", page_len); break all_keys } else { let new_last_key = all_keys.last().expect("all_keys is populated; has .last(); qed"); - debug!( + log::debug!( target: LOG_TARGET, "new total = {}, full page received: {:?}", all_keys.len(), @@ -286,7 +295,7 @@ impl Builder { use serde_json::to_value; let keys = self.get_keys_paged(prefix, at).await?; let keys_count = keys.len(); - debug!(target: LOG_TARGET, "Querying a total of {} keys", keys.len()); + log::debug!(target: LOG_TARGET, "Querying a total of {} keys", keys.len()); let mut key_values: Vec = vec![]; let client = self.as_online().rpc_client(); @@ -323,7 +332,7 @@ impl Builder { key_values.push((key.clone(), value)); if key_values.len() % (10 * BATCH_SIZE) == 0 { let ratio: f64 = key_values.len() as f64 / keys_count as f64; - debug!( + log::debug!( target: LOG_TARGET, "progress = {:.2} [{} / {}]", ratio, @@ -342,14 +351,14 @@ impl Builder { impl Builder { /// Save the given data as state snapshot. fn save_state_snapshot(&self, data: &[KeyPair], path: &Path) -> Result<(), &'static str> { - debug!(target: LOG_TARGET, "writing to state snapshot file {:?}", path); + log::debug!(target: LOG_TARGET, "writing to state snapshot file {:?}", path); fs::write(path, data.encode()).map_err(|_| "fs::write failed.")?; Ok(()) } /// initialize `Self` from state snapshot. Panics if the file does not exist. fn load_state_snapshot(&self, path: &Path) -> Result, &'static str> { - info!(target: LOG_TARGET, "scraping key-pairs from state snapshot {:?}", path); + log::info!(target: LOG_TARGET, "scraping key-pairs from state snapshot {:?}", path); let bytes = fs::read(path).map_err(|_| "fs::read failed.")?; Decode::decode(&mut &*bytes).map_err(|_| "decode failed") } @@ -362,14 +371,14 @@ impl Builder { .at .expect("online config must be initialized by this point; qed.") .clone(); - info!(target: LOG_TARGET, "scraping key-pairs from remote @ {:?}", at); + log::info!(target: LOG_TARGET, "scraping key-pairs from remote @ {:?}", at); let mut keys_and_values = if config.pallets.len() > 0 { let mut filtered_kv = vec![]; for f in config.pallets.iter() { let hashed_prefix = StorageKey(twox_128(f.as_bytes()).to_vec()); let module_kv = self.rpc_get_pairs_paged(hashed_prefix.clone(), at).await?; - info!( + log::info!( target: LOG_TARGET, "downloaded data for module {} (count: {} / prefix: {:?}).", f, @@ -380,12 +389,12 @@ impl Builder { } filtered_kv } else { - info!(target: LOG_TARGET, "downloading data for all pallets."); + log::info!(target: LOG_TARGET, "downloading data for all pallets."); self.rpc_get_pairs_paged(StorageKey(vec![]), at).await? }; for prefix in &self.hashed_prefixes { - info!( + log::info!( target: LOG_TARGET, "adding data for hashed prefix: {:?}", HexDisplay::from(prefix) @@ -397,7 +406,11 @@ impl Builder { for key in &self.hashed_keys { let key = StorageKey(key.to_vec()); - info!(target: LOG_TARGET, "adding data for hashed key: {:?}", HexDisplay::from(&key)); + log::info!( + target: LOG_TARGET, + "adding data for hashed key: {:?}", + HexDisplay::from(&key) + ); let value = self.rpc_get_storage(key.clone(), Some(at)).await?; keys_and_values.push((key, value)); } @@ -407,7 +420,7 @@ impl Builder { pub(crate) async fn init_remote_client(&mut self) -> Result<(), &'static str> { let mut online = self.as_online_mut(); - debug!(target: LOG_TARGET, "initializing remote client to {:?}", online.transport.uri); + log::debug!(target: LOG_TARGET, "initializing remote client to {:?}", online.transport.uri); // First, initialize the ws client. let ws_client = WsClientBuilder::default() @@ -437,11 +450,23 @@ impl Builder { } kp }, + Mode::OfflineOrElseOnline(offline_config, online_config) => { + if let Ok(kv) = self.load_state_snapshot(&offline_config.state_snapshot.path) { + kv + } else { + self.init_remote_client().await?; + let kp = self.load_remote().await?; + if let Some(c) = online_config.state_snapshot { + self.save_state_snapshot(&kp, &c.path)?; + } + kp + } + }, }; // inject manual key values. if !self.hashed_key_values.is_empty() { - debug!( + log::debug!( target: LOG_TARGET, "extending externalities with {} manually injected key-values", self.hashed_key_values.len() @@ -451,7 +476,7 @@ impl Builder { // exclude manual key values. if !self.hashed_blacklist.is_empty() { - debug!( + log::debug!( target: LOG_TARGET, "excluding externalities from {} keys", self.hashed_blacklist.len() @@ -522,7 +547,7 @@ impl Builder { let kv = self.pre_build().await?; let mut ext = TestExternalities::new_empty(); - info!(target: LOG_TARGET, "injecting a total of {} keys", kv.len()); + log::info!(target: LOG_TARGET, "injecting a total of {} keys", kv.len()); for (k, v) in kv { let (k, v) = (k.0, v.0); // Insert the key,value pair into the test trie backend @@ -603,12 +628,51 @@ mod remote_tests { const REMOTE_INACCESSIBLE: &'static str = "Can't reach the remote node. Is it running?"; + #[tokio::test] + async fn offline_else_online_works() { + init_logger(); + // this shows that in the second run, we use the remote and create a cache. + Builder::::new() + .mode(Mode::OfflineOrElseOnline( + OfflineConfig { + state_snapshot: SnapshotConfig::new("test_snapshot_to_remove.bin"), + }, + OnlineConfig { + pallets: vec!["Proxy".to_owned()], + state_snapshot: Some(SnapshotConfig::new("test_snapshot_to_remove.bin")), + ..Default::default() + }, + )) + .build() + .await + .expect(REMOTE_INACCESSIBLE) + .execute_with(|| {}); + + // this shows that in the second run, we are not using the remote + Builder::::new() + .mode(Mode::OfflineOrElseOnline( + OfflineConfig { + state_snapshot: SnapshotConfig::new("test_snapshot_to_remove.bin"), + }, + OnlineConfig { + pallets: vec!["Proxy".to_owned()], + state_snapshot: Some(SnapshotConfig::new("test_snapshot_to_remove.bin")), + transport: "ws://non-existent:666".to_owned().into(), + ..Default::default() + }, + )) + .build() + .await + .expect(REMOTE_INACCESSIBLE) + .execute_with(|| {}); + } + #[tokio::test] async fn can_build_one_pallet() { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - pallets: vec!["System".to_owned()], + pallets: vec!["Proxy".to_owned()], ..Default::default() })) .build() @@ -622,11 +686,7 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - pallets: vec![ - "Proxy".to_owned(), - "Multisig".to_owned(), - "PhragmenElection".to_owned(), - ], + pallets: vec!["Proxy".to_owned(), "Multisig".to_owned()], ..Default::default() })) .build() @@ -639,6 +699,7 @@ mod remote_tests { async fn sanity_check_decoding() { use pallet_elections_phragmen::SeatHolder; use sp_core::crypto::Ss58Codec; + type AccountId = sp_runtime::AccountId32; type Balance = u128; frame_support::generate_storage_alias!( @@ -676,7 +737,7 @@ mod remote_tests { Builder::::new() .mode(Mode::Online(OnlineConfig { state_snapshot: Some(SnapshotConfig::new("test_snapshot_to_remove.bin")), - pallets: vec!["Balances".to_owned()], + pallets: vec!["Proxy".to_owned()], ..Default::default() })) .build() @@ -684,7 +745,7 @@ mod remote_tests { .expect(REMOTE_INACCESSIBLE) .execute_with(|| {}); - let to_delete = std::fs::read_dir(SnapshotConfig::default().path) + let to_delete = std::fs::read_dir(Path::new(".")) .unwrap() .into_iter() .map(|d| d.unwrap()) @@ -699,6 +760,7 @@ mod remote_tests { } #[tokio::test] + #[ignore = "takes too much time on average."] async fn can_fetch_all() { init_logger(); Builder::::new() From 5111c72d3d611c0a643d89a305b2c9a4fdaa9134 Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Tue, 9 Nov 2021 14:27:40 -0700 Subject: [PATCH 0205/1472] move wiki -> docs (#10225) Co-authored-by: Dan Shields --- bin/utils/subkey/README.md | 2 +- client/cli/src/commands/run_cmd.rs | 4 ++-- primitives/core/src/crypto.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/utils/subkey/README.md b/bin/utils/subkey/README.md index 2310c59f4a283..e762a42c3e79e 100644 --- a/bin/utils/subkey/README.md +++ b/bin/utils/subkey/README.md @@ -69,7 +69,7 @@ The output above also show the **public key** and the **Account ID**. Those are The **SS58 address** (or **Public Address**) of a new account is a reprensentation of the public keys of an account for a given network (for instance Kusama or Polkadot). -You can read more about the SS58 format in the [substrate wiki](https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)) and see the list of reserved prefixes in the [Polkadot wiki](https://wiki.polkadot.network/docs/build-ss58-registry). +You can read more about the SS58 format in the [Substrate Docs](https://docs.substrate.io/v3/advanced/ss58/) and see the list of reserved prefixes in the [SS58 Registry](https://github.com/paritytech/ss58-registry). For instance, considering the previous seed `0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d` the SS58 addresses are: diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index d6c0133a7c145..ad2f04583c10b 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -58,7 +58,7 @@ pub struct RunCmd { /// /// Default is local. Note: not all RPC methods are safe to be exposed publicly. Use an RPC /// proxy server to filter out dangerous methods. More details: - /// . + /// . /// Use `--unsafe-rpc-external` to suppress the warning if you understand the risks. #[structopt(long = "rpc-external")] pub rpc_external: bool, @@ -89,7 +89,7 @@ pub struct RunCmd { /// /// Default is local. Note: not all RPC methods are safe to be exposed publicly. Use an RPC /// proxy server to filter out dangerous methods. More details: - /// . + /// . /// Use `--unsafe-ws-external` to suppress the warning if you understand the risks. #[structopt(long = "ws-external")] pub ws_external: bool, diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 21b8520c7780f..4f21d62f5850d 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -219,7 +219,7 @@ pub enum PublicError { /// Key that can be encoded to/from SS58. /// -/// See +/// See /// for information on the codec. #[cfg(feature = "full_crypto")] pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { From 5fe5974173b3f4edb83cb4f58c4af2a02685a364 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 9 Nov 2021 22:33:21 +0000 Subject: [PATCH 0206/1472] upgrade ss58-registry with additional networks. (#10224) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * upgrade ss58-registry with additional networks. * adding cargo lock * Update primitives/core/Cargo.toml Co-authored-by: Bastian Köcher * turn on std Co-authored-by: Bastian Köcher --- Cargo.lock | 4 ++-- primitives/core/Cargo.toml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b72f8ece09a4f..5e940b93f65f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9995,9 +9995,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "ss58-registry" -version = "1.0.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2413ecc7946ca99368862851dc1359f1477bc654ecfb135cf3efcb85ceca5f" +checksum = "c66cd4c4bb7ee41dc5b0c13d600574ae825d3a02e8f31326b17ac71558f2c836" dependencies = [ "Inflector", "proc-macro2", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 8262393e653fe..9948b2e968c26 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -68,7 +68,7 @@ twox-hash = { version = "1.6.1", default-features = false, optional = true } libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"], optional = true } sp-core-hashing = { version = "4.0.0-dev", path = "./hashing", default-features = false, optional = true } merlin = { version = "2.0", default-features = false, optional = true } -ss58-registry = "1.0.0" +ss58-registry = { version = "1.5.0", default-features = false } sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" } [dev-dependencies] @@ -125,6 +125,7 @@ std = [ "sp-externalities", "sp-storage/std", "sp-runtime-interface/std", + "ss58-registry/std", "zeroize/alloc", "secrecy/alloc", "futures", From 1a6631117fdc66a65f3d484d5c8c015c4207f7c7 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 10 Nov 2021 16:03:52 +0800 Subject: [PATCH 0207/1472] Upgrade wasm builder (#10226) * add TypeInfo for DispatchTime * upgrade wasm-builder to Rust 2021 * remove resolver * revert resolver in virtual workspace --- utils/wasm-builder/src/prerequisites.rs | 2 +- utils/wasm-builder/src/wasm_project.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/utils/wasm-builder/src/prerequisites.rs b/utils/wasm-builder/src/prerequisites.rs index c45f7933a1de3..7236b8169bcb5 100644 --- a/utils/wasm-builder/src/prerequisites.rs +++ b/utils/wasm-builder/src/prerequisites.rs @@ -58,7 +58,7 @@ fn create_check_toolchain_project(project_dir: &Path) { [package] name = "wasm-test" version = "1.0.0" - edition = "2018" + edition = "2021" build = "build.rs" [lib] diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 3806a890a1064..59214ab483c62 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -266,8 +266,7 @@ fn create_project_cargo_toml( let mut package = Table::new(); package.insert("name".into(), format!("{}-wasm", crate_name).into()); package.insert("version".into(), "1.0.0".into()); - package.insert("edition".into(), "2018".into()); - package.insert("resolver".into(), "2".into()); + package.insert("edition".into(), "2021".into()); wasm_workspace_toml.insert("package".into(), package.into()); From 7b24a94cb065ca1018019c825e6dfc21327b47c3 Mon Sep 17 00:00:00 2001 From: Jimmy Chu Date: Wed, 10 Nov 2021 16:11:28 +0800 Subject: [PATCH 0208/1472] Move all example pallets under `examples` folder. (#10215) * Put all examples under one folder Signed-off-by: Jimmy Chu * Updated Cargo.toml Signed-off-by: Jimmy Chu * updated for ci script Signed-off-by: Jimmy Chu * update Signed-off-by: Jimmy Chu * Added notes that example pallets are not meant to be used in production. Signed-off-by: Jimmy Chu * updated Signed-off-by: Jimmy Chu --- .gitlab-ci.yml | 6 +++--- Cargo.lock | 2 +- Cargo.toml | 6 +++--- frame/benchmarking/src/lib.rs | 4 ++-- frame/{example => examples/basic}/Cargo.toml | 21 ++++++++++--------- frame/{example => examples/basic}/README.md | 14 +++++++------ .../basic}/src/benchmarking.rs | 6 +++--- frame/{example => examples/basic}/src/lib.rs | 8 ++++--- .../{example => examples/basic}/src/tests.rs | 14 ++++++------- .../basic}/src/weights.rs | 8 +++---- .../offchain-worker}/Cargo.toml | 17 ++++++++------- .../offchain-worker}/README.md | 4 +++- .../offchain-worker}/src/lib.rs | 3 +++ .../offchain-worker}/src/tests.rs | 0 .../parallel}/Cargo.toml | 15 ++++++------- frame/examples/parallel/README.md | 7 +++++++ .../parallel}/src/lib.rs | 6 ++++-- .../parallel}/src/tests.rs | 0 18 files changed, 81 insertions(+), 60 deletions(-) rename frame/{example => examples/basic}/Cargo.toml (78%) rename frame/{example => examples/basic}/README.md (94%) rename frame/{example => examples/basic}/src/benchmarking.rs (93%) rename frame/{example => examples/basic}/src/lib.rs (99%) rename frame/{example => examples/basic}/src/tests.rs (92%) rename frame/{example => examples/basic}/src/weights.rs (93%) rename frame/{example-offchain-worker => examples/offchain-worker}/Cargo.toml (82%) rename frame/{example-offchain-worker => examples/offchain-worker}/README.md (87%) rename frame/{example-offchain-worker => examples/offchain-worker}/src/lib.rs (99%) rename frame/{example-offchain-worker => examples/offchain-worker}/src/tests.rs (100%) rename frame/{example-parallel => examples/parallel}/Cargo.toml (84%) create mode 100644 frame/examples/parallel/README.md rename frame/{example-parallel => examples/parallel}/src/lib.rs (95%) rename frame/{example-parallel => examples/parallel}/src/tests.rs (100%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5e406b36c5c5b..210bb447e4c7b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,7 +41,7 @@ variables: &default-vars CI_IMAGE: "paritytech/ci-linux:production" # FIXME set to release CARGO_UNLEASH_INSTALL_PARAMS: "--version 1.0.0-alpha.12" - CARGO_UNLEASH_PKG_DEF: "--skip node node-* pallet-template pallet-example pallet-example-* subkey chain-spec-builder" + CARGO_UNLEASH_PKG_DEF: "--skip node node-* pallet-template pallet-example-* subkey chain-spec-builder" VAULT_SERVER_URL: "https://vault.parity-mgmt-vault.parity.io" VAULT_AUTH_PATH: "gitlab-parity-io-jwt" VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" @@ -482,9 +482,9 @@ test-frame-examples-compile-to-wasm: RUSTFLAGS: "-Cdebug-assertions=y" RUST_BACKTRACE: 1 script: - - cd frame/example-offchain-worker/ + - cd frame/examples/offchain-worker/ - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features - - cd ../example + - cd ../basic - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features - sccache -s diff --git a/Cargo.lock b/Cargo.lock index 5e940b93f65f2..a7bb471f90d8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5515,7 +5515,7 @@ dependencies = [ ] [[package]] -name = "pallet-example" +name = "pallet-example-basic" version = "4.0.0-dev" dependencies = [ "frame-benchmarking", diff --git a/Cargo.toml b/Cargo.toml index 07053a0ef3162..ca60af692497d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,9 +84,9 @@ members = [ "frame/elections", "frame/election-provider-multi-phase", "frame/election-provider-support", - "frame/example", - "frame/example-offchain-worker", - "frame/example-parallel", + "frame/examples/basic", + "frame/examples/offchain-worker", + "frame/examples/parallel", "frame/executive", "frame/gilt", "frame/grandpa", diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 258b40cbe6f0b..088dbeb0bb78d 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -1217,7 +1217,7 @@ macro_rules! impl_benchmark_test { /// This creates a test suite which runs the module's benchmarks. /// -/// When called in `pallet_example` as +/// When called in `pallet_example_basic` as /// /// ```rust,ignore /// impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); @@ -1243,7 +1243,7 @@ macro_rules! impl_benchmark_test { /// } /// ``` /// -/// When called inside the `benchmarks` macro of the `pallet_example` as +/// When called inside the `benchmarks` macro of the `pallet_example_basic` as /// /// ```rust,ignore /// benchmarks! { diff --git a/frame/example/Cargo.toml b/frame/examples/basic/Cargo.toml similarity index 78% rename from frame/example/Cargo.toml rename to frame/examples/basic/Cargo.toml index 0b3a742de0dd7..a4e8ffe3261cd 100644 --- a/frame/example/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pallet-example" +name = "pallet-example-basic" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" @@ -14,18 +14,19 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } + +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } +pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } +sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.0.0-dev", path = "../../../primitives/core", default-features = false } [features] default = ["std"] diff --git a/frame/example/README.md b/frame/examples/basic/README.md similarity index 94% rename from frame/example/README.md rename to frame/examples/basic/README.md index e06dee78c3f81..358829192f11d 100644 --- a/frame/example/README.md +++ b/frame/examples/basic/README.md @@ -1,11 +1,13 @@ -# Example Pallet +# Basic Example Pallet The Example: A simple example of a FRAME pallet demonstrating concepts, APIs and structures common to most FRAME runtimes. -Run `cargo doc --package pallet-example --open` to view this pallet's documentation. +Run `cargo doc --package pallet-example-basic --open` to view this pallet's documentation. + +**This pallet serves as an example and is not meant to be used in production.** ### Documentation Guidelines: @@ -34,7 +36,7 @@ Run `cargo doc --package pallet-example --open` to view this pallet's documentat ### Documentation Template:
-Copy and paste this template from frame/example/src/lib.rs into file +Copy and paste this template from frame/examples/basic/src/lib.rs into file `frame//src/lib.rs` of your own custom pallet and complete it.

 // Add heading with custom pallet name
@@ -46,9 +48,9 @@ Copy and paste this template from frame/example/src/lib.rs into file
 // Include the following links that shows what trait needs to be implemented to use the pallet
 // and the supported dispatchables that are documented in the Call enum.
 
-- \[`::Config`](https://docs.rs/pallet-example/latest/pallet_example/trait.Config.html)
-- \[`Call`](https://docs.rs/pallet-example/latest/pallet_example/enum.Call.html)
-- \[`Module`](https://docs.rs/pallet-example/latest/pallet_example/struct.Module.html)
+- \[`::Config`](https://docs.rs/pallet-example-basic/latest/pallet_example_basic/trait.Config.html)
+- \[`Call`](https://docs.rs/pallet-example-basic/latest/pallet_example_basic/enum.Call.html)
+- \[`Module`](https://docs.rs/pallet-example-basic/latest/pallet_example_basic/struct.Module.html)
 
 \## Overview
 
diff --git a/frame/example/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs
similarity index 93%
rename from frame/example/src/benchmarking.rs
rename to frame/examples/basic/src/benchmarking.rs
index e89c646e03f1a..a031b15834d63 100644
--- a/frame/example/src/benchmarking.rs
+++ b/frame/examples/basic/src/benchmarking.rs
@@ -15,7 +15,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! Benchmarking for pallet-example.
+//! Benchmarking for pallet-example-basic.
 
 #![cfg(feature = "runtime-benchmarks")]
 
@@ -23,7 +23,7 @@ use crate::*;
 use frame_benchmarking::{benchmarks, whitelisted_caller};
 use frame_system::RawOrigin;
 
-// To actually run this benchmark on pallet-example, we need to put this pallet into the
+// To actually run this benchmark on pallet-example-basic, we need to put this pallet into the
 //   runtime and compile it with `runtime-benchmarks` feature. The detail procedures are
 //   documented at:
 //   https://docs.substrate.io/v3/runtime/benchmarking#how-to-benchmark
@@ -67,7 +67,7 @@ benchmarks! {
 	}
 
 	// This line generates test cases for benchmarking, and could be run by:
-	//   `cargo test -p pallet-example --all-features`, you will see one line per case:
+	//   `cargo test -p pallet-example-basic --all-features`, you will see one line per case:
 	//   `test benchmarking::bench_sort_vector ... ok`
 	//   `test benchmarking::bench_accumulate_dummy ... ok`
 	//   `test benchmarking::bench_set_dummy_benchmark ... ok` in the result.
diff --git a/frame/example/src/lib.rs b/frame/examples/basic/src/lib.rs
similarity index 99%
rename from frame/example/src/lib.rs
rename to frame/examples/basic/src/lib.rs
index 981274b1ba739..b172acb66d324 100644
--- a/frame/example/src/lib.rs
+++ b/frame/examples/basic/src/lib.rs
@@ -16,13 +16,15 @@
 // limitations under the License.
 
 //! 
-//! # Example Pallet
+//! # Basic Example Pallet
 //!
 //! 
 //! The Example: A simple example of a FRAME pallet demonstrating
 //! concepts, APIs and structures common to most FRAME runtimes.
 //!
-//! Run `cargo doc --package pallet-example --open` to view this pallet's documentation.
+//! Run `cargo doc --package pallet-example-basic --open` to view this pallet's documentation.
+//!
+//! **This pallet serves as an example and is not meant to be used in production.**
 //!
 //! ### Documentation Guidelines:
 //!
@@ -59,7 +61,7 @@
 //!
 //! ### Documentation Template:
//! -//! Copy and paste this template from frame/example/src/lib.rs into file +//! Copy and paste this template from frame/examples/basic/src/lib.rs into file //! `frame//src/lib.rs` of your own custom pallet and complete it. //!

 //! // Add heading with custom pallet name
diff --git a/frame/example/src/tests.rs b/frame/examples/basic/src/tests.rs
similarity index 92%
rename from frame/example/src/tests.rs
rename to frame/examples/basic/src/tests.rs
index 4c2274572db81..e069cccf8d800 100644
--- a/frame/example/src/tests.rs
+++ b/frame/examples/basic/src/tests.rs
@@ -15,7 +15,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! Tests for pallet-example.
+//! Tests for pallet-example-basic.
 
 use crate::*;
 use frame_support::{
@@ -32,7 +32,7 @@ use sp_runtime::{
 	BuildStorage,
 };
 // Reexport crate as its pallet name for construct_runtime.
-use crate as pallet_example;
+use crate as pallet_example_basic;
 
 type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic;
 type Block = frame_system::mocking::MockBlock;
@@ -46,7 +46,7 @@ frame_support::construct_runtime!(
 	{
 		System: frame_system::{Pallet, Call, Config, Storage, Event},
 		Balances: pallet_balances::{Pallet, Call, Storage, Config, Event},
-		Example: pallet_example::{Pallet, Call, Storage, Config, Event},
+		Example: pallet_example_basic::{Pallet, Call, Storage, Config, Event},
 	}
 );
 
@@ -111,7 +111,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
 		// We use default for brevity, but you can configure as desired if needed.
 		system: Default::default(),
 		balances: Default::default(),
-		example: pallet_example::GenesisConfig {
+		example: pallet_example_basic::GenesisConfig {
 			dummy: 42,
 			// we configure the map with (key, value) pairs.
 			bar: vec![(1, 2), (2, 3)],
@@ -163,7 +163,7 @@ fn set_dummy_works() {
 #[test]
 fn signed_ext_watch_dummy_works() {
 	new_test_ext().execute_with(|| {
-		let call = pallet_example::Call::set_dummy { new_value: 10 }.into();
+		let call = pallet_example_basic::Call::set_dummy { new_value: 10 }.into();
 		let info = DispatchInfo::default();
 
 		assert_eq!(
@@ -192,14 +192,14 @@ fn counted_map_works() {
 #[test]
 fn weights_work() {
 	// must have a defined weight.
-	let default_call = pallet_example::Call::::accumulate_dummy { increase_by: 10 };
+	let default_call = pallet_example_basic::Call::::accumulate_dummy { increase_by: 10 };
 	let info1 = default_call.get_dispatch_info();
 	// aka. `let info =  as GetDispatchInfo>::get_dispatch_info(&default_call);`
 	assert!(info1.weight > 0);
 
 	// `set_dummy` is simpler than `accumulate_dummy`, and the weight
 	//   should be less.
-	let custom_call = pallet_example::Call::::set_dummy { new_value: 20 };
+	let custom_call = pallet_example_basic::Call::::set_dummy { new_value: 20 };
 	let info2 = custom_call.get_dispatch_info();
 	assert!(info1.weight > info2.weight);
 }
diff --git a/frame/example/src/weights.rs b/frame/examples/basic/src/weights.rs
similarity index 93%
rename from frame/example/src/weights.rs
rename to frame/examples/basic/src/weights.rs
index efcfdc6729b53..048f7f5a8b8e5 100644
--- a/frame/example/src/weights.rs
+++ b/frame/examples/basic/src/weights.rs
@@ -15,7 +15,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! Autogenerated weights for pallet_example
+//! Autogenerated weights for pallet_example_basic
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0
 //! DATE: 2021-03-15, STEPS: `[100, ]`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]`
@@ -31,7 +31,7 @@
 // --wasm-execution
 // compiled
 // --pallet
-// pallet_example
+// pallet_example_basic
 // --extrinsic
 // *
 // --steps
@@ -52,14 +52,14 @@
 use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
 use sp_std::marker::PhantomData;
 
-/// Weight functions needed for pallet_example.
+/// Weight functions needed for pallet_example_basic.
 pub trait WeightInfo {
 	fn set_dummy_benchmark(b: u32, ) -> Weight;
 	fn accumulate_dummy(b: u32, ) -> Weight;
 	fn sort_vector(x: u32, ) -> Weight;
 }
 
-/// Weights for pallet_example using the Substrate node and recommended hardware.
+/// Weights for pallet_example_basic using the Substrate node and recommended hardware.
 pub struct SubstrateWeight(PhantomData);
 impl WeightInfo for SubstrateWeight {
 	fn set_dummy_benchmark(b: u32, ) -> Weight {
diff --git a/frame/example-offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml
similarity index 82%
rename from frame/example-offchain-worker/Cargo.toml
rename to frame/examples/offchain-worker/Cargo.toml
index ffcadca26e11e..cb505ad42f254 100644
--- a/frame/example-offchain-worker/Cargo.toml
+++ b/frame/examples/offchain-worker/Cargo.toml
@@ -14,16 +14,17 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
-frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" }
-frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" }
-sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" }
-sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore", optional = true }
-sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" }
-sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" }
-sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" }
 lite-json = { version = "0.1", default-features = false }
 log = { version = "0.4.14", default-features = false }
+scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+
+frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" }
+frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" }
+sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" }
+sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" }
+sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore", optional = true }
+sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" }
+sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" }
 
 [features]
 default = ["std"]
diff --git a/frame/example-offchain-worker/README.md b/frame/examples/offchain-worker/README.md
similarity index 87%
rename from frame/example-offchain-worker/README.md
rename to frame/examples/offchain-worker/README.md
index 5299027f39250..587431c92c0ed 100644
--- a/frame/example-offchain-worker/README.md
+++ b/frame/examples/offchain-worker/README.md
@@ -1,5 +1,5 @@
 
-# Offchain Worker Example Module
+# Offchain Worker Example Pallet
 
 The Offchain Worker Example: A simple pallet demonstrating
 concepts, APIs and structures common to most offchain workers.
@@ -11,6 +11,8 @@ documentation.
 - [`Call`](./enum.Call.html)
 - [`Module`](./struct.Module.html)
 
+**This pallet serves as an example showcasing Substrate off-chain worker and is not meant to be
+used in production.**
 
 ## Overview
 
diff --git a/frame/example-offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs
similarity index 99%
rename from frame/example-offchain-worker/src/lib.rs
rename to frame/examples/offchain-worker/src/lib.rs
index 9b63ffa663ee2..e5f2e00d9a344 100644
--- a/frame/example-offchain-worker/src/lib.rs
+++ b/frame/examples/offchain-worker/src/lib.rs
@@ -28,6 +28,8 @@
 //! - [`Call`]
 //! - [`Pallet`]
 //!
+//! **This pallet serves as an example showcasing Substrate off-chain worker and is not meant to
+//! be used in production.**
 //!
 //! ## Overview
 //!
@@ -40,6 +42,7 @@
 //! Additional logic in OCW is put in place to prevent spamming the network with both signed
 //! and unsigned transactions, and custom `UnsignedValidator` makes sure that there is only
 //! one unsigned transaction floating in the network.
+
 #![cfg_attr(not(feature = "std"), no_std)]
 
 use codec::{Decode, Encode};
diff --git a/frame/example-offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs
similarity index 100%
rename from frame/example-offchain-worker/src/tests.rs
rename to frame/examples/offchain-worker/src/tests.rs
diff --git a/frame/example-parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml
similarity index 84%
rename from frame/example-parallel/Cargo.toml
rename to frame/examples/parallel/Cargo.toml
index 169db35e65f1c..cf7f46b232247 100644
--- a/frame/example-parallel/Cargo.toml
+++ b/frame/examples/parallel/Cargo.toml
@@ -14,13 +14,14 @@ targets = ["x86_64-unknown-linux-gnu"]
 [dependencies]
 codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
 scale-info = { version = "1.0", default-features = false, features = ["derive"] }
-frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" }
-frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" }
-sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" }
-sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" }
-sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" }
-sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" }
-sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../primitives/tasks" }
+
+frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" }
+frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" }
+sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" }
+sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" }
+sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" }
+sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" }
+sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" }
 
 [features]
 default = ["std"]
diff --git a/frame/examples/parallel/README.md b/frame/examples/parallel/README.md
new file mode 100644
index 0000000000000..44b39a41507db
--- /dev/null
+++ b/frame/examples/parallel/README.md
@@ -0,0 +1,7 @@
+
+# Parallel Tasks Example Pallet
+
+This example pallet demonstrates parallelizing validation of the enlisted participants (see
+`enlist_participants` dispatch).
+
+**This pallet serves as an example and is not meant to be used in production.**
diff --git a/frame/example-parallel/src/lib.rs b/frame/examples/parallel/src/lib.rs
similarity index 95%
rename from frame/example-parallel/src/lib.rs
rename to frame/examples/parallel/src/lib.rs
index 9d191525f631e..51e022bed08b3 100644
--- a/frame/example-parallel/src/lib.rs
+++ b/frame/examples/parallel/src/lib.rs
@@ -15,10 +15,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! Parallel tasks example
+//! # Parallel Tasks Example Pallet
 //!
-//! This example pallet parallelizes validation of the enlisted participants
+//! This example pallet demonstrates parallelizing validation of the enlisted participants
 //! (see `enlist_participants` dispatch).
+//!
+//! **This pallet serves as an example and is not meant to be used in production.**
 
 #![cfg_attr(not(feature = "std"), no_std)]
 
diff --git a/frame/example-parallel/src/tests.rs b/frame/examples/parallel/src/tests.rs
similarity index 100%
rename from frame/example-parallel/src/tests.rs
rename to frame/examples/parallel/src/tests.rs

From 6ec26dfc9268ab0a43fa41db84386261ed000d9b Mon Sep 17 00:00:00 2001
From: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Date: Wed, 10 Nov 2021 09:33:14 +0000
Subject: [PATCH 0209/1472] use CountedMap in pallet-bags-list (#10179)

* use CountedMap in pallet-bags-list

* Fix build

* Update frame/bags-list/src/list/mod.rs

Co-authored-by: Keith Yeung 

* add a check as well

Co-authored-by: Keith Yeung 
---
 bin/node/runtime/src/lib.rs                   |  2 +-
 frame/bags-list/Cargo.toml                    |  5 +-
 frame/bags-list/src/lib.rs                    | 12 ++---
 frame/bags-list/src/list/mod.rs               | 33 +++++--------
 frame/bags-list/src/list/tests.rs             | 23 ++++++---
 frame/bags-list/src/migrations.rs             | 49 +++++++++++++++++++
 frame/bags-list/src/tests.rs                  |  2 +-
 .../support/src/storage/types/counted_map.rs  | 12 +++--
 8 files changed, 94 insertions(+), 44 deletions(-)
 create mode 100644 frame/bags-list/src/migrations.rs

diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs
index 570abe53ed01f..6d04ca8fdca87 100644
--- a/bin/node/runtime/src/lib.rs
+++ b/bin/node/runtime/src/lib.rs
@@ -1330,7 +1330,7 @@ pub type Executive = frame_executive::Executive<
 	frame_system::ChainContext,
 	Runtime,
 	AllPallets,
-	(),
+	pallet_bags_list::migrations::CheckCounterPrefix,
 >;
 
 /// MMR helper types.
diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml
index fa47b9bad5692..6d4cf2363c4f7 100644
--- a/frame/bags-list/Cargo.toml
+++ b/frame/bags-list/Cargo.toml
@@ -64,9 +64,10 @@ runtime-benchmarks = [
 	"frame-election-provider-support/runtime-benchmarks",
 ]
 fuzz = [
-  "sp-core",
+	"sp-core",
 	"sp-io",
-  "pallet-balances",
+	"pallet-balances",
 	"sp-tracing",
 ]
+try-runtime = [ "frame-support/try-runtime" ]
 
diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs
index b7f96799e459f..8d74ecc9bd2d1 100644
--- a/frame/bags-list/src/lib.rs
+++ b/frame/bags-list/src/lib.rs
@@ -59,6 +59,7 @@ use sp_std::prelude::*;
 mod benchmarks;
 
 mod list;
+pub mod migrations;
 #[cfg(any(test, feature = "fuzz"))]
 pub mod mock;
 #[cfg(test)]
@@ -151,17 +152,12 @@ pub mod pallet {
 		type BagThresholds: Get<&'static [VoteWeight]>;
 	}
 
-	/// How many ids are registered.
-	// NOTE: This is merely a counter for `ListNodes`. It should someday be replaced by the
-	// `CountedMap` storage.
-	#[pallet::storage]
-	pub(crate) type CounterForListNodes = StorageValue<_, u32, ValueQuery>;
-
 	/// A single node, within some bag.
 	///
 	/// Nodes store links forward and back within their respective bags.
 	#[pallet::storage]
-	pub(crate) type ListNodes = StorageMap<_, Twox64Concat, T::AccountId, list::Node>;
+	pub(crate) type ListNodes =
+		CountedStorageMap<_, Twox64Concat, T::AccountId, list::Node>;
 
 	/// A bag stored in storage.
 	///
@@ -240,7 +236,7 @@ impl SortedListProvider for Pallet {
 	}
 
 	fn count() -> u32 {
-		CounterForListNodes::::get()
+		ListNodes::::count()
 	}
 
 	fn contains(id: &T::AccountId) -> bool {
diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs
index 4efc3163816ff..df966eea80cee 100644
--- a/frame/bags-list/src/list/mod.rs
+++ b/frame/bags-list/src/list/mod.rs
@@ -18,7 +18,7 @@
 //! Implementation of a "bags list": a semi-sorted list where ordering granularity is dictated by
 //! configurable thresholds that delineate the boundaries of bags. It uses a pattern of composite
 //! data structures, where multiple storage items are masked by one outer API. See [`ListNodes`],
-//! [`CounterForListNodes`] and [`ListBags`] for more information.
+//! [`ListBags`] for more information.
 //!
 //! The outer API of this module is the [`List`] struct. It wraps all acceptable operations on top
 //! of the aggregate linked list. All operations with the bags list should happen through this
@@ -77,17 +77,18 @@ pub struct List(PhantomData);
 
 impl List {
 	/// Remove all data associated with the list from storage. Parameter `items` is the number of
-	/// items to clear from the list. WARNING: `None` will clear all items and should generally not
-	/// be used in production as it could lead to an infinite number of storage accesses.
+	/// items to clear from the list.
+	///
+	/// ## WARNING
+	///
+	/// `None` will clear all items and should generally not be used in production as it could lead
+	/// to a very large number of storage accesses.
 	pub(crate) fn clear(maybe_count: Option) -> u32 {
 		crate::ListBags::::remove_all(maybe_count);
+		let pre = crate::ListNodes::::count();
 		crate::ListNodes::::remove_all(maybe_count);
-		if let Some(count) = maybe_count {
-			crate::CounterForListNodes::::mutate(|items| *items - count);
-			count
-		} else {
-			crate::CounterForListNodes::::take()
-		}
+		let post = crate::ListNodes::::count();
+		pre.saturating_sub(post)
 	}
 
 	/// Regenerate all of the data from the given ids.
@@ -274,17 +275,13 @@ impl List {
 		// new inserts are always the tail, so we must write the bag.
 		bag.put();
 
-		crate::CounterForListNodes::::mutate(|prev_count| {
-			*prev_count = prev_count.saturating_add(1)
-		});
-
 		crate::log!(
 			debug,
 			"inserted {:?} with weight {} into bag {:?}, new count is {}",
 			id,
 			weight,
 			bag_weight,
-			crate::CounterForListNodes::::get(),
+			crate::ListNodes::::count(),
 		);
 
 		Ok(())
@@ -331,10 +328,6 @@ impl List {
 			bag.put();
 		}
 
-		crate::CounterForListNodes::::mutate(|prev_count| {
-			*prev_count = prev_count.saturating_sub(count)
-		});
-
 		count
 	}
 
@@ -390,7 +383,7 @@ impl List {
 	/// is being used, after all other staking data (such as counter) has been updated. It checks:
 	///
 	/// * there are no duplicate ids,
-	/// * length of this list is in sync with `CounterForListNodes`,
+	/// * length of this list is in sync with `ListNodes::count()`,
 	/// * and sanity-checks all bags and nodes. This will cascade down all the checks and makes sure
 	/// all bags and nodes are checked per *any* update to `List`.
 	#[cfg(feature = "std")]
@@ -403,7 +396,7 @@ impl List {
 		);
 
 		let iter_count = Self::iter().count() as u32;
-		let stored_count = crate::CounterForListNodes::::get();
+		let stored_count = crate::ListNodes::::count();
 		let nodes_count = crate::ListNodes::::iter().count() as u32;
 		ensure!(iter_count == stored_count, "iter_count != stored_count");
 		ensure!(stored_count == nodes_count, "stored_count != nodes_count");
diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs
index 14802bac9d1d8..1c345df9a2fbd 100644
--- a/frame/bags-list/src/list/tests.rs
+++ b/frame/bags-list/src/list/tests.rs
@@ -18,7 +18,7 @@
 use super::*;
 use crate::{
 	mock::{test_utils::*, *},
-	CounterForListNodes, ListBags, ListNodes,
+	ListBags, ListNodes,
 };
 use frame_election_provider_support::SortedListProvider;
 use frame_support::{assert_ok, assert_storage_noop};
@@ -29,7 +29,7 @@ fn basic_setup_works() {
 		// syntactic sugar to create a raw node
 		let node = |id, prev, next, bag_upper| Node:: { id, prev, next, bag_upper };
 
-		assert_eq!(CounterForListNodes::::get(), 4);
+		assert_eq!(ListNodes::::count(), 4);
 		assert_eq!(ListNodes::::iter().count(), 4);
 		assert_eq!(ListBags::::iter().count(), 2);
 
@@ -249,10 +249,10 @@ mod list {
 
 	#[test]
 	fn remove_works() {
-		use crate::{CounterForListNodes, ListBags, ListNodes};
+		use crate::{ListBags, ListNodes};
 		let ensure_left = |id, counter| {
 			assert!(!ListNodes::::contains_key(id));
-			assert_eq!(CounterForListNodes::::get(), counter);
+			assert_eq!(ListNodes::::count(), counter);
 			assert_eq!(ListNodes::::iter().count() as u32, counter);
 		};
 
@@ -357,10 +357,19 @@ mod list {
 			assert_eq!(List::::sanity_check(), Err("duplicate identified"));
 		});
 
-		// ensure count is in sync with `CounterForListNodes`.
+		// ensure count is in sync with `ListNodes::count()`.
 		ExtBuilder::default().build_and_execute_no_post_check(|| {
-			crate::CounterForListNodes::::mutate(|counter| *counter += 1);
-			assert_eq!(crate::CounterForListNodes::::get(), 5);
+			assert_eq!(crate::ListNodes::::count(), 4);
+			// we do some wacky stuff here to get access to the counter, since it is (reasonably)
+			// not exposed as mutable in any sense.
+			frame_support::generate_storage_alias!(
+				BagsList,
+				CounterForListNodes
+				=> Value
+			);
+			CounterForListNodes::mutate(|counter| *counter += 1);
+			assert_eq!(crate::ListNodes::::count(), 5);
+
 			assert_eq!(List::::sanity_check(), Err("iter_count != stored_count"));
 		});
 	}
diff --git a/frame/bags-list/src/migrations.rs b/frame/bags-list/src/migrations.rs
new file mode 100644
index 0000000000000..8c907539c05f1
--- /dev/null
+++ b/frame/bags-list/src/migrations.rs
@@ -0,0 +1,49 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2021 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! The migrations of this pallet.
+
+use frame_support::traits::OnRuntimeUpgrade;
+
+/// A struct that does not migration, but only checks that the counter prefix exists and is correct.
+pub struct CheckCounterPrefix(sp_std::marker::PhantomData);
+impl OnRuntimeUpgrade for CheckCounterPrefix {
+	fn on_runtime_upgrade() -> frame_support::weights::Weight {
+		0
+	}
+
+	#[cfg(feature = "try-runtime")]
+	fn pre_upgrade() -> Result<(), &'static str> {
+		use frame_support::ensure;
+		// The old explicit storage item.
+		frame_support::generate_storage_alias!(BagsList, CounterForListNodes => Value);
+
+		// ensure that a value exists in the counter struct.
+		ensure!(
+			crate::ListNodes::::count() == CounterForListNodes::get().unwrap(),
+			"wrong list node counter"
+		);
+
+		crate::log!(
+			info,
+			"checked bags-list prefix to be correct and have {} nodes",
+			crate::ListNodes::::count()
+		);
+
+		Ok(())
+	}
+}
diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs
index e94017730668b..270d25855ccd4 100644
--- a/frame/bags-list/src/tests.rs
+++ b/frame/bags-list/src/tests.rs
@@ -340,7 +340,7 @@ mod sorted_list_provider {
 		let ensure_left = |id, counter| {
 			assert!(!ListNodes::::contains_key(id));
 			assert_eq!(BagsList::count(), counter);
-			assert_eq!(CounterForListNodes::::get(), counter);
+			assert_eq!(ListNodes::::count(), counter);
 			assert_eq!(ListNodes::::iter().count() as u32, counter);
 		};
 
diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs
index 0860a4ed541c6..51edf10890267 100644
--- a/frame/support/src/storage/types/counted_map.rs
+++ b/frame/support/src/storage/types/counted_map.rs
@@ -31,6 +31,7 @@ use crate::{
 	Never,
 };
 use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen, Ref};
+use sp_arithmetic::traits::Bounded;
 use sp_runtime::traits::Saturating;
 use sp_std::prelude::*;
 
@@ -262,9 +263,10 @@ where
 	}
 
 	/// Remove all value of the storage.
-	pub fn remove_all() {
-		CounterFor::::set(0u32);
-		::Map::remove_all(None);
+	pub fn remove_all(maybe_limit: Option) {
+		let leftover = Self::count().saturating_sub(maybe_limit.unwrap_or_else(Bounded::max_value));
+		CounterFor::::set(leftover);
+		::Map::remove_all(maybe_limit);
 	}
 
 	/// Iter over all value of the storage.
@@ -676,7 +678,7 @@ mod test {
 			assert_eq!(A::count(), 2);
 
 			// Remove all.
-			A::remove_all();
+			A::remove_all(None);
 
 			assert_eq!(A::count(), 0);
 			assert_eq!(A::initialize_counter(), 0);
@@ -907,7 +909,7 @@ mod test {
 			assert_eq!(B::count(), 2);
 
 			// Remove all.
-			B::remove_all();
+			B::remove_all(None);
 
 			assert_eq!(B::count(), 0);
 			assert_eq!(B::initialize_counter(), 0);

From 755569d202b4007179cc250279bad55df45b5f7d Mon Sep 17 00:00:00 2001
From: Denis Pisarev 
Date: Wed, 10 Nov 2021 11:39:30 +0100
Subject: [PATCH 0210/1472] CI: build docs with deps (#9884)

---
 .gitlab-ci.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 210bb447e4c7b..8826b29de9786 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -661,7 +661,7 @@ build-rustdoc:
     - ./crate-docs/
   script:
     # FIXME: it fails with `RUSTDOCFLAGS="-Dwarnings"`
-    - time cargo +nightly doc --no-deps --workspace --all-features --verbose
+    - time cargo +nightly doc --workspace --all-features --verbose
     - rm -f ./target/doc/.lock
     - mv ./target/doc ./crate-docs
     # FIXME: remove me after CI image gets nonroot

From 3374a73c9824638b8270062b104906a714ea14f9 Mon Sep 17 00:00:00 2001
From: Benjamin Kampmann 
Date: Wed, 10 Nov 2021 17:30:24 +0100
Subject: [PATCH 0211/1472] Intend to reactivate cargo-unleash check (#10167)

* Intend to reactivate cargo-unleash check

It appears the bug it was deactivated for has been resolved a while ago. Trying to reactivate the checks.

* adding missing cargo.toml metadata for BEEFY crates

* fix wrong version reference

* matching up versions

* disable faulty cache

* switching more versions to prerelease

* Revert "disable faulty cache"

This reverts commit 411a12ae444a9695a8bfea4458a868438d870b06.

* bump minor of sc-allocator to fix already-published-issue

* fixup another pre-released dependency problem

* temp switch to latest unleash

* fixing dependency version and features

* prometheus endpoint has also been changed

* fixing proposer metrics versioning

* fixing hex feature for beefy

* fix generate-bags feature selection

* fixup Cargo.lock

* upgrade prometheus dependencies

* missed one

* switch to latest release
---
 .gitlab-ci.yml                                | 28 ++++++-------
 Cargo.lock                                    | 42 +++++++++----------
 client/allocator/Cargo.toml                   |  2 +-
 client/api/Cargo.toml                         |  2 +-
 client/authority-discovery/Cargo.toml         |  2 +-
 client/basic-authorship/Cargo.toml            |  4 +-
 client/beefy/Cargo.toml                       |  4 +-
 client/beefy/rpc/Cargo.toml                   |  2 +
 client/cli/Cargo.toml                         |  2 +-
 client/consensus/aura/Cargo.toml              |  2 +-
 client/consensus/babe/Cargo.toml              |  2 +-
 client/consensus/common/Cargo.toml            |  2 +-
 client/consensus/manual-seal/Cargo.toml       |  2 +-
 client/consensus/pow/Cargo.toml               |  2 +-
 client/executor/Cargo.toml                    |  4 +-
 client/executor/common/Cargo.toml             |  6 +--
 client/executor/wasmi/Cargo.toml              |  2 +-
 client/executor/wasmtime/Cargo.toml           |  2 +-
 client/finality-grandpa/Cargo.toml            |  2 +-
 client/network-gossip/Cargo.toml              |  2 +-
 client/network/Cargo.toml                     |  2 +-
 client/offchain/Cargo.toml                    |  6 +--
 client/proposer-metrics/Cargo.toml            |  4 +-
 client/rpc-servers/Cargo.toml                 |  2 +-
 client/service/Cargo.toml                     |  2 +-
 client/service/test/Cargo.toml                |  2 +-
 client/transaction-pool/Cargo.toml            |  2 +-
 client/utils/Cargo.toml                       |  2 +-
 frame/beefy-mmr/Cargo.toml                    |  1 +
 frame/beefy-mmr/primitives/Cargo.toml         |  3 +-
 frame/beefy/Cargo.toml                        |  2 +
 primitives/arithmetic/Cargo.toml              |  2 +-
 primitives/beefy/Cargo.toml                   |  2 +
 primitives/core/Cargo.toml                    |  4 +-
 primitives/debug-derive/Cargo.toml            |  2 +-
 primitives/maybe-compressed-blob/Cargo.toml   |  2 +-
 primitives/panic-handler/Cargo.toml           |  2 +-
 primitives/serializer/Cargo.toml              |  2 +-
 primitives/state-machine/Cargo.toml           |  2 +-
 primitives/storage/Cargo.toml                 |  2 +-
 utils/frame/generate-bags/Cargo.toml          | 10 ++---
 .../generate-bags/node-runtime/Cargo.toml     |  2 +-
 utils/prometheus/Cargo.toml                   |  8 ++--
 utils/wasm-builder/Cargo.toml                 |  2 +-
 44 files changed, 97 insertions(+), 89 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8826b29de9786..aa275061088d6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -40,7 +40,7 @@ variables:                         &default-vars
   ARCH:                            "x86_64"
   CI_IMAGE:                        "paritytech/ci-linux:production"
   # FIXME set to release
-  CARGO_UNLEASH_INSTALL_PARAMS:    "--version 1.0.0-alpha.12"
+  CARGO_UNLEASH_INSTALL_PARAMS:    "--version 1.0.0-alpha.13"
   CARGO_UNLEASH_PKG_DEF:           "--skip node node-* pallet-template pallet-example-* subkey chain-spec-builder"
   VAULT_SERVER_URL:                "https://vault.parity-mgmt-vault.parity.io"
   VAULT_AUTH_PATH:                 "gitlab-parity-io-jwt"
@@ -455,20 +455,20 @@ test-linux-stable:                 &test-linux
     - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout
     - sccache -s
 
-#unleash-check:
-  #stage:                           test
-  #<<:                              *docker-env
-  #<<:                              *test-refs-no-trigger
-  #script:
-    #- cargo install cargo-unleash ${CARGO_UNLEASH_INSTALL_PARAMS}
-    #- cargo unleash de-dev-deps
+unleash-check:
+  stage:                           test
+  <<:                              *docker-env
+  <<:                              *test-refs-no-trigger
+  script:
+    - cargo install cargo-unleash ${CARGO_UNLEASH_INSTALL_PARAMS}
+    - cargo unleash de-dev-deps
     # Reuse build artifacts when running checks (cuts down check time by 3x)
     # TODO: Implement this optimization in cargo-unleash rather than here
-    #- mkdir -p target/unleash
-    #- export CARGO_TARGET_DIR=target/unleash
-    #- cargo unleash check ${CARGO_UNLEASH_PKG_DEF}
+    - mkdir -p target/unleash
+    - export CARGO_TARGET_DIR=target/unleash
+    - cargo unleash check ${CARGO_UNLEASH_PKG_DEF}
   # FIXME: this job must not fail, or unleash-to-crates-io will publish broken stuff
-  #allow_failure:                   true
+  allow_failure:                   true
 
 test-frame-examples-compile-to-wasm:
   # into one job
@@ -872,9 +872,7 @@ unleash-to-crates-io:
   <<:                              *vault-secrets
   rules:
     - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/
-    # FIXME: wait until https://github.com/paritytech/cargo-unleash/issues/50 is fixed, also
-    # remove allow_failure: true on the check job
-    # - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/              # i.e. v1.0, v2.1rc1
+    - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/              # i.e. v1.0, v2.1rc1
   script:
     - cargo install cargo-unleash ${CARGO_UNLEASH_INSTALL_PARAMS}
     - cargo unleash em-dragons --no-check --owner github:paritytech:core-devs ${CARGO_UNLEASH_PKG_DEF}
diff --git a/Cargo.lock b/Cargo.lock
index a7bb471f90d8c..69cd80e292f88 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2400,7 +2400,7 @@ checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
 
 [[package]]
 name = "generate-bags"
-version = "3.0.0"
+version = "4.0.0-dev"
 dependencies = [
  "chrono",
  "frame-election-provider-support",
@@ -2698,9 +2698,9 @@ dependencies = [
 
 [[package]]
 name = "httparse"
-version = "1.4.1"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
+checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
 
 [[package]]
 name = "httpdate"
@@ -2744,9 +2744,9 @@ dependencies = [
 
 [[package]]
 name = "hyper"
-version = "0.14.11"
+version = "0.14.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11"
+checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b"
 dependencies = [
  "bytes 1.0.1",
  "futures-channel",
@@ -2773,7 +2773,7 @@ checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64"
 dependencies = [
  "ct-logs",
  "futures-util",
- "hyper 0.14.11",
+ "hyper 0.14.14",
  "log 0.4.14",
  "rustls",
  "rustls-native-certs",
@@ -2789,7 +2789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
 dependencies = [
  "bytes 1.0.1",
- "hyper 0.14.11",
+ "hyper 0.14.14",
  "native-tls",
  "tokio",
  "tokio-native-tls",
@@ -3012,7 +3012,7 @@ checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a"
 dependencies = [
  "derive_more",
  "futures 0.3.16",
- "hyper 0.14.11",
+ "hyper 0.14.14",
  "hyper-tls",
  "jsonrpc-core",
  "jsonrpc-pubsub",
@@ -3068,7 +3068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff"
 dependencies = [
  "futures 0.3.16",
- "hyper 0.14.11",
+ "hyper 0.14.14",
  "jsonrpc-core",
  "jsonrpc-server-utils",
  "log 0.4.14",
@@ -3164,7 +3164,7 @@ dependencies = [
  "beef",
  "futures-channel",
  "futures-util",
- "hyper 0.14.11",
+ "hyper 0.14.14",
  "log 0.4.14",
  "serde",
  "serde_json",
@@ -6815,9 +6815,9 @@ dependencies = [
 
 [[package]]
 name = "prometheus"
-version = "0.12.0"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5986aa8d62380092d2f50f8b1cdba9cb9b6731ffd4b25b51fd126b6c3e05b99c"
+checksum = "b7f64969ffd5dd8f39bd57a68ac53c163a095ed9d0fb707146da1b27025a3504"
 dependencies = [
  "cfg-if 1.0.0",
  "fnv",
@@ -7584,7 +7584,7 @@ dependencies = [
 
 [[package]]
 name = "sc-allocator"
-version = "4.0.0-dev"
+version = "4.1.0-dev"
 dependencies = [
  "log 0.4.14",
  "sp-core",
@@ -8355,7 +8355,7 @@ dependencies = [
  "futures 0.3.16",
  "futures-timer 3.0.2",
  "hex",
- "hyper 0.14.11",
+ "hyper 0.14.14",
  "hyper-rustls",
  "lazy_static",
  "log 0.4.14",
@@ -8397,7 +8397,7 @@ dependencies = [
 
 [[package]]
 name = "sc-proposer-metrics"
-version = "0.9.0"
+version = "0.10.0-dev"
 dependencies = [
  "log 0.4.14",
  "substrate-prometheus-endpoint",
@@ -9496,7 +9496,7 @@ dependencies = [
 
 [[package]]
 name = "sp-debug-derive"
-version = "3.0.0"
+version = "4.0.0-dev"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -9597,7 +9597,7 @@ dependencies = [
 
 [[package]]
 name = "sp-maybe-compressed-blob"
-version = "4.0.0-dev"
+version = "4.1.0-dev"
 dependencies = [
  "zstd",
 ]
@@ -9657,7 +9657,7 @@ dependencies = [
 
 [[package]]
 name = "sp-panic-handler"
-version = "3.0.0"
+version = "4.0.0-dev"
 dependencies = [
  "backtrace",
  "lazy_static",
@@ -9788,7 +9788,7 @@ dependencies = [
 
 [[package]]
 name = "sp-serializer"
-version = "3.0.0"
+version = "4.0.0-dev"
 dependencies = [
  "serde",
  "serde_json",
@@ -10171,12 +10171,12 @@ dependencies = [
 
 [[package]]
 name = "substrate-prometheus-endpoint"
-version = "0.9.0"
+version = "0.10.0-dev"
 dependencies = [
  "async-std",
  "derive_more",
  "futures-util",
- "hyper 0.14.11",
+ "hyper 0.14.14",
  "log 0.4.14",
  "prometheus",
  "tokio",
diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml
index 2b37c192c6e3e..6d324b09acde5 100644
--- a/client/allocator/Cargo.toml
+++ b/client/allocator/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sc-allocator"
-version = "4.0.0-dev"
+version = "4.1.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "Apache-2.0"
diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml
index 7b2952552a3d0..431d6e2fb0157 100644
--- a/client/api/Cargo.toml
+++ b/client/api/Cargo.toml
@@ -36,7 +36,7 @@ sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-mach
 sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" }
 sp-storage = { version = "4.0.0-dev", path = "../../primitives/storage" }
 sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" }
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.9.0", path = "../../utils/prometheus" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" }
 
 [dev-dependencies]
 sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" }
diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml
index dc4b929756810..b1d9d4ebd3935 100644
--- a/client/authority-discovery/Cargo.toml
+++ b/client/authority-discovery/Cargo.toml
@@ -25,7 +25,7 @@ futures-timer = "3.0.1"
 ip_network = "0.4.0"
 libp2p = { version = "0.39.1", default-features = false, features = ["kad"] }
 log = "0.4.8"
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.9.0" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" }
 prost = "0.8"
 rand = "0.7.2"
 sc-client-api = { version = "4.0.0-dev", path = "../api" }
diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml
index 96ab698f36213..4bfc3ca50c83f 100644
--- a/client/basic-authorship/Cargo.toml
+++ b/client/basic-authorship/Cargo.toml
@@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" }
 futures = "0.3.9"
 futures-timer = "3.0.1"
 log = "0.4.8"
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.9.0"}
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"}
 sp-api = { version = "4.0.0-dev", path = "../../primitives/api" }
 sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" }
 sp-core = { version = "4.0.0-dev", path = "../../primitives/core" }
@@ -28,7 +28,7 @@ sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" }
 sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" }
 sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../client/transaction-pool/api" }
 sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" }
-sc-proposer-metrics = { version = "0.9.0", path = "../proposer-metrics" }
+sc-proposer-metrics = { version = "0.10.0-dev", path = "../proposer-metrics" }
 
 [dev-dependencies]
 sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" }
diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml
index 60f9fde030800..96e5bc4ffbf31 100644
--- a/client/beefy/Cargo.toml
+++ b/client/beefy/Cargo.toml
@@ -4,6 +4,8 @@ version = "4.0.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
+repository = "https://github.com/paritytech/substrate"
+description = "BEEFY Client gadget for substrate"
 
 [dependencies]
 fnv = "1.0.6"
@@ -14,7 +16,7 @@ thiserror = "1.0"
 wasm-timer = "0.2.5"
 
 codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive"] }
-prometheus = { version = "0.9.0", package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" }
+prometheus = { version = "0.10.0-dev", package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" }
 
 sp-api = { version = "4.0.0-dev", path = "../../primitives/api" }
 sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" }
diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml
index 47fd2b740370c..594736841ed27 100644
--- a/client/beefy/rpc/Cargo.toml
+++ b/client/beefy/rpc/Cargo.toml
@@ -4,6 +4,8 @@ version = "4.0.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
+repository = "https://github.com/paritytech/substrate"
+description = "RPC for the BEEFY Client gadget for substrate"
 
 [dependencies]
 futures = "0.3.16"
diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml
index 4b6ef3bab9505..6107206be34e8 100644
--- a/client/cli/Cargo.toml
+++ b/client/cli/Cargo.toml
@@ -25,7 +25,7 @@ rand = "0.7.3"
 tiny-bip39 = "0.8.2"
 serde_json = "1.0.68"
 sc-keystore = { version = "4.0.0-dev", path = "../keystore" }
-sp-panic-handler = { version = "3.0.0", path = "../../primitives/panic-handler" }
+sp-panic-handler = { version = "4.0.0-dev", path = "../../primitives/panic-handler" }
 sc-client-api = { version = "4.0.0-dev", path = "../api" }
 sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" }
 sc-network = { version = "0.10.0-dev", path = "../network" }
diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml
index 62d7b3d5327ad..152c40f78f9d4 100644
--- a/client/consensus/aura/Cargo.toml
+++ b/client/consensus/aura/Cargo.toml
@@ -33,7 +33,7 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" }
 sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" }
 sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" }
 sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" }
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.9.0" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" }
 async-trait = "0.1.50"
 # We enable it only for web-wasm check
 # See https://docs.rs/getrandom/0.2.1/getrandom/#webassembly-support
diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml
index 8430ca39c9cb7..7945ecc4ec793 100644
--- a/client/consensus/babe/Cargo.toml
+++ b/client/consensus/babe/Cargo.toml
@@ -42,7 +42,7 @@ sp-consensus-vrf = { version = "0.10.0-dev", path = "../../../primitives/consens
 sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" }
 sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" }
 fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" }
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.9.0" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" }
 futures = "0.3.9"
 parking_lot = "0.11.1"
 log = "0.4.8"
diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml
index d63d124ed60e5..3f8380d3f81bc 100644
--- a/client/consensus/common/Cargo.toml
+++ b/client/consensus/common/Cargo.toml
@@ -28,7 +28,7 @@ sc-utils = { version = "4.0.0-dev", path = "../../utils" }
 sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" }
 parking_lot = "0.11.1"
 serde = { version = "1.0", features = ["derive"] }
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.9.0" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" }
 async-trait = "0.1.42"
 
 [dev-dependencies]
diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml
index a662ebf01011d..a7679f53ea9e8 100644
--- a/client/consensus/manual-seal/Cargo.toml
+++ b/client/consensus/manual-seal/Cargo.toml
@@ -42,7 +42,7 @@ sp-api = { path = "../../../primitives/api", version = "4.0.0-dev" }
 sc-transaction-pool-api = { path = "../../../client/transaction-pool/api", version = "4.0.0-dev" }
 sp-timestamp = { path = "../../../primitives/timestamp", version = "4.0.0-dev" }
 
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.9.0" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" }
 
 [dev-dependencies]
 tokio = { version = "1.10.0", features = ["rt-multi-thread", "macros"] }
diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml
index bc7c01181e41b..841631fce7cc9 100644
--- a/client/consensus/pow/Cargo.toml
+++ b/client/consensus/pow/Cargo.toml
@@ -29,5 +29,5 @@ futures = "0.3.16"
 futures-timer = "3.0.1"
 parking_lot = "0.11.1"
 derive_more = "0.99.2"
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.9.0"}
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev"}
 async-trait = "0.1.50"
diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml
index ef66d8072b537..54c4a91d72805 100644
--- a/client/executor/Cargo.toml
+++ b/client/executor/Cargo.toml
@@ -20,7 +20,7 @@ sp-core = { version = "4.0.0-dev", path = "../../primitives/core" }
 sp-tasks = { version = "4.0.0-dev", path = "../../primitives/tasks" }
 sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" }
 sp-version = { version = "4.0.0-dev", path = "../../primitives/version" }
-sp-panic-handler = { version = "3.0.0", path = "../../primitives/panic-handler" }
+sp-panic-handler = { version = "4.0.0-dev", path = "../../primitives/panic-handler" }
 wasmi = "0.9.1"
 lazy_static = "1.4.0"
 sp-api = { version = "4.0.0-dev", path = "../../primitives/api" }
@@ -42,7 +42,7 @@ sc-runtime-test = { version = "2.0.0", path = "runtime-test" }
 substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" }
 sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" }
 sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" }
-sp-maybe-compressed-blob = { version = "4.0.0-dev", path = "../../primitives/maybe-compressed-blob" }
+sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" }
 sc-tracing = { version = "4.0.0-dev", path = "../tracing" }
 tracing = "0.1.29"
 tracing-subscriber = "0.2.19"
diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml
index 7ac747bf967bd..2d9f4672768e9 100644
--- a/client/executor/common/Cargo.toml
+++ b/client/executor/common/Cargo.toml
@@ -19,10 +19,10 @@ pwasm-utils = "0.18.0"
 codec = { package = "parity-scale-codec", version = "2.0.0" }
 wasmi = "0.9.1"
 sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" }
-sc-allocator = { version = "4.0.0-dev", path = "../../allocator" }
+sc-allocator = { version = "4.1.0-dev", path = "../../allocator" }
 sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-interface" }
-sp-maybe-compressed-blob = { version = "4.0.0-dev", path = "../../../primitives/maybe-compressed-blob" }
-sp-serializer = { version = "3.0.0", path = "../../../primitives/serializer" }
+sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" }
+sp-serializer = { version = "4.0.0-dev", path = "../../../primitives/serializer" }
 thiserror = "1.0.21"
 environmental = "1.1.3"
 
diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml
index 255a470b374da..871a8aa68b626 100644
--- a/client/executor/wasmi/Cargo.toml
+++ b/client/executor/wasmi/Cargo.toml
@@ -18,7 +18,7 @@ log = "0.4.8"
 wasmi = "0.9.1"
 codec = { package = "parity-scale-codec", version = "2.0.0" }
 sc-executor-common = { version = "0.10.0-dev", path = "../common" }
-sc-allocator = { version = "4.0.0-dev", path = "../../allocator" }
+sc-allocator = { version = "4.1.0-dev", path = "../../allocator" }
 sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-interface" }
 sp-runtime-interface = { version = "4.0.0-dev", path = "../../../primitives/runtime-interface" }
 sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" }
diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml
index e52a53f71c06e..006415869c925 100644
--- a/client/executor/wasmtime/Cargo.toml
+++ b/client/executor/wasmtime/Cargo.toml
@@ -22,7 +22,7 @@ sc-executor-common = { version = "0.10.0-dev", path = "../common" }
 sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-interface" }
 sp-runtime-interface = { version = "4.0.0-dev", path = "../../../primitives/runtime-interface" }
 sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" }
-sc-allocator = { version = "4.0.0-dev", path = "../../allocator" }
+sc-allocator = { version = "4.1.0-dev", path = "../../allocator" }
 wasmtime = { version = "0.31.0", default-features = false, features = [
     "cache",
     "cranelift",
diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml
index fd0b52cd1f70b..43511ea59f146 100644
--- a/client/finality-grandpa/Cargo.toml
+++ b/client/finality-grandpa/Cargo.toml
@@ -41,7 +41,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" }
 sc-network = { version = "0.10.0-dev", path = "../network" }
 sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" }
 sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" }
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.9.0" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" }
 sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" }
 finality-grandpa = { version = "0.14.4", features = ["derive-codec"] }
 async-trait = "0.1.50"
diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml
index e17d9601eafc3..e11cb8dbe85d6 100644
--- a/client/network-gossip/Cargo.toml
+++ b/client/network-gossip/Cargo.toml
@@ -20,7 +20,7 @@ futures-timer = "3.0.1"
 libp2p = { version = "0.39.1", default-features = false }
 log = "0.4.8"
 lru = "0.7.0"
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.9.0", path = "../../utils/prometheus" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" }
 sc-network = { version = "0.10.0-dev", path = "../network" }
 sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" }
 tracing = "0.1.29"
diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml
index 19ae5dd97e425..eb91dd145e549 100644
--- a/client/network/Cargo.toml
+++ b/client/network/Cargo.toml
@@ -40,7 +40,7 @@ lru = "0.7.0"
 log = "0.4.8"
 parking_lot = "0.11.1"
 pin-project = "1.0.8"
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.9.0", path = "../../utils/prometheus" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" }
 prost = "0.8"
 rand = "0.7.2"
 sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" }
diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml
index ee697b32e1e4b..c93eec85888dc 100644
--- a/client/offchain/Cargo.toml
+++ b/client/offchain/Cargo.toml
@@ -17,8 +17,8 @@ bytes = "1.0"
 codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] }
 hex = "0.4"
 fnv = "1.0.6"
-futures = "0.3.9"
-futures-timer = "3.0.1"
+futures = "0.3.16"
+futures-timer = "3.0.2"
 log = "0.4.8"
 num_cpus = "1.10"
 parking_lot = "0.11.1"
@@ -31,7 +31,7 @@ sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" }
 sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" }
 sc-utils = { version = "4.0.0-dev", path = "../utils" }
 threadpool = "1.7"
-hyper = "0.14.11"
+hyper = { version = "0.14.14", features = ["stream"] }
 hyper-rustls = "0.22.1"
 once_cell = "1.8"
 
diff --git a/client/proposer-metrics/Cargo.toml b/client/proposer-metrics/Cargo.toml
index 93c4cce93ca65..1a4b1fd4ce2c9 100644
--- a/client/proposer-metrics/Cargo.toml
+++ b/client/proposer-metrics/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sc-proposer-metrics"
-version = "0.9.0"
+version = "0.10.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
@@ -14,4 +14,4 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 log = "0.4.8"
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.9.0"}
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"}
diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml
index b3f408cc59806..f0ae6172d6d9e 100644
--- a/client/rpc-servers/Cargo.toml
+++ b/client/rpc-servers/Cargo.toml
@@ -17,7 +17,7 @@ futures = "0.3.16"
 jsonrpc-core = "18.0.0"
 pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" }
 log = "0.4.8"
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.9.0"}
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"}
 serde_json = "1.0.68"
 tokio = "1.10"
 http = { package = "jsonrpc-http-server", version = "18.0.0" }
diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml
index 5c22c1e4fca1c..97b0f4e461c87 100644
--- a/client/service/Cargo.toml
+++ b/client/service/Cargo.toml
@@ -69,7 +69,7 @@ sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-build
 sc-informant = { version = "0.10.0-dev", path = "../informant" }
 sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" }
 sc-offchain = { version = "4.0.0-dev", path = "../offchain" }
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.9.0" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" }
 sc-tracing = { version = "4.0.0-dev", path = "../tracing" }
 sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" }
 tracing = "0.1.29"
diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml
index 49eca272ac75c..03967db15f678 100644
--- a/client/service/test/Cargo.toml
+++ b/client/service/test/Cargo.toml
@@ -40,6 +40,6 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils
 sc-client-api = { version = "4.0.0-dev", path = "../../api" }
 sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" }
 sc-executor = { version = "0.10.0-dev", path = "../../executor" }
-sp-panic-handler = { version = "3.0.0", path = "../../../primitives/panic-handler" }
+sp-panic-handler = { version = "4.0.0-dev", path = "../../../primitives/panic-handler" }
 parity-scale-codec = "2.3.1"
 sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" }
diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml
index 6d05125002f2e..99f1f3788ec0e 100644
--- a/client/transaction-pool/Cargo.toml
+++ b/client/transaction-pool/Cargo.toml
@@ -20,7 +20,7 @@ intervalier = "0.4.0"
 log = "0.4.8"
 parity-util-mem = { version = "0.10.0", default-features = false, features = ["primitive-types"] }
 parking_lot = "0.11.1"
-prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.9.0"}
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"}
 sc-client-api = { version = "4.0.0-dev", path = "../api" }
 sp-api = { version = "4.0.0-dev", path = "../../primitives/api" }
 sp-core = { version = "4.0.0-dev", path = "../../primitives/core" }
diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml
index 6d04fd4e9acdf..827164b702c6f 100644
--- a/client/utils/Cargo.toml
+++ b/client/utils/Cargo.toml
@@ -12,7 +12,7 @@ readme = "README.md"
 [dependencies]
 futures = "0.3.9"
 lazy_static = "1.4.0"
-prometheus = { version = "0.12.0", default-features = false }
+prometheus = { version = "0.13.0", default-features = false }
 futures-timer = "3.0.2"
 
 [features]
diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml
index 0a72ee193b3a7..b99b6f7e9feaa 100644
--- a/frame/beefy-mmr/Cargo.toml
+++ b/frame/beefy-mmr/Cargo.toml
@@ -5,6 +5,7 @@ authors = ["Parity Technologies "]
 edition = "2021"
 license = "Apache-2.0"
 description = "BEEFY + MMR runtime utilities"
+repository = "https://github.com/paritytech/substrate"
 
 [dependencies]
 hex = { version = "0.4", optional = true }
diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/frame/beefy-mmr/primitives/Cargo.toml
index 3669ba4c2286c..b54ac225e7818 100644
--- a/frame/beefy-mmr/primitives/Cargo.toml
+++ b/frame/beefy-mmr/primitives/Cargo.toml
@@ -4,6 +4,7 @@ version = "4.0.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "Apache-2.0"
+repository = "https://github.com/paritytech/substrate"
 description = "A no-std/Substrate compatible library to construct binary merkle tree."
 
 [dependencies]
@@ -17,7 +18,7 @@ hex = "0.4"
 hex-literal = "0.3"
 
 [features]
-debug = ["hex", "log"]
+debug = ["hex", "hex/std", "log"]
 default = ["std", "debug", "keccak"]
 keccak = ["tiny-keccak"]
 std = []
diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml
index a8b516aac66ca..7e1cec9d438ea 100644
--- a/frame/beefy/Cargo.toml
+++ b/frame/beefy/Cargo.toml
@@ -4,6 +4,8 @@ version = "4.0.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "Apache-2.0"
+repository = "https://github.com/paritytech/substrate"
+description = "BEEFY FRAME pallet"
 
 [dependencies]
 codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] }
diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml
index e6fa1759774ed..139a04180828c 100644
--- a/primitives/arithmetic/Cargo.toml
+++ b/primitives/arithmetic/Cargo.toml
@@ -24,7 +24,7 @@ static_assertions = "1.1.0"
 num-traits = { version = "0.2.8", default-features = false }
 sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" }
 serde = { version = "1.0.126", optional = true, features = ["derive"] }
-sp-debug-derive = { version = "3.0.0", default-features = false, path = "../debug-derive" }
+sp-debug-derive = { version = "4.0.0-dev", default-features = false, path = "../debug-derive" }
 
 [dev-dependencies]
 rand = "0.7.2"
diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml
index 83472f54c5135..23e98012027c7 100644
--- a/primitives/beefy/Cargo.toml
+++ b/primitives/beefy/Cargo.toml
@@ -4,6 +4,8 @@ version = "4.0.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "Apache-2.0"
+repository = "https://github.com/paritytech/substrate"
+description = "Primitives for BEEFY protocol."
 
 [dependencies]
 codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] }
diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml
index 9948b2e968c26..9e31ba644c250 100644
--- a/primitives/core/Cargo.toml
+++ b/primitives/core/Cargo.toml
@@ -40,7 +40,7 @@ zeroize = { version = "1.4.2", default-features = false }
 secrecy = { version = "0.8.0", default-features = false }
 lazy_static = { version = "1.4.0", default-features = false, optional = true }
 parking_lot = { version = "0.11.1", optional = true }
-sp-debug-derive = { version = "3.0.0", default-features = false, path = "../debug-derive" }
+sp-debug-derive = { version = "4.0.0-dev", default-features = false, path = "../debug-derive" }
 sp-externalities = { version = "0.10.0-dev", optional = true, path = "../externalities" }
 sp-storage = { version = "4.0.0-dev", default-features = false, path = "../storage" }
 parity-util-mem = { version = "0.10.0", default-features = false, features = [
@@ -72,7 +72,7 @@ ss58-registry = { version = "1.5.0", default-features = false }
 sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" }
 
 [dev-dependencies]
-sp-serializer = { version = "3.0.0", path = "../serializer" }
+sp-serializer = { version = "4.0.0-dev", path = "../serializer" }
 hex-literal = "0.3.3"
 rand = "0.7.2"
 criterion = "0.3.3"
diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml
index a2f77b7591fe1..49b8ac832cf0f 100644
--- a/primitives/debug-derive/Cargo.toml
+++ b/primitives/debug-derive/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sp-debug-derive"
-version = "3.0.0"
+version = "4.0.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "Apache-2.0"
diff --git a/primitives/maybe-compressed-blob/Cargo.toml b/primitives/maybe-compressed-blob/Cargo.toml
index 95ba9b3324127..dbed41571b149 100644
--- a/primitives/maybe-compressed-blob/Cargo.toml
+++ b/primitives/maybe-compressed-blob/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sp-maybe-compressed-blob"
-version = "4.0.0-dev"
+version = "4.1.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "Apache-2.0"
diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml
index 0845e175c2377..b7f3b6b5cb4da 100644
--- a/primitives/panic-handler/Cargo.toml
+++ b/primitives/panic-handler/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sp-panic-handler"
-version = "3.0.0"
+version = "4.0.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "Apache-2.0"
diff --git a/primitives/serializer/Cargo.toml b/primitives/serializer/Cargo.toml
index 5b2d499279a47..2b2acb8dbc373 100644
--- a/primitives/serializer/Cargo.toml
+++ b/primitives/serializer/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sp-serializer"
-version = "3.0.0"
+version = "4.0.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "Apache-2.0"
diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml
index 343151a50a927..c919d7fbef6ad 100644
--- a/primitives/state-machine/Cargo.toml
+++ b/primitives/state-machine/Cargo.toml
@@ -22,7 +22,7 @@ trie-db = { version = "0.22.6", default-features = false }
 trie-root = { version = "0.16.0", default-features = false }
 sp-trie = { version = "4.0.0-dev", path = "../trie", default-features = false }
 sp-core = { version = "4.0.0-dev", path = "../core", default-features = false }
-sp-panic-handler = { version = "3.0.0", path = "../panic-handler", optional = true }
+sp-panic-handler = { version = "4.0.0-dev", path = "../panic-handler", optional = true }
 codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
 num-traits = { version = "0.2.8", default-features = false }
 rand = { version = "0.7.2", optional = true }
diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml
index 2413c45a7312e..c9166a5bbba07 100644
--- a/primitives/storage/Cargo.toml
+++ b/primitives/storage/Cargo.toml
@@ -18,7 +18,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" }
 serde = { version = "1.0.126", optional = true, features = ["derive"] }
 impl-serde = { version = "0.3.1", optional = true }
 ref-cast = "1.0.0"
-sp-debug-derive = { version = "3.0.0", default-features = false, path = "../debug-derive" }
+sp-debug-derive = { version = "4.0.0-dev", default-features = false, path = "../debug-derive" }
 codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
 
 [features]
diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml
index 03382878710b7..225584b69069e 100644
--- a/utils/frame/generate-bags/Cargo.toml
+++ b/utils/frame/generate-bags/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "generate-bags"
-version = "3.0.0"
+version = "4.0.0-dev"
 authors = ["Parity Technologies "]
 edition = "2021"
 license = "Apache-2.0"
@@ -11,13 +11,13 @@ readme = "README.md"
 
 [dependencies]
 # FRAME
-frame-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/support" }
+frame-support = { version = "4.0.0-dev", path = "../../../frame/support" }
 frame-election-provider-support = { version = "4.0.0-dev", path = "../../../frame/election-provider-support", features = ["runtime-benchmarks"] }
-frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" }
-pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" }
+frame-system = { version = "4.0.0-dev", path = "../../../frame/system" }
+pallet-staking = { version = "4.0.0-dev", path = "../../../frame/staking" }
 
 # primitives
-sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" }
+sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" }
 
 # third party
 chrono = { version = "0.4.19" }
diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml
index 5029e049361c9..b0256722f466c 100644
--- a/utils/frame/generate-bags/node-runtime/Cargo.toml
+++ b/utils/frame/generate-bags/node-runtime/Cargo.toml
@@ -11,7 +11,7 @@ readme = "README.md"
 
 [dependencies]
 node-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runtime" }
-generate-bags = { version = "3.0.0", path = "../" }
+generate-bags = { version = "4.0.0-dev", path = "../" }
 
 # third-party
 structopt = "0.3.21"
diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml
index 78bd68ac9e3a5..390a1c733cbd7 100644
--- a/utils/prometheus/Cargo.toml
+++ b/utils/prometheus/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 description = "Endpoint to expose Prometheus metrics"
 name = "substrate-prometheus-endpoint"
-version = "0.9.0"
+version = "0.10.0-dev"
 license = "Apache-2.0"
 authors = ["Parity Technologies "]
 edition = "2021"
@@ -14,13 +14,13 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 log = "0.4.8"
-prometheus = { version = "0.12.0", default-features = false }
+prometheus = { version = "0.13.0", default-features = false }
 futures-util = { version = "0.3.17", default-features = false, features = ["io"] }
 derive_more = "0.99"
 async-std = { version = "1.10.0", features = ["unstable"] }
 tokio = "1.10"
-hyper = { version = "0.14.11", default-features = false, features = ["http1", "server", "tcp"] }
+hyper = { version = "0.14.14", default-features = false, features = ["http1", "server", "tcp"] }
 
 [dev-dependencies]
-hyper = { version = "0.14.11", features = ["client"] }
+hyper = { version = "0.14.14", features = ["client"] }
 tokio = { version = "1.10", features = ["rt-multi-thread"] }
diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml
index d8802c432f55d..88318f4f0d54c 100644
--- a/utils/wasm-builder/Cargo.toml
+++ b/utils/wasm-builder/Cargo.toml
@@ -20,4 +20,4 @@ toml = "0.5.4"
 walkdir = "2.3.2"
 wasm-gc-api = "0.1.11"
 ansi_term = "0.12.1"
-sp-maybe-compressed-blob = { version = "4.0.0-dev", path = "../../primitives/maybe-compressed-blob" }
+sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" }

From 2ab769819e8a3ee869459b78cbb98cc749728cc3 Mon Sep 17 00:00:00 2001
From: sander2 
Date: Thu, 11 Nov 2021 09:23:34 +0100
Subject: [PATCH 0212/1472] expose substrate-cli service (#10229)

* expose substrate-cli service

* chore: undo change to new_full (since new_full_base is exposed already)
---
 bin/node/cli/src/service.rs | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs
index 2220614ebaf2a..a022d501d0155 100644
--- a/bin/node/cli/src/service.rs
+++ b/bin/node/cli/src/service.rs
@@ -30,7 +30,7 @@ use sc_client_api::{BlockBackend, ExecutorProvider};
 use sc_consensus_babe::{self, SlotProportion};
 use sc_executor::NativeElseWasmExecutor;
 use sc_network::{Event, NetworkService};
-use sc_service::{config::Configuration, error::Error as ServiceError, TaskManager};
+use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager};
 use sc_telemetry::{Telemetry, TelemetryWorker};
 use sp_api::ProvideRuntimeApi;
 use sp_core::crypto::Pair;
@@ -298,6 +298,8 @@ pub struct NewFullBase {
 	pub network: Arc::Hash>>,
 	/// The transaction pool of the node.
 	pub transaction_pool: Arc,
+	/// The rpc handlers of the node.
+	pub rpc_handlers: RpcHandlers,
 }
 
 /// Creates a full service from the configuration.
@@ -358,7 +360,7 @@ pub fn new_full_base(
 	let enable_grandpa = !config.disable_grandpa;
 	let prometheus_registry = config.prometheus_registry().cloned();
 
-	let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
+	let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
 		config,
 		backend,
 		client: client.clone(),
@@ -507,7 +509,7 @@ pub fn new_full_base(
 	}
 
 	network_starter.start_network();
-	Ok(NewFullBase { task_manager, client, network, transaction_pool })
+	Ok(NewFullBase { task_manager, client, network, transaction_pool, rpc_handlers })
 }
 
 /// Builds a new service for a full client.

From 7b1c81f5b4966548fc281d3d164e317e338ef2d6 Mon Sep 17 00:00:00 2001
From: David 
Date: Thu, 11 Nov 2021 12:29:28 +0100
Subject: [PATCH 0213/1472] Upgrade jsonrpsee to v0.4.1 (#10022)

* Upgrade jsonrpsee to v0.4.1

* remove needless BlockT trait bound

* use default wss port in URL

* Fix try_runtime build

* Partially fix for "remote-tests" feature

* Review feedback

* fmt

* Sort out trait bounds for benches

* Fmt

* fmt again?

* fmt with nightly-2021-09-13

* Upgrade try-runtime as well

* fmt

Co-authored-by: Niklas Adolfsson 
---
 Cargo.lock                                    | 126 +++++++-----------
 bin/node/cli/Cargo.toml                       |   2 +-
 frame/bags-list/remote-tests/src/migration.rs |   4 +-
 .../remote-tests/src/sanity_check.rs          |   4 +-
 frame/bags-list/remote-tests/src/snapshot.rs  |   4 +-
 .../procedural/src/construct_runtime/parse.rs |   2 +-
 utils/frame/remote-externalities/Cargo.toml   |   5 +-
 utils/frame/remote-externalities/src/lib.rs   | 109 ++++++++-------
 .../frame/remote-externalities/src/rpc_api.rs |  27 ++--
 utils/frame/try-runtime/cli/Cargo.toml        |   4 +-
 .../cli/src/commands/follow_chain.rs          |   8 +-
 utils/frame/try-runtime/cli/src/lib.rs        |   7 +-
 12 files changed, 128 insertions(+), 174 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 69cd80e292f88..5ae937ad22d4f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -144,9 +144,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
 
 [[package]]
 name = "arrayvec"
-version = "0.7.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a2f58b0bb10c380af2b26e57212856b8c9a59e0925b4c20f4a174a49734eaf7"
+checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd"
 
 [[package]]
 name = "asn1_der"
@@ -419,19 +419,6 @@ dependencies = [
  "rustc-demangle",
 ]
 
-[[package]]
-name = "bae"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec107f431ee3d8a8e45e6dd117adab769556ef463959e77bf6a4888d5fd500cf"
-dependencies = [
- "heck",
- "proc-macro-error 0.4.12",
- "proc-macro2",
- "quote",
- "syn",
-]
-
 [[package]]
 name = "base-x"
 version = "0.2.8"
@@ -477,9 +464,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
 
 [[package]]
 name = "beef"
-version = "0.5.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6736e2428df2ca2848d846c43e88745121a6654696e349ce0054a420815a7409"
+checksum = "bed554bd50246729a1ec158d08aa3235d1b69d94ad120ebe187e28894787e736"
 dependencies = [
  "serde",
 ]
@@ -1634,7 +1621,7 @@ dependencies = [
  "bitflags",
  "byteorder",
  "lazy_static",
- "proc-macro-error 1.0.4",
+ "proc-macro-error",
  "proc-macro2",
  "quote",
  "syn",
@@ -3140,14 +3127,25 @@ dependencies = [
  "slab",
 ]
 
+[[package]]
+name = "jsonrpsee"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6373a33d987866ccfe1af4bc11b089dce941764313f9fd8b7cf13fcb51b72dc5"
+dependencies = [
+ "jsonrpsee-proc-macros",
+ "jsonrpsee-types",
+ "jsonrpsee-utils",
+ "jsonrpsee-ws-client",
+]
+
 [[package]]
 name = "jsonrpsee-proc-macros"
-version = "0.3.1"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8edb341d35279b59c79d7fe9e060a51aec29d45af99cc7c72ea7caa350fa71a4"
+checksum = "d802063f7a3c867456955f9d2f15eb3ee0edb5ec9ec2b5526324756759221c0f"
 dependencies = [
- "Inflector",
- "bae",
+ "log 0.4.14",
  "proc-macro-crate 1.0.0",
  "proc-macro2",
  "quote",
@@ -3156,10 +3154,11 @@ dependencies = [
 
 [[package]]
 name = "jsonrpsee-types"
-version = "0.3.1"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cc738fd55b676ada3271ef7c383a14a0867a2a88b0fa941311bf5fc0a29d498"
+checksum = "62f778cf245158fbd8f5d50823a2e9e4c708a40be164766bd35e9fb1d86715b2"
 dependencies = [
+ "anyhow",
  "async-trait",
  "beef",
  "futures-channel",
@@ -3168,32 +3167,43 @@ dependencies = [
  "log 0.4.14",
  "serde",
  "serde_json",
- "soketto 0.6.0",
+ "soketto 0.7.0",
  "thiserror",
 ]
 
+[[package]]
+name = "jsonrpsee-utils"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0109c4f972058f3b1925b73a17210aff7b63b65967264d0045d15ee88fe84f0c"
+dependencies = [
+ "arrayvec 0.7.1",
+ "beef",
+ "jsonrpsee-types",
+]
+
 [[package]]
 name = "jsonrpsee-ws-client"
-version = "0.3.1"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9841352dbecf4c2ed5dc71698df9f1660262ae4e0b610e968602529bdbcf7b30"
+checksum = "559aa56fc402af206c00fc913dc2be1d9d788dcde045d14df141a535245d35ef"
 dependencies = [
+ "arrayvec 0.7.1",
  "async-trait",
  "fnv",
  "futures 0.3.16",
+ "http",
  "jsonrpsee-types",
  "log 0.4.14",
  "pin-project 1.0.8",
- "rustls",
  "rustls-native-certs",
  "serde",
  "serde_json",
- "soketto 0.6.0",
+ "soketto 0.7.0",
  "thiserror",
  "tokio",
  "tokio-rustls",
  "tokio-util",
- "url 2.2.1",
 ]
 
 [[package]]
@@ -4353,7 +4363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99"
 dependencies = [
  "proc-macro-crate 1.0.0",
- "proc-macro-error 1.0.4",
+ "proc-macro-error",
  "proc-macro2",
  "quote",
  "syn",
@@ -6249,7 +6259,7 @@ version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909"
 dependencies = [
- "arrayvec 0.7.0",
+ "arrayvec 0.7.1",
  "bitvec 0.20.2",
  "byte-slice-cast",
  "impl-trait-for-tuples",
@@ -6742,45 +6752,19 @@ dependencies = [
  "toml",
 ]
 
-[[package]]
-name = "proc-macro-error"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7"
-dependencies = [
- "proc-macro-error-attr 0.4.12",
- "proc-macro2",
- "quote",
- "syn",
- "version_check 0.9.2",
-]
-
 [[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 1.0.4",
+ "proc-macro-error-attr",
  "proc-macro2",
  "quote",
  "syn",
  "version_check 0.9.2",
 ]
 
-[[package]]
-name = "proc-macro-error-attr"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "syn-mid",
- "version_check 0.9.2",
-]
-
 [[package]]
 name = "proc-macro-error-attr"
 version = "1.0.4"
@@ -7365,8 +7349,7 @@ version = "0.10.0-dev"
 dependencies = [
  "env_logger 0.9.0",
  "frame-support",
- "jsonrpsee-proc-macros",
- "jsonrpsee-ws-client",
+ "jsonrpsee",
  "log 0.4.14",
  "pallet-elections-phragmen",
  "parity-scale-codec",
@@ -9157,9 +9140,9 @@ dependencies = [
 
 [[package]]
 name = "soketto"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a74e48087dbeed4833785c2f3352b59140095dc192dce966a3bfc155020a439f"
+checksum = "083624472e8817d44d02c0e55df043737ff11f279af924abdf93845717c2b75c"
 dependencies = [
  "base64 0.13.0",
  "bytes 1.0.1",
@@ -10062,7 +10045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba"
 dependencies = [
  "heck",
- "proc-macro-error 1.0.4",
+ "proc-macro-error",
  "proc-macro2",
  "quote",
  "syn",
@@ -10355,17 +10338,6 @@ dependencies = [
  "unicode-xid",
 ]
 
-[[package]]
-name = "syn-mid"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baa8e7560a164edb1621a55d18a0c59abf49d360f47aa7b821061dd7eea7fac9"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
 [[package]]
 name = "synstructure"
 version = "0.12.4"
@@ -10974,7 +10946,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
 name = "try-runtime-cli"
 version = "0.10.0-dev"
 dependencies = [
- "jsonrpsee-ws-client",
+ "jsonrpsee",
  "log 0.4.14",
  "parity-scale-codec",
  "remote-externalities",
@@ -11447,7 +11419,7 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d8b86dcd2c3efdb8390728a2b56f762db07789aaa5aa872a9dc776ba3a7912ed"
 dependencies = [
- "proc-macro-error 1.0.4",
+ "proc-macro-error",
  "proc-macro2",
  "quote",
  "syn",
diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml
index 15760c5a9abb4..fc39e47ce4113 100644
--- a/bin/node/cli/Cargo.toml
+++ b/bin/node/cli/Cargo.toml
@@ -130,7 +130,7 @@ async-std = { version = "1.10.0", features = ["attributes"] }
 soketto = "0.4.2"
 criterion = { version = "0.3.5", features = [ "async_tokio" ] }
 tokio = { version = "1.10", features = ["macros", "time"] }
-jsonrpsee-ws-client = { version = "0.3.1", default-features = false, features = ["tokio1"] }
+jsonrpsee-ws-client = "0.4.1"
 wait-timeout = "0.2"
 remote-externalities = { path = "../../../utils/frame/remote-externalities" }
 pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" }
diff --git a/frame/bags-list/remote-tests/src/migration.rs b/frame/bags-list/remote-tests/src/migration.rs
index 1e977011f1439..86595c7feba9d 100644
--- a/frame/bags-list/remote-tests/src/migration.rs
+++ b/frame/bags-list/remote-tests/src/migration.rs
@@ -21,11 +21,11 @@ use frame_election_provider_support::SortedListProvider;
 use frame_support::traits::PalletInfoAccess;
 use pallet_staking::Nominators;
 use remote_externalities::{Builder, Mode, OnlineConfig};
-use sp_runtime::traits::Block as BlockT;
+use sp_runtime::{traits::Block as BlockT, DeserializeOwned};
 
 /// Test voter bags migration. `currency_unit` is the number of planks per the the runtimes `UNITS`
 /// (i.e. number of decimal places per DOT, KSM etc)
-pub async fn execute(
+pub async fn execute(
 	currency_unit: u64,
 	currency_name: &'static str,
 	ws_url: String,
diff --git a/frame/bags-list/remote-tests/src/sanity_check.rs b/frame/bags-list/remote-tests/src/sanity_check.rs
index 7282e7bad5e32..adab1ae5477ea 100644
--- a/frame/bags-list/remote-tests/src/sanity_check.rs
+++ b/frame/bags-list/remote-tests/src/sanity_check.rs
@@ -22,11 +22,11 @@ use frame_support::{
 	traits::{Get, PalletInfoAccess},
 };
 use remote_externalities::{Builder, Mode, OnlineConfig};
-use sp_runtime::traits::Block as BlockT;
+use sp_runtime::{traits::Block as BlockT, DeserializeOwned};
 use sp_std::prelude::*;
 
 /// Execute the sanity check of the bags-list.
-pub async fn execute(
+pub async fn execute(
 	currency_unit: u64,
 	currency_name: &'static str,
 	ws_url: String,
diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs
index 6e186a65cb2b9..0e68a4495edfc 100644
--- a/frame/bags-list/remote-tests/src/snapshot.rs
+++ b/frame/bags-list/remote-tests/src/snapshot.rs
@@ -18,10 +18,10 @@
 
 use frame_support::traits::PalletInfoAccess;
 use remote_externalities::{Builder, Mode, OnlineConfig};
-use sp_runtime::traits::Block as BlockT;
+use sp_runtime::{traits::Block as BlockT, DeserializeOwned};
 
 /// Execute create a snapshot from pallet-staking.
-pub async fn execute(
+pub async fn execute(
 	voter_limit: Option,
 	currency_unit: u64,
 	ws_url: String,
diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs
index f80b7b1ac554c..44db2c10fff6c 100644
--- a/frame/support/procedural/src/construct_runtime/parse.rs
+++ b/frame/support/procedural/src/construct_runtime/parse.rs
@@ -225,7 +225,7 @@ impl Parse for PalletDeclaration {
 		{
 			return Err(input.error(
 				"Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`",
-			))
+			));
 		} else {
 			None
 		};
diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml
index 9c9025d934aab..f2482f9c423db 100644
--- a/utils/frame/remote-externalities/Cargo.toml
+++ b/utils/frame/remote-externalities/Cargo.toml
@@ -13,10 +13,7 @@ readme = "README.md"
 targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
-jsonrpsee-ws-client = { version = "0.3.1", default-features = false, features = [
-    "tokio1",
-]}
-jsonrpsee-proc-macros = "0.3.1"
+jsonrpsee = { version = "0.4.1", features = ["ws-client", "macros"] }
 
 env_logger = "0.9"
 log = "0.4.11"
diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs
index bf8c57ae14ee6..da715be6b4be4 100644
--- a/utils/frame/remote-externalities/src/lib.rs
+++ b/utils/frame/remote-externalities/src/lib.rs
@@ -21,7 +21,16 @@
 //! based chain, or a local state snapshot file.
 
 use codec::{Decode, Encode};
-use jsonrpsee_ws_client::{types::v2::params::JsonRpcParams, WsClient, WsClientBuilder};
+
+use jsonrpsee::{
+	proc_macros::rpc,
+	rpc_params,
+	types::{traits::Client, Error as RpcError},
+	ws_client::{WsClient, WsClientBuilder},
+};
+
+use log::*;
+use serde::de::DeserializeOwned;
 use sp_core::{
 	hashing::twox_128,
 	hexdisplay::HexDisplay,
@@ -39,23 +48,25 @@ pub mod rpc_api;
 type KeyPair = (StorageKey, StorageData);
 
 const LOG_TARGET: &str = "remote-ext";
-const DEFAULT_TARGET: &str = "wss://rpc.polkadot.io";
+const DEFAULT_TARGET: &str = "wss://rpc.polkadot.io:443";
 const BATCH_SIZE: usize = 1000;
 
-jsonrpsee_proc_macros::rpc_client_api! {
-	RpcApi {
-		#[rpc(method = "state_getStorage", positional_params)]
-		fn get_storage(prefix: StorageKey, hash: Option) -> StorageData;
-		#[rpc(method = "state_getKeysPaged", positional_params)]
-		fn get_keys_paged(
-			prefix: Option,
-			count: u32,
-			start_key: Option,
-			hash: Option,
-		) -> Vec;
-		#[rpc(method = "chain_getFinalizedHead", positional_params)]
-		fn finalized_head() -> B::Hash;
-	}
+#[rpc(client)]
+pub trait RpcApi {
+	#[method(name = "state_getStorage")]
+	fn get_storage(&self, prefix: StorageKey, hash: Option) -> Result;
+
+	#[method(name = "state_getKeysPaged")]
+	fn get_keys_paged(
+		&self,
+		prefix: Option,
+		count: u32,
+		start_key: Option,
+		hash: Option,
+	) -> Result, RpcError>;
+
+	#[method(name = "chain_getFinalizedHead")]
+	fn finalized_head(&self) -> Result;
 }
 
 /// The execution mode.
@@ -183,7 +194,7 @@ pub struct Builder {
 
 // NOTE: ideally we would use `DefaultNoBound` here, but not worth bringing in frame-support for
 // that.
-impl Default for Builder {
+impl Default for Builder {
 	fn default() -> Self {
 		Self {
 			mode: Default::default(),
@@ -196,7 +207,7 @@ impl Default for Builder {
 }
 
 // Mode methods
-impl Builder {
+impl Builder {
 	fn as_online(&self) -> &OnlineConfig {
 		match &self.mode {
 			Mode::Online(config) => &config,
@@ -215,25 +226,23 @@ impl Builder {
 }
 
 // RPC methods
-impl Builder {
+impl Builder {
 	async fn rpc_get_storage(
 		&self,
 		key: StorageKey,
 		maybe_at: Option,
 	) -> Result {
-		log::trace!(target: LOG_TARGET, "rpc: get_storage");
-		RpcApi::::get_storage(self.as_online().rpc_client(), key, maybe_at)
-			.await
-			.map_err(|e| {
-				log::error!(target: LOG_TARGET, "Error = {:?}", e);
-				"rpc get_storage failed."
-			})
+		trace!(target: LOG_TARGET, "rpc: get_storage");
+		self.as_online().rpc_client().get_storage(key, maybe_at).await.map_err(|e| {
+			error!("Error = {:?}", e);
+			"rpc get_storage failed."
+		})
 	}
 	/// Get the latest finalized head.
 	async fn rpc_get_head(&self) -> Result {
-		log::trace!(target: LOG_TARGET, "rpc: finalized_head");
-		RpcApi::::finalized_head(self.as_online().rpc_client()).await.map_err(|e| {
-			log::error!(target: LOG_TARGET, "Error = {:?}", e);
+		trace!(target: LOG_TARGET, "rpc: finalized_head");
+		self.as_online().rpc_client().finalized_head().await.map_err(|e| {
+			error!("Error = {:?}", e);
 			"rpc finalized_head failed."
 		})
 	}
@@ -248,18 +257,15 @@ impl Builder {
 		let mut last_key: Option = None;
 		let mut all_keys: Vec = vec![];
 		let keys = loop {
-			let page = RpcApi::::get_keys_paged(
-				self.as_online().rpc_client(),
-				Some(prefix.clone()),
-				PAGE,
-				last_key.clone(),
-				Some(at),
-			)
-			.await
-			.map_err(|e| {
-				log::error!(target: LOG_TARGET, "Error = {:?}", e);
-				"rpc get_keys failed"
-			})?;
+			let page = self
+				.as_online()
+				.rpc_client()
+				.get_keys_paged(Some(prefix.clone()), PAGE, last_key.clone(), Some(at))
+				.await
+				.map_err(|e| {
+					error!(target: LOG_TARGET, "Error = {:?}", e);
+					"rpc get_keys failed"
+				})?;
 			let page_len = page.len();
 			all_keys.extend(page);
 
@@ -291,8 +297,6 @@ impl Builder {
 		prefix: StorageKey,
 		at: B::Hash,
 	) -> Result, &'static str> {
-		use jsonrpsee_ws_client::types::traits::Client;
-		use serde_json::to_value;
 		let keys = self.get_keys_paged(prefix, at).await?;
 		let keys_count = keys.len();
 		log::debug!(target: LOG_TARGET, "Querying a total of {} keys", keys.len());
@@ -303,15 +307,7 @@ impl Builder {
 			let batch = chunk_keys
 				.iter()
 				.cloned()
-				.map(|key| {
-					(
-						"state_getStorage",
-						JsonRpcParams::Array(vec![
-							to_value(key).expect("json serialization will work; qed."),
-							to_value(at).expect("json serialization will work; qed."),
-						]),
-					)
-				})
+				.map(|key| ("state_getStorage", rpc_params![key, at]))
 				.collect::>();
 			let values = client.batch_request::>(batch).await.map_err(|e| {
 				log::error!(
@@ -348,7 +344,7 @@ impl Builder {
 }
 
 // Internal methods
-impl Builder {
+impl Builder {
 	/// Save the given data as state snapshot.
 	fn save_state_snapshot(&self, data: &[KeyPair], path: &Path) -> Result<(), &'static str> {
 		log::debug!(target: LOG_TARGET, "writing to state snapshot file {:?}", path);
@@ -489,7 +485,7 @@ impl Builder {
 }
 
 // Public methods
-impl Builder {
+impl Builder {
 	/// Create a new builder.
 	pub fn new() -> Self {
 		Default::default()
@@ -625,7 +621,7 @@ mod tests {
 #[cfg(all(test, feature = "remote-test"))]
 mod remote_tests {
 	use super::test_prelude::*;
-
+	use pallet_elections_phragmen::Members;
 	const REMOTE_INACCESSIBLE: &'static str = "Can't reach the remote node. Is it running?";
 
 	#[tokio::test]
@@ -697,7 +693,6 @@ mod remote_tests {
 
 	#[tokio::test]
 	async fn sanity_check_decoding() {
-		use pallet_elections_phragmen::SeatHolder;
 		use sp_core::crypto::Ss58Codec;
 
 		type AccountId = sp_runtime::AccountId32;
@@ -722,7 +717,7 @@ mod remote_tests {
 				let gav_polkadot =
 					AccountId::from_ss58check("13RDY9nrJpyTDBSUdBw12dGwhk19sGwsrVZ2bxkzYHBSagP2")
 						.unwrap();
-				let members = Members::get().unwrap();
+				let members = Members::get();
 				assert!(members
 					.iter()
 					.map(|s| s.who.clone())
diff --git a/utils/frame/remote-externalities/src/rpc_api.rs b/utils/frame/remote-externalities/src/rpc_api.rs
index 24050856a96a1..024cbad3ca551 100644
--- a/utils/frame/remote-externalities/src/rpc_api.rs
+++ b/utils/frame/remote-externalities/src/rpc_api.rs
@@ -18,9 +18,10 @@
 //! WS RPC API for one off RPC calls to a substrate node.
 // TODO: Consolidate one off RPC calls https://github.com/paritytech/substrate/issues/8988
 
-use jsonrpsee_ws_client::{
-	types::{traits::Client, v2::params::JsonRpcParams},
-	WsClient, WsClientBuilder,
+use jsonrpsee::{
+	rpc_params,
+	types::traits::Client,
+	ws_client::{WsClient, WsClientBuilder},
 };
 use sp_runtime::{
 	generic::SignedBlock,
@@ -34,11 +35,10 @@ where
 	Block::Header: serde::de::DeserializeOwned,
 	S: AsRef,
 {
-	let params = vec![hash_to_json::(at)?];
 	let client = build_client(from).await?;
 
 	client
-		.request::("chain_getHeader", JsonRpcParams::Array(params))
+		.request::("chain_getHeader", rpc_params!(at))
 		.await
 		.map_err(|e| format!("chain_getHeader request failed: {:?}", e))
 }
@@ -52,7 +52,7 @@ where
 	let client = build_client(from).await?;
 
 	client
-		.request::("chain_getFinalizedHead", JsonRpcParams::NoParams)
+		.request::("chain_getFinalizedHead", None)
 		.await
 		.map_err(|e| format!("chain_getFinalizedHead request failed: {:?}", e))
 }
@@ -64,22 +64,15 @@ where
 	Block: BlockT + serde::de::DeserializeOwned,
 	Block::Header: HeaderT,
 {
-	let params = vec![hash_to_json::(at)?];
 	let client = build_client(from).await?;
 	let signed_block = client
-		.request::>("chain_getBlock", JsonRpcParams::Array(params))
+		.request::>("chain_getBlock", rpc_params!(at))
 		.await
 		.map_err(|e| format!("chain_getBlock request failed: {:?}", e))?;
 
 	Ok(signed_block.block)
 }
 
-/// Convert a block hash to a serde json value.
-fn hash_to_json(hash: Block::Hash) -> Result {
-	serde_json::to_value(hash)
-		.map_err(|e| format!("Block hash could not be converted to JSON: {:?}", e))
-}
-
 /// Build a website client that connects to `from`.
 async fn build_client>(from: S) -> Result {
 	WsClientBuilder::default()
@@ -99,13 +92,9 @@ where
 	Block: BlockT + serde::de::DeserializeOwned,
 	Block::Header: HeaderT,
 {
-	let params = if let Some(at) = at { vec![hash_to_json::(at)?] } else { vec![] };
 	let client = build_client(from).await?;
 	client
-		.request::(
-			"state_getRuntimeVersion",
-			JsonRpcParams::Array(params),
-		)
+		.request::("state_getRuntimeVersion", rpc_params!(at))
 		.await
 		.map_err(|e| format!("state_getRuntimeVersion request failed: {:?}", e))
 }
diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml
index 154c522c1dfd0..a89a625bbd9ed 100644
--- a/utils/frame/try-runtime/cli/Cargo.toml
+++ b/utils/frame/try-runtime/cli/Cargo.toml
@@ -31,6 +31,4 @@ sp-externalities = { version = "0.10.0-dev", path = "../../../../primitives/exte
 sp-version = { version = "4.0.0-dev", path = "../../../../primitives/version" }
 
 remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" }
-jsonrpsee-ws-client = { version = "0.3.1", default-features = false, features = [
-    "tokio1",
-]}
+jsonrpsee = { version = "0.4.1", default-features = false, features = ["ws-client"]}
diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs
index 9125db13c78f9..27fb35dd7a46a 100644
--- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs
+++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs
@@ -19,9 +19,9 @@ use crate::{
 	build_executor, ensure_matching_spec, extract_code, full_extensions, local_spec, parse,
 	state_machine_call, SharedParams, LOG_TARGET,
 };
-use jsonrpsee_ws_client::{
-	types::{traits::SubscriptionClient, v2::params::JsonRpcParams, Subscription},
-	WsClientBuilder,
+use jsonrpsee::{
+	types::{traits::SubscriptionClient, Subscription},
+	ws_client::WsClientBuilder,
 };
 use parity_scale_codec::Decode;
 use remote_externalities::{rpc_api, Builder, Mode, OnlineConfig};
@@ -72,7 +72,7 @@ where
 
 	log::info!(target: LOG_TARGET, "subscribing to {:?} / {:?}", SUB, UN_SUB);
 	let mut subscription: Subscription =
-		client.subscribe(&SUB, JsonRpcParams::NoParams, &UN_SUB).await.unwrap();
+		client.subscribe(&SUB, None, &UN_SUB).await.unwrap();
 
 	let (code_key, code) = extract_code(&config.chain_spec)?;
 	let executor = build_executor::(&shared, &config);
diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs
index 28e51b38f2ace..a74625492bb1c 100644
--- a/utils/frame/try-runtime/cli/src/lib.rs
+++ b/utils/frame/try-runtime/cli/src/lib.rs
@@ -281,7 +281,10 @@ use sp_core::{
 };
 use sp_externalities::Extensions;
 use sp_keystore::{testing::KeyStore, KeystoreExt};
-use sp_runtime::traits::{Block as BlockT, NumberFor};
+use sp_runtime::{
+	traits::{Block as BlockT, NumberFor},
+	DeserializeOwned,
+};
 use sp_state_machine::{OverlayedChanges, StateMachine};
 use std::{fmt::Debug, path::PathBuf, str::FromStr};
 
@@ -464,7 +467,7 @@ pub enum State {
 
 impl State {
 	/// Create the [`remote_externalities::Builder`] from self.
-	pub(crate) fn builder(&self) -> sc_cli::Result>
+	pub(crate) fn builder(&self) -> sc_cli::Result>
 	where
 		Block::Hash: FromStr,
 		::Err: Debug,

From 8d7898923c8287df6f2014c31940d7b5a2df9323 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 11 Nov 2021 13:56:46 +0000
Subject: [PATCH 0214/1472] Bump substrate-bip39 from 0.4.2 to 0.4.4 (#10213)

Bumps [substrate-bip39](https://github.com/paritytech/substrate-bip39) from 0.4.2 to 0.4.4.
- [Release notes](https://github.com/paritytech/substrate-bip39/releases)
- [Commits](https://github.com/paritytech/substrate-bip39/commits)

---
updated-dependencies:
- dependency-name: substrate-bip39
  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                 | 73 +++++++++++++++++---------------------
 primitives/core/Cargo.toml |  2 +-
 2 files changed, 34 insertions(+), 41 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 5ae937ad22d4f..51eb96d6989f9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -59,7 +59,7 @@ dependencies = [
  "cipher",
  "ctr",
  "ghash",
- "subtle 2.4.0",
+ "subtle",
 ]
 
 [[package]]
@@ -1309,22 +1309,22 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
 
 [[package]]
 name = "crypto-mac"
-version = "0.7.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
+checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
 dependencies = [
- "generic-array 0.12.4",
- "subtle 1.0.0",
+ "generic-array 0.14.4",
+ "subtle",
 ]
 
 [[package]]
 name = "crypto-mac"
-version = "0.8.0"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
+checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
 dependencies = [
  "generic-array 0.14.4",
- "subtle 2.4.0",
+ "subtle",
 ]
 
 [[package]]
@@ -1397,7 +1397,7 @@ dependencies = [
  "byteorder",
  "digest 0.8.1",
  "rand_core 0.5.1",
- "subtle 2.4.0",
+ "subtle",
  "zeroize",
 ]
 
@@ -1410,7 +1410,7 @@ dependencies = [
  "byteorder",
  "digest 0.9.0",
  "rand_core 0.5.1",
- "subtle 2.4.0",
+ "subtle",
  "zeroize",
 ]
 
@@ -2610,21 +2610,21 @@ checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f"
 
 [[package]]
 name = "hmac"
-version = "0.7.1"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
+checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
 dependencies = [
- "crypto-mac 0.7.0",
- "digest 0.8.1",
+ "crypto-mac 0.8.0",
+ "digest 0.9.0",
 ]
 
 [[package]]
 name = "hmac"
-version = "0.8.1"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
+checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
 dependencies = [
- "crypto-mac 0.8.0",
+ "crypto-mac 0.11.1",
  "digest 0.9.0",
 ]
 
@@ -3868,7 +3868,7 @@ checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80"
 dependencies = [
  "crunchy",
  "digest 0.9.0",
- "subtle 2.4.0",
+ "subtle",
 ]
 
 [[package]]
@@ -3879,7 +3879,7 @@ checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451"
 dependencies = [
  "crunchy",
  "digest 0.9.0",
- "subtle 2.4.0",
+ "subtle",
 ]
 
 [[package]]
@@ -6443,21 +6443,20 @@ dependencies = [
 
 [[package]]
 name = "pbkdf2"
-version = "0.3.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
+checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd"
 dependencies = [
- "byteorder",
- "crypto-mac 0.7.0",
+ "crypto-mac 0.8.0",
 ]
 
 [[package]]
 name = "pbkdf2"
-version = "0.4.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd"
+checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa"
 dependencies = [
- "crypto-mac 0.8.0",
+ "crypto-mac 0.11.1",
 ]
 
 [[package]]
@@ -8779,7 +8778,7 @@ dependencies = [
  "rand 0.7.3",
  "rand_core 0.5.1",
  "sha2 0.8.2",
- "subtle 2.4.0",
+ "subtle",
  "zeroize",
 ]
 
@@ -9097,7 +9096,7 @@ dependencies = [
  "ring",
  "rustc_version 0.3.3",
  "sha2 0.9.8",
- "subtle 2.4.0",
+ "subtle",
  "x25519-dalek",
 ]
 
@@ -10082,14 +10081,14 @@ dependencies = [
 
 [[package]]
 name = "substrate-bip39"
-version = "0.4.2"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bed6646a0159b9935b5d045611560eeef842b78d7adc3ba36f5ca325a13a0236"
+checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c"
 dependencies = [
- "hmac 0.7.1",
- "pbkdf2 0.3.0",
+ "hmac 0.11.0",
+ "pbkdf2 0.8.0",
  "schnorrkel",
- "sha2 0.8.2",
+ "sha2 0.9.8",
  "zeroize",
 ]
 
@@ -10315,12 +10314,6 @@ dependencies = [
  "wasm-gc-api",
 ]
 
-[[package]]
-name = "subtle"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
-
 [[package]]
 name = "subtle"
 version = "2.4.0"
@@ -11088,7 +11081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402"
 dependencies = [
  "generic-array 0.14.4",
- "subtle 2.4.0",
+ "subtle",
 ]
 
 [[package]]
diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml
index 9e31ba644c250..26acd44c7cbdc 100644
--- a/primitives/core/Cargo.toml
+++ b/primitives/core/Cargo.toml
@@ -32,7 +32,7 @@ hash-db = { version = "0.15.2", default-features = false }
 hash256-std-hasher = { version = "0.15.2", default-features = false }
 base58 = { version = "0.2.0", optional = true }
 rand = { version = "0.7.3", optional = true, features = ["small_rng"] }
-substrate-bip39 = { version = "0.4.2", optional = true }
+substrate-bip39 = { version = "0.4.4", optional = true }
 tiny-bip39 = { version = "0.8.2", optional = true }
 regex = { version = "1.5.4", optional = true }
 num-traits = { version = "0.2.8", default-features = false }

From 083d0ce1386e4b9d87692ce0d30199073ffd02fd Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 11 Nov 2021 12:02:39 -0300
Subject: [PATCH 0215/1472] Bump parity-util-mem from 0.10.0 to 0.10.2 (#10236)

Bumps [parity-util-mem](https://github.com/paritytech/parity-common) from 0.10.0 to 0.10.2.
- [Release notes](https://github.com/paritytech/parity-common/releases)
- [Commits](https://github.com/paritytech/parity-common/compare/parity-util-mem-v0.10.0...parity-util-mem-v0.10.2)

---
updated-dependencies:
- dependency-name: parity-util-mem
  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 ++--
 bin/node/bench/Cargo.toml             | 2 +-
 client/informant/Cargo.toml           | 2 +-
 client/service/Cargo.toml             | 2 +-
 client/state-db/Cargo.toml            | 2 +-
 client/transaction-pool/Cargo.toml    | 2 +-
 frame/support/Cargo.toml              | 2 +-
 primitives/core/Cargo.toml            | 2 +-
 primitives/runtime/Cargo.toml         | 2 +-
 primitives/test-primitives/Cargo.toml | 2 +-
 test-utils/runtime/Cargo.toml         | 2 +-
 11 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 51eb96d6989f9..8ad1560b85aa1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6301,9 +6301,9 @@ dependencies = [
 
 [[package]]
 name = "parity-util-mem"
-version = "0.10.0"
+version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ad6f1acec69b95caf435bbd158d486e5a0a44fcf51531e84922c59ff09e8457"
+checksum = "6f4cb4e169446179cbc6b8b6320cc9fca49bd2e94e8db25f25f200a8ea774770"
 dependencies = [
  "cfg-if 1.0.0",
  "hashbrown 0.11.2",
diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml
index f59ea2361186c..66a14a123ee56 100644
--- a/bin/node/bench/Cargo.toml
+++ b/bin/node/bench/Cargo.toml
@@ -35,7 +35,7 @@ fs_extra = "1"
 hex = "0.4.0"
 rand = { version = "0.7.2", features = ["small_rng"] }
 lazy_static = "1.4.0"
-parity-util-mem = { version = "0.10.0", default-features = false, features = [
+parity-util-mem = { version = "0.10.2", default-features = false, features = [
     "primitive-types",
 ] }
 parity-db = { version = "0.3" }
diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml
index 7d92e14e5d471..5eba3ecaeb2ac 100644
--- a/client/informant/Cargo.toml
+++ b/client/informant/Cargo.toml
@@ -17,7 +17,7 @@ ansi_term = "0.12.1"
 futures = "0.3.9"
 futures-timer = "3.0.1"
 log = "0.4.8"
-parity-util-mem = { version = "0.10.0", default-features = false, features = ["primitive-types"] }
+parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] }
 sc-client-api = { version = "4.0.0-dev", path = "../api" }
 sc-network = { version = "0.10.0-dev", path = "../network" }
 sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" }
diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml
index 97b0f4e461c87..c090495fe04ec 100644
--- a/client/service/Cargo.toml
+++ b/client/service/Cargo.toml
@@ -74,7 +74,7 @@ sc-tracing = { version = "4.0.0-dev", path = "../tracing" }
 sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" }
 tracing = "0.1.29"
 tracing-futures = { version = "0.2.4" }
-parity-util-mem = { version = "0.10.0", default-features = false, features = [
+parity-util-mem = { version = "0.10.2", default-features = false, features = [
 	"primitive-types",
 ] }
 async-trait = "0.1.50"
diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml
index abd378c6fff38..cd14038cb77b5 100644
--- a/client/state-db/Cargo.toml
+++ b/client/state-db/Cargo.toml
@@ -18,5 +18,5 @@ log = "0.4.11"
 sc-client-api = { version = "4.0.0-dev", path = "../api" }
 sp-core = { version = "4.0.0-dev", path = "../../primitives/core" }
 codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] }
-parity-util-mem = { version = "0.10.0", default-features = false, features = ["primitive-types"] }
+parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] }
 parity-util-mem-derive = "0.1.0"
diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml
index 99f1f3788ec0e..d26969cf1e092 100644
--- a/client/transaction-pool/Cargo.toml
+++ b/client/transaction-pool/Cargo.toml
@@ -18,7 +18,7 @@ thiserror = "1.0.21"
 futures = "0.3.16"
 intervalier = "0.4.0"
 log = "0.4.8"
-parity-util-mem = { version = "0.10.0", default-features = false, features = ["primitive-types"] }
+parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] }
 parking_lot = "0.11.1"
 prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"}
 sc-client-api = { version = "4.0.0-dev", path = "../api" }
diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml
index 42981dc160a4b..1f48dadc2987d 100644
--- a/frame/support/Cargo.toml
+++ b/frame/support/Cargo.toml
@@ -40,7 +40,7 @@ sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/c
 assert_matches = "1.3.0"
 pretty_assertions = "1.0.0"
 frame-system = { version = "4.0.0-dev", path = "../system" }
-parity-util-mem = { version = "0.10.0", default-features = false, features = ["primitive-types"] }
+parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] }
 
 [features]
 default = ["std"]
diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml
index 26acd44c7cbdc..48749904763fd 100644
--- a/primitives/core/Cargo.toml
+++ b/primitives/core/Cargo.toml
@@ -43,7 +43,7 @@ parking_lot = { version = "0.11.1", optional = true }
 sp-debug-derive = { version = "4.0.0-dev", default-features = false, path = "../debug-derive" }
 sp-externalities = { version = "0.10.0-dev", optional = true, path = "../externalities" }
 sp-storage = { version = "4.0.0-dev", default-features = false, path = "../storage" }
-parity-util-mem = { version = "0.10.0", default-features = false, features = [
+parity-util-mem = { version = "0.10.2", default-features = false, features = [
 	"primitive-types",
 ] }
 futures = { version = "0.3.1", optional = true }
diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml
index 9d2957e7aed1a..8e466bf4a1e85 100644
--- a/primitives/runtime/Cargo.toml
+++ b/primitives/runtime/Cargo.toml
@@ -27,7 +27,7 @@ log = { version = "0.4.14", default-features = false }
 paste = "1.0"
 rand = { version = "0.7.2", optional = true }
 impl-trait-for-tuples = "0.2.1"
-parity-util-mem = { version = "0.10.0", default-features = false, features = ["primitive-types"] }
+parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] }
 hash256-std-hasher = { version = "0.15.2", default-features = false }
 either = { version = "1.5", default-features = false }
 
diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml
index 4d184c7d02e7f..b95c88626996b 100644
--- a/primitives/test-primitives/Cargo.toml
+++ b/primitives/test-primitives/Cargo.toml
@@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features =
 sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" }
 serde = { version = "1.0.126", optional = true, features = ["derive"] }
 sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" }
-parity-util-mem = { version = "0.10.0", default-features = false, features = ["primitive-types"] }
+parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] }
 
 [features]
 default = [
diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml
index f02e079046336..d0d85029738ea 100644
--- a/test-utils/runtime/Cargo.toml
+++ b/test-utils/runtime/Cargo.toml
@@ -40,7 +40,7 @@ sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path =
 sp-trie = { version = "4.0.0-dev", default-features = false, path = "../../primitives/trie" }
 sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" }
 trie-db = { version = "0.22.6", default-features = false }
-parity-util-mem = { version = "0.10.0", default-features = false, features = ["primitive-types"] }
+parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] }
 sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" }
 sp-state-machine = { version = "0.10.0-dev", default-features = false, path = "../../primitives/state-machine" }
 sp-externalities = { version = "0.10.0-dev", default-features = false, path = "../../primitives/externalities" }

From c2afe155d4239480795e4d27f9ebb75f1a584ecc Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 11 Nov 2021 16:58:14 +0100
Subject: [PATCH 0216/1472] Bump proc-macro-crate from 1.0.0 to 1.1.0 (#10237)

Bumps [proc-macro-crate](https://github.com/bkchr/proc-macro-crate) from 1.0.0 to 1.1.0.
- [Release notes](https://github.com/bkchr/proc-macro-crate/releases)
- [Commits](https://github.com/bkchr/proc-macro-crate/commits)

---
updated-dependencies:
- dependency-name: proc-macro-crate
  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                                    | 28 +++++++++----------
 client/chain-spec/derive/Cargo.toml           |  2 +-
 client/tracing/proc-macro/Cargo.toml          |  2 +-
 frame/staking/reward-curve/Cargo.toml         |  2 +-
 frame/support/procedural/tools/Cargo.toml     |  2 +-
 primitives/api/proc-macro/Cargo.toml          |  2 +-
 .../npos-elections/solution-type/Cargo.toml   |  2 +-
 .../runtime-interface/proc-macro/Cargo.toml   |  2 +-
 test-utils/derive/Cargo.toml                  |  2 +-
 9 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 8ad1560b85aa1..423ec1de4e7de 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2071,7 +2071,7 @@ name = "frame-support-procedural-tools"
 version = "4.0.0-dev"
 dependencies = [
  "frame-support-procedural-tools-derive",
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "syn",
@@ -3146,7 +3146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d802063f7a3c867456955f9d2f15eb3ee0edb5ec9ec2b5526324756759221c0f"
 dependencies = [
  "log 0.4.14",
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "syn",
@@ -4362,7 +4362,7 @@ version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99"
 dependencies = [
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro-error",
  "proc-macro2",
  "quote",
@@ -6022,7 +6022,7 @@ dependencies = [
 name = "pallet-staking-reward-curve"
 version = "4.0.0-dev"
 dependencies = [
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "sp-runtime",
@@ -6273,7 +6273,7 @@ version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27"
 dependencies = [
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "syn",
@@ -6743,9 +6743,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro-crate"
-version = "1.0.0"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41fdbd1df62156fbc5945f4762632564d7d038153091c3fcf1067f6aef7cff92"
+checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83"
 dependencies = [
  "thiserror",
  "toml",
@@ -7664,7 +7664,7 @@ dependencies = [
 name = "sc-chain-spec-derive"
 version = "4.0.0-dev"
 dependencies = [
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "syn",
@@ -8665,7 +8665,7 @@ dependencies = [
 name = "sc-tracing-proc-macro"
 version = "4.0.0-dev"
 dependencies = [
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "syn",
@@ -8748,7 +8748,7 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baeb2780690380592f86205aa4ee49815feb2acad8c2f59e6dd207148c3f1fcd"
 dependencies = [
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "syn",
@@ -9174,7 +9174,7 @@ name = "sp-api-proc-macro"
 version = "4.0.0-dev"
 dependencies = [
  "blake2-rfc",
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "syn",
@@ -9618,7 +9618,7 @@ name = "sp-npos-elections-solution-type"
 version = "4.0.0-dev"
 dependencies = [
  "parity-scale-codec",
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "scale-info",
@@ -9709,7 +9709,7 @@ name = "sp-runtime-interface-proc-macro"
 version = "4.0.0-dev"
 dependencies = [
  "Inflector",
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "syn",
@@ -10285,7 +10285,7 @@ dependencies = [
 name = "substrate-test-utils-derive"
 version = "0.10.0-dev"
 dependencies = [
- "proc-macro-crate 1.0.0",
+ "proc-macro-crate 1.1.0",
  "proc-macro2",
  "quote",
  "syn",
diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml
index 25339eea14f12..3ffb70d50ef52 100644
--- a/client/chain-spec/derive/Cargo.toml
+++ b/client/chain-spec/derive/Cargo.toml
@@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 proc-macro = true
 
 [dependencies]
-proc-macro-crate = "1.0.0"
+proc-macro-crate = "1.1.0"
 proc-macro2 = "1.0.29"
 quote = "1.0.10"
 syn = "1.0.81"
diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml
index c51c8764e6772..39c22bf856b26 100644
--- a/client/tracing/proc-macro/Cargo.toml
+++ b/client/tracing/proc-macro/Cargo.toml
@@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 proc-macro = true
 
 [dependencies]
-proc-macro-crate = "1.0.0"
+proc-macro-crate = "1.1.0"
 proc-macro2 = "1.0.29"
 quote = { version = "1.0.10", features = ["proc-macro"] }
 syn = { version = "1.0.81", features = ["proc-macro", "full", "extra-traits", "parsing"] }
diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml
index 1250bbcd39056..fd306eb085727 100644
--- a/frame/staking/reward-curve/Cargo.toml
+++ b/frame/staking/reward-curve/Cargo.toml
@@ -18,7 +18,7 @@ proc-macro = true
 syn = { version = "1.0.81", features = ["full", "visit"] }
 quote = "1.0.10"
 proc-macro2 = "1.0.29"
-proc-macro-crate = "1.0.0"
+proc-macro-crate = "1.1.0"
 
 [dev-dependencies]
 sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" }
diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml
index 7b957be184014..c0a3b98632f59 100644
--- a/frame/support/procedural/tools/Cargo.toml
+++ b/frame/support/procedural/tools/Cargo.toml
@@ -16,4 +16,4 @@ frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" }
 proc-macro2 = "1.0.29"
 quote = "1.0.10"
 syn = { version = "1.0.81", features = ["full", "visit", "extra-traits"] }
-proc-macro-crate = "1.0.0"
+proc-macro-crate = "1.1.0"
diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml
index a5df7aef322ab..c8eaae7c02abe 100644
--- a/primitives/api/proc-macro/Cargo.toml
+++ b/primitives/api/proc-macro/Cargo.toml
@@ -20,7 +20,7 @@ quote = "1.0.10"
 syn = { version = "1.0.81", features = ["full", "fold", "extra-traits", "visit"] }
 proc-macro2 = "1.0.29"
 blake2-rfc = { version = "0.2.18", default-features = false }
-proc-macro-crate = "1.0.0"
+proc-macro-crate = "1.1.0"
 
 # Required for the doc tests
 [features]
diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml
index 5d8d3890577a7..a64ca45ce8424 100644
--- a/primitives/npos-elections/solution-type/Cargo.toml
+++ b/primitives/npos-elections/solution-type/Cargo.toml
@@ -18,7 +18,7 @@ proc-macro = true
 syn = { version = "1.0.81", features = ["full", "visit"] }
 quote = "1.0"
 proc-macro2 = "1.0.29"
-proc-macro-crate = "1.0.0"
+proc-macro-crate = "1.1.0"
 
 [dev-dependencies]
 parity-scale-codec = "2.3.1"
diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml
index cc5daa695bb0f..0be33c2c55ad1 100644
--- a/primitives/runtime-interface/proc-macro/Cargo.toml
+++ b/primitives/runtime-interface/proc-macro/Cargo.toml
@@ -20,4 +20,4 @@ syn = { version = "1.0.81", features = ["full", "visit", "fold", "extra-traits"]
 quote = "1.0.10"
 proc-macro2 = "1.0.29"
 Inflector = "0.11.4"
-proc-macro-crate = "1.0.0"
+proc-macro-crate = "1.1.0"
diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml
index 967fc1e87a36e..0b894d92b2bcb 100644
--- a/test-utils/derive/Cargo.toml
+++ b/test-utils/derive/Cargo.toml
@@ -11,7 +11,7 @@ description = "Substrate test utilities macros"
 [dependencies]
 quote = "1.0.10"
 syn = { version = "1.0.81", features = ["full"] }
-proc-macro-crate = "1.0.0"
+proc-macro-crate = "1.1.0"
 proc-macro2 = "1.0.29"
 
 [lib]

From f78549161b9827ddde2519a12d1a279b83634f41 Mon Sep 17 00:00:00 2001
From: sandreim <54316454+sandreim@users.noreply.github.com>
Date: Thu, 11 Nov 2021 19:15:09 +0200
Subject: [PATCH 0217/1472] Add group name in task metrics  (#10196)

* SpawnNamed: add new trait methods

Signed-off-by: Andrei Sandu 

* Implement new methods

Signed-off-by: Andrei Sandu 

* cargo fmt

Signed-off-by: Andrei Sandu 

* SpawnNamed: add new trait methods

Signed-off-by: Andrei Sandu 

* Implement new methods

Signed-off-by: Andrei Sandu 

* cargo fmt

Signed-off-by: Andrei Sandu 

* New approach - spaw() group param

Signed-off-by: Andrei Sandu 

* Update traits: SpawnNamed and SpawnNamed

Signed-off-by: Andrei Sandu 

* Update TaskManager tests

Signed-off-by: Andrei Sandu 

* Update test TaskExecutor

Signed-off-by: Andrei Sandu 

* Fix typo

Signed-off-by: Andrei Sandu 

* grunt work: fix spawn() calls

Signed-off-by: Andrei Sandu 

* cargo fmt

Signed-off-by: Andrei Sandu 

* remove old code

Signed-off-by: Andrei Sandu 

* cargo fmt - the right version

Signed-off-by: Andrei Sandu 

* Implement review feedback

- use Option group name in SpawnNamed methods
- switch to kebab case
- implement default group name
- add group name to some tasks

Signed-off-by: Andrei Sandu 
---
 bin/node-template/node/src/service.rs         |   7 +-
 bin/node/cli/src/service.rs                   |  24 +++--
 bin/node/testing/src/bench.rs                 |  14 ++-
 .../basic-authorship/src/basic_authorship.rs  |   1 +
 .../common/src/import_queue/basic_queue.rs    |   6 +-
 client/executor/src/native_executor.rs        |   1 +
 client/offchain/src/lib.rs                    |   1 +
 client/rpc/src/lib.rs                         |   3 +-
 client/service/src/builder.rs                 |  20 ++--
 client/service/src/lib.rs                     |   2 +-
 client/service/src/task_manager/mod.rs        | 100 ++++++++++++------
 client/service/src/task_manager/tests.rs      |  52 ++++-----
 client/transaction-pool/src/api.rs            |   1 +
 client/transaction-pool/src/lib.rs            |   2 +-
 primitives/core/src/testing.rs                |  22 +++-
 primitives/core/src/traits.rs                 |  67 +++++++++---
 primitives/io/src/batch_verifier.rs           |   4 +-
 primitives/tasks/src/lib.rs                   |   1 +
 test-utils/test-runner/src/client.rs          |   4 +-
 19 files changed, 232 insertions(+), 100 deletions(-)

diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs
index d673a54a94882..c71336c330882 100644
--- a/bin/node-template/node/src/service.rs
+++ b/bin/node-template/node/src/service.rs
@@ -89,7 +89,7 @@ pub fn new_partial(
 	let client = Arc::new(client);
 
 	let telemetry = telemetry.map(|(worker, telemetry)| {
-		task_manager.spawn_handle().spawn("telemetry", worker.run());
+		task_manager.spawn_handle().spawn("telemetry", None, worker.run());
 		telemetry
 	});
 
@@ -289,7 +289,9 @@ pub fn new_full(mut config: Configuration) -> Result
 
 		// 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", aura);
+		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
@@ -329,6 +331,7 @@ pub fn new_full(mut config: Configuration) -> Result
 		// if it fails we take down the service with it.
 		task_manager.spawn_essential_handle().spawn_blocking(
 			"grandpa-voter",
+			None,
 			sc_finality_grandpa::run_grandpa_voter(grandpa_config)?,
 		);
 	}
diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs
index a022d501d0155..dee546bf07001 100644
--- a/bin/node/cli/src/service.rs
+++ b/bin/node/cli/src/service.rs
@@ -170,7 +170,7 @@ pub fn new_partial(
 	let client = Arc::new(client);
 
 	let telemetry = telemetry.map(|(worker, telemetry)| {
-		task_manager.spawn_handle().spawn("telemetry", worker.run());
+		task_manager.spawn_handle().spawn("telemetry", None, worker.run());
 		telemetry
 	});
 
@@ -436,7 +436,11 @@ pub fn new_full_base(
 		};
 
 		let babe = sc_consensus_babe::start_babe(babe_config)?;
-		task_manager.spawn_essential_handle().spawn_blocking("babe-proposer", babe);
+		task_manager.spawn_essential_handle().spawn_blocking(
+			"babe-proposer",
+			Some("block-authoring"),
+			babe,
+		);
 	}
 
 	// Spawn authority discovery module.
@@ -463,9 +467,11 @@ pub fn new_full_base(
 				prometheus_registry.clone(),
 			);
 
-		task_manager
-			.spawn_handle()
-			.spawn("authority-discovery-worker", authority_discovery_worker.run());
+		task_manager.spawn_handle().spawn(
+			"authority-discovery-worker",
+			Some("networking"),
+			authority_discovery_worker.run(),
+		);
 	}
 
 	// if the node isn't actively participating in consensus then it doesn't
@@ -503,9 +509,11 @@ pub fn new_full_base(
 
 		// 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", grandpa::run_grandpa_voter(grandpa_config)?);
+		task_manager.spawn_essential_handle().spawn_blocking(
+			"grandpa-voter",
+			None,
+			grandpa::run_grandpa_voter(grandpa_config)?,
+		);
 	}
 
 	network_starter.start_network();
diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs
index cf0a463cc3e99..5ee1ec998be4d 100644
--- a/bin/node/testing/src/bench.rs
+++ b/bin/node/testing/src/bench.rs
@@ -243,11 +243,21 @@ impl TaskExecutor {
 }
 
 impl SpawnNamed for TaskExecutor {
-	fn spawn(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) {
+	fn spawn(
+		&self,
+		_: &'static str,
+		_: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	) {
 		self.pool.spawn_ok(future);
 	}
 
-	fn spawn_blocking(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) {
+	fn spawn_blocking(
+		&self,
+		_: &'static str,
+		_: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	) {
 		self.pool.spawn_ok(future);
 	}
 }
diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs
index 573601a9102c5..305c4d753c1ea 100644
--- a/client/basic-authorship/src/basic_authorship.rs
+++ b/client/basic-authorship/src/basic_authorship.rs
@@ -270,6 +270,7 @@ where
 
 		spawn_handle.spawn_blocking(
 			"basic-authorship-proposer",
+			None,
 			Box::pin(async move {
 				// leave some time for evaluation and block finalization (33%)
 				let deadline = (self.now)() + max_duration - max_duration / 3;
diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs
index 9042c8798be4f..0461d7cf954cb 100644
--- a/client/consensus/common/src/import_queue/basic_queue.rs
+++ b/client/consensus/common/src/import_queue/basic_queue.rs
@@ -89,7 +89,11 @@ impl BasicQueue {
 			metrics,
 		);
 
-		spawner.spawn_essential_blocking("basic-block-import-worker", future.boxed());
+		spawner.spawn_essential_blocking(
+			"basic-block-import-worker",
+			Some("block-import"),
+			future.boxed(),
+		);
 
 		Self { justification_sender, block_import_sender, result_port, _phantom: PhantomData }
 	}
diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs
index d912fc0fd13c9..62e76d559c0f2 100644
--- a/client/executor/src/native_executor.rs
+++ b/client/executor/src/native_executor.rs
@@ -399,6 +399,7 @@ impl RuntimeSpawn for RuntimeInstanceSpawn {
 		let scheduler = self.scheduler.clone();
 		self.scheduler.spawn(
 			"executor-extra-runtime-instance",
+			None,
 			Box::pin(async move {
 				let module = AssertUnwindSafe(module);
 
diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs
index a77fd17a2c8b8..2de24e10d927d 100644
--- a/client/offchain/src/lib.rs
+++ b/client/offchain/src/lib.rs
@@ -226,6 +226,7 @@ pub async fn notification_future(
 			if n.is_new_best {
 				spawner.spawn(
 					"offchain-on-block",
+					Some("offchain-worker"),
 					offchain
 						.on_block_imported(&n.header, network_provider.clone(), is_validator)
 						.boxed(),
diff --git a/client/rpc/src/lib.rs b/client/rpc/src/lib.rs
index 832585db4854c..8f951632698fd 100644
--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -54,7 +54,8 @@ impl SubscriptionTaskExecutor {
 
 impl Spawn for SubscriptionTaskExecutor {
 	fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
-		self.0.spawn("substrate-rpc-subscription", future.map(drop).boxed());
+		self.0
+			.spawn("substrate-rpc-subscription", Some("rpc"), future.map(drop).boxed());
 		Ok(())
 	}
 
diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs
index bcb05ce743701..88ba6282b5f4e 100644
--- a/client/service/src/builder.rs
+++ b/client/service/src/builder.rs
@@ -424,6 +424,7 @@ where
 	if let Some(offchain) = offchain_workers.clone() {
 		spawn_handle.spawn(
 			"offchain-notifications",
+			Some("offchain-worker"),
 			sc_offchain::notification_future(
 				config.role.is_authority(),
 				client.clone(),
@@ -505,11 +506,13 @@ where
 	// Inform the tx pool about imported and finalized blocks.
 	spawn_handle.spawn(
 		"txpool-notifications",
+		Some("transaction-pool"),
 		sc_transaction_pool::notification_future(client.clone(), transaction_pool.clone()),
 	);
 
 	spawn_handle.spawn(
 		"on-transaction-imported",
+		Some("transaction-pool"),
 		transaction_notifications(transaction_pool.clone(), network.clone(), telemetry.clone()),
 	);
 
@@ -520,6 +523,7 @@ where
 			let metrics = MetricsService::with_prometheus(telemetry.clone(), ®istry, &config)?;
 			spawn_handle.spawn(
 				"prometheus-endpoint",
+				None,
 				prometheus_endpoint::init_prometheus(port, registry).map(drop),
 			);
 
@@ -531,6 +535,7 @@ where
 	// Periodically updated metrics and telemetry updates.
 	spawn_handle.spawn(
 		"telemetry-periodic-send",
+		None,
 		metrics_service.run(client.clone(), transaction_pool.clone(), network.clone()),
 	);
 
@@ -567,6 +572,7 @@ where
 	// Spawn informant task
 	spawn_handle.spawn(
 		"informant",
+		None,
 		sc_informant::build(
 			client.clone(),
 			network.clone(),
@@ -798,7 +804,7 @@ where
 				config.network.default_peers_set.in_peers as usize +
 					config.network.default_peers_set.out_peers as usize,
 			);
-			spawn_handle.spawn("block_request_handler", handler.run());
+			spawn_handle.spawn("block-request-handler", Some("networking"), handler.run());
 			protocol_config
 		}
 	};
@@ -815,7 +821,7 @@ where
 				config.network.default_peers_set.in_peers as usize +
 					config.network.default_peers_set.out_peers as usize,
 			);
-			spawn_handle.spawn("state_request_handler", handler.run());
+			spawn_handle.spawn("state-request-handler", Some("networking"), handler.run());
 			protocol_config
 		}
 	};
@@ -828,7 +834,7 @@ where
 			// Allow both outgoing and incoming requests.
 			let (handler, protocol_config) =
 				WarpSyncRequestHandler::new(protocol_id.clone(), provider.clone());
-			spawn_handle.spawn("warp_sync_request_handler", handler.run());
+			spawn_handle.spawn("warp-sync-request-handler", Some("networking"), handler.run());
 			protocol_config
 		};
 		(provider, protocol_config)
@@ -842,7 +848,7 @@ where
 			// Allow both outgoing and incoming requests.
 			let (handler, protocol_config) =
 				LightClientRequestHandler::new(&protocol_id, client.clone());
-			spawn_handle.spawn("light_client_request_handler", handler.run());
+			spawn_handle.spawn("light-client-request-handler", Some("networking"), handler.run());
 			protocol_config
 		}
 	};
@@ -852,13 +858,13 @@ where
 		executor: {
 			let spawn_handle = Clone::clone(&spawn_handle);
 			Some(Box::new(move |fut| {
-				spawn_handle.spawn("libp2p-node", fut);
+				spawn_handle.spawn("libp2p-node", Some("networking"), fut);
 			}))
 		},
 		transactions_handler_executor: {
 			let spawn_handle = Clone::clone(&spawn_handle);
 			Box::new(move |fut| {
-				spawn_handle.spawn("network-transactions-handler", fut);
+				spawn_handle.spawn("network-transactions-handler", Some("networking"), fut);
 			})
 		},
 		network_config: config.network.clone(),
@@ -920,7 +926,7 @@ where
 	// issue, and ideally we would like to fix the network future to take as little time as
 	// possible, but we also take the extra harm-prevention measure to execute the networking
 	// future using `spawn_blocking`.
-	spawn_handle.spawn_blocking("network-worker", async move {
+	spawn_handle.spawn_blocking("network-worker", Some("networking"), async move {
 		if network_start_rx.await.is_err() {
 			log::warn!(
 				"The NetworkStart returned as part of `build_network` has been silently dropped"
diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs
index ce77be5a7c1d9..bd43d4c464ea0 100644
--- a/client/service/src/lib.rs
+++ b/client/service/src/lib.rs
@@ -75,7 +75,7 @@ pub use sc_transaction_pool::Options as TransactionPoolOptions;
 pub use sc_transaction_pool_api::{error::IntoPoolError, InPoolTransaction, TransactionPool};
 #[doc(hidden)]
 pub use std::{ops::Deref, result::Result, sync::Arc};
-pub use task_manager::{SpawnTaskHandle, TaskManager};
+pub use task_manager::{SpawnTaskHandle, TaskManager, DEFAULT_GROUP_NAME};
 
 const DEFAULT_PROTOCOL_ID: &str = "sup";
 
diff --git a/client/service/src/task_manager/mod.rs b/client/service/src/task_manager/mod.rs
index c827aa71dac2c..64c00226073c7 100644
--- a/client/service/src/task_manager/mod.rs
+++ b/client/service/src/task_manager/mod.rs
@@ -38,6 +38,9 @@ mod prometheus_future;
 #[cfg(test)]
 mod tests;
 
+/// Default task group name.
+pub const DEFAULT_GROUP_NAME: &'static str = "default";
+
 /// An handle for spawning tasks in the service.
 #[derive(Clone)]
 pub struct SpawnTaskHandle {
@@ -48,31 +51,39 @@ pub struct SpawnTaskHandle {
 }
 
 impl SpawnTaskHandle {
-	/// Spawns the given task with the given name.
+	/// Spawns the given task with the given name and an optional group name.
+	/// If group is not specified `DEFAULT_GROUP_NAME` will be used.
 	///
-	/// Note that the `name` is a `&'static str`. The reason for this choice is that statistics
-	/// about this task are getting reported to the Prometheus endpoint (if enabled), and that
-	/// therefore the set of possible task names must be bounded.
+	/// Note that the `name`/`group` is a `&'static str`. The reason for this choice is that
+	/// statistics about this task are getting reported to the Prometheus endpoint (if enabled), and
+	/// that therefore the set of possible task names must be bounded.
 	///
 	/// In other words, it would be a bad idea for someone to do for example
 	/// `spawn(format!("{:?}", some_public_key))`.
-	pub fn spawn(&self, name: &'static str, task: impl Future + Send + 'static) {
-		self.spawn_inner(name, task, TaskType::Async)
+	pub fn spawn(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		task: impl Future + Send + 'static,
+	) {
+		self.spawn_inner(name, group, task, TaskType::Async)
 	}
 
 	/// Spawns the blocking task with the given name. See also `spawn`.
 	pub fn spawn_blocking(
 		&self,
 		name: &'static str,
+		group: Option<&'static str>,
 		task: impl Future + Send + 'static,
 	) {
-		self.spawn_inner(name, task, TaskType::Blocking)
+		self.spawn_inner(name, group, task, TaskType::Blocking)
 	}
 
 	/// Helper function that implements the spawning logic. See `spawn` and `spawn_blocking`.
 	fn spawn_inner(
 		&self,
 		name: &'static str,
+		group: Option<&'static str>,
 		task: impl Future + Send + 'static,
 		task_type: TaskType,
 	) {
@@ -83,21 +94,23 @@ impl SpawnTaskHandle {
 
 		let on_exit = self.on_exit.clone();
 		let metrics = self.metrics.clone();
+		// If no group is specified use default.
+		let group = group.unwrap_or(DEFAULT_GROUP_NAME);
 
 		// Note that we increase the started counter here and not within the future. This way,
 		// we could properly visualize on Prometheus situations where the spawning doesn't work.
 		if let Some(metrics) = &self.metrics {
-			metrics.tasks_spawned.with_label_values(&[name]).inc();
+			metrics.tasks_spawned.with_label_values(&[name, group]).inc();
 			// We do a dummy increase in order for the task to show up in metrics.
-			metrics.tasks_ended.with_label_values(&[name, "finished"]).inc_by(0);
+			metrics.tasks_ended.with_label_values(&[name, "finished", group]).inc_by(0);
 		}
 
 		let future = async move {
 			if let Some(metrics) = metrics {
 				// Add some wrappers around `task`.
 				let task = {
-					let poll_duration = metrics.poll_duration.with_label_values(&[name]);
-					let poll_start = metrics.poll_start.with_label_values(&[name]);
+					let poll_duration = metrics.poll_duration.with_label_values(&[name, group]);
+					let poll_start = metrics.poll_start.with_label_values(&[name, group]);
 					let inner =
 						prometheus_future::with_poll_durations(poll_duration, poll_start, task);
 					// The logic of `AssertUnwindSafe` here is ok considering that we throw
@@ -108,15 +121,15 @@ impl SpawnTaskHandle {
 
 				match select(on_exit, task).await {
 					Either::Right((Err(payload), _)) => {
-						metrics.tasks_ended.with_label_values(&[name, "panic"]).inc();
+						metrics.tasks_ended.with_label_values(&[name, "panic", group]).inc();
 						panic::resume_unwind(payload)
 					},
 					Either::Right((Ok(()), _)) => {
-						metrics.tasks_ended.with_label_values(&[name, "finished"]).inc();
+						metrics.tasks_ended.with_label_values(&[name, "finished", group]).inc();
 					},
 					Either::Left(((), _)) => {
 						// The `on_exit` has triggered.
-						metrics.tasks_ended.with_label_values(&[name, "interrupted"]).inc();
+						metrics.tasks_ended.with_label_values(&[name, "interrupted", group]).inc();
 					},
 				}
 			} else {
@@ -141,12 +154,22 @@ impl SpawnTaskHandle {
 }
 
 impl sp_core::traits::SpawnNamed for SpawnTaskHandle {
-	fn spawn_blocking(&self, name: &'static str, future: BoxFuture<'static, ()>) {
-		self.spawn_blocking(name, future);
+	fn spawn_blocking(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		future: BoxFuture<'static, ()>,
+	) {
+		self.spawn_inner(name, group, future, TaskType::Blocking)
 	}
 
-	fn spawn(&self, name: &'static str, future: BoxFuture<'static, ()>) {
-		self.spawn(name, future);
+	fn spawn(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		future: BoxFuture<'static, ()>,
+	) {
+		self.spawn_inner(name, group, future, TaskType::Async)
 	}
 }
 
@@ -172,8 +195,13 @@ impl SpawnEssentialTaskHandle {
 	/// Spawns the given task with the given name.
 	///
 	/// See also [`SpawnTaskHandle::spawn`].
-	pub fn spawn(&self, name: &'static str, task: impl Future + Send + 'static) {
-		self.spawn_inner(name, task, TaskType::Async)
+	pub fn spawn(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		task: impl Future + Send + 'static,
+	) {
+		self.spawn_inner(name, group, task, TaskType::Async)
 	}
 
 	/// Spawns the blocking task with the given name.
@@ -182,14 +210,16 @@ impl SpawnEssentialTaskHandle {
 	pub fn spawn_blocking(
 		&self,
 		name: &'static str,
+		group: Option<&'static str>,
 		task: impl Future + Send + 'static,
 	) {
-		self.spawn_inner(name, task, TaskType::Blocking)
+		self.spawn_inner(name, group, task, TaskType::Blocking)
 	}
 
 	fn spawn_inner(
 		&self,
 		name: &'static str,
+		group: Option<&'static str>,
 		task: impl Future + Send + 'static,
 		task_type: TaskType,
 	) {
@@ -199,17 +229,27 @@ impl SpawnEssentialTaskHandle {
 			let _ = essential_failed.close_channel();
 		});
 
-		let _ = self.inner.spawn_inner(name, essential_task, task_type);
+		let _ = self.inner.spawn_inner(name, group, essential_task, task_type);
 	}
 }
 
 impl sp_core::traits::SpawnEssentialNamed for SpawnEssentialTaskHandle {
-	fn spawn_essential_blocking(&self, name: &'static str, future: BoxFuture<'static, ()>) {
-		self.spawn_blocking(name, future);
+	fn spawn_essential_blocking(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		future: BoxFuture<'static, ()>,
+	) {
+		self.spawn_blocking(name, group, future);
 	}
 
-	fn spawn_essential(&self, name: &'static str, future: BoxFuture<'static, ()>) {
-		self.spawn(name, future);
+	fn spawn_essential(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		future: BoxFuture<'static, ()>,
+	) {
+		self.spawn(name, group, future);
 	}
 }
 
@@ -396,28 +436,28 @@ impl Metrics {
 					buckets: exponential_buckets(0.001, 4.0, 9)
 						.expect("function parameters are constant and always valid; qed"),
 				},
-				&["task_name"]
+				&["task_name", "task_group"]
 			)?, registry)?,
 			poll_start: register(CounterVec::new(
 				Opts::new(
 					"tasks_polling_started_total",
 					"Total number of times we started invoking Future::poll"
 				),
-				&["task_name"]
+				&["task_name", "task_group"]
 			)?, registry)?,
 			tasks_spawned: register(CounterVec::new(
 				Opts::new(
 					"tasks_spawned_total",
 					"Total number of tasks that have been spawned on the Service"
 				),
-				&["task_name"]
+				&["task_name", "task_group"]
 			)?, registry)?,
 			tasks_ended: register(CounterVec::new(
 				Opts::new(
 					"tasks_ended_total",
 					"Total number of tasks for which Future::poll has returned Ready(()) or panicked"
 				),
-				&["task_name", "reason"]
+				&["task_name", "reason", "task_group"]
 			)?, registry)?,
 		})
 	}
diff --git a/client/service/src/task_manager/tests.rs b/client/service/src/task_manager/tests.rs
index 291d71ebaf03b..75092ff2ae62e 100644
--- a/client/service/src/task_manager/tests.rs
+++ b/client/service/src/task_manager/tests.rs
@@ -96,8 +96,8 @@ fn ensure_tasks_are_awaited_on_shutdown() {
 	let task_manager = new_task_manager(handle);
 	let spawn_handle = task_manager.spawn_handle();
 	let drop_tester = DropTester::new();
-	spawn_handle.spawn("task1", run_background_task(drop_tester.new_ref()));
-	spawn_handle.spawn("task2", run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref()));
 	assert_eq!(drop_tester, 2);
 	// allow the tasks to even start
 	runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await });
@@ -115,7 +115,7 @@ fn ensure_keep_alive_during_shutdown() {
 	let spawn_handle = task_manager.spawn_handle();
 	let drop_tester = DropTester::new();
 	task_manager.keep_alive(drop_tester.new_ref());
-	spawn_handle.spawn("task1", run_background_task(()));
+	spawn_handle.spawn("task1", None, run_background_task(()));
 	assert_eq!(drop_tester, 1);
 	// allow the tasks to even start
 	runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await });
@@ -134,10 +134,12 @@ fn ensure_blocking_futures_are_awaited_on_shutdown() {
 	let drop_tester = DropTester::new();
 	spawn_handle.spawn(
 		"task1",
+		None,
 		run_background_task_blocking(Duration::from_secs(3), drop_tester.new_ref()),
 	);
 	spawn_handle.spawn(
 		"task2",
+		None,
 		run_background_task_blocking(Duration::from_secs(3), drop_tester.new_ref()),
 	);
 	assert_eq!(drop_tester, 2);
@@ -156,14 +158,14 @@ fn ensure_no_task_can_be_spawn_after_terminate() {
 	let mut task_manager = new_task_manager(handle);
 	let spawn_handle = task_manager.spawn_handle();
 	let drop_tester = DropTester::new();
-	spawn_handle.spawn("task1", run_background_task(drop_tester.new_ref()));
-	spawn_handle.spawn("task2", run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref()));
 	assert_eq!(drop_tester, 2);
 	// allow the tasks to even start
 	runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await });
 	assert_eq!(drop_tester, 2);
 	task_manager.terminate();
-	spawn_handle.spawn("task3", run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task3", None, run_background_task(drop_tester.new_ref()));
 	runtime.block_on(task_manager.clean_shutdown());
 	drop_tester.wait_on_drop();
 }
@@ -176,8 +178,8 @@ fn ensure_task_manager_future_ends_when_task_manager_terminated() {
 	let mut task_manager = new_task_manager(handle);
 	let spawn_handle = task_manager.spawn_handle();
 	let drop_tester = DropTester::new();
-	spawn_handle.spawn("task1", run_background_task(drop_tester.new_ref()));
-	spawn_handle.spawn("task2", run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref()));
 	assert_eq!(drop_tester, 2);
 	// allow the tasks to even start
 	runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await });
@@ -197,13 +199,13 @@ fn ensure_task_manager_future_ends_with_error_when_essential_task_fails() {
 	let spawn_handle = task_manager.spawn_handle();
 	let spawn_essential_handle = task_manager.spawn_essential_handle();
 	let drop_tester = DropTester::new();
-	spawn_handle.spawn("task1", run_background_task(drop_tester.new_ref()));
-	spawn_handle.spawn("task2", run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref()));
 	assert_eq!(drop_tester, 2);
 	// allow the tasks to even start
 	runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await });
 	assert_eq!(drop_tester, 2);
-	spawn_essential_handle.spawn("task3", async { panic!("task failed") });
+	spawn_essential_handle.spawn("task3", None, async { panic!("task failed") });
 	runtime
 		.block_on(task_manager.future())
 		.expect_err("future()'s Result must be Err");
@@ -226,10 +228,10 @@ fn ensure_children_tasks_ends_when_task_manager_terminated() {
 	task_manager.add_child(child_2);
 	let spawn_handle = task_manager.spawn_handle();
 	let drop_tester = DropTester::new();
-	spawn_handle.spawn("task1", run_background_task(drop_tester.new_ref()));
-	spawn_handle.spawn("task2", run_background_task(drop_tester.new_ref()));
-	spawn_handle_child_1.spawn("task3", run_background_task(drop_tester.new_ref()));
-	spawn_handle_child_2.spawn("task4", run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle_child_1.spawn("task3", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle_child_2.spawn("task4", None, run_background_task(drop_tester.new_ref()));
 	assert_eq!(drop_tester, 4);
 	// allow the tasks to even start
 	runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await });
@@ -255,15 +257,15 @@ fn ensure_task_manager_future_ends_with_error_when_childs_essential_task_fails()
 	task_manager.add_child(child_2);
 	let spawn_handle = task_manager.spawn_handle();
 	let drop_tester = DropTester::new();
-	spawn_handle.spawn("task1", run_background_task(drop_tester.new_ref()));
-	spawn_handle.spawn("task2", run_background_task(drop_tester.new_ref()));
-	spawn_handle_child_1.spawn("task3", run_background_task(drop_tester.new_ref()));
-	spawn_handle_child_2.spawn("task4", run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle_child_1.spawn("task3", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle_child_2.spawn("task4", None, run_background_task(drop_tester.new_ref()));
 	assert_eq!(drop_tester, 4);
 	// allow the tasks to even start
 	runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await });
 	assert_eq!(drop_tester, 4);
-	spawn_essential_handle_child_1.spawn("task5", async { panic!("task failed") });
+	spawn_essential_handle_child_1.spawn("task5", None, async { panic!("task failed") });
 	runtime
 		.block_on(task_manager.future())
 		.expect_err("future()'s Result must be Err");
@@ -286,15 +288,15 @@ fn ensure_task_manager_future_continues_when_childs_not_essential_task_fails() {
 	task_manager.add_child(child_2);
 	let spawn_handle = task_manager.spawn_handle();
 	let drop_tester = DropTester::new();
-	spawn_handle.spawn("task1", run_background_task(drop_tester.new_ref()));
-	spawn_handle.spawn("task2", run_background_task(drop_tester.new_ref()));
-	spawn_handle_child_1.spawn("task3", run_background_task(drop_tester.new_ref()));
-	spawn_handle_child_2.spawn("task4", run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle_child_1.spawn("task3", None, run_background_task(drop_tester.new_ref()));
+	spawn_handle_child_2.spawn("task4", None, run_background_task(drop_tester.new_ref()));
 	assert_eq!(drop_tester, 4);
 	// allow the tasks to even start
 	runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await });
 	assert_eq!(drop_tester, 4);
-	spawn_handle_child_1.spawn("task5", async { panic!("task failed") });
+	spawn_handle_child_1.spawn("task5", None, async { panic!("task failed") });
 	runtime.block_on(async {
 		let t1 = task_manager.future().fuse();
 		let t2 = tokio::time::sleep(Duration::from_secs(3)).fuse();
diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs
index a735c67d846ce..8af0ea98f8100 100644
--- a/client/transaction-pool/src/api.rs
+++ b/client/transaction-pool/src/api.rs
@@ -64,6 +64,7 @@ fn spawn_validation_pool_task(
 ) {
 	spawner.spawn_essential_blocking(
 		name,
+		Some("transaction-pool"),
 		async move {
 			loop {
 				let task = receiver.lock().await.next().await;
diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs
index 8af73c3fe5b48..3565cb52ad87b 100644
--- a/client/transaction-pool/src/lib.rs
+++ b/client/transaction-pool/src/lib.rs
@@ -217,7 +217,7 @@ where
 		};
 
 		if let Some(background_task) = background_task {
-			spawner.spawn_essential("txpool-background", background_task);
+			spawner.spawn_essential("txpool-background", Some("transaction-pool"), background_task);
 		}
 
 		Self {
diff --git a/primitives/core/src/testing.rs b/primitives/core/src/testing.rs
index a7fff0def83f2..a40a37804c031 100644
--- a/primitives/core/src/testing.rs
+++ b/primitives/core/src/testing.rs
@@ -152,10 +152,20 @@ impl Default for TaskExecutor {
 
 #[cfg(feature = "std")]
 impl crate::traits::SpawnNamed for TaskExecutor {
-	fn spawn_blocking(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) {
+	fn spawn_blocking(
+		&self,
+		_name: &'static str,
+		_group: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	) {
 		self.0.spawn_ok(future);
 	}
-	fn spawn(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) {
+	fn spawn(
+		&self,
+		_name: &'static str,
+		_group: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	) {
 		self.0.spawn_ok(future);
 	}
 }
@@ -165,11 +175,17 @@ impl crate::traits::SpawnEssentialNamed for TaskExecutor {
 	fn spawn_essential_blocking(
 		&self,
 		_: &'static str,
+		_: Option<&'static str>,
 		future: futures::future::BoxFuture<'static, ()>,
 	) {
 		self.0.spawn_ok(future);
 	}
-	fn spawn_essential(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) {
+	fn spawn_essential(
+		&self,
+		_: &'static str,
+		_: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	) {
 		self.0.spawn_ok(future);
 	}
 }
diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs
index 47639f9d87ba6..e3d7d8e283e21 100644
--- a/primitives/core/src/traits.rs
+++ b/primitives/core/src/traits.rs
@@ -190,58 +190,91 @@ sp_externalities::decl_extension! {
 	pub struct RuntimeSpawnExt(Box);
 }
 
-/// Something that can spawn tasks (blocking and non-blocking) with an assigned name.
+/// Something that can spawn tasks (blocking and non-blocking) with an assigned name
+/// and optional group.
 #[dyn_clonable::clonable]
 pub trait SpawnNamed: Clone + Send + Sync {
 	/// Spawn the given blocking future.
 	///
-	/// The given `name` is used to identify the future in tracing.
-	fn spawn_blocking(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>);
+	/// The given `group` and `name` is used to identify the future in tracing.
+	fn spawn_blocking(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	);
 	/// Spawn the given non-blocking future.
 	///
-	/// The given `name` is used to identify the future in tracing.
-	fn spawn(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>);
+	/// The given `group` and `name` is used to identify the future in tracing.
+	fn spawn(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	);
 }
 
 impl SpawnNamed for Box {
-	fn spawn_blocking(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>) {
-		(**self).spawn_blocking(name, future)
+	fn spawn_blocking(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	) {
+		(**self).spawn_blocking(name, group, future)
 	}
-
-	fn spawn(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>) {
-		(**self).spawn(name, future)
+	fn spawn(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	) {
+		(**self).spawn(name, group, future)
 	}
 }
 
-/// Something that can spawn essential tasks (blocking and non-blocking) with an assigned name.
+/// Something that can spawn essential tasks (blocking and non-blocking) with an assigned name
+/// and optional group.
 ///
 /// Essential tasks are special tasks that should take down the node when they end.
 #[dyn_clonable::clonable]
 pub trait SpawnEssentialNamed: Clone + Send + Sync {
 	/// Spawn the given blocking future.
 	///
-	/// The given `name` is used to identify the future in tracing.
+	/// The given `group` and `name` is used to identify the future in tracing.
 	fn spawn_essential_blocking(
 		&self,
 		name: &'static str,
+		group: Option<&'static str>,
 		future: futures::future::BoxFuture<'static, ()>,
 	);
 	/// Spawn the given non-blocking future.
 	///
-	/// The given `name` is used to identify the future in tracing.
-	fn spawn_essential(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>);
+	/// The given `group` and `name` is used to identify the future in tracing.
+	fn spawn_essential(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	);
 }
 
 impl SpawnEssentialNamed for Box {
 	fn spawn_essential_blocking(
 		&self,
 		name: &'static str,
+		group: Option<&'static str>,
 		future: futures::future::BoxFuture<'static, ()>,
 	) {
-		(**self).spawn_essential_blocking(name, future)
+		(**self).spawn_essential_blocking(name, group, future)
 	}
 
-	fn spawn_essential(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>) {
-		(**self).spawn_essential(name, future)
+	fn spawn_essential(
+		&self,
+		name: &'static str,
+		group: Option<&'static str>,
+		future: futures::future::BoxFuture<'static, ()>,
+	) {
+		(**self).spawn_essential(name, group, future)
 	}
 }
diff --git a/primitives/io/src/batch_verifier.rs b/primitives/io/src/batch_verifier.rs
index b6da1d85907bd..05c8a63694eb3 100644
--- a/primitives/io/src/batch_verifier.rs
+++ b/primitives/io/src/batch_verifier.rs
@@ -74,6 +74,7 @@ impl BatchVerifier {
 
 		self.scheduler.spawn(
 			name,
+			None,
 			async move {
 				if !f() {
 					invalid_clone.store(true, AtomicOrdering::Relaxed);
@@ -177,7 +178,8 @@ impl BatchVerifier {
 		if pending.len() > 0 {
 			let (sender, receiver) = std::sync::mpsc::channel();
 			self.scheduler.spawn(
-				"substrate_batch_verify_join",
+				"substrate-batch-verify-join",
+				None,
 				async move {
 					futures::future::join_all(pending).await;
 					sender.send(()).expect(
diff --git a/primitives/tasks/src/lib.rs b/primitives/tasks/src/lib.rs
index e9c80ae5ff4c8..c874bb98e1ae6 100644
--- a/primitives/tasks/src/lib.rs
+++ b/primitives/tasks/src/lib.rs
@@ -95,6 +95,7 @@ mod inner {
 		let extra_scheduler = scheduler.clone();
 		scheduler.spawn(
 			"parallel-runtime-spawn",
+			Some("substrate-runtime"),
 			Box::pin(async move {
 				let result = match crate::new_async_externalities(extra_scheduler) {
 					Ok(mut ext) => {
diff --git a/test-utils/test-runner/src/client.rs b/test-utils/test-runner/src/client.rs
index 58c4cf6503a93..27c04c40fe6fe 100644
--- a/test-utils/test-runner/src/client.rs
+++ b/test-utils/test-runner/src/client.rs
@@ -235,7 +235,9 @@ where
 	});
 
 	// spawn the authorship task as an essential task.
-	task_manager.spawn_essential_handle().spawn("manual-seal", authorship_future);
+	task_manager
+		.spawn_essential_handle()
+		.spawn("manual-seal", None, authorship_future);
 
 	network_starter.start_network();
 	let rpc_handler = rpc_handlers.io_handler();

From dc899259640256c0c545b262dd3388b126d52b01 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 11 Nov 2021 19:43:04 +0100
Subject: [PATCH 0218/1472] Bump git2 from 0.13.22 to 0.13.23 (#10238)

Bumps [git2](https://github.com/rust-lang/git2-rs) from 0.13.22 to 0.13.23.
- [Release notes](https://github.com/rust-lang/git2-rs/releases)
- [Commits](https://github.com/rust-lang/git2-rs/compare/0.13.22...0.13.23)

---
updated-dependencies:
- dependency-name: git2
  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 ++++----
 utils/frame/generate-bags/Cargo.toml | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 423ec1de4e7de..5d0251bca6316 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2479,9 +2479,9 @@ dependencies = [
 
 [[package]]
 name = "git2"
-version = "0.13.22"
+version = "0.13.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c1cbbfc9a1996c6af82c2b4caf828d2c653af4fcdbb0e5674cc966eee5a4197"
+checksum = "2a8057932925d3a9d9e4434ea016570d37420ddb1ceed45a174d577f24ed6700"
 dependencies = [
  "bitflags",
  "libc",
@@ -3313,9 +3313,9 @@ checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
 
 [[package]]
 name = "libgit2-sys"
-version = "0.12.23+1.2.0"
+version = "0.12.24+1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29730a445bae719db3107078b46808cc45a5b7a6bae3f31272923af969453356"
+checksum = "ddbd6021eef06fb289a8f54b3c2acfdd85ff2a585dfbb24b8576325373d2152c"
 dependencies = [
  "cc",
  "libc",
diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml
index 225584b69069e..4bc27021b4c57 100644
--- a/utils/frame/generate-bags/Cargo.toml
+++ b/utils/frame/generate-bags/Cargo.toml
@@ -21,6 +21,6 @@ sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" }
 
 # third party
 chrono = { version = "0.4.19" }
-git2 = { version = "0.13.20", default-features = false }
+git2 = { version = "0.13.23", default-features = false }
 num-format = { version = "0.4.0" }
 structopt = "0.3.21"

From e5abe5566e5a76b3deb9b6c2766e88d32ac07eb0 Mon Sep 17 00:00:00 2001
From: Guillaume Thiolliere 
Date: Thu, 11 Nov 2021 23:53:43 +0100
Subject: [PATCH 0219/1472] Warn about usage of pallet collective set members
 call. (#10156)

* warn

* Apply suggestions from code review

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* fmt

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
---
 frame/collective/src/lib.rs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs
index 89d4c8a150c36..2797d01ffcdba 100644
--- a/frame/collective/src/lib.rs
+++ b/frame/collective/src/lib.rs
@@ -345,6 +345,13 @@ pub mod pallet {
 		/// NOTE: Does not enforce the expected `MaxMembers` limit on the amount of members, but
 		///       the weight estimations rely on it to estimate dispatchable weight.
 		///
+		/// # WARNING:
+		///
+		/// The `pallet-collective` can also be managed by logic outside of the pallet through the
+		/// implementation of the trait [`ChangeMembers`].
+		/// Any call to `set_members` must be careful that the member set doesn't get out of sync
+		/// with other logic managing the member set.
+		///
 		/// # 
 		/// ## Weight
 		/// - `O(MP + N)` where:

From 2208ac43327d4869b3fd3fcfa44eb1a9ba11bb01 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 11 Nov 2021 23:32:27 +0000
Subject: [PATCH 0220/1472] Bump thiserror from 1.0.26 to 1.0.30 (#10240)

Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.26 to 1.0.30.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.26...1.0.30)

---
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                             | 8 ++++----
 client/allocator/Cargo.toml            | 2 +-
 client/api/Cargo.toml                  | 2 +-
 client/cli/Cargo.toml                  | 2 +-
 client/consensus/common/Cargo.toml     | 2 +-
 client/consensus/slots/Cargo.toml      | 2 +-
 client/consensus/uncles/Cargo.toml     | 2 +-
 client/executor/common/Cargo.toml      | 2 +-
 client/service/Cargo.toml              | 2 +-
 client/sync-state-rpc/Cargo.toml       | 2 +-
 client/telemetry/Cargo.toml            | 2 +-
 client/tracing/Cargo.toml              | 2 +-
 client/transaction-pool/Cargo.toml     | 2 +-
 client/transaction-pool/api/Cargo.toml | 2 +-
 primitives/api/Cargo.toml              | 2 +-
 primitives/blockchain/Cargo.toml       | 2 +-
 primitives/consensus/common/Cargo.toml | 2 +-
 primitives/core/Cargo.toml             | 2 +-
 primitives/inherents/Cargo.toml        | 2 +-
 primitives/state-machine/Cargo.toml    | 2 +-
 primitives/timestamp/Cargo.toml        | 2 +-
 primitives/version/Cargo.toml          | 2 +-
 22 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 5d0251bca6316..5d2fa99ca55a5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10461,18 +10461,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.26"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
+checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.26"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
+checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml
index 6d324b09acde5..44facf0ad8892 100644
--- a/client/allocator/Cargo.toml
+++ b/client/allocator/Cargo.toml
@@ -17,4 +17,4 @@ targets = ["x86_64-unknown-linux-gnu"]
 sp-core = { version = "4.0.0-dev", path = "../../primitives/core" }
 sp-wasm-interface = { version = "4.0.0-dev", path = "../../primitives/wasm-interface" }
 log = "0.4.11"
-thiserror = "1.0.21"
+thiserror = "1.0.30"
diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml
index 431d6e2fb0157..39fe804a1415d 100644
--- a/client/api/Cargo.toml
+++ b/client/api/Cargo.toml
@@ -41,4 +41,4 @@ prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.
 [dev-dependencies]
 sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" }
 substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" }
-thiserror = "1.0.21"
+thiserror = "1.0.30"
diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml
index 6107206be34e8..9dc7ff730600b 100644
--- a/client/cli/Cargo.toml
+++ b/client/cli/Cargo.toml
@@ -42,7 +42,7 @@ structopt = "0.3.8"
 sc-tracing = { version = "4.0.0-dev", path = "../tracing" }
 chrono = "0.4.10"
 serde = "1.0.126"
-thiserror = "1.0.21"
+thiserror = "1.0.30"
 rpassword = "5.0.0"
 
 [dev-dependencies]
diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml
index 3f8380d3f81bc..c26e250edf24c 100644
--- a/client/consensus/common/Cargo.toml
+++ b/client/consensus/common/Cargo.toml
@@ -13,7 +13,7 @@ readme = "README.md"
 targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
-thiserror = "1.0.21"
+thiserror = "1.0.30"
 libp2p = { version = "0.39.1", default-features = false }
 log = "0.4.8"
 futures = { version = "0.3.1", features = ["thread-pool"] }
diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml
index 5c5f1bdfa68cd..ff4fdf041b4fe 100644
--- a/client/consensus/slots/Cargo.toml
+++ b/client/consensus/slots/Cargo.toml
@@ -31,7 +31,7 @@ sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" }
 futures = "0.3.9"
 futures-timer = "3.0.1"
 log = "0.4.11"
-thiserror = "1.0.21"
+thiserror = "1.0.30"
 async-trait = "0.1.50"
 
 [dev-dependencies]
diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml
index f644d64c7bbeb..bc5f1f25838c9 100644
--- a/client/consensus/uncles/Cargo.toml
+++ b/client/consensus/uncles/Cargo.toml
@@ -16,4 +16,4 @@ targets = ["x86_64-unknown-linux-gnu"]
 sc-client-api = { version = "4.0.0-dev", path = "../../api" }
 sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" }
 sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" }
-thiserror = "1.0.21"
+thiserror = "1.0.30"
diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml
index 2d9f4672768e9..276fe9a8380b4 100644
--- a/client/executor/common/Cargo.toml
+++ b/client/executor/common/Cargo.toml
@@ -23,7 +23,7 @@ sc-allocator = { version = "4.1.0-dev", path = "../../allocator" }
 sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-interface" }
 sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" }
 sp-serializer = { version = "4.0.0-dev", path = "../../../primitives/serializer" }
-thiserror = "1.0.21"
+thiserror = "1.0.30"
 environmental = "1.1.3"
 
 wasmer = { version = "1.0", optional = true }
diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml
index c090495fe04ec..38729fd4ba5ce 100644
--- a/client/service/Cargo.toml
+++ b/client/service/Cargo.toml
@@ -22,7 +22,7 @@ wasmtime = ["sc-executor/wasmtime"]
 test-helpers = []
 
 [dependencies]
-thiserror = "1.0.21"
+thiserror = "1.0.30"
 futures = "0.3.16"
 jsonrpc-pubsub = "18.0"
 jsonrpc-core = "18.0"
diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml
index a9503b992ab37..6d8d95954629c 100644
--- a/client/sync-state-rpc/Cargo.toml
+++ b/client/sync-state-rpc/Cargo.toml
@@ -13,7 +13,7 @@ readme = "README.md"
 targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
-thiserror = "1.0.21"
+thiserror = "1.0.30"
 jsonrpc-core = "18.0.0"
 jsonrpc-core-client = "18.0.0"
 jsonrpc-derive = "18.0.0"
diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml
index 5a25aca29b60b..744a0610a07e3 100644
--- a/client/telemetry/Cargo.toml
+++ b/client/telemetry/Cargo.toml
@@ -25,4 +25,4 @@ rand = "0.7.2"
 serde = { version = "1.0.126", features = ["derive"] }
 serde_json = "1.0.68"
 chrono = "0.4.19"
-thiserror = "1.0.21"
+thiserror = "1.0.30"
diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml
index 8640208ad3427..6a969b33deb1a 100644
--- a/client/tracing/Cargo.toml
+++ b/client/tracing/Cargo.toml
@@ -24,7 +24,7 @@ parking_lot = "0.11.1"
 regex = "1.5.4"
 rustc-hash = "1.1.0"
 serde = "1.0.126"
-thiserror = "1.0.21"
+thiserror = "1.0.30"
 tracing = "0.1.29"
 tracing-log = "0.1.2"
 tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] }
diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml
index d26969cf1e092..3d2a450c4101a 100644
--- a/client/transaction-pool/Cargo.toml
+++ b/client/transaction-pool/Cargo.toml
@@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 codec = { package = "parity-scale-codec", version = "2.0.0" }
-thiserror = "1.0.21"
+thiserror = "1.0.30"
 futures = "0.3.16"
 intervalier = "0.4.0"
 log = "0.4.8"
diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml
index 176624611fbf5..1ab1ef5bb4a16 100644
--- a/client/transaction-pool/api/Cargo.toml
+++ b/client/transaction-pool/api/Cargo.toml
@@ -12,7 +12,7 @@ description = "Transaction pool client facing API."
 futures = { version = "0.3.1"  }
 log = { version = "0.4.8" }
 serde = { version = "1.0.126", features = ["derive"] }
-thiserror = { version = "1.0.21" }
+thiserror = { version = "1.0.30" }
 sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" }
 
 derive_more = { version = "0.99.11" }
diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml
index 65da54b87753d..5723f9cf11b51 100644
--- a/primitives/api/Cargo.toml
+++ b/primitives/api/Cargo.toml
@@ -21,7 +21,7 @@ sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runti
 sp-version = { version = "4.0.0-dev", default-features = false, path = "../version" }
 sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../state-machine" }
 hash-db = { version = "0.15.2", optional = true }
-thiserror = { version = "1.0.21", optional = true }
+thiserror = { version = "1.0.30", optional = true }
 
 log = { version = "0.4.14", default-features = false }
 
diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml
index de73af10966e1..02e74a63d9590 100644
--- a/primitives/blockchain/Cargo.toml
+++ b/primitives/blockchain/Cargo.toml
@@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 log = "0.4.11"
 lru = "0.7.0"
 parking_lot = "0.11.1"
-thiserror = "1.0.21"
+thiserror = "1.0.30"
 futures = "0.3.9"
 codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
 sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" }
diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml
index 735b1e8eb095d..08e50a954288c 100644
--- a/primitives/consensus/common/Cargo.toml
+++ b/primitives/consensus/common/Cargo.toml
@@ -27,7 +27,7 @@ futures-timer = "3.0.1"
 sp-std = { version = "4.0.0-dev", path = "../../std" }
 sp-version = { version = "4.0.0-dev", path = "../../version" }
 sp-runtime = { version = "4.0.0-dev", path = "../../runtime" }
-thiserror = "1.0.21"
+thiserror = "1.0.30"
 
 [dev-dependencies]
 futures = "0.3.9"
diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml
index 48749904763fd..eaf1d26c2898c 100644
--- a/primitives/core/Cargo.toml
+++ b/primitives/core/Cargo.toml
@@ -48,7 +48,7 @@ parity-util-mem = { version = "0.10.2", default-features = false, features = [
 ] }
 futures = { version = "0.3.1", optional = true }
 dyn-clonable = { version = "0.9.0", optional = true }
-thiserror = { version = "1.0.21", optional = true }
+thiserror = { version = "1.0.30", optional = true }
 bitflags = "1.3"
 
 # full crypto
diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml
index d52140d94ed31..3efd6ab032131 100644
--- a/primitives/inherents/Cargo.toml
+++ b/primitives/inherents/Cargo.toml
@@ -19,7 +19,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" }
 sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" }
 sp-runtime = { version = "4.0.0-dev", path = "../runtime", optional = true }
 codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
-thiserror = { version = "1.0.21", optional = true }
+thiserror = { version = "1.0.30", optional = true }
 impl-trait-for-tuples = "0.2.0"
 async-trait = { version = "0.1.50", optional = true }
 
diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml
index c919d7fbef6ad..783837a6442b6 100644
--- a/primitives/state-machine/Cargo.toml
+++ b/primitives/state-machine/Cargo.toml
@@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 log = { version = "0.4.11", optional = true }
-thiserror = { version = "1.0.21", optional = true }
+thiserror = { version = "1.0.30", optional = true }
 parking_lot = { version = "0.11.1", optional = true }
 hash-db = { version = "0.15.2", default-features = false }
 trie-db = { version = "0.22.6", default-features = false }
diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml
index 552a3cb5e8d63..609ecd0d31921 100644
--- a/primitives/timestamp/Cargo.toml
+++ b/primitives/timestamp/Cargo.toml
@@ -18,7 +18,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" }
 sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" }
 codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
 sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" }
-thiserror = { version = "1.0.21", optional = true }
+thiserror = { version = "1.0.30", optional = true }
 log = { version = "0.4.8", optional = true }
 futures-timer = { version = "3.0.2", optional = true }
 async-trait = { version = "0.1.50", optional = true }
diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml
index af44aed6c5b21..bbdaf9c1cab1b 100644
--- a/primitives/version/Cargo.toml
+++ b/primitives/version/Cargo.toml
@@ -23,7 +23,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" }
 sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" }
 sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" }
 parity-wasm = { version = "0.42.2", optional = true }
-thiserror = { version = "1.0.21", optional = true }
+thiserror = { version = "1.0.30", optional = true }
 
 [features]
 default = ["std"]

From 5d22361ebbd9b5ccafd87f3f50d2646ad59b6c0b Mon Sep 17 00:00:00 2001
From: Doordashcon <90750465+Doordashcon@users.noreply.github.com>
Date: Fri, 12 Nov 2021 00:48:37 +0100
Subject: [PATCH 0221/1472] tuple to struct event variants (#10206)

* update sudo pallet

* Update mock.rs

* cargo +nightly fmt

* frame-support remote-externalities

* AFNPEV tips

* AFNPEV bin & update sudo

* cargo +nightly fmt

* optional dependency remote-test feature

* fmt

Co-authored-by: Shawn Tabrizi 
---
 bin/node/executor/tests/fees.rs             |  9 ++++--
 frame/sudo/src/lib.rs                       | 16 +++++----
 frame/sudo/src/mock.rs                      |  8 ++---
 frame/sudo/src/tests.rs                     | 10 +++---
 frame/tips/src/lib.rs                       | 36 ++++++++++++---------
 frame/tips/src/tests.rs                     | 10 +++---
 utils/frame/remote-externalities/Cargo.toml |  3 +-
 7 files changed, 51 insertions(+), 41 deletions(-)

diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs
index 379cdda5b76a3..4c7593bdb3ab2 100644
--- a/bin/node/executor/tests/fees.rs
+++ b/bin/node/executor/tests/fees.rs
@@ -241,7 +241,10 @@ fn block_weight_capacity_report() {
 		let mut xts = (0..num_transfers)
 			.map(|i| CheckedExtrinsic {
 				signed: Some((charlie(), signed_extra(nonce + i as Index, 0))),
-				function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 0)),
+				function: Call::Balances(pallet_balances::Call::transfer {
+					dest: bob().into(),
+					value: 0,
+				}),
 			})
 			.collect::>();
 
@@ -249,7 +252,7 @@ fn block_weight_capacity_report() {
 			0,
 			CheckedExtrinsic {
 				signed: None,
-				function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)),
+				function: Call::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }),
 			},
 		);
 
@@ -319,7 +322,7 @@ fn block_length_capacity_report() {
 			vec![
 				CheckedExtrinsic {
 					signed: None,
-					function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)),
+					function: Call::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }),
 				},
 				CheckedExtrinsic {
 					signed: Some((charlie(), signed_extra(nonce, 0))),
diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs
index 427455849bb00..5f8e6fc0cc13a 100644
--- a/frame/sudo/src/lib.rs
+++ b/frame/sudo/src/lib.rs
@@ -150,7 +150,7 @@ pub mod pallet {
 			ensure!(sender == Self::key(), Error::::RequireSudo);
 
 			let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into());
-			Self::deposit_event(Event::Sudid(res.map(|_| ()).map_err(|e| e.error)));
+			Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) });
 			// Sudo user does not pay a fee.
 			Ok(Pays::No.into())
 		}
@@ -176,7 +176,7 @@ pub mod pallet {
 			ensure!(sender == Self::key(), Error::::RequireSudo);
 
 			let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into());
-			Self::deposit_event(Event::Sudid(res.map(|_| ()).map_err(|e| e.error)));
+			Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) });
 			// Sudo user does not pay a fee.
 			Ok(Pays::No.into())
 		}
@@ -201,7 +201,7 @@ pub mod pallet {
 			ensure!(sender == Self::key(), Error::::RequireSudo);
 			let new = T::Lookup::lookup(new)?;
 
-			Self::deposit_event(Event::KeyChanged(Self::key()));
+			Self::deposit_event(Event::KeyChanged { new_sudoer: Self::key() });
 			>::put(new);
 			// Sudo user does not pay a fee.
 			Ok(Pays::No.into())
@@ -241,7 +241,9 @@ pub mod pallet {
 
 			let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Signed(who).into());
 
-			Self::deposit_event(Event::SudoAsDone(res.map(|_| ()).map_err(|e| e.error)));
+			Self::deposit_event(Event::SudoAsDone {
+				sudo_result: res.map(|_| ()).map_err(|e| e.error),
+			});
 			// Sudo user does not pay a fee.
 			Ok(Pays::No.into())
 		}
@@ -251,11 +253,11 @@ pub mod pallet {
 	#[pallet::generate_deposit(pub(super) fn deposit_event)]
 	pub enum Event {
 		/// A sudo just took place. \[result\]
-		Sudid(DispatchResult),
+		Sudid { sudo_result: DispatchResult },
 		/// The \[sudoer\] just switched identity; the old key is supplied.
-		KeyChanged(T::AccountId),
+		KeyChanged { new_sudoer: T::AccountId },
 		/// A sudo just took place. \[result\]
-		SudoAsDone(DispatchResult),
+		SudoAsDone { sudo_result: DispatchResult },
 	}
 
 	#[pallet::error]
diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs
index dad17384d5603..bfbed0d38ab34 100644
--- a/frame/sudo/src/mock.rs
+++ b/frame/sudo/src/mock.rs
@@ -58,7 +58,7 @@ pub mod logger {
 			// Ensure that the `origin` is `Root`.
 			ensure_root(origin)?;
 			>::append(i);
-			Self::deposit_event(Event::AppendI32(i, weight));
+			Self::deposit_event(Event::AppendI32 { value: i, weight });
 			Ok(().into())
 		}
 
@@ -72,7 +72,7 @@ pub mod logger {
 			let sender = ensure_signed(origin)?;
 			>::append(i);
 			>::append(sender.clone());
-			Self::deposit_event(Event::AppendI32AndAccount(sender, i, weight));
+			Self::deposit_event(Event::AppendI32AndAccount { sender, value: i, weight });
 			Ok(().into())
 		}
 	}
@@ -80,8 +80,8 @@ pub mod logger {
 	#[pallet::event]
 	#[pallet::generate_deposit(pub(super) fn deposit_event)]
 	pub enum Event {
-		AppendI32(i32, Weight),
-		AppendI32AndAccount(T::AccountId, i32, Weight),
+		AppendI32 { value: i32, weight: Weight },
+		AppendI32AndAccount { sender: T::AccountId, value: i32, weight: Weight },
 	}
 
 	#[pallet::storage]
diff --git a/frame/sudo/src/tests.rs b/frame/sudo/src/tests.rs
index 2eb558e9471c4..3fd199a1c8ca3 100644
--- a/frame/sudo/src/tests.rs
+++ b/frame/sudo/src/tests.rs
@@ -58,7 +58,7 @@ fn sudo_emits_events_correctly() {
 		// Should emit event to indicate success when called with the root `key` and `call` is `Ok`.
 		let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: 1 }));
 		assert_ok!(Sudo::sudo(Origin::signed(1), call));
-		System::assert_has_event(TestEvent::Sudo(Event::Sudid(Ok(()))));
+		System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) }));
 	})
 }
 
@@ -96,7 +96,7 @@ fn sudo_unchecked_weight_emits_events_correctly() {
 		// Should emit event to indicate success when called with the root `key` and `call` is `Ok`.
 		let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: 1 }));
 		assert_ok!(Sudo::sudo_unchecked_weight(Origin::signed(1), call, 1_000));
-		System::assert_has_event(TestEvent::Sudo(Event::Sudid(Ok(()))));
+		System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) }));
 	})
 }
 
@@ -123,10 +123,10 @@ fn set_key_emits_events_correctly() {
 
 		// A root `key` can change the root `key`.
 		assert_ok!(Sudo::set_key(Origin::signed(1), 2));
-		System::assert_has_event(TestEvent::Sudo(Event::KeyChanged(1)));
+		System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { new_sudoer: 1 }));
 		// Double check.
 		assert_ok!(Sudo::set_key(Origin::signed(2), 4));
-		System::assert_has_event(TestEvent::Sudo(Event::KeyChanged(2)));
+		System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { new_sudoer: 2 }));
 	});
 }
 
@@ -161,6 +161,6 @@ fn sudo_as_emits_events_correctly() {
 		// A non-privileged function will work when passed to `sudo_as` with the root `key`.
 		let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { i: 42, weight: 1 }));
 		assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call));
-		System::assert_has_event(TestEvent::Sudo(Event::SudoAsDone(Ok(()))));
+		System::assert_has_event(TestEvent::Sudo(Event::SudoAsDone { sudo_result: Ok(()) }));
 	});
 }
diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs
index f4a4edb7b3999..5aad9af346603 100644
--- a/frame/tips/src/lib.rs
+++ b/frame/tips/src/lib.rs
@@ -179,16 +179,16 @@ pub mod pallet {
 	#[pallet::event]
 	#[pallet::generate_deposit(pub(super) fn deposit_event)]
 	pub enum Event {
-		/// A new tip suggestion has been opened. \[tip_hash\]
-		NewTip(T::Hash),
-		/// A tip suggestion has reached threshold and is closing. \[tip_hash\]
-		TipClosing(T::Hash),
-		/// A tip suggestion has been closed. \[tip_hash, who, payout\]
-		TipClosed(T::Hash, T::AccountId, BalanceOf),
-		/// A tip suggestion has been retracted. \[tip_hash\]
-		TipRetracted(T::Hash),
-		/// A tip suggestion has been slashed. \[tip_hash, finder, deposit\]
-		TipSlashed(T::Hash, T::AccountId, BalanceOf),
+		/// A new tip suggestion has been opened.
+		NewTip { tip_hash: T::Hash },
+		/// A tip suggestion has reached threshold and is closing.
+		TipClosing { tip_hash: T::Hash },
+		/// A tip suggestion has been closed.
+		TipClosed { tip_hash: T::Hash, who: T::AccountId, payout: BalanceOf },
+		/// A tip suggestion has been retracted.
+		TipRetracted { tip_hash: T::Hash },
+		/// A tip suggestion has been slashed.
+		TipSlashed { tip_hash: T::Hash, finder: T::AccountId, deposit: BalanceOf },
 	}
 
 	/// Old name generated by `decl_event`.
@@ -265,7 +265,7 @@ pub mod pallet {
 				finders_fee: true,
 			};
 			Tips::::insert(&hash, tip);
-			Self::deposit_event(Event::NewTip(hash));
+			Self::deposit_event(Event::NewTip { tip_hash: hash });
 			Ok(())
 		}
 
@@ -300,7 +300,7 @@ pub mod pallet {
 				let err_amount = T::Currency::unreserve(&who, tip.deposit);
 				debug_assert!(err_amount.is_zero());
 			}
-			Self::deposit_event(Event::TipRetracted(hash));
+			Self::deposit_event(Event::TipRetracted { tip_hash: hash });
 			Ok(())
 		}
 
@@ -340,7 +340,7 @@ pub mod pallet {
 			let hash = T::Hashing::hash_of(&(&reason_hash, &who));
 
 			Reasons::::insert(&reason_hash, &reason);
-			Self::deposit_event(Event::NewTip(hash.clone()));
+			Self::deposit_event(Event::NewTip { tip_hash: hash.clone() });
 			let tips = vec![(tipper.clone(), tip_value)];
 			let tip = OpenTip {
 				reason: reason_hash,
@@ -390,7 +390,7 @@ pub mod pallet {
 
 			let mut tip = Tips::::get(hash).ok_or(Error::::UnknownTip)?;
 			if Self::insert_tip_and_check_closing(&mut tip, tipper, tip_value) {
-				Self::deposit_event(Event::TipClosing(hash.clone()));
+				Self::deposit_event(Event::TipClosing { tip_hash: hash.clone() });
 			}
 			Tips::::insert(&hash, tip);
 			Ok(())
@@ -449,7 +449,11 @@ pub mod pallet {
 				T::OnSlash::on_unbalanced(imbalance);
 			}
 			Reasons::::remove(&tip.reason);
-			Self::deposit_event(Event::TipSlashed(hash, tip.finder, tip.deposit));
+			Self::deposit_event(Event::TipSlashed {
+				tip_hash: hash,
+				finder: tip.finder,
+				deposit: tip.deposit,
+			});
 			Ok(())
 		}
 	}
@@ -544,7 +548,7 @@ impl Pallet {
 		// same as above: best-effort only.
 		let res = T::Currency::transfer(&treasury, &tip.who, payout, KeepAlive);
 		debug_assert!(res.is_ok());
-		Self::deposit_event(Event::TipClosed(hash, tip.who, payout));
+		Self::deposit_event(Event::TipClosed { tip_hash: hash, who: tip.who, payout });
 	}
 
 	pub fn migrate_retract_tip_for_tip_new(module: &[u8], item: &[u8]) {
diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs
index 7ea80d78c5532..2aac22ffe18ca 100644
--- a/frame/tips/src/tests.rs
+++ b/frame/tips/src/tests.rs
@@ -267,7 +267,7 @@ fn close_tip_works() {
 
 		let h = tip_hash();
 
-		assert_eq!(last_event(), TipEvent::NewTip(h));
+		assert_eq!(last_event(), TipEvent::NewTip { tip_hash: h });
 
 		assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10));
 
@@ -275,7 +275,7 @@ fn close_tip_works() {
 
 		assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10));
 
-		assert_eq!(last_event(), TipEvent::TipClosing(h));
+		assert_eq!(last_event(), TipEvent::TipClosing { tip_hash: h });
 
 		assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::::Premature);
 
@@ -284,7 +284,7 @@ fn close_tip_works() {
 		assert_ok!(Tips::close_tip(Origin::signed(0), h.into()));
 		assert_eq!(Balances::free_balance(3), 10);
 
-		assert_eq!(last_event(), TipEvent::TipClosed(h, 3, 10));
+		assert_eq!(last_event(), TipEvent::TipClosed { tip_hash: h, who: 3, payout: 10 });
 
 		assert_noop!(Tips::close_tip(Origin::signed(100), h.into()), Error::::UnknownTip);
 	});
@@ -306,14 +306,14 @@ fn slash_tip_works() {
 		assert_eq!(Balances::free_balance(0), 88);
 
 		let h = tip_hash();
-		assert_eq!(last_event(), TipEvent::NewTip(h));
+		assert_eq!(last_event(), TipEvent::NewTip { tip_hash: h });
 
 		// can't remove from any origin
 		assert_noop!(Tips::slash_tip(Origin::signed(0), h.clone()), BadOrigin);
 
 		// can remove from root.
 		assert_ok!(Tips::slash_tip(Origin::root(), h.clone()));
-		assert_eq!(last_event(), TipEvent::TipSlashed(h, 0, 12));
+		assert_eq!(last_event(), TipEvent::TipSlashed { tip_hash: h, finder: 0, deposit: 12 });
 
 		// tipper slashed
 		assert_eq!(Balances::reserved_balance(0), 0);
diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml
index f2482f9c423db..56f797343c0f4 100644
--- a/utils/frame/remote-externalities/Cargo.toml
+++ b/utils/frame/remote-externalities/Cargo.toml
@@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 jsonrpsee = { version = "0.4.1", features = ["ws-client", "macros"] }
 
 env_logger = "0.9"
+frame-support = { path = "../../../frame/support", optional = true }
 log = "0.4.11"
 codec = { package = "parity-scale-codec", version = "2.0.0" }
 serde_json = "1.0"
@@ -32,4 +33,4 @@ pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", versio
 frame-support = { path = "../../../frame/support", version = "4.0.0-dev" }
 
 [features]
-remote-test = []
+remote-test = ["frame-support"]

From c45c1cbfde0037e6ef650146789a0aa0190fdefb Mon Sep 17 00:00:00 2001
From: Arkadiy Paronyan 
Date: Fri, 12 Nov 2021 14:15:01 +0100
Subject: [PATCH 0222/1472] Kill the light client, CHTs and change tries.
 (#10080)

* Remove light client, change tries and CHTs

* Update tests

* fmt

* Restore changes_root

* Fixed benches

* Cargo fmt

* fmt

* fmt
---
 Cargo.lock                                    |   20 -
 Cargo.toml                                    |    1 -
 bin/node-template/node/src/chain_spec.rs      |    1 -
 bin/node-template/node/src/service.rs         |    3 -
 bin/node/cli/src/chain_spec.rs                |    5 +-
 bin/node/cli/src/service.rs                   |    7 +-
 bin/node/executor/benches/bench.rs            |    4 +-
 bin/node/executor/tests/basic.rs              |   72 +-
 bin/node/executor/tests/common.rs             |   11 +-
 bin/node/executor/tests/fees.rs               |   14 +-
 bin/node/executor/tests/submit_transaction.rs |   12 +-
 bin/node/primitives/src/lib.rs                |    2 +-
 bin/node/rpc/src/lib.rs                       |   35 -
 bin/node/testing/src/bench.rs                 |    1 -
 bin/node/testing/src/client.rs                |    6 +-
 bin/node/testing/src/genesis.rs               |   16 +-
 client/api/src/backend.rs                     |  109 +-
 client/api/src/cht.rs                         |  474 ----
 client/api/src/in_mem.rs                      |  123 +-
 client/api/src/lib.rs                         |    3 -
 client/api/src/light.rs                       |  372 ---
 client/api/src/proof_provider.rs              |   25 +-
 .../basic-authorship/src/basic_authorship.rs  |   14 +-
 client/block-builder/src/lib.rs               |   15 +-
 client/consensus/aura/src/import_queue.rs     |   18 +-
 client/consensus/aura/src/lib.rs              |   78 +-
 client/consensus/babe/src/lib.rs              |   41 +-
 client/consensus/babe/src/tests.rs            |   22 +-
 client/consensus/babe/src/verification.rs     |   13 +-
 client/consensus/common/src/block_import.rs   |    8 +-
 client/consensus/manual-seal/src/consensus.rs |    8 +-
 .../manual-seal/src/consensus/babe.rs         |   17 +-
 client/consensus/pow/src/lib.rs               |   18 +-
 client/consensus/slots/src/lib.rs             |   10 +-
 client/db/src/cache/list_cache.rs             | 2351 -----------------
 client/db/src/cache/list_entry.rs             |  187 --
 client/db/src/cache/list_storage.rs           |  441 ----
 client/db/src/cache/mod.rs                    |  413 ---
 client/db/src/changes_tries_storage.rs        | 1168 --------
 client/db/src/lib.rs                          |  273 +-
 client/db/src/light.rs                        | 1329 ----------
 client/db/src/parity_db.rs                    |    6 +-
 client/db/src/utils.rs                        |   79 +-
 client/executor/src/integration_tests/mod.rs  |    2 +-
 client/finality-grandpa/src/import.rs         |    7 +-
 client/finality-grandpa/src/lib.rs            |    5 +-
 client/finality-grandpa/src/tests.rs          |   47 +-
 client/light/Cargo.toml                       |   27 -
 client/light/README.md                        |    3 -
 client/light/src/backend.rs                   |  578 ----
 client/light/src/blockchain.rs                |  219 --
 client/light/src/call_executor.rs             |  206 --
 client/light/src/lib.rs                       |   41 -
 client/network/src/behaviour.rs               |   50 +-
 client/network/src/config.rs                  |    6 -
 client/network/src/lib.rs                     |    1 -
 client/network/src/light_client_requests.rs   |  268 --
 .../src/light_client_requests/handler.rs      |  119 +-
 .../src/light_client_requests/sender.rs       | 1294 ---------
 client/network/src/on_demand_layer.rs         |  241 --
 client/network/src/service.rs                 |   37 -
 client/network/src/service/tests.rs           |    1 -
 client/network/test/src/lib.rs                |  185 +-
 client/network/test/src/sync.rs               |  105 +-
 client/rpc/src/chain/chain_light.rs           |  114 -
 client/rpc/src/chain/mod.rs                   |   29 +-
 client/rpc/src/state/state_full.rs            |  125 +-
 client/rpc/src/state/tests.rs                 |   34 +-
 client/service/src/builder.rs                 |   27 +-
 client/service/src/client/call_executor.rs    |   18 +-
 client/service/src/client/client.rs           |  401 +--
 client/service/src/lib.rs                     |    2 +-
 client/service/test/Cargo.toml                |    1 -
 client/service/test/src/client/db.rs          |    1 -
 client/service/test/src/client/mod.rs         |  274 +-
 client/transaction-pool/src/api.rs            |  134 +-
 client/transaction-pool/src/lib.rs            |   32 +-
 frame/aura/src/lib.rs                         |    4 +-
 frame/babe/src/lib.rs                         |    2 +-
 frame/beefy-mmr/src/tests.rs                  |    2 +-
 frame/beefy/src/lib.rs                        |    4 +-
 frame/beefy/src/tests.rs                      |    3 +-
 frame/executive/src/lib.rs                    |    7 +-
 frame/grandpa/src/lib.rs                      |    2 +-
 frame/grandpa/src/mock.rs                     |    2 +-
 frame/support/src/storage/mod.rs              |   17 +-
 frame/system/benchmarking/src/lib.rs          |   21 +-
 frame/system/src/lib.rs                       |   64 +-
 .../api/proc-macro/src/impl_runtime_apis.rs   |    5 -
 .../proc-macro/src/mock_impl_runtime_apis.rs  |    4 -
 primitives/api/src/lib.rs                     |    5 +-
 primitives/api/test/tests/runtime_calls.rs    |    2 +-
 primitives/blockchain/src/backend.rs          |   31 -
 primitives/consensus/aura/src/digests.rs      |    4 +-
 primitives/consensus/babe/src/digests.rs      |    7 +-
 primitives/consensus/common/src/lib.rs        |    8 +-
 primitives/core/src/changes_trie.rs           |  321 ---
 primitives/core/src/lib.rs                    |    2 -
 primitives/externalities/src/lib.rs           |    7 -
 primitives/io/src/lib.rs                      |   15 +-
 primitives/runtime-interface/test/src/lib.rs  |    2 +-
 primitives/runtime/src/generic/digest.rs      |  248 +-
 primitives/runtime/src/generic/header.rs      |   26 +-
 primitives/runtime/src/generic/mod.rs         |    2 +-
 primitives/runtime/src/generic/tests.rs       |   15 +-
 primitives/runtime/src/testing.rs             |    4 +-
 primitives/runtime/src/traits.rs              |   16 +-
 primitives/state-machine/src/backend.rs       |   26 -
 primitives/state-machine/src/basic.rs         |    4 -
 .../state-machine/src/changes_trie/build.rs   | 1083 --------
 .../src/changes_trie/build_cache.rs           |  278 --
 .../src/changes_trie/build_iterator.rs        |  487 ----
 .../src/changes_trie/changes_iterator.rs      |  748 ------
 .../state-machine/src/changes_trie/input.rs   |  207 --
 .../state-machine/src/changes_trie/mod.rs     |  428 ---
 .../state-machine/src/changes_trie/prune.rs   |  204 --
 .../state-machine/src/changes_trie/storage.rs |  214 --
 .../src/changes_trie/surface_iterator.rs      |  326 ---
 primitives/state-machine/src/ext.rs           |  195 +-
 primitives/state-machine/src/lib.rs           |  210 +-
 .../src/overlayed_changes/changeset.rs        |    1 -
 .../src/overlayed_changes/mod.rs              |  146 +-
 primitives/state-machine/src/read_only.rs     |    4 -
 primitives/state-machine/src/testing.rs       |   73 +-
 primitives/storage/src/lib.rs                 |    3 -
 primitives/tasks/src/async_externalities.rs   |    4 -
 primitives/test-primitives/src/lib.rs         |    9 +-
 test-utils/client/Cargo.toml                  |    1 -
 test-utils/client/src/lib.rs                  |   10 +-
 test-utils/runtime/client/Cargo.toml          |    1 -
 .../runtime/client/src/block_builder_ext.rs   |   13 -
 test-utils/runtime/client/src/lib.rs          |  169 +-
 test-utils/runtime/src/genesismap.rs          |    7 -
 test-utils/runtime/src/lib.rs                 |   13 +-
 test-utils/runtime/src/system.rs              |   36 +-
 test-utils/test-runner/src/client.rs          |    3 -
 test-utils/test-runner/src/node.rs            |   16 +-
 utils/frame/benchmarking-cli/src/command.rs   |   14 +-
 utils/frame/rpc/system/src/lib.rs             |   89 +-
 .../cli/src/commands/follow_chain.rs          |    7 +-
 utils/frame/try-runtime/cli/src/lib.rs        |    3 +-
 141 files changed, 534 insertions(+), 17809 deletions(-)
 delete mode 100644 client/api/src/cht.rs
 delete mode 100644 client/api/src/light.rs
 delete mode 100644 client/db/src/cache/list_cache.rs
 delete mode 100644 client/db/src/cache/list_entry.rs
 delete mode 100644 client/db/src/cache/list_storage.rs
 delete mode 100644 client/db/src/cache/mod.rs
 delete mode 100644 client/db/src/changes_tries_storage.rs
 delete mode 100644 client/db/src/light.rs
 delete mode 100644 client/light/Cargo.toml
 delete mode 100644 client/light/README.md
 delete mode 100644 client/light/src/backend.rs
 delete mode 100644 client/light/src/blockchain.rs
 delete mode 100644 client/light/src/call_executor.rs
 delete mode 100644 client/light/src/lib.rs
 delete mode 100644 client/network/src/light_client_requests/sender.rs
 delete mode 100644 client/network/src/on_demand_layer.rs
 delete mode 100644 client/rpc/src/chain/chain_light.rs
 delete mode 100644 primitives/core/src/changes_trie.rs
 delete mode 100644 primitives/state-machine/src/changes_trie/build.rs
 delete mode 100644 primitives/state-machine/src/changes_trie/build_cache.rs
 delete mode 100644 primitives/state-machine/src/changes_trie/build_iterator.rs
 delete mode 100644 primitives/state-machine/src/changes_trie/changes_iterator.rs
 delete mode 100644 primitives/state-machine/src/changes_trie/input.rs
 delete mode 100644 primitives/state-machine/src/changes_trie/mod.rs
 delete mode 100644 primitives/state-machine/src/changes_trie/prune.rs
 delete mode 100644 primitives/state-machine/src/changes_trie/storage.rs
 delete mode 100644 primitives/state-machine/src/changes_trie/surface_iterator.rs

diff --git a/Cargo.lock b/Cargo.lock
index 5d2fa99ca55a5..74504d5f1547b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8209,23 +8209,6 @@ dependencies = [
  "tempfile",
 ]
 
-[[package]]
-name = "sc-light"
-version = "4.0.0-dev"
-dependencies = [
- "hash-db",
- "parity-scale-codec",
- "parking_lot 0.11.1",
- "sc-client-api",
- "sc-executor",
- "sp-api",
- "sp-blockchain",
- "sp-core",
- "sp-externalities",
- "sp-runtime",
- "sp-state-machine",
-]
-
 [[package]]
 name = "sc-network"
 version = "0.10.0-dev"
@@ -8558,7 +8541,6 @@ dependencies = [
  "sc-client-db",
  "sc-consensus",
  "sc-executor",
- "sc-light",
  "sc-network",
  "sc-service",
  "sc-transaction-pool-api",
@@ -10176,7 +10158,6 @@ dependencies = [
  "sc-client-db",
  "sc-consensus",
  "sc-executor",
- "sc-light",
  "sc-offchain",
  "sc-service",
  "serde",
@@ -10245,7 +10226,6 @@ dependencies = [
  "sc-block-builder",
  "sc-client-api",
  "sc-consensus",
- "sc-light",
  "sp-api",
  "sp-blockchain",
  "sp-consensus",
diff --git a/Cargo.toml b/Cargo.toml
index ca60af692497d..e03f33a4d27d5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -42,7 +42,6 @@ members = [
 	"client/finality-grandpa",
 	"client/informant",
 	"client/keystore",
-	"client/light",
 	"client/network",
 	"client/network-gossip",
 	"client/network/test",
diff --git a/bin/node-template/node/src/chain_spec.rs b/bin/node-template/node/src/chain_spec.rs
index baf5e5d41ab85..d32a0dcb29d00 100644
--- a/bin/node-template/node/src/chain_spec.rs
+++ b/bin/node-template/node/src/chain_spec.rs
@@ -134,7 +134,6 @@ fn testnet_genesis(
 		system: SystemConfig {
 			// Add Wasm runtime to storage.
 			code: wasm_binary.to_vec(),
-			changes_trie_config: Default::default(),
 		},
 		balances: BalancesConfig {
 			// Configure endowed accounts with initial balance of 1 << 60.
diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs
index c71336c330882..82b1c5625373c 100644
--- a/bin/node-template/node/src/service.rs
+++ b/bin/node-template/node/src/service.rs
@@ -194,7 +194,6 @@ pub fn new_full(mut config: Configuration) -> Result
 			transaction_pool: transaction_pool.clone(),
 			spawn_handle: task_manager.spawn_handle(),
 			import_queue,
-			on_demand: None,
 			block_announce_validator_builder: None,
 			warp_sync: Some(warp_sync),
 		})?;
@@ -234,8 +233,6 @@ pub fn new_full(mut config: Configuration) -> Result
 		task_manager: &mut task_manager,
 		transaction_pool: transaction_pool.clone(),
 		rpc_extensions_builder,
-		on_demand: None,
-		remote_blockchain: None,
 		backend,
 		system_rpc_tx,
 		config,
diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs
index 7b1ed90017c36..6d11722081e30 100644
--- a/bin/node/cli/src/chain_spec.rs
+++ b/bin/node/cli/src/chain_spec.rs
@@ -295,10 +295,7 @@ pub fn testnet_genesis(
 	const STASH: Balance = ENDOWMENT / 1000;
 
 	GenesisConfig {
-		system: SystemConfig {
-			code: wasm_binary_unwrap().to_vec(),
-			changes_trie_config: Default::default(),
-		},
+		system: SystemConfig { code: wasm_binary_unwrap().to_vec() },
 		balances: BalancesConfig {
 			balances: endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect(),
 		},
diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs
index dee546bf07001..e73b69153d1df 100644
--- a/bin/node/cli/src/service.rs
+++ b/bin/node/cli/src/service.rs
@@ -338,7 +338,6 @@ pub fn new_full_base(
 			transaction_pool: transaction_pool.clone(),
 			spawn_handle: task_manager.spawn_handle(),
 			import_queue,
-			on_demand: None,
 			block_announce_validator_builder: None,
 			warp_sync: Some(warp_sync),
 		})?;
@@ -369,8 +368,6 @@ pub fn new_full_base(
 		rpc_extensions_builder: Box::new(rpc_extensions_builder),
 		transaction_pool: transaction_pool.clone(),
 		task_manager: &mut task_manager,
-		on_demand: None,
-		remote_blockchain: None,
 		system_rpc_tx,
 		telemetry: telemetry.as_mut(),
 	})?;
@@ -542,7 +539,7 @@ mod tests {
 	use sc_service_test::TestNetNode;
 	use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool};
 	use sp_consensus::{BlockOrigin, Environment, Proposer};
-	use sp_core::{crypto::Pair as CryptoPair, Public, H256};
+	use sp_core::{crypto::Pair as CryptoPair, Public};
 	use sp_inherents::InherentDataProvider;
 	use sp_keyring::AccountKeyring;
 	use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
@@ -621,7 +618,7 @@ mod tests {
 					None,
 				);
 
-				let mut digest = Digest::::default();
+				let mut digest = Digest::default();
 
 				// even though there's only one authority some slots might be empty,
 				// so we must keep trying the next slots until we can claim one.
diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs
index 1a39c9decb321..03c3eb53e23f9 100644
--- a/bin/node/executor/benches/bench.rs
+++ b/bin/node/executor/benches/bench.rs
@@ -53,7 +53,7 @@ const SPEC_VERSION: u32 = node_runtime::VERSION.spec_version;
 
 const HEAP_PAGES: u64 = 20;
 
-type TestExternalities = CoreTestExternalities;
+type TestExternalities = CoreTestExternalities;
 
 #[derive(Debug)]
 enum ExecutionMethod {
@@ -188,7 +188,7 @@ fn bench_execute_block(c: &mut Criterion) {
 
 	for strategy in execution_methods {
 		group.bench_function(format!("{:?}", strategy), |b| {
-			let genesis_config = node_testing::genesis::config(false, Some(compact_code_unwrap()));
+			let genesis_config = node_testing::genesis::config(Some(compact_code_unwrap()));
 			let (use_native, wasm_method) = match strategy {
 				ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted),
 				ExecutionMethod::Wasm(wasm_method) => (false, wasm_method),
diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs
index bbb9339189b06..b7df7bf0bd41a 100644
--- a/bin/node/executor/tests/basic.rs
+++ b/bin/node/executor/tests/basic.rs
@@ -29,7 +29,7 @@ use sp_runtime::{
 use node_primitives::{Balance, Hash};
 use node_runtime::{
 	constants::{currency::*, time::SLOT_DURATION},
-	Balances, Block, Call, CheckedExtrinsic, Event, Header, Runtime, System, TransactionPayment,
+	Balances, Call, CheckedExtrinsic, Event, Header, Runtime, System, TransactionPayment,
 	UncheckedExtrinsic,
 };
 use node_testing::keyring::*;
@@ -78,7 +78,7 @@ fn set_heap_pages(ext: &mut E, heap_pages: u64) {
 fn changes_trie_block() -> (Vec, Hash) {
 	let time = 42 * 1000;
 	construct_block(
-		&mut new_test_ext(compact_code_unwrap(), true),
+		&mut new_test_ext(compact_code_unwrap()),
 		1,
 		GENESIS_HASH.into(),
 		vec![
@@ -102,7 +102,7 @@ fn changes_trie_block() -> (Vec, Hash) {
 /// are not guaranteed to be deterministic) and to ensure that the correct state is propagated
 /// from block1's execution to block2 to derive the correct storage_root.
 fn blocks() -> ((Vec, Hash), (Vec, Hash)) {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	let time1 = 42 * 1000;
 	let block1 = construct_block(
 		&mut t,
@@ -160,7 +160,7 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) {
 
 fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec, Hash) {
 	construct_block(
-		&mut new_test_ext(compact_code_unwrap(), false),
+		&mut new_test_ext(compact_code_unwrap()),
 		1,
 		GENESIS_HASH.into(),
 		vec![
@@ -179,7 +179,7 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec, Hash) {
 
 #[test]
 fn panic_execution_with_foreign_code_gives_error() {
-	let mut t = new_test_ext(bloaty_code_unwrap(), false);
+	let mut t = new_test_ext(bloaty_code_unwrap());
 	t.insert(
 		>::hashed_key_for(alice()),
 		(69u128, 0u32, 0u128, 0u128, 0u128).encode(),
@@ -211,7 +211,7 @@ fn panic_execution_with_foreign_code_gives_error() {
 
 #[test]
 fn bad_extrinsic_with_native_equivalent_code_gives_error() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	t.insert(
 		>::hashed_key_for(alice()),
 		(0u32, 0u32, 0u32, 69u128, 0u128, 0u128, 0u128).encode(),
@@ -243,7 +243,7 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() {
 
 #[test]
 fn successful_execution_with_native_equivalent_code_gives_ok() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	t.insert(
 		>::hashed_key_for(alice()),
 		AccountInfo::<::Index, _> {
@@ -296,7 +296,7 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
 
 #[test]
 fn successful_execution_with_foreign_code_gives_ok() {
-	let mut t = new_test_ext(bloaty_code_unwrap(), false);
+	let mut t = new_test_ext(bloaty_code_unwrap());
 	t.insert(
 		>::hashed_key_for(alice()),
 		AccountInfo::<::Index, _> {
@@ -349,7 +349,7 @@ fn successful_execution_with_foreign_code_gives_ok() {
 
 #[test]
 fn full_native_block_import_works() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 
 	let (block1, block2) = blocks();
 
@@ -529,7 +529,7 @@ fn full_native_block_import_works() {
 
 #[test]
 fn full_wasm_block_import_works() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 
 	let (block1, block2) = blocks();
 
@@ -679,7 +679,7 @@ fn deploying_wasm_contract_should_work() {
 
 	let time = 42 * 1000;
 	let b = construct_block(
-		&mut new_test_ext(compact_code_unwrap(), false),
+		&mut new_test_ext(compact_code_unwrap()),
 		1,
 		GENESIS_HASH.into(),
 		vec![
@@ -712,7 +712,7 @@ fn deploying_wasm_contract_should_work() {
 		(time / SLOT_DURATION).into(),
 	);
 
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 
 	executor_call:: _>(&mut t, "Core_execute_block", &b.0, false, None)
 		.0
@@ -727,7 +727,7 @@ fn deploying_wasm_contract_should_work() {
 
 #[test]
 fn wasm_big_block_import_fails() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 
 	set_heap_pages(&mut t.ext(), 4);
 
@@ -744,7 +744,7 @@ fn wasm_big_block_import_fails() {
 
 #[test]
 fn native_big_block_import_succeeds() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 
 	executor_call:: _>(
 		&mut t,
@@ -759,7 +759,7 @@ fn native_big_block_import_succeeds() {
 
 #[test]
 fn native_big_block_import_fails_on_fallback() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 
 	// We set the heap pages to 8 because we know that should give an OOM in WASM with the given
 	// block.
@@ -778,7 +778,7 @@ fn native_big_block_import_fails_on_fallback() {
 
 #[test]
 fn panic_execution_gives_error() {
-	let mut t = new_test_ext(bloaty_code_unwrap(), false);
+	let mut t = new_test_ext(bloaty_code_unwrap());
 	t.insert(
 		>::hashed_key_for(alice()),
 		AccountInfo::<::Index, _> {
@@ -815,7 +815,7 @@ fn panic_execution_gives_error() {
 
 #[test]
 fn successful_execution_gives_ok() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	t.insert(
 		>::hashed_key_for(alice()),
 		AccountInfo::<::Index, _> {
@@ -874,44 +874,6 @@ fn successful_execution_gives_ok() {
 	});
 }
 
-#[test]
-fn full_native_block_import_works_with_changes_trie() {
-	let block1 = changes_trie_block();
-	let block_data = block1.0;
-	let block = Block::decode(&mut &block_data[..]).unwrap();
-
-	let mut t = new_test_ext(compact_code_unwrap(), true);
-	executor_call:: _>(
-		&mut t,
-		"Core_execute_block",
-		&block.encode(),
-		true,
-		None,
-	)
-	.0
-	.unwrap();
-
-	assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some());
-}
-
-#[test]
-fn full_wasm_block_import_works_with_changes_trie() {
-	let block1 = changes_trie_block();
-
-	let mut t = new_test_ext(compact_code_unwrap(), true);
-	executor_call:: _>(
-		&mut t,
-		"Core_execute_block",
-		&block1.0,
-		false,
-		None,
-	)
-	.0
-	.unwrap();
-
-	assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some());
-}
-
 #[test]
 fn should_import_block_with_test_client() {
 	use node_testing::client::{
diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs
index d1c24c83c836d..c81d6b7c14e02 100644
--- a/bin/node/executor/tests/common.rs
+++ b/bin/node/executor/tests/common.rs
@@ -81,7 +81,7 @@ pub const SPEC_VERSION: u32 = node_runtime::VERSION.spec_version;
 
 pub const TRANSACTION_VERSION: u32 = node_runtime::VERSION.transaction_version;
 
-pub type TestExternalities = CoreTestExternalities;
+pub type TestExternalities = CoreTestExternalities;
 
 pub fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic {
 	node_testing::keyring::sign(xt, SPEC_VERSION, TRANSACTION_VERSION, GENESIS_HASH)
@@ -123,14 +123,11 @@ pub fn executor_call<
 	executor().call::(&mut t, &runtime_code, method, data, use_native, native_call)
 }
 
-pub fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities {
-	let mut ext = TestExternalities::new_with_code(
+pub fn new_test_ext(code: &[u8]) -> TestExternalities {
+	let ext = TestExternalities::new_with_code(
 		code,
-		node_testing::genesis::config(support_changes_trie, Some(code))
-			.build_storage()
-			.unwrap(),
+		node_testing::genesis::config(Some(code)).build_storage().unwrap(),
 	);
-	ext.changes_trie_storage().insert(0, GENESIS_HASH.into(), Default::default());
 	ext
 }
 
diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs
index 4c7593bdb3ab2..4767c1bda1fcd 100644
--- a/bin/node/executor/tests/fees.rs
+++ b/bin/node/executor/tests/fees.rs
@@ -36,7 +36,7 @@ use self::common::{sign, *};
 
 #[test]
 fn fee_multiplier_increases_and_decreases_on_big_weight() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 
 	// initial fee multiplier must be one.
 	let mut prev_multiplier = Multiplier::one();
@@ -45,7 +45,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
 		assert_eq!(TransactionPayment::next_fee_multiplier(), prev_multiplier);
 	});
 
-	let mut tt = new_test_ext(compact_code_unwrap(), false);
+	let mut tt = new_test_ext(compact_code_unwrap());
 
 	let time1 = 42 * 1000;
 	// big one in terms of weight.
@@ -151,7 +151,7 @@ fn transaction_fee_is_correct() {
 	//   - 1 MILLICENTS in substrate node.
 	//   - 1 milli-dot based on current polkadot runtime.
 	// (this baed on assigning 0.1 CENT to the cheapest tx with `weight = 100`)
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	t.insert(>::hashed_key_for(alice()), new_account_info(100));
 	t.insert(>::hashed_key_for(bob()), new_account_info(10));
 	t.insert(
@@ -226,9 +226,9 @@ fn block_weight_capacity_report() {
 	use node_primitives::Index;
 
 	// execution ext.
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	// setup ext.
-	let mut tt = new_test_ext(compact_code_unwrap(), false);
+	let mut tt = new_test_ext(compact_code_unwrap());
 
 	let factor = 50;
 	let mut time = 10;
@@ -303,9 +303,9 @@ fn block_length_capacity_report() {
 	use node_primitives::Index;
 
 	// execution ext.
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	// setup ext.
-	let mut tt = new_test_ext(compact_code_unwrap(), false);
+	let mut tt = new_test_ext(compact_code_unwrap());
 
 	let factor = 256 * 1024;
 	let mut time = 10;
diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs
index 19ca8e5677c43..f047c6a44a667 100644
--- a/bin/node/executor/tests/submit_transaction.rs
+++ b/bin/node/executor/tests/submit_transaction.rs
@@ -28,7 +28,7 @@ use self::common::*;
 
 #[test]
 fn should_submit_unsigned_transaction() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	let (pool, state) = TestTransactionPoolExt::new();
 	t.register_extension(TransactionPoolExt::new(pool));
 
@@ -56,7 +56,7 @@ const PHRASE: &str = "news slush supreme milk chapter athlete soap sausage put c
 
 #[test]
 fn should_submit_signed_transaction() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	let (pool, state) = TestTransactionPoolExt::new();
 	t.register_extension(TransactionPoolExt::new(pool));
 
@@ -99,7 +99,7 @@ fn should_submit_signed_transaction() {
 
 #[test]
 fn should_submit_signed_twice_from_the_same_account() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	let (pool, state) = TestTransactionPoolExt::new();
 	t.register_extension(TransactionPoolExt::new(pool));
 
@@ -156,7 +156,7 @@ fn should_submit_signed_twice_from_the_same_account() {
 
 #[test]
 fn should_submit_signed_twice_from_all_accounts() {
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	let (pool, state) = TestTransactionPoolExt::new();
 	t.register_extension(TransactionPoolExt::new(pool));
 
@@ -220,7 +220,7 @@ fn submitted_transaction_should_be_valid() {
 		transaction_validity::{TransactionSource, TransactionTag},
 	};
 
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	let (pool, state) = TestTransactionPoolExt::new();
 	t.register_extension(TransactionPoolExt::new(pool));
 
@@ -249,7 +249,7 @@ fn submitted_transaction_should_be_valid() {
 	// check that transaction is valid, but reset environment storage,
 	// since CreateTransaction increments the nonce
 	let tx0 = state.read().transactions[0].clone();
-	let mut t = new_test_ext(compact_code_unwrap(), false);
+	let mut t = new_test_ext(compact_code_unwrap());
 	t.execute_with(|| {
 		let source = TransactionSource::External;
 		let extrinsic = UncheckedExtrinsic::decode(&mut &*tx0).unwrap();
diff --git a/bin/node/primitives/src/lib.rs b/bin/node/primitives/src/lib.rs
index dade598c704d2..fc3bd5f5114e3 100644
--- a/bin/node/primitives/src/lib.rs
+++ b/bin/node/primitives/src/lib.rs
@@ -57,7 +57,7 @@ pub type Hash = sp_core::H256;
 pub type Timestamp = u64;
 
 /// Digest item type.
-pub type DigestItem = generic::DigestItem;
+pub type DigestItem = generic::DigestItem;
 /// Header type.
 pub type Header = generic::Header;
 /// Block type.
diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs
index 2f7862d3d2644..51ab191d5e9a5 100644
--- a/bin/node/rpc/src/lib.rs
+++ b/bin/node/rpc/src/lib.rs
@@ -51,18 +51,6 @@ use sp_consensus::SelectChain;
 use sp_consensus_babe::BabeApi;
 use sp_keystore::SyncCryptoStorePtr;
 
-/// Light client extra dependencies.
-pub struct LightDeps {
-	/// The client instance to use.
-	pub client: Arc,
-	/// Transaction pool instance.
-	pub pool: Arc

, - /// Remote access to the blockchain (async). - pub remote_blockchain: Arc>, - /// Fetcher instance. - pub fetcher: Arc, -} - /// Extra dependencies for BABE. pub struct BabeDeps { /// BABE protocol config. @@ -183,26 +171,3 @@ where Ok(io) } - -/// Instantiate all Light RPC extensions. -pub fn create_light(deps: LightDeps) -> jsonrpc_core::IoHandler -where - C: sp_blockchain::HeaderBackend, - C: Send + Sync + 'static, - F: sc_client_api::light::Fetcher + 'static, - P: TransactionPool + 'static, - M: jsonrpc_core::Metadata + Default, -{ - use substrate_frame_rpc_system::{LightSystem, SystemApi}; - - let LightDeps { client, pool, remote_blockchain, fetcher } = deps; - let mut io = jsonrpc_core::IoHandler::default(); - io.extend_with(SystemApi::::to_delegate(LightSystem::new( - client, - remote_blockchain, - fetcher, - pool, - ))); - - io -} diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 5ee1ec998be4d..3240497a9d623 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -591,7 +591,6 @@ impl BenchKeyring { /// Generate genesis with accounts from this keyring endowed with some balance. pub fn generate_genesis(&self) -> node_runtime::GenesisConfig { crate::genesis::config_endowed( - false, Some(node_runtime::wasm_binary_unwrap()), self.collect_account_ids(), ) diff --git a/bin/node/testing/src/client.rs b/bin/node/testing/src/client.rs index 8bd75834c5496..4852e33de6070 100644 --- a/bin/node/testing/src/client.rs +++ b/bin/node/testing/src/client.rs @@ -42,13 +42,11 @@ pub type Transaction = sc_client_api::backend::TransactionFor Storage { - crate::genesis::config(self.support_changes_trie, None).build_storage().unwrap() + crate::genesis::config(None).build_storage().unwrap() } } diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index 80399a6670e86..fa0dd22c9c995 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -24,22 +24,17 @@ use node_runtime::{ GenesisConfig, GrandpaConfig, IndicesConfig, SessionConfig, SocietyConfig, StakerStatus, StakingConfig, SystemConfig, BABE_GENESIS_EPOCH_CONFIG, }; -use sp_core::ChangesTrieConfiguration; use sp_keyring::{Ed25519Keyring, Sr25519Keyring}; use sp_runtime::Perbill; /// Create genesis runtime configuration for tests. -pub fn config(support_changes_trie: bool, code: Option<&[u8]>) -> GenesisConfig { - config_endowed(support_changes_trie, code, Default::default()) +pub fn config(code: Option<&[u8]>) -> GenesisConfig { + config_endowed(code, Default::default()) } /// Create genesis runtime configuration for tests with some extra /// endowed accounts. -pub fn config_endowed( - support_changes_trie: bool, - code: Option<&[u8]>, - extra_endowed: Vec, -) -> GenesisConfig { +pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec) -> GenesisConfig { let mut endowed = vec![ (alice(), 111 * DOLLARS), (bob(), 100 * DOLLARS), @@ -53,11 +48,6 @@ pub fn config_endowed( GenesisConfig { system: SystemConfig { - changes_trie_config: if support_changes_trie { - Some(ChangesTrieConfiguration { digest_interval: 2, digest_levels: 2 }) - } else { - None - }, code: code.map(|x| x.to_vec()).unwrap_or_else(|| wasm_binary_unwrap().to_vec()), }, indices: IndicesConfig { indices: vec![] }, diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 9dfe82a57ab3b..a681d75fe9af3 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -20,27 +20,22 @@ use crate::{ blockchain::{well_known_cache_keys, Backend as BlockchainBackend}, - light::RemoteBlockchain, UsageInfo, }; use parking_lot::RwLock; use sp_blockchain; use sp_consensus::BlockOrigin; -use sp_core::{offchain::OffchainStorage, ChangesTrieConfigurationRange}; +use sp_core::offchain::OffchainStorage; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, HashFor, NumberFor}, Justification, Justifications, Storage, }; use sp_state_machine::{ - ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction, ChildStorageCollection, IndexOperation, OffchainChangesCollection, StorageCollection, }; -use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey}; -use std::{ - collections::{HashMap, HashSet}, - sync::Arc, -}; +use sp_storage::{ChildInfo, StorageData, StorageKey}; +use std::collections::{HashMap, HashSet}; pub use sp_state_machine::{Backend as StateBackend, KeyValueStates}; use std::marker::PhantomData; @@ -191,12 +186,6 @@ pub trait BlockImportOperation { Ok(()) } - /// Inject changes trie data into the database. - fn update_changes_trie( - &mut self, - update: ChangesTrieTransaction, NumberFor>, - ) -> sp_blockchain::Result<()>; - /// Insert auxiliary keys. /// /// Values are `None` if should be deleted. @@ -418,28 +407,6 @@ pub trait StorageProvider> { child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result>; - - /// Get longest range within [first; last] that is possible to use in `key_changes` - /// and `key_changes_proof` calls. - /// Range could be shortened from the beginning if some changes tries have been pruned. - /// Returns Ok(None) if changes tries are not supported. - fn max_key_changes_range( - &self, - first: NumberFor, - last: BlockId, - ) -> sp_blockchain::Result, BlockId)>>; - - /// Get pairs of (block, extrinsic) where key has been changed at given blocks range. - /// Works only for runtimes that are supporting changes tries. - /// - /// Changes are returned in descending order (i.e. last block comes first). - fn key_changes( - &self, - first: NumberFor, - last: BlockId, - storage_key: Option<&PrefixedStorageKey>, - key: &StorageKey, - ) -> sp_blockchain::Result, u32)>>; } /// Client backend. @@ -504,9 +471,6 @@ pub trait Backend: AuxStore + Send + Sync { /// Returns current usage statistics. fn usage_info(&self) -> Option; - /// Returns reference to changes trie storage. - fn changes_trie_storage(&self) -> Option<&dyn PrunableStateChangesTrieStorage>; - /// Returns a handle to offchain storage. fn offchain_storage(&self) -> Option; @@ -561,72 +525,5 @@ pub trait Backend: AuxStore + Send + Sync { fn get_import_lock(&self) -> &RwLock<()>; } -/// Changes trie storage that supports pruning. -pub trait PrunableStateChangesTrieStorage: - StateChangesTrieStorage, NumberFor> -{ - /// Get reference to StateChangesTrieStorage. - fn storage(&self) -> &dyn StateChangesTrieStorage, NumberFor>; - /// Get configuration at given block. - fn configuration_at( - &self, - at: &BlockId, - ) -> sp_blockchain::Result, Block::Hash>>; - /// Get end block (inclusive) of oldest pruned max-level (or skewed) digest trie blocks range. - /// It is guaranteed that we have no any changes tries before (and including) this block. - /// It is guaranteed that all existing changes tries after this block are not yet pruned (if - /// created). - fn oldest_pruned_digest_range_end(&self) -> NumberFor; -} - /// Mark for all Backend implementations, that are making use of state data, stored locally. pub trait LocalBackend: Backend {} - -/// Mark for all Backend implementations, that are fetching required state data from remote nodes. -pub trait RemoteBackend: Backend { - /// Returns true if the state for given block is available locally. - fn is_local_state_available(&self, block: &BlockId) -> bool; - - /// Returns reference to blockchain backend. - /// - /// Returned backend either resolves blockchain data - /// locally, or prepares request to fetch that data from remote node. - fn remote_blockchain(&self) -> Arc>; -} - -/// Return changes tries state at given block. -pub fn changes_tries_state_at_block<'a, Block: BlockT>( - block: &BlockId, - maybe_storage: Option<&'a dyn PrunableStateChangesTrieStorage>, -) -> sp_blockchain::Result, NumberFor>>> { - let storage = match maybe_storage { - Some(storage) => storage, - None => return Ok(None), - }; - - let config_range = storage.configuration_at(block)?; - match config_range.config { - Some(config) => - Ok(Some(ChangesTrieState::new(config, config_range.zero.0, storage.storage()))), - None => Ok(None), - } -} - -/// Provide CHT roots. These are stored on a light client and generated dynamically on a full -/// client. -pub trait ProvideChtRoots { - /// Get headers CHT root for given block. Returns None if the block is not a part of any CHT. - fn header_cht_root( - &self, - cht_size: NumberFor, - block: NumberFor, - ) -> sp_blockchain::Result>; - - /// Get changes trie CHT root for given block. Returns None if the block is not a part of any - /// CHT. - fn changes_trie_cht_root( - &self, - cht_size: NumberFor, - block: NumberFor, - ) -> sp_blockchain::Result>; -} diff --git a/client/api/src/cht.rs b/client/api/src/cht.rs deleted file mode 100644 index ee7854b5d8297..0000000000000 --- a/client/api/src/cht.rs +++ /dev/null @@ -1,474 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Canonical hash trie definitions and helper functions. -//! -//! Each CHT is a trie mapping block numbers to canonical hash. -//! One is generated for every `SIZE` blocks, allowing us to discard those blocks in -//! favor of the trie root. When the "ancient" blocks need to be accessed, we simply -//! request an inclusion proof of a specific block number against the trie with the -//! root hash. A correct proof implies that the claimed block is identical to the one -//! we discarded. - -use codec::Encode; -use hash_db; -use sp_trie; - -use sp_core::{convert_hash, H256}; -use sp_runtime::traits::{AtLeast32Bit, Header as HeaderT, One, Zero}; -use sp_state_machine::{ - prove_read_on_trie_backend, read_proof_check, read_proof_check_on_proving_backend, - Backend as StateBackend, InMemoryBackend, MemoryDB, StorageProof, TrieBackend, -}; - -use sp_blockchain::{Error as ClientError, Result as ClientResult}; - -/// The size of each CHT. This value is passed to every CHT-related function from -/// production code. Other values are passed from tests. -const SIZE: u32 = 2048; - -/// Gets default CHT size. -pub fn size>() -> N { - SIZE.into() -} - -/// Returns Some(cht_number) if CHT is need to be built when the block with given number is -/// canonized. -pub fn is_build_required(cht_size: N, block_num: N) -> Option -where - N: Clone + AtLeast32Bit, -{ - let block_cht_num = block_to_cht_number(cht_size.clone(), block_num.clone())?; - let two = N::one() + N::one(); - if block_cht_num < two { - return None - } - let cht_start = start_number(cht_size, block_cht_num.clone()); - if cht_start != block_num { - return None - } - - Some(block_cht_num - two) -} - -/// Returns Some(max_cht_number) if CHT has ever been built given maximal canonical block number. -pub fn max_cht_number(cht_size: N, max_canonical_block: N) -> Option -where - N: Clone + AtLeast32Bit, -{ - let max_cht_number = block_to_cht_number(cht_size, max_canonical_block)?; - let two = N::one() + N::one(); - if max_cht_number < two { - return None - } - Some(max_cht_number - two) -} - -/// Compute a CHT root from an iterator of block hashes. Fails if shorter than -/// SIZE items. The items are assumed to proceed sequentially from `start_number(cht_num)`. -/// Discards the trie's nodes. -pub fn compute_root( - cht_size: Header::Number, - cht_num: Header::Number, - hashes: I, -) -> ClientResult -where - Header: HeaderT, - Hasher: hash_db::Hasher, - Hasher::Out: Ord, - I: IntoIterator>>, -{ - use sp_trie::TrieConfiguration; - Ok(sp_trie::trie_types::Layout::::trie_root(build_pairs::( - cht_size, cht_num, hashes, - )?)) -} - -/// Build CHT-based header proof. -pub fn build_proof( - cht_size: Header::Number, - cht_num: Header::Number, - blocks: BlocksI, - hashes: HashesI, -) -> ClientResult -where - Header: HeaderT, - Hasher: hash_db::Hasher, - Hasher::Out: Ord + codec::Codec, - BlocksI: IntoIterator, - HashesI: IntoIterator>>, -{ - let transaction = build_pairs::(cht_size, cht_num, hashes)? - .into_iter() - .map(|(k, v)| (k, Some(v))) - .collect::>(); - let storage = InMemoryBackend::::default().update(vec![(None, transaction)]); - let trie_storage = storage - .as_trie_backend() - .expect("InMemoryState::as_trie_backend always returns Some; qed"); - prove_read_on_trie_backend( - trie_storage, - blocks.into_iter().map(|number| encode_cht_key(number)), - ) - .map_err(ClientError::from_state) -} - -/// Check CHT-based header proof. -pub fn check_proof( - local_root: Header::Hash, - local_number: Header::Number, - remote_hash: Header::Hash, - remote_proof: StorageProof, -) -> ClientResult<()> -where - Header: HeaderT, - Hasher: hash_db::Hasher, - Hasher::Out: Ord + codec::Codec, -{ - do_check_proof::( - local_root, - local_number, - remote_hash, - move |local_root, local_cht_key| { - read_proof_check::( - local_root, - remote_proof, - ::std::iter::once(local_cht_key), - ) - .map(|mut map| map.remove(local_cht_key).expect("checked proof of local_cht_key; qed")) - .map_err(ClientError::from_state) - }, - ) -} - -/// Check CHT-based header proof on pre-created proving backend. -pub fn check_proof_on_proving_backend( - local_root: Header::Hash, - local_number: Header::Number, - remote_hash: Header::Hash, - proving_backend: &TrieBackend, Hasher>, -) -> ClientResult<()> -where - Header: HeaderT, - Hasher: hash_db::Hasher, - Hasher::Out: Ord + codec::Codec, -{ - do_check_proof::( - local_root, - local_number, - remote_hash, - |_, local_cht_key| { - read_proof_check_on_proving_backend::(proving_backend, local_cht_key) - .map_err(ClientError::from_state) - }, - ) -} - -/// Check CHT-based header proof using passed checker function. -fn do_check_proof( - local_root: Header::Hash, - local_number: Header::Number, - remote_hash: Header::Hash, - checker: F, -) -> ClientResult<()> -where - Header: HeaderT, - Hasher: hash_db::Hasher, - Hasher::Out: Ord, - F: FnOnce(Hasher::Out, &[u8]) -> ClientResult>>, -{ - let root: Hasher::Out = convert_hash(&local_root); - let local_cht_key = encode_cht_key(local_number); - let local_cht_value = checker(root, &local_cht_key)?; - let local_cht_value = local_cht_value.ok_or_else(|| ClientError::InvalidCHTProof)?; - let local_hash = - decode_cht_value(&local_cht_value).ok_or_else(|| ClientError::InvalidCHTProof)?; - match &local_hash[..] == remote_hash.as_ref() { - true => Ok(()), - false => Err(ClientError::InvalidCHTProof.into()), - } -} - -/// Group ordered blocks by CHT number and call functor with blocks of each group. -pub fn for_each_cht_group( - cht_size: Header::Number, - blocks: I, - mut functor: F, - mut functor_param: P, -) -> ClientResult<()> -where - Header: HeaderT, - I: IntoIterator, - F: FnMut(P, Header::Number, Vec) -> ClientResult

, -{ - let mut current_cht_num = None; - let mut current_cht_blocks = Vec::new(); - for block in blocks { - let new_cht_num = block_to_cht_number(cht_size, block).ok_or_else(|| { - ClientError::Backend(format!("Cannot compute CHT root for the block #{}", block)) - })?; - - let advance_to_next_cht = current_cht_num.is_some() && current_cht_num != Some(new_cht_num); - if advance_to_next_cht { - let current_cht_num = current_cht_num.expect( - "advance_to_next_cht is true; - it is true only when current_cht_num is Some; qed", - ); - assert!( - new_cht_num > current_cht_num, - "for_each_cht_group only supports ordered iterators" - ); - - functor_param = - functor(functor_param, current_cht_num, std::mem::take(&mut current_cht_blocks))?; - } - - current_cht_blocks.push(block); - current_cht_num = Some(new_cht_num); - } - - if let Some(current_cht_num) = current_cht_num { - functor(functor_param, current_cht_num, std::mem::take(&mut current_cht_blocks))?; - } - - Ok(()) -} - -/// Build pairs for computing CHT. -fn build_pairs( - cht_size: Header::Number, - cht_num: Header::Number, - hashes: I, -) -> ClientResult, Vec)>> -where - Header: HeaderT, - I: IntoIterator>>, -{ - let start_num = start_number(cht_size, cht_num); - let mut pairs = Vec::new(); - let mut hash_index = Header::Number::zero(); - for hash in hashes.into_iter() { - let hash = - hash?.ok_or_else(|| ClientError::from(ClientError::MissingHashRequiredForCHT))?; - pairs.push((encode_cht_key(start_num + hash_index).to_vec(), encode_cht_value(hash))); - hash_index += Header::Number::one(); - if hash_index == cht_size { - break - } - } - - if hash_index == cht_size { - Ok(pairs) - } else { - Err(ClientError::MissingHashRequiredForCHT) - } -} - -/// Get the starting block of a given CHT. -/// CHT 0 includes block 1...SIZE, -/// CHT 1 includes block SIZE + 1 ... 2*SIZE -/// More generally: CHT N includes block (1 + N*SIZE)...((N+1)*SIZE). -/// This is because the genesis hash is assumed to be known -/// and including it would be redundant. -pub fn start_number(cht_size: N, cht_num: N) -> N { - (cht_num * cht_size) + N::one() -} - -/// Get the ending block of a given CHT. -pub fn end_number(cht_size: N, cht_num: N) -> N { - (cht_num + N::one()) * cht_size -} - -/// Convert a block number to a CHT number. -/// Returns `None` for `block_num` == 0, `Some` otherwise. -pub fn block_to_cht_number(cht_size: N, block_num: N) -> Option { - if block_num == N::zero() { - None - } else { - Some((block_num - N::one()) / cht_size) - } -} - -/// Convert header number into CHT key. -pub fn encode_cht_key(number: N) -> Vec { - number.encode() -} - -/// Convert header hash into CHT value. -fn encode_cht_value>(hash: Hash) -> Vec { - hash.as_ref().to_vec() -} - -/// Convert CHT value into block header hash. -pub fn decode_cht_value(value: &[u8]) -> Option { - match value.len() { - 32 => Some(H256::from_slice(&value[0..32])), - _ => None, - } -} - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::{generic, traits::BlakeTwo256}; - - type Header = generic::Header; - - #[test] - fn is_build_required_works() { - assert_eq!(is_build_required(SIZE, 0u32.into()), None); - assert_eq!(is_build_required(SIZE, 1u32.into()), None); - assert_eq!(is_build_required(SIZE, SIZE), None); - assert_eq!(is_build_required(SIZE, SIZE + 1), None); - assert_eq!(is_build_required(SIZE, 2 * SIZE), None); - assert_eq!(is_build_required(SIZE, 2 * SIZE + 1), Some(0)); - assert_eq!(is_build_required(SIZE, 2 * SIZE + 2), None); - assert_eq!(is_build_required(SIZE, 3 * SIZE), None); - assert_eq!(is_build_required(SIZE, 3 * SIZE + 1), Some(1)); - assert_eq!(is_build_required(SIZE, 3 * SIZE + 2), None); - } - - #[test] - fn max_cht_number_works() { - assert_eq!(max_cht_number(SIZE, 0u32.into()), None); - assert_eq!(max_cht_number(SIZE, 1u32.into()), None); - assert_eq!(max_cht_number(SIZE, SIZE), None); - assert_eq!(max_cht_number(SIZE, SIZE + 1), None); - assert_eq!(max_cht_number(SIZE, 2 * SIZE), None); - assert_eq!(max_cht_number(SIZE, 2 * SIZE + 1), Some(0)); - assert_eq!(max_cht_number(SIZE, 2 * SIZE + 2), Some(0)); - assert_eq!(max_cht_number(SIZE, 3 * SIZE), Some(0)); - assert_eq!(max_cht_number(SIZE, 3 * SIZE + 1), Some(1)); - assert_eq!(max_cht_number(SIZE, 3 * SIZE + 2), Some(1)); - } - - #[test] - fn start_number_works() { - assert_eq!(start_number(SIZE, 0u32), 1u32); - assert_eq!(start_number(SIZE, 1u32), SIZE + 1); - assert_eq!(start_number(SIZE, 2u32), SIZE + SIZE + 1); - } - - #[test] - fn end_number_works() { - assert_eq!(end_number(SIZE, 0u32), SIZE); - assert_eq!(end_number(SIZE, 1u32), SIZE + SIZE); - assert_eq!(end_number(SIZE, 2u32), SIZE + SIZE + SIZE); - } - - #[test] - fn build_pairs_fails_when_no_enough_blocks() { - assert!(build_pairs::( - SIZE as _, - 0, - ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize / 2) - ) - .is_err()); - } - - #[test] - fn build_pairs_fails_when_missing_block() { - assert!(build_pairs::( - SIZE as _, - 0, - ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))) - .take(SIZE as usize / 2) - .chain(::std::iter::once(Ok(None))) - .chain( - ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(2)))) - .take(SIZE as usize / 2 - 1) - ) - ) - .is_err()); - } - - #[test] - fn compute_root_works() { - assert!(compute_root::( - SIZE as _, - 42, - ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize) - ) - .is_ok()); - } - - #[test] - #[should_panic] - fn build_proof_panics_when_querying_wrong_block() { - assert!(build_proof::( - SIZE as _, - 0, - vec![(SIZE * 1000) as u64], - ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize) - ) - .is_err()); - } - - #[test] - fn build_proof_works() { - assert!(build_proof::( - SIZE as _, - 0, - vec![(SIZE / 2) as u64], - ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize) - ) - .is_ok()); - } - - #[test] - #[should_panic] - fn for_each_cht_group_panics() { - let cht_size = SIZE as u64; - let _ = for_each_cht_group::( - cht_size, - vec![cht_size * 5, cht_size * 2], - |_, _, _| Ok(()), - (), - ); - } - - #[test] - fn for_each_cht_group_works() { - let cht_size = SIZE as u64; - let _ = for_each_cht_group::( - cht_size, - vec![ - cht_size * 2 + 1, - cht_size * 2 + 2, - cht_size * 2 + 5, - cht_size * 4 + 1, - cht_size * 4 + 7, - cht_size * 6 + 1, - ], - |_, cht_num, blocks| { - match cht_num { - 2 => assert_eq!( - blocks, - vec![cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5] - ), - 4 => assert_eq!(blocks, vec![cht_size * 4 + 1, cht_size * 4 + 7]), - 6 => assert_eq!(blocks, vec![cht_size * 6 + 1]), - _ => unreachable!(), - } - - Ok(()) - }, - (), - ); - } -} diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 2f4327dfc4e4a..39fe9e063d20b 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -29,8 +29,8 @@ use sp_runtime::{ Justification, Justifications, Storage, }; use sp_state_machine::{ - Backend as StateBackend, ChangesTrieTransaction, ChildStorageCollection, InMemoryBackend, - IndexOperation, StorageCollection, + Backend as StateBackend, ChildStorageCollection, InMemoryBackend, IndexOperation, + StorageCollection, }; use std::{ collections::{HashMap, HashSet}, @@ -39,10 +39,10 @@ use std::{ }; use crate::{ - backend::{self, NewBlockState, ProvideChtRoots}, + backend::{self, NewBlockState}, blockchain::{self, well_known_cache_keys::Id as CacheKeyId, BlockStatus, HeaderBackend}, leaves::LeafSet, - light, UsageInfo, + UsageInfo, }; struct PendingBlock { @@ -109,7 +109,6 @@ struct BlockchainStorage { finalized_number: NumberFor, genesis_hash: Block::Hash, header_cht_roots: HashMap, Block::Hash>, - changes_trie_cht_roots: HashMap, Block::Hash>, leaves: LeafSet>, aux: HashMap, Vec>, } @@ -152,7 +151,6 @@ impl Blockchain { finalized_number: Zero::zero(), genesis_hash: Default::default(), header_cht_roots: HashMap::new(), - changes_trie_cht_roots: HashMap::new(), leaves: LeafSet::new(), aux: HashMap::new(), })); @@ -442,10 +440,6 @@ impl blockchain::Backend for Blockchain { Ok(self.storage.read().finalized_hash.clone()) } - fn cache(&self) -> Option>> { - None - } - fn leaves(&self) -> sp_blockchain::Result> { Ok(self.storage.read().leaves.hashes()) } @@ -466,12 +460,6 @@ impl blockchain::Backend for Blockchain { } } -impl blockchain::ProvideCache for Blockchain { - fn cache(&self) -> Option>> { - None - } -} - impl backend::AuxStore for Blockchain { fn insert_aux< 'a, @@ -499,82 +487,6 @@ impl backend::AuxStore for Blockchain { } } -impl light::Storage for Blockchain -where - Block::Hash: From<[u8; 32]>, -{ - fn import_header( - &self, - header: Block::Header, - _cache: HashMap>, - state: NewBlockState, - aux_ops: Vec<(Vec, Option>)>, - ) -> sp_blockchain::Result<()> { - let hash = header.hash(); - self.insert(hash, header, None, None, state)?; - - self.write_aux(aux_ops); - Ok(()) - } - - fn set_head(&self, id: BlockId) -> sp_blockchain::Result<()> { - Blockchain::set_head(self, id) - } - - fn last_finalized(&self) -> sp_blockchain::Result { - Ok(self.storage.read().finalized_hash.clone()) - } - - fn finalize_header(&self, id: BlockId) -> sp_blockchain::Result<()> { - Blockchain::finalize_header(self, id, None) - } - - fn cache(&self) -> Option>> { - None - } - - fn usage_info(&self) -> Option { - None - } -} - -impl ProvideChtRoots for Blockchain { - fn header_cht_root( - &self, - _cht_size: NumberFor, - block: NumberFor, - ) -> sp_blockchain::Result> { - self.storage - .read() - .header_cht_roots - .get(&block) - .cloned() - .ok_or_else(|| { - sp_blockchain::Error::Backend(format!("Header CHT for block {} not exists", block)) - }) - .map(Some) - } - - fn changes_trie_cht_root( - &self, - _cht_size: NumberFor, - block: NumberFor, - ) -> sp_blockchain::Result> { - self.storage - .read() - .changes_trie_cht_roots - .get(&block) - .cloned() - .ok_or_else(|| { - sp_blockchain::Error::Backend(format!( - "Changes trie CHT for block {} not exists", - block - )) - }) - .map(Some) - } -} - /// In-memory operation. pub struct BlockImportOperation { pending_block: Option>, @@ -650,13 +562,6 @@ where Ok(()) } - fn update_changes_trie( - &mut self, - _update: ChangesTrieTransaction, NumberFor>, - ) -> sp_blockchain::Result<()> { - Ok(()) - } - fn set_genesis_state( &mut self, storage: Storage, @@ -846,10 +751,6 @@ where None } - fn changes_trie_storage(&self) -> Option<&dyn backend::PrunableStateChangesTrieStorage> { - None - } - fn offchain_storage(&self) -> Option { None } @@ -885,22 +786,6 @@ where impl backend::LocalBackend for Backend where Block::Hash: Ord {} -impl backend::RemoteBackend for Backend -where - Block::Hash: Ord, -{ - fn is_local_state_available(&self, block: &BlockId) -> bool { - self.blockchain - .expect_block_number_from_id(block) - .map(|num| num.is_zero()) - .unwrap_or(false) - } - - fn remote_blockchain(&self) -> Arc> { - unimplemented!() - } -} - /// Check that genesis storage is valid. pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> { if storage.top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) { diff --git a/client/api/src/lib.rs b/client/api/src/lib.rs index f1c78f6603eb8..a7029d02cbd45 100644 --- a/client/api/src/lib.rs +++ b/client/api/src/lib.rs @@ -21,19 +21,16 @@ pub mod backend; pub mod call_executor; -pub mod cht; pub mod client; pub mod execution_extensions; pub mod in_mem; pub mod leaves; -pub mod light; pub mod notifications; pub mod proof_provider; pub use backend::*; pub use call_executor::*; pub use client::*; -pub use light::*; pub use notifications::*; pub use proof_provider::*; pub use sp_blockchain as blockchain; diff --git a/client/api/src/light.rs b/client/api/src/light.rs deleted file mode 100644 index 8638ddf741f30..0000000000000 --- a/client/api/src/light.rs +++ /dev/null @@ -1,372 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Substrate light client interfaces - -use std::{ - collections::{BTreeMap, HashMap}, - future::Future, - sync::Arc, -}; - -use crate::{ - backend::{AuxStore, NewBlockState}, - ProvideChtRoots, UsageInfo, -}; -use sp_blockchain::{ - well_known_cache_keys, Cache as BlockchainCache, Error as ClientError, HeaderBackend, - HeaderMetadata, Result as ClientResult, -}; -use sp_core::{storage::PrefixedStorageKey, ChangesTrieConfigurationRange}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT, NumberFor}, -}; -use sp_state_machine::StorageProof; - -/// Remote call request. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct RemoteCallRequest { - /// Call at state of given block. - pub block: Header::Hash, - /// Header of block at which call is performed. - pub header: Header, - /// Method to call. - pub method: String, - /// Call data. - pub call_data: Vec, - /// Number of times to retry request. None means that default RETRY_COUNT is used. - pub retry_count: Option, -} - -/// Remote canonical header request. -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -pub struct RemoteHeaderRequest { - /// The root of CHT this block is included in. - pub cht_root: Header::Hash, - /// Number of the header to query. - pub block: Header::Number, - /// Number of times to retry request. None means that default RETRY_COUNT is used. - pub retry_count: Option, -} - -/// Remote storage read request. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct RemoteReadRequest { - /// Read at state of given block. - pub block: Header::Hash, - /// Header of block at which read is performed. - pub header: Header, - /// Storage key to read. - pub keys: Vec>, - /// Number of times to retry request. None means that default RETRY_COUNT is used. - pub retry_count: Option, -} - -/// Remote storage read child request. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct RemoteReadChildRequest { - /// Read at state of given block. - pub block: Header::Hash, - /// Header of block at which read is performed. - pub header: Header, - /// Storage key for child. - pub storage_key: PrefixedStorageKey, - /// Child storage key to read. - pub keys: Vec>, - /// Number of times to retry request. None means that default RETRY_COUNT is used. - pub retry_count: Option, -} - -/// Remote key changes read request. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct RemoteChangesRequest { - /// All changes trie configurations that are valid within [first_block; last_block]. - pub changes_trie_configs: Vec>, - /// Query changes from range of blocks, starting (and including) with this hash... - pub first_block: (Header::Number, Header::Hash), - /// ...ending (and including) with this hash. Should come after first_block and - /// be the part of the same fork. - pub last_block: (Header::Number, Header::Hash), - /// Only use digests from blocks up to this hash. Should be last_block OR come - /// after this block and be the part of the same fork. - pub max_block: (Header::Number, Header::Hash), - /// Known changes trie roots for the range of blocks [tries_roots.0..max_block]. - /// Proofs for roots of ascendants of tries_roots.0 are provided by the remote node. - pub tries_roots: (Header::Number, Header::Hash, Vec), - /// Optional Child Storage key to read. - pub storage_key: Option, - /// Storage key to read. - pub key: Vec, - /// Number of times to retry request. None means that default RETRY_COUNT is used. - pub retry_count: Option, -} - -/// Key changes read proof. -#[derive(Debug, PartialEq, Eq)] -pub struct ChangesProof { - /// Max block that has been used in changes query. - pub max_block: Header::Number, - /// All touched nodes of all changes tries. - pub proof: Vec>, - /// All changes tries roots that have been touched AND are missing from - /// the requester' node. It is a map of block number => changes trie root. - pub roots: BTreeMap, - /// The proofs for all changes tries roots that have been touched AND are - /// missing from the requester' node. It is a map of CHT number => proof. - pub roots_proof: StorageProof, -} - -/// Remote block body request -#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] -pub struct RemoteBodyRequest { - /// Header of the requested block body - pub header: Header, - /// Number of times to retry request. None means that default RETRY_COUNT is used. - pub retry_count: Option, -} - -/// Light client data fetcher. Implementations of this trait must check if remote data -/// is correct (see FetchedDataChecker) and return already checked data. -pub trait Fetcher: Send + Sync { - /// Remote header future. - type RemoteHeaderResult: Future> - + Unpin - + Send - + 'static; - /// Remote storage read future. - type RemoteReadResult: Future, Option>>, ClientError>> - + Unpin - + Send - + 'static; - /// Remote call result future. - type RemoteCallResult: Future, ClientError>> + Unpin + Send + 'static; - /// Remote changes result future. - type RemoteChangesResult: Future, u32)>, ClientError>> - + Unpin - + Send - + 'static; - /// Remote block body result future. - type RemoteBodyResult: Future, ClientError>> - + Unpin - + Send - + 'static; - - /// Fetch remote header. - fn remote_header( - &self, - request: RemoteHeaderRequest, - ) -> Self::RemoteHeaderResult; - /// Fetch remote storage value. - fn remote_read(&self, request: RemoteReadRequest) -> Self::RemoteReadResult; - /// Fetch remote storage child value. - fn remote_read_child( - &self, - request: RemoteReadChildRequest, - ) -> Self::RemoteReadResult; - /// Fetch remote call result. - fn remote_call(&self, request: RemoteCallRequest) -> Self::RemoteCallResult; - /// Fetch remote changes ((block number, extrinsic index)) where given key has been changed - /// at a given blocks range. - fn remote_changes( - &self, - request: RemoteChangesRequest, - ) -> Self::RemoteChangesResult; - /// Fetch remote block body - fn remote_body(&self, request: RemoteBodyRequest) -> Self::RemoteBodyResult; -} - -/// Light client remote data checker. -/// -/// Implementations of this trait should not use any prunable blockchain data -/// except that is passed to its methods. -pub trait FetchChecker: Send + Sync { - /// Check remote header proof. - fn check_header_proof( - &self, - request: &RemoteHeaderRequest, - header: Option, - remote_proof: StorageProof, - ) -> ClientResult; - /// Check remote storage read proof. - fn check_read_proof( - &self, - request: &RemoteReadRequest, - remote_proof: StorageProof, - ) -> ClientResult, Option>>>; - /// Check remote storage read proof. - fn check_read_child_proof( - &self, - request: &RemoteReadChildRequest, - remote_proof: StorageProof, - ) -> ClientResult, Option>>>; - /// Check remote method execution proof. - fn check_execution_proof( - &self, - request: &RemoteCallRequest, - remote_proof: StorageProof, - ) -> ClientResult>; - /// Check remote changes query proof. - fn check_changes_proof( - &self, - request: &RemoteChangesRequest, - proof: ChangesProof, - ) -> ClientResult, u32)>>; - /// Check remote body proof. - fn check_body_proof( - &self, - request: &RemoteBodyRequest, - body: Vec, - ) -> ClientResult>; -} - -/// Light client blockchain storage. -pub trait Storage: - AuxStore - + HeaderBackend - + HeaderMetadata - + ProvideChtRoots -{ - /// Store new header. Should refuse to revert any finalized blocks. - /// - /// Takes new authorities, the leaf state of the new block, and - /// any auxiliary storage updates to place in the same operation. - fn import_header( - &self, - header: Block::Header, - cache: HashMap>, - state: NewBlockState, - aux_ops: Vec<(Vec, Option>)>, - ) -> ClientResult<()>; - - /// Set an existing block as new best block. - fn set_head(&self, block: BlockId) -> ClientResult<()>; - - /// Mark historic header as finalized. - fn finalize_header(&self, block: BlockId) -> ClientResult<()>; - - /// Get last finalized header. - fn last_finalized(&self) -> ClientResult; - - /// Get storage cache. - fn cache(&self) -> Option>>; - - /// Get storage usage statistics. - fn usage_info(&self) -> Option; -} - -/// Remote header. -#[derive(Debug)] -pub enum LocalOrRemote { - /// When data is available locally, it is returned. - Local(Data), - /// When data is unavailable locally, the request to fetch it from remote node is returned. - Remote(Request), - /// When data is unknown. - Unknown, -} - -/// Futures-based blockchain backend that either resolves blockchain data -/// locally, or fetches required data from remote node. -pub trait RemoteBlockchain: Send + Sync { - /// Get block header. - fn header( - &self, - id: BlockId, - ) -> ClientResult>>; -} - -/// Returns future that resolves header either locally, or remotely. -pub fn future_header>( - blockchain: &dyn RemoteBlockchain, - fetcher: &F, - id: BlockId, -) -> impl Future, ClientError>> { - use futures::future::{ready, Either, FutureExt}; - - match blockchain.header(id) { - Ok(LocalOrRemote::Remote(request)) => - Either::Left(fetcher.remote_header(request).then(|header| ready(header.map(Some)))), - Ok(LocalOrRemote::Unknown) => Either::Right(ready(Ok(None))), - Ok(LocalOrRemote::Local(local_header)) => Either::Right(ready(Ok(Some(local_header)))), - Err(err) => Either::Right(ready(Err(err))), - } -} - -#[cfg(test)] -pub mod tests { - use super::*; - use futures::future::Ready; - use parking_lot::Mutex; - use sp_blockchain::Error as ClientError; - use sp_test_primitives::{Block, Extrinsic, Header}; - - #[derive(Debug, thiserror::Error)] - #[error("Not implemented on test node")] - struct MockError; - - impl Into for MockError { - fn into(self) -> ClientError { - ClientError::Application(Box::new(self)) - } - } - - pub type OkCallFetcher = Mutex>; - - fn not_implemented_in_tests() -> Ready> { - futures::future::ready(Err(MockError.into())) - } - - impl Fetcher for OkCallFetcher { - type RemoteHeaderResult = Ready>; - type RemoteReadResult = Ready, Option>>, ClientError>>; - type RemoteCallResult = Ready, ClientError>>; - type RemoteChangesResult = Ready, u32)>, ClientError>>; - type RemoteBodyResult = Ready, ClientError>>; - - fn remote_header(&self, _request: RemoteHeaderRequest

) -> Self::RemoteHeaderResult { - not_implemented_in_tests() - } - - fn remote_read(&self, _request: RemoteReadRequest
) -> Self::RemoteReadResult { - not_implemented_in_tests() - } - - fn remote_read_child( - &self, - _request: RemoteReadChildRequest
, - ) -> Self::RemoteReadResult { - not_implemented_in_tests() - } - - fn remote_call(&self, _request: RemoteCallRequest
) -> Self::RemoteCallResult { - futures::future::ready(Ok((*self.lock()).clone())) - } - - fn remote_changes( - &self, - _request: RemoteChangesRequest
, - ) -> Self::RemoteChangesResult { - not_implemented_in_tests() - } - - fn remote_body(&self, _request: RemoteBodyRequest
) -> Self::RemoteBodyResult { - not_implemented_in_tests() - } - } -} diff --git a/client/api/src/proof_provider.rs b/client/api/src/proof_provider.rs index 75f9c55e134d2..6207139f9758b 100644 --- a/client/api/src/proof_provider.rs +++ b/client/api/src/proof_provider.rs @@ -17,10 +17,10 @@ // along with this program. If not, see . //! Proof utilities -use crate::{ChangesProof, CompactProof, StorageProof}; +use crate::{CompactProof, StorageProof}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_state_machine::{KeyValueStates, KeyValueStorageLevel}; -use sp_storage::{ChildInfo, PrefixedStorageKey, StorageKey}; +use sp_storage::ChildInfo; /// Interface for providing block proving utilities. pub trait ProofProvider { @@ -50,27 +50,6 @@ pub trait ProofProvider { method: &str, call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)>; - /// Reads given header and generates CHT-based header proof. - fn header_proof( - &self, - id: &BlockId, - ) -> sp_blockchain::Result<(Block::Header, StorageProof)>; - - /// Get proof for computation of (block, extrinsic) pairs where key has been changed at given - /// blocks range. `min` is the hash of the first block, which changes trie root is known to the - /// requester - when we're using changes tries from ascendants of this block, we should provide - /// proofs for changes tries roots `max` is the hash of the last block known to the requester - - /// we can't use changes tries from descendants of this block. - /// Works only for runtimes that are supporting changes tries. - fn key_changes_proof( - &self, - first: Block::Hash, - last: Block::Hash, - min: Block::Hash, - max: Block::Hash, - storage_key: Option<&PrefixedStorageKey>, - key: &StorageKey, - ) -> sp_blockchain::Result>; /// Given a `BlockId` iterate over all storage values starting at `start_keys`. /// Last `start_keys` element contains last accessed key value. diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 305c4d753c1ea..4c7f6c856ec86 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -41,7 +41,8 @@ use sp_core::traits::SpawnNamed; use sp_inherents::InherentData; use sp_runtime::{ generic::BlockId, - traits::{BlakeTwo256, Block as BlockT, DigestFor, Hash as HashT, Header as HeaderT}, + traits::{BlakeTwo256, Block as BlockT, Hash as HashT, Header as HeaderT}, + Digest, }; use std::{marker::PhantomData, pin::Pin, sync::Arc, time}; @@ -261,7 +262,7 @@ where fn propose( self, inherent_data: InherentData, - inherent_digests: DigestFor, + inherent_digests: Digest, max_duration: time::Duration, block_size_limit: Option, ) -> Self::Proposal { @@ -310,7 +311,7 @@ where async fn propose_with( self, inherent_data: InherentData, - inherent_digests: DigestFor, + inherent_digests: Digest, deadline: time::Instant, block_size_limit: Option, ) -> Result, PR::Proof>, sp_blockchain::Error> @@ -690,13 +691,8 @@ mod tests { api.execute_block(&block_id, proposal.block).unwrap(); let state = backend.state_at(block_id).unwrap(); - let changes_trie_state = - backend::changes_tries_state_at_block(&block_id, backend.changes_trie_storage()) - .unwrap(); - let storage_changes = api - .into_storage_changes(&state, changes_trie_state.as_ref(), genesis_hash) - .unwrap(); + let storage_changes = api.into_storage_changes(&state, genesis_hash).unwrap(); assert_eq!( proposal.storage_changes.transaction_storage_root, diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index e89421edfb168..01afaca0cacf4 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -35,7 +35,8 @@ use sp_blockchain::{ApplyExtrinsicFailed, Error}; use sp_core::ExecutionContext; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, DigestFor, Hash, HashFor, Header as HeaderT, NumberFor, One}, + traits::{Block as BlockT, Hash, HashFor, Header as HeaderT, NumberFor, One}, + Digest, }; pub use sp_block_builder::BlockBuilder as BlockBuilderApi; @@ -119,14 +120,14 @@ where fn new_block_at>( &self, parent: &BlockId, - inherent_digests: DigestFor, + inherent_digests: Digest, record_proof: R, ) -> sp_blockchain::Result>; /// Create a new block, built on the head of the chain. fn new_block( &self, - inherent_digests: DigestFor, + inherent_digests: Digest, ) -> sp_blockchain::Result>; } @@ -159,7 +160,7 @@ where parent_hash: Block::Hash, parent_number: NumberFor, record_proof: RecordProof, - inherent_digests: DigestFor, + inherent_digests: Digest, backend: &'a B, ) -> Result { let header = <::Header as HeaderT>::new( @@ -237,15 +238,11 @@ where let proof = self.api.extract_proof(); let state = self.backend.state_at(self.block_id)?; - let changes_trie_state = backend::changes_tries_state_at_block( - &self.block_id, - self.backend.changes_trie_storage(), - )?; let parent_hash = self.parent_hash; let storage_changes = self .api - .into_storage_changes(&state, changes_trie_state.as_ref(), parent_hash) + .into_storage_changes(&state, parent_hash) .map_err(|e| sp_blockchain::Error::StorageChanges(e))?; Ok(BuiltBlock { diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index a4dbe5012ea19..d2c4ad4498d5e 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -33,7 +33,7 @@ use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_block_builder::BlockBuilder as BlockBuilderApi; use sp_blockchain::{ well_known_cache_keys::{self, Id as CacheKeyId}, - HeaderBackend, ProvideCache, + HeaderBackend, }; use sp_consensus::{CanAuthorWith, Error as ConsensusError}; use sp_consensus_aura::{ @@ -45,7 +45,8 @@ use sp_core::{crypto::Pair, ExecutionContext}; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider as _}; use sp_runtime::{ generic::{BlockId, OpaqueDigestItemId}, - traits::{Block as BlockT, DigestItemFor, Header}, + traits::{Block as BlockT, Header}, + DigestItem, }; use std::{fmt::Debug, hash::Hash, marker::PhantomData, sync::Arc}; @@ -61,9 +62,8 @@ fn check_header( hash: B::Hash, authorities: &[AuthorityId

], check_for_equivocation: CheckForEquivocation, -) -> Result)>, Error> +) -> Result, Error> where - DigestItemFor: CompatibleDigestItem, P::Signature: Codec, C: sc_client_api::backend::AuxStore, P::Public: Encode + Decode + PartialEq + Clone, @@ -189,14 +189,8 @@ where #[async_trait::async_trait] impl Verifier for AuraVerifier where - C: ProvideRuntimeApi - + Send - + Sync - + sc_client_api::backend::AuxStore - + ProvideCache - + BlockOf, + C: ProvideRuntimeApi + Send + Sync + sc_client_api::backend::AuxStore + BlockOf, C::Api: BlockBuilderApi + AuraApi> + ApiExt, - DigestItemFor: CompatibleDigestItem, P: Pair + Send + Sync + 'static, P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + 'static, P::Signature: Encode + Decode, @@ -385,7 +379,6 @@ where C: 'static + ProvideRuntimeApi + BlockOf - + ProvideCache + Send + Sync + AuxStore @@ -395,7 +388,6 @@ where + Send + Sync + 'static, - DigestItemFor: CompatibleDigestItem, P: Pair + Send + Sync + 'static, P::Public: Clone + Eq + Send + Sync + Hash + Debug + Encode + Decode, P::Signature: Encode + Decode, diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 946e0b90c4dd4..16880ae188ad6 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -52,7 +52,7 @@ use sc_consensus_slots::{ use sc_telemetry::TelemetryHandle; use sp_api::ProvideRuntimeApi; use sp_application_crypto::{AppKey, AppPublic}; -use sp_blockchain::{HeaderBackend, ProvideCache, Result as CResult}; +use sp_blockchain::{HeaderBackend, Result as CResult}; use sp_consensus::{ BlockOrigin, CanAuthorWith, Environment, Error as ConsensusError, Proposer, SelectChain, }; @@ -62,7 +62,8 @@ use sp_inherents::CreateInherentDataProviders; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, DigestItemFor, Header, Member, NumberFor, Zero}, + traits::{Block as BlockT, Header, Member, NumberFor, Zero}, + DigestItem, }; mod import_queue; @@ -178,7 +179,7 @@ where P::Public: AppPublic + Hash + Member + Encode + Decode, P::Signature: TryFrom> + Hash + Member + Encode + Decode, B: BlockT, - C: ProvideRuntimeApi + BlockOf + ProvideCache + AuxStore + HeaderBackend + Send + Sync, + C: ProvideRuntimeApi + BlockOf + AuxStore + HeaderBackend + Send + Sync, C::Api: AuraApi>, SC: SelectChain, I: BlockImport> + Send + Sync + 'static, @@ -267,7 +268,7 @@ pub fn build_aura_worker( ) -> impl sc_consensus_slots::SlotWorker>::Proof> where B: BlockT, - C: ProvideRuntimeApi + BlockOf + ProvideCache + AuxStore + HeaderBackend + Send + Sync, + C: ProvideRuntimeApi + BlockOf + AuxStore + HeaderBackend + Send + Sync, C::Api: AuraApi>, PF: Environment + Send + Sync + 'static, PF::Proposer: Proposer>, @@ -316,7 +317,7 @@ impl sc_consensus_slots::SimpleSlotWorker for AuraWorker where B: BlockT, - C: ProvideRuntimeApi + BlockOf + ProvideCache + HeaderBackend + Sync, + C: ProvideRuntimeApi + BlockOf + HeaderBackend + Sync, C::Api: AuraApi>, E: Environment + Send + Sync, E::Proposer: Proposer>, @@ -377,12 +378,8 @@ where }) } - fn pre_digest_data( - &self, - slot: Slot, - _claim: &Self::Claim, - ) -> Vec> { - vec![ as CompatibleDigestItem>::aura_pre_digest(slot)] + fn pre_digest_data(&self, slot: Slot, _claim: &Self::Claim) -> Vec { + vec![>::aura_pre_digest(slot)] } fn block_import_params( @@ -426,7 +423,7 @@ where .map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?; let signature_digest_item = - as CompatibleDigestItem>::aura_seal(signature); + >::aura_seal(signature); let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); import_block.post_digests.push(signature_digest_item); @@ -545,7 +542,7 @@ fn authorities(client: &C, at: &BlockId) -> Result, Consensus where A: Codec + Debug, B: BlockT, - C: ProvideRuntimeApi + BlockOf + ProvideCache, + C: ProvideRuntimeApi + BlockOf, C::Api: AuraApi, { client @@ -574,7 +571,10 @@ mod tests { use sp_consensus_aura::sr25519::AuthorityPair; use sp_inherents::InherentData; use sp_keyring::sr25519::Keyring; - use sp_runtime::traits::{Block as BlockT, DigestFor, Header as _}; + use sp_runtime::{ + traits::{Block as BlockT, Header as _}, + Digest, + }; use sp_timestamp::InherentDataProvider as TimestampInherentDataProvider; use std::{ task::Poll, @@ -611,7 +611,7 @@ mod tests { fn propose( self, _: InherentData, - digests: DigestFor, + digests: Digest, _: Duration, _: Option, ) -> Self::Proposal { @@ -661,29 +661,25 @@ mod tests { _cfg: &ProtocolConfig, _peer_data: &(), ) -> Self::Verifier { - match client { - PeersClient::Full(client, _) => { - let slot_duration = slot_duration(&*client).expect("slot duration available"); - - assert_eq!(slot_duration.slot_duration().as_millis() as u64, SLOT_DURATION); - import_queue::AuraVerifier::new( - client, - Box::new(|_, _| async { - let timestamp = TimestampInherentDataProvider::from_system_time(); - let slot = InherentDataProvider::from_timestamp_and_duration( - *timestamp, - Duration::from_secs(6), - ); - - Ok((timestamp, slot)) - }), - AlwaysCanAuthor, - CheckForEquivocation::Yes, - None, - ) - }, - PeersClient::Light(_, _) => unreachable!("No (yet) tests for light client + Aura"), - } + let client = client.as_client(); + let slot_duration = slot_duration(&*client).expect("slot duration available"); + + assert_eq!(slot_duration.slot_duration().as_millis() as u64, SLOT_DURATION); + import_queue::AuraVerifier::new( + client, + Box::new(|_, _| async { + let timestamp = TimestampInherentDataProvider::from_system_time(); + let slot = InherentDataProvider::from_timestamp_and_duration( + *timestamp, + Duration::from_secs(6), + ); + + Ok((timestamp, slot)) + }), + AlwaysCanAuthor, + CheckForEquivocation::Yes, + None, + ) } fn make_block_import( @@ -724,7 +720,7 @@ mod tests { for (peer_id, key) in peers { let mut net = net.lock(); let peer = net.peer(*peer_id); - let client = peer.client().as_full().expect("full clients are created").clone(); + let client = peer.client().as_client(); let select_chain = peer.select_chain().expect("full client has a select chain"); let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = Arc::new( @@ -823,7 +819,7 @@ mod tests { let mut net = net.lock(); let peer = net.peer(3); - let client = peer.client().as_full().expect("full clients are created").clone(); + let client = peer.client().as_client(); let environ = DummyFactory(client.clone()); let worker = AuraWorker { @@ -875,7 +871,7 @@ mod tests { let mut net = net.lock(); let peer = net.peer(3); - let client = peer.client().as_full().expect("full clients are created").clone(); + let client = peer.client().as_client(); let environ = DummyFactory(client.clone()); let mut worker = AuraWorker { diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 1fde788041155..4fb9f750004c5 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -103,9 +103,7 @@ use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_TRACE} use sp_api::{ApiExt, NumberFor, ProvideRuntimeApi}; use sp_application_crypto::AppKey; use sp_block_builder::BlockBuilder as BlockBuilderApi; -use sp_blockchain::{ - Error as ClientError, HeaderBackend, HeaderMetadata, ProvideCache, Result as ClientResult, -}; +use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult}; use sp_consensus::{ BlockOrigin, CacheKeyId, CanAuthorWith, Environment, Error as ConsensusError, Proposer, SelectChain, SlotData, @@ -117,7 +115,8 @@ use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvid use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::{BlockId, OpaqueDigestItemId}, - traits::{Block as BlockT, DigestItemFor, Header, Zero}, + traits::{Block as BlockT, Header, Zero}, + DigestItem, }; pub use sc_consensus_slots::SlotProportion; @@ -465,7 +464,6 @@ pub fn start_babe( where B: BlockT, C: ProvideRuntimeApi - + ProvideCache + ProvideUncles + BlockchainEvents + HeaderBackend @@ -539,7 +537,6 @@ async fn answer_requests( epoch_changes: SharedEpochChanges, ) where C: ProvideRuntimeApi - + ProvideCache + ProvideUncles + BlockchainEvents + HeaderBackend @@ -677,10 +674,7 @@ impl sc_consensus_slots::SimpleSlotWorker for BabeSlotWorker where B: BlockT, - C: ProvideRuntimeApi - + ProvideCache - + HeaderBackend - + HeaderMetadata, + C: ProvideRuntimeApi + HeaderBackend + HeaderMetadata, C::Api: BabeApi, E: Environment + Sync, E::Proposer: Proposer>, @@ -774,12 +768,8 @@ where }); } - fn pre_digest_data( - &self, - _slot: Slot, - claim: &Self::Claim, - ) -> Vec> { - vec![ as CompatibleDigestItem>::babe_pre_digest(claim.0.clone())] + fn pre_digest_data(&self, _slot: Slot, claim: &Self::Claim) -> Vec { + vec![::babe_pre_digest(claim.0.clone())] } fn block_import_params( @@ -820,8 +810,7 @@ where .clone() .try_into() .map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?; - let digest_item = - as CompatibleDigestItem>::babe_seal(signature.into()); + let digest_item = ::babe_seal(signature.into()); let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); import_block.post_digests.push(digest_item); @@ -921,10 +910,7 @@ pub fn find_pre_digest(header: &B::Header) -> Result( header: &B::Header, -) -> Result, Error> -where - DigestItemFor: CompatibleDigestItem, -{ +) -> Result, Error> { let mut epoch_digest: Option<_> = None; for log in header.digest().logs() { trace!(target: "babe", "Checking log {:?}, looking for epoch change digest.", log); @@ -943,10 +929,7 @@ where /// Extract the BABE config change digest from the given header, if it exists. fn find_next_config_digest( header: &B::Header, -) -> Result, Error> -where - DigestItemFor: CompatibleDigestItem, -{ +) -> Result, Error> { let mut config_digest: Option<_> = None; for log in header.digest().logs() { trace!(target: "babe", "Checking log {:?}, looking for epoch change digest.", log); @@ -1132,8 +1115,7 @@ where + ProvideRuntimeApi + Send + Sync - + AuxStore - + ProvideCache, + + AuxStore, Client::Api: BlockBuilderApi + BabeApi, SelectChain: sp_consensus::SelectChain, CAW: CanAuthorWith + Send + Sync, @@ -1332,7 +1314,6 @@ where + HeaderMetadata + AuxStore + ProvideRuntimeApi - + ProvideCache + Send + Sync, Client::Api: BabeApi + ApiExt, @@ -1399,7 +1380,6 @@ where + HeaderMetadata + AuxStore + ProvideRuntimeApi - + ProvideCache + Send + Sync, Client::Api: BabeApi + ApiExt, @@ -1756,7 +1736,6 @@ where + Sync + 'static, Client: ProvideRuntimeApi - + ProvideCache + HeaderBackend + HeaderMetadata + AuxStore diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index c033f4535be0b..73cc453812eae 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -43,13 +43,13 @@ use sp_consensus_babe::{ use sp_core::crypto::Pair; use sp_keystore::{vrf::make_transcript as transcript_from_data, SyncCryptoStore}; use sp_runtime::{ - generic::DigestItem, - traits::{Block as BlockT, DigestFor}, + generic::{Digest, DigestItem}, + traits::Block as BlockT, }; use sp_timestamp::InherentDataProvider as TimestampInherentDataProvider; use std::{cell::RefCell, task::Poll, time::Duration}; -type Item = DigestItem; +type Item = DigestItem; type Error = sp_blockchain::Error; @@ -108,7 +108,7 @@ impl Environment for DummyFactory { impl DummyProposer { fn propose_with( &mut self, - pre_digests: DigestFor, + pre_digests: Digest, ) -> future::Ready< Result< Proposal< @@ -181,7 +181,7 @@ impl Proposer for DummyProposer { fn propose( mut self, _: InherentData, - pre_digests: DigestFor, + pre_digests: Digest, _: Duration, _: Option, ) -> Self::Proposal { @@ -295,7 +295,7 @@ impl TestNetFactory for BabeTestNet { Option>, Option, ) { - let client = client.as_full().expect("only full clients are tested"); + let client = client.as_client(); let config = Config::get_or_compute(&*client).expect("config available"); let (block_import, link) = crate::block_import(config, client.clone(), client.clone()) @@ -320,7 +320,7 @@ impl TestNetFactory for BabeTestNet { ) -> Self::Verifier { use substrate_test_runtime_client::DefaultTestClientBuilderExt; - let client = client.as_full().expect("only full clients are used in test"); + let client = client.as_client(); trace!(target: "babe", "Creating a verifier"); // ensure block import and verifier are linked correctly. @@ -395,7 +395,7 @@ fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static for (peer_id, seed) in peers { let mut net = net.lock(); let peer = net.peer(*peer_id); - let client = peer.client().as_full().expect("Only full clients are used in tests").clone(); + let client = peer.client().as_client(); let select_chain = peer.select_chain().expect("Full client has select_chain"); let keystore_path = tempfile::tempdir().expect("Creates keystore path"); @@ -679,7 +679,7 @@ fn importing_block_one_sets_genesis_epoch() { let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); - let client = peer.client().as_full().expect("Only full clients are used in tests").clone(); + let client = peer.client().as_client(); let mut proposer_factory = DummyFactory { client: client.clone(), @@ -721,7 +721,7 @@ fn importing_epoch_change_block_prunes_tree() { let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); - let client = peer.client().as_full().expect("Only full clients are used in tests").clone(); + let client = peer.client().as_client(); let mut block_import = data.block_import.lock().take().expect("import set up during init"); let epoch_changes = data.link.epoch_changes.clone(); @@ -836,7 +836,7 @@ fn verify_slots_are_strictly_increasing() { let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); - let client = peer.client().as_full().expect("Only full clients are used in tests").clone(); + let client = peer.client().as_client(); let mut block_import = data.block_import.lock().take().expect("import set up during init"); let mut proposer_factory = DummyFactory { diff --git a/client/consensus/babe/src/verification.rs b/client/consensus/babe/src/verification.rs index af118312dd07c..174b2d03c6ef0 100644 --- a/client/consensus/babe/src/verification.rs +++ b/client/consensus/babe/src/verification.rs @@ -32,7 +32,7 @@ use sp_consensus_babe::{ }; use sp_consensus_slots::Slot; use sp_core::{Pair, Public}; -use sp_runtime::traits::{DigestItemFor, Header}; +use sp_runtime::{traits::Header, DigestItem}; /// BABE verification parameters pub(super) struct VerificationParams<'a, B: 'a + BlockT> { @@ -61,10 +61,7 @@ pub(super) struct VerificationParams<'a, B: 'a + BlockT> { /// with each having different validation logic. pub(super) fn check_header( params: VerificationParams, -) -> Result>, Error> -where - DigestItemFor: CompatibleDigestItem, -{ +) -> Result, Error> { let VerificationParams { mut header, pre_digest, slot_now, epoch } = params; let authorities = &epoch.authorities; @@ -137,9 +134,9 @@ where Ok(CheckedHeader::Checked(header, info)) } -pub(super) struct VerifiedHeaderInfo { - pub(super) pre_digest: DigestItemFor, - pub(super) seal: DigestItemFor, +pub(super) struct VerifiedHeaderInfo { + pub(super) pre_digest: DigestItem, + pub(super) seal: DigestItem, pub(super) author: AuthorityId, } diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index 5294db2396042..03fde159736ca 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -20,8 +20,8 @@ use serde::{Deserialize, Serialize}; use sp_runtime::{ - traits::{Block as BlockT, DigestItemFor, HashFor, Header as HeaderT, NumberFor}, - Justification, Justifications, + traits::{Block as BlockT, HashFor, Header as HeaderT, NumberFor}, + DigestItem, Justification, Justifications, }; use std::{any::Any, borrow::Cow, collections::HashMap, sync::Arc}; @@ -122,7 +122,7 @@ pub struct BlockCheckParams { /// Precomputed storage. pub enum StorageChanges { /// Changes coming from block execution. - Changes(sp_state_machine::StorageChanges, NumberFor>), + Changes(sp_state_machine::StorageChanges>), /// Whole new state. Import(ImportedState), } @@ -175,7 +175,7 @@ pub struct BlockImportParams { pub justifications: Option, /// Digest items that have been added after the runtime for external /// work, like a consensus signature. - pub post_digests: Vec>, + pub post_digests: Vec, /// The body of the block. pub body: Option>, /// Indexed transaction body of the block. diff --git a/client/consensus/manual-seal/src/consensus.rs b/client/consensus/manual-seal/src/consensus.rs index 33a4c8616f6d2..4284d40179d2f 100644 --- a/client/consensus/manual-seal/src/consensus.rs +++ b/client/consensus/manual-seal/src/consensus.rs @@ -21,7 +21,7 @@ use super::Error; use sc_consensus::BlockImportParams; use sp_inherents::InherentData; -use sp_runtime::traits::{Block as BlockT, DigestFor}; +use sp_runtime::{traits::Block as BlockT, Digest}; pub mod babe; @@ -32,11 +32,7 @@ pub trait ConsensusDataProvider: Send + Sync { type Transaction; /// Attempt to create a consensus digest. - fn create_digest( - &self, - parent: &B::Header, - inherents: &InherentData, - ) -> Result, Error>; + fn create_digest(&self, parent: &B::Header, inherents: &InherentData) -> Result; /// set up the neccessary import params. fn append_block_import( diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 1d3afe392d62f..e06c544aaedc3 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -49,7 +49,8 @@ use sp_consensus_slots::Slot; use sp_inherents::{InherentData, InherentDataProvider, InherentIdentifier}; use sp_runtime::{ generic::{BlockId, Digest}, - traits::{Block as BlockT, DigestFor, DigestItemFor, Header, Zero}, + traits::{Block as BlockT, Header, Zero}, + DigestItem, }; use sp_timestamp::{InherentType, TimestampInherentData, INHERENT_IDENTIFIER}; @@ -193,11 +194,7 @@ where { type Transaction = TransactionFor; - fn create_digest( - &self, - parent: &B::Header, - inherents: &InherentData, - ) -> Result, Error> { + fn create_digest(&self, parent: &B::Header, inherents: &InherentData) -> Result { let slot = inherents .babe_inherent_data()? .ok_or_else(|| Error::StringError("No babe inherent data".into()))?; @@ -207,7 +204,7 @@ where let logs = if let Some((predigest, _)) = authorship::claim_slot(slot, &epoch, &self.keystore) { - vec![ as CompatibleDigestItem>::babe_pre_digest(predigest)] + vec![::babe_pre_digest(predigest)] } else { // well we couldn't claim a slot because this is an existing chain and we're not in the // authorities. we need to tell BabeBlockImport that the epoch has changed, and we put @@ -244,13 +241,13 @@ where }); vec![ - DigestItemFor::::PreRuntime(BABE_ENGINE_ID, predigest.encode()), - DigestItemFor::::Consensus(BABE_ENGINE_ID, next_epoch.encode()), + DigestItem::PreRuntime(BABE_ENGINE_ID, predigest.encode()), + DigestItem::Consensus(BABE_ENGINE_ID, next_epoch.encode()), ] }, ViableEpochDescriptor::UnimportedGenesis(_) => { // since this is the genesis, secondary predigest works for now. - vec![DigestItemFor::::PreRuntime(BABE_ENGINE_ID, predigest.encode())] + vec![DigestItem::PreRuntime(BABE_ENGINE_ID, predigest.encode())] }, } }; diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 7b1012888e869..3ab0b977255ee 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -55,7 +55,7 @@ use sc_consensus::{ }; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder as BlockBuilderApi; -use sp_blockchain::{well_known_cache_keys::Id as CacheKeyId, HeaderBackend, ProvideCache}; +use sp_blockchain::{well_known_cache_keys::Id as CacheKeyId, HeaderBackend}; use sp_consensus::{ CanAuthorWith, Environment, Error as ConsensusError, Proposer, SelectChain, SyncOracle, }; @@ -240,7 +240,7 @@ where B: BlockT, I: BlockImport> + Send + Sync, I::Error: Into, - C: ProvideRuntimeApi + Send + Sync + HeaderBackend + AuxStore + ProvideCache + BlockOf, + C: ProvideRuntimeApi + Send + Sync + HeaderBackend + AuxStore + BlockOf, C::Api: BlockBuilderApi, Algorithm: PowAlgorithm, CAW: CanAuthorWith, @@ -319,7 +319,7 @@ where I: BlockImport> + Send + Sync, I::Error: Into, S: SelectChain, - C: ProvideRuntimeApi + Send + Sync + HeaderBackend + AuxStore + ProvideCache + BlockOf, + C: ProvideRuntimeApi + Send + Sync + HeaderBackend + AuxStore + BlockOf, C::Api: BlockBuilderApi, Algorithm: PowAlgorithm + Send + Sync, Algorithm::Difficulty: 'static + Send, @@ -425,10 +425,7 @@ impl PowVerifier { Self { algorithm, _marker: PhantomData } } - fn check_header( - &self, - mut header: B::Header, - ) -> Result<(B::Header, DigestItem), Error> + fn check_header(&self, mut header: B::Header) -> Result<(B::Header, DigestItem), Error> where Algorithm: PowAlgorithm, { @@ -630,7 +627,7 @@ where }, }; - let mut inherent_digest = Digest::::default(); + let mut inherent_digest = Digest::default(); if let Some(pre_runtime) = &pre_runtime { inherent_digest.push(DigestItem::PreRuntime(POW_ENGINE_ID, pre_runtime.to_vec())); } @@ -702,10 +699,7 @@ fn find_pre_digest(header: &B::Header) -> Result>, Err } /// Fetch PoW seal. -fn fetch_seal( - digest: Option<&DigestItem>, - hash: B::Hash, -) -> Result, Error> { +fn fetch_seal(digest: Option<&DigestItem>, hash: B::Hash) -> Result, Error> { match digest { Some(DigestItem::Seal(id, seal)) => if id == &POW_ENGINE_ID { diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index bfaa388014ef0..ead209ef86a65 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -45,7 +45,7 @@ use sp_consensus_slots::Slot; use sp_inherents::CreateInherentDataProviders; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, HashFor, Header as HeaderT, NumberFor}, + traits::{Block as BlockT, HashFor, Header as HeaderT}, }; use sp_timestamp::Timestamp; use std::{fmt::Debug, ops::Deref, time::Duration}; @@ -54,7 +54,7 @@ use std::{fmt::Debug, ops::Deref, time::Duration}; /// /// See [`sp_state_machine::StorageChanges`] for more information. pub type StorageChanges = - sp_state_machine::StorageChanges, NumberFor>; + sp_state_machine::StorageChanges>; /// The result of [`SlotWorker::on_slot`]. #[derive(Debug, Clone)] @@ -141,11 +141,7 @@ pub trait SimpleSlotWorker { fn notify_slot(&self, _header: &B::Header, _slot: Slot, _epoch_data: &Self::EpochData) {} /// Return the pre digest data to include in a block authored with the given claim. - fn pre_digest_data( - &self, - slot: Slot, - claim: &Self::Claim, - ) -> Vec>; + fn pre_digest_data(&self, slot: Slot, claim: &Self::Claim) -> Vec; /// Returns a function which produces a `BlockImportParams`. fn block_import_params( diff --git a/client/db/src/cache/list_cache.rs b/client/db/src/cache/list_cache.rs deleted file mode 100644 index 795cb8f901183..0000000000000 --- a/client/db/src/cache/list_cache.rs +++ /dev/null @@ -1,2351 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! List-based cache. -//! -//! Maintains several lists, containing nodes that are inserted whenever -//! cached value at new block differs from the value at previous block. -//! Example: -//! B1(a) <--- B2(b) <--- B3(b) <--- B4(c) -//! N1(b) <-------------- N2(c) -//! -//! There's single list for all finalized blocks and >= 0 lists for unfinalized -//! blocks. -//! When new non-final block is inserted (with value that differs from the value -//! at parent), it starts new unfinalized fork. -//! When new final block is inserted (with value that differs from the value at -//! parent), new entry is appended to the finalized fork. -//! When existing non-final block is finalized (with value that differs from the -//! value at parent), new entry is appended to the finalized fork AND unfinalized -//! fork is dropped. -//! -//! Entries from abandoned unfinalized forks (forks that are forking from block B -//! which is ascendant of the best finalized block) are deleted when block F with -//! number B.number (i.e. 'parallel' canon block) is finalized. -//! -//! Finalized entry E1 is pruned when block B is finalized so that: -//! EntryAt(B.number - prune_depth).points_to(E1) - -use std::collections::{BTreeMap, BTreeSet}; - -use log::warn; - -use sp_blockchain::{Error as ClientError, Result as ClientResult}; -use sp_runtime::traits::{Block as BlockT, Bounded, CheckedSub, NumberFor, Zero}; - -use crate::cache::{ - list_entry::{Entry, StorageEntry}, - list_storage::{Metadata, Storage, StorageTransaction}, - CacheItemT, ComplexBlockId, EntryType, -}; - -/// Pruning strategy. -#[derive(Debug, Clone, Copy)] -pub enum PruningStrategy { - /// Prune entries when they're too far behind best finalized block. - ByDepth(N), - /// Do not prune old entries at all. - NeverPrune, -} - -/// List-based cache. -pub struct ListCache> { - /// Cache storage. - storage: S, - /// Pruning strategy. - pruning_strategy: PruningStrategy>, - /// Best finalized block. - best_finalized_block: ComplexBlockId, - /// Best finalized entry (if exists). - best_finalized_entry: Option>, - /// All unfinalized 'forks'. - unfinalized: Vec>, -} - -/// All possible list cache operations that could be performed after transaction is committed. -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq))] -pub enum CommitOperation { - /// New block is appended to the fork without changing the cached value. - AppendNewBlock(usize, ComplexBlockId), - /// New block is appended to the fork with the different value. - AppendNewEntry(usize, Entry), - /// New fork is added with the given head entry. - AddNewFork(Entry), - /// New block is finalized and possibly: - /// - new entry is finalized AND/OR - /// - some forks are destroyed - BlockFinalized(ComplexBlockId, Option>, BTreeSet), - /// When best block is reverted - contains the forks that have to be updated - /// (they're either destroyed, or their best entry is updated to earlier block). - BlockReverted(BTreeMap>>), -} - -/// A set of commit operations. -#[derive(Debug)] -pub struct CommitOperations { - operations: Vec>, -} - -/// Single fork of list-based cache. -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq))] -pub struct Fork { - /// The best block of this fork. We do not save this field in the database to avoid - /// extra updates => it could be None after restart. It will be either filled when - /// the block is appended to this fork, or the whole fork will be abandoned when the - /// block from the other fork is finalized - best_block: Option>, - /// The head entry of this fork. - head: Entry, -} - -/// Outcome of Fork::try_append_or_fork. -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq))] -pub enum ForkAppendResult { - /// New entry should be appended to the end of the fork. - Append, - /// New entry should be forked from the fork, starting with entry at given block. - Fork(ComplexBlockId), -} - -impl> ListCache { - /// Create new db list cache entry. - pub fn new( - storage: S, - pruning_strategy: PruningStrategy>, - best_finalized_block: ComplexBlockId, - ) -> ClientResult { - let (best_finalized_entry, unfinalized) = - storage.read_meta().and_then(|meta| read_forks(&storage, meta))?; - - Ok(ListCache { - storage, - pruning_strategy, - best_finalized_block, - best_finalized_entry, - unfinalized, - }) - } - - /// Get reference to the storage. - pub fn storage(&self) -> &S { - &self.storage - } - - /// Get unfinalized forks reference. - #[cfg(test)] - pub fn unfinalized(&self) -> &[Fork] { - &self.unfinalized - } - - /// Get value valid at block. - pub fn value_at_block( - &self, - at: &ComplexBlockId, - ) -> ClientResult, Option>, T)>> { - let head = if at.number <= self.best_finalized_block.number { - // if the block is older than the best known finalized block - // => we're should search for the finalized value - - // BUT since we're not guaranteeing to provide correct values for forks - // behind the finalized block, check if the block is finalized first - if !chain::is_finalized_block(&self.storage, &at, Bounded::max_value())? { - return Err(ClientError::NotInFinalizedChain) - } - - self.best_finalized_entry.as_ref() - } else if self.unfinalized.is_empty() { - // there are no unfinalized entries - // => we should search for the finalized value - self.best_finalized_entry.as_ref() - } else { - // there are unfinalized entries - // => find the fork containing given block and read from this fork - // IF there's no matching fork, ensure that this isn't a block from a fork that has - // forked behind the best finalized block and search at finalized fork - - match self.find_unfinalized_fork(&at)? { - Some(fork) => Some(&fork.head), - None => match self.best_finalized_entry.as_ref() { - Some(best_finalized_entry) - if chain::is_connected_to_block( - &self.storage, - &at, - &best_finalized_entry.valid_from, - )? => - Some(best_finalized_entry), - _ => None, - }, - } - }; - - match head { - Some(head) => head - .search_best_before(&self.storage, at.number) - .map(|e| e.map(|e| (e.0.valid_from, e.1, e.0.value))), - None => Ok(None), - } - } - - /// When new block is inserted into database. - /// - /// None passed as value means that the value has not changed since previous block. - pub fn on_block_insert>( - &self, - tx: &mut Tx, - parent: ComplexBlockId, - block: ComplexBlockId, - value: Option, - entry_type: EntryType, - operations: &mut CommitOperations, - ) -> ClientResult<()> { - Ok(operations - .append(self.do_on_block_insert(tx, parent, block, value, entry_type, operations)?)) - } - - /// When previously inserted block is finalized. - pub fn on_block_finalize>( - &self, - tx: &mut Tx, - parent: ComplexBlockId, - block: ComplexBlockId, - operations: &mut CommitOperations, - ) -> ClientResult<()> { - Ok(operations.append(self.do_on_block_finalize(tx, parent, block, operations)?)) - } - - /// When block is reverted. - pub fn on_block_revert>( - &self, - tx: &mut Tx, - reverted_block: &ComplexBlockId, - operations: &mut CommitOperations, - ) -> ClientResult<()> { - Ok(operations.append(Some(self.do_on_block_revert(tx, reverted_block)?))) - } - - /// When transaction is committed. - pub fn on_transaction_commit(&mut self, ops: CommitOperations) { - for op in ops.operations { - match op { - CommitOperation::AppendNewBlock(index, best_block) => { - let mut fork = self.unfinalized.get_mut(index).expect( - "ListCache is a crate-private type; - internal clients of ListCache are committing transaction while cache is locked; - CommitOperation holds valid references while cache is locked; qed", - ); - fork.best_block = Some(best_block); - }, - CommitOperation::AppendNewEntry(index, entry) => { - let mut fork = self.unfinalized.get_mut(index).expect( - "ListCache is a crate-private type; - internal clients of ListCache are committing transaction while cache is locked; - CommitOperation holds valid references while cache is locked; qed", - ); - fork.best_block = Some(entry.valid_from.clone()); - fork.head = entry; - }, - CommitOperation::AddNewFork(entry) => { - self.unfinalized - .push(Fork { best_block: Some(entry.valid_from.clone()), head: entry }); - }, - CommitOperation::BlockFinalized(block, finalizing_entry, forks) => { - self.best_finalized_block = block; - if let Some(finalizing_entry) = finalizing_entry { - self.best_finalized_entry = Some(finalizing_entry); - } - for fork_index in forks.iter().rev() { - self.unfinalized.remove(*fork_index); - } - }, - CommitOperation::BlockReverted(forks) => { - for (fork_index, updated_fork) in forks.into_iter().rev() { - match updated_fork { - Some(updated_fork) => self.unfinalized[fork_index] = updated_fork, - None => { - self.unfinalized.remove(fork_index); - }, - } - } - }, - } - } - } - - fn do_on_block_insert>( - &self, - tx: &mut Tx, - parent: ComplexBlockId, - block: ComplexBlockId, - value: Option, - entry_type: EntryType, - operations: &CommitOperations, - ) -> ClientResult>> { - // this guarantee is currently provided by LightStorage && we're relying on it here - let prev_operation = operations.operations.last(); - debug_assert!( - entry_type != EntryType::Final || - self.unfinalized.is_empty() || - self.best_finalized_block.hash == parent.hash || - match prev_operation { - Some(&CommitOperation::BlockFinalized(ref best_finalized_block, _, _)) => - best_finalized_block.hash == parent.hash, - _ => false, - } - ); - - // we do not store any values behind finalized - if block.number != Zero::zero() && self.best_finalized_block.number >= block.number { - return Ok(None) - } - - // if the block is not final, it is possibly appended to/forking from existing unfinalized - // fork - let is_final = entry_type == EntryType::Final || entry_type == EntryType::Genesis; - if !is_final { - let mut fork_and_action = None; - - // when value hasn't changed and block isn't final, there's nothing we need to do - if value.is_none() { - return Ok(None) - } - - // first: try to find fork that is known to has the best block we're appending to - for (index, fork) in self.unfinalized.iter().enumerate() { - if fork.try_append(&parent) { - fork_and_action = Some((index, ForkAppendResult::Append)); - break - } - } - - // if not found, check cases: - // - we're appending to the fork for the first time after restart; - // - we're forking existing unfinalized fork from the middle; - if fork_and_action.is_none() { - let best_finalized_entry_block = - self.best_finalized_entry.as_ref().map(|f| f.valid_from.number); - for (index, fork) in self.unfinalized.iter().enumerate() { - if let Some(action) = - fork.try_append_or_fork(&self.storage, &parent, best_finalized_entry_block)? - { - fork_and_action = Some((index, action)); - break - } - } - } - - // if we have found matching unfinalized fork => early exit - match fork_and_action { - // append to unfinalized fork - Some((index, ForkAppendResult::Append)) => { - let new_storage_entry = match self.unfinalized[index].head.try_update(value) { - Some(new_storage_entry) => new_storage_entry, - None => return Ok(Some(CommitOperation::AppendNewBlock(index, block))), - }; - - tx.insert_storage_entry(&block, &new_storage_entry); - let operation = - CommitOperation::AppendNewEntry(index, new_storage_entry.into_entry(block)); - tx.update_meta( - self.best_finalized_entry.as_ref(), - &self.unfinalized, - &operation, - ); - return Ok(Some(operation)) - }, - // fork from the middle of unfinalized fork - Some((_, ForkAppendResult::Fork(prev_valid_from))) => { - // it is possible that we're inserting extra (but still required) fork here - let new_storage_entry = StorageEntry { - prev_valid_from: Some(prev_valid_from), - value: value.expect("checked above that !value.is_none(); qed"), - }; - - tx.insert_storage_entry(&block, &new_storage_entry); - let operation = - CommitOperation::AddNewFork(new_storage_entry.into_entry(block)); - tx.update_meta( - self.best_finalized_entry.as_ref(), - &self.unfinalized, - &operation, - ); - return Ok(Some(operation)) - }, - None => (), - } - } - - // if we're here, then one of following is true: - // - either we're inserting final block => all ancestors are already finalized AND the only - // thing we can do is to try to update last finalized entry - // - either we're inserting non-final blocks that has no ancestors in any known unfinalized - // forks - - let new_storage_entry = match self.best_finalized_entry.as_ref() { - Some(best_finalized_entry) => best_finalized_entry.try_update(value), - None if value.is_some() => Some(StorageEntry { - prev_valid_from: None, - value: value.expect("value.is_some(); qed"), - }), - None => None, - }; - - if !is_final { - return Ok(match new_storage_entry { - Some(new_storage_entry) => { - tx.insert_storage_entry(&block, &new_storage_entry); - let operation = - CommitOperation::AddNewFork(new_storage_entry.into_entry(block)); - tx.update_meta( - self.best_finalized_entry.as_ref(), - &self.unfinalized, - &operation, - ); - Some(operation) - }, - None => None, - }) - } - - // cleanup database from abandoned unfinalized forks and obsolete finalized entries - let abandoned_forks = self.destroy_abandoned_forks(tx, &block, prev_operation); - self.prune_finalized_entries(tx, &block); - - match new_storage_entry { - Some(new_storage_entry) => { - tx.insert_storage_entry(&block, &new_storage_entry); - let operation = CommitOperation::BlockFinalized( - block.clone(), - Some(new_storage_entry.into_entry(block)), - abandoned_forks, - ); - tx.update_meta(self.best_finalized_entry.as_ref(), &self.unfinalized, &operation); - Ok(Some(operation)) - }, - None => Ok(Some(CommitOperation::BlockFinalized(block, None, abandoned_forks))), - } - } - - fn do_on_block_finalize>( - &self, - tx: &mut Tx, - parent: ComplexBlockId, - block: ComplexBlockId, - operations: &CommitOperations, - ) -> ClientResult>> { - // this guarantee is currently provided by db backend && we're relying on it here - let prev_operation = operations.operations.last(); - debug_assert!( - self.best_finalized_block.hash == parent.hash || - match prev_operation { - Some(&CommitOperation::BlockFinalized(ref best_finalized_block, _, _)) => - best_finalized_block.hash == parent.hash, - _ => false, - } - ); - - // there could be at most one entry that is finalizing - let finalizing_entry = - self.storage.read_entry(&block)?.map(|entry| entry.into_entry(block.clone())); - - // cleanup database from abandoned unfinalized forks and obsolete finalized entries - let abandoned_forks = self.destroy_abandoned_forks(tx, &block, prev_operation); - self.prune_finalized_entries(tx, &block); - - let operation = CommitOperation::BlockFinalized(block, finalizing_entry, abandoned_forks); - tx.update_meta(self.best_finalized_entry.as_ref(), &self.unfinalized, &operation); - - Ok(Some(operation)) - } - - fn do_on_block_revert>( - &self, - tx: &mut Tx, - reverted_block: &ComplexBlockId, - ) -> ClientResult> { - // can't revert finalized blocks - debug_assert!(self.best_finalized_block.number < reverted_block.number); - - // iterate all unfinalized forks and truncate/destroy if required - let mut updated = BTreeMap::new(); - for (index, fork) in self.unfinalized.iter().enumerate() { - // we only need to truncate fork if its head is ancestor of truncated block - if fork.head.valid_from.number < reverted_block.number { - continue - } - - // we only need to truncate fork if its head is connected to truncated block - if !chain::is_connected_to_block(&self.storage, reverted_block, &fork.head.valid_from)? - { - continue - } - - let updated_fork = fork.truncate( - &self.storage, - tx, - reverted_block.number, - self.best_finalized_block.number, - )?; - updated.insert(index, updated_fork); - } - - // schedule commit operation and update meta - let operation = CommitOperation::BlockReverted(updated); - tx.update_meta(self.best_finalized_entry.as_ref(), &self.unfinalized, &operation); - - Ok(operation) - } - - /// Prune old finalized entries. - fn prune_finalized_entries>( - &self, - tx: &mut Tx, - block: &ComplexBlockId, - ) { - let prune_depth = match self.pruning_strategy { - PruningStrategy::ByDepth(prune_depth) => prune_depth, - PruningStrategy::NeverPrune => return, - }; - - let mut do_pruning = || -> ClientResult<()> { - // calculate last ancient block number - let ancient_block = match block.number.checked_sub(&prune_depth) { - Some(number) => match self.storage.read_id(number)? { - Some(hash) => ComplexBlockId::new(hash, number), - None => return Ok(()), - }, - None => return Ok(()), - }; - - // if there's an entry at this block: - // - remove reference from this entry to the previous entry - // - destroy fork starting with previous entry - let current_entry = match self.storage.read_entry(&ancient_block)? { - Some(current_entry) => current_entry, - None => return Ok(()), - }; - let first_entry_to_truncate = match current_entry.prev_valid_from { - Some(prev_valid_from) => prev_valid_from, - None => return Ok(()), - }; - - // truncate ancient entry - tx.insert_storage_entry( - &ancient_block, - &StorageEntry { prev_valid_from: None, value: current_entry.value }, - ); - - // destroy 'fork' ending with previous entry - destroy_fork(first_entry_to_truncate, &self.storage, tx, None) - }; - - if let Err(error) = do_pruning() { - warn!(target: "db", "Failed to prune ancient cache entries: {}", error); - } - } - - /// Try to destroy abandoned forks (forked before best finalized block) when block is finalized. - fn destroy_abandoned_forks>( - &self, - tx: &mut Tx, - block: &ComplexBlockId, - prev_operation: Option<&CommitOperation>, - ) -> BTreeSet { - // if some block has been finalized already => take it into account - let prev_abandoned_forks = match prev_operation { - Some(&CommitOperation::BlockFinalized(_, _, ref abandoned_forks)) => - Some(abandoned_forks), - _ => None, - }; - - let mut destroyed = prev_abandoned_forks.cloned().unwrap_or_else(|| BTreeSet::new()); - let live_unfinalized = self.unfinalized.iter().enumerate().filter(|(idx, _)| { - prev_abandoned_forks - .map(|prev_abandoned_forks| !prev_abandoned_forks.contains(idx)) - .unwrap_or(true) - }); - for (index, fork) in live_unfinalized { - if fork.head.valid_from.number == block.number { - destroyed.insert(index); - if fork.head.valid_from.hash != block.hash { - if let Err(error) = fork.destroy(&self.storage, tx, Some(block.number)) { - warn!(target: "db", "Failed to destroy abandoned unfinalized cache fork: {}", error); - } - } - } - } - - destroyed - } - - /// Search unfinalized fork where given block belongs. - fn find_unfinalized_fork( - &self, - block: &ComplexBlockId, - ) -> ClientResult>> { - for unfinalized in &self.unfinalized { - if unfinalized.matches(&self.storage, block)? { - return Ok(Some(&unfinalized)) - } - } - - Ok(None) - } -} - -impl Fork { - /// Get reference to the head entry of this fork. - pub fn head(&self) -> &Entry { - &self.head - } - - /// Check if the block is the part of the fork. - pub fn matches>( - &self, - storage: &S, - block: &ComplexBlockId, - ) -> ClientResult { - let range = self.head.search_best_range_before(storage, block.number)?; - match range { - None => Ok(false), - Some((begin, end)) => - chain::is_connected_to_range(storage, block, (&begin, end.as_ref())), - } - } - - /// Try to append NEW block to the fork. This method will only 'work' (return true) when block - /// is actually appended to the fork AND the best known block of the fork is known (i.e. some - /// block has been already appended to this fork after last restart). - pub fn try_append(&self, parent: &ComplexBlockId) -> bool { - // when the best block of the fork is known, the check is trivial - // - // most of calls will hopefully end here, because best_block is only unknown - // after restart and until new block is appended to the fork - self.best_block.as_ref() == Some(parent) - } - - /// Try to append new block to the fork OR fork it. - pub fn try_append_or_fork>( - &self, - storage: &S, - parent: &ComplexBlockId, - best_finalized_entry_block: Option>, - ) -> ClientResult>> { - // try to find entries that are (possibly) surrounding the parent block - let range = self.head.search_best_range_before(storage, parent.number)?; - let begin = match range { - Some((begin, _)) => begin, - None => return Ok(None), - }; - - // check if the parent is connected to the beginning of the range - if !chain::is_connected_to_block(storage, parent, &begin)? { - return Ok(None) - } - - // the block is connected to the begin-entry. If begin is the head entry - // => we need to append new block to the fork - if begin == self.head.valid_from { - return Ok(Some(ForkAppendResult::Append)) - } - - // the parent block belongs to this fork AND it is located after last finalized entry - // => we need to make a new fork - if best_finalized_entry_block.map(|f| begin.number > f).unwrap_or(true) { - return Ok(Some(ForkAppendResult::Fork(begin))) - } - - Ok(None) - } - - /// Destroy fork by deleting all unfinalized entries. - pub fn destroy, Tx: StorageTransaction>( - &self, - storage: &S, - tx: &mut Tx, - best_finalized_block: Option>, - ) -> ClientResult<()> { - destroy_fork(self.head.valid_from.clone(), storage, tx, best_finalized_block) - } - - /// Truncate fork by deleting all entries that are descendants of given block. - pub fn truncate, Tx: StorageTransaction>( - &self, - storage: &S, - tx: &mut Tx, - reverting_block: NumberFor, - best_finalized_block: NumberFor, - ) -> ClientResult>> { - let mut current = self.head.valid_from.clone(); - loop { - // read pointer to previous entry - let entry = storage.require_entry(¤t)?; - - // truncation stops when we have reached the ancestor of truncated block - if current.number < reverting_block { - // if we have reached finalized block => destroy fork - if chain::is_finalized_block(storage, ¤t, best_finalized_block)? { - return Ok(None) - } - - // else fork needs to be updated - return Ok(Some(Fork { best_block: None, head: entry.into_entry(current) })) - } - - tx.remove_storage_entry(¤t); - - // truncation also stops when there are no more entries in the list - current = match entry.prev_valid_from { - Some(prev_valid_from) => prev_valid_from, - None => return Ok(None), - }; - } - } -} - -impl Default for CommitOperations { - fn default() -> Self { - CommitOperations { operations: Vec::new() } - } -} - -// This should never be allowed for non-test code to avoid revealing its internals. -#[cfg(test)] -impl From>> - for CommitOperations -{ - fn from(operations: Vec>) -> Self { - CommitOperations { operations } - } -} - -impl CommitOperations { - /// Append operation to the set. - fn append(&mut self, new_operation: Option>) { - let new_operation = match new_operation { - Some(new_operation) => new_operation, - None => return, - }; - - let last_operation = match self.operations.pop() { - Some(last_operation) => last_operation, - None => { - self.operations.push(new_operation); - return - }, - }; - - // we are able (and obliged to) to merge two consequent block finalization operations - match last_operation { - CommitOperation::BlockFinalized( - old_finalized_block, - old_finalized_entry, - old_abandoned_forks, - ) => match new_operation { - CommitOperation::BlockFinalized( - new_finalized_block, - new_finalized_entry, - new_abandoned_forks, - ) => { - self.operations.push(CommitOperation::BlockFinalized( - new_finalized_block, - new_finalized_entry, - new_abandoned_forks, - )); - }, - _ => { - self.operations.push(CommitOperation::BlockFinalized( - old_finalized_block, - old_finalized_entry, - old_abandoned_forks, - )); - self.operations.push(new_operation); - }, - }, - _ => { - self.operations.push(last_operation); - self.operations.push(new_operation); - }, - } - } -} - -/// Destroy fork by deleting all unfinalized entries. -pub fn destroy_fork< - Block: BlockT, - T: CacheItemT, - S: Storage, - Tx: StorageTransaction, ->( - head_valid_from: ComplexBlockId, - storage: &S, - tx: &mut Tx, - best_finalized_block: Option>, -) -> ClientResult<()> { - let mut current = head_valid_from; - loop { - // optionally: deletion stops when we found entry at finalized block - if let Some(best_finalized_block) = best_finalized_block { - if chain::is_finalized_block(storage, ¤t, best_finalized_block)? { - return Ok(()) - } - } - - // read pointer to previous entry - let entry = storage.require_entry(¤t)?; - tx.remove_storage_entry(¤t); - - // deletion stops when there are no more entries in the list - current = match entry.prev_valid_from { - Some(prev_valid_from) => prev_valid_from, - None => return Ok(()), - }; - } -} - -/// Blockchain related functions. -mod chain { - use super::*; - use sp_runtime::traits::Header as HeaderT; - - /// Is the block1 connected both ends of the range. - pub fn is_connected_to_range>( - storage: &S, - block: &ComplexBlockId, - range: (&ComplexBlockId, Option<&ComplexBlockId>), - ) -> ClientResult { - let (begin, end) = range; - Ok(is_connected_to_block(storage, block, begin)? && - match end { - Some(end) => is_connected_to_block(storage, block, end)?, - None => true, - }) - } - - /// Is the block1 directly connected (i.e. part of the same fork) to block2? - pub fn is_connected_to_block>( - storage: &S, - block1: &ComplexBlockId, - block2: &ComplexBlockId, - ) -> ClientResult { - let (begin, end) = if *block1 > *block2 { (block2, block1) } else { (block1, block2) }; - let mut current = storage - .read_header(&end.hash)? - .ok_or_else(|| ClientError::UnknownBlock(format!("{}", end.hash)))?; - while *current.number() > begin.number { - current = storage - .read_header(current.parent_hash())? - .ok_or_else(|| ClientError::UnknownBlock(format!("{}", current.parent_hash())))?; - } - - Ok(begin.hash == current.hash()) - } - - /// Returns true if the given block is finalized. - pub fn is_finalized_block>( - storage: &S, - block: &ComplexBlockId, - best_finalized_block: NumberFor, - ) -> ClientResult { - if block.number > best_finalized_block { - return Ok(false) - } - - storage.read_id(block.number).map(|hash| hash.as_ref() == Some(&block.hash)) - } -} - -/// Read list cache forks at blocks IDs. -fn read_forks>( - storage: &S, - meta: Metadata, -) -> ClientResult<(Option>, Vec>)> { - let finalized = match meta.finalized { - Some(finalized) => Some(storage.require_entry(&finalized)?.into_entry(finalized)), - None => None, - }; - - let unfinalized = meta - .unfinalized - .into_iter() - .map(|unfinalized| { - storage.require_entry(&unfinalized).map(|storage_entry| Fork { - best_block: None, - head: storage_entry.into_entry(unfinalized), - }) - }) - .collect::>()?; - - Ok((finalized, unfinalized)) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::cache::list_storage::tests::{DummyStorage, DummyTransaction, FaultyStorage}; - use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, Header}; - use substrate_test_runtime_client::runtime::H256; - - type Block = RawBlock>; - - fn test_id(number: u64) -> ComplexBlockId { - ComplexBlockId::new(H256::from_low_u64_be(number), number) - } - - fn correct_id(number: u64) -> ComplexBlockId { - ComplexBlockId::new(test_header(number).hash(), number) - } - - fn fork_id(fork_nonce: u64, fork_from: u64, number: u64) -> ComplexBlockId { - ComplexBlockId::new(fork_header(fork_nonce, fork_from, number).hash(), number) - } - - fn test_header(number: u64) -> Header { - Header { - parent_hash: if number == 0 { - Default::default() - } else { - test_header(number - 1).hash() - }, - number, - state_root: Default::default(), - extrinsics_root: Default::default(), - digest: Default::default(), - } - } - - fn fork_header(fork_nonce: u64, fork_from: u64, number: u64) -> Header { - if fork_from == number { - test_header(number) - } else { - Header { - parent_hash: fork_header(fork_nonce, fork_from, number - 1).hash(), - number, - state_root: H256::from_low_u64_be(1 + fork_nonce), - extrinsics_root: Default::default(), - digest: Default::default(), - } - } - } - - #[test] - fn list_value_at_block_works() { - // when block is earlier than best finalized block AND it is not finalized - // --- 50 --- - // ----------> [100] - assert!(ListCache::<_, u64, _>::new( - DummyStorage::new(), - PruningStrategy::ByDepth(1024), - test_id(100) - ) - .unwrap() - .value_at_block(&test_id(50)) - .is_err()); - // when block is earlier than best finalized block AND it is finalized AND value is some - // [30] ---- 50 ---> [100] - assert_eq!( - ListCache::new( - DummyStorage::new() - .with_meta(Some(test_id(100)), Vec::new()) - .with_id(50, H256::from_low_u64_be(50)) - .with_entry( - test_id(100), - StorageEntry { prev_valid_from: Some(test_id(30)), value: 100 } - ) - .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: 30 }), - PruningStrategy::ByDepth(1024), - test_id(100) - ) - .unwrap() - .value_at_block(&test_id(50)) - .unwrap(), - Some((test_id(30), Some(test_id(100)), 30)) - ); - // when block is the best finalized block AND value is some - // ---> [100] - assert_eq!( - ListCache::new( - DummyStorage::new() - .with_meta(Some(test_id(100)), Vec::new()) - .with_id(100, H256::from_low_u64_be(100)) - .with_entry( - test_id(100), - StorageEntry { prev_valid_from: Some(test_id(30)), value: 100 } - ) - .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: 30 }), - PruningStrategy::ByDepth(1024), - test_id(100) - ) - .unwrap() - .value_at_block(&test_id(100)) - .unwrap(), - Some((test_id(100), None, 100)) - ); - // when block is parallel to the best finalized block - // ---- 100 - // ---> [100] - assert!(ListCache::new( - DummyStorage::new() - .with_meta(Some(test_id(100)), Vec::new()) - .with_id(50, H256::from_low_u64_be(50)) - .with_entry( - test_id(100), - StorageEntry { prev_valid_from: Some(test_id(30)), value: 100 } - ) - .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: 30 }), - PruningStrategy::ByDepth(1024), - test_id(100) - ) - .unwrap() - .value_at_block(&ComplexBlockId::new(H256::from_low_u64_be(2), 100)) - .is_err()); - - // when block is later than last finalized block AND there are no forks AND finalized value - // is Some ---> [100] --- 200 - assert_eq!( - ListCache::new( - DummyStorage::new() - .with_meta(Some(test_id(100)), Vec::new()) - .with_id(50, H256::from_low_u64_be(50)) - .with_entry( - test_id(100), - StorageEntry { prev_valid_from: Some(test_id(30)), value: 100 } - ), - PruningStrategy::ByDepth(1024), - test_id(100) - ) - .unwrap() - .value_at_block(&test_id(200)) - .unwrap(), - Some((test_id(100), None, 100)) - ); - - // when block is later than last finalized block AND there are no matching forks - // AND block is connected to finalized block AND finalized value is Some - // --- 3 - // ---> [2] /---------> [4] - assert_eq!( - ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_entry( - correct_id(4), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 4 } - ) - .with_header(test_header(2)) - .with_header(test_header(3)) - .with_header(test_header(4)) - .with_header(fork_header(0, 2, 3)), - PruningStrategy::ByDepth(1024), - test_id(2) - ) - .unwrap() - .value_at_block(&fork_id(0, 2, 3)) - .unwrap(), - Some((correct_id(2), None, 2)) - ); - // when block is later than last finalized block AND there are no matching forks - // AND block is not connected to finalized block - // --- 2 --- 3 - // 1 /---> [2] ---------> [4] - assert_eq!( - ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_entry( - correct_id(4), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 4 } - ) - .with_header(test_header(1)) - .with_header(test_header(2)) - .with_header(test_header(3)) - .with_header(test_header(4)) - .with_header(fork_header(0, 1, 3)) - .with_header(fork_header(0, 1, 2)), - PruningStrategy::ByDepth(1024), - test_id(2) - ) - .unwrap() - .value_at_block(&fork_id(0, 1, 3)) - .unwrap(), - None - ); - - // when block is later than last finalized block AND it appends to unfinalized fork from the - // end AND unfinalized value is Some - // ---> [2] ---> [4] ---> 5 - assert_eq!( - ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_entry( - correct_id(4), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 4 } - ) - .with_header(test_header(4)) - .with_header(test_header(5)), - PruningStrategy::ByDepth(1024), - test_id(2) - ) - .unwrap() - .value_at_block(&correct_id(5)) - .unwrap(), - Some((correct_id(4), None, 4)) - ); - // when block is later than last finalized block AND it does not fits unfinalized fork - // AND it is connected to the finalized block AND finalized value is Some - // ---> [2] ----------> [4] - // \--- 3 - assert_eq!( - ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry( - correct_id(4), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 4 } - ) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_header(test_header(2)) - .with_header(test_header(3)) - .with_header(test_header(4)) - .with_header(fork_header(0, 2, 3)), - PruningStrategy::ByDepth(1024), - test_id(2) - ) - .unwrap() - .value_at_block(&fork_id(0, 2, 3)) - .unwrap(), - Some((correct_id(2), None, 2)) - ); - } - - #[test] - fn list_on_block_insert_works() { - let nfin = EntryType::NonFinal; - let fin = EntryType::Final; - - // when trying to insert block < finalized number - let mut ops = Default::default(); - assert!(ListCache::new(DummyStorage::new(), PruningStrategy::ByDepth(1024), test_id(100)) - .unwrap() - .do_on_block_insert( - &mut DummyTransaction::new(), - test_id(49), - test_id(50), - Some(50), - nfin, - &mut ops, - ) - .unwrap() - .is_none()); - // when trying to insert block @ finalized number - assert!(ListCache::new(DummyStorage::new(), PruningStrategy::ByDepth(1024), test_id(100)) - .unwrap() - .do_on_block_insert( - &mut DummyTransaction::new(), - test_id(99), - test_id(100), - Some(100), - nfin, - &Default::default(), - ) - .unwrap() - .is_none()); - - // when trying to insert non-final block AND it appends to the best block of unfinalized - // fork AND new value is the same as in the fork' best block - let mut cache = ListCache::new( - DummyStorage::new() - .with_meta(None, vec![test_id(4)]) - .with_entry(test_id(4), StorageEntry { prev_valid_from: None, value: 4 }), - PruningStrategy::ByDepth(1024), - test_id(2), - ) - .unwrap(); - cache.unfinalized[0].best_block = Some(test_id(4)); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - test_id(4), - test_id(5), - Some(4), - nfin, - &Default::default() - ) - .unwrap(), - Some(CommitOperation::AppendNewBlock(0, test_id(5))), - ); - assert!(tx.inserted_entries().is_empty()); - assert!(tx.removed_entries().is_empty()); - assert!(tx.updated_meta().is_none()); - // when trying to insert non-final block AND it appends to the best block of unfinalized - // fork AND new value is the same as in the fork' best block - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - test_id(4), - test_id(5), - Some(5), - nfin, - &Default::default() - ) - .unwrap(), - Some(CommitOperation::AppendNewEntry(0, Entry { valid_from: test_id(5), value: 5 })), - ); - assert_eq!(*tx.inserted_entries(), vec![test_id(5).hash].into_iter().collect()); - assert!(tx.removed_entries().is_empty()); - assert_eq!( - *tx.updated_meta(), - Some(Metadata { finalized: None, unfinalized: vec![test_id(5)] }) - ); - - // when trying to insert non-final block AND it is the first block that appends to the best - // block of unfinalized fork AND new value is the same as in the fork' best block - let cache = ListCache::new( - DummyStorage::new() - .with_meta(None, vec![correct_id(4)]) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: None, value: 4 }) - .with_header(test_header(4)), - PruningStrategy::ByDepth(1024), - test_id(2), - ) - .unwrap(); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - correct_id(4), - correct_id(5), - Some(4), - nfin, - &Default::default(), - ) - .unwrap(), - Some(CommitOperation::AppendNewBlock(0, correct_id(5))), - ); - assert!(tx.inserted_entries().is_empty()); - assert!(tx.removed_entries().is_empty()); - assert!(tx.updated_meta().is_none()); - // when trying to insert non-final block AND it is the first block that appends to the best - // block of unfinalized fork AND new value is the same as in the fork' best block - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - correct_id(4), - correct_id(5), - Some(5), - nfin, - &Default::default(), - ) - .unwrap(), - Some(CommitOperation::AppendNewEntry(0, Entry { valid_from: correct_id(5), value: 5 })), - ); - assert_eq!(*tx.inserted_entries(), vec![correct_id(5).hash].into_iter().collect()); - assert!(tx.removed_entries().is_empty()); - assert_eq!( - *tx.updated_meta(), - Some(Metadata { finalized: None, unfinalized: vec![correct_id(5)] }) - ); - - // when trying to insert non-final block AND it forks unfinalized fork - let cache = ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry( - correct_id(4), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 4 }, - ) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_header(test_header(2)) - .with_header(test_header(3)) - .with_header(test_header(4)), - PruningStrategy::ByDepth(1024), - correct_id(2), - ) - .unwrap(); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - correct_id(3), - fork_id(0, 3, 4), - Some(14), - nfin, - &Default::default() - ) - .unwrap(), - Some(CommitOperation::AddNewFork(Entry { valid_from: fork_id(0, 3, 4), value: 14 })), - ); - assert_eq!(*tx.inserted_entries(), vec![fork_id(0, 3, 4).hash].into_iter().collect()); - assert!(tx.removed_entries().is_empty()); - assert_eq!( - *tx.updated_meta(), - Some(Metadata { - finalized: Some(correct_id(2)), - unfinalized: vec![correct_id(4), fork_id(0, 3, 4)] - }) - ); - - // when trying to insert non-final block AND there are no unfinalized forks - // AND value is the same as last finalized - let cache = ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }), - PruningStrategy::ByDepth(1024), - correct_id(2), - ) - .unwrap(); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - correct_id(2), - correct_id(3), - Some(2), - nfin, - &Default::default() - ) - .unwrap(), - None, - ); - assert!(tx.inserted_entries().is_empty()); - assert!(tx.removed_entries().is_empty()); - assert!(tx.updated_meta().is_none()); - // when trying to insert non-final block AND there are no unfinalized forks - // AND value differs from last finalized - let cache = ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }), - PruningStrategy::ByDepth(1024), - correct_id(2), - ) - .unwrap(); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - correct_id(2), - correct_id(3), - Some(3), - nfin, - &Default::default() - ) - .unwrap(), - Some(CommitOperation::AddNewFork(Entry { valid_from: correct_id(3), value: 3 })), - ); - assert_eq!(*tx.inserted_entries(), vec![correct_id(3).hash].into_iter().collect()); - assert!(tx.removed_entries().is_empty()); - assert_eq!( - *tx.updated_meta(), - Some(Metadata { finalized: Some(correct_id(2)), unfinalized: vec![correct_id(3)] }) - ); - - // when inserting finalized entry AND there are no previous finalized entries - let cache = - ListCache::new(DummyStorage::new(), PruningStrategy::ByDepth(1024), correct_id(2)) - .unwrap(); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - correct_id(2), - correct_id(3), - Some(3), - fin, - &Default::default() - ) - .unwrap(), - Some(CommitOperation::BlockFinalized( - correct_id(3), - Some(Entry { valid_from: correct_id(3), value: 3 }), - Default::default(), - )), - ); - assert_eq!(*tx.inserted_entries(), vec![correct_id(3).hash].into_iter().collect()); - assert!(tx.removed_entries().is_empty()); - assert_eq!( - *tx.updated_meta(), - Some(Metadata { finalized: Some(correct_id(3)), unfinalized: vec![] }) - ); - // when inserting finalized entry AND value is the same as in previous finalized - let cache = ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }), - PruningStrategy::ByDepth(1024), - correct_id(2), - ) - .unwrap(); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - correct_id(2), - correct_id(3), - Some(2), - fin, - &Default::default() - ) - .unwrap(), - Some(CommitOperation::BlockFinalized(correct_id(3), None, Default::default())), - ); - assert!(tx.inserted_entries().is_empty()); - assert!(tx.removed_entries().is_empty()); - assert!(tx.updated_meta().is_none()); - // when inserting finalized entry AND value differs from previous finalized - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - correct_id(2), - correct_id(3), - Some(3), - fin, - &Default::default() - ) - .unwrap(), - Some(CommitOperation::BlockFinalized( - correct_id(3), - Some(Entry { valid_from: correct_id(3), value: 3 }), - Default::default(), - )), - ); - assert_eq!(*tx.inserted_entries(), vec![correct_id(3).hash].into_iter().collect()); - assert!(tx.removed_entries().is_empty()); - assert_eq!( - *tx.updated_meta(), - Some(Metadata { finalized: Some(correct_id(3)), unfinalized: vec![] }) - ); - - // inserting finalized entry removes abandoned fork EVEN if new entry is not inserted - let cache = ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![fork_id(0, 1, 3)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: None, value: 13 }), - PruningStrategy::ByDepth(1024), - correct_id(2), - ) - .unwrap(); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_insert( - &mut tx, - correct_id(2), - correct_id(3), - Some(2), - fin, - &Default::default() - ) - .unwrap(), - Some(CommitOperation::BlockFinalized( - correct_id(3), - None, - vec![0].into_iter().collect() - )), - ); - } - - #[test] - fn list_on_block_finalized_works() { - // finalization does not finalizes entry if it does not exists - let cache = ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(5)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 }, - ), - PruningStrategy::ByDepth(1024), - correct_id(2), - ) - .unwrap(); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_finalize(&mut tx, correct_id(2), correct_id(3), &Default::default()) - .unwrap(), - Some(CommitOperation::BlockFinalized(correct_id(3), None, Default::default())), - ); - assert!(tx.inserted_entries().is_empty()); - assert!(tx.removed_entries().is_empty()); - assert_eq!( - *tx.updated_meta(), - Some(Metadata { finalized: Some(correct_id(2)), unfinalized: vec![correct_id(5)] }), - ); - // finalization finalizes entry - let cache = ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(5)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 }, - ), - PruningStrategy::ByDepth(1024), - correct_id(4), - ) - .unwrap(); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_finalize(&mut tx, correct_id(4), correct_id(5), &Default::default()) - .unwrap(), - Some(CommitOperation::BlockFinalized( - correct_id(5), - Some(Entry { valid_from: correct_id(5), value: 5 }), - vec![0].into_iter().collect(), - )), - ); - assert!(tx.inserted_entries().is_empty()); - assert!(tx.removed_entries().is_empty()); - assert_eq!( - *tx.updated_meta(), - Some(Metadata { finalized: Some(correct_id(5)), unfinalized: vec![] }) - ); - // finalization removes abandoned forks - let cache = ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![fork_id(0, 1, 3)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: None, value: 13 }), - PruningStrategy::ByDepth(1024), - correct_id(2), - ) - .unwrap(); - let mut tx = DummyTransaction::new(); - assert_eq!( - cache - .do_on_block_finalize(&mut tx, correct_id(2), correct_id(3), &Default::default()) - .unwrap(), - Some(CommitOperation::BlockFinalized( - correct_id(3), - None, - vec![0].into_iter().collect() - )), - ); - } - - #[test] - fn list_transaction_commit_works() { - let mut cache = ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(5), correct_id(6)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 }, - ) - .with_entry( - correct_id(6), - StorageEntry { prev_valid_from: Some(correct_id(5)), value: 6 }, - ), - PruningStrategy::ByDepth(1024), - correct_id(2), - ) - .unwrap(); - - // when new block is appended to unfinalized fork - cache.on_transaction_commit(vec![CommitOperation::AppendNewBlock(0, correct_id(6))].into()); - assert_eq!(cache.unfinalized[0].best_block, Some(correct_id(6))); - // when new entry is appended to unfinalized fork - cache.on_transaction_commit( - vec![CommitOperation::AppendNewEntry(0, Entry { valid_from: correct_id(7), value: 7 })] - .into(), - ); - assert_eq!(cache.unfinalized[0].best_block, Some(correct_id(7))); - assert_eq!(cache.unfinalized[0].head, Entry { valid_from: correct_id(7), value: 7 }); - // when new fork is added - cache.on_transaction_commit( - vec![CommitOperation::AddNewFork(Entry { valid_from: correct_id(10), value: 10 })] - .into(), - ); - assert_eq!(cache.unfinalized[2].best_block, Some(correct_id(10))); - assert_eq!(cache.unfinalized[2].head, Entry { valid_from: correct_id(10), value: 10 }); - // when block is finalized + entry is finalized + unfinalized forks are deleted - cache.on_transaction_commit( - vec![CommitOperation::BlockFinalized( - correct_id(20), - Some(Entry { valid_from: correct_id(20), value: 20 }), - vec![0, 1, 2].into_iter().collect(), - )] - .into(), - ); - assert_eq!(cache.best_finalized_block, correct_id(20)); - assert_eq!( - cache.best_finalized_entry, - Some(Entry { valid_from: correct_id(20), value: 20 }) - ); - assert!(cache.unfinalized.is_empty()); - } - - #[test] - fn list_find_unfinalized_fork_works() { - // ----------> [3] - // --- [2] ---------> 4 ---> [5] - assert_eq!( - ListCache::new( - DummyStorage::new() - .with_meta(None, vec![fork_id(0, 1, 3), correct_id(5)]) - .with_entry( - fork_id(0, 1, 3), - StorageEntry { prev_valid_from: Some(correct_id(1)), value: 13 } - ) - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 } - ) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) - .with_header(test_header(2)) - .with_header(test_header(3)) - .with_header(test_header(4)) - .with_header(test_header(5)), - PruningStrategy::ByDepth(1024), - correct_id(0) - ) - .unwrap() - .find_unfinalized_fork((&correct_id(4)).into()) - .unwrap() - .unwrap() - .head - .valid_from, - correct_id(5) - ); - // --- [2] ---------------> [5] - // ----------> [3] ---> 4 - assert_eq!( - ListCache::new( - DummyStorage::new() - .with_meta(None, vec![correct_id(5), fork_id(0, 1, 3)]) - .with_entry( - fork_id(0, 1, 3), - StorageEntry { prev_valid_from: Some(correct_id(1)), value: 13 } - ) - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 } - ) - .with_entry( - correct_id(2), - StorageEntry { prev_valid_from: Some(correct_id(1)), value: 2 } - ) - .with_header(test_header(2)) - .with_header(test_header(3)) - .with_header(test_header(4)) - .with_header(test_header(5)) - .with_header(fork_header(0, 1, 2)) - .with_header(fork_header(0, 1, 3)) - .with_header(fork_header(0, 1, 4)), - PruningStrategy::ByDepth(1024), - correct_id(0) - ) - .unwrap() - .find_unfinalized_fork((&fork_id(0, 1, 4)).into()) - .unwrap() - .unwrap() - .head - .valid_from, - fork_id(0, 1, 3) - ); - // --- [2] ---------------> [5] - // ----------> [3] - // -----------------> 4 - assert!(ListCache::new( - DummyStorage::new() - .with_meta(None, vec![correct_id(5), fork_id(0, 1, 3)]) - .with_entry( - fork_id(0, 1, 3), - StorageEntry { prev_valid_from: Some(correct_id(1)), value: 13 } - ) - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 } - ) - .with_entry( - correct_id(2), - StorageEntry { prev_valid_from: Some(correct_id(1)), value: 2 } - ) - .with_header(test_header(2)) - .with_header(test_header(3)) - .with_header(test_header(4)) - .with_header(test_header(5)) - .with_header(fork_header(0, 1, 3)) - .with_header(fork_header(0, 1, 4)) - .with_header(fork_header(1, 1, 2)) - .with_header(fork_header(1, 1, 3)) - .with_header(fork_header(1, 1, 4)), - PruningStrategy::ByDepth(1024), - correct_id(0) - ) - .unwrap() - .find_unfinalized_fork((&fork_id(1, 1, 4)).into()) - .unwrap() - .is_none()); - } - - #[test] - fn fork_matches_works() { - // when block is not within list range - let storage = DummyStorage::new() - .with_entry( - test_id(100), - StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 }, - ) - .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: 50 }); - assert_eq!( - Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } - .matches(&storage, (&test_id(20)).into()) - .unwrap(), - false - ); - // when block is not connected to the begin block - let storage = DummyStorage::new() - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }, - ) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) - .with_header(test_header(5)) - .with_header(test_header(4)) - .with_header(test_header(3)) - .with_header(fork_header(0, 2, 4)) - .with_header(fork_header(0, 2, 3)); - assert_eq!( - Fork::<_, u64> { - best_block: None, - head: Entry { valid_from: correct_id(5), value: 100 } - } - .matches(&storage, (&fork_id(0, 2, 4)).into()) - .unwrap(), - false - ); - // when block is not connected to the end block - let storage = DummyStorage::new() - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }, - ) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) - .with_header(test_header(5)) - .with_header(test_header(4)) - .with_header(test_header(3)) - .with_header(fork_header(0, 3, 4)); - assert_eq!( - Fork::<_, u64> { - best_block: None, - head: Entry { valid_from: correct_id(5), value: 100 } - } - .matches(&storage, (&fork_id(0, 3, 4)).into()) - .unwrap(), - false - ); - // when block is connected to the begin block AND end is open - let storage = DummyStorage::new() - .with_entry(correct_id(5), StorageEntry { prev_valid_from: None, value: 100 }) - .with_header(test_header(5)) - .with_header(test_header(6)); - assert_eq!( - Fork::<_, u64> { - best_block: None, - head: Entry { valid_from: correct_id(5), value: 100 } - } - .matches(&storage, (&correct_id(6)).into()) - .unwrap(), - true - ); - // when block is connected to the begin block AND to the end block - let storage = DummyStorage::new() - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }, - ) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) - .with_header(test_header(5)) - .with_header(test_header(4)) - .with_header(test_header(3)); - assert_eq!( - Fork::<_, u64> { - best_block: None, - head: Entry { valid_from: correct_id(5), value: 100 } - } - .matches(&storage, (&correct_id(4)).into()) - .unwrap(), - true - ); - } - - #[test] - fn fork_try_append_works() { - // when best block is unknown - assert_eq!( - Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } - .try_append(&test_id(100)), - false - ); - // when best block is known but different - assert_eq!( - Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } - .try_append(&test_id(101)), - false - ); - // when best block is known and the same - assert_eq!( - Fork::<_, u64> { - best_block: Some(test_id(100)), - head: Entry { valid_from: test_id(100), value: 0 } - } - .try_append(&test_id(100)), - true - ); - } - - #[test] - fn fork_try_append_or_fork_works() { - // when there's no entry before parent - let storage = DummyStorage::new() - .with_entry( - test_id(100), - StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 }, - ) - .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: 50 }); - assert_eq!( - Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } - .try_append_or_fork(&storage, &test_id(30), None) - .unwrap(), - None - ); - // when parent does not belong to the fork - let storage = DummyStorage::new() - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }, - ) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) - .with_header(test_header(5)) - .with_header(test_header(4)) - .with_header(test_header(3)) - .with_header(fork_header(0, 2, 4)) - .with_header(fork_header(0, 2, 3)); - assert_eq!( - Fork::<_, u64> { - best_block: None, - head: Entry { valid_from: correct_id(5), value: 100 } - } - .try_append_or_fork(&storage, &fork_id(0, 2, 4), None) - .unwrap(), - None - ); - // when the entry before parent is the head entry - let storage = DummyStorage::new() - .with_entry( - ComplexBlockId::new(test_header(5).hash(), 5), - StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }, - ) - .with_header(test_header(6)) - .with_header(test_header(5)); - assert_eq!( - Fork::<_, u64> { - best_block: None, - head: Entry { valid_from: correct_id(5), value: 100 } - } - .try_append_or_fork(&storage, &correct_id(6), None) - .unwrap(), - Some(ForkAppendResult::Append) - ); - // when the parent located after last finalized entry - let storage = DummyStorage::new() - .with_entry( - correct_id(6), - StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }, - ) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) - .with_header(test_header(6)) - .with_header(test_header(5)) - .with_header(test_header(4)) - .with_header(test_header(3)) - .with_header(fork_header(0, 4, 5)); - assert_eq!( - Fork::<_, u64> { - best_block: None, - head: Entry { valid_from: correct_id(6), value: 100 } - } - .try_append_or_fork(&storage, &fork_id(0, 4, 5), None) - .unwrap(), - Some(ForkAppendResult::Fork(ComplexBlockId::new(test_header(3).hash(), 3))) - ); - // when the parent located before last finalized entry - let storage = DummyStorage::new() - .with_entry( - correct_id(6), - StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }, - ) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) - .with_header(test_header(6)) - .with_header(test_header(5)) - .with_header(test_header(4)) - .with_header(test_header(3)) - .with_header(fork_header(0, 4, 5)); - assert_eq!( - Fork::<_, u64> { - best_block: None, - head: Entry { valid_from: correct_id(6), value: 100 } - } - .try_append_or_fork(&storage, &fork_id(0, 4, 5), Some(3)) - .unwrap(), - None - ); - } - - #[test] - fn fork_destroy_works() { - // when we reached finalized entry without iterations - let storage = DummyStorage::new().with_id(100, H256::from_low_u64_be(100)); - let mut tx = DummyTransaction::new(); - Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } - .destroy(&storage, &mut tx, Some(200)) - .unwrap(); - assert!(tx.removed_entries().is_empty()); - // when we reach finalized entry with iterations - let storage = DummyStorage::new() - .with_id(10, H256::from_low_u64_be(10)) - .with_entry( - test_id(100), - StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 }, - ) - .with_entry(test_id(50), StorageEntry { prev_valid_from: Some(test_id(20)), value: 50 }) - .with_entry(test_id(20), StorageEntry { prev_valid_from: Some(test_id(10)), value: 20 }) - .with_entry(test_id(10), StorageEntry { prev_valid_from: Some(test_id(5)), value: 10 }) - .with_entry(test_id(5), StorageEntry { prev_valid_from: Some(test_id(3)), value: 5 }) - .with_entry(test_id(3), StorageEntry { prev_valid_from: None, value: 0 }); - let mut tx = DummyTransaction::new(); - Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } - .destroy(&storage, &mut tx, Some(200)) - .unwrap(); - assert_eq!( - *tx.removed_entries(), - vec![test_id(100).hash, test_id(50).hash, test_id(20).hash] - .into_iter() - .collect() - ); - // when we reach beginning of fork before finalized block - let storage = DummyStorage::new() - .with_id(10, H256::from_low_u64_be(10)) - .with_entry( - test_id(100), - StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 }, - ) - .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: 50 }); - let mut tx = DummyTransaction::new(); - Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } - .destroy(&storage, &mut tx, Some(200)) - .unwrap(); - assert_eq!( - *tx.removed_entries(), - vec![test_id(100).hash, test_id(50).hash].into_iter().collect() - ); - } - - #[test] - fn is_connected_to_block_fails() { - // when storage returns error - assert!(chain::is_connected_to_block::<_, u64, _>( - &FaultyStorage, - (&test_id(1)).into(), - &test_id(100), - ) - .is_err(),); - // when there's no header in the storage - assert!(chain::is_connected_to_block::<_, u64, _>( - &DummyStorage::new(), - (&test_id(1)).into(), - &test_id(100), - ) - .is_err(),); - } - - #[test] - fn is_connected_to_block_works() { - // when without iterations we end up with different block - assert_eq!( - chain::is_connected_to_block::<_, u64, _>( - &DummyStorage::new().with_header(test_header(1)), - (&test_id(1)).into(), - &correct_id(1) - ) - .unwrap(), - false - ); - // when with ASC iterations we end up with different block - assert_eq!( - chain::is_connected_to_block::<_, u64, _>( - &DummyStorage::new() - .with_header(test_header(0)) - .with_header(test_header(1)) - .with_header(test_header(2)), - (&test_id(0)).into(), - &correct_id(2) - ) - .unwrap(), - false - ); - // when with DESC iterations we end up with different block - assert_eq!( - chain::is_connected_to_block::<_, u64, _>( - &DummyStorage::new() - .with_header(test_header(0)) - .with_header(test_header(1)) - .with_header(test_header(2)), - (&correct_id(2)).into(), - &test_id(0) - ) - .unwrap(), - false - ); - // when without iterations we end up with the same block - assert_eq!( - chain::is_connected_to_block::<_, u64, _>( - &DummyStorage::new().with_header(test_header(1)), - (&correct_id(1)).into(), - &correct_id(1) - ) - .unwrap(), - true - ); - // when with ASC iterations we end up with the same block - assert_eq!( - chain::is_connected_to_block::<_, u64, _>( - &DummyStorage::new() - .with_header(test_header(0)) - .with_header(test_header(1)) - .with_header(test_header(2)), - (&correct_id(0)).into(), - &correct_id(2) - ) - .unwrap(), - true - ); - // when with DESC iterations we end up with the same block - assert_eq!( - chain::is_connected_to_block::<_, u64, _>( - &DummyStorage::new() - .with_header(test_header(0)) - .with_header(test_header(1)) - .with_header(test_header(2)), - (&correct_id(2)).into(), - &correct_id(0) - ) - .unwrap(), - true - ); - } - - #[test] - fn is_finalized_block_fails() { - // when storage returns error - assert!(chain::is_finalized_block::<_, u64, _>(&FaultyStorage, &test_id(1), 100).is_err()); - } - - #[test] - fn is_finalized_block_works() { - // when number of block is larger than last finalized block - assert_eq!( - chain::is_finalized_block::<_, u64, _>(&DummyStorage::new(), &test_id(100), 1).unwrap(), - false - ); - // when there's no hash for this block number in the database - assert_eq!( - chain::is_finalized_block::<_, u64, _>(&DummyStorage::new(), &test_id(1), 100).unwrap(), - false - ); - // when there's different hash for this block number in the database - assert_eq!( - chain::is_finalized_block::<_, u64, _>( - &DummyStorage::new().with_id(1, H256::from_low_u64_be(2)), - &test_id(1), - 100 - ) - .unwrap(), - false - ); - // when there's the same hash for this block number in the database - assert_eq!( - chain::is_finalized_block::<_, u64, _>( - &DummyStorage::new().with_id(1, H256::from_low_u64_be(1)), - &test_id(1), - 100 - ) - .unwrap(), - true - ); - } - - #[test] - fn read_forks_fails() { - // when storage returns error during finalized entry read - assert!(read_forks::( - &FaultyStorage, - Metadata { finalized: Some(test_id(1)), unfinalized: vec![] } - ) - .is_err()); - // when storage returns error during unfinalized entry read - assert!(read_forks::( - &FaultyStorage, - Metadata { finalized: None, unfinalized: vec![test_id(1)] } - ) - .is_err()); - // when finalized entry is not found - assert!(read_forks::( - &DummyStorage::new(), - Metadata { finalized: Some(test_id(1)), unfinalized: vec![] } - ) - .is_err()); - // when unfinalized entry is not found - assert!(read_forks::( - &DummyStorage::new(), - Metadata { finalized: None, unfinalized: vec![test_id(1)] } - ) - .is_err()); - } - - #[test] - fn read_forks_works() { - let storage = DummyStorage::new() - .with_entry(test_id(10), StorageEntry { prev_valid_from: Some(test_id(1)), value: 11 }) - .with_entry(test_id(20), StorageEntry { prev_valid_from: Some(test_id(2)), value: 0 }) - .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: 33 }); - let expected = ( - Some(Entry { valid_from: test_id(10), value: 11 }), - vec![ - Fork { best_block: None, head: Entry { valid_from: test_id(20), value: 0 } }, - Fork { best_block: None, head: Entry { valid_from: test_id(30), value: 33 } }, - ], - ); - - assert_eq!( - expected, - read_forks( - &storage, - Metadata { - finalized: Some(test_id(10)), - unfinalized: vec![test_id(20), test_id(30)], - } - ) - .unwrap() - ); - } - - #[test] - fn ancient_entries_are_pruned_when_pruning_enabled() { - fn do_test(strategy: PruningStrategy) { - let cache = ListCache::new( - DummyStorage::new() - .with_id(10, H256::from_low_u64_be(10)) - .with_id(20, H256::from_low_u64_be(20)) - .with_id(30, H256::from_low_u64_be(30)) - .with_entry(test_id(10), StorageEntry { prev_valid_from: None, value: 10 }) - .with_entry( - test_id(20), - StorageEntry { prev_valid_from: Some(test_id(10)), value: 20 }, - ) - .with_entry( - test_id(30), - StorageEntry { prev_valid_from: Some(test_id(20)), value: 30 }, - ), - strategy, - test_id(9), - ) - .unwrap(); - let mut tx = DummyTransaction::new(); - - // when finalizing entry #10: no entries pruned - cache.prune_finalized_entries(&mut tx, &test_id(10)); - assert!(tx.removed_entries().is_empty()); - assert!(tx.inserted_entries().is_empty()); - // when finalizing entry #19: no entries pruned - cache.prune_finalized_entries(&mut tx, &test_id(19)); - assert!(tx.removed_entries().is_empty()); - assert!(tx.inserted_entries().is_empty()); - // when finalizing entry #20: no entries pruned - cache.prune_finalized_entries(&mut tx, &test_id(20)); - assert!(tx.removed_entries().is_empty()); - assert!(tx.inserted_entries().is_empty()); - // when finalizing entry #30: entry 10 pruned + entry 20 is truncated (if pruning is - // enabled) - cache.prune_finalized_entries(&mut tx, &test_id(30)); - match strategy { - PruningStrategy::NeverPrune => { - assert!(tx.removed_entries().is_empty()); - assert!(tx.inserted_entries().is_empty()); - }, - PruningStrategy::ByDepth(_) => { - assert_eq!(*tx.removed_entries(), vec![test_id(10).hash].into_iter().collect()); - assert_eq!( - *tx.inserted_entries(), - vec![test_id(20).hash].into_iter().collect() - ); - }, - } - } - - do_test(PruningStrategy::ByDepth(10)); - do_test(PruningStrategy::NeverPrune) - } - - #[test] - fn revert_block_works() { - // 1 -> (2) -> 3 -> 4 -> 5 - // \ - // -> 5'' - // \ - // -> (3') -> 4' -> 5' - let mut cache = ListCache::new( - DummyStorage::new() - .with_meta( - Some(correct_id(1)), - vec![correct_id(5), fork_id(1, 2, 5), fork_id(2, 4, 5)], - ) - .with_id(1, correct_id(1).hash) - .with_entry(correct_id(1), StorageEntry { prev_valid_from: None, value: 1 }) - .with_entry( - correct_id(3), - StorageEntry { prev_valid_from: Some(correct_id(1)), value: 3 }, - ) - .with_entry( - correct_id(4), - StorageEntry { prev_valid_from: Some(correct_id(3)), value: 4 }, - ) - .with_entry( - correct_id(5), - StorageEntry { prev_valid_from: Some(correct_id(4)), value: 5 }, - ) - .with_entry( - fork_id(1, 2, 4), - StorageEntry { prev_valid_from: Some(correct_id(1)), value: 14 }, - ) - .with_entry( - fork_id(1, 2, 5), - StorageEntry { prev_valid_from: Some(fork_id(1, 2, 4)), value: 15 }, - ) - .with_entry( - fork_id(2, 4, 5), - StorageEntry { prev_valid_from: Some(correct_id(4)), value: 25 }, - ) - .with_header(test_header(1)) - .with_header(test_header(2)) - .with_header(test_header(3)) - .with_header(test_header(4)) - .with_header(test_header(5)) - .with_header(fork_header(1, 2, 3)) - .with_header(fork_header(1, 2, 4)) - .with_header(fork_header(1, 2, 5)) - .with_header(fork_header(2, 4, 5)), - PruningStrategy::ByDepth(1024), - correct_id(1), - ) - .unwrap(); - - // when 5 is reverted: entry 5 is truncated - let op = cache.do_on_block_revert(&mut DummyTransaction::new(), &correct_id(5)).unwrap(); - assert_eq!( - op, - CommitOperation::BlockReverted( - vec![( - 0, - Some(Fork { - best_block: None, - head: Entry { valid_from: correct_id(4), value: 4 } - }) - ),] - .into_iter() - .collect() - ) - ); - cache.on_transaction_commit(vec![op].into()); - - // when 3 is reverted: entries 4+5' are truncated - let op = cache.do_on_block_revert(&mut DummyTransaction::new(), &correct_id(3)).unwrap(); - assert_eq!( - op, - CommitOperation::BlockReverted(vec![(0, None), (2, None),].into_iter().collect()) - ); - cache.on_transaction_commit(vec![op].into()); - - // when 2 is reverted: entries 4'+5' are truncated - let op = cache.do_on_block_revert(&mut DummyTransaction::new(), &correct_id(2)).unwrap(); - assert_eq!(op, CommitOperation::BlockReverted(vec![(0, None),].into_iter().collect())); - cache.on_transaction_commit(vec![op].into()); - } - - #[test] - fn append_commit_operation_works() { - let mut ops = CommitOperations::default(); - ops.append(None); - assert_eq!(ops.operations, Vec::new()); - - ops.append(Some(CommitOperation::BlockFinalized( - test_id(10), - Some(Entry { valid_from: test_id(10), value: 10 }), - vec![5].into_iter().collect(), - ))); - assert_eq!( - ops.operations, - vec![CommitOperation::BlockFinalized( - test_id(10), - Some(Entry { valid_from: test_id(10), value: 10 }), - vec![5].into_iter().collect(), - )], - ); - - ops.append(Some(CommitOperation::BlockFinalized( - test_id(20), - Some(Entry { valid_from: test_id(20), value: 20 }), - vec![5, 6].into_iter().collect(), - ))); - - assert_eq!( - ops.operations, - vec![CommitOperation::BlockFinalized( - test_id(20), - Some(Entry { valid_from: test_id(20), value: 20 }), - vec![5, 6].into_iter().collect(), - )], - ); - } -} diff --git a/client/db/src/cache/list_entry.rs b/client/db/src/cache/list_entry.rs deleted file mode 100644 index 7cee7a5146260..0000000000000 --- a/client/db/src/cache/list_entry.rs +++ /dev/null @@ -1,187 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! List-cache storage entries. - -use codec::{Decode, Encode}; -use sp_blockchain::Result as ClientResult; -use sp_runtime::traits::{Block as BlockT, NumberFor}; - -use crate::cache::{list_storage::Storage, CacheItemT, ComplexBlockId}; - -/// Single list-based cache entry. -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq))] -pub struct Entry { - /// first block, when this value became actual. - pub valid_from: ComplexBlockId, - /// Value stored at this entry. - pub value: T, -} - -/// Internal representation of the single list-based cache entry. The entry points to the -/// previous entry in the cache, allowing us to traverse back in time in list-style. -#[derive(Debug, Encode, Decode)] -#[cfg_attr(test, derive(Clone, PartialEq))] -pub struct StorageEntry { - /// None if valid from the beginning. - pub prev_valid_from: Option>, - /// Value stored at this entry. - pub value: T, -} - -impl Entry { - /// Returns Some if the entry should be updated with the new value. - pub fn try_update(&self, value: Option) -> Option> { - match value { - Some(value) => match self.value == value { - true => None, - false => - Some(StorageEntry { prev_valid_from: Some(self.valid_from.clone()), value }), - }, - None => None, - } - } - - /// Wrapper that calls search_before to get range where the given block fits. - pub fn search_best_range_before>( - &self, - storage: &S, - block: NumberFor, - ) -> ClientResult, Option>)>> { - Ok(self - .search_best_before(storage, block)? - .map(|(entry, next)| (entry.valid_from, next))) - } - - /// Searches the list, ending with THIS entry for the best entry preceding (or at) - /// given block number. - /// If the entry is found, result is the entry and the block id of next entry (if exists). - /// NOTE that this function does not check that the passed block is actually linked to - /// the blocks it found. - pub fn search_best_before>( - &self, - storage: &S, - block: NumberFor, - ) -> ClientResult, Option>)>> { - // we're looking for the best value - let mut next = None; - let mut current = self.valid_from.clone(); - if block >= self.valid_from.number { - let value = self.value.clone(); - return Ok(Some((Entry { valid_from: current, value }, next))) - } - - // else - travel back in time - loop { - let entry = storage.require_entry(¤t)?; - if block >= current.number { - return Ok(Some((Entry { valid_from: current, value: entry.value }, next))) - } - - next = Some(current); - current = match entry.prev_valid_from { - Some(prev_valid_from) => prev_valid_from, - None => return Ok(None), - }; - } - } -} - -impl StorageEntry { - /// Converts storage entry into an entry, valid from given block. - pub fn into_entry(self, valid_from: ComplexBlockId) -> Entry { - Entry { valid_from, value: self.value } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::cache::list_storage::tests::{DummyStorage, FaultyStorage}; - use substrate_test_runtime_client::runtime::{Block, H256}; - - fn test_id(number: u64) -> ComplexBlockId { - ComplexBlockId::new(H256::from_low_u64_be(number), number) - } - - #[test] - fn entry_try_update_works() { - // when trying to update with None value - assert_eq!(Entry::<_, u64> { valid_from: test_id(1), value: 42 }.try_update(None), None); - // when trying to update with the same Some value - assert_eq!(Entry { valid_from: test_id(1), value: 1 }.try_update(Some(1)), None); - // when trying to update with different Some value - assert_eq!( - Entry { valid_from: test_id(1), value: 1 }.try_update(Some(2)), - Some(StorageEntry { prev_valid_from: Some(test_id(1)), value: 2 }) - ); - } - - #[test] - fn entry_search_best_before_fails() { - // when storage returns error - assert!(Entry::<_, u64> { valid_from: test_id(100), value: 42 } - .search_best_before(&FaultyStorage, 50) - .is_err()); - } - - #[test] - fn entry_search_best_before_works() { - // when block is better than our best block - assert_eq!( - Entry::<_, u64> { valid_from: test_id(100), value: 100 } - .search_best_before(&DummyStorage::new(), 150) - .unwrap(), - Some((Entry::<_, u64> { valid_from: test_id(100), value: 100 }, None)) - ); - // when block is found between two entries - assert_eq!( - Entry::<_, u64> { valid_from: test_id(100), value: 100 } - .search_best_before( - &DummyStorage::new() - .with_entry( - test_id(100), - StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 } - ) - .with_entry( - test_id(50), - StorageEntry { prev_valid_from: Some(test_id(30)), value: 50 } - ), - 75 - ) - .unwrap(), - Some((Entry::<_, u64> { valid_from: test_id(50), value: 50 }, Some(test_id(100)))) - ); - // when block is not found - assert_eq!( - Entry::<_, u64> { valid_from: test_id(100), value: 100 } - .search_best_before( - &DummyStorage::new() - .with_entry( - test_id(100), - StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 } - ) - .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: 50 }), - 30 - ) - .unwrap(), - None - ); - } -} diff --git a/client/db/src/cache/list_storage.rs b/client/db/src/cache/list_storage.rs deleted file mode 100644 index bb47b8dab5a7f..0000000000000 --- a/client/db/src/cache/list_storage.rs +++ /dev/null @@ -1,441 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! List-cache storage definition and implementation. - -use std::sync::Arc; - -use crate::utils::{self, meta_keys}; -use codec::{Decode, Encode}; -use sp_blockchain::{Error as ClientError, Result as ClientResult}; -use sp_database::{Database, Transaction}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT, NumberFor}, -}; - -use crate::{ - cache::{ - list_cache::{CommitOperation, Fork}, - list_entry::{Entry, StorageEntry}, - CacheItemT, ComplexBlockId, - }, - DbHash, -}; - -/// Single list-cache metadata. -#[derive(Debug)] -#[cfg_attr(test, derive(Clone, PartialEq))] -pub struct Metadata { - /// Block at which best finalized entry is stored. - pub finalized: Option>, - /// A set of blocks at which best unfinalized entries are stored. - pub unfinalized: Vec>, -} - -/// Readonly list-cache storage trait. -pub trait Storage { - /// Reads hash of the block at given number. - fn read_id(&self, at: NumberFor) -> ClientResult>; - - /// Reads header of the block with given hash. - fn read_header(&self, at: &Block::Hash) -> ClientResult>; - - /// Reads cache metadata: best finalized entry (if some) and the list. - fn read_meta(&self) -> ClientResult>; - - /// Reads cache entry from the storage. - fn read_entry( - &self, - at: &ComplexBlockId, - ) -> ClientResult>>; - - /// Reads referenced (and thus existing) cache entry from the storage. - fn require_entry(&self, at: &ComplexBlockId) -> ClientResult> { - self.read_entry(at).and_then(|entry| { - entry.ok_or_else(|| { - ClientError::from(ClientError::Backend(format!( - "Referenced cache entry at {:?} is not found", - at - ))) - }) - }) - } -} - -/// List-cache storage transaction. -pub trait StorageTransaction { - /// Insert storage entry at given block. - fn insert_storage_entry(&mut self, at: &ComplexBlockId, entry: &StorageEntry); - - /// Delete storage entry at given block. - fn remove_storage_entry(&mut self, at: &ComplexBlockId); - - /// Update metadata of the cache. - fn update_meta( - &mut self, - best_finalized_entry: Option<&Entry>, - unfinalized: &[Fork], - operation: &CommitOperation, - ); -} - -/// A set of columns used by the DbStorage. -#[derive(Debug)] -pub struct DbColumns { - /// Column holding cache meta. - pub meta: u32, - /// Column holding the mapping of { block number => block hash } for blocks of the best chain. - pub key_lookup: u32, - /// Column holding the mapping of { block hash => block header }. - pub header: u32, - /// Column holding cache entries. - pub cache: u32, -} - -/// Database-backed list cache storage. -pub struct DbStorage { - name: Vec, - meta_key: Vec, - db: Arc>, - columns: DbColumns, -} - -impl DbStorage { - /// Create new database-backed list cache storage. - pub fn new(name: Vec, db: Arc>, columns: DbColumns) -> Self { - let meta_key = meta::key(&name); - DbStorage { name, meta_key, db, columns } - } - - /// Get reference to the database. - pub fn db(&self) -> &Arc> { - &self.db - } - - /// Get reference to the database columns. - pub fn columns(&self) -> &DbColumns { - &self.columns - } - - /// Encode block id for storing as a key in cache column. - /// We append prefix to the actual encoding to allow several caches - /// store entries in the same column. - pub fn encode_block_id(&self, block: &ComplexBlockId) -> Vec { - let mut encoded = self.name.clone(); - encoded.extend(block.hash.as_ref()); - encoded - } -} - -impl Storage for DbStorage { - fn read_id(&self, at: NumberFor) -> ClientResult> { - utils::read_header::( - &*self.db, - self.columns.key_lookup, - self.columns.header, - BlockId::Number(at), - ) - .map(|maybe_header| maybe_header.map(|header| header.hash())) - } - - fn read_header(&self, at: &Block::Hash) -> ClientResult> { - utils::read_header::( - &*self.db, - self.columns.key_lookup, - self.columns.header, - BlockId::Hash(*at), - ) - } - - fn read_meta(&self) -> ClientResult> { - match self.db.get(self.columns.meta, &self.meta_key) { - Some(meta) => meta::decode(&*meta), - None => Ok(Metadata { finalized: None, unfinalized: Vec::new() }), - } - } - - fn read_entry( - &self, - at: &ComplexBlockId, - ) -> ClientResult>> { - match self.db.get(self.columns.cache, &self.encode_block_id(at)) { - Some(entry) => StorageEntry::::decode(&mut &entry[..]) - .map_err(|_| ClientError::Backend("Failed to decode cache entry".into())) - .map(Some), - None => Ok(None), - } - } -} - -/// Database-backed list cache storage transaction. -pub struct DbStorageTransaction<'a> { - storage: &'a DbStorage, - tx: &'a mut Transaction, -} - -impl<'a> DbStorageTransaction<'a> { - /// Create new database transaction. - pub fn new(storage: &'a DbStorage, tx: &'a mut Transaction) -> Self { - DbStorageTransaction { storage, tx } - } -} - -impl<'a, Block: BlockT, T: CacheItemT> StorageTransaction for DbStorageTransaction<'a> { - fn insert_storage_entry(&mut self, at: &ComplexBlockId, entry: &StorageEntry) { - self.tx.set_from_vec( - self.storage.columns.cache, - &self.storage.encode_block_id(at), - entry.encode(), - ); - } - - fn remove_storage_entry(&mut self, at: &ComplexBlockId) { - self.tx.remove(self.storage.columns.cache, &self.storage.encode_block_id(at)); - } - - fn update_meta( - &mut self, - best_finalized_entry: Option<&Entry>, - unfinalized: &[Fork], - operation: &CommitOperation, - ) { - self.tx.set_from_vec( - self.storage.columns.meta, - &self.storage.meta_key, - meta::encode(best_finalized_entry, unfinalized, operation), - ); - } -} - -/// Metadata related functions. -mod meta { - use super::*; - - /// Convert cache name into cache metadata key. - pub fn key(name: &[u8]) -> Vec { - let mut key_name = meta_keys::CACHE_META_PREFIX.to_vec(); - key_name.extend_from_slice(name); - key_name - } - - /// Encode cache metadata 'applying' commit operation before encoding. - pub fn encode( - best_finalized_entry: Option<&Entry>, - unfinalized: &[Fork], - op: &CommitOperation, - ) -> Vec { - let mut finalized = best_finalized_entry.as_ref().map(|entry| &entry.valid_from); - let mut unfinalized = - unfinalized.iter().map(|fork| &fork.head().valid_from).collect::>(); - - match op { - CommitOperation::AppendNewBlock(_, _) => (), - CommitOperation::AppendNewEntry(index, ref entry) => { - unfinalized[*index] = &entry.valid_from; - }, - CommitOperation::AddNewFork(ref entry) => { - unfinalized.push(&entry.valid_from); - }, - CommitOperation::BlockFinalized(_, ref finalizing_entry, ref forks) => { - if let Some(finalizing_entry) = finalizing_entry.as_ref() { - finalized = Some(&finalizing_entry.valid_from); - } - for fork_index in forks.iter().rev() { - unfinalized.remove(*fork_index); - } - }, - CommitOperation::BlockReverted(ref forks) => { - for (fork_index, updated_fork) in forks.iter().rev() { - match updated_fork { - Some(updated_fork) => - unfinalized[*fork_index] = &updated_fork.head().valid_from, - None => { - unfinalized.remove(*fork_index); - }, - } - } - }, - } - - (finalized, unfinalized).encode() - } - - /// Decode meta information. - pub fn decode(encoded: &[u8]) -> ClientResult> { - let input = &mut &*encoded; - let finalized: Option> = Decode::decode(input).map_err(|_| { - ClientError::from(ClientError::Backend("Error decoding cache meta".into())) - })?; - let unfinalized: Vec> = Decode::decode(input).map_err(|_| { - ClientError::from(ClientError::Backend("Error decoding cache meta".into())) - })?; - - Ok(Metadata { finalized, unfinalized }) - } -} - -#[cfg(test)] -pub mod tests { - use super::*; - use std::collections::{HashMap, HashSet}; - - pub struct FaultyStorage; - - impl Storage for FaultyStorage { - fn read_id(&self, _at: NumberFor) -> ClientResult> { - Err(ClientError::Backend("TestError".into())) - } - - fn read_header(&self, _at: &Block::Hash) -> ClientResult> { - Err(ClientError::Backend("TestError".into())) - } - - fn read_meta(&self) -> ClientResult> { - Err(ClientError::Backend("TestError".into())) - } - - fn read_entry( - &self, - _at: &ComplexBlockId, - ) -> ClientResult>> { - Err(ClientError::Backend("TestError".into())) - } - } - - pub struct DummyStorage { - meta: Metadata, - ids: HashMap, Block::Hash>, - headers: HashMap, - entries: HashMap>, - } - - impl DummyStorage { - pub fn new() -> Self { - DummyStorage { - meta: Metadata { finalized: None, unfinalized: Vec::new() }, - ids: HashMap::new(), - headers: HashMap::new(), - entries: HashMap::new(), - } - } - - pub fn with_meta( - mut self, - finalized: Option>, - unfinalized: Vec>, - ) -> Self { - self.meta.finalized = finalized; - self.meta.unfinalized = unfinalized; - self - } - - pub fn with_id(mut self, at: NumberFor, id: Block::Hash) -> Self { - self.ids.insert(at, id); - self - } - - pub fn with_header(mut self, header: Block::Header) -> Self { - self.headers.insert(header.hash(), header); - self - } - - pub fn with_entry( - mut self, - at: ComplexBlockId, - entry: StorageEntry, - ) -> Self { - self.entries.insert(at.hash, entry); - self - } - } - - impl Storage for DummyStorage { - fn read_id(&self, at: NumberFor) -> ClientResult> { - Ok(self.ids.get(&at).cloned()) - } - - fn read_header(&self, at: &Block::Hash) -> ClientResult> { - Ok(self.headers.get(&at).cloned()) - } - - fn read_meta(&self) -> ClientResult> { - Ok(self.meta.clone()) - } - - fn read_entry( - &self, - at: &ComplexBlockId, - ) -> ClientResult>> { - Ok(self.entries.get(&at.hash).cloned()) - } - } - - pub struct DummyTransaction { - updated_meta: Option>, - inserted_entries: HashSet, - removed_entries: HashSet, - } - - impl DummyTransaction { - pub fn new() -> Self { - DummyTransaction { - updated_meta: None, - inserted_entries: HashSet::new(), - removed_entries: HashSet::new(), - } - } - - pub fn inserted_entries(&self) -> &HashSet { - &self.inserted_entries - } - - pub fn removed_entries(&self) -> &HashSet { - &self.removed_entries - } - - pub fn updated_meta(&self) -> &Option> { - &self.updated_meta - } - } - - impl StorageTransaction for DummyTransaction { - fn insert_storage_entry( - &mut self, - at: &ComplexBlockId, - _entry: &StorageEntry, - ) { - self.inserted_entries.insert(at.hash); - } - - fn remove_storage_entry(&mut self, at: &ComplexBlockId) { - self.removed_entries.insert(at.hash); - } - - fn update_meta( - &mut self, - best_finalized_entry: Option<&Entry>, - unfinalized: &[Fork], - operation: &CommitOperation, - ) { - self.updated_meta = Some( - meta::decode(&meta::encode(best_finalized_entry, unfinalized, operation)).unwrap(), - ); - } - } -} diff --git a/client/db/src/cache/mod.rs b/client/db/src/cache/mod.rs deleted file mode 100644 index 5502896aced2c..0000000000000 --- a/client/db/src/cache/mod.rs +++ /dev/null @@ -1,413 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! DB-backed cache of blockchain data. - -use parking_lot::RwLock; -use std::{ - collections::{hash_map::Entry, HashMap}, - sync::Arc, -}; - -use crate::{ - utils::{self, COLUMN_META}, - DbHash, -}; -use codec::{Decode, Encode}; -use sc_client_api::blockchain::{ - well_known_cache_keys::{self, Id as CacheKeyId}, - Cache as BlockchainCache, -}; -use sp_blockchain::{HeaderMetadataCache, Result as ClientResult}; -use sp_database::{Database, Transaction}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, -}; - -use self::list_cache::{ListCache, PruningStrategy}; - -mod list_cache; -mod list_entry; -mod list_storage; - -/// Minimal post-finalization age of finalized blocks before they'll pruned. -const PRUNE_DEPTH: u32 = 1024; - -/// The type of entry that is inserted to the cache. -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum EntryType { - /// Non-final entry. - NonFinal, - /// Final entry. - Final, - /// Genesis entry (inserted during cache initialization). - Genesis, -} - -/// Block identifier that holds both hash and number. -#[derive(Clone, Debug, Encode, Decode, PartialEq)] -pub struct ComplexBlockId { - /// Hash of the block. - pub(crate) hash: Block::Hash, - /// Number of the block. - pub(crate) number: NumberFor, -} - -impl ComplexBlockId { - /// Create new complex block id. - pub fn new(hash: Block::Hash, number: NumberFor) -> Self { - ComplexBlockId { hash, number } - } -} - -impl ::std::cmp::PartialOrd for ComplexBlockId { - fn partial_cmp(&self, other: &ComplexBlockId) -> Option<::std::cmp::Ordering> { - self.number.partial_cmp(&other.number) - } -} - -/// All cache items must implement this trait. -pub trait CacheItemT: Clone + Decode + Encode + PartialEq {} - -impl CacheItemT for T where T: Clone + Decode + Encode + PartialEq {} - -/// Database-backed blockchain data cache. -pub struct DbCache { - cache_at: HashMap, self::list_storage::DbStorage>>, - header_metadata_cache: Arc>, - db: Arc>, - key_lookup_column: u32, - header_column: u32, - cache_column: u32, - genesis_hash: Block::Hash, - best_finalized_block: ComplexBlockId, -} - -impl DbCache { - /// Create new cache. - pub fn new( - db: Arc>, - header_metadata_cache: Arc>, - key_lookup_column: u32, - header_column: u32, - cache_column: u32, - genesis_hash: Block::Hash, - best_finalized_block: ComplexBlockId, - ) -> Self { - Self { - cache_at: HashMap::new(), - db, - header_metadata_cache, - key_lookup_column, - header_column, - cache_column, - genesis_hash, - best_finalized_block, - } - } - - /// Set genesis block hash. - pub fn set_genesis_hash(&mut self, genesis_hash: Block::Hash) { - self.genesis_hash = genesis_hash; - } - - /// Begin cache transaction. - pub fn transaction<'a>( - &'a mut self, - tx: &'a mut Transaction, - ) -> DbCacheTransaction<'a, Block> { - DbCacheTransaction { - cache: self, - tx, - cache_at_ops: HashMap::new(), - best_finalized_block: None, - } - } - - /// Begin cache transaction with given ops. - pub fn transaction_with_ops<'a>( - &'a mut self, - tx: &'a mut Transaction, - ops: DbCacheTransactionOps, - ) -> DbCacheTransaction<'a, Block> { - DbCacheTransaction { - cache: self, - tx, - cache_at_ops: ops.cache_at_ops, - best_finalized_block: ops.best_finalized_block, - } - } - - /// Run post-commit cache operations. - pub fn commit(&mut self, ops: DbCacheTransactionOps) -> ClientResult<()> { - for (name, ops) in ops.cache_at_ops.into_iter() { - self.get_cache(name)?.on_transaction_commit(ops); - } - if let Some(best_finalized_block) = ops.best_finalized_block { - self.best_finalized_block = best_finalized_block; - } - Ok(()) - } - - /// Creates `ListCache` with the given name or returns a reference to the existing. - pub(crate) fn get_cache( - &mut self, - name: CacheKeyId, - ) -> ClientResult<&mut ListCache, self::list_storage::DbStorage>> { - get_cache_helper( - &mut self.cache_at, - name, - &self.db, - self.key_lookup_column, - self.header_column, - self.cache_column, - &self.best_finalized_block, - ) - } -} - -// This helper is needed because otherwise the borrow checker will require to -// clone all parameters outside of the closure. -fn get_cache_helper<'a, Block: BlockT>( - cache_at: &'a mut HashMap, self::list_storage::DbStorage>>, - name: CacheKeyId, - db: &Arc>, - key_lookup: u32, - header: u32, - cache: u32, - best_finalized_block: &ComplexBlockId, -) -> ClientResult<&'a mut ListCache, self::list_storage::DbStorage>> { - match cache_at.entry(name) { - Entry::Occupied(entry) => Ok(entry.into_mut()), - Entry::Vacant(entry) => { - let cache = ListCache::new( - self::list_storage::DbStorage::new( - name.to_vec(), - db.clone(), - self::list_storage::DbColumns { meta: COLUMN_META, key_lookup, header, cache }, - ), - cache_pruning_strategy(name), - best_finalized_block.clone(), - )?; - Ok(entry.insert(cache)) - }, - } -} - -/// Cache operations that are to be committed after database transaction is committed. -#[derive(Default)] -pub struct DbCacheTransactionOps { - cache_at_ops: HashMap>>, - best_finalized_block: Option>, -} - -impl DbCacheTransactionOps { - /// Empty transaction ops. - pub fn empty() -> DbCacheTransactionOps { - DbCacheTransactionOps { cache_at_ops: HashMap::new(), best_finalized_block: None } - } -} - -/// Database-backed blockchain data cache transaction valid for single block import. -pub struct DbCacheTransaction<'a, Block: BlockT> { - cache: &'a mut DbCache, - tx: &'a mut Transaction, - cache_at_ops: HashMap>>, - best_finalized_block: Option>, -} - -impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> { - /// Convert transaction into post-commit operations set. - pub fn into_ops(self) -> DbCacheTransactionOps { - DbCacheTransactionOps { - cache_at_ops: self.cache_at_ops, - best_finalized_block: self.best_finalized_block, - } - } - - /// When new block is inserted into database. - pub fn on_block_insert( - mut self, - parent: ComplexBlockId, - block: ComplexBlockId, - data_at: HashMap>, - entry_type: EntryType, - ) -> ClientResult { - // prepare list of caches that are not update - // (we might still need to do some cache maintenance in this case) - let missed_caches = self - .cache - .cache_at - .keys() - .filter(|cache| !data_at.contains_key(*cache)) - .cloned() - .collect::>(); - - let mut insert_op = |name: CacheKeyId, - value: Option>| - -> Result<(), sp_blockchain::Error> { - let cache = self.cache.get_cache(name)?; - let cache_ops = self.cache_at_ops.entry(name).or_default(); - cache.on_block_insert( - &mut self::list_storage::DbStorageTransaction::new(cache.storage(), &mut self.tx), - parent.clone(), - block.clone(), - value, - entry_type, - cache_ops, - )?; - - Ok(()) - }; - - data_at.into_iter().try_for_each(|(name, data)| insert_op(name, Some(data)))?; - missed_caches.into_iter().try_for_each(|name| insert_op(name, None))?; - - match entry_type { - EntryType::Final | EntryType::Genesis => self.best_finalized_block = Some(block), - EntryType::NonFinal => (), - } - - Ok(self) - } - - /// When previously inserted block is finalized. - pub fn on_block_finalize( - mut self, - parent: ComplexBlockId, - block: ComplexBlockId, - ) -> ClientResult { - for (name, cache) in self.cache.cache_at.iter() { - let cache_ops = self.cache_at_ops.entry(*name).or_default(); - cache.on_block_finalize( - &mut self::list_storage::DbStorageTransaction::new(cache.storage(), &mut self.tx), - parent.clone(), - block.clone(), - cache_ops, - )?; - } - - self.best_finalized_block = Some(block); - - Ok(self) - } - - /// When block is reverted. - pub fn on_block_revert(mut self, reverted_block: &ComplexBlockId) -> ClientResult { - for (name, cache) in self.cache.cache_at.iter() { - let cache_ops = self.cache_at_ops.entry(*name).or_default(); - cache.on_block_revert( - &mut self::list_storage::DbStorageTransaction::new(cache.storage(), &mut self.tx), - reverted_block, - cache_ops, - )?; - } - - Ok(self) - } -} - -/// Synchronous implementation of database-backed blockchain data cache. -pub struct DbCacheSync(pub RwLock>); - -impl BlockchainCache for DbCacheSync { - fn initialize(&self, key: &CacheKeyId, data: Vec) -> ClientResult<()> { - let mut cache = self.0.write(); - let genesis_hash = cache.genesis_hash; - let cache_contents = vec![(*key, data)].into_iter().collect(); - let db = cache.db.clone(); - let mut dbtx = Transaction::new(); - let tx = cache.transaction(&mut dbtx); - let tx = tx.on_block_insert( - ComplexBlockId::new(Default::default(), Zero::zero()), - ComplexBlockId::new(genesis_hash, Zero::zero()), - cache_contents, - EntryType::Genesis, - )?; - let tx_ops = tx.into_ops(); - db.commit(dbtx)?; - cache.commit(tx_ops)?; - - Ok(()) - } - - fn get_at( - &self, - key: &CacheKeyId, - at: &BlockId, - ) -> ClientResult< - Option<((NumberFor, Block::Hash), Option<(NumberFor, Block::Hash)>, Vec)>, - > { - let mut cache = self.0.write(); - let header_metadata_cache = cache.header_metadata_cache.clone(); - let cache = cache.get_cache(*key)?; - let storage = cache.storage(); - let db = storage.db(); - let columns = storage.columns(); - let at = match *at { - BlockId::Hash(hash) => match header_metadata_cache.header_metadata(hash) { - Some(metadata) => ComplexBlockId::new(hash, metadata.number), - None => { - let header = utils::require_header::( - &**db, - columns.key_lookup, - columns.header, - BlockId::Hash(hash.clone()), - )?; - ComplexBlockId::new(hash, *header.number()) - }, - }, - BlockId::Number(number) => { - let hash = utils::require_header::( - &**db, - columns.key_lookup, - columns.header, - BlockId::Number(number.clone()), - )? - .hash(); - ComplexBlockId::new(hash, number) - }, - }; - - cache.value_at_block(&at).map(|block_and_value| { - block_and_value.map(|(begin_block, end_block, value)| { - ( - (begin_block.number, begin_block.hash), - end_block.map(|end_block| (end_block.number, end_block.hash)), - value, - ) - }) - }) - } -} - -/// Get pruning strategy for given cache. -fn cache_pruning_strategy>(cache: CacheKeyId) -> PruningStrategy { - // the cache is mostly used to store data from consensus engines - // this kind of data is only required for non-finalized blocks - // => by default we prune finalized cached entries - - match cache { - // we need to keep changes tries configurations forever (or at least until changes tries, - // that were built using this configuration, are pruned) to make it possible to refer - // to old changes tries - well_known_cache_keys::CHANGES_TRIE_CONFIG => PruningStrategy::NeverPrune, - _ => PruningStrategy::ByDepth(PRUNE_DEPTH.into()), - } -} diff --git a/client/db/src/changes_tries_storage.rs b/client/db/src/changes_tries_storage.rs deleted file mode 100644 index 3a3c5918535f9..0000000000000 --- a/client/db/src/changes_tries_storage.rs +++ /dev/null @@ -1,1168 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! DB-backed changes tries storage. - -use crate::{ - cache::{ - ComplexBlockId, DbCache, DbCacheSync, DbCacheTransactionOps, EntryType as CacheEntryType, - }, - utils::{self, meta_keys, Meta}, - Database, DbHash, -}; -use codec::{Decode, Encode}; -use hash_db::Prefix; -use parking_lot::RwLock; -use sc_client_api::backend::PrunableStateChangesTrieStorage; -use sp_blockchain::{ - well_known_cache_keys, Cache as BlockchainCache, Error as ClientError, HeaderMetadataCache, - Result as ClientResult, -}; -use sp_core::{ - convert_hash, storage::PrefixedStorageKey, ChangesTrieConfiguration, - ChangesTrieConfigurationRange, -}; -use sp_database::Transaction; -use sp_runtime::{ - generic::{BlockId, ChangesTrieSignal, DigestItem}, - traits::{Block as BlockT, CheckedSub, HashFor, Header as HeaderT, NumberFor, One, Zero}, -}; -use sp_state_machine::{ChangesTrieBuildCache, ChangesTrieCacheAction}; -use sp_trie::MemoryDB; -use std::{ - collections::{HashMap, HashSet}, - sync::Arc, -}; - -/// Extract new changes trie configuration (if available) from the header. -pub fn extract_new_configuration( - header: &Header, -) -> Option<&Option> { - header - .digest() - .log(DigestItem::as_changes_trie_signal) - .and_then(ChangesTrieSignal::as_new_configuration) -} - -/// Opaque configuration cache transaction. During its lifetime, no-one should modify cache. This is -/// currently guaranteed because import lock is held during block import/finalization. -pub struct DbChangesTrieStorageTransaction { - /// Cache operations that must be performed after db transaction is committed. - cache_ops: DbCacheTransactionOps, - /// New configuration (if changed at current block). - new_config: Option>, -} - -impl DbChangesTrieStorageTransaction { - /// Consume self and return transaction with given new configuration. - pub fn with_new_config(mut self, new_config: Option>) -> Self { - self.new_config = new_config; - self - } -} - -impl From> for DbChangesTrieStorageTransaction { - fn from(cache_ops: DbCacheTransactionOps) -> Self { - DbChangesTrieStorageTransaction { cache_ops, new_config: None } - } -} - -/// Changes tries storage. -/// -/// Stores all tries in separate DB column. -/// Lock order: meta, tries_meta, cache, build_cache. -pub struct DbChangesTrieStorage { - db: Arc>, - meta_column: u32, - changes_tries_column: u32, - key_lookup_column: u32, - header_column: u32, - meta: Arc, Block::Hash>>>, - tries_meta: RwLock>, - min_blocks_to_keep: Option, - /// The cache stores all ever existing changes tries configurations. - cache: DbCacheSync, - /// Build cache is a map of block => set of storage keys changed at this block. - /// They're used to build digest blocks - instead of reading+parsing tries from db - /// we just use keys sets from the cache. - build_cache: RwLock>>, -} - -/// Persistent struct that contains all the changes tries metadata. -#[derive(Decode, Encode, Debug)] -struct ChangesTriesMeta { - /// Oldest unpruned max-level (or skewed) digest trie blocks range. - /// The range is inclusive from both sides. - /// Is None only if: - /// 1) we haven't yet finalized any blocks (except genesis) - /// 2) if best_finalized_block - min_blocks_to_keep points to the range where changes tries are - /// disabled 3) changes tries pruning is disabled - pub oldest_digest_range: Option<(NumberFor, NumberFor)>, - /// End block (inclusive) of oldest pruned max-level (or skewed) digest trie blocks range. - /// It is guaranteed that we have no any changes tries before (and including) this block. - /// It is guaranteed that all existing changes tries after this block are not yet pruned (if - /// created). - pub oldest_pruned_digest_range_end: NumberFor, -} - -impl DbChangesTrieStorage { - /// Create new changes trie storage. - pub fn new( - db: Arc>, - header_metadata_cache: Arc>, - meta_column: u32, - changes_tries_column: u32, - key_lookup_column: u32, - header_column: u32, - cache_column: u32, - meta: Arc, Block::Hash>>>, - min_blocks_to_keep: Option, - ) -> ClientResult { - let (finalized_hash, finalized_number, genesis_hash) = { - let meta = meta.read(); - (meta.finalized_hash, meta.finalized_number, meta.genesis_hash) - }; - let tries_meta = read_tries_meta(&*db, meta_column)?; - Ok(Self { - db: db.clone(), - meta_column, - changes_tries_column, - key_lookup_column, - header_column, - meta, - min_blocks_to_keep, - cache: DbCacheSync(RwLock::new(DbCache::new( - db.clone(), - header_metadata_cache, - key_lookup_column, - header_column, - cache_column, - genesis_hash, - ComplexBlockId::new(finalized_hash, finalized_number), - ))), - build_cache: RwLock::new(ChangesTrieBuildCache::new()), - tries_meta: RwLock::new(tries_meta), - }) - } - - /// Commit new changes trie. - pub fn commit( - &self, - tx: &mut Transaction, - mut changes_trie: MemoryDB>, - parent_block: ComplexBlockId, - block: ComplexBlockId, - new_header: &Block::Header, - finalized: bool, - new_configuration: Option>, - cache_tx: Option>, - ) -> ClientResult> { - // insert changes trie, associated with block, into DB - for (key, (val, _)) in changes_trie.drain() { - tx.set(self.changes_tries_column, key.as_ref(), &val); - } - - // if configuration has not been changed AND block is not finalized => nothing to do here - let new_configuration = match new_configuration { - Some(new_configuration) => new_configuration, - None if !finalized => return Ok(DbCacheTransactionOps::empty().into()), - None => - return self.finalize( - tx, - parent_block.hash, - block.hash, - block.number, - Some(new_header), - cache_tx, - ), - }; - - // update configuration cache - let mut cache_at = HashMap::new(); - cache_at.insert(well_known_cache_keys::CHANGES_TRIE_CONFIG, new_configuration.encode()); - Ok(DbChangesTrieStorageTransaction::from(match cache_tx { - Some(cache_tx) => self - .cache - .0 - .write() - .transaction_with_ops(tx, cache_tx.cache_ops) - .on_block_insert( - parent_block, - block, - cache_at, - if finalized { CacheEntryType::Final } else { CacheEntryType::NonFinal }, - )? - .into_ops(), - None => self - .cache - .0 - .write() - .transaction(tx) - .on_block_insert( - parent_block, - block, - cache_at, - if finalized { CacheEntryType::Final } else { CacheEntryType::NonFinal }, - )? - .into_ops(), - }) - .with_new_config(Some(new_configuration))) - } - - /// Called when block is finalized. - pub fn finalize( - &self, - tx: &mut Transaction, - parent_block_hash: Block::Hash, - block_hash: Block::Hash, - block_num: NumberFor, - new_header: Option<&Block::Header>, - cache_tx: Option>, - ) -> ClientResult> { - // prune obsolete changes tries - self.prune(tx, block_hash, block_num, new_header.clone(), cache_tx.as_ref())?; - - // if we have inserted the block that we're finalizing in the same transaction - // => then we have already finalized it from the commit() call - if cache_tx.is_some() { - if let Some(new_header) = new_header { - if new_header.hash() == block_hash { - return Ok(cache_tx.expect("guarded by cache_tx.is_some(); qed")) - } - } - } - - // and finalize configuration cache entries - let block = ComplexBlockId::new(block_hash, block_num); - let parent_block_num = block_num.checked_sub(&One::one()).unwrap_or_else(|| Zero::zero()); - let parent_block = ComplexBlockId::new(parent_block_hash, parent_block_num); - Ok(match cache_tx { - Some(cache_tx) => DbChangesTrieStorageTransaction::from( - self.cache - .0 - .write() - .transaction_with_ops(tx, cache_tx.cache_ops) - .on_block_finalize(parent_block, block)? - .into_ops(), - ) - .with_new_config(cache_tx.new_config), - None => DbChangesTrieStorageTransaction::from( - self.cache - .0 - .write() - .transaction(tx) - .on_block_finalize(parent_block, block)? - .into_ops(), - ), - }) - } - - /// When block is reverted. - pub fn revert( - &self, - tx: &mut Transaction, - block: &ComplexBlockId, - ) -> ClientResult> { - Ok(self.cache.0.write().transaction(tx).on_block_revert(block)?.into_ops().into()) - } - - /// When transaction has been committed. - pub fn post_commit(&self, tx: Option>) { - if let Some(tx) = tx { - self.cache.0.write().commit(tx.cache_ops).expect( - "only fails if cache with given name isn't loaded yet; cache is already loaded \ - because there is tx; qed", - ); - } - } - - /// Commit changes into changes trie build cache. - pub fn commit_build_cache( - &self, - cache_update: ChangesTrieCacheAction>, - ) { - self.build_cache.write().perform(cache_update); - } - - /// Prune obsolete changes tries. - fn prune( - &self, - tx: &mut Transaction, - block_hash: Block::Hash, - block_num: NumberFor, - new_header: Option<&Block::Header>, - cache_tx: Option<&DbChangesTrieStorageTransaction>, - ) -> ClientResult<()> { - // never prune on archive nodes - let min_blocks_to_keep = match self.min_blocks_to_keep { - Some(min_blocks_to_keep) => min_blocks_to_keep, - None => return Ok(()), - }; - - let mut tries_meta = self.tries_meta.write(); - let mut next_digest_range_start = block_num; - loop { - // prune oldest digest if it is known - // it could be unknown if: - // 1) either we're finalizing block#1 - // 2) or we are (or were) in period where changes tries are disabled - if let Some((begin, end)) = tries_meta.oldest_digest_range { - if block_num <= end || block_num - end <= min_blocks_to_keep.into() { - break - } - - tries_meta.oldest_pruned_digest_range_end = end; - sp_state_machine::prune_changes_tries( - &*self, - begin, - end, - &sp_state_machine::ChangesTrieAnchorBlockId { - hash: convert_hash(&block_hash), - number: block_num, - }, - |node| tx.remove(self.changes_tries_column, node.as_ref()), - ); - - next_digest_range_start = end + One::one(); - } - - // proceed to the next configuration range - let next_digest_range_start_hash = match block_num == next_digest_range_start { - true => block_hash, - false => utils::require_header::( - &*self.db, - self.key_lookup_column, - self.header_column, - BlockId::Number(next_digest_range_start), - )? - .hash(), - }; - - let config_for_new_block = new_header - .map(|header| *header.number() == next_digest_range_start) - .unwrap_or(false); - let next_config = match cache_tx { - Some(cache_tx) if config_for_new_block && cache_tx.new_config.is_some() => { - let config = cache_tx.new_config.clone().expect("guarded by is_some(); qed"); - Ok(ChangesTrieConfigurationRange { - zero: (block_num, block_hash), - end: None, - config, - }) - }, - _ if config_for_new_block => self.configuration_at(&BlockId::Hash( - *new_header - .expect("config_for_new_block is only true when new_header is passed; qed") - .parent_hash(), - )), - _ => self.configuration_at(&BlockId::Hash(next_digest_range_start_hash)), - }; - let next_config = match next_config { - Ok(next_config) => next_config, - Err(ClientError::UnknownBlock(_)) => break, // No block means nothing to prune. - Err(e) => return Err(e), - }; - if let Some(config) = next_config.config { - let mut oldest_digest_range = config - .next_max_level_digest_range(next_config.zero.0, next_digest_range_start) - .unwrap_or_else(|| (next_digest_range_start, next_digest_range_start)); - - if let Some(end) = next_config.end { - if end.0 < oldest_digest_range.1 { - oldest_digest_range.1 = end.0; - } - } - - tries_meta.oldest_digest_range = Some(oldest_digest_range); - continue - } - - tries_meta.oldest_digest_range = None; - break - } - - write_tries_meta(tx, self.meta_column, &*tries_meta); - Ok(()) - } -} - -impl PrunableStateChangesTrieStorage for DbChangesTrieStorage { - fn storage( - &self, - ) -> &dyn sp_state_machine::ChangesTrieStorage, NumberFor> { - self - } - - fn configuration_at( - &self, - at: &BlockId, - ) -> ClientResult, Block::Hash>> { - self.cache - .get_at(&well_known_cache_keys::CHANGES_TRIE_CONFIG, at)? - .and_then(|(zero, end, encoded)| { - Decode::decode(&mut &encoded[..]) - .ok() - .map(|config| ChangesTrieConfigurationRange { zero, end, config }) - }) - .ok_or_else(|| ClientError::ErrorReadingChangesTriesConfig) - } - - fn oldest_pruned_digest_range_end(&self) -> NumberFor { - self.tries_meta.read().oldest_pruned_digest_range_end - } -} - -impl sp_state_machine::ChangesTrieRootsStorage, NumberFor> - for DbChangesTrieStorage -{ - fn build_anchor( - &self, - hash: Block::Hash, - ) -> Result>, String> { - utils::read_header::( - &*self.db, - self.key_lookup_column, - self.header_column, - BlockId::Hash(hash), - ) - .map_err(|e| e.to_string()) - .and_then(|maybe_header| { - maybe_header - .map(|header| sp_state_machine::ChangesTrieAnchorBlockId { - hash, - number: *header.number(), - }) - .ok_or_else(|| format!("Unknown header: {}", hash)) - }) - } - - fn root( - &self, - anchor: &sp_state_machine::ChangesTrieAnchorBlockId>, - block: NumberFor, - ) -> Result, String> { - // check API requirement: we can't get NEXT block(s) based on anchor - if block > anchor.number { - return Err(format!( - "Can't get changes trie root at {} using anchor at {}", - block, anchor.number - )) - } - - // we need to get hash of the block to resolve changes trie root - let block_id = if block <= self.meta.read().finalized_number { - // if block is finalized, we could just read canonical hash - BlockId::Number(block) - } else { - // the block is not finalized - let mut current_num = anchor.number; - let mut current_hash: Block::Hash = convert_hash(&anchor.hash); - let maybe_anchor_header: Block::Header = utils::require_header::( - &*self.db, - self.key_lookup_column, - self.header_column, - BlockId::Number(current_num), - ) - .map_err(|e| e.to_string())?; - if maybe_anchor_header.hash() == current_hash { - // if anchor is canonicalized, then the block is also canonicalized - BlockId::Number(block) - } else { - // else (block is not finalized + anchor is not canonicalized): - // => we should find the required block hash by traversing - // back from the anchor to the block with given number - while current_num != block { - let current_header: Block::Header = utils::require_header::( - &*self.db, - self.key_lookup_column, - self.header_column, - BlockId::Hash(current_hash), - ) - .map_err(|e| e.to_string())?; - - current_hash = *current_header.parent_hash(); - current_num = current_num - One::one(); - } - - BlockId::Hash(current_hash) - } - }; - - Ok(utils::require_header::( - &*self.db, - self.key_lookup_column, - self.header_column, - block_id, - ) - .map_err(|e| e.to_string())? - .digest() - .log(DigestItem::as_changes_trie_root) - .cloned()) - } -} - -impl sp_state_machine::ChangesTrieStorage, NumberFor> - for DbChangesTrieStorage -where - Block: BlockT, -{ - fn as_roots_storage( - &self, - ) -> &dyn sp_state_machine::ChangesTrieRootsStorage, NumberFor> { - self - } - - fn with_cached_changed_keys( - &self, - root: &Block::Hash, - functor: &mut dyn FnMut(&HashMap, HashSet>>), - ) -> bool { - self.build_cache.read().with_changed_keys(root, functor) - } - - fn get(&self, key: &Block::Hash, _prefix: Prefix) -> Result>, String> { - Ok(self.db.get(self.changes_tries_column, key.as_ref())) - } -} - -/// Read changes tries metadata from database. -fn read_tries_meta( - db: &dyn Database, - meta_column: u32, -) -> ClientResult> { - match db.get(meta_column, meta_keys::CHANGES_TRIES_META) { - Some(h) => Decode::decode(&mut &h[..]).map_err(|err| { - ClientError::Backend(format!("Error decoding changes tries metadata: {}", err)) - }), - None => Ok(ChangesTriesMeta { - oldest_digest_range: None, - oldest_pruned_digest_range_end: Zero::zero(), - }), - } -} - -/// Write changes tries metadata from database. -fn write_tries_meta( - tx: &mut Transaction, - meta_column: u32, - meta: &ChangesTriesMeta, -) { - tx.set_from_vec(meta_column, meta_keys::CHANGES_TRIES_META, meta.encode()); -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - tests::{insert_header, prepare_changes, Block}, - Backend, - }; - use hash_db::EMPTY_PREFIX; - use sc_client_api::backend::{ - Backend as ClientBackend, BlockImportOperation, NewBlockState, - PrunableStateChangesTrieStorage, - }; - use sp_blockchain::HeaderBackend as BlockchainHeaderBackend; - use sp_core::H256; - use sp_runtime::{ - testing::{Digest, Header}, - traits::{BlakeTwo256, Hash}, - }; - use sp_state_machine::{ChangesTrieRootsStorage, ChangesTrieStorage}; - - fn changes(number: u64) -> Option, Vec)>> { - Some(vec![(number.to_le_bytes().to_vec(), number.to_le_bytes().to_vec())]) - } - - fn insert_header_with_configuration_change( - backend: &Backend, - number: u64, - parent_hash: H256, - changes: Option, Vec)>>, - new_configuration: Option, - ) -> H256 { - let mut digest = Digest::default(); - let mut changes_trie_update = Default::default(); - if let Some(changes) = changes { - let (root, update) = prepare_changes(changes); - digest.push(DigestItem::ChangesTrieRoot(root)); - changes_trie_update = update; - } - digest.push(DigestItem::ChangesTrieSignal(ChangesTrieSignal::NewConfiguration( - new_configuration, - ))); - - let header = Header { - number, - parent_hash, - state_root: BlakeTwo256::trie_root(Vec::new()), - digest, - extrinsics_root: Default::default(), - }; - let header_hash = header.hash(); - - let block_id = if number == 0 { - BlockId::Hash(Default::default()) - } else { - BlockId::Number(number - 1) - }; - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, block_id).unwrap(); - op.set_block_data(header, None, None, None, NewBlockState::Best).unwrap(); - op.update_changes_trie((changes_trie_update, ChangesTrieCacheAction::Clear)) - .unwrap(); - backend.commit_operation(op).unwrap(); - - header_hash - } - - #[test] - fn changes_trie_storage_works() { - let backend = Backend::::new_test(1000, 100); - backend.changes_tries_storage.meta.write().finalized_number = 1000; - - let check_changes = |backend: &Backend, - block: u64, - changes: Vec<(Vec, Vec)>| { - let (changes_root, mut changes_trie_update) = prepare_changes(changes); - let anchor = sp_state_machine::ChangesTrieAnchorBlockId { - hash: backend.blockchain().header(BlockId::Number(block)).unwrap().unwrap().hash(), - number: block, - }; - assert_eq!(backend.changes_tries_storage.root(&anchor, block), Ok(Some(changes_root))); - - let storage = backend.changes_tries_storage.storage(); - for (key, (val, _)) in changes_trie_update.drain() { - assert_eq!(storage.get(&key, EMPTY_PREFIX), Ok(Some(val))); - } - }; - - let changes0 = vec![(b"key_at_0".to_vec(), b"val_at_0".to_vec())]; - let changes1 = vec![ - (b"key_at_1".to_vec(), b"val_at_1".to_vec()), - (b"another_key_at_1".to_vec(), b"another_val_at_1".to_vec()), - ]; - let changes2 = vec![(b"key_at_2".to_vec(), b"val_at_2".to_vec())]; - - let block0 = insert_header( - &backend, - 0, - Default::default(), - Some(changes0.clone()), - Default::default(), - ); - let block1 = insert_header(&backend, 1, block0, Some(changes1.clone()), Default::default()); - let _ = insert_header(&backend, 2, block1, Some(changes2.clone()), Default::default()); - - // check that the storage contains tries for all blocks - check_changes(&backend, 0, changes0); - check_changes(&backend, 1, changes1); - check_changes(&backend, 2, changes2); - } - - #[test] - fn changes_trie_storage_works_with_forks() { - let backend = Backend::::new_test(1000, 100); - - let changes0 = vec![(b"k0".to_vec(), b"v0".to_vec())]; - let changes1 = vec![(b"k1".to_vec(), b"v1".to_vec())]; - let changes2 = vec![(b"k2".to_vec(), b"v2".to_vec())]; - let block0 = insert_header( - &backend, - 0, - Default::default(), - Some(changes0.clone()), - Default::default(), - ); - let block1 = insert_header(&backend, 1, block0, Some(changes1.clone()), Default::default()); - let block2 = insert_header(&backend, 2, block1, Some(changes2.clone()), Default::default()); - - let changes2_1_0 = vec![(b"k3".to_vec(), b"v3".to_vec())]; - let changes2_1_1 = vec![(b"k4".to_vec(), b"v4".to_vec())]; - let block2_1_0 = - insert_header(&backend, 3, block2, Some(changes2_1_0.clone()), Default::default()); - let block2_1_1 = - insert_header(&backend, 4, block2_1_0, Some(changes2_1_1.clone()), Default::default()); - - let changes2_2_0 = vec![(b"k5".to_vec(), b"v5".to_vec())]; - let changes2_2_1 = vec![(b"k6".to_vec(), b"v6".to_vec())]; - let block2_2_0 = - insert_header(&backend, 3, block2, Some(changes2_2_0.clone()), Default::default()); - let block2_2_1 = - insert_header(&backend, 4, block2_2_0, Some(changes2_2_1.clone()), Default::default()); - - // finalize block1 - backend.changes_tries_storage.meta.write().finalized_number = 1; - - // branch1: when asking for finalized block hash - let (changes1_root, _) = prepare_changes(changes1); - let anchor = sp_state_machine::ChangesTrieAnchorBlockId { hash: block2_1_1, number: 4 }; - assert_eq!(backend.changes_tries_storage.root(&anchor, 1), Ok(Some(changes1_root))); - - // branch2: when asking for finalized block hash - let anchor = sp_state_machine::ChangesTrieAnchorBlockId { hash: block2_2_1, number: 4 }; - assert_eq!(backend.changes_tries_storage.root(&anchor, 1), Ok(Some(changes1_root))); - - // branch1: when asking for non-finalized block hash (search by traversal) - let (changes2_1_0_root, _) = prepare_changes(changes2_1_0); - let anchor = sp_state_machine::ChangesTrieAnchorBlockId { hash: block2_1_1, number: 4 }; - assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_1_0_root))); - - // branch2: when asking for non-finalized block hash (search using canonicalized hint) - let (changes2_2_0_root, _) = prepare_changes(changes2_2_0); - let anchor = sp_state_machine::ChangesTrieAnchorBlockId { hash: block2_2_1, number: 4 }; - assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_2_0_root))); - - // finalize first block of branch2 (block2_2_0) - backend.changes_tries_storage.meta.write().finalized_number = 3; - - // branch2: when asking for finalized block of this branch - assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_2_0_root))); - - // branch1: when asking for finalized block of other branch - // => result is incorrect (returned for the block of branch1), but this is expected, - // because the other fork is abandoned (forked before finalized header) - let anchor = sp_state_machine::ChangesTrieAnchorBlockId { hash: block2_1_1, number: 4 }; - assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_2_0_root))); - } - - #[test] - fn changes_tries_are_pruned_on_finalization() { - let mut backend = Backend::::new_test(1000, 100); - backend.changes_tries_storage.min_blocks_to_keep = Some(8); - - let parent_hash = |number| { - if number == 0 { - Default::default() - } else { - backend - .blockchain() - .header(BlockId::Number(number - 1)) - .unwrap() - .unwrap() - .hash() - } - }; - - let insert_regular_header = |with_changes, number| { - insert_header( - &backend, - number, - parent_hash(number), - if with_changes { changes(number) } else { None }, - Default::default(), - ); - }; - - let is_pruned = |number| { - let trie_root = backend - .blockchain() - .header(BlockId::Number(number)) - .unwrap() - .unwrap() - .digest() - .log(DigestItem::as_changes_trie_root) - .cloned(); - match trie_root { - Some(trie_root) => - backend.changes_tries_storage.get(&trie_root, EMPTY_PREFIX).unwrap().is_none(), - None => true, - } - }; - - let finalize_block = |number| { - let header = backend.blockchain().header(BlockId::Number(number)).unwrap().unwrap(); - let mut tx = Transaction::new(); - let cache_ops = backend - .changes_tries_storage - .finalize(&mut tx, *header.parent_hash(), header.hash(), number, None, None) - .unwrap(); - backend.storage.db.commit(tx).unwrap(); - backend.changes_tries_storage.post_commit(Some(cache_ops)); - }; - - // configuration ranges: - // (0; 6] - None - // [7; 17] - Some(2^2): D2 is built at #10, #14; SD is built at #17 - // [18; 21] - None - // [22; 32] - Some(8^1): D1 is built at #29; SD is built at #32 - // [33; ... - Some(1) - let config_at_6 = Some(ChangesTrieConfiguration::new(2, 2)); - let config_at_17 = None; - let config_at_21 = Some(ChangesTrieConfiguration::new(8, 1)); - let config_at_32 = Some(ChangesTrieConfiguration::new(1, 0)); - - (0..6).for_each(|number| insert_regular_header(false, number)); - insert_header_with_configuration_change(&backend, 6, parent_hash(6), None, config_at_6); - (7..17).for_each(|number| insert_regular_header(true, number)); - insert_header_with_configuration_change( - &backend, - 17, - parent_hash(17), - changes(17), - config_at_17, - ); - (18..21).for_each(|number| insert_regular_header(false, number)); - insert_header_with_configuration_change(&backend, 21, parent_hash(21), None, config_at_21); - (22..32).for_each(|number| insert_regular_header(true, number)); - insert_header_with_configuration_change( - &backend, - 32, - parent_hash(32), - changes(32), - config_at_32, - ); - (33..50).for_each(|number| insert_regular_header(true, number)); - - // when only genesis is finalized, nothing is pruned - (0..=6).for_each(|number| assert!(is_pruned(number))); - (7..=17).for_each(|number| assert!(!is_pruned(number))); - (18..=21).for_each(|number| assert!(is_pruned(number))); - (22..50).for_each(|number| assert!(!is_pruned(number))); - - // when blocks [1; 18] are finalized, nothing is pruned - (1..=18).for_each(|number| finalize_block(number)); - (0..=6).for_each(|number| assert!(is_pruned(number))); - (7..=17).for_each(|number| assert!(!is_pruned(number))); - (18..=21).for_each(|number| assert!(is_pruned(number))); - (22..50).for_each(|number| assert!(!is_pruned(number))); - - // when block 19 is finalized, changes tries for blocks [7; 10] are pruned - finalize_block(19); - (0..=10).for_each(|number| assert!(is_pruned(number))); - (11..=17).for_each(|number| assert!(!is_pruned(number))); - (18..=21).for_each(|number| assert!(is_pruned(number))); - (22..50).for_each(|number| assert!(!is_pruned(number))); - - // when blocks [20; 22] are finalized, nothing is pruned - (20..=22).for_each(|number| finalize_block(number)); - (0..=10).for_each(|number| assert!(is_pruned(number))); - (11..=17).for_each(|number| assert!(!is_pruned(number))); - (18..=21).for_each(|number| assert!(is_pruned(number))); - (22..50).for_each(|number| assert!(!is_pruned(number))); - - // when block 23 is finalized, changes tries for blocks [11; 14] are pruned - finalize_block(23); - (0..=14).for_each(|number| assert!(is_pruned(number))); - (15..=17).for_each(|number| assert!(!is_pruned(number))); - (18..=21).for_each(|number| assert!(is_pruned(number))); - (22..50).for_each(|number| assert!(!is_pruned(number))); - - // when blocks [24; 25] are finalized, nothing is pruned - (24..=25).for_each(|number| finalize_block(number)); - (0..=14).for_each(|number| assert!(is_pruned(number))); - (15..=17).for_each(|number| assert!(!is_pruned(number))); - (18..=21).for_each(|number| assert!(is_pruned(number))); - (22..50).for_each(|number| assert!(!is_pruned(number))); - - // when block 26 is finalized, changes tries for blocks [15; 17] are pruned - finalize_block(26); - (0..=21).for_each(|number| assert!(is_pruned(number))); - (22..50).for_each(|number| assert!(!is_pruned(number))); - - // when blocks [27; 37] are finalized, nothing is pruned - (27..=37).for_each(|number| finalize_block(number)); - (0..=21).for_each(|number| assert!(is_pruned(number))); - (22..50).for_each(|number| assert!(!is_pruned(number))); - - // when block 38 is finalized, changes tries for blocks [22; 29] are pruned - finalize_block(38); - (0..=29).for_each(|number| assert!(is_pruned(number))); - (30..50).for_each(|number| assert!(!is_pruned(number))); - - // when blocks [39; 40] are finalized, nothing is pruned - (39..=40).for_each(|number| finalize_block(number)); - (0..=29).for_each(|number| assert!(is_pruned(number))); - (30..50).for_each(|number| assert!(!is_pruned(number))); - - // when block 41 is finalized, changes tries for blocks [30; 32] are pruned - finalize_block(41); - (0..=32).for_each(|number| assert!(is_pruned(number))); - (33..50).for_each(|number| assert!(!is_pruned(number))); - - // when block 42 is finalized, changes trie for block 33 is pruned - finalize_block(42); - (0..=33).for_each(|number| assert!(is_pruned(number))); - (34..50).for_each(|number| assert!(!is_pruned(number))); - - // when block 43 is finalized, changes trie for block 34 is pruned - finalize_block(43); - (0..=34).for_each(|number| assert!(is_pruned(number))); - (35..50).for_each(|number| assert!(!is_pruned(number))); - } - - #[test] - fn changes_tries_configuration_is_updated_on_block_insert() { - let backend = Backend::::new_test(1000, 100); - - // configurations at blocks - let config_at_1 = Some(ChangesTrieConfiguration { digest_interval: 4, digest_levels: 2 }); - let config_at_3 = Some(ChangesTrieConfiguration { digest_interval: 8, digest_levels: 1 }); - let config_at_5 = None; - let config_at_7 = Some(ChangesTrieConfiguration { digest_interval: 8, digest_levels: 1 }); - - // insert some blocks - let block0 = insert_header(&backend, 0, Default::default(), None, Default::default()); - let block1 = - insert_header_with_configuration_change(&backend, 1, block0, None, config_at_1.clone()); - let block2 = insert_header(&backend, 2, block1, None, Default::default()); - let block3 = - insert_header_with_configuration_change(&backend, 3, block2, None, config_at_3.clone()); - let block4 = insert_header(&backend, 4, block3, None, Default::default()); - let block5 = - insert_header_with_configuration_change(&backend, 5, block4, None, config_at_5.clone()); - let block6 = insert_header(&backend, 6, block5, None, Default::default()); - let block7 = - insert_header_with_configuration_change(&backend, 7, block6, None, config_at_7.clone()); - - // test configuration cache - let storage = &backend.changes_tries_storage; - assert_eq!( - storage.configuration_at(&BlockId::Hash(block1)).unwrap().config, - config_at_1.clone(), - ); - assert_eq!( - storage.configuration_at(&BlockId::Hash(block2)).unwrap().config, - config_at_1.clone(), - ); - assert_eq!( - storage.configuration_at(&BlockId::Hash(block3)).unwrap().config, - config_at_3.clone(), - ); - assert_eq!( - storage.configuration_at(&BlockId::Hash(block4)).unwrap().config, - config_at_3.clone(), - ); - assert_eq!( - storage.configuration_at(&BlockId::Hash(block5)).unwrap().config, - config_at_5.clone(), - ); - assert_eq!( - storage.configuration_at(&BlockId::Hash(block6)).unwrap().config, - config_at_5.clone(), - ); - assert_eq!( - storage.configuration_at(&BlockId::Hash(block7)).unwrap().config, - config_at_7.clone(), - ); - } - - #[test] - fn test_finalize_several_configuration_change_blocks_in_single_operation() { - let mut backend = Backend::::new_test(10, 10); - backend.changes_tries_storage.min_blocks_to_keep = Some(8); - - let configs = - (0..=7).map(|i| Some(ChangesTrieConfiguration::new(2, i))).collect::>(); - - // insert unfinalized headers - let block0 = insert_header_with_configuration_change( - &backend, - 0, - Default::default(), - None, - configs[0].clone(), - ); - let block1 = insert_header_with_configuration_change( - &backend, - 1, - block0, - changes(1), - configs[1].clone(), - ); - let block2 = insert_header_with_configuration_change( - &backend, - 2, - block1, - changes(2), - configs[2].clone(), - ); - - let side_config2_1 = Some(ChangesTrieConfiguration::new(3, 2)); - let side_config2_2 = Some(ChangesTrieConfiguration::new(3, 3)); - let block2_1 = insert_header_with_configuration_change( - &backend, - 2, - block1, - changes(8), - side_config2_1.clone(), - ); - let _ = insert_header_with_configuration_change( - &backend, - 3, - block2_1, - changes(9), - side_config2_2.clone(), - ); - - // insert finalized header => 4 headers are finalized at once - let header3 = Header { - number: 3, - parent_hash: block2, - state_root: Default::default(), - digest: Digest { - logs: vec![DigestItem::ChangesTrieSignal(ChangesTrieSignal::NewConfiguration( - configs[3].clone(), - ))], - }, - extrinsics_root: Default::default(), - }; - let block3 = header3.hash(); - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(block2)).unwrap(); - op.mark_finalized(BlockId::Hash(block1), None).unwrap(); - op.mark_finalized(BlockId::Hash(block2), None).unwrap(); - op.set_block_data(header3, None, None, None, NewBlockState::Final).unwrap(); - backend.commit_operation(op).unwrap(); - - // insert more unfinalized headers - let block4 = insert_header_with_configuration_change( - &backend, - 4, - block3, - changes(4), - configs[4].clone(), - ); - let block5 = insert_header_with_configuration_change( - &backend, - 5, - block4, - changes(5), - configs[5].clone(), - ); - let block6 = insert_header_with_configuration_change( - &backend, - 6, - block5, - changes(6), - configs[6].clone(), - ); - - // insert finalized header => 4 headers are finalized at once - let header7 = Header { - number: 7, - parent_hash: block6, - state_root: Default::default(), - digest: Digest { - logs: vec![DigestItem::ChangesTrieSignal(ChangesTrieSignal::NewConfiguration( - configs[7].clone(), - ))], - }, - extrinsics_root: Default::default(), - }; - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(block6)).unwrap(); - op.mark_finalized(BlockId::Hash(block4), None).unwrap(); - op.mark_finalized(BlockId::Hash(block5), None).unwrap(); - op.mark_finalized(BlockId::Hash(block6), None).unwrap(); - op.set_block_data(header7, None, None, None, NewBlockState::Final).unwrap(); - backend.commit_operation(op).unwrap(); - } - - #[test] - fn changes_tries_configuration_is_reverted() { - let backend = Backend::::new_test(10, 10); - - let config0 = Some(ChangesTrieConfiguration::new(2, 5)); - let block0 = - insert_header_with_configuration_change(&backend, 0, Default::default(), None, config0); - let config1 = Some(ChangesTrieConfiguration::new(2, 6)); - let block1 = - insert_header_with_configuration_change(&backend, 1, block0, changes(0), config1); - let just1 = Some((*b"TEST", vec![42])); - backend.finalize_block(BlockId::Number(1), just1).unwrap(); - let config2 = Some(ChangesTrieConfiguration::new(2, 7)); - let block2 = - insert_header_with_configuration_change(&backend, 2, block1, changes(1), config2); - let config2_1 = Some(ChangesTrieConfiguration::new(2, 8)); - let _ = - insert_header_with_configuration_change(&backend, 3, block2, changes(10), config2_1); - let config2_2 = Some(ChangesTrieConfiguration::new(2, 9)); - let block2_2 = - insert_header_with_configuration_change(&backend, 3, block2, changes(20), config2_2); - let config2_3 = Some(ChangesTrieConfiguration::new(2, 10)); - let _ = - insert_header_with_configuration_change(&backend, 4, block2_2, changes(30), config2_3); - - // before truncate there are 2 unfinalized forks - block2_1+block2_3 - assert_eq!( - backend - .changes_tries_storage - .cache - .0 - .write() - .get_cache(well_known_cache_keys::CHANGES_TRIE_CONFIG) - .unwrap() - .unfinalized() - .iter() - .map(|fork| fork.head().valid_from.number) - .collect::>(), - vec![3, 4], - ); - - // after truncating block2_3 - there are 2 unfinalized forks - block2_1+block2_2 - backend.revert(1, false).unwrap(); - assert_eq!( - backend - .changes_tries_storage - .cache - .0 - .write() - .get_cache(well_known_cache_keys::CHANGES_TRIE_CONFIG) - .unwrap() - .unfinalized() - .iter() - .map(|fork| fork.head().valid_from.number) - .collect::>(), - vec![3, 3], - ); - - // after truncating block2_1 && block2_2 - there are still two unfinalized forks (cache impl - // specifics), the 1st one points to the block #3 because it isn't truncated - backend.revert(1, false).unwrap(); - assert_eq!( - backend - .changes_tries_storage - .cache - .0 - .write() - .get_cache(well_known_cache_keys::CHANGES_TRIE_CONFIG) - .unwrap() - .unfinalized() - .iter() - .map(|fork| fork.head().valid_from.number) - .collect::>(), - vec![3, 2], - ); - - // after truncating block2 - there are no unfinalized forks - backend.revert(1, false).unwrap(); - assert!(backend - .changes_tries_storage - .cache - .0 - .write() - .get_cache(well_known_cache_keys::CHANGES_TRIE_CONFIG) - .unwrap() - .unfinalized() - .iter() - .map(|fork| fork.head().valid_from.number) - .collect::>() - .is_empty(),); - } -} diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 3b8936c0f7bac..7d46b63da5bb4 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -28,14 +28,11 @@ #![warn(missing_docs)] -pub mod light; pub mod offchain; #[cfg(any(feature = "with-kvdb-rocksdb", test))] pub mod bench; -mod cache; -mod changes_tries_storage; mod children; #[cfg(feature = "with-parity-db")] mod parity_db; @@ -56,7 +53,6 @@ use std::{ }; use crate::{ - changes_tries_storage::{DbChangesTrieStorage, DbChangesTrieStorageTransaction}, stats::StateUsageStats, storage_cache::{new_shared_cache, CachingState, SharedCache, SyncingCachingState}, utils::{meta_keys, read_db, read_meta, DatabaseType, Meta}, @@ -64,8 +60,7 @@ use crate::{ use codec::{Decode, Encode}; use hash_db::Prefix; use sc_client_api::{ - backend::{NewBlockState, ProvideChtRoots, PrunableStateChangesTrieStorage}, - cht, + backend::NewBlockState, leaves::{FinalizationDisplaced, LeafSet}, utils::is_descendent_of, IoInfo, MemoryInfo, MemorySize, UsageInfo, @@ -79,11 +74,10 @@ use sp_blockchain::{ use sp_core::{ offchain::OffchainOverlayedChange, storage::{well_known_keys, ChildInfo}, - ChangesTrieConfiguration, }; use sp_database::Transaction; use sp_runtime::{ - generic::{BlockId, DigestItem}, + generic::BlockId, traits::{ Block as BlockT, Hash, HashFor, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero, @@ -91,9 +85,8 @@ use sp_runtime::{ Justification, Justifications, Storage, }; use sp_state_machine::{ - backend::Backend as StateBackend, ChangesTrieCacheAction, ChangesTrieTransaction, - ChildStorageCollection, DBValue, IndexOperation, OffchainChangesCollection, StateMachineStats, - StorageCollection, UsageInfo as StateUsageInfo, + backend::Backend as StateBackend, ChildStorageCollection, DBValue, IndexOperation, + OffchainChangesCollection, StateMachineStats, StorageCollection, UsageInfo as StateUsageInfo, }; use sp_trie::{prefixed_key, MemoryDB, PrefixedMemoryDB}; @@ -104,7 +97,6 @@ pub use sp_database::Database; #[cfg(any(feature = "with-kvdb-rocksdb", test))] pub use bench::BenchmarkingState; -const MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR: u32 = 32768; const CACHE_HEADERS: usize = 8; /// Default value for storage cache child ratio. @@ -406,11 +398,9 @@ pub(crate) mod columns { pub const HEADER: u32 = 4; pub const BODY: u32 = 5; pub const JUSTIFICATIONS: u32 = 6; - pub const CHANGES_TRIE: u32 = 7; pub const AUX: u32 = 8; /// Offchain workers local storage pub const OFFCHAIN: u32 = 9; - pub const CACHE: u32 = 10; /// Transactions pub const TRANSACTION: u32 = 11; } @@ -506,13 +496,6 @@ impl BlockchainDb { let mut meta = self.meta.write(); meta.block_gap = gap; } - - // Get block changes trie root, if available. - fn changes_trie_root(&self, block: BlockId) -> ClientResult> { - self.header(block).map(|header| { - header.and_then(|header| header.digest().log(DigestItem::as_changes_trie_root).cloned()) - }) - } } impl sc_client_api::blockchain::HeaderBackend for BlockchainDb { @@ -646,10 +629,6 @@ impl sc_client_api::blockchain::Backend for BlockchainDb Option>> { - None - } - fn leaves(&self) -> ClientResult> { Ok(self.leaves.read().hashes()) } @@ -702,12 +681,6 @@ impl sc_client_api::blockchain::Backend for BlockchainDb sc_client_api::blockchain::ProvideCache for BlockchainDb { - fn cache(&self) -> Option>> { - None - } -} - impl HeaderMetadata for BlockchainDb { type Error = sp_blockchain::Error; @@ -745,62 +718,6 @@ impl HeaderMetadata for BlockchainDb { } } -impl ProvideChtRoots for BlockchainDb { - fn header_cht_root( - &self, - cht_size: NumberFor, - block: NumberFor, - ) -> sp_blockchain::Result> { - let cht_number = match cht::block_to_cht_number(cht_size, block) { - Some(number) => number, - None => return Ok(None), - }; - - let cht_start: NumberFor = cht::start_number(cht::size(), cht_number); - - let mut current_num = cht_start; - let cht_range = ::std::iter::from_fn(|| { - let old_current_num = current_num; - current_num = current_num + One::one(); - Some(old_current_num) - }); - - cht::compute_root::, _>( - cht::size(), - cht_number, - cht_range.map(|num| self.hash(num)), - ) - .map(Some) - } - - fn changes_trie_cht_root( - &self, - cht_size: NumberFor, - block: NumberFor, - ) -> sp_blockchain::Result> { - let cht_number = match cht::block_to_cht_number(cht_size, block) { - Some(number) => number, - None => return Ok(None), - }; - - let cht_start: NumberFor = cht::start_number(cht::size(), cht_number); - - let mut current_num = cht_start; - let cht_range = ::std::iter::from_fn(|| { - let old_current_num = current_num; - current_num = current_num + One::one(); - Some(old_current_num) - }); - - cht::compute_root::, _>( - cht::size(), - cht_number, - cht_range.map(|num| self.changes_trie_root(BlockId::Number(num))), - ) - .map(Some) - } -} - /// Database transaction pub struct BlockImportOperation { old_state: SyncingCachingState, Block>, @@ -808,9 +725,6 @@ pub struct BlockImportOperation { storage_updates: StorageCollection, child_storage_updates: ChildStorageCollection, offchain_storage_updates: OffchainChangesCollection, - changes_trie_updates: MemoryDB>, - changes_trie_build_cache_update: Option>>, - changes_trie_config_update: Option>, pending_block: Option>, aux_ops: Vec<(Vec, Option>)>, finalized_blocks: Vec<(BlockId, Option)>, @@ -858,25 +772,12 @@ impl BlockImportOperation { ) }); - let mut changes_trie_config = None; let (root, transaction) = self.old_state.full_storage_root( - storage.top.iter().map(|(k, v)| { - if &k[..] == well_known_keys::CHANGES_TRIE_CONFIG { - changes_trie_config = Some(Decode::decode(&mut &v[..])); - } - (&k[..], Some(&v[..])) - }), + storage.top.iter().map(|(k, v)| (&k[..], Some(&v[..]))), child_delta, ); - let changes_trie_config = match changes_trie_config { - Some(Ok(c)) => Some(c), - Some(Err(_)) => return Err(sp_blockchain::Error::InvalidState.into()), - None => None, - }; - self.db_updates = transaction; - self.changes_trie_config_update = Some(changes_trie_config); Ok(root) } } @@ -899,11 +800,6 @@ impl sc_client_api::backend::BlockImportOperation leaf_state: NewBlockState, ) -> ClientResult<()> { assert!(self.pending_block.is_none(), "Only one block per operation is allowed"); - if let Some(changes_trie_config_update) = - changes_tries_storage::extract_new_configuration(&header) - { - self.changes_trie_config_update = Some(changes_trie_config_update.clone()); - } self.pending_block = Some(PendingBlock { header, body, indexed_body, justifications, leaf_state }); Ok(()) @@ -930,15 +826,6 @@ impl sc_client_api::backend::BlockImportOperation Ok(root) } - fn update_changes_trie( - &mut self, - update: ChangesTrieTransaction, NumberFor>, - ) -> ClientResult<()> { - self.changes_trie_updates = update.0; - self.changes_trie_build_cache_update = Some(update.1); - Ok(()) - } - fn insert_aux(&mut self, ops: I) -> ClientResult<()> where I: IntoIterator, Option>)>, @@ -1095,7 +982,6 @@ impl FrozenForDuration { pub struct Backend { storage: Arc>, offchain_storage: offchain::LocalStorage, - changes_tries_storage: DbChangesTrieStorage, blockchain: BlockchainDb, canonicalization_delay: u64, shared_cache: SharedCache, @@ -1155,7 +1041,6 @@ impl Backend { ) -> ClientResult { let is_archive_pruning = config.state_pruning.is_archive(); let blockchain = BlockchainDb::new(db.clone(), config.transaction_storage.clone())?; - let meta = blockchain.meta.clone(); let map_e = |e: sc_state_db::Error| sp_blockchain::Error::from_state_db(e); let state_db: StateDb<_, _> = StateDb::new( config.state_pruning.clone(), @@ -1166,22 +1051,10 @@ impl Backend { let storage_db = StorageDb { db: db.clone(), state_db, prefix_keys: !db.supports_ref_counting() }; let offchain_storage = offchain::LocalStorage::new(db.clone()); - let changes_tries_storage = DbChangesTrieStorage::new( - db, - blockchain.header_metadata_cache.clone(), - columns::META, - columns::CHANGES_TRIE, - columns::KEY_LOOKUP, - columns::HEADER, - columns::CACHE, - meta, - if is_archive_pruning { None } else { Some(MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR) }, - )?; let backend = Backend { storage: Arc::new(storage_db), offchain_storage, - changes_tries_storage, blockchain, canonicalization_delay, shared_cache: new_shared_cache( @@ -1318,7 +1191,6 @@ impl Backend { header: &Block::Header, last_finalized: Option, justification: Option, - changes_trie_cache_ops: &mut Option>, finalization_displaced: &mut Option>>, ) -> ClientResult> { // TODO: ensure best chain contains this block. @@ -1326,15 +1198,7 @@ impl Backend { self.ensure_sequential_finalization(header, last_finalized)?; let with_state = sc_client_api::Backend::have_state_at(self, &hash, number); - self.note_finalized( - transaction, - false, - header, - *hash, - changes_trie_cache_ops, - finalization_displaced, - with_state, - )?; + self.note_finalized(transaction, header, *hash, finalization_displaced, with_state)?; if let Some(justification) = justification { transaction.set_from_vec( @@ -1400,7 +1264,6 @@ impl Backend { (meta.best_number, meta.finalized_hash, meta.finalized_number, meta.block_gap.clone()) }; - let mut changes_trie_cache_ops = None; for (block, justification) in operation.finalized_blocks { let block_hash = self.blockchain.expect_block_hash_from_id(&block)?; let block_header = self.blockchain.expect_header(BlockId::Hash(block_hash))?; @@ -1410,7 +1273,6 @@ impl Backend { &block_header, Some(last_finalized_hash), justification, - &mut changes_trie_cache_ops, &mut finalization_displaced_leaves, )?); last_finalized_hash = block_hash; @@ -1475,11 +1337,6 @@ impl Backend { ); transaction.set(columns::META, meta_keys::GENESIS_HASH, hash.as_ref()); - // for tests, because config is set from within the reset_storage - if operation.changes_trie_config_update.is_none() { - operation.changes_trie_config_update = Some(None); - } - if operation.commit_state { transaction.set_from_vec(columns::META, meta_keys::FINALIZED_STATE, lookup_key); } else { @@ -1578,7 +1435,6 @@ impl Backend { let header = &pending_block.header; let is_best = pending_block.leaf_state.is_best(); - let changes_trie_updates = operation.changes_trie_updates; debug!(target: "db", "DB Commit {:?} ({}), best={}, state={}, existing={}", hash, number, is_best, operation.commit_state, existing_header, @@ -1593,10 +1449,8 @@ impl Backend { self.ensure_sequential_finalization(header, Some(last_finalized_hash))?; self.note_finalized( &mut transaction, - true, header, hash, - &mut changes_trie_cache_ops, &mut finalization_displaced_leaves, operation.commit_state, )?; @@ -1606,21 +1460,6 @@ impl Backend { } if !existing_header { - let changes_trie_config_update = operation.changes_trie_config_update; - changes_trie_cache_ops = Some(self.changes_tries_storage.commit( - &mut transaction, - changes_trie_updates, - cache::ComplexBlockId::new( - *header.parent_hash(), - if number.is_zero() { Zero::zero() } else { number - One::one() }, - ), - cache::ComplexBlockId::new(hash, number), - header, - finalized, - changes_trie_config_update, - changes_trie_cache_ops, - )?); - { let mut leaves = self.blockchain.leaves.write(); leaves.import(hash, number, parent_hash); @@ -1747,11 +1586,6 @@ impl Backend { ); } - if let Some(changes_trie_build_cache_update) = operation.changes_trie_build_cache_update { - self.changes_tries_storage.commit_build_cache(changes_trie_build_cache_update); - } - self.changes_tries_storage.post_commit(changes_trie_cache_ops); - if let Some((enacted, retracted)) = cache_update { self.shared_cache.write().sync(&enacted, &retracted); } @@ -1770,10 +1604,8 @@ impl Backend { fn note_finalized( &self, transaction: &mut Transaction, - is_inserted: bool, f_header: &Block::Header, f_hash: Block::Hash, - changes_trie_cache_ops: &mut Option>, displaced: &mut Option>>, with_state: bool, ) -> ClientResult<()> { @@ -1798,18 +1630,6 @@ impl Backend { apply_state_commit(transaction, commit); } - if !f_num.is_zero() { - let new_changes_trie_cache_ops = self.changes_tries_storage.finalize( - transaction, - *f_header.parent_hash(), - f_hash, - f_num, - if is_inserted { Some(&f_header) } else { None }, - changes_trie_cache_ops.take(), - )?; - *changes_trie_cache_ops = Some(new_changes_trie_cache_ops); - } - let new_displaced = self.blockchain.leaves.write().finalize_height(f_num); self.prune_blocks(transaction, f_num, &new_displaced)?; match displaced { @@ -2036,9 +1856,6 @@ impl sc_client_api::backend::Backend for Backend { storage_updates: Default::default(), child_storage_updates: Default::default(), offchain_storage_updates: Default::default(), - changes_trie_config_update: None, - changes_trie_updates: MemoryDB::default(), - changes_trie_build_cache_update: None, aux_ops: Vec::new(), finalized_blocks: Vec::new(), set_head: None, @@ -2089,19 +1906,16 @@ impl sc_client_api::backend::Backend for Backend { let header = self.blockchain.expect_header(block)?; let mut displaced = None; - let mut changes_trie_cache_ops = None; let m = self.finalize_block_with_transaction( &mut transaction, &hash, &header, None, justification, - &mut changes_trie_cache_ops, &mut displaced, )?; self.storage.db.commit(transaction)?; self.blockchain.update_meta(m); - self.changes_tries_storage.post_commit(changes_trie_cache_ops); Ok(()) } @@ -2148,10 +1962,6 @@ impl sc_client_api::backend::Backend for Backend { Ok(()) } - fn changes_trie_storage(&self) -> Option<&dyn PrunableStateChangesTrieStorage> { - Some(&self.changes_tries_storage) - } - fn offchain_storage(&self) -> Option { Some(self.offchain_storage.clone()) } @@ -2208,7 +2018,6 @@ impl sc_client_api::backend::Backend for Backend { return Ok(c.saturated_into::>()) } let mut transaction = Transaction::new(); - let removed_number = best_number; let removed = self.blockchain.header(BlockId::Number(best_number))?.ok_or_else(|| { sp_blockchain::Error::UnknownBlock(format!( @@ -2241,10 +2050,6 @@ impl sc_client_api::backend::Backend for Backend { let key = utils::number_and_hash_to_lookup_key(best_number.clone(), &best_hash)?; - let changes_trie_cache_ops = self.changes_tries_storage.revert( - &mut transaction, - &cache::ComplexBlockId::new(removed.hash(), removed_number), - )?; if update_finalized { transaction.set_from_vec( columns::META, @@ -2283,7 +2088,6 @@ impl sc_client_api::backend::Backend for Backend { best_hash, ); self.storage.db.commit(transaction)?; - self.changes_tries_storage.post_commit(Some(changes_trie_cache_ops)); self.blockchain.update_meta(MetaUpdate { hash: best_hash, number: best_number, @@ -2345,11 +2149,6 @@ impl sc_client_api::backend::Backend for Backend { apply_state_commit(&mut transaction, commit); } transaction.remove(columns::KEY_LOOKUP, hash.as_ref()); - let changes_trie_cache_ops = self - .changes_tries_storage - .revert(&mut transaction, &cache::ComplexBlockId::new(*hash, hdr.number))?; - - self.changes_tries_storage.post_commit(Some(changes_trie_cache_ops)); leaves.revert(hash.clone(), hdr.number); leaves.prepare_transaction(&mut transaction, columns::META, meta_keys::LEAF_PREFIX); self.storage.db.commit(transaction)?; @@ -2461,32 +2260,16 @@ pub(crate) mod tests { use sp_blockchain::{lowest_common_ancestor, tree_route}; use sp_core::H256; use sp_runtime::{ - generic::DigestItem, testing::{Block as RawBlock, ExtrinsicWrapper, Header}, traits::{BlakeTwo256, Hash}, ConsensusEngineId, }; - use sp_state_machine::{TrieDBMut, TrieMut}; const CONS0_ENGINE_ID: ConsensusEngineId = *b"CON0"; const CONS1_ENGINE_ID: ConsensusEngineId = *b"CON1"; pub(crate) type Block = RawBlock>; - pub fn prepare_changes(changes: Vec<(Vec, Vec)>) -> (H256, MemoryDB) { - let mut changes_root = H256::default(); - let mut changes_trie_update = MemoryDB::::default(); - { - let mut trie = - TrieDBMut::::new(&mut changes_trie_update, &mut changes_root); - for (key, value) in changes { - trie.insert(&key, &value).unwrap(); - } - } - - (changes_root, changes_trie_update) - } - pub fn insert_header( backend: &Backend, number: u64, @@ -2501,20 +2284,14 @@ pub(crate) mod tests { backend: &Backend, number: u64, parent_hash: H256, - changes: Option, Vec)>>, + _changes: Option, Vec)>>, extrinsics_root: H256, body: Vec>, transaction_index: Option>, ) -> H256 { use sp_runtime::testing::Digest; - let mut digest = Digest::default(); - let mut changes_trie_update = Default::default(); - if let Some(changes) = changes { - let (root, update) = prepare_changes(changes); - digest.push(DigestItem::ChangesTrieRoot(root)); - changes_trie_update = update; - } + let digest = Digest::default(); let header = Header { number, parent_hash, @@ -2535,8 +2312,6 @@ pub(crate) mod tests { if let Some(index) = transaction_index { op.update_transaction_index(index).unwrap(); } - op.update_changes_trie((changes_trie_update, ChangesTrieCacheAction::Clear)) - .unwrap(); backend.commit_operation(op).unwrap(); header_hash @@ -3241,38 +3016,6 @@ pub(crate) mod tests { } } - #[test] - fn header_cht_root_works() { - use sc_client_api::ProvideChtRoots; - - let backend = Backend::::new_test(10, 10); - - // insert 1 + SIZE + SIZE + 1 blocks so that CHT#0 is created - let mut prev_hash = - insert_header(&backend, 0, Default::default(), None, Default::default()); - let cht_size: u64 = cht::size(); - for i in 1..1 + cht_size + cht_size + 1 { - prev_hash = insert_header(&backend, i, prev_hash, None, Default::default()); - } - - let blockchain = backend.blockchain(); - - let cht_root_1 = blockchain - .header_cht_root(cht_size, cht::start_number(cht_size, 0)) - .unwrap() - .unwrap(); - let cht_root_2 = blockchain - .header_cht_root(cht_size, cht::start_number(cht_size, 0) + cht_size / 2) - .unwrap() - .unwrap(); - let cht_root_3 = blockchain - .header_cht_root(cht_size, cht::end_number(cht_size, 0)) - .unwrap() - .unwrap(); - assert_eq!(cht_root_1, cht_root_2); - assert_eq!(cht_root_2, cht_root_3); - } - #[test] fn prune_blocks_on_finalize() { for storage in &[TransactionStorageMode::BlockBody, TransactionStorageMode::StorageChain] { diff --git a/client/db/src/light.rs b/client/db/src/light.rs deleted file mode 100644 index 48cf0489cf2a0..0000000000000 --- a/client/db/src/light.rs +++ /dev/null @@ -1,1329 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! RocksDB-based light client blockchain storage. - -use parking_lot::RwLock; -use std::{collections::HashMap, convert::TryInto, sync::Arc}; - -use crate::{ - cache::{ComplexBlockId, DbCache, DbCacheSync, EntryType as CacheEntryType}, - utils::{self, block_id_to_lookup_key, meta_keys, read_db, read_meta, DatabaseType, Meta}, - DatabaseSettings, DbHash, FrozenForDuration, -}; -use codec::{Decode, Encode}; -use log::{debug, trace, warn}; -use sc_client_api::{ - backend::{AuxStore, NewBlockState, ProvideChtRoots}, - blockchain::{BlockStatus, Cache as BlockchainCache, Info as BlockchainInfo}, - cht, Storage, UsageInfo, -}; -use sp_blockchain::{ - well_known_cache_keys, CachedHeaderMetadata, Error as ClientError, - HeaderBackend as BlockchainHeaderBackend, HeaderMetadata, HeaderMetadataCache, - Result as ClientResult, -}; -use sp_database::{Database, Transaction}; -use sp_runtime::{ - generic::{BlockId, DigestItem}, - traits::{Block as BlockT, HashFor, Header as HeaderT, NumberFor, One, Zero}, -}; - -pub(crate) mod columns { - pub const META: u32 = crate::utils::COLUMN_META; - pub const KEY_LOOKUP: u32 = 1; - pub const HEADER: u32 = 2; - pub const CACHE: u32 = 3; - pub const CHT: u32 = 4; - pub const AUX: u32 = 5; -} - -/// Prefix for headers CHT. -const HEADER_CHT_PREFIX: u8 = 0; -/// Prefix for changes tries roots CHT. -const CHANGES_TRIE_CHT_PREFIX: u8 = 1; - -/// Light blockchain storage. Stores most recent headers + CHTs for older headers. -/// Locks order: meta, cache. -pub struct LightStorage { - db: Arc>, - meta: RwLock, Block::Hash>>, - cache: Arc>, - header_metadata_cache: Arc>, - io_stats: FrozenForDuration, -} - -impl LightStorage { - /// Create new storage with given settings. - pub fn new(config: DatabaseSettings) -> ClientResult { - let db = crate::utils::open_database::(&config, DatabaseType::Light)?; - Self::from_kvdb(db as Arc<_>) - } - - /// Create new memory-backed `LightStorage` for tests. - #[cfg(any(test, feature = "test-helpers"))] - pub fn new_test() -> Self { - let db = Arc::new(sp_database::MemDb::default()); - Self::from_kvdb(db as Arc<_>).expect("failed to create test-db") - } - - fn from_kvdb(db: Arc>) -> ClientResult { - let meta = read_meta::(&*db, columns::HEADER)?; - let header_metadata_cache = Arc::new(HeaderMetadataCache::default()); - let cache = DbCache::new( - db.clone(), - header_metadata_cache.clone(), - columns::KEY_LOOKUP, - columns::HEADER, - columns::CACHE, - meta.genesis_hash, - ComplexBlockId::new(meta.finalized_hash, meta.finalized_number), - ); - - Ok(LightStorage { - db, - meta: RwLock::new(meta), - cache: Arc::new(DbCacheSync(RwLock::new(cache))), - header_metadata_cache, - io_stats: FrozenForDuration::new(std::time::Duration::from_secs(1)), - }) - } - - #[cfg(test)] - pub(crate) fn cache(&self) -> &DbCacheSync { - &self.cache - } - - fn update_meta( - &self, - hash: Block::Hash, - number: NumberFor, - is_best: bool, - is_finalized: bool, - ) { - let mut meta = self.meta.write(); - - if number.is_zero() { - meta.genesis_hash = hash; - meta.finalized_hash = hash; - } - - if is_best { - meta.best_number = number; - meta.best_hash = hash; - } - - if is_finalized { - meta.finalized_number = number; - meta.finalized_hash = hash; - } - } -} - -impl BlockchainHeaderBackend for LightStorage -where - Block: BlockT, -{ - fn header(&self, id: BlockId) -> ClientResult> { - utils::read_header(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id) - } - - fn info(&self) -> BlockchainInfo { - let meta = self.meta.read(); - BlockchainInfo { - best_hash: meta.best_hash, - best_number: meta.best_number, - genesis_hash: meta.genesis_hash.clone(), - finalized_hash: meta.finalized_hash, - finalized_number: meta.finalized_number, - finalized_state: if meta.finalized_hash != Default::default() { - Some((meta.genesis_hash, Zero::zero())) - } else { - None - }, - number_leaves: 1, - block_gap: None, - } - } - - fn status(&self, id: BlockId) -> ClientResult { - let exists = match id { - BlockId::Hash(_) => - read_db(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id)?.is_some(), - BlockId::Number(n) => n <= self.meta.read().best_number, - }; - match exists { - true => Ok(BlockStatus::InChain), - false => Ok(BlockStatus::Unknown), - } - } - - fn number(&self, hash: Block::Hash) -> ClientResult>> { - if let Some(lookup_key) = - block_id_to_lookup_key::(&*self.db, columns::KEY_LOOKUP, BlockId::Hash(hash))? - { - let number = utils::lookup_key_to_number(&lookup_key)?; - Ok(Some(number)) - } else { - Ok(None) - } - } - - fn hash(&self, number: NumberFor) -> ClientResult> { - Ok(self.header(BlockId::Number(number))?.map(|header| header.hash().clone())) - } -} - -impl HeaderMetadata for LightStorage { - type Error = ClientError; - - fn header_metadata( - &self, - hash: Block::Hash, - ) -> Result, Self::Error> { - self.header_metadata_cache.header_metadata(hash).map_or_else( - || { - self.header(BlockId::hash(hash))? - .map(|header| { - let header_metadata = CachedHeaderMetadata::from(&header); - self.header_metadata_cache - .insert_header_metadata(header_metadata.hash, header_metadata.clone()); - header_metadata - }) - .ok_or_else(|| { - ClientError::UnknownBlock(format!("header not found in db: {}", hash)) - }) - }, - Ok, - ) - } - - fn insert_header_metadata(&self, hash: Block::Hash, metadata: CachedHeaderMetadata) { - self.header_metadata_cache.insert_header_metadata(hash, metadata) - } - - fn remove_header_metadata(&self, hash: Block::Hash) { - self.header_metadata_cache.remove_header_metadata(hash); - } -} - -impl LightStorage { - // Get block changes trie root, if available. - fn changes_trie_root(&self, block: BlockId) -> ClientResult> { - self.header(block).map(|header| { - header.and_then(|header| header.digest().log(DigestItem::as_changes_trie_root).cloned()) - }) - } - - /// Handle setting head within a transaction. `route_to` should be the last - /// block that existed in the database. `best_to` should be the best block - /// to be set. - /// - /// In the case where the new best block is a block to be imported, `route_to` - /// should be the parent of `best_to`. In the case where we set an existing block - /// to be best, `route_to` should equal to `best_to`. - fn set_head_with_transaction( - &self, - transaction: &mut Transaction, - route_to: Block::Hash, - best_to: (NumberFor, Block::Hash), - ) -> ClientResult<()> { - let lookup_key = utils::number_and_hash_to_lookup_key(best_to.0, &best_to.1)?; - - // handle reorg. - let meta = self.meta.read(); - if meta.best_hash != Default::default() { - let tree_route = sp_blockchain::tree_route(self, meta.best_hash, route_to)?; - - // update block number to hash lookup entries. - for retracted in tree_route.retracted() { - if retracted.hash == meta.finalized_hash { - // TODO: can we recover here? - warn!( - "Safety failure: reverting finalized block {:?}", - (&retracted.number, &retracted.hash) - ); - } - - utils::remove_number_to_key_mapping( - transaction, - columns::KEY_LOOKUP, - retracted.number, - )?; - } - - for enacted in tree_route.enacted() { - utils::insert_number_to_key_mapping( - transaction, - columns::KEY_LOOKUP, - enacted.number, - enacted.hash, - )?; - } - } - - transaction.set_from_vec(columns::META, meta_keys::BEST_BLOCK, lookup_key); - utils::insert_number_to_key_mapping( - transaction, - columns::KEY_LOOKUP, - best_to.0, - best_to.1, - )?; - - Ok(()) - } - - // Note that a block is finalized. Only call with child of last finalized block. - fn note_finalized( - &self, - transaction: &mut Transaction, - header: &Block::Header, - hash: Block::Hash, - ) -> ClientResult<()> { - let meta = self.meta.read(); - if &meta.finalized_hash != header.parent_hash() { - return Err(::sp_blockchain::Error::NonSequentialFinalization(format!( - "Last finalized {:?} not parent of {:?}", - meta.finalized_hash, hash - )) - .into()) - } - - let lookup_key = utils::number_and_hash_to_lookup_key(header.number().clone(), hash)?; - transaction.set_from_vec(columns::META, meta_keys::FINALIZED_BLOCK, lookup_key); - - // build new CHT(s) if required - if let Some(new_cht_number) = cht::is_build_required(cht::size(), *header.number()) { - let new_cht_start: NumberFor = cht::start_number(cht::size(), new_cht_number); - - let mut current_num = new_cht_start; - let cht_range = ::std::iter::from_fn(|| { - let old_current_num = current_num; - current_num = current_num + One::one(); - Some(old_current_num) - }); - - let new_header_cht_root = cht::compute_root::, _>( - cht::size(), - new_cht_number, - cht_range.map(|num| self.hash(num)), - )?; - transaction.set( - columns::CHT, - &cht_key(HEADER_CHT_PREFIX, new_cht_start)?, - new_header_cht_root.as_ref(), - ); - - // if the header includes changes trie root, let's build a changes tries roots CHT - if header.digest().log(DigestItem::as_changes_trie_root).is_some() { - let mut current_num = new_cht_start; - let cht_range = std::iter::from_fn(|| { - let old_current_num = current_num; - current_num = current_num + One::one(); - Some(old_current_num) - }); - let new_changes_trie_cht_root = - cht::compute_root::, _>( - cht::size(), - new_cht_number, - cht_range.map(|num| self.changes_trie_root(BlockId::Number(num))), - )?; - transaction.set( - columns::CHT, - &cht_key(CHANGES_TRIE_CHT_PREFIX, new_cht_start)?, - new_changes_trie_cht_root.as_ref(), - ); - } - - // prune headers that are replaced with CHT - let mut prune_block = new_cht_start; - let new_cht_end = cht::end_number(cht::size(), new_cht_number); - trace!(target: "db", "Replacing blocks [{}..{}] with CHT#{}", - new_cht_start, new_cht_end, new_cht_number); - - while prune_block <= new_cht_end { - if let Some(hash) = self.hash(prune_block)? { - let lookup_key = block_id_to_lookup_key::(&*self.db, columns::KEY_LOOKUP, BlockId::Number(prune_block))? - .expect("retrieved hash for `prune_block` right above. therefore retrieving lookup key must succeed. q.e.d."); - utils::remove_key_mappings( - transaction, - columns::KEY_LOOKUP, - prune_block, - hash, - )?; - transaction.remove(columns::HEADER, &lookup_key); - } - prune_block += One::one(); - } - } - - Ok(()) - } - - /// Read CHT root of given type for the block. - fn read_cht_root( - &self, - cht_type: u8, - cht_size: NumberFor, - block: NumberFor, - ) -> ClientResult> { - let no_cht_for_block = || ClientError::Backend(format!("Missing CHT for block {}", block)); - - let meta = self.meta.read(); - let max_cht_number = cht::max_cht_number(cht_size, meta.finalized_number); - let cht_number = cht::block_to_cht_number(cht_size, block).ok_or_else(no_cht_for_block)?; - match max_cht_number { - Some(max_cht_number) if cht_number <= max_cht_number => (), - _ => return Ok(None), - } - - let cht_start = cht::start_number(cht_size, cht_number); - self.db - .get(columns::CHT, &cht_key(cht_type, cht_start)?) - .ok_or_else(no_cht_for_block) - .and_then(|hash| Block::Hash::decode(&mut &*hash).map_err(|_| no_cht_for_block())) - .map(Some) - } -} - -impl AuxStore for LightStorage -where - Block: BlockT, -{ - fn insert_aux< - 'a, - 'b: 'a, - 'c: 'a, - I: IntoIterator, - D: IntoIterator, - >( - &self, - insert: I, - delete: D, - ) -> ClientResult<()> { - let mut transaction = Transaction::new(); - for (k, v) in insert { - transaction.set(columns::AUX, k, v); - } - for k in delete { - transaction.remove(columns::AUX, k); - } - self.db.commit(transaction)?; - - Ok(()) - } - - fn get_aux(&self, key: &[u8]) -> ClientResult>> { - Ok(self.db.get(columns::AUX, key)) - } -} - -impl Storage for LightStorage -where - Block: BlockT, -{ - fn import_header( - &self, - header: Block::Header, - mut cache_at: HashMap>, - leaf_state: NewBlockState, - aux_ops: Vec<(Vec, Option>)>, - ) -> ClientResult<()> { - let mut transaction = Transaction::new(); - - let hash = header.hash(); - let number = *header.number(); - let parent_hash = *header.parent_hash(); - - for (key, maybe_val) in aux_ops { - match maybe_val { - Some(val) => transaction.set_from_vec(columns::AUX, &key, val), - None => transaction.remove(columns::AUX, &key), - } - } - - // blocks are keyed by number + hash. - let lookup_key = utils::number_and_hash_to_lookup_key(number, &hash)?; - - if leaf_state.is_best() { - self.set_head_with_transaction(&mut transaction, parent_hash, (number, hash))?; - } - - utils::insert_hash_to_key_mapping(&mut transaction, columns::KEY_LOOKUP, number, hash)?; - transaction.set_from_vec(columns::HEADER, &lookup_key, header.encode()); - - let header_metadata = CachedHeaderMetadata::from(&header); - self.header_metadata_cache - .insert_header_metadata(header.hash().clone(), header_metadata); - - let is_genesis = number.is_zero(); - if is_genesis { - self.cache.0.write().set_genesis_hash(hash); - transaction.set(columns::META, meta_keys::GENESIS_HASH, hash.as_ref()); - } - - let finalized = match leaf_state { - _ if is_genesis => true, - NewBlockState::Final => true, - _ => false, - }; - - if finalized { - self.note_finalized(&mut transaction, &header, hash)?; - } - - // update changes trie configuration cache - if !cache_at.contains_key(&well_known_cache_keys::CHANGES_TRIE_CONFIG) { - if let Some(new_configuration) = - crate::changes_tries_storage::extract_new_configuration(&header) - { - cache_at - .insert(well_known_cache_keys::CHANGES_TRIE_CONFIG, new_configuration.encode()); - } - } - - { - let mut cache = self.cache.0.write(); - let cache_ops = cache - .transaction(&mut transaction) - .on_block_insert( - ComplexBlockId::new( - *header.parent_hash(), - if number.is_zero() { Zero::zero() } else { number - One::one() }, - ), - ComplexBlockId::new(hash, number), - cache_at, - if finalized { CacheEntryType::Final } else { CacheEntryType::NonFinal }, - )? - .into_ops(); - - debug!("Light DB Commit {:?} ({})", hash, number); - - self.db.commit(transaction)?; - cache.commit(cache_ops).expect( - "only fails if cache with given name isn't loaded yet; cache is already loaded \ - because there are cache_ops; qed", - ); - } - - self.update_meta(hash, number, leaf_state.is_best(), finalized); - - Ok(()) - } - - fn set_head(&self, id: BlockId) -> ClientResult<()> { - if let Some(header) = self.header(id)? { - let hash = header.hash(); - let number = header.number(); - - let mut transaction = Transaction::new(); - self.set_head_with_transaction( - &mut transaction, - hash.clone(), - (number.clone(), hash.clone()), - )?; - self.db.commit(transaction)?; - self.update_meta(hash, header.number().clone(), true, false); - - Ok(()) - } else { - Err(ClientError::UnknownBlock(format!("Cannot set head {:?}", id))) - } - } - - fn finalize_header(&self, id: BlockId) -> ClientResult<()> { - if let Some(header) = self.header(id)? { - let mut transaction = Transaction::new(); - let hash = header.hash(); - let number = *header.number(); - self.note_finalized(&mut transaction, &header, hash.clone())?; - { - let mut cache = self.cache.0.write(); - let cache_ops = cache - .transaction(&mut transaction) - .on_block_finalize( - ComplexBlockId::new( - *header.parent_hash(), - if number.is_zero() { Zero::zero() } else { number - One::one() }, - ), - ComplexBlockId::new(hash, number), - )? - .into_ops(); - - self.db.commit(transaction)?; - cache.commit(cache_ops).expect( - "only fails if cache with given name isn't loaded yet; cache is already loaded \ - because there are cache_ops; qed", - ); - } - self.update_meta(hash, header.number().clone(), false, true); - - Ok(()) - } else { - Err(ClientError::UnknownBlock(format!("Cannot finalize block {:?}", id))) - } - } - - fn last_finalized(&self) -> ClientResult { - Ok(self.meta.read().finalized_hash.clone()) - } - - fn cache(&self) -> Option>> { - Some(self.cache.clone()) - } - - fn usage_info(&self) -> Option { - use sc_client_api::{IoInfo, MemoryInfo, MemorySize}; - - // TODO: reimplement IO stats - let database_cache = MemorySize::from_bytes(0); - let io_stats = self.io_stats.take_or_else(|| kvdb::IoStats::empty()); - - Some(UsageInfo { - memory: MemoryInfo { - database_cache, - state_cache: Default::default(), - state_db: Default::default(), - }, - io: IoInfo { - transactions: io_stats.transactions, - bytes_read: io_stats.bytes_read, - bytes_written: io_stats.bytes_written, - writes: io_stats.writes, - reads: io_stats.reads, - average_transaction_size: io_stats.avg_transaction_size() as u64, - // Light client does not track those - state_reads: 0, - state_writes: 0, - state_reads_cache: 0, - state_writes_cache: 0, - state_writes_nodes: 0, - }, - }) - } -} - -impl ProvideChtRoots for LightStorage -where - Block: BlockT, -{ - fn header_cht_root( - &self, - cht_size: NumberFor, - block: NumberFor, - ) -> ClientResult> { - self.read_cht_root(HEADER_CHT_PREFIX, cht_size, block) - } - - fn changes_trie_cht_root( - &self, - cht_size: NumberFor, - block: NumberFor, - ) -> ClientResult> { - self.read_cht_root(CHANGES_TRIE_CHT_PREFIX, cht_size, block) - } -} - -/// Build the key for inserting header-CHT at given block. -fn cht_key>(cht_type: u8, block: N) -> ClientResult<[u8; 5]> { - let mut key = [cht_type; 5]; - key[1..].copy_from_slice(&utils::number_index_key(block)?); - Ok(key) -} - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - use sc_client_api::cht; - use sp_blockchain::{lowest_common_ancestor, tree_route}; - use sp_core::ChangesTrieConfiguration; - use sp_runtime::{ - generic::{ChangesTrieSignal, DigestItem}, - testing::{Block as RawBlock, ExtrinsicWrapper, Header, H256 as Hash}, - }; - - type Block = RawBlock>; - type AuthorityId = sp_core::ed25519::Public; - - pub fn default_header(parent: &Hash, number: u64) -> Header { - Header { - number: number.into(), - parent_hash: *parent, - state_root: Hash::random(), - digest: Default::default(), - extrinsics_root: Default::default(), - } - } - - fn header_with_changes_trie(parent: &Hash, number: u64) -> Header { - let mut header = default_header(parent, number); - header - .digest - .logs - .push(DigestItem::ChangesTrieRoot([(number % 256) as u8; 32].into())); - header - } - - fn header_with_extrinsics_root(parent: &Hash, number: u64, extrinsics_root: Hash) -> Header { - let mut header = default_header(parent, number); - header.extrinsics_root = extrinsics_root; - header - } - - pub fn insert_block Header>( - db: &LightStorage, - cache: HashMap>, - mut header: F, - ) -> Hash { - let header = header(); - let hash = header.hash(); - db.import_header(header, cache, NewBlockState::Best, Vec::new()).unwrap(); - hash - } - - fn insert_final_block Header>( - db: &LightStorage, - cache: HashMap>, - header: F, - ) -> Hash { - let header = header(); - let hash = header.hash(); - db.import_header(header, cache, NewBlockState::Final, Vec::new()).unwrap(); - hash - } - - fn insert_non_best_block Header>( - db: &LightStorage, - cache: HashMap>, - header: F, - ) -> Hash { - let header = header(); - let hash = header.hash(); - db.import_header(header, cache, NewBlockState::Normal, Vec::new()).unwrap(); - hash - } - - #[test] - fn returns_known_header() { - let db = LightStorage::new_test(); - let known_hash = - insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); - let header_by_hash = db.header(BlockId::Hash(known_hash)).unwrap().unwrap(); - let header_by_number = db.header(BlockId::Number(0)).unwrap().unwrap(); - assert_eq!(header_by_hash, header_by_number); - } - - #[test] - fn does_not_return_unknown_header() { - let db = LightStorage::::new_test(); - assert!(db.header(BlockId::Hash(Hash::from_low_u64_be(1))).unwrap().is_none()); - assert!(db.header(BlockId::Number(0)).unwrap().is_none()); - } - - #[test] - fn returns_info() { - let db = LightStorage::new_test(); - let genesis_hash = - insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); - let info = db.info(); - assert_eq!(info.best_hash, genesis_hash); - assert_eq!(info.best_number, 0); - assert_eq!(info.genesis_hash, genesis_hash); - let best_hash = insert_block(&db, HashMap::new(), || default_header(&genesis_hash, 1)); - let info = db.info(); - assert_eq!(info.best_hash, best_hash); - assert_eq!(info.best_number, 1); - assert_eq!(info.genesis_hash, genesis_hash); - } - - #[test] - fn returns_block_status() { - let db = LightStorage::new_test(); - let genesis_hash = - insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); - assert_eq!(db.status(BlockId::Hash(genesis_hash)).unwrap(), BlockStatus::InChain); - assert_eq!(db.status(BlockId::Number(0)).unwrap(), BlockStatus::InChain); - assert_eq!( - db.status(BlockId::Hash(Hash::from_low_u64_be(1))).unwrap(), - BlockStatus::Unknown - ); - assert_eq!(db.status(BlockId::Number(1)).unwrap(), BlockStatus::Unknown); - } - - #[test] - fn returns_block_hash() { - let db = LightStorage::new_test(); - let genesis_hash = - insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); - assert_eq!(db.hash(0).unwrap(), Some(genesis_hash)); - assert_eq!(db.hash(1).unwrap(), None); - } - - #[test] - fn import_header_works() { - let raw_db = Arc::new(sp_database::MemDb::default()); - let db = LightStorage::from_kvdb(raw_db.clone()).unwrap(); - - let genesis_hash = - insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); - assert_eq!(raw_db.count(columns::HEADER), 1); - assert_eq!(raw_db.count(columns::KEY_LOOKUP), 2); - - let _ = insert_block(&db, HashMap::new(), || default_header(&genesis_hash, 1)); - assert_eq!(raw_db.count(columns::HEADER), 2); - assert_eq!(raw_db.count(columns::KEY_LOOKUP), 4); - } - - #[test] - fn finalized_ancient_headers_are_replaced_with_cht() { - fn insert_headers Header>( - header_producer: F, - ) -> (Arc, LightStorage) { - let raw_db = Arc::new(sp_database::MemDb::default()); - let db = LightStorage::from_kvdb(raw_db.clone()).unwrap(); - let cht_size: u64 = cht::size(); - let ucht_size: usize = cht_size as _; - - // insert genesis block header (never pruned) - let mut prev_hash = - insert_final_block(&db, HashMap::new(), || header_producer(&Default::default(), 0)); - - // insert SIZE blocks && ensure that nothing is pruned - - for number in 0..cht::size() { - prev_hash = - insert_block(&db, HashMap::new(), || header_producer(&prev_hash, 1 + number)); - } - assert_eq!(raw_db.count(columns::HEADER), 1 + ucht_size); - assert_eq!(raw_db.count(columns::CHT), 0); - - // insert next SIZE blocks && ensure that nothing is pruned - for number in 0..(cht_size as _) { - prev_hash = insert_block(&db, HashMap::new(), || { - header_producer(&prev_hash, 1 + cht_size + number) - }); - } - assert_eq!(raw_db.count(columns::HEADER), 1 + ucht_size + ucht_size); - assert_eq!(raw_db.count(columns::CHT), 0); - - // insert block #{2 * cht::size() + 1} && check that new CHT is created + headers of - // this CHT are pruned nothing is yet finalized, so nothing is pruned. - prev_hash = insert_block(&db, HashMap::new(), || { - header_producer(&prev_hash, 1 + cht_size + cht_size) - }); - assert_eq!(raw_db.count(columns::HEADER), 2 + ucht_size + ucht_size); - assert_eq!(raw_db.count(columns::CHT), 0); - - // now finalize the block. - for i in (0..(ucht_size + ucht_size)).map(|i| i + 1) { - db.finalize_header(BlockId::Number(i as _)).unwrap(); - } - db.finalize_header(BlockId::Hash(prev_hash)).unwrap(); - (raw_db, db) - } - - // when headers are created without changes tries roots - let (raw_db, db) = insert_headers(default_header); - let cht_size: u64 = cht::size(); - assert_eq!(raw_db.count(columns::HEADER), (1 + cht_size + 1) as usize); - assert_eq!(raw_db.count(columns::KEY_LOOKUP), (2 * (1 + cht_size + 1)) as usize); - assert_eq!(raw_db.count(columns::CHT), 1); - assert!((0..cht_size as _).all(|i| db.header(BlockId::Number(1 + i)).unwrap().is_none())); - assert!(db.header_cht_root(cht_size, cht_size / 2).unwrap().is_some()); - assert!(db.header_cht_root(cht_size, cht_size + cht_size / 2).unwrap().is_none()); - assert!(db.changes_trie_cht_root(cht_size, cht_size / 2).is_err()); - assert!(db.changes_trie_cht_root(cht_size, cht_size + cht_size / 2).unwrap().is_none()); - - // when headers are created with changes tries roots - let (raw_db, db) = insert_headers(header_with_changes_trie); - assert_eq!(raw_db.count(columns::HEADER), (1 + cht_size + 1) as usize); - assert_eq!(raw_db.count(columns::CHT), 2); - assert!((0..cht_size as _).all(|i| db.header(BlockId::Number(1 + i)).unwrap().is_none())); - assert!(db.header_cht_root(cht_size, cht_size / 2).unwrap().is_some()); - assert!(db.header_cht_root(cht_size, cht_size + cht_size / 2).unwrap().is_none()); - assert!(db.changes_trie_cht_root(cht_size, cht_size / 2).unwrap().is_some()); - assert!(db.changes_trie_cht_root(cht_size, cht_size + cht_size / 2).unwrap().is_none()); - } - - #[test] - fn get_cht_fails_for_genesis_block() { - assert!(LightStorage::::new_test().header_cht_root(cht::size(), 0).is_err()); - } - - #[test] - fn get_cht_fails_for_non_existent_cht() { - let cht_size: u64 = cht::size(); - assert!(LightStorage::::new_test() - .header_cht_root(cht_size, cht_size / 2) - .unwrap() - .is_none()); - } - - #[test] - fn get_cht_works() { - let db = LightStorage::new_test(); - - // insert 1 + SIZE + SIZE + 1 blocks so that CHT#0 is created - let mut prev_hash = insert_final_block(&db, HashMap::new(), || { - header_with_changes_trie(&Default::default(), 0) - }); - let cht_size: u64 = cht::size(); - let ucht_size: usize = cht_size as _; - for i in 1..1 + ucht_size + ucht_size + 1 { - prev_hash = insert_block(&db, HashMap::new(), || { - header_with_changes_trie(&prev_hash, i as u64) - }); - db.finalize_header(BlockId::Hash(prev_hash)).unwrap(); - } - - let cht_root_1 = - db.header_cht_root(cht_size, cht::start_number(cht_size, 0)).unwrap().unwrap(); - let cht_root_2 = db - .header_cht_root(cht_size, cht::start_number(cht_size, 0) + cht_size / 2) - .unwrap() - .unwrap(); - let cht_root_3 = - db.header_cht_root(cht_size, cht::end_number(cht_size, 0)).unwrap().unwrap(); - assert_eq!(cht_root_1, cht_root_2); - assert_eq!(cht_root_2, cht_root_3); - - let cht_root_1 = db - .changes_trie_cht_root(cht_size, cht::start_number(cht_size, 0)) - .unwrap() - .unwrap(); - let cht_root_2 = db - .changes_trie_cht_root(cht_size, cht::start_number(cht_size, 0) + cht_size / 2) - .unwrap() - .unwrap(); - let cht_root_3 = db - .changes_trie_cht_root(cht_size, cht::end_number(cht_size, 0)) - .unwrap() - .unwrap(); - assert_eq!(cht_root_1, cht_root_2); - assert_eq!(cht_root_2, cht_root_3); - } - - #[test] - fn tree_route_works() { - let db = LightStorage::new_test(); - let block0 = insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); - - // fork from genesis: 3 prong. - let a1 = insert_block(&db, HashMap::new(), || default_header(&block0, 1)); - let a2 = insert_block(&db, HashMap::new(), || default_header(&a1, 2)); - let a3 = insert_block(&db, HashMap::new(), || default_header(&a2, 3)); - - // fork from genesis: 2 prong. - let b1 = insert_block(&db, HashMap::new(), || { - header_with_extrinsics_root(&block0, 1, Hash::from([1; 32])) - }); - let b2 = insert_block(&db, HashMap::new(), || default_header(&b1, 2)); - - { - let tree_route = tree_route(&db, a3, b2).unwrap(); - - assert_eq!(tree_route.common_block().hash, block0); - assert_eq!( - tree_route.retracted().iter().map(|r| r.hash).collect::>(), - vec![a3, a2, a1] - ); - assert_eq!( - tree_route.enacted().iter().map(|r| r.hash).collect::>(), - vec![b1, b2] - ); - } - - { - let tree_route = tree_route(&db, a1, a3).unwrap(); - - assert_eq!(tree_route.common_block().hash, a1); - assert!(tree_route.retracted().is_empty()); - assert_eq!( - tree_route.enacted().iter().map(|r| r.hash).collect::>(), - vec![a2, a3] - ); - } - - { - let tree_route = tree_route(&db, a3, a1).unwrap(); - - assert_eq!(tree_route.common_block().hash, a1); - assert_eq!( - tree_route.retracted().iter().map(|r| r.hash).collect::>(), - vec![a3, a2] - ); - assert!(tree_route.enacted().is_empty()); - } - - { - let tree_route = tree_route(&db, a2, a2).unwrap(); - - assert_eq!(tree_route.common_block().hash, a2); - assert!(tree_route.retracted().is_empty()); - assert!(tree_route.enacted().is_empty()); - } - } - - #[test] - fn lowest_common_ancestor_works() { - let db = LightStorage::new_test(); - let block0 = insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); - - // fork from genesis: 3 prong. - let a1 = insert_block(&db, HashMap::new(), || default_header(&block0, 1)); - let a2 = insert_block(&db, HashMap::new(), || default_header(&a1, 2)); - let a3 = insert_block(&db, HashMap::new(), || default_header(&a2, 3)); - - // fork from genesis: 2 prong. - let b1 = insert_block(&db, HashMap::new(), || { - header_with_extrinsics_root(&block0, 1, Hash::from([1; 32])) - }); - let b2 = insert_block(&db, HashMap::new(), || default_header(&b1, 2)); - - { - let lca = lowest_common_ancestor(&db, a3, b2).unwrap(); - - assert_eq!(lca.hash, block0); - assert_eq!(lca.number, 0); - } - - { - let lca = lowest_common_ancestor(&db, a1, a3).unwrap(); - - assert_eq!(lca.hash, a1); - assert_eq!(lca.number, 1); - } - - { - let lca = lowest_common_ancestor(&db, a3, a1).unwrap(); - - assert_eq!(lca.hash, a1); - assert_eq!(lca.number, 1); - } - - { - let lca = lowest_common_ancestor(&db, a2, a3).unwrap(); - - assert_eq!(lca.hash, a2); - assert_eq!(lca.number, 2); - } - - { - let lca = lowest_common_ancestor(&db, a2, a1).unwrap(); - - assert_eq!(lca.hash, a1); - assert_eq!(lca.number, 1); - } - - { - let lca = lowest_common_ancestor(&db, a2, a2).unwrap(); - - assert_eq!(lca.hash, a2); - assert_eq!(lca.number, 2); - } - } - - #[test] - fn authorities_are_cached() { - let db = LightStorage::new_test(); - - fn run_checks( - db: &LightStorage, - max: u64, - checks: &[(u64, Option>)], - ) { - for (at, expected) in checks.iter().take_while(|(at, _)| *at <= max) { - let actual = authorities(db.cache(), BlockId::Number(*at)); - assert_eq!(*expected, actual); - } - } - - fn same_authorities() -> HashMap> { - HashMap::new() - } - - fn make_authorities( - authorities: Vec, - ) -> HashMap> { - let mut map = HashMap::new(); - map.insert(well_known_cache_keys::AUTHORITIES, authorities.encode()); - map - } - - fn authorities( - cache: &dyn BlockchainCache, - at: BlockId, - ) -> Option> { - cache - .get_at(&well_known_cache_keys::AUTHORITIES, &at) - .unwrap_or(None) - .and_then(|(_, _, val)| Decode::decode(&mut &val[..]).ok()) - } - - let auth1 = || AuthorityId::from_raw([1u8; 32]); - let auth2 = || AuthorityId::from_raw([2u8; 32]); - let auth3 = || AuthorityId::from_raw([3u8; 32]); - let auth4 = || AuthorityId::from_raw([4u8; 32]); - let auth5 = || AuthorityId::from_raw([5u8; 32]); - let auth6 = || AuthorityId::from_raw([6u8; 32]); - - let (hash2, hash6) = { - // first few blocks are instantly finalized - // B0(None) -> B1(None) -> B2(1) -> B3(1) -> B4(1, 2) -> B5(1, 2) -> B6(1, 2) - let checks = vec![ - (0, None), - (1, None), - (2, Some(vec![auth1()])), - (3, Some(vec![auth1()])), - (4, Some(vec![auth1(), auth2()])), - (5, Some(vec![auth1(), auth2()])), - (6, Some(vec![auth1(), auth2()])), - ]; - - let hash0 = insert_final_block(&db, same_authorities(), || { - default_header(&Default::default(), 0) - }); - run_checks(&db, 0, &checks); - let hash1 = insert_final_block(&db, same_authorities(), || default_header(&hash0, 1)); - run_checks(&db, 1, &checks); - let hash2 = insert_final_block(&db, make_authorities(vec![auth1()]), || { - default_header(&hash1, 2) - }); - run_checks(&db, 2, &checks); - let hash3 = insert_final_block(&db, make_authorities(vec![auth1()]), || { - default_header(&hash2, 3) - }); - run_checks(&db, 3, &checks); - let hash4 = insert_final_block(&db, make_authorities(vec![auth1(), auth2()]), || { - default_header(&hash3, 4) - }); - run_checks(&db, 4, &checks); - let hash5 = insert_final_block(&db, make_authorities(vec![auth1(), auth2()]), || { - default_header(&hash4, 5) - }); - run_checks(&db, 5, &checks); - let hash6 = insert_final_block(&db, same_authorities(), || default_header(&hash5, 6)); - run_checks(&db, 6, &checks); - - (hash2, hash6) - }; - - { - // some older non-best blocks are inserted - // ... -> B2(1) -> B2_1(1) -> B2_2(2) - // => the cache ignores all writes before best finalized block - let hash2_1 = insert_non_best_block(&db, make_authorities(vec![auth1()]), || { - default_header(&hash2, 3) - }); - assert_eq!(None, authorities(db.cache(), BlockId::Hash(hash2_1))); - let hash2_2 = - insert_non_best_block(&db, make_authorities(vec![auth1(), auth2()]), || { - default_header(&hash2_1, 4) - }); - assert_eq!(None, authorities(db.cache(), BlockId::Hash(hash2_2))); - } - - let (hash7, hash8, hash6_1, hash6_2, hash6_1_1, hash6_1_2) = { - // inserting non-finalized blocks - // B6(None) -> B7(3) -> B8(3) - // \> B6_1(4) -> B6_2(4) - // \> B6_1_1(5) - // \> B6_1_2(6) -> B6_1_3(7) - - let hash7 = - insert_block(&db, make_authorities(vec![auth3()]), || default_header(&hash6, 7)); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6)), Some(vec![auth1(), auth2()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); - let hash8 = - insert_block(&db, make_authorities(vec![auth3()]), || default_header(&hash7, 8)); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6)), Some(vec![auth1(), auth2()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()])); - let hash6_1 = - insert_block(&db, make_authorities(vec![auth4()]), || default_header(&hash6, 7)); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6)), Some(vec![auth1(), auth2()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); - let hash6_1_1 = insert_non_best_block(&db, make_authorities(vec![auth5()]), || { - default_header(&hash6_1, 8) - }); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6)), Some(vec![auth1(), auth2()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1_1)), Some(vec![auth5()])); - let hash6_1_2 = insert_non_best_block(&db, make_authorities(vec![auth6()]), || { - default_header(&hash6_1, 8) - }); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6)), Some(vec![auth1(), auth2()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1_1)), Some(vec![auth5()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1_2)), Some(vec![auth6()])); - let hash6_2 = - insert_block(&db, make_authorities(vec![auth4()]), || default_header(&hash6_1, 8)); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6)), Some(vec![auth1(), auth2()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1_1)), Some(vec![auth5()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1_2)), Some(vec![auth6()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_2)), Some(vec![auth4()])); - - (hash7, hash8, hash6_1, hash6_2, hash6_1_1, hash6_1_2) - }; - - { - // finalize block hash6_1 - db.finalize_header(BlockId::Hash(hash6_1)).unwrap(); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6)), Some(vec![auth1(), auth2()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash7)), None); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash8)), None); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1_1)), Some(vec![auth5()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1_2)), Some(vec![auth6()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_2)), Some(vec![auth4()])); - // finalize block hash6_2 - db.finalize_header(BlockId::Hash(hash6_2)).unwrap(); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6)), Some(vec![auth1(), auth2()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash7)), None); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash8)), None); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1_1)), None); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_1_2)), None); - assert_eq!(authorities(db.cache(), BlockId::Hash(hash6_2)), Some(vec![auth4()])); - } - } - - #[test] - fn database_is_reopened() { - let db = LightStorage::new_test(); - let hash0 = - insert_final_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); - assert_eq!(db.info().best_hash, hash0); - assert_eq!(db.header(BlockId::Hash(hash0)).unwrap().unwrap().hash(), hash0); - - let db = db.db; - let db = LightStorage::from_kvdb(db).unwrap(); - assert_eq!(db.info().best_hash, hash0); - assert_eq!(db.header(BlockId::Hash::(hash0)).unwrap().unwrap().hash(), hash0); - } - - #[test] - fn aux_store_works() { - let db = LightStorage::::new_test(); - - // insert aux1 + aux2 using direct store access - db.insert_aux(&[(&[1][..], &[101][..]), (&[2][..], &[102][..])], ::std::iter::empty()) - .unwrap(); - - // check aux values - assert_eq!(db.get_aux(&[1]).unwrap(), Some(vec![101])); - assert_eq!(db.get_aux(&[2]).unwrap(), Some(vec![102])); - assert_eq!(db.get_aux(&[3]).unwrap(), None); - - // delete aux1 + insert aux3 using import operation - db.import_header( - default_header(&Default::default(), 0), - HashMap::new(), - NewBlockState::Best, - vec![(vec![3], Some(vec![103])), (vec![1], None)], - ) - .unwrap(); - - // check aux values - assert_eq!(db.get_aux(&[1]).unwrap(), None); - assert_eq!(db.get_aux(&[2]).unwrap(), Some(vec![102])); - assert_eq!(db.get_aux(&[3]).unwrap(), Some(vec![103])); - } - - #[test] - fn cache_can_be_initialized_after_genesis_inserted() { - let (genesis_hash, storage) = { - let db = LightStorage::::new_test(); - - // before cache is initialized => Err - assert!(db.cache().get_at(b"test", &BlockId::Number(0)).is_err()); - - // insert genesis block (no value for cache is provided) - let mut genesis_hash = None; - insert_block(&db, HashMap::new(), || { - let header = default_header(&Default::default(), 0); - genesis_hash = Some(header.hash()); - header - }); - - // after genesis is inserted => None - assert_eq!(db.cache().get_at(b"test", &BlockId::Number(0)).unwrap(), None); - - // initialize cache - db.cache().initialize(b"test", vec![42]).unwrap(); - - // after genesis is inserted + cache is initialized => Some - assert_eq!( - db.cache().get_at(b"test", &BlockId::Number(0)).unwrap(), - Some(((0, genesis_hash.unwrap()), None, vec![42])), - ); - - (genesis_hash, db.db) - }; - - // restart && check that after restart value is read from the cache - let db = - LightStorage::::from_kvdb(storage as Arc<_>).expect("failed to create test-db"); - assert_eq!( - db.cache().get_at(b"test", &BlockId::Number(0)).unwrap(), - Some(((0, genesis_hash.unwrap()), None, vec![42])), - ); - } - - #[test] - fn changes_trie_configuration_is_tracked_on_light_client() { - let db = LightStorage::::new_test(); - - let new_config = Some(ChangesTrieConfiguration::new(2, 2)); - - // insert block#0 && block#1 (no value for cache is provided) - let hash0 = insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); - assert_eq!( - db.cache() - .get_at(&well_known_cache_keys::CHANGES_TRIE_CONFIG, &BlockId::Number(0)) - .unwrap() - .map(|(_, _, v)| ChangesTrieConfiguration::decode(&mut &v[..]).unwrap()), - None, - ); - - // insert configuration at block#1 (starts from block#2) - insert_block(&db, HashMap::new(), || { - let mut header = default_header(&hash0, 1); - header.digest_mut().push(DigestItem::ChangesTrieSignal( - ChangesTrieSignal::NewConfiguration(new_config.clone()), - )); - header - }); - assert_eq!( - db.cache() - .get_at(&well_known_cache_keys::CHANGES_TRIE_CONFIG, &BlockId::Number(1)) - .unwrap() - .map(|(_, _, v)| Option::::decode(&mut &v[..]).unwrap()), - Some(new_config), - ); - } -} diff --git a/client/db/src/parity_db.rs b/client/db/src/parity_db.rs index 1b645ca9fb2b9..61c0b94dc701c 100644 --- a/client/db/src/parity_db.rs +++ b/client/db/src/parity_db.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . use crate::{ - columns, light, + columns, utils::{DatabaseType, NUM_COLUMNS}, }; /// A `Database` adapter for parity-db. @@ -61,10 +61,6 @@ pub fn open>( state_col.preimage = true; state_col.uniform = true; }, - DatabaseType::Light => { - config.columns[light::columns::HEADER as usize].compression = - parity_db::CompressionType::Lz4; - }, } let db = if create { diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index 0e895eaaf3851..b098a7864bafb 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -56,10 +56,6 @@ pub mod meta_keys { pub const FINALIZED_STATE: &[u8; 6] = b"fstate"; /// Block gap. pub const BLOCK_GAP: &[u8; 3] = b"gap"; - /// Meta information prefix for list-based caches. - pub const CACHE_META_PREFIX: &[u8; 5] = b"cache"; - /// Meta information for changes tries key. - pub const CHANGES_TRIES_META: &[u8; 5] = b"ctrie"; /// Genesis block hash. pub const GENESIS_HASH: &[u8; 3] = b"gen"; /// Leaves prefix list key. @@ -95,8 +91,6 @@ pub type NumberIndexKey = [u8; 4]; pub enum DatabaseType { /// Full node database. Full, - /// Light node database. - Light, } /// Convert block number into short lookup key (LE representation) for @@ -124,19 +118,6 @@ where Ok(lookup_key) } -/// Convert block lookup key into block number. -/// all block lookup keys start with the block number. -pub fn lookup_key_to_number(key: &[u8]) -> sp_blockchain::Result -where - N: From, -{ - if key.len() < 4 { - return Err(sp_blockchain::Error::Backend("Invalid block key".into())) - } - Ok((key[0] as u32) << 24 | (key[1] as u32) << 16 | (key[2] as u32) << 8 | (key[3] as u32)) - .map(Into::into) -} - /// Delete number to hash mapping in DB transaction. pub fn remove_number_to_key_mapping>( transaction: &mut Transaction, @@ -147,18 +128,6 @@ pub fn remove_number_to_key_mapping>( Ok(()) } -/// Remove key mappings. -pub fn remove_key_mappings, H: AsRef<[u8]>>( - transaction: &mut Transaction, - key_lookup_col: u32, - number: N, - hash: H, -) -> sp_blockchain::Result<()> { - remove_number_to_key_mapping(transaction, key_lookup_col, number)?; - transaction.remove(key_lookup_col, hash.as_ref()); - Ok(()) -} - /// Place a number mapping into the database. This maps number to current perceived /// block hash at that position. pub fn insert_number_to_key_mapping + Clone, H: AsRef<[u8]>>( @@ -357,18 +326,6 @@ fn open_kvdb_rocksdb( other_col_budget, ); }, - DatabaseType::Light => { - let col_budget = cache_size / (NUM_COLUMNS as usize); - for i in 0..NUM_COLUMNS { - memory_budget.insert(i, col_budget); - } - log::trace!( - target: "db", - "Open RocksDB light database at {:?}, column cache: {} MiB", - path, - col_budget, - ); - }, } db_config.memory_budget = memory_budget; @@ -424,8 +381,7 @@ fn maybe_migrate_to_type_subdir( // See if there's a file identifying a rocksdb or paritydb folder in the parent dir and // the target path ends in a role specific directory if (basedir.join("db_version").exists() || basedir.join("metadata").exists()) && - (p.ends_with(DatabaseType::Full.as_str()) || - p.ends_with(DatabaseType::Light.as_str())) + (p.ends_with(DatabaseType::Full.as_str())) { // Try to open the database to check if the current `DatabaseType` matches the type of // database stored in the target directory and close the database on success. @@ -501,18 +457,6 @@ pub fn read_header( } } -/// Required header from the database. -pub fn require_header( - db: &dyn Database, - col_index: u32, - col: u32, - id: BlockId, -) -> sp_blockchain::Result { - read_header(db, col_index, col, id).and_then(|header| { - header.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("Require header: {}", id))) - }) -} - /// Read meta from the database. pub fn read_meta( db: &dyn Database, @@ -598,7 +542,6 @@ impl DatabaseType { pub fn as_str(&self) -> &'static str { match *self { DatabaseType::Full => "full", - DatabaseType::Light => "light", } } } @@ -669,23 +612,12 @@ mod tests { assert!(old_db_path.join(db_type.as_str()).join(db_check_file).exists()); } - check_dir_for_db_type( - DatabaseType::Light, - DatabaseSource::RocksDb { path: PathBuf::new(), cache_size: 128 }, - "db_version", - ); check_dir_for_db_type( DatabaseType::Full, DatabaseSource::RocksDb { path: PathBuf::new(), cache_size: 128 }, "db_version", ); - #[cfg(feature = "with-parity-db")] - check_dir_for_db_type( - DatabaseType::Light, - DatabaseSource::ParityDb { path: PathBuf::new() }, - "metadata", - ); #[cfg(feature = "with-parity-db")] check_dir_for_db_type( DatabaseType::Full, @@ -709,16 +641,8 @@ mod tests { assert!(!old_db_path.join("light/db_version").exists()); assert!(!old_db_path.join("full/db_version").exists()); } - let source = DatabaseSource::RocksDb { - path: old_db_path.join(DatabaseType::Light.as_str()), - cache_size: 128, - }; - let settings = db_settings(source); - let db_res = open_database::(&settings, DatabaseType::Light); - assert!(db_res.is_err(), "Opening a light database in full role should fail"); // assert nothing was changed assert!(old_db_path.join("db_version").exists()); - assert!(!old_db_path.join("light/db_version").exists()); assert!(!old_db_path.join("full/db_version").exists()); } } @@ -735,7 +659,6 @@ mod tests { #[test] fn database_type_as_str_works() { assert_eq!(DatabaseType::Full.as_str(), "full"); - assert_eq!(DatabaseType::Light.as_str(), "light"); } #[test] diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 1cded769c6856..7aa02a61dba11 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -40,7 +40,7 @@ use tracing_subscriber::layer::SubscriberExt; use crate::WasmExecutionMethod; -pub type TestExternalities = CoreTestExternalities; +pub type TestExternalities = CoreTestExternalities; type HostFunctions = sp_io::SubstrateHostFunctions; /// Simple macro that runs a given method as test with the available wasm execution methods. diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index d54f7234b44b4..000f7397ac9d9 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -19,7 +19,7 @@ use std::{collections::HashMap, marker::PhantomData, sync::Arc}; use log::debug; -use parity_scale_codec::{Decode, Encode}; +use parity_scale_codec::Decode; use sc_client_api::{backend::Backend, utils::is_descendent_of}; use sc_consensus::{ @@ -35,7 +35,7 @@ use sp_core::hashing::twox_128; use sp_finality_grandpa::{ConsensusLog, GrandpaApi, ScheduledChange, SetId, GRANDPA_ENGINE_ID}; use sp_runtime::{ generic::{BlockId, OpaqueDigestItemId}, - traits::{Block as BlockT, DigestFor, Header as HeaderT, NumberFor, Zero}, + traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, Justification, }; @@ -89,7 +89,6 @@ impl JustificationImport for GrandpaBlockImport where NumberFor: finality_grandpa::BlockNumberOps, - DigestFor: Encode, BE: Backend, Client: ClientForGrandpa, SC: SelectChain, @@ -229,7 +228,6 @@ pub fn find_forced_change( impl GrandpaBlockImport where NumberFor: finality_grandpa::BlockNumberOps, - DigestFor: Encode, BE: Backend, Client: ClientForGrandpa, Client::Api: GrandpaApi, @@ -515,7 +513,6 @@ where impl BlockImport for GrandpaBlockImport where NumberFor: finality_grandpa::BlockNumberOps, - DigestFor: Encode, BE: Backend, Client: ClientForGrandpa, Client::Api: GrandpaApi, diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 452659ced6a70..e7618929fd089 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -58,7 +58,7 @@ use futures::{prelude::*, StreamExt}; use log::{debug, error, info}; -use parity_scale_codec::{Decode, Encode}; +use parity_scale_codec::Decode; use parking_lot::RwLock; use prometheus_endpoint::{PrometheusError, Registry}; use sc_client_api::{ @@ -77,7 +77,7 @@ use sp_core::crypto::Public; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, DigestFor, NumberFor, Zero}, + traits::{Block as BlockT, NumberFor, Zero}, }; pub use finality_grandpa::BlockNumberOps; @@ -718,7 +718,6 @@ where SC: SelectChain + 'static, VR: VotingRule + Clone + 'static, NumberFor: BlockNumberOps, - DigestFor: Encode, C: ClientForGrandpa + 'static, C::Api: GrandpaApi, { diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 1aef7cd1b017a..8439bf6963d01 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -43,6 +43,7 @@ use sp_finality_grandpa::{ use sp_keyring::Ed25519Keyring; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ + codec::Encode, generic::{BlockId, DigestItem}, traits::{Block as BlockT, Header as HeaderT}, Justifications, @@ -139,26 +140,16 @@ impl TestNetFactory for GrandpaTestNet { &self, client: PeersClient, ) -> (BlockImportAdapter, Option>, PeerData) { - match client { - PeersClient::Full(ref client, ref backend) => { - let (import, link) = block_import( - client.clone(), - &self.test_config, - LongestChain::new(backend.clone()), - None, - ) - .expect("Could not create block import for fresh peer."); - let justification_import = Box::new(import.clone()); - ( - BlockImportAdapter::new(import), - Some(justification_import), - Mutex::new(Some(link)), - ) - }, - PeersClient::Light(..) => { - panic!("Light client is not used in tests."); - }, - } + let (client, backend) = (client.as_client(), client.as_backend()); + let (import, link) = block_import( + client.clone(), + &self.test_config, + LongestChain::new(backend.clone()), + None, + ) + .expect("Could not create block import for fresh peer."); + let justification_import = Box::new(import.clone()); + (BlockImportAdapter::new(import), Some(justification_import), Mutex::new(Some(link))) } fn peer(&mut self, i: usize) -> &mut GrandpaPeer { @@ -466,7 +457,7 @@ fn finalize_3_voters_1_full_observer() { // all peers should have stored the justification for the best finalized block #20 for peer_id in 0..4 { - let client = net.lock().peers[peer_id].client().as_full().unwrap(); + let client = net.lock().peers[peer_id].client().as_client(); let justification = crate::aux_schema::best_justification::<_, Block>(&*client).unwrap().unwrap(); @@ -539,7 +530,7 @@ fn transition_3_voters_twice_1_full_observer() { net.lock().block_until_sync(); for (i, peer) in net.lock().peers().iter().enumerate() { - let full_client = peer.client().as_full().expect("only full clients are used in test"); + let full_client = peer.client().as_client(); assert_eq!(full_client.chain_info().best_number, 1, "Peer #{} failed to sync", i); let set: AuthoritySet = @@ -614,7 +605,7 @@ fn transition_3_voters_twice_1_full_observer() { .take_while(|n| future::ready(n.header.number() < &30)) .for_each(move |_| future::ready(())) .map(move |()| { - let full_client = client.as_full().expect("only full clients are used in test"); + let full_client = client.as_client(); let set: AuthoritySet = crate::aux_schema::load_authorities(&*full_client).unwrap(); @@ -835,7 +826,7 @@ fn force_change_to_new_set() { for (i, peer) in net.lock().peers().iter().enumerate() { assert_eq!(peer.client().info().best_number, 26, "Peer #{} failed to sync", i); - let full_client = peer.client().as_full().expect("only full clients are used in test"); + let full_client = peer.client().as_client(); let set: AuthoritySet = crate::aux_schema::load_authorities(&*full_client).unwrap(); @@ -861,7 +852,7 @@ fn allows_reimporting_change_blocks() { let client = net.peer(0).client().clone(); let (mut block_import, ..) = net.make_block_import(client.clone()); - let full_client = client.as_full().unwrap(); + let full_client = client.as_client(); let builder = full_client .new_block_at(&BlockId::Number(0), Default::default(), false) .unwrap(); @@ -908,7 +899,7 @@ fn test_bad_justification() { let client = net.peer(0).client().clone(); let (mut block_import, ..) = net.make_block_import(client.clone()); - let full_client = client.as_full().expect("only full clients are used in test"); + let full_client = client.as_client(); let builder = full_client .new_block_at(&BlockId::Number(0), Default::default(), false) .unwrap(); @@ -1148,7 +1139,7 @@ fn voter_persists_its_votes() { .await; let block_30_hash = - net.lock().peer(0).client().as_full().unwrap().hash(30).unwrap().unwrap(); + net.lock().peer(0).client().as_client().hash(30).unwrap().unwrap(); // we restart alice's voter abort.abort(); @@ -1581,7 +1572,7 @@ fn imports_justification_for_regular_blocks_on_import() { let client = net.peer(0).client().clone(); let (mut block_import, ..) = net.make_block_import(client.clone()); - let full_client = client.as_full().expect("only full clients are used in test"); + let full_client = client.as_client(); let builder = full_client .new_block_at(&BlockId::Number(0), Default::default(), false) .unwrap(); diff --git a/client/light/Cargo.toml b/client/light/Cargo.toml deleted file mode 100644 index 1b83bf5be42f4..0000000000000 --- a/client/light/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -description = "components for a light client" -name = "sc-light" -version = "4.0.0-dev" -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -authors = ["Parity Technologies "] -edition = "2021" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -documentation = "https://docs.rs/sc-light" -readme = "README.md" - -[dependencies] -parking_lot = "0.11.1" -hash-db = "0.15.2" -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } -sp-externalities = { version = "0.10.0-dev", path = "../../primitives/externalities" } -sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } -sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } -sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -codec = { package = "parity-scale-codec", version = "2.0.0" } -sc-executor = { version = "0.10.0-dev", path = "../executor" } - -[features] -default = [] diff --git a/client/light/README.md b/client/light/README.md deleted file mode 100644 index 1ba1f155b1652..0000000000000 --- a/client/light/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Light client components. - -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file diff --git a/client/light/src/backend.rs b/client/light/src/backend.rs deleted file mode 100644 index 3091dce625a3f..0000000000000 --- a/client/light/src/backend.rs +++ /dev/null @@ -1,578 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Light client backend. Only stores headers and justifications of blocks. -//! Everything else is requested from full nodes on demand. - -use parking_lot::RwLock; -use std::{ - collections::{HashMap, HashSet}, - sync::Arc, -}; - -use codec::{Decode, Encode}; - -use super::blockchain::Blockchain; -use hash_db::Hasher; -use sc_client_api::{ - backend::{ - AuxStore, Backend as ClientBackend, BlockImportOperation, NewBlockState, - PrunableStateChangesTrieStorage, RemoteBackend, - }, - blockchain::{well_known_cache_keys, HeaderBackend as BlockchainHeaderBackend}, - in_mem::check_genesis_storage, - light::Storage as BlockchainStorage, - UsageInfo, -}; -use sp_blockchain::{Error as ClientError, Result as ClientResult}; -use sp_core::{ - offchain::storage::InMemOffchainStorage, - storage::{well_known_keys, ChildInfo}, - ChangesTrieConfiguration, -}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, HashFor, Header, NumberFor, Zero}, - Justification, Justifications, Storage, -}; -use sp_state_machine::{ - Backend as StateBackend, ChangesTrieTransaction, ChildStorageCollection, InMemoryBackend, - IndexOperation, StorageCollection, TrieBackend, -}; - -const IN_MEMORY_EXPECT_PROOF: &str = - "InMemory state backend has Void error type and always succeeds; qed"; - -/// Light client backend. -pub struct Backend { - blockchain: Arc>, - genesis_state: RwLock>>, - import_lock: RwLock<()>, -} - -/// Light block (header and justification) import operation. -pub struct ImportOperation { - header: Option, - cache: HashMap>, - leaf_state: NewBlockState, - aux_ops: Vec<(Vec, Option>)>, - finalized_blocks: Vec>, - set_head: Option>, - storage_update: Option>>, - changes_trie_config_update: Option>, - _phantom: std::marker::PhantomData, -} - -/// Either in-memory genesis state, or locally-unavailable state. -pub enum GenesisOrUnavailableState { - /// Genesis state - storage values are stored in-memory. - Genesis(InMemoryBackend), - /// We know that state exists, but all calls will fail with error, because it - /// isn't locally available. - Unavailable, -} - -impl Backend { - /// Create new light backend. - pub fn new(blockchain: Arc>) -> Self { - Self { blockchain, genesis_state: RwLock::new(None), import_lock: Default::default() } - } - - /// Get shared blockchain reference. - pub fn blockchain(&self) -> &Arc> { - &self.blockchain - } -} - -impl AuxStore for Backend { - fn insert_aux< - 'a, - 'b: 'a, - 'c: 'a, - I: IntoIterator, - D: IntoIterator, - >( - &self, - insert: I, - delete: D, - ) -> ClientResult<()> { - self.blockchain.storage().insert_aux(insert, delete) - } - - fn get_aux(&self, key: &[u8]) -> ClientResult>> { - self.blockchain.storage().get_aux(key) - } -} - -impl ClientBackend for Backend> -where - Block: BlockT, - S: BlockchainStorage, - Block::Hash: Ord, -{ - type BlockImportOperation = ImportOperation; - type Blockchain = Blockchain; - type State = GenesisOrUnavailableState>; - type OffchainStorage = InMemOffchainStorage; - - fn begin_operation(&self) -> ClientResult { - Ok(ImportOperation { - header: None, - cache: Default::default(), - leaf_state: NewBlockState::Normal, - aux_ops: Vec::new(), - finalized_blocks: Vec::new(), - set_head: None, - storage_update: None, - changes_trie_config_update: None, - _phantom: Default::default(), - }) - } - - fn begin_state_operation( - &self, - _operation: &mut Self::BlockImportOperation, - _block: BlockId, - ) -> ClientResult<()> { - Ok(()) - } - - fn commit_operation(&self, mut operation: Self::BlockImportOperation) -> ClientResult<()> { - if !operation.finalized_blocks.is_empty() { - for block in operation.finalized_blocks { - self.blockchain.storage().finalize_header(block)?; - } - } - - if let Some(header) = operation.header { - let is_genesis_import = header.number().is_zero(); - if let Some(new_config) = operation.changes_trie_config_update { - operation - .cache - .insert(well_known_cache_keys::CHANGES_TRIE_CONFIG, new_config.encode()); - } - self.blockchain.storage().import_header( - header, - operation.cache, - operation.leaf_state, - operation.aux_ops, - )?; - - // when importing genesis block => remember its state - if is_genesis_import { - *self.genesis_state.write() = operation.storage_update.take(); - } - } else { - for (key, maybe_val) in operation.aux_ops { - match maybe_val { - Some(val) => self - .blockchain - .storage() - .insert_aux(&[(&key[..], &val[..])], std::iter::empty())?, - None => - self.blockchain.storage().insert_aux(std::iter::empty(), &[&key[..]])?, - } - } - } - - if let Some(set_head) = operation.set_head { - self.blockchain.storage().set_head(set_head)?; - } - - Ok(()) - } - - fn finalize_block( - &self, - block: BlockId, - _justification: Option, - ) -> ClientResult<()> { - self.blockchain.storage().finalize_header(block) - } - - fn append_justification( - &self, - _block: BlockId, - _justification: Justification, - ) -> ClientResult<()> { - Ok(()) - } - - fn blockchain(&self) -> &Blockchain { - &self.blockchain - } - - fn usage_info(&self) -> Option { - self.blockchain.storage().usage_info() - } - - fn changes_trie_storage(&self) -> Option<&dyn PrunableStateChangesTrieStorage> { - None - } - - fn offchain_storage(&self) -> Option { - None - } - - fn state_at(&self, block: BlockId) -> ClientResult { - let block_number = self.blockchain.expect_block_number_from_id(&block)?; - - // special case for genesis block - if block_number.is_zero() { - if let Some(genesis_state) = self.genesis_state.read().clone() { - return Ok(GenesisOrUnavailableState::Genesis(genesis_state)) - } - } - - // else return unavailable state. We do not return error here, because error - // would mean that we do not know this state at all. But we know that it exists - Ok(GenesisOrUnavailableState::Unavailable) - } - - fn revert( - &self, - _n: NumberFor, - _revert_finalized: bool, - ) -> ClientResult<(NumberFor, HashSet)> { - Err(ClientError::NotAvailableOnLightClient) - } - - fn remove_leaf_block(&self, _hash: &Block::Hash) -> ClientResult<()> { - Err(ClientError::NotAvailableOnLightClient) - } - - fn get_import_lock(&self) -> &RwLock<()> { - &self.import_lock - } -} - -impl RemoteBackend for Backend> -where - Block: BlockT, - S: BlockchainStorage + 'static, - Block::Hash: Ord, -{ - fn is_local_state_available(&self, block: &BlockId) -> bool { - self.genesis_state.read().is_some() && - self.blockchain - .expect_block_number_from_id(block) - .map(|num| num.is_zero()) - .unwrap_or(false) - } - - fn remote_blockchain(&self) -> Arc> { - self.blockchain.clone() - } -} - -impl BlockImportOperation for ImportOperation -where - Block: BlockT, - S: BlockchainStorage, - Block::Hash: Ord, -{ - type State = GenesisOrUnavailableState>; - - fn state(&self) -> ClientResult> { - // None means 'locally-stateless' backend - Ok(None) - } - - fn set_block_data( - &mut self, - header: Block::Header, - _body: Option>, - _indexed_body: Option>>, - _justifications: Option, - state: NewBlockState, - ) -> ClientResult<()> { - self.leaf_state = state; - self.header = Some(header); - Ok(()) - } - - fn update_cache(&mut self, cache: HashMap>) { - self.cache = cache; - } - - fn update_db_storage( - &mut self, - _update: >>::Transaction, - ) -> ClientResult<()> { - // we're not storing anything locally => ignore changes - Ok(()) - } - - fn update_changes_trie( - &mut self, - _update: ChangesTrieTransaction, NumberFor>, - ) -> ClientResult<()> { - // we're not storing anything locally => ignore changes - Ok(()) - } - - fn set_genesis_state(&mut self, input: Storage, commit: bool) -> ClientResult { - check_genesis_storage(&input)?; - - // changes trie configuration - let changes_trie_config = input - .top - .iter() - .find(|(k, _)| &k[..] == well_known_keys::CHANGES_TRIE_CONFIG) - .map(|(_, v)| { - Decode::decode(&mut &v[..]) - .expect("changes trie configuration is encoded properly at genesis") - }); - self.changes_trie_config_update = Some(changes_trie_config); - - // this is only called when genesis block is imported => shouldn't be performance bottleneck - let mut storage: HashMap, _> = HashMap::new(); - storage.insert(None, input.top); - - // create a list of children keys to re-compute roots for - let child_delta = input - .children_default - .iter() - .map(|(_storage_key, storage_child)| (&storage_child.child_info, std::iter::empty())); - - // make sure to persist the child storage - for (_child_key, storage_child) in input.children_default.clone() { - storage.insert(Some(storage_child.child_info), storage_child.data); - } - - let storage_update = InMemoryBackend::from(storage); - let (storage_root, _) = storage_update.full_storage_root(std::iter::empty(), child_delta); - if commit { - self.storage_update = Some(storage_update); - } - - Ok(storage_root) - } - - fn reset_storage(&mut self, _input: Storage) -> ClientResult { - Err(ClientError::NotAvailableOnLightClient) - } - - fn insert_aux(&mut self, ops: I) -> ClientResult<()> - where - I: IntoIterator, Option>)>, - { - self.aux_ops.append(&mut ops.into_iter().collect()); - Ok(()) - } - - fn update_storage( - &mut self, - _update: StorageCollection, - _child_update: ChildStorageCollection, - ) -> ClientResult<()> { - // we're not storing anything locally => ignore changes - Ok(()) - } - - fn mark_finalized( - &mut self, - block: BlockId, - _justifications: Option, - ) -> ClientResult<()> { - self.finalized_blocks.push(block); - Ok(()) - } - - fn mark_head(&mut self, block: BlockId) -> ClientResult<()> { - self.set_head = Some(block); - Ok(()) - } - - fn update_transaction_index( - &mut self, - _index: Vec, - ) -> sp_blockchain::Result<()> { - // noop for the light client - Ok(()) - } -} - -impl std::fmt::Debug for GenesisOrUnavailableState { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => state.fmt(f), - GenesisOrUnavailableState::Unavailable => write!(f, "Unavailable"), - } - } -} - -impl StateBackend for GenesisOrUnavailableState -where - H::Out: Ord + codec::Codec, -{ - type Error = ClientError; - type Transaction = as StateBackend>::Transaction; - type TrieBackendStorage = as StateBackend>::TrieBackendStorage; - - fn storage(&self, key: &[u8]) -> ClientResult>> { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => - Ok(state.storage(key).expect(IN_MEMORY_EXPECT_PROOF)), - GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient), - } - } - - fn child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> ClientResult>> { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => - Ok(state.child_storage(child_info, key).expect(IN_MEMORY_EXPECT_PROOF)), - GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient), - } - } - - fn next_storage_key(&self, key: &[u8]) -> Result>, Self::Error> { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => - Ok(state.next_storage_key(key).expect(IN_MEMORY_EXPECT_PROOF)), - GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient), - } - } - - fn next_child_storage_key( - &self, - child_info: &ChildInfo, - key: &[u8], - ) -> Result>, Self::Error> { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => - Ok(state.next_child_storage_key(child_info, key).expect(IN_MEMORY_EXPECT_PROOF)), - GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient), - } - } - - fn for_keys_with_prefix(&self, prefix: &[u8], action: A) { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => - state.for_keys_with_prefix(prefix, action), - GenesisOrUnavailableState::Unavailable => (), - } - } - - fn for_key_values_with_prefix(&self, prefix: &[u8], action: A) { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => - state.for_key_values_with_prefix(prefix, action), - GenesisOrUnavailableState::Unavailable => (), - } - } - - fn apply_to_key_values_while, Vec) -> bool>( - &self, - child_info: Option<&ChildInfo>, - prefix: Option<&[u8]>, - start_at: Option<&[u8]>, - action: A, - allow_missing: bool, - ) -> ClientResult { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => Ok(state - .apply_to_key_values_while(child_info, prefix, start_at, action, allow_missing) - .expect(IN_MEMORY_EXPECT_PROOF)), - GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient), - } - } - - fn apply_to_keys_while bool>( - &self, - child_info: Option<&ChildInfo>, - prefix: Option<&[u8]>, - action: A, - ) { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => - state.apply_to_keys_while(child_info, prefix, action), - GenesisOrUnavailableState::Unavailable => (), - } - } - - fn for_child_keys_with_prefix( - &self, - child_info: &ChildInfo, - prefix: &[u8], - action: A, - ) { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => - state.for_child_keys_with_prefix(child_info, prefix, action), - GenesisOrUnavailableState::Unavailable => (), - } - } - - fn storage_root<'a>( - &self, - delta: impl Iterator)>, - ) -> (H::Out, Self::Transaction) - where - H::Out: Ord, - { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => state.storage_root(delta), - GenesisOrUnavailableState::Unavailable => Default::default(), - } - } - - fn child_storage_root<'a>( - &self, - child_info: &ChildInfo, - delta: impl Iterator)>, - ) -> (H::Out, bool, Self::Transaction) - where - H::Out: Ord, - { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => { - let (root, is_equal, _) = state.child_storage_root(child_info, delta); - (root, is_equal, Default::default()) - }, - GenesisOrUnavailableState::Unavailable => (H::Out::default(), true, Default::default()), - } - } - - fn pairs(&self) -> Vec<(Vec, Vec)> { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => state.pairs(), - GenesisOrUnavailableState::Unavailable => Vec::new(), - } - } - - fn keys(&self, prefix: &[u8]) -> Vec> { - match *self { - GenesisOrUnavailableState::Genesis(ref state) => state.keys(prefix), - GenesisOrUnavailableState::Unavailable => Vec::new(), - } - } - - fn register_overlay_stats(&self, _stats: &sp_state_machine::StateMachineStats) {} - - fn usage_info(&self) -> sp_state_machine::UsageInfo { - sp_state_machine::UsageInfo::empty() - } - - fn as_trie_backend(&self) -> Option<&TrieBackend> { - match self { - GenesisOrUnavailableState::Genesis(ref state) => state.as_trie_backend(), - GenesisOrUnavailableState::Unavailable => None, - } - } -} diff --git a/client/light/src/blockchain.rs b/client/light/src/blockchain.rs deleted file mode 100644 index 24d9ef4fd4b95..0000000000000 --- a/client/light/src/blockchain.rs +++ /dev/null @@ -1,219 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Light client blockchain backend. Only stores headers and justifications of recent -//! blocks. CHT roots are stored for headers of ancient blocks. - -use std::sync::Arc; - -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, - Justifications, -}; - -use sc_client_api::light::RemoteHeaderRequest; -pub use sc_client_api::{ - backend::{AuxStore, NewBlockState, ProvideChtRoots}, - blockchain::{ - well_known_cache_keys, Backend as BlockchainBackend, BlockStatus, Cache as BlockchainCache, - HeaderBackend as BlockchainHeaderBackend, Info as BlockchainInfo, ProvideCache, - }, - cht, - light::{LocalOrRemote, RemoteBlockchain, Storage}, -}; -use sp_blockchain::{ - CachedHeaderMetadata, Error as ClientError, HeaderMetadata, Result as ClientResult, -}; - -/// Light client blockchain. -pub struct Blockchain { - storage: S, -} - -impl Blockchain { - /// Create new light blockchain backed with given storage. - pub fn new(storage: S) -> Self { - Self { storage } - } - - /// Get storage reference. - pub fn storage(&self) -> &S { - &self.storage - } -} - -impl BlockchainHeaderBackend for Blockchain -where - Block: BlockT, - S: Storage, -{ - fn header(&self, id: BlockId) -> ClientResult> { - match RemoteBlockchain::header(self, id)? { - LocalOrRemote::Local(header) => Ok(Some(header)), - LocalOrRemote::Remote(_) => Err(ClientError::NotAvailableOnLightClient), - LocalOrRemote::Unknown => Ok(None), - } - } - - fn info(&self) -> BlockchainInfo { - self.storage.info() - } - - fn status(&self, id: BlockId) -> ClientResult { - self.storage.status(id) - } - - fn number(&self, hash: Block::Hash) -> ClientResult>> { - self.storage.number(hash) - } - - fn hash( - &self, - number: <::Header as HeaderT>::Number, - ) -> ClientResult> { - self.storage.hash(number) - } -} - -impl HeaderMetadata for Blockchain -where - Block: BlockT, - S: Storage, -{ - type Error = ClientError; - - fn header_metadata( - &self, - hash: Block::Hash, - ) -> Result, Self::Error> { - self.storage.header_metadata(hash) - } - - fn insert_header_metadata(&self, hash: Block::Hash, metadata: CachedHeaderMetadata) { - self.storage.insert_header_metadata(hash, metadata) - } - - fn remove_header_metadata(&self, hash: Block::Hash) { - self.storage.remove_header_metadata(hash) - } -} - -impl BlockchainBackend for Blockchain -where - Block: BlockT, - S: Storage, -{ - fn body(&self, _id: BlockId) -> ClientResult>> { - Err(ClientError::NotAvailableOnLightClient) - } - - fn justifications(&self, _id: BlockId) -> ClientResult> { - Err(ClientError::NotAvailableOnLightClient) - } - - fn last_finalized(&self) -> ClientResult { - self.storage.last_finalized() - } - - fn cache(&self) -> Option>> { - self.storage.cache() - } - - fn leaves(&self) -> ClientResult> { - Err(ClientError::NotAvailableOnLightClient) - } - - fn children(&self, _parent_hash: Block::Hash) -> ClientResult> { - Err(ClientError::NotAvailableOnLightClient) - } - - fn indexed_transaction(&self, _hash: &Block::Hash) -> ClientResult>> { - Err(ClientError::NotAvailableOnLightClient) - } - - fn block_indexed_body( - &self, - _id: BlockId, - ) -> sp_blockchain::Result>>> { - Err(ClientError::NotAvailableOnLightClient) - } -} - -impl, Block: BlockT> ProvideCache for Blockchain { - fn cache(&self) -> Option>> { - self.storage.cache() - } -} - -impl RemoteBlockchain for Blockchain -where - S: Storage, -{ - fn header( - &self, - id: BlockId, - ) -> ClientResult>> { - // first, try to read header from local storage - if let Some(local_header) = self.storage.header(id)? { - return Ok(LocalOrRemote::Local(local_header)) - } - - // we need to know block number to check if it's a part of CHT - let number = match id { - BlockId::Hash(hash) => match self.storage.number(hash)? { - Some(number) => number, - None => return Ok(LocalOrRemote::Unknown), - }, - BlockId::Number(number) => number, - }; - - // if the header is genesis (never pruned), non-canonical, or from future => return - if number.is_zero() || self.storage.status(BlockId::Number(number))? == BlockStatus::Unknown - { - return Ok(LocalOrRemote::Unknown) - } - - Ok(LocalOrRemote::Remote(RemoteHeaderRequest { - cht_root: match self.storage.header_cht_root(cht::size(), number)? { - Some(cht_root) => cht_root, - None => return Ok(LocalOrRemote::Unknown), - }, - block: number, - retry_count: None, - })) - } -} - -impl, Block: BlockT> ProvideChtRoots for Blockchain { - fn header_cht_root( - &self, - cht_size: NumberFor, - block: NumberFor, - ) -> sp_blockchain::Result> { - self.storage().header_cht_root(cht_size, block) - } - - fn changes_trie_cht_root( - &self, - cht_size: NumberFor, - block: NumberFor, - ) -> sp_blockchain::Result> { - self.storage().changes_trie_cht_root(cht_size, block) - } -} diff --git a/client/light/src/call_executor.rs b/client/light/src/call_executor.rs deleted file mode 100644 index a0776131e406d..0000000000000 --- a/client/light/src/call_executor.rs +++ /dev/null @@ -1,206 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Methods that light client could use to execute runtime calls. - -use std::{cell::RefCell, panic::UnwindSafe, result, sync::Arc}; - -use codec::{Decode, Encode}; -use hash_db::Hasher; -use sp_core::{ - convert_hash, - traits::{CodeExecutor, SpawnNamed}, - NativeOrEncoded, -}; -use sp_externalities::Extensions; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT}, -}; -use sp_state_machine::{ - create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionManager, - ExecutionStrategy, OverlayedChanges, StorageProof, -}; - -use sp_api::{ProofRecorder, StorageTransactionCache}; - -use sp_blockchain::{Error as ClientError, Result as ClientResult}; - -use sc_client_api::{ - backend::RemoteBackend, call_executor::CallExecutor, light::RemoteCallRequest, -}; -use sc_executor::RuntimeVersion; - -/// Call executor that is able to execute calls only on genesis state. -/// -/// Trying to execute call on non-genesis state leads to error. -pub struct GenesisCallExecutor { - backend: Arc, - local: L, -} - -impl GenesisCallExecutor { - /// Create new genesis call executor. - pub fn new(backend: Arc, local: L) -> Self { - Self { backend, local } - } -} - -impl Clone for GenesisCallExecutor { - fn clone(&self) -> Self { - GenesisCallExecutor { backend: self.backend.clone(), local: self.local.clone() } - } -} - -impl CallExecutor for GenesisCallExecutor -where - Block: BlockT, - B: RemoteBackend, - Local: CallExecutor, -{ - type Error = ClientError; - - type Backend = B; - - fn call( - &self, - id: &BlockId, - method: &str, - call_data: &[u8], - strategy: ExecutionStrategy, - extensions: Option, - ) -> ClientResult> { - if self.backend.is_local_state_available(id) { - self.local.call(id, method, call_data, strategy, extensions) - } else { - Err(ClientError::NotAvailableOnLightClient) - } - } - - fn contextual_call< - EM: Fn( - Result, Self::Error>, - Result, Self::Error>, - ) -> Result, Self::Error>, - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, - >( - &self, - at: &BlockId, - method: &str, - call_data: &[u8], - changes: &RefCell, - _: Option<&RefCell>>, - _manager: ExecutionManager, - native_call: Option, - recorder: &Option>, - extensions: Option, - ) -> ClientResult> - where - ExecutionManager: Clone, - { - // there's no actual way/need to specify native/wasm execution strategy on light node - // => we can safely ignore passed values - - if self.backend.is_local_state_available(at) { - CallExecutor::contextual_call::< - fn( - Result, Local::Error>, - Result, Local::Error>, - ) -> Result, Local::Error>, - _, - NC, - >( - &self.local, - at, - method, - call_data, - changes, - None, - ExecutionManager::NativeWhenPossible, - native_call, - recorder, - extensions, - ) - } else { - Err(ClientError::NotAvailableOnLightClient) - } - } - - fn prove_execution( - &self, - at: &BlockId, - method: &str, - call_data: &[u8], - ) -> ClientResult<(Vec, StorageProof)> { - if self.backend.is_local_state_available(at) { - self.local.prove_execution(at, method, call_data) - } else { - Err(ClientError::NotAvailableOnLightClient) - } - } - - fn runtime_version(&self, id: &BlockId) -> ClientResult { - if self.backend.is_local_state_available(id) { - self.local.runtime_version(id) - } else { - Err(ClientError::NotAvailableOnLightClient) - } - } -} - -/// Check remote contextual execution proof using given backend. -/// -/// Proof should include the method execution proof. -pub fn check_execution_proof( - executor: &E, - spawn_handle: Box, - request: &RemoteCallRequest

, - remote_proof: StorageProof, -) -> ClientResult> -where - Header: HeaderT, - E: CodeExecutor + Clone + 'static, - H: Hasher, - H::Out: Ord + codec::Codec + 'static, -{ - let local_state_root = request.header.state_root(); - let root: H::Out = convert_hash(&local_state_root); - - // prepare execution environment - let mut changes = OverlayedChanges::default(); - let trie_backend = create_proof_check_backend(root, remote_proof)?; - - // TODO: Remove when solved: https://github.com/paritytech/substrate/issues/5047 - let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&trie_backend); - let runtime_code = backend_runtime_code - .runtime_code() - .map_err(|_e| ClientError::RuntimeCodeMissing)?; - - // execute method - execution_proof_check_on_trie_backend::( - &trie_backend, - &mut changes, - executor, - spawn_handle, - &request.method, - &request.call_data, - &runtime_code, - ) - .map_err(Into::into) -} diff --git a/client/light/src/lib.rs b/client/light/src/lib.rs deleted file mode 100644 index 4b084cda0f8b1..0000000000000 --- a/client/light/src/lib.rs +++ /dev/null @@ -1,41 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Light client components. - -use sp_runtime::traits::{Block as BlockT, HashFor}; -use std::sync::Arc; - -pub mod backend; -pub mod blockchain; -pub mod call_executor; - -pub use backend::*; -pub use blockchain::*; -pub use call_executor::*; - -use sc_client_api::light::Storage as BlockchainStorage; - -/// Create an instance of light client backend. -pub fn new_light_backend(blockchain: Arc>) -> Arc>> -where - B: BlockT, - S: BlockchainStorage, -{ - Arc::new(Backend::new(blockchain)) -} diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 7b334175a2805..e2b950cf67e8c 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -20,14 +20,14 @@ use crate::{ bitswap::Bitswap, config::ProtocolId, discovery::{DiscoveryBehaviour, DiscoveryConfig, DiscoveryOut}, - light_client_requests, peer_info, + peer_info, protocol::{message::Roles, CustomMessageOutcome, NotificationsSink, Protocol}, request_responses, DhtEvent, ObservedRole, }; use bytes::Bytes; use codec::Encode; -use futures::{channel::oneshot, stream::StreamExt}; +use futures::channel::oneshot; use libp2p::{ core::{Multiaddr, PeerId, PublicKey}, identify::IdentifyInfo, @@ -76,10 +76,6 @@ pub struct Behaviour { #[behaviour(ignore)] events: VecDeque>, - /// Light client request handling. - #[behaviour(ignore)] - light_client_request_sender: light_client_requests::sender::LightClientRequestSender, - /// Protocol name used to send out block requests via /// [`request_responses::RequestResponsesBehaviour`]. #[behaviour(ignore)] @@ -198,7 +194,6 @@ impl Behaviour { substrate: Protocol, user_agent: String, local_public_key: PublicKey, - light_client_request_sender: light_client_requests::sender::LightClientRequestSender, disco_config: DiscoveryConfig, block_request_protocol_config: request_responses::ProtocolConfig, state_request_protocol_config: request_responses::ProtocolConfig, @@ -233,7 +228,6 @@ impl Behaviour { request_response_protocols.into_iter(), peerset, )?, - light_client_request_sender, events: VecDeque::new(), block_request_protocol_name, state_request_protocol_name, @@ -316,14 +310,6 @@ impl Behaviour { pub fn put_value(&mut self, key: record::Key, value: Vec) { self.discovery.put_value(key, value); } - - /// Issue a light client request. - pub fn light_client_request( - &mut self, - r: light_client_requests::sender::Request, - ) -> Result<(), light_client_requests::sender::SendRequestError> { - self.light_client_request_sender.request(r) - } } fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole { @@ -436,17 +422,11 @@ impl NetworkBehaviourEventProcess> for Behavi CustomMessageOutcome::NotificationsReceived { remote, messages } => { self.events.push_back(BehaviourOut::NotificationsReceived { remote, messages }); }, - CustomMessageOutcome::PeerNewBest(peer_id, number) => { - self.light_client_request_sender.update_best_block(&peer_id, number); - }, - CustomMessageOutcome::SyncConnected(peer_id) => { - self.light_client_request_sender.inject_connected(peer_id); - self.events.push_back(BehaviourOut::SyncConnected(peer_id)) - }, - CustomMessageOutcome::SyncDisconnected(peer_id) => { - self.light_client_request_sender.inject_disconnected(peer_id); - self.events.push_back(BehaviourOut::SyncDisconnected(peer_id)) - }, + CustomMessageOutcome::PeerNewBest(_peer_id, _number) => {}, + CustomMessageOutcome::SyncConnected(peer_id) => + self.events.push_back(BehaviourOut::SyncConnected(peer_id)), + CustomMessageOutcome::SyncDisconnected(peer_id) => + self.events.push_back(BehaviourOut::SyncDisconnected(peer_id)), CustomMessageOutcome::None => {}, } } @@ -534,23 +514,9 @@ impl NetworkBehaviourEventProcess for Behaviour { impl Behaviour { fn poll( &mut self, - cx: &mut Context, + _cx: &mut Context, _: &mut impl PollParameters, ) -> Poll>> { - use light_client_requests::sender::OutEvent; - while let Poll::Ready(Some(event)) = self.light_client_request_sender.poll_next_unpin(cx) { - match event { - OutEvent::SendRequest { target, request, pending_response, protocol_name } => - self.request_responses.send_request( - &target, - &protocol_name, - request, - pending_response, - IfDisconnected::ImmediateError, - ), - } - } - if let Some(event) = self.events.pop_front() { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event)) } diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 76c806ccbf7b6..8ef52e46fd071 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -23,7 +23,6 @@ pub use crate::{ chain::Client, - on_demand_layer::{AlwaysBadChecker, OnDemand}, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, @@ -83,11 +82,6 @@ pub struct Params { /// Client that contains the blockchain. pub chain: Arc>, - /// The `OnDemand` object acts as a "receiver" for block data requests from the client. - /// If `Some`, the network worker will process these requests and answer them. - /// Normally used only for light clients. - pub on_demand: Option>>, - /// Pool of transactions. /// /// The network worker will fetch transactions from this object in order to propagate them on diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 2f81ddfa1fb13..cb16eb163ee46 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -247,7 +247,6 @@ mod behaviour; mod chain; mod discovery; -mod on_demand_layer; mod peer_info; mod protocol; mod request_responses; diff --git a/client/network/src/light_client_requests.rs b/client/network/src/light_client_requests.rs index e18b783f219be..b1793ce9384ed 100644 --- a/client/network/src/light_client_requests.rs +++ b/client/network/src/light_client_requests.rs @@ -20,8 +20,6 @@ /// For incoming light client requests. pub mod handler; -/// For outgoing light client requests. -pub mod sender; use crate::{config::ProtocolId, request_responses::ProtocolConfig}; @@ -47,269 +45,3 @@ pub fn generate_protocol_config(protocol_id: &ProtocolId) -> ProtocolConfig { inbound_queue: None, } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::{config::ProtocolId, request_responses::IncomingRequest}; - - use assert_matches::assert_matches; - use futures::{ - channel::oneshot, - executor::{block_on, LocalPool}, - prelude::*, - task::Spawn, - }; - use libp2p::PeerId; - use sc_client_api::{ - light::{ - self, ChangesProof, RemoteBodyRequest, RemoteCallRequest, RemoteChangesRequest, - RemoteHeaderRequest, RemoteReadRequest, - }, - FetchChecker, RemoteReadChildRequest, StorageProof, - }; - use sp_blockchain::Error as ClientError; - use sp_core::storage::ChildInfo; - use sp_runtime::{ - generic::Header, - traits::{BlakeTwo256, Block as BlockT, NumberFor}, - }; - use std::{collections::HashMap, sync::Arc}; - - pub struct DummyFetchChecker { - pub ok: bool, - pub _mark: std::marker::PhantomData, - } - - impl FetchChecker for DummyFetchChecker { - fn check_header_proof( - &self, - _request: &RemoteHeaderRequest, - header: Option, - _remote_proof: StorageProof, - ) -> Result { - match self.ok { - true if header.is_some() => Ok(header.unwrap()), - _ => Err(ClientError::Backend("Test error".into())), - } - } - - fn check_read_proof( - &self, - request: &RemoteReadRequest, - _: StorageProof, - ) -> Result, Option>>, ClientError> { - match self.ok { - true => Ok(request.keys.iter().cloned().map(|k| (k, Some(vec![42]))).collect()), - false => Err(ClientError::Backend("Test error".into())), - } - } - - fn check_read_child_proof( - &self, - request: &RemoteReadChildRequest, - _: StorageProof, - ) -> Result, Option>>, ClientError> { - match self.ok { - true => Ok(request.keys.iter().cloned().map(|k| (k, Some(vec![42]))).collect()), - false => Err(ClientError::Backend("Test error".into())), - } - } - - fn check_execution_proof( - &self, - _: &RemoteCallRequest, - _: StorageProof, - ) -> Result, ClientError> { - match self.ok { - true => Ok(vec![42]), - false => Err(ClientError::Backend("Test error".into())), - } - } - - fn check_changes_proof( - &self, - _: &RemoteChangesRequest, - _: ChangesProof, - ) -> Result, u32)>, ClientError> { - match self.ok { - true => Ok(vec![(100u32.into(), 2)]), - false => Err(ClientError::Backend("Test error".into())), - } - } - - fn check_body_proof( - &self, - _: &RemoteBodyRequest, - body: Vec, - ) -> Result, ClientError> { - match self.ok { - true => Ok(body), - false => Err(ClientError::Backend("Test error".into())), - } - } - } - - pub fn protocol_id() -> ProtocolId { - ProtocolId::from("test") - } - - pub fn peerset() -> (sc_peerset::Peerset, sc_peerset::PeersetHandle) { - let cfg = sc_peerset::SetConfig { - in_peers: 128, - out_peers: 128, - bootnodes: Default::default(), - reserved_only: false, - reserved_nodes: Default::default(), - }; - sc_peerset::Peerset::from_config(sc_peerset::PeersetConfig { sets: vec![cfg] }) - } - - pub fn dummy_header() -> sp_test_primitives::Header { - sp_test_primitives::Header { - parent_hash: Default::default(), - number: 0, - state_root: Default::default(), - extrinsics_root: Default::default(), - digest: Default::default(), - } - } - - type Block = - sp_runtime::generic::Block, substrate_test_runtime::Extrinsic>; - - fn send_receive(request: sender::Request, pool: &LocalPool) { - let client = Arc::new(substrate_test_runtime_client::new()); - let (handler, protocol_config) = - handler::LightClientRequestHandler::new(&protocol_id(), client); - pool.spawner().spawn_obj(handler.run().boxed().into()).unwrap(); - - let (_peer_set, peer_set_handle) = peerset(); - let mut sender = sender::LightClientRequestSender::::new( - &protocol_id(), - Arc::new(crate::light_client_requests::tests::DummyFetchChecker { - ok: true, - _mark: std::marker::PhantomData, - }), - peer_set_handle, - ); - sender.inject_connected(PeerId::random()); - - sender.request(request).unwrap(); - let sender::OutEvent::SendRequest { pending_response, request, .. } = - block_on(sender.next()).unwrap(); - let (tx, rx) = oneshot::channel(); - block_on(protocol_config.inbound_queue.unwrap().send(IncomingRequest { - peer: PeerId::random(), - payload: request, - pending_response: tx, - })) - .unwrap(); - pool.spawner() - .spawn_obj( - async move { - pending_response.send(Ok(rx.await.unwrap().result.unwrap())).unwrap(); - } - .boxed() - .into(), - ) - .unwrap(); - - pool.spawner() - .spawn_obj(sender.for_each(|_| future::ready(())).boxed().into()) - .unwrap(); - } - - #[test] - fn send_receive_call() { - let chan = oneshot::channel(); - let request = light::RemoteCallRequest { - block: Default::default(), - header: dummy_header(), - method: "test".into(), - call_data: vec![], - retry_count: None, - }; - - let mut pool = LocalPool::new(); - send_receive(sender::Request::Call { request, sender: chan.0 }, &pool); - assert_eq!(vec![42], pool.run_until(chan.1).unwrap().unwrap()); - // ^--- from `DummyFetchChecker::check_execution_proof` - } - - #[test] - fn send_receive_read() { - let chan = oneshot::channel(); - let request = light::RemoteReadRequest { - header: dummy_header(), - block: Default::default(), - keys: vec![b":key".to_vec()], - retry_count: None, - }; - let mut pool = LocalPool::new(); - send_receive(sender::Request::Read { request, sender: chan.0 }, &pool); - assert_eq!( - Some(vec![42]), - pool.run_until(chan.1).unwrap().unwrap().remove(&b":key"[..]).unwrap() - ); - // ^--- from `DummyFetchChecker::check_read_proof` - } - - #[test] - fn send_receive_read_child() { - let chan = oneshot::channel(); - let child_info = ChildInfo::new_default(&b":child_storage:default:sub"[..]); - let request = light::RemoteReadChildRequest { - header: dummy_header(), - block: Default::default(), - storage_key: child_info.prefixed_storage_key(), - keys: vec![b":key".to_vec()], - retry_count: None, - }; - let mut pool = LocalPool::new(); - send_receive(sender::Request::ReadChild { request, sender: chan.0 }, &pool); - assert_eq!( - Some(vec![42]), - pool.run_until(chan.1).unwrap().unwrap().remove(&b":key"[..]).unwrap() - ); - // ^--- from `DummyFetchChecker::check_read_child_proof` - } - - #[test] - fn send_receive_header() { - sp_tracing::try_init_simple(); - let chan = oneshot::channel(); - let request = light::RemoteHeaderRequest { - cht_root: Default::default(), - block: 1, - retry_count: None, - }; - let mut pool = LocalPool::new(); - send_receive(sender::Request::Header { request, sender: chan.0 }, &pool); - // The remote does not know block 1: - assert_matches!(pool.run_until(chan.1).unwrap(), Err(ClientError::RemoteFetchFailed)); - } - - #[test] - fn send_receive_changes() { - let chan = oneshot::channel(); - let request = light::RemoteChangesRequest { - changes_trie_configs: vec![sp_core::ChangesTrieConfigurationRange { - zero: (0, Default::default()), - end: None, - config: Some(sp_core::ChangesTrieConfiguration::new(4, 2)), - }], - first_block: (1, Default::default()), - last_block: (100, Default::default()), - max_block: (100, Default::default()), - tries_roots: (1, Default::default(), Vec::new()), - key: Vec::new(), - storage_key: None, - retry_count: None, - }; - let mut pool = LocalPool::new(); - send_receive(sender::Request::Changes { request, sender: chan.0 }, &pool); - assert_eq!(vec![(100, 2)], pool.run_until(chan.1).unwrap().unwrap()); - // ^--- from `DummyFetchChecker::check_changes_proof` - } -} diff --git a/client/network/src/light_client_requests/handler.rs b/client/network/src/light_client_requests/handler.rs index 43504edddd73a..a04c5e310a67e 100644 --- a/client/network/src/light_client_requests/handler.rs +++ b/client/network/src/light_client_requests/handler.rs @@ -32,17 +32,14 @@ use codec::{self, Decode, Encode}; use futures::{channel::mpsc, prelude::*}; use log::{debug, trace}; use prost::Message; -use sc_client_api::{light, StorageProof}; +use sc_client_api::StorageProof; use sc_peerset::ReputationChange; use sp_core::{ hexdisplay::HexDisplay, - storage::{ChildInfo, ChildType, PrefixedStorageKey, StorageKey}, + storage::{ChildInfo, ChildType, PrefixedStorageKey}, }; -use sp_runtime::{ - generic::BlockId, - traits::{Block, Zero}, -}; -use std::{collections::BTreeMap, sync::Arc}; +use sp_runtime::{generic::BlockId, traits::Block}; +use std::sync::Arc; const LOG_TARGET: &str = "light-client-request-handler"; @@ -137,12 +134,12 @@ impl LightClientRequestHandler { self.on_remote_call_request(&peer, r)?, Some(schema::v1::light::request::Request::RemoteReadRequest(r)) => self.on_remote_read_request(&peer, r)?, - Some(schema::v1::light::request::Request::RemoteHeaderRequest(r)) => - self.on_remote_header_request(&peer, r)?, + Some(schema::v1::light::request::Request::RemoteHeaderRequest(_r)) => + return Err(HandleRequestError::BadRequest("Not supported.")), Some(schema::v1::light::request::Request::RemoteReadChildRequest(r)) => self.on_remote_read_child_request(&peer, r)?, - Some(schema::v1::light::request::Request::RemoteChangesRequest(r)) => - self.on_remote_changes_request(&peer, r)?, + Some(schema::v1::light::request::Request::RemoteChangesRequest(_r)) => + return Err(HandleRequestError::BadRequest("Not supported.")), None => return Err(HandleRequestError::BadRequest("Remote request without request data.")), }; @@ -285,106 +282,6 @@ impl LightClientRequestHandler { Ok(schema::v1::light::Response { response: Some(response) }) } - - fn on_remote_header_request( - &mut self, - peer: &PeerId, - request: &schema::v1::light::RemoteHeaderRequest, - ) -> Result { - trace!("Remote header proof request from {} ({:?}).", peer, request.block); - - let block = Decode::decode(&mut request.block.as_ref())?; - let (header, proof) = match self.client.header_proof(&BlockId::Number(block)) { - Ok((header, proof)) => (header.encode(), proof), - Err(error) => { - trace!( - "Remote header proof request from {} ({:?}) failed with: {}.", - peer, - request.block, - error - ); - (Default::default(), StorageProof::empty()) - }, - }; - - let response = { - let r = schema::v1::light::RemoteHeaderResponse { header, proof: proof.encode() }; - schema::v1::light::response::Response::RemoteHeaderResponse(r) - }; - - Ok(schema::v1::light::Response { response: Some(response) }) - } - - fn on_remote_changes_request( - &mut self, - peer: &PeerId, - request: &schema::v1::light::RemoteChangesRequest, - ) -> Result { - trace!( - "Remote changes proof request from {} for key {} ({:?}..{:?}).", - peer, - if !request.storage_key.is_empty() { - format!( - "{} : {}", - HexDisplay::from(&request.storage_key), - HexDisplay::from(&request.key) - ) - } else { - HexDisplay::from(&request.key).to_string() - }, - request.first, - request.last, - ); - - let first = Decode::decode(&mut request.first.as_ref())?; - let last = Decode::decode(&mut request.last.as_ref())?; - let min = Decode::decode(&mut request.min.as_ref())?; - let max = Decode::decode(&mut request.max.as_ref())?; - let key = StorageKey(request.key.clone()); - let storage_key = if request.storage_key.is_empty() { - None - } else { - Some(PrefixedStorageKey::new_ref(&request.storage_key)) - }; - - let proof = - match self.client.key_changes_proof(first, last, min, max, storage_key, &key) { - Ok(proof) => proof, - Err(error) => { - trace!( - "Remote changes proof request from {} for key {} ({:?}..{:?}) failed with: {}.", - peer, - format!("{} : {}", HexDisplay::from(&request.storage_key), HexDisplay::from(&key.0)), - request.first, - request.last, - error, - ); - - light::ChangesProof:: { - max_block: Zero::zero(), - proof: Vec::new(), - roots: BTreeMap::new(), - roots_proof: StorageProof::empty(), - } - }, - }; - - let response = { - let r = schema::v1::light::RemoteChangesResponse { - max: proof.max_block.encode(), - proof: proof.proof, - roots: proof - .roots - .into_iter() - .map(|(k, v)| schema::v1::light::Pair { fst: k.encode(), snd: v.encode() }) - .collect(), - roots_proof: proof.roots_proof.encode(), - }; - schema::v1::light::response::Response::RemoteChangesResponse(r) - }; - - Ok(schema::v1::light::Response { response: Some(response) }) - } } #[derive(derive_more::Display, derive_more::From)] diff --git a/client/network/src/light_client_requests/sender.rs b/client/network/src/light_client_requests/sender.rs deleted file mode 100644 index 284db827594b4..0000000000000 --- a/client/network/src/light_client_requests/sender.rs +++ /dev/null @@ -1,1294 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Helper for outgoing light client requests. -//! -//! Call [`LightClientRequestSender::request`](sender::LightClientRequestSender::request) -//! to send out light client requests. It will: -//! -//! 1. Build the request. -//! -//! 2. Forward the request to [`crate::request_responses::RequestResponsesBehaviour`] via -//! [`OutEvent::SendRequest`](sender::OutEvent::SendRequest). -//! -//! 3. Wait for the response and forward the response via the [`futures::channel::oneshot::Sender`] -//! provided earlier with [`LightClientRequestSender::request`](sender::LightClientRequestSender:: -//! request). - -use crate::{ - config::ProtocolId, - protocol::message::BlockAttributes, - request_responses::{OutboundFailure, RequestFailure}, - schema, PeerId, -}; -use codec::{self, Decode, Encode}; -use futures::{channel::oneshot, future::BoxFuture, prelude::*, stream::FuturesUnordered}; -use prost::Message; -use sc_client_api::light::{self, RemoteBodyRequest}; -use sc_peerset::ReputationChange; -use sp_blockchain::Error as ClientError; -use sp_runtime::traits::{Block, Header, NumberFor}; -use std::{ - collections::{BTreeMap, HashMap, VecDeque}, - pin::Pin, - sync::Arc, - task::{Context, Poll}, -}; - -mod rep { - use super::*; - - /// Reputation change for a peer when a request timed out. - pub const TIMEOUT: ReputationChange = - ReputationChange::new(-(1 << 8), "light client request timeout"); - /// Reputation change for a peer when a request is refused. - pub const REFUSED: ReputationChange = - ReputationChange::new(-(1 << 8), "light client request refused"); -} - -/// Configuration options for [`LightClientRequestSender`]. -#[derive(Debug, Clone)] -struct Config { - max_pending_requests: usize, - light_protocol: String, - block_protocol: String, -} - -impl Config { - /// Create a new [`LightClientRequestSender`] configuration. - pub fn new(id: &ProtocolId) -> Self { - Self { - max_pending_requests: 128, - light_protocol: super::generate_protocol_name(id), - block_protocol: crate::block_request_handler::generate_protocol_name(id), - } - } -} - -/// State machine helping to send out light client requests. -pub struct LightClientRequestSender { - /// This behaviour's configuration. - config: Config, - /// Verifies that received responses are correct. - checker: Arc>, - /// Peer information (addresses, their best block, etc.) - peers: HashMap>, - /// Pending (local) requests. - pending_requests: VecDeque>, - /// Requests on their way to remote peers. - sent_requests: FuturesUnordered< - BoxFuture< - 'static, - (SentRequest, Result, RequestFailure>, oneshot::Canceled>), - >, - >, - /// Handle to use for reporting misbehaviour of peers. - peerset: sc_peerset::PeersetHandle, -} - -/// Augments a pending light client request with metadata. -#[derive(Debug)] -struct PendingRequest { - /// Remaining attempts. - attempts_left: usize, - /// The actual request. - request: Request, -} - -impl PendingRequest { - fn new(req: Request) -> Self { - Self { - // Number of retries + one for the initial attempt. - attempts_left: req.retries() + 1, - request: req, - } - } - - fn into_sent(self, peer_id: PeerId) -> SentRequest { - SentRequest { attempts_left: self.attempts_left, request: self.request, peer: peer_id } - } -} - -/// Augments a light client request with metadata that is currently being send to a remote. -#[derive(Debug)] -struct SentRequest { - /// Remaining attempts. - attempts_left: usize, - /// The actual request. - request: Request, - /// The peer that the request is send to. - peer: PeerId, -} - -impl SentRequest { - fn into_pending(self) -> PendingRequest { - PendingRequest { attempts_left: self.attempts_left, request: self.request } - } -} - -impl Unpin for LightClientRequestSender {} - -impl LightClientRequestSender -where - B: Block, -{ - /// Construct a new light client handler. - pub fn new( - id: &ProtocolId, - checker: Arc>, - peerset: sc_peerset::PeersetHandle, - ) -> Self { - Self { - config: Config::new(id), - checker, - peers: Default::default(), - pending_requests: Default::default(), - sent_requests: Default::default(), - peerset, - } - } - - /// We rely on external information about peers best blocks as we lack the - /// means to determine it ourselves. - pub fn update_best_block(&mut self, peer: &PeerId, num: NumberFor) { - if let Some(info) = self.peers.get_mut(peer) { - log::trace!("new best block for {:?}: {:?}", peer, num); - info.best_block = Some(num) - } - } - - /// Issue a new light client request. - pub fn request(&mut self, req: Request) -> Result<(), SendRequestError> { - if self.pending_requests.len() >= self.config.max_pending_requests { - return Err(SendRequestError::TooManyRequests) - } - self.pending_requests.push_back(PendingRequest::new(req)); - Ok(()) - } - - /// Remove the given peer. - /// - /// In-flight requests to the given peer might fail and be retried. See - /// [`::poll_next`]. - fn remove_peer(&mut self, peer: PeerId) { - self.peers.remove(&peer); - } - - /// Process a local request's response from remote. - /// - /// If successful, this will give us the actual, checked data we should be - /// sending back to the client, otherwise an error. - fn on_response( - &mut self, - peer: PeerId, - request: &Request, - response: Response, - ) -> Result, Error> { - log::trace!("response from {}", peer); - match response { - Response::Light(r) => self.on_response_light(request, r), - Response::Block(r) => self.on_response_block(request, r), - } - } - - fn on_response_light( - &mut self, - request: &Request, - response: schema::v1::light::Response, - ) -> Result, Error> { - use schema::v1::light::response::Response; - match response.response { - Some(Response::RemoteCallResponse(response)) => { - if let Request::Call { request, .. } = request { - let proof = Decode::decode(&mut response.proof.as_ref())?; - let reply = self.checker.check_execution_proof(request, proof)?; - Ok(Reply::VecU8(reply)) - } else { - Err(Error::UnexpectedResponse) - } - }, - Some(Response::RemoteReadResponse(response)) => match request { - Request::Read { request, .. } => { - let proof = Decode::decode(&mut response.proof.as_ref())?; - let reply = self.checker.check_read_proof(&request, proof)?; - Ok(Reply::MapVecU8OptVecU8(reply)) - }, - Request::ReadChild { request, .. } => { - let proof = Decode::decode(&mut response.proof.as_ref())?; - let reply = self.checker.check_read_child_proof(&request, proof)?; - Ok(Reply::MapVecU8OptVecU8(reply)) - }, - _ => Err(Error::UnexpectedResponse), - }, - Some(Response::RemoteChangesResponse(response)) => { - if let Request::Changes { request, .. } = request { - let max_block = Decode::decode(&mut response.max.as_ref())?; - let roots_proof = Decode::decode(&mut response.roots_proof.as_ref())?; - let roots = { - let mut r = BTreeMap::new(); - for pair in response.roots { - let k = Decode::decode(&mut pair.fst.as_ref())?; - let v = Decode::decode(&mut pair.snd.as_ref())?; - r.insert(k, v); - } - r - }; - let reply = self.checker.check_changes_proof( - &request, - light::ChangesProof { - max_block, - proof: response.proof, - roots, - roots_proof, - }, - )?; - Ok(Reply::VecNumberU32(reply)) - } else { - Err(Error::UnexpectedResponse) - } - }, - Some(Response::RemoteHeaderResponse(response)) => { - if let Request::Header { request, .. } = request { - let header = if response.header.is_empty() { - None - } else { - Some(Decode::decode(&mut response.header.as_ref())?) - }; - let proof = Decode::decode(&mut response.proof.as_ref())?; - let reply = self.checker.check_header_proof(&request, header, proof)?; - Ok(Reply::Header(reply)) - } else { - Err(Error::UnexpectedResponse) - } - }, - None => Err(Error::UnexpectedResponse), - } - } - - fn on_response_block( - &mut self, - request: &Request, - response: schema::v1::BlockResponse, - ) -> Result, Error> { - let request = if let Request::Body { request, .. } = &request { - request - } else { - return Err(Error::UnexpectedResponse) - }; - - let body: Vec<_> = match response.blocks.into_iter().next() { - Some(b) => b.body, - None => return Err(Error::UnexpectedResponse), - }; - - let body = body - .into_iter() - .map(|extrinsic| B::Extrinsic::decode(&mut &extrinsic[..])) - .collect::>()?; - - let body = self.checker.check_body_proof(&request, body)?; - Ok(Reply::Extrinsics(body)) - } - - /// Signal that the node is connected to the given peer. - pub fn inject_connected(&mut self, peer: PeerId) { - let prev_entry = self.peers.insert(peer, Default::default()); - debug_assert!( - prev_entry.is_none(), - "Expect `inject_connected` to be called for disconnected peer.", - ); - } - - /// Signal that the node disconnected from the given peer. - pub fn inject_disconnected(&mut self, peer: PeerId) { - self.remove_peer(peer) - } -} - -impl Stream for LightClientRequestSender { - type Item = OutEvent; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - // If we have received responses to previously sent requests, check them and pass them on. - while let Poll::Ready(Some((sent_request, request_result))) = - self.sent_requests.poll_next_unpin(cx) - { - if let Some(info) = self.peers.get_mut(&sent_request.peer) { - if info.status != PeerStatus::Busy { - // If we get here, something is wrong with our internal handling of peer status - // information. At any time, a single peer processes at most one request from - // us. A malicious peer should not be able to get us here. It is our own fault - // and must be fixed! - panic!("unexpected peer status {:?} for {}", info.status, sent_request.peer); - } - - info.status = PeerStatus::Idle; // Make peer available again. - } - - let request_result = match request_result { - Ok(r) => r, - Err(oneshot::Canceled) => { - log::debug!("Oneshot for request to peer {} was canceled.", sent_request.peer); - self.remove_peer(sent_request.peer); - self.peerset.report_peer( - sent_request.peer, - ReputationChange::new_fatal("no response from peer"), - ); - self.pending_requests.push_back(sent_request.into_pending()); - continue - }, - }; - - let decoded_request_result = request_result.map(|response| { - if sent_request.request.is_block_request() { - schema::v1::BlockResponse::decode(&response[..]).map(|r| Response::Block(r)) - } else { - schema::v1::light::Response::decode(&response[..]).map(|r| Response::Light(r)) - } - }); - - let response = match decoded_request_result { - Ok(Ok(response)) => response, - Ok(Err(e)) => { - log::debug!( - "Failed to decode response from peer {}: {:?}.", - sent_request.peer, - e - ); - self.remove_peer(sent_request.peer); - self.peerset.report_peer( - sent_request.peer, - ReputationChange::new_fatal("invalid response from peer"), - ); - self.pending_requests.push_back(sent_request.into_pending()); - continue - }, - Err(e) => { - log::debug!("Request to peer {} failed with {:?}.", sent_request.peer, e); - - match e { - RequestFailure::NotConnected => { - self.remove_peer(sent_request.peer); - self.pending_requests.push_back(sent_request.into_pending()); - }, - RequestFailure::UnknownProtocol => { - debug_assert!( - false, - "Light client and block request protocol should be known when \ - sending requests.", - ); - }, - RequestFailure::Refused => { - self.remove_peer(sent_request.peer); - self.peerset.report_peer(sent_request.peer, rep::REFUSED); - self.pending_requests.push_back(sent_request.into_pending()); - }, - RequestFailure::Obsolete => { - debug_assert!( - false, - "Can not receive `RequestFailure::Obsolete` after dropping the \ - response receiver.", - ); - self.pending_requests.push_back(sent_request.into_pending()); - }, - RequestFailure::Network(OutboundFailure::Timeout) => { - self.remove_peer(sent_request.peer); - self.peerset.report_peer(sent_request.peer, rep::TIMEOUT); - self.pending_requests.push_back(sent_request.into_pending()); - }, - RequestFailure::Network(OutboundFailure::UnsupportedProtocols) => { - self.remove_peer(sent_request.peer); - self.peerset.report_peer( - sent_request.peer, - ReputationChange::new_fatal( - "peer does not support light client or block request protocol", - ), - ); - self.pending_requests.push_back(sent_request.into_pending()); - }, - RequestFailure::Network(OutboundFailure::DialFailure) => { - self.remove_peer(sent_request.peer); - self.peerset.report_peer( - sent_request.peer, - ReputationChange::new_fatal("failed to dial peer"), - ); - self.pending_requests.push_back(sent_request.into_pending()); - }, - RequestFailure::Network(OutboundFailure::ConnectionClosed) => { - self.remove_peer(sent_request.peer); - self.peerset.report_peer( - sent_request.peer, - ReputationChange::new_fatal("connection to peer closed"), - ); - self.pending_requests.push_back(sent_request.into_pending()); - }, - } - - continue - }, - }; - - match self.on_response(sent_request.peer, &sent_request.request, response) { - Ok(reply) => sent_request.request.return_reply(Ok(reply)), - Err(Error::UnexpectedResponse) => { - log::debug!("Unexpected response from peer {}.", sent_request.peer); - self.remove_peer(sent_request.peer); - self.peerset.report_peer( - sent_request.peer, - ReputationChange::new_fatal("unexpected response from peer"), - ); - self.pending_requests.push_back(sent_request.into_pending()); - }, - Err(other) => { - log::debug!( - "error handling response from peer {}: {}", - sent_request.peer, - other - ); - self.remove_peer(sent_request.peer); - self.peerset.report_peer( - sent_request.peer, - ReputationChange::new_fatal("invalid response from peer"), - ); - self.pending_requests.push_back(sent_request.into_pending()) - }, - } - } - - // If we have a pending request to send, try to find an available peer and send it. - while let Some(mut pending_request) = self.pending_requests.pop_front() { - if pending_request.attempts_left == 0 { - pending_request.request.return_reply(Err(ClientError::RemoteFetchFailed)); - continue - } - - let protocol = if pending_request.request.is_block_request() { - self.config.block_protocol.clone() - } else { - self.config.light_protocol.clone() - }; - - // Out of all idle peers, find one who's best block is high enough, choose any idle peer - // if none exists. - let mut peer = None; - for (peer_id, peer_info) in self.peers.iter_mut() { - if peer_info.status == PeerStatus::Idle { - match peer_info.best_block { - Some(n) if n >= pending_request.request.required_block() => { - peer = Some((*peer_id, peer_info)); - break - }, - _ => peer = Some((*peer_id, peer_info)), - } - } - } - - // Break in case there is no idle peer. - let (peer_id, peer_info) = match peer { - Some((peer_id, peer_info)) => (peer_id, peer_info), - None => { - self.pending_requests.push_front(pending_request); - log::debug!("No peer available to send request to."); - - break - }, - }; - - let request_bytes = match pending_request.request.serialize_request() { - Ok(bytes) => bytes, - Err(error) => { - log::debug!("failed to serialize request: {}", error); - pending_request.request.return_reply(Err(ClientError::RemoteFetchFailed)); - continue - }, - }; - - let (tx, rx) = oneshot::channel(); - - peer_info.status = PeerStatus::Busy; - - pending_request.attempts_left -= 1; - - self.sent_requests - .push(async move { (pending_request.into_sent(peer_id), rx.await) }.boxed()); - - return Poll::Ready(Some(OutEvent::SendRequest { - target: peer_id, - request: request_bytes, - pending_response: tx, - protocol_name: protocol, - })) - } - - Poll::Pending - } -} - -/// Events returned by [`LightClientRequestSender`]. -#[derive(Debug)] -pub enum OutEvent { - /// Emit a request to be send out on the network e.g. via [`crate::request_responses`]. - SendRequest { - /// The remote peer to send the request to. - target: PeerId, - /// The encoded request. - request: Vec, - /// The [`oneshot::Sender`] channel to pass the response to. - pending_response: oneshot::Sender, RequestFailure>>, - /// The name of the protocol to use to send the request. - protocol_name: String, - }, -} - -/// Incoming response from remote. -#[derive(Debug, Clone)] -pub enum Response { - /// Incoming light response from remote. - Light(schema::v1::light::Response), - /// Incoming block response from remote. - Block(schema::v1::BlockResponse), -} - -/// Error returned by [`LightClientRequestSender::request`]. -#[derive(Debug, derive_more::Display, derive_more::From)] -pub enum SendRequestError { - /// There are currently too many pending request. - #[display(fmt = "too many pending requests")] - TooManyRequests, -} - -/// Error type to propagate errors internally. -#[derive(Debug, derive_more::Display, derive_more::From)] -enum Error { - /// The response type does not correspond to the issued request. - #[display(fmt = "unexpected response")] - UnexpectedResponse, - /// Encoding or decoding of some data failed. - #[display(fmt = "codec error: {}", _0)] - Codec(codec::Error), - /// The chain client errored. - #[display(fmt = "client error: {}", _0)] - Client(ClientError), -} - -/// The data to send back to the light client over the oneshot channel. -// It is unified here in order to be able to return it as a function -// result instead of delivering it to the client as a side effect of -// response processing. -#[derive(Debug)] -enum Reply { - VecU8(Vec), - VecNumberU32(Vec<(::Number, u32)>), - MapVecU8OptVecU8(HashMap, Option>>), - Header(B::Header), - Extrinsics(Vec), -} - -/// Information we have about some peer. -#[derive(Debug)] -struct PeerInfo { - best_block: Option>, - status: PeerStatus, -} - -impl Default for PeerInfo { - fn default() -> Self { - PeerInfo { best_block: None, status: PeerStatus::Idle } - } -} - -/// A peer is either idle or busy processing a request from us. -#[derive(Debug, Clone, PartialEq, Eq)] -enum PeerStatus { - /// The peer is available. - Idle, - /// We wait for the peer to return us a response for the given request ID. - Busy, -} - -/// The possible light client requests we support. -/// -/// The associated `oneshot::Sender` will be used to convey the result of -/// their request back to them (cf. `Reply`). -// This is modeled after light_dispatch.rs's `RequestData` which is not -// used because we currently only support a subset of those. -#[derive(Debug)] -pub enum Request { - /// Remote body request. - Body { - /// Request. - request: RemoteBodyRequest, - /// [`oneshot::Sender`] to return response. - sender: oneshot::Sender, ClientError>>, - }, - /// Remote header request. - Header { - /// Request. - request: light::RemoteHeaderRequest, - /// [`oneshot::Sender`] to return response. - sender: oneshot::Sender>, - }, - /// Remote read request. - Read { - /// Request. - request: light::RemoteReadRequest, - /// [`oneshot::Sender`] to return response. - sender: oneshot::Sender, Option>>, ClientError>>, - }, - /// Remote read child request. - ReadChild { - /// Request. - request: light::RemoteReadChildRequest, - /// [`oneshot::Sender`] to return response. - sender: oneshot::Sender, Option>>, ClientError>>, - }, - /// Remote call request. - Call { - /// Request. - request: light::RemoteCallRequest, - /// [`oneshot::Sender`] to return response. - sender: oneshot::Sender, ClientError>>, - }, - /// Remote changes request. - Changes { - /// Request. - request: light::RemoteChangesRequest, - /// [`oneshot::Sender`] to return response. - sender: oneshot::Sender, u32)>, ClientError>>, - }, -} - -impl Request { - fn is_block_request(&self) -> bool { - matches!(self, Request::Body { .. }) - } - - fn required_block(&self) -> NumberFor { - match self { - Request::Body { request, .. } => *request.header.number(), - Request::Header { request, .. } => request.block, - Request::Read { request, .. } => *request.header.number(), - Request::ReadChild { request, .. } => *request.header.number(), - Request::Call { request, .. } => *request.header.number(), - Request::Changes { request, .. } => request.max_block.0, - } - } - - fn retries(&self) -> usize { - let rc = match self { - Request::Body { request, .. } => request.retry_count, - Request::Header { request, .. } => request.retry_count, - Request::Read { request, .. } => request.retry_count, - Request::ReadChild { request, .. } => request.retry_count, - Request::Call { request, .. } => request.retry_count, - Request::Changes { request, .. } => request.retry_count, - }; - rc.unwrap_or(0) - } - - fn serialize_request(&self) -> Result, prost::EncodeError> { - let request = match self { - Request::Body { request, .. } => { - let rq = schema::v1::BlockRequest { - fields: BlockAttributes::BODY.to_be_u32(), - from_block: Some(schema::v1::block_request::FromBlock::Hash( - request.header.hash().encode(), - )), - to_block: Default::default(), - direction: schema::v1::Direction::Ascending as i32, - max_blocks: 1, - support_multiple_justifications: true, - }; - - let mut buf = Vec::with_capacity(rq.encoded_len()); - rq.encode(&mut buf)?; - return Ok(buf) - }, - Request::Header { request, .. } => { - let r = schema::v1::light::RemoteHeaderRequest { block: request.block.encode() }; - schema::v1::light::request::Request::RemoteHeaderRequest(r) - }, - Request::Read { request, .. } => { - let r = schema::v1::light::RemoteReadRequest { - block: request.block.encode(), - keys: request.keys.clone(), - }; - schema::v1::light::request::Request::RemoteReadRequest(r) - }, - Request::ReadChild { request, .. } => { - let r = schema::v1::light::RemoteReadChildRequest { - block: request.block.encode(), - storage_key: request.storage_key.clone().into_inner(), - keys: request.keys.clone(), - }; - schema::v1::light::request::Request::RemoteReadChildRequest(r) - }, - Request::Call { request, .. } => { - let r = schema::v1::light::RemoteCallRequest { - block: request.block.encode(), - method: request.method.clone(), - data: request.call_data.clone(), - }; - schema::v1::light::request::Request::RemoteCallRequest(r) - }, - Request::Changes { request, .. } => { - let r = schema::v1::light::RemoteChangesRequest { - first: request.first_block.1.encode(), - last: request.last_block.1.encode(), - min: request.tries_roots.1.encode(), - max: request.max_block.1.encode(), - storage_key: request - .storage_key - .clone() - .map(|s| s.into_inner()) - .unwrap_or_default(), - key: request.key.clone(), - }; - schema::v1::light::request::Request::RemoteChangesRequest(r) - }, - }; - - let rq = schema::v1::light::Request { request: Some(request) }; - let mut buf = Vec::with_capacity(rq.encoded_len()); - rq.encode(&mut buf)?; - Ok(buf) - } - - fn return_reply(self, result: Result, ClientError>) { - fn send(item: T, sender: oneshot::Sender) { - let _ = sender.send(item); // It is okay if the other end already hung up. - } - match self { - Request::Body { request, sender } => match result { - Err(e) => send(Err(e), sender), - Ok(Reply::Extrinsics(x)) => send(Ok(x), sender), - reply => log::error!("invalid reply for body request: {:?}, {:?}", reply, request), - }, - Request::Header { request, sender } => match result { - Err(e) => send(Err(e), sender), - Ok(Reply::Header(x)) => send(Ok(x), sender), - reply => { - log::error!("invalid reply for header request: {:?}, {:?}", reply, request) - }, - }, - Request::Read { request, sender } => match result { - Err(e) => send(Err(e), sender), - Ok(Reply::MapVecU8OptVecU8(x)) => send(Ok(x), sender), - reply => log::error!("invalid reply for read request: {:?}, {:?}", reply, request), - }, - Request::ReadChild { request, sender } => match result { - Err(e) => send(Err(e), sender), - Ok(Reply::MapVecU8OptVecU8(x)) => send(Ok(x), sender), - reply => { - log::error!("invalid reply for read child request: {:?}, {:?}", reply, request) - }, - }, - Request::Call { request, sender } => match result { - Err(e) => send(Err(e), sender), - Ok(Reply::VecU8(x)) => send(Ok(x), sender), - reply => log::error!("invalid reply for call request: {:?}, {:?}", reply, request), - }, - Request::Changes { request, sender } => match result { - Err(e) => send(Err(e), sender), - Ok(Reply::VecNumberU32(x)) => send(Ok(x), sender), - reply => { - log::error!("invalid reply for changes request: {:?}, {:?}", reply, request) - }, - }, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - light_client_requests::tests::{dummy_header, peerset, protocol_id, DummyFetchChecker}, - request_responses::OutboundFailure, - }; - - use assert_matches::assert_matches; - use futures::{channel::oneshot, executor::block_on, poll}; - use sc_client_api::StorageProof; - use sp_core::storage::ChildInfo; - use sp_runtime::{generic::Header, traits::BlakeTwo256}; - use std::{collections::HashSet, iter::FromIterator}; - - fn empty_proof() -> Vec { - StorageProof::empty().encode() - } - - #[test] - fn removes_peer_if_told() { - let peer = PeerId::random(); - let (_peer_set, peer_set_handle) = peerset(); - let mut sender = LightClientRequestSender::::new( - &protocol_id(), - Arc::new(DummyFetchChecker { ok: true, _mark: std::marker::PhantomData }), - peer_set_handle, - ); - - sender.inject_connected(peer); - assert_eq!(1, sender.peers.len()); - - sender.inject_disconnected(peer); - assert_eq!(0, sender.peers.len()); - } - - type Block = - sp_runtime::generic::Block, substrate_test_runtime::Extrinsic>; - - #[test] - fn body_request_fields_encoded_properly() { - let (sender, _receiver) = oneshot::channel(); - let request = Request::::Body { - request: RemoteBodyRequest { header: dummy_header(), retry_count: None }, - sender, - }; - let serialized_request = request.serialize_request().unwrap(); - let deserialized_request = - schema::v1::BlockRequest::decode(&serialized_request[..]).unwrap(); - assert!(BlockAttributes::from_be_u32(deserialized_request.fields) - .unwrap() - .contains(BlockAttributes::BODY)); - } - - #[test] - fn disconnects_from_peer_if_request_times_out() { - let peer0 = PeerId::random(); - let peer1 = PeerId::random(); - - let (_peer_set, peer_set_handle) = peerset(); - let mut sender = LightClientRequestSender::::new( - &protocol_id(), - Arc::new(crate::light_client_requests::tests::DummyFetchChecker { - ok: true, - _mark: std::marker::PhantomData, - }), - peer_set_handle, - ); - - sender.inject_connected(peer0); - sender.inject_connected(peer1); - - assert_eq!( - HashSet::from_iter(&[peer0.clone(), peer1.clone()]), - sender.peers.keys().collect::>(), - "Expect knowledge of two peers." - ); - - assert!(sender.pending_requests.is_empty(), "Expect no pending request."); - assert!(sender.sent_requests.is_empty(), "Expect no sent request."); - - // Issue a request! - let chan = oneshot::channel(); - let request = light::RemoteCallRequest { - block: Default::default(), - header: dummy_header(), - method: "test".into(), - call_data: vec![], - retry_count: Some(1), - }; - sender.request(Request::Call { request, sender: chan.0 }).unwrap(); - assert_eq!(1, sender.pending_requests.len(), "Expect one pending request."); - - let OutEvent::SendRequest { target, pending_response, .. } = - block_on(sender.next()).unwrap(); - assert!(target == peer0 || target == peer1, "Expect request to originate from known peer."); - - // And we should have one busy peer. - assert!({ - let (idle, busy): (Vec<_>, Vec<_>) = - sender.peers.iter().partition(|(_, info)| info.status == PeerStatus::Idle); - idle.len() == 1 && - busy.len() == 1 && (idle[0].0 == &peer0 || busy[0].0 == &peer0) && - (idle[0].0 == &peer1 || busy[0].0 == &peer1) - }); - - assert_eq!(0, sender.pending_requests.len(), "Expect no pending request."); - assert_eq!(1, sender.sent_requests.len(), "Expect one request to be sent."); - - // Report first attempt as timed out. - pending_response - .send(Err(RequestFailure::Network(OutboundFailure::Timeout))) - .unwrap(); - - // Expect a new request to be issued. - let OutEvent::SendRequest { pending_response, .. } = block_on(sender.next()).unwrap(); - - assert_eq!(1, sender.peers.len(), "Expect peer to be removed."); - assert_eq!(0, sender.pending_requests.len(), "Expect no request to be pending."); - assert_eq!(1, sender.sent_requests.len(), "Expect new request to be issued."); - - // Report second attempt as timed out. - pending_response - .send(Err(RequestFailure::Network(OutboundFailure::Timeout))) - .unwrap(); - assert_matches!( - block_on(async { poll!(sender.next()) }), - Poll::Pending, - "Expect sender to not issue another attempt.", - ); - assert_matches!( - block_on(chan.1).unwrap(), - Err(ClientError::RemoteFetchFailed), - "Expect request failure to be reported.", - ); - assert_eq!(0, sender.peers.len(), "Expect no peer to be left"); - assert_eq!(0, sender.pending_requests.len(), "Expect no request to be pending."); - assert_eq!(0, sender.sent_requests.len(), "Expect no other request to be in progress."); - } - - #[test] - fn disconnects_from_peer_on_incorrect_response() { - let peer = PeerId::random(); - - let (_peer_set, peer_set_handle) = peerset(); - let mut sender = LightClientRequestSender::::new( - &protocol_id(), - Arc::new(crate::light_client_requests::tests::DummyFetchChecker { - ok: false, - // ^--- Making sure the response data check fails. - _mark: std::marker::PhantomData, - }), - peer_set_handle, - ); - - sender.inject_connected(peer); - assert_eq!(1, sender.peers.len(), "Expect one peer."); - - let chan = oneshot::channel(); - let request = light::RemoteCallRequest { - block: Default::default(), - header: dummy_header(), - method: "test".into(), - call_data: vec![], - retry_count: Some(1), - }; - sender.request(Request::Call { request, sender: chan.0 }).unwrap(); - - assert_eq!(1, sender.pending_requests.len(), "Expect one pending request."); - assert_eq!(0, sender.sent_requests.len(), "Expect zero sent requests."); - - let OutEvent::SendRequest { pending_response, .. } = block_on(sender.next()).unwrap(); - assert_eq!(0, sender.pending_requests.len(), "Expect zero pending requests."); - assert_eq!(1, sender.sent_requests.len(), "Expect one sent request."); - - let response = { - let r = schema::v1::light::RemoteCallResponse { proof: empty_proof() }; - let response = schema::v1::light::Response { - response: Some(schema::v1::light::response::Response::RemoteCallResponse(r)), - }; - let mut data = Vec::new(); - response.encode(&mut data).unwrap(); - data - }; - - pending_response.send(Ok(response)).unwrap(); - - assert_matches!( - block_on(async { poll!(sender.next()) }), - Poll::Pending, - "Expect sender to not issue another attempt, given that there is no peer left.", - ); - - assert!(sender.peers.is_empty(), "Expect no peers to be left."); - assert_eq!(1, sender.pending_requests.len(), "Expect request to be pending again."); - assert_eq!(0, sender.sent_requests.len(), "Expect no request to be sent."); - } - - #[test] - fn disconnects_from_peer_on_wrong_response_type() { - let peer = PeerId::random(); - let (_peer_set, peer_set_handle) = peerset(); - let mut sender = LightClientRequestSender::::new( - &protocol_id(), - Arc::new(crate::light_client_requests::tests::DummyFetchChecker { - ok: true, - _mark: std::marker::PhantomData, - }), - peer_set_handle, - ); - - sender.inject_connected(peer); - assert_eq!(1, sender.peers.len(), "Expect one peer."); - - let chan = oneshot::channel(); - let request = light::RemoteCallRequest { - block: Default::default(), - header: dummy_header(), - method: "test".into(), - call_data: vec![], - retry_count: Some(1), - }; - sender.request(Request::Call { request, sender: chan.0 }).unwrap(); - - assert_eq!(1, sender.pending_requests.len()); - assert_eq!(0, sender.sent_requests.len()); - let OutEvent::SendRequest { pending_response, .. } = block_on(sender.next()).unwrap(); - assert_eq!(0, sender.pending_requests.len(), "Expect zero pending requests."); - assert_eq!(1, sender.sent_requests.len(), "Expect one sent request."); - - let response = { - let r = schema::v1::light::RemoteReadResponse { proof: empty_proof() }; // Not a RemoteCallResponse! - let response = schema::v1::light::Response { - response: Some(schema::v1::light::response::Response::RemoteReadResponse(r)), - }; - let mut data = Vec::new(); - response.encode(&mut data).unwrap(); - data - }; - - pending_response.send(Ok(response)).unwrap(); - assert_matches!( - block_on(async { poll!(sender.next()) }), - Poll::Pending, - "Expect sender to not issue another attempt, given that there is no peer left.", - ); - - assert!(sender.peers.is_empty(), "Expect no peers to be left."); - assert_eq!(1, sender.pending_requests.len(), "Expect request to be pending again."); - assert_eq!(0, sender.sent_requests.len(), "Expect no request to be sent."); - } - - #[test] - fn receives_remote_failure_after_retry_count_failures() { - let peers = (0..4).map(|_| PeerId::random()).collect::>(); - - let (_peer_set, peer_set_handle) = peerset(); - let mut sender = LightClientRequestSender::::new( - &protocol_id(), - Arc::new(crate::light_client_requests::tests::DummyFetchChecker { - ok: false, - // ^--- Making sure the response data check fails. - _mark: std::marker::PhantomData, - }), - peer_set_handle, - ); - - for peer in &peers { - sender.inject_connected(*peer); - } - assert_eq!(4, sender.peers.len(), "Expect four peers."); - - let mut chan = oneshot::channel(); - let request = light::RemoteCallRequest { - block: Default::default(), - header: dummy_header(), - method: "test".into(), - call_data: vec![], - retry_count: Some(3), // Attempt up to three retries. - }; - sender.request(Request::Call { request, sender: chan.0 }).unwrap(); - - assert_eq!(1, sender.pending_requests.len()); - assert_eq!(0, sender.sent_requests.len()); - let mut pending_response = match block_on(sender.next()).unwrap() { - OutEvent::SendRequest { pending_response, .. } => Some(pending_response), - }; - assert_eq!(0, sender.pending_requests.len(), "Expect zero pending requests."); - assert_eq!(1, sender.sent_requests.len(), "Expect one sent request."); - - for (i, _peer) in peers.iter().enumerate() { - // Construct an invalid response - let response = { - let r = schema::v1::light::RemoteCallResponse { proof: empty_proof() }; - let response = schema::v1::light::Response { - response: Some(schema::v1::light::response::Response::RemoteCallResponse(r)), - }; - let mut data = Vec::new(); - response.encode(&mut data).unwrap(); - data - }; - pending_response.take().unwrap().send(Ok(response)).unwrap(); - - if i < 3 { - pending_response = match block_on(sender.next()).unwrap() { - OutEvent::SendRequest { pending_response, .. } => Some(pending_response), - }; - assert_matches!(chan.1.try_recv(), Ok(None)) - } else { - // Last peer and last attempt. - assert_matches!( - block_on(async { poll!(sender.next()) }), - Poll::Pending, - "Expect sender to not issue another attempt, given that there is no peer left.", - ); - assert_matches!(chan.1.try_recv(), Ok(Some(Err(ClientError::RemoteFetchFailed)))) - } - } - } - - fn issue_request(request: Request) { - let peer = PeerId::random(); - - let (_peer_set, peer_set_handle) = peerset(); - let mut sender = LightClientRequestSender::::new( - &protocol_id(), - Arc::new(crate::light_client_requests::tests::DummyFetchChecker { - ok: true, - _mark: std::marker::PhantomData, - }), - peer_set_handle, - ); - - sender.inject_connected(peer); - assert_eq!(1, sender.peers.len(), "Expect one peer."); - - let response = match request { - Request::Body { .. } => unimplemented!(), - Request::Header { .. } => { - let r = schema::v1::light::RemoteHeaderResponse { - header: dummy_header().encode(), - proof: empty_proof(), - }; - schema::v1::light::Response { - response: Some(schema::v1::light::response::Response::RemoteHeaderResponse(r)), - } - }, - Request::Read { .. } => { - let r = schema::v1::light::RemoteReadResponse { proof: empty_proof() }; - schema::v1::light::Response { - response: Some(schema::v1::light::response::Response::RemoteReadResponse(r)), - } - }, - Request::ReadChild { .. } => { - let r = schema::v1::light::RemoteReadResponse { proof: empty_proof() }; - schema::v1::light::Response { - response: Some(schema::v1::light::response::Response::RemoteReadResponse(r)), - } - }, - Request::Call { .. } => { - let r = schema::v1::light::RemoteCallResponse { proof: empty_proof() }; - schema::v1::light::Response { - response: Some(schema::v1::light::response::Response::RemoteCallResponse(r)), - } - }, - Request::Changes { .. } => { - let r = schema::v1::light::RemoteChangesResponse { - max: std::iter::repeat(1).take(32).collect(), - proof: Vec::new(), - roots: Vec::new(), - roots_proof: empty_proof(), - }; - schema::v1::light::Response { - response: Some(schema::v1::light::response::Response::RemoteChangesResponse(r)), - } - }, - }; - - let response = { - let mut data = Vec::new(); - response.encode(&mut data).unwrap(); - data - }; - - sender.request(request).unwrap(); - - assert_eq!(1, sender.pending_requests.len()); - assert_eq!(0, sender.sent_requests.len()); - let OutEvent::SendRequest { pending_response, .. } = block_on(sender.next()).unwrap(); - assert_eq!(0, sender.pending_requests.len()); - assert_eq!(1, sender.sent_requests.len()); - - pending_response.send(Ok(response)).unwrap(); - assert_matches!( - block_on(async { poll!(sender.next()) }), - Poll::Pending, - "Expect sender to not issue another attempt, given that there is no peer left.", - ); - - assert_eq!(0, sender.pending_requests.len()); - assert_eq!(0, sender.sent_requests.len()) - } - - #[test] - fn receives_remote_call_response() { - let mut chan = oneshot::channel(); - let request = light::RemoteCallRequest { - block: Default::default(), - header: dummy_header(), - method: "test".into(), - call_data: vec![], - retry_count: None, - }; - issue_request(Request::Call { request, sender: chan.0 }); - assert_matches!(chan.1.try_recv(), Ok(Some(Ok(_)))) - } - - #[test] - fn receives_remote_read_response() { - let mut chan = oneshot::channel(); - let request = light::RemoteReadRequest { - header: dummy_header(), - block: Default::default(), - keys: vec![b":key".to_vec()], - retry_count: None, - }; - issue_request(Request::Read { request, sender: chan.0 }); - assert_matches!(chan.1.try_recv(), Ok(Some(Ok(_)))) - } - - #[test] - fn receives_remote_read_child_response() { - let mut chan = oneshot::channel(); - let child_info = ChildInfo::new_default(&b":child_storage:default:sub"[..]); - let request = light::RemoteReadChildRequest { - header: dummy_header(), - block: Default::default(), - storage_key: child_info.prefixed_storage_key(), - keys: vec![b":key".to_vec()], - retry_count: None, - }; - issue_request(Request::ReadChild { request, sender: chan.0 }); - assert_matches!(chan.1.try_recv(), Ok(Some(Ok(_)))) - } - - #[test] - fn receives_remote_header_response() { - let mut chan = oneshot::channel(); - let request = light::RemoteHeaderRequest { - cht_root: Default::default(), - block: 1, - retry_count: None, - }; - issue_request(Request::Header { request, sender: chan.0 }); - assert_matches!(chan.1.try_recv(), Ok(Some(Ok(_)))) - } - - #[test] - fn receives_remote_changes_response() { - let mut chan = oneshot::channel(); - let request = light::RemoteChangesRequest { - changes_trie_configs: vec![sp_core::ChangesTrieConfigurationRange { - zero: (0, Default::default()), - end: None, - config: Some(sp_core::ChangesTrieConfiguration::new(4, 2)), - }], - first_block: (1, Default::default()), - last_block: (100, Default::default()), - max_block: (100, Default::default()), - tries_roots: (1, Default::default(), Vec::new()), - key: Vec::new(), - storage_key: None, - retry_count: None, - }; - issue_request(Request::Changes { request, sender: chan.0 }); - assert_matches!(chan.1.try_recv(), Ok(Some(Ok(_)))) - } -} diff --git a/client/network/src/on_demand_layer.rs b/client/network/src/on_demand_layer.rs deleted file mode 100644 index eaeb0bee98f2c..0000000000000 --- a/client/network/src/on_demand_layer.rs +++ /dev/null @@ -1,241 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! On-demand requests service. - -use crate::light_client_requests; - -use futures::{channel::oneshot, prelude::*}; -use parking_lot::Mutex; -use sc_client_api::{ - ChangesProof, FetchChecker, Fetcher, RemoteBodyRequest, RemoteCallRequest, - RemoteChangesRequest, RemoteHeaderRequest, RemoteReadChildRequest, RemoteReadRequest, - StorageProof, -}; -use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; -use sp_blockchain::Error as ClientError; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; -use std::{ - collections::HashMap, - pin::Pin, - sync::Arc, - task::{Context, Poll}, -}; - -/// Implements the `Fetcher` trait of the client. Makes it possible for the light client to perform -/// network requests for some state. -/// -/// This implementation stores all the requests in a queue. The network, in parallel, is then -/// responsible for pulling elements out of that queue and fulfilling them. -pub struct OnDemand { - /// Objects that checks whether what has been retrieved is correct. - checker: Arc>, - - /// Queue of requests. Set to `Some` at initialization, then extracted by the network. - /// - /// Note that a better alternative would be to use a MPMC queue here, and add a `poll` method - /// from the `OnDemand`. However there exists no popular implementation of MPMC channels in - /// asynchronous Rust at the moment - requests_queue: - Mutex>>>, - - /// Sending side of `requests_queue`. - requests_send: TracingUnboundedSender>, -} - -#[derive(Debug, thiserror::Error)] -#[error("AlwaysBadChecker")] -struct ErrorAlwaysBadChecker; - -impl Into for ErrorAlwaysBadChecker { - fn into(self) -> ClientError { - ClientError::Application(Box::new(self)) - } -} - -/// Dummy implementation of `FetchChecker` that always assumes that responses are bad. -/// -/// Considering that it is the responsibility of the client to build the fetcher, it can use this -/// implementation if it knows that it will never perform any request. -#[derive(Default, Clone)] -pub struct AlwaysBadChecker; - -impl FetchChecker for AlwaysBadChecker { - fn check_header_proof( - &self, - _request: &RemoteHeaderRequest, - _remote_header: Option, - _remote_proof: StorageProof, - ) -> Result { - Err(ErrorAlwaysBadChecker.into()) - } - - fn check_read_proof( - &self, - _request: &RemoteReadRequest, - _remote_proof: StorageProof, - ) -> Result, Option>>, ClientError> { - Err(ErrorAlwaysBadChecker.into()) - } - - fn check_read_child_proof( - &self, - _request: &RemoteReadChildRequest, - _remote_proof: StorageProof, - ) -> Result, Option>>, ClientError> { - Err(ErrorAlwaysBadChecker.into()) - } - - fn check_execution_proof( - &self, - _request: &RemoteCallRequest, - _remote_proof: StorageProof, - ) -> Result, ClientError> { - Err(ErrorAlwaysBadChecker.into()) - } - - fn check_changes_proof( - &self, - _request: &RemoteChangesRequest, - _remote_proof: ChangesProof, - ) -> Result, u32)>, ClientError> { - Err(ErrorAlwaysBadChecker.into()) - } - - fn check_body_proof( - &self, - _request: &RemoteBodyRequest, - _body: Vec, - ) -> Result, ClientError> { - Err(ErrorAlwaysBadChecker.into()) - } -} - -impl OnDemand -where - B::Header: HeaderT, -{ - /// Creates new on-demand service. - pub fn new(checker: Arc>) -> Self { - let (requests_send, requests_queue) = tracing_unbounded("mpsc_ondemand"); - let requests_queue = Mutex::new(Some(requests_queue)); - - Self { checker, requests_queue, requests_send } - } - - /// Get checker reference. - pub fn checker(&self) -> &Arc> { - &self.checker - } - - /// Extracts the queue of requests. - /// - /// Whenever one of the methods of the `Fetcher` trait is called, an element is pushed on this - /// channel. - /// - /// If this function returns `None`, that means that the receiver has already been extracted in - /// the past, and therefore that something already handles the requests. - pub(crate) fn extract_receiver( - &self, - ) -> Option>> { - self.requests_queue.lock().take() - } -} - -impl Fetcher for OnDemand -where - B: BlockT, - B::Header: HeaderT, -{ - type RemoteHeaderResult = RemoteResponse; - type RemoteReadResult = RemoteResponse, Option>>>; - type RemoteCallResult = RemoteResponse>; - type RemoteChangesResult = RemoteResponse, u32)>>; - type RemoteBodyResult = RemoteResponse>; - - fn remote_header(&self, request: RemoteHeaderRequest) -> Self::RemoteHeaderResult { - let (sender, receiver) = oneshot::channel(); - let _ = self - .requests_send - .unbounded_send(light_client_requests::sender::Request::Header { request, sender }); - RemoteResponse { receiver } - } - - fn remote_read(&self, request: RemoteReadRequest) -> Self::RemoteReadResult { - let (sender, receiver) = oneshot::channel(); - let _ = self - .requests_send - .unbounded_send(light_client_requests::sender::Request::Read { request, sender }); - RemoteResponse { receiver } - } - - fn remote_read_child( - &self, - request: RemoteReadChildRequest, - ) -> Self::RemoteReadResult { - let (sender, receiver) = oneshot::channel(); - let _ = self - .requests_send - .unbounded_send(light_client_requests::sender::Request::ReadChild { request, sender }); - RemoteResponse { receiver } - } - - fn remote_call(&self, request: RemoteCallRequest) -> Self::RemoteCallResult { - let (sender, receiver) = oneshot::channel(); - let _ = self - .requests_send - .unbounded_send(light_client_requests::sender::Request::Call { request, sender }); - RemoteResponse { receiver } - } - - fn remote_changes( - &self, - request: RemoteChangesRequest, - ) -> Self::RemoteChangesResult { - let (sender, receiver) = oneshot::channel(); - let _ = self - .requests_send - .unbounded_send(light_client_requests::sender::Request::Changes { request, sender }); - RemoteResponse { receiver } - } - - fn remote_body(&self, request: RemoteBodyRequest) -> Self::RemoteBodyResult { - let (sender, receiver) = oneshot::channel(); - let _ = self - .requests_send - .unbounded_send(light_client_requests::sender::Request::Body { request, sender }); - RemoteResponse { receiver } - } -} - -/// Future for an on-demand remote call response. -pub struct RemoteResponse { - receiver: oneshot::Receiver>, -} - -impl Future for RemoteResponse { - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { - match self.receiver.poll_unpin(cx) { - Poll::Ready(Ok(res)) => Poll::Ready(res), - Poll::Ready(Err(_)) => Poll::Ready(Err(ClientError::RemoteFetchCancelled)), - Poll::Pending => Poll::Pending, - } - } -} diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 90e647505fa1f..caf4db89f653a 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -33,11 +33,9 @@ use crate::{ config::{parse_str_addr, Params, TransportConfig}, discovery::DiscoveryConfig, error::Error, - light_client_requests, network_state::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, - on_demand_layer::AlwaysBadChecker, protocol::{ self, event::Event, @@ -238,12 +236,6 @@ impl NetworkWorker { } })?; - let checker = params - .on_demand - .as_ref() - .map(|od| od.checker().clone()) - .unwrap_or_else(|| Arc::new(AlwaysBadChecker)); - let num_connected = Arc::new(AtomicUsize::new(0)); let is_major_syncing = Arc::new(AtomicBool::new(false)); @@ -255,14 +247,6 @@ impl NetworkWorker { params.network_config.client_version, params.network_config.node_name ); - let light_client_request_sender = { - light_client_requests::sender::LightClientRequestSender::new( - ¶ms.protocol_id, - checker, - peerset_handle.clone(), - ) - }; - let discovery_config = { let mut config = DiscoveryConfig::new(local_public.clone()); config.with_permanent_addresses(known_addresses); @@ -347,7 +331,6 @@ impl NetworkWorker { protocol, user_agent, local_public, - light_client_request_sender, discovery_config, params.block_request_protocol_config, params.state_request_protocol_config, @@ -447,7 +430,6 @@ impl NetworkWorker { service, import_queue: params.import_queue, from_service, - light_client_rqs: params.on_demand.and_then(|od| od.extract_receiver()), event_streams: out_events::OutChannels::new(params.metrics_registry.as_ref())?, peers_notifications_sinks, tx_handler_controller, @@ -1464,8 +1446,6 @@ pub struct NetworkWorker { import_queue: Box>, /// Messages from the [`NetworkService`] that must be processed. from_service: TracingUnboundedReceiver>, - /// Receiver for queries from the light client that must be processed. - light_client_rqs: Option>>, /// Senders for events that happen on the network. event_streams: out_events::OutChannels, /// Prometheus network metrics. @@ -1489,23 +1469,6 @@ impl Future for NetworkWorker { this.import_queue .poll_actions(cx, &mut NetworkLink { protocol: &mut this.network_service }); - // Check for new incoming light client requests. - if let Some(light_client_rqs) = this.light_client_rqs.as_mut() { - while let Poll::Ready(Some(rq)) = light_client_rqs.poll_next_unpin(cx) { - let result = this.network_service.behaviour_mut().light_client_request(rq); - match result { - Ok(()) => {}, - Err(light_client_requests::sender::SendRequestError::TooManyRequests) => { - warn!("Couldn't start light client request: too many pending requests"); - }, - } - - if let Some(metrics) = this.metrics.as_ref() { - metrics.issued_light_requests.inc(); - } - } - } - // At the time of writing of this comment, due to a high volume of messages, the network // worker sometimes takes a long time to process the loop below. When that happens, the // rest of the polling is frozen. In order to avoid negative side-effects caused by this diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 69b172d07edfe..1c66986e422fc 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -116,7 +116,6 @@ fn build_test_full_node( }), network_config: config, chain: client.clone(), - on_demand: None, transaction_pool: Arc::new(crate::config::EmptyTransactionPool), protocol_id, import_queue, diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 084b09fd65f8f..cfd42327b6003 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -48,13 +48,13 @@ use sc_consensus::{ }; pub use sc_network::config::EmptyTransactionPool; use sc_network::{ - block_request_handler::{self, BlockRequestHandler}, + block_request_handler::BlockRequestHandler, config::{ MultiaddrWithPeerId, NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, ProtocolConfig, ProtocolId, Role, SyncMode, TransportConfig, }, - light_client_requests::{self, handler::LightClientRequestHandler}, - state_request_handler::{self, StateRequestHandler}, + light_client_requests::handler::LightClientRequestHandler, + state_request_handler::StateRequestHandler, warp_request_handler, Multiaddr, NetworkService, NetworkWorker, }; use sc_service::client::Client; @@ -133,25 +133,20 @@ pub type PeersFullClient = Client< Block, substrate_test_runtime_client::runtime::RuntimeApi, >; -pub type PeersLightClient = Client< - substrate_test_runtime_client::LightBackend, - substrate_test_runtime_client::LightExecutor, - Block, - substrate_test_runtime_client::runtime::RuntimeApi, ->; #[derive(Clone)] -pub enum PeersClient { - Full(Arc, Arc), - Light(Arc, Arc), +pub struct PeersClient { + client: Arc, + backend: Arc, } impl PeersClient { - pub fn as_full(&self) -> Option> { - match *self { - PeersClient::Full(ref client, _) => Some(client.clone()), - _ => None, - } + pub fn as_client(&self) -> Arc { + self.client.clone() + } + + pub fn as_backend(&self) -> Arc { + self.backend.clone() } pub fn as_block_import(&self) -> BlockImportAdapter { @@ -159,27 +154,18 @@ impl PeersClient { } pub fn get_aux(&self, key: &[u8]) -> ClientResult>> { - match *self { - PeersClient::Full(ref client, _) => client.get_aux(key), - PeersClient::Light(ref client, _) => client.get_aux(key), - } + self.client.get_aux(key) } pub fn info(&self) -> BlockchainInfo { - match *self { - PeersClient::Full(ref client, _) => client.chain_info(), - PeersClient::Light(ref client, _) => client.chain_info(), - } + self.client.info() } pub fn header( &self, block: &BlockId, ) -> ClientResult::Header>> { - match *self { - PeersClient::Full(ref client, _) => client.header(block), - PeersClient::Light(ref client, _) => client.header(block), - } + self.client.header(block) } pub fn has_state_at(&self, block: &BlockId) -> bool { @@ -187,33 +173,19 @@ impl PeersClient { Some(header) => header, None => return false, }; - match self { - PeersClient::Full(_client, backend) => - backend.have_state_at(&header.hash(), *header.number()), - PeersClient::Light(_client, backend) => - backend.have_state_at(&header.hash(), *header.number()), - } + self.backend.have_state_at(&header.hash(), *header.number()) } pub fn justifications(&self, block: &BlockId) -> ClientResult> { - match *self { - PeersClient::Full(ref client, _) => client.justifications(block), - PeersClient::Light(ref client, _) => client.justifications(block), - } + self.client.justifications(block) } pub fn finality_notification_stream(&self) -> FinalityNotifications { - match *self { - PeersClient::Full(ref client, _) => client.finality_notification_stream(), - PeersClient::Light(ref client, _) => client.finality_notification_stream(), - } + self.client.finality_notification_stream() } pub fn import_notification_stream(&self) -> ImportNotifications { - match *self { - PeersClient::Full(ref client, _) => client.import_notification_stream(), - PeersClient::Light(ref client, _) => client.import_notification_stream(), - } + self.client.import_notification_stream() } pub fn finalize_block( @@ -222,12 +194,7 @@ impl PeersClient { justification: Option, notify: bool, ) -> ClientResult<()> { - match *self { - PeersClient::Full(ref client, ref _backend) => - client.finalize_block(id, justification, notify), - PeersClient::Light(ref client, ref _backend) => - client.finalize_block(id, justification, notify), - } + self.client.finalize_block(id, justification, notify) } } @@ -240,10 +207,7 @@ impl BlockImport for PeersClient { &mut self, block: BlockCheckParams, ) -> Result { - match self { - PeersClient::Full(client, _) => client.check_block(block).await, - PeersClient::Light(client, _) => client.check_block(block).await, - } + self.client.check_block(block).await } async fn import_block( @@ -251,12 +215,7 @@ impl BlockImport for PeersClient { block: BlockImportParams, cache: HashMap>, ) -> Result { - match self { - PeersClient::Full(client, _) => - client.import_block(block.clear_storage_changes_and_mutate(), cache).await, - PeersClient::Light(client, _) => - client.import_block(block.clear_storage_changes_and_mutate(), cache).await, - } + self.client.import_block(block.clear_storage_changes_and_mutate(), cache).await } } @@ -370,8 +329,7 @@ where BlockBuilder, ) -> Block, { - let full_client = - self.client.as_full().expect("blocks could only be generated by full clients"); + let full_client = self.client.as_client(); let mut at = full_client.header(&at).unwrap().unwrap().hash(); for _ in 0..count { let builder = @@ -779,11 +737,11 @@ where let (c, longest_chain) = test_client_builder.build_with_longest_chain(); let client = Arc::new(c); - let (block_import, justification_import, data) = - self.make_block_import(PeersClient::Full(client.clone(), backend.clone())); + let (block_import, justification_import, data) = self + .make_block_import(PeersClient { client: client.clone(), backend: backend.clone() }); let verifier = self.make_verifier( - PeersClient::Full(client.clone(), backend.clone()), + PeersClient { client: client.clone(), backend: backend.clone() }, &Default::default(), &data, ); @@ -868,7 +826,6 @@ where }), network_config, chain: client.clone(), - on_demand: None, transaction_pool: Arc::new(EmptyTransactionPool), protocol_id, import_queue, @@ -899,7 +856,7 @@ where peers.push(Peer { data, - client: PeersClient::Full(client.clone(), backend.clone()), + client: PeersClient { client: client.clone(), backend: backend.clone() }, select_chain: Some(longest_chain), backend: Some(backend), imported_blocks_stream, @@ -912,94 +869,6 @@ where }); } - /// Add a light peer. - fn add_light_peer(&mut self) { - let (c, backend) = substrate_test_runtime_client::new_light(); - let client = Arc::new(c); - let (block_import, justification_import, data) = - self.make_block_import(PeersClient::Light(client.clone(), backend.clone())); - - let verifier = self.make_verifier( - PeersClient::Light(client.clone(), backend.clone()), - &Default::default(), - &data, - ); - let verifier = VerifierAdapter::new(verifier); - - let import_queue = Box::new(BasicQueue::new( - verifier.clone(), - Box::new(block_import.clone()), - justification_import, - &sp_core::testing::TaskExecutor::new(), - None, - )); - - let listen_addr = build_multiaddr![Memory(rand::random::())]; - - let mut network_config = - NetworkConfiguration::new("test-node", "test-client", Default::default(), None); - network_config.transport = TransportConfig::MemoryOnly; - network_config.listen_addresses = vec![listen_addr.clone()]; - network_config.allow_non_globals_in_dht = true; - - let protocol_id = ProtocolId::from("test-protocol-name"); - - let block_request_protocol_config = - block_request_handler::generate_protocol_config(&protocol_id); - let state_request_protocol_config = - state_request_handler::generate_protocol_config(&protocol_id); - - let light_client_request_protocol_config = - light_client_requests::generate_protocol_config(&protocol_id); - - let network = NetworkWorker::new(sc_network::config::Params { - role: Role::Light, - executor: None, - transactions_handler_executor: Box::new(|task| { - async_std::task::spawn(task); - }), - network_config, - chain: client.clone(), - on_demand: None, - transaction_pool: Arc::new(EmptyTransactionPool), - protocol_id, - import_queue, - block_announce_validator: Box::new(DefaultBlockAnnounceValidator), - metrics_registry: None, - block_request_protocol_config, - state_request_protocol_config, - light_client_request_protocol_config, - warp_sync: None, - }) - .unwrap(); - - self.mut_peers(|peers| { - for peer in peers.iter_mut() { - peer.network.add_known_address( - network.service().local_peer_id().clone(), - listen_addr.clone(), - ); - } - - let imported_blocks_stream = Box::pin(client.import_notification_stream().fuse()); - let finality_notification_stream = - Box::pin(client.finality_notification_stream().fuse()); - - peers.push(Peer { - data, - verifier, - select_chain: None, - backend: None, - block_import, - client: PeersClient::Light(client, backend), - imported_blocks_stream, - finality_notification_stream, - network, - listen_addr, - }); - }); - } - /// Used to spawn background tasks, e.g. the block request protocol handler. fn spawn_task(&self, f: BoxFuture<'static, ()>) { async_std::task::spawn(f); diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index ff62b5476d1e6..4828cae842218 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -20,7 +20,6 @@ use super::*; use futures::{executor::block_on, Future}; use sp_consensus::{block_validation::Validation, BlockOrigin}; use sp_runtime::Justifications; -use std::time::Duration; use substrate_test_runtime::Header; fn test_ancestor_search_when_common_is(n: usize) { @@ -391,35 +390,6 @@ fn own_blocks_are_announced() { (net.peers()[2].blockchain_canon_equals(peer0)); } -#[test] -fn blocks_are_not_announced_by_light_nodes() { - sp_tracing::try_init_simple(); - let mut net = TestNet::new(0); - - // full peer0 is connected to light peer - // light peer1 is connected to full peer2 - net.add_full_peer(); - net.add_light_peer(); - - // Sync between 0 and 1. - net.peer(0).push_blocks(1, false); - assert_eq!(net.peer(0).client.info().best_number, 1); - net.block_until_sync(); - assert_eq!(net.peer(1).client.info().best_number, 1); - - // Add another node and remove node 0. - net.add_full_peer(); - net.peers.remove(0); - - // Poll for a few seconds and make sure 1 and 2 (now 0 and 1) don't sync together. - let mut delay = futures_timer::Delay::new(Duration::from_secs(5)); - block_on(futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - Pin::new(&mut delay).poll(cx) - })); - assert_eq!(net.peer(1).client.info().best_number, 0); -} - #[test] fn can_sync_small_non_best_forks() { sp_tracing::try_init_simple(); @@ -483,72 +453,6 @@ fn can_sync_small_non_best_forks() { })); } -#[test] -fn can_not_sync_from_light_peer() { - sp_tracing::try_init_simple(); - - // given the network with 1 full nodes (#0) and 1 light node (#1) - let mut net = TestNet::new(1); - net.add_light_peer(); - - // generate some blocks on #0 - net.peer(0).push_blocks(1, false); - - // and let the light client sync from this node - net.block_until_sync(); - - // ensure #0 && #1 have the same best block - let full0_info = net.peer(0).client.info(); - let light_info = net.peer(1).client.info(); - assert_eq!(full0_info.best_number, 1); - assert_eq!(light_info.best_number, 1); - assert_eq!(light_info.best_hash, full0_info.best_hash); - - // add new full client (#2) && remove #0 - net.add_full_peer(); - net.peers.remove(0); - - // ensure that the #2 (now #1) fails to sync block #1 even after 5 seconds - let mut test_finished = futures_timer::Delay::new(Duration::from_secs(5)); - block_on(futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - Pin::new(&mut test_finished).poll(cx) - })); -} - -#[test] -fn light_peer_imports_header_from_announce() { - sp_tracing::try_init_simple(); - - fn import_with_announce(net: &mut TestNet, hash: H256) { - net.peer(0).announce_block(hash, None); - - block_on(futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - if net.peer(1).client().header(&BlockId::Hash(hash)).unwrap().is_some() { - Poll::Ready(()) - } else { - Poll::Pending - } - })); - } - - // given the network with 1 full nodes (#0) and 1 light node (#1) - let mut net = TestNet::new(1); - net.add_light_peer(); - - // let them connect to each other - net.block_until_sync(); - - // check that NEW block is imported from announce message - let new_hash = net.peer(0).push_blocks(1, false); - import_with_announce(&mut net, new_hash); - - // check that KNOWN STALE block is imported from announce message - let known_stale_hash = net.peer(0).push_blocks_at(BlockId::Number(0), 1, true); - import_with_announce(&mut net, known_stale_hash); -} - #[test] fn can_sync_explicit_forks() { sp_tracing::try_init_simple(); @@ -1210,16 +1114,14 @@ fn syncs_indexed_blocks() { assert!(net .peer(0) .client() - .as_full() - .unwrap() + .as_client() .indexed_transaction(&indexed_key) .unwrap() .is_some()); assert!(net .peer(1) .client() - .as_full() - .unwrap() + .as_client() .indexed_transaction(&indexed_key) .unwrap() .is_none()); @@ -1228,8 +1130,7 @@ fn syncs_indexed_blocks() { assert!(net .peer(1) .client() - .as_full() - .unwrap() + .as_client() .indexed_transaction(&indexed_key) .unwrap() .is_some()); diff --git a/client/rpc/src/chain/chain_light.rs b/client/rpc/src/chain/chain_light.rs deleted file mode 100644 index 2d15c819e1dab..0000000000000 --- a/client/rpc/src/chain/chain_light.rs +++ /dev/null @@ -1,114 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Blockchain API backend for light nodes. - -use futures::{future::ready, FutureExt, TryFutureExt}; -use jsonrpc_pubsub::manager::SubscriptionManager; -use std::sync::Arc; - -use sc_client_api::light::{Fetcher, RemoteBlockchain, RemoteBodyRequest}; -use sp_runtime::{ - generic::{BlockId, SignedBlock}, - traits::Block as BlockT, -}; - -use super::{client_err, error::FutureResult, ChainBackend}; -use sc_client_api::BlockchainEvents; -use sp_blockchain::HeaderBackend; - -/// Blockchain API backend for light nodes. Reads all the data from local -/// database, if available, or fetches it from remote node otherwise. -pub struct LightChain { - /// Substrate client. - client: Arc, - /// Current subscriptions. - subscriptions: SubscriptionManager, - /// Remote blockchain reference - remote_blockchain: Arc>, - /// Remote fetcher reference. - fetcher: Arc, -} - -impl> LightChain { - /// Create new Chain API RPC handler. - pub fn new( - client: Arc, - subscriptions: SubscriptionManager, - remote_blockchain: Arc>, - fetcher: Arc, - ) -> Self { - Self { client, subscriptions, remote_blockchain, fetcher } - } -} - -impl ChainBackend for LightChain -where - Block: BlockT + 'static, - Block::Header: Unpin, - Client: BlockchainEvents + HeaderBackend + Send + Sync + 'static, - F: Fetcher + Send + Sync + 'static, -{ - fn client(&self) -> &Arc { - &self.client - } - - fn subscriptions(&self) -> &SubscriptionManager { - &self.subscriptions - } - - fn header(&self, hash: Option) -> FutureResult> { - let hash = self.unwrap_or_best(hash); - - let fetcher = self.fetcher.clone(); - let maybe_header = sc_client_api::light::future_header( - &*self.remote_blockchain, - &*fetcher, - BlockId::Hash(hash), - ); - - maybe_header.then(move |result| ready(result.map_err(client_err))).boxed() - } - - fn block(&self, hash: Option) -> FutureResult>> { - let fetcher = self.fetcher.clone(); - self.header(hash) - .and_then(move |header| async move { - match header { - Some(header) => { - let body = fetcher - .remote_body(RemoteBodyRequest { - header: header.clone(), - retry_count: Default::default(), - }) - .await; - - body.map(|body| { - Some(SignedBlock { - block: Block::new(header, body), - justifications: None, - }) - }) - .map_err(client_err) - }, - None => Ok(None), - } - }) - .boxed() - } -} diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index 9428ac3248f32..c2f512c338b11 100644 --- a/client/rpc/src/chain/mod.rs +++ b/client/rpc/src/chain/mod.rs @@ -19,7 +19,6 @@ //! Substrate blockchain API. mod chain_full; -mod chain_light; #[cfg(test)] mod tests; @@ -33,10 +32,7 @@ use rpc::{ use std::sync::Arc; use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; -use sc_client_api::{ - light::{Fetcher, RemoteBlockchain}, - BlockchainEvents, -}; +use sc_client_api::BlockchainEvents; use sp_rpc::{list::ListOrValue, number::NumberOrHex}; use sp_runtime::{ generic::{BlockId, SignedBlock}, @@ -204,29 +200,6 @@ where Chain { backend: Box::new(self::chain_full::FullChain::new(client, subscriptions)) } } -/// Create new state API that works on light node. -pub fn new_light>( - client: Arc, - subscriptions: SubscriptionManager, - remote_blockchain: Arc>, - fetcher: Arc, -) -> Chain -where - Block: BlockT + 'static, - Block::Header: Unpin, - Client: BlockBackend + HeaderBackend + BlockchainEvents + 'static, - F: Send + Sync + 'static, -{ - Chain { - backend: Box::new(self::chain_light::LightChain::new( - client, - subscriptions, - remote_blockchain, - fetcher, - )), - } -} - /// Chain API with subscriptions support. pub struct Chain { backend: Box>, diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 97f77a4077962..d3b41d2f18279 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -26,11 +26,7 @@ use futures::{ use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; use log::warn; use rpc::Result as RpcResult; -use std::{ - collections::{BTreeMap, HashMap}, - ops::Range, - sync::Arc, -}; +use std::{collections::HashMap, sync::Arc}; use sc_rpc_api::state::ReadProof; use sp_blockchain::{ @@ -43,10 +39,7 @@ use sp_core::{ }, Bytes, }; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, CheckedSub, NumberFor, SaturatedConversion}, -}; +use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_version::RuntimeVersion; use sp_api::{CallApiAt, Metadata, ProvideRuntimeApi}; @@ -66,14 +59,6 @@ use std::marker::PhantomData; struct QueryStorageRange { /// Hashes of all the blocks in the range. pub hashes: Vec, - /// Number of the first block in the range. - pub first_number: NumberFor, - /// Blocks subrange ([begin; end) indices within `hashes`) where we should read keys at - /// each state to get changes. - pub unfiltered_range: Range, - /// Blocks subrange ([begin; end) indices within `hashes`) where we could pre-filter - /// blocks-with-changes by using changes tries. - pub filtered_range: Option>, } /// State API backend for full nodes. @@ -107,10 +92,8 @@ where Ok(hash.unwrap_or_else(|| self.client.info().best_hash)) } - /// Splits the `query_storage` block range into 'filtered' and 'unfiltered' subranges. - /// Blocks that contain changes within filtered subrange could be filtered using changes tries. - /// Blocks that contain changes within unfiltered subrange must be filtered manually. - fn split_query_storage_range( + /// Validates block range. + fn query_storage_range( &self, from: Block::Hash, to: Option, @@ -156,23 +139,7 @@ where hashes }; - // check if we can filter blocks-with-changes from some (sub)range using changes tries - let changes_trie_range = self - .client - .max_key_changes_range(from_number, BlockId::Hash(to_meta.hash)) - .map_err(client_err)?; - let filtered_range_begin = changes_trie_range.and_then(|(begin, _)| { - // avoids a corner case where begin < from_number (happens when querying genesis) - begin.checked_sub(&from_number).map(|x| x.saturated_into::()) - }); - let (unfiltered_range, filtered_range) = split_range(hashes.len(), filtered_range_begin); - - Ok(QueryStorageRange { - hashes, - first_number: from_number, - unfiltered_range, - filtered_range, - }) + Ok(QueryStorageRange { hashes }) } /// Iterates through range.unfiltered_range and check each block for changes of keys' values. @@ -183,8 +150,8 @@ where last_values: &mut HashMap>, changes: &mut Vec>, ) -> Result<()> { - for block in range.unfiltered_range.start..range.unfiltered_range.end { - let block_hash = range.hashes[block].clone(); + for block_hash in &range.hashes { + let block_hash = block_hash.clone(); let mut block_changes = StorageChangeSet { block: block_hash.clone(), changes: Vec::new() }; let id = BlockId::hash(block_hash); @@ -207,57 +174,6 @@ where } Ok(()) } - - /// Iterates through all blocks that are changing keys within range.filtered_range and collects - /// these changes. - fn query_storage_filtered( - &self, - range: &QueryStorageRange, - keys: &[StorageKey], - last_values: &HashMap>, - changes: &mut Vec>, - ) -> Result<()> { - let (begin, end) = match range.filtered_range { - Some(ref filtered_range) => ( - range.first_number + filtered_range.start.saturated_into(), - BlockId::Hash(range.hashes[filtered_range.end - 1].clone()), - ), - None => return Ok(()), - }; - let mut changes_map: BTreeMap, StorageChangeSet> = - BTreeMap::new(); - for key in keys { - let mut last_block = None; - let mut last_value = last_values.get(key).cloned().unwrap_or_default(); - let key_changes = self.client.key_changes(begin, end, None, key).map_err(client_err)?; - for (block, _) in key_changes.into_iter().rev() { - if last_block == Some(block) { - continue - } - - let block_hash = - range.hashes[(block - range.first_number).saturated_into::()].clone(); - let id = BlockId::Hash(block_hash); - let value_at_block = self.client.storage(&id, key).map_err(client_err)?; - if last_value == value_at_block { - continue - } - - changes_map - .entry(block) - .or_insert_with(|| StorageChangeSet { block: block_hash, changes: Vec::new() }) - .changes - .push((key.clone(), value_at_block.clone())); - last_block = Some(block); - last_value = value_at_block; - } - } - if let Some(additional_capacity) = changes_map.len().checked_sub(changes.len()) { - changes.reserve(additional_capacity); - } - changes.extend(changes_map.into_iter().map(|(_, cs)| cs)); - Ok(()) - } } impl StateBackend for FullState @@ -430,11 +346,10 @@ where keys: Vec, ) -> FutureResult>> { let call_fn = move || { - let range = self.split_query_storage_range(from, to)?; + let range = self.query_storage_range(from, to)?; let mut changes = Vec::new(); let mut last_values = HashMap::new(); self.query_storage_unfiltered(&range, &keys, &mut last_values, &mut changes)?; - self.query_storage_filtered(&range, &keys, &last_values, &mut changes)?; Ok(changes) }; @@ -768,30 +683,6 @@ where } } -/// Splits passed range into two subranges where: -/// - first range has at least one element in it; -/// - second range (optionally) starts at given `middle` element. -pub(crate) fn split_range( - size: usize, - middle: Option, -) -> (Range, Option>) { - // check if we can filter blocks-with-changes from some (sub)range using changes tries - let range2_begin = match middle { - // some of required changes tries are pruned => use available tries - Some(middle) if middle != 0 => Some(middle), - // all required changes tries are available, but we still want values at first block - // => do 'unfiltered' read for the first block and 'filtered' for the rest - Some(_) if size > 1 => Some(1), - // range contains single element => do not use changes tries - Some(_) => None, - // changes tries are not available => do 'unfiltered' read for the whole range - None => None, - }; - let range1 = 0..range2_begin.unwrap_or(size); - let range2 = range2_begin.map(|begin| begin..size); - (range1, range2) -} - fn invalid_block_range( from: &CachedHeaderMetadata, to: &CachedHeaderMetadata, diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 712fe00c54386..d360701c88b2a 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -17,16 +17,15 @@ // along with this program. If not, see . use self::error::Error; -use super::{state_full::split_range, *}; +use super::*; use crate::testing::TaskExecutor; use assert_matches::assert_matches; use futures::{executor, StreamExt}; use sc_block_builder::BlockBuilderProvider; use sc_rpc_api::DenyUnsafe; use sp_consensus::BlockOrigin; -use sp_core::{hash::H256, storage::ChildInfo, ChangesTrieConfiguration}; +use sp_core::{hash::H256, storage::ChildInfo}; use sp_io::hashing::blake2_256; -use sp_runtime::generic::BlockId; use std::sync::Arc; use substrate_test_runtime_client::{prelude::*, runtime}; @@ -336,7 +335,7 @@ fn should_send_initial_storage_changes_and_notifications() { #[test] fn should_query_storage() { - fn run_tests(mut client: Arc, has_changes_trie_config: bool) { + fn run_tests(mut client: Arc) { let (api, _child) = new_full( client.clone(), SubscriptionManager::new(Arc::new(TaskExecutor)), @@ -369,13 +368,6 @@ fn should_query_storage() { let block2_hash = add_block(1); let genesis_hash = client.genesis_hash(); - if has_changes_trie_config { - assert_eq!( - client.max_key_changes_range(1, BlockId::Hash(block1_hash)).unwrap(), - Some((0, BlockId::Hash(block1_hash))), - ); - } - let mut expected = vec![ StorageChangeSet { block: genesis_hash, @@ -519,24 +511,8 @@ fn should_query_storage() { ); } - run_tests(Arc::new(substrate_test_runtime_client::new()), false); - run_tests( - Arc::new( - TestClientBuilder::new() - .changes_trie_config(Some(ChangesTrieConfiguration::new(4, 2))) - .build(), - ), - true, - ); -} - -#[test] -fn should_split_ranges() { - assert_eq!(split_range(1, None), (0..1, None)); - assert_eq!(split_range(100, None), (0..100, None)); - assert_eq!(split_range(1, Some(0)), (0..1, None)); - assert_eq!(split_range(100, Some(50)), (0..50, Some(50..100))); - assert_eq!(split_range(100, Some(99)), (0..99, Some(99..100))); + run_tests(Arc::new(substrate_test_runtime_client::new())); + run_tests(Arc::new(TestClientBuilder::new().build())); } #[test] diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 88ba6282b5f4e..718cfce981f1a 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -30,9 +30,8 @@ use log::info; use prometheus_endpoint::Registry; use sc_chain_spec::get_extension; use sc_client_api::{ - execution_extensions::ExecutionExtensions, light::RemoteBlockchain, - proof_provider::ProofProvider, BadBlocks, BlockBackend, BlockchainEvents, ExecutorProvider, - ForkBlocks, StorageProvider, UsageProvider, + execution_extensions::ExecutionExtensions, proof_provider::ProofProvider, BadBlocks, + BlockBackend, BlockchainEvents, ExecutorProvider, ForkBlocks, StorageProvider, UsageProvider, }; use sc_client_db::{Backend, DatabaseSettings}; use sc_consensus::import_queue::ImportQueue; @@ -40,7 +39,7 @@ use sc_executor::RuntimeVersionOf; use sc_keystore::LocalKeystore; use sc_network::{ block_request_handler::{self, BlockRequestHandler}, - config::{OnDemand, Role, SyncMode}, + config::{Role, SyncMode}, light_client_requests::{self, handler::LightClientRequestHandler}, state_request_handler::{self, StateRequestHandler}, warp_request_handler::{self, RequestHandler as WarpSyncRequestHandler, WarpSyncProvider}, @@ -381,23 +380,19 @@ where pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> { /// The service configuration. pub config: Configuration, - /// A shared client returned by `new_full_parts`/`new_light_parts`. + /// A shared client returned by `new_full_parts`. pub client: Arc, - /// A shared backend returned by `new_full_parts`/`new_light_parts`. + /// A shared backend returned by `new_full_parts`. pub backend: Arc, - /// A task manager returned by `new_full_parts`/`new_light_parts`. + /// A task manager returned by `new_full_parts`. pub task_manager: &'a mut TaskManager, - /// A shared keystore returned by `new_full_parts`/`new_light_parts`. + /// A shared keystore returned by `new_full_parts`. pub keystore: SyncCryptoStorePtr, - /// An optional, shared data fetcher for light clients. - pub on_demand: Option>>, /// A shared transaction pool. pub transaction_pool: Arc, /// A RPC extension builder. Use `NoopRpcExtensionBuilder` if you just want to pass in the /// extensions directly. pub rpc_extensions_builder: Box + Send>, - /// An optional, shared remote blockchain instance. Used for light clients. - pub remote_blockchain: Option>>, /// A shared network instance. pub network: Arc::Hash>>, /// A Sender for RPC requests. @@ -475,12 +470,10 @@ where mut config, task_manager, client, - on_demand: _, backend, keystore, transaction_pool, rpc_extensions_builder, - remote_blockchain: _, network, system_rpc_tx, telemetry, @@ -725,7 +718,7 @@ where pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> { /// The service configuration. pub config: &'a Configuration, - /// A shared client returned by `new_full_parts`/`new_light_parts`. + /// A shared client returned by `new_full_parts`. pub client: Arc, /// A shared transaction pool. pub transaction_pool: Arc, @@ -733,8 +726,6 @@ pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> { pub spawn_handle: SpawnTaskHandle, /// An import queue. pub import_queue: TImpQu, - /// An optional, shared data fetcher for light clients. - pub on_demand: Option>>, /// A block announce validator builder. pub block_announce_validator_builder: Option) -> Box + Send> + Send>>, @@ -773,7 +764,6 @@ where transaction_pool, spawn_handle, import_queue, - on_demand, block_announce_validator_builder, warp_sync, } = params; @@ -869,7 +859,6 @@ where }, network_config: config.network.clone(), chain: client.clone(), - on_demand, transaction_pool: transaction_pool_adapter as _, import_queue: Box::new(import_queue), protocol_id, diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index d7a8b6f227e8f..be871cc371ed5 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -26,10 +26,7 @@ use sp_core::{ NativeOrEncoded, NeverNativeValue, }; use sp_externalities::Extensions; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, NumberFor}, -}; +use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_state_machine::{ self, backend::Backend as _, ExecutionManager, ExecutionStrategy, Ext, OverlayedChanges, StateMachine, StorageProof, @@ -153,8 +150,6 @@ where extensions: Option, ) -> sp_blockchain::Result> { let mut changes = OverlayedChanges::default(); - let changes_trie = - backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?; let state = self.backend.state_at(*at)?; let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); let runtime_code = @@ -168,7 +163,6 @@ where let return_data = StateMachine::new( &state, - changes_trie, &mut changes, &self.executor, method, @@ -208,8 +202,6 @@ where where ExecutionManager: Clone, { - let changes_trie_state = - backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?; let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut()); let state = self.backend.state_at(*at)?; @@ -243,7 +235,6 @@ where let mut state_machine = StateMachine::new( &backend, - changes_trie_state, changes, &self.executor, method, @@ -262,7 +253,6 @@ where None => { let mut state_machine = StateMachine::new( &state, - changes_trie_state, changes, &self.executor, method, @@ -286,11 +276,9 @@ where fn runtime_version(&self, id: &BlockId) -> sp_blockchain::Result { let mut overlay = OverlayedChanges::default(); - let changes_trie_state = - backend::changes_tries_state_at_block(id, self.backend.changes_trie_storage())?; let state = self.backend.state_at(*id)?; let mut cache = StorageTransactionCache::::default(); - let mut ext = Ext::new(&mut overlay, &mut cache, &state, changes_trie_state, None); + let mut ext = Ext::new(&mut overlay, &mut cache, &state, None); let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; @@ -317,7 +305,7 @@ where state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; let runtime_code = self.check_override(runtime_code, at)?; - sp_state_machine::prove_execution_on_trie_backend::<_, _, NumberFor, _, _>( + sp_state_machine::prove_execution_on_trie_backend( &trie_backend, &mut Default::default(), &self.executor, diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 6ce2feb050759..b46c6b99b9a9c 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -23,7 +23,6 @@ use super::{ genesis, }; use codec::{Decode, Encode}; -use hash_db::Prefix; use log::{info, trace, warn}; use parking_lot::{Mutex, RwLock}; use prometheus_endpoint::Registry; @@ -31,18 +30,15 @@ use rand::Rng; use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider, RecordProof}; use sc_client_api::{ backend::{ - self, apply_aux, changes_tries_state_at_block, BlockImportOperation, ClientImportOperation, - Finalizer, ImportSummary, LockImportRun, NewBlockState, PrunableStateChangesTrieStorage, - StorageProvider, + self, apply_aux, BlockImportOperation, ClientImportOperation, Finalizer, ImportSummary, + LockImportRun, NewBlockState, StorageProvider, }, - cht, client::{ BadBlocks, BlockBackend, BlockImportNotification, BlockOf, BlockchainEvents, ClientInfo, FinalityNotification, FinalityNotifications, ForkBlocks, ImportNotifications, ProvideUncles, }, execution_extensions::ExecutionExtensions, - light::ChangesProof, notifications::{StorageEventStream, StorageNotifications}, CallExecutor, ExecutorProvider, KeyIterator, ProofProvider, UsageProvider, }; @@ -56,39 +52,36 @@ use sp_api::{ ProvideRuntimeApi, }; use sp_blockchain::{ - self as blockchain, well_known_cache_keys::Id as CacheKeyId, Backend as ChainBackend, Cache, - CachedHeaderMetadata, Error, HeaderBackend as ChainHeaderBackend, HeaderMetadata, ProvideCache, + self as blockchain, well_known_cache_keys::Id as CacheKeyId, Backend as ChainBackend, + CachedHeaderMetadata, Error, HeaderBackend as ChainHeaderBackend, HeaderMetadata, }; use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sp_core::{ - convert_hash, storage::{ well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, StorageChild, StorageData, StorageKey, }, - ChangesTrieConfiguration, NativeOrEncoded, + NativeOrEncoded, }; #[cfg(feature = "test-helpers")] use sp_keystore::SyncCryptoStorePtr; use sp_runtime::{ - generic::{BlockId, DigestItem, SignedBlock}, + generic::{BlockId, SignedBlock}, traits::{ - Block as BlockT, DigestFor, HashFor, Header as HeaderT, NumberFor, One, - SaturatedConversion, Zero, + Block as BlockT, HashFor, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero, }, - BuildStorage, Justification, Justifications, + BuildStorage, Digest, Justification, Justifications, }; use sp_state_machine::{ - key_changes, key_changes_proof, prove_child_read, prove_range_read_with_child_with_size, - prove_read, read_range_proof_check_with_child_on_proving_backend, Backend as StateBackend, - ChangesTrieAnchorBlockId, ChangesTrieConfigurationRange, ChangesTrieRootsStorage, - ChangesTrieStorage, DBValue, KeyValueStates, KeyValueStorageLevel, MAX_NESTED_TRIE_DEPTH, + prove_child_read, prove_range_read_with_child_with_size, prove_read, + read_range_proof_check_with_child_on_proving_backend, Backend as StateBackend, KeyValueStates, + KeyValueStorageLevel, MAX_NESTED_TRIE_DEPTH, }; use sp_trie::{CompactProof, StorageProof}; use std::{ - collections::{BTreeMap, HashMap, HashSet}, + collections::{HashMap, HashSet}, marker::PhantomData, panic::UnwindSafe, path::PathBuf, @@ -413,250 +406,6 @@ where self.executor.runtime_version(id) } - /// Reads given header and generates CHT-based header proof for CHT of given size. - pub fn header_proof_with_cht_size( - &self, - id: &BlockId, - cht_size: NumberFor, - ) -> sp_blockchain::Result<(Block::Header, StorageProof)> { - let proof_error = || { - sp_blockchain::Error::Backend(format!("Failed to generate header proof for {:?}", id)) - }; - let header = self.backend.blockchain().expect_header(*id)?; - let block_num = *header.number(); - let cht_num = cht::block_to_cht_number(cht_size, block_num).ok_or_else(proof_error)?; - let cht_start = cht::start_number(cht_size, cht_num); - let mut current_num = cht_start; - let cht_range = ::std::iter::from_fn(|| { - let old_current_num = current_num; - current_num = current_num + One::one(); - Some(old_current_num) - }); - let headers = cht_range.map(|num| self.block_hash(num)); - let proof = cht::build_proof::, _, _>( - cht_size, - cht_num, - std::iter::once(block_num), - headers, - )?; - Ok((header, proof)) - } - - /// Does the same work as `key_changes_proof`, but assumes that CHTs are of passed size. - pub fn key_changes_proof_with_cht_size( - &self, - first: Block::Hash, - last: Block::Hash, - min: Block::Hash, - max: Block::Hash, - storage_key: Option<&PrefixedStorageKey>, - key: &StorageKey, - cht_size: NumberFor, - ) -> sp_blockchain::Result> { - struct AccessedRootsRecorder<'a, Block: BlockT> { - storage: &'a dyn ChangesTrieStorage, NumberFor>, - min: NumberFor, - required_roots_proofs: Mutex, Block::Hash>>, - } - - impl<'a, Block: BlockT> ChangesTrieRootsStorage, NumberFor> - for AccessedRootsRecorder<'a, Block> - { - fn build_anchor( - &self, - hash: Block::Hash, - ) -> Result>, String> { - self.storage.build_anchor(hash) - } - - fn root( - &self, - anchor: &ChangesTrieAnchorBlockId>, - block: NumberFor, - ) -> Result, String> { - let root = self.storage.root(anchor, block)?; - if block < self.min { - if let Some(ref root) = root { - self.required_roots_proofs.lock().insert(block, root.clone()); - } - } - Ok(root) - } - } - - impl<'a, Block: BlockT> ChangesTrieStorage, NumberFor> - for AccessedRootsRecorder<'a, Block> - { - fn as_roots_storage( - &self, - ) -> &dyn sp_state_machine::ChangesTrieRootsStorage, NumberFor> { - self - } - - fn with_cached_changed_keys( - &self, - root: &Block::Hash, - functor: &mut dyn FnMut(&HashMap, HashSet>>), - ) -> bool { - self.storage.with_cached_changed_keys(root, functor) - } - - fn get(&self, key: &Block::Hash, prefix: Prefix) -> Result, String> { - self.storage.get(key, prefix) - } - } - - let first_number = - self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(first))?; - let (storage, configs) = self.require_changes_trie(first_number, last, true)?; - let min_number = - self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(min))?; - - let recording_storage = AccessedRootsRecorder:: { - storage: storage.storage(), - min: min_number, - required_roots_proofs: Mutex::new(BTreeMap::new()), - }; - - let max_number = std::cmp::min( - self.backend.blockchain().info().best_number, - self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(max))?, - ); - - // fetch key changes proof - let mut proof = Vec::new(); - for (config_zero, config_end, config) in configs { - let last_number = - self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(last))?; - let config_range = ChangesTrieConfigurationRange { - config: &config, - zero: config_zero, - end: config_end.map(|(config_end_number, _)| config_end_number), - }; - let proof_range = key_changes_proof::, _>( - config_range, - &recording_storage, - first_number, - &ChangesTrieAnchorBlockId { hash: convert_hash(&last), number: last_number }, - max_number, - storage_key, - &key.0, - ) - .map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))?; - proof.extend(proof_range); - } - - // now gather proofs for all changes tries roots that were touched during key_changes_proof - // execution AND are unknown (i.e. replaced with CHT) to the requester - let roots = recording_storage.required_roots_proofs.into_inner(); - let roots_proof = self.changes_trie_roots_proof(cht_size, roots.keys().cloned())?; - - Ok(ChangesProof { - max_block: max_number, - proof, - roots: roots.into_iter().map(|(n, h)| (n, convert_hash(&h))).collect(), - roots_proof, - }) - } - - /// Generate CHT-based proof for roots of changes tries at given blocks. - fn changes_trie_roots_proof>>( - &self, - cht_size: NumberFor, - blocks: I, - ) -> sp_blockchain::Result { - // most probably we have touched several changes tries that are parts of the single CHT - // => GroupBy changes tries by CHT number and then gather proof for the whole group at once - let mut proofs = Vec::new(); - - cht::for_each_cht_group::( - cht_size, - blocks, - |_, cht_num, cht_blocks| { - let cht_proof = - self.changes_trie_roots_proof_at_cht(cht_size, cht_num, cht_blocks)?; - proofs.push(cht_proof); - Ok(()) - }, - (), - )?; - - Ok(StorageProof::merge(proofs)) - } - - /// Generates CHT-based proof for roots of changes tries at given blocks - /// (that are part of single CHT). - fn changes_trie_roots_proof_at_cht( - &self, - cht_size: NumberFor, - cht_num: NumberFor, - blocks: Vec>, - ) -> sp_blockchain::Result { - let cht_start = cht::start_number(cht_size, cht_num); - let mut current_num = cht_start; - let cht_range = ::std::iter::from_fn(|| { - let old_current_num = current_num; - current_num = current_num + One::one(); - Some(old_current_num) - }); - let roots = cht_range.map(|num| { - self.header(&BlockId::Number(num)).map(|block| { - block - .and_then(|block| block.digest().log(DigestItem::as_changes_trie_root).cloned()) - }) - }); - let proof = cht::build_proof::, _, _>( - cht_size, cht_num, blocks, roots, - )?; - Ok(proof) - } - - /// Returns changes trie storage and all configurations that have been active - /// in the range [first; last]. - /// - /// Configurations are returned in descending order (and obviously never overlap). - /// If fail_if_disabled is false, returns maximal consequent configurations ranges, - /// starting from last and stopping on either first, or when CT have been disabled. - /// If fail_if_disabled is true, fails when there's a subrange where CT have been disabled - /// inside first..last blocks range. - fn require_changes_trie( - &self, - first: NumberFor, - last: Block::Hash, - fail_if_disabled: bool, - ) -> sp_blockchain::Result<( - &dyn PrunableStateChangesTrieStorage, - Vec<(NumberFor, Option<(NumberFor, Block::Hash)>, ChangesTrieConfiguration)>, - )> { - let storage = self - .backend - .changes_trie_storage() - .ok_or_else(|| sp_blockchain::Error::ChangesTriesNotSupported)?; - - let mut configs = Vec::with_capacity(1); - let mut current = last; - loop { - let config_range = storage.configuration_at(&BlockId::Hash(current))?; - match config_range.config { - Some(config) => configs.push((config_range.zero.0, config_range.end, config)), - None if !fail_if_disabled => return Ok((storage, configs)), - None => return Err(sp_blockchain::Error::ChangesTriesNotSupported), - } - - if config_range.zero.0 < first { - break - } - - current = *self - .backend - .blockchain() - .expect_header(BlockId::Hash(config_range.zero.1))? - .parent_hash(); - } - - Ok((storage, configs)) - } - /// Apply a checked and validated block to an operation. If a justification is provided /// then `finalized` *must* be true. fn apply_block( @@ -811,7 +560,7 @@ where sc_consensus::StorageChanges::Changes(storage_changes) => { self.backend .begin_state_operation(&mut operation.op, BlockId::Hash(parent_hash))?; - let (main_sc, child_sc, offchain_sc, tx, _, changes_trie_tx, tx_index) = + let (main_sc, child_sc, offchain_sc, tx, _, tx_index) = storage_changes.into_inner(); if self.config.offchain_indexing_api { @@ -822,9 +571,6 @@ where operation.op.update_storage(main_sc.clone(), child_sc.clone())?; operation.op.update_transaction_index(tx_index)?; - if let Some(changes_trie_transaction) = changes_trie_tx { - operation.op.update_changes_trie(changes_trie_transaction)?; - } Some((main_sc, child_sc)) }, sc_consensus::StorageChanges::Import(changes) => { @@ -1003,11 +749,8 @@ where )?; let state = self.backend.state_at(at)?; - let changes_trie_state = - changes_tries_state_at_block(&at, self.backend.changes_trie_storage())?; - let gen_storage_changes = runtime_api - .into_storage_changes(&state, changes_trie_state.as_ref(), *parent_hash) + .into_storage_changes(&state, *parent_hash) .map_err(sp_blockchain::Error::Storage)?; if import_block.header.state_root() != &gen_storage_changes.transaction_storage_root @@ -1356,25 +1099,6 @@ where .map(|(r, p)| (r, StorageProof::merge(vec![p, code_proof]))) } - fn header_proof( - &self, - id: &BlockId, - ) -> sp_blockchain::Result<(Block::Header, StorageProof)> { - self.header_proof_with_cht_size(id, cht::size()) - } - - fn key_changes_proof( - &self, - first: Block::Hash, - last: Block::Hash, - min: Block::Hash, - max: Block::Hash, - storage_key: Option<&PrefixedStorageKey>, - key: &StorageKey, - ) -> sp_blockchain::Result> { - self.key_changes_proof_with_cht_size(first, last, min, max, storage_key, key, cht::size()) - } - fn read_proof_collection( &self, id: &BlockId, @@ -1540,7 +1264,7 @@ where fn new_block_at>( &self, parent: &BlockId, - inherent_digests: DigestFor, + inherent_digests: Digest, record_proof: R, ) -> sp_blockchain::Result> { sc_block_builder::BlockBuilder::new( @@ -1555,7 +1279,7 @@ where fn new_block( &self, - inherent_digests: DigestFor, + inherent_digests: Digest, ) -> sp_blockchain::Result> { let info = self.chain_info(); sc_block_builder::BlockBuilder::new( @@ -1703,89 +1427,6 @@ where .child_storage_hash(child_info, &key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?) } - - fn max_key_changes_range( - &self, - first: NumberFor, - last: BlockId, - ) -> sp_blockchain::Result, BlockId)>> { - let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?; - let last_hash = self.backend.blockchain().expect_block_hash_from_id(&last)?; - if first > last_number { - return Err(sp_blockchain::Error::ChangesTrieAccessFailed( - "Invalid changes trie range".into(), - )) - } - - let (storage, configs) = match self.require_changes_trie(first, last_hash, false).ok() { - Some((storage, configs)) => (storage, configs), - None => return Ok(None), - }; - - let first_available_changes_trie = configs.last().map(|config| config.0); - match first_available_changes_trie { - Some(first_available_changes_trie) => { - let oldest_unpruned = storage.oldest_pruned_digest_range_end(); - let first = std::cmp::max(first_available_changes_trie, oldest_unpruned); - Ok(Some((first, last))) - }, - None => Ok(None), - } - } - - fn key_changes( - &self, - first: NumberFor, - last: BlockId, - storage_key: Option<&PrefixedStorageKey>, - key: &StorageKey, - ) -> sp_blockchain::Result, u32)>> { - let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?; - let last_hash = self.backend.blockchain().expect_block_hash_from_id(&last)?; - let (storage, configs) = self.require_changes_trie(first, last_hash, true)?; - - let mut result = Vec::new(); - let best_number = self.backend.blockchain().info().best_number; - for (config_zero, config_end, config) in configs { - let range_first = ::std::cmp::max(first, config_zero + One::one()); - let range_anchor = match config_end { - Some((config_end_number, config_end_hash)) => - if last_number > config_end_number { - ChangesTrieAnchorBlockId { - hash: config_end_hash, - number: config_end_number, - } - } else { - ChangesTrieAnchorBlockId { - hash: convert_hash(&last_hash), - number: last_number, - } - }, - None => - ChangesTrieAnchorBlockId { hash: convert_hash(&last_hash), number: last_number }, - }; - - let config_range = ChangesTrieConfigurationRange { - config: &config, - zero: config_zero.clone(), - end: config_end.map(|(config_end_number, _)| config_end_number), - }; - let result_range: Vec<(NumberFor, u32)> = key_changes::, _>( - config_range, - storage.storage(), - range_first, - &range_anchor, - best_number, - storage_key, - &key.0, - ) - .and_then(|r| r.map(|r| r.map(|(block, tx)| (block, tx))).collect::>()) - .map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))?; - result.extend(result_range); - } - - Ok(result) - } } impl HeaderMetadata for Client @@ -1913,16 +1554,6 @@ where } } -impl ProvideCache for Client -where - B: backend::Backend, - Block: BlockT, -{ - fn cache(&self) -> Option>> { - self.backend.blockchain().cache() - } -} - impl ProvideRuntimeApi for Client where B: backend::Backend, diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index bd43d4c464ea0..563846c75d89a 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -68,7 +68,7 @@ use sc_client_api::{blockchain::HeaderBackend, BlockchainEvents}; pub use sc_consensus::ImportQueue; pub use sc_executor::NativeExecutionDispatch; #[doc(hidden)] -pub use sc_network::config::{OnDemand, TransactionImport, TransactionImportFuture}; +pub use sc_network::config::{TransactionImport, TransactionImportFuture}; pub use sc_rpc::Metadata as RpcMetadata; pub use sc_tracing::TracingReceiver; pub use sc_transaction_pool::Options as TransactionPoolOptions; diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 03967db15f678..7694e0f6893d6 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -19,7 +19,6 @@ tokio = { version = "1.10.0", features = ["time"] } log = "0.4.8" fdlimit = "0.2.1" parking_lot = "0.11.1" -sc-light = { version = "4.0.0-dev", path = "../../light" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } diff --git a/client/service/test/src/client/db.rs b/client/service/test/src/client/db.rs index 772fdcada72ef..5278c9a13a4d7 100644 --- a/client/service/test/src/client/db.rs +++ b/client/service/test/src/client/db.rs @@ -21,7 +21,6 @@ use std::sync::Arc; type TestBackend = sc_client_api::in_mem::Backend; - #[test] fn test_leaves_with_complex_block_tree() { let backend = Arc::new(TestBackend::new()); diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 33cbefbb06a95..d5e23d319e83e 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -27,29 +27,25 @@ use sc_client_db::{ use sc_consensus::{ BlockCheckParams, BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, }; -use sc_service::client::{self, new_in_mem, Client, LocalCallExecutor}; +use sc_service::client::{new_in_mem, Client, LocalCallExecutor}; use sp_api::ProvideRuntimeApi; use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError, SelectChain}; -use sp_core::{blake2_256, testing::TaskExecutor, ChangesTrieConfiguration, H256}; +use sp_core::{testing::TaskExecutor, H256}; use sp_runtime::{ generic::BlockId, traits::{BlakeTwo256, Block as BlockT, Header as HeaderT}, - ConsensusEngineId, DigestItem, Justifications, + ConsensusEngineId, Justifications, }; use sp_state_machine::{ backend::Backend as _, ExecutionStrategy, InMemoryBackend, OverlayedChanges, StateMachine, }; use sp_storage::{ChildInfo, StorageKey}; use sp_trie::{trie_types::Layout, TrieConfiguration}; -use std::{ - collections::{HashMap, HashSet}, - sync::Arc, -}; +use std::{collections::HashSet, sync::Arc}; use substrate_test_runtime::TestAPI; use substrate_test_runtime_client::{ prelude::*, runtime::{ - self, genesismap::{insert_genesis_block, GenesisConfig}, Block, BlockNumber, Digest, Hash, Header, RuntimeApi, Transfer, }, @@ -57,6 +53,8 @@ use substrate_test_runtime_client::{ Sr25519Keyring, TestClientBuilder, TestClientBuilderExt, }; +mod db; + const TEST_ENGINE_ID: ConsensusEngineId = *b"TEST"; pub struct ExecutorDispatch; @@ -77,86 +75,6 @@ fn executor() -> sc_executor::NativeElseWasmExecutor { sc_executor::NativeElseWasmExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None, 8) } -pub fn prepare_client_with_key_changes() -> ( - client::Client< - substrate_test_runtime_client::Backend, - substrate_test_runtime_client::ExecutorDispatch, - Block, - RuntimeApi, - >, - Vec, - Vec<(u64, u64, Vec, Vec<(u64, u32)>)>, -) { - // prepare block structure - let blocks_transfers = vec![ - vec![ - (AccountKeyring::Alice, AccountKeyring::Dave), - (AccountKeyring::Bob, AccountKeyring::Dave), - ], - vec![(AccountKeyring::Charlie, AccountKeyring::Eve)], - vec![], - vec![(AccountKeyring::Alice, AccountKeyring::Dave)], - ]; - - // prepare client ang import blocks - let mut local_roots = Vec::new(); - let config = Some(ChangesTrieConfiguration::new(4, 2)); - let mut remote_client = TestClientBuilder::new().changes_trie_config(config).build(); - let mut nonces: HashMap<_, u64> = Default::default(); - for (i, block_transfers) in blocks_transfers.into_iter().enumerate() { - let mut builder = remote_client.new_block(Default::default()).unwrap(); - for (from, to) in block_transfers { - builder - .push_transfer(Transfer { - from: from.into(), - to: to.into(), - amount: 1, - nonce: *nonces.entry(from).and_modify(|n| *n = *n + 1).or_default(), - }) - .unwrap(); - } - let block = builder.build().unwrap().block; - block_on(remote_client.import(BlockOrigin::Own, block)).unwrap(); - - let header = remote_client.header(&BlockId::Number(i as u64 + 1)).unwrap().unwrap(); - let trie_root = header - .digest() - .log(DigestItem::as_changes_trie_root) - .map(|root| H256::from_slice(root.as_ref())) - .unwrap(); - local_roots.push(trie_root); - } - - // prepare test cases - let alice = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Alice.into())).to_vec(); - let bob = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Bob.into())).to_vec(); - let charlie = - blake2_256(&runtime::system::balance_of_key(AccountKeyring::Charlie.into())).to_vec(); - let dave = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec(); - let eve = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Eve.into())).to_vec(); - let ferdie = - blake2_256(&runtime::system::balance_of_key(AccountKeyring::Ferdie.into())).to_vec(); - let test_cases = vec![ - (1, 4, alice.clone(), vec![(4, 0), (1, 0)]), - (1, 3, alice.clone(), vec![(1, 0)]), - (2, 4, alice.clone(), vec![(4, 0)]), - (2, 3, alice.clone(), vec![]), - (1, 4, bob.clone(), vec![(1, 1)]), - (1, 1, bob.clone(), vec![(1, 1)]), - (2, 4, bob.clone(), vec![]), - (1, 4, charlie.clone(), vec![(2, 0)]), - (1, 4, dave.clone(), vec![(4, 0), (1, 1), (1, 0)]), - (1, 1, dave.clone(), vec![(1, 1), (1, 0)]), - (3, 4, dave.clone(), vec![(4, 0)]), - (1, 4, eve.clone(), vec![(2, 0)]), - (1, 1, eve.clone(), vec![]), - (3, 4, eve.clone(), vec![]), - (1, 4, ferdie.clone(), vec![]), - ]; - - (remote_client, local_roots, test_cases) -} - fn construct_block( backend: &InMemoryBackend, number: BlockNumber, @@ -184,7 +102,6 @@ fn construct_block( StateMachine::new( backend, - sp_state_machine::disabled_changes_trie_state::<_, u64>(), &mut overlay, &executor(), "Core_initialize_block", @@ -199,7 +116,6 @@ fn construct_block( for tx in transactions.iter() { StateMachine::new( backend, - sp_state_machine::disabled_changes_trie_state::<_, u64>(), &mut overlay, &executor(), "BlockBuilder_apply_extrinsic", @@ -214,7 +130,6 @@ fn construct_block( let ret_data = StateMachine::new( backend, - sp_state_machine::disabled_changes_trie_state::<_, u64>(), &mut overlay, &executor(), "BlockBuilder_finalize_block", @@ -248,7 +163,6 @@ fn block1(genesis_hash: Hash, backend: &InMemoryBackend) -> (Vec(), &mut overlay, &executor(), "Core_execute_block", @@ -283,7 +196,6 @@ fn construct_genesis_should_work_with_native() { #[test] fn construct_genesis_should_work_with_wasm() { let mut storage = GenesisConfig::new( - None, vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()], vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], 1000, @@ -302,7 +214,6 @@ fn construct_genesis_should_work_with_wasm() { let _ = StateMachine::new( &backend, - sp_state_machine::disabled_changes_trie_state::<_, u64>(), &mut overlay, &executor(), "Core_execute_block", @@ -318,7 +229,6 @@ fn construct_genesis_should_work_with_wasm() { #[test] fn construct_genesis_with_bad_transaction_should_panic() { let mut storage = GenesisConfig::new( - None, vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()], vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], 68, @@ -337,7 +247,6 @@ fn construct_genesis_with_bad_transaction_should_panic() { let r = StateMachine::new( &backend, - sp_state_machine::disabled_changes_trie_state::<_, u64>(), &mut overlay, &executor(), "Core_execute_block", @@ -906,23 +815,6 @@ fn best_containing_on_longest_chain_with_max_depth_higher_than_best() { ); } -#[test] -fn key_changes_works() { - let (client, _, test_cases) = prepare_client_with_key_changes(); - - for (index, (begin, end, key, expected_result)) in test_cases.into_iter().enumerate() { - let end = client.block_hash(end).unwrap().unwrap(); - let actual_result = - client.key_changes(begin, BlockId::Hash(end), None, &StorageKey(key)).unwrap(); - if actual_result != expected_result { - panic!( - "Failed test {}: actual = {:?}, expected = {:?}", - index, actual_result, expected_result, - ); - } - } -} - #[test] fn import_with_justification() { let mut client = substrate_test_runtime_client::new(); @@ -1229,12 +1121,8 @@ fn doesnt_import_blocks_that_revert_finality() { ClientExt::finalize_block(&client, BlockId::Hash(a2.hash()), None).unwrap(); let import_err = block_on(client.import(BlockOrigin::Own, b3)).err().unwrap(); - let expected_err = ConsensusError::ClientImport( - sp_blockchain::Error::RuntimeApiError(sp_api::ApiError::Application(Box::new( - sp_blockchain::Error::NotInFinalizedChain, - ))) - .to_string(), - ); + let expected_err = + ConsensusError::ClientImport(sp_blockchain::Error::NotInFinalizedChain.to_string()); assert_eq!(import_err.to_string(), expected_err.to_string()); @@ -1536,152 +1424,6 @@ fn returns_status_for_pruned_blocks() { ); } -#[test] -fn imports_blocks_with_changes_tries_config_change() { - // create client with initial 4^2 configuration - let mut client = TestClientBuilder::with_default_backend() - .changes_trie_config(Some(ChangesTrieConfiguration { - digest_interval: 4, - digest_levels: 2, - })) - .build(); - - // =================================================================== - // blocks 1,2,3,4,5,6,7,8,9,10 are empty - // block 11 changes the key - // block 12 is the L1 digest that covers this change - // blocks 13,14,15,16,17,18,19,20,21,22 are empty - // block 23 changes the configuration to 5^1 AND is skewed digest - // =================================================================== - // blocks 24,25 are changing the key - // block 26 is empty - // block 27 changes the key - // block 28 is the L1 digest (NOT SKEWED!!!) that covers changes AND changes configuration to - // `3^1` - // =================================================================== - // block 29 is empty - // block 30 changes the key - // block 31 is L1 digest that covers this change - // =================================================================== - (1..11).for_each(|number| { - let block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap() - .build() - .unwrap() - .block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - (11..12).for_each(|number| { - let mut block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap(); - block - .push_storage_change(vec![42], Some(number.to_le_bytes().to_vec())) - .unwrap(); - let block = block.build().unwrap().block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - (12..23).for_each(|number| { - let block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap() - .build() - .unwrap() - .block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - (23..24).for_each(|number| { - let mut block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap(); - block - .push_changes_trie_configuration_update(Some(ChangesTrieConfiguration { - digest_interval: 5, - digest_levels: 1, - })) - .unwrap(); - let block = block.build().unwrap().block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - (24..26).for_each(|number| { - let mut block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap(); - block - .push_storage_change(vec![42], Some(number.to_le_bytes().to_vec())) - .unwrap(); - let block = block.build().unwrap().block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - (26..27).for_each(|number| { - let block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap() - .build() - .unwrap() - .block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - (27..28).for_each(|number| { - let mut block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap(); - block - .push_storage_change(vec![42], Some(number.to_le_bytes().to_vec())) - .unwrap(); - let block = block.build().unwrap().block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - (28..29).for_each(|number| { - let mut block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap(); - block - .push_changes_trie_configuration_update(Some(ChangesTrieConfiguration { - digest_interval: 3, - digest_levels: 1, - })) - .unwrap(); - let block = block.build().unwrap().block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - (29..30).for_each(|number| { - let block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap() - .build() - .unwrap() - .block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - (30..31).for_each(|number| { - let mut block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap(); - block - .push_storage_change(vec![42], Some(number.to_le_bytes().to_vec())) - .unwrap(); - let block = block.build().unwrap().block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - (31..32).for_each(|number| { - let block = client - .new_block_at(&BlockId::Number(number - 1), Default::default(), false) - .unwrap() - .build() - .unwrap() - .block; - block_on(client.import(BlockOrigin::Own, block)).unwrap(); - }); - - // now check that configuration cache works - assert_eq!( - client.key_changes(1, BlockId::Number(31), None, &StorageKey(vec![42])).unwrap(), - vec![(30, 0), (27, 0), (25, 0), (24, 0), (11, 0)] - ); -} - #[test] fn storage_keys_iter_prefix_and_start_key_works() { let child_info = ChildInfo::new_default(b"child"); diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index 8af0ea98f8100..08fe1e34edb88 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -18,7 +18,7 @@ //! Chain api required for the transaction pool. -use codec::{Decode, Encode}; +use codec::Encode; use futures::{ channel::{mpsc, oneshot}, future::{ready, Future, FutureExt, Ready}, @@ -28,16 +28,12 @@ use futures::{ use std::{marker::PhantomData, pin::Pin, sync::Arc}; use prometheus_endpoint::Registry as PrometheusRegistry; -use sc_client_api::{ - blockchain::HeaderBackend, - light::{Fetcher, RemoteBodyRequest, RemoteCallRequest}, - BlockBackend, -}; +use sc_client_api::{blockchain::HeaderBackend, BlockBackend}; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_core::traits::SpawnEssentialNamed; use sp_runtime::{ generic::BlockId, - traits::{self, Block as BlockT, BlockIdTo, Hash as HashT, Header as HeaderT}, + traits::{self, Block as BlockT, BlockIdTo}, transaction_validity::{TransactionSource, TransactionValidity}, }; use sp_transaction_pool::runtime_api::TaggedTransactionQueue; @@ -290,127 +286,3 @@ where validate_transaction_blocking(&*self.client, at, source, uxt) } } - -/// The transaction pool logic for light client. -pub struct LightChainApi { - client: Arc, - fetcher: Arc, - _phantom: PhantomData, -} - -impl LightChainApi { - /// Create new transaction pool logic. - pub fn new(client: Arc, fetcher: Arc) -> Self { - LightChainApi { client, fetcher, _phantom: Default::default() } - } -} - -impl graph::ChainApi for LightChainApi -where - Block: BlockT, - Client: HeaderBackend + 'static, - F: Fetcher + 'static, -{ - type Block = Block; - type Error = error::Error; - type ValidationFuture = - Box> + Send + Unpin>; - type BodyFuture = Pin< - Box< - dyn Future::Extrinsic>>>> - + Send, - >, - >; - - fn validate_transaction( - &self, - at: &BlockId, - source: TransactionSource, - uxt: graph::ExtrinsicFor, - ) -> Self::ValidationFuture { - let header_hash = self.client.expect_block_hash_from_id(at); - let header_and_hash = header_hash.and_then(|header_hash| { - self.client - .expect_header(BlockId::Hash(header_hash)) - .map(|header| (header_hash, header)) - }); - let (block, header) = match header_and_hash { - Ok((header_hash, header)) => (header_hash, header), - Err(err) => return Box::new(ready(Err(err.into()))), - }; - let remote_validation_request = self.fetcher.remote_call(RemoteCallRequest { - block, - header, - method: "TaggedTransactionQueue_validate_transaction".into(), - call_data: (source, uxt, block).encode(), - retry_count: None, - }); - let remote_validation_request = remote_validation_request.then(move |result| { - let result: error::Result = - result.map_err(Into::into).and_then(|result| { - Decode::decode(&mut &result[..]).map_err(|e| { - Error::RuntimeApi(format!("Error decoding tx validation result: {:?}", e)) - }) - }); - ready(result) - }); - - Box::new(remote_validation_request) - } - - fn block_id_to_number( - &self, - at: &BlockId, - ) -> error::Result>> { - Ok(self.client.block_number_from_id(at)?) - } - - fn block_id_to_hash( - &self, - at: &BlockId, - ) -> error::Result>> { - Ok(self.client.block_hash_from_id(at)?) - } - - fn hash_and_length( - &self, - ex: &graph::ExtrinsicFor, - ) -> (graph::ExtrinsicHash, usize) { - ex.using_encoded(|x| (<::Hashing as HashT>::hash(x), x.len())) - } - - fn block_body(&self, id: &BlockId) -> Self::BodyFuture { - let header = self - .client - .header(*id) - .and_then(|h| h.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", id)))); - let header = match header { - Ok(header) => header, - Err(err) => { - log::warn!(target: "txpool", "Failed to query header: {:?}", err); - return Box::pin(ready(Ok(None))) - }, - }; - - let fetcher = self.fetcher.clone(); - async move { - let transactions = fetcher - .remote_body(RemoteBodyRequest { header, retry_count: None }) - .await - .unwrap_or_else(|e| { - log::warn!(target: "txpool", "Failed to fetch block body: {:?}", e); - Vec::new() - }); - - Ok(Some(transactions)) - } - .boxed() - } - - fn block_header( - &self, - at: &BlockId, - ) -> Result::Header>, Self::Error> { - self.client.header(*at).map_err(Into::into) - } -} diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 3565cb52ad87b..85af4f89d72b5 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -38,7 +38,7 @@ pub mod test_helpers { }; } -pub use crate::api::{FullChainApi, LightChainApi}; +pub use crate::api::FullChainApi; use futures::{ channel::oneshot, future::{self, ready}, @@ -79,9 +79,6 @@ type PolledIterator = Pin = BasicPool, Block>; -/// A transaction pool for a light node. -pub type LightPool = - BasicPool, Block>; /// Basic implementation of transaction pool that can be customized by providing PoolApi. pub struct BasicPool @@ -364,33 +361,6 @@ where } } -impl LightPool -where - Block: BlockT, - Client: sp_blockchain::HeaderBackend + sc_client_api::UsageProvider + 'static, - Fetcher: sc_client_api::Fetcher + 'static, -{ - /// Create new basic transaction pool for a light node with the provided api. - pub fn new_light( - options: graph::Options, - prometheus: Option<&PrometheusRegistry>, - spawner: impl SpawnEssentialNamed, - client: Arc, - fetcher: Arc, - ) -> Self { - let pool_api = Arc::new(LightChainApi::new(client.clone(), fetcher)); - Self::with_revalidation_type( - options, - false.into(), - pool_api, - prometheus, - RevalidationType::Light, - spawner, - client.usage_info().chain.best_number, - ) - } -} - impl FullPool where Block: BlockT, diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index a4e55f25df5f6..887bb359ed3db 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -151,7 +151,7 @@ impl Pallet { fn change_authorities(new: WeakBoundedVec) { >::put(&new); - let log: DigestItem = DigestItem::Consensus( + let log = DigestItem::Consensus( AURA_ENGINE_ID, ConsensusLog::AuthoritiesChange(new.into_inner()).encode(), ); @@ -222,7 +222,7 @@ impl OneSessionHandler for Pallet { } fn on_disabled(i: u32) { - let log: DigestItem = DigestItem::Consensus( + let log = DigestItem::Consensus( AURA_ENGINE_ID, ConsensusLog::::OnDisabled(i as AuthorityIndex).encode(), ); diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 033d993f4e26d..569722ca38ced 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -633,7 +633,7 @@ impl Pallet { } fn deposit_consensus(new: U) { - let log: DigestItem = DigestItem::Consensus(BABE_ENGINE_ID, new.encode()); + let log = DigestItem::Consensus(BABE_ENGINE_ID, new.encode()); >::deposit_log(log.into()) } diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index 7c70766623b4d..f27bc450ad146 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -40,7 +40,7 @@ fn init_block(block: u64) { BeefyMmr::on_initialize(block); } -pub fn beefy_log(log: ConsensusLog) -> DigestItem { +pub fn beefy_log(log: ConsensusLog) -> DigestItem { DigestItem::Consensus(BEEFY_ENGINE_ID, log.encode()) } diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 3b28d454849cf..6a7118c1f5c96 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -110,7 +110,7 @@ impl Pallet { let next_id = Self::validator_set_id() + 1u64; >::put(next_id); - let log: DigestItem = DigestItem::Consensus( + let log = DigestItem::Consensus( BEEFY_ENGINE_ID, ConsensusLog::AuthoritiesChange(ValidatorSet { validators: new, id: next_id }) .encode(), @@ -163,7 +163,7 @@ impl OneSessionHandler for Pallet { } fn on_disabled(i: u32) { - let log: DigestItem = DigestItem::Consensus( + let log = DigestItem::Consensus( BEEFY_ENGINE_ID, ConsensusLog::::OnDisabled(i as AuthorityIndex).encode(), ); diff --git a/frame/beefy/src/tests.rs b/frame/beefy/src/tests.rs index 24f9acaf76bfc..252c03efb54a9 100644 --- a/frame/beefy/src/tests.rs +++ b/frame/beefy/src/tests.rs @@ -20,7 +20,6 @@ use std::vec; use beefy_primitives::ValidatorSet; use codec::Encode; -use sp_core::H256; use sp_runtime::DigestItem; use frame_support::traits::OnInitialize; @@ -32,7 +31,7 @@ fn init_block(block: u64) { Session::on_initialize(block); } -pub fn beefy_log(log: ConsensusLog) -> DigestItem { +pub fn beefy_log(log: ConsensusLog) -> DigestItem { DigestItem::Consensus(BEEFY_ENGINE_ID, log.encode()) } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index b1bdf357ec07d..e77c811a35e2d 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -125,7 +125,6 @@ use frame_support::{ }, weights::{DispatchClass, DispatchInfo, GetDispatchInfo}, }; -use frame_system::DigestOf; use sp_runtime::{ generic::Digest, traits::{ @@ -281,8 +280,8 @@ where Self::initialize_block_impl(header.number(), header.parent_hash(), &digests); } - fn extract_pre_digest(header: &System::Header) -> DigestOf { - let mut digest = >::default(); + fn extract_pre_digest(header: &System::Header) -> Digest { + let mut digest = ::default(); header.digest().logs().iter().for_each(|d| { if d.as_pre_runtime().is_some() { digest.push(d.clone()) @@ -294,7 +293,7 @@ where fn initialize_block_impl( block_number: &System::BlockNumber, parent_hash: &System::Hash, - digest: &Digest, + digest: &Digest, ) { let mut weight = 0; if Self::runtime_upgraded() { diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 9f6967a7d3c85..0e7d885649cc3 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -508,7 +508,7 @@ impl Pallet { /// Deposit one of this module's logs. fn deposit_log(log: ConsensusLog) { - let log: DigestItem = DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode()); + let log = DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode()); >::deposit_log(log.into()); } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index f1996553f02eb..49e4022a4aaed 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -254,7 +254,7 @@ impl Config for Test { type MaxAuthorities = MaxAuthorities; } -pub fn grandpa_log(log: ConsensusLog) -> DigestItem { +pub fn grandpa_log(log: ConsensusLog) -> DigestItem { DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode()) } diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 69445932b869e..81f98f2c23d48 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -1223,7 +1223,7 @@ mod private { pub trait Sealed {} impl Sealed for Vec {} - impl Sealed for Digest {} + impl Sealed for Digest {} impl Sealed for BoundedVec {} impl Sealed for WeakBoundedVec {} impl Sealed for bounded_btree_map::BoundedBTreeMap {} @@ -1263,7 +1263,7 @@ impl StorageDecodeLength for Vec {} /// We abuse the fact that SCALE does not put any marker into the encoding, i.e. we only encode the /// internal vec and we can append to this vec. We have a test that ensures that if the `Digest` /// format ever changes, we need to remove this here. -impl StorageAppend> for Digest {} +impl StorageAppend for Digest {} /// Marker trait that is implemented for types that support the `storage::append` api with a limit /// on the number of element. @@ -1484,8 +1484,8 @@ mod test { fn digest_storage_append_works_as_expected() { TestExternalities::default().execute_with(|| { struct Storage; - impl generator::StorageValue> for Storage { - type Query = Digest; + impl generator::StorageValue for Storage { + type Query = Digest; fn module_prefix() -> &'static [u8] { b"MyModule" @@ -1495,23 +1495,20 @@ mod test { b"Storage" } - fn from_optional_value_to_query(v: Option>) -> Self::Query { + fn from_optional_value_to_query(v: Option) -> Self::Query { v.unwrap() } - fn from_query_to_optional_value(v: Self::Query) -> Option> { + fn from_query_to_optional_value(v: Self::Query) -> Option { Some(v) } } - Storage::append(DigestItem::ChangesTrieRoot(1)); Storage::append(DigestItem::Other(Vec::new())); let value = unhashed::get_raw(&Storage::storage_value_final_key()).unwrap(); - let expected = Digest { - logs: vec![DigestItem::ChangesTrieRoot(1), DigestItem::Other(Vec::new())], - }; + let expected = Digest { logs: vec![DigestItem::Other(Vec::new())] }; assert_eq!(Digest::decode(&mut &value[..]).unwrap(), expected); }); } diff --git a/frame/system/benchmarking/src/lib.rs b/frame/system/benchmarking/src/lib.rs index e7371b1099e5e..eddf78ce6b254 100644 --- a/frame/system/benchmarking/src/lib.rs +++ b/frame/system/benchmarking/src/lib.rs @@ -22,8 +22,8 @@ use codec::Encode; use frame_benchmarking::{benchmarks, whitelisted_caller}; use frame_support::{storage, traits::Get, weights::DispatchClass}; -use frame_system::{Call, DigestItemOf, Pallet as System, RawOrigin}; -use sp_core::{storage::well_known_keys, ChangesTrieConfiguration}; +use frame_system::{Call, Pallet as System, RawOrigin}; +use sp_core::storage::well_known_keys; use sp_runtime::traits::Hash; use sp_std::{prelude::*, vec}; @@ -62,23 +62,6 @@ benchmarks! { assert_eq!(current_code.len(), 4_000_000 as usize); } - set_changes_trie_config { - let d = 1000; - - let digest_item = DigestItemOf::::Other(vec![]); - - for i in 0 .. d { - System::::deposit_log(digest_item.clone()); - } - let changes_trie_config = ChangesTrieConfiguration { - digest_interval: d, - digest_levels: d, - }; - }: _(RawOrigin::Root, Some(changes_trie_config)) - verify { - assert_eq!(System::::digest().logs.len(), (d + 1) as usize) - } - #[skip_meta] set_storage { let i in 1 .. 1000; diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 41e1738c034f1..d5b930fa165e6 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -95,7 +95,7 @@ use frame_support::{ Parameter, }; use scale_info::TypeInfo; -use sp_core::{storage::well_known_keys, ChangesTrieConfiguration}; +use sp_core::storage::well_known_keys; #[cfg(feature = "std")] use frame_support::traits::GenesisBuild; @@ -405,37 +405,6 @@ pub mod pallet { Ok(().into()) } - /// Set the new changes trie configuration. - /// - /// # - /// - `O(1)` - /// - 1 storage write or delete (codec `O(1)`). - /// - 1 call to `deposit_log`: Uses `append` API, so O(1) - /// - Base Weight: 7.218 µs - /// - DB Weight: - /// - Writes: Changes Trie, System Digest - /// # - #[pallet::weight((T::SystemWeightInfo::set_changes_trie_config(), DispatchClass::Operational))] - pub fn set_changes_trie_config( - origin: OriginFor, - changes_trie_config: Option, - ) -> DispatchResultWithPostInfo { - ensure_root(origin)?; - match changes_trie_config.clone() { - Some(changes_trie_config) => storage::unhashed::put_raw( - well_known_keys::CHANGES_TRIE_CONFIG, - &changes_trie_config.encode(), - ), - None => storage::unhashed::kill(well_known_keys::CHANGES_TRIE_CONFIG), - } - - let log = generic::DigestItem::ChangesTrieSignal( - generic::ChangesTrieSignal::NewConfiguration(changes_trie_config), - ); - Self::deposit_log(log.into()); - Ok(().into()) - } - /// Set some items of storage. /// /// # @@ -617,7 +586,7 @@ pub mod pallet { /// Digest of the current block, also part of the block header. #[pallet::storage] #[pallet::getter(fn digest)] - pub(super) type Digest = StorageValue<_, DigestOf, ValueQuery>; + pub(super) type Digest = StorageValue<_, generic::Digest, ValueQuery>; /// Events deposited for the current block. /// @@ -666,7 +635,6 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { - pub changes_trie_config: Option, #[serde(with = "sp_core::bytes")] pub code: Vec, } @@ -674,7 +642,7 @@ pub mod pallet { #[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { - Self { changes_trie_config: Default::default(), code: Default::default() } + Self { code: Default::default() } } } @@ -689,12 +657,6 @@ pub mod pallet { sp_io::storage::set(well_known_keys::CODE, &self.code); sp_io::storage::set(well_known_keys::EXTRINSIC_INDEX, &0u32.encode()); - if let Some(ref changes_trie_config) = self.changes_trie_config { - sp_io::storage::set( - well_known_keys::CHANGES_TRIE_CONFIG, - &changes_trie_config.encode(), - ); - } } } } @@ -759,9 +721,6 @@ impl GenesisConfig { } } -pub type DigestOf = generic::Digest<::Hash>; -pub type DigestItemOf = generic::DigestItem<::Hash>; - pub type Key = Vec; pub type KeyValue = (Vec, Vec); @@ -1369,7 +1328,7 @@ impl Pallet { pub fn initialize( number: &T::BlockNumber, parent_hash: &T::Hash, - digest: &DigestOf, + digest: &generic::Digest, kind: InitKind, ) { // populate environment @@ -1409,7 +1368,7 @@ impl Pallet { // stay to be inspected by the client and will be cleared by `Self::initialize`. let number = >::get(); let parent_hash = >::get(); - let mut digest = >::get(); + let digest = >::get(); let extrinsics = (0..ExtrinsicCount::::take().unwrap_or_default()) .map(ExtrinsicData::::take) @@ -1427,17 +1386,6 @@ impl Pallet { let storage_root = T::Hash::decode(&mut &sp_io::storage::root()[..]) .expect("Node is configured to use the same hash; qed"); - let storage_changes_root = sp_io::storage::changes_root(&parent_hash.encode()); - - // we can't compute changes trie root earlier && put it to the Digest - // because it will include all currently existing temporaries. - if let Some(storage_changes_root) = storage_changes_root { - let item = generic::DigestItem::ChangesTrieRoot( - T::Hash::decode(&mut &storage_changes_root[..]) - .expect("Node is configured to use the same hash; qed"), - ); - digest.push(item); - } ::new( number, @@ -1454,7 +1402,7 @@ impl Pallet { /// - `O(1)` /// - 1 storage write (codec `O(1)`) /// # - pub fn deposit_log(item: DigestItemOf) { + pub fn deposit_log(item: generic::DigestItem) { >::append(item); } diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index bc0f027e1efaa..dd2a7f6c14909 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -288,10 +288,6 @@ fn generate_runtime_api_base_structures() -> Result { fn into_storage_changes( &self, backend: &Self::StateBackend, - changes_trie_state: Option<&#crate_::ChangesTrieState< - #crate_::HashFor, - #crate_::NumberFor, - >>, parent_hash: Block::Hash, ) -> std::result::Result< #crate_::StorageChanges, @@ -299,7 +295,6 @@ fn generate_runtime_api_base_structures() -> Result { > where Self: Sized { self.changes.replace(Default::default()).into_storage_changes( backend, - changes_trie_state, parent_hash, self.storage_transaction_cache.replace(Default::default()), ) diff --git a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs index 77f8a07f85c48..9483d018c4a40 100644 --- a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs @@ -116,10 +116,6 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result, - #crate_::NumberFor<#block_type>, - >>, _: <#block_type as #crate_::BlockT>::Hash, ) -> std::result::Result< #crate_::StorageChanges, diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index cb74f95d21b09..7f64e191941f7 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -97,7 +97,7 @@ pub use sp_runtime::{ #[doc(hidden)] #[cfg(feature = "std")] pub use sp_state_machine::{ - Backend as StateBackend, ChangesTrieState, InMemoryBackend, OverlayedChanges, StorageProof, + Backend as StateBackend, InMemoryBackend, OverlayedChanges, StorageProof, }; #[cfg(feature = "std")] use sp_std::result; @@ -394,14 +394,12 @@ pub type ProofRecorder = sp_state_machine::ProofRecorder<::Hash> pub type StorageTransactionCache = sp_state_machine::StorageTransactionCache< >>::Transaction, HashFor, - NumberFor, >; #[cfg(feature = "std")] pub type StorageChanges = sp_state_machine::StorageChanges< >>::Transaction, HashFor, - NumberFor, >; /// Extract the state backend type for a type that implements `ProvideRuntimeApi`. @@ -514,7 +512,6 @@ pub trait ApiExt { fn into_storage_changes( &self, backend: &Self::StateBackend, - changes_trie_state: Option<&ChangesTrieState, NumberFor>>, parent_hash: Block::Hash, ) -> Result, String> where diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 101f92fd6c7d7..e32290b12a599 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -211,7 +211,7 @@ fn record_proof_works() { None, 8, ); - execution_proof_check_on_trie_backend::<_, u64, _, _>( + execution_proof_check_on_trie_backend( &backend, &mut overlay, &executor, diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index fc70ce845dc98..71c3f36a161b6 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -17,8 +17,6 @@ //! Substrate blockchain trait -use std::sync::Arc; - use log::warn; use parking_lot::RwLock; use sp_runtime::{ @@ -96,8 +94,6 @@ pub trait Backend: fn justifications(&self, id: BlockId) -> Result>; /// Get last finalized block hash. fn last_finalized(&self) -> Result; - /// Returns data cache reference, if it is enabled on this backend. - fn cache(&self) -> Option>>; /// Returns hashes of all blocks that are leaves of the block tree. /// in other words, that have no children, are chain heads. @@ -237,33 +233,6 @@ pub trait Backend: fn block_indexed_body(&self, id: BlockId) -> Result>>>; } -/// Provides access to the optional cache. -pub trait ProvideCache { - /// Returns data cache reference, if it is enabled on this backend. - fn cache(&self) -> Option>>; -} - -/// Blockchain optional data cache. -pub trait Cache: Send + Sync { - /// Initialize genesis value for the given cache. - /// - /// The operation should be performed once before anything else is inserted in the cache. - /// Otherwise cache may end up in inconsistent state. - fn initialize(&self, key: &well_known_cache_keys::Id, value_at_genesis: Vec) -> Result<()>; - /// Returns cached value by the given key. - /// - /// Returned tuple is the range where value has been active and the value itself. - /// Fails if read from cache storage fails or if the value for block is discarded - /// (i.e. if block is earlier that best finalized, but it is not in canonical chain). - fn get_at( - &self, - key: &well_known_cache_keys::Id, - block: &BlockId, - ) -> Result< - Option<((NumberFor, Block::Hash), Option<(NumberFor, Block::Hash)>, Vec)>, - >; -} - /// Blockchain info #[derive(Debug, Eq, PartialEq)] pub struct Info { diff --git a/primitives/consensus/aura/src/digests.rs b/primitives/consensus/aura/src/digests.rs index eaa29036d98a1..6925862d0ce94 100644 --- a/primitives/consensus/aura/src/digests.rs +++ b/primitives/consensus/aura/src/digests.rs @@ -25,7 +25,6 @@ use crate::AURA_ENGINE_ID; use codec::{Codec, Encode}; use sp_consensus_slots::Slot; use sp_runtime::generic::DigestItem; -use sp_std::fmt::Debug; /// A digest item which is usable with aura consensus. pub trait CompatibleDigestItem: Sized { @@ -42,10 +41,9 @@ pub trait CompatibleDigestItem: Sized { fn as_aura_pre_digest(&self) -> Option; } -impl CompatibleDigestItem for DigestItem +impl CompatibleDigestItem for DigestItem where Signature: Codec, - Hash: Debug + Send + Sync + Eq + Clone + Codec + 'static, { fn aura_seal(signature: Signature) -> Self { DigestItem::Seal(AURA_ENGINE_ID, signature.encode()) diff --git a/primitives/consensus/babe/src/digests.rs b/primitives/consensus/babe/src/digests.rs index 1c908fe61fc0b..4847adec37f18 100644 --- a/primitives/consensus/babe/src/digests.rs +++ b/primitives/consensus/babe/src/digests.rs @@ -21,7 +21,7 @@ use super::{ AllowedSlots, AuthorityId, AuthorityIndex, AuthoritySignature, BabeAuthorityWeight, BabeEpochConfiguration, Slot, BABE_ENGINE_ID, }; -use codec::{Codec, Decode, Encode, MaxEncodedLen}; +use codec::{Decode, Encode, MaxEncodedLen}; use sp_runtime::{DigestItem, RuntimeDebug}; use sp_std::vec::Vec; @@ -177,10 +177,7 @@ pub trait CompatibleDigestItem: Sized { fn as_next_config_descriptor(&self) -> Option; } -impl CompatibleDigestItem for DigestItem -where - Hash: Send + Sync + Eq + Clone + Codec + 'static, -{ +impl CompatibleDigestItem for DigestItem { fn babe_pre_digest(digest: PreDigest) -> Self { DigestItem::PreRuntime(BABE_ENGINE_ID, digest.encode()) } diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index d7979baf47c11..ce834fd0a47f4 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -26,7 +26,8 @@ use std::{sync::Arc, time::Duration}; use futures::prelude::*; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, DigestFor, HashFor, NumberFor}, + traits::{Block as BlockT, HashFor}, + Digest, }; use sp_state_machine::StorageProof; @@ -111,8 +112,7 @@ pub struct Proposal { /// Proof that was recorded while building the block. pub proof: Proof, /// The storage changes while building this block. - pub storage_changes: - sp_state_machine::StorageChanges, NumberFor>, + pub storage_changes: sp_state_machine::StorageChanges>, } /// Error that is returned when [`ProofRecording`] requested to record a proof, @@ -224,7 +224,7 @@ pub trait Proposer { fn propose( self, inherent_data: InherentData, - inherent_digests: DigestFor, + inherent_digests: Digest, max_duration: Duration, block_size_limit: Option, ) -> Self::Proposal; diff --git a/primitives/core/src/changes_trie.rs b/primitives/core/src/changes_trie.rs deleted file mode 100644 index f4ce83dc2c877..0000000000000 --- a/primitives/core/src/changes_trie.rs +++ /dev/null @@ -1,321 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Substrate changes trie configuration. - -use codec::{Decode, Encode}; -use num_traits::Zero; -#[cfg(any(feature = "std", test))] -use serde::{Deserialize, Serialize}; - -/// Substrate changes trie configuration. -#[cfg_attr( - any(feature = "std", test), - derive(Serialize, Deserialize, parity_util_mem::MallocSizeOf) -)] -#[derive(Debug, Clone, PartialEq, Eq, Default, Encode, Decode, scale_info::TypeInfo)] -pub struct ChangesTrieConfiguration { - /// Interval (in blocks) at which level1-digests are created. Digests are not - /// created when this is less or equal to 1. - pub digest_interval: u32, - /// Maximal number of digest levels in hierarchy. 0 means that digests are not - /// created at all (even level1 digests). 1 means only level1-digests are created. - /// 2 means that every digest_interval^2 there will be a level2-digest, and so on. - /// Please ensure that maximum digest interval (i.e. digest_interval^digest_levels) - /// is within `u32` limits. Otherwise you'll never see digests covering such intervals - /// && maximal digests interval will be truncated to the last interval that fits - /// `u32` limits. - pub digest_levels: u32, -} - -/// Substrate changes trie configuration range. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ChangesTrieConfigurationRange { - /// Zero block of configuration. - pub zero: (Number, Hash), - /// Last block of configuration (if configuration has been deactivated at some point). - pub end: Option<(Number, Hash)>, - /// The configuration itself. None if changes tries were disabled in this range. - pub config: Option, -} - -impl ChangesTrieConfiguration { - /// Create new configuration given digest interval and levels. - pub fn new(digest_interval: u32, digest_levels: u32) -> Self { - Self { digest_interval, digest_levels } - } - - /// Is digest build enabled? - pub fn is_digest_build_enabled(&self) -> bool { - self.digest_interval > 1 && self.digest_levels > 0 - } - - /// Do we need to build digest at given block? - pub fn is_digest_build_required_at_block(&self, zero: Number, block: Number) -> bool - where - Number: From - + PartialEq - + ::sp_std::ops::Rem - + ::sp_std::ops::Sub - + ::sp_std::cmp::PartialOrd - + Zero, - { - block > zero && - self.is_digest_build_enabled() && - ((block - zero) % self.digest_interval.into()).is_zero() - } - - /// Returns max digest interval. One if digests are not created at all. - pub fn max_digest_interval(&self) -> u32 { - if !self.is_digest_build_enabled() { - return 1 - } - - // we'll get >1 loop iteration only when bad configuration parameters are selected - let mut current_level = self.digest_levels; - loop { - if let Some(max_digest_interval) = self.digest_interval.checked_pow(current_level) { - return max_digest_interval - } - - current_level -= 1; - } - } - - /// Returns max level digest block number that has been created at block <= passed block number. - /// - /// Returns None if digests are not created at all. - pub fn prev_max_level_digest_block(&self, zero: Number, block: Number) -> Option - where - Number: Clone - + From - + PartialOrd - + PartialEq - + ::sp_std::ops::Add - + ::sp_std::ops::Sub - + ::sp_std::ops::Div - + ::sp_std::ops::Mul - + Zero, - { - if block <= zero { - return None - } - - let (next_begin, next_end) = - self.next_max_level_digest_range(zero.clone(), block.clone())?; - - // if 'next' digest includes our block, then it is a also a previous digest - if next_end == block { - return Some(block) - } - - // if previous digest ends at zero block, then there are no previous digest - let prev_end = next_begin - 1.into(); - if prev_end == zero { - None - } else { - Some(prev_end) - } - } - - /// Returns max level digest blocks range (inclusive) which includes passed block. - /// - /// Returns None if digests are not created at all. - /// It will return the first max-level digest if block is <= zero. - pub fn next_max_level_digest_range( - &self, - zero: Number, - mut block: Number, - ) -> Option<(Number, Number)> - where - Number: Clone - + From - + PartialOrd - + PartialEq - + ::sp_std::ops::Add - + ::sp_std::ops::Sub - + ::sp_std::ops::Div - + ::sp_std::ops::Mul, - { - if !self.is_digest_build_enabled() { - return None - } - - if block <= zero { - block = zero.clone() + 1.into(); - } - - let max_digest_interval: Number = self.max_digest_interval().into(); - let max_digests_since_zero = (block.clone() - zero.clone()) / max_digest_interval.clone(); - if max_digests_since_zero == 0.into() { - return Some((zero.clone() + 1.into(), zero + max_digest_interval)) - } - let last_max_digest_block = zero + max_digests_since_zero * max_digest_interval.clone(); - Some(if block == last_max_digest_block { - (block.clone() - max_digest_interval + 1.into(), block) - } else { - (last_max_digest_block.clone() + 1.into(), last_max_digest_block + max_digest_interval) - }) - } - - /// Returns Some if digest must be built at given block number. - /// The tuple is: - /// ( - /// digest level - /// digest interval (in blocks) - /// step between blocks we're interested in when digest is built - /// ) - pub fn digest_level_at_block( - &self, - zero: Number, - block: Number, - ) -> Option<(u32, u32, u32)> - where - Number: Clone - + From - + PartialEq - + ::sp_std::ops::Rem - + ::sp_std::ops::Sub - + ::sp_std::cmp::PartialOrd - + Zero, - { - if !self.is_digest_build_required_at_block(zero.clone(), block.clone()) { - return None - } - - let relative_block = block - zero; - let mut digest_interval = self.digest_interval; - let mut current_level = 1u32; - let mut digest_step = 1u32; - while current_level < self.digest_levels { - let new_digest_interval = match digest_interval.checked_mul(self.digest_interval) { - Some(new_digest_interval) - if (relative_block.clone() % new_digest_interval.into()).is_zero() => - new_digest_interval, - _ => break, - }; - - digest_step = digest_interval; - digest_interval = new_digest_interval; - current_level += 1; - } - - Some((current_level, digest_interval, digest_step)) - } -} - -#[cfg(test)] -mod tests { - use super::ChangesTrieConfiguration; - - fn config(interval: u32, levels: u32) -> ChangesTrieConfiguration { - ChangesTrieConfiguration { digest_interval: interval, digest_levels: levels } - } - - #[test] - fn is_digest_build_enabled_works() { - assert!(!config(0, 100).is_digest_build_enabled()); - assert!(!config(1, 100).is_digest_build_enabled()); - assert!(config(2, 100).is_digest_build_enabled()); - assert!(!config(100, 0).is_digest_build_enabled()); - assert!(config(100, 1).is_digest_build_enabled()); - } - - #[test] - fn is_digest_build_required_at_block_works() { - fn test_with_zero(zero: u64) { - assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero)); - assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 1u64)); - assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 2u64)); - assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 4u64)); - assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 8u64)); - assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 9u64)); - assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 64u64)); - assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 64u64)); - assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 512u64)); - assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 4096u64)); - assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 4103u64)); - assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 4104u64)); - assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 4108u64)); - } - - test_with_zero(0); - test_with_zero(8); - test_with_zero(17); - } - - #[test] - fn digest_level_at_block_works() { - fn test_with_zero(zero: u64) { - assert_eq!(config(8, 4).digest_level_at_block(zero, zero), None); - assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 7u64), None); - assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 63u64), None); - assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 8u64), Some((1, 8, 1))); - assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 64u64), Some((2, 64, 8))); - assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 512u64), Some((3, 512, 64))); - assert_eq!( - config(8, 4).digest_level_at_block(zero, zero + 4096u64), - Some((4, 4096, 512)) - ); - assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 4112u64), Some((1, 8, 1))); - } - - test_with_zero(0); - test_with_zero(8); - test_with_zero(17); - } - - #[test] - fn max_digest_interval_works() { - assert_eq!(config(0, 0).max_digest_interval(), 1); - assert_eq!(config(2, 2).max_digest_interval(), 4); - assert_eq!(config(8, 4).max_digest_interval(), 4096); - assert_eq!(config(::std::u32::MAX, 1024).max_digest_interval(), ::std::u32::MAX); - } - - #[test] - fn next_max_level_digest_range_works() { - assert_eq!(config(0, 0).next_max_level_digest_range(0u64, 16), None); - assert_eq!(config(1, 1).next_max_level_digest_range(0u64, 16), None); - assert_eq!(config(2, 1).next_max_level_digest_range(0u64, 16), Some((15, 16))); - assert_eq!(config(4, 1).next_max_level_digest_range(0u64, 16), Some((13, 16))); - assert_eq!(config(32, 1).next_max_level_digest_range(0u64, 16), Some((1, 32))); - assert_eq!(config(2, 3).next_max_level_digest_range(0u64, 10), Some((9, 16))); - assert_eq!(config(2, 3).next_max_level_digest_range(0u64, 8), Some((1, 8))); - assert_eq!(config(2, 1).next_max_level_digest_range(1u64, 1), Some((2, 3))); - assert_eq!(config(2, 2).next_max_level_digest_range(7u64, 9), Some((8, 11))); - - assert_eq!(config(2, 2).next_max_level_digest_range(7u64, 5), Some((8, 11))); - } - - #[test] - fn prev_max_level_digest_block_works() { - assert_eq!(config(0, 0).prev_max_level_digest_block(0u64, 16), None); - assert_eq!(config(1, 1).prev_max_level_digest_block(0u64, 16), None); - assert_eq!(config(2, 1).prev_max_level_digest_block(0u64, 16), Some(16)); - assert_eq!(config(4, 1).prev_max_level_digest_block(0u64, 16), Some(16)); - assert_eq!(config(4, 2).prev_max_level_digest_block(0u64, 16), Some(16)); - assert_eq!(config(4, 2).prev_max_level_digest_block(0u64, 17), Some(16)); - assert_eq!(config(4, 2).prev_max_level_digest_block(0u64, 33), Some(32)); - assert_eq!(config(32, 1).prev_max_level_digest_block(0u64, 16), None); - assert_eq!(config(2, 3).prev_max_level_digest_block(0u64, 10), Some(8)); - assert_eq!(config(2, 3).prev_max_level_digest_block(0u64, 8), Some(8)); - assert_eq!(config(2, 2).prev_max_level_digest_block(7u64, 8), None); - - assert_eq!(config(2, 2).prev_max_level_digest_block(7u64, 5), None); - } -} diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index fd752397cd9a9..3983f7cc155d9 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -58,7 +58,6 @@ pub mod hexdisplay; pub mod u32_trait; -mod changes_trie; pub mod ecdsa; pub mod ed25519; pub mod hash; @@ -76,7 +75,6 @@ pub use self::{ hash::{convert_hash, H160, H256, H512}, uint::{U256, U512}, }; -pub use changes_trie::{ChangesTrieConfiguration, ChangesTrieConfigurationRange}; #[cfg(feature = "full_crypto")] pub use crypto::{DeriveJunction, Pair, Public}; diff --git a/primitives/externalities/src/lib.rs b/primitives/externalities/src/lib.rs index e6a8f8caa8d33..aac45234deadd 100644 --- a/primitives/externalities/src/lib.rs +++ b/primitives/externalities/src/lib.rs @@ -173,13 +173,6 @@ pub trait Externalities: ExtensionStore { /// operation. fn storage_append(&mut self, key: Vec, value: Vec); - /// Get the changes trie root of the current storage overlay at a block with given `parent`. - /// - /// `parent` expects a SCALE encoded hash. - /// - /// The returned hash is defined by the `Block` and is SCALE encoded. - fn storage_changes_root(&mut self, parent: &[u8]) -> Result>, ()>; - /// Start a new nested transaction. /// /// This allows to either commit or roll back all changes made after this call to the diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 78e6f0c847952..e4f52fd4e0e21 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -195,16 +195,9 @@ pub trait Storage { self.storage_root() } - /// "Commit" all existing operations and get the resulting storage change root. - /// `parent_hash` is a SCALE encoded hash. - /// - /// The hashing algorithm is defined by the `Block`. - /// - /// Returns `Some(Vec)` which holds the SCALE encoded hash or `None` when - /// changes trie is disabled. - fn changes_root(&mut self, parent_hash: &[u8]) -> Option> { - self.storage_changes_root(parent_hash) - .expect("Invalid `parent_hash` given to `changes_root`.") + /// Always returns `None`. This function exists for compatibility reasons. + fn changes_root(&mut self, _parent_hash: &[u8]) -> Option> { + None } /// Get the next key in storage after the given one in lexicographic order. @@ -1497,7 +1490,7 @@ pub fn oom(_: core::alloc::Layout) -> ! { /// Type alias for Externalities implementation used in tests. #[cfg(feature = "std")] -pub type TestExternalities = sp_state_machine::TestExternalities; +pub type TestExternalities = sp_state_machine::TestExternalities; /// The host functions Substrate provides for the Wasm runtime environment. /// diff --git a/primitives/runtime-interface/test/src/lib.rs b/primitives/runtime-interface/test/src/lib.rs index 82c50fffeb8d7..1749cc4853672 100644 --- a/primitives/runtime-interface/test/src/lib.rs +++ b/primitives/runtime-interface/test/src/lib.rs @@ -31,7 +31,7 @@ use std::{ sync::{Arc, Mutex}, }; -type TestExternalities = sp_state_machine::TestExternalities; +type TestExternalities = sp_state_machine::TestExternalities; fn call_wasm_method_with_result( binary: &[u8], diff --git a/primitives/runtime/src/generic/digest.rs b/primitives/runtime/src/generic/digest.rs index 87af9bc77a5fa..978653efb93d8 100644 --- a/primitives/runtime/src/generic/digest.rs +++ b/primitives/runtime/src/generic/digest.rs @@ -26,59 +26,49 @@ use crate::{ codec::{Decode, Encode, Error, Input}, scale_info::{ build::{Fields, Variants}, - meta_type, Path, Type, TypeInfo, TypeParameter, + Path, Type, TypeInfo, }, ConsensusEngineId, }; -use sp_core::{ChangesTrieConfiguration, RuntimeDebug}; +use sp_core::RuntimeDebug; /// Generic header digest. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, parity_util_mem::MallocSizeOf))] -pub struct Digest { +pub struct Digest { /// A list of logs in the digest. - #[cfg_attr( - feature = "std", - serde(bound(serialize = "Hash: codec::Codec", deserialize = "Hash: codec::Codec")) - )] - pub logs: Vec>, + pub logs: Vec, } -impl Default for Digest { +impl Default for Digest { fn default() -> Self { Self { logs: Vec::new() } } } -impl Digest { +impl Digest { /// Get reference to all digest items. - pub fn logs(&self) -> &[DigestItem] { + pub fn logs(&self) -> &[DigestItem] { &self.logs } /// Push new digest item. - pub fn push(&mut self, item: DigestItem) { + pub fn push(&mut self, item: DigestItem) { self.logs.push(item); } /// Pop a digest item. - pub fn pop(&mut self) -> Option> { + pub fn pop(&mut self) -> Option { self.logs.pop() } /// Get reference to the first digest item that matches the passed predicate. - pub fn log) -> Option<&T>>( - &self, - predicate: F, - ) -> Option<&T> { + pub fn log Option<&T>>(&self, predicate: F) -> Option<&T> { self.logs().iter().find_map(predicate) } /// Get a conversion of the first digest item that successfully converts using the function. - pub fn convert_first) -> Option>( - &self, - predicate: F, - ) -> Option { + pub fn convert_first Option>(&self, predicate: F) -> Option { self.logs().iter().find_map(predicate) } } @@ -87,12 +77,7 @@ impl Digest { /// provide opaque access to other items. #[derive(PartialEq, Eq, Clone, RuntimeDebug)] #[cfg_attr(feature = "std", derive(parity_util_mem::MallocSizeOf))] -pub enum DigestItem { - /// System digest item that contains the root of changes trie at given - /// block. It is created for every block iff runtime supports changes - /// trie creation. - ChangesTrieRoot(Hash), - +pub enum DigestItem { /// A pre-runtime digest. /// /// These are messages from the consensus engine to the runtime, although @@ -116,10 +101,6 @@ pub enum DigestItem { /// by runtimes. Seal(ConsensusEngineId, Vec), - /// Digest item that contains signal from changes tries manager to the - /// native code. - ChangesTrieSignal(ChangesTrieSignal), - /// Some other thing. Unsupported and experimental. Other(Vec), @@ -132,25 +113,8 @@ pub enum DigestItem { RuntimeEnvironmentUpdated, } -/// Available changes trie signals. -#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] -#[cfg_attr(feature = "std", derive(Debug, parity_util_mem::MallocSizeOf))] -pub enum ChangesTrieSignal { - /// New changes trie configuration is enacted, starting from **next block**. - /// - /// The block that emits this signal will contain changes trie (CT) that covers - /// blocks range [BEGIN; current block], where BEGIN is (order matters): - /// - LAST_TOP_LEVEL_DIGEST_BLOCK+1 if top level digest CT has ever been created using current - /// configuration AND the last top level digest CT has been created at block - /// LAST_TOP_LEVEL_DIGEST_BLOCK; - /// - LAST_CONFIGURATION_CHANGE_BLOCK+1 if there has been CT configuration change before and - /// the last configuration change happened at block LAST_CONFIGURATION_CHANGE_BLOCK; - /// - 1 otherwise. - NewConfiguration(Option), -} - #[cfg(feature = "std")] -impl serde::Serialize for DigestItem { +impl serde::Serialize for DigestItem { fn serialize(&self, seq: S) -> Result where S: serde::Serializer, @@ -160,7 +124,7 @@ impl serde::Serialize for DigestItem { } #[cfg(feature = "std")] -impl<'a, Hash: Decode> serde::Deserialize<'a> for DigestItem { +impl<'a> serde::Deserialize<'a> for DigestItem { fn deserialize(de: D) -> Result where D: serde::Deserializer<'a>, @@ -171,75 +135,48 @@ impl<'a, Hash: Decode> serde::Deserialize<'a> for DigestItem { } } -impl TypeInfo for DigestItem -where - Hash: TypeInfo + 'static, -{ +impl TypeInfo for DigestItem { type Identity = Self; fn type_info() -> Type { - Type::builder() - .path(Path::new("DigestItem", module_path!())) - .type_params(vec![TypeParameter::new("Hash", Some(meta_type::()))]) - .variant( - Variants::new() - .variant("ChangesTrieRoot", |v| { - v.index(DigestItemType::ChangesTrieRoot as u8) - .fields(Fields::unnamed().field(|f| f.ty::().type_name("Hash"))) - }) - .variant("PreRuntime", |v| { - v.index(DigestItemType::PreRuntime as u8).fields( - Fields::unnamed() - .field(|f| { - f.ty::().type_name("ConsensusEngineId") - }) - .field(|f| f.ty::>().type_name("Vec")), - ) - }) - .variant("Consensus", |v| { - v.index(DigestItemType::Consensus as u8).fields( - Fields::unnamed() - .field(|f| { - f.ty::().type_name("ConsensusEngineId") - }) - .field(|f| f.ty::>().type_name("Vec")), - ) - }) - .variant("Seal", |v| { - v.index(DigestItemType::Seal as u8).fields( - Fields::unnamed() - .field(|f| { - f.ty::().type_name("ConsensusEngineId") - }) - .field(|f| f.ty::>().type_name("Vec")), - ) - }) - .variant("ChangesTrieSignal", |v| { - v.index(DigestItemType::ChangesTrieSignal as u8).fields( - Fields::unnamed().field(|f| { - f.ty::().type_name("ChangesTrieSignal") - }), - ) - }) - .variant("Other", |v| { - v.index(DigestItemType::Other as u8).fields( - Fields::unnamed().field(|f| f.ty::>().type_name("Vec")), - ) - }) - .variant("RuntimeEnvironmentUpdated", |v| { - v.index(DigestItemType::RuntimeEnvironmentUpdated as u8) - .fields(Fields::unit()) - }), - ) + Type::builder().path(Path::new("DigestItem", module_path!())).variant( + Variants::new() + .variant("PreRuntime", |v| { + v.index(DigestItemType::PreRuntime as u8).fields( + Fields::unnamed() + .field(|f| f.ty::().type_name("ConsensusEngineId")) + .field(|f| f.ty::>().type_name("Vec")), + ) + }) + .variant("Consensus", |v| { + v.index(DigestItemType::Consensus as u8).fields( + Fields::unnamed() + .field(|f| f.ty::().type_name("ConsensusEngineId")) + .field(|f| f.ty::>().type_name("Vec")), + ) + }) + .variant("Seal", |v| { + v.index(DigestItemType::Seal as u8).fields( + Fields::unnamed() + .field(|f| f.ty::().type_name("ConsensusEngineId")) + .field(|f| f.ty::>().type_name("Vec")), + ) + }) + .variant("Other", |v| { + v.index(DigestItemType::Other as u8) + .fields(Fields::unnamed().field(|f| f.ty::>().type_name("Vec"))) + }) + .variant("RuntimeEnvironmentUpdated", |v| { + v.index(DigestItemType::RuntimeEnvironmentUpdated as u8).fields(Fields::unit()) + }), + ) } } /// A 'referencing view' for digest item. Does not own its contents. Used by /// final runtime implementations for encoding/decoding its log items. #[derive(PartialEq, Eq, Clone, RuntimeDebug)] -pub enum DigestItemRef<'a, Hash: 'a> { - /// Reference to `DigestItem::ChangesTrieRoot`. - ChangesTrieRoot(&'a Hash), +pub enum DigestItemRef<'a> { /// A pre-runtime digest. /// /// These are messages from the consensus engine to the runtime, although @@ -254,9 +191,6 @@ pub enum DigestItemRef<'a, Hash: 'a> { /// Put a Seal on it. This is only used by native code, and is never seen /// by runtimes. Seal(&'a ConsensusEngineId, &'a Vec), - /// Digest item that contains signal from changes tries manager to the - /// native code. - ChangesTrieSignal(&'a ChangesTrieSignal), /// Any 'non-system' digest item, opaque to the native code. Other(&'a Vec), /// Runtime code or heap pages updated. @@ -271,11 +205,9 @@ pub enum DigestItemRef<'a, Hash: 'a> { #[derive(Encode, Decode)] pub enum DigestItemType { Other = 0, - ChangesTrieRoot = 2, Consensus = 4, Seal = 5, PreRuntime = 6, - ChangesTrieSignal = 7, RuntimeEnvironmentUpdated = 8, } @@ -293,25 +225,18 @@ pub enum OpaqueDigestItemId<'a> { Other, } -impl DigestItem { +impl DigestItem { /// Returns a 'referencing view' for this digest item. - pub fn dref(&self) -> DigestItemRef { + pub fn dref(&self) -> DigestItemRef { match *self { - Self::ChangesTrieRoot(ref v) => DigestItemRef::ChangesTrieRoot(v), Self::PreRuntime(ref v, ref s) => DigestItemRef::PreRuntime(v, s), Self::Consensus(ref v, ref s) => DigestItemRef::Consensus(v, s), Self::Seal(ref v, ref s) => DigestItemRef::Seal(v, s), - Self::ChangesTrieSignal(ref s) => DigestItemRef::ChangesTrieSignal(s), Self::Other(ref v) => DigestItemRef::Other(v), Self::RuntimeEnvironmentUpdated => DigestItemRef::RuntimeEnvironmentUpdated, } } - /// Returns `Some` if the entry is the `ChangesTrieRoot` entry. - pub fn as_changes_trie_root(&self) -> Option<&Hash> { - self.dref().as_changes_trie_root() - } - /// Returns `Some` if this entry is the `PreRuntime` entry. pub fn as_pre_runtime(&self) -> Option<(ConsensusEngineId, &[u8])> { self.dref().as_pre_runtime() @@ -327,11 +252,6 @@ impl DigestItem { self.dref().as_seal() } - /// Returns `Some` if the entry is the `ChangesTrieSignal` entry. - pub fn as_changes_trie_signal(&self) -> Option<&ChangesTrieSignal> { - self.dref().as_changes_trie_signal() - } - /// Returns Some if `self` is a `DigestItem::Other`. pub fn as_other(&self) -> Option<&[u8]> { self.dref().as_other() @@ -372,20 +292,19 @@ impl DigestItem { } } -impl Encode for DigestItem { +impl Encode for DigestItem { fn encode(&self) -> Vec { self.dref().encode() } } -impl codec::EncodeLike for DigestItem {} +impl codec::EncodeLike for DigestItem {} -impl Decode for DigestItem { +impl Decode for DigestItem { #[allow(deprecated)] fn decode(input: &mut I) -> Result { let item_type: DigestItemType = Decode::decode(input)?; match item_type { - DigestItemType::ChangesTrieRoot => Ok(Self::ChangesTrieRoot(Decode::decode(input)?)), DigestItemType::PreRuntime => { let vals: (ConsensusEngineId, Vec) = Decode::decode(input)?; Ok(Self::PreRuntime(vals.0, vals.1)) @@ -398,23 +317,13 @@ impl Decode for DigestItem { let vals: (ConsensusEngineId, Vec) = Decode::decode(input)?; Ok(Self::Seal(vals.0, vals.1)) }, - DigestItemType::ChangesTrieSignal => - Ok(Self::ChangesTrieSignal(Decode::decode(input)?)), DigestItemType::Other => Ok(Self::Other(Decode::decode(input)?)), DigestItemType::RuntimeEnvironmentUpdated => Ok(Self::RuntimeEnvironmentUpdated), } } } -impl<'a, Hash> DigestItemRef<'a, Hash> { - /// Cast this digest item into `ChangesTrieRoot`. - pub fn as_changes_trie_root(&self) -> Option<&'a Hash> { - match *self { - Self::ChangesTrieRoot(ref changes_trie_root) => Some(changes_trie_root), - _ => None, - } - } - +impl<'a> DigestItemRef<'a> { /// Cast this digest item into `PreRuntime` pub fn as_pre_runtime(&self) -> Option<(ConsensusEngineId, &'a [u8])> { match *self { @@ -439,14 +348,6 @@ impl<'a, Hash> DigestItemRef<'a, Hash> { } } - /// Cast this digest item into `ChangesTrieSignal`. - pub fn as_changes_trie_signal(&self) -> Option<&'a ChangesTrieSignal> { - match *self { - Self::ChangesTrieSignal(ref changes_trie_signal) => Some(changes_trie_signal), - _ => None, - } - } - /// Cast this digest item into `PreRuntime` pub fn as_other(&self) -> Option<&'a [u8]> { match *self { @@ -508,15 +409,11 @@ impl<'a, Hash> DigestItemRef<'a, Hash> { } } -impl<'a, Hash: Encode> Encode for DigestItemRef<'a, Hash> { +impl<'a> Encode for DigestItemRef<'a> { fn encode(&self) -> Vec { let mut v = Vec::new(); match *self { - Self::ChangesTrieRoot(changes_trie_root) => { - DigestItemType::ChangesTrieRoot.encode_to(&mut v); - changes_trie_root.encode_to(&mut v); - }, Self::Consensus(val, data) => { DigestItemType::Consensus.encode_to(&mut v); (val, data).encode_to(&mut v); @@ -529,10 +426,6 @@ impl<'a, Hash: Encode> Encode for DigestItemRef<'a, Hash> { DigestItemType::PreRuntime.encode_to(&mut v); (val, data).encode_to(&mut v); }, - Self::ChangesTrieSignal(changes_trie_signal) => { - DigestItemType::ChangesTrieSignal.encode_to(&mut v); - changes_trie_signal.encode_to(&mut v); - }, Self::Other(val) => { DigestItemType::Other.encode_to(&mut v); val.encode_to(&mut v); @@ -546,16 +439,7 @@ impl<'a, Hash: Encode> Encode for DigestItemRef<'a, Hash> { } } -impl ChangesTrieSignal { - /// Try to cast this signal to NewConfiguration. - pub fn as_new_configuration(&self) -> Option<&Option> { - match self { - Self::NewConfiguration(config) => Some(config), - } - } -} - -impl<'a, Hash: Encode> codec::EncodeLike for DigestItemRef<'a, Hash> {} +impl<'a> codec::EncodeLike for DigestItemRef<'a> {} #[cfg(test)] mod tests { @@ -564,22 +448,18 @@ mod tests { #[test] fn should_serialize_digest() { let digest = Digest { - logs: vec![ - DigestItem::ChangesTrieRoot(4), - DigestItem::Other(vec![1, 2, 3]), - DigestItem::Seal(*b"test", vec![1, 2, 3]), - ], + logs: vec![DigestItem::Other(vec![1, 2, 3]), DigestItem::Seal(*b"test", vec![1, 2, 3])], }; assert_eq!( serde_json::to_string(&digest).unwrap(), - r#"{"logs":["0x0204000000","0x000c010203","0x05746573740c010203"]}"# + r#"{"logs":["0x000c010203","0x05746573740c010203"]}"# ); } #[test] fn digest_item_type_info() { - let type_info = DigestItem::::type_info(); + let type_info = DigestItem::type_info(); let variants = if let scale_info::TypeDef::Variant(variant) = type_info.type_def() { variant.variants() } else { @@ -589,21 +469,13 @@ mod tests { // ensure that all variants are covered by manual TypeInfo impl let check = |digest_item_type: DigestItemType| { let (variant_name, digest_item) = match digest_item_type { - DigestItemType::Other => ("Other", DigestItem::::Other(Default::default())), - DigestItemType::ChangesTrieRoot => - ("ChangesTrieRoot", DigestItem::ChangesTrieRoot(Default::default())), + DigestItemType::Other => ("Other", DigestItem::Other(Default::default())), DigestItemType::Consensus => ("Consensus", DigestItem::Consensus(Default::default(), Default::default())), DigestItemType::Seal => ("Seal", DigestItem::Seal(Default::default(), Default::default())), DigestItemType::PreRuntime => ("PreRuntime", DigestItem::PreRuntime(Default::default(), Default::default())), - DigestItemType::ChangesTrieSignal => ( - "ChangesTrieSignal", - DigestItem::ChangesTrieSignal(ChangesTrieSignal::NewConfiguration( - Default::default(), - )), - ), DigestItemType::RuntimeEnvironmentUpdated => ("RuntimeEnvironmentUpdated", DigestItem::RuntimeEnvironmentUpdated), }; @@ -617,11 +489,9 @@ mod tests { }; check(DigestItemType::Other); - check(DigestItemType::ChangesTrieRoot); check(DigestItemType::Consensus); check(DigestItemType::Seal); check(DigestItemType::PreRuntime); - check(DigestItemType::ChangesTrieSignal); check(DigestItemType::RuntimeEnvironmentUpdated); } } diff --git a/primitives/runtime/src/generic/header.rs b/primitives/runtime/src/generic/header.rs index 82f081c0d70b0..21c2a6eef73af 100644 --- a/primitives/runtime/src/generic/header.rs +++ b/primitives/runtime/src/generic/header.rs @@ -51,7 +51,7 @@ pub struct Header + TryFrom, Hash: HashT> { /// The merkle root of the extrinsics. pub extrinsics_root: Hash::Output, /// A chain-specific digest of data useful for light clients or referencing auxiliary data. - pub digest: Digest, + pub digest: Digest, } #[cfg(feature = "std")] @@ -150,11 +150,11 @@ where self.parent_hash = hash } - fn digest(&self) -> &Digest { + fn digest(&self) -> &Digest { &self.digest } - fn digest_mut(&mut self) -> &mut Digest { + fn digest_mut(&mut self) -> &mut Digest { #[cfg(feature = "std")] log::debug!(target: "header", "Retrieving mutable reference to digest"); &mut self.digest @@ -165,7 +165,7 @@ where extrinsics_root: Self::Hash, state_root: Self::Hash, parent_hash: Self::Hash, - digest: Digest, + digest: Digest, ) -> Self { Self { number, extrinsics_root, state_root, parent_hash, digest } } @@ -235,10 +235,7 @@ mod tests { state_root: BlakeTwo256::hash(b"3"), extrinsics_root: BlakeTwo256::hash(b"4"), digest: crate::generic::Digest { - logs: vec![ - crate::generic::DigestItem::ChangesTrieRoot(BlakeTwo256::hash(b"5")), - crate::generic::DigestItem::Other(b"6".to_vec()), - ], + logs: vec![crate::generic::DigestItem::Other(b"6".to_vec())], }, }; @@ -251,9 +248,7 @@ mod tests { 72, 51, 123, 15, 62, 20, 134, 32, 23, 61, 170, 165, 249, 77, 0, 216, 129, 112, 93, 203, 240, 170, 131, 239, 218, 186, 97, 210, 237, 225, 235, 134, 73, 33, 73, 151, 87, 78, 32, 196, 100, 56, 138, 23, 36, 32, 210, 84, 3, 104, 43, 187, 184, 12, 73, - 104, 49, 200, 204, 31, 143, 13, 8, 2, 112, 178, 1, 53, 47, 36, 191, 28, 151, 112, - 185, 159, 143, 113, 32, 24, 33, 65, 28, 244, 20, 55, 124, 155, 140, 45, 188, 238, - 97, 219, 135, 214, 0, 4, 54 + 104, 49, 200, 204, 31, 143, 13, 4, 0, 4, 54 ], ); assert_eq!(header, Header::::decode(&mut &header_encoded[..]).unwrap()); @@ -264,10 +259,7 @@ mod tests { state_root: BlakeTwo256::hash(b"3000"), extrinsics_root: BlakeTwo256::hash(b"4000"), digest: crate::generic::Digest { - logs: vec![ - crate::generic::DigestItem::Other(b"5000".to_vec()), - crate::generic::DigestItem::ChangesTrieRoot(BlakeTwo256::hash(b"6000")), - ], + logs: vec![crate::generic::DigestItem::Other(b"5000".to_vec())], }, }; @@ -280,9 +272,7 @@ mod tests { 47, 12, 107, 88, 153, 146, 55, 21, 226, 186, 110, 48, 167, 187, 67, 183, 228, 232, 118, 136, 30, 254, 11, 87, 48, 112, 7, 97, 31, 82, 146, 110, 96, 87, 152, 68, 98, 162, 227, 222, 78, 14, 244, 194, 120, 154, 112, 97, 222, 144, 174, 101, 220, 44, - 111, 126, 54, 34, 155, 220, 253, 124, 8, 0, 16, 53, 48, 48, 48, 2, 42, 105, 109, - 150, 206, 223, 24, 44, 164, 77, 27, 137, 177, 220, 25, 170, 140, 35, 156, 246, 233, - 112, 26, 23, 192, 61, 226, 14, 84, 219, 144, 252 + 111, 126, 54, 34, 155, 220, 253, 124, 4, 0, 16, 53, 48, 48, 48 ], ); assert_eq!(header, Header::::decode(&mut &header_encoded[..]).unwrap()); diff --git a/primitives/runtime/src/generic/mod.rs b/primitives/runtime/src/generic/mod.rs index 71127e88ec32c..3d8e8a0ce7faa 100644 --- a/primitives/runtime/src/generic/mod.rs +++ b/primitives/runtime/src/generic/mod.rs @@ -31,7 +31,7 @@ mod unchecked_extrinsic; pub use self::{ block::{Block, BlockId, SignedBlock}, checked_extrinsic::CheckedExtrinsic, - digest::{ChangesTrieSignal, Digest, DigestItem, DigestItemRef, OpaqueDigestItemId}, + digest::{Digest, DigestItem, DigestItemRef, OpaqueDigestItemId}, era::{Era, Phase}, header::Header, unchecked_extrinsic::{SignedPayload, UncheckedExtrinsic}, diff --git a/primitives/runtime/src/generic/tests.rs b/primitives/runtime/src/generic/tests.rs index 095bcb717bb11..a65e212bf07ec 100644 --- a/primitives/runtime/src/generic/tests.rs +++ b/primitives/runtime/src/generic/tests.rs @@ -19,29 +19,26 @@ use super::DigestItem; use crate::codec::{Decode, Encode}; -use sp_core::H256; #[test] fn system_digest_item_encoding() { - let item = DigestItem::ChangesTrieRoot::(H256::default()); + let item = DigestItem::Consensus([1, 2, 3, 4], vec![5, 6, 7, 8]); let encoded = item.encode(); assert_eq!( encoded, vec![ - // type = DigestItemType::ChangesTrieRoot - 2, // trie root - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, + 4, // type = DigestItemType::Consensus + 1, 2, 3, 4, 16, 5, 6, 7, 8, ] ); - let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); + let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); assert_eq!(item, decoded); } #[test] fn non_system_digest_item_encoding() { - let item = DigestItem::Other::(vec![10, 20, 30]); + let item = DigestItem::Other(vec![10, 20, 30]); let encoded = item.encode(); assert_eq!( encoded, @@ -53,6 +50,6 @@ fn non_system_digest_item_encoding() { ] ); - let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); + let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); assert_eq!(item, decoded); } diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index fe9ba588adb87..4573bc84473a3 100644 --- a/primitives/runtime/src/testing.rs +++ b/primitives/runtime/src/testing.rs @@ -182,10 +182,10 @@ impl traits::Verify for TestSignature { } /// Digest item -pub type DigestItem = generic::DigestItem; +pub type DigestItem = generic::DigestItem; /// Header Digest -pub type Digest = generic::Digest; +pub type Digest = generic::Digest; /// Block Header pub type Header = generic::Header; diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 6d79d740dc4e1..f61de70e35197 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -19,7 +19,7 @@ use crate::{ codec::{Codec, Decode, Encode, MaxEncodedLen}, - generic::{Digest, DigestItem}, + generic::Digest, scale_info::{MetaType, StaticTypeInfo, TypeInfo}, transaction_validity::{ TransactionSource, TransactionValidity, TransactionValidityError, UnknownTransaction, @@ -548,10 +548,7 @@ impl CheckEqual for sp_core::H256 { } } -impl CheckEqual for super::generic::DigestItem -where - H: Encode, -{ +impl CheckEqual for super::generic::DigestItem { #[cfg(feature = "std")] fn check_equal(&self, other: &Self) { if self != other { @@ -642,7 +639,7 @@ pub trait Header: extrinsics_root: Self::Hash, state_root: Self::Hash, parent_hash: Self::Hash, - digest: Digest, + digest: Digest, ) -> Self; /// Returns a reference to the header number. @@ -666,9 +663,9 @@ pub trait Header: fn set_parent_hash(&mut self, hash: Self::Hash); /// Returns a reference to the digest. - fn digest(&self) -> &Digest; + fn digest(&self) -> &Digest; /// Get a mutable reference to the digest. - fn digest_mut(&mut self) -> &mut Digest; + fn digest_mut(&mut self) -> &mut Digest; /// Returns the hash of the header. fn hash(&self) -> Self::Hash { @@ -763,9 +760,6 @@ pub type HashFor = <::Header as Header>::Hashing; /// Extract the number type for a block. pub type NumberFor = <::Header as Header>::Number; /// Extract the digest type for a block. -pub type DigestFor = Digest<<::Header as Header>::Hash>; -/// Extract the digest item type for a block. -pub type DigestItemFor = DigestItem<<::Header as Header>::Hash>; /// A "checkable" piece of information, used by the standard Substrate Executive in order to /// check the validity of a piece of extrinsic information, usually by verifying the signature. diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index 7dcf92b06de06..eb6e2939b83fc 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -292,32 +292,6 @@ impl> Consolidate for sp_trie::GenericMem } } -/// Insert input pairs into memory db. -#[cfg(test)] -pub(crate) fn insert_into_memory_db( - mdb: &mut sp_trie::MemoryDB, - input: I, -) -> Option -where - H: Hasher, - I: IntoIterator, -{ - use sp_trie::{trie_types::TrieDBMut, TrieMut}; - - let mut root = ::Out::default(); - { - let mut trie = TrieDBMut::::new(mdb, &mut root); - for (key, value) in input { - if let Err(e) = trie.insert(&key, &value) { - log::warn!(target: "trie", "Failed to write to trie: {}", e); - return None - } - } - } - - Some(root) -} - /// Wrapper to create a [`RuntimeCode`] from a type that implements [`Backend`]. #[cfg(feature = "std")] pub struct BackendRuntimeCode<'a, B, H> { diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index 0bbd2d0a8e8e6..3774adc5b0368 100644 --- a/primitives/state-machine/src/basic.rs +++ b/primitives/state-machine/src/basic.rs @@ -309,10 +309,6 @@ impl Externalities for BasicExternalities { .encode() } - fn storage_changes_root(&mut self, _parent: &[u8]) -> Result>, ()> { - Ok(None) - } - fn storage_start_transaction(&mut self) { unimplemented!("Transactions are not supported by BasicExternalities"); } diff --git a/primitives/state-machine/src/changes_trie/build.rs b/primitives/state-machine/src/changes_trie/build.rs deleted file mode 100644 index d3c6c12122c4f..0000000000000 --- a/primitives/state-machine/src/changes_trie/build.rs +++ /dev/null @@ -1,1083 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Structures and functions required to build changes trie for given block. - -use crate::{ - backend::Backend, - changes_trie::{ - build_iterator::digest_build_iterator, - input::{ChildIndex, DigestIndex, ExtrinsicIndex, InputKey, InputPair}, - AnchorBlockId, BlockNumber, ConfigurationRange, Storage, - }, - overlayed_changes::{OverlayedChanges, OverlayedValue}, - trie_backend_essence::TrieBackendEssence, - StorageKey, -}; -use codec::{Decode, Encode}; -use hash_db::Hasher; -use num_traits::One; -use sp_core::storage::{ChildInfo, PrefixedStorageKey}; -use std::collections::{btree_map::Entry, BTreeMap}; - -/// Prepare input pairs for building a changes trie of given block. -/// -/// Returns Err if storage error has occurred OR if storage haven't returned -/// required data. -pub(crate) fn prepare_input<'a, B, H, Number>( - backend: &'a B, - storage: &'a dyn Storage, - config: ConfigurationRange<'a, Number>, - overlay: &'a OverlayedChanges, - parent: &'a AnchorBlockId, -) -> Result< - ( - impl Iterator> + 'a, - Vec<(ChildIndex, impl Iterator> + 'a)>, - Vec, - ), - String, -> -where - B: Backend, - H: Hasher + 'a, - H::Out: Encode, - Number: BlockNumber, -{ - let number = parent.number.clone() + One::one(); - let (extrinsics_input, children_extrinsics_input) = - prepare_extrinsics_input(backend, &number, overlay)?; - let (digest_input, mut children_digest_input, digest_input_blocks) = - prepare_digest_input::(parent, config, number, storage)?; - - let mut children_digest = Vec::with_capacity(children_extrinsics_input.len()); - for (child_index, ext_iter) in children_extrinsics_input.into_iter() { - let dig_iter = children_digest_input.remove(&child_index); - children_digest.push(( - child_index, - Some(ext_iter).into_iter().flatten().chain(dig_iter.into_iter().flatten()), - )); - } - for (child_index, dig_iter) in children_digest_input.into_iter() { - children_digest.push(( - child_index, - None.into_iter().flatten().chain(Some(dig_iter).into_iter().flatten()), - )); - } - - Ok((extrinsics_input.chain(digest_input), children_digest, digest_input_blocks)) -} -/// Prepare ExtrinsicIndex input pairs. -fn prepare_extrinsics_input<'a, B, H, Number>( - backend: &'a B, - block: &Number, - overlay: &'a OverlayedChanges, -) -> Result< - ( - impl Iterator> + 'a, - BTreeMap, impl Iterator> + 'a>, - ), - String, -> -where - B: Backend, - H: Hasher + 'a, - Number: BlockNumber, -{ - let mut children_result = BTreeMap::new(); - - for (child_changes, child_info) in overlay.children() { - let child_index = ChildIndex:: { - block: block.clone(), - storage_key: child_info.prefixed_storage_key(), - }; - - let iter = prepare_extrinsics_input_inner( - backend, - block, - overlay, - Some(child_info.clone()), - child_changes, - )?; - children_result.insert(child_index, iter); - } - - let top = prepare_extrinsics_input_inner(backend, block, overlay, None, overlay.changes())?; - - Ok((top, children_result)) -} - -fn prepare_extrinsics_input_inner<'a, B, H, Number>( - backend: &'a B, - block: &Number, - overlay: &'a OverlayedChanges, - child_info: Option, - changes: impl Iterator, -) -> Result> + 'a, String> -where - B: Backend, - H: Hasher, - Number: BlockNumber, -{ - changes - .filter_map(|(k, v)| { - let extrinsics = v.extrinsics(); - if !extrinsics.is_empty() { - Some((k, extrinsics)) - } else { - None - } - }) - .try_fold( - BTreeMap::new(), - |mut map: BTreeMap<&[u8], (ExtrinsicIndex, Vec)>, (k, extrinsics)| { - match map.entry(k) { - Entry::Vacant(entry) => { - // ignore temporary values (values that have null value at the end of - // operation AND are not in storage at the beginning of operation - if let Some(child_info) = child_info.as_ref() { - if !overlay - .child_storage(child_info, k) - .map(|v| v.is_some()) - .unwrap_or_default() - { - if !backend - .exists_child_storage(&child_info, k) - .map_err(|e| format!("{}", e))? - { - return Ok(map) - } - } - } else { - if !overlay.storage(k).map(|v| v.is_some()).unwrap_or_default() { - if !backend.exists_storage(k).map_err(|e| format!("{}", e))? { - return Ok(map) - } - } - }; - - let extrinsics = extrinsics.into_iter().collect(); - entry.insert(( - ExtrinsicIndex { block: block.clone(), key: k.to_vec() }, - extrinsics, - )); - }, - Entry::Occupied(mut entry) => { - // we do not need to check for temporary values here, because entry is - // Occupied AND we are checking it before insertion - let entry_extrinsics = &mut entry.get_mut().1; - entry_extrinsics.extend(extrinsics.into_iter()); - entry_extrinsics.sort(); - }, - } - - Ok(map) - }, - ) - .map(|pairs| pairs.into_iter().map(|(_, (k, v))| InputPair::ExtrinsicIndex(k, v))) -} - -/// Prepare DigestIndex input pairs. -fn prepare_digest_input<'a, H, Number>( - parent: &'a AnchorBlockId, - config: ConfigurationRange, - block: Number, - storage: &'a dyn Storage, -) -> Result< - ( - impl Iterator> + 'a, - BTreeMap, impl Iterator> + 'a>, - Vec, - ), - String, -> -where - H: Hasher, - H::Out: 'a + Encode, - Number: BlockNumber, -{ - let build_skewed_digest = config.end.as_ref() == Some(&block); - let block_for_digest = if build_skewed_digest { - config - .config - .next_max_level_digest_range(config.zero.clone(), block.clone()) - .map(|(_, end)| end) - .unwrap_or_else(|| block.clone()) - } else { - block.clone() - }; - - let digest_input_blocks = digest_build_iterator(config, block_for_digest).collect::>(); - digest_input_blocks - .clone() - .into_iter() - .try_fold( - (BTreeMap::new(), BTreeMap::new()), - move |(mut map, mut child_map), digest_build_block| { - let extrinsic_prefix = - ExtrinsicIndex::key_neutral_prefix(digest_build_block.clone()); - let digest_prefix = DigestIndex::key_neutral_prefix(digest_build_block.clone()); - let child_prefix = ChildIndex::key_neutral_prefix(digest_build_block.clone()); - let trie_root = storage.root(parent, digest_build_block.clone())?; - let trie_root = trie_root.ok_or_else(|| { - format!("No changes trie root for block {}", digest_build_block.clone()) - })?; - - let insert_to_map = |map: &mut BTreeMap<_, _>, key: StorageKey| { - match map.entry(key.clone()) { - Entry::Vacant(entry) => { - entry.insert(( - DigestIndex { block: block.clone(), key }, - vec![digest_build_block.clone()], - )); - }, - Entry::Occupied(mut entry) => { - // DigestIndexValue must be sorted. Here we are relying on the fact that - // digest_build_iterator() returns blocks in ascending order => we only - // need to check for duplicates - // - // is_dup_block could be true when key has been changed in both digest - // block AND other blocks that it covers - let is_dup_block = entry.get().1.last() == Some(&digest_build_block); - if !is_dup_block { - entry.get_mut().1.push(digest_build_block.clone()); - } - }, - } - }; - - // try to get all updated keys from cache - let populated_from_cache = - storage.with_cached_changed_keys(&trie_root, &mut |changed_keys| { - for (storage_key, changed_keys) in changed_keys { - let map = match storage_key { - Some(storage_key) => child_map - .entry(ChildIndex:: { - block: block.clone(), - storage_key: storage_key.clone(), - }) - .or_default(), - None => &mut map, - }; - for changed_key in changed_keys.iter().cloned() { - insert_to_map(map, changed_key); - } - } - }); - if populated_from_cache { - return Ok((map, child_map)) - } - - let mut children_roots = BTreeMap::::new(); - { - let trie_storage = TrieBackendEssence::<_, H>::new( - crate::changes_trie::TrieBackendStorageAdapter(storage), - trie_root, - ); - - trie_storage.for_key_values_with_prefix(&child_prefix, |mut key, mut value| { - if let Ok(InputKey::ChildIndex::(trie_key)) = - Decode::decode(&mut key) - { - if let Ok(value) = >::decode(&mut value) { - let mut trie_root = ::Out::default(); - trie_root.as_mut().copy_from_slice(&value[..]); - children_roots.insert(trie_key.storage_key, trie_root); - } - } - }); - - trie_storage.for_keys_with_prefix(&extrinsic_prefix, |mut key| { - if let Ok(InputKey::ExtrinsicIndex::(trie_key)) = - Decode::decode(&mut key) - { - insert_to_map(&mut map, trie_key.key); - } - }); - - trie_storage.for_keys_with_prefix(&digest_prefix, |mut key| { - if let Ok(InputKey::DigestIndex::(trie_key)) = - Decode::decode(&mut key) - { - insert_to_map(&mut map, trie_key.key); - } - }); - } - - for (storage_key, trie_root) in children_roots.into_iter() { - let child_index = ChildIndex:: { block: block.clone(), storage_key }; - - let mut map = child_map.entry(child_index).or_default(); - let trie_storage = TrieBackendEssence::<_, H>::new( - crate::changes_trie::TrieBackendStorageAdapter(storage), - trie_root, - ); - trie_storage.for_keys_with_prefix(&extrinsic_prefix, |mut key| { - if let Ok(InputKey::ExtrinsicIndex::(trie_key)) = - Decode::decode(&mut key) - { - insert_to_map(&mut map, trie_key.key); - } - }); - - trie_storage.for_keys_with_prefix(&digest_prefix, |mut key| { - if let Ok(InputKey::DigestIndex::(trie_key)) = - Decode::decode(&mut key) - { - insert_to_map(&mut map, trie_key.key); - } - }); - } - Ok((map, child_map)) - }, - ) - .map(|(pairs, child_pairs)| { - ( - pairs.into_iter().map(|(_, (k, v))| InputPair::DigestIndex(k, v)), - child_pairs - .into_iter() - .map(|(sk, pairs)| { - (sk, pairs.into_iter().map(|(_, (k, v))| InputPair::DigestIndex(k, v))) - }) - .collect(), - digest_input_blocks, - ) - }) -} - -#[cfg(test)] -mod test { - use super::*; - use crate::{ - changes_trie::{ - build_cache::{IncompleteCacheAction, IncompleteCachedBuildData}, - storage::InMemoryStorage, - Configuration, RootsStorage, - }, - InMemoryBackend, - }; - use sp_core::Blake2Hasher; - - fn prepare_for_build( - zero: u64, - ) -> ( - InMemoryBackend, - InMemoryStorage, - OverlayedChanges, - Configuration, - ) { - let child_info_1 = ChildInfo::new_default(b"storage_key1"); - let child_info_2 = ChildInfo::new_default(b"storage_key2"); - let backend: InMemoryBackend<_> = vec![ - (vec![100], vec![255]), - (vec![101], vec![255]), - (vec![102], vec![255]), - (vec![103], vec![255]), - (vec![104], vec![255]), - (vec![105], vec![255]), - ] - .into_iter() - .collect::>() - .into(); - let prefixed_child_trie_key1 = child_info_1.prefixed_storage_key(); - let storage = InMemoryStorage::with_inputs( - vec![ - ( - zero + 1, - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 1, key: vec![100] }, - vec![1, 3], - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 1, key: vec![101] }, - vec![0, 2], - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 1, key: vec![105] }, - vec![0, 2, 4], - ), - ], - ), - ( - zero + 2, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 2, key: vec![102] }, - vec![0], - )], - ), - ( - zero + 3, - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 3, key: vec![100] }, - vec![0], - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 3, key: vec![105] }, - vec![1], - ), - ], - ), - ( - zero + 4, - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![100] }, - vec![0, 2, 3], - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![101] }, - vec![1], - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![103] }, - vec![0, 1], - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![100] }, - vec![zero + 1, zero + 3], - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![101] }, - vec![zero + 1], - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![102] }, - vec![zero + 2], - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![105] }, - vec![zero + 1, zero + 3], - ), - ], - ), - (zero + 5, Vec::new()), - ( - zero + 6, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 6, key: vec![105] }, - vec![2], - )], - ), - (zero + 7, Vec::new()), - ( - zero + 8, - vec![InputPair::DigestIndex( - DigestIndex { block: zero + 8, key: vec![105] }, - vec![zero + 6], - )], - ), - (zero + 9, Vec::new()), - (zero + 10, Vec::new()), - (zero + 11, Vec::new()), - (zero + 12, Vec::new()), - (zero + 13, Vec::new()), - (zero + 14, Vec::new()), - (zero + 15, Vec::new()), - ], - vec![( - prefixed_child_trie_key1.clone(), - vec![ - ( - zero + 1, - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 1, key: vec![100] }, - vec![1, 3], - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 1, key: vec![101] }, - vec![0, 2], - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 1, key: vec![105] }, - vec![0, 2, 4], - ), - ], - ), - ( - zero + 2, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 2, key: vec![102] }, - vec![0], - )], - ), - ( - zero + 4, - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 2, key: vec![102] }, - vec![0, 3], - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![102] }, - vec![zero + 2], - ), - ], - ), - ], - )], - ); - - let mut changes = OverlayedChanges::default(); - changes.set_collect_extrinsics(true); - - changes.start_transaction(); - - changes.set_extrinsic_index(1); - changes.set_storage(vec![101], Some(vec![203])); - - changes.set_extrinsic_index(3); - changes.set_storage(vec![100], Some(vec![202])); - changes.set_child_storage(&child_info_1, vec![100], Some(vec![202])); - - changes.commit_transaction().unwrap(); - - changes.set_extrinsic_index(0); - changes.set_storage(vec![100], Some(vec![0])); - changes.set_extrinsic_index(2); - changes.set_storage(vec![100], Some(vec![200])); - - changes.set_extrinsic_index(0); - changes.set_storage(vec![103], Some(vec![0])); - changes.set_extrinsic_index(1); - changes.set_storage(vec![103], None); - - changes.set_extrinsic_index(0); - changes.set_child_storage(&child_info_1, vec![100], Some(vec![0])); - changes.set_extrinsic_index(2); - changes.set_child_storage(&child_info_1, vec![100], Some(vec![200])); - - changes.set_extrinsic_index(0); - changes.set_child_storage(&child_info_2, vec![100], Some(vec![0])); - changes.set_extrinsic_index(2); - changes.set_child_storage(&child_info_2, vec![100], Some(vec![200])); - - changes.set_extrinsic_index(1); - - let config = Configuration { digest_interval: 4, digest_levels: 2 }; - - (backend, storage, changes, config) - } - - fn configuration_range<'a>( - config: &'a Configuration, - zero: u64, - ) -> ConfigurationRange<'a, u64> { - ConfigurationRange { config, zero, end: None } - } - - #[test] - fn build_changes_trie_nodes_on_non_digest_block() { - fn test_with_zero(zero: u64) { - let child_trie_key1 = ChildInfo::new_default(b"storage_key1").prefixed_storage_key(); - let child_trie_key2 = ChildInfo::new_default(b"storage_key2").prefixed_storage_key(); - let (backend, storage, changes, config) = prepare_for_build(zero); - let parent = AnchorBlockId { hash: Default::default(), number: zero + 4 }; - let changes_trie_nodes = prepare_input( - &backend, - &storage, - configuration_range(&config, zero), - &changes, - &parent, - ) - .unwrap(); - assert_eq!( - changes_trie_nodes.0.collect::>>(), - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 5, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 5, key: vec![101] }, - vec![1] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 5, key: vec![103] }, - vec![0, 1] - ), - ] - ); - assert_eq!( - changes_trie_nodes - .1 - .into_iter() - .map(|(k, v)| (k, v.collect::>())) - .collect::>(), - vec![ - ( - ChildIndex { block: zero + 5u64, storage_key: child_trie_key1 }, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 5u64, key: vec![100] }, - vec![0, 2, 3] - ),] - ), - ( - ChildIndex { block: zero + 5, storage_key: child_trie_key2 }, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 5, key: vec![100] }, - vec![0, 2] - ),] - ), - ] - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn build_changes_trie_nodes_on_digest_block_l1() { - fn test_with_zero(zero: u64) { - let child_trie_key1 = ChildInfo::new_default(b"storage_key1").prefixed_storage_key(); - let child_trie_key2 = ChildInfo::new_default(b"storage_key2").prefixed_storage_key(); - let (backend, storage, changes, config) = prepare_for_build(zero); - let parent = AnchorBlockId { hash: Default::default(), number: zero + 3 }; - let changes_trie_nodes = prepare_input( - &backend, - &storage, - configuration_range(&config, zero), - &changes, - &parent, - ) - .unwrap(); - assert_eq!( - changes_trie_nodes.0.collect::>>(), - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![101] }, - vec![1] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![103] }, - vec![0, 1] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![100] }, - vec![zero + 1, zero + 3] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![101] }, - vec![zero + 1] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![102] }, - vec![zero + 2] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![105] }, - vec![zero + 1, zero + 3] - ), - ] - ); - assert_eq!( - changes_trie_nodes - .1 - .into_iter() - .map(|(k, v)| (k, v.collect::>())) - .collect::>(), - vec![ - ( - ChildIndex { block: zero + 4u64, storage_key: child_trie_key1.clone() }, - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4u64, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![100] }, - vec![zero + 1] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![101] }, - vec![zero + 1] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![102] }, - vec![zero + 2] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![105] }, - vec![zero + 1] - ), - ] - ), - ( - ChildIndex { block: zero + 4, storage_key: child_trie_key2.clone() }, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![100] }, - vec![0, 2] - ),] - ), - ] - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn build_changes_trie_nodes_on_digest_block_l2() { - fn test_with_zero(zero: u64) { - let child_trie_key1 = ChildInfo::new_default(b"storage_key1").prefixed_storage_key(); - let child_trie_key2 = ChildInfo::new_default(b"storage_key2").prefixed_storage_key(); - let (backend, storage, changes, config) = prepare_for_build(zero); - let parent = AnchorBlockId { hash: Default::default(), number: zero + 15 }; - let changes_trie_nodes = prepare_input( - &backend, - &storage, - configuration_range(&config, zero), - &changes, - &parent, - ) - .unwrap(); - assert_eq!( - changes_trie_nodes.0.collect::>>(), - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 16, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 16, key: vec![101] }, - vec![1] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 16, key: vec![103] }, - vec![0, 1] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 16, key: vec![100] }, - vec![zero + 4] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 16, key: vec![101] }, - vec![zero + 4] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 16, key: vec![102] }, - vec![zero + 4] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 16, key: vec![103] }, - vec![zero + 4] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 16, key: vec![105] }, - vec![zero + 4, zero + 8] - ), - ] - ); - assert_eq!( - changes_trie_nodes - .1 - .into_iter() - .map(|(k, v)| (k, v.collect::>())) - .collect::>(), - vec![ - ( - ChildIndex { block: zero + 16u64, storage_key: child_trie_key1.clone() }, - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 16u64, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 16, key: vec![102] }, - vec![zero + 4] - ), - ] - ), - ( - ChildIndex { block: zero + 16, storage_key: child_trie_key2.clone() }, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 16, key: vec![100] }, - vec![0, 2] - ),] - ), - ] - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn build_changes_trie_nodes_on_skewed_digest_block() { - fn test_with_zero(zero: u64) { - let (backend, storage, changes, config) = prepare_for_build(zero); - let parent = AnchorBlockId { hash: Default::default(), number: zero + 10 }; - - let mut configuration_range = configuration_range(&config, zero); - let changes_trie_nodes = - prepare_input(&backend, &storage, configuration_range.clone(), &changes, &parent) - .unwrap(); - assert_eq!( - changes_trie_nodes.0.collect::>>(), - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 11, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 11, key: vec![101] }, - vec![1] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 11, key: vec![103] }, - vec![0, 1] - ), - ] - ); - - configuration_range.end = Some(zero + 11); - let changes_trie_nodes = - prepare_input(&backend, &storage, configuration_range, &changes, &parent).unwrap(); - assert_eq!( - changes_trie_nodes.0.collect::>>(), - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 11, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 11, key: vec![101] }, - vec![1] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 11, key: vec![103] }, - vec![0, 1] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 11, key: vec![100] }, - vec![zero + 4] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 11, key: vec![101] }, - vec![zero + 4] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 11, key: vec![102] }, - vec![zero + 4] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 11, key: vec![103] }, - vec![zero + 4] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 11, key: vec![105] }, - vec![zero + 4, zero + 8] - ), - ] - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn build_changes_trie_nodes_ignores_temporary_storage_values() { - fn test_with_zero(zero: u64) { - let child_trie_key1 = ChildInfo::new_default(b"storage_key1").prefixed_storage_key(); - let child_trie_key2 = ChildInfo::new_default(b"storage_key2").prefixed_storage_key(); - let (backend, storage, mut changes, config) = prepare_for_build(zero); - - // 110: missing from backend, set to None in overlay - changes.set_storage(vec![110], None); - - let parent = AnchorBlockId { hash: Default::default(), number: zero + 3 }; - let changes_trie_nodes = prepare_input( - &backend, - &storage, - configuration_range(&config, zero), - &changes, - &parent, - ) - .unwrap(); - assert_eq!( - changes_trie_nodes.0.collect::>>(), - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![101] }, - vec![1] - ), - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![103] }, - vec![0, 1] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![100] }, - vec![zero + 1, zero + 3] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![101] }, - vec![zero + 1] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![102] }, - vec![zero + 2] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![105] }, - vec![zero + 1, zero + 3] - ), - ] - ); - assert_eq!( - changes_trie_nodes - .1 - .into_iter() - .map(|(k, v)| (k, v.collect::>())) - .collect::>(), - vec![ - ( - ChildIndex { block: zero + 4u64, storage_key: child_trie_key1.clone() }, - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4u64, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![100] }, - vec![zero + 1] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![101] }, - vec![zero + 1] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![102] }, - vec![zero + 2] - ), - InputPair::DigestIndex( - DigestIndex { block: zero + 4, key: vec![105] }, - vec![zero + 1] - ), - ] - ), - ( - ChildIndex { block: zero + 4, storage_key: child_trie_key2.clone() }, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: zero + 4, key: vec![100] }, - vec![0, 2] - ),] - ), - ] - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn cache_is_used_when_changes_trie_is_built() { - let child_trie_key1 = ChildInfo::new_default(b"storage_key1").prefixed_storage_key(); - let child_trie_key2 = ChildInfo::new_default(b"storage_key2").prefixed_storage_key(); - let (backend, mut storage, changes, config) = prepare_for_build(0); - let parent = AnchorBlockId { hash: Default::default(), number: 15 }; - - // override some actual values from storage with values from the cache - // - // top-level storage: - // (keys 100, 101, 103, 105 are now missing from block#4 => they do not appear - // in l2 digest at block 16) - // - // "1" child storage: - // key 102 is now missing from block#4 => it doesn't appear in l2 digest at block 16 - // (keys 103, 104) are now added to block#4 => they appear in l2 digest at block 16 - // - // "2" child storage: - // (keys 105, 106) are now added to block#4 => they appear in l2 digest at block 16 - let trie_root4 = storage.root(&parent, 4).unwrap().unwrap(); - let cached_data4 = IncompleteCacheAction::CacheBuildData(IncompleteCachedBuildData::new()) - .set_digest_input_blocks(vec![1, 2, 3]) - .insert(None, vec![vec![100], vec![102]].into_iter().collect()) - .insert(Some(child_trie_key1.clone()), vec![vec![103], vec![104]].into_iter().collect()) - .insert(Some(child_trie_key2.clone()), vec![vec![105], vec![106]].into_iter().collect()) - .complete(4, &trie_root4); - storage.cache_mut().perform(cached_data4); - - let (root_changes_trie_nodes, child_changes_tries_nodes, _) = - prepare_input(&backend, &storage, configuration_range(&config, 0), &changes, &parent) - .unwrap(); - assert_eq!( - root_changes_trie_nodes.collect::>>(), - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: 16, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 16, key: vec![101] }, vec![1]), - InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 16, key: vec![103] }, vec![0, 1]), - InputPair::DigestIndex(DigestIndex { block: 16, key: vec![100] }, vec![4]), - InputPair::DigestIndex(DigestIndex { block: 16, key: vec![102] }, vec![4]), - InputPair::DigestIndex(DigestIndex { block: 16, key: vec![105] }, vec![8]), - ] - ); - - let child_changes_tries_nodes = child_changes_tries_nodes - .into_iter() - .map(|(k, i)| (k, i.collect::>())) - .collect::>(); - assert_eq!( - child_changes_tries_nodes - .get(&ChildIndex { block: 16u64, storage_key: child_trie_key1.clone() }) - .unwrap(), - &vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: 16u64, key: vec![100] }, - vec![0, 2, 3] - ), - InputPair::DigestIndex(DigestIndex { block: 16u64, key: vec![103] }, vec![4]), - InputPair::DigestIndex(DigestIndex { block: 16u64, key: vec![104] }, vec![4]), - ], - ); - assert_eq!( - child_changes_tries_nodes - .get(&ChildIndex { block: 16u64, storage_key: child_trie_key2.clone() }) - .unwrap(), - &vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: 16u64, key: vec![100] }, - vec![0, 2] - ), - InputPair::DigestIndex(DigestIndex { block: 16u64, key: vec![105] }, vec![4]), - InputPair::DigestIndex(DigestIndex { block: 16u64, key: vec![106] }, vec![4]), - ], - ); - } -} diff --git a/primitives/state-machine/src/changes_trie/build_cache.rs b/primitives/state-machine/src/changes_trie/build_cache.rs deleted file mode 100644 index 04820242d9d08..0000000000000 --- a/primitives/state-machine/src/changes_trie/build_cache.rs +++ /dev/null @@ -1,278 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Changes tries build cache. - -use std::collections::{HashMap, HashSet}; - -use crate::StorageKey; -use sp_core::storage::PrefixedStorageKey; - -/// Changes trie build cache. -/// -/// Helps to avoid read of changes tries from the database when digest trie -/// is built. It holds changed keys for every block (indexed by changes trie -/// root) that could be referenced by future digest items. For digest entries -/// it also holds keys covered by this digest. Entries for top level digests -/// are never created, because they'll never be used to build other digests. -/// -/// Entries are pruned from the cache once digest block that is using this entry -/// is inserted (because digest block will includes all keys from this entry). -/// When there's a fork, entries are pruned when first changes trie is inserted. -pub struct BuildCache { - /// Map of block (implies changes trie) number => changes trie root. - roots_by_number: HashMap, - /// Map of changes trie root => set of storage keys that are in this trie. - /// The `Option>` in inner `HashMap` stands for the child storage key. - /// If it is `None`, then the `HashSet` contains keys changed in top-level storage. - /// If it is `Some`, then the `HashSet` contains keys changed in child storage, identified by - /// the key. - changed_keys: HashMap, HashSet>>, -} - -/// The action to perform when block-with-changes-trie is imported. -#[derive(Debug, PartialEq)] -pub enum CacheAction { - /// Cache data that has been collected when CT has been built. - CacheBuildData(CachedBuildData), - /// Clear cache from all existing entries. - Clear, -} - -/// The data that has been cached during changes trie building. -#[derive(Debug, PartialEq)] -pub struct CachedBuildData { - block: N, - trie_root: H, - digest_input_blocks: Vec, - changed_keys: HashMap, HashSet>, -} - -/// The action to perform when block-with-changes-trie is imported. -#[derive(Debug, PartialEq)] -pub(crate) enum IncompleteCacheAction { - /// Cache data that has been collected when CT has been built. - CacheBuildData(IncompleteCachedBuildData), - /// Clear cache from all existing entries. - Clear, -} - -/// The data (without changes trie root) that has been cached during changes trie building. -#[derive(Debug, PartialEq)] -pub(crate) struct IncompleteCachedBuildData { - digest_input_blocks: Vec, - changed_keys: HashMap, HashSet>, -} - -impl BuildCache -where - N: Eq + ::std::hash::Hash, - H: Eq + ::std::hash::Hash + Clone, -{ - /// Create new changes trie build cache. - pub fn new() -> Self { - BuildCache { roots_by_number: HashMap::new(), changed_keys: HashMap::new() } - } - - /// Get cached changed keys for changes trie with given root. - pub fn get( - &self, - root: &H, - ) -> Option<&HashMap, HashSet>> { - self.changed_keys.get(&root) - } - - /// Execute given functor with cached entry for given block. - /// Returns true if the functor has been called and false otherwise. - pub fn with_changed_keys( - &self, - root: &H, - functor: &mut dyn FnMut(&HashMap, HashSet>), - ) -> bool { - match self.changed_keys.get(&root) { - Some(changed_keys) => { - functor(changed_keys); - true - }, - None => false, - } - } - - /// Insert data into cache. - pub fn perform(&mut self, action: CacheAction) { - match action { - CacheAction::CacheBuildData(data) => { - self.roots_by_number.insert(data.block, data.trie_root.clone()); - self.changed_keys.insert(data.trie_root, data.changed_keys); - - for digest_input_block in data.digest_input_blocks { - let digest_input_block_hash = self.roots_by_number.remove(&digest_input_block); - if let Some(digest_input_block_hash) = digest_input_block_hash { - self.changed_keys.remove(&digest_input_block_hash); - } - } - }, - CacheAction::Clear => { - self.roots_by_number.clear(); - self.changed_keys.clear(); - }, - } - } -} - -impl IncompleteCacheAction { - /// Returns true if we need to collect changed keys for this action. - pub fn collects_changed_keys(&self) -> bool { - match *self { - IncompleteCacheAction::CacheBuildData(_) => true, - IncompleteCacheAction::Clear => false, - } - } - - /// Complete cache action with computed changes trie root. - pub(crate) fn complete(self, block: N, trie_root: &H) -> CacheAction { - match self { - IncompleteCacheAction::CacheBuildData(build_data) => - CacheAction::CacheBuildData(build_data.complete(block, trie_root.clone())), - IncompleteCacheAction::Clear => CacheAction::Clear, - } - } - - /// Set numbers of blocks that are superseded by this new entry. - /// - /// If/when this build data is committed to the cache, entries for these blocks - /// will be removed from the cache. - pub(crate) fn set_digest_input_blocks(self, digest_input_blocks: Vec) -> Self { - match self { - IncompleteCacheAction::CacheBuildData(build_data) => - IncompleteCacheAction::CacheBuildData( - build_data.set_digest_input_blocks(digest_input_blocks), - ), - IncompleteCacheAction::Clear => IncompleteCacheAction::Clear, - } - } - - /// Insert changed keys of given storage into cached data. - pub(crate) fn insert( - self, - storage_key: Option, - changed_keys: HashSet, - ) -> Self { - match self { - IncompleteCacheAction::CacheBuildData(build_data) => - IncompleteCacheAction::CacheBuildData(build_data.insert(storage_key, changed_keys)), - IncompleteCacheAction::Clear => IncompleteCacheAction::Clear, - } - } -} - -impl IncompleteCachedBuildData { - /// Create new cached data. - pub(crate) fn new() -> Self { - IncompleteCachedBuildData { digest_input_blocks: Vec::new(), changed_keys: HashMap::new() } - } - - fn complete(self, block: N, trie_root: H) -> CachedBuildData { - CachedBuildData { - block, - trie_root, - digest_input_blocks: self.digest_input_blocks, - changed_keys: self.changed_keys, - } - } - - fn set_digest_input_blocks(mut self, digest_input_blocks: Vec) -> Self { - self.digest_input_blocks = digest_input_blocks; - self - } - - fn insert( - mut self, - storage_key: Option, - changed_keys: HashSet, - ) -> Self { - self.changed_keys.insert(storage_key, changed_keys); - self - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn updated_keys_are_stored_when_non_top_level_digest_is_built() { - let mut data = IncompleteCachedBuildData::::new(); - data = data.insert(None, vec![vec![1]].into_iter().collect()); - assert_eq!(data.changed_keys.len(), 1); - - let mut cache = BuildCache::new(); - cache.perform(CacheAction::CacheBuildData(data.complete(1, 1))); - assert_eq!(cache.changed_keys.len(), 1); - assert_eq!( - cache.get(&1).unwrap().clone(), - vec![(None, vec![vec![1]].into_iter().collect())].into_iter().collect(), - ); - } - - #[test] - fn obsolete_entries_are_purged_when_new_ct_is_built() { - let mut cache = BuildCache::::new(); - cache.perform(CacheAction::CacheBuildData( - IncompleteCachedBuildData::new() - .insert(None, vec![vec![1]].into_iter().collect()) - .complete(1, 1), - )); - cache.perform(CacheAction::CacheBuildData( - IncompleteCachedBuildData::new() - .insert(None, vec![vec![2]].into_iter().collect()) - .complete(2, 2), - )); - cache.perform(CacheAction::CacheBuildData( - IncompleteCachedBuildData::new() - .insert(None, vec![vec![3]].into_iter().collect()) - .complete(3, 3), - )); - - assert_eq!(cache.changed_keys.len(), 3); - - cache.perform(CacheAction::CacheBuildData( - IncompleteCachedBuildData::new() - .set_digest_input_blocks(vec![1, 2, 3]) - .complete(4, 4), - )); - - assert_eq!(cache.changed_keys.len(), 1); - - cache.perform(CacheAction::CacheBuildData( - IncompleteCachedBuildData::new() - .insert(None, vec![vec![8]].into_iter().collect()) - .complete(8, 8), - )); - cache.perform(CacheAction::CacheBuildData( - IncompleteCachedBuildData::new() - .insert(None, vec![vec![12]].into_iter().collect()) - .complete(12, 12), - )); - - assert_eq!(cache.changed_keys.len(), 3); - - cache.perform(CacheAction::Clear); - - assert_eq!(cache.changed_keys.len(), 0); - } -} diff --git a/primitives/state-machine/src/changes_trie/build_iterator.rs b/primitives/state-machine/src/changes_trie/build_iterator.rs deleted file mode 100644 index 62bb00a2f8829..0000000000000 --- a/primitives/state-machine/src/changes_trie/build_iterator.rs +++ /dev/null @@ -1,487 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Structures and functions to return blocks whose changes are to be included -//! in given block's changes trie. - -use crate::changes_trie::{BlockNumber, ConfigurationRange}; -use num_traits::Zero; - -/// Returns iterator of OTHER blocks that are required for inclusion into -/// changes trie of given block. Blocks are guaranteed to be returned in -/// ascending order. -/// -/// Skewed digest is built IF block >= config.end. -pub fn digest_build_iterator<'a, Number: BlockNumber>( - config: ConfigurationRange<'a, Number>, - block: Number, -) -> DigestBuildIterator { - // prepare digest build parameters - let (_, _, digest_step) = match config.config.digest_level_at_block(config.zero, block.clone()) - { - Some((current_level, digest_interval, digest_step)) => - (current_level, digest_interval, digest_step), - None => return DigestBuildIterator::empty(), - }; - - DigestBuildIterator::new( - block.clone(), - config.end.unwrap_or(block), - config.config.digest_interval, - digest_step, - ) -} - -/// Changes trie build iterator that returns numbers of OTHER blocks that are -/// required for inclusion into changes trie of given block. -#[derive(Debug)] -pub struct DigestBuildIterator { - /// Block we're building changes trie for. It could (logically) be a post-end block if we are - /// creating skewed digest. - block: Number, - /// Block that is a last block where current configuration is active. We have never yet created - /// anything after this block => digest that we're creating can't reference any blocks that are - /// >= end. - end: Number, - /// Interval of L1 digest blocks. - digest_interval: u32, - /// Max step that could be used when digest is created. - max_step: u32, - - // Mutable data below: - /// Step of current blocks range. - current_step: u32, - /// Reverse step of current blocks range. - current_step_reverse: u32, - /// Current blocks range. - current_range: Option>, - /// Last block that we have returned. - last_block: Option, -} - -impl DigestBuildIterator { - /// Create new digest build iterator. - pub fn new(block: Number, end: Number, digest_interval: u32, max_step: u32) -> Self { - DigestBuildIterator { - block, - end, - digest_interval, - max_step, - current_step: max_step, - current_step_reverse: 0, - current_range: None, - last_block: None, - } - } - - /// Create empty digest build iterator. - pub fn empty() -> Self { - Self::new(Zero::zero(), Zero::zero(), 0, 0) - } -} - -impl Iterator for DigestBuildIterator { - type Item = Number; - - fn next(&mut self) -> Option { - // when we're building skewed digest, we might want to skip some blocks if - // they're not covered by current configuration - loop { - if let Some(next) = self.current_range.as_mut().and_then(|iter| iter.next()) { - if next < self.end { - self.last_block = Some(next.clone()); - return Some(next) - } - } - - // we are safe to use non-checking mul/sub versions here because: - // DigestBuildIterator is created only by internal function that is checking - // that all multiplications/subtractions are safe within max_step limit - - let next_step_reverse = if self.current_step_reverse == 0 { - 1 - } else { - self.current_step_reverse * self.digest_interval - }; - if next_step_reverse > self.max_step { - return None - } - - self.current_step_reverse = next_step_reverse; - self.current_range = Some(BlocksRange::new( - match self.last_block.clone() { - Some(last_block) => last_block + self.current_step.into(), - None => - self.block.clone() - - (self.current_step * self.digest_interval - self.current_step).into(), - }, - self.block.clone(), - self.current_step.into(), - )); - - self.current_step = self.current_step / self.digest_interval; - if self.current_step == 0 { - self.current_step = 1; - } - } - } -} - -/// Blocks range iterator with builtin step_by support. -#[derive(Debug)] -struct BlocksRange { - current: Number, - end: Number, - step: Number, -} - -impl BlocksRange { - pub fn new(begin: Number, end: Number, step: Number) -> Self { - BlocksRange { current: begin, end, step } - } -} - -impl Iterator for BlocksRange { - type Item = Number; - - fn next(&mut self) -> Option { - if self.current >= self.end { - return None - } - - let current = Some(self.current.clone()); - self.current += self.step.clone(); - current - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::changes_trie::Configuration; - - fn digest_build_iterator( - digest_interval: u32, - digest_levels: u32, - zero: u64, - block: u64, - end: Option, - ) -> DigestBuildIterator { - super::digest_build_iterator( - ConfigurationRange { - config: &Configuration { digest_interval, digest_levels }, - zero, - end, - }, - block, - ) - } - - fn digest_build_iterator_basic( - digest_interval: u32, - digest_levels: u32, - zero: u64, - block: u64, - ) -> (u64, u32, u32) { - let iter = digest_build_iterator(digest_interval, digest_levels, zero, block, None); - (iter.block, iter.digest_interval, iter.max_step) - } - - fn digest_build_iterator_blocks( - digest_interval: u32, - digest_levels: u32, - zero: u64, - block: u64, - end: Option, - ) -> Vec { - digest_build_iterator(digest_interval, digest_levels, zero, block, end).collect() - } - - #[test] - fn suggest_digest_inclusion_returns_empty_iterator() { - fn test_with_zero(zero: u64) { - let empty = (0, 0, 0); - assert_eq!(digest_build_iterator_basic(4, 16, zero, zero + 0), empty, "block is 0"); - assert_eq!( - digest_build_iterator_basic(0, 16, zero, zero + 64), - empty, - "digest_interval is 0" - ); - assert_eq!( - digest_build_iterator_basic(1, 16, zero, zero + 64), - empty, - "digest_interval is 1" - ); - assert_eq!( - digest_build_iterator_basic(4, 0, zero, zero + 64), - empty, - "digest_levels is 0" - ); - assert_eq!( - digest_build_iterator_basic(4, 16, zero, zero + 1), - empty, - "digest is not required for this block", - ); - assert_eq!( - digest_build_iterator_basic(4, 16, zero, zero + 2), - empty, - "digest is not required for this block", - ); - assert_eq!( - digest_build_iterator_basic(4, 16, zero, zero + 15), - empty, - "digest is not required for this block", - ); - assert_eq!( - digest_build_iterator_basic(4, 16, zero, zero + 17), - empty, - "digest is not required for this block", - ); - assert_eq!( - digest_build_iterator_basic(::std::u32::MAX / 2 + 1, 16, zero, ::std::u64::MAX,), - empty, - "digest_interval * 2 is greater than u64::MAX" - ); - } - - test_with_zero(0); - test_with_zero(1); - test_with_zero(2); - test_with_zero(4); - test_with_zero(17); - } - - #[test] - fn suggest_digest_inclusion_returns_level1_iterator() { - fn test_with_zero(zero: u64) { - assert_eq!( - digest_build_iterator_basic(16, 1, zero, zero + 16), - (zero + 16, 16, 1), - "!(block % interval) && first digest level == block", - ); - assert_eq!( - digest_build_iterator_basic(16, 1, zero, zero + 256), - (zero + 256, 16, 1), - "!(block % interval^2), but there's only 1 digest level", - ); - assert_eq!( - digest_build_iterator_basic(16, 2, zero, zero + 32), - (zero + 32, 16, 1), - "second level digest is not required for this block", - ); - assert_eq!( - digest_build_iterator_basic(16, 3, zero, zero + 4080), - (zero + 4080, 16, 1), - "second && third level digest are not required for this block", - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn suggest_digest_inclusion_returns_level2_iterator() { - fn test_with_zero(zero: u64) { - assert_eq!( - digest_build_iterator_basic(16, 2, zero, zero + 256), - (zero + 256, 16, 16), - "second level digest", - ); - assert_eq!( - digest_build_iterator_basic(16, 2, zero, zero + 4096), - (zero + 4096, 16, 16), - "!(block % interval^3), but there's only 2 digest levels", - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn suggest_digest_inclusion_returns_level3_iterator() { - fn test_with_zero(zero: u64) { - assert_eq!( - digest_build_iterator_basic(16, 3, zero, zero + 4096), - (zero + 4096, 16, 256), - "third level digest: beginning", - ); - assert_eq!( - digest_build_iterator_basic(16, 3, zero, zero + 8192), - (zero + 8192, 16, 256), - "third level digest: next", - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn digest_iterator_returns_level1_blocks() { - fn test_with_zero(zero: u64) { - assert_eq!( - digest_build_iterator_blocks(16, 1, zero, zero + 16, None), - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] - .iter() - .map(|item| zero + item) - .collect::>() - ); - assert_eq!( - digest_build_iterator_blocks(16, 1, zero, zero + 256, None), - [241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255] - .iter() - .map(|item| zero + item) - .collect::>() - ); - assert_eq!( - digest_build_iterator_blocks(16, 2, zero, zero + 32, None), - [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] - .iter() - .map(|item| zero + item) - .collect::>() - ); - assert_eq!( - digest_build_iterator_blocks(16, 3, zero, zero + 4080, None), - [ - 4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077, - 4078, 4079 - ] - .iter() - .map(|item| zero + item) - .collect::>() - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn digest_iterator_returns_level1_and_level2_blocks() { - fn test_with_zero(zero: u64) { - assert_eq!( - digest_build_iterator_blocks(16, 2, zero, zero + 256, None), - [ - // level2 points to previous 16-1 level1 digests: - 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, - // level2 is a level1 digest of 16-1 previous blocks: - 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - ] - .iter() - .map(|item| zero + item) - .collect::>(), - ); - assert_eq!( - digest_build_iterator_blocks(16, 2, zero, zero + 4096, None), - [ - // level2 points to previous 16-1 level1 digests: - 3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048, - 4064, 4080, // level2 is a level1 digest of 16-1 previous blocks: - 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, - 4094, 4095, - ] - .iter() - .map(|item| zero + item) - .collect::>(), - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn digest_iterator_returns_level1_and_level2_and_level3_blocks() { - fn test_with_zero(zero: u64) { - assert_eq!( - digest_build_iterator_blocks(16, 3, zero, zero + 4096, None), - [ - // level3 points to previous 16-1 level2 digests: - 256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, - 3840, // level3 points to previous 16-1 level1 digests: - 3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048, - 4064, 4080, // level3 is a level1 digest of 16-1 previous blocks: - 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, - 4094, 4095, - ] - .iter() - .map(|item| zero + item) - .collect::>(), - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn digest_iterator_returns_skewed_digest_blocks() { - fn test_with_zero(zero: u64) { - assert_eq!( - digest_build_iterator_blocks(16, 3, zero, zero + 4096, Some(zero + 1338)), - [ - // level3 MUST point to previous 16-1 level2 digests, BUT there are only 5: - 256, 512, 768, 1024, 1280, - // level3 MUST point to previous 16-1 level1 digests, BUT there are only 3: - 1296, 1312, 1328, - // level3 MUST be a level1 digest of 16-1 previous blocks, BUT there are only - // 9: - 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, - ] - .iter() - .map(|item| zero + item) - .collect::>(), - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } - - #[test] - fn digest_iterator_returns_skewed_digest_blocks_skipping_level() { - fn test_with_zero(zero: u64) { - assert_eq!( - digest_build_iterator_blocks(16, 3, zero, zero + 4096, Some(zero + 1284)), - [ - // level3 MUST point to previous 16-1 level2 digests, BUT there are only 5: - 256, 512, 768, 1024, 1280, - // level3 MUST point to previous 16-1 level1 digests, BUT there are NO ANY - // L1-digests: level3 MUST be a level1 digest of 16-1 previous blocks, BUT - // there are only 3: - 1281, 1282, 1283, - ] - .iter() - .map(|item| zero + item) - .collect::>(), - ); - } - - test_with_zero(0); - test_with_zero(16); - test_with_zero(17); - } -} diff --git a/primitives/state-machine/src/changes_trie/changes_iterator.rs b/primitives/state-machine/src/changes_trie/changes_iterator.rs deleted file mode 100644 index 9343a226a3aa8..0000000000000 --- a/primitives/state-machine/src/changes_trie/changes_iterator.rs +++ /dev/null @@ -1,748 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Functions + iterator that traverses changes tries and returns all -//! (block, extrinsic) pairs where given key has been changed. - -use crate::{ - changes_trie::{ - input::{ChildIndex, DigestIndex, DigestIndexValue, ExtrinsicIndex, ExtrinsicIndexValue}, - storage::{InMemoryStorage, TrieBackendAdapter}, - surface_iterator::{surface_iterator, SurfaceIterator}, - AnchorBlockId, BlockNumber, ConfigurationRange, RootsStorage, Storage, - }, - proving_backend::ProvingBackendRecorder, - trie_backend_essence::TrieBackendEssence, -}; -use codec::{Codec, Decode, Encode}; -use hash_db::Hasher; -use num_traits::Zero; -use sp_core::storage::PrefixedStorageKey; -use sp_trie::Recorder; -use std::{cell::RefCell, collections::VecDeque}; - -/// Return changes of given key at given blocks range. -/// `max` is the number of best known block. -/// Changes are returned in descending order (i.e. last block comes first). -pub fn key_changes<'a, H: Hasher, Number: BlockNumber>( - config: ConfigurationRange<'a, Number>, - storage: &'a dyn Storage, - begin: Number, - end: &'a AnchorBlockId, - max: Number, - storage_key: Option<&'a PrefixedStorageKey>, - key: &'a [u8], -) -> Result, String> { - // we can't query any roots before root - let max = std::cmp::min(max, end.number.clone()); - - Ok(DrilldownIterator { - essence: DrilldownIteratorEssence { - storage_key, - key, - roots_storage: storage.as_roots_storage(), - storage, - begin: begin.clone(), - end, - config: config.clone(), - surface: surface_iterator(config, max, begin, end.number.clone())?, - - extrinsics: Default::default(), - blocks: Default::default(), - - _hasher: ::std::marker::PhantomData::::default(), - }, - }) -} - -/// Returns proof of changes of given key at given blocks range. -/// `max` is the number of best known block. -pub fn key_changes_proof<'a, H: Hasher, Number: BlockNumber>( - config: ConfigurationRange<'a, Number>, - storage: &dyn Storage, - begin: Number, - end: &AnchorBlockId, - max: Number, - storage_key: Option<&PrefixedStorageKey>, - key: &[u8], -) -> Result>, String> -where - H::Out: Codec, -{ - // we can't query any roots before root - let max = std::cmp::min(max, end.number.clone()); - - let mut iter = ProvingDrilldownIterator { - essence: DrilldownIteratorEssence { - storage_key, - key, - roots_storage: storage.as_roots_storage(), - storage, - begin: begin.clone(), - end, - config: config.clone(), - surface: surface_iterator(config, max, begin, end.number.clone())?, - - extrinsics: Default::default(), - blocks: Default::default(), - - _hasher: ::std::marker::PhantomData::::default(), - }, - proof_recorder: Default::default(), - }; - - // iterate to collect proof - while let Some(item) = iter.next() { - item?; - } - - Ok(iter.extract_proof()) -} - -/// Check key changes proof and return changes of the key at given blocks range. -/// `max` is the number of best known block. -/// Changes are returned in descending order (i.e. last block comes first). -pub fn key_changes_proof_check<'a, H: Hasher, Number: BlockNumber>( - config: ConfigurationRange<'a, Number>, - roots_storage: &dyn RootsStorage, - proof: Vec>, - begin: Number, - end: &AnchorBlockId, - max: Number, - storage_key: Option<&PrefixedStorageKey>, - key: &[u8], -) -> Result, String> -where - H::Out: Encode, -{ - key_changes_proof_check_with_db( - config, - roots_storage, - &InMemoryStorage::with_proof(proof), - begin, - end, - max, - storage_key, - key, - ) -} - -/// Similar to the `key_changes_proof_check` function, but works with prepared proof storage. -pub fn key_changes_proof_check_with_db<'a, H: Hasher, Number: BlockNumber>( - config: ConfigurationRange<'a, Number>, - roots_storage: &dyn RootsStorage, - proof_db: &InMemoryStorage, - begin: Number, - end: &AnchorBlockId, - max: Number, - storage_key: Option<&PrefixedStorageKey>, - key: &[u8], -) -> Result, String> -where - H::Out: Encode, -{ - // we can't query any roots before root - let max = std::cmp::min(max, end.number.clone()); - - DrilldownIterator { - essence: DrilldownIteratorEssence { - storage_key, - key, - roots_storage, - storage: proof_db, - begin: begin.clone(), - end, - config: config.clone(), - surface: surface_iterator(config, max, begin, end.number.clone())?, - - extrinsics: Default::default(), - blocks: Default::default(), - - _hasher: ::std::marker::PhantomData::::default(), - }, - } - .collect() -} - -/// Drilldown iterator - receives 'digest points' from surface iterator and explores -/// every point until extrinsic is found. -pub struct DrilldownIteratorEssence<'a, H, Number> -where - H: Hasher, - Number: BlockNumber, - H::Out: 'a, -{ - storage_key: Option<&'a PrefixedStorageKey>, - key: &'a [u8], - roots_storage: &'a dyn RootsStorage, - storage: &'a dyn Storage, - begin: Number, - end: &'a AnchorBlockId, - config: ConfigurationRange<'a, Number>, - surface: SurfaceIterator<'a, Number>, - - extrinsics: VecDeque<(Number, u32)>, - blocks: VecDeque<(Number, Option)>, - - _hasher: ::std::marker::PhantomData, -} - -impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number> -where - H: Hasher, - Number: BlockNumber, - H::Out: 'a, -{ - pub fn next(&mut self, trie_reader: F) -> Option> - where - F: FnMut(&dyn Storage, H::Out, &[u8]) -> Result>, String>, - { - match self.do_next(trie_reader) { - Ok(Some(res)) => Some(Ok(res)), - Ok(None) => None, - Err(err) => Some(Err(err)), - } - } - - fn do_next(&mut self, mut trie_reader: F) -> Result, String> - where - F: FnMut(&dyn Storage, H::Out, &[u8]) -> Result>, String>, - { - loop { - if let Some((block, extrinsic)) = self.extrinsics.pop_front() { - return Ok(Some((block, extrinsic))) - } - - if let Some((block, level)) = self.blocks.pop_front() { - // not having a changes trie root is an error because: - // we never query roots for future blocks - // AND trie roots for old blocks are known (both on full + light node) - let trie_root = - self.roots_storage.root(&self.end, block.clone())?.ok_or_else(|| { - format!("Changes trie root for block {} is not found", block.clone()) - })?; - let trie_root = if let Some(storage_key) = self.storage_key { - let child_key = - ChildIndex { block: block.clone(), storage_key: storage_key.clone() } - .encode(); - if let Some(trie_root) = trie_reader(self.storage, trie_root, &child_key)? - .and_then(|v| >::decode(&mut &v[..]).ok()) - .map(|v| { - let mut hash = H::Out::default(); - hash.as_mut().copy_from_slice(&v[..]); - hash - }) { - trie_root - } else { - continue - } - } else { - trie_root - }; - - // only return extrinsics for blocks before self.max - // most of blocks will be filtered out before pushing to `self.blocks` - // here we just throwing away changes at digest blocks we're processing - debug_assert!( - block >= self.begin, - "We shall not touch digests earlier than a range' begin" - ); - if block <= self.end.number { - let extrinsics_key = - ExtrinsicIndex { block: block.clone(), key: self.key.to_vec() }.encode(); - let extrinsics = trie_reader(self.storage, trie_root, &extrinsics_key); - if let Some(extrinsics) = extrinsics? { - if let Ok(extrinsics) = ExtrinsicIndexValue::decode(&mut &extrinsics[..]) { - self.extrinsics - .extend(extrinsics.into_iter().rev().map(|e| (block.clone(), e))); - } - } - } - - let blocks_key = - DigestIndex { block: block.clone(), key: self.key.to_vec() }.encode(); - let blocks = trie_reader(self.storage, trie_root, &blocks_key); - if let Some(blocks) = blocks? { - if let Ok(blocks) = >::decode(&mut &blocks[..]) { - // filter level0 blocks here because we tend to use digest blocks, - // AND digest block changes could also include changes for out-of-range - // blocks - let begin = self.begin.clone(); - let end = self.end.number.clone(); - let config = self.config.clone(); - self.blocks.extend( - blocks - .into_iter() - .rev() - .filter(|b| { - level.map(|level| level > 1).unwrap_or(true) || - (*b >= begin && *b <= end) - }) - .map(|b| { - let prev_level = - level.map(|level| Some(level - 1)).unwrap_or_else(|| { - Some( - config - .config - .digest_level_at_block( - config.zero.clone(), - b.clone(), - ) - .map(|(level, _, _)| level) - .unwrap_or_else(|| Zero::zero()), - ) - }); - (b, prev_level) - }), - ); - } - } - - continue - } - - match self.surface.next() { - Some(Ok(block)) => self.blocks.push_back(block), - Some(Err(err)) => return Err(err), - None => return Ok(None), - } - } - } -} - -/// Exploring drilldown operator. -pub struct DrilldownIterator<'a, H, Number> -where - Number: BlockNumber, - H: Hasher, - H::Out: 'a, -{ - essence: DrilldownIteratorEssence<'a, H, Number>, -} - -impl<'a, H: Hasher, Number: BlockNumber> Iterator for DrilldownIterator<'a, H, Number> -where - H::Out: Encode, -{ - type Item = Result<(Number, u32), String>; - - fn next(&mut self) -> Option { - self.essence.next(|storage, root, key| { - TrieBackendEssence::<_, H>::new(TrieBackendAdapter::new(storage), root).storage(key) - }) - } -} - -/// Proving drilldown iterator. -struct ProvingDrilldownIterator<'a, H, Number> -where - Number: BlockNumber, - H: Hasher, - H::Out: 'a, -{ - essence: DrilldownIteratorEssence<'a, H, Number>, - proof_recorder: RefCell>, -} - -impl<'a, H, Number> ProvingDrilldownIterator<'a, H, Number> -where - Number: BlockNumber, - H: Hasher, - H::Out: 'a, -{ - /// Consume the iterator, extracting the gathered proof in lexicographical order - /// by value. - pub fn extract_proof(self) -> Vec> { - self.proof_recorder - .into_inner() - .drain() - .into_iter() - .map(|n| n.data.to_vec()) - .collect() - } -} - -impl<'a, H, Number> Iterator for ProvingDrilldownIterator<'a, H, Number> -where - Number: BlockNumber, - H: Hasher, - H::Out: 'a + Codec, -{ - type Item = Result<(Number, u32), String>; - - fn next(&mut self) -> Option { - let proof_recorder = &mut *self - .proof_recorder - .try_borrow_mut() - .expect("only fails when already borrowed; storage() is non-reentrant; qed"); - self.essence.next(|storage, root, key| { - ProvingBackendRecorder::<_, H> { - backend: &TrieBackendEssence::new(TrieBackendAdapter::new(storage), root), - proof_recorder, - } - .storage(key) - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::changes_trie::{input::InputPair, storage::InMemoryStorage, Configuration}; - use sp_runtime::traits::BlakeTwo256; - use std::iter::FromIterator; - - fn child_key() -> PrefixedStorageKey { - let child_info = sp_core::storage::ChildInfo::new_default(&b"1"[..]); - child_info.prefixed_storage_key() - } - - fn prepare_for_drilldown() -> (Configuration, InMemoryStorage) { - let config = Configuration { digest_interval: 4, digest_levels: 2 }; - let backend = InMemoryStorage::with_inputs( - vec![ - // digest: 1..4 => [(3, 0)] - (1, vec![]), - (2, vec![]), - ( - 3, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: 3, key: vec![42] }, - vec![0], - )], - ), - (4, vec![InputPair::DigestIndex(DigestIndex { block: 4, key: vec![42] }, vec![3])]), - // digest: 5..8 => [(6, 3), (8, 1+2)] - (5, vec![]), - ( - 6, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: 6, key: vec![42] }, - vec![3], - )], - ), - (7, vec![]), - ( - 8, - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: 8, key: vec![42] }, - vec![1, 2], - ), - InputPair::DigestIndex(DigestIndex { block: 8, key: vec![42] }, vec![6]), - ], - ), - // digest: 9..12 => [] - (9, vec![]), - (10, vec![]), - (11, vec![]), - (12, vec![]), - // digest: 0..16 => [4, 8] - (13, vec![]), - (14, vec![]), - (15, vec![]), - ( - 16, - vec![InputPair::DigestIndex( - DigestIndex { block: 16, key: vec![42] }, - vec![4, 8], - )], - ), - ], - vec![( - child_key(), - vec![ - ( - 1, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: 1, key: vec![42] }, - vec![0], - )], - ), - ( - 2, - vec![InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: 2, key: vec![42] }, - vec![3], - )], - ), - ( - 16, - vec![ - InputPair::ExtrinsicIndex( - ExtrinsicIndex { block: 16, key: vec![42] }, - vec![5], - ), - InputPair::DigestIndex( - DigestIndex { block: 16, key: vec![42] }, - vec![2], - ), - ], - ), - ], - )], - ); - - (config, backend) - } - - fn configuration_range<'a>( - config: &'a Configuration, - zero: u64, - ) -> ConfigurationRange<'a, u64> { - ConfigurationRange { config, zero, end: None } - } - - #[test] - fn drilldown_iterator_works() { - let (config, storage) = prepare_for_drilldown(); - let drilldown_result = key_changes::( - configuration_range(&config, 0), - &storage, - 1, - &AnchorBlockId { hash: Default::default(), number: 16 }, - 16, - None, - &[42], - ) - .and_then(Result::from_iter); - assert_eq!(drilldown_result, Ok(vec![(8, 2), (8, 1), (6, 3), (3, 0)])); - - let drilldown_result = key_changes::( - configuration_range(&config, 0), - &storage, - 1, - &AnchorBlockId { hash: Default::default(), number: 2 }, - 4, - None, - &[42], - ) - .and_then(Result::from_iter); - assert_eq!(drilldown_result, Ok(vec![])); - - let drilldown_result = key_changes::( - configuration_range(&config, 0), - &storage, - 1, - &AnchorBlockId { hash: Default::default(), number: 3 }, - 4, - None, - &[42], - ) - .and_then(Result::from_iter); - assert_eq!(drilldown_result, Ok(vec![(3, 0)])); - - let drilldown_result = key_changes::( - configuration_range(&config, 0), - &storage, - 1, - &AnchorBlockId { hash: Default::default(), number: 7 }, - 7, - None, - &[42], - ) - .and_then(Result::from_iter); - assert_eq!(drilldown_result, Ok(vec![(6, 3), (3, 0)])); - - let drilldown_result = key_changes::( - configuration_range(&config, 0), - &storage, - 7, - &AnchorBlockId { hash: Default::default(), number: 8 }, - 8, - None, - &[42], - ) - .and_then(Result::from_iter); - assert_eq!(drilldown_result, Ok(vec![(8, 2), (8, 1)])); - - let drilldown_result = key_changes::( - configuration_range(&config, 0), - &storage, - 5, - &AnchorBlockId { hash: Default::default(), number: 7 }, - 8, - None, - &[42], - ) - .and_then(Result::from_iter); - assert_eq!(drilldown_result, Ok(vec![(6, 3)])); - } - - #[test] - fn drilldown_iterator_fails_when_storage_fails() { - let (config, storage) = prepare_for_drilldown(); - storage.clear_storage(); - - assert!(key_changes::( - configuration_range(&config, 0), - &storage, - 1, - &AnchorBlockId { hash: Default::default(), number: 100 }, - 1000, - None, - &[42], - ) - .and_then(|i| i.collect::, _>>()) - .is_err()); - - assert!(key_changes::( - configuration_range(&config, 0), - &storage, - 1, - &AnchorBlockId { hash: Default::default(), number: 100 }, - 1000, - Some(&child_key()), - &[42], - ) - .and_then(|i| i.collect::, _>>()) - .is_err()); - } - - #[test] - fn drilldown_iterator_fails_when_range_is_invalid() { - let (config, storage) = prepare_for_drilldown(); - assert!(key_changes::( - configuration_range(&config, 0), - &storage, - 1, - &AnchorBlockId { hash: Default::default(), number: 100 }, - 50, - None, - &[42], - ) - .is_err()); - assert!(key_changes::( - configuration_range(&config, 0), - &storage, - 20, - &AnchorBlockId { hash: Default::default(), number: 10 }, - 100, - None, - &[42], - ) - .is_err()); - } - - #[test] - fn proving_drilldown_iterator_works() { - // happens on remote full node: - - // create drilldown iterator that records all trie nodes during drilldown - let (remote_config, remote_storage) = prepare_for_drilldown(); - let remote_proof = key_changes_proof::( - configuration_range(&remote_config, 0), - &remote_storage, - 1, - &AnchorBlockId { hash: Default::default(), number: 16 }, - 16, - None, - &[42], - ) - .unwrap(); - - let (remote_config, remote_storage) = prepare_for_drilldown(); - let remote_proof_child = key_changes_proof::( - configuration_range(&remote_config, 0), - &remote_storage, - 1, - &AnchorBlockId { hash: Default::default(), number: 16 }, - 16, - Some(&child_key()), - &[42], - ) - .unwrap(); - - // happens on local light node: - - // create drilldown iterator that works the same, but only depends on trie - let (local_config, local_storage) = prepare_for_drilldown(); - local_storage.clear_storage(); - let local_result = key_changes_proof_check::( - configuration_range(&local_config, 0), - &local_storage, - remote_proof, - 1, - &AnchorBlockId { hash: Default::default(), number: 16 }, - 16, - None, - &[42], - ); - - let (local_config, local_storage) = prepare_for_drilldown(); - local_storage.clear_storage(); - let local_result_child = key_changes_proof_check::( - configuration_range(&local_config, 0), - &local_storage, - remote_proof_child, - 1, - &AnchorBlockId { hash: Default::default(), number: 16 }, - 16, - Some(&child_key()), - &[42], - ); - - // check that drilldown result is the same as if it was happening at the full node - assert_eq!(local_result, Ok(vec![(8, 2), (8, 1), (6, 3), (3, 0)])); - assert_eq!(local_result_child, Ok(vec![(16, 5), (2, 3)])); - } - - #[test] - fn drilldown_iterator_works_with_skewed_digest() { - let config = Configuration { digest_interval: 4, digest_levels: 3 }; - let mut config_range = configuration_range(&config, 0); - config_range.end = Some(91); - - // when 4^3 deactivates at block 91: - // last L3 digest has been created at block#64 - // skewed digest covers: - // L2 digests at blocks: 80 - // L1 digests at blocks: 84, 88 - // regular blocks: 89, 90, 91 - let mut input = (1u64..92u64).map(|b| (b, vec![])).collect::>(); - // changed at block#63 and covered by L3 digest at block#64 - input[63 - 1] - .1 - .push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 63, key: vec![42] }, vec![0])); - input[64 - 1] - .1 - .push(InputPair::DigestIndex(DigestIndex { block: 64, key: vec![42] }, vec![63])); - // changed at block#79 and covered by L2 digest at block#80 + skewed digest at block#91 - input[79 - 1] - .1 - .push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 79, key: vec![42] }, vec![1])); - input[80 - 1] - .1 - .push(InputPair::DigestIndex(DigestIndex { block: 80, key: vec![42] }, vec![79])); - input[91 - 1] - .1 - .push(InputPair::DigestIndex(DigestIndex { block: 91, key: vec![42] }, vec![80])); - let storage = InMemoryStorage::with_inputs(input, vec![]); - - let drilldown_result = key_changes::( - config_range, - &storage, - 1, - &AnchorBlockId { hash: Default::default(), number: 91 }, - 100_000u64, - None, - &[42], - ) - .and_then(Result::from_iter); - assert_eq!(drilldown_result, Ok(vec![(79, 1), (63, 0)])); - } -} diff --git a/primitives/state-machine/src/changes_trie/input.rs b/primitives/state-machine/src/changes_trie/input.rs deleted file mode 100644 index af0a423e57267..0000000000000 --- a/primitives/state-machine/src/changes_trie/input.rs +++ /dev/null @@ -1,207 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Different types of changes trie input pairs. - -use crate::{changes_trie::BlockNumber, StorageKey, StorageValue}; -use codec::{Decode, Encode, Error, Input, Output}; -use sp_core::storage::PrefixedStorageKey; - -/// Key of { changed key => set of extrinsic indices } mapping. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ExtrinsicIndex { - /// Block at which this key has been inserted in the trie. - pub block: Number, - /// Storage key this node is responsible for. - pub key: StorageKey, -} - -/// Value of { changed key => set of extrinsic indices } mapping. -pub type ExtrinsicIndexValue = Vec; - -/// Key of { changed key => block/digest block numbers } mapping. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct DigestIndex { - /// Block at which this key has been inserted in the trie. - pub block: Number, - /// Storage key this node is responsible for. - pub key: StorageKey, -} - -/// Key of { childtrie key => Childchange trie } mapping. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct ChildIndex { - /// Block at which this key has been inserted in the trie. - pub block: Number, - /// Storage key this node is responsible for. - pub storage_key: PrefixedStorageKey, -} - -/// Value of { changed key => block/digest block numbers } mapping. -pub type DigestIndexValue = Vec; - -/// Value of { changed key => block/digest block numbers } mapping. -/// That is the root of the child change trie. -pub type ChildIndexValue = Vec; - -/// Single input pair of changes trie. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum InputPair { - /// Element of { key => set of extrinsics where key has been changed } element mapping. - ExtrinsicIndex(ExtrinsicIndex, ExtrinsicIndexValue), - /// Element of { key => set of blocks/digest blocks where key has been changed } element - /// mapping. - DigestIndex(DigestIndex, DigestIndexValue), - /// Element of { childtrie key => Childchange trie } where key has been changed } element - /// mapping. - ChildIndex(ChildIndex, ChildIndexValue), -} - -/// Single input key of changes trie. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum InputKey { - /// Key of { key => set of extrinsics where key has been changed } element mapping. - ExtrinsicIndex(ExtrinsicIndex), - /// Key of { key => set of blocks/digest blocks where key has been changed } element mapping. - DigestIndex(DigestIndex), - /// Key of { childtrie key => Childchange trie } where key has been changed } element mapping. - ChildIndex(ChildIndex), -} - -impl InputPair { - /// Extract storage key that this pair corresponds to. - pub fn key(&self) -> Option<&[u8]> { - match *self { - InputPair::ExtrinsicIndex(ref key, _) => Some(&key.key), - InputPair::DigestIndex(ref key, _) => Some(&key.key), - InputPair::ChildIndex(_, _) => None, - } - } -} - -impl Into<(StorageKey, StorageValue)> for InputPair { - fn into(self) -> (StorageKey, StorageValue) { - match self { - InputPair::ExtrinsicIndex(key, value) => (key.encode(), value.encode()), - InputPair::DigestIndex(key, value) => (key.encode(), value.encode()), - InputPair::ChildIndex(key, value) => (key.encode(), value.encode()), - } - } -} - -impl Into> for InputPair { - fn into(self) -> InputKey { - match self { - InputPair::ExtrinsicIndex(key, _) => InputKey::ExtrinsicIndex(key), - InputPair::DigestIndex(key, _) => InputKey::DigestIndex(key), - InputPair::ChildIndex(key, _) => InputKey::ChildIndex(key), - } - } -} - -impl ExtrinsicIndex { - pub fn key_neutral_prefix(block: Number) -> Vec { - let mut prefix = vec![1]; - prefix.extend(block.encode()); - prefix - } -} - -impl Encode for ExtrinsicIndex { - fn encode_to(&self, dest: &mut W) { - dest.push_byte(1); - self.block.encode_to(dest); - self.key.encode_to(dest); - } -} - -impl codec::EncodeLike for ExtrinsicIndex {} - -impl DigestIndex { - pub fn key_neutral_prefix(block: Number) -> Vec { - let mut prefix = vec![2]; - prefix.extend(block.encode()); - prefix - } -} - -impl Encode for DigestIndex { - fn encode_to(&self, dest: &mut W) { - dest.push_byte(2); - self.block.encode_to(dest); - self.key.encode_to(dest); - } -} - -impl ChildIndex { - pub fn key_neutral_prefix(block: Number) -> Vec { - let mut prefix = vec![3]; - prefix.extend(block.encode()); - prefix - } -} - -impl Encode for ChildIndex { - fn encode_to(&self, dest: &mut W) { - dest.push_byte(3); - self.block.encode_to(dest); - self.storage_key.encode_to(dest); - } -} - -impl codec::EncodeLike for DigestIndex {} - -impl Decode for InputKey { - fn decode(input: &mut I) -> Result { - match input.read_byte()? { - 1 => Ok(InputKey::ExtrinsicIndex(ExtrinsicIndex { - block: Decode::decode(input)?, - key: Decode::decode(input)?, - })), - 2 => Ok(InputKey::DigestIndex(DigestIndex { - block: Decode::decode(input)?, - key: Decode::decode(input)?, - })), - 3 => Ok(InputKey::ChildIndex(ChildIndex { - block: Decode::decode(input)?, - storage_key: PrefixedStorageKey::new(Decode::decode(input)?), - })), - _ => Err("Invalid input key variant".into()), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn extrinsic_index_serialized_and_deserialized() { - let original = ExtrinsicIndex { block: 777u64, key: vec![42] }; - let serialized = original.encode(); - let deserialized: InputKey = Decode::decode(&mut &serialized[..]).unwrap(); - assert_eq!(InputKey::ExtrinsicIndex(original), deserialized); - } - - #[test] - fn digest_index_serialized_and_deserialized() { - let original = DigestIndex { block: 777u64, key: vec![42] }; - let serialized = original.encode(); - let deserialized: InputKey = Decode::decode(&mut &serialized[..]).unwrap(); - assert_eq!(InputKey::DigestIndex(original), deserialized); - } -} diff --git a/primitives/state-machine/src/changes_trie/mod.rs b/primitives/state-machine/src/changes_trie/mod.rs deleted file mode 100644 index 40148095247dd..0000000000000 --- a/primitives/state-machine/src/changes_trie/mod.rs +++ /dev/null @@ -1,428 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Changes trie related structures and functions. -//! -//! Changes trie is a trie built of { storage key => extrinsics } pairs -//! at the end of each block. For every changed storage key it contains -//! a pair, mapping key to the set of extrinsics where it has been changed. -//! -//! Optionally, every N blocks, additional level1-digest nodes are appended -//! to the changes trie, containing pairs { storage key => blocks }. For every -//! storage key that has been changed in PREVIOUS N-1 blocks (except for genesis -//! block) it contains a pair, mapping this key to the set of blocks where it -//! has been changed. -//! -//! Optionally, every N^digest_level (where digest_level > 1) blocks, additional -//! digest_level digest is created. It is built out of pairs { storage key => digest -//! block }, containing entries for every storage key that has been changed in -//! the last N*digest_level-1 blocks (except for genesis block), mapping these keys -//! to the set of lower-level digest blocks. -//! -//! Changes trie configuration could change within a time. The range of blocks, where -//! configuration has been active, is given by two blocks: zero and end. Zero block is -//! the block where configuration has been set. But the first changes trie that uses -//! this configuration will be built at the block zero+1. If configuration deactivates -//! at some block, this will be the end block of the configuration. It is also the -//! zero block of the next configuration. -//! -//! If configuration has the end block, it also means that 'skewed digest' has/should -//! been built at that block. If this is the block where max-level digest should have -//! been created, than it is simply max-level digest of this configuration. Otherwise, -//! it is the digest that covers all blocks since last max-level digest block was -//! created. -//! -//! Changes trie only contains the top level storage changes. Sub-level changes -//! are propagated through its storage root on the top level storage. - -mod build; -mod build_cache; -mod build_iterator; -mod changes_iterator; -mod input; -mod prune; -mod storage; -mod surface_iterator; - -pub use self::{ - build_cache::{BuildCache, CacheAction, CachedBuildData}, - changes_iterator::{ - key_changes, key_changes_proof, key_changes_proof_check, key_changes_proof_check_with_db, - }, - prune::prune, - storage::InMemoryStorage, -}; - -use crate::{ - backend::Backend, - changes_trie::{ - build::prepare_input, - build_cache::{IncompleteCacheAction, IncompleteCachedBuildData}, - }, - overlayed_changes::OverlayedChanges, - StorageKey, -}; -use codec::{Decode, Encode}; -use hash_db::{Hasher, Prefix}; -use num_traits::{One, Zero}; -use sp_core::{self, storage::PrefixedStorageKey}; -use sp_trie::{trie_types::TrieDBMut, DBValue, MemoryDB, TrieMut}; -use std::{ - collections::{HashMap, HashSet}, - convert::TryInto, -}; - -/// Requirements for block number that can be used with changes tries. -pub trait BlockNumber: - Send - + Sync - + 'static - + std::fmt::Display - + Clone - + From - + TryInto - + One - + Zero - + PartialEq - + Ord - + std::hash::Hash - + std::ops::Add - + ::std::ops::Sub - + std::ops::Mul - + ::std::ops::Div - + std::ops::Rem - + std::ops::AddAssign - + num_traits::CheckedMul - + num_traits::CheckedSub - + Decode - + Encode -{ -} - -impl BlockNumber for T where - T: Send - + Sync - + 'static - + std::fmt::Display - + Clone - + From - + TryInto - + One - + Zero - + PartialEq - + Ord - + std::hash::Hash - + std::ops::Add - + ::std::ops::Sub - + std::ops::Mul - + ::std::ops::Div - + std::ops::Rem - + std::ops::AddAssign - + num_traits::CheckedMul - + num_traits::CheckedSub - + Decode - + Encode -{ -} - -/// Block identifier that could be used to determine fork of this block. -#[derive(Debug)] -pub struct AnchorBlockId { - /// Hash of this block. - pub hash: Hash, - /// Number of this block. - pub number: Number, -} - -/// Changes tries state at some block. -pub struct State<'a, H, Number> { - /// Configuration that is active at given block. - pub config: Configuration, - /// Configuration activation block number. Zero if it is the first configuration on the chain, - /// or number of the block that have emit NewConfiguration signal (thus activating - /// configuration starting from the **next** block). - pub zero: Number, - /// Underlying changes tries storage reference. - pub storage: &'a dyn Storage, -} - -/// Changes trie storage. Provides access to trie roots and trie nodes. -pub trait RootsStorage: Send + Sync { - /// Resolve hash of the block into anchor. - fn build_anchor(&self, hash: H::Out) -> Result, String>; - /// Get changes trie root for the block with given number which is an ancestor (or the block - /// itself) of the anchor_block (i.e. anchor_block.number >= block). - fn root( - &self, - anchor: &AnchorBlockId, - block: Number, - ) -> Result, String>; -} - -/// Changes trie storage. Provides access to trie roots and trie nodes. -pub trait Storage: RootsStorage { - /// Casts from self reference to RootsStorage reference. - fn as_roots_storage(&self) -> &dyn RootsStorage; - /// Execute given functor with cached entry for given trie root. - /// Returns true if the functor has been called (cache entry exists) and false otherwise. - fn with_cached_changed_keys( - &self, - root: &H::Out, - functor: &mut dyn FnMut(&HashMap, HashSet>), - ) -> bool; - /// Get a trie node. - fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String>; -} - -/// Changes trie storage -> trie backend essence adapter. -pub struct TrieBackendStorageAdapter<'a, H: Hasher, Number: BlockNumber>( - pub &'a dyn Storage, -); - -impl<'a, H: Hasher, N: BlockNumber> crate::TrieBackendStorage - for TrieBackendStorageAdapter<'a, H, N> -{ - type Overlay = sp_trie::MemoryDB; - - fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String> { - self.0.get(key, prefix) - } -} - -/// Changes trie configuration. -pub type Configuration = sp_core::ChangesTrieConfiguration; - -/// Blocks range where configuration has been constant. -#[derive(Clone)] -pub struct ConfigurationRange<'a, N> { - /// Active configuration. - pub config: &'a Configuration, - /// Zero block of this configuration. The configuration is active starting from the next block. - pub zero: N, - /// End block of this configuration. It is the last block where configuration has been active. - pub end: Option, -} - -impl<'a, H, Number> State<'a, H, Number> { - /// Create state with given config and storage. - pub fn new(config: Configuration, zero: Number, storage: &'a dyn Storage) -> Self { - Self { config, zero, storage } - } -} - -impl<'a, H, Number: Clone> Clone for State<'a, H, Number> { - fn clone(&self) -> Self { - State { config: self.config.clone(), zero: self.zero.clone(), storage: self.storage } - } -} - -/// Create state where changes tries are disabled. -pub fn disabled_state<'a, H, Number>() -> Option> { - None -} - -/// Compute the changes trie root and transaction for given block. -/// Returns Err(()) if unknown `parent_hash` has been passed. -/// Returns Ok(None) if there's no data to perform computation. -/// Panics if background storage returns an error OR if insert to MemoryDB fails. -pub fn build_changes_trie<'a, B: Backend, H: Hasher, Number: BlockNumber>( - backend: &B, - state: Option<&'a State<'a, H, Number>>, - changes: &OverlayedChanges, - parent_hash: H::Out, - panic_on_storage_error: bool, -) -> Result, H::Out, CacheAction)>, ()> -where - H::Out: Ord + 'static + Encode, -{ - /// Panics when `res.is_err() && panic`, otherwise it returns `Err(())` on an error. - fn maybe_panic( - res: std::result::Result, - panic: bool, - ) -> std::result::Result { - res.map(Ok).unwrap_or_else(|e| { - if panic { - panic!( - "changes trie: storage access is not allowed to fail within runtime: {:?}", - e - ) - } else { - Err(()) - } - }) - } - - // when storage isn't provided, changes tries aren't created - let state = match state { - Some(state) => state, - None => return Ok(None), - }; - - // build_anchor error should not be considered fatal - let parent = state.storage.build_anchor(parent_hash).map_err(|_| ())?; - let block = parent.number.clone() + One::one(); - - // prepare configuration range - we already know zero block. Current block may be the end block - // if configuration has been changed in this block - let is_config_changed = - match changes.storage(sp_core::storage::well_known_keys::CHANGES_TRIE_CONFIG) { - Some(Some(new_config)) => new_config != &state.config.encode()[..], - Some(None) => true, - None => false, - }; - let config_range = ConfigurationRange { - config: &state.config, - zero: state.zero.clone(), - end: if is_config_changed { Some(block.clone()) } else { None }, - }; - - // storage errors are considered fatal (similar to situations when runtime fetches values from - // storage) - let (input_pairs, child_input_pairs, digest_input_blocks) = maybe_panic( - prepare_input::( - backend, - state.storage, - config_range.clone(), - changes, - &parent, - ), - panic_on_storage_error, - )?; - - // prepare cached data - let mut cache_action = prepare_cached_build_data(config_range, block.clone()); - let needs_changed_keys = cache_action.collects_changed_keys(); - cache_action = cache_action.set_digest_input_blocks(digest_input_blocks); - - let mut mdb = MemoryDB::default(); - let mut child_roots = Vec::with_capacity(child_input_pairs.len()); - for (child_index, input_pairs) in child_input_pairs { - let mut not_empty = false; - let mut root = Default::default(); - { - let mut trie = TrieDBMut::::new(&mut mdb, &mut root); - let mut storage_changed_keys = HashSet::new(); - for input_pair in input_pairs { - if needs_changed_keys { - if let Some(key) = input_pair.key() { - storage_changed_keys.insert(key.to_vec()); - } - } - - let (key, value) = input_pair.into(); - not_empty = true; - maybe_panic(trie.insert(&key, &value), panic_on_storage_error)?; - } - - cache_action = - cache_action.insert(Some(child_index.storage_key.clone()), storage_changed_keys); - } - if not_empty { - child_roots.push(input::InputPair::ChildIndex(child_index, root.as_ref().to_vec())); - } - } - let mut root = Default::default(); - { - let mut trie = TrieDBMut::::new(&mut mdb, &mut root); - for (key, value) in child_roots.into_iter().map(Into::into) { - maybe_panic(trie.insert(&key, &value), panic_on_storage_error)?; - } - - let mut storage_changed_keys = HashSet::new(); - for input_pair in input_pairs { - if needs_changed_keys { - if let Some(key) = input_pair.key() { - storage_changed_keys.insert(key.to_vec()); - } - } - - let (key, value) = input_pair.into(); - maybe_panic(trie.insert(&key, &value), panic_on_storage_error)?; - } - - cache_action = cache_action.insert(None, storage_changed_keys); - } - - let cache_action = cache_action.complete(block, &root); - Ok(Some((mdb, root, cache_action))) -} - -/// Prepare empty cached build data for given block. -fn prepare_cached_build_data( - config: ConfigurationRange, - block: Number, -) -> IncompleteCacheAction { - // when digests are not enabled in configuration, we do not need to cache anything - // because it'll never be used again for building other tries - // => let's clear the cache - if !config.config.is_digest_build_enabled() { - return IncompleteCacheAction::Clear - } - - // when this is the last block where current configuration is active - // => let's clear the cache - if config.end.as_ref() == Some(&block) { - return IncompleteCacheAction::Clear - } - - // we do not need to cache anything when top-level digest trie is created, because - // it'll never be used again for building other tries - // => let's clear the cache - match config.config.digest_level_at_block(config.zero.clone(), block) { - Some((digest_level, _, _)) if digest_level == config.config.digest_levels => - IncompleteCacheAction::Clear, - _ => IncompleteCacheAction::CacheBuildData(IncompleteCachedBuildData::new()), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn cache_is_cleared_when_digests_are_disabled() { - let config = Configuration { digest_interval: 0, digest_levels: 0 }; - let config_range = ConfigurationRange { zero: 0, end: None, config: &config }; - assert_eq!(prepare_cached_build_data(config_range, 8u32), IncompleteCacheAction::Clear); - } - - #[test] - fn build_data_is_cached_when_digests_are_enabled() { - let config = Configuration { digest_interval: 8, digest_levels: 2 }; - let config_range = ConfigurationRange { zero: 0, end: None, config: &config }; - assert!(prepare_cached_build_data(config_range.clone(), 4u32).collects_changed_keys()); - assert!(prepare_cached_build_data(config_range.clone(), 7u32).collects_changed_keys()); - assert!(prepare_cached_build_data(config_range, 8u32).collects_changed_keys()); - } - - #[test] - fn cache_is_cleared_when_digests_are_enabled_and_top_level_digest_is_built() { - let config = Configuration { digest_interval: 8, digest_levels: 2 }; - let config_range = ConfigurationRange { zero: 0, end: None, config: &config }; - assert_eq!(prepare_cached_build_data(config_range, 64u32), IncompleteCacheAction::Clear); - } - - #[test] - fn cache_is_cleared_when_end_block_of_configuration_is_built() { - let config = Configuration { digest_interval: 8, digest_levels: 2 }; - let config_range = ConfigurationRange { zero: 0, end: Some(4u32), config: &config }; - assert_eq!( - prepare_cached_build_data(config_range.clone(), 4u32), - IncompleteCacheAction::Clear - ); - } -} diff --git a/primitives/state-machine/src/changes_trie/prune.rs b/primitives/state-machine/src/changes_trie/prune.rs deleted file mode 100644 index 2ca540562b47f..0000000000000 --- a/primitives/state-machine/src/changes_trie/prune.rs +++ /dev/null @@ -1,204 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Changes trie pruning-related functions. - -use crate::{ - changes_trie::{ - input::{ChildIndex, InputKey}, - storage::TrieBackendAdapter, - AnchorBlockId, BlockNumber, Storage, - }, - proving_backend::ProvingBackendRecorder, - trie_backend_essence::TrieBackendEssence, -}; -use codec::{Codec, Decode}; -use hash_db::Hasher; -use log::warn; -use num_traits::One; -use sp_trie::Recorder; - -/// Prune obsolete changes tries. Pruning happens at the same block, where highest -/// level digest is created. Pruning guarantees to save changes tries for last -/// `min_blocks_to_keep` blocks. We only prune changes tries at `max_digest_interval` -/// ranges. -pub fn prune( - storage: &dyn Storage, - first: Number, - last: Number, - current_block: &AnchorBlockId, - mut remove_trie_node: F, -) where - H::Out: Codec, -{ - // delete changes trie for every block in range - let mut block = first; - loop { - if block >= last.clone() + One::one() { - break - } - - let prev_block = block.clone(); - block += One::one(); - - let block = prev_block; - let root = match storage.root(current_block, block.clone()) { - Ok(Some(root)) => root, - Ok(None) => continue, - Err(error) => { - // try to delete other tries - warn!(target: "trie", "Failed to read changes trie root from DB: {}", error); - continue - }, - }; - let children_roots = { - let trie_storage = TrieBackendEssence::<_, H>::new( - crate::changes_trie::TrieBackendStorageAdapter(storage), - root, - ); - let child_prefix = ChildIndex::key_neutral_prefix(block.clone()); - let mut children_roots = Vec::new(); - trie_storage.for_key_values_with_prefix(&child_prefix, |mut key, mut value| { - if let Ok(InputKey::ChildIndex::(_trie_key)) = Decode::decode(&mut key) { - if let Ok(value) = >::decode(&mut value) { - let mut trie_root = ::Out::default(); - trie_root.as_mut().copy_from_slice(&value[..]); - children_roots.push(trie_root); - } - } - }); - - children_roots - }; - for root in children_roots.into_iter() { - prune_trie(storage, root, &mut remove_trie_node); - } - - prune_trie(storage, root, &mut remove_trie_node); - } -} - -// Prune a trie. -fn prune_trie( - storage: &dyn Storage, - root: H::Out, - remove_trie_node: &mut F, -) where - H::Out: Codec, -{ - // enumerate all changes trie' keys, recording all nodes that have been 'touched' - // (effectively - all changes trie nodes) - let mut proof_recorder: Recorder = Default::default(); - { - let mut trie = ProvingBackendRecorder::<_, H> { - backend: &TrieBackendEssence::new(TrieBackendAdapter::new(storage), root), - proof_recorder: &mut proof_recorder, - }; - trie.record_all_keys(); - } - - // all nodes of this changes trie should be pruned - remove_trie_node(root); - for node in proof_recorder.drain().into_iter().map(|n| n.hash) { - remove_trie_node(node); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{backend::insert_into_memory_db, changes_trie::storage::InMemoryStorage}; - use codec::Encode; - use sp_core::H256; - use sp_runtime::traits::BlakeTwo256; - use sp_trie::MemoryDB; - use std::collections::HashSet; - - fn prune_by_collect( - storage: &dyn Storage, - first: u64, - last: u64, - current_block: u64, - ) -> HashSet { - let mut pruned_trie_nodes = HashSet::new(); - let anchor = AnchorBlockId { hash: Default::default(), number: current_block }; - prune(storage, first, last, &anchor, |node| { - pruned_trie_nodes.insert(node); - }); - pruned_trie_nodes - } - - #[test] - fn prune_works() { - fn prepare_storage() -> InMemoryStorage { - let child_info = sp_core::storage::ChildInfo::new_default(&b"1"[..]); - let child_key = - ChildIndex { block: 67u64, storage_key: child_info.prefixed_storage_key() } - .encode(); - let mut mdb1 = MemoryDB::::default(); - let root1 = - insert_into_memory_db::(&mut mdb1, vec![(vec![10], vec![20])]) - .unwrap(); - let mut mdb2 = MemoryDB::::default(); - let root2 = insert_into_memory_db::( - &mut mdb2, - vec![(vec![11], vec![21]), (vec![12], vec![22])], - ) - .unwrap(); - let mut mdb3 = MemoryDB::::default(); - let ch_root3 = - insert_into_memory_db::(&mut mdb3, vec![(vec![110], vec![120])]) - .unwrap(); - let root3 = insert_into_memory_db::( - &mut mdb3, - vec![ - (vec![13], vec![23]), - (vec![14], vec![24]), - (child_key, ch_root3.as_ref().encode()), - ], - ) - .unwrap(); - let mut mdb4 = MemoryDB::::default(); - let root4 = - insert_into_memory_db::(&mut mdb4, vec![(vec![15], vec![25])]) - .unwrap(); - let storage = InMemoryStorage::new(); - storage.insert(65, root1, mdb1); - storage.insert(66, root2, mdb2); - storage.insert(67, root3, mdb3); - storage.insert(68, root4, mdb4); - - storage - } - - let storage = prepare_storage(); - assert!(prune_by_collect(&storage, 20, 30, 90).is_empty()); - assert!(!storage.into_mdb().drain().is_empty()); - - let storage = prepare_storage(); - let prune60_65 = prune_by_collect(&storage, 60, 65, 90); - assert!(!prune60_65.is_empty()); - storage.remove_from_storage(&prune60_65); - assert!(!storage.into_mdb().drain().is_empty()); - - let storage = prepare_storage(); - let prune60_70 = prune_by_collect(&storage, 60, 70, 90); - assert!(!prune60_70.is_empty()); - storage.remove_from_storage(&prune60_70); - assert!(storage.into_mdb().drain().is_empty()); - } -} diff --git a/primitives/state-machine/src/changes_trie/storage.rs b/primitives/state-machine/src/changes_trie/storage.rs deleted file mode 100644 index bd5e3a32b5657..0000000000000 --- a/primitives/state-machine/src/changes_trie/storage.rs +++ /dev/null @@ -1,214 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Changes trie storage utilities. - -use crate::{ - changes_trie::{AnchorBlockId, BlockNumber, BuildCache, RootsStorage, Storage}, - trie_backend_essence::TrieBackendStorage, - StorageKey, -}; -use hash_db::{Hasher, Prefix, EMPTY_PREFIX}; -use parking_lot::RwLock; -use sp_core::storage::PrefixedStorageKey; -use sp_trie::{DBValue, MemoryDB}; -use std::collections::{BTreeMap, HashMap, HashSet}; - -#[cfg(test)] -use crate::backend::insert_into_memory_db; -#[cfg(test)] -use crate::changes_trie::input::{ChildIndex, InputPair}; - -/// In-memory implementation of changes trie storage. -pub struct InMemoryStorage { - data: RwLock>, - cache: BuildCache, -} - -/// Adapter for using changes trie storage as a TrieBackendEssence' storage. -pub struct TrieBackendAdapter<'a, H: Hasher, Number: BlockNumber> { - storage: &'a dyn Storage, - _hasher: std::marker::PhantomData<(H, Number)>, -} - -struct InMemoryStorageData { - roots: BTreeMap, - mdb: MemoryDB, -} - -impl InMemoryStorage { - /// Creates storage from given in-memory database. - pub fn with_db(mdb: MemoryDB) -> Self { - Self { - data: RwLock::new(InMemoryStorageData { roots: BTreeMap::new(), mdb }), - cache: BuildCache::new(), - } - } - - /// Creates storage with empty database. - pub fn new() -> Self { - Self::with_db(Default::default()) - } - - /// Creates storage with given proof. - pub fn with_proof(proof: Vec>) -> Self { - use hash_db::HashDB; - - let mut proof_db = MemoryDB::::default(); - for item in proof { - proof_db.insert(EMPTY_PREFIX, &item); - } - Self::with_db(proof_db) - } - - /// Get mutable cache reference. - pub fn cache_mut(&mut self) -> &mut BuildCache { - &mut self.cache - } - - /// Create the storage with given blocks. - pub fn with_blocks(blocks: Vec<(Number, H::Out)>) -> Self { - Self { - data: RwLock::new(InMemoryStorageData { - roots: blocks.into_iter().collect(), - mdb: MemoryDB::default(), - }), - cache: BuildCache::new(), - } - } - - #[cfg(test)] - pub fn with_inputs( - mut top_inputs: Vec<(Number, Vec>)>, - children_inputs: Vec<(PrefixedStorageKey, Vec<(Number, Vec>)>)>, - ) -> Self { - let mut mdb = MemoryDB::default(); - let mut roots = BTreeMap::new(); - for (storage_key, child_input) in children_inputs { - for (block, pairs) in child_input { - let root = - insert_into_memory_db::(&mut mdb, pairs.into_iter().map(Into::into)); - - if let Some(root) = root { - let ix = if let Some(ix) = top_inputs.iter().position(|v| v.0 == block) { - ix - } else { - top_inputs.push((block.clone(), Default::default())); - top_inputs.len() - 1 - }; - top_inputs[ix].1.push(InputPair::ChildIndex( - ChildIndex { block: block.clone(), storage_key: storage_key.clone() }, - root.as_ref().to_vec(), - )); - } - } - } - - for (block, pairs) in top_inputs { - let root = insert_into_memory_db::(&mut mdb, pairs.into_iter().map(Into::into)); - if let Some(root) = root { - roots.insert(block, root); - } - } - - InMemoryStorage { - data: RwLock::new(InMemoryStorageData { roots, mdb }), - cache: BuildCache::new(), - } - } - - #[cfg(test)] - pub fn clear_storage(&self) { - self.data.write().mdb = MemoryDB::default(); // use new to be more correct - } - - #[cfg(test)] - pub fn remove_from_storage(&self, keys: &HashSet) { - let mut data = self.data.write(); - for key in keys { - data.mdb.remove_and_purge(key, hash_db::EMPTY_PREFIX); - } - } - - #[cfg(test)] - pub fn into_mdb(self) -> MemoryDB { - self.data.into_inner().mdb - } - - /// Insert changes trie for given block. - pub fn insert(&self, block: Number, changes_trie_root: H::Out, trie: MemoryDB) { - let mut data = self.data.write(); - data.roots.insert(block, changes_trie_root); - data.mdb.consolidate(trie); - } -} - -impl RootsStorage for InMemoryStorage { - fn build_anchor(&self, parent_hash: H::Out) -> Result, String> { - self.data - .read() - .roots - .iter() - .find(|(_, v)| **v == parent_hash) - .map(|(k, _)| AnchorBlockId { hash: parent_hash, number: k.clone() }) - .ok_or_else(|| format!("Can't find associated number for block {:?}", parent_hash)) - } - - fn root( - &self, - _anchor_block: &AnchorBlockId, - block: Number, - ) -> Result, String> { - Ok(self.data.read().roots.get(&block).cloned()) - } -} - -impl Storage for InMemoryStorage { - fn as_roots_storage(&self) -> &dyn RootsStorage { - self - } - - fn with_cached_changed_keys( - &self, - root: &H::Out, - functor: &mut dyn FnMut(&HashMap, HashSet>), - ) -> bool { - self.cache.with_changed_keys(root, functor) - } - - fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String> { - MemoryDB::::get(&self.data.read().mdb, key, prefix) - } -} - -impl<'a, H: Hasher, Number: BlockNumber> TrieBackendAdapter<'a, H, Number> { - pub fn new(storage: &'a dyn Storage) -> Self { - Self { storage, _hasher: Default::default() } - } -} - -impl<'a, H, Number> TrieBackendStorage for TrieBackendAdapter<'a, H, Number> -where - Number: BlockNumber, - H: Hasher, -{ - type Overlay = MemoryDB; - - fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String> { - self.storage.get(key, prefix) - } -} diff --git a/primitives/state-machine/src/changes_trie/surface_iterator.rs b/primitives/state-machine/src/changes_trie/surface_iterator.rs deleted file mode 100644 index b3e5a490cd184..0000000000000 --- a/primitives/state-machine/src/changes_trie/surface_iterator.rs +++ /dev/null @@ -1,326 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The best way to understand how this iterator works is to imagine some 2D terrain that have some -//! mountains (digest changes tries) and valleys (changes tries for regular blocks). There are gems -//! (blocks) beneath the terrain. Given the request to find all gems in the range [X1; X2] this -//! iterator will return **minimal set** of points at the terrain (mountains and valleys) inside -//! this range that have to be drilled down to search for gems. - -use crate::changes_trie::{BlockNumber, ConfigurationRange}; -use num_traits::One; - -/// Returns surface iterator for given range of blocks. -/// -/// `max` is the number of best block, known to caller. We can't access any changes tries -/// that are built after this block, even though we may have them built already. -pub fn surface_iterator<'a, Number: BlockNumber>( - config: ConfigurationRange<'a, Number>, - max: Number, - begin: Number, - end: Number, -) -> Result, String> { - let (current, current_begin, digest_step, digest_level) = - lower_bound_max_digest(config.clone(), max.clone(), begin.clone(), end)?; - Ok(SurfaceIterator { - config, - begin, - max, - current: Some(current), - current_begin, - digest_step, - digest_level, - }) -} - -/// Surface iterator - only traverses top-level digests from given range and tries to find -/// all valid digest changes. -/// -/// Iterator item is the tuple of (last block of the current point + digest level of the current -/// point). Digest level is Some(0) when it is regular block, is Some(non-zero) when it is digest -/// block and None if it is skewed digest block. -pub struct SurfaceIterator<'a, Number: BlockNumber> { - config: ConfigurationRange<'a, Number>, - begin: Number, - max: Number, - current: Option, - current_begin: Number, - digest_step: u32, - digest_level: Option, -} - -impl<'a, Number: BlockNumber> Iterator for SurfaceIterator<'a, Number> { - type Item = Result<(Number, Option), String>; - - fn next(&mut self) -> Option { - let current = self.current.clone()?; - let digest_level = self.digest_level; - - if current < self.digest_step.into() { - self.current = None; - } else { - let next = current.clone() - self.digest_step.into(); - if next.is_zero() || next < self.begin { - self.current = None; - } else if next > self.current_begin { - self.current = Some(next); - } else { - let max_digest_interval = lower_bound_max_digest( - self.config.clone(), - self.max.clone(), - self.begin.clone(), - next, - ); - let (current, current_begin, digest_step, digest_level) = match max_digest_interval - { - Err(err) => return Some(Err(err)), - Ok(range) => range, - }; - - self.current = Some(current); - self.current_begin = current_begin; - self.digest_step = digest_step; - self.digest_level = digest_level; - } - } - - Some(Ok((current, digest_level))) - } -} - -/// Returns parameters of highest level digest block that includes the end of given range -/// and tends to include the whole range. -fn lower_bound_max_digest<'a, Number: BlockNumber>( - config: ConfigurationRange<'a, Number>, - max: Number, - begin: Number, - end: Number, -) -> Result<(Number, Number, u32, Option), String> { - if end > max || begin > end { - return Err(format!("invalid changes range: {}..{}/{}", begin, end, max)) - } - if begin <= config.zero || - config.end.as_ref().map(|config_end| end > *config_end).unwrap_or(false) - { - return Err(format!( - "changes trie range is not covered by configuration: {}..{}/{}..{}", - begin, - end, - config.zero, - match config.end.as_ref() { - Some(config_end) => format!("{}", config_end), - None => "None".into(), - } - )) - } - - let mut digest_level = 0u32; - let mut digest_step = 1u32; - let mut digest_interval = 0u32; - let mut current = end.clone(); - let mut current_begin = begin.clone(); - if current_begin != current { - while digest_level != config.config.digest_levels { - // try to use next level digest - let new_digest_level = digest_level + 1; - let new_digest_step = digest_step * config.config.digest_interval; - let new_digest_interval = config.config.digest_interval * { - if digest_interval == 0 { - 1 - } else { - digest_interval - } - }; - let new_digest_begin = config.zero.clone() + - ((current.clone() - One::one() - config.zero.clone()) / - new_digest_interval.into()) * - new_digest_interval.into(); - let new_digest_end = new_digest_begin.clone() + new_digest_interval.into(); - let new_current = new_digest_begin.clone() + new_digest_interval.into(); - - // check if we met skewed digest - if let Some(skewed_digest_end) = config.end.as_ref() { - if new_digest_end > *skewed_digest_end { - let skewed_digest_start = config.config.prev_max_level_digest_block( - config.zero.clone(), - skewed_digest_end.clone(), - ); - if let Some(skewed_digest_start) = skewed_digest_start { - let skewed_digest_range = (skewed_digest_end.clone() - - skewed_digest_start.clone()) - .try_into() - .ok() - .expect( - "skewed digest range is always <= max level digest range;\ - max level digest range always fits u32; qed", - ); - return Ok(( - skewed_digest_end.clone(), - skewed_digest_start, - skewed_digest_range, - None, - )) - } - } - } - - // we can't use next level digest if it touches any unknown (> max) blocks - if new_digest_end > max { - if begin < new_digest_begin { - current_begin = new_digest_begin; - } - break - } - - // we can (and will) use this digest - digest_level = new_digest_level; - digest_step = new_digest_step; - digest_interval = new_digest_interval; - current = new_current; - current_begin = new_digest_begin; - - // if current digest covers the whole range => no need to use next level digest - if current_begin <= begin && new_digest_end >= end { - break - } - } - } - - Ok((current, current_begin, digest_step, Some(digest_level))) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::changes_trie::Configuration; - - fn configuration_range<'a>( - config: &'a Configuration, - zero: u64, - ) -> ConfigurationRange<'a, u64> { - ConfigurationRange { config, zero, end: None } - } - - #[test] - fn lower_bound_max_digest_works() { - let config = Configuration { digest_interval: 4, digest_levels: 2 }; - - // when config activates at 0 - assert_eq!( - lower_bound_max_digest(configuration_range(&config, 0u64), 100_000u64, 20u64, 180u64) - .unwrap(), - (192, 176, 16, Some(2)), - ); - - // when config activates at 30 - assert_eq!( - lower_bound_max_digest(configuration_range(&config, 30u64), 100_000u64, 50u64, 210u64) - .unwrap(), - (222, 206, 16, Some(2)), - ); - } - - #[test] - fn surface_iterator_works() { - let config = Configuration { digest_interval: 4, digest_levels: 2 }; - - // when config activates at 0 - assert_eq!( - surface_iterator(configuration_range(&config, 0u64), 100_000u64, 40u64, 180u64,) - .unwrap() - .collect::>(), - vec![ - Ok((192, Some(2))), - Ok((176, Some(2))), - Ok((160, Some(2))), - Ok((144, Some(2))), - Ok((128, Some(2))), - Ok((112, Some(2))), - Ok((96, Some(2))), - Ok((80, Some(2))), - Ok((64, Some(2))), - Ok((48, Some(2))), - ], - ); - - // when config activates at 30 - assert_eq!( - surface_iterator(configuration_range(&config, 30u64), 100_000u64, 40u64, 180u64,) - .unwrap() - .collect::>(), - vec![ - Ok((190, Some(2))), - Ok((174, Some(2))), - Ok((158, Some(2))), - Ok((142, Some(2))), - Ok((126, Some(2))), - Ok((110, Some(2))), - Ok((94, Some(2))), - Ok((78, Some(2))), - Ok((62, Some(2))), - Ok((46, Some(2))), - ], - ); - - // when config activates at 0 AND max block is before next digest - assert_eq!( - surface_iterator(configuration_range(&config, 0u64), 183u64, 40u64, 183u64) - .unwrap() - .collect::>(), - vec![ - Ok((183, Some(0))), - Ok((182, Some(0))), - Ok((181, Some(0))), - Ok((180, Some(1))), - Ok((176, Some(2))), - Ok((160, Some(2))), - Ok((144, Some(2))), - Ok((128, Some(2))), - Ok((112, Some(2))), - Ok((96, Some(2))), - Ok((80, Some(2))), - Ok((64, Some(2))), - Ok((48, Some(2))), - ], - ); - } - - #[test] - fn surface_iterator_works_with_skewed_digest() { - let config = Configuration { digest_interval: 4, digest_levels: 2 }; - let mut config_range = configuration_range(&config, 0u64); - - // when config activates at 0 AND ends at 170 - config_range.end = Some(170); - assert_eq!( - surface_iterator(config_range, 100_000u64, 40u64, 170u64) - .unwrap() - .collect::>(), - vec![ - Ok((170, None)), - Ok((160, Some(2))), - Ok((144, Some(2))), - Ok((128, Some(2))), - Ok((112, Some(2))), - Ok((96, Some(2))), - Ok((80, Some(2))), - Ok((64, Some(2))), - Ok((48, Some(2))), - ], - ); - } -} diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index c20d8492fb1f3..8f914ab3eee64 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -28,8 +28,6 @@ use sp_core::storage::{well_known_keys::is_child_storage_key, ChildInfo, Tracked use sp_externalities::{Extension, ExtensionStore, Externalities}; use sp_trie::{empty_child_trie_root, trie_types::Layout}; -#[cfg(feature = "std")] -use crate::changes_trie::State as ChangesTrieState; use crate::{log_error, trace, warn, StorageTransactionCache}; use sp_std::{ any::{Any, TypeId}, @@ -90,62 +88,52 @@ impl error::Error for Error { } /// Wraps a read-only backend, call executor, and current overlayed changes. -pub struct Ext<'a, H, N, B> +pub struct Ext<'a, H, B> where H: Hasher, B: 'a + Backend, - N: crate::changes_trie::BlockNumber, { /// The overlayed changes to write to. overlay: &'a mut OverlayedChanges, /// The storage backend to read from. backend: &'a B, /// The cache for the storage transactions. - storage_transaction_cache: &'a mut StorageTransactionCache, - /// Changes trie state to read from. - #[cfg(feature = "std")] - changes_trie_state: Option>, + storage_transaction_cache: &'a mut StorageTransactionCache, /// Pseudo-unique id used for tracing. pub id: u16, - /// Dummy usage of N arg. - _phantom: sp_std::marker::PhantomData, /// Extensions registered with this instance. #[cfg(feature = "std")] extensions: Option>, } -impl<'a, H, N, B> Ext<'a, H, N, B> +impl<'a, H, B> Ext<'a, H, B> where H: Hasher, B: Backend, - N: crate::changes_trie::BlockNumber, { /// Create a new `Ext`. #[cfg(not(feature = "std"))] pub fn new( overlay: &'a mut OverlayedChanges, - storage_transaction_cache: &'a mut StorageTransactionCache, + storage_transaction_cache: &'a mut StorageTransactionCache, backend: &'a B, ) -> Self { - Ext { overlay, backend, id: 0, storage_transaction_cache, _phantom: Default::default() } + Ext { overlay, backend, id: 0, storage_transaction_cache } } /// Create a new `Ext` from overlayed changes and read-only backend #[cfg(feature = "std")] pub fn new( overlay: &'a mut OverlayedChanges, - storage_transaction_cache: &'a mut StorageTransactionCache, + storage_transaction_cache: &'a mut StorageTransactionCache, backend: &'a B, - changes_trie_state: Option>, extensions: Option<&'a mut sp_externalities::Extensions>, ) -> Self { Self { overlay, backend, - changes_trie_state, storage_transaction_cache, id: rand::random(), - _phantom: Default::default(), extensions: extensions.map(OverlayedExtensions::new), } } @@ -159,12 +147,11 @@ where } #[cfg(test)] -impl<'a, H, N, B> Ext<'a, H, N, B> +impl<'a, H, B> Ext<'a, H, B> where H: Hasher, H::Out: Ord + 'static, B: 'a + Backend, - N: crate::changes_trie::BlockNumber, { pub fn storage_pairs(&self) -> Vec<(StorageKey, StorageValue)> { use std::collections::HashMap; @@ -181,12 +168,11 @@ where } } -impl<'a, H, N, B> Externalities for Ext<'a, H, N, B> +impl<'a, H, B> Externalities for Ext<'a, H, B> where H: Hasher, H::Out: Ord + 'static + codec::Codec, B: Backend, - N: crate::changes_trie::BlockNumber, { fn set_offchain_storage(&mut self, key: &[u8], value: Option<&[u8]>) { self.overlay.set_offchain_storage(key, value) @@ -644,54 +630,6 @@ where .add_transaction_index(IndexOperation::Renew { extrinsic: index, hash: hash.to_vec() }); } - #[cfg(not(feature = "std"))] - fn storage_changes_root(&mut self, _parent_hash: &[u8]) -> Result>, ()> { - Ok(None) - } - - #[cfg(feature = "std")] - fn storage_changes_root(&mut self, mut parent_hash: &[u8]) -> Result>, ()> { - let _guard = guard(); - if let Some(ref root) = self.storage_transaction_cache.changes_trie_transaction_storage_root - { - trace!( - target: "state", - method = "ChangesRoot", - ext_id = %HexDisplay::from(&self.id.to_le_bytes()), - parent_hash = %HexDisplay::from(&parent_hash), - ?root, - cached = true, - ); - - Ok(Some(root.encode())) - } else { - let root = self.overlay.changes_trie_root( - self.backend, - self.changes_trie_state.as_ref(), - Decode::decode(&mut parent_hash).map_err(|e| { - trace!( - target: "state", - error = %e, - "Failed to decode changes root parent hash", - ) - })?, - true, - self.storage_transaction_cache, - ); - - trace!( - target: "state", - method = "ChangesRoot", - ext_id = %HexDisplay::from(&self.id.to_le_bytes()), - parent_hash = %HexDisplay::from(&parent_hash), - ?root, - cached = false, - ); - - root.map(|r| r.map(|o| o.encode())) - } - } - fn storage_start_transaction(&mut self) { self.overlay.start_transaction() } @@ -710,13 +648,7 @@ where self.overlay.rollback_transaction().expect(BENCHMARKING_FN); } self.overlay - .drain_storage_changes( - self.backend, - #[cfg(feature = "std")] - None, - Default::default(), - self.storage_transaction_cache, - ) + .drain_storage_changes(self.backend, Default::default(), self.storage_transaction_cache) .expect(EXT_NOT_ALLOWED_TO_FAIL); self.backend.wipe().expect(EXT_NOT_ALLOWED_TO_FAIL); self.mark_dirty(); @@ -731,13 +663,7 @@ where } let changes = self .overlay - .drain_storage_changes( - self.backend, - #[cfg(feature = "std")] - None, - Default::default(), - self.storage_transaction_cache, - ) + .drain_storage_changes(self.backend, Default::default(), self.storage_transaction_cache) .expect(EXT_NOT_ALLOWED_TO_FAIL); self.backend .commit( @@ -778,12 +704,11 @@ where } } -impl<'a, H, N, B> Ext<'a, H, N, B> +impl<'a, H, B> Ext<'a, H, B> where H: Hasher, H::Out: Ord + 'static + codec::Codec, B: Backend, - N: crate::changes_trie::BlockNumber, { fn limit_remove_from_backend( &mut self, @@ -869,12 +794,11 @@ impl<'a> StorageAppend<'a> { } #[cfg(not(feature = "std"))] -impl<'a, H, N, B> ExtensionStore for Ext<'a, H, N, B> +impl<'a, H, B> ExtensionStore for Ext<'a, H, B> where H: Hasher, H::Out: Ord + 'static + codec::Codec, B: Backend, - N: crate::changes_trie::BlockNumber, { fn extension_by_type_id(&mut self, _type_id: TypeId) -> Option<&mut dyn Any> { None @@ -897,11 +821,10 @@ where } #[cfg(feature = "std")] -impl<'a, H, N, B> ExtensionStore for Ext<'a, H, N, B> +impl<'a, H, B> ExtensionStore for Ext<'a, H, B> where H: Hasher, B: 'a + Backend, - N: crate::changes_trie::BlockNumber, { fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> { self.extensions.as_mut().and_then(|exts| exts.get_mut(type_id)) @@ -938,86 +861,16 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{ - changes_trie::{ - Configuration as ChangesTrieConfiguration, InMemoryStorage as TestChangesTrieStorage, - }, - InMemoryBackend, - }; + use crate::InMemoryBackend; use codec::Encode; - use hex_literal::hex; - use num_traits::Zero; use sp_core::{ map, - storage::{well_known_keys::EXTRINSIC_INDEX, Storage, StorageChild}, - Blake2Hasher, H256, + storage::{Storage, StorageChild}, + Blake2Hasher, }; type TestBackend = InMemoryBackend; - type TestExt<'a> = Ext<'a, Blake2Hasher, u64, TestBackend>; - - fn prepare_overlay_with_changes() -> OverlayedChanges { - let mut changes = OverlayedChanges::default(); - changes.set_collect_extrinsics(true); - changes.set_extrinsic_index(1); - changes.set_storage(vec![1], Some(vec![100])); - changes.set_storage(EXTRINSIC_INDEX.to_vec(), Some(3u32.encode())); - changes.set_offchain_storage(b"k1", Some(b"v1")); - changes.set_offchain_storage(b"k2", Some(b"v2")); - changes - } - - fn changes_trie_config() -> ChangesTrieConfiguration { - ChangesTrieConfiguration { digest_interval: 0, digest_levels: 0 } - } - - #[test] - fn storage_changes_root_is_none_when_storage_is_not_provided() { - let mut overlay = prepare_overlay_with_changes(); - let mut cache = StorageTransactionCache::default(); - let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None); - assert_eq!(ext.storage_changes_root(&H256::default().encode()).unwrap(), None); - } - - #[test] - fn storage_changes_root_is_none_when_state_is_not_provided() { - let mut overlay = prepare_overlay_with_changes(); - let mut cache = StorageTransactionCache::default(); - let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None); - assert_eq!(ext.storage_changes_root(&H256::default().encode()).unwrap(), None); - } - - #[test] - fn storage_changes_root_is_some_when_extrinsic_changes_are_non_empty() { - let mut overlay = prepare_overlay_with_changes(); - let mut cache = StorageTransactionCache::default(); - let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]); - let state = Some(ChangesTrieState::new(changes_trie_config(), Zero::zero(), &storage)); - let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &mut cache, &backend, state, None); - assert_eq!( - ext.storage_changes_root(&H256::default().encode()).unwrap(), - Some(hex!("bb0c2ef6e1d36d5490f9766cfcc7dfe2a6ca804504c3bb206053890d6dd02376").to_vec()), - ); - } - - #[test] - fn storage_changes_root_is_some_when_extrinsic_changes_are_empty() { - let mut overlay = prepare_overlay_with_changes(); - let mut cache = StorageTransactionCache::default(); - overlay.set_collect_extrinsics(false); - overlay.set_storage(vec![1], None); - let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]); - let state = Some(ChangesTrieState::new(changes_trie_config(), Zero::zero(), &storage)); - let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &mut cache, &backend, state, None); - assert_eq!( - ext.storage_changes_root(&H256::default().encode()).unwrap(), - Some(hex!("96f5aae4690e7302737b6f9b7f8567d5bbb9eac1c315f80101235a92d9ec27f4").to_vec()), - ); - } + type TestExt<'a> = Ext<'a, Blake2Hasher, TestBackend>; #[test] fn next_storage_key_works() { @@ -1035,7 +888,7 @@ mod tests { } .into(); - let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None); + let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); // next_backend < next_overlay assert_eq!(ext.next_storage_key(&[5]), Some(vec![10])); @@ -1051,7 +904,7 @@ mod tests { drop(ext); overlay.set_storage(vec![50], Some(vec![50])); - let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None); + let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); // next_overlay exist but next_backend doesn't exist assert_eq!(ext.next_storage_key(&[40]), Some(vec![50])); @@ -1079,7 +932,7 @@ mod tests { } .into(); - let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None); + let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); assert_eq!(ext.next_storage_key(&[5]), Some(vec![30])); @@ -1110,7 +963,7 @@ mod tests { } .into(); - let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None); + let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); // next_backend < next_overlay assert_eq!(ext.next_child_storage_key(child_info, &[5]), Some(vec![10])); @@ -1126,7 +979,7 @@ mod tests { drop(ext); overlay.set_child_storage(child_info, vec![50], Some(vec![50])); - let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None); + let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); // next_overlay exist but next_backend doesn't exist assert_eq!(ext.next_child_storage_key(child_info, &[40]), Some(vec![50])); @@ -1155,7 +1008,7 @@ mod tests { } .into(); - let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None); + let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); assert_eq!(ext.child_storage(child_info, &[10]), Some(vec![10])); assert_eq!( @@ -1192,7 +1045,7 @@ mod tests { } .into(); - let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None); + let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); use sp_core::storage::well_known_keys; let mut ext = ext; diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index b0178021f3130..f7477e232bc66 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -23,8 +23,6 @@ pub mod backend; #[cfg(feature = "std")] mod basic; -#[cfg(feature = "std")] -mod changes_trie; mod error; mod ext; #[cfg(feature = "std")] @@ -140,28 +138,10 @@ pub use crate::{ }; pub use error::{Error, ExecutionError}; -#[cfg(not(feature = "std"))] -mod changes_trie { - /// Stub for change trie block number until - /// change trie move to no_std. - pub trait BlockNumber {} - - impl BlockNumber for N {} -} - #[cfg(feature = "std")] mod std_reexport { pub use crate::{ basic::BasicExternalities, - changes_trie::{ - disabled_state as disabled_changes_trie_state, key_changes, key_changes_proof, - key_changes_proof_check, key_changes_proof_check_with_db, prune as prune_changes_tries, - AnchorBlockId as ChangesTrieAnchorBlockId, BlockNumber as ChangesTrieBlockNumber, - BuildCache as ChangesTrieBuildCache, CacheAction as ChangesTrieCacheAction, - ConfigurationRange as ChangesTrieConfigurationRange, - InMemoryStorage as InMemoryChangesTrieStorage, RootsStorage as ChangesTrieRootsStorage, - State as ChangesTrieState, Storage as ChangesTrieStorage, - }, error::{Error, ExecutionError}, in_memory_backend::new_in_mem, proving_backend::{ @@ -205,10 +185,6 @@ mod execution { /// Default handler of the execution manager. pub type DefaultHandler = fn(CallResult, CallResult) -> CallResult; - /// Type of changes trie transaction. - pub type ChangesTrieTransaction = - (MemoryDB, ChangesTrieCacheAction<::Out, N>); - /// Trie backend with in-memory storage. pub type InMemoryBackend = TrieBackend, H>; @@ -308,11 +284,10 @@ mod execution { } /// The substrate state machine. - pub struct StateMachine<'a, B, H, N, Exec> + pub struct StateMachine<'a, B, H, Exec> where H: Hasher, B: Backend, - N: ChangesTrieBlockNumber, { backend: &'a B, exec: &'a Exec, @@ -320,8 +295,7 @@ mod execution { call_data: &'a [u8], overlay: &'a mut OverlayedChanges, extensions: Extensions, - changes_trie_state: Option>, - storage_transaction_cache: Option<&'a mut StorageTransactionCache>, + storage_transaction_cache: Option<&'a mut StorageTransactionCache>, runtime_code: &'a RuntimeCode<'a>, stats: StateMachineStats, /// The hash of the block the state machine will be executed on. @@ -330,29 +304,26 @@ mod execution { parent_hash: Option, } - impl<'a, B, H, N, Exec> Drop for StateMachine<'a, B, H, N, Exec> + impl<'a, B, H, Exec> Drop for StateMachine<'a, B, H, Exec> where H: Hasher, B: Backend, - N: ChangesTrieBlockNumber, { fn drop(&mut self) { self.backend.register_overlay_stats(&self.stats); } } - impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> + impl<'a, B, H, Exec> StateMachine<'a, B, H, Exec> where H: Hasher, H::Out: Ord + 'static + codec::Codec, Exec: CodeExecutor + Clone + 'static, B: Backend, - N: crate::changes_trie::BlockNumber, { /// Creates new substrate state machine. pub fn new( backend: &'a B, - changes_trie_state: Option>, overlay: &'a mut OverlayedChanges, exec: &'a Exec, method: &'a str, @@ -371,7 +342,6 @@ mod execution { call_data, extensions, overlay, - changes_trie_state, storage_transaction_cache: None, runtime_code, stats: StateMachineStats::default(), @@ -386,7 +356,7 @@ mod execution { /// build that will be cached. pub fn with_storage_transaction_cache( mut self, - cache: Option<&'a mut StorageTransactionCache>, + cache: Option<&'a mut StorageTransactionCache>, ) -> Self { self.storage_transaction_cache = cache; self @@ -439,13 +409,7 @@ mod execution { .enter_runtime() .expect("StateMachine is never called from the runtime; qed"); - let mut ext = Ext::new( - self.overlay, - cache, - self.backend, - self.changes_trie_state.clone(), - Some(&mut self.extensions), - ); + let mut ext = Ext::new(self.overlay, cache, self.backend, Some(&mut self.extensions)); let ext_id = ext.id; @@ -562,9 +526,6 @@ mod execution { CallResult, ) -> CallResult, { - let changes_tries_enabled = self.changes_trie_state.is_some(); - self.overlay.set_collect_extrinsics(changes_tries_enabled); - let result = { match manager { ExecutionManager::Both(on_consensus_failure) => self @@ -588,7 +549,7 @@ mod execution { } /// Prove execution using the given state backend, overlayed changes, and call executor. - pub fn prove_execution( + pub fn prove_execution( backend: &mut B, overlay: &mut OverlayedChanges, exec: &Exec, @@ -602,13 +563,12 @@ mod execution { H: Hasher, H::Out: Ord + 'static + codec::Codec, Exec: CodeExecutor + Clone + 'static, - N: crate::changes_trie::BlockNumber, Spawn: SpawnNamed + Send + 'static, { let trie_backend = backend .as_trie_backend() .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; - prove_execution_on_trie_backend::<_, _, N, _, _>( + prove_execution_on_trie_backend::<_, _, _, _>( trie_backend, overlay, exec, @@ -628,7 +588,7 @@ mod execution { /// /// Note: changes to code will be in place if this call is made again. For running partial /// blocks (e.g. a transaction at a time), ensure a different method is used. - pub fn prove_execution_on_trie_backend( + pub fn prove_execution_on_trie_backend( trie_backend: &TrieBackend, overlay: &mut OverlayedChanges, exec: &Exec, @@ -642,13 +602,11 @@ mod execution { H: Hasher, H::Out: Ord + 'static + codec::Codec, Exec: CodeExecutor + 'static + Clone, - N: crate::changes_trie::BlockNumber, Spawn: SpawnNamed + Send + 'static, { let proving_backend = proving_backend::ProvingBackend::new(trie_backend); - let mut sm = StateMachine::<_, H, N, Exec>::new( + let mut sm = StateMachine::<_, H, Exec>::new( &proving_backend, - None, overlay, exec, method, @@ -667,7 +625,7 @@ mod execution { } /// Check execution proof, generated by `prove_execution` call. - pub fn execution_proof_check( + pub fn execution_proof_check( root: H::Out, proof: StorageProof, overlay: &mut OverlayedChanges, @@ -681,11 +639,10 @@ mod execution { H: Hasher, Exec: CodeExecutor + Clone + 'static, H::Out: Ord + 'static + codec::Codec, - N: crate::changes_trie::BlockNumber, Spawn: SpawnNamed + Send + 'static, { let trie_backend = create_proof_check_backend::(root.into(), proof)?; - execution_proof_check_on_trie_backend::<_, N, _, _>( + execution_proof_check_on_trie_backend::<_, _, _>( &trie_backend, overlay, exec, @@ -697,7 +654,7 @@ mod execution { } /// Check execution proof on proving backend, generated by `prove_execution` call. - pub fn execution_proof_check_on_trie_backend( + pub fn execution_proof_check_on_trie_backend( trie_backend: &TrieBackend, H>, overlay: &mut OverlayedChanges, exec: &Exec, @@ -710,12 +667,10 @@ mod execution { H: Hasher, H::Out: Ord + 'static + codec::Codec, Exec: CodeExecutor + Clone + 'static, - N: crate::changes_trie::BlockNumber, Spawn: SpawnNamed + Send + 'static, { - let mut sm = StateMachine::<_, H, N, Exec>::new( + let mut sm = StateMachine::<_, H, Exec>::new( trie_backend, - None, overlay, exec, method, @@ -1390,7 +1345,7 @@ mod execution { #[cfg(test)] mod tests { - use super::{changes_trie::Configuration as ChangesTrieConfig, ext::Ext, *}; + use super::{ext::Ext, *}; use crate::execution::CallResult; use codec::{Decode, Encode}; use sp_core::{ @@ -1409,7 +1364,6 @@ mod tests { #[derive(Clone)] struct DummyCodeExecutor { - change_changes_trie_config: bool, native_available: bool, native_succeeds: bool, fallback_succeeds: bool, @@ -1430,13 +1384,6 @@ mod tests { use_native: bool, native_call: Option, ) -> (CallResult, bool) { - if self.change_changes_trie_config { - ext.place_storage( - sp_core::storage::well_known_keys::CHANGES_TRIE_CONFIG.to_vec(), - Some(ChangesTrieConfig { digest_interval: 777, digest_levels: 333 }.encode()), - ); - } - let using_native = use_native && self.native_available; match (using_native, self.native_succeeds, self.fallback_succeeds, native_call) { (true, true, _, Some(call)) => { @@ -1472,10 +1419,8 @@ mod tests { let mut state_machine = StateMachine::new( &backend, - changes_trie::disabled_state::<_, u64>(), &mut overlayed_changes, &DummyCodeExecutor { - change_changes_trie_config: false, native_available: true, native_succeeds: true, fallback_succeeds: true, @@ -1498,10 +1443,8 @@ mod tests { let mut state_machine = StateMachine::new( &backend, - changes_trie::disabled_state::<_, u64>(), &mut overlayed_changes, &DummyCodeExecutor { - change_changes_trie_config: false, native_available: true, native_succeeds: true, fallback_succeeds: true, @@ -1525,10 +1468,8 @@ mod tests { let mut state_machine = StateMachine::new( &backend, - changes_trie::disabled_state::<_, u64>(), &mut overlayed_changes, &DummyCodeExecutor { - change_changes_trie_config: false, native_available: true, native_succeeds: true, fallback_succeeds: false, @@ -1555,7 +1496,6 @@ mod tests { #[test] fn prove_execution_and_proof_check_works() { let executor = DummyCodeExecutor { - change_changes_trie_config: false, native_available: true, native_succeeds: true, fallback_succeeds: true, @@ -1564,7 +1504,7 @@ mod tests { // fetch execution proof from 'remote' full node let mut remote_backend = trie_backend::tests::test_trie(); let remote_root = remote_backend.storage_root(std::iter::empty()).0; - let (remote_result, remote_proof) = prove_execution::<_, _, u64, _, _>( + let (remote_result, remote_proof) = prove_execution( &mut remote_backend, &mut Default::default(), &executor, @@ -1576,7 +1516,7 @@ mod tests { .unwrap(); // check proof locally - let local_result = execution_proof_check::( + let local_result = execution_proof_check::( remote_root, remote_proof, &mut Default::default(), @@ -1614,13 +1554,7 @@ mod tests { let overlay_limit = overlay.clone(); { let mut cache = StorageTransactionCache::default(); - let mut ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); ext.clear_prefix(b"ab", None); } overlay.commit_transaction().unwrap(); @@ -1644,13 +1578,7 @@ mod tests { let mut overlay = overlay_limit; { let mut cache = StorageTransactionCache::default(); - let mut ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); assert_eq!((false, 1), ext.clear_prefix(b"ab", Some(1))); } overlay.commit_transaction().unwrap(); @@ -1692,13 +1620,7 @@ mod tests { { let mut cache = StorageTransactionCache::default(); - let mut ext = Ext::new( - &mut overlay, - &mut cache, - &backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); assert_eq!(ext.kill_child_storage(&child_info, Some(2)), (false, 2)); } @@ -1733,13 +1655,7 @@ mod tests { let backend = InMemoryBackend::::from(initial); let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); - let mut ext = Ext::new( - &mut overlay, - &mut cache, - &backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); assert_eq!(ext.kill_child_storage(&child_info, Some(0)), (false, 0)); assert_eq!(ext.kill_child_storage(&child_info, Some(1)), (false, 1)); assert_eq!(ext.kill_child_storage(&child_info, Some(2)), (false, 2)); @@ -1758,13 +1674,7 @@ mod tests { let backend = state.as_trie_backend().unwrap(); let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); - let mut ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); ext.set_child_storage(child_info, b"abc".to_vec(), b"def".to_vec()); assert_eq!(ext.child_storage(child_info, b"abc"), Some(b"def".to_vec())); @@ -1781,26 +1691,14 @@ mod tests { let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); { - let mut ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); ext.storage_append(key.clone(), reference_data[0].encode()); assert_eq!(ext.storage(key.as_slice()), Some(vec![reference_data[0].clone()].encode())); } overlay.start_transaction(); { - let mut ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); for i in reference_data.iter().skip(1) { ext.storage_append(key.clone(), i.encode()); @@ -1809,13 +1707,7 @@ mod tests { } overlay.rollback_transaction().unwrap(); { - let ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let ext = Ext::new(&mut overlay, &mut cache, backend, None); assert_eq!(ext.storage(key.as_slice()), Some(vec![reference_data[0].clone()].encode())); } } @@ -1837,13 +1729,7 @@ mod tests { // For example, block initialization with event. { - let mut ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); ext.clear_storage(key.as_slice()); ext.storage_append(key.clone(), Item::InitializationItem.encode()); } @@ -1851,13 +1737,7 @@ mod tests { // For example, first transaction resulted in panic during block building { - let mut ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); assert_eq!(ext.storage(key.as_slice()), Some(vec![Item::InitializationItem].encode())); @@ -1872,13 +1752,7 @@ mod tests { // Then we apply next transaction which is valid this time. { - let mut ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); assert_eq!(ext.storage(key.as_slice()), Some(vec![Item::InitializationItem].encode())); @@ -1893,13 +1767,7 @@ mod tests { // Then only initlaization item and second (committed) item should persist. { - let ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let ext = Ext::new(&mut overlay, &mut cache, backend, None); assert_eq!( ext.storage(key.as_slice()), Some(vec![Item::InitializationItem, Item::CommitedItem].encode()), @@ -2214,13 +2082,7 @@ mod tests { let mut transaction = { let backend = test_trie(); let mut cache = StorageTransactionCache::default(); - let mut ext = Ext::new( - &mut overlay, - &mut cache, - &backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); ext.set_child_storage(&child_info_1, b"abc".to_vec(), b"def".to_vec()); ext.set_child_storage(&child_info_2, b"abc".to_vec(), b"def".to_vec()); ext.storage_root(); @@ -2257,13 +2119,7 @@ mod tests { { let mut cache = StorageTransactionCache::default(); - let mut ext = Ext::new( - &mut overlay, - &mut cache, - backend, - changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); assert_eq!(ext.storage(b"bbb"), Some(vec![])); assert_eq!(ext.storage(b"ccc"), Some(vec![])); ext.clear_storage(b"ccc"); @@ -2286,10 +2142,8 @@ mod tests { let mut state_machine = StateMachine::new( &backend, - changes_trie::disabled_state::<_, u64>(), &mut overlayed_changes, &DummyCodeExecutor { - change_changes_trie_config: false, native_available: true, native_succeeds: true, fallback_succeeds: false, @@ -2301,7 +2155,7 @@ mod tests { TaskExecutor::new(), ); - let run_state_machine = |state_machine: &mut StateMachine<_, _, _, _>| { + let run_state_machine = |state_machine: &mut StateMachine<_, _, _>| { state_machine .execute_using_consensus_failure_handler:: _, _, _>( ExecutionManager::NativeWhenPossible, diff --git a/primitives/state-machine/src/overlayed_changes/changeset.rs b/primitives/state-machine/src/overlayed_changes/changeset.rs index 1ffd569e2828b..818b7be99bc6e 100644 --- a/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -69,7 +69,6 @@ struct InnerValue { /// Current value. None if value has been deleted. value: V, /// The set of extrinsic indices where the values has been changed. - /// Is filled only if runtime has announced changes trie support. extrinsics: Extrinsics, } diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index cf7af1c9a6f3a..b7a535792aae6 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -21,12 +21,7 @@ mod changeset; mod offchain; use self::changeset::OverlayedChangeSet; -use crate::{backend::Backend, changes_trie::BlockNumber, stats::StateMachineStats, DefaultError}; -#[cfg(feature = "std")] -use crate::{ - changes_trie::{build_changes_trie, State as ChangesTrieState}, - ChangesTrieTransaction, -}; +use crate::{backend::Backend, stats::StateMachineStats, DefaultError}; use codec::{Decode, Encode}; use hash_db::Hasher; pub use offchain::OffchainOverlayedChanges; @@ -134,7 +129,7 @@ pub enum IndexOperation { /// /// This contains all the changes to the storage and transactions to apply theses changes to the /// backend. -pub struct StorageChanges { +pub struct StorageChanges { /// All changes to the main storage. /// /// A value of `None` means that it was deleted. @@ -150,22 +145,13 @@ pub struct StorageChanges { pub transaction: Transaction, /// The storage root after applying the transaction. pub transaction_storage_root: H::Out, - /// Contains the transaction for the backend for the changes trie. - /// - /// If changes trie is disabled the value is set to `None`. - #[cfg(feature = "std")] - pub changes_trie_transaction: Option>, - /// Phantom data for block number until change trie support no_std. - #[cfg(not(feature = "std"))] - pub _ph: sp_std::marker::PhantomData, - /// Changes to the transaction index, #[cfg(feature = "std")] pub transaction_index_changes: Vec, } #[cfg(feature = "std")] -impl StorageChanges { +impl StorageChanges { /// Deconstruct into the inner values pub fn into_inner( self, @@ -175,7 +161,6 @@ impl StorageChanges { OffchainChangesCollection, Transaction, H::Out, - Option>, Vec, ) { ( @@ -184,58 +169,35 @@ impl StorageChanges { self.offchain_storage_changes, self.transaction, self.transaction_storage_root, - self.changes_trie_transaction, self.transaction_index_changes, ) } } -/// The storage transaction are calculated as part of the `storage_root` and -/// `changes_trie_storage_root`. These transactions can be reused for importing the block into the +/// Storage transactions are calculated as part of the `storage_root`. +/// These transactions can be reused for importing the block into the /// storage. So, we cache them to not require a recomputation of those transactions. -pub struct StorageTransactionCache { +pub struct StorageTransactionCache { /// Contains the changes for the main and the child storages as one transaction. pub(crate) transaction: Option, /// The storage root after applying the transaction. pub(crate) transaction_storage_root: Option, - /// Contains the changes trie transaction. - #[cfg(feature = "std")] - pub(crate) changes_trie_transaction: Option>>, - /// The storage root after applying the changes trie transaction. - #[cfg(feature = "std")] - pub(crate) changes_trie_transaction_storage_root: Option>, - /// Phantom data for block number until change trie support no_std. - #[cfg(not(feature = "std"))] - pub(crate) _ph: sp_std::marker::PhantomData, } -impl StorageTransactionCache { +impl StorageTransactionCache { /// Reset the cached transactions. pub fn reset(&mut self) { *self = Self::default(); } } -impl Default - for StorageTransactionCache -{ +impl Default for StorageTransactionCache { fn default() -> Self { - Self { - transaction: None, - transaction_storage_root: None, - #[cfg(feature = "std")] - changes_trie_transaction: None, - #[cfg(feature = "std")] - changes_trie_transaction_storage_root: None, - #[cfg(not(feature = "std"))] - _ph: Default::default(), - } + Self { transaction: None, transaction_storage_root: None } } } -impl Default - for StorageChanges -{ +impl Default for StorageChanges { fn default() -> Self { Self { main_storage_changes: Default::default(), @@ -244,10 +206,6 @@ impl Default transaction: Default::default(), transaction_storage_root: Default::default(), #[cfg(feature = "std")] - changes_trie_transaction: None, - #[cfg(not(feature = "std"))] - _ph: Default::default(), - #[cfg(feature = "std")] transaction_index_changes: Default::default(), } } @@ -539,27 +497,25 @@ impl OverlayedChanges { /// Convert this instance with all changes into a [`StorageChanges`] instance. #[cfg(feature = "std")] - pub fn into_storage_changes, H: Hasher, N: BlockNumber>( + pub fn into_storage_changes, H: Hasher>( mut self, backend: &B, - changes_trie_state: Option<&ChangesTrieState>, parent_hash: H::Out, - mut cache: StorageTransactionCache, - ) -> Result, DefaultError> + mut cache: StorageTransactionCache, + ) -> Result, DefaultError> where H::Out: Ord + Encode + 'static, { - self.drain_storage_changes(backend, changes_trie_state, parent_hash, &mut cache) + self.drain_storage_changes(backend, parent_hash, &mut cache) } /// Drain all changes into a [`StorageChanges`] instance. Leave empty overlay in place. - pub fn drain_storage_changes, H: Hasher, N: BlockNumber>( + pub fn drain_storage_changes, H: Hasher>( &mut self, backend: &B, - #[cfg(feature = "std")] changes_trie_state: Option<&ChangesTrieState>, - parent_hash: H::Out, - mut cache: &mut StorageTransactionCache, - ) -> Result, DefaultError> + _parent_hash: H::Out, + mut cache: &mut StorageTransactionCache, + ) -> Result, DefaultError> where H::Out: Ord + Encode + 'static, { @@ -574,21 +530,6 @@ impl OverlayedChanges { .and_then(|t| cache.transaction_storage_root.take().map(|tr| (t, tr))) .expect("Transaction was be generated as part of `storage_root`; qed"); - // If the transaction does not exist, we generate it. - #[cfg(feature = "std")] - if cache.changes_trie_transaction.is_none() { - self.changes_trie_root(backend, changes_trie_state, parent_hash, false, &mut cache) - .map_err(|_| "Failed to generate changes trie transaction")?; - } - #[cfg(not(feature = "std"))] - let _ = parent_hash; - - #[cfg(feature = "std")] - let changes_trie_transaction = cache - .changes_trie_transaction - .take() - .expect("Changes trie transaction was generated by `changes_trie_root`; qed"); - let (main_storage_changes, child_storage_changes) = self.drain_committed(); let offchain_storage_changes = self.offchain_drain_committed().collect(); @@ -604,11 +545,7 @@ impl OverlayedChanges { transaction, transaction_storage_root, #[cfg(feature = "std")] - changes_trie_transaction, - #[cfg(feature = "std")] transaction_index_changes, - #[cfg(not(feature = "std"))] - _ph: Default::default(), }) } @@ -639,10 +576,10 @@ impl OverlayedChanges { /// as seen by the current transaction. /// /// Returns the storage root and caches storage transaction in the given `cache`. - pub fn storage_root>( + pub fn storage_root>( &self, backend: &B, - cache: &mut StorageTransactionCache, + cache: &mut StorageTransactionCache, ) -> H::Out where H::Out: Ord + Encode, @@ -660,40 +597,6 @@ impl OverlayedChanges { root } - /// Generate the changes trie root. - /// - /// Returns the changes trie root and caches the storage transaction into the given `cache`. - /// - /// # Panics - /// - /// Panics on storage error, when `panic_on_storage_error` is set. - #[cfg(feature = "std")] - pub fn changes_trie_root<'a, H: Hasher, N: BlockNumber, B: Backend>( - &self, - backend: &B, - changes_trie_state: Option<&'a ChangesTrieState<'a, H, N>>, - parent_hash: H::Out, - panic_on_storage_error: bool, - cache: &mut StorageTransactionCache, - ) -> Result, ()> - where - H::Out: Ord + Encode + 'static, - { - build_changes_trie::<_, H, N>( - backend, - changes_trie_state, - self, - parent_hash, - panic_on_storage_error, - ) - .map(|r| { - let root = r.as_ref().map(|r| r.1).clone(); - cache.changes_trie_transaction = Some(r.map(|(db, _, cache)| (db, cache))); - cache.changes_trie_transaction_storage_root = Some(root); - root - }) - } - /// Returns an iterator over the keys (in lexicographic order) following `key` (excluding `key`) /// alongside its value. pub fn iter_after(&self, key: &[u8]) -> impl Iterator { @@ -937,7 +840,6 @@ mod tests { .collect(); let backend = InMemoryBackend::::from(initial); let mut overlay = OverlayedChanges::default(); - overlay.set_collect_extrinsics(false); overlay.start_transaction(); overlay.set_storage(b"dog".to_vec(), Some(b"puppy".to_vec())); @@ -950,13 +852,7 @@ mod tests { overlay.set_storage(b"doug".to_vec(), None); let mut cache = StorageTransactionCache::default(); - let mut ext = Ext::new( - &mut overlay, - &mut cache, - &backend, - crate::changes_trie::disabled_state::<_, u64>(), - None, - ); + let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); const ROOT: [u8; 32] = hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa"); diff --git a/primitives/state-machine/src/read_only.rs b/primitives/state-machine/src/read_only.rs index 5b7d568b0311e..b3e43d4c46e7f 100644 --- a/primitives/state-machine/src/read_only.rs +++ b/primitives/state-machine/src/read_only.rs @@ -153,10 +153,6 @@ impl<'a, H: Hasher, B: 'a + Backend> Externalities for ReadOnlyExternalities< unimplemented!("child_storage_root is not supported in ReadOnlyExternalities") } - fn storage_changes_root(&mut self, _parent: &[u8]) -> Result>, ()> { - unimplemented!("storage_changes_root is not supported in ReadOnlyExternalities") - } - fn storage_start_transaction(&mut self) { unimplemented!("Transactions are not supported by ReadOnlyExternalities"); } diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index 23f66ee14d87e..59a0a5a6837ec 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -23,21 +23,15 @@ use std::{ }; use crate::{ - backend::Backend, - changes_trie::{ - BlockNumber as ChangesTrieBlockNumber, Configuration as ChangesTrieConfiguration, - InMemoryStorage as ChangesTrieInMemoryStorage, State as ChangesTrieState, - }, - ext::Ext, - InMemoryBackend, OverlayedChanges, StorageKey, StorageTransactionCache, StorageValue, + backend::Backend, ext::Ext, InMemoryBackend, OverlayedChanges, StorageKey, + StorageTransactionCache, StorageValue, }; -use codec::Decode; use hash_db::Hasher; use sp_core::{ offchain::testing::TestPersistentOffchainDB, storage::{ - well_known_keys::{is_child_storage_key, CHANGES_TRIE_CONFIG, CODE}, + well_known_keys::{is_child_storage_key, CODE}, Storage, }, testing::TaskExecutor, @@ -46,7 +40,7 @@ use sp_core::{ use sp_externalities::{Extension, ExtensionStore, Extensions}; /// Simple HashMap-based Externalities impl. -pub struct TestExternalities +pub struct TestExternalities where H::Out: codec::Codec + Ord, { @@ -54,33 +48,23 @@ where overlay: OverlayedChanges, offchain_db: TestPersistentOffchainDB, storage_transaction_cache: - StorageTransactionCache< as Backend>::Transaction, H, N>, + StorageTransactionCache< as Backend>::Transaction, H>, /// Storage backend. pub backend: InMemoryBackend, - changes_trie_config: Option, - changes_trie_storage: ChangesTrieInMemoryStorage, /// Extensions. pub extensions: Extensions, } -impl TestExternalities +impl TestExternalities where H::Out: Ord + 'static + codec::Codec, { /// Get externalities implementation. - pub fn ext(&mut self) -> Ext> { + pub fn ext(&mut self) -> Ext> { Ext::new( &mut self.overlay, &mut self.storage_transaction_cache, &self.backend, - match self.changes_trie_config.clone() { - Some(config) => Some(ChangesTrieState { - config, - zero: 0.into(), - storage: &self.changes_trie_storage, - }), - None => None, - }, Some(&mut self.extensions), ) } @@ -97,12 +81,7 @@ where /// Create a new instance of `TestExternalities` with code and storage. pub fn new_with_code(code: &[u8], mut storage: Storage) -> Self { - let mut overlay = OverlayedChanges::default(); - let changes_trie_config = storage - .top - .get(CHANGES_TRIE_CONFIG) - .and_then(|v| Decode::decode(&mut &v[..]).ok()); - overlay.set_collect_extrinsics(changes_trie_config.is_some()); + let overlay = OverlayedChanges::default(); assert!(storage.top.keys().all(|key| !is_child_storage_key(key))); assert!(storage.children_default.keys().all(|key| is_child_storage_key(key))); @@ -117,9 +96,7 @@ where TestExternalities { overlay, offchain_db, - changes_trie_config, extensions, - changes_trie_storage: ChangesTrieInMemoryStorage::new(), backend: storage.into(), storage_transaction_cache: Default::default(), } @@ -150,11 +127,6 @@ where self.extensions.register(ext); } - /// Get mutable reference to changes trie storage. - pub fn changes_trie_storage(&mut self) -> &mut ChangesTrieInMemoryStorage { - &mut self.changes_trie_storage - } - /// Return a new backend with all pending changes. /// /// In contrast to [`commit_all`](Self::commit_all) this will not panic if there are open @@ -180,9 +152,8 @@ where /// /// This will panic if there are still open transactions. pub fn commit_all(&mut self) -> Result<(), String> { - let changes = self.overlay.drain_storage_changes::<_, _, N>( + let changes = self.overlay.drain_storage_changes::<_, _>( &self.backend, - None, Default::default(), &mut Default::default(), )?; @@ -216,7 +187,7 @@ where } } -impl std::fmt::Debug for TestExternalities +impl std::fmt::Debug for TestExternalities where H::Out: Ord + codec::Codec, { @@ -225,18 +196,18 @@ where } } -impl PartialEq for TestExternalities +impl PartialEq for TestExternalities where H::Out: Ord + 'static + codec::Codec, { /// This doesn't test if they are in the same state, only if they contains the /// same data at this state - fn eq(&self, other: &TestExternalities) -> bool { + fn eq(&self, other: &TestExternalities) -> bool { self.as_backend().eq(&other.as_backend()) } } -impl Default for TestExternalities +impl Default for TestExternalities where H::Out: Ord + 'static + codec::Codec, { @@ -245,7 +216,7 @@ where } } -impl From for TestExternalities +impl From for TestExternalities where H::Out: Ord + 'static + codec::Codec, { @@ -254,11 +225,10 @@ where } } -impl sp_externalities::ExtensionStore for TestExternalities +impl sp_externalities::ExtensionStore for TestExternalities where H: Hasher, H::Out: Ord + codec::Codec, - N: ChangesTrieBlockNumber, { fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> { self.extensions.get_mut(type_id) @@ -284,11 +254,10 @@ where } } -impl sp_externalities::ExternalitiesExt for TestExternalities +impl sp_externalities::ExternalitiesExt for TestExternalities where H: Hasher, H::Out: Ord + codec::Codec, - N: ChangesTrieBlockNumber, { fn extension(&mut self) -> Option<&mut T> { self.extension_by_type_id(TypeId::of::()).and_then(::downcast_mut) @@ -312,7 +281,7 @@ mod tests { #[test] fn commit_should_work() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::::default(); let mut ext = ext.ext(); ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); @@ -324,7 +293,7 @@ mod tests { #[test] fn set_and_retrieve_code() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::::default(); let mut ext = ext.ext(); let code = vec![1, 2, 3]; @@ -336,12 +305,12 @@ mod tests { #[test] fn check_send() { fn assert_send() {} - assert_send::>(); + assert_send::>(); } #[test] fn commit_all_and_kill_child_storage() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::::default(); let child_info = ChildInfo::new_default(&b"test_child"[..]); { @@ -366,7 +335,7 @@ mod tests { #[test] fn as_backend_generates_same_backend_as_commit_all() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::::default(); { let mut ext = ext.ext(); ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index 45474a44693ab..1144e258e0e28 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -204,9 +204,6 @@ pub mod well_known_keys { /// Current extrinsic index (u32) is stored under this key. pub const EXTRINSIC_INDEX: &'static [u8] = b":extrinsic_index"; - /// Changes trie configuration is stored under this key. - pub const CHANGES_TRIE_CONFIG: &'static [u8] = b":changes_trie"; - /// Prefix of child storage keys. pub const CHILD_STORAGE_KEY_PREFIX: &'static [u8] = b":child_storage:"; diff --git a/primitives/tasks/src/async_externalities.rs b/primitives/tasks/src/async_externalities.rs index 975a81af4f53d..59733490a18ff 100644 --- a/primitives/tasks/src/async_externalities.rs +++ b/primitives/tasks/src/async_externalities.rs @@ -134,10 +134,6 @@ impl Externalities for AsyncExternalities { panic!("`child_storage_root`: should not be used in async externalities!") } - fn storage_changes_root(&mut self, _parent: &[u8]) -> Result>, ()> { - panic!("`storage_changes_root`: should not be used in async externalities!") - } - fn storage_start_transaction(&mut self) { unimplemented!("Transactions are not supported by AsyncExternalities"); } diff --git a/primitives/test-primitives/src/lib.rs b/primitives/test-primitives/src/lib.rs index d988160b1dc7b..341839a1deb20 100644 --- a/primitives/test-primitives/src/lib.rs +++ b/primitives/test-primitives/src/lib.rs @@ -73,15 +73,10 @@ pub type BlockNumber = u64; /// Index of a transaction. pub type Index = u64; /// The item of a block digest. -pub type DigestItem = sp_runtime::generic::DigestItem; +pub type DigestItem = sp_runtime::generic::DigestItem; /// The digest of a block. -pub type Digest = sp_runtime::generic::Digest; +pub type Digest = sp_runtime::generic::Digest; /// A test block. pub type Block = sp_runtime::generic::Block; /// A test block's header. pub type Header = sp_runtime::generic::Header; - -/// Changes trie configuration (optionally) used in tests. -pub fn changes_trie_config() -> sp_core::ChangesTrieConfiguration { - sp_core::ChangesTrieConfiguration { digest_interval: 4, digest_levels: 2 } -} diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index a8b2e8f57ac52..1277863c94f73 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -23,7 +23,6 @@ sc-client-db = { version = "0.10.0-dev", features = [ ], path = "../../client/db" } sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } sc-executor = { version = "0.10.0-dev", path = "../../client/executor" } -sc-light = { version = "4.0.0-dev", path = "../../client/light" } sc-offchain = { version = "4.0.0-dev", path = "../../client/offchain" } sc-service = { version = "0.10.0-dev", default-features = false, features = [ "test-helpers", diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 9bc411af5d3ed..2d1cb4bbc66a2 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -45,21 +45,13 @@ use sc_client_api::BlockchainEvents; use sc_service::client::{ClientConfig, LocalCallExecutor}; use serde::Deserialize; use sp_core::storage::ChildInfo; -use sp_runtime::{ - codec::Encode, - traits::{BlakeTwo256, Block as BlockT}, - OpaqueExtrinsic, -}; +use sp_runtime::{codec::Encode, traits::Block as BlockT, OpaqueExtrinsic}; use std::{ collections::{HashMap, HashSet}, pin::Pin, sync::Arc, }; -/// Test client light database backend. -pub type LightBackend = - sc_light::Backend, BlakeTwo256>; - /// A genesis storage initialization trait. pub trait GenesisInit: Default { /// Construct genesis storage. diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index fbc6aefdb850c..e5cba3a3399a1 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -12,7 +12,6 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sc-light = { version = "4.0.0-dev", path = "../../../client/light" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } diff --git a/test-utils/runtime/client/src/block_builder_ext.rs b/test-utils/runtime/client/src/block_builder_ext.rs index e8c1d2ac5cd48..4519dce65960d 100644 --- a/test-utils/runtime/client/src/block_builder_ext.rs +++ b/test-utils/runtime/client/src/block_builder_ext.rs @@ -19,7 +19,6 @@ use sc_client_api::backend; use sp_api::{ApiExt, ProvideRuntimeApi}; -use sp_core::ChangesTrieConfiguration; use sc_block_builder::BlockBuilderApi; @@ -36,11 +35,6 @@ pub trait BlockBuilderExt { key: Vec, value: Option>, ) -> Result<(), sp_blockchain::Error>; - /// Add changes trie configuration update extrinsic to the block. - fn push_changes_trie_configuration_update( - &mut self, - new_config: Option, - ) -> Result<(), sp_blockchain::Error>; } impl<'a, A, B> BlockBuilderExt @@ -68,11 +62,4 @@ where ) -> Result<(), sp_blockchain::Error> { self.push(substrate_test_runtime::Extrinsic::StorageChange(key, value)) } - - fn push_changes_trie_configuration_update( - &mut self, - new_config: Option, - ) -> Result<(), sp_blockchain::Error> { - self.push(substrate_test_runtime::Extrinsic::ChangesTrieConfigUpdate(new_config)) - } } diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index da92e0f37983c..2948e918cdf8b 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -24,22 +24,18 @@ pub mod trait_tests; mod block_builder_ext; pub use sc_consensus::LongestChain; -use std::{collections::HashMap, sync::Arc}; +use std::sync::Arc; pub use substrate_test_client::*; pub use substrate_test_runtime as runtime; pub use self::block_builder_ext::BlockBuilderExt; -use sc_client_api::light::{ - Fetcher, RemoteBodyRequest, RemoteCallRequest, RemoteChangesRequest, RemoteHeaderRequest, - RemoteReadChildRequest, RemoteReadRequest, -}; use sp_core::{ sr25519, storage::{ChildInfo, Storage, StorageChild}, - ChangesTrieConfiguration, Pair, + Pair, }; -use sp_runtime::traits::{Block as BlockT, Hash as HashT, HashFor, Header as HeaderT, NumberFor}; +use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT}; use substrate_test_runtime::genesismap::{additional_storage_with_genesis, GenesisConfig}; /// A prelude to import in tests. @@ -51,8 +47,8 @@ pub mod prelude { }; // Client structs pub use super::{ - Backend, ExecutorDispatch, LightBackend, LightExecutor, LocalExecutorDispatch, - NativeElseWasmExecutor, TestClient, TestClientBuilder, WasmExecutionMethod, + Backend, ExecutorDispatch, LocalExecutorDispatch, NativeElseWasmExecutor, TestClient, + TestClientBuilder, WasmExecutionMethod, }; // Keyring pub use super::{AccountKeyring, Sr25519Keyring}; @@ -84,26 +80,9 @@ pub type ExecutorDispatch = client::LocalCallExecutor< NativeElseWasmExecutor, >; -/// Test client light database backend. -pub type LightBackend = substrate_test_client::LightBackend; - -/// Test client light executor. -pub type LightExecutor = sc_light::GenesisCallExecutor< - LightBackend, - client::LocalCallExecutor< - substrate_test_runtime::Block, - sc_light::Backend< - sc_client_db::light::LightStorage, - HashFor, - >, - NativeElseWasmExecutor, - >, ->; - /// Parameters of test-client builder with test-runtime. #[derive(Default)] pub struct GenesisParameters { - changes_trie_config: Option, heap_pages_override: Option, extra_storage: Storage, wasm_code: Option>, @@ -112,7 +91,6 @@ pub struct GenesisParameters { impl GenesisParameters { fn genesis_config(&self) -> GenesisConfig { GenesisConfig::new( - self.changes_trie_config.clone(), vec![ sr25519::Public::from(Sr25519Keyring::Alice).into(), sr25519::Public::from(Sr25519Keyring::Bob).into(), @@ -215,12 +193,6 @@ pub trait TestClientBuilderExt: Sized { /// Returns a mutable reference to the genesis parameters. fn genesis_init_mut(&mut self) -> &mut GenesisParameters; - /// Set changes trie configuration for genesis. - fn changes_trie_config(mut self, config: Option) -> Self { - self.genesis_init_mut().changes_trie_config = config; - self - } - /// Override the default value for Wasm heap pages. fn set_heap_pages(mut self, heap_pages: u64) -> Self { self.genesis_init_mut().heap_pages_override = Some(heap_pages); @@ -308,142 +280,11 @@ impl TestClientBuilderExt } } -/// Type of optional fetch callback. -type MaybeFetcherCallback = - Option Result + Send + Sync>>; - -/// Type of fetcher future result. -type FetcherFutureResult = futures::future::Ready>; - -/// Implementation of light client fetcher used in tests. -#[derive(Default)] -pub struct LightFetcher { - call: MaybeFetcherCallback, Vec>, - body: MaybeFetcherCallback< - RemoteBodyRequest, - Vec, - >, -} - -impl LightFetcher { - /// Sets remote call callback. - pub fn with_remote_call( - self, - call: MaybeFetcherCallback, Vec>, - ) -> Self { - LightFetcher { call, body: self.body } - } - - /// Sets remote body callback. - pub fn with_remote_body( - self, - body: MaybeFetcherCallback< - RemoteBodyRequest, - Vec, - >, - ) -> Self { - LightFetcher { call: self.call, body } - } -} - -impl Fetcher for LightFetcher { - type RemoteHeaderResult = FetcherFutureResult; - type RemoteReadResult = FetcherFutureResult, Option>>>; - type RemoteCallResult = FetcherFutureResult>; - type RemoteChangesResult = - FetcherFutureResult, u32)>>; - type RemoteBodyResult = FetcherFutureResult>; - - fn remote_header( - &self, - _: RemoteHeaderRequest, - ) -> Self::RemoteHeaderResult { - unimplemented!() - } - - fn remote_read( - &self, - _: RemoteReadRequest, - ) -> Self::RemoteReadResult { - unimplemented!() - } - - fn remote_read_child( - &self, - _: RemoteReadChildRequest, - ) -> Self::RemoteReadResult { - unimplemented!() - } - - fn remote_call( - &self, - req: RemoteCallRequest, - ) -> Self::RemoteCallResult { - match self.call { - Some(ref call) => futures::future::ready(call(req)), - None => unimplemented!(), - } - } - - fn remote_changes( - &self, - _: RemoteChangesRequest, - ) -> Self::RemoteChangesResult { - unimplemented!() - } - - fn remote_body( - &self, - req: RemoteBodyRequest, - ) -> Self::RemoteBodyResult { - match self.body { - Some(ref body) => futures::future::ready(body(req)), - None => unimplemented!(), - } - } -} - /// Creates new client instance used for tests. pub fn new() -> Client { TestClientBuilder::new().build() } -/// Creates new light client instance used for tests. -pub fn new_light() -> ( - client::Client< - LightBackend, - LightExecutor, - substrate_test_runtime::Block, - substrate_test_runtime::RuntimeApi, - >, - Arc, -) { - let storage = sc_client_db::light::LightStorage::new_test(); - let blockchain = Arc::new(sc_light::Blockchain::new(storage)); - let backend = Arc::new(LightBackend::new(blockchain)); - let executor = new_native_executor(); - let local_call_executor = client::LocalCallExecutor::new( - backend.clone(), - executor, - Box::new(sp_core::testing::TaskExecutor::new()), - Default::default(), - ) - .expect("Creates LocalCallExecutor"); - let call_executor = LightExecutor::new(backend.clone(), local_call_executor); - - ( - TestClientBuilder::with_backend(backend.clone()) - .build_with_executor(call_executor) - .0, - backend, - ) -} - -/// Creates new light client fetcher used for tests. -pub fn new_light_fetcher() -> LightFetcher { - LightFetcher::default() -} - /// Create a new native executor. pub fn new_native_executor() -> sc_executor::NativeElseWasmExecutor { sc_executor::NativeElseWasmExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None, 8) diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index a8801b8519dfe..a06d9f310fb04 100644 --- a/test-utils/runtime/src/genesismap.rs +++ b/test-utils/runtime/src/genesismap.rs @@ -23,7 +23,6 @@ use sc_service::client::genesis; use sp_core::{ map, storage::{well_known_keys, Storage}, - ChangesTrieConfiguration, }; use sp_io::hashing::{blake2_256, twox_128}; use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT}; @@ -31,7 +30,6 @@ use std::collections::BTreeMap; /// Configuration of a general Substrate test genesis block. pub struct GenesisConfig { - changes_trie_config: Option, authorities: Vec, balances: Vec<(AccountId, u64)>, heap_pages_override: Option, @@ -41,7 +39,6 @@ pub struct GenesisConfig { impl GenesisConfig { pub fn new( - changes_trie_config: Option, authorities: Vec, endowed_accounts: Vec, balance: u64, @@ -49,7 +46,6 @@ impl GenesisConfig { extra_storage: Storage, ) -> Self { GenesisConfig { - changes_trie_config, authorities, balances: endowed_accounts.into_iter().map(|a| (a, balance)).collect(), heap_pages_override, @@ -77,9 +73,6 @@ impl GenesisConfig { .into_iter(), ) .collect(); - if let Some(ref changes_trie_config) = self.changes_trie_config { - map.insert(well_known_keys::CHANGES_TRIE_CONFIG.to_vec(), changes_trie_config.encode()); - } map.insert(twox_128(&b"sys:auth"[..])[..].to_vec(), self.authorities.encode()); // Add the extra storage entries. map.extend(self.extra_storage.top.clone().into_iter()); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 943c41c247f75..08863de510d09 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -28,7 +28,7 @@ use scale_info::TypeInfo; use sp_std::{marker::PhantomData, prelude::*}; use sp_application_crypto::{ecdsa, ed25519, sr25519, RuntimeAppPublic}; -use sp_core::{offchain::KeyTypeId, ChangesTrieConfiguration, OpaqueMetadata, RuntimeDebug}; +use sp_core::{offchain::KeyTypeId, OpaqueMetadata, RuntimeDebug}; use sp_trie::{ trie_types::{TrieDB, TrieDBMut}, PrefixedMemoryDB, StorageProof, @@ -161,7 +161,6 @@ pub enum Extrinsic { }, IncludeData(Vec), StorageChange(Vec, Option>), - ChangesTrieConfigUpdate(Option), OffchainIndexSet(Vec, Vec), OffchainIndexClear(Vec), Store(Vec), @@ -197,8 +196,6 @@ impl BlindCheckable for Extrinsic { }, Extrinsic::IncludeData(v) => Ok(Extrinsic::IncludeData(v)), Extrinsic::StorageChange(key, value) => Ok(Extrinsic::StorageChange(key, value)), - Extrinsic::ChangesTrieConfigUpdate(new_config) => - Ok(Extrinsic::ChangesTrieConfigUpdate(new_config)), Extrinsic::OffchainIndexSet(key, value) => Ok(Extrinsic::OffchainIndexSet(key, value)), Extrinsic::OffchainIndexClear(key) => Ok(Extrinsic::OffchainIndexClear(key)), Extrinsic::Store(data) => Ok(Extrinsic::Store(data)), @@ -265,9 +262,9 @@ pub type BlockNumber = u64; /// Index of a transaction. pub type Index = u64; /// The item of a block digest. -pub type DigestItem = sp_runtime::generic::DigestItem; +pub type DigestItem = sp_runtime::generic::DigestItem; /// The digest of a block. -pub type Digest = sp_runtime::generic::Digest; +pub type Digest = sp_runtime::generic::Digest; /// A test block. pub type Block = sp_runtime::generic::Block; /// A test block's header. @@ -1264,15 +1261,13 @@ fn test_witness(proof: StorageProof, root: crate::Hash) { let db: sp_trie::MemoryDB = proof.into_memory_db(); let backend = sp_state_machine::TrieBackend::<_, crate::Hashing>::new(db, root); let mut overlay = sp_state_machine::OverlayedChanges::default(); - let mut cache = sp_state_machine::StorageTransactionCache::<_, _, BlockNumber>::default(); + let mut cache = sp_state_machine::StorageTransactionCache::<_, _>::default(); let mut ext = sp_state_machine::Ext::new( &mut overlay, &mut cache, &backend, #[cfg(feature = "std")] None, - #[cfg(feature = "std")] - None, ); assert!(ext.storage(b"value3").is_some()); assert!(ext.storage_root().as_slice() == &root[..]); diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 334569d055a0c..165fe0355628e 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -24,12 +24,8 @@ use crate::{ use codec::{Decode, Encode, KeyedVec}; use frame_support::{decl_module, decl_storage, storage}; use frame_system::Config; -use sp_core::{storage::well_known_keys, ChangesTrieConfiguration}; -use sp_io::{ - hashing::blake2_256, - storage::{changes_root as storage_changes_root, root as storage_root}, - trie, -}; +use sp_core::storage::well_known_keys; +use sp_io::{hashing::blake2_256, storage::root as storage_root, trie}; use sp_runtime::{ generic, traits::Header as _, @@ -54,7 +50,6 @@ decl_storage! { Number get(fn number): Option; ParentHash get(fn parent_hash): Hash; NewAuthorities get(fn new_authorities): Option>; - NewChangesTrieConfig get(fn new_changes_trie_config): Option>; StorageDigest get(fn storage_digest): Option; Authorities get(fn authorities) config(): Vec; } @@ -207,30 +202,17 @@ pub fn finalize_block() -> Header { let mut digest = ::take().expect("StorageDigest is set by `initialize_block`"); let o_new_authorities = ::take(); - let new_changes_trie_config = ::take(); // This MUST come after all changes to storage are done. Otherwise we will fail the // “Storage root does not match that calculated” assertion. let storage_root = Hash::decode(&mut &storage_root()[..]).expect("`storage_root` is a valid hash"); - let storage_changes_root = storage_changes_root(&parent_hash.encode()) - .map(|r| Hash::decode(&mut &r[..]).expect("`storage_changes_root` is a valid hash")); - - if let Some(storage_changes_root) = storage_changes_root { - digest.push(generic::DigestItem::ChangesTrieRoot(storage_changes_root)); - } if let Some(new_authorities) = o_new_authorities { digest.push(generic::DigestItem::Consensus(*b"aura", new_authorities.encode())); digest.push(generic::DigestItem::Consensus(*b"babe", new_authorities.encode())); } - if let Some(new_config) = new_changes_trie_config { - digest.push(generic::DigestItem::ChangesTrieSignal( - generic::ChangesTrieSignal::NewConfiguration(new_config), - )); - } - Header { number, extrinsics_root, state_root: storage_root, parent_hash, digest } } @@ -251,8 +233,6 @@ fn execute_transaction_backend(utx: &Extrinsic, extrinsic_index: u32) -> ApplyEx Extrinsic::IncludeData(_) => Ok(Ok(())), Extrinsic::StorageChange(key, value) => execute_storage_change(key, value.as_ref().map(|v| &**v)), - Extrinsic::ChangesTrieConfigUpdate(ref new_config) => - execute_changes_trie_config_update(new_config.clone()), Extrinsic::OffchainIndexSet(key, value) => { sp_io::offchain_index::set(&key, &value); Ok(Ok(())) @@ -311,18 +291,6 @@ fn execute_storage_change(key: &[u8], value: Option<&[u8]>) -> ApplyExtrinsicRes Ok(Ok(())) } -fn execute_changes_trie_config_update( - new_config: Option, -) -> ApplyExtrinsicResult { - match new_config.clone() { - Some(new_config) => - storage::unhashed::put_raw(well_known_keys::CHANGES_TRIE_CONFIG, &new_config.encode()), - None => storage::unhashed::kill(well_known_keys::CHANGES_TRIE_CONFIG), - } - ::put(new_config); - Ok(Ok(())) -} - #[cfg(feature = "std")] fn info_expect_equal_hash(given: &Hash, expected: &Hash) { use sp_core::hexdisplay::HexDisplay; diff --git a/test-utils/test-runner/src/client.rs b/test-utils/test-runner/src/client.rs index 27c04c40fe6fe..c68a33056c163 100644 --- a/test-utils/test-runner/src/client.rs +++ b/test-utils/test-runner/src/client.rs @@ -159,7 +159,6 @@ where transaction_pool: transaction_pool.clone(), spawn_handle: task_manager.spawn_handle(), import_queue, - on_demand: None, block_announce_validator_builder: None, warp_sync: None, }; @@ -195,14 +194,12 @@ where backend: backend.clone(), task_manager: &mut task_manager, keystore: keystore.sync_keystore(), - on_demand: None, transaction_pool: transaction_pool.clone(), rpc_extensions_builder: Box::new(move |_, _| { let mut io = jsonrpc_core::IoHandler::default(); io.extend_with(ManualSealApi::to_delegate(ManualSeal::new(rpc_sink.clone()))); Ok(io) }), - remote_blockchain: None, network, system_rpc_tx, telemetry: None, diff --git a/test-utils/test-runner/src/node.rs b/test-utils/test-runner/src/node.rs index 9114013b747f7..07259263c5e4d 100644 --- a/test-utils/test-runner/src/node.rs +++ b/test-utils/test-runner/src/node.rs @@ -25,10 +25,7 @@ use futures::{ }; use jsonrpc_core::MetaIoHandler; use manual_seal::EngineCommand; -use sc_client_api::{ - backend::{self, Backend}, - CallExecutor, ExecutorProvider, -}; +use sc_client_api::{backend::Backend, CallExecutor, ExecutorProvider}; use sc_executor::NativeElseWasmExecutor; use sc_service::{TFullBackend, TFullCallExecutor, TFullClient, TaskManager}; use sc_transaction_pool_api::TransactionPool; @@ -160,9 +157,6 @@ where { let id = BlockId::Hash(self.client.info().best_hash); let mut overlay = OverlayedChanges::default(); - let changes_trie = - backend::changes_tries_state_at_block(&id, self.backend.changes_trie_storage()) - .unwrap(); let mut cache = StorageTransactionCache::< T::Block, as Backend>::State, @@ -176,13 +170,7 @@ where .state_at(id.clone()) .expect(&format!("State at block {} not found", id)); - let mut ext = Ext::new( - &mut overlay, - &mut cache, - &state_backend, - changes_trie.clone(), - Some(&mut extensions), - ); + let mut ext = Ext::new(&mut overlay, &mut cache, &state_backend, Some(&mut extensions)); sp_externalities::set_and_run_with_externalities(&mut ext, closure) } diff --git a/utils/frame/benchmarking-cli/src/command.rs b/utils/frame/benchmarking-cli/src/command.rs index 5efa970d93580..48d05dd8dda9c 100644 --- a/utils/frame/benchmarking-cli/src/command.rs +++ b/utils/frame/benchmarking-cli/src/command.rs @@ -33,7 +33,7 @@ use sp_core::offchain::{ }; use sp_externalities::Extensions; use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStorePtr}; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_state_machine::StateMachine; use std::{fmt::Debug, sync::Arc, time}; @@ -152,9 +152,8 @@ impl BenchmarkCmd { // Get Benchmark List let state = &state_without_tracking; - let result = StateMachine::<_, _, NumberFor, _>::new( + let result = StateMachine::new( state, - None, &mut changes, &executor, "Benchmark_benchmark_metadata", @@ -243,9 +242,8 @@ impl BenchmarkCmd { if !self.no_verify { // Dont use these results since verification code will add overhead let state = &state_without_tracking; - let _results = StateMachine::<_, _, NumberFor, _>::new( + let _results = StateMachine::new( state, - None, &mut changes, &executor, "Benchmark_dispatch_benchmark", @@ -270,9 +268,8 @@ impl BenchmarkCmd { // Do one loop of DB tracking. { let state = &state_with_tracking; - let result = StateMachine::<_, _, NumberFor, _>::new( + let result = StateMachine::new( state, // todo remove tracking - None, &mut changes, &executor, "Benchmark_dispatch_benchmark", @@ -303,9 +300,8 @@ impl BenchmarkCmd { // Finally run a bunch of loops to get extrinsic timing information. for r in 0..self.external_repeat { let state = &state_without_tracking; - let result = StateMachine::<_, _, NumberFor, _>::new( + let result = StateMachine::new( state, // todo remove tracking - None, &mut changes, &executor, "Benchmark_dispatch_benchmark", diff --git a/utils/frame/rpc/system/src/lib.rs b/utils/frame/rpc/system/src/lib.rs index f0f37f0b20675..41a5f3ba0eb3e 100644 --- a/utils/frame/rpc/system/src/lib.rs +++ b/utils/frame/rpc/system/src/lib.rs @@ -20,14 +20,13 @@ use std::sync::Arc; use codec::{Codec, Decode, Encode}; -use futures::{future::ready, FutureExt, TryFutureExt}; +use futures::FutureExt; use jsonrpc_core::{Error as RpcError, ErrorCode}; use jsonrpc_derive::rpc; -use sc_client_api::light::{future_header, Fetcher, RemoteBlockchain, RemoteCallRequest}; use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_block_builder::BlockBuilder; -use sp_blockchain::{Error as ClientError, HeaderBackend}; +use sp_blockchain::HeaderBackend; use sp_core::{hexdisplay::HexDisplay, Bytes}; use sp_runtime::{generic::BlockId, traits}; @@ -154,90 +153,6 @@ where } } -/// An implementation of System-specific RPC methods on light client. -pub struct LightSystem { - client: Arc, - remote_blockchain: Arc>, - fetcher: Arc, - pool: Arc

, -} - -impl LightSystem { - /// Create new `LightSystem`. - pub fn new( - client: Arc, - remote_blockchain: Arc>, - fetcher: Arc, - pool: Arc

, - ) -> Self { - LightSystem { client, remote_blockchain, fetcher, pool } - } -} - -impl SystemApi<::Hash, AccountId, Index> - for LightSystem -where - P: TransactionPool + 'static, - C: HeaderBackend, - C: Send + Sync + 'static, - F: Fetcher + 'static, - Block: traits::Block, - AccountId: Clone + std::fmt::Display + Codec + Send + 'static, - Index: Clone + std::fmt::Display + Codec + Send + traits::AtLeast32Bit + 'static, -{ - fn nonce(&self, account: AccountId) -> FutureResult { - let best_hash = self.client.info().best_hash; - let best_id = BlockId::hash(best_hash); - let future_best_header = future_header(&*self.remote_blockchain, &*self.fetcher, best_id); - let fetcher = self.fetcher.clone(); - let call_data = account.encode(); - let future_best_header = future_best_header.and_then(move |maybe_best_header| { - ready( - maybe_best_header - .ok_or_else(|| ClientError::UnknownBlock(format!("{}", best_hash))), - ) - }); - - let future_nonce = future_best_header.and_then(move |best_header| { - fetcher.remote_call(RemoteCallRequest { - block: best_hash, - header: best_header, - method: "AccountNonceApi_account_nonce".into(), - call_data, - retry_count: None, - }) - }); - - let future_nonce = future_nonce.and_then(|nonce| async move { - Index::decode(&mut &nonce[..]) - .map_err(|e| ClientError::CallResultDecode("Cannot decode account nonce", e)) - }); - let future_nonce = future_nonce.map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to query nonce.".into(), - data: Some(format!("{:?}", e).into()), - }); - - let pool = self.pool.clone(); - future_nonce.map_ok(move |nonce| adjust_nonce(&*pool, account, nonce)).boxed() - } - - fn dry_run( - &self, - _extrinsic: Bytes, - _at: Option<::Hash>, - ) -> FutureResult { - async { - Err(RpcError { - code: ErrorCode::MethodNotFound, - message: "Unable to dry run extrinsic.".into(), - data: None, - }) - } - .boxed() - } -} - /// Adjust account nonce from state, so that tx with the nonce will be /// placed after all ready txpool transactions. fn adjust_nonce(pool: &P, account: AccountId, nonce: Index) -> Index diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index 27fb35dd7a46a..70f177dc1f869 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -152,12 +152,7 @@ where .map_err(|e| format!("failed to decode output: {:?}", e))?; let storage_changes = changes - .drain_storage_changes::<_, _, NumberFor>( - &state_ext.backend, - None, - Default::default(), - &mut Default::default(), - ) + .drain_storage_changes(&state_ext.backend, Default::default(), &mut Default::default()) .unwrap(); state_ext.backend.apply_transaction( storage_changes.transaction_storage_root, diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index a74625492bb1c..4aa1c213703ed 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -680,9 +680,8 @@ pub(crate) fn state_machine_call sc_cli::Result<(OverlayedChanges, Vec)> { let mut changes = Default::default(); - let encoded_results = StateMachine::<_, _, NumberFor, _>::new( + let encoded_results = StateMachine::new( &ext.backend, - None, &mut changes, executor, method, From 9e8c7b80e9c167dc81244cdae0097d463c1b2e66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Nov 2021 14:42:26 +0100 Subject: [PATCH 0223/1472] Bump rustversion from 1.0.4 to 1.0.5 (#10243) Bumps [rustversion](https://github.com/dtolnay/rustversion) from 1.0.4 to 1.0.5. - [Release notes](https://github.com/dtolnay/rustversion/releases) - [Commits](https://github.com/dtolnay/rustversion/compare/1.0.4...1.0.5) --- updated-dependencies: - dependency-name: rustversion 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 ++-- frame/support/test/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74504d5f1547b..998072f2f9327 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7510,9 +7510,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" +checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" [[package]] name = "rw-stream-sink" diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 762c85f75c363..09a1538e2741d 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -25,7 +25,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../pri sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } trybuild = "1.0.52" pretty_assertions = "1.0.0" -rustversion = "1.0.0" +rustversion = "1.0.5" frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } # The "std" feature for this pallet is never activated on purpose, in order to test construct_runtime error message test-pallet = { package = "frame-support-test-pallet", default-features = false, path = "pallet" } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 8c274b386470a..dccc123142dac 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -22,7 +22,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-build codec = { package = "parity-scale-codec", version = "2.0.0" } sp-state-machine = { version = "0.10.0-dev", path = "../../state-machine" } trybuild = "1.0.52" -rustversion = "1.0.0" +rustversion = "1.0.5" [dev-dependencies] criterion = "0.3.0" diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index c640f02824f24..dd93b92b9be4e 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -30,7 +30,7 @@ sp-runtime-interface-test-wasm = { version = "2.0.0", path = "test-wasm" } sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } sp-core = { version = "4.0.0-dev", path = "../core" } sp-io = { version = "4.0.0-dev", path = "../io" } -rustversion = "1.0.0" +rustversion = "1.0.5" trybuild = "1.0.52" [features] From 3f3cc90c06a1e0a7a93dbd5b660a475e9b4a783e Mon Sep 17 00:00:00 2001 From: Sergei Shulepov Date: Fri, 12 Nov 2021 20:38:26 +0100 Subject: [PATCH 0224/1472] Update requirement for pwasm-utils (#10250) --- client/executor/common/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 276fe9a8380b4..1bb057fabad84 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] derive_more = "0.99.2" -pwasm-utils = "0.18.0" +pwasm-utils = "0.18.2" codec = { package = "parity-scale-codec", version = "2.0.0" } wasmi = "0.9.1" sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } From 54699ec8220fd13fa353f1846db0c923a0fdc310 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Nov 2021 00:32:44 +0000 Subject: [PATCH 0225/1472] Bump hex-literal from 0.3.3 to 0.3.4 (#10246) Bumps [hex-literal](https://github.com/RustCrypto/utils) from 0.3.3 to 0.3.4. - [Release notes](https://github.com/RustCrypto/utils/releases) - [Commits](https://github.com/RustCrypto/utils/compare/hex-literal-v0.3.3...hex-literal-v0.3.4) --- 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 | 4 ++-- bin/node-template/runtime/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 2 +- frame/executive/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 998072f2f9327..c90cf1cf52861 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2598,9 +2598,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-literal" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" [[package]] name = "hex_fmt" diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index e4e2039866b46..bff47f5a7ea39 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -45,7 +45,7 @@ pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", default-fe # Used for runtime benchmarking frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/benchmarking", optional = true } frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system/benchmarking", optional = true } -hex-literal = { version = "0.3.3", optional = true } +hex-literal = { version = "0.3.4", optional = true } pallet-template = { version = "3.0.0", default-features = false, path = "../pallets/template" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index fc39e47ce4113..4e29c7c5314e2 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -37,7 +37,7 @@ crate-type = ["cdylib", "rlib"] codec = { package = "parity-scale-codec", version = "2.0.0" } serde = { version = "1.0.126", features = ["derive"] } futures = "0.3.16" -hex-literal = "0.3.3" +hex-literal = "0.3.4" log = "0.4.8" rand = "0.7.2" structopt = { version = "0.3.8", optional = true } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index c0b888e55b1f6..d086b6f12d590 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } static_assertions = "1.1.0" -hex-literal = { version = "0.3.3", optional = true } +hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.14", default-features = false } # primitives diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 54c4a91d72805..4a8e678105437 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -37,7 +37,7 @@ sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/c [dev-dependencies] wat = "1.0" -hex-literal = "0.3.3" +hex-literal = "0.3.4" sc-runtime-test = { version = "2.0.0", path = "runtime-test" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 7694e0f6893d6..114473b66c975 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] hex = "0.4" -hex-literal = "0.3.3" +hex-literal = "0.3.4" tempfile = "3.1.0" tokio = { version = "1.10.0", features = ["time"] } log = "0.4.8" diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index fdc386978dee5..a6bfcf2a552fc 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -28,7 +28,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys log = { version = "0.4.14", default-features = false } [dev-dependencies] -hex-literal = "0.3.3" +hex-literal = "0.3.4" [features] default = ["std"] diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 52d2f41cb1e34..20e31fe0a5720 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -26,7 +26,7 @@ sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primiti sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } [dev-dependencies] -hex-literal = "0.3.3" +hex-literal = "0.3.4" sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 7167ae7424571..a8c6e60af2f82 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.126", optional = true } -hex-literal = { version = "0.3.3", optional = true } +hex-literal = { version = "0.3.4", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index eaf1d26c2898c..dc8904f33e0c1 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -73,7 +73,7 @@ sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = [dev-dependencies] sp-serializer = { version = "4.0.0-dev", path = "../serializer" } -hex-literal = "0.3.3" +hex-literal = "0.3.4" rand = "0.7.2" criterion = "0.3.3" serde_json = "1.0" diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 783837a6442b6..0133ea17370a8 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -32,7 +32,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } tracing = { version = "0.1.29", optional = true } [dev-dependencies] -hex-literal = "0.3.3" +hex-literal = "0.3.4" sp-runtime = { version = "4.0.0-dev", path = "../runtime" } pretty_assertions = "1.0.0" rand = "0.7.2" diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 6190df210403c..8eaeb424781bf 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -31,7 +31,7 @@ sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } trie-bench = "0.28.0" trie-standardmap = "0.15.2" criterion = "0.3.3" -hex-literal = "0.3.3" +hex-literal = "0.3.4" sp-runtime = { version = "4.0.0-dev", path = "../runtime" } [features] From b01bd3162dd3909f9eba33ba0e63ab074f26d53f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Nov 2021 02:35:07 +0000 Subject: [PATCH 0226/1472] Bump structopt from 0.3.23 to 0.3.25 (#10253) * Bump structopt from 0.3.23 to 0.3.25 Bumps [structopt](https://github.com/TeXitoi/structopt) from 0.3.23 to 0.3.25. - [Release notes](https://github.com/TeXitoi/structopt/releases) - [Changelog](https://github.com/TeXitoi/structopt/blob/master/CHANGELOG.md) - [Commits](https://github.com/TeXitoi/structopt/compare/v0.3.23...v0.3.25) --- updated-dependencies: - dependency-name: structopt dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * cargo fmt Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Keith Yeung --- Cargo.lock | 8 ++++---- bin/node-template/node/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 4 ++-- bin/utils/chain-spec-builder/Cargo.toml | 2 +- bin/utils/subkey/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/babe/src/verification.rs | 4 ++-- client/network/src/protocol/notifications/behaviour.rs | 4 ++-- client/network/src/protocol/sync/blocks.rs | 2 +- client/network/src/service/tests.rs | 2 +- client/network/src/transactions.rs | 4 ++-- frame/bags-list/remote-tests/Cargo.toml | 2 +- frame/election-provider-multi-phase/src/lib.rs | 2 +- .../support/procedural/src/pallet/parse/pallet_struct.rs | 4 ++-- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/frame-utilities-cli/Cargo.toml | 2 +- utils/frame/generate-bags/Cargo.toml | 2 +- utils/frame/generate-bags/node-runtime/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 20 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c90cf1cf52861..e41a6c867177f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10010,9 +10010,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "structopt" -version = "0.3.23" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa" +checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c" dependencies = [ "clap", "lazy_static", @@ -10021,9 +10021,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.16" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck", "proc-macro-error", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 1d8abad406a14..6f3a63593aa3e 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] name = "node-template" [dependencies] -structopt = "0.3.8" +structopt = "0.3.25" sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 4e29c7c5314e2..374015a3426c9 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -40,7 +40,7 @@ futures = "0.3.16" hex-literal = "0.3.4" log = "0.4.8" rand = "0.7.2" -structopt = { version = "0.3.8", optional = true } +structopt = { version = "0.3.25", optional = true } # primitives sp-authority-discovery = { version = "4.0.0-dev", path = "../../../primitives/authority-discovery" } @@ -136,7 +136,7 @@ remote-externalities = { path = "../../../utils/frame/remote-externalities" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } [build-dependencies] -structopt = { version = "0.3.8", optional = true } +structopt = { version = "0.3.25", optional = true } node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } frame-benchmarking-cli = { version = "4.0.0-dev", optional = true, path = "../../../utils/frame/benchmarking-cli" } substrate-build-script-utils = { version = "3.0.0", optional = true, path = "../../../utils/build-script-utils" } diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index a35fbba5cdc46..daffd5a0359a5 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -21,4 +21,4 @@ node-cli = { version = "3.0.0-dev", path = "../../node/cli" } sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } rand = "0.7.2" -structopt = "0.3.8" +structopt = "0.3.25" diff --git a/bin/utils/subkey/Cargo.toml b/bin/utils/subkey/Cargo.toml index 14ba673b33be2..d3c38edb5771d 100644 --- a/bin/utils/subkey/Cargo.toml +++ b/bin/utils/subkey/Cargo.toml @@ -18,4 +18,4 @@ name = "subkey" [dependencies] sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } -structopt = "0.3.14" +structopt = "0.3.25" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 9dc7ff730600b..b027063b109a8 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -38,7 +38,7 @@ sc-service = { version = "0.10.0-dev", default-features = false, path = "../serv sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } names = { version = "0.12.0", default-features = false } -structopt = "0.3.8" +structopt = "0.3.25" sc-tracing = { version = "4.0.0-dev", path = "../tracing" } chrono = "0.4.10" serde = "1.0.126" diff --git a/client/consensus/babe/src/verification.rs b/client/consensus/babe/src/verification.rs index 174b2d03c6ef0..2322a96262161 100644 --- a/client/consensus/babe/src/verification.rs +++ b/client/consensus/babe/src/verification.rs @@ -111,7 +111,7 @@ pub(super) fn check_header( ); check_secondary_plain_header::(pre_hash, secondary, sig, &epoch)?; - } + }, PreDigest::SecondaryVRF(secondary) if epoch.config.allowed_slots.is_secondary_vrf_slots_allowed() => { @@ -122,7 +122,7 @@ pub(super) fn check_header( ); check_secondary_vrf_header::(pre_hash, secondary, sig, &epoch)?; - } + }, _ => return Err(babe_err(Error::SecondarySlotAssignmentsDisabled)), } diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 01138e3207570..f66f1fbe9e95a 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -712,7 +712,7 @@ impl Notifications { timer: delay_id, timer_deadline: *backoff, }; - } + }, // Disabled => Enabled PeerState::Disabled { mut connections, backoff_until } => { @@ -2085,7 +2085,7 @@ impl NetworkBehaviour for Notifications { .boxed(), ); } - } + }, // We intentionally never remove elements from `delays`, and it may // thus contain obsolete entries. This is a normal situation. diff --git a/client/network/src/protocol/sync/blocks.rs b/client/network/src/protocol/sync/blocks.rs index 30ba7ffafeffc..ce4535dc0b45f 100644 --- a/client/network/src/protocol/sync/blocks.rs +++ b/client/network/src/protocol/sync/blocks.rs @@ -203,7 +203,7 @@ impl BlockCollection { { *downloading -= 1; false - } + }, Some(&mut BlockRangeState::Downloading { .. }) => true, _ => false, }; diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 1c66986e422fc..8271da886fca7 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -529,7 +529,7 @@ fn fallback_name_working() { { assert_eq!(negotiated_fallback, Some(PROTOCOL_NAME)); break - } + }, _ => {}, }; } diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 99350f603a375..6d190651160f0 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -336,13 +336,13 @@ impl TransactionsHandler { }, ); debug_assert!(_was_in.is_none()); - } + }, Event::NotificationStreamClosed { remote, protocol } if protocol == self.protocol_name => { let _peer = self.peers.remove(&remote); debug_assert!(_peer.is_some()); - } + }, Event::NotificationsReceived { remote, messages } => { for (protocol, message) in messages { diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 37f351f0d27ef..ecc0b4da242c7 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -33,5 +33,5 @@ remote-externalities = { path = "../../../utils/frame/remote-externalities", ver # others tokio = { version = "1", features = ["macros"] } log = "0.4.14" -structopt = "0.3.23" +structopt = "0.3.25" clap = "2.33.3" diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 80a13aa99fb70..4c4de82af592f 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -772,7 +772,7 @@ pub mod pallet { Self::on_initialize_open_unsigned(enabled, now); T::WeightInfo::on_initialize_open_unsigned() } - } + }, _ => T::WeightInfo::on_initialize_nothing(), } } diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index 278f46e13818e..c528faf669ee3 100644 --- a/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -130,12 +130,12 @@ impl PalletStructDef { if generate_storage_info.is_none() => { generate_storage_info = Some(span); - } + }, PalletStructAttr::StorageVersion { storage_version, .. } if storage_version_found.is_none() => { storage_version_found = Some(storage_version); - } + }, attr => { let msg = "Unexpected duplicated attribute"; return Err(syn::Error::new(attr.span(), msg)) diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index f9fce9d8744da..59d12c5a5d2ee 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -20,7 +20,7 @@ honggfuzz = "0.5" rand = { version = "0.7.3", features = ["std", "small_rng"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } -structopt = "0.3.21" +structopt = "0.3.25" [[bin]] name = "reduce" diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 605a14e3adff7..03520f9cbd5d7 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -25,7 +25,7 @@ sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } codec = { version = "2.0.0", package = "parity-scale-codec" } -structopt = "0.3.8" +structopt = "0.3.25" chrono = "0.4" serde = "1.0.126" handlebars = "3.5.0" diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index 9d14819337419..dfbf73ee9d5fa 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -structopt = "0.3.8" +structopt = "0.3.25" frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 4bc27021b4c57..2c9374fc5cca4 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -23,4 +23,4 @@ sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } chrono = { version = "0.4.19" } git2 = { version = "0.13.23", default-features = false } num-format = { version = "0.4.0" } -structopt = "0.3.21" +structopt = "0.3.25" diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml index b0256722f466c..b5a7e0b898c92 100644 --- a/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -14,4 +14,4 @@ node-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runtime" } generate-bags = { version = "4.0.0-dev", path = "../" } # third-party -structopt = "0.3.21" +structopt = "0.3.25" diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index a89a625bbd9ed..44be678ba3814 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] log = "0.4.8" parity-scale-codec = { version = "2.3.1" } serde = "1.0.126" -structopt = "0.3.8" +structopt = "0.3.25" sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../../client/service" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } From ab40c7ef81b1ecdce254c1b76bbaf559b5473576 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Nov 2021 19:56:41 +0100 Subject: [PATCH 0227/1472] Bump nix from 0.19.1 to 0.23.0 (#10254) Bumps [nix](https://github.com/nix-rust/nix) from 0.19.1 to 0.23.0. - [Release notes](https://github.com/nix-rust/nix/releases) - [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md) - [Commits](https://github.com/nix-rust/nix/compare/v0.19.1...v0.23.0) --- updated-dependencies: - dependency-name: nix 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 | 5 +++-- bin/node/cli/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e41a6c867177f..7c32ecb3f36d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4469,14 +4469,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.19.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2" +checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188" dependencies = [ "bitflags", "cc", "cfg-if 1.0.0", "libc", + "memoffset", ] [[package]] diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 374015a3426c9..122f2d0c2c8fc 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -122,7 +122,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" futures = "0.3.16" tempfile = "3.1.0" assert_cmd = "2.0.2" -nix = "0.19" +nix = "0.23" serde_json = "1.0" regex = "1" platforms = "1.1" From ed60316879773b5d81cad4525fd9c1a511de2952 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Nov 2021 21:27:46 +0100 Subject: [PATCH 0228/1472] Bump cargo_metadata from 0.13.1 to 0.14.1 (#10255) Bumps [cargo_metadata](https://github.com/oli-obk/cargo_metadata) from 0.13.1 to 0.14.1. - [Release notes](https://github.com/oli-obk/cargo_metadata/releases) - [Commits](https://github.com/oli-obk/cargo_metadata/compare/v0.13.1...0.14.1) --- updated-dependencies: - dependency-name: cargo_metadata 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 | 11 ++++++----- utils/wasm-builder/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c32ecb3f36d1..57bf1278822c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -812,14 +812,13 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.13.1" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081e3f0755c1f380c2d010481b6fa2e02973586d5f2b24eebb7a2a1d98b143d8" +checksum = "ba2ae6de944143141f6155a473a6b02f66c7c3f9f47316f802f80204ebfe6e12" dependencies = [ "camino", "cargo-platform", - "semver 0.11.0", - "semver-parser 0.10.2", + "semver 1.0.4", "serde", "serde_json", ] @@ -8844,7 +8843,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ "semver-parser 0.10.2", - "serde", ] [[package]] @@ -8852,6 +8850,9 @@ name = "semver" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +dependencies = [ + "serde", +] [[package]] name = "semver-parser" diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index 88318f4f0d54c..a2a56a5bf22cf 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] build-helper = "0.1.1" -cargo_metadata = "0.13.1" +cargo_metadata = "0.14.1" tempfile = "3.1.0" toml = "0.5.4" walkdir = "2.3.2" From ee8ac3a6c9c9292911afbf5ec16fbb2bb0d44b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 13 Nov 2021 23:57:19 +0100 Subject: [PATCH 0229/1472] Fix cargo unleash check (#10261) --- utils/frame/remote-externalities/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 56f797343c0f4..8f54dd01df0a3 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] jsonrpsee = { version = "0.4.1", features = ["ws-client", "macros"] } env_logger = "0.9" -frame-support = { path = "../../../frame/support", optional = true } +frame-support = { path = "../../../frame/support", optional = true, version = "4.0.0-dev" } log = "0.4.11" codec = { package = "parity-scale-codec", version = "2.0.0" } serde_json = "1.0" From 1b646b219e0e0c7489a2a8488381fc2e32da6a1c Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sun, 14 Nov 2021 15:04:20 +0000 Subject: [PATCH 0230/1472] rework `staking::reap_stash` (#10178) * rework reap_stash * Update frame/staking/src/pallet/mod.rs Co-authored-by: Zeke Mostov * Update frame/staking/src/pallet/mod.rs Co-authored-by: Zeke Mostov * Update frame/staking/src/pallet/mod.rs Co-authored-by: Zeke Mostov * Fix Co-authored-by: Shawn Tabrizi Co-authored-by: Zeke Mostov --- frame/staking/src/benchmarking.rs | 5 +- frame/staking/src/pallet/mod.rs | 40 +++++----- frame/staking/src/tests.rs | 118 +++++++----------------------- 3 files changed, 50 insertions(+), 113 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 80630818de7e6..e312aedbec1f3 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -28,7 +28,7 @@ use frame_support::{ traits::{Currency, CurrencyToVote, Get, Imbalance}, }; use sp_runtime::{ - traits::{StaticLookup, Zero}, + traits::{Bounded, One, StaticLookup, Zero}, Perbill, Percent, }; use sp_staking::SessionIndex; @@ -38,7 +38,6 @@ pub use frame_benchmarking::{ account, benchmarks, impl_benchmark_test_suite, whitelist_account, whitelisted_caller, }; use frame_system::RawOrigin; -use sp_runtime::traits::{Bounded, One}; const SEED: u32 = 0; const MAX_SPANS: u32 = 100; @@ -695,7 +694,7 @@ benchmarks! { let stash = scenario.origin_stash1.clone(); add_slashing_spans::(&stash, s); - T::Currency::make_free_balance_be(&stash, T::Currency::minimum_balance()); + Ledger::::insert(&controller, StakingLedger { active: T::Currency::minimum_balance() - One::one(), total: T::Currency::minimum_balance() - One::one(), ..Default::default() }); assert!(Bonded::::contains_key(&stash)); assert!(T::SortedListProvider::contains(&stash)); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 8e97a90e07544..197c2eed325a1 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -1425,33 +1425,37 @@ pub mod pallet { Ok(()) } - /// Remove all data structure concerning a staker/stash once its balance is at the minimum. - /// This is essentially equivalent to `withdraw_unbonded` except it can be called by anyone - /// and the target `stash` must have no funds left beyond the ED. + /// Remove all data structures concerning a staker/stash once it is at a state where it can + /// be considered `dust` in the staking system. The requirements are: /// - /// This can be called from any origin. + /// 1. the `total_balance` of the stash is below existential deposit. + /// 2. or, the `ledger.total` of the stash is below existential deposit. /// - /// - `stash`: The stash account to reap. Its balance must be zero. + /// The former can happen in cases like a slash; the latter when a fully unbonded account + /// is still receiving staking rewards in `RewardDestination::Staked`. /// - /// # - /// Complexity: O(S) where S is the number of slashing spans on the account. - /// DB Weight: - /// - Reads: Stash Account, Bonded, Slashing Spans, Locks - /// - Writes: Bonded, Slashing Spans (if S > 0), Ledger, Payee, Validators, Nominators, - /// Stash Account, Locks - /// - Writes Each: SpanSlash * S - /// # + /// It can be called by anyone, as long as `stash` meets the above requirements. + /// + /// Refunds the transaction fees upon successful execution. #[pallet::weight(T::WeightInfo::reap_stash(*num_slashing_spans))] pub fn reap_stash( - _origin: OriginFor, + origin: OriginFor, stash: T::AccountId, num_slashing_spans: u32, - ) -> DispatchResult { - let at_minimum = T::Currency::total_balance(&stash) == T::Currency::minimum_balance(); - ensure!(at_minimum, Error::::FundedTarget); + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + + let ed = T::Currency::minimum_balance(); + let reapable = T::Currency::total_balance(&stash) < ed || + Self::ledger(Self::bonded(stash.clone()).ok_or(Error::::NotStash)?) + .map(|l| l.total) + .unwrap_or_default() < ed; + ensure!(reapable, Error::::FundedTarget); + Self::kill_stash(&stash, num_slashing_spans)?; T::Currency::remove_lock(STAKING_ID, &stash); - Ok(()) + + Ok(Pays::No.into()) } /// Remove the given nominations from the calling validator. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index d6d92d5bd57fc..8e8a7ee636d8d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1633,115 +1633,49 @@ fn reward_to_stake_works() { } #[test] -fn on_free_balance_zero_stash_removes_validator() { - // Tests that validator storage items are cleaned up when stash is empty - // Tests that storage items are untouched when controller is empty +fn reap_stash_works() { ExtBuilder::default() .existential_deposit(10) .balance_factor(10) .build_and_execute(|| { - // Check the balance of the validator account + // given assert_eq!(Balances::free_balance(10), 10); - // Check the balance of the stash account - assert_eq!(Balances::free_balance(11), 10 * 1000); - // Check these two accounts are bonded - assert_eq!(Staking::bonded(&11), Some(10)); - - // Set payee information - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash)); - - // Check storage items that should be cleaned up - assert!(>::contains_key(&10)); - assert!(>::contains_key(&11)); - assert!(>::contains_key(&11)); - assert!(>::contains_key(&11)); - - // Reduce free_balance of controller to 0 - let _ = Balances::slash(&10, Balance::max_value()); - - // Check the balance of the stash account has not been touched assert_eq!(Balances::free_balance(11), 10 * 1000); - // Check these two accounts are still bonded assert_eq!(Staking::bonded(&11), Some(10)); - // Check storage items have not changed assert!(>::contains_key(&10)); assert!(>::contains_key(&11)); assert!(>::contains_key(&11)); assert!(>::contains_key(&11)); - // Reduce free_balance of stash to 0 - let _ = Balances::slash(&11, Balance::max_value()); - // Check total balance of stash - assert_eq!(Balances::total_balance(&11), 10); - - // Reap the stash - assert_ok!(Staking::reap_stash(Origin::none(), 11, 0)); - - // Check storage items do not exist - assert!(!>::contains_key(&10)); - assert!(!>::contains_key(&11)); - assert!(!>::contains_key(&11)); - assert!(!>::contains_key(&11)); - assert!(!>::contains_key(&11)); - }); -} - -#[test] -fn on_free_balance_zero_stash_removes_nominator() { - // Tests that nominator storage items are cleaned up when stash is empty - // Tests that storage items are untouched when controller is empty - ExtBuilder::default() - .existential_deposit(10) - .balance_factor(10) - .build_and_execute(|| { - // Make 10 a nominator - assert_ok!(Staking::nominate(Origin::signed(10), vec![20])); - // Check that account 10 is a nominator - assert!(>::contains_key(11)); - // Check the balance of the nominator account - assert_eq!(Balances::free_balance(10), 10); - // Check the balance of the stash account - assert_eq!(Balances::free_balance(11), 10_000); - - // Set payee information - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash)); - - // Check storage items that should be cleaned up - assert!(>::contains_key(&10)); - assert!(>::contains_key(&11)); - assert!(>::contains_key(&11)); - assert!(>::contains_key(&11)); - - // Reduce free_balance of controller to 0 - let _ = Balances::slash(&10, Balance::max_value()); - // Check total balance of account 10 - assert_eq!(Balances::total_balance(&10), 0); - - // Check the balance of the stash account has not been touched - assert_eq!(Balances::free_balance(11), 10_000); - // Check these two accounts are still bonded - assert_eq!(Staking::bonded(&11), Some(10)); - - // Check storage items have not changed - assert!(>::contains_key(&10)); - assert!(>::contains_key(&11)); - assert!(>::contains_key(&11)); - assert!(>::contains_key(&11)); + // stash is not reapable + assert_noop!( + Staking::reap_stash(Origin::signed(20), 11, 0), + Error::::FundedTarget + ); + // controller or any other account is not reapable + assert_noop!(Staking::reap_stash(Origin::signed(20), 10, 0), Error::::NotStash); - // Reduce free_balance of stash to 0 - let _ = Balances::slash(&11, Balance::max_value()); - // Check total balance of stash - assert_eq!(Balances::total_balance(&11), 10); + // no easy way to cause an account to go below ED, we tweak their staking ledger + // instead. + Ledger::::insert( + 10, + StakingLedger { + stash: 11, + total: 5, + active: 5, + unlocking: vec![], + claimed_rewards: vec![], + }, + ); - // Reap the stash - assert_ok!(Staking::reap_stash(Origin::none(), 11, 0)); + // reap-able + assert_ok!(Staking::reap_stash(Origin::signed(20), 11, 0)); - // Check storage items do not exist + // then assert!(!>::contains_key(&10)); assert!(!>::contains_key(&11)); assert!(!>::contains_key(&11)); - assert!(!>::contains_key(&11)); assert!(!>::contains_key(&11)); }); } @@ -2556,10 +2490,10 @@ fn garbage_collection_after_slashing() { // reap_stash respects num_slashing_spans so that weight is accurate assert_noop!( - Staking::reap_stash(Origin::none(), 11, 0), + Staking::reap_stash(Origin::signed(20), 11, 0), Error::::IncorrectSlashingSpans ); - assert_ok!(Staking::reap_stash(Origin::none(), 11, 2)); + assert_ok!(Staking::reap_stash(Origin::signed(20), 11, 2)); assert!(::SlashingSpans::get(&11).is_none()); assert_eq!(::SpanSlash::get(&(11, 0)).amount_slashed(), &0); From 7db0768a85dc36a3f2a44d042b32f3715c00a90d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 15 Nov 2021 12:45:37 +0100 Subject: [PATCH 0231/1472] Keystore: Store files with permission 600 on unix (#10263) --- client/keystore/src/local.rs | 44 +++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index e5c8ff14af095..965e68336e3bc 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -364,8 +364,7 @@ impl KeystoreInner { let path = path.into(); fs::create_dir_all(&path)?; - let instance = Self { path: Some(path), additional: HashMap::new(), password }; - Ok(instance) + Ok(Self { path: Some(path), additional: HashMap::new(), password }) } /// Get the password for this store. @@ -397,10 +396,9 @@ impl KeystoreInner { /// Places it into the file system store, if a path is configured. fn insert_unknown(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<()> { if let Some(path) = self.key_file_path(public, key_type) { - let mut file = File::create(path).map_err(Error::Io)?; - serde_json::to_writer(&file, &suri).map_err(Error::Json)?; - file.flush().map_err(Error::Io)?; + Self::write_to_file(path, suri)?; } + Ok(()) } @@ -411,15 +409,29 @@ impl KeystoreInner { fn generate_by_type(&mut self, key_type: KeyTypeId) -> Result { let (pair, phrase, _) = Pair::generate_with_phrase(self.password()); if let Some(path) = self.key_file_path(pair.public().as_slice(), key_type) { - let mut file = File::create(path)?; - serde_json::to_writer(&file, &phrase)?; - file.flush()?; + Self::write_to_file(path, &phrase)?; } else { self.insert_ephemeral_pair(&pair, &phrase, key_type); } + Ok(pair) } + /// Write the given `data` to `file`. + fn write_to_file(file: PathBuf, data: &str) -> Result<()> { + let mut file = File::create(file)?; + serde_json::to_writer(&file, data)?; + file.flush()?; + + #[cfg(target_family = "unix")] + { + use std::os::unix::fs::PermissionsExt; + file.set_permissions(fs::Permissions::from_mode(0o600))?; + } + + Ok(()) + } + /// Create a new key from seed. /// /// Does not place it into the file system store. @@ -735,4 +747,20 @@ mod tests { SyncCryptoStore::sr25519_generate_new(&store, TEST_KEY_TYPE, None).unwrap(); assert_eq!(SyncCryptoStore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 2); } + + #[test] + #[cfg(target_family = "unix")] + fn uses_correct_file_permissions_on_unix() { + use std::os::unix::fs::PermissionsExt; + + let temp_dir = TempDir::new().unwrap(); + let store = LocalKeystore::open(temp_dir.path(), None).unwrap(); + + let public = SyncCryptoStore::sr25519_generate_new(&store, TEST_KEY_TYPE, None).unwrap(); + + let path = store.0.read().key_file_path(public.as_ref(), TEST_KEY_TYPE).unwrap(); + let permissions = File::open(path).unwrap().metadata().unwrap().permissions(); + + assert_eq!(0o100600, permissions.mode()); + } } From 7ebab91ed5179c3be7176c04d6a4f3996cb50563 Mon Sep 17 00:00:00 2001 From: Ayevbeosa Iyamu Date: Mon, 15 Nov 2021 20:16:03 +0100 Subject: [PATCH 0232/1472] Add field names to pallet `Event` variants (#10184) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Changed named fields to struct variants * Fixed errors. * Made adjustments as per `cargo +nightly fmt`. * Update frame/uniques/src/lib.rs Co-authored-by: Alexander Theißen * Removed redundant comments for structs. * Moved frame-support to dev dependencies Co-authored-by: Alexander Theißen --- frame/contracts/src/exec.rs | 8 +- frame/proxy/src/tests.rs | 6 +- frame/uniques/src/benchmarking.rs | 52 ++++---- frame/uniques/src/functions.rs | 13 +- frame/uniques/src/impl_nonfungibles.rs | 2 +- frame/uniques/src/lib.rs | 174 +++++++++++++++---------- frame/utility/src/lib.rs | 9 +- frame/utility/src/tests.rs | 20 ++- frame/vesting/src/lib.rs | 27 ++-- 9 files changed, 185 insertions(+), 126 deletions(-) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 7ef1aec2dfc60..90a640418bcc0 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -2157,10 +2157,10 @@ mod tests { }, EventRecord { phase: Phase::Initialization, - event: MetaEvent::Utility(pallet_utility::Event::BatchInterrupted( - 1, - frame_system::Error::::CallFiltered.into() - ),), + event: MetaEvent::Utility(pallet_utility::Event::BatchInterrupted { + index: 1, + error: frame_system::Error::::CallFiltered.into() + },), topics: vec![], }, ] diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 93a0e4ce7d622..ed21a80f62139 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -369,7 +369,8 @@ fn filtering_works() { ); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); expect_events(vec![ - UtilityEvent::BatchInterrupted(0, SystemError::CallFiltered.into()).into(), + UtilityEvent::BatchInterrupted { index: 0, error: SystemError::CallFiltered.into() } + .into(), ProxyEvent::ProxyExecuted(Ok(())).into(), ]); @@ -387,7 +388,8 @@ fn filtering_works() { ); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); expect_events(vec![ - UtilityEvent::BatchInterrupted(0, SystemError::CallFiltered.into()).into(), + UtilityEvent::BatchInterrupted { index: 0, error: SystemError::CallFiltered.into() } + .into(), ProxyEvent::ProxyExecuted(Ok(())).into(), ]); diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 0e161bf7bfe85..513509bda70ea 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -141,7 +141,7 @@ benchmarks_instance_pallet! { T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup) verify { - assert_last_event::(Event::Created(Default::default(), caller.clone(), caller).into()); + assert_last_event::(Event::Created { class: Default::default(), creator: caller.clone(), owner: caller }.into()); } force_create { @@ -149,7 +149,7 @@ benchmarks_instance_pallet! { let caller_lookup = T::Lookup::unlookup(caller.clone()); }: _(SystemOrigin::Root, Default::default(), caller_lookup, true) verify { - assert_last_event::(Event::ForceCreated(Default::default(), caller).into()); + assert_last_event::(Event::ForceCreated { class: Default::default(), owner: caller }.into()); } destroy { @@ -171,7 +171,7 @@ benchmarks_instance_pallet! { let witness = Class::::get(class).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), class, witness) verify { - assert_last_event::(Event::Destroyed(class).into()); + assert_last_event::(Event::Destroyed { class: class }.into()); } mint { @@ -179,7 +179,7 @@ benchmarks_instance_pallet! { let instance = Default::default(); }: _(SystemOrigin::Signed(caller.clone()), class, instance, caller_lookup) verify { - assert_last_event::(Event::Issued(class, instance, caller).into()); + assert_last_event::(Event::Issued { class, instance, owner: caller }.into()); } burn { @@ -187,7 +187,7 @@ benchmarks_instance_pallet! { let (instance, ..) = mint_instance::(0); }: _(SystemOrigin::Signed(caller.clone()), class, instance, Some(caller_lookup)) verify { - assert_last_event::(Event::Burned(class, instance, caller).into()); + assert_last_event::(Event::Burned { class, instance, owner: caller }.into()); } transfer { @@ -198,7 +198,7 @@ benchmarks_instance_pallet! { let target_lookup = T::Lookup::unlookup(target.clone()); }: _(SystemOrigin::Signed(caller.clone()), class, instance, target_lookup) verify { - assert_last_event::(Event::Transferred(class, instance, caller, target).into()); + assert_last_event::(Event::Transferred { class, instance, from: caller, to: target }.into()); } redeposit { @@ -217,7 +217,7 @@ benchmarks_instance_pallet! { )?; }: _(SystemOrigin::Signed(caller.clone()), class, instances.clone()) verify { - assert_last_event::(Event::Redeposited(class, instances).into()); + assert_last_event::(Event::Redeposited { class, successful_instances: instances }.into()); } freeze { @@ -225,7 +225,7 @@ benchmarks_instance_pallet! { let (instance, ..) = mint_instance::(Default::default()); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), Default::default()) verify { - assert_last_event::(Event::Frozen(Default::default(), Default::default()).into()); + assert_last_event::(Event::Frozen { class: Default::default(), instance: Default::default() }.into()); } thaw { @@ -238,14 +238,14 @@ benchmarks_instance_pallet! { )?; }: _(SystemOrigin::Signed(caller.clone()), class, instance) verify { - assert_last_event::(Event::Thawed(class, instance).into()); + assert_last_event::(Event::Thawed { class, instance }.into()); } freeze_class { let (class, caller, caller_lookup) = create_class::(); }: _(SystemOrigin::Signed(caller.clone()), class) verify { - assert_last_event::(Event::ClassFrozen(class).into()); + assert_last_event::(Event::ClassFrozen { class }.into()); } thaw_class { @@ -254,7 +254,7 @@ benchmarks_instance_pallet! { Uniques::::freeze_class(origin, class)?; }: _(SystemOrigin::Signed(caller.clone()), class) verify { - assert_last_event::(Event::ClassThawed(class).into()); + assert_last_event::(Event::ClassThawed { class }.into()); } transfer_ownership { @@ -264,7 +264,7 @@ benchmarks_instance_pallet! { T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); }: _(SystemOrigin::Signed(caller), class, target_lookup) verify { - assert_last_event::(Event::OwnerChanged(class, target).into()); + assert_last_event::(Event::OwnerChanged { class, new_owner: target }.into()); } set_team { @@ -274,12 +274,12 @@ benchmarks_instance_pallet! { let target2 = T::Lookup::unlookup(account("target", 2, SEED)); }: _(SystemOrigin::Signed(caller), Default::default(), target0.clone(), target1.clone(), target2.clone()) verify { - assert_last_event::(Event::TeamChanged( + assert_last_event::(Event::TeamChanged{ class, - account("target", 0, SEED), - account("target", 1, SEED), - account("target", 2, SEED), - ).into()); + issuer: account("target", 0, SEED), + admin: account("target", 1, SEED), + freezer: account("target", 2, SEED), + }.into()); } force_asset_status { @@ -296,7 +296,7 @@ benchmarks_instance_pallet! { }; }: { call.dispatch_bypass_filter(origin)? } verify { - assert_last_event::(Event::AssetStatusChanged(class).into()); + assert_last_event::(Event::AssetStatusChanged { class }.into()); } set_attribute { @@ -308,7 +308,7 @@ benchmarks_instance_pallet! { add_instance_metadata::(instance); }: _(SystemOrigin::Signed(caller), class, Some(instance), key.clone(), value.clone()) verify { - assert_last_event::(Event::AttributeSet(class, Some(instance), key, value).into()); + assert_last_event::(Event::AttributeSet { class, maybe_instance: Some(instance), key, value }.into()); } clear_attribute { @@ -318,7 +318,7 @@ benchmarks_instance_pallet! { let (key, ..) = add_instance_attribute::(instance); }: _(SystemOrigin::Signed(caller), class, Some(instance), key.clone()) verify { - assert_last_event::(Event::AttributeCleared(class, Some(instance), key).into()); + assert_last_event::(Event::AttributeCleared { class, maybe_instance: Some(instance), key }.into()); } set_metadata { @@ -328,7 +328,7 @@ benchmarks_instance_pallet! { let (instance, ..) = mint_instance::(0); }: _(SystemOrigin::Signed(caller), class, instance, data.clone(), false) verify { - assert_last_event::(Event::MetadataSet(class, instance, data, false).into()); + assert_last_event::(Event::MetadataSet { class, instance, data, is_frozen: false }.into()); } clear_metadata { @@ -337,7 +337,7 @@ benchmarks_instance_pallet! { add_instance_metadata::(instance); }: _(SystemOrigin::Signed(caller), class, instance) verify { - assert_last_event::(Event::MetadataCleared(class, instance).into()); + assert_last_event::(Event::MetadataCleared { class, instance }.into()); } set_class_metadata { @@ -346,7 +346,7 @@ benchmarks_instance_pallet! { let (class, caller, _) = create_class::(); }: _(SystemOrigin::Signed(caller), class, data.clone(), false) verify { - assert_last_event::(Event::ClassMetadataSet(class, data, false).into()); + assert_last_event::(Event::ClassMetadataSet { class, data, is_frozen: false }.into()); } clear_class_metadata { @@ -354,7 +354,7 @@ benchmarks_instance_pallet! { add_class_metadata::(); }: _(SystemOrigin::Signed(caller), class) verify { - assert_last_event::(Event::ClassMetadataCleared(class).into()); + assert_last_event::(Event::ClassMetadataCleared { class }.into()); } approve_transfer { @@ -364,7 +364,7 @@ benchmarks_instance_pallet! { let delegate_lookup = T::Lookup::unlookup(delegate.clone()); }: _(SystemOrigin::Signed(caller.clone()), class, instance, delegate_lookup) verify { - assert_last_event::(Event::ApprovedTransfer(class, instance, caller, delegate).into()); + assert_last_event::(Event::ApprovedTransfer { class, instance, owner: caller, delegate }.into()); } cancel_approval { @@ -376,7 +376,7 @@ benchmarks_instance_pallet! { Uniques::::approve_transfer(origin, class, instance, delegate_lookup.clone())?; }: _(SystemOrigin::Signed(caller.clone()), class, instance, Some(delegate_lookup)) verify { - assert_last_event::(Event::ApprovalCancelled(class, instance, caller, delegate).into()); + assert_last_event::(Event::ApprovalCancelled { class, instance, owner: caller, delegate }.into()); } impl_benchmark_test_suite!(Uniques, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 68acf7f1879fb..43d634ad569e7 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -44,7 +44,12 @@ impl, I: 'static> Pallet { details.owner = dest; Asset::::insert(&class, &instance, &details); - Self::deposit_event(Event::Transferred(class, instance, origin, details.owner)); + Self::deposit_event(Event::Transferred { + class, + instance, + from: origin, + to: details.owner, + }); Ok(()) } @@ -105,7 +110,7 @@ impl, I: 'static> Pallet { Attribute::::remove_prefix((&class,), None); T::Currency::unreserve(&class_details.owner, class_details.total_deposit); - Self::deposit_event(Event::Destroyed(class)); + Self::deposit_event(Event::Destroyed { class }); Ok(DestroyWitness { instances: class_details.instances, @@ -146,7 +151,7 @@ impl, I: 'static> Pallet { Ok(()) })?; - Self::deposit_event(Event::Issued(class, instance, owner)); + Self::deposit_event(Event::Issued { class, instance, owner }); Ok(()) } @@ -174,7 +179,7 @@ impl, I: 'static> Pallet { Asset::::remove(&class, &instance); Account::::remove((&owner, &class, &instance)); - Self::deposit_event(Event::Burned(class, instance, owner)); + Self::deposit_event(Event::Burned { class, instance, owner }); Ok(()) } } diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index 5394f02160e3c..72aa1dd0d4cb1 100644 --- a/frame/uniques/src/impl_nonfungibles.rs +++ b/frame/uniques/src/impl_nonfungibles.rs @@ -98,7 +98,7 @@ impl, I: 'static> Create<::AccountId> for Pallet admin.clone(), T::ClassDeposit::get(), false, - Event::Created(class.clone(), who.clone(), admin.clone()), + Event::Created { class: class.clone(), creator: who.clone(), owner: admin.clone() }, ) } } diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 1bf220e4a7876..7e380459252e7 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -191,63 +191,90 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { - /// An asset class was created. \[ class, creator, owner \] - Created(T::ClassId, T::AccountId, T::AccountId), - /// An asset class was force-created. \[ class, owner \] - ForceCreated(T::ClassId, T::AccountId), - /// An asset `class` was destroyed. \[ class \] - Destroyed(T::ClassId), - /// An asset `instance` was issued. \[ class, instance, owner \] - Issued(T::ClassId, T::InstanceId, T::AccountId), - /// An asset `instance` was transferred. \[ class, instance, from, to \] - Transferred(T::ClassId, T::InstanceId, T::AccountId, T::AccountId), - /// An asset `instance` was destroyed. \[ class, instance, owner \] - Burned(T::ClassId, T::InstanceId, T::AccountId), - /// Some asset `instance` was frozen. \[ class, instance \] - Frozen(T::ClassId, T::InstanceId), - /// Some asset `instance` was thawed. \[ class, instance \] - Thawed(T::ClassId, T::InstanceId), - /// Some asset `class` was frozen. \[ class \] - ClassFrozen(T::ClassId), - /// Some asset `class` was thawed. \[ class \] - ClassThawed(T::ClassId), - /// The owner changed \[ class, new_owner \] - OwnerChanged(T::ClassId, T::AccountId), - /// The management team changed \[ class, issuer, admin, freezer \] - TeamChanged(T::ClassId, T::AccountId, T::AccountId, T::AccountId), + /// An asset class was created. + Created { class: T::ClassId, creator: T::AccountId, owner: T::AccountId }, + /// An asset class was force-created. + ForceCreated { class: T::ClassId, owner: T::AccountId }, + /// An asset `class` was destroyed. + Destroyed { class: T::ClassId }, + /// An asset `instance` was issued. + Issued { class: T::ClassId, instance: T::InstanceId, owner: T::AccountId }, + /// An asset `instance` was transferred. + Transferred { + class: T::ClassId, + instance: T::InstanceId, + from: T::AccountId, + to: T::AccountId, + }, + /// An asset `instance` was destroyed. + Burned { class: T::ClassId, instance: T::InstanceId, owner: T::AccountId }, + /// Some asset `instance` was frozen. + Frozen { class: T::ClassId, instance: T::InstanceId }, + /// Some asset `instance` was thawed. + Thawed { class: T::ClassId, instance: T::InstanceId }, + /// Some asset `class` was frozen. + ClassFrozen { class: T::ClassId }, + /// Some asset `class` was thawed. + ClassThawed { class: T::ClassId }, + /// The owner changed. + OwnerChanged { class: T::ClassId, new_owner: T::AccountId }, + /// The management team changed. + TeamChanged { + class: T::ClassId, + issuer: T::AccountId, + admin: T::AccountId, + freezer: T::AccountId, + }, /// An `instance` of an asset `class` has been approved by the `owner` for transfer by a /// `delegate`. - /// \[ class, instance, owner, delegate \] - ApprovedTransfer(T::ClassId, T::InstanceId, T::AccountId, T::AccountId), + ApprovedTransfer { + class: T::ClassId, + instance: T::InstanceId, + owner: T::AccountId, + delegate: T::AccountId, + }, /// An approval for a `delegate` account to transfer the `instance` of an asset `class` was /// cancelled by its `owner`. - /// \[ class, instance, owner, delegate \] - ApprovalCancelled(T::ClassId, T::InstanceId, T::AccountId, T::AccountId), + ApprovalCancelled { + class: T::ClassId, + instance: T::InstanceId, + owner: T::AccountId, + delegate: T::AccountId, + }, /// An asset `class` has had its attributes changed by the `Force` origin. - /// \[ class \] - AssetStatusChanged(T::ClassId), - /// New metadata has been set for an asset class. \[ class, data, is_frozen \] - ClassMetadataSet(T::ClassId, BoundedVec, bool), - /// Metadata has been cleared for an asset class. \[ class \] - ClassMetadataCleared(T::ClassId), + AssetStatusChanged { class: T::ClassId }, + /// New metadata has been set for an asset class. + ClassMetadataSet { + class: T::ClassId, + data: BoundedVec, + is_frozen: bool, + }, + /// Metadata has been cleared for an asset class. + ClassMetadataCleared { class: T::ClassId }, /// New metadata has been set for an asset instance. - /// \[ class, instance, data, is_frozen \] - MetadataSet(T::ClassId, T::InstanceId, BoundedVec, bool), - /// Metadata has been cleared for an asset instance. \[ class, instance \] - MetadataCleared(T::ClassId, T::InstanceId), - /// Metadata has been cleared for an asset instance. \[ class, successful_instances \] - Redeposited(T::ClassId, Vec), + MetadataSet { + class: T::ClassId, + instance: T::InstanceId, + data: BoundedVec, + is_frozen: bool, + }, + /// Metadata has been cleared for an asset instance. + MetadataCleared { class: T::ClassId, instance: T::InstanceId }, + /// Metadata has been cleared for an asset instance. + Redeposited { class: T::ClassId, successful_instances: Vec }, /// New attribute metadata has been set for an asset class or instance. - /// \[ class, maybe_instance, key, value \] - AttributeSet( - T::ClassId, - Option, - BoundedVec, - BoundedVec, - ), + AttributeSet { + class: T::ClassId, + maybe_instance: Option, + key: BoundedVec, + value: BoundedVec, + }, /// Attribute metadata has been cleared for an asset class or instance. - /// \[ class, maybe_instance, key, maybe_value \] - AttributeCleared(T::ClassId, Option, BoundedVec), + AttributeCleared { + class: T::ClassId, + maybe_instance: Option, + key: BoundedVec, + }, } #[pallet::error] @@ -317,7 +344,7 @@ pub mod pallet { admin.clone(), T::ClassDeposit::get(), false, - Event::Created(class, owner, admin), + Event::Created { class, creator: owner, owner: admin }, ) } @@ -353,7 +380,7 @@ pub mod pallet { owner.clone(), Zero::zero(), free_holding, - Event::ForceCreated(class, owner), + Event::ForceCreated { class, owner }, ) } @@ -549,7 +576,10 @@ pub mod pallet { } Class::::insert(&class, &class_details); - Self::deposit_event(Event::::Redeposited(class, successful)); + Self::deposit_event(Event::::Redeposited { + class, + successful_instances: successful, + }); Ok(()) } @@ -580,7 +610,7 @@ pub mod pallet { details.is_frozen = true; Asset::::insert(&class, &instance, &details); - Self::deposit_event(Event::::Frozen(class, instance)); + Self::deposit_event(Event::::Frozen { class, instance }); Ok(()) } @@ -610,7 +640,7 @@ pub mod pallet { details.is_frozen = false; Asset::::insert(&class, &instance, &details); - Self::deposit_event(Event::::Thawed(class, instance)); + Self::deposit_event(Event::::Thawed { class, instance }); Ok(()) } @@ -636,7 +666,7 @@ pub mod pallet { details.is_frozen = true; - Self::deposit_event(Event::::ClassFrozen(class)); + Self::deposit_event(Event::::ClassFrozen { class }); Ok(()) }) } @@ -663,7 +693,7 @@ pub mod pallet { details.is_frozen = false; - Self::deposit_event(Event::::ClassThawed(class)); + Self::deposit_event(Event::::ClassThawed { class }); Ok(()) }) } @@ -703,7 +733,7 @@ pub mod pallet { )?; details.owner = owner.clone(); - Self::deposit_event(Event::OwnerChanged(class, owner)); + Self::deposit_event(Event::OwnerChanged { class, new_owner: owner }); Ok(()) }) } @@ -741,7 +771,7 @@ pub mod pallet { details.admin = admin.clone(); details.freezer = freezer.clone(); - Self::deposit_event(Event::TeamChanged(class, issuer, admin, freezer)); + Self::deposit_event(Event::TeamChanged { class, issuer, admin, freezer }); Ok(()) }) } @@ -783,7 +813,12 @@ pub mod pallet { Asset::::insert(&class, &instance, &details); let delegate = details.approved.expect("set as Some above; qed"); - Self::deposit_event(Event::ApprovedTransfer(class, instance, details.owner, delegate)); + Self::deposit_event(Event::ApprovedTransfer { + class, + instance, + owner: details.owner, + delegate, + }); Ok(()) } @@ -829,7 +864,12 @@ pub mod pallet { } Asset::::insert(&class, &instance, &details); - Self::deposit_event(Event::ApprovalCancelled(class, instance, details.owner, old)); + Self::deposit_event(Event::ApprovalCancelled { + class, + instance, + owner: details.owner, + delegate: old, + }); Ok(()) } @@ -874,7 +914,7 @@ pub mod pallet { asset.is_frozen = is_frozen; *maybe_asset = Some(asset); - Self::deposit_event(Event::AssetStatusChanged(class)); + Self::deposit_event(Event::AssetStatusChanged { class }); Ok(()) }) } @@ -940,7 +980,7 @@ pub mod pallet { Attribute::::insert((&class, maybe_instance, &key), (&value, deposit)); Class::::insert(class, &class_details); - Self::deposit_event(Event::AttributeSet(class, maybe_instance, key, value)); + Self::deposit_event(Event::AttributeSet { class, maybe_instance, key, value }); Ok(()) } @@ -988,7 +1028,7 @@ pub mod pallet { class_details.total_deposit.saturating_reduce(deposit); T::Currency::unreserve(&class_details.owner, deposit); Class::::insert(class, &class_details); - Self::deposit_event(Event::AttributeCleared(class, maybe_instance, key)); + Self::deposit_event(Event::AttributeCleared { class, maybe_instance, key }); } Ok(()) } @@ -1053,7 +1093,7 @@ pub mod pallet { *metadata = Some(InstanceMetadata { deposit, data: data.clone(), is_frozen }); Class::::insert(&class, &class_details); - Self::deposit_event(Event::MetadataSet(class, instance, data, is_frozen)); + Self::deposit_event(Event::MetadataSet { class, instance, data, is_frozen }); Ok(()) }) } @@ -1098,7 +1138,7 @@ pub mod pallet { class_details.total_deposit.saturating_reduce(deposit); Class::::insert(&class, &class_details); - Self::deposit_event(Event::MetadataCleared(class, instance)); + Self::deposit_event(Event::MetadataCleared { class, instance }); Ok(()) }) } @@ -1158,7 +1198,7 @@ pub mod pallet { *metadata = Some(ClassMetadata { deposit, data: data.clone(), is_frozen }); - Self::deposit_event(Event::ClassMetadataSet(class, data, is_frozen)); + Self::deposit_event(Event::ClassMetadataSet { class, data, is_frozen }); Ok(()) }) } @@ -1195,7 +1235,7 @@ pub mod pallet { let deposit = metadata.take().ok_or(Error::::Unknown)?.deposit; T::Currency::unreserve(&details.owner, deposit); - Self::deposit_event(Event::ClassMetadataCleared(class)); + Self::deposit_event(Event::ClassMetadataCleared { class }); Ok(()) }) } diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 241526cef2230..14d8a66514e36 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -109,8 +109,8 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Batch of dispatches did not complete fully. Index of first failing dispatch given, as - /// well as the error. \[index, error\] - BatchInterrupted(u32, DispatchError), + /// well as the error. + BatchInterrupted { index: u32, error: DispatchError }, /// Batch of dispatches completed fully with no error. BatchCompleted, /// A single item within a Batch of dispatches has completed with no error. @@ -217,7 +217,10 @@ pub mod pallet { // Add the weight of this call. weight = weight.saturating_add(extract_actual_weight(&result, &info)); if let Err(e) = result { - Self::deposit_event(Event::BatchInterrupted(index as u32, e.error)); + Self::deposit_event(Event::BatchInterrupted { + index: index as u32, + error: e.error, + }); // Take the weight of this function itself into account. let base_weight = T::WeightInfo::batch(index.saturating_add(1) as u32); // Return the actual used weight + base_weight of this call. diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index f4d09a30ec078..32582fae82116 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -339,8 +339,11 @@ fn batch_with_signed_filters() { vec![Call::Balances(pallet_balances::Call::transfer_keep_alive { dest: 2, value: 1 })] ),); System::assert_last_event( - utility::Event::BatchInterrupted(0, frame_system::Error::::CallFiltered.into()) - .into(), + utility::Event::BatchInterrupted { + index: 0, + error: frame_system::Error::::CallFiltered.into(), + } + .into(), ); }); } @@ -411,7 +414,7 @@ fn batch_handles_weight_refund() { let result = call.dispatch(Origin::signed(1)); assert_ok!(result); System::assert_last_event( - utility::Event::BatchInterrupted(1, DispatchError::Other("")).into(), + utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), ); // No weight is refunded assert_eq!(extract_actual_weight(&result, &info), info.weight); @@ -426,7 +429,7 @@ fn batch_handles_weight_refund() { let result = call.dispatch(Origin::signed(1)); assert_ok!(result); System::assert_last_event( - utility::Event::BatchInterrupted(1, DispatchError::Other("")).into(), + utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), ); assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); @@ -439,7 +442,7 @@ fn batch_handles_weight_refund() { let result = call.dispatch(Origin::signed(1)); assert_ok!(result); System::assert_last_event( - utility::Event::BatchInterrupted(1, DispatchError::Other("")).into(), + utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), ); assert_eq!( extract_actual_weight(&result, &info), @@ -587,8 +590,11 @@ fn batch_all_does_not_nest() { // and balances. assert_ok!(Utility::batch_all(Origin::signed(1), vec![batch_nested])); System::assert_has_event( - utility::Event::BatchInterrupted(0, frame_system::Error::::CallFiltered.into()) - .into(), + utility::Event::BatchInterrupted { + index: 0, + error: frame_system::Error::::CallFiltered.into(), + } + .into(), ); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 654723d009fab..6857918bc9a1c 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -104,9 +104,9 @@ enum VestingAction { /// Do not actively remove any schedules. Passive, /// Remove the schedule specified by the index. - Remove(usize), + Remove { index: usize }, /// Remove the two schedules, specified by index, so they can be merged. - Merge(usize, usize), + Merge { index1: usize, index2: usize }, } impl VestingAction { @@ -114,8 +114,8 @@ impl VestingAction { fn should_remove(&self, index: usize) -> bool { match self { Self::Passive => false, - Self::Remove(index1) => *index1 == index, - Self::Merge(index1, index2) => *index1 == index || *index2 == index, + Self::Remove { index: index1 } => *index1 == index, + Self::Merge { index1, index2 } => *index1 == index || *index2 == index, } } @@ -279,10 +279,9 @@ pub mod pallet { pub enum Event { /// The amount vested has been updated. This could indicate a change in funds available. /// The balance given is the amount which is left unvested (and thus locked). - /// \[account, unvested\] - VestingUpdated(T::AccountId, BalanceOf), + VestingUpdated { account: T::AccountId, unvested: BalanceOf }, /// An \[account\] has become fully vested. - VestingCompleted(T::AccountId), + VestingCompleted { account: T::AccountId }, } /// Error for the vesting pallet. @@ -450,7 +449,8 @@ pub mod pallet { let schedule2_index = schedule2_index as usize; let schedules = Self::vesting(&who).ok_or(Error::::NotVesting)?; - let merge_action = VestingAction::Merge(schedule1_index, schedule2_index); + let merge_action = + VestingAction::Merge { index1: schedule1_index, index2: schedule2_index }; let (schedules, locked_now) = Self::exec_action(schedules.to_vec(), merge_action)?; @@ -590,11 +590,14 @@ impl Pallet { fn write_lock(who: &T::AccountId, total_locked_now: BalanceOf) { if total_locked_now.is_zero() { T::Currency::remove_lock(VESTING_ID, who); - Self::deposit_event(Event::::VestingCompleted(who.clone())); + Self::deposit_event(Event::::VestingCompleted { account: who.clone() }); } else { let reasons = WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE; T::Currency::set_lock(VESTING_ID, who, total_locked_now, reasons); - Self::deposit_event(Event::::VestingUpdated(who.clone(), total_locked_now)); + Self::deposit_event(Event::::VestingUpdated { + account: who.clone(), + unvested: total_locked_now, + }); }; } @@ -637,7 +640,7 @@ impl Pallet { action: VestingAction, ) -> Result<(Vec, T::BlockNumber>>, BalanceOf), DispatchError> { let (schedules, locked_now) = match action { - VestingAction::Merge(idx1, idx2) => { + VestingAction::Merge { index1: idx1, index2: idx2 } => { // The schedule index is based off of the schedule ordering prior to filtering out // any schedules that may be ending at this block. let schedule1 = *schedules.get(idx1).ok_or(Error::::ScheduleIndexOutOfBounds)?; @@ -762,7 +765,7 @@ where /// Remove a vesting schedule for a given account. fn remove_vesting_schedule(who: &T::AccountId, schedule_index: u32) -> DispatchResult { let schedules = Self::vesting(who).ok_or(Error::::NotVesting)?; - let remove_action = VestingAction::Remove(schedule_index as usize); + let remove_action = VestingAction::Remove { index: schedule_index as usize }; let (schedules, locked_now) = Self::exec_action(schedules.to_vec(), remove_action)?; From 7aa029ae4101ab61aa1d5d8a043cdf53b853225d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Nov 2021 19:39:11 +0000 Subject: [PATCH 0233/1472] Bump tokio from 1.12.0 to 1.13.0 (#10265) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.12.0 to 1.13.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.12.0...tokio-1.13.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 | 4 ++-- bin/node/cli/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- test-utils/test-crate/Cargo.toml | 2 +- test-utils/test-runner/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 4 ++-- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57bf1278822c0..99b2b53a74a4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10545,9 +10545,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" +checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee" dependencies = [ "autocfg 1.0.1", "bytes 1.0.1", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 122f2d0c2c8fc..7529138c7f9d7 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -129,7 +129,7 @@ platforms = "1.1" async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" criterion = { version = "0.3.5", features = [ "async_tokio" ] } -tokio = { version = "1.10", features = ["macros", "time"] } +tokio = { version = "1.13", features = ["macros", "time"] } jsonrpsee-ws-client = "0.4.1" wait-timeout = "0.2" remote-externalities = { path = "../../../utils/frame/remote-externalities" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index b027063b109a8..2855e63cdc6a0 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.11" regex = "1.5.4" -tokio = { version = "1.10", features = [ "signal", "rt-multi-thread" ] } +tokio = { version = "1.13", features = [ "signal", "rt-multi-thread" ] } futures = "0.3.9" fdlimit = "0.2.1" libp2p = "0.39.1" diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index a7679f53ea9e8..90edc15863cdb 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -45,7 +45,7 @@ sp-timestamp = { path = "../../../primitives/timestamp", version = "4.0.0-dev" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } [dev-dependencies] -tokio = { version = "1.10.0", features = ["rt-multi-thread", "macros"] } +tokio = { version = "1.13.0", features = ["rt-multi-thread", "macros"] } sc-basic-authorship = { path = "../../basic-authorship", version = "0.10.0-dev" } substrate-test-runtime-client = { path = "../../../test-utils/runtime/client", version = "2.0.0" } substrate-test-runtime-transaction-pool = { path = "../../../test-utils/runtime/transaction-pool", version = "2.0.0" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 43511ea59f146..ec4bac715ad40 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -57,5 +57,5 @@ sc-network-test = { version = "0.8.0", path = "../network/test" } sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } -tokio = "1.10" +tokio = "1.13" tempfile = "3.1.0" diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index c93eec85888dc..2a6fdddd7ad36 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -43,7 +43,7 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/a sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -tokio = "1.10" +tokio = "1.13" lazy_static = "1.4.0" [features] diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index f0ae6172d6d9e..3be2380785064 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -19,7 +19,7 @@ pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} serde_json = "1.0.68" -tokio = "1.10" +tokio = "1.13" http = { package = "jsonrpc-http-server", version = "18.0.0" } ipc = { package = "jsonrpc-ipc-server", version = "18.0.0" } ws = { package = "jsonrpc-ws-server", version = "18.0.0" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 38729fd4ba5ce..a66a4fc67680e 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -78,7 +78,7 @@ parity-util-mem = { version = "0.10.2", default-features = false, features = [ "primitive-types", ] } async-trait = "0.1.50" -tokio = { version = "1.10", features = ["time", "rt-multi-thread"] } +tokio = { version = "1.13", features = ["time", "rt-multi-thread"] } tempfile = "3.1.0" directories = "4.0.1" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 114473b66c975..fe953a53bdd04 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] hex = "0.4" hex-literal = "0.3.4" tempfile = "3.1.0" -tokio = { version = "1.10.0", features = ["time"] } +tokio = { version = "1.13.0", features = ["time"] } log = "0.4.8" fdlimit = "0.2.1" parking_lot = "0.11.1" diff --git a/test-utils/test-crate/Cargo.toml b/test-utils/test-crate/Cargo.toml index 071a82f3c769f..4621332ccc0c1 100644 --- a/test-utils/test-crate/Cargo.toml +++ b/test-utils/test-crate/Cargo.toml @@ -12,6 +12,6 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] -tokio = { version = "1.10", features = ["macros"] } +tokio = { version = "1.13", features = ["macros"] } test-utils = { version = "4.0.0-dev", path = "..", package = "substrate-test-utils" } sc-service = { version = "0.10.0-dev", path = "../../client/service" } diff --git a/test-utils/test-runner/Cargo.toml b/test-utils/test-runner/Cargo.toml index 9299076bb1f68..7066fc778cbdd 100644 --- a/test-utils/test-runner/Cargo.toml +++ b/test-utils/test-runner/Cargo.toml @@ -48,7 +48,7 @@ frame-system = { path = "../../frame/system" } log = "0.4.8" futures = "0.3.16" -tokio = { version = "1.10", features = ["signal"] } +tokio = { version = "1.13", features = ["signal"] } # Calling RPC jsonrpc-core = "18.0" num-traits = "0.2.14" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 8f54dd01df0a3..105ab1739f5b6 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -28,7 +28,7 @@ sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } [dev-dependencies] -tokio = { version = "1.10", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.13", features = ["macros", "rt-multi-thread"] } pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", version = "5.0.0-dev" } frame-support = { path = "../../../frame/support", version = "4.0.0-dev" } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 0d21bdd6c0181..dbaa12ee5ddb9 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -26,4 +26,4 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } [dev-dependencies] frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } scale-info = "1.0" -tokio = "1.10" +tokio = "1.13" diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 390a1c733cbd7..e2104ec5d55aa 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -18,9 +18,9 @@ prometheus = { version = "0.13.0", default-features = false } futures-util = { version = "0.3.17", default-features = false, features = ["io"] } derive_more = "0.99" async-std = { version = "1.10.0", features = ["unstable"] } -tokio = "1.10" +tokio = "1.13" hyper = { version = "0.14.14", default-features = false, features = ["http1", "server", "tcp"] } [dev-dependencies] hyper = { version = "0.14.14", features = ["client"] } -tokio = { version = "1.10", features = ["rt-multi-thread"] } +tokio = { version = "1.13", features = ["rt-multi-thread"] } From bc4cb49f4b3993887e6e9a8f6a7f649928f92689 Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Mon, 15 Nov 2021 20:41:41 +0100 Subject: [PATCH 0234/1472] client/service: refactor group param of spawn into an Enum (#10248) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refractored group param to enum * refractored group param to enum * changed group param to GroupName enum for other methods too such as spawn_inner updated docs * revert on task type * put back ticks in GroupName * Update client/service/src/task_manager/mod.rs Co-authored-by: Bastian Köcher * document group name change specific to actual in enum declaration * change documentation * Update client/service/src/task_manager/mod.rs Co-authored-by: Andronik Ordian * changed Actual to Specific * Update client/service/src/task_manager/mod.rs Co-authored-by: Andronik Ordian * Update client/service/src/task_manager/mod.rs Co-authored-by: Bastian Köcher * Update client/service/src/task_manager/mod.rs Co-authored-by: Bastian Köcher * Update client/service/src/task_manager/mod.rs Co-authored-by: Bastian Köcher Co-authored-by: Damilare Co-authored-by: Bastian Köcher Co-authored-by: Andronik Ordian --- client/service/src/task_manager/mod.rs | 50 ++++++++++++++++++++------ 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/client/service/src/task_manager/mod.rs b/client/service/src/task_manager/mod.rs index 64c00226073c7..25d3ecd7d5c3c 100644 --- a/client/service/src/task_manager/mod.rs +++ b/client/service/src/task_manager/mod.rs @@ -41,6 +41,32 @@ mod tests; /// Default task group name. pub const DEFAULT_GROUP_NAME: &'static str = "default"; +/// The name of a group a task belongs to. +/// +/// This name is passed belong-side the task name to the prometheus metrics and can be used +/// to group tasks. +pub enum GroupName { + /// Sets the group name to `default`. + Default, + /// Use the specifically given name as group name. + Specific(&'static str), +} + +impl From> for GroupName { + fn from(name: Option<&'static str>) -> Self { + match name { + Some(name) => Self::Specific(name), + None => Self::Default, + } + } +} + +impl From<&'static str> for GroupName { + fn from(name: &'static str) -> Self { + Self::Specific(name) + } +} + /// An handle for spawning tasks in the service. #[derive(Clone)] pub struct SpawnTaskHandle { @@ -51,10 +77,10 @@ pub struct SpawnTaskHandle { } impl SpawnTaskHandle { - /// Spawns the given task with the given name and an optional group name. + /// Spawns the given task with the given name and a group name. /// If group is not specified `DEFAULT_GROUP_NAME` will be used. /// - /// Note that the `name`/`group` is a `&'static str`. The reason for this choice is that + /// Note that the `name` is a `&'static str`. The reason for this choice is that /// statistics about this task are getting reported to the Prometheus endpoint (if enabled), and /// that therefore the set of possible task names must be bounded. /// @@ -63,7 +89,7 @@ impl SpawnTaskHandle { pub fn spawn( &self, name: &'static str, - group: Option<&'static str>, + group: impl Into, task: impl Future + Send + 'static, ) { self.spawn_inner(name, group, task, TaskType::Async) @@ -73,7 +99,7 @@ impl SpawnTaskHandle { pub fn spawn_blocking( &self, name: &'static str, - group: Option<&'static str>, + group: impl Into, task: impl Future + Send + 'static, ) { self.spawn_inner(name, group, task, TaskType::Blocking) @@ -83,7 +109,7 @@ impl SpawnTaskHandle { fn spawn_inner( &self, name: &'static str, - group: Option<&'static str>, + group: impl Into, task: impl Future + Send + 'static, task_type: TaskType, ) { @@ -94,8 +120,12 @@ impl SpawnTaskHandle { let on_exit = self.on_exit.clone(); let metrics = self.metrics.clone(); - // If no group is specified use default. - let group = group.unwrap_or(DEFAULT_GROUP_NAME); + + let group = match group.into() { + GroupName::Specific(var) => var, + // If no group is specified use default. + GroupName::Default => DEFAULT_GROUP_NAME, + }; // Note that we increase the started counter here and not within the future. This way, // we could properly visualize on Prometheus situations where the spawning doesn't work. @@ -198,7 +228,7 @@ impl SpawnEssentialTaskHandle { pub fn spawn( &self, name: &'static str, - group: Option<&'static str>, + group: impl Into, task: impl Future + Send + 'static, ) { self.spawn_inner(name, group, task, TaskType::Async) @@ -210,7 +240,7 @@ impl SpawnEssentialTaskHandle { pub fn spawn_blocking( &self, name: &'static str, - group: Option<&'static str>, + group: impl Into, task: impl Future + Send + 'static, ) { self.spawn_inner(name, group, task, TaskType::Blocking) @@ -219,7 +249,7 @@ impl SpawnEssentialTaskHandle { fn spawn_inner( &self, name: &'static str, - group: Option<&'static str>, + group: impl Into, task: impl Future + Send + 'static, task_type: TaskType, ) { From c087bbedbde16711450c186518314903a2949cb3 Mon Sep 17 00:00:00 2001 From: David Salami <31099392+Wizdave97@users.noreply.github.com> Date: Tue, 16 Nov 2021 02:56:00 +0100 Subject: [PATCH 0235/1472] Add field names to pallet Event variants (#9993) * convert pallet-assets events to struct types * updated events of a couple pallets * updated pallet event field names * update pallet event field names * updated events in test files * cargo fmt * minorfixes * fix assertion error * minor fix * formatting fix * fmt --- bin/node/executor/tests/basic.rs | 69 ++-- frame/assets/src/benchmarking.rs | 56 +-- frame/assets/src/functions.rs | 41 +- frame/assets/src/lib.rs | 125 +++--- frame/assets/src/tests.rs | 7 +- frame/atomic-swap/src/lib.rs | 21 +- frame/bags-list/src/lib.rs | 6 +- frame/balances/src/lib.rs | 114 +++--- frame/balances/src/tests.rs | 30 +- frame/balances/src/tests_local.rs | 10 +- frame/balances/src/tests_reentrancy.rs | 47 ++- frame/bounties/src/benchmarking.rs | 6 +- frame/bounties/src/lib.rs | 49 ++- frame/bounties/src/tests.rs | 16 +- frame/collective/src/benchmarking.rs | 16 +- frame/collective/src/lib.rs | 77 ++-- frame/collective/src/tests.rs | 373 ++++++++++++++---- frame/contracts/src/tests.rs | 38 +- frame/democracy/src/benchmarking.rs | 2 +- frame/democracy/src/lib.rs | 112 +++--- .../election-provider-multi-phase/src/lib.rs | 48 ++- .../src/signed.rs | 4 +- frame/elections-phragmen/src/lib.rs | 63 +-- frame/elections/src/lib.rs | 23 +- frame/examples/basic/src/lib.rs | 17 +- frame/examples/offchain-worker/src/lib.rs | 5 +- frame/gilt/src/lib.rs | 36 +- frame/grandpa/src/lib.rs | 10 +- frame/grandpa/src/tests.rs | 10 +- frame/identity/src/benchmarking.rs | 8 +- frame/identity/src/lib.rs | 69 ++-- frame/im-online/src/lib.rs | 12 +- frame/indices/src/lib.rs | 22 +- frame/lottery/src/lib.rs | 8 +- frame/membership/src/lib.rs | 2 +- frame/multisig/src/lib.rs | 63 +-- frame/multisig/src/tests.rs | 9 +- frame/nicks/src/lib.rs | 30 +- frame/node-authorization/src/lib.rs | 42 +- frame/offences/benchmarking/src/lib.rs | 14 +- frame/offences/src/lib.rs | 4 +- frame/offences/src/tests.rs | 10 +- frame/proxy/src/benchmarking.rs | 18 +- frame/proxy/src/lib.rs | 44 ++- frame/proxy/src/tests.rs | 62 +-- frame/staking/src/slashing.rs | 2 +- frame/staking/src/tests.rs | 4 +- frame/transaction-payment/src/lib.rs | 8 +- 48 files changed, 1181 insertions(+), 681 deletions(-) diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index b7df7bf0bd41a..7dc6c22aa3544 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -387,24 +387,27 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Withdraw(alice().into(), fees)), + event: Event::Balances(pallet_balances::Event::Withdraw { + who: alice().into(), + amount: fees, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Transfer( - alice().into(), - bob().into(), - 69 * DOLLARS, - )), + event: Event::Balances(pallet_balances::Event::Transfer { + from: alice().into(), + to: bob().into(), + amount: 69 * DOLLARS, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Deposit( - pallet_treasury::Pallet::::account_id(), - fees * 8 / 10, - )), + event: Event::Balances(pallet_balances::Event::Deposit { + who: pallet_treasury::Pallet::::account_id(), + amount: fees * 8 / 10, + }), topics: vec![], }, EventRecord { @@ -454,24 +457,27 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Withdraw(bob().into(), fees)), + event: Event::Balances(pallet_balances::Event::Withdraw { + who: bob().into(), + amount: fees, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Transfer( - bob().into(), - alice().into(), - 5 * DOLLARS, - )), + event: Event::Balances(pallet_balances::Event::Transfer { + from: bob().into(), + to: alice().into(), + amount: 5 * DOLLARS, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Deposit( - pallet_treasury::Pallet::::account_id(), - fees * 8 / 10, - )), + event: Event::Balances(pallet_balances::Event::Deposit { + who: pallet_treasury::Pallet::::account_id(), + amount: fees * 8 / 10, + }), topics: vec![], }, EventRecord { @@ -489,24 +495,27 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Balances(pallet_balances::Event::Withdraw(alice().into(), fees)), + event: Event::Balances(pallet_balances::Event::Withdraw { + who: alice().into(), + amount: fees, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Balances(pallet_balances::Event::Transfer( - alice().into(), - bob().into(), - 15 * DOLLARS, - )), + event: Event::Balances(pallet_balances::Event::Transfer { + from: alice().into(), + to: bob().into(), + amount: 15 * DOLLARS, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Balances(pallet_balances::Event::Deposit( - pallet_treasury::Pallet::::account_id(), - fees * 8 / 10, - )), + event: Event::Balances(pallet_balances::Event::Deposit { + who: pallet_treasury::Pallet::::account_id(), + amount: fees * 8 / 10, + }), topics: vec![], }, EventRecord { diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index d9de9ed3dedd4..475864bac9430 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -155,7 +155,7 @@ benchmarks_instance_pallet! { T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, 1u32.into()) verify { - assert_last_event::(Event::Created(Default::default(), caller.clone(), caller).into()); + assert_last_event::(Event::Created { asset_id: Default::default(), creator: caller.clone(), owner: caller }.into()); } force_create { @@ -163,7 +163,7 @@ benchmarks_instance_pallet! { let caller_lookup = T::Lookup::unlookup(caller.clone()); }: _(SystemOrigin::Root, Default::default(), caller_lookup, true, 1u32.into()) verify { - assert_last_event::(Event::ForceCreated(Default::default(), caller).into()); + assert_last_event::(Event::ForceCreated { asset_id: Default::default(), owner: caller }.into()); } destroy { @@ -177,7 +177,7 @@ benchmarks_instance_pallet! { let witness = Asset::::get(T::AssetId::default()).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), Default::default(), witness) verify { - assert_last_event::(Event::Destroyed(Default::default()).into()); + assert_last_event::(Event::Destroyed { asset_id: Default::default() }.into()); } mint { @@ -185,7 +185,7 @@ benchmarks_instance_pallet! { let amount = T::Balance::from(100u32); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, amount) verify { - assert_last_event::(Event::Issued(Default::default(), caller, amount).into()); + assert_last_event::(Event::Issued { asset_id: Default::default(), owner: caller, total_supply: amount }.into()); } burn { @@ -193,7 +193,7 @@ benchmarks_instance_pallet! { let (caller, caller_lookup) = create_default_minted_asset::(true, amount); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, amount) verify { - assert_last_event::(Event::Burned(Default::default(), caller, amount).into()); + assert_last_event::(Event::Burned { asset_id: Default::default(), owner: caller, balance: amount }.into()); } transfer { @@ -203,7 +203,7 @@ benchmarks_instance_pallet! { let target_lookup = T::Lookup::unlookup(target.clone()); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), target_lookup, amount) verify { - assert_last_event::(Event::Transferred(Default::default(), caller, target, amount).into()); + assert_last_event::(Event::Transferred { asset_id: Default::default(), from: caller, to: target, amount }.into()); } transfer_keep_alive { @@ -215,7 +215,7 @@ benchmarks_instance_pallet! { }: _(SystemOrigin::Signed(caller.clone()), Default::default(), target_lookup, amount) verify { assert!(frame_system::Pallet::::account_exists(&caller)); - assert_last_event::(Event::Transferred(Default::default(), caller, target, amount).into()); + assert_last_event::(Event::Transferred { asset_id: Default::default(), from: caller, to: target, amount }.into()); } force_transfer { @@ -226,7 +226,7 @@ benchmarks_instance_pallet! { }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, target_lookup, amount) verify { assert_last_event::( - Event::Transferred(Default::default(), caller, target, amount).into() + Event::Transferred { asset_id: Default::default(), from: caller, to: target, amount }.into() ); } @@ -234,7 +234,7 @@ benchmarks_instance_pallet! { let (caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup) verify { - assert_last_event::(Event::Frozen(Default::default(), caller).into()); + assert_last_event::(Event::Frozen { asset_id: Default::default(), who: caller }.into()); } thaw { @@ -246,14 +246,14 @@ benchmarks_instance_pallet! { )?; }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup) verify { - assert_last_event::(Event::Thawed(Default::default(), caller).into()); + assert_last_event::(Event::Thawed { asset_id: Default::default(), who: caller }.into()); } freeze_asset { let (caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); }: _(SystemOrigin::Signed(caller.clone()), Default::default()) verify { - assert_last_event::(Event::AssetFrozen(Default::default()).into()); + assert_last_event::(Event::AssetFrozen { asset_id: Default::default() }.into()); } thaw_asset { @@ -264,7 +264,7 @@ benchmarks_instance_pallet! { )?; }: _(SystemOrigin::Signed(caller.clone()), Default::default()) verify { - assert_last_event::(Event::AssetThawed(Default::default()).into()); + assert_last_event::(Event::AssetThawed { asset_id: Default::default() }.into()); } transfer_ownership { @@ -273,7 +273,7 @@ benchmarks_instance_pallet! { let target_lookup = T::Lookup::unlookup(target.clone()); }: _(SystemOrigin::Signed(caller), Default::default(), target_lookup) verify { - assert_last_event::(Event::OwnerChanged(Default::default(), target).into()); + assert_last_event::(Event::OwnerChanged { asset_id: Default::default(), owner: target }.into()); } set_team { @@ -283,12 +283,12 @@ benchmarks_instance_pallet! { let target2 = T::Lookup::unlookup(account("target", 2, SEED)); }: _(SystemOrigin::Signed(caller), Default::default(), target0.clone(), target1.clone(), target2.clone()) verify { - assert_last_event::(Event::TeamChanged( - Default::default(), - account("target", 0, SEED), - account("target", 1, SEED), - account("target", 2, SEED), - ).into()); + assert_last_event::(Event::TeamChanged { + asset_id: Default::default(), + issuer: account("target", 0, SEED), + admin: account("target", 1, SEED), + freezer: account("target", 2, SEED), + }.into()); } set_metadata { @@ -304,7 +304,7 @@ benchmarks_instance_pallet! { }: _(SystemOrigin::Signed(caller), Default::default(), name.clone(), symbol.clone(), decimals) verify { let id = Default::default(); - assert_last_event::(Event::MetadataSet(id, name, symbol, decimals, false).into()); + assert_last_event::(Event::MetadataSet { asset_id: id, name, symbol, decimals, is_frozen: false }.into()); } clear_metadata { @@ -315,7 +315,7 @@ benchmarks_instance_pallet! { Assets::::set_metadata(origin, Default::default(), dummy.clone(), dummy, 12)?; }: _(SystemOrigin::Signed(caller), Default::default()) verify { - assert_last_event::(Event::MetadataCleared(Default::default()).into()); + assert_last_event::(Event::MetadataCleared { asset_id: Default::default() }.into()); } force_set_metadata { @@ -339,7 +339,7 @@ benchmarks_instance_pallet! { }: { call.dispatch_bypass_filter(origin)? } verify { let id = Default::default(); - assert_last_event::(Event::MetadataSet(id, name, symbol, decimals, false).into()); + assert_last_event::(Event::MetadataSet { asset_id: id, name, symbol, decimals, is_frozen: false }.into()); } force_clear_metadata { @@ -353,7 +353,7 @@ benchmarks_instance_pallet! { let call = Call::::force_clear_metadata { id: Default::default() }; }: { call.dispatch_bypass_filter(origin)? } verify { - assert_last_event::(Event::MetadataCleared(Default::default()).into()); + assert_last_event::(Event::MetadataCleared { asset_id: Default::default() }.into()); } force_asset_status { @@ -372,7 +372,7 @@ benchmarks_instance_pallet! { }; }: { call.dispatch_bypass_filter(origin)? } verify { - assert_last_event::(Event::AssetStatusChanged(Default::default()).into()); + assert_last_event::(Event::AssetStatusChanged { asset_id: Default::default() }.into()); } approve_transfer { @@ -385,7 +385,7 @@ benchmarks_instance_pallet! { let amount = 100u32.into(); }: _(SystemOrigin::Signed(caller.clone()), id, delegate_lookup, amount) verify { - assert_last_event::(Event::ApprovedTransfer(id, caller, delegate, amount).into()); + assert_last_event::(Event::ApprovedTransfer { asset_id: id, source: caller, delegate, amount }.into()); } transfer_approved { @@ -405,7 +405,7 @@ benchmarks_instance_pallet! { }: _(SystemOrigin::Signed(delegate.clone()), id, owner_lookup, dest_lookup, amount) verify { assert!(T::Currency::reserved_balance(&owner).is_zero()); - assert_event::(Event::Transferred(id, owner, dest, amount).into()); + assert_event::(Event::Transferred { asset_id: id, from: owner, to: dest, amount }.into()); } cancel_approval { @@ -420,7 +420,7 @@ benchmarks_instance_pallet! { Assets::::approve_transfer(origin, id, delegate_lookup.clone(), amount)?; }: _(SystemOrigin::Signed(caller.clone()), id, delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled(id, caller, delegate).into()); + assert_last_event::(Event::ApprovalCancelled { asset_id: id, owner: caller, delegate }.into()); } force_cancel_approval { @@ -435,7 +435,7 @@ benchmarks_instance_pallet! { Assets::::approve_transfer(origin, id, delegate_lookup.clone(), amount)?; }: _(SystemOrigin::Signed(caller.clone()), id, caller_lookup, delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled(id, caller, delegate).into()); + assert_last_event::(Event::ApprovalCancelled { asset_id: id, owner: caller, delegate }.into()); } impl_benchmark_test_suite!(Assets, crate::mock::new_test_ext(), crate::mock::Test) diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index a4685d88d0497..f01954cb970ee 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -275,7 +275,11 @@ impl, I: 'static> Pallet { details.supply = details.supply.saturating_add(amount); Ok(()) })?; - Self::deposit_event(Event::Issued(id, beneficiary.clone(), amount)); + Self::deposit_event(Event::Issued { + asset_id: id, + owner: beneficiary.clone(), + total_supply: amount, + }); Ok(()) } @@ -342,7 +346,7 @@ impl, I: 'static> Pallet { Ok(()) })?; - Self::deposit_event(Event::Burned(id, target.clone(), actual)); + Self::deposit_event(Event::Burned { asset_id: id, owner: target.clone(), balance: actual }); Ok(actual) } @@ -415,7 +419,12 @@ impl, I: 'static> Pallet { ) -> Result { // Early exist if no-op. if amount.is_zero() { - Self::deposit_event(Event::Transferred(id, source.clone(), dest.clone(), amount)); + Self::deposit_event(Event::Transferred { + asset_id: id, + from: source.clone(), + to: dest.clone(), + amount, + }); return Ok(amount) } @@ -476,7 +485,12 @@ impl, I: 'static> Pallet { Ok(()) })?; - Self::deposit_event(Event::Transferred(id, source.clone(), dest.clone(), credit)); + Self::deposit_event(Event::Transferred { + asset_id: id, + from: source.clone(), + to: dest.clone(), + amount: credit, + }); Ok(credit) } @@ -514,7 +528,7 @@ impl, I: 'static> Pallet { is_frozen: false, }, ); - Self::deposit_event(Event::ForceCreated(id, owner)); + Self::deposit_event(Event::ForceCreated { asset_id: id, owner }); Ok(()) } @@ -554,7 +568,7 @@ impl, I: 'static> Pallet { for ((owner, _), approval) in Approvals::::drain_prefix((&id,)) { T::Currency::unreserve(&owner, approval.deposit); } - Self::deposit_event(Event::Destroyed(id)); + Self::deposit_event(Event::Destroyed { asset_id: id }); Ok(DestroyWitness { accounts: details.accounts, @@ -599,7 +613,12 @@ impl, I: 'static> Pallet { }, )?; Asset::::insert(id, d); - Self::deposit_event(Event::ApprovedTransfer(id, owner.clone(), delegate.clone(), amount)); + Self::deposit_event(Event::ApprovedTransfer { + asset_id: id, + source: owner.clone(), + delegate: delegate.clone(), + amount, + }); Ok(()) } @@ -683,7 +702,13 @@ impl, I: 'static> Pallet { is_frozen: false, }); - Self::deposit_event(Event::MetadataSet(id, name, symbol, decimals, false)); + Self::deposit_event(Event::MetadataSet { + asset_id: id, + name, + symbol, + decimals, + is_frozen: false, + }); Ok(()) }) } diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index b89d411e41db8..f2bc86843ad9c 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -379,47 +379,70 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { - /// Some asset class was created. \[asset_id, creator, owner\] - Created(T::AssetId, T::AccountId, T::AccountId), - /// Some assets were issued. \[asset_id, owner, total_supply\] - Issued(T::AssetId, T::AccountId, T::Balance), - /// Some assets were transferred. \[asset_id, from, to, amount\] - Transferred(T::AssetId, T::AccountId, T::AccountId, T::Balance), - /// Some assets were destroyed. \[asset_id, owner, balance\] - Burned(T::AssetId, T::AccountId, T::Balance), - /// The management team changed \[asset_id, issuer, admin, freezer\] - TeamChanged(T::AssetId, T::AccountId, T::AccountId, T::AccountId), - /// The owner changed \[asset_id, owner\] - OwnerChanged(T::AssetId, T::AccountId), - /// Some account `who` was frozen. \[asset_id, who\] - Frozen(T::AssetId, T::AccountId), - /// Some account `who` was thawed. \[asset_id, who\] - Thawed(T::AssetId, T::AccountId), - /// Some asset `asset_id` was frozen. \[asset_id\] - AssetFrozen(T::AssetId), - /// Some asset `asset_id` was thawed. \[asset_id\] - AssetThawed(T::AssetId), + /// Some asset class was created. + Created { asset_id: T::AssetId, creator: T::AccountId, owner: T::AccountId }, + /// Some assets were issued. + Issued { asset_id: T::AssetId, owner: T::AccountId, total_supply: T::Balance }, + /// Some assets were transferred. + Transferred { + asset_id: T::AssetId, + from: T::AccountId, + to: T::AccountId, + amount: T::Balance, + }, + /// Some assets were destroyed. + Burned { asset_id: T::AssetId, owner: T::AccountId, balance: T::Balance }, + /// The management team changed. + TeamChanged { + asset_id: T::AssetId, + issuer: T::AccountId, + admin: T::AccountId, + freezer: T::AccountId, + }, + /// The owner changed. + OwnerChanged { asset_id: T::AssetId, owner: T::AccountId }, + /// Some account `who` was frozen. + Frozen { asset_id: T::AssetId, who: T::AccountId }, + /// Some account `who` was thawed. + Thawed { asset_id: T::AssetId, who: T::AccountId }, + /// Some asset `asset_id` was frozen. + AssetFrozen { asset_id: T::AssetId }, + /// Some asset `asset_id` was thawed. + AssetThawed { asset_id: T::AssetId }, /// An asset class was destroyed. - Destroyed(T::AssetId), - /// Some asset class was force-created. \[asset_id, owner\] - ForceCreated(T::AssetId, T::AccountId), - /// New metadata has been set for an asset. \[asset_id, name, symbol, decimals, is_frozen\] - MetadataSet(T::AssetId, Vec, Vec, u8, bool), - /// Metadata has been cleared for an asset. \[asset_id\] - MetadataCleared(T::AssetId), + Destroyed { asset_id: T::AssetId }, + /// Some asset class was force-created. + ForceCreated { asset_id: T::AssetId, owner: T::AccountId }, + /// New metadata has been set for an asset. + MetadataSet { + asset_id: T::AssetId, + name: Vec, + symbol: Vec, + decimals: u8, + is_frozen: bool, + }, + /// Metadata has been cleared for an asset. + MetadataCleared { asset_id: T::AssetId }, /// (Additional) funds have been approved for transfer to a destination account. - /// \[asset_id, source, delegate, amount\] - ApprovedTransfer(T::AssetId, T::AccountId, T::AccountId, T::Balance), + ApprovedTransfer { + asset_id: T::AssetId, + source: T::AccountId, + delegate: T::AccountId, + amount: T::Balance, + }, /// An approval for account `delegate` was cancelled by `owner`. - /// \[id, owner, delegate\] - ApprovalCancelled(T::AssetId, T::AccountId, T::AccountId), + ApprovalCancelled { asset_id: T::AssetId, owner: T::AccountId, delegate: T::AccountId }, /// An `amount` was transferred in its entirety from `owner` to `destination` by /// the approved `delegate`. - /// \[id, owner, delegate, destination\] - TransferredApproved(T::AssetId, T::AccountId, T::AccountId, T::AccountId, T::Balance), + TransferredApproved { + asset_id: T::AssetId, + owner: T::AccountId, + delegate: T::AccountId, + destination: T::AccountId, + amount: T::Balance, + }, /// An asset has had its attributes changed by the `Force` origin. - /// \[id\] - AssetStatusChanged(T::AssetId), + AssetStatusChanged { asset_id: T::AssetId }, } #[pallet::error] @@ -505,7 +528,7 @@ pub mod pallet { is_frozen: false, }, ); - Self::deposit_event(Event::Created(id, owner, admin)); + Self::deposit_event(Event::Created { asset_id: id, creator: owner, owner: admin }); Ok(()) } @@ -761,7 +784,7 @@ pub mod pallet { Account::::mutate(id, &who, |a| a.is_frozen = true); - Self::deposit_event(Event::::Frozen(id, who)); + Self::deposit_event(Event::::Frozen { asset_id: id, who }); Ok(()) } @@ -790,7 +813,7 @@ pub mod pallet { Account::::mutate(id, &who, |a| a.is_frozen = false); - Self::deposit_event(Event::::Thawed(id, who)); + Self::deposit_event(Event::::Thawed { asset_id: id, who }); Ok(()) } @@ -816,7 +839,7 @@ pub mod pallet { d.is_frozen = true; - Self::deposit_event(Event::::AssetFrozen(id)); + Self::deposit_event(Event::::AssetFrozen { asset_id: id }); Ok(()) }) } @@ -843,7 +866,7 @@ pub mod pallet { d.is_frozen = false; - Self::deposit_event(Event::::AssetThawed(id)); + Self::deposit_event(Event::::AssetThawed { asset_id: id }); Ok(()) }) } @@ -882,7 +905,7 @@ pub mod pallet { details.owner = owner.clone(); - Self::deposit_event(Event::OwnerChanged(id, owner)); + Self::deposit_event(Event::OwnerChanged { asset_id: id, owner }); Ok(()) }) } @@ -920,7 +943,7 @@ pub mod pallet { details.admin = admin.clone(); details.freezer = freezer.clone(); - Self::deposit_event(Event::TeamChanged(id, issuer, admin, freezer)); + Self::deposit_event(Event::TeamChanged { asset_id: id, issuer, admin, freezer }); Ok(()) }) } @@ -977,7 +1000,7 @@ pub mod pallet { Metadata::::try_mutate_exists(id, |metadata| { let deposit = metadata.take().ok_or(Error::::Unknown)?.deposit; T::Currency::unreserve(&d.owner, deposit); - Self::deposit_event(Event::MetadataCleared(id)); + Self::deposit_event(Event::MetadataCleared { asset_id: id }); Ok(()) }) } @@ -1024,7 +1047,13 @@ pub mod pallet { is_frozen, }); - Self::deposit_event(Event::MetadataSet(id, name, symbol, decimals, is_frozen)); + Self::deposit_event(Event::MetadataSet { + asset_id: id, + name, + symbol, + decimals, + is_frozen, + }); Ok(()) }) } @@ -1051,7 +1080,7 @@ pub mod pallet { Metadata::::try_mutate_exists(id, |metadata| { let deposit = metadata.take().ok_or(Error::::Unknown)?.deposit; T::Currency::unreserve(&d.owner, deposit); - Self::deposit_event(Event::MetadataCleared(id)); + Self::deposit_event(Event::MetadataCleared { asset_id: id }); Ok(()) }) } @@ -1103,7 +1132,7 @@ pub mod pallet { asset.is_frozen = is_frozen; *maybe_asset = Some(asset); - Self::deposit_event(Event::AssetStatusChanged(id)); + Self::deposit_event(Event::AssetStatusChanged { asset_id: id }); Ok(()) }) } @@ -1169,7 +1198,7 @@ pub mod pallet { d.approvals.saturating_dec(); Asset::::insert(id, d); - Self::deposit_event(Event::ApprovalCancelled(id, owner, delegate)); + Self::deposit_event(Event::ApprovalCancelled { asset_id: id, owner, delegate }); Ok(()) } @@ -1211,7 +1240,7 @@ pub mod pallet { d.approvals.saturating_dec(); Asset::::insert(id, d); - Self::deposit_event(Event::ApprovalCancelled(id, owner, delegate)); + Self::deposit_event(Event::ApprovalCancelled { asset_id: id, owner, delegate }); Ok(()) } diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 5250fafaa8f9a..e24a1d45215da 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -500,7 +500,12 @@ fn transferring_less_than_one_unit_is_fine() { assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 0)); - System::assert_last_event(mock::Event::Assets(crate::Event::Transferred(0, 1, 2, 0))); + System::assert_last_event(mock::Event::Assets(crate::Event::Transferred { + asset_id: 0, + from: 1, + to: 2, + amount: 0, + })); }); } diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 9cf92c3bd2337..4775cd06b1afd 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -218,13 +218,12 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Swap created. \[account, proof, swap\] - NewSwap(T::AccountId, HashedProof, PendingSwap), + /// Swap created. + NewSwap { account: T::AccountId, proof: HashedProof, swap: PendingSwap }, /// Swap claimed. The last parameter indicates whether the execution succeeds. - /// \[account, proof, success\] - SwapClaimed(T::AccountId, HashedProof, bool), - /// Swap cancelled. \[account, proof\] - SwapCancelled(T::AccountId, HashedProof), + SwapClaimed { account: T::AccountId, proof: HashedProof, success: bool }, + /// Swap cancelled. + SwapCancelled { account: T::AccountId, proof: HashedProof }, } /// Old name generated by `decl_event`. @@ -268,7 +267,7 @@ pub mod pallet { }; PendingSwaps::::insert(target.clone(), hashed_proof.clone(), swap.clone()); - Self::deposit_event(Event::NewSwap(target, hashed_proof, swap)); + Self::deposit_event(Event::NewSwap { account: target, proof: hashed_proof, swap }); Ok(()) } @@ -304,7 +303,11 @@ pub mod pallet { PendingSwaps::::remove(target.clone(), hashed_proof.clone()); - Self::deposit_event(Event::SwapClaimed(target, hashed_proof, succeeded)); + Self::deposit_event(Event::SwapClaimed { + account: target, + proof: hashed_proof, + success: succeeded, + }); Ok(()) } @@ -333,7 +336,7 @@ pub mod pallet { swap.action.cancel(&swap.source); PendingSwaps::::remove(&target, hashed_proof.clone()); - Self::deposit_event(Event::SwapCancelled(target, hashed_proof)); + Self::deposit_event(Event::SwapCancelled { account: target, proof: hashed_proof }); Ok(()) } diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 8d74ecc9bd2d1..8be1afbe29bbe 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -168,8 +168,8 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(crate) fn deposit_event)] pub enum Event { - /// Moved an account from one bag to another. \[who, from, to\]. - Rebagged(T::AccountId, VoteWeight, VoteWeight), + /// Moved an account from one bag to another. + Rebagged { who: T::AccountId, from: VoteWeight, to: VoteWeight }, } #[pallet::call] @@ -216,7 +216,7 @@ impl Pallet { let maybe_movement = list::Node::::get(&account) .and_then(|node| List::update_position_for(node, new_weight)); if let Some((from, to)) = maybe_movement { - Self::deposit_event(Event::::Rebagged(account.clone(), from, to)); + Self::deposit_event(Event::::Rebagged { who: account.clone(), from, to }); }; maybe_movement } diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index da8019583c3be..b7c64da460768 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -346,7 +346,7 @@ pub mod pallet { (account.free, account.reserved) })?; - Self::deposit_event(Event::BalanceSet(who, free, reserved)); + Self::deposit_event(Event::BalanceSet { who, free, reserved }); Ok(().into()) } @@ -454,31 +454,33 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { - /// An account was created with some free balance. \[account, free_balance\] - Endowed(T::AccountId, T::Balance), + /// An account was created with some free balance. + Endowed { account: T::AccountId, free_balance: T::Balance }, /// An account was removed whose balance was non-zero but below ExistentialDeposit, - /// resulting in an outright loss. \[account, balance\] - DustLost(T::AccountId, T::Balance), - /// Transfer succeeded. \[from, to, value\] - Transfer(T::AccountId, T::AccountId, T::Balance), - /// A balance was set by root. \[who, free, reserved\] - BalanceSet(T::AccountId, T::Balance, T::Balance), - /// Some balance was reserved (moved from free to reserved). \[who, value\] - Reserved(T::AccountId, T::Balance), - /// Some balance was unreserved (moved from reserved to free). \[who, value\] - Unreserved(T::AccountId, T::Balance), + /// resulting in an outright loss. + DustLost { account: T::AccountId, amount: T::Balance }, + /// Transfer succeeded. + Transfer { from: T::AccountId, to: T::AccountId, amount: T::Balance }, + /// A balance was set by root. + BalanceSet { who: T::AccountId, free: T::Balance, reserved: T::Balance }, + /// Some balance was reserved (moved from free to reserved). + Reserved { who: T::AccountId, amount: T::Balance }, + /// Some balance was unreserved (moved from reserved to free). + Unreserved { who: T::AccountId, amount: T::Balance }, /// Some balance was moved from the reserve of the first account to the second account. /// Final argument indicates the destination balance type. - /// \[from, to, balance, destination_status\] - ReserveRepatriated(T::AccountId, T::AccountId, T::Balance, Status), - /// Some amount was deposited into the account (e.g. for transaction fees). \[who, - /// deposit\] - Deposit(T::AccountId, T::Balance), - /// Some amount was withdrawn from the account (e.g. for transaction fees). \[who, value\] - Withdraw(T::AccountId, T::Balance), - /// Some amount was removed from the account (e.g. for misbehavior). \[who, - /// amount_slashed\] - Slashed(T::AccountId, T::Balance), + ReserveRepatriated { + from: T::AccountId, + to: T::AccountId, + amount: T::Balance, + destination_status: Status, + }, + /// Some amount was deposited (e.g. for transaction fees). + Deposit { who: T::AccountId, amount: T::Balance }, + /// Some amount was withdrawn from the account (e.g. for transaction fees). + Withdraw { who: T::AccountId, amount: T::Balance }, + /// Some amount was removed from the account (e.g. for misbehavior). + Slashed { who: T::AccountId, amount: T::Balance }, } /// Old name generated by `decl_event`. @@ -742,7 +744,7 @@ pub struct DustCleaner, I: 'static = ()>( impl, I: 'static> Drop for DustCleaner { fn drop(&mut self) { if let Some((who, dust)) = self.0.take() { - Pallet::::deposit_event(Event::DustLost(who, dust.peek())); + Pallet::::deposit_event(Event::DustLost { account: who, amount: dust.peek() }); T::DustRemoval::on_unbalanced(dust); } } @@ -939,7 +941,7 @@ impl, I: 'static> Pallet { }); result.map(|(maybe_endowed, maybe_dust, result)| { if let Some(endowed) = maybe_endowed { - Self::deposit_event(Event::Endowed(who.clone(), endowed)); + Self::deposit_event(Event::Endowed { account: who.clone(), free_balance: endowed }); } let dust_cleaner = DustCleaner(maybe_dust.map(|dust| (who.clone(), dust))); (result, dust_cleaner) @@ -1051,12 +1053,12 @@ impl, I: 'static> Pallet { }, )?; - Self::deposit_event(Event::ReserveRepatriated( - slashed.clone(), - beneficiary.clone(), - actual, - status, - )); + Self::deposit_event(Event::ReserveRepatriated { + from: slashed.clone(), + to: beneficiary.clone(), + amount: actual, + destination_status: status, + }); Ok(actual) } } @@ -1109,7 +1111,7 @@ impl, I: 'static> fungible::Mutate for Pallet { Ok(()) })?; TotalIssuance::::mutate(|t| *t += amount); - Self::deposit_event(Event::Deposit(who.clone(), amount)); + Self::deposit_event(Event::Deposit { who: who.clone(), amount }); Ok(()) } @@ -1130,7 +1132,7 @@ impl, I: 'static> fungible::Mutate for Pallet { }, )?; TotalIssuance::::mutate(|t| *t -= actual); - Self::deposit_event(Event::Withdraw(who.clone(), amount)); + Self::deposit_event(Event::Withdraw { who: who.clone(), amount }); Ok(actual) } } @@ -1151,7 +1153,11 @@ impl, I: 'static> fungible::Unbalanced for Pallet DispatchResult { Self::mutate_account(who, |account| { account.free = amount; - Self::deposit_event(Event::BalanceSet(who.clone(), account.free, account.reserved)); + Self::deposit_event(Event::BalanceSet { + who: who.clone(), + free: account.free, + reserved: account.reserved, + }); })?; Ok(()) } @@ -1531,7 +1537,11 @@ where )?; // Emit transfer event. - Self::deposit_event(Event::Transfer(transactor.clone(), dest.clone(), value)); + Self::deposit_event(Event::Transfer { + from: transactor.clone(), + to: dest.clone(), + amount: value, + }); Ok(()) } @@ -1595,10 +1605,10 @@ where }, ) { Ok((imbalance, not_slashed)) => { - Self::deposit_event(Event::Slashed( - who.clone(), - value.saturating_sub(not_slashed), - )); + Self::deposit_event(Event::Slashed { + who: who.clone(), + amount: value.saturating_sub(not_slashed), + }); return (imbalance, not_slashed) }, Err(_) => (), @@ -1625,7 +1635,7 @@ where |account, is_new| -> Result { ensure!(!is_new, Error::::DeadAccount); account.free = account.free.checked_add(&value).ok_or(ArithmeticError::Overflow)?; - Self::deposit_event(Event::Deposit(who.clone(), value)); + Self::deposit_event(Event::Deposit { who: who.clone(), amount: value }); Ok(PositiveImbalance::new(value)) }, ) @@ -1658,7 +1668,7 @@ where None => return Ok(Self::PositiveImbalance::zero()), }; - Self::deposit_event(Event::Deposit(who.clone(), value)); + Self::deposit_event(Event::Deposit { who: who.clone(), amount: value }); Ok(PositiveImbalance::new(value)) }, ) @@ -1696,7 +1706,7 @@ where account.free = new_free_account; - Self::deposit_event(Event::Withdraw(who.clone(), value)); + Self::deposit_event(Event::Withdraw { who: who.clone(), amount: value }); Ok(NegativeImbalance::new(value)) }, ) @@ -1729,7 +1739,11 @@ where SignedImbalance::Negative(NegativeImbalance::new(account.free - value)) }; account.free = value; - Self::deposit_event(Event::BalanceSet(who.clone(), account.free, account.reserved)); + Self::deposit_event(Event::BalanceSet { + who: who.clone(), + free: account.free, + reserved: account.reserved, + }); Ok(imbalance) }, ) @@ -1773,7 +1787,7 @@ where Self::ensure_can_withdraw(&who, value.clone(), WithdrawReasons::RESERVE, account.free) })?; - Self::deposit_event(Event::Reserved(who.clone(), value)); + Self::deposit_event(Event::Reserved { who: who.clone(), amount: value }); Ok(()) } @@ -1805,7 +1819,7 @@ where }, }; - Self::deposit_event(Event::Unreserved(who.clone(), actual.clone())); + Self::deposit_event(Event::Unreserved { who: who.clone(), amount: actual.clone() }); value - actual } @@ -1846,10 +1860,10 @@ where (NegativeImbalance::new(actual), value - actual) }) { Ok((imbalance, not_slashed)) => { - Self::deposit_event(Event::Slashed( - who.clone(), - value.saturating_sub(not_slashed), - )); + Self::deposit_event(Event::Slashed { + who: who.clone(), + amount: value.saturating_sub(not_slashed), + }); return (imbalance, not_slashed) }, Err(_) => (), @@ -1992,7 +2006,7 @@ where // `actual <= to_change` and `to_change <= amount`; qed; reserves[index].amount -= actual; - Self::deposit_event(Event::Slashed(who.clone(), actual)); + Self::deposit_event(Event::Slashed { who: who.clone(), amount: actual }); (imb, value - actual) }, Err(_) => (NegativeImbalance::zero(), value), diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 6a6ebc692c34a..1f7f4dd03716d 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -314,7 +314,7 @@ macro_rules! decl_tests { <$ext_builder>::default().monied(true).build().execute_with(|| { assert_eq!(Balances::total_balance(&1), 10); assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop)); - System::assert_last_event(Event::Balances(crate::Event::Deposit(1, 10))); + System::assert_last_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 10 })); assert_eq!(Balances::total_balance(&1), 20); assert_eq!(>::get(), 120); }); @@ -342,7 +342,7 @@ macro_rules! decl_tests { fn balance_works() { <$ext_builder>::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 42); - System::assert_has_event(Event::Balances(crate::Event::Deposit(1, 42))); + System::assert_has_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 42 })); assert_eq!(Balances::free_balance(1), 42); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::total_balance(&1), 42); @@ -444,7 +444,7 @@ macro_rules! decl_tests { let _ = Balances::withdraw( &2, 11, WithdrawReasons::TRANSFER, ExistenceRequirement::KeepAlive ); - System::assert_last_event(Event::Balances(crate::Event::Withdraw(2, 11))); + System::assert_last_event(Event::Balances(crate::Event::Withdraw { who: 2, amount: 11 })); assert_eq!(Balances::free_balance(2), 100); assert_eq!(>::get(), 100); }); @@ -505,7 +505,7 @@ macro_rules! decl_tests { assert_ok!(Balances::reserve(&1, 110)); assert_ok!(Balances::repatriate_reserved(&1, &2, 41, Status::Free), 0); System::assert_last_event( - Event::Balances(crate::Event::ReserveRepatriated(1, 2, 41, Status::Free)) + Event::Balances(crate::Event::ReserveRepatriated { from: 1, to: 2, amount: 41, destination_status: Status::Free }) ); assert_eq!(Balances::reserved_balance(1), 69); assert_eq!(Balances::free_balance(1), 0); @@ -724,18 +724,18 @@ macro_rules! decl_tests { System::set_block_number(2); assert_ok!(Balances::reserve(&1, 10)); - System::assert_last_event(Event::Balances(crate::Event::Reserved(1, 10))); + System::assert_last_event(Event::Balances(crate::Event::Reserved { who: 1, amount: 10 })); System::set_block_number(3); assert!(Balances::unreserve(&1, 5).is_zero()); - System::assert_last_event(Event::Balances(crate::Event::Unreserved(1, 5))); + System::assert_last_event(Event::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); System::set_block_number(4); assert_eq!(Balances::unreserve(&1, 6), 1); // should only unreserve 5 - System::assert_last_event(Event::Balances(crate::Event::Unreserved(1, 5))); + System::assert_last_event(Event::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); }); } @@ -751,8 +751,8 @@ macro_rules! decl_tests { events(), [ Event::System(system::Event::NewAccount(1)), - Event::Balances(crate::Event::Endowed(1, 100)), - Event::Balances(crate::Event::BalanceSet(1, 100, 0)), + Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), + Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] ); @@ -763,8 +763,8 @@ macro_rules! decl_tests { events(), [ Event::System(system::Event::KilledAccount(1)), - Event::Balances(crate::Event::DustLost(1, 99)), - Event::Balances(crate::Event::Slashed(1, 1)), + Event::Balances(crate::Event::DustLost { account: 1, amount: 99 }), + Event::Balances(crate::Event::Slashed { who: 1, amount: 1 }), ] ); }); @@ -782,8 +782,8 @@ macro_rules! decl_tests { events(), [ Event::System(system::Event::NewAccount(1)), - Event::Balances(crate::Event::Endowed(1, 100)), - Event::Balances(crate::Event::BalanceSet(1, 100, 0)), + Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), + Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] ); @@ -794,7 +794,7 @@ macro_rules! decl_tests { events(), [ Event::System(system::Event::KilledAccount(1)), - Event::Balances(crate::Event::Slashed(1, 100)), + Event::Balances(crate::Event::Slashed { who: 1, amount: 100 }), ] ); }); @@ -814,7 +814,7 @@ macro_rules! decl_tests { assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0)); // Account is still alive assert!(System::account_exists(&1)); - System::assert_last_event(Event::Balances(crate::Event::Slashed(1, 900))); + System::assert_last_event(Event::Balances(crate::Event::Slashed { who: 1, amount: 900 })); // SCENARIO: Slash will kill account because not enough balance left. assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index b2113a916caa5..c9de662b9e8fe 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -164,8 +164,8 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { events(), [ Event::System(system::Event::NewAccount(1)), - Event::Balances(crate::Event::Endowed(1, 100)), - Event::Balances(crate::Event::BalanceSet(1, 100, 0)), + Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), + Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] ); @@ -173,7 +173,7 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { assert_eq!(res, (NegativeImbalance::new(98), 0)); // no events - assert_eq!(events(), [Event::Balances(crate::Event::Slashed(1, 98))]); + assert_eq!(events(), [Event::Balances(crate::Event::Slashed { who: 1, amount: 98 })]); let res = Balances::slash(&1, 1); assert_eq!(res, (NegativeImbalance::new(1), 0)); @@ -182,8 +182,8 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { events(), [ Event::System(system::Event::KilledAccount(1)), - Event::Balances(crate::Event::DustLost(1, 1)), - Event::Balances(crate::Event::Slashed(1, 1)), + Event::Balances(crate::Event::DustLost { account: 1, amount: 1 }), + Event::Balances(crate::Event::Slashed { who: 1, amount: 1 }) ] ); }); diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 9a5ebb003af2c..43edd16baf3b3 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -169,9 +169,16 @@ fn transfer_dust_removal_tst1_should_work() { // Verify the events assert_eq!(System::events().len(), 12); - System::assert_has_event(Event::Balances(crate::Event::Transfer(2, 3, 450))); - System::assert_has_event(Event::Balances(crate::Event::DustLost(2, 50))); - System::assert_has_event(Event::Balances(crate::Event::Deposit(1, 50))); + System::assert_has_event(Event::Balances(crate::Event::Transfer { + from: 2, + to: 3, + amount: 450, + })); + System::assert_has_event(Event::Balances(crate::Event::DustLost { + account: 2, + amount: 50, + })); + System::assert_has_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 50 })); }); } @@ -197,9 +204,16 @@ fn transfer_dust_removal_tst2_should_work() { // Verify the events assert_eq!(System::events().len(), 10); - System::assert_has_event(Event::Balances(crate::Event::Transfer(2, 1, 450))); - System::assert_has_event(Event::Balances(crate::Event::DustLost(2, 50))); - System::assert_has_event(Event::Balances(crate::Event::Deposit(1, 50))); + System::assert_has_event(Event::Balances(crate::Event::Transfer { + from: 2, + to: 1, + amount: 450, + })); + System::assert_has_event(Event::Balances(crate::Event::DustLost { + account: 2, + amount: 50, + })); + System::assert_has_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 50 })); }); } @@ -234,13 +248,18 @@ fn repatriating_reserved_balance_dust_removal_should_work() { // Verify the events assert_eq!(System::events().len(), 11); - System::assert_has_event(Event::Balances(crate::Event::ReserveRepatriated( - 2, - 1, - 450, - Status::Free, - ))); - System::assert_has_event(Event::Balances(crate::Event::DustLost(2, 50))); - System::assert_last_event(Event::Balances(crate::Event::Deposit(1, 50))); + System::assert_has_event(Event::Balances(crate::Event::ReserveRepatriated { + from: 2, + to: 1, + amount: 450, + destination_status: Status::Free, + })); + + System::assert_has_event(Event::Balances(crate::Event::DustLost { + account: 2, + amount: 50, + })); + + System::assert_last_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 50 })); }); } diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 33af02fbb9ea0..341d019c49d47 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -172,7 +172,7 @@ benchmarks! { let bounty_id = BountyCount::::get() - 1; }: close_bounty(RawOrigin::Root, bounty_id) verify { - assert_last_event::(Event::BountyCanceled(bounty_id).into()) + assert_last_event::(Event::BountyCanceled { index: bounty_id }.into()) } extend_bounty_expiry { @@ -184,7 +184,7 @@ benchmarks! { let curator = T::Lookup::lookup(curator_lookup).map_err(<&str>::from)?; }: _(RawOrigin::Signed(curator), bounty_id, Vec::new()) verify { - assert_last_event::(Event::BountyExtended(bounty_id).into()) + assert_last_event::(Event::BountyExtended { index: bounty_id }.into()) } spend_funds { @@ -207,7 +207,7 @@ benchmarks! { verify { ensure!(budget_remaining < BalanceOf::::max_value(), "Budget not used"); ensure!(missed_any == false, "Missed some"); - assert_last_event::(Event::BountyBecameActive(b - 1).into()) + assert_last_event::(Event::BountyBecameActive { index: b - 1 }.into()) } impl_benchmark_test_suite!(Bounties, crate::tests::new_test_ext(), crate::tests::Test) diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 69380502bad3f..5c96fdcc6b98f 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -228,20 +228,20 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// New bounty proposal. \[index\] - BountyProposed(BountyIndex), - /// A bounty proposal was rejected; funds were slashed. \[index, bond\] - BountyRejected(BountyIndex, BalanceOf), - /// A bounty proposal is funded and became active. \[index\] - BountyBecameActive(BountyIndex), - /// A bounty is awarded to a beneficiary. \[index, beneficiary\] - BountyAwarded(BountyIndex, T::AccountId), - /// A bounty is claimed by beneficiary. \[index, payout, beneficiary\] - BountyClaimed(BountyIndex, BalanceOf, T::AccountId), - /// A bounty is cancelled. \[index\] - BountyCanceled(BountyIndex), - /// A bounty expiry is extended. \[index\] - BountyExtended(BountyIndex), + /// New bounty proposal. + BountyProposed { index: BountyIndex }, + /// A bounty proposal was rejected; funds were slashed. + BountyRejected { index: BountyIndex, bond: BalanceOf }, + /// A bounty proposal is funded and became active. + BountyBecameActive { index: BountyIndex }, + /// A bounty is awarded to a beneficiary. + BountyAwarded { index: BountyIndex, beneficiary: T::AccountId }, + /// A bounty is claimed by beneficiary. + BountyClaimed { index: BountyIndex, payout: BalanceOf, beneficiary: T::AccountId }, + /// A bounty is cancelled. + BountyCanceled { index: BountyIndex }, + /// A bounty expiry is extended. + BountyExtended { index: BountyIndex }, } /// Number of bounty proposals that have been made. @@ -526,7 +526,7 @@ pub mod pallet { Ok(()) })?; - Self::deposit_event(Event::::BountyAwarded(bounty_id, beneficiary)); + Self::deposit_event(Event::::BountyAwarded { index: bounty_id, beneficiary }); Ok(()) } @@ -571,7 +571,11 @@ pub mod pallet { BountyDescriptions::::remove(bounty_id); - Self::deposit_event(Event::::BountyClaimed(bounty_id, payout, beneficiary)); + Self::deposit_event(Event::::BountyClaimed { + index: bounty_id, + payout, + beneficiary, + }); Ok(()) } else { Err(Error::::UnexpectedStatus.into()) @@ -612,7 +616,10 @@ pub mod pallet { T::OnSlash::on_unbalanced(imbalance); *maybe_bounty = None; - Self::deposit_event(Event::::BountyRejected(bounty_id, value)); + Self::deposit_event(Event::::BountyRejected { + index: bounty_id, + bond: value, + }); // Return early, nothing else to do. return Ok( Some(::WeightInfo::close_bounty_proposed()).into() @@ -656,7 +663,7 @@ pub mod pallet { debug_assert!(res.is_ok()); *maybe_bounty = None; - Self::deposit_event(Event::::BountyCanceled(bounty_id)); + Self::deposit_event(Event::::BountyCanceled { index: bounty_id }); Ok(Some(::WeightInfo::close_bounty_active()).into()) }, ) @@ -696,7 +703,7 @@ pub mod pallet { Ok(()) })?; - Self::deposit_event(Event::::BountyExtended(bounty_id)); + Self::deposit_event(Event::::BountyExtended { index: bounty_id }); Ok(()) } } @@ -753,7 +760,7 @@ impl Pallet { Bounties::::insert(index, &bounty); BountyDescriptions::::insert(index, description); - Self::deposit_event(Event::::BountyProposed(index)); + Self::deposit_event(Event::::BountyProposed { index }); Ok(()) } @@ -787,7 +794,7 @@ impl pallet_treasury::SpendFunds for Pallet { bounty.value, )); - Self::deposit_event(Event::::BountyBecameActive(index)); + Self::deposit_event(Event::::BountyBecameActive { index }); false } else { *missed_any = true; diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index 96c09581fdd1e..344bb6495c3bc 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -398,7 +398,7 @@ fn propose_bounty_works() { assert_ok!(Bounties::propose_bounty(Origin::signed(0), 10, b"1234567890".to_vec())); - assert_eq!(last_event(), BountiesEvent::BountyProposed(0)); + assert_eq!(last_event(), BountiesEvent::BountyProposed { index: 0 }); let deposit: u64 = 85 + 5; assert_eq!(Balances::reserved_balance(0), deposit); @@ -460,7 +460,7 @@ fn close_bounty_works() { let deposit: u64 = 80 + 5; - assert_eq!(last_event(), BountiesEvent::BountyRejected(0, deposit)); + assert_eq!(last_event(), BountiesEvent::BountyRejected { index: 0, bond: deposit }); assert_eq!(Balances::reserved_balance(0), 0); assert_eq!(Balances::free_balance(0), 100 - deposit); @@ -692,7 +692,10 @@ fn award_and_claim_bounty_works() { assert_ok!(Bounties::claim_bounty(Origin::signed(1), 0)); - assert_eq!(last_event(), BountiesEvent::BountyClaimed(0, 56, 3)); + assert_eq!( + last_event(), + BountiesEvent::BountyClaimed { index: 0, payout: 56, beneficiary: 3 } + ); assert_eq!(Balances::free_balance(4), 14); // initial 10 + fee 4 @@ -731,7 +734,10 @@ fn claim_handles_high_fee() { assert_ok!(Bounties::claim_bounty(Origin::signed(1), 0)); - assert_eq!(last_event(), BountiesEvent::BountyClaimed(0, 0, 3)); + assert_eq!( + last_event(), + BountiesEvent::BountyClaimed { index: 0, payout: 0, beneficiary: 3 } + ); assert_eq!(Balances::free_balance(4), 70); // 30 + 50 - 10 assert_eq!(Balances::free_balance(3), 0); @@ -808,7 +814,7 @@ fn award_and_cancel() { assert_ok!(Bounties::unassign_curator(Origin::root(), 0)); assert_ok!(Bounties::close_bounty(Origin::root(), 0)); - assert_eq!(last_event(), BountiesEvent::BountyCanceled(0)); + assert_eq!(last_event(), BountiesEvent::BountyCanceled { index: 0 }); assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 0); diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index c26a2b43f5b75..5ca57cf72e8fc 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -128,7 +128,7 @@ benchmarks_instance_pallet! { let proposal_hash = T::Hashing::hash_of(&proposal); // Note that execution fails due to mis-matched origin assert_last_event::( - Event::MemberExecuted(proposal_hash, Err(DispatchError::BadOrigin)).into() + Event::MemberExecuted { proposal_hash, result: Err(DispatchError::BadOrigin) }.into() ); } @@ -159,7 +159,7 @@ benchmarks_instance_pallet! { let proposal_hash = T::Hashing::hash_of(&proposal); // Note that execution fails due to mis-matched origin assert_last_event::( - Event::Executed(proposal_hash, Err(DispatchError::BadOrigin)).into() + Event::Executed { proposal_hash, result: Err(DispatchError::BadOrigin) }.into() ); } @@ -203,7 +203,7 @@ benchmarks_instance_pallet! { // New proposal is recorded assert_eq!(Collective::::proposals().len(), p as usize); let proposal_hash = T::Hashing::hash_of(&proposal); - assert_last_event::(Event::Proposed(caller, p - 1, proposal_hash, threshold).into()); + assert_last_event::(Event::Proposed { account: caller, proposal_index: p - 1, proposal_hash, threshold }.into()); } vote { @@ -359,7 +359,7 @@ benchmarks_instance_pallet! { verify { // The last proposal is removed. assert_eq!(Collective::::proposals().len(), (p - 1) as usize); - assert_last_event::(Event::Disapproved(last_hash).into()); + assert_last_event::(Event::Disapproved { proposal_hash: last_hash }.into()); } close_early_approved { @@ -440,7 +440,7 @@ benchmarks_instance_pallet! { verify { // The last proposal is removed. assert_eq!(Collective::::proposals().len(), (p - 1) as usize); - assert_last_event::(Event::Executed(last_hash, Err(DispatchError::BadOrigin)).into()); + assert_last_event::(Event::Executed { proposal_hash: last_hash, result: Err(DispatchError::BadOrigin) }.into()); } close_disapproved { @@ -514,7 +514,7 @@ benchmarks_instance_pallet! { }: close(SystemOrigin::Signed(caller), last_hash, index, Weight::max_value(), bytes_in_storage) verify { assert_eq!(Collective::::proposals().len(), (p - 1) as usize); - assert_last_event::(Event::Disapproved(last_hash).into()); + assert_last_event::(Event::Disapproved { proposal_hash: last_hash }.into()); } close_approved { @@ -586,7 +586,7 @@ benchmarks_instance_pallet! { }: close(SystemOrigin::Signed(caller), last_hash, p - 1, Weight::max_value(), bytes_in_storage) verify { assert_eq!(Collective::::proposals().len(), (p - 1) as usize); - assert_last_event::(Event::Executed(last_hash, Err(DispatchError::BadOrigin)).into()); + assert_last_event::(Event::Executed { proposal_hash: last_hash, result: Err(DispatchError::BadOrigin) }.into()); } disapprove_proposal { @@ -634,7 +634,7 @@ benchmarks_instance_pallet! { }: _(SystemOrigin::Root, last_hash) verify { assert_eq!(Collective::::proposals().len(), (p - 1) as usize); - assert_last_event::(Event::Disapproved(last_hash).into()); + assert_last_event::(Event::Disapproved { proposal_hash: last_hash }.into()); } impl_benchmark_test_suite!(Collective, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 2797d01ffcdba..26b18b6232577 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -279,27 +279,31 @@ pub mod pallet { pub enum Event, I: 'static = ()> { /// A motion (given hash) has been proposed (by given account) with a threshold (given /// `MemberCount`). - /// \[account, proposal_index, proposal_hash, threshold\] - Proposed(T::AccountId, ProposalIndex, T::Hash, MemberCount), + Proposed { + account: T::AccountId, + proposal_index: ProposalIndex, + proposal_hash: T::Hash, + threshold: MemberCount, + }, /// A motion (given hash) has been voted on by given account, leaving /// a tally (yes votes and no votes given respectively as `MemberCount`). - /// \[account, proposal_hash, voted, yes, no\] - Voted(T::AccountId, T::Hash, bool, MemberCount, MemberCount), + Voted { + account: T::AccountId, + proposal_hash: T::Hash, + voted: bool, + yes: MemberCount, + no: MemberCount, + }, /// A motion was approved by the required threshold. - /// \[proposal_hash\] - Approved(T::Hash), + Approved { proposal_hash: T::Hash }, /// A motion was not approved by the required threshold. - /// \[proposal_hash\] - Disapproved(T::Hash), + Disapproved { proposal_hash: T::Hash }, /// A motion was executed; result will be `Ok` if it returned without error. - /// \[proposal_hash, result\] - Executed(T::Hash, DispatchResult), + Executed { proposal_hash: T::Hash, result: DispatchResult }, /// A single member did some action; result will be `Ok` if it returned without error. - /// \[proposal_hash, result\] - MemberExecuted(T::Hash, DispatchResult), + MemberExecuted { proposal_hash: T::Hash, result: DispatchResult }, /// A proposal was closed because its threshold was reached or after its duration was up. - /// \[proposal_hash, yes, no\] - Closed(T::Hash, MemberCount, MemberCount), + Closed { proposal_hash: T::Hash, yes: MemberCount, no: MemberCount }, } /// Old name generated by `decl_event`. @@ -442,10 +446,10 @@ pub mod pallet { let proposal_hash = T::Hashing::hash_of(&proposal); let result = proposal.dispatch(RawOrigin::Member(who).into()); - Self::deposit_event(Event::MemberExecuted( + Self::deposit_event(Event::MemberExecuted { proposal_hash, - result.map(|_| ()).map_err(|e| e.error), - )); + result: result.map(|_| ()).map_err(|e| e.error), + }); Ok(get_result_weight(result) .map(|w| { @@ -521,10 +525,10 @@ pub mod pallet { if threshold < 2 { let seats = Self::members().len() as MemberCount; let result = proposal.dispatch(RawOrigin::Members(1, seats).into()); - Self::deposit_event(Event::Executed( + Self::deposit_event(Event::Executed { proposal_hash, - result.map(|_| ()).map_err(|e| e.error), - )); + result: result.map(|_| ()).map_err(|e| e.error), + }); Ok(get_result_weight(result) .map(|w| { @@ -552,7 +556,12 @@ pub mod pallet { }; >::insert(proposal_hash, votes); - Self::deposit_event(Event::Proposed(who, index, proposal_hash, threshold)); + Self::deposit_event(Event::Proposed { + account: who, + proposal_index: index, + proposal_hash, + threshold, + }); Ok(Some(T::WeightInfo::propose_proposed( proposal_len as u32, // B @@ -620,7 +629,13 @@ pub mod pallet { let yes_votes = voting.ayes.len() as MemberCount; let no_votes = voting.nays.len() as MemberCount; - Self::deposit_event(Event::Voted(who, proposal, approve, yes_votes, no_votes)); + Self::deposit_event(Event::Voted { + account: who, + proposal_hash: proposal, + voted: approve, + yes: yes_votes, + no: no_votes, + }); Voting::::insert(&proposal, voting); @@ -701,7 +716,7 @@ pub mod pallet { length_bound, proposal_weight_bound, )?; - Self::deposit_event(Event::Closed(proposal_hash, yes_votes, no_votes)); + Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); let (proposal_weight, proposal_count) = Self::do_approve_proposal(seats, yes_votes, proposal_hash, proposal); return Ok(( @@ -713,7 +728,7 @@ pub mod pallet { ) .into()) } else if disapproved { - Self::deposit_event(Event::Closed(proposal_hash, yes_votes, no_votes)); + Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); let proposal_count = Self::do_disapprove_proposal(proposal_hash); return Ok(( Some(T::WeightInfo::close_early_disapproved(seats, proposal_count)), @@ -746,7 +761,7 @@ pub mod pallet { length_bound, proposal_weight_bound, )?; - Self::deposit_event(Event::Closed(proposal_hash, yes_votes, no_votes)); + Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); let (proposal_weight, proposal_count) = Self::do_approve_proposal(seats, yes_votes, proposal_hash, proposal); Ok(( @@ -758,7 +773,7 @@ pub mod pallet { ) .into()) } else { - Self::deposit_event(Event::Closed(proposal_hash, yes_votes, no_votes)); + Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); let proposal_count = Self::do_disapprove_proposal(proposal_hash); Ok((Some(T::WeightInfo::close_disapproved(seats, proposal_count)), Pays::No).into()) } @@ -848,15 +863,15 @@ impl, I: 'static> Pallet { proposal_hash: T::Hash, proposal: >::Proposal, ) -> (Weight, u32) { - Self::deposit_event(Event::Approved(proposal_hash)); + Self::deposit_event(Event::Approved { proposal_hash }); let dispatch_weight = proposal.get_dispatch_info().weight; let origin = RawOrigin::Members(yes_votes, seats).into(); let result = proposal.dispatch(origin); - Self::deposit_event(Event::Executed( + Self::deposit_event(Event::Executed { proposal_hash, - result.map(|_| ()).map_err(|e| e.error), - )); + result: result.map(|_| ()).map_err(|e| e.error), + }); // default to the dispatch info weight for safety let proposal_weight = get_result_weight(result).unwrap_or(dispatch_weight); // P1 @@ -866,7 +881,7 @@ impl, I: 'static> Pallet { fn do_disapprove_proposal(proposal_hash: T::Hash) -> u32 { // disapproved - Self::deposit_event(Event::Disapproved(proposal_hash)); + Self::deposit_event(Event::Disapproved { proposal_hash }); Self::remove_proposal(proposal_hash) } diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index b8feb64867cf8..7e52b10a9b1d6 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -216,11 +216,32 @@ fn close_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed(1, 0, hash, 3))), - record(Event::Collective(CollectiveEvent::Voted(1, hash, true, 1, 0))), - record(Event::Collective(CollectiveEvent::Voted(2, hash, true, 2, 0))), - record(Event::Collective(CollectiveEvent::Closed(hash, 2, 1))), - record(Event::Collective(CollectiveEvent::Disapproved(hash))) + record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 3 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: true, + yes: 1, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 2, + proposal_hash: hash, + voted: true, + yes: 2, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Closed { + proposal_hash: hash, + yes: 2, + no: 1 + })), + record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) ] ); }); @@ -315,11 +336,32 @@ fn close_with_prime_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed(1, 0, hash, 3))), - record(Event::Collective(CollectiveEvent::Voted(1, hash, true, 1, 0))), - record(Event::Collective(CollectiveEvent::Voted(2, hash, true, 2, 0))), - record(Event::Collective(CollectiveEvent::Closed(hash, 2, 1))), - record(Event::Collective(CollectiveEvent::Disapproved(hash))) + record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 3 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: true, + yes: 1, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 2, + proposal_hash: hash, + voted: true, + yes: 2, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Closed { + proposal_hash: hash, + yes: 2, + no: 1 + })), + record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) ] ); }); @@ -354,15 +396,36 @@ fn close_with_voting_prime_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed(1, 0, hash, 3))), - record(Event::Collective(CollectiveEvent::Voted(1, hash, true, 1, 0))), - record(Event::Collective(CollectiveEvent::Voted(2, hash, true, 2, 0))), - record(Event::Collective(CollectiveEvent::Closed(hash, 3, 0))), - record(Event::Collective(CollectiveEvent::Approved(hash))), - record(Event::Collective(CollectiveEvent::Executed( - hash, - Err(DispatchError::BadOrigin) - ))) + record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 3 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: true, + yes: 1, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 2, + proposal_hash: hash, + voted: true, + yes: 2, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Closed { + proposal_hash: hash, + yes: 3, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(Event::Collective(CollectiveEvent::Executed { + proposal_hash: hash, + result: Err(DispatchError::BadOrigin) + })) ] ); }); @@ -404,16 +467,45 @@ fn close_with_no_prime_but_majority_works() { assert_eq!( System::events(), vec![ - record(Event::CollectiveMajority(CollectiveEvent::Proposed(1, 0, hash, 5))), - record(Event::CollectiveMajority(CollectiveEvent::Voted(1, hash, true, 1, 0))), - record(Event::CollectiveMajority(CollectiveEvent::Voted(2, hash, true, 2, 0))), - record(Event::CollectiveMajority(CollectiveEvent::Voted(3, hash, true, 3, 0))), - record(Event::CollectiveMajority(CollectiveEvent::Closed(hash, 5, 0))), - record(Event::CollectiveMajority(CollectiveEvent::Approved(hash))), - record(Event::CollectiveMajority(CollectiveEvent::Executed( - hash, - Err(DispatchError::BadOrigin) - ))) + record(Event::CollectiveMajority(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 5 + })), + record(Event::CollectiveMajority(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: true, + yes: 1, + no: 0 + })), + record(Event::CollectiveMajority(CollectiveEvent::Voted { + account: 2, + proposal_hash: hash, + voted: true, + yes: 2, + no: 0 + })), + record(Event::CollectiveMajority(CollectiveEvent::Voted { + account: 3, + proposal_hash: hash, + voted: true, + yes: 3, + no: 0 + })), + record(Event::CollectiveMajority(CollectiveEvent::Closed { + proposal_hash: hash, + yes: 5, + no: 0 + })), + record(Event::CollectiveMajority(CollectiveEvent::Approved { + proposal_hash: hash + })), + record(Event::CollectiveMajority(CollectiveEvent::Executed { + proposal_hash: hash, + result: Err(DispatchError::BadOrigin) + })) ] ); }); @@ -537,7 +629,12 @@ fn propose_works() { assert_eq!( System::events(), - vec![record(Event::Collective(CollectiveEvent::Proposed(1, 0, hash, 3)))] + vec![record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 3 + }))] ); }); } @@ -696,9 +793,26 @@ fn motions_vote_after_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed(1, 0, hash, 2))), - record(Event::Collective(CollectiveEvent::Voted(1, hash, true, 1, 0))), - record(Event::Collective(CollectiveEvent::Voted(1, hash, false, 0, 1))), + record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 2 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: true, + yes: 1, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: false, + yes: 0, + no: 1 + })), ] ); }); @@ -812,15 +926,36 @@ fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed(1, 0, hash, 2))), - record(Event::Collective(CollectiveEvent::Voted(1, hash, true, 1, 0))), - record(Event::Collective(CollectiveEvent::Voted(2, hash, true, 2, 0))), - record(Event::Collective(CollectiveEvent::Closed(hash, 2, 0))), - record(Event::Collective(CollectiveEvent::Approved(hash))), - record(Event::Collective(CollectiveEvent::Executed( - hash, - Err(DispatchError::BadOrigin) - ))), + record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 2 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: true, + yes: 1, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 2, + proposal_hash: hash, + voted: true, + yes: 2, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Closed { + proposal_hash: hash, + yes: 2, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(Event::Collective(CollectiveEvent::Executed { + proposal_hash: hash, + result: Err(DispatchError::BadOrigin) + })), ] ); @@ -840,14 +975,44 @@ fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed(1, 1, hash, 2))), - record(Event::Collective(CollectiveEvent::Voted(1, hash, true, 1, 0))), - record(Event::Collective(CollectiveEvent::Voted(2, hash, true, 2, 0))), - record(Event::Collective(CollectiveEvent::Voted(3, hash, true, 3, 0))), - record(Event::Collective(CollectiveEvent::Closed(hash, 3, 0))), - record(Event::Collective(CollectiveEvent::Approved(hash))), + record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 1, + proposal_hash: hash, + threshold: 2 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: true, + yes: 1, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 2, + proposal_hash: hash, + voted: true, + yes: 2, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 3, + proposal_hash: hash, + voted: true, + yes: 3, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Closed { + proposal_hash: hash, + yes: 3, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), record(Event::Democracy(mock_democracy::pallet::Event::::ExternalProposed)), - record(Event::Collective(CollectiveEvent::Executed(hash, Ok(())))), + record(Event::Collective(CollectiveEvent::Executed { + proposal_hash: hash, + result: Ok(()) + })), ] ); }); @@ -873,11 +1038,32 @@ fn motions_disapproval_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed(1, 0, hash, 3))), - record(Event::Collective(CollectiveEvent::Voted(1, hash, true, 1, 0))), - record(Event::Collective(CollectiveEvent::Voted(2, hash, false, 1, 1))), - record(Event::Collective(CollectiveEvent::Closed(hash, 1, 1))), - record(Event::Collective(CollectiveEvent::Disapproved(hash))), + record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 3 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: true, + yes: 1, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 2, + proposal_hash: hash, + voted: false, + yes: 1, + no: 1 + })), + record(Event::Collective(CollectiveEvent::Closed { + proposal_hash: hash, + yes: 1, + no: 1 + })), + record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })), ] ); }); @@ -903,15 +1089,36 @@ fn motions_approval_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed(1, 0, hash, 2))), - record(Event::Collective(CollectiveEvent::Voted(1, hash, true, 1, 0))), - record(Event::Collective(CollectiveEvent::Voted(2, hash, true, 2, 0))), - record(Event::Collective(CollectiveEvent::Closed(hash, 2, 0))), - record(Event::Collective(CollectiveEvent::Approved(hash))), - record(Event::Collective(CollectiveEvent::Executed( - hash, - Err(DispatchError::BadOrigin) - ))), + record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 2 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: true, + yes: 1, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 2, + proposal_hash: hash, + voted: true, + yes: 2, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Closed { + proposal_hash: hash, + yes: 2, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(Event::Collective(CollectiveEvent::Executed { + proposal_hash: hash, + result: Err(DispatchError::BadOrigin) + })), ] ); }); @@ -932,7 +1139,12 @@ fn motion_with_no_votes_closes_with_disapproval() { )); assert_eq!( System::events()[0], - record(Event::Collective(CollectiveEvent::Proposed(1, 0, hash, 3))) + record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 3 + })) ); // Closing the motion too early is not possible because it has neither @@ -951,11 +1163,15 @@ fn motion_with_no_votes_closes_with_disapproval() { // Events show that the close ended in a disapproval. assert_eq!( System::events()[1], - record(Event::Collective(CollectiveEvent::Closed(hash, 0, 3))) + record(Event::Collective(CollectiveEvent::Closed { + proposal_hash: hash, + yes: 0, + no: 3 + })) ); assert_eq!( System::events()[2], - record(Event::Collective(CollectiveEvent::Disapproved(hash))) + record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) ); }) } @@ -1015,10 +1231,27 @@ fn disapprove_proposal_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed(1, 0, hash, 2))), - record(Event::Collective(CollectiveEvent::Voted(1, hash, true, 1, 0))), - record(Event::Collective(CollectiveEvent::Voted(2, hash, true, 2, 0))), - record(Event::Collective(CollectiveEvent::Disapproved(hash))), + record(Event::Collective(CollectiveEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 2 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 1, + proposal_hash: hash, + voted: true, + yes: 1, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Voted { + account: 2, + proposal_hash: hash, + voted: true, + yes: 2, + no: 0 + })), + record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })), ] ); }) diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index bd5dbae5b34a6..2214ce8f40b1a 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -447,7 +447,10 @@ fn instantiate_and_call_and_deposit_event() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Deposit(ALICE, 1_000_000)), + event: Event::Balances(pallet_balances::Event::Deposit { + who: ALICE, + amount: 1_000_000 + }), topics: vec![], }, EventRecord { @@ -457,7 +460,10 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed(ALICE, 1_000_000)), + event: Event::Balances(pallet_balances::Event::Endowed { + account: ALICE, + free_balance: 1_000_000 + }), topics: vec![], }, EventRecord { @@ -467,19 +473,19 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed( - addr.clone(), - subsistence * 100 - )), + event: Event::Balances(pallet_balances::Event::Endowed { + account: addr.clone(), + free_balance: subsistence * 100 + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer( - ALICE, - addr.clone(), - subsistence * 100 - )), + event: Event::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), + amount: subsistence * 100 + }), topics: vec![], }, EventRecord { @@ -766,11 +772,11 @@ fn self_destruct_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer( - addr.clone(), - DJANGO, - 100_000, - )), + event: Event::Balances(pallet_balances::Event::Transfer { + from: addr.clone(), + to: DJANGO, + amount: 100_000, + }), topics: vec![], }, EventRecord { diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index 34bcb0da301e6..136c2d2a7c9e2 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -774,7 +774,7 @@ benchmarks! { }: enact_proposal(RawOrigin::Root, proposal_hash, 0) verify { // Fails due to mismatched origin - assert_last_event::(Event::::Executed(0, Err(BadOrigin.into())).into()); + assert_last_event::(Event::::Executed { ref_index: 0, result: Err(BadOrigin.into()) }.into()); } #[extra] diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 893e4676bef7b..529bcebc8e374 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -507,45 +507,45 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A motion has been proposed by a public account. \[proposal_index, deposit\] - Proposed(PropIndex, BalanceOf), - /// A public proposal has been tabled for referendum vote. \[proposal_index, deposit, - /// depositors\] - Tabled(PropIndex, BalanceOf, Vec), + /// A motion has been proposed by a public account. + Proposed { proposal_index: PropIndex, deposit: BalanceOf }, + /// A public proposal has been tabled for referendum vote. + Tabled { proposal_index: PropIndex, deposit: BalanceOf, depositors: Vec }, /// An external proposal has been tabled. ExternalTabled, - /// A referendum has begun. \[ref_index, threshold\] - Started(ReferendumIndex, VoteThreshold), - /// A proposal has been approved by referendum. \[ref_index\] - Passed(ReferendumIndex), - /// A proposal has been rejected by referendum. \[ref_index\] - NotPassed(ReferendumIndex), - /// A referendum has been cancelled. \[ref_index\] - Cancelled(ReferendumIndex), - /// A proposal has been enacted. \[ref_index, result\] - Executed(ReferendumIndex, DispatchResult), - /// An account has delegated their vote to another account. \[who, target\] - Delegated(T::AccountId, T::AccountId), - /// An \[account\] has cancelled a previous delegation operation. - Undelegated(T::AccountId), - /// An external proposal has been vetoed. \[who, proposal_hash, until\] - Vetoed(T::AccountId, T::Hash, T::BlockNumber), - /// A proposal's preimage was noted, and the deposit taken. \[proposal_hash, who, deposit\] - PreimageNoted(T::Hash, T::AccountId, BalanceOf), + /// A referendum has begun. + Started { ref_index: ReferendumIndex, threshold: VoteThreshold }, + /// A proposal has been approved by referendum. + Passed { ref_index: ReferendumIndex }, + /// A proposal has been rejected by referendum. + NotPassed { ref_index: ReferendumIndex }, + /// A referendum has been cancelled. + Cancelled { ref_index: ReferendumIndex }, + /// A proposal has been enacted. + Executed { ref_index: ReferendumIndex, result: DispatchResult }, + /// An account has delegated their vote to another account. + Delegated { who: T::AccountId, target: T::AccountId }, + /// An account has cancelled a previous delegation operation. + Undelegated { account: T::AccountId }, + /// An external proposal has been vetoed. + Vetoed { who: T::AccountId, proposal_hash: T::Hash, until: T::BlockNumber }, + /// A proposal's preimage was noted, and the deposit taken. + PreimageNoted { proposal_hash: T::Hash, who: T::AccountId, deposit: BalanceOf }, /// A proposal preimage was removed and used (the deposit was returned). - /// \[proposal_hash, provider, deposit\] - PreimageUsed(T::Hash, T::AccountId, BalanceOf), + PreimageUsed { proposal_hash: T::Hash, provider: T::AccountId, deposit: BalanceOf }, /// A proposal could not be executed because its preimage was invalid. - /// \[proposal_hash, ref_index\] - PreimageInvalid(T::Hash, ReferendumIndex), + PreimageInvalid { proposal_hash: T::Hash, ref_index: ReferendumIndex }, /// A proposal could not be executed because its preimage was missing. - /// \[proposal_hash, ref_index\] - PreimageMissing(T::Hash, ReferendumIndex), + PreimageMissing { proposal_hash: T::Hash, ref_index: ReferendumIndex }, /// A registered preimage was removed and the deposit collected by the reaper. - /// \[proposal_hash, provider, deposit, reaper\] - PreimageReaped(T::Hash, T::AccountId, BalanceOf, T::AccountId), - /// A proposal \[hash\] has been blacklisted permanently. - Blacklisted(T::Hash), + PreimageReaped { + proposal_hash: T::Hash, + provider: T::AccountId, + deposit: BalanceOf, + reaper: T::AccountId, + }, + /// A proposal_hash has been blacklisted permanently. + Blacklisted { proposal_hash: T::Hash }, } #[pallet::error] @@ -657,7 +657,7 @@ pub mod pallet { >::append((index, proposal_hash, who)); - Self::deposit_event(Event::::Proposed(index, value)); + Self::deposit_event(Event::::Proposed { proposal_index: index, deposit: value }); Ok(()) } @@ -882,7 +882,7 @@ pub mod pallet { let until = >::block_number() + T::CooloffPeriod::get(); >::insert(&proposal_hash, (until, existing_vetoers)); - Self::deposit_event(Event::::Vetoed(who, proposal_hash, until)); + Self::deposit_event(Event::::Vetoed { who, proposal_hash, until }); >::kill(); Ok(()) } @@ -1104,7 +1104,12 @@ pub mod pallet { T::Currency::repatriate_reserved(&provider, &who, deposit, BalanceStatus::Free); debug_assert!(res.is_ok()); >::remove(&proposal_hash); - Self::deposit_event(Event::::PreimageReaped(proposal_hash, provider, deposit, who)); + Self::deposit_event(Event::::PreimageReaped { + proposal_hash, + provider, + deposit, + reaper: who, + }); Ok(()) } @@ -1249,7 +1254,7 @@ pub mod pallet { } } - Self::deposit_event(Event::::Blacklisted(proposal_hash)); + Self::deposit_event(Event::::Blacklisted { proposal_hash }); Ok(()) } @@ -1330,7 +1335,7 @@ impl Pallet { /// Remove a referendum. pub fn internal_cancel_referendum(ref_index: ReferendumIndex) { - Self::deposit_event(Event::::Cancelled(ref_index)); + Self::deposit_event(Event::::Cancelled { ref_index }); ReferendumInfoOf::::remove(ref_index); } @@ -1532,7 +1537,7 @@ impl Pallet { T::Currency::extend_lock(DEMOCRACY_ID, &who, balance, WithdrawReasons::TRANSFER); Ok(votes) })?; - Self::deposit_event(Event::::Delegated(who, target)); + Self::deposit_event(Event::::Delegated { who, target }); Ok(votes) } @@ -1558,7 +1563,7 @@ impl Pallet { Voting::Direct { .. } => Err(Error::::NotDelegating.into()), } })?; - Self::deposit_event(Event::::Undelegated(who)); + Self::deposit_event(Event::::Undelegated { account: who }); Ok(votes) } @@ -1589,7 +1594,7 @@ impl Pallet { ReferendumStatus { end, proposal_hash, threshold, delay, tally: Default::default() }; let item = ReferendumInfo::Ongoing(status); >::insert(ref_index, item); - Self::deposit_event(Event::::Started(ref_index, threshold)); + Self::deposit_event(Event::::Started { ref_index, threshold }); ref_index } @@ -1635,7 +1640,11 @@ impl Pallet { for d in &depositors { T::Currency::unreserve(d, deposit); } - Self::deposit_event(Event::::Tabled(prop_index, deposit, depositors)); + Self::deposit_event(Event::::Tabled { + proposal_index: prop_index, + deposit, + depositors, + }); Self::inject_referendum( now + T::VotingPeriod::get(), proposal, @@ -1655,22 +1664,25 @@ impl Pallet { if let Ok(proposal) = T::Proposal::decode(&mut &data[..]) { let err_amount = T::Currency::unreserve(&provider, deposit); debug_assert!(err_amount.is_zero()); - Self::deposit_event(Event::::PreimageUsed(proposal_hash, provider, deposit)); + Self::deposit_event(Event::::PreimageUsed { proposal_hash, provider, deposit }); let res = proposal .dispatch(frame_system::RawOrigin::Root.into()) .map(|_| ()) .map_err(|e| e.error); - Self::deposit_event(Event::::Executed(index, res)); + Self::deposit_event(Event::::Executed { ref_index: index, result: res }); Ok(()) } else { T::Slash::on_unbalanced(T::Currency::slash_reserved(&provider, deposit).0); - Self::deposit_event(Event::::PreimageInvalid(proposal_hash, index)); + Self::deposit_event(Event::::PreimageInvalid { + proposal_hash, + ref_index: index, + }); Err(Error::::PreimageInvalid.into()) } } else { - Self::deposit_event(Event::::PreimageMissing(proposal_hash, index)); + Self::deposit_event(Event::::PreimageMissing { proposal_hash, ref_index: index }); Err(Error::::PreimageMissing.into()) } } @@ -1684,7 +1696,7 @@ impl Pallet { let approved = status.threshold.approved(status.tally, total_issuance); if approved { - Self::deposit_event(Event::::Passed(index)); + Self::deposit_event(Event::::Passed { ref_index: index }); if status.delay.is_zero() { let _ = Self::do_enact_proposal(status.proposal_hash, index); } else { @@ -1713,7 +1725,7 @@ impl Pallet { } } } else { - Self::deposit_event(Event::::NotPassed(index)); + Self::deposit_event(Event::::NotPassed { ref_index: index }); } approved @@ -1870,7 +1882,7 @@ impl Pallet { }; >::insert(proposal_hash, a); - Self::deposit_event(Event::::PreimageNoted(proposal_hash, who, deposit)); + Self::deposit_event(Event::::PreimageNoted { proposal_hash, who, deposit }); Ok(()) } @@ -1896,7 +1908,7 @@ impl Pallet { }; >::insert(proposal_hash, a); - Self::deposit_event(Event::::PreimageNoted(proposal_hash, who, free)); + Self::deposit_event(Event::::PreimageNoted { proposal_hash, who, deposit: free }); Ok(()) } diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 4c4de82af592f..cdf5a2098d6bb 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -886,10 +886,10 @@ pub mod pallet { log!(info, "queued unsigned solution with score {:?}", ready.score); let ejected_a_solution = >::exists(); >::put(ready); - Self::deposit_event(Event::SolutionStored( - ElectionCompute::Unsigned, - ejected_a_solution, - )); + Self::deposit_event(Event::SolutionStored { + election_compute: ElectionCompute::Unsigned, + prev_ejected: ejected_a_solution, + }); Ok(None.into()) } @@ -1012,7 +1012,10 @@ pub mod pallet { } signed_submissions.put(); - Self::deposit_event(Event::SolutionStored(ElectionCompute::Signed, ejected_a_solution)); + Self::deposit_event(Event::SolutionStored { + election_compute: ElectionCompute::Signed, + prev_ejected: ejected_a_solution, + }); Ok(()) } } @@ -1026,18 +1029,18 @@ pub mod pallet { /// solution is unsigned, this means that it has also been processed. /// /// The `bool` is `true` when a previous solution was ejected to make room for this one. - SolutionStored(ElectionCompute, bool), + SolutionStored { election_compute: ElectionCompute, prev_ejected: bool }, /// The election has been finalized, with `Some` of the given computation, or else if the /// election failed, `None`. - ElectionFinalized(Option), + ElectionFinalized { election_compute: Option }, /// An account has been rewarded for their signed submission being finalized. - Rewarded(::AccountId, BalanceOf), + Rewarded { account: ::AccountId, value: BalanceOf }, /// An account has been slashed for submitting an invalid signed submission. - Slashed(::AccountId, BalanceOf), + Slashed { account: ::AccountId, value: BalanceOf }, /// The signed phase of the given round has started. - SignedPhaseStarted(u32), + SignedPhaseStarted { round: u32 }, /// The unsigned phase of the given round has started. - UnsignedPhaseStarted(u32), + UnsignedPhaseStarted { round: u32 }, } /// Error of the pallet that can be returned in response to dispatches. @@ -1245,7 +1248,7 @@ impl Pallet { pub fn on_initialize_open_signed() { log!(info, "Starting signed phase round {}.", Self::round()); >::put(Phase::Signed); - Self::deposit_event(Event::SignedPhaseStarted(Self::round())); + Self::deposit_event(Event::SignedPhaseStarted { round: Self::round() }); } /// Logic for [`>::on_initialize`] when unsigned phase is being opened. @@ -1253,7 +1256,7 @@ impl Pallet { let round = Self::round(); log!(info, "Starting unsigned phase round {} enabled {}.", round, enabled); >::put(Phase::Unsigned((enabled, now))); - Self::deposit_event(Event::UnsignedPhaseStarted(round)); + Self::deposit_event(Event::UnsignedPhaseStarted { round }); } /// Parts of [`create_snapshot`] that happen inside of this pallet. @@ -1473,14 +1476,14 @@ impl Pallet { |ReadySolution { supports, compute, .. }| Ok((supports, compute)), ) .map(|(supports, compute)| { - Self::deposit_event(Event::ElectionFinalized(Some(compute))); + Self::deposit_event(Event::ElectionFinalized { election_compute: Some(compute) }); if Self::round() != 1 { log!(info, "Finalized election round with compute {:?}.", compute); } supports }) .map_err(|err| { - Self::deposit_event(Event::ElectionFinalized(None)); + Self::deposit_event(Event::ElectionFinalized { election_compute: None }); if Self::round() != 1 { log!(warn, "Failed to finalize election round. reason {:?}", err); } @@ -1737,7 +1740,7 @@ mod tests { roll_to(15); assert_eq!(MultiPhase::current_phase(), Phase::Signed); - assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted(1)]); + assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); assert!(MultiPhase::snapshot().is_some()); assert_eq!(MultiPhase::round(), 1); @@ -1750,7 +1753,10 @@ mod tests { assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); assert_eq!( multi_phase_events(), - vec![Event::SignedPhaseStarted(1), Event::UnsignedPhaseStarted(1)], + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 } + ], ); assert!(MultiPhase::snapshot().is_some()); @@ -1861,7 +1867,7 @@ mod tests { assert_eq!(MultiPhase::current_phase(), Phase::Off); roll_to(15); - assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted(1)]); + assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!(MultiPhase::round(), 1); @@ -1873,8 +1879,8 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted(1), - Event::ElectionFinalized(Some(ElectionCompute::Fallback)) + Event::SignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { election_compute: Some(ElectionCompute::Fallback) } ], ); // All storage items must be cleared. @@ -1896,7 +1902,7 @@ mod tests { assert_eq!(MultiPhase::current_phase(), Phase::Off); roll_to(15); - assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted(1)]); + assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!(MultiPhase::round(), 1); diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 61215059c53a6..b762ad706486c 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -429,7 +429,7 @@ impl Pallet { >::put(ready_solution); // emit reward event - Self::deposit_event(crate::Event::Rewarded(who.clone(), reward)); + Self::deposit_event(crate::Event::Rewarded { account: who.clone(), value: reward }); // unreserve deposit. let _remaining = T::Currency::unreserve(who, deposit); @@ -446,7 +446,7 @@ impl Pallet { /// /// Infallible pub fn finalize_signed_phase_reject_solution(who: &T::AccountId, deposit: BalanceOf) { - Self::deposit_event(crate::Event::Slashed(who.clone(), deposit)); + Self::deposit_event(crate::Event::Slashed { account: who.clone(), value: deposit }); let (negative_imbalance, _remaining) = T::Currency::slash_reserved(who, deposit); debug_assert!(_remaining.is_zero()); T::SlashHandler::on_unbalanced(negative_imbalance); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index d7b42383da757..116c0937bf983 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -425,7 +425,7 @@ pub mod pallet { Renouncing::Member => { let _ = Self::remove_and_replace_member(&who, false) .map_err(|_| Error::::InvalidRenouncing)?; - Self::deposit_event(Event::Renounced(who)); + Self::deposit_event(Event::Renounced { candidate: who }); }, Renouncing::RunnerUp => { >::try_mutate::<_, Error, _>(|runners_up| { @@ -437,7 +437,7 @@ pub mod pallet { let SeatHolder { deposit, .. } = runners_up.remove(index); let _remainder = T::Currency::unreserve(&who, deposit); debug_assert!(_remainder.is_zero()); - Self::deposit_event(Event::Renounced(who)); + Self::deposit_event(Event::Renounced { candidate: who }); Ok(()) })?; }, @@ -450,7 +450,7 @@ pub mod pallet { let (_removed, deposit) = candidates.remove(index); let _remainder = T::Currency::unreserve(&who, deposit); debug_assert!(_remainder.is_zero()); - Self::deposit_event(Event::Renounced(who)); + Self::deposit_event(Event::Renounced { candidate: who }); Ok(()) })?; }, @@ -496,7 +496,7 @@ pub mod pallet { let had_replacement = Self::remove_and_replace_member(&who, true)?; debug_assert_eq!(has_replacement, had_replacement); - Self::deposit_event(Event::MemberKicked(who.clone())); + Self::deposit_event(Event::MemberKicked { member: who.clone() }); if !had_replacement { Self::do_phragmen(); @@ -534,29 +534,32 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A new term with \[new_members\]. This indicates that enough candidates existed to run + /// A new term with new_members. This indicates that enough candidates existed to run /// the election, not that enough have has been elected. The inner value must be examined /// for this purpose. A `NewTerm(\[\])` indicates that some candidates got their bond /// slashed and none were elected, whilst `EmptyTerm` means that no candidates existed to /// begin with. - NewTerm(Vec<(::AccountId, BalanceOf)>), + NewTerm { new_members: Vec<(::AccountId, BalanceOf)> }, /// No (or not enough) candidates existed for this round. This is different from /// `NewTerm(\[\])`. See the description of `NewTerm`. EmptyTerm, /// Internal error happened while trying to perform election. ElectionError, - /// A \[member\] has been removed. This should always be followed by either `NewTerm` or + /// A member has been removed. This should always be followed by either `NewTerm` or /// `EmptyTerm`. - MemberKicked(::AccountId), + MemberKicked { member: ::AccountId }, /// Someone has renounced their candidacy. - Renounced(::AccountId), - /// A \[candidate\] was slashed by \[amount\] due to failing to obtain a seat as member or + Renounced { candidate: ::AccountId }, + /// A candidate was slashed by amount due to failing to obtain a seat as member or /// runner-up. /// /// Note that old members and runners-up are also candidates. - CandidateSlashed(::AccountId, BalanceOf), - /// A \[seat holder\] was slashed by \[amount\] by being forcefully removed from the set. - SeatHolderSlashed(::AccountId, BalanceOf), + CandidateSlashed { candidate: ::AccountId, amount: BalanceOf }, + /// A seat holder was slashed by amount by being forcefully removed from the set. + SeatHolderSlashed { + seat_holder: ::AccountId, + amount: BalanceOf, + }, } #[deprecated(note = "use `Event` instead")] @@ -748,7 +751,10 @@ impl Pallet { let (imbalance, _remainder) = T::Currency::slash_reserved(who, removed.deposit); debug_assert!(_remainder.is_zero()); T::LoserCandidate::on_unbalanced(imbalance); - Self::deposit_event(Event::SeatHolderSlashed(who.clone(), removed.deposit)); + Self::deposit_event(Event::SeatHolderSlashed { + seat_holder: who.clone(), + amount: removed.deposit, + }); } else { T::Currency::unreserve(who, removed.deposit); } @@ -1001,7 +1007,10 @@ impl Pallet { { let (imbalance, _) = T::Currency::slash_reserved(c, *d); T::LoserCandidate::on_unbalanced(imbalance); - Self::deposit_event(Event::CandidateSlashed(c.clone(), *d)); + Self::deposit_event(Event::CandidateSlashed { + candidate: c.clone(), + amount: *d, + }); } }); @@ -1041,7 +1050,7 @@ impl Pallet { // clean candidates. >::kill(); - Self::deposit_event(Event::NewTerm(new_members_sorted_by_id)); + Self::deposit_event(Event::NewTerm { new_members: new_members_sorted_by_id }); >::mutate(|v| *v += 1); }) .map_err(|e| { @@ -2147,10 +2156,9 @@ mod tests { System::set_block_number(5); Elections::on_initialize(System::block_number()); - System::assert_last_event(Event::Elections(super::Event::NewTerm(vec![ - (4, 40), - (5, 50), - ]))); + System::assert_last_event(Event::Elections(super::Event::NewTerm { + new_members: vec![(4, 40), (5, 50)], + })); assert_eq!(members_and_stake(), vec![(4, 40), (5, 50)]); assert_eq!(runners_up_and_stake(), vec![]); @@ -2161,7 +2169,9 @@ mod tests { System::set_block_number(10); Elections::on_initialize(System::block_number()); - System::assert_last_event(Event::Elections(super::Event::NewTerm(vec![]))); + System::assert_last_event(Event::Elections(super::Event::NewTerm { + new_members: vec![], + })); // outgoing have lost their bond. assert_eq!(balances(&4), (37, 0)); @@ -2231,7 +2241,9 @@ mod tests { assert_eq!(Elections::election_rounds(), 1); assert!(members_ids().is_empty()); - System::assert_last_event(Event::Elections(super::Event::NewTerm(vec![]))); + System::assert_last_event(Event::Elections(super::Event::NewTerm { + new_members: vec![], + })); }); } @@ -2583,10 +2595,9 @@ mod tests { // 5 is an outgoing loser. will also get slashed. assert_eq!(balances(&5), (45, 2)); - System::assert_has_event(Event::Elections(super::Event::NewTerm(vec![ - (4, 40), - (5, 50), - ]))); + System::assert_has_event(Event::Elections(super::Event::NewTerm { + new_members: vec![(4, 40), (5, 50)], + })); }) } diff --git a/frame/elections/src/lib.rs b/frame/elections/src/lib.rs index ac13bce31b0f6..7ca11f4ed20e8 100644 --- a/frame/elections/src/lib.rs +++ b/frame/elections/src/lib.rs @@ -465,15 +465,14 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Reaped \[voter, reaper\]. - VoterReaped(T::AccountId, T::AccountId), - /// Slashed \[reaper\]. - BadReaperSlashed(T::AccountId), - /// A tally (for approval votes of \[seats\]) has started. - TallyStarted(u32), + /// Reaped + VoterReaped { voter: T::AccountId, reaper: T::AccountId }, + /// Slashed + BadReaperSlashed { reaper: T::AccountId }, + /// A tally (for approval votes of seats) has started. + TallyStarted { seats: u32 }, /// A tally (for approval votes of seat(s)) has ended (with one or more new members). - /// \[incoming, outgoing\] - TallyFinalized(Vec, Vec), + TallyFinalized { incoming: Vec, outgoing: Vec }, } #[pallet::call] @@ -590,11 +589,11 @@ pub mod pallet { T::VotingBond::get(), BalanceStatus::Free, )?; - Self::deposit_event(Event::::VoterReaped(who, reporter)); + Self::deposit_event(Event::::VoterReaped { voter: who, reaper: reporter }); } else { let imbalance = T::Currency::slash_reserved(&reporter, T::VotingBond::get()).0; T::BadReaper::on_unbalanced(imbalance); - Self::deposit_event(Event::::BadReaperSlashed(reporter)); + Self::deposit_event(Event::::BadReaperSlashed { reaper: reporter }); } Ok(()) } @@ -1024,7 +1023,7 @@ impl Pallet { leaderboard_size ]); - Self::deposit_event(Event::::TallyStarted(empty_seats as u32)); + Self::deposit_event(Event::::TallyStarted { seats: empty_seats as u32 }); } } @@ -1118,7 +1117,7 @@ impl Pallet { new_candidates.truncate(last_index + 1); } - Self::deposit_event(Event::::TallyFinalized(incoming, outgoing)); + Self::deposit_event(Event::::TallyFinalized { incoming, outgoing }); >::put(new_candidates); CandidateCount::::put(count); diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index b172acb66d324..25ff76f4d1514 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -525,7 +525,7 @@ pub mod pallet { }); // Let's deposit an event to let the outside world know this happened. - Self::deposit_event(Event::AccumulateDummy(increase_by)); + Self::deposit_event(Event::AccumulateDummy { balance: increase_by }); // All good, no refund. Ok(()) @@ -557,7 +557,7 @@ pub mod pallet { // Put the new value into storage. >::put(new_value); - Self::deposit_event(Event::SetDummy(new_value)); + Self::deposit_event(Event::SetDummy { balance: new_value }); // All good, no refund. Ok(()) @@ -574,9 +574,16 @@ pub mod pallet { pub enum Event { // Just a normal `enum`, here's a dummy event to ensure it compiles. /// Dummy event, just here so there's a generic type that's used. - AccumulateDummy(BalanceOf), - SetDummy(BalanceOf), - SetBar(T::AccountId, BalanceOf), + AccumulateDummy { + balance: BalanceOf, + }, + SetDummy { + balance: BalanceOf, + }, + SetBar { + account: T::AccountId, + balance: BalanceOf, + }, } // pallet::storage attributes allow for type-safe usage of the Substrate storage database, diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index e5f2e00d9a344..9812d35ffa074 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -291,8 +291,7 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Event generated when new price is accepted to contribute to the average. - /// \[price, who\] - NewPrice(u32, T::AccountId), + NewPrice { price: u32, who: T::AccountId }, } #[pallet::validate_unsigned] @@ -658,7 +657,7 @@ impl Pallet { .expect("The average is not empty, because it was just mutated; qed"); log::info!("Current average price is: {}", average); // here we are raising the NewPrice event - Self::deposit_event(Event::NewPrice(price, who)); + Self::deposit_event(Event::NewPrice { price, who }); } /// Calculate current average price. diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index 1594601b457cb..b494eed67445c 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -272,17 +272,23 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// A bid was successfully placed. - /// \[ who, amount, duration \] - BidPlaced(T::AccountId, BalanceOf, u32), + BidPlaced { who: T::AccountId, amount: BalanceOf, duration: u32 }, /// A bid was successfully removed (before being accepted as a gilt). - /// \[ who, amount, duration \] - BidRetracted(T::AccountId, BalanceOf, u32), + BidRetracted { who: T::AccountId, amount: BalanceOf, duration: u32 }, /// A bid was accepted as a gilt. The balance may not be released until expiry. - /// \[ index, expiry, who, amount \] - GiltIssued(ActiveIndex, T::BlockNumber, T::AccountId, BalanceOf), + GiltIssued { + index: ActiveIndex, + expiry: T::BlockNumber, + who: T::AccountId, + amount: BalanceOf, + }, /// An expired gilt has been thawed. - /// \[ index, who, original_amount, additional_amount \] - GiltThawed(ActiveIndex, T::AccountId, BalanceOf, BalanceOf), + GiltThawed { + index: ActiveIndex, + who: T::AccountId, + original_amount: BalanceOf, + additional_amount: BalanceOf, + }, } #[pallet::error] @@ -376,7 +382,7 @@ pub mod pallet { qs[queue_index].0 += net.0; qs[queue_index].1 = qs[queue_index].1.saturating_add(net.1); }); - Self::deposit_event(Event::BidPlaced(who.clone(), amount, duration)); + Self::deposit_event(Event::BidPlaced { who: who.clone(), amount, duration }); Ok(().into()) } @@ -414,7 +420,7 @@ pub mod pallet { }); T::Currency::unreserve(&bid.who, bid.amount); - Self::deposit_event(Event::BidRetracted(bid.who, bid.amount, duration)); + Self::deposit_event(Event::BidRetracted { who: bid.who, amount: bid.amount, duration }); Ok(().into()) } @@ -493,7 +499,12 @@ pub mod pallet { debug_assert!(err_amt.is_zero()); } - let e = Event::GiltThawed(index, gilt.who, gilt.amount, gilt_value); + let e = Event::GiltThawed { + index, + who: gilt.who, + original_amount: gilt.amount, + additional_amount: gilt_value, + }; Self::deposit_event(e); }); @@ -603,7 +614,8 @@ pub mod pallet { totals.frozen += bid.amount; totals.proportion = totals.proportion.saturating_add(proportion); totals.index += 1; - let e = Event::GiltIssued(index, expiry, who.clone(), amount); + let e = + Event::GiltIssued { index, expiry, who: who.clone(), amount }; Self::deposit_event(e); let gilt = ActiveGilt { amount, proportion, who, expiry }; Active::::insert(index, gilt); diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 0e7d885649cc3..b289da464a93f 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -154,9 +154,9 @@ pub mod pallet { // enact the change if we've reached the enacting block if block_number == pending_change.scheduled_at + pending_change.delay { Self::set_grandpa_authorities(&pending_change.next_authorities); - Self::deposit_event(Event::NewAuthorities( - pending_change.next_authorities.to_vec(), - )); + Self::deposit_event(Event::NewAuthorities { + authority_set: pending_change.next_authorities.to_vec(), + }); >::kill(); } } @@ -255,8 +255,8 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(fn deposit_event)] pub enum Event { - /// New authority set has been applied. \[authority_set\] - NewAuthorities(AuthorityList), + /// New authority set has been applied. + NewAuthorities { authority_set: AuthorityList }, /// Current authority set has been paused. Paused, /// Current authority set has been resumed. diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 98f54f966fadc..6dc0a26da8bd3 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -57,7 +57,10 @@ fn authorities_change_logged() { System::events(), vec![EventRecord { phase: Phase::Finalization, - event: Event::NewAuthorities(to_authorities(vec![(4, 1), (5, 1), (6, 1)])).into(), + event: Event::NewAuthorities { + authority_set: to_authorities(vec![(4, 1), (5, 1), (6, 1)]) + } + .into(), topics: vec![], },] ); @@ -93,7 +96,10 @@ fn authorities_change_logged_after_delay() { System::events(), vec![EventRecord { phase: Phase::Finalization, - event: Event::NewAuthorities(to_authorities(vec![(4, 1), (5, 1), (6, 1)])).into(), + event: Event::NewAuthorities { + authority_set: to_authorities(vec![(4, 1), (5, 1), (6, 1)]) + } + .into(), topics: vec![], },] ); diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 68869a43992f9..db257fec43a13 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -153,7 +153,7 @@ benchmarks! { }; }: _(RawOrigin::Signed(caller.clone()), Box::new(create_identity_info::(x))) verify { - assert_last_event::(Event::::IdentitySet(caller).into()); + assert_last_event::(Event::::IdentitySet { who: caller }.into()); } // We need to split `set_subs` into two benchmarks to accurately isolate the potential @@ -237,7 +237,7 @@ benchmarks! { }; }: _(RawOrigin::Signed(caller.clone()), r - 1, 10u32.into()) verify { - assert_last_event::(Event::::JudgementRequested(caller, r-1).into()); + assert_last_event::(Event::::JudgementRequested { who: caller, registrar_index: r-1 }.into()); } cancel_request { @@ -257,7 +257,7 @@ benchmarks! { Identity::::request_judgement(caller_origin, r - 1, 10u32.into())?; }: _(RawOrigin::Signed(caller.clone()), r - 1) verify { - assert_last_event::(Event::::JudgementUnrequested(caller, r-1).into()); + assert_last_event::(Event::::JudgementUnrequested { who: caller, registrar_index: r-1 }.into()); } set_fee { @@ -328,7 +328,7 @@ benchmarks! { Identity::::request_judgement(user_origin.clone(), r, 10u32.into())?; }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable) verify { - assert_last_event::(Event::::JudgementGiven(user, r).into()) + assert_last_event::(Event::::JudgementGiven { target: user, registrar_index: r }.into()) } kill_identity { diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 4d86efd27e534..b4b52331618cb 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -241,28 +241,27 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A name was set or reset (which will remove all judgements). \[who\] - IdentitySet(T::AccountId), - /// A name was cleared, and the given balance returned. \[who, deposit\] - IdentityCleared(T::AccountId, BalanceOf), - /// A name was removed and the given balance slashed. \[who, deposit\] - IdentityKilled(T::AccountId, BalanceOf), - /// A judgement was asked from a registrar. \[who, registrar_index\] - JudgementRequested(T::AccountId, RegistrarIndex), - /// A judgement request was retracted. \[who, registrar_index\] - JudgementUnrequested(T::AccountId, RegistrarIndex), - /// A judgement was given by a registrar. \[target, registrar_index\] - JudgementGiven(T::AccountId, RegistrarIndex), - /// A registrar was added. \[registrar_index\] - RegistrarAdded(RegistrarIndex), - /// A sub-identity was added to an identity and the deposit paid. \[sub, main, deposit\] - SubIdentityAdded(T::AccountId, T::AccountId, BalanceOf), + /// A name was set or reset (which will remove all judgements). + IdentitySet { who: T::AccountId }, + /// A name was cleared, and the given balance returned. + IdentityCleared { who: T::AccountId, deposit: BalanceOf }, + /// A name was removed and the given balance slashed. + IdentityKilled { who: T::AccountId, deposit: BalanceOf }, + /// A judgement was asked from a registrar. + JudgementRequested { who: T::AccountId, registrar_index: RegistrarIndex }, + /// A judgement request was retracted. + JudgementUnrequested { who: T::AccountId, registrar_index: RegistrarIndex }, + /// A judgement was given by a registrar. + JudgementGiven { target: T::AccountId, registrar_index: RegistrarIndex }, + /// A registrar was added. + RegistrarAdded { registrar_index: RegistrarIndex }, + /// A sub-identity was added to an identity and the deposit paid. + SubIdentityAdded { sub: T::AccountId, main: T::AccountId, deposit: BalanceOf }, /// A sub-identity was removed from an identity and the deposit freed. - /// \[sub, main, deposit\] - SubIdentityRemoved(T::AccountId, T::AccountId, BalanceOf), + SubIdentityRemoved { sub: T::AccountId, main: T::AccountId, deposit: BalanceOf }, /// A sub-identity was cleared, and the given deposit repatriated from the - /// main identity account to the sub-identity account. \[sub, main, deposit\] - SubIdentityRevoked(T::AccountId, T::AccountId, BalanceOf), + /// main identity account to the sub-identity account. + SubIdentityRevoked { sub: T::AccountId, main: T::AccountId, deposit: BalanceOf }, } #[pallet::call] @@ -301,7 +300,7 @@ pub mod pallet { }, )?; - Self::deposit_event(Event::RegistrarAdded(i)); + Self::deposit_event(Event::RegistrarAdded { registrar_index: i }); Ok(Some(T::WeightInfo::add_registrar(registrar_count as u32)).into()) } @@ -364,7 +363,7 @@ pub mod pallet { let judgements = id.judgements.len(); >::insert(&sender, id); - Self::deposit_event(Event::IdentitySet(sender)); + Self::deposit_event(Event::IdentitySet { who: sender }); Ok(Some(T::WeightInfo::set_identity( judgements as u32, // R @@ -489,7 +488,7 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&sender, deposit.clone()); debug_assert!(err_amount.is_zero()); - Self::deposit_event(Event::IdentityCleared(sender, deposit)); + Self::deposit_event(Event::IdentityCleared { who: sender, deposit }); Ok(Some(T::WeightInfo::clear_identity( id.judgements.len() as u32, // R @@ -558,7 +557,10 @@ pub mod pallet { let extra_fields = id.info.additional.len(); >::insert(&sender, id); - Self::deposit_event(Event::JudgementRequested(sender, reg_index)); + Self::deposit_event(Event::JudgementRequested { + who: sender, + registrar_index: reg_index, + }); Ok(Some(T::WeightInfo::request_judgement(judgements as u32, extra_fields as u32)) .into()) @@ -608,7 +610,10 @@ pub mod pallet { let extra_fields = id.info.additional.len(); >::insert(&sender, id); - Self::deposit_event(Event::JudgementUnrequested(sender, reg_index)); + Self::deposit_event(Event::JudgementUnrequested { + who: sender, + registrar_index: reg_index, + }); Ok(Some(T::WeightInfo::cancel_request(judgements as u32, extra_fields as u32)).into()) } @@ -791,7 +796,7 @@ pub mod pallet { let judgements = id.judgements.len(); let extra_fields = id.info.additional.len(); >::insert(&target, id); - Self::deposit_event(Event::JudgementGiven(target, reg_index)); + Self::deposit_event(Event::JudgementGiven { target, registrar_index: reg_index }); Ok(Some(T::WeightInfo::provide_judgement(judgements as u32, extra_fields as u32)) .into()) @@ -839,7 +844,7 @@ pub mod pallet { // Slash their deposit from them. T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0); - Self::deposit_event(Event::IdentityKilled(target, deposit)); + Self::deposit_event(Event::IdentityKilled { who: target, deposit }); Ok(Some(T::WeightInfo::kill_identity( id.judgements.len() as u32, // R @@ -882,7 +887,7 @@ pub mod pallet { sub_ids.try_push(sub.clone()).expect("sub ids length checked above; qed"); *subs_deposit = subs_deposit.saturating_add(deposit); - Self::deposit_event(Event::SubIdentityAdded(sub, sender.clone(), deposit)); + Self::deposit_event(Event::SubIdentityAdded { sub, main: sender.clone(), deposit }); Ok(()) }) } @@ -929,7 +934,7 @@ pub mod pallet { *subs_deposit -= deposit; let err_amount = T::Currency::unreserve(&sender, deposit); debug_assert!(err_amount.is_zero()); - Self::deposit_event(Event::SubIdentityRemoved(sub, sender, deposit)); + Self::deposit_event(Event::SubIdentityRemoved { sub, main: sender, deposit }); }); Ok(()) } @@ -954,7 +959,11 @@ pub mod pallet { *subs_deposit -= deposit; let _ = T::Currency::repatriate_reserved(&sup, &sender, deposit, BalanceStatus::Free); - Self::deposit_event(Event::SubIdentityRevoked(sender, sup.clone(), deposit)); + Self::deposit_event(Event::SubIdentityRevoked { + sub: sender, + main: sup.clone(), + deposit, + }); }); Ok(()) } diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 2c5a7633c3b4a..718c735fdad41 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -374,12 +374,12 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A new heartbeat was received from `AuthorityId` \[authority_id\] - HeartbeatReceived(T::AuthorityId), + /// A new heartbeat was received from `AuthorityId`. + HeartbeatReceived { authority_id: T::AuthorityId }, /// At the end of the session, no offence was committed. AllGood, - /// At the end of the session, at least one validator was found to be \[offline\]. - SomeOffline(Vec>), + /// At the end of the session, at least one validator was found to be offline. + SomeOffline { offline: Vec> }, } #[pallet::error] @@ -495,7 +495,7 @@ pub mod pallet { let keys = Keys::::get(); let public = keys.get(heartbeat.authority_index as usize); if let (false, Some(public)) = (exists, public) { - Self::deposit_event(Event::::HeartbeatReceived(public.clone())); + Self::deposit_event(Event::::HeartbeatReceived { authority_id: public.clone() }); let network_state_bounded = BoundedOpaqueNetworkState::< T::MaxPeerDataEncodingSize, @@ -908,7 +908,7 @@ impl OneSessionHandler for Pallet { if offenders.is_empty() { Self::deposit_event(Event::::AllGood); } else { - Self::deposit_event(Event::::SomeOffline(offenders.clone())); + Self::deposit_event(Event::::SomeOffline { offline: offenders.clone() }); let validator_set_count = keys.len() as u32; let offence = UnresponsivenessOffence { session_index, validator_set_count, offenders }; diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index 0901a89d41ad6..d8051bac0a3cd 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -105,7 +105,7 @@ pub mod pallet { *maybe_value = Some((who.clone(), T::Deposit::get(), false)); T::Currency::reserve(&who, T::Deposit::get()) })?; - Self::deposit_event(Event::IndexAssigned(who, index)); + Self::deposit_event(Event::IndexAssigned { who, index }); Ok(()) } @@ -146,7 +146,7 @@ pub mod pallet { *maybe_value = Some((new.clone(), amount.saturating_sub(lost), false)); Ok(()) })?; - Self::deposit_event(Event::IndexAssigned(new, index)); + Self::deposit_event(Event::IndexAssigned { who: new, index }); Ok(()) } @@ -179,7 +179,7 @@ pub mod pallet { T::Currency::unreserve(&who, amount); Ok(()) })?; - Self::deposit_event(Event::IndexFreed(index)); + Self::deposit_event(Event::IndexFreed { index }); Ok(()) } @@ -219,7 +219,7 @@ pub mod pallet { } *maybe_value = Some((new.clone(), Zero::zero(), freeze)); }); - Self::deposit_event(Event::IndexAssigned(new, index)); + Self::deposit_event(Event::IndexAssigned { who: new, index }); Ok(()) } @@ -253,7 +253,7 @@ pub mod pallet { *maybe_value = Some((account, Zero::zero(), true)); Ok(()) })?; - Self::deposit_event(Event::IndexFrozen(index, who)); + Self::deposit_event(Event::IndexFrozen { index, who }); Ok(()) } } @@ -261,12 +261,12 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A account index was assigned. \[index, who\] - IndexAssigned(T::AccountId, T::AccountIndex), - /// A account index has been freed up (unassigned). \[index\] - IndexFreed(T::AccountIndex), - /// A account index has been frozen to its current account ID. \[index, who\] - IndexFrozen(T::AccountIndex, T::AccountId), + /// A account index was assigned. + IndexAssigned { who: T::AccountId, index: T::AccountIndex }, + /// A account index has been freed up (unassigned). + IndexFreed { index: T::AccountIndex }, + /// A account index has been frozen to its current account ID. + IndexFrozen { index: T::AccountIndex, who: T::AccountId }, } /// Old name generated by `decl_event`. diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index 260b4c2d76ae9..c1c536b8ba290 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -176,9 +176,9 @@ pub mod pallet { /// A new set of calls have been set! CallsUpdated, /// A winner has been chosen! - Winner(T::AccountId, BalanceOf), + Winner { winner: T::AccountId, lottery_balance: BalanceOf }, /// A ticket has been bought! - TicketBought(T::AccountId, CallIndex), + TicketBought { who: T::AccountId, call_index: CallIndex }, } #[pallet::error] @@ -250,7 +250,7 @@ pub mod pallet { ); debug_assert!(res.is_ok()); - Self::deposit_event(Event::::Winner(winner, lottery_balance)); + Self::deposit_event(Event::::Winner { winner, lottery_balance }); TicketsCount::::kill(); @@ -452,7 +452,7 @@ impl Pallet { }, )?; - Self::deposit_event(Event::::TicketBought(caller.clone(), call_index)); + Self::deposit_event(Event::::TicketBought { who: caller.clone(), call_index }); Ok(()) } diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 8fa2abb0ad3f3..6cd8c13f39aff 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -143,7 +143,7 @@ pub mod pallet { /// One of the members' keys changed. KeyChanged, /// Phantom member, never used. - Dummy(PhantomData<(T::AccountId, >::Event)>), + Dummy { _phantom_data: PhantomData<(T::AccountId, >::Event)> }, } /// Old name generated by `decl_event`. diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index c38ddf1793ee1..757a99b42dae8 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -205,21 +205,30 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A new multisig operation has begun. \[approving, multisig, call_hash\] - NewMultisig(T::AccountId, T::AccountId, CallHash), + /// A new multisig operation has begun. + NewMultisig { approving: T::AccountId, multisig: T::AccountId, call_hash: CallHash }, /// A multisig operation has been approved by someone. - /// \[approving, timepoint, multisig, call_hash\] - MultisigApproval(T::AccountId, Timepoint, T::AccountId, CallHash), - /// A multisig operation has been executed. \[approving, timepoint, multisig, call_hash\] - MultisigExecuted( - T::AccountId, - Timepoint, - T::AccountId, - CallHash, - DispatchResult, - ), - /// A multisig operation has been cancelled. \[canceling, timepoint, multisig, call_hash\] - MultisigCancelled(T::AccountId, Timepoint, T::AccountId, CallHash), + MultisigApproval { + approving: T::AccountId, + timepoint: Timepoint, + multisig: T::AccountId, + call_hash: CallHash, + }, + /// A multisig operation has been executed. + MultisigExecuted { + approving: T::AccountId, + timepoint: Timepoint, + multisig: T::AccountId, + call_hash: CallHash, + result: DispatchResult, + }, + /// A multisig operation has been cancelled. + MultisigCancelled { + cancelling: T::AccountId, + timepoint: Timepoint, + multisig: T::AccountId, + call_hash: CallHash, + }, } #[pallet::hooks] @@ -481,7 +490,12 @@ pub mod pallet { >::remove(&id, &call_hash); Self::clear_call(&call_hash); - Self::deposit_event(Event::MultisigCancelled(who, timepoint, id, call_hash)); + Self::deposit_event(Event::MultisigCancelled { + cancelling: who, + timepoint, + multisig: id, + call_hash, + }); Ok(()) } } @@ -557,13 +571,13 @@ impl Pallet { T::Currency::unreserve(&m.depositor, m.deposit); let result = call.dispatch(RawOrigin::Signed(id.clone()).into()); - Self::deposit_event(Event::MultisigExecuted( - who, + Self::deposit_event(Event::MultisigExecuted { + approving: who, timepoint, - id, + multisig: id, call_hash, - result.map(|_| ()).map_err(|e| e.error), - )); + result: result.map(|_| ()).map_err(|e| e.error), + }); Ok(get_result_weight(result) .map(|actual_weight| { T::WeightInfo::as_multi_complete( @@ -594,7 +608,12 @@ impl Pallet { // Record approval. m.approvals.insert(pos, who.clone()); >::insert(&id, call_hash, m); - Self::deposit_event(Event::MultisigApproval(who, timepoint, id, call_hash)); + Self::deposit_event(Event::MultisigApproval { + approving: who, + timepoint, + multisig: id, + call_hash, + }); } else { // If we already approved and didn't store the Call, then this was useless and // we report an error. @@ -638,7 +657,7 @@ impl Pallet { approvals: vec![who.clone()], }, ); - Self::deposit_event(Event::NewMultisig(who, id, call_hash)); + Self::deposit_event(Event::NewMultisig { approving: who, multisig: id, call_hash }); let final_weight = if stored { T::WeightInfo::as_multi_create_store(other_signatories_len as u32, call_len as u32) diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index c5607c80abce4..523aefd1e753c 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -706,7 +706,14 @@ fn multisig_2_of_3_cannot_reissue_same_call() { let err = DispatchError::from(BalancesError::::InsufficientBalance).stripped(); System::assert_last_event( - pallet_multisig::Event::MultisigExecuted(3, now(), multi, hash, Err(err)).into(), + pallet_multisig::Event::MultisigExecuted { + approving: 3, + timepoint: now(), + multisig: multi, + call_hash: hash, + result: Err(err), + } + .into(), ); }); } diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index f502a683f633c..438929576269c 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -89,16 +89,16 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A name was set. \[who\] - NameSet(T::AccountId), - /// A name was forcibly set. \[target\] - NameForced(T::AccountId), - /// A name was changed. \[who\] - NameChanged(T::AccountId), - /// A name was cleared, and the given balance returned. \[who, deposit\] - NameCleared(T::AccountId, BalanceOf), - /// A name was removed and the given balance slashed. \[target, deposit\] - NameKilled(T::AccountId, BalanceOf), + /// A name was set. + NameSet { who: T::AccountId }, + /// A name was forcibly set. + NameForced { target: T::AccountId }, + /// A name was changed. + NameChanged { who: T::AccountId }, + /// A name was cleared, and the given balance returned. + NameCleared { who: T::AccountId, deposit: BalanceOf }, + /// A name was removed and the given balance slashed. + NameKilled { target: T::AccountId, deposit: BalanceOf }, } /// Error for the nicks pallet. @@ -147,12 +147,12 @@ pub mod pallet { ensure!(name.len() <= T::MaxLength::get() as usize, Error::::TooLong); let deposit = if let Some((_, deposit)) = >::get(&sender) { - Self::deposit_event(Event::::NameChanged(sender.clone())); + Self::deposit_event(Event::::NameChanged { who: sender.clone() }); deposit } else { let deposit = T::ReservationFee::get(); T::Currency::reserve(&sender, deposit.clone())?; - Self::deposit_event(Event::::NameSet(sender.clone())); + Self::deposit_event(Event::::NameSet { who: sender.clone() }); deposit }; @@ -179,7 +179,7 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&sender, deposit.clone()); debug_assert!(err_amount.is_zero()); - Self::deposit_event(Event::::NameCleared(sender, deposit)); + Self::deposit_event(Event::::NameCleared { who: sender, deposit }); Ok(()) } @@ -210,7 +210,7 @@ pub mod pallet { // Slash their deposit from them. T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit.clone()).0); - Self::deposit_event(Event::::NameKilled(target, deposit)); + Self::deposit_event(Event::::NameKilled { target, deposit }); Ok(()) } @@ -238,7 +238,7 @@ pub mod pallet { let deposit = >::get(&target).map(|x| x.1).unwrap_or_else(Zero::zero); >::insert(&target, (name, deposit)); - Self::deposit_event(Event::::NameForced(target)); + Self::deposit_event(Event::::NameForced { target }); Ok(()) } } diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 016f12d2eb838..6e3ec58ba63f9 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -128,24 +128,24 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// The given well known node was added. - NodeAdded(PeerId, T::AccountId), + NodeAdded { peer_id: PeerId, who: T::AccountId }, /// The given well known node was removed. - NodeRemoved(PeerId), + NodeRemoved { peer_id: PeerId }, /// The given well known node was swapped; first item was removed, /// the latter was added. - NodeSwapped(PeerId, PeerId), + NodeSwapped { removed: PeerId, added: PeerId }, /// The given well known nodes were reset. - NodesReset(Vec<(PeerId, T::AccountId)>), + NodesReset { nodes: Vec<(PeerId, T::AccountId)> }, /// The given node was claimed by a user. - NodeClaimed(PeerId, T::AccountId), + NodeClaimed { peer_id: PeerId, who: T::AccountId }, /// The given claim was removed by its owner. - ClaimRemoved(PeerId, T::AccountId), + ClaimRemoved { peer_id: PeerId, who: T::AccountId }, /// The node was transferred to another account. - NodeTransferred(PeerId, T::AccountId), + NodeTransferred { peer_id: PeerId, target: T::AccountId }, /// The allowed connections were added to a node. - ConnectionsAdded(PeerId, Vec), + ConnectionsAdded { peer_id: PeerId, allowed_connections: Vec }, /// The allowed connections were removed from a node. - ConnectionsRemoved(PeerId, Vec), + ConnectionsRemoved { peer_id: PeerId, allowed_connections: Vec }, } #[pallet::error] @@ -224,7 +224,7 @@ pub mod pallet { WellKnownNodes::::put(&nodes); >::insert(&node, &owner); - Self::deposit_event(Event::NodeAdded(node, owner)); + Self::deposit_event(Event::NodeAdded { peer_id: node, who: owner }); Ok(()) } @@ -248,7 +248,7 @@ pub mod pallet { >::remove(&node); AdditionalConnections::::remove(&node); - Self::deposit_event(Event::NodeRemoved(node)); + Self::deposit_event(Event::NodeRemoved { peer_id: node }); Ok(()) } @@ -284,7 +284,7 @@ pub mod pallet { Owners::::swap(&remove, &add); AdditionalConnections::::swap(&remove, &add); - Self::deposit_event(Event::NodeSwapped(remove, add)); + Self::deposit_event(Event::NodeSwapped { removed: remove, added: add }); Ok(()) } @@ -305,7 +305,7 @@ pub mod pallet { Self::initialize_nodes(&nodes); - Self::deposit_event(Event::NodesReset(nodes)); + Self::deposit_event(Event::NodesReset { nodes }); Ok(()) } @@ -321,7 +321,7 @@ pub mod pallet { ensure!(!Owners::::contains_key(&node), Error::::AlreadyClaimed); Owners::::insert(&node, &sender); - Self::deposit_event(Event::NodeClaimed(node, sender)); + Self::deposit_event(Event::NodeClaimed { peer_id: node, who: sender }); Ok(()) } @@ -342,7 +342,7 @@ pub mod pallet { Owners::::remove(&node); AdditionalConnections::::remove(&node); - Self::deposit_event(Event::ClaimRemoved(node, sender)); + Self::deposit_event(Event::ClaimRemoved { peer_id: node, who: sender }); Ok(()) } @@ -364,7 +364,7 @@ pub mod pallet { Owners::::insert(&node, &owner); - Self::deposit_event(Event::NodeTransferred(node, owner)); + Self::deposit_event(Event::NodeTransferred { peer_id: node, target: owner }); Ok(()) } @@ -395,7 +395,10 @@ pub mod pallet { AdditionalConnections::::insert(&node, nodes); - Self::deposit_event(Event::ConnectionsAdded(node, connections)); + Self::deposit_event(Event::ConnectionsAdded { + peer_id: node, + allowed_connections: connections, + }); Ok(()) } @@ -423,7 +426,10 @@ pub mod pallet { AdditionalConnections::::insert(&node, nodes); - Self::deposit_event(Event::ConnectionsRemoved(node, connections)); + Self::deposit_event(Event::ConnectionsRemoved { + peer_id: node, + allowed_connections: connections, + }); Ok(()) } } diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index c920b0b900dff..33ebe23d8d1fd 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -315,13 +315,13 @@ benchmarks! { ::Event::from(StakingEvent::::Slashed(id, BalanceOf::::from(slash_amount))) ); let balance_slash = |id| core::iter::once( - ::Event::from(pallet_balances::Event::::Slashed(id, slash_amount.into())) + ::Event::from(pallet_balances::Event::::Slashed{who: id, amount: slash_amount.into()}) ); let chill = |id| core::iter::once( ::Event::from(StakingEvent::::Chilled(id)) ); let balance_deposit = |id, amount: u32| - ::Event::from(pallet_balances::Event::::Deposit(id, amount.into())); + ::Event::from(pallet_balances::Event::::Deposit{who: id, amount: amount.into()}); let mut first = true; let slash_events = raw_offenders.into_iter() .flat_map(|offender| { @@ -344,7 +344,7 @@ benchmarks! { balance_deposit(reporter.clone(), reward.into()).into(), frame_system::Event::::NewAccount(reporter.clone()).into(), ::Event::from( - pallet_balances::Event::::Endowed(reporter.clone(), reward.into()) + pallet_balances::Event::::Endowed{account: reporter.clone(), free_balance: reward.into()} ).into(), ]) .collect::>(); @@ -371,10 +371,10 @@ benchmarks! { std::iter::empty() .chain(slash_events.into_iter().map(Into::into)) .chain(std::iter::once(::Event::from( - pallet_offences::Event::Offence( - UnresponsivenessOffence::::ID, - 0_u32.to_le_bytes().to_vec(), - ) + pallet_offences::Event::Offence{ + kind: UnresponsivenessOffence::::ID, + timeslot: 0_u32.to_le_bytes().to_vec(), + } ).into())) ); } diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index d50bc55f88357..ddae73e280d57 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -108,7 +108,7 @@ pub mod pallet { /// There is an offence reported of the given `kind` happened at the `session_index` and /// (kind-specific) time slot. This event is not deposited for duplicate slashes. /// \[kind, timeslot\]. - Offence(Kind, OpaqueTimeSlot), + Offence { kind: Kind, timeslot: OpaqueTimeSlot }, } #[pallet::hooks] @@ -153,7 +153,7 @@ where ); // Deposit the event. - Self::deposit_event(Event::Offence(O::ID, time_slot.encode())); + Self::deposit_event(Event::Offence { kind: O::ID, timeslot: time_slot.encode() }); Ok(()) } diff --git a/frame/offences/src/tests.rs b/frame/offences/src/tests.rs index 18cfa9410a6c6..8c4fdcc08f995 100644 --- a/frame/offences/src/tests.rs +++ b/frame/offences/src/tests.rs @@ -114,7 +114,10 @@ fn should_deposit_event() { System::events(), vec![EventRecord { phase: Phase::Initialization, - event: Event::Offences(crate::Event::Offence(KIND, time_slot.encode())), + event: Event::Offences(crate::Event::Offence { + kind: KIND, + timeslot: time_slot.encode() + }), topics: vec![], }] ); @@ -145,7 +148,10 @@ fn doesnt_deposit_event_for_dups() { System::events(), vec![EventRecord { phase: Phase::Initialization, - event: Event::Offences(crate::Event::Offence(KIND, time_slot.encode())), + event: Event::Offences(crate::Event::Offence { + kind: KIND, + timeslot: time_slot.encode() + }), topics: vec![], }] ); diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index 1eb3ec5770544..224610b65185b 100644 --- a/frame/proxy/src/benchmarking.rs +++ b/frame/proxy/src/benchmarking.rs @@ -86,7 +86,7 @@ benchmarks! { let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); }: _(RawOrigin::Signed(caller), real, Some(T::ProxyType::default()), Box::new(call)) verify { - assert_last_event::(Event::ProxyExecuted(Ok(())).into()) + assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) } proxy_announced { @@ -107,7 +107,7 @@ benchmarks! { add_announcements::(a, Some(delegate.clone()), None)?; }: _(RawOrigin::Signed(caller), delegate, real, Some(T::ProxyType::default()), Box::new(call)) verify { - assert_last_event::(Event::ProxyExecuted(Ok(())).into()) + assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) } remove_announcement { @@ -165,7 +165,7 @@ benchmarks! { let call_hash = T::CallHasher::hash_of(&call); }: _(RawOrigin::Signed(caller.clone()), real.clone(), call_hash) verify { - assert_last_event::(Event::Announced(real, caller, call_hash).into()); + assert_last_event::(Event::Announced { real, proxy: caller, call_hash }.into()); } add_proxy { @@ -216,12 +216,12 @@ benchmarks! { ) verify { let anon_account = Pallet::::anonymous_account(&caller, &T::ProxyType::default(), 0, None); - assert_last_event::(Event::AnonymousCreated( - anon_account, - caller, - T::ProxyType::default(), - 0, - ).into()); + assert_last_event::(Event::AnonymousCreated { + anonymous: anon_account, + who: caller, + proxy_type: T::ProxyType::default(), + disambiguation_index: 0, + }.into()); } kill_anonymous { diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index b73101fa73486..695fa077f98d5 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -327,7 +327,12 @@ pub mod pallet { T::Currency::reserve(&who, deposit)?; Proxies::::insert(&anonymous, (bounded_proxies, deposit)); - Self::deposit_event(Event::AnonymousCreated(anonymous, who, proxy_type, index)); + Self::deposit_event(Event::AnonymousCreated { + anonymous, + who, + proxy_type, + disambiguation_index: index, + }); Ok(()) } @@ -427,7 +432,7 @@ pub mod pallet { }) .map(|d| *deposit = d) })?; - Self::deposit_event(Event::Announced(real, who, call_hash)); + Self::deposit_event(Event::Announced { real, proxy: who, call_hash }); Ok(()) } @@ -547,16 +552,25 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A proxy was executed correctly, with the given \[result\]. - ProxyExecuted(DispatchResult), + /// A proxy was executed correctly, with the given. + ProxyExecuted { result: DispatchResult }, /// Anonymous account has been created by new proxy with given - /// disambiguation index and proxy type. \[anonymous, who, proxy_type, - /// disambiguation_index\] - AnonymousCreated(T::AccountId, T::AccountId, T::ProxyType, u16), - /// An announcement was placed to make a call in the future. \[real, proxy, call_hash\] - Announced(T::AccountId, T::AccountId, CallHashOf), - /// A proxy was added. \[delegator, delegatee, proxy_type, delay\] - ProxyAdded(T::AccountId, T::AccountId, T::ProxyType, T::BlockNumber), + /// disambiguation index and proxy type. + AnonymousCreated { + anonymous: T::AccountId, + who: T::AccountId, + proxy_type: T::ProxyType, + disambiguation_index: u16, + }, + /// An announcement was placed to make a call in the future. + Announced { real: T::AccountId, proxy: T::AccountId, call_hash: CallHashOf }, + /// A proxy was added. + ProxyAdded { + delegator: T::AccountId, + delegatee: T::AccountId, + proxy_type: T::ProxyType, + delay: T::BlockNumber, + }, } /// Old name generated by `decl_event`. @@ -672,12 +686,12 @@ impl Pallet { T::Currency::unreserve(delegator, *deposit - new_deposit); } *deposit = new_deposit; - Self::deposit_event(Event::::ProxyAdded( - delegator.clone(), + Self::deposit_event(Event::::ProxyAdded { + delegator: delegator.clone(), delegatee, proxy_type, delay, - )); + }); Ok(()) }) } @@ -800,6 +814,6 @@ impl Pallet { } }); let e = call.dispatch(origin); - Self::deposit_event(Event::ProxyExecuted(e.map(|_| ()).map_err(|e| e.error))); + Self::deposit_event(Event::ProxyExecuted { result: e.map(|_| ()).map_err(|e| e.error) }); } } diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index ed21a80f62139..d3565525910fb 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -211,7 +211,15 @@ fn call_transfer(dest: u64, value: u64) -> Call { fn announcement_works() { new_test_ext().execute_with(|| { assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 1)); - System::assert_last_event(ProxyEvent::ProxyAdded(1, 3, ProxyType::Any, 1).into()); + System::assert_last_event( + ProxyEvent::ProxyAdded { + delegator: 1, + delegatee: 3, + proxy_type: ProxyType::Any, + delay: 1, + } + .into(), + ); assert_ok!(Proxy::add_proxy(Origin::signed(2), 3, ProxyType::Any, 1)); assert_eq!(Balances::reserved_balance(3), 0); @@ -332,12 +340,12 @@ fn filtering_works() { let call = Box::new(call_transfer(6, 1)); assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Ok(())).into()); + System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Ok(())).into()); + System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); System::assert_last_event( - ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); let derivative_id = Utility::derivative_account_id(1, 0); @@ -347,31 +355,31 @@ fn filtering_works() { let call = Box::new(Call::Utility(UtilityCall::as_derivative { index: 0, call: inner.clone() })); assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Ok(())).into()); + System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); System::assert_last_event( - ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); System::assert_last_event( - ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); let call = Box::new(Call::Utility(UtilityCall::batch { calls: vec![*inner] })); assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchCompleted.into(), - ProxyEvent::ProxyExecuted(Ok(())).into(), + ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); System::assert_last_event( - ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchInterrupted { index: 0, error: SystemError::CallFiltered.into() } .into(), - ProxyEvent::ProxyExecuted(Ok(())).into(), + ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); let inner = @@ -380,32 +388,32 @@ fn filtering_works() { assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchCompleted.into(), - ProxyEvent::ProxyExecuted(Ok(())).into(), + ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); System::assert_last_event( - ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchInterrupted { index: 0, error: SystemError::CallFiltered.into() } .into(), - ProxyEvent::ProxyExecuted(Ok(())).into(), + ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); let call = Box::new(Call::Proxy(ProxyCall::remove_proxies {})); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); System::assert_last_event( - ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); System::assert_last_event( - ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); expect_events(vec![ - BalancesEvent::::Unreserved(1, 5).into(), - ProxyEvent::ProxyExecuted(Ok(())).into(), + BalancesEvent::::Unreserved { who: 1, amount: 5 }.into(), + ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); }); } @@ -476,13 +484,13 @@ fn proxying_works() { Error::::NotProxy ); assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Ok(())).into()); + System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 1); let call = Box::new(Call::System(SystemCall::set_code { code: vec![] })); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); System::assert_last_event( - ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); let call = @@ -490,10 +498,10 @@ fn proxying_works() { assert_ok!(Call::Proxy(super::Call::new_call_variant_proxy(1, None, call.clone())) .dispatch(Origin::signed(2))); System::assert_last_event( - ProxyEvent::ProxyExecuted(Err(SystemError::CallFiltered.into())).into(), + ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted(Ok(())).into()); + System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 2); }); } @@ -504,7 +512,13 @@ fn anonymous_works() { assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 0)); let anon = Proxy::anonymous_account(&1, &ProxyType::Any, 0, None); System::assert_last_event( - ProxyEvent::AnonymousCreated(anon.clone(), 1, ProxyType::Any, 0).into(), + ProxyEvent::AnonymousCreated { + anonymous: anon.clone(), + who: 1, + proxy_type: ProxyType::Any, + disambiguation_index: 0, + } + .into(), ); // other calls to anonymous allowed as long as they're not exactly the same. @@ -525,7 +539,7 @@ fn anonymous_works() { let call = Box::new(call_transfer(6, 1)); assert_ok!(Balances::transfer(Origin::signed(3), anon, 5)); assert_ok!(Proxy::proxy(Origin::signed(1), anon, None, call)); - System::assert_last_event(ProxyEvent::ProxyExecuted(Ok(())).into()); + System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 1); let call = Box::new(Call::Proxy(ProxyCall::new_call_variant_kill_anonymous( @@ -537,7 +551,7 @@ fn anonymous_works() { ))); assert_ok!(Proxy::proxy(Origin::signed(2), anon2, None, call.clone())); let de = DispatchError::from(Error::::NoPermission).stripped(); - System::assert_last_event(ProxyEvent::ProxyExecuted(Err(de)).into()); + System::assert_last_event(ProxyEvent::ProxyExecuted { result: Err(de) }.into()); assert_noop!( Proxy::kill_anonymous(Origin::signed(1), 1, ProxyType::Any, 0, 1, 0), Error::::NoPermission diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 68088d0e0d777..414c21aa347f0 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -190,7 +190,7 @@ pub(crate) struct SpanRecord { impl SpanRecord { /// The value of stash balance slashed in this span. #[cfg(test)] - pub(crate) fn amount_slashed(&self) -> &Balance { + pub(crate) fn amount(&self) -> &Balance { &self.slashed } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 8e8a7ee636d8d..8f13fd7850803 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2469,7 +2469,7 @@ fn garbage_collection_after_slashing() { assert_eq!(Balances::free_balance(11), 2000 - 200); assert!(::SlashingSpans::get(&11).is_some()); - assert_eq!(::SpanSlash::get(&(11, 0)).amount_slashed(), &200); + assert_eq!(::SpanSlash::get(&(11, 0)).amount(), &200); on_offence_now( &[OffenceDetails { @@ -2496,7 +2496,7 @@ fn garbage_collection_after_slashing() { assert_ok!(Staking::reap_stash(Origin::signed(20), 11, 2)); assert!(::SlashingSpans::get(&11).is_none()); - assert_eq!(::SpanSlash::get(&(11, 0)).amount_slashed(), &0); + assert_eq!(::SpanSlash::get(&(11, 0)).amount(), &0); }) } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 64cd5d5290635..a0d8aeb11706d 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -1363,9 +1363,11 @@ mod tests { )); assert_eq!(Balances::free_balance(2), 0); // Transfer Event - System::assert_has_event(Event::Balances(pallet_balances::Event::Transfer( - 2, 3, 80, - ))); + System::assert_has_event(Event::Balances(pallet_balances::Event::Transfer { + from: 2, + to: 3, + amount: 80, + })); // Killed Event System::assert_has_event(Event::System(system::Event::KilledAccount(2))); }); From 07d98e28cd7a79e45f02a982af14fbde929d8a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 16 Nov 2021 07:52:27 +0100 Subject: [PATCH 0236/1472] Forward wasmer-sandbox feature to sp-sandbox (#10268) --- Cargo.lock | 1 + bin/node/runtime/Cargo.toml | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 99b2b53a74a4a..d93e70162926f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4758,6 +4758,7 @@ dependencies = [ "sp-npos-elections", "sp-offchain", "sp-runtime", + "sp-sandbox", "sp-session", "sp-staking", "sp-std", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index d086b6f12d590..9a481120fd01e 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -41,6 +41,7 @@ sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } +sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } # frame dependencies frame-executive = { version = "4.0.0-dev", default-features = false, path = "../../../frame/executive" } @@ -257,3 +258,8 @@ try-runtime = [ # Make contract callable functions marked as __unstable__ available. Do not enable # on live chains as those are subject to change. contracts-unstable-interface = ["pallet-contracts/unstable-interface"] +# Force `sp-sandbox` to call into the host resident executor. One still need to make sure +# that `sc-executor` gets the `wasmer-sandbox` feature which happens automatically when +# specified on the command line. +# Don't use that on a production chain. +wasmer-sandbox = ["sp-sandbox/wasmer-sandbox"] From f846ee0d56e3882cdfa78616d8e9a36885379c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 16 Nov 2021 14:01:35 +0100 Subject: [PATCH 0237/1472] Cli: Introduce `--detailed-log-output` flag (#10278) * Cli: Introduce `--detailed-log-output` flag If this CLI flag is given, detailed log output will be enabled. This includes the log level, log target ad the thread name. Before this was only enabled when a log level higher than `info` should be logged. * Update client/tracing/src/logging/mod.rs Co-authored-by: David Co-authored-by: David --- client/cli/src/config.rs | 9 ++++- client/cli/src/params/shared_params.rs | 13 +++++++ client/tracing/src/logging/mod.rs | 54 ++++++++++++++++++-------- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 86eeed5b40237..20e2bf0df5b2e 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -547,6 +547,11 @@ pub trait CliConfiguration: Sized { Ok(self.shared_params().log_filters().join(",")) } + /// Should the detailed log output be enabled. + fn detailed_log_output(&self) -> Result { + Ok(self.shared_params().detailed_log_output()) + } + /// Is log reloading enabled? fn enable_log_reloading(&self) -> Result { Ok(self.shared_params().enable_log_reloading()) @@ -568,7 +573,9 @@ pub trait CliConfiguration: Sized { sp_panic_handler::set(&C::support_url(), &C::impl_version()); let mut logger = LoggerBuilder::new(self.log_filters()?); - logger.with_log_reloading(self.enable_log_reloading()?); + logger + .with_log_reloading(self.enable_log_reloading()?) + .with_detailed_output(self.detailed_log_output()?); if let Some(tracing_targets) = self.tracing_targets()? { let tracing_receiver = self.tracing_receiver()?; diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 58aabb3148dd2..4a6fe0d2743ef 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -49,6 +49,14 @@ pub struct SharedParams { #[structopt(short = "l", long, value_name = "LOG_PATTERN")] pub log: Vec, + /// Enable detailed log output. + /// + /// This includes displaying the log target, log level and thread name. + /// + /// This is automatically enabled when something is logged with any higher level than `info`. + #[structopt(long)] + pub detailed_log_output: bool, + /// Disable log color output. #[structopt(long)] pub disable_log_color: bool, @@ -107,6 +115,11 @@ impl SharedParams { &self.log } + /// Should the detailed log output be enabled. + pub fn detailed_log_output(&self) -> bool { + self.detailed_log_output + } + /// Should the log color output be disabled? pub fn disable_log_color(&self) -> bool { self.disable_log_color diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index 49807098d1cf4..521cfca30e29b 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -95,6 +95,7 @@ fn prepare_subscriber( directives: &str, profiling_targets: Option<&str>, force_colors: Option, + detailed_output: bool, builder_hook: impl Fn( SubscriberBuilder, ) -> SubscriberBuilder, @@ -157,19 +158,19 @@ where tracing_log::LogTracer::builder().with_max_level(max_level).init()?; // If we're only logging `INFO` entries then we'll use a simplified logging format. - let simple = match max_level_hint { - Some(level) if level <= tracing_subscriber::filter::LevelFilter::INFO => true, - _ => false, - }; + let detailed_output = match max_level_hint { + Some(level) if level <= tracing_subscriber::filter::LevelFilter::INFO => false, + _ => true, + } || detailed_output; let enable_color = force_colors.unwrap_or_else(|| atty::is(atty::Stream::Stderr)); - let timer = fast_local_time::FastLocalTime { with_fractional: !simple }; + let timer = fast_local_time::FastLocalTime { with_fractional: detailed_output }; let event_format = EventFormat { timer, - display_target: !simple, - display_level: !simple, - display_thread_name: !simple, + display_target: detailed_output, + display_level: detailed_output, + display_thread_name: detailed_output, enable_color, dup_to_stdout: !atty::is(atty::Stream::Stderr) && atty::is(atty::Stream::Stdout), }; @@ -194,6 +195,7 @@ pub struct LoggerBuilder { profiling: Option<(crate::TracingReceiver, String)>, log_reloading: bool, force_colors: Option, + detailed_output: bool, } impl LoggerBuilder { @@ -204,6 +206,7 @@ impl LoggerBuilder { profiling: None, log_reloading: false, force_colors: None, + detailed_output: false, } } @@ -223,6 +226,17 @@ impl LoggerBuilder { self } + /// Whether detailed log output should be enabled. + /// + /// This includes showing the log target, log level and thread name. + /// + /// This will be automatically enabled when there is a log level enabled that is higher than + /// `info`. + pub fn with_detailed_output(&mut self, detailed: bool) -> &mut Self { + self.detailed_output = detailed; + self + } + /// Force enable/disable colors. pub fn with_colors(&mut self, enable: bool) -> &mut Self { self.force_colors = Some(enable); @@ -239,6 +253,7 @@ impl LoggerBuilder { &self.directives, Some(&profiling_targets), self.force_colors, + self.detailed_output, |builder| enable_log_reloading!(builder), )?; let profiling = crate::ProfilingLayer::new(tracing_receiver, &profiling_targets); @@ -251,6 +266,7 @@ impl LoggerBuilder { &self.directives, Some(&profiling_targets), self.force_colors, + self.detailed_output, |builder| builder, )?; let profiling = crate::ProfilingLayer::new(tracing_receiver, &profiling_targets); @@ -261,19 +277,25 @@ impl LoggerBuilder { } } else { if self.log_reloading { - let subscriber = - prepare_subscriber(&self.directives, None, self.force_colors, |builder| { - enable_log_reloading!(builder) - })?; + let subscriber = prepare_subscriber( + &self.directives, + None, + self.force_colors, + self.detailed_output, + |builder| enable_log_reloading!(builder), + )?; tracing::subscriber::set_global_default(subscriber)?; Ok(()) } else { - let subscriber = - prepare_subscriber(&self.directives, None, self.force_colors, |builder| { - builder - })?; + let subscriber = prepare_subscriber( + &self.directives, + None, + self.force_colors, + self.detailed_output, + |builder| builder, + )?; tracing::subscriber::set_global_default(subscriber)?; From 74c39a23076bfd23328e1f1d1eed2f508a28247d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 16 Nov 2021 14:02:04 +0100 Subject: [PATCH 0238/1472] Vesting: Fix `post_migration` check (#10280) * Vesting: Fix `post_migration` check As the vesting migration could already have been done, people could already have started to merge schedules. * :facepalm: --- frame/vesting/src/migrations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/vesting/src/migrations.rs b/frame/vesting/src/migrations.rs index 086257d285ea0..f8024926f34aa 100644 --- a/frame/vesting/src/migrations.rs +++ b/frame/vesting/src/migrations.rs @@ -70,7 +70,7 @@ pub(crate) mod v1 { for (_key, schedules) in Vesting::::iter() { assert!( - schedules.len() == 1, + schedules.len() >= 1, "A bounded vec with incorrect count of items was created." ); From 9fec502b0310de85cdfab15cefe467e86d843233 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Nov 2021 14:03:48 +0100 Subject: [PATCH 0239/1472] Bump handlebars from 3.5.3 to 4.1.4 (#10273) Bumps [handlebars](https://github.com/sunng87/handlebars-rust) from 3.5.3 to 4.1.4. - [Release notes](https://github.com/sunng87/handlebars-rust/releases) - [Changelog](https://github.com/sunng87/handlebars-rust/blob/master/CHANGELOG.md) - [Commits](https://github.com/sunng87/handlebars-rust/compare/v3.5.3...v4.1.4) --- updated-dependencies: - dependency-name: handlebars 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 | 4 ++-- utils/frame/benchmarking-cli/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d93e70162926f..f1e8b00c6eb0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2529,9 +2529,9 @@ checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" [[package]] name = "handlebars" -version = "3.5.3" +version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb0867bbc5a3da37a753e78021d5fcf8a4db00e18dd2dd90fd36e24190e162d" +checksum = "e1874024f4a29f47d609014caec0b1c866f1c1eb0661a09c9733ecc4757f5f88" dependencies = [ "log 0.4.14", "pest", diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 03520f9cbd5d7..fab2b963239d3 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -28,7 +28,7 @@ codec = { version = "2.0.0", package = "parity-scale-codec" } structopt = "0.3.25" chrono = "0.4" serde = "1.0.126" -handlebars = "3.5.0" +handlebars = "4.1.4" Inflector = "0.11.4" linked-hash-map = "0.5.4" log = "0.4.8" From 9a00c43a1a81217548b3b7853271f07de6a6b858 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 16 Nov 2021 14:17:19 +0000 Subject: [PATCH 0240/1472] Update mod.rs (#10277) As many people are unbonding, I've had to explain this to a handful of people recently. This improves the error message a bit and puts it in the error description, so that it is shown in the front page of all explorers if `unbond` fails, hopefully making it clear. --- frame/staking/src/pallet/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 197c2eed325a1..ec7e86af958f1 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -608,7 +608,9 @@ pub mod pallet { DuplicateIndex, /// Slash record index out of bounds. InvalidSlashIndex, - /// Can not bond with value less than minimum required. + /// Cannot have a validator or nominator role, with value less than the minimum defined by + /// governance (see `MinValidatorBond` and `MinNominatorBond`). If unbonding is the + /// intention, `chill` first to remove one's role as validator/nominator. InsufficientBond, /// Can not schedule more unlock chunks. NoMoreChunks, From cc4bf9134b492d3a11f45c6b1cfa4fdf307e63e2 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Wed, 17 Nov 2021 15:16:28 +0800 Subject: [PATCH 0241/1472] pallet-session: Migrate the historical part to the new pallet macro (#9878) * Migrate session-historical to the new pallet macro Signed-off-by: koushiro * pallet-session: Migrate the historical part to the new pallet macro Signed-off-by: koushiro * Fix staking test runtime Signed-off-by: koushiro * Update frame/session/src/historical/mod.rs * Update frame/session/src/historical/mod.rs * update migration doc Signed-off-by: koushiro * use hardcoded prefix for migration v1 Signed-off-by: koushiro * cargo +nightly-2021-11-08 fmt Signed-off-by: koushiro Co-authored-by: Guillaume Thiolliere --- frame/session/benchmarking/src/lib.rs | 4 +- frame/session/src/historical/mod.rs | 136 ++++++++-------- frame/session/src/historical/offchain.rs | 4 +- frame/session/src/lib.rs | 1 + frame/session/src/migrations/mod.rs | 24 +++ frame/session/src/migrations/v1.rs | 194 +++++++++++++++++++++++ frame/session/src/tests.rs | 27 ++++ frame/staking/src/mock.rs | 1 + 8 files changed, 325 insertions(+), 66 deletions(-) create mode 100644 frame/session/src/migrations/mod.rs create mode 100644 frame/session/src/migrations/v1.rs diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index 8ca713b1bbf61..6d9d81f385176 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -22,6 +22,7 @@ mod mock; +use sp_runtime::traits::{One, StaticLookup}; use sp_std::{prelude::*, vec}; use frame_benchmarking::benchmarks; @@ -30,12 +31,11 @@ use frame_support::{ traits::{KeyOwnerProofSystem, OnInitialize}, }; use frame_system::RawOrigin; -use pallet_session::{historical::Module as Historical, Pallet as Session, *}; +use pallet_session::{historical::Pallet as Historical, Pallet as Session, *}; use pallet_staking::{ benchmarking::create_validator_with_nominators, testing_utils::create_validators, RewardDestination, }; -use sp_runtime::traits::{One, StaticLookup}; const MAX_VALIDATORS: u32 = 1000; diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index 0801b2aca1701..a3e64f4f9efa4 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -26,62 +26,74 @@ //! These roots and proofs of inclusion can be generated at any time during the current session. //! Afterwards, the proofs can be fed to a consensus module when reporting misbehavior. -use super::{Pallet as SessionModule, SessionIndex}; +pub mod offchain; +pub mod onchain; +mod shared; + use codec::{Decode, Encode}; -use frame_support::{ - decl_module, decl_storage, print, - traits::{ValidatorSet, ValidatorSetWithIdentification}, - Parameter, -}; use sp_runtime::{ traits::{Convert, OpaqueKeys}, KeyTypeId, }; use sp_session::{MembershipProof, ValidatorCount}; +use sp_staking::SessionIndex; use sp_std::prelude::*; use sp_trie::{ trie_types::{TrieDB, TrieDBMut}, MemoryDB, Recorder, Trie, TrieMut, EMPTY_PREFIX, }; -pub mod offchain; -pub mod onchain; -mod shared; +use frame_support::{ + print, + traits::{KeyOwnerProofSystem, StorageVersion, ValidatorSet, ValidatorSetWithIdentification}, + Parameter, +}; -/// Config necessary for the historical module. -pub trait Config: super::Config { - /// Full identification of the validator. - type FullIdentification: Parameter; - - /// A conversion from validator ID to full identification. - /// - /// This should contain any references to economic actors associated with the - /// validator, since they may be outdated by the time this is queried from a - /// historical trie. - /// - /// It must return the identification for the current session index. - type FullIdentificationOf: Convert>; -} +use crate::{self as pallet_session, Pallet as Session}; + +pub use pallet::*; -decl_storage! { - trait Store for Module as Session { - /// Mapping from historical session indices to session-data root hash and validator count. - HistoricalSessions get(fn historical_root): - map hasher(twox_64_concat) SessionIndex => Option<(T::Hash, ValidatorCount)>; - /// The range of historical sessions we store. [first, last) - StoredRange: Option<(SessionIndex, SessionIndex)>; - /// Deprecated. - CachedObsolete: - map hasher(twox_64_concat) SessionIndex - => Option>; +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + /// Config necessary for the historical pallet. + #[pallet::config] + pub trait Config: pallet_session::Config + frame_system::Config { + /// Full identification of the validator. + type FullIdentification: Parameter; + + /// A conversion from validator ID to full identification. + /// + /// This should contain any references to economic actors associated with the + /// validator, since they may be outdated by the time this is queried from a + /// historical trie. + /// + /// It must return the identification for the current session index. + type FullIdentificationOf: Convert>; } -} -decl_module! { - pub struct Module for enum Call where origin: T::Origin {} + /// Mapping from historical session indices to session-data root hash and validator count. + #[pallet::storage] + #[pallet::getter(fn historical_root)] + pub type HistoricalSessions = + StorageMap<_, Twox64Concat, SessionIndex, (T::Hash, ValidatorCount), OptionQuery>; + + /// The range of historical sessions we store. [first, last) + #[pallet::storage] + pub type StoredRange = StorageValue<_, (SessionIndex, SessionIndex), OptionQuery>; } -impl Module { +impl Pallet { /// Prune historical stored session roots up to (but not including) /// `up_to`. pub fn prune_up_to(up_to: SessionIndex) { @@ -109,7 +121,7 @@ impl Module { } } -impl ValidatorSet for Module { +impl ValidatorSet for Pallet { type ValidatorId = T::ValidatorId; type ValidatorIdOf = T::ValidatorIdOf; @@ -122,7 +134,7 @@ impl ValidatorSet for Module { } } -impl ValidatorSetWithIdentification for Module { +impl ValidatorSetWithIdentification for Pallet { type Identification = T::FullIdentification; type IdentificationOf = T::FullIdentificationOf; } @@ -130,7 +142,7 @@ impl ValidatorSetWithIdentification for Module { /// Specialization of the crate-level `SessionManager` which returns the set of full identification /// when creating a new session. pub trait SessionManager: - crate::SessionManager + pallet_session::SessionManager { /// If there was a validator set change, its returns the set of new validators along with their /// full identifications. @@ -150,7 +162,7 @@ pub struct NoteHistoricalRoot(sp_std::marker::PhantomData<(T, I)>); impl> NoteHistoricalRoot { fn do_new_session(new_index: SessionIndex, is_genesis: bool) -> Option> { - StoredRange::mutate(|range| { + >::mutate(|range| { range.get_or_insert_with(|| (new_index, new_index)).1 = new_index + 1; }); @@ -183,7 +195,7 @@ impl> NoteHi } } -impl crate::SessionManager for NoteHistoricalRoot +impl pallet_session::SessionManager for NoteHistoricalRoot where I: SessionManager, { @@ -207,7 +219,7 @@ where /// A tuple of the validator's ID and their full identification. pub type IdentificationTuple = - (::ValidatorId, ::FullIdentification); + (::ValidatorId, ::FullIdentification); /// A trie instance for checking and generating proofs. pub struct ProvingTrie { @@ -227,7 +239,7 @@ impl ProvingTrie { let mut trie = TrieDBMut::new(&mut db, &mut root); for (i, (validator, full_id)) in validators.into_iter().enumerate() { let i = i as u32; - let keys = match >::load_keys(&validator) { + let keys = match >::load_keys(&validator) { None => continue, Some(k) => k, }; @@ -304,15 +316,13 @@ impl ProvingTrie { } } -impl> frame_support::traits::KeyOwnerProofSystem<(KeyTypeId, D)> - for Module -{ +impl> KeyOwnerProofSystem<(KeyTypeId, D)> for Pallet { type Proof = MembershipProof; type IdentificationTuple = IdentificationTuple; fn prove(key: (KeyTypeId, D)) -> Option { - let session = >::current_index(); - let validators = >::validators() + let session = >::current_index(); + let validators = >::validators() .into_iter() .filter_map(|validator| { T::FullIdentificationOf::convert(validator.clone()) @@ -335,10 +345,10 @@ impl> frame_support::traits::KeyOwnerProofSystem<(KeyT fn check_proof(key: (KeyTypeId, D), proof: Self::Proof) -> Option> { let (id, data) = key; - if proof.session == >::current_index() { - >::key_owner(id, data.as_ref()).and_then(|owner| { + if proof.session == >::current_index() { + >::key_owner(id, data.as_ref()).and_then(|owner| { T::FullIdentificationOf::convert(owner.clone()).and_then(move |id| { - let count = >::validators().len() as ValidatorCount; + let count = >::validators().len() as ValidatorCount; if count != proof.validator_count { return None @@ -374,7 +384,7 @@ pub(crate) mod tests { BasicExternalities, }; - type Historical = Module; + type Historical = Pallet; pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); @@ -386,7 +396,9 @@ pub(crate) mod tests { frame_system::Pallet::::inc_providers(k); } }); - crate::GenesisConfig:: { keys }.assimilate_storage(&mut t).unwrap(); + pallet_session::GenesisConfig:: { keys } + .assimilate_storage(&mut t) + .unwrap(); sp_io::TestExternalities::new(t) } @@ -436,27 +448,27 @@ pub(crate) mod tests { Session::on_initialize(i); } - assert_eq!(StoredRange::get(), Some((0, 100))); + assert_eq!(>::get(), Some((0, 100))); for i in 0..100 { assert!(Historical::historical_root(i).is_some()) } Historical::prune_up_to(10); - assert_eq!(StoredRange::get(), Some((10, 100))); + assert_eq!(>::get(), Some((10, 100))); Historical::prune_up_to(9); - assert_eq!(StoredRange::get(), Some((10, 100))); + assert_eq!(>::get(), Some((10, 100))); for i in 10..100 { assert!(Historical::historical_root(i).is_some()) } Historical::prune_up_to(99); - assert_eq!(StoredRange::get(), Some((99, 100))); + assert_eq!(>::get(), Some((99, 100))); Historical::prune_up_to(100); - assert_eq!(StoredRange::get(), None); + assert_eq!(>::get(), None); for i in 99..199u64 { set_next_validators(vec![i]); @@ -466,14 +478,14 @@ pub(crate) mod tests { Session::on_initialize(i); } - assert_eq!(StoredRange::get(), Some((100, 200))); + assert_eq!(>::get(), Some((100, 200))); for i in 100..200 { assert!(Historical::historical_root(i).is_some()) } Historical::prune_up_to(9999); - assert_eq!(StoredRange::get(), None); + assert_eq!(>::get(), None); for i in 100..200 { assert!(Historical::historical_root(i).is_none()) diff --git a/frame/session/src/historical/offchain.rs b/frame/session/src/historical/offchain.rs index b646ecc2764f7..0b292b57658d0 100644 --- a/frame/session/src/historical/offchain.rs +++ b/frame/session/src/historical/offchain.rs @@ -140,7 +140,7 @@ pub fn keep_newest(n_to_keep: usize) { mod tests { use super::*; use crate::{ - historical::{onchain, Module}, + historical::{onchain, Pallet}, mock::{force_new_session, set_next_validators, Session, System, Test, NEXT_VALIDATORS}, }; @@ -156,7 +156,7 @@ mod tests { BasicExternalities, }; - type Historical = Module; + type Historical = Pallet; pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default() diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 6779285ee3187..2fd34365705bb 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -108,6 +108,7 @@ #[cfg(feature = "historical")] pub mod historical; +pub mod migrations; #[cfg(test)] mod mock; #[cfg(test)] diff --git a/frame/session/src/migrations/mod.rs b/frame/session/src/migrations/mod.rs new file mode 100644 index 0000000000000..ccc5ee3c2e525 --- /dev/null +++ b/frame/session/src/migrations/mod.rs @@ -0,0 +1,24 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Version 1. +/// +/// In version 0 session historical pallet uses `Session` for storage module prefix. +/// In version 1 it uses its name as configured in `construct_runtime`. +/// This migration moves session historical pallet storages from old prefix to new prefix. +#[cfg(feature = "historical")] +pub mod v1; diff --git a/frame/session/src/migrations/v1.rs b/frame/session/src/migrations/v1.rs new file mode 100644 index 0000000000000..1de199fe7bedd --- /dev/null +++ b/frame/session/src/migrations/v1.rs @@ -0,0 +1,194 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sp_io::hashing::twox_128; +use sp_std::str; + +use frame_support::{ + storage::{generator::StorageValue, StoragePrefixedMap}, + traits::{ + Get, GetStorageVersion, PalletInfoAccess, StorageVersion, + STORAGE_VERSION_STORAGE_KEY_POSTFIX, + }, + weights::Weight, +}; + +use crate::historical as pallet_session_historical; + +const OLD_PREFIX: &str = "Session"; + +/// Migrate the entire storage of this pallet to a new prefix. +/// +/// This new prefix must be the same as the one set in construct_runtime. +/// +/// The migration will look into the storage version in order not to trigger a migration on an up +/// to date storage. Thus the on chain storage version must be less than 1 in order to trigger the +/// migration. +pub fn migrate( +) -> Weight { + let new_pallet_name =

::name(); + + if new_pallet_name == OLD_PREFIX { + log::info!( + target: "runtime::session_historical", + "New pallet name is equal to the old prefix. No migration needs to be done.", + ); + return 0 + } + + let on_chain_storage_version =

::on_chain_storage_version(); + log::info!( + target: "runtime::session_historical", + "Running migration to v1 for session_historical with storage version {:?}", + on_chain_storage_version, + ); + + if on_chain_storage_version < 1 { + let storage_prefix = pallet_session_historical::HistoricalSessions::::storage_prefix(); + frame_support::storage::migration::move_storage_from_pallet( + storage_prefix, + OLD_PREFIX.as_bytes(), + new_pallet_name.as_bytes(), + ); + log_migration("migration", storage_prefix, OLD_PREFIX, new_pallet_name); + + let storage_prefix = pallet_session_historical::StoredRange::::storage_prefix(); + frame_support::storage::migration::move_storage_from_pallet( + storage_prefix, + OLD_PREFIX.as_bytes(), + new_pallet_name.as_bytes(), + ); + log_migration("migration", storage_prefix, OLD_PREFIX, new_pallet_name); + + StorageVersion::new(1).put::

(); + ::BlockWeights::get().max_block + } else { + log::warn!( + target: "runtime::session_historical", + "Attempted to apply migration to v1 but failed because storage version is {:?}", + on_chain_storage_version, + ); + 0 + } +} + +/// Some checks prior to migration. This can be linked to +/// [`frame_support::traits::OnRuntimeUpgrade::pre_upgrade`] for further testing. +/// +/// Panics if anything goes wrong. +pub fn pre_migrate< + T: pallet_session_historical::Config, + P: GetStorageVersion + PalletInfoAccess, +>() { + let new_pallet_name =

::name(); + + let storage_prefix_historical_sessions = + pallet_session_historical::HistoricalSessions::::storage_prefix(); + let storage_prefix_stored_range = pallet_session_historical::StoredRange::::storage_prefix(); + + log_migration("pre-migration", storage_prefix_historical_sessions, OLD_PREFIX, new_pallet_name); + log_migration("pre-migration", storage_prefix_stored_range, OLD_PREFIX, new_pallet_name); + + if new_pallet_name == OLD_PREFIX { + return + } + + let new_pallet_prefix = twox_128(new_pallet_name.as_bytes()); + let storage_version_key = twox_128(STORAGE_VERSION_STORAGE_KEY_POSTFIX); + + let mut new_pallet_prefix_iter = frame_support::storage::KeyPrefixIterator::new( + new_pallet_prefix.to_vec(), + new_pallet_prefix.to_vec(), + |key| Ok(key.to_vec()), + ); + + // Ensure nothing except the storage_version_key is stored in the new prefix. + assert!(new_pallet_prefix_iter.all(|key| key == storage_version_key)); + + assert!(

::on_chain_storage_version() < 1); +} + +/// Some checks for after migration. This can be linked to +/// [`frame_support::traits::OnRuntimeUpgrade::post_upgrade`] for further testing. +/// +/// Panics if anything goes wrong. +pub fn post_migrate< + T: pallet_session_historical::Config, + P: GetStorageVersion + PalletInfoAccess, +>() { + let new_pallet_name =

::name(); + + let storage_prefix_historical_sessions = + pallet_session_historical::HistoricalSessions::::storage_prefix(); + let storage_prefix_stored_range = pallet_session_historical::StoredRange::::storage_prefix(); + + log_migration( + "post-migration", + storage_prefix_historical_sessions, + OLD_PREFIX, + new_pallet_name, + ); + log_migration("post-migration", storage_prefix_stored_range, OLD_PREFIX, new_pallet_name); + + if new_pallet_name == OLD_PREFIX { + return + } + + // Assert that no `HistoricalSessions` and `StoredRange` storages remains at the old prefix. + let old_pallet_prefix = twox_128(OLD_PREFIX.as_bytes()); + let old_historical_sessions_key = + [&old_pallet_prefix, &twox_128(storage_prefix_historical_sessions)[..]].concat(); + let old_historical_sessions_key_iter = frame_support::storage::KeyPrefixIterator::new( + old_historical_sessions_key.to_vec(), + old_historical_sessions_key.to_vec(), + |_| Ok(()), + ); + assert_eq!(old_historical_sessions_key_iter.count(), 0); + + let old_stored_range_key = + [&old_pallet_prefix, &twox_128(storage_prefix_stored_range)[..]].concat(); + let old_stored_range_key_iter = frame_support::storage::KeyPrefixIterator::new( + old_stored_range_key.to_vec(), + old_stored_range_key.to_vec(), + |_| Ok(()), + ); + assert_eq!(old_stored_range_key_iter.count(), 0); + + // Assert that the `HistoricalSessions` and `StoredRange` storages (if they exist) have been + // moved to the new prefix. + // NOTE: storage_version_key is already in the new prefix. + let new_pallet_prefix = twox_128(new_pallet_name.as_bytes()); + let new_pallet_prefix_iter = frame_support::storage::KeyPrefixIterator::new( + new_pallet_prefix.to_vec(), + new_pallet_prefix.to_vec(), + |_| Ok(()), + ); + assert!(new_pallet_prefix_iter.count() >= 1); + + assert_eq!(

::on_chain_storage_version(), 1); +} + +fn log_migration(stage: &str, storage_prefix: &[u8], old_pallet_name: &str, new_pallet_name: &str) { + log::info!( + target: "runtime::session_historical", + "{} prefix of storage '{}': '{}' ==> '{}'", + stage, + str::from_utf8(storage_prefix).unwrap_or(""), + old_pallet_name, + new_pallet_name, + ); +} diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index 308ed7c5e5487..cc0606edf499d 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -453,3 +453,30 @@ fn upgrade_keys() { } }) } + +#[cfg(feature = "historical")] +#[test] +fn test_migration_v1() { + use crate::{ + historical::{HistoricalSessions, StoredRange}, + mock::Historical, + }; + use frame_support::traits::PalletInfoAccess; + + new_test_ext().execute_with(|| { + assert!(>::iter_values().count() > 0); + assert!(>::exists()); + + let old_pallet = "Session"; + let new_pallet = ::name(); + frame_support::storage::migration::move_pallet( + new_pallet.as_bytes(), + old_pallet.as_bytes(), + ); + StorageVersion::new(0).put::(); + + crate::migrations::v1::pre_migrate::(); + crate::migrations::v1::migrate::(); + crate::migrations::v1::post_migrate::(); + }); +} diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 95d397359f8d6..e5a3e49033934 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -96,6 +96,7 @@ frame_support::construct_runtime!( Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, + Historical: pallet_session::historical::{Pallet, Storage}, BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, } ); From 0baa586a57803dffa09ce1051ef54a63ad6f40d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 17 Nov 2021 10:53:31 +0100 Subject: [PATCH 0242/1472] authority-discovery: Support multiple authority ids per peer id (#10259) * authority-discovery: Support multiple authority ids per peer id An peer id can be mapped to multiple authority ids, because an authority id is a session key that could be changed every session. Before this pr the internal authority discovery cache assumed that each authority id can only be mapped to one peer id. However, this isn't true since we changed the default implementation of the authority discovery to combine the current and next session authorities. * Review feedback * Update client/authority-discovery/src/worker/addr_cache.rs Co-authored-by: Andronik Ordian * Early return on no peer ids * Update client/authority-discovery/src/worker/addr_cache.rs Co-authored-by: Pierre Krieger * Update types in comment * FMT * Add warning * Update client/authority-discovery/src/worker/addr_cache.rs Co-authored-by: Andronik Ordian * Feedback Co-authored-by: Andronik Ordian Co-authored-by: Pierre Krieger --- client/authority-discovery/src/lib.rs | 11 +- client/authority-discovery/src/service.rs | 11 +- client/authority-discovery/src/tests.rs | 8 +- client/authority-discovery/src/worker.rs | 8 +- .../src/worker/addr_cache.rs | 242 +++++++++++------- .../authority-discovery/src/worker/tests.rs | 5 +- 6 files changed, 173 insertions(+), 112 deletions(-) diff --git a/client/authority-discovery/src/lib.rs b/client/authority-discovery/src/lib.rs index 800f683aa0aef..1bbb9f38796c2 100644 --- a/client/authority-discovery/src/lib.rs +++ b/client/authority-discovery/src/lib.rs @@ -18,6 +18,7 @@ #![warn(missing_docs)] #![recursion_limit = "1024"] + //! Substrate authority discovery. //! //! This crate enables Substrate authorities to discover and directly connect to @@ -31,7 +32,7 @@ pub use crate::{ worker::{NetworkProvider, Role, Worker}, }; -use std::{sync::Arc, time::Duration}; +use std::{collections::HashSet, sync::Arc, time::Duration}; use futures::{ channel::{mpsc, oneshot}, @@ -58,11 +59,13 @@ pub struct WorkerConfig { /// /// By default this is set to 1 hour. pub max_publish_interval: Duration, + /// Interval at which the keystore is queried. If the keys have changed, unconditionally /// re-publish its addresses on the DHT. /// /// By default this is set to 1 minute. pub keystore_refresh_interval: Duration, + /// The maximum interval in which the node will query the DHT for new entries. /// /// By default this is set to 10 minutes. @@ -156,7 +159,7 @@ where /// Message send from the [`Service`] to the [`Worker`]. pub(crate) enum ServicetoWorkerMsg { /// See [`Service::get_addresses_by_authority_id`]. - GetAddressesByAuthorityId(AuthorityId, oneshot::Sender>>), - /// See [`Service::get_authority_id_by_peer_id`]. - GetAuthorityIdByPeerId(PeerId, oneshot::Sender>), + GetAddressesByAuthorityId(AuthorityId, oneshot::Sender>>), + /// See [`Service::get_authority_ids_by_peer_id`]. + GetAuthorityIdsByPeerId(PeerId, oneshot::Sender>>), } diff --git a/client/authority-discovery/src/service.rs b/client/authority-discovery/src/service.rs index 2e5ae66e4dd4a..9b59a4ec8647f 100644 --- a/client/authority-discovery/src/service.rs +++ b/client/authority-discovery/src/service.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::fmt::Debug; +use std::{collections::HashSet, fmt::Debug}; use crate::ServicetoWorkerMsg; @@ -62,7 +62,7 @@ impl Service { pub async fn get_addresses_by_authority_id( &mut self, authority: AuthorityId, - ) -> Option> { + ) -> Option> { let (tx, rx) = oneshot::channel(); self.to_worker @@ -78,11 +78,14 @@ impl Service { /// /// Returns `None` if no entry was present or connection to the /// [`crate::Worker`] failed. - pub async fn get_authority_id_by_peer_id(&mut self, peer_id: PeerId) -> Option { + pub async fn get_authority_ids_by_peer_id( + &mut self, + peer_id: PeerId, + ) -> Option> { let (tx, rx) = oneshot::channel(); self.to_worker - .send(ServicetoWorkerMsg::GetAuthorityIdByPeerId(peer_id, tx)) + .send(ServicetoWorkerMsg::GetAuthorityIdsByPeerId(peer_id, tx)) .await .ok()?; diff --git a/client/authority-discovery/src/tests.rs b/client/authority-discovery/src/tests.rs index 3784b4c834266..cef91445064ca 100644 --- a/client/authority-discovery/src/tests.rs +++ b/client/authority-discovery/src/tests.rs @@ -29,7 +29,7 @@ use libp2p::core::{ multiaddr::{Multiaddr, Protocol}, PeerId, }; -use std::sync::Arc; +use std::{collections::HashSet, sync::Arc}; use sp_authority_discovery::AuthorityId; use sp_core::crypto::key_types; @@ -73,12 +73,12 @@ fn get_addresses_and_authority_id() { pool.run_until(async { assert_eq!( - Some(vec![remote_addr]), + Some(HashSet::from([remote_addr])), service.get_addresses_by_authority_id(remote_authority_id.clone()).await, ); assert_eq!( - Some(remote_authority_id), - service.get_authority_id_by_peer_id(remote_peer_id).await, + Some(HashSet::from([remote_authority_id])), + service.get_authority_ids_by_peer_id(remote_peer_id).await, ); }); } diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index a689d0bafd262..00021ecbdcb83 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -259,9 +259,9 @@ where self.addr_cache.get_addresses_by_authority_id(&authority).map(Clone::clone), ); }, - ServicetoWorkerMsg::GetAuthorityIdByPeerId(peer_id, sender) => { + ServicetoWorkerMsg::GetAuthorityIdsByPeerId(peer_id, sender) => { let _ = sender - .send(self.addr_cache.get_authority_id_by_peer_id(&peer_id).map(Clone::clone)); + .send(self.addr_cache.get_authority_ids_by_peer_id(&peer_id).map(Clone::clone)); }, } } @@ -374,7 +374,7 @@ where .map_err(|e| Error::CallingRuntime(e.into()))? .into_iter() .filter(|id| !local_keys.contains(id.as_ref())) - .collect(); + .collect::>(); self.addr_cache.retain_ids(&authorities); @@ -548,7 +548,7 @@ where if let Some(metrics) = &self.metrics { metrics .known_authorities_count - .set(self.addr_cache.num_ids().try_into().unwrap_or(std::u64::MAX)); + .set(self.addr_cache.num_authority_ids().try_into().unwrap_or(std::u64::MAX)); } } Ok(()) diff --git a/client/authority-discovery/src/worker/addr_cache.rs b/client/authority-discovery/src/worker/addr_cache.rs index e770297f6f3be..d4ba156d5fa19 100644 --- a/client/authority-discovery/src/worker/addr_cache.rs +++ b/client/authority-discovery/src/worker/addr_cache.rs @@ -17,79 +17,94 @@ // along with this program. If not, see . use libp2p::core::multiaddr::{Multiaddr, Protocol}; -use std::collections::HashMap; use sc_network::PeerId; use sp_authority_discovery::AuthorityId; +use std::collections::{hash_map::Entry, HashMap, HashSet}; -/// Cache for [`AuthorityId`] -> [`Vec`] and [`PeerId`] -> [`AuthorityId`] mappings. +/// Cache for [`AuthorityId`] -> [`HashSet`] and [`PeerId`] -> [`HashSet`] +/// mappings. pub(super) struct AddrCache { - // The addresses found in `authority_id_to_addresses` are guaranteed to always match - // the peerids found in `peer_id_to_authority_id`. In other words, these two hashmaps - // are similar to a bi-directional map. - authority_id_to_addresses: HashMap>, - peer_id_to_authority_id: HashMap, + /// The addresses found in `authority_id_to_addresses` are guaranteed to always match + /// the peerids found in `peer_id_to_authority_ids`. In other words, these two hashmaps + /// are similar to a bi-directional map. + /// + /// Since we may store the mapping across several sessions, a single + /// `PeerId` might correspond to multiple `AuthorityId`s. However, + /// it's not expected that a single `AuthorityId` can have multiple `PeerId`s. + authority_id_to_addresses: HashMap>, + peer_id_to_authority_ids: HashMap>, } impl AddrCache { pub fn new() -> Self { AddrCache { authority_id_to_addresses: HashMap::new(), - peer_id_to_authority_id: HashMap::new(), + peer_id_to_authority_ids: HashMap::new(), } } /// Inserts the given [`AuthorityId`] and [`Vec`] pair for future lookups by /// [`AuthorityId`] or [`PeerId`]. - pub fn insert(&mut self, authority_id: AuthorityId, mut addresses: Vec) { - addresses.sort_unstable_by(|a, b| a.as_ref().cmp(b.as_ref())); + pub fn insert(&mut self, authority_id: AuthorityId, addresses: Vec) { + let addresses = addresses.into_iter().collect::>(); + let peer_ids = addresses_to_peer_ids(&addresses); + + if peer_ids.is_empty() { + log::debug!( + target: super::LOG_TARGET, + "Authority({:?}) provides no addresses or addresses without peer ids. Adresses: {:?}", + authority_id, + addresses, + ); - // Insert into `self.peer_id_to_authority_id`. - let peer_ids = addresses - .iter() - .map(|a| peer_id_from_multiaddr(a)) - .filter_map(|peer_id| peer_id); - for peer_id in peer_ids.clone() { - let former_auth = - match self.peer_id_to_authority_id.insert(peer_id, authority_id.clone()) { - Some(a) if a != authority_id => a, - _ => continue, - }; - - // PeerId was associated to a different authority id before. - // Remove corresponding authority from `self.authority_id_to_addresses`. - let former_auth_addrs = match self.authority_id_to_addresses.get_mut(&former_auth) { - Some(a) => a, - None => { - debug_assert!(false); - continue - }, - }; - former_auth_addrs.retain(|a| peer_id_from_multiaddr(a).map_or(true, |p| p != peer_id)); + return + } else if peer_ids.len() > 1 { + log::warn!( + target: super::LOG_TARGET, + "Authority({:?}) can be reached through multiple peer ids: {:?}", + authority_id, + peer_ids + ); } - // Insert into `self.authority_id_to_addresses`. - for former_addr in self - .authority_id_to_addresses - .insert(authority_id.clone(), addresses.clone()) - .unwrap_or_default() - { - // Must remove from `self.peer_id_to_authority_id` any PeerId formerly associated - // to that authority but that can't be found in its new addresses. - - let peer_id = match peer_id_from_multiaddr(&former_addr) { - Some(p) => p, - None => continue, - }; + let old_addresses = self.authority_id_to_addresses.insert(authority_id.clone(), addresses); + let old_peer_ids = addresses_to_peer_ids(&old_addresses.unwrap_or_default()); - if !peer_ids.clone().any(|p| p == peer_id) { - self.peer_id_to_authority_id.remove(&peer_id); + // Add the new peer ids + peer_ids.difference(&old_peer_ids).for_each(|new_peer_id| { + self.peer_id_to_authority_ids + .entry(*new_peer_id) + .or_default() + .insert(authority_id.clone()); + }); + + // Remove the old peer ids + self.remove_authority_id_from_peer_ids(&authority_id, old_peer_ids.difference(&peer_ids)); + } + + /// Remove the given `authority_id` from the `peer_id` to `authority_ids` mapping. + /// + /// If a `peer_id` doesn't have any `authority_id` assigned anymore, it is removed. + fn remove_authority_id_from_peer_ids<'a>( + &mut self, + authority_id: &AuthorityId, + peer_ids: impl Iterator, + ) { + peer_ids.for_each(|peer_id| { + if let Entry::Occupied(mut e) = self.peer_id_to_authority_ids.entry(*peer_id) { + e.get_mut().remove(authority_id); + + // If there are no more entries, remove the peer id. + if e.get().is_empty() { + e.remove(); + } } - } + }) } /// Returns the number of authority IDs in the cache. - pub fn num_ids(&self) -> usize { + pub fn num_authority_ids(&self) -> usize { self.authority_id_to_addresses.len() } @@ -97,18 +112,21 @@ impl AddrCache { pub fn get_addresses_by_authority_id( &self, authority_id: &AuthorityId, - ) -> Option<&Vec> { - self.authority_id_to_addresses.get(&authority_id) + ) -> Option<&HashSet> { + self.authority_id_to_addresses.get(authority_id) } - /// Returns the [`AuthorityId`] for the given [`PeerId`]. - pub fn get_authority_id_by_peer_id(&self, peer_id: &PeerId) -> Option<&AuthorityId> { - self.peer_id_to_authority_id.get(peer_id) + /// Returns the [`AuthorityId`]s for the given [`PeerId`]. + /// + /// As the authority id can change between sessions, one [`PeerId`] can be mapped to + /// multiple authority ids. + pub fn get_authority_ids_by_peer_id(&self, peer_id: &PeerId) -> Option<&HashSet> { + self.peer_id_to_authority_ids.get(peer_id) } /// Removes all [`PeerId`]s and [`Multiaddr`]s from the cache that are not related to the given /// [`AuthorityId`]s. - pub fn retain_ids(&mut self, authority_ids: &Vec) { + pub fn retain_ids(&mut self, authority_ids: &[AuthorityId]) { // The below logic could be replaced by `BtreeMap::drain_filter` once it stabilized. let authority_ids_to_remove = self .authority_id_to_addresses @@ -120,19 +138,18 @@ impl AddrCache { for authority_id_to_remove in authority_ids_to_remove { // Remove other entries from `self.authority_id_to_addresses`. - let addresses = self.authority_id_to_addresses.remove(&authority_id_to_remove); - - // Remove other entries from `self.peer_id_to_authority_id`. - let peer_ids = addresses - .iter() - .flatten() - .map(|a| peer_id_from_multiaddr(a)) - .filter_map(|peer_id| peer_id); - for peer_id in peer_ids { - if let Some(id) = self.peer_id_to_authority_id.remove(&peer_id) { - debug_assert_eq!(authority_id_to_remove, id); - } - } + let addresses = if let Some(addresses) = + self.authority_id_to_addresses.remove(&authority_id_to_remove) + { + addresses + } else { + continue + }; + + self.remove_authority_id_from_peer_ids( + &authority_id_to_remove, + addresses_to_peer_ids(&addresses).iter(), + ); } } } @@ -147,6 +164,13 @@ fn peer_id_from_multiaddr(addr: &Multiaddr) -> Option { }) } +fn addresses_to_peer_ids(addresses: &HashSet) -> HashSet { + addresses + .iter() + .filter_map(|a| peer_id_from_multiaddr(a)) + .collect::>() +} + #[cfg(test)] mod tests { use super::*; @@ -226,27 +250,27 @@ mod tests { cache.insert(third.0.clone(), vec![third.1.clone()]); assert_eq!( - Some(&vec![third.1.clone()]), + Some(&HashSet::from([third.1.clone()])), cache.get_addresses_by_authority_id(&third.0), - "Expect `get_addresses_by_authority_id` to return addresses of third authority." + "Expect `get_addresses_by_authority_id` to return addresses of third authority.", ); assert_eq!( - Some(&third.0), - cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&third.1).unwrap()), - "Expect `get_authority_id_by_peer_id` to return `AuthorityId` of third authority." + Some(&HashSet::from([third.0.clone()])), + cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&third.1).unwrap()), + "Expect `get_authority_id_by_peer_id` to return `AuthorityId` of third authority.", ); - cache.retain_ids(&vec![first.0, second.0]); + cache.retain_ids(&vec![first.0.clone(), second.0]); assert_eq!( None, cache.get_addresses_by_authority_id(&third.0), - "Expect `get_addresses_by_authority_id` to not return `None` for third authority." + "Expect `get_addresses_by_authority_id` to not return `None` for third authority.", ); assert_eq!( None, - cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&third.1).unwrap()), - "Expect `get_authority_id_by_peer_id` to return `None` for third authority." + cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&third.1).unwrap()), + "Expect `get_authority_id_by_peer_id` to return `None` for third authority.", ); TestResult::passed() @@ -282,44 +306,47 @@ mod tests { assert_eq!( None, - cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&multiaddr1).unwrap()) + cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr1).unwrap()) ); assert_eq!( - Some(&authority1), - cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&multiaddr2).unwrap()) + Some(&HashSet::from([authority1.clone()])), + cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr2).unwrap()) ); assert_eq!( - Some(&authority1), - cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&multiaddr3).unwrap()) + Some(&HashSet::from([authority1.clone()])), + cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr3).unwrap()) ); assert_eq!( - Some(&authority1), - cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&multiaddr4).unwrap()) + Some(&HashSet::from([authority1.clone()])), + cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr4).unwrap()) ); cache.insert(authority2.clone(), vec![multiaddr2.clone()]); assert_eq!( - Some(&authority2), - cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&multiaddr2).unwrap()) + Some(&HashSet::from([authority2.clone(), authority1.clone()])), + cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr2).unwrap()) ); assert_eq!( - Some(&authority1), - cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&multiaddr3).unwrap()) + Some(&HashSet::from([authority1.clone()])), + cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr3).unwrap()) ); - assert_eq!(cache.get_addresses_by_authority_id(&authority1).unwrap().len(), 2); + assert_eq!(cache.get_addresses_by_authority_id(&authority1).unwrap().len(), 3); cache.insert(authority2.clone(), vec![multiaddr2.clone(), multiaddr3.clone()]); assert_eq!( - Some(&authority2), - cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&multiaddr2).unwrap()) + Some(&HashSet::from([authority2.clone(), authority1.clone()])), + cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr2).unwrap()) + ); + assert_eq!( + Some(&HashSet::from([authority2.clone(), authority1.clone()])), + cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr3).unwrap()) ); assert_eq!( - Some(&authority2), - cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&multiaddr3).unwrap()) + &HashSet::from([multiaddr2.clone(), multiaddr3.clone(), multiaddr4.clone()]), + cache.get_addresses_by_authority_id(&authority1).unwrap(), ); - assert!(cache.get_addresses_by_authority_id(&authority1).unwrap().is_empty()); TestResult::passed() } @@ -328,4 +355,31 @@ mod tests { .max_tests(10) .quickcheck(property as fn(_, _, _, _, _) -> TestResult) } + + /// As the runtime gives us the current + next authority ids, it can happen that some + /// authority changed its session keys. Changing the sessions keys leads to having two + /// authority ids that map to the same `PeerId` & addresses. + #[test] + fn adding_two_authority_ids_for_the_same_peer_id() { + let mut addr_cache = AddrCache::new(); + + let peer_id = PeerId::random(); + let addr = Multiaddr::empty().with(Protocol::P2p(peer_id.into())); + + let authority_id0 = AuthorityPair::generate().0.public(); + let authority_id1 = AuthorityPair::generate().0.public(); + + addr_cache.insert(authority_id0.clone(), vec![addr.clone()]); + addr_cache.insert(authority_id1.clone(), vec![addr.clone()]); + + assert_eq!(2, addr_cache.num_authority_ids()); + assert_eq!( + &HashSet::from([addr.clone()]), + addr_cache.get_addresses_by_authority_id(&authority_id0).unwrap() + ); + assert_eq!( + &HashSet::from([addr]), + addr_cache.get_addresses_by_authority_id(&authority_id1).unwrap() + ); + } } diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index 3c1610256f5bc..130aea71fdfb0 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -19,6 +19,7 @@ use crate::worker::schema; use std::{ + collections::HashSet, sync::{Arc, Mutex}, task::Poll, }; @@ -469,7 +470,7 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { .send(ServicetoWorkerMsg::GetAddressesByAuthorityId(remote_public_key, sender)) .await .expect("Channel has capacity of 1."); - assert_eq!(Some(vec![remote_multiaddr]), addresses.await.unwrap()); + assert_eq!(Some(HashSet::from([remote_multiaddr])), addresses.await.unwrap()); }); } @@ -562,7 +563,7 @@ fn do_not_cache_addresses_without_peer_id() { local_worker.handle_dht_value_found_event(vec![dht_event]).unwrap(); assert_eq!( - Some(&vec![multiaddr_with_peer_id]), + Some(&HashSet::from([multiaddr_with_peer_id])), local_worker.addr_cache.get_addresses_by_authority_id(&remote_public.into()), "Expect worker to only cache `Multiaddr`s with `PeerId`s.", ); From e75d8e9a51b3d2b793018bd4d9ea772435a39c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 17 Nov 2021 11:35:21 +0100 Subject: [PATCH 0243/1472] Offchain testing: Fix reading response (#10294) --- primitives/core/src/offchain/testing.rs | 2 +- primitives/runtime/src/offchain/http.rs | 32 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index 26bcdb66de836..29b9edb03deb5 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -341,7 +341,7 @@ impl offchain::Externalities for TestOffchainExt { Ok(0) } else { let read = std::cmp::min(buffer.len(), response[req.read..].len()); - buffer[0..read].copy_from_slice(&response[req.read..read]); + buffer[0..read].copy_from_slice(&response[req.read..req.read + read]); req.read += read; Ok(read) } diff --git a/primitives/runtime/src/offchain/http.rs b/primitives/runtime/src/offchain/http.rs index 469f2fb5aff3a..a8c82e616a476 100644 --- a/primitives/runtime/src/offchain/http.rs +++ b/primitives/runtime/src/offchain/http.rs @@ -535,6 +535,38 @@ mod tests { }) } + #[test] + fn should_send_huge_response() { + let (offchain, state) = testing::TestOffchainExt::new(); + let mut t = TestExternalities::default(); + t.register_extension(OffchainWorkerExt::new(offchain)); + + t.execute_with(|| { + let request: Request = Request::get("http://localhost:1234"); + let pending = request.add_header("X-Auth", "hunter2").send().unwrap(); + // make sure it's sent correctly + state.write().fulfill_pending_request( + 0, + testing::PendingRequest { + method: "GET".into(), + uri: "http://localhost:1234".into(), + headers: vec![("X-Auth".into(), "hunter2".into())], + sent: true, + ..Default::default() + }, + vec![0; 5923], + None, + ); + + // wait + let response = pending.wait().unwrap(); + + let body = response.body(); + assert_eq!(body.clone().collect::>(), vec![0; 5923]); + assert_eq!(body.error(), &None); + }) + } + #[test] fn should_send_a_post_request() { let (offchain, state) = testing::TestOffchainExt::new(); From 6d61f48427ae40b11dbebc2b548818773c3c7f8e Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Wed, 17 Nov 2021 13:46:10 +0100 Subject: [PATCH 0244/1472] Check if BEEFY authority is in current set (#10281) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * check if BEEFY authority is in current set * Update client/beefy/src/round.rs Co-authored-by: Bastian Köcher * Update client/beefy/src/round.rs * Update client/beefy/src/round.rs Co-authored-by: Andreas Doerr * remove stray semi Co-authored-by: Bastian Köcher Co-authored-by: Andreas Doerr --- client/beefy/src/round.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index 7d443603b364e..51284c9bd2f6e 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -82,7 +82,11 @@ where } pub(crate) fn add_vote(&mut self, round: (H, N), vote: (Public, Signature)) -> bool { - self.rounds.entry(round).or_default().add_vote(vote) + if self.validator_set.validators.iter().any(|id| vote.0 == *id) { + self.rounds.entry(round).or_default().add_vote(vote) + } else { + false + } } pub(crate) fn is_done(&self, round: &(H, N)) -> bool { From 05a6abb9369426e862fc09fa51c544f1d03d5b71 Mon Sep 17 00:00:00 2001 From: wigy <1888808+wigy-opensource-developer@users.noreply.github.com> Date: Wed, 17 Nov 2021 15:11:02 +0100 Subject: [PATCH 0245/1472] Offence implementations can disable offenders independently from slashing (#10201) * Offence implementations can disable offenders independently from slashing * Fix build on CI * Run cargo fmt * Fixes based on review comments * Make parameter naming consistent * Fix migration and some English * Fix migration - again * cargo fmt * Cover 2 new cases with a test --- frame/offences/src/lib.rs | 1 + frame/offences/src/migration.rs | 9 +++- frame/offences/src/mock.rs | 3 +- frame/staking/src/mock.rs | 8 ++-- frame/staking/src/pallet/impls.rs | 4 +- frame/staking/src/slashing.rs | 70 +++++++++++++++---------------- frame/staking/src/tests.rs | 48 +++++++++++++++++++-- primitives/staking/src/offence.rs | 32 ++++++++++++++ 8 files changed, 129 insertions(+), 46 deletions(-) diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index ddae73e280d57..c230eac88dcee 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -150,6 +150,7 @@ where &concurrent_offenders, &slash_perbill, offence.session_index(), + offence.disable_strategy(), ); // Deposit the event. diff --git a/frame/offences/src/migration.rs b/frame/offences/src/migration.rs index b6e32cbe69e26..d655f2cec539a 100644 --- a/frame/offences/src/migration.rs +++ b/frame/offences/src/migration.rs @@ -19,7 +19,7 @@ use super::{Config, OffenceDetails, Perbill, SessionIndex}; use frame_support::{ generate_storage_alias, pallet_prelude::ValueQuery, traits::Get, weights::Weight, }; -use sp_staking::offence::OnOffenceHandler; +use sp_staking::offence::{DisableStrategy, OnOffenceHandler}; use sp_std::vec::Vec; /// Type of data stored as a deferred offence @@ -41,7 +41,12 @@ pub fn remove_deferred_storage() -> Weight { let deferred = >::take(); log::info!(target: "runtime::offences", "have {} deferred offences, applying.", deferred.len()); for (offences, perbill, session) in deferred.iter() { - let consumed = T::OnOffenceHandler::on_offence(&offences, &perbill, *session); + let consumed = T::OnOffenceHandler::on_offence( + &offences, + &perbill, + *session, + DisableStrategy::WhenSlashed, + ); weight = weight.saturating_add(consumed); } diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 5e4c94944b6fd..bce51f527abc6 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -36,7 +36,7 @@ use sp_runtime::{ Perbill, }; use sp_staking::{ - offence::{self, Kind, OffenceDetails}, + offence::{self, DisableStrategy, Kind, OffenceDetails}, SessionIndex, }; use std::cell::RefCell; @@ -55,6 +55,7 @@ impl offence::OnOffenceHandler _offenders: &[OffenceDetails], slash_fraction: &[Perbill], _offence_session: SessionIndex, + _disable_strategy: DisableStrategy, ) -> Weight { ON_OFFENCE_PERBILL.with(|f| { *f.borrow_mut() = slash_fraction.to_vec(); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index e5a3e49033934..2b74b0188cff4 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -33,7 +33,7 @@ use sp_runtime::{ testing::{Header, TestXt, UintAuthorityId}, traits::{IdentityLookup, Zero}, }; -use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; +use sp_staking::offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}; use std::cell::RefCell; pub const INIT_TIMESTAMP: u64 = 30_000; @@ -765,11 +765,12 @@ pub(crate) fn on_offence_in_era( >], slash_fraction: &[Perbill], era: EraIndex, + disable_strategy: DisableStrategy, ) { let bonded_eras = crate::BondedEras::::get(); for &(bonded_era, start_session) in bonded_eras.iter() { if bonded_era == era { - let _ = Staking::on_offence(offenders, slash_fraction, start_session); + let _ = Staking::on_offence(offenders, slash_fraction, start_session, disable_strategy); return } else if bonded_era > era { break @@ -781,6 +782,7 @@ pub(crate) fn on_offence_in_era( offenders, slash_fraction, Staking::eras_start_session_index(era).unwrap(), + disable_strategy, ); } else { panic!("cannot slash in era {}", era); @@ -795,7 +797,7 @@ pub(crate) fn on_offence_now( slash_fraction: &[Perbill], ) { let now = Staking::active_era().unwrap().index; - on_offence_in_era(offenders, slash_fraction, now) + on_offence_in_era(offenders, slash_fraction, now, DisableStrategy::WhenSlashed) } pub(crate) fn add_slash(who: &AccountId) { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 7ca1cb1a4a61b..8d86cfbe6b0d6 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -36,7 +36,7 @@ use sp_runtime::{ Perbill, }; use sp_staking::{ - offence::{OffenceDetails, OnOffenceHandler}, + offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, SessionIndex, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -1137,6 +1137,7 @@ where >], slash_fraction: &[Perbill], slash_session: SessionIndex, + disable_strategy: DisableStrategy, ) -> Weight { let reward_proportion = SlashRewardFraction::::get(); let mut consumed_weight: Weight = 0; @@ -1206,6 +1207,7 @@ where window_start, now: active_era, reward_proportion, + disable_strategy, }); if let Some(mut unapplied) = unapplied { diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 414c21aa347f0..066142d8ecc24 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -63,6 +63,7 @@ use sp_runtime::{ traits::{Saturating, Zero}, DispatchResult, RuntimeDebug, }; +use sp_staking::offence::DisableStrategy; use sp_std::vec::Vec; /// The proportion of the slashing reward to be paid out on the first slashing detection. @@ -213,6 +214,8 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> { /// The maximum percentage of a slash that ever gets paid out. /// This is f_inf in the paper. pub(crate) reward_proportion: Perbill, + /// When to disable offenders. + pub(crate) disable_strategy: DisableStrategy, } /// Computes a slash of a validator and nominators. It returns an unapplied @@ -224,15 +227,12 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> { pub(crate) fn compute_slash( params: SlashParams, ) -> Option>> { - let SlashParams { stash, slash, exposure, slash_era, window_start, now, reward_proportion } = - params.clone(); - let mut reward_payout = Zero::zero(); let mut val_slashed = Zero::zero(); // is the slash amount here a maximum for the era? - let own_slash = slash * exposure.own; - if slash * exposure.total == Zero::zero() { + let own_slash = params.slash * params.exposure.own; + if params.slash * params.exposure.total == Zero::zero() { // kick out the validator even if they won't be slashed, // as long as the misbehavior is from their most recent slashing span. kick_out_if_recent::(params); @@ -240,13 +240,17 @@ pub(crate) fn compute_slash( } let (prior_slash_p, _era_slash) = - as Store>::ValidatorSlashInEra::get(&slash_era, stash) + as Store>::ValidatorSlashInEra::get(¶ms.slash_era, params.stash) .unwrap_or((Perbill::zero(), Zero::zero())); // compare slash proportions rather than slash values to avoid issues due to rounding // error. - if slash.deconstruct() > prior_slash_p.deconstruct() { - as Store>::ValidatorSlashInEra::insert(&slash_era, stash, &(slash, own_slash)); + if params.slash.deconstruct() > prior_slash_p.deconstruct() { + as Store>::ValidatorSlashInEra::insert( + ¶ms.slash_era, + params.stash, + &(params.slash, own_slash), + ); } else { // we slash based on the max in era - this new event is not the max, // so neither the validator or any nominators will need an update. @@ -261,14 +265,14 @@ pub(crate) fn compute_slash( // apply slash to validator. { let mut spans = fetch_spans::( - stash, - window_start, + params.stash, + params.window_start, &mut reward_payout, &mut val_slashed, - reward_proportion, + params.reward_proportion, ); - let target_span = spans.compare_and_update_span_slash(slash_era, own_slash); + let target_span = spans.compare_and_update_span_slash(params.slash_era, own_slash); if target_span == Some(spans.span_index()) { // misbehavior occurred within the current slashing span - take appropriate @@ -276,20 +280,19 @@ pub(crate) fn compute_slash( // chill the validator - it misbehaved in the current span and should // not continue in the next election. also end the slashing span. - spans.end_span(now); - >::chill_stash(stash); + spans.end_span(params.now); + >::chill_stash(params.stash); } } - // add the validator to the offenders list and make sure it is disabled for - // the duration of the era - add_offending_validator::(params.stash, true); + let disable_when_slashed = params.disable_strategy != DisableStrategy::Never; + add_offending_validator::(params.stash, disable_when_slashed); let mut nominators_slashed = Vec::new(); - reward_payout += slash_nominators::(params, prior_slash_p, &mut nominators_slashed); + reward_payout += slash_nominators::(params.clone(), prior_slash_p, &mut nominators_slashed); Some(UnappliedSlash { - validator: stash.clone(), + validator: params.stash.clone(), own: val_slashed, others: nominators_slashed, reporters: Vec::new(), @@ -316,9 +319,8 @@ fn kick_out_if_recent(params: SlashParams) { >::chill_stash(params.stash); } - // add the validator to the offenders list but since there's no slash being - // applied there's no need to disable the validator - add_offending_validator::(params.stash, false); + let disable_without_slash = params.disable_strategy == DisableStrategy::Always; + add_offending_validator::(params.stash, disable_without_slash); } /// Add the given validator to the offenders list and optionally disable it. @@ -371,13 +373,10 @@ fn slash_nominators( prior_slash_p: Perbill, nominators_slashed: &mut Vec<(T::AccountId, BalanceOf)>, ) -> BalanceOf { - let SlashParams { stash: _, slash, exposure, slash_era, window_start, now, reward_proportion } = - params; - let mut reward_payout = Zero::zero(); - nominators_slashed.reserve(exposure.others.len()); - for nominator in &exposure.others { + nominators_slashed.reserve(params.exposure.others.len()); + for nominator in ¶ms.exposure.others { let stash = &nominator.who; let mut nom_slashed = Zero::zero(); @@ -385,15 +384,16 @@ fn slash_nominators( // had a new max slash for the era. let era_slash = { let own_slash_prior = prior_slash_p * nominator.value; - let own_slash_by_validator = slash * nominator.value; + let own_slash_by_validator = params.slash * nominator.value; let own_slash_difference = own_slash_by_validator.saturating_sub(own_slash_prior); - let mut era_slash = as Store>::NominatorSlashInEra::get(&slash_era, stash) - .unwrap_or_else(|| Zero::zero()); + let mut era_slash = + as Store>::NominatorSlashInEra::get(¶ms.slash_era, stash) + .unwrap_or_else(|| Zero::zero()); era_slash += own_slash_difference; - as Store>::NominatorSlashInEra::insert(&slash_era, stash, &era_slash); + as Store>::NominatorSlashInEra::insert(¶ms.slash_era, stash, &era_slash); era_slash }; @@ -402,18 +402,18 @@ fn slash_nominators( { let mut spans = fetch_spans::( stash, - window_start, + params.window_start, &mut reward_payout, &mut nom_slashed, - reward_proportion, + params.reward_proportion, ); - let target_span = spans.compare_and_update_span_slash(slash_era, era_slash); + let target_span = spans.compare_and_update_span_slash(params.slash_era, era_slash); if target_span == Some(spans.span_index()) { // End the span, but don't chill the nominator. its nomination // on this validator will be ignored in the future. - spans.end_span(now); + spans.end_span(params.now); } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 8f13fd7850803..f8f37bed0066c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -34,7 +34,7 @@ use sp_runtime::{ Perbill, Percent, }; use sp_staking::{ - offence::{OffenceDetails, OnOffenceHandler}, + offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, SessionIndex, }; use sp_std::prelude::*; @@ -2250,6 +2250,7 @@ fn slash_in_old_span_does_not_deselect() { }], &[Perbill::from_percent(0)], 1, + DisableStrategy::WhenSlashed, ); // the validator doesn't get chilled again @@ -2266,6 +2267,7 @@ fn slash_in_old_span_does_not_deselect() { // NOTE: A 100% slash here would clean up the account, causing de-registration. &[Perbill::from_percent(95)], 1, + DisableStrategy::WhenSlashed, ); // the validator doesn't get chilled again @@ -2562,6 +2564,7 @@ fn slashing_nominators_by_span_max() { }], &[Perbill::from_percent(10)], 2, + DisableStrategy::WhenSlashed, ); assert_eq!(Balances::free_balance(11), 900); @@ -2588,6 +2591,7 @@ fn slashing_nominators_by_span_max() { }], &[Perbill::from_percent(30)], 3, + DisableStrategy::WhenSlashed, ); // 11 was not further slashed, but 21 and 101 were. @@ -2609,6 +2613,7 @@ fn slashing_nominators_by_span_max() { }], &[Perbill::from_percent(20)], 2, + DisableStrategy::WhenSlashed, ); // 11 was further slashed, but 21 and 101 were not. @@ -2744,6 +2749,7 @@ fn remove_deferred() { &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], &[Perbill::from_percent(15)], 1, + DisableStrategy::WhenSlashed, ); // fails if empty @@ -2933,6 +2939,40 @@ fn non_slashable_offence_doesnt_disable_validator() { }); } +#[test] +fn slashing_independent_of_disabling_validator() { + ExtBuilder::default().build_and_execute(|| { + mock::start_active_era(1); + assert_eq_uvec!(Session::validators(), vec![11, 21]); + + let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + + let now = Staking::active_era().unwrap().index; + + // offence with no slash associated, BUT disabling + on_offence_in_era( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::zero()], + now, + DisableStrategy::Always, + ); + + // offence that slashes 25% of the bond, BUT not disabling + on_offence_in_era( + &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[Perbill::from_percent(25)], + now, + DisableStrategy::Never, + ); + + // the offence for validator 10 was explicitly disabled + assert!(is_disabled(10)); + // whereas validator 20 is explicitly not disabled + assert!(!is_disabled(20)); + }); +} + #[test] fn offence_threshold_triggers_new_era() { ExtBuilder::default() @@ -3595,7 +3635,7 @@ fn offences_weight_calculated_correctly() { ExtBuilder::default().nominate(true).build_and_execute(|| { // On offence with zero offenders: 4 Reads, 1 Write let zero_offence_weight = ::DbWeight::get().reads_writes(4, 1); - assert_eq!(Staking::on_offence(&[], &[Perbill::from_percent(50)], 0), zero_offence_weight); + assert_eq!(Staking::on_offence(&[], &[Perbill::from_percent(50)], 0, DisableStrategy::WhenSlashed), zero_offence_weight); // On Offence with N offenders, Unapplied: 4 Reads, 1 Write + 4 Reads, 5 Writes let n_offence_unapplied_weight = ::DbWeight::get().reads_writes(4, 1) @@ -3608,7 +3648,7 @@ fn offences_weight_calculated_correctly() { reporters: vec![], } ).collect(); - assert_eq!(Staking::on_offence(&offenders, &[Perbill::from_percent(50)], 0), n_offence_unapplied_weight); + assert_eq!(Staking::on_offence(&offenders, &[Perbill::from_percent(50)], 0, DisableStrategy::WhenSlashed), n_offence_unapplied_weight); // On Offence with one offenders, Applied let one_offender = [ @@ -3629,7 +3669,7 @@ fn offences_weight_calculated_correctly() { // `reward_cost` * reporters (1) + ::DbWeight::get().reads_writes(2, 2); - assert_eq!(Staking::on_offence(&one_offender, &[Perbill::from_percent(50)], 0), one_offence_unapplied_weight); + assert_eq!(Staking::on_offence(&one_offender, &[Perbill::from_percent(50)], 0, DisableStrategy::WhenSlashed), one_offence_unapplied_weight); }); } diff --git a/primitives/staking/src/offence.rs b/primitives/staking/src/offence.rs index a91cb47c117b6..fdff02d42065e 100644 --- a/primitives/staking/src/offence.rs +++ b/primitives/staking/src/offence.rs @@ -37,6 +37,29 @@ pub type Kind = [u8; 16]; /// so that we can slash it accordingly. pub type OffenceCount = u32; +/// In case of an offence, which conditions get an offending validator disabled. +#[derive( + Clone, + Copy, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + Encode, + Decode, + sp_runtime::RuntimeDebug, + scale_info::TypeInfo, +)] +pub enum DisableStrategy { + /// Independently of slashing, this offence will not disable the offender. + Never, + /// Only disable the offender if it is also slashed. + WhenSlashed, + /// Independently of slashing, this offence will always disable the offender. + Always, +} + /// A trait implemented by an offence report. /// /// This trait assumes that the offence is legitimate and was validated already. @@ -79,6 +102,11 @@ pub trait Offence { /// number. Note that for GRANDPA the round number is reset each epoch. fn time_slot(&self) -> Self::TimeSlot; + /// In which cases this offence needs to disable offenders until the next era starts. + fn disable_strategy(&self) -> DisableStrategy { + DisableStrategy::WhenSlashed + } + /// A slash fraction of the total exposure that should be slashed for this /// particular offence kind for the given parameters that happened at a singular `TimeSlot`. /// @@ -150,12 +178,15 @@ pub trait OnOffenceHandler { /// /// The `session` parameter is the session index of the offence. /// + /// The `disable_strategy` parameter decides if the offenders need to be disabled immediately. + /// /// The receiver might decide to not accept this offence. In this case, the call site is /// responsible for queuing the report and re-submitting again. fn on_offence( offenders: &[OffenceDetails], slash_fraction: &[Perbill], session: SessionIndex, + disable_strategy: DisableStrategy, ) -> Res; } @@ -164,6 +195,7 @@ impl OnOffenceHandler _offenders: &[OffenceDetails], _slash_fraction: &[Perbill], _session: SessionIndex, + _disable_strategy: DisableStrategy, ) -> Res { Default::default() } From 4c98bbab7fffc9b79525b31caf0e2f346b26185e Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 18 Nov 2021 00:14:16 -0400 Subject: [PATCH 0246/1472] Fix Weight Handlebar Template (#10302) * fix template * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_identity --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/identity/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- .maintain/frame-weight-template.hbs | 68 +++---- frame/identity/src/weights.rs | 191 +++++++++--------- utils/frame/benchmarking-cli/src/template.hbs | 30 +-- 3 files changed, 144 insertions(+), 145 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 045140d54dff7..4f34707b96020 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -22,7 +22,7 @@ //! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} // Executed Command: -{{#each args as |arg|~}} +{{#each args as |arg|}} // {{arg}} {{/each}} @@ -35,80 +35,80 @@ use sp_std::marker::PhantomData; /// Weight functions needed for {{pallet}}. pub trait WeightInfo { - {{~#each benchmarks as |benchmark|}} + {{#each benchmarks as |benchmark|}} fn {{benchmark.name~}} ( {{~#each benchmark.components as |c| ~}} {{c.name}}: u32, {{/each~}} ) -> Weight; - {{~/each}} + {{/each}} } /// Weights for {{pallet}} using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); -{{~#if (eq pallet "frame_system")}} +{{#if (eq pallet "frame_system")}} impl WeightInfo for SubstrateWeight { -{{~else}} +{{else}} impl WeightInfo for SubstrateWeight { -{{~/if}} - {{~#each benchmarks as |benchmark|}} - {{~#each benchmark.comments as |comment|}} +{{/if}} + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} // {{comment}} - {{~/each}} + {{/each}} fn {{benchmark.name~}} ( {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { ({{underscore benchmark.base_weight}} as Weight) - {{~#each benchmark.component_weight as |cw|}} + {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) - {{~/each}} - {{~#if (ne benchmark.base_reads "0")}} + {{/each}} + {{#if (ne benchmark.base_reads "0")}} .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight)) - {{~/if}} - {{~#each benchmark.component_reads as |cr|}} + {{/if}} + {{#each benchmark.component_reads as |cr|}} .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) - {{~/each}} - {{~#if (ne benchmark.base_writes "0")}} + {{/each}} + {{#if (ne benchmark.base_writes "0")}} .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight)) - {{~/if}} - {{~#each benchmark.component_writes as |cw|}} + {{/if}} + {{#each benchmark.component_writes as |cw|}} .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) - {{~/each}} + {{/each}} } - {{~/each}} + {{/each}} } // For backwards compatibility and tests impl WeightInfo for () { - {{~#each benchmarks as |benchmark|}} - {{~#each benchmark.comments as |comment|}} + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} // {{comment}} - {{~/each}} + {{/each}} fn {{benchmark.name~}} ( {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { ({{underscore benchmark.base_weight}} as Weight) - {{~#each benchmark.component_weight as |cw|}} + {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) - {{~/each}} - {{~#if (ne benchmark.base_reads "0")}} + {{/each}} + {{#if (ne benchmark.base_reads "0")}} .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}} as Weight)) - {{~/if}} - {{~#each benchmark.component_reads as |cr|}} + {{/if}} + {{#each benchmark.component_reads as |cr|}} .saturating_add(RocksDbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) - {{~/each}} - {{~#if (ne benchmark.base_writes "0")}} + {{/each}} + {{#if (ne benchmark.base_writes "0")}} .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}} as Weight)) - {{~/if}} - {{~#each benchmark.component_writes as |cw|}} + {{/if}} + {{#each benchmark.component_writes as |cw|}} .saturating_add(RocksDbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) - {{~/each}} + {{/each}} } - {{~/each}} + {{/each}} } diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 611909f326eab..92bc4cbaae924 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_identity //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-11-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -35,7 +35,6 @@ // --output=./frame/identity/src/weights.rs // --template=./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -68,19 +67,19 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:1) fn add_registrar(r: u32, ) -> Weight { - (22_152_000 as Weight) - // Standard Error: 6_000 - .saturating_add((339_000 as Weight).saturating_mul(r as Weight)) + (19_176_000 as Weight) + // Standard Error: 5_000 + .saturating_add((313_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn set_identity(r: u32, x: u32, ) -> Weight { - (53_017_000 as Weight) - // Standard Error: 14_000 - .saturating_add((279_000 as Weight).saturating_mul(r as Weight)) + (44_668_000 as Weight) + // Standard Error: 12_000 + .saturating_add((244_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((1_081_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((811_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -88,9 +87,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) fn set_subs_new(s: u32, ) -> Weight { - (44_693_000 as Weight) - // Standard Error: 1_000 - .saturating_add((6_631_000 as Weight).saturating_mul(s as Weight)) + (38_917_000 as Weight) + // Standard Error: 3_000 + .saturating_add((5_331_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -100,9 +99,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) fn set_subs_old(p: u32, ) -> Weight { - (42_017_000 as Weight) + (36_057_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_193_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_756_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -111,13 +110,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (50_989_000 as Weight) - // Standard Error: 11_000 - .saturating_add((258_000 as Weight).saturating_mul(r as Weight)) + (44_348_000 as Weight) + // Standard Error: 9_000 + .saturating_add((183_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((2_184_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_724_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 1_000 - .saturating_add((579_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((439_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -125,56 +124,56 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn request_judgement(r: u32, x: u32, ) -> Weight { - (55_562_000 as Weight) + (46_592_000 as Weight) // Standard Error: 5_000 - .saturating_add((317_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((321_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((1_137_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((858_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn cancel_request(r: u32, x: u32, ) -> Weight { - (51_744_000 as Weight) + (43_556_000 as Weight) // Standard Error: 6_000 - .saturating_add((192_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((174_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((1_131_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((850_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fee(r: u32, ) -> Weight { - (9_472_000 as Weight) - // Standard Error: 3_000 - .saturating_add((321_000 as Weight).saturating_mul(r as Weight)) + (7_971_000 as Weight) + // Standard Error: 4_000 + .saturating_add((283_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_account_id(r: u32, ) -> Weight { - (9_705_000 as Weight) - // Standard Error: 3_000 - .saturating_add((312_000 as Weight).saturating_mul(r as Weight)) + (8_234_000 as Weight) + // Standard Error: 4_000 + .saturating_add((280_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fields(r: u32, ) -> Weight { - (9_537_000 as Weight) - // Standard Error: 3_000 - .saturating_add((318_000 as Weight).saturating_mul(r as Weight)) + (8_126_000 as Weight) + // Standard Error: 4_000 + .saturating_add((275_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn provide_judgement(r: u32, x: u32, ) -> Weight { - (36_298_000 as Weight) + (30_949_000 as Weight) // Standard Error: 5_000 - .saturating_add((284_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((286_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((1_141_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((856_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -183,11 +182,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (63_238_000 as Weight) - // Standard Error: 10_000 - .saturating_add((246_000 as Weight).saturating_mul(r as Weight)) + (63_792_000 as Weight) + // Standard Error: 11_000 + .saturating_add((242_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((2_184_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_738_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -196,18 +195,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn add_sub(s: u32, ) -> Weight { - (57_394_000 as Weight) + (48_751_000 as Weight) // Standard Error: 1_000 - .saturating_add((208_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((193_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) fn rename_sub(s: u32, ) -> Weight { - (18_274_000 as Weight) + (15_892_000 as Weight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -215,18 +214,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn remove_sub(s: u32, ) -> Weight { - (58_184_000 as Weight) + (49_746_000 as Weight) // Standard Error: 1_000 - .saturating_add((195_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((181_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn quit_sub(s: u32, ) -> Weight { - (36_304_000 as Weight) + (32_286_000 as Weight) // Standard Error: 1_000 - .saturating_add((191_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((166_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -236,19 +235,19 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:1) fn add_registrar(r: u32, ) -> Weight { - (22_152_000 as Weight) - // Standard Error: 6_000 - .saturating_add((339_000 as Weight).saturating_mul(r as Weight)) + (19_176_000 as Weight) + // Standard Error: 5_000 + .saturating_add((313_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn set_identity(r: u32, x: u32, ) -> Weight { - (53_017_000 as Weight) - // Standard Error: 14_000 - .saturating_add((279_000 as Weight).saturating_mul(r as Weight)) + (44_668_000 as Weight) + // Standard Error: 12_000 + .saturating_add((244_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((1_081_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((811_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -256,9 +255,9 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) fn set_subs_new(s: u32, ) -> Weight { - (44_693_000 as Weight) - // Standard Error: 1_000 - .saturating_add((6_631_000 as Weight).saturating_mul(s as Weight)) + (38_917_000 as Weight) + // Standard Error: 3_000 + .saturating_add((5_331_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -268,9 +267,9 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) fn set_subs_old(p: u32, ) -> Weight { - (42_017_000 as Weight) + (36_057_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_193_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_756_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -279,13 +278,13 @@ impl WeightInfo for () { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (50_989_000 as Weight) - // Standard Error: 11_000 - .saturating_add((258_000 as Weight).saturating_mul(r as Weight)) + (44_348_000 as Weight) + // Standard Error: 9_000 + .saturating_add((183_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((2_184_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_724_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 1_000 - .saturating_add((579_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((439_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -293,56 +292,56 @@ impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn request_judgement(r: u32, x: u32, ) -> Weight { - (55_562_000 as Weight) + (46_592_000 as Weight) // Standard Error: 5_000 - .saturating_add((317_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((321_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((1_137_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((858_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn cancel_request(r: u32, x: u32, ) -> Weight { - (51_744_000 as Weight) + (43_556_000 as Weight) // Standard Error: 6_000 - .saturating_add((192_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((174_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((1_131_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((850_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fee(r: u32, ) -> Weight { - (9_472_000 as Weight) - // Standard Error: 3_000 - .saturating_add((321_000 as Weight).saturating_mul(r as Weight)) + (7_971_000 as Weight) + // Standard Error: 4_000 + .saturating_add((283_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_account_id(r: u32, ) -> Weight { - (9_705_000 as Weight) - // Standard Error: 3_000 - .saturating_add((312_000 as Weight).saturating_mul(r as Weight)) + (8_234_000 as Weight) + // Standard Error: 4_000 + .saturating_add((280_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fields(r: u32, ) -> Weight { - (9_537_000 as Weight) - // Standard Error: 3_000 - .saturating_add((318_000 as Weight).saturating_mul(r as Weight)) + (8_126_000 as Weight) + // Standard Error: 4_000 + .saturating_add((275_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn provide_judgement(r: u32, x: u32, ) -> Weight { - (36_298_000 as Weight) + (30_949_000 as Weight) // Standard Error: 5_000 - .saturating_add((284_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((286_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((1_141_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((856_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -351,11 +350,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (63_238_000 as Weight) - // Standard Error: 10_000 - .saturating_add((246_000 as Weight).saturating_mul(r as Weight)) + (63_792_000 as Weight) + // Standard Error: 11_000 + .saturating_add((242_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((2_184_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_738_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -364,18 +363,18 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn add_sub(s: u32, ) -> Weight { - (57_394_000 as Weight) + (48_751_000 as Weight) // Standard Error: 1_000 - .saturating_add((208_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((193_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) fn rename_sub(s: u32, ) -> Weight { - (18_274_000 as Weight) + (15_892_000 as Weight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -383,18 +382,18 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn remove_sub(s: u32, ) -> Weight { - (58_184_000 as Weight) + (49_746_000 as Weight) // Standard Error: 1_000 - .saturating_add((195_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((181_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn quit_sub(s: u32, ) -> Weight { - (36_304_000 as Weight) + (32_286_000 as Weight) // Standard Error: 1_000 - .saturating_add((191_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((166_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/utils/frame/benchmarking-cli/src/template.hbs b/utils/frame/benchmarking-cli/src/template.hbs index 36abf27f59a6e..ea734e165919a 100644 --- a/utils/frame/benchmarking-cli/src/template.hbs +++ b/utils/frame/benchmarking-cli/src/template.hbs @@ -6,7 +6,7 @@ //! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} // Executed Command: -{{#each args as |arg|~}} +{{#each args as |arg|}} // {{arg}} {{/each}} @@ -20,32 +20,32 @@ use sp_std::marker::PhantomData; /// Weight functions for `{{pallet}}`. pub struct WeightInfo(PhantomData); impl {{pallet}}::WeightInfo for WeightInfo { - {{~#each benchmarks as |benchmark|}} - {{~#each benchmark.comments as |comment|}} + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} // {{comment}} - {{~/each}} + {{/each}} fn {{benchmark.name~}} ( {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { ({{underscore benchmark.base_weight}} as Weight) - {{~#each benchmark.component_weight as |cw|}} + {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) - {{~/each}} - {{~#if (ne benchmark.base_reads "0")}} + {{/each}} + {{#if (ne benchmark.base_reads "0")}} .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight)) - {{~/if}} - {{~#each benchmark.component_reads as |cr|}} + {{/if}} + {{#each benchmark.component_reads as |cr|}} .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) - {{~/each}} - {{~#if (ne benchmark.base_writes "0")}} + {{/each}} + {{#if (ne benchmark.base_writes "0")}} .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight)) - {{~/if}} - {{~#each benchmark.component_writes as |cw|}} + {{/if}} + {{#each benchmark.component_writes as |cw|}} .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) - {{~/each}} + {{/each}} } - {{~/each}} + {{/each}} } From 0214f26b5fb6afb89b5322aa59e18b1d19e88a54 Mon Sep 17 00:00:00 2001 From: MOZGIII Date: Thu, 18 Nov 2021 12:05:48 +0300 Subject: [PATCH 0247/1472] Set current dir at check_wasm_toolchain_installed at wasm-builder (#10284) * Set current dir at check_wasm_toolchain_installed * Add comments --- utils/wasm-builder/src/prerequisites.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/utils/wasm-builder/src/prerequisites.rs b/utils/wasm-builder/src/prerequisites.rs index 7236b8169bcb5..88b1073a2951f 100644 --- a/utils/wasm-builder/src/prerequisites.rs +++ b/utils/wasm-builder/src/prerequisites.rs @@ -120,6 +120,9 @@ fn check_wasm_toolchain_installed( let manifest_path = temp.path().join("Cargo.toml").display().to_string(); let mut build_cmd = cargo_command.command(); + // Chdir to temp to avoid including project's .cargo/config.toml + // by accident - it can happen in some CI environments. + build_cmd.current_dir(&temp); build_cmd.args(&[ "build", "--target=wasm32-unknown-unknown", @@ -132,6 +135,9 @@ fn check_wasm_toolchain_installed( } let mut run_cmd = cargo_command.command(); + // Chdir to temp to avoid including project's .cargo/config.toml + // by accident - it can happen in some CI environments. + run_cmd.current_dir(&temp); run_cmd.args(&["run", "--manifest-path", &manifest_path]); // Unset the `CARGO_TARGET_DIR` to prevent a cargo deadlock From e670c040d42132da982e156e25a385df213354ed Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 18 Nov 2021 20:16:38 +0900 Subject: [PATCH 0248/1472] Clear WASM linear memory on other OSes besides Linux too (#10291) --- client/executor/src/integration_tests/mod.rs | 78 +++++++++++++++++++ .../executor/wasmtime/src/instance_wrapper.rs | 16 ++-- client/executor/wasmtime/src/runtime.rs | 8 +- 3 files changed, 91 insertions(+), 11 deletions(-) diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 7aa02a61dba11..01c040687ddd9 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -699,3 +699,81 @@ fn panic_in_spawned_instance_panics_on_joining_its_result(wasm_method: WasmExecu assert!(format!("{}", error_result).contains("Spawned task")); } + +test_wasm_execution!(memory_is_cleared_between_invocations); +fn memory_is_cleared_between_invocations(wasm_method: WasmExecutionMethod) { + // This is based on the code generated by compiling a runtime *without* + // the `-C link-arg=--import-memory` using the following code and then + // disassembling the resulting blob with `wasm-dis`: + // + // ``` + // #[no_mangle] + // #[cfg(not(feature = "std"))] + // pub fn returns_no_bss_mutable_static(_: *mut u8, _: usize) -> u64 { + // static mut COUNTER: usize = 0; + // let output = unsafe { + // COUNTER += 1; + // COUNTER as u64 + // }; + // sp_core::to_substrate_wasm_fn_return_value(&output) + // } + // ``` + // + // This results in the BSS section to *not* be emitted, hence the executor has no way + // of knowing about the `static` variable's existence, so this test will fail if the linear + // memory is not properly cleared between invocations. + let binary = wat::parse_str(r#" + (module + (type $i32_=>_i32 (func (param i32) (result i32))) + (type $i32_i32_=>_i64 (func (param i32 i32) (result i64))) + (import "env" "ext_allocator_malloc_version_1" (func $ext_allocator_malloc_version_1 (param i32) (result i32))) + (global $__stack_pointer (mut i32) (i32.const 1048576)) + (global $global$1 i32 (i32.const 1048580)) + (global $global$2 i32 (i32.const 1048592)) + (memory $0 17) + (export "memory" (memory $0)) + (export "returns_no_bss_mutable_static" (func $returns_no_bss_mutable_static)) + (export "__data_end" (global $global$1)) + (export "__heap_base" (global $global$2)) + (func $returns_no_bss_mutable_static (param $0 i32) (param $1 i32) (result i64) + (local $2 i32) + (local $3 i32) + (i32.store offset=1048576 + (i32.const 0) + (local.tee $2 + (i32.add + (i32.load offset=1048576 (i32.const 0)) + (i32.const 1) + ) + ) + ) + (i64.store + (local.tee $3 + (call $ext_allocator_malloc_version_1 (i32.const 8)) + ) + (i64.extend_i32_u (local.get $2)) + ) + (i64.or + (i64.extend_i32_u (local.get $3)) + (i64.const 34359738368) + ) + ) + )"#).unwrap(); + + let runtime = crate::wasm_runtime::create_wasm_runtime_with_code( + wasm_method, + 1024, + RuntimeBlob::uncompress_if_needed(&binary[..]).unwrap(), + HostFunctions::host_functions(), + true, + None, + ) + .unwrap(); + + let mut instance = runtime.new_instance().unwrap(); + let res = instance.call_export("returns_no_bss_mutable_static", &[0]).unwrap(); + assert_eq!(1, u64::decode(&mut &res[..]).unwrap()); + + let res = instance.call_export("returns_no_bss_mutable_static", &[0]).unwrap(); + assert_eq!(1, u64::decode(&mut &res[..]).unwrap()); +} diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index 2b8508ee2b07f..1d40563d0a9ff 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -403,10 +403,10 @@ impl InstanceWrapper { self.memory.data_ptr(ctx) } - /// Removes physical backing from the allocated linear memory. This leads to returning the - /// memory back to the system. While the memory is zeroed this is considered as a side-effect - /// and is not relied upon. Thus this function acts as a hint. - pub fn decommit(&self, ctx: impl AsContext) { + /// If possible removes physical backing from the allocated linear memory which + /// leads to returning the memory back to the system; this also zeroes the memory + /// as a side-effect. + pub fn decommit(&self, mut ctx: impl AsContextMut) { if self.memory.data_size(&ctx) == 0 { return } @@ -417,7 +417,7 @@ impl InstanceWrapper { unsafe { let ptr = self.memory.data_ptr(&ctx); - let len = self.memory.data_size(ctx); + let len = self.memory.data_size(&ctx); // Linux handles MADV_DONTNEED reliably. The result is that the given area // is unmapped and will be zeroed on the next pagefault. @@ -429,9 +429,15 @@ impl InstanceWrapper { std::io::Error::last_os_error(), ); }); + } else { + return; } } } } + + // If we're on an unsupported OS or the memory couldn't have been + // decommited for some reason then just manually zero it out. + self.memory.data_mut(ctx.as_context_mut()).fill(0); } } diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index bd113c3383838..4d107862173b0 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -237,7 +237,7 @@ impl WasmInstance for WasmtimeInstance { // Signal to the OS that we are done with the linear memory and that it can be // reclaimed. - instance_wrapper.decommit(&store); + instance_wrapper.decommit(store); result }, @@ -415,11 +415,7 @@ pub struct Semantics { /// /// Primarily this is achieved by not recreating the instance for each call and performing a /// bare minimum clean up: reapplying the data segments and restoring the values for global - /// variables. The vast majority of the linear memory is not restored, meaning that effects - /// of previous executions on the same [`WasmInstance`] can be observed there. - /// - /// This is not a problem for a standard substrate runtime execution because it's up to the - /// runtime itself to make sure that it doesn't involve any non-determinism. + /// variables. /// /// Since this feature depends on instrumentation, it can be set only if runtime is /// instantiated using the runtime blob, e.g. using [`create_runtime`]. From 80bc4a0c79f840e36059eae5427045086b7b8d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 18 Nov 2021 21:12:08 +0100 Subject: [PATCH 0249/1472] Make authorship soft deadline configurable. (#10125) * Make soft deadline configurable. * cargo +nightly fmt --all * Move setter where it belongs. --- .../basic-authorship/src/basic_authorship.rs | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 4c7f6c856ec86..0fd3932807a17 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -42,7 +42,7 @@ use sp_inherents::InherentData; use sp_runtime::{ generic::BlockId, traits::{BlakeTwo256, Block as BlockT, Hash as HashT, Header as HeaderT}, - Digest, + Digest, Percent, SaturatedConversion, }; use std::{marker::PhantomData, pin::Pin, sync::Arc, time}; @@ -58,6 +58,8 @@ use sc_proposer_metrics::MetricsLink as PrometheusMetrics; /// transferred to other nodes. pub const DEFAULT_BLOCK_SIZE_LIMIT: usize = 4 * 1024 * 1024 + 512; +const DEFAULT_SOFT_DEADLINE_PERCENT: Percent = Percent::from_percent(50); + /// [`Proposer`] factory. pub struct ProposerFactory { spawn_handle: Box, @@ -72,6 +74,14 @@ pub struct ProposerFactory { /// If no `block_size_limit` is passed to [`sp_consensus::Proposer::propose`], this block size /// limit will be used. default_block_size_limit: usize, + /// Soft deadline percentage of hard deadline. + /// + /// The value is used to compute soft deadline during block production. + /// The soft deadline indicates where we should stop attempting to add transactions + /// to the block, which exhaust resources. After soft deadline is reached, + /// we switch to a fixed-amount mode, in which after we see `MAX_SKIPPED_TRANSACTIONS` + /// transactions which exhaust resrouces, we will conclude that the block is full. + soft_deadline_percent: Percent, telemetry: Option, /// When estimating the block size, should the proof be included? include_proof_in_block_size_estimation: bool, @@ -96,6 +106,7 @@ impl ProposerFactory { transaction_pool, metrics: PrometheusMetrics::new(prometheus), default_block_size_limit: DEFAULT_BLOCK_SIZE_LIMIT, + soft_deadline_percent: DEFAULT_SOFT_DEADLINE_PERCENT, telemetry, client, include_proof_in_block_size_estimation: false, @@ -124,6 +135,7 @@ impl ProposerFactory { transaction_pool, metrics: PrometheusMetrics::new(prometheus), default_block_size_limit: DEFAULT_BLOCK_SIZE_LIMIT, + soft_deadline_percent: DEFAULT_SOFT_DEADLINE_PERCENT, telemetry, include_proof_in_block_size_estimation: true, _phantom: PhantomData, @@ -147,6 +159,22 @@ impl ProposerFactory { pub fn set_default_block_size_limit(&mut self, limit: usize) { self.default_block_size_limit = limit; } + + /// Set soft deadline percentage. + /// + /// The value is used to compute soft deadline during block production. + /// The soft deadline indicates where we should stop attempting to add transactions + /// to the block, which exhaust resources. After soft deadline is reached, + /// we switch to a fixed-amount mode, in which after we see `MAX_SKIPPED_TRANSACTIONS` + /// transactions which exhaust resrouces, we will conclude that the block is full. + /// + /// Setting the value too low will significantly limit the amount of transactions + /// we try in case they exhaust resources. Setting the value too high can + /// potentially open a DoS vector, where many "exhaust resources" transactions + /// are being tried with no success, hence block producer ends up creating an empty block. + pub fn set_soft_deadline(&mut self, percent: Percent) { + self.soft_deadline_percent = percent; + } } impl ProposerFactory @@ -184,6 +212,7 @@ where now, metrics: self.metrics.clone(), default_block_size_limit: self.default_block_size_limit, + soft_deadline_percent: self.soft_deadline_percent, telemetry: self.telemetry.clone(), _phantom: PhantomData, include_proof_in_block_size_estimation: self.include_proof_in_block_size_estimation, @@ -229,6 +258,7 @@ pub struct Proposer { metrics: PrometheusMetrics, default_block_size_limit: usize, include_proof_in_block_size_estimation: bool, + soft_deadline_percent: Percent, telemetry: Option, _phantom: PhantomData<(B, PR)>, } @@ -340,7 +370,10 @@ where // proceed with transactions // We calculate soft deadline used only in case we start skipping transactions. let now = (self.now)(); - let soft_deadline = now + deadline.saturating_duration_since(now) / 2; + let left = deadline.saturating_duration_since(now); + let left_micros: u64 = left.as_micros().saturated_into(); + let soft_deadline = + now + time::Duration::from_micros(self.soft_deadline_percent.mul_floor(left_micros)); let block_timer = time::Instant::now(); let mut skipped = 0; let mut unqueue_invalid = Vec::new(); From 3d4f1866ebb3cc73cceb12548b15775cedd3e475 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Fri, 19 Nov 2021 06:08:17 +0800 Subject: [PATCH 0250/1472] Migrate all doc to new pallet macro (#10187) * Migrate all doc to new pallet macro Signed-off-by: koushiro * Fix indent Signed-off-by: koushiro * Fix format Signed-off-by: koushiro --- bin/node-template/pallets/template/src/lib.rs | 2 +- frame/assets/README.md | 50 +++++++++++-------- frame/assets/src/lib.rs | 21 ++++---- frame/assets/src/mock.rs | 2 +- frame/collective/src/tests.rs | 3 +- frame/democracy/src/lib.rs | 13 ++--- frame/im-online/README.md | 34 ++++++++----- frame/im-online/src/lib.rs | 39 ++++++++------- frame/lottery/src/lib.rs | 4 +- frame/nicks/src/lib.rs | 8 +-- frame/node-authorization/src/lib.rs | 2 +- frame/randomness-collective-flip/README.md | 34 ++++++++----- frame/randomness-collective-flip/src/lib.rs | 8 +-- frame/recovery/src/lib.rs | 4 +- frame/scored-pool/README.md | 41 ++++++++------- frame/scored-pool/src/lib.rs | 27 ++++++---- frame/staking/README.md | 24 ++++++--- frame/staking/src/lib.rs | 22 +++++--- frame/sudo/README.md | 25 ++++++---- frame/sudo/src/lib.rs | 15 +++--- frame/system/README.md | 37 ++++++++------ frame/timestamp/README.md | 37 ++++++++------ frame/timestamp/src/lib.rs | 26 ++++++---- 23 files changed, 276 insertions(+), 202 deletions(-) diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index 18599168f1a63..f5ce8c5a0f7fd 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -16,7 +16,7 @@ mod benchmarking; #[frame_support::pallet] pub mod pallet { - use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; /// Configure the pallet by specifying the parameters and types on which it depends. diff --git a/frame/assets/README.md b/frame/assets/README.md index a99b60fa33d56..aae5244953e50 100644 --- a/frame/assets/README.md +++ b/frame/assets/README.md @@ -69,35 +69,43 @@ Import the Assets module and types and derive your runtime's configuration trait ```rust use pallet_assets as assets; -use frame_support::{decl_module, dispatch, ensure}; -use frame_system::ensure_signed; use sp_runtime::ArithmeticError; -pub trait Config: assets::Config { } +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - pub fn issue_token_airdrop(origin) -> dispatch::DispatchResult { - let sender = ensure_signed(origin).map_err(|e| e.as_str())?; + #[pallet::pallet] + pub struct Pallet(_); - const ACCOUNT_ALICE: u64 = 1; - const ACCOUNT_BOB: u64 = 2; - const COUNT_AIRDROP_RECIPIENTS: u64 = 2; - const TOKENS_FIXED_SUPPLY: u64 = 100; + #[pallet::config] + pub trait Config: frame_system::Config + assets::Config {} - ensure!(!COUNT_AIRDROP_RECIPIENTS.is_zero(), ArithmeticError::DivisionByZero); + #[pallet::call] + impl Pallet { + pub fn issue_token_airdrop(origin: OriginFor) -> DispatchResult { + let sender = ensure_signed(origin)?; - let asset_id = Self::next_asset_id(); + const ACCOUNT_ALICE: u64 = 1; + const ACCOUNT_BOB: u64 = 2; + const COUNT_AIRDROP_RECIPIENTS: u64 = 2; + const TOKENS_FIXED_SUPPLY: u64 = 100; - >::mutate(|asset_id| *asset_id += 1); - >::insert((asset_id, &ACCOUNT_ALICE), TOKENS_FIXED_SUPPLY / COUNT_AIRDROP_RECIPIENTS); - >::insert((asset_id, &ACCOUNT_BOB), TOKENS_FIXED_SUPPLY / COUNT_AIRDROP_RECIPIENTS); - >::insert(asset_id, TOKENS_FIXED_SUPPLY); + ensure!(!COUNT_AIRDROP_RECIPIENTS.is_zero(), ArithmeticError::DivisionByZero); - Self::deposit_event(RawEvent::Issued(asset_id, sender, TOKENS_FIXED_SUPPLY)); - Ok(()) - } - } + let asset_id = Self::next_asset_id(); + + >::mutate(|asset_id| *asset_id += 1); + >::insert((asset_id, &ACCOUNT_ALICE), TOKENS_FIXED_SUPPLY / COUNT_AIRDROP_RECIPIENTS); + >::insert((asset_id, &ACCOUNT_BOB), TOKENS_FIXED_SUPPLY / COUNT_AIRDROP_RECIPIENTS); + >::insert(asset_id, TOKENS_FIXED_SUPPLY); + + Self::deposit_event(Event::Issued(asset_id, sender, TOKENS_FIXED_SUPPLY)); + Ok(()) + } + } } ``` diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index f2bc86843ad9c..940120954f968 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -140,6 +140,15 @@ mod types; pub use types::*; use codec::HasCompact; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{ + AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedSub, Saturating, StaticLookup, Zero, + }, + ArithmeticError, TokenError, +}; +use sp_std::{borrow::Borrow, convert::TryInto, prelude::*}; + use frame_support::{ dispatch::{DispatchError, DispatchResult}, ensure, @@ -151,16 +160,6 @@ use frame_support::{ }, }; use frame_system::Config as SystemConfig; -use sp_runtime::{ - traits::{ - AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedSub, Saturating, StaticLookup, Zero, - }, - ArithmeticError, TokenError, -}; -use sp_std::{borrow::Borrow, prelude::*}; - -#[cfg(feature = "std")] -use frame_support::traits::GenesisBuild; pub use pallet::*; pub use weights::WeightInfo; @@ -168,7 +167,7 @@ pub use weights::WeightInfo; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; #[pallet::pallet] diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 1e1ea8ba9a961..aedf437ee8439 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -20,7 +20,7 @@ use super::*; use crate as pallet_assets; -use frame_support::{construct_runtime, parameter_types}; +use frame_support::{construct_runtime, parameter_types, traits::GenesisBuild}; use sp_core::H256; use sp_runtime::{ testing::Header, diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 7e52b10a9b1d6..cbd2f68ac73e8 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -52,9 +52,8 @@ mod mock_democracy { pub use pallet::*; #[frame_support::pallet] pub mod pallet { - use frame_support::{pallet_prelude::*, traits::EnsureOrigin}; + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - use sp_runtime::DispatchResult; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 529bcebc8e374..ec706ca8f48aa 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -240,16 +240,9 @@ enum Releases { #[frame_support::pallet] pub mod pallet { - use super::*; - use frame_support::{ - dispatch::DispatchResultWithPostInfo, - pallet_prelude::*, - traits::EnsureOrigin, - weights::{DispatchClass, Pays}, - Parameter, - }; - use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; - use sp_runtime::DispatchResult; + use super::{DispatchResult, *}; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] diff --git a/frame/im-online/README.md b/frame/im-online/README.md index 46b2268f18b12..be11e0c49dff3 100644 --- a/frame/im-online/README.md +++ b/frame/im-online/README.md @@ -26,21 +26,29 @@ It is submitted as an Unsigned Transaction via off-chain workers. ## Usage ```rust -use frame_support::{decl_module, dispatch}; -use frame_system::ensure_signed; use pallet_im_online::{self as im_online}; -pub trait Config: im_online::Config {} - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - #[weight = 0] - pub fn is_online(origin, authority_index: u32) -> dispatch::DispatchResult { - let _sender = ensure_signed(origin)?; - let _is_online = >::is_online(authority_index); - Ok(()) - } - } +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + im_online::Config {} + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + pub fn is_online(origin: OriginFor, authority_index: u32) -> DispatchResult { + let _sender = ensure_signed(origin)?; + let _is_online = >::is_online(authority_index); + Ok(()) + } + } } ``` diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 718c735fdad41..dbae5ed96d58a 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -17,12 +17,12 @@ //! # I'm online Pallet //! -//! If the local node is a validator (i.e. contains an authority key), this module +//! If the local node is a validator (i.e. contains an authority key), this pallet //! gossips a heartbeat transaction with each new session. The heartbeat functions //! as a simple mechanism to signal that the node is online in the current era. //! //! Received heartbeats are tracked for one era and reset with each new era. The -//! module exposes two public functions to query if a heartbeat has been received +//! pallet exposes two public functions to query if a heartbeat has been received //! in the current era or session. //! //! The heartbeat is a signed transaction, which was signed using the session key @@ -43,16 +43,24 @@ //! ## Usage //! //! ``` -//! use frame_support::{decl_module, dispatch}; -//! use frame_system::ensure_signed; //! use pallet_im_online::{self as im_online}; //! -//! pub trait Config: im_online::Config {} +//! #[frame_support::pallet] +//! pub mod pallet { +//! use super::*; +//! use frame_support::pallet_prelude::*; +//! use frame_system::pallet_prelude::*; //! -//! decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = 0] -//! pub fn is_online(origin, authority_index: u32) -> dispatch::DispatchResult { +//! #[pallet::pallet] +//! pub struct Pallet(_); +//! +//! #[pallet::config] +//! pub trait Config: frame_system::Config + im_online::Config {} +//! +//! #[pallet::call] +//! impl Pallet { +//! #[pallet::weight(0)] +//! pub fn is_online(origin: OriginFor, authority_index: u32) -> DispatchResult { //! let _sender = ensure_signed(origin)?; //! let _is_online = >::is_online(authority_index); //! Ok(()) @@ -64,7 +72,7 @@ //! //! ## Dependencies //! -//! This module depends on the [Session module](../pallet_session/index.html). +//! This pallet depends on the [Session pallet](../pallet_session/index.html). // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] @@ -302,15 +310,8 @@ type OffchainResult = Result::B #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, traits::Get, Parameter}; - use frame_system::{ensure_none, pallet_prelude::*}; - use sp_runtime::{ - traits::{MaybeSerializeDeserialize, Member}, - transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, - ValidTransaction, - }, - }; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index c1c536b8ba290..b30bc1dc523a6 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -115,8 +115,8 @@ impl ValidateCall for Pallet { #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, traits::EnsureOrigin, weights::Weight, Parameter}; - use frame_system::{ensure_signed, pallet_prelude::*}; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 438929576269c..bfc23187fc5b5 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -52,12 +52,8 @@ type NegativeImbalanceOf = <::Currency as Currency< #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{ - ensure, - pallet_prelude::*, - traits::{EnsureOrigin, Get}, - }; - use frame_system::{ensure_signed, pallet_prelude::*}; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; #[pallet::config] pub trait Config: frame_system::Config { diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 6e3ec58ba63f9..17b74053e6684 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -52,7 +52,7 @@ pub use weights::WeightInfo; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; #[pallet::pallet] diff --git a/frame/randomness-collective-flip/README.md b/frame/randomness-collective-flip/README.md index 9885c734d9fad..0730d4abf7cf2 100644 --- a/frame/randomness-collective-flip/README.md +++ b/frame/randomness-collective-flip/README.md @@ -20,18 +20,28 @@ the system trait. ### Example - Get random seed for the current block ```rust -use frame_support::{decl_module, dispatch, traits::Randomness}; - -pub trait Config: frame_system::Config {} - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - #[weight = 0] - pub fn random_module_example(origin) -> dispatch::DispatchResult { - let _random_value = >::random(&b"my context"[..]); - Ok(()) - } - } +use frame_support::traits::Randomness; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + pallet_randomness_collective_flip::Config {} + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + pub fn random_module_example(origin: OriginFor) -> DispatchResult { + let _random_value = >::random(&b"my context"[..]); + Ok(()) + } + } } ``` diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index a9abb2c9564df..345b8072c5e47 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Randomness Module +//! # Randomness Pallet //! -//! The Randomness Collective Flip module provides a [`random`](./struct.Module.html#method.random) +//! The Randomness Collective Flip pallet provides a [`random`](./struct.Module.html#method.random) //! function that generates low-influence random values based on the block hashes from the previous //! `81` blocks. Low-influence randomness can be useful when defending against relatively weak //! adversaries. Using this pallet as a randomness source is advisable primarily in low-security @@ -31,7 +31,7 @@ //! //! ### Prerequisites //! -//! Import the Randomness Collective Flip module and derive your module's configuration trait from +//! Import the Randomness Collective Flip pallet and derive your pallet's configuration trait from //! the system trait. //! //! ### Example - Get random seed for the current block @@ -41,9 +41,9 @@ //! //! #[frame_support::pallet] //! pub mod pallet { +//! use super::*; //! use frame_support::pallet_prelude::*; //! use frame_system::pallet_prelude::*; -//! use super::*; //! //! #[pallet::pallet] //! #[pallet::generate_store(pub(super) trait Store)] diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index 797581788077b..522d7008017f3 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -206,8 +206,8 @@ pub struct RecoveryConfig { #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{ensure, pallet_prelude::*, traits::Get, Parameter}; - use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; use sp_runtime::ArithmeticError; #[pallet::pallet] diff --git a/frame/scored-pool/README.md b/frame/scored-pool/README.md index bf20124edf52e..56c6af916ecd0 100644 --- a/frame/scored-pool/README.md +++ b/frame/scored-pool/README.md @@ -37,26 +37,33 @@ by the next highest scoring candidate in the pool, if available. ## Usage ```rust -use frame_support::{decl_module, dispatch}; -use frame_system::ensure_signed; use pallet_scored_pool::{self as scored_pool}; -pub trait Config: scored_pool::Config {} - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - #[weight = 0] - pub fn candidate(origin) -> dispatch::DispatchResult { - let who = ensure_signed(origin)?; - - let _ = >::submit_candidacy( - T::Origin::from(Some(who.clone()).into()) - ); - Ok(()) - } - } +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + scored_pool::Config {} + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + pub fn candidate(origin: OriginFor) -> DispatchResult { + let who = ensure_signed(origin)?; + + let _ = >::submit_candidacy( + T::Origin::from(Some(who.clone()).into()) + ); + Ok(()) + } + } } - ``` ## Dependencies diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index a5cdb6274f995..7c90d163dee1f 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -54,16 +54,24 @@ //! ## Usage //! //! ``` -//! use frame_support::{decl_module, dispatch}; -//! use frame_system::ensure_signed; //! use pallet_scored_pool::{self as scored_pool}; //! -//! pub trait Config: scored_pool::Config {} +//! #[frame_support::pallet] +//! pub mod pallet { +//! use super::*; +//! use frame_support::pallet_prelude::*; +//! use frame_system::pallet_prelude::*; //! -//! decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = 0] -//! pub fn candidate(origin) -> dispatch::DispatchResult { +//! #[pallet::pallet] +//! pub struct Pallet(_); +//! +//! #[pallet::config] +//! pub trait Config: frame_system::Config + scored_pool::Config {} +//! +//! #[pallet::call] +//! impl Pallet { +//! #[pallet::weight(0)] +//! pub fn candidate(origin: OriginFor) -> DispatchResult { //! let who = ensure_signed(origin)?; //! //! let _ = >::submit_candidacy( @@ -116,9 +124,8 @@ enum ChangeReceiver { #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, traits::EnsureOrigin, weights::Weight}; - use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; - use sp_runtime::traits::MaybeSerializeDeserialize; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] diff --git a/frame/staking/README.md b/frame/staking/README.md index 072353b1a586c..bbd5bd18f6e81 100644 --- a/frame/staking/README.md +++ b/frame/staking/README.md @@ -133,19 +133,27 @@ The Staking module contains many public storage items and (im)mutable functions. ### Example: Rewarding a validator by id. ```rust -use frame_support::{decl_module, dispatch}; -use frame_system::ensure_signed; use pallet_staking::{self as staking}; -pub trait Config: staking::Config {} +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; -decl_module! { - pub struct Module for enum Call where origin: T::Origin { + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + staking::Config {} + + #[pallet::call] + impl Pallet { /// Reward a validator. - #[weight = 0] - pub fn reward_myself(origin) -> dispatch::DispatchResult { + #[pallet::weight(0)] + pub fn reward_myself(origin: OriginFor) -> DispatchResult { let reported = ensure_signed(origin)?; - >::reward_by_ids(vec![(reported, 10)]); + >::reward_by_ids(vec![(reported, 10)]); Ok(()) } } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index be02e8d91d326..cb91abe476cba 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -157,17 +157,25 @@ //! ### Example: Rewarding a validator by id. //! //! ``` -//! use frame_support::{decl_module, dispatch}; -//! use frame_system::ensure_signed; //! use pallet_staking::{self as staking}; //! -//! pub trait Config: staking::Config {} +//! #[frame_support::pallet] +//! pub mod pallet { +//! use super::*; +//! use frame_support::pallet_prelude::*; +//! use frame_system::pallet_prelude::*; //! -//! decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { +//! #[pallet::pallet] +//! pub struct Pallet(_); +//! +//! #[pallet::config] +//! pub trait Config: frame_system::Config + staking::Config {} +//! +//! #[pallet::call] +//! impl Pallet { //! /// Reward a validator. -//! #[weight = 0] -//! pub fn reward_myself(origin) -> dispatch::DispatchResult { +//! #[pallet::weight(0)] +//! pub fn reward_myself(origin: OriginFor) -> DispatchResult { //! let reported = ensure_signed(origin)?; //! >::reward_by_ids(vec![(reported, 10)]); //! Ok(()) diff --git a/frame/sudo/README.md b/frame/sudo/README.md index 60090db46a4fc..e8f688091e326 100644 --- a/frame/sudo/README.md +++ b/frame/sudo/README.md @@ -35,15 +35,22 @@ Learn more about privileged functions and `Root` origin in the [`Origin`] type d This is an example of a module that exposes a privileged function: ```rust -use frame_support::{decl_module, dispatch}; -use frame_system::ensure_root; - -pub trait Config: frame_system::Config {} - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - #[weight = 0] - pub fn privileged_function(origin) -> dispatch::DispatchResult { +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + pub fn privileged_function(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; // do something... diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 5f8e6fc0cc13a..de3b3439bc344 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -52,28 +52,27 @@ //! This is an example of a pallet that exposes a privileged function: //! //! ``` -//! //! #[frame_support::pallet] -//! pub mod logger { +//! pub mod pallet { +//! use super::*; //! use frame_support::pallet_prelude::*; //! use frame_system::pallet_prelude::*; -//! use super::*; +//! +//! #[pallet::pallet] +//! pub struct Pallet(_); //! //! #[pallet::config] //! pub trait Config: frame_system::Config {} //! -//! #[pallet::pallet] -//! pub struct Pallet(PhantomData); -//! //! #[pallet::call] //! impl Pallet { //! #[pallet::weight(0)] -//! pub fn privileged_function(origin: OriginFor) -> DispatchResultWithPostInfo { +//! pub fn privileged_function(origin: OriginFor) -> DispatchResult { //! ensure_root(origin)?; //! //! // do something... //! -//! Ok(().into()) +//! Ok(()) //! } //! } //! } diff --git a/frame/system/README.md b/frame/system/README.md index 6766c3d73f4de..c22b41e42d798 100644 --- a/frame/system/README.md +++ b/frame/system/README.md @@ -54,21 +54,28 @@ Import the System module and derive your module's configuration trait from the s ### Example - Get extrinsic count and parent hash for the current block ```rust -use frame_support::{decl_module, dispatch}; -use frame_system::{self as system, ensure_signed}; - -pub trait Config: system::Config {} - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - #[weight = 0] - pub fn system_module_example(origin) -> dispatch::DispatchResult { - let _sender = ensure_signed(origin)?; - let _extrinsic_count = >::extrinsic_count(); - let _parent_hash = >::parent_hash(); - Ok(()) - } - } +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + pub fn system_module_example(origin: OriginFor) -> DispatchResult { + let _sender = ensure_signed(origin)?; + let _extrinsic_count = >::extrinsic_count(); + let _parent_hash = >::parent_hash(); + Ok(()) + } + } } ``` diff --git a/frame/timestamp/README.md b/frame/timestamp/README.md index 5f8388b04f829..1546377ee6743 100644 --- a/frame/timestamp/README.md +++ b/frame/timestamp/README.md @@ -45,20 +45,29 @@ trait from the timestamp trait. ### Get current timestamp ```rust -use frame_support::{decl_module, dispatch}; -use frame_system::ensure_signed; - -pub trait Config: timestamp::Config {} - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - #[weight = 0] - pub fn get_time(origin) -> dispatch::DispatchResult { - let _sender = ensure_signed(origin)?; - let _now = >::get(); - Ok(()) - } - } +use pallet_timestamp::{self as timestamp}; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + timestamp::Config {} + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + pub fn get_time(origin: OriginFor) -> DispatchResult { + let _sender = ensure_signed(origin)?; + let _now = >::get(); + Ok(()) + } + } } ``` diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index 153606bedbacf..eeb840715f817 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -64,18 +64,26 @@ //! ### Get current timestamp //! //! ``` -//! use frame_support::{decl_module, dispatch}; -//! # use pallet_timestamp as timestamp; -//! use frame_system::ensure_signed; +//! use pallet_timestamp::{self as timestamp}; //! -//! pub trait Config: timestamp::Config {} +//! #[frame_support::pallet] +//! pub mod pallet { +//! use super::*; +//! use frame_support::pallet_prelude::*; +//! use frame_system::pallet_prelude::*; //! -//! decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = 0] -//! pub fn get_time(origin) -> dispatch::DispatchResult { +//! #[pallet::pallet] +//! pub struct Pallet(_); +//! +//! #[pallet::config] +//! pub trait Config: frame_system::Config + timestamp::Config {} +//! +//! #[pallet::call] +//! impl Pallet { +//! #[pallet::weight(0)] +//! pub fn get_time(origin: OriginFor) -> DispatchResult { //! let _sender = ensure_signed(origin)?; -//! let _now = >::get(); +//! let _now = >::get(); //! Ok(()) //! } //! } From 4581dd99ed59f65ede46a34c81133177d5824a68 Mon Sep 17 00:00:00 2001 From: Georges Date: Fri, 19 Nov 2021 09:29:12 +0000 Subject: [PATCH 0251/1472] Moving `pallet-asset-tx-payment` from cumulus to substrate (#10127) * Moving `pallet-asset-tx-payment` from cumulus * move pallet-asset-tx-payment into transaction payment directory * cargo +nightly fmt * Adding `pallet-asset-tx-payment` to node runtime I had to change the Balance type to u128. Also harmonised that pallet's version * Updating cargo.lock after merge * forgot this * Adding tx-payment signature * Missed one more * `transaction-payment` replaced in`SignedExtension` by `asset-tx-payment` and not added * Fixing benches * add test to verify that we don't charge on post-dispatch if we didn't on pre-dispatch * add (failing) test for asset tx payment of unsigned extrinsics * fix test by removing debug_assert * cargo +nightly fmt * typo in `Cargo.lock` * Object defined twice in lock file * cargo update * remove todo * Apply formatting suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Refactoring `post_dispatch` of `asset-tx-payment` to reuse `post_dispatch` of `transaction-payment` if the fee asset is native Removing unneeded imports. * Removing redundant `TODO` * Reverting an accidental bump of `impl-serde` from `0.3.1` to `0.3.2` * Revert unneeded changes to `cargo.lock` * Update frame/transaction-payment/asset-tx-payment/src/payment.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fixing cargo fmt Reverting changes which broke cargo fmt Co-authored-by: Alexander Popiak Co-authored-by: Alexander Popiak Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 26 + Cargo.toml | 1 + bin/node/cli/Cargo.toml | 1 + bin/node/cli/src/service.rs | 6 +- bin/node/runtime/Cargo.toml | 1 + bin/node/runtime/src/impls.rs | 19 +- bin/node/runtime/src/lib.rs | 17 +- bin/node/test-runner-example/Cargo.toml | 1 + bin/node/test-runner-example/src/lib.rs | 2 +- bin/node/testing/Cargo.toml | 1 + bin/node/testing/src/keyring.rs | 2 +- .../asset-tx-payment/Cargo.toml | 55 ++ .../asset-tx-payment/README.md | 21 + .../asset-tx-payment/src/lib.rs | 288 +++++++ .../asset-tx-payment/src/payment.rs | 168 ++++ .../asset-tx-payment/src/tests.rs | 748 ++++++++++++++++++ 16 files changed, 1346 insertions(+), 11 deletions(-) create mode 100644 frame/transaction-payment/asset-tx-payment/Cargo.toml create mode 100644 frame/transaction-payment/asset-tx-payment/README.md create mode 100644 frame/transaction-payment/asset-tx-payment/src/lib.rs create mode 100644 frame/transaction-payment/asset-tx-payment/src/payment.rs create mode 100644 frame/transaction-payment/asset-tx-payment/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index f1e8b00c6eb0e..32234cc4c93a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4536,6 +4536,7 @@ dependencies = [ "node-primitives", "node-rpc", "node-runtime", + "pallet-asset-tx-payment", "pallet-balances", "pallet-im-online", "pallet-timestamp", @@ -4701,6 +4702,7 @@ dependencies = [ "hex-literal", "log 0.4.14", "node-primitives", + "pallet-asset-tx-payment", "pallet-assets", "pallet-authority-discovery", "pallet-authorship", @@ -4861,6 +4863,7 @@ dependencies = [ "node-executor", "node-primitives", "node-runtime", + "pallet-asset-tx-payment", "pallet-transaction-payment", "parity-scale-codec", "sc-block-builder", @@ -5104,6 +5107,28 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "pallet-asset-tx-payment" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "pallet-assets", + "pallet-authorship", + "pallet-balances", + "pallet-transaction-payment", + "parity-scale-codec", + "scale-info", + "serde", + "serde_json", + "smallvec 1.7.0", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-storage", +] + [[package]] name = "pallet-assets" version = "4.0.0-dev" @@ -10420,6 +10445,7 @@ dependencies = [ "node-cli", "node-primitives", "node-runtime", + "pallet-asset-tx-payment", "pallet-transaction-payment", "sc-consensus", "sc-consensus-babe", diff --git a/Cargo.toml b/Cargo.toml index e03f33a4d27d5..f30b223a9b205 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -124,6 +124,7 @@ members = [ "frame/system/rpc/runtime-api", "frame/timestamp", "frame/transaction-payment", + "frame/transaction-payment/asset-tx-payment", "frame/transaction-payment/rpc", "frame/transaction-payment/rpc/runtime-api", "frame/transaction-storage", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 7529138c7f9d7..5a9e76bccf63b 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -81,6 +81,7 @@ sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../frame/system/rpc/runtime-api" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } +pallet-asset-tx-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/asset-tx-payment/" } pallet-im-online = { version = "4.0.0-dev", default-features = false, path = "../../../frame/im-online" } # node-specific dependencies diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index e73b69153d1df..fec91a9b67cc4 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -92,7 +92,7 @@ pub fn create_extrinsic( )), frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(tip), + pallet_asset_tx_payment::ChargeAssetTxPayment::::from(tip, None), ); let raw_payload = node_runtime::SignedPayload::from_raw( @@ -725,7 +725,7 @@ mod tests { let check_era = frame_system::CheckEra::from(Era::Immortal); let check_nonce = frame_system::CheckNonce::from(index); let check_weight = frame_system::CheckWeight::new(); - let payment = pallet_transaction_payment::ChargeTransactionPayment::from(0); + let tx_payment = pallet_asset_tx_payment::ChargeAssetTxPayment::from(0, None); let extra = ( check_spec_version, check_tx_version, @@ -733,7 +733,7 @@ mod tests { check_era, check_nonce, check_weight, - payment, + tx_payment, ); let raw_payload = SignedPayload::from_raw( function, diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 9a481120fd01e..f9ce4b0fca900 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -95,6 +95,7 @@ pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../ pallet-utility = { version = "4.0.0-dev", default-features = false, path = "../../../frame/utility" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment/rpc/runtime-api/" } +pallet-asset-tx-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment/asset-tx-payment/" } pallet-transaction-storage = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-storage" } pallet-uniques = { version = "4.0.0-dev", default-features = false, path = "../../../frame/uniques" } pallet-vesting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/vesting" } diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index e315a45e698ce..cdd9f0900fd38 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -17,8 +17,12 @@ //! Some configurable implementations as associated type for the substrate runtime. -use crate::{Authorship, Balances, NegativeImbalance}; -use frame_support::traits::{Currency, OnUnbalanced}; +use crate::{AccountId, Assets, Authorship, Balances, NegativeImbalance, Runtime}; +use frame_support::traits::{ + fungibles::{Balanced, CreditOf}, + Currency, OnUnbalanced, +}; +use pallet_asset_tx_payment::HandleCredit; pub struct Author; impl OnUnbalanced for Author { @@ -27,6 +31,17 @@ impl OnUnbalanced for Author { } } +/// A `HandleCredit` implementation that naively transfers the fees to the block author. +/// Will drop and burn the assets in case the transfer fails. +pub struct CreditToBlockAuthor; +impl HandleCredit for CreditToBlockAuthor { + fn handle_credit(credit: CreditOf) { + let author = pallet_authorship::Pallet::::author(); + // Drop the result which will trigger the `OnDrop` of the imbalance in case of error. + let _ = Assets::resolve(&author, credit); + } +} + #[cfg(test)] mod multiplier_tests { use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 6d04ca8fdca87..5b3c0685d1a2a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -87,7 +87,7 @@ pub use sp_runtime::BuildStorage; /// Implementations of some helper traits passed into runtime modules as associated types. pub mod impls; -use impls::Author; +use impls::{Author, CreditToBlockAuthor}; /// Constant values used within the runtime. pub mod constants; @@ -432,6 +432,14 @@ impl pallet_transaction_payment::Config for Runtime { TargetedFeeAdjustment; } +impl pallet_asset_tx_payment::Config for Runtime { + type Fungibles = Assets; + type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< + pallet_assets::BalanceToAssetBalance, + CreditToBlockAuthor, + >; +} + parameter_types! { pub const MinimumPeriod: Moment = SLOT_DURATION / 2; } @@ -969,7 +977,7 @@ where frame_system::CheckEra::::from(era), frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(tip), + pallet_asset_tx_payment::ChargeAssetTxPayment::::from(tip, None), ); let raw_payload = SignedPayload::new(call, extra) .map_err(|e| { @@ -1168,7 +1176,7 @@ parameter_types! { impl pallet_assets::Config for Runtime { type Event = Event; - type Balance = u64; + type Balance = u128; type AssetId = u32; type Currency = Balances; type ForceOrigin = EnsureRoot; @@ -1257,6 +1265,7 @@ construct_runtime!( Indices: pallet_indices, Balances: pallet_balances, TransactionPayment: pallet_transaction_payment, + AssetTxPayment: pallet_asset_tx_payment, ElectionProviderMultiPhase: pallet_election_provider_multi_phase, Staking: pallet_staking, Session: pallet_session, @@ -1315,7 +1324,7 @@ pub type SignedExtra = ( frame_system::CheckEra, frame_system::CheckNonce, frame_system::CheckWeight, - pallet_transaction_payment::ChargeTransactionPayment, + pallet_asset_tx_payment::ChargeAssetTxPayment, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; diff --git a/bin/node/test-runner-example/Cargo.toml b/bin/node/test-runner-example/Cargo.toml index b664cdb8e50e2..831a687254409 100644 --- a/bin/node/test-runner-example/Cargo.toml +++ b/bin/node/test-runner-example/Cargo.toml @@ -11,6 +11,7 @@ test-runner = { path = "../../../test-utils/test-runner" } frame-system = { path = "../../../frame/system" } frame-benchmarking = { path = "../../../frame/benchmarking" } pallet-transaction-payment = { path = "../../../frame/transaction-payment" } +pallet-asset-tx-payment = { path = "../../../frame/transaction-payment/asset-tx-payment/" } node-runtime = { path = "../runtime" } node-primitives = { path = "../primitives" } diff --git a/bin/node/test-runner-example/src/lib.rs b/bin/node/test-runner-example/src/lib.rs index 0de7f5a4e2b70..68c14b73bf562 100644 --- a/bin/node/test-runner-example/src/lib.rs +++ b/bin/node/test-runner-example/src/lib.rs @@ -77,7 +77,7 @@ impl ChainInfo for NodeTemplateChainInfo { frame_system::Pallet::::account_nonce(from), ), frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(0), + pallet_asset_tx_payment::ChargeAssetTxPayment::::from(0, None), ) } } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 1854029b0709e..0e5ed07ac2952 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -38,6 +38,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } substrate-test-client = { version = "2.0.0", path = "../../../test-utils/client" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } +pallet-asset-tx-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/asset-tx-payment/" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/timestamp" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } diff --git a/bin/node/testing/src/keyring.rs b/bin/node/testing/src/keyring.rs index 4e2d88b4bba33..1040e90c4d5d4 100644 --- a/bin/node/testing/src/keyring.rs +++ b/bin/node/testing/src/keyring.rs @@ -76,7 +76,7 @@ pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra { frame_system::CheckEra::from(Era::mortal(256, 0)), frame_system::CheckNonce::from(nonce), frame_system::CheckWeight::new(), - pallet_transaction_payment::ChargeTransactionPayment::from(extra_fee), + pallet_asset_tx_payment::ChargeAssetTxPayment::from(extra_fee, None), ) } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml new file mode 100644 index 0000000000000..a381145d667a1 --- /dev/null +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "pallet-asset-tx-payment" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "pallet to manage transaction payments in assets" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +# Substrate dependencies +sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } + +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } +pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = ".." } + +# Other dependencies +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +serde = { version = "1.0.126", optional = true } + +[dev-dependencies] +smallvec = "1.7.0" +serde_json = "1.0.68" + +sp-storage = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/storage" } + +pallet-assets = { version = "4.0.0-dev", path = "../../assets" } +pallet-authorship = { version = "4.0.0-dev", path = "../../authorship" } +pallet-balances = { version = "4.0.0-dev", path = "../../balances" } + + +[features] +default = ["std"] +std = [ + "serde", + "codec/std", + "sp-std/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", + "sp-io/std", + "sp-core/std", + "pallet-transaction-payment/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/transaction-payment/asset-tx-payment/README.md b/frame/transaction-payment/asset-tx-payment/README.md new file mode 100644 index 0000000000000..fc860347d85fa --- /dev/null +++ b/frame/transaction-payment/asset-tx-payment/README.md @@ -0,0 +1,21 @@ +# pallet-asset-tx-payment + +## Asset Transaction Payment Pallet + +This pallet allows runtimes that include it to pay for transactions in assets other than the +native token of the chain. + +### Overview +It does this by extending transactions to include an optional `AssetId` that specifies the asset +to be used for payment (defaulting to the native token on `None`). It expects an +[`OnChargeAssetTransaction`] implementation analogously to [`pallet-transaction-payment`]. The +included [`FungiblesAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the fee +amount by converting the fee calculated by [`pallet-transaction-payment`] into the desired +asset. + +### Integration +This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means +you should include both pallets in your `construct_runtime` macro, but only include this +pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). + +License: Apache-2.0 diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs new file mode 100644 index 0000000000000..1f22669857d76 --- /dev/null +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -0,0 +1,288 @@ +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Asset Transaction Payment Pallet +//! +//! This pallet allows runtimes that include it to pay for transactions in assets other than the +//! main token of the chain. +//! +//! ## Overview + +//! It does this by extending transactions to include an optional `AssetId` that specifies the asset +//! to be used for payment (defaulting to the native token on `None`). It expects an +//! [`OnChargeAssetTransaction`] implementation analogously to [`pallet-transaction-payment`]. The +//! included [`FungiblesAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the fee +//! amount by converting the fee calculated by [`pallet-transaction-payment`] into the desired +//! asset. +//! +//! ## Integration + +//! This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means +//! you should include both pallets in your `construct_runtime` macro, but only include this +//! pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). + +#![cfg_attr(not(feature = "std"), no_std)] + +use sp_std::prelude::*; + +use codec::{Decode, Encode}; +use frame_support::{ + dispatch::DispatchResult, + traits::{ + tokens::{ + fungibles::{Balanced, CreditOf, Inspect}, + WithdrawConsequence, + }, + IsType, + }, + weights::{DispatchInfo, PostDispatchInfo}, + DefaultNoBound, +}; +use pallet_transaction_payment::OnChargeTransaction; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero}, + transaction_validity::{ + InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, + }, + FixedPointOperand, +}; + +#[cfg(test)] +mod tests; + +mod payment; +pub use payment::*; + +// Type aliases used for interaction with `OnChargeTransaction`. +pub(crate) type OnChargeTransactionOf = + ::OnChargeTransaction; +// Balance type alias. +pub(crate) type BalanceOf = as OnChargeTransaction>::Balance; +// Liquity info type alias. +pub(crate) type LiquidityInfoOf = + as OnChargeTransaction>::LiquidityInfo; + +// Type alias used for interaction with fungibles (assets). +// Balance type alias. +pub(crate) type AssetBalanceOf = + <::Fungibles as Inspect<::AccountId>>::Balance; +/// Asset id type alias. +pub(crate) type AssetIdOf = + <::Fungibles as Inspect<::AccountId>>::AssetId; + +// Type aliases used for interaction with `OnChargeAssetTransaction`. +// Balance type alias. +pub(crate) type ChargeAssetBalanceOf = + <::OnChargeAssetTransaction as OnChargeAssetTransaction>::Balance; +// Asset id type alias. +pub(crate) type ChargeAssetIdOf = + <::OnChargeAssetTransaction as OnChargeAssetTransaction>::AssetId; +// Liquity info type alias. +pub(crate) type ChargeAssetLiquidityOf = + <::OnChargeAssetTransaction as OnChargeAssetTransaction>::LiquidityInfo; + +/// Used to pass the initial payment info from pre- to post-dispatch. +#[derive(Encode, Decode, DefaultNoBound, TypeInfo)] +pub enum InitialPayment { + /// No initial fee was payed. + Nothing, + /// The initial fee was payed in the native currency. + Native(LiquidityInfoOf), + /// The initial fee was payed in an asset. + Asset(CreditOf), +} + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config + pallet_transaction_payment::Config { + /// The fungibles instance used to pay for transactions in assets. + type Fungibles: Balanced; + /// The actual transaction charging logic that charges the fees. + type OnChargeAssetTransaction: OnChargeAssetTransaction; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); +} + +/// Require the transactor pay for themselves and maybe include a tip to gain additional priority +/// in the queue. Allows paying via both `Currency` as well as `fungibles::Balanced`. +/// +/// Wraps the transaction logic in [`pallet_transaction_payment`] and extends it with assets. +/// An asset id of `None` falls back to the underlying transaction payment via the native currency. +#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct ChargeAssetTxPayment { + #[codec(compact)] + tip: BalanceOf, + asset_id: Option>, +} + +impl ChargeAssetTxPayment +where + T::Call: Dispatchable, + AssetBalanceOf: Send + Sync + FixedPointOperand, + BalanceOf: Send + Sync + FixedPointOperand + IsType>, + ChargeAssetIdOf: Send + Sync, + CreditOf: IsType>, +{ + /// Utility constructor. Used only in client/factory code. + pub fn from(tip: BalanceOf, asset_id: Option>) -> Self { + Self { tip, asset_id } + } + + /// Fee withdrawal logic that dispatches to either `OnChargeAssetTransaction` or + /// `OnChargeTransaction`. + fn withdraw_fee( + &self, + who: &T::AccountId, + call: &T::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result<(BalanceOf, InitialPayment), TransactionValidityError> { + let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); + debug_assert!(self.tip <= fee, "tip should be included in the computed fee"); + if fee.is_zero() { + Ok((fee, InitialPayment::Nothing)) + } else if let Some(asset_id) = self.asset_id { + T::OnChargeAssetTransaction::withdraw_fee( + who, + call, + info, + asset_id, + fee.into(), + self.tip.into(), + ) + .map(|i| (fee, InitialPayment::Asset(i.into()))) + } else { + as OnChargeTransaction>::withdraw_fee( + who, call, info, fee, self.tip, + ) + .map(|i| (fee, InitialPayment::Native(i))) + .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() }) + } + } +} + +impl sp_std::fmt::Debug for ChargeAssetTxPayment { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "ChargeAssetTxPayment<{:?}, {:?}>", self.tip, self.asset_id.encode()) + } + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +impl SignedExtension for ChargeAssetTxPayment +where + T::Call: Dispatchable, + AssetBalanceOf: Send + Sync + FixedPointOperand, + BalanceOf: Send + Sync + From + FixedPointOperand + IsType>, + ChargeAssetIdOf: Send + Sync, + CreditOf: IsType>, +{ + const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; + type AccountId = T::AccountId; + type Call = T::Call; + type AdditionalSigned = (); + type Pre = ( + // tip + BalanceOf, + // who paid the fee + Self::AccountId, + // imbalance resulting from withdrawing the fee + InitialPayment, + ); + + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + + fn validate( + &self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> TransactionValidity { + use pallet_transaction_payment::ChargeTransactionPayment; + let (fee, _) = self.withdraw_fee(who, call, info, len)?; + let priority = ChargeTransactionPayment::::get_priority(info, len, self.tip, fee); + Ok(ValidTransaction { priority, ..Default::default() }) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?; + Ok((self.tip, who.clone(), initial_payment)) + } + + fn post_dispatch( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + let (tip, who, initial_payment) = pre; + match initial_payment { + InitialPayment::Native(already_withdrawn) => { + pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( + (tip, who, already_withdrawn), + info, + post_info, + len, + result, + )?; + }, + InitialPayment::Asset(already_withdrawn) => { + let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( + len as u32, info, post_info, tip, + ); + T::OnChargeAssetTransaction::correct_and_deposit_fee( + &who, + info, + post_info, + actual_fee.into(), + tip.into(), + already_withdrawn.into(), + )?; + }, + InitialPayment::Nothing => { + // `actual_fee` should be zero here for any signed extrinsic. It would be non-zero + // here in case of unsigned extrinsics as they don't pay fees but + // `compute_actual_fee` is not aware of them. In both cases it's fine to just move + // ahead without adjusting the fee, though, so we do nothing. + debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); + }, + } + + Ok(()) + } +} diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs new file mode 100644 index 0000000000000..09482f96490c7 --- /dev/null +++ b/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -0,0 +1,168 @@ +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +///! Traits and default implementation for paying transaction fees in assets. +use super::*; +use crate::Config; + +use codec::FullCodec; +use frame_support::{ + traits::{ + fungibles::{Balanced, CreditOf, Inspect}, + tokens::BalanceConversion, + }, + unsigned::TransactionValidityError, +}; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{ + AtLeast32BitUnsigned, DispatchInfoOf, MaybeSerializeDeserialize, One, PostDispatchInfoOf, + }, + transaction_validity::InvalidTransaction, +}; +use sp_std::{fmt::Debug, marker::PhantomData}; + +/// Handle withdrawing, refunding and depositing of transaction fees. +pub trait OnChargeAssetTransaction { + /// The underlying integer type in which fees are calculated. + type Balance: AtLeast32BitUnsigned + + FullCodec + + Copy + + MaybeSerializeDeserialize + + Debug + + Default + + TypeInfo; + /// The type used to identify the assets used for transaction payment. + type AssetId: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo; + /// The type used to store the intermediate values between pre- and post-dispatch. + type LiquidityInfo; + + /// Before the transaction is executed the payment of the transaction fees needs to be secured. + /// + /// Note: The `fee` already includes the `tip`. + fn withdraw_fee( + who: &T::AccountId, + call: &T::Call, + dispatch_info: &DispatchInfoOf, + asset_id: Self::AssetId, + fee: Self::Balance, + tip: Self::Balance, + ) -> Result; + + /// After the transaction was executed the actual fee can be calculated. + /// This function should refund any overpaid fees and optionally deposit + /// the corrected amount. + /// + /// Note: The `fee` already includes the `tip`. + fn correct_and_deposit_fee( + who: &T::AccountId, + dispatch_info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + corrected_fee: Self::Balance, + tip: Self::Balance, + already_withdrawn: Self::LiquidityInfo, + ) -> Result<(), TransactionValidityError>; +} + +/// Allows specifying what to do with the withdrawn asset fees. +pub trait HandleCredit> { + /// Implement to determine what to do with the withdrawn asset fees. + /// Default for `CreditOf` from the assets pallet is to burn and + /// decrease total issuance. + fn handle_credit(credit: CreditOf); +} + +/// Default implementation that just drops the credit according to the `OnDrop` in the underlying +/// imbalance type. +impl> HandleCredit for () { + fn handle_credit(_credit: CreditOf) {} +} + +/// Implements the asset transaction for a balance to asset converter (implementing +/// [`BalanceConversion`]) and a credit handler (implementing [`HandleCredit`]). +/// +/// The credit handler is given the complete fee in terms of the asset used for the transaction. +pub struct FungiblesAdapter(PhantomData<(CON, HC)>); + +/// Default implementation for a runtime instantiating this pallet, a balance to asset converter and +/// a credit handler. +impl OnChargeAssetTransaction for FungiblesAdapter +where + T: Config, + CON: BalanceConversion, AssetIdOf, AssetBalanceOf>, + HC: HandleCredit, + AssetIdOf: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo, +{ + type Balance = BalanceOf; + type AssetId = AssetIdOf; + type LiquidityInfo = CreditOf; + + /// Withdraw the predicted fee from the transaction origin. + /// + /// Note: The `fee` already includes the `tip`. + fn withdraw_fee( + who: &T::AccountId, + _call: &T::Call, + _info: &DispatchInfoOf, + asset_id: Self::AssetId, + fee: Self::Balance, + _tip: Self::Balance, + ) -> Result { + // We don't know the precision of the underlying asset. Because the converted fee could be + // less than one (e.g. 0.5) but gets rounded down by integer division we introduce a minimum + // fee. + let min_converted_fee = if fee.is_zero() { Zero::zero() } else { One::one() }; + let converted_fee = CON::to_asset_balance(fee, asset_id) + .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))? + .max(min_converted_fee); + let can_withdraw = >::can_withdraw( + asset_id.into(), + who, + converted_fee, + ); + if !matches!(can_withdraw, WithdrawConsequence::Success) { + return Err(InvalidTransaction::Payment.into()) + } + >::withdraw(asset_id.into(), who, converted_fee) + .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment)) + } + + /// Hand the fee and the tip over to the `[HandleCredit]` implementation. + /// Since the predicted fee might have been too high, parts of the fee may be refunded. + /// + /// Note: The `corrected_fee` already includes the `tip`. + fn correct_and_deposit_fee( + who: &T::AccountId, + _dispatch_info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, + corrected_fee: Self::Balance, + _tip: Self::Balance, + paid: Self::LiquidityInfo, + ) -> Result<(), TransactionValidityError> { + let min_converted_fee = if corrected_fee.is_zero() { Zero::zero() } else { One::one() }; + // Convert the corrected fee into the asset used for payment. + let converted_fee = CON::to_asset_balance(corrected_fee, paid.asset().into()) + .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })? + .max(min_converted_fee); + // Calculate how much refund we should return. + let (final_fee, refund) = paid.split(converted_fee); + // Refund to the account that paid the fees. If this fails, the account might have dropped + // below the existential balance. In that case we don't refund anything. + let _ = >::resolve(who, refund); + // Handle the final fee, e.g. by transferring to the block author or burning. + HC::handle_credit(final_fee); + Ok(()) + } +} diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs new file mode 100644 index 0000000000000..bd5dc57239a28 --- /dev/null +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -0,0 +1,748 @@ +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate as pallet_asset_tx_payment; + +use frame_support::{ + assert_ok, + pallet_prelude::*, + parameter_types, + traits::{fungibles::Mutate, FindAuthor}, + weights::{ + DispatchClass, DispatchInfo, PostDispatchInfo, Weight, WeightToFeeCoefficient, + WeightToFeeCoefficients, WeightToFeePolynomial, + }, + ConsensusEngineId, +}; +use frame_system as system; +use frame_system::EnsureRoot; +use pallet_balances::Call as BalancesCall; +use pallet_transaction_payment::CurrencyAdapter; +use smallvec::smallvec; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, ConvertInto, IdentityLookup, StaticLookup}, + Perbill, +}; +use std::cell::RefCell; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; +type Balance = u64; +type AccountId = u64; + +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + Assets: pallet_assets::{Pallet, Call, Storage, Event}, + Authorship: pallet_authorship::{Pallet, Call, Storage}, + AssetTxPayment: pallet_asset_tx_payment::{Pallet}, + } +); + +const CALL: &::Call = + &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + +thread_local! { + static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(0); +} + +pub struct BlockWeights; +impl Get for BlockWeights { + fn get() -> frame_system::limits::BlockWeights { + frame_system::limits::BlockWeights::builder() + .base_block(0) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into(); + }) + .for_class(DispatchClass::non_mandatory(), |weights| { + weights.max_total = 1024.into(); + }) + .build_or_panic() + } +} + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub static TransactionByteFee: u64 = 1; + pub static WeightToFee: u64 = 1; +} + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = BlockWeights; + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = Call; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 10; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxLocks = (); + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; +} + +impl WeightToFeePolynomial for WeightToFee { + type Balance = u64; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: WEIGHT_TO_FEE.with(|v| *v.borrow()), + negative: false, + }] + } +} + +parameter_types! { + pub const OperationalFeeMultiplier: u8 = 5; +} + +impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = CurrencyAdapter; + type TransactionByteFee = TransactionByteFee; + type WeightToFee = WeightToFee; + type FeeMultiplierUpdate = (); + type OperationalFeeMultiplier = OperationalFeeMultiplier; +} + +parameter_types! { + pub const AssetDeposit: u64 = 2; + pub const MetadataDeposit: u64 = 0; + pub const StringLimit: u32 = 20; +} + +impl pallet_assets::Config for Runtime { + type Event = Event; + type Balance = Balance; + type AssetId = u32; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDeposit; + type MetadataDepositPerByte = MetadataDeposit; + type ApprovalDeposit = MetadataDeposit; + type StringLimit = StringLimit; + type Freezer = (); + type Extra = (); + type WeightInfo = (); +} + +pub struct HardcodedAuthor; +const BLOCK_AUTHOR: AccountId = 1234; +impl FindAuthor for HardcodedAuthor { + fn find_author<'a, I>(_: I) -> Option + where + I: 'a + IntoIterator, + { + Some(BLOCK_AUTHOR) + } +} + +impl pallet_authorship::Config for Runtime { + type FindAuthor = HardcodedAuthor; + type UncleGenerations = (); + type FilterUncle = (); + type EventHandler = (); +} + +pub struct CreditToBlockAuthor; +impl HandleCredit for CreditToBlockAuthor { + fn handle_credit(credit: CreditOf) { + let author = pallet_authorship::Pallet::::author(); + // What to do in case paying the author fails (e.g. because `fee < min_balance`) + // default: drop the result which will trigger the `OnDrop` of the imbalance. + let _ = >::resolve(&author, credit); + } +} + +impl Config for Runtime { + type Fungibles = Assets; + type OnChargeAssetTransaction = FungiblesAdapter< + pallet_assets::BalanceToAssetBalance, + CreditToBlockAuthor, + >; +} + +pub struct ExtBuilder { + balance_factor: u64, + base_weight: u64, + byte_fee: u64, + weight_to_fee: u64, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { balance_factor: 1, base_weight: 0, byte_fee: 1, weight_to_fee: 1 } + } +} + +impl ExtBuilder { + pub fn base_weight(mut self, base_weight: u64) -> Self { + self.base_weight = base_weight; + self + } + pub fn balance_factor(mut self, factor: u64) -> Self { + self.balance_factor = factor; + self + } + fn set_constants(&self) { + EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); + TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee); + WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); + } + pub fn build(self) -> sp_io::TestExternalities { + self.set_constants(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { + balances: if self.balance_factor > 0 { + vec![ + (1, 10 * self.balance_factor), + (2, 20 * self.balance_factor), + (3, 30 * self.balance_factor), + (4, 40 * self.balance_factor), + (5, 50 * self.balance_factor), + (6, 60 * self.balance_factor), + ] + } else { + vec![] + }, + } + .assimilate_storage(&mut t) + .unwrap(); + t.into() + } +} + +/// create a transaction info struct from weight. Handy to avoid building the whole struct. +pub fn info_from_weight(w: Weight) -> DispatchInfo { + // pays_fee: Pays::Yes -- class: DispatchClass::Normal + DispatchInfo { weight: w, ..Default::default() } +} + +fn post_info_from_weight(w: Weight) -> PostDispatchInfo { + PostDispatchInfo { actual_weight: Some(w), pays_fee: Default::default() } +} + +fn info_from_pays(p: Pays) -> DispatchInfo { + DispatchInfo { pays_fee: p, ..Default::default() } +} + +fn post_info_from_pays(p: Pays) -> PostDispatchInfo { + PostDispatchInfo { actual_weight: None, pays_fee: p } +} + +fn default_post_info() -> PostDispatchInfo { + PostDispatchInfo { actual_weight: None, pays_fee: Default::default() } +} + +#[test] +fn transaction_payment_in_native_possible() { + let balance_factor = 100; + ExtBuilder::default() + .balance_factor(balance_factor) + .base_weight(5) + .build() + .execute_with(|| { + let len = 10; + let pre = ChargeAssetTxPayment::::from(0, None) + .pre_dispatch(&1, CALL, &info_from_weight(5), len) + .unwrap(); + let initial_balance = 10 * balance_factor; + assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); + + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + pre, + &info_from_weight(5), + &default_post_info(), + len, + &Ok(()) + )); + assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); + + let pre = ChargeAssetTxPayment::::from(5 /* tipped */, None) + .pre_dispatch(&2, CALL, &info_from_weight(100), len) + .unwrap(); + let initial_balance_for_2 = 20 * balance_factor; + assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5); + + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + pre, + &info_from_weight(100), + &post_info_from_weight(50), + len, + &Ok(()) + )); + assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5); + }); +} + +#[test] +fn transaction_payment_in_asset_possible() { + let base_weight = 5; + let balance_factor = 100; + ExtBuilder::default() + .balance_factor(balance_factor) + .base_weight(base_weight) + .build() + .execute_with(|| { + // create the asset + let asset_id = 1; + let min_balance = 2; + assert_ok!(Assets::force_create( + Origin::root(), + asset_id, + 42, /* owner */ + true, /* is_sufficient */ + min_balance + )); + + // mint into the caller account + let caller = 1; + let beneficiary = ::Lookup::unlookup(caller); + let balance = 100; + assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, caller), balance); + let weight = 5; + let len = 10; + // we convert the from weight to fee based on the ratio between asset min balance and + // existential deposit + let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .unwrap(); + // assert that native balance is not used + assert_eq!(Balances::free_balance(caller), 10 * balance_factor); + // check that fee was charged in the given asset + assert_eq!(Assets::balance(asset_id, caller), balance - fee); + assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); + + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + pre, + &info_from_weight(weight), + &default_post_info(), + len, + &Ok(()) + )); + assert_eq!(Assets::balance(asset_id, caller), balance - fee); + // check that the block author gets rewarded + assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), fee); + }); +} + +#[test] +fn transaction_payment_without_fee() { + let base_weight = 5; + let balance_factor = 100; + ExtBuilder::default() + .balance_factor(balance_factor) + .base_weight(base_weight) + .build() + .execute_with(|| { + // create the asset + let asset_id = 1; + let min_balance = 2; + assert_ok!(Assets::force_create( + Origin::root(), + asset_id, + 42, /* owner */ + true, /* is_sufficient */ + min_balance + )); + + // mint into the caller account + let caller = 1; + let beneficiary = ::Lookup::unlookup(caller); + let balance = 100; + assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, caller), balance); + let weight = 5; + let len = 10; + // we convert the from weight to fee based on the ratio between asset min balance and + // existential deposit + let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .unwrap(); + // assert that native balance is not used + assert_eq!(Balances::free_balance(caller), 10 * balance_factor); + // check that fee was charged in the given asset + assert_eq!(Assets::balance(asset_id, caller), balance - fee); + assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); + + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + pre, + &info_from_weight(weight), + &post_info_from_pays(Pays::No), + len, + &Ok(()) + )); + // caller should be refunded + assert_eq!(Assets::balance(asset_id, caller), balance); + // check that the block author did not get rewarded + assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); + }); +} + +#[test] +fn asset_transaction_payment_with_tip_and_refund() { + let base_weight = 5; + ExtBuilder::default() + .balance_factor(100) + .base_weight(base_weight) + .build() + .execute_with(|| { + // create the asset + let asset_id = 1; + let min_balance = 2; + assert_ok!(Assets::force_create( + Origin::root(), + asset_id, + 42, /* owner */ + true, /* is_sufficient */ + min_balance + )); + + // mint into the caller account + let caller = 2; + let beneficiary = ::Lookup::unlookup(caller); + let balance = 1000; + assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, caller), balance); + let weight = 100; + let tip = 5; + let len = 10; + // we convert the from weight to fee based on the ratio between asset min balance and + // existential deposit + let fee_with_tip = + (base_weight + weight + len as u64 + tip) * min_balance / ExistentialDeposit::get(); + let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .unwrap(); + assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip); + + let final_weight = 50; + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + pre, + &info_from_weight(weight), + &post_info_from_weight(final_weight), + len, + &Ok(()) + )); + let final_fee = + fee_with_tip - (weight - final_weight) * min_balance / ExistentialDeposit::get(); + assert_eq!(Assets::balance(asset_id, caller), balance - (final_fee)); + assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), final_fee); + }); +} + +#[test] +fn payment_from_account_with_only_assets() { + let base_weight = 5; + ExtBuilder::default() + .balance_factor(100) + .base_weight(base_weight) + .build() + .execute_with(|| { + // create the asset + let asset_id = 1; + let min_balance = 2; + assert_ok!(Assets::force_create( + Origin::root(), + asset_id, + 42, /* owner */ + true, /* is_sufficient */ + min_balance + )); + + // mint into the caller account + let caller = 333; + let beneficiary = ::Lookup::unlookup(caller); + let balance = 100; + assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, caller), balance); + // assert that native balance is not necessary + assert_eq!(Balances::free_balance(caller), 0); + let weight = 5; + let len = 10; + // we convert the from weight to fee based on the ratio between asset min balance and + // existential deposit + let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .unwrap(); + assert_eq!(Balances::free_balance(caller), 0); + // check that fee was charged in the given asset + assert_eq!(Assets::balance(asset_id, caller), balance - fee); + + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + pre, + &info_from_weight(weight), + &default_post_info(), + len, + &Ok(()) + )); + assert_eq!(Assets::balance(asset_id, caller), balance - fee); + assert_eq!(Balances::free_balance(caller), 0); + }); +} + +#[test] +fn payment_only_with_existing_sufficient_asset() { + let base_weight = 5; + ExtBuilder::default() + .balance_factor(100) + .base_weight(base_weight) + .build() + .execute_with(|| { + let asset_id = 1; + let caller = 1; + let weight = 5; + let len = 10; + // pre_dispatch fails for non-existent asset + assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .is_err()); + + // create the non-sufficient asset + let min_balance = 2; + assert_ok!(Assets::force_create( + Origin::root(), + asset_id, + 42, /* owner */ + false, /* is_sufficient */ + min_balance + )); + // pre_dispatch fails for non-sufficient asset + assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .is_err()); + }); +} + +#[test] +fn converted_fee_is_never_zero_if_input_fee_is_not() { + let base_weight = 1; + ExtBuilder::default() + .balance_factor(100) + .base_weight(base_weight) + .build() + .execute_with(|| { + // create the asset + let asset_id = 1; + let min_balance = 1; + assert_ok!(Assets::force_create( + Origin::root(), + asset_id, + 42, /* owner */ + true, /* is_sufficient */ + min_balance + )); + + // mint into the caller account + let caller = 333; + let beneficiary = ::Lookup::unlookup(caller); + let balance = 100; + assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, caller), balance); + let weight = 1; + let len = 1; + // we convert the from weight to fee based on the ratio between asset min balance and + // existential deposit + let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); + // naive fee calculation would round down to zero + assert_eq!(fee, 0); + { + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) + .unwrap(); + // `Pays::No` still implies no fees + assert_eq!(Assets::balance(asset_id, caller), balance); + + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + pre, + &info_from_pays(Pays::No), + &post_info_from_pays(Pays::No), + len, + &Ok(()) + )); + assert_eq!(Assets::balance(asset_id, caller), balance); + } + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .unwrap(); + // check that at least one coin was charged in the given asset + assert_eq!(Assets::balance(asset_id, caller), balance - 1); + + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + pre, + &info_from_weight(weight), + &default_post_info(), + len, + &Ok(()) + )); + assert_eq!(Assets::balance(asset_id, caller), balance - 1); + }); +} + +#[test] +fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { + let base_weight = 1; + ExtBuilder::default() + .balance_factor(100) + .base_weight(base_weight) + .build() + .execute_with(|| { + // create the asset + let asset_id = 1; + let min_balance = 100; + assert_ok!(Assets::force_create( + Origin::root(), + asset_id, + 42, /* owner */ + true, /* is_sufficient */ + min_balance + )); + + // mint into the caller account + let caller = 333; + let beneficiary = ::Lookup::unlookup(caller); + let balance = 100; + assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, caller), balance); + let weight = 1; + let len = 1; + // we convert the from weight to fee based on the ratio between asset min balance and + // existential deposit + let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); + // calculated fee is greater than 0 + assert!(fee > 0); + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) + .unwrap(); + // `Pays::No` implies no pre-dispatch fees + assert_eq!(Assets::balance(asset_id, caller), balance); + let (_tip, _who, initial_payment) = ⪯ + let not_paying = match initial_payment { + &InitialPayment::Nothing => true, + _ => false, + }; + assert!(not_paying, "initial payment should be Nothing if we pass Pays::No"); + + // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the + // initial fee) + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + pre, + &info_from_pays(Pays::No), + &post_info_from_pays(Pays::Yes), + len, + &Ok(()) + )); + assert_eq!(Assets::balance(asset_id, caller), balance); + }); +} + +#[test] +fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { + let base_weight = 1; + ExtBuilder::default() + .balance_factor(100) + .base_weight(base_weight) + .build() + .execute_with(|| { + // create the asset + let asset_id = 1; + let min_balance = 100; + assert_ok!(Assets::force_create( + Origin::root(), + asset_id, + 42, /* owner */ + true, /* is_sufficient */ + min_balance + )); + + // mint into the caller account + let caller = 333; + let beneficiary = ::Lookup::unlookup(caller); + let balance = 100; + assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, caller), balance); + let weight = 1; + let len = 1; + let pre = ChargeAssetTxPayment::::pre_dispatch_unsigned( + CALL, + &info_from_weight(weight), + len, + ) + .unwrap(); + + assert_eq!(Assets::balance(asset_id, caller), balance); + let (_tip, _who, initial_payment) = ⪯ + let not_paying = match initial_payment { + &InitialPayment::Nothing => true, + _ => false, + }; + assert!(not_paying, "initial payment is Nothing for unsigned extrinsics"); + + // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the + // initial fee) + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + pre, + &info_from_weight(weight), + &post_info_from_pays(Pays::Yes), + len, + &Ok(()) + )); + assert_eq!(Assets::balance(asset_id, caller), balance); + }); +} From 72b9c36d66e351af9d90cbf8c37e2cf90dd59582 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 19 Nov 2021 10:37:37 +0100 Subject: [PATCH 0252/1472] Don't generate the consensusEngine field in chain specs (#10303) --- client/chain-spec/res/chain_spec.json | 1 - client/chain-spec/res/chain_spec2.json | 1 - client/chain-spec/src/chain_spec.rs | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/client/chain-spec/res/chain_spec.json b/client/chain-spec/res/chain_spec.json index 673f35d507919..c3365a9192f6e 100644 --- a/client/chain-spec/res/chain_spec.json +++ b/client/chain-spec/res/chain_spec.json @@ -19,7 +19,6 @@ ["wss://telemetry.polkadot.io/submit/", 0] ], "protocolId": "fir", - "consensusEngine": null, "genesis": { "raw": [ { diff --git a/client/chain-spec/res/chain_spec2.json b/client/chain-spec/res/chain_spec2.json index 950a7fc827494..00b9d603ae29e 100644 --- a/client/chain-spec/res/chain_spec2.json +++ b/client/chain-spec/res/chain_spec2.json @@ -19,7 +19,6 @@ ["wss://telemetry.polkadot.io/submit/", 0] ], "protocolId": "fir", - "consensusEngine": null, "myProperty": "Test Extension", "genesis": { "raw": [ diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 4aa0aa74630e0..8d8f62a5182cf 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -168,6 +168,7 @@ struct ClientSpec { #[serde(flatten)] extensions: E, // Never used, left only for backward compatibility. + #[serde(default, skip_serializing)] consensus_engine: (), #[serde(skip_serializing)] #[allow(unused)] From 0d0299099b18816fa3de1dbbe9f8f7b7c751994c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 19 Nov 2021 12:33:28 +0100 Subject: [PATCH 0253/1472] Offchain worker: Enable http2 and improve logging (#10305) * Offchain worker: Enable http2 and improve logging Apparently some webpages now return http2 by default and that silently breaks the offchain http extension. The solution to this is to enable the `http2` feature of hyper. Besides that, this pr improves the logging to make it easier to debug such errors. * FMT * Adds http2 test --- Cargo.lock | 22 +++++- client/offchain/Cargo.toml | 4 +- client/offchain/src/api.rs | 50 ++++++++------ client/offchain/src/api/http.rs | 119 ++++++++++++++++++++++++++------ client/offchain/src/lib.rs | 32 ++++++--- 5 files changed, 172 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 32234cc4c93a6..60f8217d69e8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2521,6 +2521,25 @@ dependencies = [ "web-sys", ] +[[package]] +name = "h2" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55" +dependencies = [ + "bytes 1.0.1", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "1.7.1" @@ -2738,6 +2757,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", + "h2", "http", "http-body", "httparse", @@ -8349,7 +8369,6 @@ dependencies = [ "hyper 0.14.14", "hyper-rustls", "lazy_static", - "log 0.4.14", "num_cpus", "once_cell", "parity-scale-codec", @@ -8371,6 +8390,7 @@ dependencies = [ "substrate-test-runtime-client", "threadpool", "tokio", + "tracing", ] [[package]] diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 2a6fdddd7ad36..b92ee7041e5fd 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -19,7 +19,6 @@ hex = "0.4" fnv = "1.0.6" futures = "0.3.16" futures-timer = "3.0.2" -log = "0.4.8" num_cpus = "1.10" parking_lot = "0.11.1" rand = "0.7.2" @@ -31,9 +30,10 @@ sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } threadpool = "1.7" -hyper = { version = "0.14.14", features = ["stream"] } +hyper = { version = "0.14.14", features = ["stream", "http2"] } hyper-rustls = "0.22.1" once_cell = "1.8" +tracing = "0.1.29" [dev-dependencies] sc-client-db = { version = "0.10.0-dev", default-features = true, path = "../db" } diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 07136d1815b91..c2830510b015c 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -37,10 +37,11 @@ mod http; mod timestamp; fn unavailable_yet(name: &str) -> R { - log::error!( - target: "sc_offchain", + tracing::error!( + target: super::LOG_TARGET, "The {:?} API is not available for offchain workers yet. Follow \ - https://github.com/paritytech/substrate/issues/1458 for details", name + https://github.com/paritytech/substrate/issues/1458 for details", + name ); Default::default() } @@ -75,9 +76,12 @@ impl Db { impl offchain::DbExternalities for Db { fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) { - log::debug!( - target: "sc_offchain", - "{:?}: Write: {:?} <= {:?}", kind, hex::encode(key), hex::encode(value) + tracing::debug!( + target: "offchain-worker::storage", + ?kind, + key = ?hex::encode(key), + value = ?hex::encode(value), + "Write", ); match kind { StorageKind::PERSISTENT => self.persistent.set(STORAGE_PREFIX, key, value), @@ -86,9 +90,11 @@ impl offchain::DbExternalities for Db { } fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) { - log::debug!( - target: "sc_offchain", - "{:?}: Clear: {:?}", kind, hex::encode(key) + tracing::debug!( + target: "offchain-worker::storage", + ?kind, + key = ?hex::encode(key), + "Clear", ); match kind { StorageKind::PERSISTENT => self.persistent.remove(STORAGE_PREFIX, key), @@ -103,13 +109,13 @@ impl offchain::DbExternalities for Db { old_value: Option<&[u8]>, new_value: &[u8], ) -> bool { - log::debug!( - target: "sc_offchain", - "{:?}: CAS: {:?} <= {:?} vs {:?}", - kind, - hex::encode(key), - hex::encode(new_value), - old_value.as_ref().map(hex::encode), + tracing::debug!( + target: "offchain-worker::storage", + ?kind, + key = ?hex::encode(key), + new_value = ?hex::encode(new_value), + old_value = ?old_value.as_ref().map(hex::encode), + "CAS", ); match kind { StorageKind::PERSISTENT => @@ -123,12 +129,12 @@ impl offchain::DbExternalities for Db { StorageKind::PERSISTENT => self.persistent.get(STORAGE_PREFIX, key), StorageKind::LOCAL => unavailable_yet(LOCAL_DB), }; - log::debug!( - target: "sc_offchain", - "{:?}: Read: {:?} => {:?}", - kind, - hex::encode(key), - result.as_ref().map(hex::encode) + tracing::debug!( + target: "offchain-worker::storage", + ?kind, + key = ?hex::encode(key), + result = ?result.as_ref().map(hex::encode), + "Read", ); result } diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index a2975bad16528..632c94b481074 100644 --- a/client/offchain/src/api/http.rs +++ b/client/offchain/src/api/http.rs @@ -33,7 +33,6 @@ use fnv::FnvHashMap; use futures::{channel::mpsc, future, prelude::*}; use hyper::{client, Body, Client as HyperClient}; use hyper_rustls::HttpsConnector; -use log::error; use once_cell::sync::Lazy; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_core::offchain::{HttpError, HttpRequestId, HttpRequestStatus, Timestamp}; @@ -46,6 +45,8 @@ use std::{ task::{Context, Poll}, }; +const LOG_TARGET: &str = "offchain-worker::http"; + /// Wrapper struct used for keeping the hyper_rustls client running. #[derive(Clone)] pub struct SharedClient(Arc, Body>>>); @@ -146,13 +147,24 @@ impl HttpApi { match self.next_id.0.checked_add(1) { Some(new_id) => self.next_id.0 = new_id, None => { - error!("Overflow in offchain worker HTTP request ID assignment"); + tracing::error!( + target: LOG_TARGET, + "Overflow in offchain worker HTTP request ID assignment" + ); return Err(()) }, }; self.requests .insert(new_id, HttpApiRequest::NotDispatched(request, body_sender)); + tracing::error!( + target: LOG_TARGET, + id = %new_id.0, + %method, + %uri, + "Requested started", + ); + Ok(new_id) } @@ -168,11 +180,14 @@ impl HttpApi { _ => return Err(()), }; - let name = hyper::header::HeaderName::try_from(name).map_err(drop)?; - let value = hyper::header::HeaderValue::try_from(value).map_err(drop)?; + let header_name = hyper::header::HeaderName::try_from(name).map_err(drop)?; + let header_value = hyper::header::HeaderValue::try_from(value).map_err(drop)?; // Note that we're always appending headers and never replacing old values. // We assume here that the user knows what they're doing. - request.headers_mut().append(name, value); + request.headers_mut().append(header_name, header_value); + + tracing::debug!(target: LOG_TARGET, id = %request_id.0, %name, %value, "Added header to request"); + Ok(()) } @@ -207,7 +222,7 @@ impl HttpApi { sender.send_data(hyper::body::Bytes::from(chunk.to_owned())), ) .map_err(|_| { - error!("HTTP sender refused data despite being ready"); + tracing::error!(target: "offchain-worker::http", "HTTP sender refused data despite being ready"); HttpError::IoError }) }; @@ -215,6 +230,7 @@ impl HttpApi { loop { request = match request { HttpApiRequest::NotDispatched(request, sender) => { + tracing::debug!(target: LOG_TARGET, id = %request_id.0, "Added new body chunk"); // If the request is not dispatched yet, dispatch it and loop again. let _ = self .to_worker @@ -225,14 +241,20 @@ impl HttpApi { HttpApiRequest::Dispatched(Some(mut sender)) => { if !chunk.is_empty() { match poll_sender(&mut sender) { - Err(HttpError::IoError) => return Err(HttpError::IoError), + Err(HttpError::IoError) => { + tracing::debug!(target: LOG_TARGET, id = %request_id.0, "Encountered io error while trying to add new chunk to body"); + return Err(HttpError::IoError) + }, other => { + tracing::debug!(target: LOG_TARGET, id = %request_id.0, res = ?other, "Added chunk to body"); self.requests .insert(request_id, HttpApiRequest::Dispatched(Some(sender))); return other }, } } else { + tracing::debug!(target: LOG_TARGET, id = %request_id.0, "Finished writing body"); + // Writing an empty body is a hint that we should stop writing. Dropping // the sender. self.requests.insert(request_id, HttpApiRequest::Dispatched(None)); @@ -250,14 +272,20 @@ impl HttpApi { .as_mut() .expect("Can only enter this match branch if Some; qed"), ) { - Err(HttpError::IoError) => return Err(HttpError::IoError), + Err(HttpError::IoError) => { + tracing::debug!(target: LOG_TARGET, id = %request_id.0, "Encountered io error while trying to add new chunk to body"); + return Err(HttpError::IoError) + }, other => { + tracing::debug!(target: LOG_TARGET, id = %request_id.0, res = ?other, "Added chunk to body"); self.requests .insert(request_id, HttpApiRequest::Response(response)); return other }, } } else { + tracing::debug!(target: LOG_TARGET, id = %request_id.0, "Finished writing body"); + // Writing an empty body is a hint that we should stop writing. Dropping // the sender. self.requests.insert( @@ -271,13 +299,18 @@ impl HttpApi { } }, - HttpApiRequest::Fail(_) => - // If the request has already failed, return without putting back the request - // in the list. - return Err(HttpError::IoError), + HttpApiRequest::Fail(error) => { + tracing::debug!(target: LOG_TARGET, id = %request_id.0, ?error, "Request failed"); + + // If the request has already failed, return without putting back the request + // in the list. + return Err(HttpError::IoError) + }, v @ HttpApiRequest::Dispatched(None) | v @ HttpApiRequest::Response(HttpApiRequestRp { sending_body: None, .. }) => { + tracing::debug!(target: LOG_TARGET, id = %request_id.0, "Body sending already finished"); + // We have already finished sending this body. self.requests.insert(request_id, v); return Err(HttpError::Invalid) @@ -350,8 +383,19 @@ impl HttpApi { // Requests in "fail" mode are purged before returning. debug_assert_eq!(output.len(), ids.len()); for n in (0..ids.len()).rev() { - if let HttpRequestStatus::IoError = output[n] { - self.requests.remove(&ids[n]); + match output[n] { + HttpRequestStatus::IoError => { + self.requests.remove(&ids[n]); + }, + HttpRequestStatus::Invalid => { + tracing::debug!(target: LOG_TARGET, id = %ids[n].0, "Unknown request"); + }, + HttpRequestStatus::DeadlineReached => { + tracing::debug!(target: LOG_TARGET, id = %ids[n].0, "Deadline reached"); + }, + HttpRequestStatus::Finished(_) => { + tracing::debug!(target: LOG_TARGET, id = %ids[n].0, "Request finished"); + }, } } return output @@ -388,20 +432,23 @@ impl HttpApi { ); }, None => {}, // can happen if we detected an IO error when sending the body - _ => error!("State mismatch between the API and worker"), + _ => + tracing::error!(target: "offchain-worker::http", "State mismatch between the API and worker"), } }, Some(WorkerToApi::Fail { id, error }) => match self.requests.remove(&id) { Some(HttpApiRequest::Dispatched(_)) => { + tracing::debug!(target: LOG_TARGET, id = %id.0, ?error, "Request failed"); self.requests.insert(id, HttpApiRequest::Fail(error)); }, None => {}, // can happen if we detected an IO error when sending the body - _ => error!("State mismatch between the API and worker"), + _ => + tracing::error!(target: "offchain-worker::http", "State mismatch between the API and worker"), }, None => { - error!("Worker has crashed"); + tracing::error!(target: "offchain-worker::http", "Worker has crashed"); return ids.iter().map(|_| HttpRequestStatus::IoError).collect() }, } @@ -474,7 +521,7 @@ impl HttpApi { }, Err(err) => { // This code should never be reached unless there's a logic error somewhere. - error!("Failed to read from current read chunk: {:?}", err); + tracing::error!(target: "offchain-worker::http", "Failed to read from current read chunk: {:?}", err); return Err(HttpError::IoError) }, } @@ -719,7 +766,10 @@ mod tests { // Returns an `HttpApi` whose worker is ran in the background, and a `SocketAddr` to an HTTP // server that runs in the background as well. macro_rules! build_api_server { - () => {{ + () => { + build_api_server!(hyper::Response::new(hyper::Body::from("Hello World!"))) + }; + ( $response:expr ) => {{ let hyper_client = SHARED_CLIENT.clone(); let (api, worker) = http(hyper_client.clone()); @@ -736,9 +786,7 @@ mod tests { // otherwise the tests are flaky. let _ = req.into_body().collect::>().await; - Ok::<_, Infallible>(hyper::Response::new(hyper::Body::from( - "Hello World!", - ))) + Ok::<_, Infallible>($response) }, )) }), @@ -776,6 +824,33 @@ mod tests { assert_eq!(&buf[..n], b"Hello World!"); } + #[test] + fn basic_http2_localhost() { + let deadline = timestamp::now().add(Duration::from_millis(10_000)); + + // Performs an HTTP query to a background HTTP server. + + let (mut api, addr) = build_api_server!(hyper::Response::builder() + .version(hyper::Version::HTTP_2) + .body(hyper::Body::from("Hello World!")) + .unwrap()); + + let id = api.request_start("POST", &format!("http://{}", addr)).unwrap(); + api.request_write_body(id, &[], Some(deadline)).unwrap(); + + match api.response_wait(&[id], Some(deadline))[0] { + HttpRequestStatus::Finished(200) => {}, + v => panic!("Connecting to localhost failed: {:?}", v), + } + + let headers = api.response_headers(id); + assert!(headers.iter().any(|(h, _)| h.eq_ignore_ascii_case(b"Date"))); + + let mut buf = vec![0; 2048]; + let n = api.response_read_body(id, &mut buf, Some(deadline)).unwrap(); + assert_eq!(&buf[..n], b"Hello World!"); + } + #[test] fn request_start_invalid_call() { let (mut api, addr) = build_api_server!(); diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 2de24e10d927d..f9230a1552e1e 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -41,7 +41,6 @@ use futures::{ future::{ready, Future}, prelude::*, }; -use log::{debug, warn}; use parking_lot::Mutex; use sc_network::{ExHashT, NetworkService, NetworkStateInfo, PeerId}; use sp_api::{ApiExt, ProvideRuntimeApi}; @@ -57,6 +56,8 @@ mod api; pub use api::Db as OffchainDb; pub use sp_offchain::{OffchainWorkerApi, STORAGE_PREFIX}; +const LOG_TARGET: &str = "offchain-worker"; + /// NetworkProvider provides [`OffchainWorkers`] with all necessary hooks into the /// underlying Substrate networking. pub trait NetworkProvider: NetworkStateInfo { @@ -149,15 +150,25 @@ where err => { let help = "Consider turning off offchain workers if they are not part of your runtime."; - log::error!("Unsupported Offchain Worker API version: {:?}. {}.", err, help); + tracing::error!( + target: LOG_TARGET, + "Unsupported Offchain Worker API version: {:?}. {}.", + err, + help + ); 0 }, }; - debug!("Checking offchain workers at {:?}: version:{}", at, version); + tracing::debug!( + target: LOG_TARGET, + "Checking offchain workers at {:?}: version:{}", + at, + version + ); let process = (version > 0).then(|| { let (api, runner) = api::AsyncApi::new(network_provider, is_validator, self.shared_http_client.clone()); - debug!("Spawning offchain workers at {:?}", at); + tracing::debug!(target: LOG_TARGET, "Spawning offchain workers at {:?}", at); let header = header.clone(); let client = self.client.clone(); @@ -167,7 +178,7 @@ where self.spawn_worker(move || { let runtime = client.runtime_api(); let api = Box::new(api); - debug!("Running offchain workers at {:?}", at); + tracing::debug!(target: LOG_TARGET, "Running offchain workers at {:?}", at); let context = ExecutionContext::OffchainCall(Some((api, capabilities))); let run = if version == 2 { @@ -181,7 +192,12 @@ where ) }; if let Err(e) = run { - log::error!("Error running offchain workers at {:?}: {:?}", at, e); + tracing::error!( + target: LOG_TARGET, + "Error running offchain workers at {:?}: {:?}", + at, + e + ); } }); @@ -232,8 +248,8 @@ pub async fn notification_future( .boxed(), ); } else { - log::debug!( - target: "sc_offchain", + tracing::debug!( + target: LOG_TARGET, "Skipping offchain workers for non-canon block: {:?}", n.header, ) From 69e384bae9f6189089d2136edb560644964b8788 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Nov 2021 12:36:09 +0100 Subject: [PATCH 0254/1472] Bump libsecp256k1 from 0.6.0 to 0.7.0 (#10214) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump libsecp256k1 from 0.6.0 to 0.7.0 Bumps [libsecp256k1](https://github.com/paritytech/libsecp256k1) from 0.6.0 to 0.7.0. - [Release notes](https://github.com/paritytech/libsecp256k1/releases) - [Changelog](https://github.com/paritytech/libsecp256k1/blob/master/CHANGELOG.md) - [Commits](https://github.com/paritytech/libsecp256k1/commits) --- updated-dependencies: - dependency-name: libsecp256k1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Fix pallet_contracts for new libsecp256k1 version Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Alexander Theißen --- Cargo.lock | 42 ++++++++++-------------- client/executor/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 8 ++--- frame/contracts/src/benchmarking/code.rs | 14 ++++---- primitives/core/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- 6 files changed, 31 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60f8217d69e8a..e9798d4c42054 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3843,25 +3843,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "libsecp256k1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" -dependencies = [ - "arrayref", - "base64 0.12.3", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core 0.2.2", - "libsecp256k1-gen-ecmult 0.2.1", - "libsecp256k1-gen-genmult 0.2.1", - "rand 0.7.3", - "serde", - "sha2 0.9.8", - "typenum", -] - [[package]] name = "libsecp256k1" version = "0.7.0" @@ -3871,12 +3852,14 @@ dependencies = [ "arrayref", "base64 0.13.0", "digest 0.9.0", + "hmac-drbg", "libsecp256k1-core 0.3.0", "libsecp256k1-gen-ecmult 0.3.0", "libsecp256k1-gen-genmult 0.3.0", "rand 0.8.4", "serde", "sha2 0.9.8", + "typenum", ] [[package]] @@ -5414,7 +5397,7 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", - "libsecp256k1 0.6.0", + "libsecp256k1 0.7.0", "log 0.4.14", "pallet-balances", "pallet-contracts-primitives", @@ -5425,8 +5408,8 @@ dependencies = [ "parity-scale-codec", "pretty_assertions", "pwasm-utils", - "rand 0.7.3", - "rand_pcg 0.2.1", + "rand 0.8.4", + "rand_pcg 0.3.1", "scale-info", "serde", "smallvec 1.7.0", @@ -7233,6 +7216,15 @@ 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.2", +] + [[package]] name = "rand_xorshift" version = "0.1.1" @@ -8068,7 +8060,7 @@ version = "0.10.0-dev" dependencies = [ "hex-literal", "lazy_static", - "libsecp256k1 0.6.0", + "libsecp256k1 0.7.0", "log 0.4.14", "parity-scale-codec", "parking_lot 0.11.1", @@ -9442,7 +9434,7 @@ dependencies = [ "hex-literal", "impl-serde", "lazy_static", - "libsecp256k1 0.6.0", + "libsecp256k1 0.7.0", "log 0.4.14", "merlin", "num-traits", @@ -9562,7 +9554,7 @@ version = "4.0.0-dev" dependencies = [ "futures 0.3.16", "hash-db", - "libsecp256k1 0.6.0", + "libsecp256k1 0.7.0", "log 0.4.14", "parity-scale-codec", "parking_lot 0.11.1", diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 4a8e678105437..ebdcc44ff0d8c 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -32,7 +32,7 @@ sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } parking_lot = "0.11.1" log = "0.4.8" -libsecp256k1 = "0.6" +libsecp256k1 = "0.7" sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } [dev-dependencies] diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index dec33768a0426..6639d939e1796 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -28,9 +28,9 @@ smallvec = { version = "1", default-features = false, features = [ wasmi-validation = { version = "0.4", default-features = false } # Only used in benchmarking to generate random contract code -libsecp256k1 = { version = "0.6.0", optional = true, default-features = false, features = ["hmac", "static-context"] } -rand = { version = "0.7.3", optional = true, default-features = false } -rand_pcg = { version = "0.2", optional = true } +libsecp256k1 = { version = "0.7", optional = true, default-features = false, features = ["hmac", "static-context"] } +rand = { version = "0.8", optional = true, default-features = false } +rand_pcg = { version = "0.3", optional = true } # Substrate Dependencies frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } @@ -47,7 +47,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primit [dev-dependencies] assert_matches = "1" hex-literal = "0.3" -pretty_assertions = "1.0.0" +pretty_assertions = "1" wat = "1" # Substrate Dependencies diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 98f52f4719a61..5dac8a84ace8a 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -495,11 +495,11 @@ pub mod body { vec![Instruction::I32Const(current as i32)] }, DynInstr::RandomUnaligned(low, high) => { - let unaligned = rng.gen_range(*low, *high) | 1; + let unaligned = rng.gen_range(*low..*high) | 1; vec![Instruction::I32Const(unaligned as i32)] }, DynInstr::RandomI32(low, high) => { - vec![Instruction::I32Const(rng.gen_range(*low, *high))] + vec![Instruction::I32Const(rng.gen_range(*low..*high))] }, DynInstr::RandomI32Repeated(num) => (&mut rng) .sample_iter(Standard) @@ -512,19 +512,19 @@ pub mod body { .map(|val| Instruction::I64Const(val)) .collect(), DynInstr::RandomGetLocal(low, high) => { - vec![Instruction::GetLocal(rng.gen_range(*low, *high))] + vec![Instruction::GetLocal(rng.gen_range(*low..*high))] }, DynInstr::RandomSetLocal(low, high) => { - vec![Instruction::SetLocal(rng.gen_range(*low, *high))] + vec![Instruction::SetLocal(rng.gen_range(*low..*high))] }, DynInstr::RandomTeeLocal(low, high) => { - vec![Instruction::TeeLocal(rng.gen_range(*low, *high))] + vec![Instruction::TeeLocal(rng.gen_range(*low..*high))] }, DynInstr::RandomGetGlobal(low, high) => { - vec![Instruction::GetGlobal(rng.gen_range(*low, *high))] + vec![Instruction::GetGlobal(rng.gen_range(*low..*high))] }, DynInstr::RandomSetGlobal(low, high) => { - vec![Instruction::SetGlobal(rng.gen_range(*low, *high))] + vec![Instruction::SetGlobal(rng.gen_range(*low..*high))] }, }) .chain(sp_std::iter::once(Instruction::End)) diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index dc8904f33e0c1..61451e10ecf2f 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -65,7 +65,7 @@ schnorrkel = { version = "0.9.1", features = [ sha2 = { version = "0.9.8", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } twox-hash = { version = "1.6.1", default-features = false, optional = true } -libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"], optional = true } +libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", "static-context"], optional = true } sp-core-hashing = { version = "4.0.0-dev", path = "./hashing", default-features = false, optional = true } merlin = { version = "2.0", default-features = false, optional = true } ss58-registry = { version = "1.5.0", default-features = false } diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 2d7c50bdc25e4..2e0982a6e5f13 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -20,7 +20,7 @@ hash-db = { version = "0.15.2", default-features = false } sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } sp-keystore = { version = "0.10.0-dev", default-features = false, optional = true, path = "../keystore" } sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } -libsecp256k1 = { version = "0.6", optional = true } +libsecp256k1 = { version = "0.7", optional = true } sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../state-machine" } sp-wasm-interface = { version = "4.0.0-dev", path = "../wasm-interface", default-features = false } sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" } From cdcf872c3791d148dc67b4df2dff168c9008ca76 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Fri, 19 Nov 2021 16:14:21 +0100 Subject: [PATCH 0255/1472] Add prometheus metrics for block authorship (#10316) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add prom metric to basic authorship * Add proposer_block_proposal_time * +nightly-2021-10-29 fmt * Use saturating_duration_since, not elasped * Update client/basic-authorship/src/basic_authorship.rs Co-authored-by: Bastian Köcher * Update client/basic-authorship/src/basic_authorship.rs Co-authored-by: Bastian Köcher * +nightly-2021-10-29 fmt Co-authored-by: Bastian Köcher --- .../basic-authorship/src/basic_authorship.rs | 23 ++++++++++++++++++- client/proposer-metrics/src/lib.rs | 16 +++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 0fd3932807a17..70633925c5ba6 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -346,10 +346,23 @@ where block_size_limit: Option, ) -> Result, PR::Proof>, sp_blockchain::Error> { + let propose_with_start = time::Instant::now(); let mut block_builder = self.client.new_block_at(&self.parent_id, inherent_digests, PR::ENABLED)?; - for inherent in block_builder.create_inherents(inherent_data)? { + let create_inherents_start = time::Instant::now(); + let inherents = block_builder.create_inherents(inherent_data)?; + let create_inherents_end = time::Instant::now(); + + self.metrics.report(|metrics| { + metrics.create_inherents_time.observe( + create_inherents_end + .saturating_duration_since(create_inherents_start) + .as_secs_f64(), + ); + }); + + for inherent in inherents { match block_builder.push(inherent) { Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() => { warn!("⚠️ Dropping non-mandatory inherent from overweight block.") @@ -529,6 +542,14 @@ where let proof = PR::into_proof(proof).map_err(|e| sp_blockchain::Error::Application(Box::new(e)))?; + + let propose_with_end = time::Instant::now(); + self.metrics.report(|metrics| { + metrics.create_block_proposal_time.observe( + propose_with_end.saturating_duration_since(propose_with_start).as_secs_f64(), + ); + }); + Ok(Proposal { block, proof, storage_changes }) } } diff --git a/client/proposer-metrics/src/lib.rs b/client/proposer-metrics/src/lib.rs index da29fb2951995..452a796b73920 100644 --- a/client/proposer-metrics/src/lib.rs +++ b/client/proposer-metrics/src/lib.rs @@ -47,6 +47,8 @@ impl MetricsLink { pub struct Metrics { pub block_constructed: Histogram, pub number_of_transactions: Gauge, + pub create_inherents_time: Histogram, + pub create_block_proposal_time: Histogram, } impl Metrics { @@ -66,6 +68,20 @@ impl Metrics { )?, registry, )?, + create_inherents_time: register( + Histogram::with_opts(HistogramOpts::new( + "proposer_create_inherents_time", + "Histogram of time taken to execute create inherents", + ))?, + registry, + )?, + create_block_proposal_time: register( + Histogram::with_opts(HistogramOpts::new( + "proposer_block_proposal_time", + "Histogram of time taken to construct a block and prepare it for proposal", + ))?, + registry, + )?, }) } } From 3cf5449fd2143d07ff2ee24eb3b3c40ecf1e57ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 19 Nov 2021 21:30:37 +0100 Subject: [PATCH 0256/1472] Taskmanager: Remove `clean_shutdown` (#10314) There is no reason for this function, tokio already blocks automatically until all tasks are ended. Another reason to remove this feature is `mpsc_background_tasks` unbounded channel. Recently this channel was reporting too many unprocessed elements. We assume that this was a result of a lot of very shot lived tasks that somehow flooded this channel. --- client/cli/src/runner.rs | 3 +- client/service/src/task_manager/mod.rs | 83 +----- client/service/src/task_manager/tests.rs | 316 +++++++++-------------- test-utils/test-runner/src/node.rs | 2 - 4 files changed, 140 insertions(+), 264 deletions(-) diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index 6f03e02a12d05..640b87584d4b6 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -98,7 +98,7 @@ where pin_mut!(f); tokio_runtime.block_on(main(f))?; - tokio_runtime.block_on(task_manager.clean_shutdown()); + drop(task_manager); Ok(()) } @@ -154,7 +154,6 @@ impl Runner { self.print_node_infos(); let mut task_manager = self.tokio_runtime.block_on(initialize(self.config))?; let res = self.tokio_runtime.block_on(main(task_manager.future().fuse())); - self.tokio_runtime.block_on(task_manager.clean_shutdown()); Ok(res?) } diff --git a/client/service/src/task_manager/mod.rs b/client/service/src/task_manager/mod.rs index 25d3ecd7d5c3c..342ea6627be68 100644 --- a/client/service/src/task_manager/mod.rs +++ b/client/service/src/task_manager/mod.rs @@ -21,17 +21,16 @@ use crate::{config::TaskType, Error}; use exit_future::Signal; use futures::{ - future::{join_all, pending, select, try_join_all, BoxFuture, Either}, + future::{pending, select, try_join_all, BoxFuture, Either}, Future, FutureExt, StreamExt, }; -use log::debug; use prometheus_endpoint::{ exponential_buckets, register, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry, U64, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use std::{panic, pin::Pin, result::Result}; -use tokio::{runtime::Handle, task::JoinHandle}; +use tokio::runtime::Handle; use tracing_futures::Instrument; mod prometheus_future; @@ -73,7 +72,6 @@ pub struct SpawnTaskHandle { on_exit: exit_future::Exit, tokio_handle: Handle, metrics: Option, - task_notifier: TracingUnboundedSender>, } impl SpawnTaskHandle { @@ -113,11 +111,6 @@ impl SpawnTaskHandle { task: impl Future + Send + 'static, task_type: TaskType, ) { - if self.task_notifier.is_closed() { - debug!("Attempt to spawn a new task has been prevented: {}", name); - return - } - let on_exit = self.on_exit.clone(); let metrics = self.metrics.clone(); @@ -169,17 +162,17 @@ impl SpawnTaskHandle { } .in_current_span(); - let join_handle = match task_type { - TaskType::Async => self.tokio_handle.spawn(future), + match task_type { + TaskType::Async => { + self.tokio_handle.spawn(future); + }, TaskType::Blocking => { let handle = self.tokio_handle.clone(); self.tokio_handle.spawn_blocking(move || { handle.block_on(future); - }) + }); }, - }; - - let _ = self.task_notifier.unbounded_send(join_handle); + } } } @@ -288,8 +281,8 @@ pub struct TaskManager { /// A future that resolves when the service has exited, this is useful to /// make sure any internally spawned futures stop when the service does. on_exit: exit_future::Exit, - /// A signal that makes the exit future above resolve, fired on service drop. - signal: Option, + /// A signal that makes the exit future above resolve, fired on drop. + _signal: Signal, /// Tokio runtime handle that is used to spawn futures. tokio_handle: Handle, /// Prometheus metric where to report the polling times. @@ -301,10 +294,6 @@ pub struct TaskManager { essential_failed_rx: TracingUnboundedReceiver<()>, /// Things to keep alive until the task manager is dropped. keep_alive: Box, - /// A sender to a stream of background tasks. This is used for the completion future. - task_notifier: TracingUnboundedSender>, - /// This future will complete when all the tasks are joined and the stream is closed. - completion_future: JoinHandle<()>, /// A list of other `TaskManager`'s to terminate and gracefully shutdown when the parent /// terminates and gracefully shutdown. Also ends the parent `future()` if a child's essential /// task fails. @@ -325,25 +314,14 @@ impl TaskManager { let metrics = prometheus_registry.map(Metrics::register).transpose()?; - let (task_notifier, background_tasks) = tracing_unbounded("mpsc_background_tasks"); - // NOTE: for_each_concurrent will await on all the JoinHandle futures at the same time. It - // is possible to limit this but it's actually better for the memory foot print to await - // them all to not accumulate anything on that stream. - let completion_future = - tokio_handle.spawn(background_tasks.for_each_concurrent(None, |x| async move { - let _ = x.await; - })); - Ok(Self { on_exit, - signal: Some(signal), + _signal: signal, tokio_handle, metrics, essential_failed_tx, essential_failed_rx, keep_alive: Box::new(()), - task_notifier, - completion_future, children: Vec::new(), }) } @@ -354,7 +332,6 @@ impl TaskManager { on_exit: self.on_exit.clone(), tokio_handle: self.tokio_handle.clone(), metrics: self.metrics.clone(), - task_notifier: self.task_notifier.clone(), } } @@ -363,36 +340,12 @@ impl TaskManager { SpawnEssentialTaskHandle::new(self.essential_failed_tx.clone(), self.spawn_handle()) } - /// Send the signal for termination, prevent new tasks to be created, await for all the existing - /// tasks to be finished and drop the object. You can consider this as an async drop. - /// - /// It's always better to call and await this function before exiting the process as background - /// tasks may be running in the background. If the process exit and the background tasks are not - /// cancelled, this will lead to objects not getting dropped properly. - /// - /// This is an issue in some cases as some of our dependencies do require that we drop all the - /// objects properly otherwise it triggers a SIGABRT on exit. - pub fn clean_shutdown(mut self) -> Pin + Send>> { - self.terminate(); - let children_shutdowns = self.children.into_iter().map(|x| x.clean_shutdown()); - let keep_alive = self.keep_alive; - let completion_future = self.completion_future; - - Box::pin(async move { - join_all(children_shutdowns).await; - let _ = completion_future.await; - - let _ = keep_alive; - }) - } - /// Return a future that will end with success if the signal to terminate was sent /// (`self.terminate()`) or with an error if an essential task fails. /// /// # Warning /// - /// This function will not wait until the end of the remaining task. You must call and await - /// `clean_shutdown()` after this. + /// This function will not wait until the end of the remaining task. pub fn future<'a>( &'a mut self, ) -> Pin> + Send + 'a>> { @@ -417,18 +370,6 @@ impl TaskManager { }) } - /// Signal to terminate all the running tasks. - pub fn terminate(&mut self) { - if let Some(signal) = self.signal.take() { - let _ = signal.fire(); - // NOTE: this will prevent new tasks to be spawned - self.task_notifier.close_channel(); - for child in self.children.iter_mut() { - child.terminate(); - } - } - } - /// Set what the task manager should keep alive, can be called multiple times. pub fn keep_alive(&mut self, to_keep_alive: T) { // allows this fn to safely called multiple times. diff --git a/client/service/src/task_manager/tests.rs b/client/service/src/task_manager/tests.rs index 75092ff2ae62e..f14023f34f6bd 100644 --- a/client/service/src/task_manager/tests.rs +++ b/client/service/src/task_manager/tests.rs @@ -90,225 +90,163 @@ fn new_task_manager(tokio_handle: tokio::runtime::Handle) -> TaskManager { #[test] fn ensure_tasks_are_awaited_on_shutdown() { - let runtime = tokio::runtime::Runtime::new().unwrap(); - let handle = runtime.handle().clone(); - - let task_manager = new_task_manager(handle); - let spawn_handle = task_manager.spawn_handle(); let drop_tester = DropTester::new(); - spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); - spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); - assert_eq!(drop_tester, 2); - // allow the tasks to even start - runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); - assert_eq!(drop_tester, 2); - runtime.block_on(task_manager.clean_shutdown()); + { + let runtime = tokio::runtime::Runtime::new().unwrap(); + let handle = runtime.handle().clone(); + + let task_manager = new_task_manager(handle); + let spawn_handle = task_manager.spawn_handle(); + spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); + spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); + assert_eq!(drop_tester, 2); + // allow the tasks to even start + runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); + assert_eq!(drop_tester, 2); + } drop_tester.wait_on_drop(); } #[test] fn ensure_keep_alive_during_shutdown() { - let runtime = tokio::runtime::Runtime::new().unwrap(); - let handle = runtime.handle().clone(); - - let mut task_manager = new_task_manager(handle); - let spawn_handle = task_manager.spawn_handle(); let drop_tester = DropTester::new(); - task_manager.keep_alive(drop_tester.new_ref()); - spawn_handle.spawn("task1", None, run_background_task(())); - assert_eq!(drop_tester, 1); - // allow the tasks to even start - runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); - assert_eq!(drop_tester, 1); - runtime.block_on(task_manager.clean_shutdown()); + { + let runtime = tokio::runtime::Runtime::new().unwrap(); + let handle = runtime.handle().clone(); + + let mut task_manager = new_task_manager(handle); + let spawn_handle = task_manager.spawn_handle(); + task_manager.keep_alive(drop_tester.new_ref()); + spawn_handle.spawn("task1", None, run_background_task(())); + assert_eq!(drop_tester, 1); + // allow the tasks to even start + runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); + assert_eq!(drop_tester, 1); + } drop_tester.wait_on_drop(); } #[test] fn ensure_blocking_futures_are_awaited_on_shutdown() { - let runtime = tokio::runtime::Runtime::new().unwrap(); - let handle = runtime.handle().clone(); - - let task_manager = new_task_manager(handle); - let spawn_handle = task_manager.spawn_handle(); - let drop_tester = DropTester::new(); - spawn_handle.spawn( - "task1", - None, - run_background_task_blocking(Duration::from_secs(3), drop_tester.new_ref()), - ); - spawn_handle.spawn( - "task2", - None, - run_background_task_blocking(Duration::from_secs(3), drop_tester.new_ref()), - ); - assert_eq!(drop_tester, 2); - // allow the tasks to even start - runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); - assert_eq!(drop_tester, 2); - runtime.block_on(task_manager.clean_shutdown()); - assert_eq!(drop_tester, 0); -} - -#[test] -fn ensure_no_task_can_be_spawn_after_terminate() { - let runtime = tokio::runtime::Runtime::new().unwrap(); - let handle = runtime.handle().clone(); - - let mut task_manager = new_task_manager(handle); - let spawn_handle = task_manager.spawn_handle(); - let drop_tester = DropTester::new(); - spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); - spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); - assert_eq!(drop_tester, 2); - // allow the tasks to even start - runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); - assert_eq!(drop_tester, 2); - task_manager.terminate(); - spawn_handle.spawn("task3", None, run_background_task(drop_tester.new_ref())); - runtime.block_on(task_manager.clean_shutdown()); - drop_tester.wait_on_drop(); -} - -#[test] -fn ensure_task_manager_future_ends_when_task_manager_terminated() { - let runtime = tokio::runtime::Runtime::new().unwrap(); - let handle = runtime.handle().clone(); - - let mut task_manager = new_task_manager(handle); - let spawn_handle = task_manager.spawn_handle(); let drop_tester = DropTester::new(); - spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); - spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); - assert_eq!(drop_tester, 2); - // allow the tasks to even start - runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); - assert_eq!(drop_tester, 2); - task_manager.terminate(); - runtime.block_on(task_manager.future()).expect("future has ended without error"); - runtime.block_on(task_manager.clean_shutdown()); + { + let runtime = tokio::runtime::Runtime::new().unwrap(); + let handle = runtime.handle().clone(); + + let task_manager = new_task_manager(handle); + let spawn_handle = task_manager.spawn_handle(); + spawn_handle.spawn( + "task1", + None, + run_background_task_blocking(Duration::from_secs(3), drop_tester.new_ref()), + ); + spawn_handle.spawn( + "task2", + None, + run_background_task_blocking(Duration::from_secs(3), drop_tester.new_ref()), + ); + assert_eq!(drop_tester, 2); + // allow the tasks to even start + runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); + assert_eq!(drop_tester, 2); + } assert_eq!(drop_tester, 0); } #[test] fn ensure_task_manager_future_ends_with_error_when_essential_task_fails() { - let runtime = tokio::runtime::Runtime::new().unwrap(); - let handle = runtime.handle().clone(); - - let mut task_manager = new_task_manager(handle); - let spawn_handle = task_manager.spawn_handle(); - let spawn_essential_handle = task_manager.spawn_essential_handle(); let drop_tester = DropTester::new(); - spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); - spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); - assert_eq!(drop_tester, 2); - // allow the tasks to even start - runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); - assert_eq!(drop_tester, 2); - spawn_essential_handle.spawn("task3", None, async { panic!("task failed") }); - runtime - .block_on(task_manager.future()) - .expect_err("future()'s Result must be Err"); - assert_eq!(drop_tester, 2); - runtime.block_on(task_manager.clean_shutdown()); - drop_tester.wait_on_drop(); -} - -#[test] -fn ensure_children_tasks_ends_when_task_manager_terminated() { - let runtime = tokio::runtime::Runtime::new().unwrap(); - let handle = runtime.handle().clone(); - - let mut task_manager = new_task_manager(handle.clone()); - let child_1 = new_task_manager(handle.clone()); - let spawn_handle_child_1 = child_1.spawn_handle(); - let child_2 = new_task_manager(handle.clone()); - let spawn_handle_child_2 = child_2.spawn_handle(); - task_manager.add_child(child_1); - task_manager.add_child(child_2); - let spawn_handle = task_manager.spawn_handle(); - let drop_tester = DropTester::new(); - spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); - spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); - spawn_handle_child_1.spawn("task3", None, run_background_task(drop_tester.new_ref())); - spawn_handle_child_2.spawn("task4", None, run_background_task(drop_tester.new_ref())); - assert_eq!(drop_tester, 4); - // allow the tasks to even start - runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); - assert_eq!(drop_tester, 4); - task_manager.terminate(); - runtime.block_on(task_manager.future()).expect("future has ended without error"); - runtime.block_on(task_manager.clean_shutdown()); + { + let runtime = tokio::runtime::Runtime::new().unwrap(); + let handle = runtime.handle().clone(); + + let mut task_manager = new_task_manager(handle); + let spawn_handle = task_manager.spawn_handle(); + let spawn_essential_handle = task_manager.spawn_essential_handle(); + spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); + spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); + assert_eq!(drop_tester, 2); + // allow the tasks to even start + runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); + assert_eq!(drop_tester, 2); + spawn_essential_handle.spawn("task3", None, async { panic!("task failed") }); + runtime + .block_on(task_manager.future()) + .expect_err("future()'s Result must be Err"); + assert_eq!(drop_tester, 2); + } drop_tester.wait_on_drop(); } #[test] fn ensure_task_manager_future_ends_with_error_when_childs_essential_task_fails() { - let runtime = tokio::runtime::Runtime::new().unwrap(); - let handle = runtime.handle().clone(); - - let mut task_manager = new_task_manager(handle.clone()); - let child_1 = new_task_manager(handle.clone()); - let spawn_handle_child_1 = child_1.spawn_handle(); - let spawn_essential_handle_child_1 = child_1.spawn_essential_handle(); - let child_2 = new_task_manager(handle.clone()); - let spawn_handle_child_2 = child_2.spawn_handle(); - task_manager.add_child(child_1); - task_manager.add_child(child_2); - let spawn_handle = task_manager.spawn_handle(); let drop_tester = DropTester::new(); - spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); - spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); - spawn_handle_child_1.spawn("task3", None, run_background_task(drop_tester.new_ref())); - spawn_handle_child_2.spawn("task4", None, run_background_task(drop_tester.new_ref())); - assert_eq!(drop_tester, 4); - // allow the tasks to even start - runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); - assert_eq!(drop_tester, 4); - spawn_essential_handle_child_1.spawn("task5", None, async { panic!("task failed") }); - runtime - .block_on(task_manager.future()) - .expect_err("future()'s Result must be Err"); - assert_eq!(drop_tester, 4); - runtime.block_on(task_manager.clean_shutdown()); + { + let runtime = tokio::runtime::Runtime::new().unwrap(); + let handle = runtime.handle().clone(); + + let mut task_manager = new_task_manager(handle.clone()); + let child_1 = new_task_manager(handle.clone()); + let spawn_handle_child_1 = child_1.spawn_handle(); + let spawn_essential_handle_child_1 = child_1.spawn_essential_handle(); + let child_2 = new_task_manager(handle.clone()); + let spawn_handle_child_2 = child_2.spawn_handle(); + task_manager.add_child(child_1); + task_manager.add_child(child_2); + let spawn_handle = task_manager.spawn_handle(); + spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); + spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); + spawn_handle_child_1.spawn("task3", None, run_background_task(drop_tester.new_ref())); + spawn_handle_child_2.spawn("task4", None, run_background_task(drop_tester.new_ref())); + assert_eq!(drop_tester, 4); + // allow the tasks to even start + runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); + assert_eq!(drop_tester, 4); + spawn_essential_handle_child_1.spawn("task5", None, async { panic!("task failed") }); + runtime + .block_on(task_manager.future()) + .expect_err("future()'s Result must be Err"); + assert_eq!(drop_tester, 4); + } drop_tester.wait_on_drop(); } #[test] fn ensure_task_manager_future_continues_when_childs_not_essential_task_fails() { - let runtime = tokio::runtime::Runtime::new().unwrap(); - let handle = runtime.handle().clone(); - - let mut task_manager = new_task_manager(handle.clone()); - let child_1 = new_task_manager(handle.clone()); - let spawn_handle_child_1 = child_1.spawn_handle(); - let child_2 = new_task_manager(handle.clone()); - let spawn_handle_child_2 = child_2.spawn_handle(); - task_manager.add_child(child_1); - task_manager.add_child(child_2); - let spawn_handle = task_manager.spawn_handle(); let drop_tester = DropTester::new(); - spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); - spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); - spawn_handle_child_1.spawn("task3", None, run_background_task(drop_tester.new_ref())); - spawn_handle_child_2.spawn("task4", None, run_background_task(drop_tester.new_ref())); - assert_eq!(drop_tester, 4); - // allow the tasks to even start - runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); - assert_eq!(drop_tester, 4); - spawn_handle_child_1.spawn("task5", None, async { panic!("task failed") }); - runtime.block_on(async { - let t1 = task_manager.future().fuse(); - let t2 = tokio::time::sleep(Duration::from_secs(3)).fuse(); - - pin_mut!(t1, t2); - - select! { - res = t1 => panic!("task should not have stopped: {:?}", res), - _ = t2 => {}, - } - }); - assert_eq!(drop_tester, 4); - runtime.block_on(task_manager.clean_shutdown()); + { + let runtime = tokio::runtime::Runtime::new().unwrap(); + let handle = runtime.handle().clone(); + + let mut task_manager = new_task_manager(handle.clone()); + let child_1 = new_task_manager(handle.clone()); + let spawn_handle_child_1 = child_1.spawn_handle(); + let child_2 = new_task_manager(handle.clone()); + let spawn_handle_child_2 = child_2.spawn_handle(); + task_manager.add_child(child_1); + task_manager.add_child(child_2); + let spawn_handle = task_manager.spawn_handle(); + spawn_handle.spawn("task1", None, run_background_task(drop_tester.new_ref())); + spawn_handle.spawn("task2", None, run_background_task(drop_tester.new_ref())); + spawn_handle_child_1.spawn("task3", None, run_background_task(drop_tester.new_ref())); + spawn_handle_child_2.spawn("task4", None, run_background_task(drop_tester.new_ref())); + assert_eq!(drop_tester, 4); + // allow the tasks to even start + runtime.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await }); + assert_eq!(drop_tester, 4); + spawn_handle_child_1.spawn("task5", None, async { panic!("task failed") }); + runtime.block_on(async { + let t1 = task_manager.future().fuse(); + let t2 = tokio::time::sleep(Duration::from_secs(3)).fuse(); + + pin_mut!(t1, t2); + + select! { + res = t1 => panic!("task should not have stopped: {:?}", res), + _ = t2 => {}, + } + }); + assert_eq!(drop_tester, 4); + } drop_tester.wait_on_drop(); } diff --git a/test-utils/test-runner/src/node.rs b/test-utils/test-runner/src/node.rs index 07259263c5e4d..5fd8e4669c33d 100644 --- a/test-utils/test-runner/src/node.rs +++ b/test-utils/test-runner/src/node.rs @@ -261,8 +261,6 @@ where let signal = tokio::signal::ctrl_c(); futures::pin_mut!(signal); futures::future::select(task, signal).await; - // we don't really care whichever comes first. - task_manager.clean_shutdown().await } } } From 197b8fd3675104a45ad547b2a424a4c70734cba8 Mon Sep 17 00:00:00 2001 From: Doordashcon <90750465+Doordashcon@users.noreply.github.com> Date: Sat, 20 Nov 2021 09:00:43 +0100 Subject: [PATCH 0257/1472] tuple to struct event variants (#10257) * AFNPEV recovery * AFNPEV session * cargo +nightly fmt && cargo fmt * removed redundant comments * update * update & cargo +nightly fmt * update & cargo +nightly fmt * update recovery/src/lib.rs * update session/src/lib.rs --- frame/recovery/src/lib.rs | 54 +++++++++++++++++++++++++-------------- frame/session/src/lib.rs | 6 ++--- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index 522d7008017f3..24090e9000fa4 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -262,22 +262,22 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A recovery process has been set up for an \[account\]. - RecoveryCreated(T::AccountId), + /// A recovery process has been set up for an account. + RecoveryCreated { account: T::AccountId }, /// A recovery process has been initiated for lost account by rescuer account. - /// \[lost, rescuer\] - RecoveryInitiated(T::AccountId, T::AccountId), + RecoveryInitiated { lost_account: T::AccountId, rescuer_account: T::AccountId }, /// A recovery process for lost account by rescuer account has been vouched for by sender. - /// \[lost, rescuer, sender\] - RecoveryVouched(T::AccountId, T::AccountId, T::AccountId), + RecoveryVouched { + lost_account: T::AccountId, + rescuer_account: T::AccountId, + sender: T::AccountId, + }, /// A recovery process for lost account by rescuer account has been closed. - /// \[lost, rescuer\] - RecoveryClosed(T::AccountId, T::AccountId), + RecoveryClosed { lost_account: T::AccountId, rescuer_account: T::AccountId }, /// Lost account has been successfully recovered by rescuer account. - /// \[lost, rescuer\] - AccountRecovered(T::AccountId, T::AccountId), - /// A recovery process has been removed for an \[account\]. - RecoveryRemoved(T::AccountId), + AccountRecovered { lost_account: T::AccountId, rescuer_account: T::AccountId }, + /// A recovery process has been removed for an account. + RecoveryRemoved { lost_account: T::AccountId }, } #[pallet::error] @@ -409,7 +409,10 @@ pub mod pallet { ensure_root(origin)?; // Create the recovery storage item. >::insert(&rescuer, &lost); - Self::deposit_event(Event::::AccountRecovered(lost, rescuer)); + Self::deposit_event(Event::::AccountRecovered { + lost_account: lost, + rescuer_account: rescuer, + }); Ok(()) } @@ -472,7 +475,7 @@ pub mod pallet { // Create the recovery configuration storage item >::insert(&who, recovery_config); - Self::deposit_event(Event::::RecoveryCreated(who)); + Self::deposit_event(Event::::RecoveryCreated { account: who }); Ok(()) } @@ -519,7 +522,10 @@ pub mod pallet { }; // Create the active recovery storage item >::insert(&account, &who, recovery_status); - Self::deposit_event(Event::::RecoveryInitiated(account, who)); + Self::deposit_event(Event::::RecoveryInitiated { + lost_account: account, + rescuer_account: who, + }); Ok(()) } @@ -568,7 +574,11 @@ pub mod pallet { } // Update storage with the latest details >::insert(&lost, &rescuer, active_recovery); - Self::deposit_event(Event::::RecoveryVouched(lost, rescuer, who)); + Self::deposit_event(Event::::RecoveryVouched { + lost_account: lost, + rescuer_account: rescuer, + sender: who, + }); Ok(()) } @@ -617,7 +627,10 @@ pub mod pallet { frame_system::Pallet::::inc_consumers(&who).map_err(|_| Error::::BadState)?; // Create the recovery storage item Proxy::::insert(&who, &account); - Self::deposit_event(Event::::AccountRecovered(account, who)); + Self::deposit_event(Event::::AccountRecovered { + lost_account: account, + rescuer_account: who, + }); Ok(()) } @@ -656,7 +669,10 @@ pub mod pallet { BalanceStatus::Free, ); debug_assert!(res.is_ok()); - Self::deposit_event(Event::::RecoveryClosed(who, rescuer)); + Self::deposit_event(Event::::RecoveryClosed { + lost_account: who, + rescuer_account: rescuer, + }); Ok(()) } @@ -692,7 +708,7 @@ pub mod pallet { // Unreserve the initial deposit for the recovery configuration. T::Currency::unreserve(&who, recovery_config.deposit); - Self::deposit_event(Event::::RecoveryRemoved(who)); + Self::deposit_event(Event::::RecoveryRemoved { lost_account: who }); Ok(()) } diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 2fd34365705bb..f56d282c0f111 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -532,9 +532,9 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// New session has happened. Note that the argument is the \[session_index\], not the + /// New session has happened. Note that the argument is the session index, not the /// block number as the type might suggest. - NewSession(SessionIndex), + NewSession { session_index: SessionIndex }, } /// Old name generated by `decl_event`. @@ -703,7 +703,7 @@ impl Pallet { >::put(next_changed); // Record that this happened. - Self::deposit_event(Event::NewSession(session_index)); + Self::deposit_event(Event::NewSession { session_index }); // Tell everyone about the new session keys. T::SessionHandler::on_new_session::(changed, &session_keys, &queued_amalgamated); From 664ac530640823f55bcb8b7a2a4cc215fd5b11d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 20 Nov 2021 23:08:49 +0000 Subject: [PATCH 0258/1472] Bump derive_more from 0.99.11 to 0.99.16 (#10282) Bumps [derive_more](https://github.com/JelteF/derive_more) from 0.99.11 to 0.99.16. - [Release notes](https://github.com/JelteF/derive_more/releases) - [Changelog](https://github.com/JelteF/derive_more/blob/master/CHANGELOG.md) - [Commits](https://github.com/JelteF/derive_more/compare/v0.99.11...v0.99.16) --- updated-dependencies: - dependency-name: derive_more 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 | 12 ++++++++++-- bin/node/bench/Cargo.toml | 2 +- client/authority-discovery/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/executor/common/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- test-utils/runtime/transaction-pool/Cargo.toml | 2 +- 15 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9798d4c42054..56eb2a5543c8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -993,6 +993,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[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.1" @@ -1476,12 +1482,14 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.11" +version = "0.99.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c" +checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df" dependencies = [ + "convert_case", "proc-macro2", "quote", + "rustc_version 0.3.3", "syn", ] diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 66a14a123ee56..037a233a4ca0d 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -19,7 +19,7 @@ sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-m serde = "1.0.126" serde_json = "1.0.68" structopt = "0.3" -derive_more = "0.99.2" +derive_more = "0.99.16" kvdb = "0.10.0" kvdb-rocksdb = "0.14.0" sp-trie = { version = "4.0.0-dev", path = "../../../primitives/trie" } diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index b1d9d4ebd3935..fff1ed08a8c11 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -19,7 +19,7 @@ prost-build = "0.9" [dependencies] async-trait = "0.1" codec = { package = "parity-scale-codec", default-features = false, version = "2.0.0" } -derive_more = "0.99.2" +derive_more = "0.99.16" futures = "0.3.9" futures-timer = "3.0.1" ip_network = "0.4.0" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 152c40f78f9d4..f4f12a0a601c9 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } -derive_more = "0.99.2" +derive_more = "0.99.16" futures = "0.3.9" sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } log = "0.4.8" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 7945ecc4ec793..5020a4a564782 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -49,7 +49,7 @@ log = "0.4.8" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } rand = "0.7.2" merlin = "2.0" -derive_more = "0.99.2" +derive_more = "0.99.16" retain_mut = "0.1.4" async-trait = "0.1.50" diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index bc57092d34001..3a7cf86a800c1 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -24,7 +24,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockcha sp-runtime = { version = "4.0.0-dev", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } futures = "0.3.16" -derive_more = "0.99.2" +derive_more = "0.99.16" sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } sp-core = { version = "4.0.0-dev", path = "../../../../primitives/core" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 90edc15863cdb..48ba910655441 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -derive_more = "0.99.2" +derive_more = "0.99.16" futures = "0.3.9" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 841631fce7cc9..25e39641ae43e 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -28,6 +28,6 @@ log = "0.4.8" futures = "0.3.16" futures-timer = "3.0.1" parking_lot = "0.11.1" -derive_more = "0.99.2" +derive_more = "0.99.16" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev"} async-trait = "0.1.50" diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 1bb057fabad84..3d2cec9ac60c9 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -derive_more = "0.99.2" +derive_more = "0.99.16" pwasm-utils = "0.18.2" codec = { package = "parity-scale-codec", version = "2.0.0" } wasmi = "0.9.1" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index ec4bac715ad40..1dd8c2518ab72 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -derive_more = "0.99.2" +derive_more = "0.99.16" dyn-clone = "1.0" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } futures = "0.3.9" diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index bd158091e747c..9e2928d41e898 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" -derive_more = "0.99.2" +derive_more = "0.99.16" sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index eb91dd145e549..13eb408b0bb58 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -25,7 +25,7 @@ bytes = "1" codec = { package = "parity-scale-codec", version = "2.0.0", features = [ "derive", ] } -derive_more = "0.99.2" +derive_more = "0.99.16" either = "1.5.3" fnv = "1.0.6" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 1ab1ef5bb4a16..f44ec588e9543 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -15,5 +15,5 @@ serde = { version = "1.0.126", features = ["derive"] } thiserror = { version = "1.0.30" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } -derive_more = { version = "0.99.11" } +derive_more = { version = "0.99.16" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index e16ff4676c3b1..ab026ccedd512 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" -derive_more = "0.99.2" +derive_more = "0.99.16" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } futures = { version = "0.3.1" } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index 402caa93d10d8..ee1ac4814db5f 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -20,4 +20,4 @@ sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool", features = ["test-helpers"] } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } futures = "0.3.16" -derive_more = "0.99.2" +derive_more = "0.99.16" From 541a72f9eb41678e4601593735655a5cf794bd4a Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Sun, 21 Nov 2021 14:42:21 +0100 Subject: [PATCH 0259/1472] use proper intra doc link (#10271) * use proper intra doc link * use proper intra doc link * get system path name from path module name function for the docs * used format macro in formatting doc string for better output * helper function to get intra doc string * helper function to get intra doc string * use helper function on expand_origin_pallet_conversions * remove duplicates * Update frame/support/procedural/src/construct_runtime/expand/origin.rs Co-authored-by: Guillaume Thiolliere * remove leading white space Co-authored-by: Damilare Co-authored-by: Guillaume Thiolliere --- .../src/construct_runtime/expand/origin.rs | 53 +++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index eb0212c3efee3..5c2b4c9f93b0b 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -68,14 +68,39 @@ pub fn expand_outer_origin( } let system_path = &system_pallet.path; + let system_index = system_pallet.index; + let system_path_name = system_path.module_name(); + + let doc_string = get_intra_doc_string( + "Origin is always created with the base filter configured in", + &system_path_name, + ); + + let doc_string_none_origin = + get_intra_doc_string("Create with system none origin and", &system_path_name); + + let doc_string_root_origin = + get_intra_doc_string("Create with system root origin and", &system_path_name); + + let doc_string_signed_origin = + get_intra_doc_string("Create with system signed origin and", &system_path_name); + + let doc_string_runtime_origin = + get_intra_doc_string("Convert to runtime origin, using as filter:", &system_path_name); + + let doc_string_runtime_origin_with_caller = get_intra_doc_string( + "Convert to runtime origin with caller being system signed or none and use filter", + &system_path_name, + ); + Ok(quote! { #( #query_origin_part_macros )* - /// The runtime origin type represanting the origin of a call. + /// The runtime origin type representing the origin of a call. /// - /// Origin is always created with the base filter configured in `frame_system::Config::BaseCallFilter`. + #[doc = #doc_string] #[derive(Clone)] pub struct Origin { caller: OriginCaller, @@ -182,15 +207,18 @@ pub fn expand_outer_origin( // For backwards compatibility and ease of accessing these functions. #[allow(dead_code)] impl Origin { - /// Create with system none origin and `frame-system::Config::BaseCallFilter`. + + #[doc = #doc_string_none_origin] pub fn none() -> Self { ::none() } - /// Create with system root origin and `frame-system::Config::BaseCallFilter`. + + #[doc = #doc_string_root_origin] pub fn root() -> Self { ::root() } - /// Create with system signed origin and `frame-system::Config::BaseCallFilter`. + + #[doc = #doc_string_signed_origin] pub fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self { ::signed(by) } @@ -216,7 +244,8 @@ pub fn expand_outer_origin( } impl From<#system_path::Origin<#runtime>> for Origin { - /// Convert to runtime origin, using as filter: `frame-system::Config::BaseCallFilter`. + + #[doc = #doc_string_runtime_origin] fn from(x: #system_path::Origin<#runtime>) -> Self { let o: OriginCaller = x.into(); o.into() @@ -247,8 +276,7 @@ pub fn expand_outer_origin( } } impl From::AccountId>> for Origin { - /// Convert to runtime origin with caller being system signed or none and use filter - /// `frame-system::Config::BaseCallFilter`. + #[doc = #doc_string_runtime_origin_with_caller] fn from(x: Option<<#runtime as #system_path::Config>::AccountId>) -> Self { <#system_path::Origin<#runtime>>::from(x).into() } @@ -303,6 +331,8 @@ fn expand_origin_pallet_conversions( None => quote!(#path::Origin), }; + let doc_string = get_intra_doc_string(" Convert to runtime origin using", &path.module_name()); + quote! { impl From<#pallet_origin> for OriginCaller { fn from(x: #pallet_origin) -> Self { @@ -311,7 +341,7 @@ fn expand_origin_pallet_conversions( } impl From<#pallet_origin> for Origin { - /// Convert to runtime origin using `frame-system::Config::BaseCallFilter`. + #[doc = #doc_string] fn from(x: #pallet_origin) -> Self { let x: OriginCaller = x.into(); x.into() @@ -343,3 +373,8 @@ fn expand_origin_pallet_conversions( } } } + +// Get the actual documentation using the doc information and system path name +fn get_intra_doc_string(doc_info: &str, system_path_name: &String) -> String { + format!(" {} [`{}::Config::BaseCallFilter`].", doc_info, system_path_name) +} From 35fcfd66d380c8336030810030d8f09171b51734 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Mon, 22 Nov 2021 19:48:53 +0900 Subject: [PATCH 0260/1472] Fix some doc link (#10329) * fix some doc link * fmt --- client/consensus/pow/src/lib.rs | 4 ++-- client/executor/wasmtime/src/runtime.rs | 8 ++++---- client/telemetry/src/lib.rs | 2 +- frame/bags-list/src/lib.rs | 11 ++++++----- frame/bags-list/src/list/mod.rs | 6 +++--- frame/beefy-mmr/primitives/src/lib.rs | 5 +++-- frame/beefy-mmr/src/lib.rs | 2 +- frame/benchmarking/src/lib.rs | 6 +++--- frame/contracts/src/lib.rs | 2 +- frame/election-provider-multi-phase/src/lib.rs | 8 ++++---- frame/election-provider-support/src/lib.rs | 6 +++--- frame/election-provider-support/src/onchain.rs | 2 +- frame/executive/src/lib.rs | 2 +- frame/staking/src/pallet/mod.rs | 5 +++-- frame/support/procedural/src/construct_runtime/mod.rs | 1 + frame/support/src/lib.rs | 2 +- frame/support/src/storage/bounded_vec.rs | 2 +- frame/support/src/storage/weak_bounded_vec.rs | 2 +- frame/support/src/traits/misc.rs | 2 +- frame/system/src/lib.rs | 3 ++- primitives/beefy/src/commitment.rs | 9 +++++---- primitives/npos-elections/solution-type/src/lib.rs | 2 +- primitives/npos-elections/src/assignments.rs | 2 +- primitives/sandbox/src/lib.rs | 2 +- utils/frame/generate-bags/src/lib.rs | 2 +- 25 files changed, 52 insertions(+), 46 deletions(-) diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 3ab0b977255ee..6ccdf53c0f047 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -27,9 +27,9 @@ //! started via the [`start_mining_worker`] function. It returns a worker //! handle together with a future. The future must be pulled. Through //! the worker handle, you can pull the metadata needed to start the -//! mining process via [`MiningWorker::metadata`], and then do the actual +//! mining process via [`MiningHandle::metadata`], and then do the actual //! mining on a standalone thread. Finally, when a seal is found, call -//! [`MiningWorker::submit`] to build the block. +//! [`MiningHandle::submit`] to build the block. //! //! The auxiliary storage for PoW engine only stores the total difficulty. //! For other storage requirements for particular PoW algorithm (such as diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 4d107862173b0..7808ac7ce547d 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -459,11 +459,11 @@ pub struct Config { /// The total amount of memory in bytes an instance can request. /// /// If specified, the runtime will be able to allocate only that much of wasm memory. - /// This is the total number and therefore the [`heap_pages`] is accounted for. + /// This is the total number and therefore the [`Config::heap_pages`] is accounted for. /// - /// That means that the initial number of pages of a linear memory plus the [`heap_pages`] - /// multiplied by the wasm page size (64KiB) should be less than or equal to `max_memory_size`, - /// otherwise the instance won't be created. + /// That means that the initial number of pages of a linear memory plus the + /// [`Config::heap_pages`] multiplied by the wasm page size (64KiB) should be less than or + /// equal to `max_memory_size`, otherwise the instance won't be created. /// /// Moreover, `memory.grow` will fail (return -1) if the sum of sizes of currently mounted /// and additional pages exceeds `max_memory_size`. diff --git a/client/telemetry/src/lib.rs b/client/telemetry/src/lib.rs index 9fb86f57d8392..2e50bf5884fa7 100644 --- a/client/telemetry/src/lib.rs +++ b/client/telemetry/src/lib.rs @@ -440,7 +440,7 @@ enum Register { /// Report a telemetry. /// -/// Translates to [`tracing::info`], but contains an additional verbosity parameter which the log +/// Translates to `tracing::info`, but contains an additional verbosity parameter which the log /// record is tagged with. Additionally the verbosity parameter is added to the record as a /// key-value pair. /// diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 8be1afbe29bbe..2cff68b54c9c7 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -19,11 +19,11 @@ //! //! A semi-sorted list, where items hold an `AccountId` based on some `VoteWeight`. The `AccountId` //! (`id` for short) might be synonym to a `voter` or `nominator` in some context, and `VoteWeight` -//! signifies the chance of each id being included in the final [`VoteWeightProvider::iter`]. +//! signifies the chance of each id being included in the final [`SortedListProvider::iter`]. //! -//! It implements [`sp_election_provider_support::SortedListProvider`] to provide a semi-sorted list -//! of accounts to another pallet. It needs some other pallet to give it some information about the -//! weights of accounts via [`sp_election_provider_support::VoteWeightProvider`]. +//! It implements [`frame_election_provider_support::SortedListProvider`] to provide a semi-sorted +//! list of accounts to another pallet. It needs some other pallet to give it some information about +//! the weights of accounts via [`frame_election_provider_support::VoteWeightProvider`]. //! //! This pallet is not configurable at genesis. Whoever uses it should call appropriate functions of //! the `SortedListProvider` (e.g. `on_insert`, or `regenerate`) at their genesis. @@ -38,7 +38,8 @@ //! //! # Details //! -//! - items are kept in bags, which are delineated by their range of weight (See [`BagThresholds`]). +//! - items are kept in bags, which are delineated by their range of weight (See +//! [`Config::BagThresholds`]). //! - for iteration, bags are chained together from highest to lowest and elements within the bag //! are iterated from head to tail. //! - items within a bag are iterated in order of insertion. Thus removing an item and re-inserting diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index df966eea80cee..b381b36dc9ee2 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -17,8 +17,8 @@ //! Implementation of a "bags list": a semi-sorted list where ordering granularity is dictated by //! configurable thresholds that delineate the boundaries of bags. It uses a pattern of composite -//! data structures, where multiple storage items are masked by one outer API. See [`ListNodes`], -//! [`ListBags`] for more information. +//! data structures, where multiple storage items are masked by one outer API. See +//! [`crate::ListNodes`], [`crate::ListBags`] for more information. //! //! The outer API of this module is the [`List`] struct. It wraps all acceptable operations on top //! of the aggregate linked list. All operations with the bags list should happen through this @@ -460,7 +460,7 @@ impl List { } } -/// A Bag is a doubly-linked list of ids, where each id is mapped to a [`ListNode`]. +/// A Bag is a doubly-linked list of ids, where each id is mapped to a [`Node`]. /// /// Note that we maintain both head and tail pointers. While it would be possible to get away with /// maintaining only a head pointer and cons-ing elements onto the front of the list, it's more diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/frame/beefy-mmr/primitives/src/lib.rs index 4d4d4e8721ac8..ee1484607563f 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/frame/beefy-mmr/primitives/src/lib.rs @@ -44,7 +44,8 @@ pub type Hash = [u8; 32]; /// Generic hasher trait. /// /// Implement the function to support custom way of hashing data. -/// The implementation must return a [Hash] type, so only 32-byte output hashes are supported. +/// The implementation must return a [Hash](type@Hash) type, so only 32-byte output hashes are +/// supported. pub trait Hasher { /// Hash given arbitrary-length piece of data. fn hash(data: &[u8]) -> Hash; @@ -173,7 +174,7 @@ impl Visitor for () { /// /// # Panic /// -/// The function will panic if given [`leaf_index`] is greater than the number of leaves. +/// The function will panic if given `leaf_index` is greater than the number of leaves. pub fn merkle_proof(leaves: I, leaf_index: usize) -> MerkleProof where H: Hasher, diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 001831639b169..b846aa4a7dd6b 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -149,7 +149,7 @@ pub mod pallet { /// Details of next BEEFY authority set. /// - /// This storage entry is used as cache for calls to [`update_beefy_next_authority_set`]. + /// This storage entry is used as cache for calls to `update_beefy_next_authority_set`. #[pallet::storage] #[pallet::getter(fn beefy_next_authorities)] pub type BeefyNextAuthorities = diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 088dbeb0bb78d..56545914dcba3 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -1266,21 +1266,21 @@ macro_rules! impl_benchmark_test { /// fn bench_accumulate_dummy() { /// new_test_ext().execute_with(|| { /// assert_ok!(test_benchmark_accumulate_dummy::()); -/// } +/// }) /// } /// /// #[test] /// fn bench_set_dummy() { /// new_test_ext().execute_with(|| { /// assert_ok!(test_benchmark_set_dummy::()); -/// } +/// }) /// } /// /// #[test] /// fn bench_sort_vector() { /// new_test_ext().execute_with(|| { /// assert_ok!(test_benchmark_sort_vector::()); -/// } +/// }) /// } /// } /// ``` diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 62b74b9b7b954..b2e221dde6ad9 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -202,7 +202,7 @@ pub mod pallet { type Schedule: Get>; /// The deposit that must be placed into the contract's account to instantiate it. - /// This is in **addition** to the [`pallet_balances::Pallet::ExistenialDeposit`]. + /// This is in **addition** to the [`Currency::minimum_balance`]. /// The minimum balance for a contract's account can be queried using /// [`Pallet::subsistence_threshold`]. #[pallet::constant] diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index cdf5a2098d6bb..ee4c9ae45d42b 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -183,8 +183,8 @@ //! are helpful for logging and are thus nested as: //! - [`ElectionError::Miner`]: wraps a [`unsigned::MinerError`]. //! - [`ElectionError::Feasibility`]: wraps a [`FeasibilityError`]. -//! - [`ElectionError::OnChainFallback`]: wraps a -//! [`frame_election_provider_support::onchain::Error`]. +//! - [`ElectionError::Fallback`]: wraps a fallback error. +//! - [`ElectionError::DataProvider`]: wraps a static str. //! //! Note that there could be an overlap between these sub-errors. For example, A //! `SnapshotUnavailable` can happen in both miner and feasibility check phase. @@ -1244,14 +1244,14 @@ impl Pallet { } } - /// Logic for [`::on_initialize`] when signed phase is being opened. + /// Logic for `::on_initialize` when signed phase is being opened. pub fn on_initialize_open_signed() { log!(info, "Starting signed phase round {}.", Self::round()); >::put(Phase::Signed); Self::deposit_event(Event::SignedPhaseStarted { round: Self::round() }); } - /// Logic for [`>::on_initialize`] when unsigned phase is being opened. + /// Logic for `>::on_initialize` when unsigned phase is being opened. pub fn on_initialize_open_unsigned(enabled: bool, now: T::BlockNumber) { let round = Self::round(); log!(info, "Starting unsigned phase round {} enabled {}.", round, enabled); diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index cb36e025c3bee..472584ed2506b 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -384,7 +384,7 @@ pub trait NposSolver { ) -> Result, Self::Error>; } -/// A wrapper for [`sp_npos_elections::seq_phragmen`] that implements [`super::NposSolver`]. See the +/// A wrapper for [`sp_npos_elections::seq_phragmen`] that implements [`NposSolver`]. See the /// documentation of [`sp_npos_elections::seq_phragmen`] for more info. pub struct SequentialPhragmen( sp_std::marker::PhantomData<(AccountId, Accuracy, Balancing)>, @@ -408,8 +408,8 @@ impl< } } -/// A wrapper for [`sp_npos_elections::phragmms`] that implements [`NposSolver`]. See the -/// documentation of [`sp_npos_elections::phragmms`] for more info. +/// A wrapper for [`sp_npos_elections::phragmms()`] that implements [`NposSolver`]. See the +/// documentation of [`sp_npos_elections::phragmms()`] for more info. pub struct PhragMMS( sp_std::marker::PhantomData<(AccountId, Accuracy, Balancing)>, ); diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index fb1ccfdfe2566..6379adae4206b 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -57,7 +57,7 @@ pub struct OnChainSequentialPhragmen(PhantomData); /// /// WARNING: the user of this pallet must ensure that the `Accuracy` type will work nicely with the /// normalization operation done inside `seq_phragmen`. See -/// [`sp_npos_elections::assignment::try_normalize`] for more info. +/// [`sp_npos_elections::Assignment::try_normalize`] for more info. pub trait Config: frame_system::Config { /// The accuracy used to compute the election: type Accuracy: PerThing128; diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index e77c811a35e2d..dd0a9abf8687b 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -219,7 +219,7 @@ where weight } - /// Execute given block, but don't do any of the [`final_checks`]. + /// Execute given block, but don't do any of the `final_checks`. /// /// Should only be used for testing. #[cfg(feature = "try-runtime")] diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index ec7e86af958f1..542b79b792dc7 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -69,7 +69,8 @@ pub mod pallet { /// Convert a balance into a number used for election calculation. This must fit into a /// `u64` but is allowed to be sensibly lossy. The `u64` is used to communicate with the - /// [`sp_npos_elections`] crate which accepts u64 numbers and does operations in 128. + /// [`frame_election_provider_support`] crate which accepts u64 numbers and does operations + /// in 128. /// Consequently, the backward convert is used convert the u128s from sp-elections back to a /// [`BalanceOf`]. type CurrencyToVote: CurrencyToVote>; @@ -146,7 +147,7 @@ pub mod pallet { type OffendingValidatorsThreshold: Get; /// Something that can provide a sorted list of voters in a somewhat sorted way. The - /// original use case for this was designed with [`pallet_bags_list::Pallet`] in mind. If + /// original use case for this was designed with `pallet_bags_list::Pallet` in mind. If /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. type SortedListProvider: SortedListProvider; diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index f54fa79ce609b..a5da775b9c9ea 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -84,6 +84,7 @@ //! }] //! pattern = [{ System: frame_system }] //! tokens = [{ ::{Pallet, Call} }] +//! } //! }] //! pattern = [{ Balances: pallet_balances }] //! tokens = [{ ::{Pallet, Call} }] diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index af9192f6ea836..2adcd8ce4efcf 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1749,7 +1749,7 @@ pub mod pallet_prelude { /// ``` /// /// The optional attribute `#[pallet::unbounded]` allows to declare the storage as unbounded. -/// When implementating the storage info (when #[pallet::generate_storage_info]` is specified +/// When implementating the storage info (when `#[pallet::generate_storage_info]` is specified /// on the pallet struct placeholder), the size of the storage will be declared as unbounded. /// This can be useful for storage which can never go into PoV (Proof of Validity). /// diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 3b5e7bda1651c..b9ece89bff284 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -130,7 +130,7 @@ impl BoundedVec { self.0.retain(f) } - /// Exactly the same semantics as [`Vec::get_mut`]. + /// Exactly the same semantics as [`slice::get_mut`]. pub fn get_mut>( &mut self, index: I, diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 823c50c55d0b9..566889f5f192c 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -90,7 +90,7 @@ impl WeakBoundedVec { self.0.retain(f) } - /// Exactly the same semantics as [`Vec::get_mut`]. + /// Exactly the same semantics as [`slice::get_mut`]. pub fn get_mut>( &mut self, index: I, diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 0a3fb045d6c1d..153c3804bd599 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -301,7 +301,7 @@ pub trait PrivilegeCmp { /// Implementation of [`PrivilegeCmp`] that only checks for equal origins. /// -/// This means it will either return [`Origin::Equal`] or `None`. +/// This means it will either return [`Ordering::Equal`] or `None`. pub struct EqualPrivilegeOnly; impl PrivilegeCmp for EqualPrivilegeOnly { fn cmp_privilege(left: &Origin, right: &Origin) -> Option { diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index d5b930fa165e6..12361ed859d0e 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -301,7 +301,8 @@ pub mod pallet { /// What to do if the runtime wants to change the code to something new. /// /// The default (`()`) implementation is responsible for setting the correct storage - /// entry and emitting corresponding event and log item. (see [`update_code_in_storage`]). + /// entry and emitting corresponding event and log item. (see + /// [`Pallet::update_code_in_storage`]). /// It's unlikely that this needs to be customized, unless you are writing a parachain using /// `Cumulus`, where the actual code change is deferred. type OnSetCode: SetCode; diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index 7aab93bbcb973..d9e4de6e19bb7 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -21,7 +21,8 @@ use crate::{crypto::Signature, ValidatorSetId}; /// A commitment signed by GRANDPA validators as part of BEEFY protocol. /// -/// The commitment contains a [payload] extracted from the finalized block at height [block_number]. +/// The commitment contains a [payload](Commitment::payload) extracted from the finalized block at +/// height [block_number](Commitment::block_number). /// GRANDPA validators collect signatures on commitments and a stream of such signed commitments /// (see [SignedCommitment]) forms the BEEFY protocol. #[derive(Clone, Debug, PartialEq, Eq, codec::Encode, codec::Decode)] @@ -33,7 +34,7 @@ pub struct Commitment { /// validator set. The protocol does not enforce any particular format of this data, /// nor how often it should be present in commitments, however the light client has to be /// provided with full validator set whenever it performs the transition (i.e. importing first - /// block with [validator_set_id] incremented). + /// block with [validator_set_id](Commitment::validator_set_id) incremented). pub payload: TPayload, /// Finalized block number this commitment is for. @@ -51,8 +52,8 @@ pub struct Commitment { /// /// Validator set is changing once per epoch. The Light Client must be provided by details /// about the validator set whenever it's importing first commitment with a new - /// `validator_set_id`. Validator set data MUST be verifiable, for instance using [payload] - /// information. + /// `validator_set_id`. Validator set data MUST be verifiable, for instance using + /// [payload](Commitment::payload) information. pub validator_set_id: ValidatorSetId, } diff --git a/primitives/npos-elections/solution-type/src/lib.rs b/primitives/npos-elections/solution-type/src/lib.rs index 9b0ec56fc74de..967ead4400c3e 100644 --- a/primitives/npos-elections/solution-type/src/lib.rs +++ b/primitives/npos-elections/solution-type/src/lib.rs @@ -88,7 +88,7 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error { /// ``` /// /// The given struct provides function to convert from/to `Assignment` as part of -/// [`sp_npos_elections::Solution`] trait: +/// `sp_npos_elections::Solution` trait: /// /// - `fn from_assignment<..>(..)` /// - `fn into_assignment<..>(..)` diff --git a/primitives/npos-elections/src/assignments.rs b/primitives/npos-elections/src/assignments.rs index bdd1e2cd281bb..330f7bd7e843e 100644 --- a/primitives/npos-elections/src/assignments.rs +++ b/primitives/npos-elections/src/assignments.rs @@ -201,7 +201,7 @@ impl IndexAssignment = IndexAssignment< ::VoterIndex, ::TargetIndex, diff --git a/primitives/sandbox/src/lib.rs b/primitives/sandbox/src/lib.rs index f1a24732b7a0a..79c56e70e2f4b 100755 --- a/primitives/sandbox/src/lib.rs +++ b/primitives/sandbox/src/lib.rs @@ -89,7 +89,7 @@ pub type HostFuncType = fn(&mut T, &[Value]) -> Result f64 { /// The last element is always `VoteWeight::MAX`. /// /// All other elements are computed from the previous according to the formula -/// `threshold[k + 1] = (threshold[k] * ratio).max(threshold[k] + 1); +/// `threshold[k + 1] = (threshold[k] * ratio).max(threshold[k] + 1);` pub fn thresholds( existential_weight: VoteWeight, constant_ratio: f64, From 68c0952dcf05312c1229e92ff86fa8191c8610a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Nov 2021 11:12:59 +0000 Subject: [PATCH 0261/1472] Bump platforms from 1.1.0 to 2.0.0 (#10331) Bumps [platforms](https://github.com/rustsec/rustsec) from 1.1.0 to 2.0.0. - [Release notes](https://github.com/rustsec/rustsec/releases) - [Commits](https://github.com/rustsec/rustsec/commits/platforms/v2.0.0) --- updated-dependencies: - dependency-name: platforms 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 | 4 ++-- bin/node/cli/Cargo.toml | 2 +- utils/build-script-utils/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 56eb2a5543c8e..2c10e9fe0b95e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6643,9 +6643,9 @@ checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "platforms" -version = "1.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989d43012e2ca1c4a02507c67282691a0a3207f9dc67cec596b43fe925b3d325" +checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" [[package]] name = "plotters" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 5a9e76bccf63b..1bb3671d42bae 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -126,7 +126,7 @@ assert_cmd = "2.0.2" nix = "0.23" serde_json = "1.0" regex = "1" -platforms = "1.1" +platforms = "2.0" async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" criterion = { version = "0.3.5", features = [ "async_tokio" ] } diff --git a/utils/build-script-utils/Cargo.toml b/utils/build-script-utils/Cargo.toml index 93611c7b5b017..7150b4fa5adcb 100644 --- a/utils/build-script-utils/Cargo.toml +++ b/utils/build-script-utils/Cargo.toml @@ -13,4 +13,4 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -platforms = "1.1" +platforms = "2.0" From c0da7c3d47def8600c9d3ef55617790d81b7d8bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Nov 2021 12:57:50 +0000 Subject: [PATCH 0262/1472] Bump serde_json from 1.0.68 to 1.0.71 (#10321) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.68 to 1.0.71. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.68...v1.0.71) --- 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 ++-- bin/node/bench/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- frame/transaction-payment/asset-tx-payment/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/serializer/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- 22 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c10e9fe0b95e..3fd2ba8085a9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8956,9 +8956,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.68" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19" dependencies = [ "itoa", "ryu", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 037a233a4ca0d..0beeb4e339e43 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -17,7 +17,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } serde = "1.0.126" -serde_json = "1.0.68" +serde_json = "1.0.71" structopt = "0.3" derive_more = "0.99.16" kvdb = "0.10.0" diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index d7557e2062ac4..976da45859117 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -18,7 +18,7 @@ impl-trait-for-tuples = "0.2.1" sc-network = { version = "0.10.0-dev", path = "../network" } sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } serde = { version = "1.0.126", features = ["derive"] } -serde_json = "1.0.68" +serde_json = "1.0.71" sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 2855e63cdc6a0..8667a5e876c14 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -23,7 +23,7 @@ parity-scale-codec = "2.3.1" hex = "0.4.2" rand = "0.7.3" tiny-bip39 = "0.8.2" -serde_json = "1.0.68" +serde_json = "1.0.71" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-panic-handler = { version = "4.0.0-dev", path = "../../primitives/panic-handler" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 3a7cf86a800c1..b47c3a711df99 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -33,7 +33,7 @@ sp-keystore = { version = "0.10.0-dev", path = "../../../../primitives/keystore" [dev-dependencies] sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } -serde_json = "1.0.68" +serde_json = "1.0.71" sp-keyring = { version = "4.0.0-dev", path = "../../../../primitives/keyring" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 1dd8c2518ab72..65a0580b9e953 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -35,7 +35,7 @@ sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -serde_json = "1.0.68" +serde_json = "1.0.71" sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 9e2928d41e898..9da825faf033a 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -22,7 +22,7 @@ sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } hex = "0.4.0" parking_lot = "0.11.1" -serde_json = "1.0.68" +serde_json = "1.0.71" [dev-dependencies] tempfile = "3.1.0" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 13eb408b0bb58..c4622c0c5df0e 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -47,7 +47,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } serde = { version = "1.0.126", features = ["derive"] } -serde_json = "1.0.68" +serde_json = "1.0.71" smallvec = "1.7.0" sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index 01b75f1094ff4..fba499bce00e3 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.9" libp2p = { version = "0.39.1", default-features = false } sc-utils = { version = "4.0.0-dev", path = "../utils"} log = "0.4.8" -serde_json = "1.0.68" +serde_json = "1.0.71" wasm-timer = "0.2" [dev-dependencies] diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 532a5cf6294ce..a758d29aed2c2 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -28,7 +28,7 @@ sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-runtime = { path = "../../primitives/runtime", version = "4.0.0-dev" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } serde = { version = "1.0.126", features = ["derive"] } -serde_json = "1.0.68" +serde_json = "1.0.71" sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index 3be2380785064..f6f08ac581d4f 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -18,7 +18,7 @@ jsonrpc-core = "18.0.0" pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} -serde_json = "1.0.68" +serde_json = "1.0.71" tokio = "1.13" http = { package = "jsonrpc-http-server", version = "18.0.0" } ipc = { package = "jsonrpc-ipc-server", version = "18.0.0" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index d8aecfe9fd354..6cf2d699386df 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -23,7 +23,7 @@ log = "0.4.8" sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } rpc = { package = "jsonrpc-core", version = "18.0.0" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } -serde_json = "1.0.68" +serde_json = "1.0.71" sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index a66a4fc67680e..161863b14710b 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -34,7 +34,7 @@ exit-future = "0.2.0" pin-project = "1.0.8" hash-db = "0.15.2" serde = "1.0.126" -serde_json = "1.0.68" +serde_json = "1.0.71" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 6d8d95954629c..c609ac42c76e9 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -23,7 +23,7 @@ sc-consensus-babe = { version = "0.10.0-dev", path = "../consensus/babe" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } -serde_json = "1.0.68" +serde_json = "1.0.71" serde = { version = "1.0.126", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 744a0610a07e3..9165f6f87af68 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -23,6 +23,6 @@ log = "0.4.8" pin-project = "1.0.8" rand = "0.7.2" serde = { version = "1.0.126", features = ["derive"] } -serde_json = "1.0.68" +serde_json = "1.0.71" chrono = "0.4.19" thiserror = "1.0.30" diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 881cbb3c8ebfe..d8f861ad8ec50 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -27,4 +27,4 @@ sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } [dev-dependencies] -serde_json = "1.0.68" +serde_json = "1.0.71" diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 1d3066e39fbda..3b8b85977db3d 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -29,7 +29,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -serde_json = "1.0.68" +serde_json = "1.0.71" pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index a381145d667a1..e4f3b128cfce9 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -30,7 +30,7 @@ serde = { version = "1.0.126", optional = true } [dev-dependencies] smallvec = "1.7.0" -serde_json = "1.0.68" +serde_json = "1.0.71" sp-storage = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/storage" } diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index 15f7aa2b3b896..2d56cb06fbcca 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -18,4 +18,4 @@ sp-core = { version = "4.0.0-dev", path = "../core" } rustc-hash = "1.1.0" [dev-dependencies] -serde_json = "1.0.68" +serde_json = "1.0.71" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 8e466bf4a1e85..7966bb28255b7 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -32,7 +32,7 @@ hash256-std-hasher = { version = "0.15.2", default-features = false } either = { version = "1.5", default-features = false } [dev-dependencies] -serde_json = "1.0.68" +serde_json = "1.0.71" rand = "0.7.2" sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } sp-api = { version = "4.0.0-dev", path = "../api" } diff --git a/primitives/serializer/Cargo.toml b/primitives/serializer/Cargo.toml index 2b2acb8dbc373..359217b9b4d5a 100644 --- a/primitives/serializer/Cargo.toml +++ b/primitives/serializer/Cargo.toml @@ -15,4 +15,4 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = "1.0.126" -serde_json = "1.0.68" +serde_json = "1.0.71" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 1277863c94f73..ef481dd3f202a 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } futures = "0.3.16" hex = "0.4" serde = "1.0.126" -serde_json = "1.0.68" +serde_json = "1.0.71" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } sc-client-db = { version = "0.10.0-dev", features = [ "test-helpers", From 5ed2f8fc99b67befc86fd30dce344e394c65e536 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Nov 2021 19:03:41 +0000 Subject: [PATCH 0263/1472] Bump paste from 1.0.4 to 1.0.6 (#10333) Bumps [paste](https://github.com/dtolnay/paste) from 1.0.4 to 1.0.6. - [Release notes](https://github.com/dtolnay/paste/releases) - [Commits](https://github.com/dtolnay/paste/compare/1.0.4...1.0.6) --- updated-dependencies: - dependency-name: paste 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 +++++++++--------- client/executor/runtime-test/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3fd2ba8085a9a..6eb7efb084867 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1947,7 +1947,7 @@ dependencies = [ "linregress", "log 0.4.14", "parity-scale-codec", - "paste 1.0.4", + "paste 1.0.6", "scale-info", "sp-api", "sp-io", @@ -2044,7 +2044,7 @@ dependencies = [ "once_cell", "parity-scale-codec", "parity-util-mem", - "paste 1.0.4", + "paste 1.0.6", "pretty_assertions", "scale-info", "serde", @@ -6465,9 +6465,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" [[package]] name = "paste-impl" @@ -8072,7 +8072,7 @@ dependencies = [ "log 0.4.14", "parity-scale-codec", "parking_lot 0.11.1", - "paste 1.0.4", + "paste 1.0.6", "regex", "sc-executor-common", "sc-executor-wasmi", @@ -8495,7 +8495,7 @@ dependencies = [ name = "sc-runtime-test" version = "2.0.0" dependencies = [ - "paste 1.0.4", + "paste 1.0.6", "sp-core", "sp-io", "sp-runtime", @@ -9082,7 +9082,7 @@ dependencies = [ "approx", "num-complex", "num-traits", - "paste 1.0.4", + "paste 1.0.6", ] [[package]] @@ -9696,7 +9696,7 @@ dependencies = [ "log 0.4.14", "parity-scale-codec", "parity-util-mem", - "paste 1.0.4", + "paste 1.0.6", "rand 0.7.3", "scale-info", "serde", @@ -11604,7 +11604,7 @@ dependencies = [ "libc", "log 0.4.14", "object 0.27.1", - "paste 1.0.4", + "paste 1.0.6", "psm", "rayon", "region", diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index 2c82a9705ceeb..ea379a160f80c 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -19,7 +19,7 @@ sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../.. sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } -paste = "1.0.4" +paste = "1.0.6" [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } From 07101053f9ad7b78de32b7a9df3fe0fb304cf1e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Nov 2021 22:57:44 +0100 Subject: [PATCH 0264/1472] Bump prost from 0.8.0 to 0.9.0 (#10341) Bumps [prost](https://github.com/tokio-rs/prost) from 0.8.0 to 0.9.0. - [Release notes](https://github.com/tokio-rs/prost/releases) - [Commits](https://github.com/tokio-rs/prost/compare/v0.8.0...v0.9.0) --- updated-dependencies: - dependency-name: prost 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 | 4 ++-- client/authority-discovery/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6eb7efb084867..a45e0accd49b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7632,7 +7632,7 @@ dependencies = [ "libp2p", "log 0.4.14", "parity-scale-codec", - "prost 0.8.0", + "prost 0.9.0", "prost-build 0.9.0", "quickcheck", "rand 0.7.3", @@ -8282,7 +8282,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.11.1", "pin-project 1.0.8", - "prost 0.8.0", + "prost 0.9.0", "prost-build 0.9.0", "quickcheck", "rand 0.7.3", diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index fff1ed08a8c11..b6f9b8450d861 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -26,7 +26,7 @@ ip_network = "0.4.0" libp2p = { version = "0.39.1", default-features = false, features = ["kad"] } log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } -prost = "0.8" +prost = "0.9" rand = "0.7.2" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index c4622c0c5df0e..527a18dc7755b 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -41,7 +41,7 @@ log = "0.4.8" parking_lot = "0.11.1" pin-project = "1.0.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } -prost = "0.8" +prost = "0.9" rand = "0.7.2" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../api" } From 4de8ee2dee389f4246f3156667fc3d6df7047e4f Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 23 Nov 2021 15:35:19 +0900 Subject: [PATCH 0265/1472] Fix WASM executor without instance reuse; cleanups and refactoring (#10313) * Fix WASM executor without instance reuse; cleanups and refactoring * Align to review comments * Move the functions for reading/writing memory to `util.rs` * Only `#[ignore]` the test in debug builds * More review comments and minor extra comments --- client/executor/wasmtime/build.rs | 25 ++ client/executor/wasmtime/src/host.rs | 212 ++++++++--------- client/executor/wasmtime/src/imports.rs | 15 +- .../executor/wasmtime/src/instance_wrapper.rs | 217 ++++++------------ client/executor/wasmtime/src/runtime.rs | 206 ++++++++--------- client/executor/wasmtime/src/tests.rs | 36 +++ client/executor/wasmtime/src/util.rs | 59 ++++- 7 files changed, 394 insertions(+), 376 deletions(-) create mode 100644 client/executor/wasmtime/build.rs diff --git a/client/executor/wasmtime/build.rs b/client/executor/wasmtime/build.rs new file mode 100644 index 0000000000000..6ab581c9c2685 --- /dev/null +++ b/client/executor/wasmtime/build.rs @@ -0,0 +1,25 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::env; + +fn main() { + if let Ok(profile) = env::var("PROFILE") { + println!("cargo:rustc-cfg=build_type=\"{}\"", profile); + } +} diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index fcb4c4cae3b8a..39ee9ced80af7 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -19,7 +19,7 @@ //! This module defines `HostState` and `HostContext` structs which provide logic and state //! required for execution of host. -use crate::{instance_wrapper::InstanceWrapper, runtime::StoreData}; +use crate::{runtime::StoreData, util}; use codec::{Decode, Encode}; use log::trace; use sc_allocator::FreeingBumpHeapAllocator; @@ -30,101 +30,104 @@ use sc_executor_common::{ }; use sp_core::sandbox as sandbox_primitives; use sp_wasm_interface::{FunctionContext, MemoryId, Pointer, Sandbox, WordSize}; -use std::{cell::RefCell, rc::Rc}; use wasmtime::{Caller, Func, Val}; +// The sandbox store is inside of a Option>> so that we can temporarily borrow it. +struct SandboxStore(Option>>); + +// There are a bunch of `Rc`s within the sandbox store, however we only manipulate +// those within one thread so this should be safe. +unsafe impl Send for SandboxStore {} + /// The state required to construct a HostContext context. The context only lasts for one host /// call, whereas the state is maintained for the duration of a Wasm runtime call, which may make /// many different host calls that must share state. pub struct HostState { - /// We need some interior mutability here since the host state is shared between all host - /// function handlers and the wasmtime backend's `impl WasmRuntime`. - /// - /// Furthermore, because of recursive calls (e.g. runtime can create and call an sandboxed - /// instance which in turn can call the runtime back) we have to be very careful with borrowing - /// those. - /// - /// Basically, most of the interactions should do temporary borrow immediately releasing the - /// borrow after performing necessary queries/changes. - sandbox_store: Rc>>, - allocator: RefCell, - instance: Rc, + sandbox_store: SandboxStore, + allocator: FreeingBumpHeapAllocator, } impl HostState { /// Constructs a new `HostState`. - pub fn new(allocator: FreeingBumpHeapAllocator, instance: Rc) -> Self { + pub fn new(allocator: FreeingBumpHeapAllocator) -> Self { HostState { - sandbox_store: Rc::new(RefCell::new(sandbox::Store::new( + sandbox_store: SandboxStore(Some(Box::new(sandbox::Store::new( sandbox::SandboxBackend::TryWasmer, - ))), - allocator: RefCell::new(allocator), - instance, + )))), + allocator, } } - - /// Materialize `HostContext` that can be used to invoke a substrate host `dyn Function`. - pub(crate) fn materialize<'a, 'b, 'c>( - &'a self, - caller: &'b mut Caller<'c, StoreData>, - ) -> HostContext<'a, 'b, 'c> { - HostContext { host_state: self, caller } - } } /// A `HostContext` implements `FunctionContext` for making host calls from a Wasmtime /// runtime. The `HostContext` exists only for the lifetime of the call and borrows state from /// a longer-living `HostState`. -pub(crate) struct HostContext<'a, 'b, 'c> { - host_state: &'a HostState, - caller: &'b mut Caller<'c, StoreData>, +pub(crate) struct HostContext<'a, 'b> { + pub(crate) caller: &'a mut Caller<'b, StoreData>, } -impl<'a, 'b, 'c> std::ops::Deref for HostContext<'a, 'b, 'c> { - type Target = HostState; - fn deref(&self) -> &HostState { - self.host_state +impl<'a, 'b> HostContext<'a, 'b> { + fn host_state(&self) -> &HostState { + self.caller + .data() + .host_state() + .expect("host state is not empty when calling a function in wasm; qed") + } + + fn host_state_mut(&mut self) -> &mut HostState { + self.caller + .data_mut() + .host_state_mut() + .expect("host state is not empty when calling a function in wasm; qed") + } + + fn sandbox_store(&self) -> &sandbox::Store { + self.host_state() + .sandbox_store + .0 + .as_ref() + .expect("sandbox store is only empty when temporarily borrowed") + } + + fn sandbox_store_mut(&mut self) -> &mut sandbox::Store { + self.host_state_mut() + .sandbox_store + .0 + .as_mut() + .expect("sandbox store is only empty when temporarily borrowed") } } -impl<'a, 'b, 'c> sp_wasm_interface::FunctionContext for HostContext<'a, 'b, 'c> { +impl<'a, 'b> sp_wasm_interface::FunctionContext for HostContext<'a, 'b> { fn read_memory_into( &self, address: Pointer, dest: &mut [u8], ) -> sp_wasm_interface::Result<()> { - let ctx = &self.caller; - self.host_state - .instance - .read_memory_into(ctx, address, dest) - .map_err(|e| e.to_string()) + util::read_memory_into(&self.caller, address, dest).map_err(|e| e.to_string()) } fn write_memory(&mut self, address: Pointer, data: &[u8]) -> sp_wasm_interface::Result<()> { - let ctx = &mut self.caller; - self.host_state - .instance - .write_memory_from(ctx, address, data) - .map_err(|e| e.to_string()) + util::write_memory_from(&mut self.caller, address, data).map_err(|e| e.to_string()) } fn allocate_memory(&mut self, size: WordSize) -> sp_wasm_interface::Result> { - let ctx = &mut self.caller; - let allocator = &self.host_state.allocator; - - self.host_state - .instance - .allocate(ctx, &mut *allocator.borrow_mut(), size) + let memory = self.caller.data().memory(); + let (memory, data) = memory.data_and_store_mut(&mut self.caller); + data.host_state_mut() + .expect("host state is not empty when calling a function in wasm; qed") + .allocator + .allocate(memory, size) .map_err(|e| e.to_string()) } fn deallocate_memory(&mut self, ptr: Pointer) -> sp_wasm_interface::Result<()> { - let ctx = &mut self.caller; - let allocator = &self.host_state.allocator; - - self.host_state - .instance - .deallocate(ctx, &mut *allocator.borrow_mut(), ptr) + let memory = self.caller.data().memory(); + let (memory, data) = memory.data_and_store_mut(&mut self.caller); + data.host_state_mut() + .expect("host state is not empty when calling a function in wasm; qed") + .allocator + .deallocate(memory, ptr) .map_err(|e| e.to_string()) } @@ -133,7 +136,7 @@ impl<'a, 'b, 'c> sp_wasm_interface::FunctionContext for HostContext<'a, 'b, 'c> } } -impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { +impl<'a, 'b> Sandbox for HostContext<'a, 'b> { fn memory_get( &mut self, memory_id: MemoryId, @@ -141,8 +144,7 @@ impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { buf_ptr: Pointer, buf_len: WordSize, ) -> sp_wasm_interface::Result { - let sandboxed_memory = - self.sandbox_store.borrow().memory(memory_id).map_err(|e| e.to_string())?; + let sandboxed_memory = self.sandbox_store().memory(memory_id).map_err(|e| e.to_string())?; let len = buf_len as usize; @@ -151,8 +153,7 @@ impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { Ok(buffer) => buffer, }; - let instance = self.instance.clone(); - if let Err(_) = instance.write_memory_from(&mut self.caller, buf_ptr, &buffer) { + if util::write_memory_from(&mut self.caller, buf_ptr, &buffer).is_err() { return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS) } @@ -166,17 +167,16 @@ impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { val_ptr: Pointer, val_len: WordSize, ) -> sp_wasm_interface::Result { - let sandboxed_memory = - self.sandbox_store.borrow().memory(memory_id).map_err(|e| e.to_string())?; + let sandboxed_memory = self.sandbox_store().memory(memory_id).map_err(|e| e.to_string())?; let len = val_len as usize; - let buffer = match self.instance.read_memory(&self.caller, val_ptr, len) { + let buffer = match util::read_memory(&self.caller, val_ptr, len) { Err(_) => return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), Ok(buffer) => buffer, }; - if let Err(_) = sandboxed_memory.write_from(Pointer::new(offset as u32), &buffer) { + if sandboxed_memory.write_from(Pointer::new(offset as u32), &buffer).is_err() { return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS) } @@ -184,17 +184,11 @@ impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { } fn memory_teardown(&mut self, memory_id: MemoryId) -> sp_wasm_interface::Result<()> { - self.sandbox_store - .borrow_mut() - .memory_teardown(memory_id) - .map_err(|e| e.to_string()) + self.sandbox_store_mut().memory_teardown(memory_id).map_err(|e| e.to_string()) } fn memory_new(&mut self, initial: u32, maximum: u32) -> sp_wasm_interface::Result { - self.sandbox_store - .borrow_mut() - .new_memory(initial, maximum) - .map_err(|e| e.to_string()) + self.sandbox_store_mut().new_memory(initial, maximum).map_err(|e| e.to_string()) } fn invoke( @@ -215,14 +209,10 @@ impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { .map(Into::into) .collect::>(); - let instance = - self.sandbox_store.borrow().instance(instance_id).map_err(|e| e.to_string())?; + let instance = self.sandbox_store().instance(instance_id).map_err(|e| e.to_string())?; - let dispatch_thunk = self - .sandbox_store - .borrow() - .dispatch_thunk(instance_id) - .map_err(|e| e.to_string())?; + let dispatch_thunk = + self.sandbox_store().dispatch_thunk(instance_id).map_err(|e| e.to_string())?; let result = instance.invoke( export_name, @@ -249,8 +239,7 @@ impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { } fn instance_teardown(&mut self, instance_id: u32) -> sp_wasm_interface::Result<()> { - self.sandbox_store - .borrow_mut() + self.sandbox_store_mut() .instance_teardown(instance_id) .map_err(|e| e.to_string()) } @@ -264,14 +253,12 @@ impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { ) -> sp_wasm_interface::Result { // Extract a dispatch thunk from the instance's table by the specified index. let dispatch_thunk = { - let ctx = &mut self.caller; - let table_item = self - .host_state - .instance + let table = self + .caller + .data() .table() - .as_ref() - .ok_or_else(|| "Runtime doesn't have a table; sandbox is unavailable")? - .get(ctx, dispatch_thunk_id); + .ok_or_else(|| "Runtime doesn't have a table; sandbox is unavailable")?; + let table_item = table.get(&mut self.caller, dispatch_thunk_id); table_item .ok_or_else(|| "dispatch_thunk_id is out of bounds")? @@ -281,25 +268,39 @@ impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { .clone() }; - let guest_env = - match sandbox::GuestEnvironment::decode(&*self.sandbox_store.borrow(), raw_env_def) { - Ok(guest_env) => guest_env, - Err(_) => return Ok(sandbox_primitives::ERR_MODULE as u32), - }; + let guest_env = match sandbox::GuestEnvironment::decode(&self.sandbox_store(), raw_env_def) + { + Ok(guest_env) => guest_env, + Err(_) => return Ok(sandbox_primitives::ERR_MODULE as u32), + }; - let store = self.sandbox_store.clone(); - let store = &mut store.borrow_mut(); - let result = store - .instantiate( + let mut store = self + .host_state_mut() + .sandbox_store + .0 + .take() + .expect("sandbox store is only empty when borrowed"); + + // Catch any potential panics so that we can properly restore the sandbox store + // which we've destructively borrowed. + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + store.instantiate( wasm, guest_env, state, &mut SandboxContext { host_context: self, dispatch_thunk: dispatch_thunk.clone() }, ) - .map(|i| i.register(store, dispatch_thunk)); + })); + + self.host_state_mut().sandbox_store.0 = Some(store); + + let result = match result { + Ok(result) => result, + Err(error) => std::panic::resume_unwind(error), + }; let instance_idx_or_err_code = match result { - Ok(instance_idx) => instance_idx, + Ok(instance) => instance.register(&mut self.sandbox_store_mut(), dispatch_thunk), Err(sandbox::InstantiationError::StartTrapped) => sandbox_primitives::ERR_EXECUTION, Err(_) => sandbox_primitives::ERR_MODULE, }; @@ -312,20 +313,19 @@ impl<'a, 'b, 'c> Sandbox for HostContext<'a, 'b, 'c> { instance_idx: u32, name: &str, ) -> sp_wasm_interface::Result> { - self.sandbox_store - .borrow() + self.sandbox_store() .instance(instance_idx) .map(|i| i.get_global_val(name)) .map_err(|e| e.to_string()) } } -struct SandboxContext<'a, 'b, 'c, 'd> { - host_context: &'a mut HostContext<'b, 'c, 'd>, +struct SandboxContext<'a, 'b, 'c> { + host_context: &'a mut HostContext<'b, 'c>, dispatch_thunk: Func, } -impl<'a, 'b, 'c, 'd> sandbox::SandboxContext for SandboxContext<'a, 'b, 'c, 'd> { +impl<'a, 'b, 'c> sandbox::SandboxContext for SandboxContext<'a, 'b, 'c> { fn invoke( &mut self, invoke_args_ptr: Pointer, diff --git a/client/executor/wasmtime/src/imports.rs b/client/executor/wasmtime/src/imports.rs index a00ab14263e7f..57ce48f537e94 100644 --- a/client/executor/wasmtime/src/imports.rs +++ b/client/executor/wasmtime/src/imports.rs @@ -17,6 +17,7 @@ // along with this program. If not, see . use crate::{ + host::HostContext, runtime::{Store, StoreData}, util, }; @@ -191,19 +192,7 @@ fn call_static<'a>( mut caller: Caller<'a, StoreData>, ) -> Result<(), wasmtime::Trap> { let unwind_result = { - let host_state = caller - .data() - .host_state() - .expect( - "host functions can be called only from wasm instance; - wasm instance is always called initializing context; - therefore host_ctx cannot be None; - qed - ", - ) - .clone(); - - let mut host_ctx = host_state.materialize(&mut caller); + let mut host_ctx = HostContext { caller: &mut caller }; // `from_wasmtime_val` panics if it encounters a value that doesn't fit into the values // available in substrate. diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index 1d40563d0a9ff..e9b18d8c2b89d 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -19,15 +19,12 @@ //! Defines data and logic needed for interaction with an WebAssembly instance of a substrate //! runtime module. -use crate::imports::Imports; - +use crate::runtime::{Store, StoreData}; use sc_executor_common::{ error::{Error, Result}, - util::checked_range, wasm_runtime::InvokeMethod, }; -use sp_wasm_interface::{Pointer, Value, WordSize}; -use std::marker; +use sp_wasm_interface::{Function, Pointer, Value, WordSize}; use wasmtime::{ AsContext, AsContextMut, Extern, Func, Global, Instance, Memory, Module, Table, Val, }; @@ -107,18 +104,8 @@ impl EntryPoint { /// routines. pub struct InstanceWrapper { instance: Instance, - - // The memory instance of the `instance`. - // - // It is important to make sure that we don't make any copies of this to make it easier to - // proof See `memory_as_slice` and `memory_as_slice_mut`. memory: Memory, - - /// Indirect functions table of the module - table: Option

, - - // Make this struct explicitly !Send & !Sync. - _not_send_nor_sync: marker::PhantomData<*const ()>, + store: Store, } fn extern_memory(extern_: &Extern) -> Option<&Memory> { @@ -153,11 +140,36 @@ impl InstanceWrapper { /// Create a new instance wrapper from the given wasm module. pub fn new( module: &Module, - imports: &Imports, + host_functions: &[&'static dyn Function], heap_pages: u64, - mut ctx: impl AsContextMut, + allow_missing_func_imports: bool, + max_memory_size: Option, ) -> Result { - let instance = Instance::new(&mut ctx, module, &imports.externs) + let limits = if let Some(max_memory_size) = max_memory_size { + wasmtime::StoreLimitsBuilder::new().memory_size(max_memory_size).build() + } else { + Default::default() + }; + + let mut store = Store::new( + module.engine(), + StoreData { limits, host_state: None, memory: None, table: None }, + ); + if max_memory_size.is_some() { + store.limiter(|s| &mut s.limits); + } + + // Scan all imports, find the matching host functions, and create stubs that adapt arguments + // and results. + let imports = crate::imports::resolve_imports( + &mut store, + module, + host_functions, + heap_pages, + allow_missing_func_imports, + )?; + + let instance = Instance::new(&mut store, module, &imports.externs) .map_err(|e| Error::from(format!("cannot instantiate: {}", e)))?; let memory = match imports.memory_import_index { @@ -165,55 +177,56 @@ impl InstanceWrapper { .expect("only memory can be at the `memory_idx`; qed") .clone(), None => { - let memory = get_linear_memory(&instance, &mut ctx)?; - if !memory.grow(&mut ctx, heap_pages).is_ok() { + let memory = get_linear_memory(&instance, &mut store)?; + if !memory.grow(&mut store, heap_pages).is_ok() { return Err("failed top increase the linear memory size".into()) } memory }, }; - let table = get_table(&instance, ctx); + let table = get_table(&instance, &mut store); + + store.data_mut().memory = Some(memory); + store.data_mut().table = table; - Ok(Self { table, instance, memory, _not_send_nor_sync: marker::PhantomData }) + Ok(Self { instance, memory, store }) } /// Resolves a substrate entrypoint by the given name. /// /// An entrypoint must have a signature `(i32, i32) -> i64`, otherwise this function will return /// an error. - pub fn resolve_entrypoint( - &self, - method: InvokeMethod, - mut ctx: impl AsContextMut, - ) -> Result { + pub fn resolve_entrypoint(&mut self, method: InvokeMethod) -> Result { Ok(match method { InvokeMethod::Export(method) => { // Resolve the requested method and verify that it has a proper signature. - let export = self.instance.get_export(&mut ctx, method).ok_or_else(|| { - Error::from(format!("Exported method {} is not found", method)) - })?; + let export = + self.instance.get_export(&mut self.store, method).ok_or_else(|| { + Error::from(format!("Exported method {} is not found", method)) + })?; let func = extern_func(&export) .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))? .clone(); - EntryPoint::direct(func, ctx).map_err(|_| { + EntryPoint::direct(func, &self.store).map_err(|_| { Error::from(format!("Exported function '{}' has invalid signature.", method)) })? }, InvokeMethod::Table(func_ref) => { let table = self .instance - .get_table(&mut ctx, "__indirect_function_table") + .get_table(&mut self.store, "__indirect_function_table") .ok_or(Error::NoTable)?; - let val = - table.get(&mut ctx, func_ref).ok_or(Error::NoTableEntryWithIndex(func_ref))?; + let val = table + .get(&mut self.store, func_ref) + .ok_or(Error::NoTableEntryWithIndex(func_ref))?; let func = val .funcref() .ok_or(Error::TableElementIsNotAFunction(func_ref))? .ok_or(Error::FunctionRefIsNull(func_ref))? .clone(); - EntryPoint::direct(func, ctx).map_err(|_| { + EntryPoint::direct(func, &self.store).map_err(|_| { Error::from(format!( "Function @{} in exported table has invalid signature for direct call.", func_ref, @@ -223,10 +236,10 @@ impl InstanceWrapper { InvokeMethod::TableWithWrapper { dispatcher_ref, func } => { let table = self .instance - .get_table(&mut ctx, "__indirect_function_table") + .get_table(&mut self.store, "__indirect_function_table") .ok_or(Error::NoTable)?; let val = table - .get(&mut ctx, dispatcher_ref) + .get(&mut self.store, dispatcher_ref) .ok_or(Error::NoTableEntryWithIndex(dispatcher_ref))?; let dispatcher = val .funcref() @@ -234,7 +247,7 @@ impl InstanceWrapper { .ok_or(Error::FunctionRefIsNull(dispatcher_ref))? .clone(); - EntryPoint::wrapped(dispatcher, func, ctx).map_err(|_| { + EntryPoint::wrapped(dispatcher, func, &self.store).map_err(|_| { Error::from(format!( "Function @{} in exported table has invalid signature for wrapped call.", dispatcher_ref, @@ -244,25 +257,20 @@ impl InstanceWrapper { }) } - /// Returns an indirect function table of this instance. - pub fn table(&self) -> Option<&Table> { - self.table.as_ref() - } - /// Reads `__heap_base: i32` global variable and returns it. /// /// If it doesn't exist, not a global or of not i32 type returns an error. - pub fn extract_heap_base(&self, mut ctx: impl AsContextMut) -> Result { + pub fn extract_heap_base(&mut self) -> Result { let heap_base_export = self .instance - .get_export(&mut ctx, "__heap_base") + .get_export(&mut self.store, "__heap_base") .ok_or_else(|| Error::from("__heap_base is not found"))?; let heap_base_global = extern_global(&heap_base_export) .ok_or_else(|| Error::from("__heap_base is not a global"))?; let heap_base = heap_base_global - .get(&mut ctx) + .get(&mut self.store) .i32() .ok_or_else(|| Error::from("__heap_base is not a i32"))?; @@ -270,15 +278,15 @@ impl InstanceWrapper { } /// Get the value from a global with the given `name`. - pub fn get_global_val(&self, mut ctx: impl AsContextMut, name: &str) -> Result> { - let global = match self.instance.get_export(&mut ctx, name) { + pub fn get_global_val(&mut self, name: &str) -> Result> { + let global = match self.instance.get_export(&mut self.store, name) { Some(global) => global, None => return Ok(None), }; let global = extern_global(&global).ok_or_else(|| format!("`{}` is not a global", name))?; - match global.get(ctx) { + match global.get(&mut self.store) { Val::I32(val) => Ok(Some(Value::I32(val))), Val::I64(val) => Ok(Some(Value::I64(val))), Val::F32(val) => Ok(Some(Value::F32(val))), @@ -288,8 +296,8 @@ impl InstanceWrapper { } /// Get a global with the given `name`. - pub fn get_global(&self, ctx: impl AsContextMut, name: &str) -> Option { - self.instance.get_global(ctx, name) + pub fn get_global(&mut self, name: &str) -> Option { + self.instance.get_global(&mut self.store, name) } } @@ -307,7 +315,7 @@ fn get_linear_memory(instance: &Instance, ctx: impl AsContextMut) -> Result Option
{ +fn get_table(instance: &Instance, ctx: &mut Store) -> Option
{ instance .get_export(ctx, "__indirect_function_table") .as_ref() @@ -317,97 +325,16 @@ fn get_table(instance: &Instance, ctx: impl AsContextMut) -> Option
{ /// Functions related to memory. impl InstanceWrapper { - /// Read data from a slice of memory into a newly allocated buffer. - /// - /// Returns an error if the read would go out of the memory bounds. - pub fn read_memory( - &self, - ctx: impl AsContext, - source_addr: Pointer, - size: usize, - ) -> Result> { - let range = checked_range(source_addr.into(), size, self.memory.data_size(&ctx)) - .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; - - let mut buffer = vec![0; range.len()]; - self.read_memory_into(ctx, source_addr, &mut buffer)?; - - Ok(buffer) - } - - /// Read data from the instance memory into a slice. - /// - /// Returns an error if the read would go out of the memory bounds. - pub fn read_memory_into( - &self, - ctx: impl AsContext, - address: Pointer, - dest: &mut [u8], - ) -> Result<()> { - let memory = self.memory.data(ctx.as_context()); - - let range = checked_range(address.into(), dest.len(), memory.len()) - .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; - dest.copy_from_slice(&memory[range]); - Ok(()) - } - - /// Write data to the instance memory from a slice. - /// - /// Returns an error if the write would go out of the memory bounds. - pub fn write_memory_from( - &self, - mut ctx: impl AsContextMut, - address: Pointer, - data: &[u8], - ) -> Result<()> { - let memory = self.memory.data_mut(ctx.as_context_mut()); - - let range = checked_range(address.into(), data.len(), memory.len()) - .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; - memory[range].copy_from_slice(data); - Ok(()) - } - - /// Allocate some memory of the given size. Returns pointer to the allocated memory region. - /// - /// Returns `Err` in case memory cannot be allocated. Refer to the allocator documentation - /// to get more details. - pub fn allocate( - &self, - mut ctx: impl AsContextMut, - allocator: &mut sc_allocator::FreeingBumpHeapAllocator, - size: WordSize, - ) -> Result> { - let memory = self.memory.data_mut(ctx.as_context_mut()); - - allocator.allocate(memory, size).map_err(Into::into) - } - - /// Deallocate the memory pointed by the given pointer. - /// - /// Returns `Err` in case the given memory region cannot be deallocated. - pub fn deallocate( - &self, - mut ctx: impl AsContextMut, - allocator: &mut sc_allocator::FreeingBumpHeapAllocator, - ptr: Pointer, - ) -> Result<()> { - let memory = self.memory.data_mut(ctx.as_context_mut()); - - allocator.deallocate(memory, ptr).map_err(Into::into) - } - /// Returns the pointer to the first byte of the linear memory for this instance. - pub fn base_ptr(&self, ctx: impl AsContext) -> *const u8 { - self.memory.data_ptr(ctx) + pub fn base_ptr(&self) -> *const u8 { + self.memory.data_ptr(&self.store) } /// If possible removes physical backing from the allocated linear memory which /// leads to returning the memory back to the system; this also zeroes the memory /// as a side-effect. - pub fn decommit(&self, mut ctx: impl AsContextMut) { - if self.memory.data_size(&ctx) == 0 { + pub fn decommit(&mut self) { + if self.memory.data_size(&self.store) == 0 { return } @@ -416,8 +343,8 @@ impl InstanceWrapper { use std::sync::Once; unsafe { - let ptr = self.memory.data_ptr(&ctx); - let len = self.memory.data_size(&ctx); + let ptr = self.memory.data_ptr(&self.store); + let len = self.memory.data_size(&self.store); // Linux handles MADV_DONTNEED reliably. The result is that the given area // is unmapped and will be zeroed on the next pagefault. @@ -438,6 +365,14 @@ impl InstanceWrapper { // If we're on an unsupported OS or the memory couldn't have been // decommited for some reason then just manually zero it out. - self.memory.data_mut(ctx.as_context_mut()).fill(0); + self.memory.data_mut(self.store.as_context_mut()).fill(0); + } + + pub(crate) fn store(&self) -> &Store { + &self.store + } + + pub(crate) fn store_mut(&mut self) -> &mut Store { + &mut self.store } } diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 7808ac7ce547d..606401132e9e9 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -20,7 +20,6 @@ use crate::{ host::HostState, - imports::{resolve_imports, Imports}, instance_wrapper::{EntryPoint, InstanceWrapper}, util, }; @@ -37,75 +36,98 @@ use sp_runtime_interface::unpack_ptr_and_len; use sp_wasm_interface::{Function, Pointer, Value, WordSize}; use std::{ path::{Path, PathBuf}, - rc::Rc, sync::{ atomic::{AtomicBool, Ordering}, Arc, }, }; -use wasmtime::{AsContext, AsContextMut, Engine, StoreLimits}; +use wasmtime::{Engine, Memory, StoreLimits, Table}; pub(crate) struct StoreData { - /// The limits we aply to the store. We need to store it here to return a reference to this + /// The limits we apply to the store. We need to store it here to return a reference to this /// object when we have the limits enabled. - limits: StoreLimits, + pub(crate) limits: StoreLimits, /// This will only be set when we call into the runtime. - host_state: Option>, + pub(crate) host_state: Option, + /// This will be always set once the store is initialized. + pub(crate) memory: Option, + /// This will be set only if the runtime actually contains a table. + pub(crate) table: Option
, } impl StoreData { /// Returns a reference to the host state. - pub fn host_state(&self) -> Option<&Rc> { + pub fn host_state(&self) -> Option<&HostState> { self.host_state.as_ref() } + + /// Returns a mutable reference to the host state. + pub fn host_state_mut(&mut self) -> Option<&mut HostState> { + self.host_state.as_mut() + } + + /// Returns the host memory. + pub fn memory(&self) -> Memory { + self.memory.expect("memory is always set; qed") + } + + /// Returns the host table. + pub fn table(&self) -> Option
{ + self.table + } } pub(crate) type Store = wasmtime::Store; enum Strategy { FastInstanceReuse { - instance_wrapper: Rc, + instance_wrapper: InstanceWrapper, globals_snapshot: GlobalsSnapshot, data_segments_snapshot: Arc, heap_base: u32, - store: Store, }, RecreateInstance(InstanceCreator), } struct InstanceCreator { - store: Store, module: Arc, - imports: Arc, + host_functions: Vec<&'static dyn Function>, heap_pages: u64, + allow_missing_func_imports: bool, + max_memory_size: Option, } impl InstanceCreator { fn instantiate(&mut self) -> Result { - InstanceWrapper::new(&*self.module, &*self.imports, self.heap_pages, &mut self.store) + InstanceWrapper::new( + &*self.module, + &self.host_functions, + self.heap_pages, + self.allow_missing_func_imports, + self.max_memory_size, + ) } } -struct InstanceGlobals<'a, C> { - ctx: &'a mut C, - instance: &'a InstanceWrapper, +struct InstanceGlobals<'a> { + instance: &'a mut InstanceWrapper, } -impl<'a, C: AsContextMut> runtime_blob::InstanceGlobals for InstanceGlobals<'a, C> { +impl<'a> runtime_blob::InstanceGlobals for InstanceGlobals<'a> { type Global = wasmtime::Global; fn get_global(&mut self, export_name: &str) -> Self::Global { self.instance - .get_global(&mut self.ctx, export_name) + .get_global(export_name) .expect("get_global is guaranteed to be called with an export name of a global; qed") } fn get_global_value(&mut self, global: &Self::Global) -> Value { - util::from_wasmtime_val(global.get(&mut self.ctx)) + util::from_wasmtime_val(global.get(&mut self.instance.store_mut())) } fn set_global_value(&mut self, global: &Self::Global, value: Value) { - global.set(&mut self.ctx, util::into_wasmtime_val(value)).expect( + global.set(&mut self.instance.store_mut(), util::into_wasmtime_val(value)).expect( "the value is guaranteed to be of the same value; the global is guaranteed to be mutable; qed", ); } @@ -124,50 +146,19 @@ pub struct WasmtimeRuntime { snapshot_data: Option, config: Config, host_functions: Vec<&'static dyn Function>, - engine: Engine, -} - -impl WasmtimeRuntime { - /// Creates the store respecting the set limits. - fn new_store(&self) -> Store { - let limits = if let Some(max_memory_size) = self.config.max_memory_size { - wasmtime::StoreLimitsBuilder::new().memory_size(max_memory_size).build() - } else { - Default::default() - }; - - let mut store = Store::new(&self.engine, StoreData { limits, host_state: None }); - - if self.config.max_memory_size.is_some() { - store.limiter(|s| &mut s.limits); - } - - store - } } impl WasmModule for WasmtimeRuntime { fn new_instance(&self) -> Result> { - let mut store = self.new_store(); - - // Scan all imports, find the matching host functions, and create stubs that adapt arguments - // and results. - // - // NOTE: Attentive reader may notice that this could've been moved in `WasmModule` creation. - // However, I am not sure if that's a good idea since it would be pushing our luck - // further by assuming that `Store` not only `Send` but also `Sync`. - let imports = resolve_imports( - &mut store, - &self.module, - &self.host_functions, - self.config.heap_pages, - self.config.allow_missing_func_imports, - )?; - let strategy = if let Some(ref snapshot_data) = self.snapshot_data { - let instance_wrapper = - InstanceWrapper::new(&self.module, &imports, self.config.heap_pages, &mut store)?; - let heap_base = instance_wrapper.extract_heap_base(&mut store)?; + let mut instance_wrapper = InstanceWrapper::new( + &self.module, + &self.host_functions, + self.config.heap_pages, + self.config.allow_missing_func_imports, + self.config.max_memory_size, + )?; + let heap_base = instance_wrapper.extract_heap_base()?; // This function panics if the instance was created from a runtime blob different from // which the mutable globals were collected. Here, it is easy to see that there is only @@ -175,22 +166,22 @@ impl WasmModule for WasmtimeRuntime { // instance and collecting the mutable globals. let globals_snapshot = GlobalsSnapshot::take( &snapshot_data.mutable_globals, - &mut InstanceGlobals { ctx: &mut store, instance: &instance_wrapper }, + &mut InstanceGlobals { instance: &mut instance_wrapper }, ); Strategy::FastInstanceReuse { - instance_wrapper: Rc::new(instance_wrapper), + instance_wrapper, globals_snapshot, data_segments_snapshot: snapshot_data.data_segments_snapshot.clone(), heap_base, - store, } } else { Strategy::RecreateInstance(InstanceCreator { - imports: Arc::new(imports), module: self.module.clone(), - store, + host_functions: self.host_functions.clone(), heap_pages: self.config.heap_pages, + allow_missing_func_imports: self.config.allow_missing_func_imports, + max_memory_size: self.config.max_memory_size, }) }; @@ -204,68 +195,52 @@ pub struct WasmtimeInstance { strategy: Strategy, } -// This is safe because `WasmtimeInstance` does not leak reference to `self.imports` -// and all imports don't reference anything, other than host functions and memory -unsafe impl Send for WasmtimeInstance {} - impl WasmInstance for WasmtimeInstance { fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result> { match &mut self.strategy { Strategy::FastInstanceReuse { - instance_wrapper, + ref mut instance_wrapper, globals_snapshot, data_segments_snapshot, heap_base, - ref mut store, } => { - let entrypoint = instance_wrapper.resolve_entrypoint(method, &mut *store)?; + let entrypoint = instance_wrapper.resolve_entrypoint(method)?; data_segments_snapshot.apply(|offset, contents| { - instance_wrapper.write_memory_from(&mut *store, Pointer::new(offset), contents) + util::write_memory_from( + instance_wrapper.store_mut(), + Pointer::new(offset), + contents, + ) })?; - globals_snapshot - .apply(&mut InstanceGlobals { ctx: &mut *store, instance: &*instance_wrapper }); + globals_snapshot.apply(&mut InstanceGlobals { instance: instance_wrapper }); let allocator = FreeingBumpHeapAllocator::new(*heap_base); - let result = perform_call( - &mut *store, - data, - instance_wrapper.clone(), - entrypoint, - allocator, - ); + let result = perform_call(data, instance_wrapper, entrypoint, allocator); // Signal to the OS that we are done with the linear memory and that it can be // reclaimed. - instance_wrapper.decommit(store); + instance_wrapper.decommit(); result }, Strategy::RecreateInstance(ref mut instance_creator) => { - let instance_wrapper = instance_creator.instantiate()?; - let heap_base = instance_wrapper.extract_heap_base(&mut instance_creator.store)?; - let entrypoint = - instance_wrapper.resolve_entrypoint(method, &mut instance_creator.store)?; + let mut instance_wrapper = instance_creator.instantiate()?; + let heap_base = instance_wrapper.extract_heap_base()?; + let entrypoint = instance_wrapper.resolve_entrypoint(method)?; let allocator = FreeingBumpHeapAllocator::new(heap_base); - perform_call( - &mut instance_creator.store, - data, - Rc::new(instance_wrapper), - entrypoint, - allocator, - ) + perform_call(data, &mut instance_wrapper, entrypoint, allocator) }, } } fn get_global_const(&mut self, name: &str) -> Result> { match &mut self.strategy { - Strategy::FastInstanceReuse { instance_wrapper, ref mut store, .. } => - instance_wrapper.get_global_val(&mut *store, name), - Strategy::RecreateInstance(ref mut instance_creator) => instance_creator - .instantiate()? - .get_global_val(&mut instance_creator.store, name), + Strategy::FastInstanceReuse { instance_wrapper, .. } => + instance_wrapper.get_global_val(name), + Strategy::RecreateInstance(ref mut instance_creator) => + instance_creator.instantiate()?.get_global_val(name), } } @@ -276,8 +251,8 @@ impl WasmInstance for WasmtimeInstance { // associated with it. None }, - Strategy::FastInstanceReuse { instance_wrapper, store, .. } => - Some(instance_wrapper.base_ptr(&store)), + Strategy::FastInstanceReuse { instance_wrapper, .. } => + Some(instance_wrapper.base_ptr()), } } } @@ -591,7 +566,7 @@ unsafe fn do_create_runtime( }, }; - Ok(WasmtimeRuntime { module: Arc::new(module), snapshot_data, config, host_functions, engine }) + Ok(WasmtimeRuntime { module: Arc::new(module), snapshot_data, config, host_functions }) } fn instrument( @@ -627,50 +602,51 @@ pub fn prepare_runtime_artifact( } fn perform_call( - mut ctx: impl AsContextMut, data: &[u8], - instance_wrapper: Rc, + instance_wrapper: &mut InstanceWrapper, entrypoint: EntryPoint, mut allocator: FreeingBumpHeapAllocator, ) -> Result> { - let (data_ptr, data_len) = - inject_input_data(&mut ctx, &instance_wrapper, &mut allocator, data)?; + let (data_ptr, data_len) = inject_input_data(instance_wrapper, &mut allocator, data)?; - let host_state = HostState::new(allocator, instance_wrapper.clone()); + let host_state = HostState::new(allocator); // Set the host state before calling into wasm. - ctx.as_context_mut().data_mut().host_state = Some(Rc::new(host_state)); + instance_wrapper.store_mut().data_mut().host_state = Some(host_state); - let ret = entrypoint.call(&mut ctx, data_ptr, data_len).map(unpack_ptr_and_len); + let ret = entrypoint + .call(instance_wrapper.store_mut(), data_ptr, data_len) + .map(unpack_ptr_and_len); // Reset the host state - ctx.as_context_mut().data_mut().host_state = None; + instance_wrapper.store_mut().data_mut().host_state = None; let (output_ptr, output_len) = ret?; - let output = extract_output_data(ctx, &instance_wrapper, output_ptr, output_len)?; + let output = extract_output_data(instance_wrapper, output_ptr, output_len)?; Ok(output) } fn inject_input_data( - mut ctx: impl AsContextMut, - instance: &InstanceWrapper, + instance: &mut InstanceWrapper, allocator: &mut FreeingBumpHeapAllocator, data: &[u8], ) -> Result<(Pointer, WordSize)> { + let mut ctx = instance.store_mut(); + let memory = ctx.data().memory(); + let memory = memory.data_mut(&mut ctx); let data_len = data.len() as WordSize; - let data_ptr = instance.allocate(&mut ctx, allocator, data_len)?; - instance.write_memory_from(ctx, data_ptr, data)?; + let data_ptr = allocator.allocate(memory, data_len)?; + util::write_memory_from(instance.store_mut(), data_ptr, data)?; Ok((data_ptr, data_len)) } fn extract_output_data( - ctx: impl AsContext, instance: &InstanceWrapper, output_ptr: u32, output_len: u32, ) -> Result> { let mut output = vec![0; output_len as usize]; - instance.read_memory_into(ctx, Pointer::new(output_ptr), &mut output)?; + util::read_memory_into(instance.store(), Pointer::new(output_ptr), &mut output)?; Ok(output) } diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index 261afba0c6bc9..c34cbfad11138 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -310,3 +310,39 @@ fn test_max_memory_pages() { ) .unwrap(); } + +// This test takes quite a while to execute in a debug build (over 6 minutes on a TR 3970x) +// so it's ignored by default unless it was compiled with `--release`. +#[cfg_attr(build_type = "debug", ignore)] +#[test] +fn test_instances_without_reuse_are_not_leaked() { + use sp_wasm_interface::HostFunctions; + + let runtime = crate::create_runtime( + RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(), + crate::Config { + heap_pages: 2048, + max_memory_size: None, + allow_missing_func_imports: true, + cache_path: None, + semantics: crate::Semantics { + fast_instance_reuse: false, + deterministic_stack_limit: None, + canonicalize_nans: false, + parallel_compilation: true, + }, + }, + sp_io::SubstrateHostFunctions::host_functions(), + ) + .unwrap(); + + // As long as the `wasmtime`'s `Store` lives the instances spawned through it + // will live indefinitely. Currently it has a maximum limit of 10k instances, + // so let's spawn 10k + 1 of them to make sure our code doesn't keep the `Store` + // alive longer than it is necessary. (And since we disabled instance reuse + // a new instance will be spawned on each call.) + let mut instance = runtime.new_instance().unwrap(); + for _ in 0..10001 { + instance.call_export("test_empty_return", &[0]).unwrap(); + } +} diff --git a/client/executor/wasmtime/src/util.rs b/client/executor/wasmtime/src/util.rs index 2c135fe7a343b..2c9379e9ce812 100644 --- a/client/executor/wasmtime/src/util.rs +++ b/client/executor/wasmtime/src/util.rs @@ -16,7 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use sp_wasm_interface::Value; +use crate::runtime::StoreData; +use sc_executor_common::{ + error::{Error, Result}, + util::checked_range, +}; +use sp_wasm_interface::{Pointer, Value}; +use wasmtime::{AsContext, AsContextMut}; /// Converts a [`wasmtime::Val`] into a substrate runtime interface [`Value`]. /// @@ -41,3 +47,54 @@ pub fn into_wasmtime_val(value: Value) -> wasmtime::Val { Value::F64(f_bits) => wasmtime::Val::F64(f_bits), } } + +/// Read data from a slice of memory into a newly allocated buffer. +/// +/// Returns an error if the read would go out of the memory bounds. +pub(crate) fn read_memory( + ctx: impl AsContext, + source_addr: Pointer, + size: usize, +) -> Result> { + let range = + checked_range(source_addr.into(), size, ctx.as_context().data().memory().data_size(&ctx)) + .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; + + let mut buffer = vec![0; range.len()]; + read_memory_into(ctx, source_addr, &mut buffer)?; + + Ok(buffer) +} + +/// Read data from the instance memory into a slice. +/// +/// Returns an error if the read would go out of the memory bounds. +pub(crate) fn read_memory_into( + ctx: impl AsContext, + address: Pointer, + dest: &mut [u8], +) -> Result<()> { + let memory = ctx.as_context().data().memory().data(&ctx); + + let range = checked_range(address.into(), dest.len(), memory.len()) + .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; + dest.copy_from_slice(&memory[range]); + Ok(()) +} + +/// Write data to the instance memory from a slice. +/// +/// Returns an error if the write would go out of the memory bounds. +pub(crate) fn write_memory_from( + mut ctx: impl AsContextMut, + address: Pointer, + data: &[u8], +) -> Result<()> { + let memory = ctx.as_context().data().memory(); + let memory = memory.data_mut(&mut ctx); + + let range = checked_range(address.into(), data.len(), memory.len()) + .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; + memory[range].copy_from_slice(data); + Ok(()) +} From fe7c02941122bbe4a7956aff53739b62f575240d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 23 Nov 2021 09:39:43 +0100 Subject: [PATCH 0266/1472] frame-benchmarking: Fix `min-square` for `--steps=1` (#10323) --- frame/benchmarking/src/analysis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index 5ffb6e93c8fc3..6e0ffd23ee988 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -199,7 +199,7 @@ impl Analysis { } pub fn min_squares_iqr(r: &Vec, selector: BenchmarkSelector) -> Option { - if r[0].components.is_empty() { + if r[0].components.len() <= 1 { return Self::median_value(r, selector) } From 09252188126a94a40eae47b694a6c9d8f6f35662 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 23 Nov 2021 10:19:05 +0100 Subject: [PATCH 0267/1472] Put back consensus_engine, only accept its absence (#10345) --- client/chain-spec/src/chain_spec.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 8d8f62a5182cf..e8247d7314991 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -168,7 +168,9 @@ struct ClientSpec { #[serde(flatten)] extensions: E, // Never used, left only for backward compatibility. - #[serde(default, skip_serializing)] + // In a future version, a `skip_serializing` attribute should be added in order to no longer + // generate chain specs with this field. + #[serde(default)] consensus_engine: (), #[serde(skip_serializing)] #[allow(unused)] From 1d74e58d2c448a056e915f1672bc87c428e09cb0 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Tue, 23 Nov 2021 19:06:33 +0900 Subject: [PATCH 0268/1472] fix (#10342) --- frame/contracts/src/storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 41db0796717e4..2b994d66af7e6 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -182,7 +182,7 @@ where let outcome = child::kill_storage(&child_trie_info(&trie.trie_id), Some(remaining_key_budget)); let keys_removed = match outcome { - // This should not happen as our budget was large enough to remove all keys. + // This happens when our budget wasn't large enough to remove all keys. KillStorageResult::SomeRemaining(count) => count, KillStorageResult::AllRemoved(count) => { // We do not care to preserve order. The contract is deleted already and From c3de64869fc30da61ecb149b7903debddc46940e Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Tue, 23 Nov 2021 19:28:58 +0900 Subject: [PATCH 0269/1472] remove unused file (#10343) --- client/network/src/gossip.rs | 229 -------------------------- client/network/src/gossip/tests.rs | 250 ----------------------------- 2 files changed, 479 deletions(-) delete mode 100644 client/network/src/gossip.rs delete mode 100644 client/network/src/gossip/tests.rs diff --git a/client/network/src/gossip.rs b/client/network/src/gossip.rs deleted file mode 100644 index 0bc46b2164bcb..0000000000000 --- a/client/network/src/gossip.rs +++ /dev/null @@ -1,229 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Helper for sending rate-limited gossip messages. -//! -//! # Context -//! -//! The [`NetworkService`] struct provides a way to send notifications to a certain peer through -//! the [`NetworkService::notification_sender`] method. This method is quite low level and isn't -//! expected to be used directly. -//! -//! The [`QueuedSender`] struct provided by this module is built on top of -//! [`NetworkService::notification_sender`] and provides a cleaner way to send notifications. -//! -//! # Behaviour -//! -//! An instance of [`QueuedSender`] is specific to a certain combination of `PeerId` and -//! protocol name. It maintains a buffer of messages waiting to be sent out. The user of this API -//! is able to manipulate that queue, adding or removing obsolete messages. -//! -//! Creating a [`QueuedSender`] also returns a opaque `Future` whose responsibility it to -//! drain that queue and actually send the messages. If the substream with the given combination -//! of peer and protocol is closed, the queue is silently discarded. It is the role of the user -//! to track which peers we are connected to. -//! -//! In normal situations, messages sent through a [`QueuedSender`] will arrive in the same -//! order as they have been sent. -//! It is possible, in the situation of disconnects and reconnects, that messages arrive in a -//! different order. See also . -//! However, if multiple instances of [`QueuedSender`] exist for the same peer and protocol, or -//! if some other code uses the [`NetworkService`] to send notifications to this combination or -//! peer and protocol, then the notifications will be interleaved in an unpredictable way. -//! - -use crate::{ExHashT, NetworkService}; - -use async_std::sync::{Mutex, MutexGuard}; -use futures::prelude::*; -use futures::channel::mpsc::{channel, Receiver, Sender}; -use libp2p::PeerId; -use sp_runtime::traits::Block as BlockT; -use std::{ - borrow::Cow, - collections::VecDeque, - fmt, - sync::Arc, -}; - -#[cfg(test)] -mod tests; - -/// Notifications sender for a specific combination of network service, peer, and protocol. -pub struct QueuedSender { - /// Shared between the user-facing [`QueuedSender`] and the background future. - shared_message_queue: SharedMessageQueue, - /// Used to notify the background future to check for new messages in the message queue. - notify_background_future: Sender<()>, - /// Maximum number of elements in [`QueuedSender::shared_message_queue`]. - queue_size_limit: usize, -} - -impl QueuedSender { - /// Returns a new [`QueuedSender`] containing a queue of message for this specific - /// combination of peer and protocol. - /// - /// In addition to the [`QueuedSender`], also returns a `Future` whose role is to drive - /// the messages sending forward. - pub fn new( - service: Arc>, - peer_id: PeerId, - protocol: Cow<'static, str>, - queue_size_limit: usize, - messages_encode: F - ) -> (Self, impl Future + Send + 'static) - where - M: Send + 'static, - B: BlockT + 'static, - H: ExHashT, - F: Fn(M) -> Vec + Send + 'static, - { - let (notify_background_future, wait_for_sender) = channel(0); - - let shared_message_queue = Arc::new(Mutex::new( - VecDeque::with_capacity(queue_size_limit), - )); - - let background_future = create_background_future( - wait_for_sender, - service, - peer_id, - protocol, - shared_message_queue.clone(), - messages_encode - ); - - let sender = Self { - shared_message_queue, - notify_background_future, - queue_size_limit, - }; - - (sender, background_future) - } - - /// Locks the queue of messages towards this peer. - /// - /// The returned `Future` is expected to be ready quite quickly. - pub async fn lock_queue<'a>(&'a mut self) -> QueueGuard<'a, M> { - QueueGuard { - message_queue: self.shared_message_queue.lock().await, - queue_size_limit: self.queue_size_limit, - notify_background_future: &mut self.notify_background_future, - } - } - - /// Pushes a message to the queue, or discards it if the queue is full. - /// - /// The returned `Future` is expected to be ready quite quickly. - pub async fn queue_or_discard(&mut self, message: M) - where - M: Send + 'static - { - self.lock_queue().await.push_or_discard(message); - } -} - -impl fmt::Debug for QueuedSender { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("QueuedSender").finish() - } -} - -/// Locked queue of messages to the given peer. -/// -/// As long as this struct exists, the background future is asleep and the owner of the -/// [`QueueGuard`] is in total control of the message queue. Messages can only ever be sent out on -/// the network after the [`QueueGuard`] is dropped. -#[must_use] -pub struct QueueGuard<'a, M> { - message_queue: MutexGuard<'a, MessageQueue>, - /// Same as [`QueuedSender::queue_size_limit`]. - queue_size_limit: usize, - notify_background_future: &'a mut Sender<()>, -} - -impl<'a, M: Send + 'static> QueueGuard<'a, M> { - /// Pushes a message to the queue, or discards it if the queue is full. - /// - /// The message will only start being sent out after the [`QueueGuard`] is dropped. - pub fn push_or_discard(&mut self, message: M) { - if self.message_queue.len() < self.queue_size_limit { - self.message_queue.push_back(message); - } - } - - /// Calls `filter` for each message in the queue, and removes the ones for which `false` is - /// returned. - /// - /// > **Note**: The parameter of `filter` is a `&M` and not a `&mut M` (which would be - /// > better) because the underlying implementation relies on `VecDeque::retain`. - pub fn retain(&mut self, filter: impl FnMut(&M) -> bool) { - self.message_queue.retain(filter); - } -} - -impl<'a, M> Drop for QueueGuard<'a, M> { - fn drop(&mut self) { - // Notify background future to check for new messages in the message queue. - let _ = self.notify_background_future.try_send(()); - } -} - -type MessageQueue = VecDeque; - -/// [`MessageQueue`] shared between [`QueuedSender`] and background future. -type SharedMessageQueue = Arc>>; - -async fn create_background_future Vec>( - mut wait_for_sender: Receiver<()>, - service: Arc>, - peer_id: PeerId, - protocol: Cow<'static, str>, - shared_message_queue: SharedMessageQueue, - messages_encode: F, -) { - loop { - if wait_for_sender.next().await.is_none() { - return - } - - loop { - let mut queue_guard = shared_message_queue.lock().await; - let next_message = match queue_guard.pop_front() { - Some(msg) => msg, - None => break, - }; - drop(queue_guard); - - // Starting from below, we try to send the message. If an error happens when sending, - // the only sane option we have is to silently discard the message. - let sender = match service.notification_sender(peer_id.clone(), protocol.clone()) { - Ok(s) => s, - Err(_) => continue, - }; - - let ready = match sender.ready().await { - Ok(r) => r, - Err(_) => continue, - }; - - let _ = ready.send(messages_encode(next_message)); - } - } -} diff --git a/client/network/src/gossip/tests.rs b/client/network/src/gossip/tests.rs deleted file mode 100644 index 88c4160bc5066..0000000000000 --- a/client/network/src/gossip/tests.rs +++ /dev/null @@ -1,250 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::block_request_handler::BlockRequestHandler; -use crate::state_request_handler::StateRequestHandler; -use crate::light_client_requests::handler::LightClientRequestHandler; -use crate::gossip::QueuedSender; -use crate::{config, Event, NetworkService, NetworkWorker}; - -use futures::prelude::*; -use sp_runtime::traits::{Block as BlockT, Header as _}; -use std::{borrow::Cow, sync::Arc, time::Duration}; -use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; - -type TestNetworkService = NetworkService< - substrate_test_runtime_client::runtime::Block, - substrate_test_runtime_client::runtime::Hash, ->; - -/// Builds a full node to be used for testing. Returns the node service and its associated events -/// stream. -/// -/// > **Note**: We return the events stream in order to not possibly lose events between the -/// > construction of the service and the moment the events stream is grabbed. -fn build_test_full_node(network_config: config::NetworkConfiguration) - -> (Arc, impl Stream) -{ - let client = Arc::new( - TestClientBuilder::with_default_backend() - .build_with_longest_chain() - .0, - ); - - #[derive(Clone)] - struct PassThroughVerifier(bool); - - #[async_trait::async_trait] - impl sc_consensus::Verifier for PassThroughVerifier { - async fn verify( - &mut self, - mut block: sp_consensus::BlockImportParams, - ) -> Result< - ( - sc_consensus::BlockImportParams, - Option)>>, - ), - String, - > { - let maybe_keys = block.header - .digest() - .log(|l| { - l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"aura")) - .or_else(|| { - l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"babe")) - }) - }) - .map(|blob| { - vec![( - sp_blockchain::well_known_cache_keys::AUTHORITIES, - blob.to_vec(), - )] - }); - - block.finalized = self.0; - block.fork_choice = Some(sc_consensus::ForkChoiceStrategy::LongestChain); - Ok((block, maybe_keys)) - } - } - - let import_queue = Box::new(sc_consensus::BasicQueue::new( - PassThroughVerifier(false), - Box::new(client.clone()), - None, - &sp_core::testing::TaskExecutor::new(), - None, - )); - - let protocol_id = config::ProtocolId::from("/test-protocol-name"); - - let block_request_protocol_config = { - let (handler, protocol_config) = BlockRequestHandler::new( - &protocol_id, - client.clone(), - 50, - ); - async_std::task::spawn(handler.run().boxed()); - protocol_config - }; - - let state_request_protocol_config = { - let (handler, protocol_config) = StateRequestHandler::new( - &protocol_id, - client.clone(), - 50, - ); - async_std::task::spawn(handler.run().boxed()); - protocol_config - }; - - let light_client_request_protocol_config = { - let (handler, protocol_config) = LightClientRequestHandler::new( - &protocol_id, - client.clone(), - ); - async_std::task::spawn(handler.run().boxed()); - protocol_config - }; - - let worker = NetworkWorker::new(config::Params { - role: config::Role::Full, - executor: None, - transactions_handler_executor: Box::new(|task| { async_std::task::spawn(task); }), - network_config, - chain: client.clone(), - on_demand: None, - transaction_pool: Arc::new(crate::config::EmptyTransactionPool), - protocol_id, - import_queue, - block_announce_validator: Box::new( - sp_consensus::block_validation::DefaultBlockAnnounceValidator, - ), - metrics_registry: None, - block_request_protocol_config, - state_request_protocol_config, - light_client_request_protocol_config, - warp_sync: None, - }) - .unwrap(); - - let service = worker.service().clone(); - let event_stream = service.event_stream("test"); - - async_std::task::spawn(async move { - futures::pin_mut!(worker); - let _ = worker.await; - }); - - (service, event_stream) -} - -const PROTOCOL_NAME: Cow<'static, str> = Cow::Borrowed("/foo"); - -/// Builds two nodes and their associated events stream. -/// The nodes are connected together and have the `PROTOCOL_NAME` protocol registered. -fn build_nodes_one_proto() - -> (Arc, impl Stream, Arc, impl Stream) -{ - let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - - let (node1, events_stream1) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![ - config::NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME, - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - set_config: Default::default() - } - ], - listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, - .. config::NetworkConfiguration::new_local() - }); - - let (node2, events_stream2) = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![], - extra_sets: vec![ - config::NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME, - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - set_config: config::SetConfig { - reserved_nodes: vec![config::MultiaddrWithPeerId { - multiaddr: listen_addr, - peer_id: node1.local_peer_id().clone(), - }], - .. Default::default() - }, - } - ], - transport: config::TransportConfig::MemoryOnly, - .. config::NetworkConfiguration::new_local() - }); - - (node1, events_stream1, node2, events_stream2) -} - -#[test] -fn basic_works() { - const NUM_NOTIFS: usize = 256; - - let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); - let node2_id = node2.local_peer_id().clone(); - - let receiver = async_std::task::spawn(async move { - let mut received_notifications = 0; - - while received_notifications < NUM_NOTIFS { - match events_stream2.next().await.unwrap() { - Event::NotificationStreamClosed { .. } => panic!(), - Event::NotificationsReceived { messages, .. } => { - for message in messages { - assert_eq!(message.0, PROTOCOL_NAME); - assert_eq!(message.1, &b"message"[..]); - received_notifications += 1; - } - } - _ => {} - }; - - if rand::random::() < 2 { - async_std::task::sleep(Duration::from_millis(rand::random::() % 750)).await; - } - } - }); - - async_std::task::block_on(async move { - let (mut sender, bg_future) = - QueuedSender::new(node1, node2_id, PROTOCOL_NAME, NUM_NOTIFS, |msg| msg); - async_std::task::spawn(bg_future); - - // Wait for the `NotificationStreamOpened`. - loop { - match events_stream1.next().await.unwrap() { - Event::NotificationStreamOpened { .. } => break, - _ => {} - }; - } - - for _ in 0..NUM_NOTIFS { - sender.queue_or_discard(b"message".to_vec()).await; - } - - receiver.await; - }); -} From 7a531b08ae8ea975dc868ed2a6fa4f4856c0816a Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Tue, 23 Nov 2021 21:04:05 +0800 Subject: [PATCH 0270/1472] Support MMR Pruning (#9700) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use `0.3.2` * Replace `u64` with `NodeIndex` * Fix Typo * Add Pruning Logic * Fix Some Tests * Remove Comment * Log Only Under STD * Return while No Element to Append * Optimize Pruning Algorithm * Update Doc * Update Doc * Zero Copy Algorithm * Import Missing Type * Fix Merge Mistake * Import Missing Item * Make `verify` Off-Chain * `cargo fmt` * Avoid using NodeIndex in incorrect places. * Simplify pruning. * Format Co-authored-by: Tomasz Drwięga --- Cargo.lock | 4 +- bin/node/runtime/src/lib.rs | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- .../primitives/src/lib.rs | 16 ++- frame/merkle-mountain-range/rpc/src/lib.rs | 6 +- .../merkle-mountain-range/src/benchmarking.rs | 2 +- frame/merkle-mountain-range/src/lib.rs | 14 +-- frame/merkle-mountain-range/src/mmr/mmr.rs | 14 +-- .../merkle-mountain-range/src/mmr/storage.rs | 99 +++++++++++++++---- frame/merkle-mountain-range/src/mmr/utils.rs | 14 +-- frame/merkle-mountain-range/src/tests.rs | 49 +++++++-- 11 files changed, 163 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a45e0accd49b7..0091223b09e6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -936,9 +936,9 @@ dependencies = [ [[package]] name = "ckb-merkle-mountain-range" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e486fe53bb9f2ca0f58cb60e8679a5354fd6687a839942ef0a75967250289ca6" +checksum = "4f061f97d64fd1822664bdfb722f7ae5469a97b77567390f7442be5b5dc82a5b" dependencies = [ "cfg-if 0.1.10", ] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 5b3c0685d1a2a..299b7257f9d45 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1559,7 +1559,7 @@ impl_runtime_apis! { Block, mmr::Hash, > for Runtime { - fn generate_proof(leaf_index: u64) + fn generate_proof(leaf_index: pallet_mmr::primitives::LeafIndex) -> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof), mmr::Error> { Mmr::generate_proof(leaf_index) diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index ca09725769ab2..2ff8b16fa4bde 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, version = "0.3.1" } +mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, version = "0.3.2" } sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } diff --git a/frame/merkle-mountain-range/primitives/src/lib.rs b/frame/merkle-mountain-range/primitives/src/lib.rs index dac57bd42cd35..9aae26508f3c4 100644 --- a/frame/merkle-mountain-range/primitives/src/lib.rs +++ b/frame/merkle-mountain-range/primitives/src/lib.rs @@ -26,6 +26,16 @@ use sp_std::fmt; #[cfg(not(feature = "std"))] use sp_std::prelude::Vec; +/// A type to describe node position in the MMR (node index). +pub type NodeIndex = u64; + +/// A type to describe leaf position in the MMR. +/// +/// Note this is different from [`NodeIndex`], which can be applied to +/// both leafs and inner nodes. Leafs will always have consecutive `LeafIndex`, +/// but might be actually at different positions in the MMR `NodeIndex`. +pub type LeafIndex = u64; + /// A provider of the MMR's leaf data. pub trait LeafDataProvider { /// A type that should end up in the leaf of MMR. @@ -275,9 +285,9 @@ impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3, E:4); #[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq)] pub struct Proof { /// The index of the leaf the proof is for. - pub leaf_index: u64, + pub leaf_index: LeafIndex, /// Number of leaves in MMR, when the proof was generated. - pub leaf_count: u64, + pub leaf_count: NodeIndex, /// Proof elements (hashes of siblings of inner nodes on the path to the leaf). pub items: Vec, } @@ -402,7 +412,7 @@ sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. pub trait MmrApi { /// Generate MMR proof for a leaf under given index. - fn generate_proof(leaf_index: u64) -> Result<(EncodableOpaqueLeaf, Proof), Error>; + fn generate_proof(leaf_index: LeafIndex) -> Result<(EncodableOpaqueLeaf, Proof), Error>; /// Verify MMR proof against on-chain MMR. /// diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 4719893778f6a..004a70a8e962e 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -32,7 +32,7 @@ use sp_blockchain::HeaderBackend; use sp_core::Bytes; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; -pub use pallet_mmr_primitives::MmrApi as MmrRuntimeApi; +pub use pallet_mmr_primitives::{LeafIndex, MmrApi as MmrRuntimeApi}; /// Retrieved MMR leaf and its proof. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] @@ -71,7 +71,7 @@ pub trait MmrApi { #[rpc(name = "mmr_generateProof")] fn generate_proof( &self, - leaf_index: u64, + leaf_index: LeafIndex, at: Option, ) -> Result>; } @@ -98,7 +98,7 @@ where { fn generate_proof( &self, - leaf_index: u64, + leaf_index: LeafIndex, at: Option<::Hash>, ) -> Result::Hash>> { let api = self.client.runtime_api(); diff --git a/frame/merkle-mountain-range/src/benchmarking.rs b/frame/merkle-mountain-range/src/benchmarking.rs index d6ef76d01ac3a..7c0dae26b3373 100644 --- a/frame/merkle-mountain-range/src/benchmarking.rs +++ b/frame/merkle-mountain-range/src/benchmarking.rs @@ -25,7 +25,7 @@ benchmarks_instance_pallet! { on_initialize { let x in 1 .. 1_000; - let leaves = x as u64; + let leaves = x as NodeIndex; }: { for b in 0..leaves { Pallet::::on_initialize((b as u32).into()); diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 01bf1b2254f09..12577880c5600 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -70,10 +70,10 @@ mod mock; mod tests; pub use pallet::*; -pub use pallet_mmr_primitives as primitives; +pub use pallet_mmr_primitives::{self as primitives, NodeIndex}; pub trait WeightInfo { - fn on_initialize(peaks: u64) -> Weight; + fn on_initialize(peaks: NodeIndex) -> Weight; } #[frame_support::pallet] @@ -160,7 +160,7 @@ pub mod pallet { /// Current size of the MMR (number of leaves). #[pallet::storage] #[pallet::getter(fn mmr_leaves)] - pub type NumberOfLeaves = StorageValue<_, u64, ValueQuery>; + pub type NumberOfLeaves = StorageValue<_, NodeIndex, ValueQuery>; /// Hashes of the nodes in the MMR. /// @@ -169,7 +169,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn mmr_peak)] pub type Nodes, I: 'static = ()> = - StorageMap<_, Identity, u64, >::Hash, OptionQuery>; + StorageMap<_, Identity, NodeIndex, >::Hash, OptionQuery>; #[pallet::hooks] impl, I: 'static> Hooks> for Pallet { @@ -228,7 +228,7 @@ where } impl, I: 'static> Pallet { - fn offchain_key(pos: u64) -> sp_std::prelude::Vec { + fn offchain_key(pos: NodeIndex) -> sp_std::prelude::Vec { (T::INDEXING_PREFIX, pos).encode() } @@ -239,7 +239,7 @@ impl, I: 'static> Pallet { /// all the leaves to be present. /// It may return an error or panic if used incorrectly. pub fn generate_proof( - leaf_index: u64, + leaf_index: NodeIndex, ) -> Result<(LeafOf, primitives::Proof<>::Hash>), primitives::Error> { let mmr: ModuleMmr = mmr::Mmr::new(Self::mmr_leaves()); mmr.generate_proof(leaf_index) @@ -263,7 +263,7 @@ impl, I: 'static> Pallet { .log_debug("The proof has incorrect number of leaves or proof items.")) } - let mmr: ModuleMmr = mmr::Mmr::new(proof.leaf_count); + let mmr: ModuleMmr = mmr::Mmr::new(proof.leaf_count); let is_valid = mmr.verify_leaf_proof(leaf, proof)?; if is_valid { Ok(()) diff --git a/frame/merkle-mountain-range/src/mmr/mmr.rs b/frame/merkle-mountain-range/src/mmr/mmr.rs index d5036e58f432e..a1963275a0cde 100644 --- a/frame/merkle-mountain-range/src/mmr/mmr.rs +++ b/frame/merkle-mountain-range/src/mmr/mmr.rs @@ -21,7 +21,7 @@ use crate::{ utils::NodesUtils, Hasher, Node, NodeOf, }, - primitives::{self, Error}, + primitives::{self, Error, NodeIndex}, Config, HashingOf, }; #[cfg(not(feature = "std"))] @@ -60,7 +60,7 @@ where Storage: mmr_lib::MMRStore>, { mmr: mmr_lib::MMR, Hasher, L>, Storage>, - leaves: u64, + leaves: NodeIndex, } impl Mmr @@ -71,7 +71,7 @@ where Storage: mmr_lib::MMRStore>, { /// Create a pointer to an existing MMR with given number of leaves. - pub fn new(leaves: u64) -> Self { + pub fn new(leaves: NodeIndex) -> Self { let size = NodesUtils::new(leaves).size(); Self { mmr: mmr_lib::MMR::new(size, Default::default()), leaves } } @@ -94,7 +94,7 @@ where /// Return the internal size of the MMR (number of nodes). #[cfg(test)] - pub fn size(&self) -> u64 { + pub fn size(&self) -> NodeIndex { self.mmr.mmr_size() } } @@ -109,7 +109,7 @@ where /// Push another item to the MMR. /// /// Returns element position (index) in the MMR. - pub fn push(&mut self, leaf: L) -> Option { + pub fn push(&mut self, leaf: L) -> Option { let position = self.mmr.push(Node::Data(leaf)).map_err(|e| Error::Push.log_error(e)).ok()?; @@ -120,7 +120,7 @@ where /// Commit the changes to underlying storage, return current number of leaves and /// calculate the new MMR's root hash. - pub fn finalize(self) -> Result<(u64, >::Hash), Error> { + pub fn finalize(self) -> Result<(NodeIndex, >::Hash), Error> { let root = self.mmr.get_root().map_err(|e| Error::GetRoot.log_error(e))?; self.mmr.commit().map_err(|e| Error::Commit.log_error(e))?; Ok((self.leaves, root.hash())) @@ -140,7 +140,7 @@ where /// (i.e. you can't run the function in the pruned storage). pub fn generate_proof( &self, - leaf_index: u64, + leaf_index: NodeIndex, ) -> Result<(L, primitives::Proof<>::Hash>), Error> { let position = mmr_lib::leaf_index_to_pos(leaf_index); let store = >::default(); diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index 09e24017816ec..6e4bf91d802fa 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -18,19 +18,24 @@ //! A MMR storage implementations. use codec::Encode; +use frame_support::log; +use mmr_lib::helper; +use sp_io::offchain_index; +use sp_std::iter::Peekable; #[cfg(not(feature = "std"))] -use sp_std::prelude::Vec; +use sp_std::prelude::*; use crate::{ - mmr::{Node, NodeOf}, - primitives, Config, Nodes, NumberOfLeaves, Pallet, + mmr::{utils::NodesUtils, Node, NodeOf}, + primitives::{self, NodeIndex}, + Config, Nodes, NumberOfLeaves, Pallet, }; /// A marker type for runtime-specific storage implementation. /// /// Allows appending new items to the MMR and proof verification. /// MMR nodes are appended to two different storages: -/// 1. We add nodes (leaves) hashes to the on-chain storge (see [crate::Nodes]). +/// 1. We add nodes (leaves) hashes to the on-chain storage (see [crate::Nodes]). /// 2. We add full leaves (and all inner nodes as well) into the `IndexingAPI` during block /// processing, so the values end up in the Offchain DB if indexing is enabled. pub struct RuntimeStorage; @@ -60,14 +65,14 @@ where I: 'static, L: primitives::FullLeaf + codec::Decode, { - fn get_elem(&self, pos: u64) -> mmr_lib::Result>> { + fn get_elem(&self, pos: NodeIndex) -> mmr_lib::Result>> { let key = Pallet::::offchain_key(pos); // Retrieve the element from Off-chain DB. Ok(sp_io::offchain::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) .and_then(|v| codec::Decode::decode(&mut &*v).ok())) } - fn append(&mut self, _: u64, _: Vec>) -> mmr_lib::Result<()> { + fn append(&mut self, _: NodeIndex, _: Vec>) -> mmr_lib::Result<()> { panic!("MMR must not be altered in the off-chain context.") } } @@ -78,32 +83,90 @@ where I: 'static, L: primitives::FullLeaf, { - fn get_elem(&self, pos: u64) -> mmr_lib::Result>> { + fn get_elem(&self, pos: NodeIndex) -> mmr_lib::Result>> { Ok(>::get(pos).map(Node::Hash)) } - fn append(&mut self, pos: u64, elems: Vec>) -> mmr_lib::Result<()> { - let mut leaves = crate::NumberOfLeaves::::get(); - let mut size = crate::mmr::utils::NodesUtils::new(leaves).size(); + fn append(&mut self, pos: NodeIndex, elems: Vec>) -> mmr_lib::Result<()> { + if elems.is_empty() { + return Ok(()) + } + + sp_std::if_std! { + log::trace!("elems: {:?}", elems.iter().map(|elem| elem.hash()).collect::>()); + } + + let leaves = NumberOfLeaves::::get(); + let size = NodesUtils::new(leaves).size(); + if pos != size { return Err(mmr_lib::Error::InconsistentStore) } + let new_size = size + elems.len() as NodeIndex; + + // A sorted (ascending) iterator over peak indices to prune and persist. + let (peaks_to_prune, mut peaks_to_store) = peaks_to_prune_and_store(size, new_size); + + // Now we are going to iterate over elements to insert + // and keep track of the current `node_index` and `leaf_index`. + let mut leaf_index = leaves; + let mut node_index = size; + for elem in elems { - // on-chain we only store the hash (even if it's a leaf) - >::insert(size, elem.hash()); - // Indexing API is used to store the full leaf content. - let key = Pallet::::offchain_key(size); - elem.using_encoded(|elem| sp_io::offchain_index::set(&key, elem)); - size += 1; + // Indexing API is used to store the full node content (both leaf and inner). + elem.using_encoded(|elem| { + offchain_index::set(&Pallet::::offchain_key(node_index), elem) + }); + + // On-chain we are going to only store new peaks. + if peaks_to_store.next_if_eq(&node_index).is_some() { + >::insert(node_index, elem.hash()); + } + // Increase the indices. if let Node::Data(..) = elem { - leaves += 1; + leaf_index += 1; } + node_index += 1; } - NumberOfLeaves::::put(leaves); + // Update current number of leaves. + NumberOfLeaves::::put(leaf_index); + + // And remove all remaining items from `peaks_before` collection. + for pos in peaks_to_prune { + >::remove(pos); + } Ok(()) } } + +fn peaks_to_prune_and_store( + old_size: NodeIndex, + new_size: NodeIndex, +) -> (impl Iterator, Peekable>) { + // A sorted (ascending) collection of peak indices before and after insertion. + // both collections may share a common prefix. + let peaks_before = if old_size == 0 { vec![] } else { helper::get_peaks(old_size) }; + let peaks_after = helper::get_peaks(new_size); + sp_std::if_std! { + log::trace!("peaks_before: {:?}", peaks_before); + log::trace!("peaks_after: {:?}", peaks_after); + } + let mut peaks_before = peaks_before.into_iter().peekable(); + let mut peaks_after = peaks_after.into_iter().peekable(); + + // Consume a common prefix between `peaks_before` and `peaks_after`, + // since that's something we will not be touching anyway. + while peaks_before.peek() == peaks_after.peek() { + peaks_before.next(); + peaks_after.next(); + } + + // what's left in both collections is: + // 1. Old peaks to remove from storage + // 2. New peaks to persist in storage + (peaks_before, peaks_after) +} diff --git a/frame/merkle-mountain-range/src/mmr/utils.rs b/frame/merkle-mountain-range/src/mmr/utils.rs index 8fc725f11e72f..77ce0e8ebbb36 100644 --- a/frame/merkle-mountain-range/src/mmr/utils.rs +++ b/frame/merkle-mountain-range/src/mmr/utils.rs @@ -17,29 +17,31 @@ //! Merkle Mountain Range utilities. +use crate::primitives::{LeafIndex, NodeIndex}; + /// MMR nodes & size -related utilities. pub struct NodesUtils { - no_of_leaves: u64, + no_of_leaves: LeafIndex, } impl NodesUtils { /// Create new instance of MMR nodes utilities for given number of leaves. - pub fn new(no_of_leaves: u64) -> Self { + pub fn new(no_of_leaves: LeafIndex) -> Self { Self { no_of_leaves } } /// Calculate number of peaks in the MMR. - pub fn number_of_peaks(&self) -> u64 { - self.number_of_leaves().count_ones() as u64 + pub fn number_of_peaks(&self) -> NodeIndex { + self.number_of_leaves().count_ones() as NodeIndex } /// Return the number of leaves in the MMR. - pub fn number_of_leaves(&self) -> u64 { + pub fn number_of_leaves(&self) -> LeafIndex { self.no_of_leaves } /// Calculate the total size of MMR (number of nodes). - pub fn size(&self) -> u64 { + pub fn size(&self) -> NodeIndex { 2 * self.no_of_leaves - self.number_of_peaks() } diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 50512e9286951..3faf2bfbd9c2f 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -15,9 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{mock::*, *}; +use crate::{mmr::utils, mock::*, *}; use frame_support::traits::OnInitialize; +use mmr_lib::helper; use pallet_mmr_primitives::{Compact, Proof}; use sp_core::{ offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt}, @@ -48,6 +49,12 @@ fn new_block() -> u64 { MMR::on_initialize(number) } +fn peaks_from_leaves_count(leaves_count: NodeIndex) -> Vec { + let size = utils::NodesUtils::new(leaves_count).size(); + + helper::get_peaks(size) +} + pub(crate) fn hex(s: &str) -> H256 { s.parse().unwrap() } @@ -115,10 +122,29 @@ fn should_append_to_mmr_when_on_initialize_is_called() { ext.execute_with(|| { // when new_block(); + + // then + assert_eq!(crate::NumberOfLeaves::::get(), 1); + assert_eq!( + ( + crate::Nodes::::get(0), + crate::Nodes::::get(1), + crate::RootHash::::get(), + ), + ( + Some(hex("4320435e8c3318562dba60116bdbcc0b82ffcecb9bb39aae3300cfda3ad0b8b0")), + None, + hex("0x4320435e8c3318562dba60116bdbcc0b82ffcecb9bb39aae3300cfda3ad0b8b0"), + ) + ); + + // when new_block(); // then assert_eq!(crate::NumberOfLeaves::::get(), 2); + let peaks = peaks_from_leaves_count(2); + assert_eq!(peaks, vec![2]); assert_eq!( ( crate::Nodes::::get(0), @@ -128,8 +154,8 @@ fn should_append_to_mmr_when_on_initialize_is_called() { crate::RootHash::::get(), ), ( - Some(hex("4320435e8c3318562dba60116bdbcc0b82ffcecb9bb39aae3300cfda3ad0b8b0")), - Some(hex("ad4cbc033833612ccd4626d5f023b9dfc50a35e838514dd1f3c86f8506728705")), + None, + None, Some(hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854")), None, hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854"), @@ -166,14 +192,21 @@ fn should_construct_larger_mmr_correctly() { // then assert_eq!(crate::NumberOfLeaves::::get(), 7); + let peaks = peaks_from_leaves_count(7); + assert_eq!(peaks, vec![6, 9, 10]); + for i in (0..=10).filter(|p| !peaks.contains(p)) { + assert!(crate::Nodes::::get(i).is_none()); + } assert_eq!( ( - crate::Nodes::::get(0), + crate::Nodes::::get(6), + crate::Nodes::::get(9), crate::Nodes::::get(10), crate::RootHash::::get(), ), ( - Some(hex("4320435e8c3318562dba60116bdbcc0b82ffcecb9bb39aae3300cfda3ad0b8b0")), + Some(hex("ae88a0825da50e953e7a359c55fe13c8015e48d03d301b8bdfc9193874da9252")), + Some(hex("7e4316ae2ebf7c3b6821cb3a46ca8b7a4f9351a9b40fcf014bb0a4fd8e8f29da")), Some(hex("611c2174c6164952a66d985cfe1ec1a623794393e3acff96b136d198f37a648c")), hex("e45e25259f7930626431347fa4dd9aae7ac83b4966126d425ca70ab343709d2c"), ) @@ -265,11 +298,7 @@ fn should_verify() { crate::Pallet::::generate_proof(5).unwrap() }); - // Now to verify the proof, we really shouldn't require offchain storage or extension. - // Hence we initialize the storage once again, using different externalities and then - // verify. - let mut ext2 = new_test_ext(); - ext2.execute_with(|| { + ext.execute_with(|| { init_chain(7); // then assert_eq!(crate::Pallet::::verify_leaf(leaf, proof5), Ok(())); From 1d8f7bf6de1f447b706a121c83e759da807d3a01 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 23 Nov 2021 17:04:06 +0100 Subject: [PATCH 0271/1472] [ci] Add ssh token for publishing gh-pages (#10338) * [ci] Added ssh token for publishing gh-pages * changed ssh commands for gh-pages * return github_token back to vault secrets * check simnet-tests-quick without vault secrets * remove vault secrets from simnet jobs --- .gitlab-ci.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aa275061088d6..8815ab15f640e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -204,6 +204,9 @@ default: GITHUB_PR_TOKEN: vault: cicd/gitlab/parity/GITHUB_PR_TOKEN@kv file: false + GITHUB_TOKEN: + vault: cicd/gitlab/parity/GITHUB_TOKEN@kv + file: false AWS_ACCESS_KEY_ID: vault: cicd/gitlab/$CI_PROJECT_PATH/AWS_ACCESS_KEY_ID@kv file: false @@ -228,9 +231,9 @@ default: GITHUB_RELEASE_TOKEN: vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_RELEASE_TOKEN@kv file: false - GITHUB_TOKEN: - vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_TOKEN@kv - file: false + GITHUB_SSH_PRIV_KEY: + vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_SSH_PRIV_KEY@kv + file: true GITHUB_USER: vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_USER@kv file: false @@ -809,12 +812,14 @@ publish-rustdoc: # Putting spaces at the front and back to ensure we are not matching just any substring, but the # whole space-separated value. - '[[ " ${RUSTDOCS_DEPLOY_REFS} " =~ " ${CI_COMMIT_REF_NAME} " ]] || exit 0' + # setup ssh + - apt-get update && apt-get install -y ssh - rm -rf /tmp/* # Set git config - - rm -rf .git/config + - git config core.sshCommand "ssh -i ${GITHUB_SSH_PRIV_KEY} -F /dev/null -o StrictHostKeyChecking=no" - git config user.email "devops-team@parity.io" - git config user.name "${GITHUB_USER}" - - git config remote.origin.url "https://${GITHUB_TOKEN}@github.com/paritytech/${CI_PROJECT_NAME}.git" + - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch origin gh-pages # Install `ejs` and generate index.html based on RUSTDOCS_DEPLOY_REFS @@ -909,7 +914,6 @@ simnet-tests: stage: deploy image: docker.io/paritytech/simnet:${SIMNET_REF} <<: *kubernetes-env - <<: *vault-secrets rules: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never @@ -939,7 +943,6 @@ simnet-tests-quick: stage: deploy image: docker.io/paritytech/simnet:${SIMNET_REF} <<: *kubernetes-env - <<: *vault-secrets <<: *test-refs-no-trigger-prs-only variables: SIMNET_FEATURES: "${SIMNET_FEATURES_PATH}/quick" From 7406442bea0194ffcafc4e8d48d895d4d8d11346 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 24 Nov 2021 10:42:44 +0100 Subject: [PATCH 0272/1472] [ci] Fix publish-rustdoc job (#10363) --- .gitlab-ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8815ab15f640e..0982ca5b4979e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -233,7 +233,7 @@ default: file: false GITHUB_SSH_PRIV_KEY: vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_SSH_PRIV_KEY@kv - file: true + file: false GITHUB_USER: vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_USER@kv file: false @@ -814,9 +814,12 @@ publish-rustdoc: - '[[ " ${RUSTDOCS_DEPLOY_REFS} " =~ " ${CI_COMMIT_REF_NAME} " ]] || exit 0' # setup ssh - apt-get update && apt-get install -y ssh + - eval $(ssh-agent) + - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} + - mkdir ~/.ssh && touch ~/.ssh/known_hosts + - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts - rm -rf /tmp/* # Set git config - - git config core.sshCommand "ssh -i ${GITHUB_SSH_PRIV_KEY} -F /dev/null -o StrictHostKeyChecking=no" - git config user.email "devops-team@parity.io" - git config user.name "${GITHUB_USER}" - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" From 3f657a56b3c9bfe14613d213efc6570292ffaf86 Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Wed, 24 Nov 2021 14:10:40 +0300 Subject: [PATCH 0273/1472] Introduce temporary GitLab & GHA benchmarking jobs (#10311) * Introduce temporary bench job * Add runner label * CI: bench GHA * CI: bench GHA * CI: docs * CI: more docs * CI: run on master only Co-authored-by: Denis P --- .github/workflows/bench_gh_gl.yaml | 75 ++++++++++++++++++++++++++++++ .gitlab-ci.yml | 29 ++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 .github/workflows/bench_gh_gl.yaml diff --git a/.github/workflows/bench_gh_gl.yaml b/.github/workflows/bench_gh_gl.yaml new file mode 100644 index 0000000000000..b243f7f661419 --- /dev/null +++ b/.github/workflows/bench_gh_gl.yaml @@ -0,0 +1,75 @@ +# Please do not tamper with this job, it's a part of benchmarking experiment. +# However, you absolutely can copy it into another file and redo the last job in the pipeline. +# Just make sure you won't introduce long queues to the GHA runner, we have just one at the moment. + +name: bench GHA against GitLab + +on: + push: + branches: [ master ] + +jobs: + bench_gh: + runs-on: self-hosted + env: + CARGO_INCREMENTAL: 0 + RUSTUP_HOME: /usr/local/rustup + CARGO_HOME: /usr/local/cargo + CC: clang + CXX: clang + + steps: + + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.9.1 + with: + access_token: ${{ github.token }} + + - name: Install dependencies + # Template job, one can copy it to another pipeline. + run: | + apt-get update + apt-get install -y --no-install-recommends time clang + update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100 + + - name: Install Rust + # Template job, one can copy it to another pipeline. + # Referance code https://github.com/paritytech/scripts/blob/master/dockerfiles/base-ci-linux/Dockerfile + # Better keep Rust versions here in sync with the CI image, otherwise the results will conflict. + run: | + curl -L "https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init" -o rustup-init + chmod +x rustup-init + ./rustup-init -y --no-modify-path --profile minimal --default-toolchain stable + rm rustup-init + # add rustup tp PATH so it's usable right away + echo "/usr/local/cargo/bin" >> $GITHUB_PATH + source /usr/local/cargo/env + chmod -R a+w ${RUSTUP_HOME} ${CARGO_HOME} + # install nightly toolchain + rustup toolchain install nightly-2021-11-08 --profile minimal --component rustfmt clippy + # link the pinned toolchain to nightly + ln -s /usr/local/rustup/toolchains/nightly-2021-11-08-x86_64-unknown-linux-gnu /usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu + rustup target add wasm32-unknown-unknown + rustup target add wasm32-unknown-unknown --toolchain nightly + # show versions + rustup show + cargo --version + # remove clutter from the installations + rm -rf "${CARGO_HOME}/registry" "${CARGO_HOME}/git" + + - name: Checkout sources + uses: actions/checkout@v2 + + - name: bench-GHA-test-full-crypto-feature + # GitHub env variables reference: https://docs.github.com/en/actions/learn-github-actions/environment-variables + # The important part of the experiment is the line with `curl`: it sends the job's timing to Prometheus. + run: | + START_TIME=`date '+%s'` + cd primitives/core/ + time cargo +nightly build --verbose --no-default-features --features full_crypto + cd ../application-crypto + time cargo +nightly build --verbose --no-default-features --features full_crypto + END_TIME=`date '+%s'` + TOTAL_TIME=`expr $END_TIME - $START_TIME` + # please remove this line if you want to play with GHA runner. + curl -d "parity_github_job_time{project=\"$GITHUB_REPOSITORY\",job=\"$GITHUB_WORKFLOW\",runner=\"github\"} $TOTAL_TIME" -X POST http://vm-longterm.parity-build.parity.io/api/v1/import/prometheus diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0982ca5b4979e..0b578f19d098b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -538,6 +538,35 @@ test-full-crypto-feature: - time cargo +nightly build --verbose --no-default-features --features full_crypto - sccache -s + +# Mostly same as the job above, additional instrumentation was added to push test run times +# to the time series database. +# This is temporary and will be eventually removed. +bench-test-full-crypto-feature: + stage: test + <<: *docker-env + <<: *build-refs + variables: + <<: *default-vars + RUSTFLAGS: "-Cdebug-assertions=y" + RUST_BACKTRACE: 1 + before_script: [""] + script: + # disable sccache for the bench purposes + - unset RUSTC_WRAPPER + - START_TIME=`date '+%s'` + - cd primitives/core/ + - time cargo +nightly build --verbose --no-default-features --features full_crypto + - cd ../application-crypto + - time cargo +nightly build --verbose --no-default-features --features full_crypto + - END_TIME=`date '+%s'` + - TOTAL_TIME=`expr $END_TIME - $START_TIME` + # send the job time measuring to the prometheus endpoint + - curl -d "parity_gitlab_job_time{project=\"$CI_PROJECT_PATH\",job=\"$CI_JOB_NAME\",runner=\"gitlab\"} $TOTAL_TIME" -X POST $VM_LONGTERM_URI/api/v1/import/prometheus + tags: + - linux-docker-compare + + test-wasmer-sandbox: stage: test <<: *docker-env From d732a9d82de5df570a8a849b4367365a3e18075c Mon Sep 17 00:00:00 2001 From: Alexander Popiak Date: Wed, 24 Nov 2021 14:39:11 +0100 Subject: [PATCH 0274/1472] derive Debug for CrateVersion and StorageVersion (#10355) --- frame/support/src/traits/metadata.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/support/src/traits/metadata.rs b/frame/support/src/traits/metadata.rs index 0da76f7585aca..50fb53fc57063 100644 --- a/frame/support/src/traits/metadata.rs +++ b/frame/support/src/traits/metadata.rs @@ -135,7 +135,7 @@ pub trait GetCallMetadata { } /// The version of a crate. -#[derive(RuntimeDebug, Eq, PartialEq, Encode, Decode, Clone, Copy, Default)] +#[derive(Debug, Eq, PartialEq, Encode, Decode, Clone, Copy, Default)] pub struct CrateVersion { /// The major version of the crate. pub major: u16, @@ -175,7 +175,7 @@ pub const STORAGE_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__STORAGE_VERSION__:"; /// /// Each storage version of a pallet is stored in the state under a fixed key. See /// [`STORAGE_VERSION_STORAGE_KEY_POSTFIX`] for how this key is built. -#[derive(RuntimeDebug, Eq, PartialEq, Encode, Decode, Ord, Clone, Copy, PartialOrd, Default)] +#[derive(Debug, Eq, PartialEq, Encode, Decode, Ord, Clone, Copy, PartialOrd, Default)] pub struct StorageVersion(u16); impl StorageVersion { From c519f0f11059e14ab40c868429ba91e7d2525f33 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 24 Nov 2021 16:00:03 +0100 Subject: [PATCH 0275/1472] [ci] Fix publish-rustdoc (#10364) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0b578f19d098b..b1987b834fef0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -842,12 +842,12 @@ publish-rustdoc: # whole space-separated value. - '[[ " ${RUSTDOCS_DEPLOY_REFS} " =~ " ${CI_COMMIT_REF_NAME} " ]] || exit 0' # setup ssh + # FIXME: add ssh to docker image - apt-get update && apt-get install -y ssh - eval $(ssh-agent) - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} - mkdir ~/.ssh && touch ~/.ssh/known_hosts - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts - - rm -rf /tmp/* # Set git config - git config user.email "devops-team@parity.io" - git config user.name "${GITHUB_USER}" From e9fca0f4d7a65998206f29baf0133a7931452104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 24 Nov 2021 18:20:55 +0100 Subject: [PATCH 0276/1472] Stabilize "seal1" seal_call (#10366) --- frame/contracts/src/wasm/mod.rs | 9 +++------ frame/contracts/src/wasm/runtime.rs | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 10aa0d19a04f7..6a807710a5265 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -541,11 +541,10 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn contract_call_forward_input() { const CODE: &str = r#" (module - (import "__unstable__" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) + (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "env" "memory" (memory 1 1)) (func (export "call") @@ -596,11 +595,10 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn contract_call_clone_input() { const CODE: &str = r#" (module - (import "__unstable__" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) + (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) @@ -652,11 +650,10 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn contract_call_tail_call() { const CODE: &str = r#" (module - (import "__unstable__" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) + (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) (func (export "call") (drop diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 883dfd0802483..204db09ed3e8d 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -928,7 +928,7 @@ define_env!(Env, , // `ReturnCode::BelowSubsistenceThreshold` // `ReturnCode::TransferFailed` // `ReturnCode::NotCallable` - [__unstable__] seal_call( + [seal1] seal_call( ctx, flags: u32, callee_ptr: u32, @@ -940,7 +940,7 @@ define_env!(Env, , output_len_ptr: u32 ) -> ReturnCode => { ctx.call( - CallFlags::from_bits(flags).ok_or_else(|| "used rerved bit in CallFlags")?, + CallFlags::from_bits(flags).ok_or_else(|| "used reserved bit in CallFlags")?, callee_ptr, gas, value_ptr, From 5e2bb785dd8858c12b2c7f85f59d143507bd9819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 24 Nov 2021 20:46:28 +0100 Subject: [PATCH 0277/1472] Enable wasmtime for aarch64 as well (#10367) --- bin/node/cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 1bb3671d42bae..42df74100415d 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -96,7 +96,7 @@ frame-benchmarking-cli = { version = "4.0.0-dev", optional = true, path = "../.. node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../utils/frame/try-runtime/cli" } -[target.'cfg(target_arch="x86_64")'.dependencies] +[target.'cfg(any(target_arch="x86_64", target_arch="aarch64"))'.dependencies] node-executor = { version = "3.0.0-dev", path = "../executor", features = [ "wasmtime", ] } From 3009d322dd2f4ab019afa7b54baa02ff91be0191 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 25 Nov 2021 09:30:07 +0100 Subject: [PATCH 0278/1472] Don't send ForceClose repeatedly in send_sync_notification (#10348) --- .../src/protocol/notifications/handler.rs | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index a0c49fa592b21..db0385bea8f69 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -365,10 +365,12 @@ struct NotificationsSinkInner { /// Sender to use in asynchronous contexts. Uses an asynchronous mutex. async_channel: FuturesMutex>, /// Sender to use in synchronous contexts. Uses a synchronous mutex. + /// Contains `None` if the channel was full at some point, in which case the channel will + /// be closed in the near future anyway. /// This channel has a large capacity and is meant to be used in contexts where /// back-pressure cannot be properly exerted. /// It will be removed in a future version. - sync_channel: Mutex>, + sync_channel: Mutex>>, } /// Message emitted through the [`NotificationsSink`] and processed by the background task @@ -400,14 +402,20 @@ impl NotificationsSink { /// This method will be removed in a future version. pub fn send_sync_notification<'a>(&'a self, message: impl Into>) { let mut lock = self.inner.sync_channel.lock(); - let result = - lock.try_send(NotificationsSinkMessage::Notification { message: message.into() }); - - if result.is_err() { - // Cloning the `mpsc::Sender` guarantees the allocation of an extra spot in the - // buffer, and therefore `try_send` will succeed. - let _result2 = lock.clone().try_send(NotificationsSinkMessage::ForceClose); - debug_assert!(_result2.map(|()| true).unwrap_or_else(|err| err.is_disconnected())); + + if let Some(tx) = lock.as_mut() { + let result = + tx.try_send(NotificationsSinkMessage::Notification { message: message.into() }); + + if result.is_err() { + // Cloning the `mpsc::Sender` guarantees the allocation of an extra spot in the + // buffer, and therefore `try_send` will succeed. + let _result2 = tx.clone().try_send(NotificationsSinkMessage::ForceClose); + debug_assert!(_result2.map(|()| true).unwrap_or_else(|err| err.is_disconnected())); + + // Destroy the sender in order to not send more `ForceClose` messages. + *lock = None; + } } } @@ -554,7 +562,7 @@ impl ProtocolsHandler for NotifsHandler { inner: Arc::new(NotificationsSinkInner { peer_id: self.peer_id, async_channel: FuturesMutex::new(async_tx), - sync_channel: Mutex::new(sync_tx), + sync_channel: Mutex::new(Some(sync_tx)), }), }; From 4617267aa82f63c0082592c4cd0f912bbc52b0ef Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 25 Nov 2021 11:33:33 +0300 Subject: [PATCH 0279/1472] Bump libp2p to 0.40.0 (#10035) * Bump libp2p to 0.40.0-rc.1 * Fix PingFailure import * Reduce the number of compilation errors (this is a FIXME commit) * Bump libp2p to 0.40.0-rc.2 * Fix sc-network::Behaviour to inject events into fields * Fix some NetworkBehaviourAction types * More fixes * More fixes * More fixes * Fix DiscoveryBehaviour * Fix PeerInfoBehaviour * Fix RequestResponsesBehaviour * Fix RequestResponsesBehaviour * Fix Notifications * Fix NetworkWorker * Fix Behaviour * Please borrowchk * Please borrowchk * Please borrowchk * Fix fmt * Cover all cases in matches * Fix some clippy warnings * Fix into_peer_id -> to_peer_id * Fix some warnings * Fix some inject_dial_failure FIXMEs * Fix DiscoveryBehaviour::inject_dial_failure * Fix RequestResponsesBehaviour::inject_dial_failure * Fix the order of inject_connection_closed PeerInfoBehaviour events * Make KademliaEvent with filtering unreachable * Fix Notifications::inject_dial_failure * Use concurrent_dial_errors in NetworkWorker * Remove commented-out RequestResponsesBehaviour::inject_addr_reach_failure * Fix tests * Dont report new PendingConnectionError and DialError variants to metrics * Bump libp2p to 0.40.0 * Add fn inject_listen_failure and inject_address_change * Review fixes --- Cargo.lock | 388 ++++++++---------- client/authority-discovery/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/cli/src/commands/build_spec_cmd.rs | 2 +- client/cli/src/commands/generate_node_key.rs | 2 +- client/cli/src/commands/inspect_node_key.rs | 2 +- client/consensus/common/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 4 +- client/network/src/behaviour.rs | 12 +- client/network/src/bitswap.rs | 14 +- client/network/src/discovery.rs | 135 ++++-- client/network/src/peer_info.rs | 98 +++-- client/network/src/protocol.rs | 36 +- .../src/protocol/notifications/behaviour.rs | 133 +++--- .../src/protocol/notifications/tests.rs | 38 +- client/network/src/request_responses.rs | 89 ++-- client/network/src/service.rs | 89 ++-- client/network/test/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- 21 files changed, 564 insertions(+), 492 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0091223b09e6a..3e956ea462ee7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -545,6 +545,12 @@ dependencies = [ "sp-std", ] +[[package]] +name = "bimap" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50ae17cabbc8a38a1e3e4c1a6a664e9a09672dc14d0896fa8d865d3a5a446b07" + [[package]] name = "bincode" version = "1.3.2" @@ -1592,6 +1598,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "dtoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + [[package]] name = "dyn-clonable" version = "0.9.0" @@ -1874,12 +1886,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "fixedbitset" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" - [[package]] name = "fixedbitset" version = "0.4.0" @@ -3388,9 +3394,9 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libp2p" -version = "0.39.1" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9004c06878ef8f3b4b4067e69a140d87ed20bf777287f82223e49713b36ee433" +checksum = "3bec54343492ba5940a6c555e512c6721139835d28c59bc22febece72dfd0d9d" dependencies = [ "atomic", "bytes 1.0.1", @@ -3404,12 +3410,14 @@ dependencies = [ "libp2p-identify", "libp2p-kad", "libp2p-mdns", + "libp2p-metrics", "libp2p-mplex", "libp2p-noise", "libp2p-ping", "libp2p-plaintext", "libp2p-pnet", "libp2p-relay", + "libp2p-rendezvous", "libp2p-request-response", "libp2p-swarm", "libp2p-swarm-derive", @@ -3427,9 +3435,9 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af9b4abdeaa420593a297c8592f63fad4234f4b88dc9343b8fd8e736c35faa59" +checksum = "bef22d9bba1e8bcb7ec300073e6802943fe8abb8190431842262b5f1c30abba1" dependencies = [ "asn1_der", "bs58", @@ -3439,16 +3447,16 @@ dependencies = [ "futures 0.3.16", "futures-timer 3.0.2", "lazy_static", - "libsecp256k1 0.5.0", + "libsecp256k1", "log 0.4.14", "multiaddr", "multihash 0.14.0", "multistream-select", "parking_lot 0.11.1", "pin-project 1.0.8", - "prost 0.8.0", - "prost-build 0.8.0", - "rand 0.7.3", + "prost", + "prost-build", + "rand 0.8.4", "ring", "rw-stream-sink", "sha2 0.9.8", @@ -3461,9 +3469,9 @@ dependencies = [ [[package]] name = "libp2p-deflate" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66097fccc0b7f8579f90a03ea76ba6196332ea049fd07fd969490a06819dcdc8" +checksum = "51a800adb195f33de63f4b17b63fe64cfc23bf2c6a0d3d0d5321328664e65197" dependencies = [ "flate2", "futures 0.3.16", @@ -3472,9 +3480,9 @@ dependencies = [ [[package]] name = "libp2p-dns" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ff08b3196b85a17f202d80589e93b1660a574af67275706657fdc762e42c32" +checksum = "bb8f89d15cb6e3c5bc22afff7513b11bab7856f2872d3cfba86f7f63a06bc498" dependencies = [ "async-std-resolver", "futures 0.3.16", @@ -3486,9 +3494,9 @@ dependencies = [ [[package]] name = "libp2p-floodsub" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "404eca8720967179dac7a5b4275eb91f904a53859c69ca8d018560ad6beb214f" +checksum = "aab3d7210901ea51b7bae2b581aa34521797af8c4ec738c980bda4a06434067f" dependencies = [ "cuckoofilter", "fnv", @@ -3496,17 +3504,17 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "prost 0.8.0", - "prost-build 0.8.0", + "prost", + "prost-build", "rand 0.7.3", "smallvec 1.7.0", ] [[package]] name = "libp2p-gossipsub" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cc48709bcbc3a3321f08a73560b4bbb4166a7d56f6fdb615bc775f4f91058e" +checksum = "dfeead619eb5dac46e65acc78c535a60aaec803d1428cca6407c3a4fc74d698d" dependencies = [ "asynchronous-codec 0.6.0", "base64 0.13.0", @@ -3518,8 +3526,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "prost 0.8.0", - "prost-build 0.8.0", + "prost", + "prost-build", "rand 0.7.3", "regex", "sha2 0.9.8", @@ -3530,25 +3538,26 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7b61f6cf07664fb97016c318c4d4512b3dd4cc07238607f3f0163245f99008e" +checksum = "cca1275574183f288ff8b72d535d5ffa5ea9292ef7829af8b47dcb197c7b0dcd" dependencies = [ "futures 0.3.16", "libp2p-core", "libp2p-swarm", "log 0.4.14", - "prost 0.8.0", - "prost-build 0.8.0", + "lru 0.6.6", + "prost", + "prost-build", "smallvec 1.7.0", "wasm-timer", ] [[package]] name = "libp2p-kad" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50ed78489c87924235665a0ab345b298ee34dff0f7ad62c0ba6608b2144fb75e" +checksum = "a2297dc0ca285f3a09d1368bde02449e539b46f94d32d53233f53f6625bcd3ba" dependencies = [ "arrayvec 0.5.2", "asynchronous-codec 0.6.0", @@ -3559,8 +3568,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "prost 0.8.0", - "prost-build 0.8.0", + "prost", + "prost-build", "rand 0.7.3", "sha2 0.9.8", "smallvec 1.7.0", @@ -3572,9 +3581,9 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a29e6cbc2a24b8471b6567e580a0e8e7b70a6d0f0ea2be0844d1e842d7d4fa33" +checksum = "14c864b64bdc8a84ff3910a0df88e6535f256191a450870f1e7e10cbf8e64d45" dependencies = [ "async-io", "data-encoding", @@ -3591,11 +3600,25 @@ dependencies = [ "void", ] +[[package]] +name = "libp2p-metrics" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4af432fcdd2f8ba4579b846489f8f0812cfd738ced2c0af39df9b1c48bbb6ab2" +dependencies = [ + "libp2p-core", + "libp2p-identify", + "libp2p-kad", + "libp2p-ping", + "libp2p-swarm", + "open-metrics-client", +] + [[package]] name = "libp2p-mplex" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313d9ea526c68df4425f580024e67a9d3ffd49f2c33de5154b1f5019816f7a99" +checksum = "7f2cd64ef597f40e14bfce0497f50ecb63dd6d201c61796daeb4227078834fbf" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.0.1", @@ -3611,9 +3634,9 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1db7212f342b6ba7c981cc40e31f76e9e56cb48e65fa4c142ecaca5839523e" +checksum = "a8772c7a99088221bb7ca9c5c0574bf55046a7ab4c319f3619b275f28c8fb87a" dependencies = [ "bytes 1.0.1", "curve25519-dalek 3.0.2", @@ -3621,8 +3644,8 @@ dependencies = [ "lazy_static", "libp2p-core", "log 0.4.14", - "prost 0.8.0", - "prost-build 0.8.0", + "prost", + "prost-build", "rand 0.8.4", "sha2 0.9.8", "snow", @@ -3633,9 +3656,9 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2482cfd9eb0b7a0baaf3e7b329dc4f2785181a161b1a47b7192f8d758f54a439" +checksum = "80ef7b0ec5cf06530d9eb6cf59ae49d46a2c45663bde31c25a12f682664adbcf" dependencies = [ "futures 0.3.16", "libp2p-core", @@ -3648,26 +3671,26 @@ dependencies = [ [[package]] name = "libp2p-plaintext" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b4783e5423870b9a5c199f65a7a3bc66d86ab56b2b9beebf3c338d889cf8e4" +checksum = "5fba1a6ff33e4a274c89a3b1d78b9f34f32af13265cc5c46c16938262d4e945a" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.0.1", "futures 0.3.16", "libp2p-core", "log 0.4.14", - "prost 0.8.0", - "prost-build 0.8.0", + "prost", + "prost-build", "unsigned-varint 0.7.0", "void", ] [[package]] name = "libp2p-pnet" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cb4dd4b917e5b40ddefe49b96b07adcd8d342e0317011d175b7b2bb1dcc974" +checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" dependencies = [ "futures 0.3.16", "log 0.4.14", @@ -3679,9 +3702,9 @@ dependencies = [ [[package]] name = "libp2p-relay" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0133f6cfd81cdc16e716de2982e012c62e6b9d4f12e41967b3ee361051c622aa" +checksum = "2852b61c90fa8ce3c8fcc2aba76e6cefc20d648f9df29157d6b3a916278ef3e3" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.0.1", @@ -3691,8 +3714,8 @@ dependencies = [ "libp2p-swarm", "log 0.4.14", "pin-project 1.0.8", - "prost 0.8.0", - "prost-build 0.8.0", + "prost", + "prost-build", "rand 0.7.3", "smallvec 1.7.0", "unsigned-varint 0.7.0", @@ -3700,11 +3723,33 @@ dependencies = [ "wasm-timer", ] +[[package]] +name = "libp2p-rendezvous" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14a6d2b9e7677eff61dc3d2854876aaf3976d84a01ef6664b610c77a0c9407c5" +dependencies = [ + "asynchronous-codec 0.6.0", + "bimap", + "futures 0.3.16", + "libp2p-core", + "libp2p-swarm", + "log 0.4.14", + "prost", + "prost-build", + "rand 0.8.4", + "sha2 0.9.8", + "thiserror", + "unsigned-varint 0.7.0", + "void", + "wasm-timer", +] + [[package]] name = "libp2p-request-response" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06cdae44b6821466123af93cbcdec7c9e6ba9534a8af9cdc296446d39416d241" +checksum = "a877a4ced6d46bf84677e1974e8cf61fb434af73b2e96fb48d6cb6223a4634d8" dependencies = [ "async-trait", "bytes 1.0.1", @@ -3712,8 +3757,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "lru 0.6.6", - "minicbor", + "lru 0.7.0", "rand 0.7.3", "smallvec 1.7.0", "unsigned-varint 0.7.0", @@ -3722,9 +3766,9 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7083861341e1555467863b4cd802bea1e8c4787c0f7b5110097d0f1f3248f9a9" +checksum = "3f5184a508f223bc100a12665517773fb8730e9f36fc09eefb670bf01b107ae9" dependencies = [ "either", "futures 0.3.16", @@ -3738,9 +3782,9 @@ dependencies = [ [[package]] name = "libp2p-swarm-derive" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8cb308d4fc854869f5abb54fdab0833d2cf670d407c745849dc47e6e08d79c" +checksum = "072c290f727d39bdc4e9d6d1c847978693d25a673bd757813681e33e5f6c00c2" dependencies = [ "quote", "syn", @@ -3748,9 +3792,9 @@ dependencies = [ [[package]] name = "libp2p-tcp" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79edd26b6b4bb5feee210dcda562dca186940dfecb0024b979c3f50824b3bf28" +checksum = "7399c5b6361ef525d41c11fcf51635724f832baf5819b30d3d873eabb4fbae4b" dependencies = [ "async-io", "futures 0.3.16", @@ -3765,9 +3809,9 @@ dependencies = [ [[package]] name = "libp2p-uds" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280e793440dd4e9f273d714f4497325c72cddb0fe85a49f9a03c88f41dd20182" +checksum = "b8b7563e46218165dfd60f64b96f7ce84590d75f53ecbdc74a7dd01450dc5973" dependencies = [ "async-std", "futures 0.3.16", @@ -3777,9 +3821,9 @@ dependencies = [ [[package]] name = "libp2p-wasm-ext" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f553b7140fad3d7a76f50497b0ea591e26737d9607428a75509fc191e4d1b1f6" +checksum = "1008a302b73c5020251f9708c653f5ed08368e530e247cc9cd2f109ff30042cf" dependencies = [ "futures 0.3.16", "js-sys", @@ -3791,9 +3835,9 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf99dcbf5063e9d59087f61b1e85c686ceab2f5abedb472d32288065c0e5e27" +checksum = "22e12df82d1ed64969371a9e65ea92b91064658604cc2576c2757f18ead9a1cf" dependencies = [ "either", "futures 0.3.16", @@ -3802,16 +3846,16 @@ dependencies = [ "log 0.4.14", "quicksink", "rw-stream-sink", - "soketto 0.4.2", + "soketto 0.7.0", "url 2.2.1", "webpki-roots", ] [[package]] name = "libp2p-yamux" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214cc0dd9c37cbed27f0bb1eba0c41bbafdb93a8be5e9d6ae1e6b4b42cd044bf" +checksum = "4e7362abb8867d7187e7e93df17f460d554c997fc5c8ac57dc1259057f6889af" dependencies = [ "futures 0.3.16", "libp2p-core", @@ -3832,25 +3876,6 @@ dependencies = [ "libc", ] -[[package]] -name = "libsecp256k1" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd1137239ab33b41aa9637a88a28249e5e70c40a42ccc92db7f12cc356c1fcd7" -dependencies = [ - "arrayref", - "base64 0.12.3", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core 0.2.2", - "libsecp256k1-gen-ecmult 0.2.1", - "libsecp256k1-gen-genmult 0.2.1", - "rand 0.7.3", - "serde", - "sha2 0.9.8", - "typenum", -] - [[package]] name = "libsecp256k1" version = "0.7.0" @@ -3861,26 +3886,15 @@ dependencies = [ "base64 0.13.0", "digest 0.9.0", "hmac-drbg", - "libsecp256k1-core 0.3.0", - "libsecp256k1-gen-ecmult 0.3.0", - "libsecp256k1-gen-genmult 0.3.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", "rand 0.8.4", "serde", "sha2 0.9.8", "typenum", ] -[[package]] -name = "libsecp256k1-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" -dependencies = [ - "crunchy", - "digest 0.9.0", - "subtle", -] - [[package]] name = "libsecp256k1-core" version = "0.3.0" @@ -3892,31 +3906,13 @@ dependencies = [ "subtle", ] -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" -dependencies = [ - "libsecp256k1-core 0.2.2", -] - [[package]] name = "libsecp256k1-gen-ecmult" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" dependencies = [ - "libsecp256k1-core 0.3.0", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" -dependencies = [ - "libsecp256k1-core 0.2.2", + "libsecp256k1-core", ] [[package]] @@ -3925,7 +3921,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" dependencies = [ - "libsecp256k1-core 0.3.0", + "libsecp256k1-core", ] [[package]] @@ -4205,26 +4201,6 @@ dependencies = [ "log 0.3.9", ] -[[package]] -name = "minicbor" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea79ce4ab9f445ec6b71833a2290ac0a29c9dde0fa7cae4c481eecae021d9bd9" -dependencies = [ - "minicbor-derive", -] - -[[package]] -name = "minicbor-derive" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce18b5423c573a13e80cb3046ea0af6379ef725dc3af4886bdb8f4e5093068" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "miniz_oxide" version = "0.4.4" @@ -5067,6 +5043,29 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "open-metrics-client" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7337d80c23c2d8b1349563981bc4fb531220733743ba8115454a67b181173f0d" +dependencies = [ + "dtoa", + "itoa", + "open-metrics-client-derive-text-encode", + "owning_ref", +] + +[[package]] +name = "open-metrics-client-derive-text-encode" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c83b586f00268c619c1cb3340ec1a6f59dd9ba1d9833a273a68e6d5cd8ffc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl" version = "0.10.35" @@ -5345,7 +5344,7 @@ dependencies = [ "frame-system", "hex", "hex-literal", - "libsecp256k1 0.7.0", + "libsecp256k1", "log 0.4.14", "pallet-beefy", "pallet-mmr", @@ -5405,7 +5404,7 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", - "libsecp256k1 0.7.0", + "libsecp256k1", "log 0.4.14", "pallet-balances", "pallet-contracts-primitives", @@ -6557,23 +6556,13 @@ dependencies = [ "sha-1 0.8.2", ] -[[package]] -name = "petgraph" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" -dependencies = [ - "fixedbitset 0.2.0", - "indexmap", -] - [[package]] name = "petgraph" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" dependencies = [ - "fixedbitset 0.4.0", + "fixedbitset", "indexmap", ] @@ -6847,16 +6836,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "prost" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020" -dependencies = [ - "bytes 1.0.1", - "prost-derive 0.8.0", -] - [[package]] name = "prost" version = "0.9.0" @@ -6864,25 +6843,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ "bytes 1.0.1", - "prost-derive 0.9.0", -] - -[[package]] -name = "prost-build" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603" -dependencies = [ - "bytes 1.0.1", - "heck", - "itertools", - "log 0.4.14", - "multimap", - "petgraph 0.5.1", - "prost 0.8.0", - "prost-types 0.8.0", - "tempfile", - "which", + "prost-derive", ] [[package]] @@ -6897,27 +6858,14 @@ dependencies = [ "lazy_static", "log 0.4.14", "multimap", - "petgraph 0.6.0", - "prost 0.9.0", - "prost-types 0.9.0", + "petgraph", + "prost", + "prost-types", "regex", "tempfile", "which", ] -[[package]] -name = "prost-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "prost-derive" version = "0.9.0" @@ -6931,16 +6879,6 @@ dependencies = [ "syn", ] -[[package]] -name = "prost-types" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b" -dependencies = [ - "bytes 1.0.1", - "prost 0.8.0", -] - [[package]] name = "prost-types" version = "0.9.0" @@ -6948,7 +6886,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" dependencies = [ "bytes 1.0.1", - "prost 0.9.0", + "prost", ] [[package]] @@ -7594,9 +7532,9 @@ checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" [[package]] name = "salsa20" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecbd2eb639fd7cab5804a0837fe373cc2172d15437e804c054a9fb885cb923b0" +checksum = "0c0fbb5f676da676c260ba276a8f43a8dc67cf02d1438423aeb1c677a7212686" dependencies = [ "cipher", ] @@ -7632,8 +7570,8 @@ dependencies = [ "libp2p", "log 0.4.14", "parity-scale-codec", - "prost 0.9.0", - "prost-build 0.9.0", + "prost", + "prost-build", "quickcheck", "rand 0.7.3", "sc-client-api", @@ -8068,7 +8006,7 @@ version = "0.10.0-dev" dependencies = [ "hex-literal", "lazy_static", - "libsecp256k1 0.7.0", + "libsecp256k1", "log 0.4.14", "parity-scale-codec", "parking_lot 0.11.1", @@ -8282,8 +8220,8 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.11.1", "pin-project 1.0.8", - "prost 0.9.0", - "prost-build 0.9.0", + "prost", + "prost-build", "quickcheck", "rand 0.7.3", "sc-block-builder", @@ -9159,7 +9097,6 @@ checksum = "b5c71ed3d54db0a699f4948e1bb3e45b450fa31fe602621dee6680361d569c88" dependencies = [ "base64 0.12.3", "bytes 0.5.6", - "flate2", "futures 0.3.16", "httparse", "log 0.4.14", @@ -9175,6 +9112,7 @@ checksum = "083624472e8817d44d02c0e55df043737ff11f279af924abdf93845717c2b75c" dependencies = [ "base64 0.13.0", "bytes 1.0.1", + "flate2", "futures 0.3.16", "httparse", "log 0.4.14", @@ -9442,7 +9380,7 @@ dependencies = [ "hex-literal", "impl-serde", "lazy_static", - "libsecp256k1 0.7.0", + "libsecp256k1", "log 0.4.14", "merlin", "num-traits", @@ -9562,7 +9500,7 @@ version = "4.0.0-dev" dependencies = [ "futures 0.3.16", "hash-db", - "libsecp256k1 0.7.0", + "libsecp256k1", "log 0.4.14", "parity-scale-codec", "parking_lot 0.11.1", diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index b6f9b8450d861..f3169e82fb3c8 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -23,7 +23,7 @@ derive_more = "0.99.16" futures = "0.3.9" futures-timer = "3.0.1" ip_network = "0.4.0" -libp2p = { version = "0.39.1", default-features = false, features = ["kad"] } +libp2p = { version = "0.40.0", default-features = false, features = ["kad"] } log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } prost = "0.9" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 8667a5e876c14..dddd48cb2f142 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -18,7 +18,7 @@ regex = "1.5.4" tokio = { version = "1.13", features = [ "signal", "rt-multi-thread" ] } futures = "0.3.9" fdlimit = "0.2.1" -libp2p = "0.39.1" +libp2p = "0.40.0" parity-scale-codec = "2.3.1" hex = "0.4.2" rand = "0.7.3" diff --git a/client/cli/src/commands/build_spec_cmd.rs b/client/cli/src/commands/build_spec_cmd.rs index 75fdf07643ee2..5e43a26a1e67d 100644 --- a/client/cli/src/commands/build_spec_cmd.rs +++ b/client/cli/src/commands/build_spec_cmd.rs @@ -65,7 +65,7 @@ impl BuildSpecCmd { if spec.boot_nodes().is_empty() && !self.disable_default_bootnode { let keys = network_config.node_key.into_keypair()?; - let peer_id = keys.public().into_peer_id(); + let peer_id = keys.public().to_peer_id(); let addr = MultiaddrWithPeerId { multiaddr: build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(30333u16)], peer_id, diff --git a/client/cli/src/commands/generate_node_key.rs b/client/cli/src/commands/generate_node_key.rs index 74a4197f36621..cc26bb73240ac 100644 --- a/client/cli/src/commands/generate_node_key.rs +++ b/client/cli/src/commands/generate_node_key.rs @@ -42,7 +42,7 @@ impl GenerateNodeKeyCmd { pub fn run(&self) -> Result<(), Error> { let keypair = libp2p_ed25519::Keypair::generate(); let secret = keypair.secret(); - let peer_id = PublicKey::Ed25519(keypair.public()).into_peer_id(); + let peer_id = PublicKey::Ed25519(keypair.public()).to_peer_id(); let secret_hex = hex::encode(secret.as_ref()); match &self.file { diff --git a/client/cli/src/commands/inspect_node_key.rs b/client/cli/src/commands/inspect_node_key.rs index 92a71f8975052..7527fbe4315ae 100644 --- a/client/cli/src/commands/inspect_node_key.rs +++ b/client/cli/src/commands/inspect_node_key.rs @@ -47,7 +47,7 @@ impl InspectNodeKeyCmd { ed25519::SecretKey::from_bytes(&mut file_content).map_err(|_| "Bad node key file")?; let keypair = ed25519::Keypair::from(secret); - let peer_id = PublicKey::Ed25519(keypair.public()).into_peer_id(); + let peer_id = PublicKey::Ed25519(keypair.public()).to_peer_id(); println!("{}", peer_id); diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index c26e250edf24c..308028c85d23c 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] thiserror = "1.0.30" -libp2p = { version = "0.39.1", default-features = false } +libp2p = { version = "0.40.0", default-features = false } log = "0.4.8" futures = { version = "0.3.1", features = ["thread-pool"] } futures-timer = "3.0.1" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index e11cb8dbe85d6..840cb50c8c9fc 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.9" futures-timer = "3.0.1" -libp2p = { version = "0.39.1", default-features = false } +libp2p = { version = "0.40.0", default-features = false } log = "0.4.8" lru = "0.7.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 527a18dc7755b..8ee4d7f145726 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -64,11 +64,11 @@ unsigned-varint = { version = "0.6.0", features = [ ] } void = "1.0.2" zeroize = "1.4.2" -libp2p = "0.39.1" +libp2p = "0.40.0" [dev-dependencies] assert_matches = "1.3" -libp2p = { version = "0.39.1", default-features = false } +libp2p = { version = "0.40.0", default-features = false } quickcheck = "1.0.3" rand = "0.7.2" sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index e2b950cf67e8c..a6a67d7bce2d1 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -32,7 +32,10 @@ use libp2p::{ core::{Multiaddr, PeerId, PublicKey}, identify::IdentifyInfo, kad::record, - swarm::{toggle::Toggle, NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters}, + swarm::{ + toggle::Toggle, NetworkBehaviour, NetworkBehaviourAction, NetworkBehaviourEventProcess, + PollParameters, + }, NetworkBehaviour, }; use log::debug; @@ -58,7 +61,7 @@ pub use crate::request_responses::{ /// General behaviour of the network. Combines all protocols together. #[derive(NetworkBehaviour)] -#[behaviour(out_event = "BehaviourOut", poll_method = "poll")] +#[behaviour(out_event = "BehaviourOut", poll_method = "poll", event_process = true)] pub struct Behaviour { /// All the substrate-specific protocols. substrate: Protocol, @@ -512,11 +515,12 @@ impl NetworkBehaviourEventProcess for Behaviour { } impl Behaviour { - fn poll( + fn poll( &mut self, _cx: &mut Context, _: &mut impl PollParameters, - ) -> Poll>> { + ) -> Poll, ::ProtocolsHandler>> + { if let Some(event) = self.events.pop_front() { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event)) } diff --git a/client/network/src/bitswap.rs b/client/network/src/bitswap.rs index 6b53dce626505..e6cb1d9d79e3a 100644 --- a/client/network/src/bitswap.rs +++ b/client/network/src/bitswap.rs @@ -39,8 +39,7 @@ use libp2p::{ UpgradeInfo, }, swarm::{ - IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, - OneShotHandler, PollParameters, ProtocolsHandler, + NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, OneShotHandler, PollParameters, }, }; use log::{debug, error, trace}; @@ -297,12 +296,11 @@ impl NetworkBehaviour for Bitswap { self.ready_blocks.push_back((peer, response)); } - fn poll(&mut self, _ctx: &mut Context, _: &mut impl PollParameters) -> Poll< - NetworkBehaviourAction< - <::Handler as ProtocolsHandler>::InEvent, - Self::OutEvent, - >, - >{ + fn poll( + &mut self, + _ctx: &mut Context, + _: &mut impl PollParameters, + ) -> Poll> { if let Some((peer_id, message)) = self.ready_blocks.pop_front() { return Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 2a4b25a621e04..dc08ab57ed3f6 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -67,8 +67,8 @@ use libp2p::{ mdns::{Mdns, MdnsConfig, MdnsEvent}, multiaddr::Protocol, swarm::{ - protocols_handler::multi::IntoMultiHandler, IntoProtocolsHandler, NetworkBehaviour, - NetworkBehaviourAction, PollParameters, ProtocolsHandler, + protocols_handler::multi::IntoMultiHandler, DialError, IntoProtocolsHandler, + NetworkBehaviour, NetworkBehaviourAction, PollParameters, ProtocolsHandler, }, }; use log::{debug, error, info, trace, warn}; @@ -107,7 +107,7 @@ impl DiscoveryConfig { /// Create a default configuration with the given public key. pub fn new(local_public_key: PublicKey) -> Self { Self { - local_peer_id: local_public_key.into_peer_id(), + local_peer_id: local_public_key.to_peer_id(), permanent_addresses: Vec::new(), dht_random_walk: true, allow_private_ipv4: true, @@ -428,6 +428,29 @@ impl DiscoveryBehaviour { }; ip.is_global() } + + fn new_handler_with_replacement( + &mut self, + pid: ProtocolId, + handler: KademliaHandlerProto, + ) -> ::ProtocolsHandler { + let mut handlers: HashMap<_, _> = self + .kademlias + .iter_mut() + .map(|(p, k)| (p.clone(), NetworkBehaviour::new_handler(k))) + .collect(); + + if let Some(h) = handlers.get_mut(&pid) { + *h = handler + } + + IntoMultiHandler::try_from_iter(handlers).expect( + "There can be at most one handler per `ProtocolId` and protocol names contain the \ + `ProtocolId` so no two protocol names in `self.kademlias` can be equal which is the \ + only error `try_from_iter` can return, therefore this call is guaranteed to succeed; \ + qed", + ) + } } /// Event generated by the `DiscoveryBehaviour`. @@ -527,15 +550,34 @@ impl NetworkBehaviour for DiscoveryBehaviour { list } + fn inject_address_change( + &mut self, + peer_id: &PeerId, + connection_id: &ConnectionId, + old: &ConnectedPoint, + new: &ConnectedPoint, + ) { + for k in self.kademlias.values_mut() { + NetworkBehaviour::inject_address_change(k, peer_id, connection_id, old, new); + } + } + fn inject_connection_established( &mut self, peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, + failed_addresses: Option<&Vec>, ) { self.num_connections += 1; for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_connection_established(k, peer_id, conn, endpoint) + NetworkBehaviour::inject_connection_established( + k, + peer_id, + conn, + endpoint, + failed_addresses, + ) } } @@ -547,14 +589,13 @@ impl NetworkBehaviour for DiscoveryBehaviour { fn inject_connection_closed( &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - endpoint: &ConnectedPoint, + _peer_id: &PeerId, + _conn: &ConnectionId, + _endpoint: &ConnectedPoint, + _handler: ::Handler, ) { self.num_connections -= 1; - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_connection_closed(k, peer_id, conn, endpoint) - } + // NetworkBehaviour::inject_connection_closed on Kademlia does nothing. } fn inject_disconnected(&mut self, peer_id: &PeerId) { @@ -563,20 +604,25 @@ impl NetworkBehaviour for DiscoveryBehaviour { } } - fn inject_addr_reach_failure( + fn inject_dial_failure( &mut self, - peer_id: Option<&PeerId>, - addr: &Multiaddr, - error: &dyn std::error::Error, + peer_id: Option, + _: Self::ProtocolsHandler, + error: &DialError, ) { if let Some(peer_id) = peer_id { - if let Some(list) = self.ephemeral_addresses.get_mut(peer_id) { - list.retain(|a| a != addr); + if let DialError::Transport(errors) = error { + if let Some(list) = self.ephemeral_addresses.get_mut(&peer_id) { + for (addr, _error) in errors { + list.retain(|a| a != addr); + } + } } } for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_addr_reach_failure(k, peer_id, addr, error) + let handler = k.new_handler(); + NetworkBehaviour::inject_dial_failure(k, peer_id, handler, error); } } @@ -631,12 +677,6 @@ impl NetworkBehaviour for DiscoveryBehaviour { } } - fn inject_dial_failure(&mut self, peer_id: &PeerId) { - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_dial_failure(k, peer_id) - } - } - fn inject_new_listener(&mut self, id: ListenerId) { for k in self.kademlias.values_mut() { NetworkBehaviour::inject_new_listener(k, id) @@ -649,6 +689,10 @@ impl NetworkBehaviour for DiscoveryBehaviour { } } + fn inject_listen_failure(&mut self, _: &Multiaddr, _: &Multiaddr, _: Self::ProtocolsHandler) { + // NetworkBehaviour::inject_listen_failure on Kademlia does nothing. + } + fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) { for k in self.kademlias.values_mut() { NetworkBehaviour::inject_listener_error(k, id, err) @@ -665,12 +709,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { &mut self, cx: &mut Context, params: &mut impl PollParameters, - ) -> Poll< - NetworkBehaviourAction< - <::Handler as ProtocolsHandler>::InEvent, - Self::OutEvent, - >, - >{ + ) -> Poll> { // Immediately process the content of `discovered`. if let Some(ev) = self.pending_events.pop_front() { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) @@ -731,6 +770,10 @@ impl NetworkBehaviour for DiscoveryBehaviour { let ev = DiscoveryOut::Discovered(peer); return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) }, + KademliaEvent::InboundPutRecordRequest { .. } | + KademliaEvent::InboundAddProviderRequest { .. } => { + debug_assert!(false, "We don't use kad filtering at the moment"); + }, KademliaEvent::PendingRoutablePeer { .. } | KademliaEvent::InboundRequestServed { .. } => { // We are not interested in this event at the moment. @@ -847,10 +890,20 @@ impl NetworkBehaviour for DiscoveryBehaviour { warn!(target: "sub-libp2p", "Libp2p => Unhandled Kademlia event: {:?}", e) }, }, - NetworkBehaviourAction::DialAddress { address } => - return Poll::Ready(NetworkBehaviourAction::DialAddress { address }), - NetworkBehaviourAction::DialPeer { peer_id, condition } => - return Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition }), + NetworkBehaviourAction::DialAddress { address, handler } => { + let pid = pid.clone(); + let handler = self.new_handler_with_replacement(pid, handler); + return Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) + }, + NetworkBehaviourAction::DialPeer { peer_id, condition, handler } => { + let pid = pid.clone(); + let handler = self.new_handler_with_replacement(pid, handler); + return Poll::Ready(NetworkBehaviourAction::DialPeer { + peer_id, + condition, + handler, + }) + }, NetworkBehaviourAction::NotifyHandler { peer_id, handler, event } => return Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, @@ -888,10 +941,12 @@ impl NetworkBehaviour for DiscoveryBehaviour { }, MdnsEvent::Expired(_) => {}, }, - NetworkBehaviourAction::DialAddress { address } => - return Poll::Ready(NetworkBehaviourAction::DialAddress { address }), - NetworkBehaviourAction::DialPeer { peer_id, condition } => - return Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition }), + NetworkBehaviourAction::DialAddress { .. } => { + unreachable!("mDNS never dials!"); + }, + NetworkBehaviourAction::DialPeer { .. } => { + unreachable!("mDNS never dials!"); + }, NetworkBehaviourAction::NotifyHandler { event, .. } => match event {}, /* `event` is an enum with no variant */ NetworkBehaviourAction::ReportObservedAddr { address, score } => return Poll::Ready(NetworkBehaviourAction::ReportObservedAddr { @@ -940,7 +995,7 @@ impl MdnsWrapper { &mut self, cx: &mut Context<'_>, params: &mut impl PollParameters, - ) -> Poll> { + ) -> Poll::ProtocolsHandler>> { loop { match self { Self::Instantiating(fut) => @@ -1007,13 +1062,13 @@ mod tests { config.finish() }; - let mut swarm = Swarm::new(transport, behaviour, keypair.public().into_peer_id()); + let mut swarm = Swarm::new(transport, behaviour, keypair.public().to_peer_id()); let listen_addr: Multiaddr = format!("/memory/{}", rand::random::()).parse().unwrap(); if i == 0 { first_swarm_peer_id_and_addr = - Some((keypair.public().into_peer_id(), listen_addr.clone())) + Some((keypair.public().to_peer_id(), listen_addr.clone())) } swarm.listen_on(listen_addr.clone()).unwrap(); diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index 141cc59247d1a..2c37fdb460a76 100644 --- a/client/network/src/peer_info.rs +++ b/client/network/src/peer_info.rs @@ -186,6 +186,17 @@ impl NetworkBehaviour for PeerInfoBehaviour { list } + fn inject_address_change( + &mut self, + peer_id: &PeerId, + conn: &ConnectionId, + old: &ConnectedPoint, + new: &ConnectedPoint, + ) { + self.ping.inject_address_change(peer_id, conn, old, new); + self.identify.inject_address_change(peer_id, conn, old, new); + } + fn inject_connected(&mut self, peer_id: &PeerId) { self.ping.inject_connected(peer_id); self.identify.inject_connected(peer_id); @@ -196,9 +207,12 @@ impl NetworkBehaviour for PeerInfoBehaviour { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, + failed_addresses: Option<&Vec>, ) { - self.ping.inject_connection_established(peer_id, conn, endpoint); - self.identify.inject_connection_established(peer_id, conn, endpoint); + self.ping + .inject_connection_established(peer_id, conn, endpoint, failed_addresses); + self.identify + .inject_connection_established(peer_id, conn, endpoint, failed_addresses); match self.nodes_info.entry(*peer_id) { Entry::Vacant(e) => { e.insert(NodeInfo::new(endpoint.clone())); @@ -220,9 +234,12 @@ impl NetworkBehaviour for PeerInfoBehaviour { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, + handler: ::Handler, ) { - self.ping.inject_connection_closed(peer_id, conn, endpoint); - self.identify.inject_connection_closed(peer_id, conn, endpoint); + let (ping_handler, identity_handler) = handler.into_inner(); + self.identify + .inject_connection_closed(peer_id, conn, endpoint, identity_handler); + self.ping.inject_connection_closed(peer_id, conn, endpoint, ping_handler); if let Some(entry) = self.nodes_info.get_mut(peer_id) { entry.endpoints.retain(|ep| ep != endpoint) @@ -256,19 +273,15 @@ impl NetworkBehaviour for PeerInfoBehaviour { } } - fn inject_addr_reach_failure( + fn inject_dial_failure( &mut self, - peer_id: Option<&PeerId>, - addr: &Multiaddr, - error: &dyn std::error::Error, + peer_id: Option, + handler: Self::ProtocolsHandler, + error: &libp2p::swarm::DialError, ) { - self.ping.inject_addr_reach_failure(peer_id, addr, error); - self.identify.inject_addr_reach_failure(peer_id, addr, error); - } - - fn inject_dial_failure(&mut self, peer_id: &PeerId) { - self.ping.inject_dial_failure(peer_id); - self.identify.inject_dial_failure(peer_id); + let (ping_handler, identity_handler) = handler.into_inner(); + self.identify.inject_dial_failure(peer_id, identity_handler, error); + self.ping.inject_dial_failure(peer_id, ping_handler, error); } fn inject_new_listener(&mut self, id: ListenerId) { @@ -296,6 +309,18 @@ impl NetworkBehaviour for PeerInfoBehaviour { self.identify.inject_expired_external_addr(addr); } + fn inject_listen_failure( + &mut self, + local_addr: &Multiaddr, + send_back_addr: &Multiaddr, + handler: Self::ProtocolsHandler, + ) { + let (ping_handler, identity_handler) = handler.into_inner(); + self.identify + .inject_listen_failure(local_addr, send_back_addr, identity_handler); + self.ping.inject_listen_failure(local_addr, send_back_addr, ping_handler); + } + fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn error::Error + 'static)) { self.ping.inject_listener_error(id, err); self.identify.inject_listener_error(id, err); @@ -309,13 +334,8 @@ impl NetworkBehaviour for PeerInfoBehaviour { fn poll( &mut self, cx: &mut Context, - params: &mut impl PollParameters - ) -> Poll< - NetworkBehaviourAction< - <::Handler as ProtocolsHandler>::InEvent, - Self::OutEvent - > - >{ + params: &mut impl PollParameters, + ) -> Poll> { loop { match self.ping.poll(cx, params) { Poll::Pending => break, @@ -324,10 +344,20 @@ impl NetworkBehaviour for PeerInfoBehaviour { self.handle_ping_report(&peer, rtt) } }, - Poll::Ready(NetworkBehaviourAction::DialAddress { address }) => - return Poll::Ready(NetworkBehaviourAction::DialAddress { address }), - Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition }) => - return Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition }), + Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) => { + let handler = + IntoProtocolsHandler::select(handler, self.identify.new_handler()); + return Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) + }, + Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition, handler }) => { + let handler = + IntoProtocolsHandler::select(handler, self.identify.new_handler()); + return Poll::Ready(NetworkBehaviourAction::DialPeer { + peer_id, + condition, + handler, + }) + }, Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, handler, event }) => return Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, @@ -362,10 +392,18 @@ impl NetworkBehaviour for PeerInfoBehaviour { IdentifyEvent::Pushed { .. } => {}, IdentifyEvent::Sent { .. } => {}, }, - Poll::Ready(NetworkBehaviourAction::DialAddress { address }) => - return Poll::Ready(NetworkBehaviourAction::DialAddress { address }), - Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition }) => - return Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition }), + Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) => { + let handler = IntoProtocolsHandler::select(self.ping.new_handler(), handler); + return Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) + }, + Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition, handler }) => { + let handler = IntoProtocolsHandler::select(self.ping.new_handler(), handler); + return Poll::Ready(NetworkBehaviourAction::DialPeer { + peer_id, + condition, + handler, + }) + }, Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, handler, event }) => return Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index a0c52d14fa62f..bfaf42d5ff227 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -1362,8 +1362,10 @@ impl NetworkBehaviour for Protocol { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, + failed_addresses: Option<&Vec>, ) { - self.behaviour.inject_connection_established(peer_id, conn, endpoint) + self.behaviour + .inject_connection_established(peer_id, conn, endpoint, failed_addresses) } fn inject_connection_closed( @@ -1371,8 +1373,9 @@ impl NetworkBehaviour for Protocol { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, + handler: ::Handler, ) { - self.behaviour.inject_connection_closed(peer_id, conn, endpoint) + self.behaviour.inject_connection_closed(peer_id, conn, endpoint, handler) } fn inject_connected(&mut self, peer_id: &PeerId) { @@ -1396,12 +1399,7 @@ impl NetworkBehaviour for Protocol { &mut self, cx: &mut std::task::Context, params: &mut impl PollParameters, - ) -> Poll< - NetworkBehaviourAction< - <::Handler as ProtocolsHandler>::InEvent, - Self::OutEvent - > - >{ + ) -> Poll> { if let Some(message) = self.pending_messages.pop_front() { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(message)) } @@ -1562,10 +1560,10 @@ impl NetworkBehaviour for Protocol { let event = match self.behaviour.poll(cx, params) { Poll::Pending => return Poll::Pending, Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) => ev, - Poll::Ready(NetworkBehaviourAction::DialAddress { address }) => - return Poll::Ready(NetworkBehaviourAction::DialAddress { address }), - Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition }) => - return Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition }), + Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) => + return Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }), + Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition, handler }) => + return Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition, handler }), Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, handler, event }) => return Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, @@ -1778,17 +1776,13 @@ impl NetworkBehaviour for Protocol { Poll::Pending } - fn inject_addr_reach_failure( + fn inject_dial_failure( &mut self, - peer_id: Option<&PeerId>, - addr: &Multiaddr, - error: &dyn std::error::Error, + peer_id: Option, + handler: Self::ProtocolsHandler, + error: &libp2p::swarm::DialError, ) { - self.behaviour.inject_addr_reach_failure(peer_id, addr, error) - } - - fn inject_dial_failure(&mut self, peer_id: &PeerId) { - self.behaviour.inject_dial_failure(peer_id) + self.behaviour.inject_dial_failure(peer_id, handler, error); } fn inject_new_listener(&mut self, id: ListenerId) { diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index f66f1fbe9e95a..26a246f57690f 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -26,7 +26,8 @@ use futures::prelude::*; use libp2p::{ core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId}, swarm::{ - DialPeerCondition, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, + DialError, DialPeerCondition, IntoProtocolsHandler, NetworkBehaviour, + NetworkBehaviourAction, NotifyHandler, PollParameters, }, }; use log::{error, trace, warn}; @@ -38,7 +39,7 @@ use std::{ borrow::Cow, cmp, collections::{hash_map::Entry, VecDeque}, - error, mem, + mem, pin::Pin, str, sync::Arc, @@ -132,7 +133,7 @@ pub struct Notifications { next_incoming_index: sc_peerset::IncomingIndex, /// Events to produce from `poll()`. - events: VecDeque>, + events: VecDeque>, } /// Configuration for a notifications protocol. @@ -628,6 +629,7 @@ impl Notifications { /// Function that is called when the peerset wants us to connect to a peer. fn peerset_report_connect(&mut self, peer_id: PeerId, set_id: sc_peerset::SetId) { // If `PeerId` is unknown to us, insert an entry, start dialing, and return early. + let handler = self.new_handler(); let mut occ_entry = match self.peers.entry((peer_id, set_id)) { Entry::Occupied(entry) => entry, Entry::Vacant(entry) => { @@ -643,6 +645,7 @@ impl Notifications { self.events.push_back(NetworkBehaviourAction::DialPeer { peer_id: entry.key().0.clone(), condition: DialPeerCondition::Disconnected, + handler, }); entry.insert(PeerState::Requested); return @@ -679,6 +682,7 @@ impl Notifications { self.events.push_back(NetworkBehaviourAction::DialPeer { peer_id: occ_entry.key().0.clone(), condition: DialPeerCondition::Disconnected, + handler, }); *occ_entry.into_mut() = PeerState::Requested; }, @@ -1094,6 +1098,7 @@ impl NetworkBehaviour for Notifications { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, + _failed_addresses: Option<&Vec>, ) { for set_id in (0..self.notif_protocols.len()).map(sc_peerset::SetId::from) { match self.peers.entry((*peer_id, set_id)).or_insert(PeerState::Poisoned) { @@ -1152,6 +1157,7 @@ impl NetworkBehaviour for Notifications { peer_id: &PeerId, conn: &ConnectionId, _endpoint: &ConnectedPoint, + _handler: ::Handler, ) { for set_id in (0..self.notif_protocols.len()).map(sc_peerset::SetId::from) { let mut entry = if let Entry::Occupied(entry) = self.peers.entry((*peer_id, set_id)) { @@ -1411,70 +1417,74 @@ impl NetworkBehaviour for Notifications { fn inject_disconnected(&mut self, _peer_id: &PeerId) {} - fn inject_addr_reach_failure( + fn inject_dial_failure( &mut self, - peer_id: Option<&PeerId>, - addr: &Multiaddr, - error: &dyn error::Error, + peer_id: Option, + _: Self::ProtocolsHandler, + error: &DialError, ) { - trace!(target: "sub-libp2p", "Libp2p => Reach failure for {:?} through {:?}: {:?}", peer_id, addr, error); - } + if let DialError::Transport(errors) = error { + for (addr, error) in errors.iter() { + trace!(target: "sub-libp2p", "Libp2p => Reach failure for {:?} through {:?}: {:?}", peer_id, addr, error); + } + } - fn inject_dial_failure(&mut self, peer_id: &PeerId) { - trace!(target: "sub-libp2p", "Libp2p => Dial failure for {:?}", peer_id); + if let Some(peer_id) = peer_id { + trace!(target: "sub-libp2p", "Libp2p => Dial failure for {:?}", peer_id); - for set_id in (0..self.notif_protocols.len()).map(sc_peerset::SetId::from) { - if let Entry::Occupied(mut entry) = self.peers.entry((peer_id.clone(), set_id)) { - match mem::replace(entry.get_mut(), PeerState::Poisoned) { - // The peer is not in our list. - st @ PeerState::Backoff { .. } => { - *entry.into_mut() = st; - }, - - // "Basic" situation: we failed to reach a peer that the peerset requested. - st @ PeerState::Requested | st @ PeerState::PendingRequest { .. } => { - trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", peer_id, set_id); - self.peerset.dropped(set_id, *peer_id, DropReason::Unknown); + for set_id in (0..self.notif_protocols.len()).map(sc_peerset::SetId::from) { + if let Entry::Occupied(mut entry) = self.peers.entry((peer_id.clone(), set_id)) { + match mem::replace(entry.get_mut(), PeerState::Poisoned) { + // The peer is not in our list. + st @ PeerState::Backoff { .. } => { + *entry.into_mut() = st; + }, - let now = Instant::now(); - let ban_duration = match st { - PeerState::PendingRequest { timer_deadline, .. } - if timer_deadline > now => - cmp::max(timer_deadline - now, Duration::from_secs(5)), - _ => Duration::from_secs(5), - }; + // "Basic" situation: we failed to reach a peer that the peerset requested. + st @ PeerState::Requested | st @ PeerState::PendingRequest { .. } => { + trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", peer_id, set_id); + self.peerset.dropped(set_id, peer_id, DropReason::Unknown); - let delay_id = self.next_delay_id; - self.next_delay_id.0 += 1; - let delay = futures_timer::Delay::new(ban_duration); - let peer_id = *peer_id; - self.delays.push( - async move { - delay.await; - (delay_id, peer_id, set_id) - } - .boxed(), - ); - - *entry.into_mut() = PeerState::Backoff { - timer: delay_id, - timer_deadline: now + ban_duration, - }; - }, + let now = Instant::now(); + let ban_duration = match st { + PeerState::PendingRequest { timer_deadline, .. } + if timer_deadline > now => + cmp::max(timer_deadline - now, Duration::from_secs(5)), + _ => Duration::from_secs(5), + }; - // We can still get dial failures even if we are already connected to the peer, - // as an extra diagnostic for an earlier attempt. - st @ PeerState::Disabled { .. } | - st @ PeerState::Enabled { .. } | - st @ PeerState::DisabledPendingEnable { .. } | - st @ PeerState::Incoming { .. } => { - *entry.into_mut() = st; - }, + let delay_id = self.next_delay_id; + self.next_delay_id.0 += 1; + let delay = futures_timer::Delay::new(ban_duration); + let peer_id = peer_id; + self.delays.push( + async move { + delay.await; + (delay_id, peer_id, set_id) + } + .boxed(), + ); - PeerState::Poisoned => { - error!(target: "sub-libp2p", "State of {:?} is poisoned", peer_id); - debug_assert!(false); - }, + *entry.into_mut() = PeerState::Backoff { + timer: delay_id, + timer_deadline: now + ban_duration, + }; + }, + + // We can still get dial failures even if we are already connected to the + // peer, as an extra diagnostic for an earlier attempt. + st @ PeerState::Disabled { .. } | + st @ PeerState::Enabled { .. } | + st @ PeerState::DisabledPendingEnable { .. } | + st @ PeerState::Incoming { .. } => { + *entry.into_mut() = st; + }, + + PeerState::Poisoned => { + error!(target: "sub-libp2p", "State of {:?} is poisoned", peer_id); + debug_assert!(false); + }, + } } } } @@ -2000,7 +2010,7 @@ impl NetworkBehaviour for Notifications { &mut self, cx: &mut Context, _params: &mut impl PollParameters, - ) -> Poll> { + ) -> Poll> { if let Some(event) = self.events.pop_front() { return Poll::Ready(event) } @@ -2032,6 +2042,8 @@ impl NetworkBehaviour for Notifications { while let Poll::Ready(Some((delay_id, peer_id, set_id))) = Pin::new(&mut self.delays).poll_next(cx) { + let handler = self.new_handler(); + let peer_state = match self.peers.get_mut(&(peer_id, set_id)) { Some(s) => s, // We intentionally never remove elements from `delays`, and it may @@ -2051,6 +2063,7 @@ impl NetworkBehaviour for Notifications { self.events.push_back(NetworkBehaviourAction::DialPeer { peer_id, condition: DialPeerCondition::Disconnected, + handler, }); *peer_state = PeerState::Requested; }, diff --git a/client/network/src/protocol/notifications/tests.rs b/client/network/src/protocol/notifications/tests.rs index 0b3ffc01a4b8d..ffc25194def09 100644 --- a/client/network/src/protocol/notifications/tests.rs +++ b/client/network/src/protocol/notifications/tests.rs @@ -29,7 +29,7 @@ use libp2p::{ }, identity, noise, swarm::{ - IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters, + DialError, IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters, ProtocolsHandler, Swarm, SwarmEvent, }, yamux, Multiaddr, PeerId, Transport, @@ -68,7 +68,7 @@ fn build_nodes() -> (Swarm, Swarm) { in_peers: 25, out_peers: 25, bootnodes: if index == 0 { - keypairs.iter().skip(1).map(|keypair| keypair.public().into_peer_id()).collect() + keypairs.iter().skip(1).map(|keypair| keypair.public().to_peer_id()).collect() } else { vec![] }, @@ -92,7 +92,7 @@ fn build_nodes() -> (Swarm, Swarm) { .enumerate() .filter_map(|(n, a)| { if n != index { - Some((keypairs[n].public().into_peer_id(), a.clone())) + Some((keypairs[n].public().to_peer_id(), a.clone())) } else { None } @@ -100,7 +100,7 @@ fn build_nodes() -> (Swarm, Swarm) { .collect(), }; - let mut swarm = Swarm::new(transport, behaviour, keypairs[index].public().into_peer_id()); + let mut swarm = Swarm::new(transport, behaviour, keypairs[index].public().to_peer_id()); swarm.listen_on(addrs[index].clone()).unwrap(); out.push(swarm); } @@ -163,8 +163,10 @@ impl NetworkBehaviour for CustomProtoWithAddr { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, + failed_addresses: Option<&Vec>, ) { - self.inner.inject_connection_established(peer_id, conn, endpoint) + self.inner + .inject_connection_established(peer_id, conn, endpoint, failed_addresses) } fn inject_connection_closed( @@ -172,8 +174,9 @@ impl NetworkBehaviour for CustomProtoWithAddr { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, + handler: ::Handler, ) { - self.inner.inject_connection_closed(peer_id, conn, endpoint) + self.inner.inject_connection_closed(peer_id, conn, endpoint, handler) } fn inject_event( @@ -188,27 +191,18 @@ impl NetworkBehaviour for CustomProtoWithAddr { fn poll( &mut self, cx: &mut Context, - params: &mut impl PollParameters - ) -> Poll< - NetworkBehaviourAction< - <::Handler as ProtocolsHandler>::InEvent, - Self::OutEvent - > - >{ + params: &mut impl PollParameters, + ) -> Poll> { self.inner.poll(cx, params) } - fn inject_addr_reach_failure( + fn inject_dial_failure( &mut self, - peer_id: Option<&PeerId>, - addr: &Multiaddr, - error: &dyn std::error::Error, + peer_id: Option, + handler: Self::ProtocolsHandler, + error: &DialError, ) { - self.inner.inject_addr_reach_failure(peer_id, addr, error) - } - - fn inject_dial_failure(&mut self, peer_id: &PeerId) { - self.inner.inject_dial_failure(peer_id) + self.inner.inject_dial_failure(peer_id, handler, error) } fn inject_new_listener(&mut self, id: ListenerId) { diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 0908d7510e359..aa3e1701eee52 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -45,12 +45,12 @@ use libp2p::{ ConnectedPoint, Multiaddr, PeerId, }, request_response::{ - ProtocolSupport, RequestResponse, RequestResponseCodec, RequestResponseConfig, - RequestResponseEvent, RequestResponseMessage, ResponseChannel, + handler::RequestResponseHandler, ProtocolSupport, RequestResponse, RequestResponseCodec, + RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, ResponseChannel, }, swarm::{ - protocols_handler::multi::MultiHandler, NetworkBehaviour, NetworkBehaviourAction, - PollParameters, ProtocolsHandler, + protocols_handler::multi::MultiHandler, IntoProtocolsHandler, NetworkBehaviour, + NetworkBehaviourAction, PollParameters, ProtocolsHandler, }, }; use std::{ @@ -377,6 +377,27 @@ impl RequestResponsesBehaviour { }; } } + + fn new_handler_with_replacement( + &mut self, + protocol: String, + handler: RequestResponseHandler, + ) -> ::ProtocolsHandler { + let mut handlers: HashMap<_, _> = self + .protocols + .iter_mut() + .map(|(p, (r, _))| (p.to_string(), NetworkBehaviour::new_handler(r))) + .collect(); + + if let Some(h) = handlers.get_mut(&protocol) { + *h = handler + } + + MultiHandler::try_from_iter(handlers).expect( + "Protocols are in a HashMap and there can be at most one handler per protocol name, \ + which is the only possible error; qed", + ) + } } impl NetworkBehaviour for RequestResponsesBehaviour { @@ -405,9 +426,16 @@ impl NetworkBehaviour for RequestResponsesBehaviour { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, + failed_addresses: Option<&Vec>, ) { for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_connection_established(p, peer_id, conn, endpoint) + NetworkBehaviour::inject_connection_established( + p, + peer_id, + conn, + endpoint, + failed_addresses, + ) } } @@ -422,9 +450,11 @@ impl NetworkBehaviour for RequestResponsesBehaviour { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, + _handler: ::Handler, ) { for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_connection_closed(p, peer_id, conn, endpoint) + let handler = p.new_handler(); + NetworkBehaviour::inject_connection_closed(p, peer_id, conn, endpoint, handler); } } @@ -434,17 +464,6 @@ impl NetworkBehaviour for RequestResponsesBehaviour { } } - fn inject_addr_reach_failure( - &mut self, - peer_id: Option<&PeerId>, - addr: &Multiaddr, - error: &dyn std::error::Error, - ) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_addr_reach_failure(p, peer_id, addr, error) - } - } - fn inject_event( &mut self, peer_id: PeerId, @@ -478,9 +497,15 @@ impl NetworkBehaviour for RequestResponsesBehaviour { } } - fn inject_dial_failure(&mut self, peer_id: &PeerId) { + fn inject_dial_failure( + &mut self, + peer_id: Option, + _: Self::ProtocolsHandler, + error: &libp2p::swarm::DialError, + ) { for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_dial_failure(p, peer_id) + let handler = p.new_handler(); + NetworkBehaviour::inject_dial_failure(p, peer_id, handler, error) } } @@ -512,12 +537,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { &mut self, cx: &mut Context, params: &mut impl PollParameters, - ) -> Poll< - NetworkBehaviourAction< - ::InEvent, - Self::OutEvent, - >, - > { + ) -> Poll> { 'poll_all: loop { if let Some(message_request) = self.message_request.take() { // Now we can can poll `MessageRequest` until we get the reputation @@ -658,17 +678,26 @@ impl NetworkBehaviour for RequestResponsesBehaviour { // Other events generated by the underlying behaviour are transparently // passed through. - NetworkBehaviourAction::DialAddress { address } => { + NetworkBehaviourAction::DialAddress { address, handler } => { log::error!( "The request-response isn't supposed to start dialing peers" ); - return Poll::Ready(NetworkBehaviourAction::DialAddress { address }) + let protocol = protocol.to_string(); + let handler = self.new_handler_with_replacement(protocol, handler); + return Poll::Ready(NetworkBehaviourAction::DialAddress { + address, + handler, + }) }, - NetworkBehaviourAction::DialPeer { peer_id, condition } => + NetworkBehaviourAction::DialPeer { peer_id, condition, handler } => { + let protocol = protocol.to_string(); + let handler = self.new_handler_with_replacement(protocol, handler); return Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition, - }), + handler, + }) + }, NetworkBehaviourAction::NotifyHandler { peer_id, handler, event } => return Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, @@ -1061,7 +1090,7 @@ mod tests { let behaviour = RequestResponsesBehaviour::new(list, handle).unwrap(); - let mut swarm = Swarm::new(transport, behaviour, keypair.public().into_peer_id()); + let mut swarm = Swarm::new(transport, behaviour, keypair.public().to_peer_id()); let listen_addr: Multiaddr = format!("/memory/{}", rand::random::()).parse().unwrap(); swarm.listen_on(listen_addr.clone()).unwrap(); diff --git a/client/network/src/service.rs b/client/network/src/service.rs index caf4db89f653a..3dadf810c6b49 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -56,10 +56,10 @@ use libp2p::{ }, kad::record, multiaddr, - ping::handler::PingFailure, + ping::Failure as PingFailure, swarm::{ - protocols_handler::NodeHandlerWrapperError, AddressScore, NetworkBehaviour, SwarmBuilder, - SwarmEvent, + protocols_handler::NodeHandlerWrapperError, AddressScore, DialError, NetworkBehaviour, + SwarmBuilder, SwarmEvent, }, Multiaddr, PeerId, }; @@ -176,7 +176,7 @@ impl NetworkWorker { // Private and public keys configuration. let local_identity = params.network_config.node_key.clone().into_keypair()?; let local_public = local_identity.public(); - let local_peer_id = local_public.clone().into_peer_id(); + let local_peer_id = local_public.clone().to_peer_id(); info!( target: "sub-libp2p", "🏷 Local node identity is: {}", @@ -1845,8 +1845,13 @@ impl Future for NetworkWorker { peer_id, endpoint, num_established, + concurrent_dial_errors, }) => { - debug!(target: "sub-libp2p", "Libp2p => Connected({:?})", peer_id); + if let Some(errors) = concurrent_dial_errors { + debug!(target: "sub-libp2p", "Libp2p => Connected({:?}) with errors: {:?}", peer_id, errors); + } else { + debug!(target: "sub-libp2p", "Libp2p => Connected({:?})", peer_id); + } if let Some(metrics) = this.metrics.as_ref() { let direction = match endpoint { @@ -1914,37 +1919,41 @@ impl Future for NetworkWorker { metrics.listeners_local_addresses.dec(); } }, - Poll::Ready(SwarmEvent::UnreachableAddr { peer_id, address, error, .. }) => { - trace!( - target: "sub-libp2p", - "Libp2p => Failed to reach {:?} through {:?}: {}", - peer_id, address, error, - ); + Poll::Ready(SwarmEvent::OutgoingConnectionError { peer_id, error }) => { + if let Some(peer_id) = peer_id { + trace!( + target: "sub-libp2p", + "Libp2p => Failed to reach {:?}: {}", + peer_id, error, + ); - if this.boot_node_ids.contains(&peer_id) { - if let PendingConnectionError::InvalidPeerId = error { - error!( - "💔 The bootnode you want to connect to at `{}` provided a different peer ID than the one you expect: `{}`.", - address, peer_id, - ); + if this.boot_node_ids.contains(&peer_id) { + if let DialError::InvalidPeerId = error { + error!( + "💔 The bootnode you want to connect provided a different peer ID than the one you expect: `{}`.", + peer_id, + ); + } } } if let Some(metrics) = this.metrics.as_ref() { - match error { - PendingConnectionError::ConnectionLimit(_) => metrics - .pending_connections_errors_total - .with_label_values(&["limit-reached"]) - .inc(), - PendingConnectionError::InvalidPeerId => metrics - .pending_connections_errors_total - .with_label_values(&["invalid-peer-id"]) - .inc(), - PendingConnectionError::Transport(_) | - PendingConnectionError::IO(_) => metrics + let reason = match error { + DialError::ConnectionLimit(_) => Some("limit-reached"), + DialError::InvalidPeerId => Some("invalid-peer-id"), + DialError::Transport(_) | DialError::ConnectionIo(_) => + Some("transport-error"), + DialError::Banned | + DialError::LocalPeerId | + DialError::NoAddresses | + DialError::DialPeerConditionFalse(_) | + DialError::Aborted => None, // ignore them + }; + if let Some(reason) = reason { + metrics .pending_connections_errors_total - .with_label_values(&["transport-error"]) - .inc(), + .with_label_values(&[reason]) + .inc(); } } }, @@ -1970,16 +1979,19 @@ impl Future for NetworkWorker { ); if let Some(metrics) = this.metrics.as_ref() { let reason = match error { - PendingConnectionError::ConnectionLimit(_) => "limit-reached", - PendingConnectionError::InvalidPeerId => "invalid-peer-id", + PendingConnectionError::ConnectionLimit(_) => Some("limit-reached"), + PendingConnectionError::InvalidPeerId => Some("invalid-peer-id"), PendingConnectionError::Transport(_) | - PendingConnectionError::IO(_) => "transport-error", + PendingConnectionError::IO(_) => Some("transport-error"), + PendingConnectionError::Aborted => None, // ignore it }; - metrics - .incoming_connections_errors_total - .with_label_values(&[reason]) - .inc(); + if let Some(reason) = reason { + metrics + .incoming_connections_errors_total + .with_label_values(&[reason]) + .inc(); + } } }, Poll::Ready(SwarmEvent::BannedPeer { peer_id, endpoint }) => { @@ -1995,9 +2007,6 @@ impl Future for NetworkWorker { .inc(); } }, - Poll::Ready(SwarmEvent::UnknownPeerUnreachableAddr { address, error }) => { - trace!(target: "sub-libp2p", "Libp2p => UnknownPeerUnreachableAddr({}): {}", address, error) - }, Poll::Ready(SwarmEvent::ListenerClosed { reason, addresses, .. }) => { if let Some(metrics) = this.metrics.as_ref() { metrics.listeners_local_addresses.sub(addresses.len() as u64); diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 539c57fe4cb91..84aab96a673d6 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -20,7 +20,7 @@ parking_lot = "0.11.1" futures = "0.3.9" futures-timer = "3.0.1" rand = "0.7.2" -libp2p = { version = "0.39.1", default-features = false } +libp2p = { version = "0.40.0", default-features = false } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index fba499bce00e3..ec226b3d9bee2 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.9" -libp2p = { version = "0.39.1", default-features = false } +libp2p = { version = "0.40.0", default-features = false } sc-utils = { version = "4.0.0-dev", path = "../utils"} log = "0.4.8" serde_json = "1.0.71" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 9165f6f87af68..73efdbc039c51 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] parking_lot = "0.11.1" futures = "0.3.9" wasm-timer = "0.2.5" -libp2p = { version = "0.39.1", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } +libp2p = { version = "0.40.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.8" pin-project = "1.0.8" rand = "0.7.2" From 5714e30cd280906a8f20e699b187fdef22989ffc Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 25 Nov 2021 02:24:45 -0800 Subject: [PATCH 0280/1472] REAL fix for `min-square` for `--steps=1 --repeats=1` (#10323) (#10369) * Revert "frame-benchmarking: Fix `min-square` for `--steps=1` (#10323)" This reverts commit fe7c02941122bbe4a7956aff53739b62f575240d. * actual fix --- frame/benchmarking/src/analysis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index 6e0ffd23ee988..f655e8fa76320 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -199,7 +199,7 @@ impl Analysis { } pub fn min_squares_iqr(r: &Vec, selector: BenchmarkSelector) -> Option { - if r[0].components.len() <= 1 { + if r[0].components.is_empty() || r.len() <= 2 { return Self::median_value(r, selector) } From 120bd65e3ee8113f83bf77843ed239daf8cdbbfd Mon Sep 17 00:00:00 2001 From: Andreas Doerr Date: Thu, 25 Nov 2021 11:26:10 +0100 Subject: [PATCH 0281/1472] `BEEFY` add tests for rounds (#10328) * new_rounds() * WIP * test add_vote() * test drop() * learn to spell * go get some coffee * cargo fmt * lump everythings together again --- Cargo.lock | 1 + client/beefy/Cargo.toml | 1 + client/beefy/src/gossip.rs | 178 ++++++++++++++++++- client/beefy/src/gossip_tests.rs | 182 ------------------- client/beefy/src/keystore.rs | 269 +++++++++++++++++++++++++++- client/beefy/src/keystore_tests.rs | 275 ----------------------------- client/beefy/src/round.rs | 151 ++++++++++++++++ 7 files changed, 592 insertions(+), 465 deletions(-) delete mode 100644 client/beefy/src/gossip_tests.rs delete mode 100644 client/beefy/src/keystore_tests.rs diff --git a/Cargo.lock b/Cargo.lock index 3e956ea462ee7..08d39c1d2b3de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -494,6 +494,7 @@ dependencies = [ "sp-core", "sp-keystore", "sp-runtime", + "sp-tracing", "strum", "substrate-prometheus-endpoint", "thiserror", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 96e5bc4ffbf31..23c9294d35100 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -35,6 +35,7 @@ sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } [dev-dependencies] +sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } sc-network-test = { version = "0.8.0", path = "../network/test" } strum = { version = "0.22", features = ["derive"] } diff --git a/client/beefy/src/gossip.rs b/client/beefy/src/gossip.rs index d0199964b6ebf..8a43b5a039478 100644 --- a/client/beefy/src/gossip.rs +++ b/client/beefy/src/gossip.rs @@ -35,10 +35,6 @@ use beefy_primitives::{ use crate::keystore::BeefyKeystore; -#[cfg(test)] -#[path = "gossip_tests.rs"] -mod tests; - // Limit BEEFY gossip by keeping only a bound number of voting rounds alive. const MAX_LIVE_GOSSIP_ROUNDS: usize = 3; @@ -234,3 +230,177 @@ where }) } } + +#[cfg(test)] +mod tests { + use sc_keystore::LocalKeystore; + use sc_network_test::Block; + use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; + + use beefy_primitives::{crypto::Signature, Commitment, MmrRootHash, VoteMessage, KEY_TYPE}; + + use crate::keystore::{tests::Keyring, BeefyKeystore}; + + use super::*; + + #[test] + fn note_round_works() { + let gv = GossipValidator::::new(); + + gv.note_round(1u64); + + let live = gv.known_votes.read(); + assert!(GossipValidator::::is_live(&live, &1u64)); + + drop(live); + + gv.note_round(3u64); + gv.note_round(7u64); + gv.note_round(10u64); + + let live = gv.known_votes.read(); + + assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + + assert!(!GossipValidator::::is_live(&live, &1u64)); + assert!(GossipValidator::::is_live(&live, &3u64)); + assert!(GossipValidator::::is_live(&live, &7u64)); + assert!(GossipValidator::::is_live(&live, &10u64)); + } + + #[test] + fn keeps_most_recent_max_rounds() { + let gv = GossipValidator::::new(); + + gv.note_round(3u64); + gv.note_round(7u64); + gv.note_round(10u64); + gv.note_round(1u64); + + let live = gv.known_votes.read(); + + assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + + assert!(GossipValidator::::is_live(&live, &3u64)); + assert!(!GossipValidator::::is_live(&live, &1u64)); + + drop(live); + + gv.note_round(23u64); + gv.note_round(15u64); + gv.note_round(20u64); + gv.note_round(2u64); + + let live = gv.known_votes.read(); + + assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + + assert!(GossipValidator::::is_live(&live, &15u64)); + assert!(GossipValidator::::is_live(&live, &20u64)); + assert!(GossipValidator::::is_live(&live, &23u64)); + } + + #[test] + fn note_same_round_twice() { + let gv = GossipValidator::::new(); + + gv.note_round(3u64); + gv.note_round(7u64); + gv.note_round(10u64); + + let live = gv.known_votes.read(); + + assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + + drop(live); + + // note round #7 again -> should not change anything + gv.note_round(7u64); + + let live = gv.known_votes.read(); + + assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + + assert!(GossipValidator::::is_live(&live, &3u64)); + assert!(GossipValidator::::is_live(&live, &7u64)); + assert!(GossipValidator::::is_live(&live, &10u64)); + } + + struct TestContext; + impl ValidatorContext for TestContext { + fn broadcast_topic(&mut self, _topic: B::Hash, _force: bool) { + todo!() + } + + fn broadcast_message(&mut self, _topic: B::Hash, _message: Vec, _force: bool) { + todo!() + } + + fn send_message(&mut self, _who: &sc_network::PeerId, _message: Vec) { + todo!() + } + + fn send_topic(&mut self, _who: &sc_network::PeerId, _topic: B::Hash, _force: bool) { + todo!() + } + } + + fn sign_commitment( + who: &Keyring, + commitment: &Commitment, + ) -> Signature { + let store: SyncCryptoStorePtr = std::sync::Arc::new(LocalKeystore::in_memory()); + SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&who.to_seed())).unwrap(); + let beefy_keystore: BeefyKeystore = Some(store).into(); + + beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() + } + + #[test] + fn should_avoid_verifying_signatures_twice() { + let gv = GossipValidator::::new(); + let sender = sc_network::PeerId::random(); + let mut context = TestContext; + + let commitment = Commitment { + payload: MmrRootHash::default(), + block_number: 3_u64, + validator_set_id: 0, + }; + + let signature = sign_commitment(&Keyring::Alice, &commitment); + + let vote = VoteMessage { commitment, id: Keyring::Alice.public(), signature }; + + gv.note_round(3u64); + gv.note_round(7u64); + gv.note_round(10u64); + + // first time the cache should be populated. + let res = gv.validate(&mut context, &sender, &vote.encode()); + + assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); + assert_eq!( + gv.known_votes.read().get(&vote.commitment.block_number).map(|x| x.len()), + Some(1) + ); + + // second time we should hit the cache + let res = gv.validate(&mut context, &sender, &vote.encode()); + + assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); + + // next we should quickly reject if the round is not live. + gv.note_round(11_u64); + gv.note_round(12_u64); + + assert!(!GossipValidator::::is_live( + &*gv.known_votes.read(), + &vote.commitment.block_number + )); + + let res = gv.validate(&mut context, &sender, &vote.encode()); + + assert!(matches!(res, ValidationResult::Discard)); + } +} diff --git a/client/beefy/src/gossip_tests.rs b/client/beefy/src/gossip_tests.rs deleted file mode 100644 index 2d46b873cb7b0..0000000000000 --- a/client/beefy/src/gossip_tests.rs +++ /dev/null @@ -1,182 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use sc_keystore::LocalKeystore; -use sc_network_test::Block; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; - -use beefy_primitives::{crypto::Signature, Commitment, MmrRootHash, VoteMessage, KEY_TYPE}; - -use crate::keystore::{tests::Keyring, BeefyKeystore}; - -use super::*; - -#[test] -fn note_round_works() { - let gv = GossipValidator::::new(); - - gv.note_round(1u64); - - let live = gv.known_votes.read(); - assert!(GossipValidator::::is_live(&live, &1u64)); - - drop(live); - - gv.note_round(3u64); - gv.note_round(7u64); - gv.note_round(10u64); - - let live = gv.known_votes.read(); - - assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); - - assert!(!GossipValidator::::is_live(&live, &1u64)); - assert!(GossipValidator::::is_live(&live, &3u64)); - assert!(GossipValidator::::is_live(&live, &7u64)); - assert!(GossipValidator::::is_live(&live, &10u64)); -} - -#[test] -fn keeps_most_recent_max_rounds() { - let gv = GossipValidator::::new(); - - gv.note_round(3u64); - gv.note_round(7u64); - gv.note_round(10u64); - gv.note_round(1u64); - - let live = gv.known_votes.read(); - - assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); - - assert!(GossipValidator::::is_live(&live, &3u64)); - assert!(!GossipValidator::::is_live(&live, &1u64)); - - drop(live); - - gv.note_round(23u64); - gv.note_round(15u64); - gv.note_round(20u64); - gv.note_round(2u64); - - let live = gv.known_votes.read(); - - assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); - - assert!(GossipValidator::::is_live(&live, &15u64)); - assert!(GossipValidator::::is_live(&live, &20u64)); - assert!(GossipValidator::::is_live(&live, &23u64)); -} - -#[test] -fn note_same_round_twice() { - let gv = GossipValidator::::new(); - - gv.note_round(3u64); - gv.note_round(7u64); - gv.note_round(10u64); - - let live = gv.known_votes.read(); - - assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); - - drop(live); - - // note round #7 again -> should not change anything - gv.note_round(7u64); - - let live = gv.known_votes.read(); - - assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); - - assert!(GossipValidator::::is_live(&live, &3u64)); - assert!(GossipValidator::::is_live(&live, &7u64)); - assert!(GossipValidator::::is_live(&live, &10u64)); -} - -struct TestContext; -impl ValidatorContext for TestContext { - fn broadcast_topic(&mut self, _topic: B::Hash, _force: bool) { - todo!() - } - - fn broadcast_message(&mut self, _topic: B::Hash, _message: Vec, _force: bool) { - todo!() - } - - fn send_message(&mut self, _who: &sc_network::PeerId, _message: Vec) { - todo!() - } - - fn send_topic(&mut self, _who: &sc_network::PeerId, _topic: B::Hash, _force: bool) { - todo!() - } -} - -fn sign_commitment( - who: &Keyring, - commitment: &Commitment, -) -> Signature { - let store: SyncCryptoStorePtr = std::sync::Arc::new(LocalKeystore::in_memory()); - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&who.to_seed())).unwrap(); - let beefy_keystore: BeefyKeystore = Some(store).into(); - - beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() -} - -#[test] -fn should_avoid_verifying_signatures_twice() { - let gv = GossipValidator::::new(); - let sender = sc_network::PeerId::random(); - let mut context = TestContext; - - let commitment = - Commitment { payload: MmrRootHash::default(), block_number: 3_u64, validator_set_id: 0 }; - - let signature = sign_commitment(&Keyring::Alice, &commitment); - - let vote = VoteMessage { commitment, id: Keyring::Alice.public(), signature }; - - gv.note_round(3u64); - gv.note_round(7u64); - gv.note_round(10u64); - - // first time the cache should be populated. - let res = gv.validate(&mut context, &sender, &vote.encode()); - - assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); - assert_eq!(gv.known_votes.read().get(&vote.commitment.block_number).map(|x| x.len()), Some(1)); - - // second time we should hit the cache - let res = gv.validate(&mut context, &sender, &vote.encode()); - - assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); - - // next we should quickly reject if the round is not live. - gv.note_round(11_u64); - gv.note_round(12_u64); - - assert!(!GossipValidator::::is_live( - &*gv.known_votes.read(), - &vote.commitment.block_number - )); - - let res = gv.validate(&mut context, &sender, &vote.encode()); - - assert!(matches!(res, ValidationResult::Discard)); -} diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index 88618b8a5a140..7ee1ceb46bc35 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -31,10 +31,6 @@ use beefy_primitives::{ use crate::error; -#[cfg(test)] -#[path = "keystore_tests.rs"] -pub mod tests; - /// A BEEFY specific keystore implemented as a `Newtype`. This is basically a /// wrapper around [`sp_keystore::SyncCryptoStore`] and allows to customize /// common cryptographic functionality. @@ -117,3 +113,268 @@ impl From> for BeefyKeystore { BeefyKeystore(store) } } + +#[cfg(test)] +pub mod tests { + use std::sync::Arc; + + use sc_keystore::LocalKeystore; + use sp_core::{ecdsa, keccak_256, Pair}; + use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; + + use beefy_primitives::{crypto, KEY_TYPE}; + + use super::BeefyKeystore; + use crate::error::Error; + + /// Set of test accounts using [`beefy_primitives::crypto`] types. + #[allow(missing_docs)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display, strum::EnumIter)] + pub(crate) enum Keyring { + Alice, + Bob, + Charlie, + Dave, + Eve, + Ferdie, + One, + Two, + } + + impl Keyring { + /// Sign `msg`. + pub fn sign(self, msg: &[u8]) -> crypto::Signature { + let msg = keccak_256(msg); + ecdsa::Pair::from(self).sign_prehashed(&msg).into() + } + + /// Return key pair. + pub fn pair(self) -> crypto::Pair { + ecdsa::Pair::from_string(self.to_seed().as_str(), None).unwrap().into() + } + + /// Return public key. + pub fn public(self) -> crypto::Public { + self.pair().public() + } + + /// Return seed string. + pub fn to_seed(self) -> String { + format!("//{}", self) + } + } + + impl From for crypto::Pair { + fn from(k: Keyring) -> Self { + k.pair() + } + } + + impl From for ecdsa::Pair { + fn from(k: Keyring) -> Self { + k.pair().into() + } + } + + fn keystore() -> SyncCryptoStorePtr { + Arc::new(LocalKeystore::in_memory()) + } + + #[test] + fn verify_should_work() { + let msg = keccak_256(b"I am Alice!"); + let sig = Keyring::Alice.sign(b"I am Alice!"); + + assert!(ecdsa::Pair::verify_prehashed( + &sig.clone().into(), + &msg, + &Keyring::Alice.public().into(), + )); + + // different public key -> fail + assert!(!ecdsa::Pair::verify_prehashed( + &sig.clone().into(), + &msg, + &Keyring::Bob.public().into(), + )); + + let msg = keccak_256(b"I am not Alice!"); + + // different msg -> fail + assert!( + !ecdsa::Pair::verify_prehashed(&sig.into(), &msg, &Keyring::Alice.public().into(),) + ); + } + + #[test] + fn pair_works() { + let want = crypto::Pair::from_string("//Alice", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Alice.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Bob", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Bob.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Charlie", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Charlie.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Dave", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Dave.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Eve", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Eve.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Ferdie", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Ferdie.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//One", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::One.pair().to_raw_vec(); + assert_eq!(want, got); + + let want = crypto::Pair::from_string("//Two", None).expect("Pair failed").to_raw_vec(); + let got = Keyring::Two.pair().to_raw_vec(); + assert_eq!(want, got); + } + + #[test] + fn authority_id_works() { + let store = keystore(); + + let alice: crypto::Public = + SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) + .ok() + .unwrap() + .into(); + + let bob = Keyring::Bob.public(); + let charlie = Keyring::Charlie.public(); + + let store: BeefyKeystore = Some(store).into(); + + let mut keys = vec![bob, charlie]; + + let id = store.authority_id(keys.as_slice()); + assert!(id.is_none()); + + keys.push(alice.clone()); + + let id = store.authority_id(keys.as_slice()).unwrap(); + assert_eq!(id, alice); + } + + #[test] + fn sign_works() { + let store = keystore(); + + let alice: crypto::Public = + SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) + .ok() + .unwrap() + .into(); + + let store: BeefyKeystore = Some(store).into(); + + let msg = b"are you involved or commited?"; + + let sig1 = store.sign(&alice, msg).unwrap(); + let sig2 = Keyring::Alice.sign(msg); + + assert_eq!(sig1, sig2); + } + + #[test] + fn sign_error() { + let store = keystore(); + + let _ = + SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Bob.to_seed())) + .ok() + .unwrap(); + + let store: BeefyKeystore = Some(store).into(); + + let alice = Keyring::Alice.public(); + + let msg = b"are you involved or commited?"; + let sig = store.sign(&alice, msg).err().unwrap(); + let err = Error::Signature("ecdsa_sign_prehashed() failed".to_string()); + + assert_eq!(sig, err); + } + + #[test] + fn sign_no_keystore() { + let store: BeefyKeystore = None.into(); + + let alice = Keyring::Alice.public(); + let msg = b"are you involved or commited"; + + let sig = store.sign(&alice, msg).err().unwrap(); + let err = Error::Keystore("no Keystore".to_string()); + assert_eq!(sig, err); + } + + #[test] + fn verify_works() { + let store = keystore(); + + let alice: crypto::Public = + SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) + .ok() + .unwrap() + .into(); + + let store: BeefyKeystore = Some(store).into(); + + // `msg` and `sig` match + let msg = b"are you involved or commited?"; + let sig = store.sign(&alice, msg).unwrap(); + assert!(BeefyKeystore::verify(&alice, &sig, msg)); + + // `msg and `sig` don't match + let msg = b"you are just involved"; + assert!(!BeefyKeystore::verify(&alice, &sig, msg)); + } + + // Note that we use keys with and without a seed for this test. + #[test] + fn public_keys_works() { + const TEST_TYPE: sp_application_crypto::KeyTypeId = + sp_application_crypto::KeyTypeId(*b"test"); + + let store = keystore(); + + let add_key = |key_type, seed: Option<&str>| { + SyncCryptoStore::ecdsa_generate_new(&*store, key_type, seed).unwrap() + }; + + // test keys + let _ = add_key(TEST_TYPE, Some(Keyring::Alice.to_seed().as_str())); + let _ = add_key(TEST_TYPE, Some(Keyring::Bob.to_seed().as_str())); + + let _ = add_key(TEST_TYPE, None); + let _ = add_key(TEST_TYPE, None); + + // BEEFY keys + let _ = add_key(KEY_TYPE, Some(Keyring::Dave.to_seed().as_str())); + let _ = add_key(KEY_TYPE, Some(Keyring::Eve.to_seed().as_str())); + + let key1: crypto::Public = add_key(KEY_TYPE, None).into(); + let key2: crypto::Public = add_key(KEY_TYPE, None).into(); + + let store: BeefyKeystore = Some(store).into(); + + let keys = store.public_keys().ok().unwrap(); + + assert!(keys.len() == 4); + assert!(keys.contains(&Keyring::Dave.public())); + assert!(keys.contains(&Keyring::Eve.public())); + assert!(keys.contains(&key1)); + assert!(keys.contains(&key2)); + } +} diff --git a/client/beefy/src/keystore_tests.rs b/client/beefy/src/keystore_tests.rs deleted file mode 100644 index 99e3e42228df2..0000000000000 --- a/client/beefy/src/keystore_tests.rs +++ /dev/null @@ -1,275 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use std::sync::Arc; - -use sc_keystore::LocalKeystore; -use sp_core::{ecdsa, keccak_256, Pair}; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; - -use beefy_primitives::{crypto, KEY_TYPE}; - -use super::BeefyKeystore; -use crate::error::Error; - -/// Set of test accounts using [`beefy_primitives::crypto`] types. -#[allow(missing_docs)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display, strum::EnumIter)] -pub(crate) enum Keyring { - Alice, - Bob, - Charlie, - Dave, - Eve, - Ferdie, - One, - Two, -} - -impl Keyring { - /// Sign `msg`. - pub fn sign(self, msg: &[u8]) -> crypto::Signature { - let msg = keccak_256(msg); - ecdsa::Pair::from(self).sign_prehashed(&msg).into() - } - - /// Return key pair. - pub fn pair(self) -> crypto::Pair { - ecdsa::Pair::from_string(self.to_seed().as_str(), None).unwrap().into() - } - - /// Return public key. - pub fn public(self) -> crypto::Public { - self.pair().public() - } - - /// Return seed string. - pub fn to_seed(self) -> String { - format!("//{}", self) - } -} - -impl From for crypto::Pair { - fn from(k: Keyring) -> Self { - k.pair() - } -} - -impl From for ecdsa::Pair { - fn from(k: Keyring) -> Self { - k.pair().into() - } -} - -fn keystore() -> SyncCryptoStorePtr { - Arc::new(LocalKeystore::in_memory()) -} - -#[test] -fn verify_should_work() { - let msg = keccak_256(b"I am Alice!"); - let sig = Keyring::Alice.sign(b"I am Alice!"); - - assert!(ecdsa::Pair::verify_prehashed( - &sig.clone().into(), - &msg, - &Keyring::Alice.public().into(), - )); - - // different public key -> fail - assert!(!ecdsa::Pair::verify_prehashed( - &sig.clone().into(), - &msg, - &Keyring::Bob.public().into(), - )); - - let msg = keccak_256(b"I am not Alice!"); - - // different msg -> fail - assert!(!ecdsa::Pair::verify_prehashed(&sig.into(), &msg, &Keyring::Alice.public().into(),)); -} - -#[test] -fn pair_works() { - let want = crypto::Pair::from_string("//Alice", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Alice.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = crypto::Pair::from_string("//Bob", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Bob.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = crypto::Pair::from_string("//Charlie", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Charlie.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = crypto::Pair::from_string("//Dave", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Dave.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = crypto::Pair::from_string("//Eve", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Eve.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = crypto::Pair::from_string("//Ferdie", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Ferdie.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = crypto::Pair::from_string("//One", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::One.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = crypto::Pair::from_string("//Two", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Two.pair().to_raw_vec(); - assert_eq!(want, got); -} - -#[test] -fn authority_id_works() { - let store = keystore(); - - let alice: crypto::Public = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); - - let bob = Keyring::Bob.public(); - let charlie = Keyring::Charlie.public(); - - let store: BeefyKeystore = Some(store).into(); - - let mut keys = vec![bob, charlie]; - - let id = store.authority_id(keys.as_slice()); - assert!(id.is_none()); - - keys.push(alice.clone()); - - let id = store.authority_id(keys.as_slice()).unwrap(); - assert_eq!(id, alice); -} - -#[test] -fn sign_works() { - let store = keystore(); - - let alice: crypto::Public = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); - - let store: BeefyKeystore = Some(store).into(); - - let msg = b"are you involved or commited?"; - - let sig1 = store.sign(&alice, msg).unwrap(); - let sig2 = Keyring::Alice.sign(msg); - - assert_eq!(sig1, sig2); -} - -#[test] -fn sign_error() { - let store = keystore(); - - let _ = SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Bob.to_seed())) - .ok() - .unwrap(); - - let store: BeefyKeystore = Some(store).into(); - - let alice = Keyring::Alice.public(); - - let msg = b"are you involved or commited?"; - let sig = store.sign(&alice, msg).err().unwrap(); - let err = Error::Signature("ecdsa_sign_prehashed() failed".to_string()); - - assert_eq!(sig, err); -} - -#[test] -fn sign_no_keystore() { - let store: BeefyKeystore = None.into(); - - let alice = Keyring::Alice.public(); - let msg = b"are you involved or commited"; - - let sig = store.sign(&alice, msg).err().unwrap(); - let err = Error::Keystore("no Keystore".to_string()); - assert_eq!(sig, err); -} - -#[test] -fn verify_works() { - let store = keystore(); - - let alice: crypto::Public = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); - - let store: BeefyKeystore = Some(store).into(); - - // `msg` and `sig` match - let msg = b"are you involved or commited?"; - let sig = store.sign(&alice, msg).unwrap(); - assert!(BeefyKeystore::verify(&alice, &sig, msg)); - - // `msg and `sig` don't match - let msg = b"you are just involved"; - assert!(!BeefyKeystore::verify(&alice, &sig, msg)); -} - -// Note that we use keys with and without a seed for this test. -#[test] -fn public_keys_works() { - const TEST_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"test"); - - let store = keystore(); - - let add_key = |key_type, seed: Option<&str>| { - SyncCryptoStore::ecdsa_generate_new(&*store, key_type, seed).unwrap() - }; - - // test keys - let _ = add_key(TEST_TYPE, Some(Keyring::Alice.to_seed().as_str())); - let _ = add_key(TEST_TYPE, Some(Keyring::Bob.to_seed().as_str())); - - let _ = add_key(TEST_TYPE, None); - let _ = add_key(TEST_TYPE, None); - - // BEEFY keys - let _ = add_key(KEY_TYPE, Some(Keyring::Dave.to_seed().as_str())); - let _ = add_key(KEY_TYPE, Some(Keyring::Eve.to_seed().as_str())); - - let key1: crypto::Public = add_key(KEY_TYPE, None).into(); - let key2: crypto::Public = add_key(KEY_TYPE, None).into(); - - let store: BeefyKeystore = Some(store).into(); - - let keys = store.public_keys().ok().unwrap(); - - assert!(keys.len() == 4); - assert!(keys.contains(&Keyring::Dave.public())); - assert!(keys.contains(&Keyring::Eve.public())); - assert!(keys.contains(&key1)); - assert!(keys.contains(&key2)); -} diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index 51284c9bd2f6e..e9f5ad2062433 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -123,3 +123,154 @@ where ) } } + +#[cfg(test)] +mod tests { + use sc_network_test::Block; + use sp_core::H256; + use sp_runtime::traits::NumberFor; + + use beefy_primitives::{crypto::Public, ValidatorSet}; + + use super::Rounds; + use crate::keystore::tests::Keyring; + + #[test] + fn new_rounds() { + sp_tracing::try_init_simple(); + + let rounds = Rounds::>::new(ValidatorSet::::empty()); + + assert_eq!(0, rounds.validator_set_id()); + assert!(rounds.validators().is_empty()); + + let validators = ValidatorSet:: { + validators: vec![ + Keyring::Alice.public(), + Keyring::Bob.public(), + Keyring::Charlie.public(), + ], + id: 42, + }; + + let rounds = Rounds::>::new(validators); + + assert_eq!(42, rounds.validator_set_id()); + + assert_eq!( + vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + rounds.validators() + ); + } + + #[test] + fn add_vote() { + sp_tracing::try_init_simple(); + + let validators = ValidatorSet:: { + validators: vec![ + Keyring::Alice.public(), + Keyring::Bob.public(), + Keyring::Charlie.public(), + ], + id: Default::default(), + }; + + let mut rounds = Rounds::>::new(validators); + + assert!(rounds.add_vote( + (H256::from_low_u64_le(1), 1), + (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")) + )); + + assert!(!rounds.is_done(&(H256::from_low_u64_le(1), 1))); + + // invalid vote + assert!(!rounds.add_vote( + (H256::from_low_u64_le(1), 1), + (Keyring::Dave.public(), Keyring::Dave.sign(b"I am committed")) + )); + + assert!(!rounds.is_done(&(H256::from_low_u64_le(1), 1))); + + assert!(rounds.add_vote( + (H256::from_low_u64_le(1), 1), + (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")) + )); + + assert!(!rounds.is_done(&(H256::from_low_u64_le(1), 1))); + + assert!(rounds.add_vote( + (H256::from_low_u64_le(1), 1), + (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am committed")) + )); + + assert!(rounds.is_done(&(H256::from_low_u64_le(1), 1))); + } + + #[test] + fn drop() { + sp_tracing::try_init_simple(); + + let validators = ValidatorSet:: { + validators: vec![ + Keyring::Alice.public(), + Keyring::Bob.public(), + Keyring::Charlie.public(), + ], + id: Default::default(), + }; + + let mut rounds = Rounds::>::new(validators); + + // round 1 + rounds.add_vote( + (H256::from_low_u64_le(1), 1), + (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), + ); + rounds.add_vote( + (H256::from_low_u64_le(1), 1), + (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")), + ); + + // round 2 + rounds.add_vote( + (H256::from_low_u64_le(2), 2), + (Keyring::Alice.public(), Keyring::Alice.sign(b"I am again committed")), + ); + rounds.add_vote( + (H256::from_low_u64_le(2), 2), + (Keyring::Bob.public(), Keyring::Bob.sign(b"I am again committed")), + ); + + // round 3 + rounds.add_vote( + (H256::from_low_u64_le(3), 3), + (Keyring::Alice.public(), Keyring::Alice.sign(b"I am still committed")), + ); + rounds.add_vote( + (H256::from_low_u64_le(3), 3), + (Keyring::Bob.public(), Keyring::Bob.sign(b"I am still committed")), + ); + + assert_eq!(3, rounds.rounds.len()); + + // drop unknown round + assert!(rounds.drop(&(H256::from_low_u64_le(5), 5)).is_none()); + assert_eq!(3, rounds.rounds.len()); + + // drop round 2 + let signatures = rounds.drop(&(H256::from_low_u64_le(2), 2)).unwrap(); + + assert_eq!(2, rounds.rounds.len()); + + assert_eq!( + signatures, + vec![ + Some(Keyring::Alice.sign(b"I am again committed")), + Some(Keyring::Bob.sign(b"I am again committed")), + None + ] + ); + } +} From 4f3c3a5d9b6587482f5a57e83c44fcfb79d4d844 Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Fri, 26 Nov 2021 05:38:21 +0100 Subject: [PATCH 0282/1472] remove base weight annotations (#10373) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove base weight annotations * Update frame/scheduler/src/lib.rs Co-authored-by: Shawn Tabrizi Co-authored-by: Damilare Co-authored-by: Bastian Köcher Co-authored-by: Shawn Tabrizi --- frame/balances/src/lib.rs | 17 -------------- frame/scheduler/src/lib.rs | 46 -------------------------------------- frame/system/src/lib.rs | 29 ------------------------ 3 files changed, 92 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index b7c64da460768..4471ed91a9afc 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -271,8 +271,6 @@ pub mod pallet { /// - `transfer_keep_alive` works the same way as `transfer`, but has an additional check /// that the transfer will not kill the origin account. /// --------------------------------- - /// - Base Weight: 73.64 µs, worst case scenario (account created, account removed) - /// - DB Weight: 1 Read and 1 Write to destination account /// - Origin account is already in memory, so no DB operations for them. /// # #[pallet::weight(T::WeightInfo::transfer())] @@ -300,16 +298,6 @@ pub mod pallet { /// it will reset the account nonce (`frame_system::AccountNonce`). /// /// The dispatch origin for this call is `root`. - /// - /// # - /// - Independent of the arguments. - /// - Contains a limited number of reads and writes. - /// --------------------- - /// - Base Weight: - /// - Creating: 27.56 µs - /// - Killing: 35.11 µs - /// - DB Weight: 1 Read, 1 Write to `who` - /// # #[pallet::weight( T::WeightInfo::set_balance_creating() // Creates a new account. .max(T::WeightInfo::set_balance_killing()) // Kills an existing account. @@ -381,11 +369,6 @@ pub mod pallet { /// 99% of the time you want [`transfer`] instead. /// /// [`transfer`]: struct.Pallet.html#method.transfer - /// # - /// - Cheaper than transfer because account cannot be killed. - /// - Base Weight: 51.4 µs - /// - DB Weight: 1 Read and 1 Write to dest (sender is in overlay already) - /// # #[pallet::weight(T::WeightInfo::transfer_keep_alive())] pub fn transfer_keep_alive( origin: OriginFor, diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index d59c42cc850dd..d25fc3b376e83 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -243,16 +243,6 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { /// Execute the scheduled calls - /// - /// # - /// - S = Number of already scheduled calls - /// - N = Named scheduled calls - /// - P = Periodic Calls - /// - Base Weight: 9.243 + 23.45 * S µs - /// - DB Weight: - /// - Read: Agenda + Lookup * N + Agenda(Future) * P - /// - Write: Agenda + Lookup * N + Agenda(future) * P - /// # fn on_initialize(now: T::BlockNumber) -> Weight { let limit = T::MaximumWeight::get(); let mut queued = Agenda::::take(now) @@ -352,15 +342,6 @@ pub mod pallet { #[pallet::call] impl Pallet { /// Anonymously schedule a task. - /// - /// # - /// - S = Number of already scheduled calls - /// - Base Weight: 22.29 + .126 * S µs - /// - DB Weight: - /// - Read: Agenda - /// - Write: Agenda - /// - Will use base weight of 25 which should be good for up to 30 scheduled calls - /// # #[pallet::weight(::WeightInfo::schedule(T::MaxScheduledPerBlock::get()))] pub fn schedule( origin: OriginFor, @@ -382,15 +363,6 @@ pub mod pallet { } /// Cancel an anonymously scheduled task. - /// - /// # - /// - S = Number of already scheduled calls - /// - Base Weight: 22.15 + 2.869 * S µs - /// - DB Weight: - /// - Read: Agenda - /// - Write: Agenda, Lookup - /// - Will use base weight of 100 which should be good for up to 30 scheduled calls - /// # #[pallet::weight(::WeightInfo::cancel(T::MaxScheduledPerBlock::get()))] pub fn cancel(origin: OriginFor, when: T::BlockNumber, index: u32) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; @@ -400,15 +372,6 @@ pub mod pallet { } /// Schedule a named task. - /// - /// # - /// - S = Number of already scheduled calls - /// - Base Weight: 29.6 + .159 * S µs - /// - DB Weight: - /// - Read: Agenda, Lookup - /// - Write: Agenda, Lookup - /// - Will use base weight of 35 which should be good for more than 30 scheduled calls - /// # #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] pub fn schedule_named( origin: OriginFor, @@ -432,15 +395,6 @@ pub mod pallet { } /// Cancel a named scheduled task. - /// - /// # - /// - S = Number of already scheduled calls - /// - Base Weight: 24.91 + 2.907 * S µs - /// - DB Weight: - /// - Read: Agenda, Lookup - /// - Write: Agenda, Lookup - /// - Will use base weight of 100 which should be good for up to 30 scheduled calls - /// # #[pallet::weight(::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))] pub fn cancel_named(origin: OriginFor, id: Vec) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 12361ed859d0e..0b00a7d8f5973 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -351,14 +351,6 @@ pub mod pallet { } /// Set the number of pages in the WebAssembly environment's heap. - /// - /// # - /// - `O(1)` - /// - 1 storage write. - /// - Base Weight: 1.405 µs - /// - 1 write to HEAP_PAGES - /// - 1 digest item - /// # #[pallet::weight((T::SystemWeightInfo::set_heap_pages(), DispatchClass::Operational))] pub fn set_heap_pages(origin: OriginFor, pages: u64) -> DispatchResultWithPostInfo { ensure_root(origin)?; @@ -407,13 +399,6 @@ pub mod pallet { } /// Set some items of storage. - /// - /// # - /// - `O(I)` where `I` length of `items` - /// - `I` storage writes (`O(1)`). - /// - Base Weight: 0.568 * i µs - /// - Writes: Number of items - /// # #[pallet::weight(( T::SystemWeightInfo::set_storage(items.len() as u32), DispatchClass::Operational, @@ -430,13 +415,6 @@ pub mod pallet { } /// Kill some items from storage. - /// - /// # - /// - `O(IK)` where `I` length of `keys` and `K` length of one key - /// - `I` storage deletions. - /// - Base Weight: .378 * i µs - /// - Writes: Number of items - /// # #[pallet::weight(( T::SystemWeightInfo::kill_storage(keys.len() as u32), DispatchClass::Operational, @@ -453,13 +431,6 @@ pub mod pallet { /// /// **NOTE:** We rely on the Root origin to provide us the number of subkeys under /// the prefix we are removing to accurately calculate the weight of this function. - /// - /// # - /// - `O(P)` where `P` amount of keys with prefix `prefix` - /// - `P` storage deletions. - /// - Base Weight: 0.834 * P µs - /// - Writes: Number of subkeys + 1 - /// # #[pallet::weight(( T::SystemWeightInfo::kill_prefix(_subkeys.saturating_add(1)), DispatchClass::Operational, From de6033a2aa4f0191877200516fbc2655399faa4b Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 26 Nov 2021 00:58:00 -0800 Subject: [PATCH 0283/1472] Update W3F URL links (#10374) --- frame/staking/src/slashing.rs | 2 +- frame/transaction-payment/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 066142d8ecc24..acfb30fb81482 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -47,7 +47,7 @@ //! has multiple misbehaviors. However, accounting for such cases is necessary //! to deter a class of "rage-quit" attacks. //! -//! Based on research at +//! Based on research at use crate::{ BalanceOf, Config, EraIndex, Error, Exposure, NegativeImbalanceOf, Pallet, Perbill, diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index a0d8aeb11706d..f912866f7bb39 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -127,7 +127,7 @@ type BalanceOf = <::OnChargeTransaction as OnChargeTransaction +/// pub struct TargetedFeeAdjustment(sp_std::marker::PhantomData<(T, S, V, M)>); /// Something that can convert the current multiplier to the next one. From 3fdb445b3b14880017680a3af85e89fb591666a0 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sun, 28 Nov 2021 13:47:33 +0100 Subject: [PATCH 0284/1472] Reduce the execution time of some tests (#10377) * Reduce the execution time of some tests * Fix * Fix build * fmt --- bin/node/runtime/src/lib.rs | 17 +- frame/babe/src/mock.rs | 3 +- .../election-provider-multi-phase/src/lib.rs | 10 - .../election-provider-multi-phase/src/mock.rs | 15 +- frame/grandpa/src/mock.rs | 1 + frame/offences/benchmarking/src/mock.rs | 1 + frame/session/benchmarking/src/mock.rs | 1 + frame/staking/fuzzer/src/mock.rs | 202 ------------------ frame/staking/src/benchmarking.rs | 17 +- frame/staking/src/lib.rs | 22 +- frame/staking/src/mock.rs | 3 +- frame/staking/src/pallet/mod.rs | 5 + 12 files changed, 68 insertions(+), 229 deletions(-) delete mode 100644 frame/staking/fuzzer/src/mock.rs diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 299b7257f9d45..44cefecd067f1 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -26,8 +26,8 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ construct_runtime, parameter_types, traits::{ - Currency, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, - LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, + ConstU32, Currency, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, + KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, @@ -515,6 +515,12 @@ impl onchain::Config for Runtime { type DataProvider = Staking; } +pub struct StakingBenchmarkingConfig; +impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { + type MaxNominators = ConstU32<1000>; + type MaxValidators = ConstU32<1000>; +} + impl pallet_staking::Config for Runtime { const MAX_NOMINATIONS: u32 = MAX_NOMINATIONS; type Currency = Balances; @@ -544,6 +550,7 @@ impl pallet_staking::Config for Runtime { // Note that the aforementioned does not scale to a very large number of nominators. type SortedListProvider = BagsList; type WeightInfo = pallet_staking::weights::SubstrateWeight; + type BenchmarkingConfig = StakingBenchmarkingConfig; } parameter_types! { @@ -591,8 +598,8 @@ pub const MAX_NOMINATIONS: u32 = ; type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; type ForceOrigin = EnsureRootOrHalfCouncil; - type BenchmarkingConfig = BenchmarkConfig; + type BenchmarkingConfig = ElectionProviderBenchmarkConfig; type VoterSnapshotPerBlock = VoterSnapshotPerBlock; } diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index e7ec692689032..f62e73aa43917 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -215,8 +215,9 @@ impl pallet_staking::Config for Test { type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; - type WeightInfo = (); type SortedListProvider = pallet_staking::UseNominatorsMap; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type WeightInfo = (); } impl pallet_offences::Config for Test { diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index ee4c9ae45d42b..70bbed95fe973 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -309,16 +309,6 @@ pub trait BenchmarkingConfig { const MAXIMUM_TARGETS: u32; } -impl BenchmarkingConfig for () { - const VOTERS: [u32; 2] = [4000, 6000]; - const TARGETS: [u32; 2] = [1000, 1600]; - const ACTIVE_VOTERS: [u32; 2] = [1000, 3000]; - const DESIRED_TARGETS: [u32; 2] = [400, 800]; - const SNAPSHOT_MAXIMUM_VOTERS: u32 = 10_000; - const MINER_MAXIMUM_VOTERS: u32 = 10_000; - const MAXIMUM_TARGETS: u32 = 2_000; -} - /// A fallback implementation that transitions the pallet to the emergency phase. pub struct NoFallback(sp_std::marker::PhantomData); diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index fbde6ad991706..f90c64b75ccb0 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -377,6 +377,19 @@ parameter_types! { pub static Balancing: Option<(usize, ExtendedBalance)> = Some((0, 0)); } +pub struct TestBenchmarkingConfig; +impl BenchmarkingConfig for TestBenchmarkingConfig { + const VOTERS: [u32; 2] = [400, 600]; + const ACTIVE_VOTERS: [u32; 2] = [100, 300]; + const TARGETS: [u32; 2] = [200, 400]; + const DESIRED_TARGETS: [u32; 2] = [100, 180]; + + const SNAPSHOT_MAXIMUM_VOTERS: u32 = 1000; + const MINER_MAXIMUM_VOTERS: u32 = 1000; + + const MAXIMUM_TARGETS: u32 = 200; +} + impl crate::Config for Runtime { type Event = Event; type Currency = Balances; @@ -398,7 +411,7 @@ impl crate::Config for Runtime { type RewardHandler = (); type DataProvider = StakingMock; type WeightInfo = DualMockWeightInfo; - type BenchmarkingConfig = (); + type BenchmarkingConfig = TestBenchmarkingConfig; type Fallback = MockFallback; type ForceOrigin = frame_system::EnsureRoot; type Solution = TestNposSolution; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 49e4022a4aaed..fe7a530ffe0c8 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -218,6 +218,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 3097f9b95be3f..26a53c7f8a048 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -178,6 +178,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index f534cc097e8a0..e000255b84b87 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -183,6 +183,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/staking/fuzzer/src/mock.rs b/frame/staking/fuzzer/src/mock.rs deleted file mode 100644 index d5ca78193b0c0..0000000000000 --- a/frame/staking/fuzzer/src/mock.rs +++ /dev/null @@ -1,202 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Mock file for staking fuzzing. - -use frame_support::parameter_types; - -type AccountId = u64; -type AccountIndex = u32; -type BlockNumber = u64; -type Balance = u64; - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; - -frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Staking: pallet_staking::{Pallet, Call, Config, Storage, Event, ValidateUnsigned}, - Indices: pallet_indices::{Pallet, Call, Storage, Config, Event}, - Session: pallet_session::{Pallet, Call, Storage, Event, Config}, - } -); - -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type Origin = Origin; - type Index = AccountIndex; - type BlockNumber = BlockNumber; - type Call = Call; - type Hash = sp_core::H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = AccountId; - type Lookup = Indices; - type Header = sp_runtime::testing::Header; - type Event = Event; - type BlockHashCount = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); -} -parameter_types! { - pub const ExistentialDeposit: Balance = 10; -} -impl pallet_balances::Config for Test { - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type Balance = Balance; - type Event = Event; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); -} -impl pallet_indices::Config for Test { - type AccountIndex = AccountIndex; - type Event = Event; - type Currency = Balances; - type Deposit = (); - type WeightInfo = (); -} -parameter_types! { - pub const MinimumPeriod: u64 = 5; -} -impl pallet_timestamp::Config for Test { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; - type WeightInfo = (); -} -impl pallet_session::historical::Config for Test { - type FullIdentification = pallet_staking::Exposure; - type FullIdentificationOf = pallet_staking::ExposureOf; -} - -sp_runtime::impl_opaque_keys! { - pub struct SessionKeys { - pub foo: sp_runtime::testing::UintAuthorityId, - } -} - -pub struct TestSessionHandler; -impl pallet_session::SessionHandler for TestSessionHandler { - const KEY_TYPE_IDS: &'static [sp_runtime::KeyTypeId] = &[]; - - fn on_genesis_session(_validators: &[(AccountId, Ks)]) {} - - fn on_new_session( - _: bool, - _: &[(AccountId, Ks)], - _: &[(AccountId, Ks)], - ) {} - - fn on_disabled(_: u32) {} -} - -impl pallet_session::Config for Test { - type SessionManager = pallet_session::historical::NoteHistoricalRoot; - type Keys = SessionKeys; - type ShouldEndSession = pallet_session::PeriodicSessions<(), ()>; - type NextSessionRotation = pallet_session::PeriodicSessions<(), ()>; - type SessionHandler = TestSessionHandler; - type Event = Event; - type ValidatorId = AccountId; - type ValidatorIdOf = pallet_staking::StashOf; - type DisabledValidatorsThreshold = (); - type WeightInfo = (); -} -pallet_staking_reward_curve::build! { - const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( - min_inflation: 0_025_000, - max_inflation: 0_100_000, - ideal_stake: 0_500_000, - falloff: 0_050_000, - max_piece_count: 40, - test_precision: 0_005_000, - ); -} -parameter_types! { - pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; - pub const MaxNominatorRewardedPerValidator: u32 = 64; - pub const MaxIterations: u32 = 20; -} - -pub type Extrinsic = sp_runtime::testing::TestXt; - -impl frame_system::offchain::SendTransactionTypes for Test -where - Call: From, -{ - type OverarchingCall = Call; - type Extrinsic = Extrinsic; -} - -pub struct MockElectionProvider; -impl frame_election_provider_support::ElectionProvider - for MockElectionProvider -{ - type Error = (); - type DataProvider = pallet_staking::Module; - - fn elect() -> Result< - (sp_npos_elections::Supports, frame_support::weights::Weight), - Self::Error - > { - Err(()) - } -} - -impl pallet_staking::Config for Test { - type Currency = Balances; - type UnixTime = pallet_timestamp::Pallet; - type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; - type RewardRemainder = (); - type Event = Event; - type Slash = (); - type Reward = (); - type SessionsPerEra = (); - type SlashDeferDuration = (); - type SlashCancelOrigin = frame_system::EnsureRoot; - type BondingDuration = (); - type SessionInterface = Self; - type EraPayout = pallet_staking::ConvertCurve; - type NextNewSession = Session; - type ElectionLookahead = (); - type Call = Call; - type MaxIterations = MaxIterations; - type MinSolutionScoreBump = (); - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; - type UnsignedPriority = (); - type OffchainSolutionWeightLimit = (); - type WeightInfo = (); - type ElectionProvider = MockElectionProvider; -} diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index e312aedbec1f3..5feb1692d955d 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -41,10 +41,11 @@ use frame_system::RawOrigin; const SEED: u32 = 0; const MAX_SPANS: u32 = 100; -const MAX_VALIDATORS: u32 = 1000; -const MAX_NOMINATORS: u32 = 1000; const MAX_SLASHES: u32 = 1000; +type MaxValidators = <::BenchmarkingConfig as BenchmarkingConfig>::MaxValidators; +type MaxNominators = <::BenchmarkingConfig as BenchmarkingConfig>::MaxNominators; + // Add slashing spans to a user account. Not relevant for actual use, only to benchmark // read and write operations. fn add_slashing_spans(who: &T::AccountId, spans: u32) { @@ -481,7 +482,7 @@ benchmarks! { } set_validator_count { - let validator_count = MAX_VALIDATORS; + let validator_count = MaxValidators::::get(); }: _(RawOrigin::Root, validator_count) verify { assert_eq!(ValidatorCount::::get(), validator_count); @@ -498,7 +499,7 @@ benchmarks! { // Worst case scenario, the list of invulnerables is very long. set_invulnerables { - let v in 0 .. MAX_VALIDATORS; + let v in 0 .. MaxValidators::::get(); let mut invulnerables = Vec::new(); for i in 0 .. v { invulnerables.push(account("invulnerable", i, SEED)); @@ -804,9 +805,9 @@ benchmarks! { get_npos_voters { // number of validator intention. - let v in (MAX_VALIDATORS / 2) .. MAX_VALIDATORS; + let v in (MaxValidators::::get() / 2) .. MaxValidators::::get(); // number of nominator intention. - let n in (MAX_NOMINATORS / 2) .. MAX_NOMINATORS; + let n in (MaxNominators::::get() / 2) .. MaxNominators::::get(); // total number of slashing spans. Assigned to validators randomly. let s in 1 .. 20; @@ -829,9 +830,9 @@ benchmarks! { get_npos_targets { // number of validator intention. - let v in (MAX_VALIDATORS / 2) .. MAX_VALIDATORS; + let v in (MaxValidators::::get() / 2) .. MaxValidators::::get(); // number of nominator intention. - let n = MAX_NOMINATORS; + let n = MaxNominators::::get(); let _ = create_validators_with_nominators_for_era::( v, n, T::MAX_NOMINATIONS as usize, false, None diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index cb91abe476cba..f2e5f0f783895 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -301,7 +301,7 @@ mod pallet; use codec::{Decode, Encode, HasCompact}; use frame_support::{ - traits::{Currency, Get}, + traits::{ConstU32, Currency, Get}, weights::Weight, }; use scale_info::TypeInfo; @@ -807,3 +807,23 @@ where R::is_known_offence(offenders, time_slot) } } + +/// Configurations of the benchmarking of the pallet. +pub trait BenchmarkingConfig { + /// The maximum number of validators to use. + type MaxValidators: Get; + /// The maximum number of nominators to use. + type MaxNominators: Get; +} + +/// A mock benchmarking config for pallet-staking. +/// +/// Should only be used for testing. +#[cfg(feature = "std")] +pub struct TestBenchmarkingConfig; + +#[cfg(feature = "std")] +impl BenchmarkingConfig for TestBenchmarkingConfig { + type MaxValidators = ConstU32<100>; + type MaxNominators = ConstU32<100>; +} diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 2b74b0188cff4..0b1d6a06d9c7f 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -272,9 +272,10 @@ impl crate::pallet::pallet::Config for Test { type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; - type WeightInfo = (); // NOTE: consider a macro and use `UseNominatorsMap` as well. type SortedListProvider = BagsList; + type BenchmarkingConfig = TestBenchmarkingConfig; + type WeightInfo = (); } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 542b79b792dc7..f8f9c8c794dc7 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -50,6 +50,8 @@ const STAKING_ID: LockIdentifier = *b"staking "; #[frame_support::pallet] pub mod pallet { + use crate::BenchmarkingConfig; + use super::*; #[pallet::pallet] @@ -151,6 +153,9 @@ pub mod pallet { /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. type SortedListProvider: SortedListProvider; + /// Some parameters of the benchmarking. + type BenchmarkingConfig: BenchmarkingConfig; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } From f2cecdbf3fa5b98f5638719109a0ce43303b7160 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Mon, 29 Nov 2021 17:16:23 +0900 Subject: [PATCH 0285/1472] ignoring errors and some fix (#10344) --- client/network/src/block_request_handler.rs | 2 +- .../src/light_client_requests/handler.rs | 2 +- client/network/src/service.rs | 9 ++--- client/network/src/state_request_handler.rs | 2 +- client/service/src/client/mod.rs | 5 ++- utils/frame/try-runtime/cli/src/lib.rs | 36 +++++++++---------- 6 files changed, 26 insertions(+), 30 deletions(-) diff --git a/client/network/src/block_request_handler.rs b/client/network/src/block_request_handler.rs index 3ea7833970d9e..9d963480a7e01 100644 --- a/client/network/src/block_request_handler.rs +++ b/client/network/src/block_request_handler.rs @@ -15,7 +15,7 @@ // along with Substrate. If not, see . //! Helper for handling (i.e. answering) block requests from a remote peer via the -//! [`crate::request_responses::RequestResponsesBehaviour`]. +//! `crate::request_responses::RequestResponsesBehaviour`. use crate::{ chain::Client, diff --git a/client/network/src/light_client_requests/handler.rs b/client/network/src/light_client_requests/handler.rs index a04c5e310a67e..5ecc85bdb0a0f 100644 --- a/client/network/src/light_client_requests/handler.rs +++ b/client/network/src/light_client_requests/handler.rs @@ -19,7 +19,7 @@ //! Helper for incoming light client requests. //! //! Handle (i.e. answer) incoming light client requests from a remote peer received via -//! [`crate::request_responses::RequestResponsesBehaviour`] with +//! `crate::request_responses::RequestResponsesBehaviour` with //! [`LightClientRequestHandler`](handler::LightClientRequestHandler). use crate::{ diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 3dadf810c6b49..4377ff358de7b 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -710,8 +710,7 @@ impl NetworkService { /// > preventing the message from being delivered. /// /// The protocol must have been registered with - /// [`NetworkConfiguration::notifications_protocols`](crate::config::NetworkConfiguration:: - /// notifications_protocols). + /// `crate::config::NetworkConfiguration::notifications_protocols`. pub fn write_notification( &self, target: PeerId, @@ -775,8 +774,7 @@ impl NetworkService { /// in which case enqueued notifications will be lost. /// /// The protocol must have been registered with - /// [`NetworkConfiguration::notifications_protocols`](crate::config::NetworkConfiguration:: - /// notifications_protocols). + /// `crate::config::NetworkConfiguration::notifications_protocols`. /// /// # Usage /// @@ -817,8 +815,7 @@ impl NetworkService { /// if buffer is full /// /// - /// See also the [`gossip`](crate::gossip) module for a higher-level way to send - /// notifications. + /// See also the `sc-network-gossip` crate for a higher-level way to send notifications. pub fn notification_sender( &self, target: PeerId, diff --git a/client/network/src/state_request_handler.rs b/client/network/src/state_request_handler.rs index 0d710c13af607..89f1f2b363c4c 100644 --- a/client/network/src/state_request_handler.rs +++ b/client/network/src/state_request_handler.rs @@ -15,7 +15,7 @@ // along with Substrate. If not, see . //! Helper for handling (i.e. answering) state requests from a remote peer via the -//! [`crate::request_responses::RequestResponsesBehaviour`]. +//! `crate::request_responses::RequestResponsesBehaviour`. use crate::{ chain::Client, diff --git a/client/service/src/client/mod.rs b/client/service/src/client/mod.rs index 7743f479a1713..d10b3d16b8139 100644 --- a/client/service/src/client/mod.rs +++ b/client/service/src/client/mod.rs @@ -37,9 +37,8 @@ //! The latter typically requires passing one of: //! //! - A [`LocalCallExecutor`] running the runtime locally. -//! - A [`RemoteCallExecutor`](sc_client_api::light::RemoteCallRequest) that will ask a -//! third-party to perform the executions. -//! - A [`RemoteOrLocalCallExecutor`](sc_client_api::light::LocalOrRemote), combination of the two. +//! - A `RemoteCallExecutor` that will ask a third-party to perform the executions. +//! - A `RemoteOrLocalCallExecutor` combination of the two. //! //! Additionally, the fourth generic parameter of the `Client` is a marker type representing //! the ways in which the runtime can interface with the outside. Any code that builds a `Client` diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 4aa1c213703ed..8b8c6b2d2bb36 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -125,7 +125,7 @@ //! #### Adding pre/post hooks //! //! One of the gems that come only in the `try-runtime` feature flag is the `pre_upgrade` and -//! `post_upgrade` hooks for [`OnRuntimeUpgrade`]. This trait is implemented either inside the +//! `post_upgrade` hooks for `OnRuntimeUpgrade`. This trait is implemented either inside the //! pallet, or manually in a runtime, to define a migration. In both cases, these functions can be //! added, given the right flag: //! @@ -141,7 +141,7 @@ //! //! These hooks allow you to execute some code, only within the `on-runtime-upgrade` command, before //! and after the migration. If any data needs to be temporarily stored between the pre/post -//! migration hooks, [`OnRuntimeUpgradeHelpersExt`] can help with that. +//! migration hooks, `OnRuntimeUpgradeHelpersExt` can help with that. //! //! #### Logging //! @@ -151,7 +151,7 @@ //! //! #### Guarding migrations //! -//! Always make sure that any migration code is guarded either by [`StorageVersion`], or by some +//! Always make sure that any migration code is guarded either by `StorageVersion`, or by some //! custom storage item, so that it is NEVER executed twice, even if the code lives in two //! consecutive runtimes. //! @@ -160,7 +160,7 @@ //! Run the migrations of the local runtime on the state of polkadot, from the polkadot repo where //! we have `--chain polkadot-dev`, on the latest finalized block's state //! -//! ```ignore +//! ```sh //! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ //! cargo run try-runtime \ //! --execution Native \ @@ -174,7 +174,7 @@ //! Same as previous one, but let's say we want to run this command from the substrate repo, where //! we don't have a matching spec name/version. //! -//! ```ignore +//! ```sh //! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ //! cargo run try-runtime \ //! --execution Native \ @@ -188,7 +188,7 @@ //! Same as the previous one, but run it at specific block number's state. This means that this //! block hash's state shall not yet have been pruned in `rpc.polkadot.io`. //! -//! ```ignore +//! ```sh //! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ //! cargo run try-runtime \ //! --execution Native \ @@ -206,7 +206,7 @@ //! First, let's assume you are in a branch that has the same spec name/version as the live polkadot //! network. //! -//! ```ignore +//! ```sh //! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ //! cargo run try-runtime \ //! --execution Wasm \ @@ -222,14 +222,14 @@ //! change `--execution Wasm` to `--execution Native` to achieve this. Your logs of `executor=trace` //! should show something among the lines of: //! -//! ```ignore +//! ```text //! Request for native execution succeeded (native: polkadot-9900 (parity-polkadot-0.tx7.au0), chain: polkadot-9900 (parity-polkadot-0.tx7.au0)) //! ``` //! //! If you don't have matching spec versions, then are doomed to execute wasm. In this case, you can //! manually overwrite the wasm code with your local runtime: //! -//! ```ignore +//! ```sh //! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ //! cargo run try-runtime \ //! --execution Wasm \ @@ -242,12 +242,12 @@ //! ``` //! //! For all of these blocks, the block with hash `` is being used, and the initial state -//! is the state of the parent hash. This is because by omitting [`ExecuteBlockCmd::block_at`], the +//! is the state of the parent hash. This is because by omitting `ExecuteBlockCmd::block_at`, the //! `--at` is used for both. This should be good enough for 99% of the cases. The only case where //! you need to specify `block-at` and `block-ws-uri` is with snapshots. Let's say you have a file //! `snap` and you know it corresponds to the state of the parent block of `X`. Then you'd do: //! -//! ```ignore +//! ```sh //! RUST_LOG=runtime=trace,try-runtime::cli=trace,executor=trace \ //! cargo run try-runtime \ //! --execution Wasm \ @@ -306,7 +306,7 @@ pub enum Command { /// Executes the given block against some state. /// - /// Unlike [`Command:::OnRuntimeUpgrade`], this command needs two inputs: the state, and the + /// Unlike [`Command::OnRuntimeUpgrade`], this command needs two inputs: the state, and the /// block data. Since the state could be cached (see [`State::Snap`]), different flags are /// provided for both. `--block-at` and `--block-uri`, if provided, are only used for fetching /// the block. For convenience, these flags can be both emitted, if the [`State::Live`] is @@ -314,7 +314,7 @@ pub enum Command { /// /// Note that by default, this command does not overwrite the code, so in wasm execution, the /// live chain's code is used. This can be disabled if desired, see - /// [`ExecuteBlockCmd::overwrite_wasm_code`]. + /// `ExecuteBlockCmd::overwrite_wasm_code`. /// /// Note that if you do overwrite the wasm code, or generally use the local runtime for this, /// you might @@ -326,7 +326,7 @@ pub enum Command { /// different state transition function. /// /// To make testing slightly more dynamic, you can disable the state root check by enabling - /// [`ExecuteBlockCmd::no_check`]. If you get signature verification errors, you should + /// `ExecuteBlockCmd::no_check`. If you get signature verification errors, you should /// manually tweak your local runtime's spec version to fix this. /// /// A subtle detail of execute block is that if you want to execute block 100 of a live chain @@ -335,19 +335,19 @@ pub enum Command { /// If [`State::Snap`] is being used, then this needs to be manually taken into consideration. /// /// This executes the same runtime api as normal block import, namely `Core_execute_block`. If - /// [`ExecuteBlockCmd::no_check`] is set, it uses a custom, try-runtime-only runtime + /// `ExecuteBlockCmd::no_check` is set, it uses a custom, try-runtime-only runtime /// api called `TryRuntime_execute_block_no_check`. ExecuteBlock(commands::execute_block::ExecuteBlockCmd), /// Executes *the offchain worker hooks* of a given block against some state. /// - /// Similar to [`Command:::ExecuteBlock`], this command needs two inputs: the state, and the + /// Similar to [`Command::ExecuteBlock`], this command needs two inputs: the state, and the /// header data. Likewise, `--header-at` and `--header-uri` can be filled, or omitted if /// [`State::Live`] is used. /// - /// Similar to [`Command:::ExecuteBlock`], this command does not overwrite the code, so in wasm + /// Similar to [`Command::ExecuteBlock`], this command does not overwrite the code, so in wasm /// execution, the live chain's code is used. This can be disabled if desired, see - /// [`OffchainWorkerCmd::overwrite_wasm_code`]. + /// `OffchainWorkerCmd::overwrite_wasm_code`. /// /// This executes the same runtime api as normal block import, namely /// `OffchainWorkerApi_offchain_worker`. From e2a89b2a6b476ea4dd5e0bd1c0e87790da4c17cb Mon Sep 17 00:00:00 2001 From: ferrell-code Date: Mon, 29 Nov 2021 13:38:07 -0500 Subject: [PATCH 0286/1472] Tips Benchmarking to be Runtime Agnostic (#10368) * use config traits instead of constants * bounties too * do bounties too * update docs --- frame/bounties/src/benchmarking.rs | 18 +++++++++--------- frame/bounties/src/lib.rs | 2 ++ frame/tips/src/benchmarking.rs | 17 +++++++---------- frame/tips/src/lib.rs | 5 ++++- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 341d019c49d47..19f50fdf3931b 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -33,7 +33,8 @@ const SEED: u32 = 0; // Create bounties that are approved for use in `on_initialize`. fn create_approved_bounties(n: u32) -> Result<(), &'static str> { for i in 0..n { - let (caller, _curator, _fee, value, reason) = setup_bounty::(i, MAX_BYTES); + let (caller, _curator, _fee, value, reason) = + setup_bounty::(i, T::MaximumReasonLength::get()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; @@ -50,7 +51,8 @@ fn setup_bounty( let caller = account("caller", u, SEED); let value: BalanceOf = T::BountyValueMinimum::get().saturating_mul(100u32.into()); let fee = value / 2u32.into(); - let deposit = T::BountyDepositBase::get() + T::DataDepositPerByte::get() * MAX_BYTES.into(); + let deposit = T::BountyDepositBase::get() + + T::DataDepositPerByte::get() * T::MaximumReasonLength::get().into(); let _ = T::Currency::make_free_balance_be(&caller, deposit); let curator = account("curator", u, SEED); let _ = T::Currency::make_free_balance_be(&curator, fee / 2u32.into()); @@ -60,7 +62,7 @@ fn setup_bounty( fn create_bounty( ) -> Result<(::Source, BountyIndex), &'static str> { - let (caller, curator, fee, value, reason) = setup_bounty::(0, MAX_BYTES); + let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; @@ -81,24 +83,22 @@ fn assert_last_event(generic_event: ::Event) { frame_system::Pallet::::assert_last_event(generic_event.into()); } -const MAX_BYTES: u32 = 16384; - benchmarks! { propose_bounty { - let d in 0 .. MAX_BYTES; + let d in 0 .. T::MaximumReasonLength::get(); let (caller, curator, fee, value, description) = setup_bounty::(0, d); }: _(RawOrigin::Signed(caller), value, description) approve_bounty { - let (caller, curator, fee, value, reason) = setup_bounty::(0, MAX_BYTES); + let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; }: _(RawOrigin::Root, bounty_id) propose_curator { setup_pot_account::(); - let (caller, curator, fee, value, reason) = setup_bounty::(0, MAX_BYTES); + let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; @@ -118,7 +118,7 @@ benchmarks! { accept_curator { setup_pot_account::(); - let (caller, curator, fee, value, reason) = setup_bounty::(0, MAX_BYTES); + let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 5c96fdcc6b98f..5021608b506b9 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -195,6 +195,8 @@ pub mod pallet { type Event: From> + IsType<::Event>; /// Maximum acceptable reason length. + /// + /// Benchmarks depend on this value, be sure to update weights file when changing this value #[pallet::constant] type MaximumReasonLength: Get; diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index d8227332bb334..5b6f11de77dde 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -84,12 +84,9 @@ fn setup_pot_account() { let _ = T::Currency::make_free_balance_be(&pot_account, value); } -const MAX_BYTES: u32 = 16384; -const MAX_TIPPERS: u32 = 100; - benchmarks! { report_awesome { - let r in 0 .. MAX_BYTES; + let r in 0 .. T::MaximumReasonLength::get(); let (caller, reason, awesome_person) = setup_awesome::(r); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); @@ -97,7 +94,7 @@ benchmarks! { }: _(RawOrigin::Signed(caller), reason, awesome_person) retract_tip { - let r = MAX_BYTES; + let r = T::MaximumReasonLength::get(); let (caller, reason, awesome_person) = setup_awesome::(r); TipsMod::::report_awesome( RawOrigin::Signed(caller.clone()).into(), @@ -112,8 +109,8 @@ benchmarks! { }: _(RawOrigin::Signed(caller), hash) tip_new { - let r in 0 .. MAX_BYTES; - let t in 1 .. MAX_TIPPERS; + let r in 0 .. T::MaximumReasonLength::get(); + let t in 1 .. T::Tippers::max_len() as u32; let (caller, reason, beneficiary, value) = setup_tip::(r, t)?; // Whitelist caller account from further DB operations. @@ -122,7 +119,7 @@ benchmarks! { }: _(RawOrigin::Signed(caller), reason, beneficiary, value) tip { - let t in 1 .. MAX_TIPPERS; + let t in 1 .. T::Tippers::max_len() as u32; let (member, reason, beneficiary, value) = setup_tip::(0, t)?; let value = T::Currency::minimum_balance().saturating_mul(100u32.into()); TipsMod::::tip_new( @@ -142,7 +139,7 @@ benchmarks! { }: _(RawOrigin::Signed(caller), hash, value) close_tip { - let t in 1 .. MAX_TIPPERS; + let t in 1 .. T::Tippers::max_len() as u32; // Make sure pot is funded setup_pot_account::(); @@ -171,7 +168,7 @@ benchmarks! { }: _(RawOrigin::Signed(caller), hash) slash_tip { - let t in 1 .. MAX_TIPPERS; + let t in 1 .. T::Tippers::max_len() as u32; // Make sure pot is funded setup_pot_account::(); diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index 5aad9af346603..0d2a56520a154 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -128,6 +128,8 @@ pub mod pallet { type Event: From> + IsType<::Event>; /// Maximum acceptable reason length. + /// + /// Benchmarks depend on this value, be sure to update weights file when changing this value #[pallet::constant] type MaximumReasonLength: Get; @@ -150,7 +152,8 @@ pub mod pallet { /// Origin from which tippers must come. /// /// `ContainsLengthBound::max_len` must be cost free (i.e. no storage read or heavy - /// operation). + /// operation). Benchmarks depend on the value of `ContainsLengthBound::max_len` be sure to + /// update weights file when altering this method. type Tippers: SortedMembers + ContainsLengthBound; /// Weight information for extrinsics in this pallet. From 270fac303a366c8c4c2e04771a7a346208db648c Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Tue, 30 Nov 2021 08:02:32 -0500 Subject: [PATCH 0287/1472] Add `vote` and `seconded` events to Democracy pallet. (#10352) * add the events * spec_version * Update bin/node/runtime/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Alan Sapede Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/democracy/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index ec706ca8f48aa..d80f8aa89ec35 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -539,6 +539,10 @@ pub mod pallet { }, /// A proposal_hash has been blacklisted permanently. Blacklisted { proposal_hash: T::Hash }, + /// An account has voted in a referendum + Voted { voter: T::AccountId, ref_index: ReferendumIndex, vote: AccountVote> }, + /// An account has secconded a proposal + Seconded { seconder: T::AccountId, prop_index: PropIndex }, } #[pallet::error] @@ -677,8 +681,9 @@ pub mod pallet { ensure!(seconds <= seconds_upper_bound, Error::::WrongUpperBound); let mut deposit = Self::deposit_of(proposal).ok_or(Error::::ProposalMissing)?; T::Currency::reserve(&who, deposit.1)?; - deposit.0.push(who); + deposit.0.push(who.clone()); >::insert(proposal, deposit); + Self::deposit_event(Event::::Seconded { seconder: who, prop_index: proposal }); Ok(()) } @@ -1378,6 +1383,7 @@ impl Pallet { votes.insert(i, (ref_index, vote)); }, } + Self::deposit_event(Event::::Voted { voter: who.clone(), ref_index, vote }); // Shouldn't be possible to fail, but we handle it gracefully. status.tally.add(vote).ok_or(ArithmeticError::Overflow)?; if let Some(approve) = vote.as_standard() { From 20b54920cee7512efc68b4c84dce1febc88c5518 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Tue, 30 Nov 2021 21:15:52 +0800 Subject: [PATCH 0288/1472] Add runtime-benchmarks for frame-benchmarking (#10324) * update frame/benchmarking/src/baseline.rs * add runtime-benchmarks feature * add runtime-benchmarks for frame-benchmarking * update frame-benchmarking/runtime-benchmarks * trigger GitHub actions --- bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- frame/assets/Cargo.toml | 2 +- frame/babe/Cargo.toml | 2 +- frame/bags-list/Cargo.toml | 2 +- frame/balances/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 1 + frame/benchmarking/src/baseline.rs | 2 ++ frame/bounties/Cargo.toml | 2 +- frame/collective/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- frame/election-provider-multi-phase/Cargo.toml | 2 +- frame/elections-phragmen/Cargo.toml | 2 +- frame/examples/basic/Cargo.toml | 2 +- frame/gilt/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/identity/Cargo.toml | 2 +- frame/im-online/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- frame/lottery/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 2 +- frame/proxy/Cargo.toml | 2 +- frame/scheduler/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/timestamp/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 2 +- frame/utility/Cargo.toml | 2 +- frame/vesting/Cargo.toml | 2 +- 35 files changed, 36 insertions(+), 33 deletions(-) diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 7ea5628b97c1e..1a239bef3262a 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -36,5 +36,5 @@ std = [ 'frame-benchmarking/std', ] -runtime-benchmarks = ["frame-benchmarking"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index bff47f5a7ea39..c821bdac169e6 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -83,7 +83,7 @@ std = [ "sp-version/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system-benchmarking", "frame-system/runtime-benchmarks", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index f9ce4b0fca900..4771202b90a0c 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -176,7 +176,7 @@ std = [ "sp-io/std" ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-election-provider-multi-phase/runtime-benchmarks", diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 08cadb527750b..233c88279d35b 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -42,7 +42,7 @@ std = [ "frame-benchmarking/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 9ae942486d627..a2224df86798c 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -60,5 +60,5 @@ std = [ "sp-std/std", "log/std", ] -runtime-benchmarks = ["frame-benchmarking"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 6d4cf2363c4f7..b7eebdd0df102 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -56,7 +56,7 @@ std = [ "log/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "sp-core", "sp-io", "pallet-balances", diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 4ea2e9cbe8a31..5565915f6ded6 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -39,5 +39,5 @@ std = [ "frame-system/std", "log/std", ] -runtime-benchmarks = ["frame-benchmarking"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index a6bfcf2a552fc..2bf4a53b0f424 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -44,3 +44,4 @@ std = [ "linregress", "log/std", ] +runtime-benchmarks = [] diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index a2ffca60c5cf1..2b924a692129a 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -18,6 +18,8 @@ //! A set of benchmarks which can establish a global baseline for all other //! benchmarking. +#![cfg(feature = "runtime-benchmarks")] + use crate::benchmarks; use codec::Encode; use frame_system::Pallet as System; diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index cce6ed69a25ba..6c9cef417e99f 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -45,7 +45,7 @@ std = [ "log/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index 6d4567a7851e2..d4dc8f9a2d8d0 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -41,7 +41,7 @@ std = [ "frame-system/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 6639d939e1796..cc21f19b63527 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -79,7 +79,7 @@ std = [ "libsecp256k1/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "libsecp256k1", "rand", "rand_pcg", diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 1973677531e9a..43b35b9f7a1f6 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -44,7 +44,7 @@ std = [ "frame-system/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "frame-support/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index b37054a7bbddf..c041d6c684c7f 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -72,7 +72,7 @@ std = [ "log/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-election-provider-support/runtime-benchmarks", "rand", "strum", diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index 6c87be7b6d589..921a7057bcda9 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -47,7 +47,7 @@ std = [ "log/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index a4e8ffe3261cd..8ac375cb36037 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -42,5 +42,5 @@ std = [ "sp-runtime/std", "sp-std/std" ] -runtime-benchmarks = ["frame-benchmarking"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index 6b2eae1156a89..e9ee8ba14abad 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -40,7 +40,7 @@ std = [ "frame-system/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index af125d64ea218..ba2d98fc354e8 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -60,5 +60,5 @@ std = [ "pallet-session/std", "log/std", ] -runtime-benchmarks = ["frame-benchmarking"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 9a370674e5876..b791256d9452b 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -40,7 +40,7 @@ std = [ "frame-system/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index f4cf5a9077c9b..2fa0b5ebc12aa 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -47,5 +47,5 @@ std = [ "frame-system/std", "log/std", ] -runtime-benchmarks = ["frame-benchmarking"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index f1913d4138be0..7f27ac23c6456 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -42,7 +42,7 @@ std = [ "frame-system/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index d4ee5b8008f19..e65bb01660b58 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -41,7 +41,7 @@ std = [ "frame-system/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "frame-support/runtime-benchmarks", ] diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index a3747ca0576f5..9eafaedee7db1 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -41,7 +41,7 @@ std = [ "frame-benchmarking/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 2ff8b16fa4bde..ee9080b19d611 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -46,5 +46,5 @@ std = [ "frame-system/std", "pallet-mmr-primitives/std", ] -runtime-benchmarks = ["frame-benchmarking"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index 2b0d8f5cee792..f409e0c6c8d06 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -39,7 +39,7 @@ std = [ "sp-std/std" ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index 030209b83cc6c..be288ecc0d759 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -40,7 +40,7 @@ std = [ "sp-io/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index fab2bc2c635ca..01cf95fa7fc7c 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -39,7 +39,7 @@ std = [ "log/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index d9461ab454f39..81f5b181850c1 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -68,7 +68,7 @@ std = [ "frame-election-provider-support/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-election-provider-support/runtime-benchmarks", "rand_chacha", ] diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 2f07b2a0975a5..a942b58e09509 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -45,5 +45,5 @@ std = [ "sp-timestamp/std", "log/std", ] -runtime-benchmarks = ["frame-benchmarking", "sp-io"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "sp-io"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 805f1663d1ae3..49b19756e43cc 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -50,7 +50,7 @@ std = [ "pallet-treasury/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index a8c6e60af2f82..4b4ee7de85098 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -33,7 +33,7 @@ sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-featu [features] default = ["std"] -runtime-benchmarks = ["frame-benchmarking", "hex-literal"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "hex-literal"] std = [ "serde", "codec/std", diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index d375e22df949b..d44699825a6f9 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -47,7 +47,7 @@ std = [ "pallet-balances/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 4b6d0485567c2..9d7e8f7184d16 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -39,7 +39,7 @@ std = [ "frame-benchmarking/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index c55b20df27855..8407bf53e73d2 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -40,7 +40,7 @@ std = [ "sp-std/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 035124f7d0de3..efec3be330dcc 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -39,5 +39,5 @@ std = [ "frame-support/std", "frame-system/std", ] -runtime-benchmarks = ["frame-benchmarking"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] From 4bef50f5ea7726d77142ec21437fb14e3e737a3b Mon Sep 17 00:00:00 2001 From: Enoch Chejieh Date: Tue, 30 Nov 2021 21:03:06 +0100 Subject: [PATCH 0289/1472] Add pallet names to Events (#10296) * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: add pallet names to events * chore: formatted pallet name changes in events * chore: formatted pallet name changes in events * chore: formatted pallet name changes in events * chore: formatted pallet name changes in events * chore: formatted pallet name changes in events * chore: formatted pallet name changes in events * chore: formatted pallet name changes in events * chore: formatted pallet name changes in events * chore: formatted pallet name changes in events * fix: add fix to tests for event variants * chore: modified comments for event variants * chore: modified comments for event variants * chore: modified comments for event variants * chore: modified comments for event variants * chore: modified system pallet event variants * chore: modified system pallet event variants * chore: modified system pallet event variants * chore: modified system pallet event variants * chore: modified system pallet event variants * chore: modified system pallet event variants * chore: modified system pallet event variants * chore: modified system pallet event variants * chore: modified system pallet event variants * chore: updated transaction-storage pallet event variants * chore: updated transaction-storage pallet event variants * chore: formatted contracts pallet * chore: update treasury event variants --- bin/node/executor/tests/basic.rs | 51 ++++----- frame/balances/src/tests.rs | 8 +- frame/balances/src/tests_local.rs | 4 +- frame/contracts/src/exec.rs | 10 +- frame/contracts/src/tests.rs | 10 +- frame/offences/benchmarking/src/lib.rs | 2 +- frame/scheduler/src/lib.rs | 42 ++++---- frame/society/src/lib.rs | 101 +++++++++--------- frame/system/src/lib.rs | 30 +++--- frame/system/src/tests.rs | 63 ++++++----- frame/transaction-payment/src/lib.rs | 4 +- frame/transaction-storage/src/benchmarking.rs | 4 +- frame/transaction-storage/src/lib.rs | 8 +- frame/treasury/src/lib.rs | 48 +++++---- frame/utility/src/lib.rs | 8 +- 15 files changed, 209 insertions(+), 184 deletions(-) diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 7dc6c22aa3544..9c460a0238e38 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -378,11 +378,13 @@ fn full_native_block_import_works() { let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), - event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo { - weight: timestamp_weight, - class: DispatchClass::Mandatory, - ..Default::default() - })), + event: Event::System(frame_system::Event::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: timestamp_weight, + class: DispatchClass::Mandatory, + ..Default::default() + }, + }), topics: vec![], }, EventRecord { @@ -412,15 +414,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Treasury(pallet_treasury::Event::Deposit(fees * 8 / 10)), + event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo { - weight: transfer_weight, - ..Default::default() - })), + event: Event::System(frame_system::Event::ExtrinsicSuccess { + dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, + }), topics: vec![], }, ]; @@ -448,11 +449,13 @@ fn full_native_block_import_works() { let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), - event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo { - weight: timestamp_weight, - class: DispatchClass::Mandatory, - ..Default::default() - })), + event: Event::System(frame_system::Event::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: timestamp_weight, + class: DispatchClass::Mandatory, + ..Default::default() + }, + }), topics: vec![], }, EventRecord { @@ -482,15 +485,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Treasury(pallet_treasury::Event::Deposit(fees * 8 / 10)), + event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo { - weight: transfer_weight, - ..Default::default() - })), + event: Event::System(frame_system::Event::ExtrinsicSuccess { + dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, + }), topics: vec![], }, EventRecord { @@ -520,15 +522,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Treasury(pallet_treasury::Event::Deposit(fees * 8 / 10)), + event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo { - weight: transfer_weight, - ..Default::default() - })), + event: Event::System(frame_system::Event::ExtrinsicSuccess { + dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, + }), topics: vec![], }, ]; diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 1f7f4dd03716d..e05ed5a3d689c 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -750,7 +750,7 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::NewAccount(1)), + Event::System(system::Event::NewAccount { account: 1 }), Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] @@ -762,7 +762,7 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::KilledAccount(1)), + Event::System(system::Event::KilledAccount { account: 1 }), Event::Balances(crate::Event::DustLost { account: 1, amount: 99 }), Event::Balances(crate::Event::Slashed { who: 1, amount: 1 }), ] @@ -781,7 +781,7 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::NewAccount(1)), + Event::System(system::Event::NewAccount { account: 1 }), Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] @@ -793,7 +793,7 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::KilledAccount(1)), + Event::System(system::Event::KilledAccount { account: 1 }), Event::Balances(crate::Event::Slashed { who: 1, amount: 100 }), ] ); diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index c9de662b9e8fe..a861df4746a11 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -163,7 +163,7 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { assert_eq!( events(), [ - Event::System(system::Event::NewAccount(1)), + Event::System(system::Event::NewAccount { account: 1 }), Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] @@ -181,7 +181,7 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { assert_eq!( events(), [ - Event::System(system::Event::KilledAccount(1)), + Event::System(system::Event::KilledAccount { account: 1 }), Event::Balances(crate::Event::DustLost { account: 1, amount: 1 }), Event::Balances(crate::Event::Slashed { who: 1, amount: 1 }) ] diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 90a640418bcc0..bc88e162c5c0d 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -2089,7 +2089,10 @@ mod tests { System::events(), vec![EventRecord { phase: Phase::Initialization, - event: MetaEvent::System(frame_system::Event::Remarked(BOB, remark_hash)), + event: MetaEvent::System(frame_system::Event::Remarked { + sender: BOB, + hash: remark_hash + }), topics: vec![], },] ); @@ -2147,7 +2150,10 @@ mod tests { vec![ EventRecord { phase: Phase::Initialization, - event: MetaEvent::System(frame_system::Event::Remarked(BOB, remark_hash)), + event: MetaEvent::System(frame_system::Event::Remarked { + sender: BOB, + hash: remark_hash + }), topics: vec![], }, EventRecord { diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 2214ce8f40b1a..6a252527d1eac 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -455,7 +455,9 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount(ALICE.clone())), + event: Event::System(frame_system::Event::NewAccount { + account: ALICE.clone() + }), topics: vec![], }, EventRecord { @@ -468,7 +470,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount(addr.clone())), + event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), topics: vec![], }, EventRecord { @@ -767,7 +769,9 @@ fn self_destruct_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::KilledAccount(addr.clone())), + event: Event::System(frame_system::Event::KilledAccount { + account: addr.clone() + }), topics: vec![], }, EventRecord { diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 33ebe23d8d1fd..4d042cfd9997f 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -342,7 +342,7 @@ benchmarks! { let mut reward_events = reporters.clone().into_iter() .flat_map(|reporter| vec![ balance_deposit(reporter.clone(), reward.into()).into(), - frame_system::Event::::NewAccount(reporter.clone()).into(), + frame_system::Event::::NewAccount { account: reporter.clone() }.into(), ::Event::from( pallet_balances::Event::::Endowed{account: reporter.clone(), free_balance: reward.into()} ).into(), diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index d25fc3b376e83..b3e64fe57f642 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -203,12 +203,16 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Scheduled some task. \[when, index\] - Scheduled(T::BlockNumber, u32), - /// Canceled some task. \[when, index\] - Canceled(T::BlockNumber, u32), - /// Dispatched some task. \[task, id, result\] - Dispatched(TaskAddress, Option>, DispatchResult), + /// Scheduled some task. + Scheduled { when: T::BlockNumber, index: u32 }, + /// Canceled some task. + Canceled { when: T::BlockNumber, index: u32 }, + /// Dispatched some task. + Dispatched { + task: TaskAddress, + id: Option>, + result: DispatchResult, + }, } #[pallet::error] @@ -319,11 +323,11 @@ pub mod pallet { Lookup::::remove(id); } } - Self::deposit_event(Event::Dispatched( - (now, index), - maybe_id, - r.map(|_| ()).map_err(|e| e.error), - )); + Self::deposit_event(Event::Dispatched { + task: (now, index), + id: maybe_id, + result: r.map(|_| ()).map_err(|e| e.error), + }); total_weight = cumulative_weight; None } else { @@ -563,7 +567,7 @@ impl Pallet { expected from the runtime configuration. An update might be needed.", ); } - Self::deposit_event(Event::Scheduled(when, index)); + Self::deposit_event(Event::Scheduled { when, index }); Ok((when, index)) } @@ -592,7 +596,7 @@ impl Pallet { if let Some(id) = s.maybe_id { Lookup::::remove(id); } - Self::deposit_event(Event::Canceled(when, index)); + Self::deposit_event(Event::Canceled { when, index }); Ok(()) } else { Err(Error::::NotFound)? @@ -617,8 +621,8 @@ impl Pallet { })?; let new_index = Agenda::::decode_len(new_time).unwrap_or(1) as u32 - 1; - Self::deposit_event(Event::Canceled(when, index)); - Self::deposit_event(Event::Scheduled(new_time, new_index)); + Self::deposit_event(Event::Canceled { when, index }); + Self::deposit_event(Event::Scheduled { when: new_time, index: new_index }); Ok((new_time, new_index)) } @@ -663,7 +667,7 @@ impl Pallet { } let address = (when, index); Lookup::::insert(&id, &address); - Self::deposit_event(Event::Scheduled(when, index)); + Self::deposit_event(Event::Scheduled { when, index }); Ok(address) } @@ -686,7 +690,7 @@ impl Pallet { } Ok(()) })?; - Self::deposit_event(Event::Canceled(when, index)); + Self::deposit_event(Event::Canceled { when, index }); Ok(()) } else { Err(Error::::NotFound)? @@ -718,8 +722,8 @@ impl Pallet { })?; let new_index = Agenda::::decode_len(new_time).unwrap_or(1) as u32 - 1; - Self::deposit_event(Event::Canceled(when, index)); - Self::deposit_event(Event::Scheduled(new_time, new_index)); + Self::deposit_event(Event::Canceled { when, index }); + Self::deposit_event(Event::Scheduled { when: new_time, index: new_index }); *lookup = Some((new_time, new_index)); diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 83b1c4203722b..0b95129032670 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -475,42 +475,41 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { - /// The society is founded by the given identity. \[founder\] - Founded(T::AccountId), + /// The society is founded by the given identity. + Founded { founder: T::AccountId }, /// A membership bid just happened. The given account is the candidate's ID and their offer - /// is the second. \[candidate_id, offer\] - Bid(T::AccountId, BalanceOf), + /// is the second. + Bid { candidate_id: T::AccountId, offer: BalanceOf }, /// A membership bid just happened by vouching. The given account is the candidate's ID and - /// their offer is the second. The vouching party is the third. \[candidate_id, offer, - /// vouching\] - Vouch(T::AccountId, BalanceOf, T::AccountId), - /// A \[candidate\] was dropped (due to an excess of bids in the system). - AutoUnbid(T::AccountId), - /// A \[candidate\] was dropped (by their request). - Unbid(T::AccountId), - /// A \[candidate\] was dropped (by request of who vouched for them). - Unvouch(T::AccountId), + /// their offer is the second. The vouching party is the third. + Vouch { candidate_id: T::AccountId, offer: BalanceOf, vouching: T::AccountId }, + /// A candidate was dropped (due to an excess of bids in the system). + AutoUnbid { candidate: T::AccountId }, + /// A candidate was dropped (by their request). + Unbid { candidate: T::AccountId }, + /// A candidate was dropped (by request of who vouched for them). + Unvouch { candidate: T::AccountId }, /// A group of candidates have been inducted. The batch's primary is the first value, the - /// batch in full is the second. \[primary, candidates\] - Inducted(T::AccountId, Vec), - /// A suspended member has been judged. \[who, judged\] - SuspendedMemberJudgement(T::AccountId, bool), - /// A \[candidate\] has been suspended - CandidateSuspended(T::AccountId), - /// A \[member\] has been suspended - MemberSuspended(T::AccountId), - /// A \[member\] has been challenged - Challenged(T::AccountId), - /// A vote has been placed \[candidate, voter, vote\] - Vote(T::AccountId, T::AccountId, bool), - /// A vote has been placed for a defending member \[voter, vote\] - DefenderVote(T::AccountId, bool), + /// batch in full is the second. + Inducted { primary: T::AccountId, candidates: Vec }, + /// A suspended member has been judged. + SuspendedMemberJudgement { who: T::AccountId, judged: bool }, + /// A candidate has been suspended + CandidateSuspended { candidate: T::AccountId }, + /// A member has been suspended + MemberSuspended { member: T::AccountId }, + /// A member has been challenged + Challenged { member: T::AccountId }, + /// A vote has been placed + Vote { candidate: T::AccountId, voter: T::AccountId, vote: bool }, + /// A vote has been placed for a defending member + DefenderVote { voter: T::AccountId, vote: bool }, /// A new \[max\] member count has been set - NewMaxMembers(u32), - /// Society is unfounded. \[founder\] - Unfounded(T::AccountId), - /// Some funds were deposited into the society account. \[value\] - Deposit(BalanceOf), + NewMaxMembers { max: u32 }, + /// Society is unfounded. + Unfounded { founder: T::AccountId }, + /// Some funds were deposited into the society account. + Deposit { value: BalanceOf }, } /// Old name generated by `decl_event`. @@ -729,7 +728,7 @@ pub mod pallet { T::Currency::reserve(&who, deposit)?; Self::put_bid(bids, &who, value.clone(), BidKind::Deposit(deposit)); - Self::deposit_event(Event::::Bid(who, value)); + Self::deposit_event(Event::::Bid { candidate_id: who, offer: value }); Ok(()) } @@ -771,7 +770,7 @@ pub mod pallet { >::remove(&voucher); }, } - Self::deposit_event(Event::::Unbid(who)); + Self::deposit_event(Event::::Unbid { candidate: who }); Ok(()) } else { Err(Error::::BadPosition)? @@ -849,7 +848,11 @@ pub mod pallet { >::insert(&voucher, VouchingStatus::Vouching); Self::put_bid(bids, &who, value.clone(), BidKind::Vouch(voucher.clone(), tip)); - Self::deposit_event(Event::::Vouch(who, value, voucher)); + Self::deposit_event(Event::::Vouch { + candidate_id: who, + offer: value, + vouching: voucher, + }); Ok(()) } @@ -884,7 +887,7 @@ pub mod pallet { b[pos].kind.check_voucher(&voucher)?; >::remove(&voucher); let who = b.remove(pos).who; - Self::deposit_event(Event::::Unvouch(who)); + Self::deposit_event(Event::::Unvouch { candidate: who }); Ok(()) } else { Err(Error::::BadPosition)? @@ -927,7 +930,7 @@ pub mod pallet { let vote = if approve { Vote::Approve } else { Vote::Reject }; >::insert(&candidate, &voter, vote); - Self::deposit_event(Event::::Vote(candidate, voter, approve)); + Self::deposit_event(Event::::Vote { candidate, voter, vote: approve }); Ok(()) } @@ -956,7 +959,7 @@ pub mod pallet { let vote = if approve { Vote::Approve } else { Vote::Reject }; >::insert(&voter, vote); - Self::deposit_event(Event::::DefenderVote(voter, approve)); + Self::deposit_event(Event::::DefenderVote { voter, vote: approve }); Ok(()) } @@ -1039,7 +1042,7 @@ pub mod pallet { >::put(&founder); >::put(&founder); Rules::::put(T::Hashing::hash(&rules)); - Self::deposit_event(Event::::Founded(founder)); + Self::deposit_event(Event::::Founded { founder }); Ok(()) } @@ -1068,7 +1071,7 @@ pub mod pallet { Rules::::kill(); Candidates::::kill(); SuspendedCandidates::::remove_all(None); - Self::deposit_event(Event::::Unfounded(founder)); + Self::deposit_event(Event::::Unfounded { founder }); Ok(()) } @@ -1125,14 +1128,14 @@ pub mod pallet { if let Some(pos) = bids.iter().position(|b| b.kind.check_voucher(&who).is_ok()) { // Remove the bid, and emit an event let vouched = bids.remove(pos).who; - Self::deposit_event(Event::::Unvouch(vouched)); + Self::deposit_event(Event::::Unvouch { candidate: vouched }); } ); } } >::remove(&who); - Self::deposit_event(Event::::SuspendedMemberJudgement(who, forgive)); + Self::deposit_event(Event::::SuspendedMemberJudgement { who, judged: forgive }); Ok(()) } @@ -1253,7 +1256,7 @@ pub mod pallet { ensure_root(origin)?; ensure!(max > 1, Error::::MaxMembers); MaxMembers::::put(max); - Self::deposit_event(Event::::NewMaxMembers(max)); + Self::deposit_event(Event::::NewMaxMembers { max }); Ok(()) } } @@ -1339,7 +1342,7 @@ impl, I: 'static> Pallet { >::remove(&voucher); }, } - Self::deposit_event(Event::::AutoUnbid(popped)); + Self::deposit_event(Event::::AutoUnbid { candidate: popped }); } >::put(bids); @@ -1504,7 +1507,7 @@ impl, I: 'static> Pallet { } else { // Suspend Candidate >::insert(&candidate, (value, kind)); - Self::deposit_event(Event::::CandidateSuspended(candidate)); + Self::deposit_event(Event::::CandidateSuspended { candidate }); None } }) @@ -1573,7 +1576,7 @@ impl, I: 'static> Pallet { >::put(&primary); T::MembershipChanged::change_members_sorted(&accounts, &[], &members); - Self::deposit_event(Event::::Inducted(primary, accounts)); + Self::deposit_event(Event::::Inducted { primary, candidates: accounts }); } // Bump the pot by at most PeriodSpend, but less if there's not very much left in our @@ -1638,7 +1641,7 @@ impl, I: 'static> Pallet { if Self::remove_member(&who).is_ok() { >::insert(who, true); >::remove(who); - Self::deposit_event(Event::::MemberSuspended(who.clone())); + Self::deposit_event(Event::::MemberSuspended { member: who.clone() }); } } @@ -1716,7 +1719,7 @@ impl, I: 'static> Pallet { let chosen = pick_item(&mut rng, &members[1..members.len() - 1]) .expect("exited if members empty; qed"); >::put(&chosen); - Self::deposit_event(Event::::Challenged(chosen.clone())); + Self::deposit_event(Event::::Challenged { member: chosen.clone() }); } else { >::kill(); } @@ -1820,6 +1823,6 @@ impl, I: 'static> OnUnbalanced> for Palle // Must resolve into existing but better to be safe. let _ = T::Currency::resolve_creating(&Self::account_id(), amount); - Self::deposit_event(Event::::Deposit(numeric_amount)); + Self::deposit_event(Event::::Deposit { value: numeric_amount }); } } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 0b00a7d8f5973..31b702c135dea 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -458,7 +458,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let hash = T::Hashing::hash(&remark[..]); - Self::deposit_event(Event::Remarked(who, hash)); + Self::deposit_event(Event::Remarked { sender: who, hash }); Ok(().into()) } } @@ -466,18 +466,18 @@ pub mod pallet { /// Event for the System pallet. #[pallet::event] pub enum Event { - /// An extrinsic completed successfully. \[info\] - ExtrinsicSuccess(DispatchInfo), - /// An extrinsic failed. \[error, info\] - ExtrinsicFailed(DispatchError, DispatchInfo), + /// An extrinsic completed successfully. + ExtrinsicSuccess { dispatch_info: DispatchInfo }, + /// An extrinsic failed. + ExtrinsicFailed { dispatch_error: DispatchError, dispatch_info: DispatchInfo }, /// `:code` was updated. CodeUpdated, - /// A new \[account\] was created. - NewAccount(T::AccountId), - /// An \[account\] was reaped. - KilledAccount(T::AccountId), - /// On on-chain remark happened. \[origin, remark_hash\] - Remarked(T::AccountId, T::Hash), + /// A new account was created. + NewAccount { account: T::AccountId }, + /// An account was reaped. + KilledAccount { account: T::AccountId }, + /// On on-chain remark happened. + Remarked { sender: T::AccountId, hash: T::Hash }, } /// Old name generated by `decl_event`. @@ -1486,7 +1486,7 @@ impl Pallet { pub fn note_applied_extrinsic(r: &DispatchResultWithPostInfo, mut info: DispatchInfo) { info.weight = extract_actual_weight(r, &info); Self::deposit_event(match r { - Ok(_) => Event::ExtrinsicSuccess(info), + Ok(_) => Event::ExtrinsicSuccess { dispatch_info: info }, Err(err) => { log::trace!( target: "runtime::system", @@ -1494,7 +1494,7 @@ impl Pallet { Self::block_number(), err, ); - Event::ExtrinsicFailed(err.error, info) + Event::ExtrinsicFailed { dispatch_error: err.error, dispatch_info: info } }, }); @@ -1522,13 +1522,13 @@ impl Pallet { /// An account is being created. pub fn on_created_account(who: T::AccountId, _a: &mut AccountInfo) { T::OnNewAccount::on_new_account(&who); - Self::deposit_event(Event::NewAccount(who)); + Self::deposit_event(Event::NewAccount { account: who }); } /// Do anything that needs to be done after an account has been killed. fn on_killed_account(who: T::AccountId) { T::OnKilledAccount::on_killed_account(&who); - Self::deposit_event(Event::KilledAccount(who)); + Self::deposit_event(Event::KilledAccount { account: who }); } /// Determine whether or not it is possible to update the code. diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index a4dd3403f2c3a..f9c167ec4be34 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -168,44 +168,44 @@ fn deposit_event_should_work() { ); System::initialize(&2, &[0u8; 32].into(), &Default::default(), InitKind::Full); - System::deposit_event(SysEvent::NewAccount(32)); + System::deposit_event(SysEvent::NewAccount { account: 32 }); System::note_finished_initialize(); - System::deposit_event(SysEvent::KilledAccount(42)); + System::deposit_event(SysEvent::KilledAccount { account: 42 }); System::note_applied_extrinsic(&Ok(().into()), Default::default()); System::note_applied_extrinsic(&Err(DispatchError::BadOrigin.into()), Default::default()); System::note_finished_extrinsics(); - System::deposit_event(SysEvent::NewAccount(3)); + System::deposit_event(SysEvent::NewAccount { account: 3 }); System::finalize(); assert_eq!( System::events(), vec![ EventRecord { phase: Phase::Initialization, - event: SysEvent::NewAccount(32).into(), + event: SysEvent::NewAccount { account: 32 }.into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(0), - event: SysEvent::KilledAccount(42).into(), + event: SysEvent::KilledAccount { account: 42 }.into(), topics: vec![] }, EventRecord { phase: Phase::ApplyExtrinsic(0), - event: SysEvent::ExtrinsicSuccess(Default::default()).into(), + event: SysEvent::ExtrinsicSuccess { dispatch_info: Default::default() }.into(), topics: vec![] }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: SysEvent::ExtrinsicFailed( - DispatchError::BadOrigin.into(), - Default::default() - ) + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: Default::default() + } .into(), topics: vec![] }, EventRecord { phase: Phase::Finalization, - event: SysEvent::NewAccount(3).into(), + event: SysEvent::NewAccount { account: 3 }.into(), topics: vec![] }, ] @@ -234,37 +234,34 @@ fn deposit_event_uses_actual_weight() { vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), - event: SysEvent::ExtrinsicSuccess(DispatchInfo { - weight: 300, - ..Default::default() - },) + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { weight: 300, ..Default::default() }, + } .into(), topics: vec![] }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: SysEvent::ExtrinsicSuccess(DispatchInfo { - weight: 1000, - ..Default::default() - },) + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { weight: 1000, ..Default::default() }, + } .into(), topics: vec![] }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: SysEvent::ExtrinsicSuccess(DispatchInfo { - weight: 1000, - ..Default::default() - },) + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { weight: 1000, ..Default::default() }, + } .into(), topics: vec![] }, EventRecord { phase: Phase::ApplyExtrinsic(3), - event: SysEvent::ExtrinsicFailed( - DispatchError::BadOrigin.into(), - DispatchInfo { weight: 999, ..Default::default() }, - ) + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { weight: 999, ..Default::default() }, + } .into(), topics: vec![] }, @@ -284,9 +281,9 @@ fn deposit_event_topics() { let topics = vec![H256::repeat_byte(1), H256::repeat_byte(2), H256::repeat_byte(3)]; // We deposit a few events with different sets of topics. - System::deposit_event_indexed(&topics[0..3], SysEvent::NewAccount(1).into()); - System::deposit_event_indexed(&topics[0..1], SysEvent::NewAccount(2).into()); - System::deposit_event_indexed(&topics[1..2], SysEvent::NewAccount(3).into()); + System::deposit_event_indexed(&topics[0..3], SysEvent::NewAccount { account: 1 }.into()); + System::deposit_event_indexed(&topics[0..1], SysEvent::NewAccount { account: 2 }.into()); + System::deposit_event_indexed(&topics[1..2], SysEvent::NewAccount { account: 3 }.into()); System::finalize(); @@ -296,17 +293,17 @@ fn deposit_event_topics() { vec![ EventRecord { phase: Phase::Finalization, - event: SysEvent::NewAccount(1).into(), + event: SysEvent::NewAccount { account: 1 }.into(), topics: topics[0..3].to_vec(), }, EventRecord { phase: Phase::Finalization, - event: SysEvent::NewAccount(2).into(), + event: SysEvent::NewAccount { account: 2 }.into(), topics: topics[0..1].to_vec(), }, EventRecord { phase: Phase::Finalization, - event: SysEvent::NewAccount(3).into(), + event: SysEvent::NewAccount { account: 3 }.into(), topics: topics[1..2].to_vec(), } ] diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index f912866f7bb39..ed96f26cc0079 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -1369,7 +1369,9 @@ mod tests { amount: 80, })); // Killed Event - System::assert_has_event(Event::System(system::Event::KilledAccount(2))); + System::assert_has_event(Event::System(system::Event::KilledAccount { + account: 2, + })); }); } diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs index 6ca9b247f0228..0f90b51087ae9 100644 --- a/frame/transaction-storage/src/benchmarking.rs +++ b/frame/transaction-storage/src/benchmarking.rs @@ -109,7 +109,7 @@ benchmarks! { }: _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize]) verify { assert!(!BlockTransactions::::get().is_empty()); - assert_last_event::(Event::Stored(0).into()); + assert_last_event::(Event::Stored { index: 0 }.into()); } renew { @@ -122,7 +122,7 @@ benchmarks! { run_to_block::(1u32.into()); }: _(RawOrigin::Signed(caller.clone()), T::BlockNumber::zero(), 0) verify { - assert_last_event::(Event::Renewed(0).into()); + assert_last_event::(Event::Renewed { index: 0 }.into()); } check_proof_max { diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index bc31199d90391..94937c04ed5d8 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -210,7 +210,7 @@ pub mod pallet { }); Ok(()) })?; - Self::deposit_event(Event::Stored(index)); + Self::deposit_event(Event::Stored { index }); Ok(()) } @@ -251,7 +251,7 @@ pub mod pallet { }); Ok(()) })?; - Self::deposit_event(Event::Renewed(index)); + Self::deposit_event(Event::Renewed { index }); Ok(().into()) } @@ -313,9 +313,9 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Stored data under specified index. - Stored(u32), + Stored { index: u32 }, /// Renewed data under specified index. - Renewed(u32), + Renewed { index: u32 }, /// Storage proof was successfully checked. ProofChecked, } diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 646baa99b99b0..5258426e2681c 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -255,21 +255,20 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { - /// New proposal. \[proposal_index\] - Proposed(ProposalIndex), - /// We have ended a spend period and will now allocate funds. \[budget_remaining\] - Spending(BalanceOf), - /// Some funds have been allocated. \[proposal_index, award, beneficiary\] - Awarded(ProposalIndex, BalanceOf, T::AccountId), - /// A proposal was rejected; funds were slashed. \[proposal_index, slashed\] - Rejected(ProposalIndex, BalanceOf), - /// Some of our funds have been burnt. \[burn\] - Burnt(BalanceOf), + /// New proposal. + Proposed { proposal_index: ProposalIndex }, + /// We have ended a spend period and will now allocate funds. + Spending { budget_remaining: BalanceOf }, + /// Some funds have been allocated. + Awarded { proposal_index: ProposalIndex, award: BalanceOf, account: T::AccountId }, + /// A proposal was rejected; funds were slashed. + Rejected { proposal_index: ProposalIndex, slashed: BalanceOf }, + /// Some of our funds have been burnt. + Burnt { burnt_funds: BalanceOf }, /// Spending has finished; this is the amount that rolls over until next spend. - /// \[budget_remaining\] - Rollover(BalanceOf), - /// Some funds have been deposited. \[deposit\] - Deposit(BalanceOf), + Rollover { rollover_balance: BalanceOf }, + /// Some funds have been deposited. + Deposit { value: BalanceOf }, } /// Old name generated by `decl_event`. @@ -334,7 +333,7 @@ pub mod pallet { >::put(c + 1); >::insert(c, Proposal { proposer, value, beneficiary, bond }); - Self::deposit_event(Event::Proposed(c)); + Self::deposit_event(Event::Proposed { proposal_index: c }); Ok(()) } @@ -360,7 +359,10 @@ pub mod pallet { let imbalance = T::Currency::slash_reserved(&proposal.proposer, value).0; T::OnSlash::on_unbalanced(imbalance); - Self::deposit_event(Event::::Rejected(proposal_id, value)); + Self::deposit_event(Event::::Rejected { + proposal_index: proposal_id, + slashed: value, + }); Ok(()) } @@ -410,7 +412,7 @@ impl, I: 'static> Pallet { let mut total_weight: Weight = Zero::zero(); let mut budget_remaining = Self::pot(); - Self::deposit_event(Event::Spending(budget_remaining)); + Self::deposit_event(Event::Spending { budget_remaining }); let account_id = Self::account_id(); let mut missed_any = false; @@ -431,7 +433,11 @@ impl, I: 'static> Pallet { // provide the allocation. imbalance.subsume(T::Currency::deposit_creating(&p.beneficiary, p.value)); - Self::deposit_event(Event::Awarded(index, p.value, p.beneficiary)); + Self::deposit_event(Event::Awarded { + proposal_index: index, + award: p.value, + account: p.beneficiary, + }); false } else { missed_any = true; @@ -462,7 +468,7 @@ impl, I: 'static> Pallet { let (debit, credit) = T::Currency::pair(burn); imbalance.subsume(debit); T::BurnDestination::on_unbalanced(credit); - Self::deposit_event(Event::Burnt(burn)) + Self::deposit_event(Event::Burnt { burnt_funds: burn }) } // Must never be an error, but better to be safe. @@ -477,7 +483,7 @@ impl, I: 'static> Pallet { drop(problem); } - Self::deposit_event(Event::Rollover(budget_remaining)); + Self::deposit_event(Event::Rollover { rollover_balance: budget_remaining }); total_weight } @@ -498,6 +504,6 @@ impl, I: 'static> OnUnbalanced> for Palle // Must resolve into existing but better to be safe. let _ = T::Currency::resolve_creating(&Self::account_id(), amount); - Self::deposit_event(Event::Deposit(numeric_amount)); + Self::deposit_event(Event::Deposit { value: numeric_amount }); } } diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 14d8a66514e36..fde4e78366e68 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -115,8 +115,8 @@ pub mod pallet { BatchCompleted, /// A single item within a Batch of dispatches has completed with no error. ItemCompleted, - /// A call was dispatched. \[result\] - DispatchedAs(DispatchResult), + /// A call was dispatched. + DispatchedAs { result: DispatchResult }, } // Align the call size to 1KB. As we are currently compiling the runtime for native/wasm @@ -380,7 +380,9 @@ pub mod pallet { let res = call.dispatch_bypass_filter((*as_origin).into()); - Self::deposit_event(Event::DispatchedAs(res.map(|_| ()).map_err(|e| e.error))); + Self::deposit_event(Event::DispatchedAs { + result: res.map(|_| ()).map_err(|e| e.error), + }); Ok(()) } } From b6c1c1bcfa5d831bfd1f278064d7af757f9b38f5 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Wed, 1 Dec 2021 09:59:09 +0900 Subject: [PATCH 0290/1472] Fix order of hook execution (#10043) * fix order * Update frame/support/procedural/src/construct_runtime/mod.rs Co-authored-by: Alexander Popiak * format * more accurate description * format * better explicit types * fix tests * address feedback * add a type to ease non breaking implementation * add comment about constraint * fix test * add test for generated types Co-authored-by: Alexander Popiak --- bin/node-template/runtime/src/lib.rs | 2 +- bin/node/runtime/src/lib.rs | 4 +- frame/executive/src/lib.rs | 104 +++++++-------- .../procedural/src/construct_runtime/mod.rs | 71 +++++++++-- frame/support/test/tests/pallet.rs | 120 +++++++++++++++++- frame/support/test/tests/pallet_instance.rs | 19 ++- 6 files changed, 231 insertions(+), 89 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 8ecb2199dda71..4eaa0aa00d0b6 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -323,7 +323,7 @@ pub type Executive = frame_executive::Executive< Block, frame_system::ChainContext, Runtime, - AllPallets, + AllPalletsWithSystem, >; impl_runtime_apis! { diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 44cefecd067f1..3f553221e67ac 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1268,6 +1268,8 @@ construct_runtime!( Utility: pallet_utility, Babe: pallet_babe, Timestamp: pallet_timestamp, + // Authorship must be before session in order to note author in the correct session and era + // for im-online and staking. Authorship: pallet_authorship, Indices: pallet_indices, Balances: pallet_balances, @@ -1345,7 +1347,7 @@ pub type Executive = frame_executive::Executive< Block, frame_system::ChainContext, Runtime, - AllPallets, + AllPalletsWithSystem, pallet_bags_list::migrations::CheckCounterPrefix, >; diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index dd0a9abf8687b..9b81527fadb35 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -59,7 +59,7 @@ //! # type Context = frame_system::ChainContext; //! # pub type Block = generic::Block; //! # pub type Balances = u64; -//! # pub type AllPallets = u64; +//! # pub type AllPalletsWithSystem = u64; //! # pub enum Runtime {}; //! # use sp_runtime::transaction_validity::{ //! # TransactionValidity, UnknownTransaction, TransactionSource, @@ -73,7 +73,7 @@ //! # } //! # } //! /// Executive: handles dispatch to the various modules. -//! pub type Executive = executive::Executive; +//! pub type Executive = executive::Executive; //! ``` //! //! ### Custom `OnRuntimeUpgrade` logic @@ -90,7 +90,7 @@ //! # type Context = frame_system::ChainContext; //! # pub type Block = generic::Block; //! # pub type Balances = u64; -//! # pub type AllPallets = u64; +//! # pub type AllPalletsWithSystem = u64; //! # pub enum Runtime {}; //! # use sp_runtime::transaction_validity::{ //! # TransactionValidity, UnknownTransaction, TransactionSource, @@ -111,7 +111,7 @@ //! } //! } //! -//! pub type Executive = executive::Executive; +//! pub type Executive = executive::Executive; //! ``` #![cfg_attr(not(feature = "std"), no_std)] @@ -147,11 +147,26 @@ pub type OriginOf = as Dispatchable>::Origin; /// - `Block`: The block type of the runtime /// - `Context`: The context that is used when checking an extrinsic. /// - `UnsignedValidator`: The unsigned transaction validator of the runtime. -/// - `AllPallets`: Tuple that contains all modules. Will be used to call e.g. `on_initialize`. +/// - `AllPalletsWithSystem`: Tuple that contains all pallets including frame system pallet. Will be +/// used to call hooks e.g. `on_initialize`. /// - `OnRuntimeUpgrade`: Custom logic that should be called after a runtime upgrade. Modules are -/// already called by `AllPallets`. It will be called before all modules will be called. -pub struct Executive( - PhantomData<(System, Block, Context, UnsignedValidator, AllPallets, OnRuntimeUpgrade)>, +/// already called by `AllPalletsWithSystem`. It will be called before all modules will be called. +pub struct Executive< + System, + Block, + Context, + UnsignedValidator, + AllPalletsWithSystem, + OnRuntimeUpgrade = (), +>( + PhantomData<( + System, + Block, + Context, + UnsignedValidator, + AllPalletsWithSystem, + OnRuntimeUpgrade, + )>, ); impl< @@ -159,14 +174,14 @@ impl< Block: traits::Block
, Context: Default, UnsignedValidator, - AllPallets: OnRuntimeUpgrade + AllPalletsWithSystem: OnRuntimeUpgrade + OnInitialize + OnIdle + OnFinalize + OffchainWorker, COnRuntimeUpgrade: OnRuntimeUpgrade, > ExecuteBlock - for Executive + for Executive where Block::Extrinsic: Checkable + Codec, CheckedOf: Applyable + GetDispatchInfo, @@ -181,7 +196,7 @@ where Block, Context, UnsignedValidator, - AllPallets, + AllPalletsWithSystem, COnRuntimeUpgrade, >::execute_block(block); } @@ -192,13 +207,13 @@ impl< Block: traits::Block
, Context: Default, UnsignedValidator, - AllPallets: OnRuntimeUpgrade + AllPalletsWithSystem: OnRuntimeUpgrade + OnInitialize + OnIdle + OnFinalize + OffchainWorker, COnRuntimeUpgrade: OnRuntimeUpgrade, - > Executive + > Executive where Block::Extrinsic: Checkable + Codec, CheckedOf: Applyable + GetDispatchInfo, @@ -209,14 +224,7 @@ where { /// Execute all `OnRuntimeUpgrade` of this runtime, and return the aggregate weight. pub fn execute_on_runtime_upgrade() -> frame_support::weights::Weight { - let mut weight = 0; - weight = weight.saturating_add(COnRuntimeUpgrade::on_runtime_upgrade()); - weight = weight.saturating_add( - as OnRuntimeUpgrade>::on_runtime_upgrade(), - ); - weight = weight.saturating_add(::on_runtime_upgrade()); - - weight + <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::on_runtime_upgrade() } /// Execute given block, but don't do any of the `final_checks`. @@ -255,19 +263,10 @@ where /// This should only be used for testing. #[cfg(feature = "try-runtime")] pub fn try_runtime_upgrade() -> Result { - < - (frame_system::Pallet::, COnRuntimeUpgrade, AllPallets) - as - OnRuntimeUpgrade - >::pre_upgrade().unwrap(); - + <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::pre_upgrade().unwrap(); let weight = Self::execute_on_runtime_upgrade(); - < - (frame_system::Pallet::, COnRuntimeUpgrade, AllPallets) - as - OnRuntimeUpgrade - >::post_upgrade().unwrap(); + <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::post_upgrade().unwrap(); Ok(weight) } @@ -305,12 +304,9 @@ where digest, frame_system::InitKind::Full, ); - weight = weight.saturating_add( as OnInitialize< + weight = weight.saturating_add(>::on_initialize(*block_number)); - weight = weight.saturating_add( - >::on_initialize(*block_number), - ); weight = weight.saturating_add( >::get().base_block, ); @@ -415,30 +411,20 @@ where fn idle_and_finalize_hook(block_number: NumberFor) { let weight = >::block_weight(); let max_weight = >::get().max_block; - let mut remaining_weight = max_weight.saturating_sub(weight.total()); + let remaining_weight = max_weight.saturating_sub(weight.total()); if remaining_weight > 0 { - let mut used_weight = - as OnIdle>::on_idle( - block_number, - remaining_weight, - ); - remaining_weight = remaining_weight.saturating_sub(used_weight); - used_weight = >::on_idle( + let used_weight = >::on_idle( block_number, remaining_weight, - ) - .saturating_add(used_weight); + ); >::register_extra_weight_unchecked( used_weight, DispatchClass::Mandatory, ); } - as OnFinalize>::on_finalize( - block_number, - ); - >::on_finalize(block_number); + >::on_finalize(block_number); } /// Apply extrinsic outside of the block execution function. @@ -567,7 +553,9 @@ where // as well. frame_system::BlockHash::::insert(header.number(), header.hash()); - >::offchain_worker(*header.number()) + >::offchain_worker( + *header.number(), + ) } } @@ -849,7 +837,7 @@ mod tests { Block, ChainContext, Runtime, - AllPallets, + AllPalletsWithSystem, CustomOnRuntimeUpgrade, >; @@ -1360,23 +1348,19 @@ mod tests { )); // All weights that show up in the `initialize_block_impl` - let frame_system_upgrade_weight = frame_system::Pallet::::on_runtime_upgrade(); let custom_runtime_upgrade_weight = CustomOnRuntimeUpgrade::on_runtime_upgrade(); - let runtime_upgrade_weight = ::on_runtime_upgrade(); - let frame_system_on_initialize_weight = - frame_system::Pallet::::on_initialize(block_number); + let runtime_upgrade_weight = + ::on_runtime_upgrade(); let on_initialize_weight = - >::on_initialize(block_number); + >::on_initialize(block_number); let base_block_weight = ::BlockWeights::get().base_block; // Weights are recorded correctly assert_eq!( frame_system::Pallet::::block_weight().total(), - frame_system_upgrade_weight + - custom_runtime_upgrade_weight + + custom_runtime_upgrade_weight + runtime_upgrade_weight + - frame_system_on_initialize_weight + on_initialize_weight + base_block_weight, ); }); diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index a5da775b9c9ea..b32ecf1bccd5c 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -304,35 +304,82 @@ fn decl_all_pallets<'a>( types.extend(type_decl); names.push(&pallet_declaration.name); } - // Make nested tuple structure like (((Babe, Consensus), Grandpa), ...) + + // Make nested tuple structure like: + // `((FirstPallet, (SecondPallet, ( ... , LastPallet) ... ))))` // But ignore the system pallet. - let all_pallets = names + let all_pallets_without_system = names .iter() .filter(|n| **n != SYSTEM_PALLET_NAME) + .rev() .fold(TokenStream2::default(), |combined, name| quote!((#name, #combined))); + // Make nested tuple structure like: + // `((FirstPallet, (SecondPallet, ( ... , LastPallet) ... ))))` let all_pallets_with_system = names .iter() + .rev() + .fold(TokenStream2::default(), |combined, name| quote!((#name, #combined))); + + // Make nested tuple structure like: + // `((LastPallet, (SecondLastPallet, ( ... , FirstPallet) ... ))))` + // But ignore the system pallet. + let all_pallets_without_system_reversed = names + .iter() + .filter(|n| **n != SYSTEM_PALLET_NAME) .fold(TokenStream2::default(), |combined, name| quote!((#name, #combined))); + // Make nested tuple structure like: + // `((LastPallet, (SecondLastPallet, ( ... , FirstPallet) ... ))))` + let all_pallets_with_system_reversed = names + .iter() + .fold(TokenStream2::default(), |combined, name| quote!((#name, #combined))); + + let system_pallet = match names.iter().find(|n| **n == SYSTEM_PALLET_NAME) { + Some(name) => name, + None => + return syn::Error::new( + proc_macro2::Span::call_site(), + "`System` pallet declaration is missing. \ + Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},`", + ) + .into_compile_error(), + }; + quote!( #types /// All pallets included in the runtime as a nested tuple of types. - /// Excludes the System pallet. - pub type AllPallets = ( #all_pallets ); + #[deprecated(note = "The type definition has changed from representing all pallets \ + excluding system, in reversed order to become the representation of all pallets \ + including system pallet in regular order. For this reason it is encouraged to use \ + explicitly one of `AllPalletsWithSystem`, `AllPalletsWithoutSystem`, \ + `AllPalletsWithSystemReversed`, `AllPalletsWithoutSystemReversed`. \ + Note that the type `frame_executive::Executive` expects one of `AllPalletsWithSystem` \ + , `AllPalletsWithSystemReversed`, `AllPalletsReversedWithSystemFirst`. More details in \ + https://github.com/paritytech/substrate/pull/10043")] + pub type AllPallets = AllPalletsWithSystem; + /// All pallets included in the runtime as a nested tuple of types. pub type AllPalletsWithSystem = ( #all_pallets_with_system ); - /// All modules included in the runtime as a nested tuple of types. + /// All pallets included in the runtime as a nested tuple of types. + /// Excludes the System pallet. + pub type AllPalletsWithoutSystem = ( #all_pallets_without_system ); + + /// All pallets included in the runtime as a nested tuple of types in reversed order. /// Excludes the System pallet. - #[deprecated(note = "use `AllPallets` instead")] - #[allow(dead_code)] - pub type AllModules = ( #all_pallets ); - /// All modules included in the runtime as a nested tuple of types. - #[deprecated(note = "use `AllPalletsWithSystem` instead")] - #[allow(dead_code)] - pub type AllModulesWithSystem = ( #all_pallets_with_system ); + pub type AllPalletsWithoutSystemReversed = ( #all_pallets_without_system_reversed ); + + /// All pallets included in the runtime as a nested tuple of types in reversed order. + pub type AllPalletsWithSystemReversed = ( #all_pallets_with_system_reversed ); + + /// All pallets included in the runtime as a nested tuple of types in reversed order. + /// With the system pallet first. + pub type AllPalletsReversedWithSystemFirst = ( + #system_pallet, + AllPalletsWithoutSystemReversed + ); ) } diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index dcf739af614b8..509e3217ddf96 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -453,9 +453,21 @@ pub mod pallet2 { pub struct Pallet(_); #[pallet::hooks] - impl Hooks> for Pallet where - T::AccountId: From + SomeAssociation1 + impl Hooks> for Pallet + where + T::AccountId: From + SomeAssociation1, { + fn on_initialize(_: BlockNumberFor) -> Weight { + Self::deposit_event(Event::Something(11)); + 0 + } + fn on_finalize(_: BlockNumberFor) { + Self::deposit_event(Event::Something(21)); + } + fn on_runtime_upgrade() -> Weight { + Self::deposit_event(Event::Something(31)); + 0 + } } #[pallet::call] @@ -469,6 +481,7 @@ pub mod pallet2 { CountedStorageMap; #[pallet::event] + #[pallet::generate_deposit(fn deposit_event)] pub enum Event { /// Something Something(u32), @@ -963,10 +976,10 @@ fn pallet_hooks_expand() { TestExternalities::default().execute_with(|| { frame_system::Pallet::::set_block_number(1); - assert_eq!(AllPallets::on_initialize(1), 10); - AllPallets::on_finalize(1); + assert_eq!(AllPalletsWithoutSystem::on_initialize(1), 10); + AllPalletsWithoutSystem::on_finalize(1); - assert_eq!(AllPallets::on_runtime_upgrade(), 30); + assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), 30); assert_eq!( frame_system::Pallet::::events()[0].event, @@ -974,10 +987,62 @@ fn pallet_hooks_expand() { ); assert_eq!( frame_system::Pallet::::events()[1].event, + Event::Example2(pallet2::Event::Something(11)), + ); + assert_eq!( + frame_system::Pallet::::events()[2].event, Event::Example(pallet::Event::Something(20)), ); + assert_eq!( + frame_system::Pallet::::events()[3].event, + Event::Example2(pallet2::Event::Something(21)), + ); + assert_eq!( + frame_system::Pallet::::events()[4].event, + Event::Example(pallet::Event::Something(30)), + ); + assert_eq!( + frame_system::Pallet::::events()[5].event, + Event::Example2(pallet2::Event::Something(31)), + ); + }) +} + +#[test] +fn all_pallets_type_reversed_order_is_correct() { + TestExternalities::default().execute_with(|| { + frame_system::Pallet::::set_block_number(1); + + #[allow(deprecated)] + { + assert_eq!(AllPalletsWithoutSystemReversed::on_initialize(1), 10); + AllPalletsWithoutSystemReversed::on_finalize(1); + + assert_eq!(AllPalletsWithoutSystemReversed::on_runtime_upgrade(), 30); + } + + assert_eq!( + frame_system::Pallet::::events()[0].event, + Event::Example2(pallet2::Event::Something(11)), + ); + assert_eq!( + frame_system::Pallet::::events()[1].event, + Event::Example(pallet::Event::Something(10)), + ); assert_eq!( frame_system::Pallet::::events()[2].event, + Event::Example2(pallet2::Event::Something(21)), + ); + assert_eq!( + frame_system::Pallet::::events()[3].event, + Event::Example(pallet::Event::Something(20)), + ); + assert_eq!( + frame_system::Pallet::::events()[4].event, + Event::Example2(pallet2::Event::Something(31)), + ); + assert_eq!( + frame_system::Pallet::::events()[5].event, Event::Example(pallet::Event::Something(30)), ); }) @@ -1499,3 +1564,48 @@ fn test_storage_info() { ], ); } + +#[test] +fn assert_type_all_pallets_reversed_with_system_first_is_correct() { + // Just ensure the 2 types are same. + fn _a(_t: AllPalletsReversedWithSystemFirst) {} + fn _b(t: (System, (Example4, (Example2, (Example,))))) { + _a(t) + } +} + +#[test] +fn assert_type_all_pallets_with_system_is_correct() { + // Just ensure the 2 types are same. + fn _a(_t: AllPalletsWithSystem) {} + fn _b(t: (System, (Example, (Example2, (Example4,))))) { + _a(t) + } +} + +#[test] +fn assert_type_all_pallets_without_system_is_correct() { + // Just ensure the 2 types are same. + fn _a(_t: AllPalletsWithoutSystem) {} + fn _b(t: (Example, (Example2, (Example4,)))) { + _a(t) + } +} + +#[test] +fn assert_type_all_pallets_with_system_reversed_is_correct() { + // Just ensure the 2 types are same. + fn _a(_t: AllPalletsWithSystemReversed) {} + fn _b(t: (Example4, (Example2, (Example, (System,))))) { + _a(t) + } +} + +#[test] +fn assert_type_all_pallets_without_system_reversed_is_correct() { + // Just ensure the 2 types are same. + fn _a(_t: AllPalletsWithoutSystemReversed) {} + fn _b(t: (Example4, (Example2, (Example,)))) { + _a(t) + } +} diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index c031ac9fe1bf5..de70b0e7e404e 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -551,35 +551,34 @@ fn pallet_hooks_expand() { TestExternalities::default().execute_with(|| { frame_system::Pallet::::set_block_number(1); - assert_eq!(AllPallets::on_initialize(1), 21); - AllPallets::on_finalize(1); + assert_eq!(AllPalletsWithoutSystem::on_initialize(1), 21); + AllPalletsWithoutSystem::on_finalize(1); - assert_eq!(AllPallets::on_runtime_upgrade(), 61); + assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), 61); - // The order is indeed reversed due to https://github.com/paritytech/substrate/issues/6280 assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Instance1Example(pallet::Event::Something(11)), + Event::Example(pallet::Event::Something(10)), ); assert_eq!( frame_system::Pallet::::events()[1].event, - Event::Example(pallet::Event::Something(10)), + Event::Instance1Example(pallet::Event::Something(11)), ); assert_eq!( frame_system::Pallet::::events()[2].event, - Event::Instance1Example(pallet::Event::Something(21)), + Event::Example(pallet::Event::Something(20)), ); assert_eq!( frame_system::Pallet::::events()[3].event, - Event::Example(pallet::Event::Something(20)), + Event::Instance1Example(pallet::Event::Something(21)), ); assert_eq!( frame_system::Pallet::::events()[4].event, - Event::Instance1Example(pallet::Event::Something(31)), + Event::Example(pallet::Event::Something(30)), ); assert_eq!( frame_system::Pallet::::events()[5].event, - Event::Example(pallet::Event::Something(30)), + Event::Instance1Example(pallet::Event::Something(31)), ); }) } From b6a3ecc150040daa440637ac892265165f3450f6 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 1 Dec 2021 13:37:30 +0800 Subject: [PATCH 0291/1472] use double quotes instead of single quotes & upgrade 2021 (#10398) --- bin/node-template/pallets/template/Cargo.toml | 18 +++++++++--------- bin/node-template/runtime/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 1a239bef3262a..887b022d6ca7f 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = 'pallet-template' +name = "pallet-template" version = "3.0.0" description = "FRAME pallet template for defining custom runtime logic." -authors = ['Substrate DevHub '] +authors = ["Substrate DevHub "] homepage = "https://substrate.io/" -edition = '2018' +edition = "2021" license = "Unlicense" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" @@ -27,13 +27,13 @@ sp-io = { default-features = false, version = "4.0.0-dev", path = "../../../../p sp-runtime = { default-features = false, version = "4.0.0-dev", path = "../../../../primitives/runtime" } [features] -default = ['std'] +default = ["std"] std = [ - 'codec/std', - 'scale-info/std', - 'frame-support/std', - 'frame-system/std', - 'frame-benchmarking/std', + "codec/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index c821bdac169e6..c7ff0ff5a268a 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "node-template-runtime" version = "3.0.0" -description = 'A fresh FRAME-based Substrate runtime, ready for hacking.' +description = "A fresh FRAME-based Substrate runtime, ready for hacking." authors = ["Substrate DevHub "] homepage = "https://substrate.io/" edition = "2021" diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index e4f3b128cfce9..a79bf68551000 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-asset-tx-payment" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" From 8bf9836f3a709f220ff74be23a4004146480eb79 Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Wed, 1 Dec 2021 12:45:36 +0100 Subject: [PATCH 0292/1472] Make BEEFY payload extensible (#10307) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * make BEEFY payload extensible * cargo fmt * cargo fmt * remove generic payload param in beefy-primitives * cargo fmt * Apply suggestions from code review Co-authored-by: Tomasz Drwięga * adds Paylaod Type * remove hex * fix tests * Apply suggestions from code review Co-authored-by: Tomasz Drwięga * use binary_search_by to sort * Payload::new() * fix tests * Apply suggestions from code review Co-authored-by: Tomasz Drwięga * fix tests * cargo fmt * fix get_decoded * fix test Co-authored-by: Tomasz Drwięga --- Cargo.lock | 1 + client/beefy/src/gossip.rs | 32 +++----- client/beefy/src/notification.rs | 3 +- client/beefy/src/round.rs | 36 ++++----- client/beefy/src/worker.rs | 15 ++-- primitives/beefy/Cargo.toml | 2 +- primitives/beefy/src/commitment.rs | 122 +++++++++++++++++++++-------- primitives/beefy/src/lib.rs | 8 +- primitives/beefy/src/witness.rs | 32 ++++---- 9 files changed, 152 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 08d39c1d2b3de..fbdf0297d4531 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -535,6 +535,7 @@ dependencies = [ name = "beefy-primitives" version = "4.0.0-dev" dependencies = [ + "hex", "hex-literal", "parity-scale-codec", "scale-info", diff --git a/client/beefy/src/gossip.rs b/client/beefy/src/gossip.rs index 8a43b5a039478..dc59f664caa91 100644 --- a/client/beefy/src/gossip.rs +++ b/client/beefy/src/gossip.rs @@ -30,7 +30,7 @@ use wasm_timer::Instant; use beefy_primitives::{ crypto::{Public, Signature}, - MmrRootHash, VoteMessage, + VoteMessage, }; use crate::keystore::BeefyKeystore; @@ -142,9 +142,7 @@ where sender: &PeerId, mut data: &[u8], ) -> ValidationResult { - if let Ok(msg) = - VoteMessage::, Public, Signature>::decode(&mut data) - { + if let Ok(msg) = VoteMessage::, Public, Signature>::decode(&mut data) { let msg_hash = twox_64(data); let round = msg.commitment.block_number; @@ -178,9 +176,7 @@ where fn message_expired<'a>(&'a self) -> Box bool + 'a> { let known_votes = self.known_votes.read(); Box::new(move |_topic, mut data| { - let msg = match VoteMessage::, Public, Signature>::decode( - &mut data, - ) { + let msg = match VoteMessage::, Public, Signature>::decode(&mut data) { Ok(vote) => vote, Err(_) => return true, }; @@ -214,9 +210,7 @@ where return do_rebroadcast } - let msg = match VoteMessage::, Public, Signature>::decode( - &mut data, - ) { + let msg = match VoteMessage::, Public, Signature>::decode(&mut data) { Ok(vote) => vote, Err(_) => return true, }; @@ -237,9 +231,11 @@ mod tests { use sc_network_test::Block; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; - use beefy_primitives::{crypto::Signature, Commitment, MmrRootHash, VoteMessage, KEY_TYPE}; - use crate::keystore::{tests::Keyring, BeefyKeystore}; + use beefy_primitives::{ + crypto::Signature, known_payload_ids, Commitment, MmrRootHash, Payload, VoteMessage, + KEY_TYPE, + }; use super::*; @@ -345,10 +341,7 @@ mod tests { } } - fn sign_commitment( - who: &Keyring, - commitment: &Commitment, - ) -> Signature { + fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { let store: SyncCryptoStorePtr = std::sync::Arc::new(LocalKeystore::in_memory()); SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&who.to_seed())).unwrap(); let beefy_keystore: BeefyKeystore = Some(store).into(); @@ -362,11 +355,8 @@ mod tests { let sender = sc_network::PeerId::random(); let mut context = TestContext; - let commitment = Commitment { - payload: MmrRootHash::default(), - block_number: 3_u64, - validator_set_id: 0, - }; + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, MmrRootHash::default().encode()); + let commitment = Commitment { payload, block_number: 3_u64, validator_set_id: 0 }; let signature = sign_commitment(&Keyring::Alice, &commitment); diff --git a/client/beefy/src/notification.rs b/client/beefy/src/notification.rs index 6099c9681447b..f394ae6c840a2 100644 --- a/client/beefy/src/notification.rs +++ b/client/beefy/src/notification.rs @@ -24,8 +24,7 @@ use sp_runtime::traits::{Block, NumberFor}; use parking_lot::Mutex; /// Stream of signed commitments returned when subscribing. -pub type SignedCommitment = - beefy_primitives::SignedCommitment, beefy_primitives::MmrRootHash>; +pub type SignedCommitment = beefy_primitives::SignedCommitment>; /// Stream of signed commitments returned when subscribing. type SignedCommitmentStream = TracingUnboundedReceiver>; diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index e9f5ad2062433..db41f0f465db6 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -53,14 +53,14 @@ fn threshold(authorities: usize) -> usize { authorities - faulty } -pub(crate) struct Rounds { - rounds: BTreeMap<(Hash, Number), RoundTracker>, +pub(crate) struct Rounds { + rounds: BTreeMap<(Payload, Number), RoundTracker>, validator_set: ValidatorSet, } -impl Rounds +impl Rounds where - H: Ord + Hash, + P: Ord + Hash, N: Ord + AtLeast32BitUnsigned + MaybeDisplay, { pub(crate) fn new(validator_set: ValidatorSet) -> Self { @@ -70,8 +70,8 @@ where impl Rounds where - H: Ord + Hash, - N: Ord + AtLeast32BitUnsigned + MaybeDisplay, + H: Ord + Hash + Clone, + N: Ord + AtLeast32BitUnsigned + MaybeDisplay + Clone, { pub(crate) fn validator_set_id(&self) -> ValidatorSetId { self.validator_set.id @@ -81,9 +81,9 @@ where self.validator_set.validators.clone() } - pub(crate) fn add_vote(&mut self, round: (H, N), vote: (Public, Signature)) -> bool { + pub(crate) fn add_vote(&mut self, round: &(H, N), vote: (Public, Signature)) -> bool { if self.validator_set.validators.iter().any(|id| vote.0 == *id) { - self.rounds.entry(round).or_default().add_vote(vote) + self.rounds.entry(round.clone()).or_default().add_vote(vote) } else { false } @@ -179,7 +179,7 @@ mod tests { let mut rounds = Rounds::>::new(validators); assert!(rounds.add_vote( - (H256::from_low_u64_le(1), 1), + &(H256::from_low_u64_le(1), 1), (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")) )); @@ -187,21 +187,21 @@ mod tests { // invalid vote assert!(!rounds.add_vote( - (H256::from_low_u64_le(1), 1), + &(H256::from_low_u64_le(1), 1), (Keyring::Dave.public(), Keyring::Dave.sign(b"I am committed")) )); assert!(!rounds.is_done(&(H256::from_low_u64_le(1), 1))); assert!(rounds.add_vote( - (H256::from_low_u64_le(1), 1), + &(H256::from_low_u64_le(1), 1), (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")) )); assert!(!rounds.is_done(&(H256::from_low_u64_le(1), 1))); assert!(rounds.add_vote( - (H256::from_low_u64_le(1), 1), + &(H256::from_low_u64_le(1), 1), (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am committed")) )); @@ -225,31 +225,31 @@ mod tests { // round 1 rounds.add_vote( - (H256::from_low_u64_le(1), 1), + &(H256::from_low_u64_le(1), 1), (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), ); rounds.add_vote( - (H256::from_low_u64_le(1), 1), + &(H256::from_low_u64_le(1), 1), (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")), ); // round 2 rounds.add_vote( - (H256::from_low_u64_le(2), 2), + &(H256::from_low_u64_le(2), 2), (Keyring::Alice.public(), Keyring::Alice.sign(b"I am again committed")), ); rounds.add_vote( - (H256::from_low_u64_le(2), 2), + &(H256::from_low_u64_le(2), 2), (Keyring::Bob.public(), Keyring::Bob.sign(b"I am again committed")), ); // round 3 rounds.add_vote( - (H256::from_low_u64_le(3), 3), + &(H256::from_low_u64_le(3), 3), (Keyring::Alice.public(), Keyring::Alice.sign(b"I am still committed")), ); rounds.add_vote( - (H256::from_low_u64_le(3), 3), + &(H256::from_low_u64_le(3), 3), (Keyring::Bob.public(), Keyring::Bob.sign(b"I am still committed")), ); diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 3f52686930332..fa48e64c12b4e 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -36,8 +36,8 @@ use sp_runtime::{ use beefy_primitives::{ crypto::{AuthorityId, Public, Signature}, - BeefyApi, Commitment, ConsensusLog, MmrRootHash, SignedCommitment, ValidatorSet, - VersionedCommitment, VoteMessage, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, + known_payload_ids, BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, SignedCommitment, + ValidatorSet, VersionedCommitment, VoteMessage, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, }; use crate::{ @@ -79,7 +79,7 @@ where /// Min delta in block numbers between two blocks, BEEFY should vote on min_block_delta: u32, metrics: Option, - rounds: round::Rounds>, + rounds: round::Rounds>, finality_notifications: FinalityNotifications, /// Best block we received a GRANDPA notification for best_grandpa_block: NumberFor, @@ -262,8 +262,9 @@ where return }; + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, mmr_root.encode()); let commitment = Commitment { - payload: mmr_root, + payload, block_number: notification.header.number(), validator_set_id: self.rounds.validator_set_id(), }; @@ -301,10 +302,10 @@ where } } - fn handle_vote(&mut self, round: (MmrRootHash, NumberFor), vote: (Public, Signature)) { + fn handle_vote(&mut self, round: (Payload, NumberFor), vote: (Public, Signature)) { self.gossip_validator.note_round(round.1); - let vote_added = self.rounds.add_vote(round, vote); + let vote_added = self.rounds.add_vote(&round, vote); if vote_added && self.rounds.is_done(&round) { if let Some(signatures) = self.rounds.drop(&round) { @@ -352,7 +353,7 @@ where |notification| async move { debug!(target: "beefy", "🥩 Got vote message: {:?}", notification); - VoteMessage::, Public, Signature>::decode( + VoteMessage::, Public, Signature>::decode( &mut ¬ification.message[..], ) .ok() diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 23e98012027c7..e38af745cd714 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -18,8 +18,8 @@ sp-runtime = { version = "4.0.0-dev", path = "../runtime", default-features = fa sp-std = { version = "4.0.0-dev", path = "../std", default-features = false } [dev-dependencies] +hex = "0.4.3" hex-literal = "0.3" - sp-keystore = { version = "0.10.0-dev", path = "../keystore" } [features] diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index d9e4de6e19bb7..667c03cc2284c 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -15,10 +15,65 @@ // See the License for the specific language governing permissions and // limitations under the License. +use codec::{Decode, Encode}; use sp_std::{cmp, prelude::*}; use crate::{crypto::Signature, ValidatorSetId}; +/// Id of different payloads in the [`Commitment`] data +pub type BeefyPayloadId = [u8; 2]; + +/// Registry of all known [`BeefyPayloadId`]. +pub mod known_payload_ids { + use crate::BeefyPayloadId; + + /// A [`Payload`] identifier for Merkle Mountain Range root hash. + /// + /// Encoded value should contain a [`beefy_primitives::MmrRootHash`] type (i.e. 32-bytes hash). + pub const MMR_ROOT_ID: BeefyPayloadId = *b"mh"; +} + +/// A BEEFY payload type allowing for future extensibility of adding additional kinds of payloads. +/// +/// The idea is to store a vector of SCALE-encoded values with an extra identifier. +/// Identifiers MUST be sorted by the [`BeefyPayloadId`] to allow efficient lookup of expected +/// value. Duplicated identifiers are disallowed. It's okay for different implementations to only +/// support a subset of possible values. +#[derive(Decode, Encode, Debug, PartialEq, Eq, Clone, Ord, PartialOrd, Hash)] +pub struct Payload(Vec<(BeefyPayloadId, Vec)>); + +impl Payload { + /// Construct a new payload given an initial vallue + pub fn new(id: BeefyPayloadId, value: Vec) -> Self { + Self(vec![(id, value)]) + } + + /// Returns a raw payload under given `id`. + /// + /// If the [`BeefyPayloadId`] is not found in the payload `None` is returned. + pub fn get_raw(&self, id: &BeefyPayloadId) -> Option<&Vec> { + let index = self.0.binary_search_by(|probe| probe.0.cmp(id)).ok()?; + Some(&self.0[index].1) + } + + /// Returns a decoded payload value under given `id`. + /// + /// In case the value is not there or it cannot be decoded does not match `None` is returned. + pub fn get_decoded(&self, id: &BeefyPayloadId) -> Option { + self.get_raw(id).and_then(|raw| T::decode(&mut &raw[..]).ok()) + } + + /// Push a `Vec` with a given id into the payload vec. + /// This method will internally sort the payload vec after every push. + /// + /// Returns self to allow for daisy chaining. + pub fn push_raw(mut self, id: BeefyPayloadId, value: Vec) -> Self { + self.0.push((id, value)); + self.0.sort_by_key(|(id, _)| *id); + self + } +} + /// A commitment signed by GRANDPA validators as part of BEEFY protocol. /// /// The commitment contains a [payload](Commitment::payload) extracted from the finalized block at @@ -26,16 +81,17 @@ use crate::{crypto::Signature, ValidatorSetId}; /// GRANDPA validators collect signatures on commitments and a stream of such signed commitments /// (see [SignedCommitment]) forms the BEEFY protocol. #[derive(Clone, Debug, PartialEq, Eq, codec::Encode, codec::Decode)] -pub struct Commitment { - /// The payload being signed. +pub struct Commitment { + /// A collection of payloads to be signed, see [`Payload`] for details. /// - /// This should be some form of cumulative representation of the chain (think MMR root hash). - /// The payload should also contain some details that allow the light client to verify next - /// validator set. The protocol does not enforce any particular format of this data, - /// nor how often it should be present in commitments, however the light client has to be - /// provided with full validator set whenever it performs the transition (i.e. importing first - /// block with [validator_set_id](Commitment::validator_set_id) incremented). - pub payload: TPayload, + /// One of the payloads should be some form of cumulative representation of the chain (think + /// MMR root hash). Additionally one of the payloads should also contain some details that + /// allow the light client to verify next validator set. The protocol does not enforce any + /// particular format of this data, nor how often it should be present in commitments, however + /// the light client has to be provided with full validator set whenever it performs the + /// transition (i.e. importing first block with + /// [validator_set_id](Commitment::validator_set_id) incremented). + pub payload: Payload, /// Finalized block number this commitment is for. /// @@ -57,20 +113,18 @@ pub struct Commitment { pub validator_set_id: ValidatorSetId, } -impl cmp::PartialOrd for Commitment +impl cmp::PartialOrd for Commitment where TBlockNumber: cmp::Ord, - TPayload: cmp::Eq, { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl cmp::Ord for Commitment +impl cmp::Ord for Commitment where TBlockNumber: cmp::Ord, - TPayload: cmp::Eq, { fn cmp(&self, other: &Self) -> cmp::Ordering { self.validator_set_id @@ -81,9 +135,9 @@ where /// A commitment with matching GRANDPA validators' signatures. #[derive(Clone, Debug, PartialEq, Eq, codec::Encode, codec::Decode)] -pub struct SignedCommitment { +pub struct SignedCommitment { /// The commitment signatures are collected for. - pub commitment: Commitment, + pub commitment: Commitment, /// GRANDPA validators' signatures for the commitment. /// /// The length of this `Vec` must match number of validators in the current set (see @@ -91,7 +145,7 @@ pub struct SignedCommitment { pub signatures: Vec>, } -impl SignedCommitment { +impl SignedCommitment { /// Return the number of collected signatures. pub fn no_of_signatures(&self) -> usize { self.signatures.iter().filter(|x| x.is_some()).count() @@ -102,10 +156,10 @@ impl SignedCommitment { /// to the block justifications for the block for which the signed commitment /// has been generated. #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] -pub enum VersionedCommitment { +pub enum VersionedCommitment { #[codec(index = 1)] /// Current active version - V1(SignedCommitment), + V1(SignedCommitment), } #[cfg(test)] @@ -119,9 +173,9 @@ mod tests { use crate::{crypto, KEY_TYPE}; - type TestCommitment = Commitment; - type TestSignedCommitment = SignedCommitment; - type TestVersionedCommitment = VersionedCommitment; + type TestCommitment = Commitment; + type TestSignedCommitment = SignedCommitment; + type TestVersionedCommitment = VersionedCommitment; // The mock signatures are equivalent to the ones produced by the BEEFY keystore fn mock_signatures() -> (crypto::Signature, crypto::Signature) { @@ -148,8 +202,9 @@ mod tests { #[test] fn commitment_encode_decode() { // given + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = - Commitment { payload: "Hello World!".into(), block_number: 5, validator_set_id: 0 }; + Commitment { payload, block_number: 5, validator_set_id: 0 }; // when let encoded = codec::Encode::encode(&commitment); @@ -160,7 +215,7 @@ mod tests { assert_eq!( encoded, hex_literal::hex!( - "3048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000" + "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000" ) ); } @@ -168,8 +223,9 @@ mod tests { #[test] fn signed_commitment_encode_decode() { // given + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = - Commitment { payload: "Hello World!".into(), block_number: 5, validator_set_id: 0 }; + Commitment { payload, block_number: 5, validator_set_id: 0 }; let sigs = mock_signatures(); @@ -187,10 +243,11 @@ mod tests { assert_eq!( encoded, hex_literal::hex!( - "3048656c6c6f20576f726c64210500000000000000000000000000000000000000000000001000 - 0001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d - 10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a - 2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a00" + "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000 + 10000001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321 + f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a86cdd9aaa + cdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a + 0046395a71681be3d0c2a00" ) ); } @@ -198,8 +255,9 @@ mod tests { #[test] fn signed_commitment_count_signatures() { // given + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = - Commitment { payload: "Hello World!".into(), block_number: 5, validator_set_id: 0 }; + Commitment { payload, block_number: 5, validator_set_id: 0 }; let sigs = mock_signatures(); @@ -222,7 +280,8 @@ mod tests { block_number: u128, validator_set_id: crate::ValidatorSetId, ) -> TestCommitment { - Commitment { payload: "Hello World!".into(), block_number, validator_set_id } + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + Commitment { payload, block_number, validator_set_id } } // given @@ -241,8 +300,9 @@ mod tests { #[test] fn versioned_commitment_encode_decode() { + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = - Commitment { payload: "Hello World!".into(), block_number: 5, validator_set_id: 0 }; + Commitment { payload, block_number: 5, validator_set_id: 0 }; let sigs = mock_signatures(); diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index 790b915ab98db..cb3cf601a76bc 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -35,7 +35,9 @@ mod commitment; pub mod mmr; pub mod witness; -pub use commitment::{Commitment, SignedCommitment, VersionedCommitment}; +pub use commitment::{ + known_payload_ids, BeefyPayloadId, Commitment, Payload, SignedCommitment, VersionedCommitment, +}; use codec::{Codec, Decode, Encode}; use scale_info::TypeInfo; @@ -118,9 +120,9 @@ pub enum ConsensusLog { /// A vote message is a direct vote created by a BEEFY node on every voting round /// and is gossiped to its peers. #[derive(Debug, Decode, Encode, TypeInfo)] -pub struct VoteMessage { +pub struct VoteMessage { /// Commit to information extracted from a finalized block - pub commitment: Commitment, + pub commitment: Commitment, /// Node authority id pub id: Id, /// Node signature diff --git a/primitives/beefy/src/witness.rs b/primitives/beefy/src/witness.rs index c28a464e72df5..3ead08bdd7cb3 100644 --- a/primitives/beefy/src/witness.rs +++ b/primitives/beefy/src/witness.rs @@ -40,9 +40,9 @@ use crate::{ /// Ethereum Mainnet), in a commit-reveal like scheme, where first we submit only the signed /// commitment witness and later on, the client picks only some signatures to verify at random. #[derive(Debug, PartialEq, Eq, codec::Encode, codec::Decode)] -pub struct SignedCommitmentWitness { +pub struct SignedCommitmentWitness { /// The full content of the commitment. - pub commitment: Commitment, + pub commitment: Commitment, /// The bit vector of validators who signed the commitment. pub signed_by: Vec, // TODO [ToDr] Consider replacing with bitvec crate @@ -51,9 +51,7 @@ pub struct SignedCommitmentWitness { pub signatures_merkle_root: TMerkleRoot, } -impl - SignedCommitmentWitness -{ +impl SignedCommitmentWitness { /// Convert [SignedCommitment] into [SignedCommitmentWitness]. /// /// This takes a [SignedCommitment], which contains full signatures @@ -63,7 +61,7 @@ impl /// /// Returns the full list of signatures along with the witness. pub fn from_signed( - signed: SignedCommitment, + signed: SignedCommitment, merkelize: TMerkelize, ) -> (Self, Vec>) where @@ -86,12 +84,11 @@ mod tests { use super::*; use codec::Decode; - use crate::{crypto, KEY_TYPE}; + use crate::{crypto, known_payload_ids, Payload, KEY_TYPE}; - type TestCommitment = Commitment; - type TestSignedCommitment = SignedCommitment; - type TestSignedCommitmentWitness = - SignedCommitmentWitness>>; + type TestCommitment = Commitment; + type TestSignedCommitment = SignedCommitment; + type TestSignedCommitmentWitness = SignedCommitmentWitness>>; // The mock signatures are equivalent to the ones produced by the BEEFY keystore fn mock_signatures() -> (crypto::Signature, crypto::Signature) { @@ -116,8 +113,10 @@ mod tests { } fn signed_commitment() -> TestSignedCommitment { + let payload = + Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".as_bytes().to_vec()); let commitment: TestCommitment = - Commitment { payload: "Hello World!".into(), block_number: 5, validator_set_id: 0 }; + Commitment { payload, block_number: 5, validator_set_id: 0 }; let sigs = mock_signatures(); @@ -152,10 +151,11 @@ mod tests { assert_eq!( encoded, hex_literal::hex!( - "3048656c6c6f20576f726c64210500000000000000000000000000000000000000000000001000 - 00010110000001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e9 - 9a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd - 48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a00" + "046d683048656c6c6f20576f726c642105000000000000000000000000000000000000000000000010 + 0000010110000001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c + 746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a86 + cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bc + a2324b6a0046395a71681be3d0c2a00" ) ); } From 089aa2509f928b161b0f970d1ff670635f6a26fe Mon Sep 17 00:00:00 2001 From: Alex Pozhylenkov Date: Wed, 1 Dec 2021 23:31:57 +0200 Subject: [PATCH 0293/1472] Move EnsureOneOf into the dispatch.rs, make an interface more general (#10379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * move EnsureOneOf into the dispatch.rs, make an interface more general * Update frame/support/src/traits/dispatch.rs Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher Co-authored-by: Shawn Tabrizi --- bin/node/runtime/src/lib.rs | 9 +---- frame/identity/src/tests.rs | 10 +++-- frame/scheduler/src/lib.rs | 6 +-- frame/support/src/traits.rs | 2 +- frame/support/src/traits/dispatch.rs | 60 +++++++++++++++++++++++++++- frame/system/src/lib.rs | 25 +----------- frame/system/src/tests.rs | 11 ----- 7 files changed, 72 insertions(+), 51 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3f553221e67ac..2cf6548b79211 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -26,7 +26,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU32, Currency, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, + ConstU32, Currency, EnsureOneOf, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, }, weights::{ @@ -37,7 +37,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureOneOf, EnsureRoot, + EnsureRoot, }; pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; @@ -535,7 +535,6 @@ impl pallet_staking::Config for Runtime { type SlashDeferDuration = SlashDeferDuration; /// A super-majority of the council can cancel the slash. type SlashCancelOrigin = EnsureOneOf< - AccountId, EnsureRoot, pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>, >; @@ -726,7 +725,6 @@ impl pallet_democracy::Config for Runtime { // To cancel a proposal before it has been passed, the technical committee must be unanimous or // Root must agree. type CancelProposalOrigin = EnsureOneOf< - AccountId, EnsureRoot, pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>, >; @@ -817,7 +815,6 @@ impl pallet_collective::Config for Runtime { } type EnsureRootOrHalfCouncil = EnsureOneOf< - AccountId, EnsureRoot, pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>, >; @@ -857,12 +854,10 @@ impl pallet_treasury::Config for Runtime { type PalletId = TreasuryPalletId; type Currency = Balances; type ApproveOrigin = EnsureOneOf< - AccountId, EnsureRoot, pallet_collective::EnsureProportionAtLeast<_3, _5, AccountId, CouncilCollective>, >; type RejectOrigin = EnsureOneOf< - AccountId, EnsureRoot, pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>, >; diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index c842b0e2f64be..31b93e70fd3dc 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -21,8 +21,10 @@ use super::*; use crate as pallet_identity; use codec::{Decode, Encode}; -use frame_support::{assert_noop, assert_ok, ord_parameter_types, parameter_types, BoundedVec}; -use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; +use frame_support::{ + assert_noop, assert_ok, ord_parameter_types, parameter_types, traits::EnsureOneOf, BoundedVec, +}; +use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -100,8 +102,8 @@ ord_parameter_types! { pub const One: u64 = 1; pub const Two: u64 = 2; } -type EnsureOneOrRoot = EnsureOneOf, EnsureSignedBy>; -type EnsureTwoOrRoot = EnsureOneOf, EnsureSignedBy>; +type EnsureOneOrRoot = EnsureOneOf, EnsureSignedBy>; +type EnsureTwoOrRoot = EnsureOneOf, EnsureSignedBy>; impl pallet_identity::Config for Test { type Event = Event; type Currency = Balances; diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index b3e64fe57f642..260ef90b05372 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -805,11 +805,11 @@ mod tests { use crate as scheduler; use frame_support::{ assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + traits::{Contains, EnsureOneOf, EqualPrivilegeOnly, OnFinalize, OnInitialize}, weights::constants::RocksDbWeight, Hashable, }; - use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; + use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -950,7 +950,7 @@ mod tests { type PalletsOrigin = OriginCaller; type Call = Call; type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; + type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index bb990e25646db..9b5453c0a01ae 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -84,7 +84,7 @@ pub use storage::{ }; mod dispatch; -pub use dispatch::{EnsureOrigin, OriginTrait, UnfilteredDispatchable}; +pub use dispatch::{EnsureOneOf, EnsureOrigin, OriginTrait, UnfilteredDispatchable}; mod voting; pub use voting::{CurrencyToVote, SaturatingCurrencyToVote, U128CurrencyToVote}; diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 92b832ba32961..d7605593cd604 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -18,7 +18,7 @@ //! Traits for dealing with dispatching calls and the origin from which they are dispatched. use crate::dispatch::DispatchResultWithPostInfo; -use sp_runtime::traits::BadOrigin; +use sp_runtime::{traits::BadOrigin, Either}; /// Some sort of check on the origin is performed by this object. pub trait EnsureOrigin { @@ -94,3 +94,61 @@ pub trait OriginTrait: Sized { /// Create with system signed origin and `frame_system::Config::BaseCallFilter`. fn signed(by: Self::AccountId) -> Self; } + +/// The "OR gate" implementation of `EnsureOrigin`. +/// +/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. +pub struct EnsureOneOf(sp_std::marker::PhantomData<(L, R)>); + +impl, R: EnsureOrigin> + EnsureOrigin for EnsureOneOf +{ + type Success = Either; + fn try_origin(o: OuterOrigin) -> Result { + L::try_origin(o) + .map_or_else(|o| R::try_origin(o).map(|o| Either::Right(o)), |o| Ok(Either::Left(o))) + } + + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> OuterOrigin { + L::successful_origin() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + struct EnsureSuccess; + struct EnsureFail; + + impl EnsureOrigin<()> for EnsureSuccess { + type Success = (); + fn try_origin(_: ()) -> Result { + Ok(()) + } + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> () { + () + } + } + + impl EnsureOrigin<()> for EnsureFail { + type Success = (); + fn try_origin(_: ()) -> Result { + Err(()) + } + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> () { + () + } + } + + #[test] + fn ensure_one_of_test() { + assert!(>::try_origin(()).is_ok()); + assert!(>::try_origin(()).is_ok()); + assert!(>::try_origin(()).is_ok()); + assert!(>::try_origin(()).is_err()); + } +} diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 31b702c135dea..aac104fa8f765 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -73,7 +73,7 @@ use sp_runtime::{ CheckEqual, Dispatchable, Hash, Lookup, LookupError, MaybeDisplay, MaybeMallocSizeOf, MaybeSerializeDeserialize, Member, One, Saturating, SimpleBitOps, StaticLookup, Zero, }, - DispatchError, Either, Perbill, RuntimeDebug, + DispatchError, Perbill, RuntimeDebug, }; #[cfg(any(feature = "std", test))] use sp_std::map; @@ -902,29 +902,6 @@ impl EnsureOrigin for EnsureNever { } } -/// The "OR gate" implementation of `EnsureOrigin`. -/// -/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. -pub struct EnsureOneOf(sp_std::marker::PhantomData<(AccountId, L, R)>); -impl< - AccountId, - O: Into, O>> + From>, - L: EnsureOrigin, - R: EnsureOrigin, - > EnsureOrigin for EnsureOneOf -{ - type Success = Either; - fn try_origin(o: O) -> Result { - L::try_origin(o) - .map_or_else(|o| R::try_origin(o).map(|o| Either::Right(o)), |o| Ok(Either::Left(o))) - } - - #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { - L::successful_origin() - } -} - /// Ensure that the origin `o` represents a signed extrinsic (i.e. transaction). /// Returns `Ok` with the account that signed the extrinsic or an `Err` otherwise. pub fn ensure_signed(o: OuterOrigin) -> Result diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index f9c167ec4be34..d8f9fd1af2bc2 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -461,17 +461,6 @@ fn events_not_emitted_during_genesis() { }); } -#[test] -fn ensure_one_of_works() { - fn ensure_root_or_signed(o: RawOrigin) -> Result, Origin> { - EnsureOneOf::, EnsureSigned>::try_origin(o.into()) - } - - assert_eq!(ensure_root_or_signed(RawOrigin::Root).unwrap(), Either::Left(())); - assert_eq!(ensure_root_or_signed(RawOrigin::Signed(0)).unwrap(), Either::Right(0)); - assert!(ensure_root_or_signed(RawOrigin::None).is_err()); -} - #[test] fn extrinsics_root_is_calculated_correctly() { new_test_ext().execute_with(|| { From 3904d77ad2499ab36b242e52fbe23d5cd8773ad9 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 2 Dec 2021 09:11:10 +0100 Subject: [PATCH 0294/1472] Minimum commission for validators (#10347) * Minimum commission for validators * rename * Fix benchmakrs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/staking/src/pallet/mod.rs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot Co-authored-by: Shawn Tabrizi --- frame/staking/src/benchmarking.rs | 11 +- frame/staking/src/pallet/mod.rs | 38 +++- frame/staking/src/tests.rs | 80 +++++++- frame/staking/src/weights.rs | 233 ++++++++++++------------ primitives/arithmetic/src/per_things.rs | 10 + 5 files changed, 236 insertions(+), 136 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 5feb1692d955d..69a73c51fdc7e 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -842,7 +842,7 @@ benchmarks! { assert_eq!(targets.len() as u32, v); } - set_staking_limits { + set_staking_configs { // This function always does the same thing... just write to 4 storage items. }: _( RawOrigin::Root, @@ -850,13 +850,15 @@ benchmarks! { BalanceOf::::max_value(), Some(u32::MAX), Some(u32::MAX), - Some(Percent::max_value()) + Some(Percent::max_value()), + Perbill::max_value() ) verify { assert_eq!(MinNominatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MinValidatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MaxNominatorsCount::::get(), Some(u32::MAX)); assert_eq!(MaxValidatorsCount::::get(), Some(u32::MAX)); assert_eq!(ChillThreshold::::get(), Some(Percent::from_percent(100))); + assert_eq!(MinCommission::::get(), Perbill::from_percent(100)); } chill_other { @@ -872,13 +874,14 @@ benchmarks! { let stash = scenario.origin_stash1.clone(); assert!(T::SortedListProvider::contains(&stash)); - Staking::::set_staking_limits( + Staking::::set_staking_configs( RawOrigin::Root.into(), BalanceOf::::max_value(), BalanceOf::::max_value(), Some(0), Some(0), - Some(Percent::from_percent(0)) + Some(Percent::from_percent(0)), + Zero::zero(), )?; let caller = whitelisted_caller(); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index f8f9c8c794dc7..f7e96ce0cf765 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -215,6 +215,12 @@ pub mod pallet { #[pallet::storage] pub type MinValidatorBond = StorageValue<_, BalanceOf, ValueQuery>; + /// The minimum amount of commission that validators can set. + /// + /// If set to `0`, no limit exists. + #[pallet::storage] + pub type MinCommission = StorageValue<_, Perbill, ValueQuery>; + /// Map from all (unlocked) "controller" accounts to the info regarding the staking. #[pallet::storage] #[pallet::getter(fn ledger)] @@ -486,6 +492,8 @@ pub mod pallet { Vec<(T::AccountId, T::AccountId, BalanceOf, crate::StakerStatus)>, pub min_nominator_bond: BalanceOf, pub min_validator_bond: BalanceOf, + pub max_validator_count: Option, + pub max_nominator_count: Option, } #[cfg(feature = "std")] @@ -502,6 +510,8 @@ pub mod pallet { stakers: Default::default(), min_nominator_bond: Default::default(), min_validator_bond: Default::default(), + max_validator_count: None, + max_nominator_count: None, } } } @@ -519,6 +529,12 @@ pub mod pallet { StorageVersion::::put(Releases::V7_0_0); MinNominatorBond::::put(self.min_nominator_bond); MinValidatorBond::::put(self.min_validator_bond); + if let Some(x) = self.max_validator_count { + MaxValidatorsCount::::put(x); + } + if let Some(x) = self.max_nominator_count { + MaxNominatorsCount::::put(x); + } for &(ref stash, ref controller, balance, ref status) in &self.stakers { log!( @@ -650,6 +666,8 @@ pub mod pallet { /// There are too many validators in the system. Governance needs to adjust the staking /// settings to keep things safe for the runtime. TooManyValidators, + /// Commission is too low. Must be at least `MinCommission`. + CommissionTooLow, } #[pallet::hooks] @@ -955,9 +973,13 @@ pub mod pallet { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + ensure!(ledger.active >= MinValidatorBond::::get(), Error::::InsufficientBond); let stash = &ledger.stash; + // ensure their commission is correct. + ensure!(prefs.commission >= MinCommission::::get(), Error::::CommissionTooLow); + // Only check limits if they are not already a validator. if !Validators::::contains_key(stash) { // If this error is reached, we need to adjust the `MinValidatorBond` and start @@ -1508,7 +1530,7 @@ pub mod pallet { Ok(()) } - /// Update the various staking limits this pallet. + /// Update the various staking configurations . /// /// * `min_nominator_bond`: The minimum active bond needed to be a nominator. /// * `min_validator_bond`: The minimum active bond needed to be a validator. @@ -1516,26 +1538,32 @@ pub mod pallet { /// set to `None`, no limit is enforced. /// * `max_validator_count`: The max number of users who can be a validator at once. When /// set to `None`, no limit is enforced. + /// * `chill_threshold`: The ratio of `max_nominator_count` or `max_validator_count` which + /// should be filled in order for the `chill_other` transaction to work. + /// * `min_commission`: The minimum amount of commission that each validators must maintain. + /// This is checked only upon calling `validate`. Existing validators are not affected. /// /// Origin must be Root to call this function. /// /// NOTE: Existing nominators and validators will not be affected by this update. /// to kick people under the new limits, `chill_other` should be called. - #[pallet::weight(T::WeightInfo::set_staking_limits())] - pub fn set_staking_limits( + #[pallet::weight(T::WeightInfo::set_staking_configs())] + pub fn set_staking_configs( origin: OriginFor, min_nominator_bond: BalanceOf, min_validator_bond: BalanceOf, max_nominator_count: Option, max_validator_count: Option, - threshold: Option, + chill_threshold: Option, + min_commission: Perbill, ) -> DispatchResult { ensure_root(origin)?; MinNominatorBond::::set(min_nominator_bond); MinValidatorBond::::set(min_validator_bond); MaxNominatorsCount::::set(max_nominator_count); MaxValidatorsCount::::set(max_validator_count); - ChillThreshold::::set(threshold); + ChillThreshold::::set(chill_threshold); + MinCommission::::set(min_commission); Ok(()) } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index f8f37bed0066c..4604351b52305 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4350,7 +4350,15 @@ fn chill_other_works() { ); // Change the minimum bond... but no limits. - assert_ok!(Staking::set_staking_limits(Origin::root(), 1_500, 2_000, None, None, None)); + assert_ok!(Staking::set_staking_configs( + Origin::root(), + 1_500, + 2_000, + None, + None, + None, + Zero::zero() + )); // Still can't chill these users assert_noop!( @@ -4363,13 +4371,14 @@ fn chill_other_works() { ); // Add limits, but no threshold - assert_ok!(Staking::set_staking_limits( + assert_ok!(Staking::set_staking_configs( Origin::root(), 1_500, 2_000, Some(10), Some(10), - None + None, + Zero::zero() )); // Still can't chill these users @@ -4383,13 +4392,14 @@ fn chill_other_works() { ); // Add threshold, but no limits - assert_ok!(Staking::set_staking_limits( + assert_ok!(Staking::set_staking_configs( Origin::root(), 1_500, 2_000, None, None, - Some(Percent::from_percent(0)) + Some(Percent::from_percent(0)), + Zero::zero() )); // Still can't chill these users @@ -4403,13 +4413,14 @@ fn chill_other_works() { ); // Add threshold and limits - assert_ok!(Staking::set_staking_limits( + assert_ok!(Staking::set_staking_configs( Origin::root(), 1_500, 2_000, Some(10), Some(10), - Some(Percent::from_percent(75)) + Some(Percent::from_percent(75)), + Zero::zero() )); // 16 people total because tests start with 2 active one @@ -4447,13 +4458,14 @@ fn capped_stakers_works() { // Change the maximums let max = 10; - assert_ok!(Staking::set_staking_limits( + assert_ok!(Staking::set_staking_configs( Origin::root(), 10, 10, Some(max), Some(max), - Some(Percent::from_percent(0)) + Some(Percent::from_percent(0)), + Zero::zero(), )); // can create `max - validator_count` validators @@ -4516,12 +4528,60 @@ fn capped_stakers_works() { )); // No problem when we set to `None` again - assert_ok!(Staking::set_staking_limits(Origin::root(), 10, 10, None, None, None)); + assert_ok!(Staking::set_staking_configs( + Origin::root(), + 10, + 10, + None, + None, + None, + Zero::zero(), + )); assert_ok!(Staking::nominate(Origin::signed(last_nominator), vec![1])); assert_ok!(Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default())); }) } +#[test] +fn min_commission_works() { + ExtBuilder::default().build_and_execute(|| { + assert_ok!(Staking::validate( + Origin::signed(10), + ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } + )); + + assert_ok!(Staking::set_staking_configs( + Origin::root(), + 0, + 0, + None, + None, + None, + Perbill::from_percent(10), + )); + + // can't make it less than 10 now + assert_noop!( + Staking::validate( + Origin::signed(10), + ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } + ), + Error::::CommissionTooLow + ); + + // can only change to higher. + assert_ok!(Staking::validate( + Origin::signed(10), + ValidatorPrefs { commission: Perbill::from_percent(10), blocked: false } + )); + + assert_ok!(Staking::validate( + Origin::signed(10), + ValidatorPrefs { commission: Perbill::from_percent(15), blocked: false } + )); + }) +} + mod sorted_list_provider { use super::*; use frame_election_provider_support::SortedListProvider; diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 32c8dc80da158..0ca819898fbb0 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-09-04, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-11-29, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -35,7 +35,6 @@ // --output=./frame/staking/src/weights.rs // --template=./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -71,7 +70,7 @@ pub trait WeightInfo { fn new_era(v: u32, n: u32, ) -> Weight; fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight; fn get_npos_targets(v: u32, ) -> Weight; - fn set_staking_limits() -> Weight; + fn set_staking_configs() -> Weight; fn chill_other() -> Weight; } @@ -85,7 +84,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (73_865_000 as Weight) + (63_660_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -95,7 +94,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (114_296_000 as Weight) + (103_672_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -109,7 +108,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (121_737_000 as Weight) + (110_884_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -118,7 +117,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (51_631_000 as Weight) + (46_379_000 as Weight) // Standard Error: 0 .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) @@ -138,12 +137,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (101_870_000 as Weight) + (91_303_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(11 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) + // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) // Storage: Staking MaxValidatorsCount (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) @@ -153,16 +153,16 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (69_092_000 as Weight) - .saturating_add(T::DbWeight::get().reads(11 as Weight)) + (66_587_000 as Weight) + .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (21_468_000 as Weight) - // Standard Error: 19_000 - .saturating_add((16_415_000 as Weight).saturating_mul(k as Weight)) + (21_153_000 as Weight) + // Standard Error: 16_000 + .saturating_add((13_502_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -179,9 +179,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (82_389_000 as Weight) - // Standard Error: 14_000 - .saturating_add((5_597_000 as Weight).saturating_mul(n as Weight)) + (75_456_000 as Weight) + // Standard Error: 12_000 + .saturating_add((5_051_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(6 as Weight)) @@ -194,47 +194,47 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (69_655_000 as Weight) + (65_332_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (12_770_000 as Weight) + (11_757_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (27_756_000 as Weight) + (24_252_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (2_446_000 as Weight) + (2_252_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (2_720_000 as Weight) + (2_431_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (2_711_000 as Weight) + (2_397_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (2_796_000 as Weight) + (2_423_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (3_141_000 as Weight) + (2_876_000 as Weight) // Standard Error: 0 .saturating_add((53_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -253,18 +253,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (97_394_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_370_000 as Weight).saturating_mul(s as Weight)) + (87_540_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_791_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (2_783_746_000 as Weight) - // Standard Error: 182_000 - .saturating_add((16_223_000 as Weight).saturating_mul(s as Weight)) + (2_769_801_000 as Weight) + // Standard Error: 181_000 + .saturating_add((16_225_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -279,9 +279,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (109_233_000 as Weight) - // Standard Error: 17_000 - .saturating_add((47_612_000 as Weight).saturating_mul(n as Weight)) + (103_452_000 as Weight) + // Standard Error: 19_000 + .saturating_add((42_909_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -299,9 +299,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (177_392_000 as Weight) - // Standard Error: 20_000 - .saturating_add((60_771_000 as Weight).saturating_mul(n as Weight)) + (145_995_000 as Weight) + // Standard Error: 27_000 + .saturating_add((55_974_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -314,9 +314,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (111_858_000 as Weight) - // Standard Error: 4_000 - .saturating_add((36_000 as Weight).saturating_mul(l as Weight)) + (101_568_000 as Weight) + // Standard Error: 2_000 + .saturating_add((66_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(9 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -331,14 +331,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 68_000 - .saturating_add((33_495_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 69_000 + .saturating_add((29_939_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) .saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:1) // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) @@ -347,14 +348,13 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (100_178_000 as Weight) + (96_886_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_358_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(11 as Weight)) + .saturating_add((1_790_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } @@ -378,10 +378,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 860_000 - .saturating_add((298_721_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 873_000 + .saturating_add((286_141_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 43_000 - .saturating_add((49_427_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((44_712_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -399,12 +399,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 91_000 - .saturating_add((26_605_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 91_000 - .saturating_add((31_481_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 3_122_000 - .saturating_add((16_672_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 87_000 + .saturating_add((24_049_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 87_000 + .saturating_add((27_514_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(204 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -413,19 +411,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 34_000 - .saturating_add((10_558_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 32_000 + .saturating_add((10_128_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } + // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) // Storage: Staking MaxValidatorsCount (r:0 w:1) // Storage: Staking ChillThreshold (r:0 w:1) // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) - fn set_staking_limits() -> Weight { - (6_353_000 as Weight) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + fn set_staking_configs() -> Weight { + (6_187_000 as Weight) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking ChillThreshold (r:1 w:0) @@ -438,7 +437,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (83_389_000 as Weight) + (78_282_000 as Weight) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -453,7 +452,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (73_865_000 as Weight) + (63_660_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -463,7 +462,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (114_296_000 as Weight) + (103_672_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } @@ -477,7 +476,7 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (121_737_000 as Weight) + (110_884_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -486,7 +485,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (51_631_000 as Weight) + (46_379_000 as Weight) // Standard Error: 0 .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) @@ -506,12 +505,13 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (101_870_000 as Weight) + (91_303_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) + // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) // Storage: Staking MaxValidatorsCount (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) @@ -521,16 +521,16 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (69_092_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(11 as Weight)) + (66_587_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (21_468_000 as Weight) - // Standard Error: 19_000 - .saturating_add((16_415_000 as Weight).saturating_mul(k as Weight)) + (21_153_000 as Weight) + // Standard Error: 16_000 + .saturating_add((13_502_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -547,9 +547,9 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (82_389_000 as Weight) - // Standard Error: 14_000 - .saturating_add((5_597_000 as Weight).saturating_mul(n as Weight)) + (75_456_000 as Weight) + // Standard Error: 12_000 + .saturating_add((5_051_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) @@ -562,47 +562,47 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (69_655_000 as Weight) + (65_332_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (12_770_000 as Weight) + (11_757_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (27_756_000 as Weight) + (24_252_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (2_446_000 as Weight) + (2_252_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (2_720_000 as Weight) + (2_431_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (2_711_000 as Weight) + (2_397_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (2_796_000 as Weight) + (2_423_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (3_141_000 as Weight) + (2_876_000 as Weight) // Standard Error: 0 .saturating_add((53_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -621,18 +621,18 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (97_394_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_370_000 as Weight).saturating_mul(s as Weight)) + (87_540_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_791_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (2_783_746_000 as Weight) - // Standard Error: 182_000 - .saturating_add((16_223_000 as Weight).saturating_mul(s as Weight)) + (2_769_801_000 as Weight) + // Standard Error: 181_000 + .saturating_add((16_225_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -647,9 +647,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (109_233_000 as Weight) - // Standard Error: 17_000 - .saturating_add((47_612_000 as Weight).saturating_mul(n as Weight)) + (103_452_000 as Weight) + // Standard Error: 19_000 + .saturating_add((42_909_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -667,9 +667,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (177_392_000 as Weight) - // Standard Error: 20_000 - .saturating_add((60_771_000 as Weight).saturating_mul(n as Weight)) + (145_995_000 as Weight) + // Standard Error: 27_000 + .saturating_add((55_974_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -682,9 +682,9 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (111_858_000 as Weight) - // Standard Error: 4_000 - .saturating_add((36_000 as Weight).saturating_mul(l as Weight)) + (101_568_000 as Weight) + // Standard Error: 2_000 + .saturating_add((66_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(9 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -699,14 +699,15 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 68_000 - .saturating_add((33_495_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 69_000 + .saturating_add((29_939_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) .saturating_add(RocksDbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:1) // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) @@ -715,14 +716,13 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (100_178_000 as Weight) + (96_886_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_358_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(11 as Weight)) + .saturating_add((1_790_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } @@ -746,10 +746,10 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 860_000 - .saturating_add((298_721_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 873_000 + .saturating_add((286_141_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 43_000 - .saturating_add((49_427_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((44_712_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -767,12 +767,10 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 91_000 - .saturating_add((26_605_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 91_000 - .saturating_add((31_481_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 3_122_000 - .saturating_add((16_672_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 87_000 + .saturating_add((24_049_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 87_000 + .saturating_add((27_514_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(204 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -781,19 +779,20 @@ impl WeightInfo for () { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 34_000 - .saturating_add((10_558_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 32_000 + .saturating_add((10_128_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } + // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) // Storage: Staking MaxValidatorsCount (r:0 w:1) // Storage: Staking ChillThreshold (r:0 w:1) // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) - fn set_staking_limits() -> Weight { - (6_353_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + fn set_staking_configs() -> Weight { + (6_187_000 as Weight) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking ChillThreshold (r:1 w:0) @@ -806,7 +805,7 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (83_389_000 as Weight) + (78_282_000 as Weight) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index f388c19de6b43..783b331b33532 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -833,6 +833,16 @@ macro_rules! implement_per_thing { } } + impl $crate::traits::Zero for $name { + fn zero() -> Self { + Self::zero() + } + + fn is_zero(&self) -> bool { + self == &Self::zero() + } + } + #[cfg(test)] mod $test_mod { From 40f24836121ed5574696efe37cdc4bdf4ecbff70 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 3 Dec 2021 01:17:23 +0200 Subject: [PATCH 0295/1472] Account for transaction priority when enforcing limits (#10388) * Account for transaction priority when enforcing limits * Improve `enforce_limits` comment * Explanation comment on why comparison impl is not used for limit enforcement --- .../transaction-pool/src/graph/base_pool.rs | 44 +++++++----- client/transaction-pool/src/graph/pool.rs | 70 ++++++++++++++++++- 2 files changed, 97 insertions(+), 17 deletions(-) diff --git a/client/transaction-pool/src/graph/base_pool.rs b/client/transaction-pool/src/graph/base_pool.rs index 2c8becdfb2f0b..cf634c3213a84 100644 --- a/client/transaction-pool/src/graph/base_pool.rs +++ b/client/transaction-pool/src/graph/base_pool.rs @@ -20,7 +20,7 @@ //! //! For a more full-featured pool, have a look at the `pool` module. -use std::{collections::HashSet, fmt, hash, sync::Arc}; +use std::{cmp::Ordering, collections::HashSet, fmt, hash, sync::Arc}; use log::{debug, trace, warn}; use sc_transaction_pool_api::{error, InPoolTransaction, PoolStatus}; @@ -36,7 +36,7 @@ use sp_runtime::{ use super::{ future::{FutureTransactions, WaitingTransaction}, - ready::{BestIterator, ReadyTransactions}, + ready::{BestIterator, ReadyTransactions, TransactionRef}, }; /// Successful import result. @@ -384,8 +384,8 @@ impl BasePool BasePool, _>(|worst, current| { let transaction = ¤t.transaction; - match minimal { - None => Some(transaction.clone()), - Some(ref tx) if tx.insertion_id > transaction.insertion_id => - Some(transaction.clone()), - other => other, - } + worst + .map(|worst| { + // Here we don't use `TransactionRef`'s ordering implementation because + // while it prefers priority like need here, it also prefers older + // transactions for inclusion purposes and limit enforcement needs to prefer + // newer transactions instead and drop the older ones. + match worst.transaction.priority.cmp(&transaction.transaction.priority) { + Ordering::Less => worst, + Ordering::Equal => + if worst.insertion_id > transaction.insertion_id { + transaction.clone() + } else { + worst + }, + Ordering::Greater => transaction.clone(), + } + }) + .or_else(|| Some(transaction.clone())) }); - if let Some(minimal) = minimal { - removed.append(&mut self.remove_subtree(&[minimal.transaction.hash.clone()])) + if let Some(worst) = worst { + removed.append(&mut self.remove_subtree(&[worst.transaction.hash.clone()])) } else { break } @@ -414,14 +426,14 @@ impl BasePool Some(current.clone()), Some(ref tx) if tx.imported_at > current.imported_at => Some(current.clone()), other => other, }); - if let Some(minimal) = minimal { - removed.append(&mut self.remove_subtree(&[minimal.transaction.hash.clone()])) + if let Some(worst) = worst { + removed.append(&mut self.remove_subtree(&[worst.transaction.hash.clone()])) } else { break } diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 2af5a8a19a5a9..af46dbad0ee53 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -539,6 +539,13 @@ mod tests { longevity: 9001, propagate: false, }), + Extrinsic::Store(_) => Ok(ValidTransaction { + priority: 9001, + requires: vec![], + provides: vec![vec![43]], + longevity: 9001, + propagate: false, + }), _ => unimplemented!(), }; @@ -1044,7 +1051,7 @@ mod tests { } #[test] - fn should_trigger_dropped() { + fn should_trigger_dropped_older() { // given let limit = Limit { count: 1, total_bytes: 1000 }; let options = @@ -1077,6 +1084,67 @@ mod tests { assert_eq!(stream.next(), Some(TransactionStatus::Dropped)); } + #[test] + fn should_trigger_dropped_lower_priority() { + { + // given + let limit = Limit { count: 1, total_bytes: 1000 }; + let options = + Options { ready: limit.clone(), future: limit.clone(), ..Default::default() }; + + let pool = Pool::new(options, true.into(), TestApi::default().into()); + + let xt = Extrinsic::IncludeData(Vec::new()); + block_on(pool.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap(); + assert_eq!(pool.validated_pool().status().ready, 1); + + // then + let xt = uxt(Transfer { + from: AccountId::from_h256(H256::from_low_u64_be(2)), + to: AccountId::from_h256(H256::from_low_u64_be(1)), + amount: 4, + nonce: 1, + }); + let result = block_on(pool.submit_one(&BlockId::Number(1), SOURCE, xt)); + assert!(matches!( + result, + Err(sc_transaction_pool_api::error::Error::ImmediatelyDropped) + )); + } + { + // given + let limit = Limit { count: 2, total_bytes: 1000 }; + let options = + Options { ready: limit.clone(), future: limit.clone(), ..Default::default() }; + + let pool = Pool::new(options, true.into(), TestApi::default().into()); + + let xt = Extrinsic::IncludeData(Vec::new()); + block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, xt)).unwrap(); + assert_eq!(pool.validated_pool().status().ready, 1); + + let xt = uxt(Transfer { + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }); + let watcher = + block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, xt)).unwrap(); + assert_eq!(pool.validated_pool().status().ready, 2); + + // when + let xt = Extrinsic::Store(Vec::new()); + block_on(pool.submit_one(&BlockId::Number(1), SOURCE, xt)).unwrap(); + assert_eq!(pool.validated_pool().status().ready, 2); + + // then + let mut stream = futures::executor::block_on_stream(watcher.into_stream()); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::Dropped)); + } + } + #[test] fn should_handle_pruning_in_the_middle_of_import() { // given From b6d489ed3015646e0cd65861ec9381a44de76985 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Fri, 3 Dec 2021 14:58:12 +0900 Subject: [PATCH 0296/1472] Fix pallet bags list and doc (#10231) * fix bags list * improve doc * doc * inner doc * fix test * Update docs in frame/election-provider-support/src/lib.rs * fix staking impl * prepend unsafe to clear and regenerate * fix test Co-authored-by: Keith Yeung Co-authored-by: Shawn Tabrizi --- frame/bags-list/remote-tests/src/migration.rs | 2 +- frame/bags-list/src/benchmarks.rs | 6 +++-- frame/bags-list/src/lib.rs | 16 +++++++++---- frame/bags-list/src/list/mod.rs | 23 +++++++++---------- frame/election-provider-support/src/lib.rs | 18 +++++++++++---- frame/staking/src/migrations.rs | 2 +- frame/staking/src/pallet/impls.rs | 17 ++++++-------- frame/staking/src/testing_utils.rs | 3 ++- frame/support/src/storage/mod.rs | 6 ++++- .../support/src/storage/types/counted_map.rs | 15 ++++++------ frame/support/src/storage/types/double_map.rs | 6 ++++- frame/support/src/storage/types/map.rs | 6 ++++- primitives/io/src/lib.rs | 6 ++--- 13 files changed, 76 insertions(+), 50 deletions(-) diff --git a/frame/bags-list/remote-tests/src/migration.rs b/frame/bags-list/remote-tests/src/migration.rs index 86595c7feba9d..aadbbdae3d61b 100644 --- a/frame/bags-list/remote-tests/src/migration.rs +++ b/frame/bags-list/remote-tests/src/migration.rs @@ -47,7 +47,7 @@ pub async fn execute( log::info!(target: LOG_TARGET, "Nominator count: {}", pre_migrate_nominator_count); // run the actual migration, - let moved = ::SortedListProvider::regenerate( + let moved = ::SortedListProvider::unsafe_regenerate( pallet_staking::Nominators::::iter().map(|(n, _)| n), pallet_staking::Pallet::::weight_of_fn(), ); diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index d86adc674c44a..800e668324e0c 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -35,7 +35,8 @@ frame_benchmarking::benchmarks! { // node in the destination in addition to the work we do otherwise. (2 W/R) // clear any pre-existing storage. - List::::clear(None); + // NOTE: safe to call outside block production + List::::unsafe_clear(); // define our origin and destination thresholds. let origin_bag_thresh = T::BagThresholds::get()[0]; @@ -94,7 +95,8 @@ frame_benchmarking::benchmarks! { // node in the destination in addition to the work we do otherwise. (2 W/R) // clear any pre-existing storage. - List::::clear(None); + // NOTE: safe to call outside block production + List::::unsafe_clear(); // define our origin and destination thresholds. let origin_bag_thresh = T::BagThresholds::get()[0]; diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 2cff68b54c9c7..d3be2c29533f9 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -26,7 +26,7 @@ //! the weights of accounts via [`frame_election_provider_support::VoteWeightProvider`]. //! //! This pallet is not configurable at genesis. Whoever uses it should call appropriate functions of -//! the `SortedListProvider` (e.g. `on_insert`, or `regenerate`) at their genesis. +//! the `SortedListProvider` (e.g. `on_insert`, or `unsafe_regenerate`) at their genesis. //! //! # Goals //! @@ -256,11 +256,14 @@ impl SortedListProvider for Pallet { List::::remove(id) } - fn regenerate( + fn unsafe_regenerate( all: impl IntoIterator, weight_of: Box VoteWeight>, ) -> u32 { - List::::regenerate(all, weight_of) + // NOTE: This call is unsafe for the same reason as SortedListProvider::unsafe_regenerate. + // I.e. because it can lead to many storage accesses. + // So it is ok to call it as caller must ensure the conditions. + List::::unsafe_regenerate(all, weight_of) } #[cfg(feature = "std")] @@ -273,8 +276,11 @@ impl SortedListProvider for Pallet { Ok(()) } - fn clear(maybe_count: Option) -> u32 { - List::::clear(maybe_count) + fn unsafe_clear() { + // NOTE: This call is unsafe for the same reason as SortedListProvider::unsafe_clear. + // I.e. because it can lead to many storage accesses. + // So it is ok to call it as caller must ensure the conditions. + List::::unsafe_clear() } #[cfg(feature = "runtime-benchmarks")] diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index b381b36dc9ee2..1ec4996c26fd3 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -76,19 +76,15 @@ pub fn notional_bag_for(weight: VoteWeight) -> VoteWeight { pub struct List(PhantomData); impl List { - /// Remove all data associated with the list from storage. Parameter `items` is the number of - /// items to clear from the list. + /// Remove all data associated with the list from storage. /// /// ## WARNING /// - /// `None` will clear all items and should generally not be used in production as it could lead - /// to a very large number of storage accesses. - pub(crate) fn clear(maybe_count: Option) -> u32 { - crate::ListBags::::remove_all(maybe_count); - let pre = crate::ListNodes::::count(); - crate::ListNodes::::remove_all(maybe_count); - let post = crate::ListNodes::::count(); - pre.saturating_sub(post) + /// this function should generally not be used in production as it could lead to a very large + /// number of storage accesses. + pub(crate) fn unsafe_clear() { + crate::ListBags::::remove_all(None); + crate::ListNodes::::remove_all(); } /// Regenerate all of the data from the given ids. @@ -100,11 +96,14 @@ impl List { /// pallet using this `List`. /// /// Returns the number of ids migrated. - pub fn regenerate( + pub fn unsafe_regenerate( all: impl IntoIterator, weight_of: Box VoteWeight>, ) -> u32 { - Self::clear(None); + // NOTE: This call is unsafe for the same reason as SortedListProvider::unsafe_regenerate. + // I.e. because it can lead to many storage accesses. + // So it is ok to call it as caller must ensure the conditions. + Self::unsafe_clear(); Self::insert_many(all, weight_of) } diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 472584ed2506b..ac3bfccbbdb54 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -333,15 +333,23 @@ pub trait SortedListProvider { /// Regenerate this list from scratch. Returns the count of items inserted. /// /// This should typically only be used at a runtime upgrade. - fn regenerate( + /// + /// ## WARNING + /// + /// This function should be called with care, regenerate will remove the current list write the + /// new list, which can lead to too many storage accesses, exhausting the block weight. + fn unsafe_regenerate( all: impl IntoIterator, weight_of: Box VoteWeight>, ) -> u32; - /// Remove `maybe_count` number of items from the list. Returns the number of items actually - /// removed. WARNING: removes all items if `maybe_count` is `None`, which should never be done - /// in production settings because it can lead to an unbounded amount of storage accesses. - fn clear(maybe_count: Option) -> u32; + /// Remove all items from the list. + /// + /// ## WARNING + /// + /// This function should never be called in production settings because it can lead to an + /// unbounded amount of storage accesses. + fn unsafe_clear(); /// Sanity check internal state of list. Only meant for debug compilation. fn sanity_check() -> Result<(), &'static str>; diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 7064f06dd12c7..6f1d3953f8f17 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -40,7 +40,7 @@ pub mod v8 { if StorageVersion::::get() == crate::Releases::V7_0_0 { crate::log!(info, "migrating staking to Releases::V8_0_0"); - let migrated = T::SortedListProvider::regenerate( + let migrated = T::SortedListProvider::unsafe_regenerate( Nominators::::iter().map(|(id, _)| id), Pallet::::weight_of_fn(), ); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 8d86cfbe6b0d6..cd26ff3b729c5 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -971,7 +971,7 @@ impl ElectionDataProvider> for Pallet >::remove_all(None); >::kill(); >::kill(); - let _ = T::SortedListProvider::clear(None); + T::SortedListProvider::unsafe_clear(); } #[cfg(feature = "runtime-benchmarks")] @@ -1299,7 +1299,7 @@ impl SortedListProvider for UseNominatorsMap { fn on_remove(_: &T::AccountId) { // nothing to do on remove. } - fn regenerate( + fn unsafe_regenerate( _: impl IntoIterator, _: Box VoteWeight>, ) -> u32 { @@ -1309,13 +1309,10 @@ impl SortedListProvider for UseNominatorsMap { fn sanity_check() -> Result<(), &'static str> { Ok(()) } - fn clear(maybe_count: Option) -> u32 { - Nominators::::remove_all(maybe_count); - if let Some(count) = maybe_count { - CounterForNominators::::mutate(|noms| *noms - count); - count - } else { - CounterForNominators::::take() - } + fn unsafe_clear() { + // NOTE: Caller must ensure this doesn't lead to too many storage accesses. This is a + // condition of SortedListProvider::unsafe_clear. + Nominators::::remove_all(None); + CounterForNominators::::take(); } } diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 13762cf5886db..611773fc0ccf2 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -42,7 +42,8 @@ pub fn clear_validators_and_nominators() { // whenever we touch nominators counter we should update `T::SortedListProvider` as well. Nominators::::remove_all(None); CounterForNominators::::kill(); - let _ = T::SortedListProvider::clear(None); + // NOTE: safe to call outside block production + T::SortedListProvider::unsafe_clear(); } /// Grab a funded user. diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 81f98f2c23d48..9217cf4e6d9e4 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -1133,7 +1133,11 @@ pub trait StoragePrefixedMap { crate::storage::storage_prefix(Self::module_prefix(), Self::storage_prefix()) } - /// Remove all value of the storage. + /// Remove all values of the storage in the overlay and up to `limit` in the backend. + /// + /// All values in the client overlay will be deleted, if there is some `limit` then up to + /// `limit` values are deleted from the client backend, if `limit` is none then all values in + /// the client backend are deleted. fn remove_all(limit: Option) -> sp_io::KillStorageResult { sp_io::storage::clear_prefix(&Self::final_prefix(), limit) } diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 51edf10890267..5211453fd09b4 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -31,7 +31,6 @@ use crate::{ Never, }; use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen, Ref}; -use sp_arithmetic::traits::Bounded; use sp_runtime::traits::Saturating; use sp_std::prelude::*; @@ -263,10 +262,12 @@ where } /// Remove all value of the storage. - pub fn remove_all(maybe_limit: Option) { - let leftover = Self::count().saturating_sub(maybe_limit.unwrap_or_else(Bounded::max_value)); - CounterFor::::set(leftover); - ::Map::remove_all(maybe_limit); + pub fn remove_all() { + // NOTE: it is not possible to remove up to some limit because + // `sp_io::storage::clear_prefix` and `StorageMap::remove_all` don't give the number of + // value removed from the overlay. + CounterFor::::set(0u32); + ::Map::remove_all(None); } /// Iter over all value of the storage. @@ -678,7 +679,7 @@ mod test { assert_eq!(A::count(), 2); // Remove all. - A::remove_all(None); + A::remove_all(); assert_eq!(A::count(), 0); assert_eq!(A::initialize_counter(), 0); @@ -909,7 +910,7 @@ mod test { assert_eq!(B::count(), 2); // Remove all. - B::remove_all(None); + B::remove_all(); assert_eq!(B::count(), 0); assert_eq!(B::initialize_counter(), 0); diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index b9af4a621b92a..d3595814d04b0 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -335,7 +335,11 @@ where >(key1, key2) } - /// Remove all value of the storage. + /// Remove all values of the storage in the overlay and up to `limit` in the backend. + /// + /// All values in the client overlay will be deleted, if there is some `limit` then up to + /// `limit` values are deleted from the client backend, if `limit` is none then all values in + /// the client backend are deleted. pub fn remove_all(limit: Option) -> sp_io::KillStorageResult { >::remove_all(limit) } diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 45340f9015eaa..6532d47cfec67 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -234,7 +234,11 @@ where >::migrate_key::(key) } - /// Remove all value of the storage. + /// Remove all values of the storage in the overlay and up to `limit` in the backend. + /// + /// All values in the client overlay will be deleted, if there is some `limit` then up to + /// `limit` values are deleted from the client backend, if `limit` is none then all values in + /// the client backend are deleted. pub fn remove_all(limit: Option) -> sp_io::KillStorageResult { >::remove_all(limit) } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index e4f52fd4e0e21..94ae1a8f70838 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -88,12 +88,12 @@ pub enum EcdsaVerifyError { } /// The outcome of calling `storage_kill`. Returned value is the number of storage items -/// removed from the trie from making the `storage_kill` call. +/// removed from the backend from making the `storage_kill` call. #[derive(PassByCodec, Encode, Decode)] pub enum KillStorageResult { - /// No key remains in the child trie. + /// All key to remove were removed, return number of key removed from backend. AllRemoved(u32), - /// At least one key still resides in the child trie due to the supplied limit. + /// Not all key to remove were removed, return number of key removed from backend. SomeRemaining(u32), } From 3d005a3eaa968e4dc58407a1369a8d670c9a35df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 3 Dec 2021 11:29:51 +0100 Subject: [PATCH 0297/1472] wasm-override: Support checking `spec_name` (#10380) This adds support to the wasm-override feature to compare the spec_name. If the spec_name doesn't match, a warning will be printed and the override will be ignored. --- client/service/src/client/call_executor.rs | 15 ++- client/service/src/client/wasm_override.rs | 125 ++++++++++++++++----- primitives/runtime/src/runtime_string.rs | 12 ++ 3 files changed, 118 insertions(+), 34 deletions(-) diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index be871cc371ed5..7d15ce4704ab4 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -38,7 +38,7 @@ use std::{cell::RefCell, panic::UnwindSafe, result, sync::Arc}; pub struct LocalCallExecutor { backend: Arc, executor: E, - wasm_override: Option, + wasm_override: Arc>, wasm_substitutes: WasmSubstitutes, spawn_handle: Box, client_config: ClientConfig, @@ -71,7 +71,7 @@ where Ok(LocalCallExecutor { backend, executor, - wasm_override, + wasm_override: Arc::new(wasm_override), spawn_handle, client_config, wasm_substitutes, @@ -90,16 +90,19 @@ where Block: BlockT, B: backend::Backend, { - let spec = self.runtime_version(id)?.spec_version; + let spec = self.runtime_version(id)?; let code = if let Some(d) = self .wasm_override .as_ref() - .map(|o| o.get(&spec, onchain_code.heap_pages)) + .as_ref() + .map(|o| o.get(&spec.spec_version, onchain_code.heap_pages, &spec.spec_name)) .flatten() { log::debug!(target: "wasm_overrides", "using WASM override for block {}", id); d - } else if let Some(s) = self.wasm_substitutes.get(spec, onchain_code.heap_pages, id) { + } else if let Some(s) = + self.wasm_substitutes.get(spec.spec_version, onchain_code.heap_pages, id) + { log::debug!(target: "wasm_substitutes", "Using WASM substitute for block {:?}", id); s } else { @@ -395,7 +398,7 @@ mod tests { let call_executor = LocalCallExecutor { backend: backend.clone(), executor: executor.clone(), - wasm_override: Some(overrides), + wasm_override: Arc::new(Some(overrides)), spawn_handle: Box::new(TaskExecutor::new()), client_config, wasm_substitutes: WasmSubstitutes::new( diff --git a/client/service/src/client/wasm_override.rs b/client/service/src/client/wasm_override.rs index 3d28467a9cbd9..ba3f2855fc7a5 100644 --- a/client/service/src/client/wasm_override.rs +++ b/client/service/src/client/wasm_override.rs @@ -35,9 +35,10 @@ //! A custom WASM blob will override on-chain WASM if the spec version matches. If it is //! required to overrides multiple runtimes, multiple WASM blobs matching each of the spec versions //! needed must be provided in the given directory. + use sc_executor::RuntimeVersionOf; use sp_blockchain::Result; -use sp_core::traits::{FetchRuntimeCode, RuntimeCode}; +use sp_core::traits::{FetchRuntimeCode, RuntimeCode, WrappedRuntimeCode}; use sp_state_machine::BasicExternalities; use sp_version::RuntimeVersion; use std::{ @@ -45,19 +46,32 @@ use std::{ fs, hash::Hasher as _, path::{Path, PathBuf}, + time::{Duration, Instant}, }; -#[derive(Clone, Debug, PartialEq)] +/// The interval in that we will print a warning when a wasm blob `spec_name` +/// doesn't match with the on-chain `spec_name`. +const WARN_INTERVAL: Duration = Duration::from_secs(30); + /// Auxiliary structure that holds a wasm blob and its hash. +#[derive(Debug)] struct WasmBlob { + /// The actual wasm blob, aka the code. code: Vec, + /// The hash of [`Self::code`]. hash: Vec, + /// The path where this blob was found. + path: PathBuf, + /// The `spec_name` found in the runtime version of this blob. + spec_name: String, + /// When was the last time we have warned about the wasm blob having + /// a wrong `spec_name`? + last_warn: parking_lot::Mutex>, } impl WasmBlob { - fn new(code: Vec) -> Self { - let hash = make_hash(&code); - Self { code, hash } + fn new(code: Vec, hash: Vec, path: PathBuf, spec_name: String) -> Self { + Self { code, hash, path, spec_name, last_warn: Default::default() } } fn runtime_code(&self, heap_pages: Option) -> RuntimeCode { @@ -103,7 +117,7 @@ impl From for sp_blockchain::Error { /// Scrapes WASM from a folder and returns WASM from that folder /// if the runtime spec version matches. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct WasmOverride { // Map of runtime spec version -> Wasm Blob overrides: HashMap, @@ -122,8 +136,35 @@ impl WasmOverride { /// Gets an override by it's runtime spec version. /// /// Returns `None` if an override for a spec version does not exist. - pub fn get<'a, 'b: 'a>(&'b self, spec: &u32, pages: Option) -> Option> { - self.overrides.get(spec).map(|w| w.runtime_code(pages)) + pub fn get<'a, 'b: 'a>( + &'b self, + spec: &u32, + pages: Option, + spec_name: &str, + ) -> Option> { + self.overrides.get(spec).and_then(|w| { + if spec_name == w.spec_name { + Some(w.runtime_code(pages)) + } else { + let mut last_warn = w.last_warn.lock(); + let now = Instant::now(); + + if last_warn.map_or(true, |l| l + WARN_INTERVAL <= now) { + *last_warn = Some(now); + + tracing::warn!( + target = "wasm_overrides", + on_chain_spec_name = %spec_name, + override_spec_name = %w.spec_name, + spec_version = %spec, + wasm_file = %w.path.display(), + "On chain and override `spec_name` do not match! Ignoring override.", + ); + } + + None + } + }) } /// Scrapes a folder for WASM runtimes. @@ -147,22 +188,29 @@ impl WasmOverride { let path = entry.path(); match path.extension().map(|e| e.to_str()).flatten() { Some("wasm") => { - let wasm = WasmBlob::new(fs::read(&path).map_err(handle_err)?); - let version = Self::runtime_version(executor, &wasm, Some(128))?; - log::info!( + let code = fs::read(&path).map_err(handle_err)?; + let code_hash = make_hash(&code); + let version = Self::runtime_version(executor, &code, &code_hash, Some(128))?; + + tracing::info!( target: "wasm_overrides", - "Found wasm override in file: `{:?}`, version: {}", - path.to_str(), - version, + version = %version, + file = %path.display(), + "Found wasm override.", ); - if let Some(_duplicate) = overrides.insert(version.spec_version, wasm) { - log::info!( + + let wasm = + WasmBlob::new(code, code_hash, path.clone(), version.spec_name.to_string()); + + if let Some(other) = overrides.insert(version.spec_version, wasm) { + tracing::info!( target: "wasm_overrides", - "Found duplicate spec version for runtime in file: `{:?}`, version: {}", - path.to_str(), - version, + first = %other.path.display(), + second = %path.display(), + %version, + "Found duplicate spec version for runtime.", ); - duplicates.push(format!("{}", path.display())); + duplicates.push(path.display().to_string()); } }, _ => (), @@ -178,7 +226,8 @@ impl WasmOverride { fn runtime_version( executor: &E, - code: &WasmBlob, + code: &[u8], + code_hash: &[u8], heap_pages: Option, ) -> Result where @@ -186,7 +235,14 @@ impl WasmOverride { { let mut ext = BasicExternalities::default(); executor - .runtime_version(&mut ext, &code.runtime_code(heap_pages)) + .runtime_version( + &mut ext, + &RuntimeCode { + code_fetcher: &WrappedRuntimeCode(code.into()), + heap_pages, + hash: code_hash.into(), + }, + ) .map_err(|e| WasmOverrideError::VersionInvalid(format!("{:?}", e)).into()) } } @@ -195,9 +251,18 @@ impl WasmOverride { #[cfg(test)] pub fn dummy_overrides() -> WasmOverride { let mut overrides = HashMap::new(); - overrides.insert(0, WasmBlob::new(vec![0, 0, 0, 0, 0, 0, 0, 0])); - overrides.insert(1, WasmBlob::new(vec![1, 1, 1, 1, 1, 1, 1, 1])); - overrides.insert(2, WasmBlob::new(vec![2, 2, 2, 2, 2, 2, 2, 2])); + overrides.insert( + 0, + WasmBlob::new(vec![0, 0, 0, 0, 0, 0, 0, 0], vec![0], PathBuf::new(), "test".into()), + ); + overrides.insert( + 1, + WasmBlob::new(vec![1, 1, 1, 1, 1, 1, 1, 1], vec![1], PathBuf::new(), "test".into()), + ); + overrides.insert( + 2, + WasmBlob::new(vec![2, 2, 2, 2, 2, 2, 2, 2], vec![2], PathBuf::new(), "test".into()), + ); WasmOverride { overrides } } @@ -226,15 +291,19 @@ mod tests { #[test] fn should_get_runtime_version() { - let wasm = WasmBlob::new(substrate_test_runtime::wasm_binary_unwrap().to_vec()); let executor = NativeElseWasmExecutor::::new( WasmExecutionMethod::Interpreted, Some(128), 1, ); - let version = WasmOverride::runtime_version(&executor, &wasm, Some(128)) - .expect("should get the `RuntimeVersion` of the test-runtime wasm blob"); + let version = WasmOverride::runtime_version( + &executor, + substrate_test_runtime::wasm_binary_unwrap(), + &[1], + Some(128), + ) + .expect("should get the `RuntimeVersion` of the test-runtime wasm blob"); assert_eq!(version.spec_version, 2); } diff --git a/primitives/runtime/src/runtime_string.rs b/primitives/runtime/src/runtime_string.rs index 179e881451813..a69e85418d82a 100644 --- a/primitives/runtime/src/runtime_string.rs +++ b/primitives/runtime/src/runtime_string.rs @@ -92,6 +92,18 @@ impl AsRef<[u8]> for RuntimeString { } } +#[cfg(feature = "std")] +impl std::ops::Deref for RuntimeString { + type Target = str; + + fn deref(&self) -> &str { + match self { + Self::Borrowed(val) => &val, + Self::Owned(val) => &val, + } + } +} + impl Encode for RuntimeString { fn encode(&self) -> Vec { match self { From 205069d0540973362902aa2ad68af924bfdf2a3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 3 Dec 2021 16:11:06 +0100 Subject: [PATCH 0298/1472] Fix cumulus companion checks (#10412) * Fix cumulus companion checks * Add missing tag * Fix * Update .gitlab-ci.yml Co-authored-by: Denis Pisarev <17856421+TriplEight@users.noreply.github.com> Co-authored-by: Shawn Tabrizi Co-authored-by: Denis Pisarev <17856421+TriplEight@users.noreply.github.com> --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b1987b834fef0..f4391cf7d312c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,6 +46,7 @@ variables: &default-vars VAULT_AUTH_PATH: "gitlab-parity-io-jwt" VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" SIMNET_FEATURES_PATH: "simnet_tests/tests" + PIPELINE_SCRIPTS_TAG: "v0.4" default: cache: {} @@ -606,6 +607,7 @@ cargo-check-macos: --substrate "$DEPENDENT_REPO" "$GITHUB_PR_TOKEN" + "$CARGO_UPDATE_CRATES" # Individual jobs are set up for each dependent project so that they can be ran in parallel. # Arguably we could generate a job for each companion in the PR's description using Gitlab's @@ -615,11 +617,13 @@ check-dependent-polkadot: <<: *check-dependent-project variables: DEPENDENT_REPO: polkadot + CARGO_UPDATE_CRATES: "sp-io" check-dependent-cumulus: <<: *check-dependent-project variables: DEPENDENT_REPO: cumulus + CARGO_UPDATE_CRATES: "sp-io polkadot-runtime-common" build-linux-substrate: From a2f24d5d721e158a8aefa50c6022ee9acfeeb975 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 3 Dec 2021 19:50:23 +0100 Subject: [PATCH 0299/1472] No longer include :code and :heappages in execution proofs (#10419) * No longer include :code and :heap_pages in execution proofs * Oops, forgot the line * Rustfmt --- client/service/src/client/client.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index b46c6b99b9a9c..833d8b7bc2257 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1085,18 +1085,7 @@ where method: &str, call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)> { - // Make sure we include the `:code` and `:heap_pages` in the execution proof to be - // backwards compatible. - // - // TODO: Remove when solved: https://github.com/paritytech/substrate/issues/5047 - let code_proof = self.read_proof( - id, - &mut [well_known_keys::CODE, well_known_keys::HEAP_PAGES].iter().map(|v| *v), - )?; - - self.executor - .prove_execution(id, method, call_data) - .map(|(r, p)| (r, StorageProof::merge(vec![p, code_proof]))) + self.executor.prove_execution(id, method, call_data) } fn read_proof_collection( From e9ebf0c00fde8657a3a5989ad099e6272427ddd2 Mon Sep 17 00:00:00 2001 From: Devdutt Shenoi Date: Sat, 4 Dec 2021 03:18:11 +0530 Subject: [PATCH 0300/1472] Optimize encoded-size of `SignedCommitment` (#10409) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Include code from paritytech/grandpa-bridge-gadget#186 * Cargo fmt commitment.rs * Make changes suggested by @tomusdrw Co-authored-by: Tomasz Drwięga --- primitives/beefy/src/commitment.rs | 212 ++++++++++++++++++++++++++++- 1 file changed, 205 insertions(+), 7 deletions(-) diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index 667c03cc2284c..6553f6ffc905f 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use codec::{Decode, Encode}; +use codec::{Decode, Encode, Error, Input}; use sp_std::{cmp, prelude::*}; use crate::{crypto::Signature, ValidatorSetId}; @@ -80,7 +80,7 @@ impl Payload { /// height [block_number](Commitment::block_number). /// GRANDPA validators collect signatures on commitments and a stream of such signed commitments /// (see [SignedCommitment]) forms the BEEFY protocol. -#[derive(Clone, Debug, PartialEq, Eq, codec::Encode, codec::Decode)] +#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] pub struct Commitment { /// A collection of payloads to be signed, see [`Payload`] for details. /// @@ -134,7 +134,11 @@ where } /// A commitment with matching GRANDPA validators' signatures. -#[derive(Clone, Debug, PartialEq, Eq, codec::Encode, codec::Decode)] +/// +/// Note that SCALE-encoding of the structure is optimized for size efficiency over the wire, +/// please take a look at custom [`Encode`] and [`Decode`] implementations and +/// [`CompactSignedCommitment`] struct. +#[derive(Clone, Debug, PartialEq, Eq)] pub struct SignedCommitment { /// The commitment signatures are collected for. pub commitment: Commitment, @@ -152,6 +156,126 @@ impl SignedCommitment { } } +/// Type to be used to denote placement of signatures +type BitField = Vec; +/// Compress 8 bit values into a single u8 Byte +const CONTAINER_BIT_SIZE: usize = 8; + +/// Compressed representation of [`SignedCommitment`], used for encoding efficiency. +#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] +struct CompactSignedCommitment { + /// The commitment, unchanged compared to regular [`SignedCommitment`]. + commitment: TCommitment, + /// A bitfield representing presence of a signature coming from a validator at some index. + /// + /// The bit at index `0` is set to `1` in case we have a signature coming from a validator at + /// index `0` in in the original validator set. In case the [`SignedCommitment`] does not + /// contain that signature the `bit` will be set to `0`. Bits are packed into `Vec` + signatures_from: BitField, + /// Number of validators in the Validator Set and hence number of significant bits in the + /// [`signatures_from`] collection. + /// + /// Note this might be smaller than the size of `signatures_compact` in case some signatures + /// are missing. + validator_set_len: u32, + /// A `Vec` containing all `Signature`s present in the original [`SignedCommitment`]. + /// + /// Note that in order to associate a `Signature` from this `Vec` with a validator, one needs + /// to look at the `signatures_from` bitfield, since some validators might have not produced a + /// signature. + signatures_compact: Vec, +} + +impl<'a, TBlockNumber> CompactSignedCommitment<&'a Commitment> { + /// Packs a `SignedCommitment` into the compressed `CompactSignedCommitment` format for + /// efficient network transport. + fn pack(signed_commitment: &'a SignedCommitment) -> Self { + let SignedCommitment { commitment, signatures } = signed_commitment; + let validator_set_len = signatures.len() as u32; + let mut signatures_from: BitField = vec![]; + let mut signatures_compact: Vec = vec![]; + + for signature in signatures { + match signature { + Some(value) => signatures_compact.push(value.clone()), + None => (), + } + } + + let mut bits: Vec = + signatures.iter().map(|x| if x.is_some() { 1 } else { 0 }).collect(); + + // Resize with excess bits for placement purposes + let excess_bits_len = + CONTAINER_BIT_SIZE - (validator_set_len as usize % CONTAINER_BIT_SIZE); + bits.resize(bits.len() + excess_bits_len, 0); + + let chunks = bits.chunks(CONTAINER_BIT_SIZE); + for chunk in chunks { + let mut iter = chunk.iter().copied(); + let mut v = iter.next().unwrap() as u8; + + for bit in iter { + v <<= 1; + v |= bit as u8; + } + + signatures_from.push(v); + } + + Self { commitment, signatures_from, validator_set_len, signatures_compact } + } + + /// Unpacks a `CompactSignedCommitment` into the uncompressed `SignedCommitment` form. + fn unpack( + temporary_signatures: CompactSignedCommitment>, + ) -> SignedCommitment { + let CompactSignedCommitment { + commitment, + signatures_from, + validator_set_len, + signatures_compact, + } = temporary_signatures; + let mut bits: Vec = vec![]; + + for block in signatures_from { + for bit in 0..CONTAINER_BIT_SIZE { + bits.push((block >> (CONTAINER_BIT_SIZE - bit - 1)) & 1); + } + } + + bits.truncate(validator_set_len as usize); + + let mut next_signature = signatures_compact.into_iter(); + let signatures: Vec> = bits + .iter() + .map(|&x| if x == 1 { next_signature.next() } else { None }) + .collect(); + + SignedCommitment { commitment, signatures } + } +} + +impl Encode for SignedCommitment +where + TBlockNumber: Encode, +{ + fn using_encoded R>(&self, f: F) -> R { + let temp = CompactSignedCommitment::pack(self); + temp.using_encoded(f) + } +} + +impl Decode for SignedCommitment +where + TBlockNumber: Decode, +{ + fn decode(input: &mut I) -> Result { + let temp = CompactSignedCommitment::decode(input)?; + Ok(CompactSignedCommitment::unpack(temp)) + } +} + /// A [SignedCommitment] with a version number. This variant will be appended /// to the block justifications for the block for which the signed commitment /// has been generated. @@ -244,10 +368,10 @@ mod tests { encoded, hex_literal::hex!( "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000 - 10000001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321 - f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a86cdd9aaa - cdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a - 0046395a71681be3d0c2a00" + 04300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746 + cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba012d6e1f8105c337a86cdd9a + aacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b + 6a0046395a71681be3d0c2a00" ) ); } @@ -322,4 +446,78 @@ mod tests { assert_eq!(decoded, Ok(versioned)); } + + #[test] + fn large_signed_commitment_encode_decode() { + // given + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let commitment: TestCommitment = + Commitment { payload, block_number: 5, validator_set_id: 0 }; + + let sigs = mock_signatures(); + + let signatures: Vec> = (0..1024) + .into_iter() + .map(|x| if x < 340 { None } else { Some(sigs.0.clone()) }) + .collect(); + let signed = SignedCommitment { commitment, signatures }; + + // when + let encoded = codec::Encode::encode(&signed); + let decoded = TestSignedCommitment::decode(&mut &*encoded); + + // then + assert_eq!(decoded, Ok(signed)); + assert_eq!( + encoded, + hex_literal::hex!( + "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000 + 05020000000000000000000000000000000000000000000000000000000000000000000000000000000 + 000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + fffffffffff0000040000b10a558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed + 4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad812 + 79df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d1 + 0dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2 + ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01 + 558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e9 + 9a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72 + d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bc + b7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc3 + 21f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc9855 + 80e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0 + c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da + 8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279d + f0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd + 3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac8 + 0a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558 + 455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a8 + 30e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d94 + 8d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb78 + 16f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f + 2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e + 4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33 + c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da848 + 0c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df07 + 95cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd + 68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a0 + 9abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455 + ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e + 314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1 + 107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f + 9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f231 + 9a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb + 75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86 + e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c7 + 46cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795c + c985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68c + e3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09ab + ed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad8 + 1279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314 + d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107 + b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba + 01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01" + ) + ); + } } From 6d09a45caf40a143791deab4f605b95230b787d1 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sat, 4 Dec 2021 07:11:25 +0100 Subject: [PATCH 0301/1472] allow try-runtime and `TestExternalities` to report PoV size (#10372) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * allow try-runtime and test-externalities to report proof size * self review * fix test * Fix humanized dispaly of bytes * Fix some test * Fix some review grumbles * last of the review comments * fmt * remove unused import * move test * fix import * Update primitives/state-machine/src/testing.rs Co-authored-by: Bastian Köcher * last touches * fix Co-authored-by: Bastian Köcher --- Cargo.lock | 2 + primitives/runtime/Cargo.toml | 1 + primitives/runtime/src/lib.rs | 47 ++ primitives/state-machine/src/lib.rs | 3 + .../state-machine/src/proving_backend.rs | 9 +- primitives/state-machine/src/testing.rs | 34 +- primitives/storage/src/lib.rs | 26 +- primitives/trie/src/storage_proof.rs | 6 +- utils/frame/remote-externalities/src/lib.rs | 561 +++++++++++++++--- .../test_data/{proxy_test => proxy_test.top} | Bin utils/frame/try-runtime/cli/Cargo.toml | 2 + .../cli/src/commands/execute_block.rs | 4 +- .../cli/src/commands/follow_chain.rs | 4 +- .../cli/src/commands/on_runtime_upgrade.rs | 4 +- utils/frame/try-runtime/cli/src/lib.rs | 102 +++- 15 files changed, 688 insertions(+), 117 deletions(-) rename utils/frame/remote-externalities/test_data/{proxy_test => proxy_test.top} (100%) diff --git a/Cargo.lock b/Cargo.lock index fbdf0297d4531..d277db3f519b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9650,6 +9650,7 @@ dependencies = [ "sp-std", "sp-tracing", "substrate-test-runtime-client", + "zstd", ] [[package]] @@ -10925,6 +10926,7 @@ dependencies = [ "sp-state-machine", "sp-version", "structopt", + "zstd", ] [[package]] diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 7966bb28255b7..511d3c1e37923 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -38,6 +38,7 @@ sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } sp-api = { version = "4.0.0-dev", path = "../api" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +zstd = "0.9" [features] bench = [] diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 80293fe734844..8cd15b51a32c3 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -916,9 +916,13 @@ impl TransactionOutcome { #[cfg(test)] mod tests { + use crate::traits::BlakeTwo256; + use super::*; use codec::{Decode, Encode}; use sp_core::crypto::Pair; + use sp_io::TestExternalities; + use sp_state_machine::create_proof_check_backend; #[test] fn opaque_extrinsic_serialization() { @@ -1019,4 +1023,47 @@ mod tests { panic!("Hey, I'm an error"); }); } + + #[test] + fn execute_and_generate_proof_works() { + use codec::Encode; + use sp_state_machine::Backend; + let mut ext = TestExternalities::default(); + + ext.insert(b"a".to_vec(), vec![1u8; 33]); + ext.insert(b"b".to_vec(), vec![2u8; 33]); + ext.insert(b"c".to_vec(), vec![3u8; 33]); + ext.insert(b"d".to_vec(), vec![4u8; 33]); + + let pre_root = ext.backend.root().clone(); + let (_, proof) = ext.execute_and_prove(|| { + sp_io::storage::get(b"a"); + sp_io::storage::get(b"b"); + sp_io::storage::get(b"v"); + sp_io::storage::get(b"d"); + }); + + let compact_proof = proof.clone().into_compact_proof::(pre_root).unwrap(); + let compressed_proof = zstd::stream::encode_all(&compact_proof.encode()[..], 0).unwrap(); + + // just an example of how you'd inspect the size of the proof. + println!("proof size: {:?}", proof.encoded_size()); + println!("compact proof size: {:?}", compact_proof.encoded_size()); + println!("zstd-compressed compact proof size: {:?}", &compressed_proof.len()); + + // create a new trie-backed from the proof and make sure it contains everything + let proof_check = create_proof_check_backend::(pre_root, proof).unwrap(); + assert_eq!(proof_check.storage(b"a",).unwrap().unwrap(), vec![1u8; 33]); + + let _ = ext.execute_and_prove(|| { + sp_io::storage::set(b"a", &vec![1u8; 44]); + }); + + // ensure that these changes are propagated to the backend. + + ext.execute_with(|| { + assert_eq!(sp_io::storage::get(b"a").unwrap(), vec![1u8; 44]); + assert_eq!(sp_io::storage::get(b"b").unwrap(), vec![2u8; 33]); + }); + } } diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index f7477e232bc66..e5c19f3bb0d57 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -188,6 +188,9 @@ mod execution { /// Trie backend with in-memory storage. pub type InMemoryBackend = TrieBackend, H>; + /// Proving Trie backend with in-memory storage. + pub type InMemoryProvingBackend<'a, H> = ProvingBackend<'a, MemoryDB, H>; + /// Strategy for executing a call into the runtime. #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum ExecutionStrategy { diff --git a/primitives/state-machine/src/proving_backend.rs b/primitives/state-machine/src/proving_backend.rs index 690266dab1e72..a354adaf697d6 100644 --- a/primitives/state-machine/src/proving_backend.rs +++ b/primitives/state-machine/src/proving_backend.rs @@ -221,6 +221,11 @@ where pub fn estimate_encoded_size(&self) -> usize { self.0.essence().backend_storage().proof_recorder.estimate_encoded_size() } + + /// Clear the proof recorded data. + pub fn clear_recorder(&self) { + self.0.essence().backend_storage().proof_recorder.reset() + } } impl<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> TrieBackendStorage @@ -358,7 +363,9 @@ where } } -/// Create proof check backend. +/// Create a backend used for checking the proof., using `H` as hasher. +/// +/// `proof` and `root` must match, i.e. `root` must be the correct root of `proof` nodes. pub fn create_proof_check_backend( root: H::Out, proof: StorageProof, diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index 59a0a5a6837ec..890137c43d881 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -23,8 +23,8 @@ use std::{ }; use crate::{ - backend::Backend, ext::Ext, InMemoryBackend, OverlayedChanges, StorageKey, - StorageTransactionCache, StorageValue, + backend::Backend, ext::Ext, InMemoryBackend, InMemoryProvingBackend, OverlayedChanges, + StorageKey, StorageTransactionCache, StorageValue, }; use hash_db::Hasher; @@ -38,6 +38,7 @@ use sp_core::{ traits::TaskExecutorExt, }; use sp_externalities::{Extension, ExtensionStore, Extensions}; +use sp_trie::StorageProof; /// Simple HashMap-based Externalities impl. pub struct TestExternalities @@ -122,6 +123,13 @@ where self.backend.insert(vec![(None, vec![(k, Some(v))])]); } + /// Insert key/value into backend. + /// + /// This only supports inserting keys in child tries. + pub fn insert_child(&mut self, c: sp_core::storage::ChildInfo, k: StorageKey, v: StorageValue) { + self.backend.insert(vec![(Some(c), vec![(k, Some(v))])]); + } + /// Registers the given extension for this instance. pub fn register_extension(&mut self, ext: E) { self.extensions.register(ext); @@ -171,9 +179,29 @@ where sp_externalities::set_and_run_with_externalities(&mut ext, execute) } + /// Execute the given closure while `self`, with `proving_backend` as backend, is set as + /// externalities. + /// + /// This implementation will wipe the proof recorded in between calls. Consecutive calls will + /// get their own proof from scratch. + pub fn execute_and_prove<'a, R>(&mut self, execute: impl FnOnce() -> R) -> (R, StorageProof) { + let proving_backend = InMemoryProvingBackend::new(&self.backend); + let mut proving_ext = Ext::new( + &mut self.overlay, + &mut self.storage_transaction_cache, + &proving_backend, + Some(&mut self.extensions), + ); + + let outcome = sp_externalities::set_and_run_with_externalities(&mut proving_ext, execute); + let proof = proving_backend.extract_proof(); + + (outcome, proof) + } + /// Execute the given closure while `self` is set as externalities. /// - /// Returns the result of the given closure, if no panics occured. + /// Returns the result of the given closure, if no panics occurred. /// Otherwise, returns `Err`. pub fn execute_with_safe( &mut self, diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index 1144e258e0e28..c655a9bdc1cf0 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -210,6 +210,14 @@ pub mod well_known_keys { /// Prefix of the default child storage keys in the top trie. pub const DEFAULT_CHILD_STORAGE_KEY_PREFIX: &'static [u8] = b":child_storage:default:"; + /// Whether a key is a default child storage key. + /// + /// This is convenience function which basically checks if the given `key` starts + /// with `DEFAULT_CHILD_STORAGE_KEY_PREFIX` and doesn't do anything apart from that. + pub fn is_default_child_storage_key(key: &[u8]) -> bool { + key.starts_with(DEFAULT_CHILD_STORAGE_KEY_PREFIX) + } + /// Whether a key is a child storage key. /// /// This is convenience function which basically checks if the given `key` starts @@ -231,7 +239,7 @@ pub mod well_known_keys { /// Information related to a child state. #[derive(Debug, Clone)] -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Hash, PartialOrd, Ord))] +#[cfg_attr(feature = "std", derive(PartialEq, Eq, Hash, PartialOrd, Ord, Encode, Decode))] pub enum ChildInfo { /// This is the one used by default. ParentKeyId(ChildTrieParentKeyId), @@ -370,16 +378,14 @@ impl ChildType { } /// A child trie of default type. -/// It uses the same default implementation as the top trie, -/// top trie being a child trie with no keyspace and no storage key. -/// Its keyspace is the variable (unprefixed) part of its storage key. -/// It shares its trie nodes backend storage with every other -/// child trie, so its storage key needs to be a unique id -/// that will be use only once. -/// Those unique id also required to be long enough to avoid any -/// unique id to be prefixed by an other unique id. +/// +/// It uses the same default implementation as the top trie, top trie being a child trie with no +/// keyspace and no storage key. Its keyspace is the variable (unprefixed) part of its storage key. +/// It shares its trie nodes backend storage with every other child trie, so its storage key needs +/// to be a unique id that will be use only once. Those unique id also required to be long enough to +/// avoid any unique id to be prefixed by an other unique id. #[derive(Debug, Clone)] -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Hash, PartialOrd, Ord))] +#[cfg_attr(feature = "std", derive(PartialEq, Eq, Hash, PartialOrd, Ord, Encode, Decode))] pub struct ChildTrieParentKeyId { /// Data is the storage key without prefix. data: Vec, diff --git a/primitives/trie/src/storage_proof.rs b/primitives/trie/src/storage_proof.rs index cfdb8566ea75f..91f2159f2957e 100644 --- a/primitives/trie/src/storage_proof.rs +++ b/primitives/trie/src/storage_proof.rs @@ -67,6 +67,7 @@ impl StorageProof { pub fn into_nodes(self) -> Vec> { self.trie_nodes } + /// Creates a `MemoryDB` from `Self`. pub fn into_memory_db(self) -> crate::MemoryDB { self.into() @@ -100,8 +101,9 @@ impl StorageProof { /// Returns the estimated encoded size of the compact proof. /// - /// Runing this operation is a slow operation (build the whole compact proof) and should only be - /// in non sensitive path. + /// Running this operation is a slow operation (build the whole compact proof) and should only + /// be in non sensitive path. + /// /// Return `None` on error. pub fn encoded_compact_size(self, root: H::Out) -> Option { let compact_proof = self.into_compact_proof::(root); diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index da715be6b4be4..e8453ddcd8f66 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -34,7 +34,10 @@ use serde::de::DeserializeOwned; use sp_core::{ hashing::twox_128, hexdisplay::HexDisplay, - storage::{StorageData, StorageKey}, + storage::{ + well_known_keys::{is_default_child_storage_key, DEFAULT_CHILD_STORAGE_KEY_PREFIX}, + ChildInfo, ChildType, PrefixedStorageKey, StorageData, StorageKey, + }, }; pub use sp_io::TestExternalities; use sp_runtime::traits::Block as BlockT; @@ -45,7 +48,9 @@ use std::{ pub mod rpc_api; -type KeyPair = (StorageKey, StorageData); +type KeyValue = (StorageKey, StorageData); +type TopKeyValues = Vec; +type ChildKeyValues = Vec<(ChildInfo, Vec)>; const LOG_TARGET: &str = "remote-ext"; const DEFAULT_TARGET: &str = "wss://rpc.polkadot.io:443"; @@ -53,6 +58,22 @@ const BATCH_SIZE: usize = 1000; #[rpc(client)] pub trait RpcApi { + #[method(name = "childstate_getKeys")] + fn child_get_keys( + &self, + child_key: PrefixedStorageKey, + prefix: StorageKey, + hash: Option, + ) -> Result, RpcError>; + + #[method(name = "childstate_getStorage")] + fn child_get_storage( + &self, + child_key: PrefixedStorageKey, + prefix: StorageKey, + hash: Option, + ) -> Result; + #[method(name = "state_getStorage")] fn get_storage(&self, prefix: StorageKey, hash: Option) -> Result; @@ -180,7 +201,7 @@ impl Default for SnapshotConfig { pub struct Builder { /// Custom key-pairs to be injected into the externalities. The *hashed* keys and values must /// be given. - hashed_key_values: Vec, + hashed_key_values: Vec, /// Storage entry key prefixes to be injected into the externalities. The *hashed* prefix must /// be given. hashed_prefixes: Vec>, @@ -234,21 +255,22 @@ impl Builder { ) -> Result { trace!(target: LOG_TARGET, "rpc: get_storage"); self.as_online().rpc_client().get_storage(key, maybe_at).await.map_err(|e| { - error!("Error = {:?}", e); + error!(target: LOG_TARGET, "Error = {:?}", e); "rpc get_storage failed." }) } + /// Get the latest finalized head. async fn rpc_get_head(&self) -> Result { trace!(target: LOG_TARGET, "rpc: finalized_head"); self.as_online().rpc_client().finalized_head().await.map_err(|e| { - error!("Error = {:?}", e); + error!(target: LOG_TARGET, "Error = {:?}", e); "rpc finalized_head failed." }) } /// Get all the keys at `prefix` at `hash` using the paged, safe RPC methods. - async fn get_keys_paged( + async fn rpc_get_keys_paged( &self, prefix: StorageKey, at: B::Hash, @@ -277,7 +299,7 @@ impl Builder { all_keys.last().expect("all_keys is populated; has .last(); qed"); log::debug!( target: LOG_TARGET, - "new total = {}, full page received: {:?}", + "new total = {}, full page received: {}", all_keys.len(), HexDisplay::from(new_last_key) ); @@ -296,12 +318,12 @@ impl Builder { &self, prefix: StorageKey, at: B::Hash, - ) -> Result, &'static str> { - let keys = self.get_keys_paged(prefix, at).await?; + ) -> Result, &'static str> { + let keys = self.rpc_get_keys_paged(prefix, at).await?; let keys_count = keys.len(); log::debug!(target: LOG_TARGET, "Querying a total of {} keys", keys.len()); - let mut key_values: Vec = vec![]; + let mut key_values: Vec = vec![]; let client = self.as_online().rpc_client(); for chunk_keys in keys.chunks(BATCH_SIZE) { let batch = chunk_keys @@ -318,7 +340,9 @@ impl Builder { ); "batch failed." })?; + assert_eq!(chunk_keys.len(), values.len()); + for (idx, key) in chunk_keys.into_iter().enumerate() { let maybe_value = values[idx].clone(); let value = maybe_value.unwrap_or_else(|| { @@ -341,26 +365,216 @@ impl Builder { Ok(key_values) } + + /// Get the values corresponding to `child_keys` at the given `prefixed_top_key`. + pub(crate) async fn rpc_child_get_storage_paged( + &self, + prefixed_top_key: &StorageKey, + child_keys: Vec, + at: B::Hash, + ) -> Result, &'static str> { + let mut child_kv_inner = vec![]; + for batch_child_key in child_keys.chunks(BATCH_SIZE) { + let batch_request = batch_child_key + .iter() + .cloned() + .map(|key| { + ( + "childstate_getStorage", + rpc_params![ + PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), + key, + at + ], + ) + }) + .collect::>(); + + let batch_response = self + .as_online() + .rpc_client() + .batch_request::>(batch_request) + .await + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "failed to execute batch: {:?}. Error: {:?}", + batch_child_key, + e + ); + "batch failed." + })?; + + assert_eq!(batch_child_key.len(), batch_response.len()); + + for (idx, key) in batch_child_key.into_iter().enumerate() { + let maybe_value = batch_response[idx].clone(); + let value = maybe_value.unwrap_or_else(|| { + log::warn!(target: LOG_TARGET, "key {:?} had none corresponding value.", &key); + StorageData(vec![]) + }); + child_kv_inner.push((key.clone(), value)); + } + } + + Ok(child_kv_inner) + } + + pub(crate) async fn rpc_child_get_keys( + &self, + prefixed_top_key: &StorageKey, + child_prefix: StorageKey, + at: B::Hash, + ) -> Result, &'static str> { + let child_keys = self + .as_online() + .rpc_client() + .child_get_keys( + PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), + child_prefix, + Some(at), + ) + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Error = {:?}", e); + "rpc child_get_keys failed." + })?; + + debug!( + target: LOG_TARGET, + "scraped {} child-keys of the child-bearing top key: {}", + child_keys.len(), + HexDisplay::from(prefixed_top_key) + ); + + Ok(child_keys) + } } // Internal methods impl Builder { - /// Save the given data as state snapshot. - fn save_state_snapshot(&self, data: &[KeyPair], path: &Path) -> Result<(), &'static str> { - log::debug!(target: LOG_TARGET, "writing to state snapshot file {:?}", path); - fs::write(path, data.encode()).map_err(|_| "fs::write failed.")?; + /// Save the given data to the top keys snapshot. + fn save_top_snapshot(&self, data: &[KeyValue], path: &PathBuf) -> Result<(), &'static str> { + let mut path = path.clone(); + let encoded = data.encode(); + path.set_extension("top"); + debug!( + target: LOG_TARGET, + "writing {} bytes to state snapshot file {:?}", + encoded.len(), + path + ); + fs::write(path, encoded).map_err(|_| "fs::write failed.")?; Ok(()) } - /// initialize `Self` from state snapshot. Panics if the file does not exist. - fn load_state_snapshot(&self, path: &Path) -> Result, &'static str> { - log::info!(target: LOG_TARGET, "scraping key-pairs from state snapshot {:?}", path); + /// Save the given data to the child keys snapshot. + fn save_child_snapshot( + &self, + data: &ChildKeyValues, + path: &PathBuf, + ) -> Result<(), &'static str> { + let mut path = path.clone(); + path.set_extension("child"); + let encoded = data.encode(); + debug!( + target: LOG_TARGET, + "writing {} bytes to state snapshot file {:?}", + encoded.len(), + path + ); + fs::write(path, encoded).map_err(|_| "fs::write failed.")?; + Ok(()) + } + + fn load_top_snapshot(&self, path: &PathBuf) -> Result { + let mut path = path.clone(); + path.set_extension("top"); + info!(target: LOG_TARGET, "loading top key-pairs from snapshot {:?}", path); + let bytes = fs::read(path).map_err(|_| "fs::read failed.")?; + Decode::decode(&mut &*bytes).map_err(|e| { + log::error!(target: LOG_TARGET, "{:?}", e); + "decode failed" + }) + } + + fn load_child_snapshot(&self, path: &PathBuf) -> Result { + let mut path = path.clone(); + path.set_extension("child"); + info!(target: LOG_TARGET, "loading child key-pairs from snapshot {:?}", path); let bytes = fs::read(path).map_err(|_| "fs::read failed.")?; - Decode::decode(&mut &*bytes).map_err(|_| "decode failed") + Decode::decode(&mut &*bytes).map_err(|e| { + log::error!(target: LOG_TARGET, "{:?}", e); + "decode failed" + }) + } + + /// Load all the `top` keys from the remote config, and maybe write then to cache. + async fn load_top_remote_and_maybe_save(&self) -> Result { + let top_kv = self.load_top_remote().await?; + if let Some(c) = &self.as_online().state_snapshot { + self.save_top_snapshot(&top_kv, &c.path)?; + } + Ok(top_kv) + } + + /// Load all of the child keys from the remote config, given the already scraped list of top key + /// pairs. + /// + /// Stores all values to cache as well, if provided. + async fn load_child_remote_and_maybe_save( + &self, + top_kv: &[KeyValue], + ) -> Result { + let child_kv = self.load_child_remote(&top_kv).await?; + if let Some(c) = &self.as_online().state_snapshot { + self.save_child_snapshot(&child_kv, &c.path)?; + } + Ok(child_kv) + } + + /// Load all of the child keys from the remote config, given the already scraped list of top key + /// pairs. + /// + /// `top_kv` need not be only child-bearing top keys. It should be all of the top keys that are + /// included thus far. + async fn load_child_remote(&self, top_kv: &[KeyValue]) -> Result { + let child_roots = top_kv + .iter() + .filter_map(|(k, _)| is_default_child_storage_key(k.as_ref()).then(|| k)) + .collect::>(); + + info!( + target: LOG_TARGET, + "👩‍👦 scraping child-tree data from {} top keys", + child_roots.len() + ); + + let mut child_kv = vec![]; + for prefixed_top_key in child_roots { + let at = self.as_online().at.expect("at must be initialized in online mode."); + let child_keys = + self.rpc_child_get_keys(prefixed_top_key, StorageKey(vec![]), at).await?; + let child_kv_inner = + self.rpc_child_get_storage_paged(prefixed_top_key, child_keys, at).await?; + + let prefixed_top_key = PrefixedStorageKey::new(prefixed_top_key.clone().0); + let un_prefixed = match ChildType::from_prefixed_key(&prefixed_top_key) { + Some((ChildType::ParentKeyId, storage_key)) => storage_key, + None => { + log::error!(target: LOG_TARGET, "invalid key: {:?}", prefixed_top_key); + return Err("Invalid child key") + }, + }; + + child_kv.push((ChildInfo::new_default(&un_prefixed), child_kv_inner)); + } + + Ok(child_kv) } /// Build `Self` from a network node denoted by `uri`. - async fn load_remote(&self) -> Result, &'static str> { + async fn load_top_remote(&self) -> Result { let config = self.as_online(); let at = self .as_online() @@ -371,17 +585,17 @@ impl Builder { let mut keys_and_values = if config.pallets.len() > 0 { let mut filtered_kv = vec![]; - for f in config.pallets.iter() { - let hashed_prefix = StorageKey(twox_128(f.as_bytes()).to_vec()); - let module_kv = self.rpc_get_pairs_paged(hashed_prefix.clone(), at).await?; + for p in config.pallets.iter() { + let hashed_prefix = StorageKey(twox_128(p.as_bytes()).to_vec()); + let pallet_kv = self.rpc_get_pairs_paged(hashed_prefix.clone(), at).await?; log::info!( target: LOG_TARGET, - "downloaded data for module {} (count: {} / prefix: {:?}).", - f, - module_kv.len(), + "downloaded data for module {} (count: {} / prefix: {}).", + p, + pallet_kv.len(), HexDisplay::from(&hashed_prefix), ); - filtered_kv.extend(module_kv); + filtered_kv.extend(pallet_kv); } filtered_kv } else { @@ -423,7 +637,10 @@ impl Builder { .max_request_body_size(u32::MAX) .build(&online.transport.uri) .await - .map_err(|_| "failed to build ws client")?; + .map_err(|e| { + log::error!(target: LOG_TARGET, "error: {:?}", e); + "failed to build ws client" + })?; online.transport.client = Some(ws_client); // Then, if `at` is not set, set it. @@ -435,27 +652,21 @@ impl Builder { Ok(()) } - pub(crate) async fn pre_build(mut self) -> Result, &'static str> { - let mut base_kv = match self.mode.clone() { - Mode::Offline(config) => self.load_state_snapshot(&config.state_snapshot.path)?, - Mode::Online(config) => { + pub(crate) async fn pre_build( + mut self, + ) -> Result<(TopKeyValues, ChildKeyValues), &'static str> { + let mut top_kv = match self.mode.clone() { + Mode::Offline(config) => self.load_top_snapshot(&config.state_snapshot.path)?, + Mode::Online(_) => { self.init_remote_client().await?; - let kp = self.load_remote().await?; - if let Some(c) = config.state_snapshot { - self.save_state_snapshot(&kp, &c.path)?; - } - kp + self.load_top_remote_and_maybe_save().await? }, - Mode::OfflineOrElseOnline(offline_config, online_config) => { - if let Ok(kv) = self.load_state_snapshot(&offline_config.state_snapshot.path) { + Mode::OfflineOrElseOnline(offline_config, _) => { + if let Ok(kv) = self.load_top_snapshot(&offline_config.state_snapshot.path) { kv } else { self.init_remote_client().await?; - let kp = self.load_remote().await?; - if let Some(c) = online_config.state_snapshot { - self.save_state_snapshot(&kp, &c.path)?; - } - kp + self.load_top_remote_and_maybe_save().await? } }, }; @@ -467,7 +678,7 @@ impl Builder { "extending externalities with {} manually injected key-values", self.hashed_key_values.len() ); - base_kv.extend(self.hashed_key_values.clone()); + top_kv.extend(self.hashed_key_values.clone()); } // exclude manual key values. @@ -477,10 +688,30 @@ impl Builder { "excluding externalities from {} keys", self.hashed_blacklist.len() ); - base_kv.retain(|(k, _)| !self.hashed_blacklist.contains(&k.0)) + top_kv.retain(|(k, _)| !self.hashed_blacklist.contains(&k.0)) } - Ok(base_kv) + let child_kv = match self.mode.clone() { + Mode::Online(_) => self.load_child_remote_and_maybe_save(&top_kv).await?, + Mode::OfflineOrElseOnline(offline_config, _) => + if let Ok(kv) = self.load_child_snapshot(&offline_config.state_snapshot.path) { + kv + } else { + self.load_child_remote_and_maybe_save(&top_kv).await? + }, + Mode::Offline(ref config) => self + .load_child_snapshot(&config.state_snapshot.path) + .map_err(|why| { + log::warn!( + target: LOG_TARGET, + "failed to load child-key file due to {:?}.", + why + ) + }) + .unwrap_or_default(), + }; + + Ok((top_kv, child_kv)) } } @@ -492,12 +723,13 @@ impl Builder { } /// Inject a manual list of key and values to the storage. - pub fn inject_hashed_key_value(mut self, injections: &[KeyPair]) -> Self { + pub fn inject_hashed_key_value(mut self, injections: &[KeyValue]) -> Self { for i in injections { self.hashed_key_values.push(i.clone()); } self } + /// Inject a hashed prefix. This is treated as-is, and should be pre-hashed. /// /// This should be used to inject a "PREFIX", like a storage (double) map. @@ -506,6 +738,22 @@ impl Builder { self } + /// Just a utility wrapper of [`inject_hashed_prefix`] that injects + /// [`DEFAULT_CHILD_STORAGE_KEY_PREFIX`] as a prefix. + /// + /// If set, this will guarantee that the child-tree data of ALL pallets will be downloaded. + /// + /// This is not needed if the entire state is being downloaded. + /// + /// Otherwise, the only other way to make sure a child-tree is manually included is to inject + /// its root (`DEFAULT_CHILD_STORAGE_KEY_PREFIX`, plus some other postfix) into + /// [`inject_hashed_key`]. Unfortunately, there's no federated way of managing child tree roots + /// as of now and each pallet does its own thing. Therefore, it is not possible for this library + /// to automatically include child trees of pallet X, when its top keys are included. + pub fn inject_default_child_tree_prefix(self) -> Self { + self.inject_hashed_prefix(DEFAULT_CHILD_STORAGE_KEY_PREFIX) + } + /// Inject a hashed key to scrape. This is treated as-is, and should be pre-hashed. /// /// This should be used to inject a "KEY", like a storage value. @@ -540,16 +788,37 @@ impl Builder { /// Build the test externalities. pub async fn build(self) -> Result { - let kv = self.pre_build().await?; - let mut ext = TestExternalities::new_empty(); - - log::info!(target: LOG_TARGET, "injecting a total of {} keys", kv.len()); - for (k, v) in kv { - let (k, v) = (k.0, v.0); - // Insert the key,value pair into the test trie backend - ext.insert(k, v); + let (top_kv, child_kv) = self.pre_build().await?; + let mut ext = TestExternalities::new_with_code(Default::default(), Default::default()); + + info!(target: LOG_TARGET, "injecting a total of {} top keys", top_kv.len()); + for (k, v) in top_kv { + // skip writing the child root data. + if is_default_child_storage_key(k.as_ref()) { + continue + } + ext.insert(k.0, v.0); } + info!( + target: LOG_TARGET, + "injecting a total of {} child keys", + child_kv.iter().map(|(_, kv)| kv).flatten().count() + ); + + for (info, key_values) in child_kv { + for (k, v) in key_values { + ext.insert_child(info.clone(), k.0, v.0); + } + } + + ext.commit_all().unwrap(); + info!( + target: LOG_TARGET, + "initialized state externalities with storage root {:?}", + ext.as_backend().root() + ); + Ok(ext) } } @@ -621,7 +890,6 @@ mod tests { #[cfg(all(test, feature = "remote-test"))] mod remote_tests { use super::test_prelude::*; - use pallet_elections_phragmen::Members; const REMOTE_INACCESSIBLE: &'static str = "Can't reach the remote node. Is it running?"; #[tokio::test] @@ -631,11 +899,11 @@ mod remote_tests { Builder::::new() .mode(Mode::OfflineOrElseOnline( OfflineConfig { - state_snapshot: SnapshotConfig::new("test_snapshot_to_remove.bin"), + state_snapshot: SnapshotConfig::new("offline_else_online_works_data"), }, OnlineConfig { pallets: vec!["Proxy".to_owned()], - state_snapshot: Some(SnapshotConfig::new("test_snapshot_to_remove.bin")), + state_snapshot: Some(SnapshotConfig::new("offline_else_online_works_data")), ..Default::default() }, )) @@ -648,11 +916,11 @@ mod remote_tests { Builder::::new() .mode(Mode::OfflineOrElseOnline( OfflineConfig { - state_snapshot: SnapshotConfig::new("test_snapshot_to_remove.bin"), + state_snapshot: SnapshotConfig::new("offline_else_online_works_data"), }, OnlineConfig { pallets: vec!["Proxy".to_owned()], - state_snapshot: Some(SnapshotConfig::new("test_snapshot_to_remove.bin")), + state_snapshot: Some(SnapshotConfig::new("offline_else_online_works_data")), transport: "ws://non-existent:666".to_owned().into(), ..Default::default() }, @@ -661,14 +929,56 @@ mod remote_tests { .await .expect(REMOTE_INACCESSIBLE) .execute_with(|| {}); + + let to_delete = std::fs::read_dir(Path::new(".")) + .unwrap() + .into_iter() + .map(|d| d.unwrap()) + .filter(|p| { + p.path().file_name().unwrap_or_default() == "offline_else_online_works_data" || + p.path().extension().unwrap_or_default() == "top" || + p.path().extension().unwrap_or_default() == "child" + }) + .collect::>(); + assert!(to_delete.len() > 0); + for d in to_delete { + std::fs::remove_file(d.path()).unwrap(); + } } #[tokio::test] - async fn can_build_one_pallet() { + #[ignore = "too slow"] + async fn can_build_one_big_pallet() { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - pallets: vec!["Proxy".to_owned()], + pallets: vec!["System".to_owned()], + ..Default::default() + })) + .build() + .await + .expect(REMOTE_INACCESSIBLE) + .execute_with(|| {}); + } + + #[tokio::test] + async fn can_build_one_small_pallet() { + init_logger(); + Builder::::new() + .mode(Mode::Online(OnlineConfig { + transport: "wss://kusama-rpc.polkadot.io:443".to_owned().into(), + pallets: vec!["Council".to_owned()], + ..Default::default() + })) + .build() + .await + .expect(REMOTE_INACCESSIBLE) + .execute_with(|| {}); + + Builder::::new() + .mode(Mode::Online(OnlineConfig { + transport: "wss://rpc.polkadot.io:443".to_owned().into(), + pallets: vec!["Council".to_owned()], ..Default::default() })) .build() @@ -682,6 +992,18 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { + transport: "wss://kusama-rpc.polkadot.io:443".to_owned().into(), + pallets: vec!["Proxy".to_owned(), "Multisig".to_owned()], + ..Default::default() + })) + .build() + .await + .expect(REMOTE_INACCESSIBLE) + .execute_with(|| {}); + + Builder::::new() + .mode(Mode::Online(OnlineConfig { + transport: "wss://rpc.polkadot.io:443".to_owned().into(), pallets: vec!["Proxy".to_owned(), "Multisig".to_owned()], ..Default::default() })) @@ -692,49 +1014,70 @@ mod remote_tests { } #[tokio::test] - async fn sanity_check_decoding() { - use sp_core::crypto::Ss58Codec; - - type AccountId = sp_runtime::AccountId32; - type Balance = u128; - frame_support::generate_storage_alias!( - PhragmenElection, - Members => - Value>> - ); + async fn can_create_top_snapshot() { + init_logger(); + Builder::::new() + .mode(Mode::Online(OnlineConfig { + state_snapshot: Some(SnapshotConfig::new("can_create_top_snapshot_data")), + pallets: vec!["Proxy".to_owned()], + ..Default::default() + })) + .build() + .await + .expect(REMOTE_INACCESSIBLE) + .execute_with(|| {}); + + let to_delete = std::fs::read_dir(Path::new(".")) + .unwrap() + .into_iter() + .map(|d| d.unwrap()) + .filter(|p| { + p.path().file_name().unwrap_or_default() == "can_create_top_snapshot_data" || + p.path().extension().unwrap_or_default() == "top" || + p.path().extension().unwrap_or_default() == "child" + }) + .collect::>(); + + assert!(to_delete.len() > 0); + + for d in to_delete { + use std::os::unix::fs::MetadataExt; + if d.path().extension().unwrap_or_default() == "top" { + // if this is the top snapshot it must not be empty. + assert!(std::fs::metadata(d.path()).unwrap().size() > 1); + } else { + // the child is empty for this pallet. + assert!(std::fs::metadata(d.path()).unwrap().size() == 1); + } + std::fs::remove_file(d.path()).unwrap(); + } + } + #[tokio::test] + async fn can_build_child_tree() { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - pallets: vec!["PhragmenElection".to_owned()], + transport: "wss://rpc.polkadot.io:443".to_owned().into(), + pallets: vec!["Crowdloan".to_owned()], ..Default::default() })) .build() .await .expect(REMOTE_INACCESSIBLE) - .execute_with(|| { - // Gav's polkadot account. 99% this will be in the council. - let gav_polkadot = - AccountId::from_ss58check("13RDY9nrJpyTDBSUdBw12dGwhk19sGwsrVZ2bxkzYHBSagP2") - .unwrap(); - let members = Members::get(); - assert!(members - .iter() - .map(|s| s.who.clone()) - .find(|a| a == &gav_polkadot) - .is_some()); - }); + .execute_with(|| {}); } #[tokio::test] - async fn can_create_state_snapshot() { + async fn can_create_child_snapshot() { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - state_snapshot: Some(SnapshotConfig::new("test_snapshot_to_remove.bin")), - pallets: vec!["Proxy".to_owned()], + state_snapshot: Some(SnapshotConfig::new("can_create_child_snapshot_data")), + pallets: vec!["Crowdloan".to_owned()], ..Default::default() })) + .inject_default_child_tree_prefix() .build() .await .expect(REMOTE_INACCESSIBLE) @@ -744,24 +1087,62 @@ mod remote_tests { .unwrap() .into_iter() .map(|d| d.unwrap()) - .filter(|p| p.path().extension().unwrap_or_default() == "bin") + .filter(|p| { + p.path().file_name().unwrap_or_default() == "can_create_child_snapshot_data" || + p.path().extension().unwrap_or_default() == "top" || + p.path().extension().unwrap_or_default() == "child" + }) .collect::>(); assert!(to_delete.len() > 0); for d in to_delete { + use std::os::unix::fs::MetadataExt; + // if this is the top snapshot it must not be empty + if d.path().extension().unwrap_or_default() == "child" { + assert!(std::fs::metadata(d.path()).unwrap().size() > 1); + } else { + assert!(std::fs::metadata(d.path()).unwrap().size() > 1); + } std::fs::remove_file(d.path()).unwrap(); } } #[tokio::test] - #[ignore = "takes too much time on average."] async fn can_fetch_all() { init_logger(); Builder::::new() + .mode(Mode::Online(OnlineConfig { + state_snapshot: Some(SnapshotConfig::new("can_fetch_all_data")), + ..Default::default() + })) .build() .await .expect(REMOTE_INACCESSIBLE) .execute_with(|| {}); + + let to_delete = std::fs::read_dir(Path::new(".")) + .unwrap() + .into_iter() + .map(|d| d.unwrap()) + .filter(|p| { + p.path().file_name().unwrap_or_default() == "can_fetch_all_data" || + p.path().extension().unwrap_or_default() == "top" || + p.path().extension().unwrap_or_default() == "child" + }) + .collect::>(); + + assert!(to_delete.len() > 0); + + for d in to_delete { + use std::os::unix::fs::MetadataExt; + // if we download everything, child tree must also be filled. + if d.path().extension().unwrap_or_default() == "child" { + assert!(std::fs::metadata(d.path()).unwrap().size() > 1); + } else { + assert!(std::fs::metadata(d.path()).unwrap().size() > 1); + } + std::fs::remove_file(d.path()).unwrap(); + } } } diff --git a/utils/frame/remote-externalities/test_data/proxy_test b/utils/frame/remote-externalities/test_data/proxy_test.top similarity index 100% rename from utils/frame/remote-externalities/test_data/proxy_test rename to utils/frame/remote-externalities/test_data/proxy_test.top diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 44be678ba3814..388b23aeb3eba 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -32,3 +32,5 @@ sp-version = { version = "4.0.0-dev", path = "../../../../primitives/version" } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } jsonrpsee = { version = "0.4.1", default-features = false, features = ["ws-client"]} + +zstd = "0.9.0" diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index 216c63d00525d..a717b410c2bf4 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -17,7 +17,7 @@ use crate::{ build_executor, ensure_matching_spec, extract_code, full_extensions, hash_of, local_spec, - state_machine_call, SharedParams, State, LOG_TARGET, + state_machine_call_with_proof, SharedParams, State, LOG_TARGET, }; use remote_externalities::rpc_api; use sc_service::{Configuration, NativeExecutionDispatch}; @@ -167,7 +167,7 @@ where ) .await; - let _ = state_machine_call::( + let _ = state_machine_call_with_proof::( &ext, &executor, execution, diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index 70f177dc1f869..09f541c887536 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -17,7 +17,7 @@ use crate::{ build_executor, ensure_matching_spec, extract_code, full_extensions, local_spec, parse, - state_machine_call, SharedParams, LOG_TARGET, + state_machine_call_with_proof, SharedParams, LOG_TARGET, }; use jsonrpsee::{ types::{traits::SubscriptionClient, Subscription}, @@ -139,7 +139,7 @@ where let state_ext = maybe_state_ext.as_mut().expect("state_ext either existed or was just created"); - let (mut changes, encoded_result) = state_machine_call::( + let (mut changes, encoded_result) = state_machine_call_with_proof::( &state_ext, &executor, execution, diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 8de3cb3a32005..6343b2b2e3f0d 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -23,7 +23,7 @@ use sc_service::Configuration; use sp_runtime::traits::{Block as BlockT, NumberFor}; use crate::{ - build_executor, ensure_matching_spec, extract_code, local_spec, state_machine_call, + build_executor, ensure_matching_spec, extract_code, local_spec, state_machine_call_with_proof, SharedParams, State, LOG_TARGET, }; @@ -69,7 +69,7 @@ where .await; } - let (_, encoded_result) = state_machine_call::( + let (_, encoded_result) = state_machine_call_with_proof::( &ext, &executor, execution, diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 8b8c6b2d2bb36..8ea2e39297a95 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -285,7 +285,7 @@ use sp_runtime::{ traits::{Block as BlockT, NumberFor}, DeserializeOwned, }; -use sp_state_machine::{OverlayedChanges, StateMachine}; +use sp_state_machine::{InMemoryProvingBackend, OverlayedChanges, StateMachine}; use std::{fmt::Debug, path::PathBuf, str::FromStr}; mod commands; @@ -462,6 +462,14 @@ pub enum State { /// The pallets to scrape. If empty, entire chain state will be scraped. #[structopt(short, long, require_delimiter = true)] pallets: Option>, + + /// Fetch the child-keys as well. + /// + /// Default is `false`, if specific `pallets` are specified, true otherwise. In other + /// words, if you scrape the whole state the child tree data is included out of the box. + /// Otherwise, it must be enabled explicitly using this flag. + #[structopt(long, require_delimiter = true)] + child_tree: bool, }, } @@ -477,21 +485,26 @@ impl State { Builder::::new().mode(Mode::Offline(OfflineConfig { state_snapshot: SnapshotConfig::new(snapshot_path), })), - State::Live { snapshot_path, pallets, uri, at } => { + State::Live { snapshot_path, pallets, uri, at, child_tree } => { let at = match at { Some(at_str) => Some(hash_of::(at_str)?), None => None, }; - Builder::::new() + let mut builder = Builder::::new() .mode(Mode::Online(OnlineConfig { transport: uri.to_owned().into(), state_snapshot: snapshot_path.as_ref().map(SnapshotConfig::new), - pallets: pallets.to_owned().unwrap_or_default(), + pallets: pallets.clone().unwrap_or_default(), at, + ..Default::default() })) .inject_hashed_key( &[twox_128(b"System"), twox_128(b"LastRuntimeUpgrade")].concat(), - ) + ); + if *child_tree { + builder = builder.inject_default_child_tree_prefix(); + } + builder }, }) } @@ -697,6 +710,85 @@ pub(crate) fn state_machine_call( + ext: &TestExternalities, + executor: &NativeElseWasmExecutor, + execution: sc_cli::ExecutionStrategy, + method: &'static str, + data: &[u8], + extensions: Extensions, +) -> sc_cli::Result<(OverlayedChanges, Vec)> { + use parity_scale_codec::Encode; + use sp_core::hexdisplay::HexDisplay; + + let mut changes = Default::default(); + let backend = ext.backend.clone(); + let proving_backend = InMemoryProvingBackend::new(&backend); + + let runtime_code_backend = sp_state_machine::backend::BackendRuntimeCode::new(&proving_backend); + let runtime_code = runtime_code_backend.runtime_code()?; + + let pre_root = backend.root().clone(); + + let encoded_results = StateMachine::new( + &proving_backend, + &mut changes, + executor, + method, + data, + extensions, + &runtime_code, + sp_core::testing::TaskExecutor::new(), + ) + .execute(execution.into()) + .map_err(|e| format!("failed to execute {}: {:?}", method, e)) + .map_err::(Into::into)?; + + let proof = proving_backend.extract_proof(); + let proof_size = proof.encoded_size(); + let compact_proof = proof + .clone() + .into_compact_proof::(pre_root) + .map_err(|e| format!("failed to generate compact proof {}: {:?}", method, e))?; + + let compact_proof_size = compact_proof.encoded_size(); + let compressed_proof = zstd::stream::encode_all(&compact_proof.encode()[..], 0) + .map_err(|e| format!("failed to generate compact proof {}: {:?}", method, e))?; + + let proof_nodes = proof.into_nodes(); + + let humanize = |s| { + if s < 1024 * 1024 { + format!("{:.2} KB ({} bytes)", s as f64 / 1024f64, s) + } else { + format!( + "{:.2} MB ({} KB) ({} bytes)", + s as f64 / (1024f64 * 1024f64), + s as f64 / 1024f64, + s + ) + } + }; + log::info!( + target: LOG_TARGET, + "proof: {} / {} nodes", + HexDisplay::from(&proof_nodes.iter().flatten().cloned().collect::>()), + proof_nodes.len() + ); + log::info!(target: LOG_TARGET, "proof size: {}", humanize(proof_size)); + log::info!(target: LOG_TARGET, "compact proof size: {}", humanize(compact_proof_size),); + log::info!( + target: LOG_TARGET, + "zstd-compressed compact proof {}", + humanize(compressed_proof.len()), + ); + Ok((changes, encoded_results)) +} + /// Get the spec `(name, version)` from the local runtime. pub(crate) fn local_spec( ext: &TestExternalities, From 76d34c44bdc137beff9aabcd965b7302ba9abc4c Mon Sep 17 00:00:00 2001 From: wigy <1888808+wigy-opensource-developer@users.noreply.github.com> Date: Sun, 5 Dec 2021 20:17:14 +0100 Subject: [PATCH 0302/1472] Authentication of PeerIds in authority discovery records (#10317) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Consolidating test and production code * Signing/verifying authority discovery records with PeerId Unsigned records cannot be rejected yet, they just produce a warning in the log. * Upgrading to libp2p 0.40 * libp2p::identity and sp_core::crypto Ed25519 are compatible * Rejecting authority records unsigned by peer id can be configured * Fixes based on review comments * No command-line argument needed * info was still too much spam in the logs * Added tests for both strict and loose validation * Fixing based on review comments * Pierre preferred a signing method * Ooops, I need to slow down * Update bin/node/cli/src/service.rs * Reexport libp2p crypto used in sc-network * Added proto3 compatibility tests. And import noise. Co-authored-by: Bastian Köcher --- client/authority-discovery/README.md | 4 +- client/authority-discovery/build.rs | 6 +- client/authority-discovery/src/error.rs | 8 + client/authority-discovery/src/lib.rs | 6 + client/authority-discovery/src/tests.rs | 29 ++ client/authority-discovery/src/worker.rs | 238 +++++++++---- .../worker/schema/{dht.proto => dht-v1.proto} | 4 +- .../src/worker/schema/dht-v2.proto | 23 ++ .../src/worker/schema/tests.rs | 90 +++++ .../authority-discovery/src/worker/tests.rs | 330 ++++++++++++------ client/keystore/src/local.rs | 4 +- client/network/src/lib.rs | 5 +- client/network/src/service.rs | 32 +- client/network/src/service/signature.rs | 50 +++ 14 files changed, 633 insertions(+), 196 deletions(-) rename client/authority-discovery/src/worker/schema/{dht.proto => dht-v1.proto} (90%) create mode 100644 client/authority-discovery/src/worker/schema/dht-v2.proto create mode 100644 client/authority-discovery/src/worker/schema/tests.rs create mode 100644 client/network/src/service/signature.rs diff --git a/client/authority-discovery/README.md b/client/authority-discovery/README.md index 54c51d5ba04f4..042e8f5982cd0 100644 --- a/client/authority-discovery/README.md +++ b/client/authority-discovery/README.md @@ -1,4 +1,4 @@ -Substrate authority discovery. +# Substrate authority discovery This crate enables Substrate authorities to discover and directly connect to other authorities. It is split into two components the [`Worker`] and the @@ -6,4 +6,4 @@ other authorities. It is split into two components the [`Worker`] and the See [`Worker`] and [`Service`] for more documentation. -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/client/authority-discovery/build.rs b/client/authority-discovery/build.rs index c44fe8578ba25..00d45f07ae159 100644 --- a/client/authority-discovery/build.rs +++ b/client/authority-discovery/build.rs @@ -1,3 +1,7 @@ fn main() { - prost_build::compile_protos(&["src/worker/schema/dht.proto"], &["src/worker/schema"]).unwrap(); + prost_build::compile_protos( + &["src/worker/schema/dht-v1.proto", "src/worker/schema/dht-v2.proto"], + &["src/worker/schema"], + ) + .unwrap(); } diff --git a/client/authority-discovery/src/error.rs b/client/authority-discovery/src/error.rs index b271f7b9d62bb..d37b6f3b43bc8 100644 --- a/client/authority-discovery/src/error.rs +++ b/client/authority-discovery/src/error.rs @@ -46,10 +46,18 @@ pub enum Error { EncodingDecodingScale(codec::Error), /// Failed to parse a libp2p multi address. ParsingMultiaddress(libp2p::core::multiaddr::Error), + /// Failed to parse a libp2p key. + ParsingLibp2pIdentity(sc_network::DecodingError), /// Failed to sign using a specific public key. MissingSignature(CryptoTypePublicPair), /// Failed to sign using all public keys. Signing, /// Failed to register Prometheus metric. Prometheus(prometheus_endpoint::PrometheusError), + /// Received authority record that contains addresses with multiple peer ids + ReceivingDhtValueFoundEventWithDifferentPeerIds, + /// Received authority record without any addresses having a peer id + ReceivingDhtValueFoundEventWithNoPeerIds, + /// Received authority record without a valid signature for the remote peer id. + MissingPeerIdSignature, } diff --git a/client/authority-discovery/src/lib.rs b/client/authority-discovery/src/lib.rs index 1bbb9f38796c2..e619463fa1ad4 100644 --- a/client/authority-discovery/src/lib.rs +++ b/client/authority-discovery/src/lib.rs @@ -78,6 +78,11 @@ pub struct WorkerConfig { /// /// Defaults to `true` to avoid the surprise factor. pub publish_non_global_ips: bool, + + /// Reject authority discovery records that are not signed by their network identity (PeerId) + /// + /// Defaults to `false` to provide compatibility with old versions + pub strict_record_validation: bool, } impl Default for WorkerConfig { @@ -98,6 +103,7 @@ impl Default for WorkerConfig { // `authority_discovery_dht_event_received`. max_query_interval: Duration::from_secs(10 * 60), publish_non_global_ips: true, + strict_record_validation: false, } } } diff --git a/client/authority-discovery/src/tests.rs b/client/authority-discovery/src/tests.rs index cef91445064ca..f1965907f4dad 100644 --- a/client/authority-discovery/src/tests.rs +++ b/client/authority-discovery/src/tests.rs @@ -82,3 +82,32 @@ fn get_addresses_and_authority_id() { ); }); } + +#[test] +fn cryptos_are_compatible() { + use sp_core::crypto::Pair; + + let libp2p_secret = sc_network::Keypair::generate_ed25519(); + let libp2p_public = libp2p_secret.public(); + + let sp_core_secret = { + let libp2p_ed_secret = match libp2p_secret.clone() { + sc_network::Keypair::Ed25519(x) => x, + _ => panic!("generate_ed25519 should have generated an Ed25519 key ¯\\_(ツ)_/¯"), + }; + sp_core::ed25519::Pair::from_seed_slice(&libp2p_ed_secret.secret().as_ref()).unwrap() + }; + let sp_core_public = sp_core_secret.public(); + + let message = b"we are more powerful than not to be better"; + + let libp2p_signature = libp2p_secret.sign(message).unwrap(); + let sp_core_signature = sp_core_secret.sign(message); // no error expected... + + assert!(sp_core::ed25519::Pair::verify( + &sp_core::ed25519::Signature::from_slice(&libp2p_signature), + message, + &sp_core_public + )); + assert!(libp2p_public.verify(message, sp_core_signature.as_ref())); +} diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index 00021ecbdcb83..ce04e0eb65b15 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -19,7 +19,7 @@ use crate::{ error::{Error, Result}, interval::ExpIncInterval, - ServicetoWorkerMsg, + ServicetoWorkerMsg, WorkerConfig, }; use std::{ @@ -57,7 +57,10 @@ use sp_runtime::{generic::BlockId, traits::Block as BlockT}; mod addr_cache; /// Dht payload schemas generated from Protobuf definitions via Prost crate in build.rs. mod schema { - include!(concat!(env!("OUT_DIR"), "/authority_discovery.rs")); + #[cfg(test)] + mod tests; + + include!(concat!(env!("OUT_DIR"), "/authority_discovery_v2.rs")); } #[cfg(test)] pub mod tests; @@ -111,6 +114,7 @@ pub struct Worker { client: Arc, network: Arc, + /// Channel we receive Dht events on. dht_event_rx: DhtEventStream, @@ -124,6 +128,8 @@ pub struct Worker { latest_published_keys: HashSet, /// Same value as in the configuration. publish_non_global_ips: bool, + /// Same value as in the configuration. + strict_record_validation: bool, /// Interval at which to request addresses of authorities, refilling the pending lookups queue. query_interval: ExpIncInterval, @@ -131,7 +137,7 @@ pub struct Worker { /// Queue of throttled lookups pending to be passed to the network. pending_lookups: Vec, /// Set of in-flight lookups. - in_flight_lookups: HashMap, + in_flight_lookups: HashMap, addr_cache: addr_cache::AddrCache, @@ -158,7 +164,7 @@ where dht_event_rx: DhtEventStream, role: Role, prometheus_registry: Option, - config: crate::WorkerConfig, + config: WorkerConfig, ) -> Self { // When a node starts up publishing and querying might fail due to various reasons, for // example due to being not yet fully bootstrapped on the DHT. Thus one should retry rather @@ -197,6 +203,7 @@ where publish_if_changed_interval, latest_published_keys: HashSet::new(), publish_non_global_ips: config.publish_non_global_ips, + strict_record_validation: config.strict_record_validation, query_interval, pending_lookups: Vec::new(), in_flight_lookups: HashMap::new(), @@ -313,7 +320,7 @@ where return Ok(()) } - let addresses = self.addresses_to_publish().map(|a| a.to_vec()).collect::>(); + let addresses = serialize_addresses(self.addresses_to_publish()); if let Some(metrics) = &self.metrics { metrics.publish.inc(); @@ -322,32 +329,21 @@ where .set(addresses.len().try_into().unwrap_or(std::u64::MAX)); } - let mut serialized_addresses = vec![]; - schema::AuthorityAddresses { addresses } - .encode(&mut serialized_addresses) - .map_err(Error::EncodingProto)?; + let serialized_record = serialize_authority_record(addresses)?; + let peer_signature = sign_record_with_peer_id(&serialized_record, self.network.as_ref())?; let keys_vec = keys.iter().cloned().collect::>(); - let signatures = key_store - .sign_with_all( - key_types::AUTHORITY_DISCOVERY, - keys_vec.clone(), - serialized_addresses.as_slice(), - ) - .await - .map_err(|_| Error::Signing)?; - - for (sign_result, key) in signatures.into_iter().zip(keys_vec.iter()) { - let mut signed_addresses = vec![]; - // Verify that all signatures exist for all provided keys. - let signature = - sign_result.ok().flatten().ok_or_else(|| Error::MissingSignature(key.clone()))?; - schema::SignedAuthorityAddresses { addresses: serialized_addresses.clone(), signature } - .encode(&mut signed_addresses) - .map_err(Error::EncodingProto)?; + let kv_pairs = sign_record_with_authority_ids( + serialized_record, + Some(peer_signature), + key_store.as_ref(), + keys_vec, + ) + .await?; - self.network.put_value(hash_authority_id(key.1.as_ref()), signed_addresses); + for (key, value) in kv_pairs.into_iter() { + self.network.put_value(key, value); } self.latest_published_keys = keys; @@ -471,18 +467,11 @@ where fn handle_dht_value_found_event( &mut self, - values: Vec<(libp2p::kad::record::Key, Vec)>, + values: Vec<(sc_network::KademliaKey, Vec)>, ) -> Result<()> { // Ensure `values` is not empty and all its keys equal. - let remote_key = values - .iter() - .fold(Ok(None), |acc, (key, _)| match acc { - Ok(None) => Ok(Some(key.clone())), - Ok(Some(ref prev_key)) if prev_key != key => - Err(Error::ReceivingDhtValueFoundEventWithDifferentKeys), - x @ Ok(_) => x, - Err(e) => Err(e), - })? + let remote_key = single(values.iter().map(|(key, _)| key.clone())) + .map_err(|_| Error::ReceivingDhtValueFoundEventWithDifferentKeys)? .ok_or(Error::ReceivingDhtValueFoundEventWithNoRecords)?; let authority_id: AuthorityId = self @@ -495,18 +484,18 @@ where let remote_addresses: Vec = values .into_iter() .map(|(_k, v)| { - let schema::SignedAuthorityAddresses { signature, addresses } = - schema::SignedAuthorityAddresses::decode(v.as_slice()) + let schema::SignedAuthorityRecord { record, auth_signature, peer_signature } = + schema::SignedAuthorityRecord::decode(v.as_slice()) .map_err(Error::DecodingProto)?; - let signature = AuthoritySignature::decode(&mut &signature[..]) + let auth_signature = AuthoritySignature::decode(&mut &auth_signature[..]) .map_err(Error::EncodingDecodingScale)?; - if !AuthorityPair::verify(&signature, &addresses, &authority_id) { + if !AuthorityPair::verify(&auth_signature, &record, &authority_id) { return Err(Error::VerifyingDhtPayload) } - let addresses = schema::AuthorityAddresses::decode(addresses.as_slice()) + let addresses: Vec = schema::AuthorityRecord::decode(record.as_slice()) .map(|a| a.addresses) .map_err(Error::DecodingProto)? .into_iter() @@ -514,32 +503,49 @@ where .collect::>() .map_err(Error::ParsingMultiaddress)?; + let get_peer_id = |a: &Multiaddr| match a.iter().last() { + Some(multiaddr::Protocol::P2p(key)) => PeerId::from_multihash(key).ok(), + _ => None, + }; + + // Ignore [`Multiaddr`]s without [`PeerId`] or with own addresses. + let addresses: Vec = addresses + .into_iter() + .filter(|a| get_peer_id(&a).filter(|p| *p != local_peer_id).is_some()) + .collect(); + + let remote_peer_id = single(addresses.iter().map(get_peer_id)) + .map_err(|_| Error::ReceivingDhtValueFoundEventWithDifferentPeerIds)? // different peer_id in records + .flatten() + .ok_or(Error::ReceivingDhtValueFoundEventWithNoPeerIds)?; // no records with peer_id in them + + // At this point we know all the valid multiaddresses from the record, know that + // each of them belong to the same PeerId, we just need to check if the record is + // properly signed by the owner of the PeerId + + if let Some(peer_signature) = peer_signature { + let public_key = + sc_network::PublicKey::from_protobuf_encoding(&peer_signature.public_key) + .map_err(|e| Error::ParsingLibp2pIdentity(e))?; + let signature = + sc_network::Signature { public_key, bytes: peer_signature.signature }; + + if !signature.verify(record, &remote_peer_id) { + return Err(Error::VerifyingDhtPayload) + } + } else if self.strict_record_validation { + return Err(Error::MissingPeerIdSignature) + } else { + debug!( + target: LOG_TARGET, + "Received unsigned authority discovery record from {}", authority_id + ); + } Ok(addresses) }) .collect::>>>()? .into_iter() .flatten() - // Ignore [`Multiaddr`]s without [`PeerId`] and own addresses. - .filter(|addr| { - addr.iter().any(|protocol| { - // Parse to PeerId first as Multihashes of old and new PeerId - // representation don't equal. - // - // See https://github.com/libp2p/rust-libp2p/issues/555 for - // details. - if let multiaddr::Protocol::P2p(hash) = protocol { - let peer_id = match PeerId::from_multihash(hash) { - Ok(peer_id) => peer_id, - Err(_) => return false, // Discard address. - }; - - // Discard if equal to local peer id, keep if it differs. - return !(peer_id == local_peer_id) - } - - false // `protocol` is not a [`Protocol::P2p`], let's keep looking. - }) - }) .take(MAX_ADDRESSES_PER_AUTHORITY) .collect(); @@ -588,16 +594,37 @@ where } } +pub trait NetworkSigner { + /// Sign a message in the name of `self.local_peer_id()` + fn sign_with_local_identity( + &self, + msg: impl AsRef<[u8]>, + ) -> std::result::Result; +} + /// NetworkProvider provides [`Worker`] with all necessary hooks into the /// underlying Substrate networking. Using this trait abstraction instead of /// [`sc_network::NetworkService`] directly is necessary to unit test [`Worker`]. #[async_trait] -pub trait NetworkProvider: NetworkStateInfo { +pub trait NetworkProvider: NetworkStateInfo + NetworkSigner { /// Start putting a value in the Dht. - fn put_value(&self, key: libp2p::kad::record::Key, value: Vec); + fn put_value(&self, key: sc_network::KademliaKey, value: Vec); /// Start getting a value from the Dht. - fn get_value(&self, key: &libp2p::kad::record::Key); + fn get_value(&self, key: &sc_network::KademliaKey); +} + +impl NetworkSigner for sc_network::NetworkService +where + B: BlockT + 'static, + H: ExHashT, +{ + fn sign_with_local_identity( + &self, + msg: impl AsRef<[u8]>, + ) -> std::result::Result { + self.sign_with_local_identity(msg) + } } #[async_trait::async_trait] @@ -606,16 +633,87 @@ where B: BlockT + 'static, H: ExHashT, { - fn put_value(&self, key: libp2p::kad::record::Key, value: Vec) { + fn put_value(&self, key: sc_network::KademliaKey, value: Vec) { self.put_value(key, value) } - fn get_value(&self, key: &libp2p::kad::record::Key) { + fn get_value(&self, key: &sc_network::KademliaKey) { self.get_value(key) } } -fn hash_authority_id(id: &[u8]) -> libp2p::kad::record::Key { - libp2p::kad::record::Key::new(&libp2p::multihash::Sha2_256::digest(id)) +fn hash_authority_id(id: &[u8]) -> sc_network::KademliaKey { + sc_network::KademliaKey::new(&libp2p::multihash::Sha2_256::digest(id)) +} + +// Makes sure all values are the same and returns it +// +// Returns Err(_) if not all values are equal. Returns Ok(None) if there are +// no values. +fn single(values: impl IntoIterator) -> std::result::Result, ()> +where + T: PartialEq, +{ + values.into_iter().try_fold(None, |acc, item| match acc { + None => Ok(Some(item)), + Some(ref prev) if *prev != item => Err(()), + Some(x) => Ok(Some(x)), + }) +} + +fn serialize_addresses(addresses: impl Iterator) -> Vec> { + addresses.map(|a| a.to_vec()).collect() +} + +fn serialize_authority_record(addresses: Vec>) -> Result> { + let mut serialized_record = vec![]; + schema::AuthorityRecord { addresses } + .encode(&mut serialized_record) + .map_err(Error::EncodingProto)?; + Ok(serialized_record) +} + +fn sign_record_with_peer_id( + serialized_record: &[u8], + network: &impl NetworkSigner, +) -> Result { + let signature = network + .sign_with_local_identity(serialized_record) + .map_err(|_| Error::Signing)?; + let public_key = signature.public_key.to_protobuf_encoding(); + let signature = signature.bytes; + Ok(schema::PeerSignature { signature, public_key }) +} + +async fn sign_record_with_authority_ids( + serialized_record: Vec, + peer_signature: Option, + key_store: &dyn CryptoStore, + keys: Vec, +) -> Result)>> { + let signatures = key_store + .sign_with_all(key_types::AUTHORITY_DISCOVERY, keys.clone(), &serialized_record) + .await + .map_err(|_| Error::Signing)?; + + let mut result = vec![]; + for (sign_result, key) in signatures.into_iter().zip(keys.iter()) { + let mut signed_record = vec![]; + + // Verify that all signatures exist for all provided keys. + let auth_signature = + sign_result.ok().flatten().ok_or_else(|| Error::MissingSignature(key.clone()))?; + schema::SignedAuthorityRecord { + record: serialized_record.clone(), + auth_signature, + peer_signature: peer_signature.clone(), + } + .encode(&mut signed_record) + .map_err(Error::EncodingProto)?; + + result.push((hash_authority_id(key.1.as_ref()), signed_record)); + } + + Ok(result) } /// Prometheus metrics for a [`Worker`]. diff --git a/client/authority-discovery/src/worker/schema/dht.proto b/client/authority-discovery/src/worker/schema/dht-v1.proto similarity index 90% rename from client/authority-discovery/src/worker/schema/dht.proto rename to client/authority-discovery/src/worker/schema/dht-v1.proto index 9dbe9d559f4b1..0ef628888c093 100644 --- a/client/authority-discovery/src/worker/schema/dht.proto +++ b/client/authority-discovery/src/worker/schema/dht-v1.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package authority_discovery; +package authority_discovery_v1; // First we need to serialize the addresses in order to be able to sign them. message AuthorityAddresses { @@ -11,4 +11,4 @@ message AuthorityAddresses { message SignedAuthorityAddresses { bytes addresses = 1; bytes signature = 2; -} +} \ No newline at end of file diff --git a/client/authority-discovery/src/worker/schema/dht-v2.proto b/client/authority-discovery/src/worker/schema/dht-v2.proto new file mode 100644 index 0000000000000..c63f6c1767351 --- /dev/null +++ b/client/authority-discovery/src/worker/schema/dht-v2.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + +package authority_discovery_v2; + +// First we need to serialize the addresses in order to be able to sign them. +message AuthorityRecord { + // Possibly multiple `MultiAddress`es through which the node can be + repeated bytes addresses = 1; +} + +message PeerSignature { + bytes signature = 1; + bytes public_key = 2; +} + +// Then we need to serialize the authority record and signature to send them over the wire. +message SignedAuthorityRecord { + bytes record = 1; + bytes auth_signature = 2; + // Even if there are multiple `record.addresses`, all of them have the same peer id. + // Old versions are missing this field, so `optional` will provide compatibility both ways. + optional PeerSignature peer_signature = 3; +} diff --git a/client/authority-discovery/src/worker/schema/tests.rs b/client/authority-discovery/src/worker/schema/tests.rs new file mode 100644 index 0000000000000..ef96078411e97 --- /dev/null +++ b/client/authority-discovery/src/worker/schema/tests.rs @@ -0,0 +1,90 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +mod schema_v1 { + include!(concat!(env!("OUT_DIR"), "/authority_discovery_v1.rs")); +} + +use super::*; +use libp2p::multiaddr::Multiaddr; +use prost::Message; +use sc_network::PeerId; + +#[test] +fn v2_decodes_v1() { + let peer_id = PeerId::random(); + let multiaddress: Multiaddr = + format!("/ip4/127.0.0.1/tcp/3003/p2p/{}", peer_id).parse().unwrap(); + let vec_addresses = vec![multiaddress.to_vec()]; + let vec_auth_signature = b"Totally valid signature, I promise!".to_vec(); + + let addresses_v1 = schema_v1::AuthorityAddresses { addresses: vec_addresses.clone() }; + let mut vec_addresses_v1 = vec![]; + addresses_v1.encode(&mut vec_addresses_v1).unwrap(); + let signed_addresses_v1 = schema_v1::SignedAuthorityAddresses { + addresses: vec_addresses_v1.clone(), + signature: vec_auth_signature.clone(), + }; + let mut vec_signed_addresses_v1 = vec![]; + signed_addresses_v1.encode(&mut vec_signed_addresses_v1).unwrap(); + + let signed_record_v2_decoded = + SignedAuthorityRecord::decode(vec_signed_addresses_v1.as_slice()).unwrap(); + + assert_eq!(&signed_record_v2_decoded.record, &vec_addresses_v1); + assert_eq!(&signed_record_v2_decoded.auth_signature, &vec_auth_signature); + assert_eq!(&signed_record_v2_decoded.peer_signature, &None); + + let record_v2_decoded = AuthorityRecord::decode(vec_addresses_v1.as_slice()).unwrap(); + assert_eq!(&record_v2_decoded.addresses, &vec_addresses); +} + +#[test] +fn v1_decodes_v2() { + let peer_secret = sc_network::Keypair::generate_ed25519(); + let peer_public = peer_secret.public(); + let peer_id = peer_public.to_peer_id(); + let multiaddress: Multiaddr = + format!("/ip4/127.0.0.1/tcp/3003/p2p/{}", peer_id).parse().unwrap(); + let vec_addresses = vec![multiaddress.to_vec()]; + let vec_auth_signature = b"Totally valid signature, I promise!".to_vec(); + let vec_peer_signature = b"Surprisingly hard to crack crypto".to_vec(); + + let record_v2 = AuthorityRecord { addresses: vec_addresses.clone() }; + let mut vec_record_v2 = vec![]; + record_v2.encode(&mut vec_record_v2).unwrap(); + let vec_peer_public = peer_public.to_protobuf_encoding(); + let peer_signature_v2 = + PeerSignature { public_key: vec_peer_public, signature: vec_peer_signature }; + let signed_record_v2 = SignedAuthorityRecord { + record: vec_record_v2.clone(), + auth_signature: vec_auth_signature.clone(), + peer_signature: Some(peer_signature_v2.clone()), + }; + let mut vec_signed_record_v2 = vec![]; + signed_record_v2.encode(&mut vec_signed_record_v2).unwrap(); + + let signed_addresses_v1_decoded = + schema_v1::SignedAuthorityAddresses::decode(vec_signed_record_v2.as_slice()).unwrap(); + + assert_eq!(&signed_addresses_v1_decoded.addresses, &vec_record_v2); + assert_eq!(&signed_addresses_v1_decoded.signature, &vec_auth_signature); + + let addresses_v2_decoded = AuthorityRecord::decode(vec_record_v2.as_slice()).unwrap(); + assert_eq!(&addresses_v2_decoded.addresses, &vec_addresses); +} diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index 130aea71fdfb0..1129427ac8680 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -16,8 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::worker::schema; - use std::{ collections::HashSet, sync::{Arc, Mutex}, @@ -32,11 +30,10 @@ use futures::{ sink::SinkExt, task::LocalSpawn, }; -use libp2p::{core::multiaddr, kad, PeerId}; +use libp2p::{core::multiaddr, PeerId}; use prometheus_endpoint::prometheus::default_registry; use sp_api::{ApiRef, ProvideRuntimeApi}; -use sp_core::crypto::Public; use sp_keystore::{testing::KeyStore, CryptoStore}; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; use substrate_test_runtime_client::runtime::Block; @@ -114,17 +111,18 @@ sp_api::mock_impl_runtime_apis! { #[derive(Debug)] pub enum TestNetworkEvent { - GetCalled(kad::record::Key), - PutCalled(kad::record::Key, Vec), + GetCalled(sc_network::KademliaKey), + PutCalled(sc_network::KademliaKey, Vec), } pub struct TestNetwork { peer_id: PeerId, + identity: sc_network::Keypair, external_addresses: Vec, // Whenever functions on `TestNetwork` are called, the function arguments are added to the // vectors below. - pub put_value_call: Arc)>>>, - pub get_value_call: Arc>>, + pub put_value_call: Arc)>>>, + pub get_value_call: Arc>>, event_sender: mpsc::UnboundedSender, event_receiver: Option>, } @@ -138,8 +136,10 @@ impl TestNetwork { impl Default for TestNetwork { fn default() -> Self { let (tx, rx) = mpsc::unbounded(); + let identity = sc_network::Keypair::generate_ed25519(); TestNetwork { - peer_id: PeerId::random(), + peer_id: identity.public().to_peer_id(), + identity, external_addresses: vec!["/ip6/2001:db8::/tcp/30333".parse().unwrap()], put_value_call: Default::default(), get_value_call: Default::default(), @@ -149,16 +149,25 @@ impl Default for TestNetwork { } } +impl NetworkSigner for TestNetwork { + fn sign_with_local_identity( + &self, + msg: impl AsRef<[u8]>, + ) -> std::result::Result { + sc_network::Signature::sign_message(msg, &self.identity) + } +} + #[async_trait] impl NetworkProvider for TestNetwork { - fn put_value(&self, key: kad::record::Key, value: Vec) { + fn put_value(&self, key: sc_network::KademliaKey, value: Vec) { self.put_value_call.lock().unwrap().push((key.clone(), value.clone())); self.event_sender .clone() .unbounded_send(TestNetworkEvent::PutCalled(key, value)) .unwrap(); } - fn get_value(&self, key: &kad::record::Key) { + fn get_value(&self, key: &sc_network::KademliaKey) { self.get_value_call.lock().unwrap().push(key.clone()); self.event_sender .clone() @@ -177,35 +186,35 @@ impl NetworkStateInfo for TestNetwork { } } -async fn build_dht_event( +impl NetworkSigner for sc_network::Keypair { + fn sign_with_local_identity( + &self, + msg: impl AsRef<[u8]>, + ) -> std::result::Result { + sc_network::Signature::sign_message(msg, self) + } +} + +async fn build_dht_event( addresses: Vec, public_key: AuthorityId, - key_store: &KeyStore, -) -> (libp2p::kad::record::Key, Vec) { - let mut serialized_addresses = vec![]; - schema::AuthorityAddresses { addresses: addresses.into_iter().map(|a| a.to_vec()).collect() } - .encode(&mut serialized_addresses) - .map_err(Error::EncodingProto) - .unwrap(); - - let signature = key_store - .sign_with( - key_types::AUTHORITY_DISCOVERY, - &public_key.clone().into(), - serialized_addresses.as_slice(), - ) - .await - .unwrap() - .unwrap(); - - let mut signed_addresses = vec![]; - schema::SignedAuthorityAddresses { addresses: serialized_addresses.clone(), signature } - .encode(&mut signed_addresses) - .unwrap(); - - let key = hash_authority_id(&public_key.to_raw_vec()); - let value = signed_addresses; - (key, value) + key_store: &dyn CryptoStore, + network: Option<&Signer>, +) -> Vec<(sc_network::KademliaKey, Vec)> { + let serialized_record = + serialize_authority_record(serialize_addresses(addresses.into_iter())).unwrap(); + + let peer_signature = network.map(|n| sign_record_with_peer_id(&serialized_record, n).unwrap()); + let kv_pairs = sign_record_with_authority_ids( + serialized_record, + peer_signature, + key_store, + vec![public_key.into()], + ) + .await + .unwrap(); + // There is always a single item in it, because we signed it with a single key + kv_pairs } #[test] @@ -453,13 +462,14 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { // Make previously triggered lookup succeed. let dht_event = { - let (key, value) = build_dht_event( + let kv_pairs = build_dht_event::( vec![remote_multiaddr.clone()], remote_public_key.clone(), &remote_key_store, + None, ) .await; - sc_network::DhtEvent::ValueFound(vec![(key, value)]) + sc_network::DhtEvent::ValueFound(kv_pairs) }; dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); @@ -474,97 +484,191 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { }); } -#[test] -fn limit_number_of_addresses_added_to_cache_per_authority() { - let remote_key_store = KeyStore::new(); - let remote_public = - block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)) - .unwrap(); +struct DhtValueFoundTester { + pub remote_key_store: KeyStore, + pub remote_authority_public: sp_core::sr25519::Public, + pub remote_node_key: sc_network::Keypair, + pub local_worker: Option< + Worker< + TestApi, + TestNetwork, + sp_runtime::generic::Block< + sp_runtime::generic::Header, + substrate_test_runtime_client::runtime::Extrinsic, + >, + std::pin::Pin>>, + >, + >, +} - let addresses = (0..100) - .map(|_| { - let peer_id = PeerId::random(); - let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap(); - address.with(multiaddr::Protocol::P2p(peer_id.into())) - }) - .collect(); +impl DhtValueFoundTester { + fn new() -> Self { + let remote_key_store = KeyStore::new(); + let remote_authority_public = + block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)) + .unwrap(); - let dht_event = block_on(build_dht_event(addresses, remote_public.into(), &remote_key_store)); + let remote_node_key = sc_network::Keypair::generate_ed25519(); + Self { remote_key_store, remote_authority_public, remote_node_key, local_worker: None } + } - let (_dht_event_tx, dht_event_rx) = channel(1); + fn multiaddr_with_peer_id(&self, idx: u16) -> Multiaddr { + let peer_id = self.remote_node_key.public().to_peer_id(); + let address: Multiaddr = + format!("/ip6/2001:db8:0:0:0:0:0:{:x}/tcp/30333", idx).parse().unwrap(); - let (_to_worker, from_service) = mpsc::channel(0); - let mut worker = Worker::new( - from_service, - Arc::new(TestApi { authorities: vec![remote_public.into()] }), - Arc::new(TestNetwork::default()), - Box::pin(dht_event_rx), - Role::Discover, + address.with(multiaddr::Protocol::P2p(peer_id.into())) + } + + fn process_value_found( + &mut self, + strict_record_validation: bool, + values: Vec<(sc_network::KademliaKey, Vec)>, + ) -> Option<&HashSet> { + let (_dht_event_tx, dht_event_rx) = channel(1); + let local_test_api = + Arc::new(TestApi { authorities: vec![self.remote_authority_public.clone().into()] }); + let local_network: Arc = Arc::new(Default::default()); + let local_key_store = KeyStore::new(); + + let (_to_worker, from_service) = mpsc::channel(0); + let mut local_worker = Worker::new( + from_service, + local_test_api, + local_network.clone(), + Box::pin(dht_event_rx), + Role::PublishAndDiscover(Arc::new(local_key_store)), + None, + WorkerConfig { strict_record_validation, ..Default::default() }, + ); + + block_on(local_worker.refill_pending_lookups_queue()).unwrap(); + local_worker.start_new_lookups(); + + drop(local_worker.handle_dht_value_found_event(values)); + + self.local_worker = Some(local_worker); + + self.local_worker + .as_ref() + .map(|w| { + w.addr_cache + .get_addresses_by_authority_id(&self.remote_authority_public.clone().into()) + }) + .unwrap() + } +} + +#[test] +fn limit_number_of_addresses_added_to_cache_per_authority() { + let mut tester = DhtValueFoundTester::new(); + assert!(MAX_ADDRESSES_PER_AUTHORITY < 100); + let addresses = (1..100).map(|i| tester.multiaddr_with_peer_id(i)).collect(); + let kv_pairs = block_on(build_dht_event::( + addresses, + tester.remote_authority_public.clone().into(), + &tester.remote_key_store, None, - Default::default(), - ); + )); + + let cached_remote_addresses = tester.process_value_found(false, kv_pairs); + assert_eq!(MAX_ADDRESSES_PER_AUTHORITY, cached_remote_addresses.unwrap().len()); +} + +#[test] +fn strict_accept_address_with_peer_signature() { + let mut tester = DhtValueFoundTester::new(); + let addr = tester.multiaddr_with_peer_id(1); + let kv_pairs = block_on(build_dht_event( + vec![addr.clone()], + tester.remote_authority_public.clone().into(), + &tester.remote_key_store, + Some(&tester.remote_node_key), + )); - block_on(worker.refill_pending_lookups_queue()).unwrap(); - worker.start_new_lookups(); + let cached_remote_addresses = tester.process_value_found(true, kv_pairs); - worker.handle_dht_value_found_event(vec![dht_event]).unwrap(); assert_eq!( - MAX_ADDRESSES_PER_AUTHORITY, - worker - .addr_cache - .get_addresses_by_authority_id(&remote_public.into()) - .unwrap() - .len(), + Some(&HashSet::from([addr])), + cached_remote_addresses, + "Expect worker to only cache `Multiaddr`s with `PeerId`s.", ); } #[test] -fn do_not_cache_addresses_without_peer_id() { - let remote_key_store = KeyStore::new(); - let remote_public = - block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)) - .unwrap(); - - let multiaddr_with_peer_id = { - let peer_id = PeerId::random(); - let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333".parse().unwrap(); +fn reject_address_with_rogue_peer_signature() { + let mut tester = DhtValueFoundTester::new(); + let rogue_remote_node_key = sc_network::Keypair::generate_ed25519(); + let kv_pairs = block_on(build_dht_event( + vec![tester.multiaddr_with_peer_id(1)], + tester.remote_authority_public.clone().into(), + &tester.remote_key_store, + Some(&rogue_remote_node_key), + )); - address.with(multiaddr::Protocol::P2p(peer_id.into())) - }; + let cached_remote_addresses = tester.process_value_found(false, kv_pairs); - let multiaddr_without_peer_id: Multiaddr = - "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap(); + assert!( + cached_remote_addresses.is_none(), + "Expected worker to ignore record signed by a different key.", + ); +} - let dht_event = block_on(build_dht_event( - vec![multiaddr_with_peer_id.clone(), multiaddr_without_peer_id], - remote_public.into(), - &remote_key_store, +#[test] +fn reject_address_with_invalid_peer_signature() { + let mut tester = DhtValueFoundTester::new(); + let mut kv_pairs = block_on(build_dht_event( + vec![tester.multiaddr_with_peer_id(1)], + tester.remote_authority_public.clone().into(), + &tester.remote_key_store, + Some(&tester.remote_node_key), )); + // tamper with the signature + let mut record = schema::SignedAuthorityRecord::decode(kv_pairs[0].1.as_slice()).unwrap(); + record.peer_signature.as_mut().map(|p| p.signature[1] += 1); + record.encode(&mut kv_pairs[0].1).unwrap(); - let (_dht_event_tx, dht_event_rx) = channel(1); - let local_test_api = Arc::new(TestApi { authorities: vec![remote_public.into()] }); - let local_network: Arc = Arc::new(Default::default()); - let local_key_store = KeyStore::new(); + let cached_remote_addresses = tester.process_value_found(false, kv_pairs); - let (_to_worker, from_service) = mpsc::channel(0); - let mut local_worker = Worker::new( - from_service, - local_test_api, - local_network.clone(), - Box::pin(dht_event_rx), - Role::PublishAndDiscover(Arc::new(local_key_store)), - None, - Default::default(), + assert!( + cached_remote_addresses.is_none(), + "Expected worker to ignore record with tampered signature.", ); +} + +#[test] +fn reject_address_without_peer_signature() { + let mut tester = DhtValueFoundTester::new(); + let kv_pairs = block_on(build_dht_event::( + vec![tester.multiaddr_with_peer_id(1)], + tester.remote_authority_public.clone().into(), + &tester.remote_key_store, + None, + )); - block_on(local_worker.refill_pending_lookups_queue()).unwrap(); - local_worker.start_new_lookups(); + let cached_remote_addresses = tester.process_value_found(true, kv_pairs); - local_worker.handle_dht_value_found_event(vec![dht_event]).unwrap(); + assert!(cached_remote_addresses.is_none(), "Expected worker to ignore unsigned record.",); +} + +#[test] +fn do_not_cache_addresses_without_peer_id() { + let mut tester = DhtValueFoundTester::new(); + let multiaddr_with_peer_id = tester.multiaddr_with_peer_id(1); + let multiaddr_without_peer_id: Multiaddr = + "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333".parse().unwrap(); + let kv_pairs = block_on(build_dht_event::( + vec![multiaddr_with_peer_id.clone(), multiaddr_without_peer_id], + tester.remote_authority_public.clone().into(), + &tester.remote_key_store, + None, + )); + + let cached_remote_addresses = tester.process_value_found(false, kv_pairs); assert_eq!( Some(&HashSet::from([multiaddr_with_peer_id])), - local_worker.addr_cache.get_addresses_by_authority_id(&remote_public.into()), + cached_remote_addresses, "Expect worker to only cache `Multiaddr`s with `PeerId`s.", ); } @@ -697,10 +801,14 @@ fn lookup_throttling() { let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap(); let remote_key: AuthorityId = remote_hash_to_key.get(&remote_hash).unwrap().clone(); let dht_event = { - let (key, value) = - build_dht_event(vec![remote_multiaddr.clone()], remote_key, &remote_key_store) - .await; - sc_network::DhtEvent::ValueFound(vec![(key, value)]) + let kv_pairs = build_dht_event::( + vec![remote_multiaddr.clone()], + remote_key, + &remote_key_store, + None, + ) + .await; + sc_network::DhtEvent::ValueFound(kv_pairs) }; dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 965e68336e3bc..d5a7fd93d7dc7 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -420,8 +420,6 @@ impl KeystoreInner { /// Write the given `data` to `file`. fn write_to_file(file: PathBuf, data: &str) -> Result<()> { let mut file = File::create(file)?; - serde_json::to_writer(&file, data)?; - file.flush()?; #[cfg(target_family = "unix")] { @@ -429,6 +427,8 @@ impl KeystoreInner { file.set_permissions(fs::Permissions::from_mode(0o600))?; } + serde_json::to_writer(&file, data)?; + file.flush()?; Ok(()) } diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index cb16eb163ee46..d07e9d3baaa42 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -273,8 +273,9 @@ pub use protocol::{ PeerInfo, }; pub use service::{ - IfDisconnected, NetworkService, NetworkWorker, NotificationSender, NotificationSenderReady, - OutboundFailure, RequestFailure, + DecodingError, IfDisconnected, KademliaKey, Keypair, NetworkService, NetworkWorker, + NotificationSender, NotificationSenderReady, OutboundFailure, PublicKey, RequestFailure, + Signature, SigningError, }; pub use sc_peerset::ReputationChange; diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 4377ff358de7b..e03bdcfa2f7ed 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -54,7 +54,6 @@ use libp2p::{ either::EitherError, upgrade, ConnectedPoint, Executor, }, - kad::record, multiaddr, ping::Failure as PingFailure, swarm::{ @@ -93,9 +92,19 @@ pub use behaviour::{ mod metrics; mod out_events; +mod signature; #[cfg(test)] mod tests; +pub use libp2p::{ + identity::{ + error::{DecodingError, SigningError}, + Keypair, PublicKey, + }, + kad::record::Key as KademliaKey, +}; +pub use signature::*; + /// Substrate network service. Handles network IO and manages connectivity. pub struct NetworkService { /// Number of peers we're connected to. @@ -106,6 +115,8 @@ pub struct NetworkService { is_major_syncing: Arc, /// Local copy of the `PeerId` of the local node. local_peer_id: PeerId, + /// The `KeyPair` that defines the `PeerId` of the local node. + local_identity: Keypair, /// Bandwidth logging system. Can be queried to know the average bandwidth consumed. bandwidth: Arc, /// Peerset manager (PSM); manages the reputation of nodes and indicates the network which @@ -318,7 +329,7 @@ impl NetworkWorker { }; transport::build_transport( - local_identity, + local_identity.clone(), config_mem, params.network_config.yamux_window_size, yamux_maximum_buffer_size, @@ -406,6 +417,7 @@ impl NetworkWorker { is_major_syncing: is_major_syncing.clone(), peerset: peerset_handle, local_peer_id, + local_identity, to_worker, peers_notifications_sinks: peers_notifications_sinks.clone(), notifications_sizes_metric: metrics @@ -667,6 +679,14 @@ impl NetworkService { &self.local_peer_id } + /// Signs the message with the `KeyPair` that defined the local `PeerId`. + pub fn sign_with_local_identity( + &self, + msg: impl AsRef<[u8]>, + ) -> Result { + Signature::sign_message(msg.as_ref(), &self.local_identity) + } + /// Set authorized peers. /// /// Need a better solution to manage authorized peers, but now just use reserved peers for @@ -1024,7 +1044,7 @@ impl NetworkService { /// /// This will generate either a `ValueFound` or a `ValueNotFound` event and pass it as an /// item on the [`NetworkWorker`] stream. - pub fn get_value(&self, key: &record::Key) { + pub fn get_value(&self, key: &KademliaKey) { let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::GetValue(key.clone())); } @@ -1032,7 +1052,7 @@ impl NetworkService { /// /// This will generate either a `ValuePut` or a `ValuePutFailed` event and pass it as an /// item on the [`NetworkWorker`] stream. - pub fn put_value(&self, key: record::Key, value: Vec) { + pub fn put_value(&self, key: KademliaKey, value: Vec) { let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::PutValue(key, value)); } @@ -1393,8 +1413,8 @@ enum ServiceToWorkerMsg { RequestJustification(B::Hash, NumberFor), ClearJustificationRequests, AnnounceBlock(B::Hash, Option>), - GetValue(record::Key), - PutValue(record::Key, Vec), + GetValue(KademliaKey), + PutValue(KademliaKey, Vec), AddKnownAddress(PeerId, Multiaddr), SetReservedOnly(bool), AddReserved(PeerId), diff --git a/client/network/src/service/signature.rs b/client/network/src/service/signature.rs new file mode 100644 index 0000000000000..c2d6c4f7db6e8 --- /dev/null +++ b/client/network/src/service/signature.rs @@ -0,0 +1,50 @@ +// This file is part of Substrate. +// +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// If you read this, you are very thorough, congratulations. + +use super::*; + +/// A result of signing a message with a network identity. Since `PeerId` is potentially a hash of a +/// `PublicKey`, you need to reveal the `PublicKey` next to the signature, so the verifier can check +/// if the signature was made by the entity that controls a given `PeerId`. +pub struct Signature { + /// The public key derived from the network identity that signed the message. + pub public_key: PublicKey, + /// The actual signature made for the message signed. + pub bytes: Vec, +} + +impl Signature { + /// Create a signature for a message with a given network identity. + pub fn sign_message( + message: impl AsRef<[u8]>, + keypair: &Keypair, + ) -> Result { + let public_key = keypair.public(); + let bytes = keypair.sign(message.as_ref())?; + Ok(Self { public_key, bytes }) + } + + /// Verify whether the signature was made for the given message by the entity that controls the + /// given `PeerId`. + pub fn verify(&self, message: impl AsRef<[u8]>, peer_id: &PeerId) -> bool { + *peer_id == self.public_key.to_peer_id() && + self.public_key.verify(message.as_ref(), &self.bytes) + } +} From 0e6cc5668d9ee8d852a3aa3f85a2ab5fcb4c75a1 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Tue, 7 Dec 2021 00:31:13 +1300 Subject: [PATCH 0303/1472] allow tip value of 1 (#10425) * allow tip value of 1 * update comment * fmt * update test * fmt --- frame/transaction-payment/src/lib.rs | 56 ++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index ed96f26cc0079..02ba9621c175d 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -52,8 +52,8 @@ use scale_info::TypeInfo; use sp_runtime::{ traits::{ - Convert, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating, - SignedExtension, Zero, + Convert, DispatchInfoOf, Dispatchable, One, PostDispatchInfoOf, SaturatedConversion, + Saturating, SignedExtension, Zero, }, transaction_validity::{ TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction, @@ -649,9 +649,9 @@ where .saturated_into::>(); let max_reward = |val: BalanceOf| val.saturating_mul(max_tx_per_block); - // To distribute no-tip transactions a little bit, we set the minimal tip as `1`. + // To distribute no-tip transactions a little bit, we increase the tip value by one. // This means that given two transactions without a tip, smaller one will be preferred. - let tip = tip.max(1.saturated_into()); + let tip = tip.saturating_add(One::one()); let scaled_tip = max_reward(tip); match info.class { @@ -1480,14 +1480,14 @@ mod tests { .unwrap() .priority; - assert_eq!(priority, 50); + assert_eq!(priority, 60); let priority = ChargeTransactionPayment::(2 * tip) .validate(&2, CALL, &normal, len) .unwrap() .priority; - assert_eq!(priority, 100); + assert_eq!(priority, 110); }); ExtBuilder::default().balance_factor(100).build().execute_with(|| { @@ -1500,13 +1500,13 @@ mod tests { .validate(&2, CALL, &op, len) .unwrap() .priority; - assert_eq!(priority, 5800); + assert_eq!(priority, 5810); let priority = ChargeTransactionPayment::(2 * tip) .validate(&2, CALL, &op, len) .unwrap() .priority; - assert_eq!(priority, 6100); + assert_eq!(priority, 6110); }); } @@ -1540,6 +1540,46 @@ mod tests { }); } + #[test] + fn higher_tip_have_higher_priority() { + let get_priorities = |tip: u64| { + let mut priority1 = 0; + let mut priority2 = 0; + let len = 10; + ExtBuilder::default().balance_factor(100).build().execute_with(|| { + let normal = + DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; + priority1 = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &normal, len) + .unwrap() + .priority; + }); + + ExtBuilder::default().balance_factor(100).build().execute_with(|| { + let op = DispatchInfo { + weight: 100, + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + priority2 = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &op, len) + .unwrap() + .priority; + }); + + (priority1, priority2) + }; + + let mut prev_priorities = get_priorities(0); + + for tip in 1..3 { + let priorities = get_priorities(tip); + assert!(prev_priorities.0 < priorities.0); + assert!(prev_priorities.1 < priorities.1); + prev_priorities = priorities; + } + } + #[test] fn post_info_can_change_pays_fee() { ExtBuilder::default() From f0b85c6024296519913ca6f748bb3081f1b4bacd Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Mon, 6 Dec 2021 13:31:16 -0800 Subject: [PATCH 0304/1472] Add baseline benchmark for sr25519 verification (#10414) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add baseline benchmark for sr25519 verification * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=frame_benchmarking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/benchmarking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Register keystore for correct test externalities * Update frame/benchmarking/src/baseline.rs Co-authored-by: Bastian Köcher * fix build Co-authored-by: Parity Bot Co-authored-by: Bastian Köcher --- Cargo.lock | 2 ++ frame/benchmarking/Cargo.toml | 2 ++ frame/benchmarking/src/baseline.rs | 41 +++++++++++++++++++++-- frame/benchmarking/src/weights.rs | 54 +++++++++++++++++++----------- 4 files changed, 77 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d277db3f519b9..d67ebd7f24ddf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1958,7 +1958,9 @@ dependencies = [ "paste 1.0.6", "scale-info", "sp-api", + "sp-application-crypto", "sp-io", + "sp-keystore", "sp-runtime", "sp-runtime-interface", "sp-std", diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 2bf4a53b0f424..4160f040c3bcb 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -22,6 +22,7 @@ sp-runtime-interface = { version = "4.0.0-dev", path = "../../primitives/runtime sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0-dev", path = "../../primitives/std", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } +sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto", default-features = false } sp-storage = { version = "4.0.0-dev", path = "../../primitives/storage", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -29,6 +30,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] hex-literal = "0.3.4" +sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } [features] default = ["std"] diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 2b924a692129a..87cdf80409b89 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -23,9 +23,23 @@ use crate::benchmarks; use codec::Encode; use frame_system::Pallet as System; -use sp_runtime::traits::Hash; +use sp_application_crypto::KeyTypeId; +use sp_runtime::{ + traits::{AppVerify, Hash}, + RuntimeAppPublic, +}; use sp_std::prelude::*; +pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test"); + +mod app_sr25519 { + use super::TEST_KEY_TYPE_ID; + use sp_application_crypto::{app_crypto, sr25519}; + app_crypto!(sr25519, TEST_KEY_TYPE_ID); +} + +type SignerId = app_sr25519::Public; + pub struct Pallet(System); pub trait Config: frame_system::Config {} @@ -75,6 +89,23 @@ benchmarks! { assert!(hash != T::Hash::default()); } + sr25519_verification { + let i in 1 .. 100; + + let public = SignerId::generate_pair(None); + + let sigs_count: u8 = i.try_into().unwrap(); + let msg_and_sigs: Vec<_> = (0..sigs_count).map(|j| { + let msg = vec![j, j]; + (msg.clone(), public.sign(&msg).unwrap()) + }) + .collect(); + }: { + msg_and_sigs.iter().for_each(|(msg, sig)| { + assert!(sig.verify(&msg[..], &public)); + }); + } + #[skip_meta] storage_read { let i in 0 .. 1_000; @@ -169,7 +200,13 @@ pub mod mock { impl super::Config for Test {} pub fn new_test_ext() -> sp_io::TestExternalities { + use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStorePtr}; + use sp_std::sync::Arc; + let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - sp_io::TestExternalities::new(t) + let mut ext = sp_io::TestExternalities::new(t); + ext.register_extension(KeystoreExt(Arc::new(KeyStore::new()) as SyncCryptoStorePtr)); + + ext } } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index 807ff697fdcaa..af0a782e6b2c5 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for frame_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-10-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-12-02, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -35,7 +35,6 @@ // --output=./frame/benchmarking/src/weights.rs // --template=./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -50,6 +49,7 @@ pub trait WeightInfo { fn multiplication(i: u32, ) -> Weight; fn division(i: u32, ) -> Weight; fn hashing(i: u32, ) -> Weight; + fn sr25519_verification(i: u32, ) -> Weight; fn storage_read(i: u32, ) -> Weight; fn storage_write(i: u32, ) -> Weight; } @@ -58,32 +58,39 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn addition(_i: u32, ) -> Weight { - (337_000 as Weight) + (284_000 as Weight) } fn subtraction(_i: u32, ) -> Weight { - (343_000 as Weight) + (279_000 as Weight) } fn multiplication(_i: u32, ) -> Weight { - (340_000 as Weight) + (278_000 as Weight) } fn division(_i: u32, ) -> Weight { - (346_000 as Weight) + (274_000 as Weight) + } + fn hashing(i: u32, ) -> Weight { + (33_441_957_000 as Weight) + // Standard Error: 535_000 + .saturating_add((363_000 as Weight).saturating_mul(i as Weight)) } - fn hashing(_i: u32, ) -> Weight { - (35_449_143_000 as Weight) + fn sr25519_verification(i: u32, ) -> Weight { + (26_000 as Weight) + // Standard Error: 14_000 + .saturating_add((48_151_000 as Weight).saturating_mul(i as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_000 - .saturating_add((2_851_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 4_000 + .saturating_add((2_694_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((662_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((606_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } } @@ -91,32 +98,39 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn addition(_i: u32, ) -> Weight { - (337_000 as Weight) + (284_000 as Weight) } fn subtraction(_i: u32, ) -> Weight { - (343_000 as Weight) + (279_000 as Weight) } fn multiplication(_i: u32, ) -> Weight { - (340_000 as Weight) + (278_000 as Weight) } fn division(_i: u32, ) -> Weight { - (346_000 as Weight) + (274_000 as Weight) + } + fn hashing(i: u32, ) -> Weight { + (33_441_957_000 as Weight) + // Standard Error: 535_000 + .saturating_add((363_000 as Weight).saturating_mul(i as Weight)) } - fn hashing(_i: u32, ) -> Weight { - (35_449_143_000 as Weight) + fn sr25519_verification(i: u32, ) -> Weight { + (26_000 as Weight) + // Standard Error: 14_000 + .saturating_add((48_151_000 as Weight).saturating_mul(i as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_000 - .saturating_add((2_851_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 4_000 + .saturating_add((2_694_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((662_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((606_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } } From 264da3bedca973f0028c1e521e96327e2e72c35d Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Tue, 7 Dec 2021 00:35:45 +0200 Subject: [PATCH 0305/1472] Minor documentation update for `AuxStore` and `BlockImportParams.auxiliary` (#10428) --- client/api/src/backend.rs | 4 ++++ client/consensus/common/src/block_import.rs | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index a681d75fe9af3..f300e31f826c9 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -259,6 +259,10 @@ pub trait Finalizer> { } /// Provides access to an auxiliary database. +/// +/// This is a simple global database not aware of forks. Can be used for storing auxiliary +/// information like total block weight/difficulty for fork resolution purposes as a common use +/// case. pub trait AuxStore { /// Insert auxiliary data into key-value store. /// diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index 03fde159736ca..aff16566e0de4 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -190,8 +190,9 @@ pub struct BlockImportParams { /// rejects block import if there are still intermediate values that remain unhandled. pub intermediates: HashMap, Box>, /// Auxiliary consensus data produced by the block. - /// Contains a list of key-value pairs. If values are `None`, the keys - /// will be deleted. + /// Contains a list of key-value pairs. If values are `None`, the keys will be deleted. These + /// changes will be applied to `AuxStore` database all as one batch, which is more efficient + /// than updating `AuxStore` directly. pub auxiliary: Vec<(Vec, Option>)>, /// Fork choice strategy of this import. This should only be set by a /// synchronous import, otherwise it may race against other imports. From 6079539db562472bce2276cdf44dccef6c2b3a6f Mon Sep 17 00:00:00 2001 From: Ayevbeosa Iyamu Date: Tue, 7 Dec 2021 10:21:27 +0100 Subject: [PATCH 0306/1472] Used CountedStorageMap in pallet-staking (#10233) * Removed counters and used CountedStorageMap instead. * Little refactoring * Update frame/staking/src/migrations.rs Co-authored-by: Shawn Tabrizi * Removed redundant code to update counter for validator & nominator. * Removed redundant code to update counter for validator & nominator. * Removed unreachable code to inject the hashed prefix for nominator & validator. * Removed redundant check for nominator & validator count. * Generated `fn prefix_hash` for `CountedStorageMap`. * Applied changes from `cargo fmt` * Possible correct implementation of migration code * Implemented fn module_prefix, storage_prefix and prefix_hash. * Removed counted_map.rs * Renamed `fn storage_prefix` to `storage_counter_prefix`. * Update frame/support/src/storage/types/counted_map.rs * Update frame/bags-list/remote-tests/src/snapshot.rs * Update frame/support/src/storage/types/counted_map.rs * Fixed errors. Co-authored-by: Shawn Tabrizi Co-authored-by: Guillaume Thiolliere --- frame/bags-list/remote-tests/src/snapshot.rs | 9 +-- frame/staking/src/benchmarking.rs | 8 +-- frame/staking/src/migrations.rs | 20 +++++-- frame/staking/src/mock.rs | 4 +- frame/staking/src/pallet/impls.rs | 55 ++++++------------- frame/staking/src/pallet/mod.rs | 26 +++------ frame/staking/src/testing_utils.rs | 7 +-- frame/staking/src/tests.rs | 16 +++--- .../support/src/storage/types/counted_map.rs | 11 ++++ 9 files changed, 74 insertions(+), 82 deletions(-) diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index 0e68a4495edfc..f05c00cd9a244 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -27,6 +27,7 @@ pub async fn execute ws_url: String, ) { use frame_support::storage::generator::StorageMap; + let mut ext = Builder::::new() .mode(Mode::Online(OnlineConfig { transport: ws_url.to_string().into(), @@ -38,10 +39,10 @@ pub async fn execute })) .inject_hashed_prefix(&>::prefix_hash()) .inject_hashed_prefix(&>::prefix_hash()) - .inject_hashed_prefix(&>::prefix_hash()) - .inject_hashed_prefix(&>::prefix_hash()) - .inject_hashed_key(&>::hashed_key()) - .inject_hashed_key(&>::hashed_key()) + .inject_hashed_prefix(&>::map_storage_final_prefix()) + .inject_hashed_prefix(&>::map_storage_final_prefix()) + .inject_hashed_key(&>::counter_storage_final_key()) + .inject_hashed_key(&>::counter_storage_final_key()) .build() .await .unwrap(); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 69a73c51fdc7e..5b242e1f223a8 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -112,8 +112,8 @@ pub fn create_validator_with_nominators( assert_eq!(new_validators.len(), 1); assert_eq!(new_validators[0], v_stash, "Our validator was not selected!"); - assert_ne!(CounterForValidators::::get(), 0); - assert_ne!(CounterForNominators::::get(), 0); + assert_ne!(Validators::::count(), 0); + assert_ne!(Nominators::::count(), 0); // Give Era Points let reward = EraRewardPoints:: { @@ -922,8 +922,8 @@ mod tests { let count_validators = Validators::::iter().count(); let count_nominators = Nominators::::iter().count(); - assert_eq!(count_validators, CounterForValidators::::get() as usize); - assert_eq!(count_nominators, CounterForNominators::::get() as usize); + assert_eq!(count_validators, Validators::::count() as usize); + assert_eq!(count_nominators, Nominators::::count() as usize); assert_eq!(count_validators, v as usize); assert_eq!(count_nominators, n as usize); diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 6f1d3953f8f17..33f45d80870a3 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -70,10 +70,22 @@ pub mod v8 { pub mod v7 { use super::*; + use frame_support::generate_storage_alias; + + generate_storage_alias!(Staking, CounterForValidators => Value); + generate_storage_alias!(Staking, CounterForNominators => Value); pub fn pre_migrate() -> Result<(), &'static str> { - assert!(CounterForValidators::::get().is_zero(), "CounterForValidators already set."); - assert!(CounterForNominators::::get().is_zero(), "CounterForNominators already set."); + assert!( + CounterForValidators::get().unwrap().is_zero(), + "CounterForValidators already set." + ); + assert!( + CounterForNominators::get().unwrap().is_zero(), + "CounterForNominators already set." + ); + assert!(Validators::::count().is_zero(), "Validators already set."); + assert!(Nominators::::count().is_zero(), "Nominators already set."); assert!(StorageVersion::::get() == Releases::V6_0_0); Ok(()) } @@ -83,8 +95,8 @@ pub mod v7 { let validator_count = Validators::::iter().count() as u32; let nominator_count = Nominators::::iter().count() as u32; - CounterForValidators::::put(validator_count); - CounterForNominators::::put(nominator_count); + CounterForValidators::put(validator_count); + CounterForNominators::put(nominator_count); StorageVersion::::put(Releases::V7_0_0); log!(info, "Completed staking migration to Releases::V7_0_0"); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 0b1d6a06d9c7f..8a8ab1f1e4d04 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -536,8 +536,8 @@ fn post_conditions() { fn check_count() { let nominator_count = Nominators::::iter().count() as u32; let validator_count = Validators::::iter().count() as u32; - assert_eq!(nominator_count, CounterForNominators::::get()); - assert_eq!(validator_count, CounterForValidators::::get()); + assert_eq!(nominator_count, Nominators::::count()); + assert_eq!(validator_count, Validators::::count()); // the voters that the `SortedListProvider` list is storing for us. let external_voters = ::SortedListProvider::count(); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index cd26ff3b729c5..b3158c4ef6b3d 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -665,8 +665,8 @@ impl Pallet { maybe_max_len: Option, ) -> Vec<(T::AccountId, VoteWeight, Vec)> { let max_allowed_len = { - let nominator_count = CounterForNominators::::get() as usize; - let validator_count = CounterForValidators::::get() as usize; + let nominator_count = Nominators::::count() as usize; + let validator_count = Validators::::count() as usize; let all_voter_count = validator_count.saturating_add(nominator_count); maybe_max_len.unwrap_or(all_voter_count).min(all_voter_count) }; @@ -765,18 +765,15 @@ impl Pallet { } /// This function will add a nominator to the `Nominators` storage map, - /// [`SortedListProvider`] and keep track of the `CounterForNominators`. + /// and [`SortedListProvider`]. /// /// If the nominator already exists, their nominations will be updated. /// /// NOTE: you must ALWAYS use this function to add nominator or update their targets. Any access - /// to `Nominators`, its counter, or `VoterList` outside of this function is almost certainly + /// to `Nominators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { if !Nominators::::contains_key(who) { - // maybe update the counter. - CounterForNominators::::mutate(|x| x.saturating_inc()); - // maybe update sorted list. Error checking is defensive-only - this should never fail. if T::SortedListProvider::on_insert(who.clone(), Self::weight_of(who)).is_err() { log!(warn, "attempt to insert duplicate nominator ({:#?})", who); @@ -790,53 +787,46 @@ impl Pallet { } /// This function will remove a nominator from the `Nominators` storage map, - /// [`SortedListProvider`] and keep track of the `CounterForNominators`. + /// and [`SortedListProvider`]. /// /// Returns true if `who` was removed from `Nominators`, otherwise false. /// /// NOTE: you must ALWAYS use this function to remove a nominator from the system. Any access to - /// `Nominators`, its counter, or `VoterList` outside of this function is almost certainly + /// `Nominators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_remove_nominator(who: &T::AccountId) -> bool { if Nominators::::contains_key(who) { Nominators::::remove(who); - CounterForNominators::::mutate(|x| x.saturating_dec()); T::SortedListProvider::on_remove(who); debug_assert_eq!(T::SortedListProvider::sanity_check(), Ok(())); - debug_assert_eq!(CounterForNominators::::get(), T::SortedListProvider::count()); + debug_assert_eq!(Nominators::::count(), T::SortedListProvider::count()); true } else { false } } - /// This function will add a validator to the `Validators` storage map, and keep track of the - /// `CounterForValidators`. + /// This function will add a validator to the `Validators` storage map. /// /// If the validator already exists, their preferences will be updated. /// /// NOTE: you must ALWAYS use this function to add a validator to the system. Any access to - /// `Validators`, its counter, or `VoterList` outside of this function is almost certainly + /// `Validators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_add_validator(who: &T::AccountId, prefs: ValidatorPrefs) { - if !Validators::::contains_key(who) { - CounterForValidators::::mutate(|x| x.saturating_inc()) - } Validators::::insert(who, prefs); } - /// This function will remove a validator from the `Validators` storage map, - /// and keep track of the `CounterForValidators`. + /// This function will remove a validator from the `Validators` storage map. /// /// Returns true if `who` was removed from `Validators`, otherwise false. /// /// NOTE: you must ALWAYS use this function to remove a validator from the system. Any access to - /// `Validators`, its counter, or `VoterList` outside of this function is almost certainly + /// `Validators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_remove_validator(who: &T::AccountId) -> bool { if Validators::::contains_key(who) { Validators::::remove(who); - CounterForValidators::::mutate(|x| x.saturating_dec()); true } else { false @@ -865,14 +855,6 @@ impl ElectionDataProvider> for Pallet fn voters( maybe_max_len: Option, ) -> data_provider::Result)>> { - debug_assert!(>::iter().count() as u32 == CounterForNominators::::get()); - debug_assert!(>::iter().count() as u32 == CounterForValidators::::get()); - debug_assert_eq!( - CounterForNominators::::get(), - T::SortedListProvider::count(), - "voter_count must be accurate", - ); - // This can never fail -- if `maybe_max_len` is `Some(_)` we handle it. let voters = Self::get_npos_voters(maybe_max_len); debug_assert!(maybe_max_len.map_or(true, |max| voters.len() <= max)); @@ -881,7 +863,7 @@ impl ElectionDataProvider> for Pallet } fn targets(maybe_max_len: Option) -> data_provider::Result> { - let target_count = CounterForValidators::::get(); + let target_count = Validators::::count(); // We can't handle this case yet -- return an error. if maybe_max_len.map_or(false, |max_len| target_count > max_len as u32) { @@ -967,10 +949,9 @@ impl ElectionDataProvider> for Pallet fn clear() { >::remove_all(None); >::remove_all(None); - >::remove_all(None); - >::remove_all(None); - >::kill(); - >::kill(); + >::remove_all(); + >::remove_all(); + T::SortedListProvider::unsafe_clear(); } @@ -1284,7 +1265,7 @@ impl SortedListProvider for UseNominatorsMap { Box::new(Nominators::::iter().map(|(n, _)| n)) } fn count() -> u32 { - CounterForNominators::::get() + Nominators::::count() } fn contains(id: &T::AccountId) -> bool { Nominators::::contains_key(id) @@ -1309,10 +1290,10 @@ impl SortedListProvider for UseNominatorsMap { fn sanity_check() -> Result<(), &'static str> { Ok(()) } + fn unsafe_clear() { // NOTE: Caller must ensure this doesn't lead to too many storage accesses. This is a // condition of SortedListProvider::unsafe_clear. - Nominators::::remove_all(None); - CounterForNominators::::take(); + Nominators::::remove_all(); } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index f7e96ce0cf765..091df82e28172 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -234,16 +234,10 @@ pub mod pallet { StorageMap<_, Twox64Concat, T::AccountId, RewardDestination, ValueQuery>; /// The map from (wannabe) validator stash key to the preferences of that validator. - /// - /// When updating this storage item, you must also update the `CounterForValidators`. #[pallet::storage] #[pallet::getter(fn validators)] pub type Validators = - StorageMap<_, Twox64Concat, T::AccountId, ValidatorPrefs, ValueQuery>; - - /// A tracker to keep count of the number of items in the `Validators` map. - #[pallet::storage] - pub type CounterForValidators = StorageValue<_, u32, ValueQuery>; + CountedStorageMap<_, Twox64Concat, T::AccountId, ValidatorPrefs, ValueQuery>; /// The maximum validator count before we stop allowing new validators to join. /// @@ -252,16 +246,10 @@ pub mod pallet { pub type MaxValidatorsCount = StorageValue<_, u32, OptionQuery>; /// The map from nominator stash key to the set of stash keys of all validators to nominate. - /// - /// When updating this storage item, you must also update the `CounterForNominators`. #[pallet::storage] #[pallet::getter(fn nominators)] pub type Nominators = - StorageMap<_, Twox64Concat, T::AccountId, Nominations>; - - /// A tracker to keep count of the number of items in the `Nominators` map. - #[pallet::storage] - pub type CounterForNominators = StorageValue<_, u32, ValueQuery>; + CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations>; /// The maximum nominator count before we stop allowing new validators to join. /// @@ -570,7 +558,7 @@ pub mod pallet { // all voters are reported to the `SortedListProvider`. assert_eq!( T::SortedListProvider::count(), - CounterForNominators::::get(), + Nominators::::count(), "not all genesis stakers were inserted into sorted list provider, something is wrong." ); } @@ -987,7 +975,7 @@ pub mod pallet { // the runtime. if let Some(max_validators) = MaxValidatorsCount::::get() { ensure!( - CounterForValidators::::get() < max_validators, + Validators::::count() < max_validators, Error::::TooManyValidators ); } @@ -1027,7 +1015,7 @@ pub mod pallet { // the runtime. if let Some(max_nominators) = MaxNominatorsCount::::get() { ensure!( - CounterForNominators::::get() < max_nominators, + Nominators::::count() < max_nominators, Error::::TooManyNominators ); } @@ -1610,7 +1598,7 @@ pub mod pallet { let min_active_bond = if Nominators::::contains_key(&stash) { let max_nominator_count = MaxNominatorsCount::::get().ok_or(Error::::CannotChillOther)?; - let current_nominator_count = CounterForNominators::::get(); + let current_nominator_count = Nominators::::count(); ensure!( threshold * max_nominator_count < current_nominator_count, Error::::CannotChillOther @@ -1619,7 +1607,7 @@ pub mod pallet { } else if Validators::::contains_key(&stash) { let max_validator_count = MaxValidatorsCount::::get().ok_or(Error::::CannotChillOther)?; - let current_validator_count = CounterForValidators::::get(); + let current_validator_count = Validators::::count(); ensure!( threshold * max_validator_count < current_validator_count, Error::::CannotChillOther diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 611773fc0ccf2..1c9163bd56402 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -36,12 +36,11 @@ const SEED: u32 = 0; /// This function removes all validators and nominators from storage. pub fn clear_validators_and_nominators() { - Validators::::remove_all(None); - CounterForValidators::::kill(); + Validators::::remove_all(); // whenever we touch nominators counter we should update `T::SortedListProvider` as well. - Nominators::::remove_all(None); - CounterForNominators::::kill(); + Nominators::::remove_all(); + // NOTE: safe to call outside block production T::SortedListProvider::unsafe_clear(); } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 4604351b52305..ec8be43f02841 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4300,8 +4300,8 @@ fn chill_other_works() { .min_nominator_bond(1_000) .min_validator_bond(1_500) .build_and_execute(|| { - let initial_validators = CounterForValidators::::get(); - let initial_nominators = CounterForNominators::::get(); + let initial_validators = Validators::::count(); + let initial_nominators = Nominators::::count(); for i in 0..15 { let a = 4 * i; let b = 4 * i + 1; @@ -4424,8 +4424,8 @@ fn chill_other_works() { )); // 16 people total because tests start with 2 active one - assert_eq!(CounterForNominators::::get(), 15 + initial_nominators); - assert_eq!(CounterForValidators::::get(), 15 + initial_validators); + assert_eq!(Nominators::::count(), 15 + initial_nominators); + assert_eq!(Validators::::count(), 15 + initial_validators); // Users can now be chilled down to 7 people, so we try to remove 9 of them (starting // with 16) @@ -4437,13 +4437,13 @@ fn chill_other_works() { } // chill a nominator. Limit is not reached, not chill-able - assert_eq!(CounterForNominators::::get(), 7); + assert_eq!(Nominators::::count(), 7); assert_noop!( Staking::chill_other(Origin::signed(1337), 1), Error::::CannotChillOther ); // chill a validator. Limit is reached, chill-able. - assert_eq!(CounterForValidators::::get(), 9); + assert_eq!(Validators::::count(), 9); assert_ok!(Staking::chill_other(Origin::signed(1337), 3)); }) } @@ -4451,9 +4451,9 @@ fn chill_other_works() { #[test] fn capped_stakers_works() { ExtBuilder::default().build_and_execute(|| { - let validator_count = CounterForValidators::::get(); + let validator_count = Validators::::count(); assert_eq!(validator_count, 3); - let nominator_count = CounterForNominators::::get(); + let nominator_count = Nominators::::count(); assert_eq!(nominator_count, 1); // Change the maximums diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 5211453fd09b4..01414d7019ae1 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -98,6 +98,17 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { + /// The key used to store the counter of the map. + pub fn counter_storage_final_key() -> [u8; 32] { + CounterFor::::hashed_key() + } + + /// The prefix used to generate the key of the map. + pub fn map_storage_final_prefix() -> Vec { + use crate::storage::generator::StorageMap; + ::Map::prefix_hash() + } + /// Get the storage key used to fetch a value corresponding to a specific key. pub fn hashed_key_for>(key: KeyArg) -> Vec { ::Map::hashed_key_for(key) From a1c31a7bdb004cf9b9c5c0abc723e4cb58d005e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 7 Dec 2021 13:19:30 +0100 Subject: [PATCH 0307/1472] contracts: Add storage deposits (#10082) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Frame no longer needs to be mutable (refactoring artifact) * Remove Contract/Tombstone deposit * Add StorageMeter * cargo fmt * Fix weight annotation * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Simplify keep check for contract accounts - Make sure that the "base deposit" for each contract >= ed - Remove now obsolete checks when sneding away free balance * Remove unused imports and functions * Rename storage_limit to storage_deposit_limit * cargo fmt * Fix typo Co-authored-by: Michael Müller * Finish up rename of storage_limit * Fix rpc tests * Make use of `StorageDepositLimitTooHigh` * Add tests and fix bugs discovered by tests * Add storage migration * Don't use u128 in RPC * Fix weight of migration * Rename `endowment` to `value` * Fix bug where contract couldn't get funded by a storage deposit - Make sure that contract gets funded from deposits before value is transferred - Don't reserve value at origin because otherwise funding isn't possible - Just transfer free balance and reserve it after the transfer - When refunding make sure that this refund can't dust the contract - Can only happen after a runtime upgrade where costs where upped - Add more tests * Apply suggestions from code review Co-authored-by: Andrew Jones * Remove unused `fn storage_meter` * Fix copy pasta doc error * Import `MaxEncodeLen` from codec * Beautify RPC trait bounds * Add re-instrument behaviour to dispatchable doc * Make sure a account won't be destroyed a refund after a slash * Apply suggestions from code review Co-authored-by: Andrew Jones * Update `Storage::write` docs * Improve doc * Remove superflous conditional * Typos * Remove superflous clone (refactoring artifact) * Apply suggestions from code review Co-authored-by: Andrew Jones Co-authored-by: Parity Bot Co-authored-by: Michael Müller Co-authored-by: Andrew Jones --- Cargo.lock | 3 + bin/node/executor/Cargo.toml | 1 + bin/node/executor/tests/basic.rs | 6 +- bin/node/executor/tests/common.rs | 2 +- bin/node/runtime/src/lib.rs | 30 +- frame/contracts/Cargo.toml | 1 + frame/contracts/common/Cargo.toml | 2 + frame/contracts/common/src/lib.rs | 183 +- .../fixtures/destroy_and_transfer.wat | 2 +- frame/contracts/fixtures/drain.wat | 6 +- frame/contracts/fixtures/multi_store.wat | 54 + frame/contracts/fixtures/store.wat | 45 + frame/contracts/rpc/runtime-api/src/lib.rs | 20 +- frame/contracts/rpc/src/lib.rs | 167 +- frame/contracts/src/benchmarking/mod.rs | 285 +-- frame/contracts/src/exec.rs | 483 +++-- frame/contracts/src/lib.rs | 298 ++- frame/contracts/src/migration.rs | 142 +- frame/contracts/src/schedule.rs | 4 - frame/contracts/src/storage.rs | 65 +- frame/contracts/src/storage/meter.rs | 726 +++++++ frame/contracts/src/tests.rs | 1499 ++++++++++++--- frame/contracts/src/wasm/code_cache.rs | 243 ++- frame/contracts/src/wasm/mod.rs | 202 +- frame/contracts/src/wasm/prepare.rs | 54 +- frame/contracts/src/wasm/runtime.rs | 69 +- frame/contracts/src/weights.rs | 1677 +++++++++-------- 27 files changed, 4375 insertions(+), 1894 deletions(-) create mode 100644 frame/contracts/fixtures/multi_store.wat create mode 100644 frame/contracts/fixtures/store.wat create mode 100644 frame/contracts/src/storage/meter.rs diff --git a/Cargo.lock b/Cargo.lock index d67ebd7f24ddf..08d2ab7328398 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4616,6 +4616,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-state-machine", + "sp-tracing", "sp-trie", "wat", ] @@ -5404,6 +5405,7 @@ version = "4.0.0-dev" dependencies = [ "assert_matches", "bitflags", + "env_logger 0.9.0", "frame-benchmarking", "frame-support", "frame-system", @@ -5442,6 +5444,7 @@ dependencies = [ "scale-info", "serde", "sp-core", + "sp-rpc", "sp-runtime", "sp-std", ] diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 21785079c6c54..6fdd5f8d2351b 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -20,6 +20,7 @@ sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } +sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } sp-trie = { version = "4.0.0-dev", path = "../../../primitives/trie" } frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 9c460a0238e38..6406a04e8dc63 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -685,8 +685,6 @@ fn deploying_wasm_contract_should_work() { let addr = pallet_contracts::Pallet::::contract_address(&charlie(), &transfer_ch, &[]); - let subsistence = pallet_contracts::Pallet::::subsistence_threshold(); - let time = 42 * 1000; let b = construct_block( &mut new_test_ext(compact_code_unwrap()), @@ -701,8 +699,9 @@ fn deploying_wasm_contract_should_work() { signed: Some((charlie(), signed_extra(0, 0))), function: Call::Contracts( pallet_contracts::Call::instantiate_with_code:: { - endowment: 1000 * DOLLARS + subsistence, + value: 0, gas_limit: 500_000_000, + storage_deposit_limit: None, code: transfer_code, data: Vec::new(), salt: Vec::new(), @@ -715,6 +714,7 @@ fn deploying_wasm_contract_should_work() { dest: sp_runtime::MultiAddress::Id(addr.clone()), value: 10, gas_limit: 500_000_000, + storage_deposit_limit: None, data: vec![0x00, 0x01, 0x02, 0x03], }), }, diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index c81d6b7c14e02..87506ba66a3e4 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -119,7 +119,7 @@ pub fn executor_call< hash: sp_core::blake2_256(&code).to_vec(), heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()), }; - + sp_tracing::try_init_simple(); executor().call::(&mut t, &runtime_code, method, data, use_native, native_call) } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 2cf6548b79211..9573b86c6ee2c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -897,10 +897,8 @@ impl pallet_tips::Config for Runtime { } parameter_types! { - pub ContractDeposit: Balance = deposit( - 1, - >::contract_info_size(), - ); + pub const DepositPerItem: Balance = deposit(1, 0); + pub const DepositPerByte: Balance = deposit(0, 1); pub const MaxValueSize: u32 = 16 * 1024; // The lazy deletion runs inside on_initialize. pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO * @@ -927,7 +925,8 @@ impl pallet_contracts::Config for Runtime { /// change because that would break already deployed contracts. The `Call` structure itself /// is not allowed to change the indices of existing pallets, too. type CallFilter = Nothing; - type ContractDeposit = ContractDeposit; + type DepositPerItem = DepositPerItem; + type DepositPerByte = DepositPerByte; type CallStack = [pallet_contracts::Frame; 31]; type WeightPrice = pallet_transaction_payment::Pallet; type WeightInfo = pallet_contracts::weights::SubstrateWeight; @@ -1522,21 +1521,32 @@ impl_runtime_apis! { dest: AccountId, value: Balance, gas_limit: u64, + storage_deposit_limit: Option, input_data: Vec, - ) -> pallet_contracts_primitives::ContractExecResult { - Contracts::bare_call(origin, dest, value, gas_limit, input_data, true) + ) -> pallet_contracts_primitives::ContractExecResult { + Contracts::bare_call(origin, dest, value, gas_limit, storage_deposit_limit, input_data, true) } fn instantiate( origin: AccountId, - endowment: Balance, + value: Balance, gas_limit: u64, + storage_deposit_limit: Option, code: pallet_contracts_primitives::Code, data: Vec, salt: Vec, - ) -> pallet_contracts_primitives::ContractInstantiateResult + ) -> pallet_contracts_primitives::ContractInstantiateResult + { + Contracts::bare_instantiate(origin, value, gas_limit, storage_deposit_limit, code, data, salt, true) + } + + fn upload_code( + origin: AccountId, + code: Vec, + storage_deposit_limit: Option, + ) -> pallet_contracts_primitives::CodeUploadResult { - Contracts::bare_instantiate(origin, endowment, gas_limit, code, data, salt, true) + Contracts::bare_upload_code(origin, code, storage_deposit_limit) } fn get_storage( diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index cc21f19b63527..0b10962f0e63f 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -46,6 +46,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primit [dev-dependencies] assert_matches = "1" +env_logger = "0.9" hex-literal = "0.3" pretty_assertions = "1" wat = "1" diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/common/Cargo.toml index c30efc6869403..5f52ce7fcfe55 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/common/Cargo.toml @@ -21,6 +21,7 @@ serde = { version = "1", features = ["derive"], optional = true } # Substrate Dependencies (This crate should not rely on frame) sp-core = { version = "4.0.0-dev", path = "../../../primitives/core", default-features = false } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } [features] @@ -31,5 +32,6 @@ std = [ "sp-core/std", "sp-runtime/std", "sp-std/std", + "sp-rpc", "serde", ] diff --git a/frame/contracts/common/src/lib.rs b/frame/contracts/common/src/lib.rs index c57f728c26b68..d8408f77e06e2 100644 --- a/frame/contracts/common/src/lib.rs +++ b/frame/contracts/common/src/lib.rs @@ -22,19 +22,32 @@ use bitflags::bitflags; use codec::{Decode, Encode}; use sp_core::Bytes; -use sp_runtime::{DispatchError, RuntimeDebug}; +use sp_runtime::{ + traits::{Saturating, Zero}, + DispatchError, RuntimeDebug, +}; use sp_std::prelude::*; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; +#[cfg(feature = "std")] +use sp_rpc::number::NumberOrHex; + /// Result type of a `bare_call` or `bare_instantiate` call. /// /// It contains the execution result together with some auxiliary information. #[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] -pub struct ContractResult { +#[cfg_attr( + feature = "std", + serde( + rename_all = "camelCase", + bound(serialize = "R: Serialize, Balance: Copy + Into"), + bound(deserialize = "R: Deserialize<'de>, Balance: TryFrom") + ) +)] +pub struct ContractResult { /// How much gas was consumed during execution. pub gas_consumed: u64, /// How much gas is required as gas limit in order to execute this call. @@ -45,7 +58,14 @@ pub struct ContractResult { /// /// This can only different from [`Self::gas_consumed`] when weight pre charging /// is used. Currently, only `seal_call_runtime` makes use of pre charging. + /// Additionally, any `seal_call` or `seal_instantiate` makes use of pre-charging + /// when a non-zero `gas_limit` argument is supplied. pub gas_required: u64, + /// How much balance was deposited and reserved during execution in order to pay for storage. + /// + /// The storage deposit is never actually charged from the caller in case of [`Self::result`] + /// is `Err`. This is because on error all storage changes are rolled back. + pub storage_deposit: StorageDeposit, /// An optional debug message. This message is only filled when explicitly requested /// by the code that calls into the contract. Otherwise it is empty. /// @@ -63,15 +83,20 @@ pub struct ContractResult { #[cfg_attr(feature = "std", serde(with = "as_string"))] pub debug_message: Vec, /// The execution result of the wasm code. - pub result: T, + pub result: R, } /// Result type of a `bare_call` call. -pub type ContractExecResult = ContractResult>; +pub type ContractExecResult = + ContractResult, Balance>; /// Result type of a `bare_instantiate` call. -pub type ContractInstantiateResult = - ContractResult, DispatchError>>; +pub type ContractInstantiateResult = + ContractResult, DispatchError>, Balance>; + +/// Result type of a `bare_code_upload` call. +pub type CodeUploadResult = + Result, DispatchError>; /// Result type of a `get_storage` call. pub type GetStorageResult = Result>, ContractAccessError>; @@ -123,6 +148,17 @@ pub struct InstantiateReturnValue { pub account_id: AccountId, } +/// The result of succesfully uploading a contract. +#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] +pub struct CodeUploadReturnValue { + /// The key under which the new code is stored. + pub code_hash: CodeHash, + /// The deposit that was reserved at the caller. Is zero when the code already existed. + pub deposit: Balance, +} + /// Reference to an existing code hash or a new wasm module. #[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] @@ -134,6 +170,116 @@ pub enum Code { Existing(Hash), } +/// The amount of balance that was either charged or refunded in order to pay for storage. +#[derive(Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, Clone)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "std", + serde( + rename_all = "camelCase", + bound(serialize = "Balance: Copy + Into"), + bound(deserialize = "Balance: TryFrom") + ) +)] +pub enum StorageDeposit { + /// The transaction reduced storage consumption. + /// + /// This means that the specified amount of balance was transferred from the involved + /// contracts to the call origin. + #[cfg_attr(feature = "std", serde(with = "as_hex"))] + Refund(Balance), + /// The transaction increased overall storage usage. + /// + /// This means that the specified amount of balance was transferred from the call origin + /// to the contracts involved. + #[cfg_attr(feature = "std", serde(with = "as_hex"))] + Charge(Balance), +} + +impl Default for StorageDeposit { + fn default() -> Self { + Self::Charge(Zero::zero()) + } +} + +impl StorageDeposit { + /// Returns how much balance is charged or `0` in case of a refund. + pub fn charge_or_zero(&self) -> Balance { + match self { + Self::Charge(amount) => *amount, + Self::Refund(_) => Zero::zero(), + } + } + + pub fn is_zero(&self) -> bool { + match self { + Self::Charge(amount) => amount.is_zero(), + Self::Refund(amount) => amount.is_zero(), + } + } +} + +impl StorageDeposit +where + Balance: Saturating + Ord + Copy, +{ + /// This is essentially a saturating signed add. + pub fn saturating_add(&self, rhs: &Self) -> Self { + use StorageDeposit::*; + match (self, rhs) { + (Charge(lhs), Charge(rhs)) => Charge(lhs.saturating_add(*rhs)), + (Refund(lhs), Refund(rhs)) => Refund(lhs.saturating_add(*rhs)), + (Charge(lhs), Refund(rhs)) => + if lhs >= rhs { + Charge(lhs.saturating_sub(*rhs)) + } else { + Refund(rhs.saturating_sub(*lhs)) + }, + (Refund(lhs), Charge(rhs)) => + if lhs > rhs { + Refund(lhs.saturating_sub(*rhs)) + } else { + Charge(rhs.saturating_sub(*lhs)) + }, + } + } + + /// This is essentially a saturating signed sub. + pub fn saturating_sub(&self, rhs: &Self) -> Self { + use StorageDeposit::*; + match (self, rhs) { + (Charge(lhs), Refund(rhs)) => Charge(lhs.saturating_add(*rhs)), + (Refund(lhs), Charge(rhs)) => Refund(lhs.saturating_add(*rhs)), + (Charge(lhs), Charge(rhs)) => + if lhs >= rhs { + Charge(lhs.saturating_sub(*rhs)) + } else { + Refund(rhs.saturating_sub(*lhs)) + }, + (Refund(lhs), Refund(rhs)) => + if lhs > rhs { + Refund(lhs.saturating_sub(*rhs)) + } else { + Charge(rhs.saturating_sub(*lhs)) + }, + } + } + + /// If the amount of deposit (this type) is constrained by a `limit` this calcuates how + /// much balance (if any) is still available from this limit. + /// + /// # Note + /// + /// In case of a refund the return value can be larger than `limit`. + pub fn available(&self, limit: &Balance) -> Balance { + use StorageDeposit::*; + match self { + Charge(amount) => limit.saturating_sub(*amount), + Refund(amount) => limit.saturating_add(*amount), + } + } +} + #[cfg(feature = "std")] mod as_string { use super::*; @@ -149,3 +295,26 @@ mod as_string { Ok(String::deserialize(deserializer)?.into_bytes()) } } + +#[cfg(feature = "std")] +mod as_hex { + use super::*; + use serde::{de::Error as _, Deserializer, Serializer}; + + pub fn serialize(balance: &Balance, serializer: S) -> Result + where + S: Serializer, + Balance: Copy + Into, + { + Into::::into(*balance).serialize(serializer) + } + + pub fn deserialize<'de, D, Balance>(deserializer: D) -> Result + where + D: Deserializer<'de>, + Balance: TryFrom, + { + Balance::try_from(NumberOrHex::deserialize(deserializer)?) + .map_err(|_| D::Error::custom("Cannot decode NumberOrHex to Balance")) + } +} diff --git a/frame/contracts/fixtures/destroy_and_transfer.wat b/frame/contracts/fixtures/destroy_and_transfer.wat index aa13cd8b81072..2555479555272 100644 --- a/frame/contracts/fixtures/destroy_and_transfer.wat +++ b/frame/contracts/fixtures/destroy_and_transfer.wat @@ -9,7 +9,7 @@ )) (import "env" "memory" (memory 1 1)) - ;; [0, 8) Endowment to send when creating contract. + ;; [0, 8) value to send when creating contract. (data (i32.const 0) "\00\00\01") ;; [8, 16) Value to send when calling contract. diff --git a/frame/contracts/fixtures/drain.wat b/frame/contracts/fixtures/drain.wat index 546026ac95986..94c6518422667 100644 --- a/frame/contracts/fixtures/drain.wat +++ b/frame/contracts/fixtures/drain.wat @@ -33,7 +33,9 @@ ) ) - ;; Self-destruct by sending full balance to the 0 address. + ;; Try to self-destruct by sending full balance to the 0 address. + ;; All the *free* balance will be send away, which is a valid thing to do + ;; because the storage deposits will keep the account alive. (call $assert (i32.eq (call $seal_transfer @@ -42,7 +44,7 @@ (i32.const 0) ;; Pointer to the buffer with value to transfer (i32.const 8) ;; Length of the buffer with value to transfer ) - (i32.const 4) ;; ReturnCode::BelowSubsistenceThreshold + (i32.const 0) ;; ReturnCode::Success ) ) ) diff --git a/frame/contracts/fixtures/multi_store.wat b/frame/contracts/fixtures/multi_store.wat new file mode 100644 index 0000000000000..2592baf618355 --- /dev/null +++ b/frame/contracts/fixtures/multi_store.wat @@ -0,0 +1,54 @@ +;; Does two stores to two seperate storage items +;; Expects (len0, len1) as input. +(module + (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "env" "memory" (memory 16 16)) + + ;; [0, 32) storage key 0 + (data (i32.const 0) "\01") + + ;; [32, 64) storage key 1 + (data (i32.const 32) "\02") + + ;; [64, 72) buffer where input is copied (expected sizes of storage items) + + ;; [72, 76) size of the input buffer + (data (i32.const 72) "\08") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + (call $seal_input (i32.const 64) (i32.const 72)) + + ;; assert input size == 8 + (call $assert + (i32.eq + (i32.load (i32.const 72)) + (i32.const 8) + ) + ) + + ;; place a values in storage sizes are specified in the input buffer + ;; we don't care about the contents of the storage item + (call $seal_set_storage + (i32.const 0) ;; Pointer to storage key + (i32.const 0) ;; Pointer to value + (i32.load (i32.const 64)) ;; Size of value + ) + (call $seal_set_storage + (i32.const 32) ;; Pointer to storage key + (i32.const 0) ;; Pointer to value + (i32.load (i32.const 68)) ;; Size of value + ) + ) + + (func (export "deploy")) +) diff --git a/frame/contracts/fixtures/store.wat b/frame/contracts/fixtures/store.wat new file mode 100644 index 0000000000000..9e090d31801f8 --- /dev/null +++ b/frame/contracts/fixtures/store.wat @@ -0,0 +1,45 @@ +;; Stores a value of the passed size. +(module + (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "env" "memory" (memory 16 16)) + + ;; [0, 32) storage key + (data (i32.const 0) "\01") + + ;; [32, 36) buffer where input is copied (expected size of storage item) + + ;; [36, 40) size of the input buffer + (data (i32.const 36) "\04") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + (call $seal_input (i32.const 32) (i32.const 36)) + + ;; assert input size == 4 + (call $assert + (i32.eq + (i32.load (i32.const 36)) + (i32.const 4) + ) + ) + + ;; place a value in storage, the size of which is specified by the call input. + ;; we don't care about the contents of the storage item + (call $seal_set_storage + (i32.const 0) ;; Pointer to storage key + (i32.const 0) ;; Pointer to value + (i32.load (i32.const 32)) ;; Size of value + ) + ) + + (func (export "deploy")) +) diff --git a/frame/contracts/rpc/runtime-api/src/lib.rs b/frame/contracts/rpc/runtime-api/src/lib.rs index 20dfbe210e5ce..485040fd235cd 100644 --- a/frame/contracts/rpc/runtime-api/src/lib.rs +++ b/frame/contracts/rpc/runtime-api/src/lib.rs @@ -25,7 +25,7 @@ use codec::Codec; use pallet_contracts_primitives::{ - Code, ContractExecResult, ContractInstantiateResult, GetStorageResult, + Code, CodeUploadResult, ContractExecResult, ContractInstantiateResult, GetStorageResult, }; use sp_std::vec::Vec; @@ -45,20 +45,32 @@ sp_api::decl_runtime_apis! { dest: AccountId, value: Balance, gas_limit: u64, + storage_deposit_limit: Option, input_data: Vec, - ) -> ContractExecResult; + ) -> ContractExecResult; /// Instantiate a new contract. /// /// See `pallet_contracts::Pallet::instantiate`. fn instantiate( origin: AccountId, - endowment: Balance, + value: Balance, gas_limit: u64, + storage_deposit_limit: Option, code: Code, data: Vec, salt: Vec, - ) -> ContractInstantiateResult; + ) -> ContractInstantiateResult; + + + /// Upload new code without instantiating a contract from it. + /// + /// See `pallet_contracts::Pallet::upload_code`. + fn upload_code( + origin: AccountId, + code: Vec, + storage_deposit_limit: Option, + ) -> CodeUploadResult; /// Query a given storage key in a given contract. /// diff --git a/frame/contracts/rpc/src/lib.rs b/frame/contracts/rpc/src/lib.rs index c82cf44d97c7f..c4a577196c999 100644 --- a/frame/contracts/rpc/src/lib.rs +++ b/frame/contracts/rpc/src/lib.rs @@ -22,7 +22,9 @@ use std::sync::Arc; use codec::Codec; use jsonrpc_core::{Error, ErrorCode, Result}; use jsonrpc_derive::rpc; -use pallet_contracts_primitives::{Code, ContractExecResult, ContractInstantiateResult}; +use pallet_contracts_primitives::{ + Code, CodeUploadResult, ContractExecResult, ContractInstantiateResult, +}; use serde::{Deserialize, Serialize}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; @@ -78,6 +80,7 @@ pub struct CallRequest { dest: AccountId, value: NumberOrHex, gas_limit: NumberOrHex, + storage_deposit_limit: Option, input_data: Bytes, } @@ -87,32 +90,47 @@ pub struct CallRequest { #[serde(deny_unknown_fields)] pub struct InstantiateRequest { origin: AccountId, - endowment: NumberOrHex, + value: NumberOrHex, gas_limit: NumberOrHex, + storage_deposit_limit: Option, code: Code, data: Bytes, salt: Bytes, } +/// A struct that encodes RPC parameters required for a call to upload a new code. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] +pub struct CodeUploadRequest { + origin: AccountId, + code: Bytes, + storage_deposit_limit: Option, +} + /// Contracts RPC methods. #[rpc] -pub trait ContractsApi { +pub trait ContractsApi +where + Balance: Copy + TryFrom + Into, +{ /// Executes a call to a contract. /// /// This call is performed locally without submitting any transactions. Thus executing this /// won't change any state. Nonetheless, the calling state-changing contracts is still possible. /// - /// This method is useful for calling getter-like methods on contracts. + /// This method is useful for calling getter-like methods on contracts or to dry-run a + /// a contract call in order to determine the `gas_limit`. #[rpc(name = "contracts_call")] fn call( &self, call_request: CallRequest, at: Option, - ) -> Result; + ) -> Result>; /// Instantiate a new contract. /// - /// This call is performed locally without submitting any transactions. Thus the contract + /// This instantiate is performed locally without submitting any transactions. Thus the contract /// is not actually created. /// /// This method is useful for UIs to dry-run contract instantiations. @@ -121,7 +139,20 @@ pub trait ContractsApi { &self, instantiate_request: InstantiateRequest, at: Option, - ) -> Result>; + ) -> Result>; + + /// Upload new code without instantiating a contract from it. + /// + /// This upload is performed locally without submitting any transactions. Thus executing this + /// won't change any state. + /// + /// This method is useful for UIs to dry-run code upload. + #[rpc(name = "contracts_upload_code")] + fn upload_code( + &self, + upload_request: CodeUploadRequest, + at: Option, + ) -> Result>; /// Returns the value under a specified storage `key` in a contract given by `address` param, /// or `None` if it is not set. @@ -165,54 +196,88 @@ where Hash, >, AccountId: Codec, - Balance: Codec + TryFrom, + Balance: Codec + Copy + TryFrom + Into, Hash: Codec, { fn call( &self, call_request: CallRequest, at: Option<::Hash>, - ) -> Result { + ) -> Result> { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. self.client.info().best_hash)); - let CallRequest { origin, dest, value, gas_limit, input_data } = call_request; + let CallRequest { origin, dest, value, gas_limit, storage_deposit_limit, input_data } = + call_request; let value: Balance = decode_hex(value, "balance")?; let gas_limit: Weight = decode_hex(gas_limit, "weight")?; + let storage_deposit_limit: Option = + storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; limit_gas(gas_limit)?; - let exec_result = api - .call(&at, origin, dest, value, gas_limit, input_data.to_vec()) - .map_err(runtime_error_into_rpc_err)?; - - Ok(exec_result) + api.call(&at, origin, dest, value, gas_limit, storage_deposit_limit, input_data.to_vec()) + .map_err(runtime_error_into_rpc_err) } fn instantiate( &self, instantiate_request: InstantiateRequest, at: Option<::Hash>, - ) -> Result> { + ) -> Result> { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. self.client.info().best_hash)); - let InstantiateRequest { origin, endowment, gas_limit, code, data, salt } = - instantiate_request; + let InstantiateRequest { + origin, + value, + gas_limit, + storage_deposit_limit, + code, + data, + salt, + } = instantiate_request; - let endowment: Balance = decode_hex(endowment, "balance")?; + let value: Balance = decode_hex(value, "balance")?; let gas_limit: Weight = decode_hex(gas_limit, "weight")?; + let storage_deposit_limit: Option = + storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; limit_gas(gas_limit)?; - let exec_result = api - .instantiate(&at, origin, endowment, gas_limit, code, data.to_vec(), salt.to_vec()) - .map_err(runtime_error_into_rpc_err)?; + api.instantiate( + &at, + origin, + value, + gas_limit, + storage_deposit_limit, + code, + data.to_vec(), + salt.to_vec(), + ) + .map_err(runtime_error_into_rpc_err) + } + + fn upload_code( + &self, + upload_request: CodeUploadRequest, + at: Option<::Hash>, + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash)); + + let CodeUploadRequest { origin, code, storage_deposit_limit } = upload_request; - Ok(exec_result) + let storage_deposit_limit: Option = + storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; + + api.upload_code(&at, origin, code.to_vec(), storage_deposit_limit) + .map_err(runtime_error_into_rpc_err) } fn get_storage( @@ -287,12 +352,14 @@ mod tests { "dest": "5DRakbLVnjVrW6niwLfHGW24EeCEvDAFGEXrtaYS5M4ynoom", "value": "0x112210f4B16c1cb1", "gasLimit": 1000000000000, + "storageDepositLimit": 5000, "inputData": "0x8c97db39" } "#, ) .unwrap(); assert_eq!(req.gas_limit.into_u256(), U256::from(0xe8d4a51000u64)); + assert_eq!(req.storage_deposit_limit.map(|l| l.into_u256()), Some(5000.into())); assert_eq!(req.value.into_u256(), U256::from(1234567890987654321u128)); } @@ -303,7 +370,7 @@ mod tests { r#" { "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", - "endowment": "0x88", + "value": "0x88", "gasLimit": 42, "code": { "existing": "0x1122" }, "data": "0x4299", @@ -314,8 +381,9 @@ mod tests { .unwrap(); assert_eq!(req.origin, "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"); - assert_eq!(req.endowment.into_u256(), 0x88.into()); + assert_eq!(req.value.into_u256(), 0x88.into()); assert_eq!(req.gas_limit.into_u256(), 42.into()); + assert_eq!(req.storage_deposit_limit, None); assert_eq!(&*req.data, [0x42, 0x99].as_ref()); assert_eq!(&*req.salt, [0x99, 0x88].as_ref()); let code = match req.code { @@ -325,10 +393,28 @@ mod tests { assert_eq!(&code, "0x1122"); } + #[test] + fn code_upload_request_should_serialize_deserialize_properly() { + type Req = CodeUploadRequest; + let req: Req = serde_json::from_str( + r#" + { + "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + "code": "0x8c97db39", + "storageDepositLimit": 5000 + } + "#, + ) + .unwrap(); + assert_eq!(req.origin, "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"); + assert_eq!(&*req.code, [0x8c, 0x97, 0xdb, 0x39].as_ref()); + assert_eq!(req.storage_deposit_limit.map(|l| l.into_u256()), Some(5000.into())); + } + #[test] fn call_result_should_serialize_deserialize_properly() { fn test(expected: &str) { - let res: ContractExecResult = serde_json::from_str(expected).unwrap(); + let res: ContractExecResult = serde_json::from_str(expected).unwrap(); let actual = serde_json::to_string(&res).unwrap(); assert_eq!(actual, trim(expected).as_str()); } @@ -336,6 +422,7 @@ mod tests { r#"{ "gasConsumed": 5000, "gasRequired": 8000, + "storageDeposit": {"charge": 42000}, "debugMessage": "HelloWorld", "result": { "Ok": { @@ -349,6 +436,7 @@ mod tests { r#"{ "gasConsumed": 3400, "gasRequired": 5200, + "storageDeposit": {"refund": 12000}, "debugMessage": "HelloWorld", "result": { "Err": "BadOrigin" @@ -360,7 +448,8 @@ mod tests { #[test] fn instantiate_result_should_serialize_deserialize_properly() { fn test(expected: &str) { - let res: ContractInstantiateResult = serde_json::from_str(expected).unwrap(); + let res: ContractInstantiateResult = + serde_json::from_str(expected).unwrap(); let actual = serde_json::to_string(&res).unwrap(); assert_eq!(actual, trim(expected).as_str()); } @@ -368,6 +457,7 @@ mod tests { r#"{ "gasConsumed": 5000, "gasRequired": 8000, + "storageDeposit": {"refund": 12000}, "debugMessage": "HelloWorld", "result": { "Ok": { @@ -384,6 +474,7 @@ mod tests { r#"{ "gasConsumed": 3400, "gasRequired": 5200, + "storageDeposit": {"charge": 0}, "debugMessage": "HelloWorld", "result": { "Err": "BadOrigin" @@ -391,4 +482,26 @@ mod tests { }"#, ); } + + #[test] + fn code_upload_result_should_serialize_deserialize_properly() { + fn test(expected: &str) { + let res: CodeUploadResult = serde_json::from_str(expected).unwrap(); + let actual = serde_json::to_string(&res).unwrap(); + assert_eq!(actual, trim(expected).as_str()); + } + test( + r#"{ + "Ok": { + "codeHash": 4711, + "deposit": 99 + } + }"#, + ); + test( + r#"{ + "Err": "BadOrigin" + }"#, + ); + } } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 665ec565c8e65..884fddb6f907f 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -57,13 +57,14 @@ struct Contract { caller: T::AccountId, account_id: T::AccountId, addr: ::Source, - endowment: BalanceOf, + value: BalanceOf, } impl Contract where T: Config, T::AccountId: UncheckedFrom + AsRef<[u8]>, + as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode, { /// Create new contract and use a default account id as instantiator. fn new(module: WasmModule, data: Vec) -> Result, &'static str> { @@ -85,27 +86,24 @@ where module: WasmModule, data: Vec, ) -> Result, &'static str> { - let endowment = contract_funding::(); + let value = T::Currency::minimum_balance(); T::Currency::make_free_balance_be(&caller, caller_funding::()); let salt = vec![0xff]; let addr = Contracts::::contract_address(&caller, &module.hash, &salt); - Contracts::::store_code_raw(module.code)?; + Contracts::::store_code_raw(module.code, caller.clone())?; Contracts::::instantiate( RawOrigin::Signed(caller.clone()).into(), - endowment, - Weight::max_value(), + value, + Weight::MAX, + None, module.hash, data, salt, )?; - let result = Contract { - caller, - account_id: addr.clone(), - addr: T::Lookup::unlookup(addr), - endowment, - }; + let result = + Contract { caller, account_id: addr.clone(), addr: T::Lookup::unlookup(addr), value }; ContractInfoOf::::insert(&result.account_id, result.info()?); @@ -134,9 +132,9 @@ where /// Store the supplied storage items into this contracts storage. fn store(&self, items: &Vec<(StorageKey, Vec)>) -> Result<(), &'static str> { - let mut info = self.info()?; + let info = self.info()?; for item in items { - Storage::::write(&mut info, &item.0, Some(item.1.clone())) + Storage::::write(&info.trie_id, &item.0, Some(item.1.clone()), None) .map_err(|_| "Failed to write storage to restoration dest")?; } >::insert(&self.account_id, info.clone()); @@ -152,6 +150,25 @@ where fn info(&self) -> Result, &'static str> { Self::address_info(&self.account_id) } + + /// Set the balance of the contract to the supplied amount. + fn set_balance(&self, balance: BalanceOf) { + T::Currency::make_free_balance_be(&self.account_id, balance); + } + + /// Returns `true` iff all storage entries related to code storage exist. + fn code_exists(hash: &CodeHash) -> bool { + >::contains_key(hash) && + >::contains_key(&hash) && + >::contains_key(&hash) + } + + /// Returns `true` iff no storage entry related to code storage exist. + fn code_removed(hash: &CodeHash) -> bool { + !>::contains_key(hash) && + !>::contains_key(&hash) && + !>::contains_key(&hash) + } } /// The funding that each account that either calls or instantiates contracts is funded with. @@ -159,11 +176,6 @@ fn caller_funding() -> BalanceOf { BalanceOf::::max_value() / 2u32.into() } -/// The funding used for contracts. It is less than `caller_funding` in purpose. -fn contract_funding() -> BalanceOf { - caller_funding::().saturating_sub(T::Currency::minimum_balance() * 100u32.into()) -} - /// Load the specified contract file from disk by including it into the runtime. /// /// We need to load a different version of ink! contracts when the benchmark is run as @@ -186,11 +198,12 @@ benchmarks! { where_clause { where T::AccountId: UncheckedFrom, T::AccountId: AsRef<[u8]>, + as codec::HasCompact>::Type: Clone + Eq + PartialEq + sp_std::fmt::Debug + scale_info::TypeInfo + codec::Encode, } // The base weight without any actual work performed apart from the setup costs. on_initialize {}: { - Storage::::process_deletion_queue_batch(Weight::max_value()) + Storage::::process_deletion_queue_batch(Weight::MAX) } #[skip_meta] @@ -199,7 +212,7 @@ benchmarks! { let instance = Contract::::with_storage(WasmModule::dummy(), k, T::Schedule::get().limits.payload_len)?; Storage::::queue_trie_for_deletion(&instance.info()?)?; }: { - Storage::::process_deletion_queue_batch(Weight::max_value()) + Storage::::process_deletion_queue_batch(Weight::MAX) } on_initialize_per_queue_item { @@ -210,7 +223,7 @@ benchmarks! { ContractInfoOf::::remove(instance.account_id); } }: { - Storage::::process_deletion_queue_batch(Weight::max_value()) + Storage::::process_deletion_queue_batch(Weight::MAX) } // This benchmarks the additional weight that is charged when a contract is executed the @@ -219,9 +232,10 @@ benchmarks! { instrument { let c in 0 .. T::Schedule::get().limits.code_len / 1024; let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024); - Contracts::::store_code_raw(code)?; - let mut module = PrefabWasmModule::from_storage_noinstr(hash)?; + Contracts::::store_code_raw(code, whitelisted_caller())?; let schedule = T::Schedule::get(); + let mut gas_meter = GasMeter::new(Weight::MAX); + let mut module = PrefabWasmModule::from_storage(hash, &schedule, &mut gas_meter)?; }: { Contracts::::reinstrument_module(&mut module, &schedule)?; } @@ -230,19 +244,11 @@ benchmarks! { code_load { let c in 0 .. T::Schedule::get().limits.code_len / 1024; let WasmModule { code, hash, .. } = WasmModule::::dummy_with_bytes(c * 1024); - Contracts::::store_code_raw(code)?; - }: { - >::from_storage_noinstr(hash)?; - } - - // The weight of changing the refcount of a contract's code per kilobyte. - code_refcount { - let c in 0 .. T::Schedule::get().limits.code_len / 1024; - let WasmModule { code, hash, .. } = WasmModule::::dummy_with_bytes(c * 1024); - Contracts::::store_code_raw(code)?; - let mut gas_meter = GasMeter::new(Weight::max_value()); + Contracts::::store_code_raw(code, whitelisted_caller())?; + let schedule = T::Schedule::get(); + let mut gas_meter = GasMeter::new(Weight::MAX); }: { - >::add_user(hash, &mut gas_meter)?; + >::from_storage(hash, &schedule, &mut gas_meter)?; } // This constructs a contract that is maximal expensive to instrument. @@ -260,18 +266,24 @@ benchmarks! { let c in 0 .. Perbill::from_percent(50).mul_ceil(T::Schedule::get().limits.code_len / 1024); let s in 0 .. code::max_pages::() * 64; let salt = vec![42u8; (s * 1024) as usize]; - let endowment = contract_funding::() / 3u32.into(); + let value = T::Currency::minimum_balance(); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024); let origin = RawOrigin::Signed(caller.clone()); let addr = Contracts::::contract_address(&caller, &hash, &salt); - }: _(origin, endowment, Weight::max_value(), code, vec![], salt) + }: _(origin, value, Weight::MAX, None, code, vec![], salt) verify { - // endowment was removed from the caller - assert_eq!(T::Currency::free_balance(&caller), caller_funding::() - endowment); - // contract has the full endowment - assert_eq!(T::Currency::free_balance(&addr), endowment); + // the contract itself does not trigger any reserves + let deposit = T::Currency::reserved_balance(&addr); + // uploading the code reserves some balance in the callers account + let code_deposit = T::Currency::reserved_balance(&caller); + assert_eq!( + T::Currency::free_balance(&caller), + caller_funding::() - value - deposit - code_deposit, + ); + // contract has the full value + assert_eq!(T::Currency::free_balance(&addr), value); // instantiate should leave a contract Contract::::address_info(&addr)?; } @@ -281,19 +293,21 @@ benchmarks! { instantiate { let s in 0 .. code::max_pages::() * 64; let salt = vec![42u8; (s * 1024) as usize]; - let endowment = contract_funding::() / 3u32.into(); + let value = T::Currency::minimum_balance(); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::dummy(); let origin = RawOrigin::Signed(caller.clone()); let addr = Contracts::::contract_address(&caller, &hash, &salt); - Contracts::::store_code_raw(code)?; - }: _(origin, endowment, Weight::max_value(), hash, vec![], salt) + Contracts::::store_code_raw(code, caller.clone())?; + }: _(origin, value, Weight::MAX, None, hash, vec![], salt) verify { - // endowment was removed from the caller - assert_eq!(T::Currency::free_balance(&caller), caller_funding::() - endowment); - // contract has the full endowment - assert_eq!(T::Currency::free_balance(&addr), endowment); + // the contract itself does not trigger any reserves + let deposit = T::Currency::reserved_balance(&addr); + // value was removed from the caller + assert_eq!(T::Currency::free_balance(&caller), caller_funding::() - value - deposit); + // contract has the full value + assert_eq!(T::Currency::free_balance(&addr), value); // instantiate should leave a contract Contract::::address_info(&addr)?; } @@ -312,12 +326,14 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); let callee = instance.addr.clone(); let before = T::Currency::free_balance(&instance.account_id); - }: _(origin, callee, value, Weight::max_value(), data) + }: _(origin, callee, value, Weight::MAX, None, data) verify { - // endowment and value transfered via call should be removed from the caller + // the contract itself does not trigger any reserves + let deposit = T::Currency::reserved_balance(&instance.account_id); + // value and value transfered via call should be removed from the caller assert_eq!( T::Currency::free_balance(&instance.caller), - caller_funding::() - instance.endowment - value, + caller_funding::() - instance.value - value - deposit, ); // contract should have received the value assert_eq!(T::Currency::free_balance(&instance.account_id), before + value); @@ -325,13 +341,53 @@ benchmarks! { instance.info()?; } + // This constructs a contract that is maximal expensive to instrument. + // It creates a maximum number of metering blocks per byte. + // `c`: Size of the code in kilobytes. + // + // # Note + // + // We cannot let `c` grow to the maximum code size because the code is not allowed + // to be larger than the maximum size **after instrumentation**. + upload_code { + let c in 0 .. Perbill::from_percent(50).mul_ceil(T::Schedule::get().limits.code_len / 1024); + let caller = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, caller_funding::()); + let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024); + let origin = RawOrigin::Signed(caller.clone()); + }: _(origin, code, None) + verify { + // uploading the code reserves some balance in the callers account + assert!(T::Currency::reserved_balance(&caller) > 0u32.into()); + assert!(>::code_exists(&hash)); + } + + // Removing code does not depend on the size of the contract because all the information + // needed to verify the removal claim (refcount, owner) is stored in a separate storage + // item (`OwnerInfoOf`). + remove_code { + let caller = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, caller_funding::()); + let WasmModule { code, hash, .. } = WasmModule::::dummy(); + let origin = RawOrigin::Signed(caller.clone()); + let uploaded = >::bare_upload_code(caller.clone(), code, None)?; + assert_eq!(uploaded.code_hash, hash); + assert_eq!(uploaded.deposit, T::Currency::reserved_balance(&caller)); + assert!(>::code_exists(&hash)); + }: _(origin, hash) + verify { + // removing the code should have unreserved the deposit + assert_eq!(T::Currency::reserved_balance(&caller), 0u32.into()); + assert!(>::code_removed(&hash)); + } + seal_caller { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( "seal_caller", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_address { let r in 0 .. API_BENCHMARK_BATCHES; @@ -339,7 +395,7 @@ benchmarks! { "seal_address", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_gas_left { let r in 0 .. API_BENCHMARK_BATCHES; @@ -347,7 +403,7 @@ benchmarks! { "seal_gas_left", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_balance { let r in 0 .. API_BENCHMARK_BATCHES; @@ -355,7 +411,7 @@ benchmarks! { "seal_balance", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_value_transferred { let r in 0 .. API_BENCHMARK_BATCHES; @@ -363,7 +419,7 @@ benchmarks! { "seal_value_transferred", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_minimum_balance { let r in 0 .. API_BENCHMARK_BATCHES; @@ -371,15 +427,7 @@ benchmarks! { "seal_minimum_balance", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) - - seal_tombstone_deposit { - let r in 0 .. API_BENCHMARK_BATCHES; - let instance = Contract::::new(WasmModule::getter( - "seal_tombstone_deposit", r * API_BENCHMARK_BATCH_SIZE - ), vec![])?; - let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_block_number { let r in 0 .. API_BENCHMARK_BATCHES; @@ -387,7 +435,7 @@ benchmarks! { "seal_block_number", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_now { let r in 0 .. API_BENCHMARK_BATCHES; @@ -395,7 +443,7 @@ benchmarks! { "seal_now", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_weight_to_fee { let r in 0 .. API_BENCHMARK_BATCHES; @@ -422,7 +470,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_gas { let r in 0 .. API_BENCHMARK_BATCHES; @@ -442,7 +490,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_input { let r in 0 .. API_BENCHMARK_BATCHES; @@ -469,7 +517,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_input_per_kb { let n in 0 .. code::max_pages::() * 64; @@ -499,7 +547,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let data = vec![42u8; (n * 1024).min(buffer_size) as usize]; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), data) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, data) // We cannot call `seal_return` multiple times. Therefore our weight determination is not // as precise as with other APIs. Because this function can only be called once per @@ -524,7 +572,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_return_per_kb { let n in 0 .. code::max_pages::() * 64; @@ -547,7 +595,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // The same argument as for `seal_return` is true here. seal_terminate { @@ -579,12 +627,13 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into()); - assert_eq!(T::Currency::total_balance(&instance.account_id), contract_funding::()); - }: call(origin, instance.addr.clone(), 0u32.into(), Weight::max_value(), vec![]) + assert_eq!(T::Currency::free_balance(&instance.account_id), T::Currency::minimum_balance()); + assert_ne!(T::Currency::reserved_balance(&instance.account_id), 0u32.into()); + }: call(origin, instance.addr.clone(), 0u32.into(), Weight::MAX, None, vec![]) verify { if r > 0 { assert_eq!(T::Currency::total_balance(&instance.account_id), 0u32.into()); - assert_eq!(T::Currency::total_balance(&beneficiary), contract_funding::()); + assert_eq!(T::Currency::total_balance(&beneficiary), T::Currency::minimum_balance()); } } @@ -621,7 +670,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Overhead of calling the function without any topic. // We benchmark for the worst case (largest event). @@ -646,7 +695,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Benchmark the overhead that topics generate. // `t`: Number of topics @@ -684,7 +733,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // The size of the supplied message does not influence the weight because as it is never // processed during on-chain execution: It is only ever read during debugging which happens @@ -710,7 +759,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. // The contract is a bit more complex because I needs to use different keys in order @@ -747,7 +796,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_set_storage_per_kb { let n in 0 .. T::Schedule::get().limits.payload_len / 1024; @@ -777,7 +826,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Similar to seal_set_storage. However, we store all the keys that we are about to // delete beforehand in order to prevent any optimizations that could occur when @@ -811,18 +860,19 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; - let mut info = instance.info()?; + let info = instance.info()?; for key in keys { Storage::::write( - &mut info, + &info.trie_id, key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![42; T::Schedule::get().limits.payload_len as usize]) + Some(vec![42; T::Schedule::get().limits.payload_len as usize]), + None, ) .map_err(|_| "Failed to write to storage during setup.")?; } >::insert(&instance.account_id, info.clone()); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // We make sure that all storage accesses are to unique keys. #[skip_meta] @@ -858,18 +908,19 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; - let mut info = instance.info()?; + let info = instance.info()?; for key in keys { Storage::::write( - &mut info, + &info.trie_id, key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![]) + Some(vec![]), + None, ) .map_err(|_| "Failed to write to storage during setup.")?; } >::insert(&instance.account_id, info.clone()); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_get_storage_per_kb { let n in 0 .. T::Schedule::get().limits.payload_len / 1024; @@ -904,16 +955,17 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; - let mut info = instance.info()?; + let info = instance.info()?; Storage::::write( - &mut info, + &info.trie_id, key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![42u8; (n * 1024) as usize]) + Some(vec![42u8; (n * 1024) as usize]), + None, ) .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info.clone()); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // We transfer to unique accounts. seal_transfer { @@ -923,7 +975,7 @@ benchmarks! { .collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); let account_bytes = accounts.iter().flat_map(|x| x.encode()).collect(); - let value = Contracts::::subsistence_threshold(); + let value = T::Currency::minimum_balance(); assert!(value > 0u32.into()); let value_bytes = value.encode(); let value_len = value_bytes.len(); @@ -956,11 +1008,12 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; + instance.set_balance(value * (r * API_BENCHMARK_BATCH_SIZE + 1).into()); let origin = RawOrigin::Signed(instance.caller.clone()); for account in &accounts { assert_eq!(T::Currency::total_balance(account), 0u32.into()); } - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) verify { for account in &accounts { assert_eq!(T::Currency::total_balance(account), value); @@ -1024,7 +1077,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) seal_call_per_transfer_input_output_kb { let t in 0 .. 1; @@ -1109,9 +1162,9 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - // We assume that every instantiate sends at least the subsistence amount. + // We assume that every instantiate sends at least the minimum balance. seal_instantiate { let r in 0 .. API_BENCHMARK_BATCHES; let hashes = (0..r * API_BENCHMARK_BATCH_SIZE) @@ -1127,14 +1180,14 @@ benchmarks! { ])), .. Default::default() }); - Contracts::::store_code_raw(code.code)?; + Contracts::::store_code_raw(code.code, whitelisted_caller())?; Ok(code.hash) }) .collect::, &'static str>>()?; let hash_len = hashes.get(0).map(|x| x.encode().len()).unwrap_or(0); let hashes_bytes = hashes.iter().flat_map(|x| x.encode()).collect::>(); let hashes_len = hashes_bytes.len(); - let value = contract_funding::() / (r * API_BENCHMARK_BATCH_SIZE + 2).into(); + let value = T::Currency::minimum_balance(); assert!(value > 0u32.into()); let value_bytes = value.encode(); let value_len = value_bytes.len(); @@ -1202,6 +1255,7 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; + instance.set_balance(value * (r * API_BENCHMARK_BATCH_SIZE + 1).into()); let origin = RawOrigin::Signed(instance.caller.clone()); let callee = instance.addr.clone(); let addresses = hashes @@ -1216,7 +1270,7 @@ benchmarks! { return Err("Expected that contract does not exist at this point.".into()); } } - }: call(origin, callee, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]) verify { for addr in &addresses { ContractInfoOf::::get(&addr) @@ -1252,12 +1306,12 @@ benchmarks! { let hash = callee_code.hash.clone(); let hash_bytes = callee_code.hash.encode(); let hash_len = hash_bytes.len(); - Contracts::::store_code_raw(callee_code.code)?; + Contracts::::store_code_raw(callee_code.code, whitelisted_caller())?; let inputs = (0..API_BENCHMARK_BATCH_SIZE).map(|x| x.encode()).collect::>(); let input_len = inputs.get(0).map(|x| x.len()).unwrap_or(0); let input_bytes = inputs.iter().cloned().flatten().collect::>(); let inputs_len = input_bytes.len(); - let value = contract_funding::() / (API_BENCHMARK_BATCH_SIZE + 2).into(); + let value = T::Currency::minimum_balance(); assert!(value > 0u32.into()); let value_bytes = value.encode(); let value_len = value_bytes.len(); @@ -1340,8 +1394,9 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; + instance.set_balance(value * (API_BENCHMARK_BATCH_SIZE + 1).into()); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. seal_hash_sha2_256 { @@ -1350,7 +1405,7 @@ benchmarks! { "seal_hash_sha2_256", r * API_BENCHMARK_BATCH_SIZE, 0, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes seal_hash_sha2_256_per_kb { @@ -1359,7 +1414,7 @@ benchmarks! { "seal_hash_sha2_256", API_BENCHMARK_BATCH_SIZE, n * 1024, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. seal_hash_keccak_256 { @@ -1368,7 +1423,7 @@ benchmarks! { "seal_hash_keccak_256", r * API_BENCHMARK_BATCH_SIZE, 0, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes seal_hash_keccak_256_per_kb { @@ -1377,7 +1432,7 @@ benchmarks! { "seal_hash_keccak_256", API_BENCHMARK_BATCH_SIZE, n * 1024, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. seal_hash_blake2_256 { @@ -1386,7 +1441,7 @@ benchmarks! { "seal_hash_blake2_256", r * API_BENCHMARK_BATCH_SIZE, 0, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes seal_hash_blake2_256_per_kb { @@ -1395,7 +1450,7 @@ benchmarks! { "seal_hash_blake2_256", API_BENCHMARK_BATCH_SIZE, n * 1024, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. seal_hash_blake2_128 { @@ -1404,7 +1459,7 @@ benchmarks! { "seal_hash_blake2_128", r * API_BENCHMARK_BATCH_SIZE, 0, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes seal_hash_blake2_128_per_kb { @@ -1413,7 +1468,7 @@ benchmarks! { "seal_hash_blake2_128", API_BENCHMARK_BATCH_SIZE, n * 1024, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only calling the function itself with valid arguments. // It generates different private keys and signatures for the message "Hello world". @@ -1467,7 +1522,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // We make the assumption that pushing a constant and dropping a value takes roughly // the same amount of time. We follow that `t.load` and `drop` both have the weight @@ -2274,6 +2329,7 @@ benchmarks! { instance.account_id, 0u32.into(), Weight::MAX, + None, data, false, ) @@ -2320,6 +2376,7 @@ benchmarks! { instance.account_id, 0u32.into(), Weight::MAX, + None, data, false, ) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index bc88e162c5c0d..916c2d3df84f5 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -16,12 +16,13 @@ // limitations under the License. use crate::{ - gas::GasMeter, storage::Storage, AccountCounter, BalanceOf, CodeHash, Config, ContractInfo, - ContractInfoOf, Error, Event, Pallet as Contracts, Schedule, + gas::GasMeter, + storage::{self, Storage}, + AccountCounter, BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Error, Event, + Pallet as Contracts, Schedule, }; use frame_support::{ dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable}, - ensure, storage::{with_transaction, TransactionOutcome}, traits::{Contains, Currency, ExistenceRequirement, Get, OriginTrait, Randomness, Time}, weights::Weight, @@ -31,14 +32,9 @@ use pallet_contracts_primitives::ExecReturnValue; use smallvec::{Array, SmallVec}; use sp_core::crypto::UncheckedFrom; use sp_io::crypto::secp256k1_ecdsa_recover_compressed; -use sp_runtime::traits::{Convert, Saturating}; +use sp_runtime::traits::Convert; use sp_std::{marker::PhantomData, mem, prelude::*}; -/// When fields are added to the [`ContractInfo`] that can change during execution this -/// variable needs to be set to true. This will also force changes to the -/// `in_memory_changes_not_discarded` test. -const CONTRACT_INFO_CAN_CHANGE: bool = false; - pub type AccountIdOf = ::AccountId; pub type MomentOf = <::Time as Time>::Moment; pub type SeedOf = ::Hash; @@ -112,7 +108,7 @@ pub trait Ext: sealing::Sealed { /// /// Returns the original code size of the called contract. /// The newly created account will be associated with `code`. `value` specifies the amount of - /// value transferred from this to the newly created account (also known as endowment). + /// value transferred from this to the newly created account. /// /// # Return Value /// @@ -159,7 +155,7 @@ pub trait Ext: sealing::Sealed { /// The `value_transferred` is already added. fn balance(&self) -> BalanceOf; - /// Returns the value transferred along with this call or as endowment. + /// Returns the value transferred along with this call. fn value_transferred(&self) -> BalanceOf; /// Returns a reference to the timestamp of the current block @@ -168,9 +164,6 @@ pub trait Ext: sealing::Sealed { /// Returns the minimum balance that is required for creating an account. fn minimum_balance(&self) -> BalanceOf; - /// Returns the deposit required to instantiate a contract. - fn contract_deposit(&self) -> BalanceOf; - /// Returns a random number for the current block with the given subject. fn random(&self, subject: &[u8]) -> (SeedOf, BlockNumberOf); @@ -209,6 +202,10 @@ pub trait Ext: sealing::Sealed { /// Recovers ECDSA compressed public key based on signature and message hash. fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()>; + + /// Tests sometimes need to modify and inspect the contract info directly. + #[cfg(test)] + fn contract_info(&mut self) -> &mut ContractInfo; } /// Describes the different functions that can be exported by an [`Executable`]. @@ -235,37 +232,12 @@ pub trait Executable: Sized { gas_meter: &mut GasMeter, ) -> Result; - /// Load the module from storage without re-instrumenting it. - /// - /// A code module is re-instrumented on-load when it was originally instrumented with - /// an older schedule. This skips this step for cases where the code storage is - /// queried for purposes other than execution. - /// - /// # Note - /// - /// Does not charge from the gas meter. Do not call in contexts where this is important. - fn from_storage_noinstr(code_hash: CodeHash) -> Result; - - /// Increment the refcount by one. Fails if the code does not exist on-chain. - /// - /// Returns the size of the original code. + /// Decrement the refcount by one if the code exists. /// /// # Note /// /// Charges weight proportional to the code size from the gas meter. - fn add_user(code_hash: CodeHash, gas_meter: &mut GasMeter) -> Result<(), DispatchError>; - - /// Decrement the refcount by one and remove the code when it drops to zero. - /// - /// Returns the size of the original code. - /// - /// # Note - /// - /// Charges weight proportional to the code size from the gas meter - fn remove_user( - code_hash: CodeHash, - gas_meter: &mut GasMeter, - ) -> Result<(), DispatchError>; + fn remove_user(code_hash: CodeHash) -> Result<(), DispatchError>; /// Execute the specified exported function and return the result. /// @@ -288,12 +260,6 @@ pub trait Executable: Sized { /// Size of the instrumented code in bytes. fn code_len(&self) -> u32; - - /// Sum of instrumented and pristine code len. - fn aggregate_code_len(&self) -> u32; - - // The number of contracts using this executable. - fn refcount(&self) -> u32; } /// The complete call stack of a contract execution. @@ -314,6 +280,8 @@ pub struct Stack<'a, T: Config, E> { schedule: &'a Schedule, /// The gas meter where costs are charged to. gas_meter: &'a mut GasMeter, + /// The storage meter makes sure that the storage deposit limit is obeyed. + storage_meter: &'a mut storage::meter::Meter, /// The timestamp at the point of call stack instantiation. timestamp: MomentOf, /// The block number at the time of call stack instantiation. @@ -354,7 +322,9 @@ pub struct Frame { /// Determines whether this is a call or instantiate frame. entry_point: ExportedFunction, /// The gas meter capped to the supplied gas limit. - nested_meter: GasMeter, + nested_gas: GasMeter, + /// The storage meter for the individual call. + nested_storage: storage::meter::NestedMeter, /// If `false` the contract enabled its defense against reentrance attacks. allows_reentry: bool, } @@ -396,6 +366,26 @@ enum CachedContract { Terminated, } +impl CachedContract { + /// Return `Some(ContractInfo)` if the contract is in cached state. `None` otherwise. + fn into_contract(self) -> Option> { + if let CachedContract::Cached(contract) = self { + Some(contract) + } else { + None + } + } + + /// Return `Some(&mut ContractInfo)` if the contract is in cached state. `None` otherwise. + fn as_contract(&mut self) -> Option<&mut ContractInfo> { + if let CachedContract::Cached(contract) = self { + Some(contract) + } else { + None + } + } +} + impl Frame { /// Return the `contract_info` of the current contract. fn contract_info(&mut self) -> &mut ContractInfo { @@ -432,6 +422,26 @@ macro_rules! get_cached_or_panic_after_load { }}; } +/// Same as [`Stack::top_frame`]. +/// +/// We need this access as a macro because sometimes hiding the lifetimes behind +/// a function won't work out. +macro_rules! top_frame { + ($stack:expr) => { + $stack.frames.last().unwrap_or(&$stack.first_frame) + }; +} + +/// Same as [`Stack::top_frame_mut`]. +/// +/// We need this access as a macro because sometimes hiding the lifetimes behind +/// a function won't work out. +macro_rules! top_frame_mut { + ($stack:expr) => { + $stack.frames.last_mut().unwrap_or(&mut $stack.first_frame) + }; +} + impl CachedContract { /// Load the `contract_info` from storage if necessary. fn load(&mut self, account_id: &T::AccountId) { @@ -476,6 +486,7 @@ where origin: T::AccountId, dest: T::AccountId, gas_meter: &'a mut GasMeter, + storage_meter: &'a mut storage::meter::Meter, schedule: &'a Schedule, value: BalanceOf, input_data: Vec, @@ -485,6 +496,7 @@ where FrameArgs::Call { dest, cached_info: None }, origin, gas_meter, + storage_meter, schedule, value, debug_message, @@ -506,6 +518,7 @@ where origin: T::AccountId, executable: E, gas_meter: &'a mut GasMeter, + storage_meter: &'a mut storage::meter::Meter, schedule: &'a Schedule, value: BalanceOf, input_data: Vec, @@ -521,6 +534,7 @@ where }, origin, gas_meter, + storage_meter, schedule, value, debug_message, @@ -534,16 +548,18 @@ where args: FrameArgs, origin: T::AccountId, gas_meter: &'a mut GasMeter, + storage_meter: &'a mut storage::meter::Meter, schedule: &'a Schedule, value: BalanceOf, debug_message: Option<&'a mut Vec>, ) -> Result<(Self, E), ExecError> { let (first_frame, executable, account_counter) = - Self::new_frame(args, value, gas_meter, 0, &schedule)?; + Self::new_frame(args, value, gas_meter, storage_meter, 0, &schedule)?; let stack = Self { origin, schedule, gas_meter, + storage_meter, timestamp: T::Time::now(), block_number: >::block_number(), account_counter, @@ -560,10 +576,11 @@ where /// /// This does not take `self` because when constructing the first frame `self` is /// not initialized, yet. - fn new_frame( + fn new_frame( frame_args: FrameArgs, value_transferred: BalanceOf, gas_meter: &mut GasMeter, + storage_meter: &mut storage::meter::GenericMeter, gas_limit: Weight, schedule: &Schedule, ) -> Result<(Frame, E, Option), ExecError> { @@ -598,7 +615,8 @@ where contract_info: CachedContract::Cached(contract_info), account_id, entry_point, - nested_meter: gas_meter.nested(gas_limit)?, + nested_gas: gas_meter.nested(gas_limit)?, + nested_storage: storage_meter.nested(), allows_reentry: true, }; @@ -616,23 +634,28 @@ where return Err(Error::::MaxCallDepthReached.into()) } - if CONTRACT_INFO_CAN_CHANGE { - // We need to make sure that changes made to the contract info are not discarded. - // See the `in_memory_changes_not_discarded` test for more information. - // We do not store on instantiate because we do not allow to call into a contract - // from its own constructor. - let frame = self.top_frame(); - if let (CachedContract::Cached(contract), ExportedFunction::Call) = - (&frame.contract_info, frame.entry_point) - { - >::insert(frame.account_id.clone(), contract.clone()); - } + // We need to make sure that changes made to the contract info are not discarded. + // See the `in_memory_changes_not_discarded` test for more information. + // We do not store on instantiate because we do not allow to call into a contract + // from its own constructor. + let frame = self.top_frame(); + if let (CachedContract::Cached(contract), ExportedFunction::Call) = + (&frame.contract_info, frame.entry_point) + { + >::insert(frame.account_id.clone(), contract.clone()); } - let nested_meter = - &mut self.frames.last_mut().unwrap_or(&mut self.first_frame).nested_meter; - let (frame, executable, _) = - Self::new_frame(frame_args, value_transferred, nested_meter, gas_limit, self.schedule)?; + let frame = top_frame_mut!(self); + let nested_gas = &mut frame.nested_gas; + let nested_storage = &mut frame.nested_storage; + let (frame, executable, _) = Self::new_frame( + frame_args, + value_transferred, + nested_gas, + nested_storage, + gas_limit, + self.schedule, + )?; self.frames.push(frame); Ok(executable) } @@ -643,6 +666,17 @@ where fn run(&mut self, executable: E, input_data: Vec) -> Result { let entry_point = self.top_frame().entry_point; let do_transaction = || { + // We need to charge the storage deposit before the initial transfer so that + // it can create the account in case the initial transfer is < ed. + if entry_point == ExportedFunction::Constructor { + let top_frame = top_frame_mut!(self); + top_frame.nested_storage.charge_instantiate( + &self.origin, + &top_frame.account_id, + &mut top_frame.contract_info.get(&top_frame.account_id), + )?; + } + // Every call or instantiate also optionally transferres balance. self.initial_transfer()?; @@ -653,18 +687,20 @@ where // Additional work needs to be performed in case of an instantiation. if output.is_success() && entry_point == ExportedFunction::Constructor { - let frame = self.top_frame_mut(); - let account_id = frame.account_id.clone(); + let frame = self.top_frame(); // It is not allowed to terminate a contract inside its constructor. - if let CachedContract::Terminated = frame.contract_info { + if matches!(frame.contract_info, CachedContract::Terminated) { return Err(Error::::TerminatedInConstructor.into()) } // Deposit an instantiation event. deposit_event::( vec![], - Event::Instantiated { deployer: self.caller().clone(), contract: account_id }, + Event::Instantiated { + deployer: self.caller().clone(), + contract: frame.account_id.clone(), + }, ); } @@ -700,15 +736,34 @@ where // A `None` means that we are returning from the `first_frame`. let frame = self.frames.pop(); - if let Some(frame) = frame { - let prev = self.top_frame_mut(); + // Both branches do essentially the same with the exception. The difference is that + // the else branch does consume the hardcoded `first_frame`. + if let Some(mut frame) = frame { let account_id = &frame.account_id; - prev.nested_meter.absorb_nested(frame.nested_meter); + let prev = top_frame_mut!(self); + + prev.nested_gas.absorb_nested(frame.nested_gas); + // Only gas counter changes are persisted in case of a failure. if !persist { return } - if let CachedContract::Cached(contract) = frame.contract_info { + + // Record the storage meter changes of the nested call into the parent meter. + // If the dropped frame's contract wasn't terminated we update the deposit counter + // in its contract info. The load is necessary to to pull it from storage in case + // it was invalidated. + frame.contract_info.load(account_id); + let mut contract = frame.contract_info.into_contract(); + prev.nested_storage.absorb( + frame.nested_storage, + &self.origin, + account_id, + contract.as_mut(), + ); + + // In case the contract wasn't terminated we need to persist changes made to it. + if let Some(contract) = contract { // optimization: Predecessor is the same contract. // We can just copy the contract into the predecessor without a storage write. // This is possible when there is no other contract in-between that could @@ -736,14 +791,19 @@ where core::str::from_utf8(msg).unwrap_or(""), ); } - // Write back to the root gas meter. - self.gas_meter.absorb_nested(mem::take(&mut self.first_frame.nested_meter)); - // Only gas counter changes are persisted in case of a failure. + self.gas_meter.absorb_nested(mem::take(&mut self.first_frame.nested_gas)); if !persist { return } - if let CachedContract::Cached(contract) = &self.first_frame.contract_info { - >::insert(&self.first_frame.account_id, contract.clone()); + let mut contract = self.first_frame.contract_info.as_contract(); + self.storage_meter.absorb( + mem::take(&mut self.first_frame.nested_storage), + &self.origin, + &self.first_frame.account_id, + contract.as_deref_mut(), + ); + if let Some(contract) = contract { + >::insert(&self.first_frame.account_id, contract); } if let Some(counter) = self.account_counter { >::set(counter); @@ -752,38 +812,14 @@ where } /// Transfer some funds from `from` to `to`. - /// - /// We only allow allow for draining all funds of the sender if `allow_death` is - /// is specified as `true`. Otherwise, any transfer that would bring the sender below the - /// subsistence threshold (for contracts) or the existential deposit (for plain accounts) - /// results in an error. fn transfer( - sender_is_contract: bool, - allow_death: bool, + existence_requirement: ExistenceRequirement, from: &T::AccountId, to: &T::AccountId, value: BalanceOf, ) -> DispatchResult { - if value == 0u32.into() { - return Ok(()) - } - - let existence_requirement = match (allow_death, sender_is_contract) { - (true, _) => ExistenceRequirement::AllowDeath, - (false, true) => { - ensure!( - T::Currency::total_balance(from).saturating_sub(value) >= - Contracts::::subsistence_threshold(), - Error::::BelowSubsistenceThreshold, - ); - ExistenceRequirement::KeepAlive - }, - (false, false) => ExistenceRequirement::KeepAlive, - }; - T::Currency::transfer(from, to, value, existence_requirement) .map_err(|_| Error::::TransferFailed)?; - Ok(()) } @@ -791,31 +827,18 @@ where fn initial_transfer(&self) -> DispatchResult { let frame = self.top_frame(); let value = frame.value_transferred; - let subsistence_threshold = >::subsistence_threshold(); - - // If the value transferred to a new contract is less than the subsistence threshold - // we can error out early. This avoids executing the constructor in cases where - // we already know that the contract has too little balance. - if frame.entry_point == ExportedFunction::Constructor && value < subsistence_threshold { - return Err(>::NewContractNotFunded.into()) - } - Self::transfer(self.caller_is_origin(), false, self.caller(), &frame.account_id, value) - } - - /// Wether the caller is the initiator of the call stack. - fn caller_is_origin(&self) -> bool { - !self.frames.is_empty() + Self::transfer(ExistenceRequirement::KeepAlive, self.caller(), &frame.account_id, value) } /// Reference to the current (top) frame. fn top_frame(&self) -> &Frame { - self.frames.last().unwrap_or(&self.first_frame) + top_frame!(self) } /// Mutable reference to the current (top) frame. fn top_frame_mut(&mut self) -> &mut Frame { - self.frames.last_mut().unwrap_or(&mut self.first_frame) + top_frame_mut!(self) } /// Iterator over all frames. @@ -911,7 +934,7 @@ where &mut self, gas_limit: Weight, code_hash: CodeHash, - endowment: BalanceOf, + value: BalanceOf, input_data: Vec, salt: &[u8], ) -> Result<(AccountIdOf, ExecReturnValue), ExecError> { @@ -924,7 +947,7 @@ where executable, salt, }, - endowment, + value, gas_limit, )?; let account_id = self.top_frame().account_id.clone(); @@ -937,16 +960,16 @@ where } let frame = self.top_frame_mut(); let info = frame.terminate(); + frame.nested_storage.terminate(&info); Storage::::queue_trie_for_deletion(&info)?; >::transfer( - true, - true, + ExistenceRequirement::AllowDeath, &frame.account_id, beneficiary, T::Currency::free_balance(&frame.account_id), )?; ContractInfoOf::::remove(&frame.account_id); - E::remove_user(info.code_hash, &mut frame.nested_meter)?; + E::remove_user(info.code_hash)?; Contracts::::deposit_event(Event::Terminated { contract: frame.account_id.clone(), beneficiary: beneficiary.clone(), @@ -955,7 +978,7 @@ where } fn transfer(&mut self, to: &T::AccountId, value: BalanceOf) -> DispatchResult { - Self::transfer(true, false, &self.top_frame().account_id, to, value) + Self::transfer(ExistenceRequirement::KeepAlive, &self.top_frame().account_id, to, value) } fn get_storage(&mut self, key: &StorageKey) -> Option> { @@ -964,7 +987,12 @@ where fn set_storage(&mut self, key: StorageKey, value: Option>) -> DispatchResult { let frame = self.top_frame_mut(); - Storage::::write(frame.contract_info(), &key, value) + Storage::::write( + &frame.contract_info.get(&frame.account_id).trie_id, + &key, + value, + Some(&mut frame.nested_storage), + ) } fn address(&self) -> &T::AccountId { @@ -995,10 +1023,6 @@ where T::Currency::minimum_balance() } - fn contract_deposit(&self) -> BalanceOf { - T::ContractDeposit::get() - } - fn deposit_event(&mut self, topics: Vec, data: Vec) { deposit_event::( topics, @@ -1023,7 +1047,7 @@ where } fn gas_meter(&mut self) -> &mut GasMeter { - &mut self.top_frame_mut().nested_meter + &mut self.top_frame_mut().nested_gas } fn append_debug_buffer(&mut self, msg: &str) -> bool { @@ -1046,6 +1070,11 @@ where fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()> { secp256k1_ecdsa_recover_compressed(&signature, &message_hash).map_err(|_| ()) } + + #[cfg(test)] + fn contract_info(&mut self) -> &mut ContractInfo { + self.top_frame_mut().contract_info() + } } fn deposit_event(topics: Vec, event: Event) { @@ -1083,9 +1112,9 @@ mod tests { storage::Storage, tests::{ test_utils::{get_balance, place_contract, set_balance}, - Call, Event as MetaEvent, ExtBuilder, Test, TestFilter, ALICE, BOB, CHARLIE, + Call, Event as MetaEvent, ExtBuilder, Test, TestFilter, ALICE, BOB, CHARLIE, GAS_LIMIT, }, - Error, Weight, + Error, }; use assert_matches::assert_matches; use codec::{Decode, Encode}; @@ -1101,8 +1130,6 @@ mod tests { type MockStack<'a> = Stack<'a, Test, MockExecutable>; - const GAS_LIMIT: Weight = 10_000_000_000; - thread_local! { static LOADER: RefCell = RefCell::new(MockLoader::default()); } @@ -1193,10 +1220,6 @@ mod tests { _schedule: &Schedule, _gas_meter: &mut GasMeter, ) -> Result { - Self::from_storage_noinstr(code_hash) - } - - fn from_storage_noinstr(code_hash: CodeHash) -> Result { LOADER.with(|loader| { loader .borrow_mut() @@ -1207,18 +1230,7 @@ mod tests { }) } - fn add_user( - code_hash: CodeHash, - _: &mut GasMeter, - ) -> Result<(), DispatchError> { - MockLoader::increment_refcount(code_hash); - Ok(()) - } - - fn remove_user( - code_hash: CodeHash, - _: &mut GasMeter, - ) -> Result<(), DispatchError> { + fn remove_user(code_hash: CodeHash) -> Result<(), DispatchError> { MockLoader::decrement_refcount(code_hash); Ok(()) } @@ -1246,14 +1258,6 @@ mod tests { fn code_len(&self) -> u32 { 0 } - - fn aggregate_code_len(&self) -> u32 { - 0 - } - - fn refcount(&self) -> u32 { - self.refcount as u32 - } } fn exec_success() -> ExecResult { @@ -1280,9 +1284,19 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = ::Schedule::get(); place_contract(&BOB, exec_ch); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), value).unwrap(); assert_matches!( - MockStack::run_call(ALICE, BOB, &mut gas_meter, &schedule, value, vec![], None,), + MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + value, + vec![], + None, + ), Ok(_) ); }); @@ -1301,7 +1315,7 @@ mod tests { set_balance(&origin, 100); set_balance(&dest, 0); - MockStack::transfer(true, false, &origin, &dest, 55).unwrap(); + MockStack::transfer(ExistenceRequirement::KeepAlive, &origin, &dest, 55).unwrap(); assert_eq!(get_balance(&origin), 45); assert_eq!(get_balance(&dest), 55); @@ -1324,11 +1338,13 @@ mod tests { place_contract(&dest, return_ch); set_balance(&origin, 100); let balance = get_balance(&dest); + let mut storage_meter = storage::meter::Meter::new(&origin, Some(0), 55).unwrap(); let output = MockStack::run_call( origin.clone(), dest.clone(), &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, 55, vec![], @@ -1352,7 +1368,7 @@ mod tests { ExtBuilder::default().build().execute_with(|| { set_balance(&origin, 0); - let result = MockStack::transfer(false, false, &origin, &dest, 100); + let result = MockStack::transfer(ExistenceRequirement::KeepAlive, &origin, &dest, 100); assert_eq!(result, Err(Error::::TransferFailed.into())); assert_eq!(get_balance(&origin), 0); @@ -1372,12 +1388,14 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = ::Schedule::get(); + let mut storage_meter = storage::meter::Meter::new(&origin, Some(0), 0).unwrap(); place_contract(&BOB, return_ch); let result = MockStack::run_call( origin, dest, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, 0, vec![], @@ -1403,11 +1421,13 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = ::Schedule::get(); place_contract(&BOB, return_ch); + let mut storage_meter = storage::meter::Meter::new(&origin, Some(0), 0).unwrap(); let result = MockStack::run_call( origin, dest, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, 0, vec![], @@ -1431,11 +1451,13 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = ::Schedule::get(); place_contract(&BOB, input_data_ch); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); let result = MockStack::run_call( ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, 0, vec![1, 2, 3, 4], @@ -1455,19 +1477,21 @@ mod tests { // This one tests passing the input data into a contract via instantiate. ExtBuilder::default().build().execute_with(|| { let schedule = ::Schedule::get(); - let subsistence = Contracts::::subsistence_threshold(); + let min_balance = ::Currency::minimum_balance(); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage(input_data_ch, &schedule, &mut gas_meter).unwrap(); - - set_balance(&ALICE, subsistence * 10); + set_balance(&ALICE, min_balance * 1000); + let mut storage_meter = + storage::meter::Meter::new(&ALICE, Some(min_balance * 100), min_balance).unwrap(); let result = MockStack::run_instantiate( ALICE, executable, &mut gas_meter, + &mut storage_meter, &schedule, - subsistence * 3, + min_balance, vec![1, 2, 3, 4], &[], None, @@ -1508,11 +1532,13 @@ mod tests { let schedule = ::Schedule::get(); set_balance(&BOB, 1); place_contract(&BOB, recurse_ch); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), value).unwrap(); let result = MockStack::run_call( ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, value, vec![], @@ -1553,11 +1579,13 @@ mod tests { let schedule = ::Schedule::get(); place_contract(&dest, bob_ch); place_contract(&CHARLIE, charlie_ch); + let mut storage_meter = storage::meter::Meter::new(&origin, Some(0), 0).unwrap(); let result = MockStack::run_call( origin.clone(), dest.clone(), &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, 0, vec![], @@ -1590,11 +1618,13 @@ mod tests { let schedule = ::Schedule::get(); place_contract(&BOB, bob_ch); place_contract(&CHARLIE, charlie_ch); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); let result = MockStack::run_call( ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, 0, vec![], @@ -1614,14 +1644,16 @@ mod tests { let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage(dummy_ch, &schedule, &mut gas_meter).unwrap(); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); assert_matches!( MockStack::run_instantiate( ALICE, executable, &mut gas_meter, + &mut storage_meter, &schedule, - 0, // <- zero endowment + 0, // <- zero value vec![], &[], None, @@ -1639,18 +1671,22 @@ mod tests { ExtBuilder::default().existential_deposit(15).build().execute_with(|| { let schedule = ::Schedule::get(); + let min_balance = ::Currency::minimum_balance(); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage(dummy_ch, &schedule, &mut gas_meter).unwrap(); - set_balance(&ALICE, 1000); + set_balance(&ALICE, min_balance * 1000); + let mut storage_meter = + storage::meter::Meter::new(&ALICE, Some(min_balance * 100), min_balance).unwrap(); let instantiated_contract_address = assert_matches!( MockStack::run_instantiate( ALICE, executable, &mut gas_meter, + &mut storage_meter, &schedule, - 100, + min_balance, vec![], &[], None, @@ -1679,18 +1715,22 @@ mod tests { ExtBuilder::default().existential_deposit(15).build().execute_with(|| { let schedule = ::Schedule::get(); + let min_balance = ::Currency::minimum_balance(); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage(dummy_ch, &schedule, &mut gas_meter).unwrap(); - set_balance(&ALICE, 1000); + set_balance(&ALICE, min_balance * 1000); + let mut storage_meter = + storage::meter::Meter::new(&ALICE, Some(min_balance * 100), min_balance).unwrap(); let instantiated_contract_address = assert_matches!( MockStack::run_instantiate( ALICE, executable, &mut gas_meter, + &mut storage_meter, &schedule, - 100, + min_balance, vec![], &[], None, @@ -1718,7 +1758,7 @@ mod tests { .instantiate( 0, dummy_ch, - Contracts::::subsistence_threshold() * 3, + ::Currency::minimum_balance(), vec![], &[48, 49, 50], ) @@ -1731,16 +1771,21 @@ mod tests { ExtBuilder::default().existential_deposit(15).build().execute_with(|| { let schedule = ::Schedule::get(); - set_balance(&ALICE, Contracts::::subsistence_threshold() * 100); + let min_balance = ::Currency::minimum_balance(); + set_balance(&ALICE, min_balance * 100); place_contract(&BOB, instantiator_ch); + let mut storage_meter = + storage::meter::Meter::new(&ALICE, Some(min_balance * 10), min_balance * 10) + .unwrap(); assert_matches!( MockStack::run_call( ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, - 20, + min_balance * 10, vec![], None, ), @@ -1774,7 +1819,7 @@ mod tests { ctx.ext.instantiate( 0, dummy_ch, - Contracts::::subsistence_threshold(), + ::Currency::minimum_balance(), vec![], &[], ), @@ -1793,14 +1838,16 @@ mod tests { set_balance(&ALICE, 1000); set_balance(&BOB, 100); place_contract(&BOB, instantiator_ch); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(100), 0).unwrap(); assert_matches!( MockStack::run_call( ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, - 20, + 0, vec![], None, ), @@ -1826,12 +1873,14 @@ mod tests { let executable = MockExecutable::from_storage(terminate_ch, &schedule, &mut gas_meter).unwrap(); set_balance(&ALICE, 1000); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(100), 100).unwrap(); assert_eq!( MockStack::run_instantiate( ALICE, executable, &mut gas_meter, + &mut storage_meter, &schedule, 100, vec![], @@ -1847,10 +1896,6 @@ mod tests { #[test] fn in_memory_changes_not_discarded() { - // Remove this assert and fill out the "DO" stubs once fields are added to the - // contract info that can be modified during exection. - assert!(!CONTRACT_INFO_CAN_CHANGE); - // Call stack: BOB -> CHARLIE (trap) -> BOB' (success) // This tests verfies some edge case of the contract info cache: // We change some value in our contract info before calling into a contract @@ -1861,9 +1906,11 @@ mod tests { // are made before calling into CHARLIE are not discarded. let code_bob = MockLoader::insert(Call, |ctx, _| { if ctx.input_data[0] == 0 { - // DO: modify medata (ContractInfo) of own contract through ctx.ext functions + let info = ctx.ext.contract_info(); + assert_eq!(info.storage_deposit, 0); + info.storage_deposit = 42; assert_eq!(ctx.ext.call(0, CHARLIE, 0, vec![], true), exec_trapped()); - // DO: check that the value is not discarded (query via ctx.ext) + assert_eq!(ctx.ext.contract_info().storage_deposit, 42); } exec_success() }); @@ -1877,11 +1924,13 @@ mod tests { let schedule = ::Schedule::get(); place_contract(&BOB, code_bob); place_contract(&CHARLIE, code_charlie); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); let result = MockStack::run_call( ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, 0, vec![0], @@ -1904,18 +1953,20 @@ mod tests { // This one tests passing the input data into a contract via instantiate. ExtBuilder::default().build().execute_with(|| { let schedule = ::Schedule::get(); - let subsistence = Contracts::::subsistence_threshold(); + let min_balance = ::Currency::minimum_balance(); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage(code, &schedule, &mut gas_meter).unwrap(); - - set_balance(&ALICE, subsistence * 10); + set_balance(&ALICE, min_balance * 1000); + let mut storage_meter = + storage::meter::Meter::new(&ALICE, Some(min_balance * 100), min_balance).unwrap(); let result = MockStack::run_instantiate( ALICE, executable, &mut gas_meter, + &mut storage_meter, &schedule, - subsistence * 3, + min_balance, vec![], &[], None, @@ -1935,15 +1986,17 @@ mod tests { let mut debug_buffer = Vec::new(); ExtBuilder::default().build().execute_with(|| { - let subsistence = Contracts::::subsistence_threshold(); + let min_balance = ::Currency::minimum_balance(); let schedule = ::Schedule::get(); let mut gas_meter = GasMeter::::new(GAS_LIMIT); - set_balance(&ALICE, subsistence * 10); + set_balance(&ALICE, min_balance * 10); place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); MockStack::run_call( ALICE, BOB, &mut gas_meter, + &mut storage_meter, &schedule, 0, vec![], @@ -1966,15 +2019,17 @@ mod tests { let mut debug_buffer = Vec::new(); ExtBuilder::default().build().execute_with(|| { - let subsistence = Contracts::::subsistence_threshold(); + let min_balance = ::Currency::minimum_balance(); let schedule = ::Schedule::get(); let mut gas_meter = GasMeter::::new(GAS_LIMIT); - set_balance(&ALICE, subsistence * 10); + set_balance(&ALICE, min_balance * 10); place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); let result = MockStack::run_call( ALICE, BOB, &mut gas_meter, + &mut storage_meter, &schedule, 0, vec![], @@ -2000,12 +2055,14 @@ mod tests { let schedule = ::Schedule::get(); place_contract(&BOB, code_bob); place_contract(&CHARLIE, code_charlie); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); // Calling another contract should succeed assert_ok!(MockStack::run_call( ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, 0, CHARLIE.encode(), @@ -2018,6 +2075,7 @@ mod tests { ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, 0, BOB.encode(), @@ -2047,6 +2105,7 @@ mod tests { let schedule = ::Schedule::get(); place_contract(&BOB, code_bob); place_contract(&CHARLIE, code_charlie); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); // BOB -> CHARLIE -> BOB fails as BOB denies reentry. assert_err!( @@ -2054,6 +2113,7 @@ mod tests { ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, &schedule, 0, vec![0], @@ -2076,13 +2136,24 @@ mod tests { }); ExtBuilder::default().build().execute_with(|| { - let subsistence = Contracts::::subsistence_threshold(); + let min_balance = ::Currency::minimum_balance(); let schedule = ::Schedule::get(); let mut gas_meter = GasMeter::::new(GAS_LIMIT); - set_balance(&ALICE, subsistence * 10); + set_balance(&ALICE, min_balance * 10); place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); System::reset_events(); - MockStack::run_call(ALICE, BOB, &mut gas_meter, &schedule, 0, vec![], None).unwrap(); + MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + None, + ) + .unwrap(); let remark_hash = ::Hashing::hash(b"Hello World"); assert_eq!( @@ -2136,13 +2207,24 @@ mod tests { }); ExtBuilder::default().build().execute_with(|| { - let subsistence = Contracts::::subsistence_threshold(); + let min_balance = ::Currency::minimum_balance(); let schedule = ::Schedule::get(); let mut gas_meter = GasMeter::::new(GAS_LIMIT); - set_balance(&ALICE, subsistence * 10); + set_balance(&ALICE, min_balance * 10); place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); System::reset_events(); - MockStack::run_call(ALICE, BOB, &mut gas_meter, &schedule, 0, vec![], None).unwrap(); + MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + None, + ) + .unwrap(); let remark_hash = ::Hashing::hash(b"Hello"); assert_eq!( @@ -2209,11 +2291,15 @@ mod tests { let succ_succ_executable = MockExecutable::from_storage(succ_succ_code, &schedule, &mut gas_meter).unwrap(); set_balance(&ALICE, min_balance * 1000); + let mut storage_meter = + storage::meter::Meter::new(&ALICE, Some(min_balance * 500), min_balance * 100) + .unwrap(); MockStack::run_instantiate( ALICE, fail_executable, &mut gas_meter, + &mut storage_meter, &schedule, min_balance * 100, vec![], @@ -2227,6 +2313,7 @@ mod tests { ALICE, success_executable, &mut gas_meter, + &mut storage_meter, &schedule, min_balance * 100, vec![], @@ -2239,6 +2326,7 @@ mod tests { ALICE, succ_fail_executable, &mut gas_meter, + &mut storage_meter, &schedule, min_balance * 200, vec![], @@ -2251,6 +2339,7 @@ mod tests { ALICE, succ_succ_executable, &mut gas_meter, + &mut storage_meter, &schedule, min_balance * 200, vec![], diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index b2e221dde6ad9..0b8786fa704a3 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -106,24 +106,27 @@ pub use crate::{ use crate::{ exec::{AccountIdOf, ExecError, Executable, Stack as ExecStack}, gas::GasMeter, - storage::{ContractInfo, DeletedContract, Storage}, - wasm::PrefabWasmModule, + storage::{meter::Meter as StorageMeter, ContractInfo, DeletedContract, Storage}, + wasm::{OwnerInfo, PrefabWasmModule}, weights::WeightInfo, }; +use codec::{Encode, HasCompact}; use frame_support::{ dispatch::Dispatchable, ensure, - traits::{Contains, Currency, Get, Randomness, StorageVersion, Time}, - weights::{GetDispatchInfo, PostDispatchInfo, Weight}, + traits::{Contains, Currency, Get, Randomness, ReservableCurrency, StorageVersion, Time}, + weights::{GetDispatchInfo, Pays, PostDispatchInfo, Weight}, }; use frame_system::Pallet as System; use pallet_contracts_primitives::{ - Code, ContractAccessError, ContractExecResult, ContractInstantiateResult, ExecReturnValue, - GetStorageResult, InstantiateReturnValue, + Code, CodeUploadResult, CodeUploadReturnValue, ContractAccessError, ContractExecResult, + ContractInstantiateResult, ExecReturnValue, GetStorageResult, InstantiateReturnValue, + StorageDeposit, }; +use scale_info::TypeInfo; use sp_core::{crypto::UncheckedFrom, Bytes}; use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup}; -use sp_std::prelude::*; +use sp_std::{fmt::Debug, prelude::*}; type CodeHash = ::Hash; type TrieId = Vec; @@ -131,7 +134,7 @@ type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; /// The current storage version. -const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); +const STORAGE_VERSION: StorageVersion = StorageVersion::new(6); #[frame_support::pallet] pub mod pallet { @@ -148,7 +151,7 @@ pub mod pallet { type Randomness: Randomness; /// The currency in which fees are paid and contract balances are held. - type Currency: Currency; + type Currency: ReservableCurrency; /// The overarching event type. type Event: From> + IsType<::Event>; @@ -165,12 +168,6 @@ pub mod pallet { /// This is applied in **addition** to [`frame_system::Config::BaseCallFilter`]. /// It is recommended to treat this as a whitelist. /// - /// # Subsistence Threshold - /// - /// The runtime **must** make sure that any allowed dispatchable makes sure that the - /// `total_balance` of the contract stays above [`Pallet::subsistence_threshold()`]. - /// Otherwise users could clutter the storage with contracts. - /// /// # Stability /// /// The runtime **must** make sure that all dispatchables that are callable by @@ -201,13 +198,6 @@ pub mod pallet { #[pallet::constant] type Schedule: Get>; - /// The deposit that must be placed into the contract's account to instantiate it. - /// This is in **addition** to the [`Currency::minimum_balance`]. - /// The minimum balance for a contract's account can be queried using - /// [`Pallet::subsistence_threshold`]. - #[pallet::constant] - type ContractDeposit: Get>; - /// The type of the call stack determines the maximum nesting depth of contract calls. /// /// The allowed depth is `CallStack::size() + 1`. @@ -222,6 +212,21 @@ pub mod pallet { /// The maximum amount of weight that can be consumed per block for lazy trie removal. #[pallet::constant] type DeletionWeightLimit: Get; + + /// The amount of balance a caller has to pay for each byte of storage. + /// + /// # Note + /// + /// Changing this value for an existing chain might need a storage migration. + #[pallet::constant] + type DepositPerByte: Get>; + + /// The amount of balance a caller has to pay for each storage item. + /// # Note + /// + /// Changing this value for an existing chain might need a storage migration. + #[pallet::constant] + type DepositPerItem: Get>; } #[pallet::pallet] @@ -255,9 +260,19 @@ pub mod pallet { where T::AccountId: UncheckedFrom, T::AccountId: AsRef<[u8]>, + as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode, { /// Makes a call to an account, optionally transferring some balance. /// + /// # Parameters + /// + /// * `dest`: Address of the contract to call. + /// * `value`: The balance to transfer from the `origin` to `dest`. + /// * `gas_limit`: The gas limit enforced when executing the constructor. + /// * `storage_deposit_limit`: The maximum amount of balance that can be charged from the + /// caller to pay for the storage consumed. + /// * `data`: The input data to pass to the contract. + /// /// * If the account is a smart-contract account, the associated code will be /// executed and any value will be transferred. /// * If the account is a regular account, any value will be transferred. @@ -269,23 +284,36 @@ pub mod pallet { dest: ::Source, #[pallet::compact] value: BalanceOf, #[pallet::compact] gas_limit: Weight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, data: Vec, ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; - let output = Self::internal_call(origin, dest, value, gas_limit, data, None); + let output = Self::internal_call( + origin, + dest, + value, + gas_limit, + storage_deposit_limit.map(Into::into), + data, + None, + ); output.gas_meter.into_dispatch_result(output.result, T::WeightInfo::call()) } /// Instantiates a new contract from the supplied `code` optionally transferring /// some balance. /// - /// This is the only function that can deploy new code to the chain. + /// This dispatchable has the same effect as calling [`Self::upload_code`] + + /// [`Self::instantiate`]. Bundling them together provides efficiency gains. Please + /// also check the documentation of [`Self::upload_code`]. /// /// # Parameters /// - /// * `endowment`: The balance to transfer from the `origin` to the newly created contract. + /// * `value`: The balance to transfer from the `origin` to the newly created contract. /// * `gas_limit`: The gas limit enforced when executing the constructor. + /// * `storage_deposit_limit`: The maximum amount of balance that can be charged/reserved + /// from the caller to pay for the storage consumed. /// * `code`: The contract code to deploy in raw bytes. /// * `data`: The input data to pass to the contract constructor. /// * `salt`: Used for the address derivation. See [`Pallet::contract_address`]. @@ -297,7 +325,7 @@ pub mod pallet { /// - If the `code_hash` already exists on the chain the underlying `code` will be shared. /// - The destination address is computed based on the sender, code_hash and the salt. /// - The smart-contract account is created at the computed address. - /// - The `endowment` is transferred to the new account. + /// - The `value` is transferred to the new account. /// - The `deploy` function is executed in the context of the newly-created account. #[pallet::weight( T::WeightInfo::instantiate_with_code( @@ -308,8 +336,9 @@ pub mod pallet { )] pub fn instantiate_with_code( origin: OriginFor, - #[pallet::compact] endowment: BalanceOf, + #[pallet::compact] value: BalanceOf, #[pallet::compact] gas_limit: Weight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, code: Vec, data: Vec, salt: Vec, @@ -319,8 +348,9 @@ pub mod pallet { let salt_len = salt.len() as u32; let output = Self::internal_instantiate( origin, - endowment, + value, gas_limit, + storage_deposit_limit.map(Into::into), Code::Upload(Bytes(code)), data, salt, @@ -342,8 +372,9 @@ pub mod pallet { )] pub fn instantiate( origin: OriginFor, - #[pallet::compact] endowment: BalanceOf, + #[pallet::compact] value: BalanceOf, #[pallet::compact] gas_limit: Weight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, code_hash: CodeHash, data: Vec, salt: Vec, @@ -352,8 +383,9 @@ pub mod pallet { let salt_len = salt.len() as u32; let output = Self::internal_instantiate( origin, - endowment, + value, gas_limit, + storage_deposit_limit.map(Into::into), Code::Existing(code_hash), data, salt, @@ -364,6 +396,47 @@ pub mod pallet { T::WeightInfo::instantiate(salt_len / 1024), ) } + + /// Upload new `code` without instantiating a contract from it. + /// + /// If the code does not already exist a deposit is reserved from the caller + /// and unreserved only when [`Self::remove_code`] is called. The size of the reserve + /// depends on the instrumented size of the the supplied `code`. + /// + /// If the code already exists in storage it will still return `Ok` and upgrades + /// the in storage version to the current + /// [`InstructionWeights::version`](InstructionWeights). + /// + /// # Note + /// + /// Anyone can instantiate a contract from any uploaded code and thus prevent its removal. + /// To avoid this situation a constructor could employ access control so that it can + /// only be instantiated by permissioned entities. The same is true when uploading + /// through [`Self::instantiate_with_code`]. + #[pallet::weight(T::WeightInfo::upload_code(code.len() as u32 / 1024))] + pub fn upload_code( + origin: OriginFor, + code: Vec, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::bare_upload_code(origin, code, storage_deposit_limit.map(Into::into)).map(|_| ()) + } + + /// Remove the code stored under `code_hash` and refund the deposit to its owner. + /// + /// A code can only be removed by its original uploader (its owner) and only if it is + /// not used by any contract. + #[pallet::weight(T::WeightInfo::remove_code())] + pub fn remove_code( + origin: OriginFor, + code_hash: CodeHash, + ) -> DispatchResultWithPostInfo { + let origin = ensure_signed(origin)?; + >::remove(&origin, code_hash)?; + // we waive the fee because removing unused code is beneficial + Ok(Pays::No.into()) + } } #[pallet::event] @@ -388,12 +461,6 @@ pub mod pallet { /// Code with the specified hash has been stored. CodeStored { code_hash: T::Hash }, - /// Triggered when the current schedule is updated. - ScheduleUpdated { - /// The version of the newly set schedule. - version: u32, - }, - /// A custom event emitted by the contract. ContractEmitted { /// The contract that emitted the event. @@ -404,8 +471,6 @@ pub mod pallet { }, /// A code with the specified hash was removed. - /// - /// This happens when the last contract that uses this code hash was removed. CodeRemoved { code_hash: T::Hash }, } @@ -417,16 +482,8 @@ pub mod pallet { OutOfGas, /// The output buffer supplied to a contract API call was too small. OutputBufferTooSmall, - /// Performing the requested transfer would have brought the contract below - /// the subsistence threshold. No transfer is allowed to do this. Use `seal_terminate` - /// to recover a deposit. - BelowSubsistenceThreshold, - /// The newly created contract is below the subsistence threshold after executing - /// its contructor. No contracts are allowed to exist below that threshold. - NewContractNotFunded, - /// Performing the requested transfer failed for a reason originating in the - /// chosen currency implementation of the runtime. Most probably the balance is - /// too low or locks are placed on it. + /// Performing the requested transfer failed. Probably because there isn't enough + /// free balance in the sender's account. TransferFailed, /// Performing a call was denied because the calling depth reached the limit /// of what is specified in the schedule. @@ -467,11 +524,6 @@ pub mod pallet { /// The queue is filled by deleting contracts and emptied by a fixed amount each block. /// Trying again during another block is the only way to resolve this issue. DeletionQueueFull, - /// A storage modification exhausted the 32bit type that holds the storage size. - /// - /// This can either happen when the accumulated storage in bytes is too large or - /// when number of storage items is too large. - StorageExhausted, /// A contract with the same AccountId already exists. DuplicateContract, /// A contract self destructed in its constructor. @@ -482,6 +534,12 @@ pub mod pallet { DebugMessageInvalidUTF8, /// A call tried to invoke a contract that is flagged as non-reentrant. ReentranceDenied, + /// Origin doesn't have enough balance to pay the required storage deposits. + StorageDepositNotEnoughFunds, + /// More storage was created than allowed by the storage deposit limit. + StorageDepositLimitExhausted, + /// Code removal was denied because the code is still in use by at least one contract. + CodeInUse, } /// A mapping from an original code hash to the original code, untouched by instrumentation. @@ -493,6 +551,10 @@ pub mod pallet { pub(crate) type CodeStorage = StorageMap<_, Identity, CodeHash, PrefabWasmModule>; + /// A mapping between an original code hash and its owner information. + #[pallet::storage] + pub(crate) type OwnerInfoOf = StorageMap<_, Identity, CodeHash, OwnerInfo>; + /// The subtrie counter. #[pallet::storage] pub(crate) type AccountCounter = StorageValue<_, u64, ValueQuery>; @@ -522,6 +584,8 @@ type InternalInstantiateOutput = InternalOutput, ExecRetur struct InternalOutput { /// The gas meter that was used to execute the call. gas_meter: GasMeter, + /// The storage deposit used by the call. + storage_deposit: StorageDeposit>, /// The result of the call. result: Result, } @@ -547,16 +611,25 @@ where dest: T::AccountId, value: BalanceOf, gas_limit: Weight, + storage_deposit_limit: Option>, data: Vec, debug: bool, - ) -> ContractExecResult { + ) -> ContractExecResult> { let mut debug_message = if debug { Some(Vec::new()) } else { None }; - let output = - Self::internal_call(origin, dest, value, gas_limit, data, debug_message.as_mut()); + let output = Self::internal_call( + origin, + dest, + value, + gas_limit, + storage_deposit_limit, + data, + debug_message.as_mut(), + ); ContractExecResult { result: output.result.map_err(|r| r.error), gas_consumed: output.gas_meter.gas_consumed(), gas_required: output.gas_meter.gas_required(), + storage_deposit: output.storage_deposit, debug_message: debug_message.unwrap_or_default(), } } @@ -568,7 +641,6 @@ where /// /// It returns the execution result, account id and the amount of used weight. /// - /// /// # Note /// /// `debug` should only ever be set to `true` when executing as an RPC because @@ -576,18 +648,20 @@ where /// If set to `true` it returns additional human readable debugging information. pub fn bare_instantiate( origin: T::AccountId, - endowment: BalanceOf, + value: BalanceOf, gas_limit: Weight, + storage_deposit_limit: Option>, code: Code>, data: Vec, salt: Vec, debug: bool, - ) -> ContractInstantiateResult { + ) -> ContractInstantiateResult> { let mut debug_message = if debug { Some(Vec::new()) } else { None }; let output = Self::internal_instantiate( origin, - endowment, + value, gas_limit, + storage_deposit_limit, code, data, salt, @@ -600,10 +674,31 @@ where .map_err(|e| e.error), gas_consumed: output.gas_meter.gas_consumed(), gas_required: output.gas_meter.gas_required(), + storage_deposit: output.storage_deposit, debug_message: debug_message.unwrap_or_default(), } } + /// Upload new code without instantiating a contract from it. + /// + /// This function is similar to [`Self::upload_code`], but doesn't perform any address lookups + /// and better suitable for calling directly from Rust. + pub fn bare_upload_code( + origin: T::AccountId, + code: Vec, + storage_deposit_limit: Option>, + ) -> CodeUploadResult, BalanceOf> { + let schedule = T::Schedule::get(); + let module = PrefabWasmModule::from_code(code, &schedule, origin)?; + let deposit = module.open_deposit(); + if let Some(storage_deposit_limit) = storage_deposit_limit { + ensure!(storage_deposit_limit >= deposit, >::StorageDepositLimitExhausted); + } + let result = CodeUploadReturnValue { code_hash: *module.code_hash(), deposit }; + module.store()?; + Ok(result) + } + /// Query storage of a specified contract under a specified key. pub fn get_storage(address: T::AccountId, key: [u8; 32]) -> GetStorageResult { let contract_info = @@ -636,35 +731,14 @@ where UncheckedFrom::unchecked_from(T::Hashing::hash(&buf)) } - /// Subsistence threshold is the extension of the minimum balance (aka existential deposit) - /// by the contract deposit. It is the minimum balance any contract must hold. - /// - /// Any contract initiated balance transfer mechanism cannot make the balance lower - /// than the subsistence threshold. The only way to recover the balance is to remove - /// contract using `seal_terminate`. - pub fn subsistence_threshold() -> BalanceOf { - T::Currency::minimum_balance().saturating_add(T::ContractDeposit::get()) - } - - /// The in-memory size in bytes of the data structure associated with each contract. - /// - /// The data structure is also put into storage for each contract. The in-storage size - /// is never larger than the in-memory representation and usually smaller due to compact - /// encoding and lack of padding. - /// - /// # Note - /// - /// This returns the in-memory size because the in-storage size (SCALE encoded) cannot - /// be efficiently determined. Treat this as an upper bound of the in-storage size. - pub fn contract_info_size() -> u32 { - sp_std::mem::size_of::>() as u32 - } - /// Store code for benchmarks which does not check nor instrument the code. #[cfg(feature = "runtime-benchmarks")] - fn store_code_raw(code: Vec) -> frame_support::dispatch::DispatchResult { + fn store_code_raw( + code: Vec, + owner: T::AccountId, + ) -> frame_support::dispatch::DispatchResult { let schedule = T::Schedule::get(); - PrefabWasmModule::store_code_unchecked(code, &schedule)?; + PrefabWasmModule::store_code_unchecked(code, &schedule, owner)?; Ok(()) } @@ -685,21 +759,32 @@ where dest: T::AccountId, value: BalanceOf, gas_limit: Weight, + storage_deposit_limit: Option>, data: Vec, debug_message: Option<&mut Vec>, ) -> InternalCallOutput { let mut gas_meter = GasMeter::new(gas_limit); + let mut storage_meter = match StorageMeter::new(&origin, storage_deposit_limit, value) { + Ok(meter) => meter, + Err(err) => + return InternalCallOutput { + result: Err(err.into()), + gas_meter, + storage_deposit: Default::default(), + }, + }; let schedule = T::Schedule::get(); let result = ExecStack::>::run_call( origin, dest, &mut gas_meter, + &mut storage_meter, &schedule, value, data, debug_message, ); - InternalCallOutput { gas_meter, result } + InternalCallOutput { result, gas_meter, storage_deposit: storage_meter.into_deposit() } } /// Internal function that does the actual instantiation. @@ -707,43 +792,62 @@ where /// Called by dispatchables and public functions. fn internal_instantiate( origin: T::AccountId, - endowment: BalanceOf, + value: BalanceOf, gas_limit: Weight, + storage_deposit_limit: Option>, code: Code>, data: Vec, salt: Vec, debug_message: Option<&mut Vec>, ) -> InternalInstantiateOutput { + let mut storage_deposit = Default::default(); let mut gas_meter = GasMeter::new(gas_limit); - let schedule = T::Schedule::get(); let try_exec = || { - let executable = match code { + let schedule = T::Schedule::get(); + let (extra_deposit, executable) = match code { Code::Upload(Bytes(binary)) => { ensure!( binary.len() as u32 <= schedule.limits.code_len, >::CodeTooLarge ); - let executable = PrefabWasmModule::from_code(binary, &schedule)?; + let executable = + PrefabWasmModule::from_code(binary, &schedule, origin.clone())?; ensure!( executable.code_len() <= schedule.limits.code_len, >::CodeTooLarge ); - executable + // The open deposit will be charged during execution when the + // uploaded module does not already exist. This deposit is not part of the + // storage meter because it is not transfered to the contract but + // reserved on the uploading account. + (executable.open_deposit(), executable) }, - Code::Existing(hash) => + Code::Existing(hash) => ( + Default::default(), PrefabWasmModule::from_storage(hash, &schedule, &mut gas_meter)?, + ), }; - ExecStack::>::run_instantiate( + let mut storage_meter = StorageMeter::new( + &origin, + storage_deposit_limit, + value.saturating_add(extra_deposit), + )?; + let result = ExecStack::>::run_instantiate( origin, executable, &mut gas_meter, + &mut storage_meter, &schedule, - endowment, + value, data, &salt, debug_message, - ) + ); + storage_deposit = storage_meter + .into_deposit() + .saturating_add(&StorageDeposit::Charge(extra_deposit)); + result }; - InternalInstantiateOutput { result: try_exec(), gas_meter } + InternalInstantiateOutput { result: try_exec(), gas_meter, storage_deposit } } } diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index b7fa9575e23b5..93eb2e64a1d84 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -15,12 +15,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{Config, Pallet, Weight}; +use crate::{BalanceOf, CodeHash, Config, Pallet, TrieId, Weight}; +use codec::{Decode, Encode}; use frame_support::{ + codec, generate_storage_alias, storage::migration, traits::{Get, PalletInfoAccess}, + Identity, Twox64Concat, }; -use sp_std::prelude::*; +use sp_std::{marker::PhantomData, prelude::*}; pub fn migrate() -> Weight { use frame_support::traits::StorageVersion; @@ -38,6 +41,11 @@ pub fn migrate() -> Weight { StorageVersion::new(5).put::>(); } + if version < 6 { + weight = weight.saturating_add(v6::migrate::()); + StorageVersion::new(6).put::>(); + } + weight } @@ -54,11 +62,6 @@ mod v4 { /// V5: State rent is removed which obsoletes some fields in `ContractInfo`. mod v5 { use super::*; - use crate::{ - BalanceOf, CodeHash, ContractInfo, ContractInfoOf, DeletedContract, DeletionQueue, TrieId, - }; - use codec::Decode; - use sp_std::marker::PhantomData; type AliveContractInfo = RawAliveContractInfo, BalanceOf, ::BlockNumber>; @@ -95,6 +98,30 @@ mod v5 { trie_id: TrieId, } + pub type ContractInfo = RawContractInfo>; + + #[derive(Encode, Decode)] + pub struct RawContractInfo { + pub trie_id: TrieId, + pub code_hash: CodeHash, + pub _reserved: Option<()>, + } + + #[derive(Encode, Decode)] + struct DeletedContract { + trie_id: TrieId, + } + + generate_storage_alias!( + Contracts, + ContractInfoOf => Map<(Twox64Concat, T::AccountId), ContractInfo> + ); + + generate_storage_alias!( + Contracts, + DeletionQueue => Value> + ); + pub fn migrate() -> Weight { let mut weight: Weight = 0; @@ -110,7 +137,7 @@ mod v5 { } }); - >::translate(|old: Option>| { + DeletionQueue::translate(|old: Option>| { weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); old.map(|old| old.into_iter().map(|o| DeletedContract { trie_id: o.trie_id }).collect()) }) @@ -119,3 +146,102 @@ mod v5 { weight } } + +/// V6: Added storage deposits +mod v6 { + use super::*; + + #[derive(Encode, Decode)] + struct OldPrefabWasmModule { + #[codec(compact)] + instruction_weights_version: u32, + #[codec(compact)] + initial: u32, + #[codec(compact)] + maximum: u32, + #[codec(compact)] + refcount: u64, + _reserved: Option<()>, + code: Vec, + original_code_len: u32, + } + + #[derive(Encode, Decode)] + struct PrefabWasmModule { + #[codec(compact)] + instruction_weights_version: u32, + #[codec(compact)] + initial: u32, + #[codec(compact)] + maximum: u32, + code: Vec, + } + + use v5::ContractInfo as OldContractInfo; + + #[derive(Encode, Decode)] + pub struct RawContractInfo { + trie_id: TrieId, + code_hash: CodeHash, + storage_deposit: Balance, + } + + #[derive(Encode, Decode)] + pub struct OwnerInfo { + owner: T::AccountId, + #[codec(compact)] + deposit: BalanceOf, + #[codec(compact)] + refcount: u64, + } + + type ContractInfo = RawContractInfo, BalanceOf>; + + generate_storage_alias!( + Contracts, + ContractInfoOf => Map<(Twox64Concat, T::AccountId), ContractInfo> + ); + + generate_storage_alias!( + Contracts, + CodeStorage => Map<(Identity, CodeHash), PrefabWasmModule> + ); + + generate_storage_alias!( + Contracts, + OwnerInfoOf => Map<(Identity, CodeHash), OwnerInfo> + ); + + pub fn migrate() -> Weight { + let mut weight: Weight = 0; + + >::translate(|_key, old: OldContractInfo| { + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + Some(ContractInfo:: { + trie_id: old.trie_id, + code_hash: old.code_hash, + storage_deposit: Default::default(), + }) + }); + + >::translate(|key, old: OldPrefabWasmModule| { + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)); + >::insert( + key, + OwnerInfo { + refcount: old.refcount, + owner: Default::default(), + deposit: Default::default(), + }, + ); + Some(PrefabWasmModule { + instruction_weights_version: old.instruction_weights_version, + initial: old.initial, + maximum: old.maximum, + code: old.code, + }) + }); + + weight + } +} diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index c14165b4c6aec..b9acc9d49204f 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -271,9 +271,6 @@ pub struct HostFnWeights { /// Weight of calling `seal_minimum_balance`. pub minimum_balance: Weight, - /// Weight of calling `seal_contract_deposit`. - pub contract_deposit: Weight, - /// Weight of calling `seal_block_number`. pub block_number: Weight, @@ -561,7 +558,6 @@ impl Default for HostFnWeights { balance: cost_batched!(seal_balance), value_transferred: cost_batched!(seal_value_transferred), minimum_balance: cost_batched!(seal_minimum_balance), - contract_deposit: cost_batched!(seal_tombstone_deposit), block_number: cost_batched!(seal_block_number), now: cost_batched!(seal_now), weight_to_fee: cost_batched!(seal_weight_to_fee), diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 2b994d66af7e6..6d67729a9a682 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -17,10 +17,12 @@ //! This module contains routines for accessing and altering a contract related state. +pub mod meter; + use crate::{ exec::{AccountIdOf, StorageKey}, weights::WeightInfo, - CodeHash, Config, ContractInfoOf, DeletionQueue, Error, TrieId, + BalanceOf, CodeHash, Config, ContractInfoOf, DeletionQueue, Error, TrieId, }; use codec::{Decode, Encode}; use frame_support::{ @@ -32,24 +34,27 @@ use frame_support::{ use scale_info::TypeInfo; use sp_core::crypto::UncheckedFrom; use sp_io::hashing::blake2_256; -use sp_runtime::{traits::Hash, RuntimeDebug}; +use sp_runtime::{ + traits::{Hash, Zero}, + RuntimeDebug, +}; use sp_std::{marker::PhantomData, prelude::*}; -pub type ContractInfo = RawContractInfo>; +pub type ContractInfo = RawContractInfo, BalanceOf>; /// Information for managing an account and its sub trie abstraction. /// This is the required info to cache for an account. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub struct RawContractInfo { +pub struct RawContractInfo { /// Unique ID for the subtree encoded as a bytes vector. pub trie_id: TrieId, /// The code associated with a given account. pub code_hash: CodeHash, - /// This field is reserved for future evolution of format. - pub _reserved: Option<()>, + /// The amount of balance that is currently deposited to pay for consumed storage. + pub storage_deposit: Balance, } -impl RawContractInfo { +impl RawContractInfo { /// Associated child trie unique id is built from the hash part of the trie id. #[cfg(test)] pub fn child_trie_info(&self) -> ChildInfo { @@ -79,26 +84,49 @@ where /// The read is performed from the `trie_id` only. The `address` is not necessary. If the /// contract doesn't store under the given `key` `None` is returned. pub fn read(trie_id: &TrieId, key: &StorageKey) -> Option> { - child::get_raw(&child_trie_info(&trie_id), &blake2_256(key)) + child::get_raw(&child_trie_info(trie_id), &blake2_256(key)) } /// Update a storage entry into a contract's kv storage. /// - /// If the `opt_new_value` is `None` then the kv pair is removed. + /// If the `new_value` is `None` then the kv pair is removed. /// - /// This function also updates the bookkeeping info such as: number of total non-empty pairs a - /// contract owns, the last block the storage was written to, etc. That's why, in contrast to - /// `read`, this function also requires the `account` ID. + /// This function also records how much storage was created or removed if a `storage_meter` + /// is supplied. It should only be absent for testing or benchmarking code. pub fn write( - new_info: &mut ContractInfo, + trie_id: &TrieId, key: &StorageKey, - opt_new_value: Option>, + new_value: Option>, + storage_meter: Option<&mut meter::NestedMeter>, ) -> DispatchResult { let hashed_key = blake2_256(key); - let child_trie_info = &child_trie_info(&new_info.trie_id); + let child_trie_info = &child_trie_info(trie_id); + + if let Some(storage_meter) = storage_meter { + let mut diff = meter::Diff::default(); + let old_len = child::len(&child_trie_info, &hashed_key); + match (old_len, new_value.as_ref().map(|v| v.len() as u32)) { + (Some(old_len), Some(new_len)) => + if new_len > old_len { + diff.bytes_added = new_len - old_len; + } else { + diff.bytes_removed = old_len - new_len; + }, + (None, Some(new_len)) => { + diff.bytes_added = new_len; + diff.items_added = 1; + }, + (Some(old_len), None) => { + diff.bytes_removed = old_len; + diff.items_removed = 1; + }, + (None, None) => (), + } + storage_meter.charge(&diff)?; + } - match opt_new_value { - Some(new_value) => child::put_raw(&child_trie_info, &hashed_key, &new_value[..]), + match &new_value { + Some(new_value) => child::put_raw(&child_trie_info, &hashed_key, new_value), None => child::kill(&child_trie_info, &hashed_key), } @@ -118,7 +146,8 @@ where return Err(Error::::DuplicateContract.into()) } - let contract = ContractInfo:: { code_hash: ch, trie_id, _reserved: None }; + let contract = + ContractInfo:: { code_hash: ch, trie_id, storage_deposit: >::zero() }; Ok(contract) } diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs new file mode 100644 index 0000000000000..96ce02fd83ae7 --- /dev/null +++ b/frame/contracts/src/storage/meter.rs @@ -0,0 +1,726 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This module contains functions to meter the storage deposit. + +use crate::{storage::ContractInfo, BalanceOf, Config, Error}; +use codec::Encode; +use frame_support::{ + dispatch::DispatchError, + traits::{tokens::BalanceStatus, Currency, ExistenceRequirement, Get, ReservableCurrency}, + DefaultNoBound, +}; +use pallet_contracts_primitives::StorageDeposit as Deposit; +use sp_core::crypto::UncheckedFrom; +use sp_runtime::traits::{Saturating, Zero}; +use sp_std::marker::PhantomData; + +/// Deposit that uses the native currency's balance type. +pub type DepositOf = Deposit>; + +/// A production root storage meter that actually charges from its origin. +pub type Meter = RawMeter; + +/// A poduction nested storage meter that actually charges from its origin. +pub type NestedMeter = RawMeter; + +/// A poduction storage meter that actually charges from its origin. +/// +/// This can be used where we want to be generic over the state (Root vs. Nested). +pub type GenericMeter = RawMeter; + +/// A trait that allows to decouple the metering from the charging of balance. +/// +/// This mostly exists for testing so that the charging can be mocked. +pub trait Ext { + /// This checks whether `origin` is able to afford the storage deposit limit. + /// + /// It is necessary to do this check beforehand so that the charge won't fail later on. + /// + /// `origin`: The origin of the call stack from which is responsible for putting down a deposit. + /// `limit`: The limit with which the meter was constructed. + /// `min_leftover`: How much `free_balance` in addition to the ed should be left inside the + /// `origin` account. + /// + /// Returns the limit that should be used by the meter. If origin can't afford the `limit` + /// it returns `Err`. + fn check_limit( + origin: &T::AccountId, + limit: Option>, + min_leftover: BalanceOf, + ) -> Result, DispatchError>; + /// This is called to inform the implementer that some balance should be charged due to + /// some interaction of the `origin` with a `contract`. + /// + /// The balance transfer can either flow from `origin` to `contract` or the other way + /// around depending on whether `amount` constitutes a `Charge` or a `Refund`. + /// It is guaranteed that that this succeeds because no more balance than returned by + /// `check_limit` is ever charged. This is why this function is infallible. + /// `terminated` designates whether the `contract` was terminated. + fn charge( + origin: &T::AccountId, + contract: &T::AccountId, + amount: &DepositOf, + terminated: bool, + ); +} + +/// This [`Ext`] is used for actual on-chain execution when balance needs to be charged. +/// +/// It uses [`ReservableCurrency`] in order to do accomplish the reserves. +pub enum ReservingExt {} + +/// Used to implement a type state pattern for the meter. +/// +/// It is sealed and cannot be implemented outside of this module. +pub trait State: private::Sealed {} + +/// State parameter that constitutes a meter that is in its root state. +pub enum Root {} + +/// State parameter that constitutes a meter that is in its nested state. +pub enum Nested {} + +impl State for Root {} +impl State for Nested {} + +/// A type that allows the metering of consumed or freed storage of a single contract call stack. +#[derive(DefaultNoBound)] +pub struct RawMeter, S: State> { + /// The limit of how much balance this meter is allowed to consume. + limit: BalanceOf, + /// The amount of balance that was used in this meter and all of its already absorbed children. + total_deposit: DepositOf, + /// The amount of balance that was used in this meter alone. + own_deposit: DepositOf, + /// Only when a contract was terminated we allow it to drop below the minimum balance. + terminated: bool, + /// Type parameters are only used in impls. + _phantom: PhantomData<(E, S)>, +} + +/// This type is used to describe a storage change when charging from the meter. +#[derive(Default)] +pub struct Diff { + /// How many bytes were added to storage. + pub bytes_added: u32, + /// How many bytes were removed from storage. + pub bytes_removed: u32, + /// How many storage items were added to storage. + pub items_added: u32, + /// How many storage items were removed from storage. + pub items_removed: u32, + /// If set to true the derived deposit will always a `Charge` larger than the + /// the existential deposit. + pub require_ed: bool, +} + +impl Diff { + /// Calculate how much of a charge or refund results from applying the diff. + pub fn to_deposit(&self) -> DepositOf { + let mut deposit = Deposit::default(); + let per_byte = T::DepositPerByte::get(); + let per_item = T::DepositPerItem::get(); + + if self.bytes_added > self.bytes_removed { + deposit = deposit.saturating_add(&Deposit::Charge( + per_byte.saturating_mul((self.bytes_added - self.bytes_removed).into()), + )); + } else if self.bytes_removed > self.bytes_added { + deposit = deposit.saturating_add(&Deposit::Refund( + per_byte.saturating_mul((self.bytes_removed - self.bytes_added).into()), + )); + } + + if self.items_added > self.items_removed { + deposit = deposit.saturating_add(&Deposit::Charge( + per_item.saturating_mul((self.items_added - self.items_removed).into()), + )); + } else if self.items_removed > self.items_added { + deposit = deposit.saturating_add(&Deposit::Refund( + per_item.saturating_mul((self.items_removed - self.items_added).into()), + )); + } + + if self.require_ed { + deposit = deposit.max(Deposit::Charge(T::Currency::minimum_balance())) + } + + deposit + } +} + +/// Functions that apply to all states. +impl RawMeter +where + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]>, + E: Ext, + S: State, +{ + /// Create a new child that has its `limit` set to whatever is remaining of it. + /// + /// This is called whenever a new subcall is initiated in order to track the storage + /// usage for this sub call separately. This is necessary because we want to exchange balance + /// with the current contract we are interacting with. + pub fn nested(&self) -> RawMeter { + RawMeter { limit: self.available(), ..Default::default() } + } + + /// Absorb a child that was spawned to handle a sub call. + /// + /// This should be called whenever a sub call comes to its end and it is **not** reverted. + /// This does the actual balance transfer from/to `origin` and `contract` based on the overall + /// storage consumption of the call. It also updates the supplied contract info. + /// + /// In case a contract reverted the child meter should just be dropped in order to revert + /// any changes it recorded. + /// + /// # Parameters + /// + /// `absorbed`: The child storage meter that should be absorbed. + /// `origin`: The origin that spawned the original root meter. + /// `contract`: The contract that this sub call belongs to. + /// `info`: The info of the contract in question. `None` if the contract was terminated. + pub fn absorb( + &mut self, + mut absorbed: RawMeter, + origin: &T::AccountId, + contract: &T::AccountId, + info: Option<&mut ContractInfo>, + ) { + // Absorbing from an existing (non terminated) contract. + if let Some(info) = info { + match &mut absorbed.own_deposit { + Deposit::Charge(amount) => + info.storage_deposit = info.storage_deposit.saturating_add(*amount), + Deposit::Refund(amount) => { + // We need to make sure to never refund more than what was deposited and + // still leave the existential deposit inside the contract's account. + // This case can happen when costs change due to a runtime upgrade where + // increased costs could remove an account due to refunds. + let amount = { + let corrected_amount = (*amount).min( + info.storage_deposit.saturating_sub(T::Currency::minimum_balance()), + ); + let correction = (*amount).saturating_sub(corrected_amount); + absorbed.total_deposit = + absorbed.total_deposit.saturating_sub(&Deposit::Refund(correction)); + *amount = corrected_amount; + corrected_amount + }; + info.storage_deposit = info.storage_deposit.saturating_sub(amount); + }, + } + } + + self.total_deposit = self.total_deposit.saturating_add(&absorbed.total_deposit); + if !absorbed.own_deposit.is_zero() { + E::charge(origin, &contract, &absorbed.own_deposit, absorbed.terminated); + } + } + + /// The amount of balance that is still available from the original `limit`. + fn available(&self) -> BalanceOf { + self.total_deposit.available(&self.limit) + } +} + +/// Functions that only apply to the root state. +impl RawMeter +where + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]>, + E: Ext, +{ + /// Create new storage meter for the specified `origin` and `limit`. + /// + /// This tries to [`Ext::check_limit`] on `origin` and fails if this is not possible. + pub fn new( + origin: &T::AccountId, + limit: Option>, + min_leftover: BalanceOf, + ) -> Result { + let limit = E::check_limit(&origin, limit, min_leftover)?; + Ok(Self { limit, ..Default::default() }) + } + + /// The total amount of deposit that should change hands as result of the execution + /// that this meter was passed into. + /// + /// This drops the root meter in order to make sure it is only called when the whole + /// execution did finish. + pub fn into_deposit(self) -> DepositOf { + self.total_deposit + } +} + +/// Functions that only apply to the nested state. +impl RawMeter +where + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]>, + E: Ext, +{ + /// Try to charge the `diff` from the meter. Fails if this would exceed the original limit. + pub fn charge(&mut self, diff: &Diff) -> Result, DispatchError> { + debug_assert!(!self.terminated); + let deposit = diff.to_deposit::(); + let total_deposit = self.total_deposit.saturating_add(&deposit); + if let Deposit::Charge(amount) = total_deposit { + if amount > self.limit { + return Err(>::StorageDepositLimitExhausted.into()) + } + } + self.total_deposit = total_deposit; + self.own_deposit = self.own_deposit.saturating_add(&deposit); + Ok(deposit) + } + + /// Charge from `origin` a storage deposit for contract instantiation. + /// + /// This immediately transfers the balance in order to create the account. + pub fn charge_instantiate( + &mut self, + origin: &T::AccountId, + contract: &T::AccountId, + info: &mut ContractInfo, + ) -> Result, DispatchError> { + debug_assert!(!self.terminated); + let deposit = Diff { + bytes_added: info.encoded_size() as u32, + items_added: 1, + require_ed: true, + ..Default::default() + } + .to_deposit::(); + debug_assert!(matches!(deposit, Deposit::Charge(_))); + // We do not increase `own_deposit` because this will be charged later when the contract + // execution does conclude. + let total_deposit = self.total_deposit.saturating_add(&deposit); + if let Deposit::Charge(amount) = &total_deposit { + if amount > &self.limit { + return Err(>::StorageDepositLimitExhausted.into()) + } + } + info.storage_deposit = info.storage_deposit.saturating_add(deposit.charge_or_zero()); + self.total_deposit = total_deposit; + if !deposit.is_zero() { + // We need to charge immediately so that the account is created before the `value` + // is transferred from the caller to the contract. + E::charge(origin, contract, &deposit, false); + } + Ok(deposit) + } + + /// Call to tell the meter that the currently executing contract was executed. + /// + /// This will manipulate the meter so that all storage deposit accumulated in + /// `contract_info` will be refunded to the `origin` of the meter. + pub fn terminate(&mut self, contract_info: &ContractInfo) { + debug_assert!(!self.terminated); + let refund = Deposit::Refund(contract_info.storage_deposit); + + // The deposit for `own_deposit` isn't persisted into the contract info until the current + // frame is dropped. This means that whatever changes were introduced during the + // current frame are dicarded when terminating. + self.total_deposit = + self.total_deposit.saturating_add(&refund).saturating_sub(&self.own_deposit); + self.own_deposit = refund; + self.terminated = true; + } +} + +impl Ext for ReservingExt { + fn check_limit( + origin: &T::AccountId, + limit: Option>, + min_leftover: BalanceOf, + ) -> Result, DispatchError> { + let max = T::Currency::free_balance(origin) + .saturating_sub(T::Currency::minimum_balance()) + .saturating_sub(min_leftover); + match limit { + Some(limit) if limit <= max => Ok(limit), + None => Ok(max), + _ => Err(>::StorageDepositNotEnoughFunds.into()), + } + } + + fn charge( + origin: &T::AccountId, + contract: &T::AccountId, + amount: &DepositOf, + terminated: bool, + ) { + // There is nothing we can do when this fails as this constitutes a bug in the runtime: + // Either the runtime does not hold up the invariant of never deleting a contract's account + // or it does not honor reserved balances. We need to settle for emitting an error log + // in this case. + match amount { + Deposit::Charge(amount) => { + // This will never fail because a contract's account is required to exist + // at all times. The pallet enforces this invariant by depositing at least the + // existential deposit when instantiating and never refunds it unless the contract + // is removed. This means the receiver always exists except when instantiating a + // contract. In this case we made sure that at least the existential deposit is + // sent. The sender always has enough balance because we checked that it had enough + // balance when instantiating the storage meter. + let result = T::Currency::transfer( + origin, + contract, + *amount, + ExistenceRequirement::KeepAlive, + ) + .and_then(|_| T::Currency::reserve(contract, *amount)); + if let Err(err) = result { + log::error!( + target: "runtime::contracts", + "Failed to transfer storage deposit {:?} from origin {:?} to contract {:?}: {:?}", + amount, origin, contract, err, + ); + } + }, + // For `Refund(_)` no error happen because the initial value transfer from the + // origin to the contract has a keep alive existence requirement and when reserving we + // make sure to leave at least the ed in the free balance. Therefore the receiver always + // exists because there is no way for it to be removed in between. The sender always has + // enough reserved balance because we track it in the `ContractInfo` and never send more + // back than we have. + Deposit::Refund(amount) => { + let amount = if terminated { + *amount + } else { + // This is necessary when the `storage_deposit` tracked inside the account + // info is out of sync with the actual balance. That can only happen due to + // slashing. We make sure to never dust the contract's account through a + // refund because we consider this unexpected behaviour. + *amount.min( + &T::Currency::reserved_balance(contract) + .saturating_sub(T::Currency::minimum_balance()), + ) + }; + let result = + T::Currency::repatriate_reserved(contract, origin, amount, BalanceStatus::Free); + if matches!(result, Ok(val) if !val.is_zero()) || matches!(result, Err(_)) { + log::error!( + target: "runtime::contracts", + "Failed to repatriate storage deposit {:?} from contract {:?} to origin {:?}: {:?}", + amount, contract, origin, result, + ); + } + }, + }; + } +} + +mod private { + pub trait Sealed {} + impl Sealed for super::Root {} + impl Sealed for super::Nested {} +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + exec::AccountIdOf, + tests::{Test, ALICE, BOB, CHARLIE}, + }; + use pretty_assertions::assert_eq; + use std::cell::RefCell; + + type TestMeter = RawMeter; + + thread_local! { + static TEST_EXT: RefCell = RefCell::new(Default::default()); + } + + #[derive(Debug, PartialEq, Eq)] + struct LimitCheck { + origin: AccountIdOf, + limit: BalanceOf, + min_leftover: BalanceOf, + } + + #[derive(Debug, PartialEq, Eq)] + struct Charge { + origin: AccountIdOf, + contract: AccountIdOf, + amount: DepositOf, + terminated: bool, + } + + #[derive(Default, Debug, PartialEq, Eq)] + struct TestExt { + limit_checks: Vec, + charges: Vec, + } + + impl TestExt { + fn clear(&mut self) { + self.limit_checks.clear(); + self.charges.clear(); + } + } + + impl Ext for TestExt { + fn check_limit( + origin: &AccountIdOf, + limit: Option>, + min_leftover: BalanceOf, + ) -> Result, DispatchError> { + let limit = limit.unwrap_or(42); + TEST_EXT.with(|ext| { + ext.borrow_mut().limit_checks.push(LimitCheck { + origin: origin.clone(), + limit, + min_leftover, + }) + }); + Ok(limit) + } + + fn charge( + origin: &AccountIdOf, + contract: &AccountIdOf, + amount: &DepositOf, + terminated: bool, + ) { + TEST_EXT.with(|ext| { + ext.borrow_mut().charges.push(Charge { + origin: origin.clone(), + contract: contract.clone(), + amount: amount.clone(), + terminated, + }) + }); + } + } + + fn clear_ext() { + TEST_EXT.with(|ext| ext.borrow_mut().clear()) + } + + fn new_info(deposit: BalanceOf) -> ContractInfo { + use crate::storage::Storage; + use sp_runtime::traits::Hash; + + ContractInfo:: { + trie_id: >::generate_trie_id(&ALICE, 42), + code_hash: ::Hashing::hash(b"42"), + storage_deposit: deposit, + } + } + + #[test] + fn new_reserves_balance_works() { + clear_ext(); + + TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); + + TEST_EXT.with(|ext| { + assert_eq!( + *ext.borrow(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + ..Default::default() + } + ) + }); + } + + #[test] + fn empty_charge_works() { + clear_ext(); + + let mut meter = TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); + assert_eq!(meter.available(), 1_000); + + // an empty charge foes not create a `Charge` entry + let mut nested0 = meter.nested(); + nested0.charge(&Default::default()).unwrap(); + meter.absorb(nested0, &ALICE, &BOB, None); + + TEST_EXT.with(|ext| { + assert_eq!( + *ext.borrow(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + ..Default::default() + } + ) + }); + } + + #[test] + fn existential_deposit_works() { + clear_ext(); + + let mut meter = TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); + assert_eq!(meter.available(), 1_000); + + // a `Refund` will be turned into a `Charge(ed)` which is intended behaviour + let mut nested0 = meter.nested(); + nested0.charge(&Diff { require_ed: true, ..Default::default() }).unwrap(); + nested0 + .charge(&Diff { bytes_removed: 1, require_ed: true, ..Default::default() }) + .unwrap(); + meter.absorb(nested0, &ALICE, &BOB, None); + + TEST_EXT.with(|ext| { + assert_eq!( + *ext.borrow(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + charges: vec![Charge { + origin: ALICE, + contract: BOB, + amount: Deposit::Charge(::Currency::minimum_balance() * 2), + terminated: false, + }], + ..Default::default() + } + ) + }); + } + + #[test] + fn charging_works() { + clear_ext(); + + let min_balance = ::Currency::minimum_balance(); + + let mut meter = TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); + assert_eq!(meter.available(), 1_000); + + let mut nested0_info = new_info(100); + let mut nested0 = meter.nested(); + nested0 + .charge(&Diff { + bytes_added: 10, + bytes_removed: 5, + items_added: 1, + items_removed: 2, + ..Default::default() + }) + .unwrap(); + nested0.charge(&Diff { bytes_removed: 1, ..Default::default() }).unwrap(); + + let mut nested1_info = new_info(50); + let mut nested1 = nested0.nested(); + nested1.charge(&Diff { items_removed: 5, ..Default::default() }).unwrap(); + nested0.absorb(nested1, &ALICE, &CHARLIE, Some(&mut nested1_info)); + + // Trying to refund more than is available in the contract will cap the charge + // to (deposit_in_contract - ed). + let mut nested2_info = new_info(5); + let mut nested2 = nested0.nested(); + nested2.charge(&Diff { bytes_removed: 7, ..Default::default() }).unwrap(); + nested0.absorb(nested2, &ALICE, &CHARLIE, Some(&mut nested2_info)); + + meter.absorb(nested0, &ALICE, &BOB, Some(&mut nested0_info)); + + assert_eq!(nested0_info.storage_deposit, 102); + assert_eq!(nested1_info.storage_deposit, 40); + assert_eq!(nested2_info.storage_deposit, min_balance); + + TEST_EXT.with(|ext| { + assert_eq!( + *ext.borrow(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + charges: vec![ + Charge { + origin: ALICE, + contract: CHARLIE, + amount: Deposit::Refund(10), + terminated: false + }, + Charge { + origin: ALICE, + contract: CHARLIE, + amount: Deposit::Refund(4), + terminated: false + }, + Charge { + origin: ALICE, + contract: BOB, + amount: Deposit::Charge(2), + terminated: false + } + ], + ..Default::default() + } + ) + }); + } + + #[test] + fn termination_works() { + clear_ext(); + + let mut meter = TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); + assert_eq!(meter.available(), 1_000); + + let mut nested0 = meter.nested(); + nested0 + .charge(&Diff { + bytes_added: 5, + bytes_removed: 1, + items_added: 3, + items_removed: 1, + ..Default::default() + }) + .unwrap(); + nested0.charge(&Diff { items_added: 2, ..Default::default() }).unwrap(); + + let nested1_info = new_info(400); + let mut nested1 = nested0.nested(); + nested1.charge(&Diff { items_removed: 5, ..Default::default() }).unwrap(); + nested1.charge(&Diff { bytes_added: 20, ..Default::default() }).unwrap(); + nested1.terminate(&nested1_info); + nested0.absorb(nested1, &ALICE, &CHARLIE, None); + + meter.absorb(nested0, &ALICE, &BOB, None); + drop(meter); + + TEST_EXT.with(|ext| { + assert_eq!( + *ext.borrow(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + charges: vec![ + Charge { + origin: ALICE, + contract: CHARLIE, + amount: Deposit::Refund(400), + terminated: true + }, + Charge { + origin: ALICE, + contract: BOB, + amount: Deposit::Charge(12), + terminated: false + } + ], + ..Default::default() + } + ) + }); + } +} diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 6a252527d1eac..f19f5a3159557 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -21,19 +21,19 @@ use crate::{ ReturnFlags, SysConfig, UncheckedFrom, }, exec::Frame, - storage::{RawContractInfo, Storage}, + storage::Storage, wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, - BalanceOf, Config, ContractInfoOf, Error, Pallet, Schedule, + BalanceOf, CodeStorage, Config, ContractInfoOf, Error, Pallet, Schedule, }; use assert_matches::assert_matches; use codec::Encode; use frame_support::{ - assert_err, assert_err_ignore_postinfo, assert_ok, + assert_err, assert_err_ignore_postinfo, assert_noop, assert_ok, dispatch::DispatchErrorWithPostInfo, parameter_types, storage::child, - traits::{Contains, Currency, OnInitialize, ReservableCurrency}, + traits::{BalanceStatus, Contains, Currency, OnInitialize, ReservableCurrency}, weights::{constants::WEIGHT_PER_SECOND, DispatchClass, PostDispatchInfo, Weight}, }; use frame_system::{self as system, EventRecord, Phase}; @@ -71,30 +71,17 @@ frame_support::construct_runtime!( pub mod test_utils { use super::{Balances, Test}; use crate::{ - exec::{AccountIdOf, StorageKey}, - storage::Storage, - AccountCounter, CodeHash, ContractInfoOf, Pallet as Contracts, TrieId, + exec::AccountIdOf, storage::Storage, AccountCounter, CodeHash, Config, ContractInfoOf, }; use frame_support::traits::Currency; - pub fn set_storage(addr: &AccountIdOf, key: &StorageKey, value: Option>) { - let mut contract_info = >::get(&addr).unwrap(); - Storage::::write(&mut contract_info, key, value).unwrap(); - } - pub fn get_storage(addr: &AccountIdOf, key: &StorageKey) -> Option> { - let contract_info = >::get(&addr).unwrap(); - Storage::::read(&contract_info.trie_id, key) - } - pub fn generate_trie_id(address: &AccountIdOf) -> TrieId { + pub fn place_contract(address: &AccountIdOf, code_hash: CodeHash) { let seed = >::mutate(|counter| { *counter += 1; *counter }); - Storage::::generate_trie_id(address, seed) - } - pub fn place_contract(address: &AccountIdOf, code_hash: CodeHash) { - let trie_id = generate_trie_id(address); - set_balance(address, Contracts::::subsistence_threshold() * 10); + let trie_id = Storage::::generate_trie_id(address, seed); + set_balance(address, ::Currency::minimum_balance() * 10); let contract = Storage::::new_contract(&address, trie_id, code_hash).unwrap(); >::insert(address, contract); } @@ -113,7 +100,7 @@ pub mod test_utils { } macro_rules! assert_refcount { ( $code_hash:expr , $should:expr $(,)? ) => {{ - let is = crate::CodeStorage::::get($code_hash).map(|m| m.refcount()).unwrap_or(0); + let is = crate::OwnerInfoOf::::get($code_hash).map(|m| m.refcount()).unwrap(); assert_eq!(is, $should); }}; } @@ -193,7 +180,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND); - pub static ExistentialDeposit: u64 = 0; + pub static ExistentialDeposit: u64 = 1; } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; @@ -248,13 +235,14 @@ impl pallet_utility::Config for Test { type WeightInfo = (); } parameter_types! { - pub const ContractDeposit: u64 = 16; pub const MaxValueSize: u32 = 16_384; pub const DeletionQueueDepth: u32 = 1024; pub const DeletionWeightLimit: Weight = 500_000_000_000; pub const MaxCodeSize: u32 = 2 * 1024; pub MySchedule: Schedule = >::default(); pub const TransactionByteFee: u64 = 0; + pub static DepositPerByte: BalanceOf = 1; + pub const DepositPerItem: BalanceOf = 2; } impl Convert> for Test { @@ -289,7 +277,6 @@ impl Config for Test { type Event = Event; type Call = Call; type CallFilter = TestFilter; - type ContractDeposit = ContractDeposit; type CallStack = [Frame; 31]; type WeightPrice = Self; type WeightInfo = (); @@ -297,6 +284,8 @@ impl Config for Test { type DeletionQueueDepth = DeletionQueueDepth; type DeletionWeightLimit = DeletionWeightLimit; type Schedule = MySchedule; + type DepositPerByte = DepositPerByte; + type DepositPerItem = DepositPerItem; } pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); @@ -304,14 +293,14 @@ pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]); pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]); -const GAS_LIMIT: Weight = 10_000_000_000; +pub const GAS_LIMIT: Weight = 10_000_000_000; pub struct ExtBuilder { existential_deposit: u64, } impl Default for ExtBuilder { fn default() -> Self { - Self { existential_deposit: 1 } + Self { existential_deposit: ExistentialDeposit::get() } } } impl ExtBuilder { @@ -323,6 +312,9 @@ impl ExtBuilder { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); } pub fn build(self) -> sp_io::TestExternalities { + use env_logger::{Builder, Env}; + let env = Env::new().default_filter_or("runtime=debug"); + let _ = Builder::from_env(env).is_test(true).try_init(); self.set_associated_consts(); let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![] } @@ -358,7 +350,7 @@ fn calling_plain_account_fails() { let base_cost = <::WeightInfo as WeightInfo>::call(); assert_eq!( - Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, Vec::new()), + Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, None, Vec::new()), Err(DispatchErrorWithPostInfo { error: Error::::ContractNotFound.into(), post_info: PostDispatchInfo { @@ -370,114 +362,65 @@ fn calling_plain_account_fails() { }); } -#[test] -fn account_removal_does_not_remove_storage() { - use self::test_utils::{get_storage, set_storage}; - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let trie_id1 = test_utils::generate_trie_id(&ALICE); - let trie_id2 = test_utils::generate_trie_id(&BOB); - let key1 = &[1; 32]; - let key2 = &[2; 32]; - - // Set up two accounts with free balance above the existential threshold. - { - let alice_contract_info = RawContractInfo { - trie_id: trie_id1.clone(), - code_hash: H256::repeat_byte(1), - _reserved: None, - }; - let _ = Balances::deposit_creating(&ALICE, 110); - ContractInfoOf::::insert(ALICE, &alice_contract_info); - set_storage(&ALICE, &key1, Some(b"1".to_vec())); - set_storage(&ALICE, &key2, Some(b"2".to_vec())); - - let bob_contract_info = RawContractInfo { - trie_id: trie_id2.clone(), - code_hash: H256::repeat_byte(2), - _reserved: None, - }; - let _ = Balances::deposit_creating(&BOB, 110); - ContractInfoOf::::insert(BOB, &bob_contract_info); - set_storage(&BOB, &key1, Some(b"3".to_vec())); - set_storage(&BOB, &key2, Some(b"4".to_vec())); - } - - // Transfer funds from ALICE account of such amount that after this transfer - // the balance of the ALICE account will be below the existential threshold. - // - // This does not remove the contract storage as we are not notified about a - // account removal. This cannot happen in reality because a contract can only - // remove itself by `seal_terminate`. There is no external event that can remove - // the account appart from that. - assert_ok!(Balances::transfer(Origin::signed(ALICE), BOB, 20)); - - // Verify that no entries are removed. - { - assert_eq!(get_storage(&ALICE, key1), Some(b"1".to_vec())); - assert_eq!(get_storage(&ALICE, key2), Some(b"2".to_vec())); - - assert_eq!(get_storage(&BOB, key1), Some(b"3".to_vec())); - assert_eq!(get_storage(&BOB, key2), Some(b"4".to_vec())); - } - }); -} - #[test] fn instantiate_and_call_and_deposit_event() { let (wasm, code_hash) = compile_module::("return_from_start_fn").unwrap(); - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); - let subsistence = Pallet::::subsistence_threshold(); + let min_balance = ::Currency::minimum_balance(); + let value = 100; + + // We determine the storage deposit limit after uploading because it depends on ALICEs free + // balance which is changed by uploading a module. + assert_ok!(Contracts::upload_code(Origin::signed(ALICE), wasm, None)); + + // Drop previous events + initialize_block(2); // Check at the end to get hash on error easily - let creation = Contracts::instantiate_with_code( + assert_ok!(Contracts::instantiate( Origin::signed(ALICE), - subsistence * 100, + value, GAS_LIMIT, - wasm, + None, + code_hash, vec![], vec![], - ); + )); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + assert!(ContractInfoOf::::contains_key(&addr)); assert_eq!( System::events(), vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Deposit { - who: ALICE, - amount: 1_000_000 - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { - account: ALICE.clone() - }), + event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), topics: vec![], }, EventRecord { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::Endowed { - account: ALICE, - free_balance: 1_000_000 + account: addr.clone(), + free_balance: min_balance, }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + event: Event::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), + amount: min_balance, + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { - account: addr.clone(), - free_balance: subsistence * 100 + event: Event::Balances(pallet_balances::Event::Reserved { + who: addr.clone(), + amount: min_balance, }), topics: vec![], }, @@ -486,14 +429,7 @@ fn instantiate_and_call_and_deposit_event() { event: Event::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), - amount: subsistence * 100 - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { - code_hash: code_hash.into() + amount: value, }), topics: vec![], }, @@ -515,9 +451,6 @@ fn instantiate_and_call_and_deposit_event() { }, ] ); - - assert_ok!(creation); - assert!(ContractInfoOf::::contains_key(&addr)); }); } @@ -532,6 +465,7 @@ fn deposit_event_max_value_limit() { Origin::signed(ALICE), 30_000, GAS_LIMIT, + None, wasm, vec![], vec![], @@ -544,6 +478,7 @@ fn deposit_event_max_value_limit() { addr.clone(), 0, GAS_LIMIT * 2, // we are copying a huge buffer, + None, ::Schedule::get().limits.payload_len.encode(), )); @@ -554,6 +489,7 @@ fn deposit_event_max_value_limit() { addr, 0, GAS_LIMIT, + None, (::Schedule::get().limits.payload_len + 1).encode(), ), Error::::ValueTooLarge, @@ -564,15 +500,15 @@ fn deposit_event_max_value_limit() { #[test] fn run_out_of_gas() { let (wasm, code_hash) = compile_module::("run_out_of_gas").unwrap(); - let subsistence = Pallet::::subsistence_threshold(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - 100 * subsistence, + 100 * min_balance, GAS_LIMIT, + None, wasm, vec![], vec![], @@ -587,6 +523,7 @@ fn run_out_of_gas() { addr, // newly created account 0, 1_000_000_000_000, + None, vec![], ), Error::::OutOfGas, @@ -609,6 +546,7 @@ fn storage_max_value_limit() { Origin::signed(ALICE), 30_000, GAS_LIMIT, + None, wasm, vec![], vec![], @@ -622,6 +560,7 @@ fn storage_max_value_limit() { addr.clone(), 0, GAS_LIMIT * 2, // we are copying a huge buffer + None, ::Schedule::get().limits.payload_len.encode(), )); @@ -632,6 +571,7 @@ fn storage_max_value_limit() { addr, 0, GAS_LIMIT, + None, (::Schedule::get().limits.payload_len + 1).encode(), ), Error::::ValueTooLarge, @@ -641,16 +581,21 @@ fn storage_max_value_limit() { #[test] fn deploy_and_call_other_contract() { - let (callee_wasm, callee_code_hash) = compile_module::("return_with_data").unwrap(); let (caller_wasm, caller_code_hash) = compile_module::("caller_contract").unwrap(); + let (callee_wasm, callee_code_hash) = compile_module::("return_with_data").unwrap(); + let caller_addr = Contracts::contract_address(&ALICE, &caller_code_hash, &[]); + let callee_addr = Contracts::contract_address(&caller_addr, &callee_code_hash, &[]); + + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), 100_000, GAS_LIMIT, + None, caller_wasm, vec![], vec![], @@ -659,34 +604,104 @@ fn deploy_and_call_other_contract() { Origin::signed(ALICE), 100_000, GAS_LIMIT, + None, callee_wasm, 0u32.to_le_bytes().encode(), vec![42], )); + // Drop previous events + initialize_block(2); + // Call BOB contract, which attempts to instantiate and call the callee contract and // makes various assertions on the results from those calls. assert_ok!(Contracts::call( Origin::signed(ALICE), - Contracts::contract_address(&ALICE, &caller_code_hash, &[]), + caller_addr.clone(), 0, GAS_LIMIT, + None, callee_code_hash.as_ref().to_vec(), )); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: Event::System(frame_system::Event::NewAccount { + account: callee_addr.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Endowed { + account: callee_addr.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: callee_addr.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Reserved { + who: callee_addr.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Transfer { + from: caller_addr.clone(), + to: callee_addr.clone(), + amount: 32768, // hard coded in wasm + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Instantiated { + deployer: caller_addr.clone(), + contract: callee_addr.clone(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Transfer { + from: caller_addr.clone(), + to: callee_addr.clone(), + amount: 32768, + }), + topics: vec![], + }, + ] + ); }); } #[test] fn cannot_self_destruct_through_draning() { let (wasm, code_hash) = compile_module::("drain").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - 100_000, + 1_000, GAS_LIMIT, + None, wasm, vec![], vec![], @@ -697,8 +712,153 @@ fn cannot_self_destruct_through_draning() { assert_matches!(ContractInfoOf::::get(&addr), Some(_)); // Call BOB which makes it send all funds to the zero address - // The contract code asserts that the correct error value is returned. - assert_ok!(Contracts::call(Origin::signed(ALICE), addr, 0, GAS_LIMIT, vec![])); + // The contract code asserts that the transfer was successful + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![] + )); + + // Make sure the account wasn't remove by sending all free balance away. + assert_eq!( + ::Currency::total_balance(&addr), + ::Currency::minimum_balance(), + ); + }); +} + +#[test] +fn cannot_self_destruct_through_storage_refund_after_price_change() { + let (wasm, code_hash) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let min_balance = ::Currency::minimum_balance(); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the BOB contract has been instantiated and has the minimum balance + let info = ContractInfoOf::::get(&addr).unwrap(); + assert_eq!(info.storage_deposit, min_balance); + assert_eq!(::Currency::total_balance(&addr), min_balance); + + // Create 100 bytes of storage with a price of per byte + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + 100u32.to_le_bytes().to_vec() + )); + + // Increase the byte price and trigger a refund. This could potentially destroy the account + // because the refund removes the reserved existential deposit. This should not happen. + DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 500); + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + 0u32.to_le_bytes().to_vec() + )); + + // Make sure the account wasn't removed by the refund + assert_eq!( + ::Currency::total_balance(&addr), + ::Currency::minimum_balance(), + ); + }); +} + +#[test] +fn cannot_self_destruct_by_refund_after_slash() { + let (wasm, code_hash) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let min_balance = ::Currency::minimum_balance(); + + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // create 100 more reserved balance + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + 98u32.encode(), + )); + + // Drop previous events + initialize_block(2); + + // slash parts of the 100 so that the next refund ould remove the account + // because it the value it stored for `storage_deposit` becomes out of sync + let _ = ::Currency::slash(&addr, 90); + assert_eq!(::Currency::total_balance(&addr), min_balance + 10); + + // trigger a refund of 50 which would bring the contract below min when actually refunded + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + 48u32.encode(), + )); + + // Make sure the account kept the minimum balance and was not destroyed + assert_eq!(::Currency::total_balance(&addr), min_balance); + + // even though it was not charged it is still substracted from the storage deposit tracker + assert_eq!(ContractInfoOf::::get(&addr).unwrap().storage_deposit, 550); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Slashed { + who: addr.clone(), + amount: 90, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::ReserveRepatriated { + from: addr.clone(), + to: ALICE, + amount: 10, + destination_status: BalanceStatus::Free, + }), + topics: vec![], + }, + ] + ); }); } @@ -713,6 +873,7 @@ fn cannot_self_destruct_while_live() { Origin::signed(ALICE), 100_000, GAS_LIMIT, + None, wasm, vec![], vec![], @@ -725,7 +886,7 @@ fn cannot_self_destruct_while_live() { // Call BOB with input data, forcing it make a recursive call to itself to // self-destruct, resulting in a trap. assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![0],), + Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![0],), Error::::ContractTrapped, ); @@ -737,7 +898,7 @@ fn cannot_self_destruct_while_live() { #[test] fn self_destruct_works() { let (wasm, code_hash) = compile_module::("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + ExtBuilder::default().existential_deposit(1_000).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); let _ = Balances::deposit_creating(&DJANGO, 1_000_000); @@ -746,6 +907,7 @@ fn self_destruct_works() { Origin::signed(ALICE), 100_000, GAS_LIMIT, + None, wasm, vec![], vec![], @@ -760,51 +922,59 @@ fn self_destruct_works() { // Call BOB without input data which triggers termination. assert_matches!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![],), + Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), Ok(_) ); + // Check that code is still there but refcount dropped to zero. + assert_refcount!(&code_hash, 0); + + // Check that account is gone + assert!(ContractInfoOf::::get(&addr).is_none()); + assert_eq!(Balances::total_balance(&addr), 0); + + // check that the beneficiary (django) got remaining balance + assert_eq!(Balances::free_balance(DJANGO), 1_000_000 + 100_000); + pretty_assertions::assert_eq!( System::events(), vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::KilledAccount { - account: addr.clone() + event: Event::Balances(pallet_balances::Event::Transfer { + from: addr.clone(), + to: DJANGO, + amount: 100_000, }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { - from: addr.clone(), - to: DJANGO, - amount: 100_000, + event: Event::Contracts(crate::Event::Terminated { + contract: addr.clone(), + beneficiary: DJANGO }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeRemoved { code_hash }), + event: Event::System(frame_system::Event::KilledAccount { + account: addr.clone() + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Terminated { - contract: addr.clone(), - beneficiary: DJANGO + event: Event::Balances(pallet_balances::Event::ReserveRepatriated { + from: addr.clone(), + to: ALICE, + amount: 1_000, + destination_status: BalanceStatus::Free, }), topics: vec![], }, ], ); - - // Check that account is gone - assert!(ContractInfoOf::::get(&addr).is_none()); - - // check that the beneficiary (django) got remaining balance - // some rent was deducted before termination - assert_eq!(Balances::free_balance(DJANGO), 1_000_000 + 100_000); }); } @@ -822,6 +992,7 @@ fn destroy_contract_and_transfer_funds() { Origin::signed(ALICE), 200_000, GAS_LIMIT, + None, callee_wasm, vec![], vec![42] @@ -833,6 +1004,7 @@ fn destroy_contract_and_transfer_funds() { Origin::signed(ALICE), 200_000, GAS_LIMIT, + None, caller_wasm, callee_code_hash.as_ref().to_vec(), vec![], @@ -849,6 +1021,7 @@ fn destroy_contract_and_transfer_funds() { addr_bob, 0, GAS_LIMIT, + None, addr_charlie.encode(), )); @@ -869,6 +1042,7 @@ fn cannot_self_destruct_in_constructor() { Origin::signed(ALICE), 100_000, GAS_LIMIT, + None, wasm, vec![], vec![], @@ -890,6 +1064,7 @@ fn crypto_hashes() { Origin::signed(ALICE), 100_000, GAS_LIMIT, + None, wasm, vec![], vec![], @@ -917,7 +1092,7 @@ fn crypto_hashes() { let mut params = vec![(n + 1) as u8]; params.extend_from_slice(input); let result = - >::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, params, false) + >::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, params, false) .result .unwrap(); assert!(result.is_success()); @@ -931,32 +1106,35 @@ fn crypto_hashes() { fn transfer_return_code() { let (wasm, code_hash) = compile_module::("transfer_return_code").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, wasm, vec![], vec![], ),); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - // Contract has only the minimal balance so any transfer will return BelowSubsistence. - Balances::make_free_balance_be(&addr, subsistence); - let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![], false) + // Contract has only the minimal balance so any transfer will fail. + Balances::make_free_balance_be(&addr, min_balance); + let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![], false) .result .unwrap(); - assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); - // Contract has enough total balance in order to not go below the subsistence + // Contract has enough total balance in order to not go below the min balance // threshold when transfering 100 balance but this balance is reserved so - // the transfer still fails but with another return code. - Balances::make_free_balance_be(&addr, subsistence + 100); - Balances::reserve(&addr, subsistence + 100).unwrap(); - let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, vec![], false).result.unwrap(); + // the transfer still fails. + Balances::make_free_balance_be(&addr, min_balance + 100); + Balances::reserve(&addr, min_balance + 100).unwrap(); + let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, None, vec![], false) + .result + .unwrap(); assert_return_code!(result, RuntimeReturnCode::TransferFailed); }); } @@ -966,20 +1144,21 @@ fn call_return_code() { let (caller_code, caller_hash) = compile_module::("call_return_code").unwrap(); let (callee_code, callee_hash) = compile_module::("ok_trap_revert").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); - let _ = Balances::deposit_creating(&CHARLIE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); + let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, caller_code, vec![0], vec![], ),); let addr_bob = Contracts::contract_address(&ALICE, &caller_hash, &[]); - Balances::make_free_balance_be(&addr_bob, subsistence); + Balances::make_free_balance_be(&addr_bob, min_balance); // Contract calls into Django which is no valid contract let result = Contracts::bare_call( @@ -987,6 +1166,7 @@ fn call_return_code() { addr_bob.clone(), 0, GAS_LIMIT, + None, AsRef::<[u8]>::as_ref(&DJANGO).to_vec(), false, ) @@ -996,21 +1176,23 @@ fn call_return_code() { assert_ok!(Contracts::instantiate_with_code( Origin::signed(CHARLIE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, callee_code, vec![0], vec![], ),); let addr_django = Contracts::contract_address(&CHARLIE, &callee_hash, &[]); - Balances::make_free_balance_be(&addr_django, subsistence); + Balances::make_free_balance_be(&addr_django, min_balance); - // Contract has only the minimal balance so any transfer will return BelowSubsistence. + // Contract has only the minimal balance so any transfer will fail. let result = Contracts::bare_call( ALICE, addr_bob.clone(), 0, GAS_LIMIT, + None, AsRef::<[u8]>::as_ref(&addr_django) .iter() .chain(&0u32.to_le_bytes()) @@ -1020,18 +1202,19 @@ fn call_return_code() { ) .result .unwrap(); - assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); - // Contract has enough total balance in order to not go below the subsistence + // Contract has enough total balance in order to not go below the min balance // threshold when transfering 100 balance but this balance is reserved so - // the transfer still fails but with another return code. - Balances::make_free_balance_be(&addr_bob, subsistence + 100); - Balances::reserve(&addr_bob, subsistence + 100).unwrap(); + // the transfer still fails. + Balances::make_free_balance_be(&addr_bob, min_balance + 100); + Balances::reserve(&addr_bob, min_balance + 100).unwrap(); let result = Contracts::bare_call( ALICE, addr_bob.clone(), 0, GAS_LIMIT, + None, AsRef::<[u8]>::as_ref(&addr_django) .iter() .chain(&0u32.to_le_bytes()) @@ -1044,12 +1227,13 @@ fn call_return_code() { assert_return_code!(result, RuntimeReturnCode::TransferFailed); // Contract has enough balance but callee reverts because "1" is passed. - Balances::make_free_balance_be(&addr_bob, subsistence + 1000); + Balances::make_free_balance_be(&addr_bob, min_balance + 1000); let result = Contracts::bare_call( ALICE, addr_bob.clone(), 0, GAS_LIMIT, + None, AsRef::<[u8]>::as_ref(&addr_django) .iter() .chain(&1u32.to_le_bytes()) @@ -1067,6 +1251,7 @@ fn call_return_code() { addr_bob, 0, GAS_LIMIT, + None, AsRef::<[u8]>::as_ref(&addr_django) .iter() .chain(&2u32.to_le_bytes()) @@ -1085,15 +1270,16 @@ fn instantiate_return_code() { let (caller_code, caller_hash) = compile_module::("instantiate_return_code").unwrap(); let (callee_code, callee_hash) = compile_module::("ok_trap_revert").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); - let _ = Balances::deposit_creating(&CHARLIE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); + let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); let callee_hash = callee_hash.as_ref().to_vec(); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, callee_code, vec![], vec![], @@ -1101,46 +1287,63 @@ fn instantiate_return_code() { assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, caller_code, vec![], vec![], ),); let addr = Contracts::contract_address(&ALICE, &caller_hash, &[]); - // Contract has only the minimal balance so any transfer will return BelowSubsistence. - Balances::make_free_balance_be(&addr, subsistence); - let result = - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, callee_hash.clone(), false) - .result - .unwrap(); - assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold); - - // Contract has enough total balance in order to not go below the subsistence - // threshold when transfering the balance but this balance is reserved so - // the transfer still fails but with another return code. - Balances::make_free_balance_be(&addr, subsistence + 10_000); - Balances::reserve(&addr, subsistence + 10_000).unwrap(); - let result = - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, callee_hash.clone(), false) - .result - .unwrap(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); - - // Contract has enough balance but the passed code hash is invalid - Balances::make_free_balance_be(&addr, subsistence + 10_000); - let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![0; 33], false) - .result - .unwrap(); - assert_return_code!(result, RuntimeReturnCode::CodeNotFound); - - // Contract has enough balance but callee reverts because "1" is passed. + // Contract has only the minimal balance so any transfer will fail. + Balances::make_free_balance_be(&addr, min_balance); let result = Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, + None, + callee_hash.clone(), + false, + ) + .result + .unwrap(); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); + + // Contract has enough total balance in order to not go below the min_balance + // threshold when transfering the balance but this balance is reserved so + // the transfer still fails. + Balances::make_free_balance_be(&addr, min_balance + 10_000); + Balances::reserve(&addr, min_balance + 10_000).unwrap(); + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + callee_hash.clone(), + false, + ) + .result + .unwrap(); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); + + // Contract has enough balance but the passed code hash is invalid + Balances::make_free_balance_be(&addr, min_balance + 10_000); + let result = + Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![0; 33], false) + .result + .unwrap(); + assert_return_code!(result, RuntimeReturnCode::CodeNotFound); + + // Contract has enough balance but callee reverts because "1" is passed. + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, callee_hash.iter().chain(&1u32.to_le_bytes()).cloned().collect(), false, ) @@ -1154,6 +1357,7 @@ fn instantiate_return_code() { addr, 0, GAS_LIMIT, + None, callee_hash.iter().chain(&2u32.to_le_bytes()).cloned().collect(), false, ) @@ -1167,14 +1371,15 @@ fn instantiate_return_code() { fn disabled_chain_extension_wont_deploy() { let (code, _hash) = compile_module::("chain_extension").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); TestExtension::disable(); assert_err_ignore_postinfo!( Contracts::instantiate_with_code( Origin::signed(ALICE), - 3 * subsistence, + 3 * min_balance, GAS_LIMIT, + None, code, vec![], vec![], @@ -1188,12 +1393,13 @@ fn disabled_chain_extension_wont_deploy() { fn disabled_chain_extension_errors_on_call() { let (code, hash) = compile_module::("chain_extension").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, code, vec![], vec![], @@ -1201,7 +1407,7 @@ fn disabled_chain_extension_errors_on_call() { let addr = Contracts::contract_address(&ALICE, &hash, &[]); TestExtension::disable(); assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![],), + Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), Error::::NoChainExtension, ); }); @@ -1211,12 +1417,13 @@ fn disabled_chain_extension_errors_on_call() { fn chain_extension_works() { let (code, hash) = compile_module::("chain_extension").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, code, vec![], vec![], @@ -1228,25 +1435,27 @@ fn chain_extension_works() { // func_id. // 0 = read input buffer and pass it through as output - let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![0, 99], false); + let result = + Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![0, 99], false); let gas_consumed = result.gas_consumed; assert_eq!(TestExtension::last_seen_buffer(), vec![0, 99]); assert_eq!(result.result.unwrap().data, Bytes(vec![0, 99])); // 1 = treat inputs as integer primitives and store the supplied integers - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![1], false) + Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![1], false) .result .unwrap(); // those values passed in the fixture assert_eq!(TestExtension::last_seen_inputs(), (4, 1, 16, 12)); // 2 = charge some extra weight (amount supplied in second byte) - let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![2, 42], false); + let result = + Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![2, 42], false); assert_ok!(result.result); assert_eq!(result.gas_consumed, gas_consumed + 42); // 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer - let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![3], false) + let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![3], false) .result .unwrap(); assert_eq!(result.flags, ReturnFlags::REVERT); @@ -1258,13 +1467,14 @@ fn chain_extension_works() { fn lazy_removal_works() { let (code, hash) = compile_module::("self_destruct").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, code, vec![], vec![], @@ -1278,7 +1488,14 @@ fn lazy_removal_works() { child::put(trie, &[99], &42); // Terminate the contract - assert_ok!(Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![])); + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![] + )); // Contract info should be gone assert!(!>::contains_key(&addr)); @@ -1309,29 +1526,37 @@ fn lazy_removal_partial_remove_works() { let mut ext = ExtBuilder::default().existential_deposit(50).build(); let trie = ext.execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, code, vec![], vec![], ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let mut info = >::get(&addr).unwrap(); + let info = >::get(&addr).unwrap(); // Put value into the contracts child trie for val in &vals { - Storage::::write(&mut info, &val.0, Some(val.2.clone())).unwrap(); + Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None).unwrap(); } >::insert(&addr, info.clone()); // Terminate the contract - assert_ok!(Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![])); + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![] + )); // Contract info should be gone assert!(!>::contains_key(&addr)); @@ -1379,20 +1604,21 @@ fn lazy_removal_partial_remove_works() { fn lazy_removal_does_no_run_on_full_block() { let (code, hash) = compile_module::("self_destruct").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, code, vec![], vec![], ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let mut info = >::get(&addr).unwrap(); + let info = >::get(&addr).unwrap(); let max_keys = 30; // Create some storage items for the contract. @@ -1402,12 +1628,19 @@ fn lazy_removal_does_no_run_on_full_block() { // Put value into the contracts child trie for val in &vals { - Storage::::write(&mut info, &val.0, Some(val.2.clone())).unwrap(); + Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None).unwrap(); } >::insert(&addr, info.clone()); // Terminate the contract - assert_ok!(Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![])); + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![] + )); // Contract info should be gone assert!(!>::contains_key(&addr)); @@ -1454,20 +1687,21 @@ fn lazy_removal_does_not_use_all_weight() { let mut ext = ExtBuilder::default().existential_deposit(50).build(); let (trie, vals, weight_per_key) = ext.execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, code, vec![], vec![], ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let mut info = >::get(&addr).unwrap(); + let info = >::get(&addr).unwrap(); let (weight_per_key, max_keys) = Storage::::deletion_budget(1, weight_limit); // We create a contract with one less storage item than we can remove within the limit @@ -1477,12 +1711,19 @@ fn lazy_removal_does_not_use_all_weight() { // Put value into the contracts child trie for val in &vals { - Storage::::write(&mut info, &val.0, Some(val.2.clone())).unwrap(); + Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None).unwrap(); } >::insert(&addr, info.clone()); // Terminate the contract - assert_ok!(Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![])); + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![] + )); // Contract info should be gone assert!(!>::contains_key(&addr)); @@ -1519,13 +1760,14 @@ fn lazy_removal_does_not_use_all_weight() { fn deletion_queue_full() { let (code, hash) = compile_module::("self_destruct").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, code, vec![], vec![], @@ -1538,7 +1780,7 @@ fn deletion_queue_full() { // Terminate the contract should fail assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![],), + Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), Error::::DeletionQueueFull, ); @@ -1552,21 +1794,23 @@ fn refcounter() { let (wasm, code_hash) = compile_module::("self_destruct").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); - let subsistence = Pallet::::subsistence_threshold(); + let min_balance = ::Currency::minimum_balance(); // Create two contracts with the same code and check that they do in fact share it. assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, wasm.clone(), vec![], vec![0], )); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, wasm.clone(), vec![], vec![1], @@ -1576,8 +1820,9 @@ fn refcounter() { // Sharing should also work with the usual instantiate call assert_ok!(Contracts::instantiate( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, code_hash, vec![], vec![2], @@ -1590,23 +1835,23 @@ fn refcounter() { let addr2 = Contracts::contract_address(&ALICE, &code_hash, &[2]); // Terminating one contract should decrement the refcount - assert_ok!(Contracts::call(Origin::signed(ALICE), addr0, 0, GAS_LIMIT, vec![])); + assert_ok!(Contracts::call(Origin::signed(ALICE), addr0, 0, GAS_LIMIT, None, vec![])); assert_refcount!(code_hash, 2); // remove another one - assert_ok!(Contracts::call(Origin::signed(ALICE), addr1, 0, GAS_LIMIT, vec![])); + assert_ok!(Contracts::call(Origin::signed(ALICE), addr1, 0, GAS_LIMIT, None, vec![])); assert_refcount!(code_hash, 1); // Pristine code should still be there crate::PristineCode::::get(code_hash).unwrap(); // remove the last contract - assert_ok!(Contracts::call(Origin::signed(ALICE), addr2, 0, GAS_LIMIT, vec![])); + assert_ok!(Contracts::call(Origin::signed(ALICE), addr2, 0, GAS_LIMIT, None, vec![])); assert_refcount!(code_hash, 0); - // all code should be gone - assert_matches!(crate::PristineCode::::get(code_hash), None); - assert_matches!(crate::CodeStorage::::get(code_hash), None); + // refcount is `0` but code should still exists because it needs to be removed manually + assert!(crate::PristineCode::::contains_key(&code_hash)); + assert!(crate::CodeStorage::::contains_key(&code_hash)); }); } @@ -1615,14 +1860,15 @@ fn reinstrument_does_charge() { let (wasm, code_hash) = compile_module::("return_with_data").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); - let subsistence = Pallet::::subsistence_threshold(); + let min_balance = ::Currency::minimum_balance(); let zero = 0u32.to_le_bytes().encode(); let code_len = wasm.len() as u32; assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, wasm, zero.clone(), vec![], @@ -1632,10 +1878,12 @@ fn reinstrument_does_charge() { // Call the contract two times without reinstrument - let result0 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, zero.clone(), false); + let result0 = + Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); assert!(result0.result.unwrap().is_success()); - let result1 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, zero.clone(), false); + let result1 = + Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); assert!(result1.result.unwrap().is_success()); // They should match because both where called with the same schedule. @@ -1648,7 +1896,8 @@ fn reinstrument_does_charge() { }); // This call should trigger reinstrumentation - let result2 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, zero.clone(), false); + let result2 = + Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); assert!(result2.result.unwrap().is_success()); assert!(result2.gas_consumed > result1.gas_consumed); assert_eq!( @@ -1668,12 +1917,13 @@ fn debug_message_works() { Origin::signed(ALICE), 30_000, GAS_LIMIT, + None, wasm, vec![], vec![], ),); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, vec![], true); + let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, None, vec![], true); assert_matches!(result.result, Ok(_)); assert_eq!(std::str::from_utf8(&result.debug_message).unwrap(), "Hello World!"); @@ -1690,16 +1940,17 @@ fn debug_message_logging_disabled() { Origin::signed(ALICE), 30_000, GAS_LIMIT, + None, wasm, vec![], vec![], ),); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // disable logging by passing `false` - let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![], false); + let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![], false); assert_matches!(result.result, Ok(_)); // the dispatchables always run without debugging - assert_ok!(Contracts::call(Origin::signed(ALICE), addr, 0, GAS_LIMIT, vec![])); + assert_ok!(Contracts::call(Origin::signed(ALICE), addr, 0, GAS_LIMIT, None, vec![])); assert!(result.debug_message.is_empty()); }); } @@ -1714,12 +1965,13 @@ fn debug_message_invalid_utf8() { Origin::signed(ALICE), 30_000, GAS_LIMIT, + None, wasm, vec![], vec![], ),); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, vec![], true); + let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, None, vec![], true); assert_err!(result.result, >::DebugMessageInvalidUTF8); }); } @@ -1729,14 +1981,15 @@ fn gas_estimation_nested_call_fixed_limit() { let (caller_code, caller_hash) = compile_module::("call_with_limit").unwrap(); let (callee_code, callee_hash) = compile_module::("dummy").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); - let _ = Balances::deposit_creating(&CHARLIE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); + let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, caller_code, vec![], vec![0], @@ -1745,8 +1998,9 @@ fn gas_estimation_nested_call_fixed_limit() { assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, callee_code, vec![], vec![1], @@ -1760,15 +2014,32 @@ fn gas_estimation_nested_call_fixed_limit() { .collect(); // Call in order to determine the gas that is required for this call - let result = - Contracts::bare_call(ALICE, addr_caller.clone(), 0, GAS_LIMIT, input.clone(), false); + let result = Contracts::bare_call( + ALICE, + addr_caller.clone(), + 0, + GAS_LIMIT, + None, + input.clone(), + false, + ); assert_ok!(&result.result); + // We have a subcall with a fixed gas limit. This constitutes precharging. assert!(result.gas_required > result.gas_consumed); // Make the same call using the estimated gas. Should succeed. assert_ok!( - Contracts::bare_call(ALICE, addr_caller, 0, result.gas_required, input, false,).result + Contracts::bare_call( + ALICE, + addr_caller, + 0, + result.gas_required, + Some(result.storage_deposit.charge_or_zero()), + input, + false, + ) + .result ); }); } @@ -1779,14 +2050,15 @@ fn gas_estimation_call_runtime() { let (caller_code, caller_hash) = compile_module::("call_runtime").unwrap(); let (callee_code, callee_hash) = compile_module::("dummy").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let subsistence = Pallet::::subsistence_threshold(); - let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence); - let _ = Balances::deposit_creating(&CHARLIE, 1000 * subsistence); + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); + let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, caller_code, vec![], vec![0], @@ -1795,8 +2067,9 @@ fn gas_estimation_call_runtime() { assert_ok!(Contracts::instantiate_with_code( Origin::signed(ALICE), - subsistence * 100, + min_balance * 100, GAS_LIMIT, + None, callee_code, vec![], vec![1], @@ -1809,18 +2082,34 @@ fn gas_estimation_call_runtime() { dest: addr_callee, value: 0, gas_limit: GAS_LIMIT / 3, + storage_deposit_limit: None, data: vec![], }); - let result = - Contracts::bare_call(ALICE, addr_caller.clone(), 0, GAS_LIMIT, call.encode(), false); + let result = Contracts::bare_call( + ALICE, + addr_caller.clone(), + 0, + GAS_LIMIT, + None, + call.encode(), + false, + ); assert_ok!(&result.result); assert!(result.gas_required > result.gas_consumed); // Make the same call using the required gas. Should succeed. assert_ok!( - Contracts::bare_call(ALICE, addr_caller, 0, result.gas_required, call.encode(), false,) - .result + Contracts::bare_call( + ALICE, + addr_caller, + 0, + result.gas_required, + None, + call.encode(), + false, + ) + .result ); }); } @@ -1838,6 +2127,7 @@ fn ecdsa_recover() { Origin::signed(ALICE), 100_000, GAS_LIMIT, + None, wasm, vec![], vec![], @@ -1867,10 +2157,653 @@ fn ecdsa_recover() { params.extend_from_slice(&signature); params.extend_from_slice(&message_hash); assert!(params.len() == 65 + 32); - let result = >::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, params, false) - .result - .unwrap(); + let result = + >::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, params, false) + .result + .unwrap(); assert!(result.is_success()); assert_eq!(result.data.as_ref(), &EXPECTED_COMPRESSED_PUBLIC_KEY); }) } + +#[test] +fn upload_code_works() { + let (wasm, code_hash) = compile_module::("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert!(!>::contains_key(code_hash)); + assert_ok!(Contracts::upload_code( + Origin::signed(ALICE), + wasm, + Some(codec::Compact(1_000)) + )); + assert!(>::contains_key(code_hash)); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Reserved { + who: ALICE, + amount: 180, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::CodeStored { code_hash }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn upload_code_limit_too_low() { + let (wasm, _code_hash) = compile_module::("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert_noop!( + Contracts::upload_code(Origin::signed(ALICE), wasm, Some(codec::Compact(100))), + >::StorageDepositLimitExhausted, + ); + + assert_eq!(System::events(), vec![]); + }); +} + +#[test] +fn upload_code_not_enough_balance() { + let (wasm, _code_hash) = compile_module::("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 150); + + // Drop previous events + initialize_block(2); + + assert_noop!( + Contracts::upload_code(Origin::signed(ALICE), wasm, Some(codec::Compact(1_000))), + >::StorageDepositNotEnoughFunds, + ); + + assert_eq!(System::events(), vec![]); + }); +} + +#[test] +fn remove_code_works() { + let (wasm, code_hash) = compile_module::("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert_ok!(Contracts::upload_code( + Origin::signed(ALICE), + wasm, + Some(codec::Compact(1_000)) + )); + + assert!(>::contains_key(code_hash)); + assert_ok!(Contracts::remove_code(Origin::signed(ALICE), code_hash)); + assert!(!>::contains_key(code_hash)); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Reserved { + who: ALICE, + amount: 180, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::CodeStored { code_hash }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Unreserved { + who: ALICE, + amount: 180, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::CodeRemoved { code_hash }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn remove_code_wrong_origin() { + let (wasm, code_hash) = compile_module::("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert_ok!(Contracts::upload_code( + Origin::signed(ALICE), + wasm, + Some(codec::Compact(1_000)) + )); + + assert_noop!( + Contracts::remove_code(Origin::signed(BOB), code_hash), + sp_runtime::traits::BadOrigin, + ); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Reserved { + who: ALICE, + amount: 180, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::CodeStored { code_hash }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn remove_code_in_use() { + let (wasm, code_hash) = compile_module::("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + + // Drop previous events + initialize_block(2); + + assert_noop!( + Contracts::remove_code(Origin::signed(ALICE), code_hash), + >::CodeInUse, + ); + + assert_eq!(System::events(), vec![]); + }); +} + +#[test] +fn remove_code_not_found() { + let (_wasm, code_hash) = compile_module::("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert_noop!( + Contracts::remove_code(Origin::signed(ALICE), code_hash), + >::CodeNotFound, + ); + + assert_eq!(System::events(), vec![]); + }); +} + +#[test] +fn instantiate_with_zero_balance_works() { + let (wasm, code_hash) = compile_module::("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let min_balance = ::Currency::minimum_balance(); + + // Drop previous events + initialize_block(2); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the BOB contract has been instantiated. + assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + + // Make sure the account exists even though no free balance was send + assert_eq!(::Currency::free_balance(&addr), 0,); + assert_eq!( + ::Currency::total_balance(&addr), + ::Currency::minimum_balance(), + ); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Endowed { + account: addr.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Reserved { + who: addr.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Reserved { + who: ALICE, + amount: 180, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::CodeStored { code_hash }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Instantiated { + deployer: ALICE, + contract: addr.clone(), + }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn instantiate_with_below_existential_deposit_works() { + let (wasm, code_hash) = compile_module::("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let min_balance = ::Currency::minimum_balance(); + + // Drop previous events + initialize_block(2); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + 50, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the BOB contract has been instantiated. + assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + + // Make sure the account exists even though no free balance was send + assert_eq!(::Currency::free_balance(&addr), 50,); + assert_eq!( + ::Currency::total_balance(&addr), + ::Currency::minimum_balance() + 50, + ); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Endowed { + account: addr.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Reserved { + who: addr.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), + amount: 50, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Reserved { + who: ALICE, + amount: 180, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::CodeStored { code_hash }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Instantiated { + deployer: ALICE, + contract: addr.clone(), + }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn storage_deposit_works() { + let (wasm, code_hash) = compile_module::("multi_store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let mut deposit = ::Currency::minimum_balance(); + + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Drop previous events + initialize_block(2); + + // Create storage + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 42, + GAS_LIMIT, + None, + (1_000u32, 5_000u32).encode(), + )); + // 4 is for creating 2 storage items + let charged0 = 4 + 1_000 + 5_000; + deposit += charged0; + assert_eq!(>::get(&addr).unwrap().storage_deposit, deposit); + + // Add more storage (but also remove some) + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + (2_000u32, 4_900u32).encode(), + )); + let charged1 = 1_000 - 100; + deposit += charged1; + assert_eq!(>::get(&addr).unwrap().storage_deposit, deposit); + + // Remove more storage (but also add some) + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + (2_100u32, 900u32).encode(), + )); + let refunded0 = 4_000 - 100; + deposit -= refunded0; + assert_eq!(>::get(&addr).unwrap().storage_deposit, deposit); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), + amount: 42, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), + amount: charged0, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Reserved { + who: addr.clone(), + amount: charged0, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), + amount: charged1, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Reserved { + who: addr.clone(), + amount: charged1, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::ReserveRepatriated { + from: addr.clone(), + to: ALICE, + amount: refunded0, + destination_status: BalanceStatus::Free, + }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn call_after_killed_account_needs_funding() { + let (wasm, code_hash) = compile_module::("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let min_balance = ::Currency::minimum_balance(); + + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + 700, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Drop previous events + initialize_block(2); + + // Destroy the account of the contract by slashing. + // Slashing can actually happen if the contract takes part in staking. + // It is a corner case and we except the destruction of the account. + let _ = ::Currency::slash( + &addr, + ::Currency::total_balance(&addr), + ); + + // Sending below the minimum balance will fail the call because it needs to create the + // account in order to send balance there. + assert_err_ignore_postinfo!( + Contracts::call( + Origin::signed(ALICE), + addr.clone(), + min_balance - 1, + GAS_LIMIT, + None, + vec![], + ), + >::TransferFailed + ); + + // Sending zero should work as it does not do a transfer + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![], + )); + + // Sending minimum balance should work + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + min_balance, + GAS_LIMIT, + None, + vec![], + )); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: Event::System(frame_system::Event::KilledAccount { + account: addr.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Slashed { + who: addr.clone(), + amount: min_balance + 700 + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Endowed { + account: addr.clone(), + free_balance: min_balance + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), + amount: min_balance + }), + topics: vec![], + }, + ] + ); + }); +} diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index afb68d4d81179..823d6ed34a671 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -28,177 +28,170 @@ //! this guarantees that every instrumented contract code in cache cannot have the version equal to //! the current one. Thus, before executing a contract it should be reinstrument with new schedule. -#[cfg(feature = "runtime-benchmarks")] -pub use self::private::reinstrument; use crate::{ gas::{GasMeter, Token}, wasm::{prepare, PrefabWasmModule}, weights::WeightInfo, - CodeHash, CodeStorage, Config, Error, Event, Pallet as Contracts, PristineCode, Schedule, + CodeHash, CodeStorage, Config, Error, Event, OwnerInfoOf, Pallet, PristineCode, Schedule, Weight, }; -use frame_support::dispatch::DispatchError; +use frame_support::{ + dispatch::{DispatchError, DispatchResult}, + ensure, + storage::StorageMap, + traits::ReservableCurrency, +}; use sp_core::crypto::UncheckedFrom; +use sp_runtime::traits::BadOrigin; /// Put the instrumented module in storage. /// /// Increments the refcount of the in-storage `prefab_module` if it already exists in storage /// under the specified `code_hash`. -pub fn store(mut prefab_module: PrefabWasmModule) +pub fn store(mut module: PrefabWasmModule, instantiated: bool) -> DispatchResult where T::AccountId: UncheckedFrom + AsRef<[u8]>, { - let code_hash = sp_std::mem::take(&mut prefab_module.code_hash); - - // original_code is only `Some` if the contract was instantiated from a new code - // but `None` if it was loaded from storage. - if let Some(code) = prefab_module.original_code.take() { - >::insert(&code_hash, code); - } + let code_hash = sp_std::mem::take(&mut module.code_hash); >::mutate(&code_hash, |existing| match existing { - Some(module) => increment_64(&mut module.refcount), + Some(existing) => { + // We instrument any uploaded contract anyways. We might as well store it to save + // a potential re-instrumentation later. + existing.code = module.code; + existing.instruction_weights_version = module.instruction_weights_version; + // When the code was merely uploaded but not instantiated we can skip this. + if instantiated { + >::mutate(&code_hash, |owner_info| { + if let Some(owner_info) = owner_info { + owner_info.refcount = owner_info.refcount.checked_add(1).expect( + " + refcount is 64bit. Generating this overflow would require to store + _at least_ 18 exabyte of data assuming that a contract consumes only + one byte of data. Any node would run out of storage space before hitting + this overflow. + qed + ", + ); + } + }) + } + Ok(()) + }, None => { - *existing = Some(prefab_module); - Contracts::::deposit_event(Event::CodeStored { code_hash }) + let orig_code = module.original_code.take().expect( + " + If an executable isn't in storage it was uploaded. + If it was uploaded the original code must exist. qed + ", + ); + let mut owner_info = module.owner_info.take().expect( + "If an executable isn't in storage it was uploaded. + If it was uploaded the owner info was generated and attached. qed + ", + ); + // This `None` case happens only in freshly uploaded modules. This means that + // the `owner` is always the origin of the current transaction. + T::Currency::reserve(&owner_info.owner, owner_info.deposit) + .map_err(|_| >::StorageDepositNotEnoughFunds)?; + owner_info.refcount = if instantiated { 1 } else { 0 }; + >::insert(&code_hash, orig_code); + >::insert(&code_hash, owner_info); + *existing = Some(module); + >::deposit_event(Event::CodeStored { code_hash }); + Ok(()) }, + }) +} + +/// Decrement the refcount of a code in-storage by one. +/// +/// # Note +/// +/// A contract whose refcount dropped to zero isn't automatically removed. A `remove_code` +/// transaction must be submitted by the original uploader to do so. +pub fn decrement_refcount(code_hash: CodeHash) -> Result<(), DispatchError> { + >::mutate(code_hash, |existing| { + if let Some(info) = existing { + info.refcount = info.refcount.saturating_sub(1); + } }); + Ok(()) } -/// Increment the refcount of a code in-storage by one. -pub fn increment_refcount( - code_hash: CodeHash, - gas_meter: &mut GasMeter, -) -> Result<(), DispatchError> -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ - gas_meter.charge(CodeToken::UpdateRefcount(estimate_code_size::(&code_hash)?))?; - >::mutate(code_hash, |existing| { - if let Some(module) = existing { - increment_64(&mut module.refcount); +/// Try to remove code together with all associated information. +pub fn try_remove(origin: &T::AccountId, code_hash: CodeHash) -> DispatchResult { + >::try_mutate_exists(&code_hash, |existing| { + if let Some(owner_info) = existing { + ensure!(owner_info.refcount == 0, >::CodeInUse); + ensure!(&owner_info.owner == origin, BadOrigin); + T::Currency::unreserve(&owner_info.owner, owner_info.deposit); + *existing = None; + >::remove(&code_hash); + >::remove(&code_hash); + >::deposit_event(Event::CodeRemoved { code_hash }); Ok(()) } else { - Err(Error::::CodeNotFound.into()) + Err(>::CodeNotFound.into()) } }) } -/// Decrement the refcount of a code in-storage by one and remove the code when it drops to zero. -pub fn decrement_refcount( - code_hash: CodeHash, - gas_meter: &mut GasMeter, -) -> Result<(), DispatchError> -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ - if let Ok(len) = estimate_code_size::(&code_hash) { - gas_meter.charge(CodeToken::UpdateRefcount(len))?; - } - >::mutate_exists(code_hash, |existing| { - if let Some(module) = existing { - module.refcount = module.refcount.saturating_sub(1); - if module.refcount == 0 { - *existing = None; - finish_removal::(code_hash); - } - } - }); - Ok(()) -} - /// Load code with the given code hash. /// /// If the module was instrumented with a lower version of schedule than /// the current one given as an argument, then this function will perform /// re-instrumentation and update the cache in the storage. -/// -/// # Note -/// -/// If `reinstrument` is set it is assumed that the load is performed in the context of -/// a contract call: This means we charge the size based cased for loading the contract. pub fn load( code_hash: CodeHash, - mut reinstrument: Option<(&Schedule, &mut GasMeter)>, + schedule: &Schedule, + gas_meter: &mut GasMeter, ) -> Result, DispatchError> where T::AccountId: UncheckedFrom + AsRef<[u8]>, { - // The reinstrument case coincides with the cases where we need to charge extra - // based upon the code size: On-chain execution. - if let Some((_, gas_meter)) = &mut reinstrument { - gas_meter.charge(CodeToken::Load(estimate_code_size::(&code_hash)?))?; - } + gas_meter.charge(CodeToken::Load(estimate_code_size::, _>(&code_hash)?))?; let mut prefab_module = >::get(code_hash).ok_or_else(|| Error::::CodeNotFound)?; prefab_module.code_hash = code_hash; - if let Some((schedule, gas_meter)) = reinstrument { - if prefab_module.instruction_weights_version < schedule.instruction_weights.version { - // The instruction weights have changed. - // We need to re-instrument the code with the new instruction weights. - gas_meter.charge(CodeToken::Instrument(prefab_module.original_code_len))?; - private::reinstrument(&mut prefab_module, schedule)?; - } - } - Ok(prefab_module) -} - -mod private { - use super::*; - - /// Instruments the passed prefab wasm module with the supplied schedule. - pub fn reinstrument( - prefab_module: &mut PrefabWasmModule, - schedule: &Schedule, - ) -> Result<(), DispatchError> - where - T::AccountId: UncheckedFrom + AsRef<[u8]>, - { - let original_code = >::get(&prefab_module.code_hash) - .ok_or_else(|| Error::::CodeNotFound)?; - prefab_module.code = prepare::reinstrument_contract::(original_code, schedule)?; - prefab_module.instruction_weights_version = schedule.instruction_weights.version; - >::insert(&prefab_module.code_hash, &*prefab_module); - Ok(()) + if prefab_module.instruction_weights_version < schedule.instruction_weights.version { + // The instruction weights have changed. + // We need to re-instrument the code with the new instruction weights. + gas_meter.charge(CodeToken::Instrument(estimate_code_size::, _>( + &code_hash, + )?))?; + reinstrument(&mut prefab_module, schedule)?; } -} -/// Finish removal of a code by deleting the pristine code and emitting an event. -fn finish_removal(code_hash: CodeHash) -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ - >::remove(code_hash); - Contracts::::deposit_event(Event::CodeRemoved { code_hash }) + Ok(prefab_module) } -/// Increment the refcount panicking if it should ever overflow (which will not happen). -/// -/// We try hard to be infallible here because otherwise more storage transactions would be -/// necessary to account for failures in storing code for an already instantiated contract. -fn increment_64(refcount: &mut u64) { - *refcount = refcount.checked_add(1).expect( - " - refcount is 64bit. Generating this overflow would require to store - _at least_ 18 exabyte of data assuming that a contract consumes only - one byte of data. Any node would run out of storage space before hitting - this overflow. - qed - ", - ); +/// Instruments the passed prefab wasm module with the supplied schedule. +pub fn reinstrument( + prefab_module: &mut PrefabWasmModule, + schedule: &Schedule, +) -> Result<(), DispatchError> { + let original_code = + >::get(&prefab_module.code_hash).ok_or_else(|| Error::::CodeNotFound)?; + prefab_module.code = prepare::reinstrument_contract::(original_code, schedule)?; + prefab_module.instruction_weights_version = schedule.instruction_weights.version; + >::insert(&prefab_module.code_hash, &*prefab_module); + Ok(()) } -/// Get the size of the instrumented code stored at `code_hash` without loading it. +/// Get the size of the code stored at `code_hash` without loading it. /// -/// The returned value is slightly too large because it also contains the fields apart from -/// `code` which are located inside [`PrefabWasmModule`]. However, those are negligible when -/// compared to the code size. Additionally, charging too much weight is completely safe. -fn estimate_code_size(code_hash: &CodeHash) -> Result +/// The returned value is slightly too large when using it for the [`PrefabWasmModule`] +/// because it has other fields in addition to the code itself. However, those are negligible +/// when compared to the code size. Additionally, charging too much weight is completely safe. +fn estimate_code_size(code_hash: &CodeHash) -> Result where - T::AccountId: UncheckedFrom + AsRef<[u8]>, + T: Config, + M: StorageMap, V>, + V: codec::FullCodec, { - let key = >::hashed_key_for(code_hash); + let key = M::hashed_key_for(code_hash); let mut data = [0u8; 0]; let len = sp_io::storage::read(&key, &mut data, 0).ok_or_else(|| Error::::CodeNotFound)?; Ok(len) @@ -212,18 +205,12 @@ enum CodeToken { Instrument(u32), /// Weight for loading a contract per kilobyte. Load(u32), - /// Weight for changing the refcount of a contract per kilobyte. - UpdateRefcount(u32), } -impl Token for CodeToken -where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl Token for CodeToken { fn weight(&self) -> Weight { use self::CodeToken::*; - // In case of `Load` and `UpdateRefcount` we already covered the general costs of + // In case of `Load` we already covered the general costs of // accessing the storage but still need to account for the actual size of the // contract code. This is why we substract `T::*::(0)`. We need to do this at this // point because when charging the general weight we do not know the size of @@ -232,8 +219,6 @@ where Instrument(len) => T::WeightInfo::instrument(len / 1024), Load(len) => T::WeightInfo::code_load(len / 1024).saturating_sub(T::WeightInfo::code_load(0)), - UpdateRefcount(len) => T::WeightInfo::code_refcount(len / 1024) - .saturating_sub(T::WeightInfo::code_refcount(0)), } } } diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 6a807710a5265..01e220d410fa4 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -31,10 +31,10 @@ use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, gas::GasMeter, wasm::env_def::FunctionImplProvider, - CodeHash, Config, Schedule, + AccountIdOf, BalanceOf, CodeHash, CodeStorage, Config, Schedule, }; -use codec::{Decode, Encode}; -use frame_support::dispatch::DispatchError; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::dispatch::{DispatchError, DispatchResult}; use sp_core::crypto::UncheckedFrom; use sp_sandbox::{SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory}; use sp_std::prelude::*; @@ -46,10 +46,9 @@ pub use tests::MockExt; /// # Note /// /// This data structure is mostly immutable once created and stored. The exceptions that -/// can be changed by calling a contract are `refcount`, `instruction_weights_version` and `code`. -/// `refcount` can change when a contract instantiates a new contract or self terminates. -/// `instruction_weights_version` and `code` when a contract with an outdated instrumention is -/// called. Therefore one must be careful when holding any in-memory representation of this +/// can be changed by calling a contract are `instruction_weights_version` and `code`. +/// `instruction_weights_version` and `code` change when a contract with an outdated instrumentation +/// is called. Therefore one must be careful when holding any in-memory representation of this /// type while calling into a contract as those fields can get out of date. #[derive(Clone, Encode, Decode, scale_info::TypeInfo)] #[scale_info(skip_type_params(T))] @@ -63,26 +62,8 @@ pub struct PrefabWasmModule { /// The maximum memory size of a contract's sandbox. #[codec(compact)] maximum: u32, - /// The number of contracts that use this as their contract code. - /// - /// If this number drops to zero this module is removed from storage. - #[codec(compact)] - refcount: u64, - /// This field is reserved for future evolution of format. - /// - /// For now this field is serialized as `None`. In the future we are able to change the - /// type parameter to a new struct that contains the fields that we want to add. - /// That new struct would also contain a reserved field for its future extensions. - /// This works because in SCALE `None` is encoded independently from the type parameter - /// of the option. - _reserved: Option<()>, /// Code instrumented with the latest schedule. code: Vec, - /// The size of the uninstrumented code. - /// - /// We cache this value here in order to avoid the need to pull the pristine code - /// from storage when we only need its length for rent calculations. - original_code_len: u32, /// The uninstrumented, pristine version of the code. /// /// It is not stored because the pristine code has its own storage item. The value @@ -96,6 +77,27 @@ pub struct PrefabWasmModule { /// when loading the module from storage. #[codec(skip)] code_hash: CodeHash, + // This isn't needed for contract execution and does not get loaded from storage by default. + // It is `Some` if and only if this struct was generated from code. + #[codec(skip)] + owner_info: Option>, +} + +/// Information that belongs to a [`PrefabWasmModule`] but is stored separately. +/// +/// It is stored in a separate storage entry to avoid loading the code when not necessary. +#[derive(Clone, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen)] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub struct OwnerInfo { + /// The account that has deployed the contract and hence is allowed to remove it. + owner: AccountIdOf, + /// The amount of balance that was deposited by the owner in order to deploy it. + #[codec(compact)] + deposit: BalanceOf, + /// The number of contracts that use this as their code. + #[codec(compact)] + refcount: u64, } impl ExportedFunction { @@ -113,11 +115,43 @@ where T::AccountId: UncheckedFrom + AsRef<[u8]>, { /// Create the module by checking and instrumenting `original_code`. + /// + /// This does **not** store the module. For this one need to either call [`Self::store`] + /// or [`::execute`]. pub fn from_code( original_code: Vec, schedule: &Schedule, + owner: AccountIdOf, ) -> Result { - prepare::prepare_contract(original_code, schedule).map_err(Into::into) + prepare::prepare_contract(original_code, schedule, owner).map_err(Into::into) + } + + /// Store the code without instantiating it. + /// + /// Otherwise the code is stored when [`::execute`] is called. + pub fn store(self) -> DispatchResult { + code_cache::store(self, false) + } + + /// Remove the code from storage and refund the deposit to its owner. + /// + /// Applies all necessary checks before removing the code. + pub fn remove(origin: &T::AccountId, code_hash: CodeHash) -> DispatchResult { + code_cache::try_remove::(origin, code_hash) + } + + /// Returns whether there is a deposit to be payed for this module. + /// + /// Returns `0` if the module is already in storage and hence no deposit will + /// be charged when storing it. + pub fn open_deposit(&self) -> BalanceOf { + if >::contains_key(&self.code_hash) { + 0u32.into() + } else { + // Only already in-storage contracts have their `owner_info` set to `None`. + // Therefore it is correct to return `0` in this case. + self.owner_info.as_ref().map(|i| i.deposit).unwrap_or_default() + } } /// Create and store the module without checking nor instrumenting the passed code. @@ -125,22 +159,16 @@ where /// # Note /// /// This is useful for benchmarking where we don't want instrumentation to skew - /// our results. + /// our results. This also does not collect any deposit from the `owner`. #[cfg(feature = "runtime-benchmarks")] pub fn store_code_unchecked( original_code: Vec, schedule: &Schedule, - ) -> Result<(), DispatchError> { - let executable = prepare::benchmarking::prepare_contract(original_code, schedule) + owner: T::AccountId, + ) -> DispatchResult { + let executable = prepare::benchmarking::prepare_contract(original_code, schedule, owner) .map_err::(Into::into)?; - code_cache::store(executable); - Ok(()) - } - - /// Return the refcount of the module. - #[cfg(test)] - pub fn refcount(&self) -> u64 { - self.refcount + code_cache::store(executable, false) } /// Decrement instruction_weights_version by 1. Panics if it is already 0. @@ -150,6 +178,14 @@ where } } +impl OwnerInfo { + /// Return the refcount of the module. + #[cfg(test)] + pub fn refcount(&self) -> u64 { + self.refcount + } +} + impl Executable for PrefabWasmModule where T::AccountId: UncheckedFrom + AsRef<[u8]>, @@ -159,22 +195,11 @@ where schedule: &Schedule, gas_meter: &mut GasMeter, ) -> Result { - code_cache::load(code_hash, Some((schedule, gas_meter))) - } - - fn from_storage_noinstr(code_hash: CodeHash) -> Result { - code_cache::load(code_hash, None) + code_cache::load(code_hash, schedule, gas_meter) } - fn add_user(code_hash: CodeHash, gas_meter: &mut GasMeter) -> Result<(), DispatchError> { - code_cache::increment_refcount::(code_hash, gas_meter) - } - - fn remove_user( - code_hash: CodeHash, - gas_meter: &mut GasMeter, - ) -> Result<(), DispatchError> { - code_cache::decrement_refcount::(code_hash, gas_meter) + fn remove_user(code_hash: CodeHash) -> Result<(), DispatchError> { + code_cache::decrement_refcount::(code_hash) } fn execute>( @@ -200,16 +225,15 @@ where imports.add_host_func(module, name, func_ptr); }); - let mut runtime = Runtime::new(ext, input_data, memory); - // We store before executing so that the code hash is available in the constructor. let code = self.code.clone(); if let &ExportedFunction::Constructor = function { - code_cache::store(self) + code_cache::store(self, true)?; } // Instantiate the instance from the instrumented module code and invoke the contract // entrypoint. + let mut runtime = Runtime::new(ext, input_data, memory); let result = sp_sandbox::default_executor::Instance::new(&code, &imports, &mut runtime) .and_then(|mut instance| instance.invoke(function.identifier(), &[], &mut runtime)); @@ -223,14 +247,6 @@ where fn code_len(&self) -> u32 { self.code.len() as u32 } - - fn aggregate_code_len(&self) -> u32 { - self.original_code_len.saturating_add(self.code_len()) - } - - fn refcount(&self) -> u32 { - self.refcount as u32 - } } #[cfg(test)] @@ -260,7 +276,7 @@ mod tests { #[derive(Debug, PartialEq, Eq)] struct InstantiateEntry { code_hash: H256, - endowment: u64, + value: u64, data: Vec, gas_left: u64, salt: Vec, @@ -341,13 +357,13 @@ mod tests { &mut self, gas_limit: Weight, code_hash: CodeHash, - endowment: u64, + value: u64, data: Vec, salt: &[u8], ) -> Result<(AccountIdOf, ExecReturnValue), ExecError> { self.instantiates.push(InstantiateEntry { code_hash: code_hash.clone(), - endowment, + value, data: data.to_vec(), gas_left: gas_limit, salt: salt.to_vec(), @@ -390,9 +406,6 @@ mod tests { fn minimum_balance(&self) -> u64 { 666 } - fn contract_deposit(&self) -> u64 { - 16 - } fn random(&self, subject: &[u8]) -> (SeedOf, BlockNumberOf) { (H256::from_slice(subject), 42) } @@ -422,7 +435,6 @@ mod tests { self.runtime_calls.borrow_mut().push(call); Ok(Default::default()) } - fn ecdsa_recover( &self, signature: &[u8; 65], @@ -431,13 +443,16 @@ mod tests { self.ecdsa_recover.borrow_mut().push((signature.clone(), message_hash.clone())); Ok([3; 33]) } + fn contract_info(&mut self) -> &mut crate::ContractInfo { + unimplemented!() + } } fn execute>(wat: &str, input_data: Vec, mut ext: E) -> ExecResult { let wasm = wat::parse_str(wat).unwrap(); let schedule = crate::Schedule::default(); let executable = - PrefabWasmModule::<::T>::from_code(wasm, &schedule).unwrap(); + PrefabWasmModule::<::T>::from_code(wasm, &schedule, ALICE).unwrap(); executable.execute(ext.borrow_mut(), &ExportedFunction::Call, input_data) } @@ -761,7 +776,7 @@ mod tests { &mock_ext.instantiates[..], [InstantiateEntry { code_hash, - endowment: 3, + value: 3, data, gas_left: _, salt, @@ -1393,51 +1408,6 @@ mod tests { assert_ok!(execute(CODE_MINIMUM_BALANCE, vec![], MockExt::default())); } - const CODE_CONTRACT_DEPOSIT: &str = r#" -(module - (import "seal0" "seal_contract_deposit" (func $seal_contract_deposit (param i32 i32))) - (import "env" "memory" (memory 1 1)) - - ;; size of our buffer is 32 bytes - (data (i32.const 32) "\20") - - (func $assert (param i32) - (block $ok - (br_if $ok - (get_local 0) - ) - (unreachable) - ) - ) - - (func (export "call") - (call $seal_contract_deposit (i32.const 0) (i32.const 32)) - - ;; assert len == 8 - (call $assert - (i32.eq - (i32.load (i32.const 32)) - (i32.const 8) - ) - ) - - ;; assert that contents of the buffer is equal to the i64 value of 16. - (call $assert - (i64.eq - (i64.load (i32.const 0)) - (i64.const 16) - ) - ) - ) - (func (export "deploy")) -) -"#; - - #[test] - fn contract_deposit() { - assert_ok!(execute(CODE_CONTRACT_DEPOSIT, vec![], MockExt::default())); - } - const CODE_RANDOM: &str = r#" (module (import "seal0" "seal_random" (func $seal_random (param i32 i32 i32 i32))) diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index c766914f3d46e..6d13c097bd434 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -21,9 +21,11 @@ use crate::{ chain_extension::ChainExtension, - wasm::{env_def::ImportSatisfyCheck, PrefabWasmModule}, - Config, Schedule, + storage::meter::Diff, + wasm::{env_def::ImportSatisfyCheck, OwnerInfo, PrefabWasmModule}, + AccountIdOf, Config, Schedule, }; +use codec::{Encode, MaxEncodedLen}; use pwasm_utils::parity_wasm::elements::{self, External, Internal, MemoryType, Type, ValueType}; use sp_runtime::traits::Hash; use sp_std::prelude::*; @@ -395,20 +397,35 @@ fn check_and_instrument( fn do_preparation( original_code: Vec, schedule: &Schedule, + owner: AccountIdOf, ) -> Result, &'static str> { let (code, (initial, maximum)) = check_and_instrument::(original_code.as_ref(), schedule)?; - Ok(PrefabWasmModule { + let original_code_len = original_code.len(); + + let mut module = PrefabWasmModule { instruction_weights_version: schedule.instruction_weights.version, initial, maximum, - _reserved: None, code, - original_code_len: original_code.len() as u32, - refcount: 1, code_hash: T::Hashing::hash(&original_code), original_code: Some(original_code), - }) + owner_info: None, + }; + + // We need to add the sizes of the `#[codec(skip)]` fields which are stored in different + // storage items. This is also why we have `3` items added and not only one. + let bytes_added = module + .encoded_size() + .saturating_add(original_code_len) + .saturating_add(>::max_encoded_len()) as u32; + let deposit = Diff { bytes_added, items_added: 3, ..Default::default() } + .to_deposit::() + .charge_or_zero(); + + module.owner_info = Some(OwnerInfo { owner, deposit, refcount: 0 }); + + Ok(module) } /// Loads the given module given in `original_code`, performs some checks on it and @@ -425,8 +442,9 @@ fn do_preparation( pub fn prepare_contract( original_code: Vec, schedule: &Schedule, + owner: AccountIdOf, ) -> Result, &'static str> { - do_preparation::(original_code, schedule) + do_preparation::(original_code, schedule, owner) } /// The same as [`prepare_contract`] but without constructing a new [`PrefabWasmModule`] @@ -461,6 +479,7 @@ pub mod benchmarking { pub fn prepare_contract( original_code: Vec, schedule: &Schedule, + owner: AccountIdOf, ) -> Result, &'static str> { let contract_module = ContractModule::new(&original_code, schedule)?; let memory_limits = get_memory_limits(contract_module.scan_imports::<()>(&[])?, schedule)?; @@ -468,12 +487,15 @@ pub mod benchmarking { instruction_weights_version: schedule.instruction_weights.version, initial: memory_limits.0, maximum: memory_limits.1, - _reserved: None, code: contract_module.into_wasm_code()?, - original_code_len: original_code.len() as u32, - refcount: 1, code_hash: T::Hashing::hash(&original_code), original_code: Some(original_code), + owner_info: Some(OwnerInfo { + owner, + // this is a helper function for benchmarking which skips deposit collection + deposit: Default::default(), + refcount: 0, + }), }) } } @@ -481,10 +503,14 @@ pub mod benchmarking { #[cfg(test)] mod tests { use super::*; - use crate::{exec::Ext, schedule::Limits}; + use crate::{ + exec::Ext, + schedule::Limits, + tests::{Test, ALICE}, + }; use std::fmt; - impl fmt::Debug for PrefabWasmModule { + impl fmt::Debug for PrefabWasmModule { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "PreparedContract {{ .. }}") } @@ -526,7 +552,7 @@ mod tests { }, .. Default::default() }; - let r = do_preparation::(wasm, &schedule); + let r = do_preparation::(wasm, &schedule, ALICE); assert_matches::assert_matches!(r, $($expected)*); } }; diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 204db09ed3e8d..a7341e9e02e56 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -31,7 +31,7 @@ use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pwasm_utils::parity_wasm::elements::ValueType; use sp_core::{crypto::UncheckedFrom, Bytes}; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; -use sp_runtime::traits::Bounded; +use sp_runtime::traits::{Bounded, Zero}; use sp_sandbox::SandboxMemory; use sp_std::prelude::*; @@ -55,15 +55,12 @@ pub enum ReturnCode { CalleeReverted = 2, /// The passed key does not exist in storage. KeyNotFound = 3, - /// Transfer failed because it would have brought the sender's total balance below the - /// subsistence threshold. - BelowSubsistenceThreshold = 4, - /// Transfer failed for other reasons. Most probably reserved or locked balance of the - /// sender prevents the transfer. + /// Deprecated and no longer returned: There is only the minimum balance. + _BelowSubsistenceThreshold = 4, + /// See [`Error::TransferFailed`]. TransferFailed = 5, - /// The newly created contract is below the subsistence threshold after executing - /// its constructor. - NewContractNotFunded = 6, + /// Deprecated and no longer returned: Endowment is no longer required. + _EndowmentTooLow = 6, /// No code could be found at the supplied code hash. CodeNotFound = 7, /// The contract that was called is no contract (a plain account). @@ -151,8 +148,6 @@ pub enum RuntimeCosts { ValueTransferred, /// Weight of calling `seal_minimum_balance`. MinimumBalance, - /// Weight of calling `seal_contract_deposit`. - ContractDeposit, /// Weight of calling `seal_block_number`. BlockNumber, /// Weight of calling `seal_now`. @@ -231,7 +226,6 @@ impl RuntimeCosts { Balance => s.balance, ValueTransferred => s.value_transferred, MinimumBalance => s.minimum_balance, - ContractDeposit => s.contract_deposit, BlockNumber => s.block_number, Now => s.now, WeightToFee => s.weight_to_fee, @@ -611,16 +605,12 @@ where fn err_into_return_code(from: DispatchError) -> Result { use ReturnCode::*; - let below_sub = Error::::BelowSubsistenceThreshold.into(); let transfer_failed = Error::::TransferFailed.into(); - let not_funded = Error::::NewContractNotFunded.into(); let no_code = Error::::CodeNotFound.into(); let not_found = Error::::ContractNotFound.into(); match from { - x if x == below_sub => Ok(BelowSubsistenceThreshold), x if x == transfer_failed => Ok(TransferFailed), - x if x == not_funded => Ok(NewContractNotFunded), x if x == no_code => Ok(CodeNotFound), x if x == not_found => Ok(NotCallable), err => Err(err), @@ -837,7 +827,6 @@ define_env!(Env, , // // # Errors // - // `ReturnCode::BelowSubsistenceThreshold` // `ReturnCode::TransferFailed` [seal0] seal_transfer( ctx, @@ -925,7 +914,6 @@ define_env!(Env, , // // `ReturnCode::CalleeReverted`: Output buffer is returned. // `ReturnCode::CalleeTrapped` - // `ReturnCode::BelowSubsistenceThreshold` // `ReturnCode::TransferFailed` // `ReturnCode::NotCallable` [seal1] seal_call( @@ -1002,9 +990,8 @@ define_env!(Env, , // length to `output_len_ptr`. The copy of the output buffer and address can be skipped by // supplying the sentinel value of `u32::MAX` to `output_ptr` or `address_ptr`. // - // After running the constructor it is verified that the contract account holds at - // least the subsistence threshold. If that is not the case the instantiation fails and - // the contract is not created. + // `value` must be at least the minimum balance. Otherwise the instantiation fails and the + // contract is not created. // // # Parameters // @@ -1033,9 +1020,7 @@ define_env!(Env, , // // `ReturnCode::CalleeReverted`: Output buffer is returned. // `ReturnCode::CalleeTrapped` - // `ReturnCode::BelowSubsistenceThreshold` // `ReturnCode::TransferFailed` - // `ReturnCode::NewContractNotFunded` // `ReturnCode::CodeNotFound` [seal1] seal_instantiate( ctx, @@ -1082,7 +1067,7 @@ define_env!(Env, , ctx.terminate(beneficiary_ptr) }, - // Remove the calling account and transfer remaining balance. + // Remove the calling account and transfer remaining **free** balance. // // This function never returns. Either the termination was successful and the // execution of the destroyed contract is halted. Or it failed during the termination @@ -1215,7 +1200,7 @@ define_env!(Env, , )?) }, - // Stores the balance of the current account into the supplied buffer. + // Stores the **free* balance of the current account into the supplied buffer. // // The value is stored to linear memory at the address pointed to by `out_ptr`. // `out_len_ptr` must point to a u32 value that describes the available space at @@ -1230,7 +1215,7 @@ define_env!(Env, , )?) }, - // Stores the value transferred along with this call or as endowment into the supplied buffer. + // Stores the value transferred along with this call/instantiate into the supplied buffer. // // The value is stored to linear memory at the address pointed to by `out_ptr`. // `out_len_ptr` must point to a u32 value that describes the available space at @@ -1323,38 +1308,20 @@ define_env!(Env, , )?) }, - // Stores the contract deposit into the supplied buffer. - // - // # Deprecation - // - // This is equivalent to calling `seal_contract_deposit` and only exists for backwards - // compatibility. See that function for documentation. - [seal0] seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeCosts::ContractDeposit)?; - Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.contract_deposit().encode(), false, already_charged - )?) - }, - - // Stores the contract deposit into the supplied buffer. + // Stores the tombstone deposit into the supplied buffer. // // The value is stored to linear memory at the address pointed to by `out_ptr`. // `out_len_ptr` must point to a u32 value that describes the available space at // `out_ptr`. This call overwrites it with the size of the value. If the available // space at `out_ptr` is less than the size of the value a trap is triggered. // - // The data is encoded as T::Balance. - // - // # Note + // # Deprecation // - // The contract deposit is on top of the existential deposit. The sum - // is commonly referred as subsistence threshold in code. No contract initiated - // balance transfer can go below this threshold. - [seal0] seal_contract_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeCosts::ContractDeposit)?; - Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.contract_deposit().encode(), false, already_charged - )?) + // There is no longer a tombstone deposit. This function always returns 0. + [seal0] seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => { + ctx.charge_gas(RuntimeCosts::Balance)?; + let deposit = >::zero().encode(); + Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, &deposit, false, already_charged)?) }, // Was used to restore the given destination contract sacrificing the caller. diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 4b6c40764ad0a..504ee9ebde03a 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-10-28, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-11-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -35,7 +35,6 @@ // --output=./frame/contracts/src/weights.rs // --template=./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -50,17 +49,17 @@ pub trait WeightInfo { fn on_initialize_per_queue_item(q: u32, ) -> Weight; fn instrument(c: u32, ) -> Weight; fn code_load(c: u32, ) -> Weight; - fn code_refcount(c: u32, ) -> Weight; fn instantiate_with_code(c: u32, s: u32, ) -> Weight; fn instantiate(s: u32, ) -> Weight; fn call() -> Weight; + fn upload_code(c: u32, ) -> Weight; + fn remove_code() -> Weight; fn seal_caller(r: u32, ) -> Weight; fn seal_address(r: u32, ) -> Weight; fn seal_gas_left(r: u32, ) -> Weight; fn seal_balance(r: u32, ) -> Weight; fn seal_value_transferred(r: u32, ) -> Weight; fn seal_minimum_balance(r: u32, ) -> Weight; - fn seal_tombstone_deposit(r: u32, ) -> Weight; fn seal_block_number(r: u32, ) -> Weight; fn seal_now(r: u32, ) -> Weight; fn seal_weight_to_fee(r: u32, ) -> Weight; @@ -151,761 +150,792 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (2_987_000 as Weight) + (2_832_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_000 - .saturating_add((2_201_000 as Weight).saturating_mul(k as Weight)) + // Standard Error: 3_000 + .saturating_add((2_197_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (97_470_000 as Weight) + (92_378_000 as Weight) // Standard Error: 2_000 - .saturating_add((322_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((328_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn instrument(c: u32, ) -> Weight { - (28_804_000 as Weight) - // Standard Error: 84_000 - .saturating_add((71_838_000 as Weight).saturating_mul(c as Weight)) + (27_381_000 as Weight) + // Standard Error: 92_000 + .saturating_add((90_220_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:0) fn code_load(c: u32, ) -> Weight { - (5_658_000 as Weight) + (7_710_000 as Weight) // Standard Error: 0 - .saturating_add((1_425_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((1_457_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) - fn code_refcount(c: u32, ) -> Weight { - (9_001_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_281_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) - // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) + // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (499_349_000 as Weight) - // Standard Error: 199_000 - .saturating_add((174_439_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 13_000 - .saturating_add((2_096_000 as Weight).saturating_mul(s as Weight)) + (559_294_000 as Weight) + // Standard Error: 171_000 + .saturating_add((206_170_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 11_000 + .saturating_add((2_107_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (181_151_000 as Weight) + (236_193_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_025_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add((2_022_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (153_830_000 as Weight) + (189_193_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Contracts CodeStorage (r:1 w:1) + // Storage: Contracts PristineCode (r:0 w:1) + // Storage: Contracts OwnerInfoOf (r:0 w:1) + fn upload_code(c: u32, ) -> Weight { + (79_753_000 as Weight) + // Standard Error: 98_000 + .saturating_add((90_928_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:0 w:1) + // Storage: Contracts PristineCode (r:0 w:1) + fn remove_code() -> Weight { + (40_206_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (423_222_000 as Weight) - // Standard Error: 169_000 - .saturating_add((114_763_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (464_937_000 as Weight) + // Standard Error: 182_000 + .saturating_add((112_166_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (420_731_000 as Weight) - // Standard Error: 165_000 - .saturating_add((115_213_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (464_387_000 as Weight) + // Standard Error: 155_000 + .saturating_add((112_307_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (422_407_000 as Weight) - // Standard Error: 176_000 - .saturating_add((113_935_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (462_005_000 as Weight) + // Standard Error: 185_000 + .saturating_add((111_402_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System Account (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (425_698_000 as Weight) - // Standard Error: 210_000 - .saturating_add((335_171_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (468_139_000 as Weight) + // Standard Error: 192_000 + .saturating_add((317_634_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (410_218_000 as Weight) - // Standard Error: 187_000 - .saturating_add((115_360_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (447_610_000 as Weight) + // Standard Error: 196_000 + .saturating_add((112_915_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (402_765_000 as Weight) - // Standard Error: 169_000 - .saturating_add((116_553_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - // Storage: Contracts ContractInfoOf (r:1 w:1) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - fn seal_tombstone_deposit(r: u32, ) -> Weight { - (404_817_000 as Weight) - // Standard Error: 173_000 - .saturating_add((115_894_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (450_012_000 as Weight) + // Standard Error: 167_000 + .saturating_add((112_311_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (405_604_000 as Weight) - // Standard Error: 193_000 - .saturating_add((115_757_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (453_687_000 as Weight) + // Standard Error: 185_000 + .saturating_add((111_902_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (413_577_000 as Weight) - // Standard Error: 166_000 - .saturating_add((115_115_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (453_283_000 as Weight) + // Standard Error: 162_000 + .saturating_add((112_543_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (413_932_000 as Weight) - // Standard Error: 201_000 - .saturating_add((272_742_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (454_171_000 as Weight) + // Standard Error: 205_000 + .saturating_add((267_487_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (144_109_000 as Weight) - // Standard Error: 96_000 - .saturating_add((52_461_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (190_254_000 as Weight) + // Standard Error: 116_000 + .saturating_add((51_037_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (422_584_000 as Weight) - // Standard Error: 158_000 - .saturating_add((98_316_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (460_590_000 as Weight) + // Standard Error: 173_000 + .saturating_add((99_887_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (549_530_000 as Weight) - // Standard Error: 8_000 - .saturating_add((38_025_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (616_346_000 as Weight) + // Standard Error: 9_000 + .saturating_add((38_016_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(r: u32, ) -> Weight { - (403_711_000 as Weight) - // Standard Error: 114_000 - .saturating_add((2_996_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + fn seal_return(_r: u32, ) -> Weight { + (447_340_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (408_252_000 as Weight) + (452_105_000 as Weight) // Standard Error: 1_000 - .saturating_add((630_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add((633_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts DeletionQueue (r:1 w:1) - // Storage: System Account (r:2 w:2) + // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (412_619_000 as Weight) - // Standard Error: 896_000 - .saturating_add((66_155_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (456_662_000 as Weight) + // Standard Error: 2_550_000 + .saturating_add((71_297_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(r as Weight))) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (416_604_000 as Weight) - // Standard Error: 274_000 - .saturating_add((366_304_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (460_302_000 as Weight) + // Standard Error: 223_000 + .saturating_add((351_206_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (417_326_000 as Weight) - // Standard Error: 457_000 - .saturating_add((640_211_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (456_800_000 as Weight) + // Standard Error: 413_000 + .saturating_add((574_183_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_121_348_000 as Weight) - // Standard Error: 2_483_000 - .saturating_add((463_498_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 489_000 - .saturating_add((167_147_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) + (1_099_926_000 as Weight) + // Standard Error: 2_170_000 + .saturating_add((461_522_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 427_000 + .saturating_add((164_778_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(t as Weight))) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (159_880_000 as Weight) - // Standard Error: 138_000 - .saturating_add((67_837_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (208_518_000 as Weight) + // Standard Error: 131_000 + .saturating_add((70_862_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (389_400_000 as Weight) - // Standard Error: 239_000 - .saturating_add((238_933_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (492_961_000 as Weight) + // Standard Error: 506_000 + .saturating_add((373_157_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } + // Storage: System Account (r:2 w:2) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:0 w:1) + // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (611_980_000 as Weight) - // Standard Error: 234_000 - .saturating_add((72_047_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + (793_894_000 as Weight) + // Standard Error: 250_000 + .saturating_add((74_081_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (436_588_000 as Weight) - // Standard Error: 222_000 - .saturating_add((209_734_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (214_581_000 as Weight) + // Standard Error: 1_604_000 + .saturating_add((844_938_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (285_689_000 as Weight) - // Standard Error: 742_000 - .saturating_add((496_745_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) + (328_005_000 as Weight) + // Standard Error: 753_000 + .saturating_add((493_893_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (693_967_000 as Weight) - // Standard Error: 226_000 - .saturating_add((111_370_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (736_348_000 as Weight) + // Standard Error: 232_000 + .saturating_add((110_871_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System Account (r:101 w:101) fn seal_transfer(r: u32, ) -> Weight { - (332_032_000 as Weight) - // Standard Error: 2_537_000 - .saturating_add((4_071_041_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + (346_206_000 as Weight) + // Standard Error: 1_888_000 + .saturating_add((3_729_835_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 10_806_000 - .saturating_add((39_442_275_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + // Standard Error: 11_456_000 + .saturating_add((39_404_197_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System Account (r:101 w:101) - fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (38_600_435_000 as Weight) - // Standard Error: 53_014_000 - .saturating_add((3_392_887_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 18_000 - .saturating_add((63_348_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 20_000 - .saturating_add((101_366_000 as Weight).saturating_mul(o as Weight)) - .saturating_add(T::DbWeight::get().reads(104 as Weight)) - .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) - .saturating_add(T::DbWeight::get().writes(101 as Weight)) - .saturating_add(T::DbWeight::get().writes((101 as Weight).saturating_mul(t as Weight))) + fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, _o: u32, ) -> Weight { + (136_101_024_000 as Weight) + // Standard Error: 6_000 + .saturating_add((62_954_000 as Weight).saturating_mul(i as Weight)) + .saturating_add(T::DbWeight::get().reads(105 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) + .saturating_add(T::DbWeight::get().writes(102 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts AccountCounter (r:1 w:1) - // Storage: System Account (r:101 w:101) + // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { - (643_999_000 as Weight) - // Standard Error: 37_244_000 - .saturating_add((45_559_839_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((300 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - .saturating_add(T::DbWeight::get().writes((300 as Weight).saturating_mul(r as Weight))) + (0 as Weight) + // Standard Error: 47_948_000 + .saturating_add((48_494_963_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(T::DbWeight::get().writes((400 as Weight).saturating_mul(r as Weight))) } + // Storage: System Account (r:102 w:102) // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts AccountCounter (r:1 w:1) - // Storage: System Account (r:101 w:101) + // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (45_415_035_000 as Weight) - // Standard Error: 30_000 - .saturating_add((63_567_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 30_000 - .saturating_add((100_900_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 30_000 - .saturating_add((201_139_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(206 as Weight)) - .saturating_add(T::DbWeight::get().writes(204 as Weight)) + (45_566_426_000 as Weight) + // Standard Error: 50_000 + .saturating_add((63_809_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 50_000 + .saturating_add((101_448_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 50_000 + .saturating_add((201_652_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(208 as Weight)) + .saturating_add(T::DbWeight::get().writes(206 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (417_335_000 as Weight) - // Standard Error: 174_000 - .saturating_add((126_268_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (457_229_000 as Weight) + // Standard Error: 197_000 + .saturating_add((124_742_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (700_565_000 as Weight) - // Standard Error: 68_000 - .saturating_add((499_898_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (586_056_000 as Weight) + // Standard Error: 30_000 + .saturating_add((505_871_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (416_014_000 as Weight) - // Standard Error: 168_000 - .saturating_add((134_320_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (458_528_000 as Weight) + // Standard Error: 154_000 + .saturating_add((137_710_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (534_466_000 as Weight) + (573_132_000 as Weight) // Standard Error: 19_000 - .saturating_add((346_588_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add((363_983_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (414_278_000 as Weight) - // Standard Error: 164_000 - .saturating_add((106_210_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (456_881_000 as Weight) + // Standard Error: 187_000 + .saturating_add((106_987_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (569_659_000 as Weight) - // Standard Error: 16_000 - .saturating_add((163_989_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (587_192_000 as Weight) + // Standard Error: 17_000 + .saturating_add((164_114_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (421_251_000 as Weight) - // Standard Error: 166_000 - .saturating_add((104_678_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (457_938_000 as Weight) + // Standard Error: 184_000 + .saturating_add((105_658_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (568_490_000 as Weight) - // Standard Error: 21_000 - .saturating_add((163_999_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (567_129_000 as Weight) + // Standard Error: 16_000 + .saturating_add((164_146_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (361_122_000 as Weight) - // Standard Error: 1_172_000 - .saturating_add((15_591_590_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (426_602_000 as Weight) + // Standard Error: 1_393_000 + .saturating_add((15_587_531_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (46_003_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_185_000 as Weight).saturating_mul(r as Weight)) + (39_689_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (42_908_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_570_000 as Weight).saturating_mul(r as Weight)) + (45_362_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_665_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (42_739_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_791_000 as Weight).saturating_mul(r as Weight)) + (45_514_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_696_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (47_543_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_834_000 as Weight).saturating_mul(r as Weight)) + (45_931_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_919_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (50_540_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_663_000 as Weight).saturating_mul(r as Weight)) + (46_362_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_942_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (47_732_000 as Weight) - // Standard Error: 8_000 - .saturating_add((1_771_000 as Weight).saturating_mul(r as Weight)) + (44_648_000 as Weight) + // Standard Error: 15_000 + .saturating_add((1_856_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (49_005_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_072_000 as Weight).saturating_mul(r as Weight)) + (45_989_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_418_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (45_975_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) + (48_883_000 as Weight) + // Standard Error: 18_000 + .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) } - fn instr_br_table_per_entry(_e: u32, ) -> Weight { - (55_461_000 as Weight) + fn instr_br_table_per_entry(e: u32, ) -> Weight { + (48_685_000 as Weight) + // Standard Error: 2_000 + .saturating_add((39_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (41_932_000 as Weight) - // Standard Error: 29_000 - .saturating_add((19_800_000 as Weight).saturating_mul(r as Weight)) + (50_428_000 as Weight) + // Standard Error: 24_000 + .saturating_add((20_121_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (56_550_000 as Weight) - // Standard Error: 34_000 - .saturating_add((28_414_000 as Weight).saturating_mul(r as Weight)) + (54_899_000 as Weight) + // Standard Error: 32_000 + .saturating_add((29_588_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (93_172_000 as Weight) - // Standard Error: 6_000 - .saturating_add((1_018_000 as Weight).saturating_mul(p as Weight)) + (92_176_000 as Weight) + // Standard Error: 5_000 + .saturating_add((989_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (54_603_000 as Weight) - // Standard Error: 14_000 - .saturating_add((764_000 as Weight).saturating_mul(r as Weight)) + (48_130_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_194_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (54_763_000 as Weight) - // Standard Error: 14_000 - .saturating_add((878_000 as Weight).saturating_mul(r as Weight)) + (47_550_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_244_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (56_137_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_194_000 as Weight).saturating_mul(r as Weight)) + (48_806_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_757_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (69_513_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_125_000 as Weight).saturating_mul(r as Weight)) + (62_369_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_779_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (69_120_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_215_000 as Weight).saturating_mul(r as Weight)) + (61_063_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_751_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (46_021_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_103_000 as Weight).saturating_mul(r as Weight)) + (39_781_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (52_245_000 as Weight) - // Standard Error: 4_119_000 - .saturating_add((619_498_000 as Weight).saturating_mul(r as Weight)) + (50_983_000 as Weight) + // Standard Error: 4_238_000 + .saturating_add((618_956_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (47_314_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_720_000 as Weight).saturating_mul(r as Weight)) + (42_490_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_937_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (47_855_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_701_000 as Weight).saturating_mul(r as Weight)) + (42_296_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_943_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (47_704_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_708_000 as Weight).saturating_mul(r as Weight)) + (42_263_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_944_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (47_656_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_705_000 as Weight).saturating_mul(r as Weight)) + (42_087_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_952_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (55_202_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_229_000 as Weight).saturating_mul(r as Weight)) + (48_024_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (55_193_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_223_000 as Weight).saturating_mul(r as Weight)) + (48_056_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_780_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (48_125_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_704_000 as Weight).saturating_mul(r as Weight)) + (42_352_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (49_162_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_241_000 as Weight).saturating_mul(r as Weight)) + (45_439_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_382_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (48_635_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_262_000 as Weight).saturating_mul(r as Weight)) + (45_232_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_393_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (48_550_000 as Weight) - // Standard Error: 9_000 - .saturating_add((2_267_000 as Weight).saturating_mul(r as Weight)) + (45_351_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_386_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (49_135_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_219_000 as Weight).saturating_mul(r as Weight)) + (45_448_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_385_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (49_638_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_206_000 as Weight).saturating_mul(r as Weight)) + (45_275_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_386_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (49_889_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_201_000 as Weight).saturating_mul(r as Weight)) + (45_180_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_396_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (49_763_000 as Weight) - // Standard Error: 9_000 - .saturating_add((2_210_000 as Weight).saturating_mul(r as Weight)) + (45_396_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_400_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (49_607_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_207_000 as Weight).saturating_mul(r as Weight)) + (45_597_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_392_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (49_664_000 as Weight) - // Standard Error: 9_000 - .saturating_add((2_213_000 as Weight).saturating_mul(r as Weight)) + (45_137_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_400_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (49_718_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_206_000 as Weight).saturating_mul(r as Weight)) + (45_091_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_401_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (49_513_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_208_000 as Weight).saturating_mul(r as Weight)) + (45_547_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_380_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (49_837_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_201_000 as Weight).saturating_mul(r as Weight)) + (45_435_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_383_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (49_684_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_210_000 as Weight).saturating_mul(r as Weight)) + (45_244_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_389_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (48_749_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_872_000 as Weight).saturating_mul(r as Weight)) + (45_253_000 as Weight) + // Standard Error: 11_000 + .saturating_add((3_046_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (49_134_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_630_000 as Weight).saturating_mul(r as Weight)) + (45_339_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_711_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (48_981_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_861_000 as Weight).saturating_mul(r as Weight)) + (45_312_000 as Weight) + // Standard Error: 11_000 + .saturating_add((3_020_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (49_195_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_593_000 as Weight).saturating_mul(r as Weight)) + (45_397_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_739_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (49_304_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_238_000 as Weight).saturating_mul(r as Weight)) + (45_282_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_387_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (48_636_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_259_000 as Weight).saturating_mul(r as Weight)) + (45_508_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_390_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (48_761_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_262_000 as Weight).saturating_mul(r as Weight)) + (45_089_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_397_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (48_492_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_263_000 as Weight).saturating_mul(r as Weight)) + (45_878_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_395_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (48_736_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_256_000 as Weight).saturating_mul(r as Weight)) + (45_459_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_401_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (48_675_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_256_000 as Weight).saturating_mul(r as Weight)) + (45_663_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_398_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (48_703_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_257_000 as Weight).saturating_mul(r as Weight)) + (45_739_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_393_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (48_758_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_259_000 as Weight).saturating_mul(r as Weight)) + (45_290_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_392_000 as Weight).saturating_mul(r as Weight)) } } @@ -913,760 +943,791 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (2_987_000 as Weight) + (2_832_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_000 - .saturating_add((2_201_000 as Weight).saturating_mul(k as Weight)) + // Standard Error: 3_000 + .saturating_add((2_197_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (97_470_000 as Weight) + (92_378_000 as Weight) // Standard Error: 2_000 - .saturating_add((322_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((328_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn instrument(c: u32, ) -> Weight { - (28_804_000 as Weight) - // Standard Error: 84_000 - .saturating_add((71_838_000 as Weight).saturating_mul(c as Weight)) + (27_381_000 as Weight) + // Standard Error: 92_000 + .saturating_add((90_220_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:0) fn code_load(c: u32, ) -> Weight { - (5_658_000 as Weight) + (7_710_000 as Weight) // Standard Error: 0 - .saturating_add((1_425_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((1_457_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) - fn code_refcount(c: u32, ) -> Weight { - (9_001_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_281_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - } // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) - // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) + // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (499_349_000 as Weight) - // Standard Error: 199_000 - .saturating_add((174_439_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 13_000 - .saturating_add((2_096_000 as Weight).saturating_mul(s as Weight)) + (559_294_000 as Weight) + // Standard Error: 171_000 + .saturating_add((206_170_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 11_000 + .saturating_add((2_107_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (181_151_000 as Weight) + (236_193_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_025_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add((2_022_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (153_830_000 as Weight) + (189_193_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: Contracts CodeStorage (r:1 w:1) + // Storage: Contracts PristineCode (r:0 w:1) + // Storage: Contracts OwnerInfoOf (r:0 w:1) + fn upload_code(c: u32, ) -> Weight { + (79_753_000 as Weight) + // Standard Error: 98_000 + .saturating_add((90_928_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:0 w:1) + // Storage: Contracts PristineCode (r:0 w:1) + fn remove_code() -> Weight { + (40_206_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (423_222_000 as Weight) - // Standard Error: 169_000 - .saturating_add((114_763_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (464_937_000 as Weight) + // Standard Error: 182_000 + .saturating_add((112_166_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (420_731_000 as Weight) - // Standard Error: 165_000 - .saturating_add((115_213_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (464_387_000 as Weight) + // Standard Error: 155_000 + .saturating_add((112_307_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (422_407_000 as Weight) - // Standard Error: 176_000 - .saturating_add((113_935_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (462_005_000 as Weight) + // Standard Error: 185_000 + .saturating_add((111_402_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System Account (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (425_698_000 as Weight) - // Standard Error: 210_000 - .saturating_add((335_171_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (468_139_000 as Weight) + // Standard Error: 192_000 + .saturating_add((317_634_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (410_218_000 as Weight) - // Standard Error: 187_000 - .saturating_add((115_360_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (447_610_000 as Weight) + // Standard Error: 196_000 + .saturating_add((112_915_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (402_765_000 as Weight) - // Standard Error: 169_000 - .saturating_add((116_553_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - } - // Storage: Contracts ContractInfoOf (r:1 w:1) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - fn seal_tombstone_deposit(r: u32, ) -> Weight { - (404_817_000 as Weight) - // Standard Error: 173_000 - .saturating_add((115_894_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (450_012_000 as Weight) + // Standard Error: 167_000 + .saturating_add((112_311_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (405_604_000 as Weight) - // Standard Error: 193_000 - .saturating_add((115_757_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (453_687_000 as Weight) + // Standard Error: 185_000 + .saturating_add((111_902_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (413_577_000 as Weight) - // Standard Error: 166_000 - .saturating_add((115_115_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (453_283_000 as Weight) + // Standard Error: 162_000 + .saturating_add((112_543_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (413_932_000 as Weight) - // Standard Error: 201_000 - .saturating_add((272_742_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (454_171_000 as Weight) + // Standard Error: 205_000 + .saturating_add((267_487_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (144_109_000 as Weight) - // Standard Error: 96_000 - .saturating_add((52_461_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (190_254_000 as Weight) + // Standard Error: 116_000 + .saturating_add((51_037_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (422_584_000 as Weight) - // Standard Error: 158_000 - .saturating_add((98_316_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (460_590_000 as Weight) + // Standard Error: 173_000 + .saturating_add((99_887_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (549_530_000 as Weight) - // Standard Error: 8_000 - .saturating_add((38_025_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (616_346_000 as Weight) + // Standard Error: 9_000 + .saturating_add((38_016_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(r: u32, ) -> Weight { - (403_711_000 as Weight) - // Standard Error: 114_000 - .saturating_add((2_996_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + fn seal_return(_r: u32, ) -> Weight { + (447_340_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (408_252_000 as Weight) + (452_105_000 as Weight) // Standard Error: 1_000 - .saturating_add((630_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add((633_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts DeletionQueue (r:1 w:1) - // Storage: System Account (r:2 w:2) + // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (412_619_000 as Weight) - // Standard Error: 896_000 - .saturating_add((66_155_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (456_662_000 as Weight) + // Standard Error: 2_550_000 + .saturating_add((71_297_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(r as Weight))) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (416_604_000 as Weight) - // Standard Error: 274_000 - .saturating_add((366_304_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (460_302_000 as Weight) + // Standard Error: 223_000 + .saturating_add((351_206_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (417_326_000 as Weight) - // Standard Error: 457_000 - .saturating_add((640_211_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (456_800_000 as Weight) + // Standard Error: 413_000 + .saturating_add((574_183_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_121_348_000 as Weight) - // Standard Error: 2_483_000 - .saturating_add((463_498_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 489_000 - .saturating_add((167_147_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + (1_099_926_000 as Weight) + // Standard Error: 2_170_000 + .saturating_add((461_522_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 427_000 + .saturating_add((164_778_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(t as Weight))) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (159_880_000 as Weight) - // Standard Error: 138_000 - .saturating_add((67_837_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (208_518_000 as Weight) + // Standard Error: 131_000 + .saturating_add((70_862_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (389_400_000 as Weight) - // Standard Error: 239_000 - .saturating_add((238_933_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (492_961_000 as Weight) + // Standard Error: 506_000 + .saturating_add((373_157_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } + // Storage: System Account (r:2 w:2) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:0 w:1) + // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (611_980_000 as Weight) - // Standard Error: 234_000 - .saturating_add((72_047_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + (793_894_000 as Weight) + // Standard Error: 250_000 + .saturating_add((74_081_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (436_588_000 as Weight) - // Standard Error: 222_000 - .saturating_add((209_734_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (214_581_000 as Weight) + // Standard Error: 1_604_000 + .saturating_add((844_938_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (285_689_000 as Weight) - // Standard Error: 742_000 - .saturating_add((496_745_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + (328_005_000 as Weight) + // Standard Error: 753_000 + .saturating_add((493_893_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (693_967_000 as Weight) - // Standard Error: 226_000 - .saturating_add((111_370_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (736_348_000 as Weight) + // Standard Error: 232_000 + .saturating_add((110_871_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System Account (r:101 w:101) fn seal_transfer(r: u32, ) -> Weight { - (332_032_000 as Weight) - // Standard Error: 2_537_000 - .saturating_add((4_071_041_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + (346_206_000 as Weight) + // Standard Error: 1_888_000 + .saturating_add((3_729_835_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 10_806_000 - .saturating_add((39_442_275_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + // Standard Error: 11_456_000 + .saturating_add((39_404_197_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System Account (r:101 w:101) - fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (38_600_435_000 as Weight) - // Standard Error: 53_014_000 - .saturating_add((3_392_887_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 18_000 - .saturating_add((63_348_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 20_000 - .saturating_add((101_366_000 as Weight).saturating_mul(o as Weight)) - .saturating_add(RocksDbWeight::get().reads(104 as Weight)) - .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) - .saturating_add(RocksDbWeight::get().writes(101 as Weight)) - .saturating_add(RocksDbWeight::get().writes((101 as Weight).saturating_mul(t as Weight))) + fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, _o: u32, ) -> Weight { + (136_101_024_000 as Weight) + // Standard Error: 6_000 + .saturating_add((62_954_000 as Weight).saturating_mul(i as Weight)) + .saturating_add(RocksDbWeight::get().reads(105 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) + .saturating_add(RocksDbWeight::get().writes(102 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts AccountCounter (r:1 w:1) - // Storage: System Account (r:101 w:101) + // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { - (643_999_000 as Weight) - // Standard Error: 37_244_000 - .saturating_add((45_559_839_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((300 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes((300 as Weight).saturating_mul(r as Weight))) + (0 as Weight) + // Standard Error: 47_948_000 + .saturating_add((48_494_963_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes((400 as Weight).saturating_mul(r as Weight))) } + // Storage: System Account (r:102 w:102) // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts AccountCounter (r:1 w:1) - // Storage: System Account (r:101 w:101) + // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (45_415_035_000 as Weight) - // Standard Error: 30_000 - .saturating_add((63_567_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 30_000 - .saturating_add((100_900_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 30_000 - .saturating_add((201_139_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(206 as Weight)) - .saturating_add(RocksDbWeight::get().writes(204 as Weight)) + (45_566_426_000 as Weight) + // Standard Error: 50_000 + .saturating_add((63_809_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 50_000 + .saturating_add((101_448_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 50_000 + .saturating_add((201_652_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(208 as Weight)) + .saturating_add(RocksDbWeight::get().writes(206 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (417_335_000 as Weight) - // Standard Error: 174_000 - .saturating_add((126_268_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (457_229_000 as Weight) + // Standard Error: 197_000 + .saturating_add((124_742_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (700_565_000 as Weight) - // Standard Error: 68_000 - .saturating_add((499_898_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (586_056_000 as Weight) + // Standard Error: 30_000 + .saturating_add((505_871_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (416_014_000 as Weight) - // Standard Error: 168_000 - .saturating_add((134_320_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (458_528_000 as Weight) + // Standard Error: 154_000 + .saturating_add((137_710_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (534_466_000 as Weight) + (573_132_000 as Weight) // Standard Error: 19_000 - .saturating_add((346_588_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add((363_983_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (414_278_000 as Weight) - // Standard Error: 164_000 - .saturating_add((106_210_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (456_881_000 as Weight) + // Standard Error: 187_000 + .saturating_add((106_987_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (569_659_000 as Weight) - // Standard Error: 16_000 - .saturating_add((163_989_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (587_192_000 as Weight) + // Standard Error: 17_000 + .saturating_add((164_114_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (421_251_000 as Weight) - // Standard Error: 166_000 - .saturating_add((104_678_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (457_938_000 as Weight) + // Standard Error: 184_000 + .saturating_add((105_658_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (568_490_000 as Weight) - // Standard Error: 21_000 - .saturating_add((163_999_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (567_129_000 as Weight) + // Standard Error: 16_000 + .saturating_add((164_146_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (361_122_000 as Weight) - // Standard Error: 1_172_000 - .saturating_add((15_591_590_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (426_602_000 as Weight) + // Standard Error: 1_393_000 + .saturating_add((15_587_531_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (46_003_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_185_000 as Weight).saturating_mul(r as Weight)) + (39_689_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (42_908_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_570_000 as Weight).saturating_mul(r as Weight)) + (45_362_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_665_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (42_739_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_791_000 as Weight).saturating_mul(r as Weight)) + (45_514_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_696_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (47_543_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_834_000 as Weight).saturating_mul(r as Weight)) + (45_931_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_919_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (50_540_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_663_000 as Weight).saturating_mul(r as Weight)) + (46_362_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_942_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (47_732_000 as Weight) - // Standard Error: 8_000 - .saturating_add((1_771_000 as Weight).saturating_mul(r as Weight)) + (44_648_000 as Weight) + // Standard Error: 15_000 + .saturating_add((1_856_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (49_005_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_072_000 as Weight).saturating_mul(r as Weight)) + (45_989_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_418_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (45_975_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) + (48_883_000 as Weight) + // Standard Error: 18_000 + .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) } - fn instr_br_table_per_entry(_e: u32, ) -> Weight { - (55_461_000 as Weight) + fn instr_br_table_per_entry(e: u32, ) -> Weight { + (48_685_000 as Weight) + // Standard Error: 2_000 + .saturating_add((39_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (41_932_000 as Weight) - // Standard Error: 29_000 - .saturating_add((19_800_000 as Weight).saturating_mul(r as Weight)) + (50_428_000 as Weight) + // Standard Error: 24_000 + .saturating_add((20_121_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (56_550_000 as Weight) - // Standard Error: 34_000 - .saturating_add((28_414_000 as Weight).saturating_mul(r as Weight)) + (54_899_000 as Weight) + // Standard Error: 32_000 + .saturating_add((29_588_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (93_172_000 as Weight) - // Standard Error: 6_000 - .saturating_add((1_018_000 as Weight).saturating_mul(p as Weight)) + (92_176_000 as Weight) + // Standard Error: 5_000 + .saturating_add((989_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (54_603_000 as Weight) - // Standard Error: 14_000 - .saturating_add((764_000 as Weight).saturating_mul(r as Weight)) + (48_130_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_194_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (54_763_000 as Weight) - // Standard Error: 14_000 - .saturating_add((878_000 as Weight).saturating_mul(r as Weight)) + (47_550_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_244_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (56_137_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_194_000 as Weight).saturating_mul(r as Weight)) + (48_806_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_757_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (69_513_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_125_000 as Weight).saturating_mul(r as Weight)) + (62_369_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_779_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (69_120_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_215_000 as Weight).saturating_mul(r as Weight)) + (61_063_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_751_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (46_021_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_103_000 as Weight).saturating_mul(r as Weight)) + (39_781_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (52_245_000 as Weight) - // Standard Error: 4_119_000 - .saturating_add((619_498_000 as Weight).saturating_mul(r as Weight)) + (50_983_000 as Weight) + // Standard Error: 4_238_000 + .saturating_add((618_956_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (47_314_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_720_000 as Weight).saturating_mul(r as Weight)) + (42_490_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_937_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (47_855_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_701_000 as Weight).saturating_mul(r as Weight)) + (42_296_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_943_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (47_704_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_708_000 as Weight).saturating_mul(r as Weight)) + (42_263_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_944_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (47_656_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_705_000 as Weight).saturating_mul(r as Weight)) + (42_087_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_952_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (55_202_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_229_000 as Weight).saturating_mul(r as Weight)) + (48_024_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (55_193_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_223_000 as Weight).saturating_mul(r as Weight)) + (48_056_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_780_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (48_125_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_704_000 as Weight).saturating_mul(r as Weight)) + (42_352_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (49_162_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_241_000 as Weight).saturating_mul(r as Weight)) + (45_439_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_382_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (48_635_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_262_000 as Weight).saturating_mul(r as Weight)) + (45_232_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_393_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (48_550_000 as Weight) - // Standard Error: 9_000 - .saturating_add((2_267_000 as Weight).saturating_mul(r as Weight)) + (45_351_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_386_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (49_135_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_219_000 as Weight).saturating_mul(r as Weight)) + (45_448_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_385_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (49_638_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_206_000 as Weight).saturating_mul(r as Weight)) + (45_275_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_386_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (49_889_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_201_000 as Weight).saturating_mul(r as Weight)) + (45_180_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_396_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (49_763_000 as Weight) - // Standard Error: 9_000 - .saturating_add((2_210_000 as Weight).saturating_mul(r as Weight)) + (45_396_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_400_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (49_607_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_207_000 as Weight).saturating_mul(r as Weight)) + (45_597_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_392_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (49_664_000 as Weight) - // Standard Error: 9_000 - .saturating_add((2_213_000 as Weight).saturating_mul(r as Weight)) + (45_137_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_400_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (49_718_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_206_000 as Weight).saturating_mul(r as Weight)) + (45_091_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_401_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (49_513_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_208_000 as Weight).saturating_mul(r as Weight)) + (45_547_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_380_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (49_837_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_201_000 as Weight).saturating_mul(r as Weight)) + (45_435_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_383_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (49_684_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_210_000 as Weight).saturating_mul(r as Weight)) + (45_244_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_389_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (48_749_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_872_000 as Weight).saturating_mul(r as Weight)) + (45_253_000 as Weight) + // Standard Error: 11_000 + .saturating_add((3_046_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (49_134_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_630_000 as Weight).saturating_mul(r as Weight)) + (45_339_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_711_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (48_981_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_861_000 as Weight).saturating_mul(r as Weight)) + (45_312_000 as Weight) + // Standard Error: 11_000 + .saturating_add((3_020_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (49_195_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_593_000 as Weight).saturating_mul(r as Weight)) + (45_397_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_739_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (49_304_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_238_000 as Weight).saturating_mul(r as Weight)) + (45_282_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_387_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (48_636_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_259_000 as Weight).saturating_mul(r as Weight)) + (45_508_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_390_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (48_761_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_262_000 as Weight).saturating_mul(r as Weight)) + (45_089_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_397_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (48_492_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_263_000 as Weight).saturating_mul(r as Weight)) + (45_878_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_395_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (48_736_000 as Weight) - // Standard Error: 8_000 - .saturating_add((2_256_000 as Weight).saturating_mul(r as Weight)) + (45_459_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_401_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (48_675_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_256_000 as Weight).saturating_mul(r as Weight)) + (45_663_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_398_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (48_703_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_257_000 as Weight).saturating_mul(r as Weight)) + (45_739_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_393_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (48_758_000 as Weight) - // Standard Error: 7_000 - .saturating_add((2_259_000 as Weight).saturating_mul(r as Weight)) + (45_290_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_392_000 as Weight).saturating_mul(r as Weight)) } } From 95853fb270774c8e62155878cc7a21a1e40cccc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 7 Dec 2021 17:48:28 +0100 Subject: [PATCH 0308/1472] Clean up `pallet-contracts` documentation (#10438) * Update CHANGELOG.md * Remove COMPLEXITY.md --- frame/contracts/CHANGELOG.md | 10 +- frame/contracts/COMPLEXITY.md | 487 ---------------------------- frame/contracts/README.md | 28 ++ frame/contracts/src/wasm/runtime.rs | 7 +- 4 files changed, 34 insertions(+), 498 deletions(-) delete mode 100644 frame/contracts/COMPLEXITY.md diff --git a/frame/contracts/CHANGELOG.md b/frame/contracts/CHANGELOG.md index eaedd28bf3e47..ab3998e6dc4f7 100644 --- a/frame/contracts/CHANGELOG.md +++ b/frame/contracts/CHANGELOG.md @@ -23,13 +23,9 @@ In other words: Upgrading this pallet will not break pre-existing contracts. - Allow contracts to dispatch calls into the runtime (**unstable**) [#9276](https://github.com/paritytech/substrate/pull/9276) -- New **unstable** version of `seal_call` that offers more features. +- New version of `seal_call` that offers more features. [#8909](https://github.com/paritytech/substrate/pull/8909) -- New **unstable** `seal_rent_params` and `seal_rent_status` contract callable function. -[#8231](https://github.com/paritytech/substrate/pull/8231) -[#8780](https://github.com/paritytech/substrate/pull/8780) - - New `instantiate` RPC that allows clients to dry-run contract instantiation. [#8451](https://github.com/paritytech/substrate/pull/8451) @@ -38,6 +34,10 @@ In other words: Upgrading this pallet will not break pre-existing contracts. ### Changed +- Replaced storage rent with automatic storage deposits +[#9669](https://github.com/paritytech/substrate/pull/9669) +[#10082](https://github.com/paritytech/substrate/pull/10082) + - Replaced `seal_println` with the `seal_debug_message` API which allows outputting debug messages to the console and RPC clients. [#8773](https://github.com/paritytech/substrate/pull/8773) diff --git a/frame/contracts/COMPLEXITY.md b/frame/contracts/COMPLEXITY.md deleted file mode 100644 index 1fc1932fe1b5f..0000000000000 --- a/frame/contracts/COMPLEXITY.md +++ /dev/null @@ -1,487 +0,0 @@ -# Complexity - -This analysis is on the computing and memory complexity of specific procedures. It provides a rough estimate of operations performed in general and especially focusing on DB reads and writes. It is also an attempt to estimate the memory consumption at its peak. - -The primary goal is to come up with decent pricing for functions that can be invoked by a user (via extrinsics) or by untrusted code that prevents DoS attacks. - -## Sandboxing - -It makes sense to describe the sandboxing module first because the smart-contract module is built upon it. - -### Memory - -#### set - -Copies data from the supervisor's memory to the guest's memory. - -**complexity**: It doesn't allocate, and the computational complexity is proportional to the number of bytes to copy. - -#### get - -Copies data from the guest's memory to the supervisor's memory. - -**complexity**: It doesn't allocate, and the computational complexity is proportional to the number of bytes to copy. - -## Instance - -### Instantiation - -Instantiation of a sandbox module consists of the following steps: - -1. Loading the wasm module in the in-memory representation, -2. Performing validation of the wasm code, -3. Setting up the environment which will be used to instantiate the module, -4. Performing the standard wasm instantiation process, which includes (but is not limited to): - 1. Allocating of memory requested by the instance, - 2. Copying static data from the module to newly allocated memory, - 3. Executing the `start` function. - -**Note** that the `start` function can be viewed as a normal function and can do anything that a normal function can do, including allocation of more memory or calling the host environment. The complexity of running the `start` function should be considered separately. - -In order to start the process of instantiation, the supervisor should provide the wasm module code being instantiated and the environment definition (a set of functions, memories (and maybe globals and tables in the future) available for import by the guest module) for that module. While the environment definition typically is of the constant size (unless mechanisms like dynamic linking are used), the size of wasm is not. - -Validation and instantiation in WebAssembly are designed to be able to be performed in linear time. The allocation and computational complexity of loading a wasm module depend on the underlying wasm VM being used. For example, for JIT compilers it can and probably will be non-linear because of compilation. However, for wasmi, it should be linear. We can try to use other VMs that are able to compile code with memory and time consumption proportional to the size of the code. - -Since the module itself requests memory, the amount of allocation depends on the module code itself. If untrusted code is being instantiated, it's up to the supervisor to limit the amount of memory available to allocate. - -**complexity**: The computational complexity is proportional to the size of wasm code. Memory complexity is proportional to the size of wasm code and the amount of memory requested by the module. - -### Preparation to invoke - -Invocation of an exported function in the sandboxed module consists of the following steps: - -1. Marshalling, copying and unmarshalling the arguments when passing them between the supervisor and executor, -2. Calling into the underlying VM, -3. Marshalling, copying and unmarshalling the result when passing it between the executor and supervisor, - -**Note** that the complexity of running the function code itself should be considered separately. - -The actual complexity of invocation depends on the underlying VM. Wasmi will reserve a relatively large chunk of memory for the stack before execution of the code, although it's of constant size. - -The size of the arguments and the return value depends on the exact function in question, but can be considered as constant. - -**complexity**: Memory and computational complexity can be considered as a constant. - -### Call from the guest to the supervisor - -The executor handles each call from the guest. The execution of it consists of the following steps: - -1. Marshalling, copying and unmarshalling the arguments when passing them between the guest and executor, -2. Calling into the supervisor, -3. Marshaling, copying and unmarshalling the result when passing it between the executor and guest. - -**Note** that the complexity of running the supervisor handler should be considered separately. - -Because calling into the supervisor requires invoking a wasm VM, the actual complexity of invocation depends on the actual VM used for the runtime/supervisor. Wasmi will reserve a relatively large chunk of memory for the stack before execution of the code, although it's of constant size. - -The size of the arguments and the return value depends on the exact function in question, but can be considered as a constant. - -**complexity**: Memory and computational complexity can be considered as a constant. - -## Transactional Storage - -The contracts module makes use of the nested storage transactions feature offered by -the underlying storage which allows efficient roll back of changes made by contracts. - -> ℹ️ The underlying storage has a overlay layer implemented as a `Map`. If the runtime reads a storage location and the -> respective key doesn't exist in the overlay, then the underlying storage performs a DB access, but the value won't be -> placed into the overlay. The overlay is only filled with writes. -> -> This means that the overlay can be abused in the following ways: -> -> - The overlay can be inflated by issuing a lot of writes to unique locations, -> - Deliberate cache misses can be induced by reading non-modified storage locations, - -It also worth noting that the performance degrades with more state stored in the trie. Due to this -there is not negligible chance that gas schedule will be updated for all operations that involve -storage access. - -## get_storage, get_code_hash, get_rent_allowance, get_balance, contract_exists - -Those query the underlying storage for the requested value. If the value was modified in the -current block they are served from the cache. Otherwise a database read is performed. - -**complexity**: The memory complexity is proportional to the size of the value. The computational complexity is proportional the size of the value; the cost is dominated by the DB read. - -## set_storage, set_balance, set_rent_allowance - -These function write to the underlying storage which caches those values and does not write -them to the database immediately. - -While these functions only modify the local cache, they trigger a database write later when -all changes that were not rolled back are written to storage. Moreover, if the balance of the -account is changed to be below `existential_deposit` then that account along with all its storage -will be removed, which requires time proportional to the number of storage entries that account has. -It should be ensured that pricing accounts for these facts. - -**complexity**: Each lookup has a logarithmical computing time to the number of already inserted entries. -No additional memory is required. - -## instantiate_contract - -Calls `contract_exists` and if it doesn't exist, do not modify the local `Map` similarly to `set_rent_allowance`. - -**complexity**: The computational complexity is proportional to the depth of the overlay cascade and the size of the value; the cost is dominated by the DB read though. No additional memory is required. - -## commit - -In this function, all values modified in the current transactions are committed to the parent -transaction. - -This will trigger `N` inserts into parent transaction (`O(log M)` complexity) or into the storage, where `N` is the size of the current transaction and `M` is the size of the parent transaction. Consider adjusting the price of modifying the -current transaction to account for this (since pricing for the count of entries in `commit` will make the price of commit way less predictable). No additional memory is required. - -Note that in case of storage modification we need to construct a key in the underlying storage. In order to do that we need: - -- perform `twox_128` hashing over a concatenation of some prefix literal and the `AccountId` of the storage owner. -- then perform `blake2_256` hashing of the storage key. -- concatenation of these hashes will constitute the key in the underlying storage. - -There is also a special case to think of: if the balance of some account goes below `existential_deposit`, then all storage entries of that account will be erased, which requires time proportional to the number of storage entries that account has. - -**complexity**: `N` inserts into a transaction or eventually into the storage (if committed). Every deleted account will induce removal of all its storage which is proportional to the number of storage entries that account has. - -## revert - -Consists of dropping (in the Rust sense) of the current transaction. - -**complexity**: Computing complexity is proportional to a number of changed entries in a overlay. No additional memory is required. - -## Executive - -### Transfer - -This function performs the following steps: - -1. Querying source and destination balances from the current transaction (see `get_balance`), -2. Querying `existential_deposit`. -3. Executing `ensure_account_liquid` hook. -4. Updating source and destination balance in the overlay (see `set_balance`). - -**Note** that the complexity of executing `ensure_account_liquid` hook should be considered separately. - -In the course of the execution this function can perform up to 2 DB reads to `get_balance` of source and destination accounts. It can also induce up to 2 DB writes via `set_balance` if flushed to the storage. - -Moreover, if the source balance goes below `existential_deposit` then the transfer is denied and -returns with an error. - -Assuming marshaled size of a balance value is of the constant size we can neglect its effect on the performance. - -**complexity**: up to 2 DB reads and up to 2 DB writes (if flushed to the storage) in the standard case. If removal of the source account takes place then it will additionally perform a DB write per one storage entry that the account has. Memorywise it can be assumed to be constant. - -### Initialization - -Before a call or instantiate can be performed the execution context must be initialized. - -For the first call or instantiation in the handling of an extrinsic, this involves two calls: - -1. `>::now()` -2. `>::block_number()` - -The complexity of initialization depends on the complexity of these functions. In the current -implementation they just involve a DB read. - -For subsequent calls and instantiations during contract execution, the initialization requires no -expensive operations. - -### Terminate - -This function performs the following steps: - -1. Check the calling contract is not already on the callstack by calling `is_live`. -2. `transfer` funds from caller to the beneficiary. -3. Flag the caller contract as deleted in the overlay. - -`is_live` does not do any database access nor does it allocate memory. It walks up the call -stack and therefore executes in linear time depending on size of the call stack. Because -the call stack is of a fixed maximum size we consider this operation as constant time. - -**complexity**: Database accesses as described in Transfer + Removal of the contract. Currently, -we are using child trie removal which is linear in the amount of stored keys. Upcoming changes -will make the account removal constant time. - -### Call - -This function receives input data for the contract execution. The execution consists of the following steps: - -1. Initialization of the execution context. -2. Checking rent payment. -3. Loading code from the DB. -4. Starting a new storage transaction. -5. `transfer`-ing funds between the caller and the destination account. -6. Executing the code of the destination account. -7. Committing or rolling back the storage transaction. - -**Note** that the complexity of executing the contract code should be considered separately. - -Checking for rent involves 2 unconditional DB reads: `ContractInfoOf` and `block_number` -and on top of that at most once per block: - -- DB read to `free_balance` and -- `rent_deposit_offset` and -- `rent_byte_price` and -- `Currency::minimum_balance` and -- `tombstone_deposit`. -- Calls to `ensure_can_withdraw`, `withdraw`, `make_free_balance_be` can perform arbitrary logic and should be considered separately, -- `child_storage_root` -- `kill_child_storage` -- mutation of `ContractInfoOf` - -Loading code most likely will trigger a DB read, since the code is immutable and therefore will not get into the cache (unless a suicide removes it, or it has been instantiated in the same call chain). - -Also, `transfer` can make up to 2 DB reads and up to 2 DB writes (if flushed to the storage) in the standard case. If removal of the source account takes place then it will additionally perform a DB write per one storage entry that the account has. - -Finally, the current storage transaction is closed. The complexity of this depends on the number of changes performed by the code. Thus, the pricing of storage modification should account for that. - -**complexity**: - -- Only for the first invocation of the contract: up to 5 DB reads and one DB write as well as logic executed by `ensure_can_withdraw`, `withdraw`, `make_free_balance_be`. -- On top of that for every invocation: Up to 5 DB reads. DB read of the code is of dynamic size. There can also be up to 2 DB writes (if flushed to the storage). Additionally, if the source account removal takes place a DB write will be performed per one storage entry that the account has. - -### Instantiate - -This function takes the code of the constructor and input data. Instantiation of a contract consists of the following steps: - -1. Initialization of the execution context. -2. Calling `DetermineContractAddress` hook to determine an address for the contract, -3. Starting a new storage transaction. -4. `transfer`-ing funds between self and the newly instantiated contract. -5. Executing the constructor code. This will yield the final code of the code. -6. Storing the code for the newly instantiated contract in the overlay. -7. Committing or rolling back the storage transaction. - -**Note** that the complexity of executing the constructor code should be considered separately. - -**Note** that the complexity of `DetermineContractAddress` hook should be considered separately as well. Most likely it will use some kind of hashing over the code of the constructor and input data. The default `SimpleAddressDeterminer` does precisely that. - -**Note** that the constructor returns code in the owned form and it's obtained via return facilities, which should have take fee for the return value. - -Also, `transfer` can make up to 2 DB reads and up to 2 DB writes (if flushed to the storage) in the standard case. If removal of the source account takes place then it will additionally perform a DB write per one storage entry that the account has. - -Storing the code in the overlay may induce another DB write (if flushed to the storage) with the size proportional to the size of the constructor code. - -Finally, the current storage transaction is closed.. The complexity of this depends on the number of changes performed by the constructor code. Thus, the pricing of storage modification should account for that. - -**complexity**: Up to 2 DB reads and induces up to 3 DB writes (if flushed to the storage), one of which is dependent on the size of the code. Additionally, if the source account removal takes place a DB write will be performed per one storage entry that the account has. - -## Contracts API - -Each API function invoked from a contract can involve some overhead. - -## Getter functions - -Those are simple getter functions which copy a requested value to contract memory. They -all have the following two arguments: - -- `output_ptr`: Pointer into contract memory where to copy the value. -- `output_len_ptr`: Pointer into contract memory where the size of the buffer is stored. The size of the copied value is also stored there. - -**complexity**: The size of the returned value is constant for a given runtime. Therefore we -consider its complexity constant even though some of them might involve at most one DB read. Some of those -functions call into other pallets of the runtime. The assumption here is that those functions are also -linear in regard to the size of the data that is returned and therefore considered constant for a -given runtime. - -This is the list of getters: - -- seal_caller -- seal_address -- seal_weight_to_fee -- seal_gas_left -- seal_balance -- seal_value_transferred -- seal_now -- seal_minimum_balance -- seal_tombstone_deposit -- seal_rent_allowance -- seal_block_number - -### seal_set_storage - -This function receives a `key` and `value` as arguments. It consists of the following steps: - -1. Reading the sandbox memory for `key` and `value` (see sandboxing memory get). -2. Setting the storage at the given `key` to the given `value` (see `set_storage`). - -**complexity**: Complexity is proportional to the size of the `value`. This function induces a DB write of size proportional to the `value` size (if flushed to the storage), so should be priced accordingly. - -### seal_clear_storage - -This function receives a `key` as argument. It consists of the following steps: - -1. Reading the sandbox memory for `key` (see sandboxing memory get). -2. Clearing the storage at the given `key` (see `set_storage`). - -**complexity**: Complexity is constant. This function induces a DB write to clear the storage entry -(upon being flushed to the storage) and should be priced accordingly. - -### seal_get_storage - -This function receives a `key` as an argument. It consists of the following steps: - -1. Reading the sandbox memory for `key` (see sandboxing memory get). -2. Reading the storage with the given key (see `get_storage`). It receives back the owned result buffer. -3. Writing the storage value to contract memory. - -Key is of a constant size. Therefore, the sandbox memory load can be considered to be of constant complexity. - -Unless the value is cached, a DB read will be performed. The size of the value is not known until the read is -performed. Moreover, the DB read has to be synchronous and no progress can be made until the value is fetched. - -**complexity**: The memory and computing complexity is proportional to the size of the fetched value. This function performs a DB read. - -### seal_transfer - -This function receives the following arguments: - -- `account` buffer of a marshaled `AccountId`, -- `value` buffer of a marshaled `Balance`, - -It consists of the following steps: - -1. Loading `account` buffer from the sandbox memory (see sandboxing memory get) and then decoding it. -2. Loading `value` buffer from the sandbox memory and then decoding it. -3. Invoking the executive function `transfer`. - -Loading of `account` and `value` buffers should be charged. This is because the sizes of buffers are specified by the calling code, even though marshaled representations are, essentially, of constant size. This can be fixed by assigning an upper bound for sizes of `AccountId` and `Balance`. - -### seal_call - -This function receives the following arguments: - -- `callee` buffer of a marshaled `AccountId`, -- `gas` limit which is plain u64, -- `value` buffer of a marshaled `Balance`, -- `input_data` an arbitrarily sized byte vector. -- `output_ptr` pointer to contract memory. - -It consists of the following steps: - -1. Loading `callee` buffer from the sandbox memory (see sandboxing memory get) and then decoding it. -2. Loading `value` buffer from the sandbox memory and then decoding it. -3. Loading `input_data` buffer from the sandbox memory. -4. Invoking the executive function `call`. -5. Writing output buffer to contract memory. - -Loading of `callee` and `value` buffers should be charged. This is because the sizes of buffers are specified by the calling code, even though marshaled representations are, essentially, of constant size. This can be fixed by assigning an upper bound for sizes of `AccountId` and `Balance`. - -Loading `input_data` should be charged in any case. - -**complexity**: All complexity comes from loading and writing buffers and executing `call` executive function. The former component is proportional to the sizes of `callee`, `value`, `input_data` and `output_ptr` buffers. The latter component completely depends on the complexity of `call` executive function, and also dominated by it. - -### seal_instantiate - -This function receives the following arguments: - -- `init_code`, a buffer which contains the code of the constructor. -- `gas` limit which is plain u64 -- `value` buffer of a marshaled `Balance` -- `input_data`. an arbitrarily sized byte vector. - -It consists of the following steps: - -1. Loading `init_code` buffer from the sandbox memory (see sandboxing memory get) and then decoding it. -2. Loading `value` buffer from the sandbox memory and then decoding it. -3. Loading `input_data` buffer from the sandbox memory. -4. Invoking `instantiate` executive function. - -Loading of `value` buffer should be charged. This is because the size of the buffer is specified by the calling code, even though marshaled representation is, essentially, of constant size. This can be fixed by assigning an upper bound for size for `Balance`. - -Loading `init_code` and `input_data` should be charged in any case. - -**complexity**: All complexity comes from loading buffers and executing `instantiate` executive function. The former component is proportional to the sizes of `init_code`, `value` and `input_data` buffers. The latter component completely depends on the complexity of `instantiate` executive function and also dominated by it. - -### seal_terminate - -This function receives the following arguments: - -- `beneficiary`, buffer of a marshaled `AccountId` - -It consists of the following steps: - -1. Loading `beneficiary` buffer from the sandbox memory (see sandboxing memory get) and then decoding it. - -Loading of the `beneficiary` buffer should be charged. This is because the sizes of buffers are specified by the calling code, even though marshaled representations are, essentially, of constant size. This can be fixed by assigning an upper bound for sizes of `AccountId`. - -**complexity**: All complexity comes from loading buffers and executing `terminate` executive function. The former component is proportional to the size of the `beneficiary` buffer. The latter component completely depends on the complexity of `terminate` executive function and also dominated by it. - -### seal_input - -This function receives a pointer to contract memory. It copies the input to the contract call to this location. - -**complexity**: The complextity is proportional to the size of the input buffer. - -### seal_return - -This function receives a `data` buffer and `flags` arguments. Execution of the function consists of the following steps: - -1. Loading `data` buffer from the sandbox memory (see sandboxing memory get). -2. Storing the `u32` flags value. -3. Trapping - -**complexity**: The complexity of this function is proportional to the size of the `data` buffer. - -### seal_deposit_event - -This function receives a `data` buffer as an argument. Execution of the function consists of the following steps: - -1. Loading `data` buffer from the sandbox memory (see sandboxing memory get), -2. Insert to nested context execution -3. Copies from nested to underlying contexts -4. Call system deposit event - -**complexity**: The complexity of this function is proportional to the size of the `data` buffer. - -### seal_set_rent_allowance - -This function receives the following argument: - -- `value` buffer of a marshaled `Balance`, - -It consists of the following steps: - -1. Loading `value` buffer from the sandbox memory and then decoding it. -2. Invoking `set_rent_allowance` AccountDB function. - -**complexity**: Complexity is proportional to the size of the `value`. This function induces a DB write of size proportional to the `value` size (if flushed to the storage), so should be priced accordingly. - -## Built-in hashing functions - -This paragraph concerns the following supported built-in hash functions: - -- `SHA2` with 256-bit width -- `KECCAK` with 256-bit width -- `BLAKE2` with 128-bit and 256-bit widths - -These functions compute a cryptographic hash on the given inputs and copy the -resulting hash directly back into the sandboxed Wasm contract output buffer. - -Execution of the function consists of the following steps: - -1. Load data stored in the input buffer into an intermediate buffer. -2. Compute the cryptographic hash `H` on the intermediate buffer. -3. Copy back the bytes of `H` into the contract side output buffer. - -**complexity**: Complexity is proportional to the size of the input buffer in bytes -as well as to the size of the output buffer in bytes. Also different cryptographic -algorithms have different inherent complexity so users must expect the above -mentioned crypto hashes to have varying gas costs. -The complexity of each cryptographic hash function highly depends on the underlying -implementation. - -### seal_ecdsa_recover - -This function receives the following arguments: - -- `signature` is 65 bytes buffer, -- `message_hash` is 32 bytes buffer, -- `output` is 33 bytes buffer to return compressed public key, - -It consists of the following steps: - -1. Loading `signature` buffer from the sandbox memory (see sandboxing memory get). -2. Loading `message_hash` buffer from the sandbox memory. -3. Invoking the executive function `secp256k1_ecdsa_recover_compressed`. -4. Copy the bytes of compressed public key into the contract side output buffer. - -**complexity**: Complexity is partially constant(it doesn't depend on input) but still depends on points of ECDSA and calculation. \ No newline at end of file diff --git a/frame/contracts/README.md b/frame/contracts/README.md index 978ee25fcb109..50e43ddb998a7 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -49,6 +49,34 @@ fails, A can decide how to handle that failure, either proceeding or reverting A Those are documented in the [reference documentation](https://docs.rs/pallet-contracts/latest/pallet_contracts/#dispatchable-functions). +### Interface exposed to contracts + +Each contract is one WebAssembly module that looks like this: + +```wat +(module + ;; Invoked by pallet-contracts when a contract is instantiated. + ;; No arguments and empty return type. + (func (export "deploy")) + + ;; Invoked by pallet-contracts when a contract is called. + ;; No arguments and empty return type. + (func (export "call")) + + ;; If a contract uses memory it must be imported. Memory is optional. + ;; The maximum allowed memory size depends on the pallet-contracts configuration. + (import "env" "memory" (memory 1 1)) + + ;; This is one of many functions that can be imported and is implemented by pallet-contracts. + ;; This function is used to copy the result buffer and flags back to the caller. + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) +) +``` + +The documentation of all importable functions can be found +[here](https://github.com/paritytech/substrate/blob/master/frame/contracts/src/wasm/runtime.rs). +Look for the `define_env!` macro invocation. + ## Usage This module executes WebAssembly smart contracts. These can potentially be written in any language diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index a7341e9e02e56..ad13d18435a96 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -726,12 +726,7 @@ where } } -// *********************************************************** -// * AFTER MAKING A CHANGE MAKE SURE TO UPDATE COMPLEXITY.MD * -// *********************************************************** - -// Define a function `fn init_env() -> HostFunctionSet` that returns -// a function set which can be imported by an executed contract. +// This is the API exposed to contracts. // // # Note // From fd350e3c02d7fb9421d908e6c552d50992b167ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 7 Dec 2021 21:31:28 +0000 Subject: [PATCH 0309/1472] grandpa: allow authority set hard forks to be forced (#10444) * grandpa: allow authority set hard forks to be forced * grandpa: fix authority set hard forks in warp proof provider * grandpa: make AuthoritySetHardFork public * grandpa: extend comment --- client/finality-grandpa/src/lib.rs | 41 ++++++++++++++++++----- client/finality-grandpa/src/warp_proof.rs | 11 +++--- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index e7618929fd089..b300066469472 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -541,6 +541,24 @@ where ) } +/// A descriptor for an authority set hard fork. These are authority set changes +/// that are not signalled by the runtime and instead are defined off-chain +/// (hence the hard fork). +pub struct AuthoritySetHardFork { + /// The new authority set id. + pub set_id: SetId, + /// The block hash and number at which the hard fork should be applied. + pub block: (Block::Hash, NumberFor), + /// The authorities in the new set. + pub authorities: AuthorityList, + /// The latest block number that was finalized before this authority set + /// hard fork. When defined, the authority set change will be forced, i.e. + /// the node won't wait for the block above to be finalized before enacting + /// the change, and the given finalized number will be used as a base for + /// voting. + pub last_finalized: Option>, +} + /// Make block importer and link half necessary to tie the background voter to /// it. A vector of authority set hard forks can be passed, any authority set /// change signaled at the given block (either already signalled or in a further @@ -550,7 +568,7 @@ pub fn block_import_with_authority_set_hard_forks client: Arc, genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, select_chain: SC, - authority_set_hard_forks: Vec<(SetId, (Block::Hash, NumberFor), AuthorityList)>, + authority_set_hard_forks: Vec>, telemetry: Option, ) -> Result<(GrandpaBlockImport, LinkHalf), ClientError> where @@ -580,19 +598,24 @@ where let (justification_sender, justification_stream) = GrandpaJustificationStream::channel(); - // create pending change objects with 0 delay and enacted on finality - // (i.e. standard changes) for each authority set hard fork. + // create pending change objects with 0 delay for each authority set hard fork. let authority_set_hard_forks = authority_set_hard_forks .into_iter() - .map(|(set_id, (hash, number), authorities)| { + .map(|fork| { + let delay_kind = if let Some(last_finalized) = fork.last_finalized { + authorities::DelayKind::Best { median_last_finalized: last_finalized } + } else { + authorities::DelayKind::Finalized + }; + ( - set_id, + fork.set_id, authorities::PendingChange { - next_authorities: authorities, + next_authorities: fork.authorities, delay: Zero::zero(), - canon_hash: hash, - canon_height: number, - delay_kind: authorities::DelayKind::Finalized, + canon_hash: fork.block.0, + canon_height: fork.block.1, + delay_kind, }, ) }) diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index 3c1fa4892f8a3..39d570d22bd7d 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -19,8 +19,8 @@ use sp_runtime::codec::{self, Decode, Encode}; use crate::{ - best_justification, find_scheduled_change, AuthoritySetChanges, BlockNumberOps, - GrandpaJustification, SharedAuthoritySet, + best_justification, find_scheduled_change, AuthoritySetChanges, AuthoritySetHardFork, + BlockNumberOps, GrandpaJustification, SharedAuthoritySet, }; use sc_client_api::Backend as ClientBackend; use sc_network::warp_request_handler::{EncodedProof, VerificationResult, WarpSyncProvider}; @@ -255,12 +255,15 @@ where pub fn new( backend: Arc, authority_set: SharedAuthoritySet>, - hard_forks: Vec<(SetId, (Block::Hash, NumberFor), AuthorityList)>, + hard_forks: Vec>, ) -> Self { NetworkProvider { backend, authority_set, - hard_forks: hard_forks.into_iter().map(|(s, hn, list)| (hn, (s, list))).collect(), + hard_forks: hard_forks + .into_iter() + .map(|fork| (fork.block, (fork.set_id, fork.authorities))) + .collect(), } } } From 4abd91cee8ea4599f1940e819102256c557c63cc Mon Sep 17 00:00:00 2001 From: Gautam Dhameja Date: Tue, 7 Dec 2021 23:40:47 +0100 Subject: [PATCH 0310/1472] Add child-bounties pallet. (#10309) * Extract child-bounties as a separate pallet. * Initial tests added. * More tests. * Tests complete. Fixed curator fee issue. * Fixed comments. * Added benchmarks for child-bounties pallet. * Added weights. * Fixed formatting. * Fixed comments. * Re-run benchmarks for bounties pallet. * Make cargo fmt happy again * add max encoded len * use event structs * fmt * fix compile * Addressed review comments. * Use config type instead of const in benchmarking. * Addressed more review comments. * Use ensure_can_withdraw instead of just checking min balance. * fmt. * Introduce ChildBountyCuratorDepositBase to avoid zero curator deposits for child bounties. * Fix unassign curator logic for child-bounties. * Added more tests for unassign curator. * Reduce bounty description max length in node runtime. * Updated weights for child bounties pallet. * reduce indentation of unassign_curator * more indentation reduction * deduplicate slashing arms * reintroduce ensure check * add assertion to check that bad unassign origin fails * formatting * Updated comments. Co-authored-by: Ricardo Rius Co-authored-by: Shawn Tabrizi Co-authored-by: Alexander Popiak --- Cargo.lock | 20 + Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 6 +- bin/node/runtime/src/lib.rs | 17 +- frame/bounties/src/lib.rs | 57 +- frame/bounties/src/tests.rs | 1 + frame/bounties/src/weights.rs | 158 +-- frame/child-bounties/Cargo.toml | 54 + frame/child-bounties/README.md | 21 + frame/child-bounties/src/benchmarking.rs | 308 ++++++ frame/child-bounties/src/lib.rs | 897 ++++++++++++++++ frame/child-bounties/src/tests.rs | 1219 ++++++++++++++++++++++ frame/child-bounties/src/weights.rs | 215 ++++ 13 files changed, 2896 insertions(+), 78 deletions(-) create mode 100644 frame/child-bounties/Cargo.toml create mode 100644 frame/child-bounties/README.md create mode 100644 frame/child-bounties/src/benchmarking.rs create mode 100644 frame/child-bounties/src/lib.rs create mode 100644 frame/child-bounties/src/tests.rs create mode 100644 frame/child-bounties/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 08d2ab7328398..d1618f83b476f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4702,6 +4702,7 @@ dependencies = [ "pallet-bags-list", "pallet-balances", "pallet-bounties", + "pallet-child-bounties", "pallet-collective", "pallet-contracts", "pallet-contracts-primitives", @@ -5383,6 +5384,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-child-bounties" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log 0.4.14", + "pallet-balances", + "pallet-bounties", + "pallet-treasury", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-collective" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index f30b223a9b205..7bb08345c0fe2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,6 +74,7 @@ members = [ "frame/beefy-mmr/primitives", "frame/benchmarking", "frame/bounties", + "frame/child-bounties", "frame/collective", "frame/contracts", "frame/contracts/rpc", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 4771202b90a0c..a61c2311917a8 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -59,6 +59,7 @@ pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../. pallet-bags-list = { version = "4.0.0-dev", default-features = false, path = "../../../frame/bags-list" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../../frame/balances" } pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../../../frame/bounties" } +pallet-child-bounties = { version = "4.0.0-dev", default-features = false, path = "../../../frame/child-bounties" } pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../../../frame/collective" } pallet-contracts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts" } pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/common/" } @@ -173,7 +174,8 @@ std = [ "log/std", "frame-try-runtime/std", "sp-npos-elections/std", - "sp-io/std" + "sp-io/std", + "pallet-child-bounties/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -186,6 +188,7 @@ runtime-benchmarks = [ "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-bounties/runtime-benchmarks", + "pallet-child-bounties/runtime-benchmarks", "pallet-collective/runtime-benchmarks", "pallet-contracts/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", @@ -225,6 +228,7 @@ try-runtime = [ "pallet-babe/try-runtime", "pallet-balances/try-runtime", "pallet-bounties/try-runtime", + "pallet-child-bounties/try-runtime", "pallet-collective/try-runtime", "pallet-contracts/try-runtime", "pallet-democracy/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 9573b86c6ee2c..45b49dc46b897 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -844,10 +844,13 @@ parameter_types! { pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS; pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS; - pub const MaximumReasonLength: u32 = 16384; + pub const MaximumReasonLength: u32 = 300; pub const BountyCuratorDeposit: Permill = Permill::from_percent(50); pub const BountyValueMinimum: Balance = 5 * DOLLARS; pub const MaxApprovals: u32 = 100; + pub const MaxActiveChildBountyCount: u32 = 5; + pub const ChildBountyValueMinimum: Balance = 1 * DOLLARS; + pub const ChildBountyCuratorDepositBase: Permill = Permill::from_percent(10); } impl pallet_treasury::Config for Runtime { @@ -883,6 +886,15 @@ impl pallet_bounties::Config for Runtime { type DataDepositPerByte = DataDepositPerByte; type MaximumReasonLength = MaximumReasonLength; type WeightInfo = pallet_bounties::weights::SubstrateWeight; + type ChildBountyManager = ChildBounties; +} + +impl pallet_child_bounties::Config for Runtime { + type Event = Event; + type MaxActiveChildBountyCount = MaxActiveChildBountyCount; + type ChildBountyValueMinimum = ChildBountyValueMinimum; + type ChildBountyCuratorDepositBase = ChildBountyCuratorDepositBase; + type WeightInfo = pallet_child_bounties::weights::SubstrateWeight; } impl pallet_tips::Config for Runtime { @@ -1302,6 +1314,7 @@ construct_runtime!( Uniques: pallet_uniques, TransactionStorage: pallet_transaction_storage, BagsList: pallet_bags_list, + ChildBounties: pallet_child_bounties, } ); @@ -1652,6 +1665,7 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_bags_list, BagsList); list_benchmark!(list, extra, pallet_balances, Balances); list_benchmark!(list, extra, pallet_bounties, Bounties); + list_benchmark!(list, extra, pallet_child_bounties, ChildBounties); list_benchmark!(list, extra, pallet_collective, Council); list_benchmark!(list, extra, pallet_contracts, Contracts); list_benchmark!(list, extra, pallet_democracy, Democracy); @@ -1729,6 +1743,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_balances, Balances); add_benchmark!(params, batches, pallet_bags_list, BagsList); add_benchmark!(params, batches, pallet_bounties, Bounties); + add_benchmark!(params, batches, pallet_child_bounties, ChildBounties); add_benchmark!(params, batches, pallet_collective, Council); add_benchmark!(params, batches, pallet_contracts, Contracts); add_benchmark!(params, batches, pallet_democracy, Democracy); diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 5021608b506b9..1d32b63f38f92 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -123,6 +123,15 @@ pub struct Bounty { status: BountyStatus, } +impl + Bounty +{ + /// Getter for bounty status, to be used for child bounties. + pub fn get_status(&self) -> BountyStatus { + self.status.clone() + } +} + /// The status of a bounty proposal. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub enum BountyStatus { @@ -156,6 +165,15 @@ pub enum BountyStatus { }, } +/// The child-bounty manager. +pub trait ChildBountyManager { + /// Get the active child-bounties for a parent bounty. + fn child_bounties_count(bounty_id: BountyIndex) -> BountyIndex; + + /// Get total curator fees of children-bounty curators. + fn children_curator_fees(bounty_id: BountyIndex) -> Balance; +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -202,6 +220,9 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// The child-bounty manager. + type ChildBountyManager: ChildBountyManager>; } #[pallet::error] @@ -225,6 +246,8 @@ pub mod pallet { PendingPayout, /// The bounties cannot be claimed/closed because it's still in the countdown period. Premature, + /// The bounty cannot be closed because it has active child-bounties. + HasActiveChildBounty, } #[pallet::event] @@ -512,6 +535,13 @@ pub mod pallet { Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; + + // Ensure no active child-bounties before processing the call. + ensure!( + T::ChildBountyManager::child_bounties_count(bounty_id) == 0, + Error::::HasActiveChildBounty + ); + match &bounty.status { BountyStatus::Active { curator, .. } => { ensure!(signer == *curator, Error::::RequireCurator); @@ -563,7 +593,15 @@ pub mod pallet { let payout = balance.saturating_sub(fee); let err_amount = T::Currency::unreserve(&curator, bounty.curator_deposit); debug_assert!(err_amount.is_zero()); - let res = T::Currency::transfer(&bounty_account, &curator, fee, AllowDeath); // should not fail + + // Get total child-bounties curator fees, and subtract it from master curator + // fee. + let children_fee = T::ChildBountyManager::children_curator_fees(bounty_id); + debug_assert!(children_fee <= fee); + + let final_fee = fee.saturating_sub(children_fee); + let res = + T::Currency::transfer(&bounty_account, &curator, final_fee, AllowDeath); // should not fail debug_assert!(res.is_ok()); let res = T::Currency::transfer(&bounty_account, &beneficiary, payout, AllowDeath); // should not fail @@ -609,6 +647,12 @@ pub mod pallet { |maybe_bounty| -> DispatchResultWithPostInfo { let bounty = maybe_bounty.as_ref().ok_or(Error::::InvalidIndex)?; + // Ensure no active child-bounties before processing the call. + ensure!( + T::ChildBountyManager::child_bounties_count(bounty_id) == 0, + Error::::HasActiveChildBounty + ); + match &bounty.status { BountyStatus::Proposed => { // The reject origin would like to cancel a proposed bounty. @@ -813,3 +857,14 @@ impl pallet_treasury::SpendFunds for Pallet { *total_weight += ::WeightInfo::spend_funds(bounties_len); } } + +// Default impl for when ChildBounties is not being used in the runtime. +impl ChildBountyManager for () { + fn child_bounties_count(_bounty_id: BountyIndex) -> BountyIndex { + Default::default() + } + + fn children_curator_fees(_bounty_id: BountyIndex) -> Balance { + Zero::zero() + } +} diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index 344bb6495c3bc..bbcf9d6d9e72d 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -146,6 +146,7 @@ impl Config for Test { type DataDepositPerByte = DataDepositPerByte; type MaximumReasonLength = MaximumReasonLength; type WeightInfo = (); + type ChildBountyManager = (); } type TreasuryError = pallet_treasury::Error; diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index be93636424399..1383f69bed918 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -18,24 +18,24 @@ //! Autogenerated weights for pallet_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-11-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// target/release/substrate +// ./target/release/substrate // benchmark // --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_bounties +// --pallet +// pallet_bounties // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/bounties/src/weights.rs +// --output=./frame/bounties/src/ // --template=./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -61,87 +61,91 @@ pub trait WeightInfo { /// Weights for pallet_bounties using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Treasury BountyCount (r:1 w:1) + // Storage: Bounties BountyCount (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: Treasury BountyDescriptions (r:0 w:1) - // Storage: Treasury Bounties (r:0 w:1) + // Storage: Bounties BountyDescriptions (r:0 w:1) + // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(d: u32, ) -> Weight { - (44_482_000 as Weight) + (58_161_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) - // Storage: Treasury BountyApprovals (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) + // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (11_955_000 as Weight) + (20_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (9_771_000 as Weight) + (14_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (40_683_000 as Weight) + (62_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (36_390_000 as Weight) + (55_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) + // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (25_187_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + (46_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:3 w:3) - // Storage: Treasury BountyDescriptions (r:0 w:1) + // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (124_785_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + (185_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) + // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:1 w:1) - // Storage: Treasury BountyDescriptions (r:0 w:1) + // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (39_483_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) + (82_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) + // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:2 w:2) - // Storage: Treasury BountyDescriptions (r:0 w:1) + // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (83_453_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) + (137_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (24_151_000 as Weight) + (33_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: Treasury BountyApprovals (r:1 w:1) - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties BountyApprovals (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((58_004_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 191_000 + .saturating_add((81_116_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -151,87 +155,91 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Treasury BountyCount (r:1 w:1) + // Storage: Bounties BountyCount (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: Treasury BountyDescriptions (r:0 w:1) - // Storage: Treasury Bounties (r:0 w:1) + // Storage: Bounties BountyDescriptions (r:0 w:1) + // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(d: u32, ) -> Weight { - (44_482_000 as Weight) + (58_161_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) - // Storage: Treasury BountyApprovals (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) + // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (11_955_000 as Weight) + (20_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (9_771_000 as Weight) + (14_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (40_683_000 as Weight) + (62_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (36_390_000 as Weight) + (55_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) + // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (25_187_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + (46_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:3 w:3) - // Storage: Treasury BountyDescriptions (r:0 w:1) + // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (124_785_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + (185_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) + // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:1 w:1) - // Storage: Treasury BountyDescriptions (r:0 w:1) + // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (39_483_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + (82_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) + // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:2 w:2) - // Storage: Treasury BountyDescriptions (r:0 w:1) + // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (83_453_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + (137_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (24_151_000 as Weight) + (33_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: Treasury BountyApprovals (r:1 w:1) - // Storage: Treasury Bounties (r:1 w:1) + // Storage: Bounties BountyApprovals (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((58_004_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 191_000 + .saturating_add((81_116_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml new file mode 100644 index 0000000000000..040337424d399 --- /dev/null +++ b/frame/child-bounties/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "pallet-child-bounties" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet to manage child bounties" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ + "derive", +] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } +pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../bounties" } +sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } +sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +log = { version = "0.4.14", default-features = false } + +[dev-dependencies] +pallet-balances = { version = "4.0.0-dev", path = "../balances" } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-core/std", + "sp-io/std", + "scale-info/std", + "sp-std/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", + "pallet-treasury/std", + "pallet-bounties/std", + "log/std", +] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/child-bounties/README.md b/frame/child-bounties/README.md new file mode 100644 index 0000000000000..e07996d54957a --- /dev/null +++ b/frame/child-bounties/README.md @@ -0,0 +1,21 @@ +# Child Bounties Pallet (pallet-child-bounties) + +## Child Bounty + +> NOTE: This pallet is tightly coupled with pallet-treasury and pallet-bounties. + +With child bounties, a large bounty proposal can be divided into smaller chunks, for parallel execution, and for efficient governance and tracking of spent funds. + +A child-bounty is a smaller piece of work, extracted from a parent bounty. A curator is assigned after the child-bounty is created by the parent bounty curator, to be delegated with the responsibility of assigning a payout address once the specified set of tasks is completed. + +## Interface + +### Dispatchable Functions + +- `add_child_bounty` - Add a child-bounty for a parent-bounty to for dividing the work in smaller tasks. +- `propose_curator` - Assign an account to a child-bounty as candidate curator. +- `accept_curator` - Accept a child-bounty assignment from the parent-bounty curator, setting a curator deposit. +- `award_child_bounty` - Close and pay out the specified amount for the completed work. +- `claim_child_bounty` - Claim a specific child-bounty amount from the payout address. +- `unassign_curator` - Unassign an accepted curator from a specific child-bounty. +- `close_child_bounty` - Cancel the child-bounty for a specific treasury amount and close the bounty. diff --git a/frame/child-bounties/src/benchmarking.rs b/frame/child-bounties/src/benchmarking.rs new file mode 100644 index 0000000000000..3386245cbdca7 --- /dev/null +++ b/frame/child-bounties/src/benchmarking.rs @@ -0,0 +1,308 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Child-bounties pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; + +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_system::RawOrigin; + +use crate::Pallet as ChildBounties; +use pallet_bounties::Pallet as Bounties; +use pallet_treasury::Pallet as Treasury; + +const SEED: u32 = 0; + +#[derive(Clone)] +struct BenchmarkChildBounty { + /// Bounty ID. + bounty_id: BountyIndex, + /// ChildBounty ID. + child_bounty_id: BountyIndex, + /// The account proposing it. + caller: T::AccountId, + /// The master curator account. + curator: T::AccountId, + /// The child-bounty curator account. + child_curator: T::AccountId, + /// The (total) amount that should be paid if the bounty is rewarded. + value: BalanceOf, + /// The curator fee. included in value. + fee: BalanceOf, + /// The (total) amount that should be paid if the child-bounty is rewarded. + child_bounty_value: BalanceOf, + /// The child-bounty curator fee. included in value. + child_bounty_fee: BalanceOf, + /// Bounty description. + reason: Vec, +} + +fn setup_bounty( + user: u32, + description: u32, +) -> (T::AccountId, T::AccountId, BalanceOf, BalanceOf, Vec) { + let caller = account("caller", user, SEED); + let value: BalanceOf = T::BountyValueMinimum::get().saturating_mul(100u32.into()); + let fee = value / 2u32.into(); + let deposit = T::BountyDepositBase::get() + + T::DataDepositPerByte::get() * T::MaximumReasonLength::get().into(); + let _ = T::Currency::make_free_balance_be(&caller, deposit); + let curator = account("curator", user, SEED); + let _ = T::Currency::make_free_balance_be(&curator, fee / 2u32.into()); + let reason = vec![0; description as usize]; + (caller, curator, fee, value, reason) +} + +fn setup_child_bounty(user: u32, description: u32) -> BenchmarkChildBounty { + let (caller, curator, fee, value, reason) = setup_bounty::(user, description); + let child_curator = account("child-curator", user, SEED); + let _ = T::Currency::make_free_balance_be(&child_curator, fee / 2u32.into()); + let child_bounty_value = (value - fee) / 4u32.into(); + let child_bounty_fee = child_bounty_value / 2u32.into(); + + BenchmarkChildBounty:: { + bounty_id: 0, + child_bounty_id: 0, + caller, + curator, + child_curator, + value, + fee, + child_bounty_value, + child_bounty_fee, + reason, + } +} + +fn activate_bounty( + user: u32, + description: u32, +) -> Result, &'static str> { + let mut child_bounty_setup = setup_child_bounty::(user, description); + let curator_lookup = T::Lookup::unlookup(child_bounty_setup.curator.clone()); + Bounties::::propose_bounty( + RawOrigin::Signed(child_bounty_setup.caller.clone()).into(), + child_bounty_setup.value, + child_bounty_setup.reason.clone(), + )?; + + child_bounty_setup.bounty_id = Bounties::::bounty_count() - 1; + + Bounties::::approve_bounty(RawOrigin::Root.into(), child_bounty_setup.bounty_id)?; + Treasury::::on_initialize(T::BlockNumber::zero()); + Bounties::::propose_curator( + RawOrigin::Root.into(), + child_bounty_setup.bounty_id, + curator_lookup.clone(), + child_bounty_setup.fee, + )?; + Bounties::::accept_curator( + RawOrigin::Signed(child_bounty_setup.curator.clone()).into(), + child_bounty_setup.bounty_id, + )?; + + Ok(child_bounty_setup) +} + +fn activate_child_bounty( + user: u32, + description: u32, +) -> Result, &'static str> { + let mut bounty_setup = activate_bounty::(user, description)?; + let child_curator_lookup = T::Lookup::unlookup(bounty_setup.child_curator.clone()); + + ChildBounties::::add_child_bounty( + RawOrigin::Signed(bounty_setup.curator.clone()).into(), + bounty_setup.bounty_id, + bounty_setup.child_bounty_value, + bounty_setup.reason.clone(), + )?; + + bounty_setup.child_bounty_id = ChildBountyCount::::get() - 1; + + ChildBounties::::propose_curator( + RawOrigin::Signed(bounty_setup.curator.clone()).into(), + bounty_setup.bounty_id, + bounty_setup.child_bounty_id, + child_curator_lookup.clone(), + bounty_setup.child_bounty_fee, + )?; + + ChildBounties::::accept_curator( + RawOrigin::Signed(bounty_setup.child_curator.clone()).into(), + bounty_setup.bounty_id, + bounty_setup.child_bounty_id, + )?; + + Ok(bounty_setup) +} + +fn setup_pot_account() { + let pot_account = Bounties::::account_id(); + let value = T::Currency::minimum_balance().saturating_mul(1_000_000_000u32.into()); + let _ = T::Currency::make_free_balance_be(&pot_account, value); +} + +fn assert_last_event(generic_event: ::Event) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +benchmarks! { + add_child_bounty { + let d in 0 .. T::MaximumReasonLength::get(); + setup_pot_account::(); + let bounty_setup = activate_bounty::(0, d)?; + }: _(RawOrigin::Signed(bounty_setup.curator), bounty_setup.bounty_id, + bounty_setup.child_bounty_value, bounty_setup.reason.clone()) + verify { + assert_last_event::(Event::Added { + index: bounty_setup.bounty_id, + child_index: bounty_setup.child_bounty_id, + }.into()) + } + + propose_curator { + setup_pot_account::(); + let bounty_setup = activate_bounty::(0, T::MaximumReasonLength::get())?; + let child_curator_lookup = T::Lookup::unlookup(bounty_setup.child_curator.clone()); + + ChildBounties::::add_child_bounty( + RawOrigin::Signed(bounty_setup.curator.clone()).into(), + bounty_setup.bounty_id, + bounty_setup.child_bounty_value, + bounty_setup.reason.clone(), + )?; + let child_bounty_id = ChildBountyCount::::get() - 1; + + }: _(RawOrigin::Signed(bounty_setup.curator), bounty_setup.bounty_id, + child_bounty_id, child_curator_lookup, bounty_setup.child_bounty_fee) + + accept_curator { + setup_pot_account::(); + let mut bounty_setup = activate_bounty::(0, T::MaximumReasonLength::get())?; + let child_curator_lookup = T::Lookup::unlookup(bounty_setup.child_curator.clone()); + + ChildBounties::::add_child_bounty( + RawOrigin::Signed(bounty_setup.curator.clone()).into(), + bounty_setup.bounty_id, + bounty_setup.child_bounty_value, + bounty_setup.reason.clone(), + )?; + bounty_setup.child_bounty_id = ChildBountyCount::::get() - 1; + + ChildBounties::::propose_curator( + RawOrigin::Signed(bounty_setup.curator.clone()).into(), + bounty_setup.bounty_id, + bounty_setup.child_bounty_id, + child_curator_lookup.clone(), + bounty_setup.child_bounty_fee, + )?; + }: _(RawOrigin::Signed(bounty_setup.child_curator), bounty_setup.bounty_id, + bounty_setup.child_bounty_id) + + // Worst case when curator is inactive and any sender un-assigns the curator. + unassign_curator { + setup_pot_account::(); + let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; + Bounties::::on_initialize(T::BlockNumber::zero()); + frame_system::Pallet::::set_block_number(T::BountyUpdatePeriod::get() + 1u32.into()); + let caller = whitelisted_caller(); + }: _(RawOrigin::Signed(caller), bounty_setup.bounty_id, + bounty_setup.child_bounty_id) + + award_child_bounty { + setup_pot_account::(); + let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; + let beneficiary_account: T::AccountId = account("beneficiary", 0, SEED); + let beneficiary = T::Lookup::unlookup(beneficiary_account.clone()); + }: _(RawOrigin::Signed(bounty_setup.child_curator), bounty_setup.bounty_id, + bounty_setup.child_bounty_id, beneficiary) + verify { + assert_last_event::(Event::Awarded { + index: bounty_setup.bounty_id, + child_index: bounty_setup.child_bounty_id, + beneficiary: beneficiary_account + }.into()) + } + + claim_child_bounty { + setup_pot_account::(); + let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; + let beneficiary_account: T::AccountId = account("beneficiary", 0, SEED); + let beneficiary = T::Lookup::unlookup(beneficiary_account.clone()); + + ChildBounties::::award_child_bounty( + RawOrigin::Signed(bounty_setup.child_curator.clone()).into(), + bounty_setup.bounty_id, + bounty_setup.child_bounty_id, + beneficiary + )?; + + let beneficiary_account: T::AccountId = account("beneficiary", 0, SEED); + let beneficiary = T::Lookup::unlookup(beneficiary_account.clone()); + + frame_system::Pallet::::set_block_number(T::BountyDepositPayoutDelay::get()); + ensure!(T::Currency::free_balance(&beneficiary_account).is_zero(), + "Beneficiary already has balance."); + + }: _(RawOrigin::Signed(bounty_setup.curator), bounty_setup.bounty_id, + bounty_setup.child_bounty_id) + verify { + ensure!(!T::Currency::free_balance(&beneficiary_account).is_zero(), + "Beneficiary didn't get paid."); + } + + // Best case scenario. + close_child_bounty_added { + setup_pot_account::(); + let mut bounty_setup = activate_bounty::(0, T::MaximumReasonLength::get())?; + + ChildBounties::::add_child_bounty( + RawOrigin::Signed(bounty_setup.curator.clone()).into(), + bounty_setup.bounty_id, + bounty_setup.child_bounty_value, + bounty_setup.reason.clone(), + )?; + bounty_setup.child_bounty_id = ChildBountyCount::::get() - 1; + + }: close_child_bounty(RawOrigin::Root, bounty_setup.bounty_id, + bounty_setup.child_bounty_id) + verify { + assert_last_event::(Event::Canceled { + index: bounty_setup.bounty_id, + child_index: bounty_setup.child_bounty_id + }.into()) + } + + // Worst case scenario. + close_child_bounty_active { + setup_pot_account::(); + let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; + Bounties::::on_initialize(T::BlockNumber::zero()); + }: close_child_bounty(RawOrigin::Root, bounty_setup.bounty_id, bounty_setup.child_bounty_id) + verify { + assert_last_event::(Event::Canceled { + index: bounty_setup.bounty_id, + child_index: bounty_setup.child_bounty_id, + }.into()) + } + + impl_benchmark_test_suite!(ChildBounties, crate::tests::new_test_ext(), crate::tests::Test) +} diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs new file mode 100644 index 0000000000000..3aa160277c82b --- /dev/null +++ b/frame/child-bounties/src/lib.rs @@ -0,0 +1,897 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Child Bounties Pallet ( pallet-child-bounties ) +//! +//! ## Child Bounty +//! +//! > NOTE: This pallet is tightly coupled with pallet-treasury and pallet-bounties. +//! +//! With child bounties, a large bounty proposal can be divided into smaller chunks, +//! for parallel execution, and for efficient governance and tracking of spent funds. +//! A child-bounty is a smaller piece of work, extracted from a parent bounty. +//! A curator is assigned after the child-bounty is created by the parent bounty curator, +//! to be delegated with the responsibility of assigning a payout address once the specified +//! set of tasks is completed. +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! Child Bounty protocol: +//! - `add_child_bounty` - Add a child-bounty for a parent-bounty to for dividing the work in +//! smaller tasks. +//! - `propose_curator` - Assign an account to a child-bounty as candidate curator. +//! - `accept_curator` - Accept a child-bounty assignment from the parent-bounty curator, setting a +//! curator deposit. +//! - `award_child_bounty` - Close and pay out the specified amount for the completed work. +//! - `claim_child_bounty` - Claim a specific child-bounty amount from the payout address. +//! - `unassign_curator` - Unassign an accepted curator from a specific child-bounty. +//! - `close_child_bounty` - Cancel the child-bounty for a specific treasury amount and close the +//! bounty. + +// Most of the business logic in this pallet has been +// originally contributed by "https://github.com/shamb0", +// as part of the PR - https://github.com/paritytech/substrate/pull/7965. +// The code has been moved here and then refactored in order to +// extract child-bounties as a separate pallet. + +#![cfg_attr(not(feature = "std"), no_std)] + +mod benchmarking; +mod tests; +pub mod weights; + +use sp_std::prelude::*; + +use frame_support::traits::{ + Currency, + ExistenceRequirement::{AllowDeath, KeepAlive}, + Get, OnUnbalanced, ReservableCurrency, WithdrawReasons, +}; + +use sp_runtime::{ + traits::{AccountIdConversion, BadOrigin, CheckedSub, Saturating, StaticLookup, Zero}, + DispatchResult, Permill, RuntimeDebug, +}; + +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; +use pallet_bounties::BountyStatus; +use scale_info::TypeInfo; +pub use weights::WeightInfo; + +pub use pallet::*; + +type BalanceOf = pallet_treasury::BalanceOf; +type BountiesError = pallet_bounties::Error; +type BountyIndex = pallet_bounties::BountyIndex; + +/// A child bounty proposal. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct ChildBounty { + /// The parent of this child-bounty. + parent_bounty: BountyIndex, + /// The (total) amount that should be paid if this child-bounty is rewarded. + value: Balance, + /// The child bounty curator fee. + fee: Balance, + /// The deposit of child-bounty curator. + curator_deposit: Balance, + /// The status of this child-bounty. + status: ChildBountyStatus, +} + +/// The status of a child-bounty. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum ChildBountyStatus { + /// The child-bounty is added and waiting for curator assignment. + Added, + /// A curator has been proposed by the parent-bounty curator. Waiting for + /// acceptance from the child-bounty curator. + CuratorProposed { + /// The assigned child-bounty curator of this bounty. + curator: AccountId, + }, + /// The child-bounty is active and waiting to be awarded. + Active { + /// The curator of this child-bounty. + curator: AccountId, + }, + /// The child-bounty is awarded and waiting to released after a delay. + PendingPayout { + /// The curator of this child-bounty. + curator: AccountId, + /// The beneficiary of the child-bounty. + beneficiary: AccountId, + /// When the child-bounty can be claimed. + unlock_at: BlockNumber, + }, +} + +#[frame_support::pallet] +pub mod pallet { + + use super::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: + frame_system::Config + pallet_treasury::Config + pallet_bounties::Config + { + /// Maximum number of child-bounties that can be added to a parent bounty. + #[pallet::constant] + type MaxActiveChildBountyCount: Get; + + /// Minimum value for a child-bounty. + #[pallet::constant] + type ChildBountyValueMinimum: Get>; + + /// Percentage of child-bounty value to be reserved as curator deposit + /// when curator fee is zero. + #[pallet::constant] + type ChildBountyCuratorDepositBase: Get; + + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::error] + pub enum Error { + /// The parent bounty is not in active state. + ParentBountyNotActive, + /// The bounty balance is not enough to add new child-bounty. + InsufficientBountyBalance, + /// Number of child-bounties exceeds limit `MaxActiveChildBountyCount`. + TooManyChildBounties, + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A child-bounty is added. + Added { index: BountyIndex, child_index: BountyIndex }, + /// A child-bounty is awarded to a beneficiary. + Awarded { index: BountyIndex, child_index: BountyIndex, beneficiary: T::AccountId }, + /// A child-bounty is claimed by beneficiary. + Claimed { + index: BountyIndex, + child_index: BountyIndex, + payout: BalanceOf, + beneficiary: T::AccountId, + }, + /// A child-bounty is cancelled. + Canceled { index: BountyIndex, child_index: BountyIndex }, + } + + /// Number of total child bounties. + #[pallet::storage] + #[pallet::getter(fn child_bounty_count)] + pub type ChildBountyCount = StorageValue<_, BountyIndex, ValueQuery>; + + /// Number of child-bounties per parent bounty. + /// Map of parent bounty index to number of child bounties. + #[pallet::storage] + #[pallet::getter(fn parent_child_bounties)] + pub type ParentChildBounties = + StorageMap<_, Twox64Concat, BountyIndex, u32, ValueQuery>; + + /// Child-bounties that have been added. + #[pallet::storage] + #[pallet::getter(fn child_bounties)] + pub type ChildBounties = StorageDoubleMap< + _, + Twox64Concat, + BountyIndex, + Twox64Concat, + BountyIndex, + ChildBounty, T::BlockNumber>, + >; + + /// The description of each child-bounty. + #[pallet::storage] + #[pallet::getter(fn child_bounty_descriptions)] + pub type ChildBountyDescriptions = + StorageMap<_, Twox64Concat, BountyIndex, BoundedVec>; + + /// The cumulative child-bounty curator fee for each parent bounty. + #[pallet::storage] + #[pallet::getter(fn children_curator_fees)] + pub type ChildrenCuratorFees = + StorageMap<_, Twox64Concat, BountyIndex, BalanceOf, ValueQuery>; + + #[pallet::call] + impl Pallet { + /// Add a new child-bounty. + /// + /// The dispatch origin for this call must be the curator of parent + /// bounty and the parent bounty must be in "active" state. + /// + /// Child-bounty gets added successfully & fund gets transferred from + /// parent bounty to child-bounty account, if parent bounty has enough + /// funds, else the call fails. + /// + /// Upper bound to maximum number of active child-bounties that can be + /// added are managed via runtime trait config + /// [`Config::MaxActiveChildBountyCount`]. + /// + /// If the call is success, the status of child-bounty is updated to + /// "Added". + /// + /// - `parent_bounty_id`: Index of parent bounty for which child-bounty is being added. + /// - `value`: Value for executing the proposal. + /// - `description`: Text description for the child-bounty. + #[pallet::weight(::WeightInfo::add_child_bounty(description.len() as u32))] + pub fn add_child_bounty( + origin: OriginFor, + #[pallet::compact] parent_bounty_id: BountyIndex, + #[pallet::compact] value: BalanceOf, + description: Vec, + ) -> DispatchResult { + let signer = ensure_signed(origin)?; + + // Verify the arguments. + let bounded_description = + description.try_into().map_err(|_| BountiesError::::ReasonTooBig)?; + ensure!(value >= T::ChildBountyValueMinimum::get(), BountiesError::::InvalidValue); + ensure!( + Self::parent_child_bounties(parent_bounty_id) <= + T::MaxActiveChildBountyCount::get() as u32, + Error::::TooManyChildBounties, + ); + + let (curator, _) = Self::ensure_bounty_active(parent_bounty_id)?; + ensure!(signer == curator, BountiesError::::RequireCurator); + + // Read parent bounty account info. + let parent_bounty_account = + pallet_bounties::Pallet::::bounty_account_id(parent_bounty_id); + + // Ensure parent bounty has enough balance after adding child-bounty. + let bounty_balance = T::Currency::free_balance(&parent_bounty_account); + let new_bounty_balance = bounty_balance + .checked_sub(&value) + .ok_or(Error::::InsufficientBountyBalance)?; + T::Currency::ensure_can_withdraw( + &parent_bounty_account, + value, + WithdrawReasons::TRANSFER, + new_bounty_balance, + )?; + + // Get child-bounty ID. + let child_bounty_id = Self::child_bounty_count(); + let child_bounty_account = Self::child_bounty_account_id(child_bounty_id); + + // Transfer funds from parent bounty to child-bounty. + T::Currency::transfer(&parent_bounty_account, &child_bounty_account, value, KeepAlive)?; + + // Increment the active child-bounty count. + >::mutate(parent_bounty_id, |count| count.saturating_inc()); + >::put(child_bounty_id.saturating_add(1)); + + // Create child-bounty instance. + Self::create_child_bounty( + parent_bounty_id, + child_bounty_id, + value, + bounded_description, + ); + Ok(()) + } + + /// Propose curator for funded child-bounty. + /// + /// The dispatch origin for this call must be curator of parent bounty. + /// + /// Parent bounty must be in active state, for this child-bounty call to + /// work. + /// + /// Child-bounty must be in "Added" state, for processing the call. And + /// state of child-bounty is moved to "CuratorProposed" on successful + /// call completion. + /// + /// - `parent_bounty_id`: Index of parent bounty. + /// - `child_bounty_id`: Index of child bounty. + /// - `curator`: Address of child-bounty curator. + /// - `fee`: payment fee to child-bounty curator for execution. + #[pallet::weight(::WeightInfo::propose_curator())] + pub fn propose_curator( + origin: OriginFor, + #[pallet::compact] parent_bounty_id: BountyIndex, + #[pallet::compact] child_bounty_id: BountyIndex, + curator: ::Source, + #[pallet::compact] fee: BalanceOf, + ) -> DispatchResult { + let signer = ensure_signed(origin)?; + let child_bounty_curator = T::Lookup::lookup(curator)?; + + let (curator, _) = Self::ensure_bounty_active(parent_bounty_id)?; + ensure!(signer == curator, BountiesError::::RequireCurator); + + // Mutate the child-bounty instance. + ChildBounties::::try_mutate_exists( + parent_bounty_id, + child_bounty_id, + |maybe_child_bounty| -> DispatchResult { + let mut child_bounty = + maybe_child_bounty.as_mut().ok_or(BountiesError::::InvalidIndex)?; + + // Ensure child-bounty is in expected state. + ensure!( + child_bounty.status == ChildBountyStatus::Added, + BountiesError::::UnexpectedStatus, + ); + + // Ensure child-bounty curator fee is less than child-bounty value. + ensure!(fee < child_bounty.value, BountiesError::::InvalidFee); + + // Add child-bounty curator fee to the cumulative sum. To be + // subtracted from the parent bounty curator when claiming + // bounty. + ChildrenCuratorFees::::mutate(parent_bounty_id, |value| { + *value = value.saturating_add(fee) + }); + + // Update the child-bounty curator fee. + child_bounty.fee = fee; + + // Update the child-bounty state. + child_bounty.status = + ChildBountyStatus::CuratorProposed { curator: child_bounty_curator }; + + Ok(()) + }, + ) + } + + /// Accept the curator role for the child-bounty. + /// + /// The dispatch origin for this call must be the curator of this + /// child-bounty. + /// + /// A deposit will be reserved from the curator and refund upon + /// successful payout or cancellation. + /// + /// Fee for curator is deducted from curator fee of parent bounty. + /// + /// Parent bounty must be in active state, for this child-bounty call to + /// work. + /// + /// Child-bounty must be in "CuratorProposed" state, for processing the + /// call. And state of child-bounty is moved to "Active" on successful + /// call completion. + /// + /// - `parent_bounty_id`: Index of parent bounty. + /// - `child_bounty_id`: Index of child bounty. + #[pallet::weight(::WeightInfo::accept_curator())] + pub fn accept_curator( + origin: OriginFor, + #[pallet::compact] parent_bounty_id: BountyIndex, + #[pallet::compact] child_bounty_id: BountyIndex, + ) -> DispatchResult { + let signer = ensure_signed(origin)?; + + let _ = Self::ensure_bounty_active(parent_bounty_id)?; + // Mutate child-bounty. + ChildBounties::::try_mutate_exists( + parent_bounty_id, + child_bounty_id, + |maybe_child_bounty| -> DispatchResult { + let mut child_bounty = + maybe_child_bounty.as_mut().ok_or(BountiesError::::InvalidIndex)?; + + // Ensure child-bounty is in expected state. + if let ChildBountyStatus::CuratorProposed { ref curator } = child_bounty.status + { + ensure!(signer == *curator, BountiesError::::RequireCurator); + + // Reserve child-bounty curator deposit. Curator deposit + // is reserved based on a percentage of child-bounty + // value instead of fee, to avoid no deposit in case the + // fee is set as zero. + let deposit = T::ChildBountyCuratorDepositBase::get() * child_bounty.value; + T::Currency::reserve(curator, deposit)?; + child_bounty.curator_deposit = deposit; + + child_bounty.status = + ChildBountyStatus::Active { curator: curator.clone() }; + Ok(()) + } else { + Err(BountiesError::::UnexpectedStatus.into()) + } + }, + ) + } + + /// Unassign curator from a child-bounty. + /// + /// The dispatch origin for this call can be either `RejectOrigin`, or + /// the curator of the parent bounty, or any signed origin. + /// + /// For the origin other than T::RejectOrigin and the child-bounty + /// curator, parent-bounty must be in active state, for this call to + /// work. We allow child-bounty curator and T::RejectOrigin to execute + /// this call irrespective of the parent-bounty state. + /// + /// If this function is called by the `RejectOrigin` or the + /// parent-bounty curator, we assume that the child-bounty curator is + /// malicious or inactive. As a result, child-bounty curator deposit is + /// slashed. + /// + /// If the origin is the child-bounty curator, we take this as a sign + /// that they are unable to do their job, and are willingly giving up. + /// We could slash the deposit, but for now we allow them to unreserve + /// their deposit and exit without issue. (We may want to change this if + /// it is abused.) + /// + /// Finally, the origin can be anyone iff the child-bounty curator is + /// "inactive". Expiry update due of parent bounty is used to estimate + /// inactive state of child-bounty curator. + /// + /// This allows anyone in the community to call out that a child-bounty + /// curator is not doing their due diligence, and we should pick a new + /// one. In this case the child-bounty curator deposit is slashed. + /// + /// State of child-bounty is moved to Added state on successful call + /// completion. + /// + /// - `parent_bounty_id`: Index of parent bounty. + /// - `child_bounty_id`: Index of child bounty. + #[pallet::weight(::WeightInfo::unassign_curator())] + pub fn unassign_curator( + origin: OriginFor, + #[pallet::compact] parent_bounty_id: BountyIndex, + #[pallet::compact] child_bounty_id: BountyIndex, + ) -> DispatchResult { + let maybe_sender = ensure_signed(origin.clone()) + .map(Some) + .or_else(|_| T::RejectOrigin::ensure_origin(origin).map(|_| None))?; + + ChildBounties::::try_mutate_exists( + parent_bounty_id, + child_bounty_id, + |maybe_child_bounty| -> DispatchResult { + let mut child_bounty = + maybe_child_bounty.as_mut().ok_or(BountiesError::::InvalidIndex)?; + + let slash_curator = |curator: &T::AccountId, + curator_deposit: &mut BalanceOf| { + let imbalance = T::Currency::slash_reserved(curator, *curator_deposit).0; + T::OnSlash::on_unbalanced(imbalance); + *curator_deposit = Zero::zero(); + }; + + match child_bounty.status { + ChildBountyStatus::Added => { + // No curator to unassign at this point. + return Err(BountiesError::::UnexpectedStatus.into()) + }, + ChildBountyStatus::CuratorProposed { ref curator } => { + // A child-bounty curator has been proposed, but not accepted yet. + // Either `RejectOrigin`, parent-bounty curator or the proposed + // child-bounty curator can unassign the child-bounty curator. + ensure!( + maybe_sender.map_or(true, |sender| { + sender == *curator || + Self::ensure_bounty_active(parent_bounty_id) + .map_or(false, |(parent_curator, _)| { + sender == parent_curator + }) + }), + BadOrigin + ); + // Continue to change bounty status below. + }, + ChildBountyStatus::Active { ref curator } => { + // The child-bounty is active. + match maybe_sender { + // If the `RejectOrigin` is calling this function, slash the curator + // deposit. + None => { + slash_curator(curator, &mut child_bounty.curator_deposit); + // Continue to change child-bounty status below. + }, + Some(sender) if sender == *curator => { + // This is the child-bounty curator, willingly giving up their + // role. Give back their deposit. + T::Currency::unreserve(&curator, child_bounty.curator_deposit); + // Reset curator deposit. + child_bounty.curator_deposit = Zero::zero(); + // Continue to change bounty status below. + }, + Some(sender) => { + let (parent_curator, update_due) = + Self::ensure_bounty_active(parent_bounty_id)?; + if sender == parent_curator || + update_due < frame_system::Pallet::::block_number() + { + // Slash the child-bounty curator if + // + the call is made by the parent-bounty curator. + // + or the curator is inactive. + slash_curator(curator, &mut child_bounty.curator_deposit); + // Continue to change bounty status below. + } else { + // Curator has more time to give an update. + return Err(BountiesError::::Premature.into()) + } + }, + } + }, + ChildBountyStatus::PendingPayout { ref curator, .. } => { + let (parent_curator, _) = Self::ensure_bounty_active(parent_bounty_id)?; + ensure!( + maybe_sender.map_or(true, |sender| parent_curator == sender), + BadOrigin, + ); + slash_curator(curator, &mut child_bounty.curator_deposit); + // Continue to change child-bounty status below. + }, + }; + // Move the child-bounty state to Added. + child_bounty.status = ChildBountyStatus::Added; + Ok(()) + }, + ) + } + + /// Award child-bounty to a beneficiary. + /// + /// The beneficiary will be able to claim the funds after a delay. + /// + /// The dispatch origin for this call must be the master curator or + /// curator of this child-bounty. + /// + /// Parent bounty must be in active state, for this child-bounty call to + /// work. + /// + /// Child-bounty must be in active state, for processing the call. And + /// state of child-bounty is moved to "PendingPayout" on successful call + /// completion. + /// + /// - `parent_bounty_id`: Index of parent bounty. + /// - `child_bounty_id`: Index of child bounty. + /// - `beneficiary`: Beneficiary account. + #[pallet::weight(::WeightInfo::award_child_bounty())] + pub fn award_child_bounty( + origin: OriginFor, + #[pallet::compact] parent_bounty_id: BountyIndex, + #[pallet::compact] child_bounty_id: BountyIndex, + beneficiary: ::Source, + ) -> DispatchResult { + let signer = ensure_signed(origin)?; + let beneficiary = T::Lookup::lookup(beneficiary)?; + + // Ensure parent bounty exists, and is active. + let (parent_curator, _) = Self::ensure_bounty_active(parent_bounty_id)?; + + ChildBounties::::try_mutate_exists( + parent_bounty_id, + child_bounty_id, + |maybe_child_bounty| -> DispatchResult { + let mut child_bounty = + maybe_child_bounty.as_mut().ok_or(BountiesError::::InvalidIndex)?; + + // Ensure child-bounty is in active state. + if let ChildBountyStatus::Active { ref curator } = child_bounty.status { + ensure!( + signer == *curator || signer == parent_curator, + BountiesError::::RequireCurator, + ); + // Move the child-bounty state to pending payout. + child_bounty.status = ChildBountyStatus::PendingPayout { + curator: signer, + beneficiary: beneficiary.clone(), + unlock_at: frame_system::Pallet::::block_number() + + T::BountyDepositPayoutDelay::get(), + }; + Ok(()) + } else { + Err(BountiesError::::UnexpectedStatus.into()) + } + }, + )?; + + // Trigger the event Awarded. + Self::deposit_event(Event::::Awarded { + index: parent_bounty_id, + child_index: child_bounty_id, + beneficiary, + }); + + Ok(()) + } + + /// Claim the payout from an awarded child-bounty after payout delay. + /// + /// The dispatch origin for this call may be any signed origin. + /// + /// Call works independent of parent bounty state, No need for parent + /// bounty to be in active state. + /// + /// The Beneficiary is paid out with agreed bounty value. Curator fee is + /// paid & curator deposit is unreserved. + /// + /// Child-bounty must be in "PendingPayout" state, for processing the + /// call. And instance of child-bounty is removed from the state on + /// successful call completion. + /// + /// - `parent_bounty_id`: Index of parent bounty. + /// - `child_bounty_id`: Index of child bounty. + #[pallet::weight(::WeightInfo::claim_child_bounty())] + pub fn claim_child_bounty( + origin: OriginFor, + #[pallet::compact] parent_bounty_id: BountyIndex, + #[pallet::compact] child_bounty_id: BountyIndex, + ) -> DispatchResult { + let _ = ensure_signed(origin)?; + + // Ensure child-bounty is in expected state. + ChildBounties::::try_mutate_exists( + parent_bounty_id, + child_bounty_id, + |maybe_child_bounty| -> DispatchResult { + let child_bounty = + maybe_child_bounty.as_mut().ok_or(BountiesError::::InvalidIndex)?; + + if let ChildBountyStatus::PendingPayout { + ref curator, + ref beneficiary, + ref unlock_at, + } = child_bounty.status + { + // Ensure block number is elapsed for processing the + // claim. + ensure!( + frame_system::Pallet::::block_number() >= *unlock_at, + BountiesError::::Premature, + ); + + // Make curator fee payment. + let child_bounty_account = Self::child_bounty_account_id(child_bounty_id); + let balance = T::Currency::free_balance(&child_bounty_account); + let curator_fee = child_bounty.fee.min(balance); + let payout = balance.saturating_sub(curator_fee); + + // Unreserve the curator deposit. Should not fail + // because the deposit is always reserved when curator is + // assigned. + let _ = T::Currency::unreserve(&curator, child_bounty.curator_deposit); + + // Make payout to child-bounty curator. + // Should not fail because curator fee is always less than bounty value. + let fee_transfer_result = T::Currency::transfer( + &child_bounty_account, + &curator, + curator_fee, + AllowDeath, + ); + debug_assert!(fee_transfer_result.is_ok()); + + // Make payout to beneficiary. + // Should not fail. + let payout_transfer_result = T::Currency::transfer( + &child_bounty_account, + beneficiary, + payout, + AllowDeath, + ); + debug_assert!(payout_transfer_result.is_ok()); + + // Trigger the Claimed event. + Self::deposit_event(Event::::Claimed { + index: parent_bounty_id, + child_index: child_bounty_id, + payout, + beneficiary: beneficiary.clone(), + }); + + // Update the active child-bounty tracking count. + >::mutate(parent_bounty_id, |count| { + count.saturating_dec() + }); + + // Remove the child-bounty description. + >::remove(child_bounty_id); + + // Remove the child-bounty instance from the state. + *maybe_child_bounty = None; + + Ok(()) + } else { + Err(BountiesError::::UnexpectedStatus.into()) + } + }, + ) + } + + /// Cancel a proposed or active child-bounty. Child-bounty account funds + /// are transferred to parent bounty account. The child-bounty curator + /// deposit may be unreserved if possible. + /// + /// The dispatch origin for this call must be either parent curator or + /// `T::RejectOrigin`. + /// + /// If the state of child-bounty is `Active`, curator deposit is + /// unreserved. + /// + /// If the state of child-bounty is `PendingPayout`, call fails & + /// returns `PendingPayout` error. + /// + /// For the origin other than T::RejectOrigin, parent bounty must be in + /// active state, for this child-bounty call to work. For origin + /// T::RejectOrigin execution is forced. + /// + /// Instance of child-bounty is removed from the state on successful + /// call completion. + /// + /// - `parent_bounty_id`: Index of parent bounty. + /// - `child_bounty_id`: Index of child bounty. + #[pallet::weight(::WeightInfo::close_child_bounty_added() + .max(::WeightInfo::close_child_bounty_active()))] + pub fn close_child_bounty( + origin: OriginFor, + #[pallet::compact] parent_bounty_id: BountyIndex, + #[pallet::compact] child_bounty_id: BountyIndex, + ) -> DispatchResult { + let maybe_sender = ensure_signed(origin.clone()) + .map(Some) + .or_else(|_| T::RejectOrigin::ensure_origin(origin).map(|_| None))?; + + // Ensure parent bounty exist, get parent curator. + let (parent_curator, _) = Self::ensure_bounty_active(parent_bounty_id)?; + + ensure!(maybe_sender.map_or(true, |sender| parent_curator == sender), BadOrigin); + + Self::impl_close_child_bounty(parent_bounty_id, child_bounty_id)?; + Ok(()) + } + } +} + +impl Pallet { + /// The account ID of a child-bounty account. + pub fn child_bounty_account_id(id: BountyIndex) -> T::AccountId { + // This function is taken from the parent (bounties) pallet, but the + // prefix is changed to have different AccountId when the index of + // parent and child is same. + T::PalletId::get().into_sub_account(("cb", id)) + } + + fn create_child_bounty( + parent_bounty_id: BountyIndex, + child_bounty_id: BountyIndex, + child_bounty_value: BalanceOf, + description: BoundedVec, + ) { + let child_bounty = ChildBounty { + parent_bounty: parent_bounty_id, + value: child_bounty_value, + fee: 0u32.into(), + curator_deposit: 0u32.into(), + status: ChildBountyStatus::Added, + }; + ChildBounties::::insert(parent_bounty_id, child_bounty_id, &child_bounty); + ChildBountyDescriptions::::insert(child_bounty_id, description); + Self::deposit_event(Event::Added { index: parent_bounty_id, child_index: child_bounty_id }); + } + + fn ensure_bounty_active( + bounty_id: BountyIndex, + ) -> Result<(T::AccountId, T::BlockNumber), DispatchError> { + let parent_bounty = pallet_bounties::Pallet::::bounties(bounty_id) + .ok_or(BountiesError::::InvalidIndex)?; + if let BountyStatus::Active { curator, update_due } = parent_bounty.get_status() { + Ok((curator, update_due)) + } else { + Err(Error::::ParentBountyNotActive.into()) + } + } + + fn impl_close_child_bounty( + parent_bounty_id: BountyIndex, + child_bounty_id: BountyIndex, + ) -> DispatchResult { + ChildBounties::::try_mutate_exists( + parent_bounty_id, + child_bounty_id, + |maybe_child_bounty| -> DispatchResult { + let child_bounty = + maybe_child_bounty.as_mut().ok_or(BountiesError::::InvalidIndex)?; + + match &child_bounty.status { + ChildBountyStatus::Added | ChildBountyStatus::CuratorProposed { .. } => { + // Nothing extra to do besides the removal of the child-bounty below. + }, + ChildBountyStatus::Active { curator } => { + // Cancelled by master curator or RejectOrigin, + // refund deposit of the working child-bounty curator. + let _ = T::Currency::unreserve(curator, child_bounty.curator_deposit); + // Then execute removal of the child-bounty below. + }, + ChildBountyStatus::PendingPayout { .. } => { + // Child-bounty is already in pending payout. If parent + // curator or RejectOrigin wants to close this + // child-bounty, it should mean the child-bounty curator + // was acting maliciously. So first unassign the + // child-bounty curator, slashing their deposit. + return Err(BountiesError::::PendingPayout.into()) + }, + } + + // Revert the curator fee back to parent-bounty curator & + // reduce the active child-bounty count. + ChildrenCuratorFees::::mutate(parent_bounty_id, |value| { + *value = value.saturating_sub(child_bounty.fee) + }); + >::mutate(parent_bounty_id, |count| { + *count = count.saturating_sub(1) + }); + + // Transfer fund from child-bounty to parent bounty. + let parent_bounty_account = + pallet_bounties::Pallet::::bounty_account_id(parent_bounty_id); + let child_bounty_account = Self::child_bounty_account_id(child_bounty_id); + let balance = T::Currency::free_balance(&child_bounty_account); + let transfer_result = T::Currency::transfer( + &child_bounty_account, + &parent_bounty_account, + balance, + AllowDeath, + ); // Should not fail; child bounty account gets this balance during creation. + debug_assert!(transfer_result.is_ok()); + + // Remove the child-bounty description. + >::remove(child_bounty_id); + + *maybe_child_bounty = None; + + Self::deposit_event(Event::::Canceled { + index: parent_bounty_id, + child_index: child_bounty_id, + }); + Ok(()) + }, + ) + } +} + +// Implement ChildBountyManager to connect with the bounties pallet. This is +// where we pass the active child-bounties and child curator fees to the parent +// bounty. +impl pallet_bounties::ChildBountyManager> for Pallet { + fn child_bounties_count( + bounty_id: pallet_bounties::BountyIndex, + ) -> pallet_bounties::BountyIndex { + Self::parent_child_bounties(bounty_id) + } + + fn children_curator_fees(bounty_id: pallet_bounties::BountyIndex) -> BalanceOf { + // This is asked for when the parent bounty is being claimed. No use of + // keeping it in state after that. Hence removing. + let children_fee_total = Self::children_curator_fees(bounty_id); + >::remove(bounty_id); + children_fee_total + } +} diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs new file mode 100644 index 0000000000000..ada13e968c4d4 --- /dev/null +++ b/frame/child-bounties/src/tests.rs @@ -0,0 +1,1219 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Child-bounties pallet tests. + +#![cfg(test)] + +use super::*; +use crate as pallet_child_bounties; +use std::cell::RefCell; + +use frame_support::{ + assert_noop, assert_ok, pallet_prelude::GenesisBuild, parameter_types, traits::OnInitialize, + weights::Weight, PalletId, +}; + +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BadOrigin, BlakeTwo256, IdentityLookup}, + Perbill, Permill, +}; + +use super::Event as ChildBountiesEvent; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; +type BountiesError = pallet_bounties::Error; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Bounties: pallet_bounties::{Pallet, Call, Storage, Event}, + Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event}, + ChildBounties: pallet_child_bounties::{Pallet, Call, Storage, Event}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); +} + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = Call; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u128; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); +} +parameter_types! { + pub const ExistentialDeposit: u64 = 1; +} +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = u64; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} +thread_local! { + static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); +} +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: u64 = 1; + pub const SpendPeriod: u64 = 2; + pub const Burn: Permill = Permill::from_percent(50); + pub const DataDepositPerByte: u64 = 1; + pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub const MaxApprovals: u32 = 100; +} + +impl pallet_treasury::Config for Test { + type PalletId = TreasuryPalletId; + type Currency = pallet_balances::Pallet; + type ApproveOrigin = frame_system::EnsureRoot; + type RejectOrigin = frame_system::EnsureRoot; + type Event = Event; + type OnSlash = (); + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type SpendPeriod = SpendPeriod; + type Burn = Burn; + type BurnDestination = (); + type WeightInfo = (); + type SpendFunds = Bounties; + type MaxApprovals = MaxApprovals; +} +parameter_types! { + pub const BountyDepositBase: u64 = 80; + pub const BountyDepositPayoutDelay: u64 = 3; + pub const BountyUpdatePeriod: u32 = 10; + pub const BountyCuratorDeposit: Permill = Permill::from_percent(50); + pub const BountyValueMinimum: u64 = 5; + pub const MaximumReasonLength: u32 = 300; +} +impl pallet_bounties::Config for Test { + type Event = Event; + type BountyDepositBase = BountyDepositBase; + type BountyDepositPayoutDelay = BountyDepositPayoutDelay; + type BountyUpdatePeriod = BountyUpdatePeriod; + type BountyCuratorDeposit = BountyCuratorDeposit; + type BountyValueMinimum = BountyValueMinimum; + type DataDepositPerByte = DataDepositPerByte; + type MaximumReasonLength = MaximumReasonLength; + type WeightInfo = (); + type ChildBountyManager = ChildBounties; +} +parameter_types! { + pub const MaxActiveChildBountyCount: u32 = 2; + pub const ChildBountyValueMinimum: u64 = 1; + pub const ChildBountyCuratorDepositBase: Permill = Permill::from_percent(10); +} +impl pallet_child_bounties::Config for Test { + type Event = Event; + type MaxActiveChildBountyCount = MaxActiveChildBountyCount; + type ChildBountyValueMinimum = ChildBountyValueMinimum; + type ChildBountyCuratorDepositBase = ChildBountyCuratorDepositBase; + type WeightInfo = (); +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { + // Total issuance will be 200 with treasury account initialized at ED. + balances: vec![(0, 100), (1, 98), (2, 1)], + } + .assimilate_storage(&mut t) + .unwrap(); + GenesisBuild::::assimilate_storage(&pallet_treasury::GenesisConfig, &mut t).unwrap(); + t.into() +} + +fn last_event() -> ChildBountiesEvent { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let Event::ChildBounties(inner) = e { Some(inner) } else { None }) + .last() + .unwrap() +} + +#[test] +fn genesis_config_works() { + new_test_ext().execute_with(|| { + assert_eq!(Treasury::pot(), 0); + assert_eq!(Treasury::proposal_count(), 0); + }); +} + +#[test] +fn minting_works() { + new_test_ext().execute_with(|| { + // Check that accumulate works when we have Some value in Dummy already. + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Treasury::pot(), 100); + }); +} + +#[test] +fn add_child_bounty() { + new_test_ext().execute_with(|| { + // TestProcedure. + // 1, Create bounty & move to active state with enough bounty fund & master-curator. + // 2, Master-curator adds child-bounty child-bounty-1, test for error like RequireCurator + // ,InsufficientProposersBalance, InsufficientBountyBalance with invalid arguments. + // 3, Master-curator adds child-bounty child-bounty-1, moves to "Approved" state & + // test for the event Added. + // 4, Test for DB state of `Bounties` & `ChildBounties`. + // 5, Observe fund transaction moment between Bounty, Child-bounty, + // Curator, child-bounty curator & beneficiary. + + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 4)); + + Balances::make_free_balance_be(&4, 10); + + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + assert_eq!(Balances::free_balance(&4), 8); + assert_eq!(Balances::reserved_balance(&4), 2); + + // Add child-bounty. + // Acc-4 is the master curator. + // Call from invalid origin & check for error "RequireCurator". + assert_noop!( + ChildBounties::add_child_bounty(Origin::signed(0), 0, 10, b"12345-p1".to_vec()), + BountiesError::RequireCurator, + ); + + // Update the master curator balance. + Balances::make_free_balance_be(&4, 101); + + // Master curator fee is reserved on parent bounty account. + assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); + assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); + + assert_noop!( + ChildBounties::add_child_bounty(Origin::signed(4), 0, 50, b"12345-p1".to_vec()), + pallet_balances::Error::::KeepAlive, + ); + + assert_noop!( + ChildBounties::add_child_bounty(Origin::signed(4), 0, 100, b"12345-p1".to_vec()), + Error::::InsufficientBountyBalance, + ); + + // Add child-bounty with valid value, which can be funded by parent bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + + // Check for the event child-bounty added. + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + assert_eq!(Balances::free_balance(4), 101); + assert_eq!(Balances::reserved_balance(4), 2); + + // DB check. + // Check the child-bounty status. + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 0, + curator_deposit: 0, + status: ChildBountyStatus::Added, + } + ); + + // Check the child-bounty count. + assert_eq!(ChildBounties::parent_child_bounties(0), 1); + + // Check the child-bounty description status. + assert_eq!(ChildBounties::child_bounty_descriptions(0).unwrap(), b"12345-p1".to_vec(),); + }); +} + +#[test] +fn child_bounty_assign_curator() { + new_test_ext().execute_with(|| { + // TestProcedure + // 1, Create bounty & move to active state with enough bounty fund & master-curator. + // 2, Master-curator adds child-bounty child-bounty-1, moves to "Active" state. + // 3, Test for DB state of `ChildBounties`. + + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + Balances::make_free_balance_be(&4, 101); + Balances::make_free_balance_be(&8, 101); + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 4)); + + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Bounty account status before adding child-bounty. + assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); + assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); + + // Check the balance of master curator. + // Curator deposit is reserved for master curator on parent bounty. + assert_eq!(Balances::free_balance(4), 99); + assert_eq!(Balances::reserved_balance(4), 2); + + // Add child-bounty. + // Acc-4 is the master curator & make sure enough deposit. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + // Bounty account status after adding child-bounty. + assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 40); + assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); + + // Child-bounty account status. + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 10); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 0, + status: ChildBountyStatus::CuratorProposed { curator: 8 }, + } + ); + + // Check the balance of master curator. + assert_eq!(Balances::free_balance(4), 99); + assert_eq!(Balances::reserved_balance(4), 2); + + assert_noop!( + ChildBounties::accept_curator(Origin::signed(3), 0, 0), + BountiesError::RequireCurator, + ); + + assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 1, + status: ChildBountyStatus::Active { curator: 8 }, + } + ); + + // Deposit for child-bounty curator is reserved. + assert_eq!(Balances::free_balance(8), 100); + assert_eq!(Balances::reserved_balance(8), 1); + + // Bounty account status at exit. + assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 40); + assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); + + // Child-bounty account status at exit. + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 10); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + + // Treasury account status at exit. + assert_eq!(Balances::free_balance(Treasury::account_id()), 26); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + }); +} + +#[test] +fn award_claim_child_bounty() { + new_test_ext().execute_with(|| { + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Balances::free_balance(Treasury::account_id()), 101); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + + // Bounty curator initial balance. + Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. + Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Child-bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + // Propose and accept curator for child-bounty. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + + // Award child-bounty. + // Test for non child-bounty curator. + assert_noop!( + ChildBounties::award_child_bounty(Origin::signed(3), 0, 0, 7), + BountiesError::RequireCurator, + ); + + assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 1, + status: ChildBountyStatus::PendingPayout { + curator: 8, + beneficiary: 7, + unlock_at: 5 + }, + } + ); + + // Claim child-bounty. + // Test for Premature condition. + assert_noop!( + ChildBounties::claim_child_bounty(Origin::signed(7), 0, 0), + BountiesError::Premature + ); + + System::set_block_number(9); + + assert_ok!(ChildBounties::claim_child_bounty(Origin::signed(7), 0, 0)); + + // Ensure child-bounty curator is paid with curator fee & deposit refund. + assert_eq!(Balances::free_balance(8), 103); + assert_eq!(Balances::reserved_balance(8), 0); + + // Ensure executor is paid with beneficiary amount. + assert_eq!(Balances::free_balance(7), 8); + assert_eq!(Balances::reserved_balance(7), 0); + + // Child-bounty account status. + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 0); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + + // Check the child-bounty count. + assert_eq!(ChildBounties::parent_child_bounties(0), 0); + }); +} + +#[test] +fn close_child_bounty_added() { + new_test_ext().execute_with(|| { + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Balances::free_balance(Treasury::account_id()), 101); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + + // Bounty curator initial balance. + Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. + Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Child-bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + System::set_block_number(4); + + // Close child-bounty. + // Wrong origin. + assert_noop!(ChildBounties::close_child_bounty(Origin::signed(7), 0, 0), BadOrigin); + assert_noop!(ChildBounties::close_child_bounty(Origin::signed(8), 0, 0), BadOrigin); + + // Correct origin - parent curator. + assert_ok!(ChildBounties::close_child_bounty(Origin::signed(4), 0, 0)); + + // Check the child-bounty count. + assert_eq!(ChildBounties::parent_child_bounties(0), 0); + + // Parent-bounty account status. + assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); + assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); + + // Child-bounty account status. + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 0); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + }); +} + +#[test] +fn close_child_bounty_active() { + new_test_ext().execute_with(|| { + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Balances::free_balance(Treasury::account_id()), 101); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + + // Bounty curator initial balance. + Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. + Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Child-bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + // Propose and accept curator for child-bounty. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + + // Close child-bounty in active state. + assert_ok!(ChildBounties::close_child_bounty(Origin::signed(4), 0, 0)); + + // Check the child-bounty count. + assert_eq!(ChildBounties::parent_child_bounties(0), 0); + + // Ensure child-bounty curator balance is unreserved. + assert_eq!(Balances::free_balance(8), 101); + assert_eq!(Balances::reserved_balance(8), 0); + + // Parent-bounty account status. + assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); + assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); + + // Child-bounty account status. + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 0); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + }); +} + +#[test] +fn close_child_bounty_pending() { + new_test_ext().execute_with(|| { + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Balances::free_balance(Treasury::account_id()), 101); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + + // Bounty curator initial balance. + Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. + Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Child-bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + // Propose and accept curator for child-bounty. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + + assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + + // Close child-bounty in pending_payout state. + assert_noop!( + ChildBounties::close_child_bounty(Origin::signed(4), 0, 0), + BountiesError::PendingPayout + ); + + // Check the child-bounty count. + assert_eq!(ChildBounties::parent_child_bounties(0), 1); + + // Ensure no changes in child-bounty curator balance. + assert_eq!(Balances::free_balance(8), 100); + assert_eq!(Balances::reserved_balance(8), 1); + + // Child-bounty account status. + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 10); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + }); +} + +#[test] +fn child_bounty_added_unassign_curator() { + new_test_ext().execute_with(|| { + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Balances::free_balance(Treasury::account_id()), 101); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + + // Bounty curator initial balance. + Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. + Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Child-bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + // Unassign curator in added state. + assert_noop!( + ChildBounties::unassign_curator(Origin::signed(4), 0, 0), + BountiesError::UnexpectedStatus + ); + }); +} + +#[test] +fn child_bounty_curator_proposed_unassign_curator() { + new_test_ext().execute_with(|| { + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Balances::free_balance(Treasury::account_id()), 101); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + + // Bounty curator initial balance. + Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. + Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Child-bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + // Propose curator for child-bounty. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 0, + status: ChildBountyStatus::CuratorProposed { curator: 8 }, + } + ); + + // Random account cannot unassign the curator when in proposed state. + assert_noop!(ChildBounties::unassign_curator(Origin::signed(99), 0, 0), BadOrigin); + + // Unassign curator. + assert_ok!(ChildBounties::unassign_curator(Origin::signed(4), 0, 0)); + + // Verify updated child-bounty status. + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 0, + status: ChildBountyStatus::Added, + } + ); + }); +} + +#[test] +fn child_bounty_active_unassign_curator() { + // Covers all scenarios with all origin types. + // Step 1: Setup bounty, child bounty. + // Step 2: Assign, accept curator for child bounty. Unassign from reject origin. Should slash. + // Step 3: Assign, accept another curator for child bounty. Unassign from parent-bounty curator. + // Should slash. Step 4: Assign, accept another curator for child bounty. Unassign from + // child-bounty curator. Should NOT slash. Step 5: Assign, accept another curator for child + // bounty. Unassign from random account. Should slash. + new_test_ext().execute_with(|| { + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Balances::free_balance(Treasury::account_id()), 101); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + + // Bounty curator initial balance. + Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. + Balances::make_free_balance_be(&6, 101); // Child-bounty curator 1. + Balances::make_free_balance_be(&7, 101); // Child-bounty curator 2. + Balances::make_free_balance_be(&8, 101); // Child-bounty curator 3. + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Create Child-bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + System::set_block_number(3); + >::on_initialize(3); + + // Propose and accept curator for child-bounty. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 1, + status: ChildBountyStatus::Active { curator: 8 }, + } + ); + + System::set_block_number(4); + >::on_initialize(4); + + // Unassign curator - from reject origin. + assert_ok!(ChildBounties::unassign_curator(Origin::root(), 0, 0)); + + // Verify updated child-bounty status. + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 0, + status: ChildBountyStatus::Added, + } + ); + + // Ensure child-bounty curator was slashed. + assert_eq!(Balances::free_balance(8), 100); + assert_eq!(Balances::reserved_balance(8), 0); // slashed + + // Propose and accept curator for child-bounty again. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 7, 2)); + assert_ok!(ChildBounties::accept_curator(Origin::signed(7), 0, 0)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 1, + status: ChildBountyStatus::Active { curator: 7 }, + } + ); + + System::set_block_number(5); + >::on_initialize(5); + + // Unassign curator again - from master curator. + assert_ok!(ChildBounties::unassign_curator(Origin::signed(4), 0, 0)); + + // Verify updated child-bounty status. + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 0, + status: ChildBountyStatus::Added, + } + ); + + // Ensure child-bounty curator was slashed. + assert_eq!(Balances::free_balance(7), 100); + assert_eq!(Balances::reserved_balance(7), 0); // slashed + + // Propose and accept curator for child-bounty again. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 6, 2)); + assert_ok!(ChildBounties::accept_curator(Origin::signed(6), 0, 0)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 1, + status: ChildBountyStatus::Active { curator: 6 }, + } + ); + + System::set_block_number(6); + >::on_initialize(6); + + // Unassign curator again - from child-bounty curator. + assert_ok!(ChildBounties::unassign_curator(Origin::signed(6), 0, 0)); + + // Verify updated child-bounty status. + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 0, + status: ChildBountyStatus::Added, + } + ); + + // Ensure child-bounty curator was **not** slashed. + assert_eq!(Balances::free_balance(6), 101); // not slashed + assert_eq!(Balances::reserved_balance(6), 0); + + // Propose and accept curator for child-bounty one last time. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 6, 2)); + assert_ok!(ChildBounties::accept_curator(Origin::signed(6), 0, 0)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 1, + status: ChildBountyStatus::Active { curator: 6 }, + } + ); + + System::set_block_number(7); + >::on_initialize(7); + + // Unassign curator again - from non curator; non reject origin; some random guy. + // Bounty update period is not yet complete. + assert_noop!( + ChildBounties::unassign_curator(Origin::signed(3), 0, 0), + BountiesError::Premature + ); + + System::set_block_number(20); + >::on_initialize(20); + + // Unassign child curator from random account after inactivity. + assert_ok!(ChildBounties::unassign_curator(Origin::signed(3), 0, 0)); + + // Verify updated child-bounty status. + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 0, + status: ChildBountyStatus::Added, + } + ); + + // Ensure child-bounty curator was slashed. + assert_eq!(Balances::free_balance(6), 100); // slashed + assert_eq!(Balances::reserved_balance(6), 0); + }); +} + +#[test] +fn parent_bounty_inactive_unassign_curator_child_bounty() { + // Unassign curator when parent bounty in not in active state. + // This can happen when the curator of parent bounty has been unassigned. + new_test_ext().execute_with(|| { + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Balances::free_balance(Treasury::account_id()), 101); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + + // Bounty curator initial balance. + Balances::make_free_balance_be(&4, 101); // Parent-bounty curator 1. + Balances::make_free_balance_be(&5, 101); // Parent-bounty curator 2. + Balances::make_free_balance_be(&6, 101); // Child-bounty curator 1. + Balances::make_free_balance_be(&7, 101); // Child-bounty curator 2. + Balances::make_free_balance_be(&8, 101); // Child-bounty curator 3. + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Create Child-bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + System::set_block_number(3); + >::on_initialize(3); + + // Propose and accept curator for child-bounty. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 1, + status: ChildBountyStatus::Active { curator: 8 }, + } + ); + + System::set_block_number(4); + >::on_initialize(4); + + // Unassign parent bounty curator. + assert_ok!(Bounties::unassign_curator(Origin::root(), 0)); + + System::set_block_number(5); + >::on_initialize(5); + + // Try unassign child-bounty curator - from non curator; non reject + // origin; some random guy. Bounty update period is not yet complete. + assert_noop!( + ChildBounties::unassign_curator(Origin::signed(3), 0, 0), + Error::::ParentBountyNotActive + ); + + // Unassign curator - from reject origin. + assert_ok!(ChildBounties::unassign_curator(Origin::root(), 0, 0)); + + // Verify updated child-bounty status. + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 0, + status: ChildBountyStatus::Added, + } + ); + + // Ensure child-bounty curator was slashed. + assert_eq!(Balances::free_balance(8), 100); + assert_eq!(Balances::reserved_balance(8), 0); // slashed + + System::set_block_number(6); + >::on_initialize(6); + + // Propose and accept curator for parent-bounty again. + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 5, 6)); + assert_ok!(Bounties::accept_curator(Origin::signed(5), 0)); + + System::set_block_number(7); + >::on_initialize(7); + + // Propose and accept curator for child-bounty again. + assert_ok!(ChildBounties::propose_curator(Origin::signed(5), 0, 0, 7, 2)); + assert_ok!(ChildBounties::accept_curator(Origin::signed(7), 0, 0)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 1, + status: ChildBountyStatus::Active { curator: 7 }, + } + ); + + System::set_block_number(8); + >::on_initialize(8); + + assert_noop!( + ChildBounties::unassign_curator(Origin::signed(3), 0, 0), + BountiesError::Premature + ); + + // Unassign parent bounty curator again. + assert_ok!(Bounties::unassign_curator(Origin::signed(5), 0)); + + System::set_block_number(9); + >::on_initialize(9); + + // Unassign curator again - from master curator. + assert_ok!(ChildBounties::unassign_curator(Origin::signed(7), 0, 0)); + + // Verify updated child-bounty status. + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 0, + status: ChildBountyStatus::Added, + } + ); + + // Ensure child-bounty curator was not slashed. + assert_eq!(Balances::free_balance(7), 101); + assert_eq!(Balances::reserved_balance(7), 0); // slashed + }); +} + +#[test] +fn close_parent_with_child_bounty() { + new_test_ext().execute_with(|| { + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Balances::free_balance(Treasury::account_id()), 101); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + + // Bounty curator initial balance. + Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. + Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + // Try add child-bounty. + // Should fail, parent bounty not active yet. + assert_noop!( + ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec()), + Error::::ParentBountyNotActive + ); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Child-bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + System::set_block_number(4); + >::on_initialize(4); + + // Try close parent-bounty. + // Child bounty active, can't close parent. + assert_noop!( + Bounties::close_bounty(Origin::root(), 0), + BountiesError::HasActiveChildBounty + ); + + System::set_block_number(2); + + // Close child-bounty. + assert_ok!(ChildBounties::close_child_bounty(Origin::root(), 0, 0)); + + // Check the child-bounty count. + assert_eq!(ChildBounties::parent_child_bounties(0), 0); + + // Try close parent-bounty again. + // Should pass this time. + assert_ok!(Bounties::close_bounty(Origin::root(), 0)); + }); +} + +#[test] +fn children_curator_fee_calculation_test() { + // Tests the calculation of subtracting child-bounty curator fee + // from parent bounty fee when claiming bounties. + new_test_ext().execute_with(|| { + // Make the parent bounty. + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Balances::free_balance(Treasury::account_id()), 101); + assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); + + // Bounty curator initial balance. + Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. + Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + + // Child-bounty. + assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); + + System::set_block_number(4); + >::on_initialize(4); + + // Propose curator for child-bounty. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + + // Check curator fee added to the sum. + assert_eq!(ChildBounties::children_curator_fees(0), 2); + + // Accept curator for child-bounty. + assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + + // Award child-bounty. + assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + + assert_eq!( + ChildBounties::child_bounties(0, 0).unwrap(), + ChildBounty { + parent_bounty: 0, + value: 10, + fee: 2, + curator_deposit: 1, + status: ChildBountyStatus::PendingPayout { + curator: 8, + beneficiary: 7, + unlock_at: 7 + }, + } + ); + + System::set_block_number(9); + + // Claim child-bounty. + assert_ok!(ChildBounties::claim_child_bounty(Origin::signed(7), 0, 0)); + + // Check the child-bounty count. + assert_eq!(ChildBounties::parent_child_bounties(0), 0); + + // Award the parent bounty. + assert_ok!(Bounties::award_bounty(Origin::signed(4), 0, 9)); + + System::set_block_number(15); + + // Claim the parent bounty. + assert_ok!(Bounties::claim_bounty(Origin::signed(9), 0)); + + // Ensure parent-bounty curator received correctly reduced fee. + assert_eq!(Balances::free_balance(4), 105); // 101 + 6 - 2 + assert_eq!(Balances::reserved_balance(4), 0); + + // Verify parent-bounty beneficiary balance. + assert_eq!(Balances::free_balance(9), 34); + assert_eq!(Balances::reserved_balance(9), 0); + }); +} diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs new file mode 100644 index 0000000000000..7a52495d980b5 --- /dev/null +++ b/frame/child-bounties/src/weights.rs @@ -0,0 +1,215 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_child_bounties +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-12-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// ./target/release/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet +// pallet_child_bounties +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/child-bounties/src/ +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_child_bounties. +pub trait WeightInfo { + fn add_child_bounty(d: u32, ) -> Weight; + fn propose_curator() -> Weight; + fn accept_curator() -> Weight; + fn unassign_curator() -> Weight; + fn award_child_bounty() -> Weight; + fn claim_child_bounty() -> Weight; + fn close_child_bounty_added() -> Weight; + fn close_child_bounty_active() -> Weight; +} + +/// Weights for pallet_child_bounties using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: ChildBounties ParentChildBounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:0) + // Storage: System Account (r:2 w:2) + // Storage: ChildBounties ChildBountyCount (r:1 w:1) + // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + // Storage: ChildBounties ChildBounties (r:0 w:1) + fn add_child_bounty(d: u32, ) -> Weight { + (113_579_000 as Weight) + // Standard Error: 1_000 + .saturating_add((4_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) + } + // Storage: Bounties Bounties (r:1 w:0) + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + fn propose_curator() -> Weight { + (24_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Bounties Bounties (r:1 w:0) + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn accept_curator() -> Weight { + (55_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:0) + // Storage: System Account (r:1 w:1) + fn unassign_curator() -> Weight { + (61_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Bounties Bounties (r:1 w:0) + // Storage: ChildBounties ChildBounties (r:1 w:1) + fn award_child_bounty() -> Weight { + (42_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: System Account (r:3 w:3) + // Storage: ChildBounties ParentChildBounties (r:1 w:1) + // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + fn claim_child_bounty() -> Weight { + (153_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) + } + // Storage: Bounties Bounties (r:1 w:0) + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + // Storage: ChildBounties ParentChildBounties (r:1 w:1) + // Storage: System Account (r:2 w:2) + // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + fn close_child_bounty_added() -> Weight { + (101_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) + } + // Storage: Bounties Bounties (r:1 w:0) + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: System Account (r:3 w:3) + // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + // Storage: ChildBounties ParentChildBounties (r:1 w:1) + // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + fn close_child_bounty_active() -> Weight { + (130_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(7 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: ChildBounties ParentChildBounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:0) + // Storage: System Account (r:2 w:2) + // Storage: ChildBounties ChildBountyCount (r:1 w:1) + // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + // Storage: ChildBounties ChildBounties (r:0 w:1) + fn add_child_bounty(d: u32, ) -> Weight { + (113_579_000 as Weight) + // Standard Error: 1_000 + .saturating_add((4_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + } + // Storage: Bounties Bounties (r:1 w:0) + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + fn propose_curator() -> Weight { + (24_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Bounties Bounties (r:1 w:0) + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn accept_curator() -> Weight { + (55_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: Bounties Bounties (r:1 w:0) + // Storage: System Account (r:1 w:1) + fn unassign_curator() -> Weight { + (61_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Bounties Bounties (r:1 w:0) + // Storage: ChildBounties ChildBounties (r:1 w:1) + fn award_child_bounty() -> Weight { + (42_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: System Account (r:3 w:3) + // Storage: ChildBounties ParentChildBounties (r:1 w:1) + // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + fn claim_child_bounty() -> Weight { + (153_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + } + // Storage: Bounties Bounties (r:1 w:0) + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + // Storage: ChildBounties ParentChildBounties (r:1 w:1) + // Storage: System Account (r:2 w:2) + // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + fn close_child_bounty_added() -> Weight { + (101_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + } + // Storage: Bounties Bounties (r:1 w:0) + // Storage: ChildBounties ChildBounties (r:1 w:1) + // Storage: System Account (r:3 w:3) + // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + // Storage: ChildBounties ParentChildBounties (r:1 w:1) + // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + fn close_child_bounty_active() -> Weight { + (130_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(7 as Weight)) + } +} From c9cad66c7ed0c2d24ceaf2a5292f1c3188987b0c Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Tue, 7 Dec 2021 20:35:44 -0800 Subject: [PATCH 0311/1472] Add extrinsic to improve position in a bag of bags-list (#9829) * pallet-bags-list: Add `put_in_front_of` extrinsic This PR adds the extrinsic `put_in_front_of` which allows the user to specify a `lighter` and `heavier` account within the same bag. The extrinsic will move `heavier` directly in front of `lighter`. The parameter names refer to the fact that `lighter` must have a lower `VoteWeight` then `heavier`. In the ideal use case, where a user wants to improve the position of their account within a bag, the user would iterate the bag, starting from the head, and find the first node who's `VoteWeight` is less than theirs. They would then supply the `id` of the node as the `lighter` argument and their own `id` as the `heavier` argument. * Test & Benchmarks * Respect line width * Remove List::put_in_fron_of tests; Remove AlreadyHigher error * The dispatch origin for this call must be ... * Add some periods * Add back test to list module: put_in_front_of_exits_early_if_bag_not_found * add test tests::pallet::heavier_is_head_lighter_is_not_terminal * Cater for edge case of heavier being head * Add ExtBuilder::add_aux_data; try to make some tests use simpler data * Update frame/bags-list/src/list/tests.rs * make insert_at_unchecked infallible * Make it permissioned - only callable by heavier * Add test cases for insert_at_unchecked * Move counter update to insert_at; fix comments * Address some feedback * Make voteweight constructed with parameter_types * Always set vote weight for Ids in build * Add skip_genesis_ids * Do not pass weight fn to List put_in_front_of * Remove remants of CounterForListNodes * fmt * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_bags_list --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/bags-list/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Delete messed up weights file * Some place holder stuff so we can run bench in CI * Fix * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_bags_list --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/bags-list/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/bags-list/src/list/mod.rs Co-authored-by: Guillaume Thiolliere * fmt * Log + debug assert when refetching an Id Co-authored-by: Parity Bot Co-authored-by: Guillaume Thiolliere --- frame/bags-list/src/benchmarks.rs | 44 ++++- frame/bags-list/src/lib.rs | 25 +++ frame/bags-list/src/list/mod.rs | 78 +++++++++ frame/bags-list/src/list/tests.rs | 117 ++++++++++++++ frame/bags-list/src/mock.rs | 33 ++-- frame/bags-list/src/tests.rs | 261 +++++++++++++++++++++++++++++- frame/bags-list/src/weights.rs | 32 +++- 7 files changed, 561 insertions(+), 29 deletions(-) diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index 800e668324e0c..41c65978e0d4f 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -19,7 +19,7 @@ use super::*; use crate::list::List; -use frame_benchmarking::{account, whitelisted_caller}; +use frame_benchmarking::{account, whitelist_account, whitelisted_caller}; use frame_election_provider_support::VoteWeightProvider; use frame_support::{assert_ok, traits::Get}; use frame_system::RawOrigin as SystemOrigin; @@ -137,9 +137,41 @@ frame_benchmarking::benchmarks! { ); } - impl_benchmark_test_suite!( - Pallet, - crate::mock::ExtBuilder::default().build(), - crate::mock::Runtime, - ) + put_in_front_of { + // The most expensive case for `put_in_front_of`: + // + // - both heavier's `prev` and `next` are nodes that will need to be read and written. + // - `lighter` is the bag's `head`, so the bag will need to be read and written. + + let bag_thresh = T::BagThresholds::get()[0]; + + // insert the nodes in order + let lighter: T::AccountId = account("lighter", 0, 0); + assert_ok!(List::::insert(lighter.clone(), bag_thresh)); + + let heavier_prev: T::AccountId = account("heavier_prev", 0, 0); + assert_ok!(List::::insert(heavier_prev.clone(), bag_thresh)); + + let heavier: T::AccountId = account("heavier", 0, 0); + assert_ok!(List::::insert(heavier.clone(), bag_thresh)); + + let heavier_next: T::AccountId = account("heavier_next", 0, 0); + assert_ok!(List::::insert(heavier_next.clone(), bag_thresh)); + + T::VoteWeightProvider::set_vote_weight_of(&lighter, bag_thresh - 1); + T::VoteWeightProvider::set_vote_weight_of(&heavier, bag_thresh); + + assert_eq!( + List::::iter().map(|n| n.id().clone()).collect::>(), + vec![lighter.clone(), heavier_prev.clone(), heavier.clone(), heavier_next.clone()] + ); + + whitelist_account!(heavier); + }: _(SystemOrigin::Signed(heavier.clone()), lighter.clone()) + verify { + assert_eq!( + List::::iter().map(|n| n.id().clone()).collect::>(), + vec![heavier, lighter, heavier_prev, heavier_next] + ) + } } diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index d3be2c29533f9..193a334cf08f6 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -173,6 +173,17 @@ pub mod pallet { Rebagged { who: T::AccountId, from: VoteWeight, to: VoteWeight }, } + #[pallet::error] + #[cfg_attr(test, derive(PartialEq))] + pub enum Error { + /// Attempted to place node in front of a node in another bag. + NotInSameBag, + /// Id not found in list. + IdNotFound, + /// An Id does not have a greater vote weight than another Id. + NotHeavier, + } + #[pallet::call] impl Pallet { /// Declare that some `dislocated` account has, through rewards or penalties, sufficiently @@ -190,6 +201,20 @@ pub mod pallet { let _ = Pallet::::do_rebag(&dislocated, current_weight); Ok(()) } + + /// Move the caller's Id directly in front of `lighter`. + /// + /// The dispatch origin for this call must be _Signed_ and can only be called by the Id of + /// the account going in front of `lighter`. + /// + /// Only works if + /// - both nodes are within the same bag, + /// - and `origin` has a greater `VoteWeight` than `lighter`. + #[pallet::weight(T::WeightInfo::put_in_front_of())] + pub fn put_in_front_of(origin: OriginFor, lighter: T::AccountId) -> DispatchResult { + let heavier = ensure_signed(origin)?; + List::::put_in_front_of(&lighter, &heavier).map_err(Into::into) + } } #[pallet::hooks] diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 1ec4996c26fd3..4524101d793cf 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -376,6 +376,84 @@ impl List { }) } + /// Put `heavier_id` to the position directly in front of `lighter_id`. Both ids must be in the + /// same bag and the `weight_of` `lighter_id` must be less than that of `heavier_id`. + pub(crate) fn put_in_front_of( + lighter_id: &T::AccountId, + heavier_id: &T::AccountId, + ) -> Result<(), crate::pallet::Error> { + use crate::pallet; + use frame_support::ensure; + + let lighter_node = Node::::get(&lighter_id).ok_or(pallet::Error::IdNotFound)?; + let heavier_node = Node::::get(&heavier_id).ok_or(pallet::Error::IdNotFound)?; + + ensure!(lighter_node.bag_upper == heavier_node.bag_upper, pallet::Error::NotInSameBag); + + // this is the most expensive check, so we do it last. + ensure!( + T::VoteWeightProvider::vote_weight(&heavier_id) > + T::VoteWeightProvider::vote_weight(&lighter_id), + pallet::Error::NotHeavier + ); + + // remove the heavier node from this list. Note that this removes the node from storage and + // decrements the node counter. + Self::remove(&heavier_id); + + // re-fetch `lighter_node` from storage since it may have been updated when `heavier_node` + // was removed. + let lighter_node = Node::::get(&lighter_id).ok_or_else(|| { + debug_assert!(false, "id that should exist cannot be found"); + crate::log!(warn, "id that should exist cannot be found"); + pallet::Error::IdNotFound + })?; + + // insert `heavier_node` directly in front of `lighter_node`. This will update both nodes + // in storage and update the node counter. + Self::insert_at_unchecked(lighter_node, heavier_node); + + Ok(()) + } + + /// Insert `node` directly in front of `at`. + /// + /// WARNINGS: + /// - this is a naive function in that it does not check if `node` belongs to the same bag as + /// `at`. It is expected that the call site will check preconditions. + /// - this will panic if `at.bag_upper` is not a bag that already exists in storage. + fn insert_at_unchecked(mut at: Node, mut node: Node) { + // connect `node` to its new `prev`. + node.prev = at.prev.clone(); + if let Some(mut prev) = at.prev() { + prev.next = Some(node.id().clone()); + prev.put() + } + + // connect `node` and `at`. + node.next = Some(at.id().clone()); + at.prev = Some(node.id().clone()); + + if node.is_terminal() { + // `node` is the new head, so we make sure the bag is updated. Note, + // since `node` is always in front of `at` we know that 1) there is always at least 2 + // nodes in the bag, and 2) only `node` could be the head and only `at` could be the + // tail. + let mut bag = Bag::::get(at.bag_upper) + .expect("given nodes must always have a valid bag. qed."); + + if node.prev == None { + bag.head = Some(node.id().clone()) + } + + bag.put() + }; + + // write the updated nodes to storage. + at.put(); + node.put(); + } + /// Sanity check the list. /// /// This should be called from the call-site, whenever one of the mutating apis (e.g. `insert`) diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index 1c345df9a2fbd..f3043589681ec 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -383,6 +383,123 @@ mod list { assert!(non_existent_ids.iter().all(|id| !List::::contains(id))); }) } + + #[test] + #[should_panic = "given nodes must always have a valid bag. qed."] + fn put_in_front_of_panics_if_bag_not_found() { + ExtBuilder::default().skip_genesis_ids().build_and_execute_no_post_check(|| { + let node_10_no_bag = Node:: { id: 10, prev: None, next: None, bag_upper: 15 }; + let node_11_no_bag = Node:: { id: 11, prev: None, next: None, bag_upper: 15 }; + + // given + ListNodes::::insert(10, node_10_no_bag); + ListNodes::::insert(11, node_11_no_bag); + StakingMock::set_vote_weight_of(&10, 14); + StakingMock::set_vote_weight_of(&11, 15); + assert!(!ListBags::::contains_key(15)); + assert_eq!(List::::get_bags(), vec![]); + + // then .. this panics + let _ = List::::put_in_front_of(&10, &11); + }); + } + + #[test] + fn insert_at_unchecked_at_is_only_node() { + // Note that this `insert_at_unchecked` test should fail post checks because node 42 does + // not get re-assigned the correct bagu pper. This is because `insert_at_unchecked` assumes + // both nodes are already in the same bag with the correct bag upper. + ExtBuilder::default().build_and_execute_no_post_check(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + // implicitly also test that `node`'s `prev`/`next` are correctly re-assigned. + let node_42 = + Node:: { id: 42, prev: Some(1), next: Some(2), bag_upper: 1_000 }; + assert!(!crate::ListNodes::::contains_key(42)); + + let node_1 = crate::ListNodes::::get(&1).unwrap(); + + // when + List::::insert_at_unchecked(node_1, node_42); + + // then + assert_eq!( + List::::get_bags(), + vec![(10, vec![42, 1]), (1_000, vec![2, 3, 4])] + ); + }) + } + + #[test] + fn insert_at_unchecked_at_is_head() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + // implicitly also test that `node`'s `prev`/`next` are correctly re-assigned. + let node_42 = Node:: { id: 42, prev: Some(4), next: None, bag_upper: 1_000 }; + assert!(!crate::ListNodes::::contains_key(42)); + + let node_2 = crate::ListNodes::::get(&2).unwrap(); + + // when + List::::insert_at_unchecked(node_2, node_42); + + // then + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![42, 2, 3, 4])] + ); + }) + } + + #[test] + fn insert_at_unchecked_at_is_non_terminal() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + // implicitly also test that `node`'s `prev`/`next` are correctly re-assigned. + let node_42 = Node:: { id: 42, prev: None, next: Some(2), bag_upper: 1_000 }; + assert!(!crate::ListNodes::::contains_key(42)); + + let node_3 = crate::ListNodes::::get(&3).unwrap(); + + // when + List::::insert_at_unchecked(node_3, node_42); + + // then + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 42, 3, 4])] + ); + }) + } + + #[test] + fn insert_at_unchecked_at_is_tail() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + // implicitly also test that `node`'s `prev`/`next` are correctly re-assigned. + let node_42 = + Node:: { id: 42, prev: Some(42), next: Some(42), bag_upper: 1_000 }; + assert!(!crate::ListNodes::::contains_key(42)); + + let node_4 = crate::ListNodes::::get(&4).unwrap(); + + // when + List::::insert_at_unchecked(node_4, node_42); + + // then + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 42, 4])] + ); + }) + } } mod bags { diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 45eb1d85abe3c..6545e563a3efe 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -21,28 +21,26 @@ use super::*; use crate::{self as bags_list}; use frame_election_provider_support::VoteWeight; use frame_support::parameter_types; +use std::collections::HashMap; pub type AccountId = u32; pub type Balance = u32; parameter_types! { + // Set the vote weight for any id who's weight has _not_ been set with `set_vote_weight_of`. pub static NextVoteWeight: VoteWeight = 0; + pub static NextVoteWeightMap: HashMap = Default::default(); } pub struct StakingMock; impl frame_election_provider_support::VoteWeightProvider for StakingMock { fn vote_weight(id: &AccountId) -> VoteWeight { - match id { - 710 => 15, - 711 => 16, - 712 => 2_000, // special cases used for migrate test - _ => NextVoteWeight::get(), - } + *NextVoteWeightMap::get().get(id).unwrap_or(&NextVoteWeight::get()) } + #[cfg(any(feature = "runtime-benchmarks", test))] - fn set_vote_weight_of(_: &AccountId, weight: VoteWeight) { - // we don't really keep a mapping, just set weight for everyone. - NextVoteWeight::set(weight) + fn set_vote_weight_of(id: &AccountId, weight: VoteWeight) { + NEXT_VOTE_WEIGHT_MAP.with(|m| m.borrow_mut().insert(id.clone(), weight)); } } @@ -103,9 +101,17 @@ pub(crate) const GENESIS_IDS: [(AccountId, VoteWeight); 4] = #[derive(Default)] pub struct ExtBuilder { ids: Vec<(AccountId, VoteWeight)>, + skip_genesis_ids: bool, } impl ExtBuilder { + /// Skip adding the default genesis ids to the list. + #[cfg(test)] + pub(crate) fn skip_genesis_ids(mut self) -> Self { + self.skip_genesis_ids = true; + self + } + /// Add some AccountIds to insert into `List`. #[cfg(test)] pub(crate) fn add_ids(mut self, ids: Vec<(AccountId, VoteWeight)>) -> Self { @@ -117,10 +123,17 @@ impl ExtBuilder { sp_tracing::try_init_simple(); let storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let ids_with_weight: Vec<_> = if self.skip_genesis_ids { + self.ids.iter().collect() + } else { + GENESIS_IDS.iter().chain(self.ids.iter()).collect() + }; + let mut ext = sp_io::TestExternalities::from(storage); ext.execute_with(|| { - for (id, weight) in GENESIS_IDS.iter().chain(self.ids.iter()) { + for (id, weight) in ids_with_weight { frame_support::assert_ok!(List::::insert(*id, *weight)); + StakingMock::set_vote_weight_of(id, *weight); } }); diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs index 270d25855ccd4..8f1ccacaf1171 100644 --- a/frame/bags-list/src/tests.rs +++ b/frame/bags-list/src/tests.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::{assert_ok, assert_storage_noop, traits::IntegrityTest}; +use frame_support::{assert_noop, assert_ok, assert_storage_noop, traits::IntegrityTest}; use super::*; use frame_election_provider_support::SortedListProvider; @@ -35,7 +35,7 @@ mod pallet { ); // when increasing vote weight to the level of non-existent bag - NextVoteWeight::set(2_000); + StakingMock::set_vote_weight_of(&42, 2_000); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); // then a new bag is created and the id moves into it @@ -45,7 +45,7 @@ mod pallet { ); // when decreasing weight within the range of the current bag - NextVoteWeight::set(1001); + StakingMock::set_vote_weight_of(&42, 1_001); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); // then the id does not move @@ -55,7 +55,7 @@ mod pallet { ); // when reducing weight to the level of a non-existent bag - NextVoteWeight::set(30); + StakingMock::set_vote_weight_of(&42, 30); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); // then a new bag is created and the id moves into it @@ -65,7 +65,7 @@ mod pallet { ); // when increasing weight to the level of a pre-existing bag - NextVoteWeight::set(500); + StakingMock::set_vote_weight_of(&42, 500); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); // then the id moves into that bag @@ -85,7 +85,7 @@ mod pallet { assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); // when - NextVoteWeight::set(10); + StakingMock::set_vote_weight_of(&4, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 4)); // then @@ -93,6 +93,7 @@ mod pallet { assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(2), Some(3), 1_000)); // when + StakingMock::set_vote_weight_of(&3, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 3)); // then @@ -103,6 +104,7 @@ mod pallet { assert_eq!(get_list_as_ids(), vec![2u32, 1, 4, 3]); // when + StakingMock::set_vote_weight_of(&2, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 2)); // then @@ -117,7 +119,7 @@ mod pallet { fn rebag_head_works() { ExtBuilder::default().build_and_execute(|| { // when - NextVoteWeight::set(10); + StakingMock::set_vote_weight_of(&2, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 2)); // then @@ -125,6 +127,7 @@ mod pallet { assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(3), Some(4), 1_000)); // when + StakingMock::set_vote_weight_of(&3, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 3)); // then @@ -132,6 +135,7 @@ mod pallet { assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(4), Some(4), 1_000)); // when + StakingMock::set_vote_weight_of(&4, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 4)); // then @@ -196,6 +200,249 @@ mod pallet { assert_storage_noop!(assert!(BagsList::rebag(Origin::signed(0), 10).is_ok())); }) } + + #[test] + fn put_in_front_of_two_node_bag_heavier_is_tail() { + ExtBuilder::default() + .skip_genesis_ids() + .add_ids(vec![(10, 15), (11, 16)]) + .build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(20, vec![10, 11])]); + + // when + assert_ok!(BagsList::put_in_front_of(Origin::signed(11), 10)); + + // then + assert_eq!(List::::get_bags(), vec![(20, vec![11, 10])]); + }); + } + + #[test] + fn put_in_front_of_two_node_bag_heavier_is_head() { + ExtBuilder::default() + .skip_genesis_ids() + .add_ids(vec![(11, 16), (10, 15)]) + .build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(20, vec![11, 10])]); + + // when + assert_ok!(BagsList::put_in_front_of(Origin::signed(11), 10)); + + // then + assert_eq!(List::::get_bags(), vec![(20, vec![11, 10])]); + }); + } + + #[test] + fn put_in_front_of_non_terminal_nodes_heavier_behind() { + ExtBuilder::default().add_ids(vec![(5, 1_000)]).build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5])]); + + StakingMock::set_vote_weight_of(&3, 999); + + // when + assert_ok!(BagsList::put_in_front_of(Origin::signed(4), 3)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 4, 3, 5])]); + }); + } + + #[test] + fn put_in_front_of_non_terminal_nodes_heavier_in_front() { + ExtBuilder::default() + .add_ids(vec![(5, 1_000), (6, 1_000)]) + .build_and_execute(|| { + // given + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5, 6])] + ); + + StakingMock::set_vote_weight_of(&5, 999); + + // when + assert_ok!(BagsList::put_in_front_of(Origin::signed(3), 5)); + + // then + assert_eq!( + List::::get_bags(), + vec![(10, vec![1]), (1_000, vec![2, 4, 3, 5, 6])] + ); + }); + } + + #[test] + fn put_in_front_of_lighter_is_head_heavier_is_non_terminal() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + StakingMock::set_vote_weight_of(&2, 999); + + // when + assert_ok!(BagsList::put_in_front_of(Origin::signed(3), 2)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 2, 4])]); + }); + } + + #[test] + fn put_in_front_of_heavier_is_tail_lighter_is_non_terminal() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + StakingMock::set_vote_weight_of(&3, 999); + + // when + assert_ok!(BagsList::put_in_front_of(Origin::signed(4), 3)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 4, 3])]); + }); + } + + #[test] + fn put_in_front_of_heavier_is_tail_lighter_is_head() { + ExtBuilder::default().add_ids(vec![(5, 1_000)]).build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5])]); + + StakingMock::set_vote_weight_of(&2, 999); + + // when + assert_ok!(BagsList::put_in_front_of(Origin::signed(5), 2)); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![5, 2, 3, 4])]); + }); + } + + #[test] + fn put_in_front_of_heavier_is_head_lighter_is_not_terminal() { + ExtBuilder::default().add_ids(vec![(5, 1_000)]).build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5])]); + + StakingMock::set_vote_weight_of(&4, 999); + + // when + BagsList::put_in_front_of(Origin::signed(2), 4).unwrap(); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 2, 4, 5])]); + }); + } + + #[test] + fn put_in_front_of_lighter_is_tail_heavier_is_not_terminal() { + ExtBuilder::default().add_ids(vec![(5, 900)]).build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5])]); + + // when + BagsList::put_in_front_of(Origin::signed(3), 5).unwrap(); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 4, 3, 5])]); + }); + } + + #[test] + fn put_in_front_of_lighter_is_tail_heavier_is_head() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + StakingMock::set_vote_weight_of(&4, 999); + + // when + BagsList::put_in_front_of(Origin::signed(2), 4).unwrap(); + + // then + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 2, 4])]); + }); + } + + #[test] + fn put_in_front_of_errors_if_heavier_is_less_than_lighter() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + StakingMock::set_vote_weight_of(&3, 999); + + // then + assert_noop!( + BagsList::put_in_front_of(Origin::signed(3), 2), + crate::pallet::Error::::NotHeavier + ); + }); + } + + #[test] + fn put_in_front_of_errors_if_heavier_is_equal_weight_to_lighter() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + // then + assert_noop!( + BagsList::put_in_front_of(Origin::signed(3), 4), + crate::pallet::Error::::NotHeavier + ); + }); + } + + #[test] + fn put_in_front_of_errors_if_nodes_not_found() { + // `heavier` not found + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + assert!(!ListNodes::::contains_key(5)); + + // then + assert_noop!( + BagsList::put_in_front_of(Origin::signed(5), 4), + crate::pallet::Error::::IdNotFound + ); + }); + + // `lighter` not found + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + assert!(!ListNodes::::contains_key(5)); + + // then + assert_noop!( + BagsList::put_in_front_of(Origin::signed(4), 5), + crate::pallet::Error::::IdNotFound + ); + }); + } + + #[test] + fn put_in_front_of_errors_if_nodes_not_in_same_bag() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); + + // then + assert_noop!( + BagsList::put_in_front_of(Origin::signed(4), 1), + crate::pallet::Error::::NotInSameBag + ); + }); + } } mod sorted_list_provider { diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index 95d3dfa6eb989..7433c7ac564f7 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_bags_list //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-09-15, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-11-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -35,7 +35,6 @@ // --output=./frame/bags-list/src/weights.rs // --template=./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -47,6 +46,7 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn rebag_non_terminal() -> Weight; fn rebag_terminal() -> Weight; + fn put_in_front_of() -> Weight; } /// Weights for pallet_bags_list using the Substrate node and recommended hardware. @@ -57,7 +57,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (74_175_000 as Weight) + (70_481_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -66,10 +66,20 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (73_305_000 as Weight) + (68_642_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } + // Storage: BagsList ListNodes (r:4 w:4) + // Storage: Staking Bonded (r:2 w:0) + // Storage: Staking Ledger (r:2 w:0) + // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: BagsList ListBags (r:1 w:1) + fn put_in_front_of() -> Weight { + (82_341_000 as Weight) + .saturating_add(T::DbWeight::get().reads(10 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) + } } // For backwards compatibility and tests @@ -79,7 +89,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (74_175_000 as Weight) + (70_481_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -88,8 +98,18 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (73_305_000 as Weight) + (68_642_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } + // Storage: BagsList ListNodes (r:4 w:4) + // Storage: Staking Bonded (r:2 w:0) + // Storage: Staking Ledger (r:2 w:0) + // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: BagsList ListBags (r:1 w:1) + fn put_in_front_of() -> Weight { + (82_341_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(10 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + } } From 2651d5cf410700c8a9bbe1b5df54aa9956926b34 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 8 Dec 2021 11:28:03 +0100 Subject: [PATCH 0312/1472] Introduce CheckNonZeroSender (#10413) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Introduce CheckNonZeroSender * Missing file * Formatting * Fixes * Formatting * some fixes to compile * Update frame/system/src/extensions/check_non_zero_sender.rs Co-authored-by: Bastian Köcher * Fixes * Fixes * another fix * Formatting Co-authored-by: Shawn Tabrizi Co-authored-by: Bastian Köcher --- bin/node/cli/src/service.rs | 6 +- bin/node/executor/tests/submit_transaction.rs | 4 +- bin/node/runtime/src/lib.rs | 2 + bin/node/test-runner-example/src/lib.rs | 1 + bin/node/testing/src/keyring.rs | 1 + .../src/extensions/check_non_zero_sender.rs | 100 ++++++++++++++++++ frame/system/src/extensions/mod.rs | 1 + frame/system/src/lib.rs | 3 +- .../runtime/src/transaction_validity.rs | 3 + test-utils/test-runner/src/lib.rs | 1 + 10 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 frame/system/src/extensions/check_non_zero_sender.rs diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index fec91a9b67cc4..1dfce9331b752 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -83,6 +83,7 @@ pub fn create_extrinsic( .unwrap_or(2) as u64; let tip = 0; let extra: node_runtime::SignedExtra = ( + frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), @@ -99,6 +100,7 @@ pub fn create_extrinsic( function.clone(), extra.clone(), ( + (), node_runtime::VERSION.spec_version, node_runtime::VERSION.transaction_version, genesis_hash, @@ -719,6 +721,7 @@ mod tests { let function = Call::Balances(BalancesCall::transfer { dest: to.into(), value: amount }); + let check_non_zero_sender = frame_system::CheckNonZeroSender::new(); let check_spec_version = frame_system::CheckSpecVersion::new(); let check_tx_version = frame_system::CheckTxVersion::new(); let check_genesis = frame_system::CheckGenesis::new(); @@ -727,6 +730,7 @@ mod tests { let check_weight = frame_system::CheckWeight::new(); let tx_payment = pallet_asset_tx_payment::ChargeAssetTxPayment::from(0, None); let extra = ( + check_non_zero_sender, check_spec_version, check_tx_version, check_genesis, @@ -738,7 +742,7 @@ mod tests { let raw_payload = SignedPayload::from_raw( function, extra, - (spec_version, transaction_version, genesis_hash, genesis_hash, (), (), ()), + ((), spec_version, transaction_version, genesis_hash, genesis_hash, (), (), ()), ); let signature = raw_payload.using_encoded(|payload| signer.sign(payload)); let (function, extra, _) = raw_payload.deconstruct(); diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs index f047c6a44a667..4f0f8061641f8 100644 --- a/bin/node/executor/tests/submit_transaction.rs +++ b/bin/node/executor/tests/submit_transaction.rs @@ -146,7 +146,7 @@ fn should_submit_signed_twice_from_the_same_account() { let s = state.read(); fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { let extra = tx.signature.unwrap().2; - extra.4 + extra.5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap()); @@ -195,7 +195,7 @@ fn should_submit_signed_twice_from_all_accounts() { let s = state.read(); fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { let extra = tx.signature.unwrap().2; - extra.4 + extra.5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap()); diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 45b49dc46b897..44d39a870efcc 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -984,6 +984,7 @@ where .saturating_sub(1); let era = Era::mortal(period, current_block); let extra = ( + frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), @@ -1334,6 +1335,7 @@ pub type BlockId = generic::BlockId; /// /// [`sign`]: <../../testing/src/keyring.rs.html> pub type SignedExtra = ( + frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, frame_system::CheckGenesis, diff --git a/bin/node/test-runner-example/src/lib.rs b/bin/node/test-runner-example/src/lib.rs index 68c14b73bf562..e247fca223204 100644 --- a/bin/node/test-runner-example/src/lib.rs +++ b/bin/node/test-runner-example/src/lib.rs @@ -69,6 +69,7 @@ impl ChainInfo for NodeTemplateChainInfo { from: ::AccountId, ) -> Self::SignedExtras { ( + frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), diff --git a/bin/node/testing/src/keyring.rs b/bin/node/testing/src/keyring.rs index 1040e90c4d5d4..3e6dff301fc45 100644 --- a/bin/node/testing/src/keyring.rs +++ b/bin/node/testing/src/keyring.rs @@ -70,6 +70,7 @@ pub fn to_session_keys( /// Returns transaction extra. pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra { ( + frame_system::CheckNonZeroSender::new(), frame_system::CheckSpecVersion::new(), frame_system::CheckTxVersion::new(), frame_system::CheckGenesis::new(), diff --git a/frame/system/src/extensions/check_non_zero_sender.rs b/frame/system/src/extensions/check_non_zero_sender.rs new file mode 100644 index 0000000000000..1d45ae17cb7ac --- /dev/null +++ b/frame/system/src/extensions/check_non_zero_sender.rs @@ -0,0 +1,100 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::Config; +use codec::{Decode, Encode}; +use frame_support::weights::DispatchInfo; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{DispatchInfoOf, Dispatchable, SignedExtension}, + transaction_validity::{ + InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, + }, +}; +use sp_std::{marker::PhantomData, prelude::*}; + +/// Check to ensure that the sender is not the zero address. +#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct CheckNonZeroSender(PhantomData); + +impl sp_std::fmt::Debug for CheckNonZeroSender { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "CheckNonZeroSender") + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +impl CheckNonZeroSender { + /// Create new `SignedExtension` to check runtime version. + pub fn new() -> Self { + Self(sp_std::marker::PhantomData) + } +} + +impl SignedExtension for CheckNonZeroSender +where + T::Call: Dispatchable, +{ + type AccountId = T::AccountId; + type Call = T::Call; + type AdditionalSigned = (); + type Pre = (); + const IDENTIFIER: &'static str = "CheckNonZeroSender"; + + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + + fn validate( + &self, + who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + if who.using_encoded(|d| d.into_iter().all(|x| *x == 0)) { + return Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner)) + } + Ok(ValidTransaction::default()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{new_test_ext, Test, CALL}; + use frame_support::{assert_noop, assert_ok}; + + #[test] + fn zero_account_ban_works() { + new_test_ext().execute_with(|| { + let info = DispatchInfo::default(); + let len = 0_usize; + assert_noop!( + CheckNonZeroSender::::new().validate(&0, CALL, &info, len), + InvalidTransaction::BadSigner + ); + assert_ok!(CheckNonZeroSender::::new().validate(&1, CALL, &info, len)); + }) + } +} diff --git a/frame/system/src/extensions/mod.rs b/frame/system/src/extensions/mod.rs index 0af9722e475d1..7eaff34c1d7f3 100644 --- a/frame/system/src/extensions/mod.rs +++ b/frame/system/src/extensions/mod.rs @@ -17,6 +17,7 @@ pub mod check_genesis; pub mod check_mortality; +pub mod check_non_zero_sender; pub mod check_nonce; pub mod check_spec_version; pub mod check_tx_version; diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index aac104fa8f765..7603fe6541415 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -115,7 +115,8 @@ mod tests; pub mod weights; pub use extensions::{ - check_genesis::CheckGenesis, check_mortality::CheckMortality, check_nonce::CheckNonce, + check_genesis::CheckGenesis, check_mortality::CheckMortality, + check_non_zero_sender::CheckNonZeroSender, check_nonce::CheckNonce, check_spec_version::CheckSpecVersion, check_tx_version::CheckTxVersion, check_weight::CheckWeight, }; diff --git a/primitives/runtime/src/transaction_validity.rs b/primitives/runtime/src/transaction_validity.rs index e114bb5985460..cf5d925975996 100644 --- a/primitives/runtime/src/transaction_validity.rs +++ b/primitives/runtime/src/transaction_validity.rs @@ -79,6 +79,8 @@ pub enum InvalidTransaction { /// A transaction with a mandatory dispatch. This is invalid; only inherent extrinsics are /// allowed to have mandatory dispatches. MandatoryDispatch, + /// The sending address is disabled or known to be invalid. + BadSigner, } impl InvalidTransaction { @@ -109,6 +111,7 @@ impl From for &'static str { InvalidTransaction::MandatoryDispatch => "Transaction dispatch is mandatory; transactions may not have mandatory dispatches.", InvalidTransaction::Custom(_) => "InvalidTransaction custom error", + InvalidTransaction::BadSigner => "Invalid signing address", } } } diff --git a/test-utils/test-runner/src/lib.rs b/test-utils/test-runner/src/lib.rs index ca2c518fd6926..9f51442ed743b 100644 --- a/test-utils/test-runner/src/lib.rs +++ b/test-utils/test-runner/src/lib.rs @@ -106,6 +106,7 @@ //! let nonce = frame_system::Pallet::::account_nonce(from); //! //! ( +//! frame_system::CheckNonZeroSender::::new(), //! frame_system::CheckSpecVersion::::new(), //! frame_system::CheckTxVersion::::new(), //! frame_system::CheckGenesis::::new(), From 25e636bcbf756afb4d4534c62ad9e9b806e98be7 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 8 Dec 2021 21:06:50 +0100 Subject: [PATCH 0313/1472] Release sp-core 4.0.0 (#10447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump versions of sp-core and dependencies to v4.0.0 * Update references from `4.0.0-dev` –> `4.0.0` * Funny whitespace * Funny whitespace 2 --- Cargo.lock | 20 +++++++++---------- bin/node-template/node/Cargo.toml | 2 +- bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 4 ++-- bin/node/bench/Cargo.toml | 4 ++-- bin/node/cli/Cargo.toml | 4 ++-- bin/node/executor/Cargo.toml | 6 +++--- bin/node/inspect/Cargo.toml | 2 +- bin/node/primitives/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 4 ++-- bin/node/testing/Cargo.toml | 2 +- bin/utils/chain-spec-builder/Cargo.toml | 2 +- client/allocator/Cargo.toml | 4 ++-- client/api/Cargo.toml | 6 +++--- client/authority-discovery/Cargo.toml | 4 ++-- client/basic-authorship/Cargo.toml | 2 +- client/beefy/Cargo.toml | 4 ++-- client/beefy/rpc/Cargo.toml | 2 +- client/block-builder/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 4 ++-- client/consensus/babe/Cargo.toml | 4 ++-- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 2 +- client/db/Cargo.toml | 4 ++-- client/executor/Cargo.toml | 8 ++++---- client/executor/common/Cargo.toml | 4 ++-- client/executor/runtime-test/Cargo.toml | 4 ++-- client/executor/wasmi/Cargo.toml | 6 +++--- client/executor/wasmtime/Cargo.toml | 6 +++--- client/finality-grandpa/Cargo.toml | 4 ++-- client/finality-grandpa/rpc/Cargo.toml | 4 ++-- client/keystore/Cargo.toml | 2 +- client/network/Cargo.toml | 4 ++-- client/network/test/Cargo.toml | 4 ++-- client/offchain/Cargo.toml | 4 ++-- client/rpc-api/Cargo.toml | 4 ++-- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 8 ++++---- client/service/test/Cargo.toml | 8 ++++---- client/state-db/Cargo.toml | 2 +- client/tracing/Cargo.toml | 4 ++-- client/transaction-pool/Cargo.toml | 4 ++-- frame/assets/Cargo.toml | 6 +++--- frame/atomic-swap/Cargo.toml | 4 ++-- frame/aura/Cargo.toml | 4 ++-- frame/authority-discovery/Cargo.toml | 4 ++-- frame/authorship/Cargo.toml | 4 ++-- frame/babe/Cargo.toml | 4 ++-- frame/bags-list/Cargo.toml | 11 +++++----- frame/bags-list/remote-tests/Cargo.toml | 8 ++++---- frame/balances/Cargo.toml | 4 ++-- frame/beefy-mmr/Cargo.toml | 4 ++-- frame/beefy/Cargo.toml | 4 ++-- frame/benchmarking/Cargo.toml | 6 +++--- frame/bounties/Cargo.toml | 4 ++-- frame/child-bounties/Cargo.toml | 4 ++-- frame/collective/Cargo.toml | 4 ++-- frame/contracts/Cargo.toml | 4 ++-- frame/contracts/common/Cargo.toml | 4 ++-- frame/contracts/rpc/Cargo.toml | 2 +- frame/contracts/rpc/runtime-api/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 4 ++-- .../election-provider-multi-phase/Cargo.toml | 8 ++++---- frame/election-provider-support/Cargo.toml | 4 ++-- frame/elections-phragmen/Cargo.toml | 6 +++--- frame/elections/Cargo.toml | 4 ++-- frame/examples/basic/Cargo.toml | 4 ++-- frame/examples/offchain-worker/Cargo.toml | 4 ++-- frame/examples/parallel/Cargo.toml | 4 ++-- frame/executive/Cargo.toml | 8 ++++---- frame/gilt/Cargo.toml | 4 ++-- frame/grandpa/Cargo.toml | 4 ++-- frame/identity/Cargo.toml | 4 ++-- frame/im-online/Cargo.toml | 4 ++-- frame/indices/Cargo.toml | 4 ++-- frame/lottery/Cargo.toml | 4 ++-- frame/membership/Cargo.toml | 4 ++-- frame/merkle-mountain-range/Cargo.toml | 4 ++-- .../primitives/Cargo.toml | 4 ++-- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 4 ++-- frame/nicks/Cargo.toml | 4 ++-- frame/node-authorization/Cargo.toml | 4 ++-- frame/offences/Cargo.toml | 4 ++-- frame/offences/benchmarking/Cargo.toml | 4 ++-- frame/proxy/Cargo.toml | 4 ++-- frame/randomness-collective-flip/Cargo.toml | 4 ++-- frame/recovery/Cargo.toml | 4 ++-- frame/scheduler/Cargo.toml | 4 ++-- frame/scored-pool/Cargo.toml | 4 ++-- frame/session/Cargo.toml | 4 ++-- frame/session/benchmarking/Cargo.toml | 4 ++-- frame/society/Cargo.toml | 4 ++-- frame/staking/Cargo.toml | 6 +++--- frame/sudo/Cargo.toml | 4 ++-- frame/support/Cargo.toml | 6 +++--- frame/support/test/Cargo.toml | 4 ++-- frame/support/test/compile_pass/Cargo.toml | 2 +- frame/system/Cargo.toml | 6 +++--- frame/system/benchmarking/Cargo.toml | 4 ++-- frame/timestamp/Cargo.toml | 4 ++-- frame/tips/Cargo.toml | 6 +++--- frame/transaction-payment/Cargo.toml | 4 ++-- .../asset-tx-payment/Cargo.toml | 6 +++--- frame/transaction-payment/rpc/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 4 ++-- frame/treasury/Cargo.toml | 4 ++-- frame/try-runtime/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 6 +++--- frame/utility/Cargo.toml | 6 +++--- frame/vesting/Cargo.toml | 4 ++-- primitives/api/Cargo.toml | 4 ++-- primitives/api/test/Cargo.toml | 4 ++-- primitives/application-crypto/Cargo.toml | 4 ++-- primitives/application-crypto/test/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 4 ++-- primitives/authority-discovery/Cargo.toml | 2 +- primitives/authorship/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 4 ++-- primitives/block-builder/Cargo.toml | 2 +- primitives/consensus/aura/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 4 ++-- primitives/consensus/common/Cargo.toml | 4 ++-- primitives/consensus/pow/Cargo.toml | 4 ++-- primitives/consensus/vrf/Cargo.toml | 4 ++-- primitives/core/Cargo.toml | 14 ++++++------- primitives/core/hashing/Cargo.toml | 4 ++-- primitives/core/hashing/proc-macro/Cargo.toml | 2 +- primitives/debug-derive/Cargo.toml | 2 +- primitives/externalities/Cargo.toml | 6 +++--- primitives/finality-grandpa/Cargo.toml | 4 ++-- primitives/inherents/Cargo.toml | 4 ++-- primitives/io/Cargo.toml | 12 +++++------ primitives/keyring/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 4 ++-- primitives/npos-elections/Cargo.toml | 4 ++-- primitives/offchain/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 16 +++++++-------- .../runtime-interface/proc-macro/Cargo.toml | 2 +- .../test-wasm-deprecated/Cargo.toml | 6 +++--- .../runtime-interface/test-wasm/Cargo.toml | 6 +++--- primitives/runtime-interface/test/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 6 +++--- primitives/sandbox/Cargo.toml | 6 +++--- primitives/session/Cargo.toml | 4 ++-- primitives/staking/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 6 +++--- primitives/std/Cargo.toml | 2 +- primitives/storage/Cargo.toml | 6 +++--- primitives/tasks/Cargo.toml | 8 ++++---- primitives/test-primitives/Cargo.toml | 2 +- primitives/timestamp/Cargo.toml | 2 +- primitives/tracing/Cargo.toml | 4 ++-- .../transaction-storage-proof/Cargo.toml | 4 ++-- primitives/trie/Cargo.toml | 4 ++-- primitives/version/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 4 ++-- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 8 ++++---- test-utils/runtime/client/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 4 ++-- utils/frame/frame-utilities-cli/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 4 ++-- utils/frame/try-runtime/cli/Cargo.toml | 4 ++-- 172 files changed, 360 insertions(+), 361 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d1618f83b476f..3693fe0806930 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9391,7 +9391,7 @@ dependencies = [ [[package]] name = "sp-core" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "base58", "bitflags", @@ -9443,7 +9443,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "blake2-rfc", "byteorder", @@ -9473,7 +9473,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "proc-macro2", "quote", @@ -9482,7 +9482,7 @@ dependencies = [ [[package]] name = "sp-externalities" -version = "0.10.0-dev" +version = "0.10.0" dependencies = [ "environmental", "parity-scale-codec", @@ -9680,7 +9680,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -9702,7 +9702,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "Inflector", "proc-macro-crate 1.1.0", @@ -9822,11 +9822,11 @@ dependencies = [ [[package]] name = "sp-std" -version = "4.0.0-dev" +version = "4.0.0" [[package]] name = "sp-storage" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "impl-serde", "parity-scale-codec", @@ -9878,7 +9878,7 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "parity-scale-codec", "sp-std", @@ -9957,7 +9957,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 6f3a63593aa3e..2680b91b3a254 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -20,7 +20,7 @@ name = "node-template" structopt = "0.3.25" sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = ["wasmtime"] } sc-service = { version = "0.10.0-dev", path = "../../../client/service", features = ["wasmtime"] } sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" } diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 887b022d6ca7f..646038ca6ced8 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -22,7 +22,7 @@ frame-system = { default-features = false, version = "4.0.0-dev", path = "../../ frame-benchmarking = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/benchmarking", optional = true } [dev-dependencies] -sp-core = { default-features = false, version = "4.0.0-dev", path = "../../../../primitives/core" } +sp-core = { default-features = false, version = "4.0.0", path = "../../../../primitives/core" } sp-io = { default-features = false, version = "4.0.0-dev", path = "../../../../primitives/io" } sp-runtime = { default-features = false, version = "4.0.0-dev", path = "../../../../primitives/runtime" } diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index c7ff0ff5a268a..a25c45c692de8 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -29,12 +29,12 @@ frame-executive = { version = "4.0.0-dev", default-features = false, path = "../ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-block-builder = { path = "../../../primitives/block-builder", default-features = false, version = "4.0.0-dev"} sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/consensus/aura" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } sp-inherents = { path = "../../../primitives/inherents", default-features = false, version = "4.0.0-dev"} sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 0beeb4e339e43..27c26d21dfe06 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -23,12 +23,12 @@ derive_more = "0.99.16" kvdb = "0.10.0" kvdb-rocksdb = "0.14.0" sp-trie = { version = "4.0.0-dev", path = "../../../primitives/trie" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-basic-authorship = { version = "0.10.0-dev", path = "../../../client/basic-authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/timestamp" } -sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } hash-db = "0.15.2" tempfile = "3.1.0" fs_extra = "1" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 42df74100415d..cb632d936a2dc 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -47,7 +47,7 @@ sp-authority-discovery = { version = "4.0.0-dev", path = "../../../primitives/au sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } grandpa-primitives = { version = "4.0.0-dev", package = "sp-finality-grandpa", path = "../../../primitives/finality-grandpa" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } @@ -118,7 +118,7 @@ sc-consensus-babe = { version = "0.10.0-dev", path = "../../../client/consensus/ sc-consensus-epochs = { version = "0.10.0-dev", path = "../../../client/consensus/epochs" } sc-service-test = { version = "2.0.0", path = "../../../client/service/test" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } -sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } futures = "0.3.16" tempfile = "3.1.0" diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 6fdd5f8d2351b..13ed4d313994c 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -17,10 +17,10 @@ scale-info = { version = "1.0", features = ["derive"] } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } -sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } sp-trie = { version = "4.0.0-dev", path = "../../../primitives/trie" } frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } @@ -37,7 +37,7 @@ pallet-treasury = { version = "4.0.0-dev", path = "../../../frame/treasury" } sp-application-crypto = { version = "4.0.0-dev", path = "../../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -sp-externalities = { version = "0.10.0-dev", path = "../../../primitives/externalities" } +sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } wat = "1.0" futures = "0.3.9" diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index 6504f39a05822..18f24651ed35d 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -18,6 +18,6 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } structopt = "0.3.8" diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 2c8185d5c9c47..03d587acecd2d 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/application-crypto" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } [features] diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index a61c2311917a8..b36fd622dfa3a 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -30,8 +30,8 @@ sp-block-builder = { path = "../../../primitives/block-builder", default-feature sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents" } node-primitives = { version = "2.0.0", default-features = false, path = "../primitives" } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 0e5ed07ac2952..0fb0d40a7c2d2 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -28,7 +28,7 @@ sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = [ diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index daffd5a0359a5..79eb5becfeb84 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -18,7 +18,7 @@ ansi_term = "0.12.1" sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } node-cli = { version = "3.0.0-dev", path = "../../node/cli" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } rand = "0.7.2" structopt = "0.3.25" diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index 44facf0ad8892..48191273ff36a 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } -sp-wasm-interface = { version = "4.0.0-dev", path = "../../primitives/wasm-interface" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-wasm-interface = { version = "4.0.0", path = "../../primitives/wasm-interface" } log = "0.4.11" thiserror = "1.0.30" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index 39fe804a1415d..5e0fe88b3ca7c 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-executor = { version = "0.10.0-dev", path = "../executor" } -sp-externalities = { version = "0.10.0-dev", path = "../../primitives/externalities" } +sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } fnv = "1.0.6" futures = "0.3.1" hash-db = { version = "0.15.2", default-features = false } @@ -27,14 +27,14 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } log = "0.4.8" parking_lot = "0.11.1" sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } -sp-storage = { version = "4.0.0-dev", path = "../../primitives/storage" } +sp-storage = { version = "4.0.0", path = "../../primitives/storage" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index f3169e82fb3c8..8dcf8ab4c8140 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -32,12 +32,12 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-authority-discovery = { version = "4.0.0-dev", path = "../../primitives/authority-discovery" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } [dev-dependencies] quickcheck = "1.0.3" -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 4bfc3ca50c83f..049876f478790 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 23c9294d35100..b0f05888712d1 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -22,7 +22,7 @@ sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } @@ -35,7 +35,7 @@ sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } [dev-dependencies] -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sc-network-test = { version = "0.8.0", path = "../network/test" } strum = { version = "0.22", features = ["derive"] } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 594736841ed27..4d7bd6cef6c88 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -21,7 +21,7 @@ codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } beefy-gadget = { version = "4.0.0-dev", path = "../." } diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 25950a9e9061f..789e3fffcfa17 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -18,7 +18,7 @@ sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-mach sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-builder" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 976da45859117..1b4e3ed72d566 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } impl-trait-for-tuples = "0.2.1" sc-network = { version = "0.10.0-dev", path = "../network" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } serde = { version = "1.0.126", features = ["derive"] } serde_json = "1.0.71" sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index dddd48cb2f142..a9bc4e9f87a5d 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -32,7 +32,7 @@ sc-network = { version = "0.10.0-dev", path = "../network" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../service" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index f4f12a0a601c9..967f59999c7ec 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -26,7 +26,7 @@ derive_more = "0.99.16" futures = "0.3.9" sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } log = "0.4.8" -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } @@ -42,7 +42,7 @@ getrandom = { version = "0.2", features = ["js"], optional = true } [dev-dependencies] sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } -sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 5020a4a564782..5f1a8a0889168 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ ] } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-application-crypto = { version = "4.0.0-dev", path = "../../../primitives/application-crypto" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } num-bigint = "0.2.3" @@ -55,7 +55,7 @@ async-trait = "0.1.50" [dev-dependencies] sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index b47c3a711df99..bba579ee111b0 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -27,7 +27,7 @@ futures = "0.3.16" derive_more = "0.99.16" sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } -sp-core = { version = "4.0.0-dev", path = "../../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../../primitives/core" } sp-application-crypto = { version = "4.0.0-dev", path = "../../../../primitives/application-crypto" } sp-keystore = { version = "0.10.0-dev", path = "../../../../primitives/keystore" } diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 308028c85d23c..13b7203540182 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -20,7 +20,7 @@ futures = { version = "0.3.1", features = ["thread-pool"] } futures-timer = "3.0.1" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { path = "../../../primitives/core", version = "4.0.0-dev" } +sp-core = { path = "../../../primitives/core", version = "4.0.0" } sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 48ba910655441..24314fefd156e 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -36,7 +36,7 @@ sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10. sp-consensus-slots = { path = "../../../primitives/consensus/slots", version = "0.10.0-dev" } sp-inherents = { path = "../../../primitives/inherents", version = "4.0.0-dev" } sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0-dev" } -sp-core = { path = "../../../primitives/core", version = "4.0.0-dev" } +sp-core = { path = "../../../primitives/core", version = "4.0.0" } sp-keystore = { path = "../../../primitives/keystore", version = "0.10.0-dev" } sp-api = { path = "../../../primitives/api", version = "4.0.0-dev" } sc-transaction-pool-api = { path = "../../../client/transaction-pool/api", version = "4.0.0-dev" } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 25e39641ae43e..2b0926ce887e9 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index ff4fdf041b4fe..7b4aa26cdf540 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-arithmetic = { version = "4.0.0-dev", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 437431a50883f..08e228ee9afac 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -26,7 +26,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } @@ -36,7 +36,7 @@ sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } parity-db = { version = "0.3.4", optional = true } [dev-dependencies] -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } quickcheck = "1.0.3" kvdb-rocksdb = "0.14.0" diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index ebdcc44ff0d8c..b3a393f9472ae 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-tasks = { version = "4.0.0-dev", path = "../../primitives/tasks" } sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } @@ -24,9 +24,9 @@ sp-panic-handler = { version = "4.0.0-dev", path = "../../primitives/panic-handl wasmi = "0.9.1" lazy_static = "1.4.0" sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-wasm-interface = { version = "4.0.0-dev", path = "../../primitives/wasm-interface" } -sp-runtime-interface = { version = "4.0.0-dev", path = "../../primitives/runtime-interface" } -sp-externalities = { version = "0.10.0-dev", path = "../../primitives/externalities" } +sp-wasm-interface = { version = "4.0.0", path = "../../primitives/wasm-interface" } +sp-runtime-interface = { version = "4.0.0", path = "../../primitives/runtime-interface" } +sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } sc-executor-common = { version = "0.10.0-dev", path = "common" } sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 3d2cec9ac60c9..198d5201e1f5d 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -18,9 +18,9 @@ derive_more = "0.99.16" pwasm-utils = "0.18.2" codec = { package = "parity-scale-codec", version = "2.0.0" } wasmi = "0.9.1" -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-interface" } +sp-wasm-interface = { version = "4.0.0", path = "../../../primitives/wasm-interface" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } sp-serializer = { version = "4.0.0-dev", path = "../../../primitives/serializer" } thiserror = "1.0.30" diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index ea379a160f80c..831ff786ca090 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -13,11 +13,11 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } paste = "1.0.6" diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 871a8aa68b626..f1e01d944a6eb 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -19,7 +19,7 @@ wasmi = "0.9.1" codec = { package = "parity-scale-codec", version = "2.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-interface" } -sp-runtime-interface = { version = "4.0.0-dev", path = "../../../primitives/runtime-interface" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-wasm-interface = { version = "4.0.0", path = "../../../primitives/wasm-interface" } +sp-runtime-interface = { version = "4.0.0", path = "../../../primitives/runtime-interface" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } scoped-tls = "1.0" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 006415869c925..77210b97f3761 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -19,9 +19,9 @@ log = "0.4.8" parity-wasm = "0.42.0" codec = { package = "parity-scale-codec", version = "2.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } -sp-wasm-interface = { version = "4.0.0-dev", path = "../../../primitives/wasm-interface" } -sp-runtime-interface = { version = "4.0.0-dev", path = "../../../primitives/runtime-interface" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-wasm-interface = { version = "4.0.0", path = "../../../primitives/wasm-interface" } +sp-runtime-interface = { version = "4.0.0", path = "../../../primitives/runtime-interface" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } wasmtime = { version = "0.31.0", default-features = false, features = [ "cache", diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 65a0580b9e953..fa60751d48912 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -30,7 +30,7 @@ sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } @@ -56,6 +56,6 @@ sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-test = { version = "0.8.0", path = "../network/test" } sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } tokio = "1.13" tempfile = "3.1.0" diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index ad39ad6ba95b3..a83a47af9ed48 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" sc-finality-grandpa = { version = "0.10.0-dev", path = "../" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } finality-grandpa = { version = "0.14.4", features = ["derive-codec"] } jsonrpc-core = "18.0.0" @@ -32,7 +32,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ "test-helpers", ] } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 9da825faf033a..ac2663902b67f 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.50" derive_more = "0.99.16" sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } hex = "0.4.0" parking_lot = "0.11.1" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 8ee4d7f145726..229a273eabdc6 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -53,7 +53,7 @@ sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } @@ -72,7 +72,7 @@ libp2p = { version = "0.40.0", default-features = false } quickcheck = "1.0.3" rand = "0.7.2" sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } tempfile = "3.1.0" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 84aab96a673d6..afa4622d2f05a 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -26,11 +26,11 @@ sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } -sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } sc-service = { version = "0.10.0-dev", default-features = false, features = ["test-helpers"], path = "../../service" } async-trait = "0.1.50" diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index b92ee7041e5fd..6f1fd3a035fec 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -25,7 +25,7 @@ rand = "0.7.2" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } @@ -40,7 +40,7 @@ sc-client-db = { version = "0.10.0-dev", default-features = true, path = "../db" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } tokio = "1.13" diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index a758d29aed2c2..5f7a2d2fb32bf 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -23,7 +23,7 @@ log = "0.4.8" parking_lot = "0.11.1" thiserror = "1.0" -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-runtime = { path = "../../primitives/runtime", version = "4.0.0-dev" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } @@ -31,4 +31,4 @@ serde = { version = "1.0.126", features = ["derive"] } serde_json = "1.0.71" sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 6cf2d699386df..9d8461238fc06 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } futures = "0.3.16" jsonrpc-pubsub = "18.0.0" log = "0.4.8" -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } rpc = { package = "jsonrpc-core", version = "18.0.0" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } serde_json = "1.0.71" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 161863b14710b..91143c45b4a23 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -38,11 +38,11 @@ serde_json = "1.0.71" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } -sp-externalities = { version = "0.10.0-dev", path = "../../primitives/externalities" } +sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } @@ -50,7 +50,7 @@ sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/applic sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } -sp-storage = { version = "4.0.0-dev", path = "../../primitives/storage" } +sp-storage = { version = "4.0.0", path = "../../primitives/storage" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } @@ -71,7 +71,7 @@ sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-offchain = { version = "4.0.0-dev", path = "../offchain" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } parity-util-mem = { version = "0.10.2", default-features = false, features = [ diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index fe953a53bdd04..c89442f3aec71 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -22,9 +22,9 @@ parking_lot = "0.11.1" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } -sp-externalities = { version = "0.10.0-dev", path = "../../../primitives/externalities" } +sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } sp-trie = { version = "4.0.0-dev", path = "../../../primitives/trie" } -sp-storage = { version = "4.0.0-dev", path = "../../../primitives/storage" } +sp-storage = { version = "4.0.0", path = "../../../primitives/storage" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../../db" } futures = "0.3.16" sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../../service" } @@ -32,7 +32,7 @@ sc-network = { version = "0.10.0-dev", path = "../../network" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } @@ -41,4 +41,4 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-executor = { version = "0.10.0-dev", path = "../../executor" } sp-panic-handler = { version = "4.0.0-dev", path = "../../../primitives/panic-handler" } parity-scale-codec = "2.3.1" -sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index cd14038cb77b5..8c059e80cdb26 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] parking_lot = "0.11.1" log = "0.4.11" sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } parity-util-mem-derive = "0.1.0" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 6a969b33deb1a..81710887b816d 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -28,12 +28,12 @@ thiserror = "1.0.30" tracing = "0.1.29" tracing-log = "0.1.2" tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-tracing-proc-macro = { version = "4.0.0-dev", path = "./proc-macro" } sc-rpc-server = { version = "4.0.0-dev", path = "../rpc-servers" } diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 3d2a450c4101a..b3a7095fcb75d 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -23,9 +23,9 @@ parking_lot = "0.11.1" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 233c88279d35b..0f2e3cbf3d4e9 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } # Needed for type-safe access to storage DB. @@ -25,8 +25,8 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } -sp-std = { version = "4.0.0-dev", path = "../../primitives/std" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-std = { version = "4.0.0", path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 303116161a2dc..0c2d7616f57ed 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -18,9 +18,9 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index cb5903048ff8b..1252e7b51e00f 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-consensus-aura = { version = "0.10.0-dev", path = "../../primitives/consensus/aura", default-features = false } @@ -24,7 +24,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } [dev-dependencies] -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index 06a4e92270b2b..c7b5abe350b88 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } pallet-session = { version = "4.0.0-dev", features = [ "historical", ], path = "../session", default-features = false } @@ -28,7 +28,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index a24b578fc250e..48a6c473875c0 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -18,14 +18,14 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } impl-trait-for-tuples = "0.2.1" [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index a2224df86798c..077a8cb89a929 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -28,7 +28,7 @@ sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primiti sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } log = { version = "0.4.14", default-features = false } [dev-dependencies] @@ -36,7 +36,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } [features] diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index b7eebdd0df102..fe8d08ed9766c 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -19,7 +19,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] # primitives sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # FRAME frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -32,14 +32,14 @@ log = { version = "0.4.14", default-features = false } # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking", optional = true, default-features = false } pallet-balances = { version = "4.0.0-dev", path = "../balances", optional = true, default-features = false } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core", optional = true, default-features = false } +sp-core = { version = "4.0.0", path = "../../primitives/core", optional = true, default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", optional = true, default-features = false } -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing", optional = true, default-features = false } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing", optional = true, default-features = false } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core"} +sp-core = { version = "4.0.0", path = "../../primitives/core"} sp-io = { version = "4.0.0-dev", path = "../../primitives/io"} -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support", features = ["runtime-benchmarks"] } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } @@ -70,4 +70,3 @@ fuzz = [ "sp-tracing", ] try-runtime = [ "frame-support/try-runtime" ] - diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index ecc0b4da242c7..5a5b028285d88 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -21,11 +21,11 @@ frame-system = { path = "../../system", version = "4.0.0-dev" } frame-support = { path = "../../support", version = "4.0.0-dev" } # core -sp-storage = { path = "../../../primitives/storage", version = "4.0.0-dev" } -sp-core = { path = "../../../primitives/core", version = "4.0.0-dev" } -sp-tracing = { path = "../../../primitives/tracing", version = "4.0.0-dev" } +sp-storage = { path = "../../../primitives/storage", version = "4.0.0" } +sp-core = { path = "../../../primitives/core", version = "4.0.0" } +sp-tracing = { path = "../../../primitives/tracing", version = "4.0.0" } sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0-dev" } -sp-std = { path = "../../../primitives/std", version = "4.0.0-dev" } +sp-std = { path = "../../../primitives/std", version = "4.0.0" } # utils remote-externalities = { path = "../../../utils/frame/remote-externalities", version = "0.10.0-dev" } diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 5565915f6ded6..825869c6b9725 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -24,7 +24,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } [features] diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index b99b6f7e9feaa..cebd7a6d962b1 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -21,10 +21,10 @@ pallet-mmr = { version = "4.0.0-dev", path = "../merkle-mountain-range", default pallet-mmr-primitives = { version = "4.0.0-dev", path = "../merkle-mountain-range/primitives", default-features = false } pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } -sp-std = { version = "4.0.0-dev", path = "../../primitives/std", default-features = false } +sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } beefy-merkle-tree = { version = "4.0.0-dev", path = "./primitives", default-features = false } beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 7e1cec9d438ea..4bfd9f19b2806 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -16,14 +16,14 @@ frame-support = { version = "4.0.0-dev", path = "../support", default-features = frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } -sp-std = { version = "4.0.0-dev", path = "../../primitives/std", default-features = false } +sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", default-features = false } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 4160f040c3bcb..d907cf71948f0 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -18,12 +18,12 @@ paste = "1.0" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } -sp-runtime-interface = { version = "4.0.0-dev", path = "../../primitives/runtime-interface", default-features = false } +sp-runtime-interface = { version = "4.0.0", path = "../../primitives/runtime-interface", default-features = false } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } -sp-std = { version = "4.0.0-dev", path = "../../primitives/std", default-features = false } +sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto", default-features = false } -sp-storage = { version = "4.0.0-dev", path = "../../primitives/storage", default-features = false } +sp-storage = { version = "4.0.0", path = "../../primitives/storage", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } log = { version = "0.4.14", default-features = false } diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 6c9cef417e99f..5dfa05bba0a07 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -17,13 +17,13 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 040337424d399..37152e29d8f40 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -17,14 +17,14 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../bounties" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index d4dc8f9a2d8d0..76799ae981c7a 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -17,10 +17,10 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = log = { version = "0.4.14", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 0b10962f0e63f..bb7a0693147b2 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -38,11 +38,11 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, path = "common" } pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../primitives/sandbox" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] assert_matches = "1" diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/common/Cargo.toml index 5f52ce7fcfe55..ebfd5fab5af16 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/common/Cargo.toml @@ -19,8 +19,8 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] serde = { version = "1", features = ["derive"], optional = true } # Substrate Dependencies (This crate should not rely on frame) -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core", default-features = false } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-core = { version = "4.0.0", path = "../../../primitives/core", default-features = false } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index 82ce4bedb4985..aac5683a79e52 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -24,7 +24,7 @@ pallet-contracts-primitives = { version = "4.0.0-dev", path = "../common" } pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml index b65fbf9aba0c7..2c293b3a906a1 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/rpc/runtime-api/Cargo.toml @@ -20,7 +20,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, path = "../../common" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../../primitives/std" } [features] default = ["std"] diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 43b35b9f7a1f6..becec8a878d5d 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } @@ -26,7 +26,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index c041d6c684c7f..42d7c4064cb30 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -24,8 +24,8 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } @@ -43,10 +43,10 @@ strum_macros = { optional = true, version = "0.22.0" } [dev-dependencies] parking_lot = "0.11.0" rand = { version = "0.7.3" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } frame-election-provider-support = { version = "4.0.0-dev", features = [ ], path = "../election-provider-support" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index e22338f456c44..a69dca39b8e8f 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -24,7 +24,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys [dev-dependencies] sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index 921a7057bcda9..a5e9ca777c3ce 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -22,14 +22,14 @@ sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = ". sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] diff --git a/frame/elections/Cargo.toml b/frame/elections/Cargo.toml index 2ca2e584d2f43..e5f7d27d89113 100644 --- a/frame/elections/Cargo.toml +++ b/frame/elections/Cargo.toml @@ -17,8 +17,8 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 8ac375cb36037..5edd3bfef8de5 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -23,10 +23,10 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../../ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core", default-features = false } +sp-core = { version = "4.0.0", path = "../../../primitives/core", default-features = false } [features] default = ["std"] diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index cb505ad42f254..44886afba5e13 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -20,11 +20,11 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [features] default = ["std"] diff --git a/frame/examples/parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml index cf7f46b232247..3d9104eb35451 100644 --- a/frame/examples/parallel/Cargo.toml +++ b/frame/examples/parallel/Cargo.toml @@ -17,10 +17,10 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } [features] diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 20e31fe0a5720..9509fc5c977b5 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -20,14 +20,14 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-tracing = { version = "4.0.0-dev", default-features = false, path = "../../primitives/tracing" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } [dev-dependencies] hex-literal = "0.3.4" -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index e9ee8ba14abad..14948546a1771 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } @@ -24,7 +24,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys [dev-dependencies] sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index ba2d98fc354e8..d052b468f9272 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -16,11 +16,11 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index b791256d9452b..dc247727e0981 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } enumflags2 = { version = "0.6.2" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } @@ -24,7 +24,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index 2fa0b5ebc12aa..fc0a6acf17981 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -17,8 +17,8 @@ sp-application-crypto = { version = "4.0.0-dev", default-features = false, path pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index 7f27ac23c6456..f4f5146ae1185 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-keyring = { version = "4.0.0-dev", optional = true, path = "../../primitives/keyring" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index e65bb01660b58..db317d0d01ec3 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -27,7 +27,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " [dev-dependencies] frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 9eafaedee7db1..105bdc55b5c01 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -17,10 +17,10 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index ee9080b19d611..51b7e4a2a6071 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -16,10 +16,10 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, version = "0.3.2" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index 0531a295fafe3..11562c02bf325 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -17,9 +17,9 @@ log = { version = "0.4.14", default-features = false } serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index d8f861ad8ec50..1cad739e3ba0e 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -21,7 +21,7 @@ serde = { version = "1.0.126", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index f409e0c6c8d06..bb6323bc5cb75 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -18,13 +18,13 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 039fd7f97c851..8d66bbb6b3973 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -15,14 +15,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 450da1325f67e..ec62d972d3a0c 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -16,10 +16,10 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } log = { version = "0.4.14", default-features = false } [features] diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 15939027d3be1..8957f0c88cae3 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } serde = { version = "1.0.126", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } @@ -26,7 +26,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index cf628b6967ce0..96674989e0f71 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -31,13 +31,13 @@ pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ ], path = "../../staking" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } [dev-dependencies] pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } [features] diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index be288ecc0d759..762ab482b9854 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -19,12 +19,12 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index 38fe2f73bc71b..3bf2a9c30213b 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -17,13 +17,13 @@ safe-mix = { version = "1.0", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 12198c135e536..18d4dfe7e47c9 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -15,14 +15,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 01cf95fa7fc7c..57eb5e16bd368 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -15,14 +15,14 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } log = { version = "0.4.14", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index d60e55ae98963..8f91908dddb9a 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -17,13 +17,13 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 90de15632a0ea..50aa623c90a82 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -19,8 +19,8 @@ impl-trait-for-tuples = "0.2.1" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 31a028679cfb9..5dc0573b278fb 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] rand = { version = "0.7.2", default-features = false } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } @@ -28,7 +28,7 @@ pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ [dev-dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } scale-info = "1.0" -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index 8a817f7e0060b..47ad0865b8f4f 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } rand_chacha = { version = "0.2", default-features = false } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-io ={ version = "4.0.0-dev", path = "../../primitives/io" } frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 81f5b181850c1..70beead038b21 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } @@ -37,8 +37,8 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " rand_chacha = { version = "0.2", default-features = false, optional = true } [dev-dependencies] -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index 969dc11dbb6c5..d211d327b2d05 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -15,14 +15,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 1f48dadc2987d..411b02449e4e2 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -17,11 +17,11 @@ serde = { version = "1.0.126", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-metadata = { version = "14.0.0", default-features = false, features = ["v14"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-tracing = { version = "4.0.0-dev", default-features = false, path = "../../primitives/tracing" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 09a1538e2741d..13d66d147e578 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -20,8 +20,8 @@ sp-io = { version = "4.0.0-dev", path = "../../../primitives/io", default-featur sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../../../primitives/state-machine" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } trybuild = "1.0.52" pretty_assertions = "1.0.0" diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index b8a64f4e7022a..62472a8957ce3 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" } support = { package = "frame-support", version = "4.0.0-dev", default-features = false, path = "../../" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index c5d2144e28dd0..fc510d1d9d792 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.126", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } @@ -26,7 +26,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] criterion = "0.3.3" -sp-externalities = { version = "0.10.0-dev", path = "../../primitives/externalities" } +sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 7e7c2f6e69f20..9468c8761435a 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } [dev-dependencies] sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index a942b58e09509..26554598be103 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } @@ -29,7 +29,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] sp-io ={ version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 49b19756e43cc..565afcd3fbc66 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -18,10 +18,10 @@ log = { version = "0.4.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.126", features = ["derive"], optional = true } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -30,7 +30,7 @@ pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-storage = { version = "4.0.0-dev", path = "../../primitives/storage" } +sp-storage = { version = "4.0.0", path = "../../primitives/storage" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 3b8b85977db3d..64e1d5c762ca7 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -20,10 +20,10 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] serde = { version = "1.0.126", optional = true } smallvec = "1.7.0" -sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index a79bf68551000..cae6b7b914e17 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate dependencies -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } @@ -32,7 +32,7 @@ serde = { version = "1.0.126", optional = true } smallvec = "1.7.0" serde_json = "1.0.71" -sp-storage = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/storage" } +sp-storage = { version = "4.0.0", default-features = false, path = "../../../primitives/storage" } pallet-assets = { version = "4.0.0-dev", path = "../../assets" } pallet-authorship = { version = "4.0.0-dev", path = "../../authorship" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 8ce2e4991568c..dd18edf5daf0f 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -20,7 +20,7 @@ jsonrpc-derive = "18.0.0" sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 4b4ee7de85098..141aeb496ddec 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -21,7 +21,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-storage-proof" } @@ -29,7 +29,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " [dev-dependencies] sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = true, path = "../../primitives/transaction-storage-proof" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } [features] default = ["std"] diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index d44699825a6f9..4cbcb08c3ef68 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -21,7 +21,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] serde = { version = "1.0.126", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.1" -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } @@ -32,7 +32,7 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ [dev-dependencies] sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index c947717953192..64622bcceb020 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } -sp-std = { version = "4.0.0-dev", path = "../../primitives/std" , default-features = false } +sp-std = { version = "4.0.0", path = "../../primitives/std" , default-features = false } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" , default-features = false } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 9d7e8f7184d16..7eddc85b67bbe 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-std = { version = "4.0.0-dev", path = "../../primitives/std" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-std = { version = "4.0.0", path = "../../primitives/std" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 8407bf53e73d2..ac9254bd08546 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -17,15 +17,15 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index efec3be330dcc..5d66db1c981b9 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -26,7 +26,7 @@ log = { version = "0.4.0", default-features = false } [dev-dependencies] sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index 5723f9cf11b51..d64da8ff84d7f 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../version" } sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../state-machine" } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index dccc123142dac..dc2ca67242ac6 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-api = { version = "4.0.0-dev", path = "../" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } sp-version = { version = "4.0.0-dev", path = "../../version" } -sp-tracing = { version = "4.0.0-dev", path = "../../tracing" } +sp-tracing = { version = "4.0.0", path = "../../tracing" } sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } sp-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } @@ -28,7 +28,7 @@ rustversion = "1.0.5" criterion = "0.3.0" futures = "0.3.9" log = "0.4.14" -sp-core = { version = "4.0.0-dev", path = "../../core" } +sp-core = { version = "4.0.0", path = "../../core" } [[bench]] name = "bench" diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index e715d2ed3d31c..fd6dd87fa1b20 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.126", optional = true, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } [features] diff --git a/primitives/application-crypto/test/Cargo.toml b/primitives/application-crypto/test/Cargo.toml index f59f5d9a249cb..6ab3cfed0815d 100644 --- a/primitives/application-crypto/test/Cargo.toml +++ b/primitives/application-crypto/test/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../core" } sp-keystore = { version = "0.10.0-dev", path = "../../keystore", default-features = false } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 139a04180828c..9bd634bb51879 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -22,9 +22,9 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] integer-sqrt = "0.1.2" static_assertions = "1.1.0" num-traits = { version = "0.2.8", default-features = false } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } serde = { version = "1.0.126", optional = true, features = ["derive"] } -sp-debug-derive = { version = "4.0.0-dev", default-features = false, path = "../debug-derive" } +sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } [dev-dependencies] rand = "0.7.2" diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index 22f3884b55021..116bc1438ce67 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", default-features = false, version = "2.0.0" } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index a31a349611163..26259e45ea6bb 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index e38af745cd714..4a1f844b92002 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -13,9 +13,9 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-api = { version = "4.0.0-dev", path = "../api", default-features = false } sp-application-crypto = { version = "4.0.0-dev", path = "../application-crypto", default-features = false } -sp-core = { version = "4.0.0-dev", path = "../core", default-features = false } +sp-core = { version = "4.0.0", path = "../core", default-features = false } sp-runtime = { version = "4.0.0-dev", path = "../runtime", default-features = false } -sp-std = { version = "4.0.0-dev", path = "../std", default-features = false } +sp-std = { version = "4.0.0", path = "../std", default-features = false } [dev-dependencies] hex = "0.4.3" diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index 6c6579c353298..a346f95cc4c4b 100644 --- a/primitives/block-builder/Cargo.toml +++ b/primitives/block-builder/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index 361095c6218ff..e3c883a6e7834 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index d942f72909453..a07dc54e2979f 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -17,12 +17,12 @@ sp-application-crypto = { version = "4.0.0-dev", default-features = false, path codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } merlin = { version = "2.0", default-features = false } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-consensus = { version = "0.10.0-dev", optional = true, path = "../common" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } sp-consensus-vrf = { version = "0.10.0-dev", path = "../vrf", default-features = false } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../../keystore", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 08e50a954288c..4b5ef8796afa6 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -20,11 +20,11 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ ] } futures = { version = "0.3.1", features = ["thread-pool"] } log = "0.4.8" -sp-core = { path = "../../core", version = "4.0.0-dev" } +sp-core = { path = "../../core", version = "4.0.0" } sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } sp-state-machine = { version = "0.10.0-dev", path = "../../state-machine" } futures-timer = "3.0.1" -sp-std = { version = "4.0.0-dev", path = "../../std" } +sp-std = { version = "4.0.0", path = "../../std" } sp-version = { version = "4.0.0-dev", path = "../../version" } sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } thiserror = "1.0.30" diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index 07863850a8f87..1612868b3637c 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -14,9 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } [features] diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 8a99dc9432a0b..97e426016d9a1 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { version = "2.0.0", package = "parity-scale-codec", default-features = false } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } -sp-std = { version = "4.0.0-dev", path = "../../std", default-features = false } -sp-core = { version = "4.0.0-dev", path = "../../core", default-features = false } +sp-std = { version = "4.0.0", path = "../../std", default-features = false } +sp-core = { version = "4.0.0", path = "../../core", default-features = false } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } [features] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 61451e10ecf2f..5c805ff1dab88 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-core" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -13,7 +13,6 @@ documentation = "https://docs.rs/sp-core" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = [ "derive", "max-encoded-len", @@ -40,9 +39,10 @@ zeroize = { version = "1.4.2", default-features = false } secrecy = { version = "0.8.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.11.1", optional = true } -sp-debug-derive = { version = "4.0.0-dev", default-features = false, path = "../debug-derive" } -sp-externalities = { version = "0.10.0-dev", optional = true, path = "../externalities" } -sp-storage = { version = "4.0.0-dev", default-features = false, path = "../storage" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } +sp-storage = { version = "4.0.0", default-features = false, path = "../storage" } +sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } parity-util-mem = { version = "0.10.2", default-features = false, features = [ "primitive-types", ] } @@ -66,10 +66,10 @@ sha2 = { version = "0.9.8", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } twox-hash = { version = "1.6.1", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", "static-context"], optional = true } -sp-core-hashing = { version = "4.0.0-dev", path = "./hashing", default-features = false, optional = true } merlin = { version = "2.0", default-features = false, optional = true } ss58-registry = { version = "1.5.0", default-features = false } -sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" } +sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } +sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../runtime-interface" } [dev-dependencies] sp-serializer = { version = "4.0.0-dev", path = "../serializer" } diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index eeee40405344c..23ff01c0b34b8 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-core-hashing" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -13,7 +13,7 @@ documentation = "https://docs.rs/sp-core-hashing" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } byteorder = { version = "1.3.2", default-features = false } blake2-rfc = { version = "0.2.18", default-features = false } diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index 89b225e6aaa5f..dcd2f134519e7 100644 --- a/primitives/core/hashing/proc-macro/Cargo.toml +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -19,4 +19,4 @@ proc-macro = true syn = { version = "1.0.81", features = ["full", "parsing"] } quote = "1.0.6" proc-macro2 = "1.0.29" -sp-core-hashing = { version = "4.0.0-dev", path = "../", default-features = false } +sp-core-hashing = { version = "4.0.0", path = "../", default-features = false } diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml index 49b8ac832cf0f..a38cc186fb52c 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-debug-derive" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/externalities/Cargo.toml b/primitives/externalities/Cargo.toml index 96199c5b4d222..6c26b436796ee 100644 --- a/primitives/externalities/Cargo.toml +++ b/primitives/externalities/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-externalities" -version = "0.10.0-dev" +version = "0.10.0" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2021" @@ -14,8 +14,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-storage = { version = "4.0.0-dev", path = "../storage", default-features = false } -sp-std = { version = "4.0.0-dev", path = "../std", default-features = false } +sp-storage = { version = "4.0.0", path = "../storage", default-features = false } +sp-std = { version = "4.0.0", path = "../std", default-features = false } environmental = { version = "1.1.3", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index 4b9fde85147ea..be4f3c6d1e3dc 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -22,10 +22,10 @@ log = { version = "0.4.8", optional = true } serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../keystore", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] default = ["std"] diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 3efd6ab032131..c531ad4e5764f 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } sp-runtime = { version = "4.0.0-dev", path = "../runtime", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 2e0982a6e5f13..520dc12a52603 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -17,16 +17,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } hash-db = { version = "0.15.2", default-features = false } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } sp-keystore = { version = "0.10.0-dev", default-features = false, optional = true, path = "../keystore" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } libsecp256k1 = { version = "0.7", optional = true } sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../state-machine" } -sp-wasm-interface = { version = "4.0.0-dev", path = "../wasm-interface", default-features = false } -sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" } +sp-wasm-interface = { version = "4.0.0", path = "../wasm-interface", default-features = false } +sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../runtime-interface" } sp-trie = { version = "4.0.0-dev", optional = true, path = "../trie" } -sp-externalities = { version = "0.10.0-dev", optional = true, path = "../externalities" } -sp-tracing = { version = "4.0.0-dev", default-features = false, path = "../tracing" } +sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } +sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.8", optional = true } futures = { version = "0.3.1", features = ["thread-pool"], optional = true } parking_lot = { version = "0.11.1", optional = true } diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 249e7d766e39e..66c1240a8a567 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0-dev", path = "../core" } +sp-core = { version = "4.0.0", path = "../core" } sp-runtime = { version = "4.0.0-dev", path = "../runtime" } lazy_static = "1.4.0" strum = { version = "0.22.0", features = ["derive"] } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index ab026ccedd512..b0061ac111e20 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -21,8 +21,8 @@ schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backen merlin = { version = "2.0", default-features = false } parking_lot = { version = "0.11.1", default-features = false } serde = { version = "1.0", optional = true} -sp-core = { version = "4.0.0-dev", path = "../core" } -sp-externalities = { version = "0.10.0-dev", path = "../externalities", default-features = false } +sp-core = { version = "4.0.0", path = "../core" } +sp-externalities = { version = "0.10.0", path = "../externalities", default-features = false } [dev-dependencies] rand = "0.7.2" diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 95f303a382526..16aca8dc71d9c 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.126", optional = true, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../arithmetic" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } sp-runtime = { version = "4.0.0-dev", path = "../runtime", default-features = false } [dev-dependencies] diff --git a/primitives/offchain/Cargo.toml b/primitives/offchain/Cargo.toml index c4da2b4f88921..f079ccb7913fe 100644 --- a/primitives/offchain/Cargo.toml +++ b/primitives/offchain/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index 2d56cb06fbcca..59cbf53fee2a1 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.126", features = ["derive"] } -sp-core = { version = "4.0.0-dev", path = "../core" } +sp-core = { version = "4.0.0", path = "../core" } rustc-hash = "1.1.0" [dev-dependencies] diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index dd93b92b9be4e..64781481fa12a 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime-interface" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -14,21 +14,21 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-wasm-interface = { version = "4.0.0-dev", path = "../wasm-interface", default-features = false } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } -sp-tracing = { version = "4.0.0-dev", default-features = false, path = "../tracing" } -sp-runtime-interface-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } -sp-externalities = { version = "0.10.0-dev", optional = true, path = "../externalities" } +sp-wasm-interface = { version = "4.0.0", path = "../wasm-interface", default-features = false } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } +sp-runtime-interface-proc-macro = { version = "4.0.0", path = "proc-macro" } +sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } static_assertions = "1.0.0" primitive-types = { version = "0.10.1", default-features = false } -sp-storage = { version = "4.0.0-dev", default-features = false, path = "../storage" } +sp-storage = { version = "4.0.0", default-features = false, path = "../storage" } impl-trait-for-tuples = "0.2.1" [dev-dependencies] sp-runtime-interface-test-wasm = { version = "2.0.0", path = "test-wasm" } sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } -sp-core = { version = "4.0.0-dev", path = "../core" } +sp-core = { version = "4.0.0", path = "../core" } sp-io = { version = "4.0.0-dev", path = "../io" } rustversion = "1.0.5" trybuild = "1.0.52" diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 0be33c2c55ad1..0b5929616bd35 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime-interface-proc-macro" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 60ece9d78795f..68ed8a73282aa 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -13,10 +13,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../std" } +sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../" } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../io" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../core" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index d8dcc8a470530..ab227ddeda277 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -13,10 +13,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../std" } +sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../" } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../io" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../../core" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 4c88438f08c66..5e4483fb38ed7 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "4.0.0-dev", path = "../" } +sp-runtime-interface = { version = "4.0.0", path = "../" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-executor-common = { version = "0.10.0-dev", path = "../../../client/executor/common" } sp-runtime-interface-test-wasm = { version = "2.0.0", path = "../test-wasm" } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 511d3c1e37923..76c1d94a3b6df 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -18,10 +18,10 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.126", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../arithmetic" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } log = { version = "0.4.14", default-features = false } paste = "1.0" @@ -37,7 +37,7 @@ rand = "0.7.2" sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } sp-api = { version = "4.0.0-dev", path = "../api" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } zstd = "0.9" [features] diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index 8e7acff4ff7e8..a51873dc1e998 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -20,10 +20,10 @@ wasmi = "0.9.0" [dependencies] wasmi = { version = "0.9.0", optional = true } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } -sp-wasm-interface = { version = "4.0.0-dev", default-features = false, path = "../wasm-interface" } +sp-wasm-interface = { version = "4.0.0", default-features = false, path = "../wasm-interface" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } log = { version = "0.4", default-features = false } diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index 01b299091ed1c..eda98b2ab6a8e 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" } sp-runtime = { version = "4.0.0-dev", optional = true, path = "../runtime" } diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 3be8f4aba1428..531e696b69307 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] default = ["std"] diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 0133ea17370a8..f5047c3c7c464 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -21,14 +21,14 @@ hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.22.6", default-features = false } trie-root = { version = "0.16.0", default-features = false } sp-trie = { version = "4.0.0-dev", path = "../trie", default-features = false } -sp-core = { version = "4.0.0-dev", path = "../core", default-features = false } +sp-core = { version = "4.0.0", path = "../core", default-features = false } sp-panic-handler = { version = "4.0.0-dev", path = "../panic-handler", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } num-traits = { version = "0.2.8", default-features = false } rand = { version = "0.7.2", optional = true } -sp-externalities = { version = "0.10.0-dev", path = "../externalities", default-features = false } +sp-externalities = { version = "0.10.0", path = "../externalities", default-features = false } smallvec = "1.7.0" -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } tracing = { version = "0.1.29", optional = true } [dev-dependencies] diff --git a/primitives/std/Cargo.toml b/primitives/std/Cargo.toml index 34f27ae7256d1..4c6aa8f40b498 100644 --- a/primitives/std/Cargo.toml +++ b/primitives/std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-std" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index c9166a5bbba07..918938273c620 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-storage" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" description = "Storage related primitives" @@ -14,11 +14,11 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } serde = { version = "1.0.126", optional = true, features = ["derive"] } impl-serde = { version = "0.3.1", optional = true } ref-cast = "1.0.0" -sp-debug-derive = { version = "4.0.0-dev", default-features = false, path = "../debug-derive" } +sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } [features] diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index f472ec88ea189..9a80cc50cf2ff 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.8", optional = true } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } -sp-externalities = { version = "0.10.0-dev", optional = true, path = "../externalities" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } -sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../runtime-interface" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] codec = { package = "parity-scale-codec", default-features = false, version = "2.0.0" } diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index b95c88626996b..ea1e61c8da112 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 609ecd0d31921..0096fe4c809d2 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index f4bfb1f15dad3..0b5a273e11d39 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-tracing" -version = "4.0.0-dev" +version = "4.0.0" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2021" @@ -18,7 +18,7 @@ features = ["with-tracing"] targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] [dependencies] -sp-std = { version = "4.0.0-dev", path = "../std", default-features = false } +sp-std = { version = "4.0.0", path = "../std", default-features = false } codec = { version = "2.0.0", package = "parity-scale-codec", default-features = false, features = [ "derive", ] } diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index c967497f4ff96..05da54b24f787 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -15,9 +15,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-trie = { version = "4.0.0-dev", optional = true, path = "../trie" } -sp-core = { version = "4.0.0-dev", path = "../core", optional = true } +sp-core = { version = "4.0.0", path = "../core", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.8", optional = true } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 8eaeb424781bf..af81164ed799d 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -20,12 +20,12 @@ harness = false [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.22.6", default-features = false } trie-root = { version = "0.16.0", default-features = false } memory-db = { version = "0.27.0", default-features = false } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../core" } +sp-core = { version = "4.0.0", default-features = false, path = "../core" } [dev-dependencies] trie-bench = "0.28.0" diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index bbdaf9c1cab1b..103fe16dc53ab 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -19,7 +19,7 @@ impl-serde = { version = "0.3.1", optional = true } serde = { version = "1.0.126", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../std" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" } parity-wasm = { version = "0.42.2", optional = true } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index c378b185e392c..da0d0161c086c 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-wasm-interface" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] wasmi = { version = "0.9.1", optional = true } impl-trait-for-tuples = "0.2.1" -sp-std = { version = "4.0.0-dev", path = "../std", default-features = false } +sp-std = { version = "4.0.0", path = "../std", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } [features] diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index ef481dd3f202a..3917f3fefcf9b 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -29,7 +29,7 @@ sc-service = { version = "0.10.0-dev", default-features = false, features = [ ], path = "../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index d0d85029738ea..35c14a23f2a20 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -23,9 +23,9 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-keyring = { version = "4.0.0-dev", optional = true, path = "../../primitives/keyring" } memory-db = { version = "0.27.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } -sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } -sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime-interface" } +sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../../primitives/runtime-interface" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../frame/support" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } @@ -43,7 +43,7 @@ trie-db = { version = "0.22.6", default-features = false } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } sp-state-machine = { version = "0.10.0-dev", default-features = false, path = "../../primitives/state-machine" } -sp-externalities = { version = "0.10.0-dev", default-features = false, path = "../../primitives/externalities" } +sp-externalities = { version = "0.10.0", default-features = false, path = "../../primitives/externalities" } # 3rd party cfg-if = "1.0" diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index e5cba3a3399a1..6dd22e4954c2d 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -16,7 +16,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } substrate-test-client = { version = "2.0.0", path = "../../client" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } substrate-test-runtime = { version = "2.0.0", path = "../../runtime" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index fab2b963239d3..2943877ce4a04 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } -sp-externalities = { version = "0.10.0-dev", path = "../../../primitives/externalities" } +sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index dfbf73ee9d5fa..6c3cb04282849 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" [dependencies] -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } structopt = "0.3.25" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 105ab1739f5b6..ab91f26490178 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -23,7 +23,7 @@ serde_json = "1.0" serde = "1.0.126" sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } -sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index dbaa12ee5ddb9..8e491cc634def 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -20,7 +20,7 @@ jsonrpc-client-transports = { version = "18.0.0", features = ["http"] } codec = { package = "parity-scale-codec", version = "2.0.0" } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } -sp-storage = { version = "4.0.0-dev", path = "../../../../primitives/storage" } +sp-storage = { version = "4.0.0", path = "../../../../primitives/storage" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } [dev-dependencies] diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 31a46b3902106..5fc3812b84da4 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -23,7 +23,7 @@ log = "0.4.8" sp-runtime = { version = "4.0.0-dev", path = "../../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } -sp-core = { version = "4.0.0-dev", path = "../../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../../client/transaction-pool/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../../primitives/block-builder" } @@ -31,5 +31,5 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } -sp-tracing = { version = "4.0.0-dev", path = "../../../../primitives/tracing" } +sp-tracing = { version = "4.0.0", path = "../../../../primitives/tracing" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../../client/transaction-pool" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 388b23aeb3eba..71db6100ca175 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -24,10 +24,10 @@ sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sp-state-machine = { version = "0.10.0-dev", path = "../../../../primitives/state-machine" } sp-runtime = { version = "4.0.0-dev", path = "../../../../primitives/runtime" } -sp-core = { version = "4.0.0-dev", path = "../../../../primitives/core" } +sp-core = { version = "4.0.0", path = "../../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../../primitives/io" } sp-keystore = { version = "0.10.0-dev", path = "../../../../primitives/keystore" } -sp-externalities = { version = "0.10.0-dev", path = "../../../../primitives/externalities" } +sp-externalities = { version = "0.10.0", path = "../../../../primitives/externalities" } sp-version = { version = "4.0.0-dev", path = "../../../../primitives/version" } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } From c6f86e139d57a37511af769c49b426c2fff3f260 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Dec 2021 21:03:35 +0000 Subject: [PATCH 0314/1472] Bump parity-db from 0.3.4 to 0.3.5 (#10330) Bumps [parity-db](https://github.com/paritytech/parity-db) from 0.3.4 to 0.3.5. - [Release notes](https://github.com/paritytech/parity-db/releases) - [Commits](https://github.com/paritytech/parity-db/commits) --- updated-dependencies: - dependency-name: parity-db 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/db/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3693fe0806930..a3e186aca4287 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6299,9 +6299,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cb5195cb862b13055cf7f7a76c55073dc73885c2a61511e322b8c1666be7332" +checksum = "78a95abf24f1097c6e3181abbbbfc3630b3b5e681470940f719b69acb4911c7f" dependencies = [ "blake2-rfc", "crc32fast", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 08e228ee9afac..f0ce20354a800 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -33,7 +33,7 @@ sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -parity-db = { version = "0.3.4", optional = true } +parity-db = { version = "0.3.5", optional = true } [dev-dependencies] sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } From b45359a50fa0dea641dc9258e60d0b513006a298 Mon Sep 17 00:00:00 2001 From: remzrn Date: Thu, 9 Dec 2021 08:05:48 +0300 Subject: [PATCH 0315/1472] Fixed logic of the storage migration to triple reference counting. (#10337) * Fixed logic of the storage migration to triple reference counting. The previous behaviour made it impossible for any chain not already upgraded to dual reference counting to upgrade the runtime. * +Removed the on_runtime_upgrade() function from frame-system. +Removed the specific migration .anciallaries from the frame-system pallet level. +Introducted a new module that hosts self-contained ancillary functions and logic to perform the storage migration. The current logic attempts to infer the state of the storage based on whether or not a given migration can be conducted. * Formatting. * + Removed specific AccountData struct. AccountData must now be provided during the runtime implementation of the trait V2ToV3. + Removed apply function. + Made the individual translation function self-sufficient. * + Removed unused decorators. --- frame/system/src/lib.rs | 51 +---------- frame/system/src/migrations/mod.rs | 139 +++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 49 deletions(-) create mode 100644 frame/system/src/migrations/mod.rs diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 7603fe6541415..7825c9ec07802 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -114,6 +114,8 @@ pub mod mocking; mod tests; pub mod weights; +pub mod migrations; + pub use extensions::{ check_genesis::CheckGenesis, check_mortality::CheckMortality, check_non_zero_sender::CheckNonZeroSender, check_nonce::CheckNonce, @@ -315,15 +317,6 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { - fn on_runtime_upgrade() -> frame_support::weights::Weight { - if !UpgradedToTripleRefCount::::get() { - UpgradedToTripleRefCount::::put(true); - migrations::migrate_to_triple_ref_count::() - } else { - 0 - } - } - fn integrity_test() { T::BlockWeights::get().validate().expect("The weights are invalid."); } @@ -634,46 +627,6 @@ pub mod pallet { } } -pub mod migrations { - use super::*; - - #[allow(dead_code)] - /// Migrate from unique `u8` reference counting to triple `u32` reference counting. - pub fn migrate_all() -> frame_support::weights::Weight { - Account::::translate::<(T::Index, u8, T::AccountData), _>(|_key, (nonce, rc, data)| { - Some(AccountInfo { - nonce, - consumers: rc as RefCount, - providers: 1, - sufficients: 0, - data, - }) - }); - T::BlockWeights::get().max_block - } - - #[allow(dead_code)] - /// Migrate from unique `u32` reference counting to triple `u32` reference counting. - pub fn migrate_to_dual_ref_count() -> frame_support::weights::Weight { - Account::::translate::<(T::Index, RefCount, T::AccountData), _>( - |_key, (nonce, consumers, data)| { - Some(AccountInfo { nonce, consumers, providers: 1, sufficients: 0, data }) - }, - ); - T::BlockWeights::get().max_block - } - - /// Migrate from dual `u32` reference counting to triple `u32` reference counting. - pub fn migrate_to_triple_ref_count() -> frame_support::weights::Weight { - Account::::translate::<(T::Index, RefCount, RefCount, T::AccountData), _>( - |_key, (nonce, consumers, providers, data)| { - Some(AccountInfo { nonce, consumers, providers, sufficients: 0, data }) - }, - ); - T::BlockWeights::get().max_block - } -} - #[cfg(feature = "std")] impl GenesisConfig { /// Direct implementation of `GenesisBuild::build_storage`. diff --git a/frame/system/src/migrations/mod.rs b/frame/system/src/migrations/mod.rs new file mode 100644 index 0000000000000..03547d200f4ac --- /dev/null +++ b/frame/system/src/migrations/mod.rs @@ -0,0 +1,139 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Migrate the reference counting state. + +use codec::{Decode, Encode, FullCodec}; +use frame_support::{ + pallet_prelude::ValueQuery, traits::PalletInfoAccess, weights::Weight, Blake2_128Concat, + RuntimeDebug, +}; +use sp_std::prelude::*; + +/// Type used to encode the number of references an account has. +type RefCount = u32; + +/// Information of an account. +#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode)] +struct AccountInfo { + nonce: Index, + consumers: RefCount, + providers: RefCount, + sufficients: RefCount, + data: AccountData, +} + +/// Trait to implement to give information about types used for migration +pub trait V2ToV3 { + /// The system pallet. + type Pallet: 'static + PalletInfoAccess; + + /// System config account id + type AccountId: 'static + FullCodec; + + /// System config index + type Index: 'static + FullCodec + Copy; + + /// System config account data + type AccountData: 'static + FullCodec; +} + +// ### Warning +// +// The call below is only valid because the name System is enforced +// at runtime construction level for the system pallet. +frame_support::generate_storage_alias!( + System, UpgradedToU32RefCount => Value< + bool, + ValueQuery + > +); + +// ### Warning +// +// The call below is only valid because the name System is enforced +// at runtime construction level for the system pallet. +frame_support::generate_storage_alias!( + System, UpgradedToTripleRefCount => Value< + bool, + ValueQuery + > +); + +// ### Warning +// +// The call below is only valid because the name System is enforced +// at runtime construction level for the system pallet. +frame_support::generate_storage_alias!( + System, Account => Map< + (Blake2_128Concat, T::AccountId), + AccountInfo + > +); + +/// Migrate from unique `u8` reference counting to triple `u32` reference counting. +pub fn migrate_from_single_u8_to_triple_ref_count() -> Weight { + let mut translated: usize = 0; + >::translate::<(T::Index, u8, T::AccountData), _>(|_key, (nonce, rc, data)| { + translated = translated + 1; + Some(AccountInfo { nonce, consumers: rc as RefCount, providers: 1, sufficients: 0, data }) + }); + log::info!( + target: "runtime::system", + "Applied migration from single u8 to triple reference counting to {:?} elements.", + translated + ); + ::put(true); + ::put(true); + Weight::max_value() +} + +/// Migrate from unique `u32` reference counting to triple `u32` reference counting. +pub fn migrate_from_single_to_triple_ref_count() -> Weight { + let mut translated: usize = 0; + >::translate::<(T::Index, RefCount, T::AccountData), _>( + |_key, (nonce, consumers, data)| { + translated = translated + 1; + Some(AccountInfo { nonce, consumers, providers: 1, sufficients: 0, data }) + }, + ); + log::info!( + target: "runtime::system", + "Applied migration from single to triple reference counting to {:?} elements.", + translated + ); + ::put(true); + Weight::max_value() +} + +/// Migrate from dual `u32` reference counting to triple `u32` reference counting. +pub fn migrate_from_dual_to_triple_ref_count() -> Weight { + let mut translated: usize = 0; + >::translate::<(T::Index, RefCount, RefCount, T::AccountData), _>( + |_key, (nonce, consumers, providers, data)| { + translated = translated + 1; + Some(AccountInfo { nonce, consumers, providers, sufficients: 0, data }) + }, + ); + log::info!( + target: "runtime::system", + "Applied migration from dual to triple reference counting to {:?} elements.", + translated + ); + ::put(true); + Weight::max_value() +} From 7926c6dd211694368120f754b7037ec31bf9c4fa Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Thu, 9 Dec 2021 15:31:31 +0900 Subject: [PATCH 0316/1472] improve doc (#10431) --- frame/assets/src/types.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index 879e9d5cdcb96..16f7368f12b74 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -122,20 +122,25 @@ pub struct DestroyWitness { /// `minimum_balance` of the asset. This is additive - the `minimum_balance` of the asset must be /// met *and then* anything here in addition. pub trait FrozenBalance { - /// Return the frozen balance. Under normal behaviour, this amount should always be - /// withdrawable. + /// Return the frozen balance. /// - /// In reality, the balance of every account must be at least the sum of this (if `Some`) and - /// the asset's minimum_balance, since there may be complications to destroying an asset's - /// account completely. + /// Under normal behaviour, the account balance should not go below the sum of this (if `Some`) + /// and the asset's minimum balance. + /// But the account balance can be below this sum (e.g. if less than the sum has been + /// transfered to the account). /// - /// If `None` is returned, then nothing special is enforced. + /// In special case (privileged intervention) the account balance can go below the sum. /// - /// If any operation ever breaks this requirement (which will only happen through some sort of - /// privileged intervention), then `melted` is called to do any cleanup. + /// If `None` is returned, then nothing special is enforced. fn frozen_balance(asset: AssetId, who: &AccountId) -> Option; /// Called when an account has been removed. + /// + /// # Warning + /// + /// This function must never access storage of pallet asset. This function is called while some + /// change are pending. Calling into the pallet asset in this function can result in unexpected + /// state. fn died(asset: AssetId, who: &AccountId); } From 6681cad311d43f0b41f43da6b1c93836e6bab1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 9 Dec 2021 10:28:59 +0100 Subject: [PATCH 0317/1472] Run contract benchmarks (#10452) * Trigger benchmarks * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- frame/contracts/src/weights.rs | 1444 ++++++++++++++++---------------- 1 file changed, 729 insertions(+), 715 deletions(-) diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 504ee9ebde03a..8a78a7f289a62 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-12-09, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -150,40 +150,40 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (2_832_000 as Weight) + (2_854_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((2_197_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((2_190_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (92_378_000 as Weight) + (101_551_000 as Weight) // Standard Error: 2_000 - .saturating_add((328_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((292_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn instrument(c: u32, ) -> Weight { - (27_381_000 as Weight) - // Standard Error: 92_000 - .saturating_add((90_220_000 as Weight).saturating_mul(c as Weight)) + (33_350_000 as Weight) + // Standard Error: 106_000 + .saturating_add((91_098_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:0) fn code_load(c: u32, ) -> Weight { - (7_710_000 as Weight) + (8_080_000 as Weight) // Standard Error: 0 - .saturating_add((1_457_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((1_455_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) @@ -194,11 +194,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (559_294_000 as Weight) - // Standard Error: 171_000 - .saturating_add((206_170_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 11_000 - .saturating_add((2_107_000 as Weight).saturating_mul(s as Weight)) + (464_920_000 as Weight) + // Standard Error: 136_000 + .saturating_add((211_340_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 8_000 + .saturating_add((2_190_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -209,9 +209,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (236_193_000 as Weight) + (236_192_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_022_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_010_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -220,7 +220,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (189_193_000 as Weight) + (172_780_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -228,9 +228,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (79_753_000 as Weight) + (80_415_000 as Weight) // Standard Error: 98_000 - .saturating_add((90_928_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((93_463_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -238,233 +238,235 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (40_206_000 as Weight) + (40_042_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (464_937_000 as Weight) - // Standard Error: 182_000 - .saturating_add((112_166_000 as Weight).saturating_mul(r as Weight)) + (416_770_000 as Weight) + // Standard Error: 175_000 + .saturating_add((114_550_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (464_387_000 as Weight) - // Standard Error: 155_000 - .saturating_add((112_307_000 as Weight).saturating_mul(r as Weight)) + (415_774_000 as Weight) + // Standard Error: 176_000 + .saturating_add((115_169_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (462_005_000 as Weight) - // Standard Error: 185_000 - .saturating_add((111_402_000 as Weight).saturating_mul(r as Weight)) + (411_883_000 as Weight) + // Standard Error: 200_000 + .saturating_add((113_740_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (468_139_000 as Weight) - // Standard Error: 192_000 - .saturating_add((317_634_000 as Weight).saturating_mul(r as Weight)) + (422_382_000 as Weight) + // Standard Error: 189_000 + .saturating_add((313_581_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (447_610_000 as Weight) - // Standard Error: 196_000 - .saturating_add((112_915_000 as Weight).saturating_mul(r as Weight)) + (437_411_000 as Weight) + // Standard Error: 191_000 + .saturating_add((111_580_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (450_012_000 as Weight) - // Standard Error: 167_000 - .saturating_add((112_311_000 as Weight).saturating_mul(r as Weight)) + (431_815_000 as Weight) + // Standard Error: 170_000 + .saturating_add((111_289_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (453_687_000 as Weight) - // Standard Error: 185_000 - .saturating_add((111_902_000 as Weight).saturating_mul(r as Weight)) + (430_451_000 as Weight) + // Standard Error: 152_000 + .saturating_add((111_214_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (453_283_000 as Weight) - // Standard Error: 162_000 - .saturating_add((112_543_000 as Weight).saturating_mul(r as Weight)) + (419_363_000 as Weight) + // Standard Error: 175_000 + .saturating_add((112_089_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (454_171_000 as Weight) - // Standard Error: 205_000 - .saturating_add((267_487_000 as Weight).saturating_mul(r as Weight)) + (427_501_000 as Weight) + // Standard Error: 247_000 + .saturating_add((262_104_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (190_254_000 as Weight) - // Standard Error: 116_000 - .saturating_add((51_037_000 as Weight).saturating_mul(r as Weight)) + (145_426_000 as Weight) + // Standard Error: 115_000 + .saturating_add((52_082_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (460_590_000 as Weight) - // Standard Error: 173_000 - .saturating_add((99_887_000 as Weight).saturating_mul(r as Weight)) + (415_783_000 as Weight) + // Standard Error: 184_000 + .saturating_add((101_266_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (616_346_000 as Weight) - // Standard Error: 9_000 - .saturating_add((38_016_000 as Weight).saturating_mul(n as Weight)) + (536_645_000 as Weight) + // Standard Error: 6_000 + .saturating_add((38_077_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(_r: u32, ) -> Weight { - (447_340_000 as Weight) + fn seal_return(r: u32, ) -> Weight { + (412_785_000 as Weight) + // Standard Error: 92_000 + .saturating_add((1_476_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (452_105_000 as Weight) + (400_232_000 as Weight) // Standard Error: 1_000 - .saturating_add((633_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((644_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (456_662_000 as Weight) - // Standard Error: 2_550_000 - .saturating_add((71_297_000 as Weight).saturating_mul(r as Weight)) + (409_343_000 as Weight) + // Standard Error: 1_325_000 + .saturating_add((101_661_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (460_302_000 as Weight) - // Standard Error: 223_000 - .saturating_add((351_206_000 as Weight).saturating_mul(r as Weight)) + (417_354_000 as Weight) + // Standard Error: 299_000 + .saturating_add((343_766_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (456_800_000 as Weight) - // Standard Error: 413_000 - .saturating_add((574_183_000 as Weight).saturating_mul(r as Weight)) + (412_092_000 as Weight) + // Standard Error: 403_000 + .saturating_add((568_199_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_099_926_000 as Weight) - // Standard Error: 2_170_000 - .saturating_add((461_522_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 427_000 - .saturating_add((164_778_000 as Weight).saturating_mul(n as Weight)) + (1_095_614_000 as Weight) + // Standard Error: 2_151_000 + .saturating_add((455_690_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 424_000 + .saturating_add((163_553_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(t as Weight))) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (208_518_000 as Weight) - // Standard Error: 131_000 - .saturating_add((70_862_000 as Weight).saturating_mul(r as Weight)) + (169_113_000 as Weight) + // Standard Error: 146_000 + .saturating_add((72_877_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (492_961_000 as Weight) - // Standard Error: 506_000 - .saturating_add((373_157_000 as Weight).saturating_mul(r as Weight)) + (484_647_000 as Weight) + // Standard Error: 479_000 + .saturating_add((369_854_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -476,17 +478,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (793_894_000 as Weight) - // Standard Error: 250_000 - .saturating_add((74_081_000 as Weight).saturating_mul(n as Weight)) + (793_777_000 as Weight) + // Standard Error: 264_000 + .saturating_add((73_253_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (214_581_000 as Weight) - // Standard Error: 1_604_000 - .saturating_add((844_938_000 as Weight).saturating_mul(r as Weight)) + (180_385_000 as Weight) + // Standard Error: 1_470_000 + .saturating_add((834_911_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -494,64 +496,69 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (328_005_000 as Weight) - // Standard Error: 753_000 - .saturating_add((493_893_000 as Weight).saturating_mul(r as Weight)) + (282_452_000 as Weight) + // Standard Error: 802_000 + .saturating_add((492_119_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (736_348_000 as Weight) - // Standard Error: 232_000 - .saturating_add((110_871_000 as Weight).saturating_mul(n as Weight)) + (687_019_000 as Weight) + // Standard Error: 226_000 + .saturating_add((111_245_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (346_206_000 as Weight) - // Standard Error: 1_888_000 - .saturating_add((3_729_835_000 as Weight).saturating_mul(r as Weight)) + (273_106_000 as Weight) + // Standard Error: 1_498_000 + .saturating_add((3_509_324_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 11_456_000 - .saturating_add((39_404_197_000 as Weight).saturating_mul(r as Weight)) + (2_702_839_000 as Weight) + // Standard Error: 21_310_000 + .saturating_add((37_721_061_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, _o: u32, ) -> Weight { - (136_101_024_000 as Weight) - // Standard Error: 6_000 - .saturating_add((62_954_000 as Weight).saturating_mul(i as Weight)) + fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { + (40_088_516_000 as Weight) + // Standard Error: 69_999_000 + .saturating_add((2_981_897_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 25_000 + .saturating_add((63_345_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 26_000 + .saturating_add((100_683_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) - .saturating_add(T::DbWeight::get().writes(102 as Weight)) + .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) + .saturating_add(T::DbWeight::get().writes(101 as Weight)) + .saturating_add(T::DbWeight::get().writes((101 as Weight).saturating_mul(t as Weight))) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) @@ -559,11 +566,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 47_948_000 - .saturating_add((48_494_963_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 49_379_000 + .saturating_add((51_630_139_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((400 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:102 w:102) @@ -573,369 +580,369 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (45_566_426_000 as Weight) - // Standard Error: 50_000 - .saturating_add((63_809_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 50_000 - .saturating_add((101_448_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 50_000 - .saturating_add((201_652_000 as Weight).saturating_mul(s as Weight)) + (47_691_523_000 as Weight) + // Standard Error: 36_000 + .saturating_add((63_693_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 36_000 + .saturating_add((101_775_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 36_000 + .saturating_add((200_727_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().writes(206 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (457_229_000 as Weight) - // Standard Error: 197_000 - .saturating_add((124_742_000 as Weight).saturating_mul(r as Weight)) + (411_050_000 as Weight) + // Standard Error: 177_000 + .saturating_add((125_380_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (586_056_000 as Weight) - // Standard Error: 30_000 - .saturating_add((505_871_000 as Weight).saturating_mul(n as Weight)) + (381_286_000 as Weight) + // Standard Error: 48_000 + .saturating_add((506_160_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (458_528_000 as Weight) - // Standard Error: 154_000 - .saturating_add((137_710_000 as Weight).saturating_mul(r as Weight)) + (415_554_000 as Weight) + // Standard Error: 186_000 + .saturating_add((138_154_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (573_132_000 as Weight) - // Standard Error: 19_000 - .saturating_add((363_983_000 as Weight).saturating_mul(n as Weight)) + (509_653_000 as Weight) + // Standard Error: 20_000 + .saturating_add((364_008_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (456_881_000 as Weight) - // Standard Error: 187_000 - .saturating_add((106_987_000 as Weight).saturating_mul(r as Weight)) + (416_442_000 as Weight) + // Standard Error: 186_000 + .saturating_add((120_321_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (587_192_000 as Weight) + (586_411_000 as Weight) // Standard Error: 17_000 - .saturating_add((164_114_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((164_095_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (457_938_000 as Weight) - // Standard Error: 184_000 - .saturating_add((105_658_000 as Weight).saturating_mul(r as Weight)) + (410_054_000 as Weight) + // Standard Error: 198_000 + .saturating_add((109_368_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (567_129_000 as Weight) + (548_447_000 as Weight) // Standard Error: 16_000 - .saturating_add((164_146_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((164_100_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (426_602_000 as Weight) - // Standard Error: 1_393_000 - .saturating_add((15_587_531_000 as Weight).saturating_mul(r as Weight)) + (368_727_000 as Weight) + // Standard Error: 1_294_000 + .saturating_add((15_563_119_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (39_689_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + (47_482_000 as Weight) + // Standard Error: 11_000 + .saturating_add((811_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (45_362_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_665_000 as Weight).saturating_mul(r as Weight)) + (55_014_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_502_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (45_514_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_696_000 as Weight).saturating_mul(r as Weight)) + (54_708_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_547_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (45_931_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_919_000 as Weight).saturating_mul(r as Weight)) + (38_583_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_979_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (46_362_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_942_000 as Weight).saturating_mul(r as Weight)) + (37_647_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_107_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (44_648_000 as Weight) - // Standard Error: 15_000 - .saturating_add((1_856_000 as Weight).saturating_mul(r as Weight)) + (40_586_000 as Weight) + // Standard Error: 17_000 + .saturating_add((1_940_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (45_989_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_418_000 as Weight).saturating_mul(r as Weight)) + (39_436_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_533_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (48_883_000 as Weight) - // Standard Error: 18_000 - .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) + (45_741_000 as Weight) + // Standard Error: 21_000 + .saturating_add((2_450_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (48_685_000 as Weight) - // Standard Error: 2_000 - .saturating_add((39_000 as Weight).saturating_mul(e as Weight)) + (48_440_000 as Weight) + // Standard Error: 3_000 + .saturating_add((29_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (50_428_000 as Weight) - // Standard Error: 24_000 - .saturating_add((20_121_000 as Weight).saturating_mul(r as Weight)) + (49_819_000 as Weight) + // Standard Error: 22_000 + .saturating_add((20_642_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (54_899_000 as Weight) - // Standard Error: 32_000 - .saturating_add((29_588_000 as Weight).saturating_mul(r as Weight)) + (54_317_000 as Weight) + // Standard Error: 29_000 + .saturating_add((30_663_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (92_176_000 as Weight) + (88_087_000 as Weight) // Standard Error: 5_000 - .saturating_add((989_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_106_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (48_130_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_194_000 as Weight).saturating_mul(r as Weight)) + (40_540_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (47_550_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_244_000 as Weight).saturating_mul(r as Weight)) + (40_842_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_375_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (48_806_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_757_000 as Weight).saturating_mul(r as Weight)) + (43_679_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (62_369_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_779_000 as Weight).saturating_mul(r as Weight)) + (52_999_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_970_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (61_063_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_751_000 as Weight).saturating_mul(r as Weight)) + (58_630_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_776_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (39_781_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + (47_810_000 as Weight) + // Standard Error: 11_000 + .saturating_add((817_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (50_983_000 as Weight) - // Standard Error: 4_238_000 - .saturating_add((618_956_000 as Weight).saturating_mul(r as Weight)) + (51_086_000 as Weight) + // Standard Error: 3_690_000 + .saturating_add((622_068_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (42_490_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_937_000 as Weight).saturating_mul(r as Weight)) + (44_599_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (42_296_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_943_000 as Weight).saturating_mul(r as Weight)) + (44_523_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_500_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (42_263_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_944_000 as Weight).saturating_mul(r as Weight)) + (44_633_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_501_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (42_087_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_952_000 as Weight).saturating_mul(r as Weight)) + (44_654_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (48_024_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) + (42_020_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_950_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (48_056_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_780_000 as Weight).saturating_mul(r as Weight)) + (42_077_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_943_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (42_352_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) + (44_559_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (45_439_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_382_000 as Weight).saturating_mul(r as Weight)) + (37_902_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_480_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (45_232_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_393_000 as Weight).saturating_mul(r as Weight)) + (37_799_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_484_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (45_351_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_386_000 as Weight).saturating_mul(r as Weight)) + (37_492_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_507_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (45_448_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_385_000 as Weight).saturating_mul(r as Weight)) + (37_509_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (45_275_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_386_000 as Weight).saturating_mul(r as Weight)) + (37_563_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (45_180_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_396_000 as Weight).saturating_mul(r as Weight)) + (37_584_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_496_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (45_396_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_400_000 as Weight).saturating_mul(r as Weight)) + (37_738_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (45_597_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_392_000 as Weight).saturating_mul(r as Weight)) + (37_806_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (45_137_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_400_000 as Weight).saturating_mul(r as Weight)) + (37_858_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (45_091_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_401_000 as Weight).saturating_mul(r as Weight)) + (37_862_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (45_547_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_380_000 as Weight).saturating_mul(r as Weight)) + (37_695_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_491_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (45_435_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_383_000 as Weight).saturating_mul(r as Weight)) + (37_693_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (45_244_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_389_000 as Weight).saturating_mul(r as Weight)) + (37_623_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (45_253_000 as Weight) - // Standard Error: 11_000 - .saturating_add((3_046_000 as Weight).saturating_mul(r as Weight)) + (37_595_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_150_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (45_339_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_711_000 as Weight).saturating_mul(r as Weight)) + (37_661_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_797_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (45_312_000 as Weight) - // Standard Error: 11_000 - .saturating_add((3_020_000 as Weight).saturating_mul(r as Weight)) + (37_978_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_107_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (45_397_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_739_000 as Weight).saturating_mul(r as Weight)) + (37_668_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_842_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (45_282_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_387_000 as Weight).saturating_mul(r as Weight)) + (37_846_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_482_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (45_508_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_390_000 as Weight).saturating_mul(r as Weight)) + (37_902_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_478_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (45_089_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_397_000 as Weight).saturating_mul(r as Weight)) + (37_670_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_489_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (45_878_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_395_000 as Weight).saturating_mul(r as Weight)) + (37_987_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_479_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (45_459_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_401_000 as Weight).saturating_mul(r as Weight)) + (37_945_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_486_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (45_663_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_398_000 as Weight).saturating_mul(r as Weight)) + (37_570_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (45_739_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_393_000 as Weight).saturating_mul(r as Weight)) + (37_674_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (45_290_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_392_000 as Weight).saturating_mul(r as Weight)) + (37_467_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) } } @@ -943,40 +950,40 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (2_832_000 as Weight) + (2_854_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((2_197_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((2_190_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (92_378_000 as Weight) + (101_551_000 as Weight) // Standard Error: 2_000 - .saturating_add((328_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((292_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn instrument(c: u32, ) -> Weight { - (27_381_000 as Weight) - // Standard Error: 92_000 - .saturating_add((90_220_000 as Weight).saturating_mul(c as Weight)) + (33_350_000 as Weight) + // Standard Error: 106_000 + .saturating_add((91_098_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:0) fn code_load(c: u32, ) -> Weight { - (7_710_000 as Weight) + (8_080_000 as Weight) // Standard Error: 0 - .saturating_add((1_457_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((1_455_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) @@ -987,11 +994,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (559_294_000 as Weight) - // Standard Error: 171_000 - .saturating_add((206_170_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 11_000 - .saturating_add((2_107_000 as Weight).saturating_mul(s as Weight)) + (464_920_000 as Weight) + // Standard Error: 136_000 + .saturating_add((211_340_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 8_000 + .saturating_add((2_190_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1002,9 +1009,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (236_193_000 as Weight) + (236_192_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_022_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_010_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1013,7 +1020,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (189_193_000 as Weight) + (172_780_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1021,9 +1028,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (79_753_000 as Weight) + (80_415_000 as Weight) // Standard Error: 98_000 - .saturating_add((90_928_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((93_463_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1031,233 +1038,235 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (40_206_000 as Weight) + (40_042_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (464_937_000 as Weight) - // Standard Error: 182_000 - .saturating_add((112_166_000 as Weight).saturating_mul(r as Weight)) + (416_770_000 as Weight) + // Standard Error: 175_000 + .saturating_add((114_550_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (464_387_000 as Weight) - // Standard Error: 155_000 - .saturating_add((112_307_000 as Weight).saturating_mul(r as Weight)) + (415_774_000 as Weight) + // Standard Error: 176_000 + .saturating_add((115_169_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (462_005_000 as Weight) - // Standard Error: 185_000 - .saturating_add((111_402_000 as Weight).saturating_mul(r as Weight)) + (411_883_000 as Weight) + // Standard Error: 200_000 + .saturating_add((113_740_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (468_139_000 as Weight) - // Standard Error: 192_000 - .saturating_add((317_634_000 as Weight).saturating_mul(r as Weight)) + (422_382_000 as Weight) + // Standard Error: 189_000 + .saturating_add((313_581_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (447_610_000 as Weight) - // Standard Error: 196_000 - .saturating_add((112_915_000 as Weight).saturating_mul(r as Weight)) + (437_411_000 as Weight) + // Standard Error: 191_000 + .saturating_add((111_580_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (450_012_000 as Weight) - // Standard Error: 167_000 - .saturating_add((112_311_000 as Weight).saturating_mul(r as Weight)) + (431_815_000 as Weight) + // Standard Error: 170_000 + .saturating_add((111_289_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (453_687_000 as Weight) - // Standard Error: 185_000 - .saturating_add((111_902_000 as Weight).saturating_mul(r as Weight)) + (430_451_000 as Weight) + // Standard Error: 152_000 + .saturating_add((111_214_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (453_283_000 as Weight) - // Standard Error: 162_000 - .saturating_add((112_543_000 as Weight).saturating_mul(r as Weight)) + (419_363_000 as Weight) + // Standard Error: 175_000 + .saturating_add((112_089_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (454_171_000 as Weight) - // Standard Error: 205_000 - .saturating_add((267_487_000 as Weight).saturating_mul(r as Weight)) + (427_501_000 as Weight) + // Standard Error: 247_000 + .saturating_add((262_104_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (190_254_000 as Weight) - // Standard Error: 116_000 - .saturating_add((51_037_000 as Weight).saturating_mul(r as Weight)) + (145_426_000 as Weight) + // Standard Error: 115_000 + .saturating_add((52_082_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (460_590_000 as Weight) - // Standard Error: 173_000 - .saturating_add((99_887_000 as Weight).saturating_mul(r as Weight)) + (415_783_000 as Weight) + // Standard Error: 184_000 + .saturating_add((101_266_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (616_346_000 as Weight) - // Standard Error: 9_000 - .saturating_add((38_016_000 as Weight).saturating_mul(n as Weight)) + (536_645_000 as Weight) + // Standard Error: 6_000 + .saturating_add((38_077_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(_r: u32, ) -> Weight { - (447_340_000 as Weight) + fn seal_return(r: u32, ) -> Weight { + (412_785_000 as Weight) + // Standard Error: 92_000 + .saturating_add((1_476_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (452_105_000 as Weight) + (400_232_000 as Weight) // Standard Error: 1_000 - .saturating_add((633_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((644_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (456_662_000 as Weight) - // Standard Error: 2_550_000 - .saturating_add((71_297_000 as Weight).saturating_mul(r as Weight)) + (409_343_000 as Weight) + // Standard Error: 1_325_000 + .saturating_add((101_661_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (460_302_000 as Weight) - // Standard Error: 223_000 - .saturating_add((351_206_000 as Weight).saturating_mul(r as Weight)) + (417_354_000 as Weight) + // Standard Error: 299_000 + .saturating_add((343_766_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (456_800_000 as Weight) - // Standard Error: 413_000 - .saturating_add((574_183_000 as Weight).saturating_mul(r as Weight)) + (412_092_000 as Weight) + // Standard Error: 403_000 + .saturating_add((568_199_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_099_926_000 as Weight) - // Standard Error: 2_170_000 - .saturating_add((461_522_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 427_000 - .saturating_add((164_778_000 as Weight).saturating_mul(n as Weight)) + (1_095_614_000 as Weight) + // Standard Error: 2_151_000 + .saturating_add((455_690_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 424_000 + .saturating_add((163_553_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(t as Weight))) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (208_518_000 as Weight) - // Standard Error: 131_000 - .saturating_add((70_862_000 as Weight).saturating_mul(r as Weight)) + (169_113_000 as Weight) + // Standard Error: 146_000 + .saturating_add((72_877_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (492_961_000 as Weight) - // Standard Error: 506_000 - .saturating_add((373_157_000 as Weight).saturating_mul(r as Weight)) + (484_647_000 as Weight) + // Standard Error: 479_000 + .saturating_add((369_854_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1269,17 +1278,17 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (793_894_000 as Weight) - // Standard Error: 250_000 - .saturating_add((74_081_000 as Weight).saturating_mul(n as Weight)) + (793_777_000 as Weight) + // Standard Error: 264_000 + .saturating_add((73_253_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (214_581_000 as Weight) - // Standard Error: 1_604_000 - .saturating_add((844_938_000 as Weight).saturating_mul(r as Weight)) + (180_385_000 as Weight) + // Standard Error: 1_470_000 + .saturating_add((834_911_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1287,64 +1296,69 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (328_005_000 as Weight) - // Standard Error: 753_000 - .saturating_add((493_893_000 as Weight).saturating_mul(r as Weight)) + (282_452_000 as Weight) + // Standard Error: 802_000 + .saturating_add((492_119_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (736_348_000 as Weight) - // Standard Error: 232_000 - .saturating_add((110_871_000 as Weight).saturating_mul(n as Weight)) + (687_019_000 as Weight) + // Standard Error: 226_000 + .saturating_add((111_245_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (346_206_000 as Weight) - // Standard Error: 1_888_000 - .saturating_add((3_729_835_000 as Weight).saturating_mul(r as Weight)) + (273_106_000 as Weight) + // Standard Error: 1_498_000 + .saturating_add((3_509_324_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 11_456_000 - .saturating_add((39_404_197_000 as Weight).saturating_mul(r as Weight)) + (2_702_839_000 as Weight) + // Standard Error: 21_310_000 + .saturating_add((37_721_061_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, _o: u32, ) -> Weight { - (136_101_024_000 as Weight) - // Standard Error: 6_000 - .saturating_add((62_954_000 as Weight).saturating_mul(i as Weight)) + fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { + (40_088_516_000 as Weight) + // Standard Error: 69_999_000 + .saturating_add((2_981_897_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 25_000 + .saturating_add((63_345_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 26_000 + .saturating_add((100_683_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) - .saturating_add(RocksDbWeight::get().writes(102 as Weight)) + .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) + .saturating_add(RocksDbWeight::get().writes(101 as Weight)) + .saturating_add(RocksDbWeight::get().writes((101 as Weight).saturating_mul(t as Weight))) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) @@ -1352,11 +1366,11 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 47_948_000 - .saturating_add((48_494_963_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 49_379_000 + .saturating_add((51_630_139_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((400 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:102 w:102) @@ -1366,368 +1380,368 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (45_566_426_000 as Weight) - // Standard Error: 50_000 - .saturating_add((63_809_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 50_000 - .saturating_add((101_448_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 50_000 - .saturating_add((201_652_000 as Weight).saturating_mul(s as Weight)) + (47_691_523_000 as Weight) + // Standard Error: 36_000 + .saturating_add((63_693_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 36_000 + .saturating_add((101_775_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 36_000 + .saturating_add((200_727_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().writes(206 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (457_229_000 as Weight) - // Standard Error: 197_000 - .saturating_add((124_742_000 as Weight).saturating_mul(r as Weight)) + (411_050_000 as Weight) + // Standard Error: 177_000 + .saturating_add((125_380_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (586_056_000 as Weight) - // Standard Error: 30_000 - .saturating_add((505_871_000 as Weight).saturating_mul(n as Weight)) + (381_286_000 as Weight) + // Standard Error: 48_000 + .saturating_add((506_160_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (458_528_000 as Weight) - // Standard Error: 154_000 - .saturating_add((137_710_000 as Weight).saturating_mul(r as Weight)) + (415_554_000 as Weight) + // Standard Error: 186_000 + .saturating_add((138_154_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (573_132_000 as Weight) - // Standard Error: 19_000 - .saturating_add((363_983_000 as Weight).saturating_mul(n as Weight)) + (509_653_000 as Weight) + // Standard Error: 20_000 + .saturating_add((364_008_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (456_881_000 as Weight) - // Standard Error: 187_000 - .saturating_add((106_987_000 as Weight).saturating_mul(r as Weight)) + (416_442_000 as Weight) + // Standard Error: 186_000 + .saturating_add((120_321_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (587_192_000 as Weight) + (586_411_000 as Weight) // Standard Error: 17_000 - .saturating_add((164_114_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((164_095_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (457_938_000 as Weight) - // Standard Error: 184_000 - .saturating_add((105_658_000 as Weight).saturating_mul(r as Weight)) + (410_054_000 as Weight) + // Standard Error: 198_000 + .saturating_add((109_368_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (567_129_000 as Weight) + (548_447_000 as Weight) // Standard Error: 16_000 - .saturating_add((164_146_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((164_100_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (426_602_000 as Weight) - // Standard Error: 1_393_000 - .saturating_add((15_587_531_000 as Weight).saturating_mul(r as Weight)) + (368_727_000 as Weight) + // Standard Error: 1_294_000 + .saturating_add((15_563_119_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (39_689_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + (47_482_000 as Weight) + // Standard Error: 11_000 + .saturating_add((811_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (45_362_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_665_000 as Weight).saturating_mul(r as Weight)) + (55_014_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_502_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (45_514_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_696_000 as Weight).saturating_mul(r as Weight)) + (54_708_000 as Weight) + // Standard Error: 13_000 + .saturating_add((2_547_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (45_931_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_919_000 as Weight).saturating_mul(r as Weight)) + (38_583_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_979_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (46_362_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_942_000 as Weight).saturating_mul(r as Weight)) + (37_647_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_107_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (44_648_000 as Weight) - // Standard Error: 15_000 - .saturating_add((1_856_000 as Weight).saturating_mul(r as Weight)) + (40_586_000 as Weight) + // Standard Error: 17_000 + .saturating_add((1_940_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (45_989_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_418_000 as Weight).saturating_mul(r as Weight)) + (39_436_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_533_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (48_883_000 as Weight) - // Standard Error: 18_000 - .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) + (45_741_000 as Weight) + // Standard Error: 21_000 + .saturating_add((2_450_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (48_685_000 as Weight) - // Standard Error: 2_000 - .saturating_add((39_000 as Weight).saturating_mul(e as Weight)) + (48_440_000 as Weight) + // Standard Error: 3_000 + .saturating_add((29_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (50_428_000 as Weight) - // Standard Error: 24_000 - .saturating_add((20_121_000 as Weight).saturating_mul(r as Weight)) + (49_819_000 as Weight) + // Standard Error: 22_000 + .saturating_add((20_642_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (54_899_000 as Weight) - // Standard Error: 32_000 - .saturating_add((29_588_000 as Weight).saturating_mul(r as Weight)) + (54_317_000 as Weight) + // Standard Error: 29_000 + .saturating_add((30_663_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (92_176_000 as Weight) + (88_087_000 as Weight) // Standard Error: 5_000 - .saturating_add((989_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_106_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (48_130_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_194_000 as Weight).saturating_mul(r as Weight)) + (40_540_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (47_550_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_244_000 as Weight).saturating_mul(r as Weight)) + (40_842_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_375_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (48_806_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_757_000 as Weight).saturating_mul(r as Weight)) + (43_679_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (62_369_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_779_000 as Weight).saturating_mul(r as Weight)) + (52_999_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_970_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (61_063_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_751_000 as Weight).saturating_mul(r as Weight)) + (58_630_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_776_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (39_781_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + (47_810_000 as Weight) + // Standard Error: 11_000 + .saturating_add((817_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (50_983_000 as Weight) - // Standard Error: 4_238_000 - .saturating_add((618_956_000 as Weight).saturating_mul(r as Weight)) + (51_086_000 as Weight) + // Standard Error: 3_690_000 + .saturating_add((622_068_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (42_490_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_937_000 as Weight).saturating_mul(r as Weight)) + (44_599_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (42_296_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_943_000 as Weight).saturating_mul(r as Weight)) + (44_523_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_500_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (42_263_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_944_000 as Weight).saturating_mul(r as Weight)) + (44_633_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_501_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (42_087_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_952_000 as Weight).saturating_mul(r as Weight)) + (44_654_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (48_024_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) + (42_020_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_950_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (48_056_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_780_000 as Weight).saturating_mul(r as Weight)) + (42_077_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_943_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (42_352_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) + (44_559_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (45_439_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_382_000 as Weight).saturating_mul(r as Weight)) + (37_902_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_480_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (45_232_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_393_000 as Weight).saturating_mul(r as Weight)) + (37_799_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_484_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (45_351_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_386_000 as Weight).saturating_mul(r as Weight)) + (37_492_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_507_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (45_448_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_385_000 as Weight).saturating_mul(r as Weight)) + (37_509_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (45_275_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_386_000 as Weight).saturating_mul(r as Weight)) + (37_563_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (45_180_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_396_000 as Weight).saturating_mul(r as Weight)) + (37_584_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_496_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (45_396_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_400_000 as Weight).saturating_mul(r as Weight)) + (37_738_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (45_597_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_392_000 as Weight).saturating_mul(r as Weight)) + (37_806_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (45_137_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_400_000 as Weight).saturating_mul(r as Weight)) + (37_858_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (45_091_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_401_000 as Weight).saturating_mul(r as Weight)) + (37_862_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (45_547_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_380_000 as Weight).saturating_mul(r as Weight)) + (37_695_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_491_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (45_435_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_383_000 as Weight).saturating_mul(r as Weight)) + (37_693_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (45_244_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_389_000 as Weight).saturating_mul(r as Weight)) + (37_623_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (45_253_000 as Weight) - // Standard Error: 11_000 - .saturating_add((3_046_000 as Weight).saturating_mul(r as Weight)) + (37_595_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_150_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (45_339_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_711_000 as Weight).saturating_mul(r as Weight)) + (37_661_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_797_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (45_312_000 as Weight) - // Standard Error: 11_000 - .saturating_add((3_020_000 as Weight).saturating_mul(r as Weight)) + (37_978_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_107_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (45_397_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_739_000 as Weight).saturating_mul(r as Weight)) + (37_668_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_842_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (45_282_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_387_000 as Weight).saturating_mul(r as Weight)) + (37_846_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_482_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (45_508_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_390_000 as Weight).saturating_mul(r as Weight)) + (37_902_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_478_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (45_089_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_397_000 as Weight).saturating_mul(r as Weight)) + (37_670_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_489_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (45_878_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_395_000 as Weight).saturating_mul(r as Weight)) + (37_987_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_479_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (45_459_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_401_000 as Weight).saturating_mul(r as Weight)) + (37_945_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_486_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (45_663_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_398_000 as Weight).saturating_mul(r as Weight)) + (37_570_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (45_739_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_393_000 as Weight).saturating_mul(r as Weight)) + (37_674_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (45_290_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_392_000 as Weight).saturating_mul(r as Weight)) + (37_467_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) } } From 1a30fa202e00dfeac07cb648e1f557ce938d5f1a Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 9 Dec 2021 11:21:27 +0100 Subject: [PATCH 0318/1472] Remove Prometheus metrics prefix (#9543) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove Prometheus metrics prefix * Fix line widths * Missed some metrics * Fix CLI * Run rustfmt on modified files * Missing prefixes * Hopefully fix compilation * Rustfmt protocol.rs * Should compile now I guess * Rustfmt Co-authored-by: Bastian Köcher --- client/api/src/notifications.rs | 2 +- client/authority-discovery/src/worker.rs | 14 ++--- client/beefy/src/metrics.rs | 18 ++++-- client/cli/src/commands/run_cmd.rs | 11 ++-- client/consensus/common/src/metrics.rs | 14 +++-- .../src/communication/gossip.rs | 2 +- client/finality-grandpa/src/environment.rs | 6 +- client/finality-grandpa/src/until_imported.rs | 2 +- client/network-gossip/src/state_machine.rs | 4 +- client/network/src/protocol.rs | 9 +-- client/network/src/service/metrics.rs | 63 ++++++++++--------- client/network/src/service/out_events.rs | 6 +- client/network/src/transactions.rs | 2 +- client/proposer-metrics/src/lib.rs | 4 +- client/rpc-servers/src/lib.rs | 4 +- client/rpc-servers/src/middleware.rs | 10 +-- client/service/src/config.rs | 7 ++- client/service/src/metrics.rs | 23 ++++--- client/service/src/task_manager/mod.rs | 8 +-- client/transaction-pool/src/metrics.rs | 12 ++-- client/utils/src/metrics.rs | 6 +- 21 files changed, 125 insertions(+), 102 deletions(-) diff --git a/client/api/src/notifications.rs b/client/api/src/notifications.rs index 1346afd5e54d2..9565fd673acf4 100644 --- a/client/api/src/notifications.rs +++ b/client/api/src/notifications.rs @@ -121,7 +121,7 @@ impl StorageNotifications { let metrics = prometheus_registry.and_then(|r| { CounterVec::new( Opts::new( - "storage_notification_subscribers", + "substrate_storage_notification_subscribers", "Number of subscribers in storage notification sytem", ), &["action"], // added | removed diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index ce04e0eb65b15..5ca93b73c8132 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -733,14 +733,14 @@ impl Metrics { Ok(Self { publish: register( Counter::new( - "authority_discovery_times_published_total", + "substrate_authority_discovery_times_published_total", "Number of times authority discovery has published external addresses.", )?, registry, )?, amount_addresses_last_published: register( Gauge::new( - "authority_discovery_amount_external_addresses_last_published", + "substrate_authority_discovery_amount_external_addresses_last_published", "Number of external addresses published when authority discovery last \ published addresses.", )?, @@ -748,7 +748,7 @@ impl Metrics { )?, requests: register( Counter::new( - "authority_discovery_authority_addresses_requested_total", + "substrate_authority_discovery_authority_addresses_requested_total", "Number of times authority discovery has requested external addresses of a \ single authority.", )?, @@ -756,7 +756,7 @@ impl Metrics { )?, requests_pending: register( Gauge::new( - "authority_discovery_authority_address_requests_pending", + "substrate_authority_discovery_authority_address_requests_pending", "Number of pending authority address requests.", )?, registry, @@ -764,7 +764,7 @@ impl Metrics { dht_event_received: register( CounterVec::new( Opts::new( - "authority_discovery_dht_event_received", + "substrate_authority_discovery_dht_event_received", "Number of dht events received by authority discovery.", ), &["name"], @@ -773,14 +773,14 @@ impl Metrics { )?, handle_value_found_event_failure: register( Counter::new( - "authority_discovery_handle_value_found_event_failure", + "substrate_authority_discovery_handle_value_found_event_failure", "Number of times handling a dht value found event failed.", )?, registry, )?, known_authorities_count: register( Gauge::new( - "authority_discovery_known_authorities_count", + "substrate_authority_discovery_known_authorities_count", "Number of authorities known by authority discovery.", )?, registry, diff --git a/client/beefy/src/metrics.rs b/client/beefy/src/metrics.rs index 0fdc29f97c37a..55edee962a2ee 100644 --- a/client/beefy/src/metrics.rs +++ b/client/beefy/src/metrics.rs @@ -40,28 +40,34 @@ impl Metrics { pub(crate) fn register(registry: &Registry) -> Result { Ok(Self { beefy_validator_set_id: register( - Gauge::new("beefy_validator_set_id", "Current BEEFY active validator set id.")?, + Gauge::new( + "substrate_beefy_validator_set_id", + "Current BEEFY active validator set id.", + )?, registry, )?, beefy_votes_sent: register( - Counter::new("beefy_votes_sent", "Number of votes sent by this node")?, + Counter::new("substrate_beefy_votes_sent", "Number of votes sent by this node")?, registry, )?, beefy_round_concluded: register( - Gauge::new("beefy_round_concluded", "Voting round, that has been concluded")?, + Gauge::new( + "substrate_beefy_round_concluded", + "Voting round, that has been concluded", + )?, registry, )?, beefy_best_block: register( - Gauge::new("beefy_best_block", "Best block finalized by BEEFY")?, + Gauge::new("substrate_beefy_best_block", "Best block finalized by BEEFY")?, registry, )?, beefy_should_vote_on: register( - Gauge::new("beefy_should_vote_on", "Next block, BEEFY should vote on")?, + Gauge::new("substrate_beefy_should_vote_on", "Next block, BEEFY should vote on")?, registry, )?, beefy_skipped_sessions: register( Counter::new( - "beefy_skipped_sessions", + "substrate_beefy_skipped_sessions", "Number of sessions without a signed commitment", )?, registry, diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index ad2f04583c10b..622206fdf2977 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -368,10 +368,13 @@ impl CliConfiguration for RunCmd { let interface = if self.prometheus_external { Ipv4Addr::UNSPECIFIED } else { Ipv4Addr::LOCALHOST }; - Some(PrometheusConfig::new_with_default_registry(SocketAddr::new( - interface.into(), - self.prometheus_port.unwrap_or(default_listen_port), - ))) + Some(PrometheusConfig::new_with_default_registry( + SocketAddr::new( + interface.into(), + self.prometheus_port.unwrap_or(default_listen_port), + ), + self.shared_params.chain_id(self.shared_params.dev), + )) }) } diff --git a/client/consensus/common/src/metrics.rs b/client/consensus/common/src/metrics.rs index ade45e3ffb687..ec6ef89f609f4 100644 --- a/client/consensus/common/src/metrics.rs +++ b/client/consensus/common/src/metrics.rs @@ -41,28 +41,34 @@ impl Metrics { Ok(Self { import_queue_processed: register( CounterVec::new( - Opts::new("import_queue_processed_total", "Blocks processed by import queue"), + Opts::new( + "substrate_import_queue_processed_total", + "Blocks processed by import queue", + ), &["result"], // 'success or failure )?, registry, )?, block_verification_time: register( HistogramVec::new( - HistogramOpts::new("block_verification_time", "Time taken to verify blocks"), + HistogramOpts::new( + "substrate_block_verification_time", + "Time taken to verify blocks", + ), &["result"], )?, registry, )?, block_verification_and_import_time: register( Histogram::with_opts(HistogramOpts::new( - "block_verification_and_import_time", + "substrate_block_verification_and_import_time", "Time taken to verify and import blocks", ))?, registry, )?, justification_import_time: register( Histogram::with_opts(HistogramOpts::new( - "justification_import_time", + "substrate_justification_import_time", "Time taken to import justifications", ))?, registry, diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 2e50a3bac01d9..8a3b6afcad325 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -1299,7 +1299,7 @@ impl Metrics { messages_validated: register( CounterVec::new( Opts::new( - "finality_grandpa_communication_gossip_validator_messages", + "substrate_finality_grandpa_communication_gossip_validator_messages", "Number of messages validated by the finality grandpa gossip validator.", ), &["message", "action"], diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index c79698902e975..1f5b381c1382a 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -404,19 +404,19 @@ impl Metrics { ) -> Result { Ok(Self { finality_grandpa_round: register( - Gauge::new("finality_grandpa_round", "Highest completed GRANDPA round.")?, + Gauge::new("substrate_finality_grandpa_round", "Highest completed GRANDPA round.")?, registry, )?, finality_grandpa_prevotes: register( Counter::new( - "finality_grandpa_prevotes_total", + "substrate_finality_grandpa_prevotes_total", "Total number of GRANDPA prevotes cast locally.", )?, registry, )?, finality_grandpa_precommits: register( Counter::new( - "finality_grandpa_precommits_total", + "substrate_finality_grandpa_precommits_total", "Total number of GRANDPA precommits cast locally.", )?, registry, diff --git a/client/finality-grandpa/src/until_imported.rs b/client/finality-grandpa/src/until_imported.rs index deb6577264347..e2c00b54ea068 100644 --- a/client/finality-grandpa/src/until_imported.rs +++ b/client/finality-grandpa/src/until_imported.rs @@ -100,7 +100,7 @@ impl Metrics { Ok(Self { global_waiting_messages: register( Gauge::new( - "finality_grandpa_until_imported_waiting_messages_number", + "substrate_finality_grandpa_until_imported_waiting_messages_number", "Number of finality grandpa messages waiting within the until imported queue.", )?, registry, diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 920b44d8c1e5a..63553f2f16029 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -508,14 +508,14 @@ impl Metrics { Ok(Self { registered_messages: register( Counter::new( - "network_gossip_registered_messages_total", + "substrate_network_gossip_registered_messages_total", "Number of registered messages by the gossip service.", )?, registry, )?, expired_messages: register( Counter::new( - "network_gossip_expired_messages_total", + "substrate_network_gossip_expired_messages_total", "Number of expired messages by the gossip service.", )?, registry, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index bfaf42d5ff227..abd723f13d206 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -132,21 +132,22 @@ impl Metrics { fn register(r: &Registry) -> Result { Ok(Self { peers: { - let g = Gauge::new("sync_peers", "Number of peers we sync with")?; + let g = Gauge::new("substrate_sync_peers", "Number of peers we sync with")?; register(g, r)? }, queued_blocks: { - let g = Gauge::new("sync_queued_blocks", "Number of blocks in import queue")?; + let g = + Gauge::new("substrate_sync_queued_blocks", "Number of blocks in import queue")?; register(g, r)? }, fork_targets: { - let g = Gauge::new("sync_fork_targets", "Number of fork sync targets")?; + let g = Gauge::new("substrate_sync_fork_targets", "Number of fork sync targets")?; register(g, r)? }, justifications: { let g = GaugeVec::new( Opts::new( - "sync_extra_justifications", + "substrate_sync_extra_justifications", "Number of extra justifications requests", ), &["status"], diff --git a/client/network/src/service/metrics.rs b/client/network/src/service/metrics.rs index e33cd4b194d69..2550f255e848c 100644 --- a/client/network/src/service/metrics.rs +++ b/client/network/src/service/metrics.rs @@ -84,54 +84,54 @@ impl Metrics { // This list is ordered alphabetically connections_closed_total: prometheus::register(CounterVec::new( Opts::new( - "sub_libp2p_connections_closed_total", + "substrate_sub_libp2p_connections_closed_total", "Total number of connections closed, by direction and reason" ), &["direction", "reason"] )?, registry)?, connections_opened_total: prometheus::register(CounterVec::new( Opts::new( - "sub_libp2p_connections_opened_total", + "substrate_sub_libp2p_connections_opened_total", "Total number of connections opened by direction" ), &["direction"] )?, registry)?, distinct_peers_connections_closed_total: prometheus::register(Counter::new( - "sub_libp2p_distinct_peers_connections_closed_total", + "substrate_sub_libp2p_distinct_peers_connections_closed_total", "Total number of connections closed with distinct peers" )?, registry)?, distinct_peers_connections_opened_total: prometheus::register(Counter::new( - "sub_libp2p_distinct_peers_connections_opened_total", + "substrate_sub_libp2p_distinct_peers_connections_opened_total", "Total number of connections opened with distinct peers" )?, registry)?, import_queue_blocks_submitted: prometheus::register(Counter::new( - "import_queue_blocks_submitted", + "substrate_import_queue_blocks_submitted", "Number of blocks submitted to the import queue.", )?, registry)?, import_queue_justifications_submitted: prometheus::register(Counter::new( - "import_queue_justifications_submitted", + "substrate_import_queue_justifications_submitted", "Number of justifications submitted to the import queue.", )?, registry)?, incoming_connections_errors_total: prometheus::register(CounterVec::new( Opts::new( - "sub_libp2p_incoming_connections_handshake_errors_total", + "substrate_sub_libp2p_incoming_connections_handshake_errors_total", "Total number of incoming connections that have failed during the \ initial handshake" ), &["reason"] )?, registry)?, incoming_connections_total: prometheus::register(Counter::new( - "sub_libp2p_incoming_connections_total", + "substrate_sub_libp2p_incoming_connections_total", "Total number of incoming connections on the listening sockets" )?, registry)?, issued_light_requests: prometheus::register(Counter::new( - "issued_light_requests", + "substrate_issued_light_requests", "Number of light client requests that our node has issued.", )?, registry)?, kademlia_query_duration: prometheus::register(HistogramVec::new( HistogramOpts { common_opts: Opts::new( - "sub_libp2p_kademlia_query_duration", + "substrate_sub_libp2p_kademlia_query_duration", "Duration of Kademlia queries per query type" ), buckets: prometheus::exponential_buckets(0.5, 2.0, 10) @@ -141,43 +141,44 @@ impl Metrics { )?, registry)?, kademlia_random_queries_total: prometheus::register(CounterVec::new( Opts::new( - "sub_libp2p_kademlia_random_queries_total", + "substrate_sub_libp2p_kademlia_random_queries_total", "Number of random Kademlia queries started" ), &["protocol"] )?, registry)?, kademlia_records_count: prometheus::register(GaugeVec::new( Opts::new( - "sub_libp2p_kademlia_records_count", + "substrate_sub_libp2p_kademlia_records_count", "Number of records in the Kademlia records store" ), &["protocol"] )?, registry)?, kademlia_records_sizes_total: prometheus::register(GaugeVec::new( Opts::new( - "sub_libp2p_kademlia_records_sizes_total", + "substrate_sub_libp2p_kademlia_records_sizes_total", "Total size of all the records in the Kademlia records store" ), &["protocol"] )?, registry)?, kbuckets_num_nodes: prometheus::register(GaugeVec::new( Opts::new( - "sub_libp2p_kbuckets_num_nodes", + "substrate_sub_libp2p_kbuckets_num_nodes", "Number of nodes per kbucket per Kademlia instance" ), &["protocol", "lower_ilog2_bucket_bound"] )?, registry)?, listeners_local_addresses: prometheus::register(Gauge::new( - "sub_libp2p_listeners_local_addresses", "Number of local addresses we're listening on" + "substrate_sub_libp2p_listeners_local_addresses", + "Number of local addresses we're listening on" )?, registry)?, listeners_errors_total: prometheus::register(Counter::new( - "sub_libp2p_listeners_errors_total", + "substrate_sub_libp2p_listeners_errors_total", "Total number of non-fatal errors reported by a listener" )?, registry)?, notifications_sizes: prometheus::register(HistogramVec::new( HistogramOpts { common_opts: Opts::new( - "sub_libp2p_notifications_sizes", + "substrate_sub_libp2p_notifications_sizes", "Sizes of the notifications send to and received from all nodes" ), buckets: prometheus::exponential_buckets(64.0, 4.0, 8) @@ -187,38 +188,40 @@ impl Metrics { )?, registry)?, notifications_streams_closed_total: prometheus::register(CounterVec::new( Opts::new( - "sub_libp2p_notifications_streams_closed_total", + "substrate_sub_libp2p_notifications_streams_closed_total", "Total number of notification substreams that have been closed" ), &["protocol"] )?, registry)?, notifications_streams_opened_total: prometheus::register(CounterVec::new( Opts::new( - "sub_libp2p_notifications_streams_opened_total", + "substrate_sub_libp2p_notifications_streams_opened_total", "Total number of notification substreams that have been opened" ), &["protocol"] )?, registry)?, peerset_num_discovered: prometheus::register(Gauge::new( - "sub_libp2p_peerset_num_discovered", "Number of nodes stored in the peerset manager", + "substrate_sub_libp2p_peerset_num_discovered", + "Number of nodes stored in the peerset manager", )?, registry)?, peerset_num_requested: prometheus::register(Gauge::new( - "sub_libp2p_peerset_num_requested", "Number of nodes that the peerset manager wants us to be connected to", + "substrate_sub_libp2p_peerset_num_requested", + "Number of nodes that the peerset manager wants us to be connected to", )?, registry)?, pending_connections: prometheus::register(Gauge::new( - "sub_libp2p_pending_connections", + "substrate_sub_libp2p_pending_connections", "Number of connections in the process of being established", )?, registry)?, pending_connections_errors_total: prometheus::register(CounterVec::new( Opts::new( - "sub_libp2p_pending_connections_errors_total", + "substrate_sub_libp2p_pending_connections_errors_total", "Total number of pending connection errors" ), &["reason"] )?, registry)?, requests_in_failure_total: prometheus::register(CounterVec::new( Opts::new( - "sub_libp2p_requests_in_failure_total", + "substrate_sub_libp2p_requests_in_failure_total", "Total number of incoming requests that the node has failed to answer" ), &["protocol", "reason"] @@ -226,7 +229,7 @@ impl Metrics { requests_in_success_total: prometheus::register(HistogramVec::new( HistogramOpts { common_opts: Opts::new( - "sub_libp2p_requests_in_success_total", + "substrate_sub_libp2p_requests_in_success_total", "For successful incoming requests, time between receiving the request and \ starting to send the response" ), @@ -237,7 +240,7 @@ impl Metrics { )?, registry)?, requests_out_failure_total: prometheus::register(CounterVec::new( Opts::new( - "sub_libp2p_requests_out_failure_total", + "substrate_sub_libp2p_requests_out_failure_total", "Total number of requests that have failed" ), &["protocol", "reason"] @@ -245,7 +248,7 @@ impl Metrics { requests_out_success_total: prometheus::register(HistogramVec::new( HistogramOpts { common_opts: Opts::new( - "sub_libp2p_requests_out_success_total", + "substrate_sub_libp2p_requests_out_success_total", "For successful outgoing requests, time between a request's start and finish" ), buckets: prometheus::exponential_buckets(0.001, 2.0, 16) @@ -267,7 +270,7 @@ impl BandwidthCounters { fn register(registry: &Registry, sinks: Arc) -> Result<(), PrometheusError> { prometheus::register( SourcedCounter::new( - &Opts::new("sub_libp2p_network_bytes_total", "Total bandwidth usage") + &Opts::new("substrate_sub_libp2p_network_bytes_total", "Total bandwidth usage") .variable_label("direction"), BandwidthCounters(sinks), )?, @@ -298,7 +301,7 @@ impl MajorSyncingGauge { prometheus::register( SourcedGauge::new( &Opts::new( - "sub_libp2p_is_major_syncing", + "substrate_sub_libp2p_is_major_syncing", "Whether the node is performing a major sync or not.", ), MajorSyncingGauge(value), @@ -328,7 +331,7 @@ impl NumConnectedGauge { fn register(registry: &Registry, value: Arc) -> Result<(), PrometheusError> { prometheus::register( SourcedGauge::new( - &Opts::new("sub_libp2p_peers_count", "Number of connected peers"), + &Opts::new("substrate_sub_libp2p_peers_count", "Number of connected peers"), NumConnectedGauge(value), )?, registry, diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 2d6241278005b..90888c2371f9f 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -192,7 +192,7 @@ impl Metrics { Ok(Self { events_total: register(CounterVec::new( Opts::new( - "sub_libp2p_out_events_events_total", + "substrate_sub_libp2p_out_events_events_total", "Number of broadcast network events that have been sent or received across all \ channels" ), @@ -200,7 +200,7 @@ impl Metrics { )?, registry)?, notifications_sizes: register(CounterVec::new( Opts::new( - "sub_libp2p_out_events_notifications_sizes", + "substrate_sub_libp2p_out_events_notifications_sizes", "Size of notification events that have been sent or received across all \ channels" ), @@ -208,7 +208,7 @@ impl Metrics { )?, registry)?, num_channels: register(GaugeVec::new( Opts::new( - "sub_libp2p_out_events_num_channels", + "substrate_sub_libp2p_out_events_num_channels", "Number of internal active channels that broadcast network events", ), &["name"] diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 6d190651160f0..21fc55acd274b 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -95,7 +95,7 @@ impl Metrics { Ok(Self { propagated_transactions: register( Counter::new( - "sync_propagated_transactions", + "substrate_sync_propagated_transactions", "Number of transactions propagated to at least one peer", )?, r, diff --git a/client/proposer-metrics/src/lib.rs b/client/proposer-metrics/src/lib.rs index 452a796b73920..8bd626bd07916 100644 --- a/client/proposer-metrics/src/lib.rs +++ b/client/proposer-metrics/src/lib.rs @@ -56,14 +56,14 @@ impl Metrics { Ok(Self { block_constructed: register( Histogram::with_opts(HistogramOpts::new( - "proposer_block_constructed", + "substrate_proposer_block_constructed", "Histogram of time taken to construct new block", ))?, registry, )?, number_of_transactions: register( Gauge::new( - "proposer_number_of_transactions", + "substrate_proposer_number_of_transactions", "Number of transactions included in block", )?, registry, diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 1ac409d6ba89f..82da848343209 100644 --- a/client/rpc-servers/src/lib.rs +++ b/client/rpc-servers/src/lib.rs @@ -90,7 +90,7 @@ impl ServerMetrics { Ok(Self { session_opened: register( Counter::new( - "rpc_sessions_opened", + "substrate_rpc_sessions_opened", "Number of persistent RPC sessions opened", )?, r, @@ -98,7 +98,7 @@ impl ServerMetrics { .into(), session_closed: register( Counter::new( - "rpc_sessions_closed", + "substrate_rpc_sessions_closed", "Number of persistent RPC sessions closed", )?, r, diff --git a/client/rpc-servers/src/middleware.rs b/client/rpc-servers/src/middleware.rs index 00532b0e8d661..a78c0642cb584 100644 --- a/client/rpc-servers/src/middleware.rs +++ b/client/rpc-servers/src/middleware.rs @@ -48,7 +48,7 @@ impl RpcMetrics { requests_started: register( CounterVec::new( Opts::new( - "rpc_requests_started", + "substrate_rpc_requests_started", "Number of RPC requests (not calls) received by the server.", ), &["protocol"], @@ -58,7 +58,7 @@ impl RpcMetrics { requests_finished: register( CounterVec::new( Opts::new( - "rpc_requests_finished", + "substrate_rpc_requests_finished", "Number of RPC requests (not calls) processed by the server.", ), &["protocol"], @@ -68,7 +68,7 @@ impl RpcMetrics { calls_time: register( HistogramVec::new( HistogramOpts::new( - "rpc_calls_time", + "substrate_rpc_calls_time", "Total time [μs] of processed RPC calls", ), &["protocol", "method"], @@ -78,7 +78,7 @@ impl RpcMetrics { calls_started: register( CounterVec::new( Opts::new( - "rpc_calls_started", + "substrate_rpc_calls_started", "Number of received RPC calls (unique un-batched requests)", ), &["protocol", "method"], @@ -88,7 +88,7 @@ impl RpcMetrics { calls_finished: register( CounterVec::new( Opts::new( - "rpc_calls_finished", + "substrate_rpc_calls_finished", "Number of processed RPC calls (unique un-batched requests)", ), &["protocol", "method", "is_error"], diff --git a/client/service/src/config.rs b/client/service/src/config.rs index d3bd4e4e48793..0552baf5c209f 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -36,7 +36,7 @@ pub use sc_telemetry::TelemetryEndpoints; pub use sc_transaction_pool::Options as TransactionPoolOptions; use sp_core::crypto::SecretString; use std::{ - io, + io, iter, net::SocketAddr, path::{Path, PathBuf}, }; @@ -188,10 +188,11 @@ impl PrometheusConfig { /// Create a new config using the default registry. /// /// The default registry prefixes metrics with `substrate`. - pub fn new_with_default_registry(port: SocketAddr) -> Self { + pub fn new_with_default_registry(port: SocketAddr, chain_id: String) -> Self { + let param = iter::once((String::from("chain"), chain_id)).collect(); Self { port, - registry: Registry::new_custom(Some("substrate".into()), None) + registry: Registry::new_custom(None, Some(param)) .expect("this can only fail if the prefix is empty"), } } diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index 4d3c6df92fee7..54550330d75e5 100644 --- a/client/service/src/metrics.rs +++ b/client/service/src/metrics.rs @@ -55,7 +55,7 @@ impl PrometheusMetrics { register( Gauge::::with_opts( Opts::new( - "build_info", + "substrate_build_info", "A metric with a constant '1' value labeled by name, version", ) .const_label("name", name) @@ -65,8 +65,11 @@ impl PrometheusMetrics { )? .set(1); - register(Gauge::::new("node_roles", "The roles the node is running as")?, ®istry)? - .set(roles); + register( + Gauge::::new("substrate_node_roles", "The roles the node is running as")?, + ®istry, + )? + .set(roles); register_globals(registry)?; @@ -74,7 +77,7 @@ impl PrometheusMetrics { SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default(); register( Gauge::::new( - "process_start_time_seconds", + "substrate_process_start_time_seconds", "Number of seconds between the UNIX epoch and the moment the process started", )?, registry, @@ -85,20 +88,20 @@ impl PrometheusMetrics { // generic internals block_height: register( GaugeVec::new( - Opts::new("block_height", "Block height info of the chain"), + Opts::new("substrate_block_height", "Block height info of the chain"), &["status"], )?, registry, )?, number_leaves: register( - Gauge::new("number_leaves", "Number of known chain leaves (aka forks)")?, + Gauge::new("substrate_number_leaves", "Number of known chain leaves (aka forks)")?, registry, )?, ready_transactions_number: register( Gauge::new( - "ready_transactions_number", + "substrate_ready_transactions_number", "Number of transactions in the ready queue", )?, registry, @@ -106,16 +109,16 @@ impl PrometheusMetrics { // I/ O database_cache: register( - Gauge::new("database_cache_bytes", "RocksDB cache size in bytes")?, + Gauge::new("substrate_database_cache_bytes", "RocksDB cache size in bytes")?, registry, )?, state_cache: register( - Gauge::new("state_cache_bytes", "State cache size in bytes")?, + Gauge::new("substrate_state_cache_bytes", "State cache size in bytes")?, registry, )?, state_db: register( GaugeVec::new( - Opts::new("state_db_cache_bytes", "State DB cache in bytes"), + Opts::new("substrate_state_db_cache_bytes", "State DB cache in bytes"), &["subtype"], )?, registry, diff --git a/client/service/src/task_manager/mod.rs b/client/service/src/task_manager/mod.rs index 342ea6627be68..e09a351b60927 100644 --- a/client/service/src/task_manager/mod.rs +++ b/client/service/src/task_manager/mod.rs @@ -401,7 +401,7 @@ impl Metrics { poll_duration: register(HistogramVec::new( HistogramOpts { common_opts: Opts::new( - "tasks_polling_duration", + "substrate_tasks_polling_duration", "Duration in seconds of each invocation of Future::poll" ), buckets: exponential_buckets(0.001, 4.0, 9) @@ -411,21 +411,21 @@ impl Metrics { )?, registry)?, poll_start: register(CounterVec::new( Opts::new( - "tasks_polling_started_total", + "substrate_tasks_polling_started_total", "Total number of times we started invoking Future::poll" ), &["task_name", "task_group"] )?, registry)?, tasks_spawned: register(CounterVec::new( Opts::new( - "tasks_spawned_total", + "substrate_tasks_spawned_total", "Total number of tasks that have been spawned on the Service" ), &["task_name", "task_group"] )?, registry)?, tasks_ended: register(CounterVec::new( Opts::new( - "tasks_ended_total", + "substrate_tasks_ended_total", "Total number of tasks for which Future::poll has returned Ready(()) or panicked" ), &["task_name", "reason", "task_group"] diff --git a/client/transaction-pool/src/metrics.rs b/client/transaction-pool/src/metrics.rs index d62d64f13a0a4..7afed21509781 100644 --- a/client/transaction-pool/src/metrics.rs +++ b/client/transaction-pool/src/metrics.rs @@ -56,28 +56,28 @@ impl Metrics { Ok(Self { submitted_transactions: register( Counter::new( - "sub_txpool_submitted_transactions", + "substrate_sub_txpool_submitted_transactions", "Total number of transactions submitted", )?, registry, )?, validations_invalid: register( Counter::new( - "sub_txpool_validations_invalid", + "substrate_sub_txpool_validations_invalid", "Total number of transactions that were removed from the pool as invalid", )?, registry, )?, block_transactions_pruned: register( Counter::new( - "sub_txpool_block_transactions_pruned", + "substrate_sub_txpool_block_transactions_pruned", "Total number of transactions that was requested to be pruned by block events", )?, registry, )?, block_transactions_resubmitted: register( Counter::new( - "sub_txpool_block_transactions_resubmitted", + "substrate_sub_txpool_block_transactions_resubmitted", "Total number of transactions that was requested to be resubmitted by block events", )?, registry, @@ -98,14 +98,14 @@ impl ApiMetrics { Ok(Self { validations_scheduled: register( Counter::new( - "sub_txpool_validations_scheduled", + "substrate_sub_txpool_validations_scheduled", "Total number of transactions scheduled for validation", )?, registry, )?, validations_finished: register( Counter::new( - "sub_txpool_validations_finished", + "substrate_sub_txpool_validations_finished", "Total number of transactions that finished validation", )?, registry, diff --git a/client/utils/src/metrics.rs b/client/utils/src/metrics.rs index 85ccce626bc25..6e85a66e62e5a 100644 --- a/client/utils/src/metrics.rs +++ b/client/utils/src/metrics.rs @@ -29,17 +29,17 @@ use prometheus::{core::GenericCounterVec, Opts}; lazy_static! { pub static ref TOKIO_THREADS_TOTAL: GenericCounter = - GenericCounter::new("tokio_threads_total", "Total number of threads created") + GenericCounter::new("substrate_tokio_threads_total", "Total number of threads created") .expect("Creating of statics doesn't fail. qed"); pub static ref TOKIO_THREADS_ALIVE: GenericGauge = - GenericGauge::new("tokio_threads_alive", "Number of threads alive right now") + GenericGauge::new("substrate_tokio_threads_alive", "Number of threads alive right now") .expect("Creating of statics doesn't fail. qed"); } #[cfg(feature = "metered")] lazy_static! { pub static ref UNBOUNDED_CHANNELS_COUNTER : GenericCounterVec = GenericCounterVec::new( - Opts::new("unbounded_channel_len", "Items in each mpsc::unbounded instance"), + Opts::new("substrate_unbounded_channel_len", "Items in each mpsc::unbounded instance"), &["entity", "action"] // 'name of channel, send|received|dropped ).expect("Creating of statics doesn't fail. qed"); From 3dc984280b4380179fa83a3895aff84048dfe146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 9 Dec 2021 12:29:24 +0100 Subject: [PATCH 0319/1472] Rename some missed metrics (#10455) --- client/proposer-metrics/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/proposer-metrics/src/lib.rs b/client/proposer-metrics/src/lib.rs index 8bd626bd07916..ca60cafef3f6b 100644 --- a/client/proposer-metrics/src/lib.rs +++ b/client/proposer-metrics/src/lib.rs @@ -70,14 +70,14 @@ impl Metrics { )?, create_inherents_time: register( Histogram::with_opts(HistogramOpts::new( - "proposer_create_inherents_time", + "substrate_proposer_create_inherents_time", "Histogram of time taken to execute create inherents", ))?, registry, )?, create_block_proposal_time: register( Histogram::with_opts(HistogramOpts::new( - "proposer_block_proposal_time", + "substrate_proposer_block_proposal_time", "Histogram of time taken to construct a block and prepare it for proposal", ))?, registry, From 8a3434bb5e8f204107644cd32f97f5ba76d8714f Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 9 Dec 2021 13:22:54 +0100 Subject: [PATCH 0320/1472] Insufficient asset quota and deposits (#10382) * Allow asset accounts to exist by deposit * Place limit on consumers (and therefore freebie asset accounts) * Maximum number of assets * Fixes * Fixes * Formatting * Docs * Formatting * Destroyed assets are properly tidied * Update frame/assets/src/types.rs Co-authored-by: Guillaume Thiolliere * Docs * Docs * Formatting * Docs * Docs * Fixes * Fixes Co-authored-by: Guillaume Thiolliere --- .../pallets/template/src/mock.rs | 1 + bin/node-template/runtime/src/lib.rs | 3 +- bin/node/runtime/src/lib.rs | 7 +- frame/assets/src/extra_mutator.rs | 25 +-- frame/assets/src/functions.rs | 208 +++++++++++++----- frame/assets/src/impl_stored_map.rs | 10 +- frame/assets/src/lib.rs | 66 +++++- frame/assets/src/mock.rs | 36 ++- frame/assets/src/tests.rs | 103 ++++++++- frame/assets/src/types.rs | 54 ++++- frame/atomic-swap/src/tests.rs | 1 + frame/aura/src/mock.rs | 1 + frame/authority-discovery/src/lib.rs | 1 + frame/authorship/src/lib.rs | 1 + frame/babe/src/mock.rs | 1 + frame/bags-list/src/mock.rs | 1 + frame/balances/src/tests_composite.rs | 1 + frame/balances/src/tests_local.rs | 1 + frame/balances/src/tests_reentrancy.rs | 1 + frame/beefy-mmr/src/mock.rs | 1 + frame/beefy/src/mock.rs | 1 + frame/benchmarking/src/baseline.rs | 1 + frame/benchmarking/src/tests.rs | 1 + frame/benchmarking/src/tests_instance.rs | 1 + frame/bounties/src/tests.rs | 1 + frame/child-bounties/src/tests.rs | 1 + frame/collective/src/tests.rs | 1 + frame/contracts/src/tests.rs | 1 + frame/democracy/src/tests.rs | 1 + .../election-provider-multi-phase/src/mock.rs | 1 + .../election-provider-support/src/onchain.rs | 1 + frame/elections-phragmen/src/lib.rs | 1 + frame/elections/src/mock.rs | 1 + frame/examples/basic/src/tests.rs | 1 + frame/examples/offchain-worker/src/tests.rs | 1 + frame/examples/parallel/src/tests.rs | 1 + frame/executive/src/lib.rs | 1 + frame/gilt/src/mock.rs | 1 + frame/grandpa/src/mock.rs | 1 + frame/identity/src/tests.rs | 1 + frame/im-online/src/mock.rs | 1 + frame/indices/src/mock.rs | 1 + frame/lottery/src/mock.rs | 1 + frame/membership/src/lib.rs | 1 + frame/merkle-mountain-range/src/mock.rs | 1 + frame/multisig/src/tests.rs | 1 + frame/nicks/src/lib.rs | 1 + frame/node-authorization/src/mock.rs | 1 + frame/offences/benchmarking/src/mock.rs | 1 + frame/offences/src/mock.rs | 1 + frame/proxy/src/tests.rs | 1 + frame/randomness-collective-flip/src/lib.rs | 1 + frame/recovery/src/mock.rs | 1 + frame/scheduler/src/lib.rs | 1 + frame/scored-pool/src/mock.rs | 1 + frame/session/benchmarking/src/mock.rs | 1 + frame/session/src/mock.rs | 1 + frame/society/src/mock.rs | 1 + frame/staking/src/mock.rs | 1 + frame/sudo/src/mock.rs | 1 + frame/support/src/traits.rs | 7 +- frame/support/src/traits/misc.rs | 41 ++-- frame/support/test/compile_pass/Cargo.toml | 11 +- frame/support/test/compile_pass/src/lib.rs | 9 +- frame/support/test/tests/pallet.rs | 1 + .../test/tests/pallet_compatibility.rs | 1 + .../tests/pallet_compatibility_instance.rs | 1 + frame/support/test/tests/pallet_instance.rs | 1 + .../tests/pallet_with_name_trait_is_valid.rs | 1 + frame/system/benches/bench.rs | 1 + frame/system/benchmarking/src/mock.rs | 1 + frame/system/src/lib.rs | 15 +- frame/system/src/mock.rs | 1 + frame/timestamp/src/lib.rs | 1 + frame/tips/src/tests.rs | 1 + .../asset-tx-payment/src/tests.rs | 2 + frame/transaction-payment/src/lib.rs | 1 + frame/transaction-storage/src/mock.rs | 1 + frame/treasury/src/tests.rs | 1 + frame/uniques/src/mock.rs | 1 + frame/utility/src/tests.rs | 1 + frame/vesting/src/mock.rs | 1 + primitives/runtime/src/lib.rs | 4 + test-utils/runtime/src/lib.rs | 1 + 84 files changed, 514 insertions(+), 155 deletions(-) diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index 4532d3d09b497..733ac79d6577c 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -51,6 +51,7 @@ impl system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_template::Config for Test { diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 4eaa0aa00d0b6..335b36fe2f5c4 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -26,7 +26,7 @@ use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. pub use frame_support::{ construct_runtime, parameter_types, - traits::{KeyOwnerProofSystem, Randomness, StorageInfo}, + traits::{ConstU32, KeyOwnerProofSystem, Randomness, StorageInfo}, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, IdentityFee, Weight, @@ -191,6 +191,7 @@ impl frame_system::Config for Runtime { 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_randomness_collective_flip::Config for Runtime {} diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 44d39a870efcc..3134f25cfb265 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -26,8 +26,9 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU32, Currency, EnsureOneOf, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, - KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, + ConstU128, ConstU32, Currency, EnsureOneOf, EqualPrivilegeOnly, Everything, Imbalance, + InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, + U128CurrencyToVote, }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, @@ -219,6 +220,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = frame_system::weights::SubstrateWeight; type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_randomness_collective_flip::Config for Runtime {} @@ -1195,6 +1197,7 @@ impl pallet_assets::Config for Runtime { type Currency = Balances; type ForceOrigin = EnsureRoot; type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = ConstU128; type MetadataDepositBase = MetadataDepositBase; type MetadataDepositPerByte = MetadataDepositPerByte; type ApprovalDeposit = ApprovalDeposit; diff --git a/frame/assets/src/extra_mutator.rs b/frame/assets/src/extra_mutator.rs index 8c601b746346c..5ebfc3e547132 100644 --- a/frame/assets/src/extra_mutator.rs +++ b/frame/assets/src/extra_mutator.rs @@ -62,11 +62,11 @@ impl, I: 'static> ExtraMutator { id: T::AssetId, who: impl sp_std::borrow::Borrow, ) -> Option> { - if Account::::contains_key(id, who.borrow()) { + if let Some(a) = Account::::get(id, who.borrow()) { Some(ExtraMutator:: { id, who: who.borrow().clone(), - original: Account::::get(id, who.borrow()).extra, + original: a.extra, pending: None, }) } else { @@ -77,13 +77,8 @@ impl, I: 'static> ExtraMutator { /// Commit any changes to storage. pub fn commit(&mut self) -> Result<(), ()> { if let Some(extra) = self.pending.take() { - Account::::try_mutate_exists(self.id, self.who.borrow(), |maybe_account| { - if let Some(ref mut account) = maybe_account { - account.extra = extra; - Ok(()) - } else { - Err(()) - } + Account::::try_mutate(self.id, self.who.borrow(), |maybe_account| { + maybe_account.as_mut().ok_or(()).map(|account| account.extra = extra) }) } else { Ok(()) @@ -93,13 +88,11 @@ impl, I: 'static> ExtraMutator { /// Revert any changes, even those already committed by `self` and drop self. pub fn revert(mut self) -> Result<(), ()> { self.pending = None; - Account::::try_mutate_exists(self.id, self.who.borrow(), |maybe_account| { - if let Some(ref mut account) = maybe_account { - account.extra = self.original.clone(); - Ok(()) - } else { - Err(()) - } + Account::::try_mutate(self.id, self.who.borrow(), |maybe_account| { + maybe_account + .as_mut() + .ok_or(()) + .map(|account| account.extra = self.original.clone()) }) } } diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index f01954cb970ee..a34900e74bbbd 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -20,6 +20,14 @@ use super::*; use frame_support::{traits::Get, BoundedVec}; +#[must_use] +pub(super) enum DeadConsequence { + Remove, + Keep, +} + +use DeadConsequence::*; + // The main implementation block for the module. impl, I: 'static> Pallet { // Public immutables @@ -32,9 +40,17 @@ impl, I: 'static> Pallet { ExtraMutator::maybe_new(id, who) } - /// Get the asset `id` balance of `who`. + /// Get the asset `id` balance of `who`, or zero if the asset-account doesn't exist. pub fn balance(id: T::AssetId, who: impl sp_std::borrow::Borrow) -> T::Balance { - Account::::get(id, who.borrow()).balance + Self::maybe_balance(id, who).unwrap_or_default() + } + + /// Get the asset `id` balance of `who` if the asset-account exists. + pub fn maybe_balance( + id: T::AssetId, + who: impl sp_std::borrow::Borrow, + ) -> Option { + Account::::get(id, who.borrow()).map(|a| a.balance) } /// Get the total supply of an asset `id`. @@ -45,34 +61,44 @@ impl, I: 'static> Pallet { pub(super) fn new_account( who: &T::AccountId, d: &mut AssetDetails>, - ) -> Result { + maybe_deposit: Option>, + ) -> Result>, DispatchError> { let accounts = d.accounts.checked_add(1).ok_or(ArithmeticError::Overflow)?; - let is_sufficient = if d.is_sufficient { + let reason = if let Some(deposit) = maybe_deposit { + ExistenceReason::DepositHeld(deposit) + } else if d.is_sufficient { frame_system::Pallet::::inc_sufficients(who); d.sufficients += 1; - true + ExistenceReason::Sufficient } else { frame_system::Pallet::::inc_consumers(who).map_err(|_| Error::::NoProvider)?; - false + ExistenceReason::Consumer }; d.accounts = accounts; - Ok(is_sufficient) + Ok(reason) } pub(super) fn dead_account( what: T::AssetId, who: &T::AccountId, d: &mut AssetDetails>, - sufficient: bool, - ) { - if sufficient { - d.sufficients = d.sufficients.saturating_sub(1); - frame_system::Pallet::::dec_sufficients(who); - } else { - frame_system::Pallet::::dec_consumers(who); + reason: &ExistenceReason>, + force: bool, + ) -> DeadConsequence { + let mut result = Remove; + match *reason { + ExistenceReason::Consumer => frame_system::Pallet::::dec_consumers(who), + ExistenceReason::Sufficient => { + d.sufficients = d.sufficients.saturating_sub(1); + frame_system::Pallet::::dec_sufficients(who); + }, + ExistenceReason::DepositRefunded => {}, + ExistenceReason::DepositHeld(_) if !force => return Keep, + ExistenceReason::DepositHeld(_) => result = Keep, } d.accounts = d.accounts.saturating_sub(1); - T::Freezer::died(what, who) + T::Freezer::died(what, who); + result } pub(super) fn can_increase( @@ -87,15 +113,15 @@ impl, I: 'static> Pallet { if details.supply.checked_add(&amount).is_none() { return DepositConsequence::Overflow } - let account = Account::::get(id, who); - if account.balance.checked_add(&amount).is_none() { - return DepositConsequence::Overflow - } - if account.balance.is_zero() { + if let Some(balance) = Self::maybe_balance(id, who) { + if balance.checked_add(&amount).is_none() { + return DepositConsequence::Overflow + } + } else { if amount < details.min_balance { return DepositConsequence::BelowMinimum } - if !details.is_sufficient && frame_system::Pallet::::providers(who) == 0 { + if !details.is_sufficient && !frame_system::Pallet::::can_inc_consumer(who) { return DepositConsequence::CannotCreate } if details.is_sufficient && details.sufficients.checked_add(1).is_none() { @@ -124,7 +150,13 @@ impl, I: 'static> Pallet { if details.is_frozen { return Frozen } - let account = Account::::get(id, who); + if amount.is_zero() { + return Success + } + let account = match Account::::get(id, who) { + Some(a) => a, + None => return NoFunds, + }; if account.is_frozen { return Frozen } @@ -165,7 +197,7 @@ impl, I: 'static> Pallet { let details = Asset::::get(id).ok_or_else(|| Error::::Unknown)?; ensure!(!details.is_frozen, Error::::Frozen); - let account = Account::::get(id, who); + let account = Account::::get(id, who).ok_or(Error::::NoAccount)?; ensure!(!account.is_frozen, Error::::Frozen); let amount = if let Some(frozen) = T::Freezer::frozen_balance(id, who) { @@ -253,6 +285,48 @@ impl, I: 'static> Pallet { Ok((credit, maybe_burn)) } + /// Creates a account for `who` to hold asset `id` with a zero balance and takes a deposit. + pub(super) fn do_touch(id: T::AssetId, who: T::AccountId) -> DispatchResult { + ensure!(!Account::::contains_key(id, &who), Error::::AlreadyExists); + let deposit = T::AssetAccountDeposit::get(); + let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; + let reason = Self::new_account(&who, &mut details, Some(deposit))?; + T::Currency::reserve(&who, deposit)?; + Asset::::insert(&id, details); + Account::::insert( + id, + &who, + AssetAccountOf:: { + balance: Zero::zero(), + is_frozen: false, + reason, + extra: T::Extra::default(), + }, + ); + Ok(()) + } + + /// Returns a deposit, destroying an asset-account. + pub(super) fn do_refund(id: T::AssetId, who: T::AccountId, allow_burn: bool) -> DispatchResult { + let mut account = Account::::get(id, &who).ok_or(Error::::NoDeposit)?; + let deposit = account.reason.take_deposit().ok_or(Error::::NoDeposit)?; + let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; + + ensure!(account.balance.is_zero() || allow_burn, Error::::WouldBurn); + ensure!(!details.is_frozen, Error::::Frozen); + ensure!(!account.is_frozen, Error::::Frozen); + + T::Currency::unreserve(&who, deposit); + + if let Remove = Self::dead_account(id, &who, &mut details, &account.reason, false) { + Account::::remove(id, &who); + } else { + debug_assert!(false, "refund did not result in dead account?!"); + } + Asset::::insert(&id, details); + Ok(()) + } + /// Increases the asset `id` balance of `beneficiary` by `amount`. /// /// This alters the registered supply of the asset and emits an event. @@ -307,13 +381,22 @@ impl, I: 'static> Pallet { check(details)?; - Account::::try_mutate(id, beneficiary, |t| -> DispatchResult { - let new_balance = t.balance.saturating_add(amount); - ensure!(new_balance >= details.min_balance, TokenError::BelowMinimum); - if t.balance.is_zero() { - t.sufficient = Self::new_account(beneficiary, details)?; + Account::::try_mutate(id, beneficiary, |maybe_account| -> DispatchResult { + match maybe_account { + Some(ref mut account) => { + account.balance.saturating_accrue(amount); + }, + maybe_account @ None => { + // Note this should never fail as it's already checked by `can_increase`. + ensure!(amount >= details.min_balance, TokenError::BelowMinimum); + *maybe_account = Some(AssetAccountOf:: { + balance: amount, + reason: Self::new_account(beneficiary, details, None)?, + is_frozen: false, + extra: T::Extra::default(), + }); + }, } - t.balance = new_balance; Ok(()) })?; Ok(()) @@ -375,23 +458,25 @@ impl, I: 'static> Pallet { let actual = Self::prep_debit(id, target, amount, f)?; Asset::::try_mutate(id, |maybe_details| -> DispatchResult { - let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + let mut details = maybe_details.as_mut().ok_or(Error::::Unknown)?; check(actual, details)?; - Account::::try_mutate_exists(id, target, |maybe_account| -> DispatchResult { - let mut account = maybe_account.take().unwrap_or_default(); + Account::::try_mutate(id, target, |maybe_account| -> DispatchResult { + let mut account = maybe_account.take().ok_or(Error::::NoAccount)?; debug_assert!(account.balance >= actual, "checked in prep; qed"); // Make the debit. account.balance = account.balance.saturating_sub(actual); - *maybe_account = if account.balance < details.min_balance { + if account.balance < details.min_balance { debug_assert!(account.balance.is_zero(), "checked in prep; qed"); - Self::dead_account(id, target, details, account.sufficient); - None - } else { - Some(account) + if let Remove = + Self::dead_account(id, target, &mut details, &account.reason, false) + { + return Ok(()) + } }; + *maybe_account = Some(account); Ok(()) })?; @@ -432,7 +517,8 @@ impl, I: 'static> Pallet { let debit = Self::prep_debit(id, &source, amount, f.into())?; let (credit, maybe_burn) = Self::prep_credit(id, &dest, amount, debit, f.burn_dust)?; - let mut source_account = Account::::get(id, &source); + let mut source_account = + Account::::get(id, &source).ok_or(Error::::NoAccount)?; Asset::::try_mutate(id, |maybe_details| -> DispatchResult { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; @@ -459,29 +545,40 @@ impl, I: 'static> Pallet { debug_assert!(source_account.balance >= debit, "checked in prep; qed"); source_account.balance = source_account.balance.saturating_sub(debit); - Account::::try_mutate(id, &dest, |a| -> DispatchResult { - // Calculate new balance; this will not saturate since it's already checked in prep. - debug_assert!(a.balance.checked_add(&credit).is_some(), "checked in prep; qed"); - let new_balance = a.balance.saturating_add(credit); - - // Create a new account if there wasn't one already. - if a.balance.is_zero() { - a.sufficient = Self::new_account(&dest, details)?; + Account::::try_mutate(id, &dest, |maybe_account| -> DispatchResult { + match maybe_account { + Some(ref mut account) => { + // Calculate new balance; this will not saturate since it's already checked + // in prep. + debug_assert!( + account.balance.checked_add(&credit).is_some(), + "checked in prep; qed" + ); + account.balance.saturating_accrue(credit); + }, + maybe_account @ None => { + *maybe_account = Some(AssetAccountOf:: { + balance: credit, + is_frozen: false, + reason: Self::new_account(&dest, details, None)?, + extra: T::Extra::default(), + }); + }, } - - a.balance = new_balance; Ok(()) })?; // Remove source account if it's now dead. if source_account.balance < details.min_balance { debug_assert!(source_account.balance.is_zero(), "checked in prep; qed"); - Self::dead_account(id, &source, details, source_account.sufficient); - Account::::remove(id, &source); - } else { - Account::::insert(id, &source, &source_account) + if let Remove = + Self::dead_account(id, &source, details, &source_account.reason, false) + { + Account::::remove(id, &source); + return Ok(()) + } } - + Account::::insert(id, &source, &source_account); Ok(()) })?; @@ -554,7 +651,10 @@ impl, I: 'static> Pallet { ensure!(details.approvals <= witness.approvals, Error::::BadWitness); for (who, v) in Account::::drain_prefix(id) { - Self::dead_account(id, &who, &mut details, v.sufficient); + // We have to force this as it's destroying the entire asset class. + // This could mean that some accounts now have irreversibly reserved + // funds. + let _ = Self::dead_account(id, &who, &mut details, &v.reason, true); } debug_assert_eq!(details.accounts, 0); debug_assert_eq!(details.sufficients, 0); diff --git a/frame/assets/src/impl_stored_map.rs b/frame/assets/src/impl_stored_map.rs index 4c1ff1a0c6027..88e2203f046b6 100644 --- a/frame/assets/src/impl_stored_map.rs +++ b/frame/assets/src/impl_stored_map.rs @@ -22,11 +22,7 @@ use super::*; impl, I: 'static> StoredMap<(T::AssetId, T::AccountId), T::Extra> for Pallet { fn get(id_who: &(T::AssetId, T::AccountId)) -> T::Extra { let &(id, ref who) = id_who; - if Account::::contains_key(id, who) { - Account::::get(id, who).extra - } else { - Default::default() - } + Account::::get(id, who).map(|a| a.extra).unwrap_or_default() } fn try_mutate_exists>( @@ -34,13 +30,13 @@ impl, I: 'static> StoredMap<(T::AssetId, T::AccountId), T::Extra> f f: impl FnOnce(&mut Option) -> Result, ) -> Result { let &(id, ref who) = id_who; - let mut maybe_extra = Some(Account::::get(id, who).extra); + let mut maybe_extra = Account::::get(id, who).map(|a| a.extra); let r = f(&mut maybe_extra)?; // They want to write some value or delete it. // If the account existed and they want to write a value, then we write. // If the account didn't exist and they want to delete it, then we let it pass. // Otherwise, we fail. - Account::::try_mutate_exists(id, who, |maybe_account| { + Account::::try_mutate(id, who, |maybe_account| { if let Some(extra) = maybe_extra { // They want to write a value. Let this happen only if the account actually exists. if let Some(ref mut account) = maybe_account { diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 940120954f968..b86661d9fa4fd 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -212,6 +212,11 @@ pub mod pallet { #[pallet::constant] type AssetDeposit: Get>; + /// The amount of funds that must be reserved for a non-provider asset account to be + /// maintained. + #[pallet::constant] + type AssetAccountDeposit: Get>; + /// The basic amount of funds that must be reserved when adding metadata to your asset. #[pallet::constant] type MetadataDepositBase: Get>; @@ -250,15 +255,15 @@ pub mod pallet { >; #[pallet::storage] - /// The number of units of assets held by any given account. + /// The holdings of a specific account for a specific asset. pub(super) type Account, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::AssetId, Blake2_128Concat, T::AccountId, - AssetBalance, - ValueQuery, + AssetAccountOf, + OptionQuery, GetDefault, ConstU32<300_000>, >; @@ -448,8 +453,8 @@ pub mod pallet { pub enum Error { /// Account balance must be greater than or equal to the transfer amount. BalanceLow, - /// Balance should be non-zero. - BalanceZero, + /// The account to alter does not exist. + NoAccount, /// The signing account has no permission to do the operation. NoPermission, /// The given asset ID is unknown. @@ -471,6 +476,12 @@ pub mod pallet { Unapproved, /// The source account would not survive the transfer and it needs to stay alive. WouldDie, + /// The asset-account already exists. + AlreadyExists, + /// The asset-account doesn't have an associated deposit. + NoDeposit, + /// The operation would result in funds being burned. + WouldBurn, } #[pallet::call] @@ -633,7 +644,7 @@ pub mod pallet { /// /// Origin must be Signed and the sender should be the Manager of the asset `id`. /// - /// Bails with `BalanceZero` if the `who` is already dead. + /// Bails with `NoAccount` if the `who` is already dead. /// /// - `id`: The identifier of the asset to have some amount burned. /// - `who`: The account to be debited from. @@ -779,9 +790,11 @@ pub mod pallet { let d = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(&origin == &d.freezer, Error::::NoPermission); let who = T::Lookup::lookup(who)?; - ensure!(Account::::contains_key(id, &who), Error::::BalanceZero); - Account::::mutate(id, &who, |a| a.is_frozen = true); + Account::::try_mutate(id, &who, |maybe_account| -> DispatchResult { + maybe_account.as_mut().ok_or(Error::::NoAccount)?.is_frozen = true; + Ok(()) + })?; Self::deposit_event(Event::::Frozen { asset_id: id, who }); Ok(()) @@ -808,9 +821,11 @@ pub mod pallet { let details = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(&origin == &details.admin, Error::::NoPermission); let who = T::Lookup::lookup(who)?; - ensure!(Account::::contains_key(id, &who), Error::::BalanceZero); - Account::::mutate(id, &who, |a| a.is_frozen = false); + Account::::try_mutate(id, &who, |maybe_account| -> DispatchResult { + maybe_account.as_mut().ok_or(Error::::NoAccount)?.is_frozen = false; + Ok(()) + })?; Self::deposit_event(Event::::Thawed { asset_id: id, who }); Ok(()) @@ -1274,5 +1289,36 @@ pub mod pallet { let destination = T::Lookup::lookup(destination)?; Self::do_transfer_approved(id, &owner, &delegate, &destination, amount) } + + /// Create an asset account for non-provider assets. + /// + /// A deposit will be taken from the signer account. + /// + /// - `origin`: Must be Signed; the signer account must have sufficient funds for a deposit + /// to be taken. + /// - `id`: The identifier of the asset for the account to be created. + /// + /// Emits `Touched` event when successful. + #[pallet::weight(T::WeightInfo::mint())] + pub fn touch(origin: OriginFor, #[pallet::compact] id: T::AssetId) -> DispatchResult { + Self::do_touch(id, ensure_signed(origin)?) + } + + /// Return the deposit (if any) of an asset account. + /// + /// The origin must be Signed. + /// + /// - `id`: The identifier of the asset for the account to be created. + /// - `allow_burn`: If `true` then assets may be destroyed in order to complete the refund. + /// + /// Emits `Refunded` event when successful. + #[pallet::weight(T::WeightInfo::mint())] + pub fn refund( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, + allow_burn: bool, + ) -> DispatchResult { + Self::do_refund(id, ensure_signed(origin)?, allow_burn) + } } } diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index aedf437ee8439..1e88421dd5acd 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -20,7 +20,10 @@ use super::*; use crate as pallet_assets; -use frame_support::{construct_runtime, parameter_types, traits::GenesisBuild}; +use frame_support::{ + construct_runtime, + traits::{ConstU32, ConstU64, GenesisBuild}, +}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -42,9 +45,6 @@ construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -59,7 +59,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; @@ -69,17 +69,14 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<2>; } impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); type MaxLocks = (); @@ -87,25 +84,18 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; } -parameter_types! { - pub const AssetDeposit: u64 = 1; - pub const ApprovalDeposit: u64 = 1; - pub const StringLimit: u32 = 50; - pub const MetadataDepositBase: u64 = 1; - pub const MetadataDepositPerByte: u64 = 1; -} - impl Config for Test { type Event = Event; type Balance = u64; type AssetId = u32; type Currency = Balances; type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = AssetDeposit; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; - type StringLimit = StringLimit; + type AssetDeposit = ConstU64<1>; + type AssetAccountDeposit = ConstU64<10>; + type MetadataDepositBase = ConstU64<1>; + type MetadataDepositPerByte = ConstU64<1>; + type ApprovalDeposit = ConstU64<1>; + type StringLimit = ConstU32<50>; type Freezer = TestFreezer; type WeightInfo = (); type Extra = (); diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index e24a1d45215da..a3eacdda4452f 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -34,6 +34,97 @@ fn basic_minting_should_work() { }); } +#[test] +fn minting_too_many_insufficient_assets_fails() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(Origin::root(), 1, 1, false, 1)); + assert_ok!(Assets::force_create(Origin::root(), 2, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(Origin::signed(1), 1, 1, 100)); + assert_noop!(Assets::mint(Origin::signed(1), 2, 1, 100), TokenError::CannotCreate); + + Balances::make_free_balance_be(&2, 1); + assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::mint(Origin::signed(1), 2, 1, 100)); + }); +} + +#[test] +fn minting_insufficient_asset_with_deposit_should_work_when_consumers_exhausted() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(Origin::root(), 1, 1, false, 1)); + assert_ok!(Assets::force_create(Origin::root(), 2, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(Origin::signed(1), 1, 1, 100)); + assert_noop!(Assets::mint(Origin::signed(1), 2, 1, 100), TokenError::CannotCreate); + + assert_ok!(Assets::touch(Origin::signed(1), 2)); + assert_eq!(Balances::reserved_balance(&1), 10); + + assert_ok!(Assets::mint(Origin::signed(1), 2, 1, 100)); + }); +} + +#[test] +fn minting_insufficient_assets_with_deposit_without_consumer_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_noop!(Assets::mint(Origin::signed(1), 0, 1, 100), TokenError::CannotCreate); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::touch(Origin::signed(1), 0)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_eq!(Balances::reserved_balance(&1), 10); + assert_eq!(System::consumers(&1), 0); + }); +} + +#[test] +fn refunding_asset_deposit_with_burn_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::touch(Origin::signed(1), 0)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::refund(Origin::signed(1), 0, true)); + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Assets::balance(1, 0), 0); + }); +} + +#[test] +fn refunding_asset_deposit_with_burn_disallowed_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::touch(Origin::signed(1), 0)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_noop!(Assets::refund(Origin::signed(1), 0, false), Error::::WouldBurn); + }); +} + +#[test] +fn refunding_asset_deposit_without_burn_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_noop!(Assets::mint(Origin::signed(1), 0, 1, 100), TokenError::CannotCreate); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::touch(Origin::signed(1), 0)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + Balances::make_free_balance_be(&2, 100); + assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 100)); + assert_eq!(Assets::balance(0, 2), 100); + assert_eq!(Assets::balance(0, 1), 0); + assert_eq!(Balances::reserved_balance(&1), 10); + assert_ok!(Assets::refund(Origin::signed(1), 0, false)); + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Assets::balance(1, 0), 0); + }); +} + #[test] fn approval_lifecycle_works() { new_test_ext().execute_with(|| { @@ -299,17 +390,17 @@ fn min_balance_should_work() { // When deducting from an account to below minimum, it should be reaped. assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 91)); - assert!(Assets::balance(0, 1).is_zero()); + assert!(Assets::maybe_balance(0, 1).is_none()); assert_eq!(Assets::balance(0, 2), 100); assert_eq!(Asset::::get(0).unwrap().accounts, 1); assert_ok!(Assets::force_transfer(Origin::signed(1), 0, 2, 1, 91)); - assert!(Assets::balance(0, 2).is_zero()); + assert!(Assets::maybe_balance(0, 2).is_none()); assert_eq!(Assets::balance(0, 1), 100); assert_eq!(Asset::::get(0).unwrap().accounts, 1); assert_ok!(Assets::burn(Origin::signed(1), 0, 1, 91)); - assert!(Assets::balance(0, 1).is_zero()); + assert!(Assets::maybe_balance(0, 1).is_none()); assert_eq!(Asset::::get(0).unwrap().accounts, 0); }); } @@ -488,7 +579,7 @@ fn transferring_amount_more_than_available_balance_should_not_work() { assert_eq!(Assets::balance(0, 2), 50); assert_ok!(Assets::burn(Origin::signed(1), 0, 1, u64::MAX)); assert_eq!(Assets::balance(0, 1), 0); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 1, 50), Error::::BalanceLow); + assert_noop!(Assets::transfer(Origin::signed(1), 0, 1, 50), Error::::NoAccount); assert_noop!(Assets::transfer(Origin::signed(2), 0, 1, 51), Error::::BalanceLow); }); } @@ -536,7 +627,7 @@ fn burning_asset_balance_with_zero_balance_does_nothing() { assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 2), 0); - assert_ok!(Assets::burn(Origin::signed(1), 0, 2, u64::MAX)); + assert_noop!(Assets::burn(Origin::signed(1), 0, 2, u64::MAX), Error::::NoAccount); assert_eq!(Assets::balance(0, 2), 0); assert_eq!(Assets::total_supply(0), 100); }); @@ -688,7 +779,7 @@ fn force_metadata_should_work() { ); // string length limit check - let limit = StringLimit::get() as usize; + let limit = 50usize; assert_noop!( Assets::force_set_metadata( Origin::root(), diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index 16f7368f12b74..ecf5f5edf4179 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -26,6 +26,8 @@ use sp_runtime::{traits::Convert, FixedPointNumber, FixedPointOperand, FixedU128 pub(super) type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; +pub(super) type AssetAccountOf = + AssetAccount<>::Balance, DepositBalanceOf, >::Extra>; #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] pub struct AssetDetails { @@ -76,14 +78,47 @@ pub struct Approval { pub(super) deposit: DepositBalance, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, MaxEncodedLen, TypeInfo)] -pub struct AssetBalance { +#[test] +fn ensure_bool_decodes_to_consumer_or_sufficient() { + assert_eq!(false.encode(), ExistenceReason::<()>::Consumer.encode()); + assert_eq!(true.encode(), ExistenceReason::<()>::Sufficient.encode()); +} + +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub enum ExistenceReason { + #[codec(index = 0)] + Consumer, + #[codec(index = 1)] + Sufficient, + #[codec(index = 2)] + DepositHeld(Balance), + #[codec(index = 3)] + DepositRefunded, +} + +impl ExistenceReason { + pub(crate) fn take_deposit(&mut self) -> Option { + if !matches!(self, ExistenceReason::DepositHeld(_)) { + return None + } + if let ExistenceReason::DepositHeld(deposit) = + sp_std::mem::replace(self, ExistenceReason::DepositRefunded) + { + return Some(deposit) + } else { + return None + } + } +} + +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct AssetAccount { /// The balance. pub(super) balance: Balance, /// Whether the account is frozen. pub(super) is_frozen: bool, - /// `true` if this balance gave the account a self-sufficient reference. - pub(super) sufficient: bool, + /// The reason for the existence of the account. + pub(super) reason: ExistenceReason, /// Additional "sidecar" data, in case some other pallet wants to use this storage item. pub(super) extra: Extra, } @@ -124,12 +159,15 @@ pub struct DestroyWitness { pub trait FrozenBalance { /// Return the frozen balance. /// + /// Generally, the balance of every account must be at least the sum of this (if `Some`) and + /// the asset's `minimum_balance` (the latter since there may be complications to destroying an + /// asset's account completely). + /// /// Under normal behaviour, the account balance should not go below the sum of this (if `Some`) - /// and the asset's minimum balance. - /// But the account balance can be below this sum (e.g. if less than the sum has been - /// transfered to the account). + /// and the asset's minimum balance. However, the account balance may reasonably begin below + /// this sum (e.g. if less than the sum had ever been transfered into the account). /// - /// In special case (privileged intervention) the account balance can go below the sum. + /// In special cases (privileged intervention) the account balance may also go below the sum. /// /// If `None` is returned, then nothing special is enforced. fn frozen_balance(asset: AssetId, who: &AccountId) -> Option; diff --git a/frame/atomic-swap/src/tests.rs b/frame/atomic-swap/src/tests.rs index a76d0f20ffa3b..47e33252e0943 100644 --- a/frame/atomic-swap/src/tests.rs +++ b/frame/atomic-swap/src/tests.rs @@ -54,6 +54,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 4418d9e85ae24..12748bd212d37 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -78,6 +78,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_timestamp::Config for Test { diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index a6609860d7cf1..c867f98af3e17 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -260,6 +260,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } pub struct TestSessionHandler; diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 5d36adabe888f..cd91957475a1e 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -458,6 +458,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index f62e73aa43917..f3325d0c65a08 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -96,6 +96,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 6545e563a3efe..90d5347b1242f 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -68,6 +68,7 @@ impl frame_system::Config for Runtime { type OnKilledAccount = (); type SystemWeightInfo = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 60feedb326d8a..b1a7f2417df84 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -73,6 +73,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const TransactionByteFee: u64 = 1; diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index a861df4746a11..ff08e63562011 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -75,6 +75,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const TransactionByteFee: u64 = 1; diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 43edd16baf3b3..01b02943484bf 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -77,6 +77,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const TransactionByteFee: u64 = 1; diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 95b87c360510a..f1195dcc9c028 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -86,6 +86,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index a1fbeda4ab35c..3ce582b29d22d 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -84,6 +84,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_beefy::Config for Test { diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 87cdf80409b89..e2f9f1f2975fd 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -195,6 +195,7 @@ pub mod mock { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl super::Config for Test {} diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index a2cf381e6ecf8..e27b3e09dbedb 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -108,6 +108,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index 0ad156ce5a88d..09d11eb6c58d2 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -110,6 +110,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index bbcf9d6d9e72d..ac1f104119dfe 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -84,6 +84,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index ada13e968c4d4..8e2569738b1f2 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -86,6 +86,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index cbd2f68ac73e8..466cdb3eeeb5b 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -115,6 +115,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl Config for Test { type Origin = Origin; diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index f19f5a3159557..1554d1230089e 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -206,6 +206,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_randomness_collective_flip::Config for Test {} impl pallet_balances::Config for Test { diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 06c4ac666cfba..3c223172987e8 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -105,6 +105,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index f90c64b75ccb0..3ac14b89e7953 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -218,6 +218,7 @@ impl frame_system::Config for Runtime { type OnKilledAccount = (); type SystemWeightInfo = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 6379adae4206b..a2eb53edcf84c 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -145,6 +145,7 @@ mod tests { type OnKilledAccount = (); type SystemWeightInfo = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl Config for Runtime { diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 116c0937bf983..8daa4e7fe13c1 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1150,6 +1150,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/elections/src/mock.rs b/frame/elections/src/mock.rs index 91318e1e07bcc..bce60534a3522 100644 --- a/frame/elections/src/mock.rs +++ b/frame/elections/src/mock.rs @@ -60,6 +60,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index e069cccf8d800..b97083f27d5ee 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -79,6 +79,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 1dde8a1df60c8..9fb965784f186 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -77,6 +77,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } type Extrinsic = TestXt; diff --git a/frame/examples/parallel/src/tests.rs b/frame/examples/parallel/src/tests.rs index 4c36f0d6eb858..5de9af878723a 100644 --- a/frame/examples/parallel/src/tests.rs +++ b/frame/examples/parallel/src/tests.rs @@ -68,6 +68,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 9b81527fadb35..7ff5584879cea 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -767,6 +767,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } type Balance = u64; diff --git a/frame/gilt/src/mock.rs b/frame/gilt/src/mock.rs index ac3f4df1b71dd..9ea33a6d6b68d 100644 --- a/frame/gilt/src/mock.rs +++ b/frame/gilt/src/mock.rs @@ -74,6 +74,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index fe7a530ffe0c8..aed13ec3717a9 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -98,6 +98,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 31b93e70fd3dc..2faf65f560a88 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -75,6 +75,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 1e4d4b43d5789..1d985b9007ea9 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -139,6 +139,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index f4c87016141b5..3e3aed2986b9f 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -69,6 +69,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/lottery/src/mock.rs b/frame/lottery/src/mock.rs index d1f090aa26dcb..df86e063c477f 100644 --- a/frame/lottery/src/mock.rs +++ b/frame/lottery/src/mock.rs @@ -79,6 +79,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 6cd8c13f39aff..4bcc28c0ef46a 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -560,6 +560,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } ord_parameter_types! { pub const One: u64 = 1; diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index 3616a8d1d5242..392ae5050a96c 100644 --- a/frame/merkle-mountain-range/src/mock.rs +++ b/frame/merkle-mountain-range/src/mock.rs @@ -69,6 +69,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl Config for Test { diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index 523aefd1e753c..f050ac9d72001 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -74,6 +74,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index bfc23187fc5b5..ea58ea693d3fb 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -297,6 +297,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/node-authorization/src/mock.rs b/frame/node-authorization/src/mock.rs index 6c79f601c197d..8e2bc7cfd2a6d 100644 --- a/frame/node-authorization/src/mock.rs +++ b/frame/node-authorization/src/mock.rs @@ -71,6 +71,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } ord_parameter_types! { diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 26a53c7f8a048..ab2b3569228c6 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -63,6 +63,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: Balance = 10; diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index bce51f527abc6..c2db42ec72fac 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -112,6 +112,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl Config for Runtime { diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index d3565525910fb..538527d47ecd0 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -78,6 +78,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index 345b8072c5e47..eee70984f2576 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -219,6 +219,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_randomness_collective_flip::Config for Test {} diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index f6d4a6b159431..1bd7507436b7a 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -75,6 +75,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 260ef90b05372..02bcb5eb3109f 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -932,6 +932,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl logger::Config for Test { type Event = Event; diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index 5c5425ae2bdd8..992aecba38e82 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -81,6 +81,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index e000255b84b87..3f3b103905b58 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -68,6 +68,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: Balance = 10; diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index 6db7727fa5391..d0511d3936822 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -264,6 +264,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_timestamp::Config for Test { diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 9356c083f2331..4348f2378c425 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -89,6 +89,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 8a8ab1f1e4d04..89ab86259b95f 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -150,6 +150,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { type MaxLocks = MaxLocks; diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index bfbed0d38ab34..88379d0e5fda8 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -144,6 +144,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } // Implement the logger module's `Config` on the Test runtime. diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 9b5453c0a01ae..3c1f268ade073 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -50,9 +50,10 @@ pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter mod misc; pub use misc::{ - Backing, ConstU32, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, - ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, - OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, TryDrop, + Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, + ConstU32, ConstU64, ConstU8, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, + ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, + Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, TryDrop, UnixTime, WrapperKeepOpaque, WrapperOpaque, }; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 153c3804bd599..165a83b4be2a0 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -60,20 +60,33 @@ impl Get for GetDefault { } } -/// Implement `Get` and `Get>` using the given const. -pub struct ConstU32; - -impl Get for ConstU32 { - fn get() -> u32 { - T - } -} - -impl Get> for ConstU32 { - fn get() -> Option { - Some(T) - } -} +macro_rules! impl_const_get { + ($name:ident, $t:ty) => { + pub struct $name; + impl Get<$t> for $name { + fn get() -> $t { + T + } + } + impl Get> for $name { + fn get() -> Option<$t> { + Some(T) + } + } + }; +} + +impl_const_get!(ConstBool, bool); +impl_const_get!(ConstU8, u8); +impl_const_get!(ConstU16, u16); +impl_const_get!(ConstU32, u32); +impl_const_get!(ConstU64, u64); +impl_const_get!(ConstU128, u128); +impl_const_get!(ConstI8, i8); +impl_const_get!(ConstI16, i16); +impl_const_get!(ConstI32, i32); +impl_const_get!(ConstI64, i64); +impl_const_get!(ConstI128, i128); /// A type for which some values make sense to be able to drop without further consideration. pub trait TryDrop: Sized { diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index 62472a8957ce3..aa53f7ad358dd 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -17,14 +17,17 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-core = { version = "4.0.0", default-features = false, path = "../../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" } -support = { package = "frame-support", version = "4.0.0-dev", default-features = false, path = "../../" } -system = { package = "frame-system", version = "4.0.0-dev", default-features = false, path = "../../../system" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } [features] default = ["std"] std = [ "codec/std", "scale-info/std", - "support/std", - "system/std", + "sp-core/std", + "sp-runtime/std", + "sp-version/std", + "frame-support/std", + "frame-system/std", ] diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index 17ba40574adf7..06fb6345d3c8d 100644 --- a/frame/support/test/compile_pass/src/lib.rs +++ b/frame/support/test/compile_pass/src/lib.rs @@ -22,13 +22,13 @@ //! This crate tests that `construct_runtime!` expands the pallet parts //! correctly even when frame-support is renamed in Cargo.toml +use frame_support::{construct_runtime, parameter_types}; use sp_core::{sr25519, H256}; use sp_runtime::{ create_runtime_str, generic, traits::{BlakeTwo256, IdentityLookup, Verify}, }; use sp_version::RuntimeVersion; -use support::{construct_runtime, parameter_types}; pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("frame-support-test-compile-pass"), @@ -51,8 +51,8 @@ parameter_types! { pub const SS58Prefix: u8 = 0; } -impl system::Config for Runtime { - type BaseCallFilter = support::traits::Everything; +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); type Index = u128; @@ -73,6 +73,7 @@ impl system::Config for Runtime { type OnNewAccount = (); type OnKilledAccount = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; } @@ -87,6 +88,6 @@ construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system, + System: frame_system, } ); diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 509e3217ddf96..e9c6fe8be5601 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -566,6 +566,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index 4523063252ab9..0cd6a6e59cffc 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -246,6 +246,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 768b9f28d35f3..16f5e16cb873e 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -226,6 +226,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index de70b0e7e404e..9fd748eb332c3 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -274,6 +274,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; diff --git a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs index 1c47d13a619f2..170e515740b3c 100644 --- a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs +++ b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs @@ -152,6 +152,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_test::Trait for Runtime { diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index c8a9d4eadfea0..0d513ff599d53 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -92,6 +92,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl module::Config for Runtime { diff --git a/frame/system/benchmarking/src/mock.rs b/frame/system/benchmarking/src/mock.rs index d828fb22ff5ff..ff00b76c45fdf 100644 --- a/frame/system/benchmarking/src/mock.rs +++ b/frame/system/benchmarking/src/mock.rs @@ -62,6 +62,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl crate::Config for Test {} diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 7825c9ec07802..8823aa37c19c5 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -309,6 +309,10 @@ pub mod pallet { /// It's unlikely that this needs to be customized, unless you are writing a parachain using /// `Cumulus`, where the actual code change is deferred. type OnSetCode: SetCode; + + /// The maximum number of consumers allowed on a single account. + #[pallet::constant] + type MaxConsumers: Get; } #[pallet::pallet] @@ -1107,8 +1111,12 @@ impl Pallet { pub fn inc_consumers(who: &T::AccountId) -> Result<(), DispatchError> { Account::::try_mutate(who, |a| { if a.providers > 0 { - a.consumers = a.consumers.saturating_add(1); - Ok(()) + if a.consumers < T::MaxConsumers::get() { + a.consumers = a.consumers.saturating_add(1); + Ok(()) + } else { + Err(DispatchError::TooManyConsumers) + } } else { Err(DispatchError::NoProviders) } @@ -1148,7 +1156,8 @@ impl Pallet { /// True if the account has at least one provider reference. pub fn can_inc_consumer(who: &T::AccountId) -> bool { - Account::::get(who).providers > 0 + let a = Account::::get(who); + a.providers > 0 && a.consumers < T::MaxConsumers::get() } /// Deposits an event into this block's event record. diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index 9dd35691cab84..de89324ec9fb4 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -111,6 +111,7 @@ impl Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } pub type SysEvent = frame_system::Event; diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index eeb840715f817..ae9a3b5f69ad9 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -372,6 +372,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const MinimumPeriod: u64 = 5; diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index 2aac22ffe18ca..7d6a717347310 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -83,6 +83,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index bd5dc57239a28..106b361aff8f3 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -112,6 +112,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -169,6 +170,7 @@ impl pallet_assets::Config for Runtime { type Currency = Balances; type ForceOrigin = EnsureRoot; type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = frame_support::traits::ConstU64<2>; type MetadataDepositBase = MetadataDeposit; type MetadataDepositPerByte = MetadataDeposit; type ApprovalDeposit = MetadataDeposit; diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 02ba9621c175d..a5bcc6d12dec8 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -865,6 +865,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs index 38d14129d76e2..49b81348e7d4f 100644 --- a/frame/transaction-storage/src/mock.rs +++ b/frame/transaction-storage/src/mock.rs @@ -77,6 +77,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index 534661b2773bb..c2b41e7165234 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -79,6 +79,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index 658e82a5143e2..f65f69209b9ed 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -69,6 +69,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 32582fae82116..169ac6cfff897 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -127,6 +127,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index cb8961150003b..1e04875a7e077 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -64,6 +64,7 @@ impl frame_system::Config for Test { type OnKilledAccount = (); type OnNewAccount = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; type Origin = Origin; type PalletInfo = PalletInfo; type SS58Prefix = (); diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 8cd15b51a32c3..10fd39d38f4cc 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -494,6 +494,8 @@ pub enum DispatchError { ConsumerRemaining, /// There are no providers so the account cannot be created. NoProviders, + /// There are too many consumers so the account cannot be created. + TooManyConsumers, /// An error to do with tokens. Token(TokenError), /// An arithmetic error. @@ -629,6 +631,7 @@ impl From for &'static str { DispatchError::Module { message, .. } => message.unwrap_or("Unknown module error"), DispatchError::ConsumerRemaining => "Consumer remaining", DispatchError::NoProviders => "No providers", + DispatchError::TooManyConsumers => "Too many consumers", DispatchError::Token(e) => e.into(), DispatchError::Arithmetic(e) => e.into(), } @@ -660,6 +663,7 @@ impl traits::Printable for DispatchError { }, Self::ConsumerRemaining => "Consumer remaining".print(), Self::NoProviders => "No providers".print(), + Self::TooManyConsumers => "Too many consumers".print(), Self::Token(e) => { "Token error: ".print(); <&'static str>::from(*e).print(); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 08863de510d09..7b78880c2c3bf 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -591,6 +591,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_timestamp::Config for Runtime { From 6a634fb132f4ae50b42ac5efd10ea89e086216dc Mon Sep 17 00:00:00 2001 From: Gautam Dhameja Date: Thu, 9 Dec 2021 15:16:35 +0100 Subject: [PATCH 0321/1472] Fix reset curator deposit when curator unassigns themself. (#10443) --- frame/bounties/src/lib.rs | 1 + frame/bounties/src/tests.rs | 39 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 1d32b63f38f92..7e8ba60050561 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -453,6 +453,7 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&curator, bounty.curator_deposit); debug_assert!(err_amount.is_zero()); + bounty.curator_deposit = Zero::zero(); // Continue to change bounty status below... } }, diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index ac1f104119dfe..dc6cecc06f5ed 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -1004,3 +1004,42 @@ fn genesis_funding_works() { assert_eq!(Treasury::pot(), initial_funding - Balances::minimum_balance()); }); } + +#[test] +fn unassign_curator_self() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 1, 10)); + assert_ok!(Bounties::accept_curator(Origin::signed(1), 0)); + + assert_eq!(Balances::free_balance(1), 93); + assert_eq!(Balances::reserved_balance(1), 5); + + System::set_block_number(8); + >::on_initialize(8); + + assert_ok!(Bounties::unassign_curator(Origin::signed(1), 0)); + + assert_eq!( + Bounties::bounties(0).unwrap(), + Bounty { + proposer: 0, + fee: 10, + curator_deposit: 0, + value: 50, + bond: 85, + status: BountyStatus::Funded, + } + ); + + assert_eq!(Balances::free_balance(1), 98); + assert_eq!(Balances::reserved_balance(1), 0); // not slashed + }); +} From 1aea26eb820199c422f05f0d26558d8d7c70542e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lo=C3=AFs?= Date: Thu, 9 Dec 2021 16:10:16 +0100 Subject: [PATCH 0322/1472] Make wasm runtime cache size configurable (#10177) * Make wasm runtime cache size configurable * apply review comments * remove VersionedRuntimeValue * fix compilation * VersionedRuntime: replace clone by Arc * fmt * fix warnings * fix tests compilation * fmt --- Cargo.lock | 1 + bin/node-template/node/src/service.rs | 1 + bin/node/cli/benches/block_production.rs | 1 + bin/node/cli/benches/transaction_pool.rs | 1 + bin/node/cli/src/service.rs | 1 + bin/node/executor/benches/bench.rs | 2 +- bin/node/executor/tests/common.rs | 2 +- bin/node/inspect/src/command.rs | 1 + bin/node/testing/src/bench.rs | 2 +- client/cli/src/commands/run_cmd.rs | 8 ++ client/cli/src/config.rs | 9 ++ client/executor/Cargo.toml | 1 + client/executor/src/integration_tests/mod.rs | 3 + client/executor/src/lib.rs | 1 + client/executor/src/native_executor.rs | 10 +- client/executor/src/wasm_runtime.rs | 143 +++++++++---------- client/service/src/client/call_executor.rs | 1 + client/service/src/client/wasm_override.rs | 2 + client/service/src/config.rs | 2 + client/service/test/src/client/mod.rs | 7 +- client/service/test/src/lib.rs | 1 + primitives/api/test/tests/runtime_calls.rs | 1 + primitives/runtime-interface/test/src/lib.rs | 1 + test-utils/client/src/lib.rs | 2 +- test-utils/runtime/client/src/lib.rs | 7 +- test-utils/runtime/src/system.rs | 2 +- test-utils/test-runner/src/client.rs | 1 + test-utils/test-runner/src/utils.rs | 1 + utils/frame/benchmarking-cli/src/command.rs | 1 + utils/frame/try-runtime/cli/src/lib.rs | 8 +- 30 files changed, 142 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3e186aca4287..e7ddb66e29188 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8035,6 +8035,7 @@ dependencies = [ "lazy_static", "libsecp256k1", "log 0.4.14", + "lru 0.6.6", "parity-scale-codec", "parking_lot 0.11.1", "paste 1.0.6", diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 82b1c5625373c..92bd059e528a8 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -78,6 +78,7 @@ pub fn new_partial( config.wasm_method, config.default_heap_pages, config.max_runtime_instances, + config.runtime_cache_size, ); let (client, backend, keystore_container, task_manager) = diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 5a520e7b63397..f2dbc1fff6be2 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -104,6 +104,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { tracing_targets: None, tracing_receiver: Default::default(), max_runtime_instances: 8, + runtime_cache_size: 2, announce_block: true, base_path: Some(base_path), informant_output_format: Default::default(), diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index 4f5ccd6ea912f..2965c6336f0f7 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -96,6 +96,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { tracing_targets: None, tracing_receiver: Default::default(), max_runtime_instances: 8, + runtime_cache_size: 2, announce_block: true, base_path: Some(base_path), informant_output_format: Default::default(), diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 1dfce9331b752..fbc91c5f7d2e7 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -161,6 +161,7 @@ pub fn new_partial( config.wasm_method, config.default_heap_pages, config.max_runtime_instances, + config.runtime_cache_size, ); let (client, backend, keystore_container, task_manager) = diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index 03c3eb53e23f9..aea37b68d55ba 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -194,7 +194,7 @@ fn bench_execute_block(c: &mut Criterion) { ExecutionMethod::Wasm(wasm_method) => (false, wasm_method), }; - let executor = NativeElseWasmExecutor::new(wasm_method, None, 8); + let executor = NativeElseWasmExecutor::new(wasm_method, None, 8, 2); let runtime_code = RuntimeCode { code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()), hash: vec![1, 2, 3], diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index 87506ba66a3e4..84b5728a1a840 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -96,7 +96,7 @@ pub fn from_block_number(n: u32) -> Header { } pub fn executor() -> NativeElseWasmExecutor { - NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8) + NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2) } pub fn executor_call< diff --git a/bin/node/inspect/src/command.rs b/bin/node/inspect/src/command.rs index 9bf69511689c4..e20c91456515c 100644 --- a/bin/node/inspect/src/command.rs +++ b/bin/node/inspect/src/command.rs @@ -41,6 +41,7 @@ impl InspectCmd { config.wasm_method, config.default_heap_pages, config.max_runtime_instances, + config.runtime_cache_size, ); let client = new_full_client::(&config, None, executor)?; diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 3240497a9d623..6a5c4b80e1fef 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -400,7 +400,7 @@ impl BenchDb { let backend = sc_service::new_db_backend(db_config).expect("Should not fail"); let client = sc_service::new_client( backend.clone(), - NativeElseWasmExecutor::new(WasmExecutionMethod::Compiled, None, 8), + NativeElseWasmExecutor::new(WasmExecutionMethod::Compiled, None, 8, 2), &keyring.generate_genesis(), None, None, diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 622206fdf2977..78ea4b1276b23 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -238,6 +238,10 @@ pub struct RunCmd { #[structopt(long)] pub max_runtime_instances: Option, + /// Maximum number of different runtimes that can be cached. + #[structopt(long, default_value = "2")] + pub runtime_cache_size: u8, + /// Run a temporary node. /// /// A temporary directory will be created to store the configuration and will be deleted @@ -453,6 +457,10 @@ impl CliConfiguration for RunCmd { Ok(self.max_runtime_instances.map(|x| x.min(256))) } + fn runtime_cache_size(&self) -> Result { + Ok(self.runtime_cache_size) + } + fn base_path(&self) -> Result> { Ok(if self.tmp { Some(BasePath::new_temp_dir()?) diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 20e2bf0df5b2e..1fda07d2571fb 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -452,6 +452,13 @@ pub trait CliConfiguration: Sized { Ok(Default::default()) } + /// Get maximum different runtimes in cache + /// + /// By default this is `2`. + fn runtime_cache_size(&self) -> Result { + Ok(2) + } + /// Activate or not the automatic announcing of blocks after import /// /// By default this is `false`. @@ -482,6 +489,7 @@ pub trait CliConfiguration: Sized { let is_validator = role.is_authority(); let (keystore_remote, keystore) = self.keystore_config(&config_dir)?; let telemetry_endpoints = self.telemetry_endpoints(&chain_spec)?; + let runtime_cache_size = self.runtime_cache_size()?; let unsafe_pruning = self.import_params().map(|p| p.unsafe_pruning).unwrap_or(false); @@ -534,6 +542,7 @@ pub trait CliConfiguration: Sized { role, base_path: Some(base_path), informant_output_format: Default::default(), + runtime_cache_size, }) } diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index b3a393f9472ae..dea8a26edde36 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -34,6 +34,7 @@ parking_lot = "0.11.1" log = "0.4.8" libsecp256k1 = "0.7" sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } +lru = "0.6.6" [dev-dependencies] wat = "1.0" diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 01c040687ddd9..3ff0ecebd9acf 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -130,6 +130,7 @@ fn call_in_wasm( HostFunctions::host_functions(), 8, None, + 2, ); executor.uncached_call( RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(), @@ -480,6 +481,7 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { HostFunctions::host_functions(), 8, None, + 2, ); let err = executor @@ -593,6 +595,7 @@ fn parallel_execution(wasm_method: WasmExecutionMethod) { HostFunctions::host_functions(), 8, None, + 2, )); let threads: Vec<_> = (0..8) .map(|_| { diff --git a/client/executor/src/lib.rs b/client/executor/src/lib.rs index 041db87bc82ab..9a4d8e3cf0b6a 100644 --- a/client/executor/src/lib.rs +++ b/client/executor/src/lib.rs @@ -80,6 +80,7 @@ mod tests { sp_io::SubstrateHostFunctions::host_functions(), 8, None, + 2, ); let res = executor .uncached_call( diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 62e76d559c0f2..1c01520ac9c8e 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -130,12 +130,17 @@ impl WasmExecutor { host_functions: Vec<&'static dyn Function>, max_runtime_instances: usize, cache_path: Option, + runtime_cache_size: u8, ) -> Self { WasmExecutor { method, default_heap_pages: default_heap_pages.unwrap_or(DEFAULT_HEAP_PAGES), host_functions: Arc::new(host_functions), - cache: Arc::new(RuntimeCache::new(max_runtime_instances, cache_path.clone())), + cache: Arc::new(RuntimeCache::new( + max_runtime_instances, + cache_path.clone(), + runtime_cache_size, + )), cache_path, } } @@ -330,6 +335,7 @@ impl NativeElseWasmExecutor { fallback_method: WasmExecutionMethod, default_heap_pages: Option, max_runtime_instances: usize, + runtime_cache_size: u8, ) -> Self { let extended = D::ExtendHostFunctions::host_functions(); let mut host_functions = sp_io::SubstrateHostFunctions::host_functions() @@ -351,6 +357,7 @@ impl NativeElseWasmExecutor { host_functions, max_runtime_instances, None, + runtime_cache_size, ); NativeElseWasmExecutor { @@ -636,6 +643,7 @@ mod tests { WasmExecutionMethod::Interpreted, None, 8, + 2, ); my_interface::HostFunctions::host_functions().iter().for_each(|function| { assert_eq!(executor.wasm.host_functions.iter().filter(|f| f == &function).count(), 2); diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 88c033814ed6a..44ed6eb32304b 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -23,6 +23,7 @@ use crate::error::{Error, WasmError}; use codec::Decode; +use lru::LruCache; use parking_lot::Mutex; use sc_executor_common::{ runtime_blob::RuntimeBlob, @@ -54,20 +55,24 @@ impl Default for WasmExecutionMethod { } } -/// A Wasm runtime object along with its cached runtime version. -struct VersionedRuntime { +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +struct VersionedRuntimeId { /// Runtime code hash. code_hash: Vec, /// Wasm runtime type. wasm_method: WasmExecutionMethod, - /// Shared runtime that can spawn instances. - module: Arc, /// The number of WebAssembly heap pages this instance was created with. heap_pages: u64, +} + +/// A Wasm runtime object along with its cached runtime version. +struct VersionedRuntime { + /// Shared runtime that can spawn instances. + module: Arc, /// Runtime version according to `Core_version` if any. version: Option, /// Cached instance pool. - instances: Vec>>>, + instances: Arc>>>>, } impl VersionedRuntime { @@ -137,8 +142,6 @@ impl VersionedRuntime { } } -const MAX_RUNTIMES: usize = 2; - /// Cache for the runtimes. /// /// When an instance is requested for the first time it is added to this cache. Metadata is kept @@ -149,12 +152,12 @@ const MAX_RUNTIMES: usize = 2; /// the memory reset to the initial memory. So, one runtime instance is reused for every fetch /// request. /// -/// The size of cache is equal to `MAX_RUNTIMES`. +/// The size of cache is configurable via the cli option `--runtime-cache-size`. pub struct RuntimeCache { /// A cache of runtimes along with metadata. /// /// Runtimes sorted by recent usage. The most recently used is at the front. - runtimes: Mutex<[Option>; MAX_RUNTIMES]>, + runtimes: Mutex>>, /// The size of the instances cache for each runtime. max_runtime_instances: usize, cache_path: Option, @@ -163,13 +166,24 @@ pub struct RuntimeCache { impl RuntimeCache { /// Creates a new instance of a runtimes cache. /// - /// `max_runtime_instances` specifies the number of runtime instances preserved in an in-memory - /// cache. + /// `max_runtime_instances` specifies the number of instances per runtime preserved in an + /// in-memory cache. /// /// `cache_path` allows to specify an optional directory where the executor can store files /// for caching. - pub fn new(max_runtime_instances: usize, cache_path: Option) -> RuntimeCache { - RuntimeCache { runtimes: Default::default(), max_runtime_instances, cache_path } + /// + /// `runtime_cache_size` specifies the number of different runtimes versions preserved in an + /// in-memory cache. + pub fn new( + max_runtime_instances: usize, + cache_path: Option, + runtime_cache_size: u8, + ) -> RuntimeCache { + RuntimeCache { + runtimes: Mutex::new(LruCache::new(runtime_cache_size.into())), + max_runtime_instances, + cache_path, + } } /// Prepares a WASM module instance and executes given function for it. @@ -221,71 +235,55 @@ impl RuntimeCache { let code_hash = &runtime_code.hash; let heap_pages = runtime_code.heap_pages.unwrap_or(default_heap_pages); + let versioned_runtime_id = + VersionedRuntimeId { code_hash: code_hash.clone(), heap_pages, wasm_method }; + let mut runtimes = self.runtimes.lock(); // this must be released prior to calling f - let pos = runtimes.iter().position(|r| { - r.as_ref().map_or(false, |r| { - r.wasm_method == wasm_method && - r.code_hash == *code_hash && - r.heap_pages == heap_pages - }) - }); + let versioned_runtime = if let Some(versioned_runtime) = runtimes.get(&versioned_runtime_id) + { + versioned_runtime.clone() + } else { + let code = runtime_code.fetch_runtime_code().ok_or(WasmError::CodeNotFound)?; + + let time = std::time::Instant::now(); + + let result = create_versioned_wasm_runtime( + &code, + ext, + wasm_method, + heap_pages, + host_functions.into(), + allow_missing_func_imports, + self.max_runtime_instances, + self.cache_path.as_deref(), + ); + + match result { + Ok(ref result) => { + log::debug!( + target: "wasm-runtime", + "Prepared new runtime version {:?} in {} ms.", + result.version, + time.elapsed().as_millis(), + ); + }, + Err(ref err) => { + log::warn!(target: "wasm-runtime", "Cannot create a runtime: {:?}", err); + }, + } - let runtime = match pos { - Some(n) => runtimes[n] - .clone() - .expect("`position` only returns `Some` for entries that are `Some`"), - None => { - let code = runtime_code.fetch_runtime_code().ok_or(WasmError::CodeNotFound)?; - - let time = std::time::Instant::now(); - - let result = create_versioned_wasm_runtime( - &code, - code_hash.clone(), - ext, - wasm_method, - heap_pages, - host_functions.into(), - allow_missing_func_imports, - self.max_runtime_instances, - self.cache_path.as_deref(), - ); - - match result { - Ok(ref result) => { - log::debug!( - target: "wasm-runtime", - "Prepared new runtime version {:?} in {} ms.", - result.version, - time.elapsed().as_millis(), - ); - }, - Err(ref err) => { - log::warn!(target: "wasm-runtime", "Cannot create a runtime: {:?}", err); - }, - } + let versioned_runtime = Arc::new(result?); - Arc::new(result?) - }, + // Save new versioned wasm runtime in cache + runtimes.put(versioned_runtime_id, versioned_runtime.clone()); + + versioned_runtime }; - // Rearrange runtimes by last recently used. - match pos { - Some(0) => {}, - Some(n) => - for i in (1..n + 1).rev() { - runtimes.swap(i, i - 1); - }, - None => { - runtimes[MAX_RUNTIMES - 1] = Some(runtime.clone()); - for i in (1..MAX_RUNTIMES).rev() { - runtimes.swap(i, i - 1); - } - }, - } + // Lock must be released prior to calling f drop(runtimes); - Ok(runtime.with_instance(ext, f)) + Ok(versioned_runtime.with_instance(ext, f)) } } @@ -396,7 +394,6 @@ pub fn read_embedded_version(blob: &RuntimeBlob) -> Result, ext: &mut dyn Externalities, wasm_method: WasmExecutionMethod, heap_pages: u64, @@ -449,7 +446,7 @@ fn create_versioned_wasm_runtime( let mut instances = Vec::with_capacity(max_instances); instances.resize_with(max_instances, || Mutex::new(None)); - Ok(VersionedRuntime { code_hash, module: runtime, version, heap_pages, wasm_method, instances }) + Ok(VersionedRuntime { module: runtime, version, instances: Arc::new(instances) }) } #[cfg(test)] diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 7d15ce4704ab4..9f56424daf2f5 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -360,6 +360,7 @@ mod tests { WasmExecutionMethod::Interpreted, Some(128), 1, + 2, ); let overrides = crate::client::wasm_override::dummy_overrides(); diff --git a/client/service/src/client/wasm_override.rs b/client/service/src/client/wasm_override.rs index ba3f2855fc7a5..88b2c3895b026 100644 --- a/client/service/src/client/wasm_override.rs +++ b/client/service/src/client/wasm_override.rs @@ -282,6 +282,7 @@ mod tests { WasmExecutionMethod::Interpreted, Some(128), 1, + 2, ); let bytes = substrate_test_runtime::wasm_binary_unwrap(); let dir = tempfile::tempdir().expect("Create a temporary directory"); @@ -295,6 +296,7 @@ mod tests { WasmExecutionMethod::Interpreted, Some(128), 1, + 2, ); let version = WasmOverride::runtime_version( diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 0552baf5c209f..61ef8233f8e37 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -132,6 +132,8 @@ pub struct Configuration { pub base_path: Option, /// Configuration of the output format that the informant uses. pub informant_output_format: sc_informant::OutputFormat, + /// Maximum number of different runtime versions that can be cached. + pub runtime_cache_size: u8, } /// Type for tasks spawned by the executor. diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index d5e23d319e83e..286d819a6ce5e 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -72,7 +72,12 @@ impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { } fn executor() -> sc_executor::NativeElseWasmExecutor { - sc_executor::NativeElseWasmExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None, 8) + sc_executor::NativeElseWasmExecutor::new( + sc_executor::WasmExecutionMethod::Interpreted, + None, + 8, + 2, + ) } fn construct_block( diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index c44a5cdb97431..7033001db43c4 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -261,6 +261,7 @@ fn node_config< announce_block: true, base_path: Some(BasePath::new(root)), informant_output_format: Default::default(), + runtime_cache_size: 2, } } diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index e32290b12a599..21dfd456b1a1a 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -210,6 +210,7 @@ fn record_proof_works() { WasmExecutionMethod::Interpreted, None, 8, + 2, ); execution_proof_check_on_trie_backend( &backend, diff --git a/primitives/runtime-interface/test/src/lib.rs b/primitives/runtime-interface/test/src/lib.rs index 1749cc4853672..f64b743364278 100644 --- a/primitives/runtime-interface/test/src/lib.rs +++ b/primitives/runtime-interface/test/src/lib.rs @@ -48,6 +48,7 @@ fn call_wasm_method_with_result( host_functions, 8, None, + 2, ); executor .uncached_call( diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 2d1cb4bbc66a2..96f3c9898395d 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -283,7 +283,7 @@ impl Backend: sc_client_api::backend::Backend + 'static, { let executor = executor.into().unwrap_or_else(|| { - NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8) + NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2) }); let executor = LocalCallExecutor::new( self.backend.clone(), diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index 2948e918cdf8b..a5d1e1966e307 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -287,5 +287,10 @@ pub fn new() -> Client { /// Create a new native executor. pub fn new_native_executor() -> sc_executor::NativeElseWasmExecutor { - sc_executor::NativeElseWasmExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None, 8) + sc_executor::NativeElseWasmExecutor::new( + sc_executor::WasmExecutionMethod::Interpreted, + None, + 8, + 2, + ) } diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 165fe0355628e..0c72c083baae2 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -342,7 +342,7 @@ mod tests { } fn executor() -> NativeElseWasmExecutor { - NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8) + NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2) } fn new_test_ext() -> TestExternalities { diff --git a/test-utils/test-runner/src/client.rs b/test-utils/test-runner/src/client.rs index c68a33056c163..21039d3bc4b1b 100644 --- a/test-utils/test-runner/src/client.rs +++ b/test-utils/test-runner/src/client.rs @@ -111,6 +111,7 @@ where config.wasm_method, config.default_heap_pages, config.max_runtime_instances, + config.runtime_cache_size, ); let (client, backend, keystore, mut task_manager) = diff --git a/test-utils/test-runner/src/utils.rs b/test-utils/test-runner/src/utils.rs index a4c45c25f969b..4b44d12e1ed4c 100644 --- a/test-utils/test-runner/src/utils.rs +++ b/test-utils/test-runner/src/utils.rs @@ -113,5 +113,6 @@ pub fn default_config(tokio_handle: Handle, mut chain_spec: Box) keep_blocks: KeepBlocks::All, state_pruning: Default::default(), transaction_storage: TransactionStorageMode::BlockBody, + runtime_cache_size: 2, } } diff --git a/utils/frame/benchmarking-cli/src/command.rs b/utils/frame/benchmarking-cli/src/command.rs index 48d05dd8dda9c..2a0429b279083 100644 --- a/utils/frame/benchmarking-cli/src/command.rs +++ b/utils/frame/benchmarking-cli/src/command.rs @@ -137,6 +137,7 @@ impl BenchmarkCmd { wasm_method, self.heap_pages, 2, // The runtime instances cache size. + 2, // The runtime cache size ); let extensions = || -> Extensions { diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 8ea2e39297a95..3872f84a62a4b 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -678,8 +678,14 @@ pub(crate) fn build_executor( let wasm_method = shared.wasm_method; let heap_pages = shared.heap_pages.or(config.default_heap_pages); let max_runtime_instances = config.max_runtime_instances; + let runtime_cache_size = config.runtime_cache_size; - NativeElseWasmExecutor::::new(wasm_method.into(), heap_pages, max_runtime_instances) + NativeElseWasmExecutor::::new( + wasm_method.into(), + heap_pages, + max_runtime_instances, + runtime_cache_size, + ) } /// Execute the given `method` and `data` on top of `ext`, returning the results (encoded) and the From 0064dd52f8f81615b5c2c45dff6409cb77c82bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 9 Dec 2021 20:42:43 +0100 Subject: [PATCH 0323/1472] Prometheus: Use correct chain id (#10457) * Prometheus: Use correct chain id * FMT --- client/cli/src/commands/run_cmd.rs | 8 ++++++-- client/cli/src/config.rs | 9 +++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 78ea4b1276b23..661b3ff382330 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -365,7 +365,11 @@ impl CliConfiguration for RunCmd { Ok(self.shared_params.dev || self.force_authoring) } - fn prometheus_config(&self, default_listen_port: u16) -> Result> { + fn prometheus_config( + &self, + default_listen_port: u16, + chain_spec: &Box, + ) -> Result> { Ok(if self.no_prometheus { None } else { @@ -377,7 +381,7 @@ impl CliConfiguration for RunCmd { interface.into(), self.prometheus_port.unwrap_or(default_listen_port), ), - self.shared_params.chain_id(self.shared_params.dev), + chain_spec.id().into(), )) }) } diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 1fda07d2571fb..6d5ac71182812 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -368,7 +368,11 @@ pub trait CliConfiguration: Sized { /// Get the prometheus configuration (`None` if disabled) /// /// By default this is `None`. - fn prometheus_config(&self, _default_listen_port: u16) -> Result> { + fn prometheus_config( + &self, + _default_listen_port: u16, + _chain_spec: &Box, + ) -> Result> { Ok(None) } @@ -527,7 +531,8 @@ pub trait CliConfiguration: Sized { rpc_cors: self.rpc_cors(is_dev)?, rpc_max_payload: self.rpc_max_payload()?, ws_max_out_buffer_capacity: self.ws_max_out_buffer_capacity()?, - prometheus_config: self.prometheus_config(DCV::prometheus_listen_port())?, + prometheus_config: self + .prometheus_config(DCV::prometheus_listen_port(), &chain_spec)?, telemetry_endpoints, default_heap_pages: self.default_heap_pages()?, offchain_worker: self.offchain_worker(&role)?, From 28ae4ba635527df4fdaaf9a8e8897140eaa1f59d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 9 Dec 2021 20:43:46 +0100 Subject: [PATCH 0324/1472] Remove simnet from CI (#10456) --- .gitlab-ci.yml | 97 -------------- simnet_tests/README.md | 39 ------ .../configs/default_local_testnet.toml | 14 -- simnet_tests/run_tests.sh | 126 ------------------ simnet_tests/tests/long/002-loadtest.feature | 5 - .../tests/quick/001-smoketest.feature | 16 --- 6 files changed, 297 deletions(-) delete mode 100644 simnet_tests/README.md delete mode 100644 simnet_tests/configs/default_local_testnet.toml delete mode 100755 simnet_tests/run_tests.sh delete mode 100644 simnet_tests/tests/long/002-loadtest.feature delete mode 100644 simnet_tests/tests/quick/001-smoketest.feature diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f4391cf7d312c..7af3675f07718 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,7 +45,6 @@ variables: &default-vars VAULT_SERVER_URL: "https://vault.parity-mgmt-vault.parity.io" VAULT_AUTH_PATH: "gitlab-parity-io-jwt" VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" - SIMNET_FEATURES_PATH: "simnet_tests/tests" PIPELINE_SCRIPTS_TAG: "v0.4" default: @@ -641,18 +640,6 @@ build-linux-substrate: - printf '\n# building node-template\n\n' - ./.maintain/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz - -#Build binary for simnet quick tests. -build-linux-substrate-simnet: - stage: build - <<: *collect-artifacts-short - <<: *docker-env - <<: *test-refs-no-trigger-prs-only - before_script: - - mkdir -p ./artifacts/substrate/ - script: - - *build-linux-substrate-script - build-linux-subkey: &build-subkey stage: build <<: *collect-artifacts @@ -739,7 +726,6 @@ build-rustdoc: - buildah push --format=v2s2 "$IMAGE_NAME:latest" after_script: - buildah logout --all - # pass artifacts to the trigger-simnet job - echo "SUBSTRATE_IMAGE_NAME=${IMAGE_NAME}" | tee -a ./artifacts/$PRODUCT/build.env - IMAGE_TAG="$(cat ./artifacts/$PRODUCT/VERSION)" - echo "SUBSTRATE_IMAGE_TAG=${IMAGE_TAG}" | tee -a ./artifacts/$PRODUCT/build.env @@ -755,30 +741,6 @@ publish-docker-substrate: variables: <<: *docker-build-vars PRODUCT: substrate - artifacts: - reports: - # this artifact is used in trigger-simnet job - # https://docs.gitlab.com/ee/ci/multi_project_pipelines.html#with-variable-inheritance - dotenv: ./artifacts/substrate/build.env - -#publish artifact for quick simnet tests -publish-docker-substrate-simnet: - stage: publish - <<: *build-push-docker-image - <<: *test-refs-no-trigger-prs-only - needs: - - job: build-linux-substrate-simnet - artifacts: true - variables: - <<: *default-vars - GIT_STRATEGY: none - DOCKERFILE: $PRODUCT.Dockerfile - PRODUCT: substrate - IMAGE_NAME: docker.io/paritypr/$PRODUCT - artifacts: - reports: - # this artifact is used in simnet-tests-quick job - dotenv: ./artifacts/substrate/build.env publish-docker-subkey: stage: publish @@ -940,62 +902,3 @@ deploy-prometheus-alerting-rules: changes: - .gitlab-ci.yml - .maintain/monitoring/**/* - -# Runs "quick" and "long" tests on nightly schedule and on commit / merge to master -# A "quick" test is a smoke test where basic check-expect tests run by -# checking values from metrics exposed by the app. -# A "long" test is the load testing where we send 50K transactions into the -# network and check if all completed successfully -simnet-tests: - stage: deploy - image: docker.io/paritytech/simnet:${SIMNET_REF} - <<: *kubernetes-env - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME == "master" - needs: - - job: publish-docker-substrate - # variables: - # `build.env` brings here `${SUBSTRATE_IMAGE_NAME}` and `${SUBSTRATE_IMAGE_TAG}` - # (`$VERSION` here, # i.e. `2643-0.8.29-5f689e0a-6b24dc54`). - # ${SIMNET_REF} is a gitlab variable - before_script: - - echo "Simnet Tests Config - docker.io/paritytech/simnet:${SIMNET_REF} - ${SUBSTRATE_IMAGE_NAME} ${SUBSTRATE_IMAGE_TAG}" - script: - - /home/nonroot/simnet/gurke/scripts/run-test-environment-manager.sh - --github-remote-dir="https://github.com/paritytech/substrate/tree/master/simnet_tests" - --config="simnet_tests/configs/default_local_testnet.toml" - --image="${SUBSTRATE_IMAGE_NAME}:${SUBSTRATE_IMAGE_TAG}" - retry: 2 - tags: - - substrate-simnet - -#run quick simnet-tests for each PR -simnet-tests-quick: - stage: deploy - image: docker.io/paritytech/simnet:${SIMNET_REF} - <<: *kubernetes-env - <<: *test-refs-no-trigger-prs-only - variables: - SIMNET_FEATURES: "${SIMNET_FEATURES_PATH}/quick" - needs: - - job: publish-docker-substrate-simnet - before_script: - - echo "Simnet Tests Config - docker.io/paritytech/simnet:${SIMNET_REF} - ${SUBSTRATE_IMAGE_NAME} ${SUBSTRATE_IMAGE_TAG}" - script: - - echo "Image=${SUBSTRATE_IMAGE_NAME}:${SUBSTRATE_IMAGE_TAG}" - - echo "Features=${SIMNET_FEATURES}" - - /home/nonroot/simnet/gurke/scripts/run-test-environment-manager.sh - --github-remote-dir="https://github.com/paritytech/substrate/tree/master/simnet_tests" - --config="simnet_tests/configs/default_local_testnet.toml" - --image="${SUBSTRATE_IMAGE_NAME}:${SUBSTRATE_IMAGE_TAG}" - --features="${SIMNET_FEATURES}" - tags: - - substrate-simnet - diff --git a/simnet_tests/README.md b/simnet_tests/README.md deleted file mode 100644 index cb1b13ae98505..0000000000000 --- a/simnet_tests/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Simulation tests, or high level integration tests. - - -_The content of this directory is meant to be used by Parity's private CI/CD -infrastructure with private tools. At the moment those tools are still early -stage of development and we don't when if / when they will available for -public use._ - - -## Content of this dir. - -`configs` dir contains config files in toml format that describe how to -configure the simulation network that you want to launch. - -`tests` dir contains [cucumber](https://cucumber.io/) files. Those are -Behavior-Driven Development test files that describe tests in plain English. -Under the hood there are assertions that specific metrics should have specific -values. - -At the moment we have 2 tests: `tests/quick/001-smoketest.feature` and -`tests/long/002-loadtest.feature` -The load test uses a JS script that we added to simnet image and it's launched -by this step in the cucumber file: -`Then launch 'node' with parameters '/usr/local/bin/sub-flood --finalization --url ws://localhost:11222'` - -`run_test.sh` is a script meant to ease up launching a test. -In order to use this script locally, you need to install -[gurke](https://github.com/paritytech/gurke) -This script also helps preparing the test environment. Once you have access to -a kubernetes cluster (meaning you can do `kubectl get pods`) you can run this -script with no arguments, like `./run_test.sh` and tests should run. -Kubernetes cluster can be local, spawned with -[kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) -or an instance living in the -[cloud](https://github.com/paritytech/gurke/blob/main/docs/How-to-setup-access-to-gke-k8s-cluster.md) - - -### [Here is link to barcamp presenation of simnet](https://www.crowdcast.io/e/ph49xu01) -### [Here is link to the simnet repo, hosted on private gitlab](https://gitlab.parity.io/parity/simnet/-/tree/master) diff --git a/simnet_tests/configs/default_local_testnet.toml b/simnet_tests/configs/default_local_testnet.toml deleted file mode 100644 index 066bd4c9e332f..0000000000000 --- a/simnet_tests/configs/default_local_testnet.toml +++ /dev/null @@ -1,14 +0,0 @@ -[settings] -bootnode-domain-name = "bootnode.{{get_env(name="NAMESPACE")}}.svc.cluster.local" - - -[settings.setup] -timeout = 300 - -[settings.defaults] -timeout = 300 - -[nodes] -alice = { extra-args = ["--alice"], validator = true } -bob = { extra-args = ["--bob"], validator = true } -charlie = { extra-args = ["--charlie"], validator = true } diff --git a/simnet_tests/run_tests.sh b/simnet_tests/run_tests.sh deleted file mode 100755 index 3b8ac8a71dadf..0000000000000 --- a/simnet_tests/run_tests.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/bin/bash - -### ARGS FOR THIS SCRIPT ### -# ./${SCRIPT_NAME} NAMESPACE IMAGE LOG_PATH FEATURES -# NAMESPACE the kubernetes namespace where the test will run -# IMAGE Substrate image used to spawn network -# LOG_PATH path to dir where to save logs from external JS script that is run as part -# of step in features file -# FEATURES directory containing cucumber files or single cucumber file that describes -# what to test. -# -# All args have default values, specify args to override -# e.g: ./${SCRIPT_NAME} test-name parity/substrate:latest logs quick - -set -eou pipefail -SCRIPT_NAME="$0" -SCRIPT_PATH=$(dirname "${SCRIPT_NAME}") # relative -SCRIPT_PATH=$(cd "${SCRIPT_PATH}" && pwd) # absolutized and normalized - -function random_string { - head -1 <(fold -w 30 <(tr -dc 'a-z0-9' < /dev/urandom)) - } - -# -### Script args -# - -NAMESPACE=${1:-gurke-"$(random_string)"-runtest} -IMAGE=${2:-"parity/substrate:latest"} -LOG_PATH=${3:-"${SCRIPT_PATH}/logs"} -FEATURES=${4:-"ALL"} - -mkdir -p "${SCRIPT_PATH}"/logs - -echo "Running tests in namespace: ${NAMESPACE}" -echo "Testing image: ${IMAGE}" -echo "Storing scripts logs to: ${LOG_PATH}" -echo "Using features files from: ${FEATURES}" - -# -### Script logic -# - -function forward_port { - # RUN_IN_CONTAINER is env var that is set in the dockerfile - # use the -v operator to explicitly test if a variable is set - if [[ ! -v RUN_IN_CONTAINER ]] ; then - if is_port_forward_running ; then - kill_previous_job - fi - fi - start_forwading_job -} - -FORWARD_GREP_FILTER='kubectl.*[p]ort-forward.*svc/rpc.*11222' - -function is_port_forward_running { - # shellcheck disable=SC2009 - ps aux | grep -qE "${FORWARD_GREP_FILTER}" -} - -function kill_previous_job { - # shellcheck disable=SC2009 - job_pid=$(ps aux | grep -E "${FORWARD_GREP_FILTER}" | awk '{ print $2 }') - echo "INFO Killed forwading port 9944 into bootnode" - kill "${job_pid}" -} - -function start_forwading_job { - kubectl -n "${NAMESPACE}" \ - expose pod bootnode \ - --name=rpc \ - --type=NodePort \ - --target-port=9944 \ - --port=9944 - kubectl -n "${NAMESPACE}" \ - port-forward svc/rpc 11222:9944 &> "${LOG_PATH}/forward-${NAMESPACE}.log" & - sleep 2 - echo "INFO Started forwading port 9944 into bootnode" -} - -function update_api { - echo "INFO: Updating Polkadot JS API" - pwd - cd "${SCRIPT_PATH}"/../../sub-flood/ - npm run build - cd - -} - -function run_test { - case "${FEATURES}" in - quick) - gurke test "${NAMESPACE}" "${SCRIPT_PATH}"/tests/quick --log-path "${LOG_PATH}" - ;; - long) - gurke test "${NAMESPACE}" "${SCRIPT_PATH}"/tests/long --log-path "${LOG_PATH}" - ;; - ALL ) - gurke test "${NAMESPACE}" "${SCRIPT_PATH}"/tests --log-path "${LOG_PATH}" - ;; - ??* ) - gurke test \ - "${NAMESPACE}" \ - "${SCRIPT_PATH}"/"${FEATURES}" \ - --log-path "${LOG_PATH}" - ;; - esac -} - - -export NAMESPACE="${NAMESPACE}" - -set -x # echo the commands to stdout -gurke spawn --config "${SCRIPT_PATH}"/configs/default_local_testnet.toml \ - -n "${NAMESPACE}" \ - --image "${IMAGE}" - -echo "INFO: Checking if pods launched correctly" -kubectl -n "${NAMESPACE}" get pods -o wide - -update_api - -forward_port -run_test - - diff --git a/simnet_tests/tests/long/002-loadtest.feature b/simnet_tests/tests/long/002-loadtest.feature deleted file mode 100644 index 67d108ea55416..0000000000000 --- a/simnet_tests/tests/long/002-loadtest.feature +++ /dev/null @@ -1,5 +0,0 @@ -Feature: LoadTesting - - Scenario: spawn 50k transactions and wait their finalization - Given a test network - Then launch 'node' with parameters '/usr/local/bin/sub-flood --finalization --url ws://localhost:11222' diff --git a/simnet_tests/tests/quick/001-smoketest.feature b/simnet_tests/tests/quick/001-smoketest.feature deleted file mode 100644 index a07041e4ea622..0000000000000 --- a/simnet_tests/tests/quick/001-smoketest.feature +++ /dev/null @@ -1,16 +0,0 @@ -Feature: Smoketest - - Scenario: Minimal Example - Given a test network - Then alice is up - And alice reports substrate_node_roles is 4 - And alice reports substrate_sub_libp2p_is_major_syncing is 0 - When alice's best block should be above 30 - Then alice reports block height is greater than 30 - And alice reports peers count is at least 2 - Then bob is up - And bob reports block height is greater than 30 - And bob reports peers count is at least 2 - Then charlie is up - And charlie reports block height is greater than 30 - And charlie reports peers count is at least 2 From a634b44f504e57c33797e831d8e54ca97816ffed Mon Sep 17 00:00:00 2001 From: Andreas Doerr Date: Fri, 10 Dec 2021 09:33:23 +0100 Subject: [PATCH 0325/1472] BEEFY update CODEOWNERS (#10460) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BEEFY update CODEOWNERS Remove myself as `BEEFY` code owner. New code owner needs to be decided upon. * Update docs/CODEOWNERS * Update docs/CODEOWNERS * Update docs/CODEOWNERS Co-authored-by: Bastian Köcher --- docs/CODEOWNERS | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index ee6382b72f1b2..42d25a0a228f7 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -40,12 +40,6 @@ /client/consensus/pow/ @sorpaas /primitives/consensus/pow/ @sorpaas -# BEEFY -/client/beefy/ @adoerr -/frame/beefy/ @adoerr -/frame/beefy-mmr/ @adoerr -/primitives/beefy/ @adoerr - # Contracts /frame/contracts/ @athei From be75e554aa14774804bc949b2d77f424b74e23fd Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 10 Dec 2021 20:31:04 +0900 Subject: [PATCH 0326/1472] Automatically unsubscribe storage listeners when they're dropped (RCP node memory leak fix) (#10454) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Automatically unsubscribe storage listeners when they're dropped * Fix tests' compilation in `sc-client-api` * Add an extra test * Align to review comments; cleanups * Update client/api/src/notifications.rs * FMT Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- client/api/src/notifications.rs | 229 ++++++++++++++++++++++++-------- 1 file changed, 174 insertions(+), 55 deletions(-) diff --git a/client/api/src/notifications.rs b/client/api/src/notifications.rs index 9565fd673acf4..88a709beb1f0b 100644 --- a/client/api/src/notifications.rs +++ b/client/api/src/notifications.rs @@ -20,13 +20,20 @@ use std::{ collections::{HashMap, HashSet}, - sync::Arc, + pin::Pin, + sync::{Arc, Weak}, + task::Poll, }; use fnv::{FnvHashMap, FnvHashSet}; +use futures::Stream; +use parking_lot::Mutex; use prometheus_endpoint::{register, CounterVec, Opts, Registry, U64}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; -use sp_core::storage::{StorageData, StorageKey}; +use sp_core::{ + hexdisplay::HexDisplay, + storage::{StorageData, StorageKey}, +}; use sp_runtime::traits::Block as BlockT; /// Storage change set @@ -34,8 +41,8 @@ use sp_runtime::traits::Block as BlockT; pub struct StorageChangeSet { changes: Arc)>>, child_changes: Arc)>)>>, - filter: Option>, - child_filters: Option>>>, + filter: Keys, + child_filters: ChildKeys, } impl StorageChangeSet { @@ -74,7 +81,46 @@ impl StorageChangeSet { } /// Type that implements `futures::Stream` of storage change events. -pub type StorageEventStream = TracingUnboundedReceiver<(H, StorageChangeSet)>; +pub struct StorageEventStream { + rx: TracingUnboundedReceiver<(H, StorageChangeSet)>, + storage_notifications: Weak>>, + was_triggered: bool, + id: u64, +} + +impl Stream for StorageEventStream { + type Item = as Stream>::Item; + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + let result = Stream::poll_next(Pin::new(&mut self.rx), cx); + if result.is_ready() { + self.was_triggered = true; + } + result + } +} + +impl Drop for StorageEventStream { + fn drop(&mut self) { + if let Some(storage_notifications) = self.storage_notifications.upgrade() { + if let Some((keys, child_keys)) = + storage_notifications.lock().remove_subscriber(self.id) + { + if !self.was_triggered { + log::trace!( + target: "storage_notifications", + "Listener was never triggered: id={}, keys={:?}, child_keys={:?}", + self.id, + PrintKeys(&keys), + PrintChildKeys(&child_keys), + ); + } + } + } + } +} type SubscriberId = u64; @@ -82,7 +128,13 @@ type SubscribersGauge = CounterVec; /// Manages storage listeners. #[derive(Debug)] -pub struct StorageNotifications { +pub struct StorageNotifications(Arc>>); + +type Keys = Option>; +type ChildKeys = Option>>>; + +#[derive(Debug)] +struct StorageNotificationsImpl { metrics: Option, next_id: SubscriberId, wildcard_listeners: FnvHashSet, @@ -93,15 +145,17 @@ pub struct StorageNotifications { >, sinks: FnvHashMap< SubscriberId, - ( - TracingUnboundedSender<(Block::Hash, StorageChangeSet)>, - Option>, - Option>>>, - ), + (TracingUnboundedSender<(Hash, StorageChangeSet)>, Keys, ChildKeys), >, } impl Default for StorageNotifications { + fn default() -> Self { + Self(Default::default()) + } +} + +impl Default for StorageNotificationsImpl { fn default() -> Self { Self { metrics: Default::default(), @@ -114,10 +168,68 @@ impl Default for StorageNotifications { } } +struct PrintKeys<'a>(&'a Keys); +impl<'a> std::fmt::Debug for PrintKeys<'a> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(keys) = self.0 { + fmt.debug_list().entries(keys.iter().map(HexDisplay::from)).finish() + } else { + write!(fmt, "None") + } + } +} + +struct PrintChildKeys<'a>(&'a ChildKeys); +impl<'a> std::fmt::Debug for PrintChildKeys<'a> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(map) = self.0 { + fmt.debug_map() + .entries(map.iter().map(|(key, values)| (HexDisplay::from(key), PrintKeys(values)))) + .finish() + } else { + write!(fmt, "None") + } + } +} + impl StorageNotifications { /// Initialize a new StorageNotifications /// optionally pass a prometheus registry to send subscriber metrics to pub fn new(prometheus_registry: Option) -> Self { + StorageNotifications(Arc::new(Mutex::new(StorageNotificationsImpl::new( + prometheus_registry, + )))) + } + + /// Trigger notification to all listeners. + /// + /// Note the changes are going to be filtered by listener's filter key. + /// In fact no event might be sent if clients are not interested in the changes. + pub fn trigger( + &mut self, + hash: &Block::Hash, + changeset: impl Iterator, Option>)>, + child_changeset: impl Iterator< + Item = (Vec, impl Iterator, Option>)>), + >, + ) { + self.0.lock().trigger(hash, changeset, child_changeset); + } + + /// Start listening for particular storage keys. + pub fn listen( + &mut self, + filter_keys: Option<&[StorageKey]>, + filter_child_keys: Option<&[(StorageKey, Option>)]>, + ) -> StorageEventStream { + let (id, rx) = self.0.lock().listen(filter_keys, filter_child_keys); + let storage_notifications = Arc::downgrade(&self.0); + StorageEventStream { rx, storage_notifications, was_triggered: false, id } + } +} + +impl StorageNotificationsImpl { + fn new(prometheus_registry: Option) -> Self { let metrics = prometheus_registry.and_then(|r| { CounterVec::new( Opts::new( @@ -130,7 +242,7 @@ impl StorageNotifications { .ok() }); - StorageNotifications { + StorageNotificationsImpl { metrics, next_id: Default::default(), wildcard_listeners: Default::default(), @@ -139,18 +251,16 @@ impl StorageNotifications { sinks: Default::default(), } } - /// Trigger notification to all listeners. - /// - /// Note the changes are going to be filtered by listener's filter key. - /// In fact no event might be sent if clients are not interested in the changes. - pub fn trigger( + fn trigger( &mut self, - hash: &Block::Hash, + hash: &Hash, changeset: impl Iterator, Option>)>, child_changeset: impl Iterator< Item = (Vec, impl Iterator, Option>)>), >, - ) { + ) where + Hash: Clone, + { let has_wildcard = !self.wildcard_listeners.is_empty(); // early exit if no listeners @@ -244,7 +354,7 @@ impl StorageNotifications { fn remove_subscriber_from( subscriber: &SubscriberId, - filters: &Option>, + filters: &Keys, listeners: &mut HashMap>, wildcards: &mut FnvHashSet, ) { @@ -269,34 +379,35 @@ impl StorageNotifications { } } - fn remove_subscriber(&mut self, subscriber: SubscriberId) { - if let Some((_, filters, child_filters)) = self.sinks.remove(&subscriber) { - Self::remove_subscriber_from( - &subscriber, - &filters, - &mut self.listeners, - &mut self.wildcard_listeners, - ); - if let Some(child_filters) = child_filters.as_ref() { - for (c_key, filters) in child_filters { - if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) { - Self::remove_subscriber_from( - &subscriber, - &filters, - &mut *listeners, - &mut *wildcards, - ); - - if listeners.is_empty() && wildcards.is_empty() { - self.child_listeners.remove(&c_key); - } + fn remove_subscriber(&mut self, subscriber: SubscriberId) -> Option<(Keys, ChildKeys)> { + let (_, filters, child_filters) = self.sinks.remove(&subscriber)?; + Self::remove_subscriber_from( + &subscriber, + &filters, + &mut self.listeners, + &mut self.wildcard_listeners, + ); + if let Some(child_filters) = child_filters.as_ref() { + for (c_key, filters) in child_filters { + if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) { + Self::remove_subscriber_from( + &subscriber, + &filters, + &mut *listeners, + &mut *wildcards, + ); + + if listeners.is_empty() && wildcards.is_empty() { + self.child_listeners.remove(&c_key); } } } - if let Some(m) = self.metrics.as_ref() { - m.with_label_values(&[&"removed"]).inc(); - } } + if let Some(m) = self.metrics.as_ref() { + m.with_label_values(&[&"removed"]).inc(); + } + + Some((filters, child_filters)) } fn listen_from( @@ -304,7 +415,7 @@ impl StorageNotifications { filter_keys: &Option>, listeners: &mut HashMap>, wildcards: &mut FnvHashSet, - ) -> Option> { + ) -> Keys { match filter_keys { None => { wildcards.insert(current_id); @@ -325,12 +436,11 @@ impl StorageNotifications { } } - /// Start listening for particular storage keys. - pub fn listen( + fn listen( &mut self, filter_keys: Option<&[StorageKey]>, filter_child_keys: Option<&[(StorageKey, Option>)]>, - ) -> StorageEventStream { + ) -> (u64, TracingUnboundedReceiver<(Hash, StorageChangeSet)>) { self.next_id += 1; let current_id = self.next_id; @@ -364,7 +474,7 @@ impl StorageNotifications { m.with_label_values(&[&"added"]).inc(); } - rx + (current_id, rx) } } @@ -517,9 +627,9 @@ mod tests { let _recv3 = futures::executor::block_on_stream(notifications.listen(None, None)); let _recv4 = futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter))); - assert_eq!(notifications.listeners.len(), 2); - assert_eq!(notifications.wildcard_listeners.len(), 2); - assert_eq!(notifications.child_listeners.len(), 1); + assert_eq!(notifications.0.lock().listeners.len(), 2); + assert_eq!(notifications.0.lock().wildcard_listeners.len(), 2); + assert_eq!(notifications.0.lock().child_listeners.len(), 1); } // when @@ -528,9 +638,18 @@ mod tests { notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset); // then - assert_eq!(notifications.listeners.len(), 0); - assert_eq!(notifications.wildcard_listeners.len(), 0); - assert_eq!(notifications.child_listeners.len(), 0); + assert_eq!(notifications.0.lock().listeners.len(), 0); + assert_eq!(notifications.0.lock().wildcard_listeners.len(), 0); + assert_eq!(notifications.0.lock().child_listeners.len(), 0); + } + + #[test] + fn should_cleanup_subscriber_if_stream_is_dropped() { + let mut notifications = StorageNotifications::::default(); + let stream = notifications.listen(None, None); + assert_eq!(notifications.0.lock().sinks.len(), 1); + std::mem::drop(stream); + assert_eq!(notifications.0.lock().sinks.len(), 0); } #[test] From 5f49f1498a44614e3fb48394c99d4e8a253e910f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Fri, 10 Dec 2021 15:26:17 +0100 Subject: [PATCH 0327/1472] Make sure that weight for loading code into the sandbox is accounted for (#10448) --- frame/contracts/src/benchmarking/code.rs | 23 +- frame/contracts/src/benchmarking/mod.rs | 41 +- frame/contracts/src/tests.rs | 2 +- frame/contracts/src/wasm/code_cache.rs | 20 +- frame/contracts/src/weights.rs | 1192 +++++++++++----------- 5 files changed, 653 insertions(+), 625 deletions(-) diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 5dac8a84ace8a..49df1c3838216 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -41,6 +41,14 @@ use sp_sandbox::{ }; use sp_std::{borrow::ToOwned, prelude::*}; +/// The location where to put the genrated code. +pub enum Location { + /// Generate all code into the `call` exported function. + Call, + /// Generate all code into the `deploy` exported function. + Deploy, +} + /// Pass to `create_code` in order to create a compiled `WasmModule`. /// /// This exists to have a more declarative way to describe a wasm module than to use @@ -308,7 +316,8 @@ where /// Creates a wasm module of `target_bytes` size. Used to benchmark the performance of /// `instantiate_with_code` for different sizes of wasm modules. The generated module maximizes /// instrumentation runtime by nesting blocks as deeply as possible given the byte budget. - pub fn sized(target_bytes: u32) -> Self { + /// `code_location`: Whether to place the code into `deploy` or `call`. + pub fn sized(target_bytes: u32, code_location: Location) -> Self { use self::elements::Instruction::{End, I32Const, If, Return}; // Base size of a contract is 63 bytes and each expansion adds 6 bytes. // We do one expansion less to account for the code section and function body @@ -317,12 +326,14 @@ where // because of the maximum code size that is enforced by `instantiate_with_code`. let expansions = (target_bytes.saturating_sub(63) / 6).saturating_sub(1); const EXPANSION: [Instruction; 4] = [I32Const(0), If(BlockType::NoResult), Return, End]; - ModuleDefinition { - call_body: Some(body::repeated(expansions, &EXPANSION)), - memory: Some(ImportedMemory::max::()), - ..Default::default() + let mut module = + ModuleDefinition { memory: Some(ImportedMemory::max::()), ..Default::default() }; + let body = Some(body::repeated(expansions, &EXPANSION)); + match code_location { + Location::Call => module.call_body = body, + Location::Deploy => module.deploy_body = body, } - .into() + module.into() } /// Creates a wasm module that calls the imported function named `getter_name` `repeat` diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 884fddb6f907f..ae39d1feca114 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -25,7 +25,7 @@ mod sandbox; use self::{ code::{ body::{self, DynInstr::*}, - DataSegment, ImportedFunction, ImportedMemory, ModuleDefinition, WasmModule, + DataSegment, ImportedFunction, ImportedMemory, Location, ModuleDefinition, WasmModule, }, sandbox::Sandbox, }; @@ -229,9 +229,9 @@ benchmarks! { // This benchmarks the additional weight that is charged when a contract is executed the // first time after a new schedule was deployed: For every new schedule a contract needs // to re-run the instrumentation once. - instrument { + reinstrument { let c in 0 .. T::Schedule::get().limits.code_len / 1024; - let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024); + let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024, Location::Call); Contracts::::store_code_raw(code, whitelisted_caller())?; let schedule = T::Schedule::get(); let mut gas_meter = GasMeter::new(Weight::MAX); @@ -240,21 +240,28 @@ benchmarks! { Contracts::::reinstrument_module(&mut module, &schedule)?; } - // The weight of loading and decoding of a contract's code per kilobyte. - code_load { + // This benchmarks the overhead of loading a code of size `c` kb from storage and into + // the sandbox. This does **not** include the actual execution for which the gas meter + // is responsible. This is achieved by generating all code to the `deploy` function + // which is in the wasm module but not executed on `call`. + // The results are supposed to be used as `call_with_code_kb(c) - call_with_code_kb(0)`. + call_with_code_kb { let c in 0 .. T::Schedule::get().limits.code_len / 1024; - let WasmModule { code, hash, .. } = WasmModule::::dummy_with_bytes(c * 1024); - Contracts::::store_code_raw(code, whitelisted_caller())?; - let schedule = T::Schedule::get(); - let mut gas_meter = GasMeter::new(Weight::MAX); - }: { - >::from_storage(hash, &schedule, &mut gas_meter)?; - } + let instance = Contract::::with_caller( + whitelisted_caller(), WasmModule::sized(c * 1024, Location::Deploy), vec![], + )?; + let value = T::Currency::minimum_balance(); + let origin = RawOrigin::Signed(instance.caller.clone()); + let callee = instance.addr.clone(); + }: call(origin, callee, value, Weight::MAX, None, vec![]) // This constructs a contract that is maximal expensive to instrument. // It creates a maximum number of metering blocks per byte. // The size of the salt influences the runtime because is is hashed in order to - // determine the contract address. + // determine the contract address. All code is generated to the `call` function so that + // we don't benchmark the actual execution of this code but merely what it takes to load + // a code of that size into the sandbox. + // // `c`: Size of the code in kilobytes. // `s`: Size of the salt in kilobytes. // @@ -269,7 +276,7 @@ benchmarks! { let value = T::Currency::minimum_balance(); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); - let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024); + let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024, Location::Call); let origin = RawOrigin::Signed(caller.clone()); let addr = Contracts::::contract_address(&caller, &hash, &salt); }: _(origin, value, Weight::MAX, None, code, vec![], salt) @@ -316,7 +323,9 @@ benchmarks! { // The size of the data has no influence on the costs of this extrinsic as long as the contract // won't call `seal_input` in its constructor to copy the data to contract memory. // The dummy contract used here does not do this. The costs for the data copy is billed as - // part of `seal_input`. + // part of `seal_input`. The costs for invoking a contract of a specific size are not part + // of this benchmark because we cannot know the size of the contract when issuing a call + // transaction. See `invoke_per_code_kb` for this. call { let data = vec![42u8; 1024]; let instance = Contract::::with_caller( @@ -353,7 +362,7 @@ benchmarks! { let c in 0 .. Perbill::from_percent(50).mul_ceil(T::Schedule::get().limits.code_len / 1024); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); - let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024); + let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024, Location::Call); let origin = RawOrigin::Signed(caller.clone()); }: _(origin, code, None) verify { diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 1554d1230089e..1078a7e73352d 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -1903,7 +1903,7 @@ fn reinstrument_does_charge() { assert!(result2.gas_consumed > result1.gas_consumed); assert_eq!( result2.gas_consumed, - result1.gas_consumed + ::WeightInfo::instrument(code_len / 1024), + result1.gas_consumed + ::WeightInfo::reinstrument(code_len / 1024), ); }); } diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 823d6ed34a671..2cff043f64efa 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -158,7 +158,7 @@ where if prefab_module.instruction_weights_version < schedule.instruction_weights.version { // The instruction weights have changed. // We need to re-instrument the code with the new instruction weights. - gas_meter.charge(CodeToken::Instrument(estimate_code_size::, _>( + gas_meter.charge(CodeToken::Reinstrument(estimate_code_size::, _>( &code_hash, )?))?; reinstrument(&mut prefab_module, schedule)?; @@ -201,9 +201,9 @@ where #[cfg_attr(test, derive(Debug, PartialEq, Eq))] #[derive(Clone, Copy)] enum CodeToken { - /// Weight for instrumenting a contract contract of the supplied size in bytes. - Instrument(u32), - /// Weight for loading a contract per kilobyte. + /// Weight for reinstrumenting a contract contract of the supplied size in bytes. + Reinstrument(u32), + /// Weight for loading a contract per byte. Load(u32), } @@ -211,14 +211,14 @@ impl Token for CodeToken { fn weight(&self) -> Weight { use self::CodeToken::*; // In case of `Load` we already covered the general costs of - // accessing the storage but still need to account for the actual size of the + // calling the storage but still need to account for the actual size of the // contract code. This is why we substract `T::*::(0)`. We need to do this at this - // point because when charging the general weight we do not know the size of - // the contract. + // point because when charging the general weight for calling the contract we not know the + // size of the contract. match *self { - Instrument(len) => T::WeightInfo::instrument(len / 1024), - Load(len) => - T::WeightInfo::code_load(len / 1024).saturating_sub(T::WeightInfo::code_load(0)), + Reinstrument(len) => T::WeightInfo::reinstrument(len / 1024), + Load(len) => T::WeightInfo::call_with_code_kb(len / 1024) + .saturating_sub(T::WeightInfo::call_with_code_kb(0)), } } } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 8a78a7f289a62..5f61c1e4a3462 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -47,8 +47,8 @@ pub trait WeightInfo { fn on_initialize() -> Weight; fn on_initialize_per_trie_key(k: u32, ) -> Weight; fn on_initialize_per_queue_item(q: u32, ) -> Weight; - fn instrument(c: u32, ) -> Weight; - fn code_load(c: u32, ) -> Weight; + fn reinstrument(c: u32, ) -> Weight; + fn call_with_code_kb(c: u32, ) -> Weight; fn instantiate_with_code(c: u32, s: u32, ) -> Weight; fn instantiate(s: u32, ) -> Weight; fn call() -> Weight; @@ -150,41 +150,45 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (2_854_000 as Weight) + (2_720_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((2_190_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((2_208_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (101_551_000 as Weight) + (95_834_000 as Weight) // Standard Error: 2_000 - .saturating_add((292_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((317_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) - fn instrument(c: u32, ) -> Weight { - (33_350_000 as Weight) - // Standard Error: 106_000 - .saturating_add((91_098_000 as Weight).saturating_mul(c as Weight)) + fn reinstrument(c: u32, ) -> Weight { + (17_177_000 as Weight) + // Standard Error: 85_000 + .saturating_add((91_306_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) - fn code_load(c: u32, ) -> Weight { - (8_080_000 as Weight) - // Standard Error: 0 - .saturating_add((1_455_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + // Storage: Timestamp Now (r:1 w:0) + // Storage: System Account (r:1 w:1) + fn call_with_code_kb(c: u32, ) -> Weight { + (371_888_000 as Weight) + // Standard Error: 137_000 + .saturating_add((92_314_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts AccountCounter (r:1 w:1) @@ -194,11 +198,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (464_920_000 as Weight) - // Standard Error: 136_000 - .saturating_add((211_340_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 8_000 - .saturating_add((2_190_000 as Weight).saturating_mul(s as Weight)) + (429_131_000 as Weight) + // Standard Error: 154_000 + .saturating_add((208_736_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 10_000 + .saturating_add((2_203_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -209,9 +213,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (236_192_000 as Weight) + (241_132_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_010_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_986_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -220,7 +224,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (172_780_000 as Weight) + (173_649_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -228,9 +232,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (80_415_000 as Weight) - // Standard Error: 98_000 - .saturating_add((93_463_000 as Weight).saturating_mul(c as Weight)) + (84_508_000 as Weight) + // Standard Error: 93_000 + .saturating_add((91_690_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -238,7 +242,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (40_042_000 as Weight) + (39_407_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -247,9 +251,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (416_770_000 as Weight) - // Standard Error: 175_000 - .saturating_add((114_550_000 as Weight).saturating_mul(r as Weight)) + (421_879_000 as Weight) + // Standard Error: 168_000 + .saturating_add((114_154_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -258,9 +262,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (415_774_000 as Weight) - // Standard Error: 176_000 - .saturating_add((115_169_000 as Weight).saturating_mul(r as Weight)) + (428_124_000 as Weight) + // Standard Error: 167_000 + .saturating_add((113_196_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -269,9 +273,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (411_883_000 as Weight) - // Standard Error: 200_000 - .saturating_add((113_740_000 as Weight).saturating_mul(r as Weight)) + (424_405_000 as Weight) + // Standard Error: 182_000 + .saturating_add((112_511_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -280,9 +284,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (422_382_000 as Weight) - // Standard Error: 189_000 - .saturating_add((313_581_000 as Weight).saturating_mul(r as Weight)) + (433_901_000 as Weight) + // Standard Error: 206_000 + .saturating_add((307_273_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -291,9 +295,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (437_411_000 as Weight) - // Standard Error: 191_000 - .saturating_add((111_580_000 as Weight).saturating_mul(r as Weight)) + (428_707_000 as Weight) + // Standard Error: 203_000 + .saturating_add((113_558_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -302,9 +306,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (431_815_000 as Weight) - // Standard Error: 170_000 - .saturating_add((111_289_000 as Weight).saturating_mul(r as Weight)) + (423_775_000 as Weight) + // Standard Error: 174_000 + .saturating_add((113_371_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -313,9 +317,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (430_451_000 as Weight) - // Standard Error: 152_000 - .saturating_add((111_214_000 as Weight).saturating_mul(r as Weight)) + (423_282_000 as Weight) + // Standard Error: 220_000 + .saturating_add((113_709_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -324,9 +328,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (419_363_000 as Weight) - // Standard Error: 175_000 - .saturating_add((112_089_000 as Weight).saturating_mul(r as Weight)) + (435_209_000 as Weight) + // Standard Error: 157_000 + .saturating_add((111_492_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -336,9 +340,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (427_501_000 as Weight) - // Standard Error: 247_000 - .saturating_add((262_104_000 as Weight).saturating_mul(r as Weight)) + (432_886_000 as Weight) + // Standard Error: 193_000 + .saturating_add((260_787_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -347,9 +351,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (145_426_000 as Weight) - // Standard Error: 115_000 - .saturating_add((52_082_000 as Weight).saturating_mul(r as Weight)) + (147_315_000 as Weight) + // Standard Error: 124_000 + .saturating_add((52_336_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -358,9 +362,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (415_783_000 as Weight) - // Standard Error: 184_000 - .saturating_add((101_266_000 as Weight).saturating_mul(r as Weight)) + (422_074_000 as Weight) + // Standard Error: 199_000 + .saturating_add((100_398_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -369,9 +373,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (536_645_000 as Weight) - // Standard Error: 6_000 - .saturating_add((38_077_000 as Weight).saturating_mul(n as Weight)) + (543_944_000 as Weight) + // Standard Error: 10_000 + .saturating_add((38_098_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -380,9 +384,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (412_785_000 as Weight) - // Standard Error: 92_000 - .saturating_add((1_476_000 as Weight).saturating_mul(r as Weight)) + (398_945_000 as Weight) + // Standard Error: 417_000 + .saturating_add((15_763_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -391,9 +395,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (400_232_000 as Weight) + (416_850_000 as Weight) // Standard Error: 1_000 - .saturating_add((644_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((635_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -404,9 +408,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (409_343_000 as Weight) - // Standard Error: 1_325_000 - .saturating_add((101_661_000 as Weight).saturating_mul(r as Weight)) + (408_445_000 as Weight) + // Standard Error: 248_000 + .saturating_add((102_109_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -418,9 +422,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (417_354_000 as Weight) - // Standard Error: 299_000 - .saturating_add((343_766_000 as Weight).saturating_mul(r as Weight)) + (410_845_000 as Weight) + // Standard Error: 289_000 + .saturating_add((341_867_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -429,9 +433,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (412_092_000 as Weight) - // Standard Error: 403_000 - .saturating_add((568_199_000 as Weight).saturating_mul(r as Weight)) + (425_037_000 as Weight) + // Standard Error: 424_000 + .saturating_add((571_604_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -441,11 +445,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_095_614_000 as Weight) - // Standard Error: 2_151_000 - .saturating_add((455_690_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 424_000 - .saturating_add((163_553_000 as Weight).saturating_mul(n as Weight)) + (1_055_868_000 as Weight) + // Standard Error: 3_004_000 + .saturating_add((453_979_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 592_000 + .saturating_add((166_716_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -456,17 +460,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (169_113_000 as Weight) - // Standard Error: 146_000 - .saturating_add((72_877_000 as Weight).saturating_mul(r as Weight)) + (161_170_000 as Weight) + // Standard Error: 169_000 + .saturating_add((74_379_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (484_647_000 as Weight) - // Standard Error: 479_000 - .saturating_add((369_854_000 as Weight).saturating_mul(r as Weight)) + (500_168_000 as Weight) + // Standard Error: 473_000 + .saturating_add((371_239_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -478,17 +482,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (793_777_000 as Weight) - // Standard Error: 264_000 - .saturating_add((73_253_000 as Weight).saturating_mul(n as Weight)) + (796_175_000 as Weight) + // Standard Error: 249_000 + .saturating_add((74_071_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (180_385_000 as Weight) - // Standard Error: 1_470_000 - .saturating_add((834_911_000 as Weight).saturating_mul(r as Weight)) + (178_237_000 as Weight) + // Standard Error: 1_652_000 + .saturating_add((835_947_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -496,9 +500,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (282_452_000 as Weight) - // Standard Error: 802_000 - .saturating_add((492_119_000 as Weight).saturating_mul(r as Weight)) + (305_702_000 as Weight) + // Standard Error: 750_000 + .saturating_add((493_580_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -509,9 +513,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (687_019_000 as Weight) - // Standard Error: 226_000 - .saturating_add((111_245_000 as Weight).saturating_mul(n as Weight)) + (697_017_000 as Weight) + // Standard Error: 216_000 + .saturating_add((111_743_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -520,9 +524,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (273_106_000 as Weight) - // Standard Error: 1_498_000 - .saturating_add((3_509_324_000 as Weight).saturating_mul(r as Weight)) + (243_124_000 as Weight) + // Standard Error: 1_718_000 + .saturating_add((3_530_873_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -533,9 +537,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (2_702_839_000 as Weight) - // Standard Error: 21_310_000 - .saturating_add((37_721_061_000 as Weight).saturating_mul(r as Weight)) + (140_524_000 as Weight) + // Standard Error: 4_504_000 + .saturating_add((39_287_224_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -546,13 +550,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (40_088_516_000 as Weight) - // Standard Error: 69_999_000 - .saturating_add((2_981_897_000 as Weight).saturating_mul(t as Weight)) + (38_929_132_000 as Weight) + // Standard Error: 65_806_000 + .saturating_add((2_980_358_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 23_000 + .saturating_add((62_980_000 as Weight).saturating_mul(i as Weight)) // Standard Error: 25_000 - .saturating_add((63_345_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 26_000 - .saturating_add((100_683_000 as Weight).saturating_mul(o as Weight)) + .saturating_add((101_383_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -566,8 +570,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 49_379_000 - .saturating_add((51_630_139_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 120_171_000 + .saturating_add((50_779_937_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -580,13 +584,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (47_691_523_000 as Weight) - // Standard Error: 36_000 - .saturating_add((63_693_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 36_000 - .saturating_add((101_775_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 36_000 - .saturating_add((200_727_000 as Weight).saturating_mul(s as Weight)) + (45_749_415_000 as Weight) + // Standard Error: 34_000 + .saturating_add((64_650_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 34_000 + .saturating_add((101_902_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 34_000 + .saturating_add((201_402_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().writes(206 as Weight)) } @@ -595,9 +599,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (411_050_000 as Weight) - // Standard Error: 177_000 - .saturating_add((125_380_000 as Weight).saturating_mul(r as Weight)) + (414_773_000 as Weight) + // Standard Error: 183_000 + .saturating_add((127_117_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -606,9 +610,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (381_286_000 as Weight) - // Standard Error: 48_000 - .saturating_add((506_160_000 as Weight).saturating_mul(n as Weight)) + (581_981_000 as Weight) + // Standard Error: 38_000 + .saturating_add((505_754_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -617,9 +621,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (415_554_000 as Weight) - // Standard Error: 186_000 - .saturating_add((138_154_000 as Weight).saturating_mul(r as Weight)) + (424_421_000 as Weight) + // Standard Error: 223_000 + .saturating_add((137_068_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -628,9 +632,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (509_653_000 as Weight) - // Standard Error: 20_000 - .saturating_add((364_008_000 as Weight).saturating_mul(n as Weight)) + (497_132_000 as Weight) + // Standard Error: 24_000 + .saturating_add((363_894_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -639,9 +643,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (416_442_000 as Weight) - // Standard Error: 186_000 - .saturating_add((120_321_000 as Weight).saturating_mul(r as Weight)) + (419_414_000 as Weight) + // Standard Error: 174_000 + .saturating_add((106_283_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -650,9 +654,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (586_411_000 as Weight) - // Standard Error: 17_000 - .saturating_add((164_095_000 as Weight).saturating_mul(n as Weight)) + (572_206_000 as Weight) + // Standard Error: 24_000 + .saturating_add((163_930_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -661,9 +665,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (410_054_000 as Weight) - // Standard Error: 198_000 - .saturating_add((109_368_000 as Weight).saturating_mul(r as Weight)) + (417_971_000 as Weight) + // Standard Error: 180_000 + .saturating_add((106_016_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -672,9 +676,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (548_447_000 as Weight) - // Standard Error: 16_000 - .saturating_add((164_100_000 as Weight).saturating_mul(n as Weight)) + (568_067_000 as Weight) + // Standard Error: 20_000 + .saturating_add((163_853_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -683,266 +687,266 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (368_727_000 as Weight) - // Standard Error: 1_294_000 - .saturating_add((15_563_119_000 as Weight).saturating_mul(r as Weight)) + (372_816_000 as Weight) + // Standard Error: 1_677_000 + .saturating_add((15_723_462_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (47_482_000 as Weight) - // Standard Error: 11_000 - .saturating_add((811_000 as Weight).saturating_mul(r as Weight)) + (53_407_000 as Weight) + // Standard Error: 14_000 + .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (55_014_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_502_000 as Weight).saturating_mul(r as Weight)) + (48_061_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_947_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (54_708_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_547_000 as Weight).saturating_mul(r as Weight)) + (48_150_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_978_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (38_583_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_979_000 as Weight).saturating_mul(r as Weight)) + (50_943_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_446_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (37_647_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_107_000 as Weight).saturating_mul(r as Weight)) + (47_862_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_627_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (40_586_000 as Weight) - // Standard Error: 17_000 - .saturating_add((1_940_000 as Weight).saturating_mul(r as Weight)) + (51_291_000 as Weight) + // Standard Error: 16_000 + .saturating_add((1_467_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (39_436_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_533_000 as Weight).saturating_mul(r as Weight)) + (44_627_000 as Weight) + // Standard Error: 18_000 + .saturating_add((2_211_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (45_741_000 as Weight) - // Standard Error: 21_000 - .saturating_add((2_450_000 as Weight).saturating_mul(r as Weight)) + (38_208_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_914_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (48_440_000 as Weight) + (47_228_000 as Weight) // Standard Error: 3_000 - .saturating_add((29_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((17_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (49_819_000 as Weight) - // Standard Error: 22_000 - .saturating_add((20_642_000 as Weight).saturating_mul(r as Weight)) + (39_507_000 as Weight) + // Standard Error: 26_000 + .saturating_add((20_544_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (54_317_000 as Weight) - // Standard Error: 29_000 - .saturating_add((30_663_000 as Weight).saturating_mul(r as Weight)) + (47_235_000 as Weight) + // Standard Error: 31_000 + .saturating_add((29_869_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (88_087_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_106_000 as Weight).saturating_mul(p as Weight)) + (78_847_000 as Weight) + // Standard Error: 6_000 + .saturating_add((1_217_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (40_540_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (48_441_000 as Weight) + // Standard Error: 11_000 + .saturating_add((816_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (40_842_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_375_000 as Weight).saturating_mul(r as Weight)) + (48_324_000 as Weight) + // Standard Error: 11_000 + .saturating_add((861_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (43_679_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (45_372_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_488_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (52_999_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_970_000 as Weight).saturating_mul(r as Weight)) + (58_465_000 as Weight) + // Standard Error: 20_000 + .saturating_add((1_655_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (58_630_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_776_000 as Weight).saturating_mul(r as Weight)) + (55_457_000 as Weight) + // Standard Error: 18_000 + .saturating_add((1_671_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (47_810_000 as Weight) - // Standard Error: 11_000 - .saturating_add((817_000 as Weight).saturating_mul(r as Weight)) + (52_615_000 as Weight) + // Standard Error: 14_000 + .saturating_add((905_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (51_086_000 as Weight) - // Standard Error: 3_690_000 - .saturating_add((622_068_000 as Weight).saturating_mul(r as Weight)) + (37_739_000 as Weight) + // Standard Error: 2_851_000 + .saturating_add((634_780_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (44_599_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_498_000 as Weight).saturating_mul(r as Weight)) + (54_830_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_309_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (44_523_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_500_000 as Weight).saturating_mul(r as Weight)) + (54_712_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_310_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (44_633_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_501_000 as Weight).saturating_mul(r as Weight)) + (54_864_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_312_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (44_654_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) + (54_596_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_314_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (42_020_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_950_000 as Weight).saturating_mul(r as Weight)) + (44_536_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_514_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (42_077_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_943_000 as Weight).saturating_mul(r as Weight)) + (44_380_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_512_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (44_559_000 as Weight) + (54_968_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_310_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (37_902_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_480_000 as Weight).saturating_mul(r as Weight)) + (50_161_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_917_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (37_799_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_484_000 as Weight).saturating_mul(r as Weight)) + (50_417_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_911_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (37_492_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_507_000 as Weight).saturating_mul(r as Weight)) + (50_358_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_914_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (37_509_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) + (49_864_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (37_563_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) + (50_159_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_917_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (37_584_000 as Weight) + (50_037_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_496_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_945_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (37_738_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) + (50_482_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (37_806_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) + (50_426_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_908_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (37_858_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (50_205_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_918_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (37_862_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (50_189_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (37_695_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_491_000 as Weight).saturating_mul(r as Weight)) + (50_205_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_922_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (37_693_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) + (50_375_000 as Weight) + // Standard Error: 15_000 + .saturating_add((1_929_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (37_623_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) + (50_343_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_916_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (37_595_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_150_000 as Weight).saturating_mul(r as Weight)) + (50_707_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_667_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (37_661_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_797_000 as Weight).saturating_mul(r as Weight)) + (50_318_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_408_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (37_978_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_107_000 as Weight).saturating_mul(r as Weight)) + (50_214_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_702_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (37_668_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_842_000 as Weight).saturating_mul(r as Weight)) + (50_394_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_411_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (37_846_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_482_000 as Weight).saturating_mul(r as Weight)) + (50_397_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_910_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (37_902_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_478_000 as Weight).saturating_mul(r as Weight)) + (50_291_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_915_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (37_670_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_489_000 as Weight).saturating_mul(r as Weight)) + (50_684_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_903_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (37_987_000 as Weight) + (49_638_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_479_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_967_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (37_945_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_486_000 as Weight).saturating_mul(r as Weight)) + (50_817_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (37_570_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) + (50_987_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (37_674_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) + (50_885_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_905_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (37_467_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) + (50_465_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_908_000 as Weight).saturating_mul(r as Weight)) } } @@ -950,41 +954,45 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (2_854_000 as Weight) + (2_720_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((2_190_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((2_208_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (101_551_000 as Weight) + (95_834_000 as Weight) // Standard Error: 2_000 - .saturating_add((292_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((317_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) - fn instrument(c: u32, ) -> Weight { - (33_350_000 as Weight) - // Standard Error: 106_000 - .saturating_add((91_098_000 as Weight).saturating_mul(c as Weight)) + fn reinstrument(c: u32, ) -> Weight { + (17_177_000 as Weight) + // Standard Error: 85_000 + .saturating_add((91_306_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) - fn code_load(c: u32, ) -> Weight { - (8_080_000 as Weight) - // Standard Error: 0 - .saturating_add((1_455_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + // Storage: Timestamp Now (r:1 w:0) + // Storage: System Account (r:1 w:1) + fn call_with_code_kb(c: u32, ) -> Weight { + (371_888_000 as Weight) + // Standard Error: 137_000 + .saturating_add((92_314_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts AccountCounter (r:1 w:1) @@ -994,11 +1002,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (464_920_000 as Weight) - // Standard Error: 136_000 - .saturating_add((211_340_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 8_000 - .saturating_add((2_190_000 as Weight).saturating_mul(s as Weight)) + (429_131_000 as Weight) + // Standard Error: 154_000 + .saturating_add((208_736_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 10_000 + .saturating_add((2_203_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1009,9 +1017,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (236_192_000 as Weight) + (241_132_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_010_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_986_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1020,7 +1028,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (172_780_000 as Weight) + (173_649_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1028,9 +1036,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (80_415_000 as Weight) - // Standard Error: 98_000 - .saturating_add((93_463_000 as Weight).saturating_mul(c as Weight)) + (84_508_000 as Weight) + // Standard Error: 93_000 + .saturating_add((91_690_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1038,7 +1046,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (40_042_000 as Weight) + (39_407_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1047,9 +1055,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (416_770_000 as Weight) - // Standard Error: 175_000 - .saturating_add((114_550_000 as Weight).saturating_mul(r as Weight)) + (421_879_000 as Weight) + // Standard Error: 168_000 + .saturating_add((114_154_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1058,9 +1066,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (415_774_000 as Weight) - // Standard Error: 176_000 - .saturating_add((115_169_000 as Weight).saturating_mul(r as Weight)) + (428_124_000 as Weight) + // Standard Error: 167_000 + .saturating_add((113_196_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1069,9 +1077,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (411_883_000 as Weight) - // Standard Error: 200_000 - .saturating_add((113_740_000 as Weight).saturating_mul(r as Weight)) + (424_405_000 as Weight) + // Standard Error: 182_000 + .saturating_add((112_511_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1080,9 +1088,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (422_382_000 as Weight) - // Standard Error: 189_000 - .saturating_add((313_581_000 as Weight).saturating_mul(r as Weight)) + (433_901_000 as Weight) + // Standard Error: 206_000 + .saturating_add((307_273_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1091,9 +1099,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (437_411_000 as Weight) - // Standard Error: 191_000 - .saturating_add((111_580_000 as Weight).saturating_mul(r as Weight)) + (428_707_000 as Weight) + // Standard Error: 203_000 + .saturating_add((113_558_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1102,9 +1110,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (431_815_000 as Weight) - // Standard Error: 170_000 - .saturating_add((111_289_000 as Weight).saturating_mul(r as Weight)) + (423_775_000 as Weight) + // Standard Error: 174_000 + .saturating_add((113_371_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1113,9 +1121,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (430_451_000 as Weight) - // Standard Error: 152_000 - .saturating_add((111_214_000 as Weight).saturating_mul(r as Weight)) + (423_282_000 as Weight) + // Standard Error: 220_000 + .saturating_add((113_709_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1124,9 +1132,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (419_363_000 as Weight) - // Standard Error: 175_000 - .saturating_add((112_089_000 as Weight).saturating_mul(r as Weight)) + (435_209_000 as Weight) + // Standard Error: 157_000 + .saturating_add((111_492_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1136,9 +1144,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (427_501_000 as Weight) - // Standard Error: 247_000 - .saturating_add((262_104_000 as Weight).saturating_mul(r as Weight)) + (432_886_000 as Weight) + // Standard Error: 193_000 + .saturating_add((260_787_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1147,9 +1155,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (145_426_000 as Weight) - // Standard Error: 115_000 - .saturating_add((52_082_000 as Weight).saturating_mul(r as Weight)) + (147_315_000 as Weight) + // Standard Error: 124_000 + .saturating_add((52_336_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1158,9 +1166,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (415_783_000 as Weight) - // Standard Error: 184_000 - .saturating_add((101_266_000 as Weight).saturating_mul(r as Weight)) + (422_074_000 as Weight) + // Standard Error: 199_000 + .saturating_add((100_398_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1169,9 +1177,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (536_645_000 as Weight) - // Standard Error: 6_000 - .saturating_add((38_077_000 as Weight).saturating_mul(n as Weight)) + (543_944_000 as Weight) + // Standard Error: 10_000 + .saturating_add((38_098_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1180,9 +1188,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (412_785_000 as Weight) - // Standard Error: 92_000 - .saturating_add((1_476_000 as Weight).saturating_mul(r as Weight)) + (398_945_000 as Weight) + // Standard Error: 417_000 + .saturating_add((15_763_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1191,9 +1199,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (400_232_000 as Weight) + (416_850_000 as Weight) // Standard Error: 1_000 - .saturating_add((644_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((635_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1204,9 +1212,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (409_343_000 as Weight) - // Standard Error: 1_325_000 - .saturating_add((101_661_000 as Weight).saturating_mul(r as Weight)) + (408_445_000 as Weight) + // Standard Error: 248_000 + .saturating_add((102_109_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1218,9 +1226,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (417_354_000 as Weight) - // Standard Error: 299_000 - .saturating_add((343_766_000 as Weight).saturating_mul(r as Weight)) + (410_845_000 as Weight) + // Standard Error: 289_000 + .saturating_add((341_867_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1229,9 +1237,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (412_092_000 as Weight) - // Standard Error: 403_000 - .saturating_add((568_199_000 as Weight).saturating_mul(r as Weight)) + (425_037_000 as Weight) + // Standard Error: 424_000 + .saturating_add((571_604_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1241,11 +1249,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_095_614_000 as Weight) - // Standard Error: 2_151_000 - .saturating_add((455_690_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 424_000 - .saturating_add((163_553_000 as Weight).saturating_mul(n as Weight)) + (1_055_868_000 as Weight) + // Standard Error: 3_004_000 + .saturating_add((453_979_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 592_000 + .saturating_add((166_716_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1256,17 +1264,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (169_113_000 as Weight) - // Standard Error: 146_000 - .saturating_add((72_877_000 as Weight).saturating_mul(r as Weight)) + (161_170_000 as Weight) + // Standard Error: 169_000 + .saturating_add((74_379_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (484_647_000 as Weight) - // Standard Error: 479_000 - .saturating_add((369_854_000 as Weight).saturating_mul(r as Weight)) + (500_168_000 as Weight) + // Standard Error: 473_000 + .saturating_add((371_239_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1278,17 +1286,17 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (793_777_000 as Weight) - // Standard Error: 264_000 - .saturating_add((73_253_000 as Weight).saturating_mul(n as Weight)) + (796_175_000 as Weight) + // Standard Error: 249_000 + .saturating_add((74_071_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (180_385_000 as Weight) - // Standard Error: 1_470_000 - .saturating_add((834_911_000 as Weight).saturating_mul(r as Weight)) + (178_237_000 as Weight) + // Standard Error: 1_652_000 + .saturating_add((835_947_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1296,9 +1304,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (282_452_000 as Weight) - // Standard Error: 802_000 - .saturating_add((492_119_000 as Weight).saturating_mul(r as Weight)) + (305_702_000 as Weight) + // Standard Error: 750_000 + .saturating_add((493_580_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1309,9 +1317,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (687_019_000 as Weight) - // Standard Error: 226_000 - .saturating_add((111_245_000 as Weight).saturating_mul(n as Weight)) + (697_017_000 as Weight) + // Standard Error: 216_000 + .saturating_add((111_743_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1320,9 +1328,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (273_106_000 as Weight) - // Standard Error: 1_498_000 - .saturating_add((3_509_324_000 as Weight).saturating_mul(r as Weight)) + (243_124_000 as Weight) + // Standard Error: 1_718_000 + .saturating_add((3_530_873_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1333,9 +1341,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (2_702_839_000 as Weight) - // Standard Error: 21_310_000 - .saturating_add((37_721_061_000 as Weight).saturating_mul(r as Weight)) + (140_524_000 as Weight) + // Standard Error: 4_504_000 + .saturating_add((39_287_224_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1346,13 +1354,13 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (40_088_516_000 as Weight) - // Standard Error: 69_999_000 - .saturating_add((2_981_897_000 as Weight).saturating_mul(t as Weight)) + (38_929_132_000 as Weight) + // Standard Error: 65_806_000 + .saturating_add((2_980_358_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 23_000 + .saturating_add((62_980_000 as Weight).saturating_mul(i as Weight)) // Standard Error: 25_000 - .saturating_add((63_345_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 26_000 - .saturating_add((100_683_000 as Weight).saturating_mul(o as Weight)) + .saturating_add((101_383_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1366,8 +1374,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 49_379_000 - .saturating_add((51_630_139_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 120_171_000 + .saturating_add((50_779_937_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1380,13 +1388,13 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (47_691_523_000 as Weight) - // Standard Error: 36_000 - .saturating_add((63_693_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 36_000 - .saturating_add((101_775_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 36_000 - .saturating_add((200_727_000 as Weight).saturating_mul(s as Weight)) + (45_749_415_000 as Weight) + // Standard Error: 34_000 + .saturating_add((64_650_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 34_000 + .saturating_add((101_902_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 34_000 + .saturating_add((201_402_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().writes(206 as Weight)) } @@ -1395,9 +1403,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (411_050_000 as Weight) - // Standard Error: 177_000 - .saturating_add((125_380_000 as Weight).saturating_mul(r as Weight)) + (414_773_000 as Weight) + // Standard Error: 183_000 + .saturating_add((127_117_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1406,9 +1414,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (381_286_000 as Weight) - // Standard Error: 48_000 - .saturating_add((506_160_000 as Weight).saturating_mul(n as Weight)) + (581_981_000 as Weight) + // Standard Error: 38_000 + .saturating_add((505_754_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1417,9 +1425,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (415_554_000 as Weight) - // Standard Error: 186_000 - .saturating_add((138_154_000 as Weight).saturating_mul(r as Weight)) + (424_421_000 as Weight) + // Standard Error: 223_000 + .saturating_add((137_068_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1428,9 +1436,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (509_653_000 as Weight) - // Standard Error: 20_000 - .saturating_add((364_008_000 as Weight).saturating_mul(n as Weight)) + (497_132_000 as Weight) + // Standard Error: 24_000 + .saturating_add((363_894_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1439,9 +1447,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (416_442_000 as Weight) - // Standard Error: 186_000 - .saturating_add((120_321_000 as Weight).saturating_mul(r as Weight)) + (419_414_000 as Weight) + // Standard Error: 174_000 + .saturating_add((106_283_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1450,9 +1458,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (586_411_000 as Weight) - // Standard Error: 17_000 - .saturating_add((164_095_000 as Weight).saturating_mul(n as Weight)) + (572_206_000 as Weight) + // Standard Error: 24_000 + .saturating_add((163_930_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1461,9 +1469,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (410_054_000 as Weight) - // Standard Error: 198_000 - .saturating_add((109_368_000 as Weight).saturating_mul(r as Weight)) + (417_971_000 as Weight) + // Standard Error: 180_000 + .saturating_add((106_016_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1472,9 +1480,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (548_447_000 as Weight) - // Standard Error: 16_000 - .saturating_add((164_100_000 as Weight).saturating_mul(n as Weight)) + (568_067_000 as Weight) + // Standard Error: 20_000 + .saturating_add((163_853_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1483,265 +1491,265 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (368_727_000 as Weight) - // Standard Error: 1_294_000 - .saturating_add((15_563_119_000 as Weight).saturating_mul(r as Weight)) + (372_816_000 as Weight) + // Standard Error: 1_677_000 + .saturating_add((15_723_462_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (47_482_000 as Weight) - // Standard Error: 11_000 - .saturating_add((811_000 as Weight).saturating_mul(r as Weight)) + (53_407_000 as Weight) + // Standard Error: 14_000 + .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (55_014_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_502_000 as Weight).saturating_mul(r as Weight)) + (48_061_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_947_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (54_708_000 as Weight) - // Standard Error: 13_000 - .saturating_add((2_547_000 as Weight).saturating_mul(r as Weight)) + (48_150_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_978_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (38_583_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_979_000 as Weight).saturating_mul(r as Weight)) + (50_943_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_446_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (37_647_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_107_000 as Weight).saturating_mul(r as Weight)) + (47_862_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_627_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (40_586_000 as Weight) - // Standard Error: 17_000 - .saturating_add((1_940_000 as Weight).saturating_mul(r as Weight)) + (51_291_000 as Weight) + // Standard Error: 16_000 + .saturating_add((1_467_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (39_436_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_533_000 as Weight).saturating_mul(r as Weight)) + (44_627_000 as Weight) + // Standard Error: 18_000 + .saturating_add((2_211_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (45_741_000 as Weight) - // Standard Error: 21_000 - .saturating_add((2_450_000 as Weight).saturating_mul(r as Weight)) + (38_208_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_914_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (48_440_000 as Weight) + (47_228_000 as Weight) // Standard Error: 3_000 - .saturating_add((29_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((17_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (49_819_000 as Weight) - // Standard Error: 22_000 - .saturating_add((20_642_000 as Weight).saturating_mul(r as Weight)) + (39_507_000 as Weight) + // Standard Error: 26_000 + .saturating_add((20_544_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (54_317_000 as Weight) - // Standard Error: 29_000 - .saturating_add((30_663_000 as Weight).saturating_mul(r as Weight)) + (47_235_000 as Weight) + // Standard Error: 31_000 + .saturating_add((29_869_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (88_087_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_106_000 as Weight).saturating_mul(p as Weight)) + (78_847_000 as Weight) + // Standard Error: 6_000 + .saturating_add((1_217_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (40_540_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (48_441_000 as Weight) + // Standard Error: 11_000 + .saturating_add((816_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (40_842_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_375_000 as Weight).saturating_mul(r as Weight)) + (48_324_000 as Weight) + // Standard Error: 11_000 + .saturating_add((861_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (43_679_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (45_372_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_488_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (52_999_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_970_000 as Weight).saturating_mul(r as Weight)) + (58_465_000 as Weight) + // Standard Error: 20_000 + .saturating_add((1_655_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (58_630_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_776_000 as Weight).saturating_mul(r as Weight)) + (55_457_000 as Weight) + // Standard Error: 18_000 + .saturating_add((1_671_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (47_810_000 as Weight) - // Standard Error: 11_000 - .saturating_add((817_000 as Weight).saturating_mul(r as Weight)) + (52_615_000 as Weight) + // Standard Error: 14_000 + .saturating_add((905_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (51_086_000 as Weight) - // Standard Error: 3_690_000 - .saturating_add((622_068_000 as Weight).saturating_mul(r as Weight)) + (37_739_000 as Weight) + // Standard Error: 2_851_000 + .saturating_add((634_780_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (44_599_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_498_000 as Weight).saturating_mul(r as Weight)) + (54_830_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_309_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (44_523_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_500_000 as Weight).saturating_mul(r as Weight)) + (54_712_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_310_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (44_633_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_501_000 as Weight).saturating_mul(r as Weight)) + (54_864_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_312_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (44_654_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) + (54_596_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_314_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (42_020_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_950_000 as Weight).saturating_mul(r as Weight)) + (44_536_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_514_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (42_077_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_943_000 as Weight).saturating_mul(r as Weight)) + (44_380_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_512_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (44_559_000 as Weight) + (54_968_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_310_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (37_902_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_480_000 as Weight).saturating_mul(r as Weight)) + (50_161_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_917_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (37_799_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_484_000 as Weight).saturating_mul(r as Weight)) + (50_417_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_911_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (37_492_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_507_000 as Weight).saturating_mul(r as Weight)) + (50_358_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_914_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (37_509_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) + (49_864_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (37_563_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) + (50_159_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_917_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (37_584_000 as Weight) + (50_037_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_496_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_945_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (37_738_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) + (50_482_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (37_806_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) + (50_426_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_908_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (37_858_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (50_205_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_918_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (37_862_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (50_189_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (37_695_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_491_000 as Weight).saturating_mul(r as Weight)) + (50_205_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_922_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (37_693_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) + (50_375_000 as Weight) + // Standard Error: 15_000 + .saturating_add((1_929_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (37_623_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) + (50_343_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_916_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (37_595_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_150_000 as Weight).saturating_mul(r as Weight)) + (50_707_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_667_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (37_661_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_797_000 as Weight).saturating_mul(r as Weight)) + (50_318_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_408_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (37_978_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_107_000 as Weight).saturating_mul(r as Weight)) + (50_214_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_702_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (37_668_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_842_000 as Weight).saturating_mul(r as Weight)) + (50_394_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_411_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (37_846_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_482_000 as Weight).saturating_mul(r as Weight)) + (50_397_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_910_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (37_902_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_478_000 as Weight).saturating_mul(r as Weight)) + (50_291_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_915_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (37_670_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_489_000 as Weight).saturating_mul(r as Weight)) + (50_684_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_903_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (37_987_000 as Weight) + (49_638_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_479_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_967_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (37_945_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_486_000 as Weight).saturating_mul(r as Weight)) + (50_817_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (37_570_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) + (50_987_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (37_674_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) + (50_885_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_905_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (37_467_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_503_000 as Weight).saturating_mul(r as Weight)) + (50_465_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_908_000 as Weight).saturating_mul(r as Weight)) } } From a991b0aecba1635861eaf104a7912f55fc1f323c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 11 Dec 2021 08:13:18 +0100 Subject: [PATCH 0328/1472] `inspect-key`: Adds support for `expect-public` (#10430) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Introduce `SecretUri` * `inspect-key`: Adds support for `expect-public` `expect-public` can be used to check that a given secret uri corresponds to the given public key. This is mainly useful when the secret uri is protected by a password and a new derived account should be generated. With `--expect-public` the user can pass the public key/account-id of the "base" secret uri aka the one without any derivation to ensure the correct password was inserted. * Fixes * :facepalm: * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Review feedback * FMT * Bump the versions Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- Cargo.lock | 2 +- bin/node-template/node/Cargo.toml | 2 +- bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 2 +- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- bin/node/inspect/Cargo.toml | 2 +- bin/node/primitives/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- bin/utils/chain-spec-builder/Cargo.toml | 2 +- client/allocator/Cargo.toml | 2 +- client/api/Cargo.toml | 2 +- client/authority-discovery/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 2 +- client/beefy/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/block-builder/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/cli/src/commands/inspect_key.rs | 149 ++++++++++++++++++ client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/executor/common/Cargo.toml | 2 +- client/executor/runtime-test/Cargo.toml | 2 +- client/executor/wasmi/Cargo.toml | 2 +- client/executor/wasmtime/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 4 +- client/keystore/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- client/state-db/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- frame/assets/Cargo.toml | 2 +- frame/atomic-swap/Cargo.toml | 2 +- frame/aura/Cargo.toml | 2 +- frame/authority-discovery/Cargo.toml | 2 +- frame/authorship/Cargo.toml | 2 +- frame/babe/Cargo.toml | 2 +- frame/bags-list/Cargo.toml | 4 +- frame/bags-list/remote-tests/Cargo.toml | 2 +- frame/balances/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 2 +- frame/bounties/Cargo.toml | 2 +- frame/child-bounties/Cargo.toml | 2 +- frame/collective/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/common/Cargo.toml | 2 +- frame/contracts/rpc/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 4 +- frame/election-provider-support/Cargo.toml | 2 +- frame/elections-phragmen/Cargo.toml | 4 +- frame/elections/Cargo.toml | 2 +- frame/examples/basic/Cargo.toml | 2 +- frame/examples/offchain-worker/Cargo.toml | 2 +- frame/examples/parallel/Cargo.toml | 2 +- frame/executive/Cargo.toml | 4 +- frame/gilt/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/identity/Cargo.toml | 2 +- frame/im-online/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- frame/lottery/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- .../primitives/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 2 +- frame/nicks/Cargo.toml | 2 +- frame/node-authorization/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/offences/benchmarking/Cargo.toml | 2 +- frame/proxy/Cargo.toml | 2 +- frame/randomness-collective-flip/Cargo.toml | 2 +- frame/recovery/Cargo.toml | 2 +- frame/scheduler/Cargo.toml | 2 +- frame/scored-pool/Cargo.toml | 2 +- frame/session/Cargo.toml | 2 +- frame/session/benchmarking/Cargo.toml | 2 +- frame/society/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/sudo/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/test/Cargo.toml | 2 +- frame/support/test/compile_pass/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- frame/system/benchmarking/Cargo.toml | 2 +- frame/timestamp/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- frame/transaction-payment/rpc/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 2 +- frame/utility/Cargo.toml | 4 +- frame/vesting/Cargo.toml | 2 +- primitives/api/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/application-crypto/Cargo.toml | 2 +- primitives/application-crypto/test/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/consensus/common/Cargo.toml | 2 +- primitives/consensus/pow/Cargo.toml | 2 +- primitives/consensus/vrf/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/core/src/crypto.rs | 117 ++++++++++++-- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/inherents/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/keyring/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/offchain/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 2 +- .../test-wasm-deprecated/Cargo.toml | 2 +- .../runtime-interface/test-wasm/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/sandbox/Cargo.toml | 2 +- primitives/session/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/tasks/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 2 +- .../transaction-storage-proof/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- test-utils/runtime/client/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/frame-utilities-cli/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 152 files changed, 413 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7ddb66e29188..612cbdc8b0def 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9392,7 +9392,7 @@ dependencies = [ [[package]] name = "sp-core" -version = "4.0.0" +version = "4.1.0-dev" dependencies = [ "base58", "bitflags", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 2680b91b3a254..731e6fcda4083 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -20,7 +20,7 @@ name = "node-template" structopt = "0.3.25" sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = ["wasmtime"] } sc-service = { version = "0.10.0-dev", path = "../../../client/service", features = ["wasmtime"] } sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" } diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 646038ca6ced8..d473119702f87 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -22,7 +22,7 @@ frame-system = { default-features = false, version = "4.0.0-dev", path = "../../ frame-benchmarking = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/benchmarking", optional = true } [dev-dependencies] -sp-core = { default-features = false, version = "4.0.0", path = "../../../../primitives/core" } +sp-core = { default-features = false, version = "4.1.0-dev", path = "../../../../primitives/core" } sp-io = { default-features = false, version = "4.0.0-dev", path = "../../../../primitives/io" } sp-runtime = { default-features = false, version = "4.0.0-dev", path = "../../../../primitives/runtime" } diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index a25c45c692de8..4818535e196c4 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -29,7 +29,7 @@ frame-executive = { version = "4.0.0-dev", default-features = false, path = "../ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-block-builder = { path = "../../../primitives/block-builder", default-features = false, version = "4.0.0-dev"} sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/consensus/aura" } -sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-inherents = { path = "../../../primitives/inherents", default-features = false, version = "4.0.0-dev"} sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 27c26d21dfe06..65d12378c4cf5 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -23,7 +23,7 @@ derive_more = "0.99.16" kvdb = "0.10.0" kvdb-rocksdb = "0.14.0" sp-trie = { version = "4.0.0-dev", path = "../../../primitives/trie" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-basic-authorship = { version = "0.10.0-dev", path = "../../../client/basic-authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index cb632d936a2dc..6da2fddd331ea 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -47,7 +47,7 @@ sp-authority-discovery = { version = "4.0.0-dev", path = "../../../primitives/au sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } grandpa-primitives = { version = "4.0.0-dev", package = "sp-finality-grandpa", path = "../../../primitives/finality-grandpa" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 13ed4d313994c..2144b92986167 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -17,7 +17,7 @@ scale-info = { version = "1.0", features = ["derive"] } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index 18f24651ed35d..b0db8f6304761 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -18,6 +18,6 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } structopt = "0.3.8" diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 03d587acecd2d..d2c315bd9b6e1 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/application-crypto" } -sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } [features] diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index b36fd622dfa3a..32dcc003e879a 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -30,7 +30,7 @@ sp-block-builder = { path = "../../../primitives/block-builder", default-feature sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents" } node-primitives = { version = "2.0.0", default-features = false, path = "../primitives" } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } -sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 0fb0d40a7c2d2..7f3a911962488 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -28,7 +28,7 @@ sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = [ diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index 79eb5becfeb84..c5872ca29700d 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -18,7 +18,7 @@ ansi_term = "0.12.1" sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } node-cli = { version = "3.0.0-dev", path = "../../node/cli" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } rand = "0.7.2" structopt = "0.3.25" diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index 48191273ff36a..ea0ce3c0bbea5 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-wasm-interface = { version = "4.0.0", path = "../../primitives/wasm-interface" } log = "0.4.11" thiserror = "1.0.30" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index 5e0fe88b3ca7c..13ec13538e65e 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -27,7 +27,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } log = "0.4.8" parking_lot = "0.11.1" sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-utils = { version = "4.0.0-dev", path = "../utils" } diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 8dcf8ab4c8140..207f22753e452 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -32,7 +32,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-authority-discovery = { version = "4.0.0-dev", path = "../../primitives/authority-discovery" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 049876f478790..c1a8e9210a416 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index b0f05888712d1..cb561c0dc77a6 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -22,7 +22,7 @@ sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 4d7bd6cef6c88..83f6b392f55c7 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -21,7 +21,7 @@ codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } beefy-gadget = { version = "4.0.0-dev", path = "../." } diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 789e3fffcfa17..69154699e3f1d 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -18,7 +18,7 @@ sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-mach sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-builder" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 1b4e3ed72d566..fdc72307af2a1 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } impl-trait-for-tuples = "0.2.1" sc-network = { version = "0.10.0-dev", path = "../network" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } serde = { version = "1.0.126", features = ["derive"] } serde_json = "1.0.71" sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index a9bc4e9f87a5d..566ce21cfe903 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -32,7 +32,7 @@ sc-network = { version = "0.10.0-dev", path = "../network" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../service" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } diff --git a/client/cli/src/commands/inspect_key.rs b/client/cli/src/commands/inspect_key.rs index 277c9015f4daf..48b045f4cbaf3 100644 --- a/client/cli/src/commands/inspect_key.rs +++ b/client/cli/src/commands/inspect_key.rs @@ -21,7 +21,10 @@ use crate::{ utils::{self, print_from_public, print_from_uri}, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, NetworkSchemeFlag, OutputTypeFlag, }; +use sp_core::crypto::{ExposeSecret, SecretString, SecretUri, Ss58Codec}; +use std::str::FromStr; use structopt::StructOpt; + /// The `inspect` command #[derive(Debug, StructOpt)] #[structopt( @@ -59,6 +62,18 @@ pub struct InspectKeyCmd { #[allow(missing_docs)] #[structopt(flatten)] pub crypto_scheme: CryptoSchemeFlag, + + /// Expect that `--uri` has the given public key/account-id. + /// + /// If `--uri` has any derivations, the public key is checked against the base `uri`, i.e. the + /// `uri` without any derivation applied. However, if `uri` has a password or there is one + /// given by `--password`, it will be used to decrypt `uri` before comparing the public + /// key/account-id. + /// + /// If there is no derivation in `--uri`, the public key will be checked against the public key + /// of `--uri` directly. + #[structopt(long, conflicts_with = "public")] + pub expect_public: Option, } impl InspectKeyCmd { @@ -77,6 +92,13 @@ impl InspectKeyCmd { ) )?; } else { + if let Some(ref expect_public) = self.expect_public { + with_crypto_scheme!( + self.crypto_scheme.scheme, + expect_public_from_phrase(&&expect_public, &uri, password.as_ref(),) + )?; + } + with_crypto_scheme!( self.crypto_scheme.scheme, print_from_uri( @@ -92,9 +114,50 @@ impl InspectKeyCmd { } } +/// Checks that `expect_public` is the public key of `suri`. +/// +/// If `suri` has any derivations, `expect_public` is checked against the public key of the "bare" +/// `suri`, i.e. without any derivations. +/// +/// Returns an error if the public key does not match. +fn expect_public_from_phrase( + expect_public: &str, + suri: &str, + password: Option<&SecretString>, +) -> Result<(), Error> { + let secret_uri = SecretUri::from_str(suri).map_err(|e| format!("{:?}", e))?; + let expected_public = if let Some(public) = expect_public.strip_prefix("0x") { + let hex_public = hex::decode(&public) + .map_err(|_| format!("Invalid expected public key hex: `{}`", expect_public))?; + Pair::Public::try_from(&hex_public) + .map_err(|_| format!("Invalid expected public key: `{}`", expect_public))? + } else { + Pair::Public::from_string_with_version(expect_public) + .map_err(|_| format!("Invalid expected account id: `{}`", expect_public))? + .0 + }; + + let pair = Pair::from_string_with_seed( + secret_uri.phrase.expose_secret().as_str(), + password + .or_else(|| secret_uri.password.as_ref()) + .map(|p| p.expose_secret().as_str()), + ) + .map_err(|_| format!("Invalid secret uri: {}", suri))? + .0; + + if pair.public() == expected_public { + Ok(()) + } else { + Err(format!("Expected public ({}) key does not match.", expect_public).into()) + } +} + #[cfg(test)] mod tests { use super::*; + use sp_core::crypto::{Pair, Public}; + use sp_runtime::traits::IdentifyAccount; use structopt::StructOpt; #[test] @@ -117,4 +180,90 @@ mod tests { let inspect = InspectKeyCmd::from_iter(&["inspect-key", "--public", public]); assert!(inspect.run().is_ok()); } + + #[test] + fn inspect_with_expected_public_key() { + let check_cmd = |seed, expected_public, success| { + let inspect = InspectKeyCmd::from_iter(&[ + "inspect-key", + "--expect-public", + expected_public, + seed, + ]); + let res = inspect.run(); + + if success { + assert!(res.is_ok()); + } else { + assert!(res.unwrap_err().to_string().contains(&format!( + "Expected public ({}) key does not match.", + expected_public + ))); + } + }; + + let seed = + "remember fiber forum demise paper uniform squirrel feel access exclude casual effort"; + let invalid_public = "0x12e76e0ae8ce41b6516cce52b3f23a08dcb4cfeed53c6ee8f5eb9f7367341069"; + let valid_public = sp_core::sr25519::Pair::from_string_with_seed(seed, None) + .expect("Valid") + .0 + .public(); + let valid_public_hex = format!("0x{}", hex::encode(valid_public.as_slice())); + let valid_accountid = format!("{}", valid_public.into_account()); + + // It should fail with the invalid public key + check_cmd(seed, invalid_public, false); + + // It should work with the valid public key & account id + check_cmd(seed, &valid_public_hex, true); + check_cmd(seed, &valid_accountid, true); + + let password = "test12245"; + let seed_with_password = format!("{}///{}", seed, password); + let valid_public_with_password = + sp_core::sr25519::Pair::from_string_with_seed(&seed_with_password, Some(password)) + .expect("Valid") + .0 + .public(); + let valid_public_hex_with_password = + format!("0x{}", hex::encode(&valid_public_with_password.as_slice())); + let valid_accountid_with_password = + format!("{}", &valid_public_with_password.into_account()); + + // Only the public key that corresponds to the seed with password should be accepted. + check_cmd(&seed_with_password, &valid_public_hex, false); + check_cmd(&seed_with_password, &valid_accountid, false); + + check_cmd(&seed_with_password, &valid_public_hex_with_password, true); + check_cmd(&seed_with_password, &valid_accountid_with_password, true); + + let seed_with_password_and_derivation = format!("{}//test//account///{}", seed, password); + + let valid_public_with_password_and_derivation = + sp_core::sr25519::Pair::from_string_with_seed( + &seed_with_password_and_derivation, + Some(password), + ) + .expect("Valid") + .0 + .public(); + let valid_public_hex_with_password_and_derivation = + format!("0x{}", hex::encode(&valid_public_with_password_and_derivation.as_slice())); + + // They should still be valid, because we check the base secret key. + check_cmd(&seed_with_password_and_derivation, &valid_public_hex_with_password, true); + check_cmd(&seed_with_password_and_derivation, &valid_accountid_with_password, true); + + // And these should be invalid. + check_cmd(&seed_with_password_and_derivation, &valid_public_hex, false); + check_cmd(&seed_with_password_and_derivation, &valid_accountid, false); + + // The public of the derived account should fail. + check_cmd( + &seed_with_password_and_derivation, + &valid_public_hex_with_password_and_derivation, + false, + ); + } } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 967f59999c7ec..f12578b8a6780 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -26,7 +26,7 @@ derive_more = "0.99.16" futures = "0.3.9" sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } log = "0.4.8" -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 5f1a8a0889168..7daab5557b57c 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ ] } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-application-crypto = { version = "4.0.0-dev", path = "../../../primitives/application-crypto" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } num-bigint = "0.2.3" diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index bba579ee111b0..3bd8bf6e76580 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -27,7 +27,7 @@ futures = "0.3.16" derive_more = "0.99.16" sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } -sp-core = { version = "4.0.0", path = "../../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } sp-application-crypto = { version = "4.0.0-dev", path = "../../../../primitives/application-crypto" } sp-keystore = { version = "0.10.0-dev", path = "../../../../primitives/keystore" } diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 13b7203540182..f20e12cc4aae8 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -20,7 +20,7 @@ futures = { version = "0.3.1", features = ["thread-pool"] } futures-timer = "3.0.1" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { path = "../../../primitives/core", version = "4.0.0" } +sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 24314fefd156e..59d35819c7815 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -36,7 +36,7 @@ sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10. sp-consensus-slots = { path = "../../../primitives/consensus/slots", version = "0.10.0-dev" } sp-inherents = { path = "../../../primitives/inherents", version = "4.0.0-dev" } sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0-dev" } -sp-core = { path = "../../../primitives/core", version = "4.0.0" } +sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } sp-keystore = { path = "../../../primitives/keystore", version = "0.10.0-dev" } sp-api = { path = "../../../primitives/api", version = "4.0.0-dev" } sc-transaction-pool-api = { path = "../../../client/transaction-pool/api", version = "4.0.0-dev" } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 2b0926ce887e9..d4b156f0b8faa 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 7b4aa26cdf540..c97a3d1fe0356 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-arithmetic = { version = "4.0.0-dev", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index f0ce20354a800..a2ed46c48e1cf 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -26,7 +26,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index dea8a26edde36..58d7ec34b20ee 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-tasks = { version = "4.0.0-dev", path = "../../primitives/tasks" } sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 198d5201e1f5d..abaee76073032 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -18,7 +18,7 @@ derive_more = "0.99.16" pwasm-utils = "0.18.2" codec = { package = "parity-scale-codec", version = "2.0.0" } wasmi = "0.9.1" -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sp-wasm-interface = { version = "4.0.0", path = "../../../primitives/wasm-interface" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index 831ff786ca090..4572a23c630ae 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index f1e01d944a6eb..d50237edfe4a0 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -21,5 +21,5 @@ sc-executor-common = { version = "0.10.0-dev", path = "../common" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sp-wasm-interface = { version = "4.0.0", path = "../../../primitives/wasm-interface" } sp-runtime-interface = { version = "4.0.0", path = "../../../primitives/runtime-interface" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } scoped-tls = "1.0" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 77210b97f3761..49e44766b9d47 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sp-wasm-interface = { version = "4.0.0", path = "../../../primitives/wasm-interface" } sp-runtime-interface = { version = "4.0.0", path = "../../../primitives/runtime-interface" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } wasmtime = { version = "0.31.0", default-features = false, features = [ "cache", diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index fa60751d48912..12aedbfe0143b 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -30,7 +30,7 @@ sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index a83a47af9ed48..9d0affde3b17a 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" sc-finality-grandpa = { version = "0.10.0-dev", path = "../" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } finality-grandpa = { version = "0.14.4", features = ["derive-codec"] } jsonrpc-core = "18.0.0" @@ -32,7 +32,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ "test-helpers", ] } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index ac2663902b67f..912de249ad0b0 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.50" derive_more = "0.99.16" sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } hex = "0.4.0" parking_lot = "0.11.1" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 229a273eabdc6..5c8aedc84c19d 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -53,7 +53,7 @@ sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index afa4622d2f05a..748037fef6448 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -26,7 +26,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 6f1fd3a035fec..4494beb2e3f41 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -25,7 +25,7 @@ rand = "0.7.2" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 5f7a2d2fb32bf..3c97677c3feec 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -23,7 +23,7 @@ log = "0.4.8" parking_lot = "0.11.1" thiserror = "1.0" -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-runtime = { path = "../../primitives/runtime", version = "4.0.0-dev" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 9d8461238fc06..1f1fe6b12aed1 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } futures = "0.3.16" jsonrpc-pubsub = "18.0.0" log = "0.4.8" -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } rpc = { package = "jsonrpc-core", version = "18.0.0" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } serde_json = "1.0.71" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 91143c45b4a23..25cd9026bc8b6 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -42,7 +42,7 @@ sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index c89442f3aec71..52f0ff6ecce0e 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -32,7 +32,7 @@ sc-network = { version = "0.10.0-dev", path = "../../network" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 8c059e80cdb26..6a5b8516237d9 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] parking_lot = "0.11.1" log = "0.4.11" sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } parity-util-mem-derive = "0.1.0" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 81710887b816d..4d91e61127db8 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -33,7 +33,7 @@ sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-tracing-proc-macro = { version = "4.0.0-dev", path = "./proc-macro" } sc-rpc-server = { version = "4.0.0-dev", path = "../rpc-servers" } diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index b3a7095fcb75d..6ed97edbf476e 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -23,7 +23,7 @@ parking_lot = "0.11.1" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 0f2e3cbf3d4e9..37ff7582f5c61 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -25,7 +25,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-std = { version = "4.0.0", path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 0c2d7616f57ed..54e579550443d 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -20,7 +20,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index 1252e7b51e00f..9ed07e724b30f 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -24,7 +24,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } [dev-dependencies] -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index c7b5abe350b88..1a0f5925732c8 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -28,7 +28,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 48a6c473875c0..2a0dc8bdd9a74 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -25,7 +25,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys impl-trait-for-tuples = "0.2.1" [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 077a8cb89a929..414cfcb222d40 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -36,7 +36,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } [features] diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index fe8d08ed9766c..66bb1c48a929f 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -32,12 +32,12 @@ log = { version = "0.4.14", default-features = false } # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking", optional = true, default-features = false } pallet-balances = { version = "4.0.0-dev", path = "../balances", optional = true, default-features = false } -sp-core = { version = "4.0.0", path = "../../primitives/core", optional = true, default-features = false } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core", optional = true, default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", optional = true, default-features = false } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing", optional = true, default-features = false } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core"} +sp-core = { version = "4.1.0-dev", path = "../../primitives/core"} sp-io = { version = "4.0.0-dev", path = "../../primitives/io"} sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 5a5b028285d88..646b47275c18b 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -22,7 +22,7 @@ frame-support = { path = "../../support", version = "4.0.0-dev" } # core sp-storage = { path = "../../../primitives/storage", version = "4.0.0" } -sp-core = { path = "../../../primitives/core", version = "4.0.0" } +sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } sp-tracing = { path = "../../../primitives/tracing", version = "4.0.0" } sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0-dev" } sp-std = { path = "../../../primitives/std", version = "4.0.0" } diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 825869c6b9725..1ac7b71fb3405 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -24,7 +24,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } [features] diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index cebd7a6d962b1..64cdf805db9a2 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -21,7 +21,7 @@ pallet-mmr = { version = "4.0.0-dev", path = "../merkle-mountain-range", default pallet-mmr-primitives = { version = "4.0.0-dev", path = "../merkle-mountain-range/primitives", default-features = false } pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } -sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 4bfd9f19b2806..c90f0d7328be0 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -23,7 +23,7 @@ pallet-session = { version = "4.0.0-dev", path = "../session", default-features beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", default-features = false } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 5dfa05bba0a07..97364ba41f63f 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -23,7 +23,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 37152e29d8f40..17cfc482af065 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -24,7 +24,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../bounties" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index 76799ae981c7a..6d3b081c89c1e 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = log = { version = "0.4.14", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index bb7a0693147b2..963f1466a9ea1 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -38,7 +38,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, path = "common" } pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../primitives/sandbox" } diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/common/Cargo.toml index ebfd5fab5af16..0e0cf1528b1a8 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/common/Cargo.toml @@ -19,7 +19,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] serde = { version = "1", features = ["derive"], optional = true } # Substrate Dependencies (This crate should not rely on frame) -sp-core = { version = "4.0.0", path = "../../../primitives/core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index aac5683a79e52..e380708a9dee4 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -24,7 +24,7 @@ pallet-contracts-primitives = { version = "4.0.0-dev", path = "../common" } pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index becec8a878d5d..32acdb964ed88 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -26,7 +26,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 42d7c4064cb30..a1df7edc13311 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -25,7 +25,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } @@ -43,7 +43,7 @@ strum_macros = { optional = true, version = "0.22.0" } [dev-dependencies] parking_lot = "0.11.0" rand = { version = "0.7.3" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index a69dca39b8e8f..80b7f9d7bfc05 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -24,7 +24,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys [dev-dependencies] sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index a5e9ca777c3ce..7ab81a4f33008 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -23,13 +23,13 @@ sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primiti frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] diff --git a/frame/elections/Cargo.toml b/frame/elections/Cargo.toml index e5f7d27d89113..d1404f7626129 100644 --- a/frame/elections/Cargo.toml +++ b/frame/elections/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 5edd3bfef8de5..db39d339f2c5c 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -26,7 +26,7 @@ sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../.. sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../../primitives/core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core", default-features = false } [features] default = ["std"] diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index 44886afba5e13..f53ea369278de 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -20,7 +20,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } diff --git a/frame/examples/parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml index 3d9104eb35451..d28dd5b9ee0ab 100644 --- a/frame/examples/parallel/Cargo.toml +++ b/frame/examples/parallel/Cargo.toml @@ -17,7 +17,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 9509fc5c977b5..d511bb858c7d6 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -23,11 +23,11 @@ sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../pr sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } [dev-dependencies] hex-literal = "0.3.4" -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index 14948546a1771..05e252627b2b7 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -24,7 +24,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys [dev-dependencies] sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index d052b468f9272..601ec9aee10ee 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index dc247727e0981..76a187f90c5d2 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -24,7 +24,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index fc0a6acf17981..fdafc5376ad5a 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -17,7 +17,7 @@ sp-application-crypto = { version = "4.0.0-dev", default-features = false, path pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index f4f5146ae1185..cd3957a45f824 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -19,7 +19,7 @@ sp-keyring = { version = "4.0.0-dev", optional = true, path = "../../primitives/ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index db317d0d01ec3..259be8267fe75 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -27,7 +27,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " [dev-dependencies] frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 105bdc55b5c01..d0567a3eeb15a 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 51b7e4a2a6071..fd6615a4b5420 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, version = "0.3.2" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index 11562c02bf325..0d11e50a8b682 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -17,7 +17,7 @@ log = { version = "0.4.14", default-features = false } serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 1cad739e3ba0e..7283a4fac8b2e 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -21,7 +21,7 @@ serde = { version = "1.0.126", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index bb6323bc5cb75..d01dd58a2f3f4 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -24,7 +24,7 @@ sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primiti frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 8d66bbb6b3973..28cabde09166d 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -22,7 +22,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index ec62d972d3a0c..efaaf6371f8c3 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 8957f0c88cae3..5058f17d38570 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -26,7 +26,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index 96674989e0f71..625f275a70ce0 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -37,7 +37,7 @@ frame-election-provider-support = { version = "4.0.0-dev", default-features = fa [dev-dependencies] pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } [features] diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index 762ab482b9854..7a1fc61da9d46 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -24,7 +24,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index 3bf2a9c30213b..903e167ef95a3 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -23,7 +23,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } [features] diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 18d4dfe7e47c9..c1126ad1edd13 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -22,7 +22,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 57eb5e16bd368..a1d43b359a888 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -22,7 +22,7 @@ log = { version = "0.4.14", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index 8f91908dddb9a..e77661204d733 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -23,7 +23,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 50aa623c90a82..909dfe329c9c0 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 5dc0573b278fb..37dc40e9b25cb 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -28,7 +28,7 @@ pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ [dev-dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } scale-info = "1.0" -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index 47ad0865b8f4f..cf14d7f9f51c5 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -22,7 +22,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys rand_chacha = { version = "0.2", default-features = false } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io ={ version = "4.0.0-dev", path = "../../primitives/io" } frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 70beead038b21..42fe1075317dd 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -38,7 +38,7 @@ rand_chacha = { version = "0.2", default-features = false, optional = true } [dev-dependencies] sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index d211d327b2d05..33642ef7dc3ee 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -22,7 +22,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 411b02449e4e2..c3eab98f9e779 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -21,7 +21,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 13d66d147e578..0cd3f9ac02913 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -20,7 +20,7 @@ sp-io = { version = "4.0.0-dev", path = "../../../primitives/io", default-featur sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../../../primitives/state-machine" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } -sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } trybuild = "1.0.52" diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index aa53f7ad358dd..b72bbc2f01f5b 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0", default-features = false, path = "../../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index fc510d1d9d792..0d771cd1f80d2 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.126", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 9468c8761435a..acf13c8f6b2a4 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -20,7 +20,7 @@ sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../.. frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } -sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } [dev-dependencies] sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 26554598be103..f8ff0a587b1a1 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -29,7 +29,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] sp-io ={ version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 565afcd3fbc66..cb682769ec858 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -18,7 +18,7 @@ log = { version = "0.4.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.126", features = ["derive"], optional = true } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 64e1d5c762ca7..642c9bd399b92 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -20,7 +20,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] serde = { version = "1.0.126", optional = true } smallvec = "1.7.0" -sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index cae6b7b914e17..21fae45282d03 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate dependencies -sp-core = { version = "4.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index dd18edf5daf0f..36dad610f696a 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -20,7 +20,7 @@ jsonrpc-derive = "18.0.0" sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 141aeb496ddec..f5ce6f8441663 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -29,7 +29,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " [dev-dependencies] sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = true, path = "../../primitives/transaction-storage-proof" } -sp-core = { version = "4.0.0", path = "../../primitives/core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } [features] default = ["std"] diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 4cbcb08c3ef68..fed6b98f55eb2 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -32,7 +32,7 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ [dev-dependencies] sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 7eddc85b67bbe..2ce0c1b484eaf 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -23,7 +23,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " [dev-dependencies] sp-std = { version = "4.0.0", path = "../../primitives/std" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index ac9254bd08546..9dfbd7b410ef4 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } @@ -25,7 +25,7 @@ sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primiti frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 5d66db1c981b9..30cdc91d44f38 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -26,7 +26,7 @@ log = { version = "0.4.0", default-features = false } [dev-dependencies] sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index d64da8ff84d7f..65e39571c7eb8 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../version" } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index dc2ca67242ac6..91675e941c78f 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -28,7 +28,7 @@ rustversion = "1.0.5" criterion = "0.3.0" futures = "0.3.9" log = "0.4.14" -sp-core = { version = "4.0.0", path = "../../core" } +sp-core = { version = "4.1.0-dev", path = "../../core" } [[bench]] name = "bench" diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index fd6dd87fa1b20..f3a9f9a938390 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.126", optional = true, features = ["derive"] } diff --git a/primitives/application-crypto/test/Cargo.toml b/primitives/application-crypto/test/Cargo.toml index 6ab3cfed0815d..dc51dceeeb4d1 100644 --- a/primitives/application-crypto/test/Cargo.toml +++ b/primitives/application-crypto/test/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0", default-features = false, path = "../../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } sp-keystore = { version = "0.10.0-dev", path = "../../keystore", default-features = false } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 4a1f844b92002..4391b1939d101 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -13,7 +13,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-api = { version = "4.0.0-dev", path = "../api", default-features = false } sp-application-crypto = { version = "4.0.0-dev", path = "../application-crypto", default-features = false } -sp-core = { version = "4.0.0", path = "../core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../core", default-features = false } sp-runtime = { version = "4.0.0-dev", path = "../runtime", default-features = false } sp-std = { version = "4.0.0", path = "../std", default-features = false } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index a07dc54e2979f..997744dd52bb0 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -22,7 +22,7 @@ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-consensus = { version = "0.10.0-dev", optional = true, path = "../common" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } sp-consensus-vrf = { version = "0.10.0-dev", path = "../vrf", default-features = false } -sp-core = { version = "4.0.0", default-features = false, path = "../../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../../keystore", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 4b5ef8796afa6..2ad4a08959355 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ ] } futures = { version = "0.3.1", features = ["thread-pool"] } log = "0.4.8" -sp-core = { path = "../../core", version = "4.0.0" } +sp-core = { path = "../../core", version = "4.1.0-dev" } sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } sp-state-machine = { version = "0.10.0-dev", path = "../../state-machine" } futures-timer = "3.0.1" diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index 1612868b3637c..d7f2b18e3fdbe 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } -sp-core = { version = "4.0.0", default-features = false, path = "../../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } [features] diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 97e426016d9a1..4eb545b08a21c 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { version = "2.0.0", package = "parity-scale-codec", default-features = false } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } sp-std = { version = "4.0.0", path = "../../std", default-features = false } -sp-core = { version = "4.0.0", path = "../../core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../../core", default-features = false } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } [features] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 5c805ff1dab88..a078cc09aafc3 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-core" -version = "4.0.0" +version = "4.1.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 4f21d62f5850d..dc08d69bf4183 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -460,6 +460,7 @@ pub trait Public: fn as_slice(&self) -> &[u8] { self.as_ref() } + /// Return `CryptoTypePublicPair` from public key. fn to_public_crypto_pair(&self) -> CryptoTypePublicPair; } @@ -709,6 +710,104 @@ mod dummy { } } +/// A secret uri (`SURI`) that can be used to generate a key pair. +/// +/// The `SURI` can be parsed from a string. The string is interpreted in the following way: +/// +/// - If `string` is a possibly `0x` prefixed 64-digit hex string, then it will be interpreted +/// directly as a `MiniSecretKey` (aka "seed" in `subkey`). +/// - If `string` is a valid BIP-39 key phrase of 12, 15, 18, 21 or 24 words, then the key will +/// be derived from it. In this case: +/// - the phrase may be followed by one or more items delimited by `/` characters. +/// - the path may be followed by `///`, in which case everything after the `///` is treated +/// as a password. +/// - If `string` begins with a `/` character it is prefixed with the Substrate public `DEV_PHRASE` +/// and interpreted as above. +/// +/// In this case they are interpreted as HDKD junctions; purely numeric items are interpreted as +/// integers, non-numeric items as strings. Junctions prefixed with `/` are interpreted as soft +/// junctions, and with `//` as hard junctions. +/// +/// There is no correspondence mapping between `SURI` strings and the keys they represent. +/// Two different non-identical strings can actually lead to the same secret being derived. +/// Notably, integer junction indices may be legally prefixed with arbitrary number of zeros. +/// Similarly an empty password (ending the `SURI` with `///`) is perfectly valid and will +/// generally be equivalent to no password at all. +/// +/// # Example +/// +/// Parse [`DEV_PHRASE`] secret uri with junction: +/// +/// ``` +/// # use sp_core::crypto::{SecretUri, DeriveJunction, DEV_PHRASE, ExposeSecret}; +/// # use std::str::FromStr; +/// let suri = SecretUri::from_str("//Alice").expect("Parse SURI"); +/// +/// assert_eq!(vec![DeriveJunction::from("Alice").harden()], suri.junctions); +/// assert_eq!(DEV_PHRASE, suri.phrase.expose_secret()); +/// assert!(suri.password.is_none()); +/// ``` +/// +/// Parse [`DEV_PHRASE`] secret ui with junction and password: +/// +/// ``` +/// # use sp_core::crypto::{SecretUri, DeriveJunction, DEV_PHRASE, ExposeSecret}; +/// # use std::str::FromStr; +/// let suri = SecretUri::from_str("//Alice///SECRET_PASSWORD").expect("Parse SURI"); +/// +/// assert_eq!(vec![DeriveJunction::from("Alice").harden()], suri.junctions); +/// assert_eq!(DEV_PHRASE, suri.phrase.expose_secret()); +/// assert_eq!("SECRET_PASSWORD", suri.password.unwrap().expose_secret()); +/// ``` +/// +/// Parse [`DEV_PHRASE`] secret ui with hex phrase and junction: +/// +/// ``` +/// # use sp_core::crypto::{SecretUri, DeriveJunction, DEV_PHRASE, ExposeSecret}; +/// # use std::str::FromStr; +/// let suri = SecretUri::from_str("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a//Alice").expect("Parse SURI"); +/// +/// assert_eq!(vec![DeriveJunction::from("Alice").harden()], suri.junctions); +/// assert_eq!("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a", suri.phrase.expose_secret()); +/// assert!(suri.password.is_none()); +/// ``` +#[cfg(feature = "std")] +pub struct SecretUri { + /// The phrase to derive the private key. + /// + /// This can either be a 64-bit hex string or a BIP-39 key phrase. + pub phrase: SecretString, + /// Optional password as given as part of the uri. + pub password: Option, + /// The junctions as part of the uri. + pub junctions: Vec, +} + +#[cfg(feature = "std")] +impl sp_std::str::FromStr for SecretUri { + type Err = SecretStringError; + + fn from_str(s: &str) -> Result { + let cap = SECRET_PHRASE_REGEX.captures(s).ok_or(SecretStringError::InvalidFormat)?; + + let junctions = JUNCTION_REGEX + .captures_iter(&cap["path"]) + .map(|f| DeriveJunction::from(&f[1])) + .collect::>(); + + let phrase = cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE); + let password = cap.name("password"); + + Ok(Self { + phrase: SecretString::from_str(phrase).expect("Returns infallible error; qed"), + password: password.map(|v| { + SecretString::from_str(v.as_str()).expect("Returns infallible error; qed") + }), + junctions, + }) + } +} + /// Trait suitable for typical cryptographic PKI key pair type. /// /// For now it just specifies how to create a key from a phrase and derivation path. @@ -821,14 +920,12 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { s: &str, password_override: Option<&str>, ) -> Result<(Self, Option), SecretStringError> { - let cap = SECRET_PHRASE_REGEX.captures(s).ok_or(SecretStringError::InvalidFormat)?; - - let path = JUNCTION_REGEX.captures_iter(&cap["path"]).map(|f| DeriveJunction::from(&f[1])); - - let phrase = cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE); - let password = password_override.or_else(|| cap.name("password").map(|m| m.as_str())); + use sp_std::str::FromStr; + let SecretUri { junctions, phrase, password } = SecretUri::from_str(s)?; + let password = + password_override.or_else(|| password.as_ref().map(|p| p.expose_secret().as_str())); - let (root, seed) = if let Some(stripped) = phrase.strip_prefix("0x") { + let (root, seed) = if let Some(stripped) = phrase.expose_secret().strip_prefix("0x") { hex::decode(stripped) .ok() .and_then(|seed_vec| { @@ -842,9 +939,11 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { }) .ok_or(SecretStringError::InvalidSeed)? } else { - Self::from_phrase(phrase, password).map_err(|_| SecretStringError::InvalidPhrase)? + Self::from_phrase(phrase.expose_secret().as_str(), password) + .map_err(|_| SecretStringError::InvalidPhrase)? }; - root.derive(path, Some(seed)).map_err(|_| SecretStringError::InvalidPath) + root.derive(junctions.into_iter(), Some(seed)) + .map_err(|_| SecretStringError::InvalidPath) } /// Interprets the string `s` in order to generate a key pair. diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index be4f3c6d1e3dc..fed861553bf0d 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -22,7 +22,7 @@ log = { version = "0.4.8", optional = true } serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../keystore", optional = true } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index c531ad4e5764f..82c4f21b5c07f 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-runtime = { version = "4.0.0-dev", path = "../runtime", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 520dc12a52603..4485a8a7f45a2 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } hash-db = { version = "0.15.2", default-features = false } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-keystore = { version = "0.10.0-dev", default-features = false, optional = true, path = "../keystore" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } libsecp256k1 = { version = "0.7", optional = true } diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 66c1240a8a567..be7d138979a1c 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0", path = "../core" } +sp-core = { version = "4.1.0-dev", path = "../core" } sp-runtime = { version = "4.0.0-dev", path = "../runtime" } lazy_static = "1.4.0" strum = { version = "0.22.0", features = ["derive"] } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index b0061ac111e20..7994c67b4c51c 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -21,7 +21,7 @@ schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backen merlin = { version = "2.0", default-features = false } parking_lot = { version = "0.11.1", default-features = false } serde = { version = "1.0", optional = true} -sp-core = { version = "4.0.0", path = "../core" } +sp-core = { version = "4.1.0-dev", path = "../core" } sp-externalities = { version = "0.10.0", path = "../externalities", default-features = false } [dev-dependencies] diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 16aca8dc71d9c..a418cda2feef1 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -19,7 +19,7 @@ serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../arithmetic" } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-runtime = { version = "4.0.0-dev", path = "../runtime", default-features = false } [dev-dependencies] diff --git a/primitives/offchain/Cargo.toml b/primitives/offchain/Cargo.toml index f079ccb7913fe..55de9177e45df 100644 --- a/primitives/offchain/Cargo.toml +++ b/primitives/offchain/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index 59cbf53fee2a1..e16280f95d35d 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.126", features = ["derive"] } -sp-core = { version = "4.0.0", path = "../core" } +sp-core = { version = "4.1.0-dev", path = "../core" } rustc-hash = "1.1.0" [dev-dependencies] diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 64781481fa12a..6b120ab50c502 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -28,7 +28,7 @@ impl-trait-for-tuples = "0.2.1" [dev-dependencies] sp-runtime-interface-test-wasm = { version = "2.0.0", path = "test-wasm" } sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } -sp-core = { version = "4.0.0", path = "../core" } +sp-core = { version = "4.1.0-dev", path = "../core" } sp-io = { version = "4.0.0-dev", path = "../io" } rustversion = "1.0.5" trybuild = "1.0.52" diff --git a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 68ed8a73282aa..02fb75d108fd3 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../io" } -sp-core = { version = "4.0.0", default-features = false, path = "../../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index ab227ddeda277..24fdb88429634 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../io" } -sp-core = { version = "4.0.0", default-features = false, path = "../../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 76c1d94a3b6df..1d7c79ba68c98 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.126", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../arithmetic" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index a51873dc1e998..a94ba0f375f8c 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -20,7 +20,7 @@ wasmi = "0.9.0" [dependencies] wasmi = { version = "0.9.0", optional = true } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } sp-wasm-interface = { version = "4.0.0", default-features = false, path = "../wasm-interface" } diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index eda98b2ab6a8e..d402f36859ac4 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" } sp-runtime = { version = "4.0.0-dev", optional = true, path = "../runtime" } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index f5047c3c7c464..b6b3c90f5a7f5 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -21,7 +21,7 @@ hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.22.6", default-features = false } trie-root = { version = "0.16.0", default-features = false } sp-trie = { version = "4.0.0-dev", path = "../trie", default-features = false } -sp-core = { version = "4.0.0", path = "../core", default-features = false } +sp-core = { version = "4.1.0-dev", path = "../core", default-features = false } sp-panic-handler = { version = "4.0.0-dev", path = "../panic-handler", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } num-traits = { version = "0.2.8", default-features = false } diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index 9a80cc50cf2ff..c154d1c92dca8 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.8", optional = true } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../runtime-interface" } diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index ea1e61c8da112..18a0b9501e187 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index 05da54b24f787..f2ea55cc18c51 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -17,7 +17,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inh sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-trie = { version = "4.0.0-dev", optional = true, path = "../trie" } -sp-core = { version = "4.0.0", path = "../core", optional = true } +sp-core = { version = "4.1.0-dev", path = "../core", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.8", optional = true } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index af81164ed799d..983d58c9bb8d2 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -25,7 +25,7 @@ hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.22.6", default-features = false } trie-root = { version = "0.16.0", default-features = false } memory-db = { version = "0.27.0", default-features = false } -sp-core = { version = "4.0.0", default-features = false, path = "../core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } [dev-dependencies] trie-bench = "0.28.0" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 3917f3fefcf9b..9b77cde505af7 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -29,7 +29,7 @@ sc-service = { version = "0.10.0-dev", default-features = false, features = [ ], path = "../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-core = { version = "4.0.0", path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 35c14a23f2a20..3be0e40b0b6ba 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -23,7 +23,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-keyring = { version = "4.0.0-dev", optional = true, path = "../../primitives/keyring" } memory-db = { version = "0.27.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } -sp-core = { version = "4.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../../primitives/runtime-interface" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index 6dd22e4954c2d..b66fdc3422ae5 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -16,7 +16,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } substrate-test-client = { version = "2.0.0", path = "../../client" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } substrate-test-runtime = { version = "2.0.0", path = "../../runtime" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 2943877ce4a04..c8d762ec73cd9 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index 6c3cb04282849..feb02f1eb7213 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" [dependencies] -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } structopt = "0.3.25" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index ab91f26490178..0cf4980a104c8 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -23,7 +23,7 @@ serde_json = "1.0" serde = "1.0.126" sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } -sp-core = { version = "4.0.0", path = "../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 5fc3812b84da4..f71f3d6e93e14 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -23,7 +23,7 @@ log = "0.4.8" sp-runtime = { version = "4.0.0-dev", path = "../../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } -sp-core = { version = "4.0.0", path = "../../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../../client/transaction-pool/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../../primitives/block-builder" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 71db6100ca175..d6b75d31fac8e 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -24,7 +24,7 @@ sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sp-state-machine = { version = "0.10.0-dev", path = "../../../../primitives/state-machine" } sp-runtime = { version = "4.0.0-dev", path = "../../../../primitives/runtime" } -sp-core = { version = "4.0.0", path = "../../../../primitives/core" } +sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../../primitives/io" } sp-keystore = { version = "0.10.0-dev", path = "../../../../primitives/keystore" } sp-externalities = { version = "0.10.0", path = "../../../../primitives/externalities" } From 4d24ae04ec8c60fe7eca069df09d1ac0a636a80c Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sat, 11 Dec 2021 15:55:23 +0100 Subject: [PATCH 0329/1472] Preimage registrar and Scheduler integration (#10356) * initial idea * more * fix compile * add clear and request logic * improve some docs * Add and implement trait * continuing to improve * refcount type * infallible system preimage upload * fmt * fix requests * Make it simple * Make it simple * Formatting * Initial draft * request when scheduled * Docs * Scheduler good * Scheduler good * Scheduler tests working * Add new files * Missing stuff * Repotting, add weights. * Add some tests to preimage pallet * More tests * Fix benchmarks * preimage benchmarks * All preimage benchmarks * Tidy cargo * Update weights.rs * Allow hash provision in benchmarks * Initial work on new benchmarks for Scheduler * Tests working, refactor looks good * Tests for new Scheduler functionality * Use real weight, make tests work with runtimes without Preimage * Rename * Update benchmarks * Formatting * Formatting * Fix weird formatting * Update frame/preimage/src/lib.rs * Fix try-runtime build * Fixes * Fixes * Update frame/support/src/traits/tokens/currency.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/src/traits/tokens/currency/reservable.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/src/traits/tokens/imbalance.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/preimage/src/mock.rs Co-authored-by: Guillaume Thiolliere * Update frame/scheduler/src/lib.rs Co-authored-by: Guillaume Thiolliere * Update frame/preimage/src/lib.rs * Fixes * Fixes * Formatting * Fixes * Fixes * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_scheduler --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/scheduler/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_preimage --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/preimage/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Shawn Tabrizi Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Guillaume Thiolliere Co-authored-by: Parity Bot --- Cargo.lock | 18 + Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 32 +- frame/democracy/src/tests.rs | 2 + frame/preimage/Cargo.toml | 46 + frame/preimage/src/benchmarking.rs | 161 ++ frame/preimage/src/lib.rs | 347 +++++ frame/preimage/src/mock.rs | 131 ++ frame/preimage/src/tests.rs | 233 +++ frame/preimage/src/weights.rs | 238 +++ frame/scheduler/Cargo.toml | 37 +- frame/scheduler/src/benchmarking.rs | 214 ++- frame/scheduler/src/lib.rs | 1383 ++++------------- frame/scheduler/src/mock.rs | 203 +++ frame/scheduler/src/tests.rs | 901 +++++++++++ frame/scheduler/src/weights.rs | 275 +++- frame/support/src/traits.rs | 4 +- frame/support/src/traits/misc.rs | 65 + frame/support/src/traits/schedule.rs | 401 ++++- frame/support/src/traits/tokens/currency.rs | 88 ++ .../src/traits/tokens/currency/reservable.rs | 27 + frame/support/src/traits/tokens/imbalance.rs | 52 + frame/system/src/lib.rs | 18 +- 24 files changed, 3593 insertions(+), 1288 deletions(-) create mode 100644 frame/preimage/Cargo.toml create mode 100644 frame/preimage/src/benchmarking.rs create mode 100644 frame/preimage/src/lib.rs create mode 100644 frame/preimage/src/mock.rs create mode 100644 frame/preimage/src/tests.rs create mode 100644 frame/preimage/src/weights.rs create mode 100644 frame/scheduler/src/mock.rs create mode 100644 frame/scheduler/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 612cbdc8b0def..ab8132c6b7cd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4721,6 +4721,7 @@ dependencies = [ "pallet-multisig", "pallet-offences", "pallet-offences-benchmarking", + "pallet-preimage", "pallet-proxy", "pallet-randomness-collective-flip", "pallet-recovery", @@ -5912,6 +5913,22 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-preimage" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-proxy" version = "4.0.0-dev" @@ -5967,6 +5984,7 @@ dependencies = [ "frame-support", "frame-system", "log 0.4.14", + "pallet-preimage", "parity-scale-codec", "scale-info", "sp-core", diff --git a/Cargo.toml b/Cargo.toml index 7bb08345c0fe2..a26652e39774a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -102,6 +102,7 @@ members = [ "frame/nicks", "frame/node-authorization", "frame/offences", + "frame/preimage", "frame/proxy", "frame/randomness-collective-flip", "frame/recovery", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 32dcc003e879a..83a66f5a47b6d 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -78,6 +78,7 @@ pallet-mmr = { version = "4.0.0-dev", default-features = false, path = "../../.. pallet-multisig = { version = "4.0.0-dev", default-features = false, path = "../../../frame/multisig" } pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../../frame/offences" } pallet-offences-benchmarking = { version = "4.0.0-dev", path = "../../../frame/offences/benchmarking", default-features = false, optional = true } +pallet-preimage = { version = "4.0.0-dev", default-features = false, path = "../../../frame/preimage" } pallet-proxy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/proxy" } pallet-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/randomness-collective-flip" } pallet-recovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/recovery" } @@ -141,6 +142,7 @@ std = [ "node-primitives/std", "sp-offchain/std", "pallet-offences/std", + "pallet-preimage/std", "pallet-proxy/std", "sp-core/std", "pallet-randomness-collective-flip/std", @@ -202,6 +204,7 @@ runtime-benchmarks = [ "pallet-membership/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-society/runtime-benchmarks", @@ -243,6 +246,7 @@ try-runtime = [ "pallet-identity/try-runtime", "pallet-scheduler/try-runtime", "pallet-offences/try-runtime", + "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", "pallet-randomness-collective-flip/try-runtime", "pallet-session/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3134f25cfb265..bd4bb450c7492 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -337,6 +337,8 @@ parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; pub const MaxScheduledPerBlock: u32 = 50; + // Retry a scheduled item every 10 blocks (1 minute) until the preimage exists. + pub const NoPreimagePostponement: Option = Some(10); } impl pallet_scheduler::Config for Runtime { @@ -349,6 +351,25 @@ impl pallet_scheduler::Config for Runtime { type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; + type PreimageProvider = Preimage; + type NoPreimagePostponement = NoPreimagePostponement; +} + +parameter_types! { + pub const PreimageMaxSize: u32 = 4096 * 1024; + pub const PreimageBaseDeposit: Balance = 1 * DOLLARS; + // One cent: $10,000 / MB + pub const PreimageByteDeposit: Balance = 1 * CENTS; +} + +impl pallet_preimage::Config for Runtime { + type WeightInfo = pallet_preimage::weights::SubstrateWeight; + type Event = Event; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type MaxSize = PreimageMaxSize; + type BaseDeposit = PreimageBaseDeposit; + type ByteDeposit = PreimageByteDeposit; } parameter_types! { @@ -688,8 +709,6 @@ parameter_types! { pub const MinimumDeposit: Balance = 100 * DOLLARS; pub const EnactmentPeriod: BlockNumber = 30 * 24 * 60 * MINUTES; pub const CooloffPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; - // One cent: $10,000 / MB - pub const PreimageByteDeposit: Balance = 1 * CENTS; pub const MaxVotes: u32 = 100; pub const MaxProposals: u32 = 100; } @@ -1307,6 +1326,7 @@ construct_runtime!( Recovery: pallet_recovery, Vesting: pallet_vesting, Scheduler: pallet_scheduler, + Preimage: pallet_preimage, Proxy: pallet_proxy, Multisig: pallet_multisig, Bounties: pallet_bounties, @@ -1686,6 +1706,7 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_mmr, Mmr); list_benchmark!(list, extra, pallet_multisig, Multisig); list_benchmark!(list, extra, pallet_offences, OffencesBench::); + list_benchmark!(list, extra, pallet_preimage, Preimage); list_benchmark!(list, extra, pallet_proxy, Proxy); list_benchmark!(list, extra, pallet_scheduler, Scheduler); list_benchmark!(list, extra, pallet_session, SessionBench::); @@ -1764,6 +1785,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_mmr, Mmr); add_benchmark!(params, batches, pallet_multisig, Multisig); add_benchmark!(params, batches, pallet_offences, OffencesBench::); + add_benchmark!(params, batches, pallet_preimage, Preimage); add_benchmark!(params, batches, pallet_proxy, Proxy); add_benchmark!(params, batches, pallet_scheduler, Scheduler); add_benchmark!(params, batches, pallet_session, SessionBench::); @@ -1811,11 +1833,13 @@ mod tests { #[test] fn call_size() { + let size = core::mem::size_of::(); assert!( - core::mem::size_of::() <= 200, - "size of Call is more than 200 bytes: some calls have too big arguments, use Box to reduce the + size <= 200, + "size of Call {} is more than 200 bytes: some calls have too big arguments, use Box to reduce the size of Call. If the limit is too strong, maybe consider increase the limit to 300.", + size, ); } } diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 3c223172987e8..839478a5b8d94 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -120,6 +120,8 @@ impl pallet_scheduler::Config for Test { type MaxScheduledPerBlock = (); type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; + type PreimageProvider = (); + type NoPreimagePostponement = (); } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml new file mode 100644 index 0000000000000..b60c3fa854871 --- /dev/null +++ b/frame/preimage/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "pallet-preimage" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet for storing preimages of hashes" +readme = "README.md" + +[dependencies] +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } + +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-core = { version = "4.1.0-dev", default-features = false, optional = true, path = "../../primitives/core" } +sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } + +[dev-dependencies] +sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } +pallet-balances = { version = "4.0.0-dev", path = "../balances" } + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] +std = [ + "codec/std", + "scale-info/std", + "sp-std/std", + "sp-io/std", + "sp-core/std", + "sp-runtime/std", + "frame-system/std", + "frame-support/std", + "frame-benchmarking/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs new file mode 100644 index 0000000000000..c18c27555025d --- /dev/null +++ b/frame/preimage/src/benchmarking.rs @@ -0,0 +1,161 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Preimage pallet benchmarking. + +use super::*; +use frame_benchmarking::{account, benchmarks, whitelist_account}; +use frame_support::assert_ok; +use frame_system::RawOrigin; +use sp_runtime::traits::Bounded; +use sp_std::{prelude::*, vec}; + +use crate::Pallet as Preimage; + +const SEED: u32 = 0; + +fn funded_account(name: &'static str, index: u32) -> T::AccountId { + let caller: T::AccountId = account(name, index, SEED); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + caller +} + +fn preimage_and_hash() -> (Vec, T::Hash) { + sized_preimage_and_hash::(T::MaxSize::get()) +} + +fn sized_preimage_and_hash(size: u32) -> (Vec, T::Hash) { + let mut preimage = vec![]; + preimage.resize(size as usize, 0); + let hash = ::Hashing::hash(&preimage[..]); + (preimage, hash) +} + +benchmarks! { + // Expensive note - will reserve. + note_preimage { + let s in 0 .. T::MaxSize::get(); + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + let (preimage, hash) = sized_preimage_and_hash::(s); + }: _(RawOrigin::Signed(caller), preimage) + verify { + assert!(Preimage::::have_preimage(&hash)); + } + // Cheap note - will not reserve since it was requested. + note_requested_preimage { + let s in 0 .. T::MaxSize::get(); + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + let (preimage, hash) = sized_preimage_and_hash::(s); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + }: note_preimage(RawOrigin::Signed(caller), preimage) + verify { + assert!(Preimage::::have_preimage(&hash)); + } + // Cheap note - will not reserve since it's the manager. + note_no_deposit_preimage { + let s in 0 .. T::MaxSize::get(); + let (preimage, hash) = sized_preimage_and_hash::(s); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + }: note_preimage(T::ManagerOrigin::successful_origin(), preimage) + verify { + assert!(Preimage::::have_preimage(&hash)); + } + + // Expensive unnote - will unreserve. + unnote_preimage { + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + let (preimage, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(caller.clone()).into(), preimage)); + }: _(RawOrigin::Signed(caller), hash.clone()) + verify { + assert!(!Preimage::::have_preimage(&hash)); + } + // Cheap unnote - will not unreserve since there's no deposit held. + unnote_no_deposit_preimage { + let (preimage, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); + }: unnote_preimage(T::ManagerOrigin::successful_origin(), hash.clone()) + verify { + assert!(!Preimage::::have_preimage(&hash)); + } + + // Expensive request - will unreserve the noter's deposit. + request_preimage { + let (preimage, hash) = preimage_and_hash::(); + let noter = funded_account::("noter", 0); + whitelist_account!(noter); + assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter).into(), preimage)); + }: _(T::ManagerOrigin::successful_origin(), hash) + verify { + assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + } + // Cheap request - would unreserve the deposit but none was held. + request_no_deposit_preimage { + let (preimage, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + verify { + assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + } + // Cheap request - the preimage is not yet noted, so deposit to unreserve. + request_unnoted_preimage { + let (_, hash) = preimage_and_hash::(); + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + verify { + assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + } + // Cheap request - the preimage is already requested, so just a counter bump. + request_requested_preimage { + let (_, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + verify { + assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(2))); + } + + // Expensive unrequest - last reference and it's noted, so will destroy the preimage. + unrequest_preimage { + let (preimage, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); + }: _(T::ManagerOrigin::successful_origin(), hash.clone()) + verify { + assert_eq!(StatusFor::::get(&hash), None); + } + // Cheap unrequest - last reference, but it's not noted. + unrequest_unnoted_preimage { + let (_, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash.clone()) + verify { + assert_eq!(StatusFor::::get(&hash), None); + } + // Cheap unrequest - not the last reference. + unrequest_multi_referenced_preimage { + let (_, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash.clone()) + verify { + assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + } + + impl_benchmark_test_suite!(Preimage, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs new file mode 100644 index 0000000000000..bfa1ce5263360 --- /dev/null +++ b/frame/preimage/src/lib.rs @@ -0,0 +1,347 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Preimage Pallet +//! +//! - [`Config`] +//! - [`Call`] +//! +//! ## Overview +//! +//! The Preimage pallet allows for the users and the runtime to store the preimage +//! of a hash on chain. This can be used by other pallets where storing and managing +//! large byte-blobs. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; +pub mod weights; + +use sp_runtime::traits::{BadOrigin, Hash, Saturating}; +use sp_std::{convert::TryFrom, prelude::*}; + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + ensure, + pallet_prelude::Get, + traits::{Currency, PreimageProvider, PreimageRecipient, ReservableCurrency}, + weights::Pays, + BoundedVec, +}; +use scale_info::TypeInfo; +use weights::WeightInfo; + +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +pub use pallet::*; + +/// A type to note whether a preimage is owned by a user or the system. +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum RequestStatus { + /// The associated preimage has not yet been requested by the system. The given deposit (if + /// some) is being held until either it becomes requested or the user retracts the primage. + Unrequested(Option<(AccountId, Balance)>), + /// There are a non-zero number of outstanding requests for this hash by this chain. If there + /// is a preimage registered, then it may be removed iff this counter becomes zero. + Requested(u32), +} + +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// The Weight information for this pallet. + type WeightInfo: weights::WeightInfo; + + /// Currency type for this pallet. + type Currency: ReservableCurrency; + + /// An origin that can request a preimage be placed on-chain without a deposit or fee, or + /// manage existing preimages. + type ManagerOrigin: EnsureOrigin; + + /// Max size allowed for a preimage. + type MaxSize: Get; + + /// The base deposit for placing a preimage on chain. + type BaseDeposit: Get>; + + /// The per-byte deposit for placing a preimage on chain. + type ByteDeposit: Get>; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] + pub struct Pallet(PhantomData); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A preimage has been noted. + Noted { hash: T::Hash }, + /// A preimage has been requested. + Requested { hash: T::Hash }, + /// A preimage has ben cleared. + Cleared { hash: T::Hash }, + } + + #[pallet::error] + pub enum Error { + /// Preimage is too large to store on-chain. + TooLarge, + /// Preimage has already been noted on-chain. + AlreadyNoted, + /// The user is not authorized to perform this action. + NotAuthorized, + /// The preimage cannot be removed since it has not yet been noted. + NotNoted, + /// A preimage may not be removed when there are outstanding requests. + Requested, + /// The preimage request cannot be removed since no outstanding requests exist. + NotRequested, + } + + /// The request status of a given hash. + #[pallet::storage] + pub(super) type StatusFor = + StorageMap<_, Identity, T::Hash, RequestStatus>>; + + /// The preimages stored by this pallet. + #[pallet::storage] + pub(super) type PreimageFor = + StorageMap<_, Identity, T::Hash, BoundedVec>; + + #[pallet::call] + impl Pallet { + /// Register a preimage on-chain. + /// + /// If the preimage was previously requested, no fees or deposits are taken for providing + /// the preimage. Otherwise, a deposit is taken proportional to the size of the preimage. + #[pallet::weight(T::WeightInfo::note_preimage(bytes.len() as u32))] + pub fn note_preimage(origin: OriginFor, bytes: Vec) -> DispatchResultWithPostInfo { + // We accept a signed origin which will pay a deposit, or a root origin where a deposit + // is not taken. + let maybe_sender = Self::ensure_signed_or_manager(origin)?; + let bounded_vec = + BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; + let system_requested = Self::note_bytes(bounded_vec, maybe_sender.as_ref())?; + if system_requested || maybe_sender.is_none() { + Ok(Pays::No.into()) + } else { + Ok(().into()) + } + } + + /// Clear an unrequested preimage from the runtime storage. + #[pallet::weight(T::WeightInfo::unnote_preimage())] + pub fn unnote_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { + let maybe_sender = Self::ensure_signed_or_manager(origin)?; + Self::do_unnote_preimage(&hash, maybe_sender) + } + + /// Request a preimage be uploaded to the chain without paying any fees or deposits. + /// + /// If the preimage requests has already been provided on-chain, we unreserve any deposit + /// a user may have paid, and take the control of the preimage out of their hands. + #[pallet::weight(T::WeightInfo::request_preimage())] + pub fn request_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { + T::ManagerOrigin::ensure_origin(origin)?; + Self::do_request_preimage(&hash); + Ok(()) + } + + /// Clear a previously made request for a preimage. + /// + /// NOTE: THIS MUST NOT BE CALLED ON `hash` MORE TIMES THAN `request_preimage`. + #[pallet::weight(T::WeightInfo::unrequest_preimage())] + pub fn unrequest_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { + T::ManagerOrigin::ensure_origin(origin)?; + Self::do_unrequest_preimage(&hash) + } + } +} + +impl Pallet { + /// Ensure that the origin is either the `ManagerOrigin` or a signed origin. + fn ensure_signed_or_manager(origin: T::Origin) -> Result, BadOrigin> { + if T::ManagerOrigin::ensure_origin(origin.clone()).is_ok() { + return Ok(None) + } + let who = ensure_signed(origin)?; + Ok(Some(who)) + } + + /// Store some preimage on chain. + /// + /// We verify that the preimage is within the bounds of what the pallet supports. + /// + /// If the preimage was requested to be uploaded, then the user pays no deposits or tx fees. + fn note_bytes( + preimage: BoundedVec, + maybe_depositor: Option<&T::AccountId>, + ) -> Result { + let hash = T::Hashing::hash(&preimage); + ensure!(!PreimageFor::::contains_key(hash), Error::::AlreadyNoted); + + // We take a deposit only if there is a provided depositor, and the preimage was not + // previously requested. This also allows the tx to pay no fee. + let was_requested = match (StatusFor::::get(hash), maybe_depositor) { + (Some(RequestStatus::Requested(..)), _) => true, + (Some(RequestStatus::Unrequested(..)), _) => Err(Error::::AlreadyNoted)?, + (None, None) => { + StatusFor::::insert(hash, RequestStatus::Unrequested(None)); + false + }, + (None, Some(depositor)) => { + let length = preimage.len() as u32; + let deposit = T::BaseDeposit::get() + .saturating_add(T::ByteDeposit::get().saturating_mul(length.into())); + T::Currency::reserve(depositor, deposit)?; + let status = RequestStatus::Unrequested(Some((depositor.clone(), deposit))); + StatusFor::::insert(hash, status); + false + }, + }; + + PreimageFor::::insert(hash, preimage); + Self::deposit_event(Event::Noted { hash }); + + Ok(was_requested) + } + + // This function will add a hash to the list of requested preimages. + // + // If the preimage already exists before the request is made, the deposit for the preimage is + // returned to the user, and removed from their management. + fn do_request_preimage(hash: &T::Hash) { + let count = StatusFor::::get(hash).map_or(1, |x| match x { + RequestStatus::Requested(mut count) => { + count.saturating_inc(); + count + }, + RequestStatus::Unrequested(None) => 1, + RequestStatus::Unrequested(Some((owner, deposit))) => { + // Return the deposit - the preimage now has outstanding requests. + T::Currency::unreserve(&owner, deposit); + 1 + }, + }); + StatusFor::::insert(hash, RequestStatus::Requested(count)); + if count == 1 { + Self::deposit_event(Event::Requested { hash: hash.clone() }); + } + } + + // Clear a preimage from the storage of the chain, returning any deposit that may be reserved. + // + // If `maybe_owner` is provided, we verify that it is the correct owner before clearing the + // data. + fn do_unnote_preimage( + hash: &T::Hash, + maybe_check_owner: Option, + ) -> DispatchResult { + match StatusFor::::get(hash).ok_or(Error::::NotNoted)? { + RequestStatus::Unrequested(Some((owner, deposit))) => { + ensure!( + maybe_check_owner.map_or(true, |c| &c == &owner), + Error::::NotAuthorized + ); + T::Currency::unreserve(&owner, deposit); + }, + RequestStatus::Unrequested(None) => { + ensure!(maybe_check_owner.is_none(), Error::::NotAuthorized); + }, + RequestStatus::Requested(_) => Err(Error::::Requested)?, + } + StatusFor::::remove(hash); + PreimageFor::::remove(hash); + Self::deposit_event(Event::Cleared { hash: hash.clone() }); + Ok(()) + } + + /// Clear a preimage request. + fn do_unrequest_preimage(hash: &T::Hash) -> DispatchResult { + match StatusFor::::get(hash).ok_or(Error::::NotRequested)? { + RequestStatus::Requested(mut count) if count > 1 => { + count.saturating_dec(); + StatusFor::::insert(hash, RequestStatus::Requested(count)); + }, + RequestStatus::Requested(count) => { + debug_assert!(count == 1, "preimage request counter at zero?"); + PreimageFor::::remove(hash); + StatusFor::::remove(hash); + Self::deposit_event(Event::Cleared { hash: hash.clone() }); + }, + RequestStatus::Unrequested(_) => Err(Error::::NotRequested)?, + } + Ok(()) + } +} + +impl PreimageProvider for Pallet { + fn have_preimage(hash: &T::Hash) -> bool { + PreimageFor::::contains_key(hash) + } + + fn preimage_requested(hash: &T::Hash) -> bool { + matches!(StatusFor::::get(hash), Some(RequestStatus::Requested(..))) + } + + fn get_preimage(hash: &T::Hash) -> Option> { + PreimageFor::::get(hash).map(|preimage| preimage.to_vec()) + } + + fn request_preimage(hash: &T::Hash) { + Self::do_request_preimage(hash) + } + + fn unrequest_preimage(hash: &T::Hash) { + let res = Self::do_unrequest_preimage(hash); + debug_assert!(res.is_ok(), "do_unrequest_preimage failed - counter underflow?"); + } +} + +impl PreimageRecipient for Pallet { + type MaxSize = T::MaxSize; + + fn note_preimage(bytes: BoundedVec) { + // We don't really care if this fails, since that's only the case if someone else has + // already noted it. + let _ = Self::note_bytes(bytes, None); + } + + fn unnote_preimage(hash: &T::Hash) { + // Should never fail if authorization check is skipped. + let res = Self::do_unnote_preimage(hash, None); + debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?"); + } +} diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs new file mode 100644 index 0000000000000..601f72547237b --- /dev/null +++ b/frame/preimage/src/mock.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Scheduler test environment. + +use super::*; + +use crate as pallet_preimage; +use frame_support::{ + ord_parameter_types, parameter_types, traits::Everything, weights::constants::RocksDbWeight, +}; +use frame_system::EnsureSignedBy; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Balances: pallet_balances, + Preimage: pallet_preimage, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); +} +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = RocksDbWeight; + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 5; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Test { + type Balance = u64; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; + pub const MaxScheduledPerBlock: u32 = 10; + pub const MaxSize: u32 = 1024; + pub const BaseDeposit: u64 = 2; + pub const ByteDeposit: u64 = 1; +} + +ord_parameter_types! { + pub const One: u64 = 1; +} + +impl Config for Test { + type WeightInfo = (); + type Event = Event; + type Currency = Balances; + type ManagerOrigin = EnsureSignedBy; + type MaxSize = MaxSize; + type BaseDeposit = BaseDeposit; + type ByteDeposit = ByteDeposit; +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let balances = pallet_balances::GenesisConfig:: { + balances: vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)], + }; + balances.assimilate_storage(&mut t).unwrap(); + t.into() +} + +pub fn hashed(data: impl AsRef<[u8]>) -> H256 { + BlakeTwo256::hash(data.as_ref()) +} diff --git a/frame/preimage/src/tests.rs b/frame/preimage/src/tests.rs new file mode 100644 index 0000000000000..528b263303715 --- /dev/null +++ b/frame/preimage/src/tests.rs @@ -0,0 +1,233 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Scheduler tests. + +use super::*; +use crate::mock::*; + +use frame_support::{assert_noop, assert_ok}; +use pallet_balances::Error as BalancesError; + +#[test] +fn user_note_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_eq!(Balances::reserved_balance(2), 3); + assert_eq!(Balances::free_balance(2), 97); + + let h = hashed([1]); + assert!(Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + + assert_noop!( + Preimage::note_preimage(Origin::signed(2), vec![1]), + Error::::AlreadyNoted + ); + assert_noop!( + Preimage::note_preimage(Origin::signed(0), vec![2]), + BalancesError::::InsufficientBalance + ); + }); +} + +#[test] +fn manager_note_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::free_balance(1), 100); + + let h = hashed([1]); + assert!(Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + + assert_noop!( + Preimage::note_preimage(Origin::signed(1), vec![1]), + Error::::AlreadyNoted + ); + }); +} + +#[test] +fn user_unnote_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(3), hashed([1])), + Error::::NotAuthorized + ); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(2), hashed([2])), + Error::::NotNoted + ); + + assert_ok!(Preimage::unnote_preimage(Origin::signed(2), hashed([1]))); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(2), hashed([1])), + Error::::NotNoted + ); + + let h = hashed([1]); + assert!(!Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), None); + }); +} + +#[test] +fn manager_unnote_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_ok!(Preimage::unnote_preimage(Origin::signed(1), hashed([1]))); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(1), hashed([1])), + Error::::NotNoted + ); + + let h = hashed([1]); + assert!(!Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), None); + }); +} + +#[test] +fn manager_unnote_user_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(3), hashed([1])), + Error::::NotAuthorized + ); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(2), hashed([2])), + Error::::NotNoted + ); + + assert_ok!(Preimage::unnote_preimage(Origin::signed(1), hashed([1]))); + + let h = hashed([1]); + assert!(!Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), None); + }); +} + +#[test] +fn requested_then_noted_preimage_cannot_be_unnoted() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(1), hashed([1])), + Error::::Requested + ); + + let h = hashed([1]); + assert!(Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + }); +} + +#[test] +fn request_note_order_makes_no_difference() { + let one_way = new_test_ext().execute_with(|| { + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + ( + StatusFor::::iter().collect::>(), + PreimageFor::::iter().collect::>(), + ) + }); + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + let other_way = ( + StatusFor::::iter().collect::>(), + PreimageFor::::iter().collect::>(), + ); + assert_eq!(one_way, other_way); + }); +} + +#[test] +fn requested_then_user_noted_preimage_is_free() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::free_balance(2), 100); + + let h = hashed([1]); + assert!(Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + }); +} + +#[test] +fn request_user_note_order_makes_no_difference() { + let one_way = new_test_ext().execute_with(|| { + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + ( + StatusFor::::iter().collect::>(), + PreimageFor::::iter().collect::>(), + ) + }); + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + let other_way = ( + StatusFor::::iter().collect::>(), + PreimageFor::::iter().collect::>(), + ); + assert_eq!(one_way, other_way); + }); +} + +#[test] +fn unrequest_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_noop!( + Preimage::unrequest_preimage(Origin::signed(1), hashed([2])), + Error::::NotRequested + ); + + assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + assert!(Preimage::have_preimage(&hashed([1]))); + + assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + assert_noop!( + Preimage::unrequest_preimage(Origin::signed(1), hashed([1])), + Error::::NotRequested + ); + }); +} + +#[test] +fn user_noted_then_requested_preimage_is_refunded_once_only() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1; 3])); + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + // Still have reserve from `vec[1; 3]`. + assert_eq!(Balances::reserved_balance(2), 5); + assert_eq!(Balances::free_balance(2), 95); + }); +} diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs new file mode 100644 index 0000000000000..406ca99bfb791 --- /dev/null +++ b/frame/preimage/src/weights.rs @@ -0,0 +1,238 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_preimage +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-12-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// target/release/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_preimage +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/preimage/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_preimage. +pub trait WeightInfo { + fn note_preimage(s: u32, ) -> Weight; + fn note_requested_preimage(s: u32, ) -> Weight; + fn note_no_deposit_preimage(s: u32, ) -> Weight; + fn unnote_preimage() -> Weight; + fn unnote_no_deposit_preimage() -> Weight; + fn request_preimage() -> Weight; + fn request_no_deposit_preimage() -> Weight; + fn request_unnoted_preimage() -> Weight; + fn request_requested_preimage() -> Weight; + fn unrequest_preimage() -> Weight; + fn unrequest_unnoted_preimage() -> Weight; + fn unrequest_multi_referenced_preimage() -> Weight; +} + +/// Weights for pallet_preimage using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn note_preimage(s: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:0) + fn note_requested_preimage(s: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:0) + fn note_no_deposit_preimage(s: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unnote_preimage() -> Weight { + (60_560_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unnote_no_deposit_preimage() -> Weight { + (37_575_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_preimage() -> Weight { + (56_868_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_no_deposit_preimage() -> Weight { + (37_058_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_unnoted_preimage() -> Weight { + (21_500_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_requested_preimage() -> Weight { + (7_798_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unrequest_preimage() -> Weight { + (37_771_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unrequest_unnoted_preimage() -> Weight { + (22_913_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn unrequest_multi_referenced_preimage() -> Weight { + (7_608_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn note_preimage(s: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:0) + fn note_requested_preimage(s: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:0) + fn note_no_deposit_preimage(s: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unnote_preimage() -> Weight { + (60_560_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unnote_no_deposit_preimage() -> Weight { + (37_575_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_preimage() -> Weight { + (56_868_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_no_deposit_preimage() -> Weight { + (37_058_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_unnoted_preimage() -> Weight { + (21_500_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_requested_preimage() -> Weight { + (7_798_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unrequest_preimage() -> Weight { + (37_771_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unrequest_unnoted_preimage() -> Weight { + (22_913_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn unrequest_multi_referenced_preimage() -> Weight { + (7_608_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } +} diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index a1d43b359a888..2f76735981510 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -3,44 +3,45 @@ name = "pallet-scheduler" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" -license = "Unlicense" +license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" -description = "FRAME example pallet" +description = "FRAME Scheduler pallet" readme = "README.md" [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } log = { version = "0.4.14", default-features = false } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } +pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } [features] default = ["std"] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] std = [ "codec/std", "scale-info/std", + "log/std", + "sp-std/std", + "sp-io/std", "sp-runtime/std", - "frame-benchmarking/std", - "frame-support/std", "frame-system/std", - "sp-io/std", - "sp-std/std", - "log/std", -] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", + "frame-support/std", + "frame-benchmarking/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 1065f17027744..22e3e4f4530ba 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -17,12 +17,14 @@ //! Scheduler pallet benchmarking. -#![cfg(feature = "runtime-benchmarks")] - use super::*; use frame_benchmarking::benchmarks; -use frame_support::{ensure, traits::OnInitialize}; +use frame_support::{ + ensure, + traits::{OnInitialize, PreimageProvider, PreimageRecipient}, +}; use frame_system::RawOrigin; +use sp_runtime::traits::Hash; use sp_std::{prelude::*, vec}; use crate::Pallet as Scheduler; @@ -30,37 +32,184 @@ use frame_system::Pallet as System; const BLOCK_NUMBER: u32 = 2; -// Add `n` named items to the schedule -fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { - // Essentially a no-op call. - let call = frame_system::Call::set_storage { items: vec![] }; +/// Add `n` named items to the schedule. +/// +/// For `resolved`: +/// - `None`: aborted (hash without preimage) +/// - `Some(true)`: hash resolves into call if possible, plain call otherwise +/// - `Some(false)`: plain call +fn fill_schedule( + when: T::BlockNumber, + n: u32, + periodic: bool, + named: bool, + resolved: Option, +) -> Result<(), &'static str> { for i in 0..n { // Named schedule is strictly heavier than anonymous - Scheduler::::do_schedule_named( - i.encode(), - DispatchTime::At(when), - // Add periodicity - Some((T::BlockNumber::one(), 100)), - // HARD_DEADLINE priority means it gets executed no matter what - 0, - frame_system::RawOrigin::Root.into(), - call.clone().into(), - )?; + let (call, hash) = call_and_hash::(i); + let call_or_hash = match resolved { + Some(true) => { + T::PreimageProvider::note_preimage(call.encode().try_into().unwrap()); + if T::PreimageProvider::have_preimage(&hash) { + CallOrHashOf::::Hash(hash) + } else { + call.into() + } + }, + Some(false) => call.into(), + None => CallOrHashOf::::Hash(hash), + }; + let period = match periodic { + true => Some(((i + 100).into(), 100)), + false => None, + }; + let t = DispatchTime::At(when); + let origin = frame_system::RawOrigin::Root.into(); + if named { + Scheduler::::do_schedule_named(i.encode(), t, period, 0, origin, call_or_hash)?; + } else { + Scheduler::::do_schedule(t, period, 0, origin, call_or_hash)?; + } } ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); Ok(()) } +fn call_and_hash(i: u32) -> (::Call, T::Hash) { + // Essentially a no-op call. + let call: ::Call = frame_system::Call::remark { remark: i.encode() }.into(); + let hash = T::Hashing::hash_of(&call); + (call, hash) +} + benchmarks! { + on_initialize_periodic_named_resolved { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, true, true, Some(true))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s * 2); + for i in 0..s { + assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); + } + } + + on_initialize_named_resolved { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, true, Some(true))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s * 2); + assert!(Agenda::::iter().count() == 0); + } + + on_initialize_periodic_resolved { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, true, false, Some(true))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s * 2); + for i in 0..s { + assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); + } + } + + on_initialize_resolved { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, false, Some(true))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s * 2); + assert!(Agenda::::iter().count() == 0); + } + + on_initialize_named_aborted { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, true, None)?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), 0); + if let Some(delay) = T::NoPreimagePostponement::get() { + assert_eq!(Agenda::::get(when + delay).len(), s as usize); + } else { + assert!(Agenda::::iter().count() == 0); + } + } + + on_initialize_aborted { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, false, None)?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), 0); + if let Some(delay) = T::NoPreimagePostponement::get() { + assert_eq!(Agenda::::get(when + delay).len(), s as usize); + } else { + assert!(Agenda::::iter().count() == 0); + } + } + + on_initialize_periodic_named { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, true, true, Some(false))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s); + for i in 0..s { + assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); + } + } + + on_initialize_periodic { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, true, false, Some(false))?; + }: { Scheduler::::on_initialize(when); } + verify { + assert_eq!(System::::event_count(), s); + for i in 0..s { + assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); + } + } + + on_initialize_named { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, true, Some(false))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s); + assert!(Agenda::::iter().count() == 0); + } + + on_initialize { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, false, Some(false))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s); + assert!(Agenda::::iter().count() == 0); + } + schedule { let s in 0 .. T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); let periodic = Some((T::BlockNumber::one(), 100)); let priority = 0; // Essentially a no-op call. - let call = Box::new(frame_system::Call::set_storage { items: vec![] }.into()); + let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); + let call = Box::new(CallOrHashOf::::Value(inner_call)); - fill_schedule::(when, s)?; + fill_schedule::(when, s, true, true, Some(false))?; }: _(RawOrigin::Root, when, periodic, priority, call) verify { ensure!( @@ -73,7 +222,7 @@ benchmarks! { let s in 1 .. T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s)?; + fill_schedule::(when, s, true, true, Some(false))?; assert_eq!(Agenda::::get(when).len(), s as usize); }: _(RawOrigin::Root, when, 0) verify { @@ -95,9 +244,10 @@ benchmarks! { let periodic = Some((T::BlockNumber::one(), 100)); let priority = 0; // Essentially a no-op call. - let call = Box::new(frame_system::Call::set_storage { items: vec![] }.into()); + let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); + let call = Box::new(CallOrHashOf::::Value(inner_call)); - fill_schedule::(when, s)?; + fill_schedule::(when, s, true, true, Some(false))?; }: _(RawOrigin::Root, id, when, periodic, priority, call) verify { ensure!( @@ -110,7 +260,7 @@ benchmarks! { let s in 1 .. T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s)?; + fill_schedule::(when, s, true, true, Some(false))?; }: _(RawOrigin::Root, 0.encode()) verify { ensure!( @@ -124,21 +274,5 @@ benchmarks! { ); } - // TODO [#7141]: Make this more complex and flexible so it can be used in automation. - #[extra] - on_initialize { - let s in 0 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s)?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s); - // Next block should have all the schedules again - ensure!( - Agenda::::get(when + T::BlockNumber::one()).len() == s as usize, - "didn't append schedule" - ); - } - - impl_benchmark_test_suite!(Scheduler, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 02bcb5eb3109f..b4ee2575e23d0 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -50,14 +50,19 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "runtime-benchmarks")] mod benchmarking; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; pub mod weights; use codec::{Codec, Decode, Encode}; use frame_support::{ dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter}, traits::{ - schedule::{self, DispatchTime}, + schedule::{self, DispatchTime, MaybeHashed}, EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp, }, weights::{GetDispatchInfo, Weight}, @@ -77,6 +82,8 @@ pub type PeriodicIndex = u32; /// The location of a scheduled task that can be used to remove it. pub type TaskAddress = (BlockNumber, u32); +pub type CallOrHashOf = MaybeHashed<::Call, ::Hash>; + #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] #[derive(Clone, RuntimeDebug, Encode, Decode)] struct ScheduledV1 { @@ -89,7 +96,7 @@ struct ScheduledV1 { /// Information regarding an item to be executed in the future. #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] #[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct ScheduledV2 { +pub struct ScheduledV3 { /// The unique identity for this task, if there is one. maybe_id: Option>, /// This task's priority. @@ -103,6 +110,24 @@ pub struct ScheduledV2 { _phantom: PhantomData, } +use crate::ScheduledV3 as ScheduledV2; + +pub type ScheduledV2Of = ScheduledV3< + ::Call, + ::BlockNumber, + ::PalletsOrigin, + ::AccountId, +>; + +pub type ScheduledV3Of = ScheduledV3< + CallOrHashOf, + ::BlockNumber, + ::PalletsOrigin, + ::AccountId, +>; + +pub type ScheduledOf = ScheduledV3Of; + /// The current version of Scheduled struct. pub type Scheduled = ScheduledV2; @@ -110,10 +135,11 @@ pub type Scheduled = // A value placed in storage that represents the current version of the Scheduler storage. // This value is used by the `on_runtime_upgrade` logic to determine whether we run // storage migration logic. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] enum Releases { V1, V2, + V3, } impl Default for Releases { @@ -122,10 +148,57 @@ impl Default for Releases { } } +#[cfg(feature = "runtime-benchmarks")] +mod preimage_provider { + use frame_support::traits::PreimageRecipient; + pub trait PreimageProviderAndMaybeRecipient: PreimageRecipient {} + impl> PreimageProviderAndMaybeRecipient for T {} +} + +#[cfg(not(feature = "runtime-benchmarks"))] +mod preimage_provider { + use frame_support::traits::PreimageProvider; + pub trait PreimageProviderAndMaybeRecipient: PreimageProvider {} + impl> PreimageProviderAndMaybeRecipient for T {} +} + +pub use preimage_provider::PreimageProviderAndMaybeRecipient; + +pub(crate) trait MarginalWeightInfo: WeightInfo { + fn item(periodic: bool, named: bool, resolved: Option) -> Weight { + match (periodic, named, resolved) { + (_, false, None) => Self::on_initialize_aborted(2) - Self::on_initialize_aborted(1), + (_, true, None) => + Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1), + (false, false, Some(false)) => Self::on_initialize(2) - Self::on_initialize(1), + (false, true, Some(false)) => + Self::on_initialize_named(2) - Self::on_initialize_named(1), + (true, false, Some(false)) => + Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1), + (true, true, Some(false)) => + Self::on_initialize_periodic_named(2) - Self::on_initialize_periodic_named(1), + (false, false, Some(true)) => + Self::on_initialize_resolved(2) - Self::on_initialize_resolved(1), + (false, true, Some(true)) => + Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1), + (true, false, Some(true)) => + Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1), + (true, true, Some(true)) => + Self::on_initialize_periodic_named_resolved(2) - + Self::on_initialize_periodic_named_resolved(1), + } + } +} +impl MarginalWeightInfo for T {} + #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{ + dispatch::PostDispatchInfo, + pallet_prelude::*, + traits::{schedule::LookupError, PreimageProvider}, + }; use frame_system::pallet_prelude::*; #[pallet::pallet] @@ -148,7 +221,7 @@ pub mod pallet { /// The aggregated call type. type Call: Parameter - + Dispatchable::Origin> + + Dispatchable::Origin, PostInfo = PostDispatchInfo> + GetDispatchInfo + From>; @@ -176,17 +249,18 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// The preimage provider with which we look up call hashes to get the call. + type PreimageProvider: PreimageProviderAndMaybeRecipient; + + /// If `Some` then the number of blocks to postpone execution for when the item is delayed. + type NoPreimagePostponement: Get>; } /// Items to be executed, indexed by the block number that they should be executed on. #[pallet::storage] - pub type Agenda = StorageMap< - _, - Twox64Concat, - T::BlockNumber, - Vec::Call, T::BlockNumber, T::PalletsOrigin, T::AccountId>>>, - ValueQuery, - >; + pub type Agenda = + StorageMap<_, Twox64Concat, T::BlockNumber, Vec>>, ValueQuery>; /// Lookup from identity to the block number and index of the task. #[pallet::storage] @@ -213,6 +287,12 @@ pub mod pallet { id: Option>, result: DispatchResult, }, + /// The call for the provided hash was not found so the task has been aborted. + CallLookupFailed { + task: TaskAddress, + id: Option>, + error: LookupError, + }, } #[pallet::error] @@ -240,7 +320,7 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - StorageVersion::::put(Releases::V2); + StorageVersion::::put(Releases::V3); } } @@ -249,11 +329,13 @@ pub mod pallet { /// Execute the scheduled calls fn on_initialize(now: T::BlockNumber) -> Weight { let limit = T::MaximumWeight::get(); + let mut queued = Agenda::::take(now) .into_iter() .enumerate() - .filter_map(|(index, s)| s.map(|inner| (index as u32, inner))) + .filter_map(|(index, s)| Some((index as u32, s?))) .collect::>(); + if queued.len() as u32 > T::MaxScheduledPerBlock::get() { log::warn!( target: "runtime::scheduler", @@ -261,84 +343,111 @@ pub mod pallet { expected from the runtime configuration. An update might be needed." ); } - queued.sort_by_key(|(_, s)| s.priority); - let base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); // Agenda + Agenda(next) - let mut total_weight: Weight = 0; - queued - .into_iter() - .enumerate() - .scan(base_weight, |cumulative_weight, (order, (index, s))| { - *cumulative_weight = - cumulative_weight.saturating_add(s.call.get_dispatch_info().weight); - - let origin = - <::Origin as From>::from(s.origin.clone()) - .into(); - - if ensure_signed(origin).is_ok() { - // AccountData for inner call origin accountdata. - *cumulative_weight = - cumulative_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); - } - if s.maybe_id.is_some() { - // Remove/Modify Lookup - *cumulative_weight = - cumulative_weight.saturating_add(T::DbWeight::get().writes(1)); - } - if s.maybe_periodic.is_some() { - // Read/Write Agenda for future block - *cumulative_weight = - cumulative_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); - } + queued.sort_by_key(|(_, s)| s.priority); - Some((order, index, *cumulative_weight, s)) - }) - .filter_map(|(order, index, cumulative_weight, mut s)| { - // We allow a scheduled call if any is true: - // - It's priority is `HARD_DEADLINE` - // - It does not push the weight past the limit. - // - It is the first item in the schedule - if s.priority <= schedule::HARD_DEADLINE || - cumulative_weight <= limit || - order == 0 - { - let r = s.call.clone().dispatch(s.origin.clone().into()); - let maybe_id = s.maybe_id.clone(); - if let &Some((period, count)) = &s.maybe_periodic { - if count > 1 { - s.maybe_periodic = Some((period, count - 1)); - } else { - s.maybe_periodic = None; - } - let next = now + period; - // If scheduled is named, place it's information in `Lookup` + let next = now + One::one(); + + let mut total_weight: Weight = T::WeightInfo::on_initialize(0); + for (order, (index, mut s)) in queued.into_iter().enumerate() { + let named = if let Some(ref id) = s.maybe_id { + Lookup::::remove(id); + true + } else { + false + }; + + let (call, maybe_completed) = s.call.resolved::(); + s.call = call; + + let resolved = if let Some(completed) = maybe_completed { + T::PreimageProvider::unrequest_preimage(&completed); + true + } else { + false + }; + + let call = match s.call.as_value().cloned() { + Some(c) => c, + None => { + // Preimage not available - postpone until some block. + total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); + if let Some(delay) = T::NoPreimagePostponement::get() { + let until = now.saturating_add(delay); if let Some(ref id) = s.maybe_id { - let next_index = Agenda::::decode_len(now + period).unwrap_or(0); - Lookup::::insert(id, (next, next_index as u32)); - } - Agenda::::append(next, Some(s)); - } else { - if let Some(ref id) = s.maybe_id { - Lookup::::remove(id); + let index = Agenda::::decode_len(until).unwrap_or(0); + Lookup::::insert(id, (until, index as u32)); } + Agenda::::append(until, Some(s)); } - Self::deposit_event(Event::Dispatched { - task: (now, index), - id: maybe_id, - result: r.map(|_| ()).map_err(|e| e.error), - }); - total_weight = cumulative_weight; - None - } else { - Some(Some(s)) + continue + }, + }; + + let periodic = s.maybe_periodic.is_some(); + let call_weight = call.get_dispatch_info().weight; + let mut item_weight = T::WeightInfo::item(periodic, named, Some(resolved)); + let origin = + <::Origin as From>::from(s.origin.clone()) + .into(); + if ensure_signed(origin).is_ok() { + // Weights of Signed dispatches expect their signing account to be whitelisted. + item_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + } + + // We allow a scheduled call if any is true: + // - It's priority is `HARD_DEADLINE` + // - It does not push the weight past the limit. + // - It is the first item in the schedule + let hard_deadline = s.priority <= schedule::HARD_DEADLINE; + let test_weight = + total_weight.saturating_add(call_weight).saturating_add(item_weight); + if !hard_deadline && order > 0 && test_weight > limit { + // Cannot be scheduled this block - postpone until next. + total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); + if let Some(ref id) = s.maybe_id { + // NOTE: We could reasonably not do this (in which case there would be one + // block where the named and delayed item could not be referenced by name), + // but we will do it anyway since it should be mostly free in terms of + // weight and it is slightly cleaner. + let index = Agenda::::decode_len(next).unwrap_or(0); + Lookup::::insert(id, (next, index as u32)); } - }) - .for_each(|unused| { - let next = now + One::one(); - Agenda::::append(next, unused); + Agenda::::append(next, Some(s)); + continue + } + + let dispatch_origin = s.origin.clone().into(); + let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) { + Ok(post_info) => (post_info.actual_weight, Ok(())), + Err(error_and_info) => + (error_and_info.post_info.actual_weight, Err(error_and_info.error)), + }; + let actual_call_weight = maybe_actual_call_weight.unwrap_or(call_weight); + total_weight.saturating_accrue(item_weight); + total_weight.saturating_accrue(actual_call_weight); + + Self::deposit_event(Event::Dispatched { + task: (now, index), + id: s.maybe_id.clone(), + result, }); + if let &Some((period, count)) = &s.maybe_periodic { + if count > 1 { + s.maybe_periodic = Some((period, count - 1)); + } else { + s.maybe_periodic = None; + } + let wake = now + period; + // If scheduled is named, place its information in `Lookup` + if let Some(ref id) = s.maybe_id { + let wake_index = Agenda::::decode_len(wake).unwrap_or(0); + Lookup::::insert(id, (wake, wake_index as u32)); + } + Agenda::::append(wake, Some(s)); + } + } total_weight } } @@ -352,7 +461,7 @@ pub mod pallet { when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box<::Call>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -383,7 +492,7 @@ pub mod pallet { when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box<::Call>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -418,7 +527,7 @@ pub mod pallet { after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box<::Call>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -444,7 +553,7 @@ pub mod pallet { after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box<::Call>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -462,11 +571,11 @@ pub mod pallet { } impl Pallet { - /// Migrate storage format from V1 to V2. + /// Migrate storage format from V1 to V3. /// Return true if migration is performed. - pub fn migrate_v1_to_t2() -> bool { + pub fn migrate_v1_to_v3() -> bool { if StorageVersion::::get() == Releases::V1 { - StorageVersion::::put(Releases::V2); + StorageVersion::::put(Releases::V3); Agenda::::translate::< Vec::Call, T::BlockNumber>>>, @@ -476,10 +585,10 @@ impl Pallet { agenda .into_iter() .map(|schedule| { - schedule.map(|schedule| ScheduledV2 { + schedule.map(|schedule| ScheduledV3 { maybe_id: schedule.maybe_id, priority: schedule.priority, - call: schedule.call, + call: schedule.call.into(), maybe_periodic: schedule.maybe_periodic, origin: system::RawOrigin::Root.into(), _phantom: Default::default(), @@ -495,10 +604,58 @@ impl Pallet { } } + /// Migrate storage format from V2 to V3. + /// Return true if migration is performed. + pub fn migrate_v2_to_v3() -> Weight { + if StorageVersion::::get() == Releases::V2 { + StorageVersion::::put(Releases::V3); + + let mut weight = T::DbWeight::get().reads_writes(1, 1); + + Agenda::::translate::>>, _>(|_, agenda| { + Some( + agenda + .into_iter() + .map(|schedule| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + schedule.map(|schedule| ScheduledV3 { + maybe_id: schedule.maybe_id, + priority: schedule.priority, + call: schedule.call.into(), + maybe_periodic: schedule.maybe_periodic, + origin: system::RawOrigin::Root.into(), + _phantom: Default::default(), + }) + }) + .collect::>(), + ) + }); + + weight + } else { + 0 + } + } + + #[cfg(feature = "try-runtime")] + pub fn pre_migrate_to_v3() -> Result<(), &'static str> { + assert!(StorageVersion::::get() < Releases::V3); + Ok(()) + } + + #[cfg(feature = "try-runtime")] + pub fn post_migrate_to_v3() -> Result<(), &'static str> { + assert!(StorageVersion::::get() == Releases::V3); + for k in Agenda::::iter_keys() { + let _ = Agenda::::try_get(k).map_err(|()| "Invalid item in Agenda")?; + } + Ok(()) + } + /// Helper to migrate scheduler when the pallet origin type has changed. pub fn migrate_origin + codec::Decode>() { Agenda::::translate::< - Vec::Call, T::BlockNumber, OldOrigin, T::AccountId>>>, + Vec, T::BlockNumber, OldOrigin, T::AccountId>>>, _, >(|_, agenda| { Some( @@ -541,9 +698,10 @@ impl Pallet { maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: ::Call, + call: CallOrHashOf, ) -> Result, DispatchError> { let when = Self::resolve_time(when)?; + call.ensure_requested::(); // sanitize maybe_periodic let maybe_periodic = maybe_periodic @@ -593,6 +751,7 @@ impl Pallet { ) })?; if let Some(s) = scheduled { + s.call.ensure_unrequested::(); if let Some(id) = s.maybe_id { Lookup::::remove(id); } @@ -633,7 +792,7 @@ impl Pallet { maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: ::Call, + call: CallOrHashOf, ) -> Result, DispatchError> { // ensure id it is unique if Lookup::::contains_key(&id) { @@ -642,6 +801,8 @@ impl Pallet { let when = Self::resolve_time(when)?; + call.ensure_requested::(); + // sanitize maybe_periodic let maybe_periodic = maybe_periodic .filter(|p| p.1 > 1 && !p.0.is_zero()) @@ -685,6 +846,7 @@ impl Pallet { ) { return Err(BadOrigin.into()) } + s.call.ensure_unrequested::(); } *s = None; } @@ -733,17 +895,18 @@ impl Pallet { } } -impl schedule::Anon::Call, T::PalletsOrigin> +impl schedule::v2::Anon::Call, T::PalletsOrigin> for Pallet { type Address = TaskAddress; + type Hash = T::Hash; fn schedule( when: DispatchTime, maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: ::Call, + call: CallOrHashOf, ) -> Result { Self::do_schedule(when, maybe_periodic, priority, origin, call) } @@ -764,10 +927,11 @@ impl schedule::Anon::Call, T::PalletsOr } } -impl schedule::Named::Call, T::PalletsOrigin> +impl schedule::v2::Named::Call, T::PalletsOrigin> for Pallet { type Address = TaskAddress; + type Hash = T::Hash; fn schedule_named( id: Vec, @@ -775,7 +939,7 @@ impl schedule::Named::Call, T::PalletsO maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: ::Call, + call: CallOrHashOf, ) -> Result { Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ()) } @@ -797,1022 +961,3 @@ impl schedule::Named::Call, T::PalletsO .ok_or(()) } } - -#[cfg(test)] -mod tests { - use super::*; - - use crate as scheduler; - use frame_support::{ - assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{Contains, EnsureOneOf, EqualPrivilegeOnly, OnFinalize, OnInitialize}, - weights::constants::RocksDbWeight, - Hashable, - }; - use frame_system::{EnsureRoot, EnsureSignedBy}; - use sp_core::H256; - use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, - }; - use substrate_test_utils::assert_eq_uvec; - - // Logger module to track execution. - #[frame_support::pallet] - pub mod logger { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - use std::cell::RefCell; - - thread_local! { - static LOG: RefCell> = RefCell::new(Vec::new()); - } - pub fn log() -> Vec<(OriginCaller, u32)> { - LOG.with(|log| log.borrow().clone()) - } - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(PhantomData); - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::config] - pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - Logged(u32, Weight), - } - - #[pallet::call] - impl Pallet - where - ::Origin: OriginTrait, - { - #[pallet::weight(*weight)] - pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { - Self::deposit_event(Event::Logged(i, weight)); - LOG.with(|log| { - log.borrow_mut().push((origin.caller().clone(), i)); - }); - Ok(()) - } - - #[pallet::weight(*weight)] - pub fn log_without_filter( - origin: OriginFor, - i: u32, - weight: Weight, - ) -> DispatchResult { - Self::deposit_event(Event::Logged(i, weight)); - LOG.with(|log| { - log.borrow_mut().push((origin.caller().clone(), i)); - }); - Ok(()) - } - } - } - - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; - type Block = frame_system::mocking::MockBlock; - - frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Logger: logger::{Pallet, Call, Event}, - Scheduler: scheduler::{Pallet, Call, Storage, Event}, - } - ); - - // Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. - pub struct BaseFilter; - impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, Call::Logger(LoggerCall::log { .. })) - } - } - - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); - } - impl system::Config for Test { - type BaseCallFilter = BaseFilter; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = RocksDbWeight; - type Origin = Origin; - type Call = Call; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - impl logger::Config for Test { - type Event = Event; - } - parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 10; - } - ord_parameter_types! { - pub const One: u64 = 1; - } - - impl Config for Test { - type Event = Event; - type Origin = Origin; - type PalletsOrigin = OriginCaller; - type Call = Call; - type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; - type MaxScheduledPerBlock = MaxScheduledPerBlock; - type WeightInfo = (); - type OriginPrivilegeCmp = EqualPrivilegeOnly; - } - - pub type LoggerCall = logger::Call; - - pub fn new_test_ext() -> sp_io::TestExternalities { - let t = system::GenesisConfig::default().build_storage::().unwrap(); - t.into() - } - - fn run_to_block(n: u64) { - while System::block_number() < n { - Scheduler::on_finalize(System::block_number()); - System::set_block_number(System::block_number() + 1); - Scheduler::on_initialize(System::block_number()); - } - } - - fn root() -> OriginCaller { - system::RawOrigin::Root.into() - } - - #[test] - fn basic_scheduling_works() { - new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call)); - run_to_block(3); - assert!(logger::log().is_empty()); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); - } - - #[test] - fn schedule_after_works() { - new_test_ext().execute_with(|| { - run_to_block(2); - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 - assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call)); - run_to_block(5); - assert!(logger::log().is_empty()); - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); - } - - #[test] - fn schedule_after_zero_works() { - new_test_ext().execute_with(|| { - run_to_block(2); - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call)); - // Will trigger on the next block. - run_to_block(3); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); - } - - #[test] - fn periodic_scheduling_works() { - new_test_ext().execute_with(|| { - // at #4, every 3 blocks, 3 times. - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - Some((3, 3)), - 127, - root(), - Call::Logger(logger::Call::log { i: 42, weight: 1000 }) - )); - run_to_block(3); - assert!(logger::log().is_empty()); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(7); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); - run_to_block(9); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); - run_to_block(10); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - }); - } - - #[test] - fn reschedule_works() { - new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - assert_eq!( - Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call).unwrap(), - (4, 0) - ); - - run_to_block(3); - assert!(logger::log().is_empty()); - - assert_eq!(Scheduler::do_reschedule((4, 0), DispatchTime::At(6)).unwrap(), (6, 0)); - - assert_noop!( - Scheduler::do_reschedule((6, 0), DispatchTime::At(6)), - Error::::RescheduleNoChange - ); - - run_to_block(4); - assert!(logger::log().is_empty()); - - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); - } - - #[test] - fn reschedule_named_works() { - new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - assert_eq!( - Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(4), - None, - 127, - root(), - call - ) - .unwrap(), - (4, 0) - ); - - run_to_block(3); - assert!(logger::log().is_empty()); - - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), - (6, 0) - ); - - assert_noop!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)), - Error::::RescheduleNoChange - ); - - run_to_block(4); - assert!(logger::log().is_empty()); - - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); - } - - #[test] - fn reschedule_named_perodic_works() { - new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - assert_eq!( - Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(4), - Some((3, 3)), - 127, - root(), - call - ) - .unwrap(), - (4, 0) - ); - - run_to_block(3); - assert!(logger::log().is_empty()); - - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(5)).unwrap(), - (5, 0) - ); - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), - (6, 0) - ); - - run_to_block(5); - assert!(logger::log().is_empty()); - - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(10)).unwrap(), - (10, 0) - ); - - run_to_block(9); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(10); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); - - run_to_block(13); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - }); - } - - #[test] - fn cancel_named_scheduling_works_with_normal_cancel() { - new_test_ext().execute_with(|| { - // at #4. - Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - ) - .unwrap(); - let i = Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: 1000 }), - ) - .unwrap(); - run_to_block(3); - assert!(logger::log().is_empty()); - assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); - assert_ok!(Scheduler::do_cancel(None, i)); - run_to_block(100); - assert!(logger::log().is_empty()); - }); - } - - #[test] - fn cancel_named_periodic_scheduling_works() { - new_test_ext().execute_with(|| { - // at #4, every 3 blocks, 3 times. - Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(4), - Some((3, 3)), - 127, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: 1000 }), - ) - .unwrap(); - // same id results in error. - assert!(Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }) - ) - .is_err()); - // different id is ok. - Scheduler::do_schedule_named( - 2u32.encode(), - DispatchTime::At(8), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - ) - .unwrap(); - run_to_block(3); - assert!(logger::log().is_empty()); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(6); - assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); - }); - } - - #[test] - fn scheduler_respects_weight_limits() { - new_test_ext().execute_with(|| { - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) - )); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - )); - // 69 and 42 do not fit together - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(5); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); - }); - } - - #[test] - fn scheduler_respects_hard_deadlines_more() { - new_test_ext().execute_with(|| { - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 0, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) - )); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 0, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - )); - // With base weights, 69 and 42 should not fit together, but do because of hard - // deadlines - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); - }); - } - - #[test] - fn scheduler_respects_priority_ordering() { - new_test_ext().execute_with(|| { - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 1, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) - )); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 0, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - )); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); - }); - } - - #[test] - fn scheduler_respects_priority_ordering_with_soft_deadlines() { - new_test_ext().execute_with(|| { - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 255, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }) - )); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - )); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 126, - root(), - Call::Logger(LoggerCall::log { - i: 2600, - weight: MaximumSchedulerWeight::get() / 2 - }) - )); - - // 2600 does not fit with 69 or 42, but has higher priority, so will go through - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 2600u32)]); - // 69 and 42 fit together - run_to_block(5); - assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); - }); - } - - #[test] - fn on_initialize_weight_is_correct() { - new_test_ext().execute_with(|| { - let base_weight: Weight = - ::DbWeight::get().reads_writes(1, 2); - let base_multiplier = 0; - let named_multiplier = ::DbWeight::get().writes(1); - let periodic_multiplier = - ::DbWeight::get().reads_writes(1, 1); - - // Named - assert_ok!(Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(1), - None, - 255, - root(), - Call::Logger(LoggerCall::log { i: 3, weight: MaximumSchedulerWeight::get() / 3 }) - )); - // Anon Periodic - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(1), - Some((1000, 3)), - 128, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }) - )); - // Anon - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(1), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - )); - // Named Periodic - assert_ok!(Scheduler::do_schedule_named( - 2u32.encode(), - DispatchTime::At(1), - Some((1000, 3)), - 126, - root(), - Call::Logger(LoggerCall::log { - i: 2600, - weight: MaximumSchedulerWeight::get() / 2 - }) - )); - - // Will include the named periodic only - let actual_weight = Scheduler::on_initialize(1); - let call_weight = MaximumSchedulerWeight::get() / 2; - assert_eq!( - actual_weight, - call_weight + - base_weight + base_multiplier + - named_multiplier + periodic_multiplier - ); - assert_eq!(logger::log(), vec![(root(), 2600u32)]); - - // Will include anon and anon periodic - let actual_weight = Scheduler::on_initialize(2); - let call_weight = MaximumSchedulerWeight::get() / 2 + MaximumSchedulerWeight::get() / 3; - assert_eq!( - actual_weight, - call_weight + base_weight + base_multiplier * 2 + periodic_multiplier - ); - assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); - - // Will include named only - let actual_weight = Scheduler::on_initialize(3); - let call_weight = MaximumSchedulerWeight::get() / 3; - assert_eq!( - actual_weight, - call_weight + base_weight + base_multiplier + named_multiplier - ); - assert_eq!( - logger::log(), - vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)] - ); - - // Will contain none - let actual_weight = Scheduler::on_initialize(4); - assert_eq!(actual_weight, 0); - }); - } - - #[test] - fn root_calls_works() { - new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 })); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 })); - assert_ok!(Scheduler::schedule_named( - Origin::root(), - 1u32.encode(), - 4, - None, - 127, - call - )); - assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); - run_to_block(3); - // Scheduled calls are in the agenda. - assert_eq!(Agenda::::get(4).len(), 2); - assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(Origin::root(), 1u32.encode())); - assert_ok!(Scheduler::cancel(Origin::root(), 4, 1)); - // Scheduled calls are made NONE, so should not effect state - run_to_block(100); - assert!(logger::log().is_empty()); - }); - } - - #[test] - fn fails_to_schedule_task_in_the_past() { - new_test_ext().execute_with(|| { - run_to_block(3); - - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 })); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 })); - - assert_err!( - Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call), - Error::::TargetBlockNumberInPast, - ); - - assert_err!( - Scheduler::schedule(Origin::root(), 2, None, 127, call2.clone()), - Error::::TargetBlockNumberInPast, - ); - - assert_err!( - Scheduler::schedule(Origin::root(), 3, None, 127, call2), - Error::::TargetBlockNumberInPast, - ); - }); - } - - #[test] - fn should_use_orign() { - new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 })); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 })); - assert_ok!(Scheduler::schedule_named( - system::RawOrigin::Signed(1).into(), - 1u32.encode(), - 4, - None, - 127, - call - )); - assert_ok!(Scheduler::schedule( - system::RawOrigin::Signed(1).into(), - 4, - None, - 127, - call2 - )); - run_to_block(3); - // Scheduled calls are in the agenda. - assert_eq!(Agenda::::get(4).len(), 2); - assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), 1u32.encode())); - assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1)); - // Scheduled calls are made NONE, so should not effect state - run_to_block(100); - assert!(logger::log().is_empty()); - }); - } - - #[test] - fn should_check_orign() { - new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 })); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 })); - assert_noop!( - Scheduler::schedule_named( - system::RawOrigin::Signed(2).into(), - 1u32.encode(), - 4, - None, - 127, - call - ), - BadOrigin - ); - assert_noop!( - Scheduler::schedule(system::RawOrigin::Signed(2).into(), 4, None, 127, call2), - BadOrigin - ); - }); - } - - #[test] - fn should_check_orign_for_cancel() { - new_test_ext().execute_with(|| { - let call = - Box::new(Call::Logger(LoggerCall::log_without_filter { i: 69, weight: 1000 })); - let call2 = - Box::new(Call::Logger(LoggerCall::log_without_filter { i: 42, weight: 1000 })); - assert_ok!(Scheduler::schedule_named( - system::RawOrigin::Signed(1).into(), - 1u32.encode(), - 4, - None, - 127, - call - )); - assert_ok!(Scheduler::schedule( - system::RawOrigin::Signed(1).into(), - 4, - None, - 127, - call2 - )); - run_to_block(3); - // Scheduled calls are in the agenda. - assert_eq!(Agenda::::get(4).len(), 2); - assert!(logger::log().is_empty()); - assert_noop!( - Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), 1u32.encode()), - BadOrigin - ); - assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin); - assert_noop!( - Scheduler::cancel_named(system::RawOrigin::Root.into(), 1u32.encode()), - BadOrigin - ); - assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin); - run_to_block(5); - assert_eq!( - logger::log(), - vec![ - (system::RawOrigin::Signed(1).into(), 69u32), - (system::RawOrigin::Signed(1).into(), 42u32) - ] - ); - }); - } - - #[test] - fn migration_to_v2_works() { - new_test_ext().execute_with(|| { - for i in 0..3u64 { - let k = i.twox_64_concat(); - let old = vec![ - Some(ScheduledV1 { - maybe_id: None, - priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), - maybe_periodic: None, - }), - None, - Some(ScheduledV1 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - maybe_periodic: Some((456u64, 10)), - }), - ]; - frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); - } - - assert_eq!(StorageVersion::::get(), Releases::V1); - - assert!(Scheduler::migrate_v1_to_t2()); - - assert_eq_uvec!( - Agenda::::iter().collect::>(), - vec![ - ( - 0, - vec![ - Some(ScheduledV2 { - maybe_id: None, - priority: 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 1, - vec![ - Some(ScheduledV2 { - maybe_id: None, - priority: 11, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 2, - vec![ - Some(ScheduledV2 { - maybe_id: None, - priority: 12, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ) - ] - ); - - assert_eq!(StorageVersion::::get(), Releases::V2); - }); - } - - #[test] - fn test_migrate_origin() { - new_test_ext().execute_with(|| { - for i in 0..3u64 { - let k = i.twox_64_concat(); - let old: Vec>> = vec![ - Some(Scheduled { - maybe_id: None, - priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), - origin: 3u32, - maybe_periodic: None, - _phantom: Default::default(), - }), - None, - Some(Scheduled { - maybe_id: Some(b"test".to_vec()), - priority: 123, - origin: 2u32, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - maybe_periodic: Some((456u64, 10)), - _phantom: Default::default(), - }), - ]; - frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); - } - - impl Into for u32 { - fn into(self) -> OriginCaller { - match self { - 3u32 => system::RawOrigin::Root.into(), - 2u32 => system::RawOrigin::None.into(), - _ => unreachable!("test make no use of it"), - } - } - } - - Scheduler::migrate_origin::(); - - assert_eq_uvec!( - Agenda::::iter().collect::>(), - vec![ - ( - 0, - vec![ - Some(ScheduledV2::<_, _, OriginCaller, u64> { - maybe_id: None, - priority: 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), - maybe_periodic: None, - origin: system::RawOrigin::Root.into(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - maybe_periodic: Some((456u64, 10)), - origin: system::RawOrigin::None.into(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 1, - vec![ - Some(ScheduledV2 { - maybe_id: None, - priority: 11, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), - maybe_periodic: None, - origin: system::RawOrigin::Root.into(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - maybe_periodic: Some((456u64, 10)), - origin: system::RawOrigin::None.into(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 2, - vec![ - Some(ScheduledV2 { - maybe_id: None, - priority: 12, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), - maybe_periodic: None, - origin: system::RawOrigin::Root.into(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - maybe_periodic: Some((456u64, 10)), - origin: system::RawOrigin::None.into(), - _phantom: PhantomData::::default(), - }), - ] - ) - ] - ); - }); - } -} diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs new file mode 100644 index 0000000000000..535e91937e4dc --- /dev/null +++ b/frame/scheduler/src/mock.rs @@ -0,0 +1,203 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Scheduler test environment. + +use super::*; + +use crate as scheduler; +use frame_support::{ + ord_parameter_types, parameter_types, + traits::{Contains, EnsureOneOf, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + weights::constants::RocksDbWeight, +}; +use frame_system::{EnsureRoot, EnsureSignedBy}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, +}; + +// Logger module to track execution. +#[frame_support::pallet] +pub mod logger { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use std::cell::RefCell; + + thread_local! { + static LOG: RefCell> = RefCell::new(Vec::new()); + } + pub fn log() -> Vec<(OriginCaller, u32)> { + LOG.with(|log| log.borrow().clone()) + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::config] + pub trait Config: frame_system::Config { + type Event: From> + IsType<::Event>; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + Logged(u32, Weight), + } + + #[pallet::call] + impl Pallet + where + ::Origin: OriginTrait, + { + #[pallet::weight(*weight)] + pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { + Self::deposit_event(Event::Logged(i, weight)); + LOG.with(|log| { + log.borrow_mut().push((origin.caller().clone(), i)); + }); + Ok(()) + } + + #[pallet::weight(*weight)] + pub fn log_without_filter(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { + Self::deposit_event(Event::Logged(i, weight)); + LOG.with(|log| { + log.borrow_mut().push((origin.caller().clone(), i)); + }); + Ok(()) + } + } +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Logger: logger::{Pallet, Call, Event}, + Scheduler: scheduler::{Pallet, Call, Storage, Event}, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, + } +); + +// Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. +pub struct BaseFilter; +impl Contains for BaseFilter { + fn contains(call: &Call) -> bool { + !matches!(call, Call::Logger(LoggerCall::log { .. })) + } +} + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); +} +impl system::Config for Test { + type BaseCallFilter = BaseFilter; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = RocksDbWeight; + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} +impl logger::Config for Test { + type Event = Event; +} +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; + pub const MaxScheduledPerBlock: u32 = 10; + pub const MaxSize: u32 = 1024; + pub const NoPreimagePostponement: Option = Some(2); +} +ord_parameter_types! { + pub const One: u64 = 1; +} + +impl pallet_preimage::Config for Test { + type Event = Event; + type WeightInfo = (); + type Currency = (); + type ManagerOrigin = EnsureRoot; + type MaxSize = MaxSize; + type BaseDeposit = (); + type ByteDeposit = (); +} + +impl Config for Test { + type Event = Event; + type Origin = Origin; + type PalletsOrigin = OriginCaller; + type Call = Call; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; + type MaxScheduledPerBlock = MaxScheduledPerBlock; + type WeightInfo = (); + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type PreimageProvider = Preimage; + type NoPreimagePostponement = NoPreimagePostponement; +} + +pub type LoggerCall = logger::Call; + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = system::GenesisConfig::default().build_storage::().unwrap(); + t.into() +} + +pub fn run_to_block(n: u64) { + while System::block_number() < n { + Scheduler::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Scheduler::on_initialize(System::block_number()); + } +} + +pub fn root() -> OriginCaller { + system::RawOrigin::Root.into() +} diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs new file mode 100644 index 0000000000000..4774cfe38704d --- /dev/null +++ b/frame/scheduler/src/tests.rs @@ -0,0 +1,901 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Scheduler tests. + +use super::*; +use crate::mock::{logger, new_test_ext, root, run_to_block, Call, LoggerCall, Scheduler, Test, *}; +use frame_support::{ + assert_err, assert_noop, assert_ok, + traits::{Contains, OnInitialize, PreimageProvider}, + Hashable, +}; +use sp_runtime::traits::Hash; +use substrate_test_utils::assert_eq_uvec; + +#[test] +fn basic_scheduling_works() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into())); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn scheduling_with_preimages_works() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let hash = ::Hashing::hash_of(&call); + let hashed = MaybeHashed::Hash(hash.clone()); + assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); + assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); + assert!(Preimage::preimage_requested(&hash)); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert!(!Preimage::have_preimage(&hash)); + assert!(!Preimage::preimage_requested(&hash)); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn scheduling_with_preimage_postpones_correctly() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let hash = ::Hashing::hash_of(&call); + let hashed = MaybeHashed::Hash(hash.clone()); + + assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); + assert!(Preimage::preimage_requested(&hash)); + + run_to_block(4); + // #4 empty due to no preimage + assert!(logger::log().is_empty()); + + // Register preimage. + assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); + + run_to_block(5); + // #5 empty since postponement is 2 blocks. + assert!(logger::log().is_empty()); + + run_to_block(6); + // #6 is good. + assert_eq!(logger::log(), vec![(root(), 42u32)]); + assert!(!Preimage::have_preimage(&hash)); + assert!(!Preimage::preimage_requested(&hash)); + + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn schedule_after_works() { + new_test_ext().execute_with(|| { + run_to_block(2); + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 + assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call.into())); + run_to_block(5); + assert!(logger::log().is_empty()); + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn schedule_after_zero_works() { + new_test_ext().execute_with(|| { + run_to_block(2); + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call.into())); + // Will trigger on the next block. + run_to_block(3); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn periodic_scheduling_works() { + new_test_ext().execute_with(|| { + // at #4, every 3 blocks, 3 times. + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + Some((3, 3)), + 127, + root(), + Call::Logger(logger::Call::log { i: 42, weight: 1000 }).into() + )); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(7); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + run_to_block(9); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + run_to_block(10); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + }); +} + +#[test] +fn reschedule_works() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + assert_eq!( + Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into()).unwrap(), + (4, 0) + ); + + run_to_block(3); + assert!(logger::log().is_empty()); + + assert_eq!(Scheduler::do_reschedule((4, 0), DispatchTime::At(6)).unwrap(), (6, 0)); + + assert_noop!( + Scheduler::do_reschedule((6, 0), DispatchTime::At(6)), + Error::::RescheduleNoChange + ); + + run_to_block(4); + assert!(logger::log().is_empty()); + + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn reschedule_named_works() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + assert_eq!( + Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(4), + None, + 127, + root(), + call.into(), + ) + .unwrap(), + (4, 0) + ); + + run_to_block(3); + assert!(logger::log().is_empty()); + + assert_eq!( + Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), + (6, 0) + ); + + assert_noop!( + Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)), + Error::::RescheduleNoChange + ); + + run_to_block(4); + assert!(logger::log().is_empty()); + + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn reschedule_named_perodic_works() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + assert_eq!( + Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(4), + Some((3, 3)), + 127, + root(), + call.into(), + ) + .unwrap(), + (4, 0) + ); + + run_to_block(3); + assert!(logger::log().is_empty()); + + assert_eq!( + Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(5)).unwrap(), + (5, 0) + ); + assert_eq!( + Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), + (6, 0) + ); + + run_to_block(5); + assert!(logger::log().is_empty()); + + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + + assert_eq!( + Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(10)).unwrap(), + (10, 0) + ); + + run_to_block(9); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + + run_to_block(10); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + + run_to_block(13); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + }); +} + +#[test] +fn cancel_named_scheduling_works_with_normal_cancel() { + new_test_ext().execute_with(|| { + // at #4. + Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + ) + .unwrap(); + let i = Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into(), + ) + .unwrap(); + run_to_block(3); + assert!(logger::log().is_empty()); + assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); + assert_ok!(Scheduler::do_cancel(None, i)); + run_to_block(100); + assert!(logger::log().is_empty()); + }); +} + +#[test] +fn cancel_named_periodic_scheduling_works() { + new_test_ext().execute_with(|| { + // at #4, every 3 blocks, 3 times. + Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(4), + Some((3, 3)), + 127, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into(), + ) + .unwrap(); + // same id results in error. + assert!(Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + ) + .is_err()); + // different id is ok. + Scheduler::do_schedule_named( + 2u32.encode(), + DispatchTime::At(8), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + ) + .unwrap(); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(6); + assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); + }); +} + +#[test] +fn scheduler_respects_weight_limits() { + new_test_ext().execute_with(|| { + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), + )); + // 69 and 42 do not fit together + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(5); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); + }); +} + +#[test] +fn scheduler_respects_hard_deadlines_more() { + new_test_ext().execute_with(|| { + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 0, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 0, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), + )); + // With base weights, 69 and 42 should not fit together, but do because of hard + // deadlines + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); + }); +} + +#[test] +fn scheduler_respects_priority_ordering() { + new_test_ext().execute_with(|| { + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 1, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 0, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), + )); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); + }); +} + +#[test] +fn scheduler_respects_priority_ordering_with_soft_deadlines() { + new_test_ext().execute_with(|| { + let max_weight = MaximumSchedulerWeight::get() - <() as WeightInfo>::on_initialize(0); + let item_weight = + <() as WeightInfo>::on_initialize(1) - <() as WeightInfo>::on_initialize(0); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 255, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: max_weight / 2 - item_weight }).into(), + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: max_weight / 2 - item_weight }).into(), + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 126, + root(), + Call::Logger(LoggerCall::log { i: 2600, weight: max_weight / 2 - item_weight + 1 }) + .into(), + )); + + // 2600 does not fit with 69 or 42, but has higher priority, so will go through + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 2600u32)]); + // 69 and 42 fit together + run_to_block(5); + assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); + }); +} + +#[test] +fn on_initialize_weight_is_correct() { + new_test_ext().execute_with(|| { + let base_weight = <() as WeightInfo>::on_initialize(0); + let call_weight = MaximumSchedulerWeight::get() / 4; + + // Named + assert_ok!(Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(3), + None, + 255, + root(), + Call::Logger(LoggerCall::log { i: 3, weight: call_weight + 1 }).into(), + )); + // Anon Periodic + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(2), + Some((1000, 3)), + 128, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: call_weight + 2 }).into(), + )); + // Anon + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(2), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: call_weight + 3 }).into(), + )); + // Named Periodic + assert_ok!(Scheduler::do_schedule_named( + 2u32.encode(), + DispatchTime::At(1), + Some((1000, 3)), + 126, + root(), + Call::Logger(LoggerCall::log { i: 2600, weight: call_weight + 4 }).into(), + )); + + // Will include the named periodic only + let actual_weight = Scheduler::on_initialize(1); + assert_eq!( + actual_weight, + base_weight + + call_weight + 4 + <() as MarginalWeightInfo>::item(true, true, Some(false)) + ); + assert_eq!(logger::log(), vec![(root(), 2600u32)]); + + // Will include anon and anon periodic + let actual_weight = Scheduler::on_initialize(2); + assert_eq!( + actual_weight, + base_weight + + call_weight + 2 + <() as MarginalWeightInfo>::item(false, false, Some(false)) + + call_weight + 3 + <() as MarginalWeightInfo>::item(true, false, Some(false)) + ); + assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); + + // Will include named only + let actual_weight = Scheduler::on_initialize(3); + assert_eq!( + actual_weight, + base_weight + + call_weight + 1 + <() as MarginalWeightInfo>::item(false, true, Some(false)) + ); + assert_eq!( + logger::log(), + vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)] + ); + + // Will contain none + let actual_weight = Scheduler::on_initialize(4); + assert_eq!(actual_weight, base_weight); + }); +} + +#[test] +fn root_calls_works() { + new_test_ext().execute_with(|| { + let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + assert_ok!(Scheduler::schedule_named(Origin::root(), 1u32.encode(), 4, None, 127, call,)); + assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); + run_to_block(3); + // Scheduled calls are in the agenda. + assert_eq!(Agenda::::get(4).len(), 2); + assert!(logger::log().is_empty()); + assert_ok!(Scheduler::cancel_named(Origin::root(), 1u32.encode())); + assert_ok!(Scheduler::cancel(Origin::root(), 4, 1)); + // Scheduled calls are made NONE, so should not effect state + run_to_block(100); + assert!(logger::log().is_empty()); + }); +} + +#[test] +fn fails_to_schedule_task_in_the_past() { + new_test_ext().execute_with(|| { + run_to_block(3); + + let call1 = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + let call3 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + + assert_err!( + Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call1), + Error::::TargetBlockNumberInPast, + ); + + assert_err!( + Scheduler::schedule(Origin::root(), 2, None, 127, call2), + Error::::TargetBlockNumberInPast, + ); + + assert_err!( + Scheduler::schedule(Origin::root(), 3, None, 127, call3), + Error::::TargetBlockNumberInPast, + ); + }); +} + +#[test] +fn should_use_orign() { + new_test_ext().execute_with(|| { + let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + assert_ok!(Scheduler::schedule_named( + system::RawOrigin::Signed(1).into(), + 1u32.encode(), + 4, + None, + 127, + call, + )); + assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, 127, call2,)); + run_to_block(3); + // Scheduled calls are in the agenda. + assert_eq!(Agenda::::get(4).len(), 2); + assert!(logger::log().is_empty()); + assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), 1u32.encode())); + assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1)); + // Scheduled calls are made NONE, so should not effect state + run_to_block(100); + assert!(logger::log().is_empty()); + }); +} + +#[test] +fn should_check_orign() { + new_test_ext().execute_with(|| { + let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + assert_noop!( + Scheduler::schedule_named( + system::RawOrigin::Signed(2).into(), + 1u32.encode(), + 4, + None, + 127, + call + ), + BadOrigin + ); + assert_noop!( + Scheduler::schedule(system::RawOrigin::Signed(2).into(), 4, None, 127, call2), + BadOrigin + ); + }); +} + +#[test] +fn should_check_orign_for_cancel() { + new_test_ext().execute_with(|| { + let call = + Box::new(Call::Logger(LoggerCall::log_without_filter { i: 69, weight: 1000 }).into()); + let call2 = + Box::new(Call::Logger(LoggerCall::log_without_filter { i: 42, weight: 1000 }).into()); + assert_ok!(Scheduler::schedule_named( + system::RawOrigin::Signed(1).into(), + 1u32.encode(), + 4, + None, + 127, + call, + )); + assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, 127, call2,)); + run_to_block(3); + // Scheduled calls are in the agenda. + assert_eq!(Agenda::::get(4).len(), 2); + assert!(logger::log().is_empty()); + assert_noop!( + Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), 1u32.encode()), + BadOrigin + ); + assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin); + assert_noop!( + Scheduler::cancel_named(system::RawOrigin::Root.into(), 1u32.encode()), + BadOrigin + ); + assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin); + run_to_block(5); + assert_eq!( + logger::log(), + vec![ + (system::RawOrigin::Signed(1).into(), 69u32), + (system::RawOrigin::Signed(1).into(), 42u32) + ] + ); + }); +} + +#[test] +fn migration_to_v3_works() { + new_test_ext().execute_with(|| { + for i in 0..3u64 { + let k = i.twox_64_concat(); + let old = vec![ + Some(ScheduledV1 { + maybe_id: None, + priority: i as u8 + 10, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), + maybe_periodic: None, + }), + None, + Some(ScheduledV1 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + maybe_periodic: Some((456u64, 10)), + }), + ]; + frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); + } + + assert_eq!(StorageVersion::::get(), Releases::V1); + + assert!(Scheduler::migrate_v1_to_v3()); + + assert_eq_uvec!( + Agenda::::iter().collect::>(), + vec![ + ( + 0, + vec![ + Some(ScheduledV3Of:: { + maybe_id: None, + priority: 10, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV3Of:: { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ] + ), + ( + 1, + vec![ + Some(ScheduledV3Of:: { + maybe_id: None, + priority: 11, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV3Of:: { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ] + ), + ( + 2, + vec![ + Some(ScheduledV3Of:: { + maybe_id: None, + priority: 12, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV3Of:: { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ] + ) + ] + ); + + assert_eq!(StorageVersion::::get(), Releases::V3); + }); +} + +#[test] +fn test_migrate_origin() { + new_test_ext().execute_with(|| { + for i in 0..3u64 { + let k = i.twox_64_concat(); + let old: Vec, u64, u32, u64>>> = vec![ + Some(Scheduled { + maybe_id: None, + priority: i as u8 + 10, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + origin: 3u32, + maybe_periodic: None, + _phantom: Default::default(), + }), + None, + Some(Scheduled { + maybe_id: Some(b"test".to_vec()), + priority: 123, + origin: 2u32, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + _phantom: Default::default(), + }), + ]; + frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); + } + + impl Into for u32 { + fn into(self) -> OriginCaller { + match self { + 3u32 => system::RawOrigin::Root.into(), + 2u32 => system::RawOrigin::None.into(), + _ => unreachable!("test make no use of it"), + } + } + } + + Scheduler::migrate_origin::(); + + assert_eq_uvec!( + Agenda::::iter().collect::>(), + vec![ + ( + 0, + vec![ + Some(ScheduledV2::, u64, OriginCaller, u64> { + maybe_id: None, + priority: 10, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: system::RawOrigin::Root.into(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV2 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: system::RawOrigin::None.into(), + _phantom: PhantomData::::default(), + }), + ] + ), + ( + 1, + vec![ + Some(ScheduledV2 { + maybe_id: None, + priority: 11, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: system::RawOrigin::Root.into(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV2 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: system::RawOrigin::None.into(), + _phantom: PhantomData::::default(), + }), + ] + ), + ( + 2, + vec![ + Some(ScheduledV2 { + maybe_id: None, + priority: 12, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: system::RawOrigin::Root.into(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV2 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: system::RawOrigin::None.into(), + _phantom: PhantomData::::default(), + }), + ] + ) + ] + ); + }); +} diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index d83aefdc453af..3c2ed47110b66 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-12-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -35,7 +35,6 @@ // --output=./frame/scheduler/src/weights.rs // --template=./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -45,6 +44,16 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_scheduler. pub trait WeightInfo { + fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight; + fn on_initialize_named_resolved(s: u32, ) -> Weight; + fn on_initialize_periodic_resolved(s: u32, ) -> Weight; + fn on_initialize_resolved(s: u32, ) -> Weight; + fn on_initialize_named_aborted(s: u32, ) -> Weight; + fn on_initialize_aborted(s: u32, ) -> Weight; + fn on_initialize_periodic_named(s: u32, ) -> Weight; + fn on_initialize_periodic(s: u32, ) -> Weight; + fn on_initialize_named(s: u32, ) -> Weight; + fn on_initialize(s: u32, ) -> Weight; fn schedule(s: u32, ) -> Weight; fn cancel(s: u32, ) -> Weight; fn schedule_named(s: u32, ) -> Weight; @@ -54,38 +63,149 @@ pub trait WeightInfo { /// Weights for pallet_scheduler using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { + (8_183_000 as Weight) + // Standard Error: 36_000 + .saturating_add((34_670_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named_resolved(s: u32, ) -> Weight { + (11_520_000 as Weight) + // Standard Error: 30_000 + .saturating_add((26_386_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn on_initialize_periodic_resolved(s: u32, ) -> Weight { + (8_222_000 as Weight) + // Standard Error: 33_000 + .saturating_add((28_925_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn on_initialize_resolved(s: u32, ) -> Weight { + (11_610_000 as Weight) + // Standard Error: 26_000 + .saturating_add((23_857_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:0) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named_aborted(s: u32, ) -> Weight { + (11_067_000 as Weight) + // Standard Error: 15_000 + .saturating_add((11_728_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:0) + fn on_initialize_aborted(s: u32, ) -> Weight { + (13_045_000 as Weight) + // Standard Error: 5_000 + .saturating_add((6_378_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_periodic_named(s: u32, ) -> Weight { + (13_496_000 as Weight) + // Standard Error: 27_000 + .saturating_add((17_932_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + fn on_initialize_periodic(s: u32, ) -> Weight { + (17_074_000 as Weight) + // Standard Error: 16_000 + .saturating_add((11_982_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named(s: u32, ) -> Weight { + (18_730_000 as Weight) + // Standard Error: 10_000 + .saturating_add((9_909_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + fn on_initialize(s: u32, ) -> Weight { + (17_844_000 as Weight) + // Standard Error: 9_000 + .saturating_add((7_719_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (24_730_000 as Weight) + (23_361_000 as Weight) // Standard Error: 1_000 - .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((82_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (23_272_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_261_000 as Weight).saturating_mul(s as Weight)) + (22_359_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_219_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (30_971_000 as Weight) + (28_499_000 as Weight) // Standard Error: 1_000 - .saturating_add((96_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((98_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (25_778_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_270_000 as Weight).saturating_mul(s as Weight)) + (24_995_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_223_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -93,38 +213,149 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { + (8_183_000 as Weight) + // Standard Error: 36_000 + .saturating_add((34_670_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named_resolved(s: u32, ) -> Weight { + (11_520_000 as Weight) + // Standard Error: 30_000 + .saturating_add((26_386_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn on_initialize_periodic_resolved(s: u32, ) -> Weight { + (8_222_000 as Weight) + // Standard Error: 33_000 + .saturating_add((28_925_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn on_initialize_resolved(s: u32, ) -> Weight { + (11_610_000 as Weight) + // Standard Error: 26_000 + .saturating_add((23_857_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:0) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named_aborted(s: u32, ) -> Weight { + (11_067_000 as Weight) + // Standard Error: 15_000 + .saturating_add((11_728_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:0) + fn on_initialize_aborted(s: u32, ) -> Weight { + (13_045_000 as Weight) + // Standard Error: 5_000 + .saturating_add((6_378_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_periodic_named(s: u32, ) -> Weight { + (13_496_000 as Weight) + // Standard Error: 27_000 + .saturating_add((17_932_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + fn on_initialize_periodic(s: u32, ) -> Weight { + (17_074_000 as Weight) + // Standard Error: 16_000 + .saturating_add((11_982_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named(s: u32, ) -> Weight { + (18_730_000 as Weight) + // Standard Error: 10_000 + .saturating_add((9_909_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + fn on_initialize(s: u32, ) -> Weight { + (17_844_000 as Weight) + // Standard Error: 9_000 + .saturating_add((7_719_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (24_730_000 as Weight) + (23_361_000 as Weight) // Standard Error: 1_000 - .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((82_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (23_272_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_261_000 as Weight).saturating_mul(s as Weight)) + (22_359_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_219_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (30_971_000 as Weight) + (28_499_000 as Weight) // Standard Error: 1_000 - .saturating_add((96_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((98_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (25_778_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_270_000 as Weight).saturating_mul(s as Weight)) + (24_995_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_223_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 3c1f268ade073..01817723e94eb 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -53,8 +53,8 @@ pub use misc::{ Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, - Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, TryDrop, - UnixTime, WrapperKeepOpaque, WrapperOpaque, + Len, OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider, PreimageRecipient, + PrivilegeCmp, SameOrOther, Time, TryDrop, UnixTime, WrapperKeepOpaque, WrapperOpaque, }; mod stored_map; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 165a83b4be2a0..8bab1581a697c 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -94,6 +94,12 @@ pub trait TryDrop: Sized { fn try_drop(self) -> Result<(), Self>; } +impl TryDrop for () { + fn try_drop(self) -> Result<(), Self> { + Ok(()) + } +} + /// Return type used when we need to return one of two items, each of the opposite direction or /// sign, with one (`Same`) being of the same type as the `self` or primary argument of the function /// that returned it. @@ -577,6 +583,65 @@ impl TypeInfo for WrapperKeepOpaque { } } +/// A interface for looking up preimages from their hash on chain. +pub trait PreimageProvider { + /// Returns whether a preimage exists for a given hash. + /// + /// A value of `true` implies that `get_preimage` is `Some`. + fn have_preimage(hash: &Hash) -> bool; + + /// Returns the preimage for a given hash. + fn get_preimage(hash: &Hash) -> Option>; + + /// Returns whether a preimage request exists for a given hash. + fn preimage_requested(hash: &Hash) -> bool; + + /// Request that someone report a preimage. Providers use this to optimise the economics for + /// preimage reporting. + fn request_preimage(hash: &Hash); + + /// Cancel a previous preimage request. + fn unrequest_preimage(hash: &Hash); +} + +impl PreimageProvider for () { + fn have_preimage(_: &Hash) -> bool { + false + } + fn get_preimage(_: &Hash) -> Option> { + None + } + fn preimage_requested(_: &Hash) -> bool { + false + } + fn request_preimage(_: &Hash) {} + fn unrequest_preimage(_: &Hash) {} +} + +/// A interface for managing preimages to hashes on chain. +/// +/// Note that this API does not assume any underlying user is calling, and thus +/// does not handle any preimage ownership or fees. Other system level logic that +/// uses this API should implement that on their own side. +pub trait PreimageRecipient: PreimageProvider { + /// Maximum size of a preimage. + type MaxSize: Get; + + /// Store the bytes of a preimage on chain. + fn note_preimage(bytes: crate::BoundedVec); + + /// Clear a previously noted preimage. This is infallible and should be treated more like a + /// hint - if it was not previously noted or if it is now requested, then this will not do + /// anything. + fn unnote_preimage(hash: &Hash); +} + +impl PreimageRecipient for () { + type MaxSize = (); + fn note_preimage(_: crate::BoundedVec) {} + fn unnote_preimage(_: &Hash) {} +} + #[cfg(test)] mod test { use super::*; diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 19f50a93c0681..1cedb96cb14bb 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -17,10 +17,10 @@ //! Traits and associated utilities for scheduling dispatchables in FRAME. -use codec::{Codec, Decode, Encode, EncodeLike}; +use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{DispatchError, RuntimeDebug}; -use sp_std::{fmt::Debug, prelude::*}; +use sp_std::{fmt::Debug, prelude::*, result::Result}; /// Information relating to the period of a scheduled task. First item is the length of the /// period and the second is the number of times it should be executed in total before the task @@ -49,86 +49,323 @@ pub const HARD_DEADLINE: Priority = 63; /// The lowest priority. Most stuff should be around here. pub const LOWEST_PRIORITY: Priority = 255; -/// A type that can be used as a scheduler. -pub trait Anon { - /// An address which can be used for removing a scheduled task. - type Address: Codec + Clone + Eq + EncodeLike + Debug; - - /// Schedule a dispatch to happen at the beginning of some block in the future. - /// - /// This is not named. - fn schedule( - when: DispatchTime, - maybe_periodic: Option>, - priority: Priority, - origin: Origin, - call: Call, - ) -> Result; - - /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that, - /// also. - /// - /// Will return an error if the `address` is invalid. - /// - /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. - /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. - /// - /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For - /// that, you must name the task explicitly using the `Named` trait. - fn cancel(address: Self::Address) -> Result<(), ()>; - - /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed - /// only if it is executed *before* the currently scheduled block. For periodic tasks, - /// this dispatch is guaranteed to succeed only before the *initial* execution; for - /// others, use `reschedule_named`. - /// - /// Will return an error if the `address` is invalid. - fn reschedule( - address: Self::Address, - when: DispatchTime, - ) -> Result; - - /// Return the next dispatch time for a given task. - /// - /// Will return an error if the `address` is invalid. - fn next_dispatch_time(address: Self::Address) -> Result; +/// Type representing an encodable value or the hash of the encoding of such a value. +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum MaybeHashed { + /// The value itself. + Value(T), + /// The hash of the encoded value which this value represents. + Hash(Hash), } -/// A type that can be used as a scheduler. -pub trait Named { - /// An address which can be used for removing a scheduled task. - type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug; - - /// Schedule a dispatch to happen at the beginning of some block in the future. - /// - /// - `id`: The identity of the task. This must be unique and will return an error if not. - fn schedule_named( - id: Vec, - when: DispatchTime, - maybe_periodic: Option>, - priority: Priority, - origin: Origin, - call: Call, - ) -> Result; - - /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances - /// of that, also. - /// - /// Will return an error if the `id` is invalid. - /// - /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. - /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. - fn cancel_named(id: Vec) -> Result<(), ()>; - - /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed - /// only if it is executed *before* the currently scheduled block. - fn reschedule_named( - id: Vec, - when: DispatchTime, - ) -> Result; - - /// Return the next dispatch time for a given task. - /// - /// Will return an error if the `id` is invalid. - fn next_dispatch_time(id: Vec) -> Result; +impl From for MaybeHashed { + fn from(t: T) -> Self { + MaybeHashed::Value(t) + } } + +/// Error type for `MaybeHashed::lookup`. +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum LookupError { + /// A call of this hash was not known. + Unknown, + /// The preimage for this hash was known but could not be decoded into a `Call`. + BadFormat, +} + +impl MaybeHashed { + pub fn as_value(&self) -> Option<&T> { + match &self { + Self::Value(c) => Some(c), + Self::Hash(_) => None, + } + } + + pub fn as_hash(&self) -> Option<&H> { + match &self { + Self::Value(_) => None, + Self::Hash(h) => Some(h), + } + } + + pub fn ensure_requested>(&self) { + match &self { + Self::Value(_) => (), + Self::Hash(hash) => P::request_preimage(hash), + } + } + + pub fn ensure_unrequested>(&self) { + match &self { + Self::Value(_) => (), + Self::Hash(hash) => P::unrequest_preimage(hash), + } + } + + pub fn resolved>(self) -> (Self, Option) { + match self { + Self::Value(c) => (Self::Value(c), None), + Self::Hash(h) => { + let data = match P::get_preimage(&h) { + Some(p) => p, + None => return (Self::Hash(h), None), + }; + match T::decode(&mut &data[..]) { + Ok(c) => (Self::Value(c), Some(h)), + Err(_) => (Self::Hash(h), None), + } + }, + } + } +} + +pub mod v1 { + use super::*; + + /// A type that can be used as a scheduler. + pub trait Anon { + /// An address which can be used for removing a scheduled task. + type Address: Codec + Clone + Eq + EncodeLike + Debug; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// This is not named. + fn schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Call, + ) -> Result; + + /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that, + /// also. + /// + /// Will return an error if the `address` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + /// + /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For + /// that, you must name the task explicitly using the `Named` trait. + fn cancel(address: Self::Address) -> Result<(), ()>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. For periodic tasks, + /// this dispatch is guaranteed to succeed only before the *initial* execution; for + /// others, use `reschedule_named`. + /// + /// Will return an error if the `address` is invalid. + fn reschedule( + address: Self::Address, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an error if the `address` is invalid. + fn next_dispatch_time(address: Self::Address) -> Result; + } + + /// A type that can be used as a scheduler. + pub trait Named { + /// An address which can be used for removing a scheduled task. + type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// - `id`: The identity of the task. This must be unique and will return an error if not. + fn schedule_named( + id: Vec, + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Call, + ) -> Result; + + /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances + /// of that, also. + /// + /// Will return an error if the `id` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + fn cancel_named(id: Vec) -> Result<(), ()>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. + fn reschedule_named( + id: Vec, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an error if the `id` is invalid. + fn next_dispatch_time(id: Vec) -> Result; + } + + impl Anon for T + where + T: v2::Anon, + { + type Address = T::Address; + + fn schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Call, + ) -> Result { + let c = MaybeHashed::::Value(call); + T::schedule(when, maybe_periodic, priority, origin, c) + } + + fn cancel(address: Self::Address) -> Result<(), ()> { + T::cancel(address) + } + + fn reschedule( + address: Self::Address, + when: DispatchTime, + ) -> Result { + T::reschedule(address, when) + } + + fn next_dispatch_time(address: Self::Address) -> Result { + T::next_dispatch_time(address) + } + } + + impl Named for T + where + T: v2::Named, + { + type Address = T::Address; + + fn schedule_named( + id: Vec, + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Call, + ) -> Result { + let c = MaybeHashed::::Value(call); + T::schedule_named(id, when, maybe_periodic, priority, origin, c) + } + + fn cancel_named(id: Vec) -> Result<(), ()> { + T::cancel_named(id) + } + + fn reschedule_named( + id: Vec, + when: DispatchTime, + ) -> Result { + T::reschedule_named(id, when) + } + + fn next_dispatch_time(id: Vec) -> Result { + T::next_dispatch_time(id) + } + } +} + +pub mod v2 { + use super::*; + + /// A type that can be used as a scheduler. + pub trait Anon { + /// An address which can be used for removing a scheduled task. + type Address: Codec + Clone + Eq + EncodeLike + Debug; + /// A means of expressing a call by the hash of its encoded data. + type Hash; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// This is not named. + fn schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: MaybeHashed, + ) -> Result; + + /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that, + /// also. + /// + /// Will return an error if the `address` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + /// + /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For + /// that, you must name the task explicitly using the `Named` trait. + fn cancel(address: Self::Address) -> Result<(), ()>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. For periodic tasks, + /// this dispatch is guaranteed to succeed only before the *initial* execution; for + /// others, use `reschedule_named`. + /// + /// Will return an error if the `address` is invalid. + fn reschedule( + address: Self::Address, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an error if the `address` is invalid. + fn next_dispatch_time(address: Self::Address) -> Result; + } + + /// A type that can be used as a scheduler. + pub trait Named { + /// An address which can be used for removing a scheduled task. + type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug; + /// A means of expressing a call by the hash of its encoded data. + type Hash; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// - `id`: The identity of the task. This must be unique and will return an error if not. + fn schedule_named( + id: Vec, + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: MaybeHashed, + ) -> Result; + + /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances + /// of that, also. + /// + /// Will return an error if the `id` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + fn cancel_named(id: Vec) -> Result<(), ()>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. + fn reschedule_named( + id: Vec, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an error if the `id` is invalid. + fn next_dispatch_time(id: Vec) -> Result; + } +} + +pub use v1::*; + +use super::PreimageProvider; diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index bf078658477f5..9fdb08b8bd6e9 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -199,3 +199,91 @@ pub trait Currency { balance: Self::Balance, ) -> SignedImbalance; } + +#[cfg(feature = "std")] +impl Currency for () { + type Balance = u32; + type PositiveImbalance = (); + type NegativeImbalance = (); + fn total_balance(_: &AccountId) -> Self::Balance { + 0 + } + fn can_slash(_: &AccountId, _: Self::Balance) -> bool { + true + } + fn total_issuance() -> Self::Balance { + 0 + } + fn minimum_balance() -> Self::Balance { + 0 + } + fn burn(_: Self::Balance) -> Self::PositiveImbalance { + () + } + fn issue(_: Self::Balance) -> Self::NegativeImbalance { + () + } + fn pair(_: Self::Balance) -> (Self::PositiveImbalance, Self::NegativeImbalance) { + ((), ()) + } + fn free_balance(_: &AccountId) -> Self::Balance { + 0 + } + fn ensure_can_withdraw( + _: &AccountId, + _: Self::Balance, + _: WithdrawReasons, + _: Self::Balance, + ) -> DispatchResult { + Ok(()) + } + fn transfer( + _: &AccountId, + _: &AccountId, + _: Self::Balance, + _: ExistenceRequirement, + ) -> DispatchResult { + Ok(()) + } + fn slash(_: &AccountId, _: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { + ((), 0) + } + fn deposit_into_existing( + _: &AccountId, + _: Self::Balance, + ) -> Result { + Ok(()) + } + fn resolve_into_existing( + _: &AccountId, + _: Self::NegativeImbalance, + ) -> Result<(), Self::NegativeImbalance> { + Ok(()) + } + fn deposit_creating(_: &AccountId, _: Self::Balance) -> Self::PositiveImbalance { + () + } + fn resolve_creating(_: &AccountId, _: Self::NegativeImbalance) {} + fn withdraw( + _: &AccountId, + _: Self::Balance, + _: WithdrawReasons, + _: ExistenceRequirement, + ) -> Result { + Ok(()) + } + fn settle( + _: &AccountId, + _: Self::PositiveImbalance, + _: WithdrawReasons, + _: ExistenceRequirement, + ) -> Result<(), Self::PositiveImbalance> { + Ok(()) + } + fn make_free_balance_be( + _: &AccountId, + _: Self::Balance, + ) -> SignedImbalance { + SignedImbalance::Positive(()) + } +} diff --git a/frame/support/src/traits/tokens/currency/reservable.rs b/frame/support/src/traits/tokens/currency/reservable.rs index 0ca7a93dc7f69..e2313a9d2550d 100644 --- a/frame/support/src/traits/tokens/currency/reservable.rs +++ b/frame/support/src/traits/tokens/currency/reservable.rs @@ -81,6 +81,33 @@ pub trait ReservableCurrency: Currency { ) -> Result; } +#[cfg(feature = "std")] +impl ReservableCurrency for () { + fn can_reserve(_: &AccountId, _: Self::Balance) -> bool { + true + } + fn slash_reserved(_: &AccountId, _: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { + ((), 0) + } + fn reserved_balance(_: &AccountId) -> Self::Balance { + 0 + } + fn reserve(_: &AccountId, _: Self::Balance) -> DispatchResult { + Ok(()) + } + fn unreserve(_: &AccountId, _: Self::Balance) -> Self::Balance { + 0 + } + fn repatriate_reserved( + _: &AccountId, + _: &AccountId, + _: Self::Balance, + _: BalanceStatus, + ) -> Result { + Ok(0) + } +} + pub trait NamedReservableCurrency: ReservableCurrency { /// An identifier for a reserve. Used for disambiguating different reserves so that /// they can be individually replaced or removed. diff --git a/frame/support/src/traits/tokens/imbalance.rs b/frame/support/src/traits/tokens/imbalance.rs index 0f7b38a65efc8..eaa18be58f617 100644 --- a/frame/support/src/traits/tokens/imbalance.rs +++ b/frame/support/src/traits/tokens/imbalance.rs @@ -177,3 +177,55 @@ pub trait Imbalance: Sized + TryDrop + Default { /// The raw value of self. fn peek(&self) -> Balance; } + +#[cfg(feature = "std")] +impl Imbalance for () { + type Opposite = (); + fn zero() -> Self { + () + } + fn drop_zero(self) -> Result<(), Self> { + Ok(()) + } + fn split(self, _: Balance) -> (Self, Self) { + ((), ()) + } + fn ration(self, _: u32, _: u32) -> (Self, Self) + where + Balance: From + Saturating + Div, + { + ((), ()) + } + fn split_merge(self, _: Balance, _: (Self, Self)) -> (Self, Self) { + ((), ()) + } + fn ration_merge(self, _: u32, _: u32, _: (Self, Self)) -> (Self, Self) + where + Balance: From + Saturating + Div, + { + ((), ()) + } + fn split_merge_into(self, _: Balance, _: &mut (Self, Self)) {} + fn ration_merge_into(self, _: u32, _: u32, _: &mut (Self, Self)) + where + Balance: From + Saturating + Div, + { + } + fn merge(self, _: Self) -> Self { + () + } + fn merge_into(self, _: &mut Self) {} + fn maybe_merge(self, _: Option) -> Self { + () + } + fn subsume(&mut self, _: Self) {} + fn maybe_subsume(&mut self, _: Option) { + () + } + fn offset(self, _: Self::Opposite) -> SameOrOther { + SameOrOther::None + } + fn peek(&self) -> Balance { + Default::default() + } +} diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 8823aa37c19c5..f62d60f6fda93 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -344,7 +344,7 @@ pub mod pallet { /// # #[pallet::weight(T::SystemWeightInfo::remark(_remark.len() as u32))] pub fn remark(origin: OriginFor, _remark: Vec) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; + ensure_signed_or_root(origin)?; Ok(().into()) } @@ -872,6 +872,22 @@ where } } +/// Ensure that the origin `o` represents either a signed extrinsic (i.e. transaction) or the root. +/// Returns `Ok` with the account that signed the extrinsic, `None` if it was root, or an `Err` +/// otherwise. +pub fn ensure_signed_or_root( + o: OuterOrigin, +) -> Result, BadOrigin> +where + OuterOrigin: Into, OuterOrigin>>, +{ + match o.into() { + Ok(RawOrigin::Root) => Ok(None), + Ok(RawOrigin::Signed(t)) => Ok(Some(t)), + _ => Err(BadOrigin), + } +} + /// Ensure that the origin `o` represents the root. Returns `Ok` or an `Err` otherwise. pub fn ensure_root(o: OuterOrigin) -> Result<(), BadOrigin> where From c7a3e46d315063d553baeba2bb5ee5b84efdfb1a Mon Sep 17 00:00:00 2001 From: Denis Tsai Date: Sat, 11 Dec 2021 23:20:18 +0800 Subject: [PATCH 0330/1472] expose ecdsa_sign_prehashed in sp-io (#10119) * expose ecdsa_sign_prehashed in sp-io * add ecdsa_verify_prehashed to host functions for completeness * cargo fmt --- primitives/io/src/lib.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 94ae1a8f70838..44649abd28911 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -709,6 +709,22 @@ pub trait Crypto { .map(|sig| ecdsa::Signature::from_slice(sig.as_slice())) } + /// Sign the given a pre-hashed `msg` with the `ecdsa` key that corresponds to the given public + /// key and key type in the keystore. + /// + /// Returns the signature. + fn ecdsa_sign_prehashed( + &mut self, + id: KeyTypeId, + pub_key: &ecdsa::Public, + msg: &[u8; 32], + ) -> Option { + let keystore = &***self + .extension::() + .expect("No `keystore` associated for the current context!"); + SyncCryptoStore::ecdsa_sign_prehashed(keystore, id, pub_key, msg).ok().flatten() + } + /// Verify `ecdsa` signature. /// /// Returns `true` when the verification was successful. @@ -724,6 +740,17 @@ pub trait Crypto { ecdsa::Pair::verify(sig, msg, pub_key) } + /// Verify `ecdsa` signature with pre-hashed `msg`. + /// + /// Returns `true` when the verification was successful. + fn ecdsa_verify_prehashed( + sig: &ecdsa::Signature, + msg: &[u8; 32], + pub_key: &ecdsa::Public, + ) -> bool { + ecdsa::Pair::verify_prehashed(sig, msg, pub_key) + } + /// Register a `ecdsa` signature for batch verification. /// /// Batch verification must be enabled by calling [`start_batch_verify`]. From 914f6e50ea39682cb1e881bd3d67f4bcb2c01af9 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sun, 12 Dec 2021 00:41:46 +0100 Subject: [PATCH 0331/1472] Make Preimage WeightInfo public (#10474) --- frame/preimage/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index bfa1ce5263360..2d227000c9edc 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -48,7 +48,7 @@ use frame_support::{ BoundedVec, }; use scale_info::TypeInfo; -use weights::WeightInfo; +pub use weights::WeightInfo; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; From b9cafba3d0e7a5950ac78d81e4ab7f2074938666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 13 Dec 2021 08:23:26 +0100 Subject: [PATCH 0332/1472] frame-system weights: Remove `set_changes_trie_config`. (#10470) This dispatchable was removed, so we don't need it anymore. --- frame/system/src/weights.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index 281d26375c81b..d05ad2a867b59 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -48,7 +48,6 @@ pub trait WeightInfo { fn remark(b: u32, ) -> Weight; fn remark_with_event(b: u32, ) -> Weight; fn set_heap_pages() -> Weight; - fn set_changes_trie_config() -> Weight; fn set_storage(i: u32, ) -> Weight; fn kill_storage(i: u32, ) -> Weight; fn kill_prefix(p: u32, ) -> Weight; @@ -72,13 +71,6 @@ impl WeightInfo for SubstrateWeight { (1_891_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Digest (r:1 w:1) - // Storage: unknown [0x3a6368616e6765735f74726965] (r:0 w:1) - fn set_changes_trie_config() -> Weight { - (7_370_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - } // Storage: Skipped Metadata (r:0 w:0) fn set_storage(i: u32, ) -> Weight { (0 as Weight) @@ -119,13 +111,6 @@ impl WeightInfo for () { (1_891_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Digest (r:1 w:1) - // Storage: unknown [0x3a6368616e6765735f74726965] (r:0 w:1) - fn set_changes_trie_config() -> Weight { - (7_370_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - } // Storage: Skipped Metadata (r:0 w:0) fn set_storage(i: u32, ) -> Weight { (0 as Weight) From 55cd07a7e22c26932f7bd16b87ea5a7569e38eb4 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Mon, 13 Dec 2021 15:03:59 +0100 Subject: [PATCH 0333/1472] Remove Default bound for AccountId (#10403) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove Default for AccountId * More removals of default * Update frame/authorship/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/authorship/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/authorship/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/authorship/src/lib.rs Co-authored-by: Bastian Köcher * More work * More work * Remove old code * More work * pallet-asset-tx-payment * tips * sc-consensus-babe * sc-finality-grandpa * sc-consensus-babe-rpc * sc-cli * make npos crates accept non-default account (#10420) * minimal changes to make npos pallets all work * make this pesky reduce.rs a bit cleaner * more work * more work * Tests build * Fix imonline tests * Formatting * Fixes * Fixes * Fix bench * Fixes * Fixes * Fixes * Fixes * Fixes * Formatting * Fixes * Formatting * Fixes * Formatting * Fixes * Formatting * Fixes * Formatting * Update client/keystore/src/local.rs Co-authored-by: Bastian Köcher * Update client/finality-grandpa/src/lib.rs Co-authored-by: Bastian Köcher * Update client/keystore/src/local.rs Co-authored-by: Bastian Köcher * Update client/keystore/src/local.rs Co-authored-by: Bastian Köcher * Update frame/staking/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/staking/src/lib.rs Co-authored-by: Bastian Köcher * Update primitives/runtime/src/traits.rs Co-authored-by: Bastian Köcher * Formatting Co-authored-by: Bastian Köcher Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: kianenigma --- Cargo.lock | 16 +- Cargo.toml | 1 - bin/node-template/node/src/chain_spec.rs | 2 +- bin/node/cli/src/chain_spec.rs | 2 +- bin/node/executor/Cargo.toml | 1 + bin/node/executor/tests/submit_transaction.rs | 16 +- bin/node/runtime/src/impls.rs | 11 +- bin/node/runtime/src/lib.rs | 4 +- bin/node/testing/src/genesis.rs | 6 +- bin/utils/chain-spec-builder/src/main.rs | 2 +- .../basic-authorship/src/basic_authorship.rs | 8 +- client/cli/src/commands/insert_key.rs | 2 +- client/cli/src/commands/inspect_key.rs | 2 +- client/cli/src/commands/verify.rs | 15 +- client/cli/src/error.rs | 12 +- client/cli/src/runner.rs | 4 +- client/consensus/aura/src/lib.rs | 2 +- client/consensus/babe/rpc/src/lib.rs | 2 +- client/consensus/babe/src/authorship.rs | 2 +- client/consensus/babe/src/lib.rs | 2 +- client/consensus/babe/src/verification.rs | 2 +- client/finality-grandpa/rpc/src/lib.rs | 8 +- client/finality-grandpa/src/authorities.rs | 37 +- client/finality-grandpa/src/aux_schema.rs | 12 +- .../src/communication/gossip.rs | 21 +- .../src/communication/tests.rs | 4 +- client/finality-grandpa/src/finality_proof.rs | 10 +- client/finality-grandpa/src/lib.rs | 17 +- client/finality-grandpa/src/tests.rs | 2 +- client/finality-grandpa/src/until_imported.rs | 17 +- client/keystore/src/local.rs | 39 +- client/network/src/service.rs | 2 +- client/rpc/src/author/tests.rs | 12 +- client/service/src/lib.rs | 2 +- client/tracing/proc-macro/src/lib.rs | 8 +- client/transaction-pool/benches/basics.rs | 5 +- client/transaction-pool/src/graph/pool.rs | 7 +- frame/aura/src/lib.rs | 1 - frame/authorship/src/lib.rs | 31 +- frame/babe/src/equivocation.rs | 2 +- frame/babe/src/lib.rs | 2 +- frame/beefy-mmr/src/lib.rs | 2 +- frame/beefy/src/lib.rs | 2 +- frame/benchmarking/src/utils.rs | 12 +- frame/bounties/src/lib.rs | 2 +- frame/collective/src/benchmarking.rs | 36 +- frame/contracts/src/migration.rs | 5 +- frame/democracy/src/benchmarking.rs | 9 +- .../src/benchmarking.rs | 13 +- .../election-provider-multi-phase/src/lib.rs | 2 +- .../src/signed.rs | 20 +- frame/elections-phragmen/src/lib.rs | 17 +- frame/elections/Cargo.toml | 42 - frame/elections/README.md | 7 - frame/elections/src/lib.rs | 1324 ------------ frame/elections/src/mock.rs | 274 --- frame/elections/src/tests.rs | 1881 ----------------- frame/examples/basic/src/lib.rs | 10 + frame/examples/offchain-worker/src/lib.rs | 12 +- frame/examples/offchain-worker/src/tests.rs | 8 +- frame/examples/parallel/src/lib.rs | 8 +- frame/examples/parallel/src/tests.rs | 19 +- frame/grandpa/src/equivocation.rs | 2 +- frame/im-online/src/lib.rs | 1 - frame/im-online/src/mock.rs | 10 +- frame/multisig/src/lib.rs | 5 +- frame/proxy/src/lib.rs | 5 +- frame/session/benchmarking/src/lib.rs | 7 +- frame/session/src/lib.rs | 37 +- frame/staking/src/benchmarking.rs | 22 +- frame/staking/src/lib.rs | 49 +- frame/staking/src/mock.rs | 12 +- frame/staking/src/pallet/impls.rs | 18 +- frame/staking/src/tests.rs | 58 +- frame/sudo/src/lib.rs | 26 +- frame/sudo/src/mock.rs | 2 +- frame/sudo/src/tests.rs | 8 +- frame/support/src/traits/validation.rs | 2 +- frame/support/test/tests/construct_runtime.rs | 18 +- frame/system/src/extensions/check_genesis.rs | 12 +- .../system/src/extensions/check_mortality.rs | 10 + .../src/extensions/check_non_zero_sender.rs | 10 + .../src/extensions/check_spec_version.rs | 15 +- .../system/src/extensions/check_tx_version.rs | 14 +- frame/system/src/extensions/check_weight.rs | 18 +- frame/system/src/lib.rs | 1 - frame/tips/src/lib.rs | 7 +- .../asset-tx-payment/src/lib.rs | 65 +- .../asset-tx-payment/src/tests.rs | 37 +- frame/transaction-payment/src/lib.rs | 31 +- frame/utility/src/lib.rs | 5 +- primitives/api/test/tests/runtime_calls.rs | 2 +- primitives/application-crypto/src/ecdsa.rs | 2 +- primitives/application-crypto/src/ed25519.rs | 2 +- primitives/application-crypto/src/lib.rs | 34 +- primitives/application-crypto/src/sr25519.rs | 2 +- primitives/core/src/crypto.rs | 86 +- primitives/core/src/ecdsa.rs | 38 +- primitives/core/src/ed25519.rs | 43 +- primitives/core/src/lib.rs | 2 +- primitives/core/src/sr25519.rs | 40 +- primitives/io/src/lib.rs | 30 +- primitives/keyring/src/ed25519.rs | 2 +- primitives/keyring/src/sr25519.rs | 2 +- primitives/keystore/src/testing.rs | 12 +- primitives/npos-elections/src/lib.rs | 39 +- primitives/npos-elections/src/pjr.rs | 35 +- primitives/npos-elections/src/reduce.rs | 72 +- primitives/npos-elections/src/tests.rs | 13 +- primitives/npos-elections/src/traits.rs | 4 +- .../runtime/src/generic/checked_extrinsic.rs | 16 +- .../src/generic/unchecked_extrinsic.rs | 12 +- primitives/runtime/src/lib.rs | 37 +- primitives/runtime/src/multiaddress.rs | 6 - primitives/runtime/src/testing.rs | 8 +- primitives/runtime/src/traits.rs | 64 +- .../runtime/transaction-pool/src/lib.rs | 5 +- test-utils/test-runner/src/node.rs | 6 +- 118 files changed, 998 insertions(+), 4181 deletions(-) delete mode 100644 frame/elections/Cargo.toml delete mode 100644 frame/elections/README.md delete mode 100644 frame/elections/src/lib.rs delete mode 100644 frame/elections/src/mock.rs delete mode 100644 frame/elections/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index ab8132c6b7cd3..4bed902878934 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4613,6 +4613,7 @@ dependencies = [ "sp-consensus-babe", "sp-core", "sp-externalities", + "sp-keyring", "sp-keystore", "sp-runtime", "sp-state-machine", @@ -5554,21 +5555,6 @@ dependencies = [ "strum_macros", ] -[[package]] -name = "pallet-elections" -version = "4.0.0-dev" -dependencies = [ - "frame-support", - "frame-system", - "pallet-balances", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index a26652e39774a..93f7d42c8238c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,7 +81,6 @@ members = [ "frame/contracts/rpc/runtime-api", "frame/democracy", "frame/try-runtime", - "frame/elections", "frame/election-provider-multi-phase", "frame/election-provider-support", "frame/examples/basic", diff --git a/bin/node-template/node/src/chain_spec.rs b/bin/node-template/node/src/chain_spec.rs index d32a0dcb29d00..af94a63335e0e 100644 --- a/bin/node-template/node/src/chain_spec.rs +++ b/bin/node-template/node/src/chain_spec.rs @@ -147,7 +147,7 @@ fn testnet_genesis( }, sudo: SudoConfig { // Assign network admin rights. - key: root_key, + key: Some(root_key), }, transaction_payment: Default::default(), } diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 6d11722081e30..b29248519cc08 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -338,7 +338,7 @@ pub fn testnet_genesis( .collect(), phantom: Default::default(), }, - sudo: SudoConfig { key: root_key }, + sudo: SudoConfig { key: Some(root_key) }, babe: BabeConfig { authorities: vec![], epoch_config: Some(node_runtime::BABE_GENESIS_EPOCH_CONFIG), diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 2144b92986167..20898315d0e0a 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -38,6 +38,7 @@ sp-application-crypto = { version = "4.0.0-dev", path = "../../../primitives/app sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } +sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } wat = "1.0" futures = "0.3.9" diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs index 4f0f8061641f8..d561e08762dfa 100644 --- a/bin/node/executor/tests/submit_transaction.rs +++ b/bin/node/executor/tests/submit_transaction.rs @@ -20,6 +20,7 @@ use frame_system::offchain::{SendSignedTransaction, Signer, SubmitTransaction}; use node_runtime::{Executive, Indices, Runtime, UncheckedExtrinsic}; use sp_application_crypto::AppKey; use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt}; +use sp_keyring::sr25519::Keyring::Alice; use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStore}; use std::sync::Arc; @@ -33,7 +34,8 @@ fn should_submit_unsigned_transaction() { t.register_extension(TransactionPoolExt::new(pool)); t.execute_with(|| { - let signature = Default::default(); + let signature = + pallet_im_online::sr25519::AuthoritySignature::try_from(vec![0; 64]).unwrap(); let heartbeat_data = pallet_im_online::Heartbeat { block_number: 1, network_state: Default::default(), @@ -85,7 +87,7 @@ fn should_submit_signed_transaction() { let results = Signer::::all_accounts().send_signed_transaction(|_| { pallet_balances::Call::transfer { - dest: Default::default(), + dest: Alice.to_account_id().into(), value: Default::default(), } }); @@ -122,7 +124,7 @@ fn should_submit_signed_twice_from_the_same_account() { let result = Signer::::any_account().send_signed_transaction(|_| { pallet_balances::Call::transfer { - dest: Default::default(), + dest: Alice.to_account_id().into(), value: Default::default(), } }); @@ -134,7 +136,7 @@ fn should_submit_signed_twice_from_the_same_account() { let result = Signer::::any_account().send_signed_transaction(|_| { pallet_balances::Call::transfer { - dest: Default::default(), + dest: Alice.to_account_id().into(), value: Default::default(), } }); @@ -172,7 +174,7 @@ fn should_submit_signed_twice_from_all_accounts() { t.execute_with(|| { let results = Signer::::all_accounts() .send_signed_transaction(|_| { - pallet_balances::Call::transfer { dest: Default::default(), value: Default::default() } + pallet_balances::Call::transfer { dest: Alice.to_account_id().into(), value: Default::default() } }); let len = results.len(); @@ -183,7 +185,7 @@ fn should_submit_signed_twice_from_all_accounts() { // submit another one from the same account. The nonce should be incremented. let results = Signer::::all_accounts() .send_signed_transaction(|_| { - pallet_balances::Call::transfer { dest: Default::default(), value: Default::default() } + pallet_balances::Call::transfer { dest: Alice.to_account_id().into(), value: Default::default() } }); let len = results.len(); @@ -237,7 +239,7 @@ fn submitted_transaction_should_be_valid() { let results = Signer::::all_accounts().send_signed_transaction(|_| { pallet_balances::Call::transfer { - dest: Default::default(), + dest: Alice.to_account_id().into(), value: Default::default(), } }); diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index cdd9f0900fd38..689dc8c23fb4f 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -27,7 +27,9 @@ use pallet_asset_tx_payment::HandleCredit; pub struct Author; impl OnUnbalanced for Author { fn on_nonzero_unbalanced(amount: NegativeImbalance) { - Balances::resolve_creating(&Authorship::author(), amount); + if let Some(author) = Authorship::author() { + Balances::resolve_creating(&author, amount); + } } } @@ -36,9 +38,10 @@ impl OnUnbalanced for Author { pub struct CreditToBlockAuthor; impl HandleCredit for CreditToBlockAuthor { fn handle_credit(credit: CreditOf) { - let author = pallet_authorship::Pallet::::author(); - // Drop the result which will trigger the `OnDrop` of the imbalance in case of error. - let _ = Assets::resolve(&author, credit); + if let Some(author) = pallet_authorship::Pallet::::author() { + // Drop the result which will trigger the `OnDrop` of the imbalance in case of error. + let _ = Assets::resolve(&author, credit); + } } } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index bd4bb450c7492..e61a46abeb724 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1835,8 +1835,8 @@ mod tests { fn call_size() { let size = core::mem::size_of::(); assert!( - size <= 200, - "size of Call {} is more than 200 bytes: some calls have too big arguments, use Box to reduce the + size <= 208, + "size of Call {} is more than 208 bytes: some calls have too big arguments, use Box to reduce the size of Call. If the limit is too strong, maybe consider increase the limit to 300.", size, diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index fa0dd22c9c995..52296230b055a 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -54,11 +54,11 @@ pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec) -> Gen balances: BalancesConfig { balances: endowed }, session: SessionConfig { keys: vec![ - (dave(), alice(), to_session_keys(&Ed25519Keyring::Alice, &Sr25519Keyring::Alice)), - (eve(), bob(), to_session_keys(&Ed25519Keyring::Bob, &Sr25519Keyring::Bob)), + (alice(), dave(), to_session_keys(&Ed25519Keyring::Alice, &Sr25519Keyring::Alice)), + (bob(), eve(), to_session_keys(&Ed25519Keyring::Bob, &Sr25519Keyring::Bob)), ( - ferdie(), charlie(), + ferdie(), to_session_keys(&Ed25519Keyring::Charlie, &Sr25519Keyring::Charlie), ), ], diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index bf5f1a149578e..f45031f1eb811 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -29,7 +29,7 @@ use structopt::StructOpt; use node_cli::chain_spec::{self, AccountId}; use sc_keystore::LocalKeystore; use sp_core::{ - crypto::{Public, Ss58Codec}, + crypto::{ByteArray, Ss58Codec}, sr25519, }; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 70633925c5ba6..e79fc1f03a545 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -581,7 +581,7 @@ mod tests { amount: Default::default(), nonce, from: AccountKeyring::Alice.into(), - to: Default::default(), + to: AccountKeyring::Bob.into(), } .into_signed_tx() } @@ -593,7 +593,7 @@ mod tests { amount: 1, nonce: 0, from: pair.public(), - to: Default::default(), + to: AccountKeyring::Bob.into(), }; let signature = pair.sign(&transfer.encode()).into(); Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: true } @@ -777,14 +777,14 @@ mod tests { amount: Default::default(), nonce: 2, from: AccountKeyring::Alice.into(), - to: Default::default(), + to: AccountKeyring::Bob.into(), }.into_resources_exhausting_tx(), extrinsic(3), Transfer { amount: Default::default(), nonce: 4, from: AccountKeyring::Alice.into(), - to: Default::default(), + to: AccountKeyring::Bob.into(), }.into_resources_exhausting_tx(), extrinsic(5), extrinsic(6), diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index 081c319081607..e85b85f111ad5 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -99,7 +99,7 @@ fn to_vec(uri: &str, pass: Option) -> Result( #[cfg(test)] mod tests { use super::*; - use sp_core::crypto::{Pair, Public}; + use sp_core::crypto::{ByteArray, Pair}; use sp_runtime::traits::IdentifyAccount; use structopt::StructOpt; diff --git a/client/cli/src/commands/verify.rs b/client/cli/src/commands/verify.rs index 760793374242e..0dce444a28590 100644 --- a/client/cli/src/commands/verify.rs +++ b/client/cli/src/commands/verify.rs @@ -19,7 +19,7 @@ //! implementation of the `verify` subcommand use crate::{error, utils, with_crypto_scheme, CryptoSchemeFlag}; -use sp_core::{crypto::Ss58Codec, Public}; +use sp_core::crypto::{ByteArray, Ss58Codec}; use structopt::StructOpt; /// The `verify` command @@ -66,19 +66,14 @@ impl VerifyCmd { fn verify(sig_data: Vec, message: Vec, uri: &str) -> error::Result<()> where Pair: sp_core::Pair, - Pair::Signature: Default + AsMut<[u8]>, + Pair::Signature: for<'a> std::convert::TryFrom<&'a [u8]>, { - let mut signature = Pair::Signature::default(); - if sig_data.len() != signature.as_ref().len() { - return Err(error::Error::SignatureInvalidLength { - read: sig_data.len(), - expected: signature.as_ref().len(), - }) - } - signature.as_mut().copy_from_slice(&sig_data); + let signature = + Pair::Signature::try_from(&sig_data).map_err(|_| error::Error::SignatureFormatInvalid)?; let pubkey = if let Ok(pubkey_vec) = hex::decode(uri) { Pair::Public::from_slice(pubkey_vec.as_slice()) + .map_err(|_| error::Error::KeyFormatInvalid)? } else { Pair::Public::from_string(uri)? }; diff --git a/client/cli/src/error.rs b/client/cli/src/error.rs index c5784b2018172..9a09e560063ea 100644 --- a/client/cli/src/error.rs +++ b/client/cli/src/error.rs @@ -51,13 +51,11 @@ pub enum Error { #[error("Invalid URI; expecting either a secret URI or a public URI.")] InvalidUri(crypto::PublicError), - #[error("Signature has an invalid length. Read {read} bytes, expected {expected} bytes")] - SignatureInvalidLength { - /// Amount of signature bytes read. - read: usize, - /// Expected number of signature bytes. - expected: usize, - }, + #[error("Signature is an invalid format.")] + SignatureFormatInvalid, + + #[error("Key is an invalid format.")] + KeyFormatInvalid, #[error("Unknown key type, must be a known 4-character sequence")] KeyTypeInvalid, diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index 640b87584d4b6..34c1948012138 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -132,7 +132,7 @@ impl Runner { /// 2020-06-03 16:14:21 ✌️ version 2.0.0-rc3-f4940588c-x86_64-linux-gnu /// 2020-06-03 16:14:21 ❤️ by Parity Technologies , 2017-2020 /// 2020-06-03 16:14:21 📋 Chain specification: Flaming Fir - /// 2020-06-03 16:14:21 🏷 Node name: jolly-rod-7462 + /// 2020-06-03 16:14:21 🏷 Node name: jolly-rod-7462 /// 2020-06-03 16:14:21 👤 Role: FULL /// 2020-06-03 16:14:21 💾 Database: RocksDb at /tmp/c/chains/flamingfir7/db /// 2020-06-03 16:14:21 ⛓ Native runtime: node-251 (substrate-node-1.tx1.au10) @@ -199,7 +199,7 @@ pub fn print_node_infos(config: &Configuration) { info!("✌️ version {}", C::impl_version()); info!("❤️ by {}, {}-{}", C::author(), C::copyright_start_year(), Local::today().year()); info!("📋 Chain specification: {}", config.chain_spec.name()); - info!("🏷 Node name: {}", config.network.node_name); + info!("🏷 Node name: {}", config.network.node_name); info!("👤 Role: {}", config.display_role()); info!( "💾 Database: {} at {}", diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 16880ae188ad6..0d79e3c4ecf04 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -57,7 +57,7 @@ use sp_consensus::{ BlockOrigin, CanAuthorWith, Environment, Error as ConsensusError, Proposer, SelectChain, }; use sp_consensus_slots::Slot; -use sp_core::crypto::{Pair, Public}; +use sp_core::crypto::{ByteArray, Pair, Public}; use sp_inherents::CreateInherentDataProviders; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 285cfe543cee8..eeec7b86b1f14 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -30,7 +30,7 @@ use sp_application_crypto::AppKey; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_consensus::{Error as ConsensusError, SelectChain}; use sp_consensus_babe::{digests::PreDigest, AuthorityId, BabeApi as BabeRuntimeApi}; -use sp_core::crypto::Public; +use sp_core::crypto::ByteArray; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::traits::{Block as BlockT, Header as _}; use std::{collections::HashMap, sync::Arc}; diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 609f96c83c194..1bee73f40858a 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -27,7 +27,7 @@ use sp_consensus_babe::{ make_transcript, make_transcript_data, AuthorityId, BabeAuthorityWeight, Slot, BABE_VRF_PREFIX, }; use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; -use sp_core::{blake2_256, crypto::Public, U256}; +use sp_core::{blake2_256, crypto::ByteArray, U256}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; /// Calculates the primary selection threshold for a given authority, taking diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 4fb9f750004c5..168cdff43cda2 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -110,7 +110,7 @@ use sp_consensus::{ }; use sp_consensus_babe::inherents::BabeInherentData; use sp_consensus_slots::Slot; -use sp_core::{crypto::Public, ExecutionContext}; +use sp_core::{crypto::ByteArray, ExecutionContext}; use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ diff --git a/client/consensus/babe/src/verification.rs b/client/consensus/babe/src/verification.rs index 2322a96262161..13d2f956c8d51 100644 --- a/client/consensus/babe/src/verification.rs +++ b/client/consensus/babe/src/verification.rs @@ -31,7 +31,7 @@ use sp_consensus_babe::{ make_transcript, AuthorityId, AuthorityPair, AuthoritySignature, }; use sp_consensus_slots::Slot; -use sp_core::{Pair, Public}; +use sp_core::{ByteArray, Pair}; use sp_runtime::{traits::Header, DigestItem}; /// BABE verification parameters diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index b8b8b2d956463..3e7fddfddf2ff 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -179,7 +179,7 @@ mod tests { report, AuthorityId, FinalityProof, GrandpaJustification, GrandpaJustificationSender, }; use sp_blockchain::HeaderBackend; - use sp_core::crypto::Public; + use sp_core::crypto::ByteArray; use sp_keyring::Ed25519Keyring; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use substrate_test_runtime_client::{ @@ -196,8 +196,8 @@ mod tests { } fn voters() -> HashSet { - let voter_id_1 = AuthorityId::from_slice(&[1; 32]); - let voter_id_2 = AuthorityId::from_slice(&[2; 32]); + let voter_id_1 = AuthorityId::from_slice(&[1; 32]).unwrap(); + let voter_id_2 = AuthorityId::from_slice(&[2; 32]).unwrap(); vec![voter_id_1, voter_id_2].into_iter().collect() } @@ -245,7 +245,7 @@ mod tests { impl ReportVoterState for TestVoterState { fn get(&self) -> Option> { - let voter_id_1 = AuthorityId::from_slice(&[1; 32]); + let voter_id_1 = AuthorityId::from_slice(&[1; 32]).unwrap(); let voters_best: HashSet<_> = vec![voter_id_1].into_iter().collect(); let best_round_state = sc_finality_grandpa::report::RoundState { diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 6eb13099aa202..6ab36847fe3dd 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -753,7 +753,7 @@ impl AuthoritySetChanges { #[cfg(test)] mod tests { use super::*; - use sp_core::crypto::Public; + use sp_core::crypto::{ByteArray, UncheckedFrom}; fn static_is_descendent_of(value: bool) -> impl Fn(&A, &A) -> Result { move |_, _| Ok(value) @@ -768,7 +768,7 @@ mod tests { #[test] fn current_limit_filters_min() { - let current_authorities = vec![(AuthorityId::from_slice(&[1; 32]), 1)]; + let current_authorities = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 1)]; let mut authorities = AuthoritySet { current_authorities: current_authorities.clone(), @@ -802,7 +802,7 @@ mod tests { #[test] fn changes_iterated_in_pre_order() { - let current_authorities = vec![(AuthorityId::from_slice(&[1; 32]), 1)]; + let current_authorities = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 1)]; let mut authorities = AuthoritySet { current_authorities: current_authorities.clone(), @@ -894,8 +894,8 @@ mod tests { authority_set_changes: AuthoritySetChanges::empty(), }; - let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)]; - let set_b = vec![(AuthorityId::from_slice(&[2; 32]), 5)]; + let set_a = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 5)]; + let set_b = vec![(AuthorityId::from_slice(&[2; 32]).unwrap(), 5)]; // two competing changes at the same height on different forks let change_a = PendingChange { @@ -977,8 +977,8 @@ mod tests { authority_set_changes: AuthoritySetChanges::empty(), }; - let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)]; - let set_c = vec![(AuthorityId::from_slice(&[2; 32]), 5)]; + let set_a = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 5)]; + let set_c = vec![(AuthorityId::from_slice(&[2; 32]).unwrap(), 5)]; // two competing changes at the same height on different forks let change_a = PendingChange { @@ -1057,7 +1057,7 @@ mod tests { authority_set_changes: AuthoritySetChanges::empty(), }; - let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)]; + let set_a = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 5)]; let change_a = PendingChange { next_authorities: set_a.clone(), @@ -1128,8 +1128,8 @@ mod tests { authority_set_changes: AuthoritySetChanges::empty(), }; - let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)]; - let set_b = vec![(AuthorityId::from_slice(&[2; 32]), 5)]; + let set_a = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 5)]; + let set_b = vec![(AuthorityId::from_slice(&[2; 32]).unwrap(), 5)]; let change_a = PendingChange { next_authorities: set_a.clone(), @@ -1228,7 +1228,7 @@ mod tests { authority_set_changes: AuthoritySetChanges::empty(), }; - let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)]; + let set_a = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 5)]; // we create a forced change with no delay let change_a = PendingChange { @@ -1253,7 +1253,7 @@ mod tests { #[test] fn forced_changes_blocked_by_standard_changes() { - let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 1)]; + let set_a = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 1)]; let mut authorities = AuthoritySet { current_authorities: set_a.clone(), @@ -1378,7 +1378,7 @@ mod tests { #[test] fn next_change_works() { - let current_authorities = vec![(AuthorityId::from_slice(&[1; 32]), 1)]; + let current_authorities = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 1)]; let mut authorities = AuthoritySet { current_authorities: current_authorities.clone(), @@ -1493,8 +1493,10 @@ mod tests { None, ); - let invalid_authorities_weight = - vec![(AuthorityId::from_slice(&[1; 32]), 5), (AuthorityId::from_slice(&[2; 32]), 0)]; + let invalid_authorities_weight = vec![ + (AuthorityId::from_slice(&[1; 32]).unwrap(), 5), + (AuthorityId::from_slice(&[2; 32]).unwrap(), 0), + ]; // authority weight of zero is invalid assert_eq!(AuthoritySet::<(), ()>::genesis(invalid_authorities_weight.clone()), None); @@ -1510,7 +1512,8 @@ mod tests { ); let mut authority_set = - AuthoritySet::<(), u64>::genesis(vec![(AuthorityId::from_slice(&[1; 32]), 5)]).unwrap(); + AuthoritySet::<(), u64>::genesis(vec![(AuthorityId::unchecked_from([1; 32]), 5)]) + .unwrap(); let invalid_change_empty_authorities = PendingChange { next_authorities: vec![], @@ -1550,7 +1553,7 @@ mod tests { #[test] fn cleans_up_stale_forced_changes_when_applying_standard_change() { - let current_authorities = vec![(AuthorityId::from_slice(&[1; 32]), 1)]; + let current_authorities = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 1)]; let mut authorities = AuthoritySet { current_authorities: current_authorities.clone(), diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/finality-grandpa/src/aux_schema.rs index bad01e6dfc62f..9294fbc4161b0 100644 --- a/client/finality-grandpa/src/aux_schema.rs +++ b/client/finality-grandpa/src/aux_schema.rs @@ -498,15 +498,19 @@ pub(crate) fn load_authorities( #[cfg(test)] mod test { use super::*; - use sp_core::H256; + use sp_core::{crypto::UncheckedFrom, H256}; use sp_finality_grandpa::AuthorityId; use substrate_test_runtime_client; + fn dummy_id() -> AuthorityId { + AuthorityId::unchecked_from([1; 32]) + } + #[test] fn load_decode_from_v0_migrates_data_format() { let client = substrate_test_runtime_client::new(); - let authorities = vec![(AuthorityId::default(), 100)]; + let authorities = vec![(dummy_id(), 100)]; let set_id = 3; let round_number: RoundNumber = 42; let round_state = RoundState:: { @@ -595,7 +599,7 @@ mod test { fn load_decode_from_v1_migrates_data_format() { let client = substrate_test_runtime_client::new(); - let authorities = vec![(AuthorityId::default(), 100)]; + let authorities = vec![(dummy_id(), 100)]; let set_id = 3; let round_number: RoundNumber = 42; let round_state = RoundState:: { @@ -688,7 +692,7 @@ mod test { fn load_decode_from_v2_migrates_data_format() { let client = substrate_test_runtime_client::new(); - let authorities = vec![(AuthorityId::default(), 100)]; + let authorities = vec![(dummy_id(), 100)]; let set_id = 3; { diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 8a3b6afcad325..74e7cc5300654 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -1670,7 +1670,7 @@ mod tests { use sc_network::config::Role; use sc_network_gossip::Validator as GossipValidatorT; use sc_network_test::Block; - use sp_core::{crypto::Public, H256}; + use sp_core::{crypto::UncheckedFrom, H256}; // some random config (not really needed) fn config() -> crate::Config { @@ -1691,7 +1691,7 @@ mod tests { let base = (H256::zero(), 0); - let voters = vec![(AuthorityId::from_slice(&[1; 32]), 1)]; + let voters = vec![(AuthorityId::unchecked_from([1; 32]), 1)]; let voters = AuthoritySet::genesis(voters).unwrap(); let set_state = VoterSetState::live(0, &voters, base); @@ -1861,7 +1861,7 @@ mod tests { let (val, _) = GossipValidator::::new(config(), voter_set_state(), None, None); let set_id = 1; - let auth = AuthorityId::from_slice(&[1u8; 32]); + let auth = AuthorityId::unchecked_from([1u8; 32]); let peer = PeerId::random(); val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); @@ -1878,8 +1878,8 @@ mod tests { target_hash: Default::default(), target_number: 10, }), - signature: Default::default(), - id: AuthorityId::from_slice(&[2u8; 32]), + signature: UncheckedFrom::unchecked_from([1; 64]), + id: UncheckedFrom::unchecked_from([2u8; 32]), }, }, ); @@ -1894,7 +1894,7 @@ mod tests { target_hash: Default::default(), target_number: 10, }), - signature: Default::default(), + signature: UncheckedFrom::unchecked_from([1; 64]), id: auth.clone(), }, }, @@ -1909,7 +1909,7 @@ mod tests { let (val, _) = GossipValidator::::new(config(), voter_set_state(), None, None); let set_id = 1; - let auth = AuthorityId::from_slice(&[1u8; 32]); + let auth = AuthorityId::unchecked_from([1u8; 32]); let peer = PeerId::random(); val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); @@ -1972,7 +1972,7 @@ mod tests { let (val, _) = GossipValidator::::new(config(), set_state.clone(), None, None); let set_id = 1; - let auth = AuthorityId::from_slice(&[1u8; 32]); + let auth = AuthorityId::unchecked_from([1u8; 32]); let peer = PeerId::random(); val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); @@ -2550,12 +2550,13 @@ mod tests { fn allow_noting_different_authorities_for_same_set() { let (val, _) = GossipValidator::::new(config(), voter_set_state(), None, None); - let a1 = vec![AuthorityId::from_slice(&[0; 32])]; + let a1 = vec![UncheckedFrom::unchecked_from([0; 32])]; val.note_set(SetId(1), a1.clone(), |_, _| {}); assert_eq!(val.inner().read().authorities, a1); - let a2 = vec![AuthorityId::from_slice(&[1; 32]), AuthorityId::from_slice(&[2; 32])]; + let a2 = + vec![UncheckedFrom::unchecked_from([1; 32]), UncheckedFrom::unchecked_from([2; 32])]; val.note_set(SetId(1), a2.clone(), |_, _| {}); assert_eq!(val.inner().read().authorities, a2); diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index 1fac0230b2a84..1e88f8a934047 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -155,13 +155,13 @@ fn config() -> crate::Config { fn voter_set_state() -> SharedVoterSetState { use crate::{authorities::AuthoritySet, environment::VoterSetState}; use finality_grandpa::round::State as RoundState; - use sp_core::{crypto::Public, H256}; + use sp_core::{crypto::ByteArray, H256}; use sp_finality_grandpa::AuthorityId; let state = RoundState::genesis((H256::zero(), 0)); let base = state.prevote_ghost.unwrap(); - let voters = vec![(AuthorityId::from_slice(&[1; 32]), 1)]; + let voters = vec![(AuthorityId::from_slice(&[1; 32]).unwrap(), 1)]; let voters = AuthoritySet::genesis(voters).unwrap(); let set_state = VoterSetState::live(0, &voters, base); diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index 1e20c2edc3a6e..ac7be37eb20ca 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -243,8 +243,8 @@ pub(crate) mod tests { use sc_block_builder::BlockBuilderProvider; use sc_client_api::{apply_aux, LockImportRun}; use sp_consensus::BlockOrigin; - use sp_core::crypto::Public; - use sp_finality_grandpa::{AuthorityId, GRANDPA_ENGINE_ID as ID}; + use sp_core::crypto::UncheckedFrom; + use sp_finality_grandpa::GRANDPA_ENGINE_ID as ID; use sp_keyring::Ed25519Keyring; use substrate_test_runtime_client::{ runtime::{Block, Header, H256}, @@ -350,7 +350,7 @@ pub(crate) mod tests { // When we can't decode proof from Vec check_finality_proof::( 1, - vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)], + vec![(UncheckedFrom::unchecked_from([3u8; 32]), 1u64)], vec![42], ) .unwrap_err(); @@ -361,7 +361,7 @@ pub(crate) mod tests { // When decoded proof has zero length check_finality_proof::( 1, - vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)], + vec![(UncheckedFrom::unchecked_from([3u8; 32]), 1u64)], Vec::>::new().encode(), ) .unwrap_err(); @@ -387,7 +387,7 @@ pub(crate) mod tests { check_finality_proof::( 1, - vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)], + vec![(UncheckedFrom::unchecked_from([3u8; 32]), 1u64)], finality_proof.encode(), ) .unwrap_err(); diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index b300066469472..656d8ea434349 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -73,7 +73,7 @@ use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppKey; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; use sp_consensus::SelectChain; -use sp_core::crypto::Public; +use sp_core::crypto::ByteArray; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::BlockId, @@ -786,8 +786,8 @@ where let events = telemetry_on_connect.for_each(move |_| { let current_authorities = authorities.current_authorities(); let set_id = authorities.set_id(); - let authority_id = local_authority_id(¤t_authorities, conf.keystore.as_ref()) - .unwrap_or_default(); + let maybe_authority_id = + local_authority_id(¤t_authorities, conf.keystore.as_ref()); let authorities = current_authorities.iter().map(|(id, _)| id.to_string()).collect::>(); @@ -801,7 +801,7 @@ where telemetry; CONSENSUS_INFO; "afg.authority_set"; - "authority_id" => authority_id.to_string(), + "authority_id" => maybe_authority_id.map_or("".into(), |s| s.to_string()), "authority_set_id" => ?set_id, "authorities" => authorities, ); @@ -940,8 +940,9 @@ where fn rebuild_voter(&mut self) { debug!(target: "afg", "{}: Starting new voter with set ID {}", self.env.config.name(), self.env.set_id); - let authority_id = local_authority_id(&self.env.voters, self.env.config.keystore.as_ref()) - .unwrap_or_default(); + let maybe_authority_id = + local_authority_id(&self.env.voters, self.env.config.keystore.as_ref()); + let authority_id = maybe_authority_id.map_or("".into(), |s| s.to_string()); telemetry!( self.telemetry; @@ -949,7 +950,7 @@ where "afg.starting_new_voter"; "name" => ?self.env.config.name(), "set_id" => ?self.env.set_id, - "authority_id" => authority_id.to_string(), + "authority_id" => authority_id, ); let chain_info = self.env.client.info(); @@ -966,7 +967,7 @@ where "afg.authority_set"; "number" => ?chain_info.finalized_number, "hash" => ?chain_info.finalized_hash, - "authority_id" => authority_id.to_string(), + "authority_id" => authority_id, "authority_set_id" => ?self.env.set_id, "authorities" => authorities, ); diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 8439bf6963d01..7af02d066be32 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -1671,7 +1671,7 @@ fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { // if we set the equivocation offender to another id for which we don't have // keys it should work - equivocation.identity = Default::default(); + equivocation.identity = TryFrom::try_from(&[1; 32][..]).unwrap(); let equivocation_proof = sp_finality_grandpa::Equivocation::Prevote(equivocation); assert!(environment.report_equivocation(equivocation_proof).is_ok()); } diff --git a/client/finality-grandpa/src/until_imported.rs b/client/finality-grandpa/src/until_imported.rs index e2c00b54ea068..430db23d62204 100644 --- a/client/finality-grandpa/src/until_imported.rs +++ b/client/finality-grandpa/src/until_imported.rs @@ -563,6 +563,7 @@ mod tests { use sc_client_api::BlockImportNotification; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sp_consensus::BlockOrigin; + use sp_core::crypto::UncheckedFrom; use substrate_test_runtime_client::runtime::{Block, Hash, Header}; #[derive(Clone)] @@ -796,8 +797,8 @@ mod tests { let h3 = make_header(7); let signed_prevote = |header: &Header| finality_grandpa::SignedPrevote { - id: Default::default(), - signature: Default::default(), + id: UncheckedFrom::unchecked_from([1; 32]), + signature: UncheckedFrom::unchecked_from([1; 64]), prevote: finality_grandpa::Prevote { target_hash: header.hash(), target_number: *header.number(), @@ -805,8 +806,8 @@ mod tests { }; let signed_precommit = |header: &Header| finality_grandpa::SignedPrecommit { - id: Default::default(), - signature: Default::default(), + id: UncheckedFrom::unchecked_from([1; 32]), + signature: UncheckedFrom::unchecked_from([1; 64]), precommit: finality_grandpa::Precommit { target_hash: header.hash(), target_number: *header.number(), @@ -844,8 +845,8 @@ mod tests { let h3 = make_header(7); let signed_prevote = |header: &Header| finality_grandpa::SignedPrevote { - id: Default::default(), - signature: Default::default(), + id: UncheckedFrom::unchecked_from([1; 32]), + signature: UncheckedFrom::unchecked_from([1; 64]), prevote: finality_grandpa::Prevote { target_hash: header.hash(), target_number: *header.number(), @@ -853,8 +854,8 @@ mod tests { }; let signed_precommit = |header: &Header| finality_grandpa::SignedPrecommit { - id: Default::default(), - signature: Default::default(), + id: UncheckedFrom::unchecked_from([1; 32]), + signature: UncheckedFrom::unchecked_from([1; 64]), precommit: finality_grandpa::Precommit { target_hash: header.hash(), target_number: *header.number(), diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index d5a7fd93d7dc7..be9bb5e145977 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -21,7 +21,9 @@ use async_trait::async_trait; use parking_lot::RwLock; use sp_application_crypto::{ecdsa, ed25519, sr25519, AppKey, AppPair, IsWrappedBy}; use sp_core::{ - crypto::{CryptoTypePublicPair, ExposeSecret, KeyTypeId, Pair as PairT, Public, SecretString}, + crypto::{ + ByteArray, CryptoTypePublicPair, ExposeSecret, KeyTypeId, Pair as PairT, SecretString, + }, sr25519::{Pair as Sr25519Pair, Public as Sr25519Public}, Encode, }; @@ -189,7 +191,9 @@ impl SyncCryptoStore for LocalKeystore { ) -> std::result::Result>, TraitError> { match key.0 { ed25519::CRYPTO_ID => { - let pub_key = ed25519::Public::from_slice(key.1.as_slice()); + let pub_key = ed25519::Public::from_slice(key.1.as_slice()).map_err(|()| { + TraitError::Other("Corrupted public key - Invalid size".into()) + })?; let key_pair = self .0 .read() @@ -198,7 +202,9 @@ impl SyncCryptoStore for LocalKeystore { key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose() }, sr25519::CRYPTO_ID => { - let pub_key = sr25519::Public::from_slice(key.1.as_slice()); + let pub_key = sr25519::Public::from_slice(key.1.as_slice()).map_err(|()| { + TraitError::Other("Corrupted public key - Invalid size".into()) + })?; let key_pair = self .0 .read() @@ -207,7 +213,9 @@ impl SyncCryptoStore for LocalKeystore { key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose() }, ecdsa::CRYPTO_ID => { - let pub_key = ecdsa::Public::from_slice(key.1.as_slice()); + let pub_key = ecdsa::Public::from_slice(key.1.as_slice()).map_err(|()| { + TraitError::Other("Corrupted public key - Invalid size".into()) + })?; let key_pair = self .0 .read() @@ -223,7 +231,11 @@ impl SyncCryptoStore for LocalKeystore { self.0 .read() .raw_public_keys(key_type) - .map(|v| v.into_iter().map(|k| sr25519::Public::from_slice(k.as_slice())).collect()) + .map(|v| { + v.into_iter() + .filter_map(|k| sr25519::Public::from_slice(k.as_slice()).ok()) + .collect() + }) .unwrap_or_default() } @@ -246,7 +258,11 @@ impl SyncCryptoStore for LocalKeystore { self.0 .read() .raw_public_keys(key_type) - .map(|v| v.into_iter().map(|k| ed25519::Public::from_slice(k.as_slice())).collect()) + .map(|v| { + v.into_iter() + .filter_map(|k| ed25519::Public::from_slice(k.as_slice()).ok()) + .collect() + }) .unwrap_or_default() } @@ -269,7 +285,11 @@ impl SyncCryptoStore for LocalKeystore { self.0 .read() .raw_public_keys(key_type) - .map(|v| v.into_iter().map(|k| ecdsa::Public::from_slice(k.as_slice())).collect()) + .map(|v| { + v.into_iter() + .filter_map(|k| ecdsa::Public::from_slice(k.as_slice()).ok()) + .collect() + }) .unwrap_or_default() } @@ -561,8 +581,9 @@ mod tests { } fn public_keys(&self) -> Result> { - self.raw_public_keys(Public::ID) - .map(|v| v.into_iter().map(|k| Public::from_slice(k.as_slice())).collect()) + self.raw_public_keys(Public::ID).map(|v| { + v.into_iter().filter_map(|k| Public::from_slice(k.as_slice()).ok()).collect() + }) } fn generate(&mut self) -> Result { diff --git a/client/network/src/service.rs b/client/network/src/service.rs index e03bdcfa2f7ed..8b153bc4edf54 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -190,7 +190,7 @@ impl NetworkWorker { let local_peer_id = local_public.clone().to_peer_id(); info!( target: "sub-libp2p", - "🏷 Local node identity is: {}", + "🏷 Local node identity is: {}", local_peer_id.to_base58(), ); diff --git a/client/rpc/src/author/tests.rs b/client/rpc/src/author/tests.rs index 2349e08fee506..5c1ade96f96b7 100644 --- a/client/rpc/src/author/tests.rs +++ b/client/rpc/src/author/tests.rs @@ -24,7 +24,7 @@ use futures::executor; use sc_transaction_pool::{BasicPool, FullChainApi}; use sp_core::{ blake2_256, - crypto::{CryptoTypePublicPair, Pair, Public}, + crypto::{ByteArray, CryptoTypePublicPair, Pair}, ed25519, hexdisplay::HexDisplay, sr25519, @@ -40,8 +40,12 @@ use substrate_test_runtime_client::{ }; fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic { - let tx = - Transfer { amount: Default::default(), nonce, from: sender.into(), to: Default::default() }; + let tx = Transfer { + amount: Default::default(), + nonce, + from: sender.into(), + to: AccountKeyring::Bob.into(), + }; tx.into_signed_tx() } @@ -133,7 +137,7 @@ fn should_watch_extrinsic() { amount: 5, nonce: 0, from: AccountKeyring::Alice.into(), - to: Default::default(), + to: AccountKeyring::Bob.into(), }; tx.into_signed_tx() }; diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 563846c75d89a..9cf5cc69bdc35 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -576,7 +576,7 @@ mod tests { amount: 5, nonce: 0, from: AccountKeyring::Alice.into(), - to: Default::default(), + to: AccountKeyring::Bob.into(), } .into_signed_tx(); block_on(pool.submit_one(&BlockId::hash(best.hash()), source, transaction.clone())) diff --git a/client/tracing/proc-macro/src/lib.rs b/client/tracing/proc-macro/src/lib.rs index e9a4f58705b41..005fcf4ba0f51 100644 --- a/client/tracing/proc-macro/src/lib.rs +++ b/client/tracing/proc-macro/src/lib.rs @@ -56,7 +56,7 @@ use syn::{Error, Expr, Ident, ItemFn}; /// 2020-10-16 08:03:14 ✌️ version 2.0.0-47f7d3f2e-x86_64-linux-gnu /// 2020-10-16 08:03:14 ❤️ by Anonymous, 2017-2020 /// 2020-10-16 08:03:14 📋 Chain specification: Local Testnet -/// 2020-10-16 08:03:14 🏷 Node name: nice-glove-1401 +/// 2020-10-16 08:03:14 🏷 Node name: nice-glove-1401 /// 2020-10-16 08:03:14 👤 Role: LIGHT /// 2020-10-16 08:03:14 💾 Database: RocksDb at /tmp/substrate95w2Dk/chains/local_testnet/db /// 2020-10-16 08:03:14 ⛓ Native runtime: node-template-1 (node-template-1.tx1.au1) @@ -64,7 +64,7 @@ use syn::{Error, Expr, Ident, ItemFn}; /// 2020-10-16 08:03:14 [light] Loading GRANDPA authorities from genesis on what appears to be first startup. /// 2020-10-16 08:03:15 [light] ⏱ Loaded block-time = 6000 milliseconds from genesis on first-launch /// 2020-10-16 08:03:15 [light] Using default protocol ID "sup" because none is configured in the chain specs -/// 2020-10-16 08:03:15 [light] 🏷 Local node identity is: 12D3KooWHX4rkWT6a6N55Km7ZnvenGdShSKPkzJ3yj9DU5nqDtWR +/// 2020-10-16 08:03:15 [light] 🏷 Local node identity is: 12D3KooWHX4rkWT6a6N55Km7ZnvenGdShSKPkzJ3yj9DU5nqDtWR /// 2020-10-16 08:03:15 [light] 📦 Highest known block at #0 /// 2020-10-16 08:03:15 [light] 〽️ Prometheus server started at 127.0.0.1:9615 /// 2020-10-16 08:03:15 [light] Listening for new connections on 127.0.0.1:9944. @@ -90,7 +90,7 @@ use syn::{Error, Expr, Ident, ItemFn}; /// 2020-10-16 08:12:57 ✌️ version 2.0.0-efb9b822a-x86_64-linux-gnu /// 2020-10-16 08:12:57 ❤️ by Anonymous, 2017-2020 /// 2020-10-16 08:12:57 📋 Chain specification: Local Testnet -/// 2020-10-16 08:12:57 🏷 Node name: open-harbor-1619 +/// 2020-10-16 08:12:57 🏷 Node name: open-harbor-1619 /// 2020-10-16 08:12:57 👤 Role: LIGHT /// 2020-10-16 08:12:57 💾 Database: RocksDb at /tmp/substrate9T9Mtb/chains/local_testnet/db /// 2020-10-16 08:12:57 ⛓ Native runtime: node-template-1 (node-template-1.tx1.au1) @@ -98,7 +98,7 @@ use syn::{Error, Expr, Ident, ItemFn}; /// 2020-10-16 08:12:58 [open-harbor-1619] Loading GRANDPA authorities from genesis on what appears to be first startup. /// 2020-10-16 08:12:58 [open-harbor-1619] ⏱ Loaded block-time = 6000 milliseconds from genesis on first-launch /// 2020-10-16 08:12:58 [open-harbor-1619] Using default protocol ID "sup" because none is configured in the chain specs -/// 2020-10-16 08:12:58 [open-harbor-1619] 🏷 Local node identity is: 12D3KooWRzmYC8QTK1Pm8Cfvid3skTS4Hn54jc4AUtje8Rqbfgtp +/// 2020-10-16 08:12:58 [open-harbor-1619] 🏷 Local node identity is: 12D3KooWRzmYC8QTK1Pm8Cfvid3skTS4Hn54jc4AUtje8Rqbfgtp /// 2020-10-16 08:12:58 [open-harbor-1619] 📦 Highest known block at #0 /// 2020-10-16 08:12:58 [open-harbor-1619] 〽️ Prometheus server started at 127.0.0.1:9615 /// 2020-10-16 08:12:58 [open-harbor-1619] Listening for new connections on 127.0.0.1:9944. diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index cf30a0200ad76..cfb40c6cb2ab7 100644 --- a/client/transaction-pool/benches/basics.rs +++ b/client/transaction-pool/benches/basics.rs @@ -18,7 +18,7 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use codec::Encode; +use codec::{Decode, Encode}; use futures::{ executor::block_on, future::{ready, Ready}, @@ -126,7 +126,8 @@ impl ChainApi for TestApi { fn uxt(transfer: Transfer) -> Extrinsic { Extrinsic::Transfer { transfer, - signature: Default::default(), + signature: Decode::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite input; no dead input space; qed"), exhaust_resources_when_not_first: false, } } diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index af46dbad0ee53..1032282af99dc 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -594,11 +594,8 @@ mod tests { } fn uxt(transfer: Transfer) -> Extrinsic { - Extrinsic::Transfer { - transfer, - signature: Default::default(), - exhaust_resources_when_not_first: false, - } + let signature = TryFrom::try_from(&[0; 64][..]).unwrap(); + Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: false } } fn pool() -> Pool { diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 887bb359ed3db..e98097055920d 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -69,7 +69,6 @@ pub mod pallet { type AuthorityId: Member + Parameter + RuntimeAppPublic - + Default + MaybeSerializeDeserialize + MaxEncodedLen; /// The maximum number of authorities that the pallet can hold. diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index cd91957475a1e..98dd8f1ce6df0 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -170,7 +170,9 @@ pub mod pallet { >::put(false); - T::EventHandler::note_author(Self::author()); + if let Some(author) = Self::author() { + T::EventHandler::note_author(author); + } 0 } @@ -300,20 +302,18 @@ impl Pallet { /// /// This is safe to invoke in `on_initialize` implementations, as well /// as afterwards. - pub fn author() -> T::AccountId { + pub fn author() -> Option { // Check the memoized storage value. if let Some(author) = >::get() { - return author + return Some(author) } let digest = >::digest(); let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime()); - if let Some(author) = T::FindAuthor::find_author(pre_runtime_digests) { - >::put(&author); - author - } else { - Default::default() - } + T::FindAuthor::find_author(pre_runtime_digests).map(|a| { + >::put(&a); + a + }) } fn verify_and_import_uncles(new_uncles: Vec) -> dispatch::DispatchResult { @@ -329,14 +329,13 @@ impl Pallet { UncleEntryItem::InclusionHeight(_) => None, UncleEntryItem::Uncle(h, _) => Some(h), }); - let author = Self::verify_uncle(&uncle, prev_uncles, &mut acc)?; + let maybe_author = Self::verify_uncle(&uncle, prev_uncles, &mut acc)?; let hash = uncle.hash(); - T::EventHandler::note_uncle( - author.clone().unwrap_or_default(), - now - uncle.number().clone(), - ); - uncles.push(UncleEntryItem::Uncle(hash, author)); + if let Some(author) = maybe_author.clone() { + T::EventHandler::note_uncle(author, now - uncle.number().clone()); + } + uncles.push(UncleEntryItem::Uncle(hash, maybe_author)); } >::put(&uncles); @@ -693,7 +692,7 @@ mod tests { header.digest_mut().pop(); // pop the seal off. System::initialize(&1, &Default::default(), header.digest(), Default::default()); - assert_eq!(Authorship::author(), author); + assert_eq!(Authorship::author(), Some(author)); }); } diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index 2397918d1ef13..9247acbb3b12d 100644 --- a/frame/babe/src/equivocation.rs +++ b/frame/babe/src/equivocation.rs @@ -176,7 +176,7 @@ where } fn block_author() -> Option { - Some(>::author()) + >::author() } } diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 569722ca38ced..6ae0796c866f0 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -31,7 +31,7 @@ use frame_support::{ weights::{Pays, Weight}, BoundedVec, WeakBoundedVec, }; -use sp_application_crypto::Public; +use sp_application_crypto::ByteArray; use sp_runtime::{ generic::DigestItem, traits::{IsMember, One, SaturatedConversion, Saturating, Zero}, diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index b846aa4a7dd6b..cf65e39dba533 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -72,7 +72,7 @@ where pub struct BeefyEcdsaToEthereum; impl Convert> for BeefyEcdsaToEthereum { fn convert(a: beefy_primitives::crypto::AuthorityId) -> Vec { - use sp_core::crypto::Public; + use sp_core::crypto::ByteArray; let compressed_key = a.as_slice(); libsecp256k1::PublicKey::parse_slice( diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 6a7118c1f5c96..c18b28901bb62 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -47,7 +47,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// Authority identifier type - type BeefyId: Member + Parameter + RuntimeAppPublic + Default + MaybeSerializeDeserialize; + type BeefyId: Member + Parameter + RuntimeAppPublic + MaybeSerializeDeserialize; } #[pallet::pallet] diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index c24ad2f64e18d..0bbe8156a9f99 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -23,6 +23,7 @@ use frame_support::{ traits::StorageInfo, }; use sp_io::hashing::blake2_256; +use sp_runtime::traits::TrailingZeroInput; use sp_std::{prelude::Box, vec::Vec}; use sp_storage::TrackedStorageKey; @@ -321,17 +322,14 @@ pub trait BenchmarkingSetup { } /// Grab an account, seeded by a name and index. -pub fn account( - name: &'static str, - index: u32, - seed: u32, -) -> AccountId { +pub fn account(name: &'static str, index: u32, seed: u32) -> AccountId { let entropy = (name, index, seed).using_encoded(blake2_256); - AccountId::decode(&mut &entropy[..]).unwrap_or_default() + Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) + .expect("infinite length input; no invalid inputs for type; qed") } /// This caller account is automatically whitelisted for DB reads/writes by the benchmarking macro. -pub fn whitelisted_caller() -> AccountId { +pub fn whitelisted_caller() -> AccountId { account::("whitelisted_caller", 0, 0) } diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 7e8ba60050561..752697ce668f4 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -123,7 +123,7 @@ pub struct Bounty { status: BountyStatus, } -impl +impl Bounty { /// Getter for bounty status, to be used for child bounties. diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index 5ca57cf72e8fc..9dcfa2a9c6c87 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -43,9 +43,9 @@ benchmarks_instance_pallet! { // Set old members. // We compute the difference of old and new members, so it should influence timing. let mut old_members = vec![]; - let mut last_old_member = T::AccountId::default(); + let mut last_old_member = account::("old member", 0, SEED); for i in 0 .. m { - last_old_member = account("old member", i, SEED); + last_old_member = account::("old member", i, SEED); old_members.push(last_old_member.clone()); } let old_members_count = old_members.len() as u32; @@ -91,9 +91,9 @@ benchmarks_instance_pallet! { // Construct `new_members`. // It should influence timing since it will sort this vector. let mut new_members = vec![]; - let mut last_member = T::AccountId::default(); + let mut last_member = account::("member", 0, SEED); for i in 0 .. n { - last_member = account("member", i, SEED); + last_member = account::("member", i, SEED); new_members.push(last_member.clone()); } @@ -112,7 +112,7 @@ benchmarks_instance_pallet! { // Construct `members`. let mut members = vec![]; for i in 0 .. m - 1 { - let member = account("member", i, SEED); + let member = account::("member", i, SEED); members.push(member); } @@ -142,7 +142,7 @@ benchmarks_instance_pallet! { // Construct `members`. let mut members = vec![]; for i in 0 .. m - 1 { - let member = account("member", i, SEED); + let member = account::("member", i, SEED); members.push(member); } @@ -174,7 +174,7 @@ benchmarks_instance_pallet! { // Construct `members`. let mut members = vec![]; for i in 0 .. m - 1 { - let member = account("member", i, SEED); + let member = account::("member", i, SEED); members.push(member); } let caller: T::AccountId = whitelisted_caller(); @@ -216,13 +216,13 @@ benchmarks_instance_pallet! { // Construct `members`. let mut members = vec![]; - let proposer: T::AccountId = account("proposer", 0, SEED); + let proposer: T::AccountId = account::("proposer", 0, SEED); members.push(proposer.clone()); for i in 1 .. m - 1 { - let member = account("member", i, SEED); + let member = account::("member", i, SEED); members.push(member); } - let voter: T::AccountId = account("voter", 0, SEED); + let voter: T::AccountId = account::("voter", 0, SEED); members.push(voter.clone()); Collective::::set_members(SystemOrigin::Root.into(), members.clone(), None, T::MaxMembers::get())?; @@ -291,13 +291,13 @@ benchmarks_instance_pallet! { // Construct `members`. let mut members = vec![]; - let proposer: T::AccountId = account("proposer", 0, SEED); + let proposer = account::("proposer", 0, SEED); members.push(proposer.clone()); for i in 1 .. m - 1 { - let member = account("member", i, SEED); + let member = account::("member", i, SEED); members.push(member); } - let voter: T::AccountId = account("voter", 0, SEED); + let voter = account::("voter", 0, SEED); members.push(voter.clone()); Collective::::set_members(SystemOrigin::Root.into(), members.clone(), None, T::MaxMembers::get())?; @@ -373,7 +373,7 @@ benchmarks_instance_pallet! { // Construct `members`. let mut members = vec![]; for i in 0 .. m - 1 { - let member = account("member", i, SEED); + let member = account::("member", i, SEED); members.push(member); } let caller: T::AccountId = whitelisted_caller(); @@ -454,7 +454,7 @@ benchmarks_instance_pallet! { // Construct `members`. let mut members = vec![]; for i in 0 .. m - 1 { - let member = account("member", i, SEED); + let member = account::("member", i, SEED); members.push(member); } let caller: T::AccountId = whitelisted_caller(); @@ -528,7 +528,7 @@ benchmarks_instance_pallet! { // Construct `members`. let mut members = vec![]; for i in 0 .. m - 1 { - let member = account("member", i, SEED); + let member = account::("member", i, SEED); members.push(member); } let caller: T::AccountId = whitelisted_caller(); @@ -599,10 +599,10 @@ benchmarks_instance_pallet! { // Construct `members`. let mut members = vec![]; for i in 0 .. m - 1 { - let member = account("member", i, SEED); + let member = account::("member", i, SEED); members.push(member); } - let caller: T::AccountId = account("caller", 0, SEED); + let caller = account::("caller", 0, SEED); members.push(caller.clone()); Collective::::set_members( SystemOrigin::Root.into(), diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 93eb2e64a1d84..7751eb1a2c77d 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -224,13 +224,16 @@ mod v6 { }) }); + let nobody = T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("Infinite input; no dead input space; qed"); + >::translate(|key, old: OldPrefabWasmModule| { weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)); >::insert( key, OwnerInfo { refcount: old.refcount, - owner: Default::default(), + owner: nobody.clone(), deposit: Default::default(), }, ); diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index 136c2d2a7c9e2..4068b55f6e7bc 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -239,9 +239,14 @@ benchmarks! { let origin = T::ExternalOrigin::successful_origin(); let proposal_hash = T::Hashing::hash_of(&0); // Add proposal to blacklist with block number 0 + + let addresses = (0..v) + .into_iter() + .map(|i| account::("blacklist", i, SEED)) + .collect::>(); Blacklist::::insert( proposal_hash, - (T::BlockNumber::zero(), vec![T::AccountId::default(); v as usize]) + (T::BlockNumber::zero(), addresses), ); }: _(origin, proposal_hash) verify { @@ -292,7 +297,7 @@ benchmarks! { let mut vetoers: Vec = Vec::new(); for i in 0 .. v { - vetoers.push(account("vetoer", i, SEED)); + vetoers.push(account::("vetoer", i, SEED)); } vetoers.sort(); Blacklist::::insert(proposal_hash, (T::BlockNumber::zero(), vetoers)); diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index d9db6c3090994..1e0d3b1e9325a 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -209,7 +209,11 @@ frame_benchmarking::benchmarks! { let receiver = account("receiver", 0, SEED); let initial_balance = T::Currency::minimum_balance() * 10u32.into(); T::Currency::make_free_balance_be(&receiver, initial_balance); - let ready: ReadySolution = Default::default(); + let ready = ReadySolution { + supports: vec![], + score: Default::default(), + compute: Default::default() + }; let deposit: BalanceOf = 10u32.into(); let reward: BalanceOf = 20u32.into(); @@ -314,7 +318,12 @@ frame_benchmarking::benchmarks! { score: [(10_000_000 + i).into(), 0, 0], ..Default::default() }; - let signed_submission = SignedSubmission { raw_solution, ..Default::default() }; + let signed_submission = SignedSubmission { + raw_solution, + who: account("submitters", i, SEED), + deposit: Default::default(), + reward: Default::default(), + }; signed_submissions.insert(signed_submission); } signed_submissions.put(); diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 70bbed95fe973..70668dbe9f67a 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1189,7 +1189,7 @@ pub mod pallet { /// affect; we shouldn't need a cryptographically secure hasher. #[pallet::storage] pub(crate) type SignedSubmissionsMap = - StorageMap<_, Twox64Concat, u32, SignedSubmissionOf, ValueQuery>; + StorageMap<_, Twox64Concat, u32, SignedSubmissionOf, OptionQuery>; // `SignedSubmissions` items end here. diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index b762ad706486c..08cae62ef7d37 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -42,7 +42,7 @@ use sp_std::{ /// A raw, unchecked signed submission. /// /// This is just a wrapper around [`RawSolution`] and some additional info. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default, scale_info::TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] pub struct SignedSubmission { /// Who submitted this solution. pub who: AccountId, @@ -167,17 +167,17 @@ impl SignedSubmissions { } /// Get the submission at a particular index. - fn get_submission(&self, idx: u32) -> Option> { - if self.deletion_overlay.contains(&idx) { + fn get_submission(&self, index: u32) -> Option> { + if self.deletion_overlay.contains(&index) { // Note: can't actually remove the item from the insertion overlay (if present) // because we don't want to use `&mut self` here. There may be some kind of // `RefCell` optimization possible here in the future. None } else { self.insertion_overlay - .get(&idx) + .get(&index) .cloned() - .or_else(|| SignedSubmissionsMap::::try_get(idx).ok()) + .or_else(|| SignedSubmissionsMap::::get(index)) } } @@ -200,18 +200,18 @@ impl SignedSubmissions { remove_score: ElectionScore, insert: Option<(ElectionScore, u32)>, ) -> Option> { - let remove_idx = self.indices.remove(&remove_score)?; + let remove_index = self.indices.remove(&remove_score)?; if let Some((insert_score, insert_idx)) = insert { self.indices .try_insert(insert_score, insert_idx) .expect("just removed an item, we must be under capacity; qed"); } - self.insertion_overlay.remove(&remove_idx).or_else(|| { - (!self.deletion_overlay.contains(&remove_idx)) + self.insertion_overlay.remove(&remove_index).or_else(|| { + (!self.deletion_overlay.contains(&remove_index)) .then(|| { - self.deletion_overlay.insert(remove_idx); - SignedSubmissionsMap::::try_get(remove_idx).ok() + self.deletion_overlay.insert(remove_index); + SignedSubmissionsMap::::get(remove_index) }) .flatten() }) diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 8daa4e7fe13c1..c0b6fdfce6cd2 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -147,7 +147,7 @@ pub enum Renouncing { } /// An active voter. -#[derive(Encode, Decode, Clone, Default, RuntimeDebug, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, TypeInfo)] pub struct Voter { /// The members being backed. pub votes: Vec, @@ -159,6 +159,12 @@ pub struct Voter { pub deposit: Balance, } +impl Default for Voter { + fn default() -> Self { + Self { votes: vec![], stake: Default::default(), deposit: Default::default() } + } +} + /// A holder of a seat as either a member or a runner-up. #[derive(Encode, Decode, Clone, Default, RuntimeDebug, PartialEq, TypeInfo)] pub struct SeatHolder { @@ -1087,7 +1093,14 @@ impl SortedMembers for Pallet { fn add(who: &T::AccountId) { Members::::mutate(|members| match members.binary_search_by(|m| m.who.cmp(who)) { Ok(_) => (), - Err(pos) => members.insert(pos, SeatHolder { who: who.clone(), ..Default::default() }), + Err(pos) => { + let s = SeatHolder { + who: who.clone(), + stake: Default::default(), + deposit: Default::default(), + }; + members.insert(pos, s) + }, }) } } diff --git a/frame/elections/Cargo.toml b/frame/elections/Cargo.toml deleted file mode 100644 index d1404f7626129..0000000000000 --- a/frame/elections/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[package] -name = "pallet-elections" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "FRAME pallet for elections" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ - "derive", -] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } - -[dev-dependencies] -pallet-balances = { version = "4.0.0-dev", path = "../balances" } - -[features] -default = ["std"] -std = [ - "codec/std", - "scale-info/std", - "sp-core/std", - "sp-std/std", - "sp-io/std", - "frame-support/std", - "sp-runtime/std", - "frame-system/std", -] -try-runtime = ["frame-support/try-runtime"] diff --git a/frame/elections/README.md b/frame/elections/README.md deleted file mode 100644 index 1f6fd42331c15..0000000000000 --- a/frame/elections/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Election module for stake-weighted membership selection of a collective. - -The composition of a set of account IDs works according to one or more approval votes -weighted by stake. There is a partial carry-over facility to give greater weight to those -whose voting is serially unsuccessful. - -License: Apache-2.0 \ No newline at end of file diff --git a/frame/elections/src/lib.rs b/frame/elections/src/lib.rs deleted file mode 100644 index 7ca11f4ed20e8..0000000000000 --- a/frame/elections/src/lib.rs +++ /dev/null @@ -1,1324 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # WARNING: NOT ACTIVELY MAINTAINED -//! -//! This pallet is currently not maintained and should not be used in production until further -//! notice. -//! -//! --- -//! -//! Election pallet for stake-weighted membership selection of a collective. -//! -//! The composition of a set of account IDs works according to one or more approval votes -//! weighted by stake. There is a partial carry-over facility to give greater weight to those -//! whose voting is serially unsuccessful. - -#![cfg_attr(not(feature = "std"), no_std)] -#![recursion_limit = "128"] - -use codec::{Decode, Encode}; -use frame_support::{ - ensure, - pallet_prelude::*, - traits::{ - BalanceStatus, ChangeMembers, Currency, ExistenceRequirement, LockIdentifier, - LockableCurrency, OnUnbalanced, ReservableCurrency, WithdrawReasons, - }, - weights::{DispatchClass, Weight}, -}; -use frame_system::pallet_prelude::*; -pub use pallet::*; -use sp_runtime::{ - print, - traits::{One, Saturating, StaticLookup, Zero}, - RuntimeDebug, -}; -use sp_std::prelude::*; - -mod mock; -mod tests; - -// no polynomial attacks: -// -// all unbonded public operations should be constant time. -// all other public operations must be linear time in terms of prior public operations and: -// - those "valid" ones that cost nothing be limited to a constant number per single protected -// operation -// - the rest costing the same order as the computational complexity -// all protected operations must complete in at most O(public operations) -// -// we assume "beneficial" transactions will have the same access as attack transactions. -// -// any storage requirements should be bonded by the same order as the volume. - -// public operations: -// - express approvals (you pay in a "voter" bond the first time you do this; O(1); one extra DB -// entry, one DB change) -// - remove active voter (you get your "voter" bond back; O(1); one fewer DB entry, one DB change) -// - remove inactive voter (either you or the target is removed; if the target, you get their -// "voter" bond back; O(1); one fewer DB entry, one DB change) -// - submit candidacy (you pay a "candidate" bond; O(1); one extra DB entry, two DB changes) -// - present winner/runner-up (you may pay a "presentation" bond of O(voters) if the presentation is -// invalid; O(voters) compute; ) protected operations: -// - remove candidacy (remove all votes for a candidate) (one fewer DB entry, two DB changes) - -// to avoid a potentially problematic case of not-enough approvals prior to voting causing a -// back-to-back votes that have no way of ending, then there's a forced grace period between votes. -// to keep the system as stateless as possible (making it a bit easier to reason about), we just -// restrict when votes can begin to blocks that lie on boundaries (`voting_period`). - -// for an approval vote of C members: - -// top K runners-up are maintained between votes. all others are discarded. -// - candidate removed & bond returned when elected. -// - candidate removed & bond burned when discarded. - -// at the point that the vote ends (), all voters' balances are snapshotted. - -// for B blocks following, there's a counting period whereby each of the candidates that believe -// they fall in the top K+C voted can present themselves. they get the total stake -// recorded (based on the snapshot); an ordered list is maintained (the leaderboard). No one may -// present themselves that, if elected, would result in being included twice in the collective -// (important since existing members will have their approval votes as it may be that they -// don't get removed), nor if existing presenters would mean they're not in the top K+C. - -// following B blocks, the top C candidates are elected and have their bond returned. the top C -// candidates and all other candidates beyond the top C+K are cleared. - -// vote-clearing happens lazily; for an approval to count, the most recent vote at the time of the -// voter's most recent vote must be no later than the most recent vote at the time that the -// candidate in the approval position was registered there. as candidates are removed from the -// register and others join in their place, this prevents an approval meant for an earlier candidate -// being used to elect a new candidate. - -// the candidate list increases as needed, but the contents (though not really the capacity) reduce -// after each vote as all but K entries are cleared. newly registering candidates must use cleared -// entries before they increase the capacity. - -/// The activity status of a voter. -#[derive( - PartialEq, Eq, Copy, Clone, Encode, Decode, Default, RuntimeDebug, scale_info::TypeInfo, -)] -pub struct VoterInfo { - /// Last VoteIndex in which this voter assigned (or initialized) approvals. - last_active: VoteIndex, - /// Last VoteIndex in which one of this voter's approvals won. - /// Note that `last_win = N` indicates a last win at index `N-1`, hence `last_win = 0` means no - /// win ever. - last_win: VoteIndex, - /// The amount of stored weight as a result of not winning but changing approvals. - pot: Balance, - /// Current staked amount. A lock equal to this value always exists. - stake: Balance, -} - -/// Used to demonstrate the status of a particular index in the global voter list. -#[derive(PartialEq, Eq, RuntimeDebug)] -pub enum CellStatus { - /// Any out of bound index. Means a push a must happen to the chunk pointed by - /// `NextVoterSet`. Voting fee is applied in case a new chunk is created. - Head, - /// Already occupied by another voter. Voting fee is applied. - Occupied, - /// Empty hole which should be filled. No fee will be applied. - Hole, -} - -/// Number of voters grouped in one chunk. -pub const VOTER_SET_SIZE: usize = 64; -/// NUmber of approvals grouped in one chunk. -pub const APPROVAL_SET_SIZE: usize = 8; - -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; -type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, ->>::NegativeImbalance; - -/// Index used to access chunks. -type SetIndex = u32; -/// Index used to count voting rounds. -pub type VoteIndex = u32; -/// Underlying data type of the approvals. -type ApprovalFlag = u32; -/// Number of approval flags that can fit into [`ApprovalFlag`] type. -const APPROVAL_FLAG_LEN: usize = 32; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - - #[pallet::config] - pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; - - /// Identifier for the elections pallet's lock - #[pallet::constant] - type PalletId: Get; - - /// The currency that people are electing with. - type Currency: LockableCurrency - + ReservableCurrency; - - /// Handler for the unbalanced reduction when slashing a validator. - type BadPresentation: OnUnbalanced>; - - /// Handler for the unbalanced reduction when slashing an invalid reaping attempt. - type BadReaper: OnUnbalanced>; - - /// Handler for the unbalanced reduction when submitting a bad `voter_index`. - type BadVoterIndex: OnUnbalanced>; - - /// Handler for the unbalanced reduction when a candidate has lost (and is not a runner up) - type LoserCandidate: OnUnbalanced>; - - /// What to do when the members change. - type ChangeMembers: ChangeMembers; - - /// How much should be locked up in order to submit one's candidacy. A reasonable - /// default value is 9. - #[pallet::constant] - type CandidacyBond: Get>; - - /// How much should be locked up in order to be able to submit votes. - #[pallet::constant] - type VotingBond: Get>; - - /// The amount of fee paid upon each vote submission, unless if they submit a - /// _hole_ index and replace it. - #[pallet::constant] - type VotingFee: Get>; - - /// Minimum about that can be used as the locked value for voting. - #[pallet::constant] - type MinimumVotingLock: Get>; - - /// The punishment, per voter, if you provide an invalid presentation. A - /// reasonable default value is 1. - #[pallet::constant] - type PresentSlashPerVoter: Get>; - - /// How many runners-up should have their approvals persist until the next - /// vote. A reasonable default value is 2. - #[pallet::constant] - type CarryCount: Get; - - /// How many vote indices need to go by after a target voter's last vote before - /// they can be reaped if their approvals are moot. A reasonable default value - /// is 1. - #[pallet::constant] - type InactiveGracePeriod: Get; - - /// How often (in blocks) to check for new votes. A reasonable default value - /// is 1000. - #[pallet::constant] - type VotingPeriod: Get; - - /// Decay factor of weight when being accumulated. It should typically be set to - /// __at least__ `membership_size -1` to keep the collective secure. - /// When set to `N`, it indicates `(1/N)^t` of staked is decayed at weight - /// increment step `t`. 0 will result in no weight being added at all (normal - /// approval voting). A reasonable default value is 24. - #[pallet::constant] - type DecayRatio: Get; - } - - #[pallet::extra_constants] - impl Pallet { - // TODO: rename to snake case after https://github.com/paritytech/substrate/issues/8826 fixed. - /// The chunk size of the voter vector. - #[allow(non_snake_case)] - fn VOTER_SET_SIZE() -> u32 { - VOTER_SET_SIZE as u32 - } - - // TODO: rename to snake case after https://github.com/paritytech/substrate/issues/8826 fixed. - /// The chunk size of the approval vector. - #[allow(non_snake_case)] - fn APPROVAL_SET_SIZE() -> u32 { - APPROVAL_SET_SIZE as u32 - } - } - - // ---- permanent state (always relevant, changes only at the finalization of voting) - - /// How long to give each top candidate to present themselves after the vote ends. - #[pallet::storage] - #[pallet::getter(fn presentation_duration)] - pub type PresentationDuration = StorageValue<_, T::BlockNumber, ValueQuery>; - - /// How long each position is active for. - #[pallet::storage] - #[pallet::getter(fn term_duration)] - pub type TermDuration = StorageValue<_, T::BlockNumber, ValueQuery>; - - /// Number of accounts that should constitute the collective. - #[pallet::storage] - #[pallet::getter(fn desired_seats)] - pub type DesiredSeats = StorageValue<_, u32, ValueQuery>; - - // ---- permanent state (always relevant, changes only at the finalization of voting) - - /// The current membership. When there's a vote going on, this should still be used for - /// executive matters. The block number (second element in the tuple) is the block that - /// their position is active until (calculated by the sum of the block number when the - /// member was elected and their term duration). - #[pallet::storage] - #[pallet::getter(fn members)] - pub type Members = StorageValue<_, Vec<(T::AccountId, T::BlockNumber)>, ValueQuery>; - - /// The total number of vote rounds that have happened or are in progress. - #[pallet::storage] - #[pallet::getter(fn vote_index)] - pub type VoteCount = StorageValue<_, VoteIndex, ValueQuery>; - - // ---- persistent state (always relevant, changes constantly) - - // A list of votes for each voter. The votes are stored as numeric values and parsed in a - // bit-wise manner. In order to get a human-readable representation (`Vec`), use - // [`all_approvals_of`]. Furthermore, each vector of scalars is chunked with the cap of - // `APPROVAL_SET_SIZE`. - /// TWOX-NOTE: SAFE as `AccountId` is a crypto hash and `SetIndex` is not - /// attacker-controlled. - #[pallet::storage] - #[pallet::getter(fn approvals_of)] - pub type ApprovalsOf = - StorageMap<_, Twox64Concat, (T::AccountId, SetIndex), Vec, ValueQuery>; - - /// The vote index and list slot that the candidate `who` was registered or `None` if they - /// are not currently registered. - /// - /// TWOX-NOTE: SAFE as `AccountId` is a crypto hash. - #[pallet::storage] - #[pallet::getter(fn candidate_reg_info)] - pub type RegisterInfoOf = - StorageMap<_, Twox64Concat, T::AccountId, (VoteIndex, u32)>; - - /// Basic information about a voter. - /// - /// TWOX-NOTE: SAFE as `AccountId` is a crypto hash. - #[pallet::storage] - #[pallet::getter(fn voter_info)] - pub type VoterInfoOf = - StorageMap<_, Twox64Concat, T::AccountId, VoterInfo>>; - - /// The present voter list (chunked and capped at [`VOTER_SET_SIZE`]). - /// - /// TWOX-NOTE: OKAY ― `SetIndex` is not user-controlled data. - #[pallet::storage] - #[pallet::getter(fn voters)] - pub type Voters = - StorageMap<_, Twox64Concat, SetIndex, Vec>, ValueQuery>; - - /// the next free set to store a voter in. This will keep growing. - #[pallet::storage] - #[pallet::getter(fn next_nonfull_voter_set)] - pub type NextVoterSet = StorageValue<_, SetIndex, ValueQuery>; - - /// Current number of Voters. - #[pallet::storage] - #[pallet::getter(fn voter_count)] - pub type VoterCount = StorageValue<_, SetIndex, ValueQuery>; - - /// The present candidate list. - #[pallet::storage] - #[pallet::getter(fn candidates)] - pub type Candidates = StorageValue<_, Vec, ValueQuery>; // has holes - - /// Current number of active candidates - #[pallet::storage] - #[pallet::getter(fn candidate_count)] - pub type CandidateCount = StorageValue<_, u32, ValueQuery>; - - // ---- temporary state (only relevant during finalization/presentation) - - /// The accounts holding the seats that will become free on the next tally. - #[pallet::storage] - #[pallet::getter(fn next_finalize)] - pub type NextFinalize = StorageValue<_, (T::BlockNumber, u32, Vec)>; - - /// Get the leaderboard if we're in the presentation phase. The first element is the weight - /// of each entry; It may be the direct summed approval stakes, or a weighted version of it. - /// Sorted from low to high. - #[pallet::storage] - #[pallet::getter(fn leaderboard)] - pub type Leaderboard = StorageValue<_, Vec<(BalanceOf, T::AccountId)>>; - - #[pallet::genesis_config] - pub struct GenesisConfig { - pub presentation_duration: T::BlockNumber, - pub term_duration: T::BlockNumber, - pub desired_seats: u32, - pub members: Vec<(T::AccountId, T::BlockNumber)>, - } - - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - GenesisConfig { - presentation_duration: Default::default(), - term_duration: Default::default(), - desired_seats: Default::default(), - members: Default::default(), - } - } - } - - #[pallet::genesis_build] - impl GenesisBuild for GenesisConfig { - fn build(&self) { - PresentationDuration::::put(self.presentation_duration); - TermDuration::::put(self.term_duration); - DesiredSeats::::put(self.desired_seats); - Members::::put(&self.members); - } - } - - #[pallet::error] - pub enum Error { - /// Reporter must be a voter. - NotVoter, - /// Target for inactivity cleanup must be active. - InactiveTarget, - /// Cannot reap during presentation period. - CannotReapPresenting, - /// Cannot reap during grace period. - ReapGrace, - /// Invalid reporter index. - InvalidReporterIndex, - /// Invalid target index. - InvalidTargetIndex, - /// Invalid vote index. - InvalidVoteIndex, - /// Cannot retract when presenting. - CannotRetractPresenting, - /// Cannot retract non-voter. - RetractNonVoter, - /// Invalid retraction index. - InvalidRetractionIndex, - /// Duplicate candidate submission. - DuplicatedCandidate, - /// Invalid candidate slot. - InvalidCandidateSlot, - /// Candidate has not enough funds. - InsufficientCandidateFunds, - /// Presenter must have sufficient slashable funds. - InsufficientPresenterFunds, - /// Stake deposited to present winner and be added to leaderboard should be non-zero. - ZeroDeposit, - /// Candidate not worthy of leaderboard. - UnworthyCandidate, - /// Leaderboard must exist while present phase active. - LeaderboardMustExist, - /// Cannot present outside of presentation period. - NotPresentationPeriod, - /// Presented candidate must be current. - InvalidCandidate, - /// Duplicated presentation. - DuplicatedPresentation, - /// Incorrect total. - IncorrectTotal, - /// Invalid voter index. - InvalidVoterIndex, - /// New voter must have sufficient funds to pay the bond. - InsufficientVoterFunds, - /// Locked value must be more than limit. - InsufficientLockedValue, - /// Amount of candidate votes cannot exceed amount of candidates. - TooManyVotes, - /// Amount of candidates to receive approval votes should be non-zero. - ZeroCandidates, - /// No approval changes during presentation period. - ApprovalPresentation, - } - - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_initialize(n: T::BlockNumber) -> Weight { - if let Err(e) = Self::end_block(n) { - print("Guru meditation"); - print(e); - } - 0 - } - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// Reaped - VoterReaped { voter: T::AccountId, reaper: T::AccountId }, - /// Slashed - BadReaperSlashed { reaper: T::AccountId }, - /// A tally (for approval votes of seats) has started. - TallyStarted { seats: u32 }, - /// A tally (for approval votes of seat(s)) has ended (with one or more new members). - TallyFinalized { incoming: Vec, outgoing: Vec }, - } - - #[pallet::call] - impl Pallet { - /// Set candidate approvals. Approval slots stay valid as long as candidates in those slots - /// are registered. - /// - /// Locks `value` from the balance of `origin` indefinitely. Only - /// [`retract_voter`](Self::retract_voter) or - /// [`reap_inactive_voter`](Self::reap_inactive_voter) can unlock the balance. - /// - /// `hint` argument is interpreted differently based on: - /// - if `origin` is setting approvals for the first time: The index will be checked for - /// being a valid _hole_ in the voter list. - /// - if the hint is correctly pointing to a hole, no fee is deducted from `origin`. - /// - Otherwise, the call will succeed but the index is ignored and simply a push to the - /// last chunk with free space happens. If the new push causes a new chunk to be - /// created, a fee indicated by [`Config::VotingFee`] is deducted. - /// - if `origin` is already a voter: the index __must__ be valid and point to the correct - /// position of the `origin` in the current voters list. - /// - /// Note that any trailing `false` votes in `votes` is ignored; In approval voting, not - /// voting for a candidate and voting false, are equal. - /// - /// # - /// - O(1). - /// - Two extra DB entries, one DB change. - /// - Argument `votes` is limited in length to number of candidates. - /// # - #[pallet::weight(2_500_000_000)] - pub fn set_approvals( - origin: OriginFor, - votes: Vec, - #[pallet::compact] index: VoteIndex, - hint: SetIndex, - #[pallet::compact] value: BalanceOf, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - Self::do_set_approvals(who, votes, index, hint, value) - } - - /// Remove a voter. For it not to be a bond-consuming no-op, all approved candidate indices - /// must now be either unregistered or registered to a candidate that registered the slot - /// after the voter gave their last approval set. - /// - /// Both indices must be provided according to the following principle: - /// Voter index does not take holes into account. This means that any account submitting an - /// index at any point in time should submit: - /// `VOTER_SET_SIZE * set_index + local_index`, meaning that you are ignoring all holes in - /// the first `set_index` sets. - /// - /// May be called by anyone. Returns the voter deposit to `signed`. - /// - /// # - /// - O(1). - /// - Two fewer DB entries, one DB change. - /// # - #[pallet::weight(2_500_000_000)] - pub fn reap_inactive_voter( - origin: OriginFor, - #[pallet::compact] reporter_index: u32, - who: ::Source, - #[pallet::compact] who_index: u32, - #[pallet::compact] assumed_vote_index: VoteIndex, - ) -> DispatchResult { - let reporter = ensure_signed(origin)?; - let who = T::Lookup::lookup(who)?; - - ensure!(!Self::presentation_active(), Error::::CannotReapPresenting); - ensure!(Self::voter_info(&reporter).is_some(), Error::::NotVoter); - - let info = Self::voter_info(&who).ok_or(Error::::InactiveTarget)?; - let last_active = info.last_active; - - ensure!(assumed_vote_index == Self::vote_index(), Error::::InvalidVoteIndex); - ensure!( - assumed_vote_index > last_active + T::InactiveGracePeriod::get(), - Error::::ReapGrace, - ); - - let reporter_index = reporter_index as usize; - let who_index = who_index as usize; - let assumed_reporter = - Self::voter_at(reporter_index).ok_or(Error::::InvalidReporterIndex)?; - let assumed_who = Self::voter_at(who_index).ok_or(Error::::InvalidTargetIndex)?; - - ensure!(assumed_reporter == reporter, Error::::InvalidReporterIndex); - ensure!(assumed_who == who, Error::::InvalidTargetIndex); - - // will definitely kill one of reporter or who now. - - let valid = !Self::all_approvals_of(&who).iter().zip(Self::candidates().iter()).any( - |(&appr, addr)| { - appr && - *addr != T::AccountId::default() && - // defensive only: all items in candidates list are registered - Self::candidate_reg_info(addr).map_or(false, |x| x.0 <= last_active) - }, - ); - - Self::remove_voter( - if valid { &who } else { &reporter }, - if valid { who_index } else { reporter_index }, - ); - - T::Currency::remove_lock(T::PalletId::get(), if valid { &who } else { &reporter }); - - if valid { - // This only fails if `reporter` doesn't exist, which it clearly must do since its - // the origin. Still, it's no more harmful to propagate any error at this point. - T::Currency::repatriate_reserved( - &who, - &reporter, - T::VotingBond::get(), - BalanceStatus::Free, - )?; - Self::deposit_event(Event::::VoterReaped { voter: who, reaper: reporter }); - } else { - let imbalance = T::Currency::slash_reserved(&reporter, T::VotingBond::get()).0; - T::BadReaper::on_unbalanced(imbalance); - Self::deposit_event(Event::::BadReaperSlashed { reaper: reporter }); - } - Ok(()) - } - - /// Remove a voter. All votes are cancelled and the voter deposit is returned. - /// - /// The index must be provided according to the following principle: - /// Voter index does not take holes into account. This means that any account submitting an - /// index at any point in time should submit: - /// `VOTER_SET_SIZE * set_index + local_index`, meaning that you are ignoring all holes in - /// the first `set_index` sets. - /// - /// Also removes the lock on the balance of the voter. - /// - /// # - /// - O(1). - /// - Two fewer DB entries, one DB change. - /// # - #[pallet::weight(1_250_000_000)] - pub fn retract_voter( - origin: OriginFor, - #[pallet::compact] index: u32, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - ensure!(!Self::presentation_active(), Error::::CannotRetractPresenting); - ensure!(>::contains_key(&who), Error::::RetractNonVoter); - let index = index as usize; - let voter = Self::voter_at(index).ok_or(Error::::InvalidRetractionIndex)?; - ensure!(voter == who, Error::::InvalidRetractionIndex); - - Self::remove_voter(&who, index); - T::Currency::unreserve(&who, T::VotingBond::get()); - T::Currency::remove_lock(T::PalletId::get(), &who); - Ok(()) - } - - /// Submit oneself for candidacy. - /// - /// Account must have enough transferrable funds in it to pay the bond. - /// - /// NOTE: if `origin` has already assigned approvals via - /// [`set_approvals`](Self::set_approvals), it will NOT have any usable funds to pass - /// candidacy bond and must first retract. - /// Note that setting approvals will lock the entire balance of the voter until - /// retraction or being reported. - /// - /// # - /// - Independent of input. - /// - Three DB changes. - /// # - #[pallet::weight(2_500_000_000)] - pub fn submit_candidacy( - origin: OriginFor, - #[pallet::compact] slot: u32, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - ensure!(!Self::is_a_candidate(&who), Error::::DuplicatedCandidate); - let slot = slot as usize; - let count = Self::candidate_count() as usize; - let candidates = Self::candidates(); - ensure!( - (slot == count && count == candidates.len()) || - (slot < candidates.len() && candidates[slot] == T::AccountId::default()), - Error::::InvalidCandidateSlot, - ); - // NOTE: This must be last as it has side-effects. - T::Currency::reserve(&who, T::CandidacyBond::get()) - .map_err(|_| Error::::InsufficientCandidateFunds)?; - - >::insert(&who, (Self::vote_index(), slot as u32)); - let mut candidates = candidates; - if slot == candidates.len() { - candidates.push(who); - } else { - candidates[slot] = who; - } - >::put(candidates); - CandidateCount::::put(count as u32 + 1); - Ok(()) - } - - /// Claim that `candidate` is one of the top `carry_count + desired_seats` candidates. Only - /// works iff the presentation period is active. `candidate` should have at least collected - /// some non-zero `total` votes and `origin` must have enough funds to pay for a potential - /// slash. - /// - /// # - /// - O(voters) compute. - /// - One DB change. - /// # - #[pallet::weight(10_000_000_000)] - pub fn present_winner( - origin: OriginFor, - candidate: ::Source, - #[pallet::compact] total: BalanceOf, - #[pallet::compact] index: VoteIndex, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - ensure!(!total.is_zero(), Error::::ZeroDeposit); - - let candidate = T::Lookup::lookup(candidate)?; - ensure!(index == Self::vote_index(), Error::::InvalidVoteIndex); - let (_, _, expiring) = - Self::next_finalize().ok_or(Error::::NotPresentationPeriod)?; - let bad_presentation_punishment = - T::PresentSlashPerVoter::get() * BalanceOf::::from(Self::voter_count() as u32); - ensure!( - T::Currency::can_slash(&who, bad_presentation_punishment), - Error::::InsufficientPresenterFunds, - ); - - let mut leaderboard = Self::leaderboard().ok_or(Error::::LeaderboardMustExist)?; - ensure!(total > leaderboard[0].0, Error::::UnworthyCandidate); - - if let Some(p) = Self::members().iter().position(|&(ref c, _)| c == &candidate) { - ensure!(p < expiring.len(), Error::::DuplicatedCandidate); - } - - let voters = Self::all_voters(); - let (registered_since, candidate_index): (VoteIndex, u32) = - Self::candidate_reg_info(&candidate).ok_or(Error::::InvalidCandidate)?; - let actual_total = voters - .iter() - .filter_map(|maybe_voter| maybe_voter.as_ref()) - .filter_map(|voter| match Self::voter_info(voter) { - Some(b) if b.last_active >= registered_since => { - let last_win = b.last_win; - let now = Self::vote_index(); - let stake = b.stake; - let offset = Self::get_offset(stake, now - last_win); - let weight = stake + offset + b.pot; - if Self::approvals_of_at(voter, candidate_index as usize) { - Some(weight) - } else { - None - } - }, - _ => None, - }) - .fold(Zero::zero(), |acc, n| acc + n); - let dupe = leaderboard.iter().find(|&&(_, ref c)| c == &candidate).is_some(); - if total == actual_total && !dupe { - // insert into leaderboard - leaderboard[0] = (total, candidate); - leaderboard.sort_by_key(|&(t, _)| t); - >::put(leaderboard); - Ok(()) - } else { - // we can rest assured it will be Ok since we checked `can_slash` earlier; still - // better safe than sorry. - let imbalance = T::Currency::slash(&who, bad_presentation_punishment).0; - T::BadPresentation::on_unbalanced(imbalance); - Err(if dupe { - Error::::DuplicatedPresentation - } else { - Error::::IncorrectTotal - })? - } - } - - /// Set the desired member count; if lower than the current count, then seats will not be up - /// election when they expire. If more, then a new vote will be started if one is not - /// already in progress. - #[pallet::weight((0, DispatchClass::Operational))] - pub fn set_desired_seats( - origin: OriginFor, - #[pallet::compact] count: u32, - ) -> DispatchResult { - ensure_root(origin)?; - DesiredSeats::::put(count); - Ok(()) - } - - /// Remove a particular member from the set. This is effective immediately. - /// - /// Note: A tally should happen instantly (if not already in a presentation - /// period) to fill the seat if removal means that the desired members are not met. - #[pallet::weight((0, DispatchClass::Operational))] - pub fn remove_member( - origin: OriginFor, - who: ::Source, - ) -> DispatchResult { - ensure_root(origin)?; - let who = T::Lookup::lookup(who)?; - let new_set: Vec<(T::AccountId, T::BlockNumber)> = - Self::members().into_iter().filter(|i| i.0 != who).collect(); - >::put(&new_set); - let new_set = new_set.into_iter().map(|x| x.0).collect::>(); - T::ChangeMembers::change_members(&[], &[who], new_set); - Ok(()) - } - - /// Set the presentation duration. If there is currently a vote being presented for, will - /// invoke `finalize_vote`. - #[pallet::weight((0, DispatchClass::Operational))] - pub fn set_presentation_duration( - origin: OriginFor, - #[pallet::compact] count: T::BlockNumber, - ) -> DispatchResult { - ensure_root(origin)?; - >::put(count); - Ok(()) - } - - /// Set the presentation duration. If there is current a vote being presented for, will - /// invoke `finalize_vote`. - #[pallet::weight((0, DispatchClass::Operational))] - pub fn set_term_duration( - origin: OriginFor, - #[pallet::compact] count: T::BlockNumber, - ) -> DispatchResult { - ensure_root(origin)?; - >::put(count); - Ok(()) - } - } -} - -impl Pallet { - // exposed immutables. - - /// True if we're currently in a presentation period. - pub fn presentation_active() -> bool { - >::exists() - } - - /// If `who` a candidate at the moment? - pub fn is_a_candidate(who: &T::AccountId) -> bool { - >::contains_key(who) - } - - /// Iff the member `who` still has a seat at blocknumber `n` returns `true`. - pub fn will_still_be_member_at(who: &T::AccountId, n: T::BlockNumber) -> bool { - Self::members() - .iter() - .find(|&&(ref a, _)| a == who) - .map(|&(_, expires)| expires > n) - .unwrap_or(false) - } - - /// Determine the block that a vote can happen on which is no less than `n`. - pub fn next_vote_from(n: T::BlockNumber) -> T::BlockNumber { - let voting_period = T::VotingPeriod::get(); - (n + voting_period - One::one()) / voting_period * voting_period - } - - /// The block number on which the tally for the next election will happen. `None` only if the - /// desired seats of the set is zero. - pub fn next_tally() -> Option { - let desired_seats = Self::desired_seats(); - if desired_seats == 0 { - None - } else { - let c = Self::members(); - let (next_possible, count, coming) = if let Some((tally_end, comers, leavers)) = - Self::next_finalize() - { - // if there's a tally in progress, then next tally can begin immediately afterwards - (tally_end, c.len() - leavers.len() + comers as usize, comers) - } else { - (>::block_number(), c.len(), 0) - }; - if count < desired_seats as usize { - Some(next_possible) - } else { - // next tally begins once enough members expire to bring members below desired. - if desired_seats <= coming { - // the entire amount of desired seats is less than those new members - we'll - // have to wait until they expire. - Some(next_possible + Self::term_duration()) - } else { - Some(c[c.len() - (desired_seats - coming) as usize].1) - } - } - .map(Self::next_vote_from) - } - } - - // Private - /// Check there's nothing to do this block - fn end_block(block_number: T::BlockNumber) -> DispatchResult { - if (block_number % T::VotingPeriod::get()).is_zero() { - if let Some(number) = Self::next_tally() { - if block_number == number { - Self::start_tally(); - } - } - } - if let Some((number, _, _)) = Self::next_finalize() { - if block_number == number { - Self::finalize_tally()? - } - } - Ok(()) - } - - /// Remove a voter at a specified index from the system. - fn remove_voter(voter: &T::AccountId, index: usize) { - let (set_index, vec_index) = Self::split_index(index, VOTER_SET_SIZE); - let mut set = Self::voters(set_index); - set[vec_index] = None; - >::insert(set_index, set); - VoterCount::::mutate(|c| *c = *c - 1); - Self::remove_all_approvals_of(voter); - >::remove(voter); - } - - /// Actually do the voting. - /// - /// The voter index must be provided as explained in [`voter_at`] function. - fn do_set_approvals( - who: T::AccountId, - votes: Vec, - index: VoteIndex, - hint: SetIndex, - value: BalanceOf, - ) -> DispatchResult { - let candidates_len = ::Candidates::decode_len().unwrap_or(0_usize); - - ensure!(!Self::presentation_active(), Error::::ApprovalPresentation); - ensure!(index == Self::vote_index(), Error::::InvalidVoteIndex); - ensure!(!candidates_len.is_zero(), Error::::ZeroCandidates); - // Prevent a vote from voters that provide a list of votes that exceeds the candidates - // length since otherwise an attacker may be able to submit a very long list of `votes` that - // far exceeds the amount of candidates and waste more computation than a reasonable voting - // bond would cover. - ensure!(candidates_len >= votes.len(), Error::::TooManyVotes); - ensure!(value >= T::MinimumVotingLock::get(), Error::::InsufficientLockedValue); - - // Amount to be locked up. - let mut locked_balance = value.min(T::Currency::total_balance(&who)); - let mut pot_to_set = Zero::zero(); - let hint = hint as usize; - - if let Some(info) = Self::voter_info(&who) { - // already a voter. Index must be valid. No fee. update pot. O(1) - let voter = Self::voter_at(hint).ok_or(Error::::InvalidVoterIndex)?; - ensure!(voter == who, Error::::InvalidVoterIndex); - - // write new accumulated offset. - let last_win = info.last_win; - let now = index; - let offset = Self::get_offset(info.stake, now - last_win); - pot_to_set = info.pot + offset; - } else { - // not yet a voter. Index _could be valid_. Fee might apply. Bond will be reserved O(1). - ensure!( - T::Currency::free_balance(&who) > T::VotingBond::get(), - Error::::InsufficientVoterFunds, - ); - - let (set_index, vec_index) = Self::split_index(hint, VOTER_SET_SIZE); - match Self::cell_status(set_index, vec_index) { - CellStatus::Hole => { - // requested cell was a valid hole. - >::mutate(set_index, |set| set[vec_index] = Some(who.clone())); - }, - CellStatus::Head | CellStatus::Occupied => { - // Either occupied or out-of-range. - let next = Self::next_nonfull_voter_set(); - let set_len = >::decode_len(next).unwrap_or(0_usize); - // Caused a new set to be created. Pay for it. - // This is the last potential error. Writes will begin afterwards. - if set_len == 0 { - let imbalance = T::Currency::withdraw( - &who, - T::VotingFee::get(), - WithdrawReasons::FEE, - ExistenceRequirement::KeepAlive, - )?; - T::BadVoterIndex::on_unbalanced(imbalance); - // NOTE: this is safe since the `withdraw()` will check this. - locked_balance -= T::VotingFee::get(); - } - if set_len + 1 == VOTER_SET_SIZE { - NextVoterSet::::put(next + 1); - } - >::append(next, Some(who.clone())); - }, - } - - T::Currency::reserve(&who, T::VotingBond::get())?; - VoterCount::::mutate(|c| *c = *c + 1); - } - - T::Currency::set_lock(T::PalletId::get(), &who, locked_balance, WithdrawReasons::all()); - - >::insert( - &who, - VoterInfo::> { - last_active: index, - last_win: index, - stake: locked_balance, - pot: pot_to_set, - }, - ); - Self::set_approvals_chunked(&who, votes); - - Ok(()) - } - - /// Close the voting, record the number of seats that are actually up for grabs. - fn start_tally() { - let members = Self::members(); - let desired_seats = Self::desired_seats() as usize; - let number = >::block_number(); - let expiring = members - .iter() - .take_while(|i| i.1 <= number) - .map(|i| i.0.clone()) - .collect::>(); - let retaining_seats = members.len() - expiring.len(); - if retaining_seats < desired_seats { - let empty_seats = desired_seats - retaining_seats; - >::put(( - number + Self::presentation_duration(), - empty_seats as u32, - expiring, - )); - - // initialize leaderboard. - let leaderboard_size = empty_seats + T::CarryCount::get() as usize; - >::put(vec![ - (BalanceOf::::zero(), T::AccountId::default()); - leaderboard_size - ]); - - Self::deposit_event(Event::::TallyStarted { seats: empty_seats as u32 }); - } - } - - /// Finalize the vote, removing each of the `removals` and inserting `seats` of the most - /// approved candidates in their place. If the total number of members is less than the desired - /// membership a new vote is started. Clears all presented candidates, returning the bond of the - /// elected ones. - fn finalize_tally() -> DispatchResult { - let (_, coming, expiring): (T::BlockNumber, u32, Vec) = - >::take() - .ok_or("finalize can only be called after a tally is started.")?; - let leaderboard: Vec<(BalanceOf, T::AccountId)> = - >::take().unwrap_or_default(); - let new_expiry = >::block_number() + Self::term_duration(); - - // return bond to winners. - let candidacy_bond = T::CandidacyBond::get(); - let incoming: Vec<_> = leaderboard - .iter() - .rev() - .take_while(|&&(b, _)| !b.is_zero()) - .take(coming as usize) - .map(|(_, a)| a) - .cloned() - .inspect(|a| { - T::Currency::unreserve(a, candidacy_bond); - }) - .collect(); - - // Update last win index for anyone voted for any of the incomings. - incoming.iter().filter_map(|i| Self::candidate_reg_info(i)).for_each(|r| { - let index = r.1 as usize; - Self::all_voters() - .iter() - .filter_map(|mv| mv.as_ref()) - .filter(|v| Self::approvals_of_at(*v, index)) - .for_each(|v| { - >::mutate(v, |a| { - if let Some(activity) = a { - activity.last_win = Self::vote_index() + 1; - } - }) - }); - }); - let members = Self::members(); - let outgoing: Vec<_> = members.iter().take(expiring.len()).map(|a| a.0.clone()).collect(); - - // set the new membership set. - let mut new_set: Vec<_> = members - .into_iter() - .skip(expiring.len()) - .chain(incoming.iter().cloned().map(|a| (a, new_expiry))) - .collect(); - new_set.sort_by_key(|&(_, expiry)| expiry); - >::put(&new_set); - - let new_set = new_set.into_iter().map(|x| x.0).collect::>(); - T::ChangeMembers::change_members(&incoming, &outgoing, new_set); - - // clear all except runners-up from candidate list. - let candidates = Self::candidates(); - let mut new_candidates = vec![T::AccountId::default(); candidates.len()]; // shrink later. - let runners_up = leaderboard - .into_iter() - .rev() - .take_while(|&(b, _)| !b.is_zero()) - .skip(coming as usize) - .filter_map(|(_, a)| Self::candidate_reg_info(&a).map(|i| (a, i.1))); - let mut count = 0u32; - for (address, slot) in runners_up { - new_candidates[slot as usize] = address; - count += 1; - } - for (old, new) in candidates.iter().zip(new_candidates.iter()) { - // candidate is not a runner up. - if old != new { - // removed - kill it - >::remove(old); - - // and candidate is not a winner. - if incoming.iter().find(|e| *e == old).is_none() { - // slash the bond. - let (imbalance, _) = T::Currency::slash_reserved(&old, T::CandidacyBond::get()); - T::LoserCandidate::on_unbalanced(imbalance); - } - } - } - // discard any superfluous slots. - if let Some(last_index) = new_candidates.iter().rposition(|c| *c != T::AccountId::default()) - { - new_candidates.truncate(last_index + 1); - } - - Self::deposit_event(Event::::TallyFinalized { incoming, outgoing }); - - >::put(new_candidates); - CandidateCount::::put(count); - VoteCount::::put(Self::vote_index() + 1); - Ok(()) - } - - /// Get the set and vector index of a global voter index. - /// - /// Note that this function does not take holes into account. - /// See [`voter_at`]. - fn split_index(index: usize, scale: usize) -> (SetIndex, usize) { - let set_index = (index / scale) as u32; - let vec_index = index % scale; - (set_index, vec_index) - } - - /// Return a concatenated vector over all voter sets. - fn all_voters() -> Vec> { - let mut all = >::get(0); - let mut index = 1; - // NOTE: we could also use `Self::next_nonfull_voter_set()` here but that might change based - // on how we do chunking. This is more generic. - loop { - let next_set = >::get(index); - if next_set.is_empty() { - break - } else { - index += 1; - all.extend(next_set); - } - } - all - } - - /// Shorthand for fetching a voter at a specific (global) index. - /// - /// NOTE: this function is used for checking indices. Yet, it does not take holes into account. - /// This means that any account submitting an index at any point in time should submit: - /// `VOTER_SET_SIZE * set_index + local_index`, meaning that you are ignoring all holes in the - /// first `set_index` sets. - fn voter_at(index: usize) -> Option { - let (set_index, vec_index) = Self::split_index(index, VOTER_SET_SIZE); - let set = Self::voters(set_index); - if vec_index < set.len() { - set[vec_index].clone() - } else { - None - } - } - - /// A more sophisticated version of `voter_at`. Will be kept separate as most often it is an - /// overdue compared to `voter_at`. Only used when setting approvals. - fn cell_status(set_index: SetIndex, vec_index: usize) -> CellStatus { - let set = Self::voters(set_index); - if vec_index < set.len() { - if let Some(_) = set[vec_index] { - CellStatus::Occupied - } else { - CellStatus::Hole - } - } else { - CellStatus::Head - } - } - - /// Sets the approval of a voter in a chunked manner. - fn set_approvals_chunked(who: &T::AccountId, approvals: Vec) { - let approvals_flag_vec = Self::bool_to_flag(approvals); - approvals_flag_vec - .chunks(APPROVAL_SET_SIZE) - .enumerate() - .for_each(|(index, slice)| >::insert((&who, index as SetIndex), slice)); - } - - /// shorthand for fetching a specific approval of a voter at a specific (global) index. - /// - /// Using this function to read a vote is preferred as it reads `APPROVAL_SET_SIZE` items of - /// type `ApprovalFlag` from storage at most; not all of them. - /// - /// Note that false is returned in case of no-vote or an explicit `false`. - fn approvals_of_at(who: &T::AccountId, index: usize) -> bool { - let (flag_index, bit) = Self::split_index(index, APPROVAL_FLAG_LEN); - let (set_index, vec_index) = Self::split_index(flag_index as usize, APPROVAL_SET_SIZE); - let set = Self::approvals_of((who.clone(), set_index)); - if vec_index < set.len() { - // This is because bit_at treats numbers in lsb -> msb order. - let reversed_index = set.len() - 1 - vec_index; - Self::bit_at(set[reversed_index], bit) - } else { - false - } - } - - /// Return true of the bit `n` of scalar `x` is set to `1` and false otherwise. - fn bit_at(x: ApprovalFlag, n: usize) -> bool { - if n < APPROVAL_FLAG_LEN { - x & (1 << n) != 0 - } else { - false - } - } - - /// Convert a vec of boolean approval flags to a vec of integers, as denoted by - /// the type `ApprovalFlag`. see `bool_to_flag_should_work` test for examples. - pub fn bool_to_flag(x: Vec) -> Vec { - let mut result: Vec = Vec::with_capacity(x.len() / APPROVAL_FLAG_LEN); - if x.is_empty() { - return result - } - result.push(0); - let mut index = 0; - let mut counter = 0; - loop { - let shl_index = counter % APPROVAL_FLAG_LEN; - result[index] += (if x[counter] { 1 } else { 0 }) << shl_index; - counter += 1; - if counter > x.len() - 1 { - break - } - if counter % APPROVAL_FLAG_LEN == 0 { - result.push(0); - index += 1; - } - } - result - } - - /// Convert a vec of flags (u32) to boolean. - pub fn flag_to_bool(chunk: Vec) -> Vec { - let mut result = Vec::with_capacity(chunk.len()); - if chunk.is_empty() { - return vec![] - } - chunk - .into_iter() - .map(|num| { - (0..APPROVAL_FLAG_LEN).map(|bit| Self::bit_at(num, bit)).collect::>() - }) - .for_each(|c| { - let last_approve = match c.iter().rposition(|n| *n) { - Some(index) => index + 1, - None => 0, - }; - result.extend(c.into_iter().take(last_approve)); - }); - result - } - - /// Return a concatenated vector over all approvals of a voter as boolean. - /// The trailing zeros are removed. - fn all_approvals_of(who: &T::AccountId) -> Vec { - let mut all: Vec = vec![]; - let mut index = 0_u32; - loop { - let chunk = Self::approvals_of((who.clone(), index)); - if chunk.is_empty() { - break - } - all.extend(Self::flag_to_bool(chunk)); - index += 1; - } - all - } - - /// Remove all approvals associated with one account. - fn remove_all_approvals_of(who: &T::AccountId) { - let mut index = 0; - loop { - let set = Self::approvals_of((who.clone(), index)); - if set.len() > 0 { - >::remove((who.clone(), index)); - index += 1; - } else { - break - } - } - } - - /// Calculates the offset value (stored pot) of a stake, based on the distance - /// to the last win_index, `t`. Regardless of the internal implementation, - /// it should always be used with the following structure: - /// - /// Given Stake of voter `V` being `x` and distance to last_win index `t`, the new weight - /// of `V` is `x + get_offset(x, t)`. - /// - /// In other words, this function returns everything extra that should be added - /// to a voter's stake value to get the correct weight. Indeed, zero is - /// returned if `t` is zero. - fn get_offset(stake: BalanceOf, t: VoteIndex) -> BalanceOf { - let decay_ratio: BalanceOf = T::DecayRatio::get().into(); - if t > 150 { - return stake * decay_ratio - } - let mut offset = stake; - let mut r = Zero::zero(); - let decay = decay_ratio + One::one(); - for _ in 0..t { - offset = offset.saturating_sub(offset / decay); - r += offset - } - r - } -} diff --git a/frame/elections/src/mock.rs b/frame/elections/src/mock.rs deleted file mode 100644 index bce60534a3522..0000000000000 --- a/frame/elections/src/mock.rs +++ /dev/null @@ -1,274 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Mock file for election module. - -#![cfg(test)] - -use crate as elections; -use frame_support::{ - assert_ok, parameter_types, - traits::{ChangeMembers, Currency, LockIdentifier}, -}; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; - -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); -} -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type Origin = Origin; - type Call = Call; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 1; -} -impl pallet_balances::Config for Test { - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type Balance = u64; - type DustRemoval = (); - type Event = Event; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); -} - -parameter_types! { - pub const CandidacyBond: u64 = 3; - pub const CarryCount: u32 = 2; - pub const InactiveGracePeriod: u32 = 1; - pub const VotingPeriod: u64 = 4; - pub const MinimumVotingLock: u64 = 5; - pub static VotingBond: u64 = 0; - pub static VotingFee: u64 = 0; - pub static PresentSlashPerVoter: u64 = 0; - pub static DecayRatio: u32 = 0; - pub static Members: Vec = vec![]; -} - -pub struct TestChangeMembers; -impl ChangeMembers for TestChangeMembers { - fn change_members_sorted(incoming: &[u64], outgoing: &[u64], new: &[u64]) { - let mut old_plus_incoming = MEMBERS.with(|m| m.borrow().to_vec()); - old_plus_incoming.extend_from_slice(incoming); - old_plus_incoming.sort(); - let mut new_plus_outgoing = new.to_vec(); - new_plus_outgoing.extend_from_slice(outgoing); - new_plus_outgoing.sort(); - assert_eq!(old_plus_incoming, new_plus_outgoing); - - MEMBERS.with(|m| *m.borrow_mut() = new.to_vec()); - } -} - -parameter_types! { - pub const ElectionPalletId: LockIdentifier = *b"py/elect"; -} - -impl elections::Config for Test { - type Event = Event; - type Currency = Balances; - type BadPresentation = (); - type BadReaper = (); - type BadVoterIndex = (); - type LoserCandidate = (); - type ChangeMembers = TestChangeMembers; - type CandidacyBond = CandidacyBond; - type VotingBond = VotingBond; - type VotingFee = VotingFee; - type MinimumVotingLock = MinimumVotingLock; - type PresentSlashPerVoter = PresentSlashPerVoter; - type CarryCount = CarryCount; - type InactiveGracePeriod = InactiveGracePeriod; - type VotingPeriod = VotingPeriod; - type DecayRatio = DecayRatio; - type PalletId = ElectionPalletId; -} - -pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; - -use frame_system as system; -frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic - { - System: system::{Pallet, Call, Event}, - Balances: pallet_balances::{Pallet, Call, Event, Config}, - Elections: elections::{Pallet, Call, Event, Config}, - } -); - -pub struct ExtBuilder { - balance_factor: u64, - decay_ratio: u32, - desired_seats: u32, - voting_fee: u64, - voting_bond: u64, - bad_presentation_punishment: u64, -} - -impl Default for ExtBuilder { - fn default() -> Self { - Self { - balance_factor: 1, - decay_ratio: 24, - desired_seats: 2, - voting_fee: 0, - voting_bond: 0, - bad_presentation_punishment: 1, - } - } -} - -impl ExtBuilder { - pub fn balance_factor(mut self, factor: u64) -> Self { - self.balance_factor = factor; - self - } - pub fn decay_ratio(mut self, ratio: u32) -> Self { - self.decay_ratio = ratio; - self - } - pub fn voting_fee(mut self, fee: u64) -> Self { - self.voting_fee = fee; - self - } - pub fn bad_presentation_punishment(mut self, fee: u64) -> Self { - self.bad_presentation_punishment = fee; - self - } - pub fn voting_bond(mut self, fee: u64) -> Self { - self.voting_bond = fee; - self - } - pub fn desired_seats(mut self, seats: u32) -> Self { - self.desired_seats = seats; - self - } - pub fn build(self) -> sp_io::TestExternalities { - VOTING_BOND.with(|v| *v.borrow_mut() = self.voting_bond); - VOTING_FEE.with(|v| *v.borrow_mut() = self.voting_fee); - PRESENT_SLASH_PER_VOTER.with(|v| *v.borrow_mut() = self.bad_presentation_punishment); - DECAY_RATIO.with(|v| *v.borrow_mut() = self.decay_ratio); - let mut ext: sp_io::TestExternalities = GenesisConfig { - balances: pallet_balances::GenesisConfig:: { - balances: vec![ - (1, 10 * self.balance_factor), - (2, 20 * self.balance_factor), - (3, 30 * self.balance_factor), - (4, 40 * self.balance_factor), - (5, 50 * self.balance_factor), - (6, 60 * self.balance_factor), - ], - }, - elections: elections::GenesisConfig:: { - members: vec![], - desired_seats: self.desired_seats, - presentation_duration: 2, - term_duration: 5, - }, - } - .build_storage() - .unwrap() - .into(); - ext.execute_with(|| System::set_block_number(1)); - ext - } -} - -pub(crate) fn voter_ids() -> Vec { - Elections::all_voters().iter().map(|v| v.unwrap_or(0)).collect::>() -} - -pub(crate) fn vote(i: u64, l: usize) { - let _ = Balances::make_free_balance_be(&i, 20); - assert_ok!(Elections::set_approvals( - Origin::signed(i), - (0..l).map(|_| true).collect::>(), - 0, - 0, - 20, - )); -} - -pub(crate) fn vote_at(i: u64, l: usize, index: elections::VoteIndex) { - let _ = Balances::make_free_balance_be(&i, 20); - assert_ok!(Elections::set_approvals( - Origin::signed(i), - (0..l).map(|_| true).collect::>(), - 0, - index, - 20, - )); -} - -pub(crate) fn create_candidate(i: u64, index: u32) { - let _ = Balances::make_free_balance_be(&i, 20); - assert_ok!(Elections::submit_candidacy(Origin::signed(i), index)); -} - -pub(crate) fn balances(who: &u64) -> (u64, u64) { - (Balances::free_balance(who), Balances::reserved_balance(who)) -} - -pub(crate) fn locks(who: &u64) -> Vec { - Balances::locks(who).iter().map(|l| l.amount).collect::>() -} - -pub(crate) fn new_test_ext_with_candidate_holes() -> sp_io::TestExternalities { - let mut t = ExtBuilder::default().build(); - t.execute_with(|| { - >::put(vec![0, 0, 1]); - elections::CandidateCount::::put(1); - >::insert(1, (0, 2)); - }); - t -} diff --git a/frame/elections/src/tests.rs b/frame/elections/src/tests.rs deleted file mode 100644 index 0df84c6d79baf..0000000000000 --- a/frame/elections/src/tests.rs +++ /dev/null @@ -1,1881 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests for election module. - -#![cfg(test)] - -use crate::{mock::*, *}; - -use frame_support::{assert_err, assert_noop, assert_ok}; - -#[test] -fn params_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Elections::next_vote_from(1), 4); - assert_eq!(Elections::next_vote_from(4), 4); - assert_eq!(Elections::next_vote_from(5), 8); - assert_eq!(Elections::vote_index(), 0); - assert_eq!(Elections::presentation_duration(), 2); - assert_eq!(Elections::term_duration(), 5); - assert_eq!(Elections::desired_seats(), 2); - - assert_eq!(Elections::members(), vec![]); - assert_eq!(Elections::next_tally(), Some(4)); - assert_eq!(Elections::presentation_active(), false); - assert_eq!(Elections::next_finalize(), None); - - assert_eq!(Elections::candidates(), Vec::::new()); - assert_eq!(Elections::is_a_candidate(&1), false); - assert_eq!(Elections::candidate_reg_info(1), None); - - assert_eq!(Elections::voters(0), Vec::>::new()); - assert_eq!(Elections::voter_info(1), None); - assert!(Elections::all_approvals_of(&1).is_empty()); - }); -} - -#[test] -fn chunking_bool_to_flag_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert!(Elections::bool_to_flag(vec![]).is_empty()); - assert_eq!(Elections::bool_to_flag(vec![false]), vec![0]); - assert_eq!(Elections::bool_to_flag(vec![true]), vec![1]); - assert_eq!(Elections::bool_to_flag(vec![true, true, true, true]), vec![15]); - assert_eq!(Elections::bool_to_flag(vec![true, true, true, true, true]), vec![15 + 16]); - - let set_1 = vec![ - true, false, false, false, // 0x1 - false, true, true, true, // 0xE - ]; - assert_eq!(Elections::bool_to_flag(set_1.clone()), vec![0x00_00_00_E1_u32]); - assert_eq!(Elections::flag_to_bool(vec![0x00_00_00_E1_u32]), set_1); - - let set_2 = vec![ - false, false, false, true, // 0x8 - false, true, false, true, // 0xA - ]; - assert_eq!(Elections::bool_to_flag(set_2.clone()), vec![0x00_00_00_A8_u32]); - assert_eq!(Elections::flag_to_bool(vec![0x00_00_00_A8_u32]), set_2); - - let mut rhs = (0..100 / APPROVAL_FLAG_LEN).map(|_| 0xFFFFFFFF_u32).collect::>(); - // NOTE: this might be need change based on `APPROVAL_FLAG_LEN`. - rhs.extend(vec![0x00_00_00_0F]); - assert_eq!(Elections::bool_to_flag((0..100).map(|_| true).collect()), rhs) - }) -} - -#[test] -fn chunking_voter_set_growth_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - - // create 65. 64 (set0) + 1 (set1) - (1..=63).for_each(|i| vote(i, 0)); - assert_eq!(Elections::next_nonfull_voter_set(), 0); - vote(64, 0); - assert_eq!(Elections::next_nonfull_voter_set(), 1); - vote(65, 0); - - let set1 = Elections::voters(0); - let set2 = Elections::voters(1); - - assert_eq!(set1.len(), 64); - assert_eq!(set2.len(), 1); - - assert_eq!(set1[0], Some(1)); - assert_eq!(set1[10], Some(11)); - assert_eq!(set2[0], Some(65)); - }) -} - -#[test] -fn chunking_voter_set_reclaim_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - - (1..=129).for_each(|i| vote(i, 0)); - assert_eq!(Elections::next_nonfull_voter_set(), 2); - - assert_ok!(Elections::retract_voter(Origin::signed(11), 10)); - - assert_ok!(Elections::retract_voter(Origin::signed(66), 65)); - assert_ok!(Elections::retract_voter(Origin::signed(67), 66)); - - // length does not show it but holes do exist. - assert_eq!(Elections::voters(0).len(), 64); - assert_eq!(Elections::voters(1).len(), 64); - assert_eq!(Elections::voters(2).len(), 1); - - assert_eq!(Elections::voters(0)[10], None); - assert_eq!(Elections::voters(1)[1], None); - assert_eq!(Elections::voters(1)[2], None); - // Next set with capacity is 2. - assert_eq!(Elections::next_nonfull_voter_set(), 2); - - // But we can fill a hole. - vote_at(130, 0, 10); - - // Nothing added to set 2. A hole was filled. - assert_eq!(Elections::voters(0).len(), 64); - assert_eq!(Elections::voters(1).len(), 64); - assert_eq!(Elections::voters(2).len(), 1); - - // and the next two (scheduled) to the second set. - assert_eq!(Elections::next_nonfull_voter_set(), 2); - }) -} - -#[test] -fn chunking_approvals_set_growth_should_work() { - ExtBuilder::default().build().execute_with(|| { - // create candidates and voters. - (1..=250).for_each(|i| create_candidate(i, (i - 1) as u32)); - (1..=250).for_each(|i| vote(i, i as usize)); - - // all approvals of should return the exact expected vector. - assert_eq!( - Elections::all_approvals_of(&180), - (0..180).map(|_| true).collect::>() - ); - assert_eq!(Elections::all_approvals_of(&32), (0..32).map(|_| true).collect::>()); - assert_eq!(Elections::all_approvals_of(&8), (0..8).map(|_| true).collect::>()); - assert_eq!(Elections::all_approvals_of(&64), (0..64).map(|_| true).collect::>()); - assert_eq!(Elections::all_approvals_of(&65), (0..65).map(|_| true).collect::>()); - assert_eq!(Elections::all_approvals_of(&63), (0..63).map(|_| true).collect::>()); - - // NOTE: assuming that APPROVAL_SET_SIZE is more or less small-ish. Might fail otherwise. - let full_sets = (180 / APPROVAL_FLAG_LEN) / APPROVAL_SET_SIZE; - let left_over = (180 / APPROVAL_FLAG_LEN) / APPROVAL_SET_SIZE; - let rem = 180 % APPROVAL_FLAG_LEN; - - // grab and check the last full set, if it exists. - if full_sets > 0 { - assert_eq!( - Elections::approvals_of((180, (full_sets - 1) as SetIndex)), - Elections::bool_to_flag( - (0..APPROVAL_SET_SIZE * APPROVAL_FLAG_LEN).map(|_| true).collect::>() - ) - ); - } - - // grab and check the last, half-empty, set. - if left_over > 0 { - assert_eq!( - Elections::approvals_of((180, full_sets as SetIndex)), - Elections::bool_to_flag( - (0..left_over * APPROVAL_FLAG_LEN + rem).map(|_| true).collect::>() - ) - ); - } - }) -} - -#[test] -fn chunking_cell_status_works() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - - (1..=63).for_each(|i| vote(i, 0)); - - assert_ok!(Elections::retract_voter(Origin::signed(11), 10)); - assert_ok!(Elections::retract_voter(Origin::signed(21), 20)); - - assert_eq!(Elections::cell_status(0, 10), CellStatus::Hole); - assert_eq!(Elections::cell_status(0, 0), CellStatus::Occupied); - assert_eq!(Elections::cell_status(0, 20), CellStatus::Hole); - assert_eq!(Elections::cell_status(0, 63), CellStatus::Head); - assert_eq!(Elections::cell_status(1, 0), CellStatus::Head); - assert_eq!(Elections::cell_status(1, 10), CellStatus::Head); - }) -} - -#[test] -fn chunking_voter_index_does_not_take_holes_into_account() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - - // create 65. 64 (set0) + 1 (set1) - (1..=65).for_each(|i| vote(i, 0)); - - // account 65 has global index 65. - assert_eq!(Elections::voter_at(64).unwrap(), 65); - - assert_ok!(Elections::retract_voter(Origin::signed(1), 0)); - assert_ok!(Elections::retract_voter(Origin::signed(2), 1)); - - // still the same. These holes are in some other set. - assert_eq!(Elections::voter_at(64).unwrap(), 65); - // proof: can submit a new approval with the old index. - assert_noop!( - Elections::set_approvals(Origin::signed(65), vec![], 0, 64 - 2, 10), - Error::::InvalidVoterIndex, - ); - assert_ok!(Elections::set_approvals(Origin::signed(65), vec![], 0, 64, 10)); - }) -} - -#[test] -fn chunking_approval_storage_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); - - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false], 0, 0, 20)); - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false], 0, 0, 30)); - assert_ok!(Elections::set_approvals(Origin::signed(4), vec![], 0, 0, 40)); - - assert_eq!(Elections::all_approvals_of(&2), vec![true]); - // NOTE: these two are stored in mem differently though. - assert!(Elections::all_approvals_of(&3).is_empty()); - assert!(Elections::all_approvals_of(&4).is_empty()); - - assert_eq!(Elections::approvals_of((3, 0)), vec![0]); - assert!(Elections::approvals_of((4, 0)).is_empty()); - }); -} - -#[test] -fn voting_initial_set_approvals_ignores_voter_index() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - - // Last argument is essentially irrelevant. You might get or miss a tip. - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![], 0, 0, 30)); - assert_ok!(Elections::set_approvals(Origin::signed(4), vec![], 0, 5, 40)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![], 0, 100, 50)); - - // indices are more or less ignored. all is pushed. - assert_eq!(voter_ids(), vec![3, 4, 5]); - }) -} -#[test] -fn voting_bad_approval_index_slashes_voters_and_bond_reduces_stake() { - ExtBuilder::default().voting_fee(5).voting_bond(2).build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - - (1..=63).for_each(|i| vote(i, 0)); - assert_eq!(balances(&1), (13, 2)); - assert_eq!(balances(&10), (18, 2)); - assert_eq!(balances(&60), (18, 2)); - - // still no fee - vote(64, 0); - assert_eq!(balances(&64), (18, 2)); - assert_eq!( - Elections::voter_info(&64).unwrap(), - VoterInfo { last_win: 0, last_active: 0, stake: 20, pot: 0 } - ); - - assert_eq!(Elections::next_nonfull_voter_set(), 1); - - // now we charge the next voter. - vote(65, 0); - assert_eq!(balances(&65), (13, 2)); - assert_eq!( - Elections::voter_info(&65).unwrap(), - VoterInfo { last_win: 0, last_active: 0, stake: 15, pot: 0 } - ); - }); -} - -#[test] -fn voting_subsequent_set_approvals_checks_voter_index() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![], 0, 0, 30)); - assert_ok!(Elections::set_approvals(Origin::signed(4), vec![], 0, 5, 40)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![], 0, 100, 50)); - - // invalid index - assert_noop!( - Elections::set_approvals(Origin::signed(4), vec![true], 0, 5, 40), - Error::::InvalidVoterIndex, - ); - // wrong index - assert_noop!( - Elections::set_approvals(Origin::signed(4), vec![true], 0, 0, 40), - Error::::InvalidVoterIndex, - ); - // correct - assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 1, 40)); - }) -} - -#[test] -fn voting_cannot_lock_less_than_limit() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - - assert_noop!( - Elections::set_approvals(Origin::signed(3), vec![], 0, 0, 4), - Error::::InsufficientLockedValue, - ); - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![], 0, 0, 5)); - }); -} - -#[test] -fn voting_locking_more_than_total_balance_is_moot() { - ExtBuilder::default().voting_bond(2).build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - - assert_eq!(balances(&3), (30, 0)); - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![], 0, 0, 35)); - - assert_eq!(balances(&3), (28, 2)); - assert_eq!( - Elections::voter_info(&3).unwrap(), - VoterInfo { last_win: 0, last_active: 0, stake: 30, pot: 0 } - ); - }); -} - -#[test] -fn voting_locking_stake_and_reserving_bond_works() { - ExtBuilder::default().voting_bond(2).build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); - - assert_eq!(balances(&2), (20, 0)); - assert!(locks(&2).is_empty()); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![], 0, 0, 15)); - assert_eq!(balances(&2), (18, 2)); - assert_eq!(locks(&2), vec![15]); - - // deposit a bit more. - let _ = Balances::make_free_balance_be(&2, 100); - - // change vote - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 70)); - assert_eq!(balances(&2), (100, 2)); - assert_eq!(locks(&2), vec![70]); - - assert_ok!(Elections::retract_voter(Origin::signed(2), 0)); - - assert_eq!(balances(&2), (102, 0)); - assert!(locks(&2).is_empty()); - }); -} - -#[test] -fn voting_without_any_candidate_count_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Elections::candidates().len(), 0); - - assert_noop!( - Elections::set_approvals(Origin::signed(4), vec![], 0, 0, 40), - Error::::ZeroCandidates, - ); - }); -} - -#[test] -fn voting_setting_an_approval_vote_count_more_than_candidate_count_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); - assert_eq!(Elections::candidates().len(), 1); - - assert_noop!( - Elections::set_approvals(Origin::signed(4), vec![true, true], 0, 0, 40), - Error::::TooManyVotes, - ); - }); -} - -#[test] -fn voting_resubmitting_approvals_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 0, 40)); - - assert_eq!(Elections::all_approvals_of(&4), vec![true]); - - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); - assert_eq!(Elections::candidates().len(), 3); - assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true, false, true], 0, 0, 40)); - - assert_eq!(Elections::all_approvals_of(&4), vec![true, false, true]); - }); -} - -#[test] -fn voting_retracting_voter_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); - assert_eq!(Elections::candidates().len(), 1); - - assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0, 10)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 1, 20)); - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![true], 0, 2, 30)); - assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 3, 40)); - - assert_eq!(voter_ids(), vec![1, 2, 3, 4]); - assert_eq!(Elections::all_approvals_of(&1), vec![true]); - assert_eq!(Elections::all_approvals_of(&2), vec![true]); - assert_eq!(Elections::all_approvals_of(&3), vec![true]); - assert_eq!(Elections::all_approvals_of(&4), vec![true]); - - assert_ok!(Elections::retract_voter(Origin::signed(1), 0)); - - assert_eq!(voter_ids(), vec![0, 2, 3, 4]); - assert_eq!(Elections::all_approvals_of(&1), Vec::::new()); - assert_eq!(Elections::all_approvals_of(&2), vec![true]); - assert_eq!(Elections::all_approvals_of(&3), vec![true]); - assert_eq!(Elections::all_approvals_of(&4), vec![true]); - - assert_ok!(Elections::retract_voter(Origin::signed(2), 1)); - - assert_eq!(voter_ids(), vec![0, 0, 3, 4]); - assert_eq!(Elections::all_approvals_of(&1), Vec::::new()); - assert_eq!(Elections::all_approvals_of(&2), Vec::::new()); - assert_eq!(Elections::all_approvals_of(&3), vec![true]); - assert_eq!(Elections::all_approvals_of(&4), vec![true]); - - assert_ok!(Elections::retract_voter(Origin::signed(3), 2)); - - assert_eq!(voter_ids(), vec![0, 0, 0, 4]); - assert_eq!(Elections::all_approvals_of(&1), Vec::::new()); - assert_eq!(Elections::all_approvals_of(&2), Vec::::new()); - assert_eq!(Elections::all_approvals_of(&3), Vec::::new()); - assert_eq!(Elections::all_approvals_of(&4), vec![true]); - }); -} - -#[test] -fn voting_invalid_retraction_index_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); - - assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0, 10)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); - assert_eq!(voter_ids(), vec![1, 2]); - assert_noop!( - Elections::retract_voter(Origin::signed(1), 1), - Error::::InvalidRetractionIndex - ); - }); -} - -#[test] -fn voting_overflow_retraction_index_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); - - assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0, 10)); - assert_noop!( - Elections::retract_voter(Origin::signed(1), 1), - Error::::InvalidRetractionIndex - ); - }); -} - -#[test] -fn voting_non_voter_retraction_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); - - assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0, 10)); - assert_noop!( - Elections::retract_voter(Origin::signed(2), 0), - Error::::RetractNonVoter - ); - }); -} - -#[test] -fn retracting_inactive_voter_should_work() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 1, 0, 50)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 1)); - assert_ok!(Elections::end_block(System::block_number())); - - assert_ok!(Elections::reap_inactive_voter( - Origin::signed(5), - (voter_ids().iter().position(|&i| i == 5).unwrap() as u32).into(), - 2, - (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2 - )); - - assert_eq!(voter_ids(), vec![0, 5]); - assert_eq!(Elections::all_approvals_of(&2).len(), 0); - assert_eq!(Balances::total_balance(&2), 20); - assert_eq!(Balances::total_balance(&5), 50); - }); -} - -#[test] -fn retracting_inactive_voter_with_other_candidates_in_slots_should_work() { - ExtBuilder::default().voting_bond(2).build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 1, 0, 50)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 1)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(11); - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - - assert_ok!(Elections::reap_inactive_voter( - Origin::signed(5), - (voter_ids().iter().position(|&i| i == 5).unwrap() as u32).into(), - 2, - (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2 - )); - - assert_eq!(voter_ids(), vec![0, 5]); - assert_eq!(Elections::all_approvals_of(&2).len(), 0); - }); -} - -#[test] -fn retracting_inactive_voter_with_bad_reporter_index_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 1, 0, 50)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 1)); - assert_ok!(Elections::end_block(System::block_number())); - - assert_noop!( - Elections::reap_inactive_voter( - Origin::signed(2), - 42, - 2, - (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2 - ), - Error::::InvalidReporterIndex - ); - }); -} - -#[test] -fn retracting_inactive_voter_with_bad_target_index_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 1, 0, 50)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 1)); - assert_ok!(Elections::end_block(System::block_number())); - - assert_noop!( - Elections::reap_inactive_voter( - Origin::signed(2), - (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2, - 42, - 2 - ), - Error::::InvalidTargetIndex - ); - }); -} - -#[test] -fn retracting_active_voter_should_slash_reporter() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(4), 2)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 3)); - assert_ok!(Elections::set_approvals( - Origin::signed(2), - vec![true, false, false, false], - 0, - 0, - 20 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(3), - vec![false, true, false, false], - 0, - 0, - 30 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(4), - vec![false, false, true, false], - 0, - 0, - 40 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, false, false, true], - 0, - 0, - 50 - )); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Elections::set_desired_seats(Origin::root(), 3)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Elections::present_winner( - Origin::signed(4), - 2, - 20 + Elections::get_offset(20, 1), - 1 - )); - assert_ok!(Elections::present_winner( - Origin::signed(4), - 3, - 30 + Elections::get_offset(30, 1), - 1 - )); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::vote_index(), 2); - assert_eq!(::InactiveGracePeriod::get(), 1); - assert_eq!(::VotingPeriod::get(), 4); - assert_eq!( - Elections::voter_info(4), - Some(VoterInfo { last_win: 1, last_active: 0, stake: 40, pot: 0 }) - ); - - assert_ok!(Elections::reap_inactive_voter( - Origin::signed(4), - (voter_ids().iter().position(|&i| i == 4).unwrap() as u32).into(), - 2, - (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2 - )); - - assert_eq!(voter_ids(), vec![2, 3, 0, 5]); - assert_eq!(Elections::all_approvals_of(&4).len(), 0); - assert_eq!(Balances::total_balance(&4), 40); - }); -} - -#[test] -fn retracting_inactive_voter_by_nonvoter_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 1, 0, 50)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 1)); - assert_ok!(Elections::end_block(System::block_number())); - - assert_noop!( - Elections::reap_inactive_voter( - Origin::signed(4), - 0, - 2, - (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2 - ), - Error::::NotVoter - ); - }); -} - -#[test] -fn candidacy_simple_candidate_submission_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Elections::candidates(), Vec::::new()); - assert_eq!(Elections::candidate_reg_info(1), None); - assert_eq!(Elections::candidate_reg_info(2), None); - assert_eq!(Elections::is_a_candidate(&1), false); - assert_eq!(Elections::is_a_candidate(&2), false); - - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - assert_eq!(Elections::candidates(), vec![1]); - assert_eq!(Elections::candidate_reg_info(1), Some((0, 0))); - assert_eq!(Elections::candidate_reg_info(2), None); - assert_eq!(Elections::is_a_candidate(&1), true); - assert_eq!(Elections::is_a_candidate(&2), false); - - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); - assert_eq!(Elections::candidates(), vec![1, 2]); - assert_eq!(Elections::candidate_reg_info(1), Some((0, 0))); - assert_eq!(Elections::candidate_reg_info(2), Some((0, 1))); - assert_eq!(Elections::is_a_candidate(&1), true); - assert_eq!(Elections::is_a_candidate(&2), true); - }); -} - -#[test] -fn candidacy_submission_using_free_slot_should_work() { - let mut t = new_test_ext_with_candidate_holes(); - - t.execute_with(|| { - assert_eq!(Elections::candidates(), vec![0, 0, 1]); - - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); - assert_eq!(Elections::candidates(), vec![0, 2, 1]); - - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); - assert_eq!(Elections::candidates(), vec![3, 2, 1]); - }); -} - -#[test] -fn candidacy_submission_using_alternative_free_slot_should_work() { - let mut t = new_test_ext_with_candidate_holes(); - - t.execute_with(|| { - assert_eq!(Elections::candidates(), vec![0, 0, 1]); - - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_eq!(Elections::candidates(), vec![2, 0, 1]); - - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); - assert_eq!(Elections::candidates(), vec![2, 3, 1]); - }); -} - -#[test] -fn candidacy_submission_not_using_free_slot_should_not_work() { - let mut t = new_test_ext_with_candidate_holes(); - - t.execute_with(|| { - assert_noop!( - Elections::submit_candidacy(Origin::signed(4), 3), - Error::::InvalidCandidateSlot - ); - }); -} - -#[test] -fn candidacy_bad_candidate_slot_submission_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Elections::candidates(), Vec::::new()); - assert_noop!( - Elections::submit_candidacy(Origin::signed(1), 1), - Error::::InvalidCandidateSlot - ); - }); -} - -#[test] -fn candidacy_non_free_candidate_slot_submission_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Elections::candidates(), Vec::::new()); - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - assert_eq!(Elections::candidates(), vec![1]); - assert_noop!( - Elections::submit_candidacy(Origin::signed(2), 0), - Error::::InvalidCandidateSlot - ); - }); -} - -#[test] -fn candidacy_dupe_candidate_submission_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Elections::candidates(), Vec::::new()); - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - assert_eq!(Elections::candidates(), vec![1]); - assert_noop!( - Elections::submit_candidacy(Origin::signed(1), 1), - Error::::DuplicatedCandidate, - ); - }); -} - -#[test] -fn candidacy_poor_candidate_submission_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Elections::candidates(), Vec::::new()); - assert_noop!( - Elections::submit_candidacy(Origin::signed(7), 0), - Error::::InsufficientCandidateFunds, - ); - }); -} - -#[test] -fn election_voting_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); - - assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0, 10)); - assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 1, 40)); - - assert_eq!(Elections::all_approvals_of(&1), vec![true]); - assert_eq!(Elections::all_approvals_of(&4), vec![true]); - assert_eq!(voter_ids(), vec![1, 4]); - - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); - - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true, true], 0, 2, 20)); - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, true, true], 0, 3, 30)); - - assert_eq!(Elections::all_approvals_of(&1), vec![true]); - assert_eq!(Elections::all_approvals_of(&4), vec![true]); - assert_eq!(Elections::all_approvals_of(&2), vec![false, true, true]); - assert_eq!(Elections::all_approvals_of(&3), vec![false, true, true]); - - assert_eq!(voter_ids(), vec![1, 4, 2, 3]); - }); -} - -#[test] -fn election_simple_tally_should_work() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert!(!Elections::presentation_active()); - - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true], 0, 0, 50)); - assert_eq!(voter_ids(), vec![2, 5]); - assert_eq!(Elections::all_approvals_of(&2), vec![true]); - assert_eq!(Elections::all_approvals_of(&5), vec![false, true]); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(4), 2, 20, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(4), 5, 50, 0), Ok(())); - assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (0, 0), (20, 2), (50, 5)])); - assert_ok!(Elections::end_block(System::block_number())); - - assert!(!Elections::presentation_active()); - assert_eq!(Elections::members(), vec![(5, 11), (2, 11)]); - - assert!(!Elections::is_a_candidate(&2)); - assert!(!Elections::is_a_candidate(&5)); - assert_eq!(Elections::vote_index(), 1); - assert_eq!( - Elections::voter_info(2), - Some(VoterInfo { last_win: 1, last_active: 0, stake: 20, pot: 0 }) - ); - assert_eq!( - Elections::voter_info(5), - Some(VoterInfo { last_win: 1, last_active: 0, stake: 50, pot: 0 }) - ); - }); -} - -#[test] -fn election_seats_should_be_released() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false], 0, 0, 20)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true], 0, 0, 50)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(4), 2, 20, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(4), 5, 50, 0), Ok(())); - assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (0, 0), (20, 2), (50, 5)])); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(5, 11), (2, 11)]); - let mut current = System::block_number(); - let free_block; - loop { - current += 1; - System::set_block_number(current); - assert_ok!(Elections::end_block(System::block_number())); - if Elections::members().len() == 0 { - free_block = current; - break - } - } - // 11 + 2 which is the next voting period. - assert_eq!(free_block, 14); - }); -} - -#[test] -fn election_presentations_with_zero_staked_deposit_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_noop!( - Elections::present_winner(Origin::signed(4), 2, 0, 0), - Error::::ZeroDeposit, - ); - }); -} - -#[test] -fn election_double_presentations_should_be_punished() { - ExtBuilder::default().build().execute_with(|| { - assert!(Balances::can_slash(&4, 10)); - - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false], 0, 0, 20)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true], 0, 0, 50)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); - assert_eq!( - Elections::present_winner(Origin::signed(4), 5, 50, 0), - Err(Error::::DuplicatedPresentation.into()), - ); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(5, 11), (2, 11)]); - assert_eq!(Balances::total_balance(&4), 38); - }); -} - -#[test] -fn election_presenting_for_double_election_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_eq!(Elections::submit_candidacy(Origin::signed(2), 0), Ok(())); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(8); - // NOTE: This is now mandatory to disable the lock - assert_ok!(Elections::retract_voter(Origin::signed(2), 0)); - assert_eq!(Elections::submit_candidacy(Origin::signed(2), 0), Ok(())); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 1, 0, 20)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(10); - assert_noop!( - Elections::present_winner(Origin::signed(4), 2, 20, 1), - Error::::DuplicatedCandidate, - ); - }); -} - -#[test] -fn election_presenting_loser_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0, 60)); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true], 0, 0, 20)); - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0, 30)); - assert_ok!(Elections::submit_candidacy(Origin::signed(4), 3)); - assert_ok!(Elections::set_approvals( - Origin::signed(4), - vec![false, false, false, true], - 0, - 0, - 40 - )); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 4)); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, false, false, false, true], - 0, - 0, - 50 - )); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 1, 60, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); - - assert_eq!(Elections::leaderboard(), Some(vec![(30, 3), (40, 4), (50, 5), (60, 1)])); - - assert_noop!( - Elections::present_winner(Origin::signed(4), 2, 20, 0), - Error::::UnworthyCandidate - ); - }); -} - -#[test] -fn election_presenting_loser_first_should_not_matter() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0, 60)); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true], 0, 0, 20)); - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0, 30)); - assert_ok!(Elections::submit_candidacy(Origin::signed(4), 3)); - assert_ok!(Elections::set_approvals( - Origin::signed(4), - vec![false, false, false, true], - 0, - 0, - 40 - )); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 4)); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, false, false, false, true], - 0, - 0, - 50 - )); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 1, 60, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); - - assert_eq!(Elections::leaderboard(), Some(vec![(30, 3), (40, 4), (50, 5), (60, 1)])); - }); -} - -#[test] -fn election_present_outside_of_presentation_period_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert!(!Elections::presentation_active()); - assert_noop!( - Elections::present_winner(Origin::signed(5), 5, 1, 0), - Error::::NotPresentationPeriod, - ); - }); -} - -#[test] -fn election_present_with_invalid_vote_index_should_not_work() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false], 0, 0, 20)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true], 0, 0, 50)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_noop!( - Elections::present_winner(Origin::signed(4), 2, 20, 1), - Error::::InvalidVoteIndex - ); - }); -} - -#[test] -fn election_present_when_presenter_is_poor_should_not_work() { - let test_present = |p| { - ExtBuilder::default() - .voting_fee(5) - .voting_bond(2) - .bad_presentation_punishment(p) - .build() - .execute_with(|| { - System::set_block_number(4); - let _ = Balances::make_free_balance_be(&1, 15); - assert!(!Elections::presentation_active()); - - // -3 - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - assert_eq!(Balances::free_balance(1), 12); - // -2 -5 - assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0, 15)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_eq!(Balances::free_balance(1), 5); - assert_eq!(Balances::reserved_balance(1), 5); - if p > 5 { - assert_noop!( - Elections::present_winner(Origin::signed(1), 1, 10, 0), - Error::::InsufficientPresenterFunds, - ); - } else { - assert_ok!(Elections::present_winner(Origin::signed(1), 1, 10, 0)); - } - }); - }; - test_present(4); - test_present(6); -} - -#[test] -fn election_invalid_present_tally_should_slash() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert!(!Elections::presentation_active()); - assert_eq!(Balances::total_balance(&4), 40); - - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false], 0, 0, 20)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true], 0, 0, 50)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_err!( - Elections::present_winner(Origin::signed(4), 2, 80, 0), - Error::::IncorrectTotal - ); - - assert_eq!(Balances::total_balance(&4), 38); - }); -} - -#[test] -fn election_runners_up_should_be_kept() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert!(!Elections::presentation_active()); - - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0, 60)); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true], 0, 0, 20)); - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0, 30)); - assert_ok!(Elections::submit_candidacy(Origin::signed(4), 3)); - assert_ok!(Elections::set_approvals( - Origin::signed(4), - vec![false, false, false, true], - 0, - 0, - 40 - )); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 4)); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, false, false, false, true], - 0, - 0, - 50 - )); - - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Elections::presentation_active()); - assert_ok!(Elections::present_winner(Origin::signed(4), 1, 60, 0)); - // leaderboard length is the empty seats plus the carry count (i.e. 5 + 2), where those - // to be carried are the lowest and stored in lowest indices - assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (0, 0), (0, 0), (60, 1)])); - assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); - assert_eq!(Elections::leaderboard(), Some(vec![(30, 3), (40, 4), (50, 5), (60, 1)])); - - assert_ok!(Elections::end_block(System::block_number())); - - assert!(!Elections::presentation_active()); - assert_eq!(Elections::members(), vec![(1, 11), (5, 11)]); - - assert!(!Elections::is_a_candidate(&1)); - assert!(!Elections::is_a_candidate(&5)); - assert!(!Elections::is_a_candidate(&2)); - assert!(Elections::is_a_candidate(&3)); - assert!(Elections::is_a_candidate(&4)); - assert_eq!(Elections::vote_index(), 1); - assert_eq!( - Elections::voter_info(2), - Some(VoterInfo { last_win: 0, last_active: 0, stake: 20, pot: 0 }) - ); - assert_eq!( - Elections::voter_info(3), - Some(VoterInfo { last_win: 0, last_active: 0, stake: 30, pot: 0 }) - ); - assert_eq!( - Elections::voter_info(4), - Some(VoterInfo { last_win: 0, last_active: 0, stake: 40, pot: 0 }) - ); - assert_eq!( - Elections::voter_info(5), - Some(VoterInfo { last_win: 1, last_active: 0, stake: 50, pot: 0 }) - ); - assert_eq!( - Elections::voter_info(6), - Some(VoterInfo { last_win: 1, last_active: 0, stake: 60, pot: 0 }) - ); - assert_eq!(Elections::candidate_reg_info(3), Some((0, 2))); - assert_eq!(Elections::candidate_reg_info(4), Some((0, 3))); - }); -} - -#[test] -fn election_second_tally_should_use_runners_up() { - ExtBuilder::default().build().execute_with(|| { - System::set_block_number(4); - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0, 60)); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true], 0, 0, 20)); - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0, 30)); - assert_ok!(Elections::submit_candidacy(Origin::signed(4), 3)); - assert_ok!(Elections::set_approvals( - Origin::signed(4), - vec![false, false, false, true], - 0, - 0, - 40 - )); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 4)); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, false, false, false, true], - 0, - 0, - 50 - )); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Elections::present_winner(Origin::signed(4), 1, 60, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40, 0)); - assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Elections::set_approvals( - Origin::signed(6), - vec![false, false, true, false], - 1, - 0, - 60 - )); - assert_ok!(Elections::set_desired_seats(Origin::root(), 3)); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Elections::present_winner( - Origin::signed(4), - 3, - 30 + Elections::get_offset(30, 1) + 60, - 1 - )); - assert_ok!(Elections::present_winner( - Origin::signed(4), - 4, - 40 + Elections::get_offset(40, 1), - 1 - )); - assert_ok!(Elections::end_block(System::block_number())); - - assert!(!Elections::presentation_active()); - assert_eq!(Elections::members(), vec![(1, 11), (5, 11), (3, 15)]); - - assert!(!Elections::is_a_candidate(&1)); - assert!(!Elections::is_a_candidate(&2)); - assert!(!Elections::is_a_candidate(&3)); - assert!(!Elections::is_a_candidate(&5)); - assert!(Elections::is_a_candidate(&4)); - assert_eq!(Elections::vote_index(), 2); - assert_eq!( - Elections::voter_info(2), - Some(VoterInfo { last_win: 0, last_active: 0, stake: 20, pot: 0 }) - ); - assert_eq!( - Elections::voter_info(3), - Some(VoterInfo { last_win: 2, last_active: 0, stake: 30, pot: 0 }) - ); - assert_eq!( - Elections::voter_info(4), - Some(VoterInfo { last_win: 0, last_active: 0, stake: 40, pot: 0 }) - ); - assert_eq!( - Elections::voter_info(5), - Some(VoterInfo { last_win: 1, last_active: 0, stake: 50, pot: 0 }) - ); - assert_eq!( - Elections::voter_info(6), - Some(VoterInfo { last_win: 2, last_active: 1, stake: 60, pot: 0 }) - ); - - assert_eq!(Elections::candidate_reg_info(4), Some((0, 3))); - }); -} - -#[test] -fn election_loser_candidates_bond_gets_slashed() { - ExtBuilder::default().desired_seats(1).build().execute_with(|| { - System::set_block_number(4); - assert!(!Elections::presentation_active()); - - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Elections::submit_candidacy(Origin::signed(4), 3)); - - assert_eq!(balances(&2), (17, 3)); - - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 0, 0, 50)); - assert_ok!(Elections::set_approvals( - Origin::signed(1), - vec![false, true, true, true], - 0, - 0, - 10 - )); - - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(4), 4, 10, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(3), 3, 10, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(2), 2, 10, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(1), 1, 50, 0), Ok(())); - - // winner + carry - assert_eq!(Elections::leaderboard(), Some(vec![(10, 3), (10, 4), (50, 1)])); - assert_ok!(Elections::end_block(System::block_number())); - assert!(!Elections::presentation_active()); - assert_eq!(Elections::members(), vec![(1, 11)]); - - // account 2 is not a runner up or in leaderboard. - assert_eq!(balances(&2), (17, 0)); - }); -} - -#[test] -fn pot_accumulating_weight_and_decaying_should_work() { - ExtBuilder::default().balance_factor(10).build().execute_with(|| { - System::set_block_number(4); - assert!(!Elections::presentation_active()); - - assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 2)); - - assert_ok!(Elections::set_approvals( - Origin::signed(6), - vec![true, false, false], - 0, - 0, - 600 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, true, false], - 0, - 0, - 500 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(1), - vec![false, false, true], - 0, - 0, - 100 - )); - - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Elections::presentation_active()); - - assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(1), 1, 100, 0), Ok(())); - assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (100, 1), (500, 5), (600, 6)])); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(6, 11), (5, 11)]); - assert_eq!( - Elections::voter_info(6).unwrap(), - VoterInfo { last_win: 1, last_active: 0, stake: 600, pot: 0 }, - ); - assert_eq!( - Elections::voter_info(5).unwrap(), - VoterInfo { last_win: 1, last_active: 0, stake: 500, pot: 0 }, - ); - assert_eq!( - Elections::voter_info(1).unwrap(), - VoterInfo { last_win: 0, last_active: 0, stake: 100, pot: 0 }, - ); - - System::set_block_number(12); - // retract needed to unlock approval funds => submit candidacy again. - assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); - assert_ok!(Elections::retract_voter(Origin::signed(5), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::set_approvals( - Origin::signed(6), - vec![true, false, false], - 1, - 0, - 600 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, true, false], - 1, - 1, - 500 - )); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(14); - assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 1), Ok(())); - assert_eq!( - Elections::present_winner(Origin::signed(1), 1, 100 + Elections::get_offset(100, 1), 1), - Ok(()) - ); - assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (100 + 96, 1), (500, 5), (600, 6)])); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(6, 19), (5, 19)]); - assert_eq!( - Elections::voter_info(6).unwrap(), - VoterInfo { last_win: 2, last_active: 1, stake: 600, pot: 0 } - ); - assert_eq!( - Elections::voter_info(5).unwrap(), - VoterInfo { last_win: 2, last_active: 1, stake: 500, pot: 0 } - ); - assert_eq!( - Elections::voter_info(1).unwrap(), - VoterInfo { last_win: 0, last_active: 0, stake: 100, pot: 0 } - ); - - System::set_block_number(20); - assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); - assert_ok!(Elections::retract_voter(Origin::signed(5), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::set_approvals( - Origin::signed(6), - vec![true, false, false], - 2, - 0, - 600 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, true, false], - 2, - 1, - 500 - )); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(22); - assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 2), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 2), Ok(())); - assert_eq!( - Elections::present_winner(Origin::signed(1), 1, 100 + Elections::get_offset(100, 2), 2), - Ok(()) - ); - assert_eq!( - Elections::leaderboard(), - Some(vec![(0, 0), (100 + 96 + 93, 1), (500, 5), (600, 6)]) - ); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(6, 27), (5, 27)]); - assert_eq!( - Elections::voter_info(6).unwrap(), - VoterInfo { last_win: 3, last_active: 2, stake: 600, pot: 0 } - ); - assert_eq!( - Elections::voter_info(5).unwrap(), - VoterInfo { last_win: 3, last_active: 2, stake: 500, pot: 0 } - ); - assert_eq!( - Elections::voter_info(1).unwrap(), - VoterInfo { last_win: 0, last_active: 0, stake: 100, pot: 0 } - ); - - System::set_block_number(28); - assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); - assert_ok!(Elections::retract_voter(Origin::signed(5), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::set_approvals( - Origin::signed(6), - vec![true, false, false], - 3, - 0, - 600 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, true, false], - 3, - 1, - 500 - )); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(30); - assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 3), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 3), Ok(())); - assert_eq!( - Elections::present_winner(Origin::signed(1), 1, 100 + Elections::get_offset(100, 3), 3), - Ok(()) - ); - assert_eq!( - Elections::leaderboard(), - Some(vec![(0, 0), (100 + 96 + 93 + 90, 1), (500, 5), (600, 6)]) - ); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(6, 35), (5, 35)]); - assert_eq!( - Elections::voter_info(6).unwrap(), - VoterInfo { last_win: 4, last_active: 3, stake: 600, pot: 0 } - ); - assert_eq!( - Elections::voter_info(5).unwrap(), - VoterInfo { last_win: 4, last_active: 3, stake: 500, pot: 0 } - ); - assert_eq!( - Elections::voter_info(1).unwrap(), - VoterInfo { last_win: 0, last_active: 0, stake: 100, pot: 0 } - ); - }) -} - -#[test] -fn pot_winning_resets_accumulated_pot() { - ExtBuilder::default().balance_factor(10).build().execute_with(|| { - System::set_block_number(4); - assert!(!Elections::presentation_active()); - - assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(4), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Elections::submit_candidacy(Origin::signed(2), 3)); - - assert_ok!(Elections::set_approvals( - Origin::signed(6), - vec![true, false, false, false], - 0, - 0, - 600 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(4), - vec![false, true, false, false], - 0, - 1, - 400 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(3), - vec![false, false, true, true], - 0, - 2, - 300 - )); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(4), 4, 400, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(3), 3, 300, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(2), 2, 300, 0), Ok(())); - assert_eq!(Elections::leaderboard(), Some(vec![(300, 2), (300, 3), (400, 4), (600, 6)])); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(6, 11), (4, 11)]); - - System::set_block_number(12); - assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); - assert_ok!(Elections::retract_voter(Origin::signed(4), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(4), 1)); - assert_ok!(Elections::set_approvals( - Origin::signed(6), - vec![true, false, false, false], - 1, - 0, - 600 - )); - assert_ok!(Elections::set_approvals( - Origin::signed(4), - vec![false, true, false, false], - 1, - 1, - 400 - )); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(14); - assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(4), 4, 400, 1), Ok(())); - assert_eq!( - Elections::present_winner(Origin::signed(3), 3, 300 + Elections::get_offset(300, 1), 1), - Ok(()) - ); - assert_eq!( - Elections::present_winner(Origin::signed(2), 2, 300 + Elections::get_offset(300, 1), 1), - Ok(()) - ); - assert_eq!(Elections::leaderboard(), Some(vec![(400, 4), (588, 2), (588, 3), (600, 6)])); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(6, 19), (3, 19)]); - - System::set_block_number(20); - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(22); - // 2 will not get re-elected with 300 + 288, instead just 300. - // because one of 3's candidates (3) won in previous round - // 4 on the other hand will get extra weight since it was unlucky. - assert_eq!(Elections::present_winner(Origin::signed(3), 2, 300, 2), Ok(())); - assert_eq!( - Elections::present_winner(Origin::signed(4), 4, 400 + Elections::get_offset(400, 1), 2), - Ok(()) - ); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(4, 27), (2, 27)]); - }) -} - -#[test] -fn pot_resubmitting_approvals_stores_pot() { - ExtBuilder::default() - .voting_bond(0) - .voting_fee(0) - .balance_factor(10) - .build() - .execute_with(|| { - System::set_block_number(4); - assert!(!Elections::presentation_active()); - - assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 2)); - - assert_ok!(Elections::set_approvals( - Origin::signed(6), - vec![true, false, false], - 0, - 0, - 600 - ),); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, true, false], - 0, - 1, - 500 - ),); - assert_ok!(Elections::set_approvals( - Origin::signed(1), - vec![false, false, true], - 0, - 2, - 100 - ),); - - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Elections::presentation_active()); - - assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(1), 1, 100, 0), Ok(())); - assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (100, 1), (500, 5), (600, 6)])); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(6, 11), (5, 11)]); - - System::set_block_number(12); - assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); - assert_ok!(Elections::retract_voter(Origin::signed(5), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::set_approvals( - Origin::signed(6), - vec![true, false, false], - 1, - 0, - 600 - ),); - assert_ok!(Elections::set_approvals( - Origin::signed(5), - vec![false, true, false], - 1, - 1, - 500 - ),); - // give 1 some new high balance - let _ = Balances::make_free_balance_be(&1, 997); - assert_ok!(Elections::set_approvals( - Origin::signed(1), - vec![false, false, true], - 1, - 2, - 1000 - ),); - assert_eq!( - Elections::voter_info(1).unwrap(), - VoterInfo { - stake: 1000, // 997 + 3 which is candidacy bond. - pot: Elections::get_offset(100, 1), - last_active: 1, - last_win: 1, - } - ); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(6, 11), (5, 11)]); - - System::set_block_number(14); - assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 1), Ok(())); - assert_eq!( - Elections::present_winner(Origin::signed(1), 1, 1000 + 96 /* pot */, 1), - Ok(()), - ); - assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (500, 5), (600, 6), (1096, 1)])); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members(), vec![(1, 19), (6, 19)]); - }) -} - -#[test] -fn pot_get_offset_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Elections::get_offset(100, 0), 0); - assert_eq!(Elections::get_offset(100, 1), 96); - assert_eq!(Elections::get_offset(100, 2), 96 + 93); - assert_eq!(Elections::get_offset(100, 3), 96 + 93 + 90); - assert_eq!(Elections::get_offset(100, 4), 96 + 93 + 90 + 87); - // limit - assert_eq!(Elections::get_offset(100, 1000), 100 * 24); - - assert_eq!(Elections::get_offset(50_000_000_000, 0), 0); - assert_eq!(Elections::get_offset(50_000_000_000, 1), 48_000_000_000); - assert_eq!(Elections::get_offset(50_000_000_000, 2), 48_000_000_000 + 46_080_000_000); - assert_eq!( - Elections::get_offset(50_000_000_000, 3), - 48_000_000_000 + 46_080_000_000 + 44_236_800_000 - ); - assert_eq!( - Elections::get_offset(50_000_000_000, 4), - 48_000_000_000 + 46_080_000_000 + 44_236_800_000 + 42_467_328_000 - ); - // limit - assert_eq!(Elections::get_offset(50_000_000_000, 1000), 50_000_000_000 * 24); - }) -} - -#[test] -fn pot_get_offset_with_zero_decay() { - ExtBuilder::default().decay_ratio(0).build().execute_with(|| { - assert_eq!(Elections::get_offset(100, 0), 0); - assert_eq!(Elections::get_offset(100, 1), 0); - assert_eq!(Elections::get_offset(100, 2), 0); - assert_eq!(Elections::get_offset(100, 3), 0); - // limit - assert_eq!(Elections::get_offset(100, 1000), 0); - }) -} diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 25ff76f4d1514..2b443ff8e8dde 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -731,6 +731,16 @@ where Ok(()) } + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(self.validate(who, call, info, len).map(|_| ())?) + } + fn validate( &self, _who: &Self::AccountId, diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index 9812d35ffa074..ec728e791295c 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -233,7 +233,7 @@ pub mod pallet { // Retrieve sender of the transaction. let who = ensure_signed(origin)?; // Add the price to the on-chain list. - Self::add_price(who, price); + Self::add_price(Some(who), price); Ok(().into()) } @@ -262,7 +262,7 @@ pub mod pallet { // This ensures that the function can only be called via unsigned transaction. ensure_none(origin)?; // Add the price to the on-chain list, but mark it as coming from an empty address. - Self::add_price(Default::default(), price); + Self::add_price(None, price); // now increment the block number at which we expect next unsigned transaction. let current_block = >::block_number(); >::put(current_block + T::UnsignedInterval::get()); @@ -278,7 +278,7 @@ pub mod pallet { // This ensures that the function can only be called via unsigned transaction. ensure_none(origin)?; // Add the price to the on-chain list, but mark it as coming from an empty address. - Self::add_price(Default::default(), price_payload.price); + Self::add_price(None, price_payload.price); // now increment the block number at which we expect next unsigned transaction. let current_block = >::block_number(); >::put(current_block + T::UnsignedInterval::get()); @@ -291,7 +291,7 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Event generated when new price is accepted to contribute to the average. - NewPrice { price: u32, who: T::AccountId }, + NewPrice { price: u32, maybe_who: Option }, } #[pallet::validate_unsigned] @@ -641,7 +641,7 @@ impl Pallet { } /// Add new price to the list. - fn add_price(who: T::AccountId, price: u32) { + fn add_price(maybe_who: Option, price: u32) { log::info!("Adding to the average: {}", price); >::mutate(|prices| { const MAX_LEN: usize = 64; @@ -657,7 +657,7 @@ impl Pallet { .expect("The average is not empty, because it was just mutated; qed"); log::info!("Current average price is: {}", average); // here we are raising the NewPrice event - Self::deposit_event(Event::NewPrice { price, who }); + Self::deposit_event(Event::NewPrice { price, maybe_who }); } /// Calculate current average price. diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 9fb965784f186..d83c3c6df9eed 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -125,15 +125,19 @@ impl Config for Test { type UnsignedPriority = UnsignedPriority; } +fn test_pub() -> sp_core::sr25519::Public { + sp_core::sr25519::Public::from_raw([1u8; 32]) +} + #[test] fn it_aggregates_the_price() { sp_io::TestExternalities::default().execute_with(|| { assert_eq!(Example::average_price(), None); - assert_ok!(Example::submit_price(Origin::signed(Default::default()), 27)); + assert_ok!(Example::submit_price(Origin::signed(test_pub()), 27)); assert_eq!(Example::average_price(), Some(27)); - assert_ok!(Example::submit_price(Origin::signed(Default::default()), 43)); + assert_ok!(Example::submit_price(Origin::signed(test_pub()), 43)); assert_eq!(Example::average_price(), Some(35)); }); } diff --git a/frame/examples/parallel/src/lib.rs b/frame/examples/parallel/src/lib.rs index 51e022bed08b3..55714abb4827f 100644 --- a/frame/examples/parallel/src/lib.rs +++ b/frame/examples/parallel/src/lib.rs @@ -105,13 +105,13 @@ pub struct EnlistedParticipant { impl EnlistedParticipant { fn verify(&self, event_id: &[u8]) -> bool { - use sp_core::Public; + use sp_core::ByteArray; use sp_runtime::traits::Verify; match sp_core::sr25519::Signature::try_from(&self.signature[..]) { - Ok(signature) => { - let public = sp_core::sr25519::Public::from_slice(self.account.as_ref()); - signature.verify(event_id, &public) + Ok(signature) => match sp_core::sr25519::Public::from_slice(self.account.as_ref()) { + Err(()) => false, + Ok(signer) => signature.verify(event_id, &signer), }, _ => false, } diff --git a/frame/examples/parallel/src/tests.rs b/frame/examples/parallel/src/tests.rs index 5de9af878723a..1a841ca68184e 100644 --- a/frame/examples/parallel/src/tests.rs +++ b/frame/examples/parallel/src/tests.rs @@ -81,6 +81,14 @@ impl Config for Test { type Call = Call; } +fn test_pub(n: u8) -> sp_core::sr25519::Public { + sp_core::sr25519::Public::from_raw([n; 32]) +} + +fn test_origin(n: u8) -> Origin { + Origin::signed(test_pub(n)) +} + #[test] fn it_can_enlist() { use sp_core::Pair; @@ -91,8 +99,7 @@ fn it_can_enlist() { let event_name = b"test"; - Example::run_event(Origin::signed(Default::default()), event_name.to_vec()) - .expect("Failed to enlist"); + Example::run_event(test_origin(1), event_name.to_vec()).expect("Failed to enlist"); let participants = vec![ EnlistedParticipant { @@ -105,7 +112,7 @@ fn it_can_enlist() { }, ]; - Example::enlist_participants(Origin::signed(Default::default()), participants) + Example::enlist_participants(Origin::signed(test_pub(1)), participants) .expect("Failed to enlist"); assert_eq!(Example::participants().len(), 2); @@ -123,8 +130,7 @@ fn one_wrong_will_not_enlist_anyone() { let event_name = b"test"; - Example::run_event(Origin::signed(Default::default()), event_name.to_vec()) - .expect("Failed to enlist"); + Example::run_event(test_origin(1), event_name.to_vec()).expect("Failed to enlist"); let participants = vec![ EnlistedParticipant { @@ -142,8 +148,7 @@ fn one_wrong_will_not_enlist_anyone() { }, ]; - Example::enlist_participants(Origin::signed(Default::default()), participants) - .expect("Failed to enlist"); + Example::enlist_participants(test_origin(1), participants).expect("Failed to enlist"); assert_eq!(Example::participants().len(), 0); }); diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 8a23ce6e1ef1e..77e38cb63b7dc 100644 --- a/frame/grandpa/src/equivocation.rs +++ b/frame/grandpa/src/equivocation.rs @@ -185,7 +185,7 @@ where } fn block_author() -> Option { - Some(>::author()) + >::author() } } diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index dbae5ed96d58a..3499078149f2e 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -324,7 +324,6 @@ pub mod pallet { type AuthorityId: Member + Parameter + RuntimeAppPublic - + Default + Ord + MaybeSerializeDeserialize + MaxEncodedLen; diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 1d985b9007ea9..3168f60ce022f 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -106,7 +106,15 @@ impl ReportOffence for OffenceHandler { pub fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - t.into() + let mut result: sp_io::TestExternalities = t.into(); + // Set the default keys, otherwise session will discard the validator. + result.execute_with(|| { + for i in 1..=6 { + System::inc_providers(&i); + assert_eq!(Session::set_keys(Origin::signed(i), (i - 1).into(), vec![]), Ok(())); + } + }); + result } parameter_types! { diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 757a99b42dae8..c02efdc0d3712 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -64,7 +64,7 @@ use frame_system::{self as system, RawOrigin}; use scale_info::TypeInfo; use sp_io::hashing::blake2_256; use sp_runtime::{ - traits::{Dispatchable, Zero}, + traits::{Dispatchable, TrailingZeroInput, Zero}, DispatchError, }; use sp_std::prelude::*; @@ -508,7 +508,8 @@ impl Pallet { /// NOTE: `who` must be sorted. If it is not, then you'll get the wrong answer. pub fn multi_account_id(who: &[T::AccountId], threshold: u16) -> T::AccountId { let entropy = (b"modlpy/utilisuba", who, threshold).using_encoded(blake2_256); - T::AccountId::decode(&mut &entropy[..]).unwrap_or_default() + Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) + .expect("infinite length input; no invalid inputs for type; qed") } fn operate( diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 695fa077f98d5..fefc66554f450 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -45,7 +45,7 @@ use frame_system::{self as system}; use scale_info::TypeInfo; use sp_io::hashing::blake2_256; use sp_runtime::{ - traits::{Dispatchable, Hash, Saturating, Zero}, + traits::{Dispatchable, Hash, Saturating, TrailingZeroInput, Zero}, DispatchResult, }; use sp_std::{convert::TryInto, prelude::*}; @@ -653,7 +653,8 @@ impl Pallet { }); let entropy = (b"modlpy/proxy____", who, height, ext_index, proxy_type, index) .using_encoded(blake2_256); - T::AccountId::decode(&mut &entropy[..]).unwrap_or_default() + Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) + .expect("infinite length input; no invalid inputs for type; qed") } /// Register a proxy account for the delegator that is able to make calls on its behalf. diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index 6d9d81f385176..4e0e51b76fe18 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -22,7 +22,7 @@ mod mock; -use sp_runtime::traits::{One, StaticLookup}; +use sp_runtime::traits::{One, StaticLookup, TrailingZeroInput}; use sp_std::{prelude::*, vec}; use frame_benchmarking::benchmarks; @@ -61,7 +61,8 @@ benchmarks! { RewardDestination::Staked, )?; let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; - let keys = T::Keys::default(); + + let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap(); let proof: Vec = vec![0,1,2,3]; // Whitelist controller account from further DB operations. let v_controller_key = frame_system::Account::::hashed_key_for(&v_controller); @@ -77,7 +78,7 @@ benchmarks! { RewardDestination::Staked )?; let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; - let keys = T::Keys::default(); + let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap(); let proof: Vec = vec![0,1,2,3]; Session::::set_keys(RawOrigin::Signed(v_controller.clone()).into(), keys, proof)?; // Whitelist controller account from further DB operations. diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index f56d282c0f111..0f80494550849 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -312,8 +312,10 @@ impl SessionHandler for Tuple { for_tuples!( #( let our_keys: Box> = Box::new(validators.iter() - .map(|k| (&k.0, k.1.get::(::ID) - .unwrap_or_default()))); + .filter_map(|k| + k.1.get::(::ID).map(|k1| (&k.0, k1)) + ) + ); Tuple::on_genesis_session(our_keys); )* @@ -328,11 +330,13 @@ impl SessionHandler for Tuple { for_tuples!( #( let our_keys: Box> = Box::new(validators.iter() - .map(|k| (&k.0, k.1.get::(::ID) - .unwrap_or_default()))); + .filter_map(|k| + k.1.get::(::ID).map(|k1| (&k.0, k1)) + )); let queued_keys: Box> = Box::new(queued_validators.iter() - .map(|k| (&k.0, k.1.get::(::ID) - .unwrap_or_default()))); + .filter_map(|k| + k.1.get::(::ID).map(|k1| (&k.0, k1)) + )); Tuple::on_new_session(changed, our_keys, queued_keys); )* ) @@ -403,7 +407,7 @@ pub mod pallet { type SessionHandler: SessionHandler; /// The keys. - type Keys: OpaqueKeys + Member + Parameter + Default + MaybeSerializeDeserialize; + type Keys: OpaqueKeys + Member + Parameter + MaybeSerializeDeserialize; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -476,13 +480,18 @@ pub mod pallet { let queued_keys: Vec<_> = initial_validators_1 .iter() .cloned() - .map(|v| (v.clone(), >::load_keys(&v).unwrap_or_default())) + .filter_map(|v| { + Some(( + v.clone(), + Pallet::::load_keys(&v).expect("Validator in session 1 missing keys!"), + )) + }) .collect(); // Tell everyone about the genesis session keys T::SessionHandler::on_genesis_session::(&queued_keys); - >::put(initial_validators_0); + Validators::::put(initial_validators_0); >::put(queued_keys); T::SessionManager::start_session(0); @@ -641,7 +650,7 @@ impl Pallet { let session_keys = >::get(); let validators = session_keys.iter().map(|(validator, _)| validator.clone()).collect::>(); - >::put(&validators); + Validators::::put(&validators); if changed { // reset disabled validators @@ -663,7 +672,7 @@ impl Pallet { // same as before, as underlying economic conditions may have changed. (validators, true) } else { - (>::get(), false) + (Validators::::get(), false) }; // Queue next session keys. @@ -689,10 +698,10 @@ impl Pallet { }; let queued_amalgamated = next_validators .into_iter() - .map(|a| { - let k = Self::load_keys(&a).unwrap_or_default(); + .filter_map(|a| { + let k = Self::load_keys(&a)?; check_next_changed(&k); - (a, k) + Some((a, k)) }) .collect::>(); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 5b242e1f223a8..f96b7fd2f37bc 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -21,6 +21,7 @@ use super::*; use crate::Pallet as Staking; use testing_utils::*; +use codec::Decode; use frame_election_provider_support::SortedListProvider; use frame_support::{ dispatch::UnfilteredDispatchable, @@ -28,7 +29,7 @@ use frame_support::{ traits::{Currency, CurrencyToVote, Get, Imbalance}, }; use sp_runtime::{ - traits::{Bounded, One, StaticLookup, Zero}, + traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero}, Perbill, Percent, }; use sp_staking::SessionIndex; @@ -535,8 +536,9 @@ benchmarks! { let s in 1 .. MAX_SLASHES; let mut unapplied_slashes = Vec::new(); let era = EraIndex::one(); + let dummy = || T::AccountId::decode(&mut TrailingZeroInput::zeroes()).unwrap(); for _ in 0 .. MAX_SLASHES { - unapplied_slashes.push(UnappliedSlash::>::default()); + unapplied_slashes.push(UnappliedSlash::>::default_from(dummy())); } UnappliedSlashes::::insert(era, &unapplied_slashes); @@ -667,10 +669,11 @@ benchmarks! { let e in 1 .. 100; HistoryDepth::::put(e); CurrentEra::::put(e); + let dummy = || -> T::AccountId { codec::Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap() }; for i in 0 .. e { - >::insert(i, T::AccountId::default(), Exposure::>::default()); - >::insert(i, T::AccountId::default(), Exposure::>::default()); - >::insert(i, T::AccountId::default(), ValidatorPrefs::default()); + >::insert(i, dummy(), Exposure::>::default()); + >::insert(i, dummy(), Exposure::>::default()); + >::insert(i, dummy(), ValidatorPrefs::default()); >::insert(i, BalanceOf::::one()); >::insert(i, EraRewardPoints::::default()); >::insert(i, BalanceOf::::one()); @@ -695,7 +698,14 @@ benchmarks! { let stash = scenario.origin_stash1.clone(); add_slashing_spans::(&stash, s); - Ledger::::insert(&controller, StakingLedger { active: T::Currency::minimum_balance() - One::one(), total: T::Currency::minimum_balance() - One::one(), ..Default::default() }); + let l = StakingLedger { + stash: stash.clone(), + active: T::Currency::minimum_balance() - One::one(), + total: T::Currency::minimum_balance() - One::one(), + unlocking: vec![], + claimed_rewards: vec![], + }; + Ledger::::insert(&controller, l); assert!(Bonded::::contains_key(&stash)); assert!(T::SortedListProvider::contains(&stash)); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index f2e5f0f783895..7bc3ac8aa7075 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -364,7 +364,7 @@ pub struct ActiveEraInfo { /// Reward points of an era. Used to split era total payout between validators. /// /// This points will be used to reward validators and their respective nominators. -#[derive(PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct EraRewardPoints { /// Total number of points. Equals the sum of reward points for each validator. total: RewardPoint, @@ -372,9 +372,15 @@ pub struct EraRewardPoints { individual: BTreeMap, } +impl Default for EraRewardPoints { + fn default() -> Self { + EraRewardPoints { total: Default::default(), individual: BTreeMap::new() } + } +} + /// Indicates the initial status of the staker. #[derive(RuntimeDebug, TypeInfo)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, Clone))] pub enum StakerStatus { /// Chilling. Idle, @@ -436,7 +442,6 @@ pub struct UnlockChunk { } /// The ledger of a (bonded) stash. -#[cfg_attr(feature = "runtime-benchmarks", derive(Default))] #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct StakingLedger { /// The stash account whose balance is actually locked and at stake. @@ -457,9 +462,20 @@ pub struct StakingLedger { pub claimed_rewards: Vec, } -impl +impl StakingLedger { + /// Initializes the default object using the given `validator`. + pub fn default_from(stash: AccountId) -> Self { + Self { + stash, + total: Zero::zero(), + active: Zero::zero(), + unlocking: vec![], + claimed_rewards: vec![], + } + } + /// Remove entries from `unlocking` that are sufficiently old and reduce the /// total by the sum of their balances. fn consolidate_unlocked(self, current_era: EraIndex) -> Self { @@ -593,9 +609,7 @@ pub struct IndividualExposure { } /// A snapshot of the stake backing a single validator in the system. -#[derive( - PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default, RuntimeDebug, TypeInfo, -)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct Exposure { /// The total balance backing this validator. #[codec(compact)] @@ -607,9 +621,15 @@ pub struct Exposure { pub others: Vec>, } +impl Default for Exposure { + fn default() -> Self { + Self { total: Default::default(), own: Default::default(), others: vec![] } + } +} + /// A pending slash record. The value of the slash has been computed but not applied yet, /// rather deferred for several eras. -#[derive(Encode, Decode, Default, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] pub struct UnappliedSlash { /// The stash ID of the offending validator. validator: AccountId, @@ -623,6 +643,19 @@ pub struct UnappliedSlash { payout: Balance, } +impl UnappliedSlash { + /// Initializes the default object using the given `validator`. + pub fn default_from(validator: AccountId) -> Self { + Self { + validator, + own: Zero::zero(), + others: vec![], + reporters: vec![], + payout: Zero::zero(), + } + } +} + /// Means for interacting with a specialized version of the `session` trait. /// /// This is needed because `Staking` sets the `ValidatorIdOf` of the `pallet_session::Config` diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 89ab86259b95f..f6e2ce0e4bc18 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -480,7 +480,7 @@ impl ExtBuilder { } let _ = pallet_staking::GenesisConfig:: { - stakers, + stakers: stakers.clone(), validator_count: self.validator_count, minimum_validator_count: self.minimum_validator_count, invulnerables: self.invulnerables, @@ -493,12 +493,15 @@ impl ExtBuilder { let _ = pallet_session::GenesisConfig:: { keys: if self.has_stakers { - // genesis election will overwrite this, no worries. - Default::default() + // set the keys for the first session. + stakers + .into_iter() + .map(|(id, ..)| (id, id, SessionKeys { other: id.into() })) + .collect() } else { // set some dummy validators in genesis. (0..self.validator_count as u64) - .map(|x| (x, x, SessionKeys { other: UintAuthorityId(x as u64) })) + .map(|id| (id, id, SessionKeys { other: id.into() })) .collect() }, } @@ -644,6 +647,7 @@ pub(crate) fn bond(stash: AccountId, ctrl: AccountId, val: Balance) { pub(crate) fn bond_validator(stash: AccountId, ctrl: AccountId, val: Balance) { bond(stash, ctrl, val); assert_ok!(Staking::validate(Origin::signed(ctrl), ValidatorPrefs::default())); + assert_ok!(Session::set_keys(Origin::signed(ctrl), SessionKeys { other: ctrl.into() }, vec![])); } pub(crate) fn bond_nominator( diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index b3158c4ef6b3d..6c11e942106a7 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1089,8 +1089,13 @@ where fn note_author(author: T::AccountId) { Self::reward_by_ids(vec![(author, 20)]) } - fn note_uncle(author: T::AccountId, _age: T::BlockNumber) { - Self::reward_by_ids(vec![(>::author(), 2), (author, 1)]) + fn note_uncle(uncle_author: T::AccountId, _age: T::BlockNumber) { + // defensive-only: block author must exist. + if let Some(block_author) = >::author() { + Self::reward_by_ids(vec![(block_author, 2), (uncle_author, 1)]) + } else { + crate::log!(warn, "block author not set, this should never happen"); + } } } @@ -1238,8 +1243,13 @@ impl VoteWeightProvider for Pallet { // this will clearly results in an inconsistent state, but it should not matter for a // benchmark. let active: BalanceOf = weight.try_into().map_err(|_| ()).unwrap(); - let mut ledger = Self::ledger(who).unwrap_or_default(); - ledger.active = active; + let ledger = match Self::ledger(who) { + None => StakingLedger::default_from(who.clone()), + Some(mut l) => { + l.active = active; + l + }, + }; >::insert(who, ledger); >::insert(who, who); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index ec8be43f02841..aa806d4a15e2c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -217,16 +217,17 @@ fn rewards_should_work() { Payee::::insert(21, RewardDestination::Controller); Payee::::insert(101, RewardDestination::Controller); - >::reward_by_ids(vec![(11, 50)]); - >::reward_by_ids(vec![(11, 50)]); + Pallet::::reward_by_ids(vec![(11, 50)]); + Pallet::::reward_by_ids(vec![(11, 50)]); // This is the second validator of the current elected set. - >::reward_by_ids(vec![(21, 50)]); + Pallet::::reward_by_ids(vec![(21, 50)]); // Compute total payout now for whole duration of the session. let total_payout_0 = current_total_payout_for_duration(reward_time_per_era()); let maximum_payout = maximum_payout_for_duration(reward_time_per_era()); start_session(1); + assert_eq_uvec!(Session::validators(), vec![11, 21]); assert_eq!(Balances::total_balance(&10), init_balance_10); assert_eq!(Balances::total_balance(&11), init_balance_11); @@ -234,7 +235,6 @@ fn rewards_should_work() { assert_eq!(Balances::total_balance(&21), init_balance_21); assert_eq!(Balances::total_balance(&100), init_balance_100); assert_eq!(Balances::total_balance(&101), init_balance_101); - assert_eq_uvec!(Session::validators(), vec![11, 21]); assert_eq!( Staking::eras_reward_points(active_era()), EraRewardPoints { @@ -283,7 +283,7 @@ fn rewards_should_work() { assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2); assert_eq_uvec!(Session::validators(), vec![11, 21]); - >::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(11, 1)]); // Compute total payout now for whole duration as other parameter won't change let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); @@ -338,6 +338,7 @@ fn staking_should_work() { // add a new candidate for being a validator. account 3 controlled by 4. assert_ok!(Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller)); assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); + assert_ok!(Session::set_keys(Origin::signed(4), SessionKeys { other: 4.into() }, vec![])); // No effects will be seen so far. assert_eq_uvec!(validator_controllers(), vec![20, 10]); @@ -519,8 +520,8 @@ fn nominating_and_rewards_should_work() { // the total reward for era 0 let total_payout_0 = current_total_payout_for_duration(reward_time_per_era()); - >::reward_by_ids(vec![(41, 1)]); - >::reward_by_ids(vec![(21, 1)]); + Pallet::::reward_by_ids(vec![(41, 1)]); + Pallet::::reward_by_ids(vec![(21, 1)]); mock::start_active_era(1); @@ -561,8 +562,8 @@ fn nominating_and_rewards_should_work() { // the total reward for era 1 let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); - >::reward_by_ids(vec![(21, 2)]); - >::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(21, 2)]); + Pallet::::reward_by_ids(vec![(11, 1)]); mock::start_active_era(2); @@ -942,7 +943,7 @@ fn reward_destination_works() { // Compute total payout now for whole duration as other parameter won't change let total_payout_0 = current_total_payout_for_duration(reward_time_per_era()); - >::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(11, 1)]); mock::start_active_era(1); mock::make_all_reward_payment(0); @@ -968,7 +969,7 @@ fn reward_destination_works() { // Compute total payout now for whole duration as other parameter won't change let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); - >::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(11, 1)]); mock::start_active_era(2); mock::make_all_reward_payment(1); @@ -999,7 +1000,7 @@ fn reward_destination_works() { // Compute total payout now for whole duration as other parameter won't change let total_payout_2 = current_total_payout_for_duration(reward_time_per_era()); - >::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(11, 1)]); mock::start_active_era(3); mock::make_all_reward_payment(2); @@ -1049,7 +1050,7 @@ fn validator_payment_prefs_work() { // Compute total payout now for whole duration as other parameter won't change let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); let exposure_1 = Staking::eras_stakers(active_era(), 11); - >::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(11, 1)]); mock::start_active_era(2); mock::make_all_reward_payment(1); @@ -1610,8 +1611,8 @@ fn reward_to_stake_works() { // Compute total payout now for whole duration as other parameter won't change let total_payout_0 = current_total_payout_for_duration(reward_time_per_era()); - >::reward_by_ids(vec![(11, 1)]); - >::reward_by_ids(vec![(21, 1)]); + Pallet::::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(21, 1)]); // New era --> rewards are paid --> stakes are changed mock::start_active_era(1); @@ -1707,6 +1708,7 @@ fn switching_roles() { // add a new validator candidate assert_ok!(Staking::bond(Origin::signed(5), 6, 1000, RewardDestination::Controller)); assert_ok!(Staking::validate(Origin::signed(6), ValidatorPrefs::default())); + assert_ok!(Session::set_keys(Origin::signed(6), SessionKeys { other: 6.into() }, vec![])); mock::start_active_era(1); @@ -1715,6 +1717,7 @@ fn switching_roles() { // 2 decides to be a validator. Consequences: assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); + assert_ok!(Session::set_keys(Origin::signed(2), SessionKeys { other: 2.into() }, vec![])); // new stakes: // 10: 1000 self vote // 20: 1000 self vote + 250 vote @@ -1819,6 +1822,11 @@ fn bond_with_little_staked_value_bounded() { // Stingy validator. assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller)); assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); + assert_ok!(Session::set_keys( + Origin::signed(2), + SessionKeys { other: 2.into() }, + vec![] + )); // 1 era worth of reward. BUT, we set the timestamp after on_initialize, so outdated by // one block. @@ -2051,12 +2059,12 @@ fn reward_from_authorship_event_handler_works() { ExtBuilder::default().build_and_execute(|| { use pallet_authorship::EventHandler; - assert_eq!(>::author(), 11); + assert_eq!(>::author(), Some(11)); - >::note_author(11); - >::note_uncle(21, 1); + Pallet::::note_author(11); + Pallet::::note_uncle(21, 1); // Rewarding the same two times works. - >::note_uncle(11, 1); + Pallet::::note_uncle(11, 1); // Not mandatory but must be coherent with rewards assert_eq_uvec!(Session::validators(), vec![11, 21]); @@ -2079,9 +2087,9 @@ fn add_reward_points_fns_works() { // Not mandatory but must be coherent with rewards assert_eq_uvec!(Session::validators(), vec![21, 11]); - >::reward_by_ids(vec![(21, 1), (11, 1), (11, 1)]); + Pallet::::reward_by_ids(vec![(21, 1), (11, 1), (11, 1)]); - >::reward_by_ids(vec![(21, 1), (11, 1), (11, 1)]); + Pallet::::reward_by_ids(vec![(21, 1), (11, 1), (11, 1)]); assert_eq!( ErasRewardPoints::::get(active_era()), @@ -3091,13 +3099,13 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { Payee::::insert(11, RewardDestination::Controller); Payee::::insert(101, RewardDestination::Controller); - >::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(11, 1)]); // Compute total payout now for whole duration as other parameter won't change let total_payout_0 = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(1); - >::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(11, 1)]); // Change total issuance in order to modify total payout let _ = Balances::deposit_creating(&999, 1_000_000_000); // Compute total payout now for whole duration as other parameter won't change @@ -3106,7 +3114,7 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { mock::start_active_era(2); - >::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(11, 1)]); // Change total issuance in order to modify total payout let _ = Balances::deposit_creating(&999, 1_000_000_000); // Compute total payout now for whole duration as other parameter won't change @@ -3266,7 +3274,7 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( } mock::start_active_era(1); - >::reward_by_ids(vec![(11, 1)]); + Pallet::::reward_by_ids(vec![(11, 1)]); // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index de3b3439bc344..b6255da1d1c46 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -146,7 +146,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; - ensure!(sender == Self::key(), Error::::RequireSudo); + ensure!(Self::key().map_or(false, |k| sender == k), Error::::RequireSudo); let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) }); @@ -172,7 +172,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; - ensure!(sender == Self::key(), Error::::RequireSudo); + ensure!(Self::key().map_or(false, |k| sender == k), Error::::RequireSudo); let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) }); @@ -197,11 +197,11 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; - ensure!(sender == Self::key(), Error::::RequireSudo); + ensure!(Self::key().map_or(false, |k| sender == k), Error::::RequireSudo); let new = T::Lookup::lookup(new)?; - Self::deposit_event(Event::KeyChanged { new_sudoer: Self::key() }); - >::put(new); + Self::deposit_event(Event::KeyChanged { old_sudoer: Key::::get() }); + Key::::put(&new); // Sudo user does not pay a fee. Ok(Pays::No.into()) } @@ -234,7 +234,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; - ensure!(sender == Self::key(), Error::::RequireSudo); + ensure!(Self::key().map_or(false, |k| sender == k), Error::::RequireSudo); let who = T::Lookup::lookup(who)?; @@ -253,8 +253,8 @@ pub mod pallet { pub enum Event { /// A sudo just took place. \[result\] Sudid { sudo_result: DispatchResult }, - /// The \[sudoer\] just switched identity; the old key is supplied. - KeyChanged { new_sudoer: T::AccountId }, + /// The \[sudoer\] just switched identity; the old key is supplied if one existed. + KeyChanged { old_sudoer: Option }, /// A sudo just took place. \[result\] SudoAsDone { sudo_result: DispatchResult }, } @@ -269,25 +269,27 @@ pub mod pallet { /// The `AccountId` of the sudo key. #[pallet::storage] #[pallet::getter(fn key)] - pub(super) type Key = StorageValue<_, T::AccountId, ValueQuery>; + pub(super) type Key = StorageValue<_, T::AccountId, OptionQuery>; #[pallet::genesis_config] pub struct GenesisConfig { /// The `AccountId` of the sudo key. - pub key: T::AccountId, + pub key: Option, } #[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { - Self { key: Default::default() } + Self { key: None } } } #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - >::put(&self.key); + if let Some(ref key) = self.key { + Key::::put(key); + } } } } diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index 88379d0e5fda8..408cccc7de21d 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -165,7 +165,7 @@ pub type LoggerCall = logger::Call; // Build test environment by setting the root `key` for the Genesis. pub fn new_test_ext(root_key: u64) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - sudo::GenesisConfig:: { key: root_key } + sudo::GenesisConfig:: { key: Some(root_key) } .assimilate_storage(&mut t) .unwrap(); t.into() diff --git a/frame/sudo/src/tests.rs b/frame/sudo/src/tests.rs index 3fd199a1c8ca3..8821879061677 100644 --- a/frame/sudo/src/tests.rs +++ b/frame/sudo/src/tests.rs @@ -28,7 +28,7 @@ use mock::{ fn test_setup_works() { // Environment setup, logger storage, and sudo `key` retrieval should work as expected. new_test_ext(1).execute_with(|| { - assert_eq!(Sudo::key(), 1u64); + assert_eq!(Sudo::key(), Some(1u64)); assert!(Logger::i32_log().is_empty()); assert!(Logger::account_log().is_empty()); }); @@ -105,7 +105,7 @@ fn set_key_basics() { new_test_ext(1).execute_with(|| { // A root `key` can change the root `key` assert_ok!(Sudo::set_key(Origin::signed(1), 2)); - assert_eq!(Sudo::key(), 2u64); + assert_eq!(Sudo::key(), Some(2u64)); }); new_test_ext(1).execute_with(|| { @@ -123,10 +123,10 @@ fn set_key_emits_events_correctly() { // A root `key` can change the root `key`. assert_ok!(Sudo::set_key(Origin::signed(1), 2)); - System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { new_sudoer: 1 })); + System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old_sudoer: Some(1) })); // Double check. assert_ok!(Sudo::set_key(Origin::signed(2), 4)); - System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { new_sudoer: 2 })); + System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old_sudoer: Some(2) })); }); } diff --git a/frame/support/src/traits/validation.rs b/frame/support/src/traits/validation.rs index 674f2d718fffa..e5c81a149e4d0 100644 --- a/frame/support/src/traits/validation.rs +++ b/frame/support/src/traits/validation.rs @@ -77,7 +77,7 @@ pub trait VerifySeal { /// A session handler for specific key type. pub trait OneSessionHandler: BoundToRuntimeAppPublic { /// The key type expected. - type Key: Decode + Default + RuntimeAppPublic; + type Key: Decode + RuntimeAppPublic; /// The given validator set will be used for the genesis session. /// It is guaranteed that the given validator set will also be used diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 2d14da04f64b7..b2717b0f095ca 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -229,6 +229,10 @@ pub type AccountId = ::Signer; pub type BlockNumber = u64; pub type Index = u64; +fn test_pub() -> AccountId { + AccountId::from_raw([0; 32]) +} + impl system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Hash = H256; @@ -451,13 +455,13 @@ fn event_codec() { let event = system::Event::::ExtrinsicSuccess; assert_eq!(Event::from(event).encode()[0], 30); - let event = module1::Event::::A(Default::default()); + let event = module1::Event::::A(test_pub()); assert_eq!(Event::from(event).encode()[0], 31); let event = module2::Event::A; assert_eq!(Event::from(event).encode()[0], 32); - let event = module1::Event::::A(Default::default()); + let event = module1::Event::::A(test_pub()); assert_eq!(Event::from(event).encode()[0], 33); let event = nested::module3::Event::A; @@ -466,19 +470,19 @@ fn event_codec() { let event = module3::Event::A; assert_eq!(Event::from(event).encode()[0], 35); - let event = module1::Event::::A(Default::default()); + let event = module1::Event::::A(test_pub()); assert_eq!(Event::from(event).encode()[0], 4); - let event = module1::Event::::A(Default::default()); + let event = module1::Event::::A(test_pub()); assert_eq!(Event::from(event).encode()[0], 1); - let event = module1::Event::::A(Default::default()); + let event = module1::Event::::A(test_pub()); assert_eq!(Event::from(event).encode()[0], 2); - let event = module1::Event::::A(Default::default()); + let event = module1::Event::::A(test_pub()); assert_eq!(Event::from(event).encode()[0], 12); - let event = module1::Event::::A(Default::default()); + let event = module1::Event::::A(test_pub()); assert_eq!(Event::from(event).encode()[0], 13); } diff --git a/frame/system/src/extensions/check_genesis.rs b/frame/system/src/extensions/check_genesis.rs index 9c5c890ee6098..c758f9b6cb6ee 100644 --- a/frame/system/src/extensions/check_genesis.rs +++ b/frame/system/src/extensions/check_genesis.rs @@ -19,7 +19,7 @@ use crate::{Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{SignedExtension, Zero}, + traits::{DispatchInfoOf, SignedExtension, Zero}, transaction_validity::TransactionValidityError, }; @@ -62,4 +62,14 @@ impl SignedExtension for CheckGenesis { fn additional_signed(&self) -> Result { Ok(>::block_hash(T::BlockNumber::zero())) } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(self.validate(who, call, info, len).map(|_| ())?) + } } diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index 941f28dc6fc63..140a06298df33 100644 --- a/frame/system/src/extensions/check_mortality.rs +++ b/frame/system/src/extensions/check_mortality.rs @@ -85,6 +85,16 @@ impl SignedExtension for CheckMortality { Ok(>::block_hash(n)) } } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(self.validate(who, call, info, len).map(|_| ())?) + } } #[cfg(test)] diff --git a/frame/system/src/extensions/check_non_zero_sender.rs b/frame/system/src/extensions/check_non_zero_sender.rs index 1d45ae17cb7ac..349bc0bede0d8 100644 --- a/frame/system/src/extensions/check_non_zero_sender.rs +++ b/frame/system/src/extensions/check_non_zero_sender.rs @@ -65,6 +65,16 @@ where Ok(()) } + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(self.validate(who, call, info, len).map(|_| ())?) + } + fn validate( &self, who: &Self::AccountId, diff --git a/frame/system/src/extensions/check_spec_version.rs b/frame/system/src/extensions/check_spec_version.rs index 688abe99763a2..1e1a31d4d870d 100644 --- a/frame/system/src/extensions/check_spec_version.rs +++ b/frame/system/src/extensions/check_spec_version.rs @@ -18,7 +18,10 @@ use crate::{Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_runtime::{traits::SignedExtension, transaction_validity::TransactionValidityError}; +use sp_runtime::{ + traits::{DispatchInfoOf, SignedExtension}, + transaction_validity::TransactionValidityError, +}; /// Ensure the runtime version registered in the transaction is the same as at present. /// @@ -59,4 +62,14 @@ impl SignedExtension for CheckSpecVersion { fn additional_signed(&self) -> Result { Ok(>::runtime_version().spec_version) } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(self.validate(who, call, info, len).map(|_| ())?) + } } diff --git a/frame/system/src/extensions/check_tx_version.rs b/frame/system/src/extensions/check_tx_version.rs index f6bb53e1cba34..e1e7b070e831d 100644 --- a/frame/system/src/extensions/check_tx_version.rs +++ b/frame/system/src/extensions/check_tx_version.rs @@ -18,7 +18,10 @@ use crate::{Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_runtime::{traits::SignedExtension, transaction_validity::TransactionValidityError}; +use sp_runtime::{ + traits::{DispatchInfoOf, SignedExtension}, + transaction_validity::TransactionValidityError, +}; /// Ensure the transaction version registered in the transaction is the same as at present. /// @@ -59,4 +62,13 @@ impl SignedExtension for CheckTxVersion { fn additional_signed(&self) -> Result { Ok(>::runtime_version().transaction_version) } + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(self.validate(who, call, info, len).map(|_| ())?) + } } diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index ca885accd660f..8f83b7594cb5b 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -223,7 +223,7 @@ where } fn post_dispatch( - _pre: Self::Pre, + _pre: Option, info: &DispatchInfoOf, post_info: &PostDispatchInfoOf, _len: usize, @@ -563,7 +563,13 @@ mod tests { let pre = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap(); assert_eq!(BlockWeight::::get().total(), info.weight + 256); - assert_ok!(CheckWeight::::post_dispatch(pre, &info, &post_info, len, &Ok(()))); + assert_ok!(CheckWeight::::post_dispatch( + Some(pre), + &info, + &post_info, + len, + &Ok(()) + )); assert_eq!(BlockWeight::::get().total(), post_info.actual_weight.unwrap() + 256); }) } @@ -587,7 +593,13 @@ mod tests { info.weight + 128 + block_weights().get(DispatchClass::Normal).base_extrinsic, ); - assert_ok!(CheckWeight::::post_dispatch(pre, &info, &post_info, len, &Ok(()))); + assert_ok!(CheckWeight::::post_dispatch( + Some(pre), + &info, + &post_info, + len, + &Ok(()) + )); assert_eq!( BlockWeight::::get().total(), info.weight + 128 + block_weights().get(DispatchClass::Normal).base_extrinsic, diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index f62d60f6fda93..6bdaf8bd4b505 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -238,7 +238,6 @@ pub mod pallet { + Debug + MaybeDisplay + Ord - + Default + MaxEncodedLen; /// Converting trait to take a source type and convert to `AccountId`. diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index 0d2a56520a154..5edb5f042a61d 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -61,7 +61,7 @@ pub mod migrations; pub mod weights; use sp_runtime::{ - traits::{AccountIdConversion, BadOrigin, Hash, Zero}, + traits::{AccountIdConversion, BadOrigin, Hash, TrailingZeroInput, Zero}, Percent, RuntimeDebug, }; use sp_std::prelude::*; @@ -580,6 +580,9 @@ impl Pallet { use frame_support::{migration::storage_key_iter, Twox64Concat}; + let zero_account = T::AccountId::decode(&mut TrailingZeroInput::new(&[][..])) + .expect("infinite input; qed"); + for (hash, old_tip) in storage_key_iter::< T::Hash, OldOpenTip, T::BlockNumber, T::Hash>, @@ -589,7 +592,7 @@ impl Pallet { { let (finder, deposit, finders_fee) = match old_tip.finder { Some((finder, deposit)) => (finder, deposit, true), - None => (T::AccountId::default(), Zero::zero(), false), + None => (zero_account.clone(), Zero::zero(), false), }; let new_tip = OpenTip { reason: old_tip.reason, diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index 1f22669857d76..be16fa45f9534 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -244,43 +244,44 @@ where } fn post_dispatch( - pre: Self::Pre, + pre: Option, info: &DispatchInfoOf, post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, ) -> Result<(), TransactionValidityError> { - let (tip, who, initial_payment) = pre; - match initial_payment { - InitialPayment::Native(already_withdrawn) => { - pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( - (tip, who, already_withdrawn), - info, - post_info, - len, - result, - )?; - }, - InitialPayment::Asset(already_withdrawn) => { - let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( - len as u32, info, post_info, tip, - ); - T::OnChargeAssetTransaction::correct_and_deposit_fee( - &who, - info, - post_info, - actual_fee.into(), - tip.into(), - already_withdrawn.into(), - )?; - }, - InitialPayment::Nothing => { - // `actual_fee` should be zero here for any signed extrinsic. It would be non-zero - // here in case of unsigned extrinsics as they don't pay fees but - // `compute_actual_fee` is not aware of them. In both cases it's fine to just move - // ahead without adjusting the fee, though, so we do nothing. - debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); - }, + if let Some((tip, who, initial_payment)) = pre { + match initial_payment { + InitialPayment::Native(already_withdrawn) => { + pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( + Some((tip, who, already_withdrawn)), + info, + post_info, + len, + result, + )?; + }, + InitialPayment::Asset(already_withdrawn) => { + let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( + len as u32, info, post_info, tip, + ); + T::OnChargeAssetTransaction::correct_and_deposit_fee( + &who, + info, + post_info, + actual_fee.into(), + tip.into(), + already_withdrawn.into(), + )?; + }, + InitialPayment::Nothing => { + // `actual_fee` should be zero here for any signed extrinsic. It would be + // non-zero here in case of unsigned extrinsics as they don't pay fees but + // `compute_actual_fee` is not aware of them. In both cases it's fine to just + // move ahead without adjusting the fee, though, so we do nothing. + debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); + }, + } } Ok(()) diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index 106b361aff8f3..c6c60cfe237d5 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -201,10 +201,11 @@ impl pallet_authorship::Config for Runtime { pub struct CreditToBlockAuthor; impl HandleCredit for CreditToBlockAuthor { fn handle_credit(credit: CreditOf) { - let author = pallet_authorship::Pallet::::author(); - // What to do in case paying the author fails (e.g. because `fee < min_balance`) - // default: drop the result which will trigger the `OnDrop` of the imbalance. - let _ = >::resolve(&author, credit); + if let Some(author) = pallet_authorship::Pallet::::author() { + // What to do in case paying the author fails (e.g. because `fee < min_balance`) + // default: drop the result which will trigger the `OnDrop` of the imbalance. + let _ = >::resolve(&author, credit); + } } } @@ -304,7 +305,7 @@ fn transaction_payment_in_native_possible() { assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(5), &default_post_info(), len, @@ -319,7 +320,7 @@ fn transaction_payment_in_native_possible() { assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(100), &post_info_from_weight(50), len, @@ -370,7 +371,7 @@ fn transaction_payment_in_asset_possible() { assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(weight), &default_post_info(), len, @@ -423,7 +424,7 @@ fn transaction_payment_without_fee() { assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(weight), &post_info_from_pays(Pays::No), len, @@ -475,7 +476,7 @@ fn asset_transaction_payment_with_tip_and_refund() { let final_weight = 50; assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(weight), &post_info_from_weight(final_weight), len, @@ -528,7 +529,7 @@ fn payment_from_account_with_only_assets() { assert_eq!(Assets::balance(asset_id, caller), balance - fee); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(weight), &default_post_info(), len, @@ -612,7 +613,7 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { assert_eq!(Assets::balance(asset_id, caller), balance); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_pays(Pays::No), &post_info_from_pays(Pays::No), len, @@ -627,7 +628,7 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { assert_eq!(Assets::balance(asset_id, caller), balance - 1); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(weight), &default_post_info(), len, @@ -684,7 +685,7 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the // initial fee) assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_pays(Pays::No), &post_info_from_pays(Pays::Yes), len, @@ -721,7 +722,7 @@ fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { assert_eq!(Assets::balance(asset_id, caller), balance); let weight = 1; let len = 1; - let pre = ChargeAssetTxPayment::::pre_dispatch_unsigned( + ChargeAssetTxPayment::::pre_dispatch_unsigned( CALL, &info_from_weight(weight), len, @@ -729,17 +730,11 @@ fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance); - let (_tip, _who, initial_payment) = ⪯ - let not_paying = match initial_payment { - &InitialPayment::Nothing => true, - _ => false, - }; - assert!(not_paying, "initial payment is Nothing for unsigned extrinsics"); // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the // initial fee) assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + None, &info_from_weight(weight), &post_info_from_pays(Pays::Yes), len, diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index a5bcc6d12dec8..c7ccdafc78283 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -704,7 +704,7 @@ where type Pre = ( // tip BalanceOf, - // who paid the fee + // who paid the fee - this is an option to allow for a Default impl. Self::AccountId, // imbalance resulting from withdrawing the fee <::OnChargeTransaction as OnChargeTransaction>::LiquidityInfo, @@ -740,17 +740,18 @@ where } fn post_dispatch( - pre: Self::Pre, + maybe_pre: Option, info: &DispatchInfoOf, post_info: &PostDispatchInfoOf, len: usize, _result: &DispatchResult, ) -> Result<(), TransactionValidityError> { - let (tip, who, imbalance) = pre; - let actual_fee = Pallet::::compute_actual_fee(len as u32, info, post_info, tip); - T::OnChargeTransaction::correct_and_deposit_fee( - &who, info, post_info, actual_fee, tip, imbalance, - )?; + if let Some((tip, who, imbalance)) = maybe_pre { + let actual_fee = Pallet::::compute_actual_fee(len as u32, info, post_info, tip); + T::OnChargeTransaction::correct_and_deposit_fee( + &who, info, post_info, actual_fee, tip, imbalance, + )?; + } Ok(()) } } @@ -1014,7 +1015,7 @@ mod tests { assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); assert_ok!(ChargeTransactionPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(5), &default_post_info(), len, @@ -1032,7 +1033,7 @@ mod tests { assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); assert_ok!(ChargeTransactionPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(100), &post_info_from_weight(50), len, @@ -1061,7 +1062,7 @@ mod tests { assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 150 - 5); assert_ok!(ChargeTransactionPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(100), &post_info_from_weight(50), len, @@ -1356,7 +1357,7 @@ mod tests { assert_eq!(Balances::free_balance(2), 0); assert_ok!(ChargeTransactionPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(100), &post_info_from_weight(50), len, @@ -1390,7 +1391,7 @@ mod tests { assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); assert_ok!(ChargeTransactionPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(100), &post_info_from_weight(101), len, @@ -1418,7 +1419,7 @@ mod tests { .unwrap(); assert_eq!(Balances::total_balance(&user), 0); assert_ok!(ChargeTransactionPayment::::post_dispatch( - pre, + Some(pre), &dispatch_info, &default_post_info(), len, @@ -1450,7 +1451,7 @@ mod tests { .unwrap(); ChargeTransactionPayment::::post_dispatch( - pre, + Some(pre), &info, &post_info, len, @@ -1601,7 +1602,7 @@ mod tests { .unwrap(); ChargeTransactionPayment::::post_dispatch( - pre, + Some(pre), &info, &post_info, len, diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index fde4e78366e68..2200d96da600e 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -65,7 +65,7 @@ use frame_support::{ }; use sp_core::TypeId; use sp_io::hashing::blake2_256; -use sp_runtime::traits::Dispatchable; +use sp_runtime::traits::{Dispatchable, TrailingZeroInput}; use sp_std::prelude::*; pub use weights::WeightInfo; @@ -400,6 +400,7 @@ impl Pallet { /// Derive a derivative account ID from the owner account and the sub-account index. pub fn derivative_account_id(who: T::AccountId, index: u16) -> T::AccountId { let entropy = (b"modlpy/utilisuba", who, index).using_encoded(blake2_256); - T::AccountId::decode(&mut &entropy[..]).unwrap_or_default() + Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) + .expect("infinite length input; no invalid inputs for type; qed") } } diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 21dfd456b1a1a..5c9b25fa31861 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -187,7 +187,7 @@ fn record_proof_works() { amount: 1000, nonce: 0, from: AccountKeyring::Alice.into(), - to: Default::default(), + to: AccountKeyring::Bob.into(), } .into_signed_tx(); diff --git a/primitives/application-crypto/src/ecdsa.rs b/primitives/application-crypto/src/ecdsa.rs index 915e16ba3b1a2..fba1fc03b2533 100644 --- a/primitives/application-crypto/src/ecdsa.rs +++ b/primitives/application-crypto/src/ecdsa.rs @@ -57,6 +57,6 @@ impl RuntimePublic for Public { } fn to_raw_vec(&self) -> Vec { - sp_core::crypto::Public::to_raw_vec(self) + sp_core::crypto::ByteArray::to_raw_vec(self) } } diff --git a/primitives/application-crypto/src/ed25519.rs b/primitives/application-crypto/src/ed25519.rs index 09ce48fcb274c..35fcb2403a033 100644 --- a/primitives/application-crypto/src/ed25519.rs +++ b/primitives/application-crypto/src/ed25519.rs @@ -57,6 +57,6 @@ impl RuntimePublic for Public { } fn to_raw_vec(&self) -> Vec { - sp_core::crypto::Public::to_raw_vec(self) + sp_core::crypto::ByteArray::to_raw_vec(self) } } diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index baa6560667059..a6bba43632221 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -27,7 +27,10 @@ pub use sp_core::crypto::{DeriveJunction, Pair, SecretStringError, Ss58Codec}; #[doc(hidden)] pub use sp_core::{ self, - crypto::{CryptoType, CryptoTypePublicPair, Derive, IsWrappedBy, Public, Wraps}, + crypto::{ + ByteArray, CryptoType, CryptoTypePublicPair, Derive, IsWrappedBy, Public, UncheckedFrom, + Wraps, + }, RuntimeDebug, }; @@ -221,7 +224,7 @@ macro_rules! app_crypto_public_full_crypto { $crate::wrap! { /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. #[derive( - Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord, + Clone, Eq, Hash, PartialEq, PartialOrd, Ord, $crate::codec::Encode, $crate::codec::Decode, $crate::RuntimeDebug, @@ -258,7 +261,7 @@ macro_rules! app_crypto_public_not_full_crypto { $crate::wrap! { /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. #[derive( - Clone, Default, Eq, PartialEq, Ord, PartialOrd, + Clone, Eq, PartialEq, Ord, PartialOrd, $crate::codec::Encode, $crate::codec::Decode, $crate::RuntimeDebug, @@ -301,13 +304,12 @@ macro_rules! app_crypto_public_common { } } + impl $crate::ByteArray for Public { + const LEN: usize = <$public>::LEN; + } impl $crate::Public for Public { - fn from_slice(x: &[u8]) -> Self { - Self(<$public>::from_slice(x)) - } - fn to_public_crypto_pair(&self) -> $crate::CryptoTypePublicPair { - $crate::CryptoTypePublicPair($crypto_type, self.to_raw_vec()) + $crate::CryptoTypePublicPair($crypto_type, $crate::ByteArray::to_raw_vec(self)) } } @@ -357,7 +359,7 @@ macro_rules! app_crypto_public_common { impl From<&Public> for $crate::CryptoTypePublicPair { fn from(key: &Public) -> Self { - $crate::CryptoTypePublicPair($crypto_type, $crate::Public::to_raw_vec(key)) + $crate::CryptoTypePublicPair($crypto_type, $crate::ByteArray::to_raw_vec(key)) } } @@ -435,7 +437,7 @@ macro_rules! app_crypto_signature_full_crypto { ($sig:ty, $key_type:expr, $crypto_type:expr) => { $crate::wrap! { /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. - #[derive(Clone, Default, Eq, PartialEq, + #[derive(Clone, Eq, PartialEq, $crate::codec::Encode, $crate::codec::Decode, $crate::RuntimeDebug, @@ -470,7 +472,7 @@ macro_rules! app_crypto_signature_not_full_crypto { ($sig:ty, $key_type:expr, $crypto_type:expr) => { $crate::wrap! { /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. - #[derive(Clone, Default, Eq, PartialEq, + #[derive(Clone, Eq, PartialEq, $crate::codec::Encode, $crate::codec::Decode, $crate::scale_info::TypeInfo, @@ -516,11 +518,19 @@ macro_rules! app_crypto_signature_common { type Generic = $sig; } + impl<'a> $crate::TryFrom<&'a [u8]> for Signature { + type Error = (); + + fn try_from(data: &'a [u8]) -> Result { + <$sig>::try_from(data).map(Into::into) + } + } + impl $crate::TryFrom<$crate::Vec> for Signature { type Error = (); fn try_from(data: $crate::Vec) -> Result { - Ok(<$sig>::try_from(data.as_slice())?.into()) + Self::try_from(&data[..]) } } }; diff --git a/primitives/application-crypto/src/sr25519.rs b/primitives/application-crypto/src/sr25519.rs index f51236f2ab384..6cd1bf35a2354 100644 --- a/primitives/application-crypto/src/sr25519.rs +++ b/primitives/application-crypto/src/sr25519.rs @@ -57,6 +57,6 @@ impl RuntimePublic for Public { } fn to_raw_vec(&self) -> Vec { - sp_core::crypto::Public::to_raw_vec(self) + sp_core::crypto::ByteArray::to_raw_vec(self) } } diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index dc08d69bf4183..671f526fde32c 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -222,7 +222,7 @@ pub enum PublicError { /// See /// for information on the codec. #[cfg(feature = "full_crypto")] -pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { +pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray { /// A format filterer, can be used to ensure that `from_ss58check` family only decode for /// allowed identifiers. By default just refuses the two reserved identifiers. fn format_is_allowed(f: Ss58AddressFormat) -> bool { @@ -243,10 +243,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { #[cfg(feature = "std")] fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> { const CHECKSUM_LEN: usize = 2; - let mut res = Self::default(); - - // Must decode to our type. - let body_len = res.as_mut().len(); + let body_len = Self::LEN; let data = s.from_base58().map_err(|_| PublicError::BadBase58)?; if data.len() < 2 { @@ -280,8 +277,10 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { // Invalid checksum. return Err(PublicError::InvalidChecksum) } - res.as_mut().copy_from_slice(&data[prefix_len..body_len + prefix_len]); - Ok((res, format)) + + let result = Self::from_slice(&data[prefix_len..body_len + prefix_len]) + .map_err(|()| PublicError::BadLength)?; + Ok((result, format)) } /// Some if the string is a properly encoded SS58Check address, optionally with @@ -391,19 +390,13 @@ lazy_static::lazy_static! { } #[cfg(feature = "std")] -impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { +impl + AsRef<[u8]> + Public + Derive> Ss58Codec for T { fn from_string(s: &str) -> Result { let cap = SS58_REGEX.captures(s).ok_or(PublicError::InvalidFormat)?; let s = cap.name("ss58").map(|r| r.as_str()).unwrap_or(DEV_ADDRESS); let addr = if let Some(stripped) = s.strip_prefix("0x") { let d = hex::decode(stripped).map_err(|_| PublicError::InvalidFormat)?; - let mut r = Self::default(); - if d.len() == r.as_ref().len() { - r.as_mut().copy_from_slice(&d); - r - } else { - return Err(PublicError::BadLength) - } + Self::from_slice(&d).map_err(|()| PublicError::BadLength)? } else { Self::from_ss58check(s)? }; @@ -431,25 +424,15 @@ impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { } } -/// Trait suitable for typical cryptographic PKI key public type. -pub trait Public: - AsRef<[u8]> - + AsMut<[u8]> - + Default - + Derive - + CryptoType - + PartialEq - + Eq - + Clone - + Send - + Sync - + for<'a> TryFrom<&'a [u8]> -{ - /// A new instance from the given slice. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - fn from_slice(data: &[u8]) -> Self; +/// Trait used for types that are really just a fixed-length array. +pub trait ByteArray: AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8], Error = ()> { + /// The "length" of the values of this type, which is always the same. + const LEN: usize; + + /// A new instance from the given slice that should be `Self::LEN` bytes long. + fn from_slice(data: &[u8]) -> Result { + Self::try_from(data) + } /// Return a `Vec` filled with raw data. fn to_raw_vec(&self) -> Vec { @@ -460,7 +443,10 @@ pub trait Public: fn as_slice(&self) -> &[u8] { self.as_ref() } +} +/// Trait suitable for typical cryptographic PKI key public type. +pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync { /// Return `CryptoTypePublicPair` from public key. fn to_public_crypto_pair(&self) -> CryptoTypePublicPair; } @@ -488,6 +474,10 @@ impl UncheckedFrom for AccountId32 { } } +impl ByteArray for AccountId32 { + const LEN: usize = 32; +} + #[cfg(feature = "std")] impl Ss58Codec for AccountId32 {} @@ -650,9 +640,10 @@ mod dummy { impl Derive for Dummy {} - impl Public for Dummy { - fn from_slice(_: &[u8]) -> Self { - Self + impl ByteArray for Dummy { + const LEN: usize = 0; + fn from_slice(_: &[u8]) -> Result { + Ok(Self) } #[cfg(feature = "std")] fn to_raw_vec(&self) -> Vec { @@ -661,8 +652,10 @@ mod dummy { fn as_slice(&self) -> &[u8] { b"" } + } + impl Public for Dummy { fn to_public_crypto_pair(&self) -> CryptoTypePublicPair { - CryptoTypePublicPair(CryptoTypeId(*b"dumm"), Public::to_raw_vec(self)) + CryptoTypePublicPair(CryptoTypeId(*b"dumm"), ::to_raw_vec(self)) } } @@ -1146,17 +1139,22 @@ mod tests { impl<'a> TryFrom<&'a [u8]> for TestPublic { type Error = (); - fn try_from(_: &'a [u8]) -> Result { - Ok(Self) + fn try_from(data: &'a [u8]) -> Result { + Self::from_slice(data) } } impl CryptoType for TestPublic { type Pair = TestPair; } impl Derive for TestPublic {} - impl Public for TestPublic { - fn from_slice(_bytes: &[u8]) -> Self { - Self + impl ByteArray for TestPublic { + const LEN: usize = 0; + fn from_slice(bytes: &[u8]) -> Result { + if bytes.len() == 0 { + Ok(Self) + } else { + Err(()) + } } fn as_slice(&self) -> &[u8] { &[] @@ -1164,6 +1162,8 @@ mod tests { fn to_raw_vec(&self) -> Vec { vec![] } + } + impl Public for TestPublic { fn to_public_crypto_pair(&self) -> CryptoTypePublicPair { CryptoTypePublicPair(CryptoTypeId(*b"dumm"), self.to_raw_vec()) } diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 2751a0c40e3e5..827be8eb9aabf 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -27,7 +27,8 @@ use sp_std::cmp::Ordering; #[cfg(feature = "std")] use crate::crypto::Ss58Codec; use crate::crypto::{ - CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, UncheckedFrom, + ByteArray, CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, + UncheckedFrom, }; #[cfg(feature = "full_crypto")] use crate::{ @@ -113,17 +114,11 @@ impl Public { } } -impl TraitPublic for Public { - /// A new instance from the given slice that should be 33 bytes long. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - fn from_slice(data: &[u8]) -> Self { - let mut r = [0u8; 33]; - r.copy_from_slice(data); - Self(r) - } +impl ByteArray for Public { + const LEN: usize = 33; +} +impl TraitPublic for Public { fn to_public_crypto_pair(&self) -> CryptoTypePublicPair { CryptoTypePublicPair(CRYPTO_ID, self.to_raw_vec()) } @@ -143,12 +138,6 @@ impl From<&Public> for CryptoTypePublicPair { impl Derive for Public {} -impl Default for Public { - fn default() -> Self { - Public([0u8; 33]) - } -} - impl AsRef<[u8]> for Public { fn as_ref(&self) -> &[u8] { &self.0[..] @@ -165,11 +154,12 @@ impl sp_std::convert::TryFrom<&[u8]> for Public { type Error = (); fn try_from(data: &[u8]) -> Result { - if data.len() == 33 { - Ok(Self::from_slice(data)) - } else { - Err(()) + if data.len() != Self::LEN { + return Err(()) } + let mut r = [0u8; Self::LEN]; + r.copy_from_slice(data); + Ok(Self::unchecked_from(r)) } } @@ -340,6 +330,12 @@ impl sp_std::hash::Hash for Signature { } } +impl UncheckedFrom<[u8; 65]> for Signature { + fn unchecked_from(data: [u8; 65]) -> Signature { + Signature(data) + } +} + impl Signature { /// A new instance from the given 65-byte `data`. /// diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index d786ee9d255ff..7d60998b15dfc 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -22,7 +22,10 @@ #[cfg(feature = "full_crypto")] use sp_std::vec::Vec; -use crate::hash::{H256, H512}; +use crate::{ + crypto::ByteArray, + hash::{H256, H512}, +}; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -66,7 +69,6 @@ type Seed = [u8; 32]; Copy, Encode, Decode, - Default, PassByInner, MaxEncodedLen, TypeInfo, @@ -118,13 +120,12 @@ impl sp_std::convert::TryFrom<&[u8]> for Public { type Error = (); fn try_from(data: &[u8]) -> Result { - if data.len() == 32 { - let mut inner = [0u8; 32]; - inner.copy_from_slice(data); - Ok(Public(inner)) - } else { - Err(()) + if data.len() != Self::LEN { + return Err(()) } + let mut r = [0u8; Self::LEN]; + r.copy_from_slice(data); + Ok(Self::unchecked_from(r)) } } @@ -258,12 +259,6 @@ impl Clone for Signature { } } -impl Default for Signature { - fn default() -> Self { - Signature([0u8; 64]) - } -} - impl PartialEq for Signature { fn eq(&self, b: &Self) -> bool { self.0[..] == b.0[..] @@ -321,6 +316,12 @@ impl sp_std::hash::Hash for Signature { } } +impl UncheckedFrom<[u8; 64]> for Signature { + fn unchecked_from(data: [u8; 64]) -> Signature { + Signature(data) + } +} + impl Signature { /// A new instance from the given 64-byte `data`. /// @@ -400,17 +401,11 @@ impl Public { } } -impl TraitPublic for Public { - /// A new instance from the given slice that should be 32 bytes long. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - fn from_slice(data: &[u8]) -> Self { - let mut r = [0u8; 32]; - r.copy_from_slice(data); - Public(r) - } +impl ByteArray for Public { + const LEN: usize = 32; +} +impl TraitPublic for Public { fn to_public_crypto_pair(&self) -> CryptoTypePublicPair { CryptoTypePublicPair(CRYPTO_ID, self.to_raw_vec()) } diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 3983f7cc155d9..5fca42adde991 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -76,7 +76,7 @@ pub use self::{ uint::{U256, U512}, }; #[cfg(feature = "full_crypto")] -pub use crypto::{DeriveJunction, Pair, Public}; +pub use crypto::{ByteArray, DeriveJunction, Pair, Public}; #[cfg(feature = "std")] pub use self::hasher::blake2::Blake2Hasher; diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index 4787c2d9d13ee..97e9de5de09a7 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -41,7 +41,7 @@ use substrate_bip39::mini_secret_from_entropy; use crate::{ crypto::{ - CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, + ByteArray, CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, UncheckedFrom, }, hash::{H256, H512}, @@ -74,7 +74,6 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25"); Copy, Encode, Decode, - Default, PassByInner, MaxEncodedLen, TypeInfo, @@ -147,13 +146,12 @@ impl sp_std::convert::TryFrom<&[u8]> for Public { type Error = (); fn try_from(data: &[u8]) -> Result { - if data.len() == 32 { - let mut inner = [0u8; 32]; - inner.copy_from_slice(data); - Ok(Public(inner)) - } else { - Err(()) + if data.len() != Self::LEN { + return Err(()) } + let mut r = [0u8; 32]; + r.copy_from_slice(data); + Ok(Self::unchecked_from(r)) } } @@ -261,12 +259,6 @@ impl Clone for Signature { } } -impl Default for Signature { - fn default() -> Self { - Signature([0u8; 64]) - } -} - impl PartialEq for Signature { fn eq(&self, b: &Self) -> bool { self.0[..] == b.0[..] @@ -342,6 +334,12 @@ pub struct LocalizedSignature { pub signature: Signature, } +impl UncheckedFrom<[u8; 64]> for Signature { + fn unchecked_from(data: [u8; 64]) -> Signature { + Signature(data) + } +} + impl Signature { /// A new instance from the given 64-byte `data`. /// @@ -412,17 +410,11 @@ impl Public { } } -impl TraitPublic for Public { - /// A new instance from the given slice that should be 32 bytes long. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - fn from_slice(data: &[u8]) -> Self { - let mut r = [0u8; 32]; - r.copy_from_slice(data); - Public(r) - } +impl ByteArray for Public { + const LEN: usize = 32; +} +impl TraitPublic for Public { fn to_public_crypto_pair(&self) -> CryptoTypePublicPair { CryptoTypePublicPair(CRYPTO_ID, self.to_raw_vec()) } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 44649abd28911..1edf87703fbe6 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -1543,7 +1543,10 @@ pub type SubstrateHostFunctions = ( #[cfg(test)] mod tests { use super::*; - use sp_core::{map, storage::Storage, testing::TaskExecutor, traits::TaskExecutorExt}; + use sp_core::{ + crypto::UncheckedInto, map, storage::Storage, testing::TaskExecutor, + traits::TaskExecutorExt, + }; use sp_state_machine::BasicExternalities; use std::any::TypeId; @@ -1644,7 +1647,7 @@ mod tests { } // push invlaid - crypto::sr25519_batch_verify(&Default::default(), &Vec::new(), &Default::default()); + crypto::sr25519_batch_verify(&zero_sr_sig(), &Vec::new(), &zero_sr_pub()); assert!(!crypto::finish_batch_verify()); crypto::start_batch_verify(); @@ -1657,14 +1660,31 @@ mod tests { }); } + fn zero_ed_pub() -> ed25519::Public { + [0u8; 32].unchecked_into() + } + + fn zero_ed_sig() -> ed25519::Signature { + ed25519::Signature::from_raw([0u8; 64]) + } + + fn zero_sr_pub() -> sr25519::Public { + [0u8; 32].unchecked_into() + } + + fn zero_sr_sig() -> sr25519::Signature { + sr25519::Signature::from_raw([0u8; 64]) + } + #[test] fn batching_works() { let mut ext = BasicExternalities::default(); ext.register_extension(TaskExecutorExt::new(TaskExecutor::new())); + ext.execute_with(|| { // invalid ed25519 signature crypto::start_batch_verify(); - crypto::ed25519_batch_verify(&Default::default(), &Vec::new(), &Default::default()); + crypto::ed25519_batch_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub()); assert!(!crypto::finish_batch_verify()); // 2 valid ed25519 signatures @@ -1690,7 +1710,7 @@ mod tests { let signature = pair.sign(msg); crypto::ed25519_batch_verify(&signature, msg, &pair.public()); - crypto::ed25519_batch_verify(&Default::default(), &Vec::new(), &Default::default()); + crypto::ed25519_batch_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub()); assert!(!crypto::finish_batch_verify()); @@ -1722,7 +1742,7 @@ mod tests { let signature = pair.sign(msg); crypto::sr25519_batch_verify(&signature, msg, &pair.public()); - crypto::sr25519_batch_verify(&Default::default(), &Vec::new(), &Default::default()); + crypto::sr25519_batch_verify(&zero_sr_sig(), &Vec::new(), &zero_sr_pub()); assert!(!crypto::finish_batch_verify()); }); diff --git a/primitives/keyring/src/ed25519.rs b/primitives/keyring/src/ed25519.rs index 65341a360579b..4d99de6c59d70 100644 --- a/primitives/keyring/src/ed25519.rs +++ b/primitives/keyring/src/ed25519.rs @@ -21,7 +21,7 @@ use lazy_static::lazy_static; pub use sp_core::ed25519; use sp_core::{ ed25519::{Pair, Public, Signature}, - Pair as PairT, Public as PublicT, H256, + ByteArray, Pair as PairT, H256, }; use sp_runtime::AccountId32; use std::{collections::HashMap, ops::Deref}; diff --git a/primitives/keyring/src/sr25519.rs b/primitives/keyring/src/sr25519.rs index 604c330b1ea1b..d400cde035b70 100644 --- a/primitives/keyring/src/sr25519.rs +++ b/primitives/keyring/src/sr25519.rs @@ -21,7 +21,7 @@ use lazy_static::lazy_static; pub use sp_core::sr25519; use sp_core::{ sr25519::{Pair, Public, Signature}, - Pair as PairT, Public as PublicT, H256, + ByteArray, Pair as PairT, H256, }; use sp_runtime::AccountId32; use std::{collections::HashMap, ops::Deref}; diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index 718ba798dc0f3..92a73eb98c90f 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -18,7 +18,7 @@ //! Types that should only be used for testing! use sp_core::{ - crypto::{CryptoTypePublicPair, KeyTypeId, Pair, Public}, + crypto::{ByteArray, CryptoTypePublicPair, KeyTypeId, Pair}, ecdsa, ed25519, sr25519, }; @@ -340,20 +340,20 @@ impl SyncCryptoStore for KeyStore { match key.0 { ed25519::CRYPTO_ID => { - let key_pair = - self.ed25519_key_pair(id, &ed25519::Public::from_slice(key.1.as_slice())); + let key_pair = self + .ed25519_key_pair(id, &ed25519::Public::from_slice(key.1.as_slice()).unwrap()); key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose() }, sr25519::CRYPTO_ID => { - let key_pair = - self.sr25519_key_pair(id, &sr25519::Public::from_slice(key.1.as_slice())); + let key_pair = self + .sr25519_key_pair(id, &sr25519::Public::from_slice(key.1.as_slice()).unwrap()); key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose() }, ecdsa::CRYPTO_ID => { let key_pair = - self.ecdsa_key_pair(id, &ecdsa::Public::from_slice(key.1.as_slice())); + self.ecdsa_key_pair(id, &ecdsa::Public::from_slice(key.1.as_slice()).unwrap()); key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose() }, diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index afe85ef53b3a7..0b10b4c7c1b8f 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -178,7 +178,7 @@ impl Candidate { } /// A vote being casted by a [`Voter`] to a [`Candidate`] is an `Edge`. -#[derive(Clone, Default)] +#[derive(Clone)] pub struct Edge { /// Identifier of the target. /// @@ -193,6 +193,15 @@ pub struct Edge { weight: ExtendedBalance, } +#[cfg(test)] +impl Edge { + fn new(candidate: Candidate, weight: ExtendedBalance) -> Self { + let who = candidate.who.clone(); + let candidate = Rc::new(RefCell::new(candidate)); + Self { weight, who, candidate, load: Default::default() } + } +} + #[cfg(feature = "std")] impl sp_std::fmt::Debug for Edge { fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { @@ -223,7 +232,12 @@ impl std::fmt::Debug for Voter { impl Voter { /// Create a new `Voter`. pub fn new(who: AccountId) -> Self { - Self { who, ..Default::default() } + Self { + who, + edges: Default::default(), + budget: Default::default(), + load: Default::default(), + } } /// Returns `true` if `self` votes for `target`. @@ -339,7 +353,7 @@ pub struct ElectionResult { /// /// This, at the current version, resembles the `Exposure` defined in the Staking pallet, yet they /// do not necessarily have to be the same. -#[derive(Default, RuntimeDebug, Encode, Decode, Clone, Eq, PartialEq, scale_info::TypeInfo)] +#[derive(RuntimeDebug, Encode, Decode, Clone, Eq, PartialEq, scale_info::TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct Support { /// Total support. @@ -348,6 +362,12 @@ pub struct Support { pub voters: Vec<(AccountId, ExtendedBalance)>, } +impl Default for Support { + fn default() -> Self { + Self { total: Default::default(), voters: vec![] } + } +} + /// A target-major representation of the the election outcome. /// /// Essentially a flat variant of [`SupportMap`]. @@ -461,7 +481,15 @@ pub fn setup_inputs( .enumerate() .map(|(idx, who)| { c_idx_cache.insert(who.clone(), idx); - Candidate { who, ..Default::default() }.to_ptr() + Candidate { + who, + score: Default::default(), + approval_stake: Default::default(), + backed_stake: Default::default(), + elected: Default::default(), + round: Default::default(), + } + .to_ptr() }) .collect::>>(); @@ -482,7 +510,8 @@ pub fn setup_inputs( edges.push(Edge { who: v.clone(), candidate: Rc::clone(&candidates[*idx]), - ..Default::default() + load: Default::default(), + weight: Default::default(), }); } // else {} would be wrong votes. We don't really care about it. } diff --git a/primitives/npos-elections/src/pjr.rs b/primitives/npos-elections/src/pjr.rs index e27acf1408f96..50556ea9cc335 100644 --- a/primitives/npos-elections/src/pjr.rs +++ b/primitives/npos-elections/src/pjr.rs @@ -287,7 +287,15 @@ fn prepare_pjr_input( let elected = maybe_support.is_some(); let backed_stake = maybe_support.map(|support| support.total).unwrap_or_default(); - Candidate { who, elected, backed_stake, ..Default::default() }.to_ptr() + Candidate { + who, + elected, + backed_stake, + score: Default::default(), + approval_stake: Default::default(), + round: Default::default(), + } + .to_ptr() }) .collect::>(); @@ -315,14 +323,14 @@ fn prepare_pjr_input( who: t, candidate: Rc::clone(&candidates[*idx]), weight, - ..Default::default() + load: Default::default(), }); } } let who = v; let budget: ExtendedBalance = w.into(); - Voter { who, budget, edges, ..Default::default() } + Voter { who, budget, edges, load: Default::default() } }) .collect::>(); @@ -387,7 +395,14 @@ mod tests { .into_iter() .map(|(t, w, e)| { budget += w; - Candidate { who: t, elected: e, backed_stake: w, ..Default::default() } + Candidate { + who: t, + elected: e, + backed_stake: w, + score: Default::default(), + approval_stake: Default::default(), + round: Default::default(), + } }) .collect::>(); let edges = candidates @@ -396,7 +411,7 @@ mod tests { who: c.who, weight: c.backed_stake, candidate: c.to_ptr(), - ..Default::default() + load: Default::default(), }) .collect::>(); voter.edges = edges; @@ -432,7 +447,15 @@ mod tests { // will give 10 slack. let v3 = setup_voter(30, vec![(1, 20, true), (2, 20, true), (3, 0, false)]); - let unelected = Candidate { who: 3u32, elected: false, ..Default::default() }.to_ptr(); + let unelected = Candidate { + who: 3u32, + elected: false, + score: Default::default(), + approval_stake: Default::default(), + backed_stake: Default::default(), + round: Default::default(), + } + .to_ptr(); let score = pre_score(unelected, &vec![v1, v2, v3], 15); assert_eq!(score, 15); diff --git a/primitives/npos-elections/src/reduce.rs b/primitives/npos-elections/src/reduce.rs index 8b90796af85ca..8ff0244b4694f 100644 --- a/primitives/npos-elections/src/reduce.rs +++ b/primitives/npos-elections/src/reduce.rs @@ -55,7 +55,6 @@ use sp_arithmetic::traits::{Bounded, Zero}; use sp_std::{ collections::btree_map::{BTreeMap, Entry::*}, prelude::*, - vec, }; /// Map type used for reduce_4. Can be easily swapped with HashMap. @@ -356,7 +355,7 @@ fn reduce_all(assignments: &mut Vec>) -> u32 .or_insert_with(|| Node::new(target_id).into_ref()) .clone(); - // If one exists but the other one doesn't, or if both does not, then set the existing + // If one exists but the other one doesn't, or if both do not, then set the existing // one as the parent of the non-existing one and move on. Else, continue with the rest // of the code. match (voter_exists, target_exists) { @@ -390,39 +389,44 @@ fn reduce_all(assignments: &mut Vec>) -> u32 let common_count = trailing_common(&voter_root_path, &target_root_path); // because roots are the same. - #[cfg(feature = "std")] - debug_assert_eq!(target_root_path.last().unwrap(), voter_root_path.last().unwrap()); + //debug_assert_eq!(target_root_path.last().unwrap(), + // voter_root_path.last().unwrap()); TODO: @kian + // the common path must be non-void.. debug_assert!(common_count > 0); + // and smaller than btoh + debug_assert!(common_count <= voter_root_path.len()); + debug_assert!(common_count <= target_root_path.len()); // cycle part of each path will be `path[path.len() - common_count - 1 : 0]` // NOTE: the order of chaining is important! it is always build from [target, ..., // voter] let cycle = target_root_path .iter() - .take(target_root_path.len() - common_count + 1) + .take(target_root_path.len().saturating_sub(common_count).saturating_add(1)) .cloned() .chain( voter_root_path .iter() - .take(voter_root_path.len() - common_count) + .take(voter_root_path.len().saturating_sub(common_count)) .rev() .cloned(), ) .collect::>>(); // a cycle's length shall always be multiple of two. - #[cfg(feature = "std")] debug_assert_eq!(cycle.len() % 2, 0); // find minimum of cycle. let mut min_value: ExtendedBalance = Bounded::max_value(); - // The voter and the target pair that create the min edge. - let mut min_target: A = Default::default(); - let mut min_voter: A = Default::default(); + // The voter and the target pair that create the min edge. These MUST be set by the + // end of this code block, otherwise we skip. + let mut maybe_min_target: Option = None; + let mut maybe_min_voter: Option = None; // The index of the min in opaque cycle list. - let mut min_index = 0usize; + let mut maybe_min_index: Option = None; // 1 -> next // 0 -> prev - let mut min_direction = 0u32; + let mut maybe_min_direction: Option = None; + // helpers let next_index = |i| { if i < (cycle.len() - 1) { @@ -438,6 +442,7 @@ fn reduce_all(assignments: &mut Vec>) -> u32 cycle.len() - 1 } }; + for i in 0..cycle.len() { if cycle[i].borrow().id.role == NodeRole::Voter { // NOTE: sadly way too many clones since I don't want to make A: Copy @@ -448,10 +453,10 @@ fn reduce_all(assignments: &mut Vec>) -> u32 ass.distribution.iter().find(|d| d.0 == next).map(|(_, w)| { if *w < min_value { min_value = *w; - min_target = next.clone(); - min_voter = current.clone(); - min_index = i; - min_direction = 1; + maybe_min_target = Some(next.clone()); + maybe_min_voter = Some(current.clone()); + maybe_min_index = Some(i); + maybe_min_direction = Some(1); } }) }); @@ -459,16 +464,39 @@ fn reduce_all(assignments: &mut Vec>) -> u32 ass.distribution.iter().find(|d| d.0 == prev).map(|(_, w)| { if *w < min_value { min_value = *w; - min_target = prev.clone(); - min_voter = current.clone(); - min_index = i; - min_direction = 0; + maybe_min_target = Some(prev.clone()); + maybe_min_voter = Some(current.clone()); + maybe_min_index = Some(i); + maybe_min_direction = Some(0); } }) }); } } + // all of these values must be set by now, we assign them to un-mut values, no + // longer being optional either. + let (min_value, min_target, min_voter, min_index, min_direction) = + match ( + min_value, + maybe_min_target, + maybe_min_voter, + maybe_min_index, + maybe_min_direction, + ) { + ( + min_value, + Some(min_target), + Some(min_voter), + Some(min_index), + Some(min_direction), + ) => (min_value, min_target, min_voter, min_index, min_direction), + _ => { + sp_runtime::print("UNREACHABLE code reached in `reduce` algorithm. This must be a bug."); + break + }, + }; + // if the min edge is in the voter's sub-chain. // [target, ..., X, Y, ... voter] let target_chunk = target_root_path.len() - common_count; @@ -624,8 +652,8 @@ fn reduce_all(assignments: &mut Vec>) -> u32 num_changed } -/// Reduce the given [`Vec>`]. This removes redundant edges from -/// without changing the overall backing of any of the elected candidates. +/// Reduce the given [`Vec>`]. This removes redundant edges without +/// changing the overall backing of any of the elected candidates. /// /// Returns the number of edges removed. /// diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index bf9ca57677efa..0aac5c3c35df4 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -192,16 +192,15 @@ fn balancing_core_works() { #[test] fn voter_normalize_ops_works() { use crate::{Candidate, Edge}; - use sp_std::{cell::RefCell, rc::Rc}; // normalize { let c1 = Candidate { who: 10, elected: false, ..Default::default() }; let c2 = Candidate { who: 20, elected: false, ..Default::default() }; let c3 = Candidate { who: 30, elected: false, ..Default::default() }; - let e1 = Edge { candidate: Rc::new(RefCell::new(c1)), weight: 30, ..Default::default() }; - let e2 = Edge { candidate: Rc::new(RefCell::new(c2)), weight: 33, ..Default::default() }; - let e3 = Edge { candidate: Rc::new(RefCell::new(c3)), weight: 30, ..Default::default() }; + let e1 = Edge::new(c1, 30); + let e2 = Edge::new(c2, 33); + let e3 = Edge::new(c3, 30); let mut v = Voter { who: 1, budget: 100, edges: vec![e1, e2, e3], ..Default::default() }; @@ -214,9 +213,9 @@ fn voter_normalize_ops_works() { let c2 = Candidate { who: 20, elected: true, ..Default::default() }; let c3 = Candidate { who: 30, elected: true, ..Default::default() }; - let e1 = Edge { candidate: Rc::new(RefCell::new(c1)), weight: 30, ..Default::default() }; - let e2 = Edge { candidate: Rc::new(RefCell::new(c2)), weight: 33, ..Default::default() }; - let e3 = Edge { candidate: Rc::new(RefCell::new(c3)), weight: 30, ..Default::default() }; + let e1 = Edge::new(c1, 30); + let e2 = Edge::new(c2, 33); + let e3 = Edge::new(c3, 30); let mut v = Voter { who: 1, budget: 100, edges: vec![e1, e2, e3], ..Default::default() }; diff --git a/primitives/npos-elections/src/traits.rs b/primitives/npos-elections/src/traits.rs index 597d7e648fd9b..cb24f770cdea0 100644 --- a/primitives/npos-elections/src/traits.rs +++ b/primitives/npos-elections/src/traits.rs @@ -36,8 +36,8 @@ use sp_std::{ /// an aggregator trait for a generic type of a voter/target identifier. This usually maps to /// substrate's account id. -pub trait IdentifierT: Clone + Eq + Default + Ord + Debug + codec::Codec {} -impl IdentifierT for T {} +pub trait IdentifierT: Clone + Eq + Ord + Debug + codec::Codec {} +impl IdentifierT for T {} /// Aggregator trait for a PerThing that can be multiplied by u128 (ExtendedBalance). pub trait PerThing128: PerThing + Mul {} diff --git a/primitives/runtime/src/generic/checked_extrinsic.rs b/primitives/runtime/src/generic/checked_extrinsic.rs index b2044a6cf74fd..f65e4ead089fe 100644 --- a/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/primitives/runtime/src/generic/checked_extrinsic.rs @@ -70,20 +70,26 @@ where info: &DispatchInfoOf, len: usize, ) -> crate::ApplyExtrinsicResultWithInfo> { - let (maybe_who, pre) = if let Some((id, extra)) = self.signed { + let (maybe_who, maybe_pre) = if let Some((id, extra)) = self.signed { let pre = Extra::pre_dispatch(extra, &id, &self.function, info, len)?; - (Some(id), pre) + (Some(id), Some(pre)) } else { - let pre = Extra::pre_dispatch_unsigned(&self.function, info, len)?; + Extra::pre_dispatch_unsigned(&self.function, info, len)?; U::pre_dispatch(&self.function)?; - (None, pre) + (None, None) }; let res = self.function.dispatch(Origin::from(maybe_who)); let post_info = match res { Ok(info) => info, Err(err) => err.post_info, }; - Extra::post_dispatch(pre, info, &post_info, len, &res.map(|_| ()).map_err(|e| e.error))?; + Extra::post_dispatch( + maybe_pre, + info, + &post_info, + len, + &res.map(|_| ()).map_err(|e| e.error), + )?; Ok(res) } } diff --git a/primitives/runtime/src/generic/unchecked_extrinsic.rs b/primitives/runtime/src/generic/unchecked_extrinsic.rs index 95f4f2f3584d9..53e7c349f2a76 100644 --- a/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -364,7 +364,7 @@ mod tests { use crate::{ codec::{Decode, Encode}, testing::TestSignature as TestSig, - traits::{IdentityLookup, SignedExtension}, + traits::{DispatchInfoOf, IdentityLookup, SignedExtension}, }; use sp_io::hashing::blake2_256; @@ -387,6 +387,16 @@ mod tests { fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(self.validate(who, call, info, len).map(|_| ())?) + } } type Ex = UncheckedExtrinsic; diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 10fd39d38f4cc..26db5ef081a8c 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -44,7 +44,7 @@ pub use sp_application_crypto as app_crypto; pub use sp_core::storage::{Storage, StorageChild}; use sp_core::{ - crypto::{self, Public}, + crypto::{self, ByteArray}, ecdsa, ed25519, hash::{H256, H512}, sr25519, @@ -284,12 +284,6 @@ impl TryFrom for ecdsa::Signature { } } -impl Default for MultiSignature { - fn default() -> Self { - Self::Ed25519(Default::default()) - } -} - /// Public key for any known crypto algorithm. #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] @@ -302,12 +296,6 @@ pub enum MultiSigner { Ecdsa(ecdsa::Public), } -impl Default for MultiSigner { - fn default() -> Self { - Self::Ed25519(Default::default()) - } -} - /// NOTE: This implementations is required by `SimpleAddressDeterminer`, /// we convert the hash into some AccountId, it's fine to use any scheme. impl> crypto::UncheckedFrom for MultiSigner { @@ -403,10 +391,14 @@ impl Verify for MultiSignature { type Signer = MultiSigner; fn verify>(&self, mut msg: L, signer: &AccountId32) -> bool { match (self, signer) { - (Self::Ed25519(ref sig), who) => - sig.verify(msg, &ed25519::Public::from_slice(who.as_ref())), - (Self::Sr25519(ref sig), who) => - sig.verify(msg, &sr25519::Public::from_slice(who.as_ref())), + (Self::Ed25519(ref sig), who) => match ed25519::Public::from_slice(who.as_ref()) { + Ok(signer) => sig.verify(msg, &signer), + Err(()) => false, + }, + (Self::Sr25519(ref sig), who) => match sr25519::Public::from_slice(who.as_ref()) { + Ok(signer) => sig.verify(msg, &signer), + Err(()) => false, + }, (Self::Ecdsa(ref sig), who) => { let m = sp_io::hashing::blake2_256(msg.get()); match sp_io::crypto::secp256k1_ecdsa_recover_compressed(sig.as_ref(), &m) { @@ -433,7 +425,10 @@ impl Verify for AnySignature { .map(|s| s.verify(msg, signer)) .unwrap_or(false) || ed25519::Signature::try_from(self.0.as_fixed_bytes().as_ref()) - .map(|s| s.verify(msg, &ed25519::Public::from_slice(signer.as_ref()))) + .map(|s| match ed25519::Public::from_slice(signer.as_ref()) { + Err(()) => false, + Ok(signer) => s.verify(msg, &signer), + }) .unwrap_or(false) } } @@ -924,7 +919,7 @@ mod tests { use super::*; use codec::{Decode, Encode}; - use sp_core::crypto::Pair; + use sp_core::crypto::{Pair, UncheckedFrom}; use sp_io::TestExternalities; use sp_state_machine::create_proof_check_backend; @@ -1010,7 +1005,9 @@ mod tests { ext.execute_with(|| { let _batching = SignatureBatching::start(); - sp_io::crypto::sr25519_verify(&Default::default(), &Vec::new(), &Default::default()); + let dummy = UncheckedFrom::unchecked_from([1; 32]); + let dummy_sig = UncheckedFrom::unchecked_from([1; 64]); + sp_io::crypto::sr25519_verify(&dummy_sig, &Vec::new(), &dummy); }); } diff --git a/primitives/runtime/src/multiaddress.rs b/primitives/runtime/src/multiaddress.rs index 46d80608352dc..629099d85d726 100644 --- a/primitives/runtime/src/multiaddress.rs +++ b/primitives/runtime/src/multiaddress.rs @@ -62,9 +62,3 @@ impl From for MultiAddress Default for MultiAddress { - fn default() -> Self { - Self::Id(Default::default()) - } -} diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index 4573bc84473a3..46e7ee634c25d 100644 --- a/primitives/runtime/src/testing.rs +++ b/primitives/runtime/src/testing.rs @@ -30,7 +30,7 @@ use crate::{ }; use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; use sp_core::{ - crypto::{key_types, CryptoType, Dummy, Public}, + crypto::{key_types, ByteArray, CryptoType, Dummy}, U256, }; pub use sp_core::{sr25519, H256}; @@ -77,10 +77,10 @@ impl From for u64 { } impl UintAuthorityId { - /// Convert this authority id into a public key. - pub fn to_public_key(&self) -> T { + /// Convert this authority ID into a public key. + pub fn to_public_key(&self) -> T { let bytes: [u8; 32] = U256::from(self.0).into(); - T::from_slice(&bytes) + T::from_slice(&bytes).unwrap() } } diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index f61de70e35197..0ddd8cae93ea7 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -851,7 +851,7 @@ pub trait SignedExtension: type AdditionalSigned: Encode + TypeInfo; /// The type that encodes information that can be passed from pre_dispatch to post-dispatch. - type Pre: Default; + type Pre; /// Construct any additional data that should be in the signed payload of the transaction. Can /// also perform any pre-signature-verification checks and return an error if needed. @@ -890,11 +890,7 @@ pub trait SignedExtension: call: &Self::Call, info: &DispatchInfoOf, len: usize, - ) -> Result { - self.validate(who, call, info, len) - .map(|_| Self::Pre::default()) - .map_err(Into::into) - } + ) -> Result; /// Validate an unsigned transaction for the transaction queue. /// @@ -924,14 +920,15 @@ pub trait SignedExtension: call: &Self::Call, info: &DispatchInfoOf, len: usize, - ) -> Result { - Self::validate_unsigned(call, info, len) - .map(|_| Self::Pre::default()) - .map_err(Into::into) + ) -> Result<(), TransactionValidityError> { + Self::validate_unsigned(call, info, len).map(|_| ()).map_err(Into::into) } /// Do any post-flight stuff for an extrinsic. /// + /// If the transaction is signed, then `_pre` will contain the output of `pre_dispatch`, + /// and `None` otherwise. + /// /// This gets given the `DispatchResult` `_result` from the extrinsic and can, if desired, /// introduce a `TransactionValidityError`, causing the block to become invalid for including /// it. @@ -944,7 +941,7 @@ pub trait SignedExtension: /// introduced by the current block author; generally this implies that it is an inherent and /// will come from either an offchain-worker or via `InherentData`. fn post_dispatch( - _pre: Self::Pre, + _pre: Option, _info: &DispatchInfoOf, _post_info: &PostDispatchInfoOf, _len: usize, @@ -1029,18 +1026,26 @@ impl SignedExtension for Tuple { call: &Self::Call, info: &DispatchInfoOf, len: usize, - ) -> Result { - Ok(for_tuples!( ( #( Tuple::pre_dispatch_unsigned(call, info, len)? ),* ) )) + ) -> Result<(), TransactionValidityError> { + for_tuples!( #( Tuple::pre_dispatch_unsigned(call, info, len)?; )* ); + Ok(()) } fn post_dispatch( - pre: Self::Pre, + pre: Option, info: &DispatchInfoOf, post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, ) -> Result<(), TransactionValidityError> { - for_tuples!( #( Tuple::post_dispatch(pre.Tuple, info, post_info, len, result)?; )* ); + match pre { + Some(x) => { + for_tuples!( #( Tuple::post_dispatch(Some(x.Tuple), info, post_info, len, result)?; )* ); + }, + None => { + for_tuples!( #( Tuple::post_dispatch(None, info, post_info, len, result)?; )* ); + }, + } Ok(()) } @@ -1062,6 +1067,15 @@ impl SignedExtension for () { fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) } + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(self.validate(who, call, info, len).map(|_| ())?) + } } /// An "executable" piece of information, used by the standard Substrate Executive in order to @@ -1212,6 +1226,11 @@ impl<'a> TrailingZeroInput<'a> { pub fn new(data: &'a [u8]) -> Self { Self(data) } + + /// Create a new instance which only contains zeroes as input. + pub fn zeroes() -> Self { + Self::new(&[][..]) + } } impl<'a> codec::Input for TrailingZeroInput<'a> { @@ -1260,11 +1279,11 @@ pub trait AccountIdConversion: Sized { /// Format is TYPE_ID ++ encode(parachain ID) ++ 00.... where 00... is indefinite trailing zeroes to /// fill AccountId. -impl AccountIdConversion for Id { +impl AccountIdConversion for Id { fn into_sub_account(&self, sub: S) -> T { (Id::TYPE_ID, self, sub) .using_encoded(|b| T::decode(&mut TrailingZeroInput(b))) - .unwrap_or_default() + .expect("`AccountId` type is never greater than 32 bytes; qed") } fn try_from_sub_account(x: &T) -> Option<(Self, S)> { @@ -1317,7 +1336,7 @@ macro_rules! impl_opaque_keys_inner { ) => { $( #[ $attr ] )* #[derive( - Default, Clone, PartialEq, Eq, + Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode, $crate::scale_info::TypeInfo, @@ -1616,7 +1635,10 @@ pub trait BlockNumberProvider { mod tests { use super::*; use crate::codec::{Decode, Encode, Input}; - use sp_core::{crypto::Pair, ecdsa}; + use sp_core::{ + crypto::{Pair, UncheckedFrom}, + ecdsa, + }; mod t { use sp_application_crypto::{app_crypto, sr25519}; @@ -1629,8 +1651,8 @@ mod tests { use super::AppVerify; use t::*; - let s = Signature::default(); - let _ = s.verify(&[0u8; 100][..], &Public::default()); + let s = Signature::try_from(vec![0; 64]).unwrap(); + let _ = s.verify(&[0u8; 100][..], &Public::unchecked_from([0; 32])); } #[derive(Encode, Decode, Default, PartialEq, Debug)] diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index d0cd50394c533..e80c24b17144b 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -25,7 +25,7 @@ use parking_lot::RwLock; use sp_blockchain::CachedHeaderMetadata; use sp_runtime::{ generic::{self, BlockId}, - traits::{BlakeTwo256, Block as BlockT, Hash as HashT, Header as _}, + traits::{BlakeTwo256, Block as BlockT, Hash as HashT, Header as _, TrailingZeroInput}, transaction_validity::{ InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, @@ -370,7 +370,8 @@ impl sp_blockchain::HeaderMetadata for TestApi { /// /// Part of the test api. pub fn uxt(who: AccountKeyring, nonce: Index) -> Extrinsic { - let transfer = Transfer { from: who.into(), to: AccountId::default(), nonce, amount: 1 }; + let dummy = codec::Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap(); + let transfer = Transfer { from: who.into(), to: dummy, nonce, amount: 1 }; let signature = transfer.using_encoded(|e| who.sign(e)).into(); Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: false } } diff --git a/test-utils/test-runner/src/node.rs b/test-utils/test-runner/src/node.rs index 5fd8e4669c33d..421a4b641b59d 100644 --- a/test-utils/test-runner/src/node.rs +++ b/test-utils/test-runner/src/node.rs @@ -195,7 +195,11 @@ where { let signed_data = if let Some(signer) = signer { let extra = self.with_state(|| T::signed_extras(signer.clone())); - Some((signer.into(), MultiSignature::Sr25519(Default::default()), extra)) + Some(( + signer.into(), + MultiSignature::Sr25519(sp_core::sr25519::Signature::from_raw([0u8; 64])), + extra, + )) } else { None }; From 3cdb30e1ecbafe8a866317d4550c921b4d686869 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 13 Dec 2021 21:25:05 +0200 Subject: [PATCH 0334/1472] beefy: update CODEOWNERS (#10464) Signed-off-by: acatangiu --- docs/CODEOWNERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 42d25a0a228f7..bf9e589ff487c 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -40,6 +40,12 @@ /client/consensus/pow/ @sorpaas /primitives/consensus/pow/ @sorpaas +# BEEFY +/client/beefy/ @acatangiu +/frame/beefy/ @acatangiu +/frame/beefy-mmr/ @acatangiu +/primitives/beefy/ @acatangiu + # Contracts /frame/contracts/ @athei From 49a4b1822e19e5b82c59ba5b36a1d7997f0a3929 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 14 Dec 2021 17:26:40 +0900 Subject: [PATCH 0335/1472] Statically register host WASM functions (#10394) * Statically register host WASM functions * Fix `substrate-test-client` compilation * Move `ExtendedHostFunctions` to `sp-wasm-interface` * Fix `sp-runtime-interface` tests' compilation * Fix `sc-executor-wasmtime` tests' compilation * Use `runtime_interface` macro in `test-runner` * Fix `sc-executor` tests' compilation * Reformatting/`rustfmt` * Add an extra comment regarding the `H` generic arg in `create_runtime` * Even more `rustfmt` * Depend on `wasmtime` without default features in `sp-wasm-interface` * Bump version of `sp-wasm-interface` to 4.0.1 * Bump `sp-wasm-interface` in `Cargo.lock` too * Bump all of the `sp-wasm-interface` requirements to 4.0.1 Maybe this will appease cargo-unleash? * Revert "Bump all of the `sp-wasm-interface` requirements to 4.0.1" This reverts commit 0f7ccf8e0f371542861121b145ab87af6541ac30. * Make `cargo-unleash` happy (maybe) * Use `cargo-unleash` to bump the crates' versions * Align to review comments --- Cargo.lock | 6 +- client/allocator/Cargo.toml | 2 +- client/executor/Cargo.toml | 4 +- client/executor/common/Cargo.toml | 2 +- client/executor/runtime-test/src/lib.rs | 8 + client/executor/src/integration_tests/mod.rs | 42 ++- client/executor/src/lib.rs | 4 +- client/executor/src/native_executor.rs | 89 +++-- client/executor/src/wasm_runtime.rs | 37 +- client/executor/wasmi/Cargo.toml | 4 +- client/executor/wasmtime/Cargo.toml | 4 +- client/executor/wasmtime/src/host.rs | 16 +- client/executor/wasmtime/src/imports.rs | 241 +++++------- .../executor/wasmtime/src/instance_wrapper.rs | 13 +- client/executor/wasmtime/src/runtime.rs | 79 ++-- client/executor/wasmtime/src/tests.rs | 11 +- frame/benchmarking/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/io/Cargo.toml | 4 +- primitives/runtime-interface/Cargo.toml | 4 +- .../host_function_interface.rs | 354 ++++++++++-------- primitives/runtime-interface/src/impls.rs | 20 +- primitives/runtime-interface/src/lib.rs | 14 +- primitives/runtime-interface/src/pass_by.rs | 12 +- .../test-wasm-deprecated/Cargo.toml | 2 +- .../runtime-interface/test-wasm/Cargo.toml | 2 +- primitives/runtime-interface/test/Cargo.toml | 2 +- primitives/runtime-interface/test/src/lib.rs | 18 +- primitives/sandbox/Cargo.toml | 2 +- primitives/tasks/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 6 +- primitives/wasm-interface/src/lib.rs | 203 +++++++++- test-utils/client/src/lib.rs | 3 +- test-utils/runtime/Cargo.toml | 2 +- test-utils/test-runner/Cargo.toml | 5 + test-utils/test-runner/src/host_functions.rs | 93 ++--- 36 files changed, 743 insertions(+), 571 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4bed902878934..b576a12ea6f65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9685,7 +9685,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "4.0.0" +version = "4.1.0-dev" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -9962,12 +9962,14 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "4.0.0" +version = "4.1.0-dev" dependencies = [ "impl-trait-for-tuples", + "log 0.4.14", "parity-scale-codec", "sp-std", "wasmi", + "wasmtime", ] [[package]] diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index ea0ce3c0bbea5..eb8d298e1ec25 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -15,6 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-wasm-interface = { version = "4.0.0", path = "../../primitives/wasm-interface" } +sp-wasm-interface = { version = "4.1.0-dev", path = "../../primitives/wasm-interface" } log = "0.4.11" thiserror = "1.0.30" diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 58d7ec34b20ee..377623512fa36 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -24,8 +24,8 @@ sp-panic-handler = { version = "4.0.0-dev", path = "../../primitives/panic-handl wasmi = "0.9.1" lazy_static = "1.4.0" sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-wasm-interface = { version = "4.0.0", path = "../../primitives/wasm-interface" } -sp-runtime-interface = { version = "4.0.0", path = "../../primitives/runtime-interface" } +sp-wasm-interface = { version = "4.1.0-dev", path = "../../primitives/wasm-interface" } +sp-runtime-interface = { version = "4.1.0-dev", path = "../../primitives/runtime-interface" } sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } sc-executor-common = { version = "0.10.0-dev", path = "common" } sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index abaee76073032..5edf179c056ae 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } wasmi = "0.9.1" sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -sp-wasm-interface = { version = "4.0.0", path = "../../../primitives/wasm-interface" } +sp-wasm-interface = { version = "4.1.0-dev", path = "../../../primitives/wasm-interface" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } sp-serializer = { version = "4.0.0-dev", path = "../../../primitives/serializer" } thiserror = "1.0.30" diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 3ea6e2d7ed1aa..01e46ab946354 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -332,6 +332,14 @@ sp_core::wasm_export_functions! { fn test_panic_in_spawned() { sp_tasks::spawn(tasks::panicker, vec![]).join(); } + + fn test_return_i8() -> i8 { + -66 + } + + fn test_take_i8(value: i8) { + assert_eq!(value, -66); + } } #[cfg(not(feature = "std"))] diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 3ff0ecebd9acf..b2b31679926c2 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -34,7 +34,6 @@ use sp_core::{ use sp_runtime::traits::BlakeTwo256; use sp_state_machine::TestExternalities as CoreTestExternalities; use sp_trie::{trie_types::Layout, TrieConfiguration}; -use sp_wasm_interface::HostFunctions as _; use std::sync::Arc; use tracing_subscriber::layer::SubscriberExt; @@ -124,14 +123,8 @@ fn call_in_wasm( execution_method: WasmExecutionMethod, ext: &mut E, ) -> Result, String> { - let executor = crate::WasmExecutor::new( - execution_method, - Some(1024), - HostFunctions::host_functions(), - 8, - None, - 2, - ); + let executor = + crate::WasmExecutor::::new(execution_method, Some(1024), 8, None, 2); executor.uncached_call( RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(), ext, @@ -475,10 +468,9 @@ test_wasm_execution!(should_trap_when_heap_exhausted); fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { let mut ext = TestExternalities::default(); - let executor = crate::WasmExecutor::new( + let executor = crate::WasmExecutor::::new( wasm_method, Some(17), // `17` is the initial number of pages compiled into the binary. - HostFunctions::host_functions(), 8, None, 2, @@ -501,11 +493,10 @@ fn mk_test_runtime(wasm_method: WasmExecutionMethod, pages: u64) -> Arc( wasm_method, pages, blob, - HostFunctions::host_functions(), true, None, ) @@ -589,10 +580,9 @@ fn heap_is_reset_between_calls(wasm_method: WasmExecutionMethod) { test_wasm_execution!(parallel_execution); fn parallel_execution(wasm_method: WasmExecutionMethod) { - let executor = std::sync::Arc::new(crate::WasmExecutor::new( + let executor = std::sync::Arc::new(crate::WasmExecutor::::new( wasm_method, Some(1024), - HostFunctions::host_functions(), 8, None, 2, @@ -763,11 +753,10 @@ fn memory_is_cleared_between_invocations(wasm_method: WasmExecutionMethod) { ) )"#).unwrap(); - let runtime = crate::wasm_runtime::create_wasm_runtime_with_code( + let runtime = crate::wasm_runtime::create_wasm_runtime_with_code::( wasm_method, 1024, RuntimeBlob::uncompress_if_needed(&binary[..]).unwrap(), - HostFunctions::host_functions(), true, None, ) @@ -780,3 +769,22 @@ fn memory_is_cleared_between_invocations(wasm_method: WasmExecutionMethod) { let res = instance.call_export("returns_no_bss_mutable_static", &[0]).unwrap(); assert_eq!(1, u64::decode(&mut &res[..]).unwrap()); } + +test_wasm_execution!(return_i8); +fn return_i8(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + + assert_eq!( + call_in_wasm("test_return_i8", &[], wasm_method, &mut ext).unwrap(), + (-66_i8).encode() + ); +} + +test_wasm_execution!(take_i8); +fn take_i8(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + + call_in_wasm("test_take_i8", &(-66_i8).encode(), wasm_method, &mut ext).unwrap(); +} diff --git a/client/executor/src/lib.rs b/client/executor/src/lib.rs index 9a4d8e3cf0b6a..8bac541afc37d 100644 --- a/client/executor/src/lib.rs +++ b/client/executor/src/lib.rs @@ -67,17 +67,15 @@ mod tests { use sc_executor_common::runtime_blob::RuntimeBlob; use sc_runtime_test::wasm_binary_unwrap; use sp_io::TestExternalities; - use sp_wasm_interface::HostFunctions; #[test] fn call_in_interpreted_wasm_works() { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); - let executor = WasmExecutor::new( + let executor = WasmExecutor::::new( WasmExecutionMethod::Interpreted, Some(8), - sp_io::SubstrateHostFunctions::host_functions(), 8, None, 2, diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 1c01520ac9c8e..60e661d10da67 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -24,6 +24,7 @@ use crate::{ use std::{ collections::HashMap, + marker::PhantomData, panic::{AssertUnwindSafe, UnwindSafe}, path::PathBuf, result, @@ -46,7 +47,7 @@ use sp_core::{ use sp_externalities::ExternalitiesExt as _; use sp_tasks::new_async_externalities; use sp_version::{GetNativeVersion, NativeVersion, RuntimeVersion}; -use sp_wasm_interface::{Function, HostFunctions}; +use sp_wasm_interface::{ExtendedHostFunctions, HostFunctions}; /// Default num of pages for the heap const DEFAULT_HEAP_PAGES: u64 = 2048; @@ -91,22 +92,36 @@ pub trait NativeExecutionDispatch: Send + Sync { /// An abstraction over Wasm code executor. Supports selecting execution backend and /// manages runtime cache. -#[derive(Clone)] -pub struct WasmExecutor { +pub struct WasmExecutor { /// Method used to execute fallback Wasm code. method: WasmExecutionMethod, /// The number of 64KB pages to allocate for Wasm execution. default_heap_pages: u64, - /// The host functions registered with this instance. - host_functions: Arc>, /// WASM runtime cache. cache: Arc, /// The path to a directory which the executor can leverage for a file cache, e.g. put there /// compiled artifacts. cache_path: Option, + + phantom: PhantomData, +} + +impl Clone for WasmExecutor { + fn clone(&self) -> Self { + Self { + method: self.method, + default_heap_pages: self.default_heap_pages, + cache: self.cache.clone(), + cache_path: self.cache_path.clone(), + phantom: self.phantom, + } + } } -impl WasmExecutor { +impl WasmExecutor +where + H: HostFunctions, +{ /// Create new instance. /// /// # Parameters @@ -127,7 +142,6 @@ impl WasmExecutor { pub fn new( method: WasmExecutionMethod, default_heap_pages: Option, - host_functions: Vec<&'static dyn Function>, max_runtime_instances: usize, cache_path: Option, runtime_cache_size: u8, @@ -135,13 +149,13 @@ impl WasmExecutor { WasmExecutor { method, default_heap_pages: default_heap_pages.unwrap_or(DEFAULT_HEAP_PAGES), - host_functions: Arc::new(host_functions), cache: Arc::new(RuntimeCache::new( max_runtime_instances, cache_path.clone(), runtime_cache_size, )), cache_path, + phantom: PhantomData, } } @@ -173,12 +187,11 @@ impl WasmExecutor { AssertUnwindSafe<&mut dyn Externalities>, ) -> Result>, { - match self.cache.with_instance( + match self.cache.with_instance::( runtime_code, ext, self.method, self.default_heap_pages, - &*self.host_functions, allow_missing_host_functions, |module, instance, version, ext| { let module = AssertUnwindSafe(module); @@ -208,11 +221,10 @@ impl WasmExecutor { export_name: &str, call_data: &[u8], ) -> std::result::Result, String> { - let module = crate::wasm_runtime::create_wasm_runtime_with_code( + let module = crate::wasm_runtime::create_wasm_runtime_with_code::( self.method, self.default_heap_pages, runtime_blob, - self.host_functions.to_vec(), allow_missing_host_functions, self.cache_path.as_deref(), ) @@ -235,7 +247,10 @@ impl WasmExecutor { } } -impl sp_core::traits::ReadRuntimeVersion for WasmExecutor { +impl sp_core::traits::ReadRuntimeVersion for WasmExecutor +where + H: HostFunctions, +{ fn read_runtime_version( &self, wasm_code: &[u8], @@ -269,7 +284,10 @@ impl sp_core::traits::ReadRuntimeVersion for WasmExecutor { } } -impl CodeExecutor for WasmExecutor { +impl CodeExecutor for WasmExecutor +where + H: HostFunctions, +{ type Error = Error; fn call< @@ -299,7 +317,10 @@ impl CodeExecutor for WasmExecutor { } } -impl RuntimeVersionOf for WasmExecutor { +impl RuntimeVersionOf for WasmExecutor +where + H: HostFunctions, +{ fn runtime_version( &self, ext: &mut dyn Externalities, @@ -313,13 +334,17 @@ impl RuntimeVersionOf for WasmExecutor { /// A generic `CodeExecutor` implementation that uses a delegate to determine wasm code equivalence /// and dispatch to native code when possible, falling back on `WasmExecutor` when not. -pub struct NativeElseWasmExecutor { +pub struct NativeElseWasmExecutor +where + D: NativeExecutionDispatch, +{ /// Dummy field to avoid the compiler complaining about us not using `D`. _dummy: std::marker::PhantomData, /// Native runtime version info. native_version: NativeVersion, /// Fallback wasm executor. - wasm: WasmExecutor, + wasm: + WasmExecutor>, } impl NativeElseWasmExecutor { @@ -337,24 +362,9 @@ impl NativeElseWasmExecutor { max_runtime_instances: usize, runtime_cache_size: u8, ) -> Self { - let extended = D::ExtendHostFunctions::host_functions(); - let mut host_functions = sp_io::SubstrateHostFunctions::host_functions() - .into_iter() - // filter out any host function overrides provided. - .filter(|host_fn| { - extended - .iter() - .find(|ext_host_fn| host_fn.name() == ext_host_fn.name()) - .is_none() - }) - .collect::>(); - - // Add the custom host functions provided by the user. - host_functions.extend(extended); let wasm_executor = WasmExecutor::new( fallback_method, default_heap_pages, - host_functions, max_runtime_instances, None, runtime_cache_size, @@ -645,8 +655,21 @@ mod tests { 8, 2, ); + + fn extract_host_functions( + _: &WasmExecutor, + ) -> Vec<&'static dyn sp_wasm_interface::Function> + where + H: HostFunctions, + { + H::host_functions() + } + my_interface::HostFunctions::host_functions().iter().for_each(|function| { - assert_eq!(executor.wasm.host_functions.iter().filter(|f| f == &function).count(), 2); + assert_eq!( + extract_host_functions(&executor.wasm).iter().filter(|f| f == &function).count(), + 2 + ); }); my_interface::say_hello_world("hey"); diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 44ed6eb32304b..cebfc7b01b8d8 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -37,7 +37,7 @@ use std::{ sync::Arc, }; -use sp_wasm_interface::Function; +use sp_wasm_interface::HostFunctions; /// Specification of different methods of executing the runtime Wasm code. #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] @@ -199,14 +199,14 @@ impl RuntimeCache { /// /// `wasm_method` - Type of WASM backend to use. /// - /// `host_functions` - The host functions that should be registered for the Wasm runtime. - /// /// `allow_missing_func_imports` - Ignore missing function imports. /// /// `max_runtime_instances` - The size of the instances cache. /// /// `f` - Function to execute. /// + /// `H` - A compile-time list of host functions to expose to the runtime. + /// /// # Returns result of `f` wrapped in an additional result. /// In case of failure one of two errors can be returned: /// @@ -214,17 +214,17 @@ impl RuntimeCache { /// /// `Error::InvalidMemoryReference` is returned if no memory export with the /// identifier `memory` can be found in the runtime. - pub fn with_instance<'c, R, F>( + pub fn with_instance<'c, H, R, F>( &self, runtime_code: &'c RuntimeCode<'c>, ext: &mut dyn Externalities, wasm_method: WasmExecutionMethod, default_heap_pages: u64, - host_functions: &[&'static dyn Function], allow_missing_func_imports: bool, f: F, ) -> Result, Error> where + H: HostFunctions, F: FnOnce( &Arc, &mut dyn WasmInstance, @@ -247,12 +247,11 @@ impl RuntimeCache { let time = std::time::Instant::now(); - let result = create_versioned_wasm_runtime( + let result = create_versioned_wasm_runtime::( &code, ext, wasm_method, heap_pages, - host_functions.into(), allow_missing_func_imports, self.max_runtime_instances, self.cache_path.as_deref(), @@ -288,14 +287,16 @@ impl RuntimeCache { } /// Create a wasm runtime with the given `code`. -pub fn create_wasm_runtime_with_code( +pub fn create_wasm_runtime_with_code( wasm_method: WasmExecutionMethod, heap_pages: u64, blob: RuntimeBlob, - host_functions: Vec<&'static dyn Function>, allow_missing_func_imports: bool, cache_path: Option<&Path>, -) -> Result, WasmError> { +) -> Result, WasmError> +where + H: HostFunctions, +{ match wasm_method { WasmExecutionMethod::Interpreted => { // Wasmi doesn't have any need in a cache directory. @@ -307,13 +308,13 @@ pub fn create_wasm_runtime_with_code( sc_executor_wasmi::create_runtime( blob, heap_pages, - host_functions, + H::host_functions(), allow_missing_func_imports, ) .map(|runtime| -> Arc { Arc::new(runtime) }) }, #[cfg(feature = "wasmtime")] - WasmExecutionMethod::Compiled => sc_executor_wasmtime::create_runtime( + WasmExecutionMethod::Compiled => sc_executor_wasmtime::create_runtime::( blob, sc_executor_wasmtime::Config { heap_pages, @@ -327,7 +328,6 @@ pub fn create_wasm_runtime_with_code( parallel_compilation: true, }, }, - host_functions, ) .map(|runtime| -> Arc { Arc::new(runtime) }), } @@ -392,16 +392,18 @@ pub fn read_embedded_version(blob: &RuntimeBlob) -> Result( code: &[u8], ext: &mut dyn Externalities, wasm_method: WasmExecutionMethod, heap_pages: u64, - host_functions: Vec<&'static dyn Function>, allow_missing_func_imports: bool, max_instances: usize, cache_path: Option<&Path>, -) -> Result { +) -> Result +where + H: HostFunctions, +{ // The incoming code may be actually compressed. We decompress it here and then work with // the uncompressed code from now on. let blob = sc_executor_common::runtime_blob::RuntimeBlob::uncompress_if_needed(&code)?; @@ -411,11 +413,10 @@ fn create_versioned_wasm_runtime( // runtime. let mut version: Option<_> = read_embedded_version(&blob)?; - let runtime = create_wasm_runtime_with_code( + let runtime = create_wasm_runtime_with_code::( wasm_method, heap_pages, blob, - host_functions, allow_missing_func_imports, cache_path, )?; diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index d50237edfe4a0..9dc63747166b5 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -19,7 +19,7 @@ wasmi = "0.9.1" codec = { package = "parity-scale-codec", version = "2.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -sp-wasm-interface = { version = "4.0.0", path = "../../../primitives/wasm-interface" } -sp-runtime-interface = { version = "4.0.0", path = "../../../primitives/runtime-interface" } +sp-wasm-interface = { version = "4.1.0-dev", path = "../../../primitives/wasm-interface" } +sp-runtime-interface = { version = "4.1.0-dev", path = "../../../primitives/runtime-interface" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } scoped-tls = "1.0" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 49e44766b9d47..06f668ef67b4d 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -19,8 +19,8 @@ log = "0.4.8" parity-wasm = "0.42.0" codec = { package = "parity-scale-codec", version = "2.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } -sp-wasm-interface = { version = "4.0.0", path = "../../../primitives/wasm-interface" } -sp-runtime-interface = { version = "4.0.0", path = "../../../primitives/runtime-interface" } +sp-wasm-interface = { version = "4.1.0-dev", path = "../../../primitives/wasm-interface", features = ["wasmtime"] } +sp-runtime-interface = { version = "4.1.0-dev", path = "../../../primitives/runtime-interface" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } wasmtime = { version = "0.31.0", default-features = false, features = [ diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index 39ee9ced80af7..ab8b4cf8b73c0 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -62,11 +62,11 @@ impl HostState { /// A `HostContext` implements `FunctionContext` for making host calls from a Wasmtime /// runtime. The `HostContext` exists only for the lifetime of the call and borrows state from /// a longer-living `HostState`. -pub(crate) struct HostContext<'a, 'b> { - pub(crate) caller: &'a mut Caller<'b, StoreData>, +pub(crate) struct HostContext<'a> { + pub(crate) caller: Caller<'a, StoreData>, } -impl<'a, 'b> HostContext<'a, 'b> { +impl<'a> HostContext<'a> { fn host_state(&self) -> &HostState { self.caller .data() @@ -98,7 +98,7 @@ impl<'a, 'b> HostContext<'a, 'b> { } } -impl<'a, 'b> sp_wasm_interface::FunctionContext for HostContext<'a, 'b> { +impl<'a> sp_wasm_interface::FunctionContext for HostContext<'a> { fn read_memory_into( &self, address: Pointer, @@ -136,7 +136,7 @@ impl<'a, 'b> sp_wasm_interface::FunctionContext for HostContext<'a, 'b> { } } -impl<'a, 'b> Sandbox for HostContext<'a, 'b> { +impl<'a> Sandbox for HostContext<'a> { fn memory_get( &mut self, memory_id: MemoryId, @@ -320,12 +320,12 @@ impl<'a, 'b> Sandbox for HostContext<'a, 'b> { } } -struct SandboxContext<'a, 'b, 'c> { - host_context: &'a mut HostContext<'b, 'c>, +struct SandboxContext<'a, 'b> { + host_context: &'a mut HostContext<'b>, dispatch_thunk: Func, } -impl<'a, 'b, 'c> sandbox::SandboxContext for SandboxContext<'a, 'b, 'c> { +impl<'a, 'b> sandbox::SandboxContext for SandboxContext<'a, 'b> { fn invoke( &mut self, invoke_args_ptr: Pointer, diff --git a/client/executor/wasmtime/src/imports.rs b/client/executor/wasmtime/src/imports.rs index 57ce48f537e94..c18cf58ac722e 100644 --- a/client/executor/wasmtime/src/imports.rs +++ b/client/executor/wasmtime/src/imports.rs @@ -19,14 +19,11 @@ use crate::{ host::HostContext, runtime::{Store, StoreData}, - util, }; use sc_executor_common::error::WasmError; -use sp_wasm_interface::{Function, ValueType}; -use std::{any::Any, convert::TryInto}; -use wasmtime::{ - Caller, Extern, ExternType, Func, FuncType, ImportType, Memory, MemoryType, Module, Trap, Val, -}; +use sp_wasm_interface::{FunctionContext, HostFunctions}; +use std::{collections::HashMap, convert::TryInto}; +use wasmtime::{Extern, ExternType, Func, FuncType, ImportType, Memory, MemoryType, Module, Trap}; pub struct Imports { /// Contains the index into `externs` where the memory import is stored if any. `None` if there @@ -37,16 +34,19 @@ pub struct Imports { /// Goes over all imports of a module and prepares a vector of `Extern`s that can be used for /// instantiation of the module. Returns an error if there are imports that cannot be satisfied. -pub(crate) fn resolve_imports( +pub(crate) fn resolve_imports( store: &mut Store, module: &Module, - host_functions: &[&'static dyn Function], heap_pages: u64, allow_missing_func_imports: bool, -) -> Result { +) -> Result +where + H: HostFunctions, +{ let mut externs = vec![]; let mut memory_import_index = None; - for import_ty in module.imports() { + let mut pending_func_imports = HashMap::new(); + for (index, import_ty) in module.imports().enumerate() { let name = import_name(&import_ty)?; if import_ty.module() != "env" { @@ -57,19 +57,89 @@ pub(crate) fn resolve_imports( ))) } - let resolved = match name { - "memory" => { - memory_import_index = Some(externs.len()); - resolve_memory_import(store, &import_ty, heap_pages)? + if name == "memory" { + memory_import_index = Some(index); + externs.push((index, resolve_memory_import(store, &import_ty, heap_pages)?)); + continue + } + + match import_ty.ty() { + ExternType::Func(func_ty) => { + pending_func_imports.insert(name.to_owned(), (index, import_ty, func_ty)); }, _ => - resolve_func_import(store, &import_ty, host_functions, allow_missing_func_imports)?, + return Err(WasmError::Other(format!( + "host doesn't provide any non function imports besides 'memory': {}:{}", + import_ty.module(), + name, + ))), }; - externs.push(resolved); } + + let mut registry = Registry { store, externs, pending_func_imports }; + + H::register_static(&mut registry)?; + let mut externs = registry.externs; + + if !registry.pending_func_imports.is_empty() { + if allow_missing_func_imports { + for (_, (index, import_ty, func_ty)) in registry.pending_func_imports { + externs.push(( + index, + MissingHostFuncHandler::new(&import_ty)?.into_extern(store, &func_ty), + )); + } + } else { + let mut names = Vec::new(); + for (name, (_, import_ty, _)) in registry.pending_func_imports { + names.push(format!("'{}:{}'", import_ty.module(), name)); + } + let names = names.join(", "); + return Err(WasmError::Other(format!( + "runtime requires function imports which are not present on the host: {}", + names + ))) + } + } + + externs.sort_unstable_by_key(|&(index, _)| index); + let externs = externs.into_iter().map(|(_, ext)| ext).collect(); + Ok(Imports { memory_import_index, externs }) } +struct Registry<'a, 'b> { + store: &'a mut Store, + externs: Vec<(usize, Extern)>, + pending_func_imports: HashMap, FuncType)>, +} + +impl<'a, 'b> sp_wasm_interface::HostFunctionRegistry for Registry<'a, 'b> { + type State = StoreData; + type Error = WasmError; + type FunctionContext = HostContext<'a>; + + fn with_function_context( + caller: wasmtime::Caller, + callback: impl FnOnce(&mut dyn FunctionContext) -> R, + ) -> R { + callback(&mut HostContext { caller }) + } + + fn register_static( + &mut self, + fn_name: &str, + func: impl wasmtime::IntoFunc, + ) -> Result<(), Self::Error> { + if let Some((index, _, _)) = self.pending_func_imports.remove(fn_name) { + let func = Func::wrap(&mut *self.store, func); + self.externs.push((index, Extern::Func(func))); + } + + Ok(()) + } +} + /// When the module linking proposal is supported the import's name can be `None`. /// Because we are not using this proposal we could safely unwrap the name. /// However, we opt for an error in order to avoid panics at all costs. @@ -139,115 +209,6 @@ fn resolve_memory_import( Ok(Extern::Memory(memory)) } -fn resolve_func_import( - store: &mut Store, - import_ty: &ImportType, - host_functions: &[&'static dyn Function], - allow_missing_func_imports: bool, -) -> Result { - let name = import_name(&import_ty)?; - - let func_ty = match import_ty.ty() { - ExternType::Func(func_ty) => func_ty, - _ => - return Err(WasmError::Other(format!( - "host doesn't provide any non function imports besides 'memory': {}:{}", - import_ty.module(), - name, - ))), - }; - - let host_func = match host_functions.iter().find(|host_func| host_func.name() == name) { - Some(host_func) => host_func, - None if allow_missing_func_imports => - return Ok(MissingHostFuncHandler::new(import_ty)?.into_extern(store, &func_ty)), - None => - return Err(WasmError::Other(format!( - "host doesn't provide such function: {}:{}", - import_ty.module(), - name, - ))), - }; - if &func_ty != &wasmtime_func_sig(*host_func) { - return Err(WasmError::Other(format!( - "signature mismatch for: {}:{}", - import_ty.module(), - name, - ))) - } - - Ok(HostFuncHandler::new(*host_func).into_extern(store)) -} - -/// This structure implements `Callable` and acts as a bridge between wasmtime and -/// substrate host functions. -struct HostFuncHandler { - host_func: &'static dyn Function, -} - -fn call_static<'a>( - static_func: &'static dyn Function, - wasmtime_params: &[Val], - wasmtime_results: &mut [Val], - mut caller: Caller<'a, StoreData>, -) -> Result<(), wasmtime::Trap> { - let unwind_result = { - let mut host_ctx = HostContext { caller: &mut caller }; - - // `from_wasmtime_val` panics if it encounters a value that doesn't fit into the values - // available in substrate. - // - // This, however, cannot happen since the signature of this function is created from - // a `dyn Function` signature of which cannot have a non substrate value by definition. - let mut params = wasmtime_params.iter().cloned().map(util::from_wasmtime_val); - - std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - static_func.execute(&mut host_ctx, &mut params) - })) - }; - - let execution_result = match unwind_result { - Ok(execution_result) => execution_result, - Err(err) => return Err(Trap::new(stringify_panic_payload(err))), - }; - - match execution_result { - Ok(Some(ret_val)) => { - debug_assert!( - wasmtime_results.len() == 1, - "wasmtime function signature, therefore the number of results, should always \ - correspond to the number of results returned by the host function", - ); - wasmtime_results[0] = util::into_wasmtime_val(ret_val); - Ok(()) - }, - Ok(None) => { - debug_assert!( - wasmtime_results.len() == 0, - "wasmtime function signature, therefore the number of results, should always \ - correspond to the number of results returned by the host function", - ); - Ok(()) - }, - Err(msg) => Err(Trap::new(msg)), - } -} - -impl HostFuncHandler { - fn new(host_func: &'static dyn Function) -> Self { - Self { host_func } - } - - fn into_extern(self, store: &mut Store) -> Extern { - let host_func = self.host_func; - let func_ty = wasmtime_func_sig(self.host_func); - let func = Func::new(store, func_ty, move |caller, params, result| { - call_static(host_func, params, result, caller) - }); - Extern::Func(func) - } -} - /// A `Callable` handler for missing functions. struct MissingHostFuncHandler { module: String, @@ -270,33 +231,3 @@ impl MissingHostFuncHandler { Extern::Func(func) } } - -fn wasmtime_func_sig(func: &dyn Function) -> wasmtime::FuncType { - let signature = func.signature(); - let params = signature.args.iter().cloned().map(into_wasmtime_val_type); - - let results = signature.return_value.iter().cloned().map(into_wasmtime_val_type); - - wasmtime::FuncType::new(params, results) -} - -fn into_wasmtime_val_type(val_ty: ValueType) -> wasmtime::ValType { - match val_ty { - ValueType::I32 => wasmtime::ValType::I32, - ValueType::I64 => wasmtime::ValType::I64, - ValueType::F32 => wasmtime::ValType::F32, - ValueType::F64 => wasmtime::ValType::F64, - } -} - -/// Attempt to convert a opaque panic payload to a string. -fn stringify_panic_payload(payload: Box) -> String { - match payload.downcast::<&'static str>() { - Ok(msg) => msg.to_string(), - Err(payload) => match payload.downcast::() { - Ok(msg) => *msg, - // At least we tried... - Err(_) => "Box".to_string(), - }, - } -} diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index e9b18d8c2b89d..58f96eb26363e 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -24,7 +24,7 @@ use sc_executor_common::{ error::{Error, Result}, wasm_runtime::InvokeMethod, }; -use sp_wasm_interface::{Function, Pointer, Value, WordSize}; +use sp_wasm_interface::{HostFunctions, Pointer, Value, WordSize}; use wasmtime::{ AsContext, AsContextMut, Extern, Func, Global, Instance, Memory, Module, Table, Val, }; @@ -138,13 +138,15 @@ fn extern_func(extern_: &Extern) -> Option<&Func> { impl InstanceWrapper { /// Create a new instance wrapper from the given wasm module. - pub fn new( + pub fn new( module: &Module, - host_functions: &[&'static dyn Function], heap_pages: u64, allow_missing_func_imports: bool, max_memory_size: Option, - ) -> Result { + ) -> Result + where + H: HostFunctions, + { let limits = if let Some(max_memory_size) = max_memory_size { wasmtime::StoreLimitsBuilder::new().memory_size(max_memory_size).build() } else { @@ -161,10 +163,9 @@ impl InstanceWrapper { // Scan all imports, find the matching host functions, and create stubs that adapt arguments // and results. - let imports = crate::imports::resolve_imports( + let imports = crate::imports::resolve_imports::( &mut store, module, - host_functions, heap_pages, allow_missing_func_imports, )?; diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 606401132e9e9..b870405f92d3d 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -23,6 +23,7 @@ use crate::{ instance_wrapper::{EntryPoint, InstanceWrapper}, util, }; +use core::marker::PhantomData; use sc_allocator::FreeingBumpHeapAllocator; use sc_executor_common::{ @@ -33,7 +34,7 @@ use sc_executor_common::{ wasm_runtime::{InvokeMethod, WasmInstance, WasmModule}, }; use sp_runtime_interface::unpack_ptr_and_len; -use sp_wasm_interface::{Function, Pointer, Value, WordSize}; +use sp_wasm_interface::{HostFunctions, Pointer, Value, WordSize}; use std::{ path::{Path, PathBuf}, sync::{ @@ -79,29 +80,31 @@ impl StoreData { pub(crate) type Store = wasmtime::Store; -enum Strategy { +enum Strategy { FastInstanceReuse { instance_wrapper: InstanceWrapper, globals_snapshot: GlobalsSnapshot, data_segments_snapshot: Arc, heap_base: u32, }, - RecreateInstance(InstanceCreator), + RecreateInstance(InstanceCreator), } -struct InstanceCreator { +struct InstanceCreator { module: Arc, - host_functions: Vec<&'static dyn Function>, heap_pages: u64, allow_missing_func_imports: bool, max_memory_size: Option, + phantom: PhantomData, } -impl InstanceCreator { +impl InstanceCreator +where + H: HostFunctions, +{ fn instantiate(&mut self) -> Result { - InstanceWrapper::new( + InstanceWrapper::new::( &*self.module, - &self.host_functions, self.heap_pages, self.allow_missing_func_imports, self.max_memory_size, @@ -141,19 +144,21 @@ struct InstanceSnapshotData { /// A `WasmModule` implementation using wasmtime to compile the runtime module to machine code /// and execute the compiled code. -pub struct WasmtimeRuntime { +pub struct WasmtimeRuntime { module: Arc, snapshot_data: Option, config: Config, - host_functions: Vec<&'static dyn Function>, + phantom: PhantomData, } -impl WasmModule for WasmtimeRuntime { +impl WasmModule for WasmtimeRuntime +where + H: HostFunctions, +{ fn new_instance(&self) -> Result> { let strategy = if let Some(ref snapshot_data) = self.snapshot_data { - let mut instance_wrapper = InstanceWrapper::new( + let mut instance_wrapper = InstanceWrapper::new::( &self.module, - &self.host_functions, self.config.heap_pages, self.config.allow_missing_func_imports, self.config.max_memory_size, @@ -169,19 +174,19 @@ impl WasmModule for WasmtimeRuntime { &mut InstanceGlobals { instance: &mut instance_wrapper }, ); - Strategy::FastInstanceReuse { + Strategy::::FastInstanceReuse { instance_wrapper, globals_snapshot, data_segments_snapshot: snapshot_data.data_segments_snapshot.clone(), heap_base, } } else { - Strategy::RecreateInstance(InstanceCreator { + Strategy::::RecreateInstance(InstanceCreator { module: self.module.clone(), - host_functions: self.host_functions.clone(), heap_pages: self.config.heap_pages, allow_missing_func_imports: self.config.allow_missing_func_imports, max_memory_size: self.config.max_memory_size, + phantom: PhantomData, }) }; @@ -191,11 +196,14 @@ impl WasmModule for WasmtimeRuntime { /// A `WasmInstance` implementation that reuses compiled module and spawns instances /// to execute the compiled code. -pub struct WasmtimeInstance { - strategy: Strategy, +pub struct WasmtimeInstance { + strategy: Strategy, } -impl WasmInstance for WasmtimeInstance { +impl WasmInstance for WasmtimeInstance +where + H: HostFunctions, +{ fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result> { match &mut self.strategy { Strategy::FastInstanceReuse { @@ -483,13 +491,18 @@ enum CodeSupplyMode<'a> { /// Create a new `WasmtimeRuntime` given the code. This function performs translation from Wasm to /// machine code, which can be computationally heavy. -pub fn create_runtime( +/// +/// The `H` generic parameter is used to statically pass a set of host functions which are exposed +/// to the runtime. +pub fn create_runtime( blob: RuntimeBlob, config: Config, - host_functions: Vec<&'static dyn Function>, -) -> std::result::Result { +) -> std::result::Result, WasmError> +where + H: HostFunctions, +{ // SAFETY: this is safe because it doesn't use `CodeSupplyMode::Artifact`. - unsafe { do_create_runtime(CodeSupplyMode::Verbatim { blob }, config, host_functions) } + unsafe { do_create_runtime::(CodeSupplyMode::Verbatim { blob }, config) } } /// The same as [`create_runtime`] but takes a precompiled artifact, which makes this function @@ -503,23 +516,27 @@ pub fn create_runtime( /// /// It is ok though if the `compiled_artifact` was created by code of another version or with /// different configuration flags. In such case the caller will receive an `Err` deterministically. -pub unsafe fn create_runtime_from_artifact( +pub unsafe fn create_runtime_from_artifact( compiled_artifact: &[u8], config: Config, - host_functions: Vec<&'static dyn Function>, -) -> std::result::Result { - do_create_runtime(CodeSupplyMode::Artifact { compiled_artifact }, config, host_functions) +) -> std::result::Result, WasmError> +where + H: HostFunctions, +{ + do_create_runtime::(CodeSupplyMode::Artifact { compiled_artifact }, config) } /// # Safety /// /// This is only unsafe if called with [`CodeSupplyMode::Artifact`]. See /// [`create_runtime_from_artifact`] to get more details. -unsafe fn do_create_runtime( +unsafe fn do_create_runtime( code_supply_mode: CodeSupplyMode<'_>, config: Config, - host_functions: Vec<&'static dyn Function>, -) -> std::result::Result { +) -> std::result::Result, WasmError> +where + H: HostFunctions, +{ // Create the engine, store and finally the module from the given code. let mut wasmtime_config = common_config(&config.semantics)?; if let Some(ref cache_path) = config.cache_path { @@ -566,7 +583,7 @@ unsafe fn do_create_runtime( }, }; - Ok(WasmtimeRuntime { module: Arc::new(module), snapshot_data, config, host_functions }) + Ok(WasmtimeRuntime { module: Arc::new(module), snapshot_data, config, phantom: PhantomData }) } fn instrument( diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index c34cbfad11138..31fb5d3da1c72 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -78,7 +78,7 @@ impl RuntimeBuilder { .expect("failed to create a runtime blob out of test runtime") }; - let rt = crate::create_runtime( + let rt = crate::create_runtime::( blob, crate::Config { heap_pages: self.heap_pages, @@ -98,10 +98,6 @@ impl RuntimeBuilder { parallel_compilation: true, }, }, - { - use sp_wasm_interface::HostFunctions as _; - HostFunctions::host_functions() - }, ) .expect("cannot create runtime"); @@ -316,9 +312,7 @@ fn test_max_memory_pages() { #[cfg_attr(build_type = "debug", ignore)] #[test] fn test_instances_without_reuse_are_not_leaked() { - use sp_wasm_interface::HostFunctions; - - let runtime = crate::create_runtime( + let runtime = crate::create_runtime::( RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(), crate::Config { heap_pages: 2048, @@ -332,7 +326,6 @@ fn test_instances_without_reuse_are_not_leaked() { parallel_compilation: true, }, }, - sp_io::SubstrateHostFunctions::host_functions(), ) .unwrap(); diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index d907cf71948f0..1e89c39be1c4e 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -18,7 +18,7 @@ paste = "1.0" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } -sp-runtime-interface = { version = "4.0.0", path = "../../primitives/runtime-interface", default-features = false } +sp-runtime-interface = { version = "4.1.0-dev", path = "../../primitives/runtime-interface", default-features = false } sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index a078cc09aafc3..330dd57e817f6 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -69,7 +69,7 @@ libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", merlin = { version = "2.0", default-features = false, optional = true } ss58-registry = { version = "1.5.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } -sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../runtime-interface" } +sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../runtime-interface" } [dev-dependencies] sp-serializer = { version = "4.0.0-dev", path = "../serializer" } diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 4485a8a7f45a2..4364202618008 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -22,8 +22,8 @@ sp-keystore = { version = "0.10.0-dev", default-features = false, optional = tru sp-std = { version = "4.0.0", default-features = false, path = "../std" } libsecp256k1 = { version = "0.7", optional = true } sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../state-machine" } -sp-wasm-interface = { version = "4.0.0", path = "../wasm-interface", default-features = false } -sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../runtime-interface" } +sp-wasm-interface = { version = "4.1.0-dev", path = "../wasm-interface", default-features = false } +sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../runtime-interface" } sp-trie = { version = "4.0.0-dev", optional = true, path = "../trie" } sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 6b120ab50c502..9ff17b1dff0f0 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime-interface" -version = "4.0.0" +version = "4.1.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-wasm-interface = { version = "4.0.0", path = "../wasm-interface", default-features = false } +sp-wasm-interface = { version = "4.1.0-dev", path = "../wasm-interface", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } sp-runtime-interface-proc-macro = { version = "4.0.0", path = "proc-macro" } diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs index 75498c09c18c7..c79886d45b18c 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs @@ -35,11 +35,11 @@ use syn::{ use proc_macro2::{Span, TokenStream}; -use quote::{quote, ToTokens}; +use quote::quote; use inflector::Inflector; -use std::iter::{self, Iterator}; +use std::iter::Iterator; /// Generate the extern host functions for wasm and the `HostFunctions` struct that provides the /// implementations for the host functions on the host. @@ -163,14 +163,20 @@ fn generate_host_functions_struct( ) -> Result { let crate_ = generate_crate_access(); - let host_functions = get_runtime_interface(trait_def)? - .all_versions() - .map(|(version, method)| { - generate_host_function_implementation(&trait_def.ident, method, version, is_wasm_only) - }) - .collect::>>()?; + let mut host_function_impls = Vec::new(); + let mut host_function_names = Vec::new(); + let mut register_bodies = Vec::new(); + for (version, method) in get_runtime_interface(trait_def)?.all_versions() { + let (implementation, name, register_body) = + generate_host_function_implementation(&trait_def.ident, method, version, is_wasm_only)?; + host_function_impls.push(implementation); + host_function_names.push(name); + register_bodies.push(register_body); + } Ok(quote! { + #(#host_function_impls)* + /// Provides implementations for the extern host functions. #[cfg(feature = "std")] pub struct HostFunctions; @@ -178,7 +184,16 @@ fn generate_host_functions_struct( #[cfg(feature = "std")] impl #crate_::sp_wasm_interface::HostFunctions for HostFunctions { fn host_functions() -> Vec<&'static dyn #crate_::sp_wasm_interface::Function> { - vec![ #( #host_functions ),* ] + vec![ #( &#host_function_names as &dyn #crate_::sp_wasm_interface::Function ),* ] + } + + #crate_::sp_wasm_interface::if_wasmtime_is_enabled! { + fn register_static(registry: &mut T) -> core::result::Result<(), T::Error> + where T: #crate_::sp_wasm_interface::HostFunctionRegistry + { + #(#register_bodies)* + Ok(()) + } } } }) @@ -194,47 +209,182 @@ fn generate_host_function_implementation( method: &TraitItemMethod, version: u32, is_wasm_only: bool, -) -> Result { +) -> Result<(TokenStream, Ident, TokenStream)> { let name = create_host_function_ident(&method.sig.ident, version, trait_name).to_string(); let struct_name = Ident::new(&name.to_pascal_case(), Span::call_site()); let crate_ = generate_crate_access(); let signature = generate_wasm_interface_signature_for_host_function(&method.sig)?; - let wasm_to_ffi_values = - generate_wasm_to_ffi_values(&method.sig, trait_name).collect::>>()?; - let ffi_to_host_values = generate_ffi_to_host_value(&method.sig).collect::>>()?; - let host_function_call = generate_host_function_call(&method.sig, version, is_wasm_only); - let into_preallocated_ffi_value = generate_into_preallocated_ffi_value(&method.sig)?; - let convert_return_value = generate_return_value_into_wasm_value(&method.sig); - Ok(quote! { - { - struct #struct_name; + let fn_name = create_function_ident_with_version(&method.sig.ident, version); + let ref_and_mut = get_function_argument_types_ref_and_mut(&method.sig); + + // List of variable names containing WASM FFI-compatible arguments. + let mut ffi_names = Vec::new(); + + // List of `$name: $ty` tokens containing WASM FFI-compatible arguments. + let mut ffi_args_prototype = Vec::new(); + + // List of variable names containing arguments already converted into native Rust types. + // Also includes the preceding `&` or `&mut`. To be used to call the actual implementation of + // the host function. + let mut host_names_with_ref = Vec::new(); + + // List of code snippets to copy over the results returned from a host function through + // any `&mut` arguments back into WASM's linear memory. + let mut copy_data_into_ref_mut_args = Vec::new(); + + // List of code snippets to convert dynamic FFI args (`Value` enum) into concrete static FFI + // types (`u32`, etc.). + let mut convert_args_dynamic_ffi_to_static_ffi = Vec::new(); + + // List of code snippets to convert static FFI args (`u32`, etc.) into native Rust types. + let mut convert_args_static_ffi_to_host = Vec::new(); + + for ((host_name, host_ty), ref_and_mut) in + get_function_argument_names_and_types_without_ref(&method.sig).zip(ref_and_mut) + { + let ffi_name = generate_ffi_value_var_name(&host_name)?; + let host_name_ident = match *host_name { + Pat::Ident(ref pat_ident) => pat_ident.ident.clone(), + _ => unreachable!("`generate_ffi_value_var_name` above would return an error on `Pat` != `Ident`; qed"), + }; + + let ffi_ty = quote! { <#host_ty as #crate_::RIType>::FFIType }; + ffi_args_prototype.push(quote! { #ffi_name: #ffi_ty }); + ffi_names.push(quote! { #ffi_name }); + + let convert_arg_error = format!( + "could not marshal the '{}' argument through the WASM FFI boundary while executing '{}' from interface '{}'", + host_name_ident, + method.sig.ident, + trait_name + ); + convert_args_static_ffi_to_host.push(quote! { + let mut #host_name = <#host_ty as #crate_::host::FromFFIValue>::from_ffi_value(__function_context__, #ffi_name) + .map_err(|err| format!("{}: {}", err, #convert_arg_error))?; + }); - impl #crate_::sp_wasm_interface::Function for #struct_name { - fn name(&self) -> &str { - #name - } + let ref_and_mut_tokens = + ref_and_mut.map(|(token_ref, token_mut)| quote!(#token_ref #token_mut)); - fn signature(&self) -> #crate_::sp_wasm_interface::Signature { - #signature - } + host_names_with_ref.push(quote! { #ref_and_mut_tokens #host_name }); - fn execute( - &self, - __function_context__: &mut dyn #crate_::sp_wasm_interface::FunctionContext, - args: &mut dyn Iterator, - ) -> std::result::Result, String> { - #( #wasm_to_ffi_values )* - #( #ffi_to_host_values )* - #host_function_call - #into_preallocated_ffi_value - #convert_return_value - } + if ref_and_mut.map(|(_, token_mut)| token_mut.is_some()).unwrap_or(false) { + copy_data_into_ref_mut_args.push(quote! { + <#host_ty as #crate_::host::IntoPreallocatedFFIValue>::into_preallocated_ffi_value( + #host_name, + __function_context__, + #ffi_name, + )?; + }); + } + + let arg_count_mismatch_error = format!( + "missing argument '{}': number of arguments given to '{}' from interface '{}' does not match the expected number of arguments", + host_name_ident, + method.sig.ident, + trait_name + ); + convert_args_dynamic_ffi_to_static_ffi.push(quote! { + let #ffi_name = args.next().ok_or_else(|| #arg_count_mismatch_error.to_owned())?; + let #ffi_name: #ffi_ty = #crate_::sp_wasm_interface::TryFromValue::try_from_value(#ffi_name) + .ok_or_else(|| #convert_arg_error.to_owned())?; + }); + } + + let ffi_return_ty = match &method.sig.output { + ReturnType::Type(_, ty) => quote! { <#ty as #crate_::RIType>::FFIType }, + ReturnType::Default => quote! { () }, + }; + + let convert_return_value_host_to_static_ffi = match &method.sig.output { + ReturnType::Type(_, ty) => quote! { + let __result__ = <#ty as #crate_::host::IntoFFIValue>::into_ffi_value( + __result__, + __function_context__ + ); + }, + ReturnType::Default => quote! { + let __result__ = Ok(__result__); + }, + }; + + let convert_return_value_static_ffi_to_dynamic_ffi = match &method.sig.output { + ReturnType::Type(_, _) => quote! { + let __result__ = Ok(Some(#crate_::sp_wasm_interface::IntoValue::into_value(__result__))); + }, + ReturnType::Default => quote! { + let __result__ = Ok(None); + }, + }; + + if is_wasm_only { + host_names_with_ref.push(quote! { + __function_context__ + }); + } + + let implementation = quote! { + #[cfg(feature = "std")] + struct #struct_name; + + #[cfg(feature = "std")] + impl #struct_name { + fn call( + __function_context__: &mut dyn #crate_::sp_wasm_interface::FunctionContext, + #(#ffi_args_prototype),* + ) -> std::result::Result<#ffi_return_ty, String> { + #(#convert_args_static_ffi_to_host)* + let __result__ = #fn_name(#(#host_names_with_ref),*); + #(#copy_data_into_ref_mut_args)* + #convert_return_value_host_to_static_ffi + __result__ + } + } + + #[cfg(feature = "std")] + impl #crate_::sp_wasm_interface::Function for #struct_name { + fn name(&self) -> &str { + #name } - &#struct_name as &dyn #crate_::sp_wasm_interface::Function + fn signature(&self) -> #crate_::sp_wasm_interface::Signature { + #signature + } + + fn execute( + &self, + __function_context__: &mut dyn #crate_::sp_wasm_interface::FunctionContext, + args: &mut dyn Iterator, + ) -> std::result::Result, String> { + #(#convert_args_dynamic_ffi_to_static_ffi)* + let __result__ = Self::call( + __function_context__, + #(#ffi_names),* + )?; + #convert_return_value_static_ffi_to_dynamic_ffi + __result__ + } } - }) + }; + + let register_body = quote! { + registry.register_static( + #crate_::sp_wasm_interface::Function::name(&#struct_name), + |mut caller: #crate_::sp_wasm_interface::wasmtime::Caller, #(#ffi_args_prototype),*| + -> std::result::Result<#ffi_return_ty, #crate_::sp_wasm_interface::wasmtime::Trap> + { + T::with_function_context(caller, move |__function_context__| { + #struct_name::call( + __function_context__, + #(#ffi_names,)* + ) + }).map_err(#crate_::sp_wasm_interface::wasmtime::Trap::new) + } + )?; + }; + + Ok((implementation, struct_name, register_body)) } /// Generate the `wasm_interface::Signature` for the given host function `sig`. @@ -260,86 +410,6 @@ fn generate_wasm_interface_signature_for_host_function(sig: &Signature) -> Resul }) } -/// Generate the code that converts the wasm values given to `HostFunctions::execute` into the FFI -/// values. -fn generate_wasm_to_ffi_values<'a>( - sig: &'a Signature, - trait_name: &'a Ident, -) -> impl Iterator> + 'a { - let crate_ = generate_crate_access(); - let function_name = &sig.ident; - let error_message = format!( - "Number of arguments given to `{}` does not match the expected number of arguments!", - function_name, - ); - - get_function_argument_names_and_types_without_ref(sig).map(move |(name, ty)| { - let try_from_error = format!( - "Could not instantiate `{}` from wasm value while executing `{}` from interface `{}`!", - name.to_token_stream(), - function_name, - trait_name, - ); - - let var_name = generate_ffi_value_var_name(&name)?; - - Ok(quote! { - let val = args.next().ok_or_else(|| #error_message)?; - let #var_name = < - <#ty as #crate_::RIType>::FFIType as #crate_::sp_wasm_interface::TryFromValue - >::try_from_value(val).ok_or_else(|| #try_from_error)?; - }) - }) -} - -/// Generate the code to convert the ffi values on the host to the host values using `FromFFIValue`. -fn generate_ffi_to_host_value<'a>( - sig: &'a Signature, -) -> impl Iterator> + 'a { - let mut_access = get_function_argument_types_ref_and_mut(sig); - let crate_ = generate_crate_access(); - - get_function_argument_names_and_types_without_ref(sig) - .zip(mut_access.map(|v| v.and_then(|m| m.1))) - .map(move |((name, ty), mut_access)| { - let ffi_value_var_name = generate_ffi_value_var_name(&name)?; - - Ok(quote! { - let #mut_access #name = <#ty as #crate_::host::FromFFIValue>::from_ffi_value( - __function_context__, - #ffi_value_var_name, - )?; - }) - }) -} - -/// Generate the code to call the host function and the ident that stores the result. -fn generate_host_function_call(sig: &Signature, version: u32, is_wasm_only: bool) -> TokenStream { - let host_function_name = create_function_ident_with_version(&sig.ident, version); - let result_var_name = generate_host_function_result_var_name(&sig.ident); - let ref_and_mut = - get_function_argument_types_ref_and_mut(sig).map(|ram| ram.map(|(vr, vm)| quote!(#vr #vm))); - let names = get_function_argument_names(sig); - - let var_access = names - .zip(ref_and_mut) - .map(|(n, ref_and_mut)| quote!( #ref_and_mut #n )) - // If this is a wasm only interface, we add the function context as last parameter. - .chain( - iter::from_fn(|| if is_wasm_only { Some(quote!(__function_context__)) } else { None }) - .take(1), - ); - - quote! { - let #result_var_name = #host_function_name ( #( #var_access ),* ); - } -} - -/// Generate the variable name that stores the result of the host function. -fn generate_host_function_result_var_name(name: &Ident) -> Ident { - Ident::new(&format!("{}_result", name), Span::call_site()) -} - /// Generate the variable name that stores the FFI value. fn generate_ffi_value_var_name(pat: &Pat) -> Result { match pat { @@ -354,49 +424,3 @@ fn generate_ffi_value_var_name(pat: &Pat) -> Result { _ => Err(Error::new(pat.span(), "Not supported as variable name!")), } } - -/// Generate code that copies data from the host back to preallocated wasm memory. -/// -/// Any argument that is given as `&mut` is interpreted as preallocated memory and it is expected -/// that the type implements `IntoPreAllocatedFFIValue`. -fn generate_into_preallocated_ffi_value(sig: &Signature) -> Result { - let crate_ = generate_crate_access(); - let ref_and_mut = get_function_argument_types_ref_and_mut(sig) - .map(|ram| ram.and_then(|(vr, vm)| vm.map(|v| (vr, v)))); - let names_and_types = get_function_argument_names_and_types_without_ref(sig); - - ref_and_mut - .zip(names_and_types) - .filter_map(|(ram, (name, ty))| ram.map(|_| (name, ty))) - .map(|(name, ty)| { - let ffi_var_name = generate_ffi_value_var_name(&name)?; - - Ok(quote! { - <#ty as #crate_::host::IntoPreallocatedFFIValue>::into_preallocated_ffi_value( - #name, - __function_context__, - #ffi_var_name, - )?; - }) - }) - .collect() -} - -/// Generate the code that converts the return value into the appropriate wasm value. -fn generate_return_value_into_wasm_value(sig: &Signature) -> TokenStream { - let crate_ = generate_crate_access(); - - match &sig.output { - ReturnType::Default => quote!(Ok(None)), - ReturnType::Type(_, ty) => { - let result_var_name = generate_host_function_result_var_name(&sig.ident); - - quote! { - <#ty as #crate_::host::IntoFFIValue>::into_ffi_value( - #result_var_name, - __function_context__, - ).map(#crate_::sp_wasm_interface::IntoValue::into_value).map(Some) - } - }, - } -} diff --git a/primitives/runtime-interface/src/impls.rs b/primitives/runtime-interface/src/impls.rs index 0b9cdc26f4650..35badd27fa992 100644 --- a/primitives/runtime-interface/src/impls.rs +++ b/primitives/runtime-interface/src/impls.rs @@ -95,36 +95,36 @@ macro_rules! impl_traits_for_primitives { } impl_traits_for_primitives! { - u8, u8, - u16, u16, + u8, u32, + u16, u32, u32, u32, u64, u64, - i8, i8, - i16, i16, + i8, i32, + i16, i32, i32, i32, i64, i64, } -/// `bool` is passed as `u8`. +/// `bool` is passed as `u32`. /// /// - `1`: true /// - `0`: false impl RIType for bool { - type FFIType = u8; + type FFIType = u32; } #[cfg(not(feature = "std"))] impl IntoFFIValue for bool { type Owned = (); - fn into_ffi_value(&self) -> WrappedFFIValue { + fn into_ffi_value(&self) -> WrappedFFIValue { if *self { 1 } else { 0 }.into() } } #[cfg(not(feature = "std"))] impl FromFFIValue for bool { - fn from_ffi_value(arg: u8) -> bool { + fn from_ffi_value(arg: u32) -> bool { arg == 1 } } @@ -133,14 +133,14 @@ impl FromFFIValue for bool { impl FromFFIValue for bool { type SelfInstance = bool; - fn from_ffi_value(_: &mut dyn FunctionContext, arg: u8) -> Result { + fn from_ffi_value(_: &mut dyn FunctionContext, arg: u32) -> Result { Ok(arg == 1) } } #[cfg(feature = "std")] impl IntoFFIValue for bool { - fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result { + fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result { Ok(if self { 1 } else { 0 }) } } diff --git a/primitives/runtime-interface/src/lib.rs b/primitives/runtime-interface/src/lib.rs index 27c4422ed9006..e8e29329a980f 100644 --- a/primitives/runtime-interface/src/lib.rs +++ b/primitives/runtime-interface/src/lib.rs @@ -80,17 +80,17 @@ //! //! | Type | FFI type | Conversion | //! |----|----|----| -//! | `u8` | `u8` | `Identity` | -//! | `u16` | `u16` | `Identity` | +//! | `u8` | `u32` | zero-extended to 32-bits | +//! | `u16` | `u32` | zero-extended to 32-bits | //! | `u32` | `u32` | `Identity` | //! | `u64` | `u64` | `Identity` | //! | `i128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) | -//! | `i8` | `i8` | `Identity` | -//! | `i16` | `i16` | `Identity` | +//! | `i8` | `i32` | sign-extended to 32-bits | +//! | `i16` | `i32` | sign-extended to 32-bits | //! | `i32` | `i32` | `Identity` | //! | `i64` | `i64` | `Identity` | //! | `u128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) | -//! | `bool` | `u8` | `if v { 1 } else { 0 }` | +//! | `bool` | `u32` | `if v { 1 } else { 0 }` | //! | `&str` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | //! | `&[u8]` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | //! | `Vec` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | @@ -325,7 +325,9 @@ pub use util::{pack_ptr_and_len, unpack_ptr_and_len}; pub trait RIType { /// The ffi type that is used to represent `Self`. #[cfg(feature = "std")] - type FFIType: sp_wasm_interface::IntoValue + sp_wasm_interface::TryFromValue; + type FFIType: sp_wasm_interface::IntoValue + + sp_wasm_interface::TryFromValue + + sp_wasm_interface::WasmTy; #[cfg(not(feature = "std"))] type FFIType; } diff --git a/primitives/runtime-interface/src/pass_by.rs b/primitives/runtime-interface/src/pass_by.rs index 7324e9363804b..02cbe502f02c5 100644 --- a/primitives/runtime-interface/src/pass_by.rs +++ b/primitives/runtime-interface/src/pass_by.rs @@ -403,11 +403,11 @@ pub struct Enum + TryFrom>(PhantomData); #[cfg(feature = "std")] impl + TryFrom> PassByImpl for Enum { fn into_ffi_value(instance: T, _: &mut dyn FunctionContext) -> Result { - Ok(instance.into()) + Ok(instance.into() as u32) } fn from_ffi_value(_: &mut dyn FunctionContext, arg: Self::FFIType) -> Result { - T::try_from(arg).map_err(|_| format!("Invalid enum discriminant: {}", arg)) + T::try_from(arg as u8).map_err(|_| format!("Invalid enum discriminant: {}", arg)) } } @@ -417,17 +417,17 @@ impl + TryFrom> PassByImpl for Enum { fn into_ffi_value(instance: &T) -> WrappedFFIValue { let value: u8 = (*instance).into(); - value.into() + (value as u32).into() } fn from_ffi_value(arg: Self::FFIType) -> T { - T::try_from(arg).expect("Host to wasm provides a valid enum discriminant; qed") + T::try_from(arg as u8).expect("Host to wasm provides a valid enum discriminant; qed") } } -/// The type is passed as `u8`. +/// The type is passed as `u32`. /// /// The value is corresponds to the discriminant of the variant. impl + TryFrom> RIType for Enum { - type FFIType = u8; + type FFIType = u32; } diff --git a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 02fb75d108fd3..032de1d215f25 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../" } +sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../io" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index 24fdb88429634..80ad44569e999 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../" } +sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../io" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 5e4483fb38ed7..b197f2ab8ba94 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "4.0.0", path = "../" } +sp-runtime-interface = { version = "4.1.0-dev", path = "../" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-executor-common = { version = "0.10.0-dev", path = "../../../client/executor/common" } sp-runtime-interface-test-wasm = { version = "2.0.0", path = "../test-wasm" } diff --git a/primitives/runtime-interface/test/src/lib.rs b/primitives/runtime-interface/test/src/lib.rs index f64b743364278..bf82f3b4b52e4 100644 --- a/primitives/runtime-interface/test/src/lib.rs +++ b/primitives/runtime-interface/test/src/lib.rs @@ -24,7 +24,7 @@ use sp_runtime_interface_test_wasm::{test_api::HostFunctions, wasm_binary_unwrap use sp_runtime_interface_test_wasm_deprecated::wasm_binary_unwrap as wasm_binary_deprecated_unwrap; use sc_executor_common::runtime_blob::RuntimeBlob; -use sp_wasm_interface::HostFunctions as HostFunctionsT; +use sp_wasm_interface::{ExtendedHostFunctions, HostFunctions as HostFunctionsT}; use std::{ collections::HashSet, @@ -39,17 +39,11 @@ fn call_wasm_method_with_result( ) -> Result { let mut ext = TestExternalities::default(); let mut ext_ext = ext.ext(); - let mut host_functions = HF::host_functions(); - host_functions.extend(sp_io::SubstrateHostFunctions::host_functions()); - - let executor = sc_executor::WasmExecutor::new( - sc_executor::WasmExecutionMethod::Interpreted, - Some(8), - host_functions, - 8, - None, - 2, - ); + + let executor = sc_executor::WasmExecutor::< + ExtendedHostFunctions, + >::new(sc_executor::WasmExecutionMethod::Interpreted, Some(8), 8, None, 2); + executor .uncached_call( RuntimeBlob::uncompress_if_needed(binary).expect("Failed to parse binary"), diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index a94ba0f375f8c..26a81caea89b0 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -23,7 +23,7 @@ wasmi = { version = "0.9.0", optional = true } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } -sp-wasm-interface = { version = "4.0.0", default-features = false, path = "../wasm-interface" } +sp-wasm-interface = { version = "4.1.0-dev", default-features = false, path = "../wasm-interface" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } log = { version = "0.4", default-features = false } diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index c154d1c92dca8..c57eb50eddb56 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -18,7 +18,7 @@ log = { version = "0.4.8", optional = true } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } -sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../runtime-interface" } +sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../runtime-interface" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index da0d0161c086c..cffc05e4d8af5 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-wasm-interface" -version = "4.0.0" +version = "4.1.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -15,10 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] wasmi = { version = "0.9.1", optional = true } +wasmtime = { version = "0.31.0", optional = true, default-features = false } +log = { version = "0.4.14", optional = true } impl-trait-for-tuples = "0.2.1" sp-std = { version = "4.0.0", path = "../std", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } [features] default = [ "std" ] -std = [ "wasmi", "sp-std/std", "codec/std" ] +std = [ "wasmi", "sp-std/std", "codec/std", "log" ] diff --git a/primitives/wasm-interface/src/lib.rs b/primitives/wasm-interface/src/lib.rs index e1903ef425aeb..44afaf82ed4cd 100644 --- a/primitives/wasm-interface/src/lib.rs +++ b/primitives/wasm-interface/src/lib.rs @@ -24,6 +24,25 @@ use sp_std::{borrow::Cow, iter::Iterator, marker::PhantomData, mem, result, vec, #[cfg(feature = "std")] mod wasmi_impl; +#[cfg(not(all(feature = "std", feature = "wasmtime")))] +#[macro_export] +macro_rules! if_wasmtime_is_enabled { + ($($token:tt)*) => {}; +} + +#[cfg(all(feature = "std", feature = "wasmtime"))] +#[macro_export] +macro_rules! if_wasmtime_is_enabled { + ($($token:tt)*) => { + $($token)* + } +} + +if_wasmtime_is_enabled! { + // Reexport wasmtime so that its types are accessible from the procedural macro. + pub use wasmtime; +} + /// Result type used by traits in this crate. #[cfg(feature = "std")] pub type Result = result::Result; @@ -105,7 +124,8 @@ impl Value { } } -/// Provides `Sealed` trait to prevent implementing trait `PointerType` outside of this crate. +/// Provides `Sealed` trait to prevent implementing trait `PointerType` and `WasmTy` outside of this +/// crate. mod private { pub trait Sealed {} @@ -113,6 +133,9 @@ mod private { impl Sealed for u16 {} impl Sealed for u32 {} impl Sealed for u64 {} + + impl Sealed for i32 {} + impl Sealed for i64 {} } /// Something that can be wrapped in a wasm `Pointer`. @@ -338,10 +361,48 @@ pub trait Sandbox { fn get_global_val(&self, instance_idx: u32, name: &str) -> Result>; } +if_wasmtime_is_enabled! { + /// A trait used to statically register host callbacks with the WASM executor, + /// so that they call be called from within the runtime with minimal overhead. + /// + /// This is used internally to interface the wasmtime-based executor with the + /// host functions' definitions generated through the runtime interface macro, + /// and is not meant to be used directly. + pub trait HostFunctionRegistry { + type State; + type Error; + type FunctionContext: FunctionContext; + + /// Wraps the given `caller` in a type which implements `FunctionContext` + /// and calls the given `callback`. + fn with_function_context( + caller: wasmtime::Caller, + callback: impl FnOnce(&mut dyn FunctionContext) -> R, + ) -> R; + + /// Registers a given host function with the WASM executor. + /// + /// The function has to be statically callable, and all of its arguments + /// and its return value have to be compatible with WASM FFI. + fn register_static( + &mut self, + fn_name: &str, + func: impl wasmtime::IntoFunc + 'static, + ) -> core::result::Result<(), Self::Error>; + } +} + /// Something that provides implementations for host functions. -pub trait HostFunctions: 'static { +pub trait HostFunctions: 'static + Send + Sync { /// Returns the host functions `Self` provides. fn host_functions() -> Vec<&'static dyn Function>; + + if_wasmtime_is_enabled! { + /// Statically registers the host functions. + fn register_static(registry: &mut T) -> core::result::Result<(), T::Error> + where + T: HostFunctionRegistry; + } } #[impl_trait_for_tuples::impl_for_tuples(30)] @@ -353,8 +414,146 @@ impl HostFunctions for Tuple { host_functions } + + #[cfg(all(feature = "std", feature = "wasmtime"))] + fn register_static(registry: &mut T) -> core::result::Result<(), T::Error> + where + T: HostFunctionRegistry, + { + for_tuples!( + #( Tuple::register_static(registry)?; )* + ); + + Ok(()) + } +} + +/// A wrapper which merges two sets of host functions, and allows the second set to override +/// the host functions from the first set. +pub struct ExtendedHostFunctions { + phantom: PhantomData<(Base, Overlay)>, +} + +impl HostFunctions for ExtendedHostFunctions +where + Base: HostFunctions, + Overlay: HostFunctions, +{ + fn host_functions() -> Vec<&'static dyn Function> { + let mut base = Base::host_functions(); + let overlay = Overlay::host_functions(); + base.retain(|host_fn| { + !overlay.iter().any(|ext_host_fn| host_fn.name() == ext_host_fn.name()) + }); + base.extend(overlay); + base + } + + if_wasmtime_is_enabled! { + fn register_static(registry: &mut T) -> core::result::Result<(), T::Error> + where + T: HostFunctionRegistry, + { + struct Proxy<'a, T> { + registry: &'a mut T, + seen_overlay: std::collections::HashSet, + seen_base: std::collections::HashSet, + overlay_registered: bool, + } + + impl<'a, T> HostFunctionRegistry for Proxy<'a, T> + where + T: HostFunctionRegistry, + { + type State = T::State; + type Error = T::Error; + type FunctionContext = T::FunctionContext; + + fn with_function_context( + caller: wasmtime::Caller, + callback: impl FnOnce(&mut dyn FunctionContext) -> R, + ) -> R { + T::with_function_context(caller, callback) + } + + fn register_static( + &mut self, + fn_name: &str, + func: impl wasmtime::IntoFunc + 'static, + ) -> core::result::Result<(), Self::Error> { + if self.overlay_registered { + if !self.seen_base.insert(fn_name.to_owned()) { + log::warn!( + target: "extended_host_functions", + "Duplicate base host function: '{}'", + fn_name, + ); + + // TODO: Return an error here? + return Ok(()) + } + + if self.seen_overlay.contains(fn_name) { + // Was already registered when we went through the overlay, so just ignore it. + log::debug!( + target: "extended_host_functions", + "Overriding base host function: '{}'", + fn_name, + ); + + return Ok(()) + } + } else if !self.seen_overlay.insert(fn_name.to_owned()) { + log::warn!( + target: "extended_host_functions", + "Duplicate overlay host function: '{}'", + fn_name, + ); + + // TODO: Return an error here? + return Ok(()) + } + + self.registry.register_static(fn_name, func) + } + } + + let mut proxy = Proxy { + registry, + seen_overlay: Default::default(), + seen_base: Default::default(), + overlay_registered: false, + }; + + // The functions from the `Overlay` can override those from the `Base`, + // so `Overlay` is registered first, and then we skip those functions + // in `Base` if they were already registered from the `Overlay`. + Overlay::register_static(&mut proxy)?; + proxy.overlay_registered = true; + Base::register_static(&mut proxy)?; + + Ok(()) + } + } } +/// A trait for types directly usable at the WASM FFI boundary without any conversion at all. +/// +/// This trait is sealed and should not be implemented downstream. +#[cfg(all(feature = "std", feature = "wasmtime"))] +pub trait WasmTy: wasmtime::WasmTy + private::Sealed {} + +/// A trait for types directly usable at the WASM FFI boundary without any conversion at all. +/// +/// This trait is sealed and should not be implemented downstream. +#[cfg(not(all(feature = "std", feature = "wasmtime")))] +pub trait WasmTy: private::Sealed {} + +impl WasmTy for i32 {} +impl WasmTy for u32 {} +impl WasmTy for i64 {} +impl WasmTy for u64 {} + /// Something that can be converted into a wasm compatible `Value`. pub trait IntoValue { /// The type of the value in wasm. diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 96f3c9898395d..86231bb34c506 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -262,7 +262,8 @@ impl client::LocalCallExecutor>, Backend, G, - > + > where + D: sc_executor::NativeExecutionDispatch, { /// Build the test client with the given native executor. pub fn build_with_native_executor( diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 3be0e40b0b6ba..ae4be0d13af7e 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -25,7 +25,7 @@ memory-db = { version = "0.27.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../../primitives/runtime-interface" } +sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime-interface" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../frame/support" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } diff --git a/test-utils/test-runner/Cargo.toml b/test-utils/test-runner/Cargo.toml index 7066fc778cbdd..eb565fd7b587e 100644 --- a/test-utils/test-runner/Cargo.toml +++ b/test-utils/test-runner/Cargo.toml @@ -52,3 +52,8 @@ tokio = { version = "1.13", features = ["signal"] } # Calling RPC jsonrpc-core = "18.0" num-traits = "0.2.14" + +[features] +default = ["std"] +# This is here so that we can use the `runtime_interface` procedural macro +std = [] diff --git a/test-utils/test-runner/src/host_functions.rs b/test-utils/test-runner/src/host_functions.rs index 731abfbb9db05..6d9fa3534b34f 100644 --- a/test-utils/test-runner/src/host_functions.rs +++ b/test-utils/test-runner/src/host_functions.rs @@ -16,75 +16,38 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -/// Use this to override host functions. -/// eg -/// ```rust -/// use test_runner::override_host_functions; -/// pub struct SignatureVerificationOverride; -/// -/// impl sp_wasm_interface::HostFunctions for SignatureVerificationOverride { -/// fn host_functions() -> Vec<&'static dyn sp_wasm_interface::Function> { -/// override_host_functions!( -/// "ext_crypto_ecdsa_verify_version_1", EcdsaVerify, -/// ) -/// } -/// } -/// ``` -#[macro_export] -macro_rules! override_host_functions { - ($($fn_name:expr, $name:ident,)*) => {{ - let mut host_functions = vec![]; - $( - struct $name; - impl sp_wasm_interface::Function for $name { - fn name(&self) -> &str { - &$fn_name - } +use sp_core::{ecdsa, ed25519, sr25519}; +use sp_runtime_interface::runtime_interface; - fn signature(&self) -> sp_wasm_interface::Signature { - sp_wasm_interface::Signature { - args: std::borrow::Cow::Owned(vec![ - sp_wasm_interface::ValueType::I32, - sp_wasm_interface::ValueType::I64, - sp_wasm_interface::ValueType::I32, - ]), - return_value: Some(sp_wasm_interface::ValueType::I32), - } - } +#[runtime_interface] +trait Crypto { + fn ecdsa_verify(_sig: &ecdsa::Signature, _msg: &[u8], _pub_key: &ecdsa::Public) -> bool { + true + } + + #[version(2)] + fn ecdsa_verify(_sig: &ecdsa::Signature, _msg: &[u8], _pub_key: &ecdsa::Public) -> bool { + true + } + + fn ed25519_verify(_sig: &ed25519::Signature, _msg: &[u8], _pub_key: &ed25519::Public) -> bool { + true + } - fn execute( - &self, - context: &mut dyn sp_wasm_interface::FunctionContext, - _args: &mut dyn Iterator, - ) -> Result, String> { - ::into_ffi_value(true, context) - .map(sp_wasm_interface::IntoValue::into_value) - .map(Some) - } - } - host_functions.push(&$name as &'static dyn sp_wasm_interface::Function); - )* - host_functions - }}; + fn sr25519_verify(_sig: &sr25519::Signature, _msg: &[u8], _pub_key: &sr25519::Public) -> bool { + true + } + + #[version(2)] + fn sr25519_verify(_sig: &sr25519::Signature, _msg: &[u8], _pub_key: &sr25519::Public) -> bool { + true + } } /// Provides host functions that overrides runtime signature verification /// to always return true. -pub struct SignatureVerificationOverride; +pub type SignatureVerificationOverride = crypto::HostFunctions; -impl sp_wasm_interface::HostFunctions for SignatureVerificationOverride { - fn host_functions() -> Vec<&'static dyn sp_wasm_interface::Function> { - override_host_functions!( - "ext_crypto_ecdsa_verify_version_1", - EcdsaVerify, - "ext_crypto_ecdsa_verify_version_2", - EcdsaVerifyV2, - "ext_crypto_ed25519_verify_version_1", - Ed25519Verify, - "ext_crypto_sr25519_verify_version_1", - Sr25519Verify, - "ext_crypto_sr25519_verify_version_2", - Sr25519VerifyV2, - ) - } -} +// This is here to get rid of the warnings. +#[allow(unused_imports, dead_code)] +use self::crypto::{ecdsa_verify, ed25519_verify, sr25519_verify}; From 8aeeef953d44460c4415afce195a0ff9536d9493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 14 Dec 2021 13:05:47 +0100 Subject: [PATCH 0336/1472] Prepare code for rust 1.57 (#10471) * Prepare code for rust 1.57 * CI: revert me; staging image with stable 1.57 * Revert "CI: revert me; staging image with stable 1.57 [skip CI]" This reverts commit f3c3b8a9e877ef7126ffce6ebc4822bb4ace0379. Co-authored-by: CI system <> --- Cargo.lock | 4 ++-- frame/support/test/Cargo.toml | 2 +- .../tests/derive_no_bound_ui/clone.stderr | 6 ++--- .../test/tests/derive_no_bound_ui/eq.stderr | 6 ++--- .../call_argument_invalid_bound.stderr | 10 ++++----- .../call_argument_invalid_bound_2.stderr | 22 +++++++++---------- .../call_argument_invalid_bound_3.stderr | 12 +++++----- .../pallet_ui/event_field_not_member.stderr | 10 ++++----- .../storage_info_unsatisfied_nmap.stderr | 10 ++++----- .../reserved_keyword/on_initialize.stderr | 20 ++++++++--------- primitives/api/test/Cargo.toml | 2 +- .../npos-elections/solution-type/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 2 +- test-utils/Cargo.toml | 2 +- 14 files changed, 54 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b576a12ea6f65..c6c49939a8ff0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10963,9 +10963,9 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.52" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "150e726dc059e6fbd4fce3288f5bb3cf70128cf63b0dde23b938a3cad810fb23" +checksum = "9d664de8ea7e531ad4c0f5a834f20b8cb2b8e6dfe88d05796ee7887518ed67b9" dependencies = [ "dissimilar", "glob", diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 0cd3f9ac02913..cdbefae4bde70 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -23,7 +23,7 @@ sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../.. sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } -trybuild = "1.0.52" +trybuild = "1.0.53" pretty_assertions = "1.0.0" rustversion = "1.0.5" frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/support/test/tests/derive_no_bound_ui/clone.stderr b/frame/support/test/tests/derive_no_bound_ui/clone.stderr index 050b576c8b9ed..45428a8728c21 100644 --- a/frame/support/test/tests/derive_no_bound_ui/clone.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/clone.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `::C: Clone` is not satisfied - --> $DIR/clone.rs:7:2 + --> tests/derive_no_bound_ui/clone.rs:7:2 | 7 | c: T::C, | ^ the trait `Clone` is not implemented for `::C` | note: required by `clone` - --> $DIR/clone.rs:121:5 + --> $RUST/core/src/clone.rs | -121 | fn clone(&self) -> Self; + | fn clone(&self) -> Self; | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/derive_no_bound_ui/eq.stderr b/frame/support/test/tests/derive_no_bound_ui/eq.stderr index 19fb3ac248b81..97ac29f96902d 100644 --- a/frame/support/test/tests/derive_no_bound_ui/eq.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/eq.stderr @@ -1,12 +1,12 @@ error[E0277]: can't compare `Foo` with `Foo` - --> $DIR/eq.rs:6:8 + --> tests/derive_no_bound_ui/eq.rs:6:8 | 6 | struct Foo { | ^^^ no implementation for `Foo == Foo` | = help: the trait `PartialEq` is not implemented for `Foo` note: required by a bound in `std::cmp::Eq` - --> $DIR/cmp.rs:272:15 + --> $RUST/core/src/cmp.rs | -272 | pub trait Eq: PartialEq { + | pub trait Eq: PartialEq { | ^^^^^^^^^^^^^^^ required by this bound in `std::cmp::Eq` diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index b7a8e40e69a14..9701b1bdd06f3 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -1,5 +1,5 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` - --> $DIR/call_argument_invalid_bound.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound.rs:20:36 | 20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` @@ -9,19 +9,19 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` = note: required for the cast to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> $DIR/call_argument_invalid_bound.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound.rs:20:36 | 20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ the trait `Clone` is not implemented for `::Bar` | note: required by `clone` - --> $DIR/clone.rs:121:5 + --> $RUST/core/src/clone.rs | -121 | fn clone(&self) -> Self; + | fn clone(&self) -> Self; | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `==` cannot be applied to type `&::Bar` - --> $DIR/call_argument_invalid_bound.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound.rs:20:36 | 20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index f1bc3b5d8f381..b4a10a6af01f1 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -1,5 +1,5 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` - --> $DIR/call_argument_invalid_bound_2.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 | 20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` @@ -9,19 +9,19 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` = note: required for the cast to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> $DIR/call_argument_invalid_bound_2.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 | 20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ the trait `Clone` is not implemented for `::Bar` | note: required by `clone` - --> $DIR/clone.rs:121:5 + --> $RUST/core/src/clone.rs | -121 | fn clone(&self) -> Self; + | fn clone(&self) -> Self; | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `==` cannot be applied to type `&::Bar` - --> $DIR/call_argument_invalid_bound_2.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 | 20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ @@ -32,7 +32,7 @@ help: consider further restricting this bound | +++++++++++++++++++++ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is not satisfied - --> $DIR/call_argument_invalid_bound_2.rs:1:1 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:1:1 | 1 | #[frame_support::pallet] | ^----------------------- @@ -49,21 +49,21 @@ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is | = note: required because of the requirements on the impl of `Encode` for `::Bar` note: required by a bound in `encode_to` - --> $DIR/codec.rs:223:18 + --> $CARGO/parity-scale-codec-2.3.1/src/codec.rs | -223 | fn encode_to(&self, dest: &mut T) { + | fn encode_to(&self, dest: &mut T) { | ^^^^^^ required by this bound in `encode_to` = note: this error originates in the derive macro `frame_support::codec::Encode` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied - --> $DIR/call_argument_invalid_bound_2.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 | 20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` | = note: required because of the requirements on the impl of `Decode` for `::Bar` note: required by a bound in `parity_scale_codec::Decode::decode` - --> $DIR/codec.rs:284:15 + --> $CARGO/parity-scale-codec-2.3.1/src/codec.rs | -284 | fn decode(input: &mut I) -> Result; + | fn decode(input: &mut I) -> Result; | ^^^^^ required by this bound in `parity_scale_codec::Decode::decode` diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr index 144b7e12bd664..b884d24103f26 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr @@ -1,5 +1,5 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` - --> $DIR/call_argument_invalid_bound_3.rs:22:36 + --> tests/pallet_ui/call_argument_invalid_bound_3.rs:22:36 | 22 | pub fn foo(origin: OriginFor, bar: Bar) -> DispatchResultWithPostInfo { | ^^^ `Bar` cannot be formatted using `{:?}` @@ -10,21 +10,19 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` = note: required for the cast to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `Bar: Clone` is not satisfied - --> $DIR/call_argument_invalid_bound_3.rs:22:36 + --> tests/pallet_ui/call_argument_invalid_bound_3.rs:22:36 | 22 | pub fn foo(origin: OriginFor, bar: Bar) -> DispatchResultWithPostInfo { | ^^^ the trait `Clone` is not implemented for `Bar` | note: required by `clone` - --> $DIR/clone.rs:121:5 + --> $RUST/core/src/clone.rs | -121 | fn clone(&self) -> Self; + | fn clone(&self) -> Self; | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `==` cannot be applied to type `&Bar` - --> $DIR/call_argument_invalid_bound_3.rs:22:36 + --> tests/pallet_ui/call_argument_invalid_bound_3.rs:22:36 | 22 | pub fn foo(origin: OriginFor, bar: Bar) -> DispatchResultWithPostInfo { | ^^^ - | - = note: an implementation of `std::cmp::PartialEq` might be missing for `&Bar` diff --git a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr index 06384b0b66b84..ff184db988e3c 100644 --- a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr +++ b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr @@ -1,17 +1,17 @@ error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> $DIR/event_field_not_member.rs:23:7 + --> tests/pallet_ui/event_field_not_member.rs:23:7 | 23 | B { b: T::Bar }, | ^ the trait `Clone` is not implemented for `::Bar` | note: required by `clone` - --> $DIR/clone.rs:121:5 + --> $RUST/core/src/clone.rs | -121 | fn clone(&self) -> Self; + | fn clone(&self) -> Self; | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `==` cannot be applied to type `&::Bar` - --> $DIR/event_field_not_member.rs:23:7 + --> tests/pallet_ui/event_field_not_member.rs:23:7 | 23 | B { b: T::Bar }, | ^ @@ -22,7 +22,7 @@ help: consider further restricting this bound | +++++++++++++++++++++ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` - --> $DIR/event_field_not_member.rs:23:7 + --> tests/pallet_ui/event_field_not_member.rs:23:7 | 23 | B { b: T::Bar }, | ^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index ffbc5aeea6b4f..00d350b943d01 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -1,13 +1,13 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied - --> $DIR/storage_info_unsatisfied_nmap.rs:10:12 + --> tests/pallet_ui/storage_info_unsatisfied_nmap.rs:10:12 | 10 | #[pallet::generate_storage_info] | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | - = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `NMapKey` - = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>` + = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` + = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` note: required by `storage_info` - --> $DIR/storage.rs:71:2 + --> $WORKSPACE/frame/support/src/traits/storage.rs | -71 | fn storage_info() -> Vec; + | fn storage_info() -> Vec; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/reserved_keyword/on_initialize.stderr b/frame/support/test/tests/reserved_keyword/on_initialize.stderr index 84e93fa52c2d9..58273fb1bd3ba 100644 --- a/frame/support/test/tests/reserved_keyword/on_initialize.stderr +++ b/frame/support/test/tests/reserved_keyword/on_initialize.stderr @@ -1,39 +1,39 @@ error: Invalid call fn name: `on_finalize`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. - --> $DIR/on_initialize.rs:28:1 + --> tests/reserved_keyword/on_initialize.rs:28:1 | 28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) error: Invalid call fn name: `on_initialize`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. - --> $DIR/on_initialize.rs:28:1 + --> tests/reserved_keyword/on_initialize.rs:28:1 | 28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) error: Invalid call fn name: `on_runtime_upgrade`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. - --> $DIR/on_initialize.rs:28:1 + --> tests/reserved_keyword/on_initialize.rs:28:1 | 28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) error: Invalid call fn name: `offchain_worker`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. - --> $DIR/on_initialize.rs:28:1 + --> tests/reserved_keyword/on_initialize.rs:28:1 | 28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) error: Invalid call fn name: `deposit_event`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. - --> $DIR/on_initialize.rs:28:1 + --> tests/reserved_keyword/on_initialize.rs:28:1 | 28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 91675e941c78f..b7716f6b8de7a 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -21,7 +21,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } codec = { package = "parity-scale-codec", version = "2.0.0" } sp-state-machine = { version = "0.10.0-dev", path = "../../state-machine" } -trybuild = "1.0.52" +trybuild = "1.0.53" rustversion = "1.0.5" [dev-dependencies] diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index a64ca45ce8424..5bffcff1038d1 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -26,4 +26,4 @@ scale-info = "1.0" sp-arithmetic = { path = "../../arithmetic", version = "4.0.0-dev" } # used by generate_solution_type: sp-npos-elections = { path = "..", version = "4.0.0-dev" } -trybuild = "1.0.52" +trybuild = "1.0.53" diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 9ff17b1dff0f0..69a6792ead29d 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -31,7 +31,7 @@ sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } sp-core = { version = "4.1.0-dev", path = "../core" } sp-io = { version = "4.0.0-dev", path = "../io" } rustversion = "1.0.5" -trybuild = "1.0.52" +trybuild = "1.0.53" [features] default = [ "std" ] diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index 6cb91bb589c6d..756de58032803 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -18,4 +18,4 @@ tokio = { version = "1.10", features = ["macros", "time"] } [dev-dependencies] sc-service = { version = "0.10.0-dev", path = "../client/service" } -trybuild = { version = "1.0.52", features = [ "diff" ] } +trybuild = { version = "1.0.53", features = [ "diff" ] } From f32e7932fc24e6a6f20c6265c98d2e869f8ff92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 14 Dec 2021 23:44:04 +0100 Subject: [PATCH 0337/1472] Remove cargo unleash CI job (#10482) * Remove cargo unleash CI job The CI job is currently breaking, because we released some crates. We also don't need the job currently because releases are not done. So, the job currently just annoys people and eats CPU time. This brings us to the conclusion that this job is currently not required and can be readded at a later point when we are sure that we need it. * Hopefully fix UI test * Another try * Remove `reserved_keyword` ui --- .gitlab-ci.yml | 30 -------------- .../call_argument_invalid_bound_3.rs | 9 ++--- .../call_argument_invalid_bound_3.stderr | 18 --------- .../storage_info_unsatisfied_nmap.rs | 10 +++-- .../storage_info_unsatisfied_nmap.stderr | 4 +- frame/support/test/tests/reserved_keyword.rs | 26 ------------- .../tests/reserved_keyword/on_initialize.rs | 30 -------------- .../reserved_keyword/on_initialize.stderr | 39 ------------------- 8 files changed, 12 insertions(+), 154 deletions(-) delete mode 100644 frame/support/test/tests/reserved_keyword.rs delete mode 100644 frame/support/test/tests/reserved_keyword/on_initialize.rs delete mode 100644 frame/support/test/tests/reserved_keyword/on_initialize.stderr diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7af3675f07718..3f830c7e8e24d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -39,9 +39,6 @@ variables: &default-vars DOCKER_OS: "debian:stretch" ARCH: "x86_64" CI_IMAGE: "paritytech/ci-linux:production" - # FIXME set to release - CARGO_UNLEASH_INSTALL_PARAMS: "--version 1.0.0-alpha.13" - CARGO_UNLEASH_PKG_DEF: "--skip node node-* pallet-template pallet-example-* subkey chain-spec-builder" VAULT_SERVER_URL: "https://vault.parity-mgmt-vault.parity.io" VAULT_AUTH_PATH: "gitlab-parity-io-jwt" VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" @@ -458,21 +455,6 @@ test-linux-stable: &test-linux - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout - sccache -s -unleash-check: - stage: test - <<: *docker-env - <<: *test-refs-no-trigger - script: - - cargo install cargo-unleash ${CARGO_UNLEASH_INSTALL_PARAMS} - - cargo unleash de-dev-deps - # Reuse build artifacts when running checks (cuts down check time by 3x) - # TODO: Implement this optimization in cargo-unleash rather than here - - mkdir -p target/unleash - - export CARGO_TARGET_DIR=target/unleash - - cargo unleash check ${CARGO_UNLEASH_PKG_DEF} - # FIXME: this job must not fail, or unleash-to-crates-io will publish broken stuff - allow_failure: true - test-frame-examples-compile-to-wasm: # into one job stage: test @@ -869,18 +851,6 @@ publish-draft-release: - ./.maintain/gitlab/publish_draft_release.sh allow_failure: true -unleash-to-crates-io: - stage: publish - <<: *docker-env - <<: *vault-secrets - rules: - - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - script: - - cargo install cargo-unleash ${CARGO_UNLEASH_INSTALL_PARAMS} - - cargo unleash em-dragons --no-check --owner github:paritytech:core-devs ${CARGO_UNLEASH_PKG_DEF} - allow_failure: true - #### stage: deploy deploy-prometheus-alerting-rules: diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.rs b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.rs index e7f99d7ca4f2d..1cdfb369feadb 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.rs +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.rs @@ -1,8 +1,8 @@ #[frame_support::pallet] mod pallet { - use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; + use codec::{Decode, Encode}; + use frame_support::pallet_prelude::{DispatchResultWithPostInfo, Hooks}; use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; - use codec::{Encode, Decode}; #[pallet::config] pub trait Config: frame_system::Config {} @@ -13,7 +13,7 @@ mod pallet { #[pallet::hooks] impl Hooks> for Pallet {} - #[derive(Encode, Decode, scale_info::TypeInfo)] + #[derive(Encode, Decode, scale_info::TypeInfo, PartialEq, Clone)] struct Bar; #[pallet::call] @@ -25,5 +25,4 @@ mod pallet { } } -fn main() { -} +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr index b884d24103f26..c196b28a31ce6 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr @@ -8,21 +8,3 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` = note: add `#[derive(Debug)]` to `Bar` or manually `impl std::fmt::Debug for Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Bar` = note: required for the cast to the object type `dyn std::fmt::Debug` - -error[E0277]: the trait bound `Bar: Clone` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_3.rs:22:36 - | -22 | pub fn foo(origin: OriginFor, bar: Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `Clone` is not implemented for `Bar` - | -note: required by `clone` - --> $RUST/core/src/clone.rs - | - | fn clone(&self) -> Self; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0369]: binary operation `==` cannot be applied to type `&Bar` - --> tests/pallet_ui/call_argument_invalid_bound_3.rs:22:36 - | -22 | pub fn foo(origin: OriginFor, bar: Bar) -> DispatchResultWithPostInfo { - | ^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs index c5d773d716116..15456c78e9ba9 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs @@ -1,6 +1,9 @@ #[frame_support::pallet] mod pallet { - use frame_support::pallet_prelude::{Hooks, StorageNMap, Twox64Concat, NMapKey}; + use frame_support::{ + pallet_prelude::{Hooks, Twox64Concat}, + storage::types::{StorageNMap, Key}, + }; use frame_system::pallet_prelude::BlockNumberFor; #[pallet::config] @@ -20,8 +23,7 @@ mod pallet { struct Bar; #[pallet::storage] - type Foo = StorageNMap<_, NMapKey, u32>; + type Foo = StorageNMap<_, Key, u32>; } -fn main() { -} +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 00d350b943d01..cb9a0bd559890 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied - --> tests/pallet_ui/storage_info_unsatisfied_nmap.rs:10:12 + --> tests/pallet_ui/storage_info_unsatisfied_nmap.rs:13:12 | -10 | #[pallet::generate_storage_info] +13 | #[pallet::generate_storage_info] | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` diff --git a/frame/support/test/tests/reserved_keyword.rs b/frame/support/test/tests/reserved_keyword.rs deleted file mode 100644 index d29b0477c3836..0000000000000 --- a/frame/support/test/tests/reserved_keyword.rs +++ /dev/null @@ -1,26 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#[rustversion::attr(not(stable), ignore)] -#[test] -fn reserved_keyword() { - // As trybuild is using `cargo check`, we don't need the real WASM binaries. - std::env::set_var("SKIP_WASM_BUILD", "1"); - - let t = trybuild::TestCases::new(); - t.compile_fail("tests/reserved_keyword/*.rs"); -} diff --git a/frame/support/test/tests/reserved_keyword/on_initialize.rs b/frame/support/test/tests/reserved_keyword/on_initialize.rs deleted file mode 100644 index 72d53abfb1034..0000000000000 --- a/frame/support/test/tests/reserved_keyword/on_initialize.rs +++ /dev/null @@ -1,30 +0,0 @@ -macro_rules! reserved { - ($($reserved:ident)*) => { - $( - mod $reserved { - pub use frame_support::dispatch; - - pub trait Config: frame_support_test::Config {} - - pub mod system { - use frame_support::dispatch; - - pub fn ensure_root(_: R) -> dispatch::DispatchResult { - Ok(()) - } - } - - frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test { - #[weight = 0] - fn $reserved(_origin) -> dispatch::DispatchResult { unreachable!() } - } - } - } - )* - } -} - -reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - -fn main() {} diff --git a/frame/support/test/tests/reserved_keyword/on_initialize.stderr b/frame/support/test/tests/reserved_keyword/on_initialize.stderr deleted file mode 100644 index 58273fb1bd3ba..0000000000000 --- a/frame/support/test/tests/reserved_keyword/on_initialize.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error: Invalid call fn name: `on_finalize`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. - --> tests/reserved_keyword/on_initialize.rs:28:1 - | -28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: Invalid call fn name: `on_initialize`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. - --> tests/reserved_keyword/on_initialize.rs:28:1 - | -28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: Invalid call fn name: `on_runtime_upgrade`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. - --> tests/reserved_keyword/on_initialize.rs:28:1 - | -28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: Invalid call fn name: `offchain_worker`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. - --> tests/reserved_keyword/on_initialize.rs:28:1 - | -28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: Invalid call fn name: `deposit_event`, name is reserved and doesn't match expected signature, please refer to `decl_module!` documentation to see the appropriate usage, or rename it to an unreserved keyword. - --> tests/reserved_keyword/on_initialize.rs:28:1 - | -28 | reserved!(on_finalize on_initialize on_runtime_upgrade offchain_worker deposit_event); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::__check_reserved_fn_name` (in Nightly builds, run with -Z macro-backtrace for more info) From 9652011866b49e8c46f0fe04febd8f28a45b6233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 15 Dec 2021 00:51:12 +0100 Subject: [PATCH 0338/1472] rpc-author: Downgrade the logging level of some logs (#10483) * rpc-author: Downgrade the logging level of some logs Currently these messages are printed with `warn` levels, but they don't bring the node operator anything. The problem with these log lines is that they are triggered by external users when they send invalid transactions. This pr "resolves" this by downgrading the log severity to debug, aka not shown by default. * FMT --- client/rpc/src/author/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 40b477a662a60..5046f26319207 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -21,7 +21,6 @@ #[cfg(test)] mod tests; -use log::warn; use std::{convert::TryInto, sync::Arc}; use sp_blockchain::HeaderBackend; @@ -188,7 +187,7 @@ where let dxt = match TransactionFor::

::decode(&mut &xt[..]).map_err(error::Error::from) { Ok(tx) => tx, Err(err) => { - warn!("Failed to submit extrinsic: {}", err); + log::debug!("Failed to submit extrinsic: {}", err); // reject the subscriber (ignore errors - we don't care if subscriber is no longer // there). let _ = subscriber.reject(err.into()); @@ -211,7 +210,7 @@ where let tx_stream = match submit.await { Ok(s) => s, Err(err) => { - warn!("Failed to submit extrinsic: {}", err); + log::debug!("Failed to submit extrinsic: {}", err); // reject the subscriber (ignore errors - we don't care if subscriber is no // longer there). let _ = subscriber.reject(err.into()); @@ -222,14 +221,16 @@ where subscriptions.add(subscriber, move |sink| { tx_stream .map(|v| Ok(Ok(v))) - .forward(sink.sink_map_err(|e| warn!("Error sending notifications: {:?}", e))) + .forward( + sink.sink_map_err(|e| log::debug!("Error sending notifications: {:?}", e)), + ) .map(drop) }); }; let res = self.subscriptions.executor().spawn_obj(future.boxed().into()); if res.is_err() { - warn!("Error spawning subscription RPC task."); + log::warn!("Error spawning subscription RPC task."); } } From a64f702d20fd0e979c69d11b60e0d6d6b81d6c6d Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 15 Dec 2021 01:27:13 +0100 Subject: [PATCH 0339/1472] Fix update_lock (#10485) * Fix update_lock * Fixes * Formatting * add `inc_consumers_without_limits` to session too Co-authored-by: Shawn Tabrizi --- frame/assets/src/lib.rs | 5 ++-- frame/balances/src/lib.rs | 2 +- frame/session/src/lib.rs | 2 +- frame/system/src/lib.rs | 58 ++++++++++++++++++++++++++++++++++----- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index b86661d9fa4fd..6643cc177460c 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -467,8 +467,9 @@ pub mod pallet { BadWitness, /// Minimum balance should be non-zero. MinBalanceZero, - /// No provider reference exists to allow a non-zero balance of a non-self-sufficient - /// asset. + /// Unable to increment the consumer reference counters on the account. Either no provider + /// reference exists to allow a non-zero balance of a non-self-sufficient asset, or the + /// maximum number of consumers has been reached. NoProvider, /// Invalid metadata given. BadMetadata, diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 4471ed91a9afc..6919c66f7211e 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -971,7 +971,7 @@ impl, I: 'static> Pallet { } else { Locks::::insert(who, bounded_locks); if !existed { - if system::Pallet::::inc_consumers(who).is_err() { + if system::Pallet::::inc_consumers_without_limit(who).is_err() { // No providers for the locks. This is impossible under normal circumstances // since the funds that are under the lock will themselves be stored in the // account and therefore will need a reference. diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 0f80494550849..e88f143065052 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -448,7 +448,7 @@ pub mod pallet { for (account, val, keys) in self.keys.iter().cloned() { >::inner_set_keys(&val, keys) .expect("genesis config must not contain duplicates; qed"); - if frame_system::Pallet::::inc_consumers(&account).is_err() { + if frame_system::Pallet::::inc_consumers_without_limit(&account).is_err() { // This will leak a provider reference, however it only happens once (at // genesis) so it's really not a big deal and we assume that the user wants to // do this since it's the only way a non-endowed account can contain a session diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 6bdaf8bd4b505..e167f44ffd88c 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -85,8 +85,8 @@ use frame_support::{ dispatch::{DispatchResult, DispatchResultWithPostInfo}, storage, traits::{ - Contains, EnsureOrigin, Get, HandleLifetime, OnKilledAccount, OnNewAccount, OriginTrait, - PalletInfo, SortedMembers, StoredMap, + ConstU32, Contains, EnsureOrigin, Get, HandleLifetime, OnKilledAccount, OnNewAccount, + OriginTrait, PalletInfo, SortedMembers, StoredMap, }, weights::{ extract_actual_weight, DispatchClass, DispatchInfo, PerDispatchClass, RuntimeDbWeight, @@ -154,6 +154,36 @@ impl SetCode for () { } } +/// Numeric limits over the ability to add a consumer ref using `inc_consumers`. +pub trait ConsumerLimits { + /// The number of consumers over which `inc_consumers` will cease to work. + fn max_consumers() -> RefCount; + /// The maximum number of additional consumers expected to be over be added at once using + /// `inc_consumers_without_limit`. + /// + /// Note: This is not enforced and it's up to the chain's author to ensure this reflects the + /// actual situation. + fn max_overflow() -> RefCount; +} + +impl ConsumerLimits for ConstU32 { + fn max_consumers() -> RefCount { + Z + } + fn max_overflow() -> RefCount { + Z + } +} + +impl, MaxOverflow: Get> ConsumerLimits for (MaxNormal, MaxOverflow) { + fn max_consumers() -> RefCount { + MaxNormal::get() + } + fn max_overflow() -> RefCount { + MaxOverflow::get() + } +} + #[frame_support::pallet] pub mod pallet { use crate::{self as frame_system, pallet_prelude::*, *}; @@ -310,8 +340,7 @@ pub mod pallet { type OnSetCode: SetCode; /// The maximum number of consumers allowed on a single account. - #[pallet::constant] - type MaxConsumers: Get; + type MaxConsumers: ConsumerLimits; } #[pallet::pallet] @@ -1122,11 +1151,12 @@ impl Pallet { /// Increment the reference counter on an account. /// - /// The account `who`'s `providers` must be non-zero or this will return an error. + /// The account `who`'s `providers` must be non-zero and the current number of consumers must + /// be less than `MaxConsumers::max_consumers()` or this will return an error. pub fn inc_consumers(who: &T::AccountId) -> Result<(), DispatchError> { Account::::try_mutate(who, |a| { if a.providers > 0 { - if a.consumers < T::MaxConsumers::get() { + if a.consumers < T::MaxConsumers::max_consumers() { a.consumers = a.consumers.saturating_add(1); Ok(()) } else { @@ -1138,6 +1168,20 @@ impl Pallet { }) } + /// Increment the reference counter on an account, ignoring the `MaxConsumers` limits. + /// + /// The account `who`'s `providers` must be non-zero or this will return an error. + pub fn inc_consumers_without_limit(who: &T::AccountId) -> Result<(), DispatchError> { + Account::::try_mutate(who, |a| { + if a.providers > 0 { + a.consumers = a.consumers.saturating_add(1); + Ok(()) + } else { + Err(DispatchError::NoProviders) + } + }) + } + /// Decrement the reference counter on an account. This *MUST* only be done once for every time /// you called `inc_consumers` on `who`. pub fn dec_consumers(who: &T::AccountId) { @@ -1172,7 +1216,7 @@ impl Pallet { /// True if the account has at least one provider reference. pub fn can_inc_consumer(who: &T::AccountId) -> bool { let a = Account::::get(who); - a.providers > 0 && a.consumers < T::MaxConsumers::get() + a.providers > 0 && a.consumers < T::MaxConsumers::max_consumers() } /// Deposits an event into this block's event record. From edaf25f99a86011c3249125274e8889b06f7adb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 15 Dec 2021 08:35:05 +0100 Subject: [PATCH 0340/1472] Emit `ContractReverted` error when revert flag is set (#10481) * Emit `ContractReverted` error when revert flag is set * `is_success()` -> `did_revert()` --- frame/contracts/common/src/lib.rs | 12 +++- frame/contracts/src/exec.rs | 10 +-- frame/contracts/src/lib.rs | 26 +++++++- frame/contracts/src/tests.rs | 103 ++++++++++++++++++++++++++++-- frame/contracts/src/wasm/mod.rs | 4 +- 5 files changed, 136 insertions(+), 19 deletions(-) diff --git a/frame/contracts/common/src/lib.rs b/frame/contracts/common/src/lib.rs index d8408f77e06e2..b5873869495e9 100644 --- a/frame/contracts/common/src/lib.rs +++ b/frame/contracts/common/src/lib.rs @@ -131,9 +131,9 @@ pub struct ExecReturnValue { } impl ExecReturnValue { - /// We understand the absense of a revert flag as success. - pub fn is_success(&self) -> bool { - !self.flags.contains(ReturnFlags::REVERT) + /// The contract did revert all storage changes. + pub fn did_revert(&self) -> bool { + self.flags.contains(ReturnFlags::REVERT) } } @@ -170,6 +170,12 @@ pub enum Code { Existing(Hash), } +impl>, Hash> From for Code { + fn from(from: T) -> Self { + Code::Upload(Bytes(from.into())) + } +} + /// The amount of balance that was either charged or refunded in order to pay for storage. #[derive(Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, Clone)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 916c2d3df84f5..bd54c7a08c636 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -686,7 +686,7 @@ where .map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?; // Additional work needs to be performed in case of an instantiation. - if output.is_success() && entry_point == ExportedFunction::Constructor { + if !output.did_revert() && entry_point == ExportedFunction::Constructor { let frame = self.top_frame(); // It is not allowed to terminate a contract inside its constructor. @@ -713,7 +713,7 @@ where let (success, output) = with_transaction(|| { let output = do_transaction(); match &output { - Ok(result) if result.is_success() => TransactionOutcome::Commit((true, output)), + Ok(result) if !result.did_revert() => TransactionOutcome::Commit((true, output)), _ => TransactionOutcome::Rollback((false, output)), } }); @@ -1352,7 +1352,7 @@ mod tests { ) .unwrap(); - assert!(!output.is_success()); + assert!(output.did_revert()); assert_eq!(get_balance(&origin), 100); assert_eq!(get_balance(&dest), balance); }); @@ -1403,7 +1403,7 @@ mod tests { ); let output = result.unwrap(); - assert!(output.is_success()); + assert!(!output.did_revert()); assert_eq!(output.data, Bytes(vec![1, 2, 3, 4])); }); } @@ -1435,7 +1435,7 @@ mod tests { ); let output = result.unwrap(); - assert!(!output.is_success()); + assert!(output.did_revert()); assert_eq!(output.data, Bytes(vec![1, 2, 3, 4])); }); } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 0b8786fa704a3..b604c9618c6ae 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -289,7 +289,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; - let output = Self::internal_call( + let mut output = Self::internal_call( origin, dest, value, @@ -298,6 +298,11 @@ pub mod pallet { data, None, ); + if let Ok(retval) = &output.result { + if retval.did_revert() { + output.result = Err(>::ContractReverted.into()); + } + } output.gas_meter.into_dispatch_result(output.result, T::WeightInfo::call()) } @@ -346,7 +351,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; let code_len = code.len() as u32; let salt_len = salt.len() as u32; - let output = Self::internal_instantiate( + let mut output = Self::internal_instantiate( origin, value, gas_limit, @@ -356,6 +361,11 @@ pub mod pallet { salt, None, ); + if let Ok(retval) = &output.result { + if retval.1.did_revert() { + output.result = Err(>::ContractReverted.into()); + } + } output.gas_meter.into_dispatch_result( output.result.map(|(_address, result)| result), T::WeightInfo::instantiate_with_code(code_len / 1024, salt_len / 1024), @@ -381,7 +391,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let salt_len = salt.len() as u32; - let output = Self::internal_instantiate( + let mut output = Self::internal_instantiate( origin, value, gas_limit, @@ -391,6 +401,11 @@ pub mod pallet { salt, None, ); + if let Ok(retval) = &output.result { + if retval.1.did_revert() { + output.result = Err(>::ContractReverted.into()); + } + } output.gas_meter.into_dispatch_result( output.result.map(|(_address, output)| output), T::WeightInfo::instantiate(salt_len / 1024), @@ -540,6 +555,11 @@ pub mod pallet { StorageDepositLimitExhausted, /// Code removal was denied because the code is still in use by at least one contract. CodeInUse, + /// The contract ran to completion but decided to revert its storage changes. + /// Please note that this error is only returned from extrinsics. When called directly + /// or via RPC an `Ok` will be returned. In this case the caller needs to inspect the flags + /// to determine whether a reversion has taken place. + ContractReverted, } /// A mapping from an original code hash to the original code, untouched by instrumentation. diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 1078a7e73352d..e7745e1e5f7ff 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -24,7 +24,7 @@ use crate::{ storage::Storage, wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, - BalanceOf, CodeStorage, Config, ContractInfoOf, Error, Pallet, Schedule, + BalanceOf, Code, CodeStorage, Config, ContractInfoOf, Error, Pallet, Schedule, }; use assert_matches::assert_matches; use codec::Encode; @@ -1096,7 +1096,7 @@ fn crypto_hashes() { >::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, params, false) .result .unwrap(); - assert!(result.is_success()); + assert!(!result.did_revert()); let expected = hash_fn(input.as_ref()); assert_eq!(&result.data[..*expected_size], &*expected); } @@ -1881,11 +1881,11 @@ fn reinstrument_does_charge() { let result0 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); - assert!(result0.result.unwrap().is_success()); + assert!(!result0.result.unwrap().did_revert()); let result1 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); - assert!(result1.result.unwrap().is_success()); + assert!(!result1.result.unwrap().did_revert()); // They should match because both where called with the same schedule. assert_eq!(result0.gas_consumed, result1.gas_consumed); @@ -1899,7 +1899,7 @@ fn reinstrument_does_charge() { // This call should trigger reinstrumentation let result2 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); - assert!(result2.result.unwrap().is_success()); + assert!(!result2.result.unwrap().did_revert()); assert!(result2.gas_consumed > result1.gas_consumed); assert_eq!( result2.gas_consumed, @@ -2162,7 +2162,7 @@ fn ecdsa_recover() { >::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, params, false) .result .unwrap(); - assert!(result.is_success()); + assert!(!result.did_revert()); assert_eq!(result.data.as_ref(), &EXPECTED_COMPRESSED_PUBLIC_KEY); }) } @@ -2808,3 +2808,94 @@ fn call_after_killed_account_needs_funding() { ); }); } + +#[test] +fn contract_reverted() { + let (wasm, code_hash) = compile_module::("return_with_data").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let flags = ReturnFlags::REVERT; + let buffer = [4u8, 8, 15, 16, 23, 42]; + let input = (flags.bits(), buffer).encode(); + + // We just upload the code for later use + assert_ok!(Contracts::upload_code(Origin::signed(ALICE), wasm.clone(), None)); + + // Calling extrinsic: revert leads to an error + assert_err_ignore_postinfo!( + Contracts::instantiate( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + code_hash, + input.clone(), + vec![], + ), + >::ContractReverted, + ); + + // Calling extrinsic: revert leads to an error + assert_err_ignore_postinfo!( + Contracts::instantiate_with_code( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + input.clone(), + vec![], + ), + >::ContractReverted, + ); + + // Calling directly: revert leads to success but the flags indicate the error + // This is just a different way of transporting the error that allows the read out + // the `data` which is only there on success. Obviously, the contract isn't + // instantiated. + let result = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Existing(code_hash), + input.clone(), + vec![], + false, + ) + .result + .unwrap(); + assert_eq!(result.result.flags, flags); + assert_eq!(result.result.data.0, buffer); + assert!(!>::contains_key(result.account_id)); + + // Pass empty flags and therefore successfully instantiate the contract for later use. + let addr = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Existing(code_hash), + ReturnFlags::empty().bits().encode(), + vec![], + false, + ) + .result + .unwrap() + .account_id; + + // Calling extrinsic: revert leads to an error + assert_err_ignore_postinfo!( + Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, input.clone()), + >::ContractReverted, + ); + + // Calling directly: revert leads to success but the flags indicate the error + let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input, false) + .result + .unwrap(); + assert_eq!(result.flags, flags); + assert_eq!(result.data.0, buffer); + }); +} diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 01e220d410fa4..913894e8152db 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -1765,7 +1765,7 @@ mod tests { data: Bytes(hex!("445566778899").to_vec()), } ); - assert!(output.is_success()); + assert!(!output.did_revert()); } #[test] @@ -1781,7 +1781,7 @@ mod tests { data: Bytes(hex!("5566778899").to_vec()), } ); - assert!(!output.is_success()); + assert!(output.did_revert()); } const CODE_OUT_OF_BOUNDS_ACCESS: &str = r#" From 31cc6a535cdb019763f82f8f53342ffa077fdfc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 15 Dec 2021 09:15:48 +0100 Subject: [PATCH 0341/1472] sp-version: Add some more docs. (#10486) * sp-version: Add some more docs. * Apply suggestions from code review Co-authored-by: Shawn Tabrizi * Update lib.rs Co-authored-by: Shawn Tabrizi --- primitives/version/Cargo.toml | 1 - primitives/version/src/lib.rs | 42 +++++++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 103fe16dc53ab..a58b27c7c1517 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -13,7 +13,6 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] impl-serde = { version = "0.3.1", optional = true } serde = { version = "1.0.126", optional = true, features = ["derive"] } diff --git a/primitives/version/src/lib.rs b/primitives/version/src/lib.rs index 58216bc494dd7..0b72865e7b690 100644 --- a/primitives/version/src/lib.rs +++ b/primitives/version/src/lib.rs @@ -15,7 +15,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Version module for the Substrate runtime; Provides a function that returns the runtime version. +//! Substrate runtime version +//! +//! Each runtime that should be executed by a Substrate based node needs to have a runtime version. +//! The runtime version is defined by [`RuntimeVersion`]. The runtime version is used to +//! distinguish different runtimes. The most important field is the +//! [`spec_version`](RuntimeVersion::spec_version). The `spec_version` should be increased in a +//! runtime when a new runtime build includes breaking changes that would make other runtimes unable +//! to import blocks built by this runtime or vice-versa, where the new runtime could not import +//! blocks built by the old runtime. The runtime version also carries other version information +//! about the runtime, see [`RuntimeVersion`] for more information on this. +//! +//! Substrate will fetch the runtime version from a `wasm` blob by first checking the +//! `runtime_version` link section or calling the `Core::version` runtime api. The link section can +//! be generated in the runtime using the [`runtime_version`] attribute. The `Core` runtime api also +//! needs to be implemented for the runtime using `impl_runtime_apis!`. #![cfg_attr(not(feature = "std"), no_std)] @@ -104,7 +118,23 @@ pub use sp_version_proc_macro::runtime_version; /// The id is generated by hashing the name of the runtime api with BLAKE2 using a hash size /// of 8 bytes. /// -/// The name of the runtime api is the name of the trait when using `decl_runtime_apis!` macro. +/// The name of the runtime api is the name of the trait when using `decl_runtime_apis!` macro. So, +/// in the following runtime api declaration: +/// +/// ```nocompile +/// decl_runtime_apis! { +/// trait TestApi { +/// fn do_test(); +/// } +/// } +/// ``` +/// +/// The name of the trait would be `TestApi` and would be taken as input to the BLAKE2 hash +/// function. +/// +/// As Rust supports renaming of traits, the name of a runtime api given to `impl_runtime_apis!` +/// doesn't need to be the same as in `decl_runtime_apis!`, but only the name in +/// `decl_runtime_apis!` is the important one! pub type ApiId = [u8; 8]; /// A vector of pairs of `ApiId` and a `u32` for version. @@ -216,12 +246,16 @@ impl RuntimeVersion { } } -#[cfg(feature = "std")] +/// The version of the native runtime. +/// +/// In contrast to the bare [`RuntimeVersion`] this also carries a list of `spec_version`s of +/// runtimes this native runtime can be used to author blocks for. #[derive(Debug)] +#[cfg(feature = "std")] pub struct NativeVersion { /// Basic runtime version info. pub runtime_version: RuntimeVersion, - /// Authoring runtimes that this native runtime supports. + /// Authoring runtimes (`spec_version`s) that this native runtime supports. pub can_author_with: HashSet, } From 027368fe34e9a57ead752d4f900db6b5f85352e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 15 Dec 2021 12:13:18 +0100 Subject: [PATCH 0342/1472] Fix link to grafana dashboard (#10492) --- .maintain/monitoring/grafana-dashboards/README_dashboard.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.maintain/monitoring/grafana-dashboards/README_dashboard.md b/.maintain/monitoring/grafana-dashboards/README_dashboard.md index e00b89449cfaf..50f54a107e933 100644 --- a/.maintain/monitoring/grafana-dashboards/README_dashboard.md +++ b/.maintain/monitoring/grafana-dashboards/README_dashboard.md @@ -4,4 +4,4 @@ Shared templated Grafana dashboards. To import the dashboards follow the [Grafana documentation](https://grafana.com/docs/grafana/latest/reference/export_import/). -You can see an example setup [here](../../../.maintain/sentry-node). +You can see an example setup [here](./substrate-networking.json). From 50ab759f7a3194173ce8da0937ec2d888dee10e0 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 15 Dec 2021 12:36:17 +0100 Subject: [PATCH 0343/1472] Prepare `sp-runtime` for publication (#10451) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump versions of sp-core and dependencies to v4.0.0 * Update references from `4.0.0-dev` –> `4.0.0` * Funny whitespace * Funny whitespace 2 * Prepare `sp-runtime` for publication --- Cargo.lock | 16 ++++++++-------- bin/node-template/node/Cargo.toml | 2 +- bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 2 +- bin/node/bench/Cargo.toml | 6 +++--- bin/node/cli/Cargo.toml | 6 +++--- bin/node/executor/Cargo.toml | 10 +++++----- bin/node/inspect/Cargo.toml | 2 +- bin/node/primitives/Cargo.toml | 4 ++-- bin/node/rpc/Cargo.toml | 4 ++-- bin/node/runtime/Cargo.toml | 4 ++-- bin/node/testing/Cargo.toml | 2 +- bin/utils/chain-spec-builder/Cargo.toml | 2 +- client/api/Cargo.toml | 8 ++++---- client/authority-discovery/Cargo.toml | 4 ++-- client/basic-authorship/Cargo.toml | 2 +- client/beefy/Cargo.toml | 8 ++++---- client/beefy/rpc/Cargo.toml | 2 +- client/block-builder/Cargo.toml | 4 ++-- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 6 +++--- client/consensus/aura/Cargo.toml | 6 +++--- client/consensus/babe/Cargo.toml | 8 ++++---- client/consensus/babe/rpc/Cargo.toml | 6 +++--- client/consensus/common/Cargo.toml | 4 ++-- client/consensus/epochs/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 4 ++-- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 6 +++--- client/consensus/uncles/Cargo.toml | 2 +- client/db/Cargo.toml | 8 ++++---- client/executor/Cargo.toml | 8 ++++---- client/executor/runtime-test/Cargo.toml | 2 +- client/executor/wasmtime/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 8 ++++---- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/informant/Cargo.toml | 2 +- client/keystore/Cargo.toml | 4 ++-- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 4 ++-- client/network/test/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc/Cargo.toml | 6 +++--- client/service/Cargo.toml | 10 +++++----- client/service/test/Cargo.toml | 8 ++++---- client/sync-state-rpc/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- frame/assets/Cargo.toml | 4 ++-- frame/atomic-swap/Cargo.toml | 2 +- frame/aura/Cargo.toml | 4 ++-- frame/authority-discovery/Cargo.toml | 4 ++-- frame/authorship/Cargo.toml | 2 +- frame/babe/Cargo.toml | 6 +++--- frame/bags-list/Cargo.toml | 2 +- frame/bags-list/remote-tests/Cargo.toml | 2 +- frame/balances/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 8 ++++---- frame/bounties/Cargo.toml | 4 ++-- frame/child-bounties/Cargo.toml | 2 +- frame/collective/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/common/Cargo.toml | 2 +- frame/contracts/rpc/Cargo.toml | 2 +- frame/contracts/rpc/runtime-api/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 4 ++-- frame/election-provider-multi-phase/Cargo.toml | 6 +++--- frame/election-provider-support/Cargo.toml | 4 ++-- frame/elections-phragmen/Cargo.toml | 4 ++-- frame/examples/basic/Cargo.toml | 4 ++-- frame/examples/offchain-worker/Cargo.toml | 4 ++-- frame/examples/parallel/Cargo.toml | 2 +- frame/executive/Cargo.toml | 2 +- frame/gilt/Cargo.toml | 4 ++-- frame/grandpa/Cargo.toml | 6 +++--- frame/identity/Cargo.toml | 4 ++-- frame/im-online/Cargo.toml | 6 +++--- frame/indices/Cargo.toml | 2 +- frame/lottery/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- .../merkle-mountain-range/primitives/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 4 ++-- frame/nicks/Cargo.toml | 4 ++-- frame/node-authorization/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/offences/benchmarking/Cargo.toml | 2 +- frame/preimage/Cargo.toml | 2 +- frame/proxy/Cargo.toml | 4 ++-- frame/randomness-collective-flip/Cargo.toml | 2 +- frame/recovery/Cargo.toml | 4 ++-- frame/scheduler/Cargo.toml | 4 ++-- frame/scored-pool/Cargo.toml | 4 ++-- frame/session/Cargo.toml | 4 ++-- frame/session/benchmarking/Cargo.toml | 2 +- frame/society/Cargo.toml | 2 +- frame/staking/Cargo.toml | 6 +++--- frame/staking/reward-curve/Cargo.toml | 2 +- frame/staking/reward-fn/Cargo.toml | 2 +- frame/sudo/Cargo.toml | 4 ++-- frame/support/Cargo.toml | 8 ++++---- frame/support/test/Cargo.toml | 8 ++++---- frame/support/test/compile_pass/Cargo.toml | 2 +- frame/system/Cargo.toml | 4 ++-- frame/system/benchmarking/Cargo.toml | 4 ++-- frame/timestamp/Cargo.toml | 4 ++-- frame/tips/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- frame/transaction-payment/rpc/Cargo.toml | 2 +- .../rpc/runtime-api/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 4 ++-- frame/treasury/Cargo.toml | 2 +- frame/try-runtime/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 2 +- frame/utility/Cargo.toml | 4 ++-- frame/vesting/Cargo.toml | 2 +- primitives/api/Cargo.toml | 4 ++-- primitives/api/test/Cargo.toml | 4 ++-- primitives/application-crypto/Cargo.toml | 4 ++-- primitives/application-crypto/test/Cargo.toml | 6 +++--- primitives/arithmetic/Cargo.toml | 2 +- primitives/arithmetic/fuzzer/Cargo.toml | 2 +- primitives/authority-discovery/Cargo.toml | 4 ++-- primitives/authorship/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 6 +++--- primitives/block-builder/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 4 ++-- primitives/consensus/aura/Cargo.toml | 4 ++-- primitives/consensus/babe/Cargo.toml | 6 +++--- primitives/consensus/common/Cargo.toml | 4 ++-- primitives/consensus/pow/Cargo.toml | 2 +- primitives/consensus/slots/Cargo.toml | 4 ++-- primitives/consensus/vrf/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 6 +++--- primitives/inherents/Cargo.toml | 2 +- primitives/io/Cargo.toml | 8 ++++---- primitives/keyring/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 4 ++-- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- .../npos-elections/solution-type/Cargo.toml | 2 +- primitives/offchain/Cargo.toml | 2 +- primitives/panic-handler/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 2 +- primitives/runtime-interface/test/Cargo.toml | 6 +++--- primitives/runtime/Cargo.toml | 10 +++++----- primitives/sandbox/Cargo.toml | 2 +- primitives/session/Cargo.toml | 2 +- primitives/staking/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 8 ++++---- primitives/tasks/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 4 ++-- primitives/timestamp/Cargo.toml | 2 +- primitives/transaction-pool/Cargo.toml | 2 +- primitives/transaction-storage-proof/Cargo.toml | 4 ++-- primitives/trie/Cargo.toml | 4 ++-- primitives/version/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 6 +++--- test-utils/runtime/Cargo.toml | 10 +++++----- test-utils/runtime/client/Cargo.toml | 2 +- test-utils/runtime/transaction-pool/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 6 +++--- utils/frame/frame-utilities-cli/Cargo.toml | 2 +- utils/frame/generate-bags/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 6 +++--- 173 files changed, 317 insertions(+), 317 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6c49939a8ff0..0364fafd2547f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9203,7 +9203,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "parity-scale-codec", "scale-info", @@ -9227,7 +9227,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "criterion", "integer-sqrt", @@ -9528,7 +9528,7 @@ dependencies = [ [[package]] name = "sp-io" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "futures 0.3.16", "hash-db", @@ -9561,7 +9561,7 @@ dependencies = [ [[package]] name = "sp-keystore" -version = "0.10.0-dev" +version = "0.10.0" dependencies = [ "async-trait", "derive_more", @@ -9639,7 +9639,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "backtrace", "lazy_static", @@ -9658,7 +9658,7 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "either", "hash256-std-hasher", @@ -9802,7 +9802,7 @@ dependencies = [ [[package]] name = "sp-state-machine" -version = "0.10.0-dev" +version = "0.10.0" dependencies = [ "hash-db", "hex-literal", @@ -9917,7 +9917,7 @@ dependencies = [ [[package]] name = "sp-trie" -version = "4.0.0-dev" +version = "4.0.0" dependencies = [ "criterion", "hash-db", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 731e6fcda4083..dbf44a75c1399 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -34,7 +34,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo sc-finality-grandpa = { version = "0.10.0-dev", path = "../../../client/finality-grandpa" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } # These dependencies are used for the node template's RPCs diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index d473119702f87..ab69a3fe73ea9 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -24,7 +24,7 @@ frame-benchmarking = { default-features = false, version = "4.0.0-dev", path = " [dev-dependencies] sp-core = { default-features = false, version = "4.1.0-dev", path = "../../../../primitives/core" } sp-io = { default-features = false, version = "4.0.0-dev", path = "../../../../primitives/io" } -sp-runtime = { default-features = false, version = "4.0.0-dev", path = "../../../../primitives/runtime" } +sp-runtime = { default-features = false, version = "4.0.0", path = "../../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 4818535e196c4..c56162c8ffed9 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -32,7 +32,7 @@ sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = " sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-inherents = { path = "../../../primitives/inherents", default-features = false, version = "4.0.0-dev"} sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 65d12378c4cf5..8d2ca810273cf 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -14,15 +14,15 @@ node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } serde = "1.0.126" serde_json = "1.0.71" structopt = "0.3" derive_more = "0.99.16" kvdb = "0.10.0" kvdb-rocksdb = "0.14.0" -sp-trie = { version = "4.0.0-dev", path = "../../../primitives/trie" } +sp-trie = { version = "4.0.0", path = "../../../primitives/trie" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-basic-authorship = { version = "0.10.0-dev", path = "../../../client/basic-authorship" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 6da2fddd331ea..d7143b39816b4 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -48,12 +48,12 @@ sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consen grandpa-primitives = { version = "4.0.0-dev", package = "sp-finality-grandpa", path = "../../../primitives/finality-grandpa" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } -sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../../primitives/transaction-pool" } sp-transaction-storage-proof = { version = "4.0.0-dev", path = "../../../primitives/transaction-storage-proof" } @@ -106,7 +106,7 @@ sc-cli = { version = "0.10.0-dev", optional = true, path = "../../../client/cli" sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service", features = [ "wasmtime", ] } -sp-trie = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/trie", features = [ +sp-trie = { version = "4.0.0", default-features = false, path = "../../../primitives/trie", features = [ "memory-tracker", ] } diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 20898315d0e0a..531e53d2048a9 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -18,10 +18,10 @@ node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } -sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } +sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } +sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } -sp-trie = { version = "4.0.0-dev", path = "../../../primitives/trie" } +sp-trie = { version = "4.0.0", path = "../../../primitives/trie" } frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } [dev-dependencies] @@ -34,9 +34,9 @@ pallet-contracts = { version = "4.0.0-dev", path = "../../../frame/contracts" } pallet-im-online = { version = "4.0.0-dev", path = "../../../frame/im-online" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } pallet-treasury = { version = "4.0.0-dev", path = "../../../frame/treasury" } -sp-application-crypto = { version = "4.0.0-dev", path = "../../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", path = "../../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } wat = "1.0" diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index b0db8f6304761..cb9557b506a14 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -19,5 +19,5 @@ sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } structopt = "0.3.8" diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index d2c315bd9b6e1..05def58be2341 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -16,9 +16,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../../primitives/application-crypto" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index ef111e3f1949c..3eed3ad4e0cc0 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -29,9 +29,9 @@ sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-frame-rpc-system = { version = "4.0.0-dev", path = "../../../utils/frame/rpc/system" } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 83a66f5a47b6d..fa879adf5cbb4 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -33,14 +33,14 @@ sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../. sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-keyring = { version = "4.0.0-dev", optional = true, path = "../../../primitives/keyring" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } +sp-io = { version = "4.0.0", default-features = false, path = "../../../primitives/io" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } # frame dependencies diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 7f3a911962488..bee6f92d1280b 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -30,7 +30,7 @@ node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = [ "wasmtime", ] } diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index c5872ca29700d..f9bb4f94491a8 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -19,6 +19,6 @@ sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } node-cli = { version = "3.0.0-dev", path = "../../node/cli" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } rand = "0.7.2" structopt = "0.3.25" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index 13ec13538e65e..4738a7d611b15 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -28,12 +28,12 @@ log = "0.4.8" parking_lot = "0.11.1" sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../../primitives/keystore" } +sp-keystore = { version = "0.10.0", default-features = false, path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } -sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } +sp-trie = { version = "4.0.0", path = "../../primitives/trie" } sp-storage = { version = "4.0.0", path = "../../primitives/storage" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 207f22753e452..fd94e71ceb842 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -33,8 +33,8 @@ sc-network = { version = "0.10.0-dev", path = "../network" } sp-authority-discovery = { version = "4.0.0-dev", path = "../../primitives/authority-discovery" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } [dev-dependencies] diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index c1a8e9210a416..4b4627cb6eeac 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -19,7 +19,7 @@ futures-timer = "3.0.1" log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index cb561c0dc77a6..6c281deb85ea1 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -19,12 +19,12 @@ codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive prometheus = { version = "0.10.0-dev", package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } -sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } +sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } +sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 83f6b392f55c7..9f4a1305f2d03 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -22,7 +22,7 @@ codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } beefy-gadget = { version = "4.0.0-dev", path = "../." } beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 69154699e3f1d..ab77bc005f6c2 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index fdc72307af2a1..d06e0bce18c15 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -19,7 +19,7 @@ sc-network = { version = "0.10.0-dev", path = "../network" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } serde = { version = "1.0.126", features = ["derive"] } serde_json = "1.0.71" -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "2.0.0" } memmap2 = "0.5.0" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 566ce21cfe903..2e2b208923d57 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -25,15 +25,15 @@ rand = "0.7.3" tiny-bip39 = "0.8.2" serde_json = "1.0.71" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -sp-panic-handler = { version = "4.0.0-dev", path = "../../primitives/panic-handler" } +sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-network = { version = "0.10.0-dev", path = "../network" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../service" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index f12578b8a6780..05f0d3804e7b9 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0-dev", path = "../../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", path = "../../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consensus/aura" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } @@ -30,8 +30,8 @@ sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } async-trait = "0.1.50" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 7daab5557b57c..634c987444a07 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -20,14 +20,14 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-application-crypto = { version = "4.0.0-dev", path = "../../../primitives/application-crypto" } -sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } +sp-application-crypto = { version = "4.0.0", path = "../../../primitives/application-crypto" } +sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } num-bigint = "0.2.3" num-rational = "0.2.2" num-traits = "0.2.8" serde = { version = "1.0.126", features = ["derive"] } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } -sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } +sp-io = { version = "4.0.0", path = "../../../primitives/io" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } @@ -40,7 +40,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } sp-consensus-vrf = { version = "0.10.0-dev", path = "../../../primitives/consensus/vrf" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } futures = "0.3.9" diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 3bd8bf6e76580..cea2aea4553b1 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -21,15 +21,15 @@ jsonrpc-derive = "18.0.0" sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } serde = { version = "1.0.126", features=["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } -sp-runtime = { version = "4.0.0-dev", path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } futures = "0.3.16" derive_more = "0.99.16" sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } -sp-application-crypto = { version = "4.0.0-dev", path = "../../../../primitives/application-crypto" } -sp-keystore = { version = "0.10.0-dev", path = "../../../../primitives/keystore" } +sp-application-crypto = { version = "4.0.0", path = "../../../../primitives/application-crypto" } +sp-keystore = { version = "0.10.0", path = "../../../../primitives/keystore" } [dev-dependencies] sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index f20e12cc4aae8..9d2323b75760a 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -22,8 +22,8 @@ sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } -sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } parking_lot = "0.11.1" diff --git a/client/consensus/epochs/Cargo.toml b/client/consensus/epochs/Cargo.toml index 4cac4a24d1879..efd11b8d401d0 100644 --- a/client/consensus/epochs/Cargo.toml +++ b/client/consensus/epochs/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } -sp-runtime = { path = "../../../primitives/runtime" , version = "4.0.0-dev"} +sp-runtime = { path = "../../../primitives/runtime" , version = "4.0.0"} sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-client-api = { path = "../../api" , version = "4.0.0-dev"} sc-consensus = { path = "../common" , version = "0.10.0-dev"} diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 59d35819c7815..c69ed21fb3a91 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -35,9 +35,9 @@ sp-blockchain = { path = "../../../primitives/blockchain", version = "4.0.0-dev" sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } sp-consensus-slots = { path = "../../../primitives/consensus/slots", version = "0.10.0-dev" } sp-inherents = { path = "../../../primitives/inherents", version = "4.0.0-dev" } -sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0-dev" } +sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0" } sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } -sp-keystore = { path = "../../../primitives/keystore", version = "0.10.0-dev" } +sp-keystore = { path = "../../../primitives/keystore", version = "0.10.0" } sp-api = { path = "../../../primitives/api", version = "4.0.0-dev" } sc-transaction-pool-api = { path = "../../../client/transaction-pool/api", version = "4.0.0-dev" } sp-timestamp = { path = "../../../primitives/timestamp", version = "4.0.0-dev" } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index d4b156f0b8faa..00ee58c212477 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index c97a3d1fe0356..bf2bd59bb91e7 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -17,12 +17,12 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-arithmetic = { version = "4.0.0-dev", path = "../../../primitives/arithmetic" } +sp-arithmetic = { version = "4.0.0", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml index bc5f1f25838c9..346d3e34c01b1 100644 --- a/client/consensus/uncles/Cargo.toml +++ b/client/consensus/uncles/Cargo.toml @@ -14,6 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } thiserror = "1.0.30" diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index a2ed46c48e1cf..80ba026de3cf6 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -25,12 +25,12 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ ] } sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } -sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } -sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } +sp-trie = { version = "4.0.0", path = "../../primitives/trie" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } parity-db = { version = "0.3.5", optional = true } diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 377623512fa36..a87a382913706 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -18,9 +18,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-tasks = { version = "4.0.0-dev", path = "../../primitives/tasks" } -sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } +sp-trie = { version = "4.0.0", path = "../../primitives/trie" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } -sp-panic-handler = { version = "4.0.0-dev", path = "../../primitives/panic-handler" } +sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } wasmi = "0.9.1" lazy_static = "1.4.0" sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } @@ -41,8 +41,8 @@ wat = "1.0" hex-literal = "0.3.4" sc-runtime-test = { version = "2.0.0", path = "runtime-test" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } -sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } tracing = "0.1.29" diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index 4572a23c630ae..8fbaf2102aeb5 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 06f668ef67b4d..6718e6d13f3ce 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -32,5 +32,5 @@ wasmtime = { version = "0.31.0", default-features = false, features = [ [dev-dependencies] sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } -sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } +sp-io = { version = "4.0.0", path = "../../../primitives/io" } wat = "1.0" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 12aedbfe0143b..2ddd4f765163e 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -24,14 +24,14 @@ log = "0.4.8" parking_lot = "0.11.1" rand = "0.8.4" parity-scale-codec = { version = "2.3.1", features = ["derive"] } -sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } -sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } +sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 9d0affde3b17a..b923ec41d33f9 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -13,7 +13,7 @@ sc-finality-grandpa = { version = "0.10.0-dev", path = "../" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } finality-grandpa = { version = "0.14.4", features = ["derive-codec"] } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index 5eba3ecaeb2ac..d6e9c655aad9d 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -21,5 +21,5 @@ parity-util-mem = { version = "0.10.2", default-features = false, features = ["p sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 912de249ad0b0..abdd4ac372e74 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" derive_more = "0.99.16" -sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } hex = "0.4.0" parking_lot = "0.11.1" serde_json = "1.0.71" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 840cb50c8c9fc..c90d1db44afcb 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -22,7 +22,7 @@ log = "0.4.8" lru = "0.7.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } tracing = "0.1.29" [dev-dependencies] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 5c8aedc84c19d..95f84f493bb74 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -49,12 +49,12 @@ sc-peerset = { version = "4.0.0-dev", path = "../peerset" } serde = { version = "1.0.126", features = ["derive"] } serde_json = "1.0.71" smallvec = "1.7.0" -sp-arithmetic = { version = "4.0.0-dev", path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } thiserror = "1" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 748037fef6448..fd9e9e2f7ef37 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -25,7 +25,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 4494beb2e3f41..5ed182d6cfc41 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -27,7 +27,7 @@ sc-network = { version = "0.10.0-dev", path = "../network" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } threadpool = "1.7" hyper = { version = "0.14.14", features = ["stream", "http2"] } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 3c97677c3feec..18f499c51448a 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -25,7 +25,7 @@ thiserror = "1.0" sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } -sp-runtime = { path = "../../primitives/runtime", version = "4.0.0-dev" } +sp-runtime = { path = "../../primitives/runtime", version = "4.0.0" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } serde = { version = "1.0.126", features = ["derive"] } serde_json = "1.0.71" diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 1f1fe6b12aed1..707fbf75f7c61 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -26,10 +26,10 @@ sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } serde_json = "1.0.71" sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } -sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } @@ -43,7 +43,7 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/a assert_matches = "1.3.0" lazy_static = "1.4.0" sc-network = { version = "0.10.0-dev", path = "../network" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-io = { version = "4.0.0", path = "../../primitives/io" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 25cd9026bc8b6..6d96cafec2014 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -36,17 +36,17 @@ hash-db = "0.15.2" serde = "1.0.126" serde_json = "1.0.71" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } -sp-trie = { version = "4.0.0-dev", path = "../../primitives/trie" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-trie = { version = "4.0.0", path = "../../primitives/trie" } sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } -sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } -sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto" } +sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } +sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 52f0ff6ecce0e..113ed0d0802be 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -21,9 +21,9 @@ fdlimit = "0.2.1" parking_lot = "0.11.1" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } +sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } -sp-trie = { version = "4.0.0-dev", path = "../../../primitives/trie" } +sp-trie = { version = "4.0.0", path = "../../../primitives/trie" } sp-storage = { version = "4.0.0", path = "../../../primitives/storage" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../../db" } futures = "0.3.16" @@ -31,7 +31,7 @@ sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../. sc-network = { version = "0.10.0-dev", path = "../../network" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } @@ -39,6 +39,6 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-executor = { version = "0.10.0-dev", path = "../../executor" } -sp-panic-handler = { version = "4.0.0-dev", path = "../../../primitives/panic-handler" } +sp-panic-handler = { version = "4.0.0", path = "../../../primitives/panic-handler" } parity-scale-codec = "2.3.1" sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index c609ac42c76e9..a7b632b818002 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -26,5 +26,5 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } serde_json = "1.0.71" serde = { version = "1.0.126", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 4d91e61127db8..137cab554613c 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -30,7 +30,7 @@ tracing-log = "0.1.2" tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 6ed97edbf476e..9aaaaa36a2cb8 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -24,7 +24,7 @@ prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../.. sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index f44ec588e9543..0c65234b0d683 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -13,7 +13,7 @@ futures = { version = "0.3.1" } log = { version = "0.4.8" } serde = { version = "1.0.126", features = ["derive"] } thiserror = { version = "1.0.30" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } derive_more = { version = "0.99.16" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 37ff7582f5c61..c36200fb1ac44 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } # Needed for type-safe access to storage DB. frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } # `system` module provides us with all sorts of useful stuff and macros depend on it being around. @@ -27,7 +27,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " [dev-dependencies] sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-std = { version = "4.0.0", path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-io = { version = "4.0.0", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 54e579550443d..7a1415946e76e 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index 9ed07e724b30f..34956b1116e91 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -13,11 +13,11 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-consensus-aura = { version = "0.10.0-dev", path = "../../primitives/consensus/aura", default-features = false } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index 1a0f5925732c8..4cb40a0f2661f 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authority-discovery" } -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } @@ -23,7 +23,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives pallet-session = { version = "4.0.0-dev", features = [ "historical", ], path = "../session", default-features = false } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 2a0dc8bdd9a74..77be81c082b1f 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } impl-trait-for-tuples = "0.2.1" diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 414cfcb222d40..5242de638c387 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -21,11 +21,11 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-consensus-vrf = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/vrf" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 66bb1c48a929f..e5e746ad1b62e 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } # primitives -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # FRAME diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 646b47275c18b..8e6a24674d0af 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -24,7 +24,7 @@ frame-support = { path = "../../support", version = "4.0.0-dev" } sp-storage = { path = "../../../primitives/storage", version = "4.0.0" } sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } sp-tracing = { path = "../../../primitives/tracing", version = "4.0.0" } -sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0-dev" } +sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0" } sp-std = { path = "../../../primitives/std", version = "4.0.0" } # utils diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 1ac7b71fb3405..fdabb4132b1a2 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 64cdf805db9a2..50c4fd3f7f3ba 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -23,7 +23,7 @@ pallet-session = { version = "4.0.0-dev", path = "../session", default-features sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } beefy-merkle-tree = { version = "4.0.0-dev", path = "./primitives", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index c90f0d7328be0..2f7059d5156cd 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -15,7 +15,7 @@ serde = { version = "1.0.130", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 1e89c39be1c4e..d3dcf589e4465 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -19,10 +19,10 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } sp-runtime-interface = { version = "4.1.0-dev", path = "../../primitives/runtime-interface", default-features = false } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime", default-features = false } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-application-crypto = { version = "4.0.0-dev", path = "../../primitives/application-crypto", default-features = false } +sp-io = { version = "4.0.0", path = "../../primitives/io", default-features = false } +sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto", default-features = false } sp-storage = { version = "4.0.0", path = "../../primitives/storage", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -30,7 +30,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] hex-literal = "0.3.4" -sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } [features] default = ["std"] diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 97364ba41f63f..2e328e19b8ecd 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -18,11 +18,11 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } +sp-io = { version = "4.0.0", path = "../../primitives/io", default-features = false } sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 17cfc482af065..fcd8e839fb1e5 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index 6d3b081c89c1e..cc17a6d7ce604 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -19,7 +19,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 963f1466a9ea1..4067148e13e15 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -40,7 +40,7 @@ pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/common/Cargo.toml index 0e0cf1528b1a8..2b565b4c9e2ca 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/common/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1", features = ["derive"], optional = true } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc", optional = true } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index e380708a9dee4..51a512277c566 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -26,7 +26,7 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } [dev-dependencies] serde_json = "1" diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml index 2c293b3a906a1..c7251306192e3 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/rpc/runtime-api/Cargo.toml @@ -19,7 +19,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] # Substrate Dependencies pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, path = "../../common" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../../primitives/std" } [features] diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 32acdb964ed88..b1b84d9ad03d1 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -19,8 +19,8 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index a1df7edc13311..72ec62f321cff 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -23,12 +23,12 @@ log = { version = "0.4.14", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } # Optional imports for benchmarking diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 80b7f9d7bfc05..8fabefa7a12cf 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -16,14 +16,14 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index 7ab81a4f33008..bcf91ac5c73ca 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index db39d339f2c5c..48f505444884a 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -21,8 +21,8 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index f53ea369278de..6152b2ca95ee2 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -22,8 +22,8 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../.. frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore", optional = true } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore", optional = true } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [features] diff --git a/frame/examples/parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml index d28dd5b9ee0ab..94c18b6c98285 100644 --- a/frame/examples/parallel/Cargo.toml +++ b/frame/examples/parallel/Cargo.toml @@ -19,7 +19,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../.. frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index d511bb858c7d6..02cb2b22b3886 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index 05e252627b2b7..39b9fb5582936 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 601ec9aee10ee..f123fdbb61ee8 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -15,13 +15,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 76a187f90c5d2..32e62d8aec0b1 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -17,8 +17,8 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } enumflags2 = { version = "0.6.2" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index fdafc5376ad5a..dc839d0d1f9ec 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -13,14 +13,14 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index cd3957a45f824..da56606ed2f69 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -18,7 +18,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-keyring = { version = "4.0.0-dev", optional = true, path = "../../primitives/keyring" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 259be8267fe75..9f31f80173416 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index d0567a3eeb15a..fc0d44c766568 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -19,7 +19,7 @@ log = { version = "0.4.0", default-features = false } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index fd6615a4b5420..10476e9a73dd1 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -18,7 +18,7 @@ mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, ver sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index 0d11e50a8b682..713da64e26d9f 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -18,7 +18,7 @@ serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 7283a4fac8b2e..13d60142dfc30 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1.0.126", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index d01dd58a2f3f4..d1c8d8c60c21f 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 28cabde09166d..08d529070a5e0 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index efaaf6371f8c3..350914381c1e3 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -18,7 +18,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } log = { version = "0.4.14", default-features = false } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 5058f17d38570..02f36fab0a213 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } serde = { version = "1.0.126", optional = true } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index 625f275a70ce0..28e4fde7c3cee 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -29,7 +29,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, path = "../. pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ "runtime-benchmarks", ], path = "../../staking" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index b60c3fa854871..29763d08017f5 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -16,7 +16,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-core = { version = "4.1.0-dev", default-features = false, optional = true, path = "../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index 7a1fc61da9d46..c5d9dc857b8d5 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -17,8 +17,8 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index 903e167ef95a3..037ce134045ca 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] safe-mix = { version = "1.0", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index c1126ad1edd13..3ed194225d0ab 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 2f76735981510..9cc34f69db793 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index e77661204d733..f570039abc33a 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 909dfe329c9c0..57b7fff994792 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -22,10 +22,10 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-trie = { version = "4.0.0-dev", default-features = false, path = "../../primitives/trie", optional = true } +sp-trie = { version = "4.0.0", default-features = false, path = "../../primitives/trie", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 37dc40e9b25cb..5f889e66a870e 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] rand = { version = "0.7.2", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index cf14d7f9f51c5..ad53026f4ce02 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 42fe1075317dd..c91db8c24fda3 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -19,8 +19,8 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -28,7 +28,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, features = [ "historical", ], path = "../session" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } log = { version = "0.4.14", default-features = false } diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index fd306eb085727..82f0a6dde2be1 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -21,4 +21,4 @@ proc-macro2 = "1.0.29" proc-macro-crate = "1.1.0" [dev-dependencies] -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } diff --git a/frame/staking/reward-fn/Cargo.toml b/frame/staking/reward-fn/Cargo.toml index 4e3be2a1bc719..07dc404c8e357 100644 --- a/frame/staking/reward-fn/Cargo.toml +++ b/frame/staking/reward-fn/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [lib] [dependencies] -sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/arithmetic" } +sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../../primitives/arithmetic" } log = { version = "0.4.14", default-features = false } [features] diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index 33642ef7dc3ee..c553c80d19d21 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index c3eab98f9e779..3cfce23dabe09 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -18,18 +18,18 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-metadata = { version = "14.0.0", default-features = false, features = ["v14"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } tt-call = "1.0.8" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } -sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../../primitives/state-machine" } +sp-state-machine = { version = "0.10.0", optional = true, path = "../../primitives/state-machine" } bitflags = "1.3" impl-trait-for-tuples = "0.2.1" smallvec = "1.7.0" diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index cdbefae4bde70..d41b0fcacf236 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.126", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/arithmetic" } -sp-io = { version = "4.0.0-dev", path = "../../../primitives/io", default-features = false } -sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../../../primitives/state-machine" } +sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../../primitives/arithmetic" } +sp-io = { version = "4.0.0", path = "../../../primitives/io", default-features = false } +sp-state-machine = { version = "0.10.0", optional = true, path = "../../../primitives/state-machine" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index b72bbc2f01f5b..21d3be667253d 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 0d771cd1f80d2..70a9b12c7a237 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -18,8 +18,8 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", path = "../../primitives/io", default-features = false } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } log = { version = "0.4.14", default-features = false } diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index acf13c8f6b2a4..ff31c6fdbac49 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -16,14 +16,14 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } [dev-dependencies] -sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } +sp-io = { version = "4.0.0", path = "../../../primitives/io" } [features] default = ["std"] diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index f8ff0a587b1a1..e10acdc254572 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -18,8 +18,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io", optional = true } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io", optional = true } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index cb682769ec858..a637fa3928e02 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -20,7 +20,7 @@ serde = { version = "1.0.126", features = ["derive"], optional = true } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 642c9bd399b92..ac6fc5c71c049 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -22,7 +22,7 @@ smallvec = "1.7.0" sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 21fae45282d03..3f89a5c4b5f09 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] # Substrate dependencies sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 36dad610f696a..b8e43848dbf4e 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -22,5 +22,5 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 315f140fc4f23..6cfe02d15c4f8 100644 --- a/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../../../primitives/runtime" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment" } [features] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index f5ce6f8441663..10f1d3d2e2b29 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -20,9 +20,9 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-storage-proof" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index fed6b98f55eb2..5fe5734120d69 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1.0.126", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.1" sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index 64622bcceb020..860a9e988b117 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std" , default-features = false } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" , default-features = false } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" , default-features = false } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 2ce0c1b484eaf..c9892cac26978 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 9dfbd7b410ef4..62fa402705ef6 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -18,9 +18,9 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 30cdc91d44f38..fa0b564c855dc 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index 65e39571c7eb8..b940ae93baa55 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../version" } -sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../state-machine" } +sp-state-machine = { version = "0.10.0", optional = true, path = "../state-machine" } hash-db = { version = "0.15.2", optional = true } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index b7716f6b8de7a..53d26c08c1d93 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -16,11 +16,11 @@ sp-api = { version = "4.0.0-dev", path = "../" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } sp-version = { version = "4.0.0-dev", path = "../../version" } sp-tracing = { version = "4.0.0", path = "../../tracing" } -sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } +sp-runtime = { version = "4.0.0", path = "../../runtime" } sp-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } codec = { package = "parity-scale-codec", version = "2.0.0" } -sp-state-machine = { version = "0.10.0-dev", path = "../../state-machine" } +sp-state-machine = { version = "0.10.0", path = "../../state-machine" } trybuild = "1.0.53" rustversion = "1.0.5" diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index f3a9f9a938390..8090203bbca0f 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-application-crypto" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" description = "Provides facilities for generating application specific crypto wrapper types." @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } +sp-io = { version = "4.0.0", default-features = false, path = "../io" } [features] default = [ "std" ] diff --git a/primitives/application-crypto/test/Cargo.toml b/primitives/application-crypto/test/Cargo.toml index dc51dceeeb4d1..0fdb64c5b2925 100644 --- a/primitives/application-crypto/test/Cargo.toml +++ b/primitives/application-crypto/test/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } -sp-keystore = { version = "0.10.0-dev", path = "../../keystore", default-features = false } +sp-keystore = { version = "0.10.0", path = "../../keystore", default-features = false } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } +sp-runtime = { version = "4.0.0", path = "../../runtime" } sp-api = { version = "4.0.0-dev", path = "../../api" } -sp-application-crypto = { version = "4.0.0-dev", path = "../" } +sp-application-crypto = { version = "4.0.0", path = "../" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 9bd634bb51879..8db65342cfa0d 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-arithmetic" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index d6b2088523773..33951687c3138 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -14,7 +14,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-arithmetic = { version = "4.0.0-dev", path = ".." } +sp-arithmetic = { version = "4.0.0", path = ".." } honggfuzz = "0.5.49" primitive-types = "0.10.1" num-bigint = "0.2" diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index 116bc1438ce67..2f1d38c311529 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -13,12 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", default-features = false, version = "2.0.0" } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } [features] default = ["std"] diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index 26259e45ea6bb..81fa39e93a1ad 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 4391b1939d101..6a74c58d2ceb6 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -12,15 +12,15 @@ codec = { version = "2.2.0", package = "parity-scale-codec", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../api", default-features = false } -sp-application-crypto = { version = "4.0.0-dev", path = "../application-crypto", default-features = false } +sp-application-crypto = { version = "4.0.0", path = "../application-crypto", default-features = false } sp-core = { version = "4.1.0-dev", path = "../core", default-features = false } -sp-runtime = { version = "4.0.0-dev", path = "../runtime", default-features = false } +sp-runtime = { version = "4.0.0", path = "../runtime", default-features = false } sp-std = { version = "4.0.0", path = "../std", default-features = false } [dev-dependencies] hex = "0.4.3" hex-literal = "0.3" -sp-keystore = { version = "0.10.0-dev", path = "../keystore" } +sp-keystore = { version = "0.10.0", path = "../keystore" } [features] default = ["std"] diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index a346f95cc4c4b..083865cd2cccb 100644 --- a/primitives/block-builder/Cargo.toml +++ b/primitives/block-builder/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 02e74a63d9590..6eeacf5f2697c 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -21,7 +21,7 @@ thiserror = "1.0.30" futures = "0.3.9" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-runtime = { version = "4.0.0-dev", path = "../runtime" } -sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } +sp-runtime = { version = "4.0.0", path = "../runtime" } +sp-state-machine = { version = "0.10.0", path = "../state-machine" } sp-database = { version = "4.0.0-dev", path = "../database" } sp-api = { version = "4.0.0-dev", path = "../api" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index e3c883a6e7834..747a9f546cb03 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -13,12 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../timestamp" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 997744dd52bb0..fcfda410765e9 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } merlin = { version = "2.0", default-features = false } @@ -24,8 +24,8 @@ sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = sp-consensus-vrf = { version = "0.10.0-dev", path = "../vrf", default-features = false } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } -sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../../keystore", optional = true } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } +sp-keystore = { version = "0.10.0", default-features = false, path = "../../keystore", optional = true } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../timestamp", optional = true } serde = { version = "1.0.126", features = ["derive"], optional = true } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 2ad4a08959355..e638c04a08dce 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -22,11 +22,11 @@ futures = { version = "0.3.1", features = ["thread-pool"] } log = "0.4.8" sp-core = { path = "../../core", version = "4.1.0-dev" } sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } -sp-state-machine = { version = "0.10.0-dev", path = "../../state-machine" } +sp-state-machine = { version = "0.10.0", path = "../../state-machine" } futures-timer = "3.0.1" sp-std = { version = "4.0.0", path = "../../std" } sp-version = { version = "4.0.0-dev", path = "../../version" } -sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } +sp-runtime = { version = "4.0.0", path = "../../runtime" } thiserror = "1.0.30" [dev-dependencies] diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index d7f2b18e3fdbe..6e00453da1bd4 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index 9177157bd5ed7..23f73454aad94 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0", features = ["derive"], optional = true } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } -sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../arithmetic" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } +sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../arithmetic" } [features] default = ["std"] diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 4eb545b08a21c..586b6354f55ac 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -17,7 +17,7 @@ codec = { version = "2.0.0", package = "parity-scale-codec", default-features = schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } sp-std = { version = "4.0.0", path = "../../std", default-features = false } sp-core = { version = "4.1.0-dev", path = "../../core", default-features = false } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } [features] default = ["std"] diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index fed861553bf0d..8bcdf1462fc81 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -21,10 +21,10 @@ grandpa = { package = "finality-grandpa", version = "0.14.1", default-features = log = { version = "0.4.8", optional = true } serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../keystore", optional = true } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-keystore = { version = "0.10.0", default-features = false, path = "../keystore", optional = true } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 82c4f21b5c07f..1ef0f2012056f 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-runtime = { version = "4.0.0-dev", path = "../runtime", optional = true } +sp-runtime = { version = "4.0.0", path = "../runtime", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } impl-trait-for-tuples = "0.2.0" diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 4364202618008..9f95eb40a4e72 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-io" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -18,13 +18,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } hash-db = { version = "0.15.2", default-features = false } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-keystore = { version = "0.10.0-dev", default-features = false, optional = true, path = "../keystore" } +sp-keystore = { version = "0.10.0", default-features = false, optional = true, path = "../keystore" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } libsecp256k1 = { version = "0.7", optional = true } -sp-state-machine = { version = "0.10.0-dev", optional = true, path = "../state-machine" } +sp-state-machine = { version = "0.10.0", optional = true, path = "../state-machine" } sp-wasm-interface = { version = "4.1.0-dev", path = "../wasm-interface", default-features = false } sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../runtime-interface" } -sp-trie = { version = "4.0.0-dev", optional = true, path = "../trie" } +sp-trie = { version = "4.0.0", optional = true, path = "../trie" } sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.8", optional = true } diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index be7d138979a1c..a8529716b712a 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -16,6 +16,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "4.1.0-dev", path = "../core" } -sp-runtime = { version = "4.0.0-dev", path = "../runtime" } +sp-runtime = { version = "4.0.0", path = "../runtime" } lazy_static = "1.4.0" strum = { version = "0.22.0", features = ["derive"] } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 7994c67b4c51c..dea78c61242c2 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-keystore" -version = "0.10.0-dev" +version = "0.10.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index a418cda2feef1..3a5b00dcdf779 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -18,9 +18,9 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] serde = { version = "1.0.126", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } -sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../arithmetic" } +sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-runtime = { version = "4.0.0-dev", path = "../runtime", default-features = false } +sp-runtime = { version = "4.0.0", path = "../runtime", default-features = false } [dev-dependencies] substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 59d12c5a5d2ee..62bb1090d047f 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -19,7 +19,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] honggfuzz = "0.5" rand = { version = "0.7.3", features = ["std", "small_rng"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } -sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } +sp-runtime = { version = "4.0.0", path = "../../runtime" } structopt = "0.3.25" [[bin]] diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index 5bffcff1038d1..160778857f393 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -23,7 +23,7 @@ proc-macro-crate = "1.1.0" [dev-dependencies] parity-scale-codec = "2.3.1" scale-info = "1.0" -sp-arithmetic = { path = "../../arithmetic", version = "4.0.0-dev" } +sp-arithmetic = { path = "../../arithmetic", version = "4.0.0" } # used by generate_solution_type: sp-npos-elections = { path = "..", version = "4.0.0-dev" } trybuild = "1.0.53" diff --git a/primitives/offchain/Cargo.toml b/primitives/offchain/Cargo.toml index 55de9177e45df..50a6d8344f0d8 100644 --- a/primitives/offchain/Cargo.toml +++ b/primitives/offchain/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } [features] default = ["std"] diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml index b7f3b6b5cb4da..8c3578442a793 100644 --- a/primitives/panic-handler/Cargo.toml +++ b/primitives/panic-handler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-panic-handler" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 69a6792ead29d..fb978fbbbac1d 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -27,7 +27,7 @@ impl-trait-for-tuples = "0.2.1" [dev-dependencies] sp-runtime-interface-test-wasm = { version = "2.0.0", path = "test-wasm" } -sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } +sp-state-machine = { version = "0.10.0", path = "../state-machine" } sp-core = { version = "4.1.0-dev", path = "../core" } sp-io = { version = "4.0.0-dev", path = "../io" } rustversion = "1.0.5" diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index b197f2ab8ba94..06fcf920a6911 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -17,8 +17,8 @@ sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-executor-common = { version = "0.10.0-dev", path = "../../../client/executor/common" } sp-runtime-interface-test-wasm = { version = "2.0.0", path = "../test-wasm" } sp-runtime-interface-test-wasm-deprecated = { version = "2.0.0", path = "../test-wasm-deprecated" } -sp-state-machine = { version = "0.10.0-dev", path = "../../state-machine" } -sp-runtime = { version = "4.0.0-dev", path = "../../runtime" } -sp-io = { version = "4.0.0-dev", path = "../../io" } +sp-state-machine = { version = "0.10.0", path = "../../state-machine" } +sp-runtime = { version = "4.0.0", path = "../../runtime" } +sp-io = { version = "4.0.0", path = "../../io" } tracing = "0.1.29" tracing-core = "0.1.17" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 1d7c79ba68c98..6363a0a286310 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -19,10 +19,10 @@ serde = { version = "1.0.126", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } -sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../arithmetic" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } +sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } +sp-io = { version = "4.0.0", default-features = false, path = "../io" } log = { version = "0.4.14", default-features = false } paste = "1.0" rand = { version = "0.7.2", optional = true } @@ -34,7 +34,7 @@ either = { version = "1.5", default-features = false } [dev-dependencies] serde_json = "1.0.71" rand = "0.7.2" -sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" } +sp-state-machine = { version = "0.10.0", path = "../state-machine" } sp-api = { version = "4.0.0-dev", path = "../api" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index 26a81caea89b0..59941c9648ddd 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -22,7 +22,7 @@ wasmi = "0.9.0" wasmi = { version = "0.9.0", optional = true } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } +sp-io = { version = "4.0.0", default-features = false, path = "../io" } sp-wasm-interface = { version = "4.1.0-dev", default-features = false, path = "../wasm-interface" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } log = { version = "0.4", default-features = false } diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index d402f36859ac4..cca35710172b5 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -19,7 +19,7 @@ sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" } -sp-runtime = { version = "4.0.0-dev", optional = true, path = "../runtime" } +sp-runtime = { version = "4.0.0", optional = true, path = "../runtime" } [features] default = [ "std" ] diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 531e696b69307..533e177391b08 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index b6b3c90f5a7f5..7ca76ed58313d 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-state-machine" -version = "0.10.0-dev" +version = "0.10.0" authors = ["Parity Technologies "] description = "Substrate State Machine" edition = "2021" @@ -20,9 +20,9 @@ parking_lot = { version = "0.11.1", optional = true } hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.22.6", default-features = false } trie-root = { version = "0.16.0", default-features = false } -sp-trie = { version = "4.0.0-dev", path = "../trie", default-features = false } +sp-trie = { version = "4.0.0", path = "../trie", default-features = false } sp-core = { version = "4.1.0-dev", path = "../core", default-features = false } -sp-panic-handler = { version = "4.0.0-dev", path = "../panic-handler", optional = true } +sp-panic-handler = { version = "4.0.0", path = "../panic-handler", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } num-traits = { version = "0.2.8", default-features = false } rand = { version = "0.7.2", optional = true } @@ -33,7 +33,7 @@ tracing = { version = "0.1.29", optional = true } [dev-dependencies] hex-literal = "0.3.4" -sp-runtime = { version = "4.0.0-dev", path = "../runtime" } +sp-runtime = { version = "4.0.0", path = "../runtime" } pretty_assertions = "1.0.0" rand = "0.7.2" diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index c57eb50eddb56..6ac6c6aa98bec 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] log = { version = "0.4.8", optional = true } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" } +sp-io = { version = "4.0.0", default-features = false, path = "../io" } sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../runtime-interface" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 18a0b9501e187..5d0a3d440c46a 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -12,11 +12,11 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } serde = { version = "1.0.126", optional = true, features = ["derive"] } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } [features] diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 0096fe4c809d2..4c5fdefe990a1 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/transaction-pool/Cargo.toml b/primitives/transaction-pool/Cargo.toml index e4a407547971a..2590208078db6 100644 --- a/primitives/transaction-pool/Cargo.toml +++ b/primitives/transaction-pool/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } [features] default = [ "std" ] diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index f2ea55cc18c51..d731808c64c2b 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -14,9 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-trie = { version = "4.0.0-dev", optional = true, path = "../trie" } +sp-trie = { version = "4.0.0", optional = true, path = "../trie" } sp-core = { version = "4.1.0-dev", path = "../core", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 983d58c9bb8d2..02aaa75aa939e 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-trie" -version = "4.0.0-dev" +version = "4.0.0" authors = ["Parity Technologies "] description = "Patricia trie stuff using a parity-scale-codec node format" repository = "https://github.com/paritytech/substrate/" @@ -32,7 +32,7 @@ trie-bench = "0.28.0" trie-standardmap = "0.15.2" criterion = "0.3.3" hex-literal = "0.3.4" -sp-runtime = { version = "4.0.0-dev", path = "../runtime" } +sp-runtime = { version = "4.0.0", path = "../runtime" } [features] default = ["std"] diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index a58b27c7c1517..b8a3a5bc3e305 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -19,7 +19,7 @@ serde = { version = "1.0.126", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" } parity-wasm = { version = "0.42.2", optional = true } thiserror = { version = "1.0.30", optional = true } diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 9b77cde505af7..5d148ccd125eb 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -30,8 +30,8 @@ sc-service = { version = "0.10.0-dev", default-features = false, features = [ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0-dev", path = "../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } -sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" } -sp-state-machine = { version = "0.10.0-dev", path = "../../primitives/state-machine" } +sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } async-trait = "0.1.50" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index ae4be0d13af7e..72e2c255c15cc 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } @@ -26,23 +26,23 @@ sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../p sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime-interface" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../frame/support" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../frame/babe" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../frame/system" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../frame/system/rpc/runtime-api" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../frame/timestamp" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } -sp-trie = { version = "4.0.0-dev", default-features = false, path = "../../primitives/trie" } +sp-trie = { version = "4.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } trie-db = { version = "0.22.6", default-features = false } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } -sp-state-machine = { version = "0.10.0-dev", default-features = false, path = "../../primitives/state-machine" } +sp-state-machine = { version = "0.10.0", default-features = false, path = "../../primitives/state-machine" } sp-externalities = { version = "0.10.0", default-features = false, path = "../../primitives/externalities" } # 3rd party diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index b66fdc3422ae5..7babbfb2ed8ee 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -18,7 +18,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-build substrate-test-client = { version = "2.0.0", path = "../../client" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } substrate-test-runtime = { version = "2.0.0", path = "../../runtime" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index ee1ac4814db5f..c1794d288eca1 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -16,7 +16,7 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../client" } parking_lot = "0.11.1" codec = { package = "parity-scale-codec", version = "2.0.0" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool", features = ["test-helpers"] } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } futures = "0.3.16" diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index c8d762ec73cd9..d61cf71aec381 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -21,9 +21,9 @@ sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } -sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" } +sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } codec = { version = "2.0.0", package = "parity-scale-codec" } structopt = "0.3.25" chrono = "0.4" diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index feb02f1eb7213..db9e4a7d90744 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" [dependencies] sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } structopt = "0.3.25" frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 2c9374fc5cca4..6a512842129e7 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -17,7 +17,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-staking = { version = "4.0.0-dev", path = "../../../frame/staking" } # primitives -sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } +sp-io = { version = "4.0.0", path = "../../../primitives/io" } # third party chrono = { version = "0.4.19" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 0cf4980a104c8..edd538baf562c 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -24,7 +24,7 @@ serde = "1.0.126" sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } [dev-dependencies] diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index f71f3d6e93e14..53ad36a969306 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -20,7 +20,7 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" log = "0.4.8" -sp-runtime = { version = "4.0.0-dev", path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.0.0", path = "../../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index d6b75d31fac8e..a0eca3cc9e9c9 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -22,11 +22,11 @@ sc-service = { version = "0.10.0-dev", default-features = false, path = "../../. sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } -sp-state-machine = { version = "0.10.0-dev", path = "../../../../primitives/state-machine" } -sp-runtime = { version = "4.0.0-dev", path = "../../../../primitives/runtime" } +sp-state-machine = { version = "0.10.0", path = "../../../../primitives/state-machine" } +sp-runtime = { version = "4.0.0", path = "../../../../primitives/runtime" } sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../../primitives/io" } -sp-keystore = { version = "0.10.0-dev", path = "../../../../primitives/keystore" } +sp-keystore = { version = "0.10.0", path = "../../../../primitives/keystore" } sp-externalities = { version = "0.10.0", path = "../../../../primitives/externalities" } sp-version = { version = "4.0.0-dev", path = "../../../../primitives/version" } From 76f6078825dc1641ef134d71ab7443b552d71273 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Dec 2021 13:45:30 +0100 Subject: [PATCH 0344/1472] Bump parking_lot from 0.11.1 to 0.11.2 (#10335) Bumps [parking_lot](https://github.com/Amanieu/parking_lot) from 0.11.1 to 0.11.2. - [Release notes](https://github.com/Amanieu/parking_lot/releases) - [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md) - [Commits](https://github.com/Amanieu/parking_lot/compare/0.11.1...0.11.2) --- updated-dependencies: - dependency-name: parking_lot 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 | 124 +++++++++--------- client/api/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- client/state-db/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/database/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- .../runtime/transaction-pool/Cargo.toml | 2 +- 30 files changed, 91 insertions(+), 91 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0364fafd2547f..4ff6fc1974fa0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -480,7 +480,7 @@ dependencies = [ "futures 0.3.16", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-client-api", "sc-keystore", "sc-network", @@ -1871,7 +1871,7 @@ dependencies = [ "log 0.4.14", "num-traits", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.8.4", "scale-info", ] @@ -3097,7 +3097,7 @@ dependencies = [ "jsonrpc-server-utils", "log 0.4.14", "net2", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "unicase 2.6.0", ] @@ -3112,7 +3112,7 @@ dependencies = [ "jsonrpc-server-utils", "log 0.4.14", "parity-tokio-ipc", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "tower-service", ] @@ -3126,7 +3126,7 @@ dependencies = [ "jsonrpc-core", "lazy_static", "log 0.4.14", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "serde", ] @@ -3160,7 +3160,7 @@ dependencies = [ "jsonrpc-server-utils", "log 0.4.14", "parity-ws", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "slab", ] @@ -3297,7 +3297,7 @@ checksum = "c3b6b85fc643f5acd0bffb2cc8a6d150209379267af0d41db72170021841f9f5" dependencies = [ "kvdb", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", ] [[package]] @@ -3312,7 +3312,7 @@ dependencies = [ "num_cpus", "owning_ref", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "regex", "rocksdb", "smallvec 1.7.0", @@ -3431,7 +3431,7 @@ dependencies = [ "libp2p-websocket", "libp2p-yamux", "multiaddr", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project 1.0.8", "smallvec 1.7.0", "wasm-timer", @@ -3456,7 +3456,7 @@ dependencies = [ "multiaddr", "multihash 0.14.0", "multistream-select", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project 1.0.8", "prost", "prost-build", @@ -3630,7 +3630,7 @@ dependencies = [ "libp2p-core", "log 0.4.14", "nohash-hasher", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "smallvec 1.7.0", "unsigned-varint 0.7.0", @@ -3863,7 +3863,7 @@ checksum = "4e7362abb8867d7187e7e93df17f460d554c997fc5c8ac57dc1259057f6889af" dependencies = [ "futures 0.3.16", "libp2p-core", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "thiserror", "yamux", ] @@ -4000,9 +4000,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -5540,7 +5540,7 @@ dependencies = [ "log 0.4.14", "pallet-balances", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "scale-info", "sp-arithmetic", @@ -6315,7 +6315,7 @@ dependencies = [ "log 0.4.14", "lz4", "memmap2 0.2.1", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.8.4", "snap", ] @@ -6376,7 +6376,7 @@ dependencies = [ "hashbrown 0.11.2", "impl-trait-for-tuples", "parity-util-mem-derive", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "primitive-types", "smallvec 1.7.0", "winapi 0.3.9", @@ -6445,13 +6445,13 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", - "lock_api 0.4.2", - "parking_lot_core 0.8.3", + "lock_api 0.4.5", + "parking_lot_core 0.8.5", ] [[package]] @@ -6471,14 +6471,14 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall 0.2.5", + "redox_syscall 0.2.10", "smallvec 1.7.0", "winapi 0.3.9", ] @@ -6863,7 +6863,7 @@ dependencies = [ "fnv", "lazy_static", "memchr", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "thiserror", ] @@ -7259,9 +7259,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" -version = "0.2.5" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -7273,7 +7273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom 0.2.3", - "redox_syscall 0.2.5", + "redox_syscall 0.2.10", ] [[package]] @@ -7626,7 +7626,7 @@ dependencies = [ "futures-timer 3.0.2", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -7732,7 +7732,7 @@ dependencies = [ "hash-db", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-executor", "sc-transaction-pool-api", "sc-utils", @@ -7765,7 +7765,7 @@ dependencies = [ "log 0.4.14", "parity-db", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "quickcheck", "sc-client-api", "sc-state-db", @@ -7790,7 +7790,7 @@ dependencies = [ "futures-timer 3.0.2", "libp2p", "log 0.4.14", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-client-api", "sc-utils", "serde", @@ -7815,7 +7815,7 @@ dependencies = [ "getrandom 0.2.3", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -7857,7 +7857,7 @@ dependencies = [ "num-rational 0.2.4", "num-traits", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "rand_chacha 0.2.2", "retain_mut", @@ -7981,7 +7981,7 @@ dependencies = [ "futures-timer 3.0.2", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-client-api", "sc-consensus", "sp-api", @@ -8041,7 +8041,7 @@ dependencies = [ "log 0.4.14", "lru 0.6.6", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "paste 1.0.6", "regex", "sc-executor-common", @@ -8138,7 +8138,7 @@ dependencies = [ "futures-timer 3.0.2", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.8.4", "sc-block-builder", "sc-client-api", @@ -8217,7 +8217,7 @@ dependencies = [ "async-trait", "derive_more", "hex", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "serde_json", "sp-application-crypto", "sp-core", @@ -8250,7 +8250,7 @@ dependencies = [ "log 0.4.14", "lru 0.7.0", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project 1.0.8", "prost", "prost-build", @@ -8310,7 +8310,7 @@ dependencies = [ "futures-timer 3.0.2", "libp2p", "log 0.4.14", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8342,7 +8342,7 @@ dependencies = [ "num_cpus", "once_cell", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8396,7 +8396,7 @@ dependencies = [ "lazy_static", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -8432,7 +8432,7 @@ dependencies = [ "jsonrpc-pubsub", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-chain-spec", "sc-transaction-pool-api", "serde", @@ -8491,7 +8491,7 @@ dependencies = [ "log 0.4.14", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project 1.0.8", "rand 0.7.3", "sc-block-builder", @@ -8551,7 +8551,7 @@ dependencies = [ "hex-literal", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -8585,7 +8585,7 @@ dependencies = [ "parity-scale-codec", "parity-util-mem", "parity-util-mem-derive", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-client-api", "sp-core", ] @@ -8619,7 +8619,7 @@ dependencies = [ "futures 0.3.16", "libp2p", "log 0.4.14", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project 1.0.8", "rand 0.7.3", "serde", @@ -8640,7 +8640,7 @@ dependencies = [ "libc", "log 0.4.14", "once_cell", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "regex", "rustc-hash", "sc-client-api", @@ -8682,7 +8682,7 @@ dependencies = [ "log 0.4.14", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "retain_mut", "sc-block-builder", "sc-client-api", @@ -9294,7 +9294,7 @@ dependencies = [ "log 0.4.14", "lru 0.7.0", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sp-api", "sp-consensus", "sp-database", @@ -9418,7 +9418,7 @@ dependencies = [ "num-traits", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "primitive-types", "rand 0.7.3", "regex", @@ -9473,7 +9473,7 @@ name = "sp-database" version = "4.0.0-dev" dependencies = [ "kvdb", - "parking_lot 0.11.1", + "parking_lot 0.11.2", ] [[package]] @@ -9535,7 +9535,7 @@ dependencies = [ "libsecp256k1", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sp-core", "sp-externalities", "sp-keystore", @@ -9568,7 +9568,7 @@ dependencies = [ "futures 0.3.16", "merlin", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "rand_chacha 0.2.2", "schnorrkel", @@ -9809,7 +9809,7 @@ dependencies = [ "log 0.4.14", "num-traits", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pretty_assertions", "rand 0.7.3", "smallvec 1.7.0", @@ -10263,7 +10263,7 @@ dependencies = [ "derive_more", "futures 0.3.16", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-transaction-pool", "sc-transaction-pool-api", "sp-blockchain", @@ -10371,7 +10371,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "rand 0.8.4", - "redox_syscall 0.2.5", + "redox_syscall 0.2.10", "remove_dir_all", "winapi 0.3.9", ] @@ -10576,7 +10576,7 @@ dependencies = [ "mio 0.7.13", "num_cpus", "once_cell", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project-lite 0.2.6", "signal-hook-registry", "tokio-macros", @@ -10815,7 +10815,7 @@ dependencies = [ "chrono", "lazy_static", "matchers", - "parking_lot 0.11.1", + "parking_lot 0.9.0", "regex", "serde", "serde_json", @@ -10924,7 +10924,7 @@ dependencies = [ "lazy_static", "log 0.4.14", "lru-cache", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "resolv-conf", "smallvec 1.7.0", "thiserror", @@ -11324,7 +11324,7 @@ checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" dependencies = [ "futures 0.3.16", "js-sys", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-utils", "wasm-bindgen", "wasm-bindgen-futures", @@ -11920,7 +11920,7 @@ dependencies = [ "futures 0.3.16", "log 0.4.14", "nohash-hasher", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.8.4", "static_assertions", ] diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index 4738a7d611b15..f1d3969ec27a0 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -25,7 +25,7 @@ futures = "0.3.1" hash-db = { version = "0.15.2", default-features = false } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } log = "0.4.8" -parking_lot = "0.11.1" +parking_lot = "0.11.2" sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-keystore = { version = "0.10.0", default-features = false, path = "../../primitives/keystore" } diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 4b4627cb6eeac..26a2defbbb4d1 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -33,4 +33,4 @@ sc-proposer-metrics = { version = "0.10.0-dev", path = "../proposer-metrics" } [dev-dependencies] sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -parking_lot = "0.11.1" +parking_lot = "0.11.2" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 05f0d3804e7b9..e9c897de5dcb1 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -48,4 +48,4 @@ sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } tempfile = "3.1.0" -parking_lot = "0.11.1" +parking_lot = "0.11.2" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 634c987444a07..c96d648846c5e 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -44,7 +44,7 @@ sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } futures = "0.3.9" -parking_lot = "0.11.1" +parking_lot = "0.11.2" log = "0.4.8" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } rand = "0.7.2" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 9d2323b75760a..0ca0c5675839b 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -26,7 +26,7 @@ sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machi sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -parking_lot = "0.11.1" +parking_lot = "0.11.2" serde = { version = "1.0", features = ["derive"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } async-trait = "0.1.42" diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 00ee58c212477..19cc5135de039 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -27,7 +27,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo log = "0.4.8" futures = "0.3.16" futures-timer = "3.0.1" -parking_lot = "0.11.1" +parking_lot = "0.11.2" derive_more = "0.99.16" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev"} async-trait = "0.1.50" diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 80ba026de3cf6..5acc7e9df8b8d 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -parking_lot = "0.11.1" +parking_lot = "0.11.2" log = "0.4.8" kvdb = "0.10.0" kvdb-rocksdb = { version = "0.14.0", optional = true } diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index a87a382913706..09f10a9753401 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -30,7 +30,7 @@ sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" sc-executor-common = { version = "0.10.0-dev", path = "common" } sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } -parking_lot = "0.11.1" +parking_lot = "0.11.2" log = "0.4.8" libsecp256k1 = "0.7" sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 2ddd4f765163e..e296c5a4e3da6 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -21,7 +21,7 @@ fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } futures = "0.3.9" futures-timer = "3.0.1" log = "0.4.8" -parking_lot = "0.11.1" +parking_lot = "0.11.2" rand = "0.8.4" parity-scale-codec = { version = "2.3.1", features = ["derive"] } sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index abdd4ac372e74..b4c684a206f30 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -21,7 +21,7 @@ sp-application-crypto = { version = "4.0.0", path = "../../primitives/applicatio sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } hex = "0.4.0" -parking_lot = "0.11.1" +parking_lot = "0.11.2" serde_json = "1.0.71" [dev-dependencies] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 95f84f493bb74..643b2440209f4 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -38,7 +38,7 @@ linked-hash-map = "0.5.4" linked_hash_set = "0.1.3" lru = "0.7.0" log = "0.4.8" -parking_lot = "0.11.1" +parking_lot = "0.11.2" pin-project = "1.0.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } prost = "0.9" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index fd9e9e2f7ef37..e2e46a27b2738 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-std = "1.10.0" sc-network = { version = "0.10.0-dev", path = "../" } log = "0.4.8" -parking_lot = "0.11.1" +parking_lot = "0.11.2" futures = "0.3.9" futures-timer = "3.0.1" rand = "0.7.2" diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 5ed182d6cfc41..4271c7f5d2b2d 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -20,7 +20,7 @@ fnv = "1.0.6" futures = "0.3.16" futures-timer = "3.0.2" num_cpus = "1.10" -parking_lot = "0.11.1" +parking_lot = "0.11.2" rand = "0.7.2" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 18f499c51448a..2e75dd460bd3a 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -20,7 +20,7 @@ jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" jsonrpc-pubsub = "18.0.0" log = "0.4.8" -parking_lot = "0.11.1" +parking_lot = "0.11.2" thiserror = "1.0" sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 707fbf75f7c61..b8829dca870b3 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -35,7 +35,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } hash-db = { version = "0.15.2", default-features = false } -parking_lot = "0.11.1" +parking_lot = "0.11.2" lazy_static = { version = "1.4.0", optional = true } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 6d96cafec2014..e81125fc91545 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -27,7 +27,7 @@ futures = "0.3.16" jsonrpc-pubsub = "18.0" jsonrpc-core = "18.0" rand = "0.7.3" -parking_lot = "0.11.1" +parking_lot = "0.11.2" log = "0.4.11" futures-timer = "3.0.1" exit-future = "0.2.0" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 113ed0d0802be..a8088ebb08cb0 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -18,7 +18,7 @@ tempfile = "3.1.0" tokio = { version = "1.13.0", features = ["time"] } log = "0.4.8" fdlimit = "0.2.1" -parking_lot = "0.11.1" +parking_lot = "0.11.2" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 6a5b8516237d9..fbde840fbb8e9 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -parking_lot = "0.11.1" +parking_lot = "0.11.2" log = "0.4.11" sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 73efdbc039c51..af7b1d0a06698 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -parking_lot = "0.11.1" +parking_lot = "0.11.2" futures = "0.3.9" wasm-timer = "0.2.5" libp2p = { version = "0.40.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 137cab554613c..c4fdcde3f0673 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -20,7 +20,7 @@ lazy_static = "1.4.0" libc = "0.2.105" log = { version = "0.4.8" } once_cell = "1.8.0" -parking_lot = "0.11.1" +parking_lot = "0.11.2" regex = "1.5.4" rustc-hash = "1.1.0" serde = "1.0.126" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 9aaaaa36a2cb8..6439a1854352b 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.16" intervalier = "0.4.0" log = "0.4.8" parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } -parking_lot = "0.11.1" +parking_lot = "0.11.2" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 72ec62f321cff..75a1ed083829b 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -41,7 +41,7 @@ strum = { optional = true, version = "0.22.0" } strum_macros = { optional = true, version = "0.22.0" } [dev-dependencies] -parking_lot = "0.11.0" +parking_lot = "0.11.2" rand = { version = "0.7.3" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 6eeacf5f2697c..57732c360bac7 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.11" lru = "0.7.0" -parking_lot = "0.11.1" +parking_lot = "0.11.2" thiserror = "1.0.30" futures = "0.3.9" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 330dd57e817f6..2922c8b940ea8 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -38,7 +38,7 @@ num-traits = { version = "0.2.8", default-features = false } zeroize = { version = "1.4.2", default-features = false } secrecy = { version = "0.8.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } -parking_lot = { version = "0.11.1", optional = true } +parking_lot = { version = "0.11.2", optional = true } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } sp-storage = { version = "4.0.0", default-features = false, path = "../storage" } diff --git a/primitives/database/Cargo.toml b/primitives/database/Cargo.toml index 94e16f3cfb3d5..6c3eea9aa1f98 100644 --- a/primitives/database/Cargo.toml +++ b/primitives/database/Cargo.toml @@ -11,6 +11,6 @@ documentation = "https://docs.rs/sp-database" readme = "README.md" [dependencies] -parking_lot = "0.11.1" +parking_lot = "0.11.2" kvdb = "0.10.0" diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 9f95eb40a4e72..ee3c9e8945eb2 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -29,7 +29,7 @@ sp-externalities = { version = "0.10.0", optional = true, path = "../externaliti sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.8", optional = true } futures = { version = "0.3.1", features = ["thread-pool"], optional = true } -parking_lot = { version = "0.11.1", optional = true } +parking_lot = { version = "0.11.2", optional = true } tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.17", default-features = false} diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index dea78c61242c2..e918f5d2c6d75 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = futures = { version = "0.3.1" } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } merlin = { version = "2.0", default-features = false } -parking_lot = { version = "0.11.1", default-features = false } +parking_lot = { version = "0.11.2", default-features = false } serde = { version = "1.0", optional = true} sp-core = { version = "4.1.0-dev", path = "../core" } sp-externalities = { version = "0.10.0", path = "../externalities", default-features = false } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 7ca76ed58313d..2c84b9186d0ab 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.11", optional = true } thiserror = { version = "1.0.30", optional = true } -parking_lot = { version = "0.11.1", optional = true } +parking_lot = { version = "0.11.2", optional = true } hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.22.6", default-features = false } trie-root = { version = "0.16.0", default-features = false } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index c1794d288eca1..a0d04bd70271f 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../client" } -parking_lot = "0.11.1" +parking_lot = "0.11.2" codec = { package = "parity-scale-codec", version = "2.0.0" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } From 1306573829700eb5912e342e4372a3735a0b0679 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Thu, 16 Dec 2021 04:28:18 +0900 Subject: [PATCH 0345/1472] Deny warning when building doc (#10387) * deny warning * add new job * fix doc * fmt --- .gitlab-ci.yml | 13 ++++++++++++- primitives/beefy/src/commitment.rs | 6 +++--- utils/frame/remote-externalities/src/lib.rs | 8 ++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3f830c7e8e24d..589adeec5260d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -650,6 +650,18 @@ build-macos-subkey: tags: - osx +check-rustdoc: + stage: test + <<: *docker-env + <<: *test-refs + variables: + <<: *default-vars + SKIP_WASM_BUILD: 1 + RUSTDOCFLAGS: "-Dwarnings" + script: + - time cargo +nightly doc --workspace --all-features --verbose --no-deps + - sccache -s + build-rustdoc: stage: build <<: *docker-env @@ -665,7 +677,6 @@ build-rustdoc: paths: - ./crate-docs/ script: - # FIXME: it fails with `RUSTDOCFLAGS="-Dwarnings"` - time cargo +nightly doc --workspace --all-features --verbose - rm -f ./target/doc/.lock - mv ./target/doc ./crate-docs diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index 6553f6ffc905f..ec1ceeded878c 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -27,9 +27,9 @@ pub type BeefyPayloadId = [u8; 2]; pub mod known_payload_ids { use crate::BeefyPayloadId; - /// A [`Payload`] identifier for Merkle Mountain Range root hash. + /// A [`Payload`](super::Payload) identifier for Merkle Mountain Range root hash. /// - /// Encoded value should contain a [`beefy_primitives::MmrRootHash`] type (i.e. 32-bytes hash). + /// Encoded value should contain a [`crate::MmrRootHash`] type (i.e. 32-bytes hash). pub const MMR_ROOT_ID: BeefyPayloadId = *b"mh"; } @@ -137,7 +137,7 @@ where /// /// Note that SCALE-encoding of the structure is optimized for size efficiency over the wire, /// please take a look at custom [`Encode`] and [`Decode`] implementations and -/// [`CompactSignedCommitment`] struct. +/// `CompactSignedCommitment` struct. #[derive(Clone, Debug, PartialEq, Eq)] pub struct SignedCommitment { /// The commitment signatures are collected for. diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index e8453ddcd8f66..1b61f0711406f 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -738,7 +738,7 @@ impl Builder { self } - /// Just a utility wrapper of [`inject_hashed_prefix`] that injects + /// Just a utility wrapper of [`Self::inject_hashed_prefix`] that injects /// [`DEFAULT_CHILD_STORAGE_KEY_PREFIX`] as a prefix. /// /// If set, this will guarantee that the child-tree data of ALL pallets will be downloaded. @@ -747,9 +747,9 @@ impl Builder { /// /// Otherwise, the only other way to make sure a child-tree is manually included is to inject /// its root (`DEFAULT_CHILD_STORAGE_KEY_PREFIX`, plus some other postfix) into - /// [`inject_hashed_key`]. Unfortunately, there's no federated way of managing child tree roots - /// as of now and each pallet does its own thing. Therefore, it is not possible for this library - /// to automatically include child trees of pallet X, when its top keys are included. + /// [`Self::inject_hashed_key`]. Unfortunately, there's no federated way of managing child tree + /// roots as of now and each pallet does its own thing. Therefore, it is not possible for this + /// library to automatically include child trees of pallet X, when its top keys are included. pub fn inject_default_child_tree_prefix(self) -> Self { self.inject_hashed_prefix(DEFAULT_CHILD_STORAGE_KEY_PREFIX) } From 4db2f22446edc340374a0e16243136b7222b0d0e Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Thu, 16 Dec 2021 04:06:11 +0100 Subject: [PATCH 0346/1472] Replace parameter_types with ConstU32 &c. (#10402) * remove parameter types and use const type * remove parameter types and use const type * Delete { * Delete count, * refractor for beefy, benchmarking, child bounties, and collective pallets * refractor for pallet contracts * refractor for elections * refractor for more pallets * fix CI issues * fix CI issues * fix CI issues * fix CI issues * remove warning to fix CI issue * remove warning to fix CI issue refractor for pallet preimage * remove warning to fix CI issue refractor for pallet proxy * remove warning to fix CI issue refractor for pallet recovery refractor for pallet randomness-collective-flip * remove warning to fix CI issue refractor for pallet scored-pool refractor for pallet scheduler refractor for pallet session * remove warning to fix CI issue refractor for pallet society, support, system, timestamp, tips * remove warning to fix CI issue refractor for pallet transaction_payment, transaction_storage, treasury, uniques, utility * remove warning to fix CI issue * cargo +nightly fmt * CI fix * more param refractor on beefy-mmr * refractor for beefy * Update frame/babe/src/mock.rs * Update frame/babe/src/mock.rs * Update frame/bounties/src/tests.rs * Update frame/tips/src/tests.rs * Delete mock.rs * Update frame/examples/basic/src/tests.rs * Apply suggestions from code review * Update frame/im-online/src/mock.rs * Update frame/im-online/src/mock.rs * Update frame/offences/benchmarking/src/mock.rs * Update frame/session/benchmarking/src/mock.rs * Update frame/support/test/tests/pallet_compatibility.rs * Update frame/support/test/tests/pallet_compatibility_instance.rs * Update frame/treasury/src/tests.rs * Update test-utils/runtime/src/lib.rs * some cleanup * fmt * remove unused Co-authored-by: Damilare Co-authored-by: Guillaume Thiolliere --- .../pallets/template/src/mock.rs | 11 ++-- bin/node-template/runtime/src/lib.rs | 22 +++----- bin/node/runtime/src/lib.rs | 38 +++++--------- frame/atomic-swap/src/tests.rs | 21 ++++---- frame/aura/src/mock.rs | 14 ++--- frame/authority-discovery/src/lib.rs | 14 ++--- frame/authorship/src/lib.rs | 17 +++--- frame/babe/src/mock.rs | 35 +++---------- frame/balances/src/tests_composite.rs | 19 +++---- frame/balances/src/tests_local.rs | 23 +++----- frame/balances/src/tests_reentrancy.rs | 27 +++++----- frame/beefy-mmr/src/mock.rs | 24 +++------ frame/beefy/src/mock.rs | 21 +++----- frame/benchmarking/src/tests.rs | 8 ++- frame/benchmarking/src/tests_instance.rs | 11 ++-- frame/bounties/src/tests.rs | 46 +++++++--------- frame/child-bounties/src/tests.rs | 52 ++++++++----------- frame/collective/src/tests.rs | 19 ++++--- frame/contracts/src/tests.rs | 16 +++--- frame/democracy/src/tests.rs | 45 ++++++---------- .../election-provider-multi-phase/src/mock.rs | 8 ++- frame/elections-phragmen/src/lib.rs | 17 +++--- frame/examples/basic/src/tests.rs | 16 ++---- frame/examples/offchain-worker/src/tests.rs | 16 +++--- frame/examples/parallel/src/tests.rs | 9 +--- frame/executive/src/lib.rs | 13 ++--- frame/gilt/src/mock.rs | 38 ++++---------- frame/grandpa/src/mock.rs | 35 ++++--------- frame/identity/src/tests.rs | 29 +++++------ frame/im-online/src/mock.rs | 26 ++++------ frame/indices/src/mock.rs | 22 +++----- frame/lottery/src/mock.rs | 21 +++----- frame/membership/src/lib.rs | 11 ++-- frame/merkle-mountain-range/src/mock.rs | 9 ++-- frame/multisig/src/tests.rs | 28 +++++----- frame/nicks/src/lib.rs | 28 +++++----- frame/node-authorization/src/mock.rs | 21 ++++---- frame/offences/benchmarking/src/mock.rs | 23 ++++---- frame/offences/src/mock.rs | 6 +-- frame/preimage/src/mock.rs | 27 ++++------ frame/proxy/src/tests.rs | 37 ++++++------- frame/randomness-collective-flip/src/lib.rs | 7 ++- frame/recovery/src/mock.rs | 10 ++-- frame/scheduler/src/mock.rs | 15 +++--- frame/scored-pool/src/mock.rs | 16 +++--- frame/session/benchmarking/src/mock.rs | 16 +++--- frame/session/src/mock.rs | 14 ++--- frame/session/src/tests.rs | 12 ++--- frame/society/src/mock.rs | 37 ++++++------- frame/staking/src/benchmarking.rs | 4 +- frame/staking/src/mock.rs | 25 ++++----- frame/sudo/src/mock.rs | 7 ++- .../support/src/storage/bounded_btree_map.rs | 30 +++++------ .../support/src/storage/bounded_btree_set.rs | 30 +++++------ frame/support/src/storage/bounded_vec.rs | 36 ++++++------- frame/support/src/storage/mod.rs | 26 ++++------ frame/support/src/storage/weak_bounded_vec.rs | 36 ++++++------- frame/support/test/compile_pass/src/lib.rs | 10 ++-- frame/support/test/tests/instance.rs | 11 ++-- frame/support/test/tests/pallet.rs | 15 +++--- .../test/tests/pallet_compatibility.rs | 15 +++--- .../tests/pallet_compatibility_instance.rs | 23 ++++---- frame/support/test/tests/pallet_instance.rs | 15 ++---- .../tests/pallet_with_name_trait_is_valid.rs | 8 +-- frame/system/benches/bench.rs | 6 +-- frame/system/src/mock.rs | 10 ++-- frame/timestamp/src/lib.rs | 16 +++--- frame/tips/src/tests.rs | 42 ++++++--------- .../asset-tx-payment/src/tests.rs | 36 +++++-------- frame/transaction-payment/src/lib.rs | 13 ++--- frame/transaction-storage/src/mock.rs | 22 ++------ frame/treasury/src/tests.rs | 21 ++++---- frame/uniques/src/mock.rs | 48 ++++++----------- frame/utility/src/tests.rs | 13 ++--- frame/vesting/src/mock.rs | 14 ++--- test-utils/runtime/src/lib.rs | 13 ++--- 76 files changed, 629 insertions(+), 966 deletions(-) diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index 733ac79d6577c..8721fe6c78851 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -1,5 +1,5 @@ use crate as pallet_template; -use frame_support::parameter_types; +use frame_support::traits::{ConstU16, ConstU64}; use frame_system as system; use sp_core::H256; use sp_runtime::{ @@ -22,11 +22,6 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; -} - impl system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -42,14 +37,14 @@ impl system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); - type SS58Prefix = SS58Prefix; + type SS58Prefix = ConstU16<42>; type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 335b36fe2f5c4..5c277a1bb7942 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -26,7 +26,7 @@ use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. pub use frame_support::{ construct_runtime, parameter_types, - traits::{ConstU32, KeyOwnerProofSystem, Randomness, StorageInfo}, + traits::{ConstU128, ConstU32, ConstU8, KeyOwnerProofSystem, Randomness, StorageInfo}, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, IdentityFee, Weight, @@ -196,14 +196,10 @@ impl frame_system::Config for Runtime { impl pallet_randomness_collective_flip::Config for Runtime {} -parameter_types! { - pub const MaxAuthorities: u32 = 32; -} - impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; type DisabledValidators = (); - type MaxAuthorities = MaxAuthorities; + type MaxAuthorities = ConstU32<32>; } impl pallet_grandpa::Config for Runtime { @@ -223,7 +219,7 @@ impl pallet_grandpa::Config for Runtime { type HandleEquivocation = (); type WeightInfo = (); - type MaxAuthorities = MaxAuthorities; + type MaxAuthorities = ConstU32<32>; } parameter_types! { @@ -238,13 +234,8 @@ impl pallet_timestamp::Config for Runtime { type WeightInfo = (); } -parameter_types! { - pub const ExistentialDeposit: u128 = 500; - pub const MaxLocks: u32 = 50; -} - impl pallet_balances::Config for Runtime { - type MaxLocks = MaxLocks; + type MaxLocks = ConstU32<50>; type MaxReserves = (); type ReserveIdentifier = [u8; 8]; /// The type for recording an account's balance. @@ -252,20 +243,19 @@ impl pallet_balances::Config for Runtime { /// The ubiquitous event type. type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU128<500>; type AccountStore = System; type WeightInfo = pallet_balances::weights::SubstrateWeight; } parameter_types! { pub const TransactionByteFee: Balance = 1; - pub OperationalFeeMultiplier: u8 = 5; } impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; type TransactionByteFee = TransactionByteFee; - type OperationalFeeMultiplier = OperationalFeeMultiplier; + type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index e61a46abeb724..97de54fc21e8c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -26,8 +26,8 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU128, ConstU32, Currency, EnsureOneOf, EqualPrivilegeOnly, Everything, Imbalance, - InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, + ConstU128, ConstU16, ConstU32, Currency, EnsureOneOf, EqualPrivilegeOnly, Everything, + Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, }, weights::{ @@ -191,7 +191,6 @@ parameter_types! { }) .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) .build_or_panic(); - pub const SS58Prefix: u16 = 42; } const_assert!(NORMAL_DISPATCH_RATIO.deconstruct() >= AVERAGE_ON_INITIALIZE_RATIO.deconstruct()); @@ -218,7 +217,7 @@ impl frame_system::Config for Runtime { type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = frame_system::weights::SubstrateWeight; - type SS58Prefix = SS58Prefix; + type SS58Prefix = ConstU16<42>; type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -237,7 +236,6 @@ parameter_types! { pub const DepositBase: Balance = deposit(1, 88); // Additional storage item size of 32 bytes. pub const DepositFactor: Balance = deposit(0, 32); - pub const MaxSignatories: u16 = 100; } impl pallet_multisig::Config for Runtime { @@ -246,7 +244,7 @@ impl pallet_multisig::Config for Runtime { type Currency = Balances; type DepositBase = DepositBase; type DepositFactor = DepositFactor; - type MaxSignatories = MaxSignatories; + type MaxSignatories = ConstU16<100>; type WeightInfo = pallet_multisig::weights::SubstrateWeight; } @@ -255,10 +253,8 @@ parameter_types! { pub const ProxyDepositBase: Balance = deposit(1, 8); // Additional storage item size of 33 bytes. pub const ProxyDepositFactor: Balance = deposit(0, 33); - pub const MaxProxies: u16 = 32; pub const AnnouncementDepositBase: Balance = deposit(1, 8); pub const AnnouncementDepositFactor: Balance = deposit(0, 66); - pub const MaxPending: u16 = 32; } /// The type used to represent the kinds of proxying allowed. @@ -325,9 +321,9 @@ impl pallet_proxy::Config for Runtime { type ProxyType = ProxyType; type ProxyDepositBase = ProxyDepositBase; type ProxyDepositFactor = ProxyDepositFactor; - type MaxProxies = MaxProxies; + type MaxProxies = ConstU32<32>; type WeightInfo = pallet_proxy::weights::SubstrateWeight; - type MaxPending = MaxPending; + type MaxPending = ConstU32<32>; type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; @@ -336,7 +332,6 @@ impl pallet_proxy::Config for Runtime { parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 50; // Retry a scheduled item every 10 blocks (1 minute) until the preimage exists. pub const NoPreimagePostponement: Option = Some(10); } @@ -348,7 +343,7 @@ impl pallet_scheduler::Config for Runtime { type Call = Call; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureRoot; - type MaxScheduledPerBlock = MaxScheduledPerBlock; + type MaxScheduledPerBlock = ConstU32<50>; type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; type PreimageProvider = Preimage; @@ -581,7 +576,6 @@ parameter_types! { pub const UnsignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 4; // signed config - pub const SignedMaxSubmissions: u32 = 10; pub const SignedRewardBase: Balance = 1 * DOLLARS; pub const SignedDepositBase: Balance = 1 * DOLLARS; pub const SignedDepositByte: Balance = 1 * CENTS; @@ -599,11 +593,6 @@ parameter_types! { *RuntimeBlockLength::get() .max .get(DispatchClass::Normal); - - // BagsList allows a practically unbounded count of nominators to participate in NPoS elections. - // To ensure we respect memory limits when using the BagsList this must be set to a number of - // voters we know can fit into a single vec allocation. - pub const VoterSnapshotPerBlock: u32 = 10_000; } sp_npos_elections::generate_solution_type!( @@ -668,7 +657,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type MinerMaxWeight = MinerMaxWeight; type MinerMaxLength = MinerMaxLength; type MinerTxPriority = MultiPhaseUnsignedPriority; - type SignedMaxSubmissions = SignedMaxSubmissions; + type SignedMaxSubmissions = ConstU32<10>; type SignedRewardBase = SignedRewardBase; type SignedDepositBase = SignedDepositBase; type SignedDepositByte = SignedDepositByte; @@ -687,7 +676,10 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; type ForceOrigin = EnsureRootOrHalfCouncil; type BenchmarkingConfig = ElectionProviderBenchmarkConfig; - type VoterSnapshotPerBlock = VoterSnapshotPerBlock; + // BagsList allows a practically unbounded count of nominators to participate in NPoS elections. + // To ensure we respect memory limits when using the BagsList this must be set to a number of + // voters we know can fit into a single vec allocation. + type VoterSnapshotPerBlock = ConstU32<10_000>; } parameter_types! { @@ -705,11 +697,9 @@ parameter_types! { pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; pub const VotingPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; pub const FastTrackVotingPeriod: BlockNumber = 3 * 24 * 60 * MINUTES; - pub const InstantAllowed: bool = true; pub const MinimumDeposit: Balance = 100 * DOLLARS; pub const EnactmentPeriod: BlockNumber = 30 * 24 * 60 * MINUTES; pub const CooloffPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; - pub const MaxVotes: u32 = 100; pub const MaxProposals: u32 = 100; } @@ -738,7 +728,7 @@ impl pallet_democracy::Config for Runtime { pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>; type InstantOrigin = pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>; - type InstantAllowed = InstantAllowed; + type InstantAllowed = frame_support::traits::ConstBool; type FastTrackVotingPeriod = FastTrackVotingPeriod; // To cancel a proposal which has been passed, 2/3 of the council must agree to it. type CancellationOrigin = @@ -759,7 +749,7 @@ impl pallet_democracy::Config for Runtime { type Slash = Treasury; type Scheduler = Scheduler; type PalletsOrigin = OriginCaller; - type MaxVotes = MaxVotes; + type MaxVotes = frame_support::traits::ConstU32<100>; type WeightInfo = pallet_democracy::weights::SubstrateWeight; type MaxProposals = MaxProposals; } diff --git a/frame/atomic-swap/src/tests.rs b/frame/atomic-swap/src/tests.rs index 47e33252e0943..2352e7852d090 100644 --- a/frame/atomic-swap/src/tests.rs +++ b/frame/atomic-swap/src/tests.rs @@ -3,7 +3,10 @@ use super::*; use crate as pallet_atomic_swap; -use frame_support::parameter_types; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, +}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -26,7 +29,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -45,7 +47,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -56,9 +58,7 @@ impl frame_system::Config for Test { type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } -parameter_types! { - pub const ExistentialDeposit: u64 = 1; -} + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -66,18 +66,15 @@ impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } -parameter_types! { - pub const ProofLimit: u32 = 1024; - pub const ExpireDuration: u64 = 100; -} + impl Config for Test { type Event = Event; type SwapAction = BalanceSwapAction; - type ProofLimit = ProofLimit; + type ProofLimit = ConstU32<1024>; } const A: u64 = 1; diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 12748bd212d37..b9df2cfa0e4d7 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -22,7 +22,7 @@ use crate as pallet_aura; use frame_support::{ parameter_types, - traits::{DisabledValidators, GenesisBuild}, + traits::{ConstU32, ConstU64, DisabledValidators, GenesisBuild}, }; use sp_consensus_aura::{ed25519::AuthorityId, AuthorityIndex}; use sp_core::H256; @@ -48,10 +48,8 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); - pub const MinimumPeriod: u64 = 1; } impl frame_system::Config for Test { @@ -69,7 +67,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -84,14 +82,10 @@ impl frame_system::Config for Test { impl pallet_timestamp::Config for Test { type Moment = u64; type OnTimestampSet = Aura; - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<1>; type WeightInfo = (); } -parameter_types! { - pub const MaxAuthorities: u32 = 10; -} - thread_local! { static DISABLED_VALIDATORS: RefCell> = RefCell::new(Default::default()); } @@ -118,7 +112,7 @@ impl DisabledValidators for MockDisabledValidators { impl pallet_aura::Config for Test { type AuthorityId = AuthorityId; type DisabledValidators = MockDisabledValidators; - type MaxAuthorities = MaxAuthorities; + type MaxAuthorities = ConstU32<10>; } pub fn new_test_ext(authorities: Vec) -> sp_io::TestExternalities { diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index c867f98af3e17..5f905e92569f6 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -173,7 +173,10 @@ impl OneSessionHandler for Pallet { mod tests { use super::*; use crate as pallet_authority_discovery; - use frame_support::{parameter_types, traits::GenesisBuild}; + use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64, GenesisBuild}, + }; use sp_application_crypto::Pair; use sp_authority_discovery::AuthorityPair; use sp_core::{crypto::key_types, H256}; @@ -201,11 +204,10 @@ mod tests { parameter_types! { pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); - pub const MaxAuthorities: u32 = 100; } impl Config for Test { - type MaxAuthorities = MaxAuthorities; + type MaxAuthorities = ConstU32<100>; } impl pallet_session::Config for Test { @@ -230,8 +232,6 @@ mod tests { parameter_types! { pub const Period: BlockNumber = 1; pub const Offset: BlockNumber = 0; - pub const UncleGenerations: u64 = 0; - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -251,7 +251,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -260,7 +260,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } pub struct TestSessionHandler; diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 98dd8f1ce6df0..297f74ce8b489 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -405,7 +405,11 @@ impl Pallet { mod tests { use super::*; use crate as pallet_authorship; - use frame_support::{parameter_types, ConsensusEngineId}; + use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, + ConsensusEngineId, + }; use sp_core::H256; use sp_runtime::{ generic::DigestItem, @@ -428,7 +432,6 @@ mod tests { ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -448,7 +451,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -457,16 +460,12 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - - parameter_types! { - pub const UncleGenerations: u64 = 5; + type MaxConsumers = ConstU32<16>; } impl pallet::Config for Test { type FindAuthor = AuthorGiven; - type UncleGenerations = UncleGenerations; + type UncleGenerations = ConstU64<5>; type FilterUncle = SealVerify; type EventHandler = (); } diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index f3325d0c65a08..90051770b80f2 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -22,7 +22,7 @@ use codec::Encode; use frame_election_provider_support::onchain; use frame_support::{ parameter_types, - traits::{GenesisBuild, KeyOwnerProofSystem, OnInitialize}, + traits::{ConstU128, ConstU32, ConstU64, GenesisBuild, KeyOwnerProofSystem, OnInitialize}, }; use frame_system::InitKind; use pallet_session::historical as pallet_session_historical; @@ -67,7 +67,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -88,7 +87,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; type OnNewAccount = (); @@ -130,32 +129,20 @@ impl pallet_session::historical::Config for Test { type FullIdentificationOf = pallet_staking::ExposureOf; } -parameter_types! { - pub const UncleGenerations: u64 = 0; -} - impl pallet_authorship::Config for Test { type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type UncleGenerations = UncleGenerations; + type UncleGenerations = ConstU64<0>; type FilterUncle = (); type EventHandler = (); } -parameter_types! { - pub const MinimumPeriod: u64 = 1; -} - impl pallet_timestamp::Config for Test { type Moment = u64; type OnTimestampSet = Babe; - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<1>; type WeightInfo = (); } -parameter_types! { - pub const ExistentialDeposit: u128 = 1; -} - impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -163,7 +150,7 @@ impl pallet_balances::Config for Test { type Balance = u128; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU128<1>; type AccountStore = System; type WeightInfo = (); } @@ -183,11 +170,7 @@ parameter_types! { pub const SessionsPerEra: SessionIndex = 3; pub const BondingDuration: EraIndex = 3; pub const SlashDeferDuration: EraIndex = 0; - pub const AttestationPeriod: u64 = 100; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerValidator: u32 = 64; - pub const ElectionLookahead: u64 = 0; - pub const StakingUnsignedPriority: u64 = u64::MAX / 2; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(16); } @@ -211,7 +194,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; @@ -229,15 +212,13 @@ impl pallet_offences::Config for Test { parameter_types! { pub const EpochDuration: u64 = 3; - pub const ExpectedBlockTime: u64 = 1; pub const ReportLongevity: u64 = BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get(); - pub const MaxAuthorities: u32 = 10; } impl Config for Test { type EpochDuration = EpochDuration; - type ExpectedBlockTime = ExpectedBlockTime; + type ExpectedBlockTime = ConstU64<1>; type EpochChangeTrigger = crate::ExternalTrigger; type DisabledValidators = Session; @@ -255,7 +236,7 @@ impl Config for Test { super::EquivocationHandler; type WeightInfo = (); - type MaxAuthorities = MaxAuthorities; + type MaxAuthorities = ConstU32<10>; } pub fn go_to_block(n: u64, s: u64) { diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index b1a7f2417df84..15648d7356bec 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -22,6 +22,7 @@ use crate::{self as pallet_balances, decl_tests, Config, Pallet}; use frame_support::{ parameter_types, + traits::{ConstU32, ConstU64, ConstU8}, weights::{DispatchInfo, IdentityFee, Weight}, }; use pallet_transaction_payment::CurrencyAdapter; @@ -44,7 +45,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); pub static ExistentialDeposit: u64 = 0; @@ -64,7 +64,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = super::AccountData; @@ -75,22 +75,15 @@ impl frame_system::Config for Test { type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } -parameter_types! { - pub const TransactionByteFee: u64 = 1; - pub const OperationalFeeMultiplier: u8 = 5; -} + impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; - type TransactionByteFee = TransactionByteFee; - type OperationalFeeMultiplier = OperationalFeeMultiplier; + type TransactionByteFee = ConstU64<1>; + type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } -parameter_types! { - pub const MaxReserves: u32 = 2; -} - impl Config for Test { type Balance = u64; type DustRemoval = (); @@ -98,7 +91,7 @@ impl Config for Test { type ExistentialDeposit = ExistentialDeposit; type AccountStore = frame_system::Pallet; type MaxLocks = (); - type MaxReserves = MaxReserves; + type MaxReserves = ConstU32<2>; type ReserveIdentifier = [u8; 8]; type WeightInfo = (); } diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index ff08e63562011..4ceaff26c4d0d 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -22,7 +22,7 @@ use crate::{self as pallet_balances, decl_tests, Config, Pallet}; use frame_support::{ parameter_types, - traits::StorageMapShim, + traits::{ConstU32, ConstU64, ConstU8, StorageMapShim}, weights::{DispatchInfo, IdentityFee, Weight}, }; use pallet_transaction_payment::CurrencyAdapter; @@ -46,7 +46,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); pub static ExistentialDeposit: u64 = 0; @@ -66,7 +65,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -77,21 +76,15 @@ impl frame_system::Config for Test { type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } -parameter_types! { - pub const TransactionByteFee: u64 = 1; - pub const OperationalFeeMultiplier: u8 = 5; -} + impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; - type TransactionByteFee = TransactionByteFee; - type OperationalFeeMultiplier = OperationalFeeMultiplier; + type TransactionByteFee = ConstU64<1>; + type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } -parameter_types! { - pub const MaxLocks: u32 = 50; - pub const MaxReserves: u32 = 2; -} + impl Config for Test { type Balance = u64; type DustRemoval = (); @@ -99,8 +92,8 @@ impl Config for Test { type ExistentialDeposit = ExistentialDeposit; type AccountStore = StorageMapShim, system::Provider, u64, super::AccountData>; - type MaxLocks = MaxLocks; - type MaxReserves = MaxReserves; + type MaxLocks = ConstU32<50>; + type MaxReserves = ConstU32<2>; type ReserveIdentifier = [u8; 8]; type WeightInfo = (); } diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 01b02943484bf..8067e5974caa8 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -20,7 +20,11 @@ #![cfg(test)] use crate::{self as pallet_balances, Config, Pallet}; -use frame_support::{parameter_types, traits::StorageMapShim, weights::IdentityFee}; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64, ConstU8, StorageMapShim}, + weights::IdentityFee, +}; use pallet_transaction_payment::CurrencyAdapter; use sp_core::H256; use sp_io; @@ -48,7 +52,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); pub static ExistentialDeposit: u64 = 0; @@ -68,7 +71,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -79,14 +82,11 @@ impl frame_system::Config for Test { type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } -parameter_types! { - pub const TransactionByteFee: u64 = 1; - pub const OperationalFeeMultiplier: u8 = 5; -} + impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; - type TransactionByteFee = TransactionByteFee; - type OperationalFeeMultiplier = OperationalFeeMultiplier; + type TransactionByteFee = ConstU64<1>; + type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } @@ -97,10 +97,7 @@ impl OnUnbalanced> for OnDustRemoval { assert_ok!(Balances::resolve_into_existing(&1, amount)); } } -parameter_types! { - pub const MaxLocks: u32 = 50; - pub const MaxReserves: u32 = 2; -} + impl Config for Test { type Balance = u64; type DustRemoval = OnDustRemoval; @@ -108,8 +105,8 @@ impl Config for Test { type ExistentialDeposit = ExistentialDeposit; type AccountStore = StorageMapShim, system::Provider, u64, super::AccountData>; - type MaxLocks = MaxLocks; - type MaxReserves = MaxReserves; + type MaxLocks = ConstU32<50>; + type MaxReserves = ConstU32<2>; type ReserveIdentifier = [u8; 8]; type WeightInfo = (); } diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index f1195dcc9c028..d66385f8807b9 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -19,7 +19,9 @@ use std::vec; use beefy_primitives::mmr::MmrLeafVersion; use frame_support::{ - construct_runtime, parameter_types, sp_io::TestExternalities, traits::GenesisBuild, + construct_runtime, parameter_types, + sp_io::TestExternalities, + traits::{ConstU16, ConstU32, ConstU64, GenesisBuild}, BasicExternalities, }; use sp_core::{Hasher, H256}; @@ -57,11 +59,6 @@ construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; -} - impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -77,29 +74,24 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); - type SS58Prefix = SS58Prefix; + type SS58Prefix = ConstU16<42>; type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub const Period: u64 = 1; - pub const Offset: u64 = 0; + type MaxConsumers = ConstU32<16>; } impl pallet_session::Config for Test { type Event = Event; type ValidatorId = u64; type ValidatorIdOf = ConvertInto; - type ShouldEndSession = pallet_session::PeriodicSessions; - type NextSessionRotation = pallet_session::PeriodicSessions; + type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; + type NextSessionRotation = pallet_session::PeriodicSessions, ConstU64<0>>; type SessionManager = MockSessionManager; type SessionHandler = ::KeyTypeIdProviders; type Keys = MockSessionKeys; diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 3ce582b29d22d..22330b29b670a 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -18,7 +18,9 @@ use std::vec; use frame_support::{ - construct_runtime, parameter_types, sp_io::TestExternalities, traits::GenesisBuild, + construct_runtime, parameter_types, + sp_io::TestExternalities, + traits::{ConstU16, ConstU32, ConstU64, GenesisBuild}, BasicExternalities, }; use sp_core::H256; @@ -55,11 +57,6 @@ construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; -} - impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -75,16 +72,16 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); - type SS58Prefix = SS58Prefix; + type SS58Prefix = ConstU16<42>; type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet_beefy::Config for Test { @@ -92,8 +89,6 @@ impl pallet_beefy::Config for Test { } parameter_types! { - pub const Period: u64 = 1; - pub const Offset: u64 = 0; pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); } @@ -101,8 +96,8 @@ impl pallet_session::Config for Test { type Event = Event; type ValidatorId = u64; type ValidatorIdOf = ConvertInto; - type ShouldEndSession = pallet_session::PeriodicSessions; - type NextSessionRotation = pallet_session::PeriodicSessions; + type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; + type NextSessionRotation = pallet_session::PeriodicSessions, ConstU64<0>>; type SessionManager = MockSessionManager; type SessionHandler = ::KeyTypeIdProviders; type Keys = MockSessionKeys; diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index e27b3e09dbedb..eded93c696bd4 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -20,7 +20,7 @@ #![cfg(test)] use super::*; -use frame_support::parameter_types; +use frame_support::{parameter_types, traits::ConstU32}; use sp_runtime::{ testing::{Header, H256}, traits::{BlakeTwo256, IdentityLookup}, @@ -112,14 +112,12 @@ impl frame_system::Config for Test { } parameter_types! { - pub const LowerBound: u32 = 1; - pub const UpperBound: u32 = 100; pub const MaybeItem: Option = None; } impl pallet_test::Config for Test { - type LowerBound = LowerBound; - type UpperBound = UpperBound; + type LowerBound = ConstU32<1>; + type UpperBound = ConstU32<100>; type MaybeItem = MaybeItem; } diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index 09d11eb6c58d2..2ac01a0528203 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -20,7 +20,7 @@ #![cfg(test)] use super::*; -use frame_support::parameter_types; +use frame_support::traits::ConstU32; use sp_runtime::{ testing::{Header, H256}, traits::{BlakeTwo256, IdentityLookup}, @@ -113,15 +113,10 @@ impl frame_system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; } -parameter_types! { - pub const LowerBound: u32 = 1; - pub const UpperBound: u32 = 100; -} - impl pallet_test::Config for Test { type Event = Event; - type LowerBound = LowerBound; - type UpperBound = UpperBound; + type LowerBound = ConstU32<1>; + type UpperBound = ConstU32<100>; } impl pallet_test::OtherConfig for Test { diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index dc6cecc06f5ed..209136dcda1e2 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -24,8 +24,11 @@ use crate as pallet_bounties; use std::cell::RefCell; use frame_support::{ - assert_noop, assert_ok, pallet_prelude::GenesisBuild, parameter_types, traits::OnInitialize, - weights::Weight, PalletId, + assert_noop, assert_ok, + pallet_prelude::GenesisBuild, + parameter_types, + traits::{ConstU32, ConstU64, OnInitialize}, + PalletId, }; use sp_core::H256; @@ -54,9 +57,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: Weight = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); } @@ -75,7 +75,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -86,9 +86,7 @@ impl frame_system::Config for Test { type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } -parameter_types! { - pub const ExistentialDeposit: u64 = 1; -} + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -96,7 +94,7 @@ impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } @@ -105,13 +103,10 @@ thread_local! { } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); - pub const ProposalBondMinimum: u64 = 1; - pub const SpendPeriod: u64 = 2; pub const Burn: Permill = Permill::from_percent(50); - pub const DataDepositPerByte: u64 = 1; pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - pub const MaxApprovals: u32 = 100; } + // impl pallet_treasury::Config for Test { impl pallet_treasury::Config for Test { type PalletId = TreasuryPalletId; @@ -121,31 +116,26 @@ impl pallet_treasury::Config for Test { type Event = Event; type OnSlash = (); type ProposalBond = ProposalBond; - type ProposalBondMinimum = ProposalBondMinimum; - type SpendPeriod = SpendPeriod; + type ProposalBondMinimum = ConstU64<1>; + type SpendPeriod = ConstU64<2>; type Burn = Burn; type BurnDestination = (); // Just gets burned. type WeightInfo = (); type SpendFunds = Bounties; - type MaxApprovals = MaxApprovals; + type MaxApprovals = ConstU32<100>; } parameter_types! { - pub const BountyDepositBase: u64 = 80; - pub const BountyDepositPayoutDelay: u64 = 3; - pub const BountyUpdatePeriod: u32 = 20; pub const BountyCuratorDeposit: Permill = Permill::from_percent(50); - pub const BountyValueMinimum: u64 = 1; - pub const MaximumReasonLength: u32 = 16384; } impl Config for Test { type Event = Event; - type BountyDepositBase = BountyDepositBase; - type BountyDepositPayoutDelay = BountyDepositPayoutDelay; - type BountyUpdatePeriod = BountyUpdatePeriod; + type BountyDepositBase = ConstU64<80>; + type BountyDepositPayoutDelay = ConstU64<3>; + type BountyUpdatePeriod = ConstU64<20>; type BountyCuratorDeposit = BountyCuratorDeposit; - type BountyValueMinimum = BountyValueMinimum; - type DataDepositPerByte = DataDepositPerByte; - type MaximumReasonLength = MaximumReasonLength; + type BountyValueMinimum = ConstU64<1>; + type DataDepositPerByte = ConstU64<1>; + type MaximumReasonLength = ConstU32<16384>; type WeightInfo = (); type ChildBountyManager = (); } diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index 8e2569738b1f2..ba68d73ceddca 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -24,8 +24,12 @@ use crate as pallet_child_bounties; use std::cell::RefCell; use frame_support::{ - assert_noop, assert_ok, pallet_prelude::GenesisBuild, parameter_types, traits::OnInitialize, - weights::Weight, PalletId, + assert_noop, assert_ok, + pallet_prelude::GenesisBuild, + parameter_types, + traits::{ConstU32, ConstU64, OnInitialize}, + weights::Weight, + PalletId, }; use sp_core::H256; @@ -56,7 +60,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: Weight = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); @@ -77,7 +80,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -86,11 +89,9 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -98,7 +99,7 @@ impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } @@ -107,12 +108,8 @@ thread_local! { } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); - pub const ProposalBondMinimum: u64 = 1; - pub const SpendPeriod: u64 = 2; pub const Burn: Permill = Permill::from_percent(50); - pub const DataDepositPerByte: u64 = 1; pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - pub const MaxApprovals: u32 = 100; } impl pallet_treasury::Config for Test { @@ -123,43 +120,36 @@ impl pallet_treasury::Config for Test { type Event = Event; type OnSlash = (); type ProposalBond = ProposalBond; - type ProposalBondMinimum = ProposalBondMinimum; - type SpendPeriod = SpendPeriod; + type ProposalBondMinimum = ConstU64<1>; + type SpendPeriod = ConstU64<2>; type Burn = Burn; type BurnDestination = (); type WeightInfo = (); type SpendFunds = Bounties; - type MaxApprovals = MaxApprovals; + type MaxApprovals = ConstU32<100>; } parameter_types! { - pub const BountyDepositBase: u64 = 80; - pub const BountyDepositPayoutDelay: u64 = 3; - pub const BountyUpdatePeriod: u32 = 10; pub const BountyCuratorDeposit: Permill = Permill::from_percent(50); - pub const BountyValueMinimum: u64 = 5; - pub const MaximumReasonLength: u32 = 300; } impl pallet_bounties::Config for Test { type Event = Event; - type BountyDepositBase = BountyDepositBase; - type BountyDepositPayoutDelay = BountyDepositPayoutDelay; - type BountyUpdatePeriod = BountyUpdatePeriod; + type BountyDepositBase = ConstU64<80>; + type BountyDepositPayoutDelay = ConstU64<3>; + type BountyUpdatePeriod = ConstU64<10>; type BountyCuratorDeposit = BountyCuratorDeposit; - type BountyValueMinimum = BountyValueMinimum; - type DataDepositPerByte = DataDepositPerByte; - type MaximumReasonLength = MaximumReasonLength; + type BountyValueMinimum = ConstU64<5>; + type DataDepositPerByte = ConstU64<1>; + type MaximumReasonLength = ConstU32<300>; type WeightInfo = (); type ChildBountyManager = ChildBounties; } parameter_types! { - pub const MaxActiveChildBountyCount: u32 = 2; - pub const ChildBountyValueMinimum: u64 = 1; pub const ChildBountyCuratorDepositBase: Permill = Permill::from_percent(10); } impl pallet_child_bounties::Config for Test { type Event = Event; - type MaxActiveChildBountyCount = MaxActiveChildBountyCount; - type ChildBountyValueMinimum = ChildBountyValueMinimum; + type MaxActiveChildBountyCount = ConstU32<2>; + type ChildBountyValueMinimum = ConstU64<1>; type ChildBountyCuratorDepositBase = ChildBountyCuratorDepositBase; type WeightInfo = (); } diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 466cdb3eeeb5b..2af8b1b97036d 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -18,7 +18,10 @@ use super::{Event as CollectiveEvent, *}; use crate as pallet_collective; use frame_support::{ - assert_noop, assert_ok, parameter_types, traits::GenesisBuild, weights::Pays, Hashable, + assert_noop, assert_ok, parameter_types, + traits::{ConstU32, ConstU64, GenesisBuild}, + weights::Pays, + Hashable, }; use frame_system::{EventRecord, Phase}; use sp_core::{ @@ -83,11 +86,11 @@ mod mock_democracy { } } +pub type MaxMembers = ConstU32<100>; + parameter_types! { - pub const BlockHashCount: u64 = 250; pub const MotionDuration: u64 = 3; pub const MaxProposals: u32 = 100; - pub const MaxMembers: u32 = 100; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -106,7 +109,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -115,13 +118,13 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl Config for Test { type Origin = Origin; type Proposal = Call; type Event = Event; - type MotionDuration = MotionDuration; + type MotionDuration = ConstU64<3>; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; type DefaultVote = PrimeDefaultVote; @@ -131,7 +134,7 @@ impl Config for Test { type Origin = Origin; type Proposal = Call; type Event = Event; - type MotionDuration = MotionDuration; + type MotionDuration = ConstU64<3>; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; type DefaultVote = MoreThanMajorityThenPrimeDefaultVote; @@ -145,7 +148,7 @@ impl Config for Test { type Origin = Origin; type Proposal = Call; type Event = Event; - type MotionDuration = MotionDuration; + type MotionDuration = ConstU64<3>; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; type DefaultVote = PrimeDefaultVote; diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index e7745e1e5f7ff..584253aeaadfe 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -33,7 +33,9 @@ use frame_support::{ dispatch::DispatchErrorWithPostInfo, parameter_types, storage::child, - traits::{BalanceStatus, Contains, Currency, OnInitialize, ReservableCurrency}, + traits::{ + BalanceStatus, ConstU32, ConstU64, Contains, Currency, OnInitialize, ReservableCurrency, + }, weights::{constants::WEIGHT_PER_SECOND, DispatchClass, PostDispatchInfo, Weight}, }; use frame_system::{self as system, EventRecord, Phase}; @@ -177,7 +179,6 @@ impl ChainExtension for TestExtension { } parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND); pub static ExistentialDeposit: u64 = 1; @@ -197,7 +198,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -220,13 +221,11 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); } -parameter_types! { - pub const MinimumPeriod: u64 = 1; -} + impl pallet_timestamp::Config for Test { type Moment = u64; type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<1>; type WeightInfo = (); } impl pallet_utility::Config for Test { @@ -237,7 +236,6 @@ impl pallet_utility::Config for Test { } parameter_types! { pub const MaxValueSize: u32 = 16_384; - pub const DeletionQueueDepth: u32 = 1024; pub const DeletionWeightLimit: Weight = 500_000_000_000; pub const MaxCodeSize: u32 = 2 * 1024; pub MySchedule: Schedule = >::default(); @@ -282,7 +280,7 @@ impl Config for Test { type WeightPrice = Self; type WeightInfo = (); type ChainExtension = TestExtension; - type DeletionQueueDepth = DeletionQueueDepth; + type DeletionQueueDepth = ConstU32<1024>; type DeletionWeightLimit = DeletionWeightLimit; type Schedule = MySchedule; type DepositPerByte = DepositPerByte; diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 839478a5b8d94..1e36313122f09 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -22,7 +22,9 @@ use crate as pallet_democracy; use codec::Encode; use frame_support::{ assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize, SortedMembers}, + traits::{ + ConstU32, ConstU64, Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize, SortedMembers, + }, weights::Weight, }; use frame_system::{EnsureRoot, EnsureSignedBy}; @@ -50,8 +52,6 @@ const NAY: Vote = Vote { aye: false, conviction: Conviction::None }; const BIG_AYE: Vote = Vote { aye: true, conviction: Conviction::Locked1x }; const BIG_NAY: Vote = Vote { aye: false, conviction: Conviction::Locked1x }; -const MAX_PROPOSALS: u32 = 100; - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -77,7 +77,6 @@ impl Contains for BaseFilter { } parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1_000_000); } @@ -96,7 +95,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -123,31 +122,19 @@ impl pallet_scheduler::Config for Test { type PreimageProvider = (); type NoPreimagePostponement = (); } -parameter_types! { - pub const ExistentialDeposit: u64 = 1; - pub const MaxLocks: u32 = 10; -} + impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; - type MaxLocks = MaxLocks; + type MaxLocks = ConstU32<10>; type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } parameter_types! { - pub const LaunchPeriod: u64 = 2; - pub const VotingPeriod: u64 = 2; - pub const FastTrackVotingPeriod: u64 = 2; - pub const MinimumDeposit: u64 = 1; - pub const EnactmentPeriod: u64 = 2; - pub const VoteLockingPeriod: u64 = 3; - pub const CooloffPeriod: u64 = 2; - pub const MaxVotes: u32 = 100; - pub const MaxProposals: u32 = MAX_PROPOSALS; pub static PreimageByteDeposit: u64 = 0; pub static InstantAllowed: bool = false; } @@ -172,12 +159,12 @@ impl Config for Test { type Proposal = Call; type Event = Event; type Currency = pallet_balances::Pallet; - type EnactmentPeriod = EnactmentPeriod; - type LaunchPeriod = LaunchPeriod; - type VotingPeriod = VotingPeriod; - type VoteLockingPeriod = VoteLockingPeriod; - type FastTrackVotingPeriod = FastTrackVotingPeriod; - type MinimumDeposit = MinimumDeposit; + type EnactmentPeriod = ConstU64<2>; + type LaunchPeriod = ConstU64<2>; + type VotingPeriod = ConstU64<2>; + type VoteLockingPeriod = ConstU64<3>; + type FastTrackVotingPeriod = ConstU64<2>; + type MinimumDeposit = ConstU64<1>; type ExternalOrigin = EnsureSignedBy; type ExternalMajorityOrigin = EnsureSignedBy; type ExternalDefaultOrigin = EnsureSignedBy; @@ -186,17 +173,17 @@ impl Config for Test { type BlacklistOrigin = EnsureRoot; type CancelProposalOrigin = EnsureRoot; type VetoOrigin = EnsureSignedBy; - type CooloffPeriod = CooloffPeriod; + type CooloffPeriod = ConstU64<2>; type PreimageByteDeposit = PreimageByteDeposit; type Slash = (); type InstantOrigin = EnsureSignedBy; type InstantAllowed = InstantAllowed; type Scheduler = Scheduler; - type MaxVotes = MaxVotes; + type MaxVotes = ConstU32<100>; type OperationalPreimageOrigin = EnsureSignedBy; type PalletsOrigin = OriginCaller; type WeightInfo = (); - type MaxProposals = MaxProposals; + type MaxProposals = ConstU32<100>; } pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 3ac14b89e7953..d686df2a72f68 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -21,7 +21,11 @@ use frame_election_provider_support::{ data_provider, onchain, ElectionDataProvider, SequentialPhragmen, }; pub use frame_support::{assert_noop, assert_ok}; -use frame_support::{parameter_types, traits::Hooks, weights::Weight}; +use frame_support::{ + parameter_types, + traits::{ConstU32, Hooks}, + weights::Weight, +}; use multi_phase::unsigned::{IndexAssignmentOf, Voter}; use parking_lot::RwLock; use sp_core::{ @@ -218,7 +222,7 @@ impl frame_system::Config for Runtime { type OnKilledAccount = (); type SystemWeightInfo = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index c0b6fdfce6cd2..3a6c657a6f99c 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1121,8 +1121,10 @@ mod tests { use super::*; use crate as elections_phragmen; use frame_support::{ - assert_noop, assert_ok, dispatch::DispatchResultWithPostInfo, parameter_types, - traits::OnInitialize, + assert_noop, assert_ok, + dispatch::DispatchResultWithPostInfo, + parameter_types, + traits::{ConstU32, ConstU64, OnInitialize}, }; use frame_system::ensure_signed; use sp_core::H256; @@ -1134,7 +1136,6 @@ mod tests { use substrate_test_utils::assert_eq_uvec; parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -1154,7 +1155,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -1163,18 +1164,14 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - - parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = frame_system::Pallet; type MaxLocks = (); type MaxReserves = (); diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index b97083f27d5ee..9f93c90531180 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -20,7 +20,7 @@ use crate::*; use frame_support::{ assert_ok, parameter_types, - traits::OnInitialize, + traits::{ConstU64, OnInitialize}, weights::{DispatchInfo, GetDispatchInfo}, }; use sp_core::H256; @@ -51,7 +51,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -70,7 +69,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -81,9 +80,7 @@ impl frame_system::Config for Test { type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } -parameter_types! { - pub const ExistentialDeposit: u64 = 1; -} + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -91,16 +88,13 @@ impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } -parameter_types! { - pub const MagicNumber: u64 = 1_000_000_000; -} impl Config for Test { - type MagicNumber = MagicNumber; + type MagicNumber = ConstU64<1_000_000_000>; type Event = Event; type WeightInfo = (); } diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index d83c3c6df9eed..2c3e623e9c842 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -18,7 +18,10 @@ use crate as example_offchain_worker; use crate::*; use codec::Decode; -use frame_support::{assert_ok, parameter_types}; +use frame_support::{ + assert_ok, parameter_types, + traits::{ConstU32, ConstU64}, +}; use sp_core::{ offchain::{testing, OffchainWorkerExt, TransactionPoolExt}, sr25519::Signature, @@ -49,7 +52,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -68,7 +70,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -77,7 +79,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } type Extrinsic = TestXt; @@ -111,8 +113,6 @@ where } parameter_types! { - pub const GracePeriod: u64 = 5; - pub const UnsignedInterval: u64 = 128; pub const UnsignedPriority: u64 = 1 << 20; } @@ -120,8 +120,8 @@ impl Config for Test { type Event = Event; type AuthorityId = crypto::TestAuthId; type Call = Call; - type GracePeriod = GracePeriod; - type UnsignedInterval = UnsignedInterval; + type GracePeriod = ConstU64<5>; + type UnsignedInterval = ConstU64<128>; type UnsignedPriority = UnsignedPriority; } diff --git a/frame/examples/parallel/src/tests.rs b/frame/examples/parallel/src/tests.rs index 1a841ca68184e..82ce95d7a85bb 100644 --- a/frame/examples/parallel/src/tests.rs +++ b/frame/examples/parallel/src/tests.rs @@ -40,7 +40,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub const AvailableBlockRatio: Perbill = Perbill::one(); } @@ -57,7 +56,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = frame_support::traits::ConstU64<250>; type DbWeight = (); type BlockWeights = (); type BlockLength = (); @@ -71,12 +70,6 @@ impl frame_system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; } -parameter_types! { - pub const GracePeriod: u64 = 5; - pub const UnsignedInterval: u64 = 128; - pub const UnsignedPriority: u64 = 1 << 20; -} - impl Config for Test { type Call = Call; } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 7ff5584879cea..cc013d4c333f4 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -578,7 +578,10 @@ mod tests { use frame_support::{ assert_err, parameter_types, - traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons}, + traits::{ + ConstU32, ConstU64, ConstU8, Currency, LockIdentifier, LockableCurrency, + WithdrawReasons, + }, weights::{IdentityFee, RuntimeDbWeight, Weight, WeightToFeePolynomial}, }; use frame_system::{Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo}; @@ -731,7 +734,6 @@ mod tests { ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::builder() .base_block(10) @@ -758,7 +760,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = RuntimeVersion; type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -767,7 +769,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } type Balance = u64; @@ -788,12 +790,11 @@ mod tests { parameter_types! { pub const TransactionByteFee: Balance = 0; - pub const OperationalFeeMultiplier: u8 = 5; } impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; type TransactionByteFee = TransactionByteFee; - type OperationalFeeMultiplier = OperationalFeeMultiplier; + type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/frame/gilt/src/mock.rs b/frame/gilt/src/mock.rs index 9ea33a6d6b68d..6299f7c320312 100644 --- a/frame/gilt/src/mock.rs +++ b/frame/gilt/src/mock.rs @@ -21,7 +21,7 @@ use crate as pallet_gilt; use frame_support::{ ord_parameter_types, parameter_types, - traits::{Currency, GenesisBuild, OnFinalize, OnInitialize}, + traits::{ConstU16, ConstU32, ConstU64, Currency, GenesisBuild, OnFinalize, OnInitialize}, }; use sp_core::H256; use sp_runtime::{ @@ -45,11 +45,6 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; -} - impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -64,7 +59,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; @@ -72,20 +67,16 @@ impl frame_system::Config for Test { type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); - type SS58Prefix = SS58Prefix; + type SS58Prefix = ConstU16<42>; type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } -parameter_types! { - pub const ExistentialDeposit: u64 = 1; -} - impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = frame_support::traits::ConstU64<1>; type AccountStore = System; type WeightInfo = (); type MaxLocks = (); @@ -95,13 +86,6 @@ impl pallet_balances::Config for Test { parameter_types! { pub IgnoredIssuance: u64 = Balances::total_balance(&0); // Account zero is ignored. - pub const QueueCount: u32 = 3; - pub const MaxQueueLen: u32 = 3; - pub const FifoQueueLen: u32 = 1; - pub const Period: u64 = 3; - pub const MinFreeze: u64 = 2; - pub const IntakePeriod: u64 = 2; - pub const MaxIntakeBids: u32 = 2; } ord_parameter_types! { pub const One: u64 = 1; @@ -115,13 +99,13 @@ impl pallet_gilt::Config for Test { type Deficit = (); type Surplus = (); type IgnoredIssuance = IgnoredIssuance; - type QueueCount = QueueCount; - type MaxQueueLen = MaxQueueLen; - type FifoQueueLen = FifoQueueLen; - type Period = Period; - type MinFreeze = MinFreeze; - type IntakePeriod = IntakePeriod; - type MaxIntakeBids = MaxIntakeBids; + type QueueCount = ConstU32<3>; + type MaxQueueLen = ConstU32<3>; + type FifoQueueLen = ConstU32<1>; + type Period = ConstU64<3>; + type MinFreeze = ConstU64<2>; + type IntakePeriod = ConstU64<2>; + type MaxIntakeBids = ConstU32<2>; type WeightInfo = (); } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index aed13ec3717a9..6f7c57cad0b57 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -25,7 +25,9 @@ use codec::Encode; use frame_election_provider_support::onchain; use frame_support::{ parameter_types, - traits::{GenesisBuild, KeyOwnerProofSystem, OnFinalize, OnInitialize}, + traits::{ + ConstU128, ConstU32, ConstU64, GenesisBuild, KeyOwnerProofSystem, OnFinalize, OnInitialize, + }, }; use pallet_session::historical as pallet_session_historical; use pallet_staking::EraIndex; @@ -69,7 +71,6 @@ impl_opaque_keys! { } parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -89,7 +90,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -119,8 +120,8 @@ impl pallet_session::Config for Test { type Event = Event; type ValidatorId = u64; type ValidatorIdOf = pallet_staking::StashOf; - type ShouldEndSession = pallet_session::PeriodicSessions; - type NextSessionRotation = pallet_session::PeriodicSessions; + type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; + type NextSessionRotation = pallet_session::PeriodicSessions, ConstU64<0>>; type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = TestSessionKeys; @@ -132,21 +133,13 @@ impl pallet_session::historical::Config for Test { type FullIdentificationOf = pallet_staking::ExposureOf; } -parameter_types! { - pub const UncleGenerations: u64 = 0; -} - impl pallet_authorship::Config for Test { type FindAuthor = (); - type UncleGenerations = UncleGenerations; + type UncleGenerations = ConstU64<0>; type FilterUncle = (); type EventHandler = (); } -parameter_types! { - pub const ExistentialDeposit: u128 = 1; -} - impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -154,19 +147,15 @@ impl pallet_balances::Config for Test { type Balance = u128; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU128<1>; type AccountStore = System; type WeightInfo = (); } -parameter_types! { - pub const MinimumPeriod: u64 = 3; -} - impl pallet_timestamp::Config for Test { type Moment = u64; type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<3>; type WeightInfo = (); } @@ -187,7 +176,6 @@ parameter_types! { pub const SlashDeferDuration: EraIndex = 0; pub const AttestationPeriod: u64 = 100; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerValidator: u32 = 64; pub const ElectionLookahead: u64 = 0; pub const StakingUnsignedPriority: u64 = u64::MAX / 2; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); @@ -213,7 +201,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; @@ -232,7 +220,6 @@ impl pallet_offences::Config for Test { parameter_types! { pub const ReportLongevity: u64 = BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * Period::get(); - pub const MaxAuthorities: u32 = 100; } impl Config for Test { @@ -253,7 +240,7 @@ impl Config for Test { super::EquivocationHandler; type WeightInfo = (); - type MaxAuthorities = MaxAuthorities; + type MaxAuthorities = ConstU32<100>; } pub fn grandpa_log(log: ConsensusLog) -> DigestItem { diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 2faf65f560a88..efbd1d984f336 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -22,7 +22,9 @@ use crate as pallet_identity; use codec::{Decode, Encode}; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, parameter_types, traits::EnsureOneOf, BoundedVec, + assert_noop, assert_ok, ord_parameter_types, parameter_types, + traits::{ConstU32, ConstU64, EnsureOneOf}, + BoundedVec, }; use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; @@ -47,7 +49,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -65,7 +66,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; @@ -75,30 +76,26 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } + impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type MaxLocks = (); type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); } + parameter_types! { - pub const BasicDeposit: u64 = 10; - pub const FieldDeposit: u64 = 10; - pub const SubAccountDeposit: u64 = 10; - pub const MaxSubAccounts: u32 = 2; pub const MaxAdditionalFields: u32 = 2; pub const MaxRegistrars: u32 = 20; } + ord_parameter_types! { pub const One: u64 = 1; pub const Two: u64 = 2; @@ -109,10 +106,10 @@ impl pallet_identity::Config for Test { type Event = Event; type Currency = Balances; type Slashed = (); - type BasicDeposit = BasicDeposit; - type FieldDeposit = FieldDeposit; - type SubAccountDeposit = SubAccountDeposit; - type MaxSubAccounts = MaxSubAccounts; + type BasicDeposit = ConstU64<10>; + type FieldDeposit = ConstU64<10>; + type SubAccountDeposit = ConstU64<10>; + type MaxSubAccounts = ConstU32<2>; type MaxAdditionalFields = MaxAdditionalFields; type MaxRegistrars = MaxRegistrars; type RegistrarOrigin = EnsureOneOrRoot; diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 3168f60ce022f..8166bfc9119e7 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -21,7 +21,11 @@ use std::cell::RefCell; -use frame_support::{parameter_types, weights::Weight}; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, + weights::Weight, +}; use pallet_session::historical as pallet_session_historical; use sp_core::H256; use sp_runtime::{ @@ -118,7 +122,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { } parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -138,7 +141,7 @@ impl frame_system::Config for Runtime { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -147,7 +150,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } parameter_types! { @@ -173,13 +176,9 @@ impl pallet_session::historical::Config for Runtime { type FullIdentificationOf = ConvertInto; } -parameter_types! { - pub const UncleGenerations: u32 = 5; -} - impl pallet_authorship::Config for Runtime { type FindAuthor = (); - type UncleGenerations = UncleGenerations; + type UncleGenerations = ConstU64<5>; type FilterUncle = (); type EventHandler = ImOnline; } @@ -221,9 +220,6 @@ impl frame_support::traits::EstimateNextSessionRotation for TestNextSession parameter_types! { pub const UnsignedPriority: u64 = 1 << 20; - pub const MaxKeys: u32 = 10_000; - pub const MaxPeerInHeartbeats: u32 = 10_000; - pub const MaxPeerDataEncodingSize: u32 = 1_000; } impl Config for Runtime { @@ -234,9 +230,9 @@ impl Config for Runtime { type ReportUnresponsiveness = OffenceHandler; type UnsignedPriority = UnsignedPriority; type WeightInfo = (); - type MaxKeys = MaxKeys; - type MaxPeerInHeartbeats = MaxPeerInHeartbeats; - type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize; + type MaxKeys = ConstU32<10_000>; + type MaxPeerInHeartbeats = ConstU32<10_000>; + type MaxPeerDataEncodingSize = ConstU32<1_000>; } impl frame_system::offchain::SendTransactionTypes for Runtime diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index 3e3aed2986b9f..ef654833c3a36 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -20,7 +20,10 @@ #![cfg(test)] use crate::{self as pallet_indices, Config}; -use frame_support::parameter_types; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, +}; use sp_core::H256; use sp_runtime::testing::Header; @@ -40,7 +43,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -60,7 +62,7 @@ impl frame_system::Config for Test { type Lookup = Indices; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -69,11 +71,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { @@ -83,19 +81,15 @@ impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } -parameter_types! { - pub const Deposit: u64 = 1; -} - impl Config for Test { type AccountIndex = u64; type Currency = Balances; - type Deposit = Deposit; + type Deposit = ConstU64<1>; type Event = Event; type WeightInfo = (); } diff --git a/frame/lottery/src/mock.rs b/frame/lottery/src/mock.rs index df86e063c477f..36b847d48d97e 100644 --- a/frame/lottery/src/mock.rs +++ b/frame/lottery/src/mock.rs @@ -22,7 +22,7 @@ use crate as pallet_lottery; use frame_support::{ parameter_types, - traits::{OnFinalize, OnInitialize}, + traits::{ConstU32, ConstU64, OnFinalize, OnInitialize}, }; use frame_support_test::TestRandomness; use frame_system::EnsureRoot; @@ -49,9 +49,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: u32 = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); } @@ -70,7 +67,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -79,11 +76,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { @@ -93,15 +86,13 @@ impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } parameter_types! { pub const LotteryPalletId: PalletId = PalletId(*b"py/lotto"); - pub const MaxCalls: u32 = 2; - pub const MaxGenerateRandom: u32 = 10; } impl Config for Test { @@ -111,9 +102,9 @@ impl Config for Test { type Randomness = TestRandomness; type Event = Event; type ManagerOrigin = EnsureRoot; - type MaxCalls = MaxCalls; + type MaxCalls = ConstU32<2>; type ValidateCall = Lottery; - type MaxGenerateRandom = MaxGenerateRandom; + type MaxGenerateRandom = ConstU32<10>; type WeightInfo = (); } diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 4bcc28c0ef46a..b34051731f69d 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -509,7 +509,8 @@ mod tests { }; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, parameter_types, traits::GenesisBuild, + assert_noop, assert_ok, ord_parameter_types, parameter_types, + traits::{ConstU32, ConstU64, GenesisBuild}, }; use frame_system::EnsureSignedBy; @@ -528,8 +529,6 @@ mod tests { ); parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaxMembers: u32 = 10; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); pub static Members: Vec = vec![]; @@ -551,7 +550,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -560,7 +559,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } ord_parameter_types! { pub const One: u64 = 1; @@ -607,7 +606,7 @@ mod tests { type PrimeOrigin = EnsureSignedBy; type MembershipInitialized = TestChangeMembers; type MembershipChanged = TestChangeMembers; - type MaxMembers = MaxMembers; + type MaxMembers = ConstU32<10>; type WeightInfo = (); } diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index 392ae5050a96c..2adea420f03d7 100644 --- a/frame/merkle-mountain-range/src/mock.rs +++ b/frame/merkle-mountain-range/src/mock.rs @@ -19,7 +19,7 @@ use crate as pallet_mmr; use crate::*; use codec::{Decode, Encode}; -use frame_support::parameter_types; +use frame_support::traits::{ConstU32, ConstU64}; use pallet_mmr_primitives::{Compact, LeafDataProvider}; use sp_core::H256; use sp_runtime::{ @@ -42,9 +42,6 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type Origin = Origin; @@ -57,7 +54,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type DbWeight = (); type BlockWeights = (); type BlockLength = (); @@ -69,7 +66,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl Config for Test { diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index f050ac9d72001..2d6c02c559e8f 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -22,7 +22,10 @@ use super::*; use crate as pallet_multisig; -use frame_support::{assert_noop, assert_ok, parameter_types, traits::Contains}; +use frame_support::{ + assert_noop, assert_ok, parameter_types, + traits::{ConstU16, ConstU32, ConstU64, Contains}, +}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -46,7 +49,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -65,7 +67,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -74,11 +76,9 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -86,15 +86,11 @@ impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } -parameter_types! { - pub const DepositBase: u64 = 1; - pub const DepositFactor: u64 = 1; - pub const MaxSignatories: u16 = 3; -} + pub struct TestBaseCallFilter; impl Contains for TestBaseCallFilter { fn contains(c: &Call) -> bool { @@ -110,9 +106,9 @@ impl Config for Test { type Event = Event; type Call = Call; type Currency = Balances; - type DepositBase = DepositBase; - type DepositFactor = DepositFactor; - type MaxSignatories = MaxSignatories; + type DepositBase = ConstU64<1>; + type DepositFactor = ConstU64<1>; + type MaxSignatories = ConstU16<3>; type WeightInfo = (); } diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index ea58ea693d3fb..91918ce846002 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -245,7 +245,10 @@ mod tests { use super::*; use crate as pallet_nicks; - use frame_support::{assert_noop, assert_ok, ord_parameter_types, parameter_types}; + use frame_support::{ + assert_noop, assert_ok, ord_parameter_types, parameter_types, + traits::{ConstU32, ConstU64}, + }; use frame_system::EnsureSignedBy; use sp_core::H256; use sp_runtime::{ @@ -269,7 +272,6 @@ mod tests { ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -288,7 +290,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -297,11 +299,9 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -309,26 +309,22 @@ mod tests { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } - parameter_types! { - pub const ReservationFee: u64 = 2; - pub const MinLength: u32 = 3; - pub const MaxLength: u32 = 16; - } + ord_parameter_types! { pub const One: u64 = 1; } impl Config for Test { type Event = Event; type Currency = Balances; - type ReservationFee = ReservationFee; + type ReservationFee = ConstU64<2>; type Slashed = (); type ForceOrigin = EnsureSignedBy; - type MinLength = MinLength; - type MaxLength = MaxLength; + type MinLength = ConstU32<3>; + type MaxLength = ConstU32<16>; } fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/node-authorization/src/mock.rs b/frame/node-authorization/src/mock.rs index 8e2bc7cfd2a6d..bb882c62abb6f 100644 --- a/frame/node-authorization/src/mock.rs +++ b/frame/node-authorization/src/mock.rs @@ -20,7 +20,10 @@ use super::*; use crate as pallet_node_authorization; -use frame_support::{ord_parameter_types, parameter_types, traits::GenesisBuild}; +use frame_support::{ + ord_parameter_types, + traits::{ConstU32, ConstU64, GenesisBuild}, +}; use frame_system::EnsureSignedBy; use sp_core::H256; use sp_runtime::{ @@ -44,9 +47,6 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type DbWeight = (); @@ -62,7 +62,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -71,7 +71,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } ord_parameter_types! { @@ -80,14 +80,11 @@ ord_parameter_types! { pub const Three: u64 = 3; pub const Four: u64 = 4; } -parameter_types! { - pub const MaxWellKnownNodes: u32 = 4; - pub const MaxPeerIdLength: u32 = 2; -} + impl Config for Test { type Event = Event; - type MaxWellKnownNodes = MaxWellKnownNodes; - type MaxPeerIdLength = MaxPeerIdLength; + type MaxWellKnownNodes = ConstU32<4>; + type MaxPeerIdLength = ConstU32<2>; type AddOrigin = EnsureSignedBy; type RemoveOrigin = EnsureSignedBy; type SwapOrigin = EnsureSignedBy; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index ab2b3569228c6..1a5fdcd61bee7 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -21,7 +21,11 @@ use super::*; use frame_election_provider_support::onchain; -use frame_support::{parameter_types, weights::constants::WEIGHT_PER_SECOND}; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, + weights::constants::WEIGHT_PER_SECOND, +}; use frame_system as system; use pallet_session::historical as pallet_session_historical; use sp_runtime::{ @@ -80,13 +84,10 @@ impl pallet_balances::Config for Test { type WeightInfo = (); } -parameter_types! { - pub const MinimumPeriod: u64 = 5; -} impl pallet_timestamp::Config for Test { type Moment = u64; type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<5>; type WeightInfo = (); } impl pallet_session::historical::Config for Test { @@ -145,10 +146,6 @@ pallet_staking_reward_curve::build! { } parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; - pub const MaxNominatorRewardedPerValidator: u32 = 64; - pub const MaxKeys: u32 = 10_000; - pub const MaxPeerInHeartbeats: u32 = 10_000; - pub const MaxPeerDataEncodingSize: u32 = 1_000; } pub type Extrinsic = sp_runtime::testing::TestXt; @@ -174,7 +171,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; @@ -191,9 +188,9 @@ impl pallet_im_online::Config for Test { type ReportUnresponsiveness = Offences; type UnsignedPriority = (); type WeightInfo = (); - type MaxKeys = MaxKeys; - type MaxPeerInHeartbeats = MaxPeerInHeartbeats; - type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize; + type MaxKeys = ConstU32<10_000>; + type MaxPeerInHeartbeats = ConstU32<10_000>; + type MaxPeerDataEncodingSize = ConstU32<1_000>; } impl pallet_offences::Config for Test { diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index c2db42ec72fac..17d34d46e3137 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -24,6 +24,7 @@ use crate::Config; use codec::Encode; use frame_support::{ parameter_types, + traits::{ConstU32, ConstU64}, weights::{ constants::{RocksDbWeight, WEIGHT_PER_SECOND}, Weight, @@ -84,7 +85,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND); } @@ -103,7 +103,7 @@ impl frame_system::Config for Runtime { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -112,7 +112,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl Config for Runtime { diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index 601f72547237b..3996d84256963 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -21,7 +21,9 @@ use super::*; use crate as pallet_preimage; use frame_support::{ - ord_parameter_types, parameter_types, traits::Everything, weights::constants::RocksDbWeight, + ord_parameter_types, parameter_types, + traits::{ConstU32, ConstU64, Everything}, + weights::constants::RocksDbWeight, }; use frame_system::EnsureSignedBy; use sp_core::H256; @@ -47,7 +49,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); } @@ -66,7 +67,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -75,32 +76,24 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 5; - pub const MaxReserves: u32 = 50; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<5>; type AccountStore = System; type WeightInfo = (); type MaxLocks = (); - type MaxReserves = MaxReserves; + type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; } parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; pub const MaxScheduledPerBlock: u32 = 10; - pub const MaxSize: u32 = 1024; - pub const BaseDeposit: u64 = 2; - pub const ByteDeposit: u64 = 1; } ord_parameter_types! { @@ -112,9 +105,9 @@ impl Config for Test { type Event = Event; type Currency = Balances; type ManagerOrigin = EnsureSignedBy; - type MaxSize = MaxSize; - type BaseDeposit = BaseDeposit; - type ByteDeposit = ByteDeposit; + type MaxSize = ConstU32<1024>; + type BaseDeposit = ConstU64<2>; + type ByteDeposit = ConstU64<1>; } pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 538527d47ecd0..902eae8fc3208 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -24,7 +24,10 @@ use super::*; use crate as proxy; use codec::{Decode, Encode}; use frame_support::{ - assert_noop, assert_ok, dispatch::DispatchError, parameter_types, traits::Contains, + assert_noop, assert_ok, + dispatch::DispatchError, + parameter_types, + traits::{ConstU32, ConstU64, Contains}, RuntimeDebug, }; use sp_core::H256; @@ -50,7 +53,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -69,7 +71,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -78,11 +80,9 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -90,7 +90,7 @@ impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } @@ -100,14 +100,7 @@ impl pallet_utility::Config for Test { type PalletsOrigin = OriginCaller; type WeightInfo = (); } -parameter_types! { - pub const ProxyDepositBase: u64 = 1; - pub const ProxyDepositFactor: u64 = 1; - pub const MaxProxies: u16 = 4; - pub const MaxPending: u32 = 2; - pub const AnnouncementDepositBase: u64 = 1; - pub const AnnouncementDepositFactor: u64 = 1; -} + #[derive( Copy, Clone, @@ -161,14 +154,14 @@ impl Config for Test { type Call = Call; type Currency = Balances; type ProxyType = ProxyType; - type ProxyDepositBase = ProxyDepositBase; - type ProxyDepositFactor = ProxyDepositFactor; - type MaxProxies = MaxProxies; + type ProxyDepositBase = ConstU64<1>; + type ProxyDepositFactor = ConstU64<1>; + type MaxProxies = ConstU32<4>; type WeightInfo = (); type CallHasher = BlakeTwo256; - type MaxPending = MaxPending; - type AnnouncementDepositBase = AnnouncementDepositBase; - type AnnouncementDepositFactor = AnnouncementDepositFactor; + type MaxPending = ConstU32<2>; + type AnnouncementDepositBase = ConstU64<1>; + type AnnouncementDepositFactor = ConstU64<1>; } use super::{Call as ProxyCall, Event as ProxyEvent}; diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index eee70984f2576..bf5920acff8ed 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -169,7 +169,7 @@ mod tests { use frame_support::{ parameter_types, - traits::{OnInitialize, Randomness}, + traits::{ConstU32, ConstU64, OnInitialize, Randomness}, }; use frame_system::limits; @@ -188,7 +188,6 @@ mod tests { ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: limits::BlockWeights = limits::BlockWeights ::simple_max(1024); pub BlockLength: limits::BlockLength = limits::BlockLength @@ -210,7 +209,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -219,7 +218,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet_randomness_collective_flip::Config for Test {} diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 1bd7507436b7a..778b966c76e83 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -22,7 +22,7 @@ use super::*; use crate as recovery; use frame_support::{ parameter_types, - traits::{OnFinalize, OnInitialize}, + traits::{ConstU16, ConstU32, ConstU64, OnFinalize, OnInitialize}, }; use sp_core::H256; use sp_runtime::{ @@ -46,7 +46,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -66,7 +65,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -75,7 +74,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } parameter_types! { @@ -97,7 +96,6 @@ impl pallet_balances::Config for Test { parameter_types! { pub const ConfigDepositBase: u64 = 10; pub const FriendDepositFactor: u64 = 1; - pub const MaxFriends: u16 = 3; pub const RecoveryDeposit: u64 = 10; } @@ -107,7 +105,7 @@ impl Config for Test { type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; - type MaxFriends = MaxFriends; + type MaxFriends = ConstU16<3>; type RecoveryDeposit = RecoveryDeposit; } diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 535e91937e4dc..014f473302ab7 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -22,7 +22,9 @@ use super::*; use crate as scheduler; use frame_support::{ ord_parameter_types, parameter_types, - traits::{Contains, EnsureOneOf, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + traits::{ + ConstU32, ConstU64, Contains, EnsureOneOf, EqualPrivilegeOnly, OnFinalize, OnInitialize, + }, weights::constants::RocksDbWeight, }; use frame_system::{EnsureRoot, EnsureSignedBy}; @@ -116,7 +118,6 @@ impl Contains for BaseFilter { } parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); } @@ -135,7 +136,7 @@ impl system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -144,15 +145,13 @@ impl system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl logger::Config for Test { type Event = Event; } parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 10; - pub const MaxSize: u32 = 1024; pub const NoPreimagePostponement: Option = Some(2); } ord_parameter_types! { @@ -164,7 +163,7 @@ impl pallet_preimage::Config for Test { type WeightInfo = (); type Currency = (); type ManagerOrigin = EnsureRoot; - type MaxSize = MaxSize; + type MaxSize = ConstU32<1024>; type BaseDeposit = (); type ByteDeposit = (); } @@ -176,7 +175,7 @@ impl Config for Test { type Call = Call; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; - type MaxScheduledPerBlock = MaxScheduledPerBlock; + type MaxScheduledPerBlock = ConstU32<10>; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; type PreimageProvider = Preimage; diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index 992aecba38e82..d5b3814fd97a4 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -20,7 +20,10 @@ use super::*; use crate as pallet_scored_pool; -use frame_support::{ord_parameter_types, parameter_types, traits::GenesisBuild}; +use frame_support::{ + ord_parameter_types, parameter_types, + traits::{ConstU32, ConstU64, GenesisBuild}, +}; use frame_system::EnsureSignedBy; use sp_core::H256; use sp_runtime::{ @@ -46,9 +49,6 @@ frame_support::construct_runtime!( parameter_types! { pub const CandidateDeposit: u64 = 25; - pub const Period: u64 = 4; - pub const BlockHashCount: u64 = 250; - pub const ExistentialDeposit: u64 = 1; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -72,7 +72,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -81,7 +81,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { @@ -91,7 +91,7 @@ impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } @@ -130,7 +130,7 @@ impl Config for Test { type MembershipChanged = TestChangeMembers; type Currency = Balances; type CandidateDeposit = CandidateDeposit; - type Period = Period; + type Period = ConstU64<4>; type Score = u64; type ScoreOrigin = EnsureSignedBy; } diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 3f3b103905b58..2560563511e6a 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -20,7 +20,10 @@ #![cfg(test)] use frame_election_provider_support::onchain; -use frame_support::parameter_types; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, +}; use sp_runtime::traits::IdentityLookup; type AccountId = u64; @@ -68,7 +71,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: Balance = 10; @@ -85,13 +88,10 @@ impl pallet_balances::Config for Test { type WeightInfo = (); } -parameter_types! { - pub const MinimumPeriod: u64 = 5; -} impl pallet_timestamp::Config for Test { type Moment = u64; type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<5>; type WeightInfo = (); } impl pallet_session::historical::Config for Test { @@ -144,8 +144,6 @@ pallet_staking_reward_curve::build! { } parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; - pub const MaxNominatorRewardedPerValidator: u32 = 64; - pub const UnsignedPriority: u64 = 1 << 20; } pub type Extrinsic = sp_runtime::testing::TestXt; @@ -179,7 +177,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index d0511d3936822..ec1f841f50b14 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -32,7 +32,11 @@ use sp_runtime::{ }; use sp_staking::SessionIndex; -use frame_support::{parameter_types, traits::GenesisBuild, BasicExternalities}; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64, GenesisBuild}, + BasicExternalities, +}; impl_opaque_keys! { pub struct MockSessionKeys { @@ -234,8 +238,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { } parameter_types! { - pub const MinimumPeriod: u64 = 5; - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -255,7 +257,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -264,13 +266,13 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet_timestamp::Config for Test { type Moment = u64; type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<5>; type WeightInfo = (); } diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index cc0606edf499d..199076c88244c 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -29,7 +29,10 @@ use codec::Decode; use sp_core::crypto::key_types::DUMMY; use sp_runtime::testing::UintAuthorityId; -use frame_support::{assert_noop, assert_ok, traits::OnInitialize}; +use frame_support::{ + assert_noop, assert_ok, + traits::{ConstU64, OnInitialize}, +}; fn initialize_block(block: u64) { SESSION_CHANGED.with(|l| *l.borrow_mut() = false); @@ -291,12 +294,7 @@ fn session_changed_flag_works() { #[test] fn periodic_session_works() { - frame_support::parameter_types! { - const Period: u64 = 10; - const Offset: u64 = 3; - } - - type P = PeriodicSessions; + type P = PeriodicSessions, ConstU64<3>>; // make sure that offset phase behaves correctly for i in 0u64..3 { diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 4348f2378c425..fbf3b2fd757a5 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -20,7 +20,10 @@ use super::*; use crate as pallet_society; -use frame_support::{ord_parameter_types, parameter_types}; +use frame_support::{ + ord_parameter_types, parameter_types, + traits::{ConstU32, ConstU64}, +}; use frame_support_test::TestRandomness; use frame_system::EnsureSignedBy; use sp_core::H256; @@ -45,16 +48,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const CandidateDeposit: u64 = 25; - pub const WrongSideDeduction: u64 = 2; - pub const MaxStrikes: u32 = 2; - pub const RotationPeriod: u64 = 4; - pub const PeriodSpend: u64 = 1000; - pub const MaxLockDuration: u64 = 100; - pub const ChallengePeriod: u64 = 8; - pub const BlockHashCount: u64 = 250; - pub const ExistentialDeposit: u64 = 1; - pub const MaxCandidateIntake: u32 = 10; pub const SocietyPalletId: PalletId = PalletId(*b"py/socie"); pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); @@ -80,7 +73,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type OnNewAccount = (); @@ -89,7 +82,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { @@ -99,7 +92,7 @@ impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } @@ -108,17 +101,17 @@ impl Config for Test { type Event = Event; type Currency = pallet_balances::Pallet; type Randomness = TestRandomness; - type CandidateDeposit = CandidateDeposit; - type WrongSideDeduction = WrongSideDeduction; - type MaxStrikes = MaxStrikes; - type PeriodSpend = PeriodSpend; + type CandidateDeposit = ConstU64<25>; + type WrongSideDeduction = ConstU64<2>; + type MaxStrikes = ConstU32<2>; + type PeriodSpend = ConstU64<1000>; type MembershipChanged = (); - type RotationPeriod = RotationPeriod; - type MaxLockDuration = MaxLockDuration; + type RotationPeriod = ConstU64<4>; + type MaxLockDuration = ConstU64<100>; type FounderSetOrigin = EnsureSignedBy; type SuspensionJudgementOrigin = EnsureSignedBy; - type ChallengePeriod = ChallengePeriod; - type MaxCandidateIntake = MaxCandidateIntake; + type ChallengePeriod = ConstU64<8>; + type MaxCandidateIntake = ConstU32<10>; type PalletId = SocietyPalletId; } diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index f96b7fd2f37bc..cd9755366b0f6 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -947,7 +947,7 @@ mod tests { let (validator_stash, nominators) = create_validator_with_nominators::( n, - ::MaxNominatorRewardedPerValidator::get() as u32, + ::MaxNominatorRewardedPerValidator::get(), false, RewardDestination::Staked, ) @@ -972,7 +972,7 @@ mod tests { let (validator_stash, _nominators) = create_validator_with_nominators::( n, - ::MaxNominatorRewardedPerValidator::get() as u32, + ::MaxNominatorRewardedPerValidator::get(), false, RewardDestination::Staked, ) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index f6e2ce0e4bc18..ea9b9f05f1059 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -22,7 +22,8 @@ use frame_election_provider_support::{onchain, SortedListProvider}; use frame_support::{ assert_ok, parameter_types, traits::{ - Currency, FindAuthor, GenesisBuild, Get, Hooks, Imbalance, OnUnbalanced, OneSessionHandler, + ConstU32, ConstU64, Currency, FindAuthor, GenesisBuild, Get, Hooks, Imbalance, + OnUnbalanced, OneSessionHandler, }, weights::constants::RocksDbWeight, }; @@ -113,12 +114,10 @@ impl FindAuthor for Author11 { } parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max( frame_support::weights::constants::WEIGHT_PER_SECOND * 2 ); - pub const MaxLocks: u32 = 1024; pub static SessionsPerEra: SessionIndex = 3; pub static ExistentialDeposit: Balance = 1; pub static SlashDeferDuration: EraIndex = 0; @@ -141,7 +140,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = frame_support::traits::ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -153,7 +152,7 @@ impl frame_system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { - type MaxLocks = MaxLocks; + type MaxLocks = frame_support::traits::ConstU32<1024>; type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; @@ -163,9 +162,7 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); } -parameter_types! { - pub const UncleGenerations: u64 = 0; -} + sp_runtime::impl_opaque_keys! { pub struct SessionKeys { pub other: OtherSessionHandler, @@ -189,19 +186,18 @@ impl pallet_session::historical::Config for Test { } impl pallet_authorship::Config for Test { type FindAuthor = Author11; - type UncleGenerations = UncleGenerations; + type UncleGenerations = ConstU64<0>; type FilterUncle = (); type EventHandler = Pallet; } -parameter_types! { - pub const MinimumPeriod: u64 = 5; -} + impl pallet_timestamp::Config for Test { type Moment = u64; type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<5>; type WeightInfo = (); } + pallet_staking_reward_curve::build! { const I_NPOS: PiecewiseLinear<'static> = curve!( min_inflation: 0_025_000, @@ -215,7 +211,6 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const BondingDuration: EraIndex = 3; pub const RewardCurve: &'static PiecewiseLinear<'static> = &I_NPOS; - pub const MaxNominatorRewardedPerValidator: u32 = 64; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(75); } @@ -269,7 +264,7 @@ impl crate::pallet::pallet::Config for Test { type SessionInterface = Self; type EraPayout = ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index 408cccc7de21d..baea68788acf4 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as sudo; use frame_support::{ parameter_types, - traits::{Contains, GenesisBuild}, + traits::{ConstU32, ConstU64, Contains, GenesisBuild}, }; use frame_system::limits; use sp_core::H256; @@ -109,7 +109,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: limits::BlockWeights = limits::BlockWeights::simple_max(1024); } @@ -135,7 +134,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -144,7 +143,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } // Implement the logger module's `Config` on the Test runtime. diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index 7a59206aeba0e..224ff496a990a 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -306,18 +306,14 @@ impl codec::EncodeLike> for BoundedBTreeMap whe pub mod test { use super::*; use crate::Twox128; + use frame_support::traits::ConstU32; use sp_io::TestExternalities; - crate::parameter_types! { - pub const Seven: u32 = 7; - pub const Four: u32 = 4; - } - - crate::generate_storage_alias! { Prefix, Foo => Value> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedBTreeMap> } + crate::generate_storage_alias! { Prefix, Foo => Value>> } + crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedBTreeMap>> } crate::generate_storage_alias! { Prefix, - FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedBTreeMap> + FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedBTreeMap>> } fn map_from_keys(keys: &[K]) -> BTreeMap @@ -338,13 +334,13 @@ pub mod test { #[test] fn decode_len_works() { TestExternalities::default().execute_with(|| { - let bounded = boundedmap_from_keys::(&[1, 2, 3]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3]); Foo::put(bounded); assert_eq!(Foo::decode_len().unwrap(), 3); }); TestExternalities::default().execute_with(|| { - let bounded = boundedmap_from_keys::(&[1, 2, 3]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3]); FooMap::insert(1, bounded); assert_eq!(FooMap::decode_len(1).unwrap(), 3); assert!(FooMap::decode_len(0).is_none()); @@ -352,7 +348,7 @@ pub mod test { }); TestExternalities::default().execute_with(|| { - let bounded = boundedmap_from_keys::(&[1, 2, 3]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3]); FooDoubleMap::insert(1, 1, bounded); assert_eq!(FooDoubleMap::decode_len(1, 1).unwrap(), 3); assert!(FooDoubleMap::decode_len(2, 1).is_none()); @@ -363,7 +359,7 @@ pub mod test { #[test] fn try_insert_works() { - let mut bounded = boundedmap_from_keys::(&[1, 2, 3]); + let mut bounded = boundedmap_from_keys::>(&[1, 2, 3]); bounded.try_insert(0, ()).unwrap(); assert_eq!(*bounded, map_from_keys(&[1, 0, 2, 3])); @@ -373,7 +369,7 @@ pub mod test { #[test] fn deref_coercion_works() { - let bounded = boundedmap_from_keys::(&[1, 2, 3]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3]); // these methods come from deref-ed vec. assert_eq!(bounded.len(), 3); assert!(bounded.iter().next().is_some()); @@ -382,7 +378,7 @@ pub mod test { #[test] fn try_mutate_works() { - let bounded = boundedmap_from_keys::(&[1, 2, 3, 4, 5, 6]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); let bounded = bounded .try_mutate(|v| { v.insert(7, ()); @@ -398,7 +394,7 @@ pub mod test { #[test] fn btree_map_eq_works() { - let bounded = boundedmap_from_keys::(&[1, 2, 3, 4, 5, 6]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); assert_eq!(bounded, map_from_keys(&[1, 2, 3, 4, 5, 6])); } @@ -406,7 +402,7 @@ pub mod test { fn too_big_fail_to_decode() { let v: Vec<(u32, u32)> = vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]; assert_eq!( - BoundedBTreeMap::::decode(&mut &v.encode()[..]), + BoundedBTreeMap::>::decode(&mut &v.encode()[..]), Err("BoundedBTreeMap exceeds its limit".into()), ); } @@ -436,7 +432,7 @@ pub mod test { } } - let mut map = BoundedBTreeMap::::new(); + let mut map = BoundedBTreeMap::>::new(); // when the set is full diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index ecfb0bdbd261f..af292aa1c8ffe 100644 --- a/frame/support/src/storage/bounded_btree_set.rs +++ b/frame/support/src/storage/bounded_btree_set.rs @@ -287,19 +287,15 @@ impl codec::EncodeLike> for BoundedBTreeSet where BTreeS pub mod test { use super::*; use crate::Twox128; + use frame_support::traits::ConstU32; use sp_io::TestExternalities; use sp_std::convert::TryInto; - crate::parameter_types! { - pub const Seven: u32 = 7; - pub const Four: u32 = 4; - } - - crate::generate_storage_alias! { Prefix, Foo => Value> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedBTreeSet> } + crate::generate_storage_alias! { Prefix, Foo => Value>> } + crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedBTreeSet>> } crate::generate_storage_alias! { Prefix, - FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedBTreeSet> + FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedBTreeSet>> } fn map_from_keys(keys: &[T]) -> BTreeSet @@ -320,13 +316,13 @@ pub mod test { #[test] fn decode_len_works() { TestExternalities::default().execute_with(|| { - let bounded = boundedmap_from_keys::(&[1, 2, 3]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3]); Foo::put(bounded); assert_eq!(Foo::decode_len().unwrap(), 3); }); TestExternalities::default().execute_with(|| { - let bounded = boundedmap_from_keys::(&[1, 2, 3]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3]); FooMap::insert(1, bounded); assert_eq!(FooMap::decode_len(1).unwrap(), 3); assert!(FooMap::decode_len(0).is_none()); @@ -334,7 +330,7 @@ pub mod test { }); TestExternalities::default().execute_with(|| { - let bounded = boundedmap_from_keys::(&[1, 2, 3]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3]); FooDoubleMap::insert(1, 1, bounded); assert_eq!(FooDoubleMap::decode_len(1, 1).unwrap(), 3); assert!(FooDoubleMap::decode_len(2, 1).is_none()); @@ -345,7 +341,7 @@ pub mod test { #[test] fn try_insert_works() { - let mut bounded = boundedmap_from_keys::(&[1, 2, 3]); + let mut bounded = boundedmap_from_keys::>(&[1, 2, 3]); bounded.try_insert(0).unwrap(); assert_eq!(*bounded, map_from_keys(&[1, 0, 2, 3])); @@ -355,7 +351,7 @@ pub mod test { #[test] fn deref_coercion_works() { - let bounded = boundedmap_from_keys::(&[1, 2, 3]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3]); // these methods come from deref-ed vec. assert_eq!(bounded.len(), 3); assert!(bounded.iter().next().is_some()); @@ -364,7 +360,7 @@ pub mod test { #[test] fn try_mutate_works() { - let bounded = boundedmap_from_keys::(&[1, 2, 3, 4, 5, 6]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); let bounded = bounded .try_mutate(|v| { v.insert(7); @@ -380,7 +376,7 @@ pub mod test { #[test] fn btree_map_eq_works() { - let bounded = boundedmap_from_keys::(&[1, 2, 3, 4, 5, 6]); + let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); assert_eq!(bounded, map_from_keys(&[1, 2, 3, 4, 5, 6])); } @@ -388,7 +384,7 @@ pub mod test { fn too_big_fail_to_decode() { let v: Vec = vec![1, 2, 3, 4, 5]; assert_eq!( - BoundedBTreeSet::::decode(&mut &v.encode()[..]), + BoundedBTreeSet::>::decode(&mut &v.encode()[..]), Err("BoundedBTreeSet exceeds its limit".into()), ); } @@ -418,7 +414,7 @@ pub mod test { } } - let mut set = BoundedBTreeSet::::new(); + let mut set = BoundedBTreeSet::>::new(); // when the set is full diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index b9ece89bff284..decf2cb341bf8 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -348,35 +348,31 @@ where pub mod test { use super::*; use crate::Twox128; + use frame_support::traits::ConstU32; use sp_io::TestExternalities; - crate::parameter_types! { - pub const Seven: u32 = 7; - pub const Four: u32 = 4; - } - - crate::generate_storage_alias! { Prefix, Foo => Value> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedVec> } + crate::generate_storage_alias! { Prefix, Foo => Value>> } + crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedVec>> } crate::generate_storage_alias! { Prefix, - FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedVec> + FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedVec>> } #[test] fn try_append_is_correct() { - assert_eq!(BoundedVec::::bound(), 7); + assert_eq!(BoundedVec::>::bound(), 7); } #[test] fn decode_len_works() { TestExternalities::default().execute_with(|| { - let bounded: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); Foo::put(bounded); assert_eq!(Foo::decode_len().unwrap(), 3); }); TestExternalities::default().execute_with(|| { - let bounded: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); FooMap::insert(1, bounded); assert_eq!(FooMap::decode_len(1).unwrap(), 3); assert!(FooMap::decode_len(0).is_none()); @@ -384,7 +380,7 @@ pub mod test { }); TestExternalities::default().execute_with(|| { - let bounded: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); FooDoubleMap::insert(1, 1, bounded); assert_eq!(FooDoubleMap::decode_len(1, 1).unwrap(), 3); assert!(FooDoubleMap::decode_len(2, 1).is_none()); @@ -395,7 +391,7 @@ pub mod test { #[test] fn try_insert_works() { - let mut bounded: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let mut bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); bounded.try_insert(1, 0).unwrap(); assert_eq!(*bounded, vec![1, 0, 2, 3]); @@ -406,13 +402,13 @@ pub mod test { #[test] #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] fn try_inert_panics_if_oob() { - let mut bounded: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let mut bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); bounded.try_insert(9, 0).unwrap(); } #[test] fn try_push_works() { - let mut bounded: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let mut bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); bounded.try_push(0).unwrap(); assert_eq!(*bounded, vec![1, 2, 3, 0]); @@ -421,7 +417,7 @@ pub mod test { #[test] fn deref_coercion_works() { - let bounded: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); // these methods come from deref-ed vec. assert_eq!(bounded.len(), 3); assert!(bounded.iter().next().is_some()); @@ -430,7 +426,7 @@ pub mod test { #[test] fn try_mutate_works() { - let bounded: BoundedVec = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + let bounded: BoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); let bounded = bounded.try_mutate(|v| v.push(7)).unwrap(); assert_eq!(bounded.len(), 7); assert!(bounded.try_mutate(|v| v.push(8)).is_none()); @@ -438,13 +434,13 @@ pub mod test { #[test] fn slice_indexing_works() { - let bounded: BoundedVec = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + let bounded: BoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); assert_eq!(&bounded[0..=2], &[1, 2, 3]); } #[test] fn vec_eq_works() { - let bounded: BoundedVec = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + let bounded: BoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); assert_eq!(bounded, vec![1, 2, 3, 4, 5, 6]); } @@ -452,7 +448,7 @@ pub mod test { fn too_big_vec_fail_to_decode() { let v: Vec = vec![1, 2, 3, 4, 5]; assert_eq!( - BoundedVec::::decode(&mut &v.encode()[..]), + BoundedVec::>::decode(&mut &v.encode()[..]), Err("BoundedVec exceeds its limit".into()), ); } diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 9217cf4e6d9e4..3cfe2bfaa577a 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -1404,6 +1404,7 @@ mod test { use super::*; use crate::{assert_ok, hash::Identity, Twox128}; use bounded_vec::BoundedVec; + use frame_support::traits::ConstU32; use generator::StorageValue as _; use sp_core::hashing::twox_128; use sp_io::TestExternalities; @@ -1714,22 +1715,17 @@ mod test { }); } - crate::parameter_types! { - pub const Seven: u32 = 7; - pub const Four: u32 = 4; - } - - crate::generate_storage_alias! { Prefix, Foo => Value> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedVec> } + crate::generate_storage_alias! { Prefix, Foo => Value>> } + crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedVec>> } crate::generate_storage_alias! { Prefix, - FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedVec> + FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedVec>> } #[test] fn try_append_works() { TestExternalities::default().execute_with(|| { - let bounded: WeakBoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); Foo::put(bounded); assert_ok!(Foo::try_append(4)); assert_ok!(Foo::try_append(5)); @@ -1740,7 +1736,7 @@ mod test { }); TestExternalities::default().execute_with(|| { - let bounded: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); FooMap::insert(1, bounded); assert_ok!(FooMap::try_append(1, 4)); @@ -1755,17 +1751,17 @@ mod test { assert_ok!(FooMap::try_append(2, 4)); assert_eq!( FooMap::get(2).unwrap(), - BoundedVec::::try_from(vec![4]).unwrap(), + BoundedVec::>::try_from(vec![4]).unwrap(), ); assert_ok!(FooMap::try_append(2, 5)); assert_eq!( FooMap::get(2).unwrap(), - BoundedVec::::try_from(vec![4, 5]).unwrap(), + BoundedVec::>::try_from(vec![4, 5]).unwrap(), ); }); TestExternalities::default().execute_with(|| { - let bounded: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); FooDoubleMap::insert(1, 1, bounded); assert_ok!(FooDoubleMap::try_append(1, 1, 4)); @@ -1780,12 +1776,12 @@ mod test { assert_ok!(FooDoubleMap::try_append(2, 1, 4)); assert_eq!( FooDoubleMap::get(2, 1).unwrap(), - BoundedVec::::try_from(vec![4]).unwrap(), + BoundedVec::>::try_from(vec![4]).unwrap(), ); assert_ok!(FooDoubleMap::try_append(2, 1, 5)); assert_eq!( FooDoubleMap::get(2, 1).unwrap(), - BoundedVec::::try_from(vec![4, 5]).unwrap(), + BoundedVec::>::try_from(vec![4, 5]).unwrap(), ); }); } diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 566889f5f192c..641b623053939 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -318,36 +318,32 @@ where pub mod test { use super::*; use crate::Twox128; + use frame_support::traits::ConstU32; use sp_io::TestExternalities; use sp_std::convert::TryInto; - crate::parameter_types! { - pub const Seven: u32 = 7; - pub const Four: u32 = 4; - } - - crate::generate_storage_alias! { Prefix, Foo => Value> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), WeakBoundedVec> } + crate::generate_storage_alias! { Prefix, Foo => Value>> } + crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), WeakBoundedVec>> } crate::generate_storage_alias! { Prefix, - FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), WeakBoundedVec> + FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), WeakBoundedVec>> } #[test] fn try_append_is_correct() { - assert_eq!(WeakBoundedVec::::bound(), 7); + assert_eq!(WeakBoundedVec::>::bound(), 7); } #[test] fn decode_len_works() { TestExternalities::default().execute_with(|| { - let bounded: WeakBoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); Foo::put(bounded); assert_eq!(Foo::decode_len().unwrap(), 3); }); TestExternalities::default().execute_with(|| { - let bounded: WeakBoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); FooMap::insert(1, bounded); assert_eq!(FooMap::decode_len(1).unwrap(), 3); assert!(FooMap::decode_len(0).is_none()); @@ -355,7 +351,7 @@ pub mod test { }); TestExternalities::default().execute_with(|| { - let bounded: WeakBoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); FooDoubleMap::insert(1, 1, bounded); assert_eq!(FooDoubleMap::decode_len(1, 1).unwrap(), 3); assert!(FooDoubleMap::decode_len(2, 1).is_none()); @@ -366,7 +362,7 @@ pub mod test { #[test] fn try_insert_works() { - let mut bounded: WeakBoundedVec = vec![1, 2, 3].try_into().unwrap(); + let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); bounded.try_insert(1, 0).unwrap(); assert_eq!(*bounded, vec![1, 0, 2, 3]); @@ -377,13 +373,13 @@ pub mod test { #[test] #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] fn try_inert_panics_if_oob() { - let mut bounded: WeakBoundedVec = vec![1, 2, 3].try_into().unwrap(); + let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); bounded.try_insert(9, 0).unwrap(); } #[test] fn try_push_works() { - let mut bounded: WeakBoundedVec = vec![1, 2, 3].try_into().unwrap(); + let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); bounded.try_push(0).unwrap(); assert_eq!(*bounded, vec![1, 2, 3, 0]); @@ -392,7 +388,7 @@ pub mod test { #[test] fn deref_coercion_works() { - let bounded: WeakBoundedVec = vec![1, 2, 3].try_into().unwrap(); + let bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); // these methods come from deref-ed vec. assert_eq!(bounded.len(), 3); assert!(bounded.iter().next().is_some()); @@ -401,7 +397,7 @@ pub mod test { #[test] fn try_mutate_works() { - let bounded: WeakBoundedVec = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); let bounded = bounded.try_mutate(|v| v.push(7)).unwrap(); assert_eq!(bounded.len(), 7); assert!(bounded.try_mutate(|v| v.push(8)).is_none()); @@ -409,20 +405,20 @@ pub mod test { #[test] fn slice_indexing_works() { - let bounded: WeakBoundedVec = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); assert_eq!(&bounded[0..=2], &[1, 2, 3]); } #[test] fn vec_eq_works() { - let bounded: WeakBoundedVec = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); assert_eq!(bounded, vec![1, 2, 3, 4, 5, 6]); } #[test] fn too_big_succeed_to_decode() { let v: Vec = vec![1, 2, 3, 4, 5]; - let w = WeakBoundedVec::::decode(&mut &v.encode()[..]).unwrap(); + let w = WeakBoundedVec::>::decode(&mut &v.encode()[..]).unwrap(); assert_eq!(v, *w); } } diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index 06fb6345d3c8d..a5586996215e9 100644 --- a/frame/support/test/compile_pass/src/lib.rs +++ b/frame/support/test/compile_pass/src/lib.rs @@ -22,7 +22,10 @@ //! This crate tests that `construct_runtime!` expands the pallet parts //! correctly even when frame-support is renamed in Cargo.toml -use frame_support::{construct_runtime, parameter_types}; +use frame_support::{ + construct_runtime, parameter_types, + traits::{ConstU16, ConstU32}, +}; use sp_core::{sr25519, H256}; use sp_runtime::{ create_runtime_str, generic, @@ -48,7 +51,6 @@ pub type Index = u64; parameter_types! { pub const BlockHashCount: BlockNumber = 2400; pub const Version: RuntimeVersion = VERSION; - pub const SS58Prefix: u8 = 0; } impl frame_system::Config for Runtime { @@ -73,9 +75,9 @@ impl frame_system::Config for Runtime { type OnNewAccount = (); type OnKilledAccount = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; type SystemWeightInfo = (); - type SS58Prefix = SS58Prefix; + type SS58Prefix = ConstU16<0>; } pub type Header = generic::Header; diff --git a/frame/support/test/tests/instance.rs b/frame/support/test/tests/instance.rs index 809edae14f80c..5677b9ac14da6 100644 --- a/frame/support/test/tests/instance.rs +++ b/frame/support/test/tests/instance.rs @@ -24,8 +24,7 @@ use frame_support::{ PalletStorageMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, StorageHasher, }, - parameter_types, - traits::Get, + traits::{ConstU32, Get}, Parameter, StorageDoubleMap, StorageMap, StorageValue, }; use scale_info::TypeInfo; @@ -229,20 +228,16 @@ mod module3 { } } -parameter_types! { - pub const SomeValue: u32 = 100; -} - impl module1::Config for Runtime { type Event = Event; type Origin = Origin; - type SomeParameter = SomeValue; + type SomeParameter = ConstU32<100>; type GenericType = u32; } impl module1::Config for Runtime { type Event = Event; type Origin = Origin; - type SomeParameter = SomeValue; + type SomeParameter = ConstU32<100>; type GenericType = u32; } impl module2::Config for Runtime { diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index e9c6fe8be5601..e57c3466e7ef0 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -19,8 +19,8 @@ use frame_support::{ dispatch::{Parameter, UnfilteredDispatchable}, storage::unhashed, traits::{ - GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade, - PalletInfoAccess, StorageVersion, + ConstU32, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, + OnRuntimeUpgrade, PalletInfoAccess, StorageVersion, }, weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, RuntimeDbWeight}, }; @@ -536,10 +536,7 @@ pub mod pallet4 { } frame_support::parameter_types!( - pub const MyGetParam: u32 = 10; - pub const MyGetParam2: u32 = 11; pub const MyGetParam3: u32 = 12; - pub const BlockHashCount: u32 = 250; ); impl frame_system::Config for Runtime { @@ -554,7 +551,7 @@ impl frame_system::Config for Runtime { type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU32<250>; type BlockWeights = (); type BlockLength = (); type DbWeight = (); @@ -566,12 +563,12 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; - type MyGetParam = MyGetParam; - type MyGetParam2 = MyGetParam2; + type MyGetParam = ConstU32<10>; + type MyGetParam2 = ConstU32<11>; type MyGetParam3 = MyGetParam3; type Balance = u64; } diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index 0cd6a6e59cffc..b1ed08051f247 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use frame_support::traits::{ConstU32, ConstU64}; + pub trait SomeAssociation { type A: frame_support::dispatch::Parameter + Default; } @@ -217,11 +219,6 @@ pub mod pallet { } } -frame_support::parameter_types!( - pub const SomeConst: u64 = 10; - pub const BlockHashCount: u32 = 250; -); - impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Origin = Origin; @@ -234,7 +231,7 @@ impl frame_system::Config for Runtime { type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU32<250>; type BlockWeights = (); type BlockLength = (); type DbWeight = (); @@ -246,16 +243,16 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; - type SomeConst = SomeConst; + type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { type Event = Event; - type SomeConst = SomeConst; + type SomeConst = ConstU64<10>; type Balance = u64; } diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 16f5e16cb873e..81e16ee3624f3 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use frame_support::traits::{ConstU32, ConstU64}; + mod pallet_old { use frame_support::{ decl_error, decl_event, decl_module, decl_storage, traits::Get, weights::Weight, Parameter, @@ -197,11 +199,6 @@ pub mod pallet { } } -frame_support::parameter_types!( - pub const SomeConst: u64 = 10; - pub const BlockHashCount: u32 = 250; -); - impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); @@ -217,7 +214,7 @@ impl frame_system::Config for Runtime { type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU32<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -226,36 +223,36 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; - type SomeConst = SomeConst; + type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet::Config for Runtime { type Event = Event; - type SomeConst = SomeConst; + type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet::Config for Runtime { type Event = Event; - type SomeConst = SomeConst; + type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { type Event = Event; - type SomeConst = SomeConst; + type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { type Event = Event; - type SomeConst = SomeConst; + type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { type Event = Event; - type SomeConst = SomeConst; + type SomeConst = ConstU64<10>; type Balance = u64; } diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 9fd748eb332c3..740bfe51d439d 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -18,7 +18,7 @@ use frame_support::{ dispatch::UnfilteredDispatchable, storage::unhashed, - traits::{GetCallName, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade}, + traits::{ConstU32, GetCallName, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade}, weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, }; use sp_io::{ @@ -245,11 +245,6 @@ pub mod pallet2 { } } -frame_support::parameter_types!( - pub const MyGetParam: u32 = 10; - pub const BlockHashCount: u32 = 250; -); - impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Origin = Origin; @@ -262,7 +257,7 @@ impl frame_system::Config for Runtime { type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU32<250>; type BlockWeights = (); type BlockLength = (); type DbWeight = (); @@ -274,16 +269,16 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; - type MyGetParam = MyGetParam; + type MyGetParam = ConstU32<10>; type Balance = u64; } impl pallet::Config for Runtime { type Event = Event; - type MyGetParam = MyGetParam; + type MyGetParam = ConstU32<10>; type Balance = u64; } impl pallet2::Config for Runtime { diff --git a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs index 170e515740b3c..128960fdb1c3d 100644 --- a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs +++ b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs @@ -97,7 +97,7 @@ impl frame_support::inherent::ProvideInherent for Module { mod tests { use crate as pallet_test; - use frame_support::parameter_types; + use frame_support::traits::ConstU64; type SignedExtra = ( frame_system::CheckEra, @@ -124,10 +124,6 @@ mod tests { } ); - parameter_types! { - pub const BlockHashCount: u64 = 250; - } - impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Origin = Origin; @@ -140,7 +136,7 @@ mod tests { type Lookup = sp_runtime::traits::IdentityLookup; type Header = TestHeader; type Event = (); - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type DbWeight = (); type BlockWeights = (); type BlockLength = (); diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index 0d513ff599d53..f1d819cb6525a 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -16,6 +16,7 @@ // limitations under the License. use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use frame_support::traits::{ConstU32, ConstU64}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -58,7 +59,6 @@ frame_support::construct_runtime!( ); frame_support::parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::with_sensible_defaults( 4 * 1024 * 1024, Perbill::from_percent(75), @@ -83,7 +83,7 @@ impl frame_system::Config for Runtime { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -92,7 +92,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl module::Config for Runtime { diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index de89324ec9fb4..d8d9e7323aed6 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -16,7 +16,10 @@ // limitations under the License. use crate::{self as frame_system, *}; -use frame_support::parameter_types; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, +}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -42,7 +45,6 @@ const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); const MAX_BLOCK_WEIGHT: Weight = 1024; parameter_types! { - pub const BlockHashCount: u64 = 10; pub Version: RuntimeVersion = RuntimeVersion { spec_name: sp_version::create_runtime_str!("test"), impl_name: sp_version::create_runtime_str!("system-test"), @@ -101,7 +103,7 @@ impl Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<10>; type DbWeight = DbWeight; type Version = Version; type PalletInfo = PalletInfo; @@ -111,7 +113,7 @@ impl Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } pub type SysEvent = frame_system::Event; diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index ae9a3b5f69ad9..0d2c3f385d170 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -316,7 +316,10 @@ mod tests { use super::*; use crate as pallet_timestamp; - use frame_support::{assert_ok, parameter_types}; + use frame_support::{ + assert_ok, parameter_types, + traits::{ConstU32, ConstU64}, + }; use sp_core::H256; use sp_io::TestExternalities; use sp_runtime::{ @@ -344,7 +347,6 @@ mod tests { ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -363,7 +365,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -372,15 +374,13 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - parameter_types! { - pub const MinimumPeriod: u64 = 5; + type MaxConsumers = ConstU32<16>; } + impl Config for Test { type Moment = u64; type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<5>; type WeightInfo = (); } diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index 7d6a717347310..5bab523b0393b 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -30,8 +30,12 @@ use sp_runtime::{ use sp_storage::Storage; use frame_support::{ - assert_noop, assert_ok, pallet_prelude::GenesisBuild, parameter_types, - storage::StoragePrefixedMap, traits::SortedMembers, weights::Weight, PalletId, + assert_noop, assert_ok, + pallet_prelude::GenesisBuild, + parameter_types, + storage::StoragePrefixedMap, + traits::{ConstU32, ConstU64, SortedMembers}, + PalletId, }; use super::*; @@ -54,9 +58,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: Weight = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl frame_system::Config for Test { @@ -74,7 +75,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -83,11 +84,9 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -95,7 +94,7 @@ impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } @@ -126,13 +125,8 @@ impl ContainsLengthBound for TenToFourteen { } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); - pub const ProposalBondMinimum: u64 = 1; - pub const SpendPeriod: u64 = 2; pub const Burn: Permill = Permill::from_percent(50); - pub const DataDepositPerByte: u64 = 1; pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - pub const MaximumReasonLength: u32 = 16384; - pub const MaxApprovals: u32 = 100; } impl pallet_treasury::Config for Test { type PalletId = TreasuryPalletId; @@ -142,26 +136,24 @@ impl pallet_treasury::Config for Test { type Event = Event; type OnSlash = (); type ProposalBond = ProposalBond; - type ProposalBondMinimum = ProposalBondMinimum; - type SpendPeriod = SpendPeriod; + type ProposalBondMinimum = ConstU64<1>; + type SpendPeriod = ConstU64<2>; type Burn = Burn; type BurnDestination = (); // Just gets burned. type WeightInfo = (); type SpendFunds = (); - type MaxApprovals = MaxApprovals; + type MaxApprovals = ConstU32<100>; } parameter_types! { - pub const TipCountdown: u64 = 1; pub const TipFindersFee: Percent = Percent::from_percent(20); - pub const TipReportDepositBase: u64 = 1; } impl Config for Test { - type MaximumReasonLength = MaximumReasonLength; + type MaximumReasonLength = ConstU32<16384>; type Tippers = TenToFourteen; - type TipCountdown = TipCountdown; + type TipCountdown = ConstU64<1>; type TipFindersFee = TipFindersFee; - type TipReportDepositBase = TipReportDepositBase; - type DataDepositPerByte = DataDepositPerByte; + type TipReportDepositBase = ConstU64<1>; + type DataDepositPerByte = ConstU64<1>; type Event = Event; type WeightInfo = (); } diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index c6c60cfe237d5..6292829d21483 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -20,7 +20,7 @@ use frame_support::{ assert_ok, pallet_prelude::*, parameter_types, - traits::{fungibles::Mutate, FindAuthor}, + traits::{fungibles::Mutate, ConstU32, ConstU64, ConstU8, FindAuthor}, weights::{ DispatchClass, DispatchInfo, PostDispatchInfo, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, @@ -83,7 +83,6 @@ impl Get for BlockWeights { } parameter_types! { - pub const BlockHashCount: u64 = 250; pub static TransactionByteFee: u64 = 1; pub static WeightToFee: u64 = 1; } @@ -103,7 +102,7 @@ impl frame_system::Config for Runtime { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -112,23 +111,22 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 10; - pub const MaxReserves: u32 = 50; } impl pallet_balances::Config for Runtime { type Balance = Balance; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<10>; type AccountStore = System; type MaxLocks = (); type WeightInfo = (); - type MaxReserves = MaxReserves; + type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; } @@ -145,22 +143,12 @@ impl WeightToFeePolynomial for WeightToFee { } } -parameter_types! { - pub const OperationalFeeMultiplier: u8 = 5; -} - impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; type TransactionByteFee = TransactionByteFee; type WeightToFee = WeightToFee; type FeeMultiplierUpdate = (); - type OperationalFeeMultiplier = OperationalFeeMultiplier; -} - -parameter_types! { - pub const AssetDeposit: u64 = 2; - pub const MetadataDeposit: u64 = 0; - pub const StringLimit: u32 = 20; + type OperationalFeeMultiplier = ConstU8<5>; } impl pallet_assets::Config for Runtime { @@ -169,12 +157,12 @@ impl pallet_assets::Config for Runtime { type AssetId = u32; type Currency = Balances; type ForceOrigin = EnsureRoot; - type AssetDeposit = AssetDeposit; - type AssetAccountDeposit = frame_support::traits::ConstU64<2>; - type MetadataDepositBase = MetadataDeposit; - type MetadataDepositPerByte = MetadataDeposit; - type ApprovalDeposit = MetadataDeposit; - type StringLimit = StringLimit; + type AssetDeposit = ConstU64<2>; + type AssetAccountDeposit = ConstU64<2>; + type MetadataDepositBase = ConstU64<0>; + type MetadataDepositPerByte = ConstU64<0>; + type ApprovalDeposit = ConstU64<0>; + type StringLimit = ConstU32<20>; type Freezer = (); type Extra = (); type WeightInfo = (); diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index c7ccdafc78283..fa8b0e9be0c1c 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -789,7 +789,7 @@ mod tests { use frame_support::{ assert_noop, assert_ok, parameter_types, - traits::{Currency, Imbalance, OnUnbalanced}, + traits::{ConstU32, ConstU64, Currency, Imbalance, OnUnbalanced}, weights::{ DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, @@ -836,7 +836,6 @@ mod tests { } parameter_types! { - pub const BlockHashCount: u64 = 250; pub static TransactionByteFee: u64 = 1; pub static WeightToFee: u64 = 1; pub static OperationalFeeMultiplier: u8 = 5; @@ -857,7 +856,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -866,18 +865,14 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - - parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Runtime { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type MaxLocks = (); type MaxReserves = (); diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs index 49b81348e7d4f..6356312ca5008 100644 --- a/frame/transaction-storage/src/mock.rs +++ b/frame/transaction-storage/src/mock.rs @@ -19,10 +19,7 @@ use crate as pallet_transaction_storage; use crate::TransactionStorageProof; -use frame_support::{ - parameter_types, - traits::{OnFinalize, OnInitialize}, -}; +use frame_support::traits::{ConstU16, ConstU32, ConstU64, OnFinalize, OnInitialize}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -48,11 +45,6 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; -} - impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -67,7 +59,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; @@ -75,20 +67,16 @@ impl frame_system::Config for Test { type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); - type SS58Prefix = SS58Prefix; + type SS58Prefix = ConstU16<42>; type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); type MaxLocks = (); diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index c2b41e7165234..765f71f5dae82 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -28,7 +28,10 @@ use sp_runtime::{ }; use frame_support::{ - assert_noop, assert_ok, pallet_prelude::GenesisBuild, parameter_types, traits::OnInitialize, + assert_noop, assert_ok, + pallet_prelude::GenesisBuild, + parameter_types, + traits::{ConstU32, ConstU64, OnInitialize}, PalletId, }; @@ -51,7 +54,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -70,7 +72,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -79,10 +81,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { type MaxLocks = (); @@ -91,7 +90,7 @@ impl pallet_balances::Config for Test { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } @@ -100,8 +99,6 @@ thread_local! { } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); - pub const ProposalBondMinimum: u64 = 1; - pub const SpendPeriod: u64 = 2; pub const Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); pub const BountyUpdatePeriod: u32 = 20; @@ -117,8 +114,8 @@ impl Config for Test { type Event = Event; type OnSlash = (); type ProposalBond = ProposalBond; - type ProposalBondMinimum = ProposalBondMinimum; - type SpendPeriod = SpendPeriod; + type ProposalBondMinimum = ConstU64<1>; + type SpendPeriod = ConstU64<2>; type Burn = Burn; type BurnDestination = (); // Just gets burned. type WeightInfo = (); diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index f65f69209b9ed..679adf0424cf4 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -20,7 +20,10 @@ use super::*; use crate as pallet_uniques; -use frame_support::{construct_runtime, parameter_types}; +use frame_support::{ + construct_runtime, + traits::{ConstU32, ConstU64}, +}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -42,9 +45,6 @@ construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -59,7 +59,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; @@ -69,51 +69,35 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 1; - pub const MaxReserves: u32 = 50; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); type MaxLocks = (); - type MaxReserves = MaxReserves; + type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; } -parameter_types! { - pub const ClassDeposit: u64 = 2; - pub const InstanceDeposit: u64 = 1; - pub const KeyLimit: u32 = 50; - pub const ValueLimit: u32 = 50; - pub const StringLimit: u32 = 50; - pub const MetadataDepositBase: u64 = 1; - pub const AttributeDepositBase: u64 = 1; - pub const MetadataDepositPerByte: u64 = 1; -} - impl Config for Test { type Event = Event; type ClassId = u32; type InstanceId = u32; type Currency = Balances; type ForceOrigin = frame_system::EnsureRoot; - type ClassDeposit = ClassDeposit; - type InstanceDeposit = InstanceDeposit; - type MetadataDepositBase = MetadataDepositBase; - type AttributeDepositBase = AttributeDepositBase; - type DepositPerByte = MetadataDepositPerByte; - type StringLimit = StringLimit; - type KeyLimit = KeyLimit; - type ValueLimit = ValueLimit; + type ClassDeposit = ConstU64<2>; + type InstanceDeposit = ConstU64<1>; + type MetadataDepositBase = ConstU64<1>; + type AttributeDepositBase = ConstU64<1>; + type DepositPerByte = ConstU64<1>; + type StringLimit = ConstU32<50>; + type KeyLimit = ConstU32<50>; + type ValueLimit = ConstU32<50>; type WeightInfo = (); } diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 169ac6cfff897..11b63254eb40b 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -26,7 +26,7 @@ use frame_support::{ assert_err_ignore_postinfo, assert_noop, assert_ok, dispatch::{DispatchError, DispatchErrorWithPostInfo, Dispatchable}, parameter_types, storage, - traits::Contains, + traits::{ConstU32, ConstU64, Contains}, weights::{Pays, Weight}, }; use sp_core::H256; @@ -99,7 +99,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(Weight::max_value()); } @@ -118,7 +117,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -127,11 +126,9 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<16>; } + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -139,7 +136,7 @@ impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index 1e04875a7e077..2176716bf3405 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -15,7 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::parameter_types; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, +}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -41,7 +44,6 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -49,7 +51,7 @@ impl frame_system::Config for Test { type AccountData = pallet_balances::AccountData; type AccountId = u64; type BaseCallFilter = frame_support::traits::Everything; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type BlockLength = (); type BlockNumber = u64; type BlockWeights = (); @@ -71,16 +73,14 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type Version = (); } -parameter_types! { - pub const MaxLocks: u32 = 10; -} + impl pallet_balances::Config for Test { type AccountStore = System; type Balance = u64; type DustRemoval = (); type Event = Event; type ExistentialDeposit = ExistentialDeposit; - type MaxLocks = MaxLocks; + type MaxLocks = ConstU32<10>; type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 7b78880c2c3bf..03e39be324e90 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -38,7 +38,7 @@ use trie_db::{Trie, TrieMut}; use cfg_if::cfg_if; use frame_support::{ parameter_types, - traits::{CrateVersion, KeyOwnerProofSystem}, + traits::{ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem}, weights::RuntimeDbWeight, }; use frame_system::limits::{BlockLength, BlockWeights}; @@ -556,7 +556,6 @@ impl frame_support::traits::PalletInfo for Runtime { parameter_types! { pub const BlockHashCount: BlockNumber = 2400; - pub const MinimumPeriod: u64 = 5; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 100, write: 1000, @@ -591,26 +590,24 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<5>; type WeightInfo = (); } parameter_types! { pub const EpochDuration: u64 = 6; - pub const ExpectedBlockTime: u64 = 10_000; - pub const MaxAuthorities: u32 = 10; } impl pallet_babe::Config for Runtime { type EpochDuration = EpochDuration; - type ExpectedBlockTime = ExpectedBlockTime; + type ExpectedBlockTime = ConstU64<10_000>; // there is no actual runtime in this test-runtime, so testing crates // are manually adding the digests. normally in this situation you'd use // pallet_babe::SameAuthoritiesForever. @@ -630,7 +627,7 @@ impl pallet_babe::Config for Runtime { type HandleEquivocation = (); type WeightInfo = (); - type MaxAuthorities = MaxAuthorities; + type MaxAuthorities = ConstU32<10>; } /// Adds one to the given input and returns the final result. From 7f68a8be62433949f04abc3ab9d98a10dab95c7d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 16 Dec 2021 07:24:28 +0100 Subject: [PATCH 0347/1472] move generics of election trait to associated types (#10475) * move generics of election trait to associated types * fix doctest --- frame/bags-list/remote-tests/src/snapshot.rs | 7 +- .../src/benchmarking.rs | 2 +- .../election-provider-multi-phase/src/lib.rs | 26 +++--- .../election-provider-multi-phase/src/mock.rs | 8 +- frame/election-provider-support/src/lib.rs | 81 +++++++++++++------ .../election-provider-support/src/onchain.rs | 13 ++- frame/staking/src/pallet/impls.rs | 4 +- frame/staking/src/pallet/mod.rs | 8 +- frame/staking/src/tests.rs | 6 +- 9 files changed, 101 insertions(+), 54 deletions(-) diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index f05c00cd9a244..78f462e55b8f6 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -55,11 +55,8 @@ pub async fn execute ::SortedListProvider::count(), ); - let voters = as ElectionDataProvider< - Runtime::AccountId, - Runtime::BlockNumber, - >>::voters(voter_limit) - .unwrap(); + let voters = + as ElectionDataProvider>::voters(voter_limit).unwrap(); let mut voters_nominator_only = voters .iter() diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 1e0d3b1e9325a..04101f886cecf 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -289,7 +289,7 @@ frame_benchmarking::benchmarks! { assert!(>::get().is_some()); assert!(>::get().is_some()); }: { - assert_ok!( as ElectionProvider>::elect()); + assert_ok!( as ElectionProvider>::elect()); } verify { assert!(>::queued_solution().is_none()); assert!(>::get().is_none()); diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 70668dbe9f67a..175de0eeb0c69 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -139,7 +139,7 @@ //! To generate an emergency solution, one must only provide one argument: [`Supports`]. This is //! essentially a collection of elected winners for the election, and voters who support them. The //! supports can be generated by any means. In the simplest case, it could be manual. For example, -//! in the case of massive network failure or misbehaviour, [`Config::ForceOrigin`] might decide to +//! in the case of massive network failure or misbehavior, [`Config::ForceOrigin`] might decide to //! select only a small number of emergency winners (which would greatly restrict the next validator //! set, if this pallet is used with `pallet-staking`). If the failure is for other technical //! reasons, then a simple and safe way to generate supports is using the staking-miner binary @@ -286,10 +286,7 @@ pub type SolutionTargetIndexOf = as NposSolution>::TargetIndex /// The accuracy of the election, when submitted from offchain. Derived from [`SolutionOf`]. pub type SolutionAccuracyOf = as NposSolution>::Accuracy; /// The fallback election type. -pub type FallbackErrorOf = <::Fallback as ElectionProvider< - ::AccountId, - ::BlockNumber, ->>::Error; +pub type FallbackErrorOf = <::Fallback as ElectionProvider>::Error; /// Configuration for the benchmarks of the pallet. pub trait BenchmarkingConfig { @@ -312,7 +309,9 @@ pub trait BenchmarkingConfig { /// A fallback implementation that transitions the pallet to the emergency phase. pub struct NoFallback(sp_std::marker::PhantomData); -impl ElectionProvider for NoFallback { +impl ElectionProvider for NoFallback { + type AccountId = T::AccountId; + type BlockNumber = T::BlockNumber; type DataProvider = T::DataProvider; type Error = &'static str; @@ -654,7 +653,10 @@ pub mod pallet { type MinerMaxLength: Get; /// Something that will provide the election data. - type DataProvider: ElectionDataProvider; + type DataProvider: ElectionDataProvider< + AccountId = Self::AccountId, + BlockNumber = Self::BlockNumber, + >; /// The solution type. type Solution: codec::Codec @@ -669,8 +671,8 @@ pub mod pallet { /// Configuration for the fallback type Fallback: ElectionProvider< - Self::AccountId, - Self::BlockNumber, + AccountId = Self::AccountId, + BlockNumber = Self::BlockNumber, DataProvider = Self::DataProvider, >; @@ -818,7 +820,7 @@ pub mod pallet { // NOTE that this pallet does not really need to enforce this in runtime. The // solution cannot represent any voters more than `LIMIT` anyhow. assert_eq!( - >::MAXIMUM_VOTES_PER_VOTER, + ::MAXIMUM_VOTES_PER_VOTER, as NposSolution>::LIMIT as u32, ); } @@ -1492,7 +1494,9 @@ impl Pallet { } } -impl ElectionProvider for Pallet { +impl ElectionProvider for Pallet { + type AccountId = T::AccountId; + type BlockNumber = T::BlockNumber; type Error = ElectionError; type DataProvider = T::DataProvider; diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index d686df2a72f68..4e494322b062a 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -285,7 +285,9 @@ impl onchain::Config for Runtime { } pub struct MockFallback; -impl ElectionProvider for MockFallback { +impl ElectionProvider for MockFallback { + type AccountId = AccountId; + type BlockNumber = u64; type Error = &'static str; type DataProvider = StakingMock; @@ -438,7 +440,9 @@ pub type Extrinsic = sp_runtime::testing::TestXt; pub struct ExtBuilder {} pub struct StakingMock; -impl ElectionDataProvider for StakingMock { +impl ElectionDataProvider for StakingMock { + type AccountId = AccountId; + type BlockNumber = u64; const MAXIMUM_VOTES_PER_VOTER: u32 = ::LIMIT as u32; fn targets(maybe_max_len: Option) -> data_provider::Result> { let targets = Targets::get(); diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index ac3bfccbbdb54..a4fce64ff1d74 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -90,21 +90,24 @@ //! //! pub trait Config: Sized { //! type ElectionProvider: ElectionProvider< -//! AccountId, -//! BlockNumber, -//! DataProvider = Module, +//! AccountId = AccountId, +//! BlockNumber = BlockNumber, +//! DataProvider = Pallet, //! >; //! } //! -//! pub struct Module(std::marker::PhantomData); +//! pub struct Pallet(std::marker::PhantomData); //! -//! impl ElectionDataProvider for Module { +//! impl ElectionDataProvider for Pallet { +//! type AccountId = AccountId; +//! type BlockNumber = BlockNumber; //! const MAXIMUM_VOTES_PER_VOTER: u32 = 1; +//! //! fn desired_targets() -> data_provider::Result { //! Ok(1) //! } //! fn voters(maybe_max_len: Option) -//! -> data_provider::Result)>> +//! -> data_provider::Result)>> //! { //! Ok(Default::default()) //! } @@ -124,10 +127,12 @@ //! pub struct GenericElectionProvider(std::marker::PhantomData); //! //! pub trait Config { -//! type DataProvider: ElectionDataProvider; +//! type DataProvider: ElectionDataProvider; //! } //! -//! impl ElectionProvider for GenericElectionProvider { +//! impl ElectionProvider for GenericElectionProvider { +//! type AccountId = AccountId; +//! type BlockNumber = BlockNumber; //! type Error = &'static str; //! type DataProvider = T::DataProvider; //! @@ -146,7 +151,7 @@ //! //! struct Runtime; //! impl generic_election_provider::Config for Runtime { -//! type DataProvider = data_provider_mod::Module; +//! type DataProvider = data_provider_mod::Pallet; //! } //! //! impl data_provider_mod::Config for Runtime { @@ -178,7 +183,13 @@ pub mod data_provider { } /// Something that can provide the data to an [`ElectionProvider`]. -pub trait ElectionDataProvider { +pub trait ElectionDataProvider { + /// The account identifier type. + type AccountId; + + /// The block number type. + type BlockNumber; + /// Maximum number of votes per voter that this data provider is providing. const MAXIMUM_VOTES_PER_VOTER: u32; @@ -189,7 +200,7 @@ pub trait ElectionDataProvider { /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. - fn targets(maybe_max_len: Option) -> data_provider::Result>; + fn targets(maybe_max_len: Option) -> data_provider::Result>; /// All possible voters for the election. /// @@ -202,7 +213,7 @@ pub trait ElectionDataProvider { /// appropriate weight at the end of execution with the system pallet directly. fn voters( maybe_max_len: Option, - ) -> data_provider::Result)>>; + ) -> data_provider::Result)>>; /// The number of targets to elect. /// @@ -216,14 +227,14 @@ pub trait ElectionDataProvider { /// [`ElectionProvider::elect`]. /// /// This is only useful for stateful election providers. - fn next_election_prediction(now: BlockNumber) -> BlockNumber; + fn next_election_prediction(now: Self::BlockNumber) -> Self::BlockNumber; /// Utility function only to be used in benchmarking scenarios, to be implemented optionally, /// else a noop. #[cfg(any(feature = "runtime-benchmarks", test))] fn put_snapshot( - _voters: Vec<(AccountId, VoteWeight, Vec)>, - _targets: Vec, + _voters: Vec<(Self::AccountId, VoteWeight, Vec)>, + _targets: Vec, _target_stake: Option, ) { } @@ -233,22 +244,29 @@ pub trait ElectionDataProvider { /// /// Same as `put_snapshot`, but can add a single voter one by one. #[cfg(any(feature = "runtime-benchmarks", test))] - fn add_voter(_voter: AccountId, _weight: VoteWeight, _targets: Vec) {} + fn add_voter(_voter: Self::AccountId, _weight: VoteWeight, _targets: Vec) {} /// Utility function only to be used in benchmarking scenarios, to be implemented optionally, /// else a noop. /// /// Same as `put_snapshot`, but can add a single voter one by one. #[cfg(any(feature = "runtime-benchmarks", test))] - fn add_target(_target: AccountId) {} + fn add_target(_target: Self::AccountId) {} /// Clear all voters and targets. #[cfg(any(feature = "runtime-benchmarks", test))] fn clear() {} } +/// An election data provider that should only be used for testing. #[cfg(feature = "std")] -impl ElectionDataProvider for () { +pub struct TestDataProvider(sp_std::marker::PhantomData); + +#[cfg(feature = "std")] +impl ElectionDataProvider for TestDataProvider<(AccountId, BlockNumber)> { + type AccountId = AccountId; + type BlockNumber = BlockNumber; + const MAXIMUM_VOTES_PER_VOTER: u32 = 0; fn targets(_maybe_max_len: Option) -> data_provider::Result> { Ok(Default::default()) @@ -271,12 +289,21 @@ impl ElectionDataProvider for () /// This trait only provides an interface to _request_ an election, i.e. /// [`ElectionProvider::elect`]. That data required for the election need to be passed to the /// implemented of this trait through [`ElectionProvider::DataProvider`]. -pub trait ElectionProvider { +pub trait ElectionProvider { + /// The account identifier type. + type AccountId; + + /// The block number type. + type BlockNumber; + /// The error type that is returned by the provider. type Error: Debug; /// The data provider of the election. - type DataProvider: ElectionDataProvider; + type DataProvider: ElectionDataProvider< + AccountId = Self::AccountId, + BlockNumber = Self::BlockNumber, + >; /// Elect a new set of winners. /// @@ -284,16 +311,22 @@ pub trait ElectionProvider { /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. - fn elect() -> Result, Self::Error>; + fn elect() -> Result, Self::Error>; } +/// An election provider to be used only for testing. #[cfg(feature = "std")] -impl ElectionProvider for () { +pub struct NoElection(sp_std::marker::PhantomData); + +#[cfg(feature = "std")] +impl ElectionProvider for NoElection<(AccountId, BlockNumber)> { + type AccountId = AccountId; + type BlockNumber = BlockNumber; type Error = &'static str; - type DataProvider = (); + type DataProvider = TestDataProvider<(AccountId, BlockNumber)>; fn elect() -> Result, Self::Error> { - Err("<() as ElectionProvider> cannot do anything.") + Err(" cannot do anything.") } } diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index a2eb53edcf84c..ce15edd592add 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -62,10 +62,15 @@ pub trait Config: frame_system::Config { /// The accuracy used to compute the election: type Accuracy: PerThing128; /// Something that provides the data for election. - type DataProvider: ElectionDataProvider; + type DataProvider: ElectionDataProvider< + AccountId = Self::AccountId, + BlockNumber = Self::BlockNumber, + >; } -impl ElectionProvider for OnChainSequentialPhragmen { +impl ElectionProvider for OnChainSequentialPhragmen { + type AccountId = T::AccountId; + type BlockNumber = T::BlockNumber; type Error = Error; type DataProvider = T::DataProvider; @@ -160,7 +165,9 @@ mod tests { use crate::data_provider; pub struct DataProvider; - impl ElectionDataProvider for DataProvider { + impl ElectionDataProvider for DataProvider { + type AccountId = AccountId; + type BlockNumber = BlockNumber; const MAXIMUM_VOTES_PER_VOTER: u32 = 2; fn voters( _: Option, diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 6c11e942106a7..95af3d223e009 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -844,7 +844,9 @@ impl Pallet { } } -impl ElectionDataProvider> for Pallet { +impl ElectionDataProvider for Pallet { + type AccountId = T::AccountId; + type BlockNumber = BlockNumberFor; const MAXIMUM_VOTES_PER_VOTER: u32 = T::MAX_NOMINATIONS; fn desired_targets() -> data_provider::Result { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 091df82e28172..d03a6198c7cc4 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -79,16 +79,16 @@ pub mod pallet { /// Something that provides the election functionality. type ElectionProvider: frame_election_provider_support::ElectionProvider< - Self::AccountId, - Self::BlockNumber, + AccountId = Self::AccountId, + BlockNumber = Self::BlockNumber, // we only accept an election provider that has staking as data provider. DataProvider = Pallet, >; /// Something that provides the election functionality at genesis. type GenesisElectionProvider: frame_election_provider_support::ElectionProvider< - Self::AccountId, - Self::BlockNumber, + AccountId = Self::AccountId, + BlockNumber = Self::BlockNumber, DataProvider = Pallet, >; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index aa806d4a15e2c..74d5de7bf449e 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4013,7 +4013,7 @@ mod election_data_provider { ExtBuilder::default().build_and_execute(|| { assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); assert_eq!( - >::voters(None) + ::voters(None) .unwrap() .iter() .find(|x| x.0 == 101) @@ -4028,7 +4028,7 @@ mod election_data_provider { // 11 is gone. start_active_era(2); assert_eq!( - >::voters(None) + ::voters(None) .unwrap() .iter() .find(|x| x.0 == 101) @@ -4040,7 +4040,7 @@ mod election_data_provider { // resubmit and it is back assert_ok!(Staking::nominate(Origin::signed(100), vec![11, 21])); assert_eq!( - >::voters(None) + ::voters(None) .unwrap() .iter() .find(|x| x.0 == 101) From 558e6d9a302518c0035d365351f4991f6e61d96c Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Thu, 16 Dec 2021 12:01:30 +0200 Subject: [PATCH 0348/1472] Async block import params (#10488) * Make `SimpleSlotWorker::block_import_params()` return function that returns a future * Simplify `SimpleSlotWorker::block_import_params()` to just async method --- client/consensus/aura/src/lib.rs | 91 ++++++++++++++---------------- client/consensus/babe/src/lib.rs | 94 ++++++++++++++----------------- client/consensus/slots/src/lib.rs | 51 ++++++++--------- 3 files changed, 107 insertions(+), 129 deletions(-) diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 0d79e3c4ecf04..ec577b0844313 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -382,58 +382,51 @@ where vec![>::aura_pre_digest(slot)] } - fn block_import_params( + async fn block_import_params( &self, - ) -> Box< - dyn Fn( - B::Header, - &B::Hash, - Vec, - StorageChanges, B>, - Self::Claim, - Self::EpochData, - ) -> Result< - sc_consensus::BlockImportParams>, - sp_consensus::Error, - > + Send - + 'static, + header: B::Header, + header_hash: &B::Hash, + body: Vec, + storage_changes: StorageChanges<>::Transaction, B>, + public: Self::Claim, + _epoch: Self::EpochData, + ) -> Result< + sc_consensus::BlockImportParams>::Transaction>, + sp_consensus::Error, > { - let keystore = self.keystore.clone(); - Box::new(move |header, header_hash, body, storage_changes, public, _epoch| { - // sign the pre-sealed hash of the block and then - // add it to a digest item. - let public_type_pair = public.to_public_crypto_pair(); - let public = public.to_raw_vec(); - let signature = SyncCryptoStore::sign_with( - &*keystore, - as AppKey>::ID, - &public_type_pair, - header_hash.as_ref(), + // sign the pre-sealed hash of the block and then + // add it to a digest item. + let public_type_pair = public.to_public_crypto_pair(); + let public = public.to_raw_vec(); + let signature = SyncCryptoStore::sign_with( + &*self.keystore, + as AppKey>::ID, + &public_type_pair, + header_hash.as_ref(), + ) + .map_err(|e| sp_consensus::Error::CannotSign(public.clone(), e.to_string()))? + .ok_or_else(|| { + sp_consensus::Error::CannotSign( + public.clone(), + "Could not find key in keystore.".into(), ) - .map_err(|e| sp_consensus::Error::CannotSign(public.clone(), e.to_string()))? - .ok_or_else(|| { - sp_consensus::Error::CannotSign( - public.clone(), - "Could not find key in keystore.".into(), - ) - })?; - let signature = signature - .clone() - .try_into() - .map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?; - - let signature_digest_item = - >::aura_seal(signature); - - let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); - import_block.post_digests.push(signature_digest_item); - import_block.body = Some(body); - import_block.state_action = - StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes(storage_changes)); - import_block.fork_choice = Some(ForkChoiceStrategy::LongestChain); - - Ok(import_block) - }) + })?; + let signature = signature + .clone() + .try_into() + .map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?; + + let signature_digest_item = + >::aura_seal(signature); + + let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); + import_block.post_digests.push(signature_digest_item); + import_block.body = Some(body); + import_block.state_action = + StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes(storage_changes)); + import_block.fork_choice = Some(ForkChoiceStrategy::LongestChain); + + Ok(import_block) } fn force_authoring(&self) -> bool { diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 168cdff43cda2..21c3c883a39dd 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -772,60 +772,52 @@ where vec![::babe_pre_digest(claim.0.clone())] } - fn block_import_params( + async fn block_import_params( &self, - ) -> Box< - dyn Fn( - B::Header, - &B::Hash, - Vec, - StorageChanges, - Self::Claim, - Self::EpochData, - ) -> Result, sp_consensus::Error> - + Send - + 'static, + header: B::Header, + header_hash: &B::Hash, + body: Vec, + storage_changes: StorageChanges<>::Transaction, B>, + (_, public): Self::Claim, + epoch_descriptor: Self::EpochData, + ) -> Result< + sc_consensus::BlockImportParams>::Transaction>, + sp_consensus::Error, > { - let keystore = self.keystore.clone(); - Box::new( - move |header, header_hash, body, storage_changes, (_, public), epoch_descriptor| { - // sign the pre-sealed hash of the block and then - // add it to a digest item. - let public_type_pair = public.clone().into(); - let public = public.to_raw_vec(); - let signature = SyncCryptoStore::sign_with( - &*keystore, - ::ID, - &public_type_pair, - header_hash.as_ref(), - ) - .map_err(|e| sp_consensus::Error::CannotSign(public.clone(), e.to_string()))? - .ok_or_else(|| { - sp_consensus::Error::CannotSign( - public.clone(), - "Could not find key in keystore.".into(), - ) - })?; - let signature: AuthoritySignature = signature - .clone() - .try_into() - .map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?; - let digest_item = ::babe_seal(signature.into()); - - let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); - import_block.post_digests.push(digest_item); - import_block.body = Some(body); - import_block.state_action = StateAction::ApplyChanges( - sc_consensus::StorageChanges::Changes(storage_changes), - ); - import_block.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, - ); - - Ok(import_block) - }, + // sign the pre-sealed hash of the block and then + // add it to a digest item. + let public_type_pair = public.clone().into(); + let public = public.to_raw_vec(); + let signature = SyncCryptoStore::sign_with( + &*self.keystore, + ::ID, + &public_type_pair, + header_hash.as_ref(), ) + .map_err(|e| sp_consensus::Error::CannotSign(public.clone(), e.to_string()))? + .ok_or_else(|| { + sp_consensus::Error::CannotSign( + public.clone(), + "Could not find key in keystore.".into(), + ) + })?; + let signature: AuthoritySignature = signature + .clone() + .try_into() + .map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?; + let digest_item = ::babe_seal(signature.into()); + + let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); + import_block.post_digests.push(digest_item); + import_block.body = Some(body); + import_block.state_action = + StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes(storage_changes)); + import_block.intermediates.insert( + Cow::from(INTERMEDIATE_KEY), + Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, + ); + + Ok(import_block) } fn force_authoring(&self) -> bool { diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index ead209ef86a65..3174eacaff4d6 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -144,24 +144,17 @@ pub trait SimpleSlotWorker { fn pre_digest_data(&self, slot: Slot, claim: &Self::Claim) -> Vec; /// Returns a function which produces a `BlockImportParams`. - fn block_import_params( + async fn block_import_params( &self, - ) -> Box< - dyn Fn( - B::Header, - &B::Hash, - Vec, - StorageChanges<>::Transaction, B>, - Self::Claim, - Self::EpochData, - ) -> Result< - sc_consensus::BlockImportParams< - B, - >::Transaction, - >, - sp_consensus::Error, - > + Send - + 'static, + header: B::Header, + header_hash: &B::Hash, + body: Vec, + storage_changes: StorageChanges<>::Transaction, B>, + public: Self::Claim, + epoch: Self::EpochData, + ) -> Result< + sc_consensus::BlockImportParams>::Transaction>, + sp_consensus::Error, >; /// Whether to force authoring if offline. @@ -342,23 +335,23 @@ pub trait SimpleSlotWorker { }, }; - let block_import_params_maker = self.block_import_params(); - let block_import = self.block_import(); - let (block, storage_proof) = (proposal.block, proposal.proof); let (header, body) = block.deconstruct(); let header_num = *header.number(); let header_hash = header.hash(); let parent_hash = *header.parent_hash(); - let block_import_params = match block_import_params_maker( - header, - &header_hash, - body.clone(), - proposal.storage_changes, - claim, - epoch_data, - ) { + let block_import_params = match self + .block_import_params( + header, + &header_hash, + body.clone(), + proposal.storage_changes, + claim, + epoch_data, + ) + .await + { Ok(bi) => bi, Err(err) => { warn!(target: logging_target, "Failed to create block import params: {:?}", err); @@ -385,7 +378,7 @@ pub trait SimpleSlotWorker { ); let header = block_import_params.post_header(); - match block_import.import_block(block_import_params, Default::default()).await { + match self.block_import().import_block(block_import_params, Default::default()).await { Ok(res) => { res.handle_justification( &header.hash(), From 2db9eccff65d4fcb3eaf085bd3ea9c6b2357428f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Dec 2021 11:02:12 +0100 Subject: [PATCH 0349/1472] Bump backtrace from 0.3.61 to 0.3.63 (#10495) Bumps [backtrace](https://github.com/rust-lang/backtrace-rs) from 0.3.61 to 0.3.63. - [Release notes](https://github.com/rust-lang/backtrace-rs/releases) - [Commits](https://github.com/rust-lang/backtrace-rs/compare/0.3.61...0.3.63) --- updated-dependencies: - dependency-name: backtrace 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 | 36 +++++++++++++++++------------ primitives/panic-handler/Cargo.toml | 2 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ff6fc1974fa0..92844e51fb4a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,15 @@ dependencies = [ "gimli 0.25.0", ] +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli 0.26.1", +] + [[package]] name = "adler" version = "1.0.2" @@ -406,16 +415,16 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.61" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01" +checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" dependencies = [ - "addr2line", + "addr2line 0.17.0", "cc", "cfg-if 1.0.0", "libc", "miniz_oxide", - "object 0.26.0", + "object 0.27.1", "rustc-demangle", ] @@ -2494,6 +2503,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + [[package]] name = "git2" version = "0.13.23" @@ -5007,15 +5022,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "object" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55827317fb4c08822499848a14237d2874d6f139828893017237e7ab93eb386" -dependencies = [ - "memchr", -] - [[package]] name = "object" version = "0.27.1" @@ -10815,7 +10821,7 @@ dependencies = [ "chrono", "lazy_static", "matchers", - "parking_lot 0.9.0", + "parking_lot 0.11.2", "regex", "serde", "serde_json", @@ -11663,7 +11669,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "864ac8dfe4ce310ac59f16fdbd560c257389cb009ee5d030ac6e30523b023d11" dependencies = [ - "addr2line", + "addr2line 0.16.0", "anyhow", "bincode", "cfg-if 1.0.0", diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml index 8c3578442a793..abab34d29519b 100644 --- a/primitives/panic-handler/Cargo.toml +++ b/primitives/panic-handler/Cargo.toml @@ -14,6 +14,6 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -backtrace = "0.3.38" +backtrace = "0.3.63" regex = "1.5.4" lazy_static = "1.4.0" From fb08d15bcbea68415dd4ee90d11556b653096f10 Mon Sep 17 00:00:00 2001 From: sandreim <54316454+sandreim@users.noreply.github.com> Date: Thu, 16 Dec 2021 13:18:24 +0200 Subject: [PATCH 0350/1472] Add logger configuration hook (#10440) * Initial poc Signed-off-by: Andrei Sandu * Make config available to logger hook Signed-off-by: Andrei Sandu * fmt Signed-off-by: Andrei Sandu * Fix tests Signed-off-by: Andrei Sandu * fmt Signed-off-by: Andrei Sandu * Add metric prefix option in sc_cli::RunCmd Signed-off-by: Andrei Sandu * Remove print Signed-off-by: Andrei Sandu * Review fixes Signed-off-by: Andrei Sandu * fmt Signed-off-by: Andrei Sandu * fix docs Signed-off-by: Andrei Sandu --- client/cli/src/config.rs | 37 ++++++++++- client/cli/src/lib.rs | 40 +++++++++++- client/cli/src/runner.rs | 13 +--- client/executor/src/integration_tests/mod.rs | 6 +- client/service/src/config.rs | 2 - client/tracing/src/lib.rs | 66 ++++++++++++++------ client/tracing/src/logging/mod.rs | 25 +++++++- 7 files changed, 148 insertions(+), 41 deletions(-) diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 6d5ac71182812..7ae31eba4245a 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -581,10 +581,40 @@ pub trait CliConfiguration: Sized { /// This method: /// /// 1. Sets the panic handler + /// 2. Optionally customize logger/profiling /// 2. Initializes the logger /// 3. Raises the FD limit - fn init(&self) -> Result<()> { - sp_panic_handler::set(&C::support_url(), &C::impl_version()); + /// + /// The `logger_hook` closure is executed before the logger is constructed + /// and initialized. It is useful for setting up a custom profiler. + /// + /// Example: + /// ``` + /// use sc_tracing::{SpanDatum, TraceEvent}; + /// struct TestProfiler; + /// + /// impl sc_tracing::TraceHandler for TestProfiler { + /// fn handle_span(&self, sd: &SpanDatum) {} + /// fn handle_event(&self, _event: &TraceEvent) {} + /// }; + /// + /// fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration) -> () { + /// |logger_builder, config| { + /// logger_builder.with_custom_profiling(Box::new(TestProfiler{})); + /// } + /// } + /// ``` + fn init( + &self, + support_url: &String, + impl_version: &String, + logger_hook: F, + config: &Configuration, + ) -> Result<()> + where + F: FnOnce(&mut LoggerBuilder, &Configuration), + { + sp_panic_handler::set(support_url, impl_version); let mut logger = LoggerBuilder::new(self.log_filters()?); logger @@ -600,6 +630,9 @@ pub trait CliConfiguration: Sized { logger.with_colors(false); } + // Call hook for custom profiling setup. + logger_hook(&mut logger, &config); + logger.init()?; if let Some(new_limit) = fdlimit::raise_fd_limit() { diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index bb1bff94145f7..d20b6f136f1e1 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -224,10 +224,46 @@ pub trait SubstrateCli: Sized { /// Create a runner for the command provided in argument. This will create a Configuration and /// a tokio runtime fn create_runner(&self, command: &T) -> error::Result> { - command.init::()?; - Runner::new(self, command) + let tokio_runtime = build_runtime()?; + let config = command.create_configuration(self, tokio_runtime.handle().clone())?; + + command.init(&Self::support_url(), &Self::impl_version(), |_, _| {}, &config)?; + Runner::new(config, tokio_runtime) } + /// Create a runner for the command provided in argument. The `logger_hook` can be used to setup + /// a custom profiler or update the logger configuration before it is initialized. + /// + /// Example: + /// ``` + /// use sc_tracing::{SpanDatum, TraceEvent}; + /// struct TestProfiler; + /// + /// impl sc_tracing::TraceHandler for TestProfiler { + /// fn handle_span(&self, sd: &SpanDatum) {} + /// fn handle_event(&self, _event: &TraceEvent) {} + /// }; + /// + /// fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration) -> () { + /// |logger_builder, config| { + /// logger_builder.with_custom_profiling(Box::new(TestProfiler{})); + /// } + /// } + /// ``` + fn create_runner_with_logger_hook( + &self, + command: &T, + logger_hook: F, + ) -> error::Result> + where + F: FnOnce(&mut LoggerBuilder, &Configuration), + { + let tokio_runtime = build_runtime()?; + let config = command.create_configuration(self, tokio_runtime.handle().clone())?; + + command.init(&Self::support_url(), &Self::impl_version(), logger_hook, &config)?; + Runner::new(config, tokio_runtime) + } /// Native runtime version. fn native_runtime_version(chain_spec: &Box) -> &'static RuntimeVersion; } diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index 34c1948012138..d55dfe2537659 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{error::Error as CliError, CliConfiguration, Result, SubstrateCli}; +use crate::{error::Error as CliError, Result, SubstrateCli}; use chrono::prelude::*; use futures::{future, future::FutureExt, pin_mut, select, Future}; use log::info; @@ -112,15 +112,8 @@ pub struct Runner { impl Runner { /// Create a new runtime with the command provided in argument - pub fn new(cli: &C, command: &T) -> Result> { - let tokio_runtime = build_runtime()?; - let runtime_handle = tokio_runtime.handle().clone(); - - Ok(Runner { - config: command.create_configuration(cli, runtime_handle)?, - tokio_runtime, - phantom: PhantomData, - }) + pub fn new(config: Configuration, tokio_runtime: tokio::runtime::Runtime) -> Result> { + Ok(Runner { config, tokio_runtime, phantom: PhantomData }) } /// Log information about the node itself. diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index b2b31679926c2..89648e9bac696 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -622,11 +622,11 @@ fn wasm_tracing_should_work(wasm_method: WasmExecutionMethod) { struct TestTraceHandler(Arc>>); impl sc_tracing::TraceHandler for TestTraceHandler { - fn handle_span(&self, sd: SpanDatum) { - self.0.lock().unwrap().push(sd); + fn handle_span(&self, sd: &SpanDatum) { + self.0.lock().unwrap().push(sd.clone()); } - fn handle_event(&self, _event: TraceEvent) {} + fn handle_event(&self, _event: &TraceEvent) {} } let traces = Arc::new(Mutex::new(Vec::new())); diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 61ef8233f8e37..db2041ed96f16 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -188,8 +188,6 @@ pub struct PrometheusConfig { impl PrometheusConfig { /// Create a new config using the default registry. - /// - /// The default registry prefixes metrics with `substrate`. pub fn new_with_default_registry(port: SocketAddr, chain_id: String) -> Self { let param = iter::once((String::from("chain"), chain_id)).collect(); Self { diff --git a/client/tracing/src/lib.rs b/client/tracing/src/lib.rs index bf6e3d780c6ed..fc501bb9a4323 100644 --- a/client/tracing/src/lib.rs +++ b/client/tracing/src/lib.rs @@ -58,7 +58,7 @@ const ZERO_DURATION: Duration = Duration::from_nanos(0); /// Responsible for assigning ids to new spans, which are not re-used. pub struct ProfilingLayer { targets: Vec<(String, Level)>, - trace_handler: Box, + trace_handlers: Vec>, } /// Used to configure how to receive the metrics @@ -76,14 +76,14 @@ impl Default for TracingReceiver { /// A handler for tracing `SpanDatum` pub trait TraceHandler: Send + Sync { - /// Process a `SpanDatum` - fn handle_span(&self, span: SpanDatum); - /// Process a `TraceEvent` - fn handle_event(&self, event: TraceEvent); + /// Process a `SpanDatum`. + fn handle_span(&self, span: &SpanDatum); + /// Process a `TraceEvent`. + fn handle_event(&self, event: &TraceEvent); } /// Represents a tracing event, complete with values -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TraceEvent { /// Name of the event. pub name: String, @@ -98,7 +98,7 @@ pub struct TraceEvent { } /// Represents a single instance of a tracing span -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct SpanDatum { /// id for this span pub id: Id, @@ -213,6 +213,15 @@ impl fmt::Display for Values { } } +/// Trace handler event types. +#[derive(Debug)] +pub enum TraceHandlerEvents { + /// An event. + Event(TraceEvent), + /// A span. + Span(SpanDatum), +} + impl ProfilingLayer { /// Takes a `TracingReceiver` and a comma separated list of targets, /// either with a level: "pallet=trace,frame=debug" @@ -231,7 +240,12 @@ impl ProfilingLayer { /// wasm_tracing indicates whether to enable wasm traces pub fn new_with_handler(trace_handler: Box, targets: &str) -> Self { let targets: Vec<_> = targets.split(',').map(|s| parse_target(s)).collect(); - Self { targets, trace_handler } + Self { targets, trace_handlers: vec![trace_handler] } + } + + /// Attach additional handlers to allow handling of custom events/spans. + pub fn add_handler(&mut self, trace_handler: Box) { + self.trace_handlers.push(trace_handler); } fn check_target(&self, target: &str, level: &Level) -> bool { @@ -242,6 +256,18 @@ impl ProfilingLayer { } false } + + /// Sequentially dispatch a trace event to all handlers. + fn dispatch_event(&self, event: TraceHandlerEvents) { + match &event { + TraceHandlerEvents::Span(span_datum) => { + self.trace_handlers.iter().for_each(|handler| handler.handle_span(span_datum)); + }, + TraceHandlerEvents::Event(event) => { + self.trace_handlers.iter().for_each(|handler| handler.handle_event(event)); + }, + } + } } // Default to TRACE if no level given or unable to parse Level @@ -320,7 +346,7 @@ where values, parent_id, }; - self.trace_handler.handle_event(trace_event); + self.dispatch_event(TraceHandlerEvents::Event(trace_event)); } fn on_enter(&self, span: &Id, ctx: Context) { @@ -348,10 +374,10 @@ where span_datum.target = t; } if self.check_target(&span_datum.target, &span_datum.level) { - self.trace_handler.handle_span(span_datum); + self.dispatch_event(TraceHandlerEvents::Span(span_datum)); } } else { - self.trace_handler.handle_span(span_datum); + self.dispatch_event(TraceHandlerEvents::Span(span_datum)); } } } @@ -374,7 +400,7 @@ fn log_level(level: Level) -> log::Level { } impl TraceHandler for LogTraceHandler { - fn handle_span(&self, span_datum: SpanDatum) { + fn handle_span(&self, span_datum: &SpanDatum) { if span_datum.values.is_empty() { log::log!( log_level(span_datum.level), @@ -383,7 +409,7 @@ impl TraceHandler for LogTraceHandler { span_datum.name, span_datum.overall_time.as_nanos(), span_datum.id.into_u64(), - span_datum.parent_id.map(|s| s.into_u64()), + span_datum.parent_id.as_ref().map(|s| s.into_u64()), ); } else { log::log!( @@ -393,18 +419,18 @@ impl TraceHandler for LogTraceHandler { span_datum.name, span_datum.overall_time.as_nanos(), span_datum.id.into_u64(), - span_datum.parent_id.map(|s| s.into_u64()), + span_datum.parent_id.as_ref().map(|s| s.into_u64()), span_datum.values, ); } } - fn handle_event(&self, event: TraceEvent) { + fn handle_event(&self, event: &TraceEvent) { log::log!( log_level(event.level), "{}, parent_id: {:?}, {}", event.target, - event.parent_id.map(|s| s.into_u64()), + event.parent_id.as_ref().map(|s| s.into_u64()), event.values, ); } @@ -447,12 +473,12 @@ mod tests { } impl TraceHandler for TestTraceHandler { - fn handle_span(&self, sd: SpanDatum) { - self.spans.lock().push(sd); + fn handle_span(&self, sd: &SpanDatum) { + self.spans.lock().push(sd.clone()); } - fn handle_event(&self, event: TraceEvent) { - self.events.lock().push(event); + fn handle_event(&self, event: &TraceEvent) { + self.events.lock().push(event.clone()); } } diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index 521cfca30e29b..72740715e55b4 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -193,6 +193,7 @@ where pub struct LoggerBuilder { directives: String, profiling: Option<(crate::TracingReceiver, String)>, + custom_profiler: Option>, log_reloading: bool, force_colors: Option, detailed_output: bool, @@ -204,6 +205,7 @@ impl LoggerBuilder { Self { directives: directives.into(), profiling: None, + custom_profiler: None, log_reloading: false, force_colors: None, detailed_output: false, @@ -220,6 +222,15 @@ impl LoggerBuilder { self } + /// Add a custom profiler. + pub fn with_custom_profiling( + &mut self, + custom_profiler: Box, + ) -> &mut Self { + self.custom_profiler = Some(custom_profiler); + self + } + /// Wether or not to disable log reloading. pub fn with_log_reloading(&mut self, enabled: bool) -> &mut Self { self.log_reloading = enabled; @@ -256,7 +267,12 @@ impl LoggerBuilder { self.detailed_output, |builder| enable_log_reloading!(builder), )?; - let profiling = crate::ProfilingLayer::new(tracing_receiver, &profiling_targets); + let mut profiling = + crate::ProfilingLayer::new(tracing_receiver, &profiling_targets); + + self.custom_profiler + .into_iter() + .for_each(|profiler| profiling.add_handler(profiler)); tracing::subscriber::set_global_default(subscriber.with(profiling))?; @@ -269,7 +285,12 @@ impl LoggerBuilder { self.detailed_output, |builder| builder, )?; - let profiling = crate::ProfilingLayer::new(tracing_receiver, &profiling_targets); + let mut profiling = + crate::ProfilingLayer::new(tracing_receiver, &profiling_targets); + + self.custom_profiler + .into_iter() + .for_each(|profiler| profiling.add_handler(profiler)); tracing::subscriber::set_global_default(subscriber.with(profiling))?; From 2a7a734c373d0b28c6c658667effd3fb8c9e35bf Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 17 Dec 2021 07:19:30 +0800 Subject: [PATCH 0351/1472] Use intra doc in network-gossip (#10501) * Use intra doc in network-gossip So that we could jump to the definition easily. * cargo +nightly fmt --all --- client/network-gossip/src/bridge.rs | 4 ++-- client/network-gossip/src/lib.rs | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 70b13983d8bd3..477b0678fcc8f 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -39,7 +39,7 @@ use std::{ task::{Context, Poll}, }; -/// Wraps around an implementation of the `Network` crate and provides gossiping capabilities on +/// Wraps around an implementation of the [`Network`] trait and provides gossiping capabilities on /// top of it. pub struct GossipEngine { state_machine: ConsensusGossip, @@ -56,7 +56,7 @@ pub struct GossipEngine { } /// A gossip engine receives messages from the network via the `network_event_stream` and forwards -/// them to upper layers via the `message sinks`. In the scenario where messages have been received +/// them to upper layers via the `message_sinks`. In the scenario where messages have been received /// from the network but a subscribed message sink is not yet ready to receive the messages, the /// messages are buffered. To model this process a gossip engine can be in two states. enum ForwardingState { diff --git a/client/network-gossip/src/lib.rs b/client/network-gossip/src/lib.rs index 5dc40471f138f..4b8b4e39862ba 100644 --- a/client/network-gossip/src/lib.rs +++ b/client/network-gossip/src/lib.rs @@ -26,32 +26,32 @@ //! message, assuming it is valid. //! //! Topics are a single 32-byte tag associated with a message, used to group those messages -//! in an opaque way. Consensus code can invoke `broadcast_topic` to attempt to send all messages -//! under a single topic to all peers who don't have them yet, and `send_topic` to -//! send all messages under a single topic to a specific peer. +//! in an opaque way. Consensus code can invoke [`ValidatorContext::broadcast_topic`] to +//! attempt to send all messages under a single topic to all peers who don't have them yet, and +//! [`ValidatorContext::send_topic`] to send all messages under a single topic to a specific peer. //! //! # Usage //! -//! - Implement the `Network` trait, representing the low-level networking primitives. It is already -//! implemented on `sc_network::NetworkService`. -//! - Implement the `Validator` trait. See the section below. +//! - Implement the [`Network`] trait, representing the low-level networking primitives. It is +//! already implemented on `sc_network::NetworkService`. +//! - Implement the [`Validator`] trait. See the section below. //! - Decide on a protocol name. Each gossiping protocol should have a different one. -//! - Build a `GossipEngine` using these three elements. -//! - Use the methods of the `GossipEngine` in order to send out messages and receive incoming +//! - Build a [`GossipEngine`] using these three elements. +//! - Use the methods of the [`GossipEngine`] in order to send out messages and receive incoming //! messages. //! -//! The `GossipEngine` will automatically use `Network::add_set_reserved` and -//! `Network::remove_set_reserved` to maintain a set of peers equal to the set of peers the +//! The [`GossipEngine`] will automatically use [`Network::add_set_reserved`] and +//! [`Network::remove_set_reserved`] to maintain a set of peers equal to the set of peers the //! node is syncing from. See the documentation of `sc-network` for more explanations about the //! concepts of peer sets. //! //! # What is a validator? //! -//! The primary role of a `Validator` is to process incoming messages from peers, and decide +//! The primary role of a [`Validator`] is to process incoming messages from peers, and decide //! whether to discard them or process them. It also decides whether to re-broadcast the message. //! -//! The secondary role of the `Validator` is to check if a message is allowed to be sent to a given -//! peer. All messages, before being sent, will be checked against this filter. +//! The secondary role of the [`Validator`] is to check if a message is allowed to be sent to a +//! given peer. All messages, before being sent, will be checked against this filter. //! This enables the validator to use information it's aware of about connected peers to decide //! whether to send messages to them at any given moment in time - In particular, to wait until //! peers can accept and process the message before sending it. From ce92e8060b179ea48f1e1b3edbe8c4d296a97e30 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Dec 2021 08:30:58 +0000 Subject: [PATCH 0352/1472] Bump serde from 1.0.130 to 1.0.131 (#10500) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.130 to 1.0.131. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.130...v1.0.131) --- 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 ++++---- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- frame/merkle-mountain-range/primitives/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/test/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- frame/transaction-payment/asset-tx-payment/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- primitives/application-crypto/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/serializer/Cargo.toml | 2 +- primitives/storage/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 2 +- primitives/version/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 48 files changed, 51 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92844e51fb4a1..0c70bbdf6efca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8893,9 +8893,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.130" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" dependencies = [ "serde_derive", ] @@ -8921,9 +8921,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.130" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" dependencies = [ "proc-macro2", "quote", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 8d2ca810273cf..3ffb0f92c843e 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -16,7 +16,7 @@ node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } -serde = "1.0.126" +serde = "1.0.131" serde_json = "1.0.71" structopt = "0.3" derive_more = "0.99.16" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index d7143b39816b4..a967dd1332116 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -35,7 +35,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies codec = { package = "parity-scale-codec", version = "2.0.0" } -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } futures = "0.3.16" hex-literal = "0.3.4" log = "0.4.8" diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 9f4a1305f2d03..b5a8144faba8e 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -10,7 +10,7 @@ description = "RPC for the BEEFY Client gadget for substrate" [dependencies] futures = "0.3.16" log = "0.4" -serde = { version = "1.0.130", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index d06e0bce18c15..4ef14decf9eb3 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -17,7 +17,7 @@ sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } impl-trait-for-tuples = "0.2.1" sc-network = { version = "0.10.0-dev", path = "../network" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } serde_json = "1.0.71" sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 2e2b208923d57..cb9d09bbdbc7d 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -41,7 +41,7 @@ names = { version = "0.12.0", default-features = false } structopt = "0.3.25" sc-tracing = { version = "4.0.0-dev", path = "../tracing" } chrono = "0.4.10" -serde = "1.0.126" +serde = "1.0.131" thiserror = "1.0.30" rpassword = "5.0.0" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index c96d648846c5e..654e47b727565 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -25,7 +25,7 @@ sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } num-bigint = "0.2.3" num-rational = "0.2.2" num-traits = "0.2.8" -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } sp-io = { version = "4.0.0", path = "../../../primitives/io" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index cea2aea4553b1..28b27db82c7dc 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -19,7 +19,7 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } -serde = { version = "1.0.126", features=["derive"] } +serde = { version = "1.0.131", features=["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sp-runtime = { version = "4.0.0", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 643b2440209f4..d82d5b9574dd0 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -46,7 +46,7 @@ rand = "0.7.2" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } serde_json = "1.0.71" smallvec = "1.7.0" sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 2e75dd460bd3a..8a2feb2581b07 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -27,7 +27,7 @@ sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-runtime = { path = "../../primitives/runtime", version = "4.0.0" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } serde_json = "1.0.71" sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index e81125fc91545..4d88f403005e1 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -33,7 +33,7 @@ futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.8" hash-db = "0.15.2" -serde = "1.0.126" +serde = "1.0.131" serde_json = "1.0.71" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index a7b632b818002..1566777009c3d 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -24,7 +24,7 @@ sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } serde_json = "1.0.71" -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index af7b1d0a06698..c4e03e94a2b13 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -22,7 +22,7 @@ libp2p = { version = "0.40.0", default-features = false, features = ["dns-async- log = "0.4.8" pin-project = "1.0.8" rand = "0.7.2" -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } serde_json = "1.0.71" chrono = "0.4.19" thiserror = "1.0.30" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index c4fdcde3f0673..861e1acc68c3e 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -23,7 +23,7 @@ once_cell = "1.8.0" parking_lot = "0.11.2" regex = "1.5.4" rustc-hash = "1.1.0" -serde = "1.0.126" +serde = "1.0.131" thiserror = "1.0.30" tracing = "0.1.29" tracing-log = "0.1.2" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 6439a1854352b..2399fb449c7f0 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -30,7 +30,7 @@ sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transact sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } linked-hash-map = "0.5.4" retain_mut = "0.1.4" diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 0c65234b0d683..39e126250a9ee 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -11,7 +11,7 @@ description = "Transaction pool client facing API." [dependencies] futures = { version = "0.3.1" } log = { version = "0.4.8" } -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } thiserror = { version = "1.0.30" } sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 50c4fd3f7f3ba..a4ba9d1fbdaea 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -13,7 +13,7 @@ codec = { version = "2.2.0", package = "parity-scale-codec", default-features = libsecp256k1 = { version = "0.7.0", default-features = false } log = { version = "0.4.13", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.130", optional = true } +serde = { version = "1.0.131", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 2f7059d5156cd..e9a748b2e80d7 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -10,7 +10,7 @@ description = "BEEFY FRAME pallet" [dependencies] codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.130", optional = true } +serde = { version = "1.0.131", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index b1b84d9ad03d1..0c9306b8b5bd5 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index 713da64e26d9f..cda883ccf728f 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } log = { version = "0.4.14", default-features = false } -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 13d60142dfc30..291fd5311aa57 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 02f36fab0a213..40b211a19cd03 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -17,7 +17,7 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -serde = { version = "1.0.126", optional = true } +serde = { version = "1.0.131", optional = true } sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index c91db8c24fda3..e09d5a57d5cab 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.126", optional = true } +serde = { version = "1.0.131", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 3cfce23dabe09..c049870ecb097 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-metadata = { version = "14.0.0", default-features = false, features = ["v14"] } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index d41b0fcacf236..ebee4515f3bef 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.126", default-features = false, features = ["derive"] } +serde = { version = "1.0.131", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../../primitives/arithmetic" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 70a9b12c7a237..cc1378a35c626 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index a637fa3928e02..935ab907a8a11 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.126", features = ["derive"], optional = true } +serde = { version = "1.0.131", features = ["derive"], optional = true } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index ac6fc5c71c049..f4b9b9a18019f 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.126", optional = true } +serde = { version = "1.0.131", optional = true } smallvec = "1.7.0" sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 3f89a5c4b5f09..9c26fc8033f73 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -26,7 +26,7 @@ pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, # Other dependencies codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.126", optional = true } +serde = { version = "1.0.131", optional = true } [dev-dependencies] smallvec = "1.7.0" diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 10f1d3d2e2b29..9bbc055dae1d9 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.126", optional = true } +serde = { version = "1.0.131", optional = true } hex-literal = { version = "0.3.4", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 5fe5734120d69..53cad5edffc36 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = "max-encoded-len", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.126", features = ["derive"], optional = true } +serde = { version = "1.0.131", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.1" sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index 8090203bbca0f..750f8874493e4 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "4.0.0", default-features = false, path = "../io" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 8db65342cfa0d..a035b03b82a2d 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -23,7 +23,7 @@ integer-sqrt = "0.1.2" static_assertions = "1.1.0" num-traits = { version = "0.2.8", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } [dev-dependencies] diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index fcfda410765e9..19e94a8da21d9 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -27,7 +27,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-keystore = { version = "0.10.0", default-features = false, path = "../../keystore", optional = true } sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../timestamp", optional = true } -serde = { version = "1.0.126", features = ["derive"], optional = true } +serde = { version = "1.0.131", features = ["derive"], optional = true } async-trait = { version = "0.1.50", optional = true } [features] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 2922c8b940ea8..1ec9b5b46f1bb 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.11", default-features = false } -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } primitive-types = { version = "0.10.1", default-features = false, features = [ "codec", diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index 8bcdf1462fc81..80607a0beb196 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.14.1", default-features = false, features = ["derive-codec"] } log = { version = "0.4.8", optional = true } -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 3a5b00dcdf779..3ee25f8ab816e 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index e16280f95d35d..fdc019bad4b6b 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.126", features = ["derive"] } +serde = { version = "1.0.131", features = ["derive"] } sp-core = { version = "4.1.0-dev", path = "../core" } rustc-hash = "1.1.0" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 6363a0a286310..a30bd08452d88 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } diff --git a/primitives/serializer/Cargo.toml b/primitives/serializer/Cargo.toml index 359217b9b4d5a..89ddb28df2723 100644 --- a/primitives/serializer/Cargo.toml +++ b/primitives/serializer/Cargo.toml @@ -14,5 +14,5 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = "1.0.126" +serde = "1.0.131" serde_json = "1.0.71" diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index 918938273c620..98c8d693e9d64 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-std = { version = "4.0.0", default-features = false, path = "../std" } -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } impl-serde = { version = "0.3.1", optional = true } ref-cast = "1.0.0" sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 5d0a3d440c46a..5bc81637e82ae 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index b8a3a5bc3e305..b6ad02d4331f8 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] impl-serde = { version = "0.3.1", optional = true } -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 5d148ccd125eb..c5a4a27c2ee9c 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0" } futures = "0.3.16" hex = "0.4" -serde = "1.0.126" +serde = "1.0.131" serde_json = "1.0.71" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } sc-client-db = { version = "0.10.0-dev", features = [ diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 72e2c255c15cc..ccaae6e692437 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -48,7 +48,7 @@ sp-externalities = { version = "0.10.0", default-features = false, path = "../.. # 3rd party cfg-if = "1.0" log = { version = "0.4.14", default-features = false } -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.131", optional = true, features = ["derive"] } [dev-dependencies] sc-block-builder = { version = "0.10.0-dev", path = "../../client/block-builder" } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index d61cf71aec381..fce53612e3cef 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -27,7 +27,7 @@ sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machi codec = { version = "2.0.0", package = "parity-scale-codec" } structopt = "0.3.25" chrono = "0.4" -serde = "1.0.126" +serde = "1.0.131" handlebars = "4.1.4" Inflector = "0.11.4" linked-hash-map = "0.5.4" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index edd538baf562c..969860c3df4be 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -20,7 +20,7 @@ frame-support = { path = "../../../frame/support", optional = true, version = "4 log = "0.4.11" codec = { package = "parity-scale-codec", version = "2.0.0" } serde_json = "1.0" -serde = "1.0.126" +serde = "1.0.131" sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index a0eca3cc9e9c9..8f84750f8ebfe 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.8" parity-scale-codec = { version = "2.3.1" } -serde = "1.0.126" +serde = "1.0.131" structopt = "0.3.25" sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../../client/service" } From a404abd3b38bd19627c7307597c99168a4f3b7bf Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 17 Dec 2021 17:43:51 +0800 Subject: [PATCH 0353/1472] Derive TypeInfo for OpaqueExtrinsic (#10504) --- primitives/runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 26db5ef081a8c..deea4a73c8e2d 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -800,7 +800,7 @@ macro_rules! assert_eq_error_rate { /// Simple blob to hold an extrinsic without committing to its format and ensure it is serialized /// correctly. -#[derive(PartialEq, Eq, Clone, Default, Encode, Decode)] +#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, TypeInfo)] pub struct OpaqueExtrinsic(Vec); impl OpaqueExtrinsic { From 5bd5b842d4ea520d281b1398e1f54907c9862fcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 17 Dec 2021 11:52:16 +0100 Subject: [PATCH 0354/1472] Remove offchain workers ownership. (#10506) --- docs/CODEOWNERS | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index bf9e589ff487c..70009d311f1c6 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -27,10 +27,6 @@ /primitives/sr-sandbox/ @pepyakin /primitives/core/src/sandbox.rs @pepyakin -# Offchain -/client/offchain/ @tomusdrw -/primitives/offchain/ @tomusdrw - # GRANDPA, BABE, consensus stuff /frame/babe/ @andresilva /frame/grandpa/ @andresilva From efa4dfa97508b2fa3676da8fe99dbf6601fd04bf Mon Sep 17 00:00:00 2001 From: hamidra Date: Sat, 18 Dec 2021 07:41:05 -0800 Subject: [PATCH 0355/1472] Add ClassAccount storage to unique pallet (#9940) * add ClassAccount to uniques storage * add tests for Class and ClassAccount storage * fix format * fix description * add migration * remove extra iteration * Update frame/uniques/src/migration.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * fix format Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Parity Bot Co-authored-by: Shawn Tabrizi --- Cargo.lock | 1 + frame/uniques/Cargo.toml | 1 + frame/uniques/src/functions.rs | 2 + frame/uniques/src/lib.rs | 29 ++++++- frame/uniques/src/migration.rs | 56 +++++++++++++ frame/uniques/src/tests.rs | 18 ++++- frame/uniques/src/weights.rs | 140 ++++++++++++++++++--------------- 7 files changed, 179 insertions(+), 68 deletions(-) create mode 100644 frame/uniques/src/migration.rs diff --git a/Cargo.lock b/Cargo.lock index 0c70bbdf6efca..797343de27f15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6265,6 +6265,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log 0.4.14", "pallet-balances", "parity-scale-codec", "scale-info", diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index c9892cac26978..a168c96778ad5 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -20,6 +20,7 @@ sp-runtime = { version = "4.0.0", default-features = false, path = "../../primit frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +log = { version = "0.4.14", default-features = false } [dev-dependencies] sp-std = { version = "4.0.0", path = "../../primitives/std" } diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 43d634ad569e7..e0ee09ab62d9d 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -81,6 +81,7 @@ impl, I: 'static> Pallet { }, ); + ClassAccount::::insert(&owner, &class, ()); Self::deposit_event(event); Ok(()) } @@ -108,6 +109,7 @@ impl, I: 'static> Pallet { InstanceMetadataOf::::remove_prefix(&class, None); ClassMetadataOf::::remove(&class); Attribute::::remove_prefix((&class,), None); + ClassAccount::::remove(&class_details.owner, &class); T::Currency::unreserve(&class_details.owner, class_details.total_deposit); Self::deposit_event(Event::Destroyed { class }); diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 7e380459252e7..b5dada9ef6459 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -40,6 +40,8 @@ mod impl_nonfungibles; mod types; pub use types::*; +mod migration; + use codec::{Decode, Encode, HasCompact}; use frame_support::traits::{BalanceStatus::Reserved, Currency, ReservableCurrency}; use frame_system::Config as SystemConfig; @@ -141,6 +143,19 @@ pub mod pallet { OptionQuery, >; + #[pallet::storage] + /// The classes owned by any given account; set out this way so that classes owned by a single + /// account can be enumerated. + pub(super) type ClassAccount, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Blake2_128Concat, + T::ClassId, + (), + OptionQuery, + >; + #[pallet::storage] /// The assets in existence and their ownership details. pub(super) type Asset, I: 'static = ()> = StorageDoubleMap< @@ -302,7 +317,11 @@ pub mod pallet { } #[pallet::hooks] - impl, I: 'static> Hooks> for Pallet {} + impl, I: 'static> Hooks> for Pallet { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + migration::migrate_to_v1::() + } + } impl, I: 'static> Pallet { /// Get the owner of the asset instance, if the asset exists. @@ -731,6 +750,8 @@ pub mod pallet { details.total_deposit, Reserved, )?; + ClassAccount::::remove(&details.owner, &class); + ClassAccount::::insert(&owner, &class, ()); details.owner = owner.clone(); Self::deposit_event(Event::OwnerChanged { class, new_owner: owner }); @@ -906,13 +927,17 @@ pub mod pallet { Class::::try_mutate(class, |maybe_asset| { let mut asset = maybe_asset.take().ok_or(Error::::Unknown)?; - asset.owner = T::Lookup::lookup(owner)?; + let old_owner = asset.owner; + let new_owner = T::Lookup::lookup(owner)?; + asset.owner = new_owner.clone(); asset.issuer = T::Lookup::lookup(issuer)?; asset.admin = T::Lookup::lookup(admin)?; asset.freezer = T::Lookup::lookup(freezer)?; asset.free_holding = free_holding; asset.is_frozen = is_frozen; *maybe_asset = Some(asset); + ClassAccount::::remove(&old_owner, &class); + ClassAccount::::insert(&new_owner, &class, ()); Self::deposit_event(Event::AssetStatusChanged { class }); Ok(()) diff --git a/frame/uniques/src/migration.rs b/frame/uniques/src/migration.rs new file mode 100644 index 0000000000000..76f78c2bc64ed --- /dev/null +++ b/frame/uniques/src/migration.rs @@ -0,0 +1,56 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Various pieces of common functionality. +use super::*; +use frame_support::{ + traits::{Get, GetStorageVersion, PalletInfoAccess, StorageVersion}, + weights::Weight, +}; + +pub fn migrate_to_v1, I: 'static, P: GetStorageVersion + PalletInfoAccess>( +) -> frame_support::weights::Weight { + let on_chain_storage_version =

::on_chain_storage_version(); + log::info!( + target: "runtime::uniques", + "Running migration storage v1 for uniques with storage version {:?}", + on_chain_storage_version, + ); + + if on_chain_storage_version < 1 { + let mut count = 0; + for (class, detail) in Class::::iter() { + ClassAccount::::insert(&detail.owner, &class, ()); + count += 1; + } + StorageVersion::new(1).put::

(); + log::info!( + target: "runtime::uniques", + "Running migration storage v1 for uniques with storage version {:?} was complete", + on_chain_storage_version, + ); + // calculate and return migration weights + T::DbWeight::get().reads_writes(count as Weight + 1, count as Weight + 1) + } else { + log::warn!( + target: "runtime::uniques", + "Attempted to apply migration to v1 but failed because storage version is {:?}", + on_chain_storage_version, + ); + T::DbWeight::get().reads(1) + } +} diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index d23d694e949e2..8d0d6fdf9af37 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -48,6 +48,15 @@ fn assets() -> Vec<(u64, u32, u32)> { r } +fn classes() -> Vec<(u64, u32)> { + let mut r: Vec<_> = ClassAccount::::iter().map(|x| (x.0, x.1)).collect(); + r.sort(); + let mut s: Vec<_> = Class::::iter().map(|x| (x.1.owner, x.0)).collect(); + s.sort(); + assert_eq!(r, s); + r +} + macro_rules! bvec { ($( $x:tt )*) => { vec![$( $x )*].try_into().unwrap() @@ -73,10 +82,12 @@ fn basic_setup_works() { fn basic_minting_should_work() { new_test_ext().execute_with(|| { assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_eq!(classes(), vec![(1, 0)]); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_eq!(assets(), vec![(1, 0, 42)]); assert_ok!(Uniques::force_create(Origin::root(), 1, 2, true)); + assert_eq!(classes(), vec![(1, 0), (2, 1)]); assert_ok!(Uniques::mint(Origin::signed(2), 1, 69, 1)); assert_eq!(assets(), vec![(1, 0, 42), (1, 1, 69)]); }); @@ -88,7 +99,7 @@ fn lifecycle_should_work() { Balances::make_free_balance_be(&1, 100); assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); assert_eq!(Balances::reserved_balance(&1), 2); - + assert_eq!(classes(), vec![(1, 0)]); assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0, 0], false)); assert_eq!(Balances::reserved_balance(&1), 5); assert!(ClassMetadataOf::::contains_key(0)); @@ -120,6 +131,7 @@ fn lifecycle_should_work() { assert!(!ClassMetadataOf::::contains_key(0)); assert!(!InstanceMetadataOf::::contains_key(0, 42)); assert!(!InstanceMetadataOf::::contains_key(0, 69)); + assert_eq!(classes(), vec![]); assert_eq!(assets(), vec![]); }); } @@ -142,6 +154,7 @@ fn mint_should_work() { assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_eq!(Uniques::owner(0, 42).unwrap(), 1); + assert_eq!(classes(), vec![(1, 0)]); assert_eq!(assets(), vec![(1, 0, 42)]); }); } @@ -204,7 +217,9 @@ fn transfer_owner_should_work() { Balances::make_free_balance_be(&2, 100); Balances::make_free_balance_be(&3, 100); assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); + assert_eq!(classes(), vec![(1, 0)]); assert_ok!(Uniques::transfer_ownership(Origin::signed(1), 0, 2)); + assert_eq!(classes(), vec![(2, 0)]); assert_eq!(Balances::total_balance(&1), 98); assert_eq!(Balances::total_balance(&2), 102); assert_eq!(Balances::reserved_balance(&1), 0); @@ -220,6 +235,7 @@ fn transfer_owner_should_work() { assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_ok!(Uniques::set_metadata(Origin::signed(2), 0, 42, bvec![0u8; 20], false)); assert_ok!(Uniques::transfer_ownership(Origin::signed(2), 0, 3)); + assert_eq!(classes(), vec![(3, 0)]); assert_eq!(Balances::total_balance(&2), 57); assert_eq!(Balances::total_balance(&3), 145); assert_eq!(Balances::reserved_balance(&2), 0); diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 40d1ddfdc5566..168e0fcc80156 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-11-02, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -73,34 +73,37 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (42_138_000 as Weight) + (41_109_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (22_238_000 as Weight) + (22_986_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:0) + // Storage: Uniques ClassAccount (r:0 w:1) // Storage: Uniques Attribute (r:0 w:1000) // Storage: Uniques ClassMetadataOf (r:0 w:1) // Storage: Uniques InstanceMetadataOf (r:0 w:1000) // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 12_000 - .saturating_add((16_171_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 12_000 + // Standard Error: 14_000 + .saturating_add((14_879_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 14_000 .saturating_add((1_058_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 12_000 - .saturating_add((953_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 14_000 + .saturating_add((956_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(m as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) @@ -109,7 +112,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (55_359_000 as Weight) + (51_248_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -117,7 +120,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (58_254_000 as Weight) + (53_172_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -125,7 +128,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (42_906_000 as Weight) + (39_680_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -133,8 +136,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 9_000 - .saturating_add((25_237_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 12_000 + .saturating_add((22_759_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -143,53 +146,55 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (30_153_000 as Weight) + (27_833_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (31_212_000 as Weight) + (27_739_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_class() -> Weight { - (22_689_000 as Weight) + (20_890_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_class() -> Weight { - (22_647_000 as Weight) + (20_848_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: System Account (r:1 w:1) + // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (50_902_000 as Weight) + (51_523_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (23_632_000 as Weight) + (22_034_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques ClassAccount (r:0 w:1) fn force_asset_status() -> Weight { - (22_508_000 as Weight) + (25_877_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (69_942_000 as Weight) + (63_365_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -197,49 +202,49 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (62_314_000 as Weight) + (56_849_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (52_647_000 as Weight) + (47_982_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (50_391_000 as Weight) + (47_340_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_class_metadata() -> Weight { - (50_928_000 as Weight) + (46_897_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_class_metadata() -> Weight { - (46_667_000 as Weight) + (41_745_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (32_111_000 as Weight) + (29_828_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (32_627_000 as Weight) + (29_759_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -248,34 +253,37 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (42_138_000 as Weight) + (41_109_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (22_238_000 as Weight) + (22_986_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:0) + // Storage: Uniques ClassAccount (r:0 w:1) // Storage: Uniques Attribute (r:0 w:1000) // Storage: Uniques ClassMetadataOf (r:0 w:1) // Storage: Uniques InstanceMetadataOf (r:0 w:1000) // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 12_000 - .saturating_add((16_171_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 12_000 + // Standard Error: 14_000 + .saturating_add((14_879_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 14_000 .saturating_add((1_058_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 12_000 - .saturating_add((953_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 14_000 + .saturating_add((956_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(m as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) @@ -284,7 +292,7 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (55_359_000 as Weight) + (51_248_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -292,7 +300,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (58_254_000 as Weight) + (53_172_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -300,7 +308,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (42_906_000 as Weight) + (39_680_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -308,8 +316,8 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 9_000 - .saturating_add((25_237_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 12_000 + .saturating_add((22_759_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -318,53 +326,55 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (30_153_000 as Weight) + (27_833_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (31_212_000 as Weight) + (27_739_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_class() -> Weight { - (22_689_000 as Weight) + (20_890_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_class() -> Weight { - (22_647_000 as Weight) + (20_848_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: System Account (r:1 w:1) + // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (50_902_000 as Weight) + (51_523_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (23_632_000 as Weight) + (22_034_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques ClassAccount (r:0 w:1) fn force_asset_status() -> Weight { - (22_508_000 as Weight) + (25_877_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (69_942_000 as Weight) + (63_365_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -372,49 +382,49 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (62_314_000 as Weight) + (56_849_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (52_647_000 as Weight) + (47_982_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (50_391_000 as Weight) + (47_340_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_class_metadata() -> Weight { - (50_928_000 as Weight) + (46_897_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_class_metadata() -> Weight { - (46_667_000 as Weight) + (41_745_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (32_111_000 as Weight) + (29_828_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (32_627_000 as Weight) + (29_759_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } From 8f4facada78e51dd7a16b332c2203b30c037d4d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Dec 2021 11:26:37 +0100 Subject: [PATCH 0356/1472] Bump syn from 1.0.81 to 1.0.82 (#10505) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.81 to 1.0.82. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.81...1.0.82) --- 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 | 4 ++-- client/chain-spec/derive/Cargo.toml | 2 +- client/tracing/proc-macro/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/tools/Cargo.toml | 2 +- frame/support/procedural/tools/derive/Cargo.toml | 2 +- primitives/api/proc-macro/Cargo.toml | 2 +- primitives/core/hashing/proc-macro/Cargo.toml | 2 +- primitives/debug-derive/Cargo.toml | 2 +- primitives/npos-elections/solution-type/Cargo.toml | 2 +- primitives/runtime-interface/proc-macro/Cargo.toml | 2 +- primitives/version/proc-macro/Cargo.toml | 2 +- test-utils/derive/Cargo.toml | 2 +- 14 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 797343de27f15..e7d2ae9d50d0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10330,9 +10330,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" dependencies = [ "proc-macro2", "quote", diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index 3ffb70d50ef52..97573c8ca3b0c 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -18,6 +18,6 @@ proc-macro = true proc-macro-crate = "1.1.0" proc-macro2 = "1.0.29" quote = "1.0.10" -syn = "1.0.81" +syn = "1.0.82" [dev-dependencies] diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index 39c22bf856b26..53d463a4f4e50 100644 --- a/client/tracing/proc-macro/Cargo.toml +++ b/client/tracing/proc-macro/Cargo.toml @@ -18,4 +18,4 @@ proc-macro = true proc-macro-crate = "1.1.0" proc-macro2 = "1.0.29" quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.81", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "1.0.82", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index 82f0a6dde2be1..7d95152ea65af 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.81", features = ["full", "visit"] } +syn = { version = "1.0.82", features = ["full", "visit"] } quote = "1.0.10" proc-macro2 = "1.0.29" proc-macro-crate = "1.1.0" diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index b47cf7f97956a..7a1eaa3a08176 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -19,7 +19,7 @@ frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } proc-macro2 = "1.0.29" quote = "1.0.10" Inflector = "0.11.4" -syn = { version = "1.0.81", features = ["full"] } +syn = { version = "1.0.82", features = ["full"] } [features] default = ["std"] diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index c0a3b98632f59..265952ebc4b72 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -15,5 +15,5 @@ targets = ["x86_64-unknown-linux-gnu"] frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" } proc-macro2 = "1.0.29" quote = "1.0.10" -syn = { version = "1.0.81", features = ["full", "visit", "extra-traits"] } +syn = { version = "1.0.82", features = ["full", "visit", "extra-traits"] } proc-macro-crate = "1.1.0" diff --git a/frame/support/procedural/tools/derive/Cargo.toml b/frame/support/procedural/tools/derive/Cargo.toml index 8327134b3fb40..df994e14226d7 100644 --- a/frame/support/procedural/tools/derive/Cargo.toml +++ b/frame/support/procedural/tools/derive/Cargo.toml @@ -17,4 +17,4 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.29" quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.81", features = ["proc-macro" ,"full", "extra-traits", "parsing"] } +syn = { version = "1.0.82", features = ["proc-macro" ,"full", "extra-traits", "parsing"] } diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index c8eaae7c02abe..4afc07833649c 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = { version = "1.0.81", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.29" blake2-rfc = { version = "0.2.18", default-features = false } proc-macro-crate = "1.1.0" diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index dcd2f134519e7..4df40e55bc907 100644 --- a/primitives/core/hashing/proc-macro/Cargo.toml +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.81", features = ["full", "parsing"] } +syn = { version = "1.0.82", features = ["full", "parsing"] } quote = "1.0.6" proc-macro2 = "1.0.29" sp-core-hashing = { version = "4.0.0", path = "../", default-features = false } diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml index a38cc186fb52c..5852bd428d3e7 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = "1.0.81" +syn = "1.0.82" proc-macro2 = "1.0" [features] diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index 160778857f393..cf2a2016500a0 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.81", features = ["full", "visit"] } +syn = { version = "1.0.82", features = ["full", "visit"] } quote = "1.0" proc-macro2 = "1.0.29" proc-macro-crate = "1.1.0" diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 0b5929616bd35..031906486b559 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.81", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "1.0.82", features = ["full", "visit", "fold", "extra-traits"] } quote = "1.0.10" proc-macro2 = "1.0.29" Inflector = "0.11.4" diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index 79fb9b18a2381..df254e64f34cf 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = { version = "1.0.81", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.29" codec = { package = "parity-scale-codec", version = "2.0.0", features = [ "derive" ] } diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index 0b894d92b2bcb..83782a2ba5ff2 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -10,7 +10,7 @@ description = "Substrate test utilities macros" [dependencies] quote = "1.0.10" -syn = { version = "1.0.81", features = ["full"] } +syn = { version = "1.0.82", features = ["full"] } proc-macro-crate = "1.1.0" proc-macro2 = "1.0.29" From 2c1eaaae147fae546c7d1e7cd7177cbaaf196f49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Dec 2021 09:56:16 +0000 Subject: [PATCH 0357/1472] Bump tokio from 1.13.0 to 1.15.0 (#10512) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.13.0 to 1.15.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.13.0...tokio-1.15.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 | 9 ++++----- bin/node/cli/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- test-utils/test-crate/Cargo.toml | 2 +- test-utils/test-runner/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 4 ++-- 14 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7d2ae9d50d0d..51fc8b9d8775f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10572,11 +10572,10 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee" +checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" dependencies = [ - "autocfg 1.0.1", "bytes 1.0.1", "libc", "memchr", @@ -10624,9 +10623,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.3.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ "proc-macro2", "quote", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index a967dd1332116..671388d55d827 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -130,7 +130,7 @@ platforms = "2.0" async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" criterion = { version = "0.3.5", features = [ "async_tokio" ] } -tokio = { version = "1.13", features = ["macros", "time"] } +tokio = { version = "1.15", features = ["macros", "time"] } jsonrpsee-ws-client = "0.4.1" wait-timeout = "0.2" remote-externalities = { path = "../../../utils/frame/remote-externalities" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index cb9d09bbdbc7d..84063fa8fc23f 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.11" regex = "1.5.4" -tokio = { version = "1.13", features = [ "signal", "rt-multi-thread" ] } +tokio = { version = "1.15", features = [ "signal", "rt-multi-thread" ] } futures = "0.3.9" fdlimit = "0.2.1" libp2p = "0.40.0" diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index c69ed21fb3a91..a4bb63a7a2706 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -45,7 +45,7 @@ sp-timestamp = { path = "../../../primitives/timestamp", version = "4.0.0-dev" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } [dev-dependencies] -tokio = { version = "1.13.0", features = ["rt-multi-thread", "macros"] } +tokio = { version = "1.15.0", features = ["rt-multi-thread", "macros"] } sc-basic-authorship = { path = "../../basic-authorship", version = "0.10.0-dev" } substrate-test-runtime-client = { path = "../../../test-utils/runtime/client", version = "2.0.0" } substrate-test-runtime-transaction-pool = { path = "../../../test-utils/runtime/transaction-pool", version = "2.0.0" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index e296c5a4e3da6..6e7463792e7b4 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -57,5 +57,5 @@ sc-network-test = { version = "0.8.0", path = "../network/test" } sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } -tokio = "1.13" +tokio = "1.15" tempfile = "3.1.0" diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 4271c7f5d2b2d..36921944965f6 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -43,7 +43,7 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/a sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -tokio = "1.13" +tokio = "1.15" lazy_static = "1.4.0" [features] diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index f6f08ac581d4f..ae450c2ba9a22 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -19,7 +19,7 @@ pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} serde_json = "1.0.71" -tokio = "1.13" +tokio = "1.15" http = { package = "jsonrpc-http-server", version = "18.0.0" } ipc = { package = "jsonrpc-ipc-server", version = "18.0.0" } ws = { package = "jsonrpc-ws-server", version = "18.0.0" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 4d88f403005e1..0f093970e417e 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -78,7 +78,7 @@ parity-util-mem = { version = "0.10.2", default-features = false, features = [ "primitive-types", ] } async-trait = "0.1.50" -tokio = { version = "1.13", features = ["time", "rt-multi-thread"] } +tokio = { version = "1.15", features = ["time", "rt-multi-thread"] } tempfile = "3.1.0" directories = "4.0.1" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index a8088ebb08cb0..5073f46eb0ef5 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] hex = "0.4" hex-literal = "0.3.4" tempfile = "3.1.0" -tokio = { version = "1.13.0", features = ["time"] } +tokio = { version = "1.15.0", features = ["time"] } log = "0.4.8" fdlimit = "0.2.1" parking_lot = "0.11.2" diff --git a/test-utils/test-crate/Cargo.toml b/test-utils/test-crate/Cargo.toml index 4621332ccc0c1..4e07f92e86ea4 100644 --- a/test-utils/test-crate/Cargo.toml +++ b/test-utils/test-crate/Cargo.toml @@ -12,6 +12,6 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] -tokio = { version = "1.13", features = ["macros"] } +tokio = { version = "1.15", features = ["macros"] } test-utils = { version = "4.0.0-dev", path = "..", package = "substrate-test-utils" } sc-service = { version = "0.10.0-dev", path = "../../client/service" } diff --git a/test-utils/test-runner/Cargo.toml b/test-utils/test-runner/Cargo.toml index eb565fd7b587e..78e17d0f23b6d 100644 --- a/test-utils/test-runner/Cargo.toml +++ b/test-utils/test-runner/Cargo.toml @@ -48,7 +48,7 @@ frame-system = { path = "../../frame/system" } log = "0.4.8" futures = "0.3.16" -tokio = { version = "1.13", features = ["signal"] } +tokio = { version = "1.15", features = ["signal"] } # Calling RPC jsonrpc-core = "18.0" num-traits = "0.2.14" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 969860c3df4be..df6ef5c704194 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -28,7 +28,7 @@ sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } [dev-dependencies] -tokio = { version = "1.13", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.15", features = ["macros", "rt-multi-thread"] } pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", version = "5.0.0-dev" } frame-support = { path = "../../../frame/support", version = "4.0.0-dev" } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 8e491cc634def..6ecaabd720595 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -26,4 +26,4 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } [dev-dependencies] frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } scale-info = "1.0" -tokio = "1.13" +tokio = "1.15" diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index e2104ec5d55aa..43f8b62b9c7b1 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -18,9 +18,9 @@ prometheus = { version = "0.13.0", default-features = false } futures-util = { version = "0.3.17", default-features = false, features = ["io"] } derive_more = "0.99" async-std = { version = "1.10.0", features = ["unstable"] } -tokio = "1.13" +tokio = "1.15" hyper = { version = "0.14.14", default-features = false, features = ["http1", "server", "tcp"] } [dev-dependencies] hyper = { version = "0.14.14", features = ["client"] } -tokio = { version = "1.13", features = ["rt-multi-thread"] } +tokio = { version = "1.15", features = ["rt-multi-thread"] } From bd763f2809e501f561aea55eba1145bca93bd9a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Dec 2021 13:08:23 +0100 Subject: [PATCH 0358/1472] Bump ss58-registry from 1.5.0 to 1.10.0 (#10515) Bumps [ss58-registry](https://github.com/paritytech/ss58-registry) from 1.5.0 to 1.10.0. - [Release notes](https://github.com/paritytech/ss58-registry/releases) - [Changelog](https://github.com/paritytech/ss58-registry/blob/main/CHANGELOG.md) - [Commits](https://github.com/paritytech/ss58-registry/compare/v1.5.0...v1.10.0) --- updated-dependencies: - dependency-name: ss58-registry 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 | 4 ++-- primitives/core/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 51fc8b9d8775f..0e16ece4be628 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9987,9 +9987,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "ss58-registry" -version = "1.5.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66cd4c4bb7ee41dc5b0c13d600574ae825d3a02e8f31326b17ac71558f2c836" +checksum = "c83f0afe7e571565ef9aae7b0e4fb30fcaec4ebb9aea2f00489b772782aa03a4" dependencies = [ "Inflector", "proc-macro2", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 1ec9b5b46f1bb..a74fc75cb2037 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -67,7 +67,7 @@ hex = { version = "0.4", default-features = false, optional = true } twox-hash = { version = "1.6.1", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", "static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } -ss58-registry = { version = "1.5.0", default-features = false } +ss58-registry = { version = "1.10.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../runtime-interface" } From 3fef614506aed18bb14d2036e70faa42f47c2c0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Dec 2021 12:25:01 +0000 Subject: [PATCH 0359/1472] Bump bytes from 1.0.1 to 1.1.0 (#10223) Bumps [bytes](https://github.com/tokio-rs/bytes) from 1.0.1 to 1.1.0. - [Release notes](https://github.com/tokio-rs/bytes/releases) - [Changelog](https://github.com/tokio-rs/bytes/blob/master/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/bytes/compare/v1.0.1...v1.1.0) --- updated-dependencies: - dependency-name: bytes 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 | 58 +++++++++++++++++++------------------- client/offchain/Cargo.toml | 2 +- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e16ece4be628..84584dbab91c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,7 +355,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb4401f0a3622dad2e0763fa79e0eb328bc70fb7dccfdd645341f00d671247d6" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-sink", "futures-util", "memchr", @@ -368,7 +368,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0de5164e5edbf51c45fb8c2d9664ae1c095cce1b265ecf7569093c0d66ef690" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-sink", "futures-util", "memchr", @@ -799,9 +799,9 @@ checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" [[package]] name = "bytes" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cache-padded" @@ -2560,7 +2560,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "fnv", "futures-core", "futures-sink", @@ -2718,7 +2718,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "fnv", "itoa", ] @@ -2729,7 +2729,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "http", "pin-project-lite 0.2.6", ] @@ -2786,7 +2786,7 @@ version = "0.14.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-channel", "futures-core", "futures-util", @@ -2827,7 +2827,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "hyper 0.14.14", "native-tls", "tokio", @@ -3152,7 +3152,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures 0.3.16", "globset", "jsonrpc-core", @@ -3418,7 +3418,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bec54343492ba5940a6c555e512c6721139835d28c59bc22febece72dfd0d9d" dependencies = [ "atomic", - "bytes 1.0.1", + "bytes 1.1.0", "futures 0.3.16", "lazy_static", "libp2p-core", @@ -3538,7 +3538,7 @@ dependencies = [ "asynchronous-codec 0.6.0", "base64 0.13.0", "byteorder", - "bytes 1.0.1", + "bytes 1.1.0", "fnv", "futures 0.3.16", "hex_fmt", @@ -3580,7 +3580,7 @@ checksum = "a2297dc0ca285f3a09d1368bde02449e539b46f94d32d53233f53f6625bcd3ba" dependencies = [ "arrayvec 0.5.2", "asynchronous-codec 0.6.0", - "bytes 1.0.1", + "bytes 1.1.0", "either", "fnv", "futures 0.3.16", @@ -3640,7 +3640,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f2cd64ef597f40e14bfce0497f50ecb63dd6d201c61796daeb4227078834fbf" dependencies = [ "asynchronous-codec 0.6.0", - "bytes 1.0.1", + "bytes 1.1.0", "futures 0.3.16", "libp2p-core", "log 0.4.14", @@ -3657,7 +3657,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8772c7a99088221bb7ca9c5c0574bf55046a7ab4c319f3619b275f28c8fb87a" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "curve25519-dalek 3.0.2", "futures 0.3.16", "lazy_static", @@ -3695,7 +3695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fba1a6ff33e4a274c89a3b1d78b9f34f32af13265cc5c46c16938262d4e945a" dependencies = [ "asynchronous-codec 0.6.0", - "bytes 1.0.1", + "bytes 1.1.0", "futures 0.3.16", "libp2p-core", "log 0.4.14", @@ -3726,7 +3726,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2852b61c90fa8ce3c8fcc2aba76e6cefc20d648f9df29157d6b3a916278ef3e3" dependencies = [ "asynchronous-codec 0.6.0", - "bytes 1.0.1", + "bytes 1.1.0", "futures 0.3.16", "futures-timer 3.0.2", "libp2p-core", @@ -3771,7 +3771,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a877a4ced6d46bf84677e1974e8cf61fb434af73b2e96fb48d6cb6223a4634d8" dependencies = [ "async-trait", - "bytes 1.0.1", + "bytes 1.1.0", "futures 0.3.16", "libp2p-core", "libp2p-swarm", @@ -4387,7 +4387,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d91ec0a2440aaff5f78ec35631a7027d50386c6163aa975f7caa0d5da4b6ff8" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures 0.3.16", "log 0.4.14", "pin-project 1.0.8", @@ -6880,7 +6880,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "prost-derive", ] @@ -6890,7 +6890,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "heck", "itertools", "lazy_static", @@ -6923,7 +6923,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "prost", ] @@ -8241,7 +8241,7 @@ dependencies = [ "async-trait", "asynchronous-codec 0.5.0", "bitflags", - "bytes 1.0.1", + "bytes 1.1.0", "cid", "derive_more", "either", @@ -8338,7 +8338,7 @@ dependencies = [ name = "sc-offchain" version = "4.0.0-dev" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "fnv", "futures 0.3.16", "futures-timer 3.0.2", @@ -9150,7 +9150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "083624472e8817d44d02c0e55df043737ff11f279af924abdf93845717c2b75c" dependencies = [ "base64 0.13.0", - "bytes 1.0.1", + "bytes 1.1.0", "flate2", "futures 0.3.16", "httparse", @@ -10576,7 +10576,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "libc", "memchr", "mio 0.7.13", @@ -10724,7 +10724,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-core", "futures-io", "futures-sink", @@ -11106,7 +11106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35581ff83d4101e58b582e607120c7f5ffb17e632a980b1f38334d76b36908b2" dependencies = [ "asynchronous-codec 0.5.0", - "bytes 1.0.1", + "bytes 1.1.0", "futures-io", "futures-util", ] @@ -11118,7 +11118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f8d425fafb8cd76bc3f22aace4af471d3156301d7508f2107e98fbeae10bc7f" dependencies = [ "asynchronous-codec 0.6.0", - "bytes 1.0.1", + "bytes 1.1.0", "futures-io", "futures-util", ] diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 36921944965f6..b3d5ee045007b 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -bytes = "1.0" +bytes = "1.1" codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } hex = "0.4" fnv = "1.0.6" From 47017abc3884ff1f309a4b98261a20caca7a2b21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Dec 2021 14:10:21 +0100 Subject: [PATCH 0360/1472] Bump rustversion from 1.0.5 to 1.0.6 (#10516) Bumps [rustversion](https://github.com/dtolnay/rustversion) from 1.0.5 to 1.0.6. - [Release notes](https://github.com/dtolnay/rustversion/releases) - [Commits](https://github.com/dtolnay/rustversion/compare/1.0.5...1.0.6) --- updated-dependencies: - dependency-name: rustversion 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 ++-- frame/support/test/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84584dbab91c0..1dc9729f063ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7532,9 +7532,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "rw-stream-sink" diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index ebee4515f3bef..890fa86f97689 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -25,7 +25,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../../primiti sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } trybuild = "1.0.53" pretty_assertions = "1.0.0" -rustversion = "1.0.5" +rustversion = "1.0.6" frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } # The "std" feature for this pallet is never activated on purpose, in order to test construct_runtime error message test-pallet = { package = "frame-support-test-pallet", default-features = false, path = "pallet" } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 53d26c08c1d93..38845340027f1 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -22,7 +22,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-build codec = { package = "parity-scale-codec", version = "2.0.0" } sp-state-machine = { version = "0.10.0", path = "../../state-machine" } trybuild = "1.0.53" -rustversion = "1.0.5" +rustversion = "1.0.6" [dev-dependencies] criterion = "0.3.0" diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index fb978fbbbac1d..137780c3c91e8 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -30,7 +30,7 @@ sp-runtime-interface-test-wasm = { version = "2.0.0", path = "test-wasm" } sp-state-machine = { version = "0.10.0", path = "../state-machine" } sp-core = { version = "4.1.0-dev", path = "../core" } sp-io = { version = "4.0.0-dev", path = "../io" } -rustversion = "1.0.5" +rustversion = "1.0.6" trybuild = "1.0.53" [features] From 0bc1da8a588c06bbfcf3fc23ea0f7c39b1321427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 20 Dec 2021 14:57:32 +0100 Subject: [PATCH 0361/1472] Alter BEEFY primitives to prepare for potential BLS integration (#10466) * Generalize signature. * Fix tests. * Introduce VersionedFinalityProof. * cargo +nightly fmt --all * Rework packing a tad. --- client/beefy/src/notification.rs | 3 +- client/beefy/src/worker.rs | 4 +- primitives/beefy/src/commitment.rs | 91 ++++++++++++++++-------------- primitives/beefy/src/lib.rs | 3 +- primitives/beefy/src/witness.rs | 18 +++--- 5 files changed, 63 insertions(+), 56 deletions(-) diff --git a/client/beefy/src/notification.rs b/client/beefy/src/notification.rs index f394ae6c840a2..7caaa54352401 100644 --- a/client/beefy/src/notification.rs +++ b/client/beefy/src/notification.rs @@ -24,7 +24,8 @@ use sp_runtime::traits::{Block, NumberFor}; use parking_lot::Mutex; /// Stream of signed commitments returned when subscribing. -pub type SignedCommitment = beefy_primitives::SignedCommitment>; +pub type SignedCommitment = + beefy_primitives::SignedCommitment, beefy_primitives::crypto::Signature>; /// Stream of signed commitments returned when subscribing. type SignedCommitmentStream = TracingUnboundedReceiver>; diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index fa48e64c12b4e..bf29a50f19640 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -37,7 +37,7 @@ use sp_runtime::{ use beefy_primitives::{ crypto::{AuthorityId, Public, Signature}, known_payload_ids, BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, SignedCommitment, - ValidatorSet, VersionedCommitment, VoteMessage, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, + ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, }; use crate::{ @@ -330,7 +330,7 @@ where BlockId::Number(round.1), ( BEEFY_ENGINE_ID, - VersionedCommitment::V1(signed_commitment.clone()).encode(), + VersionedFinalityProof::V1(signed_commitment.clone()).encode(), ), ) .is_err() diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index ec1ceeded878c..63c6520d86803 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -18,7 +18,7 @@ use codec::{Decode, Encode, Error, Input}; use sp_std::{cmp, prelude::*}; -use crate::{crypto::Signature, ValidatorSetId}; +use crate::ValidatorSetId; /// Id of different payloads in the [`Commitment`] data pub type BeefyPayloadId = [u8; 2]; @@ -139,17 +139,17 @@ where /// please take a look at custom [`Encode`] and [`Decode`] implementations and /// `CompactSignedCommitment` struct. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct SignedCommitment { +pub struct SignedCommitment { /// The commitment signatures are collected for. pub commitment: Commitment, /// GRANDPA validators' signatures for the commitment. /// /// The length of this `Vec` must match number of validators in the current set (see /// [Commitment::validator_set_id]). - pub signatures: Vec>, + pub signatures: Vec>, } -impl SignedCommitment { +impl SignedCommitment { /// Return the number of collected signatures. pub fn no_of_signatures(&self) -> usize { self.signatures.iter().filter(|x| x.is_some()).count() @@ -163,9 +163,9 @@ const CONTAINER_BIT_SIZE: usize = 8; /// Compressed representation of [`SignedCommitment`], used for encoding efficiency. #[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] -struct CompactSignedCommitment { +struct CompactSignedCommitment { /// The commitment, unchanged compared to regular [`SignedCommitment`]. - commitment: TCommitment, + commitment: Commitment, /// A bitfield representing presence of a signature coming from a validator at some index. /// /// The bit at index `0` is set to `1` in case we have a signature coming from a validator at @@ -183,33 +183,29 @@ struct CompactSignedCommitment { /// Note that in order to associate a `Signature` from this `Vec` with a validator, one needs /// to look at the `signatures_from` bitfield, since some validators might have not produced a /// signature. - signatures_compact: Vec, + signatures_compact: Vec, } -impl<'a, TBlockNumber> CompactSignedCommitment<&'a Commitment> { +impl<'a, TBlockNumber: Clone, TSignature> CompactSignedCommitment { /// Packs a `SignedCommitment` into the compressed `CompactSignedCommitment` format for /// efficient network transport. - fn pack(signed_commitment: &'a SignedCommitment) -> Self { + fn pack(signed_commitment: &'a SignedCommitment) -> Self { let SignedCommitment { commitment, signatures } = signed_commitment; let validator_set_len = signatures.len() as u32; - let mut signatures_from: BitField = vec![]; - let mut signatures_compact: Vec = vec![]; - - for signature in signatures { - match signature { - Some(value) => signatures_compact.push(value.clone()), - None => (), - } - } - let mut bits: Vec = - signatures.iter().map(|x| if x.is_some() { 1 } else { 0 }).collect(); - - // Resize with excess bits for placement purposes - let excess_bits_len = - CONTAINER_BIT_SIZE - (validator_set_len as usize % CONTAINER_BIT_SIZE); - bits.resize(bits.len() + excess_bits_len, 0); + let signatures_compact: Vec<&'a TSignature> = + signatures.iter().filter_map(|x| x.as_ref()).collect(); + let bits = { + let mut bits: Vec = + signatures.iter().map(|x| if x.is_some() { 1 } else { 0 }).collect(); + // Resize with excess bits for placement purposes + let excess_bits_len = + CONTAINER_BIT_SIZE - (validator_set_len as usize % CONTAINER_BIT_SIZE); + bits.resize(bits.len() + excess_bits_len, 0); + bits + }; + let mut signatures_from: BitField = vec![]; let chunks = bits.chunks(CONTAINER_BIT_SIZE); for chunk in chunks { let mut iter = chunk.iter().copied(); @@ -223,13 +219,18 @@ impl<'a, TBlockNumber> CompactSignedCommitment<&'a Commitment> { signatures_from.push(v); } - Self { commitment, signatures_from, validator_set_len, signatures_compact } + Self { + commitment: commitment.clone(), + signatures_from, + validator_set_len, + signatures_compact, + } } /// Unpacks a `CompactSignedCommitment` into the uncompressed `SignedCommitment` form. fn unpack( - temporary_signatures: CompactSignedCommitment>, - ) -> SignedCommitment { + temporary_signatures: CompactSignedCommitment, + ) -> SignedCommitment { let CompactSignedCommitment { commitment, signatures_from, @@ -247,7 +248,7 @@ impl<'a, TBlockNumber> CompactSignedCommitment<&'a Commitment> { bits.truncate(validator_set_len as usize); let mut next_signature = signatures_compact.into_iter(); - let signatures: Vec> = bits + let signatures: Vec> = bits .iter() .map(|&x| if x == 1 { next_signature.next() } else { None }) .collect(); @@ -256,9 +257,10 @@ impl<'a, TBlockNumber> CompactSignedCommitment<&'a Commitment> { } } -impl Encode for SignedCommitment +impl Encode for SignedCommitment where - TBlockNumber: Encode, + TBlockNumber: Encode + Clone, + TSignature: Encode, { fn using_encoded R>(&self, f: F) -> R { let temp = CompactSignedCommitment::pack(self); @@ -266,9 +268,10 @@ where } } -impl Decode for SignedCommitment +impl Decode for SignedCommitment where - TBlockNumber: Decode, + TBlockNumber: Decode + Clone, + TSignature: Decode, { fn decode(input: &mut I) -> Result { let temp = CompactSignedCommitment::decode(input)?; @@ -276,14 +279,18 @@ where } } -/// A [SignedCommitment] with a version number. This variant will be appended -/// to the block justifications for the block for which the signed commitment -/// has been generated. +/// A [SignedCommitment] with a version number. +/// +/// This variant will be appended to the block justifications for the block +/// for which the signed commitment has been generated. +/// +/// Note that this enum is subject to change in the future with introduction +/// of additional cryptographic primitives to BEEFY. #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] -pub enum VersionedCommitment { +pub enum VersionedFinalityProof { #[codec(index = 1)] /// Current active version - V1(SignedCommitment), + V1(SignedCommitment), } #[cfg(test)] @@ -298,8 +305,8 @@ mod tests { use crate::{crypto, KEY_TYPE}; type TestCommitment = Commitment; - type TestSignedCommitment = SignedCommitment; - type TestVersionedCommitment = VersionedCommitment; + type TestSignedCommitment = SignedCommitment; + type TestVersionedFinalityProof = VersionedFinalityProof; // The mock signatures are equivalent to the ones produced by the BEEFY keystore fn mock_signatures() -> (crypto::Signature, crypto::Signature) { @@ -435,14 +442,14 @@ mod tests { signatures: vec![None, None, Some(sigs.0), Some(sigs.1)], }; - let versioned = TestVersionedCommitment::V1(signed.clone()); + let versioned = TestVersionedFinalityProof::V1(signed.clone()); let encoded = codec::Encode::encode(&versioned); assert_eq!(1, encoded[0]); assert_eq!(encoded[1..], codec::Encode::encode(&signed)); - let decoded = TestVersionedCommitment::decode(&mut &*encoded); + let decoded = TestVersionedFinalityProof::decode(&mut &*encoded); assert_eq!(decoded, Ok(versioned)); } diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index cb3cf601a76bc..20f6b9d0d8fb4 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -36,7 +36,8 @@ pub mod mmr; pub mod witness; pub use commitment::{ - known_payload_ids, BeefyPayloadId, Commitment, Payload, SignedCommitment, VersionedCommitment, + known_payload_ids, BeefyPayloadId, Commitment, Payload, SignedCommitment, + VersionedFinalityProof, }; use codec::{Codec, Decode, Encode}; diff --git a/primitives/beefy/src/witness.rs b/primitives/beefy/src/witness.rs index 3ead08bdd7cb3..102a6be09c789 100644 --- a/primitives/beefy/src/witness.rs +++ b/primitives/beefy/src/witness.rs @@ -25,10 +25,7 @@ use sp_std::prelude::*; -use crate::{ - commitment::{Commitment, SignedCommitment}, - crypto::Signature, -}; +use crate::commitment::{Commitment, SignedCommitment}; /// A light form of [SignedCommitment]. /// @@ -60,12 +57,12 @@ impl SignedCommitmentWitness( - signed: SignedCommitment, + pub fn from_signed( + signed: SignedCommitment, merkelize: TMerkelize, - ) -> (Self, Vec>) + ) -> (Self, Vec>) where - TMerkelize: FnOnce(&[Option]) -> TMerkleRoot, + TMerkelize: FnOnce(&[Option]) -> TMerkleRoot, { let SignedCommitment { commitment, signatures } = signed; let signed_by = signatures.iter().map(|s| s.is_some()).collect(); @@ -87,8 +84,9 @@ mod tests { use crate::{crypto, known_payload_ids, Payload, KEY_TYPE}; type TestCommitment = Commitment; - type TestSignedCommitment = SignedCommitment; - type TestSignedCommitmentWitness = SignedCommitmentWitness>>; + type TestSignedCommitment = SignedCommitment; + type TestSignedCommitmentWitness = + SignedCommitmentWitness>>; // The mock signatures are equivalent to the ones produced by the BEEFY keystore fn mock_signatures() -> (crypto::Signature, crypto::Signature) { From 680fc3feabc73869f58b31d8b48cb775fb7ff9b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Dec 2021 15:27:14 +0100 Subject: [PATCH 0362/1472] Bump hyper from 0.14.14 to 0.14.16 (#10462) Bumps [hyper](https://github.com/hyperium/hyper) from 0.14.14 to 0.14.16. - [Release notes](https://github.com/hyperium/hyper/releases) - [Changelog](https://github.com/hyperium/hyper/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/hyper/compare/v0.14.14...v0.14.16) --- updated-dependencies: - dependency-name: hyper 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 +++++++++++----------- client/offchain/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1dc9729f063ea..4af488ca98db6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2556,9 +2556,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55" +checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" dependencies = [ "bytes 1.1.0", "fnv", @@ -2782,9 +2782,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.14" +version = "0.14.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b" +checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" dependencies = [ "bytes 1.1.0", "futures-channel", @@ -2812,7 +2812,7 @@ checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" dependencies = [ "ct-logs", "futures-util", - "hyper 0.14.14", + "hyper 0.14.16", "log 0.4.14", "rustls", "rustls-native-certs", @@ -2828,7 +2828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes 1.1.0", - "hyper 0.14.14", + "hyper 0.14.16", "native-tls", "tokio", "tokio-native-tls", @@ -3051,7 +3051,7 @@ checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" dependencies = [ "derive_more", "futures 0.3.16", - "hyper 0.14.14", + "hyper 0.14.16", "hyper-tls", "jsonrpc-core", "jsonrpc-pubsub", @@ -3107,7 +3107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" dependencies = [ "futures 0.3.16", - "hyper 0.14.14", + "hyper 0.14.16", "jsonrpc-core", "jsonrpc-server-utils", "log 0.4.14", @@ -3215,7 +3215,7 @@ dependencies = [ "beef", "futures-channel", "futures-util", - "hyper 0.14.14", + "hyper 0.14.16", "log 0.4.14", "serde", "serde_json", @@ -8343,7 +8343,7 @@ dependencies = [ "futures 0.3.16", "futures-timer 3.0.2", "hex", - "hyper 0.14.14", + "hyper 0.14.16", "hyper-rustls", "lazy_static", "num_cpus", @@ -10168,7 +10168,7 @@ dependencies = [ "async-std", "derive_more", "futures-util", - "hyper 0.14.14", + "hyper 0.14.16", "log 0.4.14", "prometheus", "tokio", diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index b3d5ee045007b..38834181b163d 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -30,7 +30,7 @@ sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } threadpool = "1.7" -hyper = { version = "0.14.14", features = ["stream", "http2"] } +hyper = { version = "0.14.16", features = ["stream", "http2"] } hyper-rustls = "0.22.1" once_cell = "1.8" tracing = "0.1.29" diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 43f8b62b9c7b1..b9a3a5a5d1974 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -19,8 +19,8 @@ futures-util = { version = "0.3.17", default-features = false, features = ["io"] derive_more = "0.99" async-std = { version = "1.10.0", features = ["unstable"] } tokio = "1.15" -hyper = { version = "0.14.14", default-features = false, features = ["http1", "server", "tcp"] } +hyper = { version = "0.14.16", default-features = false, features = ["http1", "server", "tcp"] } [dev-dependencies] -hyper = { version = "0.14.14", features = ["client"] } +hyper = { version = "0.14.16", features = ["client"] } tokio = { version = "1.15", features = ["rt-multi-thread"] } From d18705ee7b5b654d3947558fea6dbd0701ac3ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 20 Dec 2021 20:49:18 +0100 Subject: [PATCH 0363/1472] SlotDuration: Always fetch the slot duration from the runtime (#10509) * SlotDuration: Always fetch the slot duration from the runtime The slot duration should always be fetched from the runtime instead of being cached in the db. The slot duration is only fetched on startup of the node, so the performance isn't that important. This is especially helpful for the case when the slot duration of a chain should be changed through a runtime upgrade (there be dragons, so take care). * Fix docs * Remove logging * Fix warning --- Cargo.lock | 1 - bin/node/cli/src/service.rs | 2 +- client/consensus/aura/src/lib.rs | 7 ++- client/consensus/babe/rpc/src/lib.rs | 2 +- client/consensus/babe/src/lib.rs | 50 ++++++++--------- client/consensus/babe/src/tests.rs | 2 +- .../manual-seal/src/consensus/babe.rs | 4 +- client/consensus/slots/Cargo.toml | 1 - client/consensus/slots/src/lib.rs | 55 ++----------------- primitives/consensus/aura/src/lib.rs | 2 - primitives/consensus/babe/src/lib.rs | 2 - primitives/consensus/common/src/lib.rs | 3 - test-utils/test-runner/src/client.rs | 2 +- test-utils/test-runner/src/lib.rs | 2 +- 14 files changed, 40 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4af488ca98db6..f4ab495c24507 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8014,7 +8014,6 @@ dependencies = [ "sc-client-api", "sc-consensus", "sc-telemetry", - "sp-api", "sp-arithmetic", "sp-blockchain", "sp-consensus", diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index fbc91c5f7d2e7..fabf8d0adfdc5 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -196,7 +196,7 @@ pub fn new_partial( let justification_import = grandpa_block_import.clone(); let (block_import, babe_link) = sc_consensus_babe::block_import( - sc_consensus_babe::Config::get_or_compute(&*client)?, + sc_consensus_babe::Config::get(&*client)?, grandpa_block_import, client.clone(), )?; diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index ec577b0844313..4579b2d73da18 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -85,7 +85,7 @@ type AuthorityId

=

::Public; /// Slot duration type for Aura. pub type SlotDuration = sc_consensus_slots::SlotDuration; -/// Get type of `SlotDuration` for Aura. +/// Get the slot duration for Aura. pub fn slot_duration(client: &C) -> CResult where A: Codec, @@ -93,7 +93,10 @@ where C: AuxStore + ProvideRuntimeApi + UsageProvider, C::Api: AuraApi, { - SlotDuration::get_or_compute(client, |a, b| a.slot_duration(b).map_err(Into::into)) + let best_block_id = BlockId::Hash(client.usage_info().chain.best_hash); + let slot_duration = client.runtime_api().slot_duration(&best_block_id)?; + + Ok(SlotDuration::new(slot_duration)) } /// Get slot author for given block along with authorities. diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index eeec7b86b1f14..463b05ef9cd2d 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -247,7 +247,7 @@ mod tests { let builder = TestClientBuilder::new(); let (client, longest_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); - let config = Config::get_or_compute(&*client).expect("config available"); + let config = Config::get(&*client).expect("config available"); let (_, link) = block_import(config.clone(), client.clone(), client.clone()) .expect("can initialize block-import"); diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 21c3c883a39dd..7a05c7a92678a 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -329,7 +329,9 @@ pub struct BabeIntermediate { /// Intermediate key for Babe engine. pub static INTERMEDIATE_KEY: &[u8] = b"babe1"; -/// A slot duration. Create with `get_or_compute`. +/// A slot duration. +/// +/// Create with [`Self::get`]. // FIXME: Once Rust has higher-kinded types, the duplication between this // and `super::babe::Config` can be eliminated. // https://github.com/paritytech/substrate/issues/2434 @@ -337,39 +339,33 @@ pub static INTERMEDIATE_KEY: &[u8] = b"babe1"; pub struct Config(sc_consensus_slots::SlotDuration); impl Config { - /// Either fetch the slot duration from disk or compute it from the genesis - /// state. - pub fn get_or_compute(client: &C) -> ClientResult + /// Fetch the config from the runtime. + pub fn get(client: &C) -> ClientResult where C: AuxStore + ProvideRuntimeApi + UsageProvider, C::Api: BabeApi, { trace!(target: "babe", "Getting slot duration"); - match sc_consensus_slots::SlotDuration::get_or_compute(client, |a, b| { - let has_api_v1 = a.has_api_with::, _>(&b, |v| v == 1)?; - let has_api_v2 = a.has_api_with::, _>(&b, |v| v == 2)?; - if has_api_v1 { - #[allow(deprecated)] - { - Ok(a.configuration_before_version_2(b)?.into()) - } - } else if has_api_v2 { - a.configuration(b).map_err(Into::into) - } else { - Err(sp_blockchain::Error::VersionInvalid( - "Unsupported or invalid BabeApi version".to_string(), - )) + let best_block_id = BlockId::Hash(client.usage_info().chain.best_hash); + let runtime_api = client.runtime_api(); + + let version = runtime_api.api_version::>(&best_block_id)?; + + let slot_duration = if version == Some(1) { + #[allow(deprecated)] + { + runtime_api.configuration_before_version_2(&best_block_id)?.into() } - }) - .map(Self) - { - Ok(s) => Ok(s), - Err(s) => { - warn!(target: "babe", "Failed to get slot duration"); - Err(s) - }, - } + } else if version == Some(2) { + runtime_api.configuration(&best_block_id)? + } else { + return Err(sp_blockchain::Error::VersionInvalid( + "Unsupported or invalid BabeApi version".to_string(), + )) + }; + + Ok(Self(sc_consensus_slots::SlotDuration::new(slot_duration))) } /// Get the inner slot duration diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 73cc453812eae..23c34d21ec7b3 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -297,7 +297,7 @@ impl TestNetFactory for BabeTestNet { ) { let client = client.as_client(); - let config = Config::get_or_compute(&*client).expect("config available"); + let config = Config::get(&*client).expect("config available"); let (block_import, link) = crate::block_import(config, client.clone(), client.clone()) .expect("can initialize block-import"); diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index e06c544aaedc3..499a82c63e402 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -154,7 +154,7 @@ where return Err(Error::StringError("Cannot supply empty authority set!".into())) } - let config = Config::get_or_compute(&*client)?; + let config = Config::get(&*client)?; Ok(Self { config, client, keystore, epoch_changes, authorities }) } @@ -327,7 +327,7 @@ impl SlotTimestampProvider { C: AuxStore + HeaderBackend + ProvideRuntimeApi + UsageProvider, C::Api: BabeApi, { - let slot_duration = Config::get_or_compute(&*client)?.slot_duration; + let slot_duration = Config::get(&*client)?.slot_duration; let info = client.info(); // looks like this isn't the first block, rehydrate the fake time. diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index bf2bd59bb91e7..782e979ed6ef1 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -23,7 +23,6 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } -sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 3174eacaff4d6..905165aa9e369 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -38,7 +38,6 @@ use futures_timer::Delay; use log::{debug, error, info, warn}; use sc_consensus::{BlockImport, JustificationSyncLink}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO, CONSENSUS_WARN}; -use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_arithmetic::traits::BaseArithmetic; use sp_consensus::{CanAuthorWith, Proposer, SelectChain, SlotData, SyncOracle}; use sp_consensus_slots::Slot; @@ -537,9 +536,7 @@ where SlotDurationInvalid(SlotDuration), } -/// A slot duration. Create with [`get_or_compute`](Self::get_or_compute). -// The internal member should stay private here to maintain invariants of -// `get_or_compute`. +/// A slot duration. Create with [`Self::new`]. #[derive(Clone, Copy, Debug, Encode, Decode, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct SlotDuration(T); @@ -554,54 +551,12 @@ impl SlotData for SlotDuration { fn slot_duration(&self) -> std::time::Duration { self.0.slot_duration() } - - const SLOT_KEY: &'static [u8] = T::SLOT_KEY; } impl SlotDuration { - /// Either fetch the slot duration from disk or compute it from the - /// genesis state. - /// - /// `slot_key` is marked as `'static`, as it should really be a - /// compile-time constant. - pub fn get_or_compute(client: &C, cb: CB) -> sp_blockchain::Result - where - C: sc_client_api::backend::AuxStore + sc_client_api::UsageProvider, - C: ProvideRuntimeApi, - CB: FnOnce(ApiRef, &BlockId) -> sp_blockchain::Result, - T: SlotData + Encode + Decode + Debug, - { - let slot_duration = match client.get_aux(T::SLOT_KEY)? { - Some(v) => ::decode(&mut &v[..]).map(SlotDuration).map_err(|_| { - sp_blockchain::Error::Backend({ - error!(target: "slots", "slot duration kept in invalid format"); - "slot duration kept in invalid format".to_string() - }) - }), - None => { - let best_hash = client.usage_info().chain.best_hash; - let slot_duration = cb(client.runtime_api(), &BlockId::hash(best_hash))?; - - info!( - "⏱ Loaded block-time = {:?} from block {:?}", - slot_duration.slot_duration(), - best_hash, - ); - - slot_duration - .using_encoded(|s| client.insert_aux(&[(T::SLOT_KEY, &s[..])], &[]))?; - - Ok(SlotDuration(slot_duration)) - }, - }?; - - if slot_duration.slot_duration() == Default::default() { - return Err(sp_blockchain::Error::Application(Box::new(Error::SlotDurationInvalid( - slot_duration, - )))) - } - - Ok(slot_duration) + /// Create a new instance of `Self`. + pub fn new(val: T) -> Self { + Self(val) } /// Returns slot data value. @@ -875,7 +830,7 @@ impl BackoffAuthoringBlocksStrategy for () { #[cfg(test)] mod test { use super::*; - use sp_api::NumberFor; + use sp_runtime::traits::NumberFor; use std::time::{Duration, Instant}; use substrate_test_runtime_client::runtime::{Block, Header}; diff --git a/primitives/consensus/aura/src/lib.rs b/primitives/consensus/aura/src/lib.rs index e6a319c1d1590..b85443e0917e4 100644 --- a/primitives/consensus/aura/src/lib.rs +++ b/primitives/consensus/aura/src/lib.rs @@ -117,6 +117,4 @@ impl sp_consensus::SlotData for SlotDuration { fn slot_duration(&self) -> std::time::Duration { std::time::Duration::from_millis(self.0) } - - const SLOT_KEY: &'static [u8] = b"aura_slot_duration"; } diff --git a/primitives/consensus/babe/src/lib.rs b/primitives/consensus/babe/src/lib.rs index 560866cfb2ab5..1971563ff198b 100644 --- a/primitives/consensus/babe/src/lib.rs +++ b/primitives/consensus/babe/src/lib.rs @@ -242,8 +242,6 @@ impl sp_consensus::SlotData for BabeGenesisConfiguration { fn slot_duration(&self) -> std::time::Duration { std::time::Duration::from_millis(self.slot_duration) } - - const SLOT_KEY: &'static [u8] = b"babe_configuration"; } /// Configuration data used by the BABE consensus engine. diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index ce834fd0a47f4..456ba965f4aa0 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -332,7 +332,4 @@ impl CanAuthorWith for NeverCanAuthor { pub trait SlotData { /// Gets the slot duration. fn slot_duration(&self) -> sp_std::time::Duration; - - /// The static slot key - const SLOT_KEY: &'static [u8]; } diff --git a/test-utils/test-runner/src/client.rs b/test-utils/test-runner/src/client.rs index 21039d3bc4b1b..b4a82b1c8950b 100644 --- a/test-utils/test-runner/src/client.rs +++ b/test-utils/test-runner/src/client.rs @@ -127,7 +127,7 @@ where None, )?; - let slot_duration = sc_consensus_babe::Config::get_or_compute(&*client)?; + let slot_duration = sc_consensus_babe::Config::get(&*client)?; let (block_import, babe_link) = sc_consensus_babe::block_import( slot_duration.clone(), grandpa_block_import, diff --git a/test-utils/test-runner/src/lib.rs b/test-utils/test-runner/src/lib.rs index 9f51442ed743b..d5e2873fe412f 100644 --- a/test-utils/test-runner/src/lib.rs +++ b/test-utils/test-runner/src/lib.rs @@ -154,7 +154,7 @@ //! sc_finality_grandpa::block_import(client.clone(), &(client.clone() as Arc<_>), select_chain.clone())?; //! //! let (block_import, babe_link) = sc_consensus_babe::block_import( -//! sc_consensus_babe::Config::get_or_compute(&*client)?, +//! sc_consensus_babe::Config::get(&*client)?, //! grandpa_block_import, //! client.clone(), //! )?; From 433bcb1dc3739edcf55994e517b067d039757f17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Dec 2021 11:17:06 +0100 Subject: [PATCH 0364/1472] Bump serde from 1.0.131 to 1.0.132 (#10517) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.131 to 1.0.132. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.131...v1.0.132) --- 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 ++++---- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- frame/merkle-mountain-range/primitives/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/test/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- frame/transaction-payment/asset-tx-payment/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- primitives/application-crypto/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/serializer/Cargo.toml | 2 +- primitives/storage/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 2 +- primitives/version/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 48 files changed, 51 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4ab495c24507..f609823d59b9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8893,9 +8893,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.131" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" +checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008" dependencies = [ "serde_derive", ] @@ -8921,9 +8921,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.131" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" +checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" dependencies = [ "proc-macro2", "quote", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 3ffb0f92c843e..114742990bcdc 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -16,7 +16,7 @@ node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } -serde = "1.0.131" +serde = "1.0.132" serde_json = "1.0.71" structopt = "0.3" derive_more = "0.99.16" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 671388d55d827..f955076e122b5 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -35,7 +35,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies codec = { package = "parity-scale-codec", version = "2.0.0" } -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } futures = "0.3.16" hex-literal = "0.3.4" log = "0.4.8" diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index b5a8144faba8e..847f054f4663e 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -10,7 +10,7 @@ description = "RPC for the BEEFY Client gadget for substrate" [dependencies] futures = "0.3.16" log = "0.4" -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 4ef14decf9eb3..601fb5b4da9e9 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -17,7 +17,7 @@ sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } impl-trait-for-tuples = "0.2.1" sc-network = { version = "0.10.0-dev", path = "../network" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.71" sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 84063fa8fc23f..f92f7b51c8b7f 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -41,7 +41,7 @@ names = { version = "0.12.0", default-features = false } structopt = "0.3.25" sc-tracing = { version = "4.0.0-dev", path = "../tracing" } chrono = "0.4.10" -serde = "1.0.131" +serde = "1.0.132" thiserror = "1.0.30" rpassword = "5.0.0" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 654e47b727565..8d0ceb2b615bd 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -25,7 +25,7 @@ sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } num-bigint = "0.2.3" num-rational = "0.2.2" num-traits = "0.2.8" -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } sp-io = { version = "4.0.0", path = "../../../primitives/io" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 28b27db82c7dc..61321e684fa9e 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -19,7 +19,7 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } -serde = { version = "1.0.131", features=["derive"] } +serde = { version = "1.0.132", features=["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sp-runtime = { version = "4.0.0", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index d82d5b9574dd0..436f9227d35ab 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -46,7 +46,7 @@ rand = "0.7.2" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.71" smallvec = "1.7.0" sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 8a2feb2581b07..f8f8e333a9c68 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -27,7 +27,7 @@ sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-runtime = { path = "../../primitives/runtime", version = "4.0.0" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.71" sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 0f093970e417e..bfe053152ba4b 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -33,7 +33,7 @@ futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.8" hash-db = "0.15.2" -serde = "1.0.131" +serde = "1.0.132" serde_json = "1.0.71" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 1566777009c3d..859173ca77eb8 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -24,7 +24,7 @@ sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } serde_json = "1.0.71" -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index c4e03e94a2b13..2001026a1201f 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -22,7 +22,7 @@ libp2p = { version = "0.40.0", default-features = false, features = ["dns-async- log = "0.4.8" pin-project = "1.0.8" rand = "0.7.2" -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.71" chrono = "0.4.19" thiserror = "1.0.30" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 861e1acc68c3e..55ecd0a1481a9 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -23,7 +23,7 @@ once_cell = "1.8.0" parking_lot = "0.11.2" regex = "1.5.4" rustc-hash = "1.1.0" -serde = "1.0.131" +serde = "1.0.132" thiserror = "1.0.30" tracing = "0.1.29" tracing-log = "0.1.2" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 2399fb449c7f0..43a368145a93f 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -30,7 +30,7 @@ sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transact sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } linked-hash-map = "0.5.4" retain_mut = "0.1.4" diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 39e126250a9ee..e79aa4c7f804b 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -11,7 +11,7 @@ description = "Transaction pool client facing API." [dependencies] futures = { version = "0.3.1" } log = { version = "0.4.8" } -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } thiserror = { version = "1.0.30" } sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index a4ba9d1fbdaea..b36b3ba873ae9 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -13,7 +13,7 @@ codec = { version = "2.2.0", package = "parity-scale-codec", default-features = libsecp256k1 = { version = "0.7.0", default-features = false } log = { version = "0.4.13", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.131", optional = true } +serde = { version = "1.0.132", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index e9a748b2e80d7..753e90faad2ed 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -10,7 +10,7 @@ description = "BEEFY FRAME pallet" [dependencies] codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.131", optional = true } +serde = { version = "1.0.132", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 0c9306b8b5bd5..ef8e1f3a2f170 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index cda883ccf728f..6991ff16939b7 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } log = { version = "0.4.14", default-features = false } -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 291fd5311aa57..c6f9124c2a275 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 40b211a19cd03..8084a63cc276f 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -17,7 +17,7 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -serde = { version = "1.0.131", optional = true } +serde = { version = "1.0.132", optional = true } sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index e09d5a57d5cab..c72a1c0ec662a 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.131", optional = true } +serde = { version = "1.0.132", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index c049870ecb097..7aea7a0058e90 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-metadata = { version = "14.0.0", default-features = false, features = ["v14"] } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 890fa86f97689..975e0830ab0e4 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.131", default-features = false, features = ["derive"] } +serde = { version = "1.0.132", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../../primitives/arithmetic" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index cc1378a35c626..7c1526bbd9d40 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 935ab907a8a11..42d58ec38844e 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.131", features = ["derive"], optional = true } +serde = { version = "1.0.132", features = ["derive"], optional = true } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index f4b9b9a18019f..7679dae8e6ea9 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.131", optional = true } +serde = { version = "1.0.132", optional = true } smallvec = "1.7.0" sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 9c26fc8033f73..3226ec09d0145 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -26,7 +26,7 @@ pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, # Other dependencies codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.131", optional = true } +serde = { version = "1.0.132", optional = true } [dev-dependencies] smallvec = "1.7.0" diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 9bbc055dae1d9..68b391387f87d 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.131", optional = true } +serde = { version = "1.0.132", optional = true } hex-literal = { version = "0.3.4", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 53cad5edffc36..a4e211283e13b 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = "max-encoded-len", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.131", features = ["derive"], optional = true } +serde = { version = "1.0.132", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.1" sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index 750f8874493e4..75766905d14f7 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "4.0.0", default-features = false, path = "../io" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index a035b03b82a2d..b1ec8639248e9 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -23,7 +23,7 @@ integer-sqrt = "0.1.2" static_assertions = "1.1.0" num-traits = { version = "0.2.8", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } [dev-dependencies] diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 19e94a8da21d9..330ce775eb065 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -27,7 +27,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-keystore = { version = "0.10.0", default-features = false, path = "../../keystore", optional = true } sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../timestamp", optional = true } -serde = { version = "1.0.131", features = ["derive"], optional = true } +serde = { version = "1.0.132", features = ["derive"], optional = true } async-trait = { version = "0.1.50", optional = true } [features] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index a74fc75cb2037..a6b2e21ce77fe 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.11", default-features = false } -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } primitive-types = { version = "0.10.1", default-features = false, features = [ "codec", diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index 80607a0beb196..e12d7a52695df 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.14.1", default-features = false, features = ["derive-codec"] } log = { version = "0.4.8", optional = true } -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 3ee25f8ab816e..d255688b56c78 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index fdc019bad4b6b..51aaa990456e9 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.131", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } sp-core = { version = "4.1.0-dev", path = "../core" } rustc-hash = "1.1.0" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index a30bd08452d88..deb877abcca08 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } diff --git a/primitives/serializer/Cargo.toml b/primitives/serializer/Cargo.toml index 89ddb28df2723..40f4d19e047eb 100644 --- a/primitives/serializer/Cargo.toml +++ b/primitives/serializer/Cargo.toml @@ -14,5 +14,5 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = "1.0.131" +serde = "1.0.132" serde_json = "1.0.71" diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index 98c8d693e9d64..81e4140bbd36f 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-std = { version = "4.0.0", default-features = false, path = "../std" } -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } impl-serde = { version = "0.3.1", optional = true } ref-cast = "1.0.0" sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 5bc81637e82ae..5a045185e7cec 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index b6ad02d4331f8..585d089a54b5c 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] impl-serde = { version = "0.3.1", optional = true } -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index c5a4a27c2ee9c..fa0ae85e706c4 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0" } futures = "0.3.16" hex = "0.4" -serde = "1.0.131" +serde = "1.0.132" serde_json = "1.0.71" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } sc-client-db = { version = "0.10.0-dev", features = [ diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index ccaae6e692437..35c1291f38fb5 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -48,7 +48,7 @@ sp-externalities = { version = "0.10.0", default-features = false, path = "../.. # 3rd party cfg-if = "1.0" log = { version = "0.4.14", default-features = false } -serde = { version = "1.0.131", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } [dev-dependencies] sc-block-builder = { version = "0.10.0-dev", path = "../../client/block-builder" } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index fce53612e3cef..bf231eb677139 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -27,7 +27,7 @@ sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machi codec = { version = "2.0.0", package = "parity-scale-codec" } structopt = "0.3.25" chrono = "0.4" -serde = "1.0.131" +serde = "1.0.132" handlebars = "4.1.4" Inflector = "0.11.4" linked-hash-map = "0.5.4" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index df6ef5c704194..f4e26b4db39b1 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -20,7 +20,7 @@ frame-support = { path = "../../../frame/support", optional = true, version = "4 log = "0.4.11" codec = { package = "parity-scale-codec", version = "2.0.0" } serde_json = "1.0" -serde = "1.0.131" +serde = "1.0.132" sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 8f84750f8ebfe..0c96d727cee09 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.8" parity-scale-codec = { version = "2.3.1" } -serde = "1.0.131" +serde = "1.0.132" structopt = "0.3.25" sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../../client/service" } From 7fd0430d74628ae33f2da3808684c5d2c1045145 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Dec 2021 12:38:58 +0100 Subject: [PATCH 0365/1472] Bump frame-metadata from 14.0.0 to 14.2.0 (#10519) Bumps [frame-metadata](https://github.com/paritytech/frame-metadata) from 14.0.0 to 14.2.0. - [Release notes](https://github.com/paritytech/frame-metadata/releases) - [Changelog](https://github.com/paritytech/frame-metadata/blob/main/CHANGELOG.md) - [Commits](https://github.com/paritytech/frame-metadata/commits) --- updated-dependencies: - dependency-name: frame-metadata 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 | 4 ++-- frame/support/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f609823d59b9e..5eb29dd2c8b44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2039,9 +2039,9 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "14.0.0" +version = "14.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96616f82e069102b95a72c87de4c84d2f87ef7f0f20630e78ce3824436483110" +checksum = "37ed5e5c346de62ca5c184b4325a6600d1eaca210666e4606fe4e449574978d0" dependencies = [ "cfg-if 1.0.0", "parity-scale-codec", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 7aea7a0058e90..efc7caab1bd4e 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.132", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -frame-metadata = { version = "14.0.0", default-features = false, features = ["v14"] } +frame-metadata = { version = "14.2.0", default-features = false, features = ["v14"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } From bdfbbb9718a17a7cba504c2e5b56b6be6898c2f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Dec 2021 12:41:45 +0100 Subject: [PATCH 0366/1472] Bump git2 from 0.13.23 to 0.13.25 (#10522) Bumps [git2](https://github.com/rust-lang/git2-rs) from 0.13.23 to 0.13.25. - [Release notes](https://github.com/rust-lang/git2-rs/releases) - [Commits](https://github.com/rust-lang/git2-rs/compare/0.13.23...0.13.25) --- updated-dependencies: - dependency-name: git2 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 ++++---- utils/frame/generate-bags/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5eb29dd2c8b44..18cfe18935514 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2511,9 +2511,9 @@ checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] name = "git2" -version = "0.13.23" +version = "0.13.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8057932925d3a9d9e4434ea016570d37420ddb1ceed45a174d577f24ed6700" +checksum = "f29229cc1b24c0e6062f6e742aa3e256492a5323365e5ed3413599f8a5eff7d6" dependencies = [ "bitflags", "libc", @@ -3365,9 +3365,9 @@ checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" [[package]] name = "libgit2-sys" -version = "0.12.24+1.3.0" +version = "0.12.26+1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddbd6021eef06fb289a8f54b3c2acfdd85ff2a585dfbb24b8576325373d2152c" +checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494" dependencies = [ "cc", "libc", diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 6a512842129e7..594683938517b 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -21,6 +21,6 @@ sp-io = { version = "4.0.0", path = "../../../primitives/io" } # third party chrono = { version = "0.4.19" } -git2 = { version = "0.13.23", default-features = false } +git2 = { version = "0.13.25", default-features = false } num-format = { version = "0.4.0" } structopt = "0.3.25" From 6605aed9f74cf90e6e4e0df38c1a2852b16913dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Dec 2021 12:36:11 +0000 Subject: [PATCH 0367/1472] Bump clap from 2.33.3 to 2.34.0 (#10523) Bumps [clap](https://github.com/clap-rs/clap) from 2.33.3 to 2.34.0. - [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/v2.33.3...v2.34.0) --- updated-dependencies: - dependency-name: clap 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 | 27 +++++++++---------------- frame/bags-list/remote-tests/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18cfe18935514..44d4e9a609281 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,15 +91,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "ansi_term" version = "0.12.1" @@ -908,7 +899,7 @@ dependencies = [ name = "chain-spec-builder" version = "2.0.0" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "node-cli", "rand 0.7.3", "sc-chain-spec", @@ -973,11 +964,11 @@ dependencies = [ [[package]] name = "clap" -version = "2.33.3" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "ansi_term 0.11.0", + "ansi_term", "atty", "bitflags", "strsim 0.8.0", @@ -6777,7 +6768,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0cfe1b2403f172ba0f234e500906ee0a3e493fb81092dac23ebefe129301cc" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "ctor", "diff", "output_vt100", @@ -8204,7 +8195,7 @@ dependencies = [ name = "sc-informant" version = "0.10.0-dev" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "futures 0.3.16", "futures-timer 3.0.2", "log 0.4.14", @@ -8638,7 +8629,7 @@ dependencies = [ name = "sc-tracing" version = "4.0.0-dev" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "atty", "chrono", "criterion", @@ -10311,7 +10302,7 @@ dependencies = [ name = "substrate-wasm-builder" version = "5.0.0-dev" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "build-helper", "cargo_metadata", "sp-maybe-compressed-blob", @@ -10816,7 +10807,7 @@ version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "chrono", "lazy_static", "matchers", diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 8e6a24674d0af..b120b32d5d4b1 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -34,4 +34,4 @@ remote-externalities = { path = "../../../utils/frame/remote-externalities", ver tokio = { version = "1", features = ["macros"] } log = "0.4.14" structopt = "0.3.25" -clap = "2.33.3" +clap = "2.34.0" From 82cc3746450ae9722a249f4ddf83b8de59ba6e0d Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 21 Dec 2021 16:34:32 +0200 Subject: [PATCH 0368/1472] Beefy: Provide well-formed `ValidatorSet` (#10445) * beefy: provide well-formed ValidatorSet * pallet-beefy: use well-formed ValidatorSet * pallet-beefy-mmr: use well-formed ValidatorSet * beefy-gadget: fail votes early when ValidatorSet empty * beefy: small efficiency improvements * address review comments Signed-off-by: acatangiu --- client/beefy/src/keystore.rs | 4 +-- client/beefy/src/round.rs | 58 ++++++++++++------------------ client/beefy/src/worker.rs | 69 ++++++++++++++++++++++-------------- frame/beefy-mmr/src/tests.rs | 7 ++-- frame/beefy/src/lib.rs | 20 ++++++----- frame/beefy/src/tests.rs | 31 ++++++++-------- primitives/beefy/src/lib.rs | 56 +++++++++++++++++++++++++---- 7 files changed, 146 insertions(+), 99 deletions(-) diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index 7ee1ceb46bc35..eaae17e2015af 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -89,8 +89,8 @@ impl BeefyKeystore { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; let pk: Vec = SyncCryptoStore::ecdsa_public_keys(&*store, KEY_TYPE) - .iter() - .map(|k| Public::from(k.clone())) + .drain(..) + .map(Public::from) .collect(); Ok(pk) diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index db41f0f465db6..b0df365b4e6f1 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -74,15 +74,15 @@ where N: Ord + AtLeast32BitUnsigned + MaybeDisplay + Clone, { pub(crate) fn validator_set_id(&self) -> ValidatorSetId { - self.validator_set.id + self.validator_set.id() } - pub(crate) fn validators(&self) -> Vec { - self.validator_set.validators.clone() + pub(crate) fn validators(&self) -> &[Public] { + self.validator_set.validators() } pub(crate) fn add_vote(&mut self, round: &(H, N), vote: (Public, Signature)) -> bool { - if self.validator_set.validators.iter().any(|id| vote.0 == *id) { + if self.validator_set.validators().iter().any(|id| vote.0 == *id) { self.rounds.entry(round.clone()).or_default().add_vote(vote) } else { false @@ -93,7 +93,7 @@ where let done = self .rounds .get(round) - .map(|tracker| tracker.is_done(threshold(self.validator_set.validators.len()))) + .map(|tracker| tracker.is_done(threshold(self.validator_set.len()))) .unwrap_or(false); debug!(target: "beefy", "🥩 Round #{} done: {}", round.1, done); @@ -108,7 +108,7 @@ where Some( self.validator_set - .validators + .validators() .iter() .map(|authority_id| { signatures.iter().find_map(|(id, sig)| { @@ -139,26 +139,18 @@ mod tests { fn new_rounds() { sp_tracing::try_init_simple(); - let rounds = Rounds::>::new(ValidatorSet::::empty()); - - assert_eq!(0, rounds.validator_set_id()); - assert!(rounds.validators().is_empty()); - - let validators = ValidatorSet:: { - validators: vec![ - Keyring::Alice.public(), - Keyring::Bob.public(), - Keyring::Charlie.public(), - ], - id: 42, - }; + let validators = ValidatorSet::::new( + vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + 42, + ) + .unwrap(); let rounds = Rounds::>::new(validators); assert_eq!(42, rounds.validator_set_id()); assert_eq!( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + &vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], rounds.validators() ); } @@ -167,14 +159,11 @@ mod tests { fn add_vote() { sp_tracing::try_init_simple(); - let validators = ValidatorSet:: { - validators: vec![ - Keyring::Alice.public(), - Keyring::Bob.public(), - Keyring::Charlie.public(), - ], - id: Default::default(), - }; + let validators = ValidatorSet::::new( + vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + Default::default(), + ) + .unwrap(); let mut rounds = Rounds::>::new(validators); @@ -212,14 +201,11 @@ mod tests { fn drop() { sp_tracing::try_init_simple(); - let validators = ValidatorSet:: { - validators: vec![ - Keyring::Alice.public(), - Keyring::Bob.public(), - Keyring::Charlie.public(), - ], - id: Default::default(), - }; + let validators = ValidatorSet::::new( + vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + Default::default(), + ) + .unwrap(); let mut rounds = Rounds::>::new(validators); diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index bf29a50f19640..306540077ae2f 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -20,7 +20,7 @@ use std::{collections::BTreeSet, fmt::Debug, marker::PhantomData, sync::Arc}; use codec::{Codec, Decode, Encode}; use futures::{future, FutureExt, StreamExt}; -use log::{debug, error, info, trace, warn}; +use log::{debug, error, info, log_enabled, trace, warn}; use parking_lot::Mutex; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications}; @@ -79,7 +79,7 @@ where /// Min delta in block numbers between two blocks, BEEFY should vote on min_block_delta: u32, metrics: Option, - rounds: round::Rounds>, + rounds: Option>>, finality_notifications: FinalityNotifications, /// Best block we received a GRANDPA notification for best_grandpa_block: NumberFor, @@ -125,7 +125,7 @@ where gossip_validator, min_block_delta, metrics, - rounds: round::Rounds::new(ValidatorSet::empty()), + rounds: None, finality_notifications: client.finality_notification_stream(), best_grandpa_block: client.info().finalized_number, best_beefy_block: None, @@ -172,7 +172,7 @@ where Some(new) } else { let at = BlockId::hash(header.hash()); - self.client.runtime_api().validator_set(&at).ok() + self.client.runtime_api().validator_set(&at).ok().flatten() }; trace!(target: "beefy", "🥩 active validator set: {:?}", new); @@ -190,11 +190,12 @@ where fn verify_validator_set( &self, block: &NumberFor, - mut active: ValidatorSet, + active: &ValidatorSet, ) -> Result<(), error::Error> { - let active: BTreeSet = active.validators.drain(..).collect(); + let active: BTreeSet<&Public> = active.validators().iter().collect(); - let store: BTreeSet = self.key_store.public_keys()?.drain(..).collect(); + let public_keys = self.key_store.public_keys()?; + let store: BTreeSet<&Public> = public_keys.iter().collect(); let missing: Vec<_> = store.difference(&active).cloned().collect(); @@ -214,26 +215,31 @@ where if let Some(active) = self.validator_set(¬ification.header) { // Authority set change or genesis set id triggers new voting rounds // - // TODO: (adoerr) Enacting a new authority set will also implicitly 'conclude' - // the currently active BEEFY voting round by starting a new one. This is - // temporary and needs to be replaced by proper round life cycle handling. - if active.id != self.rounds.validator_set_id() || - (active.id == GENESIS_AUTHORITY_SET_ID && self.best_beefy_block.is_none()) + // TODO: (grandpa-bridge-gadget#366) Enacting a new authority set will also + // implicitly 'conclude' the currently active BEEFY voting round by starting a + // new one. This should be replaced by proper round life-cycle handling. + if self.rounds.is_none() || + active.id() != self.rounds.as_ref().unwrap().validator_set_id() || + (active.id() == GENESIS_AUTHORITY_SET_ID && self.best_beefy_block.is_none()) { debug!(target: "beefy", "🥩 New active validator set id: {:?}", active); - metric_set!(self, beefy_validator_set_id, active.id); + metric_set!(self, beefy_validator_set_id, active.id()); // BEEFY should produce a signed commitment for each session - if active.id != self.last_signed_id + 1 && active.id != GENESIS_AUTHORITY_SET_ID { + if active.id() != self.last_signed_id + 1 && active.id() != GENESIS_AUTHORITY_SET_ID + { metric_inc!(self, beefy_skipped_sessions); } - // verify the new validator set - let _ = self.verify_validator_set(notification.header.number(), active.clone()); + if log_enabled!(target: "beefy", log::Level::Debug) { + // verify the new validator set - only do it if we're also logging the warning + let _ = self.verify_validator_set(notification.header.number(), &active); + } - self.rounds = round::Rounds::new(active.clone()); + let id = active.id(); + self.rounds = Some(round::Rounds::new(active)); - debug!(target: "beefy", "🥩 New Rounds for id: {:?}", active.id); + debug!(target: "beefy", "🥩 New Rounds for id: {:?}", id); self.best_beefy_block = Some(*notification.header.number()); @@ -244,9 +250,13 @@ where } if self.should_vote_on(*notification.header.number()) { - let authority_id = if let Some(id) = - self.key_store.authority_id(self.rounds.validators().as_slice()) - { + let (validators, validator_set_id) = if let Some(rounds) = &self.rounds { + (rounds.validators(), rounds.validator_set_id()) + } else { + debug!(target: "beefy", "🥩 Missing validator set - can't vote for: {:?}", notification.header.hash()); + return + }; + let authority_id = if let Some(id) = self.key_store.authority_id(validators) { debug!(target: "beefy", "🥩 Local authority id: {:?}", id); id } else { @@ -266,7 +276,7 @@ where let commitment = Commitment { payload, block_number: notification.header.number(), - validator_set_id: self.rounds.validator_set_id(), + validator_set_id, }; let encoded_commitment = commitment.encode(); @@ -305,12 +315,19 @@ where fn handle_vote(&mut self, round: (Payload, NumberFor), vote: (Public, Signature)) { self.gossip_validator.note_round(round.1); - let vote_added = self.rounds.add_vote(&round, vote); + let rounds = if let Some(rounds) = self.rounds.as_mut() { + rounds + } else { + debug!(target: "beefy", "🥩 Missing validator set - can't handle vote {:?}", vote); + return + }; + + let vote_added = rounds.add_vote(&round, vote); - if vote_added && self.rounds.is_done(&round) { - if let Some(signatures) = self.rounds.drop(&round) { + if vote_added && rounds.is_done(&round) { + if let Some(signatures) = rounds.drop(&round) { // id is stored for skipped session metric calculation - self.last_signed_id = self.rounds.validator_set_id(); + self.last_signed_id = rounds.validator_set_id(); let commitment = Commitment { payload: round.0, diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index f27bc450ad146..9cfbd94b53bca 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -84,10 +84,9 @@ fn should_contain_mmr_digest() { beefy_log(ConsensusLog::MmrRoot( hex!("f3e3afbfa69e89cd1e99f8d3570155962f3346d1d8758dc079be49ef70387758").into() )), - beefy_log(ConsensusLog::AuthoritiesChange(ValidatorSet { - validators: vec![mock_beefy_id(3), mock_beefy_id(4),], - id: 1, - })), + beefy_log(ConsensusLog::AuthoritiesChange( + ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4),], 1,).unwrap() + )), beefy_log(ConsensusLog::MmrRoot( hex!("7d4ae4524bae75d52b63f08eab173b0c263eb95ae2c55c3a1d871241bd0cc559").into() )), diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index c18b28901bb62..9ef0c0d69f305 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -97,8 +97,10 @@ pub mod pallet { impl Pallet { /// Return the current active BEEFY validator set. - pub fn validator_set() -> ValidatorSet { - ValidatorSet:: { validators: Self::authorities(), id: Self::validator_set_id() } + pub fn validator_set() -> Option> { + let validators: Vec = Self::authorities(); + let id: beefy_primitives::ValidatorSetId = Self::validator_set_id(); + ValidatorSet::::new(validators, id) } fn change_authorities(new: Vec, queued: Vec) { @@ -109,13 +111,13 @@ impl Pallet { let next_id = Self::validator_set_id() + 1u64; >::put(next_id); - - let log = DigestItem::Consensus( - BEEFY_ENGINE_ID, - ConsensusLog::AuthoritiesChange(ValidatorSet { validators: new, id: next_id }) - .encode(), - ); - >::deposit_log(log); + if let Some(validator_set) = ValidatorSet::::new(new, next_id) { + let log = DigestItem::Consensus( + BEEFY_ENGINE_ID, + ConsensusLog::AuthoritiesChange(validator_set).encode(), + ); + >::deposit_log(log); + } } >::put(&queued); diff --git a/frame/beefy/src/tests.rs b/frame/beefy/src/tests.rs index 252c03efb54a9..900a3770279be 100644 --- a/frame/beefy/src/tests.rs +++ b/frame/beefy/src/tests.rs @@ -70,10 +70,9 @@ fn session_change_updates_authorities() { assert!(1 == Beefy::validator_set_id()); - let want = beefy_log(ConsensusLog::AuthoritiesChange(ValidatorSet { - validators: vec![mock_beefy_id(3), mock_beefy_id(4)], - id: 1, - })); + let want = beefy_log(ConsensusLog::AuthoritiesChange( + ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4)], 1).unwrap(), + )); let log = System::digest().logs[0].clone(); @@ -109,11 +108,11 @@ fn validator_set_at_genesis() { let want = vec![mock_beefy_id(1), mock_beefy_id(2)]; new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - let vs = Beefy::validator_set(); + let vs = Beefy::validator_set().unwrap(); - assert_eq!(vs.id, 0u64); - assert_eq!(vs.validators[0], want[0]); - assert_eq!(vs.validators[1], want[1]); + assert_eq!(vs.id(), 0u64); + assert_eq!(vs.validators()[0], want[0]); + assert_eq!(vs.validators()[1], want[1]); }); } @@ -124,18 +123,18 @@ fn validator_set_updates_work() { new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { init_block(1); - let vs = Beefy::validator_set(); + let vs = Beefy::validator_set().unwrap(); - assert_eq!(vs.id, 0u64); - assert_eq!(want[0], vs.validators[0]); - assert_eq!(want[1], vs.validators[1]); + assert_eq!(vs.id(), 0u64); + assert_eq!(want[0], vs.validators()[0]); + assert_eq!(want[1], vs.validators()[1]); init_block(2); - let vs = Beefy::validator_set(); + let vs = Beefy::validator_set().unwrap(); - assert_eq!(vs.id, 1u64); - assert_eq!(want[2], vs.validators[0]); - assert_eq!(want[3], vs.validators[1]); + assert_eq!(vs.id(), 1u64); + assert_eq!(want[2], vs.validators()[0]); + assert_eq!(want[3], vs.validators()[1]); }); } diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index 20f6b9d0d8fb4..bf72b801eec0a 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -84,15 +84,39 @@ pub type ValidatorSetId = u64; #[derive(Decode, Encode, Debug, PartialEq, Clone, TypeInfo)] pub struct ValidatorSet { /// Public keys of the validator set elements - pub validators: Vec, + validators: Vec, /// Identifier of the validator set - pub id: ValidatorSetId, + id: ValidatorSetId, } impl ValidatorSet { - /// Return an empty validator set with id of 0. - pub fn empty() -> Self { - Self { validators: Default::default(), id: Default::default() } + /// Return a validator set with the given validators and set id. + pub fn new(validators: I, id: ValidatorSetId) -> Option + where + I: IntoIterator, + { + let validators: Vec = validators.into_iter().collect(); + if validators.is_empty() { + // No validators; the set would be empty. + None + } else { + Some(Self { validators, id }) + } + } + + /// Return a reference to the vec of validators. + pub fn validators(&self) -> &[AuthorityId] { + &self.validators + } + + /// Return the validator set id. + pub fn id(&self) -> ValidatorSetId { + self.id + } + + /// Return the number of validators in the set. + pub fn len(&self) -> usize { + self.validators.len() } } @@ -135,6 +159,26 @@ sp_api::decl_runtime_apis! { pub trait BeefyApi { /// Return the current active BEEFY validator set - fn validator_set() -> ValidatorSet; + fn validator_set() -> Option>; + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_application_crypto::ecdsa::{self, Public}; + use sp_core::Pair; + + #[test] + fn validator_set() { + // Empty set not allowed. + assert_eq!(ValidatorSet::::new(vec![], 0), None); + + let alice = ecdsa::Pair::from_string("//Alice", None).unwrap(); + let set_id = 0; + let validators = ValidatorSet::::new(vec![alice.public()], set_id).unwrap(); + + assert_eq!(validators.id(), set_id); + assert_eq!(validators.validators(), &vec![alice.public()]); } } From 5cd78cfeead8bddc79f12f6747a92233e14992ab Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 21 Dec 2021 15:09:37 +0000 Subject: [PATCH 0369/1472] Serialize CodeUploadReturnValue deposit correctly (#10526) --- frame/contracts/common/src/lib.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/frame/contracts/common/src/lib.rs b/frame/contracts/common/src/lib.rs index b5873869495e9..7d99db42a2b93 100644 --- a/frame/contracts/common/src/lib.rs +++ b/frame/contracts/common/src/lib.rs @@ -151,11 +151,19 @@ pub struct InstantiateReturnValue { /// The result of succesfully uploading a contract. #[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] +#[cfg_attr( + feature = "std", + serde( + rename_all = "camelCase", + bound(serialize = "CodeHash: Serialize, Balance: Copy + Into"), + bound(deserialize = "CodeHash: Deserialize<'de>, Balance: TryFrom") + ) +)] pub struct CodeUploadReturnValue { /// The key under which the new code is stored. pub code_hash: CodeHash, /// The deposit that was reserved at the caller. Is zero when the code already existed. + #[cfg_attr(feature = "std", serde(with = "as_hex"))] pub deposit: Balance, } From 3ce158c007ac030c2d2b43d0c34c849447d8eee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 21 Dec 2021 18:36:46 +0100 Subject: [PATCH 0370/1472] Use exists host function (#10531) --- frame/support/src/storage/child.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frame/support/src/storage/child.rs b/frame/support/src/storage/child.rs index 4b237aaa561fd..5497f642067cf 100644 --- a/frame/support/src/storage/child.rs +++ b/frame/support/src/storage/child.rs @@ -112,8 +112,7 @@ pub fn take_or_else T>( pub fn exists(child_info: &ChildInfo, key: &[u8]) -> bool { match child_info.child_type() { ChildType::ParentKeyId => - sp_io::default_child_storage::read(child_info.storage_key(), key, &mut [0; 0][..], 0) - .is_some(), + sp_io::default_child_storage::exists(child_info.storage_key(), key), } } From e2cab4ee66c594741a1db9c8f43177e4f0af0a55 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 21 Dec 2021 18:42:15 +0100 Subject: [PATCH 0371/1472] add to (#10524) --- .../support/src/storage/types/counted_map.rs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 01414d7019ae1..c4230cafc40be 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -412,6 +412,23 @@ where res }) } + + /// Enumerate all elements in the counted map after a specified `starting_raw_key` in no + /// particular order. + /// + /// If you alter the map while doing this, you'll get undefined results. + pub fn iter_from( + starting_raw_key: Vec, + ) -> crate::storage::PrefixIterator<(Key, Value), OnRemovalCounterUpdate> { + let map_iterator = ::Map::iter_from(starting_raw_key); + crate::storage::PrefixIterator { + prefix: map_iterator.prefix, + previous_key: map_iterator.previous_key, + drain: map_iterator.drain, + closure: map_iterator.closure, + phantom: Default::default(), + } + } } impl StorageEntryMetadataBuilder @@ -1022,6 +1039,25 @@ mod test { }) } + #[test] + fn test_iter_from() { + type A = CountedStorageMap; + TestExternalities::default().execute_with(|| { + A::insert(1, 1); + A::insert(2, 2); + A::insert(3, 3); + A::insert(4, 4); + + // no prefix is same as normal iter. + assert_eq!(A::iter_from(vec![]).collect::>(), A::iter().collect::>()); + + let iter_all = A::iter().collect::>(); + let (before, after) = iter_all.split_at(2); + let last_key = before.last().map(|(k, _)| k).unwrap(); + assert_eq!(A::iter_from(A::hashed_key_for(last_key)).collect::>(), after); + }) + } + #[test] fn test_metadata() { type A = CountedStorageMap; From a230543899e5b161a2ca55e56f5493010390c9e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Dec 2021 18:44:59 +0100 Subject: [PATCH 0372/1472] Bump handlebars from 4.1.4 to 4.1.6 (#10518) Bumps [handlebars](https://github.com/sunng87/handlebars-rust) from 4.1.4 to 4.1.6. - [Release notes](https://github.com/sunng87/handlebars-rust/releases) - [Changelog](https://github.com/sunng87/handlebars-rust/blob/master/CHANGELOG.md) - [Commits](https://github.com/sunng87/handlebars-rust/compare/v4.1.4...v4.1.6) --- updated-dependencies: - dependency-name: handlebars 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 ++-- utils/frame/benchmarking-cli/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44d4e9a609281..89e4f3f832b0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2572,9 +2572,9 @@ checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" [[package]] name = "handlebars" -version = "4.1.4" +version = "4.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1874024f4a29f47d609014caec0b1c866f1c1eb0661a09c9733ecc4757f5f88" +checksum = "167fa173496c9eadd8749cca6f8339ac88e248f3ad2442791d0b743318a94fc0" dependencies = [ "log 0.4.14", "pest", diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index bf231eb677139..61988e24e3b0d 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -28,7 +28,7 @@ codec = { version = "2.0.0", package = "parity-scale-codec" } structopt = "0.3.25" chrono = "0.4" serde = "1.0.132" -handlebars = "4.1.4" +handlebars = "4.1.6" Inflector = "0.11.4" linked-hash-map = "0.5.4" log = "0.4.8" From 5ddbcdd99ae6120f3f240920d683b8bcb55f437d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Dec 2021 09:21:54 +0100 Subject: [PATCH 0373/1472] Bump strum_macros from 0.22.0 to 0.23.1 (#10532) Bumps [strum_macros](https://github.com/Peternator7/strum) from 0.22.0 to 0.23.1. - [Release notes](https://github.com/Peternator7/strum/releases) - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/commits) --- updated-dependencies: - dependency-name: strum_macros 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 | 17 +++++++++++++++-- frame/election-provider-multi-phase/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 89e4f3f832b0e..0b61fef54db8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5549,7 +5549,7 @@ dependencies = [ "sp-tracing", "static_assertions", "strum", - "strum_macros", + "strum_macros 0.23.1", ] [[package]] @@ -10056,7 +10056,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" dependencies = [ - "strum_macros", + "strum_macros 0.22.0", ] [[package]] @@ -10071,6 +10071,19 @@ dependencies = [ "syn", ] +[[package]] +name = "strum_macros" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "subkey" version = "2.0.1" diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 75a1ed083829b..c8ed0c561b467 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -38,7 +38,7 @@ rand = { version = "0.7.3", default-features = false, optional = true, features "small_rng", ] } strum = { optional = true, version = "0.22.0" } -strum_macros = { optional = true, version = "0.22.0" } +strum_macros = { optional = true, version = "0.23.1" } [dev-dependencies] parking_lot = "0.11.2" From 1c67f8ec6e64e431f98d2c15ff1012aeada07996 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Dec 2021 11:47:51 +0100 Subject: [PATCH 0374/1472] Bump libc from 0.2.105 to 0.2.112 (#10537) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.105 to 0.2.112. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.105...0.2.112) --- updated-dependencies: - dependency-name: libc 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/executor/wasmtime/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b61fef54db8a..4ac0a977324c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3350,9 +3350,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.105" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "libgit2-sys" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 6718e6d13f3ce..65efc26035098 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -libc = "0.2.105" +libc = "0.2.112" cfg-if = "1.0" log = "0.4.8" parity-wasm = "0.42.0" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 55ecd0a1481a9..7ea0d80ba1f20 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -17,7 +17,7 @@ ansi_term = "0.12.1" atty = "0.2.13" chrono = "0.4.19" lazy_static = "1.4.0" -libc = "0.2.105" +libc = "0.2.112" log = { version = "0.4.8" } once_cell = "1.8.0" parking_lot = "0.11.2" From 5b491e8d9172b69a3d77f81ab17434d440f85df5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Dec 2021 11:55:05 +0100 Subject: [PATCH 0375/1472] Bump futures-util from 0.3.17 to 0.3.19 (#10513) Bumps [futures-util](https://github.com/rust-lang/futures-rs) from 0.3.17 to 0.3.19. - [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.17...0.3.19) --- updated-dependencies: - dependency-name: futures-util 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 | 39 +++++++++++++------------------------ utils/prometheus/Cargo.toml | 2 +- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ac0a977324c4..a68476797497e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2279,9 +2279,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" dependencies = [ "futures-core", "futures-sink", @@ -2289,9 +2289,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" [[package]] name = "futures-executor" @@ -2307,9 +2307,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" [[package]] name = "futures-lite" @@ -2328,12 +2328,10 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" dependencies = [ - "autocfg 1.0.1", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -2352,15 +2350,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" [[package]] name = "futures-task" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" +checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" [[package]] name = "futures-timer" @@ -2376,11 +2374,10 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" dependencies = [ - "autocfg 1.0.1", "futures 0.1.31", "futures-channel", "futures-core", @@ -2391,8 +2388,6 @@ dependencies = [ "memchr", "pin-project-lite 0.2.6", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] @@ -6836,12 +6831,6 @@ version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" version = "1.0.32" diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index b9a3a5a5d1974..4ae38f6455327 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.8" prometheus = { version = "0.13.0", default-features = false } -futures-util = { version = "0.3.17", default-features = false, features = ["io"] } +futures-util = { version = "0.3.19", default-features = false, features = ["io"] } derive_more = "0.99" async-std = { version = "1.10.0", features = ["unstable"] } tokio = "1.15" From 0b57148b55667c0802161607324ad9f517248ae1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Dec 2021 16:25:53 +0100 Subject: [PATCH 0376/1472] Bump num_cpus from 1.13.0 to 1.13.1 (#10539) Bumps [num_cpus](https://github.com/seanmonstar/num_cpus) from 1.13.0 to 1.13.1. - [Release notes](https://github.com/seanmonstar/num_cpus/releases) - [Changelog](https://github.com/seanmonstar/num_cpus/blob/master/CHANGELOG.md) - [Commits](https://github.com/seanmonstar/num_cpus/compare/v1.13.0...v1.13.1) --- updated-dependencies: - dependency-name: num_cpus 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/offchain/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a68476797497e..32a52fb460d86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4990,9 +4990,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 38834181b163d..4ca1b242a48ec 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -19,7 +19,7 @@ hex = "0.4" fnv = "1.0.6" futures = "0.3.16" futures-timer = "3.0.2" -num_cpus = "1.10" +num_cpus = "1.13" parking_lot = "0.11.2" rand = "0.7.2" sc-client-api = { version = "4.0.0-dev", path = "../api" } From e1a47ef9bd8badae77e7484b1aa5222a63f83be1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Dec 2021 16:22:55 +0000 Subject: [PATCH 0377/1472] Bump nix from 0.23.0 to 0.23.1 (#10542) Bumps [nix](https://github.com/nix-rust/nix) from 0.23.0 to 0.23.1. - [Release notes](https://github.com/nix-rust/nix/releases) - [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md) - [Commits](https://github.com/nix-rust/nix/compare/v0.23.0...v0.23.1) --- updated-dependencies: - dependency-name: nix 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 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 32a52fb460d86..5ed9325b43a35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4460,9 +4460,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ "bitflags", "cc", From 50156013c9316cd8849cb3db34670d046b8d66ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Dec 2021 17:39:30 +0100 Subject: [PATCH 0378/1472] Bump zeroize from 1.4.2 to 1.4.3 (#10538) Bumps [zeroize](https://github.com/RustCrypto/utils) from 1.4.2 to 1.4.3. - [Release notes](https://github.com/RustCrypto/utils/releases) - [Commits](https://github.com/RustCrypto/utils/commits/zeroize-v1.4.3) --- updated-dependencies: - dependency-name: zeroize 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/network/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ed9325b43a35..96146f6f8bece 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11925,9 +11925,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970" +checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" dependencies = [ "zeroize_derive", ] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 436f9227d35ab..4f3ea4e939b6e 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -63,7 +63,7 @@ unsigned-varint = { version = "0.6.0", features = [ "asynchronous_codec", ] } void = "1.0.2" -zeroize = "1.4.2" +zeroize = "1.4.3" libp2p = "0.40.0" [dev-dependencies] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index a6b2e21ce77fe..05fc1240e2742 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -35,7 +35,7 @@ substrate-bip39 = { version = "0.4.4", optional = true } tiny-bip39 = { version = "0.8.2", optional = true } regex = { version = "1.5.4", optional = true } num-traits = { version = "0.2.8", default-features = false } -zeroize = { version = "1.4.2", default-features = false } +zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.11.2", optional = true } From 0444ab7b4afbf4347d51e1e7352cda878e6a3df7 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 23 Dec 2021 19:32:06 +0800 Subject: [PATCH 0379/1472] Customizable ink address (#10521) --- bin/node/runtime/src/lib.rs | 1 + frame/contracts/src/lib.rs | 71 ++++++++++++++++++++++++++++-------- frame/contracts/src/tests.rs | 4 +- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 97de54fc21e8c..a79d8997f4ce1 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -957,6 +957,7 @@ impl pallet_contracts::Config for Runtime { type DeletionQueueDepth = DeletionQueueDepth; type DeletionWeightLimit = DeletionWeightLimit; type Schedule = Schedule; + type AddressGenerator = pallet_contracts::DefaultAddressGenerator; } impl pallet_sudo::Config for Runtime { diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index b604c9618c6ae..ab7a0c254f560 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -136,6 +136,55 @@ type BalanceOf = /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(6); +/// Provides the contract address generation method. +/// +/// See [`DefaultAddressGenerator`] for the default implementation. +pub trait AddressGenerator { + /// Generate the address of a contract based on the given instantiate parameters. + /// + /// # Note for implementors + /// 1. Make sure that there are no collisions, different inputs never lead to the same output. + /// 2. Make sure that the same inputs lead to the same output. + /// 3. Changing the implementation through a runtime upgrade without a proper storage migration + /// would lead to catastrophic misbehavior. + fn generate_address( + deploying_address: &T::AccountId, + code_hash: &CodeHash, + salt: &[u8], + ) -> T::AccountId; +} + +/// Default address generator. +/// +/// This is the default address generator used by contract instantiation. Its result +/// is only dependend on its inputs. It can therefore be used to reliably predict the +/// address of a contract. This is akin to the formular of eth's CREATE2 opcode. There +/// is no CREATE equivalent because CREATE2 is strictly more powerful. +/// +/// Formula: `hash(deploying_address ++ code_hash ++ salt)` +pub struct DefaultAddressGenerator; + +impl AddressGenerator for DefaultAddressGenerator +where + T: frame_system::Config, + T::AccountId: UncheckedFrom + AsRef<[u8]>, +{ + fn generate_address( + deploying_address: &T::AccountId, + code_hash: &CodeHash, + salt: &[u8], + ) -> T::AccountId { + let buf: Vec<_> = deploying_address + .as_ref() + .iter() + .chain(code_hash.as_ref()) + .chain(salt) + .cloned() + .collect(); + UncheckedFrom::unchecked_from(T::Hashing::hash(&buf)) + } +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -227,6 +276,9 @@ pub mod pallet { /// Changing this value for an existing chain might need a storage migration. #[pallet::constant] type DepositPerItem: Get>; + + /// The address generator used to generate the addresses of contracts. + type AddressGenerator: AddressGenerator; } #[pallet::pallet] @@ -728,27 +780,16 @@ where Ok(maybe_value) } - /// Determine the address of a contract, - /// - /// This is the address generation function used by contract instantiation. Its result - /// is only dependend on its inputs. It can therefore be used to reliably predict the - /// address of a contract. This is akin to the formular of eth's CREATE2 opcode. There - /// is no CREATE equivalent because CREATE2 is strictly more powerful. + /// Determine the address of a contract. /// - /// Formula: `hash(deploying_address ++ code_hash ++ salt)` + /// This is the address generation function used by contract instantiation. See + /// [`DefaultAddressGenerator`] for the default implementation. pub fn contract_address( deploying_address: &T::AccountId, code_hash: &CodeHash, salt: &[u8], ) -> T::AccountId { - let buf: Vec<_> = deploying_address - .as_ref() - .iter() - .chain(code_hash.as_ref()) - .chain(salt) - .cloned() - .collect(); - UncheckedFrom::unchecked_from(T::Hashing::hash(&buf)) + T::AddressGenerator::generate_address(deploying_address, code_hash, salt) } /// Store code for benchmarks which does not check nor instrument the code. diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 584253aeaadfe..6ca4e34f8aeae 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -24,7 +24,8 @@ use crate::{ storage::Storage, wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, - BalanceOf, Code, CodeStorage, Config, ContractInfoOf, Error, Pallet, Schedule, + BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, Error, Pallet, + Schedule, }; use assert_matches::assert_matches; use codec::Encode; @@ -285,6 +286,7 @@ impl Config for Test { type Schedule = MySchedule; type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; + type AddressGenerator = DefaultAddressGenerator; } pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); From 026ec33ff7b9686055c45c1633cab2ed66dc59fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 23 Dec 2021 18:45:43 +0100 Subject: [PATCH 0380/1472] chain-spec: Make chain spec writing deterministic (#10550) * chain-spec: Make chain spec writing deterministic This switches the chain spec to use `BTreeMap` internally instead of `HashMap`. This ensures that reading and writing the same chain spec always results in the same file. * fmt --- client/chain-spec/src/chain_spec.rs | 63 +++++++++++++++++++++++++---- client/chain-spec/src/lib.rs | 2 +- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index e8247d7314991..520c071d35ce1 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -29,7 +29,7 @@ use sp_core::{ Bytes, }; use sp_runtime::BuildStorage; -use std::{borrow::Cow, collections::HashMap, fs::File, path::PathBuf, sync::Arc}; +use std::{borrow::Cow, collections::BTreeMap, fs::File, path::PathBuf, sync::Arc}; enum GenesisSource { File(PathBuf), @@ -131,7 +131,7 @@ impl BuildStorage for ChainSpec { } } -pub type GenesisStorage = HashMap; +pub type GenesisStorage = BTreeMap; /// Raw storage content for genesis block. #[derive(Serialize, Deserialize)] @@ -139,7 +139,7 @@ pub type GenesisStorage = HashMap; #[serde(deny_unknown_fields)] pub struct RawGenesis { pub top: GenesisStorage, - pub children_default: HashMap, + pub children_default: BTreeMap, } #[derive(Serialize, Deserialize)] @@ -180,7 +180,7 @@ struct ClientSpec { /// The given `wasm_code` will be used to substitute the on-chain wasm code from the given /// block hash onwards. #[serde(default)] - code_substitutes: HashMap, + code_substitutes: BTreeMap, } /// A type denoting empty extensions. @@ -271,7 +271,7 @@ impl ChainSpec { extensions, consensus_engine: (), genesis: Default::default(), - code_substitutes: HashMap::new(), + code_substitutes: BTreeMap::new(), }; ChainSpec { client_spec, genesis: GenesisSource::Factory(Arc::new(constructor)) } @@ -416,7 +416,7 @@ where self.genesis = GenesisSource::Storage(storage); } - fn code_substitutes(&self) -> std::collections::HashMap> { + fn code_substitutes(&self) -> std::collections::BTreeMap> { self.client_spec .code_substitutes .iter() @@ -430,7 +430,7 @@ mod tests { use super::*; #[derive(Debug, Serialize, Deserialize)] - struct Genesis(HashMap); + struct Genesis(BTreeMap); impl BuildStorage for Genesis { fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { @@ -455,12 +455,28 @@ mod tests { assert_eq!(spec2.chain_type(), ChainType::Live) } - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] struct Extension1 { my_property: String, } + impl crate::Extension for Extension1 { + type Forks = Option<()>; + + fn get(&self) -> Option<&T> { + None + } + + fn get_any(&self, _: std::any::TypeId) -> &dyn std::any::Any { + self + } + + fn get_any_mut(&mut self, _: std::any::TypeId) -> &mut dyn std::any::Any { + self + } + } + type TestSpec2 = ChainSpec; #[test] @@ -472,4 +488,35 @@ mod tests { assert_eq!(spec.extensions().my_property, "Test Extension"); } + + #[test] + fn chain_spec_raw_output_should_be_deterministic() { + let mut spec = TestSpec2::from_json_bytes(Cow::Owned( + include_bytes!("../res/chain_spec2.json").to_vec(), + )) + .unwrap(); + + let mut storage = spec.build_storage().unwrap(); + + // Add some extra data, so that storage "sorting" is tested. + let extra_data = &[("random_key", "val"), ("r@nd0m_key", "val"), ("aaarandom_key", "val")]; + storage + .top + .extend(extra_data.iter().map(|(k, v)| (k.as_bytes().to_vec(), v.as_bytes().to_vec()))); + crate::ChainSpec::set_storage(&mut spec, storage); + + let json = spec.as_json(true).unwrap(); + + // Check multiple times that decoding and encoding the chain spec leads always to the same + // output. + for _ in 0..10 { + assert_eq!( + json, + TestSpec2::from_json_bytes(json.as_bytes().to_vec()) + .unwrap() + .as_json(true) + .unwrap() + ); + } + } } diff --git a/client/chain-spec/src/lib.rs b/client/chain-spec/src/lib.rs index 334d8f8b3d7ac..cbb1e85df3c1c 100644 --- a/client/chain-spec/src/lib.rs +++ b/client/chain-spec/src/lib.rs @@ -186,7 +186,7 @@ pub trait ChainSpec: BuildStorage + Send + Sync { /// This will be used as storage at genesis. fn set_storage(&mut self, storage: Storage); /// Returns code substitutes that should be used for the on chain wasm. - fn code_substitutes(&self) -> std::collections::HashMap>; + fn code_substitutes(&self) -> std::collections::BTreeMap>; } impl std::fmt::Debug for dyn ChainSpec { From b03e8bcf151bbf4c20a7d7faa782366fc3554d58 Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 24 Dec 2021 09:54:07 +0100 Subject: [PATCH 0381/1472] Inner hashing of value in state trie (runtime versioning). (#9732) * starting * Updated from other branch. * setting flag * flag in storage struct * fix flagging to access and insert. * added todo to fix * also missing serialize meta to storage proof * extract meta. * Isolate old trie layout. * failing test that requires storing in meta when old hash scheme is used. * old hash compatibility * Db migrate. * runing tests with both states when interesting. * fix chain spec test with serde default. * export state (missing trie function). * Pending using new branch, lacking genericity on layout resolution. * extract and set global meta * Update to branch 4 * fix iterator with root flag (no longer insert node). * fix trie root hashing of root * complete basic backend. * Remove old_hash meta from proof that do not use inner_hashing. * fix trie test for empty (force layout on empty deltas). * Root update fix. * debug on meta * Use trie key iteration that do not include value in proofs. * switch default test ext to use inner hash. * small integration test, and fix tx cache mgmt in ext. test failing * Proof scenario at state-machine level. * trace for db upgrade * try different param * act more like iter_from. * Bigger batches. * Update trie dependency. * drafting codec changes and refact * before removing unused branch no value alt hashing. more work todo rename all flag var to alt_hash, and remove extrinsic replace by storage query at every storage_root call. * alt hashing only for branch with value. * fix trie tests * Hash of value include the encoded size. * removing fields(broken) * fix trie_stream to also include value length in inner hash. * triedbmut only using alt type if inner hashing. * trie_stream to also only use alt hashing type when actually alt hashing. * Refactor meta state, logic should work with change of trie treshold. * Remove NoMeta variant. * Remove state_hashed trigger specific functions. * pending switching to using threshold, new storage root api does not make much sense. * refactoring to use state from backend (not possible payload changes). * Applying from previous state * Remove default from storage, genesis need a special build. * rem empty space * Catch problem: when using triedb with default: we should not revert nodes: otherwhise thing as trie codec cannot decode-encode without changing state. * fix compilation * Right logic to avoid switch on reencode when default layout. * Clean up some todos * remove trie meta from root upstream * update upstream and fix benches. * split some long lines. * UPdate trie crate to work with new design. * Finish update to refactored upstream. * update to latest triedb changes. * Clean up. * fix executor test. * rust fmt from master. * rust format. * rustfmt * fix * start host function driven versioning * update state-machine part * still need access to state version from runtime * state hash in mem: wrong * direction likely correct, but passing call to code exec for genesis init seem awkward. * state version serialize in runtime, wrong approach, just initialize it with no threshold for core api < 4 seems more proper. * stateversion from runtime version (core api >= 4). * update trie, fix tests * unused import * clean some TODOs * Require RuntimeVersionOf for executor * use RuntimeVersionOf to resolve genesis state version. * update runtime version test * fix state-machine tests * TODO * Use runtime version from storage wasm with fast sync. * rustfmt * fmt * fix test * revert useless changes. * clean some unused changes * fmt * removing useless trait function. * remove remaining reference to state_hash * fix some imports * Follow chain state version management. * trie update, fix and constant threshold for trie layouts. * update deps * Update to latest trie pr changes. * fix benches * Verify proof requires right layout. * update trie_root * Update trie deps to latest * Update to latest trie versioning * Removing patch * update lock * extrinsic for sc-service-test using layout v0. * Adding RuntimeVersionOf to CallExecutor works. * fmt * error when resolving version and no wasm in storage. * use existing utils to instantiate runtime code. * Patch to delay runtime switch. * Revert "Patch to delay runtime switch." This reverts commit d35f273b7d67b1b85a9e72973cab13c5c156c1d3. * useless closure * remove remaining state_hash variables. * Remove outdated comment * useless inner hash * fmt * fmt and opt-in feature to apply state change. * feature gate core version, use new test feature for node and test node * Use a 'State' api version instead of Core one. * fix merge of test function * use blake macro. * Fix state api (require declaring the api in runtime). * Opt out feature, fix macro for io to select a given version instead of latest. * run test nodes on new state. * fix * Apply review change (docs and error). * fmt * use explicit runtime_interface in doc test * fix ui test * fix doc test * fmt * use default for path and specname when resolving version. * small review related changes. * doc value size requirement. * rename old_state feature * Remove macro changes * feature rename * state version as host function parameter * remove flag for client api * fix tests * switch storage chain proof to V1 * host functions, pass by state version enum * use WrappedRuntimeCode * start * state_version in runtime version * rust fmt * Update storage proof of max size. * fix runtime version rpc test * right intent of convert from compat * fix doc test * fix doc test * split proof * decode without replay, and remove some reexports. * Decode with compatibility by default. * switch state_version to u8. And remove RuntimeVersionBasis. * test * use api when reading embedded version * fix decode with apis * extract core version instead * test fix * unused import * review changes. Co-authored-by: kianenigma --- Cargo.lock | 34 ++- bin/node-template/runtime/src/lib.rs | 1 + bin/node/bench/src/generator.rs | 5 +- bin/node/bench/src/trie.rs | 6 +- bin/node/executor/benches/bench.rs | 4 +- bin/node/executor/tests/common.rs | 2 +- bin/node/runtime/src/lib.rs | 1 + client/api/src/backend.rs | 9 +- client/api/src/call_executor.rs | 4 +- client/api/src/in_mem.rs | 15 +- client/block-builder/src/lib.rs | 1 + client/db/src/bench.rs | 13 +- client/db/src/lib.rs | 108 +++++--- client/db/src/storage_cache.rs | 22 +- client/executor/runtime-test/src/lib.rs | 1 + client/executor/src/integration_tests/mod.rs | 11 +- client/executor/src/wasm_runtime.rs | 88 ++++--- client/network/src/protocol/sync.rs | 6 +- client/rpc/src/state/tests.rs | 4 +- client/service/src/client/call_executor.rs | 16 +- client/service/src/client/client.rs | 64 ++++- client/service/src/client/genesis.rs | 6 +- client/service/test/src/client/mod.rs | 16 +- frame/benchmarking/src/lib.rs | 5 +- frame/executive/src/lib.rs | 29 ++- frame/session/src/historical/mod.rs | 4 +- frame/support/src/lib.rs | 10 +- frame/support/src/storage/child.rs | 7 +- frame/support/test/compile_pass/src/lib.rs | 1 + frame/system/src/lib.rs | 11 +- frame/system/src/mock.rs | 1 + frame/transaction-storage/src/benchmarking.rs | 116 +++++---- frame/transaction-storage/src/lib.rs | 3 +- .../api/proc-macro/src/impl_runtime_apis.rs | 7 + primitives/api/src/lib.rs | 45 +--- primitives/externalities/src/lib.rs | 10 +- primitives/io/src/lib.rs | 144 ++++++++++- primitives/runtime-interface/src/impls.rs | 4 + primitives/runtime/src/lib.rs | 1 + primitives/runtime/src/traits.rs | 22 +- primitives/state-machine/Cargo.toml | 4 +- primitives/state-machine/src/backend.rs | 18 +- primitives/state-machine/src/basic.rs | 30 ++- primitives/state-machine/src/ext.rs | 169 +++++++----- .../state-machine/src/in_memory_backend.rs | 65 +++-- primitives/state-machine/src/lib.rs | 159 +++++++++--- .../src/overlayed_changes/mod.rs | 16 +- .../state-machine/src/proving_backend.rs | 99 ++++--- primitives/state-machine/src/read_only.rs | 10 +- primitives/state-machine/src/testing.rs | 58 ++++- primitives/state-machine/src/trie_backend.rs | 157 ++++++++---- .../state-machine/src/trie_backend_essence.rs | 157 +++++++----- primitives/storage/src/lib.rs | 51 ++++ primitives/tasks/src/async_externalities.rs | 10 +- .../transaction-storage-proof/src/lib.rs | 2 +- primitives/trie/Cargo.toml | 8 +- primitives/trie/benches/bench.rs | 4 +- primitives/trie/src/lib.rs | 242 ++++++++++++------ primitives/trie/src/node_codec.rs | 114 +++++++-- primitives/trie/src/node_header.rs | 93 +++++-- primitives/trie/src/storage_proof.rs | 11 +- primitives/trie/src/trie_codec.rs | 6 +- primitives/trie/src/trie_stream.rs | 81 +++--- primitives/version/Cargo.toml | 1 + .../proc-macro/src/decl_runtime_version.rs | 24 +- primitives/version/src/lib.rs | 78 +++++- test-utils/client/src/client_ext.rs | 2 +- test-utils/client/src/lib.rs | 4 +- test-utils/runtime/Cargo.toml | 2 +- test-utils/runtime/client/src/lib.rs | 2 + test-utils/runtime/src/genesismap.rs | 2 + test-utils/runtime/src/lib.rs | 14 +- test-utils/runtime/src/system.rs | 10 +- .../cli/src/commands/execute_block.rs | 2 +- .../cli/src/commands/follow_chain.rs | 17 +- .../cli/src/commands/offchain_worker.rs | 2 +- .../cli/src/commands/on_runtime_upgrade.rs | 2 +- utils/frame/try-runtime/cli/src/lib.rs | 7 +- 78 files changed, 1811 insertions(+), 779 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96146f6f8bece..c6dd25ffd74aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4179,6 +4179,17 @@ dependencies = [ "parity-util-mem", ] +[[package]] +name = "memory-db" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d505169b746dacf02f7d14d8c80b34edfd8212159c63d23c977739a0d960c626" +dependencies = [ + "hash-db", + "hashbrown 0.11.2", + "parity-util-mem", +] + [[package]] name = "memory_units" version = "0.3.0" @@ -9908,7 +9919,7 @@ dependencies = [ "criterion", "hash-db", "hex-literal", - "memory-db", + "memory-db 0.28.0", "parity-scale-codec", "scale-info", "sp-core", @@ -9929,6 +9940,7 @@ dependencies = [ "parity-wasm 0.42.2", "scale-info", "serde", + "sp-core-hashing-proc-macro", "sp-runtime", "sp-std", "sp-version-proc-macro", @@ -10201,7 +10213,7 @@ dependencies = [ "frame-system-rpc-runtime-api", "futures 0.3.16", "log 0.4.14", - "memory-db", + "memory-db 0.27.0", "pallet-babe", "pallet-timestamp", "parity-scale-codec", @@ -10840,14 +10852,14 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" [[package]] name = "trie-bench" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4edd9bdf0c2e08fd77c0fb2608179cac7ebed997ae18f58d47a2d96425ff51f0" +checksum = "36ac46f6503d0fa976193db46f9dbb1d454e5dbde76495f1316f576c7f3f0e6b" dependencies = [ "criterion", "hash-db", "keccak-hasher", - "memory-db", + "memory-db 0.28.0", "parity-scale-codec", "trie-db", "trie-root", @@ -10856,9 +10868,9 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.22.6" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eac131e334e81b6b3be07399482042838adcd7957aa0010231d0813e39e02fa" +checksum = "e3ddae50680c12ef75bfbf58416ca6622fa43d879553f6cb2ed1a817346e1ffe" dependencies = [ "hash-db", "hashbrown 0.11.2", @@ -10869,9 +10881,9 @@ dependencies = [ [[package]] name = "trie-root" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "652931506d2c1244d7217a70b99f56718a7b4161b37f04e7cd868072a99f68cd" +checksum = "9a36c5ca3911ed3c9a5416ee6c679042064b93fc637ded67e25f92e68d783891" dependencies = [ "hash-db", ] @@ -10986,8 +10998,8 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e" dependencies = [ - "cfg-if 1.0.0", - "rand 0.8.4", + "cfg-if 0.1.10", + "rand 0.6.5", "static_assertions", ] diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 5c277a1bb7942..08c6c8fb8bcba 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -102,6 +102,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, + state_version: 1, }; /// This determines the average expected block time that we are targeting. diff --git a/bin/node/bench/src/generator.rs b/bin/node/bench/src/generator.rs index e3aa1192b5d1f..d57142893f38f 100644 --- a/bin/node/bench/src/generator.rs +++ b/bin/node/bench/src/generator.rs @@ -20,7 +20,7 @@ use std::{collections::HashMap, sync::Arc}; use kvdb::KeyValueDB; use node_primitives::Hash; -use sp_trie::{trie_types::TrieDBMut, TrieMut}; +use sp_trie::{trie_types::TrieDBMutV1, TrieMut}; use crate::simple_trie::SimpleTrie; @@ -43,8 +43,7 @@ pub fn generate_trie( ); let mut trie = SimpleTrie { db, overlay: &mut overlay }; { - let mut trie_db = TrieDBMut::new(&mut trie, &mut root); - + let mut trie_db = TrieDBMutV1::::new(&mut trie, &mut root); for (key, value) in key_values { trie_db.insert(&key, &value).expect("trie insertion failed"); } diff --git a/bin/node/bench/src/trie.rs b/bin/node/bench/src/trie.rs index a17e386ca879b..374ed3568475e 100644 --- a/bin/node/bench/src/trie.rs +++ b/bin/node/bench/src/trie.rs @@ -23,7 +23,7 @@ use kvdb::KeyValueDB; use lazy_static::lazy_static; use rand::Rng; use sp_state_machine::Backend as _; -use sp_trie::{trie_types::TrieDBMut, TrieMut as _}; +use sp_trie::{trie_types::TrieDBMutV1, TrieMut as _}; use std::{borrow::Cow, collections::HashMap, sync::Arc}; use node_primitives::Hash; @@ -286,8 +286,8 @@ impl core::Benchmark for TrieWriteBenchmark { let mut overlay = HashMap::new(); let mut trie = SimpleTrie { db: kvdb.clone(), overlay: &mut overlay }; - let mut trie_db_mut = - TrieDBMut::from_existing(&mut trie, &mut new_root).expect("Failed to create TrieDBMut"); + let mut trie_db_mut = TrieDBMutV1::from_existing(&mut trie, &mut new_root) + .expect("Failed to create TrieDBMut"); for (warmup_key, warmup_value) in self.warmup_keys.iter() { let value = trie_db_mut diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index aea37b68d55ba..f1f950182f705 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -83,14 +83,14 @@ fn construct_block( parent_hash: Hash, extrinsics: Vec, ) -> (Vec, Hash) { - use sp_trie::{trie_types::Layout, TrieConfiguration}; + use sp_trie::{LayoutV0, TrieConfiguration}; // sign extrinsics. let extrinsics = extrinsics.into_iter().map(sign).collect::>(); // calculate the header fields that we can. let extrinsics_root = - Layout::::ordered_trie_root(extrinsics.iter().map(Encode::encode)) + LayoutV0::::ordered_trie_root(extrinsics.iter().map(Encode::encode)) .to_fixed_bytes() .into(); diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index 84b5728a1a840..8d21f086795a4 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -142,7 +142,7 @@ pub fn construct_block( extrinsics: Vec, babe_slot: Slot, ) -> (Vec, Hash) { - use sp_trie::{trie_types::Layout, TrieConfiguration}; + use sp_trie::{LayoutV1 as Layout, TrieConfiguration}; // sign extrinsics. let extrinsics = extrinsics.into_iter().map(sign).collect::>(); diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index a79d8997f4ce1..1a4dad1071e15 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -126,6 +126,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, + state_version: 1, }; /// The BABE epoch configuration at genesis. diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index f300e31f826c9..76f2f569814ff 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -29,7 +29,7 @@ use sp_core::offchain::OffchainStorage; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, HashFor, NumberFor}, - Justification, Justifications, Storage, + Justification, Justifications, StateVersion, Storage, }; use sp_state_machine::{ ChildStorageCollection, IndexOperation, OffchainChangesCollection, StorageCollection, @@ -166,10 +166,15 @@ pub trait BlockImportOperation { &mut self, storage: Storage, commit: bool, + state_version: StateVersion, ) -> sp_blockchain::Result; /// Inject storage data into the database replacing any existing data. - fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result; + fn reset_storage( + &mut self, + storage: Storage, + state_version: StateVersion, + ) -> sp_blockchain::Result; /// Set storage changes. fn update_storage( diff --git a/client/api/src/call_executor.rs b/client/api/src/call_executor.rs index 22af495c06542..b1fd731ca088c 100644 --- a/client/api/src/call_executor.rs +++ b/client/api/src/call_executor.rs @@ -19,7 +19,7 @@ //! A method call executor interface. use codec::{Decode, Encode}; -use sc_executor::RuntimeVersion; +use sc_executor::{RuntimeVersion, RuntimeVersionOf}; use sp_core::NativeOrEncoded; use sp_externalities::Extensions; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; @@ -42,7 +42,7 @@ pub trait ExecutorProvider { } /// Method call executor. -pub trait CallExecutor { +pub trait CallExecutor: RuntimeVersionOf { /// Externalities error type. type Error: sp_state_machine::Error; diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 39fe9e063d20b..c9650bf6db748 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -26,7 +26,7 @@ use sp_core::{ use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, HashFor, Header as HeaderT, NumberFor, Zero}, - Justification, Justifications, Storage, + Justification, Justifications, StateVersion, Storage, }; use sp_state_machine::{ Backend as StateBackend, ChildStorageCollection, InMemoryBackend, IndexOperation, @@ -506,6 +506,7 @@ where &mut self, storage: Storage, commit: bool, + state_version: StateVersion, ) -> sp_blockchain::Result { check_genesis_storage(&storage)?; @@ -519,6 +520,7 @@ where let (root, transaction) = self.old_state.full_storage_root( storage.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))), child_delta, + state_version, ); if commit { @@ -566,12 +568,17 @@ where &mut self, storage: Storage, commit: bool, + state_version: StateVersion, ) -> sp_blockchain::Result { - self.apply_storage(storage, commit) + self.apply_storage(storage, commit, state_version) } - fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result { - self.apply_storage(storage, true) + fn reset_storage( + &mut self, + storage: Storage, + state_version: StateVersion, + ) -> sp_blockchain::Result { + self.apply_storage(storage, true, state_version) } fn insert_aux(&mut self, ops: I) -> sp_blockchain::Result<()> diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index 01afaca0cacf4..c3e91fa055400 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -232,6 +232,7 @@ where header.extrinsics_root().clone(), HashFor::::ordered_trie_root( self.extrinsics.iter().map(Encode::encode).collect(), + sp_runtime::StateVersion::V0, ), ); diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index d46aca8e8ff78..cafafca9b635c 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -34,7 +34,7 @@ use sp_core::{ }; use sp_runtime::{ traits::{Block as BlockT, HashFor}, - Storage, + StateVersion, Storage, }; use sp_state_machine::{ backend::Backend as StateBackend, ChildStorageCollection, DBValue, ProofRecorder, @@ -73,6 +73,7 @@ impl sp_state_machine::Storage> for StorageDb { root: Cell, @@ -105,9 +106,10 @@ impl BenchmarkingState { record_proof: bool, enable_tracking: bool, ) -> Result { + let state_version = sp_runtime::StateVersion::default(); let mut root = B::Hash::default(); let mut mdb = MemoryDB::>::default(); - sp_state_machine::TrieDBMut::>::new(&mut mdb, &mut root); + sp_state_machine::TrieDBMutV1::>::new(&mut mdb, &mut root); let mut state = BenchmarkingState { state: RefCell::new(None), @@ -138,6 +140,7 @@ impl BenchmarkingState { state.state.borrow_mut().as_mut().unwrap().full_storage_root( genesis.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))), child_delta, + state_version, ); state.genesis = transaction.clone().drain(); state.genesis_root = root.clone(); @@ -415,6 +418,7 @@ impl StateBackend> for BenchmarkingState { fn storage_root<'a>( &self, delta: impl Iterator)>, + state_version: StateVersion, ) -> (B::Hash, Self::Transaction) where B::Hash: Ord, @@ -422,13 +426,14 @@ impl StateBackend> for BenchmarkingState { self.state .borrow() .as_ref() - .map_or(Default::default(), |s| s.storage_root(delta)) + .map_or(Default::default(), |s| s.storage_root(delta, state_version)) } fn child_storage_root<'a>( &self, child_info: &ChildInfo, delta: impl Iterator)>, + state_version: StateVersion, ) -> (B::Hash, bool, Self::Transaction) where B::Hash: Ord, @@ -436,7 +441,7 @@ impl StateBackend> for BenchmarkingState { self.state .borrow() .as_ref() - .map_or(Default::default(), |s| s.child_storage_root(child_info, delta)) + .map_or(Default::default(), |s| s.child_storage_root(child_info, delta, state_version)) } fn pairs(&self) -> Vec<(Vec, Vec)> { diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 7d46b63da5bb4..137c26fb82188 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -82,7 +82,7 @@ use sp_runtime::{ Block as BlockT, Hash, HashFor, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero, }, - Justification, Justifications, Storage, + Justification, Justifications, StateVersion, Storage, }; use sp_state_machine::{ backend::Backend as StateBackend, ChildStorageCollection, DBValue, IndexOperation, @@ -235,22 +235,24 @@ impl StateBackend> for RefTrackingState { fn storage_root<'a>( &self, delta: impl Iterator)>, + state_version: StateVersion, ) -> (B::Hash, Self::Transaction) where B::Hash: Ord, { - self.state.storage_root(delta) + self.state.storage_root(delta, state_version) } fn child_storage_root<'a>( &self, child_info: &ChildInfo, delta: impl Iterator)>, + state_version: StateVersion, ) -> (B::Hash, bool, Self::Transaction) where B::Hash: Ord, { - self.state.child_storage_root(child_info, delta) + self.state.child_storage_root(child_info, delta, state_version) } fn pairs(&self) -> Vec<(Vec, Vec)> { @@ -760,7 +762,11 @@ impl BlockImportOperation { } } - fn apply_new_state(&mut self, storage: Storage) -> ClientResult { + fn apply_new_state( + &mut self, + storage: Storage, + state_version: StateVersion, + ) -> ClientResult { if storage.top.keys().any(|k| well_known_keys::is_child_storage_key(&k)) { return Err(sp_blockchain::Error::InvalidState.into()) } @@ -775,6 +781,7 @@ impl BlockImportOperation { let (root, transaction) = self.old_state.full_storage_root( storage.top.iter().map(|(k, v)| (&k[..], Some(&v[..]))), child_delta, + state_version, ); self.db_updates = transaction; @@ -814,14 +821,23 @@ impl sc_client_api::backend::BlockImportOperation Ok(()) } - fn reset_storage(&mut self, storage: Storage) -> ClientResult { - let root = self.apply_new_state(storage)?; + fn reset_storage( + &mut self, + storage: Storage, + state_version: StateVersion, + ) -> ClientResult { + let root = self.apply_new_state(storage, state_version)?; self.commit_state = true; Ok(root) } - fn set_genesis_state(&mut self, storage: Storage, commit: bool) -> ClientResult { - let root = self.apply_new_state(storage)?; + fn set_genesis_state( + &mut self, + storage: Storage, + commit: bool, + state_version: StateVersion, + ) -> ClientResult { + let root = self.apply_new_state(storage, state_version)?; self.commit_state = commit; Ok(root) } @@ -924,7 +940,8 @@ impl EmptyStorage { pub fn new() -> Self { let mut root = Block::Hash::default(); let mut mdb = MemoryDB::>::default(); - sp_state_machine::TrieDBMut::>::new(&mut mdb, &mut root); + // both triedbmut are the same on empty storage. + sp_state_machine::TrieDBMutV1::>::new(&mut mdb, &mut root); EmptyStorage(root) } } @@ -2262,7 +2279,7 @@ pub(crate) mod tests { use sp_runtime::{ testing::{Block as RawBlock, ExtrinsicWrapper, Header}, traits::{BlakeTwo256, Hash}, - ConsensusEngineId, + ConsensusEngineId, StateVersion, }; const CONS0_ENGINE_ID: ConsensusEngineId = *b"CON0"; @@ -2295,7 +2312,7 @@ pub(crate) mod tests { let header = Header { number, parent_hash, - state_root: BlakeTwo256::trie_root(Vec::new()), + state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), digest, extrinsics_root, }; @@ -2375,6 +2392,10 @@ pub(crate) mod tests { #[test] fn set_state_data() { + set_state_data_inner(StateVersion::V0); + set_state_data_inner(StateVersion::V1); + } + fn set_state_data_inner(state_version: StateVersion) { let db = Backend::::new_test(2, 0); let hash = { let mut op = db.begin_operation().unwrap(); @@ -2390,15 +2411,18 @@ pub(crate) mod tests { header.state_root = op .old_state - .storage_root(storage.iter().map(|(x, y)| (&x[..], Some(&y[..])))) + .storage_root(storage.iter().map(|(x, y)| (&x[..], Some(&y[..]))), state_version) .0 .into(); let hash = header.hash(); - op.reset_storage(Storage { - top: storage.into_iter().collect(), - children_default: Default::default(), - }) + op.reset_storage( + Storage { + top: storage.into_iter().collect(), + children_default: Default::default(), + }, + state_version, + ) .unwrap(); op.set_block_data(header.clone(), Some(vec![]), None, None, NewBlockState::Best) .unwrap(); @@ -2427,9 +2451,10 @@ pub(crate) mod tests { let storage = vec![(vec![1, 3, 5], None), (vec![5, 5, 5], Some(vec![4, 5, 6]))]; - let (root, overlay) = op - .old_state - .storage_root(storage.iter().map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..])))); + let (root, overlay) = op.old_state.storage_root( + storage.iter().map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..]))), + state_version, + ); op.update_db_storage(overlay).unwrap(); header.state_root = root.into(); @@ -2450,6 +2475,7 @@ pub(crate) mod tests { #[test] fn delete_only_when_negative_rc() { sp_tracing::try_init_simple(); + let state_version = StateVersion::default(); let key; let backend = Backend::::new_test(1, 0); @@ -2466,13 +2492,14 @@ pub(crate) mod tests { extrinsics_root: Default::default(), }; - header.state_root = op.old_state.storage_root(std::iter::empty()).0.into(); + header.state_root = + op.old_state.storage_root(std::iter::empty(), state_version).0.into(); let hash = header.hash(); - op.reset_storage(Storage { - top: Default::default(), - children_default: Default::default(), - }) + op.reset_storage( + Storage { top: Default::default(), children_default: Default::default() }, + state_version, + ) .unwrap(); key = op.db_updates.insert(EMPTY_PREFIX, b"hello"); @@ -2506,7 +2533,7 @@ pub(crate) mod tests { header.state_root = op .old_state - .storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y)))) + .storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y))), state_version) .0 .into(); let hash = header.hash(); @@ -2543,7 +2570,7 @@ pub(crate) mod tests { header.state_root = op .old_state - .storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y)))) + .storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y))), state_version) .0 .into(); let hash = header.hash(); @@ -2577,7 +2604,7 @@ pub(crate) mod tests { header.state_root = op .old_state - .storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y)))) + .storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y))), state_version) .0 .into(); @@ -2912,6 +2939,7 @@ pub(crate) mod tests { #[test] fn storage_hash_is_cached_correctly() { + let state_version = StateVersion::default(); let backend = Backend::::new_test(10, 10); let hash0 = { @@ -2931,15 +2959,18 @@ pub(crate) mod tests { header.state_root = op .old_state - .storage_root(storage.iter().map(|(x, y)| (&x[..], Some(&y[..])))) + .storage_root(storage.iter().map(|(x, y)| (&x[..], Some(&y[..]))), state_version) .0 .into(); let hash = header.hash(); - op.reset_storage(Storage { - top: storage.into_iter().collect(), - children_default: Default::default(), - }) + op.reset_storage( + Storage { + top: storage.into_iter().collect(), + children_default: Default::default(), + }, + state_version, + ) .unwrap(); op.set_block_data(header.clone(), Some(vec![]), None, None, NewBlockState::Best) .unwrap(); @@ -2968,9 +2999,10 @@ pub(crate) mod tests { let storage = vec![(b"test".to_vec(), Some(b"test2".to_vec()))]; - let (root, overlay) = op - .old_state - .storage_root(storage.iter().map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..])))); + let (root, overlay) = op.old_state.storage_root( + storage.iter().map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..]))), + state_version, + ); op.update_db_storage(overlay).unwrap(); header.state_root = root.into(); let hash = header.hash(); @@ -3212,7 +3244,7 @@ pub(crate) mod tests { let header = Header { number: 1, parent_hash: block0, - state_root: BlakeTwo256::trie_root(Vec::new()), + state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), digest: Default::default(), extrinsics_root: Default::default(), }; @@ -3224,7 +3256,7 @@ pub(crate) mod tests { let header = Header { number: 2, parent_hash: block1, - state_root: BlakeTwo256::trie_root(Vec::new()), + state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), digest: Default::default(), extrinsics_root: Default::default(), }; @@ -3247,7 +3279,7 @@ pub(crate) mod tests { let header = Header { number: 1, parent_hash: block0, - state_root: BlakeTwo256::trie_root(Vec::new()), + state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), digest: Default::default(), extrinsics_root: Default::default(), }; diff --git a/client/db/src/storage_cache.rs b/client/db/src/storage_cache.rs index 5fef0e5b12d08..579703ea9db85 100644 --- a/client/db/src/storage_cache.rs +++ b/client/db/src/storage_cache.rs @@ -26,7 +26,10 @@ use linked_hash_map::{Entry, LinkedHashMap}; use log::trace; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use sp_core::{hexdisplay::HexDisplay, storage::ChildInfo}; -use sp_runtime::traits::{Block as BlockT, HashFor, Header, NumberFor}; +use sp_runtime::{ + traits::{Block as BlockT, HashFor, Header, NumberFor}, + StateVersion, +}; use sp_state_machine::{ backend::Backend as StateBackend, ChildStorageCollection, StorageCollection, StorageKey, StorageValue, TrieBackend, @@ -673,22 +676,24 @@ impl>, B: BlockT> StateBackend> for Cachin fn storage_root<'a>( &self, delta: impl Iterator)>, + state_version: StateVersion, ) -> (B::Hash, Self::Transaction) where B::Hash: Ord, { - self.state.storage_root(delta) + self.state.storage_root(delta, state_version) } fn child_storage_root<'a>( &self, child_info: &ChildInfo, delta: impl Iterator)>, + state_version: StateVersion, ) -> (B::Hash, bool, Self::Transaction) where B::Hash: Ord, { - self.state.child_storage_root(child_info, delta) + self.state.child_storage_root(child_info, delta, state_version) } fn pairs(&self) -> Vec<(Vec, Vec)> { @@ -871,22 +876,24 @@ impl>, B: BlockT> StateBackend> fn storage_root<'a>( &self, delta: impl Iterator)>, + state_version: StateVersion, ) -> (B::Hash, Self::Transaction) where B::Hash: Ord, { - self.caching_state().storage_root(delta) + self.caching_state().storage_root(delta, state_version) } fn child_storage_root<'a>( &self, child_info: &ChildInfo, delta: impl Iterator)>, + state_version: StateVersion, ) -> (B::Hash, bool, Self::Transaction) where B::Hash: Ord, { - self.caching_state().child_storage_root(child_info, delta) + self.caching_state().child_storage_root(child_info, delta, state_version) } fn pairs(&self) -> Vec<(Vec, Vec)> { @@ -1182,7 +1189,10 @@ mod tests { let shared = new_shared_cache::(256 * 1024, (0, 1)); let mut backend = InMemoryBackend::::default(); - backend.insert(std::iter::once((None, vec![(key.clone(), Some(vec![1]))]))); + backend.insert( + std::iter::once((None, vec![(key.clone(), Some(vec![1]))])), + Default::default(), + ); let mut s = CachingState::new(backend.clone(), shared.clone(), Some(root_parent)); s.cache.sync_cache( diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 01e46ab946354..0655160c1ab7a 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -180,6 +180,7 @@ sp_core::wasm_export_functions! { b"one"[..].into(), b"two"[..].into(), ], + sp_core::storage::StateVersion::V1, ).as_ref().to_vec() } diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 89648e9bac696..c480ad74ade67 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -33,7 +33,7 @@ use sp_core::{ }; use sp_runtime::traits::BlakeTwo256; use sp_state_machine::TestExternalities as CoreTestExternalities; -use sp_trie::{trie_types::Layout, TrieConfiguration}; +use sp_trie::{LayoutV1 as Layout, TrieConfiguration}; use std::sync::Arc; use tracing_subscriber::layer::SubscriberExt; @@ -215,21 +215,22 @@ fn panicking_should_work(wasm_method: WasmExecutionMethod) { test_wasm_execution!(storage_should_work); fn storage_should_work(wasm_method: WasmExecutionMethod) { let mut ext = TestExternalities::default(); + // Test value must be bigger than 32 bytes + // to test the trie versioning. + let value = vec![7u8; 60]; { let mut ext = ext.ext(); ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); - let output = - call_in_wasm("test_data_in", &b"Hello world".to_vec().encode(), wasm_method, &mut ext) - .unwrap(); + let output = call_in_wasm("test_data_in", &value.encode(), wasm_method, &mut ext).unwrap(); assert_eq!(output, b"all ok!".to_vec().encode()); } let expected = TestExternalities::new(sp_core::storage::Storage { top: map![ - b"input".to_vec() => b"Hello world".to_vec(), + b"input".to_vec() => value, b"foo".to_vec() => b"bar".to_vec(), b"baz".to_vec() => b"bar".to_vec() ], diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index cebfc7b01b8d8..94c4f431ef45a 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -334,22 +334,11 @@ where } fn decode_version(mut version: &[u8]) -> Result { - let v: RuntimeVersion = sp_api::OldRuntimeVersion::decode(&mut &version[..]) - .map_err(|_| { - WasmError::Instantiation( - "failed to decode \"Core_version\" result using old runtime version".into(), - ) - })? - .into(); - - let core_api_id = sp_core_hashing_proc_macro::blake2b_64!(b"Core"); - if v.has_api_with(&core_api_id, |v| v >= 3) { - sp_api::RuntimeVersion::decode(&mut version).map_err(|_| { - WasmError::Instantiation("failed to decode \"Core_version\" result".into()) - }) - } else { - Ok(v) - } + Decode::decode(&mut version).map_err(|_| { + WasmError::Instantiation( + "failed to decode \"Core_version\" result using old runtime version".into(), + ) + }) } fn decode_runtime_apis(apis: &[u8]) -> Result, WasmError> { @@ -373,17 +362,25 @@ fn decode_runtime_apis(apis: &[u8]) -> Result, WasmError> { /// sections, `Err` will be returned. pub fn read_embedded_version(blob: &RuntimeBlob) -> Result, WasmError> { if let Some(mut version_section) = blob.custom_section_contents("runtime_version") { - // We do not use `decode_version` here because the runtime_version section is not supposed - // to ever contain a legacy version. Apart from that `decode_version` relies on presence - // of a special API in the `apis` field to treat the input as a non-legacy version. However - // the structure found in the `runtime_version` always contain an empty `apis` field. - // Therefore the version read will be mistakenly treated as an legacy one. - let mut decoded_version = sp_api::RuntimeVersion::decode(&mut version_section) - .map_err(|_| WasmError::Instantiation("failed to decode version section".into()))?; - - // Don't stop on this and check if there is a special section that encodes all runtime APIs. - if let Some(apis_section) = blob.custom_section_contents("runtime_apis") { - decoded_version.apis = decode_runtime_apis(apis_section)?.into(); + let apis = blob + .custom_section_contents("runtime_apis") + .map(decode_runtime_apis) + .transpose()? + .map(Into::into); + + let core_version = apis.as_ref().and_then(|apis| sp_version::core_version_from_apis(apis)); + // We do not use `RuntimeVersion::decode` here because that `decode_version` relies on + // presence of a special API in the `apis` field to treat the input as a non-legacy version. + // However the structure found in the `runtime_version` always contain an empty `apis` + // field. Therefore the version read will be mistakenly treated as an legacy one. + let mut decoded_version = sp_version::RuntimeVersion::decode_with_version_hint( + &mut version_section, + core_version, + ) + .map_err(|_| WasmError::Instantiation("failed to decode version section".into()))?; + + if let Some(apis) = apis { + decoded_version.apis = apis; } Ok(Some(decoded_version)) @@ -455,9 +452,20 @@ mod tests { use super::*; use codec::Encode; use sp_api::{Core, RuntimeApiInfo}; + use sp_runtime::RuntimeString; use sp_wasm_interface::HostFunctions; use substrate_test_runtime::Block; + #[derive(Encode)] + pub struct OldRuntimeVersion { + pub spec_name: RuntimeString, + pub impl_name: RuntimeString, + pub authoring_version: u32, + pub spec_version: u32, + pub impl_version: u32, + pub apis: sp_version::ApisVec, + } + #[test] fn host_functions_are_equal() { let host_functions = sp_io::SubstrateHostFunctions::host_functions(); @@ -468,7 +476,7 @@ mod tests { #[test] fn old_runtime_version_decodes() { - let old_runtime_version = sp_api::OldRuntimeVersion { + let old_runtime_version = OldRuntimeVersion { spec_name: "test".into(), impl_name: "test".into(), authoring_version: 1, @@ -479,11 +487,12 @@ mod tests { let version = decode_version(&old_runtime_version.encode()).unwrap(); assert_eq!(1, version.transaction_version); + assert_eq!(0, version.state_version); } #[test] fn old_runtime_version_decodes_fails_with_version_3() { - let old_runtime_version = sp_api::OldRuntimeVersion { + let old_runtime_version = OldRuntimeVersion { spec_name: "test".into(), impl_name: "test".into(), authoring_version: 1, @@ -505,10 +514,27 @@ mod tests { impl_version: 1, apis: sp_api::create_apis_vec!([(>::ID, 3)]), transaction_version: 3, + state_version: 4, + }; + + let version = decode_version(&old_runtime_version.encode()).unwrap(); + assert_eq!(3, version.transaction_version); + assert_eq!(0, version.state_version); + + let old_runtime_version = sp_api::RuntimeVersion { + spec_name: "test".into(), + impl_name: "test".into(), + authoring_version: 1, + spec_version: 1, + impl_version: 1, + apis: sp_api::create_apis_vec!([(>::ID, 4)]), + transaction_version: 3, + state_version: 4, }; let version = decode_version(&old_runtime_version.encode()).unwrap(); assert_eq!(3, version.transaction_version); + assert_eq!(4, version.state_version); } #[test] @@ -518,15 +544,15 @@ mod tests { sp_maybe_compressed_blob::CODE_BLOB_BOMB_LIMIT, ) .expect("Decompressing works"); - let runtime_version = RuntimeVersion { spec_name: "test_replace".into(), impl_name: "test_replace".into(), authoring_version: 100, spec_version: 100, impl_version: 100, - apis: sp_api::create_apis_vec!([(>::ID, 3)]), + apis: sp_api::create_apis_vec!([(>::ID, 4)]), transaction_version: 100, + state_version: 1, }; let embedded = sp_version::embed::embed_runtime_version(&wasm, runtime_version.clone()) diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index 37646875e3b16..a84f5131242ef 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -2539,8 +2539,10 @@ fn validate_blocks( } if let (Some(header), Some(body)) = (&b.header, &b.body) { let expected = *header.extrinsics_root(); - let got = - HashFor::::ordered_trie_root(body.iter().map(Encode::encode).collect()); + let got = HashFor::::ordered_trie_root( + body.iter().map(Encode::encode).collect(), + sp_runtime::StateVersion::V0, + ); if expected != got { debug!( target:"sync", diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index d360701c88b2a..12e1c449d3bd4 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -526,11 +526,11 @@ fn should_return_runtime_version() { ); let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ - \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",3],\ + \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\ [\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",5],\ [\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",2],\ [\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\ - \"transactionVersion\":1}"; + \"transactionVersion\":1,\"stateVersion\":1}"; let runtime_version = executor::block_on(api.runtime_version(None.into())).unwrap(); let serialized = serde_json::to_string(&runtime_version).unwrap(); diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 9f56424daf2f5..2acbbb75dcb1d 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -90,7 +90,7 @@ where Block: BlockT, B: backend::Backend, { - let spec = self.runtime_version(id)?; + let spec = CallExecutor::runtime_version(self, id)?; let code = if let Some(d) = self .wasm_override .as_ref() @@ -321,6 +321,20 @@ where } } +impl RuntimeVersionOf for LocalCallExecutor +where + E: RuntimeVersionOf, + Block: BlockT, +{ + fn runtime_version( + &self, + ext: &mut dyn sp_externalities::Externalities, + runtime_code: &sp_core::traits::RuntimeCode, + ) -> Result { + RuntimeVersionOf::runtime_version(&self.executor, ext, runtime_code) + } +} + impl sp_version::GetRuntimeVersionAt for LocalCallExecutor where B: backend::Backend, diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 833d8b7bc2257..1f76fe017ae07 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -45,7 +45,7 @@ use sc_client_api::{ use sc_consensus::{ BlockCheckParams, BlockImportParams, ForkChoiceStrategy, ImportResult, StateAction, }; -use sc_executor::RuntimeVersion; +use sc_executor::{RuntimeVersion, RuntimeVersionOf}; use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sp_api::{ ApiExt, ApiRef, CallApiAt, CallApiAtParams, ConstructRuntimeApi, Core as CoreApi, @@ -60,8 +60,8 @@ use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sp_core::{ storage::{ - well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, StorageChild, StorageData, - StorageKey, + well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, Storage, StorageChild, + StorageData, StorageKey, }, NativeOrEncoded, }; @@ -72,7 +72,7 @@ use sp_runtime::{ traits::{ Block as BlockT, HashFor, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero, }, - BuildStorage, Digest, Justification, Justifications, + BuildStorage, Digest, Justification, Justifications, StateVersion, }; use sp_state_machine::{ prove_child_read, prove_range_read_with_child_with_size, prove_read, @@ -81,7 +81,7 @@ use sp_state_machine::{ }; use sp_trie::{CompactProof, StorageProof}; use std::{ - collections::{HashMap, HashSet}, + collections::{hash_map::DefaultHasher, HashMap, HashSet}, marker::PhantomData, panic::UnwindSafe, path::PathBuf, @@ -93,7 +93,6 @@ use std::{ use { super::call_executor::LocalCallExecutor, sc_client_api::in_mem, - sc_executor::RuntimeVersionOf, sp_core::traits::{CodeExecutor, SpawnNamed}, }; @@ -334,8 +333,11 @@ where if info.finalized_state.is_none() { let genesis_storage = build_genesis_storage.build_storage().map_err(sp_blockchain::Error::Storage)?; + let genesis_state_version = + Self::resolve_state_version_from_wasm(&genesis_storage, &executor)?; let mut op = backend.begin_operation()?; - let state_root = op.set_genesis_state(genesis_storage, !config.no_genesis)?; + let state_root = + op.set_genesis_state(genesis_storage, !config.no_genesis, genesis_state_version)?; let genesis_block = genesis::construct_genesis_block::(state_root.into()); info!( "🔨 Initializing Genesis block/state (state: {}, header-hash: {})", @@ -403,7 +405,7 @@ where /// Get the RuntimeVersion at a given block. pub fn runtime_version_at(&self, id: &BlockId) -> sp_blockchain::Result { - self.executor.runtime_version(id) + CallExecutor::runtime_version(&self.executor, id) } /// Apply a checked and validated block to an operation. If a justification is provided @@ -606,7 +608,11 @@ where } } - let state_root = operation.op.reset_storage(storage)?; + // This is use by fast sync for runtime version to be resolvable from + // changes. + let state_version = + Self::resolve_state_version_from_wasm(&storage, &self.executor)?; + let state_root = operation.op.reset_storage(storage, state_version)?; if state_root != *import_headers.post().state_root() { // State root mismatch when importing state. This should not happen in // safe fast sync mode, but may happen in unsafe mode. @@ -1041,6 +1047,35 @@ where trace!("Collected {} uncles", uncles.len()); Ok(uncles) } + + fn resolve_state_version_from_wasm( + storage: &Storage, + executor: &E, + ) -> sp_blockchain::Result { + if let Some(wasm) = storage.top.get(well_known_keys::CODE) { + let mut ext = sp_state_machine::BasicExternalities::new_empty(); // just to read runtime version. + + let code_fetcher = sp_core::traits::WrappedRuntimeCode(wasm.as_slice().into()); + let runtime_code = sp_core::traits::RuntimeCode { + code_fetcher: &code_fetcher, + heap_pages: None, + hash: { + use std::hash::{Hash, Hasher}; + let mut state = DefaultHasher::new(); + wasm.hash(&mut state); + state.finish().to_le_bytes().to_vec() + }, + }; + let runtime_version = + RuntimeVersionOf::runtime_version(executor, &mut ext, &runtime_code) + .map_err(|e| sp_blockchain::Error::VersionInvalid(format!("{:?}", e)))?; + Ok(runtime_version.state_version()) + } else { + Err(sp_blockchain::Error::VersionInvalid( + "Runtime missing from initial storage, could not read state version.".to_string(), + )) + } + } } impl UsageProvider for Client @@ -1095,12 +1130,14 @@ where size_limit: usize, ) -> sp_blockchain::Result<(CompactProof, u32)> { let state = self.state_at(id)?; - let root = state.storage_root(std::iter::empty()).0; + // this is a read proof, using version V0 or V1 is equivalent. + let root = state.storage_root(std::iter::empty(), StateVersion::V0).0; let (proof, count) = prove_range_read_with_child_with_size::<_, HashFor>( state, size_limit, start_key, )?; - let proof = sp_trie::encode_compact::>>(proof, root) + // This is read proof only, we can use either LayoutV0 or LayoutV1. + let proof = sp_trie::encode_compact::>>(proof, root) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?; Ok((proof, count)) } @@ -1225,7 +1262,8 @@ where start_key: &[Vec], ) -> sp_blockchain::Result<(KeyValueStates, usize)> { let mut db = sp_state_machine::MemoryDB::>::new(&[]); - let _ = sp_trie::decode_compact::>, _, _>( + // Compact encoding + let _ = sp_trie::decode_compact::>, _, _>( &mut db, proof.iter_compact_encoded_nodes(), Some(&root), @@ -1594,7 +1632,7 @@ where } fn runtime_version_at(&self, at: &BlockId) -> Result { - self.runtime_version_at(at).map_err(Into::into) + CallExecutor::runtime_version(&self.executor, at).map_err(Into::into) } } diff --git a/client/service/src/client/genesis.rs b/client/service/src/client/genesis.rs index e764e8e24f105..b48ca2464b54e 100644 --- a/client/service/src/client/genesis.rs +++ b/client/service/src/client/genesis.rs @@ -22,8 +22,10 @@ use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero /// Create a genesis block, given the initial storage. pub fn construct_genesis_block(state_root: Block::Hash) -> Block { - let extrinsics_root = - <<::Header as HeaderT>::Hashing as HashT>::trie_root(Vec::new()); + let extrinsics_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( + Vec::new(), + sp_runtime::StateVersion::V0, + ); Block::new( <::Header as HeaderT>::new( diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 286d819a6ce5e..cd4ce132b6634 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -34,13 +34,13 @@ use sp_core::{testing::TaskExecutor, H256}; use sp_runtime::{ generic::BlockId, traits::{BlakeTwo256, Block as BlockT, Header as HeaderT}, - ConsensusEngineId, Justifications, + ConsensusEngineId, Justifications, StateVersion, }; use sp_state_machine::{ backend::Backend as _, ExecutionStrategy, InMemoryBackend, OverlayedChanges, StateMachine, }; use sp_storage::{ChildInfo, StorageKey}; -use sp_trie::{trie_types::Layout, TrieConfiguration}; +use sp_trie::{LayoutV0, TrieConfiguration}; use std::{collections::HashSet, sync::Arc}; use substrate_test_runtime::TestAPI; use substrate_test_runtime_client::{ @@ -90,7 +90,7 @@ fn construct_block( let transactions = txs.into_iter().map(|tx| tx.into_signed_tx()).collect::>(); let iter = transactions.iter().map(Encode::encode); - let extrinsics_root = Layout::::ordered_trie_root(iter).into(); + let extrinsics_root = LayoutV0::::ordered_trie_root(iter).into(); let mut header = Header { parent_hash, @@ -177,7 +177,7 @@ fn construct_genesis_should_work_with_native() { .genesis_map(); let genesis_hash = insert_genesis_block(&mut storage); - let backend = InMemoryBackend::from(storage); + let backend = InMemoryBackend::from((storage, StateVersion::default())); let (b1data, _b1hash) = block1(genesis_hash, &backend); let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend); let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); @@ -210,7 +210,7 @@ fn construct_genesis_should_work_with_wasm() { .genesis_map(); let genesis_hash = insert_genesis_block(&mut storage); - let backend = InMemoryBackend::from(storage); + let backend = InMemoryBackend::from((storage, StateVersion::default())); let (b1data, _b1hash) = block1(genesis_hash, &backend); let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend); let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); @@ -243,7 +243,7 @@ fn construct_genesis_with_bad_transaction_should_panic() { .genesis_map(); let genesis_hash = insert_genesis_block(&mut storage); - let backend = InMemoryBackend::from(storage); + let backend = InMemoryBackend::from((storage, StateVersion::default())); let (b1data, _b1hash) = block1(genesis_hash, &backend); let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend); let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); @@ -418,8 +418,8 @@ fn uncles_with_multiple_forks() { // block tree: // G -> A1 -> A2 -> A3 -> A4 -> A5 // A1 -> B2 -> B3 -> B4 - // B2 -> C3 - // A1 -> D2 + // B2 -> C3 + // A1 -> D2 let mut client = substrate_test_runtime_client::new(); // G -> A1 diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 56545914dcba3..3e1ed1ed2f11d 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -42,8 +42,9 @@ pub use sp_io::storage::root as storage_root; #[doc(hidden)] pub use sp_runtime::traits::Zero; #[doc(hidden)] -pub use sp_std::{self, boxed::Box, prelude::Vec, str, vec}; +pub use sp_runtime::StateVersion; #[doc(hidden)] +pub use sp_std::{self, boxed::Box, prelude::Vec, str, vec}; pub use sp_storage::TrackedStorageKey; pub use utils::*; @@ -1079,7 +1080,7 @@ macro_rules! impl_benchmark { // Time the storage root recalculation. let start_storage_root = $crate::benchmarking::current_time(); - $crate::storage_root(); + $crate::storage_root($crate::StateVersion::V1); let finish_storage_root = $crate::benchmarking::current_time(); let elapsed_storage_root = finish_storage_root - start_storage_root; diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index cc013d4c333f4..1b74bdc2fea0a 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -671,7 +671,7 @@ mod tests { #[pallet::weight(0)] pub fn calculate_storage_root(_origin: OriginFor) -> DispatchResult { - let root = sp_io::storage::root(); + let root = sp_io::storage::root(sp_runtime::StateVersion::V1); sp_io::storage::set("storage_root".as_bytes(), &root); Ok(()) } @@ -897,17 +897,32 @@ mod tests { t.into() } + fn new_test_ext_v0(balance_factor: Balance) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)] } + .assimilate_storage(&mut t) + .unwrap(); + (t, sp_runtime::StateVersion::V0).into() + } + #[test] fn block_import_works() { - new_test_ext(1).execute_with(|| { + block_import_works_inner( + new_test_ext_v0(1), + hex!("1039e1a4bd0cf5deefe65f313577e70169c41c7773d6acf31ca8d671397559f5").into(), + ); + block_import_works_inner( + new_test_ext(1), + hex!("75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5").into(), + ); + } + fn block_import_works_inner(mut ext: sp_io::TestExternalities, state_root: H256) { + ext.execute_with(|| { Executive::execute_block(Block { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!( - "1039e1a4bd0cf5deefe65f313577e70169c41c7773d6acf31ca8d671397559f5" - ) - .into(), + state_root, extrinsics_root: hex!( "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" ) @@ -948,7 +963,7 @@ mod tests { parent_hash: [69u8; 32].into(), number: 1, state_root: hex!( - "49cd58a254ccf6abc4a023d9a22dcfc421e385527a250faec69f8ad0d8ed3e48" + "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5" ) .into(), extrinsics_root: [0u8; 32].into(), diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index a3e64f4f9efa4..fa7cb9ee91c03 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -39,7 +39,7 @@ use sp_session::{MembershipProof, ValidatorCount}; use sp_staking::SessionIndex; use sp_std::prelude::*; use sp_trie::{ - trie_types::{TrieDB, TrieDBMut}, + trie_types::{TrieDB, TrieDBMutV0}, MemoryDB, Recorder, Trie, TrieMut, EMPTY_PREFIX, }; @@ -236,7 +236,7 @@ impl ProvingTrie { let mut root = Default::default(); { - let mut trie = TrieDBMut::new(&mut db, &mut root); + let mut trie = TrieDBMutV0::new(&mut db, &mut root); for (i, (validator, full_id)) in validators.into_iter().enumerate() { let i = i as u32; let keys = match >::load_keys(&validator) { diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 2adcd8ce4efcf..2a23d203adf63 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -46,7 +46,7 @@ pub use sp_core_hashing_proc_macro; #[doc(hidden)] pub use sp_io::{self, storage::root as storage_root}; #[doc(hidden)] -pub use sp_runtime::RuntimeDebug; +pub use sp_runtime::{RuntimeDebug, StateVersion}; #[cfg(feature = "std")] #[doc(hidden)] pub use sp_state_machine::BasicExternalities; @@ -751,9 +751,9 @@ macro_rules! assert_noop { $x:expr, $y:expr $(,)? ) => { - let h = $crate::storage_root(); + let h = $crate::storage_root($crate::StateVersion::V1); $crate::assert_err!($x, $y); - assert_eq!(h, $crate::storage_root()); + assert_eq!(h, $crate::storage_root($crate::StateVersion::V1)); }; } @@ -766,9 +766,9 @@ macro_rules! assert_storage_noop { ( $x:expr ) => { - let h = $crate::storage_root(); + let h = $crate::storage_root($crate::StateVersion::V1); $x; - assert_eq!(h, $crate::storage_root()); + assert_eq!(h, $crate::storage_root($crate::StateVersion::V1)); }; } diff --git a/frame/support/src/storage/child.rs b/frame/support/src/storage/child.rs index 5497f642067cf..19b00d1051361 100644 --- a/frame/support/src/storage/child.rs +++ b/frame/support/src/storage/child.rs @@ -24,7 +24,7 @@ pub use crate::sp_io::KillStorageResult; use crate::sp_std::prelude::*; use codec::{Codec, Decode, Encode}; -pub use sp_core::storage::{ChildInfo, ChildType}; +pub use sp_core::storage::{ChildInfo, ChildType, StateVersion}; /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. pub fn get(child_info: &ChildInfo, key: &[u8]) -> Option { @@ -167,9 +167,10 @@ pub fn put_raw(child_info: &ChildInfo, key: &[u8], value: &[u8]) { } /// Calculate current child root value. -pub fn root(child_info: &ChildInfo) -> Vec { +pub fn root(child_info: &ChildInfo, version: StateVersion) -> Vec { match child_info.child_type() { - ChildType::ParentKeyId => sp_io::default_child_storage::root(child_info.storage_key()), + ChildType::ParentKeyId => + sp_io::default_child_storage::root(child_info.storage_key(), version), } } diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index a5586996215e9..47b81e1020693 100644 --- a/frame/support/test/compile_pass/src/lib.rs +++ b/frame/support/test/compile_pass/src/lib.rs @@ -41,6 +41,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 0, apis: sp_version::create_apis_vec!([]), transaction_version: 0, + state_version: 0, }; pub type Signature = sr25519::Signature; diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index e167f44ffd88c..8026f77902ba4 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -127,13 +127,19 @@ pub use extensions::check_mortality::CheckMortality as CheckEra; pub use weights::WeightInfo; /// Compute the trie root of a list of extrinsics. +/// +/// The merkle proof is using the same trie as runtime state with +/// `state_version` 0. pub fn extrinsics_root(extrinsics: &[E]) -> H::Output { extrinsics_data_root::(extrinsics.iter().map(codec::Encode::encode).collect()) } /// Compute the trie root of a list of extrinsics. +/// +/// The merkle proof is using the same trie as runtime state with +/// `state_version` 0. pub fn extrinsics_data_root(xts: Vec>) -> H::Output { - H::ordered_trie_root(xts) + H::ordered_trie_root(xts, sp_core::storage::StateVersion::V0) } /// An object to track the currently used extrinsic weight in a block. @@ -1355,7 +1361,8 @@ impl Pallet { >::remove(to_remove); } - let storage_root = T::Hash::decode(&mut &sp_io::storage::root()[..]) + let version = T::Version::get().state_version(); + let storage_root = T::Hash::decode(&mut &sp_io::storage::root(version)[..]) .expect("Node is configured to use the same hash; qed"); ::new( diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index d8d9e7323aed6..5d10962a8f402 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -53,6 +53,7 @@ parameter_types! { impl_version: 1, apis: sp_version::create_apis_vec!([]), transaction_version: 1, + state_version: 1, }; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 10, diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs index 0f90b51087ae9..b03c75148fa12 100644 --- a/frame/transaction-storage/src/benchmarking.rs +++ b/frame/transaction-storage/src/benchmarking.rs @@ -29,54 +29,77 @@ use sp_transaction_storage_proof::TransactionStorageProof; use crate::Pallet as TransactionStorage; +// Proof generated from max size storage: +// ``` +// let mut transactions = Vec::new(); +// let tx_size = DEFAULT_MAX_TRANSACTION_SIZE; +// for _ in 0..DEFAULT_MAX_BLOCK_TRANSACTIONS { +// transactions.push(vec![0; tx_size]); +// } +// let hash = vec![0; 32]; +// build_proof(hash.as_slice(), transactions).unwrap().encode() +// ``` +// while hardforcing target chunk key in `build_proof` to [22, 21, 1, 0]. const PROOF: &[u8] = &hex_literal::hex!( " - 0104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 000000000000000000000000000000014cd0780ffff80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe8 - 7d12a3662c4c0080e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb - 13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2 - f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f - 1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f - 3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a47 - 8e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cf - f93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e31 - 6a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f - 53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c8 - 0e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4cbd05807777809a5d7a720ce5f9d9a012 - fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a3dc2f6b9e957d129e610c06d411e11743062dc1cf - 3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce186c4ddc53f118e0ddd4decd8cc809a5d7a720ce5f9d9 - a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a3dc2f6b9e957d129e610c06d411e11743062d - c1cf3ac289390ae4c00809a5d7a720ce5f9d9a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a - 3dc2f6b9e957d129e610c06d411e11743062dc1cf3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce186c - 4ddc53f118e0ddd4decd8cc809a5d7a720ce5f9d9a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bc - bf8a3dc2f6b9e957d129e610c06d411e11743062dc1cf3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce - 186c4ddc53f118e0ddd4decd8cccd0780ffff8081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb0 - 3bdb31008081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253 - 515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa139 - 8e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5 - f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3a - a1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2b - a8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f32 - 2d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa - 9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f0 - 2f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b82 - 5bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb31cd0780ffff80b4f23ac50c8e67d9b280f2b31a - 5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd1885 - 44c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2 - b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd - 188544c5f9b0080b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9 - b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84 - d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e - 67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977aca - ac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac5 - 0c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b89297 - 7acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b104401 - 0000 -" + 0104000000000000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000000000014cd0780ffff8030 + 2eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba0080302eb0a6d2 + f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15 + f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1 + 004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e304 + 8cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697 + eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a + 30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302e + b0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b + 834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e7 + 29d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c10046 + 57e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf2 + 06d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb1 + 53f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba + bd058077778010fd81bc1359802f0b871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de + 808da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff338ad7120b0256c28380221ce17f + 19117affa96e077905fe48a99723a065969c638593b7d9ab57b538438010fd81bc1359802f0b + 871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de808da338e6b722f7bf2051901bd5bc + cee5e71d5cf6b1faff338ad7120b0256c283008010fd81bc1359802f0b871aeb95e4410a8ec9 + 2b93af10ea767a2027cf4734e8de808da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff + 338ad7120b0256c28380221ce17f19117affa96e077905fe48a99723a065969c638593b7d9ab + 57b538438010fd81bc1359802f0b871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de80 + 8da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff338ad7120b0256c28380221ce17f19 + 117affa96e077905fe48a99723a065969c638593b7d9ab57b53843cd0780ffff804509f59593 + fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c00804509f59593fd47b1a9 + 7189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba6 + 5a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0 + 346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f983 + 6e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf89 + 1a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c8045 + 09f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd + 47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189 + 127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a56 + 49cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb03466 + 37f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e15 + 5eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a93 + 9c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939ccd0780ff + ff8078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e + 776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea + 05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f + 015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d + 06feafa3610fc44a5b2ef543cb81008078916e776c64ccea05e958559f015c082d9d06feafa3 + 610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b + 2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb81 + 8078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e77 + 6c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05 + e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f01 + 5c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06 + feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610f + c44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef5 + 43cb811044010000 + " ); type BalanceOf = @@ -136,7 +159,6 @@ benchmarks! { )?; } run_to_block::(StoragePeriod::::get() + T::BlockNumber::one()); - let random_hash = [0u8]; let mut encoded_proof = PROOF; let proof = TransactionStorageProof::decode(&mut encoded_proof).unwrap(); }: check_proof(RawOrigin::None, proof) diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index 94937c04ed5d8..2cd47b1cd0db2 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -188,7 +188,7 @@ pub mod pallet { // Chunk data and compute storage root let chunk_count = num_chunks(data.len() as u32); let chunks = data.chunks(CHUNK_SIZE).map(|c| c.to_vec()).collect(); - let root = sp_io::trie::blake2_256_ordered_root(chunks); + let root = sp_io::trie::blake2_256_ordered_root(chunks, sp_runtime::StateVersion::V1); let content_hash = sp_io::hashing::blake2_256(&data); let extrinsic_index = >::extrinsic_index() @@ -300,6 +300,7 @@ pub mod pallet { &proof.proof, &encode_index(chunk_index), &proof.chunk, + sp_runtime::StateVersion::V1, ), Error::::InvalidProof ); diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index dd2a7f6c14909..db3ab3b76850e 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -293,10 +293,17 @@ fn generate_runtime_api_base_structures() -> Result { #crate_::StorageChanges, String > where Self: Sized { + let at = #crate_::BlockId::Hash(parent_hash.clone()); + let state_version = self.call + .runtime_version_at(&at) + .map(|v| v.state_version()) + .map_err(|e| format!("Failed to get state version: {:?}", e))?; + self.changes.replace(Default::default()).into_storage_changes( backend, parent_hash, self.storage_transaction_cache.replace(Default::default()), + state_version, ) } } diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index 7f64e191941f7..41c0151d6c538 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -84,6 +84,8 @@ pub use sp_core::NativeOrEncoded; use sp_core::OpaqueMetadata; #[doc(hidden)] pub use sp_core::{offchain, ExecutionContext}; +#[cfg(feature = "std")] +pub use sp_runtime::StateVersion; #[doc(hidden)] pub use sp_runtime::{ generic::BlockId, @@ -269,6 +271,7 @@ pub use sp_api_proc_macro::decl_runtime_apis; /// // Here we are exposing the runtime api versions. /// apis: RUNTIME_API_VERSIONS, /// transaction_version: 1, +/// state_version: 1, /// }; /// /// # fn main() {} @@ -654,53 +657,13 @@ pub fn deserialize_runtime_api_info(bytes: [u8; RUNTIME_API_INFO_SIZE]) -> ([u8; (id, version) } -#[derive(codec::Encode, codec::Decode)] -pub struct OldRuntimeVersion { - pub spec_name: RuntimeString, - pub impl_name: RuntimeString, - pub authoring_version: u32, - pub spec_version: u32, - pub impl_version: u32, - pub apis: ApisVec, -} - -impl From for RuntimeVersion { - fn from(x: OldRuntimeVersion) -> Self { - Self { - spec_name: x.spec_name, - impl_name: x.impl_name, - authoring_version: x.authoring_version, - spec_version: x.spec_version, - impl_version: x.impl_version, - apis: x.apis, - transaction_version: 1, - } - } -} - -impl From for OldRuntimeVersion { - fn from(x: RuntimeVersion) -> Self { - Self { - spec_name: x.spec_name, - impl_name: x.impl_name, - authoring_version: x.authoring_version, - spec_version: x.spec_version, - impl_version: x.impl_version, - apis: x.apis, - } - } -} - decl_runtime_apis! { /// The `Core` runtime api that every Substrate runtime needs to implement. #[core_trait] - #[api_version(3)] + #[api_version(4)] pub trait Core { /// Returns the version of the runtime. fn version() -> RuntimeVersion; - /// Returns the version of the runtime. - #[changed_in(3)] - fn version() -> OldRuntimeVersion; /// Execute the given block. fn execute_block(block: Block); /// Initialize a block with the given header. diff --git a/primitives/externalities/src/lib.rs b/primitives/externalities/src/lib.rs index aac45234deadd..6d560c3c7f11b 100644 --- a/primitives/externalities/src/lib.rs +++ b/primitives/externalities/src/lib.rs @@ -31,7 +31,7 @@ use sp_std::{ vec::Vec, }; -use sp_storage::{ChildInfo, TrackedStorageKey}; +use sp_storage::{ChildInfo, StateVersion, TrackedStorageKey}; pub use extensions::{Extension, ExtensionStore, Extensions}; pub use scope_limited::{set_and_run_with_externalities, with_externalities}; @@ -157,7 +157,7 @@ pub trait Externalities: ExtensionStore { /// This will also update all child storage keys in the top-level storage map. /// /// The returned hash is defined by the `Block` and is SCALE encoded. - fn storage_root(&mut self) -> Vec; + fn storage_root(&mut self, state_version: StateVersion) -> Vec; /// Get the trie root of a child storage map. /// @@ -165,7 +165,11 @@ pub trait Externalities: ExtensionStore { /// /// If the storage root equals the default hash as defined by the trie, the key in the top-level /// storage map will be removed. - fn child_storage_root(&mut self, child_info: &ChildInfo) -> Vec; + fn child_storage_root( + &mut self, + child_info: &ChildInfo, + state_version: StateVersion, + ) -> Vec; /// Append storage item. /// diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 1edf87703fbe6..9025ae3d76f43 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -51,11 +51,13 @@ use sp_core::{ offchain::{ HttpError, HttpRequestId, HttpRequestStatus, OpaqueNetworkState, StorageKind, Timestamp, }, - sr25519, LogLevel, LogLevelFilter, OpaquePeerId, H256, + sr25519, + storage::StateVersion, + LogLevel, LogLevelFilter, OpaquePeerId, H256, }; #[cfg(feature = "std")] -use sp_trie::{trie_types::Layout, TrieConfiguration}; +use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; use sp_runtime_interface::{ pass_by::{PassBy, PassByCodec}, @@ -192,7 +194,17 @@ pub trait Storage { /// /// Returns a `Vec` that holds the SCALE encoded hash. fn root(&mut self) -> Vec { - self.storage_root() + self.storage_root(StateVersion::V0) + } + + /// "Commit" all existing operations and compute the resulting storage root. + /// + /// The hashing algorithm is defined by the `Block`. + /// + /// Returns a `Vec` that holds the SCALE encoded hash. + #[version(2)] + fn root(&mut self, version: StateVersion) -> Vec { + self.storage_root(version) } /// Always returns `None`. This function exists for compatibility reasons. @@ -373,7 +385,19 @@ pub trait DefaultChildStorage { /// Returns a `Vec` that holds the SCALE encoded hash. fn root(&mut self, storage_key: &[u8]) -> Vec { let child_info = ChildInfo::new_default(storage_key); - self.child_storage_root(&child_info) + self.child_storage_root(&child_info, StateVersion::V0) + } + + /// Default child root calculation. + /// + /// "Commit" all existing operations and compute the resulting child storage root. + /// The hashing algorithm is defined by the `Block`. + /// + /// Returns a `Vec` that holds the SCALE encoded hash. + #[version(2)] + fn root(&mut self, storage_key: &[u8], version: StateVersion) -> Vec { + let child_info = ChildInfo::new_default(storage_key); + self.child_storage_root(&child_info, version) } /// Child storage key iteration. @@ -390,27 +414,63 @@ pub trait DefaultChildStorage { pub trait Trie { /// A trie root formed from the iterated items. fn blake2_256_root(input: Vec<(Vec, Vec)>) -> H256 { - Layout::::trie_root(input) + LayoutV0::::trie_root(input) + } + + /// A trie root formed from the iterated items. + #[version(2)] + fn blake2_256_root(input: Vec<(Vec, Vec)>, version: StateVersion) -> H256 { + match version { + StateVersion::V0 => LayoutV0::::trie_root(input), + StateVersion::V1 => LayoutV1::::trie_root(input), + } } /// A trie root formed from the enumerated items. fn blake2_256_ordered_root(input: Vec>) -> H256 { - Layout::::ordered_trie_root(input) + LayoutV0::::ordered_trie_root(input) + } + + /// A trie root formed from the enumerated items. + #[version(2)] + fn blake2_256_ordered_root(input: Vec>, version: StateVersion) -> H256 { + match version { + StateVersion::V0 => LayoutV0::::ordered_trie_root(input), + StateVersion::V1 => LayoutV1::::ordered_trie_root(input), + } } /// A trie root formed from the iterated items. fn keccak_256_root(input: Vec<(Vec, Vec)>) -> H256 { - Layout::::trie_root(input) + LayoutV0::::trie_root(input) + } + + /// A trie root formed from the iterated items. + #[version(2)] + fn keccak_256_root(input: Vec<(Vec, Vec)>, version: StateVersion) -> H256 { + match version { + StateVersion::V0 => LayoutV0::::trie_root(input), + StateVersion::V1 => LayoutV1::::trie_root(input), + } } /// A trie root formed from the enumerated items. fn keccak_256_ordered_root(input: Vec>) -> H256 { - Layout::::ordered_trie_root(input) + LayoutV0::::ordered_trie_root(input) + } + + /// A trie root formed from the enumerated items. + #[version(2)] + fn keccak_256_ordered_root(input: Vec>, version: StateVersion) -> H256 { + match version { + StateVersion::V0 => LayoutV0::::ordered_trie_root(input), + StateVersion::V1 => LayoutV1::::ordered_trie_root(input), + } } /// Verify trie proof fn blake2_256_verify_proof(root: H256, proof: &[Vec], key: &[u8], value: &[u8]) -> bool { - sp_trie::verify_trie_proof::, _, _, _>( + sp_trie::verify_trie_proof::, _, _, _>( &root, proof, &[(key, Some(value))], @@ -418,15 +478,69 @@ pub trait Trie { .is_ok() } + /// Verify trie proof + #[version(2)] + fn blake2_256_verify_proof( + root: H256, + proof: &[Vec], + key: &[u8], + value: &[u8], + version: StateVersion, + ) -> bool { + match version { + StateVersion::V0 => sp_trie::verify_trie_proof::< + LayoutV0, + _, + _, + _, + >(&root, proof, &[(key, Some(value))]) + .is_ok(), + StateVersion::V1 => sp_trie::verify_trie_proof::< + LayoutV1, + _, + _, + _, + >(&root, proof, &[(key, Some(value))]) + .is_ok(), + } + } + /// Verify trie proof fn keccak_256_verify_proof(root: H256, proof: &[Vec], key: &[u8], value: &[u8]) -> bool { - sp_trie::verify_trie_proof::, _, _, _>( + sp_trie::verify_trie_proof::, _, _, _>( &root, proof, &[(key, Some(value))], ) .is_ok() } + + /// Verify trie proof + #[version(2)] + fn keccak_256_verify_proof( + root: H256, + proof: &[Vec], + key: &[u8], + value: &[u8], + version: StateVersion, + ) -> bool { + match version { + StateVersion::V0 => sp_trie::verify_trie_proof::< + LayoutV0, + _, + _, + _, + >(&root, proof, &[(key, Some(value))]) + .is_ok(), + StateVersion::V1 => sp_trie::verify_trie_proof::< + LayoutV1, + _, + _, + _, + >(&root, proof, &[(key, Some(value))]) + .is_ok(), + } + } } /// Interface that provides miscellaneous functions for communicating between the runtime and the @@ -1570,6 +1684,16 @@ mod tests { assert_eq!(storage::get(b"hello"), None); assert_eq!(storage::get(b"foo"), Some(b"bar".to_vec())); }); + + let value = vec![7u8; 35]; + let storage = + Storage { top: map![b"foo00".to_vec() => value.clone()], children_default: map![] }; + t = BasicExternalities::new(storage); + + t.execute_with(|| { + assert_eq!(storage::get(b"hello"), None); + assert_eq!(storage::get(b"foo00"), Some(value.clone())); + }); } #[test] diff --git a/primitives/runtime-interface/src/impls.rs b/primitives/runtime-interface/src/impls.rs index 35badd27fa992..16eecbd021e00 100644 --- a/primitives/runtime-interface/src/impls.rs +++ b/primitives/runtime-interface/src/impls.rs @@ -544,3 +544,7 @@ impl PassBy for sp_wasm_interface::Value { impl PassBy for sp_storage::TrackedStorageKey { type PassBy = Codec; } + +impl PassBy for sp_storage::StateVersion { + type PassBy = Enum; +} diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index deea4a73c8e2d..7fdc5dda5c74b 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -40,6 +40,7 @@ pub use paste; #[doc(hidden)] pub use sp_application_crypto as app_crypto; +pub use sp_core::storage::StateVersion; #[cfg(feature = "std")] pub use sp_core::storage::{Storage, StorageChild}; diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 0ddd8cae93ea7..cc83f66ea4630 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -36,7 +36,7 @@ pub use sp_arithmetic::traits::{ CheckedShr, CheckedSub, IntegerSquareRoot, One, SaturatedConversion, Saturating, UniqueSaturatedFrom, UniqueSaturatedInto, Zero, }; -use sp_core::{self, Hasher, RuntimeDebug, TypeId}; +use sp_core::{self, storage::StateVersion, Hasher, RuntimeDebug, TypeId}; use sp_std::{ self, convert::{TryFrom, TryInto}, @@ -459,10 +459,10 @@ pub trait Hash: } /// The ordered Patricia tree root of the given `input`. - fn ordered_trie_root(input: Vec>) -> Self::Output; + fn ordered_trie_root(input: Vec>, state_version: StateVersion) -> Self::Output; /// The Patricia tree root of the given mapping. - fn trie_root(input: Vec<(Vec, Vec)>) -> Self::Output; + fn trie_root(input: Vec<(Vec, Vec)>, state_version: StateVersion) -> Self::Output; } /// Blake2-256 Hash implementation. @@ -483,12 +483,12 @@ impl Hasher for BlakeTwo256 { impl Hash for BlakeTwo256 { type Output = sp_core::H256; - fn trie_root(input: Vec<(Vec, Vec)>) -> Self::Output { - sp_io::trie::blake2_256_root(input) + fn trie_root(input: Vec<(Vec, Vec)>, version: StateVersion) -> Self::Output { + sp_io::trie::blake2_256_root(input, version) } - fn ordered_trie_root(input: Vec>) -> Self::Output { - sp_io::trie::blake2_256_ordered_root(input) + fn ordered_trie_root(input: Vec>, version: StateVersion) -> Self::Output { + sp_io::trie::blake2_256_ordered_root(input, version) } } @@ -510,12 +510,12 @@ impl Hasher for Keccak256 { impl Hash for Keccak256 { type Output = sp_core::H256; - fn trie_root(input: Vec<(Vec, Vec)>) -> Self::Output { - sp_io::trie::keccak_256_root(input) + fn trie_root(input: Vec<(Vec, Vec)>, version: StateVersion) -> Self::Output { + sp_io::trie::keccak_256_root(input, version) } - fn ordered_trie_root(input: Vec>) -> Self::Output { - sp_io::trie::keccak_256_ordered_root(input) + fn ordered_trie_root(input: Vec>, version: StateVersion) -> Self::Output { + sp_io::trie::keccak_256_ordered_root(input, version) } } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 2c84b9186d0ab..b9e5c1d4f3f0f 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -18,8 +18,8 @@ log = { version = "0.4.11", optional = true } thiserror = { version = "1.0.30", optional = true } parking_lot = { version = "0.11.2", optional = true } hash-db = { version = "0.15.2", default-features = false } -trie-db = { version = "0.22.6", default-features = false } -trie-root = { version = "0.16.0", default-features = false } +trie-db = { version = "0.23.0", default-features = false } +trie-root = { version = "0.17.0", default-features = false } sp-trie = { version = "4.0.0", path = "../trie", default-features = false } sp-core = { version = "4.1.0-dev", path = "../core", default-features = false } sp-panic-handler = { version = "4.0.0", path = "../panic-handler", optional = true } diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index eb6e2939b83fc..8a6ed4d3dba81 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -23,7 +23,7 @@ use crate::{ }; use codec::Encode; use hash_db::Hasher; -use sp_core::storage::{ChildInfo, TrackedStorageKey}; +use sp_core::storage::{ChildInfo, StateVersion, TrackedStorageKey}; #[cfg(feature = "std")] use sp_core::traits::RuntimeCode; use sp_std::vec::Vec; @@ -140,6 +140,7 @@ pub trait Backend: sp_std::fmt::Debug { fn storage_root<'a>( &self, delta: impl Iterator)>, + state_version: StateVersion, ) -> (H::Out, Self::Transaction) where H::Out: Ord; @@ -151,6 +152,7 @@ pub trait Backend: sp_std::fmt::Debug { &self, child_info: &ChildInfo, delta: impl Iterator)>, + state_version: StateVersion, ) -> (H::Out, bool, Self::Transaction) where H::Out: Ord; @@ -176,7 +178,6 @@ pub trait Backend: sp_std::fmt::Debug { fn as_trie_backend(&self) -> Option<&TrieBackend> { None } - /// Calculate the storage root, with given delta over what is already stored /// in the backend, and produce a "transaction" that can be used to commit. /// Does include child storage updates. @@ -186,6 +187,7 @@ pub trait Backend: sp_std::fmt::Debug { child_deltas: impl Iterator< Item = (&'a ChildInfo, impl Iterator)>), >, + state_version: StateVersion, ) -> (H::Out, Self::Transaction) where H::Out: Ord + Encode, @@ -194,7 +196,8 @@ pub trait Backend: sp_std::fmt::Debug { let mut child_roots: Vec<_> = Default::default(); // child first for (child_info, child_delta) in child_deltas { - let (child_root, empty, child_txs) = self.child_storage_root(&child_info, child_delta); + let (child_root, empty, child_txs) = + self.child_storage_root(&child_info, child_delta, state_version); let prefixed_storage_key = child_info.prefixed_storage_key(); txs.consolidate(child_txs); if empty { @@ -205,8 +208,9 @@ pub trait Backend: sp_std::fmt::Debug { } let (root, parent_txs) = self.storage_root( delta - .map(|(k, v)| (k, v.as_ref().map(|v| &v[..]))) + .map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..]))) .chain(child_roots.iter().map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..])))), + state_version, ); txs.consolidate(parent_txs); (root, txs) @@ -286,7 +290,11 @@ impl Consolidate for Vec<(Option, StorageCollection)> { } } -impl> Consolidate for sp_trie::GenericMemoryDB { +impl Consolidate for sp_trie::GenericMemoryDB +where + H: Hasher, + KF: sp_trie::KeyFunction, +{ fn consolidate(&mut self, other: Self) { sp_trie::GenericMemoryDB::consolidate(self, other) } diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index 3774adc5b0368..c0bec8d08f000 100644 --- a/primitives/state-machine/src/basic.rs +++ b/primitives/state-machine/src/basic.rs @@ -23,13 +23,14 @@ use hash_db::Hasher; use log::warn; use sp_core::{ storage::{ - well_known_keys::is_child_storage_key, ChildInfo, Storage, StorageChild, TrackedStorageKey, + well_known_keys::is_child_storage_key, ChildInfo, StateVersion, Storage, StorageChild, + TrackedStorageKey, }, traits::Externalities, Blake2Hasher, }; use sp_externalities::{Extension, Extensions}; -use sp_trie::{empty_child_trie_root, trie_types::Layout, TrieConfiguration}; +use sp_trie::{empty_child_trie_root, LayoutV0, LayoutV1, TrieConfiguration}; use std::{ any::{Any, TypeId}, collections::BTreeMap, @@ -273,7 +274,7 @@ impl Externalities for BasicExternalities { crate::ext::StorageAppend::new(current).append(value); } - fn storage_root(&mut self) -> Vec { + fn storage_root(&mut self, state_version: StateVersion) -> Vec { let mut top = self.inner.top.clone(); let prefixed_keys: Vec<_> = self .inner @@ -284,9 +285,9 @@ impl Externalities for BasicExternalities { // Single child trie implementation currently allows using the same child // empty root for all child trie. Using null storage key until multiple // type of child trie support. - let empty_hash = empty_child_trie_root::>(); + let empty_hash = empty_child_trie_root::>(); for (prefixed_storage_key, child_info) in prefixed_keys { - let child_root = self.child_storage_root(&child_info); + let child_root = self.child_storage_root(&child_info, state_version); if &empty_hash[..] == &child_root[..] { top.remove(prefixed_storage_key.as_slice()); } else { @@ -294,17 +295,26 @@ impl Externalities for BasicExternalities { } } - Layout::::trie_root(self.inner.top.clone()).as_ref().into() + match state_version { + StateVersion::V0 => + LayoutV0::::trie_root(self.inner.top.clone()).as_ref().into(), + StateVersion::V1 => + LayoutV1::::trie_root(self.inner.top.clone()).as_ref().into(), + } } - fn child_storage_root(&mut self, child_info: &ChildInfo) -> Vec { + fn child_storage_root( + &mut self, + child_info: &ChildInfo, + state_version: StateVersion, + ) -> Vec { if let Some(child) = self.inner.children_default.get(child_info.storage_key()) { let delta = child.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))); crate::in_memory_backend::new_in_mem::() - .child_storage_root(&child.child_info, delta) + .child_storage_root(&child.child_info, delta, state_version) .0 } else { - empty_child_trie_root::>() + empty_child_trie_root::>() } .encode() } @@ -389,7 +399,7 @@ mod tests { const ROOT: [u8; 32] = hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa"); - assert_eq!(&ext.storage_root()[..], &ROOT); + assert_eq!(&ext.storage_root(StateVersion::default())[..], &ROOT); } #[test] diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index 8f914ab3eee64..f5158acbc74d1 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -24,9 +24,11 @@ use codec::{Decode, Encode, EncodeAppend}; use hash_db::Hasher; #[cfg(feature = "std")] use sp_core::hexdisplay::HexDisplay; -use sp_core::storage::{well_known_keys::is_child_storage_key, ChildInfo, TrackedStorageKey}; +use sp_core::storage::{ + well_known_keys::is_child_storage_key, ChildInfo, StateVersion, TrackedStorageKey, +}; use sp_externalities::{Extension, ExtensionStore, Externalities}; -use sp_trie::{empty_child_trie_root, trie_types::Layout}; +use sp_trie::{empty_child_trie_root, LayoutV1}; use crate::{log_error, trace, warn, StorageTransactionCache}; use sp_std::{ @@ -505,7 +507,7 @@ where StorageAppend::new(current_value).append(value); } - fn storage_root(&mut self) -> Vec { + fn storage_root(&mut self, state_version: StateVersion) -> Vec { let _guard = guard(); if let Some(ref root) = self.storage_transaction_cache.transaction_storage_root { trace!( @@ -518,7 +520,9 @@ where return root.encode() } - let root = self.overlay.storage_root(self.backend, self.storage_transaction_cache); + let root = + self.overlay + .storage_root(self.backend, self.storage_transaction_cache, state_version); trace!( target: "state", method = "StorageRoot", @@ -529,7 +533,11 @@ where root.encode() } - fn child_storage_root(&mut self, child_info: &ChildInfo) -> Vec { + fn child_storage_root( + &mut self, + child_info: &ChildInfo, + state_version: StateVersion, + ) -> Vec { let _guard = guard(); let storage_key = child_info.storage_key(); let prefixed_storage_key = child_info.prefixed_storage_key(); @@ -537,7 +545,8 @@ where let root = self .storage(prefixed_storage_key.as_slice()) .and_then(|k| Decode::decode(&mut &k[..]).ok()) - .unwrap_or_else(|| empty_child_trie_root::>()); + // V1 is equivalent to V0 on empty root. + .unwrap_or_else(|| empty_child_trie_root::>()); trace!( target: "state", method = "ChildStorageRoot", @@ -550,7 +559,7 @@ where } else { let root = if let Some((changes, info)) = self.overlay.child_changes(storage_key) { let delta = changes.map(|(k, v)| (k.as_ref(), v.value().map(AsRef::as_ref))); - Some(self.backend.child_storage_root(info, delta)) + Some(self.backend.child_storage_root(info, delta, state_version)) } else { None }; @@ -583,7 +592,8 @@ where let root = self .storage(prefixed_storage_key.as_slice()) .and_then(|k| Decode::decode(&mut &k[..]).ok()) - .unwrap_or_else(|| empty_child_trie_root::>()); + // V1 is equivalent to V0 on empty root. + .unwrap_or_else(|| empty_child_trie_root::>()); trace!( target: "state", @@ -648,7 +658,12 @@ where self.overlay.rollback_transaction().expect(BENCHMARKING_FN); } self.overlay - .drain_storage_changes(self.backend, Default::default(), self.storage_transaction_cache) + .drain_storage_changes( + self.backend, + Default::default(), + self.storage_transaction_cache, + Default::default(), // using any state + ) .expect(EXT_NOT_ALLOWED_TO_FAIL); self.backend.wipe().expect(EXT_NOT_ALLOWED_TO_FAIL); self.mark_dirty(); @@ -658,12 +673,19 @@ where } fn commit(&mut self) { + // Bench always use latest state. + let state_version = StateVersion::default(); for _ in 0..self.overlay.transaction_depth() { self.overlay.commit_transaction().expect(BENCHMARKING_FN); } let changes = self .overlay - .drain_storage_changes(self.backend, Default::default(), self.storage_transaction_cache) + .drain_storage_changes( + self.backend, + Default::default(), + self.storage_transaction_cache, + state_version, + ) .expect(EXT_NOT_ALLOWED_TO_FAIL); self.backend .commit( @@ -878,15 +900,18 @@ mod tests { let mut overlay = OverlayedChanges::default(); overlay.set_storage(vec![20], None); overlay.set_storage(vec![30], Some(vec![31])); - let backend = Storage { - top: map![ - vec![10] => vec![10], - vec![20] => vec![20], - vec![40] => vec![40] - ], - children_default: map![], - } - .into(); + let backend = ( + Storage { + top: map![ + vec![10] => vec![10], + vec![20] => vec![20], + vec![40] => vec![40] + ], + children_default: map![], + }, + StateVersion::default(), + ) + .into(); let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); @@ -924,13 +949,16 @@ mod tests { overlay.set_storage(vec![27], None); overlay.set_storage(vec![28], None); overlay.set_storage(vec![29], None); - let backend = Storage { - top: map![ - vec![30] => vec![30] - ], - children_default: map![], - } - .into(); + let backend = ( + Storage { + top: map![ + vec![30] => vec![30] + ], + children_default: map![], + }, + StateVersion::default(), + ) + .into(); let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); @@ -948,20 +976,23 @@ mod tests { let mut overlay = OverlayedChanges::default(); overlay.set_child_storage(child_info, vec![20], None); overlay.set_child_storage(child_info, vec![30], Some(vec![31])); - let backend = Storage { - top: map![], - children_default: map![ - child_info.storage_key().to_vec() => StorageChild { - data: map![ - vec![10] => vec![10], - vec![20] => vec![20], - vec![40] => vec![40] - ], - child_info: child_info.to_owned(), - } - ], - } - .into(); + let backend = ( + Storage { + top: map![], + children_default: map![ + child_info.storage_key().to_vec() => StorageChild { + data: map![ + vec![10] => vec![10], + vec![20] => vec![20], + vec![40] => vec![40] + ], + child_info: child_info.to_owned(), + } + ], + }, + StateVersion::default(), + ) + .into(); let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); @@ -993,20 +1024,23 @@ mod tests { let mut overlay = OverlayedChanges::default(); overlay.set_child_storage(child_info, vec![20], None); overlay.set_child_storage(child_info, vec![30], Some(vec![31])); - let backend = Storage { - top: map![], - children_default: map![ - child_info.storage_key().to_vec() => StorageChild { - data: map![ - vec![10] => vec![10], - vec![20] => vec![20], - vec![30] => vec![40] - ], - child_info: child_info.to_owned(), - } - ], - } - .into(); + let backend = ( + Storage { + top: map![], + children_default: map![ + child_info.storage_key().to_vec() => StorageChild { + data: map![ + vec![10] => vec![10], + vec![20] => vec![20], + vec![30] => vec![40] + ], + child_info: child_info.to_owned(), + } + ], + }, + StateVersion::default(), + ) + .into(); let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); @@ -1032,18 +1066,21 @@ mod tests { let child_info = &child_info; let mut cache = StorageTransactionCache::default(); let mut overlay = OverlayedChanges::default(); - let backend = Storage { - top: map![], - children_default: map![ - child_info.storage_key().to_vec() => StorageChild { - data: map![ - vec![30] => vec![40] - ], - child_info: child_info.to_owned(), - } - ], - } - .into(); + let backend = ( + Storage { + top: map![], + children_default: map![ + child_info.storage_key().to_vec() => StorageChild { + data: map![ + vec![30] => vec![40] + ], + child_info: child_info.to_owned(), + } + ], + }, + StateVersion::default(), + ) + .into(); let ext = TestExt::new(&mut overlay, &mut cache, &backend, None); diff --git a/primitives/state-machine/src/in_memory_backend.rs b/primitives/state-machine/src/in_memory_backend.rs index f9f94c0c50d60..f4ae0d01d5fb9 100644 --- a/primitives/state-machine/src/in_memory_backend.rs +++ b/primitives/state-machine/src/in_memory_backend.rs @@ -22,8 +22,8 @@ use crate::{ }; use codec::Codec; use hash_db::Hasher; -use sp_core::storage::{ChildInfo, Storage}; -use sp_trie::{empty_trie_root, Layout, MemoryDB}; +use sp_core::storage::{ChildInfo, StateVersion, Storage}; +use sp_trie::{empty_trie_root, LayoutV1, MemoryDB}; use std::collections::{BTreeMap, HashMap}; /// Create a new empty instance of in-memory backend. @@ -32,7 +32,8 @@ where H::Out: Codec + Ord, { let db = MemoryDB::default(); - TrieBackend::new(db, empty_trie_root::>()) + // V1 is same as V0 for an empty trie. + TrieBackend::new(db, empty_trie_root::>()) } impl TrieBackend, H> @@ -43,9 +44,10 @@ where pub fn update, StorageCollection)>>( &self, changes: T, + state_version: StateVersion, ) -> Self { let mut clone = self.clone(); - clone.insert(changes); + clone.insert(changes, state_version); clone } @@ -53,6 +55,7 @@ where pub fn insert, StorageCollection)>>( &mut self, changes: T, + state_version: StateVersion, ) { let (top, child) = changes.into_iter().partition::, _>(|v| v.0.is_none()); let (root, transaction) = self.full_storage_root( @@ -60,6 +63,7 @@ where child.iter().filter_map(|v| { v.0.as_ref().map(|c| (c, v.1.iter().map(|(k, v)| (&k[..], v.as_deref())))) }), + state_version, ); self.apply_transaction(root, transaction); @@ -103,53 +107,63 @@ where } } -impl From, BTreeMap>> +impl From<(HashMap, BTreeMap>, StateVersion)> for TrieBackend, H> where H::Out: Codec + Ord, { - fn from(inner: HashMap, BTreeMap>) -> Self { + fn from( + (inner, state_version): ( + HashMap, BTreeMap>, + StateVersion, + ), + ) -> Self { let mut backend = new_in_mem(); backend.insert( inner .into_iter() .map(|(k, m)| (k, m.into_iter().map(|(k, v)| (k, Some(v))).collect())), + state_version, ); backend } } -impl From for TrieBackend, H> +impl From<(Storage, StateVersion)> for TrieBackend, H> where H::Out: Codec + Ord, { - fn from(inners: Storage) -> Self { + fn from((inners, state_version): (Storage, StateVersion)) -> Self { let mut inner: HashMap, BTreeMap> = inners .children_default .into_iter() .map(|(_k, c)| (Some(c.child_info), c.data)) .collect(); inner.insert(None, inners.top); - inner.into() + (inner, state_version).into() } } -impl From> for TrieBackend, H> +impl From<(BTreeMap, StateVersion)> + for TrieBackend, H> where H::Out: Codec + Ord, { - fn from(inner: BTreeMap) -> Self { + fn from((inner, state_version): (BTreeMap, StateVersion)) -> Self { let mut expanded = HashMap::new(); expanded.insert(None, inner); - expanded.into() + (expanded, state_version).into() } } -impl From, StorageCollection)>> for TrieBackend, H> +impl From<(Vec<(Option, StorageCollection)>, StateVersion)> + for TrieBackend, H> where H::Out: Codec + Ord, { - fn from(inner: Vec<(Option, StorageCollection)>) -> Self { + fn from( + (inner, state_version): (Vec<(Option, StorageCollection)>, StateVersion), + ) -> Self { let mut expanded: HashMap, BTreeMap> = HashMap::new(); for (child_info, key_values) in inner { @@ -160,7 +174,7 @@ where } } } - expanded.into() + (expanded, state_version).into() } } @@ -168,16 +182,20 @@ where mod tests { use super::*; use crate::backend::Backend; + use sp_core::storage::StateVersion; use sp_runtime::traits::BlakeTwo256; /// Assert in memory backend with only child trie keys works as trie backend. #[test] fn in_memory_with_child_trie_only() { + let state_version = StateVersion::default(); let storage = new_in_mem::(); let child_info = ChildInfo::new_default(b"1"); let child_info = &child_info; - let storage = storage - .update(vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])]); + let storage = storage.update( + vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])], + state_version, + ); let trie_backend = storage.as_trie_backend().unwrap(); assert_eq!(trie_backend.child_storage(child_info, b"2").unwrap(), Some(b"3".to_vec())); let storage_key = child_info.prefixed_storage_key(); @@ -186,13 +204,18 @@ mod tests { #[test] fn insert_multiple_times_child_data_works() { + let state_version = StateVersion::default(); let mut storage = new_in_mem::(); let child_info = ChildInfo::new_default(b"1"); - storage - .insert(vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])]); - storage - .insert(vec![(Some(child_info.clone()), vec![(b"1".to_vec(), Some(b"3".to_vec()))])]); + storage.insert( + vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])], + state_version, + ); + storage.insert( + vec![(Some(child_info.clone()), vec![(b"1".to_vec(), Some(b"3".to_vec()))])], + state_version, + ); assert_eq!(storage.child_storage(&child_info, &b"2"[..]), Ok(Some(b"3".to_vec()))); assert_eq!(storage.child_storage(&child_info, &b"1"[..]), Ok(Some(b"3".to_vec()))); diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index e5c19f3bb0d57..dff4999816342 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -126,6 +126,7 @@ impl sp_std::fmt::Display for DefaultError { pub use crate::{ backend::Backend, + error::{Error, ExecutionError}, ext::Ext, overlayed_changes::{ ChildStorageCollection, IndexOperation, OffchainChangesCollection, @@ -136,7 +137,6 @@ pub use crate::{ trie_backend::TrieBackend, trie_backend_essence::{Storage, TrieBackendStorage}, }; -pub use error::{Error, ExecutionError}; #[cfg(feature = "std")] mod std_reexport { @@ -151,8 +151,8 @@ mod std_reexport { testing::TestExternalities, }; pub use sp_trie::{ - trie_types::{Layout, TrieDBMut}, - CompactProof, DBValue, MemoryDB, StorageProof, TrieMut, + trie_types::{TrieDBMutV0, TrieDBMutV1}, + CompactProof, DBValue, LayoutV0, LayoutV1, MemoryDB, StorageProof, TrieMut, }; } @@ -1353,7 +1353,7 @@ mod tests { use codec::{Decode, Encode}; use sp_core::{ map, - storage::ChildInfo, + storage::{ChildInfo, StateVersion}, testing::TaskExecutor, traits::{CodeExecutor, Externalities, RuntimeCode}, NativeOrEncoded, NeverNativeValue, @@ -1416,7 +1416,11 @@ mod tests { #[test] fn execute_works() { - let backend = trie_backend::tests::test_trie(); + execute_works_inner(StateVersion::V0); + execute_works_inner(StateVersion::V1); + } + fn execute_works_inner(state_version: StateVersion) { + let backend = trie_backend::tests::test_trie(state_version); let mut overlayed_changes = Default::default(); let wasm_code = RuntimeCode::empty(); @@ -1440,7 +1444,11 @@ mod tests { #[test] fn execute_works_with_native_else_wasm() { - let backend = trie_backend::tests::test_trie(); + execute_works_with_native_else_wasm_inner(StateVersion::V0); + execute_works_with_native_else_wasm_inner(StateVersion::V1); + } + fn execute_works_with_native_else_wasm_inner(state_version: StateVersion) { + let backend = trie_backend::tests::test_trie(state_version); let mut overlayed_changes = Default::default(); let wasm_code = RuntimeCode::empty(); @@ -1464,8 +1472,12 @@ mod tests { #[test] fn dual_execution_strategy_detects_consensus_failure() { + dual_execution_strategy_detects_consensus_failure_inner(StateVersion::V0); + dual_execution_strategy_detects_consensus_failure_inner(StateVersion::V1); + } + fn dual_execution_strategy_detects_consensus_failure_inner(state_version: StateVersion) { let mut consensus_failed = false; - let backend = trie_backend::tests::test_trie(); + let backend = trie_backend::tests::test_trie(state_version); let mut overlayed_changes = Default::default(); let wasm_code = RuntimeCode::empty(); @@ -1498,6 +1510,10 @@ mod tests { #[test] fn prove_execution_and_proof_check_works() { + prove_execution_and_proof_check_works_inner(StateVersion::V0); + prove_execution_and_proof_check_works_inner(StateVersion::V1); + } + fn prove_execution_and_proof_check_works_inner(state_version: StateVersion) { let executor = DummyCodeExecutor { native_available: true, native_succeeds: true, @@ -1505,8 +1521,8 @@ mod tests { }; // fetch execution proof from 'remote' full node - let mut remote_backend = trie_backend::tests::test_trie(); - let remote_root = remote_backend.storage_root(std::iter::empty()).0; + let mut remote_backend = trie_backend::tests::test_trie(state_version); + let remote_root = remote_backend.storage_root(std::iter::empty(), state_version).0; let (remote_result, remote_proof) = prove_execution( &mut remote_backend, &mut Default::default(), @@ -1544,7 +1560,7 @@ mod tests { b"abc".to_vec() => b"2".to_vec(), b"bbb".to_vec() => b"3".to_vec() ]; - let state = InMemoryBackend::::from(initial); + let state = InMemoryBackend::::from((initial, StateVersion::default())); let backend = state.as_trie_backend().unwrap(); let mut overlay = OverlayedChanges::default(); @@ -1613,7 +1629,7 @@ mod tests { b"d".to_vec() => b"3".to_vec() ], ]; - let backend = InMemoryBackend::::from(initial); + let backend = InMemoryBackend::::from((initial, StateVersion::default())); let mut overlay = OverlayedChanges::default(); overlay.set_child_storage(&child_info, b"1".to_vec(), Some(b"1312".to_vec())); @@ -1655,7 +1671,7 @@ mod tests { b"d".to_vec() => b"3".to_vec() ], ]; - let backend = InMemoryBackend::::from(initial); + let backend = InMemoryBackend::::from((initial, StateVersion::default())); let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); @@ -1789,13 +1805,17 @@ mod tests { #[test] fn prove_read_and_proof_check_works() { + prove_read_and_proof_check_works_inner(StateVersion::V0); + prove_read_and_proof_check_works_inner(StateVersion::V1); + } + fn prove_read_and_proof_check_works_inner(state_version: StateVersion) { let child_info = ChildInfo::new_default(b"sub1"); let missing_child_info = ChildInfo::new_default(b"sub1sub2"); // key will include other child root to proof. let child_info = &child_info; let missing_child_info = &missing_child_info; // fetch read proof from 'remote' full node - let remote_backend = trie_backend::tests::test_trie(); - let remote_root = remote_backend.storage_root(std::iter::empty()).0; + let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_root = remote_backend.storage_root(std::iter::empty(), state_version).0; let remote_proof = prove_read(remote_backend, &[b"value2"]).unwrap(); let remote_proof = test_compact(remote_proof, &remote_root); // check proof locally @@ -1812,8 +1832,8 @@ mod tests { ); assert_eq!(local_result2, false); // on child trie - let remote_backend = trie_backend::tests::test_trie(); - let remote_root = remote_backend.storage_root(std::iter::empty()).0; + let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_root = remote_backend.storage_root(std::iter::empty(), state_version).0; let remote_proof = prove_child_read(remote_backend, child_info, &[b"value3"]).unwrap(); let remote_proof = test_compact(remote_proof, &remote_root); let local_result1 = read_child_proof_check::( @@ -1877,7 +1897,8 @@ mod tests { storage.insert(Some(child_info), items); } - let trie: InMemoryBackend = storage.clone().into(); + let trie: InMemoryBackend = + (storage.clone(), StateVersion::default()).into(); let trie_root = trie.root().clone(); let backend = crate::ProvingBackend::new(&trie); let mut queries = Vec::new(); @@ -1940,15 +1961,16 @@ mod tests { #[test] fn prove_read_with_size_limit_works() { - let remote_backend = trie_backend::tests::test_trie(); - let remote_root = remote_backend.storage_root(::std::iter::empty()).0; + let state_version = StateVersion::V0; + let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_root = remote_backend.storage_root(::std::iter::empty(), state_version).0; let (proof, count) = prove_range_read_with_size(remote_backend, None, None, 0, None).unwrap(); // Always contains at least some nodes. assert_eq!(proof.into_memory_db::().drain().len(), 3); assert_eq!(count, 1); - let remote_backend = trie_backend::tests::test_trie(); + let remote_backend = trie_backend::tests::test_trie(state_version); let (proof, count) = prove_range_read_with_size(remote_backend, None, None, 800, Some(&[])).unwrap(); assert_eq!(proof.clone().into_memory_db::().drain().len(), 9); @@ -1971,7 +1993,7 @@ mod tests { assert_eq!(results.len() as u32, 101); assert_eq!(completed, false); - let remote_backend = trie_backend::tests::test_trie(); + let remote_backend = trie_backend::tests::test_trie(state_version); let (proof, count) = prove_range_read_with_size(remote_backend, None, None, 50000, Some(&[])).unwrap(); assert_eq!(proof.clone().into_memory_db::().drain().len(), 11); @@ -1989,10 +2011,66 @@ mod tests { assert_eq!(completed, true); } + #[test] + fn inner_state_versioning_switch_proofs() { + let mut state_version = StateVersion::V0; + let (mut mdb, mut root) = trie_backend::tests::test_db(state_version); + { + let mut trie = TrieDBMutV0::from_existing(&mut mdb, &mut root).unwrap(); + trie.insert(b"foo", vec![1u8; 1_000].as_slice()) // big inner hash + .expect("insert failed"); + trie.insert(b"foo2", vec![3u8; 16].as_slice()) // no inner hash + .expect("insert failed"); + trie.insert(b"foo222", vec![5u8; 100].as_slice()) // inner hash + .expect("insert failed"); + } + + let check_proof = |mdb, root, state_version| -> StorageProof { + let remote_backend = TrieBackend::new(mdb, root); + let remote_root = remote_backend.storage_root(std::iter::empty(), state_version).0; + let remote_proof = prove_read(remote_backend, &[b"foo222"]).unwrap(); + // check proof locally + let local_result1 = + read_proof_check::(remote_root, remote_proof.clone(), &[b"foo222"]) + .unwrap(); + // check that results are correct + assert_eq!( + local_result1.into_iter().collect::>(), + vec![(b"foo222".to_vec(), Some(vec![5u8; 100]))], + ); + remote_proof + }; + + let remote_proof = check_proof(mdb.clone(), root.clone(), state_version); + // check full values in proof + assert!(remote_proof.encode().len() > 1_100); + assert!(remote_proof.encoded_size() > 1_100); + let root1 = root.clone(); + + // do switch + state_version = StateVersion::V1; + { + let mut trie = TrieDBMutV1::from_existing(&mut mdb, &mut root).unwrap(); + trie.insert(b"foo222", vec![5u8; 100].as_slice()) // inner hash + .expect("insert failed"); + // update with same value do change + trie.insert(b"foo", vec![1u8; 1000].as_slice()) // inner hash + .expect("insert failed"); + } + let root3 = root.clone(); + assert!(root1 != root3); + let remote_proof = check_proof(mdb.clone(), root.clone(), state_version); + // nodes foo is replaced by its hashed value form. + assert!(remote_proof.encode().len() < 1000); + assert!(remote_proof.encoded_size() < 1000); + assert_eq!(remote_proof.encode().len(), remote_proof.encoded_size()); + } + #[test] fn prove_range_with_child_works() { - let remote_backend = trie_backend::tests::test_trie(); - let remote_root = remote_backend.storage_root(::std::iter::empty()).0; + let state_version = StateVersion::V0; + let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_root = remote_backend.storage_root(std::iter::empty(), state_version).0; let mut start_at = smallvec::SmallVec::<[Vec; 2]>::new(); let trie_backend = remote_backend.as_trie_backend().unwrap(); let max_iter = 1000; @@ -2030,20 +2108,34 @@ mod tests { #[test] fn compact_multiple_child_trie() { + let size_no_inner_hash = compact_multiple_child_trie_inner(StateVersion::V0); + let size_inner_hash = compact_multiple_child_trie_inner(StateVersion::V1); + assert!(size_inner_hash < size_no_inner_hash); + } + fn compact_multiple_child_trie_inner(state_version: StateVersion) -> usize { // this root will be queried let child_info1 = ChildInfo::new_default(b"sub1"); // this root will not be include in proof let child_info2 = ChildInfo::new_default(b"sub2"); // this root will be include in proof let child_info3 = ChildInfo::new_default(b"sub"); - let remote_backend = trie_backend::tests::test_trie(); + let remote_backend = trie_backend::tests::test_trie(state_version); + let long_vec: Vec = (0..1024usize).map(|_| 8u8).collect(); let (remote_root, transaction) = remote_backend.full_storage_root( std::iter::empty(), vec![ ( &child_info1, - vec![(&b"key1"[..], Some(&b"val2"[..])), (&b"key2"[..], Some(&b"val3"[..]))] - .into_iter(), + vec![ + // a inner hashable node + (&b"k"[..], Some(&long_vec[..])), + // need to ensure this is not an inline node + // otherwhise we do not know what is accessed when + // storing proof. + (&b"key1"[..], Some(&vec![5u8; 32][..])), + (&b"key2"[..], Some(&b"val3"[..])), + ] + .into_iter(), ), ( &child_info2, @@ -2057,11 +2149,13 @@ mod tests { ), ] .into_iter(), + state_version, ); let mut remote_storage = remote_backend.into_storage(); remote_storage.consolidate(transaction); let remote_backend = TrieBackend::new(remote_storage, remote_root); let remote_proof = prove_child_read(remote_backend, &child_info1, &[b"key1"]).unwrap(); + let size = remote_proof.encoded_size(); let remote_proof = test_compact(remote_proof, &remote_root); let local_result1 = read_child_proof_check::( remote_root, @@ -2071,11 +2165,13 @@ mod tests { ) .unwrap(); assert_eq!(local_result1.len(), 1); - assert_eq!(local_result1.get(&b"key1"[..]), Some(&Some(b"val2".to_vec()))); + assert_eq!(local_result1.get(&b"key1"[..]), Some(&Some(vec![5u8; 32]))); + size } #[test] fn child_storage_uuid() { + let state_version = StateVersion::V0; let child_info_1 = ChildInfo::new_default(b"sub_test1"); let child_info_2 = ChildInfo::new_default(b"sub_test2"); @@ -2083,12 +2179,12 @@ mod tests { let mut overlay = OverlayedChanges::default(); let mut transaction = { - let backend = test_trie(); + let backend = test_trie(state_version); let mut cache = StorageTransactionCache::default(); let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); ext.set_child_storage(&child_info_1, b"abc".to_vec(), b"def".to_vec()); ext.set_child_storage(&child_info_2, b"abc".to_vec(), b"def".to_vec()); - ext.storage_root(); + ext.storage_root(state_version); cache.transaction.unwrap() }; let mut duplicate = false; @@ -2108,7 +2204,7 @@ mod tests { b"aaa".to_vec() => b"0".to_vec(), b"bbb".to_vec() => b"".to_vec() ]; - let state = InMemoryBackend::::from(initial); + let state = InMemoryBackend::::from((initial, StateVersion::default())); let backend = state.as_trie_backend().unwrap(); let mut overlay = OverlayedChanges::default(); @@ -2134,12 +2230,13 @@ mod tests { #[test] fn runtime_registered_extensions_are_removed_after_execution() { + let state_version = StateVersion::default(); use sp_externalities::ExternalitiesExt; sp_externalities::decl_extension! { struct DummyExt(u32); } - let backend = trie_backend::tests::test_trie(); + let backend = trie_backend::tests::test_trie(state_version); let mut overlayed_changes = Default::default(); let wasm_code = RuntimeCode::empty(); diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index b7a535792aae6..659b52e0a708f 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -27,7 +27,7 @@ use hash_db::Hasher; pub use offchain::OffchainOverlayedChanges; use sp_core::{ offchain::OffchainOverlayedChange, - storage::{well_known_keys::EXTRINSIC_INDEX, ChildInfo}, + storage::{well_known_keys::EXTRINSIC_INDEX, ChildInfo, StateVersion}, }; #[cfg(feature = "std")] use sp_externalities::{Extension, Extensions}; @@ -502,11 +502,12 @@ impl OverlayedChanges { backend: &B, parent_hash: H::Out, mut cache: StorageTransactionCache, + state_version: StateVersion, ) -> Result, DefaultError> where H::Out: Ord + Encode + 'static, { - self.drain_storage_changes(backend, parent_hash, &mut cache) + self.drain_storage_changes(backend, parent_hash, &mut cache, state_version) } /// Drain all changes into a [`StorageChanges`] instance. Leave empty overlay in place. @@ -515,13 +516,14 @@ impl OverlayedChanges { backend: &B, _parent_hash: H::Out, mut cache: &mut StorageTransactionCache, + state_version: StateVersion, ) -> Result, DefaultError> where H::Out: Ord + Encode + 'static, { // If the transaction does not exist, we generate it. if cache.transaction.is_none() { - self.storage_root(backend, &mut cache); + self.storage_root(backend, &mut cache, state_version); } let (transaction, transaction_storage_root) = cache @@ -580,6 +582,7 @@ impl OverlayedChanges { &self, backend: &B, cache: &mut StorageTransactionCache, + state_version: StateVersion, ) -> H::Out where H::Out: Ord + Encode, @@ -589,7 +592,7 @@ impl OverlayedChanges { (info, changes.map(|(k, v)| (&k[..], v.value().map(|v| &v[..])))) }); - let (root, transaction) = backend.full_storage_root(delta, child_delta); + let (root, transaction) = backend.full_storage_root(delta, child_delta, state_version); cache.transaction = Some(transaction); cache.transaction_storage_root = Some(root); @@ -830,6 +833,7 @@ mod tests { #[test] fn overlayed_storage_root_works() { + let state_version = StateVersion::default(); let initial: BTreeMap<_, _> = vec![ (b"doe".to_vec(), b"reindeer".to_vec()), (b"dog".to_vec(), b"puppyXXX".to_vec()), @@ -838,7 +842,7 @@ mod tests { ] .into_iter() .collect(); - let backend = InMemoryBackend::::from(initial); + let backend = InMemoryBackend::::from((initial, state_version)); let mut overlay = OverlayedChanges::default(); overlay.start_transaction(); @@ -856,7 +860,7 @@ mod tests { const ROOT: [u8; 32] = hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa"); - assert_eq!(&ext.storage_root()[..], &ROOT); + assert_eq!(&ext.storage_root(state_version)[..], &ROOT); } #[test] diff --git a/primitives/state-machine/src/proving_backend.rs b/primitives/state-machine/src/proving_backend.rs index a354adaf697d6..4e1fd64da2b8e 100644 --- a/primitives/state-machine/src/proving_backend.rs +++ b/primitives/state-machine/src/proving_backend.rs @@ -26,14 +26,11 @@ use codec::{Codec, Decode, Encode}; use hash_db::{HashDB, Hasher, Prefix, EMPTY_PREFIX}; use log::debug; use parking_lot::RwLock; -use sp_core::storage::ChildInfo; +use sp_core::storage::{ChildInfo, StateVersion}; +pub use sp_trie::trie_types::TrieError; use sp_trie::{ empty_child_trie_root, read_child_trie_value_with, read_trie_value_with, record_all_keys, - MemoryDB, StorageProof, -}; -pub use sp_trie::{ - trie_types::{Layout, TrieError}, - Recorder, + LayoutV1, MemoryDB, Recorder, StorageProof, }; use std::{ collections::{hash_map::Entry, HashMap}, @@ -59,7 +56,8 @@ where let map_e = |e| format!("Trie lookup error: {}", e); - read_trie_value_with::, _, Ephemeral>( + // V1 is equivalent to V0 on read. + read_trie_value_with::, _, Ephemeral>( &eph, self.backend.root(), key, @@ -78,14 +76,16 @@ where let root = self .storage(storage_key)? .and_then(|r| Decode::decode(&mut &r[..]).ok()) - .unwrap_or_else(|| empty_child_trie_root::>()); + // V1 is equivalent to V0 on empty trie + .unwrap_or_else(|| empty_child_trie_root::>()); let mut read_overlay = S::Overlay::default(); let eph = Ephemeral::new(self.backend.backend_storage(), &mut read_overlay); let map_e = |e| format!("Trie lookup error: {}", e); - read_child_trie_value_with::, _, _>( + // V1 is equivalent to V0 on read + read_child_trie_value_with::, _, _>( child_info.keyspace(), &eph, &root.as_ref(), @@ -102,7 +102,8 @@ where let mut iter = move || -> Result<(), Box>> { let root = self.backend.root(); - record_all_keys::, _>(&eph, root, &mut *self.proof_recorder) + // V1 and V is equivalent to V0 on read and recorder is key read. + record_all_keys::, _>(&eph, root, &mut *self.proof_recorder) }; if let Err(e) = iter() { @@ -338,22 +339,24 @@ where fn storage_root<'b>( &self, delta: impl Iterator)>, + state_version: StateVersion, ) -> (H::Out, Self::Transaction) where H::Out: Ord, { - self.0.storage_root(delta) + self.0.storage_root(delta, state_version) } fn child_storage_root<'b>( &self, child_info: &ChildInfo, delta: impl Iterator)>, + state_version: StateVersion, ) -> (H::Out, bool, Self::Transaction) where H::Out: Ord, { - self.0.child_storage_root(child_info, delta) + self.0.child_storage_root(child_info, delta, state_version) } fn register_overlay_stats(&self, _stats: &crate::stats::StateMachineStats) {} @@ -401,13 +404,21 @@ mod tests { #[test] fn proof_is_empty_until_value_is_read() { - let trie_backend = test_trie(); + proof_is_empty_until_value_is_read_inner(StateVersion::V0); + proof_is_empty_until_value_is_read_inner(StateVersion::V1); + } + fn proof_is_empty_until_value_is_read_inner(test_hash: StateVersion) { + let trie_backend = test_trie(test_hash); assert!(test_proving(&trie_backend).extract_proof().is_empty()); } #[test] fn proof_is_non_empty_after_value_is_read() { - let trie_backend = test_trie(); + proof_is_non_empty_after_value_is_read_inner(StateVersion::V0); + proof_is_non_empty_after_value_is_read_inner(StateVersion::V1); + } + fn proof_is_non_empty_after_value_is_read_inner(test_hash: StateVersion) { + let trie_backend = test_trie(test_hash); let backend = test_proving(&trie_backend); assert_eq!(backend.storage(b"key").unwrap(), Some(b"value".to_vec())); assert!(!backend.extract_proof().is_empty()); @@ -425,58 +436,82 @@ mod tests { #[test] fn passes_through_backend_calls() { - let trie_backend = test_trie(); + passes_through_backend_calls_inner(StateVersion::V0); + passes_through_backend_calls_inner(StateVersion::V1); + } + fn passes_through_backend_calls_inner(state_version: StateVersion) { + let trie_backend = test_trie(state_version); let proving_backend = test_proving(&trie_backend); assert_eq!(trie_backend.storage(b"key").unwrap(), proving_backend.storage(b"key").unwrap()); assert_eq!(trie_backend.pairs(), proving_backend.pairs()); - let (trie_root, mut trie_mdb) = trie_backend.storage_root(std::iter::empty()); - let (proving_root, mut proving_mdb) = proving_backend.storage_root(std::iter::empty()); + let (trie_root, mut trie_mdb) = + trie_backend.storage_root(std::iter::empty(), state_version); + let (proving_root, mut proving_mdb) = + proving_backend.storage_root(std::iter::empty(), state_version); assert_eq!(trie_root, proving_root); assert_eq!(trie_mdb.drain(), proving_mdb.drain()); } #[test] - fn proof_recorded_and_checked() { - let contents = (0..64).map(|i| (vec![i], Some(vec![i]))).collect::>(); + fn proof_recorded_and_checked_top() { + proof_recorded_and_checked_inner(StateVersion::V0); + proof_recorded_and_checked_inner(StateVersion::V1); + } + fn proof_recorded_and_checked_inner(state_version: StateVersion) { + let size_content = 34; // above hashable value treshold. + let value_range = 0..64; + let contents = value_range + .clone() + .map(|i| (vec![i], Some(vec![i; size_content]))) + .collect::>(); let in_memory = InMemoryBackend::::default(); - let in_memory = in_memory.update(vec![(None, contents)]); - let in_memory_root = in_memory.storage_root(::std::iter::empty()).0; - (0..64).for_each(|i| assert_eq!(in_memory.storage(&[i]).unwrap().unwrap(), vec![i])); + let in_memory = in_memory.update(vec![(None, contents)], state_version); + let in_memory_root = in_memory.storage_root(std::iter::empty(), state_version).0; + value_range.clone().for_each(|i| { + assert_eq!(in_memory.storage(&[i]).unwrap().unwrap(), vec![i; size_content]) + }); let trie = in_memory.as_trie_backend().unwrap(); - let trie_root = trie.storage_root(::std::iter::empty()).0; + let trie_root = trie.storage_root(std::iter::empty(), state_version).0; assert_eq!(in_memory_root, trie_root); - (0..64).for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i])); + value_range + .clone() + .for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i; size_content])); let proving = ProvingBackend::new(trie); - assert_eq!(proving.storage(&[42]).unwrap().unwrap(), vec![42]); + assert_eq!(proving.storage(&[42]).unwrap().unwrap(), vec![42; size_content]); let proof = proving.extract_proof(); let proof_check = create_proof_check_backend::(in_memory_root.into(), proof).unwrap(); - assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42]); + assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42; size_content]); } #[test] fn proof_recorded_and_checked_with_child() { + proof_recorded_and_checked_with_child_inner(StateVersion::V0); + proof_recorded_and_checked_with_child_inner(StateVersion::V1); + } + fn proof_recorded_and_checked_with_child_inner(state_version: StateVersion) { let child_info_1 = ChildInfo::new_default(b"sub1"); let child_info_2 = ChildInfo::new_default(b"sub2"); let child_info_1 = &child_info_1; let child_info_2 = &child_info_2; let contents = vec![ - (None, (0..64).map(|i| (vec![i], Some(vec![i]))).collect()), + (None, (0..64).map(|i| (vec![i], Some(vec![i]))).collect::>()), (Some(child_info_1.clone()), (28..65).map(|i| (vec![i], Some(vec![i]))).collect()), (Some(child_info_2.clone()), (10..15).map(|i| (vec![i], Some(vec![i]))).collect()), ]; let in_memory = InMemoryBackend::::default(); - let in_memory = in_memory.update(contents); + let in_memory = in_memory.update(contents, state_version); let child_storage_keys = vec![child_info_1.to_owned(), child_info_2.to_owned()]; let in_memory_root = in_memory .full_storage_root( std::iter::empty(), child_storage_keys.iter().map(|k| (k, std::iter::empty())), + state_version, ) .0; (0..64).for_each(|i| assert_eq!(in_memory.storage(&[i]).unwrap().unwrap(), vec![i])); @@ -488,7 +523,7 @@ mod tests { }); let trie = in_memory.as_trie_backend().unwrap(); - let trie_root = trie.storage_root(std::iter::empty()).0; + let trie_root = trie.storage_root(std::iter::empty(), state_version).0; assert_eq!(in_memory_root, trie_root); (0..64).for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i])); @@ -516,7 +551,11 @@ mod tests { #[test] fn storage_proof_encoded_size_estimation_works() { - let trie_backend = test_trie(); + storage_proof_encoded_size_estimation_works_inner(StateVersion::V0); + storage_proof_encoded_size_estimation_works_inner(StateVersion::V1); + } + fn storage_proof_encoded_size_estimation_works_inner(state_version: StateVersion) { + let trie_backend = test_trie(state_version); let backend = test_proving(&trie_backend); let check_estimation = diff --git a/primitives/state-machine/src/read_only.rs b/primitives/state-machine/src/read_only.rs index b3e43d4c46e7f..2039b39a06038 100644 --- a/primitives/state-machine/src/read_only.rs +++ b/primitives/state-machine/src/read_only.rs @@ -21,7 +21,7 @@ use crate::{Backend, StorageKey, StorageValue}; use codec::Encode; use hash_db::Hasher; use sp_core::{ - storage::{ChildInfo, TrackedStorageKey}, + storage::{ChildInfo, StateVersion, TrackedStorageKey}, traits::Externalities, Blake2Hasher, }; @@ -145,11 +145,15 @@ impl<'a, H: Hasher, B: 'a + Backend> Externalities for ReadOnlyExternalities< unimplemented!("storage_append is not supported in ReadOnlyExternalities") } - fn storage_root(&mut self) -> Vec { + fn storage_root(&mut self, _state_version: StateVersion) -> Vec { unimplemented!("storage_root is not supported in ReadOnlyExternalities") } - fn child_storage_root(&mut self, _child_info: &ChildInfo) -> Vec { + fn child_storage_root( + &mut self, + _child_info: &ChildInfo, + _state_version: StateVersion, + ) -> Vec { unimplemented!("child_storage_root is not supported in ReadOnlyExternalities") } diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index 890137c43d881..dbb0a25d3c396 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -32,7 +32,7 @@ use sp_core::{ offchain::testing::TestPersistentOffchainDB, storage::{ well_known_keys::{is_child_storage_key, CODE}, - Storage, + StateVersion, Storage, }, testing::TaskExecutor, traits::TaskExecutorExt, @@ -54,6 +54,8 @@ where pub backend: InMemoryBackend, /// Extensions. pub extensions: Extensions, + /// State version to use during tests. + pub state_version: StateVersion, } impl TestExternalities @@ -72,18 +74,31 @@ where /// Create a new instance of `TestExternalities` with storage. pub fn new(storage: Storage) -> Self { - Self::new_with_code(&[], storage) + Self::new_with_code_and_state(&[], storage, Default::default()) + } + + /// Create a new instance of `TestExternalities` with storage for a given state version. + pub fn new_with_state_version(storage: Storage, state_version: StateVersion) -> Self { + Self::new_with_code_and_state(&[], storage, state_version) } /// New empty test externalities. pub fn new_empty() -> Self { - Self::new_with_code(&[], Storage::default()) + Self::new_with_code_and_state(&[], Storage::default(), Default::default()) } /// Create a new instance of `TestExternalities` with code and storage. - pub fn new_with_code(code: &[u8], mut storage: Storage) -> Self { - let overlay = OverlayedChanges::default(); + pub fn new_with_code(code: &[u8], storage: Storage) -> Self { + Self::new_with_code_and_state(code, storage, Default::default()) + } + /// Create a new instance of `TestExternalities` with code and storage for a given state + /// version. + pub fn new_with_code_and_state( + code: &[u8], + mut storage: Storage, + state_version: StateVersion, + ) -> Self { assert!(storage.top.keys().all(|key| !is_child_storage_key(key))); assert!(storage.children_default.keys().all(|key| is_child_storage_key(key))); @@ -94,12 +109,15 @@ where let offchain_db = TestPersistentOffchainDB::new(); + let backend = (storage, state_version).into(); + TestExternalities { - overlay, + overlay: OverlayedChanges::default(), offchain_db, extensions, - backend: storage.into(), + backend, storage_transaction_cache: Default::default(), + state_version, } } @@ -120,14 +138,14 @@ where /// Insert key/value into backend pub fn insert(&mut self, k: StorageKey, v: StorageValue) { - self.backend.insert(vec![(None, vec![(k, Some(v))])]); + self.backend.insert(vec![(None, vec![(k, Some(v))])], self.state_version); } /// Insert key/value into backend. /// /// This only supports inserting keys in child tries. pub fn insert_child(&mut self, c: sp_core::storage::ChildInfo, k: StorageKey, v: StorageValue) { - self.backend.insert(vec![(Some(c), vec![(k, Some(v))])]); + self.backend.insert(vec![(Some(c), vec![(k, Some(v))])], self.state_version); } /// Registers the given extension for this instance. @@ -151,7 +169,7 @@ where )) } - self.backend.update(transaction) + self.backend.update(transaction, self.state_version) } /// Commit all pending changes to the underlying backend. @@ -164,6 +182,7 @@ where &self.backend, Default::default(), &mut Default::default(), + self.state_version, )?; self.backend @@ -240,7 +259,8 @@ where H::Out: Ord + 'static + codec::Codec, { fn default() -> Self { - Self::new(Default::default()) + // default to default version. + Self::new_with_state_version(Storage::default(), Default::default()) } } @@ -249,7 +269,16 @@ where H::Out: Ord + 'static + codec::Codec, { fn from(storage: Storage) -> Self { - Self::new(storage) + Self::new_with_state_version(storage, Default::default()) + } +} + +impl From<(Storage, StateVersion)> for TestExternalities +where + H::Out: Ord + 'static + codec::Codec, +{ + fn from((storage, state_version): (Storage, StateVersion)) -> Self { + Self::new_with_state_version(storage, state_version) } } @@ -309,14 +338,15 @@ mod tests { #[test] fn commit_should_work() { - let mut ext = TestExternalities::::default(); + let storage = Storage::default(); // avoid adding the trie threshold. + let mut ext = TestExternalities::::from((storage, Default::default())); let mut ext = ext.ext(); ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec()); let root = H256::from(hex!("ed4d8c799d996add422395a6abd7545491d40bd838d738afafa1b8a4de625489")); - assert_eq!(H256::from_slice(ext.storage_root().as_slice()), root); + assert_eq!(H256::from_slice(ext.storage_root(Default::default()).as_slice()), root); } #[test] diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index 7f9a02e055251..616a5512ea40b 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -24,12 +24,12 @@ use crate::{ }; use codec::{Codec, Decode}; use hash_db::Hasher; -use sp_core::storage::{ChildInfo, ChildType}; +use sp_core::storage::{ChildInfo, ChildType, StateVersion}; use sp_std::{boxed::Box, vec::Vec}; use sp_trie::{ child_delta_trie_root, delta_trie_root, empty_child_trie_root, - trie_types::{Layout, TrieDB, TrieError}, - Trie, + trie_types::{TrieDB, TrieError}, + LayoutV0, LayoutV1, Trie, }; /// Patricia trie-based backend. Transaction type is an overlay of changes to commit. @@ -186,6 +186,7 @@ where fn storage_root<'a>( &self, delta: impl Iterator)>, + state_version: StateVersion, ) -> (H::Out, Self::Transaction) where H::Out: Ord, @@ -195,8 +196,14 @@ where { let mut eph = Ephemeral::new(self.essence.backend_storage(), &mut write_overlay); - - match delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta) { + let res = match state_version { + StateVersion::V0 => + delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), + StateVersion::V1 => + delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), + }; + + match res { Ok(ret) => root = ret, Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), } @@ -209,14 +216,14 @@ where &self, child_info: &ChildInfo, delta: impl Iterator)>, + state_version: StateVersion, ) -> (H::Out, bool, Self::Transaction) where H::Out: Ord, { let default_root = match child_info.child_type() { - ChildType::ParentKeyId => empty_child_trie_root::>(), + ChildType::ParentKeyId => empty_child_trie_root::>(), }; - let mut write_overlay = S::Overlay::default(); let prefixed_storage_key = child_info.prefixed_storage_key(); let mut root = match self.storage(prefixed_storage_key.as_slice()) { @@ -231,13 +238,20 @@ where { let mut eph = Ephemeral::new(self.essence.backend_storage(), &mut write_overlay); - - match child_delta_trie_root::, _, _, _, _, _, _>( - child_info.keyspace(), - &mut eph, - root, - delta, - ) { + match match state_version { + StateVersion::V0 => child_delta_trie_root::, _, _, _, _, _, _>( + child_info.keyspace(), + &mut eph, + root, + delta, + ), + StateVersion::V1 => child_delta_trie_root::, _, _, _, _, _, _>( + child_info.keyspace(), + &mut eph, + root, + delta, + ), + } { Ok(ret) => root = ret, Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), } @@ -269,52 +283,91 @@ pub mod tests { use codec::Encode; use sp_core::H256; use sp_runtime::traits::BlakeTwo256; - use sp_trie::{trie_types::TrieDBMut, KeySpacedDBMut, PrefixedMemoryDB, TrieMut}; + use sp_trie::{ + trie_types::{TrieDBMutV0, TrieDBMutV1}, + KeySpacedDBMut, PrefixedMemoryDB, TrieMut, + }; use std::{collections::HashSet, iter}; const CHILD_KEY_1: &[u8] = b"sub1"; - fn test_db() -> (PrefixedMemoryDB, H256) { + pub(crate) fn test_db(state_version: StateVersion) -> (PrefixedMemoryDB, H256) { let child_info = ChildInfo::new_default(CHILD_KEY_1); let mut root = H256::default(); let mut mdb = PrefixedMemoryDB::::default(); { let mut mdb = KeySpacedDBMut::new(&mut mdb, child_info.keyspace()); - let mut trie = TrieDBMut::new(&mut mdb, &mut root); - trie.insert(b"value3", &[142; 33]).expect("insert failed"); - trie.insert(b"value4", &[124; 33]).expect("insert failed"); + match state_version { + StateVersion::V0 => { + let mut trie = TrieDBMutV0::new(&mut mdb, &mut root); + trie.insert(b"value3", &[142; 33]).expect("insert failed"); + trie.insert(b"value4", &[124; 33]).expect("insert failed"); + }, + StateVersion::V1 => { + let mut trie = TrieDBMutV1::new(&mut mdb, &mut root); + trie.insert(b"value3", &[142; 33]).expect("insert failed"); + trie.insert(b"value4", &[124; 33]).expect("insert failed"); + }, + }; }; { let mut sub_root = Vec::new(); root.encode_to(&mut sub_root); - let mut trie = TrieDBMut::new(&mut mdb, &mut root); - trie.insert(child_info.prefixed_storage_key().as_slice(), &sub_root[..]) - .expect("insert failed"); - trie.insert(b"key", b"value").expect("insert failed"); - trie.insert(b"value1", &[42]).expect("insert failed"); - trie.insert(b"value2", &[24]).expect("insert failed"); - trie.insert(b":code", b"return 42").expect("insert failed"); - for i in 128u8..255u8 { - trie.insert(&[i], &[i]).unwrap(); + + fn build( + mut trie: sp_trie::TrieDBMut, + child_info: &ChildInfo, + sub_root: &[u8], + ) { + trie.insert(child_info.prefixed_storage_key().as_slice(), sub_root) + .expect("insert failed"); + trie.insert(b"key", b"value").expect("insert failed"); + trie.insert(b"value1", &[42]).expect("insert failed"); + trie.insert(b"value2", &[24]).expect("insert failed"); + trie.insert(b":code", b"return 42").expect("insert failed"); + for i in 128u8..255u8 { + trie.insert(&[i], &[i]).unwrap(); + } } + + match state_version { + StateVersion::V0 => { + let trie = TrieDBMutV0::new(&mut mdb, &mut root); + build(trie, &child_info, &sub_root[..]) + }, + StateVersion::V1 => { + let trie = TrieDBMutV1::new(&mut mdb, &mut root); + build(trie, &child_info, &sub_root[..]) + }, + }; } (mdb, root) } - pub(crate) fn test_trie() -> TrieBackend, BlakeTwo256> { - let (mdb, root) = test_db(); + pub(crate) fn test_trie( + hashed_value: StateVersion, + ) -> TrieBackend, BlakeTwo256> { + let (mdb, root) = test_db(hashed_value); TrieBackend::new(mdb, root) } #[test] fn read_from_storage_returns_some() { - assert_eq!(test_trie().storage(b"key").unwrap(), Some(b"value".to_vec())); + read_from_storage_returns_some_inner(StateVersion::V0); + read_from_storage_returns_some_inner(StateVersion::V1); + } + fn read_from_storage_returns_some_inner(state_version: StateVersion) { + assert_eq!(test_trie(state_version).storage(b"key").unwrap(), Some(b"value".to_vec())); } #[test] fn read_from_child_storage_returns_some() { - let test_trie = test_trie(); + read_from_child_storage_returns_some_inner(StateVersion::V0); + read_from_child_storage_returns_some_inner(StateVersion::V1); + } + fn read_from_child_storage_returns_some_inner(state_version: StateVersion) { + let test_trie = test_trie(state_version); assert_eq!( test_trie .child_storage(&ChildInfo::new_default(CHILD_KEY_1), b"value3") @@ -341,12 +394,20 @@ pub mod tests { #[test] fn read_from_storage_returns_none() { - assert_eq!(test_trie().storage(b"non-existing-key").unwrap(), None); + read_from_storage_returns_none_inner(StateVersion::V0); + read_from_storage_returns_none_inner(StateVersion::V1); + } + fn read_from_storage_returns_none_inner(state_version: StateVersion) { + assert_eq!(test_trie(state_version).storage(b"non-existing-key").unwrap(), None); } #[test] fn pairs_are_not_empty_on_non_empty_storage() { - assert!(!test_trie().pairs().is_empty()); + pairs_are_not_empty_on_non_empty_storage_inner(StateVersion::V0); + pairs_are_not_empty_on_non_empty_storage_inner(StateVersion::V1); + } + fn pairs_are_not_empty_on_non_empty_storage_inner(state_version: StateVersion) { + assert!(!test_trie(state_version).pairs().is_empty()); } #[test] @@ -361,25 +422,35 @@ pub mod tests { #[test] fn storage_root_is_non_default() { - assert!(test_trie().storage_root(iter::empty()).0 != H256::repeat_byte(0)); + storage_root_is_non_default_inner(StateVersion::V0); + storage_root_is_non_default_inner(StateVersion::V1); } - - #[test] - fn storage_root_transaction_is_empty() { - assert!(test_trie().storage_root(iter::empty()).1.drain().is_empty()); + fn storage_root_is_non_default_inner(state_version: StateVersion) { + assert!( + test_trie(state_version).storage_root(iter::empty(), state_version).0 != + H256::repeat_byte(0) + ); } #[test] fn storage_root_transaction_is_non_empty() { - let (new_root, mut tx) = - test_trie().storage_root(iter::once((&b"new-key"[..], Some(&b"new-value"[..])))); + storage_root_transaction_is_non_empty_inner(StateVersion::V0); + storage_root_transaction_is_non_empty_inner(StateVersion::V1); + } + fn storage_root_transaction_is_non_empty_inner(state_version: StateVersion) { + let (new_root, mut tx) = test_trie(state_version) + .storage_root(iter::once((&b"new-key"[..], Some(&b"new-value"[..]))), state_version); assert!(!tx.drain().is_empty()); - assert!(new_root != test_trie().storage_root(iter::empty()).0); + assert!(new_root != test_trie(state_version).storage_root(iter::empty(), state_version).0); } #[test] fn prefix_walking_works() { - let trie = test_trie(); + prefix_walking_works_inner(StateVersion::V0); + prefix_walking_works_inner(StateVersion::V1); + } + fn prefix_walking_works_inner(state_version: StateVersion) { + let trie = test_trie(state_version); let mut seen = HashSet::new(); trie.for_keys_with_prefix(b"value", |key| { diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 6c575f0d76bc7..945fd05ebffb4 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -20,20 +20,23 @@ use crate::{backend::Consolidate, debug, warn, StorageKey, StorageValue}; use codec::Encode; -use hash_db::{self, Hasher, Prefix}; +use hash_db::{self, AsHashDB, HashDB, HashDBRef, Hasher, Prefix}; #[cfg(feature = "std")] use parking_lot::RwLock; use sp_core::storage::ChildInfo; use sp_std::{boxed::Box, vec::Vec}; use sp_trie::{ empty_child_trie_root, read_child_trie_value, read_trie_value, - trie_types::{Layout, TrieDB, TrieError}, - DBValue, KeySpacedDB, MemoryDB, PrefixedMemoryDB, Trie, TrieDBIterator, + trie_types::{TrieDB, TrieError}, + DBValue, KeySpacedDB, PrefixedMemoryDB, Trie, TrieDBIterator, TrieDBKeyIterator, }; #[cfg(feature = "std")] use std::collections::HashMap; #[cfg(feature = "std")] use std::sync::Arc; +// In this module, we only use layout for read operation and empty root, +// where V1 and V0 are equivalent. +use sp_trie::LayoutV1 as Layout; #[cfg(not(feature = "std"))] macro_rules! format { @@ -178,7 +181,7 @@ where child_info: Option<&ChildInfo>, key: &[u8], ) -> Result> { - let dyn_eph: &dyn hash_db::HashDBRef<_, _>; + let dyn_eph: &dyn HashDBRef<_, _>; let keyspace_eph; if let Some(child_info) = child_info.as_ref() { keyspace_eph = KeySpacedDB::new(self, child_info.keyspace()); @@ -189,7 +192,7 @@ where let trie = TrieDB::::new(dyn_eph, root).map_err(|e| format!("TrieDB creation error: {}", e))?; - let mut iter = trie.iter().map_err(|e| format!("TrieDB iteration error: {}", e))?; + let mut iter = trie.key_iter().map_err(|e| format!("TrieDB iteration error: {}", e))?; // The key just after the one given in input, basically `key++0`. // Note: We are sure this is the next key if: @@ -205,7 +208,7 @@ where let next_element = iter.next(); let next_key = if let Some(next_element) = next_element { - let (next_key, _) = + let next_key = next_element.map_err(|e| format!("TrieDB iterator next error: {}", e))?; Some(next_key) } else { @@ -291,17 +294,7 @@ where &self.root }; - let _ = self.trie_iter_inner( - root, - prefix, - |k, _v| { - f(&k); - true - }, - child_info, - None, - false, - ); + self.trie_iter_key_inner(root, prefix, |k| f(k), child_info) } /// Execute given closure for all keys starting with prefix. @@ -320,32 +313,70 @@ where }; let mut root = H::Out::default(); root.as_mut().copy_from_slice(&root_vec); - let _ = self.trie_iter_inner( + self.trie_iter_key_inner( &root, Some(prefix), - |k, _v| { - f(&k); + |k| { + f(k); true }, Some(child_info), - None, - false, - ); + ) } /// Execute given closure for all keys starting with prefix. pub fn for_keys_with_prefix(&self, prefix: &[u8], mut f: F) { - let _ = self.trie_iter_inner( + self.trie_iter_key_inner( &self.root, Some(prefix), - |k, _v| { - f(&k); + |k| { + f(k); true }, None, - None, - false, - ); + ) + } + + fn trie_iter_key_inner bool>( + &self, + root: &H::Out, + prefix: Option<&[u8]>, + mut f: F, + child_info: Option<&ChildInfo>, + ) { + let mut iter = move |db| -> sp_std::result::Result<(), Box>> { + let trie = TrieDB::::new(db, root)?; + let iter = if let Some(prefix) = prefix.as_ref() { + TrieDBKeyIterator::new_prefixed(&trie, prefix)? + } else { + TrieDBKeyIterator::new(&trie)? + }; + + for x in iter { + let key = x?; + + debug_assert!(prefix + .as_ref() + .map(|prefix| key.starts_with(prefix)) + .unwrap_or(true)); + + if !f(&key) { + break + } + } + + Ok(()) + }; + + let result = if let Some(child_info) = child_info { + let db = KeySpacedDB::new(self, child_info.keyspace()); + iter(&db) + } else { + iter(self) + }; + if let Err(e) = result { + debug!(target: "trie", "Error while iterating by prefix: {}", e); + } } fn trie_iter_inner, Vec) -> bool>( @@ -414,13 +445,13 @@ pub(crate) struct Ephemeral<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> { overlay: &'a mut S::Overlay, } -impl<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> hash_db::AsHashDB +impl<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> AsHashDB for Ephemeral<'a, S, H> { - fn as_hash_db<'b>(&'b self) -> &'b (dyn hash_db::HashDB + 'b) { + fn as_hash_db<'b>(&'b self) -> &'b (dyn HashDB + 'b) { self } - fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn hash_db::HashDB + 'b) { + fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn HashDB + 'b) { self } } @@ -435,7 +466,7 @@ impl<'a, S: 'a + TrieBackendStorage, H: Hasher> hash_db::HashDB for Ephemeral<'a, S, H> { fn get(&self, key: &H::Out, prefix: Prefix) -> Option { - if let Some(val) = hash_db::HashDB::get(self.overlay, key, prefix) { + if let Some(val) = HashDB::get(self.overlay, key, prefix) { Some(val) } else { match self.storage.get(&key, prefix) { @@ -449,38 +480,37 @@ impl<'a, S: 'a + TrieBackendStorage, H: Hasher> hash_db::HashDB } fn contains(&self, key: &H::Out, prefix: Prefix) -> bool { - hash_db::HashDB::get(self, key, prefix).is_some() + HashDB::get(self, key, prefix).is_some() } fn insert(&mut self, prefix: Prefix, value: &[u8]) -> H::Out { - hash_db::HashDB::insert(self.overlay, prefix, value) + HashDB::insert(self.overlay, prefix, value) } fn emplace(&mut self, key: H::Out, prefix: Prefix, value: DBValue) { - hash_db::HashDB::emplace(self.overlay, key, prefix, value) + HashDB::emplace(self.overlay, key, prefix, value) } fn remove(&mut self, key: &H::Out, prefix: Prefix) { - hash_db::HashDB::remove(self.overlay, key, prefix) + HashDB::remove(self.overlay, key, prefix) } } -impl<'a, S: 'a + TrieBackendStorage, H: Hasher> hash_db::HashDBRef - for Ephemeral<'a, S, H> -{ +impl<'a, S: 'a + TrieBackendStorage, H: Hasher> HashDBRef for Ephemeral<'a, S, H> { fn get(&self, key: &H::Out, prefix: Prefix) -> Option { - hash_db::HashDB::get(self, key, prefix) + HashDB::get(self, key, prefix) } fn contains(&self, key: &H::Out, prefix: Prefix) -> bool { - hash_db::HashDB::contains(self, key, prefix) + HashDB::contains(self, key, prefix) } } /// Key-value pairs storage that is used by trie backend essence. pub trait TrieBackendStorage: Send + Sync { /// Type of in-memory overlay. - type Overlay: hash_db::HashDB + Default + Consolidate; + type Overlay: HashDB + Default + Consolidate; + /// Get the value stored at key. fn get(&self, key: &H::Out, prefix: Prefix) -> Result>; } @@ -495,35 +525,28 @@ impl TrieBackendStorage for Arc> { } } -// This implementation is used by test storage trie clients. -impl TrieBackendStorage for PrefixedMemoryDB { - type Overlay = PrefixedMemoryDB; - - fn get(&self, key: &H::Out, prefix: Prefix) -> Result> { - Ok(hash_db::HashDB::get(self, key, prefix)) - } -} - -impl TrieBackendStorage for MemoryDB { - type Overlay = MemoryDB; +impl TrieBackendStorage for sp_trie::GenericMemoryDB +where + H: Hasher, + KF: sp_trie::KeyFunction + Send + Sync, +{ + type Overlay = Self; fn get(&self, key: &H::Out, prefix: Prefix) -> Result> { Ok(hash_db::HashDB::get(self, key, prefix)) } } -impl, H: Hasher> hash_db::AsHashDB - for TrieBackendEssence -{ - fn as_hash_db<'b>(&'b self) -> &'b (dyn hash_db::HashDB + 'b) { +impl, H: Hasher> AsHashDB for TrieBackendEssence { + fn as_hash_db<'b>(&'b self) -> &'b (dyn HashDB + 'b) { self } - fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn hash_db::HashDB + 'b) { + fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn HashDB + 'b) { self } } -impl, H: Hasher> hash_db::HashDB for TrieBackendEssence { +impl, H: Hasher> HashDB for TrieBackendEssence { fn get(&self, key: &H::Out, prefix: Prefix) -> Option { if *key == self.empty { return Some([0u8].to_vec()) @@ -538,7 +561,7 @@ impl, H: Hasher> hash_db::HashDB for TrieBa } fn contains(&self, key: &H::Out, prefix: Prefix) -> bool { - hash_db::HashDB::get(self, key, prefix).is_some() + HashDB::get(self, key, prefix).is_some() } fn insert(&mut self, _prefix: Prefix, _value: &[u8]) -> H::Out { @@ -554,15 +577,13 @@ impl, H: Hasher> hash_db::HashDB for TrieBa } } -impl, H: Hasher> hash_db::HashDBRef - for TrieBackendEssence -{ +impl, H: Hasher> HashDBRef for TrieBackendEssence { fn get(&self, key: &H::Out, prefix: Prefix) -> Option { - hash_db::HashDB::get(self, key, prefix) + HashDB::get(self, key, prefix) } fn contains(&self, key: &H::Out, prefix: Prefix) -> bool { - hash_db::HashDB::contains(self, key, prefix) + HashDB::contains(self, key, prefix) } } @@ -570,7 +591,9 @@ impl, H: Hasher> hash_db::HashDBRef mod test { use super::*; use sp_core::{Blake2Hasher, H256}; - use sp_trie::{trie_types::TrieDBMut, KeySpacedDBMut, PrefixedMemoryDB, TrieMut}; + use sp_trie::{ + trie_types::TrieDBMutV1 as TrieDBMut, KeySpacedDBMut, PrefixedMemoryDB, TrieMut, + }; #[test] fn next_storage_key_and_next_child_storage_key_work() { diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index c655a9bdc1cf0..eff74c4aac0b2 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -237,6 +237,9 @@ pub mod well_known_keys { } } +/// Threshold size to start using trie value nodes in state. +pub const TRIE_VALUE_NODE_THRESHOLD: u32 = 33; + /// Information related to a child state. #[derive(Debug, Clone)] #[cfg_attr(feature = "std", derive(PartialEq, Eq, Hash, PartialOrd, Ord, Encode, Decode))] @@ -401,6 +404,54 @@ impl ChildTrieParentKeyId { } } +/// Different possible state version. +/// +/// V0 and V1 uses a same trie implementation, but V1 will write external value node in the trie for +/// value with size at least `TRIE_VALUE_NODE_THRESHOLD`. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum StateVersion { + /// Old state version, no value nodes. + V0 = 0, + /// New state version can use value nodes. + V1 = 1, +} + +impl Default for StateVersion { + fn default() -> Self { + StateVersion::V1 + } +} + +impl From for u8 { + fn from(version: StateVersion) -> u8 { + version as u8 + } +} + +impl sp_std::convert::TryFrom for StateVersion { + type Error = (); + fn try_from(val: u8) -> sp_std::result::Result { + match val { + 0 => Ok(StateVersion::V0), + 1 => Ok(StateVersion::V1), + _ => Err(()), + } + } +} + +impl StateVersion { + /// If defined, values in state of size bigger or equal + /// to this threshold will use a separate trie node. + /// Otherwhise, value will be inlined in branch or leaf + /// node. + pub fn state_value_threshold(&self) -> Option { + match self { + StateVersion::V0 => None, + StateVersion::V1 => Some(TRIE_VALUE_NODE_THRESHOLD), + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/primitives/tasks/src/async_externalities.rs b/primitives/tasks/src/async_externalities.rs index 59733490a18ff..9f2fec299f598 100644 --- a/primitives/tasks/src/async_externalities.rs +++ b/primitives/tasks/src/async_externalities.rs @@ -19,7 +19,7 @@ //! Async externalities. use sp_core::{ - storage::{ChildInfo, TrackedStorageKey}, + storage::{ChildInfo, StateVersion, TrackedStorageKey}, traits::{Externalities, RuntimeSpawn, RuntimeSpawnExt, SpawnNamed, TaskExecutorExt}, }; use sp_externalities::{Extensions, ExternalitiesExt as _}; @@ -126,11 +126,15 @@ impl Externalities for AsyncExternalities { panic!("`storage_append`: should not be used in async externalities!") } - fn storage_root(&mut self) -> Vec { + fn storage_root(&mut self, _state_version: StateVersion) -> Vec { panic!("`storage_root`: should not be used in async externalities!") } - fn child_storage_root(&mut self, _child_info: &ChildInfo) -> Vec { + fn child_storage_root( + &mut self, + _child_info: &ChildInfo, + _state_version: StateVersion, + ) -> Vec { panic!("`child_storage_root`: should not be used in async externalities!") } diff --git a/primitives/transaction-storage-proof/src/lib.rs b/primitives/transaction-storage-proof/src/lib.rs index 4b01a8d45d454..f76ae7faac08b 100644 --- a/primitives/transaction-storage-proof/src/lib.rs +++ b/primitives/transaction-storage-proof/src/lib.rs @@ -143,7 +143,7 @@ pub mod registration { use sp_trie::TrieMut; type Hasher = sp_core::Blake2Hasher; - type TrieLayout = sp_trie::Layout; + type TrieLayout = sp_trie::LayoutV1; /// Create a new inherent data provider instance for a given parent block hash. pub fn new_data_provider( diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 02aaa75aa939e..8e54035b3ae7d 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -22,13 +22,13 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } hash-db = { version = "0.15.2", default-features = false } -trie-db = { version = "0.22.6", default-features = false } -trie-root = { version = "0.16.0", default-features = false } -memory-db = { version = "0.27.0", default-features = false } +trie-db = { version = "0.23.0", default-features = false } +trie-root = { version = "0.17.0", default-features = false } +memory-db = { version = "0.28.0", default-features = false } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } [dev-dependencies] -trie-bench = "0.28.0" +trie-bench = "0.29.0" trie-standardmap = "0.15.2" criterion = "0.3.3" hex-literal = "0.3.4" diff --git a/primitives/trie/benches/bench.rs b/primitives/trie/benches/bench.rs index 8c84c6354f2c3..d78ceadff7283 100644 --- a/primitives/trie/benches/bench.rs +++ b/primitives/trie/benches/bench.rs @@ -21,11 +21,11 @@ criterion_main!(benches); fn benchmark(c: &mut Criterion) { trie_bench::standard_benchmark::< - sp_trie::Layout, + sp_trie::LayoutV1, sp_trie::TrieStream, >(c, "substrate-blake2"); trie_bench::standard_benchmark::< - sp_trie::Layout, + sp_trie::LayoutV1, sp_trie::TrieStream, >(c, "substrate-keccak"); } diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index 8ba13284d379f..399484143dbc4 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -45,31 +45,43 @@ pub use trie_db::proof::VerifyError; use trie_db::proof::{generate_proof, verify_proof}; /// Various re-exports from the `trie-db` crate. pub use trie_db::{ - nibble_ops, CError, DBValue, Query, Recorder, Trie, TrieConfiguration, TrieDBIterator, + nibble_ops, + node::{NodePlan, ValuePlan}, + CError, DBValue, Query, Recorder, Trie, TrieConfiguration, TrieDBIterator, TrieDBKeyIterator, TrieLayout, TrieMut, }; /// The Substrate format implementation of `TrieStream`. pub use trie_stream::TrieStream; -#[derive(Default)] /// substrate trie layout -pub struct Layout(sp_std::marker::PhantomData); +pub struct LayoutV0(sp_std::marker::PhantomData); -impl TrieLayout for Layout { +/// substrate trie layout, with external value nodes. +pub struct LayoutV1(sp_std::marker::PhantomData); + +impl TrieLayout for LayoutV0 +where + H: Hasher, +{ const USE_EXTENSION: bool = false; const ALLOW_EMPTY: bool = true; + const MAX_INLINE_VALUE: Option = None; + type Hash = H; type Codec = NodeCodec; } -impl TrieConfiguration for Layout { +impl TrieConfiguration for LayoutV0 +where + H: Hasher, +{ fn trie_root(input: I) -> ::Out where I: IntoIterator, A: AsRef<[u8]> + Ord, B: AsRef<[u8]>, { - trie_root::trie_root_no_extension::(input) + trie_root::trie_root_no_extension::(input, Self::MAX_INLINE_VALUE) } fn trie_root_unhashed(input: I) -> Vec @@ -78,7 +90,52 @@ impl TrieConfiguration for Layout { A: AsRef<[u8]> + Ord, B: AsRef<[u8]>, { - trie_root::unhashed_trie_no_extension::(input) + trie_root::unhashed_trie_no_extension::( + input, + Self::MAX_INLINE_VALUE, + ) + } + + fn encode_index(input: u32) -> Vec { + codec::Encode::encode(&codec::Compact(input)) + } +} + +impl TrieLayout for LayoutV1 +where + H: Hasher, +{ + const USE_EXTENSION: bool = false; + const ALLOW_EMPTY: bool = true; + const MAX_INLINE_VALUE: Option = Some(sp_core::storage::TRIE_VALUE_NODE_THRESHOLD); + + type Hash = H; + type Codec = NodeCodec; +} + +impl TrieConfiguration for LayoutV1 +where + H: Hasher, +{ + fn trie_root(input: I) -> ::Out + where + I: IntoIterator, + A: AsRef<[u8]> + Ord, + B: AsRef<[u8]>, + { + trie_root::trie_root_no_extension::(input, Self::MAX_INLINE_VALUE) + } + + fn trie_root_unhashed(input: I) -> Vec + where + I: IntoIterator, + A: AsRef<[u8]> + Ord, + B: AsRef<[u8]>, + { + trie_root::unhashed_trie_no_extension::( + input, + Self::MAX_INLINE_VALUE, + ) } fn encode_index(input: u32) -> Vec { @@ -118,17 +175,22 @@ pub type TrieDBMut<'a, L> = trie_db::TrieDBMut<'a, L>; pub type Lookup<'a, L, Q> = trie_db::Lookup<'a, L, Q>; /// Hash type for a trie layout. pub type TrieHash = <::Hash as Hasher>::Out; - /// This module is for non generic definition of trie type. /// Only the `Hasher` trait is generic in this case. pub mod trie_types { - pub type Layout = super::Layout; + use super::*; + /// Persistent trie database read-access interface for the a given hasher. - pub type TrieDB<'a, H> = super::TrieDB<'a, Layout>; + /// Read only V1 and V0 are compatible, thus we always use V1. + pub type TrieDB<'a, H> = super::TrieDB<'a, LayoutV1>; /// Persistent trie database write-access interface for the a given hasher. - pub type TrieDBMut<'a, H> = super::TrieDBMut<'a, Layout>; + pub type TrieDBMutV0<'a, H> = super::TrieDBMut<'a, LayoutV0>; + /// Persistent trie database write-access interface for the a given hasher. + pub type TrieDBMutV1<'a, H> = super::TrieDBMut<'a, LayoutV1>; + /// Querying interface, as in `trie_db` but less generic. + pub type LookupV0<'a, H, Q> = trie_db::Lookup<'a, LayoutV0, Q>; /// Querying interface, as in `trie_db` but less generic. - pub type Lookup<'a, H, Q> = trie_db::Lookup<'a, Layout, Q>; + pub type LookupV1<'a, H, Q> = trie_db::Lookup<'a, LayoutV1, Q>; /// As in `trie_db`, but less generic, error type for the crate. pub type TrieError = trie_db::TrieError; } @@ -141,16 +203,18 @@ pub mod trie_types { /// For a key `K` that is included in the `db` a proof of inclusion is generated. /// For a key `K` that is not included in the `db` a proof of non-inclusion is generated. /// These can be later checked in `verify_trie_proof`. -pub fn generate_trie_proof<'a, L: TrieConfiguration, I, K, DB>( +pub fn generate_trie_proof<'a, L, I, K, DB>( db: &DB, root: TrieHash, keys: I, ) -> Result>, Box>> where + L: TrieConfiguration, I: IntoIterator, K: 'a + AsRef<[u8]>, DB: hash_db::HashDBRef, { + // Can use default layout (read only). let trie = TrieDB::::new(db, &root)?; generate_proof(&trie, keys) } @@ -163,17 +227,18 @@ where /// checked for inclusion in the proof. /// If the value is omitted (`(key, None)`), this key will be checked for non-inclusion in the /// proof. -pub fn verify_trie_proof<'a, L: TrieConfiguration, I, K, V>( +pub fn verify_trie_proof<'a, L, I, K, V>( root: &TrieHash, proof: &[Vec], items: I, -) -> Result<(), VerifyError, error::Error>> +) -> Result<(), VerifyError, CError>> where + L: TrieConfiguration, I: IntoIterator)>, K: 'a + AsRef<[u8]>, V: 'a + AsRef<[u8]>, { - verify_proof::, _, _, _>(root, proof, items) + verify_proof::(root, proof, items) } /// Determine a trie root given a hash DB and delta values. @@ -207,28 +272,33 @@ where } /// Read a value from the trie. -pub fn read_trie_value>( +pub fn read_trie_value( db: &DB, root: &TrieHash, key: &[u8], -) -> Result>, Box>> { - TrieDB::::new(&*db, root)?.get(key).map(|x| x.map(|val| val.to_vec())) +) -> Result>, Box>> +where + L: TrieConfiguration, + DB: hash_db::HashDBRef, +{ + Ok(TrieDB::::new(&*db, root)?.get(key).map(|x| x.map(|val| val.to_vec()))?) } /// Read a value from the trie with given Query. -pub fn read_trie_value_with< - L: TrieConfiguration, - Q: Query, - DB: hash_db::HashDBRef, ->( +pub fn read_trie_value_with( db: &DB, root: &TrieHash, key: &[u8], query: Q, -) -> Result>, Box>> { - TrieDB::::new(&*db, root)? +) -> Result>, Box>> +where + L: TrieConfiguration, + Q: Query, + DB: hash_db::HashDBRef, +{ + Ok(TrieDB::::new(&*db, root)? .get_with(key, query) - .map(|x| x.map(|val| val.to_vec())) + .map(|x| x.map(|val| val.to_vec()))?) } /// Determine the empty trie root. @@ -319,7 +389,7 @@ where } /// Read a value from the child trie with given query. -pub fn read_child_trie_value_with, DB>( +pub fn read_child_trie_value_with( keyspace: &[u8], db: &DB, root_slice: &[u8], @@ -327,6 +397,8 @@ pub fn read_child_trie_value_with Result>, Box>> where + L: TrieConfiguration, + Q: Query, DB: hash_db::HashDBRef, { let mut root = TrieHash::::default(); @@ -444,11 +516,15 @@ where /// Constants used into trie simplification codec. mod trie_constants { - pub const EMPTY_TRIE: u8 = 0; - pub const NIBBLE_SIZE_BOUND: usize = u16::MAX as usize; + const FIRST_PREFIX: u8 = 0b_00 << 6; + pub const NIBBLE_SIZE_BOUND: usize = u16::max_value() as usize; pub const LEAF_PREFIX_MASK: u8 = 0b_01 << 6; pub const BRANCH_WITHOUT_MASK: u8 = 0b_10 << 6; pub const BRANCH_WITH_MASK: u8 = 0b_11 << 6; + pub const EMPTY_TRIE: u8 = FIRST_PREFIX | (0b_00 << 4); + pub const ALT_HASHING_LEAF_PREFIX_MASK: u8 = FIRST_PREFIX | (0b_1 << 5); + pub const ALT_HASHING_BRANCH_WITH_MASK: u8 = FIRST_PREFIX | (0b_01 << 4); + pub const ESCAPE_COMPACT_HEADER: u8 = EMPTY_TRIE | 0b_00_01; } #[cfg(test)] @@ -461,7 +537,11 @@ mod tests { use trie_db::{DBValue, NodeCodec as NodeCodecT, Trie, TrieMut}; use trie_standardmap::{Alphabet, StandardMap, ValueMode}; - type Layout = super::Layout; + type LayoutV0 = super::LayoutV0; + type LayoutV1 = super::LayoutV1; + + type MemoryDBMeta = + memory_db::MemoryDB, trie_db::DBValue, MemTracker>; fn hashed_null_node() -> TrieHash { ::hashed_null_node() @@ -473,7 +553,7 @@ mod tests { let d = T::trie_root_unhashed(input.clone()); println!("Data: {:#x?}, {:#x?}", d, Blake2Hasher::hash(&d[..])); let persistent = { - let mut memdb = MemoryDB::default(); + let mut memdb = MemoryDBMeta::default(); let mut root = Default::default(); let mut t = TrieDBMut::::new(&mut memdb, &mut root); for (x, y) in input.iter().rev() { @@ -486,7 +566,7 @@ mod tests { } fn check_iteration(input: &Vec<(&[u8], &[u8])>) { - let mut memdb = MemoryDB::default(); + let mut memdb = MemoryDBMeta::default(); let mut root = Default::default(); { let mut t = TrieDBMut::::new(&mut memdb, &mut root); @@ -506,14 +586,21 @@ mod tests { } } + fn check_input(input: &Vec<(&[u8], &[u8])>) { + check_equivalent::(input); + check_iteration::(input); + check_equivalent::(input); + check_iteration::(input); + } + #[test] fn default_trie_root() { let mut db = MemoryDB::default(); - let mut root = TrieHash::::default(); - let mut empty = TrieDBMut::::new(&mut db, &mut root); + let mut root = TrieHash::::default(); + let mut empty = TrieDBMut::::new(&mut db, &mut root); empty.commit(); let root1 = empty.root().as_ref().to_vec(); - let root2: Vec = Layout::trie_root::<_, Vec, Vec>(std::iter::empty()) + let root2: Vec = LayoutV1::trie_root::<_, Vec, Vec>(std::iter::empty()) .as_ref() .iter() .cloned() @@ -525,31 +612,27 @@ mod tests { #[test] fn empty_is_equivalent() { let input: Vec<(&[u8], &[u8])> = vec![]; - check_equivalent::(&input); - check_iteration::(&input); + check_input(&input); } #[test] fn leaf_is_equivalent() { let input: Vec<(&[u8], &[u8])> = vec![(&[0xaa][..], &[0xbb][..])]; - check_equivalent::(&input); - check_iteration::(&input); + check_input(&input); } #[test] fn branch_is_equivalent() { let input: Vec<(&[u8], &[u8])> = vec![(&[0xaa][..], &[0x10][..]), (&[0xba][..], &[0x11][..])]; - check_equivalent::(&input); - check_iteration::(&input); + check_input(&input); } #[test] fn extension_and_branch_is_equivalent() { let input: Vec<(&[u8], &[u8])> = vec![(&[0xaa][..], &[0x10][..]), (&[0xab][..], &[0x11][..])]; - check_equivalent::(&input); - check_iteration::(&input); + check_input(&input); } #[test] @@ -564,8 +647,7 @@ mod tests { let mut d = st.make(); d.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b)); let dr = d.iter().map(|v| (&v.0[..], &v.1[..])).collect(); - check_equivalent::(&dr); - check_iteration::(&dr); + check_input(&dr); } #[test] @@ -575,8 +657,7 @@ mod tests { (&[0xaa, 0xaa][..], &[0xaa][..]), (&[0xaa, 0xbb][..], &[0xab][..]), ]; - check_equivalent::(&input); - check_iteration::(&input); + check_input(&input); } #[test] @@ -589,8 +670,7 @@ mod tests { (&[0xbb, 0xbb][..], &[0xbb][..]), (&[0xbb, 0xcc][..], &[0xbc][..]), ]; - check_equivalent::(&input); - check_iteration::(&input); + check_input(&input); } #[test] @@ -602,8 +682,7 @@ mod tests { ), (&[0xba][..], &[0x11][..]), ]; - check_equivalent::(&input); - check_iteration::(&input); + check_input(&input); } #[test] @@ -618,15 +697,17 @@ mod tests { &b"ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC"[..], ), ]; - check_equivalent::(&input); - check_iteration::(&input); + check_input(&input); } - fn populate_trie<'db, T: TrieConfiguration>( + fn populate_trie<'db, T>( db: &'db mut dyn HashDB, root: &'db mut TrieHash, v: &[(Vec, Vec)], - ) -> TrieDBMut<'db, T> { + ) -> TrieDBMut<'db, T> + where + T: TrieConfiguration, + { let mut t = TrieDBMut::::new(db, root); for i in 0..v.len() { let key: &[u8] = &v[i].0; @@ -648,8 +729,12 @@ mod tests { #[test] fn random_should_work() { + random_should_work_inner::(); + random_should_work_inner::(); + } + fn random_should_work_inner() { let mut seed = ::Out::zero(); - for test_i in 0..10000 { + for test_i in 0..10_000 { if test_i % 50 == 0 { println!("{:?} of 10000 stress tests done", test_i); } @@ -662,10 +747,11 @@ mod tests { } .make_with(seed.as_fixed_bytes_mut()); - let real = Layout::trie_root(x.clone()); + let real = L::trie_root(x.clone()); let mut memdb = MemoryDB::default(); let mut root = Default::default(); - let mut memtrie = populate_trie::(&mut memdb, &mut root, &x); + + let mut memtrie = populate_trie::(&mut memdb, &mut root, &x); memtrie.commit(); if *memtrie.root() != real { @@ -677,9 +763,9 @@ mod tests { } } assert_eq!(*memtrie.root(), real); - unpopulate_trie::(&mut memtrie, &x); + unpopulate_trie::(&mut memtrie, &x); memtrie.commit(); - let hashed_null_node = hashed_null_node::(); + let hashed_null_node = hashed_null_node::(); if *memtrie.root() != hashed_null_node { println!("- TRIE MISMATCH"); println!(""); @@ -699,7 +785,7 @@ mod tests { #[test] fn codec_trie_empty() { let input: Vec<(&[u8], &[u8])> = vec![]; - let trie = Layout::trie_root_unhashed::<_, _, _>(input); + let trie = LayoutV1::trie_root_unhashed(input); println!("trie: {:#x?}", trie); assert_eq!(trie, vec![0x0]); } @@ -707,7 +793,7 @@ mod tests { #[test] fn codec_trie_single_tuple() { let input = vec![(vec![0xaa], vec![0xbb])]; - let trie = Layout::trie_root_unhashed::<_, _, _>(input); + let trie = LayoutV1::trie_root_unhashed(input); println!("trie: {:#x?}", trie); assert_eq!( trie, @@ -723,7 +809,7 @@ mod tests { #[test] fn codec_trie_two_tuples_disjoint_keys() { let input = vec![(&[0x48, 0x19], &[0xfe]), (&[0x13, 0x14], &[0xff])]; - let trie = Layout::trie_root_unhashed::<_, _, _>(input); + let trie = LayoutV1::trie_root_unhashed(input); println!("trie: {:#x?}", trie); let mut ex = Vec::::new(); ex.push(0x80); // branch, no value (0b_10..) no nibble @@ -747,6 +833,10 @@ mod tests { #[test] fn iterator_works() { + iterator_works_inner::(); + iterator_works_inner::(); + } + fn iterator_works_inner() { let pairs = vec![ (hex!("0103000000000000000464").to_vec(), hex!("0400000000").to_vec()), (hex!("0103000000000000000469").to_vec(), hex!("0401000000").to_vec()), @@ -777,15 +867,15 @@ mod tests { let mut memdb = MemoryDB::default(); let mut root = Default::default(); - populate_trie::(&mut memdb, &mut root, &pairs); + populate_trie::(&mut memdb, &mut root, &pairs); let non_included_key: Vec = hex!("0909").to_vec(); let proof = - generate_trie_proof::(&memdb, root, &[non_included_key.clone()]) + generate_trie_proof::(&memdb, root, &[non_included_key.clone()]) .unwrap(); // Verifying that the K was not included into the trie should work. - assert!(verify_trie_proof::>( + assert!(verify_trie_proof::>( &root, &proof, &[(non_included_key.clone(), None)], @@ -793,7 +883,7 @@ mod tests { .is_ok()); // Verifying that the K was included into the trie should fail. - assert!(verify_trie_proof::>( + assert!(verify_trie_proof::>( &root, &proof, &[(non_included_key, Some(hex!("1010").to_vec()))], @@ -810,13 +900,13 @@ mod tests { let mut memdb = MemoryDB::default(); let mut root = Default::default(); - populate_trie::(&mut memdb, &mut root, &pairs); + populate_trie::(&mut memdb, &mut root, &pairs); let proof = - generate_trie_proof::(&memdb, root, &[pairs[0].0.clone()]).unwrap(); + generate_trie_proof::(&memdb, root, &[pairs[0].0.clone()]).unwrap(); // Check that a K, V included into the proof are verified. - assert!(verify_trie_proof::( + assert!(verify_trie_proof::( &root, &proof, &[(pairs[0].0.clone(), Some(pairs[0].1.clone()))] @@ -824,7 +914,7 @@ mod tests { .is_ok()); // Absence of the V is not verified with the proof that has K, V included. - assert!(verify_trie_proof::>( + assert!(verify_trie_proof::>( &root, &proof, &[(pairs[0].0.clone(), None)] @@ -832,7 +922,7 @@ mod tests { .is_err()); // K not included into the trie is not verified. - assert!(verify_trie_proof::( + assert!(verify_trie_proof::( &root, &proof, &[(hex!("4242").to_vec(), Some(pairs[0].1.clone()))] @@ -840,7 +930,7 @@ mod tests { .is_err()); // K included into the trie but not included into the proof is not verified. - assert!(verify_trie_proof::( + assert!(verify_trie_proof::( &root, &proof, &[(pairs[1].0.clone(), Some(pairs[1].1.clone()))] @@ -865,13 +955,13 @@ mod tests { .unwrap(); let proof_db = proof.into_memory_db::(); - let first_storage_root = delta_trie_root::( + let first_storage_root = delta_trie_root::( &mut proof_db.clone(), storage_root, valid_delta, ) .unwrap(); - let second_storage_root = delta_trie_root::( + let second_storage_root = delta_trie_root::( &mut proof_db.clone(), storage_root, invalid_delta, diff --git a/primitives/trie/src/node_codec.rs b/primitives/trie/src/node_codec.rs index d5ffb3219cf68..53a5de270a79a 100644 --- a/primitives/trie/src/node_codec.rs +++ b/primitives/trie/src/node_codec.rs @@ -24,7 +24,7 @@ use hash_db::Hasher; use sp_std::{borrow::Borrow, marker::PhantomData, ops::Range, vec::Vec}; use trie_db::{ self, nibble_ops, - node::{NibbleSlicePlan, NodeHandlePlan, NodePlan}, + node::{NibbleSlicePlan, NodeHandlePlan, NodePlan, Value, ValuePlan}, ChildReference, NodeCodec as NodeCodecT, Partial, }; @@ -80,7 +80,11 @@ impl<'a> Input for ByteSliceInput<'a> { #[derive(Default, Clone)] pub struct NodeCodec(PhantomData); -impl NodeCodecT for NodeCodec { +impl NodeCodecT for NodeCodec +where + H: Hasher, +{ + const ESCAPE_HEADER: Option = Some(trie_constants::ESCAPE_COMPACT_HEADER); type Error = Error; type HashOut = H::Out; @@ -88,11 +92,22 @@ impl NodeCodecT for NodeCodec { H::hash(::empty_node()) } - fn decode_plan(data: &[u8]) -> sp_std::result::Result { + fn decode_plan(data: &[u8]) -> Result { let mut input = ByteSliceInput::new(data); - match NodeHeader::decode(&mut input)? { + + let header = NodeHeader::decode(&mut input)?; + let contains_hash = header.contains_hash_of_value(); + + let branch_has_value = if let NodeHeader::Branch(has_value, _) = &header { + *has_value + } else { + // hashed_value_branch + true + }; + + match header { NodeHeader::Null => Ok(NodePlan::Empty), - NodeHeader::Branch(has_value, nibble_count) => { + NodeHeader::HashedValueBranch(nibble_count) | NodeHeader::Branch(_, nibble_count) => { let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0; // check that the padding is valid (if any) if padding && nibble_ops::pad_left(data[input.offset]) != 0 { @@ -105,9 +120,13 @@ impl NodeCodecT for NodeCodec { let partial_padding = nibble_ops::number_padding(nibble_count); let bitmap_range = input.take(BITMAP_LENGTH)?; let bitmap = Bitmap::decode(&data[bitmap_range])?; - let value = if has_value { - let count = >::decode(&mut input)?.0 as usize; - Some(input.take(count)?) + let value = if branch_has_value { + Some(if contains_hash { + ValuePlan::Node(input.take(H::LENGTH)?) + } else { + let count = >::decode(&mut input)?.0 as usize; + ValuePlan::Inline(input.take(count)?) + }) } else { None }; @@ -132,7 +151,7 @@ impl NodeCodecT for NodeCodec { children, }) }, - NodeHeader::Leaf(nibble_count) => { + NodeHeader::HashedValueLeaf(nibble_count) | NodeHeader::Leaf(nibble_count) => { let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0; // check that the padding is valid (if any) if padding && nibble_ops::pad_left(data[input.offset]) != 0 { @@ -143,10 +162,16 @@ impl NodeCodecT for NodeCodec { nibble_ops::NIBBLE_PER_BYTE, )?; let partial_padding = nibble_ops::number_padding(nibble_count); - let count = >::decode(&mut input)?.0 as usize; + let value = if contains_hash { + ValuePlan::Node(input.take(H::LENGTH)?) + } else { + let count = >::decode(&mut input)?.0 as usize; + ValuePlan::Inline(input.take(count)?) + }; + Ok(NodePlan::Leaf { partial: NibbleSlicePlan::new(partial, partial_padding), - value: input.take(count)?, + value, }) }, } @@ -160,9 +185,23 @@ impl NodeCodecT for NodeCodec { &[trie_constants::EMPTY_TRIE] } - fn leaf_node(partial: Partial, value: &[u8]) -> Vec { - let mut output = partial_encode(partial, NodeKind::Leaf); - value.encode_to(&mut output); + fn leaf_node(partial: Partial, value: Value) -> Vec { + let contains_hash = matches!(&value, Value::Node(..)); + let mut output = if contains_hash { + partial_encode(partial, NodeKind::HashedValueLeaf) + } else { + partial_encode(partial, NodeKind::Leaf) + }; + match value { + Value::Inline(value) => { + Compact(value.len() as u32).encode_to(&mut output); + output.extend_from_slice(value); + }, + Value::Node(hash, _) => { + debug_assert!(hash.len() == H::LENGTH); + output.extend_from_slice(hash); + }, + } output } @@ -171,33 +210,46 @@ impl NodeCodecT for NodeCodec { _nbnibble: usize, _child: ChildReference<::Out>, ) -> Vec { - unreachable!() + unreachable!("No extension codec.") } fn branch_node( _children: impl Iterator::Out>>>>, - _maybe_value: Option<&[u8]>, + _maybe_value: Option, ) -> Vec { - unreachable!() + unreachable!("No extension codec.") } fn branch_node_nibbled( partial: impl Iterator, number_nibble: usize, children: impl Iterator::Out>>>>, - maybe_value: Option<&[u8]>, + value: Option, ) -> Vec { - let mut output = if maybe_value.is_some() { - partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchWithValue) - } else { - partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchNoValue) + let contains_hash = matches!(&value, Some(Value::Node(..))); + let mut output = match (&value, contains_hash) { + (&None, _) => + partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchNoValue), + (_, false) => + partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchWithValue), + (_, true) => + partial_from_iterator_encode(partial, number_nibble, NodeKind::HashedValueBranch), }; + let bitmap_index = output.len(); let mut bitmap: [u8; BITMAP_LENGTH] = [0; BITMAP_LENGTH]; (0..BITMAP_LENGTH).for_each(|_| output.push(0)); - if let Some(value) = maybe_value { - value.encode_to(&mut output); - }; + match value { + Some(Value::Inline(value)) => { + Compact(value.len() as u32).encode_to(&mut output); + output.extend_from_slice(value); + }, + Some(Value::Node(hash, _)) => { + debug_assert!(hash.len() == H::LENGTH); + output.extend_from_slice(hash); + }, + None => (), + } Bitmap::encode( children.map(|maybe_child| match maybe_child.borrow() { Some(ChildReference::Hash(h)) => { @@ -229,11 +281,15 @@ fn partial_from_iterator_encode>( ) -> Vec { let nibble_count = sp_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibble_count); - let mut output = Vec::with_capacity(3 + (nibble_count / nibble_ops::NIBBLE_PER_BYTE)); + let mut output = Vec::with_capacity(4 + (nibble_count / nibble_ops::NIBBLE_PER_BYTE)); match node_kind { NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output), NodeKind::BranchWithValue => NodeHeader::Branch(true, nibble_count).encode_to(&mut output), NodeKind::BranchNoValue => NodeHeader::Branch(false, nibble_count).encode_to(&mut output), + NodeKind::HashedValueLeaf => + NodeHeader::HashedValueLeaf(nibble_count).encode_to(&mut output), + NodeKind::HashedValueBranch => + NodeHeader::HashedValueBranch(nibble_count).encode_to(&mut output), }; output.extend(partial); output @@ -247,11 +303,15 @@ fn partial_encode(partial: Partial, node_kind: NodeKind) -> Vec { let nibble_count = sp_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibble_count); - let mut output = Vec::with_capacity(3 + partial.1.len()); + let mut output = Vec::with_capacity(4 + partial.1.len()); match node_kind { NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output), NodeKind::BranchWithValue => NodeHeader::Branch(true, nibble_count).encode_to(&mut output), NodeKind::BranchNoValue => NodeHeader::Branch(false, nibble_count).encode_to(&mut output), + NodeKind::HashedValueLeaf => + NodeHeader::HashedValueLeaf(nibble_count).encode_to(&mut output), + NodeKind::HashedValueBranch => + NodeHeader::HashedValueBranch(nibble_count).encode_to(&mut output), }; if number_nibble_encoded > 0 { output.push(nibble_ops::pad_right((partial.0).1)); diff --git a/primitives/trie/src/node_header.rs b/primitives/trie/src/node_header.rs index 9f05113a35935..895713ffd1f8d 100644 --- a/primitives/trie/src/node_header.rs +++ b/primitives/trie/src/node_header.rs @@ -25,8 +25,20 @@ use sp_std::iter::once; #[derive(Copy, Clone, PartialEq, Eq, sp_core::RuntimeDebug)] pub(crate) enum NodeHeader { Null, + // contains wether there is a value and nibble count Branch(bool, usize), + // contains nibble count Leaf(usize), + // contains nibble count. + HashedValueBranch(usize), + // contains nibble count. + HashedValueLeaf(usize), +} + +impl NodeHeader { + pub(crate) fn contains_hash_of_value(&self) -> bool { + matches!(self, NodeHeader::HashedValueBranch(_) | NodeHeader::HashedValueLeaf(_)) + } } /// NodeHeader without content @@ -34,6 +46,8 @@ pub(crate) enum NodeKind { Leaf, BranchNoValue, BranchWithValue, + HashedValueLeaf, + HashedValueBranch, } impl Encode for NodeHeader { @@ -41,11 +55,27 @@ impl Encode for NodeHeader { match self { NodeHeader::Null => output.push_byte(trie_constants::EMPTY_TRIE), NodeHeader::Branch(true, nibble_count) => - encode_size_and_prefix(*nibble_count, trie_constants::BRANCH_WITH_MASK, output), - NodeHeader::Branch(false, nibble_count) => - encode_size_and_prefix(*nibble_count, trie_constants::BRANCH_WITHOUT_MASK, output), + encode_size_and_prefix(*nibble_count, trie_constants::BRANCH_WITH_MASK, 2, output), + NodeHeader::Branch(false, nibble_count) => encode_size_and_prefix( + *nibble_count, + trie_constants::BRANCH_WITHOUT_MASK, + 2, + output, + ), NodeHeader::Leaf(nibble_count) => - encode_size_and_prefix(*nibble_count, trie_constants::LEAF_PREFIX_MASK, output), + encode_size_and_prefix(*nibble_count, trie_constants::LEAF_PREFIX_MASK, 2, output), + NodeHeader::HashedValueBranch(nibble_count) => encode_size_and_prefix( + *nibble_count, + trie_constants::ALT_HASHING_BRANCH_WITH_MASK, + 4, + output, + ), + NodeHeader::HashedValueLeaf(nibble_count) => encode_size_and_prefix( + *nibble_count, + trie_constants::ALT_HASHING_LEAF_PREFIX_MASK, + 3, + output, + ), } } } @@ -59,13 +89,22 @@ impl Decode for NodeHeader { return Ok(NodeHeader::Null) } match i & (0b11 << 6) { - trie_constants::LEAF_PREFIX_MASK => Ok(NodeHeader::Leaf(decode_size(i, input)?)), - trie_constants::BRANCH_WITHOUT_MASK => - Ok(NodeHeader::Branch(false, decode_size(i, input)?)), + trie_constants::LEAF_PREFIX_MASK => Ok(NodeHeader::Leaf(decode_size(i, input, 2)?)), trie_constants::BRANCH_WITH_MASK => - Ok(NodeHeader::Branch(true, decode_size(i, input)?)), - // do not allow any special encoding - _ => Err("Unallowed encoding".into()), + Ok(NodeHeader::Branch(true, decode_size(i, input, 2)?)), + trie_constants::BRANCH_WITHOUT_MASK => + Ok(NodeHeader::Branch(false, decode_size(i, input, 2)?)), + trie_constants::EMPTY_TRIE => { + if i & (0b111 << 5) == trie_constants::ALT_HASHING_LEAF_PREFIX_MASK { + Ok(NodeHeader::HashedValueLeaf(decode_size(i, input, 3)?)) + } else if i & (0b1111 << 4) == trie_constants::ALT_HASHING_BRANCH_WITH_MASK { + Ok(NodeHeader::HashedValueBranch(decode_size(i, input, 4)?)) + } else { + // do not allow any special encoding + Err("Unallowed encoding".into()) + } + }, + _ => unreachable!(), } } } @@ -73,12 +112,20 @@ impl Decode for NodeHeader { /// Returns an iterator over encoded bytes for node header and size. /// Size encoding allows unlimited, length inefficient, representation, but /// is bounded to 16 bit maximum value to avoid possible DOS. -pub(crate) fn size_and_prefix_iterator(size: usize, prefix: u8) -> impl Iterator { +pub(crate) fn size_and_prefix_iterator( + size: usize, + prefix: u8, + prefix_mask: usize, +) -> impl Iterator { let size = sp_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, size); - let l1 = sp_std::cmp::min(62, size); - let (first_byte, mut rem) = - if size == l1 { (once(prefix + l1 as u8), 0) } else { (once(prefix + 63), size - l1) }; + let max_value = 255u8 >> prefix_mask; + let l1 = sp_std::cmp::min((max_value as usize).saturating_sub(1), size); + let (first_byte, mut rem) = if size == l1 { + (once(prefix + l1 as u8), 0) + } else { + (once(prefix + max_value as u8), size - l1) + }; let next_bytes = move || { if rem > 0 { if rem < 256 { @@ -97,16 +144,24 @@ pub(crate) fn size_and_prefix_iterator(size: usize, prefix: u8) -> impl Iterator } /// Encodes size and prefix to a stream output. -fn encode_size_and_prefix(size: usize, prefix: u8, out: &mut W) { - for b in size_and_prefix_iterator(size, prefix) { +fn encode_size_and_prefix(size: usize, prefix: u8, prefix_mask: usize, out: &mut W) +where + W: Output + ?Sized, +{ + for b in size_and_prefix_iterator(size, prefix, prefix_mask) { out.push_byte(b) } } /// Decode size only from stream input and header byte. -fn decode_size(first: u8, input: &mut impl Input) -> Result { - let mut result = (first & 255u8 >> 2) as usize; - if result < 63 { +fn decode_size( + first: u8, + input: &mut impl Input, + prefix_mask: usize, +) -> Result { + let max_value = 255u8 >> prefix_mask; + let mut result = (first & max_value) as usize; + if result < max_value as usize { return Ok(result) } result -= 1; diff --git a/primitives/trie/src/storage_proof.rs b/primitives/trie/src/storage_proof.rs index 91f2159f2957e..cd65fa5b26f2f 100644 --- a/primitives/trie/src/storage_proof.rs +++ b/primitives/trie/src/storage_proof.rs @@ -19,6 +19,9 @@ use codec::{Decode, Encode}; use hash_db::{HashDB, Hasher}; use scale_info::TypeInfo; use sp_std::vec::Vec; +// Note that `LayoutV1` usage here (proof compaction) is compatible +// with `LayoutV0`. +use crate::LayoutV1 as Layout; /// A proof that some set of key-value pairs are included in the storage trie. The proof contains /// the storage values so that the partial storage backend can be reconstructed by a verifier that @@ -95,8 +98,8 @@ impl StorageProof { pub fn into_compact_proof( self, root: H::Out, - ) -> Result>> { - crate::encode_compact::>(self, root) + ) -> Result>> { + crate::encode_compact::>(self, root) } /// Returns the estimated encoded size of the compact proof. @@ -124,9 +127,9 @@ impl CompactProof { pub fn to_storage_proof( &self, expected_root: Option<&H::Out>, - ) -> Result<(StorageProof, H::Out), crate::CompactProofError>> { + ) -> Result<(StorageProof, H::Out), crate::CompactProofError>> { let mut db = crate::MemoryDB::::new(&[]); - let root = crate::decode_compact::, _, _>( + let root = crate::decode_compact::, _, _>( &mut db, self.iter_compact_encoded_nodes(), expected_root, diff --git a/primitives/trie/src/trie_codec.rs b/primitives/trie/src/trie_codec.rs index 1596229f2b5de..f485ee13e3329 100644 --- a/primitives/trie/src/trie_codec.rs +++ b/primitives/trie/src/trie_codec.rs @@ -112,8 +112,7 @@ where I: IntoIterator, { let mut nodes_iter = encoded.into_iter(); - let (top_root, _nb_used) = - trie_db::decode_compact_from_iter::(db, &mut nodes_iter)?; + let (top_root, _nb_used) = trie_db::decode_compact_from_iter::(db, &mut nodes_iter)?; // Only check root if expected root is passed as argument. if let Some(expected_root) = expected_root { @@ -164,8 +163,7 @@ where let mut nodes_iter = nodes_iter.peekable(); for child_root in child_tries.into_iter() { if previous_extracted_child_trie.is_none() && nodes_iter.peek().is_some() { - let (top_root, _) = - trie_db::decode_compact_from_iter::(db, &mut nodes_iter)?; + let (top_root, _) = trie_db::decode_compact_from_iter::(db, &mut nodes_iter)?; previous_extracted_child_trie = Some(top_root); } diff --git a/primitives/trie/src/trie_stream.rs b/primitives/trie/src/trie_stream.rs index e0e26fea67c2e..20f607c840d32 100644 --- a/primitives/trie/src/trie_stream.rs +++ b/primitives/trie/src/trie_stream.rs @@ -18,21 +18,18 @@ //! `TrieStream` implementation for Substrate's trie format. use crate::{ - node_codec::Bitmap, node_header::{size_and_prefix_iterator, NodeKind}, trie_constants, }; -use codec::Encode; +use codec::{Compact, Encode}; use hash_db::Hasher; use sp_std::vec::Vec; use trie_root; -const BRANCH_NODE_NO_VALUE: u8 = 254; -const BRANCH_NODE_WITH_VALUE: u8 = 255; - #[derive(Default, Clone)] /// Codec-flavored TrieStream. pub struct TrieStream { + /// Current node buffer. buffer: Vec, } @@ -60,51 +57,76 @@ fn fuse_nibbles_node<'a>(nibbles: &'a [u8], kind: NodeKind) -> impl Iterator size_and_prefix_iterator(size, trie_constants::LEAF_PREFIX_MASK), + NodeKind::Leaf => size_and_prefix_iterator(size, trie_constants::LEAF_PREFIX_MASK, 2), NodeKind::BranchNoValue => - size_and_prefix_iterator(size, trie_constants::BRANCH_WITHOUT_MASK), + size_and_prefix_iterator(size, trie_constants::BRANCH_WITHOUT_MASK, 2), NodeKind::BranchWithValue => - size_and_prefix_iterator(size, trie_constants::BRANCH_WITH_MASK), + size_and_prefix_iterator(size, trie_constants::BRANCH_WITH_MASK, 2), + NodeKind::HashedValueLeaf => + size_and_prefix_iterator(size, trie_constants::ALT_HASHING_LEAF_PREFIX_MASK, 3), + NodeKind::HashedValueBranch => + size_and_prefix_iterator(size, trie_constants::ALT_HASHING_BRANCH_WITH_MASK, 4), }; iter_start .chain(if nibbles.len() % 2 == 1 { Some(nibbles[0]) } else { None }) .chain(nibbles[nibbles.len() % 2..].chunks(2).map(|ch| ch[0] << 4 | ch[1])) } +use trie_root::Value as TrieStreamValue; impl trie_root::TrieStream for TrieStream { fn new() -> Self { - TrieStream { buffer: Vec::new() } + Self { buffer: Vec::new() } } fn append_empty_data(&mut self) { self.buffer.push(trie_constants::EMPTY_TRIE); } - fn append_leaf(&mut self, key: &[u8], value: &[u8]) { - self.buffer.extend(fuse_nibbles_node(key, NodeKind::Leaf)); - value.encode_to(&mut self.buffer); + fn append_leaf(&mut self, key: &[u8], value: TrieStreamValue) { + let kind = match &value { + TrieStreamValue::Inline(..) => NodeKind::Leaf, + TrieStreamValue::Node(..) => NodeKind::HashedValueLeaf, + }; + self.buffer.extend(fuse_nibbles_node(key, kind)); + match &value { + TrieStreamValue::Inline(value) => { + Compact(value.len() as u32).encode_to(&mut self.buffer); + self.buffer.extend_from_slice(value); + }, + TrieStreamValue::Node(hash) => { + self.buffer.extend_from_slice(hash.as_slice()); + }, + }; } fn begin_branch( &mut self, maybe_partial: Option<&[u8]>, - maybe_value: Option<&[u8]>, + maybe_value: Option, has_children: impl Iterator, ) { if let Some(partial) = maybe_partial { - if maybe_value.is_some() { - self.buffer.extend(fuse_nibbles_node(partial, NodeKind::BranchWithValue)); - } else { - self.buffer.extend(fuse_nibbles_node(partial, NodeKind::BranchNoValue)); - } + let kind = match &maybe_value { + None => NodeKind::BranchNoValue, + Some(TrieStreamValue::Inline(..)) => NodeKind::BranchWithValue, + Some(TrieStreamValue::Node(..)) => NodeKind::HashedValueBranch, + }; + + self.buffer.extend(fuse_nibbles_node(partial, kind)); let bm = branch_node_bit_mask(has_children); self.buffer.extend([bm.0, bm.1].iter()); } else { - debug_assert!(false, "trie stream codec only for no extension trie"); - self.buffer.extend(&branch_node(maybe_value.is_some(), has_children)); + unreachable!("trie stream codec only for no extension trie"); } - if let Some(value) = maybe_value { - value.encode_to(&mut self.buffer); + match maybe_value { + None => (), + Some(TrieStreamValue::Inline(value)) => { + Compact(value.len() as u32).encode_to(&mut self.buffer); + self.buffer.extend_from_slice(value); + }, + Some(TrieStreamValue::Node(hash)) => { + self.buffer.extend_from_slice(hash.as_slice()); + }, } } @@ -124,18 +146,3 @@ impl trie_root::TrieStream for TrieStream { self.buffer } } - -fn branch_node(has_value: bool, has_children: impl Iterator) -> [u8; 3] { - let mut result = [0, 0, 0]; - branch_node_buffered(has_value, has_children, &mut result[..]); - result -} - -fn branch_node_buffered(has_value: bool, has_children: I, output: &mut [u8]) -where - I: Iterator, -{ - let first = if has_value { BRANCH_NODE_WITH_VALUE } else { BRANCH_NODE_NO_VALUE }; - output[0] = first; - Bitmap::encode(has_children, &mut output[1..]); -} diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 585d089a54b5c..7fb55295088ea 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -22,6 +22,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" } parity-wasm = { version = "0.42.2", optional = true } +sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../core/hashing/proc-macro" } thiserror = { version = "1.0.30", optional = true } [features] diff --git a/primitives/version/proc-macro/src/decl_runtime_version.rs b/primitives/version/proc-macro/src/decl_runtime_version.rs index eef6314be4c81..7fcb716bbf607 100644 --- a/primitives/version/proc-macro/src/decl_runtime_version.rs +++ b/primitives/version/proc-macro/src/decl_runtime_version.rs @@ -63,6 +63,7 @@ struct RuntimeVersion { impl_version: u32, apis: u8, transaction_version: u32, + state_version: u8, } #[derive(Default, Debug)] @@ -73,6 +74,7 @@ struct ParseRuntimeVersion { spec_version: Option, impl_version: Option, transaction_version: Option, + state_version: Option, } impl ParseRuntimeVersion { @@ -122,6 +124,8 @@ impl ParseRuntimeVersion { parse_once(&mut self.impl_version, field_value, Self::parse_num_literal)?; } else if field_name == "transaction_version" { parse_once(&mut self.transaction_version, field_value, Self::parse_num_literal)?; + } else if field_name == "state_version" { + parse_once(&mut self.state_version, field_value, Self::parse_num_literal_u8)?; } else if field_name == "apis" { // Intentionally ignored // @@ -147,6 +151,18 @@ impl ParseRuntimeVersion { lit.base10_parse::() } + fn parse_num_literal_u8(expr: &Expr) -> Result { + let lit = match *expr { + Expr::Lit(ExprLit { lit: Lit::Int(ref lit), .. }) => lit, + _ => + return Err(Error::new( + expr.span(), + "only numeric literals (e.g. `10`) are supported here", + )), + }; + lit.base10_parse::() + } + fn parse_str_literal(expr: &Expr) -> Result { let mac = match *expr { Expr::Macro(syn::ExprMacro { ref mac, .. }) => mac, @@ -182,6 +198,7 @@ impl ParseRuntimeVersion { spec_version, impl_version, transaction_version, + state_version, } = self; Ok(RuntimeVersion { @@ -191,6 +208,7 @@ impl ParseRuntimeVersion { spec_version: required!(spec_version), impl_version: required!(impl_version), transaction_version: required!(transaction_version), + state_version: required!(state_version), apis: 0, }) } @@ -210,7 +228,6 @@ fn generate_emit_link_section_decl(contents: &[u8], section_name: &str) -> Token #[cfg(test)] mod tests { use super::*; - use codec::DecodeAll; use std::borrow::Cow; #[test] @@ -223,11 +240,13 @@ mod tests { impl_version: 1, apis: 0, transaction_version: 2, + state_version: 1, } .encode(); assert_eq!( - sp_version::RuntimeVersion::decode_all(&mut &version_bytes[..]).unwrap(), + sp_version::RuntimeVersion::decode_with_version_hint(&mut &version_bytes[..], Some(4)) + .unwrap(), sp_version::RuntimeVersion { spec_name: "hello".into(), impl_name: "world".into(), @@ -236,6 +255,7 @@ mod tests { impl_version: 1, apis: Cow::Owned(vec![]), transaction_version: 2, + state_version: 1, }, ); } diff --git a/primitives/version/src/lib.rs b/primitives/version/src/lib.rs index 0b72865e7b690..74251aa4320fb 100644 --- a/primitives/version/src/lib.rs +++ b/primitives/version/src/lib.rs @@ -40,10 +40,10 @@ use std::collections::HashSet; #[cfg(feature = "std")] use std::fmt; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, Input}; use scale_info::TypeInfo; -pub use sp_runtime::create_runtime_str; use sp_runtime::RuntimeString; +pub use sp_runtime::{create_runtime_str, StateVersion}; #[doc(hidden)] pub use sp_std; @@ -79,6 +79,7 @@ pub mod embed; /// impl_version: 1, /// apis: RUNTIME_API_VERSIONS, /// transaction_version: 2, +/// state_version: 1, /// }; /// /// # const RUNTIME_API_VERSIONS: sp_version::ApisVec = sp_version::create_apis_vec!([]); @@ -154,7 +155,7 @@ macro_rules! create_apis_vec { /// In particular: bug fixes should result in an increment of `spec_version` and possibly /// `authoring_version`, absolutely not `impl_version` since they change the semantics of the /// runtime. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Default, sp_runtime::RuntimeDebug, TypeInfo)] +#[derive(Clone, PartialEq, Eq, Encode, Default, sp_runtime::RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct RuntimeVersion { @@ -207,6 +208,53 @@ pub struct RuntimeVersion { /// /// It need *not* change when a new module is added or when a dispatchable is added. pub transaction_version: u32, + + /// Version of the state implementation used by this runtime. + /// Use of an incorrect version is consensus breaking. + pub state_version: u8, +} + +impl RuntimeVersion { + /// `Decode` while giving a "version hint" + /// + /// There exists multiple versions of [`RuntimeVersion`] and they are versioned using the `Core` + /// runtime api: + /// - `Core` version < 3 is a runtime version without a transaction version and state version. + /// - `Core` version 3 is a runtime version without a state version. + /// - `Core` version 4 is the latest runtime version. + pub fn decode_with_version_hint( + input: &mut I, + core_version: Option, + ) -> Result { + let spec_name = Decode::decode(input)?; + let impl_name = Decode::decode(input)?; + let authoring_version = Decode::decode(input)?; + let spec_version = Decode::decode(input)?; + let impl_version = Decode::decode(input)?; + let apis = Decode::decode(input)?; + let core_version = + if core_version.is_some() { core_version } else { core_version_from_apis(&apis) }; + let transaction_version = + if core_version.map(|v| v >= 3).unwrap_or(false) { Decode::decode(input)? } else { 1 }; + let state_version = + if core_version.map(|v| v >= 4).unwrap_or(false) { Decode::decode(input)? } else { 0 }; + Ok(RuntimeVersion { + spec_name, + impl_name, + authoring_version, + spec_version, + impl_version, + apis, + transaction_version, + state_version, + }) + } +} + +impl Decode for RuntimeVersion { + fn decode(input: &mut I) -> Result { + Self::decode_with_version_hint(input, None) + } } #[cfg(feature = "std")] @@ -225,6 +273,16 @@ impl fmt::Display for RuntimeVersion { } } +fn has_api_with bool>(apis: &ApisVec, id: &ApiId, predicate: P) -> bool { + apis.iter().any(|(s, v)| s == id && predicate(*v)) +} + +/// Returns the version of the `Core` runtime api. +pub fn core_version_from_apis(apis: &ApisVec) -> Option { + let id = sp_core_hashing_proc_macro::blake2b_64!(b"Core"); + apis.iter().find(|(s, _v)| s == &id).map(|(_s, v)| *v) +} + #[cfg(feature = "std")] impl RuntimeVersion { /// Check if this version matches other version for calling into runtime. @@ -237,7 +295,7 @@ impl RuntimeVersion { /// Check if the given api with `api_id` is implemented and the version passes the given /// `predicate`. pub fn has_api_with bool>(&self, id: &ApiId, predicate: P) -> bool { - self.apis.iter().any(|(s, v)| s == id && predicate(*v)) + has_api_with(&self.apis, id, predicate) } /// Returns the api version found for api with `id`. @@ -246,6 +304,18 @@ impl RuntimeVersion { } } +impl RuntimeVersion { + /// Returns state version to use for update. + /// + /// For runtime with core api version less than 4, + /// V0 trie version will be applied to state. + /// Otherwhise, V1 trie version will be use. + pub fn state_version(&self) -> StateVersion { + // If version > than 1, keep using latest version. + self.state_version.try_into().unwrap_or(StateVersion::V1) + } +} + /// The version of the native runtime. /// /// In contrast to the bare [`RuntimeVersion`] this also carries a list of `spec_version`s of diff --git a/test-utils/client/src/client_ext.rs b/test-utils/client/src/client_ext.rs index bf1c9898972ca..72828fdcc9188 100644 --- a/test-utils/client/src/client_ext.rs +++ b/test-utils/client/src/client_ext.rs @@ -69,7 +69,7 @@ pub trait ClientBlockImportExt: Sized { impl ClientExt for Client where B: sc_client_api::backend::Backend, - E: sc_client_api::CallExecutor + 'static, + E: sc_client_api::CallExecutor + sc_executor::RuntimeVersionOf + 'static, Self: BlockImport, Block: BlockT, { diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 86231bb34c506..6ba28d8c124f2 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -208,13 +208,13 @@ impl sc_consensus::LongestChain, ) where - ExecutorDispatch: sc_client_api::CallExecutor + 'static, + ExecutorDispatch: + sc_client_api::CallExecutor + sc_executor::RuntimeVersionOf + 'static, Backend: sc_client_api::backend::Backend, >::OffchainStorage: 'static, { let storage = { let mut storage = self.genesis_init.genesis_storage(); - // Add some child storage keys. for (key, child_content) in self.child_storage_extension { storage.children_default.insert( diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 35c1291f38fb5..c32586834f30b 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -39,7 +39,7 @@ pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = ".. sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } sp-trie = { version = "4.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } -trie-db = { version = "0.22.6", default-features = false } +trie-db = { version = "0.23.0", default-features = false } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } sp-state-machine = { version = "0.10.0", default-features = false, path = "../../primitives/state-machine" } diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index a5d1e1966e307..d5c8a4fcb8a46 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -138,6 +138,7 @@ impl substrate_test_client::GenesisInit for GenesisParameters { let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( child_content.data.clone().into_iter().collect(), + sp_runtime::StateVersion::V1, ); let prefixed_storage_key = child_content.child_info.prefixed_storage_key(); (prefixed_storage_key.into_inner(), state_root.encode()) @@ -145,6 +146,7 @@ impl substrate_test_client::GenesisInit for GenesisParameters { let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( storage.top.clone().into_iter().chain(child_roots).collect(), + sp_runtime::StateVersion::V1, ); let block: runtime::Block = client::genesis::construct_genesis_block(state_root); storage.top.extend(additional_storage_with_genesis(&block)); diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index a06d9f310fb04..b81ed91ca6df0 100644 --- a/test-utils/runtime/src/genesismap.rs +++ b/test-utils/runtime/src/genesismap.rs @@ -95,6 +95,7 @@ pub fn insert_genesis_block(storage: &mut Storage) -> sp_core::hash::H256 { let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( child_content.data.clone().into_iter().collect(), + sp_runtime::StateVersion::V1, ); (sk.clone(), state_root.encode()) }); @@ -102,6 +103,7 @@ pub fn insert_genesis_block(storage: &mut Storage) -> sp_core::hash::H256 { storage.top.extend(child_roots); let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( storage.top.clone().into_iter().collect(), + sp_runtime::StateVersion::V1, ); let block: crate::Block = genesis::construct_genesis_block(state_root); let genesis_hash = block.header.hash(); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 03e39be324e90..bf224b43946c7 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -29,10 +29,7 @@ use sp_std::{marker::PhantomData, prelude::*}; use sp_application_crypto::{ecdsa, ed25519, sr25519, RuntimeAppPublic}; use sp_core::{offchain::KeyTypeId, OpaqueMetadata, RuntimeDebug}; -use sp_trie::{ - trie_types::{TrieDB, TrieDBMut}, - PrefixedMemoryDB, StorageProof, -}; +use sp_trie::{trie_types::TrieDB, PrefixedMemoryDB, StorageProof}; use trie_db::{Trie, TrieMut}; use cfg_if::cfg_if; @@ -62,6 +59,8 @@ use sp_runtime::{ #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; +// bench on latest state. +use sp_trie::trie_types::TrieDBMutV1 as TrieDBMut; // Ensure Babe and Aura use the same crypto to simplify things a bit. pub use sp_consensus_babe::{AllowedSlots, AuthorityId, Slot}; @@ -105,6 +104,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 2, apis: RUNTIME_API_VERSIONS, transaction_version: 1, + state_version: 1, }; fn version() -> RuntimeVersion { @@ -1268,9 +1268,9 @@ fn test_witness(proof: StorageProof, root: crate::Hash) { None, ); assert!(ext.storage(b"value3").is_some()); - assert!(ext.storage_root().as_slice() == &root[..]); + assert!(ext.storage_root(Default::default()).as_slice() == &root[..]); ext.place_storage(vec![0], Some(vec![1])); - assert!(ext.storage_root().as_slice() != &root[..]); + assert!(ext.storage_root(Default::default()).as_slice() != &root[..]); } #[cfg(test)] @@ -1334,7 +1334,7 @@ mod tests { let mut root = crate::Hash::default(); let mut mdb = sp_trie::MemoryDB::::default(); { - let mut trie = sp_trie::trie_types::TrieDBMut::new(&mut mdb, &mut root); + let mut trie = sp_trie::trie_types::TrieDBMutV1::new(&mut mdb, &mut root); trie.insert(b"value3", &[142]).expect("insert failed"); trie.insert(b"value4", &[124]).expect("insert failed"); }; diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 0c72c083baae2..57eae0aecf04a 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -194,9 +194,10 @@ pub fn execute_transaction(utx: Extrinsic) -> ApplyExtrinsicResult { /// Finalize the block. pub fn finalize_block() -> Header { + use sp_core::storage::StateVersion; let extrinsic_index: u32 = storage::unhashed::take(well_known_keys::EXTRINSIC_INDEX).unwrap(); let txs: Vec<_> = (0..extrinsic_index).map(ExtrinsicData::take).collect(); - let extrinsics_root = trie::blake2_256_ordered_root(txs).into(); + let extrinsics_root = trie::blake2_256_ordered_root(txs, StateVersion::V0).into(); let number = ::take().expect("Number is set by `initialize_block`"); let parent_hash = ::take(); let mut digest = ::take().expect("StorageDigest is set by `initialize_block`"); @@ -205,8 +206,8 @@ pub fn finalize_block() -> Header { // This MUST come after all changes to storage are done. Otherwise we will fail the // “Storage root does not match that calculated” assertion. - let storage_root = - Hash::decode(&mut &storage_root()[..]).expect("`storage_root` is a valid hash"); + let storage_root = Hash::decode(&mut &storage_root(StateVersion::V1)[..]) + .expect("`storage_root` is a valid hash"); if let Some(new_authorities) = o_new_authorities { digest.push(generic::DigestItem::Consensus(*b"aura", new_authorities.encode())); @@ -351,6 +352,7 @@ mod tests { Sr25519Keyring::Bob.to_raw_public(), Sr25519Keyring::Charlie.to_raw_public(), ]; + TestExternalities::new_with_code( wasm_binary_unwrap(), sp_core::storage::Storage { @@ -359,7 +361,7 @@ mod tests { twox_128(b"sys:auth").to_vec() => authorities.encode(), blake2_256(&AccountKeyring::Alice.to_raw_public().to_keyed_vec(b"balance:")).to_vec() => { vec![111u8, 0, 0, 0, 0, 0, 0, 0] - } + }, ], children_default: map![], }, diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index a717b410c2bf4..f092f6eaf4716 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -157,7 +157,7 @@ where header.digest_mut().pop(); let block = Block::new(header, extrinsics); - let (expected_spec_name, expected_spec_version) = + let (expected_spec_name, expected_spec_version, _) = local_spec::(&ext, &executor); ensure_matching_spec::( block_ws_uri.clone(), diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index 09f541c887536..dbc1c3005f06a 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -123,7 +123,7 @@ where new_ext.as_backend().root() ); - let (expected_spec_name, expected_spec_version) = + let (expected_spec_name, expected_spec_version, spec_state_version) = local_spec::(&new_ext, &executor); ensure_matching_spec::( command.uri.clone(), @@ -133,10 +133,10 @@ where ) .await; - maybe_state_ext = Some(new_ext); + maybe_state_ext = Some((new_ext, spec_state_version)); } - let state_ext = + let (state_ext, spec_state_version) = maybe_state_ext.as_mut().expect("state_ext either existed or was just created"); let (mut changes, encoded_result) = state_machine_call_with_proof::( @@ -152,7 +152,16 @@ where .map_err(|e| format!("failed to decode output: {:?}", e))?; let storage_changes = changes - .drain_storage_changes(&state_ext.backend, Default::default(), &mut Default::default()) + .drain_storage_changes( + &state_ext.backend, + Default::default(), + &mut Default::default(), + // Note that in case a block contains a runtime upgrade, + // state version could potentially be incorrect here, + // this is very niche and would only result in unaligned + // roots, so this use case is ignored for now. + *spec_state_version, + ) .unwrap(); state_ext.backend.apply_transaction( storage_changes.transaction_storage_root, diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index 22120ef4b5fe4..8839c5556900e 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -140,7 +140,7 @@ where builder.build().await? }; - let (expected_spec_name, expected_spec_version) = + let (expected_spec_name, expected_spec_version, _) = local_spec::(&ext, &executor); ensure_matching_spec::( header_ws_uri, diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 6343b2b2e3f0d..3b5a3db72a8f1 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -58,7 +58,7 @@ where }; if let Some(uri) = command.state.live_uri() { - let (expected_spec_name, expected_spec_version) = + let (expected_spec_name, expected_spec_version, _) = local_spec::(&ext, &executor); ensure_matching_spec::( uri, diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 3872f84a62a4b..9f8af6906a351 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -799,7 +799,7 @@ pub(crate) fn state_machine_call_with_proof( ext: &TestExternalities, executor: &NativeElseWasmExecutor, -) -> (String, u32) { +) -> (String, u32, sp_core::storage::StateVersion) { let (_, encoded) = state_machine_call::( &ext, &executor, @@ -811,6 +811,9 @@ pub(crate) fn local_spec( .expect("all runtimes should have version; qed"); ::decode(&mut &*encoded) .map_err(|e| format!("failed to decode output: {:?}", e)) - .map(|v| (v.spec_name.into(), v.spec_version)) + .map(|v| { + let state_version = v.state_version(); + (v.spec_name.into(), v.spec_version, state_version) + }) .expect("all runtimes should have version; qed") } From 82d87bcd8829aa1ba40b831e5ea2cac1a5efbdee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 25 Dec 2021 08:19:46 +0100 Subject: [PATCH 0382/1472] Improve SS58 related errors (#10541) * Improve SS58 related errors This improves the SS58 error, especially when it comes to parsing public keys with unknown SS58 address formats. * Make CI happy * More fixes * More * :facepalm: * fml... --- primitives/core/src/crypto.rs | 58 +++++++++++++++++++++--------- primitives/core/src/ecdsa.rs | 65 ++++------------------------------ primitives/core/src/ed25519.rs | 36 ++----------------- primitives/core/src/sr25519.rs | 18 ++-------- 4 files changed, 52 insertions(+), 125 deletions(-) diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 671f526fde32c..e6735c7745cf6 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -198,25 +198,45 @@ impl> From for DeriveJunction { } /// An error type for SS58 decoding. +#[cfg_attr(feature = "std", derive(thiserror::Error))] +#[cfg_attr(not(feature = "std"), derive(Debug))] +#[derive(Clone, Copy, Eq, PartialEq)] +#[allow(missing_docs)] #[cfg(feature = "full_crypto")] -#[derive(Clone, Copy, Eq, PartialEq, Debug)] pub enum PublicError { - /// Bad alphabet. + #[cfg_attr(feature = "std", error("Base 58 requirement is violated"))] BadBase58, - /// Bad length. + #[cfg_attr(feature = "std", error("Length is bad"))] BadLength, - /// Unknown identifier for the encoding. - UnknownVersion, - /// Invalid checksum. + #[cfg_attr( + feature = "std", + error( + "Unknown SS58 address format `{}`. ` \ + `To support this address format, you need to call `set_default_ss58_version` at node start up.", + _0 + ) + )] + UnknownSs58AddressFormat(Ss58AddressFormat), + #[cfg_attr(feature = "std", error("Invalid checksum"))] InvalidChecksum, - /// Invalid format. + #[cfg_attr(feature = "std", error("Invalid SS58 prefix byte."))] + InvalidPrefix, + #[cfg_attr(feature = "std", error("Invalid SS58 format."))] InvalidFormat, - /// Invalid derivation path. + #[cfg_attr(feature = "std", error("Invalid derivation path."))] InvalidPath, - /// Disallowed SS58 Address Format for this datatype. + #[cfg_attr(feature = "std", error("Disallowed SS58 Address Format for this datatype."))] FormatNotAllowed, } +#[cfg(feature = "std")] +impl sp_std::fmt::Debug for PublicError { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + // Just use the `Display` implementation + write!(f, "{}", self) + } +} + /// Key that can be encoded to/from SS58. /// /// See @@ -235,7 +255,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray { Self::from_ss58check_with_version(s).and_then(|(r, v)| match v { v if !v.is_custom() => Ok(r), v if v == default_ss58_version() => Ok(r), - _ => Err(PublicError::UnknownVersion), + v => Err(PublicError::UnknownSs58AddressFormat(v)), }) } @@ -261,7 +281,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray { let upper = data[1] & 0b00111111; (2, (lower as u16) | ((upper as u16) << 8)) }, - _ => return Err(PublicError::UnknownVersion), + _ => return Err(PublicError::InvalidPrefix), }; if data.len() != prefix_len + body_len + CHECKSUM_LEN { return Err(PublicError::BadLength) @@ -290,7 +310,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray { Self::from_string_with_version(s).and_then(|(r, v)| match v { v if !v.is_custom() => Ok(r), v if v == default_ss58_version() => Ok(r), - _ => Err(PublicError::UnknownVersion), + v => Err(PublicError::UnknownSs58AddressFormat(v)), }) } @@ -359,7 +379,7 @@ static DEFAULT_VERSION: core::sync::atomic::AtomicU16 = std::sync::atomic::Atomi from_known_address_format(Ss58AddressFormatRegistry::SubstrateAccount), ); -/// Returns default ss58 format used by the current active process. +/// Returns default SS58 format used by the current active process. #[cfg(feature = "std")] pub fn default_ss58_version() -> Ss58AddressFormat { DEFAULT_VERSION.load(std::sync::atomic::Ordering::Relaxed).into() @@ -371,9 +391,15 @@ pub fn unwrap_or_default_ss58_version(network: Option) -> Ss5 network.unwrap_or_else(default_ss58_version) } -/// Set the default "version" (actually, this is a bit of a misnomer and the version byte is -/// typically used not just to encode format/version but also network identity) that is used for -/// encoding and decoding SS58 addresses. +/// Set the default SS58 "version". +/// +/// This SS58 version/format will be used when encoding/decoding SS58 addresses. +/// +/// If you want to support a custom SS58 prefix (that isn't yet registered in the `ss58-registry`), +/// you are required to call this function with your desired prefix [`Ss58AddressFormat::custom`]. +/// This will enable the node to decode ss58 addresses with this prefix. +/// +/// This SS58 version/format is also only used by the node and not by the runtime. #[cfg(feature = "std")] pub fn set_default_ss58_version(new_default: Ss58AddressFormat) { DEFAULT_VERSION.store(new_default.into(), std::sync::atomic::Ordering::Relaxed); diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 827be8eb9aabf..682f46c2a4327 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -22,7 +22,6 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime_interface::pass_by::PassByInner; -use sp_std::cmp::Ordering; #[cfg(feature = "std")] use crate::crypto::Ss58Codec; @@ -56,43 +55,12 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds"); type Seed = [u8; 32]; /// The ECDSA compressed public key. -#[derive(Clone, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "full_crypto", derive(Hash))] +#[derive( + Clone, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo, Eq, PartialEq, PartialOrd, Ord, +)] pub struct Public(pub [u8; 33]); -impl PartialOrd for Public { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Public { - fn cmp(&self, other: &Self) -> Ordering { - self.as_ref().cmp(&other.as_ref()) - } -} - -impl PartialEq for Public { - fn eq(&self, other: &Self) -> bool { - self.as_ref() == other.as_ref() - } -} - -impl Eq for Public {} - -/// An error type for SS58 decoding. -#[cfg(feature = "std")] -#[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub enum PublicError { - /// Bad alphabet. - BadBase58, - /// Bad length. - BadLength, - /// Unknown version. - UnknownVersion, - /// Invalid checksum. - InvalidChecksum, -} - impl Public { /// A new instance from the given 33-byte `data`. /// @@ -217,15 +185,9 @@ impl<'de> Deserialize<'de> for Public { } } -#[cfg(feature = "full_crypto")] -impl sp_std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.as_ref().hash(state); - } -} - /// A signature (a 512-bit value, plus 8 bits for recovery ID). -#[derive(Encode, Decode, PassByInner, TypeInfo)] +#[cfg_attr(feature = "full_crypto", derive(Hash))] +#[derive(Encode, Decode, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; 65]); impl sp_std::convert::TryFrom<&[u8]> for Signature { @@ -279,14 +241,6 @@ impl Default for Signature { } } -impl PartialEq for Signature { - fn eq(&self, b: &Self) -> bool { - self.0[..] == b.0[..] - } -} - -impl Eq for Signature {} - impl From for [u8; 65] { fn from(v: Signature) -> [u8; 65] { v.0 @@ -323,13 +277,6 @@ impl sp_std::fmt::Debug for Signature { } } -#[cfg(feature = "full_crypto")] -impl sp_std::hash::Hash for Signature { - fn hash(&self, state: &mut H) { - sp_std::hash::Hash::hash(&self.0[..], state); - } -} - impl UncheckedFrom<[u8; 65]> for Signature { fn unchecked_from(data: [u8; 65]) -> Signature { Signature(data) diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 7d60998b15dfc..df9ec6a457c62 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -211,7 +211,8 @@ impl<'de> Deserialize<'de> for Public { } /// A signature (a 512-bit value). -#[derive(Encode, Decode, PassByInner, TypeInfo)] +#[cfg_attr(feature = "full_crypto", derive(Hash))] +#[derive(Encode, Decode, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; 64]); impl sp_std::convert::TryFrom<&[u8]> for Signature { @@ -259,14 +260,6 @@ impl Clone for Signature { } } -impl PartialEq for Signature { - fn eq(&self, b: &Self) -> bool { - self.0[..] == b.0[..] - } -} - -impl Eq for Signature {} - impl From for H512 { fn from(v: Signature) -> H512 { H512::from(v.0) @@ -309,13 +302,6 @@ impl sp_std::fmt::Debug for Signature { } } -#[cfg(feature = "full_crypto")] -impl sp_std::hash::Hash for Signature { - fn hash(&self, state: &mut H) { - sp_std::hash::Hash::hash(&self.0[..], state); - } -} - impl UncheckedFrom<[u8; 64]> for Signature { fn unchecked_from(data: [u8; 64]) -> Signature { Signature(data) @@ -360,24 +346,6 @@ pub struct LocalizedSignature { pub signature: Signature, } -/// An error type for SS58 decoding. -#[cfg(feature = "std")] -#[derive(Clone, Copy, Eq, PartialEq, Debug, thiserror::Error)] -pub enum PublicError { - /// Bad alphabet. - #[error("Base 58 requirement is violated")] - BadBase58, - /// Bad length. - #[error("Length is bad")] - BadLength, - /// Unknown version. - #[error("Unknown version")] - UnknownVersion, - /// Invalid checksum. - #[error("Invalid checksum")] - InvalidChecksum, -} - impl Public { /// A new instance from the given 32-byte `data`. /// diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index 97e9de5de09a7..71379dfc66b92 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -211,7 +211,8 @@ impl<'de> Deserialize<'de> for Public { /// An Schnorrkel/Ristretto x25519 ("sr25519") signature. /// /// Instead of importing it for the local module, alias it to be available as a public type -#[derive(Encode, Decode, PassByInner, TypeInfo)] +#[cfg_attr(feature = "full_crypto", derive(Hash))] +#[derive(Encode, Decode, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; 64]); impl sp_std::convert::TryFrom<&[u8]> for Signature { @@ -259,14 +260,6 @@ impl Clone for Signature { } } -impl PartialEq for Signature { - fn eq(&self, b: &Self) -> bool { - self.0[..] == b.0[..] - } -} - -impl Eq for Signature {} - impl From for [u8; 64] { fn from(v: Signature) -> [u8; 64] { v.0 @@ -316,13 +309,6 @@ impl sp_std::fmt::Debug for Signature { } } -#[cfg(feature = "full_crypto")] -impl sp_std::hash::Hash for Signature { - fn hash(&self, state: &mut H) { - sp_std::hash::Hash::hash(&self.0[..], state); - } -} - /// A localized signature also contains sender information. /// NOTE: Encode and Decode traits are supported in ed25519 but not possible for now here. #[cfg(feature = "std")] From ba973636c86b8038ad0c8bfdbd4f4d496e86adaa Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Sun, 26 Dec 2021 16:48:51 +0200 Subject: [PATCH 0383/1472] Add beefy-gadget-rpc tests (#10555) * beefy: add RPC tests * beefy: add more RPC tests --- Cargo.lock | 2 + client/beefy/rpc/Cargo.toml | 8 +++ client/beefy/rpc/src/lib.rs | 132 ++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c6dd25ffd74aa..e58275738c929 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -516,8 +516,10 @@ dependencies = [ "parity-scale-codec", "sc-rpc", "serde", + "serde_json", "sp-core", "sp-runtime", + "substrate-test-runtime-client", ] [[package]] diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 847f054f4663e..c14d604990cbf 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -26,3 +26,11 @@ sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } beefy-gadget = { version = "4.0.0-dev", path = "../." } beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } + +[dev-dependencies] +serde_json = "1.0.50" + +sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ + "test-helpers", +] } +substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index c9a09525569b8..7370ca092727f 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -112,3 +112,135 @@ where Ok(self.manager.cancel(id)) } } + +#[cfg(test)] +mod tests { + use super::*; + use jsonrpc_core::{types::Params, Notification, Output}; + + use beefy_gadget::notification::{BeefySignedCommitmentSender, SignedCommitment}; + use beefy_primitives::{known_payload_ids, Payload}; + use codec::{Decode, Encode}; + use substrate_test_runtime_client::runtime::Block; + + fn setup_io_handler( + ) -> (jsonrpc_core::MetaIoHandler, BeefySignedCommitmentSender) { + let (commitment_sender, commitment_stream) = BeefySignedCommitmentStream::channel(); + + let handler = BeefyRpcHandler::new(commitment_stream, sc_rpc::testing::TaskExecutor); + + let mut io = jsonrpc_core::MetaIoHandler::default(); + io.extend_with(BeefyApi::to_delegate(handler)); + + (io, commitment_sender) + } + + fn setup_session() -> (sc_rpc::Metadata, futures::channel::mpsc::UnboundedReceiver) { + let (tx, rx) = futures::channel::mpsc::unbounded(); + let meta = sc_rpc::Metadata::new(tx); + (meta, rx) + } + + #[test] + fn subscribe_and_unsubscribe_to_justifications() { + let (io, _) = setup_io_handler(); + let (meta, _) = setup_session(); + + // Subscribe + let sub_request = + r#"{"jsonrpc":"2.0","method":"beefy_subscribeJustifications","params":[],"id":1}"#; + let resp = io.handle_request_sync(sub_request, meta.clone()); + let resp: Output = serde_json::from_str(&resp.unwrap()).unwrap(); + + let sub_id = match resp { + Output::Success(success) => success.result, + _ => panic!(), + }; + + // Unsubscribe + let unsub_req = format!( + "{{\"jsonrpc\":\"2.0\",\"method\":\"beefy_unsubscribeJustifications\",\"params\":[{}],\"id\":1}}", + sub_id + ); + assert_eq!( + io.handle_request_sync(&unsub_req, meta.clone()), + Some(r#"{"jsonrpc":"2.0","result":true,"id":1}"#.into()), + ); + + // Unsubscribe again and fail + assert_eq!( + io.handle_request_sync(&unsub_req, meta), + Some("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32602,\"message\":\"Invalid subscription id.\"},\"id\":1}".into()), + ); + } + + #[test] + fn subscribe_and_unsubscribe_with_wrong_id() { + let (io, _) = setup_io_handler(); + let (meta, _) = setup_session(); + + // Subscribe + let sub_request = + r#"{"jsonrpc":"2.0","method":"beefy_subscribeJustifications","params":[],"id":1}"#; + let resp = io.handle_request_sync(sub_request, meta.clone()); + let resp: Output = serde_json::from_str(&resp.unwrap()).unwrap(); + assert!(matches!(resp, Output::Success(_))); + + // Unsubscribe with wrong ID + assert_eq!( + io.handle_request_sync( + r#"{"jsonrpc":"2.0","method":"beefy_unsubscribeJustifications","params":["FOO"],"id":1}"#, + meta.clone() + ), + Some("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32602,\"message\":\"Invalid subscription id.\"},\"id\":1}".into()) + ); + } + + fn create_commitment() -> SignedCommitment { + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + SignedCommitment:: { + commitment: beefy_primitives::Commitment { + payload, + block_number: 5, + validator_set_id: 0, + }, + signatures: vec![], + } + } + + #[test] + fn subscribe_and_listen_to_one_justification() { + let (io, commitment_sender) = setup_io_handler(); + let (meta, receiver) = setup_session(); + + // Subscribe + let sub_request = + r#"{"jsonrpc":"2.0","method":"beefy_subscribeJustifications","params":[],"id":1}"#; + + let resp = io.handle_request_sync(sub_request, meta.clone()); + let mut resp: serde_json::Value = serde_json::from_str(&resp.unwrap()).unwrap(); + let sub_id: String = serde_json::from_value(resp["result"].take()).unwrap(); + + // Notify with commitment + let commitment = create_commitment(); + commitment_sender.notify(commitment.clone()); + + // Inspect what we received + let recv = futures::executor::block_on(receiver.take(1).collect::>()); + let recv: Notification = serde_json::from_str(&recv[0]).unwrap(); + let mut json_map = match recv.params { + Params::Map(json_map) => json_map, + _ => panic!(), + }; + + let recv_sub_id: String = serde_json::from_value(json_map["subscription"].take()).unwrap(); + let recv_commitment: sp_core::Bytes = + serde_json::from_value(json_map["result"].take()).unwrap(); + let recv_commitment: SignedCommitment = + Decode::decode(&mut &recv_commitment[..]).unwrap(); + + assert_eq!(recv.method, "beefy_justifications"); + assert_eq!(recv_sub_id, sub_id); + assert_eq!(recv_commitment, commitment); + } +} From a1fc5cff2ad979697384b24dd52671ccba0bf128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Mon, 27 Dec 2021 06:21:33 -0300 Subject: [PATCH 0384/1472] make check-dependent-* only be executed in PRs (#10545) Make check-dependent-* jobs only be executed in PRs instead of both PRs and master. Reason 1: The companion is not merged at the same time as the parent PR ([1](https://github.com/paritytech/parity-processbot/issues/347#issuecomment-994729950)), therefore the pipeline will fail on master since the companion PR is not yet merged in the other repository. This scenario is demonstrated by the pipeline of https://github.com/paritytech/substrate/commit/82cc3746450ae9722a249f4ddf83b8de59ba6e0d. Reason 2: The job can still fail on master due to a new commit on the companion PR's repository which was merged after `bot merge` happened, as demonstrated by the following scheme: 1. Parent PR is merged 2. Companion PR is updated and set to merge in the future 3. In the meantime a new commit is merged into the companion PR repository's master branch 4. The `check-dependent-*` job runs on master but, due to the new commit, it fails for unrelated reasons While "Reason 2" can be used as an argument against this PR, in that it would be useful to know if the integration is failing on master, "Reason 1" should be taken care of due to this inherent flaw of the current companion build system design. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 589adeec5260d..685d201d85983 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -575,7 +575,7 @@ cargo-check-macos: .check-dependent-project: &check-dependent-project stage: build <<: *docker-env - <<: *test-refs-no-trigger + <<: *test-refs-no-trigger-prs-only <<: *vault-secrets script: - git clone From e19dfaab053ed1d5ecf19bc25b004ec1fc2ba6c3 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 28 Dec 2021 23:22:48 +0000 Subject: [PATCH 0385/1472] Tweak to pallet-nicks (#10565) * Slightly easier for humans to parse * cargo fmt * Use the simpler format for construct_runtime. --- frame/nicks/src/lib.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 91918ce846002..6d9c15fd3da16 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -43,11 +43,10 @@ pub use pallet::*; use sp_runtime::traits::{StaticLookup, Zero}; use sp_std::prelude::*; -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; -type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, ->>::NegativeImbalance; +type AccountIdOf = ::AccountId; +type BalanceOf = <::Currency as Currency>>::Balance; +type NegativeImbalanceOf = + <::Currency as Currency>>::NegativeImbalance; #[frame_support::pallet] pub mod pallet { @@ -265,9 +264,9 @@ mod tests { NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Nicks: pallet_nicks::{Pallet, Call, Storage, Event}, + System: frame_system, + Balances: pallet_balances, + Nicks: pallet_nicks, } ); From f57c6447af83a1706041d462ca290b4f2a1bac4f Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 28 Dec 2021 19:42:58 -0400 Subject: [PATCH 0386/1472] Fix Places where AccountId Uses Default (#10556) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix places where accountid is default * Update frame/system/src/lib.rs * fmt * add simple test Co-authored-by: Bastian Köcher --- frame/system/src/lib.rs | 14 ++++++++++---- frame/system/src/tests.rs | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 8026f77902ba4..726837bf82672 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -820,7 +820,7 @@ impl, O>> + From>, Acco } pub struct EnsureSigned(sp_std::marker::PhantomData); -impl, O>> + From>, AccountId: Default> +impl, O>> + From>, AccountId: Decode> EnsureOrigin for EnsureSigned { type Success = AccountId; @@ -833,7 +833,10 @@ impl, O>> + From>, Acco #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> O { - O::from(RawOrigin::Signed(Default::default())) + let zero_account_id = + AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"); + O::from(RawOrigin::Signed(zero_account_id)) } } @@ -841,7 +844,7 @@ pub struct EnsureSignedBy(sp_std::marker::PhantomData<(Who, Acco impl< O: Into, O>> + From>, Who: SortedMembers, - AccountId: PartialEq + Clone + Ord + Default, + AccountId: PartialEq + Clone + Ord + Decode, > EnsureOrigin for EnsureSignedBy { type Success = AccountId; @@ -854,10 +857,13 @@ impl< #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> O { + let zero_account_id = + AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"); let members = Who::sorted_members(); let first_member = match members.get(0) { Some(account) => account.clone(), - None => Default::default(), + None => zero_account_id, }; O::from(RawOrigin::Signed(first_member.clone())) } diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index d8f9fd1af2bc2..de3158562f490 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -486,3 +486,26 @@ fn runtime_updated_digest_emitted_when_heap_pages_changed() { assert_runtime_updated_digest(1); }); } + +#[test] +fn ensure_signed_stuff_works() { + struct Members; + impl SortedMembers for Members { + fn sorted_members() -> Vec { + (0..10).collect() + } + } + + let signed_origin = Origin::signed(0u64); + assert_ok!(EnsureSigned::try_origin(signed_origin.clone())); + assert_ok!(EnsureSignedBy::::try_origin(signed_origin)); + + #[cfg(feature = "runtime-benchmarks")] + { + let successful_origin: Origin = EnsureSigned::successful_origin(); + assert_ok!(EnsureSigned::try_origin(successful_origin)); + + let successful_origin: Origin = EnsureSignedBy::::successful_origin(); + assert_ok!(EnsureSignedBy::::try_origin(successful_origin)); + } +} From 88a003283c6279bec634ba1630e738a8d0fdf8de Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres Date: Thu, 30 Dec 2021 19:32:59 +0100 Subject: [PATCH 0387/1472] node-template README persistent db (#10558) --- bin/node-template/README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/bin/node-template/README.md b/bin/node-template/README.md index 2397c57363b77..bb4df52f41a8f 100644 --- a/bin/node-template/README.md +++ b/bin/node-template/README.md @@ -55,7 +55,7 @@ node. ### Single-Node Development Chain -This command will start the single-node development chain with persistent state: +This command will start the single-node development chain with non-persistent state: ```bash ./target/release/node-template --dev @@ -72,6 +72,36 @@ Start the development chain with detailed logging: ```bash RUST_BACKTRACE=1 ./target/release/node-template -ldebug --dev ``` +> Development chain means that the state of our chain will be in a tmp folder while the nodes are +> running. Also, **alice** account will be authority and sudo account as declared in the [genesis +> state](https://github.com/substrate-developer-hub/substrate-node-template/blob/main/node/src/chain_spec.rs#L49). +> At the same time the following accounts will be prefunded: +> - Alice +> - Bob +> - Alice//stash +> - Bob//stash + +In case of being interested in maintaining the chain' state futher in time a base path other than +a temporary directory must be added so the db can be stored in the provided folder. We could use +this folder to store different chain databases, as a different folder will be created per different + chain that is ran. The following commands shows how to use a newly created folder as our db base + path. + +```bash +// Create a folder to use as the db base path +$ mkdir my-chain-state + +// Use of that folder to store the chain state +$ ./target/release/node-template --dev --base-path ./my-chain-state/ + +// Check the folder structure created inside the base path after running the chain +$ ls ./my-chain-state +chains +$ ls ./my-chain-state/chains/ +dev +$ ls ./my-chain-state/chains/dev +db keystore network +``` ### Connect with Polkadot-JS Apps Front-end From 1ca6b68cf8cd35a1c58f790c28e51ae726272ee9 Mon Sep 17 00:00:00 2001 From: green-jay <75261756+green-jay@users.noreply.github.com> Date: Fri, 31 Dec 2021 11:49:04 +0100 Subject: [PATCH 0388/1472] Expose Uniques helper functions and DestroyWitness fields (#10529) --- frame/uniques/src/functions.rs | 10 +++++----- frame/uniques/src/types.rs | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index e0ee09ab62d9d..9c3a5c1b19f86 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -22,7 +22,7 @@ use frame_support::{ensure, traits::Get}; use sp_runtime::{DispatchError, DispatchResult}; impl, I: 'static> Pallet { - pub(crate) fn do_transfer( + pub fn do_transfer( class: T::ClassId, instance: T::InstanceId, dest: T::AccountId, @@ -53,7 +53,7 @@ impl, I: 'static> Pallet { Ok(()) } - pub(super) fn do_create_class( + pub fn do_create_class( class: T::ClassId, owner: T::AccountId, admin: T::AccountId, @@ -86,7 +86,7 @@ impl, I: 'static> Pallet { Ok(()) } - pub(super) fn do_destroy_class( + pub fn do_destroy_class( class: T::ClassId, witness: DestroyWitness, maybe_check_owner: Option, @@ -122,7 +122,7 @@ impl, I: 'static> Pallet { }) } - pub(super) fn do_mint( + pub fn do_mint( class: T::ClassId, instance: T::InstanceId, owner: T::AccountId, @@ -157,7 +157,7 @@ impl, I: 'static> Pallet { Ok(()) } - pub(super) fn do_burn( + pub fn do_burn( class: T::ClassId, instance: T::InstanceId, with_details: impl FnOnce(&ClassDetailsFor, &InstanceDetailsFor) -> DispatchResult, diff --git a/frame/uniques/src/types.rs b/frame/uniques/src/types.rs index 1e4405aa09c84..5ba443dba6c4b 100644 --- a/frame/uniques/src/types.rs +++ b/frame/uniques/src/types.rs @@ -58,13 +58,13 @@ pub struct ClassDetails { pub struct DestroyWitness { /// The total number of outstanding instances of this asset class. #[codec(compact)] - pub(super) instances: u32, + pub instances: u32, /// The total number of outstanding instance metadata of this asset class. #[codec(compact)] - pub(super) instance_metadatas: u32, + pub instance_metadatas: u32, #[codec(compact)] /// The total number of attributes for this asset class. - pub(super) attributes: u32, + pub attributes: u32, } impl ClassDetails { From ded44948e2d5a398abcb4e342b0513cb690961bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 3 Jan 2022 09:22:14 +0100 Subject: [PATCH 0389/1472] Happy new year 2022 (#10573) --- .maintain/frame-weight-template.hbs | 2 +- HEADER-APACHE2 | 2 +- HEADER-GPL3 | 2 +- bin/node/bench/src/common.rs | 2 +- bin/node/bench/src/construct.rs | 2 +- bin/node/bench/src/core.rs | 2 +- bin/node/bench/src/generator.rs | 2 +- bin/node/bench/src/import.rs | 2 +- bin/node/bench/src/main.rs | 2 +- bin/node/bench/src/simple_trie.rs | 2 +- bin/node/bench/src/state_sizes.rs | 2 +- bin/node/bench/src/tempdb.rs | 2 +- bin/node/bench/src/trie.rs | 2 +- bin/node/bench/src/txpool.rs | 2 +- bin/node/cli/benches/block_production.rs | 2 +- bin/node/cli/benches/transaction_pool.rs | 2 +- bin/node/cli/bin/main.rs | 2 +- bin/node/cli/build.rs | 2 +- bin/node/cli/src/chain_spec.rs | 2 +- bin/node/cli/src/cli.rs | 2 +- bin/node/cli/src/command.rs | 2 +- bin/node/cli/src/lib.rs | 2 +- bin/node/cli/src/service.rs | 2 +- bin/node/cli/tests/build_spec_works.rs | 2 +- bin/node/cli/tests/check_block_works.rs | 2 +- bin/node/cli/tests/common.rs | 2 +- bin/node/cli/tests/export_import_flow.rs | 2 +- bin/node/cli/tests/inspect_works.rs | 2 +- bin/node/cli/tests/purge_chain_works.rs | 2 +- bin/node/cli/tests/running_the_node_and_interrupt.rs | 2 +- bin/node/cli/tests/telemetry.rs | 2 +- bin/node/cli/tests/temp_base_path_works.rs | 2 +- bin/node/cli/tests/version.rs | 2 +- bin/node/cli/tests/websocket_server.rs | 2 +- bin/node/executor/benches/bench.rs | 2 +- bin/node/executor/src/lib.rs | 2 +- bin/node/executor/tests/basic.rs | 2 +- bin/node/executor/tests/common.rs | 2 +- bin/node/executor/tests/fees.rs | 2 +- bin/node/executor/tests/submit_transaction.rs | 2 +- bin/node/inspect/src/cli.rs | 2 +- bin/node/inspect/src/command.rs | 2 +- bin/node/inspect/src/lib.rs | 2 +- bin/node/primitives/src/lib.rs | 2 +- bin/node/rpc/src/lib.rs | 2 +- bin/node/runtime/build.rs | 2 +- bin/node/runtime/src/constants.rs | 2 +- bin/node/runtime/src/impls.rs | 2 +- bin/node/runtime/src/lib.rs | 2 +- bin/node/runtime/src/voter_bags.rs | 2 +- bin/node/test-runner-example/src/lib.rs | 2 +- bin/node/testing/src/bench.rs | 2 +- bin/node/testing/src/client.rs | 2 +- bin/node/testing/src/genesis.rs | 2 +- bin/node/testing/src/keyring.rs | 2 +- bin/node/testing/src/lib.rs | 2 +- bin/utils/chain-spec-builder/build.rs | 2 +- bin/utils/chain-spec-builder/src/main.rs | 2 +- bin/utils/subkey/src/lib.rs | 2 +- bin/utils/subkey/src/main.rs | 2 +- client/allocator/src/error.rs | 2 +- client/allocator/src/freeing_bump.rs | 2 +- client/allocator/src/lib.rs | 2 +- client/api/src/backend.rs | 2 +- client/api/src/call_executor.rs | 2 +- client/api/src/client.rs | 2 +- client/api/src/execution_extensions.rs | 2 +- client/api/src/in_mem.rs | 2 +- client/api/src/leaves.rs | 2 +- client/api/src/lib.rs | 2 +- client/api/src/notifications.rs | 2 +- client/api/src/proof_provider.rs | 2 +- client/authority-discovery/src/error.rs | 2 +- client/authority-discovery/src/interval.rs | 2 +- client/authority-discovery/src/lib.rs | 2 +- client/authority-discovery/src/service.rs | 2 +- client/authority-discovery/src/tests.rs | 2 +- client/authority-discovery/src/worker.rs | 2 +- client/authority-discovery/src/worker/addr_cache.rs | 2 +- client/authority-discovery/src/worker/schema/tests.rs | 2 +- client/authority-discovery/src/worker/tests.rs | 2 +- client/basic-authorship/src/basic_authorship.rs | 2 +- client/basic-authorship/src/lib.rs | 2 +- client/beefy/rpc/src/lib.rs | 2 +- client/beefy/rpc/src/notification.rs | 2 +- client/beefy/src/error.rs | 2 +- client/beefy/src/gossip.rs | 2 +- client/beefy/src/keystore.rs | 2 +- client/beefy/src/lib.rs | 2 +- client/beefy/src/metrics.rs | 2 +- client/beefy/src/notification.rs | 2 +- client/beefy/src/round.rs | 2 +- client/beefy/src/worker.rs | 2 +- client/block-builder/src/lib.rs | 2 +- client/chain-spec/derive/src/impls.rs | 2 +- client/chain-spec/derive/src/lib.rs | 2 +- client/chain-spec/src/chain_spec.rs | 2 +- client/chain-spec/src/extension.rs | 2 +- client/chain-spec/src/lib.rs | 2 +- client/cli/src/arg_enums.rs | 2 +- client/cli/src/commands/build_spec_cmd.rs | 2 +- client/cli/src/commands/check_block_cmd.rs | 2 +- client/cli/src/commands/export_blocks_cmd.rs | 2 +- client/cli/src/commands/export_state_cmd.rs | 2 +- client/cli/src/commands/generate.rs | 2 +- client/cli/src/commands/generate_node_key.rs | 2 +- client/cli/src/commands/import_blocks_cmd.rs | 2 +- client/cli/src/commands/insert_key.rs | 2 +- client/cli/src/commands/inspect_key.rs | 2 +- client/cli/src/commands/inspect_node_key.rs | 2 +- client/cli/src/commands/key.rs | 2 +- client/cli/src/commands/mod.rs | 2 +- client/cli/src/commands/purge_chain_cmd.rs | 2 +- client/cli/src/commands/revert_cmd.rs | 2 +- client/cli/src/commands/run_cmd.rs | 2 +- client/cli/src/commands/sign.rs | 2 +- client/cli/src/commands/utils.rs | 2 +- client/cli/src/commands/vanity.rs | 2 +- client/cli/src/commands/verify.rs | 2 +- client/cli/src/config.rs | 2 +- client/cli/src/error.rs | 2 +- client/cli/src/lib.rs | 2 +- client/cli/src/params/database_params.rs | 2 +- client/cli/src/params/import_params.rs | 2 +- client/cli/src/params/keystore_params.rs | 2 +- client/cli/src/params/mod.rs | 2 +- client/cli/src/params/network_params.rs | 2 +- client/cli/src/params/node_key_params.rs | 2 +- client/cli/src/params/offchain_worker_params.rs | 2 +- client/cli/src/params/pruning_params.rs | 2 +- client/cli/src/params/shared_params.rs | 2 +- client/cli/src/params/transaction_pool_params.rs | 2 +- client/cli/src/runner.rs | 2 +- client/consensus/aura/src/import_queue.rs | 2 +- client/consensus/aura/src/lib.rs | 2 +- client/consensus/babe/rpc/src/lib.rs | 2 +- client/consensus/babe/src/authorship.rs | 2 +- client/consensus/babe/src/aux_schema.rs | 2 +- client/consensus/babe/src/lib.rs | 2 +- client/consensus/babe/src/migration.rs | 2 +- client/consensus/babe/src/tests.rs | 2 +- client/consensus/babe/src/verification.rs | 2 +- client/consensus/common/src/block_import.rs | 2 +- client/consensus/common/src/import_queue.rs | 2 +- client/consensus/common/src/import_queue/basic_queue.rs | 2 +- client/consensus/common/src/import_queue/buffered_link.rs | 2 +- client/consensus/common/src/lib.rs | 2 +- client/consensus/common/src/longest_chain.rs | 2 +- client/consensus/common/src/metrics.rs | 2 +- client/consensus/common/src/shared_data.rs | 2 +- client/consensus/epochs/src/lib.rs | 2 +- client/consensus/epochs/src/migration.rs | 2 +- client/consensus/manual-seal/src/consensus.rs | 2 +- client/consensus/manual-seal/src/consensus/babe.rs | 2 +- client/consensus/manual-seal/src/error.rs | 2 +- client/consensus/manual-seal/src/finalize_block.rs | 2 +- client/consensus/manual-seal/src/lib.rs | 2 +- client/consensus/manual-seal/src/rpc.rs | 2 +- client/consensus/manual-seal/src/seal_block.rs | 2 +- client/consensus/pow/src/lib.rs | 2 +- client/consensus/pow/src/worker.rs | 2 +- client/consensus/slots/build.rs | 2 +- client/consensus/slots/src/aux_schema.rs | 2 +- client/consensus/slots/src/lib.rs | 2 +- client/consensus/slots/src/slots.rs | 2 +- client/consensus/uncles/src/lib.rs | 2 +- client/db/src/bench.rs | 2 +- client/db/src/children.rs | 2 +- client/db/src/lib.rs | 2 +- client/db/src/offchain.rs | 2 +- client/db/src/parity_db.rs | 2 +- client/db/src/stats.rs | 2 +- client/db/src/storage_cache.rs | 2 +- client/db/src/upgrade.rs | 2 +- client/db/src/utils.rs | 2 +- client/executor/common/src/error.rs | 2 +- client/executor/common/src/lib.rs | 2 +- .../executor/common/src/runtime_blob/data_segments_snapshot.rs | 2 +- client/executor/common/src/runtime_blob/globals_snapshot.rs | 2 +- client/executor/common/src/runtime_blob/mod.rs | 2 +- client/executor/common/src/runtime_blob/runtime_blob.rs | 2 +- client/executor/common/src/sandbox.rs | 2 +- client/executor/common/src/util.rs | 2 +- client/executor/common/src/wasm_runtime.rs | 2 +- client/executor/runtime-test/build.rs | 2 +- client/executor/src/integration_tests/linux.rs | 2 +- client/executor/src/integration_tests/linux/smaps.rs | 2 +- client/executor/src/integration_tests/mod.rs | 2 +- client/executor/src/integration_tests/sandbox.rs | 2 +- client/executor/src/lib.rs | 2 +- client/executor/src/native_executor.rs | 2 +- client/executor/src/wasm_runtime.rs | 2 +- client/executor/wasmi/src/lib.rs | 2 +- client/executor/wasmtime/build.rs | 2 +- client/executor/wasmtime/src/host.rs | 2 +- client/executor/wasmtime/src/imports.rs | 2 +- client/executor/wasmtime/src/instance_wrapper.rs | 2 +- client/executor/wasmtime/src/lib.rs | 2 +- client/executor/wasmtime/src/runtime.rs | 2 +- client/executor/wasmtime/src/tests.rs | 2 +- client/executor/wasmtime/src/util.rs | 2 +- client/finality-grandpa/rpc/src/error.rs | 2 +- client/finality-grandpa/rpc/src/finality.rs | 2 +- client/finality-grandpa/rpc/src/lib.rs | 2 +- client/finality-grandpa/rpc/src/notification.rs | 2 +- client/finality-grandpa/rpc/src/report.rs | 2 +- client/finality-grandpa/src/authorities.rs | 2 +- client/finality-grandpa/src/aux_schema.rs | 2 +- client/finality-grandpa/src/communication/gossip.rs | 2 +- client/finality-grandpa/src/communication/mod.rs | 2 +- client/finality-grandpa/src/communication/periodic.rs | 2 +- client/finality-grandpa/src/communication/tests.rs | 2 +- client/finality-grandpa/src/environment.rs | 2 +- client/finality-grandpa/src/finality_proof.rs | 2 +- client/finality-grandpa/src/import.rs | 2 +- client/finality-grandpa/src/justification.rs | 2 +- client/finality-grandpa/src/lib.rs | 2 +- client/finality-grandpa/src/notification.rs | 2 +- client/finality-grandpa/src/observer.rs | 2 +- client/finality-grandpa/src/tests.rs | 2 +- client/finality-grandpa/src/until_imported.rs | 2 +- client/finality-grandpa/src/voting_rule.rs | 2 +- client/informant/src/display.rs | 2 +- client/informant/src/lib.rs | 2 +- client/keystore/src/lib.rs | 2 +- client/keystore/src/local.rs | 2 +- client/network-gossip/src/bridge.rs | 2 +- client/network-gossip/src/lib.rs | 2 +- client/network-gossip/src/state_machine.rs | 2 +- client/network-gossip/src/validator.rs | 2 +- client/network/src/behaviour.rs | 2 +- client/network/src/chain.rs | 2 +- client/network/src/config.rs | 2 +- client/network/src/discovery.rs | 2 +- client/network/src/error.rs | 2 +- client/network/src/lib.rs | 2 +- client/network/src/light_client_requests.rs | 2 +- client/network/src/light_client_requests/handler.rs | 2 +- client/network/src/network_state.rs | 2 +- client/network/src/peer_info.rs | 2 +- client/network/src/protocol.rs | 2 +- client/network/src/protocol/event.rs | 2 +- client/network/src/protocol/message.rs | 2 +- client/network/src/protocol/notifications.rs | 2 +- client/network/src/protocol/notifications/behaviour.rs | 2 +- client/network/src/protocol/notifications/handler.rs | 2 +- client/network/src/protocol/notifications/tests.rs | 2 +- client/network/src/protocol/notifications/upgrade.rs | 2 +- client/network/src/protocol/notifications/upgrade/collec.rs | 2 +- .../network/src/protocol/notifications/upgrade/notifications.rs | 2 +- client/network/src/protocol/sync.rs | 2 +- client/network/src/protocol/sync/blocks.rs | 2 +- client/network/src/protocol/sync/extra_requests.rs | 2 +- client/network/src/protocol/sync/state.rs | 2 +- client/network/src/protocol/sync/warp.rs | 2 +- client/network/src/request_responses.rs | 2 +- client/network/src/schema.rs | 2 +- client/network/src/service.rs | 2 +- client/network/src/service/metrics.rs | 2 +- client/network/src/service/out_events.rs | 2 +- client/network/src/service/signature.rs | 2 +- client/network/src/service/tests.rs | 2 +- client/network/src/transactions.rs | 2 +- client/network/src/transport.rs | 2 +- client/network/src/utils.rs | 2 +- client/network/test/src/block_import.rs | 2 +- client/network/test/src/lib.rs | 2 +- client/network/test/src/sync.rs | 2 +- client/offchain/src/api.rs | 2 +- client/offchain/src/api/http.rs | 2 +- client/offchain/src/api/timestamp.rs | 2 +- client/offchain/src/lib.rs | 2 +- client/peerset/src/lib.rs | 2 +- client/peerset/src/peersstate.rs | 2 +- client/peerset/tests/fuzz.rs | 2 +- client/proposer-metrics/src/lib.rs | 2 +- client/rpc-api/src/author/error.rs | 2 +- client/rpc-api/src/author/hash.rs | 2 +- client/rpc-api/src/author/mod.rs | 2 +- client/rpc-api/src/chain/error.rs | 2 +- client/rpc-api/src/chain/mod.rs | 2 +- client/rpc-api/src/child_state/mod.rs | 2 +- client/rpc-api/src/errors.rs | 2 +- client/rpc-api/src/helpers.rs | 2 +- client/rpc-api/src/lib.rs | 2 +- client/rpc-api/src/metadata.rs | 2 +- client/rpc-api/src/offchain/error.rs | 2 +- client/rpc-api/src/offchain/mod.rs | 2 +- client/rpc-api/src/policy.rs | 2 +- client/rpc-api/src/state/error.rs | 2 +- client/rpc-api/src/state/helpers.rs | 2 +- client/rpc-api/src/state/mod.rs | 2 +- client/rpc-api/src/system/error.rs | 2 +- client/rpc-api/src/system/helpers.rs | 2 +- client/rpc-api/src/system/mod.rs | 2 +- client/rpc-servers/src/lib.rs | 2 +- client/rpc-servers/src/middleware.rs | 2 +- client/rpc/src/author/mod.rs | 2 +- client/rpc/src/author/tests.rs | 2 +- client/rpc/src/chain/chain_full.rs | 2 +- client/rpc/src/chain/mod.rs | 2 +- client/rpc/src/chain/tests.rs | 2 +- client/rpc/src/lib.rs | 2 +- client/rpc/src/offchain/mod.rs | 2 +- client/rpc/src/offchain/tests.rs | 2 +- client/rpc/src/state/mod.rs | 2 +- client/rpc/src/state/state_full.rs | 2 +- client/rpc/src/state/tests.rs | 2 +- client/rpc/src/system/mod.rs | 2 +- client/rpc/src/system/tests.rs | 2 +- client/rpc/src/testing.rs | 2 +- client/service/src/builder.rs | 2 +- client/service/src/chain_ops/check_block.rs | 2 +- client/service/src/chain_ops/export_blocks.rs | 2 +- client/service/src/chain_ops/export_raw_state.rs | 2 +- client/service/src/chain_ops/import_blocks.rs | 2 +- client/service/src/chain_ops/mod.rs | 2 +- client/service/src/chain_ops/revert_chain.rs | 2 +- client/service/src/client/block_rules.rs | 2 +- client/service/src/client/call_executor.rs | 2 +- client/service/src/client/client.rs | 2 +- client/service/src/client/genesis.rs | 2 +- client/service/src/client/mod.rs | 2 +- client/service/src/client/wasm_override.rs | 2 +- client/service/src/client/wasm_substitutes.rs | 2 +- client/service/src/config.rs | 2 +- client/service/src/error.rs | 2 +- client/service/src/lib.rs | 2 +- client/service/src/metrics.rs | 2 +- client/service/src/task_manager/mod.rs | 2 +- client/service/src/task_manager/prometheus_future.rs | 2 +- client/service/src/task_manager/tests.rs | 2 +- client/service/test/src/client/db.rs | 2 +- client/service/test/src/client/mod.rs | 2 +- client/service/test/src/lib.rs | 2 +- client/state-db/src/lib.rs | 2 +- client/state-db/src/noncanonical.rs | 2 +- client/state-db/src/pruning.rs | 2 +- client/state-db/src/test.rs | 2 +- client/sync-state-rpc/src/lib.rs | 2 +- client/telemetry/src/endpoints.rs | 2 +- client/telemetry/src/error.rs | 2 +- client/telemetry/src/lib.rs | 2 +- client/telemetry/src/node.rs | 2 +- client/telemetry/src/transport.rs | 2 +- client/tracing/benches/bench.rs | 2 +- client/tracing/proc-macro/src/lib.rs | 2 +- client/tracing/src/lib.rs | 2 +- client/tracing/src/logging/event_format.rs | 2 +- client/tracing/src/logging/fast_local_time.rs | 2 +- client/tracing/src/logging/layers/mod.rs | 2 +- client/tracing/src/logging/layers/prefix_layer.rs | 2 +- client/tracing/src/logging/mod.rs | 2 +- client/tracing/src/logging/stderr_writer.rs | 2 +- client/transaction-pool/api/src/error.rs | 2 +- client/transaction-pool/api/src/lib.rs | 2 +- client/transaction-pool/benches/basics.rs | 2 +- client/transaction-pool/src/api.rs | 2 +- client/transaction-pool/src/error.rs | 2 +- client/transaction-pool/src/graph/base_pool.rs | 2 +- client/transaction-pool/src/graph/future.rs | 2 +- client/transaction-pool/src/graph/listener.rs | 2 +- client/transaction-pool/src/graph/mod.rs | 2 +- client/transaction-pool/src/graph/pool.rs | 2 +- client/transaction-pool/src/graph/ready.rs | 2 +- client/transaction-pool/src/graph/rotator.rs | 2 +- client/transaction-pool/src/graph/tracked_map.rs | 2 +- client/transaction-pool/src/graph/validated_pool.rs | 2 +- client/transaction-pool/src/graph/watcher.rs | 2 +- client/transaction-pool/src/lib.rs | 2 +- client/transaction-pool/src/metrics.rs | 2 +- client/transaction-pool/src/revalidation.rs | 2 +- client/transaction-pool/tests/pool.rs | 2 +- client/utils/src/lib.rs | 2 +- client/utils/src/metrics.rs | 2 +- client/utils/src/mpsc.rs | 2 +- client/utils/src/status_sinks.rs | 2 +- frame/assets/src/benchmarking.rs | 2 +- frame/assets/src/extra_mutator.rs | 2 +- frame/assets/src/functions.rs | 2 +- frame/assets/src/impl_fungibles.rs | 2 +- frame/assets/src/impl_stored_map.rs | 2 +- frame/assets/src/lib.rs | 2 +- frame/assets/src/mock.rs | 2 +- frame/assets/src/tests.rs | 2 +- frame/assets/src/types.rs | 2 +- frame/assets/src/weights.rs | 2 +- frame/atomic-swap/src/lib.rs | 2 +- frame/aura/src/lib.rs | 2 +- frame/aura/src/migrations.rs | 2 +- frame/aura/src/mock.rs | 2 +- frame/aura/src/tests.rs | 2 +- frame/authority-discovery/src/lib.rs | 2 +- frame/authorship/src/lib.rs | 2 +- frame/babe/src/benchmarking.rs | 2 +- frame/babe/src/default_weights.rs | 2 +- frame/babe/src/equivocation.rs | 2 +- frame/babe/src/lib.rs | 2 +- frame/babe/src/mock.rs | 2 +- frame/babe/src/randomness.rs | 2 +- frame/babe/src/tests.rs | 2 +- frame/bags-list/fuzzer/src/main.rs | 2 +- frame/bags-list/remote-tests/src/lib.rs | 2 +- frame/bags-list/src/benchmarks.rs | 2 +- frame/bags-list/src/lib.rs | 2 +- frame/bags-list/src/list/mod.rs | 2 +- frame/bags-list/src/list/tests.rs | 2 +- frame/bags-list/src/migrations.rs | 2 +- frame/bags-list/src/mock.rs | 2 +- frame/bags-list/src/tests.rs | 2 +- frame/bags-list/src/weights.rs | 2 +- frame/balances/src/benchmarking.rs | 2 +- frame/balances/src/lib.rs | 2 +- frame/balances/src/tests.rs | 2 +- frame/balances/src/tests_composite.rs | 2 +- frame/balances/src/tests_local.rs | 2 +- frame/balances/src/tests_reentrancy.rs | 2 +- frame/balances/src/weights.rs | 2 +- frame/beefy-mmr/primitives/src/lib.rs | 2 +- frame/beefy-mmr/src/lib.rs | 2 +- frame/beefy-mmr/src/mock.rs | 2 +- frame/beefy-mmr/src/tests.rs | 2 +- frame/beefy/src/lib.rs | 2 +- frame/beefy/src/mock.rs | 2 +- frame/beefy/src/tests.rs | 2 +- frame/benchmarking/src/analysis.rs | 2 +- frame/benchmarking/src/baseline.rs | 2 +- frame/benchmarking/src/lib.rs | 2 +- frame/benchmarking/src/tests.rs | 2 +- frame/benchmarking/src/tests_instance.rs | 2 +- frame/benchmarking/src/utils.rs | 2 +- frame/benchmarking/src/weights.rs | 2 +- frame/bounties/src/benchmarking.rs | 2 +- frame/bounties/src/lib.rs | 2 +- frame/bounties/src/migrations/mod.rs | 2 +- frame/bounties/src/migrations/v4.rs | 2 +- frame/bounties/src/tests.rs | 2 +- frame/bounties/src/weights.rs | 2 +- frame/child-bounties/src/benchmarking.rs | 2 +- frame/child-bounties/src/lib.rs | 2 +- frame/child-bounties/src/tests.rs | 2 +- frame/child-bounties/src/weights.rs | 2 +- frame/collective/src/benchmarking.rs | 2 +- frame/collective/src/lib.rs | 2 +- frame/collective/src/migrations/mod.rs | 2 +- frame/collective/src/migrations/v4.rs | 2 +- frame/collective/src/tests.rs | 2 +- frame/collective/src/weights.rs | 2 +- frame/contracts/common/src/lib.rs | 2 +- frame/contracts/proc-macro/src/lib.rs | 2 +- frame/contracts/rpc/runtime-api/src/lib.rs | 2 +- frame/contracts/rpc/src/lib.rs | 2 +- frame/contracts/src/benchmarking/code.rs | 2 +- frame/contracts/src/benchmarking/mod.rs | 2 +- frame/contracts/src/benchmarking/sandbox.rs | 2 +- frame/contracts/src/chain_extension.rs | 2 +- frame/contracts/src/exec.rs | 2 +- frame/contracts/src/gas.rs | 2 +- frame/contracts/src/lib.rs | 2 +- frame/contracts/src/migration.rs | 2 +- frame/contracts/src/schedule.rs | 2 +- frame/contracts/src/storage.rs | 2 +- frame/contracts/src/storage/meter.rs | 2 +- frame/contracts/src/tests.rs | 2 +- frame/contracts/src/wasm/code_cache.rs | 2 +- frame/contracts/src/wasm/env_def/macros.rs | 2 +- frame/contracts/src/wasm/env_def/mod.rs | 2 +- frame/contracts/src/wasm/mod.rs | 2 +- frame/contracts/src/wasm/prepare.rs | 2 +- frame/contracts/src/wasm/runtime.rs | 2 +- frame/contracts/src/weights.rs | 2 +- frame/democracy/src/benchmarking.rs | 2 +- frame/democracy/src/conviction.rs | 2 +- frame/democracy/src/lib.rs | 2 +- frame/democracy/src/tests.rs | 2 +- frame/democracy/src/tests/cancellation.rs | 2 +- frame/democracy/src/tests/decoders.rs | 2 +- frame/democracy/src/tests/delegation.rs | 2 +- frame/democracy/src/tests/external_proposing.rs | 2 +- frame/democracy/src/tests/fast_tracking.rs | 2 +- frame/democracy/src/tests/lock_voting.rs | 2 +- frame/democracy/src/tests/preimage.rs | 2 +- frame/democracy/src/tests/public_proposals.rs | 2 +- frame/democracy/src/tests/scheduling.rs | 2 +- frame/democracy/src/tests/voting.rs | 2 +- frame/democracy/src/types.rs | 2 +- frame/democracy/src/vote.rs | 2 +- frame/democracy/src/vote_threshold.rs | 2 +- frame/democracy/src/weights.rs | 2 +- frame/election-provider-multi-phase/src/benchmarking.rs | 2 +- frame/election-provider-multi-phase/src/helpers.rs | 2 +- frame/election-provider-multi-phase/src/lib.rs | 2 +- frame/election-provider-multi-phase/src/mock.rs | 2 +- frame/election-provider-multi-phase/src/signed.rs | 2 +- frame/election-provider-multi-phase/src/unsigned.rs | 2 +- frame/election-provider-multi-phase/src/weights.rs | 2 +- frame/election-provider-support/src/lib.rs | 2 +- frame/election-provider-support/src/onchain.rs | 2 +- frame/elections-phragmen/src/benchmarking.rs | 2 +- frame/elections-phragmen/src/lib.rs | 2 +- frame/elections-phragmen/src/migrations/mod.rs | 2 +- frame/elections-phragmen/src/migrations/v3.rs | 2 +- frame/elections-phragmen/src/migrations/v4.rs | 2 +- frame/elections-phragmen/src/weights.rs | 2 +- frame/examples/basic/src/benchmarking.rs | 2 +- frame/examples/basic/src/lib.rs | 2 +- frame/examples/basic/src/tests.rs | 2 +- frame/examples/basic/src/weights.rs | 2 +- frame/examples/offchain-worker/src/lib.rs | 2 +- frame/examples/offchain-worker/src/tests.rs | 2 +- frame/examples/parallel/src/lib.rs | 2 +- frame/examples/parallel/src/tests.rs | 2 +- frame/executive/src/lib.rs | 2 +- frame/gilt/src/benchmarking.rs | 2 +- frame/gilt/src/lib.rs | 2 +- frame/gilt/src/mock.rs | 2 +- frame/gilt/src/tests.rs | 2 +- frame/gilt/src/weights.rs | 2 +- frame/grandpa/src/benchmarking.rs | 2 +- frame/grandpa/src/default_weights.rs | 2 +- frame/grandpa/src/equivocation.rs | 2 +- frame/grandpa/src/lib.rs | 2 +- frame/grandpa/src/migrations.rs | 2 +- frame/grandpa/src/migrations/v4.rs | 2 +- frame/grandpa/src/mock.rs | 2 +- frame/grandpa/src/tests.rs | 2 +- frame/identity/src/benchmarking.rs | 2 +- frame/identity/src/lib.rs | 2 +- frame/identity/src/tests.rs | 2 +- frame/identity/src/types.rs | 2 +- frame/identity/src/weights.rs | 2 +- frame/im-online/src/benchmarking.rs | 2 +- frame/im-online/src/lib.rs | 2 +- frame/im-online/src/mock.rs | 2 +- frame/im-online/src/tests.rs | 2 +- frame/im-online/src/weights.rs | 2 +- frame/indices/src/benchmarking.rs | 2 +- frame/indices/src/lib.rs | 2 +- frame/indices/src/mock.rs | 2 +- frame/indices/src/tests.rs | 2 +- frame/indices/src/weights.rs | 2 +- frame/lottery/src/benchmarking.rs | 2 +- frame/lottery/src/lib.rs | 2 +- frame/lottery/src/mock.rs | 2 +- frame/lottery/src/tests.rs | 2 +- frame/lottery/src/weights.rs | 2 +- frame/membership/src/lib.rs | 2 +- frame/membership/src/migrations/mod.rs | 2 +- frame/membership/src/migrations/v4.rs | 2 +- frame/membership/src/weights.rs | 2 +- frame/merkle-mountain-range/primitives/src/lib.rs | 2 +- frame/merkle-mountain-range/rpc/src/lib.rs | 2 +- frame/merkle-mountain-range/src/benchmarking.rs | 2 +- frame/merkle-mountain-range/src/default_weights.rs | 2 +- frame/merkle-mountain-range/src/lib.rs | 2 +- frame/merkle-mountain-range/src/mmr/mmr.rs | 2 +- frame/merkle-mountain-range/src/mmr/mod.rs | 2 +- frame/merkle-mountain-range/src/mmr/storage.rs | 2 +- frame/merkle-mountain-range/src/mmr/utils.rs | 2 +- frame/merkle-mountain-range/src/mock.rs | 2 +- frame/merkle-mountain-range/src/tests.rs | 2 +- frame/multisig/src/benchmarking.rs | 2 +- frame/multisig/src/lib.rs | 2 +- frame/multisig/src/tests.rs | 2 +- frame/multisig/src/weights.rs | 2 +- frame/nicks/src/lib.rs | 2 +- frame/node-authorization/src/lib.rs | 2 +- frame/node-authorization/src/mock.rs | 2 +- frame/node-authorization/src/tests.rs | 2 +- frame/node-authorization/src/weights.rs | 2 +- frame/offences/benchmarking/src/lib.rs | 2 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/offences/src/lib.rs | 2 +- frame/offences/src/migration.rs | 2 +- frame/offences/src/mock.rs | 2 +- frame/offences/src/tests.rs | 2 +- frame/preimage/src/benchmarking.rs | 2 +- frame/preimage/src/lib.rs | 2 +- frame/preimage/src/mock.rs | 2 +- frame/preimage/src/tests.rs | 2 +- frame/preimage/src/weights.rs | 2 +- frame/proxy/src/benchmarking.rs | 2 +- frame/proxy/src/lib.rs | 2 +- frame/proxy/src/tests.rs | 2 +- frame/proxy/src/weights.rs | 2 +- frame/randomness-collective-flip/src/lib.rs | 2 +- frame/recovery/src/lib.rs | 2 +- frame/recovery/src/mock.rs | 2 +- frame/recovery/src/tests.rs | 2 +- frame/scheduler/src/benchmarking.rs | 2 +- frame/scheduler/src/lib.rs | 2 +- frame/scheduler/src/mock.rs | 2 +- frame/scheduler/src/tests.rs | 2 +- frame/scheduler/src/weights.rs | 2 +- frame/scored-pool/src/lib.rs | 2 +- frame/scored-pool/src/mock.rs | 2 +- frame/scored-pool/src/tests.rs | 2 +- frame/session/benchmarking/src/lib.rs | 2 +- frame/session/benchmarking/src/mock.rs | 2 +- frame/session/src/historical/mod.rs | 2 +- frame/session/src/historical/offchain.rs | 2 +- frame/session/src/historical/onchain.rs | 2 +- frame/session/src/historical/shared.rs | 2 +- frame/session/src/lib.rs | 2 +- frame/session/src/migrations/mod.rs | 2 +- frame/session/src/migrations/v1.rs | 2 +- frame/session/src/mock.rs | 2 +- frame/session/src/tests.rs | 2 +- frame/session/src/weights.rs | 2 +- frame/society/src/lib.rs | 2 +- frame/society/src/mock.rs | 2 +- frame/society/src/tests.rs | 2 +- frame/staking/reward-curve/src/lib.rs | 2 +- frame/staking/reward-curve/tests/test.rs | 2 +- frame/staking/reward-fn/src/lib.rs | 2 +- frame/staking/reward-fn/tests/test.rs | 2 +- frame/staking/src/benchmarking.rs | 2 +- frame/staking/src/inflation.rs | 2 +- frame/staking/src/lib.rs | 2 +- frame/staking/src/migrations.rs | 2 +- frame/staking/src/mock.rs | 2 +- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/pallet/mod.rs | 2 +- frame/staking/src/slashing.rs | 2 +- frame/staking/src/testing_utils.rs | 2 +- frame/staking/src/tests.rs | 2 +- frame/staking/src/weights.rs | 2 +- frame/sudo/src/lib.rs | 2 +- frame/sudo/src/mock.rs | 2 +- frame/sudo/src/tests.rs | 2 +- frame/support/procedural/src/clone_no_bound.rs | 2 +- frame/support/procedural/src/construct_runtime/expand/call.rs | 2 +- frame/support/procedural/src/construct_runtime/expand/config.rs | 2 +- frame/support/procedural/src/construct_runtime/expand/event.rs | 2 +- .../support/procedural/src/construct_runtime/expand/inherent.rs | 2 +- .../support/procedural/src/construct_runtime/expand/metadata.rs | 2 +- frame/support/procedural/src/construct_runtime/expand/mod.rs | 2 +- frame/support/procedural/src/construct_runtime/expand/origin.rs | 2 +- .../support/procedural/src/construct_runtime/expand/unsigned.rs | 2 +- frame/support/procedural/src/construct_runtime/mod.rs | 2 +- frame/support/procedural/src/construct_runtime/parse.rs | 2 +- frame/support/procedural/src/crate_version.rs | 2 +- frame/support/procedural/src/debug_no_bound.rs | 2 +- frame/support/procedural/src/default_no_bound.rs | 2 +- frame/support/procedural/src/key_prefix.rs | 2 +- frame/support/procedural/src/lib.rs | 2 +- frame/support/procedural/src/match_and_insert.rs | 2 +- frame/support/procedural/src/pallet/expand/call.rs | 2 +- frame/support/procedural/src/pallet/expand/config.rs | 2 +- frame/support/procedural/src/pallet/expand/constants.rs | 2 +- frame/support/procedural/src/pallet/expand/error.rs | 2 +- frame/support/procedural/src/pallet/expand/event.rs | 2 +- frame/support/procedural/src/pallet/expand/genesis_build.rs | 2 +- frame/support/procedural/src/pallet/expand/genesis_config.rs | 2 +- frame/support/procedural/src/pallet/expand/hooks.rs | 2 +- frame/support/procedural/src/pallet/expand/inherent.rs | 2 +- frame/support/procedural/src/pallet/expand/instances.rs | 2 +- frame/support/procedural/src/pallet/expand/mod.rs | 2 +- frame/support/procedural/src/pallet/expand/origin.rs | 2 +- frame/support/procedural/src/pallet/expand/pallet_struct.rs | 2 +- frame/support/procedural/src/pallet/expand/storage.rs | 2 +- frame/support/procedural/src/pallet/expand/store_trait.rs | 2 +- frame/support/procedural/src/pallet/expand/tt_default_parts.rs | 2 +- frame/support/procedural/src/pallet/expand/type_value.rs | 2 +- frame/support/procedural/src/pallet/expand/validate_unsigned.rs | 2 +- frame/support/procedural/src/pallet/mod.rs | 2 +- frame/support/procedural/src/pallet/parse/call.rs | 2 +- frame/support/procedural/src/pallet/parse/config.rs | 2 +- frame/support/procedural/src/pallet/parse/error.rs | 2 +- frame/support/procedural/src/pallet/parse/event.rs | 2 +- frame/support/procedural/src/pallet/parse/extra_constants.rs | 2 +- frame/support/procedural/src/pallet/parse/genesis_build.rs | 2 +- frame/support/procedural/src/pallet/parse/genesis_config.rs | 2 +- frame/support/procedural/src/pallet/parse/helper.rs | 2 +- frame/support/procedural/src/pallet/parse/hooks.rs | 2 +- frame/support/procedural/src/pallet/parse/inherent.rs | 2 +- frame/support/procedural/src/pallet/parse/mod.rs | 2 +- frame/support/procedural/src/pallet/parse/origin.rs | 2 +- frame/support/procedural/src/pallet/parse/pallet_struct.rs | 2 +- frame/support/procedural/src/pallet/parse/storage.rs | 2 +- frame/support/procedural/src/pallet/parse/type_value.rs | 2 +- frame/support/procedural/src/pallet/parse/validate_unsigned.rs | 2 +- frame/support/procedural/src/partial_eq_no_bound.rs | 2 +- .../procedural/src/storage/genesis_config/builder_def.rs | 2 +- .../procedural/src/storage/genesis_config/genesis_config_def.rs | 2 +- frame/support/procedural/src/storage/genesis_config/mod.rs | 2 +- frame/support/procedural/src/storage/getters.rs | 2 +- frame/support/procedural/src/storage/instance_trait.rs | 2 +- frame/support/procedural/src/storage/metadata.rs | 2 +- frame/support/procedural/src/storage/mod.rs | 2 +- frame/support/procedural/src/storage/parse.rs | 2 +- frame/support/procedural/src/storage/storage_info.rs | 2 +- frame/support/procedural/src/storage/storage_struct.rs | 2 +- frame/support/procedural/src/storage/store_trait.rs | 2 +- frame/support/procedural/src/transactional.rs | 2 +- frame/support/procedural/tools/derive/src/lib.rs | 2 +- frame/support/procedural/tools/src/lib.rs | 2 +- frame/support/procedural/tools/src/syn_ext.rs | 2 +- frame/support/src/dispatch.rs | 2 +- frame/support/src/error.rs | 2 +- frame/support/src/event.rs | 2 +- frame/support/src/hash.rs | 2 +- frame/support/src/inherent.rs | 2 +- frame/support/src/instances.rs | 2 +- frame/support/src/lib.rs | 2 +- frame/support/src/migrations.rs | 2 +- frame/support/src/storage/bounded_btree_map.rs | 2 +- frame/support/src/storage/bounded_btree_set.rs | 2 +- frame/support/src/storage/bounded_vec.rs | 2 +- frame/support/src/storage/child.rs | 2 +- frame/support/src/storage/generator/double_map.rs | 2 +- frame/support/src/storage/generator/map.rs | 2 +- frame/support/src/storage/generator/mod.rs | 2 +- frame/support/src/storage/generator/nmap.rs | 2 +- frame/support/src/storage/generator/value.rs | 2 +- frame/support/src/storage/hashed.rs | 2 +- frame/support/src/storage/migration.rs | 2 +- frame/support/src/storage/mod.rs | 2 +- frame/support/src/storage/types/counted_map.rs | 2 +- frame/support/src/storage/types/double_map.rs | 2 +- frame/support/src/storage/types/key.rs | 2 +- frame/support/src/storage/types/map.rs | 2 +- frame/support/src/storage/types/mod.rs | 2 +- frame/support/src/storage/types/nmap.rs | 2 +- frame/support/src/storage/types/value.rs | 2 +- frame/support/src/storage/unhashed.rs | 2 +- frame/support/src/storage/weak_bounded_vec.rs | 2 +- frame/support/src/traits.rs | 2 +- frame/support/src/traits/dispatch.rs | 2 +- frame/support/src/traits/filter.rs | 2 +- frame/support/src/traits/hooks.rs | 2 +- frame/support/src/traits/members.rs | 2 +- frame/support/src/traits/metadata.rs | 2 +- frame/support/src/traits/misc.rs | 2 +- frame/support/src/traits/randomness.rs | 2 +- frame/support/src/traits/schedule.rs | 2 +- frame/support/src/traits/storage.rs | 2 +- frame/support/src/traits/stored_map.rs | 2 +- frame/support/src/traits/tokens.rs | 2 +- frame/support/src/traits/tokens/currency.rs | 2 +- frame/support/src/traits/tokens/currency/lockable.rs | 2 +- frame/support/src/traits/tokens/currency/reservable.rs | 2 +- frame/support/src/traits/tokens/fungible.rs | 2 +- frame/support/src/traits/tokens/fungible/balanced.rs | 2 +- frame/support/src/traits/tokens/fungible/imbalance.rs | 2 +- frame/support/src/traits/tokens/fungibles.rs | 2 +- frame/support/src/traits/tokens/fungibles/approvals.rs | 2 +- frame/support/src/traits/tokens/fungibles/balanced.rs | 2 +- frame/support/src/traits/tokens/fungibles/imbalance.rs | 2 +- frame/support/src/traits/tokens/fungibles/metadata.rs | 2 +- frame/support/src/traits/tokens/imbalance.rs | 2 +- frame/support/src/traits/tokens/imbalance/on_unbalanced.rs | 2 +- frame/support/src/traits/tokens/imbalance/signed_imbalance.rs | 2 +- frame/support/src/traits/tokens/imbalance/split_two_ways.rs | 2 +- frame/support/src/traits/tokens/misc.rs | 2 +- frame/support/src/traits/tokens/nonfungible.rs | 2 +- frame/support/src/traits/tokens/nonfungibles.rs | 2 +- frame/support/src/traits/validation.rs | 2 +- frame/support/src/traits/voting.rs | 2 +- frame/support/src/weights.rs | 2 +- frame/support/test/compile_pass/src/lib.rs | 2 +- frame/support/test/pallet/src/lib.rs | 2 +- frame/support/test/src/lib.rs | 2 +- frame/support/test/src/pallet_version.rs | 2 +- frame/support/test/tests/construct_runtime.rs | 2 +- frame/support/test/tests/construct_runtime_ui.rs | 2 +- frame/support/test/tests/decl_module_ui.rs | 2 +- frame/support/test/tests/decl_storage.rs | 2 +- frame/support/test/tests/decl_storage_ui.rs | 2 +- frame/support/test/tests/decl_storage_ui/config_duplicate.rs | 2 +- .../support/test/tests/decl_storage_ui/config_get_duplicate.rs | 2 +- frame/support/test/tests/decl_storage_ui/get_duplicate.rs | 2 +- frame/support/test/tests/derive_no_bound.rs | 2 +- frame/support/test/tests/derive_no_bound_ui.rs | 2 +- frame/support/test/tests/final_keys.rs | 2 +- frame/support/test/tests/genesisconfig.rs | 2 +- frame/support/test/tests/instance.rs | 2 +- frame/support/test/tests/issue2219.rs | 2 +- frame/support/test/tests/pallet.rs | 2 +- frame/support/test/tests/pallet_compatibility.rs | 2 +- frame/support/test/tests/pallet_compatibility_instance.rs | 2 +- frame/support/test/tests/pallet_instance.rs | 2 +- frame/support/test/tests/pallet_ui.rs | 2 +- frame/support/test/tests/pallet_with_name_trait_is_valid.rs | 2 +- frame/support/test/tests/storage_transaction.rs | 2 +- frame/support/test/tests/system.rs | 2 +- frame/system/benches/bench.rs | 2 +- frame/system/benchmarking/src/lib.rs | 2 +- frame/system/benchmarking/src/mock.rs | 2 +- frame/system/rpc/runtime-api/src/lib.rs | 2 +- frame/system/src/extensions/check_genesis.rs | 2 +- frame/system/src/extensions/check_mortality.rs | 2 +- frame/system/src/extensions/check_non_zero_sender.rs | 2 +- frame/system/src/extensions/check_nonce.rs | 2 +- frame/system/src/extensions/check_spec_version.rs | 2 +- frame/system/src/extensions/check_tx_version.rs | 2 +- frame/system/src/extensions/check_weight.rs | 2 +- frame/system/src/extensions/mod.rs | 2 +- frame/system/src/lib.rs | 2 +- frame/system/src/limits.rs | 2 +- frame/system/src/migrations/mod.rs | 2 +- frame/system/src/mock.rs | 2 +- frame/system/src/mocking.rs | 2 +- frame/system/src/offchain.rs | 2 +- frame/system/src/tests.rs | 2 +- frame/system/src/weights.rs | 2 +- frame/timestamp/src/benchmarking.rs | 2 +- frame/timestamp/src/lib.rs | 2 +- frame/timestamp/src/weights.rs | 2 +- frame/tips/src/benchmarking.rs | 2 +- frame/tips/src/lib.rs | 2 +- frame/tips/src/migrations/mod.rs | 2 +- frame/tips/src/migrations/v4.rs | 2 +- frame/tips/src/tests.rs | 2 +- frame/tips/src/weights.rs | 2 +- frame/transaction-payment/asset-tx-payment/src/lib.rs | 2 +- frame/transaction-payment/asset-tx-payment/src/payment.rs | 2 +- frame/transaction-payment/asset-tx-payment/src/tests.rs | 2 +- frame/transaction-payment/rpc/runtime-api/src/lib.rs | 2 +- frame/transaction-payment/rpc/src/lib.rs | 2 +- frame/transaction-payment/src/lib.rs | 2 +- frame/transaction-payment/src/types.rs | 2 +- frame/transaction-storage/src/benchmarking.rs | 2 +- frame/transaction-storage/src/lib.rs | 2 +- frame/transaction-storage/src/mock.rs | 2 +- frame/transaction-storage/src/tests.rs | 2 +- frame/transaction-storage/src/weights.rs | 2 +- frame/treasury/src/benchmarking.rs | 2 +- frame/treasury/src/lib.rs | 2 +- frame/treasury/src/tests.rs | 2 +- frame/treasury/src/weights.rs | 2 +- frame/try-runtime/src/lib.rs | 2 +- frame/uniques/src/benchmarking.rs | 2 +- frame/uniques/src/functions.rs | 2 +- frame/uniques/src/impl_nonfungibles.rs | 2 +- frame/uniques/src/lib.rs | 2 +- frame/uniques/src/migration.rs | 2 +- frame/uniques/src/mock.rs | 2 +- frame/uniques/src/tests.rs | 2 +- frame/uniques/src/types.rs | 2 +- frame/uniques/src/weights.rs | 2 +- frame/utility/src/benchmarking.rs | 2 +- frame/utility/src/lib.rs | 2 +- frame/utility/src/tests.rs | 2 +- frame/utility/src/weights.rs | 2 +- frame/vesting/src/benchmarking.rs | 2 +- frame/vesting/src/lib.rs | 2 +- frame/vesting/src/migrations.rs | 2 +- frame/vesting/src/mock.rs | 2 +- frame/vesting/src/tests.rs | 2 +- frame/vesting/src/vesting_info.rs | 2 +- frame/vesting/src/weights.rs | 2 +- primitives/api/proc-macro/src/decl_runtime_apis.rs | 2 +- primitives/api/proc-macro/src/impl_runtime_apis.rs | 2 +- primitives/api/proc-macro/src/lib.rs | 2 +- primitives/api/proc-macro/src/mock_impl_runtime_apis.rs | 2 +- primitives/api/proc-macro/src/utils.rs | 2 +- primitives/api/src/lib.rs | 2 +- primitives/api/test/benches/bench.rs | 2 +- primitives/api/test/tests/decl_and_impl.rs | 2 +- primitives/api/test/tests/runtime_calls.rs | 2 +- primitives/api/test/tests/trybuild.rs | 2 +- primitives/application-crypto/src/ecdsa.rs | 2 +- primitives/application-crypto/src/ed25519.rs | 2 +- primitives/application-crypto/src/lib.rs | 2 +- primitives/application-crypto/src/sr25519.rs | 2 +- primitives/application-crypto/src/traits.rs | 2 +- primitives/application-crypto/test/src/ecdsa.rs | 2 +- primitives/application-crypto/test/src/ed25519.rs | 2 +- primitives/application-crypto/test/src/lib.rs | 2 +- primitives/application-crypto/test/src/sr25519.rs | 2 +- primitives/arithmetic/benches/bench.rs | 2 +- primitives/arithmetic/fuzzer/src/biguint.rs | 2 +- primitives/arithmetic/fuzzer/src/fixed_point.rs | 2 +- primitives/arithmetic/fuzzer/src/multiply_by_rational.rs | 2 +- primitives/arithmetic/fuzzer/src/normalize.rs | 2 +- primitives/arithmetic/fuzzer/src/per_thing_rational.rs | 2 +- primitives/arithmetic/src/biguint.rs | 2 +- primitives/arithmetic/src/fixed_point.rs | 2 +- primitives/arithmetic/src/helpers_128bit.rs | 2 +- primitives/arithmetic/src/lib.rs | 2 +- primitives/arithmetic/src/per_things.rs | 2 +- primitives/arithmetic/src/rational.rs | 2 +- primitives/arithmetic/src/traits.rs | 2 +- primitives/authority-discovery/src/lib.rs | 2 +- primitives/authorship/src/lib.rs | 2 +- primitives/beefy/src/commitment.rs | 2 +- primitives/beefy/src/lib.rs | 2 +- primitives/beefy/src/mmr.rs | 2 +- primitives/beefy/src/witness.rs | 2 +- primitives/block-builder/src/lib.rs | 2 +- primitives/blockchain/src/backend.rs | 2 +- primitives/blockchain/src/error.rs | 2 +- primitives/blockchain/src/header_metadata.rs | 2 +- primitives/blockchain/src/lib.rs | 2 +- primitives/consensus/aura/src/digests.rs | 2 +- primitives/consensus/aura/src/inherents.rs | 2 +- primitives/consensus/aura/src/lib.rs | 2 +- primitives/consensus/babe/src/digests.rs | 2 +- primitives/consensus/babe/src/inherents.rs | 2 +- primitives/consensus/babe/src/lib.rs | 2 +- primitives/consensus/common/src/block_validation.rs | 2 +- primitives/consensus/common/src/error.rs | 2 +- primitives/consensus/common/src/evaluation.rs | 2 +- primitives/consensus/common/src/lib.rs | 2 +- primitives/consensus/common/src/select_chain.rs | 2 +- primitives/consensus/pow/src/lib.rs | 2 +- primitives/consensus/slots/src/lib.rs | 2 +- primitives/consensus/vrf/src/lib.rs | 2 +- primitives/consensus/vrf/src/schnorrkel.rs | 2 +- primitives/core/hashing/proc-macro/src/impls.rs | 2 +- primitives/core/hashing/proc-macro/src/lib.rs | 2 +- primitives/core/hashing/src/lib.rs | 2 +- primitives/core/src/crypto.rs | 2 +- primitives/core/src/ecdsa.rs | 2 +- primitives/core/src/ed25519.rs | 2 +- primitives/core/src/hash.rs | 2 +- primitives/core/src/hasher.rs | 2 +- primitives/core/src/hashing.rs | 2 +- primitives/core/src/hexdisplay.rs | 2 +- primitives/core/src/lib.rs | 2 +- primitives/core/src/offchain/mod.rs | 2 +- primitives/core/src/offchain/storage.rs | 2 +- primitives/core/src/offchain/testing.rs | 2 +- primitives/core/src/sandbox.rs | 2 +- primitives/core/src/sr25519.rs | 2 +- primitives/core/src/testing.rs | 2 +- primitives/core/src/traits.rs | 2 +- primitives/core/src/u32_trait.rs | 2 +- primitives/core/src/uint.rs | 2 +- primitives/database/src/error.rs | 2 +- primitives/database/src/kvdb.rs | 2 +- primitives/database/src/lib.rs | 2 +- primitives/database/src/mem.rs | 2 +- primitives/debug-derive/src/impls.rs | 2 +- primitives/debug-derive/src/lib.rs | 2 +- primitives/debug-derive/tests/tests.rs | 2 +- primitives/externalities/src/extensions.rs | 2 +- primitives/externalities/src/lib.rs | 2 +- primitives/externalities/src/scope_limited.rs | 2 +- primitives/finality-grandpa/src/lib.rs | 2 +- primitives/inherents/src/client_side.rs | 2 +- primitives/inherents/src/lib.rs | 2 +- primitives/io/src/batch_verifier.rs | 2 +- primitives/io/src/lib.rs | 2 +- primitives/keyring/src/ed25519.rs | 2 +- primitives/keyring/src/lib.rs | 2 +- primitives/keyring/src/sr25519.rs | 2 +- primitives/keystore/src/lib.rs | 2 +- primitives/keystore/src/testing.rs | 2 +- primitives/keystore/src/vrf.rs | 2 +- primitives/maybe-compressed-blob/src/lib.rs | 2 +- primitives/npos-elections/fuzzer/src/common.rs | 2 +- primitives/npos-elections/fuzzer/src/phragmen_balancing.rs | 2 +- primitives/npos-elections/fuzzer/src/phragmen_pjr.rs | 2 +- primitives/npos-elections/fuzzer/src/phragmms_balancing.rs | 2 +- primitives/npos-elections/fuzzer/src/reduce.rs | 2 +- primitives/npos-elections/solution-type/src/codec.rs | 2 +- .../npos-elections/solution-type/src/from_assignment_helpers.rs | 2 +- primitives/npos-elections/solution-type/src/index_assignment.rs | 2 +- primitives/npos-elections/solution-type/src/lib.rs | 2 +- primitives/npos-elections/solution-type/src/single_page.rs | 2 +- primitives/npos-elections/src/assignments.rs | 2 +- primitives/npos-elections/src/balancing.rs | 2 +- primitives/npos-elections/src/helpers.rs | 2 +- primitives/npos-elections/src/lib.rs | 2 +- primitives/npos-elections/src/mock.rs | 2 +- primitives/npos-elections/src/node.rs | 2 +- primitives/npos-elections/src/phragmen.rs | 2 +- primitives/npos-elections/src/phragmms.rs | 2 +- primitives/npos-elections/src/pjr.rs | 2 +- primitives/npos-elections/src/reduce.rs | 2 +- primitives/npos-elections/src/tests.rs | 2 +- primitives/npos-elections/src/traits.rs | 2 +- primitives/offchain/src/lib.rs | 2 +- primitives/panic-handler/src/lib.rs | 2 +- primitives/rpc/src/lib.rs | 2 +- primitives/rpc/src/list.rs | 2 +- primitives/rpc/src/number.rs | 2 +- primitives/rpc/src/tracing.rs | 2 +- primitives/runtime-interface/proc-macro/src/lib.rs | 2 +- primitives/runtime-interface/proc-macro/src/pass_by/codec.rs | 2 +- primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs | 2 +- primitives/runtime-interface/proc-macro/src/pass_by/inner.rs | 2 +- primitives/runtime-interface/proc-macro/src/pass_by/mod.rs | 2 +- .../proc-macro/src/runtime_interface/bare_function_interface.rs | 2 +- .../proc-macro/src/runtime_interface/host_function_interface.rs | 2 +- .../runtime-interface/proc-macro/src/runtime_interface/mod.rs | 2 +- .../proc-macro/src/runtime_interface/trait_decl_impl.rs | 2 +- primitives/runtime-interface/proc-macro/src/utils.rs | 2 +- primitives/runtime-interface/src/host.rs | 2 +- primitives/runtime-interface/src/impls.rs | 2 +- primitives/runtime-interface/src/lib.rs | 2 +- primitives/runtime-interface/src/pass_by.rs | 2 +- primitives/runtime-interface/src/util.rs | 2 +- primitives/runtime-interface/src/wasm.rs | 2 +- primitives/runtime-interface/test-wasm-deprecated/build.rs | 2 +- primitives/runtime-interface/test-wasm-deprecated/src/lib.rs | 2 +- primitives/runtime-interface/test-wasm/build.rs | 2 +- primitives/runtime-interface/test-wasm/src/lib.rs | 2 +- primitives/runtime-interface/test/src/lib.rs | 2 +- primitives/runtime-interface/tests/ui.rs | 2 +- primitives/runtime/src/curve.rs | 2 +- primitives/runtime/src/generic/block.rs | 2 +- primitives/runtime/src/generic/checked_extrinsic.rs | 2 +- primitives/runtime/src/generic/digest.rs | 2 +- primitives/runtime/src/generic/era.rs | 2 +- primitives/runtime/src/generic/header.rs | 2 +- primitives/runtime/src/generic/mod.rs | 2 +- primitives/runtime/src/generic/tests.rs | 2 +- primitives/runtime/src/generic/unchecked_extrinsic.rs | 2 +- primitives/runtime/src/lib.rs | 2 +- primitives/runtime/src/multiaddress.rs | 2 +- primitives/runtime/src/offchain/http.rs | 2 +- primitives/runtime/src/offchain/mod.rs | 2 +- primitives/runtime/src/offchain/storage.rs | 2 +- primitives/runtime/src/offchain/storage_lock.rs | 2 +- primitives/runtime/src/runtime_logger.rs | 2 +- primitives/runtime/src/runtime_string.rs | 2 +- primitives/runtime/src/testing.rs | 2 +- primitives/runtime/src/traits.rs | 2 +- primitives/runtime/src/transaction_validity.rs | 2 +- primitives/sandbox/src/embedded_executor.rs | 2 +- primitives/sandbox/src/host_executor.rs | 2 +- primitives/sandbox/src/lib.rs | 2 +- primitives/serializer/src/lib.rs | 2 +- primitives/session/src/lib.rs | 2 +- primitives/staking/src/lib.rs | 2 +- primitives/staking/src/offence.rs | 2 +- primitives/state-machine/src/backend.rs | 2 +- primitives/state-machine/src/basic.rs | 2 +- primitives/state-machine/src/error.rs | 2 +- primitives/state-machine/src/ext.rs | 2 +- primitives/state-machine/src/in_memory_backend.rs | 2 +- primitives/state-machine/src/lib.rs | 2 +- primitives/state-machine/src/overlayed_changes/changeset.rs | 2 +- primitives/state-machine/src/overlayed_changes/mod.rs | 2 +- primitives/state-machine/src/overlayed_changes/offchain.rs | 2 +- primitives/state-machine/src/proving_backend.rs | 2 +- primitives/state-machine/src/read_only.rs | 2 +- primitives/state-machine/src/stats.rs | 2 +- primitives/state-machine/src/testing.rs | 2 +- primitives/state-machine/src/trie_backend.rs | 2 +- primitives/state-machine/src/trie_backend_essence.rs | 2 +- primitives/std/src/lib.rs | 2 +- primitives/std/with_std.rs | 2 +- primitives/std/without_std.rs | 2 +- primitives/storage/src/lib.rs | 2 +- primitives/tasks/src/async_externalities.rs | 2 +- primitives/tasks/src/lib.rs | 2 +- primitives/test-primitives/src/lib.rs | 2 +- primitives/timestamp/src/lib.rs | 2 +- primitives/tracing/src/lib.rs | 2 +- primitives/tracing/src/types.rs | 2 +- primitives/transaction-pool/src/lib.rs | 2 +- primitives/transaction-pool/src/runtime_api.rs | 2 +- primitives/transaction-storage-proof/src/lib.rs | 2 +- primitives/trie/benches/bench.rs | 2 +- primitives/trie/src/error.rs | 2 +- primitives/trie/src/lib.rs | 2 +- primitives/trie/src/node_codec.rs | 2 +- primitives/trie/src/node_header.rs | 2 +- primitives/trie/src/storage_proof.rs | 2 +- primitives/trie/src/trie_codec.rs | 2 +- primitives/trie/src/trie_stream.rs | 2 +- primitives/version/proc-macro/src/decl_runtime_version.rs | 2 +- primitives/version/proc-macro/src/lib.rs | 2 +- primitives/version/src/embed.rs | 2 +- primitives/version/src/lib.rs | 2 +- primitives/wasm-interface/src/lib.rs | 2 +- primitives/wasm-interface/src/wasmi_impl.rs | 2 +- test-utils/client/src/client_ext.rs | 2 +- test-utils/client/src/lib.rs | 2 +- test-utils/derive/src/lib.rs | 2 +- test-utils/runtime/build.rs | 2 +- test-utils/runtime/client/src/block_builder_ext.rs | 2 +- test-utils/runtime/client/src/lib.rs | 2 +- test-utils/runtime/client/src/trait_tests.rs | 2 +- test-utils/runtime/src/genesismap.rs | 2 +- test-utils/runtime/src/lib.rs | 2 +- test-utils/runtime/src/system.rs | 2 +- test-utils/runtime/transaction-pool/src/lib.rs | 2 +- test-utils/src/lib.rs | 2 +- test-utils/test-crate/src/main.rs | 2 +- test-utils/test-runner/src/client.rs | 2 +- test-utils/test-runner/src/host_functions.rs | 2 +- test-utils/test-runner/src/lib.rs | 2 +- test-utils/test-runner/src/node.rs | 2 +- test-utils/test-runner/src/utils.rs | 2 +- test-utils/tests/basic.rs | 2 +- test-utils/tests/ui.rs | 2 +- test-utils/tests/ui/too-many-func-parameters.rs | 2 +- utils/build-script-utils/src/git.rs | 2 +- utils/build-script-utils/src/lib.rs | 2 +- utils/build-script-utils/src/version.rs | 2 +- utils/fork-tree/src/lib.rs | 2 +- utils/frame/benchmarking-cli/src/command.rs | 2 +- utils/frame/benchmarking-cli/src/lib.rs | 2 +- utils/frame/benchmarking-cli/src/writer.rs | 2 +- utils/frame/frame-utilities-cli/src/lib.rs | 2 +- utils/frame/frame-utilities-cli/src/pallet_id.rs | 2 +- utils/frame/generate-bags/node-runtime/src/main.rs | 2 +- utils/frame/generate-bags/src/lib.rs | 2 +- utils/frame/remote-externalities/src/lib.rs | 2 +- utils/frame/remote-externalities/src/rpc_api.rs | 2 +- utils/frame/rpc/support/src/lib.rs | 2 +- utils/frame/rpc/system/src/lib.rs | 2 +- utils/frame/try-runtime/cli/src/commands/execute_block.rs | 2 +- utils/frame/try-runtime/cli/src/commands/follow_chain.rs | 2 +- utils/frame/try-runtime/cli/src/commands/mod.rs | 2 +- utils/frame/try-runtime/cli/src/commands/offchain_worker.rs | 2 +- utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs | 2 +- utils/frame/try-runtime/cli/src/lib.rs | 2 +- utils/frame/try-runtime/cli/src/parse.rs | 2 +- utils/prometheus/src/lib.rs | 2 +- utils/prometheus/src/networking.rs | 2 +- utils/prometheus/src/sourced.rs | 2 +- utils/wasm-builder/src/builder.rs | 2 +- utils/wasm-builder/src/lib.rs | 2 +- utils/wasm-builder/src/prerequisites.rs | 2 +- utils/wasm-builder/src/wasm_project.rs | 2 +- 1121 files changed, 1121 insertions(+), 1121 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 4f34707b96020..34852daf7d47b 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/HEADER-APACHE2 b/HEADER-APACHE2 index f364f4bdf845a..58baa53894ca7 100644 --- a/HEADER-APACHE2 +++ b/HEADER-APACHE2 @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/HEADER-GPL3 b/HEADER-GPL3 index 0dd7e4f76028f..9412b5a70bb35 100644 --- a/HEADER-GPL3 +++ b/HEADER-GPL3 @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/common.rs b/bin/node/bench/src/common.rs index d04d79e9907af..839e26f9f6d13 100644 --- a/bin/node/bench/src/common.rs +++ b/bin/node/bench/src/common.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/construct.rs b/bin/node/bench/src/construct.rs index ca1a1c18f9ea9..50b9db9f019d1 100644 --- a/bin/node/bench/src/construct.rs +++ b/bin/node/bench/src/construct.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/core.rs b/bin/node/bench/src/core.rs index 56c0f3526a4dc..b6ad3ecd80068 100644 --- a/bin/node/bench/src/core.rs +++ b/bin/node/bench/src/core.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/generator.rs b/bin/node/bench/src/generator.rs index d57142893f38f..2b26ed9089a51 100644 --- a/bin/node/bench/src/generator.rs +++ b/bin/node/bench/src/generator.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/import.rs b/bin/node/bench/src/import.rs index da9d0cdaf85b8..faba85468b1fa 100644 --- a/bin/node/bench/src/import.rs +++ b/bin/node/bench/src/import.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/main.rs b/bin/node/bench/src/main.rs index 4b006b387d0ea..f1800214e3e81 100644 --- a/bin/node/bench/src/main.rs +++ b/bin/node/bench/src/main.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/simple_trie.rs b/bin/node/bench/src/simple_trie.rs index 651772c71575f..c59389570e534 100644 --- a/bin/node/bench/src/simple_trie.rs +++ b/bin/node/bench/src/simple_trie.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/state_sizes.rs b/bin/node/bench/src/state_sizes.rs index 27112ed42d455..f97645423edcd 100644 --- a/bin/node/bench/src/state_sizes.rs +++ b/bin/node/bench/src/state_sizes.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/tempdb.rs b/bin/node/bench/src/tempdb.rs index 518c0dd96127c..1e5f3dfbce148 100644 --- a/bin/node/bench/src/tempdb.rs +++ b/bin/node/bench/src/tempdb.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/trie.rs b/bin/node/bench/src/trie.rs index 374ed3568475e..1b4534cbd0f79 100644 --- a/bin/node/bench/src/trie.rs +++ b/bin/node/bench/src/trie.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/txpool.rs b/bin/node/bench/src/txpool.rs index b0db734534855..322dc352e8972 100644 --- a/bin/node/bench/src/txpool.rs +++ b/bin/node/bench/src/txpool.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index f2dbc1fff6be2..69e9e0076a165 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index 2965c6336f0f7..9baa3e7fc117d 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/bin/main.rs b/bin/node/cli/bin/main.rs index cf32a7cf28860..3ae295754561c 100644 --- a/bin/node/cli/bin/main.rs +++ b/bin/node/cli/bin/main.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/build.rs b/bin/node/cli/build.rs index 90aec2222c9ec..e0d5dcea62eda 100644 --- a/bin/node/cli/build.rs +++ b/bin/node/cli/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index b29248519cc08..4d5054113ea0d 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 850581748fde3..59d219a01090e 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index dd8202eb71aac..d9ba53785ba0c 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/src/lib.rs b/bin/node/cli/src/lib.rs index ae851c6cdf628..791140a25484d 100644 --- a/bin/node/cli/src/lib.rs +++ b/bin/node/cli/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index fabf8d0adfdc5..c899975c850c5 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/build_spec_works.rs b/bin/node/cli/tests/build_spec_works.rs index 6d863ea7f949d..aecabed60c849 100644 --- a/bin/node/cli/tests/build_spec_works.rs +++ b/bin/node/cli/tests/build_spec_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/check_block_works.rs b/bin/node/cli/tests/check_block_works.rs index 216bcc6d9fc13..ac853b201b8c6 100644 --- a/bin/node/cli/tests/check_block_works.rs +++ b/bin/node/cli/tests/check_block_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/common.rs b/bin/node/cli/tests/common.rs index 85effc858e155..8391cff355969 100644 --- a/bin/node/cli/tests/common.rs +++ b/bin/node/cli/tests/common.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/export_import_flow.rs b/bin/node/cli/tests/export_import_flow.rs index 937f03b8e5dae..2a2133bbfe4fe 100644 --- a/bin/node/cli/tests/export_import_flow.rs +++ b/bin/node/cli/tests/export_import_flow.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/inspect_works.rs b/bin/node/cli/tests/inspect_works.rs index 6f980d2acbfcb..28ad88dd501d1 100644 --- a/bin/node/cli/tests/inspect_works.rs +++ b/bin/node/cli/tests/inspect_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/purge_chain_works.rs b/bin/node/cli/tests/purge_chain_works.rs index 8a8601c863d95..1a62aec287447 100644 --- a/bin/node/cli/tests/purge_chain_works.rs +++ b/bin/node/cli/tests/purge_chain_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/running_the_node_and_interrupt.rs b/bin/node/cli/tests/running_the_node_and_interrupt.rs index fc5094c2d722f..edce2bbc6e4c5 100644 --- a/bin/node/cli/tests/running_the_node_and_interrupt.rs +++ b/bin/node/cli/tests/running_the_node_and_interrupt.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/telemetry.rs b/bin/node/cli/tests/telemetry.rs index 78a306284c4ac..212fec7a02cf6 100644 --- a/bin/node/cli/tests/telemetry.rs +++ b/bin/node/cli/tests/telemetry.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/temp_base_path_works.rs b/bin/node/cli/tests/temp_base_path_works.rs index 5d8e6c9ec4539..a5b9b7499fc49 100644 --- a/bin/node/cli/tests/temp_base_path_works.rs +++ b/bin/node/cli/tests/temp_base_path_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/version.rs b/bin/node/cli/tests/version.rs index 5ed3a9a8800c8..133eb65f4acef 100644 --- a/bin/node/cli/tests/version.rs +++ b/bin/node/cli/tests/version.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/websocket_server.rs b/bin/node/cli/tests/websocket_server.rs index 658b8de463454..6eecfaf6de53f 100644 --- a/bin/node/cli/tests/websocket_server.rs +++ b/bin/node/cli/tests/websocket_server.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index f1f950182f705..3d7c264a89d1c 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/executor/src/lib.rs b/bin/node/executor/src/lib.rs index 9a7a0c4d3c110..9f87c7d12623c 100644 --- a/bin/node/executor/src/lib.rs +++ b/bin/node/executor/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 6406a04e8dc63..da0f4e6afb319 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index 8d21f086795a4..a2bb91056f474 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index 4767c1bda1fcd..a84ce1470d877 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs index d561e08762dfa..7df13a577006e 100644 --- a/bin/node/executor/tests/submit_transaction.rs +++ b/bin/node/executor/tests/submit_transaction.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/inspect/src/cli.rs b/bin/node/inspect/src/cli.rs index c054fedaf57c4..6e019ca5b2084 100644 --- a/bin/node/inspect/src/cli.rs +++ b/bin/node/inspect/src/cli.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/inspect/src/command.rs b/bin/node/inspect/src/command.rs index e20c91456515c..ce164e0768fbc 100644 --- a/bin/node/inspect/src/command.rs +++ b/bin/node/inspect/src/command.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/inspect/src/lib.rs b/bin/node/inspect/src/lib.rs index 30e7250ea2c6c..722a7903da4c2 100644 --- a/bin/node/inspect/src/lib.rs +++ b/bin/node/inspect/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. // -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/primitives/src/lib.rs b/bin/node/primitives/src/lib.rs index fc3bd5f5114e3..fd000af6b2f1b 100644 --- a/bin/node/primitives/src/lib.rs +++ b/bin/node/primitives/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 51ab191d5e9a5..30f7a0fdf023c 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/runtime/build.rs b/bin/node/runtime/build.rs index a1c4b2d892cfe..b773ed9cf6fb7 100644 --- a/bin/node/runtime/build.rs +++ b/bin/node/runtime/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/runtime/src/constants.rs b/bin/node/runtime/src/constants.rs index 7533025a70b00..23fb13cfb0492 100644 --- a/bin/node/runtime/src/constants.rs +++ b/bin/node/runtime/src/constants.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 689dc8c23fb4f..f73443920c213 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1a4dad1071e15..aab813f29e0aa 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/runtime/src/voter_bags.rs b/bin/node/runtime/src/voter_bags.rs index c4c731a58badc..93790f028f457 100644 --- a/bin/node/runtime/src/voter_bags.rs +++ b/bin/node/runtime/src/voter_bags.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/test-runner-example/src/lib.rs b/bin/node/test-runner-example/src/lib.rs index e247fca223204..8ac450ac12a1e 100644 --- a/bin/node/test-runner-example/src/lib.rs +++ b/bin/node/test-runner-example/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 6a5c4b80e1fef..18333280bb8a4 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/testing/src/client.rs b/bin/node/testing/src/client.rs index 4852e33de6070..8cb98511098f1 100644 --- a/bin/node/testing/src/client.rs +++ b/bin/node/testing/src/client.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index 52296230b055a..2e2f3f9a5a80a 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/testing/src/keyring.rs b/bin/node/testing/src/keyring.rs index 3e6dff301fc45..41dd28bb89988 100644 --- a/bin/node/testing/src/keyring.rs +++ b/bin/node/testing/src/keyring.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/testing/src/lib.rs b/bin/node/testing/src/lib.rs index a3392bcb29d5d..ce3471e5b1f83 100644 --- a/bin/node/testing/src/lib.rs +++ b/bin/node/testing/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/utils/chain-spec-builder/build.rs b/bin/utils/chain-spec-builder/build.rs index 57424f016f3e5..b700b28e322ca 100644 --- a/bin/utils/chain-spec-builder/build.rs +++ b/bin/utils/chain-spec-builder/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index f45031f1eb811..bf58f3110170c 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/utils/subkey/src/lib.rs b/bin/utils/subkey/src/lib.rs index 5052d1b104c2c..9a33ef2d2d6dd 100644 --- a/bin/utils/subkey/src/lib.rs +++ b/bin/utils/subkey/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/utils/subkey/src/main.rs b/bin/utils/subkey/src/main.rs index 2a0f0850713fa..d85c6dbe9d048 100644 --- a/bin/utils/subkey/src/main.rs +++ b/bin/utils/subkey/src/main.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/allocator/src/error.rs b/client/allocator/src/error.rs index 9b9a55325f758..d9fc483224adf 100644 --- a/client/allocator/src/error.rs +++ b/client/allocator/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/allocator/src/freeing_bump.rs b/client/allocator/src/freeing_bump.rs index 741f4012cdcbe..d7152f5a209ea 100644 --- a/client/allocator/src/freeing_bump.rs +++ b/client/allocator/src/freeing_bump.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/allocator/src/lib.rs b/client/allocator/src/lib.rs index 4493db3c7d146..2c3e3b2ae841d 100644 --- a/client/allocator/src/lib.rs +++ b/client/allocator/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 76f2f569814ff..004c0574fcbe8 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/call_executor.rs b/client/api/src/call_executor.rs index b1fd731ca088c..738f932a47bf0 100644 --- a/client/api/src/call_executor.rs +++ b/client/api/src/call_executor.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 21f8aecad0536..b6a5fbfad47a5 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/execution_extensions.rs b/client/api/src/execution_extensions.rs index 56e70cc2b6a62..92efafe91a174 100644 --- a/client/api/src/execution_extensions.rs +++ b/client/api/src/execution_extensions.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index c9650bf6db748..d989004ee2178 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/leaves.rs b/client/api/src/leaves.rs index 80216bc4664bd..2a3b95188e68e 100644 --- a/client/api/src/leaves.rs +++ b/client/api/src/leaves.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/lib.rs b/client/api/src/lib.rs index a7029d02cbd45..aab2fabd5e25e 100644 --- a/client/api/src/lib.rs +++ b/client/api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/notifications.rs b/client/api/src/notifications.rs index 88a709beb1f0b..8199bc6b97101 100644 --- a/client/api/src/notifications.rs +++ b/client/api/src/notifications.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/proof_provider.rs b/client/api/src/proof_provider.rs index 6207139f9758b..3aad4af1befb5 100644 --- a/client/api/src/proof_provider.rs +++ b/client/api/src/proof_provider.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/error.rs b/client/authority-discovery/src/error.rs index d37b6f3b43bc8..26ee02ef85321 100644 --- a/client/authority-discovery/src/error.rs +++ b/client/authority-discovery/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/interval.rs b/client/authority-discovery/src/interval.rs index f4e7c43e60d21..5ddf81fbccc34 100644 --- a/client/authority-discovery/src/interval.rs +++ b/client/authority-discovery/src/interval.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/lib.rs b/client/authority-discovery/src/lib.rs index e619463fa1ad4..8522da9984a6f 100644 --- a/client/authority-discovery/src/lib.rs +++ b/client/authority-discovery/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/service.rs b/client/authority-discovery/src/service.rs index 9b59a4ec8647f..c240e5d0c2287 100644 --- a/client/authority-discovery/src/service.rs +++ b/client/authority-discovery/src/service.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/tests.rs b/client/authority-discovery/src/tests.rs index f1965907f4dad..3b632d2174002 100644 --- a/client/authority-discovery/src/tests.rs +++ b/client/authority-discovery/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index 5ca93b73c8132..ee5a15b9533b7 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/worker/addr_cache.rs b/client/authority-discovery/src/worker/addr_cache.rs index d4ba156d5fa19..3cac5a6bf0348 100644 --- a/client/authority-discovery/src/worker/addr_cache.rs +++ b/client/authority-discovery/src/worker/addr_cache.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/worker/schema/tests.rs b/client/authority-discovery/src/worker/schema/tests.rs index ef96078411e97..b85a4ce37447d 100644 --- a/client/authority-discovery/src/worker/schema/tests.rs +++ b/client/authority-discovery/src/worker/schema/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index 1129427ac8680..904c674d269bc 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index e79fc1f03a545..5ab207e39e583 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/basic-authorship/src/lib.rs b/client/basic-authorship/src/lib.rs index 2b2fe554efdff..4a26ebd9df970 100644 --- a/client/basic-authorship/src/lib.rs +++ b/client/basic-authorship/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 7370ca092727f..be1c9b8691a2a 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/rpc/src/notification.rs b/client/beefy/rpc/src/notification.rs index 4830d72905a98..53c0bb618c5d5 100644 --- a/client/beefy/rpc/src/notification.rs +++ b/client/beefy/rpc/src/notification.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/error.rs b/client/beefy/src/error.rs index db532d34c1e3b..eacadeb7613a5 100644 --- a/client/beefy/src/error.rs +++ b/client/beefy/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/gossip.rs b/client/beefy/src/gossip.rs index dc59f664caa91..37358441ef88a 100644 --- a/client/beefy/src/gossip.rs +++ b/client/beefy/src/gossip.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index eaae17e2015af..32478a11434fa 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index b2372b2a6c518..59a5ff08e16ea 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/metrics.rs b/client/beefy/src/metrics.rs index 55edee962a2ee..4b2a5c8dfd5c9 100644 --- a/client/beefy/src/metrics.rs +++ b/client/beefy/src/metrics.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/notification.rs b/client/beefy/src/notification.rs index 7caaa54352401..cd410ec60bb3c 100644 --- a/client/beefy/src/notification.rs +++ b/client/beefy/src/notification.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index b0df365b4e6f1..e5404cfa6d216 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 306540077ae2f..d3aa988b8ee27 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index c3e91fa055400..a4c6f5aad2aeb 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/chain-spec/derive/src/impls.rs b/client/chain-spec/derive/src/impls.rs index 87a3db063c782..7af403d46ad10 100644 --- a/client/chain-spec/derive/src/impls.rs +++ b/client/chain-spec/derive/src/impls.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/chain-spec/derive/src/lib.rs b/client/chain-spec/derive/src/lib.rs index 53f0c69491ecd..75356a2250465 100644 --- a/client/chain-spec/derive/src/lib.rs +++ b/client/chain-spec/derive/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 520c071d35ce1..98241255de55b 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/chain-spec/src/extension.rs b/client/chain-spec/src/extension.rs index 4b59232cf5770..c0b3e15a2df4c 100644 --- a/client/chain-spec/src/extension.rs +++ b/client/chain-spec/src/extension.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/chain-spec/src/lib.rs b/client/chain-spec/src/lib.rs index cbb1e85df3c1c..64d72760639df 100644 --- a/client/chain-spec/src/lib.rs +++ b/client/chain-spec/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index 5221500f08b33..3e1ead609630a 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/build_spec_cmd.rs b/client/cli/src/commands/build_spec_cmd.rs index 5e43a26a1e67d..ad7cf455eb3b2 100644 --- a/client/cli/src/commands/build_spec_cmd.rs +++ b/client/cli/src/commands/build_spec_cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/check_block_cmd.rs b/client/cli/src/commands/check_block_cmd.rs index de0d1132ce8be..b5642cf4b629b 100644 --- a/client/cli/src/commands/check_block_cmd.rs +++ b/client/cli/src/commands/check_block_cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/export_blocks_cmd.rs b/client/cli/src/commands/export_blocks_cmd.rs index ca3069442a1d3..af7de3c12e77b 100644 --- a/client/cli/src/commands/export_blocks_cmd.rs +++ b/client/cli/src/commands/export_blocks_cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/export_state_cmd.rs b/client/cli/src/commands/export_state_cmd.rs index 36eabd2c24f5c..b322265aee2b5 100644 --- a/client/cli/src/commands/export_state_cmd.rs +++ b/client/cli/src/commands/export_state_cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/generate.rs b/client/cli/src/commands/generate.rs index 7032ebd72e0c7..ce4c24fc7d8c9 100644 --- a/client/cli/src/commands/generate.rs +++ b/client/cli/src/commands/generate.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/generate_node_key.rs b/client/cli/src/commands/generate_node_key.rs index cc26bb73240ac..2221c8a99ded1 100644 --- a/client/cli/src/commands/generate_node_key.rs +++ b/client/cli/src/commands/generate_node_key.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/import_blocks_cmd.rs b/client/cli/src/commands/import_blocks_cmd.rs index 19187f2859621..d0a0b39a5bf8c 100644 --- a/client/cli/src/commands/import_blocks_cmd.rs +++ b/client/cli/src/commands/import_blocks_cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index e85b85f111ad5..631fc4ecef951 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/inspect_key.rs b/client/cli/src/commands/inspect_key.rs index 55dd5dfe80d81..34f51dc5ec42f 100644 --- a/client/cli/src/commands/inspect_key.rs +++ b/client/cli/src/commands/inspect_key.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/inspect_node_key.rs b/client/cli/src/commands/inspect_node_key.rs index 7527fbe4315ae..a5793873dd68f 100644 --- a/client/cli/src/commands/inspect_node_key.rs +++ b/client/cli/src/commands/inspect_node_key.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/key.rs b/client/cli/src/commands/key.rs index 8e1103a8ca512..0bfc68f8c32e2 100644 --- a/client/cli/src/commands/key.rs +++ b/client/cli/src/commands/key.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/mod.rs b/client/cli/src/commands/mod.rs index 9e7c5689b49c8..2b46e1d99caa2 100644 --- a/client/cli/src/commands/mod.rs +++ b/client/cli/src/commands/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/purge_chain_cmd.rs b/client/cli/src/commands/purge_chain_cmd.rs index e1bdb3a03cc59..eb19762df7d8a 100644 --- a/client/cli/src/commands/purge_chain_cmd.rs +++ b/client/cli/src/commands/purge_chain_cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/revert_cmd.rs b/client/cli/src/commands/revert_cmd.rs index 9ad49a03aa5fd..a671469ba7fdf 100644 --- a/client/cli/src/commands/revert_cmd.rs +++ b/client/cli/src/commands/revert_cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 661b3ff382330..08b8fd87e2c82 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/sign.rs b/client/cli/src/commands/sign.rs index 20aacd9bf0020..1b2fbba40ea16 100644 --- a/client/cli/src/commands/sign.rs +++ b/client/cli/src/commands/sign.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/utils.rs b/client/cli/src/commands/utils.rs index 39e5149404b29..7f0413f596012 100644 --- a/client/cli/src/commands/utils.rs +++ b/client/cli/src/commands/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/vanity.rs b/client/cli/src/commands/vanity.rs index d2953c8396079..f2959a33dbfdf 100644 --- a/client/cli/src/commands/vanity.rs +++ b/client/cli/src/commands/vanity.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/verify.rs b/client/cli/src/commands/verify.rs index 0dce444a28590..bf03be1737d48 100644 --- a/client/cli/src/commands/verify.rs +++ b/client/cli/src/commands/verify.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 7ae31eba4245a..cc3b0590566a8 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/error.rs b/client/cli/src/error.rs index 9a09e560063ea..7f3bd84148d12 100644 --- a/client/cli/src/error.rs +++ b/client/cli/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index d20b6f136f1e1..8760e955c69ba 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/database_params.rs b/client/cli/src/params/database_params.rs index 4d6cf5f1d3674..f034ae00473ca 100644 --- a/client/cli/src/params/database_params.rs +++ b/client/cli/src/params/database_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index 3c87e91c220f7..7e1478d71e3fc 100644 --- a/client/cli/src/params/import_params.rs +++ b/client/cli/src/params/import_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/keystore_params.rs b/client/cli/src/params/keystore_params.rs index 951f61bd1bc5f..5dbab5d9e8e34 100644 --- a/client/cli/src/params/keystore_params.rs +++ b/client/cli/src/params/keystore_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/mod.rs b/client/cli/src/params/mod.rs index dac832a1f897c..c7181840a8641 100644 --- a/client/cli/src/params/mod.rs +++ b/client/cli/src/params/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 6eaf068fdaecd..6b7b2680513c3 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index 41f9033d282d1..23f3fba1cdb04 100644 --- a/client/cli/src/params/node_key_params.rs +++ b/client/cli/src/params/node_key_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/offchain_worker_params.rs b/client/cli/src/params/offchain_worker_params.rs index 685328ef17795..ac71d3a7580e7 100644 --- a/client/cli/src/params/offchain_worker_params.rs +++ b/client/cli/src/params/offchain_worker_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index 28c7fa301cc60..facf982ef8dd5 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 4a6fe0d2743ef..d385efad42784 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/transaction_pool_params.rs b/client/cli/src/params/transaction_pool_params.rs index feea19c97c2d6..dee8f57eb39c8 100644 --- a/client/cli/src/params/transaction_pool_params.rs +++ b/client/cli/src/params/transaction_pool_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index d55dfe2537659..f6edd8444735a 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index d2c4ad4498d5e..593ea193c3d12 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 4579b2d73da18..13f0d4e8f8041 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 463b05ef9cd2d..c9d2f9b76c2a2 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 1bee73f40858a..1f74afb0e78b4 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/aux_schema.rs b/client/consensus/babe/src/aux_schema.rs index d5b8a218a5a3f..2ab84b9b132cc 100644 --- a/client/consensus/babe/src/aux_schema.rs +++ b/client/consensus/babe/src/aux_schema.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 7a05c7a92678a..612a05ffaa678 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/migration.rs b/client/consensus/babe/src/migration.rs index a248c9da24db8..a8c3772bbefb8 100644 --- a/client/consensus/babe/src/migration.rs +++ b/client/consensus/babe/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 23c34d21ec7b3..7c04dc03c2f24 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/verification.rs b/client/consensus/babe/src/verification.rs index 13d2f956c8d51..41d1e1bfa5d36 100644 --- a/client/consensus/babe/src/verification.rs +++ b/client/consensus/babe/src/verification.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index aff16566e0de4..af54d54770f76 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/import_queue.rs b/client/consensus/common/src/import_queue.rs index 3f2126ccadf66..f71996fe2b1fa 100644 --- a/client/consensus/common/src/import_queue.rs +++ b/client/consensus/common/src/import_queue.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index 0461d7cf954cb..0f23d9b546bd6 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/import_queue/buffered_link.rs b/client/consensus/common/src/import_queue/buffered_link.rs index 87ea6dde5c473..8fb5689075ab2 100644 --- a/client/consensus/common/src/import_queue/buffered_link.rs +++ b/client/consensus/common/src/import_queue/buffered_link.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/lib.rs b/client/consensus/common/src/lib.rs index 640bad237e882..f291cc2704818 100644 --- a/client/consensus/common/src/lib.rs +++ b/client/consensus/common/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/longest_chain.rs b/client/consensus/common/src/longest_chain.rs index 7ec91a5ad87e9..b38183b8ac11f 100644 --- a/client/consensus/common/src/longest_chain.rs +++ b/client/consensus/common/src/longest_chain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/metrics.rs b/client/consensus/common/src/metrics.rs index ec6ef89f609f4..8314049238b88 100644 --- a/client/consensus/common/src/metrics.rs +++ b/client/consensus/common/src/metrics.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/shared_data.rs b/client/consensus/common/src/shared_data.rs index 7a25660e08aac..17217d997e236 100644 --- a/client/consensus/common/src/shared_data.rs +++ b/client/consensus/common/src/shared_data.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index c1d0bd1d04050..b380d8ed54904 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/epochs/src/migration.rs b/client/consensus/epochs/src/migration.rs index e4b685c6ffb18..c4ed47e9c1c05 100644 --- a/client/consensus/epochs/src/migration.rs +++ b/client/consensus/epochs/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/consensus.rs b/client/consensus/manual-seal/src/consensus.rs index 4284d40179d2f..9bb1d2fe1fae9 100644 --- a/client/consensus/manual-seal/src/consensus.rs +++ b/client/consensus/manual-seal/src/consensus.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 499a82c63e402..b16bee816b172 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/error.rs b/client/consensus/manual-seal/src/error.rs index 8585e6a70d644..28f1a6aed35b4 100644 --- a/client/consensus/manual-seal/src/error.rs +++ b/client/consensus/manual-seal/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/finalize_block.rs b/client/consensus/manual-seal/src/finalize_block.rs index a5ddf1d162f7a..bc242ad6085ee 100644 --- a/client/consensus/manual-seal/src/finalize_block.rs +++ b/client/consensus/manual-seal/src/finalize_block.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index 390c23fe032f1..3e5ce5b2a4014 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/rpc.rs b/client/consensus/manual-seal/src/rpc.rs index 6755879ceedd6..7b4063e9b2b1b 100644 --- a/client/consensus/manual-seal/src/rpc.rs +++ b/client/consensus/manual-seal/src/rpc.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/seal_block.rs b/client/consensus/manual-seal/src/seal_block.rs index 502705b411621..ad840bd102b3f 100644 --- a/client/consensus/manual-seal/src/seal_block.rs +++ b/client/consensus/manual-seal/src/seal_block.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 6ccdf53c0f047..0bcb9f3d00a54 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/pow/src/worker.rs b/client/consensus/pow/src/worker.rs index 3faa18ece3188..031cf7f6a2940 100644 --- a/client/consensus/pow/src/worker.rs +++ b/client/consensus/pow/src/worker.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/slots/build.rs b/client/consensus/slots/build.rs index 57424f016f3e5..b700b28e322ca 100644 --- a/client/consensus/slots/build.rs +++ b/client/consensus/slots/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/slots/src/aux_schema.rs b/client/consensus/slots/src/aux_schema.rs index c2fe3f6f4e6bb..275b12ff48f80 100644 --- a/client/consensus/slots/src/aux_schema.rs +++ b/client/consensus/slots/src/aux_schema.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 905165aa9e369..a1b335f7a5940 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/slots/src/slots.rs b/client/consensus/slots/src/slots.rs index c2ed986e1e7f8..2b792af7da8c4 100644 --- a/client/consensus/slots/src/slots.rs +++ b/client/consensus/slots/src/slots.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/uncles/src/lib.rs b/client/consensus/uncles/src/lib.rs index 368a994cfe520..d03c2f8aa6b49 100644 --- a/client/consensus/uncles/src/lib.rs +++ b/client/consensus/uncles/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index cafafca9b635c..a18e7942a54f4 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/children.rs b/client/db/src/children.rs index c11e4204997d1..538e51851f081 100644 --- a/client/db/src/children.rs +++ b/client/db/src/children.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 137c26fb82188..c570ca2f15fbe 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/offchain.rs b/client/db/src/offchain.rs index c31273ff07c63..c6351a66a2350 100644 --- a/client/db/src/offchain.rs +++ b/client/db/src/offchain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/parity_db.rs b/client/db/src/parity_db.rs index 61c0b94dc701c..ebe2988e27f04 100644 --- a/client/db/src/parity_db.rs +++ b/client/db/src/parity_db.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/stats.rs b/client/db/src/stats.rs index 9223142ef5aba..f6c14568236e9 100644 --- a/client/db/src/stats.rs +++ b/client/db/src/stats.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/storage_cache.rs b/client/db/src/storage_cache.rs index 579703ea9db85..5047087376375 100644 --- a/client/db/src/storage_cache.rs +++ b/client/db/src/storage_cache.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/upgrade.rs b/client/db/src/upgrade.rs index 0f3578ad99a37..a42a1960a57c3 100644 --- a/client/db/src/upgrade.rs +++ b/client/db/src/upgrade.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index b098a7864bafb..c3a60962a67da 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/error.rs b/client/executor/common/src/error.rs index 6ad4802e57a8b..90e658a896281 100644 --- a/client/executor/common/src/error.rs +++ b/client/executor/common/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/lib.rs b/client/executor/common/src/lib.rs index 99b927e062038..b69883afbaac2 100644 --- a/client/executor/common/src/lib.rs +++ b/client/executor/common/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/runtime_blob/data_segments_snapshot.rs b/client/executor/common/src/runtime_blob/data_segments_snapshot.rs index 5c3fedbdc963e..76f2ad2c345ee 100644 --- a/client/executor/common/src/runtime_blob/data_segments_snapshot.rs +++ b/client/executor/common/src/runtime_blob/data_segments_snapshot.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/runtime_blob/globals_snapshot.rs b/client/executor/common/src/runtime_blob/globals_snapshot.rs index a25fa6f9fd639..207fa751bc408 100644 --- a/client/executor/common/src/runtime_blob/globals_snapshot.rs +++ b/client/executor/common/src/runtime_blob/globals_snapshot.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/runtime_blob/mod.rs b/client/executor/common/src/runtime_blob/mod.rs index 1af2708d3eb47..4b163bbaaf329 100644 --- a/client/executor/common/src/runtime_blob/mod.rs +++ b/client/executor/common/src/runtime_blob/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/runtime_blob/runtime_blob.rs b/client/executor/common/src/runtime_blob/runtime_blob.rs index 6fb9303e07758..8318cce7a9bad 100644 --- a/client/executor/common/src/runtime_blob/runtime_blob.rs +++ b/client/executor/common/src/runtime_blob/runtime_blob.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/sandbox.rs b/client/executor/common/src/sandbox.rs index b627294241252..34162b7dc4978 100644 --- a/client/executor/common/src/sandbox.rs +++ b/client/executor/common/src/sandbox.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/util.rs b/client/executor/common/src/util.rs index ffbeb8c7ab533..eddf4230504c7 100644 --- a/client/executor/common/src/util.rs +++ b/client/executor/common/src/util.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/wasm_runtime.rs b/client/executor/common/src/wasm_runtime.rs index 1e9f1225518a3..d43ad758b144c 100644 --- a/client/executor/common/src/wasm_runtime.rs +++ b/client/executor/common/src/wasm_runtime.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/runtime-test/build.rs b/client/executor/runtime-test/build.rs index 9456d6bc90f4c..27f931a542d4a 100644 --- a/client/executor/runtime-test/build.rs +++ b/client/executor/runtime-test/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/integration_tests/linux.rs b/client/executor/src/integration_tests/linux.rs index 38e57707e9e6b..8775a35cb83cc 100644 --- a/client/executor/src/integration_tests/linux.rs +++ b/client/executor/src/integration_tests/linux.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/integration_tests/linux/smaps.rs b/client/executor/src/integration_tests/linux/smaps.rs index b23a188b93a26..665155ff81ea8 100644 --- a/client/executor/src/integration_tests/linux/smaps.rs +++ b/client/executor/src/integration_tests/linux/smaps.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index c480ad74ade67..36339c31871d9 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/integration_tests/sandbox.rs b/client/executor/src/integration_tests/sandbox.rs index 2b536f541f088..643db5097c6ad 100644 --- a/client/executor/src/integration_tests/sandbox.rs +++ b/client/executor/src/integration_tests/sandbox.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/lib.rs b/client/executor/src/lib.rs index 8bac541afc37d..fd127887dbc26 100644 --- a/client/executor/src/lib.rs +++ b/client/executor/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 60e661d10da67..b36d6f1297e91 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 94c4f431ef45a..cb6fba4e4dee5 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index ceab07c2f71cb..78fd300e05e3d 100644 --- a/client/executor/wasmi/src/lib.rs +++ b/client/executor/wasmi/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/build.rs b/client/executor/wasmtime/build.rs index 6ab581c9c2685..c514b0041bc34 100644 --- a/client/executor/wasmtime/build.rs +++ b/client/executor/wasmtime/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index ab8b4cf8b73c0..5d02a836640ae 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/imports.rs b/client/executor/wasmtime/src/imports.rs index c18cf58ac722e..636a5761c9475 100644 --- a/client/executor/wasmtime/src/imports.rs +++ b/client/executor/wasmtime/src/imports.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index 58f96eb26363e..af21a8080cd58 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/lib.rs b/client/executor/wasmtime/src/lib.rs index e0d6a262afda9..c54c8305f3e4b 100644 --- a/client/executor/wasmtime/src/lib.rs +++ b/client/executor/wasmtime/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index b870405f92d3d..6300163db50ca 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index 31fb5d3da1c72..c1e626f12d1aa 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/util.rs b/client/executor/wasmtime/src/util.rs index 2c9379e9ce812..60ca598aee181 100644 --- a/client/executor/wasmtime/src/util.rs +++ b/client/executor/wasmtime/src/util.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/rpc/src/error.rs b/client/finality-grandpa/rpc/src/error.rs index c812b78f3fd8e..1c1361bcaeda7 100644 --- a/client/finality-grandpa/rpc/src/error.rs +++ b/client/finality-grandpa/rpc/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/rpc/src/finality.rs b/client/finality-grandpa/rpc/src/finality.rs index 62e3502fc7180..f2be6d674b2f1 100644 --- a/client/finality-grandpa/rpc/src/finality.rs +++ b/client/finality-grandpa/rpc/src/finality.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index 3e7fddfddf2ff..e509d435af4ad 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/rpc/src/notification.rs b/client/finality-grandpa/rpc/src/notification.rs index 68944e903e0fb..6fb1383579359 100644 --- a/client/finality-grandpa/rpc/src/notification.rs +++ b/client/finality-grandpa/rpc/src/notification.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/rpc/src/report.rs b/client/finality-grandpa/rpc/src/report.rs index fc97c176f34f0..24d0b5ab0d1d6 100644 --- a/client/finality-grandpa/rpc/src/report.rs +++ b/client/finality-grandpa/rpc/src/report.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 6ab36847fe3dd..aa8be83b9529a 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/finality-grandpa/src/aux_schema.rs index 9294fbc4161b0..2ec48a804c936 100644 --- a/client/finality-grandpa/src/aux_schema.rs +++ b/client/finality-grandpa/src/aux_schema.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 74e7cc5300654..51d832c3b27be 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index c370e1d642d7d..43b2f5463c8db 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/communication/periodic.rs b/client/finality-grandpa/src/communication/periodic.rs index 77e55ad652f6c..e6d63beafc362 100644 --- a/client/finality-grandpa/src/communication/periodic.rs +++ b/client/finality-grandpa/src/communication/periodic.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index 1e88f8a934047..ed23415972f95 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 1f5b381c1382a..bbd739086ba51 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index ac7be37eb20ca..cc6853bee3b07 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index 000f7397ac9d9..71d74045f4760 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/justification.rs b/client/finality-grandpa/src/justification.rs index a852c74d9d1a4..5ee5f278ed8b6 100644 --- a/client/finality-grandpa/src/justification.rs +++ b/client/finality-grandpa/src/justification.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 656d8ea434349..b8873d00efa7c 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/notification.rs b/client/finality-grandpa/src/notification.rs index 85d581bd5065e..0d154fb3357e4 100644 --- a/client/finality-grandpa/src/notification.rs +++ b/client/finality-grandpa/src/notification.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 70a94cd504726..ab0c69ef7fc26 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 7af02d066be32..f619c03cab6f1 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/until_imported.rs b/client/finality-grandpa/src/until_imported.rs index 430db23d62204..6adce0d920209 100644 --- a/client/finality-grandpa/src/until_imported.rs +++ b/client/finality-grandpa/src/until_imported.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/voting_rule.rs b/client/finality-grandpa/src/voting_rule.rs index 7c8d94d970f86..749c504a051c1 100644 --- a/client/finality-grandpa/src/voting_rule.rs +++ b/client/finality-grandpa/src/voting_rule.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/informant/src/display.rs b/client/informant/src/display.rs index 6496172b80891..8d76939fddd6f 100644 --- a/client/informant/src/display.rs +++ b/client/informant/src/display.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/informant/src/lib.rs b/client/informant/src/lib.rs index f421dbbb7e564..88a500a3a98fa 100644 --- a/client/informant/src/lib.rs +++ b/client/informant/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/keystore/src/lib.rs b/client/keystore/src/lib.rs index 5e29f691997e6..83641f267bc8c 100644 --- a/client/keystore/src/lib.rs +++ b/client/keystore/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index be9bb5e145977..9c8e3baab1828 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 477b0678fcc8f..f72cd15616515 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network-gossip/src/lib.rs b/client/network-gossip/src/lib.rs index 4b8b4e39862ba..4b83708702466 100644 --- a/client/network-gossip/src/lib.rs +++ b/client/network-gossip/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 63553f2f16029..7ad9853b3615e 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network-gossip/src/validator.rs b/client/network-gossip/src/validator.rs index 9a2652d03f642..7d60f7b31397f 100644 --- a/client/network-gossip/src/validator.rs +++ b/client/network-gossip/src/validator.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index a6a67d7bce2d1..d0de50ef61897 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/chain.rs b/client/network/src/chain.rs index 7c131dd75370f..c66cc2ce1daf5 100644 --- a/client/network/src/chain.rs +++ b/client/network/src/chain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 8ef52e46fd071..333ea41c8d80b 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index dc08ab57ed3f6..cf75e2dcb4c65 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/error.rs b/client/network/src/error.rs index b8a31def7dc61..1dafddd7bcc55 100644 --- a/client/network/src/error.rs +++ b/client/network/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index d07e9d3baaa42..27e9a7547b44f 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/light_client_requests.rs b/client/network/src/light_client_requests.rs index b1793ce9384ed..c77416003f821 100644 --- a/client/network/src/light_client_requests.rs +++ b/client/network/src/light_client_requests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/light_client_requests/handler.rs b/client/network/src/light_client_requests/handler.rs index 5ecc85bdb0a0f..b5c6ccb196d5b 100644 --- a/client/network/src/light_client_requests/handler.rs +++ b/client/network/src/light_client_requests/handler.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/network_state.rs b/client/network/src/network_state.rs index 6f5f031bf35df..a5e2fbef421db 100644 --- a/client/network/src/network_state.rs +++ b/client/network/src/network_state.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index 2c37fdb460a76..378c258820ffb 100644 --- a/client/network/src/peer_info.rs +++ b/client/network/src/peer_info.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index abd723f13d206..a5a826ed4748c 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/event.rs b/client/network/src/protocol/event.rs index e0b35647c7531..26c9544960605 100644 --- a/client/network/src/protocol/event.rs +++ b/client/network/src/protocol/event.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index 001f6cbd7e455..3fb57b1c824a9 100644 --- a/client/network/src/protocol/message.rs +++ b/client/network/src/protocol/message.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications.rs b/client/network/src/protocol/notifications.rs index e489970e987c6..bf183abf160cb 100644 --- a/client/network/src/protocol/notifications.rs +++ b/client/network/src/protocol/notifications.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 26a246f57690f..97047201c308c 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index db0385bea8f69..158ab2ae379c6 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/tests.rs b/client/network/src/protocol/notifications/tests.rs index ffc25194def09..73058598a1e3b 100644 --- a/client/network/src/protocol/notifications/tests.rs +++ b/client/network/src/protocol/notifications/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/upgrade.rs b/client/network/src/protocol/notifications/upgrade.rs index 196b4f44f81f7..c273361acabdd 100644 --- a/client/network/src/protocol/notifications/upgrade.rs +++ b/client/network/src/protocol/notifications/upgrade.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/upgrade/collec.rs b/client/network/src/protocol/notifications/upgrade/collec.rs index 2462d2becf4b1..db9850c8da74b 100644 --- a/client/network/src/protocol/notifications/upgrade/collec.rs +++ b/client/network/src/protocol/notifications/upgrade/collec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 997a1ccf1dec7..5171d459fa400 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index a84f5131242ef..69722dac22bcb 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/sync/blocks.rs b/client/network/src/protocol/sync/blocks.rs index ce4535dc0b45f..43b70d17d8add 100644 --- a/client/network/src/protocol/sync/blocks.rs +++ b/client/network/src/protocol/sync/blocks.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/sync/extra_requests.rs b/client/network/src/protocol/sync/extra_requests.rs index c00837169598b..680094a74143e 100644 --- a/client/network/src/protocol/sync/extra_requests.rs +++ b/client/network/src/protocol/sync/extra_requests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/sync/state.rs b/client/network/src/protocol/sync/state.rs index 43aa1c4629f0e..3de165b83d9e0 100644 --- a/client/network/src/protocol/sync/state.rs +++ b/client/network/src/protocol/sync/state.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/sync/warp.rs b/client/network/src/protocol/sync/warp.rs index bbf8a28da14a6..6c51d4b3495f0 100644 --- a/client/network/src/protocol/sync/warp.rs +++ b/client/network/src/protocol/sync/warp.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index aa3e1701eee52..24b3d3df00b2d 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/schema.rs b/client/network/src/schema.rs index d4572fca7594c..032db5f1733c5 100644 --- a/client/network/src/schema.rs +++ b/client/network/src/schema.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 8b153bc4edf54..9c8c58ef49e4d 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/service/metrics.rs b/client/network/src/service/metrics.rs index 2550f255e848c..bf94287d12918 100644 --- a/client/network/src/service/metrics.rs +++ b/client/network/src/service/metrics.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 90888c2371f9f..5f088b85b1cfc 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/service/signature.rs b/client/network/src/service/signature.rs index c2d6c4f7db6e8..d21d28a3007b5 100644 --- a/client/network/src/service/signature.rs +++ b/client/network/src/service/signature.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. // -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 8271da886fca7..3dfd7392cd4dd 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 21fc55acd274b..c09c6b88dab8b 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/transport.rs b/client/network/src/transport.rs index 3f977a21b1165..9a8e080234f32 100644 --- a/client/network/src/transport.rs +++ b/client/network/src/transport.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/utils.rs b/client/network/src/utils.rs index b23b7e0c101e0..d0e61a0d0475d 100644 --- a/client/network/src/utils.rs +++ b/client/network/src/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/test/src/block_import.rs b/client/network/test/src/block_import.rs index 7a4c4f6c83081..a2bd5276c31d6 100644 --- a/client/network/test/src/block_import.rs +++ b/client/network/test/src/block_import.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index cfd42327b6003..d9e27ce575110 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index 4828cae842218..5b607a7762b34 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index c2830510b015c..30c7969279ee2 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index 632c94b481074..bc8f81f25a643 100644 --- a/client/offchain/src/api/http.rs +++ b/client/offchain/src/api/http.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/offchain/src/api/timestamp.rs b/client/offchain/src/api/timestamp.rs index f1c8c004a0198..6622331f570df 100644 --- a/client/offchain/src/api/timestamp.rs +++ b/client/offchain/src/api/timestamp.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index f9230a1552e1e..cc49c07bffcf4 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/peerset/src/lib.rs b/client/peerset/src/lib.rs index 7fbda1ba7b7f8..c777cfec19d25 100644 --- a/client/peerset/src/lib.rs +++ b/client/peerset/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/peerset/src/peersstate.rs b/client/peerset/src/peersstate.rs index d7a9ef9135876..272b903c1da2b 100644 --- a/client/peerset/src/peersstate.rs +++ b/client/peerset/src/peersstate.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/peerset/tests/fuzz.rs b/client/peerset/tests/fuzz.rs index 3a9ba686ee95c..af4838d724cbf 100644 --- a/client/peerset/tests/fuzz.rs +++ b/client/peerset/tests/fuzz.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/proposer-metrics/src/lib.rs b/client/proposer-metrics/src/lib.rs index ca60cafef3f6b..a34660faab5d3 100644 --- a/client/proposer-metrics/src/lib.rs +++ b/client/proposer-metrics/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/author/error.rs b/client/rpc-api/src/author/error.rs index c7e3ccffabbb7..5b6bec7ed4bdc 100644 --- a/client/rpc-api/src/author/error.rs +++ b/client/rpc-api/src/author/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/author/hash.rs b/client/rpc-api/src/author/hash.rs index c4acfb819ddbb..453947dd21f26 100644 --- a/client/rpc-api/src/author/hash.rs +++ b/client/rpc-api/src/author/hash.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/author/mod.rs b/client/rpc-api/src/author/mod.rs index 720598e0b32a8..84167ee95d108 100644 --- a/client/rpc-api/src/author/mod.rs +++ b/client/rpc-api/src/author/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/chain/error.rs b/client/rpc-api/src/chain/error.rs index c7f14b2dfc168..a0cacb6739155 100644 --- a/client/rpc-api/src/chain/error.rs +++ b/client/rpc-api/src/chain/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/chain/mod.rs b/client/rpc-api/src/chain/mod.rs index 79ae80d0c4d1d..d7d598942f1ea 100644 --- a/client/rpc-api/src/chain/mod.rs +++ b/client/rpc-api/src/chain/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/child_state/mod.rs b/client/rpc-api/src/child_state/mod.rs index de94790d09907..6b4cd20f22605 100644 --- a/client/rpc-api/src/child_state/mod.rs +++ b/client/rpc-api/src/child_state/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/errors.rs b/client/rpc-api/src/errors.rs index 8e4883a4cc20c..42e563342fa4d 100644 --- a/client/rpc-api/src/errors.rs +++ b/client/rpc-api/src/errors.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/helpers.rs b/client/rpc-api/src/helpers.rs index a26adbf2e9032..2fbd2f5040463 100644 --- a/client/rpc-api/src/helpers.rs +++ b/client/rpc-api/src/helpers.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/lib.rs b/client/rpc-api/src/lib.rs index 92de1e7fcb344..2b2e09e709aa9 100644 --- a/client/rpc-api/src/lib.rs +++ b/client/rpc-api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/metadata.rs b/client/rpc-api/src/metadata.rs index d493b92c11ac5..3c798782062e9 100644 --- a/client/rpc-api/src/metadata.rs +++ b/client/rpc-api/src/metadata.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/offchain/error.rs b/client/rpc-api/src/offchain/error.rs index 6b8e2bfe189b1..41f1416bfb367 100644 --- a/client/rpc-api/src/offchain/error.rs +++ b/client/rpc-api/src/offchain/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/offchain/mod.rs b/client/rpc-api/src/offchain/mod.rs index 333892fc19c4c..c76e83011072d 100644 --- a/client/rpc-api/src/offchain/mod.rs +++ b/client/rpc-api/src/offchain/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/policy.rs b/client/rpc-api/src/policy.rs index 5d56c62bfece3..4d1e1d7c4ce7c 100644 --- a/client/rpc-api/src/policy.rs +++ b/client/rpc-api/src/policy.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/state/error.rs b/client/rpc-api/src/state/error.rs index d700863476329..4414629e2e294 100644 --- a/client/rpc-api/src/state/error.rs +++ b/client/rpc-api/src/state/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/state/helpers.rs b/client/rpc-api/src/state/helpers.rs index 718ad69ac232c..25f07be1c97c8 100644 --- a/client/rpc-api/src/state/helpers.rs +++ b/client/rpc-api/src/state/helpers.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/state/mod.rs b/client/rpc-api/src/state/mod.rs index 1cc191197232b..453e954ce5952 100644 --- a/client/rpc-api/src/state/mod.rs +++ b/client/rpc-api/src/state/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/system/error.rs b/client/rpc-api/src/system/error.rs index 4ba5125d82bc1..050d79b6ad636 100644 --- a/client/rpc-api/src/system/error.rs +++ b/client/rpc-api/src/system/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/system/helpers.rs b/client/rpc-api/src/system/helpers.rs index 96e8aeb1ae3d7..e17e0f518c3e6 100644 --- a/client/rpc-api/src/system/helpers.rs +++ b/client/rpc-api/src/system/helpers.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/system/mod.rs b/client/rpc-api/src/system/mod.rs index 3ffc5f4346508..b610094f5b58d 100644 --- a/client/rpc-api/src/system/mod.rs +++ b/client/rpc-api/src/system/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 82da848343209..963d9aec072f5 100644 --- a/client/rpc-servers/src/lib.rs +++ b/client/rpc-servers/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-servers/src/middleware.rs b/client/rpc-servers/src/middleware.rs index a78c0642cb584..4adc878660090 100644 --- a/client/rpc-servers/src/middleware.rs +++ b/client/rpc-servers/src/middleware.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 5046f26319207..2b604d2897c58 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/author/tests.rs b/client/rpc/src/author/tests.rs index 5c1ade96f96b7..c555465645a74 100644 --- a/client/rpc/src/author/tests.rs +++ b/client/rpc/src/author/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/chain/chain_full.rs b/client/rpc/src/chain/chain_full.rs index 96d5b86f42498..288a825eb5bed 100644 --- a/client/rpc/src/chain/chain_full.rs +++ b/client/rpc/src/chain/chain_full.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index c2f512c338b11..c20e5a188ad3d 100644 --- a/client/rpc/src/chain/mod.rs +++ b/client/rpc/src/chain/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/chain/tests.rs b/client/rpc/src/chain/tests.rs index caa9f33138b86..fa4473d35f300 100644 --- a/client/rpc/src/chain/tests.rs +++ b/client/rpc/src/chain/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/lib.rs b/client/rpc/src/lib.rs index 8f951632698fd..3966baf13c756 100644 --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/offchain/mod.rs b/client/rpc/src/offchain/mod.rs index 9d1cc702b51e0..67b97d31ab949 100644 --- a/client/rpc/src/offchain/mod.rs +++ b/client/rpc/src/offchain/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/offchain/tests.rs b/client/rpc/src/offchain/tests.rs index f9629e70198a3..219eeb192dfdd 100644 --- a/client/rpc/src/offchain/tests.rs +++ b/client/rpc/src/offchain/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index bacf39124abc1..071db5324c836 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index d3b41d2f18279..2c5a985a2b016 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 12e1c449d3bd4..d3aca181a41e8 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/system/mod.rs b/client/rpc/src/system/mod.rs index f99994e41a1be..534e446e140ad 100644 --- a/client/rpc/src/system/mod.rs +++ b/client/rpc/src/system/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index c64449ff13aa2..3e5241e2638b2 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/testing.rs b/client/rpc/src/testing.rs index 23071ba10e0d6..bfb91adb81d31 100644 --- a/client/rpc/src/testing.rs +++ b/client/rpc/src/testing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 718cfce981f1a..262ba53a33d49 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/check_block.rs b/client/service/src/chain_ops/check_block.rs index 5e2a9faaf0c4f..e12766659d9a9 100644 --- a/client/service/src/chain_ops/check_block.rs +++ b/client/service/src/chain_ops/check_block.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/export_blocks.rs b/client/service/src/chain_ops/export_blocks.rs index 8887180103182..d442a11f2c39b 100644 --- a/client/service/src/chain_ops/export_blocks.rs +++ b/client/service/src/chain_ops/export_blocks.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/export_raw_state.rs b/client/service/src/chain_ops/export_raw_state.rs index 975149c61cfab..ffe91d0d7355e 100644 --- a/client/service/src/chain_ops/export_raw_state.rs +++ b/client/service/src/chain_ops/export_raw_state.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/import_blocks.rs b/client/service/src/chain_ops/import_blocks.rs index e4096afacdd3b..aa72b745c7cac 100644 --- a/client/service/src/chain_ops/import_blocks.rs +++ b/client/service/src/chain_ops/import_blocks.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/mod.rs b/client/service/src/chain_ops/mod.rs index c213e745a5d6b..98245eeb98d08 100644 --- a/client/service/src/chain_ops/mod.rs +++ b/client/service/src/chain_ops/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/revert_chain.rs b/client/service/src/chain_ops/revert_chain.rs index 63f1cbd15dd63..9a3ce6024ed92 100644 --- a/client/service/src/chain_ops/revert_chain.rs +++ b/client/service/src/chain_ops/revert_chain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/block_rules.rs b/client/service/src/client/block_rules.rs index 4bdf338362960..519d5a13f5168 100644 --- a/client/service/src/client/block_rules.rs +++ b/client/service/src/client/block_rules.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 2acbbb75dcb1d..f2b45bc413e2a 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 1f76fe017ae07..452450c71e785 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/genesis.rs b/client/service/src/client/genesis.rs index b48ca2464b54e..35fb11f04972a 100644 --- a/client/service/src/client/genesis.rs +++ b/client/service/src/client/genesis.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/mod.rs b/client/service/src/client/mod.rs index d10b3d16b8139..eac744923d501 100644 --- a/client/service/src/client/mod.rs +++ b/client/service/src/client/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/wasm_override.rs b/client/service/src/client/wasm_override.rs index 88b2c3895b026..86365f2d0cab4 100644 --- a/client/service/src/client/wasm_override.rs +++ b/client/service/src/client/wasm_override.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/wasm_substitutes.rs b/client/service/src/client/wasm_substitutes.rs index 28975790e9b57..6f9a6dff43c74 100644 --- a/client/service/src/client/wasm_substitutes.rs +++ b/client/service/src/client/wasm_substitutes.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/config.rs b/client/service/src/config.rs index db2041ed96f16..45a6f832f8ee1 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/error.rs b/client/service/src/error.rs index 1acd33ead6777..be2199de2643d 100644 --- a/client/service/src/error.rs +++ b/client/service/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 9cf5cc69bdc35..9710ba9e3d84f 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index 54550330d75e5..02e3ab95f1187 100644 --- a/client/service/src/metrics.rs +++ b/client/service/src/metrics.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/task_manager/mod.rs b/client/service/src/task_manager/mod.rs index e09a351b60927..2f9cd257c360b 100644 --- a/client/service/src/task_manager/mod.rs +++ b/client/service/src/task_manager/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/task_manager/prometheus_future.rs b/client/service/src/task_manager/prometheus_future.rs index 43a76a0f596c2..88296a67336fe 100644 --- a/client/service/src/task_manager/prometheus_future.rs +++ b/client/service/src/task_manager/prometheus_future.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/task_manager/tests.rs b/client/service/src/task_manager/tests.rs index f14023f34f6bd..323110a4e1b0c 100644 --- a/client/service/src/task_manager/tests.rs +++ b/client/service/src/task_manager/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/test/src/client/db.rs b/client/service/test/src/client/db.rs index 5278c9a13a4d7..5c1315fc870cd 100644 --- a/client/service/test/src/client/db.rs +++ b/client/service/test/src/client/db.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index cd4ce132b6634..535edfadaf29d 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 7033001db43c4..67b33dfd55d13 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 44629975d7813..b7d58bb808a73 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index c726ceae4b058..0509e54946e92 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/state-db/src/pruning.rs b/client/state-db/src/pruning.rs index 465c1ecda6cc1..2631405cdffa7 100644 --- a/client/state-db/src/pruning.rs +++ b/client/state-db/src/pruning.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/state-db/src/test.rs b/client/state-db/src/test.rs index ad5ce8e874cc7..9fb97036b2f24 100644 --- a/client/state-db/src/test.rs +++ b/client/state-db/src/test.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index a1621e3986d76..f416b3a0e8f73 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/telemetry/src/endpoints.rs b/client/telemetry/src/endpoints.rs index 62e6180311980..fba3822a90676 100644 --- a/client/telemetry/src/endpoints.rs +++ b/client/telemetry/src/endpoints.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/telemetry/src/error.rs b/client/telemetry/src/error.rs index 90a8018f4e1d3..4d9cdc05c51b9 100644 --- a/client/telemetry/src/error.rs +++ b/client/telemetry/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/telemetry/src/lib.rs b/client/telemetry/src/lib.rs index 2e50bf5884fa7..68128e0207085 100644 --- a/client/telemetry/src/lib.rs +++ b/client/telemetry/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/telemetry/src/node.rs b/client/telemetry/src/node.rs index 4d845c328fe89..ec857ede70fdb 100644 --- a/client/telemetry/src/node.rs +++ b/client/telemetry/src/node.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/telemetry/src/transport.rs b/client/telemetry/src/transport.rs index 04ec79ebf5645..23725b44a64dd 100644 --- a/client/telemetry/src/transport.rs +++ b/client/telemetry/src/transport.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/benches/bench.rs b/client/tracing/benches/bench.rs index ee218958be9b3..a939a26797396 100644 --- a/client/tracing/benches/bench.rs +++ b/client/tracing/benches/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/tracing/proc-macro/src/lib.rs b/client/tracing/proc-macro/src/lib.rs index 005fcf4ba0f51..b1ffcb97b752e 100644 --- a/client/tracing/proc-macro/src/lib.rs +++ b/client/tracing/proc-macro/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/lib.rs b/client/tracing/src/lib.rs index fc501bb9a4323..cbbd8063c34fa 100644 --- a/client/tracing/src/lib.rs +++ b/client/tracing/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/event_format.rs b/client/tracing/src/logging/event_format.rs index 944901d803bda..aec6b76843daf 100644 --- a/client/tracing/src/logging/event_format.rs +++ b/client/tracing/src/logging/event_format.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/fast_local_time.rs b/client/tracing/src/logging/fast_local_time.rs index 288e44aa5e3af..47fc23340482a 100644 --- a/client/tracing/src/logging/fast_local_time.rs +++ b/client/tracing/src/logging/fast_local_time.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/layers/mod.rs b/client/tracing/src/logging/layers/mod.rs index 7dd0c4d120ad7..382b79bc85d73 100644 --- a/client/tracing/src/logging/layers/mod.rs +++ b/client/tracing/src/logging/layers/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/layers/prefix_layer.rs b/client/tracing/src/logging/layers/prefix_layer.rs index 2ad786a092233..836ffd2adda8e 100644 --- a/client/tracing/src/logging/layers/prefix_layer.rs +++ b/client/tracing/src/logging/layers/prefix_layer.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index 72740715e55b4..c325a3f73c413 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/stderr_writer.rs b/client/tracing/src/logging/stderr_writer.rs index 9aab2491fb872..e62c5e82c1ac7 100644 --- a/client/tracing/src/logging/stderr_writer.rs +++ b/client/tracing/src/logging/stderr_writer.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/api/src/error.rs b/client/transaction-pool/api/src/error.rs index feee3b0a949c2..f1ac2798e62d3 100644 --- a/client/transaction-pool/api/src/error.rs +++ b/client/transaction-pool/api/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index cd8784bfc83e2..f19a994b1b947 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index cfb40c6cb2ab7..c6b15ce4f1777 100644 --- a/client/transaction-pool/benches/basics.rs +++ b/client/transaction-pool/benches/basics.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index 08fe1e34edb88..de1c79534b386 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/error.rs b/client/transaction-pool/src/error.rs index b14e0569f0830..adc19d52c7e41 100644 --- a/client/transaction-pool/src/error.rs +++ b/client/transaction-pool/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/base_pool.rs b/client/transaction-pool/src/graph/base_pool.rs index cf634c3213a84..8e0422739cc63 100644 --- a/client/transaction-pool/src/graph/base_pool.rs +++ b/client/transaction-pool/src/graph/base_pool.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/future.rs b/client/transaction-pool/src/graph/future.rs index 6ed1f1014304f..ae49e3f2d3aed 100644 --- a/client/transaction-pool/src/graph/future.rs +++ b/client/transaction-pool/src/graph/future.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/listener.rs b/client/transaction-pool/src/graph/listener.rs index b8149018f7836..d4f42b32fdbb8 100644 --- a/client/transaction-pool/src/graph/listener.rs +++ b/client/transaction-pool/src/graph/listener.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/mod.rs b/client/transaction-pool/src/graph/mod.rs index 3ecfb8fe68c60..42812897a954b 100644 --- a/client/transaction-pool/src/graph/mod.rs +++ b/client/transaction-pool/src/graph/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 1032282af99dc..3d0f8a017a971 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/ready.rs b/client/transaction-pool/src/graph/ready.rs index 92adf2e62d623..ebaa73f149240 100644 --- a/client/transaction-pool/src/graph/ready.rs +++ b/client/transaction-pool/src/graph/ready.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/rotator.rs b/client/transaction-pool/src/graph/rotator.rs index 910f86b5ed5b8..b897fe7885033 100644 --- a/client/transaction-pool/src/graph/rotator.rs +++ b/client/transaction-pool/src/graph/rotator.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/tracked_map.rs b/client/transaction-pool/src/graph/tracked_map.rs index 2f560d1c56245..32d04b0068877 100644 --- a/client/transaction-pool/src/graph/tracked_map.rs +++ b/client/transaction-pool/src/graph/tracked_map.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/validated_pool.rs b/client/transaction-pool/src/graph/validated_pool.rs index dba586adc846c..137c7298f5156 100644 --- a/client/transaction-pool/src/graph/validated_pool.rs +++ b/client/transaction-pool/src/graph/validated_pool.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/watcher.rs b/client/transaction-pool/src/graph/watcher.rs index 975ee6608886b..8cd78cfc78240 100644 --- a/client/transaction-pool/src/graph/watcher.rs +++ b/client/transaction-pool/src/graph/watcher.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 85af4f89d72b5..065c83be3bfcc 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/metrics.rs b/client/transaction-pool/src/metrics.rs index 7afed21509781..8bcefe246bff5 100644 --- a/client/transaction-pool/src/metrics.rs +++ b/client/transaction-pool/src/metrics.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/revalidation.rs b/client/transaction-pool/src/revalidation.rs index a8b2c1d32036a..6b6ed858e7ec6 100644 --- a/client/transaction-pool/src/revalidation.rs +++ b/client/transaction-pool/src/revalidation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 6c34d05cd5dcb..14ccacfb26922 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/lib.rs b/client/utils/src/lib.rs index b49cd60d67b13..fab4365c8ed83 100644 --- a/client/utils/src/lib.rs +++ b/client/utils/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/metrics.rs b/client/utils/src/metrics.rs index 6e85a66e62e5a..457ef23e41ab1 100644 --- a/client/utils/src/metrics.rs +++ b/client/utils/src/metrics.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/mpsc.rs b/client/utils/src/mpsc.rs index 1739af5e9015c..ee3fba4a5ee67 100644 --- a/client/utils/src/mpsc.rs +++ b/client/utils/src/mpsc.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/status_sinks.rs b/client/utils/src/status_sinks.rs index a87f0e0ad6e8f..a1d965d08085e 100644 --- a/client/utils/src/status_sinks.rs +++ b/client/utils/src/status_sinks.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 475864bac9430..33de190a8e36a 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/extra_mutator.rs b/frame/assets/src/extra_mutator.rs index 5ebfc3e547132..b72bfa86df5b8 100644 --- a/frame/assets/src/extra_mutator.rs +++ b/frame/assets/src/extra_mutator.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index a34900e74bbbd..e02cc7c8bb213 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index be534bfad57ab..49caac83f4c4a 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/impl_stored_map.rs b/frame/assets/src/impl_stored_map.rs index 88e2203f046b6..dfdcff37d1d69 100644 --- a/frame/assets/src/impl_stored_map.rs +++ b/frame/assets/src/impl_stored_map.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 6643cc177460c..be8df104dbf05 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 1e88421dd5acd..34a4cf9ef38f6 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index a3eacdda4452f..a9f4dafc910c0 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index ecf5f5edf4179..f8172e0a4a51b 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 912ebcf7e8510..423677cf13808 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 4775cd06b1afd..8259f53f39507 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index e98097055920d..4b1d5aeb4a705 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/aura/src/migrations.rs b/frame/aura/src/migrations.rs index e194c17406b63..d9b7cb8872a83 100644 --- a/frame/aura/src/migrations.rs +++ b/frame/aura/src/migrations.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index b9df2cfa0e4d7..636a28692ba28 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/aura/src/tests.rs b/frame/aura/src/tests.rs index 596858aac7c92..30003632729ea 100644 --- a/frame/aura/src/tests.rs +++ b/frame/aura/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index 5f905e92569f6..d5f0a4c1d3392 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 297f74ce8b489..6f825e4e7dff9 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/benchmarking.rs b/frame/babe/src/benchmarking.rs index 7747c9bd1fc8c..ac7ab28b5164a 100644 --- a/frame/babe/src/benchmarking.rs +++ b/frame/babe/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/default_weights.rs b/frame/babe/src/default_weights.rs index 20ac9b961fc8d..57c74323b7932 100644 --- a/frame/babe/src/default_weights.rs +++ b/frame/babe/src/default_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index 9247acbb3b12d..df46f3544b389 100644 --- a/frame/babe/src/equivocation.rs +++ b/frame/babe/src/equivocation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 6ae0796c866f0..424f2df5c16d0 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 90051770b80f2..f0faa55e5b333 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/randomness.rs b/frame/babe/src/randomness.rs index 7d18629050213..7be27f568e9fb 100644 --- a/frame/babe/src/randomness.rs +++ b/frame/babe/src/randomness.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 34d861d5d97f7..89911efe4e8af 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/fuzzer/src/main.rs b/frame/bags-list/fuzzer/src/main.rs index 02a2003b9a71f..3ff59b450befa 100644 --- a/frame/bags-list/fuzzer/src/main.rs +++ b/frame/bags-list/fuzzer/src/main.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/remote-tests/src/lib.rs b/frame/bags-list/remote-tests/src/lib.rs index 3d555eb1f1e35..9a88ff24f2f3b 100644 --- a/frame/bags-list/remote-tests/src/lib.rs +++ b/frame/bags-list/remote-tests/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index 41c65978e0d4f..5f0bcd4603865 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 193a334cf08f6..98261b6bbafc7 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 4524101d793cf..17844b51d4d5a 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index f3043589681ec..aaa215b0af1ca 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/migrations.rs b/frame/bags-list/src/migrations.rs index 8c907539c05f1..696733e8c7ba5 100644 --- a/frame/bags-list/src/migrations.rs +++ b/frame/bags-list/src/migrations.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 90d5347b1242f..aa3f549e12dec 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs index 8f1ccacaf1171..43397b3c120f5 100644 --- a/frame/bags-list/src/tests.rs +++ b/frame/bags-list/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index 7433c7ac564f7..cd5aed0770ab1 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/benchmarking.rs b/frame/balances/src/benchmarking.rs index 1c48820094187..4a874e4ffa1d5 100644 --- a/frame/balances/src/benchmarking.rs +++ b/frame/balances/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 6919c66f7211e..a774cfd61edf5 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index e05ed5a3d689c..638034d80cd52 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 15648d7356bec..a24be44927375 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index 4ceaff26c4d0d..ae56f3b1f0f2c 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 8067e5974caa8..4303efc2322c5 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index 6f333bfc0500f..a272753b73466 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/frame/beefy-mmr/primitives/src/lib.rs index ee1484607563f..04fa11760765b 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/frame/beefy-mmr/primitives/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index cf65e39dba533..38d0a6ac9a7f8 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index d66385f8807b9..88c182aa57ba4 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index 9cfbd94b53bca..6a81c5f25252e 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 9ef0c0d69f305..eb822915ee466 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 22330b29b670a..0d820116d07bf 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy/src/tests.rs b/frame/beefy/src/tests.rs index 900a3770279be..7acb40f200dfd 100644 --- a/frame/beefy/src/tests.rs +++ b/frame/beefy/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index f655e8fa76320..52baec80e62ed 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index e2f9f1f2975fd..1ceb9a4f8904c 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 3e1ed1ed2f11d..fcc3913cee78c 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index eded93c696bd4..06f2b5bdc4916 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index 2ac01a0528203..ef8351d37e957 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index 0bbe8156a9f99..bb0b8d36a752e 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index af0a782e6b2c5..a4d46d24b6e3a 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 19f50fdf3931b..04adacf6e4aec 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 752697ce668f4..d71b58f058823 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/migrations/mod.rs b/frame/bounties/src/migrations/mod.rs index 26d07a0cd5ac8..235d0f1c7cf15 100644 --- a/frame/bounties/src/migrations/mod.rs +++ b/frame/bounties/src/migrations/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/migrations/v4.rs b/frame/bounties/src/migrations/v4.rs index a1ca0e47680b0..8f5f3ebe55bf4 100644 --- a/frame/bounties/src/migrations/v4.rs +++ b/frame/bounties/src/migrations/v4.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index 209136dcda1e2..912a78c97570f 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 1383f69bed918..4cff3180ca795 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/child-bounties/src/benchmarking.rs b/frame/child-bounties/src/benchmarking.rs index 3386245cbdca7..d9edf14bbc9d7 100644 --- a/frame/child-bounties/src/benchmarking.rs +++ b/frame/child-bounties/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 3aa160277c82b..6bdc1865b8412 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index ba68d73ceddca..4b713e699f4d8 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index 7a52495d980b5..1662984aa7a3a 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index 9dcfa2a9c6c87..d5d0fc5f263e2 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 26b18b6232577..3f423f35b7e54 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/migrations/mod.rs b/frame/collective/src/migrations/mod.rs index 26d07a0cd5ac8..235d0f1c7cf15 100644 --- a/frame/collective/src/migrations/mod.rs +++ b/frame/collective/src/migrations/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/migrations/v4.rs b/frame/collective/src/migrations/v4.rs index 68284ba4df91d..4e6cd05584138 100644 --- a/frame/collective/src/migrations/v4.rs +++ b/frame/collective/src/migrations/v4.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 2af8b1b97036d..4f40e02732b4c 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index 40ac9eabdd6e4..bdb07834a66c9 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/common/src/lib.rs b/frame/contracts/common/src/lib.rs index 7d99db42a2b93..49f91f6769290 100644 --- a/frame/contracts/common/src/lib.rs +++ b/frame/contracts/common/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index 302a0d01a93d9..43b59debc4ad0 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/rpc/runtime-api/src/lib.rs b/frame/contracts/rpc/runtime-api/src/lib.rs index 485040fd235cd..59622a21a6593 100644 --- a/frame/contracts/rpc/runtime-api/src/lib.rs +++ b/frame/contracts/rpc/runtime-api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/rpc/src/lib.rs b/frame/contracts/rpc/src/lib.rs index c4a577196c999..580b74b5ca46d 100644 --- a/frame/contracts/rpc/src/lib.rs +++ b/frame/contracts/rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 49df1c3838216..d4828871dbbe5 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index ae39d1feca114..49344373f97d6 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/benchmarking/sandbox.rs b/frame/contracts/src/benchmarking/sandbox.rs index 4412542b547df..451d2fe433913 100644 --- a/frame/contracts/src/benchmarking/sandbox.rs +++ b/frame/contracts/src/benchmarking/sandbox.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 14080102933cb..b0e08df3adbb0 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index bd54c7a08c636..97f301d162afb 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index 38d18c1e24c19..cdf0c1407c6bd 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index ab7a0c254f560..62e79944bbe92 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 7751eb1a2c77d..29712a528a72c 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index b9acc9d49204f..dd066bfbe41ee 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 6d67729a9a682..7b0671da10582 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index 96ce02fd83ae7..2dbd7ede615d2 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 6ca4e34f8aeae..4cbc37c57ff21 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 2cff043f64efa..e3fe48ac12c24 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/wasm/env_def/macros.rs b/frame/contracts/src/wasm/env_def/macros.rs index ea7f51da75264..a50290085df8b 100644 --- a/frame/contracts/src/wasm/env_def/macros.rs +++ b/frame/contracts/src/wasm/env_def/macros.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/wasm/env_def/mod.rs b/frame/contracts/src/wasm/env_def/mod.rs index 6a55677f69a01..c74af80d3e4ef 100644 --- a/frame/contracts/src/wasm/env_def/mod.rs +++ b/frame/contracts/src/wasm/env_def/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 913894e8152db..ee7f557d34f01 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 6d13c097bd434..5e5f8e7e6fc90 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index ad13d18435a96..cae68208b31eb 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 5f61c1e4a3462..d60a8ab82f3b0 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index 4068b55f6e7bc..bce830b385a9f 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/conviction.rs b/frame/democracy/src/conviction.rs index 59a5eccc616c3..57d631e8c1f4c 100644 --- a/frame/democracy/src/conviction.rs +++ b/frame/democracy/src/conviction.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index d80f8aa89ec35..1e5f3c403006a 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 1e36313122f09..641014923c233 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/cancellation.rs b/frame/democracy/src/tests/cancellation.rs index 83822bf51829f..9035e17c5c80b 100644 --- a/frame/democracy/src/tests/cancellation.rs +++ b/frame/democracy/src/tests/cancellation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/decoders.rs b/frame/democracy/src/tests/decoders.rs index 3c1729c4355c0..1fbb88060549b 100644 --- a/frame/democracy/src/tests/decoders.rs +++ b/frame/democracy/src/tests/decoders.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/delegation.rs b/frame/democracy/src/tests/delegation.rs index d3afa1c13f90b..f644f22951748 100644 --- a/frame/democracy/src/tests/delegation.rs +++ b/frame/democracy/src/tests/delegation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/external_proposing.rs b/frame/democracy/src/tests/external_proposing.rs index 7442964584fa9..5d4a9f2a7cbfc 100644 --- a/frame/democracy/src/tests/external_proposing.rs +++ b/frame/democracy/src/tests/external_proposing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/fast_tracking.rs b/frame/democracy/src/tests/fast_tracking.rs index 9b2f2760bde1c..7a15bb8de4dac 100644 --- a/frame/democracy/src/tests/fast_tracking.rs +++ b/frame/democracy/src/tests/fast_tracking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/lock_voting.rs b/frame/democracy/src/tests/lock_voting.rs index 2e1440d8f44bb..0718734367314 100644 --- a/frame/democracy/src/tests/lock_voting.rs +++ b/frame/democracy/src/tests/lock_voting.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/preimage.rs b/frame/democracy/src/tests/preimage.rs index 6d478fcaa68c7..21303c8eddae3 100644 --- a/frame/democracy/src/tests/preimage.rs +++ b/frame/democracy/src/tests/preimage.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs index 34713c3e15725..aadc92d24f41d 100644 --- a/frame/democracy/src/tests/public_proposals.rs +++ b/frame/democracy/src/tests/public_proposals.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/scheduling.rs b/frame/democracy/src/tests/scheduling.rs index 5c857a632b97b..d28f24d76bb5b 100644 --- a/frame/democracy/src/tests/scheduling.rs +++ b/frame/democracy/src/tests/scheduling.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/voting.rs b/frame/democracy/src/tests/voting.rs index e035c2d46c1b6..d4fceaf0ee489 100644 --- a/frame/democracy/src/tests/voting.rs +++ b/frame/democracy/src/tests/voting.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/types.rs b/frame/democracy/src/types.rs index 2eb004ba61bc4..52ab8a40eb3e3 100644 --- a/frame/democracy/src/types.rs +++ b/frame/democracy/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/vote.rs b/frame/democracy/src/vote.rs index da74f7bd2fb64..e6a252dcf0151 100644 --- a/frame/democracy/src/vote.rs +++ b/frame/democracy/src/vote.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/vote_threshold.rs b/frame/democracy/src/vote_threshold.rs index ad8bce290ed4f..443d6b1166198 100644 --- a/frame/democracy/src/vote_threshold.rs +++ b/frame/democracy/src/vote_threshold.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 638852d3c7e19..aa8e68f57053c 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 04101f886cecf..d605c5131cf77 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/helpers.rs b/frame/election-provider-multi-phase/src/helpers.rs index 98a14a93a25e0..9bd5b5dbabd25 100644 --- a/frame/election-provider-multi-phase/src/helpers.rs +++ b/frame/election-provider-multi-phase/src/helpers.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 175de0eeb0c69..8087d22cffe69 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 4e494322b062a..409ebd3f1e10d 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 08cae62ef7d37..c2cb5cf44823e 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 1770f4343a0a4..6ce0ddfe67644 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 4d49f60fabfc3..7bb3303cba2ef 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index a4fce64ff1d74..d10504c88cc67 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index ce15edd592add..d325daf514757 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 9bc63848607ab..ae98de4be7e4e 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 3a6c657a6f99c..06474cd37bbdf 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/migrations/mod.rs b/frame/elections-phragmen/src/migrations/mod.rs index 9a1f86a1ad7ce..e7f6429f2298a 100644 --- a/frame/elections-phragmen/src/migrations/mod.rs +++ b/frame/elections-phragmen/src/migrations/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/migrations/v3.rs b/frame/elections-phragmen/src/migrations/v3.rs index 728e0c4b0c915..c6a7ce7e7ca1b 100644 --- a/frame/elections-phragmen/src/migrations/v3.rs +++ b/frame/elections-phragmen/src/migrations/v3.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/migrations/v4.rs b/frame/elections-phragmen/src/migrations/v4.rs index 9acc1297294d9..e0fc17ec2a12d 100644 --- a/frame/elections-phragmen/src/migrations/v4.rs +++ b/frame/elections-phragmen/src/migrations/v4.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index b60308c4f0a64..0bfc3d2ea87a7 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index a031b15834d63..b823ccd072969 100644 --- a/frame/examples/basic/src/benchmarking.rs +++ b/frame/examples/basic/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 2b443ff8e8dde..13c4591be28fd 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 9f93c90531180..0f659e12fb443 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/basic/src/weights.rs b/frame/examples/basic/src/weights.rs index 048f7f5a8b8e5..5fc6434e396eb 100644 --- a/frame/examples/basic/src/weights.rs +++ b/frame/examples/basic/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index ec728e791295c..764f6cb9e2d77 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 2c3e623e9c842..76f80deb12f90 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/parallel/src/lib.rs b/frame/examples/parallel/src/lib.rs index 55714abb4827f..4ea52173a09aa 100644 --- a/frame/examples/parallel/src/lib.rs +++ b/frame/examples/parallel/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/parallel/src/tests.rs b/frame/examples/parallel/src/tests.rs index 82ce95d7a85bb..67d823d8b204b 100644 --- a/frame/examples/parallel/src/tests.rs +++ b/frame/examples/parallel/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 1b74bdc2fea0a..be944954eaa59 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/gilt/src/benchmarking.rs b/frame/gilt/src/benchmarking.rs index 9c6d22a48398d..3df08372f499b 100644 --- a/frame/gilt/src/benchmarking.rs +++ b/frame/gilt/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index b494eed67445c..4fd18626d9313 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/gilt/src/mock.rs b/frame/gilt/src/mock.rs index 6299f7c320312..369b34ba77f44 100644 --- a/frame/gilt/src/mock.rs +++ b/frame/gilt/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/gilt/src/tests.rs b/frame/gilt/src/tests.rs index 80315141e2325..486601b5b2f21 100644 --- a/frame/gilt/src/tests.rs +++ b/frame/gilt/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/gilt/src/weights.rs b/frame/gilt/src/weights.rs index f54d917cc160c..fd4dcd1b5d5ae 100644 --- a/frame/gilt/src/weights.rs +++ b/frame/gilt/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/benchmarking.rs b/frame/grandpa/src/benchmarking.rs index 1e6be01ce8dbf..1240859149920 100644 --- a/frame/grandpa/src/benchmarking.rs +++ b/frame/grandpa/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/default_weights.rs b/frame/grandpa/src/default_weights.rs index edc18a7ff8c93..330e9bb255177 100644 --- a/frame/grandpa/src/default_weights.rs +++ b/frame/grandpa/src/default_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 77e38cb63b7dc..804272c20480f 100644 --- a/frame/grandpa/src/equivocation.rs +++ b/frame/grandpa/src/equivocation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index b289da464a93f..560c933f108c1 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/migrations.rs b/frame/grandpa/src/migrations.rs index 05c24e11b3939..7795afcd8034f 100644 --- a/frame/grandpa/src/migrations.rs +++ b/frame/grandpa/src/migrations.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/migrations/v4.rs b/frame/grandpa/src/migrations/v4.rs index 094f276efef31..ab43f7baef4e9 100644 --- a/frame/grandpa/src/migrations/v4.rs +++ b/frame/grandpa/src/migrations/v4.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 6f7c57cad0b57..ddfae3d7ea75b 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 6dc0a26da8bd3..ab0a9c677b00e 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index db257fec43a13..2f52aff394b7e 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index b4b52331618cb..a2516a1e874e5 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index efbd1d984f336..bf41b451cbaa3 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/identity/src/types.rs b/frame/identity/src/types.rs index ed6aeb18e96a1..ed3caafd3a114 100644 --- a/frame/identity/src/types.rs +++ b/frame/identity/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 92bc4cbaae924..9f04007431be8 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/im-online/src/benchmarking.rs b/frame/im-online/src/benchmarking.rs index 012da53a183e5..edc21043c34de 100644 --- a/frame/im-online/src/benchmarking.rs +++ b/frame/im-online/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 3499078149f2e..c9377cd274ade 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 8166bfc9119e7..86904b38d834b 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index bb2c4c7cae548..cab5df9ebe541 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index 1eadd63cc9d6c..19ac7e8ffc0fc 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/indices/src/benchmarking.rs b/frame/indices/src/benchmarking.rs index 873dc18b20265..cb06cd809f542 100644 --- a/frame/indices/src/benchmarking.rs +++ b/frame/indices/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index d8051bac0a3cd..0aa931559e0a9 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index ef654833c3a36..6bd79708c3dd2 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/indices/src/tests.rs b/frame/indices/src/tests.rs index 37df20e9b9288..73d591c38bb2f 100644 --- a/frame/indices/src/tests.rs +++ b/frame/indices/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 97db589739534..590aa11dec840 100644 --- a/frame/indices/src/weights.rs +++ b/frame/indices/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index 5407e16cd633f..f4a8e88e5e3f1 100644 --- a/frame/lottery/src/benchmarking.rs +++ b/frame/lottery/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index b30bc1dc523a6..5a985094dd1c9 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/lottery/src/mock.rs b/frame/lottery/src/mock.rs index 36b847d48d97e..592551fb6b93f 100644 --- a/frame/lottery/src/mock.rs +++ b/frame/lottery/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/lottery/src/tests.rs b/frame/lottery/src/tests.rs index 623beea4a6b5b..143a4b0528773 100644 --- a/frame/lottery/src/tests.rs +++ b/frame/lottery/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index 5fbc61a32e577..5d252e9d5650e 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index b34051731f69d..016c4b39851af 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/membership/src/migrations/mod.rs b/frame/membership/src/migrations/mod.rs index 26d07a0cd5ac8..235d0f1c7cf15 100644 --- a/frame/membership/src/migrations/mod.rs +++ b/frame/membership/src/migrations/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/membership/src/migrations/v4.rs b/frame/membership/src/migrations/v4.rs index c1c944be1fd4f..b3b52751d9598 100644 --- a/frame/membership/src/migrations/v4.rs +++ b/frame/membership/src/migrations/v4.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 81a1b073faac3..5b34529c7c182 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/primitives/src/lib.rs b/frame/merkle-mountain-range/primitives/src/lib.rs index 9aae26508f3c4..cc78dfefefe60 100644 --- a/frame/merkle-mountain-range/primitives/src/lib.rs +++ b/frame/merkle-mountain-range/primitives/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 004a70a8e962e..b256ccdd7d327 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/benchmarking.rs b/frame/merkle-mountain-range/src/benchmarking.rs index 7c0dae26b3373..b698e432534d8 100644 --- a/frame/merkle-mountain-range/src/benchmarking.rs +++ b/frame/merkle-mountain-range/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/default_weights.rs b/frame/merkle-mountain-range/src/default_weights.rs index 6308975ce7d22..73d1963a42964 100644 --- a/frame/merkle-mountain-range/src/default_weights.rs +++ b/frame/merkle-mountain-range/src/default_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 12577880c5600..0f5fe751bbd96 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/mmr/mmr.rs b/frame/merkle-mountain-range/src/mmr/mmr.rs index a1963275a0cde..a1516ee8607f4 100644 --- a/frame/merkle-mountain-range/src/mmr/mmr.rs +++ b/frame/merkle-mountain-range/src/mmr/mmr.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/mmr/mod.rs b/frame/merkle-mountain-range/src/mmr/mod.rs index ec2dfe245bd41..1a729b08b966f 100644 --- a/frame/merkle-mountain-range/src/mmr/mod.rs +++ b/frame/merkle-mountain-range/src/mmr/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index 6e4bf91d802fa..a48f60183d679 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/mmr/utils.rs b/frame/merkle-mountain-range/src/mmr/utils.rs index 77ce0e8ebbb36..d9f7e3b671be3 100644 --- a/frame/merkle-mountain-range/src/mmr/utils.rs +++ b/frame/merkle-mountain-range/src/mmr/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index 2adea420f03d7..56d3c9c0d77d8 100644 --- a/frame/merkle-mountain-range/src/mock.rs +++ b/frame/merkle-mountain-range/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 3faf2bfbd9c2f..588a407d6d371 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index cb98d8954030d..43abb349b7951 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index c02efdc0d3712..16ee1c500096a 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index 2d6c02c559e8f..d67d06e1bce05 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index 1bc72d251808f..eb78a88f1531c 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 6d9c15fd3da16..24d80f5a95217 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 17b74053e6684..87ec3973d0a86 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/node-authorization/src/mock.rs b/frame/node-authorization/src/mock.rs index bb882c62abb6f..d959d1b8610f5 100644 --- a/frame/node-authorization/src/mock.rs +++ b/frame/node-authorization/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/node-authorization/src/tests.rs b/frame/node-authorization/src/tests.rs index 530904fa73488..ba78d14912133 100644 --- a/frame/node-authorization/src/tests.rs +++ b/frame/node-authorization/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/node-authorization/src/weights.rs b/frame/node-authorization/src/weights.rs index dbb7956cff967..cf182f94273ce 100644 --- a/frame/node-authorization/src/weights.rs +++ b/frame/node-authorization/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 4d042cfd9997f..4d6a182034c9e 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 1a5fdcd61bee7..598ba650dfffb 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index c230eac88dcee..25605d934d57f 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/src/migration.rs b/frame/offences/src/migration.rs index d655f2cec539a..1984db0b7af3e 100644 --- a/frame/offences/src/migration.rs +++ b/frame/offences/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 17d34d46e3137..b3dfbdd90b19d 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/src/tests.rs b/frame/offences/src/tests.rs index 8c4fdcc08f995..49bd2fb5a6923 100644 --- a/frame/offences/src/tests.rs +++ b/frame/offences/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index c18c27555025d..64326108420e8 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 2d227000c9edc..17fc543084c99 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index 3996d84256963..109806049a0fd 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/tests.rs b/frame/preimage/src/tests.rs index 528b263303715..721bb128de239 100644 --- a/frame/preimage/src/tests.rs +++ b/frame/preimage/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 406ca99bfb791..fab5cdfb67361 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index 224610b65185b..ceed2e6ab22dc 100644 --- a/frame/proxy/src/benchmarking.rs +++ b/frame/proxy/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index fefc66554f450..68aa580bfe7f6 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 902eae8fc3208..b4f30ab4029ab 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 41aa3034bece1..bde4fd761179c 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index bf5920acff8ed..5f4994c471424 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index 24090e9000fa4..b0505cbb7daf9 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 778b966c76e83..577aa7dee7117 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/recovery/src/tests.rs b/frame/recovery/src/tests.rs index fe971319bc97c..7d1da6353a3ad 100644 --- a/frame/recovery/src/tests.rs +++ b/frame/recovery/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 22e3e4f4530ba..9c97bc5973384 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index b4ee2575e23d0..4fd5d50a4de0f 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 014f473302ab7..869425c2ff530 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 4774cfe38704d..7681ede136d97 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index 3c2ed47110b66..b8209c6031c89 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index 7c90d163dee1f..e95786e0c08f8 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index d5b3814fd97a4..e349d7a1cc9a5 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scored-pool/src/tests.rs b/frame/scored-pool/src/tests.rs index 0503e308e76a5..7b431160ddfe5 100644 --- a/frame/scored-pool/src/tests.rs +++ b/frame/scored-pool/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index 4e0e51b76fe18..7beb4631e0518 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 2560563511e6a..1f00236605130 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index fa7cb9ee91c03..76cefeb7b0532 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/historical/offchain.rs b/frame/session/src/historical/offchain.rs index 0b292b57658d0..95813d0a70272 100644 --- a/frame/session/src/historical/offchain.rs +++ b/frame/session/src/historical/offchain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/historical/onchain.rs b/frame/session/src/historical/onchain.rs index c80817c28d723..c7160e2fcf531 100644 --- a/frame/session/src/historical/onchain.rs +++ b/frame/session/src/historical/onchain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/historical/shared.rs b/frame/session/src/historical/shared.rs index 182e9ecacee19..9e19b9df6d78d 100644 --- a/frame/session/src/historical/shared.rs +++ b/frame/session/src/historical/shared.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index e88f143065052..cae9a6159b162 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/migrations/mod.rs b/frame/session/src/migrations/mod.rs index ccc5ee3c2e525..5981e87b677cc 100644 --- a/frame/session/src/migrations/mod.rs +++ b/frame/session/src/migrations/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/migrations/v1.rs b/frame/session/src/migrations/v1.rs index 1de199fe7bedd..2a69cd6d6a550 100644 --- a/frame/session/src/migrations/v1.rs +++ b/frame/session/src/migrations/v1.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index ec1f841f50b14..7c6cc02c9e785 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index 199076c88244c..4f2108a9a4380 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index 64e7ac19ea7a0..35c9cc7230fb4 100644 --- a/frame/session/src/weights.rs +++ b/frame/session/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 0b95129032670..abc90d5186f29 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index fbf3b2fd757a5..04ea705eed556 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/society/src/tests.rs b/frame/society/src/tests.rs index 9f8e32dea5088..d394ddc9011b0 100644 --- a/frame/society/src/tests.rs +++ b/frame/society/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/reward-curve/src/lib.rs b/frame/staking/reward-curve/src/lib.rs index 06e35d11350e0..9b2f3100b487e 100644 --- a/frame/staking/reward-curve/src/lib.rs +++ b/frame/staking/reward-curve/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/reward-curve/tests/test.rs b/frame/staking/reward-curve/tests/test.rs index fda7df145d0f3..aa19b1782453d 100644 --- a/frame/staking/reward-curve/tests/test.rs +++ b/frame/staking/reward-curve/tests/test.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/reward-fn/src/lib.rs b/frame/staking/reward-fn/src/lib.rs index 25e52051effa5..cb0b660bf544b 100644 --- a/frame/staking/reward-fn/src/lib.rs +++ b/frame/staking/reward-fn/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/reward-fn/tests/test.rs b/frame/staking/reward-fn/tests/test.rs index dc5b661c4098d..a79137716fd28 100644 --- a/frame/staking/reward-fn/tests/test.rs +++ b/frame/staking/reward-fn/tests/test.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index cd9755366b0f6..8328adc00a978 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/inflation.rs b/frame/staking/src/inflation.rs index 8e44a8c5482e5..c7519683c75d1 100644 --- a/frame/staking/src/inflation.rs +++ b/frame/staking/src/inflation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 7bc3ac8aa7075..f6e0526917540 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 33f45d80870a3..3991c4a66076f 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index ea9b9f05f1059..3bf46588044a6 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 95af3d223e009..dcbba63632051 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index d03a6198c7cc4..e45a21ab25036 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index acfb30fb81482..4fa7d347da70d 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 1c9163bd56402..8e6bd88468930 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 74d5de7bf449e..7990245068f9c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 0ca819898fbb0..4f5af6fcd5f8e 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index b6255da1d1c46..d57c75f23f5a0 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index baea68788acf4..e6af6978f8c83 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/sudo/src/tests.rs b/frame/sudo/src/tests.rs index 8821879061677..84c8e0c5c254e 100644 --- a/frame/sudo/src/tests.rs +++ b/frame/sudo/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/clone_no_bound.rs b/frame/support/procedural/src/clone_no_bound.rs index 747900fd023f6..bd2741c0d47ab 100644 --- a/frame/support/procedural/src/clone_no_bound.rs +++ b/frame/support/procedural/src/clone_no_bound.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index 5658ec045433a..b09ef126ac6dd 100644 --- a/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/config.rs b/frame/support/procedural/src/construct_runtime/expand/config.rs index 5e1b9d94700e6..79176fa7385ec 100644 --- a/frame/support/procedural/src/construct_runtime/expand/config.rs +++ b/frame/support/procedural/src/construct_runtime/expand/config.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/event.rs b/frame/support/procedural/src/construct_runtime/expand/event.rs index 798646bf27334..ef071a9fc7ef5 100644 --- a/frame/support/procedural/src/construct_runtime/expand/event.rs +++ b/frame/support/procedural/src/construct_runtime/expand/event.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/inherent.rs b/frame/support/procedural/src/construct_runtime/expand/inherent.rs index fd30416782687..0f0d538643240 100644 --- a/frame/support/procedural/src/construct_runtime/expand/inherent.rs +++ b/frame/support/procedural/src/construct_runtime/expand/inherent.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/frame/support/procedural/src/construct_runtime/expand/metadata.rs index c8445e0bbc255..6e2dd5fc002c6 100644 --- a/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/mod.rs b/frame/support/procedural/src/construct_runtime/expand/mod.rs index cf8b5eef8d105..6c92d2c3444ec 100644 --- a/frame/support/procedural/src/construct_runtime/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime/expand/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index 5c2b4c9f93b0b..077bef3744a5a 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/unsigned.rs b/frame/support/procedural/src/construct_runtime/expand/unsigned.rs index d51792dd4a8d5..c030676802093 100644 --- a/frame/support/procedural/src/construct_runtime/expand/unsigned.rs +++ b/frame/support/procedural/src/construct_runtime/expand/unsigned.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index b32ecf1bccd5c..249eb072001c9 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index 44db2c10fff6c..a2cda6a0777b8 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/crate_version.rs b/frame/support/procedural/src/crate_version.rs index cfa35c6190e15..e2be6dd889db4 100644 --- a/frame/support/procedural/src/crate_version.rs +++ b/frame/support/procedural/src/crate_version.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/debug_no_bound.rs b/frame/support/procedural/src/debug_no_bound.rs index acfd8d0cabc8a..56168edb87e83 100644 --- a/frame/support/procedural/src/debug_no_bound.rs +++ b/frame/support/procedural/src/debug_no_bound.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/default_no_bound.rs b/frame/support/procedural/src/default_no_bound.rs index 38d6e19b1732f..192be0786d96b 100644 --- a/frame/support/procedural/src/default_no_bound.rs +++ b/frame/support/procedural/src/default_no_bound.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/key_prefix.rs b/frame/support/procedural/src/key_prefix.rs index 3f424e8b8b8dd..05582f1297eed 100644 --- a/frame/support/procedural/src/key_prefix.rs +++ b/frame/support/procedural/src/key_prefix.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index d01bbf6ace526..e2233fff72285 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/match_and_insert.rs b/frame/support/procedural/src/match_and_insert.rs index 4ffc596e6dca0..79d1da7549c1d 100644 --- a/frame/support/procedural/src/match_and_insert.rs +++ b/frame/support/procedural/src/match_and_insert.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 8f7bcdccaf22d..58c4804558b0e 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index dad26ccad6dc1..8ad34361d684a 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/constants.rs b/frame/support/procedural/src/pallet/expand/constants.rs index 0fe8e467c10da..3f853902010f9 100644 --- a/frame/support/procedural/src/pallet/expand/constants.rs +++ b/frame/support/procedural/src/pallet/expand/constants.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/error.rs b/frame/support/procedural/src/pallet/expand/error.rs index c6925db07a26f..3e6247e77f8cc 100644 --- a/frame/support/procedural/src/pallet/expand/error.rs +++ b/frame/support/procedural/src/pallet/expand/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/event.rs b/frame/support/procedural/src/pallet/expand/event.rs index 69d6b461206c9..79a7acaf66a5a 100644 --- a/frame/support/procedural/src/pallet/expand/event.rs +++ b/frame/support/procedural/src/pallet/expand/event.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/genesis_build.rs b/frame/support/procedural/src/pallet/expand/genesis_build.rs index 06acaf324254c..53d0695e5f971 100644 --- a/frame/support/procedural/src/pallet/expand/genesis_build.rs +++ b/frame/support/procedural/src/pallet/expand/genesis_build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/genesis_config.rs b/frame/support/procedural/src/pallet/expand/genesis_config.rs index b2eb2166165cb..18fa87a262533 100644 --- a/frame/support/procedural/src/pallet/expand/genesis_config.rs +++ b/frame/support/procedural/src/pallet/expand/genesis_config.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index e0b7e3669da43..7a1a94cf46d31 100644 --- a/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/frame/support/procedural/src/pallet/expand/hooks.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/inherent.rs b/frame/support/procedural/src/pallet/expand/inherent.rs index 185211ecd4df2..71d95f958fcd2 100644 --- a/frame/support/procedural/src/pallet/expand/inherent.rs +++ b/frame/support/procedural/src/pallet/expand/inherent.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/instances.rs b/frame/support/procedural/src/pallet/expand/instances.rs index 2ecb5ec481ac4..52dc887635503 100644 --- a/frame/support/procedural/src/pallet/expand/instances.rs +++ b/frame/support/procedural/src/pallet/expand/instances.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/mod.rs b/frame/support/procedural/src/pallet/expand/mod.rs index 21acd3c0dd32e..83bef7a97af1f 100644 --- a/frame/support/procedural/src/pallet/expand/mod.rs +++ b/frame/support/procedural/src/pallet/expand/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/origin.rs b/frame/support/procedural/src/pallet/expand/origin.rs index 987512f69a02b..721fc781a907c 100644 --- a/frame/support/procedural/src/pallet/expand/origin.rs +++ b/frame/support/procedural/src/pallet/expand/origin.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 96dfdbb4b6f2d..5ec10d733e5e2 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index a4f030722f1c1..9d936dd50344e 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/store_trait.rs b/frame/support/procedural/src/pallet/expand/store_trait.rs index 36cc08b732fe5..4fb4f46143a14 100644 --- a/frame/support/procedural/src/pallet/expand/store_trait.rs +++ b/frame/support/procedural/src/pallet/expand/store_trait.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs index cfab7982bfdc9..173dcc0e2ac3f 100644 --- a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/type_value.rs b/frame/support/procedural/src/pallet/expand/type_value.rs index af4f0b3a67947..abe52459a791d 100644 --- a/frame/support/procedural/src/pallet/expand/type_value.rs +++ b/frame/support/procedural/src/pallet/expand/type_value.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/validate_unsigned.rs b/frame/support/procedural/src/pallet/expand/validate_unsigned.rs index 5f30d712e9a51..b49ba2b5b02ea 100644 --- a/frame/support/procedural/src/pallet/expand/validate_unsigned.rs +++ b/frame/support/procedural/src/pallet/expand/validate_unsigned.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/mod.rs b/frame/support/procedural/src/pallet/mod.rs index 93797906d04d9..ff9f122867746 100644 --- a/frame/support/procedural/src/pallet/mod.rs +++ b/frame/support/procedural/src/pallet/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index 0563568f33311..5468b1352197e 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 9e0a0fd52cbfc..526c7eda2fd57 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/error.rs b/frame/support/procedural/src/pallet/parse/error.rs index 9c9a95105c53c..419770386bf69 100644 --- a/frame/support/procedural/src/pallet/parse/error.rs +++ b/frame/support/procedural/src/pallet/parse/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/event.rs b/frame/support/procedural/src/pallet/parse/event.rs index 33de4aca8b599..e046cacac88e8 100644 --- a/frame/support/procedural/src/pallet/parse/event.rs +++ b/frame/support/procedural/src/pallet/parse/event.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/extra_constants.rs b/frame/support/procedural/src/pallet/parse/extra_constants.rs index a5f3c0a8c2dab..7163b4b632089 100644 --- a/frame/support/procedural/src/pallet/parse/extra_constants.rs +++ b/frame/support/procedural/src/pallet/parse/extra_constants.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/genesis_build.rs b/frame/support/procedural/src/pallet/parse/genesis_build.rs index 82e297b4e26e8..79ee083069821 100644 --- a/frame/support/procedural/src/pallet/parse/genesis_build.rs +++ b/frame/support/procedural/src/pallet/parse/genesis_build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/genesis_config.rs b/frame/support/procedural/src/pallet/parse/genesis_config.rs index a0cf7de1a846b..875d15bdc061d 100644 --- a/frame/support/procedural/src/pallet/parse/genesis_config.rs +++ b/frame/support/procedural/src/pallet/parse/genesis_config.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/helper.rs b/frame/support/procedural/src/pallet/parse/helper.rs index f5a7dc233cacb..8244079173581 100644 --- a/frame/support/procedural/src/pallet/parse/helper.rs +++ b/frame/support/procedural/src/pallet/parse/helper.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/hooks.rs b/frame/support/procedural/src/pallet/parse/hooks.rs index 1dd86498f22d5..cacc149e48668 100644 --- a/frame/support/procedural/src/pallet/parse/hooks.rs +++ b/frame/support/procedural/src/pallet/parse/hooks.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/inherent.rs b/frame/support/procedural/src/pallet/parse/inherent.rs index de5ad8f795db5..2833b3ef5c724 100644 --- a/frame/support/procedural/src/pallet/parse/inherent.rs +++ b/frame/support/procedural/src/pallet/parse/inherent.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/mod.rs b/frame/support/procedural/src/pallet/parse/mod.rs index 96d4776e805bc..a436f7e09c1d7 100644 --- a/frame/support/procedural/src/pallet/parse/mod.rs +++ b/frame/support/procedural/src/pallet/parse/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/origin.rs b/frame/support/procedural/src/pallet/parse/origin.rs index c4e1197ac511c..2d729376f5de4 100644 --- a/frame/support/procedural/src/pallet/parse/origin.rs +++ b/frame/support/procedural/src/pallet/parse/origin.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index c528faf669ee3..19d2811687d2e 100644 --- a/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index cd29baf93d849..ca48c568e158a 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/type_value.rs b/frame/support/procedural/src/pallet/parse/type_value.rs index d6cd4d02df8bd..a3d004cd8a532 100644 --- a/frame/support/procedural/src/pallet/parse/type_value.rs +++ b/frame/support/procedural/src/pallet/parse/type_value.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/validate_unsigned.rs b/frame/support/procedural/src/pallet/parse/validate_unsigned.rs index 87e2a326f1862..a58671d9762de 100644 --- a/frame/support/procedural/src/pallet/parse/validate_unsigned.rs +++ b/frame/support/procedural/src/pallet/parse/validate_unsigned.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/partial_eq_no_bound.rs b/frame/support/procedural/src/partial_eq_no_bound.rs index 3dbabf3f5d39a..31930c0c3dae3 100644 --- a/frame/support/procedural/src/partial_eq_no_bound.rs +++ b/frame/support/procedural/src/partial_eq_no_bound.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/genesis_config/builder_def.rs b/frame/support/procedural/src/storage/genesis_config/builder_def.rs index 001cea0f2b788..975791881da23 100644 --- a/frame/support/procedural/src/storage/genesis_config/builder_def.rs +++ b/frame/support/procedural/src/storage/genesis_config/builder_def.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/genesis_config/genesis_config_def.rs b/frame/support/procedural/src/storage/genesis_config/genesis_config_def.rs index fbdaab06b4895..d24e50096f25e 100644 --- a/frame/support/procedural/src/storage/genesis_config/genesis_config_def.rs +++ b/frame/support/procedural/src/storage/genesis_config/genesis_config_def.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/genesis_config/mod.rs b/frame/support/procedural/src/storage/genesis_config/mod.rs index daff8848364ee..d4348ee19171c 100644 --- a/frame/support/procedural/src/storage/genesis_config/mod.rs +++ b/frame/support/procedural/src/storage/genesis_config/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/getters.rs b/frame/support/procedural/src/storage/getters.rs index d877969232f84..9fe3734e6889c 100644 --- a/frame/support/procedural/src/storage/getters.rs +++ b/frame/support/procedural/src/storage/getters.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/instance_trait.rs b/frame/support/procedural/src/storage/instance_trait.rs index 00a73d6fbd6e7..14e968112029e 100644 --- a/frame/support/procedural/src/storage/instance_trait.rs +++ b/frame/support/procedural/src/storage/instance_trait.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/metadata.rs b/frame/support/procedural/src/storage/metadata.rs index c49a0dafdf5d0..d1879d1509f8d 100644 --- a/frame/support/procedural/src/storage/metadata.rs +++ b/frame/support/procedural/src/storage/metadata.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 27964d7012a28..b89e756334986 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/parse.rs b/frame/support/procedural/src/storage/parse.rs index 3a11846181a8f..54026b7d78b19 100644 --- a/frame/support/procedural/src/storage/parse.rs +++ b/frame/support/procedural/src/storage/parse.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/storage_info.rs b/frame/support/procedural/src/storage/storage_info.rs index 4b1d3347b4a43..77515fa739b2b 100644 --- a/frame/support/procedural/src/storage/storage_info.rs +++ b/frame/support/procedural/src/storage/storage_info.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/storage_struct.rs b/frame/support/procedural/src/storage/storage_struct.rs index b318225681c1d..649a41bab5ece 100644 --- a/frame/support/procedural/src/storage/storage_struct.rs +++ b/frame/support/procedural/src/storage/storage_struct.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/store_trait.rs b/frame/support/procedural/src/storage/store_trait.rs index 5794c72d22c8d..daf933b3b770c 100644 --- a/frame/support/procedural/src/storage/store_trait.rs +++ b/frame/support/procedural/src/storage/store_trait.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/transactional.rs b/frame/support/procedural/src/transactional.rs index 403f1cd02bac7..66a8d083fb562 100644 --- a/frame/support/procedural/src/transactional.rs +++ b/frame/support/procedural/src/transactional.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/tools/derive/src/lib.rs b/frame/support/procedural/tools/derive/src/lib.rs index 9ce88e7c47937..392a438342017 100644 --- a/frame/support/procedural/tools/derive/src/lib.rs +++ b/frame/support/procedural/tools/derive/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/tools/src/lib.rs b/frame/support/procedural/tools/src/lib.rs index d7aba4c7cbf1c..3abde59574119 100644 --- a/frame/support/procedural/tools/src/lib.rs +++ b/frame/support/procedural/tools/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/tools/src/syn_ext.rs b/frame/support/procedural/tools/src/syn_ext.rs index a9e9ef573985f..25c98faaf388c 100644 --- a/frame/support/procedural/tools/src/syn_ext.rs +++ b/frame/support/procedural/tools/src/syn_ext.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index a492bc12f6a38..765fb5d9d7c35 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/error.rs b/frame/support/src/error.rs index 836428c6bc7db..abac4a53269a6 100644 --- a/frame/support/src/error.rs +++ b/frame/support/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/event.rs b/frame/support/src/event.rs index 3d042a3122db8..dc45f2bf69d94 100644 --- a/frame/support/src/event.rs +++ b/frame/support/src/event.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/hash.rs b/frame/support/src/hash.rs index f943bcf323090..9ce0968351a42 100644 --- a/frame/support/src/hash.rs +++ b/frame/support/src/hash.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/inherent.rs b/frame/support/src/inherent.rs index 2125f3e7f50a7..59d55b1df3f3c 100644 --- a/frame/support/src/inherent.rs +++ b/frame/support/src/inherent.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/instances.rs b/frame/support/src/instances.rs index 9908d16076a08..81139f8671818 100644 --- a/frame/support/src/instances.rs +++ b/frame/support/src/instances.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 2a23d203adf63..64bca7262829e 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/migrations.rs b/frame/support/src/migrations.rs index c61cbac62a16b..05833e0515c07 100644 --- a/frame/support/src/migrations.rs +++ b/frame/support/src/migrations.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index 224ff496a990a..201015e3a6222 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index af292aa1c8ffe..f51439f04d137 100644 --- a/frame/support/src/storage/bounded_btree_set.rs +++ b/frame/support/src/storage/bounded_btree_set.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index decf2cb341bf8..5ea7a62c79c28 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/child.rs b/frame/support/src/storage/child.rs index 19b00d1051361..a0a673d4b0417 100644 --- a/frame/support/src/storage/child.rs +++ b/frame/support/src/storage/child.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index 636a10feb1ab3..d63dda7d5b320 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/generator/map.rs b/frame/support/src/storage/generator/map.rs index 1a4225173c4ae..4157edefeac4b 100644 --- a/frame/support/src/storage/generator/map.rs +++ b/frame/support/src/storage/generator/map.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/generator/mod.rs b/frame/support/src/storage/generator/mod.rs index 576bada2e262c..ca893f44b3cb0 100644 --- a/frame/support/src/storage/generator/mod.rs +++ b/frame/support/src/storage/generator/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 4845673d3d8c2..1ad308bb22c78 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/generator/value.rs b/frame/support/src/storage/generator/value.rs index 3486eaa005c06..55b3487b1324c 100644 --- a/frame/support/src/storage/generator/value.rs +++ b/frame/support/src/storage/generator/value.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/hashed.rs b/frame/support/src/storage/hashed.rs index 241caff809b3d..a07db73c947d5 100644 --- a/frame/support/src/storage/hashed.rs +++ b/frame/support/src/storage/hashed.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/migration.rs b/frame/support/src/storage/migration.rs index 59422a282aab5..b2339efd0d204 100644 --- a/frame/support/src/storage/migration.rs +++ b/frame/support/src/storage/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 3cfe2bfaa577a..d79ddf09b7cc7 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index c4230cafc40be..99d645fba3298 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index d3595814d04b0..1a4d979d98f8f 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index da265fd6e6c87..182ddbedd9b8e 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 6532d47cfec67..e769daa490367 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index bcab996f68323..0706e9fb377e2 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 96d6f383ae117..30e6fb5637882 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index c5e7173bd0af7..a368988f378bd 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/unhashed.rs b/frame/support/src/storage/unhashed.rs index f700771b2d5cc..5e0b527acd132 100644 --- a/frame/support/src/storage/unhashed.rs +++ b/frame/support/src/storage/unhashed.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 641b623053939..db62d73035397 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 01817723e94eb..d0719063ef3e4 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index d7605593cd604..afac31e662e3f 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/filter.rs b/frame/support/src/traits/filter.rs index c67ffc3c3a11e..95e5954184b4b 100644 --- a/frame/support/src/traits/filter.rs +++ b/frame/support/src/traits/filter.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index 2a8b0a156247a..ffb8dfb821ad0 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/members.rs b/frame/support/src/traits/members.rs index 06a4c759c46db..ba72b4819933b 100644 --- a/frame/support/src/traits/members.rs +++ b/frame/support/src/traits/members.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/metadata.rs b/frame/support/src/traits/metadata.rs index 50fb53fc57063..c76c53dbe8b2d 100644 --- a/frame/support/src/traits/metadata.rs +++ b/frame/support/src/traits/metadata.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 8bab1581a697c..c68561367e3da 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/randomness.rs b/frame/support/src/traits/randomness.rs index 865893f99b393..d68b95b1dfcf5 100644 --- a/frame/support/src/traits/randomness.rs +++ b/frame/support/src/traits/randomness.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 1cedb96cb14bb..5ba233c29be1f 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/storage.rs b/frame/support/src/traits/storage.rs index 9a88a3ed44046..e484140cc2fd9 100644 --- a/frame/support/src/traits/storage.rs +++ b/frame/support/src/traits/storage.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/stored_map.rs b/frame/support/src/traits/stored_map.rs index 715a5211be430..5173eaeb5def0 100644 --- a/frame/support/src/traits/stored_map.rs +++ b/frame/support/src/traits/stored_map.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens.rs b/frame/support/src/traits/tokens.rs index 91a9382d07fcc..92f8ce12d9128 100644 --- a/frame/support/src/traits/tokens.rs +++ b/frame/support/src/traits/tokens.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index 9fdb08b8bd6e9..d5756ee84c47a 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/currency/lockable.rs b/frame/support/src/traits/tokens/currency/lockable.rs index 26463864a6471..a10edd6e3e874 100644 --- a/frame/support/src/traits/tokens/currency/lockable.rs +++ b/frame/support/src/traits/tokens/currency/lockable.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/currency/reservable.rs b/frame/support/src/traits/tokens/currency/reservable.rs index e2313a9d2550d..35455aaecdb49 100644 --- a/frame/support/src/traits/tokens/currency/reservable.rs +++ b/frame/support/src/traits/tokens/currency/reservable.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs index b033236d447bb..712103a1e8837 100644 --- a/frame/support/src/traits/tokens/fungible.rs +++ b/frame/support/src/traits/tokens/fungible.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungible/balanced.rs b/frame/support/src/traits/tokens/fungible/balanced.rs index 7b33a595a1b55..196f3a35754af 100644 --- a/frame/support/src/traits/tokens/fungible/balanced.rs +++ b/frame/support/src/traits/tokens/fungible/balanced.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungible/imbalance.rs b/frame/support/src/traits/tokens/fungible/imbalance.rs index 362e0c126d996..ca911cf12d44c 100644 --- a/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index b164a99671658..8e68b36d60c7a 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles/approvals.rs b/frame/support/src/traits/tokens/fungibles/approvals.rs index 06e81b8591a80..7a08f11cf042a 100644 --- a/frame/support/src/traits/tokens/fungibles/approvals.rs +++ b/frame/support/src/traits/tokens/fungibles/approvals.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles/balanced.rs b/frame/support/src/traits/tokens/fungibles/balanced.rs index 40a65305b87da..e07d45cc47170 100644 --- a/frame/support/src/traits/tokens/fungibles/balanced.rs +++ b/frame/support/src/traits/tokens/fungibles/balanced.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles/imbalance.rs b/frame/support/src/traits/tokens/fungibles/imbalance.rs index c44c471646485..61bd4a43064e6 100644 --- a/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles/metadata.rs b/frame/support/src/traits/tokens/fungibles/metadata.rs index 08bf5c4710a7d..b736ab1489f58 100644 --- a/frame/support/src/traits/tokens/fungibles/metadata.rs +++ b/frame/support/src/traits/tokens/fungibles/metadata.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/imbalance.rs b/frame/support/src/traits/tokens/imbalance.rs index eaa18be58f617..d721beb41494c 100644 --- a/frame/support/src/traits/tokens/imbalance.rs +++ b/frame/support/src/traits/tokens/imbalance.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs b/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs index bc7df0e2acf33..0125254cefc85 100644 --- a/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs +++ b/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/imbalance/signed_imbalance.rs b/frame/support/src/traits/tokens/imbalance/signed_imbalance.rs index 3e76d069f50e7..f969a4363405a 100644 --- a/frame/support/src/traits/tokens/imbalance/signed_imbalance.rs +++ b/frame/support/src/traits/tokens/imbalance/signed_imbalance.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/imbalance/split_two_ways.rs b/frame/support/src/traits/tokens/imbalance/split_two_ways.rs index 882b43c2e914c..a5e42451d82eb 100644 --- a/frame/support/src/traits/tokens/imbalance/split_two_ways.rs +++ b/frame/support/src/traits/tokens/imbalance/split_two_ways.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index 100138171abe7..f30fd02bfe831 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/nonfungible.rs b/frame/support/src/traits/tokens/nonfungible.rs index 821884f6e3905..08e9a3a18a4b8 100644 --- a/frame/support/src/traits/tokens/nonfungible.rs +++ b/frame/support/src/traits/tokens/nonfungible.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/nonfungibles.rs b/frame/support/src/traits/tokens/nonfungibles.rs index b5a14761064f3..1172fb6022830 100644 --- a/frame/support/src/traits/tokens/nonfungibles.rs +++ b/frame/support/src/traits/tokens/nonfungibles.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/validation.rs b/frame/support/src/traits/validation.rs index e5c81a149e4d0..135dd927acbb2 100644 --- a/frame/support/src/traits/validation.rs +++ b/frame/support/src/traits/validation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/voting.rs b/frame/support/src/traits/voting.rs index 62c6217ad59bc..719ad7f0f71d0 100644 --- a/frame/support/src/traits/voting.rs +++ b/frame/support/src/traits/voting.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index ec5f37823ad47..65087c85d3265 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index 47b81e1020693..0c955c749613c 100644 --- a/frame/support/test/compile_pass/src/lib.rs +++ b/frame/support/test/compile_pass/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/frame/support/test/pallet/src/lib.rs b/frame/support/test/pallet/src/lib.rs index f9f94b06a0a5a..bd181ea5b81bf 100644 --- a/frame/support/test/pallet/src/lib.rs +++ b/frame/support/test/pallet/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/src/lib.rs b/frame/support/test/src/lib.rs index 073f8c9c19352..dd3fbd1f3020d 100644 --- a/frame/support/test/src/lib.rs +++ b/frame/support/test/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/src/pallet_version.rs b/frame/support/test/src/pallet_version.rs index bdea3859d65c6..096289116c419 100644 --- a/frame/support/test/src/pallet_version.rs +++ b/frame/support/test/src/pallet_version.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index b2717b0f095ca..267d560edf92d 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/construct_runtime_ui.rs b/frame/support/test/tests/construct_runtime_ui.rs index ee475e37605ef..66636416c1f51 100644 --- a/frame/support/test/tests/construct_runtime_ui.rs +++ b/frame/support/test/tests/construct_runtime_ui.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_module_ui.rs b/frame/support/test/tests/decl_module_ui.rs index e84025b9f2564..829850ec2d476 100644 --- a/frame/support/test/tests/decl_module_ui.rs +++ b/frame/support/test/tests/decl_module_ui.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_storage.rs b/frame/support/test/tests/decl_storage.rs index 347a3130daa79..be5d70be17f69 100644 --- a/frame/support/test/tests/decl_storage.rs +++ b/frame/support/test/tests/decl_storage.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_storage_ui.rs b/frame/support/test/tests/decl_storage_ui.rs index 400ddfc0f94f4..d4db02ad19a0e 100644 --- a/frame/support/test/tests/decl_storage_ui.rs +++ b/frame/support/test/tests/decl_storage_ui.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_storage_ui/config_duplicate.rs b/frame/support/test/tests/decl_storage_ui/config_duplicate.rs index 17f80c8c84755..db2cdbdc65492 100644 --- a/frame/support/test/tests/decl_storage_ui/config_duplicate.rs +++ b/frame/support/test/tests/decl_storage_ui/config_duplicate.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs b/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs index fec6aeb64cec4..b804bf8980383 100644 --- a/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs +++ b/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_storage_ui/get_duplicate.rs b/frame/support/test/tests/decl_storage_ui/get_duplicate.rs index 13c57a638bb18..bc03ff6b4a4f9 100644 --- a/frame/support/test/tests/decl_storage_ui/get_duplicate.rs +++ b/frame/support/test/tests/decl_storage_ui/get_duplicate.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/derive_no_bound.rs b/frame/support/test/tests/derive_no_bound.rs index 1827844664fa7..e1cf539f2ac58 100644 --- a/frame/support/test/tests/derive_no_bound.rs +++ b/frame/support/test/tests/derive_no_bound.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/derive_no_bound_ui.rs b/frame/support/test/tests/derive_no_bound_ui.rs index 22c116931a47e..91e530d1d8da7 100644 --- a/frame/support/test/tests/derive_no_bound_ui.rs +++ b/frame/support/test/tests/derive_no_bound_ui.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/final_keys.rs b/frame/support/test/tests/final_keys.rs index e89f961d893f5..c1723c6ad7a1b 100644 --- a/frame/support/test/tests/final_keys.rs +++ b/frame/support/test/tests/final_keys.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/genesisconfig.rs b/frame/support/test/tests/genesisconfig.rs index d488e8bfbfaff..7895e863fd826 100644 --- a/frame/support/test/tests/genesisconfig.rs +++ b/frame/support/test/tests/genesisconfig.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/instance.rs b/frame/support/test/tests/instance.rs index 5677b9ac14da6..2fe8d0e0f22f5 100644 --- a/frame/support/test/tests/instance.rs +++ b/frame/support/test/tests/instance.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/issue2219.rs b/frame/support/test/tests/issue2219.rs index 68ad2a50a21bc..196068ac2fa4a 100644 --- a/frame/support/test/tests/issue2219.rs +++ b/frame/support/test/tests/issue2219.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index e57c3466e7ef0..1e923a6fdd6ec 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index b1ed08051f247..dc76f1fcbf036 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 81e16ee3624f3..80ab3c2267fdc 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 740bfe51d439d..4a8636919b583 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet_ui.rs b/frame/support/test/tests/pallet_ui.rs index 6f56c1efd6d73..a77d76deff8dc 100644 --- a/frame/support/test/tests/pallet_ui.rs +++ b/frame/support/test/tests/pallet_ui.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs index 128960fdb1c3d..7ed8454668327 100644 --- a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs +++ b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/storage_transaction.rs b/frame/support/test/tests/storage_transaction.rs index 4e97a87377b17..0f1c3a2e0c536 100644 --- a/frame/support/test/tests/storage_transaction.rs +++ b/frame/support/test/tests/storage_transaction.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/system.rs b/frame/support/test/tests/system.rs index 9def12131dd19..0083835640cb7 100644 --- a/frame/support/test/tests/system.rs +++ b/frame/support/test/tests/system.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index f1d819cb6525a..0bc34fcbc5be2 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/benchmarking/src/lib.rs b/frame/system/benchmarking/src/lib.rs index eddf78ce6b254..367e6c73c4134 100644 --- a/frame/system/benchmarking/src/lib.rs +++ b/frame/system/benchmarking/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/benchmarking/src/mock.rs b/frame/system/benchmarking/src/mock.rs index ff00b76c45fdf..08b043ae62741 100644 --- a/frame/system/benchmarking/src/mock.rs +++ b/frame/system/benchmarking/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/rpc/runtime-api/src/lib.rs b/frame/system/rpc/runtime-api/src/lib.rs index 319883c36d748..6e01bdae2d150 100644 --- a/frame/system/rpc/runtime-api/src/lib.rs +++ b/frame/system/rpc/runtime-api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_genesis.rs b/frame/system/src/extensions/check_genesis.rs index c758f9b6cb6ee..4b52691a6d328 100644 --- a/frame/system/src/extensions/check_genesis.rs +++ b/frame/system/src/extensions/check_genesis.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index 140a06298df33..ed11c37598362 100644 --- a/frame/system/src/extensions/check_mortality.rs +++ b/frame/system/src/extensions/check_mortality.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_non_zero_sender.rs b/frame/system/src/extensions/check_non_zero_sender.rs index 349bc0bede0d8..5910a865a7766 100644 --- a/frame/system/src/extensions/check_non_zero_sender.rs +++ b/frame/system/src/extensions/check_non_zero_sender.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_nonce.rs b/frame/system/src/extensions/check_nonce.rs index 3c6f9a1b4dbd1..476aa2fb7478c 100644 --- a/frame/system/src/extensions/check_nonce.rs +++ b/frame/system/src/extensions/check_nonce.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_spec_version.rs b/frame/system/src/extensions/check_spec_version.rs index 1e1a31d4d870d..dce70a940765a 100644 --- a/frame/system/src/extensions/check_spec_version.rs +++ b/frame/system/src/extensions/check_spec_version.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_tx_version.rs b/frame/system/src/extensions/check_tx_version.rs index e1e7b070e831d..69060729cccc3 100644 --- a/frame/system/src/extensions/check_tx_version.rs +++ b/frame/system/src/extensions/check_tx_version.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index 8f83b7594cb5b..774139054d08c 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/mod.rs b/frame/system/src/extensions/mod.rs index 7eaff34c1d7f3..9ba73c5f4d4e5 100644 --- a/frame/system/src/extensions/mod.rs +++ b/frame/system/src/extensions/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 726837bf82672..80d2934914691 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index 687fb6f3dd367..4942a5dace7d4 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/migrations/mod.rs b/frame/system/src/migrations/mod.rs index 03547d200f4ac..358ba55b7c819 100644 --- a/frame/system/src/migrations/mod.rs +++ b/frame/system/src/migrations/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index 5d10962a8f402..f3f542aa83a9a 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/mocking.rs b/frame/system/src/mocking.rs index 7e6026b726186..ccb63f9bb236c 100644 --- a/frame/system/src/mocking.rs +++ b/frame/system/src/mocking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/offchain.rs b/frame/system/src/offchain.rs index c4986e67319f0..bf52ab8e3791d 100644 --- a/frame/system/src/offchain.rs +++ b/frame/system/src/offchain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index de3158562f490..411925c70275f 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index d05ad2a867b59..ff6900032d961 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/timestamp/src/benchmarking.rs b/frame/timestamp/src/benchmarking.rs index 98e05439df72b..0da71dbdd1a59 100644 --- a/frame/timestamp/src/benchmarking.rs +++ b/frame/timestamp/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index 0d2c3f385d170..a0b9babcd9842 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index b4e7370ee7616..fb452ebe35953 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 5b6f11de77dde..7abee6192f2e0 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index 5edb5f042a61d..7761800638d37 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/migrations/mod.rs b/frame/tips/src/migrations/mod.rs index 81139120da1c8..719bb2f86fddd 100644 --- a/frame/tips/src/migrations/mod.rs +++ b/frame/tips/src/migrations/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/migrations/v4.rs b/frame/tips/src/migrations/v4.rs index 69df1d08d2c8a..34f7a43ec12de 100644 --- a/frame/tips/src/migrations/v4.rs +++ b/frame/tips/src/migrations/v4.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index 5bab523b0393b..f9ad431c39480 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 3376afb066170..29e85ccad8510 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index be16fa45f9534..83801c44d3578 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs index 09482f96490c7..9eafc43fc2569 100644 --- a/frame/transaction-payment/asset-tx-payment/src/payment.rs +++ b/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index 6292829d21483..f2a1ad1406575 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/rpc/runtime-api/src/lib.rs b/frame/transaction-payment/rpc/runtime-api/src/lib.rs index 696550d3ef040..5a0c70138db24 100644 --- a/frame/transaction-payment/rpc/runtime-api/src/lib.rs +++ b/frame/transaction-payment/rpc/runtime-api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index 78230ee6e468f..b2ff31618f78a 100644 --- a/frame/transaction-payment/rpc/src/lib.rs +++ b/frame/transaction-payment/rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index fa8b0e9be0c1c..8bda316c501ad 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/src/types.rs b/frame/transaction-payment/src/types.rs index 3ce5bcf890bd1..3faebfed48946 100644 --- a/frame/transaction-payment/src/types.rs +++ b/frame/transaction-payment/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs index b03c75148fa12..285b5cba7ad22 100644 --- a/frame/transaction-storage/src/benchmarking.rs +++ b/frame/transaction-storage/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index 2cd47b1cd0db2..23cc9ee0a2389 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs index 6356312ca5008..753d4baaf00e2 100644 --- a/frame/transaction-storage/src/mock.rs +++ b/frame/transaction-storage/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-storage/src/tests.rs b/frame/transaction-storage/src/tests.rs index c443f51ffb50f..8825890ae67a2 100644 --- a/frame/transaction-storage/src/tests.rs +++ b/frame/transaction-storage/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index 104b18d3f92ce..ffea996b83d99 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index 8570b0efdb945..a0dd58ee3d42a 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 5258426e2681c..057ee0c6032a4 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index 765f71f5dae82..b6d23440a73fe 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index 126c8a1766268..79635ac2a725d 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/try-runtime/src/lib.rs b/frame/try-runtime/src/lib.rs index 754fc1d2a3303..bf08112bfc376 100644 --- a/frame/try-runtime/src/lib.rs +++ b/frame/try-runtime/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 513509bda70ea..f3f9b7b28df72 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 9c3a5c1b19f86..5d573e42097e0 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index 72aa1dd0d4cb1..a9695e8e898ae 100644 --- a/frame/uniques/src/impl_nonfungibles.rs +++ b/frame/uniques/src/impl_nonfungibles.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index b5dada9ef6459..33a8866019cf4 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/migration.rs b/frame/uniques/src/migration.rs index 76f78c2bc64ed..71ccc6b07bd72 100644 --- a/frame/uniques/src/migration.rs +++ b/frame/uniques/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index 679adf0424cf4..2a94fcbee347a 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 8d0d6fdf9af37..0e0dc413a01a3 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/types.rs b/frame/uniques/src/types.rs index 5ba443dba6c4b..4d1afe694bd8d 100644 --- a/frame/uniques/src/types.rs +++ b/frame/uniques/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 168e0fcc80156..3a67eb09017be 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index ce59d7e898eb1..402128d005808 100644 --- a/frame/utility/src/benchmarking.rs +++ b/frame/utility/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 2200d96da600e..ec48087e2ef48 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 11b63254eb40b..9a1e11f54d6e3 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index bce18271684bc..15798007a9ba3 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/benchmarking.rs b/frame/vesting/src/benchmarking.rs index b52ddac3e8857..1693fdd3f1cbe 100644 --- a/frame/vesting/src/benchmarking.rs +++ b/frame/vesting/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 6857918bc9a1c..fcad0c57f937d 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/migrations.rs b/frame/vesting/src/migrations.rs index f8024926f34aa..688ebf6ad1c93 100644 --- a/frame/vesting/src/migrations.rs +++ b/frame/vesting/src/migrations.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index 2176716bf3405..8a830d72b26b8 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/tests.rs b/frame/vesting/src/tests.rs index 2a6dd0520c3b0..cbc2e09c83199 100644 --- a/frame/vesting/src/tests.rs +++ b/frame/vesting/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/vesting_info.rs b/frame/vesting/src/vesting_info.rs index 81bffa199fd72..9069b69482769 100644 --- a/frame/vesting/src/vesting_info.rs +++ b/frame/vesting/src/vesting_info.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index 3ccc1a5bda362..660f839655579 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index 34907d6197285..6c6b8f453a267 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index db3ab3b76850e..7241a1c2610de 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/lib.rs b/primitives/api/proc-macro/src/lib.rs index b8731d70ca3cf..20a2f76f2c83d 100644 --- a/primitives/api/proc-macro/src/lib.rs +++ b/primitives/api/proc-macro/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs index 9483d018c4a40..ffc158ac94d29 100644 --- a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/utils.rs b/primitives/api/proc-macro/src/utils.rs index a3f21638751e9..2aa6a657aa9c0 100644 --- a/primitives/api/proc-macro/src/utils.rs +++ b/primitives/api/proc-macro/src/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index 41c0151d6c538..964ef15ce5f5a 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/test/benches/bench.rs b/primitives/api/test/benches/bench.rs index b3d96a2db6a56..2682c91f94106 100644 --- a/primitives/api/test/benches/bench.rs +++ b/primitives/api/test/benches/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/test/tests/decl_and_impl.rs b/primitives/api/test/tests/decl_and_impl.rs index 8d1b04a37a9fa..1db416a1d3db6 100644 --- a/primitives/api/test/tests/decl_and_impl.rs +++ b/primitives/api/test/tests/decl_and_impl.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 5c9b25fa31861..e085b023b1227 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/test/tests/trybuild.rs b/primitives/api/test/tests/trybuild.rs index 5a6025f463af0..9e3af145dc566 100644 --- a/primitives/api/test/tests/trybuild.rs +++ b/primitives/api/test/tests/trybuild.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/src/ecdsa.rs b/primitives/application-crypto/src/ecdsa.rs index fba1fc03b2533..6a0eb7ab2f84d 100644 --- a/primitives/application-crypto/src/ecdsa.rs +++ b/primitives/application-crypto/src/ecdsa.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/src/ed25519.rs b/primitives/application-crypto/src/ed25519.rs index 35fcb2403a033..f5ec40233ca93 100644 --- a/primitives/application-crypto/src/ed25519.rs +++ b/primitives/application-crypto/src/ed25519.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index a6bba43632221..b12fe72b271a6 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/src/sr25519.rs b/primitives/application-crypto/src/sr25519.rs index 6cd1bf35a2354..81c5320efd71b 100644 --- a/primitives/application-crypto/src/sr25519.rs +++ b/primitives/application-crypto/src/sr25519.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/src/traits.rs b/primitives/application-crypto/src/traits.rs index 376d12f0c7a3e..7a99c144b69f9 100644 --- a/primitives/application-crypto/src/traits.rs +++ b/primitives/application-crypto/src/traits.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/test/src/ecdsa.rs b/primitives/application-crypto/test/src/ecdsa.rs index c4aa6a2afbd61..e45a3d5f8f86c 100644 --- a/primitives/application-crypto/test/src/ecdsa.rs +++ b/primitives/application-crypto/test/src/ecdsa.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/test/src/ed25519.rs b/primitives/application-crypto/test/src/ed25519.rs index 7cfd801388c78..ef2df9fe9196e 100644 --- a/primitives/application-crypto/test/src/ed25519.rs +++ b/primitives/application-crypto/test/src/ed25519.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/test/src/lib.rs b/primitives/application-crypto/test/src/lib.rs index 6b7734764e793..7cc3f8b0780e6 100644 --- a/primitives/application-crypto/test/src/lib.rs +++ b/primitives/application-crypto/test/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/test/src/sr25519.rs b/primitives/application-crypto/test/src/sr25519.rs index 12dfbc609fb01..e15ffe82a1c35 100644 --- a/primitives/application-crypto/test/src/sr25519.rs +++ b/primitives/application-crypto/test/src/sr25519.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/benches/bench.rs b/primitives/arithmetic/benches/bench.rs index 02db00aa0bf82..3e4fafe2a4a9a 100644 --- a/primitives/arithmetic/benches/bench.rs +++ b/primitives/arithmetic/benches/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/fuzzer/src/biguint.rs b/primitives/arithmetic/fuzzer/src/biguint.rs index ca5b8379afff5..e4c088a2e8ab3 100644 --- a/primitives/arithmetic/fuzzer/src/biguint.rs +++ b/primitives/arithmetic/fuzzer/src/biguint.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/fuzzer/src/fixed_point.rs b/primitives/arithmetic/fuzzer/src/fixed_point.rs index d8f058ae51e2c..c1b93f8c63a11 100644 --- a/primitives/arithmetic/fuzzer/src/fixed_point.rs +++ b/primitives/arithmetic/fuzzer/src/fixed_point.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/fuzzer/src/multiply_by_rational.rs b/primitives/arithmetic/fuzzer/src/multiply_by_rational.rs index 3089d4b092183..019cf0ec39b7d 100644 --- a/primitives/arithmetic/fuzzer/src/multiply_by_rational.rs +++ b/primitives/arithmetic/fuzzer/src/multiply_by_rational.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/fuzzer/src/normalize.rs b/primitives/arithmetic/fuzzer/src/normalize.rs index 2662565106e66..e4f90dbc1c415 100644 --- a/primitives/arithmetic/fuzzer/src/normalize.rs +++ b/primitives/arithmetic/fuzzer/src/normalize.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/fuzzer/src/per_thing_rational.rs b/primitives/arithmetic/fuzzer/src/per_thing_rational.rs index 7b90faa94069f..7021c54c0ba04 100644 --- a/primitives/arithmetic/fuzzer/src/per_thing_rational.rs +++ b/primitives/arithmetic/fuzzer/src/per_thing_rational.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/biguint.rs b/primitives/arithmetic/src/biguint.rs index 17ed323dc0ce4..b26ac4294d111 100644 --- a/primitives/arithmetic/src/biguint.rs +++ b/primitives/arithmetic/src/biguint.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/fixed_point.rs b/primitives/arithmetic/src/fixed_point.rs index 7a81f222c4926..206e63af95b1f 100644 --- a/primitives/arithmetic/src/fixed_point.rs +++ b/primitives/arithmetic/src/fixed_point.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/helpers_128bit.rs b/primitives/arithmetic/src/helpers_128bit.rs index bbf69ea359fe0..af9729c9702c3 100644 --- a/primitives/arithmetic/src/helpers_128bit.rs +++ b/primitives/arithmetic/src/helpers_128bit.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index 8671ceb0396e7..92f8a708316de 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index 783b331b33532..21ad0dd52099c 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/rational.rs b/primitives/arithmetic/src/rational.rs index 225e1d9521827..63ae6e65bc9ee 100644 --- a/primitives/arithmetic/src/rational.rs +++ b/primitives/arithmetic/src/rational.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/traits.rs b/primitives/arithmetic/src/traits.rs index 53341117b1fee..447f8cef51f9a 100644 --- a/primitives/arithmetic/src/traits.rs +++ b/primitives/arithmetic/src/traits.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/authority-discovery/src/lib.rs b/primitives/authority-discovery/src/lib.rs index 871a35e6bf487..95bb458b1be8c 100644 --- a/primitives/authority-discovery/src/lib.rs +++ b/primitives/authority-discovery/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/authorship/src/lib.rs b/primitives/authorship/src/lib.rs index ac4b5fd315dc2..25eaeaf9bc16d 100644 --- a/primitives/authorship/src/lib.rs +++ b/primitives/authorship/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index 63c6520d86803..ed392139de13f 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index bf72b801eec0a..8dbdd66f3559b 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index e428c0ea01215..215214bef2942 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/beefy/src/witness.rs b/primitives/beefy/src/witness.rs index 102a6be09c789..aae0608150534 100644 --- a/primitives/beefy/src/witness.rs +++ b/primitives/beefy/src/witness.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/block-builder/src/lib.rs b/primitives/block-builder/src/lib.rs index 3741b19200647..229f115c6667f 100644 --- a/primitives/block-builder/src/lib.rs +++ b/primitives/block-builder/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index 71c3f36a161b6..3c6419648388e 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/blockchain/src/error.rs b/primitives/blockchain/src/error.rs index ef3afa5bce942..bbd65e002a3b3 100644 --- a/primitives/blockchain/src/error.rs +++ b/primitives/blockchain/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index 928409963bcd4..9f388dc58fbc4 100644 --- a/primitives/blockchain/src/header_metadata.rs +++ b/primitives/blockchain/src/header_metadata.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/blockchain/src/lib.rs b/primitives/blockchain/src/lib.rs index cd36cabe15517..2fdef6cba9e5f 100644 --- a/primitives/blockchain/src/lib.rs +++ b/primitives/blockchain/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/aura/src/digests.rs b/primitives/consensus/aura/src/digests.rs index 6925862d0ce94..b71930b6c6b80 100644 --- a/primitives/consensus/aura/src/digests.rs +++ b/primitives/consensus/aura/src/digests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/primitives/consensus/aura/src/inherents.rs b/primitives/consensus/aura/src/inherents.rs index 2a797b5d3f393..c3fa43bec02b8 100644 --- a/primitives/consensus/aura/src/inherents.rs +++ b/primitives/consensus/aura/src/inherents.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/aura/src/lib.rs b/primitives/consensus/aura/src/lib.rs index b85443e0917e4..cec89d0449d8e 100644 --- a/primitives/consensus/aura/src/lib.rs +++ b/primitives/consensus/aura/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/babe/src/digests.rs b/primitives/consensus/babe/src/digests.rs index 4847adec37f18..0f21c913ac57e 100644 --- a/primitives/consensus/babe/src/digests.rs +++ b/primitives/consensus/babe/src/digests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/babe/src/inherents.rs b/primitives/consensus/babe/src/inherents.rs index cecd61998a4db..1eadfd85d1147 100644 --- a/primitives/consensus/babe/src/inherents.rs +++ b/primitives/consensus/babe/src/inherents.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/babe/src/lib.rs b/primitives/consensus/babe/src/lib.rs index 1971563ff198b..e7dfc100825d6 100644 --- a/primitives/consensus/babe/src/lib.rs +++ b/primitives/consensus/babe/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/common/src/block_validation.rs b/primitives/consensus/common/src/block_validation.rs index 54a70a402b060..71f3a80b27a64 100644 --- a/primitives/consensus/common/src/block_validation.rs +++ b/primitives/consensus/common/src/block_validation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/common/src/error.rs b/primitives/consensus/common/src/error.rs index 546f30d3e8202..280ff2322898d 100644 --- a/primitives/consensus/common/src/error.rs +++ b/primitives/consensus/common/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/common/src/evaluation.rs b/primitives/consensus/common/src/evaluation.rs index 19be5e5526349..d0ddbb6fab813 100644 --- a/primitives/consensus/common/src/evaluation.rs +++ b/primitives/consensus/common/src/evaluation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index 456ba965f4aa0..492ad83ddf5bd 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/common/src/select_chain.rs b/primitives/consensus/common/src/select_chain.rs index fd8b06ecf8abb..f366cd34c51ea 100644 --- a/primitives/consensus/common/src/select_chain.rs +++ b/primitives/consensus/common/src/select_chain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/pow/src/lib.rs b/primitives/consensus/pow/src/lib.rs index ac8bc589c136f..fe10ee808db98 100644 --- a/primitives/consensus/pow/src/lib.rs +++ b/primitives/consensus/pow/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/slots/src/lib.rs b/primitives/consensus/slots/src/lib.rs index 72b3c95068e39..e8ab98399414b 100644 --- a/primitives/consensus/slots/src/lib.rs +++ b/primitives/consensus/slots/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/vrf/src/lib.rs b/primitives/consensus/vrf/src/lib.rs index 19391c6c1c84f..07e3f2c319706 100644 --- a/primitives/consensus/vrf/src/lib.rs +++ b/primitives/consensus/vrf/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/vrf/src/schnorrkel.rs b/primitives/consensus/vrf/src/schnorrkel.rs index 687e0bd231820..1ef23427e0ed0 100644 --- a/primitives/consensus/vrf/src/schnorrkel.rs +++ b/primitives/consensus/vrf/src/schnorrkel.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/hashing/proc-macro/src/impls.rs b/primitives/core/hashing/proc-macro/src/impls.rs index 0ce388762aa30..ff9593ea18441 100644 --- a/primitives/core/hashing/proc-macro/src/impls.rs +++ b/primitives/core/hashing/proc-macro/src/impls.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/hashing/proc-macro/src/lib.rs b/primitives/core/hashing/proc-macro/src/lib.rs index 2af8554f4ece9..2db292d8dc0cb 100644 --- a/primitives/core/hashing/proc-macro/src/lib.rs +++ b/primitives/core/hashing/proc-macro/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/hashing/src/lib.rs b/primitives/core/hashing/src/lib.rs index f806613c5b545..9fa433a32320a 100644 --- a/primitives/core/hashing/src/lib.rs +++ b/primitives/core/hashing/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index e6735c7745cf6..d3dd8b92bd794 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 682f46c2a4327..c5e53c7029e66 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index df9ec6a457c62..bb99a4ae02006 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/hash.rs b/primitives/core/src/hash.rs index 55a9664c9dad4..f2974e9372ad5 100644 --- a/primitives/core/src/hash.rs +++ b/primitives/core/src/hash.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/hasher.rs b/primitives/core/src/hasher.rs index 01680de083762..173bd560ad1e3 100644 --- a/primitives/core/src/hasher.rs +++ b/primitives/core/src/hasher.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/hashing.rs b/primitives/core/src/hashing.rs index 092cfc51b9508..1c439355a33c0 100644 --- a/primitives/core/src/hashing.rs +++ b/primitives/core/src/hashing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/hexdisplay.rs b/primitives/core/src/hexdisplay.rs index 4d91db1567920..e5262ba8f657b 100644 --- a/primitives/core/src/hexdisplay.rs +++ b/primitives/core/src/hexdisplay.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 5fca42adde991..c794752e9d3d2 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 8058d4d05d6ad..b9e310dc1fb10 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/offchain/storage.rs b/primitives/core/src/offchain/storage.rs index ff72006cffd60..cf2c93641f245 100644 --- a/primitives/core/src/offchain/storage.rs +++ b/primitives/core/src/offchain/storage.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index 29b9edb03deb5..a2065eb17717f 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/sandbox.rs b/primitives/core/src/sandbox.rs index acc3fda5e9b17..1f408a3b8cc05 100644 --- a/primitives/core/src/sandbox.rs +++ b/primitives/core/src/sandbox.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index 71379dfc66b92..4094c4d1b4405 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/testing.rs b/primitives/core/src/testing.rs index a40a37804c031..d5ca1dc45fa0c 100644 --- a/primitives/core/src/testing.rs +++ b/primitives/core/src/testing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs index e3d7d8e283e21..80e8963a2909d 100644 --- a/primitives/core/src/traits.rs +++ b/primitives/core/src/traits.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/u32_trait.rs b/primitives/core/src/u32_trait.rs index 37837e7c0548c..ff15080400340 100644 --- a/primitives/core/src/u32_trait.rs +++ b/primitives/core/src/u32_trait.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/uint.rs b/primitives/core/src/uint.rs index a74980332ad28..f4eb3a19ac36c 100644 --- a/primitives/core/src/uint.rs +++ b/primitives/core/src/uint.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/database/src/error.rs b/primitives/database/src/error.rs index 4bf5a20aff401..78646427a2b5d 100644 --- a/primitives/database/src/error.rs +++ b/primitives/database/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/database/src/kvdb.rs b/primitives/database/src/kvdb.rs index 1a2b0513dc28a..5fe5fda307a1e 100644 --- a/primitives/database/src/kvdb.rs +++ b/primitives/database/src/kvdb.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/database/src/lib.rs b/primitives/database/src/lib.rs index d30c7eb3323e9..2d7c5fd6653e1 100644 --- a/primitives/database/src/lib.rs +++ b/primitives/database/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/database/src/mem.rs b/primitives/database/src/mem.rs index d1b1861e98fdd..6ecd44c6005b9 100644 --- a/primitives/database/src/mem.rs +++ b/primitives/database/src/mem.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/debug-derive/src/impls.rs b/primitives/debug-derive/src/impls.rs index 0e67ef81bc853..bab0146e46824 100644 --- a/primitives/debug-derive/src/impls.rs +++ b/primitives/debug-derive/src/impls.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/debug-derive/src/lib.rs b/primitives/debug-derive/src/lib.rs index 7eaa3a0020e93..c98610ce47808 100644 --- a/primitives/debug-derive/src/lib.rs +++ b/primitives/debug-derive/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/debug-derive/tests/tests.rs b/primitives/debug-derive/tests/tests.rs index 4f4c7f4caabc2..39414da86bf45 100644 --- a/primitives/debug-derive/tests/tests.rs +++ b/primitives/debug-derive/tests/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/externalities/src/extensions.rs b/primitives/externalities/src/extensions.rs index 37086a707b648..d58edb749e9e6 100644 --- a/primitives/externalities/src/extensions.rs +++ b/primitives/externalities/src/extensions.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/externalities/src/lib.rs b/primitives/externalities/src/lib.rs index 6d560c3c7f11b..49b190b4ae260 100644 --- a/primitives/externalities/src/lib.rs +++ b/primitives/externalities/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/externalities/src/scope_limited.rs b/primitives/externalities/src/scope_limited.rs index 15a670a9abeee..1d2e6863c9e58 100644 --- a/primitives/externalities/src/scope_limited.rs +++ b/primitives/externalities/src/scope_limited.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index b762a1596bf82..dd5cef85a2ba5 100644 --- a/primitives/finality-grandpa/src/lib.rs +++ b/primitives/finality-grandpa/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/inherents/src/client_side.rs b/primitives/inherents/src/client_side.rs index 18877cae5f343..42068e24e029c 100644 --- a/primitives/inherents/src/client_side.rs +++ b/primitives/inherents/src/client_side.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/inherents/src/lib.rs b/primitives/inherents/src/lib.rs index 90f4e455a42d3..cd04a1bc3b3dd 100644 --- a/primitives/inherents/src/lib.rs +++ b/primitives/inherents/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/io/src/batch_verifier.rs b/primitives/io/src/batch_verifier.rs index 05c8a63694eb3..501d986758bf2 100644 --- a/primitives/io/src/batch_verifier.rs +++ b/primitives/io/src/batch_verifier.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 9025ae3d76f43..76ced407090c3 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keyring/src/ed25519.rs b/primitives/keyring/src/ed25519.rs index 4d99de6c59d70..6d56062d3473c 100644 --- a/primitives/keyring/src/ed25519.rs +++ b/primitives/keyring/src/ed25519.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keyring/src/lib.rs b/primitives/keyring/src/lib.rs index d7fb7c4fd2f2b..170a4c3d01b23 100644 --- a/primitives/keyring/src/lib.rs +++ b/primitives/keyring/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keyring/src/sr25519.rs b/primitives/keyring/src/sr25519.rs index d400cde035b70..86bcac9d58cbb 100644 --- a/primitives/keyring/src/sr25519.rs +++ b/primitives/keyring/src/sr25519.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keystore/src/lib.rs b/primitives/keystore/src/lib.rs index c45e8a6f5d2be..6c27e3df7ce0d 100644 --- a/primitives/keystore/src/lib.rs +++ b/primitives/keystore/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index 92a73eb98c90f..eb5847207daaf 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keystore/src/vrf.rs b/primitives/keystore/src/vrf.rs index 383abb77e17c7..7409353afe9f4 100644 --- a/primitives/keystore/src/vrf.rs +++ b/primitives/keystore/src/vrf.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/maybe-compressed-blob/src/lib.rs b/primitives/maybe-compressed-blob/src/lib.rs index e8a7e42b4eace..402ed90be21ca 100644 --- a/primitives/maybe-compressed-blob/src/lib.rs +++ b/primitives/maybe-compressed-blob/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/fuzzer/src/common.rs b/primitives/npos-elections/fuzzer/src/common.rs index e97f7f7df8b11..7ca66f72dd92b 100644 --- a/primitives/npos-elections/fuzzer/src/common.rs +++ b/primitives/npos-elections/fuzzer/src/common.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs index 0c140a8ce6fad..2af6a4c0f8151 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs b/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs index f1110da8ef8b0..59763a58686dd 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs index 7b2aacfa85882..0cd49c3f80442 100644 --- a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/fuzzer/src/reduce.rs b/primitives/npos-elections/fuzzer/src/reduce.rs index 5f8a4f0e13844..029bb18dc5b30 100644 --- a/primitives/npos-elections/fuzzer/src/reduce.rs +++ b/primitives/npos-elections/fuzzer/src/reduce.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/solution-type/src/codec.rs b/primitives/npos-elections/solution-type/src/codec.rs index 2dac076fcde42..71faa141f0b69 100644 --- a/primitives/npos-elections/solution-type/src/codec.rs +++ b/primitives/npos-elections/solution-type/src/codec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/solution-type/src/from_assignment_helpers.rs b/primitives/npos-elections/solution-type/src/from_assignment_helpers.rs index dc194baa6d9ea..e0613afc0d392 100644 --- a/primitives/npos-elections/solution-type/src/from_assignment_helpers.rs +++ b/primitives/npos-elections/solution-type/src/from_assignment_helpers.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/solution-type/src/index_assignment.rs b/primitives/npos-elections/solution-type/src/index_assignment.rs index d38dc3ec309d9..ccdcb4ba25cdb 100644 --- a/primitives/npos-elections/solution-type/src/index_assignment.rs +++ b/primitives/npos-elections/solution-type/src/index_assignment.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/solution-type/src/lib.rs b/primitives/npos-elections/solution-type/src/lib.rs index 967ead4400c3e..6e632d19e171e 100644 --- a/primitives/npos-elections/solution-type/src/lib.rs +++ b/primitives/npos-elections/solution-type/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/solution-type/src/single_page.rs b/primitives/npos-elections/solution-type/src/single_page.rs index 33017d558331a..01a8a8eba5dcc 100644 --- a/primitives/npos-elections/solution-type/src/single_page.rs +++ b/primitives/npos-elections/solution-type/src/single_page.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/assignments.rs b/primitives/npos-elections/src/assignments.rs index 330f7bd7e843e..5641a33447bad 100644 --- a/primitives/npos-elections/src/assignments.rs +++ b/primitives/npos-elections/src/assignments.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/balancing.rs b/primitives/npos-elections/src/balancing.rs index 63164049e5269..98f193e9e6116 100644 --- a/primitives/npos-elections/src/balancing.rs +++ b/primitives/npos-elections/src/balancing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/helpers.rs b/primitives/npos-elections/src/helpers.rs index ca97aeb996e48..76cfd59de6fb7 100644 --- a/primitives/npos-elections/src/helpers.rs +++ b/primitives/npos-elections/src/helpers.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 0b10b4c7c1b8f..bb1c38d3077c4 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at diff --git a/primitives/npos-elections/src/mock.rs b/primitives/npos-elections/src/mock.rs index 36fd78b5757ee..8e8e7ebc1c0c6 100644 --- a/primitives/npos-elections/src/mock.rs +++ b/primitives/npos-elections/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/node.rs b/primitives/npos-elections/src/node.rs index 62b728d52258b..6642a9ae39736 100644 --- a/primitives/npos-elections/src/node.rs +++ b/primitives/npos-elections/src/node.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index 5ed472284351a..c582c5910d69a 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index e9135a13190c6..7c51da9ee92e0 100644 --- a/primitives/npos-elections/src/phragmms.rs +++ b/primitives/npos-elections/src/phragmms.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/pjr.rs b/primitives/npos-elections/src/pjr.rs index 50556ea9cc335..2d58ca49c8a22 100644 --- a/primitives/npos-elections/src/pjr.rs +++ b/primitives/npos-elections/src/pjr.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/reduce.rs b/primitives/npos-elections/src/reduce.rs index 8ff0244b4694f..057ee339bd7d3 100644 --- a/primitives/npos-elections/src/reduce.rs +++ b/primitives/npos-elections/src/reduce.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index 0aac5c3c35df4..e7d0078b1fbe0 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/traits.rs b/primitives/npos-elections/src/traits.rs index cb24f770cdea0..0723948b62269 100644 --- a/primitives/npos-elections/src/traits.rs +++ b/primitives/npos-elections/src/traits.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/offchain/src/lib.rs b/primitives/offchain/src/lib.rs index 72ceca80cfbf8..3e967f16d2a84 100644 --- a/primitives/offchain/src/lib.rs +++ b/primitives/offchain/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/panic-handler/src/lib.rs b/primitives/panic-handler/src/lib.rs index eddb31a7f22ff..df1f78da1cbef 100644 --- a/primitives/panic-handler/src/lib.rs +++ b/primitives/panic-handler/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/rpc/src/lib.rs b/primitives/rpc/src/lib.rs index 0d716d5a07c18..915482e5fca70 100644 --- a/primitives/rpc/src/lib.rs +++ b/primitives/rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/rpc/src/list.rs b/primitives/rpc/src/list.rs index b3d0a4f546e94..7ec4d3491c7ea 100644 --- a/primitives/rpc/src/list.rs +++ b/primitives/rpc/src/list.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/rpc/src/number.rs b/primitives/rpc/src/number.rs index 916f2c3d83266..5a433a9598e01 100644 --- a/primitives/rpc/src/number.rs +++ b/primitives/rpc/src/number.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/rpc/src/tracing.rs b/primitives/rpc/src/tracing.rs index 737ace241037c..a923ffcb69e0d 100644 --- a/primitives/rpc/src/tracing.rs +++ b/primitives/rpc/src/tracing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/lib.rs b/primitives/runtime-interface/proc-macro/src/lib.rs index 6b0669a298e1c..afba38993fe76 100644 --- a/primitives/runtime-interface/proc-macro/src/lib.rs +++ b/primitives/runtime-interface/proc-macro/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/pass_by/codec.rs b/primitives/runtime-interface/proc-macro/src/pass_by/codec.rs index 2be455d17a47b..4259b137d67cb 100644 --- a/primitives/runtime-interface/proc-macro/src/pass_by/codec.rs +++ b/primitives/runtime-interface/proc-macro/src/pass_by/codec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs b/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs index f614e4d9f294d..1fd22c6a25383 100644 --- a/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs +++ b/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs b/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs index 6eaa689d6293a..7a527af129467 100644 --- a/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs +++ b/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/pass_by/mod.rs b/primitives/runtime-interface/proc-macro/src/pass_by/mod.rs index 80ac3396759fb..e32c2beb8b72a 100644 --- a/primitives/runtime-interface/proc-macro/src/pass_by/mod.rs +++ b/primitives/runtime-interface/proc-macro/src/pass_by/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs index c951dedb67713..cbb749a111a15 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs index c79886d45b18c..2416e6951fe25 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/mod.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/mod.rs index 78feda663850c..d14c1f67ecff5 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/mod.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs index c62e3ba87ccd3..c48da3b788518 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/utils.rs b/primitives/runtime-interface/proc-macro/src/utils.rs index 42ce09c573932..593f8ecafa7aa 100644 --- a/primitives/runtime-interface/proc-macro/src/utils.rs +++ b/primitives/runtime-interface/proc-macro/src/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/host.rs b/primitives/runtime-interface/src/host.rs index a6ea96af90043..36492430266a7 100644 --- a/primitives/runtime-interface/src/host.rs +++ b/primitives/runtime-interface/src/host.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/impls.rs b/primitives/runtime-interface/src/impls.rs index 16eecbd021e00..3c1927d6b361a 100644 --- a/primitives/runtime-interface/src/impls.rs +++ b/primitives/runtime-interface/src/impls.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/lib.rs b/primitives/runtime-interface/src/lib.rs index e8e29329a980f..d87b0d57a772a 100644 --- a/primitives/runtime-interface/src/lib.rs +++ b/primitives/runtime-interface/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/pass_by.rs b/primitives/runtime-interface/src/pass_by.rs index 02cbe502f02c5..fb2d6b818d174 100644 --- a/primitives/runtime-interface/src/pass_by.rs +++ b/primitives/runtime-interface/src/pass_by.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/util.rs b/primitives/runtime-interface/src/util.rs index 31045c83c9dcd..fe8afe99508a8 100644 --- a/primitives/runtime-interface/src/util.rs +++ b/primitives/runtime-interface/src/util.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/wasm.rs b/primitives/runtime-interface/src/wasm.rs index 28613f81a68b2..4ed27687a10a5 100644 --- a/primitives/runtime-interface/src/wasm.rs +++ b/primitives/runtime-interface/src/wasm.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/test-wasm-deprecated/build.rs b/primitives/runtime-interface/test-wasm-deprecated/build.rs index a1c4b2d892cfe..b773ed9cf6fb7 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/build.rs +++ b/primitives/runtime-interface/test-wasm-deprecated/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/test-wasm-deprecated/src/lib.rs b/primitives/runtime-interface/test-wasm-deprecated/src/lib.rs index 4a59e4fe8aa5f..512d52214c12b 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/src/lib.rs +++ b/primitives/runtime-interface/test-wasm-deprecated/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/test-wasm/build.rs b/primitives/runtime-interface/test-wasm/build.rs index a1c4b2d892cfe..b773ed9cf6fb7 100644 --- a/primitives/runtime-interface/test-wasm/build.rs +++ b/primitives/runtime-interface/test-wasm/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/test-wasm/src/lib.rs b/primitives/runtime-interface/test-wasm/src/lib.rs index 72acdd4ff8d6e..982febb7b4fb8 100644 --- a/primitives/runtime-interface/test-wasm/src/lib.rs +++ b/primitives/runtime-interface/test-wasm/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/test/src/lib.rs b/primitives/runtime-interface/test/src/lib.rs index bf82f3b4b52e4..785215b87421b 100644 --- a/primitives/runtime-interface/test/src/lib.rs +++ b/primitives/runtime-interface/test/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/tests/ui.rs b/primitives/runtime-interface/tests/ui.rs index 5a6025f463af0..9e3af145dc566 100644 --- a/primitives/runtime-interface/tests/ui.rs +++ b/primitives/runtime-interface/tests/ui.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/curve.rs b/primitives/runtime/src/curve.rs index d6bd94c2bff70..b5532c3d8cef7 100644 --- a/primitives/runtime/src/curve.rs +++ b/primitives/runtime/src/curve.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/block.rs b/primitives/runtime/src/generic/block.rs index 68959cc514d94..2cd350b2c5ba1 100644 --- a/primitives/runtime/src/generic/block.rs +++ b/primitives/runtime/src/generic/block.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/checked_extrinsic.rs b/primitives/runtime/src/generic/checked_extrinsic.rs index f65e4ead089fe..5d6c657a68977 100644 --- a/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/primitives/runtime/src/generic/checked_extrinsic.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/digest.rs b/primitives/runtime/src/generic/digest.rs index 978653efb93d8..ca1daabb06d29 100644 --- a/primitives/runtime/src/generic/digest.rs +++ b/primitives/runtime/src/generic/digest.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/era.rs b/primitives/runtime/src/generic/era.rs index 9d831b679c5e4..2ca50b12b2e1f 100644 --- a/primitives/runtime/src/generic/era.rs +++ b/primitives/runtime/src/generic/era.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/header.rs b/primitives/runtime/src/generic/header.rs index 21c2a6eef73af..3e1a673d257a1 100644 --- a/primitives/runtime/src/generic/header.rs +++ b/primitives/runtime/src/generic/header.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/mod.rs b/primitives/runtime/src/generic/mod.rs index 3d8e8a0ce7faa..049b0e1624e7e 100644 --- a/primitives/runtime/src/generic/mod.rs +++ b/primitives/runtime/src/generic/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/tests.rs b/primitives/runtime/src/generic/tests.rs index a65e212bf07ec..d0536a5673125 100644 --- a/primitives/runtime/src/generic/tests.rs +++ b/primitives/runtime/src/generic/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/unchecked_extrinsic.rs b/primitives/runtime/src/generic/unchecked_extrinsic.rs index 53e7c349f2a76..d919a67095d3a 100644 --- a/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 7fdc5dda5c74b..cb9ba9ff297fb 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/multiaddress.rs b/primitives/runtime/src/multiaddress.rs index 629099d85d726..b2d46fb106cbc 100644 --- a/primitives/runtime/src/multiaddress.rs +++ b/primitives/runtime/src/multiaddress.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/offchain/http.rs b/primitives/runtime/src/offchain/http.rs index a8c82e616a476..c479062de5f11 100644 --- a/primitives/runtime/src/offchain/http.rs +++ b/primitives/runtime/src/offchain/http.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/offchain/mod.rs b/primitives/runtime/src/offchain/mod.rs index c9d1eda0f8738..bbff693dea038 100644 --- a/primitives/runtime/src/offchain/mod.rs +++ b/primitives/runtime/src/offchain/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/offchain/storage.rs b/primitives/runtime/src/offchain/storage.rs index 3bc5b10f161f7..38ad268e58945 100644 --- a/primitives/runtime/src/offchain/storage.rs +++ b/primitives/runtime/src/offchain/storage.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/offchain/storage_lock.rs b/primitives/runtime/src/offchain/storage_lock.rs index b4833bf345fc0..90f8df7945578 100644 --- a/primitives/runtime/src/offchain/storage_lock.rs +++ b/primitives/runtime/src/offchain/storage_lock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/runtime_logger.rs b/primitives/runtime/src/runtime_logger.rs index ff0e531ed814f..8b5a15762e1f3 100644 --- a/primitives/runtime/src/runtime_logger.rs +++ b/primitives/runtime/src/runtime_logger.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/runtime_string.rs b/primitives/runtime/src/runtime_string.rs index a69e85418d82a..fcbdd2e787ff3 100644 --- a/primitives/runtime/src/runtime_string.rs +++ b/primitives/runtime/src/runtime_string.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index 46e7ee634c25d..003fa62c9e088 100644 --- a/primitives/runtime/src/testing.rs +++ b/primitives/runtime/src/testing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index cc83f66ea4630..84c35597b4b1b 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/transaction_validity.rs b/primitives/runtime/src/transaction_validity.rs index cf5d925975996..29c8b542319b1 100644 --- a/primitives/runtime/src/transaction_validity.rs +++ b/primitives/runtime/src/transaction_validity.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/sandbox/src/embedded_executor.rs b/primitives/sandbox/src/embedded_executor.rs index c521ff2cb63fb..43967a0a38987 100755 --- a/primitives/sandbox/src/embedded_executor.rs +++ b/primitives/sandbox/src/embedded_executor.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/sandbox/src/host_executor.rs b/primitives/sandbox/src/host_executor.rs index 43484dd66a00d..83721f40e3d93 100755 --- a/primitives/sandbox/src/host_executor.rs +++ b/primitives/sandbox/src/host_executor.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/sandbox/src/lib.rs b/primitives/sandbox/src/lib.rs index 79c56e70e2f4b..537c7cbb31b6d 100755 --- a/primitives/sandbox/src/lib.rs +++ b/primitives/sandbox/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/serializer/src/lib.rs b/primitives/serializer/src/lib.rs index ccdbbf27f179b..d1e364a133ba1 100644 --- a/primitives/serializer/src/lib.rs +++ b/primitives/serializer/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/session/src/lib.rs b/primitives/session/src/lib.rs index d85b6af4349e4..1b25d285e3bca 100644 --- a/primitives/session/src/lib.rs +++ b/primitives/session/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index 4bb8ed93f88a1..e7db609e230aa 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/staking/src/offence.rs b/primitives/staking/src/offence.rs index fdff02d42065e..4261063993a52 100644 --- a/primitives/staking/src/offence.rs +++ b/primitives/staking/src/offence.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index 8a6ed4d3dba81..cde5011ce2d8e 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index c0bec8d08f000..1f257550fbf7a 100644 --- a/primitives/state-machine/src/basic.rs +++ b/primitives/state-machine/src/basic.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/error.rs b/primitives/state-machine/src/error.rs index acc5b6080c7a3..a12b3eae71bd7 100644 --- a/primitives/state-machine/src/error.rs +++ b/primitives/state-machine/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index f5158acbc74d1..93e6ac6e5c530 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/in_memory_backend.rs b/primitives/state-machine/src/in_memory_backend.rs index f4ae0d01d5fb9..4605d07b2ab63 100644 --- a/primitives/state-machine/src/in_memory_backend.rs +++ b/primitives/state-machine/src/in_memory_backend.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index dff4999816342..1a69d51d58abf 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/overlayed_changes/changeset.rs b/primitives/state-machine/src/overlayed_changes/changeset.rs index 818b7be99bc6e..9e7f6ffeddfd7 100644 --- a/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index 659b52e0a708f..89bbb063ef9a7 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/overlayed_changes/offchain.rs b/primitives/state-machine/src/overlayed_changes/offchain.rs index ac67ca3303008..98457700013aa 100644 --- a/primitives/state-machine/src/overlayed_changes/offchain.rs +++ b/primitives/state-machine/src/overlayed_changes/offchain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/proving_backend.rs b/primitives/state-machine/src/proving_backend.rs index 4e1fd64da2b8e..934f08492deed 100644 --- a/primitives/state-machine/src/proving_backend.rs +++ b/primitives/state-machine/src/proving_backend.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/read_only.rs b/primitives/state-machine/src/read_only.rs index 2039b39a06038..3c3e779c32f3a 100644 --- a/primitives/state-machine/src/read_only.rs +++ b/primitives/state-machine/src/read_only.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/stats.rs b/primitives/state-machine/src/stats.rs index affd71f9d2e5d..863ea5cfed7ec 100644 --- a/primitives/state-machine/src/stats.rs +++ b/primitives/state-machine/src/stats.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index dbb0a25d3c396..e21644614c83c 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index 616a5512ea40b..37db59416f100 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 945fd05ebffb4..8f3c27f03c748 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/std/src/lib.rs b/primitives/std/src/lib.rs index 3d112a18edd0f..6a59dcbe49299 100644 --- a/primitives/std/src/lib.rs +++ b/primitives/std/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/std/with_std.rs b/primitives/std/with_std.rs index 8a283e8fe333c..b5fa3f85ed702 100644 --- a/primitives/std/with_std.rs +++ b/primitives/std/with_std.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/std/without_std.rs b/primitives/std/without_std.rs index 38c3a8421dacb..7a6d5851dface 100755 --- a/primitives/std/without_std.rs +++ b/primitives/std/without_std.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index eff74c4aac0b2..1e97454b26055 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/tasks/src/async_externalities.rs b/primitives/tasks/src/async_externalities.rs index 9f2fec299f598..70e3437538e8f 100644 --- a/primitives/tasks/src/async_externalities.rs +++ b/primitives/tasks/src/async_externalities.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/primitives/tasks/src/lib.rs b/primitives/tasks/src/lib.rs index c874bb98e1ae6..3711fa71a2fab 100644 --- a/primitives/tasks/src/lib.rs +++ b/primitives/tasks/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/test-primitives/src/lib.rs b/primitives/test-primitives/src/lib.rs index 341839a1deb20..976bb9ddd9cd7 100644 --- a/primitives/test-primitives/src/lib.rs +++ b/primitives/test-primitives/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/timestamp/src/lib.rs b/primitives/timestamp/src/lib.rs index 02a579497b527..9155cbd93b6c5 100644 --- a/primitives/timestamp/src/lib.rs +++ b/primitives/timestamp/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/tracing/src/lib.rs b/primitives/tracing/src/lib.rs index 9522e6df633ac..4cabbbaba6ec9 100644 --- a/primitives/tracing/src/lib.rs +++ b/primitives/tracing/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/tracing/src/types.rs b/primitives/tracing/src/types.rs index 377bd0f42c6eb..d175e1f8f17e8 100644 --- a/primitives/tracing/src/types.rs +++ b/primitives/tracing/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/transaction-pool/src/lib.rs b/primitives/transaction-pool/src/lib.rs index 3c71149255ce0..143958f06d165 100644 --- a/primitives/transaction-pool/src/lib.rs +++ b/primitives/transaction-pool/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/transaction-pool/src/runtime_api.rs b/primitives/transaction-pool/src/runtime_api.rs index be631ee03b9d7..87a0c82e9133e 100644 --- a/primitives/transaction-pool/src/runtime_api.rs +++ b/primitives/transaction-pool/src/runtime_api.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/transaction-storage-proof/src/lib.rs b/primitives/transaction-storage-proof/src/lib.rs index f76ae7faac08b..bdfe16683ebc2 100644 --- a/primitives/transaction-storage-proof/src/lib.rs +++ b/primitives/transaction-storage-proof/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/benches/bench.rs b/primitives/trie/benches/bench.rs index d78ceadff7283..f1670b0c2fa42 100644 --- a/primitives/trie/benches/bench.rs +++ b/primitives/trie/benches/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2015-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2015-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/error.rs b/primitives/trie/src/error.rs index 30a164c614755..b43412ebc7dc4 100644 --- a/primitives/trie/src/error.rs +++ b/primitives/trie/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2015-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2015-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index 399484143dbc4..ffaee2037d1c9 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2015-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2015-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/node_codec.rs b/primitives/trie/src/node_codec.rs index 53a5de270a79a..4aaed2ec7e4ee 100644 --- a/primitives/trie/src/node_codec.rs +++ b/primitives/trie/src/node_codec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2015-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2015-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/node_header.rs b/primitives/trie/src/node_header.rs index 895713ffd1f8d..c2c9510c5ac43 100644 --- a/primitives/trie/src/node_header.rs +++ b/primitives/trie/src/node_header.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2015-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2015-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/storage_proof.rs b/primitives/trie/src/storage_proof.rs index cd65fa5b26f2f..8caae06d390ce 100644 --- a/primitives/trie/src/storage_proof.rs +++ b/primitives/trie/src/storage_proof.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/trie_codec.rs b/primitives/trie/src/trie_codec.rs index f485ee13e3329..62edc82e4c547 100644 --- a/primitives/trie/src/trie_codec.rs +++ b/primitives/trie/src/trie_codec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/trie_stream.rs b/primitives/trie/src/trie_stream.rs index 20f607c840d32..7a5c7d003e034 100644 --- a/primitives/trie/src/trie_stream.rs +++ b/primitives/trie/src/trie_stream.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2015-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2015-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/version/proc-macro/src/decl_runtime_version.rs b/primitives/version/proc-macro/src/decl_runtime_version.rs index 7fcb716bbf607..9ca1a67cc7fd6 100644 --- a/primitives/version/proc-macro/src/decl_runtime_version.rs +++ b/primitives/version/proc-macro/src/decl_runtime_version.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/version/proc-macro/src/lib.rs b/primitives/version/proc-macro/src/lib.rs index 9a6d4d60bbf9f..8be18b15868f9 100644 --- a/primitives/version/proc-macro/src/lib.rs +++ b/primitives/version/proc-macro/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/version/src/embed.rs b/primitives/version/src/embed.rs index 452762dcf687a..e6b468e2e58cc 100644 --- a/primitives/version/src/embed.rs +++ b/primitives/version/src/embed.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/version/src/lib.rs b/primitives/version/src/lib.rs index 74251aa4320fb..46f8af9e22c58 100644 --- a/primitives/version/src/lib.rs +++ b/primitives/version/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/wasm-interface/src/lib.rs b/primitives/wasm-interface/src/lib.rs index 44afaf82ed4cd..21dbf9609ecf3 100644 --- a/primitives/wasm-interface/src/lib.rs +++ b/primitives/wasm-interface/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/wasm-interface/src/wasmi_impl.rs b/primitives/wasm-interface/src/wasmi_impl.rs index f7e0ec6f16d4a..39afce4df4eb2 100644 --- a/primitives/wasm-interface/src/wasmi_impl.rs +++ b/primitives/wasm-interface/src/wasmi_impl.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/client/src/client_ext.rs b/test-utils/client/src/client_ext.rs index 72828fdcc9188..f2b99a5b355f0 100644 --- a/test-utils/client/src/client_ext.rs +++ b/test-utils/client/src/client_ext.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 6ba28d8c124f2..2779656558826 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/derive/src/lib.rs b/test-utils/derive/src/lib.rs index 3f14f67477fad..06b7d2463cbd8 100644 --- a/test-utils/derive/src/lib.rs +++ b/test-utils/derive/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/runtime/build.rs b/test-utils/runtime/build.rs index 50c455b4ad831..5a7b518d0bd75 100644 --- a/test-utils/runtime/build.rs +++ b/test-utils/runtime/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/client/src/block_builder_ext.rs b/test-utils/runtime/client/src/block_builder_ext.rs index 4519dce65960d..66b0b4c3b881b 100644 --- a/test-utils/runtime/client/src/block_builder_ext.rs +++ b/test-utils/runtime/client/src/block_builder_ext.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index d5c8a4fcb8a46..fe0fef3516671 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/client/src/trait_tests.rs b/test-utils/runtime/client/src/trait_tests.rs index 938aeda36d319..65aa3e65e6141 100644 --- a/test-utils/runtime/client/src/trait_tests.rs +++ b/test-utils/runtime/client/src/trait_tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index b81ed91ca6df0..71118b4183ef9 100644 --- a/test-utils/runtime/src/genesismap.rs +++ b/test-utils/runtime/src/genesismap.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index bf224b43946c7..c6112db2374e0 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 57eae0aecf04a..9f8612b69f338 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index e80c24b17144b..d43347bdcb6e6 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index b68994926533a..643985940792e 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/test-crate/src/main.rs b/test-utils/test-crate/src/main.rs index 554adcb884064..4696e71779c12 100644 --- a/test-utils/test-crate/src/main.rs +++ b/test-utils/test-crate/src/main.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/test-runner/src/client.rs b/test-utils/test-runner/src/client.rs index b4a82b1c8950b..3fa3de3a87e05 100644 --- a/test-utils/test-runner/src/client.rs +++ b/test-utils/test-runner/src/client.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/test-runner/src/host_functions.rs b/test-utils/test-runner/src/host_functions.rs index 6d9fa3534b34f..8bc9597890d03 100644 --- a/test-utils/test-runner/src/host_functions.rs +++ b/test-utils/test-runner/src/host_functions.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/test-runner/src/lib.rs b/test-utils/test-runner/src/lib.rs index d5e2873fe412f..19e437e26da45 100644 --- a/test-utils/test-runner/src/lib.rs +++ b/test-utils/test-runner/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/test-runner/src/node.rs b/test-utils/test-runner/src/node.rs index 421a4b641b59d..f122e48d53922 100644 --- a/test-utils/test-runner/src/node.rs +++ b/test-utils/test-runner/src/node.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/test-runner/src/utils.rs b/test-utils/test-runner/src/utils.rs index 4b44d12e1ed4c..452dc600e4ae5 100644 --- a/test-utils/test-runner/src/utils.rs +++ b/test-utils/test-runner/src/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/tests/basic.rs b/test-utils/tests/basic.rs index 527ca3e365edb..4daca836c7fd9 100644 --- a/test-utils/tests/basic.rs +++ b/test-utils/tests/basic.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/tests/ui.rs b/test-utils/tests/ui.rs index 119162fdc21b8..be3b9c111b3e9 100644 --- a/test-utils/tests/ui.rs +++ b/test-utils/tests/ui.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/tests/ui/too-many-func-parameters.rs b/test-utils/tests/ui/too-many-func-parameters.rs index b1789b9d3ee7e..51059f37ab629 100644 --- a/test-utils/tests/ui/too-many-func-parameters.rs +++ b/test-utils/tests/ui/too-many-func-parameters.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/utils/build-script-utils/src/git.rs b/utils/build-script-utils/src/git.rs index 66a15737f84ca..db9a4b291ffdb 100644 --- a/utils/build-script-utils/src/git.rs +++ b/utils/build-script-utils/src/git.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/build-script-utils/src/lib.rs b/utils/build-script-utils/src/lib.rs index 0c45c4b34ebe8..7e69f2ac85d4f 100644 --- a/utils/build-script-utils/src/lib.rs +++ b/utils/build-script-utils/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/build-script-utils/src/version.rs b/utils/build-script-utils/src/version.rs index 52336eb0b6a24..e4f1be93cbccb 100644 --- a/utils/build-script-utils/src/version.rs +++ b/utils/build-script-utils/src/version.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/fork-tree/src/lib.rs b/utils/fork-tree/src/lib.rs index 9143da89a77e0..a718ff26213e4 100644 --- a/utils/fork-tree/src/lib.rs +++ b/utils/fork-tree/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/command.rs b/utils/frame/benchmarking-cli/src/command.rs index 2a0429b279083..94e1e0c8c1b88 100644 --- a/utils/frame/benchmarking-cli/src/command.rs +++ b/utils/frame/benchmarking-cli/src/command.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 316ddfb8d0c10..c331dea34c47b 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/writer.rs b/utils/frame/benchmarking-cli/src/writer.rs index e7e8b42fd8a6d..1e31c4e98e56d 100644 --- a/utils/frame/benchmarking-cli/src/writer.rs +++ b/utils/frame/benchmarking-cli/src/writer.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/frame-utilities-cli/src/lib.rs b/utils/frame/frame-utilities-cli/src/lib.rs index 4f5b1da5766a3..9a18d39263c98 100644 --- a/utils/frame/frame-utilities-cli/src/lib.rs +++ b/utils/frame/frame-utilities-cli/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/frame-utilities-cli/src/pallet_id.rs b/utils/frame/frame-utilities-cli/src/pallet_id.rs index e4acdb2182f03..2e139c639fd43 100644 --- a/utils/frame/frame-utilities-cli/src/pallet_id.rs +++ b/utils/frame/frame-utilities-cli/src/pallet_id.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/generate-bags/node-runtime/src/main.rs b/utils/frame/generate-bags/node-runtime/src/main.rs index 5d36b381a7d0c..72d1f0d8d22b9 100644 --- a/utils/frame/generate-bags/node-runtime/src/main.rs +++ b/utils/frame/generate-bags/node-runtime/src/main.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/generate-bags/src/lib.rs b/utils/frame/generate-bags/src/lib.rs index 29afb9da395a0..d4507c3be33ef 100644 --- a/utils/frame/generate-bags/src/lib.rs +++ b/utils/frame/generate-bags/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 1b61f0711406f..16aa60db1841c 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/remote-externalities/src/rpc_api.rs b/utils/frame/remote-externalities/src/rpc_api.rs index 024cbad3ca551..13254741c1acb 100644 --- a/utils/frame/remote-externalities/src/rpc_api.rs +++ b/utils/frame/remote-externalities/src/rpc_api.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/rpc/support/src/lib.rs b/utils/frame/rpc/support/src/lib.rs index 1b2453c361d97..9cf99ddf97b09 100644 --- a/utils/frame/rpc/support/src/lib.rs +++ b/utils/frame/rpc/support/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/rpc/system/src/lib.rs b/utils/frame/rpc/system/src/lib.rs index 41a5f3ba0eb3e..df24e208b51a4 100644 --- a/utils/frame/rpc/system/src/lib.rs +++ b/utils/frame/rpc/system/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index f092f6eaf4716..68c33b17b99de 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index dbc1c3005f06a..445756f9eed99 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/mod.rs b/utils/frame/try-runtime/cli/src/commands/mod.rs index bfd8290fb31c1..4861d94f077ce 100644 --- a/utils/frame/try-runtime/cli/src/commands/mod.rs +++ b/utils/frame/try-runtime/cli/src/commands/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index 8839c5556900e..47af85560398e 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 3b5a3db72a8f1..30e638217448f 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 9f8af6906a351..2cd0a18909c19 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/parse.rs b/utils/frame/try-runtime/cli/src/parse.rs index 7f205fbacd310..a12e37344c7a3 100644 --- a/utils/frame/try-runtime/cli/src/parse.rs +++ b/utils/frame/try-runtime/cli/src/parse.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/prometheus/src/lib.rs b/utils/prometheus/src/lib.rs index f81b82cb17646..f1d87ac9f729c 100644 --- a/utils/prometheus/src/lib.rs +++ b/utils/prometheus/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/prometheus/src/networking.rs b/utils/prometheus/src/networking.rs index a24216bd23629..fda20b75740bf 100644 --- a/utils/prometheus/src/networking.rs +++ b/utils/prometheus/src/networking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/prometheus/src/sourced.rs b/utils/prometheus/src/sourced.rs index ca37eef021f68..9f52d1eff47cd 100644 --- a/utils/prometheus/src/sourced.rs +++ b/utils/prometheus/src/sourced.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/wasm-builder/src/builder.rs b/utils/wasm-builder/src/builder.rs index 113b5eb068da4..81a8693968188 100644 --- a/utils/wasm-builder/src/builder.rs +++ b/utils/wasm-builder/src/builder.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/wasm-builder/src/lib.rs b/utils/wasm-builder/src/lib.rs index b13ecc4e4ab34..899903d96d169 100644 --- a/utils/wasm-builder/src/lib.rs +++ b/utils/wasm-builder/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/wasm-builder/src/prerequisites.rs b/utils/wasm-builder/src/prerequisites.rs index 88b1073a2951f..fb04dc3c98fb2 100644 --- a/utils/wasm-builder/src/prerequisites.rs +++ b/utils/wasm-builder/src/prerequisites.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 59214ab483c62..cf437ee7f0e6c 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); From 7b9e14234314b65432459c25da1de1cd11852c71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jan 2022 08:46:53 +0000 Subject: [PATCH 0390/1472] Bump sha2 from 0.9.8 to 0.10.0 (#10547) Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.9.8 to 0.10.0. - [Release notes](https://github.com/RustCrypto/hashes/releases) - [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.9.8...sha2-v0.10.0) --- updated-dependencies: - dependency-name: sha2 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 ++++++++++++++++++++++++++++-- primitives/core/Cargo.toml | 2 +- primitives/core/hashing/Cargo.toml | 2 +- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e58275738c929..0f78fef7e5d64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -694,6 +694,15 @@ dependencies = [ "generic-array 0.14.4", ] +[[package]] +name = "block-buffer" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" +dependencies = [ + "generic-array 0.14.4", +] + [[package]] name = "block-padding" version = "0.1.5" @@ -1322,6 +1331,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" +dependencies = [ + "generic-array 0.14.4", +] + [[package]] name = "crypto-mac" version = "0.8.0" @@ -1533,6 +1551,17 @@ dependencies = [ "generic-array 0.14.4", ] +[[package]] +name = "digest" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" +dependencies = [ + "block-buffer 0.10.0", + "crypto-common", + "generic-array 0.14.4", +] + [[package]] name = "directories" version = "4.0.1" @@ -8990,6 +9019,17 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha2" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900d964dd36bb15bcf2f2b35694c072feab74969a54f2bbeec7a2d725d2bdcb6" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures 0.2.1", + "digest 0.10.1", +] + [[package]] name = "sha3" version = "0.9.1" @@ -9426,7 +9466,7 @@ dependencies = [ "secrecy", "serde", "serde_json", - "sha2 0.9.8", + "sha2 0.10.0", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-debug-derive", @@ -9451,7 +9491,7 @@ version = "4.0.0" dependencies = [ "blake2-rfc", "byteorder", - "sha2 0.9.8", + "sha2 0.10.0", "sp-std", "tiny-keccak", "twox-hash", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 05fc1240e2742..c1ca9f081570e 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -62,7 +62,7 @@ schnorrkel = { version = "0.9.1", features = [ "preaudit_deprecated", "u64_backend", ], default-features = false, optional = true } -sha2 = { version = "0.9.8", default-features = false, optional = true } +sha2 = { version = "0.10.0", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } twox-hash = { version = "1.6.1", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", "static-context"], optional = true } diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index 23ff01c0b34b8..e9f3c8c714f71 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -18,7 +18,7 @@ byteorder = { version = "1.3.2", default-features = false } blake2-rfc = { version = "0.2.18", default-features = false } tiny-keccak = { version = "2.0.1", features = ["keccak"] } -sha2 = { version = "0.9.2", default-features = false } +sha2 = { version = "0.10.0", default-features = false } twox-hash = { version = "1.5.0", default-features = false } [features] From a798e290628030d9fcba9293994f3d66beba44af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 3 Jan 2022 16:08:42 +0100 Subject: [PATCH 0391/1472] Remove transaction-pool `test-helpers` feature (#10571) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove transaction-pool `test-helpers` feature `test-helpers` feature is a bad idea in general, because once the feature is enabled somewhere in the workspace, it is enabled anywhere. While removing the feature, the tests were also rewritten to get rid off other "only test" related code. Contributes towards: https://github.com/paritytech/substrate/issues/9727 * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Fix benches Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- Cargo.lock | 56 ++---- client/transaction-pool/Cargo.toml | 5 +- client/transaction-pool/benches/basics.rs | 12 +- client/transaction-pool/src/graph/pool.rs | 171 ++-------------- .../src/graph/validated_pool.rs | 6 - client/transaction-pool/src/lib.rs | 25 +-- client/transaction-pool/src/revalidation.rs | 98 +++++----- client/transaction-pool/src/tests.rs | 185 ++++++++++++++++++ client/transaction-pool/tests/pool.rs | 156 +++++++-------- client/transaction-pool/tests/revalidation.rs | 32 --- .../runtime/transaction-pool/Cargo.toml | 2 +- .../runtime/transaction-pool/src/lib.rs | 17 +- 12 files changed, 364 insertions(+), 401 deletions(-) create mode 100644 client/transaction-pool/src/tests.rs delete mode 100644 client/transaction-pool/tests/revalidation.rs diff --git a/Cargo.lock b/Cargo.lock index 0f78fef7e5d64..ba80103c174ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1898,7 +1898,7 @@ checksum = "e8ac3ff5224ef91f3c97e03eb1de2db82743427e91aaa5ac635f454f0b164f5a" dependencies = [ "either", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "log 0.4.14", "num-traits", "parity-scale-codec", @@ -2391,12 +2391,6 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" -[[package]] -name = "futures-timer" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6" - [[package]] name = "futures-timer" version = "3.0.2" @@ -2974,16 +2968,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "intervalier" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64fa110ec7b8f493f416eed552740d10e7030ad5f63b2308f82c9608ec2df275" -dependencies = [ - "futures 0.3.16", - "futures-timer 2.0.2", -] - [[package]] name = "io-lifetimes" version = "0.3.1" @@ -3481,7 +3465,7 @@ dependencies = [ "either", "fnv", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "lazy_static", "libsecp256k1", "log 0.4.14", @@ -3745,7 +3729,7 @@ dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3834,7 +3818,7 @@ checksum = "7399c5b6361ef525d41c11fcf51635724f832baf5819b30d3d873eabb4fbae4b" dependencies = [ "async-io", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "if-watch", "ipnet", "libc", @@ -7625,7 +7609,7 @@ dependencies = [ "async-trait", "derive_more", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "ip_network", "libp2p", "log 0.4.14", @@ -7652,7 +7636,7 @@ name = "sc-basic-authorship" version = "0.10.0-dev" dependencies = [ "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "log 0.4.14", "parity-scale-codec", "parking_lot 0.11.2", @@ -7816,7 +7800,7 @@ version = "0.10.0-dev" dependencies = [ "async-trait", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "libp2p", "log 0.4.14", "parking_lot 0.11.2", @@ -8007,7 +7991,7 @@ dependencies = [ "async-trait", "derive_more", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "log 0.4.14", "parity-scale-codec", "parking_lot 0.11.2", @@ -8030,7 +8014,7 @@ version = "0.10.0-dev" dependencies = [ "async-trait", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "log 0.4.14", "parity-scale-codec", "sc-client-api", @@ -8163,7 +8147,7 @@ dependencies = [ "finality-grandpa", "fork-tree", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "log 0.4.14", "parity-scale-codec", "parking_lot 0.11.2", @@ -8228,7 +8212,7 @@ version = "0.10.0-dev" dependencies = [ "ansi_term", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "log 0.4.14", "parity-util-mem", "sc-client-api", @@ -8269,7 +8253,7 @@ dependencies = [ "fnv", "fork-tree", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "hex", "ip_network", "libp2p", @@ -8316,7 +8300,7 @@ version = "0.10.0-dev" dependencies = [ "async-std", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "libp2p", "log 0.4.14", "lru 0.7.0", @@ -8335,7 +8319,7 @@ dependencies = [ "async-std", "async-trait", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "libp2p", "log 0.4.14", "parking_lot 0.11.2", @@ -8362,7 +8346,7 @@ dependencies = [ "bytes 1.1.0", "fnv", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "hex", "hyper 0.14.16", "hyper-rustls", @@ -8512,7 +8496,7 @@ dependencies = [ "directories", "exit-future", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "hash-db", "jsonrpc-core", "jsonrpc-pubsub", @@ -8704,8 +8688,8 @@ dependencies = [ "assert_matches", "criterion", "futures 0.3.16", + "futures-timer", "hex", - "intervalier", "linked-hash-map", "log 0.4.14", "parity-scale-codec", @@ -8749,7 +8733,7 @@ name = "sc-utils" version = "4.0.0-dev" dependencies = [ "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "lazy_static", "prometheus", ] @@ -9348,7 +9332,7 @@ version = "0.10.0-dev" dependencies = [ "async-trait", "futures 0.3.16", - "futures-timer 3.0.2", + "futures-timer", "log 0.4.14", "parity-scale-codec", "sp-core", @@ -9910,7 +9894,7 @@ name = "sp-timestamp" version = "4.0.0-dev" dependencies = [ "async-trait", - "futures-timer 3.0.2", + "futures-timer", "log 0.4.14", "parity-scale-codec", "sp-api", diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 43a368145a93f..a98dfac620c19 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0" } thiserror = "1.0.30" futures = "0.3.16" -intervalier = "0.4.0" +futures-timer = "3.0.2" log = "0.4.8" parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } parking_lot = "0.11.2" @@ -48,6 +48,3 @@ criterion = "0.3" [[bench]] name = "basics" harness = false - -[features] -test-helpers = [] diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index c6b15ce4f1777..c3577a45faf07 100644 --- a/client/transaction-pool/benches/basics.rs +++ b/client/transaction-pool/benches/basics.rs @@ -23,11 +23,11 @@ use futures::{ executor::block_on, future::{ready, Ready}, }; -use sc_transaction_pool::{test_helpers::*, *}; +use sc_transaction_pool::*; use sp_core::blake2_256; use sp_runtime::{ generic::BlockId, - traits::Block as BlockT, + traits::{Block as BlockT, NumberFor}, transaction_validity::{ InvalidTransaction, TransactionSource, TransactionTag as Tag, TransactionValidity, ValidTransaction, @@ -63,7 +63,7 @@ impl ChainApi for TestApi { &self, at: &BlockId, _source: TransactionSource, - uxt: test_helpers::ExtrinsicFor, + uxt: ::Extrinsic, ) -> Self::ValidationFuture { let nonce = uxt.transfer().nonce; let from = uxt.transfer().from.clone(); @@ -89,7 +89,7 @@ impl ChainApi for TestApi { fn block_id_to_number( &self, at: &BlockId, - ) -> Result>, Self::Error> { + ) -> Result>, Self::Error> { Ok(match at { BlockId::Number(num) => Some(*num), BlockId::Hash(_) => None, @@ -99,14 +99,14 @@ impl ChainApi for TestApi { fn block_id_to_hash( &self, at: &BlockId, - ) -> Result>, Self::Error> { + ) -> Result::Hash>, Self::Error> { Ok(match at { BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(), BlockId::Hash(_) => None, }) } - fn hash_and_length(&self, uxt: &test_helpers::ExtrinsicFor) -> (H256, usize) { + fn hash_and_length(&self, uxt: &::Extrinsic) -> (H256, usize) { let encoded = uxt.encode(); (blake2_256(&encoded).into(), encoded.len()) } diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 3d0f8a017a971..909ea559f5527 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -444,163 +444,16 @@ impl Clone for Pool { #[cfg(test)] mod tests { use super::{super::base_pool::Limit, *}; + use crate::tests::{pool, uxt, TestApi, INVALID_NONCE}; use assert_matches::assert_matches; - use codec::Encode; use futures::executor::block_on; use parking_lot::Mutex; use sc_transaction_pool_api::TransactionStatus; - use sp_runtime::{ - traits::Hash, - transaction_validity::{InvalidTransaction, TransactionSource, ValidTransaction}, - }; - use std::{ - collections::{HashMap, HashSet}, - time::Instant, - }; - use substrate_test_runtime::{AccountId, Block, Extrinsic, Hashing, Transfer, H256}; - - const INVALID_NONCE: u64 = 254; - const SOURCE: TransactionSource = TransactionSource::External; - - #[derive(Clone, Debug, Default)] - struct TestApi { - delay: Arc>>>, - invalidate: Arc>>, - clear_requirements: Arc>>, - add_requirements: Arc>>, - } - - impl ChainApi for TestApi { - type Block = Block; - type Error = error::Error; - type ValidationFuture = futures::future::Ready>; - type BodyFuture = futures::future::Ready>>>; - - /// Verify extrinsic at given block. - fn validate_transaction( - &self, - at: &BlockId, - _source: TransactionSource, - uxt: ExtrinsicFor, - ) -> Self::ValidationFuture { - let hash = self.hash_and_length(&uxt).0; - let block_number = self.block_id_to_number(at).unwrap().unwrap(); - - let res = match uxt { - Extrinsic::Transfer { transfer, .. } => { - let nonce = transfer.nonce; - - // This is used to control the test flow. - if nonce > 0 { - let opt = self.delay.lock().take(); - if let Some(delay) = opt { - if delay.recv().is_err() { - println!("Error waiting for delay!"); - } - } - } - - if self.invalidate.lock().contains(&hash) { - InvalidTransaction::Custom(0).into() - } else if nonce < block_number { - InvalidTransaction::Stale.into() - } else { - let mut transaction = ValidTransaction { - priority: 4, - requires: if nonce > block_number { - vec![vec![nonce as u8 - 1]] - } else { - vec![] - }, - provides: if nonce == INVALID_NONCE { - vec![] - } else { - vec![vec![nonce as u8]] - }, - longevity: 3, - propagate: true, - }; - - if self.clear_requirements.lock().contains(&hash) { - transaction.requires.clear(); - } - - if self.add_requirements.lock().contains(&hash) { - transaction.requires.push(vec![128]); - } - - Ok(transaction) - } - }, - Extrinsic::IncludeData(_) => Ok(ValidTransaction { - priority: 9001, - requires: vec![], - provides: vec![vec![42]], - longevity: 9001, - propagate: false, - }), - Extrinsic::Store(_) => Ok(ValidTransaction { - priority: 9001, - requires: vec![], - provides: vec![vec![43]], - longevity: 9001, - propagate: false, - }), - _ => unimplemented!(), - }; - - futures::future::ready(Ok(res)) - } - - /// Returns a block number given the block id. - fn block_id_to_number( - &self, - at: &BlockId, - ) -> Result>, Self::Error> { - Ok(match at { - BlockId::Number(num) => Some(*num), - BlockId::Hash(_) => None, - }) - } + use sp_runtime::transaction_validity::TransactionSource; + use std::{collections::HashMap, time::Instant}; + use substrate_test_runtime::{AccountId, Extrinsic, Transfer, H256}; - /// Returns a block hash given the block id. - fn block_id_to_hash( - &self, - at: &BlockId, - ) -> Result::Hash>, Self::Error> { - Ok(match at { - BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(), - BlockId::Hash(_) => None, - }) - } - - /// Hash the extrinsic. - fn hash_and_length(&self, uxt: &ExtrinsicFor) -> (BlockHash, usize) { - let encoded = uxt.encode(); - let len = encoded.len(); - (Hashing::hash(&encoded), len) - } - - fn block_body(&self, _id: &BlockId) -> Self::BodyFuture { - futures::future::ready(Ok(None)) - } - - fn block_header( - &self, - _: &BlockId, - ) -> Result::Header>, Self::Error> { - Ok(None) - } - } - - fn uxt(transfer: Transfer) -> Extrinsic { - let signature = TryFrom::try_from(&[0; 64][..]).unwrap(); - Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: false } - } - - fn pool() -> Pool { - Pool::new(Default::default(), true.into(), TestApi::default().into()) - } + const SOURCE: TransactionSource = TransactionSource::External; #[test] fn should_validate_and_import_transaction() { @@ -636,7 +489,7 @@ mod tests { }); // when - pool.validated_pool.rotator().ban(&Instant::now(), vec![pool.hash_of(&uxt)]); + pool.validated_pool.ban(&Instant::now(), vec![pool.hash_of(&uxt)]); let res = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt)); assert_eq!(pool.validated_pool().status().ready, 0); assert_eq!(pool.validated_pool().status().future, 0); @@ -767,9 +620,9 @@ mod tests { assert_eq!(pool.validated_pool().status().future, 0); assert_eq!(pool.validated_pool().status().ready, 0); // make sure they are temporarily banned as well - assert!(pool.validated_pool.rotator().is_banned(&hash1)); - assert!(pool.validated_pool.rotator().is_banned(&hash2)); - assert!(pool.validated_pool.rotator().is_banned(&hash3)); + assert!(pool.validated_pool.is_banned(&hash1)); + assert!(pool.validated_pool.is_banned(&hash2)); + assert!(pool.validated_pool.is_banned(&hash3)); } #[test] @@ -792,7 +645,7 @@ mod tests { block_on(pool.prune_tags(&BlockId::Number(1), vec![vec![0]], vec![hash1.clone()])).unwrap(); // then - assert!(pool.validated_pool.rotator().is_banned(&hash1)); + assert!(pool.validated_pool.is_banned(&hash1)); } #[test] @@ -832,8 +685,8 @@ mod tests { // then assert_eq!(pool.validated_pool().status().future, 1); - assert!(pool.validated_pool.rotator().is_banned(&hash1)); - assert!(!pool.validated_pool.rotator().is_banned(&hash2)); + assert!(pool.validated_pool.is_banned(&hash1)); + assert!(!pool.validated_pool.is_banned(&hash2)); } #[test] diff --git a/client/transaction-pool/src/graph/validated_pool.rs b/client/transaction-pool/src/graph/validated_pool.rs index 137c7298f5156..7e19941b25684 100644 --- a/client/transaction-pool/src/graph/validated_pool.rs +++ b/client/transaction-pool/src/graph/validated_pool.rs @@ -569,12 +569,6 @@ impl ValidatedPool { Ok(()) } - /// Get rotator reference. - #[cfg(feature = "test-helpers")] - pub fn rotator(&self) -> &PoolRotator> { - &self.rotator - } - /// Get api reference. pub fn api(&self) -> &B { &self.api diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 065c83be3bfcc..2d07815e4baac 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -23,20 +23,12 @@ #![warn(unused_extern_crates)] mod api; +pub mod error; mod graph; mod metrics; mod revalidation; - -pub mod error; - -/// Common types for testing the transaction pool -#[cfg(feature = "test-helpers")] -pub mod test_helpers { - pub use super::{ - graph::{BlockHash, ChainApi, ExtrinsicFor, NumberFor, Pool}, - revalidation::RevalidationQueue, - }; -} +#[cfg(test)] +mod tests; pub use crate::api::FullChainApi; use futures::{ @@ -170,13 +162,10 @@ where PoolApi: graph::ChainApi + 'static, { /// Create new basic transaction pool with provided api, for tests. - #[cfg(feature = "test-helpers")] - pub fn new_test( - pool_api: Arc, - ) -> (Self, Pin + Send>>, intervalier::BackSignalControl) { + pub fn new_test(pool_api: Arc) -> (Self, Pin + Send>>) { let pool = Arc::new(graph::Pool::new(Default::default(), true.into(), pool_api.clone())); - let (revalidation_queue, background_task, notifier) = - revalidation::RevalidationQueue::new_test(pool_api.clone(), pool.clone()); + let (revalidation_queue, background_task) = + revalidation::RevalidationQueue::new_background(pool_api.clone(), pool.clone()); ( Self { api: pool_api, @@ -187,7 +176,6 @@ where metrics: Default::default(), }, background_task, - notifier, ) } @@ -237,7 +225,6 @@ where } /// Get access to the underlying api - #[cfg(feature = "test-helpers")] pub fn api(&self) -> &PoolApi { &self.api } diff --git a/client/transaction-pool/src/revalidation.rs b/client/transaction-pool/src/revalidation.rs index 6b6ed858e7ec6..22b526e9dfc6d 100644 --- a/client/transaction-pool/src/revalidation.rs +++ b/client/transaction-pool/src/revalidation.rs @@ -35,10 +35,7 @@ use sp_runtime::{ use futures::prelude::*; use std::time::Duration; -#[cfg(not(feature = "test-helpers"))] const BACKGROUND_REVALIDATION_INTERVAL: Duration = Duration::from_millis(200); -#[cfg(feature = "test-helpers")] -pub const BACKGROUND_REVALIDATION_INTERVAL: Duration = Duration::from_millis(1); const MIN_BACKGROUND_REVALIDATION_BATCH_SIZE: usize = 20; @@ -213,36 +210,25 @@ impl RevalidationWorker { /// It does two things: periodically tries to process some transactions /// from the queue and also accepts messages to enqueue some more /// transactions from the pool. - pub async fn run( + pub async fn run( mut self, from_queue: TracingUnboundedReceiver>, - interval: R, - ) where - R: Send, - R::Guard: Send, - { - let interval = interval.into_stream().fuse(); + interval: Duration, + ) { + let interval_fut = futures_timer::Delay::new(interval); let from_queue = from_queue.fuse(); - futures::pin_mut!(interval, from_queue); + futures::pin_mut!(interval_fut, from_queue); let this = &mut self; loop { futures::select! { - _guard = interval.next() => { + // Using `fuse()` in here is okay, because we reset the interval when it has fired. + _ = (&mut interval_fut).fuse() => { let next_batch = this.prepare_batch(); let batch_len = next_batch.len(); batch_revalidate(this.pool.clone(), this.api.clone(), this.best_block, next_batch).await; - #[cfg(feature = "test-helpers")] - { - use intervalier::Guard; - // only trigger test events if something was processed - if batch_len == 0 { - _guard.expect("Always some() in tests").skip(); - } - } - if batch_len > 0 || this.len() > 0 { log::debug!( target: "txpool", @@ -251,6 +237,8 @@ impl RevalidationWorker { this.len(), ); } + + interval_fut.reset(interval); }, workload = from_queue.next() => { match workload { @@ -298,15 +286,11 @@ where } /// New revalidation queue with background worker. - pub fn new_with_interval( + pub fn new_with_interval( api: Arc, pool: Arc>, - interval: R, - ) -> (Self, Pin + Send>>) - where - R: Send + 'static, - R::Guard: Send, - { + interval: Duration, + ) -> (Self, Pin + Send>>) { let (to_worker, from_queue) = tracing_unbounded("mpsc_revalidation_queue"); let worker = RevalidationWorker::new(api.clone(), pool.clone()); @@ -321,24 +305,7 @@ where api: Arc, pool: Arc>, ) -> (Self, Pin + Send>>) { - Self::new_with_interval( - api, - pool, - intervalier::Interval::new(BACKGROUND_REVALIDATION_INTERVAL), - ) - } - - /// New revalidation queue with background worker and test signal. - #[cfg(feature = "test-helpers")] - pub fn new_test( - api: Arc, - pool: Arc>, - ) -> (Self, Pin + Send>>, intervalier::BackSignalControl) { - let (interval, notifier) = - intervalier::BackSignalInterval::new(BACKGROUND_REVALIDATION_INTERVAL); - let (queue, background) = Self::new_with_interval(api, pool, interval); - - (queue, background, notifier) + Self::new_with_interval(api, pool, BACKGROUND_REVALIDATION_INTERVAL) } /// Queue some transaction for later revalidation. @@ -371,4 +338,41 @@ where } #[cfg(test)] -mod tests {} +mod tests { + use super::*; + use crate::{ + graph::Pool, + tests::{uxt, TestApi}, + }; + use futures::executor::block_on; + use sc_transaction_pool_api::TransactionSource; + use sp_runtime::generic::BlockId; + use substrate_test_runtime::{AccountId, Transfer, H256}; + + #[test] + fn revalidation_queue_works() { + let api = Arc::new(TestApi::default()); + let pool = Arc::new(Pool::new(Default::default(), true.into(), api.clone())); + let queue = Arc::new(RevalidationQueue::new(api.clone(), pool.clone())); + + let uxt = uxt(Transfer { + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }); + let uxt_hash = block_on(pool.submit_one( + &BlockId::number(0), + TransactionSource::External, + uxt.clone(), + )) + .expect("Should be valid"); + + block_on(queue.revalidate_later(0, vec![uxt_hash])); + + // revalidated in sync offload 2nd time + assert_eq!(api.validation_requests().len(), 2); + // number of ready + assert_eq!(pool.validated_pool().status().ready, 1); + } +} diff --git a/client/transaction-pool/src/tests.rs b/client/transaction-pool/src/tests.rs new file mode 100644 index 0000000000000..79142e16a1b36 --- /dev/null +++ b/client/transaction-pool/src/tests.rs @@ -0,0 +1,185 @@ +// This file is part of Substrate. + +// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Testing related primitives for internal usage in this crate. + +use crate::graph::{BlockHash, ChainApi, ExtrinsicFor, NumberFor, Pool}; +use codec::Encode; +use parking_lot::Mutex; +use sc_transaction_pool_api::error; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Hash}, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, ValidTransaction, + }, +}; +use std::{collections::HashSet, sync::Arc}; +use substrate_test_runtime::{Block, Extrinsic, Hashing, Transfer, H256}; + +pub(crate) const INVALID_NONCE: u64 = 254; + +/// Test api that implements [`ChainApi`]. +#[derive(Clone, Debug, Default)] +pub(crate) struct TestApi { + pub delay: Arc>>>, + pub invalidate: Arc>>, + pub clear_requirements: Arc>>, + pub add_requirements: Arc>>, + pub validation_requests: Arc>>, +} + +impl TestApi { + /// Query validation requests received. + pub fn validation_requests(&self) -> Vec { + self.validation_requests.lock().clone() + } +} + +impl ChainApi for TestApi { + type Block = Block; + type Error = error::Error; + type ValidationFuture = futures::future::Ready>; + type BodyFuture = futures::future::Ready>>>; + + /// Verify extrinsic at given block. + fn validate_transaction( + &self, + at: &BlockId, + _source: TransactionSource, + uxt: ExtrinsicFor, + ) -> Self::ValidationFuture { + self.validation_requests.lock().push(uxt.clone()); + let hash = self.hash_and_length(&uxt).0; + let block_number = self.block_id_to_number(at).unwrap().unwrap(); + + let res = match uxt { + Extrinsic::Transfer { transfer, .. } => { + let nonce = transfer.nonce; + + // This is used to control the test flow. + if nonce > 0 { + let opt = self.delay.lock().take(); + if let Some(delay) = opt { + if delay.recv().is_err() { + println!("Error waiting for delay!"); + } + } + } + + if self.invalidate.lock().contains(&hash) { + InvalidTransaction::Custom(0).into() + } else if nonce < block_number { + InvalidTransaction::Stale.into() + } else { + let mut transaction = ValidTransaction { + priority: 4, + requires: if nonce > block_number { + vec![vec![nonce as u8 - 1]] + } else { + vec![] + }, + provides: if nonce == INVALID_NONCE { + vec![] + } else { + vec![vec![nonce as u8]] + }, + longevity: 3, + propagate: true, + }; + + if self.clear_requirements.lock().contains(&hash) { + transaction.requires.clear(); + } + + if self.add_requirements.lock().contains(&hash) { + transaction.requires.push(vec![128]); + } + + Ok(transaction) + } + }, + Extrinsic::IncludeData(_) => Ok(ValidTransaction { + priority: 9001, + requires: vec![], + provides: vec![vec![42]], + longevity: 9001, + propagate: false, + }), + Extrinsic::Store(_) => Ok(ValidTransaction { + priority: 9001, + requires: vec![], + provides: vec![vec![43]], + longevity: 9001, + propagate: false, + }), + _ => unimplemented!(), + }; + + futures::future::ready(Ok(res)) + } + + /// Returns a block number given the block id. + fn block_id_to_number( + &self, + at: &BlockId, + ) -> Result>, Self::Error> { + Ok(match at { + BlockId::Number(num) => Some(*num), + BlockId::Hash(_) => None, + }) + } + + /// Returns a block hash given the block id. + fn block_id_to_hash( + &self, + at: &BlockId, + ) -> Result::Hash>, Self::Error> { + Ok(match at { + BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(), + BlockId::Hash(_) => None, + }) + } + + /// Hash the extrinsic. + fn hash_and_length(&self, uxt: &ExtrinsicFor) -> (BlockHash, usize) { + let encoded = uxt.encode(); + let len = encoded.len(); + (Hashing::hash(&encoded), len) + } + + fn block_body(&self, _id: &BlockId) -> Self::BodyFuture { + futures::future::ready(Ok(None)) + } + + fn block_header( + &self, + _: &BlockId, + ) -> Result::Header>, Self::Error> { + Ok(None) + } +} + +pub(crate) fn uxt(transfer: Transfer) -> Extrinsic { + let signature = TryFrom::try_from(&[0; 64][..]).unwrap(); + Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: false } +} + +pub(crate) fn pool() -> Pool { + Pool::new(Default::default(), true.into(), TestApi::default().into()) +} diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 14ccacfb26922..4aeaf79a61540 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -17,6 +17,7 @@ // along with this program. If not, see . //! Tests for top-level transaction pool api + use codec::Encode; use futures::{ executor::{block_on, block_on_stream}, @@ -25,7 +26,7 @@ use futures::{ }; use sc_block_builder::BlockBuilderProvider; use sc_client_api::client::BlockchainEvents; -use sc_transaction_pool::{test_helpers::*, *}; +use sc_transaction_pool::*; use sc_transaction_pool_api::{ ChainEvent, MaintainedTransactionPool, TransactionPool, TransactionStatus, }; @@ -47,14 +48,13 @@ fn pool() -> Pool { Pool::new(Default::default(), true.into(), TestApi::with_alice_nonce(209).into()) } -fn maintained_pool( -) -> (BasicPool, futures::executor::ThreadPool, intervalier::BackSignalControl) { - let (pool, background_task, notifier) = - BasicPool::new_test(Arc::new(TestApi::with_alice_nonce(209))); +fn maintained_pool() -> (BasicPool, Arc, futures::executor::ThreadPool) { + let api = Arc::new(TestApi::with_alice_nonce(209)); + let (pool, background_task) = BasicPool::new_test(api.clone()); let thread_pool = futures::executor::ThreadPool::new().unwrap(); thread_pool.spawn_ok(background_task); - (pool, thread_pool, notifier) + (pool, api, thread_pool) } const SOURCE: TransactionSource = TransactionSource::External; @@ -135,7 +135,7 @@ fn should_ban_invalid_transactions() { #[test] fn only_prune_on_new_best() { - let pool = maintained_pool().0; + let (pool, api, _) = maintained_pool(); let uxt = uxt(Alice, 209); let _ = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, uxt.clone())) @@ -143,7 +143,7 @@ fn only_prune_on_new_best() { pool.api().push_block(1, vec![uxt.clone()], true); assert_eq!(pool.status().ready, 1); - let header = pool.api().push_block(2, vec![uxt], true); + let header = api.push_block(2, vec![uxt], true); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 0); @@ -205,12 +205,12 @@ fn block_event_with_retracted( fn should_prune_old_during_maintenance() { let xt = uxt(Alice, 209); - let (pool, _guard, _notifier) = maintained_pool(); + let (pool, api, _guard) = maintained_pool(); block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported"); assert_eq!(pool.status().ready, 1); - let header = pool.api().push_block(1, vec![xt.clone()], true); + let header = api.push_block(1, vec![xt.clone()], true); block_on(pool.maintain(block_event(header))); assert_eq!(pool.status().ready, 0); @@ -221,33 +221,38 @@ fn should_revalidate_during_maintenance() { let xt1 = uxt(Alice, 209); let xt2 = uxt(Alice, 210); - let (pool, _guard, mut notifier) = maintained_pool(); + let (pool, api, _guard) = maintained_pool(); block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported"); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt2.clone())).expect("2. Imported"); + let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt2.clone())) + .expect("2. Imported"); assert_eq!(pool.status().ready, 2); - assert_eq!(pool.api().validation_requests().len(), 2); + assert_eq!(api.validation_requests().len(), 2); + + let header = api.push_block(1, vec![xt1.clone()], true); - let header = pool.api().push_block(1, vec![xt1.clone()], true); + api.add_invalid(&xt2); block_on(pool.maintain(block_event(header))); assert_eq!(pool.status().ready, 1); - block_on(notifier.next()); // test that pool revalidated transaction that left ready and not included in the block - assert_eq!(pool.api().validation_requests().len(), 3); + assert_eq!( + futures::executor::block_on_stream(watcher).collect::>(), + vec![TransactionStatus::Ready, TransactionStatus::Invalid], + ); } #[test] fn should_resubmit_from_retracted_during_maintenance() { let xt = uxt(Alice, 209); - let (pool, _guard, _notifier) = maintained_pool(); + let (pool, api, _guard) = maintained_pool(); block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported"); assert_eq!(pool.status().ready, 1); - let header = pool.api().push_block(1, vec![], true); - let fork_header = pool.api().push_block(1, vec![], false); + let header = api.push_block(1, vec![], true); + let fork_header = api.push_block(1, vec![], false); let event = block_event_with_retracted(header, fork_header.hash(), &*pool.api()); @@ -259,13 +264,13 @@ fn should_resubmit_from_retracted_during_maintenance() { fn should_not_resubmit_from_retracted_during_maintenance_if_tx_is_also_in_enacted() { let xt = uxt(Alice, 209); - let (pool, _guard, _notifier) = maintained_pool(); + let (pool, api, _guard) = maintained_pool(); block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported"); assert_eq!(pool.status().ready, 1); - let header = pool.api().push_block(1, vec![xt.clone()], true); - let fork_header = pool.api().push_block(1, vec![xt], false); + let header = api.push_block(1, vec![xt.clone()], true); + let fork_header = api.push_block(1, vec![xt], false); let event = block_event_with_retracted(header, fork_header.hash(), &*pool.api()); @@ -277,19 +282,23 @@ fn should_not_resubmit_from_retracted_during_maintenance_if_tx_is_also_in_enacte fn should_not_retain_invalid_hashes_from_retracted() { let xt = uxt(Alice, 209); - let (pool, _guard, mut notifier) = maintained_pool(); + let (pool, api, _guard) = maintained_pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported"); + let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone())) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); - let header = pool.api().push_block(1, vec![], true); - let fork_header = pool.api().push_block(1, vec![xt.clone()], false); - pool.api().add_invalid(&xt); + let header = api.push_block(1, vec![], true); + let fork_header = api.push_block(1, vec![xt.clone()], false); + api.add_invalid(&xt); let event = block_event_with_retracted(header, fork_header.hash(), &*pool.api()); - block_on(pool.maintain(event)); - block_on(notifier.next()); + + assert_eq!( + futures::executor::block_on_stream(watcher).collect::>(), + vec![TransactionStatus::Ready, TransactionStatus::Invalid], + ); assert_eq!(pool.status().ready, 0); } @@ -300,26 +309,30 @@ fn should_revalidate_across_many_blocks() { let xt2 = uxt(Alice, 210); let xt3 = uxt(Alice, 211); - let (pool, _guard, mut notifier) = maintained_pool(); + let (pool, api, _guard) = maintained_pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported"); + let watcher1 = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt1.clone())) + .expect("1. Imported"); block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt2.clone())).expect("1. Imported"); assert_eq!(pool.status().ready, 2); - let header = pool.api().push_block(1, vec![], true); + let header = api.push_block(1, vec![], true); block_on(pool.maintain(block_event(header))); - block_on(notifier.next()); block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt3.clone())).expect("1. Imported"); assert_eq!(pool.status().ready, 3); - let header = pool.api().push_block(2, vec![xt1.clone()], true); - block_on(pool.maintain(block_event(header))); - block_on(notifier.next()); + let header = api.push_block(2, vec![xt1.clone()], true); + let block_hash = header.hash(); + block_on(pool.maintain(block_event(header.clone()))); + + block_on( + watcher1 + .take_while(|s| future::ready(*s != TransactionStatus::InBlock(block_hash))) + .collect::>(), + ); assert_eq!(pool.status().ready, 2); - // xt1 and xt2 validated twice, then xt3 once, then xt2 and xt3 again - assert_eq!(pool.api().validation_requests().len(), 7); } #[test] @@ -329,7 +342,7 @@ fn should_push_watchers_during_maintenance() { } // given - let (pool, _guard, mut notifier) = maintained_pool(); + let (pool, api, _guard) = maintained_pool(); let tx0 = alice_uxt(0); let watcher0 = @@ -349,18 +362,16 @@ fn should_push_watchers_during_maintenance() { assert_eq!(pool.status().ready, 5); // when - pool.api().add_invalid(&tx3); - pool.api().add_invalid(&tx4); + api.add_invalid(&tx3); + api.add_invalid(&tx4); // clear timer events if any - let header = pool.api().push_block(1, vec![], true); + let header = api.push_block(1, vec![], true); block_on(pool.maintain(block_event(header))); - block_on(notifier.next()); // then // hash3 is now invalid // hash4 is now invalid - assert_eq!(pool.status().ready, 3); assert_eq!( futures::executor::block_on_stream(watcher3).collect::>(), vec![TransactionStatus::Ready, TransactionStatus::Invalid], @@ -369,9 +380,10 @@ fn should_push_watchers_during_maintenance() { futures::executor::block_on_stream(watcher4).collect::>(), vec![TransactionStatus::Ready, TransactionStatus::Invalid], ); + assert_eq!(pool.status().ready, 3); // when - let header = pool.api().push_block(2, vec![tx0, tx1, tx2], true); + let header = api.push_block(2, vec![tx0, tx1, tx2], true); let header_hash = header.hash(); block_on(pool.maintain(block_event(header))); @@ -410,7 +422,7 @@ fn should_push_watchers_during_maintenance() { #[test] fn can_track_heap_size() { - let (pool, _guard, _notifier) = maintained_pool(); + let (pool, _api, _guard) = maintained_pool(); block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).expect("1. Imported"); block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).expect("1. Imported"); block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 211))).expect("1. Imported"); @@ -424,7 +436,7 @@ fn finalization() { let xt = uxt(Alice, 209); let api = TestApi::with_alice_nonce(209); api.push_block(1, vec![], true); - let (pool, _background, _) = BasicPool::new_test(api.into()); + let (pool, _background) = BasicPool::new_test(api.into()); let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())) .expect("1. Imported"); pool.api().push_block(2, vec![xt.clone()], true); @@ -449,7 +461,7 @@ fn fork_aware_finalization() { // starting block A1 (last finalized.) api.push_block(1, vec![], true); - let (pool, _background, _) = BasicPool::new_test(api.into()); + let (pool, _background) = BasicPool::new_test(api.into()); let mut canon_watchers = vec![]; let from_alice = uxt(Alice, 1); @@ -597,7 +609,7 @@ fn prune_and_retract_tx_at_same_time() { // starting block A1 (last finalized.) api.push_block(1, vec![], true); - let (pool, _background, _) = BasicPool::new_test(api.into()); + let (pool, _background) = BasicPool::new_test(api.into()); let from_alice = uxt(Alice, 1); pool.api().increment_nonce(Alice.into()); @@ -663,7 +675,7 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() { // starting block A1 (last finalized.) api.push_block(1, vec![], true); - let (pool, _background, _) = BasicPool::new_test(api.into()); + let (pool, _background) = BasicPool::new_test(api.into()); let tx0 = uxt(Alice, 1); let tx1 = uxt(Dave, 2); @@ -708,7 +720,7 @@ fn resubmit_from_retracted_fork() { // starting block A1 (last finalized.) api.push_block(1, vec![], true); - let (pool, _background, _) = BasicPool::new_test(api.into()); + let (pool, _background) = BasicPool::new_test(api.into()); let tx0 = uxt(Alice, 1); let tx1 = uxt(Dave, 2); @@ -800,7 +812,7 @@ fn resubmit_from_retracted_fork() { #[test] fn ready_set_should_not_resolve_before_block_update() { - let (pool, _guard, _notifier) = maintained_pool(); + let (pool, _api, _guard) = maintained_pool(); let xt1 = uxt(Alice, 209); block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported"); @@ -809,8 +821,8 @@ fn ready_set_should_not_resolve_before_block_update() { #[test] fn ready_set_should_resolve_after_block_update() { - let (pool, _guard, _notifier) = maintained_pool(); - let header = pool.api().push_block(1, vec![], true); + let (pool, api, _guard) = maintained_pool(); + let header = api.push_block(1, vec![], true); let xt1 = uxt(Alice, 209); @@ -822,8 +834,8 @@ fn ready_set_should_resolve_after_block_update() { #[test] fn ready_set_should_eventually_resolve_when_block_update_arrives() { - let (pool, _guard, _notifier) = maintained_pool(); - let header = pool.api().push_block(1, vec![], true); + let (pool, api, _guard) = maintained_pool(); + let header = api.push_block(1, vec![], true); let xt1 = uxt(Alice, 209); @@ -833,7 +845,7 @@ fn ready_set_should_eventually_resolve_when_block_update_arrives() { let mut context = futures::task::Context::from_waker(&noop_waker); let mut ready_set_future = pool.ready_at(1); - if let Poll::Ready(_) = ready_set_future.poll_unpin(&mut context) { + if ready_set_future.poll_unpin(&mut context).is_ready() { panic!("Ready set should not be ready before block update!"); } @@ -929,13 +941,13 @@ fn import_notification_to_pool_maintain_works() { // When we prune transactions, we need to make sure that we remove #[test] fn pruning_a_transaction_should_remove_it_from_best_transaction() { - let (pool, _guard, _notifier) = maintained_pool(); + let (pool, api, _guard) = maintained_pool(); let xt1 = Extrinsic::IncludeData(Vec::new()); block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported"); assert_eq!(pool.status().ready, 1); - let header = pool.api().push_block(1, vec![xt1.clone()], true); + let header = api.push_block(1, vec![xt1.clone()], true); // This will prune `xt1`. block_on(pool.maintain(block_event(header))); @@ -943,26 +955,6 @@ fn pruning_a_transaction_should_remove_it_from_best_transaction() { assert_eq!(pool.status().ready, 0); } -#[test] -fn only_revalidate_on_best_block() { - let xt = uxt(Alice, 209); - - let (pool, _guard, mut notifier) = maintained_pool(); - - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported"); - assert_eq!(pool.status().ready, 1); - - let header = pool.api().push_block(1, vec![], true); - - pool.api().push_block(2, vec![], false); - pool.api().push_block(2, vec![], false); - - block_on(pool.maintain(block_event(header))); - block_on(notifier.next()); - - assert_eq!(pool.status().ready, 1); -} - #[test] fn stale_transactions_are_pruned() { sp_tracing::try_init_simple(); @@ -974,7 +966,7 @@ fn stale_transactions_are_pruned() { Transfer { from: Alice.into(), to: Bob.into(), nonce: 3, amount: 1 }, ]; - let (pool, _guard, _notifier) = maintained_pool(); + let (pool, api, _guard) = maintained_pool(); xts.into_iter().for_each(|xt| { block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.into_signed_tx())) @@ -992,7 +984,7 @@ fn stale_transactions_are_pruned() { ]; // Import block - let header = pool.api().push_block(1, xts, true); + let header = api.push_block(1, xts, true); block_on(pool.maintain(block_event(header))); // The imported transactions have a different hash and should not evict our initial // transactions. @@ -1000,7 +992,7 @@ fn stale_transactions_are_pruned() { // Import enough blocks to make our transactions stale for n in 1..66 { - let header = pool.api().push_block(n, vec![], true); + let header = api.push_block(n, vec![], true); block_on(pool.maintain(block_event(header))); } diff --git a/client/transaction-pool/tests/revalidation.rs b/client/transaction-pool/tests/revalidation.rs deleted file mode 100644 index b2c8225b78f58..0000000000000 --- a/client/transaction-pool/tests/revalidation.rs +++ /dev/null @@ -1,32 +0,0 @@ -use futures::executor::block_on; -use sc_transaction_pool::test_helpers::{Pool, RevalidationQueue}; -use sc_transaction_pool_api::TransactionSource; -use sp_runtime::generic::BlockId; -use std::sync::Arc; -use substrate_test_runtime_client::AccountKeyring::*; -use substrate_test_runtime_transaction_pool::{uxt, TestApi}; - -fn setup() -> (Arc, Pool) { - let test_api = Arc::new(TestApi::empty()); - let pool = Pool::new(Default::default(), true.into(), test_api.clone()); - (test_api, pool) -} - -#[test] -fn smoky() { - let (api, pool) = setup(); - let pool = Arc::new(pool); - let queue = Arc::new(RevalidationQueue::new(api.clone(), pool.clone())); - - let uxt = uxt(Alice, 0); - let uxt_hash = - block_on(pool.submit_one(&BlockId::number(0), TransactionSource::External, uxt.clone())) - .expect("Should be valid"); - - block_on(queue.revalidate_later(0, vec![uxt_hash])); - - // revalidated in sync offload 2nd time - assert_eq!(api.validation_requests().len(), 2); - // number of ready - assert_eq!(pool.validated_pool().status().ready, 1); -} diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index a0d04bd70271f..8eaaac62c5561 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -17,7 +17,7 @@ parking_lot = "0.11.2" codec = { package = "parity-scale-codec", version = "2.0.0" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } -sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool", features = ["test-helpers"] } +sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } futures = "0.3.16" derive_more = "0.99.16" diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index d43347bdcb6e6..a339ce8c7f65f 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -25,7 +25,9 @@ use parking_lot::RwLock; use sp_blockchain::CachedHeaderMetadata; use sp_runtime::{ generic::{self, BlockId}, - traits::{BlakeTwo256, Block as BlockT, Hash as HashT, Header as _, TrailingZeroInput}, + traits::{ + BlakeTwo256, Block as BlockT, Hash as HashT, Header as _, NumberFor, TrailingZeroInput, + }, transaction_validity::{ InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, @@ -227,7 +229,7 @@ impl TestApi { } } -impl sc_transaction_pool::test_helpers::ChainApi for TestApi { +impl sc_transaction_pool::ChainApi for TestApi { type Block = Block; type Error = Error; type ValidationFuture = futures::future::Ready>; @@ -237,7 +239,7 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi { &self, at: &BlockId, _source: TransactionSource, - uxt: sc_transaction_pool::test_helpers::ExtrinsicFor, + uxt: ::Extrinsic, ) -> Self::ValidationFuture { self.validation_requests.write().push(uxt.clone()); @@ -297,7 +299,7 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi { fn block_id_to_number( &self, at: &BlockId, - ) -> Result>, Error> { + ) -> Result>, Error> { Ok(match at { generic::BlockId::Hash(x) => self.chain.read().block_by_hash.get(x).map(|b| *b.header.number()), @@ -308,7 +310,7 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi { fn block_id_to_hash( &self, at: &BlockId, - ) -> Result>, Error> { + ) -> Result::Hash>, Error> { Ok(match at { generic::BlockId::Hash(x) => Some(x.clone()), generic::BlockId::Number(num) => @@ -318,10 +320,7 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi { }) } - fn hash_and_length( - &self, - ex: &sc_transaction_pool::test_helpers::ExtrinsicFor, - ) -> (Hash, usize) { + fn hash_and_length(&self, ex: &::Extrinsic) -> (Hash, usize) { Self::hash_and_length_inner(ex) } From 7e7045267f415c1e806ef6d7804743e0a8e44ddb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jan 2022 23:07:02 +0100 Subject: [PATCH 0392/1472] Bump ip_network from 0.4.0 to 0.4.1 (#10525) Bumps [ip_network](https://github.com/JakubOnderka/ip_network) from 0.4.0 to 0.4.1. - [Release notes](https://github.com/JakubOnderka/ip_network/releases) - [Commits](https://github.com/JakubOnderka/ip_network/commits) --- updated-dependencies: - dependency-name: ip_network 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/authority-discovery/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba80103c174ba..cc6b80221b259 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2989,9 +2989,9 @@ dependencies = [ [[package]] name = "ip_network" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b746553d2f4a1ca26fab939943ddfb217a091f34f53571620a8e3d30691303" +checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" [[package]] name = "ipconfig" @@ -11024,8 +11024,8 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e" dependencies = [ - "cfg-if 0.1.10", - "rand 0.6.5", + "cfg-if 1.0.0", + "rand 0.8.4", "static_assertions", ] diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index fd94e71ceb842..ac9f0cdb1828c 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", default-features = false, version = "2 derive_more = "0.99.16" futures = "0.3.9" futures-timer = "3.0.1" -ip_network = "0.4.0" +ip_network = "0.4.1" libp2p = { version = "0.40.0", default-features = false, features = ["kad"] } log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 4f3ea4e939b6e..1a77431b4b743 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -33,7 +33,7 @@ futures = "0.3.9" futures-timer = "3.0.2" asynchronous-codec = "0.5" hex = "0.4.0" -ip_network = "0.4.0" +ip_network = "0.4.1" linked-hash-map = "0.5.4" linked_hash_set = "0.1.3" lru = "0.7.0" From cd3d2b1b65929bafa699953094bcd8b9fe7d3dfc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jan 2022 10:05:01 +0100 Subject: [PATCH 0393/1472] Bump serde_json from 1.0.71 to 1.0.74 (#10577) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.71 to 1.0.74. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.71...v1.0.74) --- 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 | 24 ++++++++++++------- bin/node/bench/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/serializer/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- 23 files changed, 37 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc6b80221b259..d5e242cc22c94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1368,7 +1368,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ "bstr", "csv-core", - "itoa", + "itoa 0.4.8", "ryu", "serde", ] @@ -2731,7 +2731,7 @@ checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" dependencies = [ "bytes 1.1.0", "fnv", - "itoa", + "itoa 0.4.8", ] [[package]] @@ -2806,7 +2806,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa", + "itoa 0.4.8", "pin-project-lite 0.2.6", "socket2 0.4.0", "tokio", @@ -3026,6 +3026,12 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + [[package]] name = "jobserver" version = "0.1.21" @@ -4968,7 +4974,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465" dependencies = [ "arrayvec 0.4.12", - "itoa", + "itoa 0.4.8", ] [[package]] @@ -5076,7 +5082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7337d80c23c2d8b1349563981bc4fb531220733743ba8115454a67b181173f0d" dependencies = [ "dtoa", - "itoa", + "itoa 0.4.8", "open-metrics-client-derive-text-encode", "owning_ref", ] @@ -7459,7 +7465,7 @@ dependencies = [ "cc", "errno", "io-lifetimes", - "itoa", + "itoa 0.4.8", "libc", "linux-raw-sys", "once_cell", @@ -8938,11 +8944,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.71" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19" +checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142" dependencies = [ - "itoa", + "itoa 1.0.1", "ryu", "serde", ] diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 114742990bcdc..90951d75cfd21 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -17,7 +17,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } serde = "1.0.132" -serde_json = "1.0.71" +serde_json = "1.0.74" structopt = "0.3" derive_more = "0.99.16" kvdb = "0.10.0" diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index c14d604990cbf..bc81732dcd41d 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -28,7 +28,7 @@ beefy-gadget = { version = "4.0.0-dev", path = "../." } beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } [dev-dependencies] -serde_json = "1.0.50" +serde_json = "1.0.74" sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ "test-helpers", diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 601fb5b4da9e9..769f502dd5ed2 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -18,7 +18,7 @@ impl-trait-for-tuples = "0.2.1" sc-network = { version = "0.10.0-dev", path = "../network" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } serde = { version = "1.0.132", features = ["derive"] } -serde_json = "1.0.71" +serde_json = "1.0.74" sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index f92f7b51c8b7f..7ef5ef9d68932 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -23,7 +23,7 @@ parity-scale-codec = "2.3.1" hex = "0.4.2" rand = "0.7.3" tiny-bip39 = "0.8.2" -serde_json = "1.0.71" +serde_json = "1.0.74" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 61321e684fa9e..dbc840d26c57c 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -33,7 +33,7 @@ sp-keystore = { version = "0.10.0", path = "../../../../primitives/keystore" } [dev-dependencies] sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } -serde_json = "1.0.71" +serde_json = "1.0.74" sp-keyring = { version = "4.0.0-dev", path = "../../../../primitives/keyring" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 6e7463792e7b4..10344e09c6858 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -35,7 +35,7 @@ sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -serde_json = "1.0.71" +serde_json = "1.0.74" sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index b4c684a206f30..7fe9e182efbdf 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -22,7 +22,7 @@ sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } hex = "0.4.0" parking_lot = "0.11.2" -serde_json = "1.0.71" +serde_json = "1.0.74" [dev-dependencies] tempfile = "3.1.0" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 1a77431b4b743..d5304cf5fbf0b 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -47,7 +47,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } serde = { version = "1.0.132", features = ["derive"] } -serde_json = "1.0.71" +serde_json = "1.0.74" smallvec = "1.7.0" sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index ec226b3d9bee2..ac3590630a1eb 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.9" libp2p = { version = "0.40.0", default-features = false } sc-utils = { version = "4.0.0-dev", path = "../utils"} log = "0.4.8" -serde_json = "1.0.71" +serde_json = "1.0.74" wasm-timer = "0.2" [dev-dependencies] diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index f8f8e333a9c68..aa560bc2e1c13 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -28,7 +28,7 @@ sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-runtime = { path = "../../primitives/runtime", version = "4.0.0" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } serde = { version = "1.0.132", features = ["derive"] } -serde_json = "1.0.71" +serde_json = "1.0.74" sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index ae450c2ba9a22..4246168c3e66c 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -18,7 +18,7 @@ jsonrpc-core = "18.0.0" pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} -serde_json = "1.0.71" +serde_json = "1.0.74" tokio = "1.15" http = { package = "jsonrpc-http-server", version = "18.0.0" } ipc = { package = "jsonrpc-ipc-server", version = "18.0.0" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index b8829dca870b3..3a2af0bb211ec 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -23,7 +23,7 @@ log = "0.4.8" sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } rpc = { package = "jsonrpc-core", version = "18.0.0" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } -serde_json = "1.0.71" +serde_json = "1.0.74" sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index bfe053152ba4b..84e24634613ff 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -34,7 +34,7 @@ exit-future = "0.2.0" pin-project = "1.0.8" hash-db = "0.15.2" serde = "1.0.132" -serde_json = "1.0.71" +serde_json = "1.0.74" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sp-trie = { version = "4.0.0", path = "../../primitives/trie" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 859173ca77eb8..e5ac6550d2136 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -23,7 +23,7 @@ sc-consensus-babe = { version = "0.10.0-dev", path = "../consensus/babe" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } -serde_json = "1.0.71" +serde_json = "1.0.74" serde = { version = "1.0.132", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 2001026a1201f..4e9a1f8938a9b 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -23,6 +23,6 @@ log = "0.4.8" pin-project = "1.0.8" rand = "0.7.2" serde = { version = "1.0.132", features = ["derive"] } -serde_json = "1.0.71" +serde_json = "1.0.74" chrono = "0.4.19" thiserror = "1.0.30" diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index c6f9124c2a275..cf6aee670b5b4 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -27,4 +27,4 @@ sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } [dev-dependencies] -serde_json = "1.0.71" +serde_json = "1.0.74" diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 7679dae8e6ea9..9cf6790de46d8 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -29,7 +29,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -serde_json = "1.0.71" +serde_json = "1.0.74" pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 3226ec09d0145..820c8f00bb8f0 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -30,7 +30,7 @@ serde = { version = "1.0.132", optional = true } [dev-dependencies] smallvec = "1.7.0" -serde_json = "1.0.71" +serde_json = "1.0.74" sp-storage = { version = "4.0.0", default-features = false, path = "../../../primitives/storage" } diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index 51aaa990456e9..52fe09b2c7894 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -18,4 +18,4 @@ sp-core = { version = "4.1.0-dev", path = "../core" } rustc-hash = "1.1.0" [dev-dependencies] -serde_json = "1.0.71" +serde_json = "1.0.74" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index deb877abcca08..abf246eece9a0 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -32,7 +32,7 @@ hash256-std-hasher = { version = "0.15.2", default-features = false } either = { version = "1.5", default-features = false } [dev-dependencies] -serde_json = "1.0.71" +serde_json = "1.0.74" rand = "0.7.2" sp-state-machine = { version = "0.10.0", path = "../state-machine" } sp-api = { version = "4.0.0-dev", path = "../api" } diff --git a/primitives/serializer/Cargo.toml b/primitives/serializer/Cargo.toml index 40f4d19e047eb..a0413164eb57a 100644 --- a/primitives/serializer/Cargo.toml +++ b/primitives/serializer/Cargo.toml @@ -15,4 +15,4 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = "1.0.132" -serde_json = "1.0.71" +serde_json = "1.0.74" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index fa0ae85e706c4..cb9f17f637dda 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } futures = "0.3.16" hex = "0.4" serde = "1.0.132" -serde_json = "1.0.71" +serde_json = "1.0.74" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } sc-client-db = { version = "0.10.0-dev", features = [ "test-helpers", From 765cd2905b738b1079923f322e11b8cd8494661d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jan 2022 13:18:16 +0000 Subject: [PATCH 0394/1472] Bump pin-project from 1.0.8 to 1.0.10 (#10578) Bumps [pin-project](https://github.com/taiki-e/pin-project) from 1.0.8 to 1.0.10. - [Release notes](https://github.com/taiki-e/pin-project/releases) - [Changelog](https://github.com/taiki-e/pin-project/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/pin-project/compare/v1.0.8...v1.0.10) --- updated-dependencies: - dependency-name: pin-project 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 | 30 +++++++++++++++--------------- client/network/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5e242cc22c94..cdd2d0d11e459 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3254,7 +3254,7 @@ dependencies = [ "http", "jsonrpsee-types", "log 0.4.14", - "pin-project 1.0.8", + "pin-project 1.0.10", "rustls-native-certs", "serde", "serde_json", @@ -3454,7 +3454,7 @@ dependencies = [ "libp2p-yamux", "multiaddr", "parking_lot 0.11.2", - "pin-project 1.0.8", + "pin-project 1.0.10", "smallvec 1.7.0", "wasm-timer", ] @@ -3479,7 +3479,7 @@ dependencies = [ "multihash 0.14.0", "multistream-select", "parking_lot 0.11.2", - "pin-project 1.0.8", + "pin-project 1.0.10", "prost", "prost-build", "rand 0.8.4", @@ -3720,7 +3720,7 @@ checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" dependencies = [ "futures 0.3.16", "log 0.4.14", - "pin-project 1.0.8", + "pin-project 1.0.10", "rand 0.7.3", "salsa20", "sha3", @@ -3739,7 +3739,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "pin-project 1.0.8", + "pin-project 1.0.10", "prost", "prost-build", "rand 0.7.3", @@ -4408,7 +4408,7 @@ dependencies = [ "bytes 1.1.0", "futures 0.3.16", "log 0.4.14", - "pin-project 1.0.8", + "pin-project 1.0.10", "smallvec 1.7.0", "unsigned-varint 0.7.0", ] @@ -6633,11 +6633,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" dependencies = [ - "pin-project-internal 1.0.8", + "pin-project-internal 1.0.10", ] [[package]] @@ -6653,9 +6653,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" dependencies = [ "proc-macro2", "quote", @@ -8269,7 +8269,7 @@ dependencies = [ "lru 0.7.0", "parity-scale-codec", "parking_lot 0.11.2", - "pin-project 1.0.8", + "pin-project 1.0.10", "prost", "prost-build", "quickcheck", @@ -8510,7 +8510,7 @@ dependencies = [ "parity-scale-codec", "parity-util-mem", "parking_lot 0.11.2", - "pin-project 1.0.8", + "pin-project 1.0.10", "rand 0.7.3", "sc-block-builder", "sc-chain-spec", @@ -8638,7 +8638,7 @@ dependencies = [ "libp2p", "log 0.4.14", "parking_lot 0.11.2", - "pin-project 1.0.8", + "pin-project 1.0.10", "rand 0.7.3", "serde", "serde_json", @@ -10822,7 +10822,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project 1.0.8", + "pin-project 1.0.10", "tracing", ] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index d5304cf5fbf0b..2df700fae8a32 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -39,7 +39,7 @@ linked_hash_set = "0.1.3" lru = "0.7.0" log = "0.4.8" parking_lot = "0.11.2" -pin-project = "1.0.8" +pin-project = "1.0.10" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } prost = "0.9" rand = "0.7.2" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 84e24634613ff..e9b05c0d28aa6 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -31,7 +31,7 @@ parking_lot = "0.11.2" log = "0.4.11" futures-timer = "3.0.1" exit-future = "0.2.0" -pin-project = "1.0.8" +pin-project = "1.0.10" hash-db = "0.15.2" serde = "1.0.132" serde_json = "1.0.74" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 4e9a1f8938a9b..2417f3c77b761 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3.9" wasm-timer = "0.2.5" libp2p = { version = "0.40.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.8" -pin-project = "1.0.8" +pin-project = "1.0.10" rand = "0.7.2" serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.74" From 823581c4adc2cf9ab6948f5337bbb3cc5cb43cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 4 Jan 2022 20:48:43 +0100 Subject: [PATCH 0395/1472] Use storage transaction when running with proof recorder (#10581) This will enable parachains to re-import a block without re-executing it. --- client/service/src/client/call_executor.rs | 4 +++- primitives/state-machine/src/backend.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index f2b45bc413e2a..739ad029dc190 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -246,8 +246,10 @@ where &runtime_code, self.spawn_handle.clone(), ) + .with_storage_transaction_cache( + storage_transaction_cache.as_mut().map(|c| &mut **c), + ) .set_parent_hash(at_hash); - // TODO: https://github.com/paritytech/substrate/issues/4455 state_machine.execute_using_consensus_failure_handler( execution_manager, native_call.map(|n| || (n)().map_err(|e| Box::new(e) as Box<_>)), diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index cde5011ce2d8e..215caaa17f302 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -40,7 +40,7 @@ pub trait Backend: sp_std::fmt::Debug { type Transaction: Consolidate + Default + Send; /// Type of trie backend storage. - type TrieBackendStorage: TrieBackendStorage; + type TrieBackendStorage: TrieBackendStorage; /// Get keyed storage or None if there is nothing associated. fn storage(&self, key: &[u8]) -> Result, Self::Error>; From 2ae62422298746828d3a8c5a8f401d8c6806b998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 5 Jan 2022 13:09:01 +0100 Subject: [PATCH 0396/1472] sc-keystore: Improve weird error message (#10584) The keystore would print "Invalid password" when a key was stored using an incorrect public key. This pr improves the error message to communicate better to the user on what is wrong. --- client/keystore/src/lib.rs | 9 ++++++--- client/keystore/src/local.rs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/client/keystore/src/lib.rs b/client/keystore/src/lib.rs index 83641f267bc8c..359326bb4cae0 100644 --- a/client/keystore/src/lib.rs +++ b/client/keystore/src/lib.rs @@ -35,8 +35,11 @@ pub enum Error { /// JSON error. Json(serde_json::Error), /// Invalid password. - #[display(fmt = "Invalid password")] - InvalidPassword, + #[display( + fmt = "Requested public key and public key of the loaded private key do not match. \n + This means either that the keystore password is incorrect or that the private key was stored under a wrong public key." + )] + PublicKeyMismatch, /// Invalid BIP39 phrase #[display(fmt = "Invalid recovery phrase (BIP39) data")] InvalidPhrase, @@ -58,7 +61,7 @@ impl From for TraitError { fn from(error: Error) -> Self { match error { Error::KeyNotSupported(id) => TraitError::KeyNotSupported(id), - Error::InvalidSeed | Error::InvalidPhrase | Error::InvalidPassword => + Error::InvalidSeed | Error::InvalidPhrase | Error::PublicKeyMismatch => TraitError::ValidationError(error.to_string()), Error::Unavailable => TraitError::Unavailable, Error::Io(e) => TraitError::Other(e.to_string()), diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 9c8e3baab1828..9f6f18d0c2930 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -503,7 +503,7 @@ impl KeystoreInner { if &pair.public() == public { Ok(Some(pair)) } else { - Err(Error::InvalidPassword) + Err(Error::PublicKeyMismatch) } } From a2ae8a5702c782f1de05dae77b39f13c6ddda3a8 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 5 Jan 2022 14:35:30 +0000 Subject: [PATCH 0397/1472] Make clippy _a little_ more annoying (#10570) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Clippy: +complexity * Update client/cli/src/arg_enums.rs Co-authored-by: Bastian Köcher * Update bin/node/inspect/src/lib.rs Co-authored-by: Bastian Köcher * Update primitives/keystore/src/testing.rs Co-authored-by: Bastian Köcher * Update frame/elections/src/lib.rs Co-authored-by: Keith Yeung * Update primitives/npos-elections/fuzzer/src/reduce.rs Co-authored-by: Keith Yeung * Incorporating feedback * No need for Ok * Additional * Needed slice * Wigy's suggestions on less derefs * fix count * reverting changes brought in by option_map_unit_fn * add --all-targets Co-authored-by: Bastian Köcher Co-authored-by: Keith Yeung --- .cargo/config.toml | 21 +++++++++- .gitlab-ci.yml | 2 +- bin/node-template/node/src/service.rs | 2 +- bin/node/inspect/src/lib.rs | 2 +- client/chain-spec/src/chain_spec.rs | 2 +- client/cli/src/arg_enums.rs | 2 +- client/cli/src/commands/sign.rs | 2 +- client/cli/src/commands/verify.rs | 2 +- client/cli/src/params/mod.rs | 4 +- client/consensus/common/src/block_import.rs | 4 +- .../manual-seal/src/consensus/babe.rs | 2 +- client/consensus/manual-seal/src/lib.rs | 6 +-- client/db/src/bench.rs | 1 - client/db/src/lib.rs | 6 +-- client/db/src/offchain.rs | 2 +- client/executor/src/integration_tests/mod.rs | 10 ++--- client/executor/src/lib.rs | 2 +- client/executor/src/wasm_runtime.rs | 2 +- client/executor/wasmtime/src/host.rs | 4 +- client/executor/wasmtime/src/tests.rs | 2 +- .../src/communication/gossip.rs | 5 +-- client/finality-grandpa/src/lib.rs | 2 +- client/rpc/src/state/state_full.rs | 5 +-- client/rpc/src/state/tests.rs | 2 +- client/rpc/src/system/tests.rs | 10 ++--- client/service/src/builder.rs | 4 +- client/service/src/client/call_executor.rs | 4 +- client/service/src/client/client.rs | 10 ++--- client/state-db/src/noncanonical.rs | 9 ++-- client/tracing/proc-macro/src/lib.rs | 2 +- client/tracing/src/block/mod.rs | 4 +- client/tracing/src/lib.rs | 9 ++-- client/transaction-pool/src/graph/pool.rs | 8 +--- frame/authority-discovery/src/lib.rs | 7 +--- frame/authorship/src/lib.rs | 8 ++-- frame/babe/src/lib.rs | 8 +--- frame/bags-list/src/list/mod.rs | 2 +- frame/balances/src/lib.rs | 9 +--- frame/contracts/src/storage/meter.rs | 9 ++-- frame/contracts/src/wasm/runtime.rs | 2 +- .../src/unsigned.rs | 2 +- frame/elections-phragmen/src/lib.rs | 2 +- frame/examples/basic/src/lib.rs | 2 +- frame/grandpa/src/lib.rs | 8 +--- frame/im-online/src/tests.rs | 2 +- frame/scored-pool/src/mock.rs | 1 - frame/session/src/lib.rs | 6 +-- frame/society/src/lib.rs | 8 ++-- frame/staking/src/lib.rs | 8 +--- frame/staking/src/pallet/impls.rs | 4 +- frame/staking/src/tests.rs | 7 ++-- .../procedural/src/pallet/parse/storage.rs | 4 +- frame/support/src/dispatch.rs | 2 +- frame/support/src/storage/migration.rs | 8 ++-- frame/support/src/storage/mod.rs | 8 ++-- frame/support/test/pallet/src/lib.rs | 8 +--- frame/support/test/tests/genesisconfig.rs | 2 +- frame/support/test/tests/issue2219.rs | 4 +- frame/support/test/tests/pallet.rs | 2 +- frame/system/src/extensions/check_genesis.rs | 2 +- .../system/src/extensions/check_mortality.rs | 2 +- .../src/extensions/check_non_zero_sender.rs | 2 +- .../src/extensions/check_spec_version.rs | 2 +- .../system/src/extensions/check_tx_version.rs | 2 +- frame/system/src/lib.rs | 8 +--- frame/uniques/src/tests.rs | 2 +- frame/vesting/src/lib.rs | 9 ++-- .../api/proc-macro/src/decl_runtime_apis.rs | 5 +-- primitives/authorship/src/lib.rs | 4 +- primitives/debug-derive/src/impls.rs | 2 +- primitives/keystore/src/testing.rs | 4 +- .../npos-elections/fuzzer/src/compact.rs | 2 +- .../npos-elections/fuzzer/src/reduce.rs | 2 +- primitives/npos-elections/src/reduce.rs | 5 +-- primitives/runtime-interface/test/src/lib.rs | 41 +++++++++---------- primitives/runtime/src/generic/digest.rs | 8 +--- .../src/generic/unchecked_extrinsic.rs | 2 +- primitives/runtime/src/traits.rs | 2 +- primitives/state-machine/src/backend.rs | 2 +- primitives/state-machine/src/ext.rs | 4 +- primitives/state-machine/src/testing.rs | 2 +- primitives/timestamp/src/lib.rs | 6 +-- .../transaction-storage-proof/src/lib.rs | 6 +-- primitives/trie/src/lib.rs | 6 +-- test-utils/runtime/src/lib.rs | 8 +--- utils/frame/benchmarking-cli/src/command.rs | 4 +- utils/frame/try-runtime/cli/src/lib.rs | 1 - utils/frame/try-runtime/cli/src/parse.rs | 7 +++- 88 files changed, 190 insertions(+), 249 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 06328af71459c..de299a90971e4 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -10,5 +10,24 @@ rustflags = [ "-Aclippy::all", "-Dclippy::correctness", "-Aclippy::if-same-then-else", - "-Aclippy::clone-double-ref" + "-Aclippy::clone-double-ref", + "-Dclippy::complexity", + "-Aclippy::clone_on_copy", # Too common + "-Aclippy::needless_lifetimes", # Backward compat? + "-Aclippy::zero-prefixed-literal", # 00_1000_000 + "-Aclippy::type_complexity", # raison d'etre + "-Aclippy::nonminimal-bool", # maybe + "-Aclippy::borrowed-box", # Reasonable to fix this one + "-Aclippy::too-many-arguments", # (Turning this on would lead to) + "-Aclippy::unnecessary_cast", # Types may change + "-Aclippy::identity-op", # One case where we do 0 + + "-Aclippy::useless_conversion", # Types may change + "-Aclippy::unit_arg", # styalistic. + "-Aclippy::option-map-unit-fn", # styalistic + "-Aclippy::bind_instead_of_map", # styalistic + "-Aclippy::erasing_op", # E.g. 0 * DOLLARS + "-Aclippy::eq_op", # In tests we test equality. + "-Aclippy::while_immutable_condition", # false positives + "-Aclippy::needless_option_as_deref", # false positives + "-Aclippy::derivable_impls", # false positives ] diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 685d201d85983..2aee053ef4de3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -350,7 +350,7 @@ cargo-clippy: <<: *docker-env <<: *test-refs script: - - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo +nightly clippy + - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo +nightly clippy --all-targets cargo-check-benches: stage: test diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 92bd059e528a8..975a491cf4da1 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -60,7 +60,7 @@ pub fn new_partial( ServiceError, > { if config.keystore_remote.is_some() { - return Err(ServiceError::Other(format!("Remote Keystores are not supported."))) + return Err(ServiceError::Other("Remote Keystores are not supported.".into())) } let telemetry = config diff --git a/bin/node/inspect/src/lib.rs b/bin/node/inspect/src/lib.rs index 722a7903da4c2..ff1eecd219a97 100644 --- a/bin/node/inspect/src/lib.rs +++ b/bin/node/inspect/src/lib.rs @@ -261,7 +261,7 @@ impl FromStr for ExtrinsicAddres let index = it .next() - .ok_or_else(|| format!("Extrinsic index missing: example \"5:0\""))? + .ok_or("Extrinsic index missing: example \"5:0\"")? .parse() .map_err(|e| format!("Invalid index format: {}", e))?; diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 98241255de55b..11e5b73fe77f8 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -223,7 +223,7 @@ impl ChainSpec { /// Network protocol id. pub fn protocol_id(&self) -> Option<&str> { - self.client_spec.protocol_id.as_ref().map(String::as_str) + self.client_spec.protocol_id.as_deref() } /// Additional loosly-typed properties of the chain. diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index 3e1ead609630a..c13361a9ac2ba 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -51,7 +51,7 @@ impl std::str::FromStr for WasmExecutionMethod { } #[cfg(not(feature = "wasmtime"))] { - Err(format!("`Compiled` variant requires the `wasmtime` feature to be enabled")) + Err("`Compiled` variant requires the `wasmtime` feature to be enabled".into()) } } else { Err(format!("Unknown variant `{}`, known variants: {:?}", s, Self::variants())) diff --git a/client/cli/src/commands/sign.rs b/client/cli/src/commands/sign.rs index 1b2fbba40ea16..8d331d7994595 100644 --- a/client/cli/src/commands/sign.rs +++ b/client/cli/src/commands/sign.rs @@ -70,7 +70,7 @@ fn sign( message: Vec, ) -> error::Result { let pair = utils::pair_from_suri::

(suri, password)?; - Ok(format!("{}", hex::encode(pair.sign(&message)))) + Ok(hex::encode(pair.sign(&message))) } #[cfg(test)] diff --git a/client/cli/src/commands/verify.rs b/client/cli/src/commands/verify.rs index bf03be1737d48..9ffd5d9d4844e 100644 --- a/client/cli/src/commands/verify.rs +++ b/client/cli/src/commands/verify.rs @@ -57,7 +57,7 @@ impl VerifyCmd { let message = utils::read_message(self.message.as_ref(), self.hex)?; let sig_data = utils::decode_hex(&self.sig)?; let uri = utils::read_uri(self.uri.as_ref())?; - let uri = if uri.starts_with("0x") { &uri[2..] } else { &uri }; + let uri = if let Some(uri) = uri.strip_prefix("0x") { uri } else { &uri }; with_crypto_scheme!(self.crypto_scheme.scheme, verify(sig_data, message, uri)) } diff --git a/client/cli/src/params/mod.rs b/client/cli/src/params/mod.rs index c7181840a8641..e6f81079263de 100644 --- a/client/cli/src/params/mod.rs +++ b/client/cli/src/params/mod.rs @@ -79,8 +79,8 @@ impl FromStr for BlockNumberOrHash { type Err = String; fn from_str(block_number: &str) -> Result { - if block_number.starts_with("0x") { - if let Some(pos) = &block_number[2..].chars().position(|c| !c.is_ascii_hexdigit()) { + if let Some(rest) = block_number.strip_prefix("0x") { + if let Some(pos) = rest.chars().position(|c| !c.is_ascii_hexdigit()) { Err(format!( "Expected block hash, found illegal hex character at position: {}", 2 + pos, diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index af54d54770f76..24fec9b974a4c 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -287,9 +287,9 @@ impl BlockImportParams { pub fn take_intermediate(&mut self, key: &[u8]) -> Result, Error> { let (k, v) = self.intermediates.remove_entry(key).ok_or(Error::NoIntermediate)?; - v.downcast::().or_else(|v| { + v.downcast::().map_err(|v| { self.intermediates.insert(k, v); - Err(Error::InvalidIntermediate) + Error::InvalidIntermediate }) } diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index b16bee816b172..6d86658cbf504 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -279,7 +279,7 @@ where // a quick check to see if we're in the authorities let epoch = self.epoch(parent, slot)?; let (authority, _) = self.authorities.first().expect("authorities is non-emptyp; qed"); - let has_authority = epoch.authorities.iter().find(|(id, _)| *id == *authority).is_some(); + let has_authority = epoch.authorities.iter().any(|(id, _)| *id == *authority); if !has_authority { log::info!(target: "manual-seal", "authority not found"); diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index 3e5ce5b2a4014..a057190f6b378 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -173,7 +173,7 @@ pub async fn run_manual_seal( env: &mut env, select_chain: &select_chain, block_import: &mut block_import, - consensus_data_provider: consensus_data_provider.as_ref().map(|p| &**p), + consensus_data_provider: consensus_data_provider.as_deref(), pool: pool.clone(), client: client.clone(), create_inherent_data_providers: &create_inherent_data_providers, @@ -408,8 +408,8 @@ mod tests { }) .await .unwrap(); - // assert that the background task returns ok - assert_eq!(rx.await.unwrap().unwrap(), ()); + // check that the background task returns ok: + rx.await.unwrap().unwrap(); } #[tokio::test] diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index a18e7942a54f4..fe31d31dfef9e 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -672,7 +672,6 @@ mod test { assert_eq!(rw_tracker.1, 0); assert_eq!(rw_tracker.2, 2); assert_eq!(rw_tracker.3, 0); - drop(rw_tracker); bench_state.wipe().unwrap(); } } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index c570ca2f15fbe..19766d76048e9 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1993,7 +1993,7 @@ impl sc_client_api::backend::Backend for Backend { }); let database_cache = MemorySize::from_bytes(0); let state_cache = - MemorySize::from_bytes((*&self.shared_cache).read().used_storage_cache_size()); + MemorySize::from_bytes(self.shared_cache.read().used_storage_cache_size()); let state_db = self.storage.state_db.memory_info(); Some(UsageInfo { @@ -2452,7 +2452,7 @@ pub(crate) mod tests { let storage = vec![(vec![1, 3, 5], None), (vec![5, 5, 5], Some(vec![4, 5, 6]))]; let (root, overlay) = op.old_state.storage_root( - storage.iter().map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..]))), + storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))), state_version, ); op.update_db_storage(overlay).unwrap(); @@ -3000,7 +3000,7 @@ pub(crate) mod tests { let storage = vec![(b"test".to_vec(), Some(b"test2".to_vec()))]; let (root, overlay) = op.old_state.storage_root( - storage.iter().map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..]))), + storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))), state_version, ); op.update_db_storage(overlay).unwrap(); diff --git a/client/db/src/offchain.rs b/client/db/src/offchain.rs index c6351a66a2350..4f0a77ce57566 100644 --- a/client/db/src/offchain.rs +++ b/client/db/src/offchain.rs @@ -92,7 +92,7 @@ impl sp_core::offchain::OffchainStorage for LocalStorage { { let _key_guard = key_lock.lock(); let val = self.db.get(columns::OFFCHAIN, &key); - is_set = val.as_ref().map(|x| &**x) == old_value; + is_set = val.as_deref() == old_value; if is_set { self.set(prefix, item_key, new_value) diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 36339c31871d9..67e9a96cd6bae 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -126,7 +126,7 @@ fn call_in_wasm( let executor = crate::WasmExecutor::::new(execution_method, Some(1024), 8, None, 2); executor.uncached_call( - RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(), + RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), ext, true, function, @@ -479,7 +479,7 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { let err = executor .uncached_call( - RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(), + RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), &mut ext.ext(), true, "test_exhaust_heap", @@ -491,7 +491,7 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { } fn mk_test_runtime(wasm_method: WasmExecutionMethod, pages: u64) -> Arc { - let blob = RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]) + let blob = RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()) .expect("failed to create a runtime blob out of test runtime"); crate::wasm_runtime::create_wasm_runtime_with_code::( @@ -597,7 +597,7 @@ fn parallel_execution(wasm_method: WasmExecutionMethod) { assert_eq!( executor .uncached_call( - RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(), + RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), &mut ext, true, "test_twox_128", @@ -691,7 +691,7 @@ fn panic_in_spawned_instance_panics_on_joining_its_result(wasm_method: WasmExecu let error_result = call_in_wasm("test_panic_in_spawned", &[], wasm_method, &mut ext).unwrap_err(); - assert!(format!("{}", error_result).contains("Spawned task")); + assert!(error_result.contains("Spawned task")); } test_wasm_execution!(memory_is_cleared_between_invocations); diff --git a/client/executor/src/lib.rs b/client/executor/src/lib.rs index fd127887dbc26..5cd04b9e4ee6a 100644 --- a/client/executor/src/lib.rs +++ b/client/executor/src/lib.rs @@ -82,7 +82,7 @@ mod tests { ); let res = executor .uncached_call( - RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(), + RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), &mut ext, true, "test_empty_return", diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index cb6fba4e4dee5..0775755aff7cf 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -77,7 +77,7 @@ struct VersionedRuntime { impl VersionedRuntime { /// Run the given closure `f` with an instance of this runtime. - fn with_instance<'c, R, F>(&self, ext: &mut dyn Externalities, f: F) -> Result + fn with_instance(&self, ext: &mut dyn Externalities, f: F) -> Result where F: FnOnce( &Arc, diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index 5d02a836640ae..5da8ff3259031 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -195,7 +195,7 @@ impl<'a> Sandbox for HostContext<'a> { &mut self, instance_id: u32, export_name: &str, - args: &[u8], + mut args: &[u8], return_val: Pointer, return_val_len: u32, state: u32, @@ -203,7 +203,7 @@ impl<'a> Sandbox for HostContext<'a> { trace!(target: "sp-sandbox", "invoke, instance_idx={}", instance_id); // Deserialize arguments and convert them into wasmi types. - let args = Vec::::decode(&mut &args[..]) + let args = Vec::::decode(&mut args) .map_err(|_| "Can't decode serialized arguments for the invocation")? .into_iter() .map(Into::into) diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index c1e626f12d1aa..08807f1dec414 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -313,7 +313,7 @@ fn test_max_memory_pages() { #[test] fn test_instances_without_reuse_are_not_leaked() { let runtime = crate::create_runtime::( - RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(), + RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), crate::Config { heap_pages: 2048, max_memory_size: None, diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 51d832c3b27be..4e8e047a9b640 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -615,8 +615,7 @@ impl Peers { // `LUCKY_PEERS / 2` is filled we start allocating to the second stage set. let half_lucky = LUCKY_PEERS / 2; let one_and_a_half_lucky = LUCKY_PEERS + half_lucky; - let mut n_authorities_added = 0; - for peer_id in shuffled_authorities { + for (n_authorities_added, peer_id) in shuffled_authorities.enumerate() { if n_authorities_added < half_lucky { first_stage_peers.insert(*peer_id); } else if n_authorities_added < one_and_a_half_lucky { @@ -624,8 +623,6 @@ impl Peers { } else { break } - - n_authorities_added += 1; } // fill up first and second sets with remaining peers (either full or authorities) diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index b8873d00efa7c..af85965c53c10 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -267,7 +267,7 @@ pub struct Config { impl Config { fn name(&self) -> &str { - self.name.as_ref().map(|s| s.as_str()).unwrap_or("") + self.name.as_deref().unwrap_or("") } } diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 2c5a985a2b016..b8132094fe8d6 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -441,10 +441,7 @@ where keys: Option>, ) { let keys = Into::>>::into(keys); - let stream = match self - .client - .storage_changes_notification_stream(keys.as_ref().map(|x| &**x), None) - { + let stream = match self.client.storage_changes_notification_stream(keys.as_deref(), None) { Ok(stream) => stream, Err(err) => { let _ = subscriber.reject(client_err(err).into()); diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index d3aca181a41e8..9dbe02cdb7d64 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -32,7 +32,7 @@ use substrate_test_runtime_client::{prelude::*, runtime}; const STORAGE_KEY: &[u8] = b"child"; fn prefixed_storage_key() -> PrefixedStorageKey { - let child_info = ChildInfo::new_default(&STORAGE_KEY[..]); + let child_info = ChildInfo::new_default(STORAGE_KEY); child_info.prefixed_storage_key() } diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index 3e5241e2638b2..5d6945b714200 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -354,26 +354,26 @@ fn test_add_reset_log_filter() { }; // Initiate logs loop in child process - child_in.write(b"\n").unwrap(); + child_in.write_all(b"\n").unwrap(); assert!(read_line().contains(EXPECTED_BEFORE_ADD)); // Initiate add directive & reload in child process - child_in.write(b"add_reload\n").unwrap(); + child_in.write_all(b"add_reload\n").unwrap(); assert!(read_line().contains(EXPECTED_BEFORE_ADD)); assert!(read_line().contains(EXPECTED_AFTER_ADD)); // Check that increasing the max log level works - child_in.write(b"add_trace\n").unwrap(); + child_in.write_all(b"add_trace\n").unwrap(); assert!(read_line().contains(EXPECTED_WITH_TRACE)); assert!(read_line().contains(EXPECTED_BEFORE_ADD)); assert!(read_line().contains(EXPECTED_AFTER_ADD)); // Initiate logs filter reset in child process - child_in.write(b"reset\n").unwrap(); + child_in.write_all(b"reset\n").unwrap(); assert!(read_line().contains(EXPECTED_BEFORE_ADD)); // Return from child process - child_in.write(b"exit\n").unwrap(); + child_in.write_all(b"exit\n").unwrap(); assert!(child_process.wait().expect("Error waiting for child process").success()); // Check for EOF diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 262ba53a33d49..c713b4936c6b0 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -363,7 +363,7 @@ where spawn_handle, config.clone(), )?; - Ok(crate::client::Client::new( + crate::client::Client::new( backend, executor, genesis_storage, @@ -373,7 +373,7 @@ where prometheus_registry, telemetry, config, - )?) + ) } /// Parameters to pass into `build`. diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 739ad029dc190..fedd3400488d2 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -266,9 +266,7 @@ where &runtime_code, self.spawn_handle.clone(), ) - .with_storage_transaction_cache( - storage_transaction_cache.as_mut().map(|c| &mut **c), - ) + .with_storage_transaction_cache(storage_transaction_cache.as_deref_mut()) .set_parent_hash(at_hash); state_machine.execute_using_consensus_failure_handler( execution_manager, diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 452450c71e785..9d898c7d1eb8f 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1409,10 +1409,9 @@ where id: &BlockId, key: &StorageKey, ) -> sp_blockchain::Result> { - Ok(self - .state_at(id)? + self.state_at(id)? .storage_hash(&key.0) - .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } fn child_storage_keys( @@ -1449,10 +1448,9 @@ where child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { - Ok(self - .state_at(id)? + self.state_at(id)? .child_storage_hash(child_info, &key.0) - .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } } diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index 0509e54946e92..d7c83492e563c 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -134,12 +134,12 @@ fn discard_descendants( hash: &BlockHash, ) -> u32 { let (first, mut remainder) = if let Some((first, rest)) = levels.0.split_first_mut() { - (Some(first), (rest, &mut levels.1[..])) + (Some(first), (rest, &mut *levels.1)) } else { if let Some((first, rest)) = levels.1.split_first_mut() { - (Some(first), (&mut levels.0[..], rest)) + (Some(first), (&mut *levels.0, rest)) } else { - (None, (&mut levels.0[..], &mut levels.1[..])) + (None, (&mut *levels.0, &mut *levels.1)) } }; let mut pinned_children = 0; @@ -261,8 +261,7 @@ impl NonCanonicalOverlay { .push((to_meta_key(LAST_CANONICAL, &()), last_canonicalized.encode())); self.last_canonicalized = Some(last_canonicalized); } else if self.last_canonicalized.is_some() { - if number < front_block_number || - number >= front_block_number + self.levels.len() as u64 + 1 + if number < front_block_number || number > front_block_number + self.levels.len() as u64 { trace!(target: "state-db", "Failed to insert block {}, current is {} .. {})", number, diff --git a/client/tracing/proc-macro/src/lib.rs b/client/tracing/proc-macro/src/lib.rs index b1ffcb97b752e..ba757619fb5a0 100644 --- a/client/tracing/proc-macro/src/lib.rs +++ b/client/tracing/proc-macro/src/lib.rs @@ -119,7 +119,7 @@ pub fn prefix_logs_with(arg: TokenStream, item: TokenStream) -> TokenStream { let name = syn::parse_macro_input!(arg as Expr); let crate_name = match crate_name("sc-tracing") { - Ok(FoundCrate::Itself) => Ident::from(Ident::new("sc_tracing", Span::call_site())), + Ok(FoundCrate::Itself) => Ident::new("sc_tracing", Span::call_site()), Ok(FoundCrate::Name(crate_name)) => Ident::new(&crate_name, Span::call_site()), Err(e) => return Error::new(Span::call_site(), e).to_compile_error().into(), }; diff --git a/client/tracing/src/block/mod.rs b/client/tracing/src/block/mod.rs index 8280d4613a189..067cdafa0ae30 100644 --- a/client/tracing/src/block/mod.rs +++ b/client/tracing/src/block/mod.rs @@ -267,7 +267,7 @@ where .lock() .drain() // Patch wasm identifiers - .filter_map(|(_, s)| patch_and_filter(SpanDatum::from(s), targets)) + .filter_map(|(_, s)| patch_and_filter(s, targets)) .collect(); let events: Vec<_> = block_subscriber .events @@ -315,7 +315,7 @@ fn event_values_filter(event: &TraceEvent, filter_kind: &str, values: &str) -> b .values .string_values .get(filter_kind) - .and_then(|value| Some(check_target(values, value, &event.level))) + .map(|value| check_target(values, value, &event.level)) .unwrap_or(false) } diff --git a/client/tracing/src/lib.rs b/client/tracing/src/lib.rs index cbbd8063c34fa..ff3723e0d1a9a 100644 --- a/client/tracing/src/lib.rs +++ b/client/tracing/src/lib.rs @@ -464,7 +464,10 @@ impl From for sp_rpc::tracing::Span { mod tests { use super::*; use parking_lot::Mutex; - use std::sync::Arc; + use std::sync::{ + mpsc::{Receiver, Sender}, + Arc, + }; use tracing_subscriber::layer::SubscriberExt; struct TestTraceHandler { @@ -617,14 +620,14 @@ mod tests { let span1 = tracing::info_span!(target: "test_target", "test_span1"); let _guard1 = span1.enter(); - let (tx, rx) = mpsc::channel(); + let (tx, rx): (Sender, Receiver) = mpsc::channel(); let handle = thread::spawn(move || { let span2 = tracing::info_span!(target: "test_target", "test_span2"); let _guard2 = span2.enter(); // emit event tracing::event!(target: "test_target", tracing::Level::INFO, "test_event1"); for msg in rx.recv() { - if msg == false { + if !msg { break } } diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 909ea559f5527..39be43f82c8b9 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -224,12 +224,8 @@ impl Pool { hashes: &[ExtrinsicHash], ) -> Result<(), B::Error> { // Get details of all extrinsics that are already in the pool - let in_pool_tags = self - .validated_pool - .extrinsics_tags(hashes) - .into_iter() - .filter_map(|x| x) - .flatten(); + let in_pool_tags = + self.validated_pool.extrinsics_tags(hashes).into_iter().flatten().flatten(); // Prune all transactions that provide given tags let prune_status = self.validated_pool.prune_tags(in_pool_tags)?; diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index d5f0a4c1d3392..03f6e753fd475 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -61,17 +61,12 @@ pub mod pallet { pub(super) type NextKeys = StorageValue<_, WeakBoundedVec, ValueQuery>; + #[cfg_attr(feature = "std", derive(Default))] #[pallet::genesis_config] pub struct GenesisConfig { pub keys: Vec, } - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - Self { keys: Default::default() } - } - } #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 6f825e4e7dff9..db453fc57e9e6 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -479,9 +479,9 @@ mod tests { where I: 'a + IntoIterator, { - for (id, data) in digests { + for (id, mut data) in digests { if id == TEST_ID { - return u64::decode(&mut &data[..]).ok() + return u64::decode(&mut data).ok() } } @@ -499,9 +499,9 @@ mod tests { let author = AuthorGiven::find_author(pre_runtime_digests).ok_or_else(|| "no author")?; - for (id, seal) in seals { + for (id, mut seal) in seals { if id == TEST_ID { - match u64::decode(&mut &seal[..]) { + match u64::decode(&mut seal) { Err(_) => return Err("wrong seal"), Ok(a) => { if a != author { diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 424f2df5c16d0..e2cc36ca098fe 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -310,19 +310,13 @@ pub mod pallet { #[pallet::storage] pub(super) type NextEpochConfig = StorageValue<_, BabeEpochConfiguration>; + #[cfg_attr(feature = "std", derive(Default))] #[pallet::genesis_config] pub struct GenesisConfig { pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, pub epoch_config: Option, } - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - GenesisConfig { authorities: Default::default(), epoch_config: Default::default() } - } - } - #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 17844b51d4d5a..aba31b67b2863 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -742,7 +742,7 @@ impl Bag { /// Check if the bag contains a node with `id`. #[cfg(feature = "std")] fn contains(&self, id: &T::AccountId) -> bool { - self.iter().find(|n| n.id() == id).is_some() + self.iter().any(|n| n.id() == id) } } diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index a774cfd61edf5..86e3f2ec05984 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -409,12 +409,7 @@ pub mod pallet { let reducible_balance = Self::reducible_balance(&transactor, keep_alive); let dest = T::Lookup::lookup(dest)?; let keep_alive = if keep_alive { KeepAlive } else { AllowDeath }; - >::transfer( - &transactor, - &dest, - reducible_balance, - keep_alive.into(), - )?; + >::transfer(&transactor, &dest, reducible_balance, keep_alive)?; Ok(()) } @@ -619,7 +614,7 @@ pub enum Reasons { impl From for Reasons { fn from(r: WithdrawReasons) -> Reasons { - if r == WithdrawReasons::from(WithdrawReasons::TRANSACTION_PAYMENT) { + if r == WithdrawReasons::TRANSACTION_PAYMENT { Reasons::Fee } else if r.contains(WithdrawReasons::TRANSACTION_PAYMENT) { Reasons::All diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index 2dbd7ede615d2..28dc3356f7143 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -592,8 +592,7 @@ mod tests { contract: BOB, amount: Deposit::Charge(::Currency::minimum_balance() * 2), terminated: false, - }], - ..Default::default() + }] } ) }); @@ -663,8 +662,7 @@ mod tests { amount: Deposit::Charge(2), terminated: false } - ], - ..Default::default() + ] } ) }); @@ -717,8 +715,7 @@ mod tests { amount: Deposit::Charge(12), terminated: false } - ], - ..Default::default() + ] } ) }); diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index cae68208b31eb..7c9e19f6ef78a 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -1592,7 +1592,7 @@ define_env!(Env, , output_len_ptr: u32 ) -> u32 => { use crate::chain_extension::{ChainExtension, Environment, RetVal}; - if ::ChainExtension::enabled() == false { + if !::ChainExtension::enabled() { Err(Error::::NoChainExtension)?; } let env = Environment::new(ctx, input_ptr, input_len, output_ptr, output_len_ptr); diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 6ce0ddfe67644..da56dd4d073df 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -544,7 +544,7 @@ impl Pallet { // Time to finish. We might have reduced less than expected due to rounding error. Increase // one last time if we have any room left, the reduce until we are sure we are below limit. - while voters + 1 <= max_voters && weight_with(voters + 1) < max_weight { + while voters < max_voters && weight_with(voters + 1) < max_weight { voters += 1; } while voters.checked_sub(1).is_some() && weight_with(voters) > max_weight { diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 06474cd37bbdf..b0e0a6fb984e8 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -836,7 +836,7 @@ impl Pallet { /// Check if `who` is currently an active runner-up. fn is_runner_up(who: &T::AccountId) -> bool { - Self::runners_up().iter().position(|r| &r.who == who).is_some() + Self::runners_up().iter().any(|r| &r.who == who) } /// Get the members' account ids. diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 13c4591be28fd..56e8db6936249 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -738,7 +738,7 @@ where info: &DispatchInfoOf, len: usize, ) -> Result { - Ok(self.validate(who, call, info, len).map(|_| ())?) + self.validate(who, call, info, len).map(|_| ()) } fn validate( diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 560c933f108c1..1f6139cf81fdc 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -327,18 +327,12 @@ pub mod pallet { #[pallet::getter(fn session_for_set)] pub(super) type SetIdSession = StorageMap<_, Twox64Concat, SetId, SessionIndex>; + #[cfg_attr(feature = "std", derive(Default))] #[pallet::genesis_config] pub struct GenesisConfig { pub authorities: AuthorityList, } - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - Self { authorities: Default::default() } - } - } - #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index cab5df9ebe541..288081556a085 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -341,7 +341,7 @@ fn should_not_send_a_report_if_already_online() { UintAuthorityId::set_all_keys(vec![1, 2, 3]); // we expect error, since the authority is already online. let mut res = ImOnline::send_heartbeats(4).unwrap(); - assert_eq!(res.next().unwrap().unwrap(), ()); + res.next().unwrap().unwrap(); assert_eq!(res.next().unwrap().unwrap_err(), OffchainErr::AlreadyOnline(1)); assert_eq!(res.next().unwrap().unwrap_err(), OffchainErr::AlreadyOnline(2)); assert_eq!(res.next(), None); diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index e349d7a1cc9a5..4fef5385eb2c5 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -153,7 +153,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pallet_scored_pool::GenesisConfig:: { pool: vec![(5, None), (10, Some(1)), (20, Some(2)), (31, Some(2)), (40, Some(3))], member_count: 2, - ..Default::default() } .assimilate_storage(&mut t) .unwrap(); diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index cae9a6159b162..7a0783718705a 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -480,11 +480,11 @@ pub mod pallet { let queued_keys: Vec<_> = initial_validators_1 .iter() .cloned() - .filter_map(|v| { - Some(( + .map(|v| { + ( v.clone(), Pallet::::load_keys(&v).expect("Validator in session 1 missing keys!"), - )) + ) }) .collect(); diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index abc90d5186f29..3d2814ad5232b 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -1290,7 +1290,7 @@ fn pick_item<'a, R: RngCore, T>(rng: &mut R, items: &'a [T]) -> Option<&'a T> { } /// Pick a new PRN, in the range [0, `max`] (inclusive). -fn pick_usize<'a, R: RngCore>(rng: &mut R, max: usize) -> usize { +fn pick_usize(rng: &mut R, max: usize) -> usize { (rng.next_u32() % (max as u32 + 1)) as usize } @@ -1316,9 +1316,9 @@ impl, I: 'static> Pallet { // Skip ahead to the suggested position .skip(pos) // Keep skipping ahead until the position changes - .skip_while(|(_, x)| x.value <= bids[pos].value) // Get the element when things changed - .next(); + .find(|(_, x)| x.value > bids[pos].value); + // If the element is not at the end of the list, insert the new element // in the spot. if let Some((p, _)) = different_bid { @@ -1351,7 +1351,7 @@ impl, I: 'static> Pallet { /// Check a user is a bid. fn is_bid(bids: &Vec>>, who: &T::AccountId) -> bool { // Bids are ordered by `value`, so we cannot binary search for a user. - bids.iter().find(|bid| bid.who == *who).is_some() + bids.iter().any(|bid| bid.who == *who) } /// Check a user is a candidate. diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index f6e0526917540..268618fb5f44f 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -412,7 +412,7 @@ impl Default for RewardDestination { } /// Preference of what happens regarding validation. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default)] pub struct ValidatorPrefs { /// Reward that validator takes up-front; only the rest is split between themselves and /// nominators. @@ -424,12 +424,6 @@ pub struct ValidatorPrefs { pub blocked: bool, } -impl Default for ValidatorPrefs { - fn default() -> Self { - ValidatorPrefs { commission: Default::default(), blocked: false } - } -} - /// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct UnlockChunk { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index dcbba63632051..ea2c746ed7177 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -224,7 +224,7 @@ impl Pallet { let dest = Self::payee(stash); match dest { RewardDestination::Controller => Self::bonded(stash) - .and_then(|controller| Some(T::Currency::deposit_creating(&controller, amount))), + .map(|controller| T::Currency::deposit_creating(&controller, amount)), RewardDestination::Stash => T::Currency::deposit_into_existing(stash, amount).ok(), RewardDestination::Staked => Self::bonded(stash) .and_then(|c| Self::ledger(&c).map(|l| (c, l))) @@ -1160,7 +1160,7 @@ where add_db_reads_writes(1, 0); // Reverse because it's more likely to find reports from recent eras. - match eras.iter().rev().filter(|&&(_, ref sesh)| sesh <= &slash_session).next() { + match eras.iter().rev().find(|&&(_, ref sesh)| sesh <= &slash_session) { Some(&(ref slash_era, _)) => *slash_era, // Before bonding period. defensive - should be filtered out. None => return consumed_weight, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 7990245068f9c..8d465c8c93dc4 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2262,7 +2262,7 @@ fn slash_in_old_span_does_not_deselect() { ); // the validator doesn't get chilled again - assert!(::Validators::iter().find(|(stash, _)| *stash == 11).is_some()); + assert!(::Validators::iter().any(|(stash, _)| stash == 11)); // but we are still forcing a new era assert_eq!(Staking::force_era(), Forcing::ForceNew); @@ -2279,7 +2279,7 @@ fn slash_in_old_span_does_not_deselect() { ); // the validator doesn't get chilled again - assert!(::Validators::iter().find(|(stash, _)| *stash == 11).is_some()); + assert!(::Validators::iter().any(|(stash, _)| stash == 11)); // but it's disabled assert!(is_disabled(10)); @@ -4003,8 +4003,7 @@ mod election_data_provider { assert!(>::iter().map(|(x, _)| x).all(|v| Staking::voters(None) .unwrap() .into_iter() - .find(|(w, _, t)| { v == *w && t[0] == *w }) - .is_some())) + .any(|(w, _, t)| { v == w && t[0] == w }))) }) } diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index ca48c568e158a..effe0ce6c55d8 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -704,11 +704,11 @@ impl StorageDef { }) .unwrap_or(Some(QueryKind::OptionQuery)); // This value must match the default generic. - if query_kind.is_none() && getter.is_some() { + if let (None, Some(getter)) = (query_kind.as_ref(), getter.as_ref()) { let msg = "Invalid pallet::storage, cannot generate getter because QueryKind is not \ identifiable. QueryKind must be `OptionQuery`, `ValueQuery`, or default one to be \ identifiable."; - return Err(syn::Error::new(getter.unwrap().span(), msg)) + return Err(syn::Error::new(getter.span(), msg)) } Ok(StorageDef { diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 765fb5d9d7c35..b5f4ab97767c2 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -1546,7 +1546,7 @@ macro_rules! decl_module { ::current_storage_version(), ); - (|| { $( $impl )* })() + { $( $impl )* } } #[cfg(feature = "try-runtime")] diff --git a/frame/support/src/storage/migration.rs b/frame/support/src/storage/migration.rs index b2339efd0d204..713c2b0f3fe01 100644 --- a/frame/support/src/storage/migration.rs +++ b/frame/support/src/storage/migration.rs @@ -181,8 +181,8 @@ pub fn storage_iter_with_suffix( prefix.extend_from_slice(&storage_prefix); prefix.extend_from_slice(suffix); let previous_key = prefix.clone(); - let closure = |raw_key_without_prefix: &[u8], raw_value: &[u8]| { - let value = T::decode(&mut &raw_value[..])?; + let closure = |raw_key_without_prefix: &[u8], mut raw_value: &[u8]| { + let value = T::decode(&mut raw_value)?; Ok((raw_key_without_prefix.to_vec(), value)) }; @@ -213,10 +213,10 @@ pub fn storage_key_iter_with_suffix< prefix.extend_from_slice(&storage_prefix); prefix.extend_from_slice(suffix); let previous_key = prefix.clone(); - let closure = |raw_key_without_prefix: &[u8], raw_value: &[u8]| { + let closure = |raw_key_without_prefix: &[u8], mut raw_value: &[u8]| { let mut key_material = H::reverse(raw_key_without_prefix); let key = K::decode(&mut key_material)?; - let value = T::decode(&mut &raw_value[..])?; + let value = T::decode(&mut raw_value)?; Ok((key, value)) }; PrefixIterator { prefix, previous_key, drain: false, closure, phantom: Default::default() } diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index d79ddf09b7cc7..04876895dc490 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -1018,8 +1018,8 @@ impl ChildTriePrefixIterator<(Vec, T)> { pub fn with_prefix(child_info: &ChildInfo, prefix: &[u8]) -> Self { let prefix = prefix.to_vec(); let previous_key = prefix.clone(); - let closure = |raw_key_without_prefix: &[u8], raw_value: &[u8]| { - let value = T::decode(&mut &raw_value[..])?; + let closure = |raw_key_without_prefix: &[u8], mut raw_value: &[u8]| { + let value = T::decode(&mut raw_value)?; Ok((raw_key_without_prefix.to_vec(), value)) }; @@ -1045,10 +1045,10 @@ impl ChildTriePrefixIterator<(K, T)> { ) -> Self { let prefix = prefix.to_vec(); let previous_key = prefix.clone(); - let closure = |raw_key_without_prefix: &[u8], raw_value: &[u8]| { + let closure = |raw_key_without_prefix: &[u8], mut raw_value: &[u8]| { let mut key_material = H::reverse(raw_key_without_prefix); let key = K::decode(&mut key_material)?; - let value = T::decode(&mut &raw_value[..])?; + let value = T::decode(&mut raw_value)?; Ok((key, value)) }; diff --git a/frame/support/test/pallet/src/lib.rs b/frame/support/test/pallet/src/lib.rs index bd181ea5b81bf..25741313c2a03 100644 --- a/frame/support/test/pallet/src/lib.rs +++ b/frame/support/test/pallet/src/lib.rs @@ -30,15 +30,9 @@ pub mod pallet { pub trait Config: frame_system::Config {} #[pallet::genesis_config] + #[cfg_attr(feature = "std", derive(Default))] pub struct GenesisConfig {} - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - Self {} - } - } - #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) {} diff --git a/frame/support/test/tests/genesisconfig.rs b/frame/support/test/tests/genesisconfig.rs index 7895e863fd826..367c7236d0158 100644 --- a/frame/support/test/tests/genesisconfig.rs +++ b/frame/support/test/tests/genesisconfig.rs @@ -40,5 +40,5 @@ impl Config for Test {} #[test] fn init_genesis_config() { - GenesisConfig:: { t: Default::default() }; + GenesisConfig::::default(); } diff --git a/frame/support/test/tests/issue2219.rs b/frame/support/test/tests/issue2219.rs index 196068ac2fa4a..d7e3d2cb5b135 100644 --- a/frame/support/test/tests/issue2219.rs +++ b/frame/support/test/tests/issue2219.rs @@ -184,7 +184,9 @@ frame_support::construct_runtime!( #[test] fn create_genesis_config() { - GenesisConfig { + let config = GenesisConfig { module: module::GenesisConfig { request_life_time: 0, enable_storage_role: true }, }; + assert_eq!(config.module.request_life_time, 0); + assert!(config.module.enable_storage_role); } diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 1e923a6fdd6ec..59b581eda58e4 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -881,7 +881,7 @@ fn pallet_expand_deposit_event() { #[test] fn pallet_new_call_variant() { - Call::Example(pallet::Call::new_call_variant_foo(3, 4)); + pallet::Call::::new_call_variant_foo(3, 4); } #[test] diff --git a/frame/system/src/extensions/check_genesis.rs b/frame/system/src/extensions/check_genesis.rs index 4b52691a6d328..a0679b11487f6 100644 --- a/frame/system/src/extensions/check_genesis.rs +++ b/frame/system/src/extensions/check_genesis.rs @@ -70,6 +70,6 @@ impl SignedExtension for CheckGenesis { info: &DispatchInfoOf, len: usize, ) -> Result { - Ok(self.validate(who, call, info, len).map(|_| ())?) + self.validate(who, call, info, len).map(|_| ()) } } diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index ed11c37598362..2fb99c9f45e2b 100644 --- a/frame/system/src/extensions/check_mortality.rs +++ b/frame/system/src/extensions/check_mortality.rs @@ -93,7 +93,7 @@ impl SignedExtension for CheckMortality { info: &DispatchInfoOf, len: usize, ) -> Result { - Ok(self.validate(who, call, info, len).map(|_| ())?) + self.validate(who, call, info, len).map(|_| ()) } } diff --git a/frame/system/src/extensions/check_non_zero_sender.rs b/frame/system/src/extensions/check_non_zero_sender.rs index 5910a865a7766..f517201fbebc2 100644 --- a/frame/system/src/extensions/check_non_zero_sender.rs +++ b/frame/system/src/extensions/check_non_zero_sender.rs @@ -72,7 +72,7 @@ where info: &DispatchInfoOf, len: usize, ) -> Result { - Ok(self.validate(who, call, info, len).map(|_| ())?) + self.validate(who, call, info, len).map(|_| ()) } fn validate( diff --git a/frame/system/src/extensions/check_spec_version.rs b/frame/system/src/extensions/check_spec_version.rs index dce70a940765a..0280d31f657ae 100644 --- a/frame/system/src/extensions/check_spec_version.rs +++ b/frame/system/src/extensions/check_spec_version.rs @@ -70,6 +70,6 @@ impl SignedExtension for CheckSpecVersion { info: &DispatchInfoOf, len: usize, ) -> Result { - Ok(self.validate(who, call, info, len).map(|_| ())?) + self.validate(who, call, info, len).map(|_| ()) } } diff --git a/frame/system/src/extensions/check_tx_version.rs b/frame/system/src/extensions/check_tx_version.rs index 69060729cccc3..b92d8978bde01 100644 --- a/frame/system/src/extensions/check_tx_version.rs +++ b/frame/system/src/extensions/check_tx_version.rs @@ -69,6 +69,6 @@ impl SignedExtension for CheckTxVersion { info: &DispatchInfoOf, len: usize, ) -> Result { - Ok(self.validate(who, call, info, len).map(|_| ())?) + self.validate(who, call, info, len).map(|_| ()) } } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 80d2934914691..cec45a8aa1cb1 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -637,19 +637,13 @@ pub mod pallet { #[pallet::storage] pub(super) type ExecutionPhase = StorageValue<_, Phase>; + #[cfg_attr(feature = "std", derive(Default))] #[pallet::genesis_config] pub struct GenesisConfig { #[serde(with = "sp_core::bytes")] pub code: Vec, } - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - Self { code: Default::default() } - } - } - #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 0e0dc413a01a3..293140d5eda1a 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -39,7 +39,7 @@ fn assets() -> Vec<(u64, u32, u32)> { Some(Some(item)) } }) - .filter_map(|item| item) + .flatten() { let details = Class::::get(class).unwrap(); let instances = Asset::::iter_prefix(class).count() as u32; diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index fcad0c57f937d..c823bccf38b1b 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -572,14 +572,13 @@ impl Pallet { let mut total_locked_now: BalanceOf = Zero::zero(); let filtered_schedules = action .pick_schedules::(schedules) - .filter_map(|schedule| { + .filter(|schedule| { let locked_now = schedule.locked_at::(now); - if locked_now.is_zero() { - None - } else { + let keep = !locked_now.is_zero(); + if keep { total_locked_now = total_locked_now.saturating_add(locked_now); - Some(schedule) } + keep }) .collect::>(); diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index 6c6b8f453a267..8d90b09d0e8c0 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -235,9 +235,7 @@ fn generate_native_call_generators(decl: &ItemTrait) -> Result { // compatible. To ensure that we forward it by ref/value, we use the value given by the // the user. Otherwise if it is not using the block, we don't need to add anything. let input_borrows = - params - .iter() - .map(|v| if type_is_using_block(&v.1) { v.2.clone() } else { None }); + params.iter().map(|v| if type_is_using_block(&v.1) { v.2 } else { None }); // Replace all `Block` with `NodeBlock`, add `'a` lifetime to references and collect // all the function inputs. @@ -380,7 +378,6 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result { // Generate the generator function result.push(quote!( #[cfg(any(feature = "std", test))] - #[allow(clippy::too_many_arguments)] pub fn #fn_name< R: #crate_::Encode + #crate_::Decode + PartialEq, NC: FnOnce() -> std::result::Result + std::panic::UnwindSafe, diff --git a/primitives/authorship/src/lib.rs b/primitives/authorship/src/lib.rs index 25eaeaf9bc16d..7ea19d9ea5ff5 100644 --- a/primitives/authorship/src/lib.rs +++ b/primitives/authorship/src/lib.rs @@ -88,13 +88,13 @@ impl sp_inherents::InherentDataProvider for InherentDataProvider async fn try_handle_error( &self, identifier: &InherentIdentifier, - error: &[u8], + mut error: &[u8], ) -> Option> { if *identifier != INHERENT_IDENTIFIER { return None } - let error = InherentError::decode(&mut &error[..]).ok()?; + let error = InherentError::decode(&mut error).ok()?; Some(Err(Error::Application(Box::from(format!("{:?}", error))))) } diff --git a/primitives/debug-derive/src/impls.rs b/primitives/debug-derive/src/impls.rs index bab0146e46824..060997fe97821 100644 --- a/primitives/debug-derive/src/impls.rs +++ b/primitives/debug-derive/src/impls.rs @@ -101,7 +101,7 @@ mod implementation { } } - fn derive_fields<'a>(name_str: &str, fields: Fields) -> TokenStream { + fn derive_fields(name_str: &str, fields: Fields) -> TokenStream { match fields { Fields::Named { names, this } => { let names_str: Vec<_> = names.iter().map(|x| x.to_string()).collect(); diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index eb5847207daaf..2723b743c10db 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -482,9 +482,7 @@ mod tests { assert!(res.is_none()); // insert key, sign again - let res = - SyncCryptoStore::insert_unknown(&store, ECDSA, suri, pair.public().as_ref()).unwrap(); - assert_eq!((), res); + SyncCryptoStore::insert_unknown(&store, ECDSA, suri, pair.public().as_ref()).unwrap(); let res = SyncCryptoStore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap(); diff --git a/primitives/npos-elections/fuzzer/src/compact.rs b/primitives/npos-elections/fuzzer/src/compact.rs index 4e78c94b82572..595048575d99c 100644 --- a/primitives/npos-elections/fuzzer/src/compact.rs +++ b/primitives/npos-elections/fuzzer/src/compact.rs @@ -11,7 +11,7 @@ fn main() { loop { fuzz!(|fuzzer_data: &[u8]| { let result_decoded: Result = - ::decode(&mut &fuzzer_data[..]); + ::decode(&mut &*fuzzer_data); // Ignore errors as not every random sequence of bytes can be decoded as // InnerTestSolutionCompact if let Ok(decoded) = result_decoded { diff --git a/primitives/npos-elections/fuzzer/src/reduce.rs b/primitives/npos-elections/fuzzer/src/reduce.rs index 029bb18dc5b30..ad3f7dc260ef5 100644 --- a/primitives/npos-elections/fuzzer/src/reduce.rs +++ b/primitives/npos-elections/fuzzer/src/reduce.rs @@ -90,7 +90,7 @@ fn generate_random_phragmen_assignment( .map(|_| { let target = targets_to_chose_from.remove(rng.gen_range(0, targets_to_chose_from.len())); - if winners.iter().find(|w| **w == target).is_none() { + if winners.iter().all(|w| *w != target) { winners.push(target.clone()); } (target, rng.gen_range(1 * KSM, 100 * KSM)) diff --git a/primitives/npos-elections/src/reduce.rs b/primitives/npos-elections/src/reduce.rs index 057ee339bd7d3..f089a37e3fff3 100644 --- a/primitives/npos-elections/src/reduce.rs +++ b/primitives/npos-elections/src/reduce.rs @@ -275,9 +275,8 @@ fn reduce_4(assignments: &mut Vec>) -> u32 { }); // remove either one of them. - let who_removed = remove_indices.iter().find(|i| **i < 2usize).is_some(); - let other_removed = - remove_indices.into_iter().find(|i| *i >= 2usize).is_some(); + let who_removed = remove_indices.iter().any(|i| *i < 2usize); + let other_removed = remove_indices.into_iter().any(|i| i >= 2usize); match (who_removed, other_removed) { (false, true) => { diff --git a/primitives/runtime-interface/test/src/lib.rs b/primitives/runtime-interface/test/src/lib.rs index 785215b87421b..e76f54f69a808 100644 --- a/primitives/runtime-interface/test/src/lib.rs +++ b/primitives/runtime-interface/test/src/lib.rs @@ -62,17 +62,17 @@ fn call_wasm_method(binary: &[u8], method: &str) -> TestExte #[test] fn test_return_data() { - call_wasm_method::(&wasm_binary_unwrap()[..], "test_return_data"); + call_wasm_method::(wasm_binary_unwrap(), "test_return_data"); } #[test] fn test_return_option_data() { - call_wasm_method::(&wasm_binary_unwrap()[..], "test_return_option_data"); + call_wasm_method::(wasm_binary_unwrap(), "test_return_option_data"); } #[test] fn test_set_storage() { - let mut ext = call_wasm_method::(&wasm_binary_unwrap()[..], "test_set_storage"); + let mut ext = call_wasm_method::(wasm_binary_unwrap(), "test_set_storage"); let expected = "world"; assert_eq!(expected.as_bytes(), &ext.ext().storage("hello".as_bytes()).unwrap()[..]); @@ -81,30 +81,30 @@ fn test_set_storage() { #[test] fn test_return_value_into_mutable_reference() { call_wasm_method::( - &wasm_binary_unwrap()[..], + wasm_binary_unwrap(), "test_return_value_into_mutable_reference", ); } #[test] fn test_get_and_return_array() { - call_wasm_method::(&wasm_binary_unwrap()[..], "test_get_and_return_array"); + call_wasm_method::(wasm_binary_unwrap(), "test_get_and_return_array"); } #[test] fn test_array_as_mutable_reference() { - call_wasm_method::(&wasm_binary_unwrap()[..], "test_array_as_mutable_reference"); + call_wasm_method::(wasm_binary_unwrap(), "test_array_as_mutable_reference"); } #[test] fn test_return_input_public_key() { - call_wasm_method::(&wasm_binary_unwrap()[..], "test_return_input_public_key"); + call_wasm_method::(wasm_binary_unwrap(), "test_return_input_public_key"); } #[test] fn host_function_not_found() { - let err = call_wasm_method_with_result::<()>(&wasm_binary_unwrap()[..], "test_return_data") - .unwrap_err(); + let err = + call_wasm_method_with_result::<()>(wasm_binary_unwrap(), "test_return_data").unwrap_err(); assert!(err.contains("Instantiation: Export ")); assert!(err.contains(" not found")); @@ -114,7 +114,7 @@ fn host_function_not_found() { #[should_panic(expected = "Invalid utf8 data provided")] fn test_invalid_utf8_data_should_return_an_error() { call_wasm_method::( - &wasm_binary_unwrap()[..], + wasm_binary_unwrap(), "test_invalid_utf8_data_should_return_an_error", ); } @@ -122,7 +122,7 @@ fn test_invalid_utf8_data_should_return_an_error() { #[test] fn test_overwrite_native_function_implementation() { call_wasm_method::( - &wasm_binary_unwrap()[..], + wasm_binary_unwrap(), "test_overwrite_native_function_implementation", ); } @@ -130,7 +130,7 @@ fn test_overwrite_native_function_implementation() { #[test] fn test_u128_i128_as_parameter_and_return_value() { call_wasm_method::( - &wasm_binary_unwrap()[..], + wasm_binary_unwrap(), "test_u128_i128_as_parameter_and_return_value", ); } @@ -138,7 +138,7 @@ fn test_u128_i128_as_parameter_and_return_value() { #[test] fn test_vec_return_value_memory_is_freed() { call_wasm_method::( - &wasm_binary_unwrap()[..], + wasm_binary_unwrap(), "test_vec_return_value_memory_is_freed", ); } @@ -146,7 +146,7 @@ fn test_vec_return_value_memory_is_freed() { #[test] fn test_encoded_return_value_memory_is_freed() { call_wasm_method::( - &wasm_binary_unwrap()[..], + wasm_binary_unwrap(), "test_encoded_return_value_memory_is_freed", ); } @@ -154,7 +154,7 @@ fn test_encoded_return_value_memory_is_freed() { #[test] fn test_array_return_value_memory_is_freed() { call_wasm_method::( - &wasm_binary_unwrap()[..], + wasm_binary_unwrap(), "test_array_return_value_memory_is_freed", ); } @@ -162,14 +162,11 @@ fn test_array_return_value_memory_is_freed() { #[test] fn test_versionining_with_new_host_works() { // We call to the new wasm binary with new host function. - call_wasm_method::(&wasm_binary_unwrap()[..], "test_versionning_works"); + call_wasm_method::(wasm_binary_unwrap(), "test_versionning_works"); // we call to the old wasm binary with a new host functions // old versions of host functions should be called and test should be ok! - call_wasm_method::( - &wasm_binary_deprecated_unwrap()[..], - "test_versionning_works", - ); + call_wasm_method::(wasm_binary_deprecated_unwrap(), "test_versionning_works"); } #[test] @@ -224,7 +221,7 @@ fn test_tracing() { let _guard = tracing::subscriber::set_default(subscriber.clone()); // Call some method to generate a trace - call_wasm_method::(&wasm_binary_unwrap()[..], "test_return_data"); + call_wasm_method::(wasm_binary_unwrap(), "test_return_data"); let inner = subscriber.0.lock().unwrap(); assert!(inner.spans.contains("return_input_version_1")); @@ -232,5 +229,5 @@ fn test_tracing() { #[test] fn test_return_input_as_tuple() { - call_wasm_method::(&wasm_binary_unwrap()[..], "test_return_input_as_tuple"); + call_wasm_method::(wasm_binary_unwrap(), "test_return_input_as_tuple"); } diff --git a/primitives/runtime/src/generic/digest.rs b/primitives/runtime/src/generic/digest.rs index ca1daabb06d29..f3cb7b99efb61 100644 --- a/primitives/runtime/src/generic/digest.rs +++ b/primitives/runtime/src/generic/digest.rs @@ -33,19 +33,13 @@ use crate::{ use sp_core::RuntimeDebug; /// Generic header digest. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, parity_util_mem::MallocSizeOf))] pub struct Digest { /// A list of logs in the digest. pub logs: Vec, } -impl Default for Digest { - fn default() -> Self { - Self { logs: Vec::new() } - } -} - impl Digest { /// Get reference to all digest items. pub fn logs(&self) -> &[DigestItem] { diff --git a/primitives/runtime/src/generic/unchecked_extrinsic.rs b/primitives/runtime/src/generic/unchecked_extrinsic.rs index d919a67095d3a..d444d0352d5ae 100644 --- a/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -395,7 +395,7 @@ mod tests { info: &DispatchInfoOf, len: usize, ) -> Result { - Ok(self.validate(who, call, info, len).map(|_| ())?) + self.validate(who, call, info, len).map(|_| ()) } } diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 84c35597b4b1b..b2e218cb9db73 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1074,7 +1074,7 @@ impl SignedExtension for () { info: &DispatchInfoOf, len: usize, ) -> Result { - Ok(self.validate(who, call, info, len).map(|_| ())?) + self.validate(who, call, info, len).map(|_| ()) } } diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index 215caaa17f302..8d0ac2d1369c9 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -208,7 +208,7 @@ pub trait Backend: sp_std::fmt::Debug { } let (root, parent_txs) = self.storage_root( delta - .map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..]))) + .map(|(k, v)| (k, v.as_ref().map(|v| &v[..]))) .chain(child_roots.iter().map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..])))), state_version, ); diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index 93e6ac6e5c530..e87b22d4f9b76 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -581,7 +581,7 @@ where target: "state", method = "ChildStorageRoot", ext_id = %HexDisplay::from(&self.id.to_le_bytes()), - child_info = %HexDisplay::from(&storage_key.as_ref()), + child_info = %HexDisplay::from(&storage_key), storage_root = %HexDisplay::from(&root.as_ref()), cached = false, ); @@ -599,7 +599,7 @@ where target: "state", method = "ChildStorageRoot", ext_id = %HexDisplay::from(&self.id.to_le_bytes()), - child_info = %HexDisplay::from(&storage_key.as_ref()), + child_info = %HexDisplay::from(&storage_key), storage_root = %HexDisplay::from(&root.as_ref()), cached = false, ); diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index e21644614c83c..6be601aa72b34 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -203,7 +203,7 @@ where /// /// This implementation will wipe the proof recorded in between calls. Consecutive calls will /// get their own proof from scratch. - pub fn execute_and_prove<'a, R>(&mut self, execute: impl FnOnce() -> R) -> (R, StorageProof) { + pub fn execute_and_prove(&mut self, execute: impl FnOnce() -> R) -> (R, StorageProof) { let proving_backend = InMemoryProvingBackend::new(&self.backend); let mut proving_ext = Ext::new( &mut self.overlay, diff --git a/primitives/timestamp/src/lib.rs b/primitives/timestamp/src/lib.rs index 9155cbd93b6c5..76725e28ac825 100644 --- a/primitives/timestamp/src/lib.rs +++ b/primitives/timestamp/src/lib.rs @@ -138,9 +138,9 @@ impl IsFatalError for InherentError { impl InherentError { /// Try to create an instance ouf of the given identifier and data. #[cfg(feature = "std")] - pub fn try_from(id: &InherentIdentifier, data: &[u8]) -> Option { + pub fn try_from(id: &InherentIdentifier, mut data: &[u8]) -> Option { if id == &INHERENT_IDENTIFIER { - ::decode(&mut &data[..]).ok() + ::decode(&mut data).ok() } else { None } @@ -227,7 +227,7 @@ impl sp_inherents::InherentDataProvider for InherentDataProvider { &self, inherent_data: &mut InherentData, ) -> Result<(), sp_inherents::Error> { - inherent_data.put_data(INHERENT_IDENTIFIER, &InherentType::from(self.timestamp)) + inherent_data.put_data(INHERENT_IDENTIFIER, &self.timestamp) } async fn try_handle_error( diff --git a/primitives/transaction-storage-proof/src/lib.rs b/primitives/transaction-storage-proof/src/lib.rs index bdfe16683ebc2..2e5aa3b2b9c71 100644 --- a/primitives/transaction-storage-proof/src/lib.rs +++ b/primitives/transaction-storage-proof/src/lib.rs @@ -67,7 +67,7 @@ pub trait TransactionStorageProofInherentData { impl TransactionStorageProofInherentData for InherentData { fn storage_proof(&self) -> Result, Error> { - Ok(self.get_data(&INHERENT_IDENTIFIER)?) + self.get_data(&INHERENT_IDENTIFIER) } } @@ -98,13 +98,13 @@ impl sp_inherents::InherentDataProvider for InherentDataProvider { async fn try_handle_error( &self, identifier: &InherentIdentifier, - error: &[u8], + mut error: &[u8], ) -> Option> { if *identifier != INHERENT_IDENTIFIER { return None } - let error = InherentError::decode(&mut &error[..]).ok()?; + let error = InherentError::decode(&mut error).ok()?; Some(Err(Error::Application(Box::from(format!("{:?}", error))))) } diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index ffaee2037d1c9..f598615be9098 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -281,7 +281,7 @@ where L: TrieConfiguration, DB: hash_db::HashDBRef, { - Ok(TrieDB::::new(&*db, root)?.get(key).map(|x| x.map(|val| val.to_vec()))?) + TrieDB::::new(&*db, root)?.get(key).map(|x| x.map(|val| val.to_vec())) } /// Read a value from the trie with given Query. @@ -296,9 +296,9 @@ where Q: Query, DB: hash_db::HashDBRef, { - Ok(TrieDB::::new(&*db, root)? + TrieDB::::new(&*db, root)? .get_with(key, query) - .map(|x| x.map(|val| val.to_vec()))?) + .map(|x| x.map(|val| val.to_vec())) } /// Determine the empty trie root. diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index c6112db2374e0..b03998621b31f 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -665,13 +665,7 @@ fn code_using_trie() -> u64 { if let Ok(trie) = TrieDB::::new(&mdb, &root) { if let Ok(iter) = trie.iter() { - let mut iter_pairs = Vec::new(); - for pair in iter { - if let Ok((key, value)) = pair { - iter_pairs.push((key, value.to_vec())); - } - } - iter_pairs.len() as u64 + iter.flatten().count() as u64 } else { 102 } diff --git a/utils/frame/benchmarking-cli/src/command.rs b/utils/frame/benchmarking-cli/src/command.rs index 94e1e0c8c1b88..bd103862fe2c3 100644 --- a/utils/frame/benchmarking-cli/src/command.rs +++ b/utils/frame/benchmarking-cli/src/command.rs @@ -176,9 +176,7 @@ impl BenchmarkCmd { .filter(|item| pallet.is_empty() || pallet == &b"*"[..] || pallet == &item.pallet[..]) .for_each(|item| { for benchmark in &item.benchmarks { - if extrinsic.is_empty() || - &extrinsic[..] == &b"*"[..] || - extrinsic == benchmark.name + if extrinsic.is_empty() || extrinsic == &b"*"[..] || extrinsic == benchmark.name { benchmarks_to_run.push(( item.pallet.clone(), diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 2cd0a18909c19..32c814b0443d0 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -496,7 +496,6 @@ impl State { state_snapshot: snapshot_path.as_ref().map(SnapshotConfig::new), pallets: pallets.clone().unwrap_or_default(), at, - ..Default::default() })) .inject_hashed_key( &[twox_128(b"System"), twox_128(b"LastRuntimeUpgrade")].concat(), diff --git a/utils/frame/try-runtime/cli/src/parse.rs b/utils/frame/try-runtime/cli/src/parse.rs index a12e37344c7a3..15a0251ebc34a 100644 --- a/utils/frame/try-runtime/cli/src/parse.rs +++ b/utils/frame/try-runtime/cli/src/parse.rs @@ -18,8 +18,11 @@ //! Utils for parsing user input pub(crate) fn hash(block_hash: &str) -> Result { - let (block_hash, offset) = - if block_hash.starts_with("0x") { (&block_hash[2..], 2) } else { (block_hash, 0) }; + let (block_hash, offset) = if let Some(block_hash) = block_hash.strip_prefix("0x") { + (block_hash, 2) + } else { + (block_hash, 0) + }; if let Some(pos) = block_hash.chars().position(|c| !c.is_ascii_hexdigit()) { Err(format!( From e4d7a24536f782a5e6410bdbd3a762facdf17c56 Mon Sep 17 00:00:00 2001 From: Robert Klotzner Date: Wed, 5 Jan 2022 17:02:32 +0100 Subject: [PATCH 0398/1472] Warn on chain selection error. (#10587) At least for Polkadot, this should not result in spam and a warning will very likely indicate some serious issue. --- client/finality-grandpa/src/environment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index bbd739086ba51..81bb24f1a5eed 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -1224,7 +1224,7 @@ where .or_else(|| Some((target_header.hash(), *target_header.number()))) }, Err(e) => { - debug!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e); + warn!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e); None }, }; From 0f070c8020fad552247fd4b43c1a6a4506e456b5 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 5 Jan 2022 19:01:44 +0200 Subject: [PATCH 0399/1472] Name changes for GrandPa and Beefy notifications protocols (#10463) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * grandpa: update notif protocol name * grandpa: add chain id prefix to protocol name * grandpa: beautify protocol name handling * grandpa: prepend genesis hash to protocol name * chain-spec: add optional 'fork_id' 'fork_id' is used to uniquely identify forks of the same chain/network 'ChainSpec' trait provides default 'None' implementation, meaning this chain hasn't been forked. * grandpa: protocol_name mod instead of struct * beefy: add genesis hash prefix to protocol name * chainspec: add fork_id * grandpa: simplify protocol name * grandpa: contain protocol name building logic * beefy: contain protocol name building logic * grandpa: fix tests * fix merge damage * fix docs reference visibility Signed-off-by: acatangiu * Update client/finality-grandpa/src/lib.rs Co-authored-by: Tomasz Drwięga * Update client/finality-grandpa/src/communication/mod.rs Co-authored-by: Tomasz Drwięga * Update client/beefy/src/lib.rs Co-authored-by: Tomasz Drwięga * Update client/beefy/src/lib.rs Co-authored-by: Tomasz Drwięga * avoid using hash default, even for protocol names Co-authored-by: Tomasz Drwięga --- Cargo.lock | 2 + bin/node-template/node/src/chain_spec.rs | 2 + bin/node-template/node/src/service.rs | 12 +++++- bin/node/cli/src/chain_spec.rs | 5 +++ bin/node/cli/src/service.rs | 10 ++++- bin/utils/chain-spec-builder/src/main.rs | 1 + client/beefy/Cargo.toml | 1 + client/beefy/src/lib.rs | 41 +++++++++++++++---- client/chain-spec/src/chain_spec.rs | 12 ++++++ client/chain-spec/src/lib.rs | 2 + client/cli/src/commands/insert_key.rs | 1 + client/finality-grandpa/Cargo.toml | 1 + .../src/communication/gossip.rs | 40 +++++++++--------- .../finality-grandpa/src/communication/mod.rs | 27 ++++++++++-- .../src/communication/tests.rs | 20 +++++---- client/finality-grandpa/src/lib.rs | 13 ++++-- client/finality-grandpa/src/tests.rs | 14 ++++++- client/network/src/config.rs | 7 ++++ 18 files changed, 164 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cdd2d0d11e459..16a24f284dc4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -481,6 +481,7 @@ dependencies = [ "log 0.4.14", "parity-scale-codec", "parking_lot 0.11.2", + "sc-chain-spec", "sc-client-api", "sc-keystore", "sc-network", @@ -8159,6 +8160,7 @@ dependencies = [ "parking_lot 0.11.2", "rand 0.8.4", "sc-block-builder", + "sc-chain-spec", "sc-client-api", "sc-consensus", "sc-keystore", diff --git a/bin/node-template/node/src/chain_spec.rs b/bin/node-template/node/src/chain_spec.rs index af94a63335e0e..ef34ec369a77f 100644 --- a/bin/node-template/node/src/chain_spec.rs +++ b/bin/node-template/node/src/chain_spec.rs @@ -68,6 +68,7 @@ pub fn development_config() -> Result { None, // Protocol ID None, + None, // Properties None, // Extensions @@ -117,6 +118,7 @@ pub fn local_testnet_config() -> Result { None, // Properties None, + None, // Extensions None, )) diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 975a491cf4da1..4395718a6d680 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -1,7 +1,7 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. use node_template_runtime::{self, opaque::Block, RuntimeApi}; -use sc_client_api::ExecutorProvider; +use sc_client_api::{BlockBackend, ExecutorProvider}; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; pub use sc_executor::NativeElseWasmExecutor; use sc_finality_grandpa::SharedVoterState; @@ -180,8 +180,15 @@ pub fn new_full(mut config: Configuration) -> Result ))), }; } + let grandpa_protocol_name = sc_finality_grandpa::protocol_standard_name( + &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), + &config.chain_spec, + ); - config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config()); + config + .network + .extra_sets + .push(sc_finality_grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone())); let warp_sync = Arc::new(sc_finality_grandpa::warp_proof::NetworkProvider::new( backend.clone(), grandpa_link.shared_authority_set().clone(), @@ -306,6 +313,7 @@ pub fn new_full(mut config: Configuration) -> Result keystore, local_role: role, telemetry: telemetry.as_ref().map(|x| x.handle()), + protocol_name: grandpa_protocol_name, }; if enable_grandpa { diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 4d5054113ea0d..747bc71c5007c 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -196,6 +196,7 @@ pub fn staging_testnet_config() -> ChainSpec { ), None, None, + None, Default::default(), ) } @@ -386,6 +387,7 @@ pub fn development_config() -> ChainSpec { None, None, None, + None, Default::default(), ) } @@ -410,6 +412,7 @@ pub fn local_testnet_config() -> ChainSpec { None, None, None, + None, Default::default(), ) } @@ -441,6 +444,7 @@ pub(crate) mod tests { None, None, None, + None, Default::default(), ) } @@ -456,6 +460,7 @@ pub(crate) mod tests { None, None, None, + None, Default::default(), ) } diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index c899975c850c5..81c68bf5d3aa7 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -326,8 +326,15 @@ pub fn new_full_base( let shared_voter_state = rpc_setup; let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht; + let grandpa_protocol_name = grandpa::protocol_standard_name( + &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), + &config.chain_spec, + ); - config.network.extra_sets.push(grandpa::grandpa_peers_set_config()); + config + .network + .extra_sets + .push(grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone())); let warp_sync = Arc::new(grandpa::warp_proof::NetworkProvider::new( backend.clone(), import_setup.1.shared_authority_set().clone(), @@ -488,6 +495,7 @@ pub fn new_full_base( keystore, local_role: role, telemetry: telemetry.as_ref().map(|x| x.handle()), + protocol_name: grandpa_protocol_name, }; if enable_grandpa { diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index bf58f3110170c..013fbeccfe0d7 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -155,6 +155,7 @@ fn generate_chain_spec( None, None, None, + None, Default::default(), ); diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 6c281deb85ea1..d57d053c16f42 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -26,6 +26,7 @@ sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 59a5ff08e16ea..7d2c3b57b1f70 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -39,15 +39,40 @@ mod round; mod worker; pub mod notification; - -pub const BEEFY_PROTOCOL_NAME: &str = "/paritytech/beefy/1"; +pub use beefy_protocol_name::standard_name as protocol_standard_name; + +pub(crate) mod beefy_protocol_name { + use sc_chain_spec::ChainSpec; + + const NAME: &'static str = "/beefy/1"; + /// Old names for the notifications protocol, used for backward compatibility. + pub(crate) const LEGACY_NAMES: [&'static str; 1] = ["/paritytech/beefy/1"]; + + /// Name of the notifications protocol used by BEEFY. + /// + /// Must be registered towards the networking in order for BEEFY to properly function. + pub fn standard_name( + genesis_hash: &Hash, + chain_spec: &Box, + ) -> std::borrow::Cow<'static, str> { + let chain_prefix = match chain_spec.fork_id() { + Some(fork_id) => format!("/{}/{}", genesis_hash, fork_id), + None => format!("/{}", genesis_hash), + }; + format!("{}{}", chain_prefix, NAME).into() + } +} /// Returns the configuration value to put in /// [`sc_network::config::NetworkConfiguration::extra_sets`]. -pub fn beefy_peers_set_config() -> sc_network::config::NonDefaultSetConfig { - let mut cfg = - sc_network::config::NonDefaultSetConfig::new(BEEFY_PROTOCOL_NAME.into(), 1024 * 1024); +/// For standard protocol name see [`beefy_protocol_name::standard_name`]. +pub fn beefy_peers_set_config( + protocol_name: std::borrow::Cow<'static, str>, +) -> sc_network::config::NonDefaultSetConfig { + let mut cfg = sc_network::config::NonDefaultSetConfig::new(protocol_name, 1024 * 1024); + cfg.allow_non_reserved(25, 25); + cfg.add_fallback_names(beefy_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect()); cfg } @@ -101,6 +126,8 @@ where pub min_block_delta: u32, /// Prometheus metric registry pub prometheus_registry: Option, + /// Chain specific GRANDPA protocol name. See [`beefy_protocol_name::standard_name`]. + pub protocol_name: std::borrow::Cow<'static, str>, } /// Start the BEEFY gadget. @@ -122,11 +149,11 @@ where signed_commitment_sender, min_block_delta, prometheus_registry, + protocol_name, } = beefy_params; let gossip_validator = Arc::new(gossip::GossipValidator::new()); - let gossip_engine = - GossipEngine::new(network, BEEFY_PROTOCOL_NAME, gossip_validator.clone(), None); + let gossip_engine = GossipEngine::new(network, protocol_name, gossip_validator.clone(), None); let metrics = prometheus_registry.as_ref().map(metrics::Metrics::register).and_then( diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 11e5b73fe77f8..9b672ce7c362d 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -164,6 +164,7 @@ struct ClientSpec { boot_nodes: Vec, telemetry_endpoints: Option, protocol_id: Option, + fork_id: Option, properties: Option, #[serde(flatten)] extensions: E, @@ -226,6 +227,11 @@ impl ChainSpec { self.client_spec.protocol_id.as_deref() } + /// Optional network fork identifier. + pub fn fork_id(&self) -> Option<&str> { + self.client_spec.fork_id.as_ref().map(String::as_str) + } + /// Additional loosly-typed properties of the chain. /// /// Returns an empty JSON object if 'properties' not defined in config @@ -257,6 +263,7 @@ impl ChainSpec { boot_nodes: Vec, telemetry_endpoints: Option, protocol_id: Option<&str>, + fork_id: Option<&str>, properties: Option, extensions: E, ) -> Self { @@ -267,6 +274,7 @@ impl ChainSpec { boot_nodes, telemetry_endpoints, protocol_id: protocol_id.map(str::to_owned), + fork_id: fork_id.map(str::to_owned), properties, extensions, consensus_engine: (), @@ -384,6 +392,10 @@ where ChainSpec::protocol_id(self) } + fn fork_id(&self) -> Option<&str> { + ChainSpec::fork_id(self) + } + fn properties(&self) -> Properties { ChainSpec::properties(self) } diff --git a/client/chain-spec/src/lib.rs b/client/chain-spec/src/lib.rs index 64d72760639df..eb72592b54a99 100644 --- a/client/chain-spec/src/lib.rs +++ b/client/chain-spec/src/lib.rs @@ -165,6 +165,8 @@ pub trait ChainSpec: BuildStorage + Send + Sync { fn telemetry_endpoints(&self) -> &Option; /// Network protocol id. fn protocol_id(&self) -> Option<&str>; + /// Optional network fork identifier. `None` by default. + fn fork_id(&self) -> Option<&str>; /// Additional loosly-typed properties of the chain. /// /// Returns an empty JSON object if 'properties' not defined in config diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index 631fc4ecef951..cf40fb7ec4bfd 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -144,6 +144,7 @@ mod tests { None, None, None, + None, NoExtension::None, ))) } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 10344e09c6858..306311b0e3e56 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -27,6 +27,7 @@ parity-scale-codec = { version = "2.3.1", features = ["derive"] } sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 4e8e047a9b640..ded918c34aa80 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -1664,6 +1664,7 @@ pub(super) struct PeerReport { #[cfg(test)] mod tests { use super::{environment::SharedVoterSetState, *}; + use crate::communication; use sc_network::config::Role; use sc_network_gossip::Validator as GossipValidatorT; use sc_network_test::Block; @@ -1679,6 +1680,7 @@ mod tests { local_role: Role::Authority, observer_enabled: true, telemetry: None, + protocol_name: communication::grandpa_protocol_name::NAME.into(), } } @@ -1840,13 +1842,13 @@ mod tests { // messages from old rounds are expired. for round_num in 1u64..last_kept_round { - let topic = crate::communication::round_topic::(round_num, 1); + let topic = communication::round_topic::(round_num, 1); assert!(is_expired(topic, &[1, 2, 3])); } // messages from not-too-old rounds are not expired. for round_num in last_kept_round..10 { - let topic = crate::communication::round_topic::(round_num, 1); + let topic = communication::round_topic::(round_num, 1); assert!(!is_expired(topic, &[1, 2, 3])); } } @@ -2262,7 +2264,7 @@ mod tests { // we accept messages from rounds 9, 10 and 11 // therefore neither of those should be considered expired for round in &[9, 10, 11] { - assert!(!is_expired(crate::communication::round_topic::(*round, 1), &[])) + assert!(!is_expired(communication::round_topic::(*round, 1), &[])) } } @@ -2310,7 +2312,7 @@ mod tests { if message_allowed( peer, MessageIntent::Broadcast, - &crate::communication::round_topic::(1, 0), + &communication::round_topic::(1, 0), &[], ) { allowed += 1; @@ -2374,7 +2376,7 @@ mod tests { assert!(!val.message_allowed()( &light_peer, MessageIntent::Broadcast, - &crate::communication::round_topic::(1, 0), + &communication::round_topic::(1, 0), &[], )); @@ -2388,7 +2390,7 @@ mod tests { assert!(!val.message_allowed()( &light_peer, MessageIntent::Broadcast, - &crate::communication::round_topic::(1, 0), + &communication::round_topic::(1, 0), &[], )); @@ -2412,8 +2414,8 @@ mod tests { auth_data: Vec::new(), }; - crate::communication::gossip::GossipMessage::::Commit( - crate::communication::gossip::FullCommitMessage { + communication::gossip::GossipMessage::::Commit( + communication::gossip::FullCommitMessage { round: Round(2), set_id: SetId(0), message: commit, @@ -2426,7 +2428,7 @@ mod tests { assert!(val.message_allowed()( &light_peer, MessageIntent::Broadcast, - &crate::communication::global_topic::(0), + &communication::global_topic::(0), &commit, )); } @@ -2466,8 +2468,8 @@ mod tests { auth_data: Vec::new(), }; - crate::communication::gossip::GossipMessage::::Commit( - crate::communication::gossip::FullCommitMessage { + communication::gossip::GossipMessage::::Commit( + communication::gossip::FullCommitMessage { round: Round(1), set_id: SetId(1), message: commit, @@ -2485,7 +2487,7 @@ mod tests { assert!(message_allowed( &peer1, MessageIntent::Broadcast, - &crate::communication::global_topic::(1), + &communication::global_topic::(1), &commit, )); @@ -2494,7 +2496,7 @@ mod tests { assert!(!message_allowed( &peer2, MessageIntent::Broadcast, - &crate::communication::global_topic::(1), + &communication::global_topic::(1), &commit, )); } @@ -2511,8 +2513,8 @@ mod tests { auth_data: Vec::new(), }; - crate::communication::gossip::GossipMessage::::Commit( - crate::communication::gossip::FullCommitMessage { + communication::gossip::GossipMessage::::Commit( + communication::gossip::FullCommitMessage { round: Round(round), set_id: SetId(set_id), message: commit, @@ -2532,15 +2534,13 @@ mod tests { // a commit message for round 1 that finalizes the same height as we // have observed previously should not be expired - assert!( - !message_expired(crate::communication::global_topic::(1), &commit(1, 1, 2),) - ); + assert!(!message_expired(communication::global_topic::(1), &commit(1, 1, 2),)); // it should be expired if it is for a lower block - assert!(message_expired(crate::communication::global_topic::(1), &commit(1, 1, 1))); + assert!(message_expired(communication::global_topic::(1), &commit(1, 1, 1))); // or the same block height but from the previous round - assert!(message_expired(crate::communication::global_topic::(1), &commit(0, 1, 2))); + assert!(message_expired(communication::global_topic::(1), &commit(0, 1, 2))); } #[test] diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 43b2f5463c8db..809e721448bd7 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -67,9 +67,27 @@ mod periodic; #[cfg(test)] pub(crate) mod tests; -/// Name of the notifications protocol used by Grandpa. Must be registered towards the networking -/// in order for Grandpa to properly function. -pub const GRANDPA_PROTOCOL_NAME: &'static str = "/paritytech/grandpa/1"; +pub mod grandpa_protocol_name { + use sc_chain_spec::ChainSpec; + + pub(crate) const NAME: &'static str = "/grandpa/1"; + /// Old names for the notifications protocol, used for backward compatibility. + pub(crate) const LEGACY_NAMES: [&'static str; 1] = ["/paritytech/grandpa/1"]; + + /// Name of the notifications protocol used by GRANDPA. + /// + /// Must be registered towards the networking in order for GRANDPA to properly function. + pub fn standard_name( + genesis_hash: &Hash, + chain_spec: &Box, + ) -> std::borrow::Cow<'static, str> { + let chain_prefix = match chain_spec.fork_id() { + Some(fork_id) => format!("/{}/{}", genesis_hash, fork_id), + None => format!("/{}", genesis_hash), + }; + format!("{}{}", chain_prefix, NAME).into() + } +} // cost scalars for reporting peers. mod cost { @@ -220,13 +238,14 @@ impl> NetworkBridge { prometheus_registry: Option<&Registry>, telemetry: Option, ) -> Self { + let protocol = config.protocol_name.clone(); let (validator, report_stream) = GossipValidator::new(config, set_state.clone(), prometheus_registry, telemetry.clone()); let validator = Arc::new(validator); let gossip_engine = Arc::new(Mutex::new(GossipEngine::new( service.clone(), - GRANDPA_PROTOCOL_NAME, + protocol, validator.clone(), prometheus_registry, ))); diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index ed23415972f95..c135f58a2eec3 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -22,7 +22,7 @@ use super::{ gossip::{self, GossipValidator}, Round, SetId, VoterSet, }; -use crate::{communication::GRANDPA_PROTOCOL_NAME, environment::SharedVoterSetState}; +use crate::{communication::grandpa_protocol_name, environment::SharedVoterSetState}; use futures::prelude::*; use parity_scale_codec::Encode; use sc_network::{config::Role, Event as NetworkEvent, ObservedRole, PeerId}; @@ -97,7 +97,7 @@ impl sc_network_gossip::ValidatorContext for TestNetwork { >::write_notification( self, who.clone(), - GRANDPA_PROTOCOL_NAME.into(), + grandpa_protocol_name::NAME.into(), data, ); } @@ -148,6 +148,7 @@ fn config() -> crate::Config { local_role: Role::Authority, observer_enabled: true, telemetry: None, + protocol_name: grandpa_protocol_name::NAME.into(), } } @@ -286,7 +287,7 @@ fn good_commit_leads_to_relay() { // Add the sending peer and send the commit let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { remote: sender_id.clone(), - protocol: GRANDPA_PROTOCOL_NAME.into(), + protocol: grandpa_protocol_name::NAME.into(), negotiated_fallback: None, role: ObservedRole::Full, }); @@ -294,7 +295,7 @@ fn good_commit_leads_to_relay() { let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { remote: sender_id.clone(), messages: vec![( - GRANDPA_PROTOCOL_NAME.into(), + grandpa_protocol_name::NAME.into(), commit_to_send.clone().into(), )], }); @@ -303,7 +304,7 @@ fn good_commit_leads_to_relay() { let receiver_id = sc_network::PeerId::random(); let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { remote: receiver_id.clone(), - protocol: GRANDPA_PROTOCOL_NAME.into(), + protocol: grandpa_protocol_name::NAME.into(), negotiated_fallback: None, role: ObservedRole::Full, }); @@ -321,7 +322,10 @@ fn good_commit_leads_to_relay() { sender.unbounded_send(NetworkEvent::NotificationsReceived { remote: receiver_id, - messages: vec![(GRANDPA_PROTOCOL_NAME.into(), msg.encode().into())], + messages: vec![( + grandpa_protocol_name::NAME.into(), + msg.encode().into(), + )], }) }; @@ -433,14 +437,14 @@ fn bad_commit_leads_to_report() { Event::EventStream(sender) => { let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { remote: sender_id.clone(), - protocol: GRANDPA_PROTOCOL_NAME.into(), + protocol: grandpa_protocol_name::NAME.into(), negotiated_fallback: None, role: ObservedRole::Full, }); let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { remote: sender_id.clone(), messages: vec![( - GRANDPA_PROTOCOL_NAME.into(), + grandpa_protocol_name::NAME.into(), commit_to_send.clone().into(), )], }); diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index af85965c53c10..b99f6c0544197 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -123,6 +123,7 @@ pub mod warp_proof; pub use authorities::{AuthoritySet, AuthoritySetChanges, SharedAuthoritySet}; pub use aux_schema::best_justification; +pub use communication::grandpa_protocol_name::standard_name as protocol_standard_name; pub use finality_grandpa::voter::report; pub use finality_proof::{FinalityProof, FinalityProofError, FinalityProofProvider}; pub use import::{find_forced_change, find_scheduled_change, GrandpaBlockImport}; @@ -263,6 +264,8 @@ pub struct Config { pub keystore: Option, /// TelemetryHandle instance. pub telemetry: Option, + /// Chain specific GRANDPA protocol name. See [`crate::protocol_standard_name`]. + pub protocol_name: std::borrow::Cow<'static, str>, } impl Config { @@ -714,10 +717,14 @@ pub struct GrandpaParams { /// Returns the configuration value to put in /// [`sc_network::config::NetworkConfiguration::extra_sets`]. -pub fn grandpa_peers_set_config() -> sc_network::config::NonDefaultSetConfig { +/// For standard protocol name see [`crate::protocol_standard_name`]. +pub fn grandpa_peers_set_config( + protocol_name: std::borrow::Cow<'static, str>, +) -> sc_network::config::NonDefaultSetConfig { + use communication::grandpa_protocol_name; sc_network::config::NonDefaultSetConfig { - notifications_protocol: communication::GRANDPA_PROTOCOL_NAME.into(), - fallback_names: Vec::new(), + notifications_protocol: protocol_name, + fallback_names: grandpa_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect(), // Notifications reach ~256kiB in size at the time of writing on Kusama and Polkadot. max_notification_size: 1024 * 1024, set_config: sc_network::config::SetConfig { diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index f619c03cab6f1..2e545b6e88ebf 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -56,6 +56,7 @@ use substrate_test_runtime_client::runtime::BlockNumber; use tokio::runtime::{Handle, Runtime}; use authorities::AuthoritySet; +use communication::grandpa_protocol_name; use sc_block_builder::BlockBuilderProvider; use sc_consensus::LongestChain; use sc_keystore::LocalKeystore; @@ -97,7 +98,7 @@ impl GrandpaTestNet { impl GrandpaTestNet { fn add_authority_peer(&mut self) { self.add_full_peer_with_config(FullPeerConfig { - notifications_protocols: vec![communication::GRANDPA_PROTOCOL_NAME.into()], + notifications_protocols: vec![grandpa_protocol_name::NAME.into()], is_authority: true, ..Default::default() }) @@ -121,7 +122,7 @@ impl TestNetFactory for GrandpaTestNet { fn add_full_peer(&mut self) { self.add_full_peer_with_config(FullPeerConfig { - notifications_protocols: vec![communication::GRANDPA_PROTOCOL_NAME.into()], + notifications_protocols: vec![grandpa_protocol_name::NAME.into()], is_authority: false, ..Default::default() }) @@ -274,6 +275,7 @@ fn initialize_grandpa( local_role: Role::Authority, observer_enabled: true, telemetry: None, + protocol_name: grandpa_protocol_name::NAME.into(), }, link, network: net_service, @@ -423,6 +425,7 @@ fn finalize_3_voters_1_full_observer() { local_role: Role::Authority, observer_enabled: true, telemetry: None, + protocol_name: grandpa_protocol_name::NAME.into(), }, link, network: net_service, @@ -513,6 +516,7 @@ fn transition_3_voters_twice_1_full_observer() { local_role: Role::Authority, observer_enabled: true, telemetry: None, + protocol_name: grandpa_protocol_name::NAME.into(), }, link, network: net_service, @@ -971,6 +975,7 @@ fn voter_persists_its_votes() { local_role: Role::Authority, observer_enabled: true, telemetry: None, + protocol_name: grandpa_protocol_name::NAME.into(), }; let set_state = { @@ -1010,6 +1015,7 @@ fn voter_persists_its_votes() { local_role: Role::Authority, observer_enabled: true, telemetry: None, + protocol_name: grandpa_protocol_name::NAME.into(), }, link, network: net_service, @@ -1050,6 +1056,7 @@ fn voter_persists_its_votes() { local_role: Role::Authority, observer_enabled: true, telemetry: None, + protocol_name: grandpa_protocol_name::NAME.into(), }, link, network: net_service, @@ -1213,6 +1220,7 @@ fn finalize_3_voters_1_light_observer() { local_role: Role::Full, observer_enabled: true, telemetry: None, + protocol_name: grandpa_protocol_name::NAME.into(), }, net.peers[3].data.lock().take().expect("link initialized at startup; qed"), net.peers[3].network_service().clone(), @@ -1259,6 +1267,7 @@ fn voter_catches_up_to_latest_round_when_behind() { local_role: Role::Authority, observer_enabled: true, telemetry: None, + protocol_name: grandpa_protocol_name::NAME.into(), }, link, network: net.lock().peer(peer_id).network_service().clone(), @@ -1376,6 +1385,7 @@ where local_role: Role::Authority, observer_enabled: true, telemetry: None, + protocol_name: grandpa_protocol_name::NAME.into(), }; let network = diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 333ea41c8d80b..14411ef2aa18a 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -603,6 +603,13 @@ impl NonDefaultSetConfig { pub fn add_reserved(&mut self, peer: MultiaddrWithPeerId) { self.set_config.reserved_nodes.push(peer); } + + /// Add a list of protocol names used for backward compatibility. + /// + /// See the explanations in [`NonDefaultSetConfig::fallback_names`]. + pub fn add_fallback_names(&mut self, fallback_names: Vec>) { + self.fallback_names.extend(fallback_names); + } } /// Configuration for the transport layer. From cfcdc10a0d37ba588b442332ab6f8153b358fa2b Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 5 Jan 2022 19:08:36 -0400 Subject: [PATCH 0400/1472] Fix Clippy (#10596) * fix clippy * fmt --- client/chain-spec/src/chain_spec.rs | 2 +- client/service/src/client/call_executor.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 9b672ce7c362d..59d3ac3513817 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -229,7 +229,7 @@ impl ChainSpec { /// Optional network fork identifier. pub fn fork_id(&self) -> Option<&str> { - self.client_spec.fork_id.as_ref().map(String::as_str) + self.client_spec.fork_id.as_deref() } /// Additional loosly-typed properties of the chain. diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index fedd3400488d2..a806b2dbb6d49 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -246,9 +246,7 @@ where &runtime_code, self.spawn_handle.clone(), ) - .with_storage_transaction_cache( - storage_transaction_cache.as_mut().map(|c| &mut **c), - ) + .with_storage_transaction_cache(storage_transaction_cache.as_deref_mut()) .set_parent_hash(at_hash); state_machine.execute_using_consensus_failure_handler( execution_manager, From cc3b082e9fa92fcd2e09836c59e113be1dcb0aa7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jan 2022 09:22:35 +0000 Subject: [PATCH 0401/1472] Bump proc-macro2 from 1.0.32 to 1.0.36 (#10564) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump proc-macro2 from 1.0.32 to 1.0.36 Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.32 to 1.0.36. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.32...1.0.36) --- updated-dependencies: - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Fix ui tests Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Bastian Köcher --- Cargo.lock | 4 ++-- client/chain-spec/derive/Cargo.toml | 2 +- client/tracing/proc-macro/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/tools/Cargo.toml | 2 +- frame/support/procedural/tools/derive/Cargo.toml | 2 +- .../tests/construct_runtime_ui/missing_where_block.stderr | 4 ++-- .../tests/construct_runtime_ui/missing_where_param.stderr | 4 ++-- primitives/api/proc-macro/Cargo.toml | 2 +- primitives/core/hashing/proc-macro/Cargo.toml | 2 +- primitives/npos-elections/solution-type/Cargo.toml | 2 +- primitives/runtime-interface/proc-macro/Cargo.toml | 2 +- primitives/version/proc-macro/Cargo.toml | 2 +- test-utils/derive/Cargo.toml | 2 +- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16a24f284dc4d..1dbd540491134 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6866,9 +6866,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.32" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index 97573c8ca3b0c..1ea9440572d47 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -16,7 +16,7 @@ proc-macro = true [dependencies] proc-macro-crate = "1.1.0" -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" quote = "1.0.10" syn = "1.0.82" diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index 53d463a4f4e50..e939d0837b216 100644 --- a/client/tracing/proc-macro/Cargo.toml +++ b/client/tracing/proc-macro/Cargo.toml @@ -16,6 +16,6 @@ proc-macro = true [dependencies] proc-macro-crate = "1.1.0" -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" quote = { version = "1.0.10", features = ["proc-macro"] } syn = { version = "1.0.82", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index 7d95152ea65af..bcbdffd6adc31 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] syn = { version = "1.0.82", features = ["full", "visit"] } quote = "1.0.10" -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" proc-macro-crate = "1.1.0" [dev-dependencies] diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 7a1eaa3a08176..640fe436b1855 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -16,7 +16,7 @@ proc-macro = true [dependencies] frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" quote = "1.0.10" Inflector = "0.11.4" syn = { version = "1.0.82", features = ["full"] } diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index 265952ebc4b72..ae2de2effd4ae 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" } -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "visit", "extra-traits"] } proc-macro-crate = "1.1.0" diff --git a/frame/support/procedural/tools/derive/Cargo.toml b/frame/support/procedural/tools/derive/Cargo.toml index df994e14226d7..5ed1b506dfb97 100644 --- a/frame/support/procedural/tools/derive/Cargo.toml +++ b/frame/support/procedural/tools/derive/Cargo.toml @@ -15,6 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" quote = { version = "1.0.10", features = ["proc-macro"] } syn = { version = "1.0.82", features = ["proc-macro" ,"full", "extra-traits", "parsing"] } diff --git a/frame/support/test/tests/construct_runtime_ui/missing_where_block.stderr b/frame/support/test/tests/construct_runtime_ui/missing_where_block.stderr index 4af672a2610b6..c6baf8fc24d07 100644 --- a/frame/support/test/tests/construct_runtime_ui/missing_where_block.stderr +++ b/frame/support/test/tests/construct_runtime_ui/missing_where_block.stderr @@ -1,5 +1,5 @@ error: expected `where` - --> $DIR/missing_where_block.rs:4:19 + --> tests/construct_runtime_ui/missing_where_block.rs:4:19 | 4 | pub enum Runtime {} - | ^^ + | ^ diff --git a/frame/support/test/tests/construct_runtime_ui/missing_where_param.stderr b/frame/support/test/tests/construct_runtime_ui/missing_where_param.stderr index ac7313523c0c4..fb7e38b53dcd6 100644 --- a/frame/support/test/tests/construct_runtime_ui/missing_where_param.stderr +++ b/frame/support/test/tests/construct_runtime_ui/missing_where_param.stderr @@ -1,5 +1,5 @@ error: Missing associated type for `UncheckedExtrinsic`. Add `UncheckedExtrinsic` = ... to where section. - --> $DIR/missing_where_param.rs:7:2 + --> tests/construct_runtime_ui/missing_where_param.rs:7:2 | 7 | {} - | ^^ + | ^ diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index 4afc07833649c..30ab3ef9562b1 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" blake2-rfc = { version = "0.2.18", default-features = false } proc-macro-crate = "1.1.0" diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index 4df40e55bc907..fea865ab9e101 100644 --- a/primitives/core/hashing/proc-macro/Cargo.toml +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -18,5 +18,5 @@ proc-macro = true [dependencies] syn = { version = "1.0.82", features = ["full", "parsing"] } quote = "1.0.6" -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" sp-core-hashing = { version = "4.0.0", path = "../", default-features = false } diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index cf2a2016500a0..cfb3af4552e2e 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] syn = { version = "1.0.82", features = ["full", "visit"] } quote = "1.0" -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" proc-macro-crate = "1.1.0" [dev-dependencies] diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 031906486b559..f69c49843c1da 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -18,6 +18,6 @@ proc-macro = true [dependencies] syn = { version = "1.0.82", features = ["full", "visit", "fold", "extra-traits"] } quote = "1.0.10" -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" Inflector = "0.11.4" proc-macro-crate = "1.1.0" diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index df254e64f34cf..a706f74f45229 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" codec = { package = "parity-scale-codec", version = "2.0.0", features = [ "derive" ] } [dev-dependencies] diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index 83782a2ba5ff2..166d9cc1eff17 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -12,7 +12,7 @@ description = "Substrate test utilities macros" quote = "1.0.10" syn = { version = "1.0.82", features = ["full"] } proc-macro-crate = "1.1.0" -proc-macro2 = "1.0.29" +proc-macro2 = "1.0.36" [lib] proc-macro = true From 3807a879241c4e43fe20fc5296239ad8d024c82c Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Thu, 6 Jan 2022 01:41:18 -0800 Subject: [PATCH 0402/1472] Add benchmark tests for pallet bags list (#10593) * Add benchmark tests for pallet bags list * Make sure to set active balance for new ledgers * fmt * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_bags_list --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/bags-list/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot Co-authored-by: Shawn Tabrizi --- frame/bags-list/src/benchmarks.rs | 6 ++++++ frame/bags-list/src/weights.rs | 16 ++++++++-------- frame/staking/src/pallet/impls.rs | 9 ++++----- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index 5f0bcd4603865..cc575d7d1efff 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -175,3 +175,9 @@ frame_benchmarking::benchmarks! { ) } } + +frame_benchmarking::impl_benchmark_test_suite!( + Pallet, + crate::mock::ExtBuilder::default().skip_genesis_ids().build(), + crate::mock::Runtime +); diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index cd5aed0770ab1..5a8f51cc07c76 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_bags_list //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -57,7 +57,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (70_481_000 as Weight) + (62_060_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -66,7 +66,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (68_642_000 as Weight) + (60_585_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -76,7 +76,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (82_341_000 as Weight) + (69_779_000 as Weight) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -89,7 +89,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (70_481_000 as Weight) + (62_060_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -98,7 +98,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (68_642_000 as Weight) + (60_585_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -108,7 +108,7 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (82_341_000 as Weight) + (69_779_000 as Weight) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index ea2c746ed7177..c97541de81961 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1245,13 +1245,12 @@ impl VoteWeightProvider for Pallet { // this will clearly results in an inconsistent state, but it should not matter for a // benchmark. let active: BalanceOf = weight.try_into().map_err(|_| ()).unwrap(); - let ledger = match Self::ledger(who) { + let mut ledger = match Self::ledger(who) { None => StakingLedger::default_from(who.clone()), - Some(mut l) => { - l.active = active; - l - }, + Some(l) => l, }; + ledger.active = active; + >::insert(who, ledger); >::insert(who, who); From d642f5eb4aa8f3e4625eba94b868280b48b8fccd Mon Sep 17 00:00:00 2001 From: wigy <1888808+wigy-opensource-developer@users.noreply.github.com> Date: Thu, 6 Jan 2022 11:12:54 +0100 Subject: [PATCH 0403/1472] Exclude big changes from file annotations (#10588) --- .git-blame-ignore-revs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000000..c99a3070231d8 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,15 @@ +# You can easily exclude big automated code changes by running +# +# git config blame.ignoreRevsFile .git-blame-ignore-revs +# +# in your local repository. It will work also in IDE integrations. +# +# On versions of Git 2.20 and later comments (#), empty lines, and any leading and +# trailing whitespace is ignored. Everything but a SHA-1 per line will error out on +# older versions. +# +# You should add new commit hashes to this file when you create or find such big +# automated refactorings while reading code history. If you only know the short hash, +# use `git rev-parse 1d5abf01` to expand it to the full SHA1 hash needed in this file. + +1d5abf01abafdb6c15bcd0172f5de09fd87c5fbf # Run cargo fmt on the whole code base (#9394) From 55f7969720e003ce77697d26d5a965eb346f8018 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 6 Jan 2022 11:55:21 +0100 Subject: [PATCH 0404/1472] some improvements to bounded vec API (#10590) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * some improvements to bounded vec * revert license tweak * more tests * fix * Update frame/support/src/storage/bounded_vec.rs Co-authored-by: Bastian Köcher * add the same stuff for btree map and set as well Co-authored-by: Bastian Köcher --- .../support/src/storage/bounded_btree_map.rs | 93 +++++++++++++- .../support/src/storage/bounded_btree_set.rs | 118 +++++++++++++++--- frame/support/src/storage/bounded_vec.rs | 109 ++++++++++++++-- frame/support/src/traits.rs | 3 +- frame/support/src/traits/misc.rs | 10 ++ 5 files changed, 301 insertions(+), 32 deletions(-) diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index 201015e3a6222..ed132adac657e 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -17,7 +17,10 @@ //! Traits, types and structs to support a bounded BTreeMap. -use crate::{storage::StorageDecodeLength, traits::Get}; +use crate::{ + storage::StorageDecodeLength, + traits::{Get, TryCollect}, +}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_std::{ borrow::Borrow, collections::btree_map::BTreeMap, convert::TryFrom, marker::PhantomData, @@ -69,6 +72,11 @@ where K: Ord, S: Get, { + /// Create `Self` from `t` without any checks. + fn unchecked_from(t: BTreeMap) -> Self { + Self(t, Default::default()) + } + /// Create a new `BoundedBTreeMap`. /// /// Does not allocate. @@ -183,16 +191,23 @@ where } } -impl PartialEq for BoundedBTreeMap +impl PartialEq> for BoundedBTreeMap where BTreeMap: PartialEq, + S1: Get, + S2: Get, { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 + fn eq(&self, other: &BoundedBTreeMap) -> bool { + S1::get() == S2::get() && self.0 == other.0 } } -impl Eq for BoundedBTreeMap where BTreeMap: Eq {} +impl Eq for BoundedBTreeMap +where + BTreeMap: Eq, + S: Get, +{ +} impl PartialEq> for BoundedBTreeMap where @@ -206,6 +221,7 @@ where impl PartialOrd for BoundedBTreeMap where BTreeMap: PartialOrd, + S: Get, { fn partial_cmp(&self, other: &Self) -> Option { self.0.partial_cmp(&other.0) @@ -215,6 +231,7 @@ where impl Ord for BoundedBTreeMap where BTreeMap: Ord, + S: Get, { fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { self.0.cmp(&other.0) @@ -302,6 +319,23 @@ impl codec::EncodeLike> for BoundedBTreeMap whe { } +impl TryCollect> for I +where + K: Ord, + I: ExactSizeIterator + Iterator, + Bound: Get, +{ + type Error = &'static str; + + fn try_collect(self) -> Result, Self::Error> { + if self.len() > Bound::get() as usize { + Err("iterator length too big") + } else { + Ok(BoundedBTreeMap::::unchecked_from(self.collect::>())) + } + } +} + #[cfg(test)] pub mod test { use super::*; @@ -452,4 +486,53 @@ pub mod test { assert_eq!(zero_key.1, false); assert_eq!(*zero_value, 6); } + + #[test] + fn can_be_collected() { + let b1 = boundedmap_from_keys::>(&[1, 2, 3, 4]); + let b2: BoundedBTreeMap> = + b1.iter().map(|(k, v)| (k + 1, *v)).try_collect().unwrap(); + assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3, 4, 5]); + + // can also be collected into a collection of length 4. + let b2: BoundedBTreeMap> = + b1.iter().map(|(k, v)| (k + 1, *v)).try_collect().unwrap(); + assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3, 4, 5]); + + // can be mutated further into iterators that are `ExactSizedIterator`. + let b2: BoundedBTreeMap> = + b1.iter().map(|(k, v)| (k + 1, *v)).rev().skip(2).try_collect().unwrap(); + // note that the binary tree will re-sort this, so rev() is not really seen + assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3]); + + let b2: BoundedBTreeMap> = + b1.iter().map(|(k, v)| (k + 1, *v)).take(2).try_collect().unwrap(); + assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3]); + + // but these worn't work + let b2: Result>, _> = + b1.iter().map(|(k, v)| (k + 1, *v)).try_collect(); + assert!(b2.is_err()); + + let b2: Result>, _> = + b1.iter().map(|(k, v)| (k + 1, *v)).skip(2).try_collect(); + assert!(b2.is_err()); + } + + #[test] + fn eq_works() { + // of same type + let b1 = boundedmap_from_keys::>(&[1, 2]); + let b2 = boundedmap_from_keys::>(&[1, 2]); + assert_eq!(b1, b2); + + // of different type, but same value and bound. + crate::parameter_types! { + B1: u32 = 7; + B2: u32 = 7; + } + let b1 = boundedmap_from_keys::(&[1, 2]); + let b2 = boundedmap_from_keys::(&[1, 2]); + assert_eq!(b1, b2); + } } diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index f51439f04d137..7d543549c6bae 100644 --- a/frame/support/src/storage/bounded_btree_set.rs +++ b/frame/support/src/storage/bounded_btree_set.rs @@ -17,7 +17,10 @@ //! Traits, types and structs to support a bounded `BTreeSet`. -use crate::{storage::StorageDecodeLength, traits::Get}; +use crate::{ + storage::StorageDecodeLength, + traits::{Get, TryCollect}, +}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_std::{ borrow::Borrow, collections::btree_set::BTreeSet, convert::TryFrom, marker::PhantomData, @@ -68,6 +71,11 @@ where T: Ord, S: Get, { + /// Create `Self` from `t` without any checks. + fn unchecked_from(t: BTreeSet) -> Self { + Self(t, Default::default()) + } + /// Create a new `BoundedBTreeSet`. /// /// Does not allocate. @@ -168,20 +176,28 @@ where } } -impl PartialEq for BoundedBTreeSet +impl PartialEq> for BoundedBTreeSet where BTreeSet: PartialEq, + S1: Get, + S2: Get, { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 + fn eq(&self, other: &BoundedBTreeSet) -> bool { + S1::get() == S2::get() && self.0 == other.0 } } -impl Eq for BoundedBTreeSet where BTreeSet: Eq {} +impl Eq for BoundedBTreeSet +where + BTreeSet: Eq, + S: Get, +{ +} impl PartialEq> for BoundedBTreeSet where BTreeSet: PartialEq, + S: Get, { fn eq(&self, other: &BTreeSet) -> bool { self.0 == *other @@ -191,6 +207,7 @@ where impl PartialOrd for BoundedBTreeSet where BTreeSet: PartialOrd, + S: Get, { fn partial_cmp(&self, other: &Self) -> Option { self.0.partial_cmp(&other.0) @@ -200,6 +217,7 @@ where impl Ord for BoundedBTreeSet where BTreeSet: Ord, + S: Get, { fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { self.0.cmp(&other.0) @@ -283,6 +301,23 @@ impl StorageDecodeLength for BoundedBTreeSet {} impl codec::EncodeLike> for BoundedBTreeSet where BTreeSet: Encode {} +impl TryCollect> for I +where + T: Ord, + I: ExactSizeIterator + Iterator, + Bound: Get, +{ + type Error = &'static str; + + fn try_collect(self) -> Result, Self::Error> { + if self.len() > Bound::get() as usize { + Err("iterator length too big") + } else { + Ok(BoundedBTreeSet::::unchecked_from(self.collect::>())) + } + } +} + #[cfg(test)] pub mod test { use super::*; @@ -298,31 +333,31 @@ pub mod test { FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedBTreeSet>> } - fn map_from_keys(keys: &[T]) -> BTreeSet + fn set_from_keys(keys: &[T]) -> BTreeSet where T: Ord + Copy, { keys.iter().copied().collect() } - fn boundedmap_from_keys(keys: &[T]) -> BoundedBTreeSet + fn boundedset_from_keys(keys: &[T]) -> BoundedBTreeSet where T: Ord + Copy, S: Get, { - map_from_keys(keys).try_into().unwrap() + set_from_keys(keys).try_into().unwrap() } #[test] fn decode_len_works() { TestExternalities::default().execute_with(|| { - let bounded = boundedmap_from_keys::>(&[1, 2, 3]); + let bounded = boundedset_from_keys::>(&[1, 2, 3]); Foo::put(bounded); assert_eq!(Foo::decode_len().unwrap(), 3); }); TestExternalities::default().execute_with(|| { - let bounded = boundedmap_from_keys::>(&[1, 2, 3]); + let bounded = boundedset_from_keys::>(&[1, 2, 3]); FooMap::insert(1, bounded); assert_eq!(FooMap::decode_len(1).unwrap(), 3); assert!(FooMap::decode_len(0).is_none()); @@ -330,7 +365,7 @@ pub mod test { }); TestExternalities::default().execute_with(|| { - let bounded = boundedmap_from_keys::>(&[1, 2, 3]); + let bounded = boundedset_from_keys::>(&[1, 2, 3]); FooDoubleMap::insert(1, 1, bounded); assert_eq!(FooDoubleMap::decode_len(1, 1).unwrap(), 3); assert!(FooDoubleMap::decode_len(2, 1).is_none()); @@ -341,17 +376,17 @@ pub mod test { #[test] fn try_insert_works() { - let mut bounded = boundedmap_from_keys::>(&[1, 2, 3]); + let mut bounded = boundedset_from_keys::>(&[1, 2, 3]); bounded.try_insert(0).unwrap(); - assert_eq!(*bounded, map_from_keys(&[1, 0, 2, 3])); + assert_eq!(*bounded, set_from_keys(&[1, 0, 2, 3])); assert!(bounded.try_insert(9).is_err()); - assert_eq!(*bounded, map_from_keys(&[1, 0, 2, 3])); + assert_eq!(*bounded, set_from_keys(&[1, 0, 2, 3])); } #[test] fn deref_coercion_works() { - let bounded = boundedmap_from_keys::>(&[1, 2, 3]); + let bounded = boundedset_from_keys::>(&[1, 2, 3]); // these methods come from deref-ed vec. assert_eq!(bounded.len(), 3); assert!(bounded.iter().next().is_some()); @@ -360,7 +395,7 @@ pub mod test { #[test] fn try_mutate_works() { - let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); + let bounded = boundedset_from_keys::>(&[1, 2, 3, 4, 5, 6]); let bounded = bounded .try_mutate(|v| { v.insert(7); @@ -376,8 +411,8 @@ pub mod test { #[test] fn btree_map_eq_works() { - let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); - assert_eq!(bounded, map_from_keys(&[1, 2, 3, 4, 5, 6])); + let bounded = boundedset_from_keys::>(&[1, 2, 3, 4, 5, 6]); + assert_eq!(bounded, set_from_keys(&[1, 2, 3, 4, 5, 6])); } #[test] @@ -433,4 +468,51 @@ pub mod test { assert_eq!(zero_item.0, 0); assert_eq!(zero_item.1, false); } + + #[test] + fn can_be_collected() { + let b1 = boundedset_from_keys::>(&[1, 2, 3, 4]); + let b2: BoundedBTreeSet> = b1.iter().map(|k| k + 1).try_collect().unwrap(); + assert_eq!(b2.into_iter().collect::>(), vec![2, 3, 4, 5]); + + // can also be collected into a collection of length 4. + let b2: BoundedBTreeSet> = b1.iter().map(|k| k + 1).try_collect().unwrap(); + assert_eq!(b2.into_iter().collect::>(), vec![2, 3, 4, 5]); + + // can be mutated further into iterators that are `ExactSizedIterator`. + let b2: BoundedBTreeSet> = + b1.iter().map(|k| k + 1).rev().skip(2).try_collect().unwrap(); + // note that the binary tree will re-sort this, so rev() is not really seen + assert_eq!(b2.into_iter().collect::>(), vec![2, 3]); + + let b2: BoundedBTreeSet> = + b1.iter().map(|k| k + 1).take(2).try_collect().unwrap(); + assert_eq!(b2.into_iter().collect::>(), vec![2, 3]); + + // but these worn't work + let b2: Result>, _> = + b1.iter().map(|k| k + 1).try_collect(); + assert!(b2.is_err()); + + let b2: Result>, _> = + b1.iter().map(|k| k + 1).skip(2).try_collect(); + assert!(b2.is_err()); + } + + #[test] + fn eq_works() { + // of same type + let b1 = boundedset_from_keys::>(&[1, 2]); + let b2 = boundedset_from_keys::>(&[1, 2]); + assert_eq!(b1, b2); + + // of different type, but same value and bound. + crate::parameter_types! { + B1: u32 = 7; + B2: u32 = 7; + } + let b1 = boundedset_from_keys::(&[1, 2]); + let b2 = boundedset_from_keys::(&[1, 2]); + assert_eq!(b1, b2); + } } diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 5ea7a62c79c28..bdac8f23d7c96 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -20,7 +20,7 @@ use crate::{ storage::{StorageDecodeLength, StorageTryAppend}, - traits::Get, + traits::{Get, TryCollect}, WeakBoundedVec, }; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; @@ -146,11 +146,34 @@ impl> From> for Vec { } impl> BoundedVec { + /// Pre-allocate `capacity` items in self. + /// + /// If `capacity` is greater than [`Self::bound`], then the minimum of the two is used. + pub fn with_bounded_capacity(capacity: usize) -> Self { + let capacity = capacity.min(Self::bound()); + Self(Vec::with_capacity(capacity), Default::default()) + } + + /// Allocate self with the maximum possible capacity. + pub fn with_max_capacity() -> Self { + Self::with_bounded_capacity(Self::bound()) + } + /// Get the bound of the type in `usize`. pub fn bound() -> usize { S::get() as usize } + /// Same as `Vec::resize`, but if `size` is more than [`Self::bound`], then [`Self::bound`] is + /// used. + pub fn bounded_resize(&mut self, size: usize, value: T) + where + T: Clone, + { + let size = size.min(Self::bound()); + self.0.resize(size, value); + } + /// Consumes self and mutates self via the given `mutate` function. /// /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is @@ -300,15 +323,14 @@ impl codec::DecodeLength for BoundedVec { } } -// NOTE: we could also implement this as: -// impl, S2: Get> PartialEq> for BoundedVec -// to allow comparison of bounded vectors with different bounds. -impl PartialEq for BoundedVec +impl PartialEq> for BoundedVec where T: PartialEq, + BoundSelf: Get, + BoundRhs: Get, { - fn eq(&self, rhs: &Self) -> bool { - self.0 == rhs.0 + fn eq(&self, rhs: &BoundedVec) -> bool { + BoundSelf::get() == BoundRhs::get() && self.0 == rhs.0 } } @@ -318,7 +340,7 @@ impl> PartialEq> for BoundedVec { } } -impl Eq for BoundedVec where T: Eq {} +impl> Eq for BoundedVec where T: Eq {} impl StorageDecodeLength for BoundedVec {} @@ -344,6 +366,22 @@ where } } +impl TryCollect> for I +where + I: ExactSizeIterator + Iterator, + Bound: Get, +{ + type Error = &'static str; + + fn try_collect(self) -> Result, Self::Error> { + if self.len() > Bound::get() as usize { + Err("iterator length too big") + } else { + Ok(BoundedVec::::unchecked_from(self.collect::>())) + } + } +} + #[cfg(test)] pub mod test { use super::*; @@ -452,4 +490,59 @@ pub mod test { Err("BoundedVec exceeds its limit".into()), ); } + + #[test] + fn can_be_collected() { + let b1: BoundedVec> = vec![1, 2, 3, 4].try_into().unwrap(); + let b2: BoundedVec> = b1.iter().map(|x| x + 1).try_collect().unwrap(); + assert_eq!(b2, vec![2, 3, 4, 5]); + + // can also be collected into a collection of length 4. + let b2: BoundedVec> = b1.iter().map(|x| x + 1).try_collect().unwrap(); + assert_eq!(b2, vec![2, 3, 4, 5]); + + // can be mutated further into iterators that are `ExactSizedIterator`. + let b2: BoundedVec> = + b1.iter().map(|x| x + 1).rev().try_collect().unwrap(); + assert_eq!(b2, vec![5, 4, 3, 2]); + + let b2: BoundedVec> = + b1.iter().map(|x| x + 1).rev().skip(2).try_collect().unwrap(); + assert_eq!(b2, vec![3, 2]); + let b2: BoundedVec> = + b1.iter().map(|x| x + 1).rev().skip(2).try_collect().unwrap(); + assert_eq!(b2, vec![3, 2]); + + let b2: BoundedVec> = + b1.iter().map(|x| x + 1).rev().take(2).try_collect().unwrap(); + assert_eq!(b2, vec![5, 4]); + let b2: BoundedVec> = + b1.iter().map(|x| x + 1).rev().take(2).try_collect().unwrap(); + assert_eq!(b2, vec![5, 4]); + + // but these worn't work + let b2: Result>, _> = b1.iter().map(|x| x + 1).try_collect(); + assert!(b2.is_err()); + + let b2: Result>, _> = + b1.iter().map(|x| x + 1).rev().take(2).try_collect(); + assert!(b2.is_err()); + } + + #[test] + fn eq_works() { + // of same type + let b1: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + let b2: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + assert_eq!(b1, b2); + + // of different type, but same value and bound. + crate::parameter_types! { + B1: u32 = 7; + B2: u32 = 7; + } + let b1: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let b2: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + assert_eq!(b1, b2); + } } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index d0719063ef3e4..85a0698759b69 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -54,7 +54,8 @@ pub use misc::{ ConstU32, ConstU64, ConstU8, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider, PreimageRecipient, - PrivilegeCmp, SameOrOther, Time, TryDrop, UnixTime, WrapperKeepOpaque, WrapperOpaque, + PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, UnixTime, WrapperKeepOpaque, + WrapperOpaque, }; mod stored_map; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index c68561367e3da..df21624c3cea0 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -23,6 +23,16 @@ use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; use sp_runtime::{traits::Block as BlockT, DispatchError}; use sp_std::{cmp::Ordering, prelude::*}; +/// Try and collect into a collection `C`. +pub trait TryCollect { + type Error; + /// Consume self and try to collect the results into `C`. + /// + /// This is useful in preventing the undesirable `.collect().try_into()` call chain on + /// collections that need to be converted into a bounded type (e.g. `BoundedVec`). + fn try_collect(self) -> Result; +} + /// Anything that can have a `::len()` method. pub trait Len { /// Return the length of data type. From 2316fc9e8e88be70c80023d26ab0e7903d0f5668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 6 Jan 2022 12:03:18 +0100 Subject: [PATCH 0405/1472] contracts: Improve documentation of lazy deletion config (#10582) * Improve documentation of lazy deletion config * Apply suggestions from code review Co-authored-by: Sacha Lansky * Update frame/contracts/src/lib.rs Co-authored-by: Andrew Jones * Improve wording Co-authored-by: Sacha Lansky Co-authored-by: Andrew Jones --- frame/contracts/src/lib.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 62e79944bbe92..e4a54362c90bc 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -254,11 +254,30 @@ pub mod pallet { /// In other words only the origin called "root contract" is allowed to execute then. type CallStack: smallvec::Array>; - /// The maximum number of tries that can be queued for deletion. + /// The maximum number of contracts that can be pending for deletion. + /// + /// When a contract is deleted by calling `seal_terminate` it becomes inaccessible + /// immediately, but the deletion of the storage items it has accumulated is performed + /// later. The contract is put into the deletion queue. This defines how many + /// contracts can be queued up at the same time. If that limit is reached `seal_terminate` + /// will fail. The action must be retried in a later block in that case. + /// + /// The reasons for limiting the queue depth are: + /// + /// 1. The queue is in storage in order to be persistent between blocks. We want to limit + /// the amount of storage that can be consumed. + /// 2. The queue is stored in a vector and needs to be decoded as a whole when reading + /// it at the end of each block. Longer queues take more weight to decode and hence + /// limit the amount of items that can be deleted per block. #[pallet::constant] type DeletionQueueDepth: Get; /// The maximum amount of weight that can be consumed per block for lazy trie removal. + /// + /// The amount of weight that is dedicated per block to work on the deletion queue. Larger + /// values allow more trie keys to be deleted in each block but reduce the amount of + /// weight that is left for transactions. See [`Self::DeletionQueueDepth`] for more + /// information about the deletion queue. #[pallet::constant] type DeletionWeightLimit: Get; @@ -271,6 +290,7 @@ pub mod pallet { type DepositPerByte: Get>; /// The amount of balance a caller has to pay for each storage item. + /// /// # Note /// /// Changing this value for an existing chain might need a storage migration. From 7409589ab78e7cb508db873dd6384634d667b8f5 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 6 Jan 2022 15:43:11 +0200 Subject: [PATCH 0406/1472] Add BEEFY `latestFinalized` RPC and deduplicate code between BEEFY and GRANDPA (#10568) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * beefy: add dummy latest_finalized() RPC * beefy: rpc latest_best_beefy() using shared mem * beefy: rpc populate latest_best_beefy() * beefy: rpc handle readiness * beefy: best block over channel - wip Not working because channel can't be simply opened and receiver passed to `rpc_extensions_builder` because `rpc_extensions_builder` has to be `Fn` and not `FnOnce`... and and Receiver side of mpsc can't be cloned yay!.. * beefy: make notification channels payload-agnostic * beefy: use notification mechanism instead of custom channel * beefy: add tracing key to notif channels * sc-utils: add notification channel - wip * beefy: use sc-utils generic notification channel * grandpa: use sc-utils generic notification channel * fix grumbles * beefy-rpc: get best block header instead of number * beefy-rpc: rename to `beefy_getFinalizedHead` * fix nitpicks * client-rpc-notifications: move generic Error from struct to fn * beefy: use header from notification instead of getting from database * beefy-rpc: get best block hash instead of header * beefy-rpc: fix and improve latestHead test * beefy-rpc: bubble up errors from rpc-handler instantiation * update lockfile * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * fix errors and warnings * fix nit Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- Cargo.lock | 40 +++++ client/beefy/rpc/Cargo.toml | 4 + client/beefy/rpc/src/lib.rs | 184 ++++++++++++++++++-- client/beefy/rpc/src/notification.rs | 8 +- client/beefy/src/lib.rs | 8 +- client/beefy/src/notification.rs | 111 +++--------- client/beefy/src/worker.rs | 42 +++-- client/finality-grandpa/rpc/src/lib.rs | 2 +- client/finality-grandpa/src/notification.rs | 87 ++------- client/utils/Cargo.toml | 4 + client/utils/src/lib.rs | 1 + client/utils/src/notification.rs | 151 ++++++++++++++++ 12 files changed, 448 insertions(+), 194 deletions(-) create mode 100644 client/utils/src/notification.rs diff --git a/Cargo.lock b/Cargo.lock index 1dbd540491134..e5192d2c8fe17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -323,6 +323,27 @@ dependencies = [ "trust-dns-resolver", ] +[[package]] +name = "async-stream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +dependencies = [ + "async-stream-impl", + "futures-core", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-task" version = "4.0.3" @@ -508,6 +529,7 @@ version = "4.0.0-dev" dependencies = [ "beefy-gadget", "beefy-primitives", + "derive_more", "futures 0.3.16", "jsonrpc-core", "jsonrpc-core-client", @@ -515,12 +537,15 @@ dependencies = [ "jsonrpc-pubsub", "log 0.4.14", "parity-scale-codec", + "parking_lot 0.11.2", "sc-rpc", + "sc-utils", "serde", "serde_json", "sp-core", "sp-runtime", "substrate-test-runtime-client", + "thiserror", ] [[package]] @@ -8743,7 +8768,9 @@ dependencies = [ "futures 0.3.16", "futures-timer", "lazy_static", + "parking_lot 0.11.2", "prometheus", + "tokio-test", ] [[package]] @@ -10745,6 +10772,19 @@ dependencies = [ "tokio-reactor", ] +[[package]] +name = "tokio-test" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53474327ae5e166530d17f2d956afcb4f8a004de581b3cae10f12006bc8163e3" +dependencies = [ + "async-stream", + "bytes 1.1.0", + "futures-core", + "tokio", + "tokio-stream", +] + [[package]] name = "tokio-tls" version = "0.2.1" diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index bc81732dcd41d..0f29804d6780e 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -8,8 +8,11 @@ repository = "https://github.com/paritytech/substrate" description = "RPC for the BEEFY Client gadget for substrate" [dependencies] +derive_more = "0.99" futures = "0.3.16" log = "0.4" +parking_lot = "0.11" +thiserror = "1.0" serde = { version = "1.0.132", features = ["derive"] } jsonrpc-core = "18.0.0" @@ -20,6 +23,7 @@ jsonrpc-pubsub = "18.0.0" codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive"] } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } +sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index be1c9b8691a2a..dc9ee8b94701b 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -20,19 +20,62 @@ #![warn(missing_docs)] +use parking_lot::RwLock; use std::sync::Arc; use sp_runtime::traits::Block as BlockT; -use futures::{FutureExt, SinkExt, StreamExt}; +use futures::{task::SpawnError, FutureExt, SinkExt, StreamExt, TryFutureExt}; use jsonrpc_derive::rpc; use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; use log::warn; -use beefy_gadget::notification::BeefySignedCommitmentStream; +use beefy_gadget::notification::{BeefyBestBlockStream, BeefySignedCommitmentStream}; mod notification; +type FutureResult = jsonrpc_core::BoxFuture>; + +#[derive(Debug, derive_more::Display, derive_more::From, thiserror::Error)] +/// Top-level error type for the RPC handler +pub enum Error { + /// The BEEFY RPC endpoint is not ready. + #[display(fmt = "BEEFY RPC endpoint not ready")] + EndpointNotReady, + /// The BEEFY RPC background task failed to spawn. + #[display(fmt = "BEEFY RPC background task failed to spawn")] + RpcTaskFailure(SpawnError), +} + +/// The error codes returned by jsonrpc. +pub enum ErrorCode { + /// Returned when BEEFY RPC endpoint is not ready. + NotReady = 1, + /// Returned on BEEFY RPC background task failure. + TaskFailure = 2, +} + +impl From for ErrorCode { + fn from(error: Error) -> Self { + match error { + Error::EndpointNotReady => ErrorCode::NotReady, + Error::RpcTaskFailure(_) => ErrorCode::TaskFailure, + } + } +} + +impl From for jsonrpc_core::Error { + fn from(error: Error) -> Self { + let message = format!("{}", error); + let code = ErrorCode::from(error); + jsonrpc_core::Error { + message, + code: jsonrpc_core::ErrorCode::ServerError(code as i64), + data: None, + } + } +} + /// Provides RPC methods for interacting with BEEFY. #[rpc] pub trait BeefyApi { @@ -62,26 +105,57 @@ pub trait BeefyApi { metadata: Option, id: SubscriptionId, ) -> jsonrpc_core::Result; + + /// Returns hash of the latest BEEFY finalized block as seen by this client. + /// + /// The latest BEEFY block might not be available if the BEEFY gadget is not running + /// in the network or if the client is still initializing or syncing with the network. + /// In such case an error would be returned. + #[rpc(name = "beefy_getFinalizedHead")] + fn latest_finalized(&self) -> FutureResult; } /// Implements the BeefyApi RPC trait for interacting with BEEFY. pub struct BeefyRpcHandler { signed_commitment_stream: BeefySignedCommitmentStream, + beefy_best_block: Arc>>, manager: SubscriptionManager, } impl BeefyRpcHandler { /// Creates a new BeefyRpcHandler instance. - pub fn new(signed_commitment_stream: BeefySignedCommitmentStream, executor: E) -> Self + pub fn new( + signed_commitment_stream: BeefySignedCommitmentStream, + best_block_stream: BeefyBestBlockStream, + executor: E, + ) -> Result where E: futures::task::Spawn + Send + Sync + 'static, { + let beefy_best_block = Arc::new(RwLock::new(None)); + + let stream = best_block_stream.subscribe(); + let closure_clone = beefy_best_block.clone(); + let future = stream.for_each(move |best_beefy| { + let async_clone = closure_clone.clone(); + async move { + *async_clone.write() = Some(best_beefy); + } + }); + + executor + .spawn_obj(futures::task::FutureObj::new(Box::pin(future))) + .map_err(|e| { + log::error!("Failed to spawn BEEFY RPC background task; err: {}", e); + e + })?; + let manager = SubscriptionManager::new(Arc::new(executor)); - Self { signed_commitment_stream, manager } + Ok(Self { signed_commitment_stream, beefy_best_block, manager }) } } -impl BeefyApi for BeefyRpcHandler +impl BeefyApi for BeefyRpcHandler where Block: BlockT, { @@ -90,12 +164,12 @@ where fn subscribe_justifications( &self, _metadata: Self::Metadata, - subscriber: Subscriber, + subscriber: Subscriber, ) { let stream = self .signed_commitment_stream .subscribe() - .map(|x| Ok::<_, ()>(Ok(notification::SignedCommitment::new::(x)))); + .map(|x| Ok::<_, ()>(Ok(notification::EncodedSignedCommitment::new::(x)))); self.manager.add(subscriber, |sink| { stream @@ -111,6 +185,17 @@ where ) -> jsonrpc_core::Result { Ok(self.manager.cancel(id)) } + + fn latest_finalized(&self) -> FutureResult { + let result: Result = self + .beefy_best_block + .read() + .as_ref() + .cloned() + .ok_or(Error::EndpointNotReady.into()); + let future = async move { result }.boxed(); + future.map_err(jsonrpc_core::Error::from).boxed() + } } #[cfg(test)] @@ -118,16 +203,30 @@ mod tests { use super::*; use jsonrpc_core::{types::Params, Notification, Output}; - use beefy_gadget::notification::{BeefySignedCommitmentSender, SignedCommitment}; + use beefy_gadget::notification::{BeefySignedCommitment, BeefySignedCommitmentSender}; use beefy_primitives::{known_payload_ids, Payload}; use codec::{Decode, Encode}; + use sp_runtime::traits::{BlakeTwo256, Hash}; use substrate_test_runtime_client::runtime::Block; fn setup_io_handler( ) -> (jsonrpc_core::MetaIoHandler, BeefySignedCommitmentSender) { - let (commitment_sender, commitment_stream) = BeefySignedCommitmentStream::channel(); + let (_, stream) = BeefyBestBlockStream::::channel(); + setup_io_handler_with_best_block_stream(stream) + } + + fn setup_io_handler_with_best_block_stream( + best_block_stream: BeefyBestBlockStream, + ) -> (jsonrpc_core::MetaIoHandler, BeefySignedCommitmentSender) { + let (commitment_sender, commitment_stream) = + BeefySignedCommitmentStream::::channel(); - let handler = BeefyRpcHandler::new(commitment_stream, sc_rpc::testing::TaskExecutor); + let handler: BeefyRpcHandler = BeefyRpcHandler::new( + commitment_stream, + best_block_stream, + sc_rpc::testing::TaskExecutor, + ) + .unwrap(); let mut io = jsonrpc_core::MetaIoHandler::default(); io.extend_with(BeefyApi::to_delegate(handler)); @@ -141,6 +240,56 @@ mod tests { (meta, rx) } + #[test] + fn uninitialized_rpc_handler() { + let (io, _) = setup_io_handler(); + + let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"BEEFY RPC endpoint not ready"},"id":1}"#; + + let meta = sc_rpc::Metadata::default(); + assert_eq!(Some(response.into()), io.handle_request_sync(request, meta)); + } + + #[test] + fn latest_finalized_rpc() { + let (sender, stream) = BeefyBestBlockStream::::channel(); + let (io, _) = setup_io_handler_with_best_block_stream(stream); + + let hash = BlakeTwo256::hash(b"42"); + let r: Result<(), ()> = sender.notify(|| Ok(hash)); + r.unwrap(); + + // Verify RPC `beefy_getFinalizedHead` returns expected hash. + let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; + let expected = "{\ + \"jsonrpc\":\"2.0\",\ + \"result\":\"0x2f0039e93a27221fcf657fb877a1d4f60307106113e885096cb44a461cd0afbf\",\ + \"id\":1\ + }"; + let not_ready = "{\ + \"jsonrpc\":\"2.0\",\ + \"error\":{\"code\":1,\"message\":\"BEEFY RPC endpoint not ready\"},\ + \"id\":1\ + }"; + + let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2); + while std::time::Instant::now() < deadline { + let meta = sc_rpc::Metadata::default(); + let response = io.handle_request_sync(request, meta); + // Retry "not ready" responses. + if response != Some(not_ready.into()) { + assert_eq!(response, Some(expected.into())); + // Success + return + } + std::thread::sleep(std::time::Duration::from_millis(50)); + } + panic!( + "Deadline reached while waiting for best BEEFY block to update. Perhaps the background task is broken?" + ); + } + #[test] fn subscribe_and_unsubscribe_to_justifications() { let (io, _) = setup_io_handler(); @@ -159,7 +308,7 @@ mod tests { // Unsubscribe let unsub_req = format!( - "{{\"jsonrpc\":\"2.0\",\"method\":\"beefy_unsubscribeJustifications\",\"params\":[{}],\"id\":1}}", + r#"{{"jsonrpc":"2.0","method":"beefy_unsubscribeJustifications","params":[{}],"id":1}}"#, sub_id ); assert_eq!( @@ -170,7 +319,7 @@ mod tests { // Unsubscribe again and fail assert_eq!( io.handle_request_sync(&unsub_req, meta), - Some("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32602,\"message\":\"Invalid subscription id.\"},\"id\":1}".into()), + Some(r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid subscription id."},"id":1}"#.into()), ); } @@ -192,13 +341,13 @@ mod tests { r#"{"jsonrpc":"2.0","method":"beefy_unsubscribeJustifications","params":["FOO"],"id":1}"#, meta.clone() ), - Some("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32602,\"message\":\"Invalid subscription id.\"},\"id\":1}".into()) + Some(r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid subscription id."},"id":1}"#.into()) ); } - fn create_commitment() -> SignedCommitment { + fn create_commitment() -> BeefySignedCommitment { let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); - SignedCommitment:: { + BeefySignedCommitment:: { commitment: beefy_primitives::Commitment { payload, block_number: 5, @@ -223,7 +372,8 @@ mod tests { // Notify with commitment let commitment = create_commitment(); - commitment_sender.notify(commitment.clone()); + let r: Result<(), ()> = commitment_sender.notify(|| Ok(commitment.clone())); + r.unwrap(); // Inspect what we received let recv = futures::executor::block_on(receiver.take(1).collect::>()); @@ -236,7 +386,7 @@ mod tests { let recv_sub_id: String = serde_json::from_value(json_map["subscription"].take()).unwrap(); let recv_commitment: sp_core::Bytes = serde_json::from_value(json_map["result"].take()).unwrap(); - let recv_commitment: SignedCommitment = + let recv_commitment: BeefySignedCommitment = Decode::decode(&mut &recv_commitment[..]).unwrap(); assert_eq!(recv.method, "beefy_justifications"); diff --git a/client/beefy/rpc/src/notification.rs b/client/beefy/rpc/src/notification.rs index 53c0bb618c5d5..2f58c7c6bb5dc 100644 --- a/client/beefy/rpc/src/notification.rs +++ b/client/beefy/rpc/src/notification.rs @@ -25,15 +25,15 @@ use sp_runtime::traits::Block as BlockT; /// The given bytes should be the SCALE-encoded representation of a /// `beefy_primitives::SignedCommitment`. #[derive(Clone, Serialize, Deserialize)] -pub struct SignedCommitment(sp_core::Bytes); +pub struct EncodedSignedCommitment(sp_core::Bytes); -impl SignedCommitment { +impl EncodedSignedCommitment { pub fn new( - signed_commitment: beefy_gadget::notification::SignedCommitment, + signed_commitment: beefy_gadget::notification::BeefySignedCommitment, ) -> Self where Block: BlockT, { - SignedCommitment(signed_commitment.encode().into()) + EncodedSignedCommitment(signed_commitment.encode().into()) } } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 7d2c3b57b1f70..9b2bf383df8ef 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -31,6 +31,8 @@ use sp_runtime::traits::Block; use beefy_primitives::BeefyApi; +use crate::notification::{BeefyBestBlockSender, BeefySignedCommitmentSender}; + mod error; mod gossip; mod keystore; @@ -121,7 +123,9 @@ where /// Gossip network pub network: N, /// BEEFY signed commitment sender - pub signed_commitment_sender: notification::BeefySignedCommitmentSender, + pub signed_commitment_sender: BeefySignedCommitmentSender, + /// BEEFY best block sender + pub beefy_best_block_sender: BeefyBestBlockSender, /// Minimal delta between blocks, BEEFY should vote for pub min_block_delta: u32, /// Prometheus metric registry @@ -147,6 +151,7 @@ where key_store, network, signed_commitment_sender, + beefy_best_block_sender, min_block_delta, prometheus_registry, protocol_name, @@ -174,6 +179,7 @@ where backend, key_store: key_store.into(), signed_commitment_sender, + beefy_best_block_sender, gossip_engine, gossip_validator, min_block_delta, diff --git a/client/beefy/src/notification.rs b/client/beefy/src/notification.rs index cd410ec60bb3c..7c18d809f6efb 100644 --- a/client/beefy/src/notification.rs +++ b/client/beefy/src/notification.rs @@ -16,98 +16,41 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::sync::Arc; +use sc_utils::notification::{NotificationSender, NotificationStream, TracingKeyStr}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; -use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; -use sp_runtime::traits::{Block, NumberFor}; - -use parking_lot::Mutex; - -/// Stream of signed commitments returned when subscribing. -pub type SignedCommitment = +/// A commitment with matching BEEFY authorities' signatures. +pub type BeefySignedCommitment = beefy_primitives::SignedCommitment, beefy_primitives::crypto::Signature>; -/// Stream of signed commitments returned when subscribing. -type SignedCommitmentStream = TracingUnboundedReceiver>; - -/// Sending endpoint for notifying about signed commitments. -type SignedCommitmentSender = TracingUnboundedSender>; - -/// Collection of channel sending endpoints shared with the receiver side so they can register -/// themselves. -type SharedSignedCommitmentSenders = Arc>>>; - -/// The sending half of the signed commitment channel(s). -/// -/// Used to send notifications about signed commitments generated at the end of a BEEFY round. -#[derive(Clone)] -pub struct BeefySignedCommitmentSender -where - B: Block, -{ - subscribers: SharedSignedCommitmentSenders, -} - -impl BeefySignedCommitmentSender -where - B: Block, -{ - /// The `subscribers` should be shared with a corresponding `SignedCommitmentSender`. - fn new(subscribers: SharedSignedCommitmentSenders) -> Self { - Self { subscribers } - } +/// The sending half of the notifications channel(s) used to send +/// notifications about best BEEFY block from the gadget side. +pub type BeefyBestBlockSender = NotificationSender<::Hash>; - /// Send out a notification to all subscribers that a new signed commitment is available for a - /// block. - pub fn notify(&self, signed_commitment: SignedCommitment) { - let mut subscribers = self.subscribers.lock(); +/// The receiving half of a notifications channel used to receive +/// notifications about best BEEFY blocks determined on the gadget side. +pub type BeefyBestBlockStream = + NotificationStream<::Hash, BeefyBestBlockTracingKey>; - // do an initial prune on closed subscriptions - subscribers.retain(|n| !n.is_closed()); +/// The sending half of the notifications channel(s) used to send notifications +/// about signed commitments generated at the end of a BEEFY round. +pub type BeefySignedCommitmentSender = NotificationSender>; - if !subscribers.is_empty() { - subscribers.retain(|n| n.unbounded_send(signed_commitment.clone()).is_ok()); - } - } -} +/// The receiving half of a notifications channel used to receive notifications +/// about signed commitments generated at the end of a BEEFY round. +pub type BeefySignedCommitmentStream = + NotificationStream, BeefySignedCommitmentTracingKey>; -/// The receiving half of the signed commitments channel. -/// -/// Used to receive notifications about signed commitments generated at the end of a BEEFY round. -/// The `BeefySignedCommitmentStream` entity stores the `SharedSignedCommitmentSenders` so it can be -/// used to add more subscriptions. +/// Provides tracing key for BEEFY best block stream. #[derive(Clone)] -pub struct BeefySignedCommitmentStream -where - B: Block, -{ - subscribers: SharedSignedCommitmentSenders, +pub struct BeefyBestBlockTracingKey; +impl TracingKeyStr for BeefyBestBlockTracingKey { + const TRACING_KEY: &'static str = "mpsc_beefy_best_block_notification_stream"; } -impl BeefySignedCommitmentStream -where - B: Block, -{ - /// Creates a new pair of receiver and sender of signed commitment notifications. - pub fn channel() -> (BeefySignedCommitmentSender, Self) { - let subscribers = Arc::new(Mutex::new(vec![])); - let receiver = BeefySignedCommitmentStream::new(subscribers.clone()); - let sender = BeefySignedCommitmentSender::new(subscribers); - (sender, receiver) - } - - /// Create a new receiver of signed commitment notifications. - /// - /// The `subscribers` should be shared with a corresponding `BeefySignedCommitmentSender`. - fn new(subscribers: SharedSignedCommitmentSenders) -> Self { - Self { subscribers } - } - - /// Subscribe to a channel through which signed commitments are sent at the end of each BEEFY - /// voting round. - pub fn subscribe(&self) -> SignedCommitmentStream { - let (sender, receiver) = tracing_unbounded("mpsc_signed_commitments_notification_stream"); - self.subscribers.lock().push(sender); - receiver - } +/// Provides tracing key for BEEFY signed commitments stream. +#[derive(Clone)] +pub struct BeefySignedCommitmentTracingKey; +impl TracingKeyStr for BeefySignedCommitmentTracingKey { + const TRACING_KEY: &'static str = "mpsc_beefy_signed_commitments_notification_stream"; } diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index d3aa988b8ee27..0c7d8d4ffdc9c 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -46,7 +46,8 @@ use crate::{ keystore::BeefyKeystore, metric_inc, metric_set, metrics::Metrics, - notification, round, Client, + notification::{BeefyBestBlockSender, BeefySignedCommitmentSender}, + round, Client, }; pub(crate) struct WorkerParams @@ -56,7 +57,8 @@ where pub client: Arc, pub backend: Arc, pub key_store: BeefyKeystore, - pub signed_commitment_sender: notification::BeefySignedCommitmentSender, + pub signed_commitment_sender: BeefySignedCommitmentSender, + pub beefy_best_block_sender: BeefyBestBlockSender, pub gossip_engine: GossipEngine, pub gossip_validator: Arc>, pub min_block_delta: u32, @@ -73,7 +75,7 @@ where client: Arc, backend: Arc, key_store: BeefyKeystore, - signed_commitment_sender: notification::BeefySignedCommitmentSender, + signed_commitment_sender: BeefySignedCommitmentSender, gossip_engine: Arc>>, gossip_validator: Arc>, /// Min delta in block numbers between two blocks, BEEFY should vote on @@ -85,6 +87,8 @@ where best_grandpa_block: NumberFor, /// Best block a BEEFY voting round has been concluded for best_beefy_block: Option>, + /// Used to keep RPC worker up to date on latest/best beefy + beefy_best_block_sender: BeefyBestBlockSender, /// Validator set id for the last signed commitment last_signed_id: u64, // keep rustc happy @@ -110,6 +114,7 @@ where backend, key_store, signed_commitment_sender, + beefy_best_block_sender, gossip_engine, gossip_validator, min_block_delta, @@ -130,6 +135,7 @@ where best_grandpa_block: client.info().finalized_number, best_beefy_block: None, last_signed_id: 0, + beefy_best_block_sender, _backend: PhantomData, } } @@ -242,6 +248,9 @@ where debug!(target: "beefy", "🥩 New Rounds for id: {:?}", id); self.best_beefy_block = Some(*notification.header.number()); + self.beefy_best_block_sender + .notify(|| Ok::<_, ()>(notification.hash.clone())) + .expect("forwards closure result; the closure always returns Ok; qed."); // this metric is kind of 'fake'. Best BEEFY block should only be updated once we // have a signed commitment for the block. Remove once the above TODO is done. @@ -329,22 +338,23 @@ where // id is stored for skipped session metric calculation self.last_signed_id = rounds.validator_set_id(); + let block_num = round.1; let commitment = Commitment { payload: round.0, - block_number: round.1, + block_number: block_num, validator_set_id: self.last_signed_id, }; let signed_commitment = SignedCommitment { commitment, signatures }; - metric_set!(self, beefy_round_concluded, round.1); + metric_set!(self, beefy_round_concluded, block_num); info!(target: "beefy", "🥩 Round #{} concluded, committed: {:?}.", round.1, signed_commitment); if self .backend .append_justification( - BlockId::Number(round.1), + BlockId::Number(block_num), ( BEEFY_ENGINE_ID, VersionedFinalityProof::V1(signed_commitment.clone()).encode(), @@ -356,11 +366,23 @@ where // conclude certain rounds multiple times. trace!(target: "beefy", "🥩 Failed to append justification: {:?}", signed_commitment); } + self.signed_commitment_sender + .notify(|| Ok::<_, ()>(signed_commitment)) + .expect("forwards closure result; the closure always returns Ok; qed."); + + self.best_beefy_block = Some(block_num); + if let Err(err) = self.client.hash(block_num).map(|h| { + if let Some(hash) = h { + self.beefy_best_block_sender + .notify(|| Ok::<_, ()>(hash)) + .expect("forwards closure result; the closure always returns Ok; qed."); + } + }) { + error!(target: "beefy", "🥩 Failed to get hash for block number {}; err: {:?}", + block_num, err); + } - self.signed_commitment_sender.notify(signed_commitment); - self.best_beefy_block = Some(round.1); - - metric_set!(self, beefy_best_block, round.1); + metric_set!(self, beefy_best_block, block_num); } } } diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index e509d435af4ad..bde2e5612b2e6 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -469,7 +469,7 @@ mod tests { // Notify with a header and justification let justification = create_justification(); - justification_sender.notify(|| Ok(justification.clone())).unwrap(); + justification_sender.notify(|| Ok::<_, ()>(justification.clone())).unwrap(); // Inspect what we received let recv = futures::executor::block_on(receiver.take(1).collect::>()); diff --git a/client/finality-grandpa/src/notification.rs b/client/finality-grandpa/src/notification.rs index 0d154fb3357e4..1d6e25e55dc65 100644 --- a/client/finality-grandpa/src/notification.rs +++ b/client/finality-grandpa/src/notification.rs @@ -16,61 +16,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use parking_lot::Mutex; -use std::sync::Arc; +use sc_utils::notification::{NotificationSender, NotificationStream, TracingKeyStr}; -use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; -use sp_runtime::traits::Block as BlockT; - -use crate::{justification::GrandpaJustification, Error}; - -// Stream of justifications returned when subscribing. -type JustificationStream = TracingUnboundedReceiver>; - -// Sending endpoint for notifying about justifications. -type JustificationSender = TracingUnboundedSender>; - -// Collection of channel sending endpoints shared with the receiver side so they can register -// themselves. -type SharedJustificationSenders = Arc>>>; +use crate::justification::GrandpaJustification; /// The sending half of the Grandpa justification channel(s). /// /// Used to send notifications about justifications generated /// at the end of a Grandpa round. -#[derive(Clone)] -pub struct GrandpaJustificationSender { - subscribers: SharedJustificationSenders, -} - -impl GrandpaJustificationSender { - /// The `subscribers` should be shared with a corresponding - /// `GrandpaJustificationStream`. - fn new(subscribers: SharedJustificationSenders) -> Self { - Self { subscribers } - } - - /// Send out a notification to all subscribers that a new justification - /// is available for a block. - pub fn notify( - &self, - justification: impl FnOnce() -> Result, Error>, - ) -> Result<(), Error> { - let mut subscribers = self.subscribers.lock(); - - // do an initial prune on closed subscriptions - subscribers.retain(|n| !n.is_closed()); - - // if there's no subscribers we avoid creating - // the justification which is a costly operation - if !subscribers.is_empty() { - let justification = justification()?; - subscribers.retain(|n| n.unbounded_send(justification.clone()).is_ok()); - } - - Ok(()) - } -} +pub type GrandpaJustificationSender = NotificationSender>; /// The receiving half of the Grandpa justification channel. /// @@ -78,33 +32,12 @@ impl GrandpaJustificationSender { /// at the end of a Grandpa round. /// The `GrandpaJustificationStream` entity stores the `SharedJustificationSenders` /// so it can be used to add more subscriptions. -#[derive(Clone)] -pub struct GrandpaJustificationStream { - subscribers: SharedJustificationSenders, -} - -impl GrandpaJustificationStream { - /// Creates a new pair of receiver and sender of justification notifications. - pub fn channel() -> (GrandpaJustificationSender, Self) { - let subscribers = Arc::new(Mutex::new(vec![])); - let receiver = GrandpaJustificationStream::new(subscribers.clone()); - let sender = GrandpaJustificationSender::new(subscribers.clone()); - (sender, receiver) - } +pub type GrandpaJustificationStream = + NotificationStream, GrandpaJustificationsTracingKey>; - /// Create a new receiver of justification notifications. - /// - /// The `subscribers` should be shared with a corresponding - /// `GrandpaJustificationSender`. - fn new(subscribers: SharedJustificationSenders) -> Self { - Self { subscribers } - } - - /// Subscribe to a channel through which justifications are sent - /// at the end of each Grandpa voting round. - pub fn subscribe(&self) -> JustificationStream { - let (sender, receiver) = tracing_unbounded("mpsc_justification_notification_stream"); - self.subscribers.lock().push(sender); - receiver - } +/// Provides tracing key for GRANDPA justifications stream. +#[derive(Clone)] +pub struct GrandpaJustificationsTracingKey; +impl TracingKeyStr for GrandpaJustificationsTracingKey { + const TRACING_KEY: &'static str = "mpsc_grandpa_justification_notification_stream"; } diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index 827164b702c6f..24075f932b508 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -12,9 +12,13 @@ readme = "README.md" [dependencies] futures = "0.3.9" lazy_static = "1.4.0" +parking_lot = "0.11" prometheus = { version = "0.13.0", default-features = false } futures-timer = "3.0.2" [features] default = ["metered"] metered = [] + +[dev-dependencies] +tokio-test = "0.4.2" diff --git a/client/utils/src/lib.rs b/client/utils/src/lib.rs index fab4365c8ed83..b3fb8400b12f6 100644 --- a/client/utils/src/lib.rs +++ b/client/utils/src/lib.rs @@ -38,4 +38,5 @@ pub mod metrics; pub mod mpsc; +pub mod notification; pub mod status_sinks; diff --git a/client/utils/src/notification.rs b/client/utils/src/notification.rs new file mode 100644 index 0000000000000..21d01c5f99fef --- /dev/null +++ b/client/utils/src/notification.rs @@ -0,0 +1,151 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Provides mpsc notification channel that can be instantiated +//! _after_ it's been shared to the consumer and producers entities. +//! +//! Useful when building RPC extensions where, at service definition time, we +//! don't know whether the specific interface where the RPC extension will be +//! exposed is safe or not and we want to lazily build the RPC extension +//! whenever we bind the service to an interface. +//! +//! See [`sc-service::builder::RpcExtensionBuilder`] for more details. + +use std::{marker::PhantomData, sync::Arc}; + +use crate::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; + +use parking_lot::Mutex; + +/// Collection of channel sending endpoints shared with the receiver side +/// so they can register themselves. +type SharedSenders = Arc>>>; + +/// Trait used to define the "tracing key" string used to tag +/// and identify the mpsc channels. +pub trait TracingKeyStr { + /// Const `str` representing the "tracing key" used to tag and identify + /// the mpsc channels owned by the object implemeting this trait. + const TRACING_KEY: &'static str; +} + +/// The sending half of the notifications channel(s). +/// +/// Used to send notifications from the BEEFY gadget side. +#[derive(Clone)] +pub struct NotificationSender { + subscribers: SharedSenders, +} + +impl NotificationSender { + /// The `subscribers` should be shared with a corresponding `NotificationStream`. + fn new(subscribers: SharedSenders) -> Self { + Self { subscribers } + } + + /// Send out a notification to all subscribers that a new payload is available for a + /// block. + pub fn notify( + &self, + payload: impl FnOnce() -> Result, + ) -> Result<(), Error> { + let mut subscribers = self.subscribers.lock(); + + // do an initial prune on closed subscriptions + subscribers.retain(|n| !n.is_closed()); + + if !subscribers.is_empty() { + let payload = payload()?; + subscribers.retain(|n| n.unbounded_send(payload.clone()).is_ok()); + } + + Ok(()) + } +} + +/// The receiving half of the notifications channel. +/// +/// The `NotificationStream` entity stores the `SharedSenders` so it can be +/// used to add more subscriptions. +#[derive(Clone)] +pub struct NotificationStream { + subscribers: SharedSenders, + _trace_key: PhantomData, +} + +impl NotificationStream { + /// Creates a new pair of receiver and sender of `Payload` notifications. + pub fn channel() -> (NotificationSender, Self) { + let subscribers = Arc::new(Mutex::new(vec![])); + let receiver = NotificationStream::new(subscribers.clone()); + let sender = NotificationSender::new(subscribers); + (sender, receiver) + } + + /// Create a new receiver of `Payload` notifications. + /// + /// The `subscribers` should be shared with a corresponding `NotificationSender`. + fn new(subscribers: SharedSenders) -> Self { + Self { subscribers, _trace_key: PhantomData } + } + + /// Subscribe to a channel through which the generic payload can be received. + pub fn subscribe(&self) -> TracingUnboundedReceiver { + let (sender, receiver) = tracing_unbounded(TK::TRACING_KEY); + self.subscribers.lock().push(sender); + receiver + } +} + +#[cfg(test)] +mod tests { + use super::*; + use futures::StreamExt; + + #[derive(Clone)] + pub struct DummyTracingKey; + impl TracingKeyStr for DummyTracingKey { + const TRACING_KEY: &'static str = "test_notification_stream"; + } + + type StringStream = NotificationStream; + + #[test] + fn notification_channel_simple() { + let (sender, stream) = StringStream::channel(); + + let test_payload = String::from("test payload"); + let closure_payload = test_payload.clone(); + + // Create a future to receive a single notification + // from the stream and verify its payload. + let future = stream.subscribe().take(1).for_each(move |payload| { + let test_payload = closure_payload.clone(); + async move { + assert_eq!(payload, test_payload); + } + }); + + // Send notification. + let r: std::result::Result<(), ()> = sender.notify(|| Ok(test_payload)); + r.unwrap(); + + // Run receiver future. + tokio_test::block_on(future); + } +} From c0f688d2c957d7a816b9abfad70d7d89a094996c Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 7 Jan 2022 19:33:52 +0000 Subject: [PATCH 0407/1472] Fix docs (#10606) --- frame/balances/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 86e3f2ec05984..5235dc97ccb4f 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -250,7 +250,6 @@ pub mod pallet { /// Transfer some liquid free balance to another account. /// /// `transfer` will set the `FreeBalance` of the sender and receiver. - /// It will decrease the total issuance of the system by the `TransferFee`. /// If the sender's account is below the existential deposit as a result /// of the transfer, the account will be reaped. /// @@ -293,7 +292,7 @@ pub mod pallet { /// Set the balances of a given account. /// /// This will alter `FreeBalance` and `ReservedBalance` in storage. it will - /// also decrease the total issuance of the system (`TotalIssuance`). + /// also alter the total issuance of the system (`TotalIssuance`) appropriately. /// If the new free or reserved balance is below the existential deposit, /// it will reset the account nonce (`frame_system::AccountNonce`). /// From e0543096a82a8b48146bd7c48091ff0c857a0001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Sat, 8 Jan 2022 13:19:23 +0100 Subject: [PATCH 0408/1472] Add additionally functionality to contracts storage interface (#10497) * Add new versions for storage access host functions * Improve docs --- frame/contracts/src/benchmarking/mod.rs | 177 +++- frame/contracts/src/exec.rs | 122 ++- frame/contracts/src/schedule.rs | 12 + frame/contracts/src/storage.rs | 39 +- frame/contracts/src/tests.rs | 9 +- frame/contracts/src/wasm/mod.rs | 314 +++++- frame/contracts/src/wasm/runtime.rs | 156 ++- frame/contracts/src/weights.rs | 1163 ++++++++++++----------- 8 files changed, 1392 insertions(+), 600 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 49344373f97d6..a0f5ceb034f78 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -134,7 +134,7 @@ where fn store(&self, items: &Vec<(StorageKey, Vec)>) -> Result<(), &'static str> { let info = self.info()?; for item in items { - Storage::::write(&info.trie_id, &item.0, Some(item.1.clone()), None) + Storage::::write(&info.trie_id, &item.0, Some(item.1.clone()), None, false) .map_err(|_| "Failed to write storage to restoration dest")?; } >::insert(&self.account_id, info.clone()); @@ -784,10 +784,10 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", + module: "__unstable__", name: "seal_set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32], - return_type: None, + return_type: Some(ValueType::I32), }], data_segments: vec![ DataSegment { @@ -800,6 +800,7 @@ benchmarks! { Regular(Instruction::I32Const(0)), // value_ptr Regular(Instruction::I32Const(0)), // value_len Regular(Instruction::Call(0)), + Regular(Instruction::Drop), ])), .. Default::default() }); @@ -814,10 +815,10 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", + module: "__unstable__", name: "seal_set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32], - return_type: None, + return_type: Some(ValueType::I32), }], data_segments: vec![ DataSegment { @@ -830,6 +831,7 @@ benchmarks! { Instruction::I32Const(0), // value_ptr Instruction::I32Const((n * 1024) as i32), // value_len Instruction::Call(0), + Instruction::Drop, ])), .. Default::default() }); @@ -851,10 +853,10 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", + module: "__unstable__", name: "seal_clear_storage", params: vec![ValueType::I32], - return_type: None, + return_type: Some(ValueType::I32), }], data_segments: vec![ DataSegment { @@ -865,6 +867,7 @@ benchmarks! { call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ Counter(0, key_len as u32), Regular(Instruction::Call(0)), + Regular(Instruction::Drop), ])), .. Default::default() }); @@ -876,6 +879,7 @@ benchmarks! { key.as_slice().try_into().map_err(|e| "Key has wrong length")?, Some(vec![42; T::Schedule::get().limits.payload_len as usize]), None, + false, ) .map_err(|_| "Failed to write to storage during setup.")?; } @@ -906,6 +910,10 @@ benchmarks! { offset: 0, value: key_bytes, }, + DataSegment { + offset: key_bytes_len as u32, + value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), + }, ], call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ Counter(0, key_len as u32), // key_ptr @@ -924,6 +932,54 @@ benchmarks! { key.as_slice().try_into().map_err(|e| "Key has wrong length")?, Some(vec![]), None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; + } + >::insert(&instance.account_id, info.clone()); + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + + // We make sure that all storage accesses are to unique keys. + #[skip_meta] + seal_contains_storage { + let r in 0 .. API_BENCHMARK_BATCHES; + let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) + .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) + .collect::>(); + let key_len = sp_std::mem::size_of::<::Output>(); + let key_bytes = keys.iter().flatten().cloned().collect::>(); + let key_bytes_len = key_bytes.len(); + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_contains_storage", + params: vec![ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: key_bytes, + }, + ], + call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, key_len as u32), // key_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let info = instance.info()?; + for key in keys { + Storage::::write( + &info.trie_id, + key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + Some(vec![42; T::Schedule::get().limits.payload_len as usize]), + None, + false, ) .map_err(|_| "Failed to write to storage during setup.")?; } @@ -970,12 +1026,117 @@ benchmarks! { key.as_slice().try_into().map_err(|e| "Key has wrong length")?, Some(vec![42u8; (n * 1024) as usize]), None, + false, ) .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info.clone()); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[skip_meta] + seal_take_storage { + let r in 0 .. API_BENCHMARK_BATCHES; + let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) + .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) + .collect::>(); + let key_len = sp_std::mem::size_of::<::Output>(); + let key_bytes = keys.iter().flatten().cloned().collect::>(); + let key_bytes_len = key_bytes.len(); + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_take_storage", + params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: key_bytes, + }, + DataSegment { + offset: key_bytes_len as u32, + value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), + }, + ], + call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, key_len as u32), // key_ptr + Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr + Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let info = instance.info()?; + for key in keys { + Storage::::write( + &info.trie_id, + key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + Some(vec![]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; + } + >::insert(&instance.account_id, info.clone()); + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + + #[skip_meta] + seal_take_storage_per_kb { + let n in 0 .. T::Schedule::get().limits.payload_len / 1024; + let keys = (0 .. API_BENCHMARK_BATCH_SIZE) + .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) + .collect::>(); + let key_len = sp_std::mem::size_of::<::Output>(); + let key_bytes = keys.iter().flatten().cloned().collect::>(); + let key_bytes_len = key_bytes.len(); + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_take_storage", + params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: key_bytes, + }, + DataSegment { + offset: key_bytes_len as u32, + value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), + }, + ], + call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, key_len as u32), // key_ptr + Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr + Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let info = instance.info()?; + for key in keys { + Storage::::write( + &info.trie_id, + key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + Some(vec![42u8; (n * 1024) as usize]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; + } + >::insert(&instance.account_id, info.clone()); + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + // We transfer to unique accounts. seal_transfer { let r in 0 .. API_BENCHMARK_BATCHES; @@ -2285,7 +2446,7 @@ benchmarks! { // configured `Schedule` during benchmark development. // It can be outputed using the following command: // cargo run --manifest-path=bin/node/cli/Cargo.toml --release \ - // --features runtime-benchmarks -- benchmark --dev --execution=native \ + // --features runtime-benchmarks -- benchmark --extra --dev --execution=native \ // -p pallet_contracts -e print_schedule --no-median-slopes --no-min-squares #[extra] print_schedule { diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 97f301d162afb..679a6adde9221 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -17,7 +17,7 @@ use crate::{ gas::GasMeter, - storage::{self, Storage}, + storage::{self, Storage, WriteOutcome}, AccountCounter, BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Error, Event, Pallet as Contracts, Schedule, }; @@ -140,9 +140,20 @@ pub trait Ext: sealing::Sealed { /// was deleted. fn get_storage(&mut self, key: &StorageKey) -> Option>; + /// Returns true iff some storage entry exists under the supplied `key` + /// + /// Returns `false` if the `key` wasn't previously set by `set_storage` or + /// was deleted. + fn contains_storage(&mut self, key: &StorageKey) -> bool; + /// Sets the storage entry by the given key to the specified value. If `value` is `None` then /// the storage entry is deleted. - fn set_storage(&mut self, key: StorageKey, value: Option>) -> DispatchResult; + fn set_storage( + &mut self, + key: StorageKey, + value: Option>, + take_old: bool, + ) -> Result; /// Returns a reference to the account id of the caller. fn caller(&self) -> &AccountIdOf; @@ -985,13 +996,23 @@ where Storage::::read(&self.top_frame_mut().contract_info().trie_id, key) } - fn set_storage(&mut self, key: StorageKey, value: Option>) -> DispatchResult { + fn contains_storage(&mut self, key: &StorageKey) -> bool { + Storage::::contains(&self.top_frame_mut().contract_info().trie_id, key) + } + + fn set_storage( + &mut self, + key: StorageKey, + value: Option>, + take_old: bool, + ) -> Result { let frame = self.top_frame_mut(); Storage::::write( &frame.contract_info.get(&frame.account_id).trie_id, &key, value, Some(&mut frame.nested_storage), + take_old, ) } @@ -2349,4 +2370,99 @@ mod tests { assert_eq!(>::get(), 4); }); } + + #[test] + fn set_storage_works() { + let code_hash = MockLoader::insert(Call, |ctx, _| { + // Write + assert_eq!( + ctx.ext.set_storage([1; 32], Some(vec![1, 2, 3]), false), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage([2; 32], Some(vec![4, 5, 6]), true), + Ok(WriteOutcome::New) + ); + assert_eq!(ctx.ext.set_storage([3; 32], None, false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage([4; 32], None, true), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage([5; 32], Some(vec![]), false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage([6; 32], Some(vec![]), true), Ok(WriteOutcome::New)); + + // Overwrite + assert_eq!( + ctx.ext.set_storage([1; 32], Some(vec![42]), false), + Ok(WriteOutcome::Overwritten(3)) + ); + assert_eq!( + ctx.ext.set_storage([2; 32], Some(vec![48]), true), + Ok(WriteOutcome::Taken(vec![4, 5, 6])) + ); + assert_eq!(ctx.ext.set_storage([3; 32], None, false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage([4; 32], None, true), Ok(WriteOutcome::New)); + assert_eq!( + ctx.ext.set_storage([5; 32], Some(vec![]), false), + Ok(WriteOutcome::Overwritten(0)) + ); + assert_eq!( + ctx.ext.set_storage([6; 32], Some(vec![]), true), + Ok(WriteOutcome::Taken(vec![])) + ); + + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); + let schedule = ::Schedule::get(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + set_balance(&ALICE, min_balance * 1000); + place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap(); + assert_ok!(MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + None, + )); + }); + } + + #[test] + fn contains_storage_works() { + let code_hash = MockLoader::insert(Call, |ctx, _| { + assert_eq!( + ctx.ext.set_storage([1; 32], Some(vec![1, 2, 3]), false), + Ok(WriteOutcome::New) + ); + assert_eq!(ctx.ext.set_storage([2; 32], Some(vec![]), false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.contains_storage(&[1; 32]), true); + assert_eq!(ctx.ext.contains_storage(&[1; 32]), true); + assert_eq!(ctx.ext.contains_storage(&[3; 32]), false); + + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); + let schedule = ::Schedule::get(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + set_balance(&ALICE, min_balance * 1000); + place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap(); + assert_ok!(MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + None, + )); + }); + } } diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index dd066bfbe41ee..f3bfaea242777 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -322,12 +322,21 @@ pub struct HostFnWeights { /// Weight of calling `seal_clear_storage`. pub clear_storage: Weight, + /// Weight of calling `seal_contains_storage`. + pub contains_storage: Weight, + /// Weight of calling `seal_get_storage`. pub get_storage: Weight, /// Weight per byte of an item received via `seal_get_storage`. pub get_storage_per_byte: Weight, + /// Weight of calling `seal_take_storage`. + pub take_storage: Weight, + + /// Weight per byte of an item received via `seal_take_storage`. + pub take_storage_per_byte: Weight, + /// Weight of calling `seal_transfer`. pub transfer: Weight, @@ -579,8 +588,11 @@ impl Default for HostFnWeights { set_storage: cost_batched!(seal_set_storage), set_storage_per_byte: cost_byte_batched!(seal_set_storage_per_kb), clear_storage: cost_batched!(seal_clear_storage), + contains_storage: cost_batched!(seal_contains_storage), get_storage: cost_batched!(seal_get_storage), get_storage_per_byte: cost_byte_batched!(seal_get_storage_per_kb), + take_storage: cost_batched!(seal_take_storage), + take_storage_per_byte: cost_byte_batched!(seal_take_storage_per_kb), transfer: cost_batched!(seal_transfer), call: cost_batched!(seal_call), call_transfer_surcharge: cost_batched_args!( diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 7b0671da10582..b84cd1d2538e1 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -72,6 +72,21 @@ pub struct DeletedContract { pub(crate) trie_id: TrieId, } +/// Information about what happended to the pre-existing value when calling [`Storage::write`]. +#[cfg_attr(test, derive(Debug, PartialEq))] +pub enum WriteOutcome { + /// No value existed at the specified key. + New, + /// A value of the returned length was overwritten. + Overwritten(u32), + /// The returned value was taken out of storage before being overwritten. + /// + /// This is only returned when specifically requested because it causes additional work + /// depending on the size of the pre-existing value. When not requested [`Self::Overwritten`] + /// is returned instead. + Taken(Vec), +} + pub struct Storage(PhantomData); impl Storage @@ -87,9 +102,15 @@ where child::get_raw(&child_trie_info(trie_id), &blake2_256(key)) } + /// Returns `true` iff the `key` exists in storage. + pub fn contains(trie_id: &TrieId, key: &StorageKey) -> bool { + child::exists(&child_trie_info(trie_id), &blake2_256(key)) + } + /// Update a storage entry into a contract's kv storage. /// - /// If the `new_value` is `None` then the kv pair is removed. + /// If the `new_value` is `None` then the kv pair is removed. If `take` is true + /// a [`WriteOutcome::Taken`] is returned instead of a [`WriteOutcome::Overwritten`]. /// /// This function also records how much storage was created or removed if a `storage_meter` /// is supplied. It should only be absent for testing or benchmarking code. @@ -98,13 +119,19 @@ where key: &StorageKey, new_value: Option>, storage_meter: Option<&mut meter::NestedMeter>, - ) -> DispatchResult { + take: bool, + ) -> Result { let hashed_key = blake2_256(key); let child_trie_info = &child_trie_info(trie_id); + let (old_len, old_value) = if take { + let val = child::get_raw(&child_trie_info, &hashed_key); + (val.as_ref().map(|v| v.len() as u32), val) + } else { + (child::len(&child_trie_info, &hashed_key), None) + }; if let Some(storage_meter) = storage_meter { let mut diff = meter::Diff::default(); - let old_len = child::len(&child_trie_info, &hashed_key); match (old_len, new_value.as_ref().map(|v| v.len() as u32)) { (Some(old_len), Some(new_len)) => if new_len > old_len { @@ -130,7 +157,11 @@ where None => child::kill(&child_trie_info, &hashed_key), } - Ok(()) + Ok(match (old_len, old_value) { + (None, _) => WriteOutcome::New, + (Some(old_len), None) => WriteOutcome::Overwritten(old_len), + (Some(_), Some(old_value)) => WriteOutcome::Taken(old_value), + }) } /// Creates a new contract descriptor in the storage with the given code hash at the given diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 4cbc37c57ff21..17e8f746be1ff 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -1545,7 +1545,8 @@ fn lazy_removal_partial_remove_works() { // Put value into the contracts child trie for val in &vals { - Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None).unwrap(); + Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None, false) + .unwrap(); } >::insert(&addr, info.clone()); @@ -1629,7 +1630,8 @@ fn lazy_removal_does_no_run_on_full_block() { // Put value into the contracts child trie for val in &vals { - Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None).unwrap(); + Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None, false) + .unwrap(); } >::insert(&addr, info.clone()); @@ -1712,7 +1714,8 @@ fn lazy_removal_does_not_use_all_weight() { // Put value into the contracts child trie for val in &vals { - Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None).unwrap(); + Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None, false) + .unwrap(); } >::insert(&addr, info.clone()); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index ee7f557d34f01..f63361a039301 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -257,21 +257,22 @@ mod tests { AccountIdOf, BlockNumberOf, ErrorOrigin, ExecError, Executable, Ext, SeedOf, StorageKey, }, gas::GasMeter, + storage::WriteOutcome, tests::{Call, Test, ALICE, BOB}, BalanceOf, CodeHash, Error, Pallet as Contracts, }; use assert_matches::assert_matches; - use frame_support::{ - assert_ok, - dispatch::{DispatchResult, DispatchResultWithPostInfo}, - weights::Weight, - }; + use frame_support::{assert_ok, dispatch::DispatchResultWithPostInfo, weights::Weight}; use hex_literal::hex; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pretty_assertions::assert_eq; use sp_core::{Bytes, H256}; use sp_runtime::DispatchError; - use std::{borrow::BorrowMut, cell::RefCell, collections::HashMap}; + use std::{ + borrow::BorrowMut, + cell::RefCell, + collections::hash_map::{Entry, HashMap}, + }; #[derive(Debug, PartialEq, Eq)] struct InstantiateEntry { @@ -384,9 +385,26 @@ mod tests { fn get_storage(&mut self, key: &StorageKey) -> Option> { self.storage.get(key).cloned() } - fn set_storage(&mut self, key: StorageKey, value: Option>) -> DispatchResult { - *self.storage.entry(key).or_insert(Vec::new()) = value.unwrap_or(Vec::new()); - Ok(()) + fn contains_storage(&mut self, key: &StorageKey) -> bool { + self.storage.contains_key(key) + } + fn set_storage( + &mut self, + key: StorageKey, + value: Option>, + take_old: bool, + ) -> Result { + let entry = self.storage.entry(key); + let result = match (entry, take_old) { + (Entry::Vacant(_), _) => WriteOutcome::New, + (Entry::Occupied(entry), false) => + WriteOutcome::Overwritten(entry.remove().len() as u32), + (Entry::Occupied(entry), true) => WriteOutcome::Taken(entry.remove()), + }; + if let Some(value) = value { + self.storage.insert(key, value); + } + Ok(result) } fn caller(&self) -> &AccountIdOf { &ALICE @@ -932,8 +950,8 @@ mod tests { "\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11" ) - ;; [32, 36) buffer size = 128 bytes - (data (i32.const 32) "\80") + ;; [32, 36) buffer size = 4k in little endian + (data (i32.const 32) "\00\10") ;; [36; inf) buffer where the result is copied @@ -1957,4 +1975,278 @@ mod tests { ); assert_eq!(*ext.runtime_calls.borrow(), vec![]); } + + #[test] + #[cfg(feature = "unstable-interface")] + fn set_storage_works() { + const CODE: &str = r#" +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "__unstable__" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; 0x1000 = 4k in little endian + ;; size of input buffer + (data (i32.const 0) "\00\10") + + (func (export "call") + ;; Receive (key ++ value_to_write) + (call $seal_input + (i32.const 4) ;; Pointer to the input buffer + (i32.const 0) ;; Size of the length buffer + ) + ;; Store the passed value to the passed key and store result to memory + (i32.store (i32.const 0) + (call $seal_set_storage + (i32.const 4) ;; key_ptr + (i32.const 36) ;; value_ptr + (i32.sub ;; value_len (input_size - key_size) + (i32.load (i32.const 0)) + (i32.const 32) + ) + ) + ) + (call $seal_return + (i32.const 0) ;; flags + (i32.const 0) ;; returned value + (i32.const 4) ;; length of returned value + ) + ) + + (func (export "deploy")) +) +"#; + + let mut ext = MockExt::default(); + + // value did not exist before -> sentinel returned + let input = ([1u8; 32], [42u8, 48]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), u32::MAX); + assert_eq!(ext.storage.get(&[1u8; 32]).unwrap(), &[42u8, 48]); + + // value do exist -> length of old value returned + let input = ([1u8; 32], [0u8; 0]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 2); + assert_eq!(ext.storage.get(&[1u8; 32]).unwrap(), &[0u8; 0]); + + // value do exist -> length of old value returned (test for zero sized val) + let input = ([1u8; 32], [99u8]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(ext.storage.get(&[1u8; 32]).unwrap(), &[99u8]); + } + + #[test] + #[cfg(feature = "unstable-interface")] + fn clear_storage_works() { + const CODE: &str = r#" +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "__unstable__" "seal_clear_storage" (func $seal_clear_storage (param i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; 0x1000 = 4k in little endian + ;; size of input buffer + (data (i32.const 0) "\00\10") + + (func (export "call") + ;; Receive key + (call $seal_input + (i32.const 4) ;; Pointer to the input buffer + (i32.const 0) ;; Size of the length buffer + ) + ;; Store the passed value to the passed key and store result to memory + (i32.store (i32.const 0) + (call $seal_clear_storage + (i32.const 4) ;; key_ptr + ) + ) + (call $seal_return + (i32.const 0) ;; flags + (i32.const 0) ;; returned value + (i32.const 4) ;; length of returned value + ) + ) + + (func (export "deploy")) +) +"#; + + let mut ext = MockExt::default(); + + ext.storage.insert([1u8; 32], vec![42u8]); + ext.storage.insert([2u8; 32], vec![]); + + // value does not exist -> sentinel returned + let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), u32::MAX); + assert_eq!(ext.storage.get(&[3u8; 32]), None); + + // value did exist -> length returned + let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1); + assert_eq!(ext.storage.get(&[1u8; 32]), None); + + // value did exist -> length returned (test for 0 sized) + let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(ext.storage.get(&[2u8; 32]), None); + } + + #[test] + #[cfg(feature = "unstable-interface")] + fn take_storage_works() { + const CODE: &str = r#" +(module + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "__unstable__" "seal_take_storage" (func $seal_take_storage (param i32 i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 32) size of input buffer (32 byte as we copy the key here) + (data (i32.const 0) "\20") + + ;; [32, 64) size of output buffer + ;; 4k in little endian + (data (i32.const 32) "\00\10") + + ;; [64, 96) input buffer + + ;; [96, inf) output buffer + + (func (export "call") + ;; Receive key + (call $seal_input + (i32.const 64) ;; Pointer to the input buffer + (i32.const 0) ;; Size of the length buffer + ) + + ;; Load a storage value and result of this call into the output buffer + (i32.store (i32.const 96) + (call $seal_take_storage + (i32.const 64) ;; The pointer to the storage key to fetch + (i32.const 100) ;; Pointer to the output buffer + (i32.const 32) ;; Pointer to the size of the buffer + ) + ) + + ;; Return the contents of the buffer + (call $seal_return + (i32.const 0) ;; flags + (i32.const 96) ;; output buffer ptr + (i32.add ;; length: storage size + 4 (retval) + (i32.load (i32.const 32)) + (i32.const 4) + ) + ) + ) + + (func (export "deploy")) +) +"#; + + let mut ext = MockExt::default(); + + ext.storage.insert([1u8; 32], vec![42u8]); + ext.storage.insert([2u8; 32], vec![]); + + // value does not exist -> error returned + let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); + assert_eq!( + u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + ReturnCode::KeyNotFound as u32 + ); + + // value did exist -> value returned + let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); + assert_eq!( + u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + ReturnCode::Success as u32 + ); + assert_eq!(ext.storage.get(&[1u8; 32]), None); + assert_eq!(&result.data.0[4..], &[42u8]); + + // value did exist -> length returned (test for 0 sized) + let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); + assert_eq!( + u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + ReturnCode::Success as u32 + ); + assert_eq!(ext.storage.get(&[2u8; 32]), None); + assert_eq!(&result.data.0[4..], &[0u8; 0]); + } + + #[test] + #[cfg(feature = "unstable-interface")] + fn contains_storage_works() { + const CODE: &str = r#" +(module + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "__unstable__" "seal_contains_storage" (func $seal_contains_storage (param i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 4) size of input buffer (32 byte as we copy the key here) + (data (i32.const 0) "\20") + + ;; [4, 36) input buffer + + ;; [36, inf) output buffer + + (func (export "call") + ;; Receive key + (call $seal_input + (i32.const 4) ;; Pointer to the input buffer + (i32.const 0) ;; Size of the length buffer + ) + + ;; Load the return value into the output buffer + (i32.store (i32.const 36) + (call $seal_contains_storage + (i32.const 4) ;; The pointer to the storage key to fetch + ) + ) + + ;; Return the contents of the buffer + (call $seal_return + (i32.const 0) ;; flags + (i32.const 36) ;; output buffer ptr + (i32.const 4) ;; result is integer (4 bytes) + ) + ) + + (func (export "deploy")) +) +"#; + + let mut ext = MockExt::default(); + + ext.storage.insert([1u8; 32], vec![42u8]); + ext.storage.insert([2u8; 32], vec![]); + + // value does not exist -> error returned + let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); + assert_eq!( + u32::from_le_bytes(result.data.0.try_into().unwrap()), + ReturnCode::KeyNotFound as u32 + ); + + // value did exist -> success + let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); + assert_eq!( + u32::from_le_bytes(result.data.0.try_into().unwrap()), + ReturnCode::Success as u32 + ); + + // value did exist -> success (zero sized type) + let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); + assert_eq!( + u32::from_le_bytes(result.data.0.try_into().unwrap()), + ReturnCode::Success as u32 + ); + } } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 7c9e19f6ef78a..8b07329e5db43 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -21,6 +21,7 @@ use crate::{ exec::{ExecError, ExecResult, Ext, StorageKey, TopicOf}, gas::{ChargedAmount, Token}, schedule::HostFnWeights, + storage::WriteOutcome, wasm::env_def::ConvertibleToWasm, BalanceOf, CodeHash, Config, Error, }; @@ -172,10 +173,19 @@ pub enum RuntimeCosts { SetStorage(u32), /// Weight of calling `seal_clear_storage`. ClearStorage, + /// Weight of calling `seal_contains_storage`. + #[cfg(feature = "unstable-interface")] + ContainsStorage, /// Weight of calling `seal_get_storage` without output weight. GetStorageBase, /// Weight of an item received via `seal_get_storage` for the given size. GetStorageCopyOut(u32), + /// Weight of calling `seal_take_storage` without output weight. + #[cfg(feature = "unstable-interface")] + TakeStorageBase, + /// Weight of an item received via `seal_take_storage` for the given size. + #[cfg(feature = "unstable-interface")] + TakeStorageCopyOut(u32), /// Weight of calling `seal_transfer`. Transfer, /// Weight of calling `seal_call` for the given input size. @@ -242,8 +252,14 @@ impl RuntimeCosts { SetStorage(len) => s.set_storage.saturating_add(s.set_storage_per_byte.saturating_mul(len.into())), ClearStorage => s.clear_storage, + #[cfg(feature = "unstable-interface")] + ContainsStorage => s.contains_storage, GetStorageBase => s.get_storage, GetStorageCopyOut(len) => s.get_storage_per_byte.saturating_mul(len.into()), + #[cfg(feature = "unstable-interface")] + TakeStorageBase => s.take_storage, + #[cfg(feature = "unstable-interface")] + TakeStorageCopyOut(len) => s.take_storage_per_byte.saturating_mul(len.into()), Transfer => s.transfer, CallBase(len) => s.call.saturating_add(s.call_per_input_byte.saturating_mul(len.into())), @@ -632,6 +648,50 @@ where } } + /// Extracts the size of the overwritten value or `u32::MAX` if there + /// was no value in storage. + /// + /// # Note + /// + /// We cannot use `0` as sentinel value because there could be a zero sized + /// storage entry which is different from a non existing one. + fn overwritten_len(outcome: WriteOutcome) -> u32 { + match outcome { + WriteOutcome::New => u32::MAX, + WriteOutcome::Overwritten(len) => len, + WriteOutcome::Taken(value) => value.len() as u32, + } + } + + fn set_storage( + &mut self, + key_ptr: u32, + value_ptr: u32, + value_len: u32, + ) -> Result { + self.charge_gas(RuntimeCosts::SetStorage(value_len))?; + if value_len > self.ext.max_value_size() { + Err(Error::::ValueTooLarge)?; + } + let mut key: StorageKey = [0; 32]; + self.read_sandbox_memory_into_buf(key_ptr, &mut key)?; + let value = Some(self.read_sandbox_memory(value_ptr, value_len)?); + self.ext + .set_storage(key, value, false) + .map(Self::overwritten_len) + .map_err(Into::into) + } + + fn clear_storage(&mut self, key_ptr: u32) -> Result { + self.charge_gas(RuntimeCosts::ClearStorage)?; + let mut key: StorageKey = [0; 32]; + self.read_sandbox_memory_into_buf(key_ptr, &mut key)?; + self.ext + .set_storage(key, None, false) + .map(Self::overwritten_len) + .map_err(Into::into) + } + fn call( &mut self, flags: CallFlags, @@ -745,10 +805,18 @@ define_env!(Env, , Ok(()) }, + // Set the value at the given key in the contract storage. + // + // Equivalent to the newer version of `seal_set_storage` with the exception of the return + // type. Still a valid thing to call when not interested in the return value. + [seal0] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) => { + ctx.set_storage(key_ptr, value_ptr, value_len).map(|_| ()) + }, + // Set the value at the given key in the contract storage. // // The value length must not exceed the maximum defined by the contracts module parameters. - // Storing an empty value is disallowed. + // Specifying a `value_len` of zero will store an empty value. // // # Parameters // @@ -756,19 +824,20 @@ define_env!(Env, , // - `value_ptr`: pointer into the linear memory where the value to set is placed. // - `value_len`: the length of the value in bytes. // - // # Traps + // # Return Value // - // - If value length exceeds the configured maximum value length of a storage entry. - // - Upon trying to set an empty storage entry (value length is 0). - [seal0] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) => { - ctx.charge_gas(RuntimeCosts::SetStorage(value_len))?; - if value_len > ctx.ext.max_value_size() { - Err(Error::::ValueTooLarge)?; - } - let mut key: StorageKey = [0; 32]; - ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; - let value = Some(ctx.read_sandbox_memory(value_ptr, value_len)?); - ctx.ext.set_storage(key, value).map_err(Into::into) + // Returns the size of the pre-existing value at the specified key if any. Otherwise + // `u32::MAX` is returned as a sentinel value. + [__unstable__] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) -> u32 => { + ctx.set_storage(key_ptr, value_ptr, value_len) + }, + + // Clear the value at the given key in the contract storage. + // + // Equivalent to the newer version of `seal_clear_storage` with the exception of the return + // type. Still a valid thing to call when not interested in the return value. + [seal0] seal_clear_storage(ctx, key_ptr: u32) => { + ctx.clear_storage(key_ptr).map(|_| ()).map_err(Into::into) }, // Clear the value at the given key in the contract storage. @@ -776,11 +845,13 @@ define_env!(Env, , // # Parameters // // - `key_ptr`: pointer into the linear memory where the location to clear the value is placed. - [seal0] seal_clear_storage(ctx, key_ptr: u32) => { - ctx.charge_gas(RuntimeCosts::ClearStorage)?; - let mut key: StorageKey = [0; 32]; - ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; - ctx.ext.set_storage(key, None).map_err(Into::into) + // + // # Return Value + // + // Returns the size of the pre-existing value at the specified key if any. Otherwise + // `u32::MAX` is returned as a sentinel value. + [__unstable__] seal_clear_storage(ctx, key_ptr: u32) -> u32 => { + ctx.clear_storage(key_ptr).map_err(Into::into) }, // Retrieve the value under the given key from storage. @@ -809,6 +880,55 @@ define_env!(Env, , } }, + // Checks whether there is a value stored under the given key. + // + // Returns `ReturnCode::Success` if there is a key in storage. Otherwise an error + // is returned. + // + // # Parameters + // + // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. + // + // # Errors + // + // `ReturnCode::KeyNotFound` + [__unstable__] seal_contains_storage(ctx, key_ptr: u32) -> ReturnCode => { + ctx.charge_gas(RuntimeCosts::ContainsStorage)?; + let mut key: StorageKey = [0; 32]; + ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; + if ctx.ext.contains_storage(&key) { + Ok(ReturnCode::Success) + } else { + Ok(ReturnCode::KeyNotFound) + } + }, + + // Retrieve and remove the value under the given key from storage. + // + // # Parameters + // + // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. + // - `out_ptr`: pointer to the linear memory where the value is written to. + // - `out_len_ptr`: in-out pointer into linear memory where the buffer length + // is read from and the value length is written to. + // + // # Errors + // + // `ReturnCode::KeyNotFound` + [__unstable__] seal_take_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { + ctx.charge_gas(RuntimeCosts::TakeStorageBase)?; + let mut key: StorageKey = [0; 32]; + ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; + if let WriteOutcome::Taken(value) = ctx.ext.set_storage(key, None, true)? { + ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, |len| { + Some(RuntimeCosts::TakeStorageCopyOut(len)) + })?; + Ok(ReturnCode::Success) + } else { + Ok(ReturnCode::KeyNotFound) + } + }, + // Transfer some value to another account. // // # Parameters diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index d60a8ab82f3b0..17ee020f01134 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-12-09, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-12-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -77,7 +77,10 @@ pub trait WeightInfo { fn seal_set_storage_per_kb(n: u32, ) -> Weight; fn seal_clear_storage(r: u32, ) -> Weight; fn seal_get_storage(r: u32, ) -> Weight; + fn seal_contains_storage(r: u32, ) -> Weight; fn seal_get_storage_per_kb(n: u32, ) -> Weight; + fn seal_take_storage(r: u32, ) -> Weight; + fn seal_take_storage_per_kb(n: u32, ) -> Weight; fn seal_transfer(r: u32, ) -> Weight; fn seal_call(r: u32, ) -> Weight; fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight; @@ -150,32 +153,32 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (2_720_000 as Weight) + (2_286_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((2_208_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((2_219_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (95_834_000 as Weight) + (95_627_000 as Weight) // Standard Error: 2_000 - .saturating_add((317_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((242_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (17_177_000 as Weight) - // Standard Error: 85_000 - .saturating_add((91_306_000 as Weight).saturating_mul(c as Weight)) + (17_037_000 as Weight) + // Standard Error: 98_000 + .saturating_add((88_875_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -184,9 +187,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (371_888_000 as Weight) - // Standard Error: 137_000 - .saturating_add((92_314_000 as Weight).saturating_mul(c as Weight)) + (348_110_000 as Weight) + // Standard Error: 136_000 + .saturating_add((81_086_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -198,11 +201,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (429_131_000 as Weight) - // Standard Error: 154_000 - .saturating_add((208_736_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 10_000 - .saturating_add((2_203_000 as Weight).saturating_mul(s as Weight)) + (414_966_000 as Weight) + // Standard Error: 137_000 + .saturating_add((198_330_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 8_000 + .saturating_add((2_180_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -213,9 +216,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (241_132_000 as Weight) + (201_465_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_986_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_993_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -224,7 +227,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (173_649_000 as Weight) + (154_139_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -232,9 +235,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (84_508_000 as Weight) + (69_640_000 as Weight) // Standard Error: 93_000 - .saturating_add((91_690_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((89_969_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -242,7 +245,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (39_407_000 as Weight) + (31_567_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -251,9 +254,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (421_879_000 as Weight) - // Standard Error: 168_000 - .saturating_add((114_154_000 as Weight).saturating_mul(r as Weight)) + (405_395_000 as Weight) + // Standard Error: 167_000 + .saturating_add((79_867_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -262,9 +265,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (428_124_000 as Weight) - // Standard Error: 167_000 - .saturating_add((113_196_000 as Weight).saturating_mul(r as Weight)) + (405_173_000 as Weight) + // Standard Error: 152_000 + .saturating_add((79_619_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -273,9 +276,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (424_405_000 as Weight) - // Standard Error: 182_000 - .saturating_add((112_511_000 as Weight).saturating_mul(r as Weight)) + (406_537_000 as Weight) + // Standard Error: 148_000 + .saturating_add((78_129_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -284,9 +287,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (433_901_000 as Weight) - // Standard Error: 206_000 - .saturating_add((307_273_000 as Weight).saturating_mul(r as Weight)) + (416_289_000 as Weight) + // Standard Error: 165_000 + .saturating_add((218_401_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -295,9 +298,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (428_707_000 as Weight) - // Standard Error: 203_000 - .saturating_add((113_558_000 as Weight).saturating_mul(r as Weight)) + (408_205_000 as Weight) + // Standard Error: 154_000 + .saturating_add((79_563_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -306,9 +309,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (423_775_000 as Weight) - // Standard Error: 174_000 - .saturating_add((113_371_000 as Weight).saturating_mul(r as Weight)) + (408_124_000 as Weight) + // Standard Error: 149_000 + .saturating_add((79_032_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -317,9 +320,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (423_282_000 as Weight) - // Standard Error: 220_000 - .saturating_add((113_709_000 as Weight).saturating_mul(r as Weight)) + (406_141_000 as Weight) + // Standard Error: 150_000 + .saturating_add((78_992_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -328,9 +331,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (435_209_000 as Weight) - // Standard Error: 157_000 - .saturating_add((111_492_000 as Weight).saturating_mul(r as Weight)) + (418_112_000 as Weight) + // Standard Error: 155_000 + .saturating_add((77_902_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -340,9 +343,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (432_886_000 as Weight) - // Standard Error: 193_000 - .saturating_add((260_787_000 as Weight).saturating_mul(r as Weight)) + (411_683_000 as Weight) + // Standard Error: 173_000 + .saturating_add((205_824_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -351,9 +354,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (147_315_000 as Weight) - // Standard Error: 124_000 - .saturating_add((52_336_000 as Weight).saturating_mul(r as Weight)) + (132_178_000 as Weight) + // Standard Error: 84_000 + .saturating_add((38_233_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -362,9 +365,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (422_074_000 as Weight) - // Standard Error: 199_000 - .saturating_add((100_398_000 as Weight).saturating_mul(r as Weight)) + (405_685_000 as Weight) + // Standard Error: 142_000 + .saturating_add((72_826_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -373,9 +376,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (543_944_000 as Weight) - // Standard Error: 10_000 - .saturating_add((38_098_000 as Weight).saturating_mul(n as Weight)) + (490_336_000 as Weight) + // Standard Error: 7_000 + .saturating_add((38_070_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -384,9 +387,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (398_945_000 as Weight) - // Standard Error: 417_000 - .saturating_add((15_763_000 as Weight).saturating_mul(r as Weight)) + (384_543_000 as Weight) + // Standard Error: 105_000 + .saturating_add((15_793_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -395,9 +398,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (416_850_000 as Weight) + (399_205_000 as Weight) // Standard Error: 1_000 - .saturating_add((635_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((637_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -408,9 +411,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (408_445_000 as Weight) - // Standard Error: 248_000 - .saturating_add((102_109_000 as Weight).saturating_mul(r as Weight)) + (396_375_000 as Weight) + // Standard Error: 3_023_000 + .saturating_add((79_797_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -422,9 +425,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (410_845_000 as Weight) - // Standard Error: 289_000 - .saturating_add((341_867_000 as Weight).saturating_mul(r as Weight)) + (390_550_000 as Weight) + // Standard Error: 290_000 + .saturating_add((245_730_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -433,9 +436,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (425_037_000 as Weight) - // Standard Error: 424_000 - .saturating_add((571_604_000 as Weight).saturating_mul(r as Weight)) + (408_011_000 as Weight) + // Standard Error: 273_000 + .saturating_add((406_522_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -445,11 +448,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_055_868_000 as Weight) - // Standard Error: 3_004_000 - .saturating_add((453_979_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 592_000 - .saturating_add((166_716_000 as Weight).saturating_mul(n as Weight)) + (890_741_000 as Weight) + // Standard Error: 2_072_000 + .saturating_add((382_953_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 408_000 + .saturating_add((162_320_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -460,17 +463,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (161_170_000 as Weight) - // Standard Error: 169_000 - .saturating_add((74_379_000 as Weight).saturating_mul(r as Weight)) + (153_163_000 as Weight) + // Standard Error: 137_000 + .saturating_add((59_081_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (500_168_000 as Weight) - // Standard Error: 473_000 - .saturating_add((371_239_000 as Weight).saturating_mul(r as Weight)) + (459_368_000 as Weight) + // Standard Error: 560_000 + .saturating_add((330_190_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -482,17 +485,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (796_175_000 as Weight) - // Standard Error: 249_000 - .saturating_add((74_071_000 as Weight).saturating_mul(n as Weight)) + (727_394_000 as Weight) + // Standard Error: 247_000 + .saturating_add((73_350_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (178_237_000 as Weight) - // Standard Error: 1_652_000 - .saturating_add((835_947_000 as Weight).saturating_mul(r as Weight)) + (163_262_000 as Weight) + // Standard Error: 1_492_000 + .saturating_add((799_087_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -500,9 +503,18 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (305_702_000 as Weight) - // Standard Error: 750_000 - .saturating_add((493_580_000 as Weight).saturating_mul(r as Weight)) + (288_728_000 as Weight) + // Standard Error: 752_000 + .saturating_add((434_780_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Skipped Metadata (r:0 w:0) + fn seal_contains_storage(r: u32, ) -> Weight { + (209_606_000 as Weight) + // Standard Error: 1_137_000 + .saturating_add((680_187_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -513,20 +525,38 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (697_017_000 as Weight) - // Standard Error: 216_000 - .saturating_add((111_743_000 as Weight).saturating_mul(n as Weight)) + (619_600_000 as Weight) + // Standard Error: 207_000 + .saturating_add((111_030_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Skipped Metadata (r:0 w:0) + fn seal_take_storage(r: u32, ) -> Weight { + (279_528_000 as Weight) + // Standard Error: 932_000 + .saturating_add((541_965_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + } + // Storage: Skipped Metadata (r:0 w:0) + fn seal_take_storage_per_kb(n: u32, ) -> Weight { + (985_732_000 as Weight) + // Standard Error: 446_000 + .saturating_add((123_295_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(105 as Weight)) + .saturating_add(T::DbWeight::get().writes(103 as Weight)) + } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (243_124_000 as Weight) - // Standard Error: 1_718_000 - .saturating_add((3_530_873_000 as Weight).saturating_mul(r as Weight)) + (284_785_000 as Weight) + // Standard Error: 1_479_000 + .saturating_add((2_527_544_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -537,9 +567,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (140_524_000 as Weight) - // Standard Error: 4_504_000 - .saturating_add((39_287_224_000 as Weight).saturating_mul(r as Weight)) + (0 as Weight) + // Standard Error: 5_742_000 + .saturating_add((37_993_391_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -550,13 +580,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (38_929_132_000 as Weight) - // Standard Error: 65_806_000 - .saturating_add((2_980_358_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 23_000 - .saturating_add((62_980_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 25_000 - .saturating_add((101_383_000 as Weight).saturating_mul(o as Weight)) + (37_404_660_000 as Weight) + // Standard Error: 92_661_000 + .saturating_add((2_486_257_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 33_000 + .saturating_add((63_001_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 35_000 + .saturating_add((101_347_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -570,8 +600,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 120_171_000 - .saturating_add((50_779_937_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 119_281_000 + .saturating_add((47_113_525_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -584,13 +614,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (45_749_415_000 as Weight) - // Standard Error: 34_000 - .saturating_add((64_650_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 34_000 - .saturating_add((101_902_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 34_000 - .saturating_add((201_402_000 as Weight).saturating_mul(s as Weight)) + (41_157_901_000 as Weight) + // Standard Error: 147_000 + .saturating_add((64_877_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 147_000 + .saturating_add((102_420_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 147_000 + .saturating_add((201_587_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().writes(206 as Weight)) } @@ -599,9 +629,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (414_773_000 as Weight) - // Standard Error: 183_000 - .saturating_add((127_117_000 as Weight).saturating_mul(r as Weight)) + (402_224_000 as Weight) + // Standard Error: 166_000 + .saturating_add((103_985_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -610,9 +640,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (581_981_000 as Weight) - // Standard Error: 38_000 - .saturating_add((505_754_000 as Weight).saturating_mul(n as Weight)) + (663_731_000 as Weight) + // Standard Error: 42_000 + .saturating_add((505_157_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -621,9 +651,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (424_421_000 as Weight) - // Standard Error: 223_000 - .saturating_add((137_068_000 as Weight).saturating_mul(r as Weight)) + (402_638_000 as Weight) + // Standard Error: 165_000 + .saturating_add((117_589_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -632,9 +662,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (497_132_000 as Weight) - // Standard Error: 24_000 - .saturating_add((363_894_000 as Weight).saturating_mul(n as Weight)) + (491_978_000 as Weight) + // Standard Error: 23_000 + .saturating_add((363_687_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -643,9 +673,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (419_414_000 as Weight) - // Standard Error: 174_000 - .saturating_add((106_283_000 as Weight).saturating_mul(r as Weight)) + (402_254_000 as Weight) + // Standard Error: 154_000 + .saturating_add((86_403_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -654,9 +684,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (572_206_000 as Weight) - // Standard Error: 24_000 - .saturating_add((163_930_000 as Weight).saturating_mul(n as Weight)) + (476_405_000 as Weight) + // Standard Error: 18_000 + .saturating_add((163_921_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -665,9 +695,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (417_971_000 as Weight) - // Standard Error: 180_000 - .saturating_add((106_016_000 as Weight).saturating_mul(r as Weight)) + (399_949_000 as Weight) + // Standard Error: 142_000 + .saturating_add((85_448_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -676,9 +706,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (568_067_000 as Weight) - // Standard Error: 20_000 - .saturating_add((163_853_000 as Weight).saturating_mul(n as Weight)) + (475_437_000 as Weight) + // Standard Error: 15_000 + .saturating_add((163_921_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -687,266 +717,266 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (372_816_000 as Weight) - // Standard Error: 1_677_000 - .saturating_add((15_723_462_000 as Weight).saturating_mul(r as Weight)) + (373_575_000 as Weight) + // Standard Error: 1_639_000 + .saturating_add((15_530_027_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (53_407_000 as Weight) - // Standard Error: 14_000 - .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) + (52_763_000 as Weight) + // Standard Error: 12_000 + .saturating_add((857_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (48_061_000 as Weight) + (47_313_000 as Weight) // Standard Error: 10_000 - .saturating_add((2_947_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_935_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (48_150_000 as Weight) + (47_147_000 as Weight) // Standard Error: 10_000 - .saturating_add((2_978_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_995_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (50_943_000 as Weight) + (50_124_000 as Weight) // Standard Error: 11_000 - .saturating_add((2_446_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_421_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (47_862_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_627_000 as Weight).saturating_mul(r as Weight)) + (47_288_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_523_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (51_291_000 as Weight) + (50_198_000 as Weight) // Standard Error: 16_000 - .saturating_add((1_467_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_473_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (44_627_000 as Weight) - // Standard Error: 18_000 - .saturating_add((2_211_000 as Weight).saturating_mul(r as Weight)) + (44_008_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_174_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (38_208_000 as Weight) + (37_602_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_914_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_820_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (47_228_000 as Weight) + (46_232_000 as Weight) // Standard Error: 3_000 .saturating_add((17_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (39_507_000 as Weight) - // Standard Error: 26_000 - .saturating_add((20_544_000 as Weight).saturating_mul(r as Weight)) + (40_148_000 as Weight) + // Standard Error: 22_000 + .saturating_add((20_585_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (47_235_000 as Weight) + (43_948_000 as Weight) // Standard Error: 31_000 - .saturating_add((29_869_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((30_226_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (78_847_000 as Weight) - // Standard Error: 6_000 - .saturating_add((1_217_000 as Weight).saturating_mul(p as Weight)) + (78_722_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_199_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (48_441_000 as Weight) - // Standard Error: 11_000 - .saturating_add((816_000 as Weight).saturating_mul(r as Weight)) + (48_083_000 as Weight) + // Standard Error: 12_000 + .saturating_add((805_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (48_324_000 as Weight) + (47_710_000 as Weight) // Standard Error: 11_000 - .saturating_add((861_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((843_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (45_372_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_488_000 as Weight).saturating_mul(r as Weight)) + (44_785_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_466_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (58_465_000 as Weight) + (50_106_000 as Weight) // Standard Error: 20_000 - .saturating_add((1_655_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_641_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (55_457_000 as Weight) + (47_058_000 as Weight) // Standard Error: 18_000 - .saturating_add((1_671_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_707_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (52_615_000 as Weight) - // Standard Error: 14_000 - .saturating_add((905_000 as Weight).saturating_mul(r as Weight)) + (51_494_000 as Weight) + // Standard Error: 15_000 + .saturating_add((925_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (37_739_000 as Weight) - // Standard Error: 2_851_000 - .saturating_add((634_780_000 as Weight).saturating_mul(r as Weight)) + (36_983_000 as Weight) + // Standard Error: 3_602_000 + .saturating_add((634_259_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (54_830_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_309_000 as Weight).saturating_mul(r as Weight)) + (60_711_000 as Weight) + // Standard Error: 22_000 + .saturating_add((1_157_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (54_712_000 as Weight) + (53_908_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_310_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_305_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (54_864_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_312_000 as Weight).saturating_mul(r as Weight)) + (53_939_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_314_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (54_596_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_314_000 as Weight).saturating_mul(r as Weight)) + (54_086_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_309_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (44_536_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_514_000 as Weight).saturating_mul(r as Weight)) + (43_845_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_493_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (44_380_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_512_000 as Weight).saturating_mul(r as Weight)) + (43_518_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_501_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (54_968_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_310_000 as Weight).saturating_mul(r as Weight)) + (53_912_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_302_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (50_161_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_917_000 as Weight).saturating_mul(r as Weight)) + (49_594_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_890_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (50_417_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_911_000 as Weight).saturating_mul(r as Weight)) + (49_659_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (50_358_000 as Weight) + (49_401_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_914_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (49_864_000 as Weight) + (49_880_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (50_159_000 as Weight) + (49_466_000 as Weight) // Standard Error: 10_000 - .saturating_add((1_917_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (50_037_000 as Weight) - // Standard Error: 16_000 - .saturating_add((1_945_000 as Weight).saturating_mul(r as Weight)) + (49_514_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (50_482_000 as Weight) + (49_588_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_898_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (50_426_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_908_000 as Weight).saturating_mul(r as Weight)) + (49_589_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (50_205_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_918_000 as Weight).saturating_mul(r as Weight)) + (49_685_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_892_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (50_189_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) + (49_601_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (50_205_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_922_000 as Weight).saturating_mul(r as Weight)) + (49_430_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (50_375_000 as Weight) - // Standard Error: 15_000 - .saturating_add((1_929_000 as Weight).saturating_mul(r as Weight)) + (49_533_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_893_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (50_343_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_916_000 as Weight).saturating_mul(r as Weight)) + (49_766_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (50_707_000 as Weight) + (49_315_000 as Weight) // Standard Error: 11_000 - .saturating_add((2_667_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_552_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (50_318_000 as Weight) + (49_786_000 as Weight) // Standard Error: 11_000 - .saturating_add((2_408_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_203_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (50_214_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_702_000 as Weight).saturating_mul(r as Weight)) + (49_651_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_461_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (50_394_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_411_000 as Weight).saturating_mul(r as Weight)) + (49_747_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_196_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (50_397_000 as Weight) + (49_719_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_910_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_892_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (50_291_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_915_000 as Weight).saturating_mul(r as Weight)) + (49_463_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_896_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (50_684_000 as Weight) - // Standard Error: 12_000 + (49_379_000 as Weight) + // Standard Error: 11_000 .saturating_add((1_903_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (49_638_000 as Weight) - // Standard Error: 17_000 - .saturating_add((1_967_000 as Weight).saturating_mul(r as Weight)) + (49_404_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (50_817_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) + (49_498_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (50_987_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) + (49_541_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_897_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (50_885_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_905_000 as Weight).saturating_mul(r as Weight)) + (49_452_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (50_465_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_908_000 as Weight).saturating_mul(r as Weight)) + (49_350_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) } } @@ -954,32 +984,32 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (2_720_000 as Weight) + (2_286_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((2_208_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((2_219_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (95_834_000 as Weight) + (95_627_000 as Weight) // Standard Error: 2_000 - .saturating_add((317_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((242_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (17_177_000 as Weight) - // Standard Error: 85_000 - .saturating_add((91_306_000 as Weight).saturating_mul(c as Weight)) + (17_037_000 as Weight) + // Standard Error: 98_000 + .saturating_add((88_875_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -988,9 +1018,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (371_888_000 as Weight) - // Standard Error: 137_000 - .saturating_add((92_314_000 as Weight).saturating_mul(c as Weight)) + (348_110_000 as Weight) + // Standard Error: 136_000 + .saturating_add((81_086_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1002,11 +1032,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (429_131_000 as Weight) - // Standard Error: 154_000 - .saturating_add((208_736_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 10_000 - .saturating_add((2_203_000 as Weight).saturating_mul(s as Weight)) + (414_966_000 as Weight) + // Standard Error: 137_000 + .saturating_add((198_330_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 8_000 + .saturating_add((2_180_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1017,9 +1047,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (241_132_000 as Weight) + (201_465_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_986_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_993_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1028,7 +1058,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (173_649_000 as Weight) + (154_139_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1036,9 +1066,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (84_508_000 as Weight) + (69_640_000 as Weight) // Standard Error: 93_000 - .saturating_add((91_690_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((89_969_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1046,7 +1076,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (39_407_000 as Weight) + (31_567_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1055,9 +1085,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (421_879_000 as Weight) - // Standard Error: 168_000 - .saturating_add((114_154_000 as Weight).saturating_mul(r as Weight)) + (405_395_000 as Weight) + // Standard Error: 167_000 + .saturating_add((79_867_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1066,9 +1096,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (428_124_000 as Weight) - // Standard Error: 167_000 - .saturating_add((113_196_000 as Weight).saturating_mul(r as Weight)) + (405_173_000 as Weight) + // Standard Error: 152_000 + .saturating_add((79_619_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1077,9 +1107,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (424_405_000 as Weight) - // Standard Error: 182_000 - .saturating_add((112_511_000 as Weight).saturating_mul(r as Weight)) + (406_537_000 as Weight) + // Standard Error: 148_000 + .saturating_add((78_129_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1088,9 +1118,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (433_901_000 as Weight) - // Standard Error: 206_000 - .saturating_add((307_273_000 as Weight).saturating_mul(r as Weight)) + (416_289_000 as Weight) + // Standard Error: 165_000 + .saturating_add((218_401_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1099,9 +1129,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (428_707_000 as Weight) - // Standard Error: 203_000 - .saturating_add((113_558_000 as Weight).saturating_mul(r as Weight)) + (408_205_000 as Weight) + // Standard Error: 154_000 + .saturating_add((79_563_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1110,9 +1140,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (423_775_000 as Weight) - // Standard Error: 174_000 - .saturating_add((113_371_000 as Weight).saturating_mul(r as Weight)) + (408_124_000 as Weight) + // Standard Error: 149_000 + .saturating_add((79_032_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1121,9 +1151,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (423_282_000 as Weight) - // Standard Error: 220_000 - .saturating_add((113_709_000 as Weight).saturating_mul(r as Weight)) + (406_141_000 as Weight) + // Standard Error: 150_000 + .saturating_add((78_992_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1132,9 +1162,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (435_209_000 as Weight) - // Standard Error: 157_000 - .saturating_add((111_492_000 as Weight).saturating_mul(r as Weight)) + (418_112_000 as Weight) + // Standard Error: 155_000 + .saturating_add((77_902_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1144,9 +1174,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (432_886_000 as Weight) - // Standard Error: 193_000 - .saturating_add((260_787_000 as Weight).saturating_mul(r as Weight)) + (411_683_000 as Weight) + // Standard Error: 173_000 + .saturating_add((205_824_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1155,9 +1185,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (147_315_000 as Weight) - // Standard Error: 124_000 - .saturating_add((52_336_000 as Weight).saturating_mul(r as Weight)) + (132_178_000 as Weight) + // Standard Error: 84_000 + .saturating_add((38_233_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1166,9 +1196,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (422_074_000 as Weight) - // Standard Error: 199_000 - .saturating_add((100_398_000 as Weight).saturating_mul(r as Weight)) + (405_685_000 as Weight) + // Standard Error: 142_000 + .saturating_add((72_826_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1177,9 +1207,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (543_944_000 as Weight) - // Standard Error: 10_000 - .saturating_add((38_098_000 as Weight).saturating_mul(n as Weight)) + (490_336_000 as Weight) + // Standard Error: 7_000 + .saturating_add((38_070_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1188,9 +1218,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (398_945_000 as Weight) - // Standard Error: 417_000 - .saturating_add((15_763_000 as Weight).saturating_mul(r as Weight)) + (384_543_000 as Weight) + // Standard Error: 105_000 + .saturating_add((15_793_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1199,9 +1229,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (416_850_000 as Weight) + (399_205_000 as Weight) // Standard Error: 1_000 - .saturating_add((635_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((637_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1212,9 +1242,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (408_445_000 as Weight) - // Standard Error: 248_000 - .saturating_add((102_109_000 as Weight).saturating_mul(r as Weight)) + (396_375_000 as Weight) + // Standard Error: 3_023_000 + .saturating_add((79_797_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1226,9 +1256,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (410_845_000 as Weight) - // Standard Error: 289_000 - .saturating_add((341_867_000 as Weight).saturating_mul(r as Weight)) + (390_550_000 as Weight) + // Standard Error: 290_000 + .saturating_add((245_730_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1237,9 +1267,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (425_037_000 as Weight) - // Standard Error: 424_000 - .saturating_add((571_604_000 as Weight).saturating_mul(r as Weight)) + (408_011_000 as Weight) + // Standard Error: 273_000 + .saturating_add((406_522_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1249,11 +1279,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_055_868_000 as Weight) - // Standard Error: 3_004_000 - .saturating_add((453_979_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 592_000 - .saturating_add((166_716_000 as Weight).saturating_mul(n as Weight)) + (890_741_000 as Weight) + // Standard Error: 2_072_000 + .saturating_add((382_953_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 408_000 + .saturating_add((162_320_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1264,17 +1294,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (161_170_000 as Weight) - // Standard Error: 169_000 - .saturating_add((74_379_000 as Weight).saturating_mul(r as Weight)) + (153_163_000 as Weight) + // Standard Error: 137_000 + .saturating_add((59_081_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (500_168_000 as Weight) - // Standard Error: 473_000 - .saturating_add((371_239_000 as Weight).saturating_mul(r as Weight)) + (459_368_000 as Weight) + // Standard Error: 560_000 + .saturating_add((330_190_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1286,17 +1316,17 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (796_175_000 as Weight) - // Standard Error: 249_000 - .saturating_add((74_071_000 as Weight).saturating_mul(n as Weight)) + (727_394_000 as Weight) + // Standard Error: 247_000 + .saturating_add((73_350_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (178_237_000 as Weight) - // Standard Error: 1_652_000 - .saturating_add((835_947_000 as Weight).saturating_mul(r as Weight)) + (163_262_000 as Weight) + // Standard Error: 1_492_000 + .saturating_add((799_087_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1304,9 +1334,18 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (305_702_000 as Weight) - // Standard Error: 750_000 - .saturating_add((493_580_000 as Weight).saturating_mul(r as Weight)) + (288_728_000 as Weight) + // Standard Error: 752_000 + .saturating_add((434_780_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Skipped Metadata (r:0 w:0) + fn seal_contains_storage(r: u32, ) -> Weight { + (209_606_000 as Weight) + // Standard Error: 1_137_000 + .saturating_add((680_187_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1317,20 +1356,38 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (697_017_000 as Weight) - // Standard Error: 216_000 - .saturating_add((111_743_000 as Weight).saturating_mul(n as Weight)) + (619_600_000 as Weight) + // Standard Error: 207_000 + .saturating_add((111_030_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: Skipped Metadata (r:0 w:0) + fn seal_take_storage(r: u32, ) -> Weight { + (279_528_000 as Weight) + // Standard Error: 932_000 + .saturating_add((541_965_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + } + // Storage: Skipped Metadata (r:0 w:0) + fn seal_take_storage_per_kb(n: u32, ) -> Weight { + (985_732_000 as Weight) + // Standard Error: 446_000 + .saturating_add((123_295_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(105 as Weight)) + .saturating_add(RocksDbWeight::get().writes(103 as Weight)) + } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (243_124_000 as Weight) - // Standard Error: 1_718_000 - .saturating_add((3_530_873_000 as Weight).saturating_mul(r as Weight)) + (284_785_000 as Weight) + // Standard Error: 1_479_000 + .saturating_add((2_527_544_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1341,9 +1398,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (140_524_000 as Weight) - // Standard Error: 4_504_000 - .saturating_add((39_287_224_000 as Weight).saturating_mul(r as Weight)) + (0 as Weight) + // Standard Error: 5_742_000 + .saturating_add((37_993_391_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1354,13 +1411,13 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (38_929_132_000 as Weight) - // Standard Error: 65_806_000 - .saturating_add((2_980_358_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 23_000 - .saturating_add((62_980_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 25_000 - .saturating_add((101_383_000 as Weight).saturating_mul(o as Weight)) + (37_404_660_000 as Weight) + // Standard Error: 92_661_000 + .saturating_add((2_486_257_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 33_000 + .saturating_add((63_001_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 35_000 + .saturating_add((101_347_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1374,8 +1431,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 120_171_000 - .saturating_add((50_779_937_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 119_281_000 + .saturating_add((47_113_525_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1388,13 +1445,13 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (45_749_415_000 as Weight) - // Standard Error: 34_000 - .saturating_add((64_650_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 34_000 - .saturating_add((101_902_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 34_000 - .saturating_add((201_402_000 as Weight).saturating_mul(s as Weight)) + (41_157_901_000 as Weight) + // Standard Error: 147_000 + .saturating_add((64_877_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 147_000 + .saturating_add((102_420_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 147_000 + .saturating_add((201_587_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().writes(206 as Weight)) } @@ -1403,9 +1460,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (414_773_000 as Weight) - // Standard Error: 183_000 - .saturating_add((127_117_000 as Weight).saturating_mul(r as Weight)) + (402_224_000 as Weight) + // Standard Error: 166_000 + .saturating_add((103_985_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1414,9 +1471,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (581_981_000 as Weight) - // Standard Error: 38_000 - .saturating_add((505_754_000 as Weight).saturating_mul(n as Weight)) + (663_731_000 as Weight) + // Standard Error: 42_000 + .saturating_add((505_157_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1425,9 +1482,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (424_421_000 as Weight) - // Standard Error: 223_000 - .saturating_add((137_068_000 as Weight).saturating_mul(r as Weight)) + (402_638_000 as Weight) + // Standard Error: 165_000 + .saturating_add((117_589_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1436,9 +1493,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (497_132_000 as Weight) - // Standard Error: 24_000 - .saturating_add((363_894_000 as Weight).saturating_mul(n as Weight)) + (491_978_000 as Weight) + // Standard Error: 23_000 + .saturating_add((363_687_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1447,9 +1504,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (419_414_000 as Weight) - // Standard Error: 174_000 - .saturating_add((106_283_000 as Weight).saturating_mul(r as Weight)) + (402_254_000 as Weight) + // Standard Error: 154_000 + .saturating_add((86_403_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1458,9 +1515,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (572_206_000 as Weight) - // Standard Error: 24_000 - .saturating_add((163_930_000 as Weight).saturating_mul(n as Weight)) + (476_405_000 as Weight) + // Standard Error: 18_000 + .saturating_add((163_921_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1469,9 +1526,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (417_971_000 as Weight) - // Standard Error: 180_000 - .saturating_add((106_016_000 as Weight).saturating_mul(r as Weight)) + (399_949_000 as Weight) + // Standard Error: 142_000 + .saturating_add((85_448_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1480,9 +1537,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (568_067_000 as Weight) - // Standard Error: 20_000 - .saturating_add((163_853_000 as Weight).saturating_mul(n as Weight)) + (475_437_000 as Weight) + // Standard Error: 15_000 + .saturating_add((163_921_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1491,265 +1548,265 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (372_816_000 as Weight) - // Standard Error: 1_677_000 - .saturating_add((15_723_462_000 as Weight).saturating_mul(r as Weight)) + (373_575_000 as Weight) + // Standard Error: 1_639_000 + .saturating_add((15_530_027_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (53_407_000 as Weight) - // Standard Error: 14_000 - .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) + (52_763_000 as Weight) + // Standard Error: 12_000 + .saturating_add((857_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (48_061_000 as Weight) + (47_313_000 as Weight) // Standard Error: 10_000 - .saturating_add((2_947_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_935_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (48_150_000 as Weight) + (47_147_000 as Weight) // Standard Error: 10_000 - .saturating_add((2_978_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_995_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (50_943_000 as Weight) + (50_124_000 as Weight) // Standard Error: 11_000 - .saturating_add((2_446_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_421_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (47_862_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_627_000 as Weight).saturating_mul(r as Weight)) + (47_288_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_523_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (51_291_000 as Weight) + (50_198_000 as Weight) // Standard Error: 16_000 - .saturating_add((1_467_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_473_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (44_627_000 as Weight) - // Standard Error: 18_000 - .saturating_add((2_211_000 as Weight).saturating_mul(r as Weight)) + (44_008_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_174_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (38_208_000 as Weight) + (37_602_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_914_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_820_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (47_228_000 as Weight) + (46_232_000 as Weight) // Standard Error: 3_000 .saturating_add((17_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (39_507_000 as Weight) - // Standard Error: 26_000 - .saturating_add((20_544_000 as Weight).saturating_mul(r as Weight)) + (40_148_000 as Weight) + // Standard Error: 22_000 + .saturating_add((20_585_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (47_235_000 as Weight) + (43_948_000 as Weight) // Standard Error: 31_000 - .saturating_add((29_869_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((30_226_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (78_847_000 as Weight) - // Standard Error: 6_000 - .saturating_add((1_217_000 as Weight).saturating_mul(p as Weight)) + (78_722_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_199_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (48_441_000 as Weight) - // Standard Error: 11_000 - .saturating_add((816_000 as Weight).saturating_mul(r as Weight)) + (48_083_000 as Weight) + // Standard Error: 12_000 + .saturating_add((805_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (48_324_000 as Weight) + (47_710_000 as Weight) // Standard Error: 11_000 - .saturating_add((861_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((843_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (45_372_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_488_000 as Weight).saturating_mul(r as Weight)) + (44_785_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_466_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (58_465_000 as Weight) + (50_106_000 as Weight) // Standard Error: 20_000 - .saturating_add((1_655_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_641_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (55_457_000 as Weight) + (47_058_000 as Weight) // Standard Error: 18_000 - .saturating_add((1_671_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_707_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (52_615_000 as Weight) - // Standard Error: 14_000 - .saturating_add((905_000 as Weight).saturating_mul(r as Weight)) + (51_494_000 as Weight) + // Standard Error: 15_000 + .saturating_add((925_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (37_739_000 as Weight) - // Standard Error: 2_851_000 - .saturating_add((634_780_000 as Weight).saturating_mul(r as Weight)) + (36_983_000 as Weight) + // Standard Error: 3_602_000 + .saturating_add((634_259_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (54_830_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_309_000 as Weight).saturating_mul(r as Weight)) + (60_711_000 as Weight) + // Standard Error: 22_000 + .saturating_add((1_157_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (54_712_000 as Weight) + (53_908_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_310_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_305_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (54_864_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_312_000 as Weight).saturating_mul(r as Weight)) + (53_939_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_314_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (54_596_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_314_000 as Weight).saturating_mul(r as Weight)) + (54_086_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_309_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (44_536_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_514_000 as Weight).saturating_mul(r as Weight)) + (43_845_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_493_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (44_380_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_512_000 as Weight).saturating_mul(r as Weight)) + (43_518_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_501_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (54_968_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_310_000 as Weight).saturating_mul(r as Weight)) + (53_912_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_302_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (50_161_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_917_000 as Weight).saturating_mul(r as Weight)) + (49_594_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_890_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (50_417_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_911_000 as Weight).saturating_mul(r as Weight)) + (49_659_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (50_358_000 as Weight) + (49_401_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_914_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (49_864_000 as Weight) + (49_880_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (50_159_000 as Weight) + (49_466_000 as Weight) // Standard Error: 10_000 - .saturating_add((1_917_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (50_037_000 as Weight) - // Standard Error: 16_000 - .saturating_add((1_945_000 as Weight).saturating_mul(r as Weight)) + (49_514_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (50_482_000 as Weight) + (49_588_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_898_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (50_426_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_908_000 as Weight).saturating_mul(r as Weight)) + (49_589_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (50_205_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_918_000 as Weight).saturating_mul(r as Weight)) + (49_685_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_892_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (50_189_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_928_000 as Weight).saturating_mul(r as Weight)) + (49_601_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (50_205_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_922_000 as Weight).saturating_mul(r as Weight)) + (49_430_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (50_375_000 as Weight) - // Standard Error: 15_000 - .saturating_add((1_929_000 as Weight).saturating_mul(r as Weight)) + (49_533_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_893_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (50_343_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_916_000 as Weight).saturating_mul(r as Weight)) + (49_766_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (50_707_000 as Weight) + (49_315_000 as Weight) // Standard Error: 11_000 - .saturating_add((2_667_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_552_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (50_318_000 as Weight) + (49_786_000 as Weight) // Standard Error: 11_000 - .saturating_add((2_408_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_203_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (50_214_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_702_000 as Weight).saturating_mul(r as Weight)) + (49_651_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_461_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (50_394_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_411_000 as Weight).saturating_mul(r as Weight)) + (49_747_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_196_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (50_397_000 as Weight) + (49_719_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_910_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_892_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (50_291_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_915_000 as Weight).saturating_mul(r as Weight)) + (49_463_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_896_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (50_684_000 as Weight) - // Standard Error: 12_000 + (49_379_000 as Weight) + // Standard Error: 11_000 .saturating_add((1_903_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (49_638_000 as Weight) - // Standard Error: 17_000 - .saturating_add((1_967_000 as Weight).saturating_mul(r as Weight)) + (49_404_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (50_817_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) + (49_498_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (50_987_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) + (49_541_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_897_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (50_885_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_905_000 as Weight).saturating_mul(r as Weight)) + (49_452_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (50_465_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_908_000 as Weight).saturating_mul(r as Weight)) + (49_350_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) } } From 617c36e0ab32cd593822d2dedacfb3d7dff9160c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 8 Jan 2022 17:13:54 +0100 Subject: [PATCH 0409/1472] frame-support: Use logging for printing corrupted state (#10612) `runtime_print!` is printed by default using `debug`, aka not being visible. With `log::error!` it will be printed directly to the user. Production networks like Polkadot disable logging, but for them we run special nodes that have logging enabled. --- frame/support/src/storage/child.rs | 5 +++-- frame/support/src/storage/unhashed.rs | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/frame/support/src/storage/child.rs b/frame/support/src/storage/child.rs index a0a673d4b0417..949df84e7e768 100644 --- a/frame/support/src/storage/child.rs +++ b/frame/support/src/storage/child.rs @@ -34,8 +34,9 @@ pub fn get(child_info: &ChildInfo, key: &[u8]) -> Option { sp_io::default_child_storage::get(storage_key, key).and_then(|v| { Decode::decode(&mut &v[..]).map(Some).unwrap_or_else(|_| { // TODO #3700: error should be handleable. - crate::runtime_print!( - "ERROR: Corrupted state in child trie at {:?}/{:?}", + log::error!( + target: "runtime::storage", + "Corrupted state in child trie at {:?}/{:?}", storage_key, key, ); diff --git a/frame/support/src/storage/unhashed.rs b/frame/support/src/storage/unhashed.rs index 5e0b527acd132..96bccc6ae0feb 100644 --- a/frame/support/src/storage/unhashed.rs +++ b/frame/support/src/storage/unhashed.rs @@ -25,7 +25,11 @@ pub fn get(key: &[u8]) -> Option { sp_io::storage::get(key).and_then(|val| { Decode::decode(&mut &val[..]).map(Some).unwrap_or_else(|_| { // TODO #3700: error should be handleable. - crate::runtime_print!("ERROR: Corrupted state at {:?}", key); + log::error!( + target: "runtime::storage", + "Corrupted state at {:?}", + key, + ); None }) }) From 42bac6770ea83ba1efe34e9677ccb2720031b312 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sun, 9 Jan 2022 10:03:21 +0100 Subject: [PATCH 0410/1472] Add Ord implementation for BoundedVec (#10615) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Ord implementation for BoundedVec * Update frame/support/src/storage/bounded_vec.rs * Update frame/support/src/storage/bounded_vec.rs * Update frame/support/src/storage/bounded_vec.rs * Update frame/support/src/storage/bounded_vec.rs Co-authored-by: Bastian Köcher --- frame/support/src/storage/bounded_vec.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index bdac8f23d7c96..9f43d37a2d7f1 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -57,6 +57,18 @@ impl<'a, T: Encode + Decode, S: Get> EncodeLike> } impl<'a, T: Encode + Decode, S: Get> EncodeLike> for BoundedSlice<'a, T, S> {} +impl> PartialOrd for BoundedVec { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl> Ord for BoundedVec { + fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + impl<'a, T, S: Get> TryFrom<&'a [T]> for BoundedSlice<'a, T, S> { type Error = (); fn try_from(t: &'a [T]) -> Result { @@ -545,4 +557,15 @@ pub mod test { let b2: BoundedVec = vec![1, 2, 3].try_into().unwrap(); assert_eq!(b1, b2); } + + #[test] + fn ord_works() { + use std::cmp::Ordering; + let b1: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + let b2: BoundedVec> = vec![1, 3, 2].try_into().unwrap(); + + // ordering for vec is lexicographic. + assert_eq!(b1.cmp(&b2), Ordering::Less); + assert_eq!(b1.cmp(&b2), b1.into_inner().cmp(&b2.into_inner())); + } } From c623d1764638c44a85c7cb5417c32f5305884a24 Mon Sep 17 00:00:00 2001 From: Alex Pozhylenkov Date: Sun, 9 Jan 2022 21:12:21 +0200 Subject: [PATCH 0411/1472] add into function for PrefixIterator (#10614) * add into function for PrefixIterator * update with comments * update with comments --- frame/support/src/storage/mod.rs | 13 +++++++ .../support/src/storage/types/counted_map.rs | 36 +++---------------- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 04876895dc490..e50577697a60a 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -802,6 +802,19 @@ pub struct PrefixIterator { phantom: core::marker::PhantomData, } +impl PrefixIterator { + /// Converts to the same iterator but with the different 'OnRemoval' type + pub fn convert_on_removal(self) -> PrefixIterator { + PrefixIterator:: { + prefix: self.prefix, + previous_key: self.previous_key, + drain: self.drain, + closure: self.closure, + phantom: Default::default(), + } + } +} + /// Trait for specialising on removal logic of [`PrefixIterator`]. pub trait PrefixIteratorOnRemoval { /// This function is called whenever a key/value is removed. diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 99d645fba3298..341dedaef0bac 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -285,14 +285,7 @@ where /// /// NOTE: If a value failed to decode because storage is corrupted then it is skipped. pub fn iter_values() -> crate::storage::PrefixIterator> { - let map_iterator = ::Map::iter_values(); - crate::storage::PrefixIterator { - prefix: map_iterator.prefix, - previous_key: map_iterator.previous_key, - drain: map_iterator.drain, - closure: map_iterator.closure, - phantom: Default::default(), - } + ::Map::iter_values().convert_on_removal() } /// Translate the values of all elements by a function `f`, in the map in no particular order. @@ -374,28 +367,14 @@ where /// /// If you alter the map while doing this, you'll get undefined results. pub fn iter() -> crate::storage::PrefixIterator<(Key, Value), OnRemovalCounterUpdate> { - let map_iterator = ::Map::iter(); - crate::storage::PrefixIterator { - prefix: map_iterator.prefix, - previous_key: map_iterator.previous_key, - drain: map_iterator.drain, - closure: map_iterator.closure, - phantom: Default::default(), - } + ::Map::iter().convert_on_removal() } /// Remove all elements from the map and iterate through them in no particular order. /// /// If you add elements to the map while doing this, you'll get undefined results. pub fn drain() -> crate::storage::PrefixIterator<(Key, Value), OnRemovalCounterUpdate> { - let map_iterator = ::Map::drain(); - crate::storage::PrefixIterator { - prefix: map_iterator.prefix, - previous_key: map_iterator.previous_key, - drain: map_iterator.drain, - closure: map_iterator.closure, - phantom: Default::default(), - } + ::Map::drain().convert_on_removal() } /// Translate the values of all elements by a function `f`, in the map in no particular order. @@ -420,14 +399,7 @@ where pub fn iter_from( starting_raw_key: Vec, ) -> crate::storage::PrefixIterator<(Key, Value), OnRemovalCounterUpdate> { - let map_iterator = ::Map::iter_from(starting_raw_key); - crate::storage::PrefixIterator { - prefix: map_iterator.prefix, - previous_key: map_iterator.previous_key, - drain: map_iterator.drain, - closure: map_iterator.closure, - phantom: Default::default(), - } + ::Map::iter_from(starting_raw_key).convert_on_removal() } } From b54c21f354fd973e6a35a53c37b317ae293dbfc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 9 Jan 2022 20:48:24 +0100 Subject: [PATCH 0412/1472] code-substitute: Switch from `block_hash` to `block_number` (#10600) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * code-substitute: Switch from `block_hash` to `block_number` This will make it easier for light clients to work with the code-substitute. For more information on this see: https://github.com/paritytech/substrate/issues/10589 Closes: https://github.com/paritytech/substrate/issues/10589 * FMT * Update client/service/src/client/wasm_substitutes.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Update client/service/src/builder.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- client/chain-spec/src/chain_spec.rs | 6 +-- client/service/src/builder.rs | 16 +++---- client/service/src/client/client.rs | 2 +- client/service/src/client/wasm_substitutes.rs | 46 ++++--------------- 4 files changed, 20 insertions(+), 50 deletions(-) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 59d3ac3513817..a22a68d2944fa 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -176,10 +176,10 @@ struct ClientSpec { #[serde(skip_serializing)] #[allow(unused)] genesis: serde::de::IgnoredAny, - /// Mapping from `block_hash` to `wasm_code`. + /// Mapping from `block_number` to `wasm_code`. /// - /// The given `wasm_code` will be used to substitute the on-chain wasm code from the given - /// block hash onwards. + /// The given `wasm_code` will be used to substitute the on-chain wasm code starting with the + /// given block number until the `spec_version` on chain changes. #[serde(default)] code_substitutes: BTreeMap, } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index c713b4936c6b0..269b7be720be0 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -57,7 +57,7 @@ use sp_core::traits::{CodeExecutor, SpawnNamed}; use sp_keystore::{CryptoStore, SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, BlockIdTo, Zero}, + traits::{Block as BlockT, BlockIdTo, NumberFor, Zero}, BuildStorage, }; use std::{str::FromStr, sync::Arc, time::SystemTime}; @@ -227,7 +227,6 @@ pub fn new_full_client( where TBl: BlockT, TExec: CodeExecutor + RuntimeVersionOf + Clone, - TBl::Hash: FromStr, { new_full_parts(config, telemetry, executor).map(|parts| parts.0) } @@ -241,7 +240,6 @@ pub fn new_full_parts( where TBl: BlockT, TExec: CodeExecutor + RuntimeVersionOf + Clone, - TBl::Hash: FromStr, { let keystore_container = KeystoreContainer::new(&config.keystore)?; @@ -281,14 +279,16 @@ where .chain_spec .code_substitutes() .into_iter() - .map(|(h, c)| { - let hash = TBl::Hash::from_str(&h).map_err(|_| { + .map(|(n, c)| { + let number = NumberFor::::from_str(&n).map_err(|_| { Error::Application(Box::from(format!( - "Failed to parse `{}` as block hash for code substitutes.", - h + "Failed to parse `{}` as block number for code substitutes. \ + In an old version the key for code substitute was a block hash. \ + Please update the chain spec to a version that is compatible with your node.", + n ))) })?; - Ok((hash, c)) + Ok((number, c)) }) .collect::, Error>>()?; diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 9d898c7d1eb8f..8769865978bf9 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -194,7 +194,7 @@ pub struct ClientConfig { pub no_genesis: bool, /// Map of WASM runtime substitute starting at the child of the given block until the runtime /// version doesn't match anymore. - pub wasm_runtime_substitutes: HashMap>, + pub wasm_runtime_substitutes: HashMap, Vec>, } impl Default for ClientConfig { diff --git a/client/service/src/client/wasm_substitutes.rs b/client/service/src/client/wasm_substitutes.rs index 6f9a6dff43c74..a45eefb7b603c 100644 --- a/client/service/src/client/wasm_substitutes.rs +++ b/client/service/src/client/wasm_substitutes.rs @@ -18,7 +18,6 @@ //! # WASM substitutes -use parking_lot::RwLock; use sc_client_api::backend; use sc_executor::RuntimeVersionOf; use sp_blockchain::{HeaderBackend, Result}; @@ -40,21 +39,14 @@ use std::{ struct WasmSubstitute { code: Vec, hash: Vec, - /// The hash of the block from that on we should use the substitute. - block_hash: Block::Hash, - /// The block number of `block_hash`. If `None`, the block is still unknown. - block_number: RwLock>>, + /// The block number on which we should start using the substitute. + block_number: NumberFor, } impl WasmSubstitute { - fn new( - code: Vec, - block_hash: Block::Hash, - backend: &impl backend::Backend, - ) -> Result { - let block_number = RwLock::new(backend.blockchain().number(block_hash)?); + fn new(code: Vec, block_number: NumberFor) -> Self { let hash = make_hash(&code); - Ok(Self { code, hash, block_hash, block_number }) + Self { code, hash, block_number } } fn runtime_code(&self, heap_pages: Option) -> RuntimeCode { @@ -63,32 +55,10 @@ impl WasmSubstitute { /// Returns `true` when the substitute matches for the given `block_id`. fn matches(&self, block_id: &BlockId, backend: &impl backend::Backend) -> bool { - let block_number = *self.block_number.read(); - let block_number = if let Some(block_number) = block_number { - block_number - } else { - let block_number = match backend.blockchain().number(self.block_hash) { - Ok(Some(n)) => n, - // still unknown - Ok(None) => return false, - Err(e) => { - log::debug!( - target: "wasm_substitutes", - "Failed to get block number for block hash {:?}: {:?}", - self.block_hash, - e, - ); - return false - }, - }; - *self.block_number.write() = Some(block_number); - block_number - }; - let requested_block_number = backend.blockchain().block_number_from_id(&block_id).ok().flatten(); - Some(block_number) <= requested_block_number + Some(self.block_number) <= requested_block_number } } @@ -145,14 +115,14 @@ where { /// Create a new instance. pub fn new( - substitutes: HashMap>, + substitutes: HashMap, Vec>, executor: Executor, backend: Arc, ) -> Result { let substitutes = substitutes .into_iter() - .map(|(parent_block_hash, code)| { - let substitute = WasmSubstitute::new(code, parent_block_hash, &*backend)?; + .map(|(block_number, code)| { + let substitute = WasmSubstitute::new(code, block_number); let version = Self::runtime_version(&executor, &substitute)?; Ok((version.spec_version, substitute)) }) From 15b154aea254d4f1fcd1bbe770b5eb593b9ff0b6 Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Mon, 10 Jan 2022 06:55:05 -0500 Subject: [PATCH 0413/1472] Manual Seal: Calculate the block's post hash (#10498) * calculate the post hash * Add test Co-authored-by: tgmichel --- client/consensus/manual-seal/src/lib.rs | 81 ++++++++++++++++++- .../consensus/manual-seal/src/seal_block.rs | 7 +- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index a057190f6b378..a8d2634ade560 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -253,7 +253,8 @@ mod tests { use sc_consensus::ImportedAux; use sc_transaction_pool::{BasicPool, Options, RevalidationType}; use sc_transaction_pool_api::{MaintainedTransactionPool, TransactionPool, TransactionSource}; - use sp_runtime::generic::BlockId; + use sp_inherents::InherentData; + use sp_runtime::generic::{BlockId, Digest, DigestItem}; use substrate_test_runtime_client::{ AccountKeyring::*, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, }; @@ -265,6 +266,35 @@ mod tests { const SOURCE: TransactionSource = TransactionSource::External; + struct TestDigestProvider { + _client: Arc, + } + impl ConsensusDataProvider for TestDigestProvider + where + B: BlockT, + C: ProvideRuntimeApi + Send + Sync, + { + type Transaction = TransactionFor; + + fn create_digest( + &self, + _parent: &B::Header, + _inherents: &InherentData, + ) -> Result { + Ok(Digest { logs: vec![] }) + } + + fn append_block_import( + &self, + _parent: &B::Header, + params: &mut BlockImportParams, + _inherents: &InherentData, + ) -> Result<(), Error> { + params.post_digests.push(DigestItem::Other(vec![1])); + Ok(()) + } + } + #[tokio::test] async fn instant_seal() { let builder = TestClientBuilder::new(); @@ -519,4 +549,53 @@ mod tests { // assert that fork block is in the db assert!(client.header(&BlockId::Hash(imported.hash)).unwrap().is_some()) } + + #[tokio::test] + async fn manual_seal_post_hash() { + let builder = TestClientBuilder::new(); + let (client, select_chain) = builder.build_with_longest_chain(); + let client = Arc::new(client); + let spawner = sp_core::testing::TaskExecutor::new(); + let pool = Arc::new(BasicPool::with_revalidation_type( + Options::default(), + true.into(), + api(), + None, + RevalidationType::Full, + spawner.clone(), + 0, + )); + let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); + + let (mut sink, commands_stream) = futures::channel::mpsc::channel(1024); + let future = run_manual_seal(ManualSealParams { + block_import: client.clone(), + env, + client: client.clone(), + pool: pool.clone(), + commands_stream, + select_chain, + // use a provider that pushes some post digest data + consensus_data_provider: Some(Box::new(TestDigestProvider { _client: client.clone() })), + create_inherent_data_providers: |_, _| async { Ok(()) }, + }); + std::thread::spawn(|| { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(future); + }); + let (tx, rx) = futures::channel::oneshot::channel(); + sink.send(EngineCommand::SealNewBlock { + parent_hash: None, + sender: Some(tx), + create_empty: true, + finalize: false, + }) + .await + .unwrap(); + let created_block = rx.await.unwrap().unwrap(); + + // assert that the background task returned the actual header hash + let header = client.header(&BlockId::Number(1)).unwrap().unwrap(); + assert_eq!(header.hash(), created_block.hash); + } } diff --git a/client/consensus/manual-seal/src/seal_block.rs b/client/consensus/manual-seal/src/seal_block.rs index ad840bd102b3f..99b003c32f136 100644 --- a/client/consensus/manual-seal/src/seal_block.rs +++ b/client/consensus/manual-seal/src/seal_block.rs @@ -153,9 +153,14 @@ pub async fn seal_block( digest_provider.append_block_import(&parent, &mut params, &inherent_data)?; } + // Make sure we return the same post-hash that will be calculated when importing the block + // This is important in case the digest_provider added any signature, seal, ect. + let mut post_header = header.clone(); + post_header.digest_mut().logs.extend(params.post_digests.iter().cloned()); + match block_import.import_block(params, HashMap::new()).await? { ImportResult::Imported(aux) => - Ok(CreatedBlock { hash: ::Header::hash(&header), aux }), + Ok(CreatedBlock { hash: ::Header::hash(&post_header), aux }), other => Err(other.into()), } }; From 2cfd23559933eaf495fca4b8024cfaf5a98b7cd6 Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Mon, 10 Jan 2022 15:39:04 +0100 Subject: [PATCH 0414/1472] Adds AuraConsensusDataProvider (#10503) * adds support for parachains to test-runner * adds file header * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * proper docs, remove unused _client * fixes * Update client/consensus/manual-seal/src/consensus/timestamp.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update client/consensus/manual-seal/src/consensus/timestamp.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * pr fixes Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 69 +--- Cargo.toml | 2 - bin/node/test-runner-example/Cargo.toml | 29 -- bin/node/test-runner-example/src/lib.rs | 132 -------- client/consensus/aura/src/lib.rs | 15 +- client/consensus/manual-seal/Cargo.toml | 2 + client/consensus/manual-seal/src/consensus.rs | 2 + .../manual-seal/src/consensus/aura.rs | 97 ++++++ .../manual-seal/src/consensus/babe.rs | 79 +---- .../manual-seal/src/consensus/timestamp.rs | 156 +++++++++ client/consensus/manual-seal/src/error.rs | 1 - test-utils/test-runner/Cargo.toml | 59 ---- test-utils/test-runner/src/client.rs | 244 -------------- test-utils/test-runner/src/host_functions.rs | 53 --- test-utils/test-runner/src/lib.rs | 310 ------------------ test-utils/test-runner/src/node.rs | 278 ---------------- test-utils/test-runner/src/utils.rs | 118 ------- 17 files changed, 278 insertions(+), 1368 deletions(-) delete mode 100644 bin/node/test-runner-example/Cargo.toml delete mode 100644 bin/node/test-runner-example/src/lib.rs create mode 100644 client/consensus/manual-seal/src/consensus/aura.rs create mode 100644 client/consensus/manual-seal/src/consensus/timestamp.rs delete mode 100644 test-utils/test-runner/Cargo.toml delete mode 100644 test-utils/test-runner/src/client.rs delete mode 100644 test-utils/test-runner/src/host_functions.rs delete mode 100644 test-utils/test-runner/src/lib.rs delete mode 100644 test-utils/test-runner/src/node.rs delete mode 100644 test-utils/test-runner/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index e5192d2c8fe17..65b0897947f1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7995,6 +7995,7 @@ dependencies = [ "sc-basic-authorship", "sc-client-api", "sc-consensus", + "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-epochs", "sc-transaction-pool", @@ -8003,6 +8004,7 @@ dependencies = [ "sp-api", "sp-blockchain", "sp-consensus", + "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-slots", "sp-core", @@ -10457,73 +10459,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "test-runner" -version = "0.9.0" -dependencies = [ - "frame-system", - "futures 0.3.16", - "jsonrpc-core", - "log 0.4.14", - "num-traits", - "sc-basic-authorship", - "sc-cli", - "sc-client-api", - "sc-consensus", - "sc-consensus-babe", - "sc-consensus-manual-seal", - "sc-executor", - "sc-finality-grandpa", - "sc-informant", - "sc-network", - "sc-rpc", - "sc-rpc-server", - "sc-service", - "sc-transaction-pool", - "sc-transaction-pool-api", - "sp-api", - "sp-block-builder", - "sp-blockchain", - "sp-consensus", - "sp-consensus-babe", - "sp-core", - "sp-externalities", - "sp-finality-grandpa", - "sp-inherents", - "sp-keyring", - "sp-offchain", - "sp-runtime", - "sp-runtime-interface", - "sp-session", - "sp-state-machine", - "sp-transaction-pool", - "sp-wasm-interface", - "tokio", -] - -[[package]] -name = "test-runner-example" -version = "0.1.0" -dependencies = [ - "frame-benchmarking", - "frame-system", - "node-cli", - "node-primitives", - "node-runtime", - "pallet-asset-tx-payment", - "pallet-transaction-payment", - "sc-consensus", - "sc-consensus-babe", - "sc-consensus-manual-seal", - "sc-executor", - "sc-finality-grandpa", - "sc-service", - "sp-consensus-babe", - "sp-keyring", - "sp-runtime", - "test-runner", -] - [[package]] name = "textwrap" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index 93f7d42c8238c..b7051bdd44ef4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,6 @@ members = [ "bin/node-template/runtime", "bin/node/bench", "bin/node/cli", - "bin/node/test-runner-example", "bin/node/executor", "bin/node/primitives", "bin/node/rpc", @@ -200,7 +199,6 @@ members = [ "test-utils/runtime", "test-utils/runtime/client", "test-utils/runtime/transaction-pool", - "test-utils/test-runner", "test-utils/test-crate", "utils/build-script-utils", "utils/fork-tree", diff --git a/bin/node/test-runner-example/Cargo.toml b/bin/node/test-runner-example/Cargo.toml deleted file mode 100644 index 831a687254409..0000000000000 --- a/bin/node/test-runner-example/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "test-runner-example" -version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" -publish = false - -[dependencies] -test-runner = { path = "../../../test-utils/test-runner" } - -frame-system = { path = "../../../frame/system" } -frame-benchmarking = { path = "../../../frame/benchmarking" } -pallet-transaction-payment = { path = "../../../frame/transaction-payment" } -pallet-asset-tx-payment = { path = "../../../frame/transaction-payment/asset-tx-payment/" } - -node-runtime = { path = "../runtime" } -node-primitives = { path = "../primitives" } -node-cli = { path = "../cli" } - -grandpa = { package = "sc-finality-grandpa", path = "../../../client/finality-grandpa" } -sp-consensus-babe = { path = "../../../primitives/consensus/babe" } -sc-consensus-babe = { path = "../../../client/consensus/babe" } -sc-consensus-manual-seal = { path = "../../../client/consensus/manual-seal" } -sc-service = { default-features = false, path = "../../../client/service" } -sc-executor = { path = "../../../client/executor" } -sc-consensus = { path = "../../../client/consensus/common" } - -sp-runtime = { path = "../../../primitives/runtime" } -sp-keyring = { path = "../../../primitives/keyring" } diff --git a/bin/node/test-runner-example/src/lib.rs b/bin/node/test-runner-example/src/lib.rs deleted file mode 100644 index 8ac450ac12a1e..0000000000000 --- a/bin/node/test-runner-example/src/lib.rs +++ /dev/null @@ -1,132 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -#![deny(unused_extern_crates, missing_docs)] - -//! Basic example of end to end runtime tests. - -use grandpa::GrandpaBlockImport; -use sc_consensus_babe::BabeBlockImport; -use sc_consensus_manual_seal::consensus::babe::SlotTimestampProvider; -use sc_executor::NativeElseWasmExecutor; -use sc_service::{TFullBackend, TFullClient}; -use sp_runtime::generic::Era; -use test_runner::{ChainInfo, SignatureVerificationOverride}; - -type BlockImport = BabeBlockImport>; - -/// A unit struct which implements `NativeExecutionDispatch` feeding in the -/// hard-coded runtime. -pub struct ExecutorDispatch; - -impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { - type ExtendHostFunctions = - (frame_benchmarking::benchmarking::HostFunctions, SignatureVerificationOverride); - - fn dispatch(method: &str, data: &[u8]) -> Option> { - node_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - node_runtime::native_version() - } -} - -/// ChainInfo implementation. -struct NodeTemplateChainInfo; - -impl ChainInfo for NodeTemplateChainInfo { - type Block = node_primitives::Block; - type ExecutorDispatch = ExecutorDispatch; - type Runtime = node_runtime::Runtime; - type RuntimeApi = node_runtime::RuntimeApi; - type SelectChain = sc_consensus::LongestChain, Self::Block>; - type BlockImport = BlockImport< - Self::Block, - TFullBackend, - TFullClient>, - Self::SelectChain, - >; - type SignedExtras = node_runtime::SignedExtra; - type InherentDataProviders = - (SlotTimestampProvider, sp_consensus_babe::inherents::InherentDataProvider); - - fn signed_extras( - from: ::AccountId, - ) -> Self::SignedExtras { - ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckMortality::::from(Era::Immortal), - frame_system::CheckNonce::::from( - frame_system::Pallet::::account_nonce(from), - ), - frame_system::CheckWeight::::new(), - pallet_asset_tx_payment::ChargeAssetTxPayment::::from(0, None), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use node_cli::chain_spec::development_config; - use sp_keyring::sr25519::Keyring::Alice; - use sp_runtime::{traits::IdentifyAccount, MultiSigner}; - use test_runner::{build_runtime, client_parts, ConfigOrChainSpec, Node}; - - #[test] - fn test_runner() { - let tokio_runtime = build_runtime().unwrap(); - let (rpc, task_manager, client, pool, command_sink, backend) = - client_parts::(ConfigOrChainSpec::ChainSpec( - Box::new(development_config()), - tokio_runtime.handle().clone(), - )) - .unwrap(); - let node = Node::::new( - rpc, - task_manager, - client, - pool, - command_sink, - backend, - ); - - tokio_runtime.block_on(async { - // seals blocks - node.seal_blocks(1).await; - // submit extrinsics - let alice = MultiSigner::from(Alice.public()).into_account(); - let _hash = node - .submit_extrinsic( - frame_system::Call::remark { remark: (b"hello world").to_vec() }, - Some(alice), - ) - .await - .unwrap(); - - // look ma, I can read state. - let _events = - node.with_state(|| frame_system::Pallet::::events()); - // get access to the underlying client. - let _client = node.client(); - }) - } -} diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 13f0d4e8f8041..d7fe613139382 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -490,24 +490,34 @@ fn aura_err(error: Error) -> Error { error } +/// Aura Errors #[derive(derive_more::Display, Debug)] -enum Error { +pub enum Error { + /// Multiple Aura pre-runtime headers #[display(fmt = "Multiple Aura pre-runtime headers")] MultipleHeaders, + /// No Aura pre-runtime digest found #[display(fmt = "No Aura pre-runtime digest found")] NoDigestFound, + /// Header is unsealed #[display(fmt = "Header {:?} is unsealed", _0)] HeaderUnsealed(B::Hash), + /// Header has a bad seal #[display(fmt = "Header {:?} has a bad seal", _0)] HeaderBadSeal(B::Hash), + /// Slot Author not found #[display(fmt = "Slot Author not found")] SlotAuthorNotFound, + /// Bad signature #[display(fmt = "Bad signature on {:?}", _0)] BadSignature(B::Hash), + /// Client Error Client(sp_blockchain::Error), + /// Unknown inherent error for identifier #[display(fmt = "Unknown inherent error for identifier: {}", "String::from_utf8_lossy(_0)")] UnknownInherentError(sp_inherents::InherentIdentifier), #[display(fmt = "Inherent error: {}", _0)] + /// Inherents Error Inherent(sp_inherents::Error), } @@ -517,7 +527,8 @@ impl std::convert::From> for String { } } -fn find_pre_digest(header: &B::Header) -> Result> { +/// Get pre-digests from the header +pub fn find_pre_digest(header: &B::Header) -> Result> { if header.number().is_zero() { return Ok(0.into()) } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index a4bb63a7a2706..c55228abb5273 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -27,8 +27,10 @@ async-trait = "0.1.50" sc-client-api = { path = "../../api", version = "4.0.0-dev" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-consensus-babe = { path = "../../consensus/babe", version = "0.10.0-dev" } +sc-consensus-aura = { path = "../../consensus/aura", version = "0.10.0-dev" } sc-consensus-epochs = { path = "../../consensus/epochs", version = "0.10.0-dev" } sp-consensus-babe = { path = "../../../primitives/consensus/babe", version = "0.10.0-dev" } +sp-consensus-aura = { path = "../../../primitives/consensus/aura", version = "0.10.0-dev" } sc-transaction-pool = { path = "../../transaction-pool", version = "4.0.0-dev" } sp-blockchain = { path = "../../../primitives/blockchain", version = "4.0.0-dev" } diff --git a/client/consensus/manual-seal/src/consensus.rs b/client/consensus/manual-seal/src/consensus.rs index 9bb1d2fe1fae9..dfd3730fd3427 100644 --- a/client/consensus/manual-seal/src/consensus.rs +++ b/client/consensus/manual-seal/src/consensus.rs @@ -23,7 +23,9 @@ use sc_consensus::BlockImportParams; use sp_inherents::InherentData; use sp_runtime::{traits::Block as BlockT, Digest}; +pub mod aura; pub mod babe; +pub mod timestamp; /// Consensus data provider, manual seal uses this trait object for authoring blocks valid /// for any runtime. diff --git a/client/consensus/manual-seal/src/consensus/aura.rs b/client/consensus/manual-seal/src/consensus/aura.rs new file mode 100644 index 0000000000000..4497a94bdd429 --- /dev/null +++ b/client/consensus/manual-seal/src/consensus/aura.rs @@ -0,0 +1,97 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Aura consensus data provider, This allows manual seal author blocks that are valid for +//! runtimes that expect the aura-specific digests. + +use crate::{ConsensusDataProvider, Error}; +use sc_client_api::{AuxStore, UsageProvider}; +use sc_consensus::BlockImportParams; +use sc_consensus_aura::slot_duration; +use sp_api::{ProvideRuntimeApi, TransactionFor}; +use sp_blockchain::{HeaderBackend, HeaderMetadata}; +use sp_consensus_aura::{ + digests::CompatibleDigestItem, + sr25519::{AuthorityId, AuthoritySignature}, + AuraApi, +}; +use sp_inherents::InherentData; +use sp_runtime::{traits::Block as BlockT, Digest, DigestItem}; +use sp_timestamp::TimestampInherentData; +use std::{marker::PhantomData, sync::Arc}; + +/// Consensus data provider for Aura. +pub struct AuraConsensusDataProvider { + // slot duration in milliseconds + slot_duration: u64, + // phantom data for required generics + _phantom: PhantomData<(B, C)>, +} + +impl AuraConsensusDataProvider +where + B: BlockT, + C: AuxStore + ProvideRuntimeApi + UsageProvider, + C::Api: AuraApi, +{ + /// Creates a new instance of the [`AuraConsensusDataProvider`], requires that `client` + /// implements [`sp_consensus_aura::AuraApi`] + pub fn new(client: Arc) -> Self { + let slot_duration = + (*slot_duration(&*client).expect("slot_duration is always present; qed.")).get(); + + Self { slot_duration, _phantom: PhantomData } + } +} + +impl ConsensusDataProvider for AuraConsensusDataProvider +where + B: BlockT, + C: AuxStore + + HeaderBackend + + HeaderMetadata + + UsageProvider + + ProvideRuntimeApi, + C::Api: AuraApi, +{ + type Transaction = TransactionFor; + + fn create_digest( + &self, + _parent: &B::Header, + inherents: &InherentData, + ) -> Result { + let time_stamp = + *inherents.timestamp_inherent_data()?.expect("Timestamp is always present; qed"); + // we always calculate the new slot number based on the current time-stamp and the slot + // duration. + let digest_item = >::aura_pre_digest( + (time_stamp / self.slot_duration).into(), + ); + Ok(Digest { logs: vec![digest_item] }) + } + + fn append_block_import( + &self, + _parent: &B::Header, + _params: &mut BlockImportParams, + _inherents: &InherentData, + ) -> Result<(), Error> { + Ok(()) + } +} diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 6d86658cbf504..9c2a1638043a7 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -16,7 +16,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! BABE consensus data provider +//! BABE consensus data provider, This allows manual seal author blocks that are valid for runtimes +//! that expect babe-specific digests. use super::ConsensusDataProvider; use crate::Error; @@ -30,11 +31,7 @@ use sc_consensus_epochs::{ descendent_query, EpochHeader, SharedEpochChanges, ViableEpochDescriptor, }; use sp_keystore::SyncCryptoStorePtr; -use std::{ - borrow::Cow, - sync::{atomic, Arc}, - time::SystemTime, -}; +use std::{borrow::Cow, sync::Arc}; use sc_consensus::{BlockImportParams, ForkChoiceStrategy, Verifier}; use sp_api::{ProvideRuntimeApi, TransactionFor}; @@ -46,13 +43,13 @@ use sp_consensus_babe::{ AuthorityId, BabeApi, BabeAuthorityWeight, ConsensusLog, BABE_ENGINE_ID, }; use sp_consensus_slots::Slot; -use sp_inherents::{InherentData, InherentDataProvider, InherentIdentifier}; +use sp_inherents::InherentData; use sp_runtime::{ generic::{BlockId, Digest}, - traits::{Block as BlockT, Header, Zero}, + traits::{Block as BlockT, Header}, DigestItem, }; -use sp_timestamp::{InherentType, TimestampInherentData, INHERENT_IDENTIFIER}; +use sp_timestamp::TimestampInherentData; /// Provides BABE-compatible predigests and BlockImportParams. /// Intended for use with BABE runtimes. @@ -311,67 +308,3 @@ where Ok(()) } } - -/// Provide duration since unix epoch in millisecond for timestamp inherent. -/// Mocks the timestamp inherent to always produce the timestamp for the next babe slot. -pub struct SlotTimestampProvider { - time: atomic::AtomicU64, - slot_duration: u64, -} - -impl SlotTimestampProvider { - /// Create a new mocked time stamp provider. - pub fn new(client: Arc) -> Result - where - B: BlockT, - C: AuxStore + HeaderBackend + ProvideRuntimeApi + UsageProvider, - C::Api: BabeApi, - { - let slot_duration = Config::get(&*client)?.slot_duration; - let info = client.info(); - - // looks like this isn't the first block, rehydrate the fake time. - // otherwise we'd be producing blocks for older slots. - let time = if info.best_number != Zero::zero() { - let header = client.header(BlockId::Hash(info.best_hash))?.unwrap(); - let slot = find_pre_digest::(&header).unwrap().slot(); - // add the slot duration so there's no collision of slots - (*slot * slot_duration) + slot_duration - } else { - // this is the first block, use the correct time. - let now = SystemTime::now(); - now.duration_since(SystemTime::UNIX_EPOCH) - .map_err(|err| Error::StringError(format!("{}", err)))? - .as_millis() as u64 - }; - - Ok(Self { time: atomic::AtomicU64::new(time), slot_duration }) - } - - /// Get the current slot number - pub fn slot(&self) -> u64 { - self.time.load(atomic::Ordering::SeqCst) / self.slot_duration - } -} - -#[async_trait::async_trait] -impl InherentDataProvider for SlotTimestampProvider { - fn provide_inherent_data( - &self, - inherent_data: &mut InherentData, - ) -> Result<(), sp_inherents::Error> { - // we update the time here. - let duration: InherentType = - self.time.fetch_add(self.slot_duration, atomic::Ordering::SeqCst).into(); - inherent_data.put_data(INHERENT_IDENTIFIER, &duration)?; - Ok(()) - } - - async fn try_handle_error( - &self, - _: &InherentIdentifier, - _: &[u8], - ) -> Option> { - None - } -} diff --git a/client/consensus/manual-seal/src/consensus/timestamp.rs b/client/consensus/manual-seal/src/consensus/timestamp.rs new file mode 100644 index 0000000000000..908d218da05ac --- /dev/null +++ b/client/consensus/manual-seal/src/consensus/timestamp.rs @@ -0,0 +1,156 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Mocked timestamp inherent, allows for manual seal to create blocks for runtimes +//! that expect this inherent. + +use crate::Error; +use sc_client_api::{AuxStore, UsageProvider}; +use sc_consensus_aura::slot_duration; +use sc_consensus_babe::Config; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_consensus_aura::{ + sr25519::{AuthorityId, AuthoritySignature}, + AuraApi, +}; +use sp_consensus_babe::BabeApi; +use sp_inherents::{InherentData, InherentDataProvider, InherentIdentifier}; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Zero}, +}; +use sp_timestamp::{InherentType, INHERENT_IDENTIFIER}; +use std::{ + sync::{atomic, Arc}, + time::SystemTime, +}; + +/// Provide duration since unix epoch in millisecond for timestamp inherent. +/// Mocks the timestamp inherent to always produce a valid timestamp for the next slot. +/// +/// This works by either fetching the `slot_number` from the most recent header and dividing +/// that value by `slot_duration` in order to fork chains that expect this inherent. +/// +/// It produces timestamp inherents that are increaed by `slot_duraation` whenever +/// `provide_inherent_data` is called. +pub struct SlotTimestampProvider { + // holds the unix millisecnd timestamp for the most recent block + unix_millis: atomic::AtomicU64, + // configured slot_duration in the runtime + slot_duration: u64, +} + +impl SlotTimestampProvider { + /// Create a new mocked time stamp provider, for babe. + pub fn new_babe(client: Arc) -> Result + where + B: BlockT, + C: AuxStore + HeaderBackend + ProvideRuntimeApi + UsageProvider, + C::Api: BabeApi, + { + let slot_duration = Config::get(&*client)?.slot_duration; + + let time = Self::with_header(&client, slot_duration, |header| { + let slot_number = *sc_consensus_babe::find_pre_digest::(&header) + .map_err(|err| format!("{}", err))? + .slot(); + Ok(slot_number) + })?; + + Ok(Self { unix_millis: atomic::AtomicU64::new(time), slot_duration }) + } + + /// Create a new mocked time stamp provider, for aura + pub fn new_aura(client: Arc) -> Result + where + B: BlockT, + C: AuxStore + HeaderBackend + ProvideRuntimeApi + UsageProvider, + C::Api: AuraApi, + { + let slot_duration = (*slot_duration(&*client)?).get(); + + let time = Self::with_header(&client, slot_duration, |header| { + let slot_number = *sc_consensus_aura::find_pre_digest::(&header) + .map_err(|err| format!("{}", err))?; + Ok(slot_number) + })?; + + Ok(Self { unix_millis: atomic::AtomicU64::new(time), slot_duration }) + } + + fn with_header(client: &Arc, slot_duration: u64, func: F) -> Result + where + B: BlockT, + C: AuxStore + HeaderBackend + UsageProvider, + F: Fn(B::Header) -> Result, + { + let info = client.info(); + + // looks like this isn't the first block, rehydrate the fake time. + // otherwise we'd be producing blocks for older slots. + let time = if info.best_number != Zero::zero() { + let header = client + .header(BlockId::Hash(info.best_hash))? + .ok_or_else(|| "best header not found in the db!".to_string())?; + let slot = func(header)?; + // add the slot duration so there's no collision of slots + (slot * slot_duration) + slot_duration + } else { + // this is the first block, use the correct time. + let now = SystemTime::now(); + now.duration_since(SystemTime::UNIX_EPOCH) + .map_err(|err| Error::StringError(format!("{}", err)))? + .as_millis() as u64 + }; + + Ok(time) + } + + /// Get the current slot number + pub fn slot(&self) -> u64 { + self.unix_millis.load(atomic::Ordering::SeqCst) / self.slot_duration + } + + /// Gets the current time stamp. + pub fn timestamp(&self) -> sp_timestamp::Timestamp { + sp_timestamp::Timestamp::new(self.unix_millis.load(atomic::Ordering::SeqCst)) + } +} + +#[async_trait::async_trait] +impl InherentDataProvider for SlotTimestampProvider { + fn provide_inherent_data( + &self, + inherent_data: &mut InherentData, + ) -> Result<(), sp_inherents::Error> { + // we update the time here. + let new_time: InherentType = + self.unix_millis.fetch_add(self.slot_duration, atomic::Ordering::SeqCst).into(); + inherent_data.put_data(INHERENT_IDENTIFIER, &new_time)?; + Ok(()) + } + + async fn try_handle_error( + &self, + _: &InherentIdentifier, + _: &[u8], + ) -> Option> { + None + } +} diff --git a/client/consensus/manual-seal/src/error.rs b/client/consensus/manual-seal/src/error.rs index 28f1a6aed35b4..3a67b36bc62bc 100644 --- a/client/consensus/manual-seal/src/error.rs +++ b/client/consensus/manual-seal/src/error.rs @@ -62,7 +62,6 @@ pub enum Error { BlockNotFound(String), /// Some string error #[display(fmt = "{}", _0)] - #[from(ignore)] StringError(String), /// send error #[display(fmt = "Consensus process is terminating")] diff --git a/test-utils/test-runner/Cargo.toml b/test-utils/test-runner/Cargo.toml deleted file mode 100644 index 78e17d0f23b6d..0000000000000 --- a/test-utils/test-runner/Cargo.toml +++ /dev/null @@ -1,59 +0,0 @@ -[package] -name = "test-runner" -version = "0.9.0" -authors = ["Parity Technologies "] -edition = "2021" -publish = false - -[dependencies] -# client deps -sc-executor = { path = "../../client/executor" } -sc-service = { path = "../../client/service" } -sc-informant = { path = "../../client/informant" } -sc-network = { path = "../../client/network" } -sc-cli = { path = "../../client/cli" } -sc-basic-authorship = { path = "../../client/basic-authorship" } -sc-rpc = { path = "../../client/rpc" } -sc-transaction-pool = { path = "../../client/transaction-pool" } -grandpa = { package = "sc-finality-grandpa", path = "../../client/finality-grandpa" } -sp-finality-grandpa = { path = "../../primitives/finality-grandpa" } -sp-consensus-babe = { path = "../../primitives/consensus/babe" } -sc-consensus-babe = { path = "../../client/consensus/babe" } -sc-consensus = { path = "../../client/consensus/common" } -sc-transaction-pool-api = { path = "../../client/transaction-pool/api" } -sc-client-api = { path = "../../client/api" } -sc-rpc-server = { path = "../../client/rpc-servers" } -manual-seal = { package = "sc-consensus-manual-seal", path = "../../client/consensus/manual-seal" } - -# primitive deps -sp-core = { path = "../../primitives/core" } -sp-blockchain = { path = "../../primitives/blockchain" } -sp-block-builder = { path = "../../primitives/block-builder" } -sp-api = { path = "../../primitives/api" } -sp-transaction-pool = { path = "../../primitives/transaction-pool" } -sp-consensus = { path = "../../primitives/consensus/common" } -sp-runtime = { path = "../../primitives/runtime" } -sp-session = { path = "../../primitives/session" } -sp-offchain = { path = "../../primitives/offchain" } -sp-inherents = { path = "../../primitives/inherents" } -sp-keyring = { path = "../../primitives/keyring" } - -sp-externalities = { path = "../../primitives/externalities" } -sp-state-machine = { path = "../../primitives/state-machine" } -sp-wasm-interface = { path = "../../primitives/wasm-interface" } -sp-runtime-interface = { path = "../../primitives/runtime-interface" } - -# pallets -frame-system = { path = "../../frame/system" } - -log = "0.4.8" -futures = "0.3.16" -tokio = { version = "1.15", features = ["signal"] } -# Calling RPC -jsonrpc-core = "18.0" -num-traits = "0.2.14" - -[features] -default = ["std"] -# This is here so that we can use the `runtime_interface` procedural macro -std = [] diff --git a/test-utils/test-runner/src/client.rs b/test-utils/test-runner/src/client.rs deleted file mode 100644 index 3fa3de3a87e05..0000000000000 --- a/test-utils/test-runner/src/client.rs +++ /dev/null @@ -1,244 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -//! Client parts -use crate::{default_config, ChainInfo}; -use futures::channel::mpsc; -use jsonrpc_core::MetaIoHandler; -use manual_seal::{ - consensus::babe::{BabeConsensusDataProvider, SlotTimestampProvider}, - import_queue, - rpc::{ManualSeal, ManualSealApi}, - run_manual_seal, EngineCommand, ManualSealParams, -}; -use sc_client_api::backend::Backend; -use sc_executor::NativeElseWasmExecutor; -use sc_service::{ - build_network, new_full_parts, spawn_tasks, BuildNetworkParams, ChainSpec, Configuration, - SpawnTasksParams, TFullBackend, TFullClient, TaskManager, -}; -use sc_transaction_pool::BasicPool; -use sc_transaction_pool_api::TransactionPool; -use sp_api::{ApiExt, ConstructRuntimeApi, Core, Metadata}; -use sp_block_builder::BlockBuilder; -use sp_consensus_babe::BabeApi; -use sp_finality_grandpa::GrandpaApi; -use sp_keyring::sr25519::Keyring::Alice; -use sp_offchain::OffchainWorkerApi; -use sp_runtime::traits::{Block as BlockT, Header}; -use sp_session::SessionKeys; -use sp_transaction_pool::runtime_api::TaggedTransactionQueue; -use std::{str::FromStr, sync::Arc}; - -type ClientParts = ( - Arc>, - TaskManager, - Arc< - TFullClient< - ::Block, - ::RuntimeApi, - NativeElseWasmExecutor<::ExecutorDispatch>, - >, - >, - Arc< - dyn TransactionPool< - Block = ::Block, - Hash = <::Block as BlockT>::Hash, - Error = sc_transaction_pool::error::Error, - InPoolTransaction = sc_transaction_pool::Transaction< - <::Block as BlockT>::Hash, - <::Block as BlockT>::Extrinsic, - >, - >, - >, - mpsc::Sender::Block as BlockT>::Hash>>, - Arc::Block>>, -); - -/// Provide the config or chain spec for a given chain -pub enum ConfigOrChainSpec { - /// Configuration object - Config(Configuration), - /// Chain spec object - ChainSpec(Box, tokio::runtime::Handle), -} -/// Creates all the client parts you need for [`Node`](crate::node::Node) -pub fn client_parts( - config_or_chain_spec: ConfigOrChainSpec, -) -> Result, sc_service::Error> -where - T: ChainInfo + 'static, - >, - >>::RuntimeApi: Core - + Metadata - + OffchainWorkerApi - + SessionKeys - + TaggedTransactionQueue - + BlockBuilder - + BabeApi - + ApiExt as Backend>::State> - + GrandpaApi, - ::Call: From>, - <::Block as BlockT>::Hash: FromStr + Unpin, - <::Block as BlockT>::Header: Unpin, - <<::Block as BlockT>::Header as Header>::Number: - num_traits::cast::AsPrimitive, -{ - use sp_consensus_babe::AuthorityId; - let config = match config_or_chain_spec { - ConfigOrChainSpec::Config(config) => config, - ConfigOrChainSpec::ChainSpec(chain_spec, tokio_handle) => - default_config(tokio_handle, chain_spec), - }; - - let executor = NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - config.runtime_cache_size, - ); - - let (client, backend, keystore, mut task_manager) = - new_full_parts::(&config, None, executor)?; - let client = Arc::new(client); - - let select_chain = sc_consensus::LongestChain::new(backend.clone()); - - let (grandpa_block_import, ..) = grandpa::block_import( - client.clone(), - &(client.clone() as Arc<_>), - select_chain.clone(), - None, - )?; - - let slot_duration = sc_consensus_babe::Config::get(&*client)?; - let (block_import, babe_link) = sc_consensus_babe::block_import( - slot_duration.clone(), - grandpa_block_import, - client.clone(), - )?; - - let consensus_data_provider = BabeConsensusDataProvider::new( - client.clone(), - keystore.sync_keystore(), - babe_link.epoch_changes().clone(), - vec![(AuthorityId::from(Alice.public()), 1000)], - ) - .expect("failed to create ConsensusDataProvider"); - - let import_queue = - import_queue(Box::new(block_import.clone()), &task_manager.spawn_essential_handle(), None); - - let transaction_pool = BasicPool::new_full( - config.transaction_pool.clone(), - true.into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), - ); - - let (network, system_rpc_tx, network_starter) = { - let params = 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: None, - }; - build_network(params)? - }; - - // offchain workers - sc_service::build_offchain_workers( - &config, - task_manager.spawn_handle(), - client.clone(), - network.clone(), - ); - - // Proposer object for block authorship. - let env = sc_basic_authorship::ProposerFactory::new( - task_manager.spawn_handle(), - client.clone(), - transaction_pool.clone(), - config.prometheus_registry(), - None, - ); - - // Channel for the rpc handler to communicate with the authorship task. - let (command_sink, commands_stream) = mpsc::channel(10); - - let rpc_sink = command_sink.clone(); - - let rpc_handlers = { - let params = SpawnTasksParams { - config, - client: client.clone(), - backend: backend.clone(), - task_manager: &mut task_manager, - keystore: keystore.sync_keystore(), - transaction_pool: transaction_pool.clone(), - rpc_extensions_builder: Box::new(move |_, _| { - let mut io = jsonrpc_core::IoHandler::default(); - io.extend_with(ManualSealApi::to_delegate(ManualSeal::new(rpc_sink.clone()))); - Ok(io) - }), - network, - system_rpc_tx, - telemetry: None, - }; - spawn_tasks(params)? - }; - - let cloned_client = client.clone(); - let create_inherent_data_providers = Box::new(move |_, _| { - let client = cloned_client.clone(); - async move { - let timestamp = - SlotTimestampProvider::new(client.clone()).map_err(|err| format!("{:?}", err))?; - let babe = - sp_consensus_babe::inherents::InherentDataProvider::new(timestamp.slot().into()); - Ok((timestamp, babe)) - } - }); - - // Background authorship future. - let authorship_future = run_manual_seal(ManualSealParams { - block_import, - env, - client: client.clone(), - pool: transaction_pool.clone(), - commands_stream, - select_chain, - consensus_data_provider: Some(Box::new(consensus_data_provider)), - create_inherent_data_providers, - }); - - // spawn the authorship task as an essential task. - task_manager - .spawn_essential_handle() - .spawn("manual-seal", None, authorship_future); - - network_starter.start_network(); - let rpc_handler = rpc_handlers.io_handler(); - - Ok((rpc_handler, task_manager, client, transaction_pool, command_sink, backend)) -} diff --git a/test-utils/test-runner/src/host_functions.rs b/test-utils/test-runner/src/host_functions.rs deleted file mode 100644 index 8bc9597890d03..0000000000000 --- a/test-utils/test-runner/src/host_functions.rs +++ /dev/null @@ -1,53 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use sp_core::{ecdsa, ed25519, sr25519}; -use sp_runtime_interface::runtime_interface; - -#[runtime_interface] -trait Crypto { - fn ecdsa_verify(_sig: &ecdsa::Signature, _msg: &[u8], _pub_key: &ecdsa::Public) -> bool { - true - } - - #[version(2)] - fn ecdsa_verify(_sig: &ecdsa::Signature, _msg: &[u8], _pub_key: &ecdsa::Public) -> bool { - true - } - - fn ed25519_verify(_sig: &ed25519::Signature, _msg: &[u8], _pub_key: &ed25519::Public) -> bool { - true - } - - fn sr25519_verify(_sig: &sr25519::Signature, _msg: &[u8], _pub_key: &sr25519::Public) -> bool { - true - } - - #[version(2)] - fn sr25519_verify(_sig: &sr25519::Signature, _msg: &[u8], _pub_key: &sr25519::Public) -> bool { - true - } -} - -/// Provides host functions that overrides runtime signature verification -/// to always return true. -pub type SignatureVerificationOverride = crypto::HostFunctions; - -// This is here to get rid of the warnings. -#[allow(unused_imports, dead_code)] -use self::crypto::{ecdsa_verify, ed25519_verify, sr25519_verify}; diff --git a/test-utils/test-runner/src/lib.rs b/test-utils/test-runner/src/lib.rs deleted file mode 100644 index 19e437e26da45..0000000000000 --- a/test-utils/test-runner/src/lib.rs +++ /dev/null @@ -1,310 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -#![deny(missing_docs, unused_extern_crates)] - -//! Test runner -//! # Substrate Test Runner -//! -//! Allows you to test -//!
-//! -//! - Migrations -//! - Runtime Upgrades -//! - Pallets and general runtime functionality. -//! -//! This works by running a full node with a Manual Seal-BABE™ hybrid consensus for block authoring. -//! -//!

Note

-//! The running node has no signature verification, which allows us author extrinsics for any -//! account on chain.
-//!
-//! -//!

How do I Use this?

-//! -//! -//! ```rust,ignore -//! use test_runner::{Node, ChainInfo, SignatureVerificationOverride, base_path, NodeConfig}; -//! use sc_finality_grandpa::GrandpaBlockImport; -//! use sc_service::{ -//! TFullBackend, TFullClient, Configuration, TaskManager, new_full_parts, BasePath, -//! DatabaseSource, KeepBlocks, TransactionStorageMode, ChainSpec, Role, -//! config::{NetworkConfiguration, KeystoreConfig}, -//! }; -//! use std::sync::Arc; -//! use sp_inherents::InherentDataProviders; -//! use sc_consensus_babe::BabeBlockImport; -//! use sp_keystore::SyncCryptoStorePtr; -//! use sp_keyring::sr25519::Keyring::{Alice, Bob}; -//! use node_cli::chain_spec::development_config; -//! use sp_consensus_babe::AuthorityId; -//! use manual_seal::{ConsensusDataProvider, consensus::babe::BabeConsensusDataProvider}; -//! use sp_runtime::{traits::IdentifyAccount, MultiSigner, generic::Era}; -//! use sc_executor::WasmExecutionMethod; -//! use sc_network::{multiaddr, config::TransportConfig}; -//! use sc_client_api::execution_extensions::ExecutionStrategies; -//! use sc_informant::OutputFormat; -//! use sp_api::TransactionFor; -//! -//! type BlockImport = BabeBlockImport>; -//! -//! pub struct ExecutorDispatch; -//! -//! impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { -//! type ExtendHostFunctions = SignatureVerificationOverride; -//! -//! fn dispatch(method: &str, data: &[u8]) -> Option> { -//! node_runtime::api::dispatch(method, data) -//! } -//! -//! fn native_version() -> sc_executor::NativeVersion { -//! node_runtime::native_version() -//! } -//! } -//! -//! struct Requirements; -//! -//! impl ChainInfo for Requirements { -//! /// Provide a Block type with an OpaqueExtrinsic -//! type Block = node_primitives::Block; -//! /// Provide an ExecutorDispatch type for the runtime -//! type ExecutorDispatch = ExecutorDispatch; -//! /// Provide the runtime itself -//! type Runtime = node_runtime::Runtime; -//! /// A touch of runtime api -//! type RuntimeApi = node_runtime::RuntimeApi; -//! /// A pinch of SelectChain implementation -//! type SelectChain = sc_consensus::LongestChain, Self::Block>; -//! /// A slice of concrete BlockImport type -//! type BlockImport = BlockImport< -//! Self::Block, -//! TFullBackend, -//! TFullClient>, -//! Self::SelectChain, -//! >; -//! /// and a dash of SignedExtensions -//! type SignedExtras = node_runtime::SignedExtra; -//! -//! /// Create your signed extras here. -//! fn signed_extras( -//! from: ::AccountId, -//! ) -> Self::SignedExtension { -//! let nonce = frame_system::Pallet::::account_nonce(from); -//! -//! ( -//! frame_system::CheckNonZeroSender::::new(), -//! frame_system::CheckSpecVersion::::new(), -//! frame_system::CheckTxVersion::::new(), -//! frame_system::CheckGenesis::::new(), -//! frame_system::CheckMortality::::from(Era::Immortal), -//! frame_system::CheckNonce::::from(nonce), -//! frame_system::CheckWeight::::new(), -//! pallet_transaction_payment::ChargeTransactionPayment::::from(0), -//! ) -//! } -//! -//! /// The function signature tells you all you need to know. ;) -//! fn create_client_parts(config: &Configuration) -> Result< -//! ( -//! Arc>>, -//! Arc>, -//! KeyStorePtr, -//! TaskManager, -//! InherentDataProviders, -//! Option>, -//! Self::Block -//! >, -//! > -//! >>, -//! Self::SelectChain, -//! Self::BlockImport -//! ), -//! sc_service::Error -//! > { -//! let ( -//! client, -//! backend, -//! keystore, -//! task_manager, -//! ) = new_full_parts::>(config)?; -//! let client = Arc::new(client); -//! -//! let inherent_providers = InherentDataProviders::new(); -//! let select_chain = sc_consensus::LongestChain::new(backend.clone()); -//! -//! let (grandpa_block_import, ..) = -//! sc_finality_grandpa::block_import(client.clone(), &(client.clone() as Arc<_>), select_chain.clone())?; -//! -//! let (block_import, babe_link) = sc_consensus_babe::block_import( -//! sc_consensus_babe::Config::get(&*client)?, -//! grandpa_block_import, -//! client.clone(), -//! )?; -//! -//! let consensus_data_provider = BabeConsensusDataProvider::new( -//! client.clone(), -//! keystore.clone(), -//! &inherent_providers, -//! babe_link.epoch_changes().clone(), -//! vec![(AuthorityId::from(Alice.public()), 1000)] -//! ) -//! .expect("failed to create ConsensusDataProvider"); -//! -//! Ok(( -//! client, -//! backend, -//! keystore, -//! task_manager, -//! inherent_providers, -//! Some(Box::new(consensus_data_provider)), -//! select_chain, -//! block_import -//! )) -//! } -//! -//! fn dispatch_with_root(call: ::Call, node: &mut Node) { -//! let alice = MultiSigner::from(Alice.public()).into_account(); -//! // for chains that support sudo, otherwise, you'd have to use pallet-democracy here. -//! let call = pallet_sudo::Call::sudo(Box::new(call)); -//! node.submit_extrinsic(call, alice); -//! node.seal_blocks(1); -//! } -//! } -//! -//! /// And now for the most basic test -//! -//! #[test] -//! fn simple_balances_test() { -//! // given -//! let config = NodeConfig { -//! execution_strategies: ExecutionStrategies { -//! syncing: sc_client_api::ExecutionStrategy::NativeWhenPossible, -//! importing: sc_client_api::ExecutionStrategy::NativeWhenPossible, -//! block_construction: sc_client_api::ExecutionStrategy::NativeWhenPossible, -//! offchain_worker: sc_client_api::ExecutionStrategy::NativeWhenPossible, -//! other: sc_client_api::ExecutionStrategy::NativeWhenPossible, -//! }, -//! chain_spec: Box::new(development_config()), -//! log_targets: vec![], -//! }; -//! let mut node = Node::::new(config).unwrap(); -//! -//! type Balances = pallet_balances::Pallet; -//! -//! let (alice, bob) = (Alice.pair(), Bob.pair()); -//! let (alice_account_id, bob_acount_id) = ( -//! MultiSigner::from(alice.public()).into_account(), -//! MultiSigner::from(bob.public()).into_account() -//! ); -//! -//! /// the function with_state allows us to read state, pretty cool right? :D -//! let old_balance = node.with_state(|| Balances::free_balance(alice_account_id.clone())); -//! -//! // 70 dots -//! let amount = 70_000_000_000_000; -//! -//! /// Send extrinsic in action. -//! node.submit_extrinsic(BalancesCall::transfer(bob_acount_id.clone(), amount), alice_account_id.clone()); -//! -//! /// Produce blocks in action, Powered by manual-seal™. -//! node.seal_blocks(1); -//! -//! /// we can check the new state :D -//! let new_balance = node.with_state(|| Balances::free_balance(alice_account_id)); -//! -//! /// we can now make assertions on how state has changed. -//! assert_eq!(old_balance + amount, new_balance); -//! } -//! ``` - -use sc_consensus::BlockImport; -use sc_executor::{NativeElseWasmExecutor, NativeExecutionDispatch}; -use sc_service::TFullClient; -use sp_api::{ConstructRuntimeApi, TransactionFor}; -use sp_consensus::SelectChain; -use sp_inherents::InherentDataProvider; -use sp_runtime::traits::{Block as BlockT, SignedExtension}; - -mod client; -mod host_functions; -mod node; -mod utils; - -pub use client::*; -pub use host_functions::*; -pub use node::*; -pub use utils::*; - -/// Wrapper trait for concrete type required by this testing framework. -pub trait ChainInfo: Sized { - /// Opaque block type - type Block: BlockT; - - /// ExecutorDispatch dispatch type - type ExecutorDispatch: NativeExecutionDispatch + 'static; - - /// Runtime - type Runtime: frame_system::Config; - - /// RuntimeApi - type RuntimeApi: Send - + Sync - + 'static - + ConstructRuntimeApi< - Self::Block, - TFullClient< - Self::Block, - Self::RuntimeApi, - NativeElseWasmExecutor, - >, - >; - - /// select chain type. - type SelectChain: SelectChain + 'static; - - /// Block import type. - type BlockImport: Send - + Sync - + Clone - + BlockImport< - Self::Block, - Error = sp_consensus::Error, - Transaction = TransactionFor< - TFullClient< - Self::Block, - Self::RuntimeApi, - NativeElseWasmExecutor, - >, - Self::Block, - >, - > + 'static; - - /// The signed extras required by the runtime - type SignedExtras: SignedExtension; - - /// The inherent data providers. - type InherentDataProviders: InherentDataProvider + 'static; - - /// Signed extras, this function is caled in an externalities provided environment. - fn signed_extras( - from: ::AccountId, - ) -> Self::SignedExtras; -} diff --git a/test-utils/test-runner/src/node.rs b/test-utils/test-runner/src/node.rs deleted file mode 100644 index f122e48d53922..0000000000000 --- a/test-utils/test-runner/src/node.rs +++ /dev/null @@ -1,278 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use std::sync::Arc; - -use crate::ChainInfo; -use futures::{ - channel::{mpsc, oneshot}, - FutureExt, SinkExt, -}; -use jsonrpc_core::MetaIoHandler; -use manual_seal::EngineCommand; -use sc_client_api::{backend::Backend, CallExecutor, ExecutorProvider}; -use sc_executor::NativeElseWasmExecutor; -use sc_service::{TFullBackend, TFullCallExecutor, TFullClient, TaskManager}; -use sc_transaction_pool_api::TransactionPool; -use sp_api::{OverlayedChanges, StorageTransactionCache}; -use sp_blockchain::HeaderBackend; -use sp_core::ExecutionContext; -use sp_runtime::{ - generic::{BlockId, UncheckedExtrinsic}, - traits::{Block as BlockT, Extrinsic, Header, NumberFor}, - transaction_validity::TransactionSource, - MultiAddress, MultiSignature, -}; -use sp_state_machine::Ext; - -/// This holds a reference to a running node on another thread, -/// the node process is dropped when this struct is dropped -/// also holds logs from the process. -pub struct Node { - /// rpc handler for communicating with the node over rpc. - rpc_handler: Arc>, - /// handle to the running node. - task_manager: Option, - /// client instance - client: Arc>>, - /// transaction pool - pool: Arc< - dyn TransactionPool< - Block = ::Block, - Hash = <::Block as BlockT>::Hash, - Error = sc_transaction_pool::error::Error, - InPoolTransaction = sc_transaction_pool::Transaction< - <::Block as BlockT>::Hash, - <::Block as BlockT>::Extrinsic, - >, - >, - >, - /// channel to communicate with manual seal on. - manual_seal_command_sink: mpsc::Sender::Hash>>, - /// backend type. - backend: Arc>, - /// Block number at initialization of this Node. - initial_block_number: NumberFor, -} - -type EventRecord = frame_system::EventRecord< - ::Event, - ::Hash, ->; - -impl Node -where - T: ChainInfo, - <::Header as Header>::Number: From, -{ - /// Creates a new node. - pub fn new( - rpc_handler: Arc>, - task_manager: TaskManager, - client: Arc< - TFullClient>, - >, - pool: Arc< - dyn TransactionPool< - Block = ::Block, - Hash = <::Block as BlockT>::Hash, - Error = sc_transaction_pool::error::Error, - InPoolTransaction = sc_transaction_pool::Transaction< - <::Block as BlockT>::Hash, - <::Block as BlockT>::Extrinsic, - >, - >, - >, - command_sink: mpsc::Sender::Hash>>, - backend: Arc>, - ) -> Self { - Self { - rpc_handler, - task_manager: Some(task_manager), - client: client.clone(), - pool, - backend, - manual_seal_command_sink: command_sink, - initial_block_number: client.info().best_number, - } - } - - /// Returns a reference to the rpc handlers, use this to send rpc requests. - /// eg - /// ```ignore - /// let request = r#"{"jsonrpc":"2.0","method":"engine_createBlock","params": [true, true],"id":1}"#; - /// let response = node.rpc_handler() - /// .handle_request_sync(request, Default::default()); - /// ``` - pub fn rpc_handler( - &self, - ) -> Arc> { - self.rpc_handler.clone() - } - - /// Return a reference to the Client - pub fn client( - &self, - ) -> Arc>> { - self.client.clone() - } - - /// Return a reference to the pool. - pub fn pool( - &self, - ) -> Arc< - dyn TransactionPool< - Block = ::Block, - Hash = <::Block as BlockT>::Hash, - Error = sc_transaction_pool::error::Error, - InPoolTransaction = sc_transaction_pool::Transaction< - <::Block as BlockT>::Hash, - <::Block as BlockT>::Extrinsic, - >, - >, - > { - self.pool.clone() - } - - /// Executes closure in an externalities provided environment. - pub fn with_state(&self, closure: impl FnOnce() -> R) -> R - where - > as CallExecutor>::Error: - std::fmt::Debug, - { - let id = BlockId::Hash(self.client.info().best_hash); - let mut overlay = OverlayedChanges::default(); - let mut cache = StorageTransactionCache::< - T::Block, - as Backend>::State, - >::default(); - let mut extensions = self - .client - .execution_extensions() - .extensions(&id, ExecutionContext::BlockConstruction); - let state_backend = self - .backend - .state_at(id.clone()) - .expect(&format!("State at block {} not found", id)); - - let mut ext = Ext::new(&mut overlay, &mut cache, &state_backend, Some(&mut extensions)); - sp_externalities::set_and_run_with_externalities(&mut ext, closure) - } - - /// submit some extrinsic to the node. if signer is None, will submit unsigned_extrinsic. - pub async fn submit_extrinsic( - &self, - call: impl Into<::Call>, - signer: Option<::AccountId>, - ) -> Result<::Hash, sc_transaction_pool::error::Error> - where - ::Extrinsic: From< - UncheckedExtrinsic< - MultiAddress< - ::AccountId, - ::Index, - >, - ::Call, - MultiSignature, - T::SignedExtras, - >, - >, - { - let signed_data = if let Some(signer) = signer { - let extra = self.with_state(|| T::signed_extras(signer.clone())); - Some(( - signer.into(), - MultiSignature::Sr25519(sp_core::sr25519::Signature::from_raw([0u8; 64])), - extra, - )) - } else { - None - }; - let ext = UncheckedExtrinsic::< - MultiAddress< - ::AccountId, - ::Index, - >, - ::Call, - MultiSignature, - T::SignedExtras, - >::new(call.into(), signed_data) - .expect("UncheckedExtrinsic::new() always returns Some"); - let at = self.client.info().best_hash; - - self.pool - .submit_one(&BlockId::Hash(at), TransactionSource::Local, ext.into()) - .await - } - - /// Get the events of the most recently produced block - pub fn events(&self) -> Vec> { - self.with_state(|| frame_system::Pallet::::events()) - } - - /// Instructs manual seal to seal new, possibly empty blocks. - pub async fn seal_blocks(&self, num: usize) { - let mut sink = self.manual_seal_command_sink.clone(); - - for count in 0..num { - let (sender, future_block) = oneshot::channel(); - let future = sink.send(EngineCommand::SealNewBlock { - create_empty: true, - finalize: false, - parent_hash: None, - sender: Some(sender), - }); - - const ERROR: &'static str = "manual-seal authorship task is shutting down"; - future.await.expect(ERROR); - - match future_block.await.expect(ERROR) { - Ok(block) => { - log::info!("sealed {} (hash: {}) of {} blocks", count + 1, block.hash, num) - }, - Err(err) => { - log::error!("failed to seal block {} of {}, error: {:?}", count + 1, num, err) - }, - } - } - } - - /// Revert count number of blocks from the chain. - pub fn revert_blocks(&self, count: NumberFor) { - self.backend.revert(count, true).expect("Failed to revert blocks: "); - } - - /// so you've decided to run the test runner as a binary, use this to shutdown gracefully. - pub async fn until_shutdown(mut self) { - let manager = self.task_manager.take(); - if let Some(mut task_manager) = manager { - let task = task_manager.future().fuse(); - let signal = tokio::signal::ctrl_c(); - futures::pin_mut!(signal); - futures::future::select(task, signal).await; - } - } -} - -impl Drop for Node { - fn drop(&mut self) { - // Revert all blocks added since creation of the node. - let diff = self.client.info().best_number - self.initial_block_number; - self.revert_blocks(diff); - } -} diff --git a/test-utils/test-runner/src/utils.rs b/test-utils/test-runner/src/utils.rs deleted file mode 100644 index 452dc600e4ae5..0000000000000 --- a/test-utils/test-runner/src/utils.rs +++ /dev/null @@ -1,118 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use sc_client_api::execution_extensions::ExecutionStrategies; -use sc_executor::WasmExecutionMethod; -use sc_informant::OutputFormat; -use sc_network::{ - config::{NetworkConfiguration, Role, TransportConfig}, - multiaddr, -}; -use sc_service::{ - config::KeystoreConfig, BasePath, ChainSpec, Configuration, DatabaseSource, KeepBlocks, - TransactionStorageMode, -}; -use sp_keyring::sr25519::Keyring::Alice; -use tokio::runtime::Handle; - -pub use sc_cli::build_runtime; - -/// Base db path gotten from env -pub fn base_path() -> BasePath { - if let Some(base) = std::env::var("DB_BASE_PATH").ok() { - BasePath::new(base) - } else { - BasePath::new_temp_dir().expect("couldn't create a temp dir") - } -} - -/// Produces a default configuration object, suitable for use with most set ups. -pub fn default_config(tokio_handle: Handle, mut chain_spec: Box) -> Configuration { - let base_path = base_path(); - let root_path = base_path.path().to_path_buf().join("chains").join(chain_spec.id()); - - let storage = chain_spec - .as_storage_builder() - .build_storage() - .expect("could not build storage"); - - chain_spec.set_storage(storage); - let key_seed = Alice.to_seed(); - - let mut network_config = NetworkConfiguration::new( - format!("Test Node for: {}", key_seed), - "network/test/0.1", - Default::default(), - None, - ); - let informant_output_format = OutputFormat { enable_color: false }; - network_config.allow_non_globals_in_dht = true; - - network_config.listen_addresses.push(multiaddr::Protocol::Memory(0).into()); - - network_config.transport = TransportConfig::MemoryOnly; - - Configuration { - impl_name: "test-node".to_string(), - impl_version: "0.1".to_string(), - role: Role::Authority, - tokio_handle, - transaction_pool: Default::default(), - network: network_config, - keystore: KeystoreConfig::Path { path: root_path.join("key"), password: None }, - database: DatabaseSource::RocksDb { path: root_path.join("db"), cache_size: 128 }, - state_cache_size: 16777216, - state_cache_child_ratio: None, - chain_spec, - wasm_method: WasmExecutionMethod::Interpreted, - execution_strategies: ExecutionStrategies { - syncing: sc_client_api::ExecutionStrategy::AlwaysWasm, - importing: sc_client_api::ExecutionStrategy::AlwaysWasm, - block_construction: sc_client_api::ExecutionStrategy::AlwaysWasm, - offchain_worker: sc_client_api::ExecutionStrategy::AlwaysWasm, - other: sc_client_api::ExecutionStrategy::AlwaysWasm, - }, - rpc_http: None, - rpc_ws: None, - rpc_ipc: None, - rpc_ws_max_connections: None, - rpc_cors: None, - rpc_methods: Default::default(), - rpc_max_payload: None, - ws_max_out_buffer_capacity: None, - prometheus_config: None, - telemetry_endpoints: None, - default_heap_pages: None, - offchain_worker: Default::default(), - force_authoring: false, - disable_grandpa: false, - dev_key_seed: Some(key_seed), - tracing_targets: None, - tracing_receiver: Default::default(), - max_runtime_instances: 8, - announce_block: true, - base_path: Some(base_path), - wasm_runtime_overrides: None, - informant_output_format, - keystore_remote: None, - keep_blocks: KeepBlocks::All, - state_pruning: Default::default(), - transaction_storage: TransactionStorageMode::BlockBody, - runtime_cache_size: 2, - } -} From daa411864031bb19ebf66521b2780b786e60799e Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 11 Jan 2022 04:18:30 +0100 Subject: [PATCH 0415/1472] frame/bench-cli: fix log formatting (#10627) Signed-off-by: Oliver Tale-Yazdi --- utils/frame/benchmarking-cli/src/command.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/frame/benchmarking-cli/src/command.rs b/utils/frame/benchmarking-cli/src/command.rs index bd103862fe2c3..368b5ce59c952 100644 --- a/utils/frame/benchmarking-cli/src/command.rs +++ b/utils/frame/benchmarking-cli/src/command.rs @@ -333,14 +333,14 @@ impl BenchmarkCmd { if elapsed >= time::Duration::from_secs(5) { timer = time::SystemTime::now(); log::info!( - "Running Benchmark:\t{}\t{}\t{}/{}\t{}/{}", + "Running Benchmark: {}.{} {}/{} {}/{}", String::from_utf8(pallet.clone()) .expect("Encoded from String; qed"), String::from_utf8(extrinsic.clone()) .expect("Encoded from String; qed"), - s, // todo show step + s + 1, // s starts at 0. todo show step self.steps, - r, + r + 1, self.external_repeat, ); } From 835a8b0fe194c62dbf35d4b2d52237e52fad66ba Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Tue, 11 Jan 2022 13:29:35 +0300 Subject: [PATCH 0416/1472] Remove the `bench-test-full-crypto-feature` GHA & GitLab jobs (#10628) * Remove the `bench-test-full-crypto-feature` job * Remove the relevant GHA job --- .github/workflows/bench_gh_gl.yaml | 75 ------------------------------ .gitlab-ci.yml | 29 ------------ 2 files changed, 104 deletions(-) delete mode 100644 .github/workflows/bench_gh_gl.yaml diff --git a/.github/workflows/bench_gh_gl.yaml b/.github/workflows/bench_gh_gl.yaml deleted file mode 100644 index b243f7f661419..0000000000000 --- a/.github/workflows/bench_gh_gl.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# Please do not tamper with this job, it's a part of benchmarking experiment. -# However, you absolutely can copy it into another file and redo the last job in the pipeline. -# Just make sure you won't introduce long queues to the GHA runner, we have just one at the moment. - -name: bench GHA against GitLab - -on: - push: - branches: [ master ] - -jobs: - bench_gh: - runs-on: self-hosted - env: - CARGO_INCREMENTAL: 0 - RUSTUP_HOME: /usr/local/rustup - CARGO_HOME: /usr/local/cargo - CC: clang - CXX: clang - - steps: - - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - - - name: Install dependencies - # Template job, one can copy it to another pipeline. - run: | - apt-get update - apt-get install -y --no-install-recommends time clang - update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100 - - - name: Install Rust - # Template job, one can copy it to another pipeline. - # Referance code https://github.com/paritytech/scripts/blob/master/dockerfiles/base-ci-linux/Dockerfile - # Better keep Rust versions here in sync with the CI image, otherwise the results will conflict. - run: | - curl -L "https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init" -o rustup-init - chmod +x rustup-init - ./rustup-init -y --no-modify-path --profile minimal --default-toolchain stable - rm rustup-init - # add rustup tp PATH so it's usable right away - echo "/usr/local/cargo/bin" >> $GITHUB_PATH - source /usr/local/cargo/env - chmod -R a+w ${RUSTUP_HOME} ${CARGO_HOME} - # install nightly toolchain - rustup toolchain install nightly-2021-11-08 --profile minimal --component rustfmt clippy - # link the pinned toolchain to nightly - ln -s /usr/local/rustup/toolchains/nightly-2021-11-08-x86_64-unknown-linux-gnu /usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu - rustup target add wasm32-unknown-unknown - rustup target add wasm32-unknown-unknown --toolchain nightly - # show versions - rustup show - cargo --version - # remove clutter from the installations - rm -rf "${CARGO_HOME}/registry" "${CARGO_HOME}/git" - - - name: Checkout sources - uses: actions/checkout@v2 - - - name: bench-GHA-test-full-crypto-feature - # GitHub env variables reference: https://docs.github.com/en/actions/learn-github-actions/environment-variables - # The important part of the experiment is the line with `curl`: it sends the job's timing to Prometheus. - run: | - START_TIME=`date '+%s'` - cd primitives/core/ - time cargo +nightly build --verbose --no-default-features --features full_crypto - cd ../application-crypto - time cargo +nightly build --verbose --no-default-features --features full_crypto - END_TIME=`date '+%s'` - TOTAL_TIME=`expr $END_TIME - $START_TIME` - # please remove this line if you want to play with GHA runner. - curl -d "parity_github_job_time{project=\"$GITHUB_REPOSITORY\",job=\"$GITHUB_WORKFLOW\",runner=\"github\"} $TOTAL_TIME" -X POST http://vm-longterm.parity-build.parity.io/api/v1/import/prometheus diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2aee053ef4de3..19d3f63dc5fea 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -520,35 +520,6 @@ test-full-crypto-feature: - time cargo +nightly build --verbose --no-default-features --features full_crypto - sccache -s - -# Mostly same as the job above, additional instrumentation was added to push test run times -# to the time series database. -# This is temporary and will be eventually removed. -bench-test-full-crypto-feature: - stage: test - <<: *docker-env - <<: *build-refs - variables: - <<: *default-vars - RUSTFLAGS: "-Cdebug-assertions=y" - RUST_BACKTRACE: 1 - before_script: [""] - script: - # disable sccache for the bench purposes - - unset RUSTC_WRAPPER - - START_TIME=`date '+%s'` - - cd primitives/core/ - - time cargo +nightly build --verbose --no-default-features --features full_crypto - - cd ../application-crypto - - time cargo +nightly build --verbose --no-default-features --features full_crypto - - END_TIME=`date '+%s'` - - TOTAL_TIME=`expr $END_TIME - $START_TIME` - # send the job time measuring to the prometheus endpoint - - curl -d "parity_gitlab_job_time{project=\"$CI_PROJECT_PATH\",job=\"$CI_JOB_NAME\",runner=\"gitlab\"} $TOTAL_TIME" -X POST $VM_LONGTERM_URI/api/v1/import/prometheus - tags: - - linux-docker-compare - - test-wasmer-sandbox: stage: test <<: *docker-env From 004412194a73741866b9fedc9931a69e6f21de34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Tue, 11 Jan 2022 08:29:42 -0300 Subject: [PATCH 0417/1472] delete process.json (#10629) The feature was removed in https://github.com/paritytech/parity-processbot/pull/358 --- Process.json | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 Process.json diff --git a/Process.json b/Process.json deleted file mode 100644 index 540bd644311cf..0000000000000 --- a/Process.json +++ /dev/null @@ -1,29 +0,0 @@ -[{ - "project_name": "Networking", - "owner": "tomaka", - "matrix_room_id": "!vUADSGcyXmxhKLeDsW:matrix.parity.io" -}, -{ "project_name": "Client", - "owner": "gnunicorn", - "matrix_room_id": "!aenJixaHcSKbJOWxYk:matrix.parity.io" -}, -{ - "project_name": "Runtime", - "owner": "gavofyork", - "matrix_room_id": "!yBKstWVBkwzUkPslsp:matrix.parity.io" -}, -{ - "project_name": "Consensus", - "owner": "andresilva", - "matrix_room_id": "!XdNWDTfVNFVixljKZU:matrix.parity.io" -}, -{ - "project_name": "Smart Contracts", - "owner": "pepyakin", - "matrix_room_id": "!yBKstWVBkwzUkPslsp:matrix.parity.io" -}, -{ - "project_name": "Benchmarking and Weights", - "owner": "shawntabrizi", - "matrix_room_id": "!pZPWqCRLVtORZTEsEf:matrix.parity.io" -}] From a6b79439ae95ba4e673c1b733881dcab85885522 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 11 Jan 2022 15:22:27 +0100 Subject: [PATCH 0418/1472] pallet-lottery: add generate_storage_info (#10594) * pallet-lottery: add generate_storage_info Signed-off-by: Oliver Tale-Yazdi * pallet-lottery: test call_to_indices with TooManyCalls Signed-off-by: Oliver Tale-Yazdi * review: move try_push above transfer Signed-off-by: Oliver Tale-Yazdi * pallet-lottery: test stop_repeat Signed-off-by: Oliver Tale-Yazdi * pallet-lottery: test do_buy_ticket as white-box Signed-off-by: Oliver Tale-Yazdi * pallet-lottery: use BoundedVec in bechmarks Signed-off-by: Oliver Tale-Yazdi * pallet-lottery: fix zero div panic Signed-off-by: Oliver Tale-Yazdi * review: extend buy_ticket tests Signed-off-by: Oliver Tale-Yazdi * review: test buy_ticket AlreadyParticipating Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * review: use /// comments on private functions Signed-off-by: Oliver Tale-Yazdi * review: use with_bounded_capacity Signed-off-by: Oliver Tale-Yazdi --- frame/lottery/src/benchmarking.rs | 11 +- frame/lottery/src/lib.rs | 77 ++++++++----- frame/lottery/src/tests.rs | 179 +++++++++++++++++++++++++++++- 3 files changed, 235 insertions(+), 32 deletions(-) diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index f4a8e88e5e3f1..1c850e66f9c6e 100644 --- a/frame/lottery/src/benchmarking.rs +++ b/frame/lottery/src/benchmarking.rs @@ -22,7 +22,10 @@ use super::*; use frame_benchmarking::{account, benchmarks, whitelisted_caller}; -use frame_support::traits::{EnsureOrigin, OnInitialize}; +use frame_support::{ + storage::bounded_vec::BoundedVec, + traits::{EnsureOrigin, OnInitialize}, +}; use frame_system::RawOrigin; use sp_runtime::traits::{Bounded, Zero}; @@ -55,12 +58,12 @@ benchmarks! { let set_code_index: CallIndex = Lottery::::call_to_index( &frame_system::Call::::set_code{ code: vec![] }.into() )?; - let already_called: (u32, Vec) = ( + let already_called: (u32, BoundedVec) = ( LotteryIndex::::get(), - vec![ + BoundedVec::::try_from(vec![ set_code_index; T::MaxCalls::get().saturating_sub(1) as usize - ], + ]).unwrap(), ); Participants::::insert(&caller, already_called); diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index 5a985094dd1c9..b04dbc8455684 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -28,7 +28,7 @@ //! users to make those calls on your network. An example of how this could be //! used is to set validator nominations as a valid lottery call. If the lottery //! is set to repeat every month, then users would be encouraged to re-nominate -//! validators every month. A user can ony purchase one ticket per valid call +//! validators every month. A user can only purchase one ticket per valid call //! per lottery. //! //! This pallet can be configured to use dynamically set calls or statically set @@ -58,6 +58,8 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchResult, Dispatchable, GetDispatchInfo}, ensure, + pallet_prelude::MaxEncodedLen, + storage::bounded_vec::BoundedVec, traits::{Currency, ExistenceRequirement::KeepAlive, Get, Randomness, ReservableCurrency}, PalletId, RuntimeDebug, }; @@ -76,7 +78,9 @@ type BalanceOf = // We use this to uniquely match someone's incoming call with the calls configured for the lottery. type CallIndex = (u8, u8); -#[derive(Encode, Decode, Default, Eq, PartialEq, RuntimeDebug, scale_info::TypeInfo)] +#[derive( + Encode, Decode, Default, Eq, PartialEq, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen, +)] pub struct LotteryConfig { /// Price per entry. price: Balance, @@ -120,6 +124,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] pub struct Pallet(_); /// The pallet's config trait. @@ -209,8 +214,13 @@ pub mod pallet { /// Users who have purchased a ticket. (Lottery Index, Tickets Purchased) #[pallet::storage] - pub(crate) type Participants = - StorageMap<_, Twox64Concat, T::AccountId, (u32, Vec), ValueQuery>; + pub(crate) type Participants = StorageMap< + _, + Twox64Concat, + T::AccountId, + (u32, BoundedVec), + ValueQuery, + >; /// Total number of tickets sold. #[pallet::storage] @@ -226,7 +236,8 @@ pub mod pallet { /// The calls stored in this pallet to be used in an active lottery if configured /// by `Config::ValidateCall`. #[pallet::storage] - pub(crate) type CallIndices = StorageValue<_, Vec, ValueQuery>; + pub(crate) type CallIndices = + StorageValue<_, BoundedVec, ValueQuery>; #[pallet::hooks] impl Hooks> for Pallet { @@ -237,10 +248,8 @@ pub mod pallet { config.start.saturating_add(config.length).saturating_add(config.delay); if payout_block <= n { let (lottery_account, lottery_balance) = Self::pot(); - let ticket_count = TicketsCount::::get(); - let winning_number = Self::choose_winner(ticket_count); - let winner = Tickets::::get(winning_number).unwrap_or(lottery_account); + let winner = Self::choose_account().unwrap_or(lottery_account); // Not much we can do if this fails... let res = T::Currency::transfer( &Self::account_id(), @@ -385,7 +394,7 @@ impl Pallet { } /// Return the pot account and amount of money in the pot. - // The existential deposit is not part of the pot so lottery account never gets deleted. + /// The existential deposit is not part of the pot so lottery account never gets deleted. fn pot() -> (T::AccountId, BalanceOf) { let account_id = Self::account_id(); let balance = @@ -394,17 +403,19 @@ impl Pallet { (account_id, balance) } - // Converts a vector of calls into a vector of call indices. - fn calls_to_indices(calls: &[::Call]) -> Result, DispatchError> { - let mut indices = Vec::with_capacity(calls.len()); + /// Converts a vector of calls into a vector of call indices. + fn calls_to_indices( + calls: &[::Call], + ) -> Result, DispatchError> { + let mut indices = BoundedVec::::with_bounded_capacity(calls.len()); for c in calls.iter() { let index = Self::call_to_index(c)?; - indices.push(index) + indices.try_push(index).map_err(|_| Error::::TooManyCalls)?; } Ok(indices) } - // Convert a call to it's call index by encoding the call and taking the first two bytes. + /// Convert a call to it's call index by encoding the call and taking the first two bytes. fn call_to_index(call: &::Call) -> Result { let encoded_call = call.encode(); if encoded_call.len() < 2 { @@ -413,7 +424,7 @@ impl Pallet { return Ok((encoded_call[0], encoded_call[1])) } - // Logic for buying a ticket. + /// Logic for buying a ticket. fn do_buy_ticket(caller: &T::AccountId, call: &::Call) -> DispatchResult { // Check the call is valid lottery let config = Lottery::::get().ok_or(Error::::NotConfigured)?; @@ -433,7 +444,7 @@ impl Pallet { let index = LotteryIndex::::get(); // If lottery index doesn't match, then reset participating calls and index. if *lottery_index != index { - *participating_calls = Vec::new(); + *participating_calls = Default::default(); *lottery_index = index; } else { // Check that user is not already participating under this call. @@ -442,12 +453,12 @@ impl Pallet { Error::::AlreadyParticipating ); } + participating_calls.try_push(call_index).map_err(|_| Error::::TooManyCalls)?; // Check user has enough funds and send it to the Lottery account. T::Currency::transfer(caller, &Self::account_id(), config.price, KeepAlive)?; // Create a new ticket. TicketsCount::::put(new_ticket_count); Tickets::::insert(ticket_count, caller.clone()); - participating_calls.push(call_index); Ok(()) }, )?; @@ -457,8 +468,22 @@ impl Pallet { Ok(()) } - // Randomly choose a winner from among the total number of participants. - fn choose_winner(total: u32) -> u32 { + /// Randomly choose a winning ticket and return the account that purchased it. + /// The more tickets an account bought, the higher are its chances of winning. + /// Returns `None` if there is no winner. + fn choose_account() -> Option { + match Self::choose_ticket(TicketsCount::::get()) { + None => None, + Some(ticket) => Tickets::::get(ticket), + } + } + + /// Randomly choose a winning ticket from among the total number of tickets. + /// Returns `None` if there are no tickets. + fn choose_ticket(total: u32) -> Option { + if total == 0 { + return None + } let mut random_number = Self::generate_random_number(0); // Best effort attempt to remove bias from modulus operator. @@ -470,15 +495,15 @@ impl Pallet { random_number = Self::generate_random_number(i); } - random_number % total + Some(random_number % total) } - // Generate a random number from a given seed. - // Note that there is potential bias introduced by using modulus operator. - // You should call this function with different seed values until the random - // number lies within `u32::MAX - u32::MAX % n`. - // TODO: deal with randomness freshness - // https://github.com/paritytech/substrate/issues/8311 + /// Generate a random number from a given seed. + /// Note that there is potential bias introduced by using modulus operator. + /// You should call this function with different seed values until the random + /// number lies within `u32::MAX - u32::MAX % n`. + /// TODO: deal with randomness freshness + /// https://github.com/paritytech/substrate/issues/8311 fn generate_random_number(seed: u32) -> u32 { let (random_seed, _) = T::Randomness::random(&(T::PalletId::get(), seed).encode()); let random_number = ::decode(&mut random_seed.as_ref()) diff --git a/frame/lottery/src/tests.rs b/frame/lottery/src/tests.rs index 143a4b0528773..d8dd6e4b7fe6c 100644 --- a/frame/lottery/src/tests.rs +++ b/frame/lottery/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for the module. use super::*; -use frame_support::{assert_noop, assert_ok}; +use frame_support::{assert_noop, assert_ok, assert_storage_noop}; use mock::{ new_test_ext, run_to_block, Balances, BalancesCall, Call, Lottery, Origin, SystemCall, Test, }; @@ -30,7 +30,7 @@ fn initial_state() { new_test_ext().execute_with(|| { assert_eq!(Balances::free_balance(Lottery::account_id()), 0); assert!(crate::Lottery::::get().is_none()); - assert_eq!(Participants::::get(&1), (0, vec![])); + assert_eq!(Participants::::get(&1), (0, Default::default())); assert_eq!(TicketsCount::::get(), 0); assert!(Tickets::::get(0).is_none()); }); @@ -90,6 +90,37 @@ fn basic_end_to_end_works() { }); } +/// Only the manager can stop the Lottery from repeating via `stop_repeat`. +#[test] +fn stop_repeat_works() { + new_test_ext().execute_with(|| { + let price = 10; + let length = 20; + let delay = 5; + + // Set no calls for the lottery. + assert_ok!(Lottery::set_calls(Origin::root(), vec![])); + // Start lottery, it repeats. + assert_ok!(Lottery::start_lottery(Origin::root(), price, length, delay, true)); + + // Non-manager fails to `stop_repeat`. + assert_noop!(Lottery::stop_repeat(Origin::signed(1)), DispatchError::BadOrigin); + // Manager can `stop_repeat`, even twice. + assert_ok!(Lottery::stop_repeat(Origin::root())); + assert_ok!(Lottery::stop_repeat(Origin::root())); + + // Lottery still exists. + assert!(crate::Lottery::::get().is_some()); + // End and pick a winner. + run_to_block(length + delay); + + // Lottery stays dead and does not repeat. + assert!(crate::Lottery::::get().is_none()); + run_to_block(length + delay + 1); + assert!(crate::Lottery::::get().is_none()); + }); +} + #[test] fn set_calls_works() { new_test_ext().execute_with(|| { @@ -120,6 +151,27 @@ fn set_calls_works() { }); } +#[test] +fn call_to_indices_works() { + new_test_ext().execute_with(|| { + let calls = vec![ + Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + ]; + let indices = Lottery::calls_to_indices(&calls).unwrap().into_inner(); + // Only comparing the length since it is otherwise dependant on the API + // of `BalancesCall`. + assert_eq!(indices.len(), calls.len()); + + let too_many_calls = vec![ + Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + Call::System(SystemCall::remark { remark: vec![] }), + ]; + assert_noop!(Lottery::calls_to_indices(&too_many_calls), Error::::TooManyCalls); + }); +} + #[test] fn start_lottery_works() { new_test_ext().execute_with(|| { @@ -239,6 +291,106 @@ fn buy_ticket_works() { }); } +/// Test that `do_buy_ticket` returns an `AlreadyParticipating` error. +/// Errors of `do_buy_ticket` are ignored by `buy_ticket`, therefore this white-box test. +#[test] +fn do_buy_ticket_already_participating() { + new_test_ext().execute_with(|| { + let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + assert_ok!(Lottery::start_lottery(Origin::root(), 1, 10, 10, false)); + + // Buying once works. + assert_ok!(Lottery::do_buy_ticket(&1, &calls[0])); + // Buying the same ticket again fails. + assert_noop!(Lottery::do_buy_ticket(&1, &calls[0]), Error::::AlreadyParticipating); + }); +} + +/// `buy_ticket` is a storage noop when called with the same ticket again. +#[test] +fn buy_ticket_already_participating() { + new_test_ext().execute_with(|| { + let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + assert_ok!(Lottery::start_lottery(Origin::root(), 1, 10, 10, false)); + + // Buying once works. + let call = Box::new(calls[0].clone()); + assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + + // Buying the same ticket again returns Ok, but changes nothing. + assert_storage_noop!(Lottery::buy_ticket(Origin::signed(1), call).unwrap()); + + // Exactly one ticket exists. + assert_eq!(TicketsCount::::get(), 1); + }); +} + +/// `buy_ticket` is a storage noop when called with insufficient balance. +#[test] +fn buy_ticket_insufficient_balance() { + new_test_ext().execute_with(|| { + let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + // Price set to 100. + assert_ok!(Lottery::start_lottery(Origin::root(), 100, 10, 10, false)); + let call = Box::new(calls[0].clone()); + + // Buying a ticket returns Ok, but changes nothing. + assert_storage_noop!(Lottery::buy_ticket(Origin::signed(1), call).unwrap()); + assert!(TicketsCount::::get().is_zero()); + }); +} + +#[test] +fn do_buy_ticket_insufficient_balance() { + new_test_ext().execute_with(|| { + let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + // Price set to 101. + assert_ok!(Lottery::start_lottery(Origin::root(), 101, 10, 10, false)); + + // Buying fails with InsufficientBalance. + assert_noop!( + Lottery::do_buy_ticket(&1, &calls[0]), + BalancesError::::InsufficientBalance + ); + assert!(TicketsCount::::get().is_zero()); + }); +} + +#[test] +fn do_buy_ticket_keep_alive() { + new_test_ext().execute_with(|| { + let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + // Price set to 100. + assert_ok!(Lottery::start_lottery(Origin::root(), 100, 10, 10, false)); + + // Buying fails with KeepAlive. + assert_noop!(Lottery::do_buy_ticket(&1, &calls[0]), BalancesError::::KeepAlive); + assert!(TicketsCount::::get().is_zero()); + }); +} + +/// The lottery handles the case that no one participated. +#[test] +fn no_participants_works() { + new_test_ext().execute_with(|| { + let length = 20; + let delay = 5; + + // Set no calls for the lottery. + assert_ok!(Lottery::set_calls(Origin::root(), vec![])); + // Start lottery. + assert_ok!(Lottery::start_lottery(Origin::root(), 10, length, delay, false)); + + // End the lottery, no one wins. + run_to_block(length + delay); + }); +} + #[test] fn start_lottery_will_create_account() { new_test_ext().execute_with(|| { @@ -251,3 +403,26 @@ fn start_lottery_will_create_account() { assert_eq!(Balances::total_balance(&Lottery::account_id()), 1); }); } + +#[test] +fn choose_ticket_trivial_cases() { + new_test_ext().execute_with(|| { + assert!(Lottery::choose_ticket(0).is_none()); + assert_eq!(Lottery::choose_ticket(1).unwrap(), 0); + }); +} + +#[test] +fn choose_account_one_participant() { + new_test_ext().execute_with(|| { + let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + assert_ok!(Lottery::start_lottery(Origin::root(), 10, 10, 10, false)); + let call = Box::new(calls[0].clone()); + + // Buy one ticket with account 1. + assert_ok!(Lottery::buy_ticket(Origin::signed(1), call)); + // Account 1 is always the winner. + assert_eq!(Lottery::choose_account().unwrap(), 1); + }); +} From 75c960922d9cf24627e2b3b53e2925f23316c0b6 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 11 Jan 2022 19:13:06 +0100 Subject: [PATCH 0419/1472] followup #10594: re-benchmark pallet-lottery (#10637) * pallet-preimage: fix crate doc Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_lottery --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/lottery/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- frame/lottery/src/weights.rs | 37 ++++++++++++++++++------------------ frame/preimage/src/lib.rs | 2 +- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index 5d252e9d5650e..53ec2aa231568 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_lottery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-11, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -35,7 +35,6 @@ // --output=./frame/lottery/src/weights.rs // --template=./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -64,28 +63,28 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (70_034_000 as Weight) + (52_219_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (15_243_000 as Weight) - // Standard Error: 8_000 - .saturating_add((312_000 as Weight).saturating_mul(n as Weight)) + (13_249_000 as Weight) + // Standard Error: 7_000 + .saturating_add((378_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (57_312_000 as Weight) + (44_636_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (6_964_000 as Weight) + (5_654_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -95,7 +94,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (110_470_000 as Weight) + (72_990_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -106,7 +105,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (114_794_000 as Weight) + (75_323_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -122,28 +121,28 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (70_034_000 as Weight) + (52_219_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (15_243_000 as Weight) - // Standard Error: 8_000 - .saturating_add((312_000 as Weight).saturating_mul(n as Weight)) + (13_249_000 as Weight) + // Standard Error: 7_000 + .saturating_add((378_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (57_312_000 as Weight) + (44_636_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (6_964_000 as Weight) + (5_654_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -153,7 +152,7 @@ impl WeightInfo for () { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (110_470_000 as Weight) + (72_990_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -164,7 +163,7 @@ impl WeightInfo for () { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (114_794_000 as Weight) + (75_323_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 17fc543084c99..7564629bad299 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -23,7 +23,7 @@ //! ## Overview //! //! The Preimage pallet allows for the users and the runtime to store the preimage -//! of a hash on chain. This can be used by other pallets where storing and managing +//! of a hash on chain. This can be used by other pallets for storing and managing //! large byte-blobs. #![cfg_attr(not(feature = "std"), no_std)] From 3541490fefd1049afb8219b1053cdd653a9225f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jan 2022 09:18:23 +0100 Subject: [PATCH 0420/1472] Bump twox-hash from 1.6.1 to 1.6.2 (#10575) Bumps [twox-hash](https://github.com/shepmaster/twox-hash) from 1.6.1 to 1.6.2. - [Release notes](https://github.com/shepmaster/twox-hash/releases) - [Commits](https://github.com/shepmaster/twox-hash/compare/v1.6.1...v1.6.2) --- updated-dependencies: - dependency-name: twox-hash 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 ++-- primitives/core/Cargo.toml | 2 +- primitives/core/hashing/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65b0897947f1a..b65795a373b35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11003,9 +11003,9 @@ checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055" [[package]] name = "twox-hash" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e" +checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ "cfg-if 1.0.0", "rand 0.8.4", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index c1ca9f081570e..83228b9251ddf 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -64,7 +64,7 @@ schnorrkel = { version = "0.9.1", features = [ ], default-features = false, optional = true } sha2 = { version = "0.10.0", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } -twox-hash = { version = "1.6.1", default-features = false, optional = true } +twox-hash = { version = "1.6.2", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", "static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } ss58-registry = { version = "1.10.0", default-features = false } diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index e9f3c8c714f71..8a84e585dad2a 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -19,7 +19,7 @@ byteorder = { version = "1.3.2", default-features = false } blake2-rfc = { version = "0.2.18", default-features = false } tiny-keccak = { version = "2.0.1", features = ["keccak"] } sha2 = { version = "0.10.0", default-features = false } -twox-hash = { version = "1.5.0", default-features = false } +twox-hash = { version = "1.6.2", default-features = false } [features] default = ["std"] From 306be17524ac0cd28cbb048dc2f73e43a39cba19 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Wed, 12 Jan 2022 21:22:29 +1300 Subject: [PATCH 0421/1472] reset events before apply runtime upgrade (#10620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * reset events before apply runtime upgrade * fix tests * add test * update comment * Update frame/system/src/lib.rs * trigger CI Co-authored-by: Bastian Köcher --- frame/aura/src/tests.rs | 4 +- frame/authorship/src/lib.rs | 6 ++- frame/babe/src/mock.rs | 7 ++-- frame/babe/src/tests.rs | 17 ++++---- frame/contracts/src/tests.rs | 3 +- frame/executive/src/lib.rs | 45 +++++++++++++++------ frame/grandpa/src/mock.rs | 6 ++- frame/merkle-mountain-range/src/tests.rs | 8 +--- frame/randomness-collective-flip/src/lib.rs | 3 +- frame/system/src/lib.rs | 42 +++---------------- frame/system/src/tests.rs | 21 ++++++---- 11 files changed, 79 insertions(+), 83 deletions(-) diff --git a/frame/aura/src/tests.rs b/frame/aura/src/tests.rs index 30003632729ea..ce09f85678c00 100644 --- a/frame/aura/src/tests.rs +++ b/frame/aura/src/tests.rs @@ -22,7 +22,6 @@ use crate::mock::{new_test_ext, Aura, MockDisabledValidators, System}; use codec::Encode; use frame_support::traits::OnInitialize; -use frame_system::InitKind; use sp_consensus_aura::{Slot, AURA_ENGINE_ID}; use sp_runtime::{Digest, DigestItem}; @@ -45,7 +44,8 @@ fn disabled_validators_cannot_author_blocks() { let pre_digest = Digest { logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())] }; - System::initialize(&42, &System::parent_hash(), &pre_digest, InitKind::Full); + System::reset_events(); + System::initialize(&42, &System::parent_hash(), &pre_digest); // let's disable the validator MockDisabledValidators::disable_validator(1); diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index db453fc57e9e6..3fa081f5263e3 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -596,7 +596,8 @@ mod tests { }; let initialize_block = |number, hash: H256| { - System::initialize(&number, &hash, &Default::default(), Default::default()) + System::reset_events(); + System::initialize(&number, &hash, &Default::default()) }; for number in 1..8 { @@ -689,7 +690,8 @@ mod tests { seal_header(create_header(1, Default::default(), [1; 32].into()), author); header.digest_mut().pop(); // pop the seal off. - System::initialize(&1, &Default::default(), header.digest(), Default::default()); + System::reset_events(); + System::initialize(&1, &Default::default(), header.digest()); assert_eq!(Authorship::author(), Some(author)); }); diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index f0faa55e5b333..22d7befab6686 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -24,7 +24,6 @@ use frame_support::{ parameter_types, traits::{ConstU128, ConstU32, ConstU64, GenesisBuild, KeyOwnerProofSystem, OnInitialize}, }; -use frame_system::InitKind; use pallet_session::historical as pallet_session_historical; use pallet_staking::EraIndex; use sp_consensus_babe::{AuthorityId, AuthorityPair, Slot}; @@ -255,7 +254,8 @@ pub fn go_to_block(n: u64, s: u64) { let pre_digest = make_secondary_plain_pre_digest(0, s.into()); - System::initialize(&n, &parent_hash, &pre_digest, InitKind::Full); + System::reset_events(); + System::initialize(&n, &parent_hash, &pre_digest); Babe::on_initialize(n); Session::on_initialize(n); @@ -421,7 +421,8 @@ pub fn generate_equivocation_proof( let make_header = || { let parent_hash = System::parent_hash(); let pre_digest = make_secondary_plain_pre_digest(offender_authority_index, slot); - System::initialize(¤t_block, &parent_hash, &pre_digest, InitKind::Full); + System::reset_events(); + System::initialize(¤t_block, &parent_hash, &pre_digest); System::set_block_number(current_block); Timestamp::set_timestamp(current_block); System::finalize() diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 89911efe4e8af..65c9de85586e4 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -67,7 +67,8 @@ fn first_block_epoch_zero_start() { let pre_digest = make_primary_pre_digest(0, genesis_slot, first_vrf.clone(), vrf_proof); assert_eq!(Babe::genesis_slot(), Slot::from(0)); - System::initialize(&1, &Default::default(), &pre_digest, Default::default()); + System::reset_events(); + System::initialize(&1, &Default::default(), &pre_digest); // see implementation of the function for details why: we issue an // epoch-change digest but don't do it via the normal session mechanism. @@ -112,7 +113,8 @@ fn author_vrf_output_for_primary() { let (vrf_output, vrf_proof, vrf_randomness) = make_vrf_output(genesis_slot, &pairs[0]); let primary_pre_digest = make_primary_pre_digest(0, genesis_slot, vrf_output, vrf_proof); - System::initialize(&1, &Default::default(), &primary_pre_digest, Default::default()); + System::reset_events(); + System::initialize(&1, &Default::default(), &primary_pre_digest); Babe::do_initialize(1); assert_eq!(Babe::author_vrf_randomness(), Some(vrf_randomness)); @@ -133,7 +135,8 @@ fn author_vrf_output_for_secondary_vrf() { let secondary_vrf_pre_digest = make_secondary_vrf_pre_digest(0, genesis_slot, vrf_output, vrf_proof); - System::initialize(&1, &Default::default(), &secondary_vrf_pre_digest, Default::default()); + System::reset_events(); + System::initialize(&1, &Default::default(), &secondary_vrf_pre_digest); Babe::do_initialize(1); assert_eq!(Babe::author_vrf_randomness(), Some(vrf_randomness)); @@ -150,12 +153,8 @@ fn no_author_vrf_output_for_secondary_plain() { let genesis_slot = Slot::from(10); let secondary_plain_pre_digest = make_secondary_plain_pre_digest(0, genesis_slot); - System::initialize( - &1, - &Default::default(), - &secondary_plain_pre_digest, - Default::default(), - ); + System::reset_events(); + System::initialize(&1, &Default::default(), &secondary_plain_pre_digest); assert_eq!(Babe::author_vrf_randomness(), None); Babe::do_initialize(1); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 17e8f746be1ff..be9904e71c5c9 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -533,7 +533,8 @@ fn run_out_of_gas() { } fn initialize_block(number: u64) { - System::initialize(&number, &[0u8; 32].into(), &Default::default(), Default::default()); + System::reset_events(); + System::initialize(&number, &[0u8; 32].into(), &Default::default()); } #[test] diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index be944954eaa59..d19ea8127bad3 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -294,16 +294,16 @@ where parent_hash: &System::Hash, digest: &Digest, ) { + // Reset events before apply runtime upgrade hook. + // This is required to preserve events from runtime upgrade hook. + // This means the format of all the event related storages must always be compatible. + >::reset_events(); + let mut weight = 0; if Self::runtime_upgraded() { weight = weight.saturating_add(Self::execute_on_runtime_upgrade()); } - >::initialize( - block_number, - parent_hash, - digest, - frame_system::InitKind::Full, - ); + >::initialize(block_number, parent_hash, digest); weight = weight.saturating_add(>::on_initialize(*block_number)); @@ -510,7 +510,6 @@ where &(frame_system::Pallet::::block_number() + One::one()), &block_hash, &Default::default(), - frame_system::InitKind::Inspection, ); enter_span! { sp_tracing::Level::TRACE, "validate_transaction" }; @@ -541,12 +540,7 @@ where // OffchainWorker RuntimeApi should skip initialization. let digests = header.digest().clone(); - >::initialize( - header.number(), - header.parent_hash(), - &digests, - frame_system::InitKind::Inspection, - ); + >::initialize(header.number(), header.parent_hash(), &digests); // Frame system only inserts the parent hash into the block hashes as normally we don't know // the hash for the header before. However, here we are aware of the hash and we can add it @@ -830,6 +824,7 @@ mod tests { fn on_runtime_upgrade() -> Weight { sp_io::storage::set(TEST_KEY, "custom_upgrade".as_bytes()); sp_io::storage::set(CUSTOM_ON_RUNTIME_KEY, &true.encode()); + System::deposit_event(frame_system::Event::CodeUpdated); 100 } } @@ -1296,6 +1291,30 @@ mod tests { }); } + #[test] + fn event_from_runtime_upgrade_is_included() { + new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called. + RUNTIME_VERSION.with(|v| { + *v.borrow_mut() = + sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + // set block number to non zero so events are not exlcuded + System::set_block_number(1); + + Executive::initialize_block(&Header::new( + 2, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + System::assert_last_event(frame_system::Event::::CodeUpdated.into()); + }); + } + /// Regression test that ensures that the custom on runtime upgrade is called when executive is /// used through the `ExecuteBlock` trait. #[test] diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index ddfae3d7ea75b..91006d66b7deb 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -326,7 +326,8 @@ pub fn start_session(session_index: SessionIndex) { System::parent_hash() }; - System::initialize(&(i as u64 + 1), &parent_hash, &Default::default(), Default::default()); + System::reset_events(); + System::initialize(&(i as u64 + 1), &parent_hash, &Default::default()); System::set_block_number((i + 1).into()); Timestamp::set_timestamp(System::block_number() * 6000); @@ -345,7 +346,8 @@ pub fn start_era(era_index: EraIndex) { } pub fn initialize_block(number: u64, parent_hash: H256) { - System::initialize(&number, &parent_hash, &Default::default(), Default::default()); + System::reset_events(); + System::initialize(&number, &parent_hash, &Default::default()); } pub fn generate_equivocation_proof( diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 588a407d6d371..576a7ace8f1c0 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -40,12 +40,8 @@ fn new_block() -> u64 { let hash = H256::repeat_byte(number as u8); LEAF_DATA.with(|r| r.borrow_mut().a = number); - frame_system::Pallet::::initialize( - &number, - &hash, - &Default::default(), - frame_system::InitKind::Full, - ); + frame_system::Pallet::::reset_events(); + frame_system::Pallet::::initialize(&number, &hash, &Default::default()); MMR::on_initialize(number) } diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index 5f4994c471424..fbc8aaaa7ec59 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -239,7 +239,8 @@ mod tests { let mut parent_hash = System::parent_hash(); for i in 1..(blocks + 1) { - System::initialize(&i, &parent_hash, &Default::default(), frame_system::InitKind::Full); + System::reset_events(); + System::initialize(&i, &parent_hash, &Default::default()); CollectiveFlip::on_initialize(i); let header = System::finalize(); diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index cec45a8aa1cb1..7615424ba57ee 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -944,27 +944,6 @@ where } } -/// A type of block initialization to perform. -pub enum InitKind { - /// Leave inspectable storage entries in state. - /// - /// i.e. `Events` are not being reset. - /// Should only be used for off-chain calls, - /// regular block execution should clear those. - Inspection, - - /// Reset also inspectable storage entries. - /// - /// This should be used for regular block execution. - Full, -} - -impl Default for InitKind { - fn default() -> Self { - InitKind::Full - } -} - /// Reference status; can be either referenced or unreferenced. #[derive(RuntimeDebug)] pub enum RefStatus { @@ -1302,12 +1281,7 @@ impl Pallet { } /// Start the execution of a particular block. - pub fn initialize( - number: &T::BlockNumber, - parent_hash: &T::Hash, - digest: &generic::Digest, - kind: InitKind, - ) { + pub fn initialize(number: &T::BlockNumber, parent_hash: &T::Hash, digest: &generic::Digest) { // populate environment ExecutionPhase::::put(Phase::Initialization); storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &0u32); @@ -1318,13 +1292,6 @@ impl Pallet { // Remove previous block data from storage BlockWeight::::kill(); - - // Kill inspectable storage entries in state when `InitKind::Full`. - if let InitKind::Full = kind { - >::kill(); - EventCount::::kill(); - >::remove_all(None); - } } /// Remove temporary "environment" entries in storage, compute the storage root and return the @@ -1444,9 +1411,10 @@ impl Pallet { AllExtrinsicsLen::::put(len as u32); } - /// Reset events. Can be used as an alternative to - /// `initialize` for tests that don't need to bother with the other environment entries. - #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] + /// Reset events. + /// + /// This needs to be used in prior calling [`initialize`](Self::initialize) for each new block + /// to clear events from previous block. pub fn reset_events() { >::kill(); EventCount::::kill(); diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index 411925c70275f..0facd796b2a0c 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -154,7 +154,8 @@ fn provider_required_to_support_consumer() { #[test] fn deposit_event_should_work() { new_test_ext().execute_with(|| { - System::initialize(&1, &[0u8; 32].into(), &Default::default(), InitKind::Full); + System::reset_events(); + System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::note_finished_extrinsics(); System::deposit_event(SysEvent::CodeUpdated); System::finalize(); @@ -167,7 +168,8 @@ fn deposit_event_should_work() { }] ); - System::initialize(&2, &[0u8; 32].into(), &Default::default(), InitKind::Full); + System::reset_events(); + System::initialize(&2, &[0u8; 32].into(), &Default::default()); System::deposit_event(SysEvent::NewAccount { account: 32 }); System::note_finished_initialize(); System::deposit_event(SysEvent::KilledAccount { account: 42 }); @@ -216,7 +218,8 @@ fn deposit_event_should_work() { #[test] fn deposit_event_uses_actual_weight() { new_test_ext().execute_with(|| { - System::initialize(&1, &[0u8; 32].into(), &Default::default(), InitKind::Full); + System::reset_events(); + System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::note_finished_initialize(); let pre_info = DispatchInfo { weight: 1000, ..Default::default() }; @@ -275,7 +278,8 @@ fn deposit_event_topics() { new_test_ext().execute_with(|| { const BLOCK_NUMBER: u64 = 1; - System::initialize(&BLOCK_NUMBER, &[0u8; 32].into(), &Default::default(), InitKind::Full); + System::reset_events(); + System::initialize(&BLOCK_NUMBER, &[0u8; 32].into(), &Default::default()); System::note_finished_extrinsics(); let topics = vec![H256::repeat_byte(1), H256::repeat_byte(2), H256::repeat_byte(3)]; @@ -333,7 +337,8 @@ fn prunes_block_hash_mappings() { new_test_ext().execute_with(|| { // simulate import of 15 blocks for n in 1..=15 { - System::initialize(&n, &[n as u8 - 1; 32].into(), &Default::default(), InitKind::Full); + System::reset_events(); + System::initialize(&n, &[n as u8 - 1; 32].into(), &Default::default()); System::finalize(); } @@ -464,7 +469,8 @@ fn events_not_emitted_during_genesis() { #[test] fn extrinsics_root_is_calculated_correctly() { new_test_ext().execute_with(|| { - System::initialize(&1, &[0u8; 32].into(), &Default::default(), InitKind::Full); + System::reset_events(); + System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::note_finished_initialize(); System::note_extrinsic(vec![1]); System::note_applied_extrinsic(&Ok(().into()), Default::default()); @@ -481,7 +487,8 @@ fn extrinsics_root_is_calculated_correctly() { #[test] fn runtime_updated_digest_emitted_when_heap_pages_changed() { new_test_ext().execute_with(|| { - System::initialize(&1, &[0u8; 32].into(), &Default::default(), InitKind::Full); + System::reset_events(); + System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::set_heap_pages(RawOrigin::Root.into(), 5).unwrap(); assert_runtime_updated_digest(1); }); From fb24fda76d613305ebb2e5728c75362c94b64aa1 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 12 Jan 2022 09:33:25 +0100 Subject: [PATCH 0422/1472] [ci] pipeline chores (#10624) * [Do not merge] pipeline chores * disable condition publish-rustdoc * revert rules * remove PIPELINE_SCRIPTS_TAG --- .gitlab-ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 19d3f63dc5fea..43674da4627a5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,7 +42,6 @@ variables: &default-vars VAULT_SERVER_URL: "https://vault.parity-mgmt-vault.parity.io" VAULT_AUTH_PATH: "gitlab-parity-io-jwt" VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" - PIPELINE_SCRIPTS_TAG: "v0.4" default: cache: {} @@ -543,6 +542,8 @@ cargo-check-macos: #### stage: build +# PIPELINE_SCRIPTS_TAG can be found in the project variables + .check-dependent-project: &check-dependent-project stage: build <<: *docker-env @@ -772,8 +773,6 @@ publish-rustdoc: # whole space-separated value. - '[[ " ${RUSTDOCS_DEPLOY_REFS} " =~ " ${CI_COMMIT_REF_NAME} " ]] || exit 0' # setup ssh - # FIXME: add ssh to docker image - - apt-get update && apt-get install -y ssh - eval $(ssh-agent) - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} - mkdir ~/.ssh && touch ~/.ssh/known_hosts From f2822169f8b05234ceadae590bb09dd7df9e2f50 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Thu, 13 Jan 2022 16:26:06 +0100 Subject: [PATCH 0423/1472] Fast/warp sync fixes (#10562) * Fast sync fixes * Fix gap blocks validation * Updated test * Formatting * Networking test --- client/consensus/babe/src/lib.rs | 6 +- client/db/src/lib.rs | 59 +++++++++++++------- client/network/src/protocol/sync.rs | 56 +++++++++++++++++-- client/service/src/client/client.rs | 3 +- client/state-db/src/lib.rs | 3 + client/state-db/src/noncanonical.rs | 22 +++++++- primitives/blockchain/src/header_metadata.rs | 9 ++- 7 files changed, 126 insertions(+), 32 deletions(-) diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 612a05ffaa678..a86eac35a1000 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -347,7 +347,11 @@ impl Config { { trace!(target: "babe", "Getting slot duration"); - let best_block_id = BlockId::Hash(client.usage_info().chain.best_hash); + let mut best_block_id = BlockId::Hash(client.usage_info().chain.best_hash); + if client.usage_info().chain.finalized_state.is_none() { + debug!(target: "babe", "No finalized state is available. Reading config from genesis"); + best_block_id = BlockId::Hash(client.usage_info().chain.genesis_hash); + } let runtime_api = client.runtime_api(); let version = runtime_api.api_version::>(&best_block_id)?; diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 19766d76048e9..d7550ff9aea17 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -477,7 +477,6 @@ impl BlockchainDb { let mut meta = self.meta.write(); if number.is_zero() { meta.genesis_hash = hash; - meta.finalized_hash = hash; } if is_best { @@ -1347,11 +1346,6 @@ impl Backend { } if number.is_zero() { - transaction.set_from_vec( - columns::META, - meta_keys::FINALIZED_BLOCK, - lookup_key.clone(), - ); transaction.set(columns::META, meta_keys::GENESIS_HASH, hash.as_ref()); if operation.commit_state { @@ -1447,14 +1441,15 @@ impl Backend { let finalized = number_u64 == 0 || pending_block.leaf_state.is_final(); finalized } else { - number.is_zero() || pending_block.leaf_state.is_final() + (number.is_zero() && last_finalized_num.is_zero()) || + pending_block.leaf_state.is_final() }; let header = &pending_block.header; let is_best = pending_block.leaf_state.is_best(); debug!(target: "db", - "DB Commit {:?} ({}), best={}, state={}, existing={}", - hash, number, is_best, operation.commit_state, existing_header, + "DB Commit {:?} ({}), best={}, state={}, existing={}, finalized={}", + hash, number, is_best, operation.commit_state, existing_header, finalized, ); self.state_usage.merge_sm(operation.old_state.usage_info()); @@ -2295,6 +2290,7 @@ pub(crate) mod tests { extrinsics_root: H256, ) -> H256 { insert_block(backend, number, parent_hash, changes, extrinsics_root, Vec::new(), None) + .unwrap() } pub fn insert_block( @@ -2305,7 +2301,7 @@ pub(crate) mod tests { extrinsics_root: H256, body: Vec>, transaction_index: Option>, - ) -> H256 { + ) -> Result { use sp_runtime::testing::Digest; let digest = Digest::default(); @@ -2329,9 +2325,9 @@ pub(crate) mod tests { if let Some(index) = transaction_index { op.update_transaction_index(index).unwrap(); } - backend.commit_operation(op).unwrap(); + backend.commit_operation(op)?; - header_hash + Ok(header_hash) } #[test] @@ -3019,7 +3015,6 @@ pub(crate) mod tests { { let header = backend.blockchain().header(BlockId::Hash(hash1)).unwrap().unwrap(); let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(hash0)).unwrap(); op.set_block_data(header, None, None, None, NewBlockState::Best).unwrap(); backend.commit_operation(op).unwrap(); } @@ -3063,7 +3058,8 @@ pub(crate) mod tests { Default::default(), vec![i.into()], None, - ); + ) + .unwrap(); blocks.push(hash); prev_hash = hash; } @@ -3100,7 +3096,8 @@ pub(crate) mod tests { Default::default(), vec![i.into()], None, - ); + ) + .unwrap(); blocks.push(hash); prev_hash = hash; } @@ -3114,7 +3111,8 @@ pub(crate) mod tests { sp_core::H256::random(), vec![2.into()], None, - ); + ) + .unwrap(); insert_block( &backend, 3, @@ -3123,7 +3121,8 @@ pub(crate) mod tests { H256::random(), vec![3.into(), 11.into()], None, - ); + ) + .unwrap(); let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); op.mark_head(BlockId::Hash(blocks[4])).unwrap(); @@ -3172,7 +3171,8 @@ pub(crate) mod tests { Default::default(), vec![i.into()], Some(index), - ); + ) + .unwrap(); blocks.push(hash); prev_hash = hash; } @@ -3206,7 +3206,8 @@ pub(crate) mod tests { Default::default(), vec![i.into()], None, - ); + ) + .unwrap(); blocks.push(hash); prev_hash = hash; } @@ -3220,7 +3221,8 @@ pub(crate) mod tests { sp_core::H256::random(), vec![42.into()], None, - ); + ) + .unwrap(); assert!(backend.remove_leaf_block(&best_hash).is_err()); assert!(backend.have_state_at(&prev_hash, 1)); backend.remove_leaf_block(&prev_hash).unwrap(); @@ -3290,4 +3292,21 @@ pub(crate) mod tests { assert_eq!(backend.blockchain().info().finalized_hash, block1); } + + #[test] + fn test_import_existing_state_fails() { + let backend: Backend = Backend::new_test(10, 10); + let genesis = + insert_block(&backend, 0, Default::default(), None, Default::default(), vec![], None) + .unwrap(); + + insert_block(&backend, 1, genesis, None, Default::default(), vec![], None).unwrap(); + let err = insert_block(&backend, 1, genesis, None, Default::default(), vec![], None) + .err() + .unwrap(); + match err { + sp_blockchain::Error::StateDatabase(m) if m == "Block already exists" => (), + e @ _ => panic!("Unexpected error {:?}", e), + } + } } diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index 69722dac22bcb..af65dec1c3fe9 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -1095,15 +1095,17 @@ impl ChainSync { } self.drain_blocks() }, - PeerSyncState::DownloadingGap(start_block) => { - let start_block = *start_block; + PeerSyncState::DownloadingGap(_) => { peer.state = PeerSyncState::Available; if let Some(gap_sync) = &mut self.gap_sync { gap_sync.blocks.clear_peer_download(who); - validate_blocks::(&blocks, who, Some(request))?; - gap_sync.blocks.insert(start_block, blocks, who.clone()); + if let Some(start_block) = + validate_blocks::(&blocks, who, Some(request))? + { + gap_sync.blocks.insert(start_block, blocks, who.clone()); + } gap = true; - gap_sync + let blocks: Vec<_> = gap_sync .blocks .drain(gap_sync.best_queued_number + One::one()) .into_iter() @@ -1126,7 +1128,9 @@ impl ChainSync { state: None, } }) - .collect() + .collect(); + debug!(target: "sync", "Drained {} gap blocks from {}", blocks.len(), gap_sync.best_queued_number); + blocks } else { debug!(target: "sync", "Unexpected gap block response from {}", who); return Err(BadPeer(who.clone(), rep::NO_BLOCK)) @@ -3169,4 +3173,44 @@ mod test { sync.peer_disconnected(&peer_id1); assert!(sync.fork_targets.len() == 0); } + + #[test] + fn can_import_response_with_missing_blocks() { + sp_tracing::try_init_simple(); + let mut client2 = Arc::new(TestClientBuilder::new().build()); + let blocks = (0..4).map(|_| build_block(&mut client2, None, false)).collect::>(); + + let empty_client = Arc::new(TestClientBuilder::new().build()); + + let mut sync = ChainSync::new( + SyncMode::Full, + empty_client.clone(), + Box::new(DefaultBlockAnnounceValidator), + 1, + None, + ) + .unwrap(); + + let peer_id1 = PeerId::random(); + let best_block = blocks[3].clone(); + sync.new_peer(peer_id1.clone(), best_block.hash(), *best_block.header().number()) + .unwrap(); + + sync.peers.get_mut(&peer_id1).unwrap().state = PeerSyncState::Available; + sync.peers.get_mut(&peer_id1).unwrap().common_number = 0; + + // Request all missing blocks and respond only with some. + let request = + get_block_request(&mut sync, FromBlock::Hash(best_block.hash()), 4, &peer_id1); + let response = + create_block_response(vec![blocks[3].clone(), blocks[2].clone(), blocks[1].clone()]); + sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); + assert_eq!(sync.best_queued_number, 0); + + // Request should only contain the missing block. + let request = get_block_request(&mut sync, FromBlock::Number(1), 1, &peer_id1); + let response = create_block_response(vec![blocks[0].clone()]); + sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + assert_eq!(sync.best_queued_number, 4); + } } diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 8769865978bf9..7673a7b4c5387 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1726,9 +1726,8 @@ where .block_status(&BlockId::Hash(hash)) .map_err(|e| ConsensusError::ClientImport(e.to_string()))? { - BlockStatus::InChainWithState | BlockStatus::Queued if !import_existing => + BlockStatus::InChainWithState | BlockStatus::Queued => return Ok(ImportResult::AlreadyInChain), - BlockStatus::InChainWithState | BlockStatus::Queued => {}, BlockStatus::InChainPruned if !import_existing => return Ok(ImportResult::AlreadyInChain), BlockStatus::InChainPruned => {}, diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index b7d58bb808a73..74f218e88f861 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -130,6 +130,8 @@ pub enum Error { InvalidPruningMode(String), /// Too many unfinalized sibling blocks inserted. TooManySiblingBlocks, + /// Trying to insert existing block. + BlockAlreadyExists, } /// Pinning error type. @@ -154,6 +156,7 @@ impl fmt::Debug for Error { Error::InvalidParent => write!(f, "Trying to insert block with unknown parent"), Error::InvalidPruningMode(e) => write!(f, "Expected pruning mode: {}", e), Error::TooManySiblingBlocks => write!(f, "Too many sibling blocks inserted"), + Error::BlockAlreadyExists => write!(f, "Block already exists"), } } } diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index d7c83492e563c..7d6fcbced7861 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -210,9 +210,10 @@ impl NonCanonicalOverlay { insert_values(&mut values, record.inserted); trace!( target: "state-db", - "Uncanonicalized journal entry {}.{} ({} inserted, {} deleted)", + "Uncanonicalized journal entry {}.{} ({:?}) ({} inserted, {} deleted)", block, index, + record.hash, overlay.inserted.len(), overlay.deleted.len() ); @@ -296,6 +297,9 @@ impl NonCanonicalOverlay { if level.blocks.len() >= MAX_BLOCKS_PER_LEVEL as usize { return Err(Error::TooManySiblingBlocks) } + if level.blocks.iter().any(|b| b.hash == *hash) { + return Err(Error::BlockAlreadyExists) + } let index = level.available_index(); let journal_key = to_journal_key(number, index); @@ -641,7 +645,7 @@ mod tests { use super::{to_journal_key, NonCanonicalOverlay}; use crate::{ test::{make_changeset, make_db}, - ChangeSet, CommitSet, MetaDb, + ChangeSet, CommitSet, Error, MetaDb, }; use sp_core::H256; use std::io; @@ -710,6 +714,20 @@ mod tests { .unwrap(); } + #[test] + fn insert_existing_fails() { + let db = make_db(&[]); + let h1 = H256::random(); + let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); + overlay + .insert::(&h1, 2, &H256::default(), ChangeSet::default()) + .unwrap(); + assert!(matches!( + overlay.insert::(&h1, 2, &H256::default(), ChangeSet::default()), + Err(Error::BlockAlreadyExists) + )); + } + #[test] #[should_panic] fn canonicalize_unknown_panics() { diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index 9f388dc58fbc4..6e8dc562473d8 100644 --- a/primitives/blockchain/src/header_metadata.rs +++ b/primitives/blockchain/src/header_metadata.rs @@ -20,7 +20,7 @@ use lru::LruCache; use parking_lot::RwLock; -use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; +use sp_runtime::traits::{Block as BlockT, Header, NumberFor, One}; /// Set to the expected max difference between `best` and `finalized` blocks at sync. const LRU_CACHE_SIZE: usize = 5_000; @@ -37,7 +37,14 @@ pub fn lowest_common_ancestor + ?Sized>( id_two: Block::Hash, ) -> Result, T::Error> { let mut header_one = backend.header_metadata(id_one)?; + if header_one.parent == id_two { + return Ok(HashAndNumber { hash: id_two, number: header_one.number - One::one() }) + } + let mut header_two = backend.header_metadata(id_two)?; + if header_two.parent == id_one { + return Ok(HashAndNumber { hash: id_one, number: header_one.number }) + } let mut orig_header_one = header_one.clone(); let mut orig_header_two = header_two.clone(); From 961666a2cb26c2aadf34f2b559967fac1392e4d8 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 13 Jan 2022 21:43:00 -0400 Subject: [PATCH 0424/1472] Use free balance rather than total balance for elections phragmen (#10646) * use free balance rather than total balance * Docs Co-authored-by: emostov <32168567+emostov@users.noreply.github.com> --- frame/elections-phragmen/src/lib.rs | 75 +++++++++++++++++------------ 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index b0e0a6fb984e8..1e8f61f6b268f 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -280,7 +280,7 @@ pub mod pallet { /// - be less than the number of possible candidates. Note that all current members and /// runners-up are also automatically candidates for the next round. /// - /// If `value` is more than `who`'s total balance, then the maximum of the two is used. + /// If `value` is more than `who`'s free balance, then the maximum of the two is used. /// /// The dispatch origin of this call must be signed. /// @@ -342,7 +342,7 @@ pub mod pallet { }; // Amount to be locked up. - let locked_stake = value.min(T::Currency::total_balance(&who)); + let locked_stake = value.min(T::Currency::free_balance(&who)); T::Currency::set_lock(T::PalletId::get(), &who, locked_stake, WithdrawReasons::all()); Voting::::insert(&who, Voter { votes, deposit: new_deposit, stake: locked_stake }); @@ -1667,11 +1667,13 @@ mod tests { System::set_block_number(5); Elections::on_initialize(System::block_number()); + assert_eq!(balances(&4), (34, 6)); + assert_eq!(balances(&5), (45, 5)); assert_eq!( Elections::members(), vec![ - SeatHolder { who: 4, stake: 40, deposit: 4 }, - SeatHolder { who: 5, stake: 50, deposit: 3 }, + SeatHolder { who: 4, stake: 34, deposit: 4 }, + SeatHolder { who: 5, stake: 45, deposit: 3 }, ] ); }) @@ -1762,7 +1764,7 @@ mod tests { assert_ok!(vote(Origin::signed(2), vec![5], 20)); assert_eq!(balances(&2), (18, 2)); - assert_eq!(has_lock(&2), 20); + assert_eq!(has_lock(&2), 18); }); } @@ -1789,9 +1791,10 @@ mod tests { assert_ok!(submit_candidacy(Origin::signed(4))); assert_ok!(vote(Origin::signed(2), vec![5], 20)); + // User only locks up to their free balance. assert_eq!(balances(&2), (18, 2)); - assert_eq!(has_lock(&2), 20); - assert_eq!(locked_stake_of(&2), 20); + assert_eq!(has_lock(&2), 18); + assert_eq!(locked_stake_of(&2), 18); // can update; different stake; different lock and reserve. assert_ok!(vote(Origin::signed(2), vec![5, 4], 15)); @@ -1856,8 +1859,8 @@ mod tests { // 2 + 2 assert_eq!(balances(&2), (16, 4)); assert_eq!(Elections::voting(&2).deposit, 4); - assert_eq!(has_lock(&2), 18); - assert_eq!(locked_stake_of(&2), 18); + assert_eq!(has_lock(&2), 16); + assert_eq!(locked_stake_of(&2), 16); // back to 1 vote. assert_ok!(vote(Origin::signed(2), vec![4], 12)); @@ -2031,15 +2034,18 @@ mod tests { } #[test] - fn can_vote_for_more_than_total_balance_but_moot() { + fn can_vote_for_more_than_free_balance_but_moot() { ExtBuilder::default().build_and_execute(|| { assert_ok!(submit_candidacy(Origin::signed(5))); assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(vote(Origin::signed(2), vec![4, 5], 30)); - // you can lie but won't get away with it. - assert_eq!(locked_stake_of(&2), 20); - assert_eq!(has_lock(&2), 20); + // User has 100 free and 50 reserved. + assert_ok!(Balances::set_balance(Origin::root(), 2, 100, 50)); + // User tries to vote with 150 tokens. + assert_ok!(vote(Origin::signed(2), vec![4, 5], 150)); + // We truncate to only their free balance, after reserving additional for voting. + assert_eq!(locked_stake_of(&2), 98); + assert_eq!(has_lock(&2), 98); }); } @@ -2052,8 +2058,10 @@ mod tests { assert_ok!(vote(Origin::signed(3), vec![5], 30)); assert_eq_uvec!(all_voters(), vec![2, 3]); - assert_eq!(locked_stake_of(&2), 20); - assert_eq!(locked_stake_of(&3), 30); + assert_eq!(balances(&2), (12, 8)); + assert_eq!(locked_stake_of(&2), 12); + assert_eq!(balances(&3), (22, 8)); + assert_eq!(locked_stake_of(&3), 22); assert_eq!(votes_of(&2), vec![5]); assert_eq!(votes_of(&3), vec![5]); @@ -2133,7 +2141,10 @@ mod tests { System::set_block_number(5); Elections::on_initialize(System::block_number()); - assert_eq!(members_and_stake(), vec![(3, 30), (5, 20)]); + assert_eq!(balances(&3), (25, 5)); + // votes for 5 + assert_eq!(balances(&2), (18, 2)); + assert_eq!(members_and_stake(), vec![(3, 25), (5, 18)]); assert!(Elections::runners_up().is_empty()); assert_eq_uvec!(all_voters(), vec![2, 3, 4]); @@ -2168,10 +2179,10 @@ mod tests { Elections::on_initialize(System::block_number()); System::assert_last_event(Event::Elections(super::Event::NewTerm { - new_members: vec![(4, 40), (5, 50)], + new_members: vec![(4, 35), (5, 45)], })); - assert_eq!(members_and_stake(), vec![(4, 40), (5, 50)]); + assert_eq!(members_and_stake(), vec![(4, 35), (5, 45)]); assert_eq!(runners_up_and_stake(), vec![]); assert_ok!(Elections::remove_voter(Origin::signed(5))); @@ -2202,7 +2213,7 @@ mod tests { System::set_block_number(5); Elections::on_initialize(System::block_number()); - assert_eq!(members_and_stake(), vec![(5, 50)]); + assert_eq!(members_and_stake(), vec![(5, 45)]); assert_eq!(Elections::election_rounds(), 1); // but now it has a valid target. @@ -2212,7 +2223,7 @@ mod tests { Elections::on_initialize(System::block_number()); // candidate 4 is affected by an old vote. - assert_eq!(members_and_stake(), vec![(4, 30), (5, 50)]); + assert_eq!(members_and_stake(), vec![(4, 28), (5, 45)]); assert_eq!(Elections::election_rounds(), 2); assert_eq_uvec!(all_voters(), vec![3, 5]); }); @@ -2300,16 +2311,16 @@ mod tests { System::set_block_number(5); Elections::on_initialize(System::block_number()); - assert_eq!(members_and_stake(), vec![(4, 40), (5, 50)]); - assert_eq!(runners_up_and_stake(), vec![(2, 20), (3, 30)]); + assert_eq!(members_and_stake(), vec![(4, 35), (5, 45)]); + assert_eq!(runners_up_and_stake(), vec![(2, 15), (3, 25)]); - assert_ok!(vote(Origin::signed(5), vec![5], 15)); + assert_ok!(vote(Origin::signed(5), vec![5], 10)); System::set_block_number(10); Elections::on_initialize(System::block_number()); - assert_eq!(members_and_stake(), vec![(3, 30), (4, 40)]); - assert_eq!(runners_up_and_stake(), vec![(5, 15), (2, 20)]); + assert_eq!(members_and_stake(), vec![(3, 25), (4, 35)]); + assert_eq!(runners_up_and_stake(), vec![(5, 10), (2, 15)]); }); } @@ -2443,8 +2454,8 @@ mod tests { System::set_block_number(b.into()); Elections::on_initialize(System::block_number()); // we keep re-electing the same folks. - assert_eq!(members_and_stake(), vec![(4, 40), (5, 50)]); - assert_eq!(runners_up_and_stake(), vec![(2, 20), (3, 30)]); + assert_eq!(members_and_stake(), vec![(4, 35), (5, 45)]); + assert_eq!(runners_up_and_stake(), vec![(2, 15), (3, 25)]); // no new candidates but old members and runners-up are always added. assert!(candidate_ids().is_empty()); assert_eq!(Elections::election_rounds(), b / 5); @@ -2596,7 +2607,7 @@ mod tests { Elections::on_initialize(System::block_number()); // 3, 4 are new members, must still be bonded, nothing slashed. - assert_eq!(members_and_stake(), vec![(3, 30), (4, 48)]); + assert_eq!(members_and_stake(), vec![(3, 25), (4, 43)]); assert_eq!(balances(&3), (25, 5)); assert_eq!(balances(&4), (35, 5)); @@ -2607,7 +2618,7 @@ mod tests { assert_eq!(balances(&5), (45, 2)); System::assert_has_event(Event::Elections(super::Event::NewTerm { - new_members: vec![(4, 40), (5, 50)], + new_members: vec![(4, 35), (5, 45)], })); }) } @@ -2646,9 +2657,9 @@ mod tests { System::set_block_number(5); Elections::on_initialize(System::block_number()); // id: low -> high. - assert_eq!(members_and_stake(), vec![(4, 50), (5, 40)]); + assert_eq!(members_and_stake(), vec![(4, 45), (5, 35)]); // merit: low -> high. - assert_eq!(runners_up_and_stake(), vec![(3, 20), (2, 30)]); + assert_eq!(runners_up_and_stake(), vec![(3, 15), (2, 25)]); }); } From 9eddaec3b8f15eec0c458e7bb3a1c16db91d8199 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 14 Jan 2022 12:02:53 +0100 Subject: [PATCH 0425/1472] Increase default rocksdb cache (#10659) --- client/cli/src/config.rs | 2 +- utils/frame/benchmarking-cli/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index cc3b0590566a8..b5470db91db3a 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -485,7 +485,7 @@ pub trait CliConfiguration: Sized { let config_dir = base_path.config_dir(chain_spec.id()); let net_config_dir = config_dir.join(DEFAULT_NETWORK_CONFIG_PATH); let client_id = C::client_id(); - let database_cache_size = self.database_cache_size()?.unwrap_or(128); + let database_cache_size = self.database_cache_size()?.unwrap_or(1024); let database = self.database()?.unwrap_or(Database::RocksDb); let node_key = self.node_key(&net_config_dir)?; let role = self.role(is_dev)?; diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index c331dea34c47b..664e526ae0d7b 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -133,7 +133,7 @@ pub struct BenchmarkCmd { pub wasm_method: WasmExecutionMethod, /// Limit the memory the database cache can use. - #[structopt(long = "db-cache", value_name = "MiB", default_value = "128")] + #[structopt(long = "db-cache", value_name = "MiB", default_value = "1024")] pub database_cache_size: u32, /// List the benchmarks that match your query rather than running them. From 3168e10f6576a28930554bbf903ff9900b833a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 15 Jan 2022 11:46:20 +0100 Subject: [PATCH 0426/1472] runtime-interface: Implement `register_only` functions (#10640) * runtime-interface: Implement `register_only` functions The runtime interface supports versioning of functions. Currently, if you add a new function it will be used by the runtime automatically. This results in requiring all nodes of a network to upgrade before the runtime is upgraded, otherwise they will fail to instantiate the new runtime because of missing host functions. This pr introduces `register_only` functions. This can be used when a new runtime interface function should be introduced, but the actual usage can be deferred. This means that nodes will have the host function for this, but the runtime will still use the old version of the function when being compiled for wasm. However, when a runtime is enacted that uses the new host function, the "old nodes" will already have the host function and will continue to work. * Update primitives/runtime-interface/src/lib.rs Co-authored-by: cheme * Update primitives/runtime-interface/proc-macro/src/utils.rs Co-authored-by: cheme * FMT Co-authored-by: cheme --- .../bare_function_interface.rs | 2 +- .../host_function_interface.rs | 17 +- .../runtime-interface/proc-macro/src/utils.rs | 157 +++++++++++------- primitives/runtime-interface/src/lib.rs | 26 ++- .../runtime-interface/test-wasm/src/lib.rs | 16 ++ primitives/runtime-interface/test/src/lib.rs | 5 + 6 files changed, 155 insertions(+), 68 deletions(-) diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs index cbb749a111a15..a06a1f9bda73e 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs @@ -52,7 +52,7 @@ pub fn generate(trait_def: &ItemTrait, is_wasm_only: bool, tracing: bool) -> Res let runtime_interface = get_runtime_interface(trait_def)?; // latest version dispatch - let token_stream: Result = runtime_interface.latest_versions().try_fold( + let token_stream: Result = runtime_interface.latest_versions_to_call().try_fold( TokenStream::new(), |mut t, (latest_version, method)| { t.extend(function_for_method(method, latest_version, is_wasm_only)?); diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs index 2416e6951fe25..626e309cc0e1c 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs @@ -45,19 +45,18 @@ use std::iter::Iterator; /// implementations for the host functions on the host. pub fn generate(trait_def: &ItemTrait, is_wasm_only: bool) -> Result { let trait_name = &trait_def.ident; - let extern_host_function_impls = get_runtime_interface(trait_def)?.latest_versions().try_fold( - TokenStream::new(), - |mut t, (version, method)| { + let extern_host_function_impls = get_runtime_interface(trait_def)? + .latest_versions_to_call() + .try_fold(TokenStream::new(), |mut t, (version, method)| { t.extend(generate_extern_host_function(method, version, trait_name)?); Ok::<_, Error>(t) - }, - )?; + })?; let exchangeable_host_functions = get_runtime_interface(trait_def)? - .latest_versions() + .latest_versions_to_call() .try_fold(TokenStream::new(), |mut t, (_, m)| { - t.extend(generate_exchangeable_host_function(m)?); - Ok::<_, Error>(t) - })?; + t.extend(generate_exchangeable_host_function(m)?); + Ok::<_, Error>(t) + })?; let host_functions_struct = generate_host_functions_struct(trait_def, is_wasm_only)?; Ok(quote! { diff --git a/primitives/runtime-interface/proc-macro/src/utils.rs b/primitives/runtime-interface/proc-macro/src/utils.rs index 593f8ecafa7aa..bc690eb21a9bd 100644 --- a/primitives/runtime-interface/proc-macro/src/utils.rs +++ b/primitives/runtime-interface/proc-macro/src/utils.rs @@ -20,8 +20,8 @@ use proc_macro2::{Span, TokenStream}; use syn::{ - parse_quote, spanned::Spanned, token, Attribute, Error, FnArg, Ident, ItemTrait, Lit, Meta, - NestedMeta, Pat, PatType, Result, Signature, TraitItem, TraitItemMethod, Type, + parse::Parse, parse_quote, spanned::Spanned, token, Error, FnArg, Ident, ItemTrait, LitInt, + Pat, PatType, Result, Signature, TraitItem, TraitItemMethod, Type, }; use proc_macro_crate::{crate_name, FoundCrate}; @@ -35,31 +35,65 @@ use quote::quote; use inflector::Inflector; +mod attributes { + syn::custom_keyword!(register_only); +} + /// Runtime interface function with all associated versions of this function. pub struct RuntimeInterfaceFunction<'a> { - latest_version: u32, + latest_version_to_call: Option, versions: BTreeMap, } impl<'a> RuntimeInterfaceFunction<'a> { - fn new(version: u32, trait_item: &'a TraitItemMethod) -> Self { + fn new(version: VersionAttribute, trait_item: &'a TraitItemMethod) -> Self { Self { - latest_version: version, - versions: { - let mut res = BTreeMap::new(); - res.insert(version, trait_item); - res - }, + latest_version_to_call: version.is_callable().then(|| version.version), + versions: BTreeMap::from([(version.version, trait_item)]), } } - pub fn latest_version(&self) -> (u32, &TraitItemMethod) { - ( - self.latest_version, - self.versions.get(&self.latest_version).expect( - "If latest_version has a value, the key with this value is in the versions; qed", + /// Returns the latest version of this runtime interface function plus the actual function + /// implementation. + /// + /// This isn't required to be the latest version, because a runtime interface function can be + /// annotated with `register_only` to ensure that the host exposes the host function but it + /// isn't used when compiling the runtime. + pub fn latest_version_to_call(&self) -> Option<(u32, &TraitItemMethod)> { + self.latest_version_to_call.map(|v| { + ( + v, + *self.versions.get(&v).expect( + "If latest_version_to_call has a value, the key with this value is in the versions; qed", ), ) + }) + } + + /// Add a different version of the function. + fn add_version( + &mut self, + version: VersionAttribute, + trait_item: &'a TraitItemMethod, + ) -> Result<()> { + if let Some(existing_item) = self.versions.get(&version.version) { + let mut err = Error::new(trait_item.span(), "Duplicated version attribute"); + err.combine(Error::new( + existing_item.span(), + "Previous version with the same number defined here", + )); + + return Err(err) + } + + self.versions.insert(version.version, trait_item); + if self.latest_version_to_call.map_or(true, |v| v < version.version) && + version.is_callable() + { + self.latest_version_to_call = Some(version.version); + } + + Ok(()) } } @@ -69,8 +103,10 @@ pub struct RuntimeInterface<'a> { } impl<'a> RuntimeInterface<'a> { - pub fn latest_versions(&self) -> impl Iterator { - self.items.iter().map(|(_, item)| item.latest_version()) + /// Returns an iterator over all runtime interface function + /// [`latest_version_to_call`](RuntimeInterfaceFunction::latest_version). + pub fn latest_versions_to_call(&self) -> impl Iterator { + self.items.iter().filter_map(|(_, item)| item.latest_version_to_call()) } pub fn all_versions(&self) -> impl Iterator { @@ -199,36 +235,55 @@ fn get_trait_methods<'a>(trait_def: &'a ItemTrait) -> impl Iterator Result { - let meta = version.parse_meta()?; - - let err = Err(Error::new( - meta.span(), - "Unexpected `version` attribute. The supported format is `#[version(1)]`", - )); - - match meta { - Meta::List(list) => - if list.nested.len() != 1 { - err - } else if let Some(NestedMeta::Lit(Lit::Int(i))) = list.nested.first() { - i.base10_parse() - } else { - err - }, - _ => err, +/// Supports the following formats: +/// - `#[version(1)]` +/// - `#[version(1, register_only)]` +/// +/// While this struct is only for parsing the inner parts inside the `()`. +struct VersionAttribute { + version: u32, + register_only: Option, +} + +impl VersionAttribute { + /// Is this function version callable? + fn is_callable(&self) -> bool { + self.register_only.is_none() + } +} + +impl Default for VersionAttribute { + fn default() -> Self { + Self { version: 1, register_only: None } + } +} + +impl Parse for VersionAttribute { + fn parse(input: syn::parse::ParseStream) -> Result { + let version: LitInt = input.parse()?; + let register_only = if input.peek(token::Comma) { + let _ = input.parse::(); + Some(input.parse()?) + } else { + if !input.is_empty() { + return Err(Error::new(input.span(), "Unexpected token, expected `,`.")) + } + + None + }; + + Ok(Self { version: version.base10_parse()?, register_only }) } } -/// Return item version (`#[version(X)]`) attribute, if present. -fn get_item_version(item: &TraitItemMethod) -> Result> { +/// Return [`VersionAttribute`], if present. +fn get_item_version(item: &TraitItemMethod) -> Result> { item.attrs .iter() .find(|attr| attr.path.is_ident("version")) - .map(|attr| parse_version_attribute(attr)) + .map(|attr| attr.parse_args()) .transpose() } @@ -238,28 +293,18 @@ pub fn get_runtime_interface<'a>(trait_def: &'a ItemTrait) -> Result { entry.insert(RuntimeInterfaceFunction::new(version, item)); }, Entry::Occupied(mut entry) => { - if let Some(existing_item) = entry.get().versions.get(&version) { - let mut err = Error::new(item.span(), "Duplicated version attribute"); - err.combine(Error::new( - existing_item.span(), - "Previous version with the same number defined here", - )); - - return Err(err) - } - - let interface_item = entry.get_mut(); - if interface_item.latest_version < version { - interface_item.latest_version = version; - } - interface_item.versions.insert(version, item); + entry.get_mut().add_version(version, item)?; }, } } diff --git a/primitives/runtime-interface/src/lib.rs b/primitives/runtime-interface/src/lib.rs index d87b0d57a772a..f9bf8825f9486 100644 --- a/primitives/runtime-interface/src/lib.rs +++ b/primitives/runtime-interface/src/lib.rs @@ -153,6 +153,22 @@ pub use sp_std; /// [17].to_vec() /// } /// +/// /// Call function, different version and only being registered. +/// /// +/// /// This `register_only` version is only being registered, aka exposed to the runtime, +/// /// but the runtime will still use the version 2 of this function. This is useful for when +/// /// new host functions should be introduced. Adding new host functions requires that all +/// /// nodes have the host functions available, because otherwise they fail at instantiation +/// /// of the runtime. With `register_only` the function will not be used when compiling the +/// /// runtime, but it will already be there for a future version of the runtime that will +/// /// switch to using these host function. +/// #[version(3, register_only)] +/// fn call(data: &[u8]) -> Vec { +/// // Here you could call some rather complex code that only compiles on native or +/// // is way faster in native than executing it in wasm. +/// [18].to_vec() +/// } +/// /// /// A function can take a `&self` or `&mut self` argument to get access to the /// /// `Externalities`. (The generated method does not require /// /// this argument, so the function can be called just with the `optional` argument) @@ -177,12 +193,14 @@ pub use sp_std; /// trait Interface { /// fn call_version_1(data: &[u8]) -> Vec; /// fn call_version_2(data: &[u8]) -> Vec; +/// fn call_version_3(data: &[u8]) -> Vec; /// fn set_or_clear_version_1(&mut self, optional: Option>); /// } /// /// impl Interface for &mut dyn sp_externalities::Externalities { /// fn call_version_1(data: &[u8]) -> Vec { Vec::new() } /// fn call_version_2(data: &[u8]) -> Vec { [17].to_vec() } +/// fn call_version_3(data: &[u8]) -> Vec { [18].to_vec() } /// fn set_or_clear_version_1(&mut self, optional: Option>) { /// match optional { /// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value), @@ -204,6 +222,10 @@ pub use sp_std; /// <&mut dyn sp_externalities::Externalities as Interface>::call_version_2(data) /// } /// +/// fn call_version_3(data: &[u8]) -> Vec { +/// <&mut dyn sp_externalities::Externalities as Interface>::call_version_3(data) +/// } +/// /// pub fn set_or_clear(optional: Option>) { /// set_or_clear_version_1(optional) /// } @@ -285,8 +307,8 @@ pub use sp_std; /// This instructs the macro to make two significant changes to the generated code: /// /// 1. The generated functions are not callable from the native side. -/// 2. The trait as shown above is not implemented for `Externalities` and is instead -/// implemented for `FunctionExecutor` (from `sp-wasm-interface`). +/// 2. The trait as shown above is not implemented for [`Externalities`] and is instead +/// implemented for `FunctionExecutor` (from `sp-wasm-interface`). /// /// # Disable tracing /// By addding `no_tracing` to the list of options you can prevent the wasm-side interface from diff --git a/primitives/runtime-interface/test-wasm/src/lib.rs b/primitives/runtime-interface/test-wasm/src/lib.rs index 982febb7b4fb8..0c8a9c04ab1e9 100644 --- a/primitives/runtime-interface/test-wasm/src/lib.rs +++ b/primitives/runtime-interface/test-wasm/src/lib.rs @@ -123,6 +123,15 @@ pub trait TestApi { data == 42 } + fn test_versionning_register_only(&self, data: u32) -> bool { + data == 80 + } + + #[version(2, register_only)] + fn test_versionning_register_only(&self, data: u32) -> bool { + data == 42 + } + /// Returns the input values as tuple. fn return_input_as_tuple( a: Vec, @@ -271,6 +280,13 @@ wasm_export_functions! { assert!(!test_api::test_versionning(102)); } + fn test_versionning_register_only_works() { + // Ensure that we will import the version of the runtime interface function that + // isn't tagged with `register_only`. + assert!(!test_api::test_versionning_register_only(42)); + assert!(test_api::test_versionning_register_only(80)); + } + fn test_return_input_as_tuple() { let a = vec![1, 3, 4, 5]; let b = 10000; diff --git a/primitives/runtime-interface/test/src/lib.rs b/primitives/runtime-interface/test/src/lib.rs index e76f54f69a808..1ab8dbfbbff22 100644 --- a/primitives/runtime-interface/test/src/lib.rs +++ b/primitives/runtime-interface/test/src/lib.rs @@ -169,6 +169,11 @@ fn test_versionining_with_new_host_works() { call_wasm_method::(wasm_binary_deprecated_unwrap(), "test_versionning_works"); } +#[test] +fn test_versionining_register_only() { + call_wasm_method::(wasm_binary_unwrap(), "test_versionning_register_only_works"); +} + #[test] fn test_tracing() { use std::fmt; From 04c7c6abef1e0c6b4126427159090a44f3221333 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sat, 15 Jan 2022 22:00:12 +0200 Subject: [PATCH 0427/1472] Minor tweaks suggested by clippy (#10673) * Minor tweaks suggested by clippy * Fix typo caused by last commit * Apply review suggestions --- .../api/proc-macro/src/decl_runtime_apis.rs | 1 + primitives/api/test/tests/runtime_calls.rs | 2 +- test-utils/runtime/src/lib.rs | 31 ++++++++----------- test-utils/runtime/src/system.rs | 10 +++--- .../runtime/transaction-pool/src/lib.rs | 18 +++++------ 5 files changed, 27 insertions(+), 35 deletions(-) diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index 8d90b09d0e8c0..85b66eca7061e 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -378,6 +378,7 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result { // Generate the generator function result.push(quote!( #[cfg(any(feature = "std", test))] + #[allow(clippy::too_many_arguments)] pub fn #fn_name< R: #crate_::Encode + #crate_::Decode + PartialEq, NC: FnOnce() -> std::result::Result + std::panic::UnwindSafe, diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index e085b023b1227..ba42b342377c7 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -59,7 +59,7 @@ fn calling_native_runtime_function_with_non_decodable_parameter() { .build(); let runtime_api = client.runtime_api(); let block_id = BlockId::Number(client.chain_info().best_number); - runtime_api.fail_convert_parameter(&block_id, DecodeFails::new()).unwrap(); + runtime_api.fail_convert_parameter(&block_id, DecodeFails::default()).unwrap(); } #[test] diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index b03998621b31f..5c9dfeca0a334 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -132,8 +132,7 @@ impl Transfer { pub fn into_signed_tx(self) -> Extrinsic { let signature = sp_keyring::AccountKeyring::from_public(&self.from) .expect("Creates keyring from public key.") - .sign(&self.encode()) - .into(); + .sign(&self.encode()); Extrinsic::Transfer { transfer: self, signature, exhaust_resources_when_not_first: false } } @@ -144,8 +143,7 @@ impl Transfer { pub fn into_resources_exhausting_tx(self) -> Extrinsic { let signature = sp_keyring::AccountKeyring::from_public(&self.from) .expect("Creates keyring from public key.") - .sign(&self.encode()) - .into(); + .sign(&self.encode()); Extrinsic::Transfer { transfer: self, signature, exhaust_resources_when_not_first: true } } } @@ -277,9 +275,9 @@ pub fn run_tests(mut input: &[u8]) -> Vec { print("run_tests..."); let block = Block::decode(&mut input).unwrap(); print("deserialized block."); - let stxs = block.extrinsics.iter().map(Encode::encode).collect::>(); + let stxs = block.extrinsics.iter().map(Encode::encode); print("reserialized transactions."); - [stxs.len() as u8].encode() + [stxs.count() as u8].encode() } /// A type that can not be decoded. @@ -296,9 +294,9 @@ impl Encode for DecodeFails { impl codec::EncodeLike for DecodeFails {} -impl DecodeFails { - /// Create a new instance. - pub fn new() -> DecodeFails { +impl Default for DecodeFails { + /// Create a default instance. + fn default() -> DecodeFails { DecodeFails { _phantom: Default::default() } } } @@ -436,8 +434,8 @@ impl From> for Origin { unimplemented!("Not required in tests!") } } -impl Into, Origin>> for Origin { - fn into(self) -> Result, Origin> { +impl From for Result, Origin> { + fn from(_origin: Origin) -> Result, Origin> { unimplemented!("Not required in tests!") } } @@ -651,12 +649,9 @@ fn code_using_trie() -> u64 { let mut mdb = PrefixedMemoryDB::default(); let mut root = sp_std::default::Default::default(); let _ = { - let v = &pairs; let mut t = TrieDBMut::::new(&mut mdb, &mut root); - for i in 0..v.len() { - let key: &[u8] = &v[i].0; - let val: &[u8] = &v[i].1; - if !t.insert(key, val).is_ok() { + for (key, value) in &pairs { + if t.insert(key, value).is_err() { return 101 } } @@ -761,7 +756,7 @@ cfg_if! { fn fail_convert_parameter(_: DecodeFails) {} fn fail_convert_return_value() -> DecodeFails { - DecodeFails::new() + DecodeFails::default() } fn function_signature_changed() -> u64 { @@ -1015,7 +1010,7 @@ cfg_if! { fn fail_convert_parameter(_: DecodeFails) {} fn fail_convert_return_value() -> DecodeFails { - DecodeFails::new() + DecodeFails::default() } fn function_signature_changed() -> Vec { diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 9f8612b69f338..6df35421d3614 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -197,7 +197,7 @@ pub fn finalize_block() -> Header { use sp_core::storage::StateVersion; let extrinsic_index: u32 = storage::unhashed::take(well_known_keys::EXTRINSIC_INDEX).unwrap(); let txs: Vec<_> = (0..extrinsic_index).map(ExtrinsicData::take).collect(); - let extrinsics_root = trie::blake2_256_ordered_root(txs, StateVersion::V0).into(); + let extrinsics_root = trie::blake2_256_ordered_root(txs, StateVersion::V0); let number = ::take().expect("Number is set by `initialize_block`"); let parent_hash = ::take(); let mut digest = ::take().expect("StorageDigest is set by `initialize_block`"); @@ -235,11 +235,11 @@ fn execute_transaction_backend(utx: &Extrinsic, extrinsic_index: u32) -> ApplyEx Extrinsic::StorageChange(key, value) => execute_storage_change(key, value.as_ref().map(|v| &**v)), Extrinsic::OffchainIndexSet(key, value) => { - sp_io::offchain_index::set(&key, &value); + sp_io::offchain_index::set(key, value); Ok(Ok(())) }, Extrinsic::OffchainIndexClear(key) => { - sp_io::offchain_index::clear(&key); + sp_io::offchain_index::clear(key); Ok(Ok(())) }, Extrinsic::Store(data) => execute_store(data.clone()), @@ -250,7 +250,7 @@ fn execute_transfer_backend(tx: &Transfer) -> ApplyExtrinsicResult { // check nonce let nonce_key = tx.from.to_keyed_vec(NONCE_OF); let expected_nonce: u64 = storage::hashed::get_or(&blake2_256, &nonce_key, 0); - if !(tx.nonce == expected_nonce) { + if tx.nonce != expected_nonce { return Err(InvalidTransaction::Stale.into()) } @@ -262,7 +262,7 @@ fn execute_transfer_backend(tx: &Transfer) -> ApplyExtrinsicResult { let from_balance: u64 = storage::hashed::get_or(&blake2_256, &from_balance_key, 0); // enact transfer - if !(tx.amount <= from_balance) { + if tx.amount > from_balance { return Err(InvalidTransaction::Payment.into()) } let to_balance_key = tx.to.to_keyed_vec(BALANCE_OF); diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index a339ce8c7f65f..ba317f57f531a 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -179,13 +179,13 @@ impl TestApi { /// Add a block to the internal state. pub fn add_block(&self, block: Block, is_best_block: bool) { let hash = block.header.hash(); - let block_number = block.header.number().clone(); + let block_number = block.header.number(); let mut chain = self.chain.write(); chain.block_by_hash.insert(hash, block.clone()); chain .block_by_number - .entry(block_number) + .entry(*block_number) .or_default() .push((block, is_best_block.into())); } @@ -259,15 +259,13 @@ impl sc_transaction_pool::ChainApi for TestApi { if !found_best { return ready(Ok(Err(TransactionValidityError::Invalid( InvalidTransaction::Custom(1), - ) - .into()))) + )))) } }, Ok(None) => return ready(Ok(Err(TransactionValidityError::Invalid( InvalidTransaction::Custom(2), - ) - .into()))), + )))), Err(e) => return ready(Err(e)), } @@ -283,9 +281,7 @@ impl sc_transaction_pool::ChainApi for TestApi { }; if self.chain.read().invalid_hashes.contains(&self.hash_and_length(&uxt).0) { - return ready(Ok(Err( - TransactionValidityError::Invalid(InvalidTransaction::Custom(0)).into() - ))) + return ready(Ok(Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0))))) } let mut validity = @@ -312,7 +308,7 @@ impl sc_transaction_pool::ChainApi for TestApi { at: &BlockId, ) -> Result::Hash>, Error> { Ok(match at { - generic::BlockId::Hash(x) => Some(x.clone()), + generic::BlockId::Hash(x) => Some(*x), generic::BlockId::Number(num) => self.chain.read().block_by_number.get(num).and_then(|blocks| { blocks.iter().find(|b| b.1.is_best()).map(|b| b.0.header().hash()) @@ -371,6 +367,6 @@ impl sp_blockchain::HeaderMetadata for TestApi { pub fn uxt(who: AccountKeyring, nonce: Index) -> Extrinsic { let dummy = codec::Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap(); let transfer = Transfer { from: who.into(), to: dummy, nonce, amount: 1 }; - let signature = transfer.using_encoded(|e| who.sign(e)).into(); + let signature = transfer.using_encoded(|e| who.sign(e)); Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: false } } From 537bed312037f12e00b52be8d77a7c62731f7fc5 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Sun, 16 Jan 2022 18:15:18 -0800 Subject: [PATCH 0428/1472] Move `EraIndex` to sp-staking (#10671) * Move `EraIndex` to sp-staking * Fix imports in mocks * Run cargo +nightly-2021-10-29 fmt --- bin/node/runtime/src/lib.rs | 4 ++-- frame/babe/src/mock.rs | 3 +-- frame/grandpa/src/mock.rs | 3 +-- frame/staking/src/lib.rs | 5 +---- frame/staking/src/pallet/impls.rs | 6 +++--- frame/staking/src/pallet/mod.rs | 4 ++-- frame/staking/src/slashing.rs | 6 +++--- primitives/staking/src/lib.rs | 3 +++ 8 files changed, 16 insertions(+), 18 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index aab813f29e0aa..b2c98e6be139d 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -520,8 +520,8 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const SessionsPerEra: sp_staking::SessionIndex = 6; - pub const BondingDuration: pallet_staking::EraIndex = 24 * 28; - pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. + pub const BondingDuration: sp_staking::EraIndex = 24 * 28; + pub const SlashDeferDuration: sp_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominatorRewardedPerValidator: u32 = 256; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 22d7befab6686..fa7a7b185b342 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -25,7 +25,6 @@ use frame_support::{ traits::{ConstU128, ConstU32, ConstU64, GenesisBuild, KeyOwnerProofSystem, OnInitialize}, }; use pallet_session::historical as pallet_session_historical; -use pallet_staking::EraIndex; use sp_consensus_babe::{AuthorityId, AuthorityPair, Slot}; use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; use sp_core::{ @@ -40,7 +39,7 @@ use sp_runtime::{ traits::{Header as _, IdentityLookup, OpaqueKeys}, Perbill, }; -use sp_staking::SessionIndex; +use sp_staking::{EraIndex, SessionIndex}; type DummyValidatorId = u64; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 91006d66b7deb..34787c93bb9ce 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -30,7 +30,6 @@ use frame_support::{ }, }; use pallet_session::historical as pallet_session_historical; -use pallet_staking::EraIndex; use sp_core::{crypto::KeyTypeId, H256}; use sp_finality_grandpa::{RoundNumber, SetId, GRANDPA_ENGINE_ID}; use sp_keyring::Ed25519Keyring; @@ -41,7 +40,7 @@ use sp_runtime::{ traits::{IdentityLookup, OpaqueKeys}, DigestItem, Perbill, }; -use sp_staking::SessionIndex; +use sp_staking::{EraIndex, SessionIndex}; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 268618fb5f44f..efe67c8b00c85 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -312,7 +312,7 @@ use sp_runtime::{ }; use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, - SessionIndex, + EraIndex, SessionIndex, }; use sp_std::{collections::btree_map::BTreeMap, convert::From, prelude::*}; pub use weights::WeightInfo; @@ -332,9 +332,6 @@ macro_rules! log { }; } -/// Counter for the number of eras that have passed. -pub type EraIndex = u32; - /// Counter for the number of "reward" points earned by a given validator. pub type RewardPoint = u32; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index c97541de81961..68b5c19027a9b 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -37,13 +37,13 @@ use sp_runtime::{ }; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - SessionIndex, + EraIndex, SessionIndex, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use crate::{ - log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraIndex, EraPayout, Exposure, - ExposureOf, Forcing, IndividualExposure, Nominations, PositiveImbalanceOf, RewardDestination, + log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf, + Forcing, IndividualExposure, Nominations, PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, }; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index e45a21ab25036..fc70d523ac9cd 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -31,7 +31,7 @@ use sp_runtime::{ traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero}, DispatchError, Perbill, Percent, }; -use sp_staking::SessionIndex; +use sp_staking::{EraIndex, SessionIndex}; use sp_std::{convert::From, prelude::*, result}; mod impls; @@ -39,7 +39,7 @@ mod impls; pub use impls::*; use crate::{ - log, migrations, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraIndex, EraPayout, + log, migrations, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 4fa7d347da70d..2f381ad631fe5 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -50,8 +50,8 @@ //! Based on research at use crate::{ - BalanceOf, Config, EraIndex, Error, Exposure, NegativeImbalanceOf, Pallet, Perbill, - SessionInterface, Store, UnappliedSlash, + BalanceOf, Config, Error, Exposure, NegativeImbalanceOf, Pallet, Perbill, SessionInterface, + Store, UnappliedSlash, }; use codec::{Decode, Encode}; use frame_support::{ @@ -63,7 +63,7 @@ use sp_runtime::{ traits::{Saturating, Zero}, DispatchResult, RuntimeDebug, }; -use sp_staking::offence::DisableStrategy; +use sp_staking::{offence::DisableStrategy, EraIndex}; use sp_std::vec::Vec; /// The proportion of the slashing reward to be paid out on the first slashing detection. diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index e7db609e230aa..15208df62cc66 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -24,3 +24,6 @@ pub mod offence; /// Simple index type with which we can count sessions. pub type SessionIndex = u32; + +/// Counter for the number of eras that have passed. +pub type EraIndex = u32; From fe3f379a105d4be72963a0f2fbe654b86e92a5ec Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Mon, 17 Jan 2022 05:28:11 -0400 Subject: [PATCH 0429/1472] Improve BoundedVec API (extracted from #10195) (#10656) * Gav wrote this code in pull #10195. Extracting to simplify that PR. * fix potential panics * prevent panics in slide * update doc * fmt * Update frame/support/src/storage/bounded_vec.rs Co-authored-by: Keith Yeung Co-authored-by: Gav Wood Co-authored-by: Keith Yeung --- frame/support/src/storage/bounded_vec.rs | 218 ++++++++++++++++++++++- 1 file changed, 216 insertions(+), 2 deletions(-) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 9f43d37a2d7f1..6d7206df6db10 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -149,6 +149,16 @@ impl BoundedVec { ) -> Option<&mut >::Output> { self.0.get_mut(index) } + + /// Exactly the same semantics as [`Vec::truncate`]. + pub fn truncate(&mut self, s: usize) { + self.0.truncate(s); + } + + /// Exactly the same semantics as [`Vec::pop`]. + pub fn pop(&mut self) -> Option { + self.0.pop() + } } impl> From> for Vec { @@ -176,6 +186,115 @@ impl> BoundedVec { S::get() as usize } + /// Forces the insertion of `s` into `self` retaining all items with index at least `index`. + /// + /// If `index == 0` and `self.len() == Self::bound()`, then this is a no-op. + /// + /// If `Self::bound() < index` or `self.len() < index`, then this is also a no-op. + /// + /// Returns `true` if the item was inserted. + pub fn force_insert_keep_right(&mut self, index: usize, element: T) -> bool { + // Check against panics. + if Self::bound() < index || self.len() < index { + return false + } + if self.len() < Self::bound() { + // Cannot panic since self.len() >= index; + self.0.insert(index, element); + } else { + if index == 0 { + return false + } + self[0] = element; + // `[0..index] cannot panic since self.len() >= index. + // `rotate_left(1)` cannot panic because there is at least 1 element. + self[0..index].rotate_left(1); + } + true + } + + /// Forces the insertion of `s` into `self` retaining all items with index at most `index`. + /// + /// If `index == Self::bound()` and `self.len() == Self::bound()`, then this is a no-op. + /// + /// If `Self::bound() < index` or `self.len() < index`, then this is also a no-op. + /// + /// Returns `true` if the item was inserted. + pub fn force_insert_keep_left(&mut self, index: usize, element: T) -> bool { + // Check against panics. + if Self::bound() < index || self.len() < index { + return false + } + // Noop condition. + if Self::bound() == index && self.len() <= Self::bound() { + return false + } + // Cannot panic since self.len() >= index; + self.0.insert(index, element); + self.0.truncate(Self::bound()); + true + } + + /// Move the position of an item from one location to another in the slice. + /// + /// Except for the item being moved, the order of the slice remains the same. + /// + /// - `index` is the location of the item to be moved. + /// - `insert_position` is the index of the item in the slice which should *immediately follow* + /// the item which is being moved. + /// + /// Returns `true` of the operation was successful, otherwise `false` if a noop. + pub fn slide(&mut self, index: usize, insert_position: usize) -> bool { + // Check against panics. + if self.len() <= index || self.len() < insert_position || index == usize::MAX { + return false + } + // Noop conditions. + if index == insert_position || index + 1 == insert_position { + return false + } + if insert_position < index && index < self.len() { + // --- --- --- === === === === @@@ --- --- --- + // ^-- N ^O^ + // ... + // /-----<<<-----\ + // --- --- --- === === === === @@@ --- --- --- + // >>> >>> >>> >>> + // ... + // --- --- --- @@@ === === === === --- --- --- + // ^N^ + self[insert_position..index + 1].rotate_right(1); + return true + } else if insert_position > 0 && index + 1 < insert_position { + // Note that the apparent asymmetry of these two branches is due to the + // fact that the "new" position is the position to be inserted *before*. + // --- --- --- @@@ === === === === --- --- --- + // ^O^ ^-- N + // ... + // /----->>>-----\ + // --- --- --- @@@ === === === === --- --- --- + // <<< <<< <<< <<< + // ... + // --- --- --- === === === === @@@ --- --- --- + // ^N^ + self[index..insert_position].rotate_left(1); + return true + } + + debug_assert!(false, "all noop conditions should have been covered above"); + false + } + + /// Forces the insertion of `s` into `self` truncating first if necessary. + /// + /// Infallible, but if the bound is zero, then it's a no-op. + pub fn force_push(&mut self, element: T) { + if Self::bound() > 0 { + self.0.truncate(Self::bound() as usize - 1); + self.0.push(element); + } + } + /// Same as `Vec::resize`, but if `size` is more than [`Self::bound`], then [`Self::bound`] is /// used. pub fn bounded_resize(&mut self, size: usize, value: T) @@ -397,8 +516,7 @@ where #[cfg(test)] pub mod test { use super::*; - use crate::Twox128; - use frame_support::traits::ConstU32; + use crate::{traits::ConstU32, Twox128}; use sp_io::TestExternalities; crate::generate_storage_alias! { Prefix, Foo => Value>> } @@ -408,6 +526,102 @@ pub mod test { FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedVec>> } + #[test] + fn slide_works() { + let mut b: BoundedVec> = vec![0, 1, 2, 3, 4, 5].try_into().unwrap(); + assert!(b.slide(1, 5)); + assert_eq!(*b, vec![0, 2, 3, 4, 1, 5]); + assert!(b.slide(4, 0)); + assert_eq!(*b, vec![1, 0, 2, 3, 4, 5]); + assert!(b.slide(0, 2)); + assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); + assert!(b.slide(1, 6)); + assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); + assert!(b.slide(0, 6)); + assert_eq!(*b, vec![2, 3, 4, 5, 1, 0]); + assert!(b.slide(5, 0)); + assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); + assert!(!b.slide(6, 0)); + assert!(!b.slide(7, 0)); + assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); + + let mut c: BoundedVec> = vec![0, 1, 2].try_into().unwrap(); + assert!(!c.slide(1, 5)); + assert_eq!(*c, vec![0, 1, 2]); + assert!(!c.slide(4, 0)); + assert_eq!(*c, vec![0, 1, 2]); + assert!(!c.slide(3, 0)); + assert_eq!(*c, vec![0, 1, 2]); + assert!(c.slide(2, 0)); + assert_eq!(*c, vec![2, 0, 1]); + } + + #[test] + fn slide_noops_work() { + let mut b: BoundedVec> = vec![0, 1, 2, 3, 4, 5].try_into().unwrap(); + assert!(!b.slide(3, 3)); + assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); + assert!(!b.slide(3, 4)); + assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); + } + + #[test] + fn force_insert_keep_left_works() { + let mut b: BoundedVec> = vec![].try_into().unwrap(); + assert!(!b.force_insert_keep_left(1, 10)); + assert!(b.is_empty()); + + assert!(b.force_insert_keep_left(0, 30)); + assert!(b.force_insert_keep_left(0, 10)); + assert!(b.force_insert_keep_left(1, 20)); + assert!(b.force_insert_keep_left(3, 40)); + assert_eq!(*b, vec![10, 20, 30, 40]); + // at capacity. + assert!(!b.force_insert_keep_left(4, 41)); + assert_eq!(*b, vec![10, 20, 30, 40]); + assert!(b.force_insert_keep_left(3, 31)); + assert_eq!(*b, vec![10, 20, 30, 31]); + assert!(b.force_insert_keep_left(1, 11)); + assert_eq!(*b, vec![10, 11, 20, 30]); + assert!(b.force_insert_keep_left(0, 1)); + assert_eq!(*b, vec![1, 10, 11, 20]); + + let mut z: BoundedVec> = vec![].try_into().unwrap(); + assert!(z.is_empty()); + assert!(!z.force_insert_keep_left(0, 10)); + assert!(z.is_empty()); + } + + #[test] + fn force_insert_keep_right_works() { + let mut b: BoundedVec> = vec![].try_into().unwrap(); + assert!(!b.force_insert_keep_right(1, 10)); + assert!(b.is_empty()); + + assert!(b.force_insert_keep_right(0, 30)); + assert!(b.force_insert_keep_right(0, 10)); + assert!(b.force_insert_keep_right(1, 20)); + assert!(b.force_insert_keep_right(3, 40)); + assert_eq!(*b, vec![10, 20, 30, 40]); + // at capacity. + assert!(!b.force_insert_keep_right(0, 0)); + assert_eq!(*b, vec![10, 20, 30, 40]); + assert!(b.force_insert_keep_right(1, 11)); + assert_eq!(*b, vec![11, 20, 30, 40]); + assert!(b.force_insert_keep_right(3, 31)); + assert_eq!(*b, vec![20, 30, 31, 40]); + assert!(b.force_insert_keep_right(4, 41)); + assert_eq!(*b, vec![30, 31, 40, 41]); + + assert!(!b.force_insert_keep_right(5, 69)); + assert_eq!(*b, vec![30, 31, 40, 41]); + + let mut z: BoundedVec> = vec![].try_into().unwrap(); + assert!(z.is_empty()); + assert!(!z.force_insert_keep_right(0, 10)); + assert!(z.is_empty()); + } + #[test] fn try_append_is_correct() { assert_eq!(BoundedVec::>::bound(), 7); From 9d1790636e55a3456bdab91ff2d0e059878d3c42 Mon Sep 17 00:00:00 2001 From: Joey Date: Mon, 17 Jan 2022 17:31:45 +0800 Subject: [PATCH 0430/1472] the report mod and REPORTING keyType is no longer used (#10679) --- bin/node/primitives/src/lib.rs | 31 ------------------------------- primitives/core/src/crypto.rs | 2 -- 2 files changed, 33 deletions(-) diff --git a/bin/node/primitives/src/lib.rs b/bin/node/primitives/src/lib.rs index fd000af6b2f1b..feb9ee60d311b 100644 --- a/bin/node/primitives/src/lib.rs +++ b/bin/node/primitives/src/lib.rs @@ -64,34 +64,3 @@ pub type Header = generic::Header; pub type Block = generic::Block; /// Block ID. pub type BlockId = generic::BlockId; - -/// App-specific crypto used for reporting equivocation/misbehavior in BABE and -/// GRANDPA. Any rewards for misbehavior reporting will be paid out to this -/// account. -pub mod report { - use super::{Signature, Verify}; - use frame_system::offchain::AppCrypto; - use sp_core::crypto::{key_types, KeyTypeId}; - - /// Key type for the reporting module. Used for reporting BABE and GRANDPA - /// equivocations. - pub const KEY_TYPE: KeyTypeId = key_types::REPORTING; - - mod app { - use sp_application_crypto::{app_crypto, sr25519}; - app_crypto!(sr25519, super::KEY_TYPE); - } - - /// Identity of the equivocation/misbehavior reporter. - pub type ReporterId = app::Public; - - /// An `AppCrypto` type to allow submitting signed transactions using the reporting - /// application key as signer. - pub struct ReporterAppCrypto; - - impl AppCrypto<::Signer, Signature> for ReporterAppCrypto { - type RuntimeAppPublic = ReporterId; - type GenericSignature = sp_core::sr25519::Signature; - type GenericPublic = sp_core::sr25519::Public; - } -} diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index d3dd8b92bd794..41ee9466ad93b 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -1121,8 +1121,6 @@ pub mod key_types { pub const AUTHORITY_DISCOVERY: KeyTypeId = KeyTypeId(*b"audi"); /// Key type for staking, built-in. Identified as `stak`. pub const STAKING: KeyTypeId = KeyTypeId(*b"stak"); - /// Key type for equivocation reporting, built-in. Identified as `fish`. - pub const REPORTING: KeyTypeId = KeyTypeId(*b"fish"); /// A key type ID useful for tests. pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy"); } From 02bdc57655d18ea24b7a9bda6377bd0f134f7d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 17 Jan 2022 11:45:28 +0200 Subject: [PATCH 0431/1472] contracts: Get rid of the dreaded `Other` error (#10595) * Print more detailed error when instrumentation fails * Apply suggestions from code review Co-authored-by: Hernando Castano * Check contents of debug buffer * Fix test Co-authored-by: Hernando Castano --- frame/contracts/fixtures/invalid_import.wat | 6 +++ frame/contracts/src/lib.rs | 16 +++++-- frame/contracts/src/tests.rs | 31 ++++++++++++- frame/contracts/src/wasm/mod.rs | 4 +- frame/contracts/src/wasm/prepare.rs | 48 ++++++++++++--------- 5 files changed, 78 insertions(+), 27 deletions(-) create mode 100644 frame/contracts/fixtures/invalid_import.wat diff --git a/frame/contracts/fixtures/invalid_import.wat b/frame/contracts/fixtures/invalid_import.wat new file mode 100644 index 0000000000000..011f1a40e76d7 --- /dev/null +++ b/frame/contracts/fixtures/invalid_import.wat @@ -0,0 +1,6 @@ +;; A valid contract which does nothing at all but imports an invalid function +(module + (import "invalid" "invalid_88_99" (func (param i32 i32 i32))) + (func (export "deploy")) + (func (export "call")) +) diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index e4a54362c90bc..24d3a7f10ef91 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -632,6 +632,10 @@ pub mod pallet { /// or via RPC an `Ok` will be returned. In this case the caller needs to inspect the flags /// to determine whether a reversion has taken place. ContractReverted, + /// The contract's code was found to be invalid during validation or instrumentation. + /// A more detailed error can be found on the node console if debug messages are enabled + /// or in the debug buffer which is returned to RPC clients. + CodeRejected, } /// A mapping from an original code hash to the original code, untouched by instrumentation. @@ -781,7 +785,8 @@ where storage_deposit_limit: Option>, ) -> CodeUploadResult, BalanceOf> { let schedule = T::Schedule::get(); - let module = PrefabWasmModule::from_code(code, &schedule, origin)?; + let module = PrefabWasmModule::from_code(code, &schedule, origin) + .map_err(|_| >::CodeRejected)?; let deposit = module.open_deposit(); if let Some(storage_deposit_limit) = storage_deposit_limit { ensure!(storage_deposit_limit >= deposit, >::StorageDepositLimitExhausted); @@ -879,7 +884,7 @@ where code: Code>, data: Vec, salt: Vec, - debug_message: Option<&mut Vec>, + mut debug_message: Option<&mut Vec>, ) -> InternalInstantiateOutput { let mut storage_deposit = Default::default(); let mut gas_meter = GasMeter::new(gas_limit); @@ -891,8 +896,11 @@ where binary.len() as u32 <= schedule.limits.code_len, >::CodeTooLarge ); - let executable = - PrefabWasmModule::from_code(binary, &schedule, origin.clone())?; + let executable = PrefabWasmModule::from_code(binary, &schedule, origin.clone()) + .map_err(|msg| { + debug_message.as_mut().map(|buffer| buffer.extend(msg.as_bytes())); + >::CodeRejected + })?; ensure!( executable.code_len() <= schedule.limits.code_len, >::CodeTooLarge diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index be9904e71c5c9..fd5c8cfd34ec9 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -1386,7 +1386,7 @@ fn disabled_chain_extension_wont_deploy() { vec![], vec![], ), - "module uses chain extensions but chain extensions are disabled", + >::CodeRejected, ); }); } @@ -2903,3 +2903,32 @@ fn contract_reverted() { assert_eq!(result.data.0, buffer); }); } + +#[test] +fn code_rejected_error_works() { + let (wasm, _) = compile_module::("invalid_import").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + assert_noop!( + Contracts::upload_code(Origin::signed(ALICE), wasm.clone(), None), + >::CodeRejected, + ); + + let result = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(Bytes(wasm)), + vec![], + vec![], + true, + ); + assert_err!(result.result, >::CodeRejected); + assert_eq!( + std::str::from_utf8(&result.debug_message).unwrap(), + "module imports a non-existent function" + ); + }); +} diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index f63361a039301..ee778982cdbd4 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -122,8 +122,8 @@ where original_code: Vec, schedule: &Schedule, owner: AccountIdOf, - ) -> Result { - prepare::prepare_contract(original_code, schedule, owner).map_err(Into::into) + ) -> Result { + prepare::prepare_contract(original_code, schedule, owner) } /// Store the code without instantiating it. diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 5e5f8e7e6fc90..a57e9aabf8bfb 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -372,26 +372,34 @@ fn check_and_instrument( original_code: &[u8], schedule: &Schedule, ) -> Result<(Vec, (u32, u32)), &'static str> { - let contract_module = ContractModule::new(&original_code, schedule)?; - contract_module.scan_exports()?; - contract_module.ensure_no_internal_memory()?; - contract_module.ensure_table_size_limit(schedule.limits.table_size)?; - contract_module.ensure_global_variable_limit(schedule.limits.globals)?; - contract_module.ensure_no_floating_types()?; - contract_module.ensure_parameter_limit(schedule.limits.parameters)?; - contract_module.ensure_br_table_size_limit(schedule.limits.br_table_size)?; - - // We disallow importing `gas` function here since it is treated as implementation detail. - let disallowed_imports = [b"gas".as_ref()]; - let memory_limits = - get_memory_limits(contract_module.scan_imports::(&disallowed_imports)?, schedule)?; - - let code = contract_module - .inject_gas_metering()? - .inject_stack_height_metering()? - .into_wasm_code()?; - - Ok((code, memory_limits)) + let result = (|| { + let contract_module = ContractModule::new(&original_code, schedule)?; + contract_module.scan_exports()?; + contract_module.ensure_no_internal_memory()?; + contract_module.ensure_table_size_limit(schedule.limits.table_size)?; + contract_module.ensure_global_variable_limit(schedule.limits.globals)?; + contract_module.ensure_no_floating_types()?; + contract_module.ensure_parameter_limit(schedule.limits.parameters)?; + contract_module.ensure_br_table_size_limit(schedule.limits.br_table_size)?; + + // We disallow importing `gas` function here since it is treated as implementation detail. + let disallowed_imports = [b"gas".as_ref()]; + let memory_limits = + get_memory_limits(contract_module.scan_imports::(&disallowed_imports)?, schedule)?; + + let code = contract_module + .inject_gas_metering()? + .inject_stack_height_metering()? + .into_wasm_code()?; + + Ok((code, memory_limits)) + })(); + + if let Err(msg) = &result { + log::debug!(target: "runtime::contracts", "CodeRejected: {}", msg); + } + + result } fn do_preparation( From 08d2ed16ecfe35ab44214112ebc911aa6fed6c1e Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 17 Jan 2022 12:52:10 +0000 Subject: [PATCH 0432/1472] Bump sp-keyring to 4.1.0-dev (#10681) --- Cargo.lock | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- primitives/keyring/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b65795a373b35..cbc99d726eb1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9611,7 +9611,7 @@ dependencies = [ [[package]] name = "sp-keyring" -version = "4.0.0-dev" +version = "4.1.0-dev" dependencies = [ "lazy_static", "sp-core", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index f955076e122b5..58b4d98068466 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -52,7 +52,7 @@ sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../../primitives/transaction-pool" } diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 531e53d2048a9..9796ef6c0ad71 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -38,7 +38,7 @@ sp-application-crypto = { version = "4.0.0", path = "../../../primitives/applica sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } -sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } wat = "1.0" futures = "0.3.9" diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index fa879adf5cbb4..1cffabe09ae60 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -35,7 +35,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../../primiti sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } -sp-keyring = { version = "4.0.0-dev", optional = true, path = "../../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../../primitives/keyring" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index bee6f92d1280b..d0348b3096bbe 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -24,7 +24,7 @@ sc-client-db = { version = "0.10.0-dev", path = "../../../client/db/", features sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } codec = { package = "parity-scale-codec", version = "2.0.0" } -sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 7ef5ef9d68932..5b7825182b38f 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -36,7 +36,7 @@ sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../service" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } -sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } names = { version = "0.12.0", default-features = false } structopt = "0.3.25" sc-tracing = { version = "4.0.0-dev", path = "../tracing" } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index e9c897de5dcb1..534aa28920ae1 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -41,7 +41,7 @@ getrandom = { version = "0.2", features = ["js"], optional = true } [dev-dependencies] sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } sc-network = { version = "0.10.0-dev", path = "../../network" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index dbc840d26c57c..0806f72e688ec 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -34,7 +34,7 @@ sp-keystore = { version = "0.10.0", path = "../../../../primitives/keystore" } [dev-dependencies] sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } serde_json = "1.0.74" -sp-keyring = { version = "4.0.0-dev", path = "../../../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", path = "../../../../primitives/keyring" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } tempfile = "3.1.0" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 306311b0e3e56..83ebe617973b6 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -55,7 +55,7 @@ finality-grandpa = { version = "0.14.1", features = [ ] } sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-test = { version = "0.8.0", path = "../network/test" } -sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } tokio = "1.15" diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index b923ec41d33f9..2fe7d3683159f 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -34,5 +34,5 @@ sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ ] } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } -sp-keyring = { version = "4.0.0-dev", path = "../../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index f123fdbb61ee8..8604c678bf641 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -33,7 +33,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } grandpa = { package = "finality-grandpa", version = "0.14.1", features = ["derive-codec"] } -sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index da56606ed2f69..d2c114e605199 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-keyring = { version = "4.0.0-dev", optional = true, path = "../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../primitives/keyring" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index a8529716b712a..d9250d0011f13 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-keyring" -version = "4.0.0-dev" +version = "4.1.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index cb9f17f637dda..91504df481dfb 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -31,7 +31,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } -sp-keyring = { version = "4.0.0-dev", path = "../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } async-trait = "0.1.50" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index c32586834f30b..ee38cfd250dcd 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -20,7 +20,7 @@ sp-block-builder = { version = "4.0.0-dev", default-features = false, path = ".. codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } -sp-keyring = { version = "4.0.0-dev", optional = true, path = "../../primitives/keyring" } +sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../primitives/keyring" } memory-db = { version = "0.27.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } From 249dbbba6a1a277a3098c2a5b302645da16451ad Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Mon, 17 Jan 2022 15:39:24 +0200 Subject: [PATCH 0433/1472] Update wasmtime to 0.33.0 (#10674) Also disable memory64 support in wasmtime --- Cargo.lock | 183 ++++++++++-------------- client/executor/wasmtime/Cargo.toml | 2 +- client/executor/wasmtime/src/runtime.rs | 1 + client/executor/wasmtime/src/tests.rs | 6 +- primitives/wasm-interface/Cargo.toml | 2 +- 5 files changed, 81 insertions(+), 113 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbc99d726eb1f..12b825375631f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,15 +12,6 @@ dependencies = [ "regex", ] -[[package]] -name = "addr2line" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" -dependencies = [ - "gimli 0.25.0", -] - [[package]] name = "addr2line" version = "0.17.0" @@ -431,7 +422,7 @@ version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" dependencies = [ - "addr2line 0.17.0", + "addr2line", "cc", "cfg-if 1.0.0", "libc", @@ -1105,11 +1096,11 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.78.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0cb7df82c8cf8f2e6a8dd394a0932a71369c160cc9b027dca414fced242513" +checksum = "9516ba6b2ba47b4cbf63b713f75b432fafa0a0e0464ec8381ec76e6efe931ab3" dependencies = [ - "cranelift-entity 0.78.0", + "cranelift-entity 0.80.0", ] [[package]] @@ -1133,17 +1124,17 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.78.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4463c15fa42eee909e61e5eac4866b7c6d22d0d8c621e57a0c5380753bfa8c" +checksum = "489e5d0081f7edff6be12d71282a8bf387b5df64d5592454b75d662397f2d642" dependencies = [ - "cranelift-bforest 0.78.0", - "cranelift-codegen-meta 0.78.0", - "cranelift-codegen-shared 0.78.0", - "cranelift-entity 0.78.0", - "gimli 0.25.0", + "cranelift-bforest 0.80.0", + "cranelift-codegen-meta 0.80.0", + "cranelift-codegen-shared 0.80.0", + "cranelift-entity 0.80.0", + "gimli 0.26.1", "log 0.4.14", - "regalloc 0.0.32", + "regalloc 0.0.33", "smallvec 1.7.0", "target-lexicon 0.12.0", ] @@ -1160,12 +1151,11 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.78.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793f6a94a053a55404ea16e1700202a88101672b8cd6b4df63e13cde950852bf" +checksum = "d36ee1140371bb0f69100e734b30400157a4adf7b86148dee8b0a438763ead48" dependencies = [ - "cranelift-codegen-shared 0.78.0", - "cranelift-entity 0.78.0", + "cranelift-codegen-shared 0.80.0", ] [[package]] @@ -1176,9 +1166,9 @@ checksum = "6759012d6d19c4caec95793f052613e9d4113e925e7f14154defbac0f1d4c938" [[package]] name = "cranelift-codegen-shared" -version = "0.78.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44aa1846df275bce5eb30379d65964c7afc63c05a117076e62a119c25fe174be" +checksum = "981da52d8f746af1feb96290c83977ff8d41071a7499e991d8abae0d4869f564" [[package]] name = "cranelift-entity" @@ -1191,9 +1181,9 @@ dependencies = [ [[package]] name = "cranelift-entity" -version = "0.78.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3a45d8d6318bf8fc518154d9298eab2a8154ec068a8885ff113f6db8d69bb3a" +checksum = "a2906740053dd3bcf95ce53df0fd9b5649c68ae4bd9adada92b406f059eae461" dependencies = [ "serde", ] @@ -1212,11 +1202,11 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.78.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e07339bd461766deb7605169de039e01954768ff730fa1254e149001884a8525" +checksum = "b7cb156de1097f567d46bf57a0cd720a72c3e15e1a2bd8b1041ba2fc894471b7" dependencies = [ - "cranelift-codegen 0.78.0", + "cranelift-codegen 0.80.0", "log 0.4.14", "smallvec 1.7.0", "target-lexicon 0.12.0", @@ -1224,24 +1214,24 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.78.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e2fca76ff57e0532936a71e3fc267eae6a19a86656716479c66e7f912e3d7b" +checksum = "166028ca0343a6ee7bddac0e70084e142b23f99c701bd6f6ea9123afac1a7a46" dependencies = [ - "cranelift-codegen 0.78.0", + "cranelift-codegen 0.80.0", "libc", "target-lexicon 0.12.0", ] [[package]] name = "cranelift-wasm" -version = "0.78.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f46fec547a1f8a32c54ea61c28be4f4ad234ad95342b718a9a9adcaadb0c778" +checksum = "5012a1cde0c8b3898770b711490d803018ae9bec2d60674ba0e5b2058a874f80" dependencies = [ - "cranelift-codegen 0.78.0", - "cranelift-entity 0.78.0", - "cranelift-frontend 0.78.0", + "cranelift-codegen 0.80.0", + "cranelift-entity 0.80.0", + "cranelift-frontend 0.80.0", "itertools", "log 0.4.14", "smallvec 1.7.0", @@ -1842,9 +1832,9 @@ checksum = "68b91989ae21441195d7d9b9993a2f9295c7e1a8c96255d8b729accddc124797" [[package]] name = "errno" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ "errno-dragonfly", "libc", @@ -2531,21 +2521,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.25.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" dependencies = [ "fallible-iterator", "indexmap", "stable_deref_trait", ] -[[package]] -name = "gimli" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" - [[package]] name = "git2" version = "0.13.25" @@ -2996,11 +2980,10 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "0.3.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47f5ce4afb9bf504b9f496a3307676bc232122f91a93c4da6d540aa99a0a0e0b" +checksum = "f6ef6787e7f0faedc040f95716bdd0e62bcfcf4ba93da053b62dea2691c13864" dependencies = [ - "rustc_version 0.4.0", "winapi 0.3.9", ] @@ -4015,9 +3998,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.0.28" +version = "0.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687387ff42ec7ea4f2149035a5675fedb675d26f98db90a1846ac63d3addb5f5" +checksum = "a261afc61b7a5e323933b402ca6a1765183687c614789b1e4db7762ed4230bca" [[package]] name = "lite-json" @@ -7354,9 +7337,9 @@ dependencies = [ [[package]] name = "regalloc" -version = "0.0.32" +version = "0.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6304468554ed921da3d32c355ea107b8d13d7b8996c3adfb7aab48d3bc321f4" +checksum = "7d808cff91dfca7b239d40b972ba628add94892b1d9e19a842aedc5cfae8ab1a" dependencies = [ "log 0.4.14", "rustc-hash", @@ -7481,23 +7464,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "rsix" -version = "0.23.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f64c5788d5aab8b75441499d99576a24eb09f76fb267b36fec7e3d970c66431" -dependencies = [ - "bitflags", - "cc", - "errno", - "io-lifetimes", - "itoa 0.4.8", - "libc", - "linux-raw-sys", - "once_cell", - "rustc_version 0.4.0", -] - [[package]] name = "rustc-demangle" version = "0.1.18" @@ -7535,12 +7501,17 @@ dependencies = [ ] [[package]] -name = "rustc_version" -version = "0.4.0" +name = "rustix" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "b2dcfc2778a90e38f56a708bfc90572422e11d6c7ee233d053d1f782cf9df6d2" dependencies = [ - "semver 1.0.4", + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "winapi 0.3.9", ] [[package]] @@ -11583,9 +11554,9 @@ checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc" [[package]] name = "wasmtime" -version = "0.31.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311d06b0c49346d1fbf48a17052e844036b95a7753c1afb34e8c0af3f6b5bb13" +checksum = "414be1bc5ca12e755ffd3ff7acc3a6d1979922f8237fc34068b2156cebcc3270" dependencies = [ "anyhow", "backtrace", @@ -11615,9 +11586,9 @@ dependencies = [ [[package]] name = "wasmtime-cache" -version = "0.31.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147930a4995137dc096e5b17a573b446799be2bbaea433e821ce6a80abe2c5" +checksum = "8b9b4cd1949206fda9241faf8c460a7d797aa1692594d3dd6bc1cbfa57ee20d0" dependencies = [ "anyhow", "base64 0.13.0", @@ -11625,7 +11596,7 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log 0.4.14", - "rsix", + "rustix", "serde", "sha2 0.9.8", "toml", @@ -11635,17 +11606,17 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "0.31.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3083a47e1ede38aac06a1d9831640d673f9aeda0b82a64e4ce002f3432e2e7" +checksum = "a4693d33725773615a4c9957e4aa731af57b27dca579702d1d8ed5750760f1a9" dependencies = [ "anyhow", - "cranelift-codegen 0.78.0", - "cranelift-entity 0.78.0", - "cranelift-frontend 0.78.0", + "cranelift-codegen 0.80.0", + "cranelift-entity 0.80.0", + "cranelift-frontend 0.80.0", "cranelift-native", "cranelift-wasm", - "gimli 0.25.0", + "gimli 0.26.1", "log 0.4.14", "more-asserts", "object 0.27.1", @@ -11657,14 +11628,13 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "0.31.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c2d194b655321053bc4111a1aa4ead552655c8a17d17264bc97766e70073510" +checksum = "5b17e47116a078b9770e6fb86cff8b9a660826623cebcfff251b047c8d8993ef" dependencies = [ "anyhow", - "cfg-if 1.0.0", - "cranelift-entity 0.78.0", - "gimli 0.25.0", + "cranelift-entity 0.80.0", + "gimli 0.26.1", "indexmap", "log 0.4.14", "more-asserts", @@ -11678,24 +11648,21 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "0.31.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864ac8dfe4ce310ac59f16fdbd560c257389cb009ee5d030ac6e30523b023d11" +checksum = "60ea5b380bdf92e32911400375aeefb900ac9d3f8e350bb6ba555a39315f2ee7" dependencies = [ - "addr2line 0.16.0", + "addr2line", "anyhow", "bincode", "cfg-if 1.0.0", - "gimli 0.25.0", - "log 0.4.14", - "more-asserts", + "gimli 0.26.1", "object 0.27.1", "region", - "rsix", + "rustix", "serde", "target-lexicon 0.12.0", "thiserror", - "wasmparser 0.81.0", "wasmtime-environ", "wasmtime-runtime", "winapi 0.3.9", @@ -11703,9 +11670,9 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "0.31.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab97da813a26b98c9abfd3b0c2d99e42f6b78b749c0646344e2e262d212d8c8b" +checksum = "abc7cd79937edd6e238b337608ebbcaf9c086a8457f01dfd598324f7fa56d81a" dependencies = [ "anyhow", "backtrace", @@ -11720,7 +11687,7 @@ dependencies = [ "more-asserts", "rand 0.8.4", "region", - "rsix", + "rustix", "thiserror", "wasmtime-environ", "winapi 0.3.9", @@ -11728,11 +11695,11 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "0.31.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff94409cc3557bfbbcce6b14520ccd6bd3727e965c0fe68d63ef2c185bf379c6" +checksum = "d9e5e51a461a2cf2b69e1fc48f325b17d78a8582816e18479e8ead58844b23f8" dependencies = [ - "cranelift-entity 0.78.0", + "cranelift-entity 0.80.0", "serde", "thiserror", "wasmparser 0.81.0", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 65efc26035098..8b3cd1a58e75f 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -23,7 +23,7 @@ sp-wasm-interface = { version = "4.1.0-dev", path = "../../../primitives/wasm-in sp-runtime-interface = { version = "4.1.0-dev", path = "../../../primitives/runtime-interface" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -wasmtime = { version = "0.31.0", default-features = false, features = [ +wasmtime = { version = "0.33.0", default-features = false, features = [ "cache", "cranelift", "jitdump", diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 6300163db50ca..6533aa194e4c4 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -344,6 +344,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result Date: Mon, 17 Jan 2022 17:00:17 +0200 Subject: [PATCH 0434/1472] Switch from `pwasm-utils` to `wasm-instrument` (#10680) * Switch executor to wasm-instrument * Switch pallet-contracts to wasm-instrument --- Cargo.lock | 24 +++++++++---------- client/executor/common/Cargo.toml | 2 +- .../runtime_blob/data_segments_snapshot.rs | 2 +- .../common/src/runtime_blob/runtime_blob.rs | 4 ++-- frame/contracts/Cargo.toml | 4 ++-- frame/contracts/src/benchmarking/code.rs | 18 +++++++------- frame/contracts/src/benchmarking/mod.rs | 2 +- frame/contracts/src/schedule.rs | 10 ++++---- frame/contracts/src/wasm/env_def/macros.rs | 8 +++---- frame/contracts/src/wasm/env_def/mod.rs | 2 +- frame/contracts/src/wasm/prepare.rs | 17 ++++++------- frame/contracts/src/wasm/runtime.rs | 2 +- 12 files changed, 47 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12b825375631f..1a43c9ded8137 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5475,7 +5475,6 @@ dependencies = [ "pallet-utility", "parity-scale-codec", "pretty_assertions", - "pwasm-utils", "rand 0.8.4", "rand_pcg 0.3.1", "scale-info", @@ -5486,6 +5485,7 @@ dependencies = [ "sp-runtime", "sp-sandbox", "sp-std", + "wasm-instrument", "wasmi-validation", "wat", ] @@ -6957,17 +6957,6 @@ dependencies = [ "cc", ] -[[package]] -name = "pwasm-utils" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "880b3384fb00b8f6ecccd5d358b93bd2201900ae3daad213791d1864f6441f5c" -dependencies = [ - "byteorder", - "log 0.4.14", - "parity-wasm 0.42.2", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -8094,13 +8083,13 @@ dependencies = [ "derive_more", "environmental", "parity-scale-codec", - "pwasm-utils", "sc-allocator", "sp-core", "sp-maybe-compressed-blob", "sp-serializer", "sp-wasm-interface", "thiserror", + "wasm-instrument", "wasmer", "wasmer-compiler-singlepass", "wasmi", @@ -11306,6 +11295,15 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "wasm-instrument" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e67369bb53d409b67e57ef31797b1b2d628955fc82f86f2ea78bb403acc7c73" +dependencies = [ + "parity-wasm 0.42.2", +] + [[package]] name = "wasm-timer" version = "0.2.5" diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 5edf179c056ae..8e4b11f8f8fae 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] derive_more = "0.99.16" -pwasm-utils = "0.18.2" +wasm-instrument = "0.1" codec = { package = "parity-scale-codec", version = "2.0.0" } wasmi = "0.9.1" sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } diff --git a/client/executor/common/src/runtime_blob/data_segments_snapshot.rs b/client/executor/common/src/runtime_blob/data_segments_snapshot.rs index 76f2ad2c345ee..b44370e681b13 100644 --- a/client/executor/common/src/runtime_blob/data_segments_snapshot.rs +++ b/client/executor/common/src/runtime_blob/data_segments_snapshot.rs @@ -18,8 +18,8 @@ use super::RuntimeBlob; use crate::error::{self, Error}; -use pwasm_utils::parity_wasm::elements::Instruction; use std::mem; +use wasm_instrument::parity_wasm::elements::Instruction; /// This is a snapshot of data segments specialzied for a particular instantiation. /// diff --git a/client/executor/common/src/runtime_blob/runtime_blob.rs b/client/executor/common/src/runtime_blob/runtime_blob.rs index 8318cce7a9bad..d95dcda1a8779 100644 --- a/client/executor/common/src/runtime_blob/runtime_blob.rs +++ b/client/executor/common/src/runtime_blob/runtime_blob.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::error::WasmError; -use pwasm_utils::{ +use wasm_instrument::{ export_mutable_globals, parity_wasm::elements::{deserialize_buffer, serialize, DataSegment, Internal, Module}, }; @@ -84,7 +84,7 @@ impl RuntimeBlob { /// depth of the wasm operand stack. pub fn inject_stack_depth_metering(self, stack_depth_limit: u32) -> Result { let injected_module = - pwasm_utils::stack_height::inject_limiter(self.raw_module, stack_depth_limit).map_err( + wasm_instrument::inject_stack_limiter(self.raw_module, stack_depth_limit).map_err( |e| WasmError::Other(format!("cannot inject the stack limiter: {:?}", e)), )?; diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 4067148e13e15..64c1de2201553 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4", default-features = false } -pwasm-utils = { version = "0.18.2", default-features = false } +wasm-instrument = { version = "0.1", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } smallvec = { version = "1", default-features = false, features = [ "const_generics", @@ -71,7 +71,7 @@ std = [ "frame-benchmarking/std", "frame-support/std", "frame-system/std", - "pwasm-utils/std", + "wasm-instrument/std", "wasmi-validation/std", "pallet-contracts-primitives/std", "pallet-contracts-proc-macro/full", diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index d4828871dbbe5..4d42349f82a1b 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -26,13 +26,6 @@ use crate::Config; use frame_support::traits::Get; -use pwasm_utils::parity_wasm::{ - builder, - elements::{ - self, BlockType, CustomSection, External, FuncBody, Instruction, Instructions, Module, - Section, ValueType, - }, -}; use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::Hash; use sp_sandbox::{ @@ -40,6 +33,13 @@ use sp_sandbox::{ SandboxEnvironmentBuilder, SandboxMemory, }; use sp_std::{borrow::ToOwned, prelude::*}; +use wasm_instrument::parity_wasm::{ + builder, + elements::{ + self, BlockType, CustomSection, External, FuncBody, Instruction, Instructions, Module, + Section, ValueType, + }, +}; /// The location where to put the genrated code. pub enum Location { @@ -562,10 +562,10 @@ where fn inject_gas_metering(module: Module) -> Module { let schedule = T::Schedule::get(); let gas_rules = schedule.rules(&module); - pwasm_utils::inject_gas_counter(module, &gas_rules, "seal0").unwrap() + wasm_instrument::gas_metering::inject(module, &gas_rules, "seal0").unwrap() } fn inject_stack_metering(module: Module) -> Module { let height = T::Schedule::get().limits.stack_height; - pwasm_utils::stack_height::inject_limiter(module, height).unwrap() + wasm_instrument::inject_stack_limiter(module, height).unwrap() } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index a0f5ceb034f78..6d4ae959f31e8 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -39,12 +39,12 @@ use codec::Encode; use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_support::weights::Weight; use frame_system::RawOrigin; -use pwasm_utils::parity_wasm::elements::{BlockType, BrTableData, Instruction, ValueType}; use sp_runtime::{ traits::{Bounded, Hash}, Perbill, }; use sp_std::prelude::*; +use wasm_instrument::parity_wasm::elements::{BlockType, BrTableData, Instruction, ValueType}; /// How many batches we do per API benchmark. const API_BENCHMARK_BATCHES: u32 = 20; diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index f3bfaea242777..459bd950ce462 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -23,12 +23,12 @@ use crate::{weights::WeightInfo, Config}; use codec::{Decode, Encode}; use frame_support::{weights::Weight, DefaultNoBound}; use pallet_contracts_proc_macro::{ScheduleDebug, WeightDebug}; -use pwasm_utils::{parity_wasm::elements, rules}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_runtime::RuntimeDebug; use sp_std::{marker::PhantomData, vec::Vec}; +use wasm_instrument::{gas_metering, parity_wasm::elements}; /// How many API calls are executed in a single batch. The reason for increasing the amount /// of API calls in batches (per benchmark component increase) is so that the linear regression @@ -652,7 +652,7 @@ struct ScheduleRules<'a, T: Config> { } impl Schedule { - pub(crate) fn rules(&self, module: &elements::Module) -> impl rules::Rules + '_ { + pub(crate) fn rules(&self, module: &elements::Module) -> impl gas_metering::Rules + '_ { ScheduleRules { schedule: &self, params: module @@ -668,7 +668,7 @@ impl Schedule { } } -impl<'a, T: Config> rules::Rules for ScheduleRules<'a, T> { +impl<'a, T: Config> gas_metering::Rules for ScheduleRules<'a, T> { fn instruction_cost(&self, instruction: &elements::Instruction) -> Option { use self::elements::Instruction::*; let w = &self.schedule.instruction_weights; @@ -752,10 +752,10 @@ impl<'a, T: Config> rules::Rules for ScheduleRules<'a, T> { Some(weight) } - fn memory_grow_cost(&self) -> Option { + fn memory_grow_cost(&self) -> gas_metering::MemoryGrowCost { // We benchmarked the memory.grow instruction with the maximum allowed pages. // The cost for growing is therefore already included in the instruction cost. - None + gas_metering::MemoryGrowCost::Free } } diff --git a/frame/contracts/src/wasm/env_def/macros.rs b/frame/contracts/src/wasm/env_def/macros.rs index a50290085df8b..aa5a1626681f4 100644 --- a/frame/contracts/src/wasm/env_def/macros.rs +++ b/frame/contracts/src/wasm/env_def/macros.rs @@ -28,7 +28,7 @@ macro_rules! convert_args { macro_rules! gen_signature { ( ( $( $params: ty ),* ) ) => ( { - pwasm_utils::parity_wasm::elements::FunctionType::new( + wasm_instrument::parity_wasm::elements::FunctionType::new( convert_args!($($params),*), vec![], ) } @@ -36,7 +36,7 @@ macro_rules! gen_signature { ( ( $( $params: ty ),* ) -> $returns: ty ) => ( { - pwasm_utils::parity_wasm::elements::FunctionType::new( + wasm_instrument::parity_wasm::elements::FunctionType::new( convert_args!($($params),*), vec![{use $crate::wasm::env_def::ConvertibleToWasm; <$returns>::VALUE_TYPE}], ) @@ -220,7 +220,7 @@ macro_rules! define_env { fn can_satisfy( module: &[u8], name: &[u8], - func_type: &pwasm_utils::parity_wasm::elements::FunctionType, + func_type: &wasm_instrument::parity_wasm::elements::FunctionType, ) -> bool { #[cfg(not(feature = "unstable-interface"))] @@ -260,9 +260,9 @@ mod tests { wasm::{runtime::TrapReason, tests::MockExt, Runtime}, Weight, }; - use pwasm_utils::parity_wasm::elements::{FunctionType, ValueType}; use sp_runtime::traits::Zero; use sp_sandbox::{ReturnValue, Value}; + use wasm_instrument::parity_wasm::elements::{FunctionType, ValueType}; struct TestRuntime { value: u32, diff --git a/frame/contracts/src/wasm/env_def/mod.rs b/frame/contracts/src/wasm/env_def/mod.rs index c74af80d3e4ef..b4c5ffe81e7c1 100644 --- a/frame/contracts/src/wasm/env_def/mod.rs +++ b/frame/contracts/src/wasm/env_def/mod.rs @@ -18,8 +18,8 @@ use super::Runtime; use crate::exec::Ext; -use pwasm_utils::parity_wasm::elements::{FunctionType, ValueType}; use sp_sandbox::Value; +use wasm_instrument::parity_wasm::elements::{FunctionType, ValueType}; #[macro_use] pub mod macros; diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index a57e9aabf8bfb..70c15cb8c4e6e 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -26,9 +26,11 @@ use crate::{ AccountIdOf, Config, Schedule, }; use codec::{Encode, MaxEncodedLen}; -use pwasm_utils::parity_wasm::elements::{self, External, Internal, MemoryType, Type, ValueType}; use sp_runtime::traits::Hash; use sp_std::prelude::*; +use wasm_instrument::parity_wasm::elements::{ + self, External, Internal, MemoryType, Type, ValueType, +}; /// Imported memory must be located inside this module. The reason for hardcoding is that current /// compiler toolchains might not support specifying other modules than "env" for memory imports. @@ -182,17 +184,16 @@ impl<'a, T: Config> ContractModule<'a, T> { fn inject_gas_metering(self) -> Result { let gas_rules = self.schedule.rules(&self.module); - let contract_module = pwasm_utils::inject_gas_counter(self.module, &gas_rules, "seal0") - .map_err(|_| "gas instrumentation failed")?; + let contract_module = + wasm_instrument::gas_metering::inject(self.module, &gas_rules, "seal0") + .map_err(|_| "gas instrumentation failed")?; Ok(ContractModule { module: contract_module, schedule: self.schedule }) } fn inject_stack_height_metering(self) -> Result { - let contract_module = pwasm_utils::stack_height::inject_limiter( - self.module, - self.schedule.limits.stack_height, - ) - .map_err(|_| "stack height instrumentation failed")?; + let contract_module = + wasm_instrument::inject_stack_limiter(self.module, self.schedule.limits.stack_height) + .map_err(|_| "stack height instrumentation failed")?; Ok(ContractModule { module: contract_module, schedule: self.schedule }) } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 8b07329e5db43..98d9d9a40cda9 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -29,12 +29,12 @@ use bitflags::bitflags; use codec::{Decode, DecodeAll, Encode, MaxEncodedLen}; use frame_support::{dispatch::DispatchError, ensure, weights::Weight}; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; -use pwasm_utils::parity_wasm::elements::ValueType; use sp_core::{crypto::UncheckedFrom, Bytes}; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; use sp_runtime::traits::{Bounded, Zero}; use sp_sandbox::SandboxMemory; use sp_std::prelude::*; +use wasm_instrument::parity_wasm::elements::ValueType; /// Every error that can be returned to a contract when it calls any of the host functions. /// From 963ee8a37130f6d76b2859e76164a01607a306cf Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Tue, 18 Jan 2022 06:21:19 +0900 Subject: [PATCH 0435/1472] Add feature: `no-metadata-doc` which removes doc from metadata and `full-metadata` which build metadata with all doc (#10493) * add features to remove or add doc * fmt * add test for event/error/call * fmt --- .gitlab-ci.yml | 2 +- frame/support/Cargo.toml | 6 ++++ frame/support/procedural/Cargo.toml | 1 + .../procedural/src/pallet/expand/call.rs | 4 ++- .../procedural/src/pallet/expand/constants.rs | 4 ++- .../procedural/src/pallet/expand/error.rs | 5 ++- .../procedural/src/pallet/expand/event.rs | 6 ++-- .../procedural/src/pallet/expand/storage.rs | 3 +- .../support/src/storage/types/counted_map.rs | 12 +++++-- frame/support/src/storage/types/double_map.rs | 2 ++ frame/support/src/storage/types/map.rs | 2 ++ frame/support/src/storage/types/nmap.rs | 2 ++ frame/support/src/storage/types/value.rs | 2 ++ frame/support/test/Cargo.toml | 1 + frame/support/test/tests/pallet.rs | 32 +++++++++++++++---- .../test/tests/pallet_compatibility.rs | 4 +++ .../tests/pallet_compatibility_instance.rs | 4 +++ 17 files changed, 76 insertions(+), 16 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 43674da4627a5..b68dd303841d8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -450,7 +450,7 @@ test-linux-stable: &test-linux script: # this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests - time cargo test --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml - - time cargo test -p frame-support-test --features=conditional-storage --manifest-path frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec + - time cargo test -p frame-support-test --features=conditional-storage,no-metadata-docs --manifest-path frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout - sccache -s diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index efc7caab1bd4e..a6bbc73f9ddb6 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -63,3 +63,9 @@ std = [ ] runtime-benchmarks = [] try-runtime = [] +# By default some types have documentation, `no-metadata-docs` allows to reduce the documentation +# in the metadata. +no-metadata-docs = ["frame-support-procedural/no-metadata-docs"] +# By default some types have documentation, `full-metadata-docs` allows to add documentation to +# more types in the metadata. +full-metadata-docs = ["scale-info/docs"] diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 640fe436b1855..4e9618b5bc167 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -24,3 +24,4 @@ syn = { version = "1.0.82", features = ["full"] } [features] default = ["std"] std = [] +no-metadata-docs = [] diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 58c4804558b0e..355d4f87d3db9 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -137,6 +137,8 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { let count = COUNTER.with(|counter| counter.borrow_mut().inc()); let macro_ident = syn::Ident::new(&format!("__is_call_part_defined_{}", count), span); + let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" }; + quote::quote_spanned!(span => #[doc(hidden)] pub mod __substrate_call_check { @@ -164,7 +166,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { )] #[codec(encode_bound())] #[codec(decode_bound())] - #[scale_info(skip_type_params(#type_use_gen), capture_docs = "always")] + #[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)] #[allow(non_camel_case_types)] pub enum #call_ident<#type_decl_bounded_gen> #where_clause { #[doc(hidden)] diff --git a/frame/support/procedural/src/pallet/expand/constants.rs b/frame/support/procedural/src/pallet/expand/constants.rs index 3f853902010f9..1f9526f9cebe0 100644 --- a/frame/support/procedural/src/pallet/expand/constants.rs +++ b/frame/support/procedural/src/pallet/expand/constants.rs @@ -79,7 +79,9 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { let const_type = &const_.type_; let ident_str = format!("{}", const_.metadata_name.unwrap_or(const_.ident)); - let doc = const_.doc.clone().into_iter(); + let no_docs = vec![]; + let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &const_.doc }; + let default_byte_impl = &const_.default_byte_impl; quote::quote!({ diff --git a/frame/support/procedural/src/pallet/expand/error.rs b/frame/support/procedural/src/pallet/expand/error.rs index 3e6247e77f8cc..4cf572c1797f2 100644 --- a/frame/support/procedural/src/pallet/expand/error.rs +++ b/frame/support/procedural/src/pallet/expand/error.rs @@ -58,12 +58,15 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { }; error_item.variants.insert(0, phantom_variant); + + let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" }; + // derive TypeInfo for error metadata error_item .attrs .push(syn::parse_quote!( #[derive(#frame_support::scale_info::TypeInfo)] )); error_item.attrs.push(syn::parse_quote!( - #[scale_info(skip_type_params(#type_use_gen), capture_docs = "always")] + #[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)] )); if get_doc_literals(&error_item.attrs).is_empty() { diff --git a/frame/support/procedural/src/pallet/expand/event.rs b/frame/support/procedural/src/pallet/expand/event.rs index 79a7acaf66a5a..acd60ab959c61 100644 --- a/frame/support/procedural/src/pallet/expand/event.rs +++ b/frame/support/procedural/src/pallet/expand/event.rs @@ -117,9 +117,11 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { )] )); - // skip requirement for type params to implement `TypeInfo`, and require docs capture + let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" }; + + // skip requirement for type params to implement `TypeInfo`, and set docs capture event_item.attrs.push(syn::parse_quote!( - #[scale_info(skip_type_params(#event_use_gen), capture_docs = "always")] + #[scale_info(skip_type_params(#event_use_gen), capture_docs = #capture_docs)] )); let deposit_event = if let Some(deposit_event) = &event.deposit_event { diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 9d936dd50344e..f45223c1cc842 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -234,7 +234,8 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { let pallet_ident = &def.pallet_struct.pallet; let entries_builder = def.storages.iter().map(|storage| { - let docs = &storage.docs; + let no_docs = vec![]; + let docs = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &storage.docs }; let ident = &storage.ident; let gen = &def.type_use_generics(storage.attr_span); diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 341dedaef0bac..0f98b13282a74 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -417,7 +417,11 @@ where fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { ::Map::build_metadata(docs, entries); CounterFor::::build_metadata( - vec![&"Counter for the related counted storage map"], + if cfg!(feature = "no-metadata-docs") { + vec![] + } else { + vec![&"Counter for the related counted storage map"] + }, entries, ); } @@ -1054,7 +1058,11 @@ mod test { modifier: StorageEntryModifier::Default, ty: StorageEntryType::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0], - docs: vec!["Counter for the related counted storage map"], + docs: if cfg!(feature = "no-metadata-docs") { + vec![] + } else { + vec!["Counter for the related counted storage map"] + }, }, ] ); diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 1a4d979d98f8f..07da0f2239b3b 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -530,6 +530,8 @@ where MaxValues: Get>, { fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; + let entry = StorageEntryMetadata { name: Prefix::STORAGE_PREFIX, modifier: QueryKind::METADATA, diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index e769daa490367..d0b82e1a84e5b 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -352,6 +352,8 @@ where MaxValues: Get>, { fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; + let entry = StorageEntryMetadata { name: Prefix::STORAGE_PREFIX, modifier: QueryKind::METADATA, diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 30e6fb5637882..03f15e335389b 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -451,6 +451,8 @@ where MaxValues: Get>, { fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; + let entry = StorageEntryMetadata { name: Prefix::STORAGE_PREFIX, modifier: QueryKind::METADATA, diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index a368988f378bd..f145e9fb30414 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -210,6 +210,8 @@ where OnEmpty: crate::traits::Get + 'static, { fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; + let entry = StorageEntryMetadata { name: Prefix::STORAGE_PREFIX, modifier: QueryKind::METADATA, diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 975e0830ab0e4..f7275cbe2e853 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -52,3 +52,4 @@ try-runtime = ["frame-support/try-runtime"] conditional-storage = [] # Disable ui tests disable-ui-tests = [] +no-metadata-docs = ["frame-support/no-metadata-docs"] diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 59b581eda58e4..5f9e886dbb672 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -1100,6 +1100,14 @@ fn migrate_from_pallet_version_to_storage_version() { fn metadata() { use frame_support::metadata::*; + fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> { + if cfg!(feature = "no-metadata-docs") { + vec![] + } else { + doc + } + } + let pallets = vec![ PalletMetadata { index: 1, @@ -1269,7 +1277,7 @@ fn metadata() { modifier: StorageEntryModifier::Default, ty: StorageEntryType::Plain(meta_type::()), default: vec![0, 0, 0, 0], - docs: vec!["Counter for the related counted storage map"], + docs: maybe_docs(vec!["Counter for the related counted storage map"]), }, StorageEntryMetadata { name: "Unbounded", @@ -1287,13 +1295,13 @@ fn metadata() { name: "MyGetParam", ty: meta_type::(), value: vec![10, 0, 0, 0], - docs: vec![" Some comment", " Some comment"], + docs: maybe_docs(vec![" Some comment", " Some comment"]), }, PalletConstantMetadata { name: "MyGetParam2", ty: meta_type::(), value: vec![11, 0, 0, 0], - docs: vec![" Some comment", " Some comment"], + docs: maybe_docs(vec![" Some comment", " Some comment"]), }, PalletConstantMetadata { name: "MyGetParam3", @@ -1305,19 +1313,19 @@ fn metadata() { name: "some_extra", ty: meta_type::(), value: vec![100, 0, 0, 0, 0, 0, 0, 0], - docs: vec![" Some doc", " Some doc"], + docs: maybe_docs(vec![" Some doc", " Some doc"]), }, PalletConstantMetadata { name: "some_extra_extra", ty: meta_type::(), value: vec![0, 0, 0, 0, 0, 0, 0, 0], - docs: vec![" Some doc"], + docs: maybe_docs(vec![" Some doc"]), }, PalletConstantMetadata { name: "SomeExtraRename", ty: meta_type::(), value: vec![0, 0, 0, 0, 0, 0, 0, 0], - docs: vec![" Some doc"], + docs: maybe_docs(vec![" Some doc"]), }, ], error: Some(PalletErrorMetadata { ty: meta_type::>() }), @@ -1351,7 +1359,7 @@ fn metadata() { modifier: StorageEntryModifier::Default, ty: StorageEntryType::Plain(meta_type::()), default: vec![0, 0, 0, 0], - docs: vec!["Counter for the related counted storage map"], + docs: maybe_docs(vec!["Counter for the related counted storage map"]), }, ], }), @@ -1362,6 +1370,16 @@ fn metadata() { }, ]; + let empty_doc = pallets[0].event.as_ref().unwrap().ty.type_info().docs().is_empty() && + pallets[0].error.as_ref().unwrap().ty.type_info().docs().is_empty() && + pallets[0].calls.as_ref().unwrap().ty.type_info().docs().is_empty(); + + if cfg!(feature = "no-metadata-docs") { + assert!(empty_doc) + } else { + assert!(!empty_doc) + } + let extrinsic = ExtrinsicMetadata { ty: meta_type::(), version: 4, diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index dc76f1fcbf036..339a8b6b09248 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -15,6 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Old macros don't support the flag `no-metadata-docs` so the result differs when the feature is +// activated. +#![cfg(not(feature = "no-metadata-docs"))] + use frame_support::traits::{ConstU32, ConstU64}; pub trait SomeAssociation { diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 80ab3c2267fdc..4fe577f520fa3 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -15,6 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Old macros don't support the flag `no-metadata-docs` so the result differs when the feature is +// activated. +#![cfg(not(feature = "no-metadata-docs"))] + use frame_support::traits::{ConstU32, ConstU64}; mod pallet_old { From 7e87c08b71ce2247b504fb2ea7d1f979f98705a2 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Mon, 17 Jan 2022 19:06:25 -0800 Subject: [PATCH 0436/1472] Migration for over locked accounts in phgragmen elections (#10649) * use free balance rather than total balance * Docs * Migration for over-locked phrag voters * New line * comment * Update frame/elections-phragmen/src/migrations/v5.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Only set lock, don't remove it * delete commented out * docs * Update migration to just take a set of accounts Co-authored-by: Shawn Tabrizi Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- .../elections-phragmen/src/migrations/mod.rs | 2 + frame/elections-phragmen/src/migrations/v5.rs | 70 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 frame/elections-phragmen/src/migrations/v5.rs diff --git a/frame/elections-phragmen/src/migrations/mod.rs b/frame/elections-phragmen/src/migrations/mod.rs index e7f6429f2298a..7c62e8fa93067 100644 --- a/frame/elections-phragmen/src/migrations/mod.rs +++ b/frame/elections-phragmen/src/migrations/mod.rs @@ -21,3 +21,5 @@ pub mod v3; /// Version 4. pub mod v4; +/// Version 5. +pub mod v5; diff --git a/frame/elections-phragmen/src/migrations/v5.rs b/frame/elections-phragmen/src/migrations/v5.rs new file mode 100644 index 0000000000000..1898668cd07b3 --- /dev/null +++ b/frame/elections-phragmen/src/migrations/v5.rs @@ -0,0 +1,70 @@ +use super::super::*; + +/// Migrate the locks and vote stake on accounts (as specified with param `to_migrate`) that have +/// more than their free balance locked. +/// +/// This migration addresses a bug were a voter could lock up to their reserved balance + free +/// balance. Since locks are only designed to operate on free balance, this put those affected in a +/// situation where they could increase their free balance but still not be able to use their funds +/// because they were less than the lock. +pub fn migrate(to_migrate: Vec) -> Weight { + let mut weight = 0; + + for who in to_migrate.iter() { + if let Ok(mut voter) = Voting::::try_get(who) { + let free_balance = T::Currency::free_balance(&who); + + weight = weight.saturating_add(T::DbWeight::get().reads(2)); + + if voter.stake > free_balance { + voter.stake = free_balance; + Voting::::insert(&who, voter); + + let pallet_id = T::PalletId::get(); + T::Currency::set_lock(pallet_id, &who, free_balance, WithdrawReasons::all()); + + weight = weight.saturating_add(T::DbWeight::get().writes(2)); + } + } + } + + weight +} + +/// Given the list of voters to migrate return a function that does some checks and information +/// prior to migration. This can be linked to [`frame_support::traits::OnRuntimeUpgrade:: +/// pre_upgrade`] for further testing. +pub fn pre_migrate_fn(to_migrate: Vec) -> Box ()> { + Box::new(move || { + for who in to_migrate.iter() { + if let Ok(voter) = Voting::::try_get(who) { + let free_balance = T::Currency::free_balance(&who); + + if voter.stake > free_balance { + // all good + } else { + log::warn!("pre-migrate elections-phragmen: voter={:?} has less stake then free balance", who); + } + } else { + log::warn!("pre-migrate elections-phragmen: cannot find voter={:?}", who); + } + } + log::info!("pre-migrate elections-phragmen complete"); + }) +} + +/// Some checks for after migration. This can be linked to +/// [`frame_support::traits::OnRuntimeUpgrade::post_upgrade`] for further testing. +/// +/// Panics if anything goes wrong. +pub fn post_migrate() { + for (who, voter) in Voting::::iter() { + let free_balance = T::Currency::free_balance(&who); + + assert!(voter.stake <= free_balance, "migration should have made locked <= free_balance"); + // Ideally we would also check that the locks and AccountData.misc_frozen where correctly + // updated, but since both of those are generic we can't do that without further bounding T. + } + + log::info!("post-migrate elections-phragmen complete"); +} From 787bb8711a031bb5a38a9deb82416d8ed14d69a0 Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Tue, 18 Jan 2022 09:18:52 +0100 Subject: [PATCH 0437/1472] bench/cli: extend --extrinsic name filtering (#10677) * implement benchmarking multiple extrinsics * ran cargo +nightly fmt * remove contains check and made it an equals check --- utils/frame/benchmarking-cli/src/command.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utils/frame/benchmarking-cli/src/command.rs b/utils/frame/benchmarking-cli/src/command.rs index 368b5ce59c952..a5046dbaad2ac 100644 --- a/utils/frame/benchmarking-cli/src/command.rs +++ b/utils/frame/benchmarking-cli/src/command.rs @@ -120,7 +120,8 @@ impl BenchmarkCmd { let pallet = self.pallet.clone().unwrap_or_else(|| String::new()); let pallet = pallet.as_bytes(); let extrinsic = self.extrinsic.clone().unwrap_or_else(|| String::new()); - let extrinsic = extrinsic.as_bytes(); + let extrinsic_split: Vec<&str> = extrinsic.split(',').collect(); + let extrinsics: Vec<_> = extrinsic_split.iter().map(|x| x.trim().as_bytes()).collect(); let genesis_storage = spec.build_storage()?; let mut changes = Default::default(); @@ -176,7 +177,10 @@ impl BenchmarkCmd { .filter(|item| pallet.is_empty() || pallet == &b"*"[..] || pallet == &item.pallet[..]) .for_each(|item| { for benchmark in &item.benchmarks { - if extrinsic.is_empty() || extrinsic == &b"*"[..] || extrinsic == benchmark.name + let benchmark_name = &benchmark.name; + if extrinsic.is_empty() || + extrinsic.as_bytes() == &b"*"[..] || + extrinsics.contains(&&benchmark_name[..]) { benchmarks_to_run.push(( item.pallet.clone(), From 4cd2cc958f5a078d87e4eae877167c40cf2ebf9e Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Tue, 18 Jan 2022 20:05:12 +0100 Subject: [PATCH 0438/1472] Minor syntax and typo edits (#10693) --- client/transaction-pool/README.md | 59 ++++++++++++++++--------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/client/transaction-pool/README.md b/client/transaction-pool/README.md index e4f8ccb3d8105..4a2bbb8838f9c 100644 --- a/client/transaction-pool/README.md +++ b/client/transaction-pool/README.md @@ -39,7 +39,7 @@ runtime (queried at current best imported block). Since the blockchain is not always linear, forks need to be correctly handled by the transaction pool as well. In case of a fork, some blocks are *retracted* from the canonical chain, and some other blocks get *enacted* on top of some -common ancestor. The transactions from retrated blocks could simply be discarded, +common ancestor. The transactions from retracted blocks could simply be discarded, but it's desirable to make sure they are still considered for inclusion in case they are deemed valid by the runtime state at best, recently enacted block (fork the chain re-organized to). @@ -49,7 +49,7 @@ pool, it's broadcasting status, block inclusion, finality, etc. ## Transaction Validity details -Information retrieved from the the runtime are encapsulated in `TransactionValidity` +Information retrieved from the the runtime are encapsulated in the `TransactionValidity` type. ```rust @@ -147,7 +147,7 @@ choosing the ones with highest priority to include to the next block first. - `priority` of transaction may change over time - on-chain conditions may affect `priority` -- Given two transactions with overlapping `provides` tags, the one with higher +- given two transactions with overlapping `provides` tags, the one with higher `priority` should be preferred. However we can also look at the total priority of a subtree rooted at that transaction and compare that instead (i.e. even though the transaction itself has lower `priority` it "unlocks" other high priority transactions). @@ -163,7 +163,7 @@ the transaction is valid all that time though. - `longevity` of transaction may change over time - on-chain conditions may affect `longevity` -- After `longevity` lapses the transaction may still be valid +- after `longevity` lapses, the transaction may still be valid ### `propagate` @@ -231,15 +231,16 @@ to instead of gossiping everyting have other peers request transactions they are interested in. Since the pool is expected to store more transactions than what can fit -to a single block. Validating the entire pool on every block might not be -feasible, so the actual implementation might need to take some shortcuts. +in a single block, validating the entire pool on every block might not be +feasible. This means that the actual implementation might need to take some +shortcuts. ## Suggestions & caveats -1. The validity of transaction should not change significantly from block to +1. The validity of a transaction should not change significantly from block to block. I.e. changes in validity should happen predictably, e.g. `longevity` decrements by 1, `priority` stays the same, `requires` changes if transaction - that provided a tag was included in block. `provides` does not change, etc. + that provided a tag was included in block, `provides` does not change, etc. 1. That means we don't have to revalidate every transaction after every block import, but we need to take care of removing potentially stale transactions. @@ -253,9 +254,9 @@ feasible, so the actual implementation might need to take some shortcuts. 1. In the past there were many issues found when running small networks with a lot of re-orgs. Make sure that transactions are never lost. -1. UTXO model is quite challenging. The transaction becomes valid right after - it's included in block, however it is waiting for exactly the same inputs to - be spent, so it will never really be included again. +1. The UTXO model is quite challenging. A transaction becomes valid right after + it's included in a block, however it is waiting for exactly the same inputs + to be spent, so it will never really be included again. 1. Note that in a non-ideal implementation the state of the pool will most likely always be a bit off, i.e. some transactions might be still in the pool, @@ -277,8 +278,8 @@ feasible, so the actual implementation might need to take some shortcuts. 1. We periodically validate all transactions in the pool in batches. -1. To minimize runtime calls, we introduce batch-verify call. Note it should reset - the state (overlay) after every verification. +1. To minimize runtime calls, we introduce the batch-verify call. Note it should + reset the state (overlay) after every verification. 1. Consider leveraging finality. Maybe we could verify against latest finalised block instead. With this the pool in different nodes can be more similar @@ -286,16 +287,16 @@ feasible, so the actual implementation might need to take some shortcuts. is not a strict requirement for a Substrate chain to have though. 1. Perhaps we could avoid maintaining ready/future queues as currently, but - rather if transaction doesn't have all requirements satisfied by existing + rather if a transaction doesn't have all requirements satisfied by existing transactions we attempt to re-import it in the future. 1. Instead of maintaining a full pool with total ordering we attempt to maintain a set of next (couple of) blocks. We could introduce batch-validate runtime - api method that pretty much attempts to simulate actual block inclusion of + api method that pretty much attempts to simulate actual block inclusion of a set of such transactions (without necessarily fully running/dispatching them). Importing a transaction would consist of figuring out which next block - this transaction have a chance to be included in and then attempting to - either push it back or replace some of existing transactions. + this transaction has a chance to be included in and then attempting to + either push it back or replace some existing transactions. 1. Perhaps we could use some immutable graph structure to easily add/remove transactions. We need some traversal method that takes priority and @@ -320,7 +321,7 @@ The pool consists of basically two independent parts: The pool is split into `ready` pool and `future` pool. The latter contains transactions that don't have their requirements satisfied, and the former holds transactions that can be used to build a graph of dependencies. Note that the -graph is build ad-hoc during the traversal process (getting the `ready` +graph is built ad-hoc during the traversal process (using the `ready` iterator). This makes the importing process cheaper (we don't need to find the exact position in the queue or graph), but traversal process slower (logarithmic). However most of the time we will only need the beginning of the @@ -342,26 +343,26 @@ to limit number of runtime verification calls. Each time a transaction is imported, we first verify it's validity and later find if the tags it `requires` can be satisfied by transactions already in `ready` pool. In case the transaction is imported to the `ready` pool we -additionally *promote* transactions from `future` pool if the transaction +additionally *promote* transactions from the `future` pool if the transaction happened to fulfill their requirements. -Note we need to cater for cases where transaction might replace a already +Note we need to cater for cases where a transaction might replace an already existing transaction in the pool. In such case we check the entire sub-tree of transactions that we are about to replace, compare their cumulative priority to determine which subtree to keep. -After a block is imported we kick-off pruning procedure. We first attempt to -figure out what tags were satisfied by transaction in that block. For each block -transaction we either call into runtime to get it's `ValidTransaction` object, +After a block is imported we kick-off the pruning procedure. We first attempt to +figure out what tags were satisfied by a transaction in that block. For each block +transaction we either call into the runtime to get it's `ValidTransaction` object, or we check the pool if that transaction is already known to spare the runtime -call. From this we gather full set of `provides` tags and perform pruning of -`ready` pool based on that. Also we promote all transactions from `future` that -have their tags satisfied. +call. From this we gather the full set of `provides` tags and perform pruning of +the `ready` pool based on that. Also, we promote all transactions from `future` +that have their tags satisfied. In case we remove transactions that we are unsure if they were already included -in current block or some block in the past, it is being added to revalidation -queue and attempted to be re-imported by the background task in the future. +in the current block or some block in the past, it gets added to the revalidation +queue and attempts to be re-imported by the background task in the future. Runtime calls to verify transactions are performed from a separate (limited) -thread pool to avoid interferring too much with other subsystems of the node. We +thread pool to avoid interfering too much with other subsystems of the node. We definitely don't want to have all cores validating network transactions, because all of these transactions need to be considered untrusted (potentially DoS). From 104c2cd917b84cf3499c14a4ffa5fee8d8c5c7b5 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 19 Jan 2022 11:58:40 +0100 Subject: [PATCH 0439/1472] Split peer slots between full and light nodes (#10688) * Split peer slots between full and light nodes * Rustfmt * Oops, accidentally removed a comma * Remove else --- client/cli/src/params/network_params.rs | 8 +++++-- client/network/src/config.rs | 9 +++++++- client/network/src/protocol.rs | 29 ++++++++++++++++++++++++- client/network/src/protocol/sync.rs | 5 +++++ client/service/src/builder.rs | 3 +-- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 6b7b2680513c3..86060486144ac 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -86,9 +86,12 @@ pub struct NetworkParams { #[structopt(long = "out-peers", value_name = "COUNT", default_value = "25")] pub out_peers: u32, - /// Specify the maximum number of incoming connections we're accepting. + /// Maximum number of inbound full nodes peers. #[structopt(long = "in-peers", value_name = "COUNT", default_value = "25")] pub in_peers: u32, + /// Maximum number of inbound light nodes peers. + #[structopt(long = "in-peers-light", value_name = "COUNT", default_value = "100")] + pub in_peers_light: u32, /// Disable mDNS discovery. /// @@ -203,7 +206,7 @@ impl NetworkParams { boot_nodes, net_config_path, default_peers_set: SetConfig { - in_peers: self.in_peers, + in_peers: self.in_peers + self.in_peers_light, out_peers: self.out_peers, reserved_nodes: self.reserved_nodes.clone(), non_reserved_mode: if self.reserved_only { @@ -212,6 +215,7 @@ impl NetworkParams { NonReservedPeerMode::Accept }, }, + default_peers_set_num_full: self.in_peers + self.out_peers, listen_addresses, public_addresses, extra_sets: Vec::new(), diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 14411ef2aa18a..3b9c864c37927 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -416,6 +416,11 @@ pub struct NetworkConfiguration { pub request_response_protocols: Vec, /// Configuration for the default set of nodes used for block syncing and transactions. pub default_peers_set: SetConfig, + /// Number of substreams to reserve for full nodes for block syncing and transactions. + /// Any other slot will be dedicated to light nodes. + /// + /// This value is implicitly capped to `default_set.out_peers + default_set.in_peers`. + pub default_peers_set_num_full: u32, /// Configuration for extra sets of nodes. pub extra_sets: Vec, /// Client identifier. Sent over the wire for debugging purposes. @@ -473,6 +478,7 @@ impl NetworkConfiguration { node_key: NodeKeyConfig, net_config_path: Option, ) -> Self { + let default_peers_set = SetConfig::default(); Self { net_config_path, listen_addresses: Vec::new(), @@ -480,7 +486,8 @@ impl NetworkConfiguration { boot_nodes: Vec::new(), node_key, request_response_protocols: Vec::new(), - default_peers_set: Default::default(), + default_peers_set_num_full: default_peers_set.in_peers + default_peers_set.out_peers, + default_peers_set, extra_sets: Vec::new(), client_version: client_version.into(), node_name: node_name.into(), diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index a5a826ed4748c..3fb40b7199d68 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -166,13 +166,19 @@ pub struct Protocol { pending_messages: VecDeque>, config: ProtocolConfig, genesis_hash: B::Hash, + /// State machine that handles the list of in-progress requests. Only full node peers are + /// registered. sync: ChainSync, - // All connected peers + // All connected peers. Contains both full and light node peers. peers: HashMap>, chain: Arc>, /// List of nodes for which we perform additional logging because they are important for the /// user. important_peers: HashSet, + /// Value that was passed as part of the configuration. Used to cap the number of full nodes. + default_peers_set_num_full: usize, + /// Number of slots to allocate to light nodes. + default_peers_set_num_light: usize, /// Used to report reputation changes. peerset_handle: sc_peerset::PeersetHandle, /// Handles opening the unique substream and sending and receiving raw messages. @@ -428,6 +434,12 @@ impl Protocol { genesis_hash: info.genesis_hash, sync, important_peers, + default_peers_set_num_full: network_config.default_peers_set_num_full as usize, + default_peers_set_num_light: { + let total = network_config.default_peers_set.out_peers + + network_config.default_peers_set.in_peers; + total.saturating_sub(network_config.default_peers_set_num_full) as usize + }, peerset_handle: peerset_handle.clone(), behaviour, notification_protocols: network_config @@ -808,6 +820,21 @@ impl Protocol { } } + if status.roles.is_full() && self.sync.num_peers() >= self.default_peers_set_num_full { + debug!(target: "sync", "Too many full nodes, rejecting {}", who); + self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); + return Err(()) + } + + if status.roles.is_light() && + (self.peers.len() - self.sync.num_peers()) < self.default_peers_set_num_light + { + // Make sure that not all slots are occupied by light clients. + debug!(target: "sync", "Too many light nodes, rejecting {}", who); + self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); + return Err(()) + } + let peer = Peer { info: PeerInfo { roles: status.roles, diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index af65dec1c3fe9..d6513ca2e5b9d 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -648,6 +648,11 @@ impl ChainSync { self.downloaded_blocks } + /// Returns the current number of peers stored within this state machine. + pub fn num_peers(&self) -> usize { + self.peers.len() + } + /// Handle a new connected peer. /// /// Call this method whenever we connect to a new peer. diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 269b7be720be0..bf681aec94c7d 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -808,8 +808,7 @@ where let (handler, protocol_config) = StateRequestHandler::new( &protocol_id, client.clone(), - config.network.default_peers_set.in_peers as usize + - config.network.default_peers_set.out_peers as usize, + config.network.default_peers_set_num_full as usize, ); spawn_handle.spawn("state-request-handler", Some("networking"), handler.run()); protocol_config From fed456fbd73253686f965f4d426776037420637e Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 19 Jan 2022 15:08:53 +0100 Subject: [PATCH 0440/1472] Allow the treasury to have a maximum bound on the bond (#10689) * Allow the treasury to have a maximum bound on the bond * Update frame/treasury/src/lib.rs Co-authored-by: Keith Yeung Co-authored-by: Keith Yeung --- bin/node/runtime/src/lib.rs | 1 + docs/Upgrading-2.0-to-3.0.md | 1 + frame/bounties/src/tests.rs | 1 + frame/child-bounties/src/tests.rs | 1 + frame/tips/src/tests.rs | 1 + frame/treasury/src/lib.rs | 10 +++++++++- frame/treasury/src/tests.rs | 1 + 7 files changed, 15 insertions(+), 1 deletion(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index b2c98e6be139d..1f0a33756fe85 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -880,6 +880,7 @@ impl pallet_treasury::Config for Runtime { type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ProposalBondMinimum; + type ProposalBondMaximum = (); type SpendPeriod = SpendPeriod; type Burn = Burn; type BurnDestination = (); diff --git a/docs/Upgrading-2.0-to-3.0.md b/docs/Upgrading-2.0-to-3.0.md index 45da3811220f4..017467ede2d7e 100644 --- a/docs/Upgrading-2.0-to-3.0.md +++ b/docs/Upgrading-2.0-to-3.0.md @@ -199,6 +199,7 @@ As mentioned above, Bounties, Tips and Lottery have been extracted out of treasu type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ProposalBondMinimum; + type ProposalBondMaximum = (); type SpendPeriod = SpendPeriod; type Burn = Burn; + type BurnDestination = (); diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index 912a78c97570f..3206fce9912fa 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -117,6 +117,7 @@ impl pallet_treasury::Config for Test { type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; + type ProposalBondMaximum = (); type SpendPeriod = ConstU64<2>; type Burn = Burn; type BurnDestination = (); // Just gets burned. diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index 4b713e699f4d8..a6748c47b73d8 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -121,6 +121,7 @@ impl pallet_treasury::Config for Test { type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; + type ProposalBondMaximum = (); type SpendPeriod = ConstU64<2>; type Burn = Burn; type BurnDestination = (); diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index f9ad431c39480..0c58a949958fe 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -137,6 +137,7 @@ impl pallet_treasury::Config for Test { type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; + type ProposalBondMaximum = (); type SpendPeriod = ConstU64<2>; type Burn = Burn; type BurnDestination = (); // Just gets burned. diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 057ee0c6032a4..c2dd59953be33 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -168,6 +168,10 @@ pub mod pallet { #[pallet::constant] type ProposalBondMinimum: Get>; + /// Maximum amount of funds that should be placed in a deposit for making a proposal. + #[pallet::constant] + type ProposalBondMaximum: Get>>; + /// Period between successive spends. #[pallet::constant] type SpendPeriod: Get; @@ -404,7 +408,11 @@ impl, I: 'static> Pallet { /// The needed bond for a proposal whose spend is `value`. fn calculate_bond(value: BalanceOf) -> BalanceOf { - T::ProposalBondMinimum::get().max(T::ProposalBond::get() * value) + let mut r = T::ProposalBondMinimum::get().max(T::ProposalBond::get() * value); + if let Some(m) = T::ProposalBondMaximum::get() { + r = r.min(m); + } + r } /// Spend some money! returns number of approvals before spend. diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index b6d23440a73fe..26189f5201498 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -115,6 +115,7 @@ impl Config for Test { type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; + type ProposalBondMaximum = (); type SpendPeriod = ConstU64<2>; type Burn = Burn; type BurnDestination = (); // Just gets burned. From bea8f32e7807233ab53045fe8214427e0f136230 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 19 Jan 2022 16:31:14 +0100 Subject: [PATCH 0441/1472] Improve usability of `add`+`list_benchmark!` (#10592) * Improve usability of add_benchmark and list_benchmark. Signed-off-by: Oliver Tale-Yazdi * node-template: use new define_benchmarks syntax Signed-off-by: Oliver Tale-Yazdi * make CI happy Signed-off-by: Oliver Tale-Yazdi * remove old imports Signed-off-by: Oliver Tale-Yazdi * fix TryBuild tests Signed-off-by: Oliver Tale-Yazdi * Revert "fix TryBuild tests" This reverts commit 82ea52fd25c0ef5efa46669217694835a7404d4e. * review: remove blank lines Signed-off-by: Oliver Tale-Yazdi --- bin/node-template/runtime/src/lib.rs | 33 ++++--- bin/node/runtime/src/lib.rs | 123 +++++++++++---------------- frame/benchmarking/src/lib.rs | 67 ++++++++++++++- 3 files changed, 133 insertions(+), 90 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 08c6c8fb8bcba..2aa6bf1f1ae71 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -318,6 +318,21 @@ pub type Executive = frame_executive::Executive< AllPalletsWithSystem, >; +#[cfg(feature = "runtime-benchmarks")] +#[macro_use] +extern crate frame_benchmarking; + +#[cfg(feature = "runtime-benchmarks")] +mod benches { + define_benchmarks!( + [frame_benchmarking, BaselineBench::] + [frame_system, SystemBench::] + [pallet_balances, Balances] + [pallet_timestamp, Timestamp] + [pallet_template, TemplateModule] + ); +} + impl_runtime_apis! { impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { @@ -455,18 +470,13 @@ impl_runtime_apis! { Vec, Vec, ) { - use frame_benchmarking::{list_benchmark, baseline, Benchmarking, BenchmarkList}; + use frame_benchmarking::{baseline, Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use baseline::Pallet as BaselineBench; let mut list = Vec::::new(); - - list_benchmark!(list, extra, frame_benchmarking, BaselineBench::); - list_benchmark!(list, extra, frame_system, SystemBench::); - list_benchmark!(list, extra, pallet_balances, Balances); - list_benchmark!(list, extra, pallet_timestamp, Timestamp); - list_benchmark!(list, extra, pallet_template, TemplateModule); + list_benchmarks!(list, extra); let storage_info = AllPalletsWithSystem::storage_info(); @@ -476,7 +486,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig ) -> Result, sp_runtime::RuntimeString> { - use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; + use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, TrackedStorageKey}; use frame_system_benchmarking::Pallet as SystemBench; use baseline::Pallet as BaselineBench; @@ -499,12 +509,7 @@ impl_runtime_apis! { let mut batches = Vec::::new(); let params = (&config, &whitelist); - - add_benchmark!(params, batches, frame_benchmarking, BaselineBench::); - add_benchmark!(params, batches, frame_system, SystemBench::); - add_benchmark!(params, batches, pallet_balances, Balances); - add_benchmark!(params, batches, pallet_timestamp, Timestamp); - add_benchmark!(params, batches, pallet_template, TemplateModule); + add_benchmarks!(params, batches); Ok(batches) } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1f0a33756fe85..6034b86987ffb 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1386,6 +1386,51 @@ mod mmr { pub type Hashing = ::Hashing; } +#[cfg(feature = "runtime-benchmarks")] +#[macro_use] +extern crate frame_benchmarking; + +#[cfg(feature = "runtime-benchmarks")] +mod benches { + define_benchmarks!( + [frame_benchmarking, BaselineBench::] + [pallet_assets, Assets] + [pallet_babe, Babe] + [pallet_bags_list, BagsList] + [pallet_balances, Balances] + [pallet_bounties, Bounties] + [pallet_child_bounties, ChildBounties] + [pallet_collective, Council] + [pallet_contracts, Contracts] + [pallet_democracy, Democracy] + [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] + [pallet_elections_phragmen, Elections] + [pallet_gilt, Gilt] + [pallet_grandpa, Grandpa] + [pallet_identity, Identity] + [pallet_im_online, ImOnline] + [pallet_indices, Indices] + [pallet_lottery, Lottery] + [pallet_membership, TechnicalMembership] + [pallet_mmr, Mmr] + [pallet_multisig, Multisig] + [pallet_offences, OffencesBench::] + [pallet_preimage, Preimage] + [pallet_proxy, Proxy] + [pallet_scheduler, Scheduler] + [pallet_session, SessionBench::] + [pallet_staking, Staking] + [frame_system, SystemBench::] + [pallet_timestamp, Timestamp] + [pallet_tips, Tips] + [pallet_transaction_storage, TransactionStorage] + [pallet_treasury, Treasury] + [pallet_uniques, Uniques] + [pallet_utility, Utility] + [pallet_vesting, Vesting] + ); +} + impl_runtime_apis! { impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { @@ -1664,7 +1709,7 @@ impl_runtime_apis! { Vec, Vec, ) { - use frame_benchmarking::{list_benchmark, baseline, Benchmarking, BenchmarkList}; + use frame_benchmarking::{baseline, Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; // Trying to add benchmarks directly to the Session Pallet caused cyclic dependency @@ -1676,42 +1721,7 @@ impl_runtime_apis! { use baseline::Pallet as BaselineBench; let mut list = Vec::::new(); - - list_benchmark!(list, extra, frame_benchmarking, BaselineBench::); - list_benchmark!(list, extra, pallet_assets, Assets); - list_benchmark!(list, extra, pallet_babe, Babe); - list_benchmark!(list, extra, pallet_bags_list, BagsList); - list_benchmark!(list, extra, pallet_balances, Balances); - list_benchmark!(list, extra, pallet_bounties, Bounties); - list_benchmark!(list, extra, pallet_child_bounties, ChildBounties); - list_benchmark!(list, extra, pallet_collective, Council); - list_benchmark!(list, extra, pallet_contracts, Contracts); - list_benchmark!(list, extra, pallet_democracy, Democracy); - list_benchmark!(list, extra, pallet_election_provider_multi_phase, ElectionProviderMultiPhase); - list_benchmark!(list, extra, pallet_elections_phragmen, Elections); - list_benchmark!(list, extra, pallet_gilt, Gilt); - list_benchmark!(list, extra, pallet_grandpa, Grandpa); - list_benchmark!(list, extra, pallet_identity, Identity); - list_benchmark!(list, extra, pallet_im_online, ImOnline); - list_benchmark!(list, extra, pallet_indices, Indices); - list_benchmark!(list, extra, pallet_lottery, Lottery); - list_benchmark!(list, extra, pallet_membership, TechnicalMembership); - list_benchmark!(list, extra, pallet_mmr, Mmr); - list_benchmark!(list, extra, pallet_multisig, Multisig); - list_benchmark!(list, extra, pallet_offences, OffencesBench::); - list_benchmark!(list, extra, pallet_preimage, Preimage); - list_benchmark!(list, extra, pallet_proxy, Proxy); - list_benchmark!(list, extra, pallet_scheduler, Scheduler); - list_benchmark!(list, extra, pallet_session, SessionBench::); - list_benchmark!(list, extra, pallet_staking, Staking); - list_benchmark!(list, extra, frame_system, SystemBench::); - list_benchmark!(list, extra, pallet_timestamp, Timestamp); - list_benchmark!(list, extra, pallet_tips, Tips); - list_benchmark!(list, extra, pallet_transaction_storage, TransactionStorage); - list_benchmark!(list, extra, pallet_treasury, Treasury); - list_benchmark!(list, extra, pallet_uniques, Uniques); - list_benchmark!(list, extra, pallet_utility, Utility); - list_benchmark!(list, extra, pallet_vesting, Vesting); + list_benchmarks!(list, extra); let storage_info = AllPalletsWithSystem::storage_info(); @@ -1721,7 +1731,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig ) -> Result, sp_runtime::RuntimeString> { - use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; + use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, TrackedStorageKey}; // Trying to add benchmarks directly to the Session Pallet caused cyclic dependency // issues. To get around that, we separated the Session benchmarks into its own crate, @@ -1755,42 +1765,7 @@ impl_runtime_apis! { let mut batches = Vec::::new(); let params = (&config, &whitelist); - - add_benchmark!(params, batches, frame_benchmarking, BaselineBench::); - add_benchmark!(params, batches, pallet_assets, Assets); - add_benchmark!(params, batches, pallet_babe, Babe); - add_benchmark!(params, batches, pallet_balances, Balances); - add_benchmark!(params, batches, pallet_bags_list, BagsList); - add_benchmark!(params, batches, pallet_bounties, Bounties); - add_benchmark!(params, batches, pallet_child_bounties, ChildBounties); - add_benchmark!(params, batches, pallet_collective, Council); - add_benchmark!(params, batches, pallet_contracts, Contracts); - add_benchmark!(params, batches, pallet_democracy, Democracy); - add_benchmark!(params, batches, pallet_election_provider_multi_phase, ElectionProviderMultiPhase); - add_benchmark!(params, batches, pallet_elections_phragmen, Elections); - add_benchmark!(params, batches, pallet_gilt, Gilt); - add_benchmark!(params, batches, pallet_grandpa, Grandpa); - add_benchmark!(params, batches, pallet_identity, Identity); - add_benchmark!(params, batches, pallet_im_online, ImOnline); - add_benchmark!(params, batches, pallet_indices, Indices); - add_benchmark!(params, batches, pallet_lottery, Lottery); - add_benchmark!(params, batches, pallet_membership, TechnicalMembership); - add_benchmark!(params, batches, pallet_mmr, Mmr); - add_benchmark!(params, batches, pallet_multisig, Multisig); - add_benchmark!(params, batches, pallet_offences, OffencesBench::); - add_benchmark!(params, batches, pallet_preimage, Preimage); - add_benchmark!(params, batches, pallet_proxy, Proxy); - add_benchmark!(params, batches, pallet_scheduler, Scheduler); - add_benchmark!(params, batches, pallet_session, SessionBench::); - add_benchmark!(params, batches, pallet_staking, Staking); - add_benchmark!(params, batches, frame_system, SystemBench::); - add_benchmark!(params, batches, pallet_timestamp, Timestamp); - add_benchmark!(params, batches, pallet_tips, Tips); - add_benchmark!(params, batches, pallet_transaction_storage, TransactionStorage); - add_benchmark!(params, batches, pallet_treasury, Treasury); - add_benchmark!(params, batches, pallet_uniques, Uniques); - add_benchmark!(params, batches, pallet_utility, Utility); - add_benchmark!(params, batches, pallet_vesting, Vesting); + add_benchmarks!(params, batches); Ok(batches) } diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index fcc3913cee78c..ca836e431e5ee 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -1701,7 +1701,6 @@ pub fn show_benchmark_debug_info( /// type Council2 = TechnicalCommittee; /// add_benchmark!(params, batches, pallet_collective, Council2); // pallet_collective_council_2.rs /// ``` - #[macro_export] macro_rules! add_benchmark { ( $params:ident, $batches:ident, $name:path, $( $location:tt )* ) => ( @@ -1770,6 +1769,20 @@ macro_rules! add_benchmark { ) } +/// Callback for `define_benchmarks` to call `add_benchmark`. +#[macro_export] +macro_rules! cb_add_benchmarks { + // anchor + ( $params:ident, $batches:ident, [ $name:path, $( $location:tt )* ] ) => { + add_benchmark!( $params, $batches, $name, $( $location )* ); + }; + // recursion tail + ( $params:ident, $batches:ident, [ $name:path, $( $location:tt )* ] $([ $names:path, $( $locations:tt )* ])+ ) => { + cb_add_benchmarks!( $params, $batches, [ $name, $( $location )* ] ); + cb_add_benchmarks!( $params, $batches, $([ $names, $( $locations )* ])+ ); + } +} + /// This macro allows users to easily generate a list of benchmarks for the pallets configured /// in the runtime. /// @@ -1789,7 +1802,6 @@ macro_rules! add_benchmark { /// ``` /// /// This should match what exists with the `add_benchmark!` macro. - #[macro_export] macro_rules! list_benchmark { ( $list:ident, $extra:ident, $name:path, $( $location:tt )* ) => ( @@ -1804,3 +1816,54 @@ macro_rules! list_benchmark { $list.push(pallet_benchmarks) ) } + +/// Callback for `define_benchmarks` to call `list_benchmark`. +#[macro_export] +macro_rules! cb_list_benchmarks { + // anchor + ( $list:ident, $extra:ident, [ $name:path, $( $location:tt )* ] ) => { + list_benchmark!( $list, $extra, $name, $( $location )* ); + }; + // recursion tail + ( $list:ident, $extra:ident, [ $name:path, $( $location:tt )* ] $([ $names:path, $( $locations:tt )* ])+ ) => { + cb_list_benchmarks!( $list, $extra, [ $name, $( $location )* ] ); + cb_list_benchmarks!( $list, $extra, $([ $names, $( $locations )* ])+ ); + } +} + +/// Defines pallet configs that `add_benchmarks` and `list_benchmarks` use. +/// Should be preferred instead of having a repetitive list of configs +/// in `add_benchmark` and `list_benchmark`. + +#[macro_export] +macro_rules! define_benchmarks { + ( $([ $names:path, $( $locations:tt )* ])* ) => { + /// Calls `list_benchmark` with all configs from `define_benchmarks` + /// and passes the first two parameters on. + /// + /// Use as: + /// ```ignore + /// list_benchmarks!(list, extra); + /// ``` + #[macro_export] + macro_rules! list_benchmarks { + ( $list:ident, $extra:ident ) => { + cb_list_benchmarks!( $list, $extra, $([ $names, $( $locations )* ])+ ); + } + } + + /// Calls `add_benchmark` with all configs from `define_benchmarks` + /// and passes the first two parameters on. + /// + /// Use as: + /// ```ignore + /// add_benchmarks!(params, batches); + /// ``` + #[macro_export] + macro_rules! add_benchmarks { + ( $params:ident, $batches:ident ) => { + cb_add_benchmarks!( $params, $batches, $([ $names, $( $locations )* ])+ ); + } + } + } +} From 33c518ebbe43d38228ac47e793e4d1c76738a56d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 19 Jan 2022 20:58:47 +0100 Subject: [PATCH 0442/1472] Remove all stale `on_runtime_upgrade` hooks in the runtime (#10650) * Remove all stale on_runtime_upgrade hooks in the runtime * add docs * cleanup * fix warn * fix more warnings * fix offence test * overwrite the damn UItest --- frame/contracts/src/lib.rs | 6 +---- frame/contracts/src/migration.rs | 1 + frame/offences/src/lib.rs | 10 +------ frame/offences/src/migration.rs | 5 ++-- frame/staking/src/pallet/mod.rs | 23 +++------------- frame/support/src/traits/hooks.rs | 9 +++++-- .../genesis_default_not_satisfied.stderr | 6 ++--- frame/uniques/src/lib.rs | 13 +++------- frame/uniques/src/migration.rs | 1 + frame/vesting/src/lib.rs | 26 ++----------------- frame/vesting/src/migrations.rs | 8 +++--- 11 files changed, 28 insertions(+), 80 deletions(-) diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 24d3a7f10ef91..36b0e12dcd7f0 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -87,12 +87,12 @@ mod gas; mod benchmarking; mod exec; -mod migration; mod schedule; mod storage; mod wasm; pub mod chain_extension; +pub mod migration; pub mod weights; #[cfg(test)] @@ -321,10 +321,6 @@ pub mod pallet { Storage::::process_deletion_queue_batch(weight_limit) .saturating_add(T::WeightInfo::on_initialize()) } - - fn on_runtime_upgrade() -> Weight { - migration::migrate::() - } } #[pallet::call] diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 29712a528a72c..59d3721ab13cf 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -25,6 +25,7 @@ use frame_support::{ }; use sp_std::{marker::PhantomData, prelude::*}; +/// Wrapper for all migrations of this pallet, based on `StorageVersion`. pub fn migrate() -> Weight { use frame_support::traits::StorageVersion; diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index 25605d934d57f..c12f0d1bcc781 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -22,7 +22,7 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -mod migration; +pub mod migration; mod mock; mod tests; @@ -47,7 +47,6 @@ type ReportIdOf = ::Hash; pub mod pallet { use super::*; use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] @@ -110,13 +109,6 @@ pub mod pallet { /// \[kind, timeslot\]. Offence { kind: Kind, timeslot: OpaqueTimeSlot }, } - - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_runtime_upgrade() -> Weight { - migration::remove_deferred_storage::() - } - } } impl> diff --git a/frame/offences/src/migration.rs b/frame/offences/src/migration.rs index 1984db0b7af3e..72c24ef7c3e5b 100644 --- a/frame/offences/src/migration.rs +++ b/frame/offences/src/migration.rs @@ -56,8 +56,7 @@ pub fn remove_deferred_storage() -> Weight { #[cfg(test)] mod test { use super::*; - use crate::mock::{new_test_ext, with_on_offence_fractions, Offences, Runtime as T}; - use frame_support::traits::OnRuntimeUpgrade; + use crate::mock::{new_test_ext, with_on_offence_fractions, Runtime as T}; use sp_runtime::Perbill; use sp_staking::offence::OffenceDetails; @@ -87,7 +86,7 @@ mod test { // when assert_eq!( - Offences::on_runtime_upgrade(), + remove_deferred_storage::(), ::DbWeight::get().reads_writes(1, 1), ); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index fc70d523ac9cd..8444034ad49d0 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -39,9 +39,9 @@ mod impls; pub use impls::*; use crate::{ - log, migrations, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, - EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, - Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, + log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints, + Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, Releases, + RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, }; @@ -660,23 +660,6 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { - fn on_runtime_upgrade() -> Weight { - if StorageVersion::::get() == Releases::V6_0_0 { - migrations::v7::migrate::() - } else { - T::DbWeight::get().reads(1) - } - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - if StorageVersion::::get() == Releases::V6_0_0 { - migrations::v7::pre_migrate::() - } else { - Ok(()) - } - } - fn on_initialize(_now: BlockNumberFor) -> Weight { // just return the weight of the on_finalize. T::DbWeight::get().reads(1) diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index ffb8dfb821ad0..385db4e4d1ad9 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -244,10 +244,15 @@ pub trait Hooks { /// # Warning /// /// This function will be called before we initialized any runtime state, aka `on_initialize` - /// wasn't called yet. So, information like the block number and any other - /// block local data are not accessible. + /// wasn't called yet. So, information like the block number and any other block local data are + /// not accessible. /// /// Return the non-negotiable weight consumed for runtime upgrade. + /// + /// While this function can be freely implemented, using `on_runtime_upgrade` from inside the + /// pallet is discouraged and might get deprecated in the future. Alternatively, export the same + /// logic as a free-function from your pallet, and pass it to `type Executive` from the + /// top-level runtime. fn on_runtime_upgrade() -> crate::weights::Weight { 0 } diff --git a/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr b/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr index 057611367fe5f..e01f66fa3d19d 100644 --- a/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr +++ b/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `pallet::GenesisConfig: std::default::Default` is not satisfied - --> $DIR/genesis_default_not_satisfied.rs:22:18 + --> tests/pallet_ui/genesis_default_not_satisfied.rs:22:18 | 22 | impl GenesisBuild for GenesisConfig {} | ^^^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `pallet::GenesisConfig` | note: required by a bound in `GenesisBuild` - --> $DIR/hooks.rs:297:36 + --> $WORKSPACE/frame/support/src/traits/hooks.rs | -297 | pub trait GenesisBuild: Default + sp_runtime::traits::MaybeSerializeDeserialize { + | pub trait GenesisBuild: Default + sp_runtime::traits::MaybeSerializeDeserialize { | ^^^^^^^ required by this bound in `GenesisBuild` diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 33a8866019cf4..dde30920b227a 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -33,14 +33,13 @@ mod benchmarking; pub mod mock; #[cfg(test)] mod tests; -pub mod weights; mod functions; mod impl_nonfungibles; mod types; -pub use types::*; -mod migration; +pub mod migration; +pub mod weights; use codec::{Decode, Encode, HasCompact}; use frame_support::traits::{BalanceStatus::Reserved, Currency, ReservableCurrency}; @@ -52,6 +51,7 @@ use sp_runtime::{ use sp_std::prelude::*; pub use pallet::*; +pub use types::*; pub use weights::WeightInfo; #[frame_support::pallet] @@ -316,13 +316,6 @@ pub mod pallet { Unapproved, } - #[pallet::hooks] - impl, I: 'static> Hooks> for Pallet { - fn on_runtime_upgrade() -> frame_support::weights::Weight { - migration::migrate_to_v1::() - } - } - impl, I: 'static> Pallet { /// Get the owner of the asset instance, if the asset exists. pub fn owner(class: T::ClassId, instance: T::InstanceId) -> Option { diff --git a/frame/uniques/src/migration.rs b/frame/uniques/src/migration.rs index 71ccc6b07bd72..2bacfc8f43b61 100644 --- a/frame/uniques/src/migration.rs +++ b/frame/uniques/src/migration.rs @@ -22,6 +22,7 @@ use frame_support::{ weights::Weight, }; +/// Migrate the pallet storage to v1. pub fn migrate_to_v1, I: 'static, P: GetStorageVersion + PalletInfoAccess>( ) -> frame_support::weights::Weight { let on_chain_storage_version =

for SnapshotConfig { } /// Description of the transport protocol (for online execution). -#[derive(Debug)] -pub struct Transport { - uri: String, - client: Option, +#[derive(Debug, Clone)] +pub enum Transport { + /// Use the `URI` to open a new WebSocket connection. + Uri(String), + /// Use existing WebSocket connection. + RemoteClient(Arc), } -impl Clone for Transport { - fn clone(&self) -> Self { - Self { uri: self.uri.clone(), client: None } +impl Transport { + fn as_client(&self) -> Option<&WsClient> { + match self { + Self::RemoteClient(client) => Some(&*client), + _ => None, + } + } + + // Open a new WebSocket connection if it's not connected. + async fn map_uri(&mut self) -> Result<(), &'static str> { + if let Self::Uri(uri) = self { + log::debug!(target: LOG_TARGET, "initializing remote client to {:?}", uri); + + let ws_client = WsClientBuilder::default() + .max_request_body_size(u32::MAX) + .build(&uri) + .await + .map_err(|e| { + log::error!(target: LOG_TARGET, "error: {:?}", e); + "failed to build ws client" + })?; + + *self = Self::RemoteClient(Arc::new(ws_client)) + } + + Ok(()) } } impl From for Transport { - fn from(t: String) -> Self { - Self { uri: t, client: None } + fn from(uri: String) -> Self { + Transport::Uri(uri) + } +} + +impl From> for Transport { + fn from(client: Arc) -> Self { + Transport::RemoteClient(client) } } @@ -161,8 +193,7 @@ impl OnlineConfig { /// Return rpc (ws) client. fn rpc_client(&self) -> &WsClient { self.transport - .client - .as_ref() + .as_client() .expect("ws client must have been initialized by now; qed.") } } @@ -170,7 +201,7 @@ impl OnlineConfig { impl Default for OnlineConfig { fn default() -> Self { Self { - transport: Transport { uri: DEFAULT_TARGET.to_owned(), client: None }, + transport: Transport::Uri(DEFAULT_TARGET.to_owned()), at: None, state_snapshot: None, pallets: vec![], @@ -629,19 +660,8 @@ impl Builder { } pub(crate) async fn init_remote_client(&mut self) -> Result<(), &'static str> { - let mut online = self.as_online_mut(); - log::debug!(target: LOG_TARGET, "initializing remote client to {:?}", online.transport.uri); - // First, initialize the ws client. - let ws_client = WsClientBuilder::default() - .max_request_body_size(u32::MAX) - .build(&online.transport.uri) - .await - .map_err(|e| { - log::error!(target: LOG_TARGET, "error: {:?}", e); - "failed to build ws client" - })?; - online.transport.client = Some(ws_client); + self.as_online_mut().transport.map_uri().await?; // Then, if `at` is not set, set it. if self.as_online().at.is_none() { diff --git a/utils/frame/remote-externalities/src/rpc_api.rs b/utils/frame/remote-externalities/src/rpc_api.rs index 13254741c1acb..37555de480d4c 100644 --- a/utils/frame/remote-externalities/src/rpc_api.rs +++ b/utils/frame/remote-externalities/src/rpc_api.rs @@ -19,8 +19,8 @@ // TODO: Consolidate one off RPC calls https://github.com/paritytech/substrate/issues/8988 use jsonrpsee::{ + core::client::ClientT, rpc_params, - types::traits::Client, ws_client::{WsClient, WsClientBuilder}, }; use sp_runtime::{ @@ -73,7 +73,7 @@ where Ok(signed_block.block) } -/// Build a website client that connects to `from`. +/// Build a websocket client that connects to `from`. async fn build_client>(from: S) -> Result { WsClientBuilder::default() .max_request_body_size(u32::MAX) From 13076478968818443b9bb97425b7db09e00e2fc0 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 28 Jan 2022 13:25:12 +0100 Subject: [PATCH 0468/1472] Add attributes and documentation to fork_id (#10746) * Add attributes and documentation to fork_id * Update client/chain-spec/src/chain_spec.rs Co-authored-by: Sacha Lansky Co-authored-by: Sacha Lansky --- client/chain-spec/src/chain_spec.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index a22a68d2944fa..2412a7cdf83f0 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -164,6 +164,10 @@ struct ClientSpec { boot_nodes: Vec, telemetry_endpoints: Option, protocol_id: Option, + /// Arbitrary string. Nodes will only synchronize with other nodes that have the same value + /// in their `fork_id`. This can be used in order to segregate nodes in cases when multiple + /// chains have the same genesis hash. + #[serde(default = "Default::default", skip_serializing_if = "Option::is_none")] fork_id: Option, properties: Option, #[serde(flatten)] From fb4f3ecb89ce4c3f144636a9ce9766325946dd58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Fri, 28 Jan 2022 19:37:54 +0100 Subject: [PATCH 0469/1472] Fix lazy batch contract removal (#10728) * Fix lazy batch contract removal * Apply suggestions * Qualify ChildInfo * Negligible change to restart pipeline * Revert "Negligible change to restart pipeline" This reverts commit b38abb622a17de9f0d19b3eadcea611ead1a7251. * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- frame/contracts/src/storage.rs | 6 +- frame/contracts/src/tests.rs | 53 ++ frame/contracts/src/weights.rs | 1154 ++++++++++++++++---------------- 3 files changed, 634 insertions(+), 579 deletions(-) diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index de65059b5b175..51a43a1782425 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -268,7 +268,9 @@ where let mut queue = >::get(); - if let (Some(trie), true) = (queue.get(0), remaining_key_budget > 0) { + while !queue.is_empty() && remaining_key_budget > 0 { + // Cannot panic due to loop condition + let trie = &mut queue[0]; let outcome = child::kill_storage(&child_trie_info(&trie.trie_id), Some(remaining_key_budget)); let keys_removed = match outcome { @@ -276,7 +278,7 @@ where KillStorageResult::SomeRemaining(count) => count, KillStorageResult::AllRemoved(count) => { // We do not care to preserve order. The contract is deleted already and - // noone waits for the trie to be deleted. + // no one waits for the trie to be deleted. queue.swap_remove(0); count }, diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 3d39bc6d78d93..f0bb8f5ffd113 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -1513,6 +1513,59 @@ fn lazy_removal_works() { }); } +#[test] +fn lazy_batch_removal_works() { + let (code, hash) = compile_module::("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); + let mut tries: Vec = vec![]; + + for i in 0..3u8 { + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + min_balance * 100, + GAS_LIMIT, + None, + code.clone(), + vec![], + vec![i], + ),); + + let addr = Contracts::contract_address(&ALICE, &hash, &[i]); + let info = >::get(&addr).unwrap(); + let trie = &info.child_trie_info(); + + // Put value into the contracts child trie + child::put(trie, &[99], &42); + + // Terminate the contract. Contract info should be gone, but value should be still there + // as the lazy removal did not run, yet. + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![] + )); + + assert!(!>::contains_key(&addr)); + assert_matches!(child::get(trie, &[99]), Some(42)); + + tries.push(trie.clone()) + } + + // Run single lazy removal + Contracts::on_initialize(Weight::max_value()); + + // The single lazy removal should have removed all queued tries + for trie in tries.iter() { + assert_matches!(child::get::(trie, &[99]), None); + } + }); +} + #[test] fn lazy_removal_partial_remove_works() { let (code, hash) = compile_module::("self_destruct").unwrap(); diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 2d74df9627db9..acc13104d9281 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-28, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -156,32 +156,32 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_636_000 as Weight) + (1_601_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (7_840_000 as Weight) + (10_543_000 as Weight) // Standard Error: 0 - .saturating_add((752_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((739_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (31_915_000 as Weight) - // Standard Error: 1_000 - .saturating_add((98_000 as Weight).saturating_mul(q as Weight)) + (0 as Weight) + // Standard Error: 3_000 + .saturating_add((2_285_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (18_897_000 as Weight) - // Standard Error: 32_000 - .saturating_add((69_663_000 as Weight).saturating_mul(c as Weight)) + (16_846_000 as Weight) + // Standard Error: 33_000 + .saturating_add((71_629_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -190,9 +190,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (204_947_000 as Weight) - // Standard Error: 54_000 - .saturating_add((58_293_000 as Weight).saturating_mul(c as Weight)) + (160_645_000 as Weight) + // Standard Error: 51_000 + .saturating_add((60_029_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -204,11 +204,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (211_187_000 as Weight) - // Standard Error: 114_000 - .saturating_add((156_529_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 7_000 - .saturating_add((1_830_000 as Weight).saturating_mul(s as Weight)) + (160_721_000 as Weight) + // Standard Error: 200_000 + .saturating_add((156_185_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 13_000 + .saturating_add((1_785_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -219,9 +219,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (150_485_000 as Weight) + (145_929_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_769_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_743_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -230,7 +230,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (117_274_000 as Weight) + (114_204_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -238,9 +238,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (51_126_000 as Weight) - // Standard Error: 49_000 - .saturating_add((72_622_000 as Weight).saturating_mul(c as Weight)) + (51_131_000 as Weight) + // Standard Error: 48_000 + .saturating_add((70_405_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -248,7 +248,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_221_000 as Weight) + (24_452_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -257,9 +257,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (219_790_000 as Weight) - // Standard Error: 126_000 - .saturating_add((56_383_000 as Weight).saturating_mul(r as Weight)) + (168_803_000 as Weight) + // Standard Error: 119_000 + .saturating_add((56_278_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -268,9 +268,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (218_377_000 as Weight) - // Standard Error: 117_000 - .saturating_add((57_243_000 as Weight).saturating_mul(r as Weight)) + (170_921_000 as Weight) + // Standard Error: 150_000 + .saturating_add((56_973_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -279,9 +279,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (217_999_000 as Weight) - // Standard Error: 104_000 - .saturating_add((56_674_000 as Weight).saturating_mul(r as Weight)) + (168_953_000 as Weight) + // Standard Error: 116_000 + .saturating_add((56_032_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -290,9 +290,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (226_932_000 as Weight) - // Standard Error: 155_000 - .saturating_add((147_401_000 as Weight).saturating_mul(r as Weight)) + (170_043_000 as Weight) + // Standard Error: 147_000 + .saturating_add((152_039_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -301,9 +301,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (233_107_000 as Weight) - // Standard Error: 110_000 - .saturating_add((55_334_000 as Weight).saturating_mul(r as Weight)) + (183_371_000 as Weight) + // Standard Error: 111_000 + .saturating_add((54_799_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -312,9 +312,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (235_364_000 as Weight) - // Standard Error: 122_000 - .saturating_add((54_700_000 as Weight).saturating_mul(r as Weight)) + (181_993_000 as Weight) + // Standard Error: 127_000 + .saturating_add((54_617_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -323,9 +323,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (232_875_000 as Weight) - // Standard Error: 108_000 - .saturating_add((54_510_000 as Weight).saturating_mul(r as Weight)) + (179_543_000 as Weight) + // Standard Error: 96_000 + .saturating_add((54_526_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -334,9 +334,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (226_089_000 as Weight) - // Standard Error: 126_000 - .saturating_add((54_899_000 as Weight).saturating_mul(r as Weight)) + (174_365_000 as Weight) + // Standard Error: 117_000 + .saturating_add((54_433_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -346,9 +346,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (234_746_000 as Weight) - // Standard Error: 146_000 - .saturating_add((132_861_000 as Weight).saturating_mul(r as Weight)) + (186_003_000 as Weight) + // Standard Error: 187_000 + .saturating_add((133_644_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -357,9 +357,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (96_247_000 as Weight) - // Standard Error: 70_000 - .saturating_add((27_918_000 as Weight).saturating_mul(r as Weight)) + (91_771_000 as Weight) + // Standard Error: 68_000 + .saturating_add((28_003_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -368,9 +368,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (221_631_000 as Weight) - // Standard Error: 139_000 - .saturating_add((54_382_000 as Weight).saturating_mul(r as Weight)) + (170_110_000 as Weight) + // Standard Error: 104_000 + .saturating_add((53_937_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -379,9 +379,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (306_449_000 as Weight) - // Standard Error: 3_000 - .saturating_add((11_919_000 as Weight).saturating_mul(n as Weight)) + (251_576_000 as Weight) + // Standard Error: 9_000 + .saturating_add((10_613_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -390,9 +390,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (222_176_000 as Weight) - // Standard Error: 72_000 - .saturating_add((3_223_000 as Weight).saturating_mul(r as Weight)) + (176_897_000 as Weight) + // Standard Error: 119_000 + .saturating_add((3_095_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -401,9 +401,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (211_079_000 as Weight) + (161_820_000 as Weight) // Standard Error: 0 - .saturating_add((237_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((184_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -414,9 +414,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (213_994_000 as Weight) - // Standard Error: 104_000 - .saturating_add((64_453_000 as Weight).saturating_mul(r as Weight)) + (163_213_000 as Weight) + // Standard Error: 922_000 + .saturating_add((65_249_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -428,9 +428,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (228_281_000 as Weight) - // Standard Error: 150_000 - .saturating_add((166_949_000 as Weight).saturating_mul(r as Weight)) + (178_636_000 as Weight) + // Standard Error: 189_000 + .saturating_add((166_008_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -439,9 +439,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (230_348_000 as Weight) - // Standard Error: 163_000 - .saturating_add((288_679_000 as Weight).saturating_mul(r as Weight)) + (187_377_000 as Weight) + // Standard Error: 186_000 + .saturating_add((289_005_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -451,11 +451,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (601_613_000 as Weight) - // Standard Error: 1_566_000 - .saturating_add((279_038_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 308_000 - .saturating_add((84_818_000 as Weight).saturating_mul(n as Weight)) + (487_726_000 as Weight) + // Standard Error: 1_980_000 + .saturating_add((291_760_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 390_000 + .saturating_add((78_950_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -466,17 +466,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (113_578_000 as Weight) - // Standard Error: 67_000 - .saturating_add((44_899_000 as Weight).saturating_mul(r as Weight)) + (105_118_000 as Weight) + // Standard Error: 80_000 + .saturating_add((45_277_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (59_019_000 as Weight) - // Standard Error: 995_000 - .saturating_add((414_759_000 as Weight).saturating_mul(r as Weight)) + (0 as Weight) + // Standard Error: 1_084_000 + .saturating_add((423_125_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -484,25 +484,25 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (620_483_000 as Weight) - // Standard Error: 242_000 - .saturating_add((30_945_000 as Weight).saturating_mul(n as Weight)) + (565_293_000 as Weight) + // Standard Error: 257_000 + .saturating_add((26_134_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (632_391_000 as Weight) - // Standard Error: 317_000 - .saturating_add((11_431_000 as Weight).saturating_mul(n as Weight)) + (582_851_000 as Weight) + // Standard Error: 306_000 + .saturating_add((11_991_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (96_628_000 as Weight) - // Standard Error: 878_000 - .saturating_add((387_212_000 as Weight).saturating_mul(r as Weight)) + (51_270_000 as Weight) + // Standard Error: 883_000 + .saturating_add((394_518_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -510,51 +510,51 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (625_960_000 as Weight) - // Standard Error: 270_000 - .saturating_add((11_170_000 as Weight).saturating_mul(n as Weight)) + (585_361_000 as Weight) + // Standard Error: 263_000 + .saturating_add((10_855_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (115_155_000 as Weight) - // Standard Error: 741_000 - .saturating_add((331_711_000 as Weight).saturating_mul(r as Weight)) + (60_404_000 as Weight) + // Standard Error: 667_000 + .saturating_add((335_130_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (582_560_000 as Weight) - // Standard Error: 360_000 - .saturating_add((68_427_000 as Weight).saturating_mul(n as Weight)) + (539_500_000 as Weight) + // Standard Error: 378_000 + .saturating_add((62_855_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (130_096_000 as Weight) - // Standard Error: 555_000 - .saturating_add((294_514_000 as Weight).saturating_mul(r as Weight)) + (58_301_000 as Weight) + // Standard Error: 701_000 + .saturating_add((301_511_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (528_701_000 as Weight) - // Standard Error: 246_000 - .saturating_add((10_375_000 as Weight).saturating_mul(n as Weight)) + (485_967_000 as Weight) + // Standard Error: 266_000 + .saturating_add((10_314_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (95_349_000 as Weight) - // Standard Error: 906_000 - .saturating_add((430_051_000 as Weight).saturating_mul(r as Weight)) + (42_688_000 as Weight) + // Standard Error: 889_000 + .saturating_add((436_932_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -562,9 +562,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (676_606_000 as Weight) - // Standard Error: 389_000 - .saturating_add((70_517_000 as Weight).saturating_mul(n as Weight)) + (638_201_000 as Weight) + // Standard Error: 373_000 + .saturating_add((64_277_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } @@ -573,9 +573,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (131_194_000 as Weight) - // Standard Error: 1_256_000 - .saturating_add((1_772_590_000 as Weight).saturating_mul(r as Weight)) + (49_486_000 as Weight) + // Standard Error: 1_275_000 + .saturating_add((1_790_231_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -586,9 +586,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (2_463_174_000 as Weight) - // Standard Error: 19_404_000 - .saturating_add((19_548_986_000 as Weight).saturating_mul(r as Weight)) + (2_498_893_000 as Weight) + // Standard Error: 20_838_000 + .saturating_add((14_474_373_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -599,13 +599,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (21_356_548_000 as Weight) - // Standard Error: 31_719_000 - .saturating_add((1_874_230_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 11_000 - .saturating_add((23_243_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 12_000 - .saturating_add((34_825_000 as Weight).saturating_mul(o as Weight)) + (16_423_215_000 as Weight) + // Standard Error: 43_595_000 + .saturating_add((1_644_304_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 15_000 + .saturating_add((17_700_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 16_000 + .saturating_add((28_564_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -619,8 +619,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 49_981_000 - .saturating_add((28_988_348_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 52_924_000 + .saturating_add((24_062_215_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -633,13 +633,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (24_726_887_000 as Weight) - // Standard Error: 32_000 - .saturating_add((23_702_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 32_000 - .saturating_add((35_841_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 32_000 - .saturating_add((161_159_000 as Weight).saturating_mul(s as Weight)) + (19_940_217_000 as Weight) + // Standard Error: 36_000 + .saturating_add((17_853_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 36_000 + .saturating_add((29_592_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 36_000 + .saturating_add((155_914_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().writes(206 as Weight)) } @@ -648,9 +648,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (221_804_000 as Weight) + (166_372_000 as Weight) // Standard Error: 150_000 - .saturating_add((84_131_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((85_445_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -659,9 +659,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (357_186_000 as Weight) - // Standard Error: 23_000 - .saturating_add((469_081_000 as Weight).saturating_mul(n as Weight)) + (323_005_000 as Weight) + // Standard Error: 28_000 + .saturating_add((464_801_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -670,9 +670,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (220_729_000 as Weight) - // Standard Error: 166_000 - .saturating_add((101_538_000 as Weight).saturating_mul(r as Weight)) + (167_869_000 as Weight) + // Standard Error: 156_000 + .saturating_add((96_037_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -681,9 +681,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (272_756_000 as Weight) - // Standard Error: 18_000 - .saturating_add((311_130_000 as Weight).saturating_mul(n as Weight)) + (235_448_000 as Weight) + // Standard Error: 30_000 + .saturating_add((306_489_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -692,9 +692,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (215_784_000 as Weight) - // Standard Error: 150_000 - .saturating_add((68_809_000 as Weight).saturating_mul(r as Weight)) + (166_113_000 as Weight) + // Standard Error: 128_000 + .saturating_add((68_810_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -703,9 +703,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (256_009_000 as Weight) - // Standard Error: 12_000 - .saturating_add((124_552_000 as Weight).saturating_mul(n as Weight)) + (276_885_000 as Weight) + // Standard Error: 16_000 + .saturating_add((120_098_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -714,9 +714,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (216_413_000 as Weight) - // Standard Error: 134_000 - .saturating_add((68_281_000 as Weight).saturating_mul(r as Weight)) + (168_106_000 as Weight) + // Standard Error: 131_000 + .saturating_add((68_109_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -725,9 +725,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (254_477_000 as Weight) - // Standard Error: 13_000 - .saturating_add((124_483_000 as Weight).saturating_mul(n as Weight)) + (244_443_000 as Weight) + // Standard Error: 19_000 + .saturating_add((120_286_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -736,265 +736,265 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (179_001_000 as Weight) - // Standard Error: 1_674_000 - .saturating_add((15_397_995_000 as Weight).saturating_mul(r as Weight)) + (207_765_000 as Weight) + // Standard Error: 1_529_000 + .saturating_add((15_403_795_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (46_905_000 as Weight) - // Standard Error: 12_000 - .saturating_add((794_000 as Weight).saturating_mul(r as Weight)) + (46_110_000 as Weight) + // Standard Error: 11_000 + .saturating_add((813_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (53_636_000 as Weight) + (52_944_000 as Weight) // Standard Error: 12_000 - .saturating_add((2_476_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (53_199_000 as Weight) + (52_968_000 as Weight) // Standard Error: 12_000 - .saturating_add((2_547_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_528_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (37_268_000 as Weight) + (36_871_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_987_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_994_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (37_138_000 as Weight) + (36_834_000 as Weight) // Standard Error: 16_000 - .saturating_add((3_057_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_060_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (39_353_000 as Weight) - // Standard Error: 17_000 - .saturating_add((1_939_000 as Weight).saturating_mul(r as Weight)) + (39_250_000 as Weight) + // Standard Error: 16_000 + .saturating_add((1_933_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (38_883_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) + (38_302_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_496_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (45_030_000 as Weight) + (44_800_000 as Weight) // Standard Error: 21_000 - .saturating_add((2_398_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_407_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (47_281_000 as Weight) + (46_996_000 as Weight) // Standard Error: 3_000 - .saturating_add((29_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((27_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (49_074_000 as Weight) - // Standard Error: 20_000 - .saturating_add((19_991_000 as Weight).saturating_mul(r as Weight)) + (48_704_000 as Weight) + // Standard Error: 24_000 + .saturating_add((20_212_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (50_071_000 as Weight) - // Standard Error: 29_000 - .saturating_add((30_156_000 as Weight).saturating_mul(r as Weight)) + (52_546_000 as Weight) + // Standard Error: 32_000 + .saturating_add((29_995_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (84_902_000 as Weight) + (85_521_000 as Weight) // Standard Error: 5_000 - .saturating_add((1_124_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_117_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (39_054_000 as Weight) + (39_081_000 as Weight) // Standard Error: 14_000 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (39_190_000 as Weight) + (39_014_000 as Weight) // Standard Error: 14_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (41_830_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_878_000 as Weight).saturating_mul(r as Weight)) + (41_269_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_879_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (40_764_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_931_000 as Weight).saturating_mul(r as Weight)) + (40_341_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_944_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (46_309_000 as Weight) + (45_833_000 as Weight) // Standard Error: 12_000 - .saturating_add((1_745_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_757_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (47_071_000 as Weight) + (46_780_000 as Weight) // Standard Error: 12_000 - .saturating_add((797_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((806_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (49_773_000 as Weight) - // Standard Error: 1_442_000 - .saturating_add((227_666_000 as Weight).saturating_mul(r as Weight)) + (49_585_000 as Weight) + // Standard Error: 1_723_000 + .saturating_add((166_106_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (43_879_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_486_000 as Weight).saturating_mul(r as Weight)) + (43_423_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_494_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (43_883_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_484_000 as Weight).saturating_mul(r as Weight)) + (43_237_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (43_415_000 as Weight) + (43_308_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_495_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_505_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (43_567_000 as Weight) + (43_440_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_493_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_503_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (41_332_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_912_000 as Weight).saturating_mul(r as Weight)) + (40_782_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_948_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (41_331_000 as Weight) + (41_210_000 as Weight) // Standard Error: 12_000 - .saturating_add((1_911_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_925_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (43_704_000 as Weight) + (43_108_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_487_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_506_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (37_103_000 as Weight) + (36_501_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_467_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (36_680_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_487_000 as Weight).saturating_mul(r as Weight)) + (36_289_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (36_659_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) + (36_414_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (36_491_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) + (36_205_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (36_440_000 as Weight) + (36_648_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_473_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (36_477_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_500_000 as Weight).saturating_mul(r as Weight)) + (36_530_000 as Weight) + // Standard Error: 18_000 + .saturating_add((2_488_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (36_561_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) + (36_622_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (36_418_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) + (36_465_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (36_835_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_484_000 as Weight).saturating_mul(r as Weight)) + (36_291_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (36_873_000 as Weight) + (36_454_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (37_013_000 as Weight) + (36_801_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_466_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_468_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (36_885_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) + (36_670_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (36_696_000 as Weight) + (36_388_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_487_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (36_924_000 as Weight) + (36_952_000 as Weight) // Standard Error: 16_000 - .saturating_add((3_118_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_113_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (36_819_000 as Weight) + (36_634_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_784_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_789_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (36_855_000 as Weight) - // Standard Error: 17_000 - .saturating_add((3_047_000 as Weight).saturating_mul(r as Weight)) + (36_686_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_104_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (36_890_000 as Weight) + (36_447_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_816_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_836_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (36_749_000 as Weight) + (36_587_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_475_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_481_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (36_928_000 as Weight) + (36_889_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (36_868_000 as Weight) + (36_628_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_470_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_476_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (36_919_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_470_000 as Weight).saturating_mul(r as Weight)) + (37_136_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_475_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (36_934_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) + (32_543_000 as Weight) + // Standard Error: 25_000 + .saturating_add((2_751_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (36_705_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) + (36_378_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (36_684_000 as Weight) + (36_563_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_477_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (36_844_000 as Weight) - // Standard Error: 17_000 + (36_625_000 as Weight) + // Standard Error: 16_000 .saturating_add((2_477_000 as Weight).saturating_mul(r as Weight)) } } @@ -1003,32 +1003,32 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_636_000 as Weight) + (1_601_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (7_840_000 as Weight) + (10_543_000 as Weight) // Standard Error: 0 - .saturating_add((752_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((739_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (31_915_000 as Weight) - // Standard Error: 1_000 - .saturating_add((98_000 as Weight).saturating_mul(q as Weight)) + (0 as Weight) + // Standard Error: 3_000 + .saturating_add((2_285_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (18_897_000 as Weight) - // Standard Error: 32_000 - .saturating_add((69_663_000 as Weight).saturating_mul(c as Weight)) + (16_846_000 as Weight) + // Standard Error: 33_000 + .saturating_add((71_629_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1037,9 +1037,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (204_947_000 as Weight) - // Standard Error: 54_000 - .saturating_add((58_293_000 as Weight).saturating_mul(c as Weight)) + (160_645_000 as Weight) + // Standard Error: 51_000 + .saturating_add((60_029_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1051,11 +1051,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (211_187_000 as Weight) - // Standard Error: 114_000 - .saturating_add((156_529_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 7_000 - .saturating_add((1_830_000 as Weight).saturating_mul(s as Weight)) + (160_721_000 as Weight) + // Standard Error: 200_000 + .saturating_add((156_185_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 13_000 + .saturating_add((1_785_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1066,9 +1066,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (150_485_000 as Weight) + (145_929_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_769_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_743_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1077,7 +1077,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (117_274_000 as Weight) + (114_204_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1085,9 +1085,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (51_126_000 as Weight) - // Standard Error: 49_000 - .saturating_add((72_622_000 as Weight).saturating_mul(c as Weight)) + (51_131_000 as Weight) + // Standard Error: 48_000 + .saturating_add((70_405_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1095,7 +1095,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_221_000 as Weight) + (24_452_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1104,9 +1104,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (219_790_000 as Weight) - // Standard Error: 126_000 - .saturating_add((56_383_000 as Weight).saturating_mul(r as Weight)) + (168_803_000 as Weight) + // Standard Error: 119_000 + .saturating_add((56_278_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1115,9 +1115,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (218_377_000 as Weight) - // Standard Error: 117_000 - .saturating_add((57_243_000 as Weight).saturating_mul(r as Weight)) + (170_921_000 as Weight) + // Standard Error: 150_000 + .saturating_add((56_973_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1126,9 +1126,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (217_999_000 as Weight) - // Standard Error: 104_000 - .saturating_add((56_674_000 as Weight).saturating_mul(r as Weight)) + (168_953_000 as Weight) + // Standard Error: 116_000 + .saturating_add((56_032_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1137,9 +1137,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (226_932_000 as Weight) - // Standard Error: 155_000 - .saturating_add((147_401_000 as Weight).saturating_mul(r as Weight)) + (170_043_000 as Weight) + // Standard Error: 147_000 + .saturating_add((152_039_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1148,9 +1148,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (233_107_000 as Weight) - // Standard Error: 110_000 - .saturating_add((55_334_000 as Weight).saturating_mul(r as Weight)) + (183_371_000 as Weight) + // Standard Error: 111_000 + .saturating_add((54_799_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1159,9 +1159,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (235_364_000 as Weight) - // Standard Error: 122_000 - .saturating_add((54_700_000 as Weight).saturating_mul(r as Weight)) + (181_993_000 as Weight) + // Standard Error: 127_000 + .saturating_add((54_617_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1170,9 +1170,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (232_875_000 as Weight) - // Standard Error: 108_000 - .saturating_add((54_510_000 as Weight).saturating_mul(r as Weight)) + (179_543_000 as Weight) + // Standard Error: 96_000 + .saturating_add((54_526_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1181,9 +1181,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (226_089_000 as Weight) - // Standard Error: 126_000 - .saturating_add((54_899_000 as Weight).saturating_mul(r as Weight)) + (174_365_000 as Weight) + // Standard Error: 117_000 + .saturating_add((54_433_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1193,9 +1193,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (234_746_000 as Weight) - // Standard Error: 146_000 - .saturating_add((132_861_000 as Weight).saturating_mul(r as Weight)) + (186_003_000 as Weight) + // Standard Error: 187_000 + .saturating_add((133_644_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1204,9 +1204,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (96_247_000 as Weight) - // Standard Error: 70_000 - .saturating_add((27_918_000 as Weight).saturating_mul(r as Weight)) + (91_771_000 as Weight) + // Standard Error: 68_000 + .saturating_add((28_003_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1215,9 +1215,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (221_631_000 as Weight) - // Standard Error: 139_000 - .saturating_add((54_382_000 as Weight).saturating_mul(r as Weight)) + (170_110_000 as Weight) + // Standard Error: 104_000 + .saturating_add((53_937_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1226,9 +1226,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (306_449_000 as Weight) - // Standard Error: 3_000 - .saturating_add((11_919_000 as Weight).saturating_mul(n as Weight)) + (251_576_000 as Weight) + // Standard Error: 9_000 + .saturating_add((10_613_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1237,9 +1237,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (222_176_000 as Weight) - // Standard Error: 72_000 - .saturating_add((3_223_000 as Weight).saturating_mul(r as Weight)) + (176_897_000 as Weight) + // Standard Error: 119_000 + .saturating_add((3_095_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1248,9 +1248,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (211_079_000 as Weight) + (161_820_000 as Weight) // Standard Error: 0 - .saturating_add((237_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((184_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1261,9 +1261,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (213_994_000 as Weight) - // Standard Error: 104_000 - .saturating_add((64_453_000 as Weight).saturating_mul(r as Weight)) + (163_213_000 as Weight) + // Standard Error: 922_000 + .saturating_add((65_249_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1275,9 +1275,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (228_281_000 as Weight) - // Standard Error: 150_000 - .saturating_add((166_949_000 as Weight).saturating_mul(r as Weight)) + (178_636_000 as Weight) + // Standard Error: 189_000 + .saturating_add((166_008_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1286,9 +1286,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (230_348_000 as Weight) - // Standard Error: 163_000 - .saturating_add((288_679_000 as Weight).saturating_mul(r as Weight)) + (187_377_000 as Weight) + // Standard Error: 186_000 + .saturating_add((289_005_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1298,11 +1298,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (601_613_000 as Weight) - // Standard Error: 1_566_000 - .saturating_add((279_038_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 308_000 - .saturating_add((84_818_000 as Weight).saturating_mul(n as Weight)) + (487_726_000 as Weight) + // Standard Error: 1_980_000 + .saturating_add((291_760_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 390_000 + .saturating_add((78_950_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1313,17 +1313,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (113_578_000 as Weight) - // Standard Error: 67_000 - .saturating_add((44_899_000 as Weight).saturating_mul(r as Weight)) + (105_118_000 as Weight) + // Standard Error: 80_000 + .saturating_add((45_277_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (59_019_000 as Weight) - // Standard Error: 995_000 - .saturating_add((414_759_000 as Weight).saturating_mul(r as Weight)) + (0 as Weight) + // Standard Error: 1_084_000 + .saturating_add((423_125_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1331,25 +1331,25 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (620_483_000 as Weight) - // Standard Error: 242_000 - .saturating_add((30_945_000 as Weight).saturating_mul(n as Weight)) + (565_293_000 as Weight) + // Standard Error: 257_000 + .saturating_add((26_134_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (632_391_000 as Weight) - // Standard Error: 317_000 - .saturating_add((11_431_000 as Weight).saturating_mul(n as Weight)) + (582_851_000 as Weight) + // Standard Error: 306_000 + .saturating_add((11_991_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (96_628_000 as Weight) - // Standard Error: 878_000 - .saturating_add((387_212_000 as Weight).saturating_mul(r as Weight)) + (51_270_000 as Weight) + // Standard Error: 883_000 + .saturating_add((394_518_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1357,51 +1357,51 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (625_960_000 as Weight) - // Standard Error: 270_000 - .saturating_add((11_170_000 as Weight).saturating_mul(n as Weight)) + (585_361_000 as Weight) + // Standard Error: 263_000 + .saturating_add((10_855_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (115_155_000 as Weight) - // Standard Error: 741_000 - .saturating_add((331_711_000 as Weight).saturating_mul(r as Weight)) + (60_404_000 as Weight) + // Standard Error: 667_000 + .saturating_add((335_130_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (582_560_000 as Weight) - // Standard Error: 360_000 - .saturating_add((68_427_000 as Weight).saturating_mul(n as Weight)) + (539_500_000 as Weight) + // Standard Error: 378_000 + .saturating_add((62_855_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (130_096_000 as Weight) - // Standard Error: 555_000 - .saturating_add((294_514_000 as Weight).saturating_mul(r as Weight)) + (58_301_000 as Weight) + // Standard Error: 701_000 + .saturating_add((301_511_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (528_701_000 as Weight) - // Standard Error: 246_000 - .saturating_add((10_375_000 as Weight).saturating_mul(n as Weight)) + (485_967_000 as Weight) + // Standard Error: 266_000 + .saturating_add((10_314_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (95_349_000 as Weight) - // Standard Error: 906_000 - .saturating_add((430_051_000 as Weight).saturating_mul(r as Weight)) + (42_688_000 as Weight) + // Standard Error: 889_000 + .saturating_add((436_932_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1409,9 +1409,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (676_606_000 as Weight) - // Standard Error: 389_000 - .saturating_add((70_517_000 as Weight).saturating_mul(n as Weight)) + (638_201_000 as Weight) + // Standard Error: 373_000 + .saturating_add((64_277_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } @@ -1420,9 +1420,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (131_194_000 as Weight) - // Standard Error: 1_256_000 - .saturating_add((1_772_590_000 as Weight).saturating_mul(r as Weight)) + (49_486_000 as Weight) + // Standard Error: 1_275_000 + .saturating_add((1_790_231_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1433,9 +1433,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (2_463_174_000 as Weight) - // Standard Error: 19_404_000 - .saturating_add((19_548_986_000 as Weight).saturating_mul(r as Weight)) + (2_498_893_000 as Weight) + // Standard Error: 20_838_000 + .saturating_add((14_474_373_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1446,13 +1446,13 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (21_356_548_000 as Weight) - // Standard Error: 31_719_000 - .saturating_add((1_874_230_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 11_000 - .saturating_add((23_243_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 12_000 - .saturating_add((34_825_000 as Weight).saturating_mul(o as Weight)) + (16_423_215_000 as Weight) + // Standard Error: 43_595_000 + .saturating_add((1_644_304_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 15_000 + .saturating_add((17_700_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 16_000 + .saturating_add((28_564_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1466,8 +1466,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 49_981_000 - .saturating_add((28_988_348_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 52_924_000 + .saturating_add((24_062_215_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1480,13 +1480,13 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (24_726_887_000 as Weight) - // Standard Error: 32_000 - .saturating_add((23_702_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 32_000 - .saturating_add((35_841_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 32_000 - .saturating_add((161_159_000 as Weight).saturating_mul(s as Weight)) + (19_940_217_000 as Weight) + // Standard Error: 36_000 + .saturating_add((17_853_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 36_000 + .saturating_add((29_592_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 36_000 + .saturating_add((155_914_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().writes(206 as Weight)) } @@ -1495,9 +1495,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (221_804_000 as Weight) + (166_372_000 as Weight) // Standard Error: 150_000 - .saturating_add((84_131_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((85_445_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1506,9 +1506,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (357_186_000 as Weight) - // Standard Error: 23_000 - .saturating_add((469_081_000 as Weight).saturating_mul(n as Weight)) + (323_005_000 as Weight) + // Standard Error: 28_000 + .saturating_add((464_801_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1517,9 +1517,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (220_729_000 as Weight) - // Standard Error: 166_000 - .saturating_add((101_538_000 as Weight).saturating_mul(r as Weight)) + (167_869_000 as Weight) + // Standard Error: 156_000 + .saturating_add((96_037_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1528,9 +1528,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (272_756_000 as Weight) - // Standard Error: 18_000 - .saturating_add((311_130_000 as Weight).saturating_mul(n as Weight)) + (235_448_000 as Weight) + // Standard Error: 30_000 + .saturating_add((306_489_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1539,9 +1539,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (215_784_000 as Weight) - // Standard Error: 150_000 - .saturating_add((68_809_000 as Weight).saturating_mul(r as Weight)) + (166_113_000 as Weight) + // Standard Error: 128_000 + .saturating_add((68_810_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1550,9 +1550,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (256_009_000 as Weight) - // Standard Error: 12_000 - .saturating_add((124_552_000 as Weight).saturating_mul(n as Weight)) + (276_885_000 as Weight) + // Standard Error: 16_000 + .saturating_add((120_098_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1561,9 +1561,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (216_413_000 as Weight) - // Standard Error: 134_000 - .saturating_add((68_281_000 as Weight).saturating_mul(r as Weight)) + (168_106_000 as Weight) + // Standard Error: 131_000 + .saturating_add((68_109_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1572,9 +1572,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (254_477_000 as Weight) - // Standard Error: 13_000 - .saturating_add((124_483_000 as Weight).saturating_mul(n as Weight)) + (244_443_000 as Weight) + // Standard Error: 19_000 + .saturating_add((120_286_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1583,265 +1583,265 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (179_001_000 as Weight) - // Standard Error: 1_674_000 - .saturating_add((15_397_995_000 as Weight).saturating_mul(r as Weight)) + (207_765_000 as Weight) + // Standard Error: 1_529_000 + .saturating_add((15_403_795_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (46_905_000 as Weight) - // Standard Error: 12_000 - .saturating_add((794_000 as Weight).saturating_mul(r as Weight)) + (46_110_000 as Weight) + // Standard Error: 11_000 + .saturating_add((813_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (53_636_000 as Weight) + (52_944_000 as Weight) // Standard Error: 12_000 - .saturating_add((2_476_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (53_199_000 as Weight) + (52_968_000 as Weight) // Standard Error: 12_000 - .saturating_add((2_547_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_528_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (37_268_000 as Weight) + (36_871_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_987_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_994_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (37_138_000 as Weight) + (36_834_000 as Weight) // Standard Error: 16_000 - .saturating_add((3_057_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_060_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (39_353_000 as Weight) - // Standard Error: 17_000 - .saturating_add((1_939_000 as Weight).saturating_mul(r as Weight)) + (39_250_000 as Weight) + // Standard Error: 16_000 + .saturating_add((1_933_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (38_883_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) + (38_302_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_496_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (45_030_000 as Weight) + (44_800_000 as Weight) // Standard Error: 21_000 - .saturating_add((2_398_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_407_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (47_281_000 as Weight) + (46_996_000 as Weight) // Standard Error: 3_000 - .saturating_add((29_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((27_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (49_074_000 as Weight) - // Standard Error: 20_000 - .saturating_add((19_991_000 as Weight).saturating_mul(r as Weight)) + (48_704_000 as Weight) + // Standard Error: 24_000 + .saturating_add((20_212_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (50_071_000 as Weight) - // Standard Error: 29_000 - .saturating_add((30_156_000 as Weight).saturating_mul(r as Weight)) + (52_546_000 as Weight) + // Standard Error: 32_000 + .saturating_add((29_995_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (84_902_000 as Weight) + (85_521_000 as Weight) // Standard Error: 5_000 - .saturating_add((1_124_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_117_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (39_054_000 as Weight) + (39_081_000 as Weight) // Standard Error: 14_000 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (39_190_000 as Weight) + (39_014_000 as Weight) // Standard Error: 14_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (41_830_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_878_000 as Weight).saturating_mul(r as Weight)) + (41_269_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_879_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (40_764_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_931_000 as Weight).saturating_mul(r as Weight)) + (40_341_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_944_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (46_309_000 as Weight) + (45_833_000 as Weight) // Standard Error: 12_000 - .saturating_add((1_745_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_757_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (47_071_000 as Weight) + (46_780_000 as Weight) // Standard Error: 12_000 - .saturating_add((797_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((806_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (49_773_000 as Weight) - // Standard Error: 1_442_000 - .saturating_add((227_666_000 as Weight).saturating_mul(r as Weight)) + (49_585_000 as Weight) + // Standard Error: 1_723_000 + .saturating_add((166_106_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (43_879_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_486_000 as Weight).saturating_mul(r as Weight)) + (43_423_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_494_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (43_883_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_484_000 as Weight).saturating_mul(r as Weight)) + (43_237_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (43_415_000 as Weight) + (43_308_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_495_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_505_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (43_567_000 as Weight) + (43_440_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_493_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_503_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (41_332_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_912_000 as Weight).saturating_mul(r as Weight)) + (40_782_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_948_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (41_331_000 as Weight) + (41_210_000 as Weight) // Standard Error: 12_000 - .saturating_add((1_911_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_925_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (43_704_000 as Weight) + (43_108_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_487_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_506_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (37_103_000 as Weight) + (36_501_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_467_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (36_680_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_487_000 as Weight).saturating_mul(r as Weight)) + (36_289_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (36_659_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) + (36_414_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (36_491_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) + (36_205_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (36_440_000 as Weight) + (36_648_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_473_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (36_477_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_500_000 as Weight).saturating_mul(r as Weight)) + (36_530_000 as Weight) + // Standard Error: 18_000 + .saturating_add((2_488_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (36_561_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) + (36_622_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (36_418_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) + (36_465_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (36_835_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_484_000 as Weight).saturating_mul(r as Weight)) + (36_291_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (36_873_000 as Weight) + (36_454_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (37_013_000 as Weight) + (36_801_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_466_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_468_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (36_885_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) + (36_670_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (36_696_000 as Weight) + (36_388_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_487_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (36_924_000 as Weight) + (36_952_000 as Weight) // Standard Error: 16_000 - .saturating_add((3_118_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_113_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (36_819_000 as Weight) + (36_634_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_784_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_789_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (36_855_000 as Weight) - // Standard Error: 17_000 - .saturating_add((3_047_000 as Weight).saturating_mul(r as Weight)) + (36_686_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_104_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (36_890_000 as Weight) + (36_447_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_816_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_836_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (36_749_000 as Weight) + (36_587_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_475_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_481_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (36_928_000 as Weight) + (36_889_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (36_868_000 as Weight) + (36_628_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_470_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_476_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (36_919_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_470_000 as Weight).saturating_mul(r as Weight)) + (37_136_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_475_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (36_934_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) + (32_543_000 as Weight) + // Standard Error: 25_000 + .saturating_add((2_751_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (36_705_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) + (36_378_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (36_684_000 as Weight) + (36_563_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_477_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (36_844_000 as Weight) - // Standard Error: 17_000 + (36_625_000 as Weight) + // Standard Error: 16_000 .saturating_add((2_477_000 as Weight).saturating_mul(r as Weight)) } } From 59857f1fabbc93169206e4013e985adbc00ba25c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 31 Jan 2022 11:05:30 +0100 Subject: [PATCH 0470/1472] Bump `wasm-instrument` 0.1.0 -> 0.1.1 (#10749) * Bump wasm-instrument 0.1.0 -> 0.1.1 * Fix benchmark --- Cargo.lock | 4 ++-- frame/contracts/src/benchmarking/mod.rs | 2 +- frame/contracts/src/tests.rs | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b57f06c50ed22..c2f24bd839ab9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11444,9 +11444,9 @@ dependencies = [ [[package]] name = "wasm-instrument" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e67369bb53d409b67e57ef31797b1b2d628955fc82f86f2ea78bb403acc7c73" +checksum = "962e5b0401bbb6c887f54e69b8c496ea36f704df65db73e81fd5ff8dc3e63a9f" dependencies = [ "parity-wasm 0.42.2", ] diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 3537af3d0cf78..83be846465e47 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -270,7 +270,7 @@ benchmarks! { // We cannot let `c` grow to the maximum code size because the code is not allowed // to be larger than the maximum size **after instrumentation**. instantiate_with_code { - let c in 0 .. Perbill::from_percent(50).mul_ceil(T::Schedule::get().limits.code_len / 1024); + let c in 0 .. Perbill::from_percent(49).mul_ceil(T::Schedule::get().limits.code_len) / 1024; let s in 0 .. code::max_pages::() * 64; let salt = vec![42u8; (s * 1024) as usize]; let value = T::Currency::minimum_balance(); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index f0bb8f5ffd113..d95d434e6a743 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -2249,7 +2249,7 @@ fn upload_code_works() { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 180, + amount: 240, }), topics: vec![], }, @@ -2328,7 +2328,7 @@ fn remove_code_works() { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 180, + amount: 240, }), topics: vec![], }, @@ -2341,7 +2341,7 @@ fn remove_code_works() { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::Unreserved { who: ALICE, - amount: 180, + amount: 240, }), topics: vec![], }, @@ -2383,7 +2383,7 @@ fn remove_code_wrong_origin() { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 180, + amount: 240, }), topics: vec![], }, @@ -2514,7 +2514,7 @@ fn instantiate_with_zero_balance_works() { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 180, + amount: 240, }), topics: vec![], }, @@ -2614,7 +2614,7 @@ fn instantiate_with_below_existential_deposit_works() { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 180, + amount: 240, }), topics: vec![], }, From b07765f9ecc4c508fb4d0fba930b476c8509f5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 31 Jan 2022 12:43:42 +0100 Subject: [PATCH 0471/1472] pallet-scheduler: Fix migrations V2 to V3 (#10757) * pallet-scheduler: Fix migrations V2 to V3 V2 already supported origins, so we need to move them over instead of setting it to `Root`. Besides that it also removes the custom `Releases` enum and moves it over to `StorageVersion`. * Fixes * Fixes * :facepalm: --- bin/node/cli/src/chain_spec.rs | 1 - bin/node/testing/src/genesis.rs | 1 - frame/democracy/src/tests.rs | 2 +- frame/scheduler/src/lib.rs | 139 +++++++++++++------------------- frame/scheduler/src/tests.rs | 8 +- 5 files changed, 61 insertions(+), 90 deletions(-) diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 6fd57e31e466e..11516f964903a 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -362,7 +362,6 @@ pub fn testnet_genesis( assets: Default::default(), gilt: Default::default(), transaction_storage: Default::default(), - scheduler: Default::default(), transaction_payment: Default::default(), } } diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index 2e2f3f9a5a80a..8d2b53b0b7210 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -91,7 +91,6 @@ pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec) -> Gen assets: Default::default(), gilt: Default::default(), transaction_storage: Default::default(), - scheduler: Default::default(), transaction_payment: Default::default(), } } diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 641014923c233..0fe83a07610d1 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -63,7 +63,7 @@ frame_support::construct_runtime!( { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Scheduler: pallet_scheduler::{Pallet, Call, Storage, Config, Event}, + Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event}, Democracy: pallet_democracy::{Pallet, Call, Storage, Config, Event}, } ); diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 7ecd9024e9f96..f9077d4c8c8fa 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -63,7 +63,7 @@ use frame_support::{ dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter}, traits::{ schedule::{self, DispatchTime, MaybeHashed}, - EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp, + EnsureOrigin, Get, IsType, OriginTrait, PalletInfoAccess, PrivilegeCmp, StorageVersion, }, weights::{GetDispatchInfo, Weight}, }; @@ -132,22 +132,6 @@ pub type ScheduledOf = ScheduledV3Of; pub type Scheduled = ScheduledV2; -// A value placed in storage that represents the current version of the Scheduler storage. -// This value is used by the `on_runtime_upgrade` logic to determine whether we run -// storage migration logic. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] -enum Releases { - V1, - V2, - V3, -} - -impl Default for Releases { - fn default() -> Self { - Releases::V1 - } -} - #[cfg(feature = "runtime-benchmarks")] mod preimage_provider { use frame_support::traits::PreimageRecipient; @@ -201,8 +185,12 @@ pub mod pallet { }; use frame_system::pallet_prelude::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); + #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] #[pallet::without_storage_info] pub struct Pallet(_); @@ -268,12 +256,6 @@ pub mod pallet { pub(crate) type Lookup = StorageMap<_, Twox64Concat, Vec, TaskAddress>; - /// Storage version of the pallet. - /// - /// New networks start with last version. - #[pallet::storage] - pub(crate) type StorageVersion = StorageValue<_, Releases, ValueQuery>; - /// Events type. #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -308,23 +290,6 @@ pub mod pallet { RescheduleNoChange, } - #[pallet::genesis_config] - pub struct GenesisConfig; - - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - Self - } - } - - #[pallet::genesis_build] - impl GenesisBuild for GenesisConfig { - fn build(&self) { - StorageVersion::::put(Releases::V3); - } - } - #[pallet::hooks] impl Hooks> for Pallet { /// Execute the scheduled calls @@ -573,19 +538,19 @@ pub mod pallet { impl Pallet { /// Migrate storage format from V1 to V3. - /// Return true if migration is performed. - pub fn migrate_v1_to_v3() -> bool { - if StorageVersion::::get() == Releases::V1 { - StorageVersion::::put(Releases::V3); - - Agenda::::translate::< - Vec::Call, T::BlockNumber>>>, - _, - >(|_, agenda| { + /// + /// Returns the weight consumed by this migration. + pub fn migrate_v1_to_v3() -> Weight { + let mut weight = T::DbWeight::get().reads_writes(1, 1); + + Agenda::::translate::::Call, T::BlockNumber>>>, _>( + |_, agenda| { Some( agenda .into_iter() .map(|schedule| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + schedule.map(|schedule| ScheduledV3 { maybe_id: schedule.maybe_id, priority: schedule.priority, @@ -597,56 +562,66 @@ impl Pallet { }) .collect::>(), ) - }); + }, + ); - true - } else { - false - } + frame_support::storage::migration::remove_storage_prefix( + Self::name().as_bytes(), + b"StorageVersion", + &[], + ); + + StorageVersion::new(3).put::(); + + weight + T::DbWeight::get().writes(2) } /// Migrate storage format from V2 to V3. - /// Return true if migration is performed. + /// + /// Returns the weight consumed by this migration. pub fn migrate_v2_to_v3() -> Weight { - if StorageVersion::::get() == Releases::V2 { - StorageVersion::::put(Releases::V3); - - let mut weight = T::DbWeight::get().reads_writes(1, 1); + let mut weight = T::DbWeight::get().reads_writes(1, 1); - Agenda::::translate::>>, _>(|_, agenda| { - Some( - agenda - .into_iter() - .map(|schedule| { - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - schedule.map(|schedule| ScheduledV3 { - maybe_id: schedule.maybe_id, - priority: schedule.priority, - call: schedule.call.into(), - maybe_periodic: schedule.maybe_periodic, - origin: system::RawOrigin::Root.into(), - _phantom: Default::default(), - }) + Agenda::::translate::>>, _>(|_, agenda| { + Some( + agenda + .into_iter() + .map(|schedule| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + schedule.map(|schedule| ScheduledV3 { + maybe_id: schedule.maybe_id, + priority: schedule.priority, + call: schedule.call.into(), + maybe_periodic: schedule.maybe_periodic, + origin: schedule.origin, + _phantom: Default::default(), }) - .collect::>(), - ) - }); + }) + .collect::>(), + ) + }); - weight - } else { - 0 - } + frame_support::storage::migration::remove_storage_prefix( + Self::name().as_bytes(), + b"StorageVersion", + &[], + ); + + StorageVersion::new(3).put::(); + + weight + T::DbWeight::get().writes(2) } #[cfg(feature = "try-runtime")] pub fn pre_migrate_to_v3() -> Result<(), &'static str> { - assert!(StorageVersion::::get() < Releases::V3); Ok(()) } #[cfg(feature = "try-runtime")] pub fn post_migrate_to_v3() -> Result<(), &'static str> { - assert!(StorageVersion::::get() == Releases::V3); + use frame_support::dispatch::GetStorageVersion; + + assert!(Self::current_storage_version() == 3); for k in Agenda::::iter_keys() { let _ = Agenda::::try_get(k).map_err(|()| "Invalid item in Agenda")?; } diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 7681ede136d97..d2a795cb19fa4 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -21,7 +21,7 @@ use super::*; use crate::mock::{logger, new_test_ext, root, run_to_block, Call, LoggerCall, Scheduler, Test, *}; use frame_support::{ assert_err, assert_noop, assert_ok, - traits::{Contains, OnInitialize, PreimageProvider}, + traits::{Contains, GetStorageVersion, OnInitialize, PreimageProvider}, Hashable, }; use sp_runtime::traits::Hash; @@ -707,9 +707,7 @@ fn migration_to_v3_works() { frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); } - assert_eq!(StorageVersion::::get(), Releases::V1); - - assert!(Scheduler::migrate_v1_to_v3()); + Scheduler::migrate_v1_to_v3(); assert_eq_uvec!( Agenda::::iter().collect::>(), @@ -783,7 +781,7 @@ fn migration_to_v3_works() { ] ); - assert_eq!(StorageVersion::::get(), Releases::V3); + assert_eq!(Scheduler::current_storage_version(), 3); }); } From 4b48e8ec7dffcb599248040f4da5be3de3c09318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 31 Jan 2022 15:16:26 +0100 Subject: [PATCH 0472/1472] Add production profile to `substrate-wasm-builder` (#10747) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add production profile to wasm builder * Fix profile detection * Apply suggestions from code review Co-authored-by: Bastian Köcher * Replace panic! by println! + exit * Default to `release` for wasm on debug builds * Replaced unwrap by expect * Update all weights Rerun on the bm2 server. Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Bastian Köcher Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Parity Bot --- Cargo.lock | 16 +- frame/assets/src/weights.rs | 138 +- frame/bags-list/src/weights.rs | 18 +- frame/balances/src/weights.rs | 34 +- frame/benchmarking/src/weights.rs | 38 +- frame/bounties/src/weights.rs | 54 +- frame/child-bounties/src/weights.rs | 46 +- frame/collective/src/weights.rs | 130 +- frame/contracts/src/weights.rs | 1258 ++++++++--------- frame/democracy/src/weights.rs | 190 +-- .../src/weights.rs | 134 +- frame/elections-phragmen/src/weights.rs | 102 +- frame/gilt/src/weights.rs | 54 +- frame/identity/src/weights.rs | 182 +-- frame/im-online/src/weights.rs | 18 +- frame/indices/src/weights.rs | 26 +- frame/lottery/src/weights.rs | 38 +- frame/membership/src/weights.rs | 62 +- frame/multisig/src/weights.rs | 86 +- frame/preimage/src/weights.rs | 42 +- frame/proxy/src/weights.rs | 110 +- frame/scheduler/src/weights.rs | 150 +- frame/session/src/weights.rs | 14 +- frame/staking/src/weights.rs | 218 +-- frame/system/src/weights.rs | 26 +- frame/timestamp/src/weights.rs | 14 +- frame/tips/src/weights.rs | 62 +- frame/transaction-storage/src/weights.rs | 14 +- frame/treasury/src/weights.rs | 34 +- frame/uniques/src/weights.rs | 118 +- frame/utility/src/weights.rs | 30 +- frame/vesting/src/weights.rs | 106 +- utils/wasm-builder/Cargo.toml | 1 + utils/wasm-builder/src/lib.rs | 6 +- utils/wasm-builder/src/wasm_project.rs | 151 +- 35 files changed, 1915 insertions(+), 1805 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2f24bd839ab9..773b770362250 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -508,7 +508,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-tracing", - "strum", + "strum 0.22.0", "substrate-prometheus-endpoint", "thiserror", "wasm-timer", @@ -5710,7 +5710,7 @@ dependencies = [ "sp-std", "sp-tracing", "static_assertions", - "strum", + "strum 0.22.0", "strum_macros 0.23.1", ] @@ -9742,7 +9742,7 @@ dependencies = [ "lazy_static", "sp-core", "sp-runtime", - "strum", + "strum 0.22.0", ] [[package]] @@ -10219,6 +10219,15 @@ dependencies = [ "strum_macros 0.22.0", ] +[[package]] +name = "strum" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" +dependencies = [ + "strum_macros 0.23.1", +] + [[package]] name = "strum_macros" version = "0.22.0" @@ -10479,6 +10488,7 @@ dependencies = [ "build-helper", "cargo_metadata", "sp-maybe-compressed-blob", + "strum 0.23.0", "tempfile", "toml", "walkdir", diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index fb6e68dfc772f..a1cd77faee82e 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/assets/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -76,13 +76,13 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (22_050_000 as Weight) + (22_102_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (11_673_000 as Weight) + (12_124_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -93,12 +93,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 36_000 - .saturating_add((14_657_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 36_000 - .saturating_add((17_018_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 362_000 - .saturating_add((16_620_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 34_000 + .saturating_add((14_683_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 34_000 + .saturating_add((17_080_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 342_000 + .saturating_add((16_533_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) @@ -111,14 +111,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (26_254_000 as Weight) + (26_632_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (30_407_000 as Weight) + (30_048_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -126,7 +126,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (44_220_000 as Weight) + (44_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -134,7 +134,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (36_910_000 as Weight) + (37_286_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -142,93 +142,95 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (44_330_000 as Weight) + (44_120_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (17_937_000 as Weight) + (18_309_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (18_224_000 as Weight) + (18_290_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (14_875_000 as Weight) + (14_744_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (14_792_000 as Weight) + (14_833_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (15_794_000 as Weight) + (16_654_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (14_702_000 as Weight) + (15_351_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn set_metadata(n: u32, s: u32, ) -> Weight { - (27_368_000 as Weight) + (27_588_000 as Weight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((6_000 as Weight).saturating_mul(n as Weight)) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((3_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (28_222_000 as Weight) + (27_710_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - (15_139_000 as Weight) + fn force_set_metadata(n: u32, s: u32, ) -> Weight { + (15_345_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (28_065_000 as Weight) + (27_552_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (13_808_000 as Weight) + (13_755_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (31_261_000 as Weight) + (30_831_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -237,21 +239,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (56_329_000 as Weight) + (56_267_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (32_086_000 as Weight) + (31_964_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - (32_502_000 as Weight) + (31_806_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -261,13 +263,13 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (22_050_000 as Weight) + (22_102_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (11_673_000 as Weight) + (12_124_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -278,12 +280,12 @@ impl WeightInfo for () { // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 36_000 - .saturating_add((14_657_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 36_000 - .saturating_add((17_018_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 362_000 - .saturating_add((16_620_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 34_000 + .saturating_add((14_683_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 34_000 + .saturating_add((17_080_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 342_000 + .saturating_add((16_533_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) @@ -296,14 +298,14 @@ impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (26_254_000 as Weight) + (26_632_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (30_407_000 as Weight) + (30_048_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -311,7 +313,7 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (44_220_000 as Weight) + (44_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -319,7 +321,7 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (36_910_000 as Weight) + (37_286_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -327,93 +329,95 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (44_330_000 as Weight) + (44_120_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (17_937_000 as Weight) + (18_309_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (18_224_000 as Weight) + (18_290_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (14_875_000 as Weight) + (14_744_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (14_792_000 as Weight) + (14_833_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (15_794_000 as Weight) + (16_654_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (14_702_000 as Weight) + (15_351_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn set_metadata(n: u32, s: u32, ) -> Weight { - (27_368_000 as Weight) + (27_588_000 as Weight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((6_000 as Weight).saturating_mul(n as Weight)) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((3_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (28_222_000 as Weight) + (27_710_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - (15_139_000 as Weight) + fn force_set_metadata(n: u32, s: u32, ) -> Weight { + (15_345_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (28_065_000 as Weight) + (27_552_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (13_808_000 as Weight) + (13_755_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (31_261_000 as Weight) + (30_831_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -422,21 +426,21 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (56_329_000 as Weight) + (56_267_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (32_086_000 as Weight) + (31_964_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - (32_502_000 as Weight) + (31_806_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index 6cd9449b42862..f35c0aaee6d6a 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_bags_list //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/optimized/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -32,7 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./weights-optimized/frame/bags-list/src//weights.rs +// --output=./frame/bags-list/src/weights.rs // --template=.maintain/frame-weight-template.hbs // --header=HEADER-APACHE2 // --raw @@ -59,7 +59,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (50_222_000 as Weight) + (46_965_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -68,7 +68,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (47_975_000 as Weight) + (45_952_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -78,7 +78,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (55_539_000 as Weight) + (52_928_000 as Weight) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -91,7 +91,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (50_222_000 as Weight) + (46_965_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -100,7 +100,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (47_975_000 as Weight) + (45_952_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -110,7 +110,7 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (55_539_000 as Weight) + (52_928_000 as Weight) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index f34dd65191e4a..435438055b333 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_balances //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/balances/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -60,43 +60,43 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (34_668_000 as Weight) + (34_200_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (26_826_000 as Weight) + (27_263_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (17_292_000 as Weight) + (17_425_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (19_988_000 as Weight) + (19_979_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (34_646_000 as Weight) + (34_783_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (32_040_000 as Weight) + (31_620_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (15_743_000 as Weight) + (15_750_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -106,43 +106,43 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (34_668_000 as Weight) + (34_200_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (26_826_000 as Weight) + (27_263_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (17_292_000 as Weight) + (17_425_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (19_988_000 as Weight) + (19_979_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (34_646_000 as Weight) + (34_783_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (32_040_000 as Weight) + (31_620_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (15_743_000 as Weight) + (15_750_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index 2945daeaf3128..a49204fbf0b90 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for frame_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/benchmarking/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -60,37 +60,37 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn addition(_i: u32, ) -> Weight { - (141_000 as Weight) + (106_000 as Weight) } fn subtraction(_i: u32, ) -> Weight { - (136_000 as Weight) + (111_000 as Weight) } fn multiplication(_i: u32, ) -> Weight { - (136_000 as Weight) + (119_000 as Weight) } fn division(_i: u32, ) -> Weight { - (134_000 as Weight) + (111_000 as Weight) } fn hashing(_i: u32, ) -> Weight { - (21_681_881_000 as Weight) + (21_203_386_000 as Weight) } fn sr25519_verification(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 6_000 - .saturating_add((42_000_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((47_077_000 as Weight).saturating_mul(i as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((1_984_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((1_963_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((363_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((364_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } } @@ -98,37 +98,37 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn addition(_i: u32, ) -> Weight { - (141_000 as Weight) + (106_000 as Weight) } fn subtraction(_i: u32, ) -> Weight { - (136_000 as Weight) + (111_000 as Weight) } fn multiplication(_i: u32, ) -> Weight { - (136_000 as Weight) + (119_000 as Weight) } fn division(_i: u32, ) -> Weight { - (134_000 as Weight) + (111_000 as Weight) } fn hashing(_i: u32, ) -> Weight { - (21_681_881_000 as Weight) + (21_203_386_000 as Weight) } fn sr25519_verification(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 6_000 - .saturating_add((42_000_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((47_077_000 as Weight).saturating_mul(i as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((1_984_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((1_963_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((363_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((364_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 9c1ce532dff73..405e11acea5aa 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/bounties/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -67,43 +67,43 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(d: u32, ) -> Weight { - (23_165_000 as Weight) + (23_620_000 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (6_876_000 as Weight) + (6_655_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (5_718_000 as Weight) + (5_720_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (27_021_000 as Weight) + (26_958_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (20_933_000 as Weight) + (21_457_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (17_285_000 as Weight) + (17_483_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -112,7 +112,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (61_264_000 as Weight) + (61_763_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -121,7 +121,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (28_218_000 as Weight) + (28_862_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -130,13 +130,13 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (45_577_000 as Weight) + (45_129_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (14_983_000 as Weight) + (15_169_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -146,7 +146,7 @@ impl WeightInfo for SubstrateWeight { fn spend_funds(b: u32, ) -> Weight { (0 as Weight) // Standard Error: 14_000 - .saturating_add((28_380_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((28_850_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -161,43 +161,43 @@ impl WeightInfo for () { // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(d: u32, ) -> Weight { - (23_165_000 as Weight) + (23_620_000 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (6_876_000 as Weight) + (6_655_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (5_718_000 as Weight) + (5_720_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (27_021_000 as Weight) + (26_958_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (20_933_000 as Weight) + (21_457_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (17_285_000 as Weight) + (17_483_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -206,7 +206,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (61_264_000 as Weight) + (61_763_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -215,7 +215,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (28_218_000 as Weight) + (28_862_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -224,13 +224,13 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (45_577_000 as Weight) + (45_129_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (14_983_000 as Weight) + (15_169_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -240,7 +240,7 @@ impl WeightInfo for () { fn spend_funds(b: u32, ) -> Weight { (0 as Weight) // Standard Error: 14_000 - .saturating_add((28_380_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((28_850_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index 73bc535cb300e..002388810b8a0 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_child_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/optimized/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -32,7 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./weights-optimized/frame/child-bounties/src//weights.rs +// --output=./frame/child-bounties/src/weights.rs // --template=.maintain/frame-weight-template.hbs // --header=HEADER-APACHE2 // --raw @@ -65,8 +65,10 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBountyCount (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) - fn add_child_bounty(_d: u32, ) -> Weight { - (44_997_000 as Weight) + fn add_child_bounty(d: u32, ) -> Weight { + (44_503_000 as Weight) + // Standard Error: 0 + .saturating_add((3_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -74,7 +76,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - (11_848_000 as Weight) + (11_661_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -82,7 +84,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (24_490_000 as Weight) + (24_162_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -90,14 +92,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (28_605_000 as Weight) + (27_924_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - (19_471_000 as Weight) + (19_332_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -106,7 +108,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - (60_737_000 as Weight) + (60_363_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -117,7 +119,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - (43_120_000 as Weight) + (42_415_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -128,7 +130,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - (53_610_000 as Weight) + (52_743_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -142,8 +144,10 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBountyCount (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) - fn add_child_bounty(_d: u32, ) -> Weight { - (44_997_000 as Weight) + fn add_child_bounty(d: u32, ) -> Weight { + (44_503_000 as Weight) + // Standard Error: 0 + .saturating_add((3_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -151,7 +155,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - (11_848_000 as Weight) + (11_661_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -159,7 +163,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (24_490_000 as Weight) + (24_162_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -167,14 +171,14 @@ impl WeightInfo for () { // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (28_605_000 as Weight) + (27_924_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - (19_471_000 as Weight) + (19_332_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -183,7 +187,7 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - (60_737_000 as Weight) + (60_363_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -194,7 +198,7 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - (43_120_000 as Weight) + (42_415_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -205,7 +209,7 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - (53_610_000 as Weight) + (52_743_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index a559261fdea0f..1280ced89eeea 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/collective/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -67,12 +67,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { (0 as Weight) - // Standard Error: 7_000 - .saturating_add((12_933_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 7_000 - .saturating_add((81_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 7_000 - .saturating_add((15_645_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 10_000 + .saturating_add((14_493_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 10_000 + .saturating_add((23_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 10_000 + .saturating_add((16_909_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(p as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -80,21 +80,21 @@ impl WeightInfo for SubstrateWeight { } // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - (12_975_000 as Weight) + (12_790_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((74_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((73_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - (15_120_000 as Weight) + (15_087_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((139_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((135_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) } // Storage: Council Members (r:1 w:0) @@ -103,22 +103,22 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - (18_343_000 as Weight) + (18_269_000 as Weight) // Standard Error: 0 .saturating_add((8_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((83_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((211_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((203_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - (26_675_000 as Weight) + (26_624_000 as Weight) // Standard Error: 2_000 - .saturating_add((166_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((161_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -127,11 +127,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - (28_535_000 as Weight) + (26_527_000 as Weight) // Standard Error: 1_000 - .saturating_add((123_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((127_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((154_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((155_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -140,13 +140,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - (27_235_000 as Weight) + (26_352_000 as Weight) // Standard Error: 0 .saturating_add((6_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((158_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((154_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((201_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((203_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -156,11 +156,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - (29_502_000 as Weight) + (28_638_000 as Weight) // Standard Error: 1_000 - .saturating_add((139_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((133_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((163_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((162_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -170,13 +170,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - (28_944_000 as Weight) + (29_946_000 as Weight) // Standard Error: 0 .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) - // Standard Error: 1_000 - .saturating_add((170_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 1_000 - .saturating_add((208_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 2_000 + .saturating_add((151_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 2_000 + .saturating_add((201_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -184,9 +184,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - (16_215_000 as Weight) + (15_778_000 as Weight) // Standard Error: 1_000 - .saturating_add((212_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((206_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -200,12 +200,12 @@ impl WeightInfo for () { // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { (0 as Weight) - // Standard Error: 7_000 - .saturating_add((12_933_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 7_000 - .saturating_add((81_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 7_000 - .saturating_add((15_645_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 10_000 + .saturating_add((14_493_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 10_000 + .saturating_add((23_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 10_000 + .saturating_add((16_909_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(p as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -213,21 +213,21 @@ impl WeightInfo for () { } // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - (12_975_000 as Weight) + (12_790_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((74_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((73_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - (15_120_000 as Weight) + (15_087_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((139_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((135_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) } // Storage: Council Members (r:1 w:0) @@ -236,22 +236,22 @@ impl WeightInfo for () { // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - (18_343_000 as Weight) + (18_269_000 as Weight) // Standard Error: 0 .saturating_add((8_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((83_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((211_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((203_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - (26_675_000 as Weight) + (26_624_000 as Weight) // Standard Error: 2_000 - .saturating_add((166_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((161_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -260,11 +260,11 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - (28_535_000 as Weight) + (26_527_000 as Weight) // Standard Error: 1_000 - .saturating_add((123_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((127_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((154_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((155_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -273,13 +273,13 @@ impl WeightInfo for () { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - (27_235_000 as Weight) + (26_352_000 as Weight) // Standard Error: 0 .saturating_add((6_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((158_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((154_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((201_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((203_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -289,11 +289,11 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - (29_502_000 as Weight) + (28_638_000 as Weight) // Standard Error: 1_000 - .saturating_add((139_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((133_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((163_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((162_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -303,13 +303,13 @@ impl WeightInfo for () { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - (28_944_000 as Weight) + (29_946_000 as Weight) // Standard Error: 0 .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) - // Standard Error: 1_000 - .saturating_add((170_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 1_000 - .saturating_add((208_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 2_000 + .saturating_add((151_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 2_000 + .saturating_add((201_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -317,9 +317,9 @@ impl WeightInfo for () { // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - (16_215_000 as Weight) + (15_778_000 as Weight) // Standard Error: 1_000 - .saturating_add((212_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((206_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index acc13104d9281..24a42cc10649a 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-28, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -156,14 +156,14 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_601_000 as Weight) + (1_642_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (10_543_000 as Weight) + (7_854_000 as Weight) // Standard Error: 0 - .saturating_add((739_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((742_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -171,17 +171,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_000 - .saturating_add((2_285_000 as Weight).saturating_mul(q as Weight)) + // Standard Error: 6_000 + .saturating_add((2_216_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (16_846_000 as Weight) - // Standard Error: 33_000 - .saturating_add((71_629_000 as Weight).saturating_mul(c as Weight)) + (17_413_000 as Weight) + // Standard Error: 39_000 + .saturating_add((64_495_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -190,9 +190,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (160_645_000 as Weight) - // Standard Error: 51_000 - .saturating_add((60_029_000 as Weight).saturating_mul(c as Weight)) + (209_071_000 as Weight) + // Standard Error: 47_000 + .saturating_add((56_555_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -204,11 +204,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (160_721_000 as Weight) - // Standard Error: 200_000 - .saturating_add((156_185_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 13_000 - .saturating_add((1_785_000 as Weight).saturating_mul(s as Weight)) + (210_420_000 as Weight) + // Standard Error: 133_000 + .saturating_add((145_601_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 8_000 + .saturating_add((1_760_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -219,9 +219,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (145_929_000 as Weight) + (173_397_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_743_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_714_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -230,7 +230,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (114_204_000 as Weight) + (140_169_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -238,9 +238,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (51_131_000 as Weight) - // Standard Error: 48_000 - .saturating_add((70_405_000 as Weight).saturating_mul(c as Weight)) + (49_076_000 as Weight) + // Standard Error: 37_000 + .saturating_add((67_150_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -248,7 +248,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_452_000 as Weight) + (24_318_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -257,9 +257,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (168_803_000 as Weight) - // Standard Error: 119_000 - .saturating_add((56_278_000 as Weight).saturating_mul(r as Weight)) + (208_256_000 as Weight) + // Standard Error: 116_000 + .saturating_add((49_878_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -268,9 +268,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (170_921_000 as Weight) - // Standard Error: 150_000 - .saturating_add((56_973_000 as Weight).saturating_mul(r as Weight)) + (230_530_000 as Weight) + // Standard Error: 132_000 + .saturating_add((47_902_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -279,9 +279,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (168_953_000 as Weight) - // Standard Error: 116_000 - .saturating_add((56_032_000 as Weight).saturating_mul(r as Weight)) + (219_027_000 as Weight) + // Standard Error: 108_000 + .saturating_add((48_039_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -290,9 +290,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (170_043_000 as Weight) - // Standard Error: 147_000 - .saturating_add((152_039_000 as Weight).saturating_mul(r as Weight)) + (219_036_000 as Weight) + // Standard Error: 152_000 + .saturating_add((137_047_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -301,9 +301,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (183_371_000 as Weight) - // Standard Error: 111_000 - .saturating_add((54_799_000 as Weight).saturating_mul(r as Weight)) + (214_401_000 as Weight) + // Standard Error: 96_000 + .saturating_add((48_435_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -312,9 +312,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (181_993_000 as Weight) - // Standard Error: 127_000 - .saturating_add((54_617_000 as Weight).saturating_mul(r as Weight)) + (216_939_000 as Weight) + // Standard Error: 106_000 + .saturating_add((48_198_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -323,9 +323,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (179_543_000 as Weight) - // Standard Error: 96_000 - .saturating_add((54_526_000 as Weight).saturating_mul(r as Weight)) + (216_637_000 as Weight) + // Standard Error: 86_000 + .saturating_add((47_819_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -334,9 +334,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (174_365_000 as Weight) - // Standard Error: 117_000 - .saturating_add((54_433_000 as Weight).saturating_mul(r as Weight)) + (214_863_000 as Weight) + // Standard Error: 110_000 + .saturating_add((48_208_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -346,9 +346,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (186_003_000 as Weight) - // Standard Error: 187_000 - .saturating_add((133_644_000 as Weight).saturating_mul(r as Weight)) + (216_494_000 as Weight) + // Standard Error: 141_000 + .saturating_add((120_736_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -357,9 +357,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (91_771_000 as Weight) - // Standard Error: 68_000 - .saturating_add((28_003_000 as Weight).saturating_mul(r as Weight)) + (123_867_000 as Weight) + // Standard Error: 33_000 + .saturating_add((24_578_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -368,9 +368,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (170_110_000 as Weight) - // Standard Error: 104_000 - .saturating_add((53_937_000 as Weight).saturating_mul(r as Weight)) + (215_578_000 as Weight) + // Standard Error: 108_000 + .saturating_add((47_512_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -379,9 +379,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (251_576_000 as Weight) - // Standard Error: 9_000 - .saturating_add((10_613_000 as Weight).saturating_mul(n as Weight)) + (297_663_000 as Weight) + // Standard Error: 3_000 + .saturating_add((11_863_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -390,9 +390,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (176_897_000 as Weight) - // Standard Error: 119_000 - .saturating_add((3_095_000 as Weight).saturating_mul(r as Weight)) + (209_709_000 as Weight) + // Standard Error: 75_000 + .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -401,9 +401,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (161_820_000 as Weight) + (214_403_000 as Weight) // Standard Error: 0 - .saturating_add((184_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((197_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -414,9 +414,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (163_213_000 as Weight) - // Standard Error: 922_000 - .saturating_add((65_249_000 as Weight).saturating_mul(r as Weight)) + (214_454_000 as Weight) + // Standard Error: 656_000 + .saturating_add((50_641_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -428,9 +428,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (178_636_000 as Weight) - // Standard Error: 189_000 - .saturating_add((166_008_000 as Weight).saturating_mul(r as Weight)) + (214_140_000 as Weight) + // Standard Error: 169_000 + .saturating_add((158_778_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -439,9 +439,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (187_377_000 as Weight) - // Standard Error: 186_000 - .saturating_add((289_005_000 as Weight).saturating_mul(r as Weight)) + (225_998_000 as Weight) + // Standard Error: 171_000 + .saturating_add((280_296_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -451,11 +451,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (487_726_000 as Weight) - // Standard Error: 1_980_000 - .saturating_add((291_760_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 390_000 - .saturating_add((78_950_000 as Weight).saturating_mul(n as Weight)) + (491_432_000 as Weight) + // Standard Error: 1_992_000 + .saturating_add((288_376_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 392_000 + .saturating_add((82_805_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -466,17 +466,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (105_118_000 as Weight) - // Standard Error: 80_000 - .saturating_add((45_277_000 as Weight).saturating_mul(r as Weight)) + (130_861_000 as Weight) + // Standard Error: 74_000 + .saturating_add((40_268_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 1_084_000 - .saturating_add((423_125_000 as Weight).saturating_mul(r as Weight)) + (38_843_000 as Weight) + // Standard Error: 1_044_000 + .saturating_add((408_027_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -484,25 +484,25 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (565_293_000 as Weight) - // Standard Error: 257_000 - .saturating_add((26_134_000 as Weight).saturating_mul(n as Weight)) + (610_782_000 as Weight) + // Standard Error: 265_000 + .saturating_add((28_221_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (582_851_000 as Weight) - // Standard Error: 306_000 - .saturating_add((11_991_000 as Weight).saturating_mul(n as Weight)) + (625_031_000 as Weight) + // Standard Error: 319_000 + .saturating_add((11_126_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (51_270_000 as Weight) - // Standard Error: 883_000 - .saturating_add((394_518_000 as Weight).saturating_mul(r as Weight)) + (78_566_000 as Weight) + // Standard Error: 970_000 + .saturating_add((384_877_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -510,51 +510,51 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (585_361_000 as Weight) - // Standard Error: 263_000 - .saturating_add((10_855_000 as Weight).saturating_mul(n as Weight)) + (601_558_000 as Weight) + // Standard Error: 280_000 + .saturating_add((11_378_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (60_404_000 as Weight) - // Standard Error: 667_000 - .saturating_add((335_130_000 as Weight).saturating_mul(r as Weight)) + (112_328_000 as Weight) + // Standard Error: 668_000 + .saturating_add((323_031_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (539_500_000 as Weight) - // Standard Error: 378_000 - .saturating_add((62_855_000 as Weight).saturating_mul(n as Weight)) + (556_303_000 as Weight) + // Standard Error: 346_000 + .saturating_add((64_170_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (58_301_000 as Weight) - // Standard Error: 701_000 - .saturating_add((301_511_000 as Weight).saturating_mul(r as Weight)) + (106_572_000 as Weight) + // Standard Error: 691_000 + .saturating_add((294_964_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (485_967_000 as Weight) - // Standard Error: 266_000 - .saturating_add((10_314_000 as Weight).saturating_mul(n as Weight)) + (508_339_000 as Weight) + // Standard Error: 245_000 + .saturating_add((10_675_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (42_688_000 as Weight) - // Standard Error: 889_000 - .saturating_add((436_932_000 as Weight).saturating_mul(r as Weight)) + (88_096_000 as Weight) + // Standard Error: 927_000 + .saturating_add((415_543_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -562,9 +562,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (638_201_000 as Weight) - // Standard Error: 373_000 - .saturating_add((64_277_000 as Weight).saturating_mul(n as Weight)) + (650_912_000 as Weight) + // Standard Error: 359_000 + .saturating_add((65_030_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } @@ -573,9 +573,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (49_486_000 as Weight) - // Standard Error: 1_275_000 - .saturating_add((1_790_231_000 as Weight).saturating_mul(r as Weight)) + (102_673_000 as Weight) + // Standard Error: 1_159_000 + .saturating_add((1_711_312_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -586,9 +586,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (2_498_893_000 as Weight) - // Standard Error: 20_838_000 - .saturating_add((14_474_373_000 as Weight).saturating_mul(r as Weight)) + (0 as Weight) + // Standard Error: 3_592_000 + .saturating_add((19_565_726_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -599,13 +599,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (16_423_215_000 as Weight) - // Standard Error: 43_595_000 - .saturating_add((1_644_304_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 15_000 - .saturating_add((17_700_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 16_000 - .saturating_add((28_564_000 as Weight).saturating_mul(o as Weight)) + (19_665_171_000 as Weight) + // Standard Error: 27_641_000 + .saturating_add((2_089_637_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 9_000 + .saturating_add((20_165_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 10_000 + .saturating_add((31_728_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -619,8 +619,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 52_924_000 - .saturating_add((24_062_215_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 48_640_000 + .saturating_add((27_307_450_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -633,13 +633,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (19_940_217_000 as Weight) - // Standard Error: 36_000 - .saturating_add((17_853_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 36_000 - .saturating_add((29_592_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 36_000 - .saturating_add((155_914_000 as Weight).saturating_mul(s as Weight)) + (24_821_248_000 as Weight) + // Standard Error: 26_000 + .saturating_add((20_118_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 26_000 + .saturating_add((31_616_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 26_000 + .saturating_add((157_567_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().writes(206 as Weight)) } @@ -648,9 +648,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (166_372_000 as Weight) - // Standard Error: 150_000 - .saturating_add((85_445_000 as Weight).saturating_mul(r as Weight)) + (213_816_000 as Weight) + // Standard Error: 147_000 + .saturating_add((80_336_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -659,9 +659,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (323_005_000 as Weight) - // Standard Error: 28_000 - .saturating_add((464_801_000 as Weight).saturating_mul(n as Weight)) + (309_038_000 as Weight) + // Standard Error: 23_000 + .saturating_add((465_306_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -670,9 +670,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (167_869_000 as Weight) - // Standard Error: 156_000 - .saturating_add((96_037_000 as Weight).saturating_mul(r as Weight)) + (212_825_000 as Weight) + // Standard Error: 143_000 + .saturating_add((91_947_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -681,9 +681,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (235_448_000 as Weight) - // Standard Error: 30_000 - .saturating_add((306_489_000 as Weight).saturating_mul(n as Weight)) + (329_548_000 as Weight) + // Standard Error: 19_000 + .saturating_add((306_729_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -692,9 +692,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (166_113_000 as Weight) - // Standard Error: 128_000 - .saturating_add((68_810_000 as Weight).saturating_mul(r as Weight)) + (215_907_000 as Weight) + // Standard Error: 129_000 + .saturating_add((63_477_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -703,9 +703,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (276_885_000 as Weight) + (423_811_000 as Weight) // Standard Error: 16_000 - .saturating_add((120_098_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((119_607_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -714,9 +714,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (168_106_000 as Weight) - // Standard Error: 131_000 - .saturating_add((68_109_000 as Weight).saturating_mul(r as Weight)) + (214_747_000 as Weight) + // Standard Error: 115_000 + .saturating_add((62_904_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -725,9 +725,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (244_443_000 as Weight) + (437_217_000 as Weight) // Standard Error: 19_000 - .saturating_add((120_286_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((120_126_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -736,266 +736,266 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (207_765_000 as Weight) - // Standard Error: 1_529_000 - .saturating_add((15_403_795_000 as Weight).saturating_mul(r as Weight)) + (195_980_000 as Weight) + // Standard Error: 1_262_000 + .saturating_add((15_428_805_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (46_110_000 as Weight) - // Standard Error: 11_000 - .saturating_add((813_000 as Weight).saturating_mul(r as Weight)) + (74_569_000 as Weight) + // Standard Error: 1_000 + .saturating_add((589_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (52_944_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) + (74_212_000 as Weight) + // Standard Error: 0 + .saturating_add((1_325_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (52_968_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_528_000 as Weight).saturating_mul(r as Weight)) + (74_505_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_423_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (36_871_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_994_000 as Weight).saturating_mul(r as Weight)) + (74_005_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_785_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (36_834_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_060_000 as Weight).saturating_mul(r as Weight)) + (74_212_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_890_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (39_250_000 as Weight) - // Standard Error: 16_000 - .saturating_add((1_933_000 as Weight).saturating_mul(r as Weight)) + (74_102_000 as Weight) + // Standard Error: 2_000 + .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (38_302_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_496_000 as Weight).saturating_mul(r as Weight)) + (73_523_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_456_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (44_800_000 as Weight) - // Standard Error: 21_000 - .saturating_add((2_407_000 as Weight).saturating_mul(r as Weight)) + (73_307_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_594_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (46_996_000 as Weight) - // Standard Error: 3_000 - .saturating_add((27_000 as Weight).saturating_mul(e as Weight)) + (76_272_000 as Weight) + // Standard Error: 0 + .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (48_704_000 as Weight) - // Standard Error: 24_000 - .saturating_add((20_212_000 as Weight).saturating_mul(r as Weight)) + (73_390_000 as Weight) + // Standard Error: 23_000 + .saturating_add((16_936_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (52_546_000 as Weight) - // Standard Error: 32_000 - .saturating_add((29_995_000 as Weight).saturating_mul(r as Weight)) + (89_331_000 as Weight) + // Standard Error: 30_000 + .saturating_add((28_104_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (85_521_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_117_000 as Weight).saturating_mul(p as Weight)) + (117_023_000 as Weight) + // Standard Error: 3_000 + .saturating_add((914_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (39_081_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (74_727_000 as Weight) + // Standard Error: 1_000 + .saturating_add((618_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (39_014_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) + (74_893_000 as Weight) + // Standard Error: 1_000 + .saturating_add((674_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (41_269_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_879_000 as Weight).saturating_mul(r as Weight)) + (74_552_000 as Weight) + // Standard Error: 1_000 + .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (40_341_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_944_000 as Weight).saturating_mul(r as Weight)) + (77_355_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_146_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (45_833_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_757_000 as Weight).saturating_mul(r as Weight)) + (77_055_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (46_780_000 as Weight) - // Standard Error: 12_000 - .saturating_add((806_000 as Weight).saturating_mul(r as Weight)) + (74_648_000 as Weight) + // Standard Error: 2_000 + .saturating_add((652_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (49_585_000 as Weight) - // Standard Error: 1_723_000 - .saturating_add((166_106_000 as Weight).saturating_mul(r as Weight)) + (73_777_000 as Weight) + // Standard Error: 226_000 + .saturating_add((187_252_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (43_423_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_494_000 as Weight).saturating_mul(r as Weight)) + (74_332_000 as Weight) + // Standard Error: 1_000 + .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (43_237_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) + (74_265_000 as Weight) + // Standard Error: 1_000 + .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (43_308_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_505_000 as Weight).saturating_mul(r as Weight)) + (74_475_000 as Weight) + // Standard Error: 2_000 + .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (43_440_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_503_000 as Weight).saturating_mul(r as Weight)) + (74_297_000 as Weight) + // Standard Error: 1_000 + .saturating_add((918_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (40_782_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_948_000 as Weight).saturating_mul(r as Weight)) + (74_146_000 as Weight) + // Standard Error: 1_000 + .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (41_210_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_925_000 as Weight).saturating_mul(r as Weight)) + (74_361_000 as Weight) + // Standard Error: 1_000 + .saturating_add((877_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (43_108_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_506_000 as Weight).saturating_mul(r as Weight)) + (74_554_000 as Weight) + // Standard Error: 1_000 + .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (36_501_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) + (74_169_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (36_289_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) + (74_164_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (36_414_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) + (74_058_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (36_205_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) + (74_039_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (36_648_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_473_000 as Weight).saturating_mul(r as Weight)) + (75_055_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (36_530_000 as Weight) - // Standard Error: 18_000 - .saturating_add((2_488_000 as Weight).saturating_mul(r as Weight)) + (74_536_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (36_622_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (74_177_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (36_465_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) + (74_080_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (36_291_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) + (74_237_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (36_454_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (74_049_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (36_801_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_468_000 as Weight).saturating_mul(r as Weight)) + (74_186_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (36_670_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (74_268_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (36_388_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) + (74_334_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_331_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (36_952_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_113_000 as Weight).saturating_mul(r as Weight)) + (74_285_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_997_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (36_634_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_789_000 as Weight).saturating_mul(r as Weight)) + (74_002_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_027_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (36_686_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_104_000 as Weight).saturating_mul(r as Weight)) + (74_281_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_977_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (36_447_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_836_000 as Weight).saturating_mul(r as Weight)) + (74_160_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_038_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (36_587_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_481_000 as Weight).saturating_mul(r as Weight)) + (74_097_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (36_889_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) + (74_020_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (36_628_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_476_000 as Weight).saturating_mul(r as Weight)) + (73_890_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (37_136_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_475_000 as Weight).saturating_mul(r as Weight)) + (74_139_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (32_543_000 as Weight) - // Standard Error: 25_000 - .saturating_add((2_751_000 as Weight).saturating_mul(r as Weight)) + (74_189_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (36_378_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) + (74_055_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (36_563_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (74_074_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (36_625_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_477_000 as Weight).saturating_mul(r as Weight)) + (74_005_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } } @@ -1003,14 +1003,14 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_601_000 as Weight) + (1_642_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (10_543_000 as Weight) + (7_854_000 as Weight) // Standard Error: 0 - .saturating_add((739_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((742_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -1018,17 +1018,17 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_000 - .saturating_add((2_285_000 as Weight).saturating_mul(q as Weight)) + // Standard Error: 6_000 + .saturating_add((2_216_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (16_846_000 as Weight) - // Standard Error: 33_000 - .saturating_add((71_629_000 as Weight).saturating_mul(c as Weight)) + (17_413_000 as Weight) + // Standard Error: 39_000 + .saturating_add((64_495_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1037,9 +1037,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (160_645_000 as Weight) - // Standard Error: 51_000 - .saturating_add((60_029_000 as Weight).saturating_mul(c as Weight)) + (209_071_000 as Weight) + // Standard Error: 47_000 + .saturating_add((56_555_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1051,11 +1051,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (160_721_000 as Weight) - // Standard Error: 200_000 - .saturating_add((156_185_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 13_000 - .saturating_add((1_785_000 as Weight).saturating_mul(s as Weight)) + (210_420_000 as Weight) + // Standard Error: 133_000 + .saturating_add((145_601_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 8_000 + .saturating_add((1_760_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1066,9 +1066,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (145_929_000 as Weight) + (173_397_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_743_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_714_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1077,7 +1077,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (114_204_000 as Weight) + (140_169_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1085,9 +1085,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (51_131_000 as Weight) - // Standard Error: 48_000 - .saturating_add((70_405_000 as Weight).saturating_mul(c as Weight)) + (49_076_000 as Weight) + // Standard Error: 37_000 + .saturating_add((67_150_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1095,7 +1095,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_452_000 as Weight) + (24_318_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1104,9 +1104,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (168_803_000 as Weight) - // Standard Error: 119_000 - .saturating_add((56_278_000 as Weight).saturating_mul(r as Weight)) + (208_256_000 as Weight) + // Standard Error: 116_000 + .saturating_add((49_878_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1115,9 +1115,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (170_921_000 as Weight) - // Standard Error: 150_000 - .saturating_add((56_973_000 as Weight).saturating_mul(r as Weight)) + (230_530_000 as Weight) + // Standard Error: 132_000 + .saturating_add((47_902_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1126,9 +1126,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (168_953_000 as Weight) - // Standard Error: 116_000 - .saturating_add((56_032_000 as Weight).saturating_mul(r as Weight)) + (219_027_000 as Weight) + // Standard Error: 108_000 + .saturating_add((48_039_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1137,9 +1137,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (170_043_000 as Weight) - // Standard Error: 147_000 - .saturating_add((152_039_000 as Weight).saturating_mul(r as Weight)) + (219_036_000 as Weight) + // Standard Error: 152_000 + .saturating_add((137_047_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1148,9 +1148,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (183_371_000 as Weight) - // Standard Error: 111_000 - .saturating_add((54_799_000 as Weight).saturating_mul(r as Weight)) + (214_401_000 as Weight) + // Standard Error: 96_000 + .saturating_add((48_435_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1159,9 +1159,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (181_993_000 as Weight) - // Standard Error: 127_000 - .saturating_add((54_617_000 as Weight).saturating_mul(r as Weight)) + (216_939_000 as Weight) + // Standard Error: 106_000 + .saturating_add((48_198_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1170,9 +1170,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (179_543_000 as Weight) - // Standard Error: 96_000 - .saturating_add((54_526_000 as Weight).saturating_mul(r as Weight)) + (216_637_000 as Weight) + // Standard Error: 86_000 + .saturating_add((47_819_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1181,9 +1181,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (174_365_000 as Weight) - // Standard Error: 117_000 - .saturating_add((54_433_000 as Weight).saturating_mul(r as Weight)) + (214_863_000 as Weight) + // Standard Error: 110_000 + .saturating_add((48_208_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1193,9 +1193,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (186_003_000 as Weight) - // Standard Error: 187_000 - .saturating_add((133_644_000 as Weight).saturating_mul(r as Weight)) + (216_494_000 as Weight) + // Standard Error: 141_000 + .saturating_add((120_736_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1204,9 +1204,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (91_771_000 as Weight) - // Standard Error: 68_000 - .saturating_add((28_003_000 as Weight).saturating_mul(r as Weight)) + (123_867_000 as Weight) + // Standard Error: 33_000 + .saturating_add((24_578_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1215,9 +1215,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (170_110_000 as Weight) - // Standard Error: 104_000 - .saturating_add((53_937_000 as Weight).saturating_mul(r as Weight)) + (215_578_000 as Weight) + // Standard Error: 108_000 + .saturating_add((47_512_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1226,9 +1226,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (251_576_000 as Weight) - // Standard Error: 9_000 - .saturating_add((10_613_000 as Weight).saturating_mul(n as Weight)) + (297_663_000 as Weight) + // Standard Error: 3_000 + .saturating_add((11_863_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1237,9 +1237,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (176_897_000 as Weight) - // Standard Error: 119_000 - .saturating_add((3_095_000 as Weight).saturating_mul(r as Weight)) + (209_709_000 as Weight) + // Standard Error: 75_000 + .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1248,9 +1248,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (161_820_000 as Weight) + (214_403_000 as Weight) // Standard Error: 0 - .saturating_add((184_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((197_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1261,9 +1261,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (163_213_000 as Weight) - // Standard Error: 922_000 - .saturating_add((65_249_000 as Weight).saturating_mul(r as Weight)) + (214_454_000 as Weight) + // Standard Error: 656_000 + .saturating_add((50_641_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1275,9 +1275,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (178_636_000 as Weight) - // Standard Error: 189_000 - .saturating_add((166_008_000 as Weight).saturating_mul(r as Weight)) + (214_140_000 as Weight) + // Standard Error: 169_000 + .saturating_add((158_778_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1286,9 +1286,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (187_377_000 as Weight) - // Standard Error: 186_000 - .saturating_add((289_005_000 as Weight).saturating_mul(r as Weight)) + (225_998_000 as Weight) + // Standard Error: 171_000 + .saturating_add((280_296_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1298,11 +1298,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (487_726_000 as Weight) - // Standard Error: 1_980_000 - .saturating_add((291_760_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 390_000 - .saturating_add((78_950_000 as Weight).saturating_mul(n as Weight)) + (491_432_000 as Weight) + // Standard Error: 1_992_000 + .saturating_add((288_376_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 392_000 + .saturating_add((82_805_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1313,17 +1313,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (105_118_000 as Weight) - // Standard Error: 80_000 - .saturating_add((45_277_000 as Weight).saturating_mul(r as Weight)) + (130_861_000 as Weight) + // Standard Error: 74_000 + .saturating_add((40_268_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 1_084_000 - .saturating_add((423_125_000 as Weight).saturating_mul(r as Weight)) + (38_843_000 as Weight) + // Standard Error: 1_044_000 + .saturating_add((408_027_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1331,25 +1331,25 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (565_293_000 as Weight) - // Standard Error: 257_000 - .saturating_add((26_134_000 as Weight).saturating_mul(n as Weight)) + (610_782_000 as Weight) + // Standard Error: 265_000 + .saturating_add((28_221_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (582_851_000 as Weight) - // Standard Error: 306_000 - .saturating_add((11_991_000 as Weight).saturating_mul(n as Weight)) + (625_031_000 as Weight) + // Standard Error: 319_000 + .saturating_add((11_126_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (51_270_000 as Weight) - // Standard Error: 883_000 - .saturating_add((394_518_000 as Weight).saturating_mul(r as Weight)) + (78_566_000 as Weight) + // Standard Error: 970_000 + .saturating_add((384_877_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1357,51 +1357,51 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (585_361_000 as Weight) - // Standard Error: 263_000 - .saturating_add((10_855_000 as Weight).saturating_mul(n as Weight)) + (601_558_000 as Weight) + // Standard Error: 280_000 + .saturating_add((11_378_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (60_404_000 as Weight) - // Standard Error: 667_000 - .saturating_add((335_130_000 as Weight).saturating_mul(r as Weight)) + (112_328_000 as Weight) + // Standard Error: 668_000 + .saturating_add((323_031_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (539_500_000 as Weight) - // Standard Error: 378_000 - .saturating_add((62_855_000 as Weight).saturating_mul(n as Weight)) + (556_303_000 as Weight) + // Standard Error: 346_000 + .saturating_add((64_170_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (58_301_000 as Weight) - // Standard Error: 701_000 - .saturating_add((301_511_000 as Weight).saturating_mul(r as Weight)) + (106_572_000 as Weight) + // Standard Error: 691_000 + .saturating_add((294_964_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (485_967_000 as Weight) - // Standard Error: 266_000 - .saturating_add((10_314_000 as Weight).saturating_mul(n as Weight)) + (508_339_000 as Weight) + // Standard Error: 245_000 + .saturating_add((10_675_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (42_688_000 as Weight) - // Standard Error: 889_000 - .saturating_add((436_932_000 as Weight).saturating_mul(r as Weight)) + (88_096_000 as Weight) + // Standard Error: 927_000 + .saturating_add((415_543_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1409,9 +1409,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (638_201_000 as Weight) - // Standard Error: 373_000 - .saturating_add((64_277_000 as Weight).saturating_mul(n as Weight)) + (650_912_000 as Weight) + // Standard Error: 359_000 + .saturating_add((65_030_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } @@ -1420,9 +1420,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (49_486_000 as Weight) - // Standard Error: 1_275_000 - .saturating_add((1_790_231_000 as Weight).saturating_mul(r as Weight)) + (102_673_000 as Weight) + // Standard Error: 1_159_000 + .saturating_add((1_711_312_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1433,9 +1433,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (2_498_893_000 as Weight) - // Standard Error: 20_838_000 - .saturating_add((14_474_373_000 as Weight).saturating_mul(r as Weight)) + (0 as Weight) + // Standard Error: 3_592_000 + .saturating_add((19_565_726_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1446,13 +1446,13 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (16_423_215_000 as Weight) - // Standard Error: 43_595_000 - .saturating_add((1_644_304_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 15_000 - .saturating_add((17_700_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 16_000 - .saturating_add((28_564_000 as Weight).saturating_mul(o as Weight)) + (19_665_171_000 as Weight) + // Standard Error: 27_641_000 + .saturating_add((2_089_637_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 9_000 + .saturating_add((20_165_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 10_000 + .saturating_add((31_728_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1466,8 +1466,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 52_924_000 - .saturating_add((24_062_215_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 48_640_000 + .saturating_add((27_307_450_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1480,13 +1480,13 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (19_940_217_000 as Weight) - // Standard Error: 36_000 - .saturating_add((17_853_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 36_000 - .saturating_add((29_592_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 36_000 - .saturating_add((155_914_000 as Weight).saturating_mul(s as Weight)) + (24_821_248_000 as Weight) + // Standard Error: 26_000 + .saturating_add((20_118_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 26_000 + .saturating_add((31_616_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 26_000 + .saturating_add((157_567_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().writes(206 as Weight)) } @@ -1495,9 +1495,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (166_372_000 as Weight) - // Standard Error: 150_000 - .saturating_add((85_445_000 as Weight).saturating_mul(r as Weight)) + (213_816_000 as Weight) + // Standard Error: 147_000 + .saturating_add((80_336_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1506,9 +1506,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (323_005_000 as Weight) - // Standard Error: 28_000 - .saturating_add((464_801_000 as Weight).saturating_mul(n as Weight)) + (309_038_000 as Weight) + // Standard Error: 23_000 + .saturating_add((465_306_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1517,9 +1517,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (167_869_000 as Weight) - // Standard Error: 156_000 - .saturating_add((96_037_000 as Weight).saturating_mul(r as Weight)) + (212_825_000 as Weight) + // Standard Error: 143_000 + .saturating_add((91_947_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1528,9 +1528,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (235_448_000 as Weight) - // Standard Error: 30_000 - .saturating_add((306_489_000 as Weight).saturating_mul(n as Weight)) + (329_548_000 as Weight) + // Standard Error: 19_000 + .saturating_add((306_729_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1539,9 +1539,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (166_113_000 as Weight) - // Standard Error: 128_000 - .saturating_add((68_810_000 as Weight).saturating_mul(r as Weight)) + (215_907_000 as Weight) + // Standard Error: 129_000 + .saturating_add((63_477_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1550,9 +1550,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (276_885_000 as Weight) + (423_811_000 as Weight) // Standard Error: 16_000 - .saturating_add((120_098_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((119_607_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1561,9 +1561,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (168_106_000 as Weight) - // Standard Error: 131_000 - .saturating_add((68_109_000 as Weight).saturating_mul(r as Weight)) + (214_747_000 as Weight) + // Standard Error: 115_000 + .saturating_add((62_904_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1572,9 +1572,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (244_443_000 as Weight) + (437_217_000 as Weight) // Standard Error: 19_000 - .saturating_add((120_286_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((120_126_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1583,265 +1583,265 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (207_765_000 as Weight) - // Standard Error: 1_529_000 - .saturating_add((15_403_795_000 as Weight).saturating_mul(r as Weight)) + (195_980_000 as Weight) + // Standard Error: 1_262_000 + .saturating_add((15_428_805_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (46_110_000 as Weight) - // Standard Error: 11_000 - .saturating_add((813_000 as Weight).saturating_mul(r as Weight)) + (74_569_000 as Weight) + // Standard Error: 1_000 + .saturating_add((589_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (52_944_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) + (74_212_000 as Weight) + // Standard Error: 0 + .saturating_add((1_325_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (52_968_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_528_000 as Weight).saturating_mul(r as Weight)) + (74_505_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_423_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (36_871_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_994_000 as Weight).saturating_mul(r as Weight)) + (74_005_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_785_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (36_834_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_060_000 as Weight).saturating_mul(r as Weight)) + (74_212_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_890_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (39_250_000 as Weight) - // Standard Error: 16_000 - .saturating_add((1_933_000 as Weight).saturating_mul(r as Weight)) + (74_102_000 as Weight) + // Standard Error: 2_000 + .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (38_302_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_496_000 as Weight).saturating_mul(r as Weight)) + (73_523_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_456_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (44_800_000 as Weight) - // Standard Error: 21_000 - .saturating_add((2_407_000 as Weight).saturating_mul(r as Weight)) + (73_307_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_594_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (46_996_000 as Weight) - // Standard Error: 3_000 - .saturating_add((27_000 as Weight).saturating_mul(e as Weight)) + (76_272_000 as Weight) + // Standard Error: 0 + .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (48_704_000 as Weight) - // Standard Error: 24_000 - .saturating_add((20_212_000 as Weight).saturating_mul(r as Weight)) + (73_390_000 as Weight) + // Standard Error: 23_000 + .saturating_add((16_936_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (52_546_000 as Weight) - // Standard Error: 32_000 - .saturating_add((29_995_000 as Weight).saturating_mul(r as Weight)) + (89_331_000 as Weight) + // Standard Error: 30_000 + .saturating_add((28_104_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (85_521_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_117_000 as Weight).saturating_mul(p as Weight)) + (117_023_000 as Weight) + // Standard Error: 3_000 + .saturating_add((914_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (39_081_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (74_727_000 as Weight) + // Standard Error: 1_000 + .saturating_add((618_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (39_014_000 as Weight) - // Standard Error: 14_000 - .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) + (74_893_000 as Weight) + // Standard Error: 1_000 + .saturating_add((674_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (41_269_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_879_000 as Weight).saturating_mul(r as Weight)) + (74_552_000 as Weight) + // Standard Error: 1_000 + .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (40_341_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_944_000 as Weight).saturating_mul(r as Weight)) + (77_355_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_146_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (45_833_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_757_000 as Weight).saturating_mul(r as Weight)) + (77_055_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (46_780_000 as Weight) - // Standard Error: 12_000 - .saturating_add((806_000 as Weight).saturating_mul(r as Weight)) + (74_648_000 as Weight) + // Standard Error: 2_000 + .saturating_add((652_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (49_585_000 as Weight) - // Standard Error: 1_723_000 - .saturating_add((166_106_000 as Weight).saturating_mul(r as Weight)) + (73_777_000 as Weight) + // Standard Error: 226_000 + .saturating_add((187_252_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (43_423_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_494_000 as Weight).saturating_mul(r as Weight)) + (74_332_000 as Weight) + // Standard Error: 1_000 + .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (43_237_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_499_000 as Weight).saturating_mul(r as Weight)) + (74_265_000 as Weight) + // Standard Error: 1_000 + .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (43_308_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_505_000 as Weight).saturating_mul(r as Weight)) + (74_475_000 as Weight) + // Standard Error: 2_000 + .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (43_440_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_503_000 as Weight).saturating_mul(r as Weight)) + (74_297_000 as Weight) + // Standard Error: 1_000 + .saturating_add((918_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (40_782_000 as Weight) - // Standard Error: 13_000 - .saturating_add((1_948_000 as Weight).saturating_mul(r as Weight)) + (74_146_000 as Weight) + // Standard Error: 1_000 + .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (41_210_000 as Weight) - // Standard Error: 12_000 - .saturating_add((1_925_000 as Weight).saturating_mul(r as Weight)) + (74_361_000 as Weight) + // Standard Error: 1_000 + .saturating_add((877_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (43_108_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_506_000 as Weight).saturating_mul(r as Weight)) + (74_554_000 as Weight) + // Standard Error: 1_000 + .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (36_501_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) + (74_169_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (36_289_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) + (74_164_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (36_414_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) + (74_058_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (36_205_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) + (74_039_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (36_648_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_473_000 as Weight).saturating_mul(r as Weight)) + (75_055_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (36_530_000 as Weight) - // Standard Error: 18_000 - .saturating_add((2_488_000 as Weight).saturating_mul(r as Weight)) + (74_536_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (36_622_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (74_177_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (36_465_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_490_000 as Weight).saturating_mul(r as Weight)) + (74_080_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (36_291_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) + (74_237_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (36_454_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (74_049_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (36_801_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_468_000 as Weight).saturating_mul(r as Weight)) + (74_186_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (36_670_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (74_268_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (36_388_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) + (74_334_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_331_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (36_952_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_113_000 as Weight).saturating_mul(r as Weight)) + (74_285_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_997_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (36_634_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_789_000 as Weight).saturating_mul(r as Weight)) + (74_002_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_027_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (36_686_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_104_000 as Weight).saturating_mul(r as Weight)) + (74_281_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_977_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (36_447_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_836_000 as Weight).saturating_mul(r as Weight)) + (74_160_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_038_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (36_587_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_481_000 as Weight).saturating_mul(r as Weight)) + (74_097_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (36_889_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) + (74_020_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (36_628_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_476_000 as Weight).saturating_mul(r as Weight)) + (73_890_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (37_136_000 as Weight) - // Standard Error: 17_000 - .saturating_add((2_475_000 as Weight).saturating_mul(r as Weight)) + (74_139_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (32_543_000 as Weight) - // Standard Error: 25_000 - .saturating_add((2_751_000 as Weight).saturating_mul(r as Weight)) + (74_189_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (36_378_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) + (74_055_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (36_563_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_483_000 as Weight).saturating_mul(r as Weight)) + (74_074_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (36_625_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_477_000 as Weight).saturating_mul(r as Weight)) + (74_005_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } } diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 22743124253b4..19bf602c5d291 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/democracy/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -82,15 +82,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (42_599_000 as Weight) + (42_560_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (25_521_000 as Weight) + (25_603_000 as Weight) // Standard Error: 1_000 - .saturating_add((171_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((167_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -98,9 +98,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (34_035_000 as Weight) - // Standard Error: 1_000 - .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) + (34_248_000 as Weight) + // Standard Error: 2_000 + .saturating_add((135_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -108,16 +108,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (33_910_000 as Weight) - // Standard Error: 1_000 - .saturating_add((147_000 as Weight).saturating_mul(r as Weight)) + (33_927_000 as Weight) + // Standard Error: 2_000 + .saturating_add((138_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (14_874_000 as Weight) + (14_714_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -128,45 +128,45 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (49_557_000 as Weight) + (49_423_000 as Weight) // Standard Error: 3_000 - .saturating_add((267_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((275_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (7_540_000 as Weight) + (7_321_000 as Weight) // Standard Error: 0 - .saturating_add((76_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((75_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (1_272_000 as Weight) + (1_325_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (1_274_000 as Weight) + (1_283_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (15_216_000 as Weight) + (15_355_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (16_713_000 as Weight) + (16_597_000 as Weight) // Standard Error: 0 - .saturating_add((92_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((90_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -174,23 +174,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (37_990_000 as Weight) + (37_695_000 as Weight) // Standard Error: 2_000 - .saturating_add((259_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((258_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (9_756_000 as Weight) + (9_456_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (19_408_000 as Weight) + (19_915_000 as Weight) // Standard Error: 1_000 - .saturating_add((650_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((609_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -198,9 +198,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (2_134_000 as Weight) - // Standard Error: 3_000 - .saturating_add((3_041_000 as Weight).saturating_mul(r as Weight)) + (3_787_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_852_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -212,9 +212,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - (6_357_000 as Weight) - // Standard Error: 3_000 - .saturating_add((3_054_000 as Weight).saturating_mul(r as Weight)) + (7_890_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_856_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -223,9 +223,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (30_822_000 as Weight) + (31_190_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_826_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_753_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(4 as Weight)) @@ -234,9 +234,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (15_307_000 as Weight) + (15_121_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_827_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_852_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -244,12 +244,12 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (1_624_000 as Weight) + (1_583_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (22_731_000 as Weight) + (22_681_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -257,7 +257,7 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (15_518_000 as Weight) + (15_599_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -266,7 +266,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (23_749_000 as Weight) + (23_663_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -276,9 +276,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (21_818_000 as Weight) + (21_928_000 as Weight) // Standard Error: 1_000 - .saturating_add((66_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((61_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -286,27 +286,27 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (21_491_000 as Weight) + (21_548_000 as Weight) // Standard Error: 1_000 - .saturating_add((121_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((123_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (11_767_000 as Weight) + (11_797_000 as Weight) // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((117_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (11_959_000 as Weight) + (11_930_000 as Weight) // Standard Error: 1_000 - .saturating_add((111_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((122_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -319,15 +319,15 @@ impl WeightInfo for () { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (42_599_000 as Weight) + (42_560_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (25_521_000 as Weight) + (25_603_000 as Weight) // Standard Error: 1_000 - .saturating_add((171_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((167_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -335,9 +335,9 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (34_035_000 as Weight) - // Standard Error: 1_000 - .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) + (34_248_000 as Weight) + // Standard Error: 2_000 + .saturating_add((135_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -345,16 +345,16 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (33_910_000 as Weight) - // Standard Error: 1_000 - .saturating_add((147_000 as Weight).saturating_mul(r as Weight)) + (33_927_000 as Weight) + // Standard Error: 2_000 + .saturating_add((138_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (14_874_000 as Weight) + (14_714_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -365,45 +365,45 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (49_557_000 as Weight) + (49_423_000 as Weight) // Standard Error: 3_000 - .saturating_add((267_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((275_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (7_540_000 as Weight) + (7_321_000 as Weight) // Standard Error: 0 - .saturating_add((76_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((75_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (1_272_000 as Weight) + (1_325_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (1_274_000 as Weight) + (1_283_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (15_216_000 as Weight) + (15_355_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (16_713_000 as Weight) + (16_597_000 as Weight) // Standard Error: 0 - .saturating_add((92_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((90_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -411,23 +411,23 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (37_990_000 as Weight) + (37_695_000 as Weight) // Standard Error: 2_000 - .saturating_add((259_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((258_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (9_756_000 as Weight) + (9_456_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (19_408_000 as Weight) + (19_915_000 as Weight) // Standard Error: 1_000 - .saturating_add((650_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((609_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -435,9 +435,9 @@ impl WeightInfo for () { // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (2_134_000 as Weight) - // Standard Error: 3_000 - .saturating_add((3_041_000 as Weight).saturating_mul(r as Weight)) + (3_787_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_852_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -449,9 +449,9 @@ impl WeightInfo for () { // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - (6_357_000 as Weight) - // Standard Error: 3_000 - .saturating_add((3_054_000 as Weight).saturating_mul(r as Weight)) + (7_890_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_856_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -460,9 +460,9 @@ impl WeightInfo for () { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (30_822_000 as Weight) + (31_190_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_826_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_753_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) @@ -471,9 +471,9 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (15_307_000 as Weight) + (15_121_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_827_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_852_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -481,12 +481,12 @@ impl WeightInfo for () { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (1_624_000 as Weight) + (1_583_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (22_731_000 as Weight) + (22_681_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -494,7 +494,7 @@ impl WeightInfo for () { } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (15_518_000 as Weight) + (15_599_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -503,7 +503,7 @@ impl WeightInfo for () { // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (23_749_000 as Weight) + (23_663_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -513,9 +513,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (21_818_000 as Weight) + (21_928_000 as Weight) // Standard Error: 1_000 - .saturating_add((66_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((61_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -523,27 +523,27 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (21_491_000 as Weight) + (21_548_000 as Weight) // Standard Error: 1_000 - .saturating_add((121_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((123_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (11_767_000 as Weight) + (11_797_000 as Weight) // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((117_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (11_959_000 as Weight) + (11_930_000 as Weight) // Standard Error: 1_000 - .saturating_add((111_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((122_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 8e627b246d376..99e149eff2410 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_election_provider_multi_phase //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/optimized/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -32,7 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./weights-optimized/frame/election-provider-multi-phase/src//weights.rs +// --output=./frame/election-provider-multi-phase/src/weights.rs // --template=.maintain/frame-weight-template.hbs // --header=HEADER-APACHE2 // --raw @@ -70,33 +70,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (12_360_000 as Weight) + (12_763_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (12_981_000 as Weight) + (13_195_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (12_684_000 as Weight) + (12_782_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (27_272_000 as Weight) + (27_421_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (20_798_000 as Weight) + (21_325_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -104,11 +104,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (13_760_000 as Weight) + (0 as Weight) // Standard Error: 1_000 - .saturating_add((201_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((216_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 3_000 - .saturating_add((49_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -121,11 +121,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (108_461_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_318_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 5_000 - .saturating_add((194_000 as Weight).saturating_mul(d as Weight)) + (38_368_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_414_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 7_000 + .saturating_add((175_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -136,9 +136,9 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit(c: u32, ) -> Weight { - (39_721_000 as Weight) - // Standard Error: 24_000 - .saturating_add((298_000 as Weight).saturating_mul(c as Weight)) + (39_488_000 as Weight) + // Standard Error: 22_000 + .saturating_add((230_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -151,14 +151,14 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_000 - .saturating_add((1_612_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 8_000 - .saturating_add((105_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 13_000 - .saturating_add((7_024_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 20_000 - .saturating_add((1_361_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 2_000 + .saturating_add((1_544_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 5_000 + .saturating_add((60_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 9_000 + .saturating_add((6_555_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 14_000 + .saturating_add((1_318_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -168,14 +168,14 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_000 - .saturating_add((1_639_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 5_000 - .saturating_add((138_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 8_000 - .saturating_add((5_665_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 13_000 - .saturating_add((980_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 3_000 + .saturating_add((1_527_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 6_000 + .saturating_add((151_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 10_000 + .saturating_add((5_433_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 15_000 + .saturating_add((1_420_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) } } @@ -191,33 +191,33 @@ impl WeightInfo for () { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (12_360_000 as Weight) + (12_763_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (12_981_000 as Weight) + (13_195_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (12_684_000 as Weight) + (12_782_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (27_272_000 as Weight) + (27_421_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (20_798_000 as Weight) + (21_325_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -225,11 +225,11 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (13_760_000 as Weight) + (0 as Weight) // Standard Error: 1_000 - .saturating_add((201_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((216_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 3_000 - .saturating_add((49_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -242,11 +242,11 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (108_461_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_318_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 5_000 - .saturating_add((194_000 as Weight).saturating_mul(d as Weight)) + (38_368_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_414_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 7_000 + .saturating_add((175_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -257,9 +257,9 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit(c: u32, ) -> Weight { - (39_721_000 as Weight) - // Standard Error: 24_000 - .saturating_add((298_000 as Weight).saturating_mul(c as Weight)) + (39_488_000 as Weight) + // Standard Error: 22_000 + .saturating_add((230_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -272,14 +272,14 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_000 - .saturating_add((1_612_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 8_000 - .saturating_add((105_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 13_000 - .saturating_add((7_024_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 20_000 - .saturating_add((1_361_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 2_000 + .saturating_add((1_544_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 5_000 + .saturating_add((60_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 9_000 + .saturating_add((6_555_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 14_000 + .saturating_add((1_318_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -289,14 +289,14 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_000 - .saturating_add((1_639_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 5_000 - .saturating_add((138_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 8_000 - .saturating_add((5_665_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 13_000 - .saturating_add((980_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 3_000 + .saturating_add((1_527_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 6_000 + .saturating_add((151_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 10_000 + .saturating_add((5_433_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 15_000 + .saturating_add((1_420_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) } } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 57cb1b718fb7b..22c1c1cbeb406 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/optimized/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -32,7 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./weights-optimized/frame/elections-phragmen/src//weights.rs +// --output=./frame/elections-phragmen/src/weights.rs // --template=.maintain/frame-weight-template.hbs // --header=HEADER-APACHE2 // --raw @@ -70,9 +70,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_equal(v: u32, ) -> Weight { - (24_231_000 as Weight) - // Standard Error: 4_000 - .saturating_add((305_000 as Weight).saturating_mul(v as Weight)) + (23_406_000 as Weight) + // Standard Error: 6_000 + .saturating_add((270_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -82,9 +82,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_more(v: u32, ) -> Weight { - (37_524_000 as Weight) + (35_660_000 as Weight) // Standard Error: 6_000 - .saturating_add((285_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((316_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -94,16 +94,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_less(v: u32, ) -> Weight { - (37_350_000 as Weight) - // Standard Error: 7_000 - .saturating_add((311_000 as Weight).saturating_mul(v as Weight)) + (35_999_000 as Weight) + // Standard Error: 6_000 + .saturating_add((299_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (35_119_000 as Weight) + (33_692_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -111,17 +111,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) fn submit_candidacy(c: u32, ) -> Weight { - (36_110_000 as Weight) + (35_506_000 as Weight) // Standard Error: 1_000 - .saturating_add((193_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((192_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (30_976_000 as Weight) + (31_402_000 as Weight) // Standard Error: 1_000 - .saturating_add((129_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((113_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -131,13 +131,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (44_456_000 as Weight) + (42_727_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (31_990_000 as Weight) + (30_638_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -152,13 +152,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (51_221_000 as Weight) + (49_317_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Elections RunnersUp (r:1 w:0) fn remove_member_wrong_refund() -> Weight { - (4_773_000 as Weight) + (4_688_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Elections Voting (r:251 w:250) @@ -169,8 +169,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:250 w:250) fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 31_000 - .saturating_add((51_744_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 36_000 + .saturating_add((51_016_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -186,12 +186,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_744_000 - .saturating_add((29_677_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 725_000 - .saturating_add((51_480_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 1_760_000 + .saturating_add((29_569_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 732_000 + .saturating_add((51_842_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 49_000 - .saturating_add((3_491_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((3_546_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) @@ -206,9 +206,9 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_equal(v: u32, ) -> Weight { - (24_231_000 as Weight) - // Standard Error: 4_000 - .saturating_add((305_000 as Weight).saturating_mul(v as Weight)) + (23_406_000 as Weight) + // Standard Error: 6_000 + .saturating_add((270_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -218,9 +218,9 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_more(v: u32, ) -> Weight { - (37_524_000 as Weight) + (35_660_000 as Weight) // Standard Error: 6_000 - .saturating_add((285_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((316_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -230,16 +230,16 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_less(v: u32, ) -> Weight { - (37_350_000 as Weight) - // Standard Error: 7_000 - .saturating_add((311_000 as Weight).saturating_mul(v as Weight)) + (35_999_000 as Weight) + // Standard Error: 6_000 + .saturating_add((299_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (35_119_000 as Weight) + (33_692_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -247,17 +247,17 @@ impl WeightInfo for () { // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) fn submit_candidacy(c: u32, ) -> Weight { - (36_110_000 as Weight) + (35_506_000 as Weight) // Standard Error: 1_000 - .saturating_add((193_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((192_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (30_976_000 as Weight) + (31_402_000 as Weight) // Standard Error: 1_000 - .saturating_add((129_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((113_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -267,13 +267,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (44_456_000 as Weight) + (42_727_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (31_990_000 as Weight) + (30_638_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -288,13 +288,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (51_221_000 as Weight) + (49_317_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Elections RunnersUp (r:1 w:0) fn remove_member_wrong_refund() -> Weight { - (4_773_000 as Weight) + (4_688_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Elections Voting (r:251 w:250) @@ -305,8 +305,8 @@ impl WeightInfo for () { // Storage: System Account (r:250 w:250) fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 31_000 - .saturating_add((51_744_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 36_000 + .saturating_add((51_016_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -322,12 +322,12 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_744_000 - .saturating_add((29_677_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 725_000 - .saturating_add((51_480_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 1_760_000 + .saturating_add((29_569_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 732_000 + .saturating_add((51_842_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 49_000 - .saturating_add((3_491_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((3_546_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) diff --git a/frame/gilt/src/weights.rs b/frame/gilt/src/weights.rs index b56b6051a9aee..6084d494c5c3a 100644 --- a/frame/gilt/src/weights.rs +++ b/frame/gilt/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_gilt //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/gilt/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -62,44 +62,44 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - (32_876_000 as Weight) + (32_753_000 as Weight) // Standard Error: 0 - .saturating_add((97_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((96_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - (125_854_000 as Weight) + (124_814_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - (33_643_000 as Weight) + (33_544_000 as Weight) // Standard Error: 0 - .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((86_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - (2_570_000 as Weight) + (2_648_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - (40_854_000 as Weight) + (41_549_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - (1_598_000 as Weight) + (1_583_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) @@ -107,9 +107,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - (34_848_000 as Weight) + (35_836_000 as Weight) // Standard Error: 1_000 - .saturating_add((3_951_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((4_008_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(b as Weight))) @@ -119,9 +119,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - (9_735_000 as Weight) + (12_139_000 as Weight) // Standard Error: 6_000 - .saturating_add((7_873_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((7_819_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(q as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -134,44 +134,44 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - (32_876_000 as Weight) + (32_753_000 as Weight) // Standard Error: 0 - .saturating_add((97_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((96_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - (125_854_000 as Weight) + (124_814_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - (33_643_000 as Weight) + (33_544_000 as Weight) // Standard Error: 0 - .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((86_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - (2_570_000 as Weight) + (2_648_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - (40_854_000 as Weight) + (41_549_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - (1_598_000 as Weight) + (1_583_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) @@ -179,9 +179,9 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - (34_848_000 as Weight) + (35_836_000 as Weight) // Standard Error: 1_000 - .saturating_add((3_951_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((4_008_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(b as Weight))) @@ -191,9 +191,9 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - (9_735_000 as Weight) + (12_139_000 as Weight) // Standard Error: 6_000 - .saturating_add((7_873_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((7_819_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(q as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 1d0a7825ec403..cf164d3cbd73f 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_identity //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/identity/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -69,19 +69,19 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:1) fn add_registrar(r: u32, ) -> Weight { - (12_513_000 as Weight) - // Standard Error: 4_000 - .saturating_add((257_000 as Weight).saturating_mul(r as Weight)) + (13_150_000 as Weight) + // Standard Error: 3_000 + .saturating_add((253_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn set_identity(r: u32, x: u32, ) -> Weight { - (27_904_000 as Weight) + (27_745_000 as Weight) // Standard Error: 7_000 - .saturating_add((215_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 0 - .saturating_add((294_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((210_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_000 + .saturating_add((289_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -89,9 +89,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) fn set_subs_new(s: u32, ) -> Weight { - (24_530_000 as Weight) + (25_184_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_914_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_722_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -101,9 +101,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) fn set_subs_old(p: u32, ) -> Weight { - (23_957_000 as Weight) + (24_144_000 as Weight) // Standard Error: 0 - .saturating_add((954_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((890_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -112,13 +112,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (31_213_000 as Weight) + (32_167_000 as Weight) // Standard Error: 8_000 - .saturating_add((99_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((46_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((931_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((875_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((188_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((184_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -126,27 +126,27 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn request_judgement(r: u32, x: u32, ) -> Weight { - (30_691_000 as Weight) - // Standard Error: 4_000 - .saturating_add((269_000 as Weight).saturating_mul(r as Weight)) + (30_009_000 as Weight) + // Standard Error: 3_000 + .saturating_add((287_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((338_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((331_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn cancel_request(r: u32, x: u32, ) -> Weight { - (27_356_000 as Weight) + (28_195_000 as Weight) // Standard Error: 3_000 - .saturating_add((179_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((137_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((335_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((328_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fee(r: u32, ) -> Weight { - (4_761_000 as Weight) + (5_080_000 as Weight) // Standard Error: 2_000 .saturating_add((202_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -154,28 +154,28 @@ impl WeightInfo for SubstrateWeight { } // Storage: Identity Registrars (r:1 w:1) fn set_account_id(r: u32, ) -> Weight { - (4_801_000 as Weight) - // Standard Error: 3_000 - .saturating_add((211_000 as Weight).saturating_mul(r as Weight)) + (5_298_000 as Weight) + // Standard Error: 2_000 + .saturating_add((195_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fields(r: u32, ) -> Weight { - (4_756_000 as Weight) + (5_263_000 as Weight) // Standard Error: 2_000 - .saturating_add((204_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((191_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn provide_judgement(r: u32, x: u32, ) -> Weight { - (21_047_000 as Weight) + (21_511_000 as Weight) // Standard Error: 3_000 - .saturating_add((246_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((219_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((327_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -184,11 +184,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (41_324_000 as Weight) - // Standard Error: 7_000 - .saturating_add((192_000 as Weight).saturating_mul(r as Weight)) + (40_654_000 as Weight) + // Standard Error: 6_000 + .saturating_add((179_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((951_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((908_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -197,18 +197,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn add_sub(s: u32, ) -> Weight { - (31_405_000 as Weight) + (31_573_000 as Weight) // Standard Error: 1_000 - .saturating_add((160_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((151_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) fn rename_sub(s: u32, ) -> Weight { - (10_622_000 as Weight) + (10_452_000 as Weight) // Standard Error: 0 - .saturating_add((47_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((45_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -216,18 +216,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn remove_sub(s: u32, ) -> Weight { - (32_765_000 as Weight) + (32_711_000 as Weight) // Standard Error: 1_000 - .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((150_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn quit_sub(s: u32, ) -> Weight { - (21_925_000 as Weight) - // Standard Error: 1_000 - .saturating_add((156_000 as Weight).saturating_mul(s as Weight)) + (21_975_000 as Weight) + // Standard Error: 0 + .saturating_add((149_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -237,19 +237,19 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:1) fn add_registrar(r: u32, ) -> Weight { - (12_513_000 as Weight) - // Standard Error: 4_000 - .saturating_add((257_000 as Weight).saturating_mul(r as Weight)) + (13_150_000 as Weight) + // Standard Error: 3_000 + .saturating_add((253_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn set_identity(r: u32, x: u32, ) -> Weight { - (27_904_000 as Weight) + (27_745_000 as Weight) // Standard Error: 7_000 - .saturating_add((215_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 0 - .saturating_add((294_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((210_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_000 + .saturating_add((289_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -257,9 +257,9 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) fn set_subs_new(s: u32, ) -> Weight { - (24_530_000 as Weight) + (25_184_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_914_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_722_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -269,9 +269,9 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) fn set_subs_old(p: u32, ) -> Weight { - (23_957_000 as Weight) + (24_144_000 as Weight) // Standard Error: 0 - .saturating_add((954_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((890_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -280,13 +280,13 @@ impl WeightInfo for () { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (31_213_000 as Weight) + (32_167_000 as Weight) // Standard Error: 8_000 - .saturating_add((99_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((46_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((931_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((875_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((188_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((184_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -294,27 +294,27 @@ impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn request_judgement(r: u32, x: u32, ) -> Weight { - (30_691_000 as Weight) - // Standard Error: 4_000 - .saturating_add((269_000 as Weight).saturating_mul(r as Weight)) + (30_009_000 as Weight) + // Standard Error: 3_000 + .saturating_add((287_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((338_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((331_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn cancel_request(r: u32, x: u32, ) -> Weight { - (27_356_000 as Weight) + (28_195_000 as Weight) // Standard Error: 3_000 - .saturating_add((179_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((137_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((335_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((328_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fee(r: u32, ) -> Weight { - (4_761_000 as Weight) + (5_080_000 as Weight) // Standard Error: 2_000 .saturating_add((202_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -322,28 +322,28 @@ impl WeightInfo for () { } // Storage: Identity Registrars (r:1 w:1) fn set_account_id(r: u32, ) -> Weight { - (4_801_000 as Weight) - // Standard Error: 3_000 - .saturating_add((211_000 as Weight).saturating_mul(r as Weight)) + (5_298_000 as Weight) + // Standard Error: 2_000 + .saturating_add((195_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fields(r: u32, ) -> Weight { - (4_756_000 as Weight) + (5_263_000 as Weight) // Standard Error: 2_000 - .saturating_add((204_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((191_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn provide_judgement(r: u32, x: u32, ) -> Weight { - (21_047_000 as Weight) + (21_511_000 as Weight) // Standard Error: 3_000 - .saturating_add((246_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((219_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((327_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -352,11 +352,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (41_324_000 as Weight) - // Standard Error: 7_000 - .saturating_add((192_000 as Weight).saturating_mul(r as Weight)) + (40_654_000 as Weight) + // Standard Error: 6_000 + .saturating_add((179_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((951_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((908_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -365,18 +365,18 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn add_sub(s: u32, ) -> Weight { - (31_405_000 as Weight) + (31_573_000 as Weight) // Standard Error: 1_000 - .saturating_add((160_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((151_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) fn rename_sub(s: u32, ) -> Weight { - (10_622_000 as Weight) + (10_452_000 as Weight) // Standard Error: 0 - .saturating_add((47_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((45_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -384,18 +384,18 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn remove_sub(s: u32, ) -> Weight { - (32_765_000 as Weight) + (32_711_000 as Weight) // Standard Error: 1_000 - .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((150_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn quit_sub(s: u32, ) -> Weight { - (21_925_000 as Weight) - // Standard Error: 1_000 - .saturating_add((156_000 as Weight).saturating_mul(s as Weight)) + (21_975_000 as Weight) + // Standard Error: 0 + .saturating_add((149_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index 4fa5727251b3a..f7d4d1441da27 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_im_online //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/optimized/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -32,7 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./weights-optimized/frame/im-online/src//weights.rs +// --output=./frame/im-online/src/weights.rs // --template=.maintain/frame-weight-template.hbs // --header=HEADER-APACHE2 // --raw @@ -58,11 +58,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - (73_594_000 as Weight) + (74_137_000 as Weight) // Standard Error: 0 - .saturating_add((128_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((125_000 as Weight).saturating_mul(k as Weight)) // Standard Error: 0 - .saturating_add((295_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((291_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -76,11 +76,11 @@ impl WeightInfo for () { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - (73_594_000 as Weight) + (74_137_000 as Weight) // Standard Error: 0 - .saturating_add((128_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((125_000 as Weight).saturating_mul(k as Weight)) // Standard Error: 0 - .saturating_add((295_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((291_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 569af75af6dc8..1687237394fbd 100644 --- a/frame/indices/src/weights.rs +++ b/frame/indices/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_indices //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/indices/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -58,33 +58,33 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - (20_754_000 as Weight) + (21_121_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (26_655_000 as Weight) + (26_843_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - (22_112_000 as Weight) + (22_174_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (22_175_000 as Weight) + (22_191_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - (24_344_000 as Weight) + (24_813_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -94,33 +94,33 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - (20_754_000 as Weight) + (21_121_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (26_655_000 as Weight) + (26_843_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - (22_112_000 as Weight) + (22_174_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (22_175_000 as Weight) + (22_191_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - (24_344_000 as Weight) + (24_813_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index 080222125c844..3b6114a73cfaa 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_lottery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/lottery/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -65,28 +65,28 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (38_270_000 as Weight) + (37_257_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (8_830_000 as Weight) - // Standard Error: 7_000 - .saturating_add((291_000 as Weight).saturating_mul(n as Weight)) + (8_966_000 as Weight) + // Standard Error: 5_000 + .saturating_add((302_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (31_404_000 as Weight) + (32_282_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (3_825_000 as Weight) + (3_903_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -96,7 +96,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (49_760_000 as Weight) + (51_489_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -107,7 +107,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (53_159_000 as Weight) + (53_046_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -123,28 +123,28 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (38_270_000 as Weight) + (37_257_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (8_830_000 as Weight) - // Standard Error: 7_000 - .saturating_add((291_000 as Weight).saturating_mul(n as Weight)) + (8_966_000 as Weight) + // Standard Error: 5_000 + .saturating_add((302_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (31_404_000 as Weight) + (32_282_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (3_825_000 as Weight) + (3_903_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -154,7 +154,7 @@ impl WeightInfo for () { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (49_760_000 as Weight) + (51_489_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -165,7 +165,7 @@ impl WeightInfo for () { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (53_159_000 as Weight) + (53_046_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 59215d3a5bff6..0d4936cfba1f9 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_membership //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/membership/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -63,9 +63,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - (14_403_000 as Weight) - // Standard Error: 1_000 - .saturating_add((94_000 as Weight).saturating_mul(m as Weight)) + (14_884_000 as Weight) + // Standard Error: 0 + .saturating_add((95_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -75,9 +75,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - (17_005_000 as Weight) + (17_612_000 as Weight) // Standard Error: 0 - .saturating_add((90_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((86_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -87,7 +87,7 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - (17_210_000 as Weight) + (17_580_000 as Weight) // Standard Error: 0 .saturating_add((98_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -99,9 +99,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - (17_425_000 as Weight) + (17_610_000 as Weight) // Standard Error: 0 - .saturating_add((194_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((199_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -111,9 +111,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - (17_948_000 as Weight) + (18_208_000 as Weight) // Standard Error: 0 - .saturating_add((95_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((96_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -121,18 +121,18 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - (4_579_000 as Weight) + (4_661_000 as Weight) // Standard Error: 0 - .saturating_add((71_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((70_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - (1_481_000 as Weight) + (1_574_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } } @@ -144,9 +144,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - (14_403_000 as Weight) - // Standard Error: 1_000 - .saturating_add((94_000 as Weight).saturating_mul(m as Weight)) + (14_884_000 as Weight) + // Standard Error: 0 + .saturating_add((95_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -156,9 +156,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - (17_005_000 as Weight) + (17_612_000 as Weight) // Standard Error: 0 - .saturating_add((90_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((86_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -168,7 +168,7 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - (17_210_000 as Weight) + (17_580_000 as Weight) // Standard Error: 0 .saturating_add((98_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -180,9 +180,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - (17_425_000 as Weight) + (17_610_000 as Weight) // Standard Error: 0 - .saturating_add((194_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((199_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -192,9 +192,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - (17_948_000 as Weight) + (18_208_000 as Weight) // Standard Error: 0 - .saturating_add((95_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((96_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -202,18 +202,18 @@ impl WeightInfo for () { // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - (4_579_000 as Weight) + (4_661_000 as Weight) // Standard Error: 0 - .saturating_add((71_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((70_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - (1_481_000 as Weight) + (1_574_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } } diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index 5dc40197db554..501fb9c184194 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_multisig //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/multisig/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -62,16 +62,16 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn as_multi_threshold_1(z: u32, ) -> Weight { - (16_904_000 as Weight) + (16_534_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - (30_172_000 as Weight) - // Standard Error: 0 - .saturating_add((142_000 as Weight).saturating_mul(s as Weight)) + (30_917_000 as Weight) + // Standard Error: 1_000 + .saturating_add((131_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -81,9 +81,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - (33_039_000 as Weight) + (33_570_000 as Weight) // Standard Error: 1_000 - .saturating_add((140_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((138_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -91,9 +91,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - (20_752_000 as Weight) + (21_051_000 as Weight) // Standard Error: 0 - .saturating_add((133_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((126_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -102,7 +102,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - (33_198_000 as Weight) + (32_581_000 as Weight) // Standard Error: 1_000 .saturating_add((135_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 @@ -114,9 +114,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - (39_407_000 as Weight) + (39_215_000 as Weight) // Standard Error: 1_000 - .saturating_add((230_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((221_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -125,18 +125,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - (28_365_000 as Weight) + (28_572_000 as Weight) // Standard Error: 1_000 - .saturating_add((156_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((146_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - (17_960_000 as Weight) + (18_032_000 as Weight) // Standard Error: 0 - .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((151_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -144,18 +144,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - (56_920_000 as Weight) + (56_353_000 as Weight) // Standard Error: 1_000 - .saturating_add((243_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((239_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - (45_336_000 as Weight) - // Standard Error: 1_000 - .saturating_add((155_000 as Weight).saturating_mul(s as Weight)) + (44_544_000 as Weight) + // Standard Error: 0 + .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -164,16 +164,16 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn as_multi_threshold_1(z: u32, ) -> Weight { - (16_904_000 as Weight) + (16_534_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - (30_172_000 as Weight) - // Standard Error: 0 - .saturating_add((142_000 as Weight).saturating_mul(s as Weight)) + (30_917_000 as Weight) + // Standard Error: 1_000 + .saturating_add((131_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -183,9 +183,9 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - (33_039_000 as Weight) + (33_570_000 as Weight) // Standard Error: 1_000 - .saturating_add((140_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((138_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -193,9 +193,9 @@ impl WeightInfo for () { } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - (20_752_000 as Weight) + (21_051_000 as Weight) // Standard Error: 0 - .saturating_add((133_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((126_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -204,7 +204,7 @@ impl WeightInfo for () { // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - (33_198_000 as Weight) + (32_581_000 as Weight) // Standard Error: 1_000 .saturating_add((135_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 @@ -216,9 +216,9 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - (39_407_000 as Weight) + (39_215_000 as Weight) // Standard Error: 1_000 - .saturating_add((230_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((221_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -227,18 +227,18 @@ impl WeightInfo for () { // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - (28_365_000 as Weight) + (28_572_000 as Weight) // Standard Error: 1_000 - .saturating_add((156_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((146_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - (17_960_000 as Weight) + (18_032_000 as Weight) // Standard Error: 0 - .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((151_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -246,18 +246,18 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - (56_920_000 as Weight) + (56_353_000 as Weight) // Standard Error: 1_000 - .saturating_add((243_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((239_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - (45_336_000 as Weight) - // Standard Error: 1_000 - .saturating_add((155_000 as Weight).saturating_mul(s as Weight)) + (44_544_000 as Weight) + // Standard Error: 0 + .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index b0f22a49297b6..0d7f583727c99 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/preimage/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -93,58 +93,58 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (38_155_000 as Weight) + (39_239_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (24_132_000 as Weight) + (24_905_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (36_703_000 as Weight) + (37_451_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (23_056_000 as Weight) + (23_397_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (12_937_000 as Weight) + (13_407_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (4_460_000 as Weight) + (4_202_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (23_761_000 as Weight) + (24_858_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (13_829_000 as Weight) + (13_763_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (4_595_000 as Weight) + (4_262_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -182,58 +182,58 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (38_155_000 as Weight) + (39_239_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (24_132_000 as Weight) + (24_905_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (36_703_000 as Weight) + (37_451_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (23_056_000 as Weight) + (23_397_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (12_937_000 as Weight) + (13_407_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (4_460_000 as Weight) + (4_202_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (23_761_000 as Weight) + (24_858_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (13_829_000 as Weight) + (13_763_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (4_595_000 as Weight) + (4_262_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 4628ada8d3c8b..176f8683e0b5f 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_proxy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/proxy/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -63,42 +63,42 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - (13_623_000 as Weight) - // Standard Error: 2_000 - .saturating_add((121_000 as Weight).saturating_mul(p as Weight)) + (13_323_000 as Weight) + // Standard Error: 1_000 + .saturating_add((114_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - (29_560_000 as Weight) - // Standard Error: 2_000 - .saturating_add((259_000 as Weight).saturating_mul(a as Weight)) + (28_825_000 as Weight) + // Standard Error: 1_000 + .saturating_add((254_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((121_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn remove_announcement(a: u32, p: u32, ) -> Weight { - (21_004_000 as Weight) + (20_594_000 as Weight) // Standard Error: 1_000 - .saturating_add((266_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((259_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((13_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((15_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_announcement(a: u32, p: u32, ) -> Weight { - (20_992_000 as Weight) + (20_316_000 as Weight) // Standard Error: 1_000 - .saturating_add((266_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((265_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((14_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((18_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -106,52 +106,52 @@ impl WeightInfo for SubstrateWeight { // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - (28_118_000 as Weight) + (27_696_000 as Weight) // Standard Error: 2_000 - .saturating_add((250_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((241_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((118_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((111_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - (23_077_000 as Weight) + (22_849_000 as Weight) // Standard Error: 2_000 - .saturating_add((159_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((140_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - (19_919_000 as Weight) + (19_350_000 as Weight) // Standard Error: 2_000 - .saturating_add((155_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((147_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - (19_625_000 as Weight) + (18_878_000 as Weight) // Standard Error: 2_000 - .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((112_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - (26_066_000 as Weight) + (25_743_000 as Weight) // Standard Error: 2_000 - .saturating_add((37_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((25_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - (21_294_000 as Weight) + (20_484_000 as Weight) // Standard Error: 2_000 - .saturating_add((112_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -161,42 +161,42 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - (13_623_000 as Weight) - // Standard Error: 2_000 - .saturating_add((121_000 as Weight).saturating_mul(p as Weight)) + (13_323_000 as Weight) + // Standard Error: 1_000 + .saturating_add((114_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - (29_560_000 as Weight) - // Standard Error: 2_000 - .saturating_add((259_000 as Weight).saturating_mul(a as Weight)) + (28_825_000 as Weight) + // Standard Error: 1_000 + .saturating_add((254_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((121_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn remove_announcement(a: u32, p: u32, ) -> Weight { - (21_004_000 as Weight) + (20_594_000 as Weight) // Standard Error: 1_000 - .saturating_add((266_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((259_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((13_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((15_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_announcement(a: u32, p: u32, ) -> Weight { - (20_992_000 as Weight) + (20_316_000 as Weight) // Standard Error: 1_000 - .saturating_add((266_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((265_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((14_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((18_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -204,52 +204,52 @@ impl WeightInfo for () { // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - (28_118_000 as Weight) + (27_696_000 as Weight) // Standard Error: 2_000 - .saturating_add((250_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((241_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((118_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((111_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - (23_077_000 as Weight) + (22_849_000 as Weight) // Standard Error: 2_000 - .saturating_add((159_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((140_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - (19_919_000 as Weight) + (19_350_000 as Weight) // Standard Error: 2_000 - .saturating_add((155_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((147_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - (19_625_000 as Weight) + (18_878_000 as Weight) // Standard Error: 2_000 - .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((112_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - (26_066_000 as Weight) + (25_743_000 as Weight) // Standard Error: 2_000 - .saturating_add((37_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((25_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - (21_294_000 as Weight) + (20_484_000 as Weight) // Standard Error: 2_000 - .saturating_add((112_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index 281b25977cf49..dd00b8dfe6cd6 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/scheduler/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -70,9 +70,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (10_798_000 as Weight) - // Standard Error: 13_000 - .saturating_add((17_708_000 as Weight).saturating_mul(s as Weight)) + (11_587_000 as Weight) + // Standard Error: 17_000 + .saturating_add((17_428_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -83,9 +83,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (8_722_000 as Weight) - // Standard Error: 10_000 - .saturating_add((13_706_000 as Weight).saturating_mul(s as Weight)) + (8_965_000 as Weight) + // Standard Error: 11_000 + .saturating_add((13_410_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -95,9 +95,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (9_414_000 as Weight) - // Standard Error: 9_000 - .saturating_add((15_176_000 as Weight).saturating_mul(s as Weight)) + (8_654_000 as Weight) + // Standard Error: 17_000 + .saturating_add((14_990_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -107,9 +107,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (9_572_000 as Weight) - // Standard Error: 12_000 - .saturating_add((12_505_000 as Weight).saturating_mul(s as Weight)) + (9_303_000 as Weight) + // Standard Error: 10_000 + .saturating_add((12_244_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -119,9 +119,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (6_900_000 as Weight) - // Standard Error: 4_000 - .saturating_add((5_486_000 as Weight).saturating_mul(s as Weight)) + (7_506_000 as Weight) + // Standard Error: 3_000 + .saturating_add((5_208_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -130,9 +130,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (8_346_000 as Weight) + (8_046_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_079_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_914_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -140,9 +140,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (13_462_000 as Weight) - // Standard Error: 5_000 - .saturating_add((8_230_000 as Weight).saturating_mul(s as Weight)) + (13_704_000 as Weight) + // Standard Error: 4_000 + .saturating_add((8_186_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -150,9 +150,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (13_046_000 as Weight) - // Standard Error: 4_000 - .saturating_add((5_782_000 as Weight).saturating_mul(s as Weight)) + (12_668_000 as Weight) + // Standard Error: 5_000 + .saturating_add((5_868_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -161,53 +161,53 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (13_481_000 as Weight) - // Standard Error: 3_000 - .saturating_add((4_385_000 as Weight).saturating_mul(s as Weight)) + (13_946_000 as Weight) + // Standard Error: 4_000 + .saturating_add((4_367_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (13_081_000 as Weight) + (13_151_000 as Weight) // Standard Error: 4_000 - .saturating_add((3_434_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((3_455_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (13_863_000 as Weight) + (14_040_000 as Weight) // Standard Error: 1_000 - .saturating_add((87_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((89_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (13_695_000 as Weight) + (14_376_000 as Weight) // Standard Error: 1_000 - .saturating_add((594_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((576_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (16_506_000 as Weight) + (16_806_000 as Weight) // Standard Error: 1_000 - .saturating_add((99_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((102_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (15_685_000 as Weight) + (15_852_000 as Weight) // Standard Error: 2_000 - .saturating_add((604_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((590_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -220,9 +220,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (10_798_000 as Weight) - // Standard Error: 13_000 - .saturating_add((17_708_000 as Weight).saturating_mul(s as Weight)) + (11_587_000 as Weight) + // Standard Error: 17_000 + .saturating_add((17_428_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -233,9 +233,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (8_722_000 as Weight) - // Standard Error: 10_000 - .saturating_add((13_706_000 as Weight).saturating_mul(s as Weight)) + (8_965_000 as Weight) + // Standard Error: 11_000 + .saturating_add((13_410_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -245,9 +245,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (9_414_000 as Weight) - // Standard Error: 9_000 - .saturating_add((15_176_000 as Weight).saturating_mul(s as Weight)) + (8_654_000 as Weight) + // Standard Error: 17_000 + .saturating_add((14_990_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -257,9 +257,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (9_572_000 as Weight) - // Standard Error: 12_000 - .saturating_add((12_505_000 as Weight).saturating_mul(s as Weight)) + (9_303_000 as Weight) + // Standard Error: 10_000 + .saturating_add((12_244_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -269,9 +269,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (6_900_000 as Weight) - // Standard Error: 4_000 - .saturating_add((5_486_000 as Weight).saturating_mul(s as Weight)) + (7_506_000 as Weight) + // Standard Error: 3_000 + .saturating_add((5_208_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -280,9 +280,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (8_346_000 as Weight) + (8_046_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_079_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_914_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -290,9 +290,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (13_462_000 as Weight) - // Standard Error: 5_000 - .saturating_add((8_230_000 as Weight).saturating_mul(s as Weight)) + (13_704_000 as Weight) + // Standard Error: 4_000 + .saturating_add((8_186_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -300,9 +300,9 @@ impl WeightInfo for () { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (13_046_000 as Weight) - // Standard Error: 4_000 - .saturating_add((5_782_000 as Weight).saturating_mul(s as Weight)) + (12_668_000 as Weight) + // Standard Error: 5_000 + .saturating_add((5_868_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -311,53 +311,53 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (13_481_000 as Weight) - // Standard Error: 3_000 - .saturating_add((4_385_000 as Weight).saturating_mul(s as Weight)) + (13_946_000 as Weight) + // Standard Error: 4_000 + .saturating_add((4_367_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (13_081_000 as Weight) + (13_151_000 as Weight) // Standard Error: 4_000 - .saturating_add((3_434_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((3_455_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (13_863_000 as Weight) + (14_040_000 as Weight) // Standard Error: 1_000 - .saturating_add((87_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((89_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (13_695_000 as Weight) + (14_376_000 as Weight) // Standard Error: 1_000 - .saturating_add((594_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((576_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (16_506_000 as Weight) + (16_806_000 as Weight) // Standard Error: 1_000 - .saturating_add((99_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((102_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (15_685_000 as Weight) + (15_852_000 as Weight) // Standard Error: 2_000 - .saturating_add((604_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((590_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index 2cf5cd9c41929..39276fb0b17ee 100644 --- a/frame/session/src/weights.rs +++ b/frame/session/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_session //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/session/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -57,7 +57,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - (42_449_000 as Weight) + (42_131_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -65,7 +65,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - (32_778_000 as Weight) + (32_374_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -77,7 +77,7 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - (42_449_000 as Weight) + (42_131_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -85,7 +85,7 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - (32_778_000 as Weight) + (32_374_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 7721fbbd23714..42f762c721e4c 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/staking/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -86,7 +86,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (38_457_000 as Weight) + (37_688_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -96,7 +96,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (65_678_000 as Weight) + (63_507_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -110,7 +110,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (71_544_000 as Weight) + (70_634_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -119,9 +119,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (30_127_000 as Weight) + (30_002_000 as Weight) // Standard Error: 0 - .saturating_add((59_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -139,7 +139,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (59_131_000 as Weight) + (58_077_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(11 as Weight)) } @@ -155,16 +155,16 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (45_519_000 as Weight) + (44_603_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (16_645_000 as Weight) - // Standard Error: 12_000 - .saturating_add((8_194_000 as Weight).saturating_mul(k as Weight)) + (14_580_000 as Weight) + // Standard Error: 13_000 + .saturating_add((8_076_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -181,9 +181,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (50_227_000 as Weight) - // Standard Error: 12_000 - .saturating_add((3_546_000 as Weight).saturating_mul(n as Weight)) + (49_856_000 as Weight) + // Standard Error: 8_000 + .saturating_add((3_430_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(6 as Weight)) @@ -196,49 +196,49 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (44_294_000 as Weight) + (43_815_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (7_556_000 as Weight) + (7_553_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (15_826_000 as Weight) + (15_177_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (1_141_000 as Weight) + (1_090_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (1_152_000 as Weight) + (1_169_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (1_169_000 as Weight) + (1_089_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (1_134_000 as Weight) + (1_144_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (1_641_000 as Weight) + (1_612_000 as Weight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((50_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) @@ -255,18 +255,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (57_227_000 as Weight) + (56_103_000 as Weight) // Standard Error: 1_000 - .saturating_add((817_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((798_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (950_241_000 as Weight) - // Standard Error: 56_000 - .saturating_add((4_960_000 as Weight).saturating_mul(s as Weight)) + (942_911_000 as Weight) + // Standard Error: 55_000 + .saturating_add((4_973_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -281,9 +281,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (73_561_000 as Weight) + (77_948_000 as Weight) // Standard Error: 13_000 - .saturating_add((24_039_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((23_507_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -301,9 +301,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (105_296_000 as Weight) - // Standard Error: 18_000 - .saturating_add((33_989_000 as Weight).saturating_mul(n as Weight)) + (94_386_000 as Weight) + // Standard Error: 19_000 + .saturating_add((32_763_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -316,9 +316,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (65_108_000 as Weight) - // Standard Error: 3_000 - .saturating_add((72_000 as Weight).saturating_mul(l as Weight)) + (63_577_000 as Weight) + // Standard Error: 2_000 + .saturating_add((47_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(9 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -333,8 +333,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 54_000 - .saturating_add((19_731_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 57_000 + .saturating_add((19_691_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) .saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -353,9 +353,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (63_115_000 as Weight) + (61_871_000 as Weight) // Standard Error: 0 - .saturating_add((812_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((796_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -380,10 +380,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 800_000 - .saturating_add((219_877_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 40_000 - .saturating_add((31_701_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 823_000 + .saturating_add((218_725_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 41_000 + .saturating_add((31_349_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -401,10 +401,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 88_000 - .saturating_add((18_183_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 88_000 - .saturating_add((21_345_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 86_000 + .saturating_add((18_168_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 86_000 + .saturating_add((21_061_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 2_951_000 + .saturating_add((8_164_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(204 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -413,8 +415,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 25_000 - .saturating_add((7_691_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 29_000 + .saturating_add((7_761_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -425,12 +427,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs() -> Weight { - (3_324_000 as Weight) + (3_586_000 as Weight) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking ChillThreshold (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking ChillThreshold (r:1 w:0) // Storage: Staking MaxNominatorsCount (r:1 w:0) // Storage: Staking CounterForNominators (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) @@ -439,7 +441,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (54_254_000 as Weight) + (54_681_000 as Weight) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -454,7 +456,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (38_457_000 as Weight) + (37_688_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -464,7 +466,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (65_678_000 as Weight) + (63_507_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } @@ -478,7 +480,7 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (71_544_000 as Weight) + (70_634_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -487,9 +489,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (30_127_000 as Weight) + (30_002_000 as Weight) // Standard Error: 0 - .saturating_add((59_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -507,7 +509,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (59_131_000 as Weight) + (58_077_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } @@ -523,16 +525,16 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (45_519_000 as Weight) + (44_603_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (16_645_000 as Weight) - // Standard Error: 12_000 - .saturating_add((8_194_000 as Weight).saturating_mul(k as Weight)) + (14_580_000 as Weight) + // Standard Error: 13_000 + .saturating_add((8_076_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -549,9 +551,9 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (50_227_000 as Weight) - // Standard Error: 12_000 - .saturating_add((3_546_000 as Weight).saturating_mul(n as Weight)) + (49_856_000 as Weight) + // Standard Error: 8_000 + .saturating_add((3_430_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) @@ -564,49 +566,49 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (44_294_000 as Weight) + (43_815_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (7_556_000 as Weight) + (7_553_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (15_826_000 as Weight) + (15_177_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (1_141_000 as Weight) + (1_090_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (1_152_000 as Weight) + (1_169_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (1_169_000 as Weight) + (1_089_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (1_134_000 as Weight) + (1_144_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (1_641_000 as Weight) + (1_612_000 as Weight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((50_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) @@ -623,18 +625,18 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (57_227_000 as Weight) + (56_103_000 as Weight) // Standard Error: 1_000 - .saturating_add((817_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((798_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (950_241_000 as Weight) - // Standard Error: 56_000 - .saturating_add((4_960_000 as Weight).saturating_mul(s as Weight)) + (942_911_000 as Weight) + // Standard Error: 55_000 + .saturating_add((4_973_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -649,9 +651,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (73_561_000 as Weight) + (77_948_000 as Weight) // Standard Error: 13_000 - .saturating_add((24_039_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((23_507_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -669,9 +671,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (105_296_000 as Weight) - // Standard Error: 18_000 - .saturating_add((33_989_000 as Weight).saturating_mul(n as Weight)) + (94_386_000 as Weight) + // Standard Error: 19_000 + .saturating_add((32_763_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -684,9 +686,9 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (65_108_000 as Weight) - // Standard Error: 3_000 - .saturating_add((72_000 as Weight).saturating_mul(l as Weight)) + (63_577_000 as Weight) + // Standard Error: 2_000 + .saturating_add((47_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(9 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -701,8 +703,8 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 54_000 - .saturating_add((19_731_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 57_000 + .saturating_add((19_691_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) .saturating_add(RocksDbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -721,9 +723,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (63_115_000 as Weight) + (61_871_000 as Weight) // Standard Error: 0 - .saturating_add((812_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((796_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -748,10 +750,10 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 800_000 - .saturating_add((219_877_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 40_000 - .saturating_add((31_701_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 823_000 + .saturating_add((218_725_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 41_000 + .saturating_add((31_349_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -769,10 +771,12 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 88_000 - .saturating_add((18_183_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 88_000 - .saturating_add((21_345_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 86_000 + .saturating_add((18_168_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 86_000 + .saturating_add((21_061_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 2_951_000 + .saturating_add((8_164_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(204 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -781,8 +785,8 @@ impl WeightInfo for () { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 25_000 - .saturating_add((7_691_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 29_000 + .saturating_add((7_761_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -793,12 +797,12 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs() -> Weight { - (3_324_000 as Weight) + (3_586_000 as Weight) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking ChillThreshold (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking ChillThreshold (r:1 w:0) // Storage: Staking MaxNominatorsCount (r:1 w:0) // Storage: Staking CounterForNominators (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) @@ -807,7 +811,7 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (54_254_000 as Weight) + (54_681_000 as Weight) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index 1fc35a41752a8..a016fe6e7d037 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for frame_system //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/optimized/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -32,7 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./weights-optimized/frame/system/src//weights.rs +// --output=./frame/system/src/weights.rs // --template=.maintain/frame-weight-template.hbs // --header=HEADER-APACHE2 // --raw @@ -68,7 +68,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (2_821_000 as Weight) + (2_864_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -76,21 +76,21 @@ impl WeightInfo for SubstrateWeight { fn set_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((385_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((389_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((286_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((285_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_prefix(p: u32, ) -> Weight { - (1_292_000 as Weight) + (753_000 as Weight) // Standard Error: 0 - .saturating_add((633_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((630_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } } @@ -108,7 +108,7 @@ impl WeightInfo for () { // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (2_821_000 as Weight) + (2_864_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -116,21 +116,21 @@ impl WeightInfo for () { fn set_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((385_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((389_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((286_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((285_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_prefix(p: u32, ) -> Weight { - (1_292_000 as Weight) + (753_000 as Weight) // Standard Error: 0 - .saturating_add((633_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((630_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } } diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index b0f4b9d30588d..33d7d6a4b9e37 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_timestamp //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/timestamp/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -56,12 +56,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - (5_191_000 as Weight) + (5_247_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (2_563_000 as Weight) + (2_604_000 as Weight) } } @@ -70,11 +70,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - (5_191_000 as Weight) + (5_247_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (2_563_000 as Weight) + (2_604_000 as Weight) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 154b6a67d8541..2ba15a0c2fcc0 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_tips //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/tips/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -60,7 +60,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - (26_318_000 as Weight) + (25_262_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -69,7 +69,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - (24_688_000 as Weight) + (24_162_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -77,20 +77,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - (17_395_000 as Weight) + (16_435_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 4_000 - .saturating_add((197_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((231_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - (10_783_000 as Weight) - // Standard Error: 6_000 - .saturating_add((568_000 as Weight).saturating_mul(t as Weight)) + (10_427_000 as Weight) + // Standard Error: 7_000 + .saturating_add((507_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -99,18 +99,18 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - (41_658_000 as Weight) - // Standard Error: 13_000 - .saturating_add((391_000 as Weight).saturating_mul(t as Weight)) + (40_901_000 as Weight) + // Standard Error: 10_000 + .saturating_add((281_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - (14_935_000 as Weight) - // Standard Error: 6_000 - .saturating_add((40_000 as Weight).saturating_mul(t as Weight)) + (14_636_000 as Weight) + // Standard Error: 4_000 + .saturating_add((29_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -121,7 +121,7 @@ impl WeightInfo for () { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - (26_318_000 as Weight) + (25_262_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -130,7 +130,7 @@ impl WeightInfo for () { // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - (24_688_000 as Weight) + (24_162_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -138,20 +138,20 @@ impl WeightInfo for () { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - (17_395_000 as Weight) + (16_435_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 4_000 - .saturating_add((197_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((231_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - (10_783_000 as Weight) - // Standard Error: 6_000 - .saturating_add((568_000 as Weight).saturating_mul(t as Weight)) + (10_427_000 as Weight) + // Standard Error: 7_000 + .saturating_add((507_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -160,18 +160,18 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - (41_658_000 as Weight) - // Standard Error: 13_000 - .saturating_add((391_000 as Weight).saturating_mul(t as Weight)) + (40_901_000 as Weight) + // Standard Error: 10_000 + .saturating_add((281_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - (14_935_000 as Weight) - // Standard Error: 6_000 - .saturating_add((40_000 as Weight).saturating_mul(t as Weight)) + (14_636_000 as Weight) + // Standard Error: 4_000 + .saturating_add((29_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index bdf4d2cf62221..a7033da7b80ce 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_transaction_storage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/optimized/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -32,7 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./weights-optimized/frame/transaction-storage/src//weights.rs +// --output=./frame/transaction-storage/src/weights.rs // --template=.maintain/frame-weight-template.hbs // --header=HEADER-APACHE2 // --raw @@ -74,7 +74,7 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - (43_773_000 as Weight) + (41_286_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -84,7 +84,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - (139_490_000 as Weight) + (136_957_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -112,7 +112,7 @@ impl WeightInfo for () { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - (43_773_000 as Weight) + (41_286_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -122,7 +122,7 @@ impl WeightInfo for () { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - (139_490_000 as Weight) + (136_957_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index ebe823ddb8cef..dcbf5983fa65c 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_treasury //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/treasury/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -58,23 +58,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (21_666_000 as Weight) + (21_673_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (25_008_000 as Weight) + (25_353_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (8_032_000 as Weight) + (8_164_000 as Weight) // Standard Error: 1_000 - .saturating_add((66_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((57_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -83,9 +83,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (25_541_000 as Weight) - // Standard Error: 19_000 - .saturating_add((27_399_000 as Weight).saturating_mul(p as Weight)) + (20_762_000 as Weight) + // Standard Error: 21_000 + .saturating_add((26_835_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -98,23 +98,23 @@ impl WeightInfo for () { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (21_666_000 as Weight) + (21_673_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (25_008_000 as Weight) + (25_353_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (8_032_000 as Weight) + (8_164_000 as Weight) // Standard Error: 1_000 - .saturating_add((66_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((57_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -123,9 +123,9 @@ impl WeightInfo for () { // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (25_541_000 as Weight) - // Standard Error: 19_000 - .saturating_add((27_399_000 as Weight).saturating_mul(p as Weight)) + (20_762_000 as Weight) + // Standard Error: 21_000 + .saturating_add((26_835_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 190ce74bbaa57..1df8fe0ff6650 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/uniques/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -76,14 +76,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (23_715_000 as Weight) + (24_063_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (12_854_000 as Weight) + (13_017_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -96,12 +96,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 13_000 - .saturating_add((9_291_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 13_000 - .saturating_add((957_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 13_000 - .saturating_add((862_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 14_000 + .saturating_add((9_248_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 14_000 + .saturating_add((854_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 14_000 + .saturating_add((758_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -113,7 +113,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (29_659_000 as Weight) + (29_865_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -121,7 +121,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (31_363_000 as Weight) + (31_603_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -129,7 +129,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (23_596_000 as Weight) + (23_331_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -137,8 +137,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_000 - .saturating_add((11_793_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 12_000 + .saturating_add((11_527_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -147,26 +147,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (17_708_000 as Weight) + (18_617_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (17_959_000 as Weight) + (18_618_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_class() -> Weight { - (14_034_000 as Weight) + (13_570_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_class() -> Weight { - (13_751_000 as Weight) + (13_937_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -174,20 +174,20 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (31_328_000 as Weight) + (31_021_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (14_586_000 as Weight) + (14_739_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_asset_status() -> Weight { - (16_374_000 as Weight) + (16_826_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -195,7 +195,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (36_952_000 as Weight) + (37_010_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -203,49 +203,49 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (35_230_000 as Weight) + (34_432_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (28_148_000 as Weight) + (28_575_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (29_027_000 as Weight) + (28_730_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_class_metadata() -> Weight { - (27_535_000 as Weight) + (28_225_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_class_metadata() -> Weight { - (26_707_000 as Weight) + (26_455_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (19_108_000 as Weight) + (19_587_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (19_779_000 as Weight) + (19_417_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -256,14 +256,14 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (23_715_000 as Weight) + (24_063_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (12_854_000 as Weight) + (13_017_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -276,12 +276,12 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 13_000 - .saturating_add((9_291_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 13_000 - .saturating_add((957_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 13_000 - .saturating_add((862_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 14_000 + .saturating_add((9_248_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 14_000 + .saturating_add((854_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 14_000 + .saturating_add((758_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -293,7 +293,7 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (29_659_000 as Weight) + (29_865_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -301,7 +301,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (31_363_000 as Weight) + (31_603_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -309,7 +309,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (23_596_000 as Weight) + (23_331_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -317,8 +317,8 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_000 - .saturating_add((11_793_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 12_000 + .saturating_add((11_527_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -327,26 +327,26 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (17_708_000 as Weight) + (18_617_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (17_959_000 as Weight) + (18_618_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_class() -> Weight { - (14_034_000 as Weight) + (13_570_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_class() -> Weight { - (13_751_000 as Weight) + (13_937_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -354,20 +354,20 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (31_328_000 as Weight) + (31_021_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (14_586_000 as Weight) + (14_739_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_asset_status() -> Weight { - (16_374_000 as Weight) + (16_826_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -375,7 +375,7 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (36_952_000 as Weight) + (37_010_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -383,49 +383,49 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (35_230_000 as Weight) + (34_432_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (28_148_000 as Weight) + (28_575_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (29_027_000 as Weight) + (28_730_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_class_metadata() -> Weight { - (27_535_000 as Weight) + (28_225_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_class_metadata() -> Weight { - (26_707_000 as Weight) + (26_455_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (19_108_000 as Weight) + (19_587_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (19_779_000 as Weight) + (19_417_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 3d80691210de0..e5f3cb0f58fd4 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_utility //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/utility/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -56,39 +56,39 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn batch(c: u32, ) -> Weight { - (15_877_000 as Weight) + (18_598_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_341_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_374_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (1_754_000 as Weight) + (1_650_000 as Weight) } fn batch_all(c: u32, ) -> Weight { - (16_581_000 as Weight) + (13_988_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_476_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_481_000 as Weight).saturating_mul(c as Weight)) } fn dispatch_as() -> Weight { - (8_294_000 as Weight) + (8_463_000 as Weight) } } // For backwards compatibility and tests impl WeightInfo for () { fn batch(c: u32, ) -> Weight { - (15_877_000 as Weight) + (18_598_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_341_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_374_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (1_754_000 as Weight) + (1_650_000 as Weight) } fn batch_all(c: u32, ) -> Weight { - (16_581_000 as Weight) + (13_988_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_476_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_481_000 as Weight).saturating_mul(c as Weight)) } fn dispatch_as() -> Weight { - (8_294_000 as Weight) + (8_463_000 as Weight) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index caf1880daefda..140c1889d6e54 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_vesting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// ./target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -34,7 +34,7 @@ // --heap-pages=4096 // --output=./frame/vesting/src/weights.rs // --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 +// --header=HEADER-APACHE2 // --raw #![cfg_attr(rustfmt, rustfmt_skip)] @@ -62,22 +62,22 @@ impl WeightInfo for SubstrateWeight { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - (27_545_000 as Weight) + (27_037_000 as Weight) // Standard Error: 1_000 - .saturating_add((111_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((78_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((69_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - (27_638_000 as Weight) + (26_627_000 as Weight) // Standard Error: 1_000 - .saturating_add((102_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((82_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((41_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -85,11 +85,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - (27_571_000 as Weight) + (26_672_000 as Weight) // Standard Error: 1_000 - .saturating_add((105_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((85_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((76_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -97,11 +97,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - (27_470_000 as Weight) + (26_682_000 as Weight) // Standard Error: 1_000 - .saturating_add((99_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((74_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -109,11 +109,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - (42_886_000 as Weight) + (42_066_000 as Weight) // Standard Error: 1_000 - .saturating_add((100_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((83_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 3_000 - .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -121,9 +121,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - (42_528_000 as Weight) + (41_672_000 as Weight) // Standard Error: 1_000 - .saturating_add((104_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((84_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 3_000 .saturating_add((46_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) @@ -133,11 +133,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (28_372_000 as Weight) - // Standard Error: 1_000 - .saturating_add((110_000 as Weight).saturating_mul(l as Weight)) + (27_627_000 as Weight) + // Standard Error: 0 + .saturating_add((86_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((71_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((68_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -145,11 +145,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (28_117_000 as Weight) + (27_143_000 as Weight) + // Standard Error: 0 + .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 1_000 - .saturating_add((108_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 2_000 - .saturating_add((76_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((72_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -160,22 +160,22 @@ impl WeightInfo for () { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - (27_545_000 as Weight) + (27_037_000 as Weight) // Standard Error: 1_000 - .saturating_add((111_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((78_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((69_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - (27_638_000 as Weight) + (26_627_000 as Weight) // Standard Error: 1_000 - .saturating_add((102_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((82_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((41_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -183,11 +183,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - (27_571_000 as Weight) + (26_672_000 as Weight) // Standard Error: 1_000 - .saturating_add((105_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((85_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((76_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -195,11 +195,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - (27_470_000 as Weight) + (26_682_000 as Weight) // Standard Error: 1_000 - .saturating_add((99_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((74_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -207,11 +207,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - (42_886_000 as Weight) + (42_066_000 as Weight) // Standard Error: 1_000 - .saturating_add((100_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((83_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 3_000 - .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -219,9 +219,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - (42_528_000 as Weight) + (41_672_000 as Weight) // Standard Error: 1_000 - .saturating_add((104_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((84_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 3_000 .saturating_add((46_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) @@ -231,11 +231,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (28_372_000 as Weight) - // Standard Error: 1_000 - .saturating_add((110_000 as Weight).saturating_mul(l as Weight)) + (27_627_000 as Weight) + // Standard Error: 0 + .saturating_add((86_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((71_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((68_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -243,11 +243,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (28_117_000 as Weight) + (27_143_000 as Weight) + // Standard Error: 0 + .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 1_000 - .saturating_add((108_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 2_000 - .saturating_add((76_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((72_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index a2a56a5bf22cf..ce9687f9ae0ef 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -21,3 +21,4 @@ walkdir = "2.3.2" wasm-gc-api = "0.1.11" ansi_term = "0.12.1" sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } +strum = { version = "0.23.0", features = ["derive"] } diff --git a/utils/wasm-builder/src/lib.rs b/utils/wasm-builder/src/lib.rs index f5e04dd7d774b..6a7f0d7ca3cd5 100644 --- a/utils/wasm-builder/src/lib.rs +++ b/utils/wasm-builder/src/lib.rs @@ -120,9 +120,11 @@ pub use builder::{WasmBuilder, WasmBuilderSelectProject}; const SKIP_BUILD_ENV: &str = "SKIP_WASM_BUILD"; /// Environment variable to force a certain build type when building the wasm binary. -/// Expects "debug" or "release" as value. +/// Expects "debug", "release" or "production" as value. /// -/// By default the WASM binary uses the same build type as the main cargo build. +/// When unset the WASM binary uses the same build type as the main cargo build with +/// the exception of a debug build: In this case the wasm build defaults to `release` in +/// order to avoid a slowdown when not explicitly requested. const WASM_BUILD_TYPE_ENV: &str = "WASM_BUILD_TYPE"; /// Environment variable to extend the `RUSTFLAGS` variable given to the wasm build. diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 9b5a33b6a6238..541c6290166c3 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -17,6 +17,8 @@ use crate::{write_file_if_changed, CargoCommandVersioned}; +use build_helper::rerun_if_changed; +use cargo_metadata::{CargoOpt, Metadata, MetadataCommand}; use std::{ borrow::ToOwned, collections::HashSet, @@ -26,13 +28,8 @@ use std::{ path::{Path, PathBuf}, process, }; - +use strum::{EnumIter, IntoEnumIterator}; use toml::value::Table; - -use build_helper::rerun_if_changed; - -use cargo_metadata::{CargoOpt, Metadata, MetadataCommand}; - use walkdir::WalkDir; /// Colorize an info message. @@ -128,9 +125,9 @@ pub(crate) fn create_and_compile( features_to_enable, ); - build_project(&project, default_rustflags, cargo_cmd); + let profile = build_project(&project, default_rustflags, cargo_cmd); let (wasm_binary, wasm_binary_compressed, bloaty) = - compact_wasm_file(&project, project_cargo_toml, wasm_binary_name); + compact_wasm_file(&project, profile, project_cargo_toml, wasm_binary_name); wasm_binary .as_ref() @@ -246,16 +243,22 @@ fn create_project_cargo_toml( let mut wasm_workspace_toml = Table::new(); - // Add `profile` with release and dev + // Add different profiles which are selected by setting `WASM_BUILD_TYPE`. let mut release_profile = Table::new(); release_profile.insert("panic".into(), "abort".into()); - release_profile.insert("lto".into(), true.into()); + release_profile.insert("lto".into(), "thin".into()); + + let mut production_profile = Table::new(); + production_profile.insert("inherits".into(), "release".into()); + production_profile.insert("lto".into(), "fat".into()); + production_profile.insert("codegen-units".into(), 1.into()); let mut dev_profile = Table::new(); dev_profile.insert("panic".into(), "abort".into()); let mut profile = Table::new(); profile.insert("release".into(), release_profile.into()); + profile.insert("production".into(), production_profile.into()); profile.insert("dev".into(), dev_profile.into()); wasm_workspace_toml.insert("profile".into(), profile.into()); @@ -420,25 +423,106 @@ fn create_project( wasm_project_folder } -/// Returns if the project should be built as a release. -fn is_release_build() -> bool { - if let Ok(var) = env::var(crate::WASM_BUILD_TYPE_ENV) { - match var.as_str() { - "release" => true, - "debug" => false, - var => panic!( - "Unexpected value for `{}` env variable: {}\nOne of the following are expected: `debug` or `release`.", - crate::WASM_BUILD_TYPE_ENV, - var, - ), +/// The cargo profile that is used to build the wasm project. +#[derive(Debug, EnumIter)] +enum Profile { + /// The `--profile dev` profile. + Debug, + /// The `--profile release` profile. + Release, + /// The `--profile production` profile. + Production, +} + +impl Profile { + /// Create a profile by detecting which profile is used for the main build. + /// + /// We cannot easily determine the profile that is used by the main cargo invocation + /// because the `PROFILE` environment variable won't contain any custom profiles like + /// "production". It would only contain the builtin profile where the custom profile + /// inherits from. This is why we inspect the build path to learn which profile is used. + /// + /// # Note + /// + /// Can be overriden by setting [`crate::WASM_BUILD_TYPE_ENV`]. + fn detect(wasm_project: &Path) -> Profile { + let (name, overriden) = if let Ok(name) = env::var(crate::WASM_BUILD_TYPE_ENV) { + (name, true) + } else { + // First go backwards to the beginning of the target directory. + // Then go forwards to find the "wbuild" directory. + // We need to go backwards first because when starting from the root there + // might be a chance that someone has a "wbuild" directory somewhere in the path. + let name = wasm_project + .components() + .rev() + .take_while(|c| c.as_os_str() != "target") + .collect::>() + .iter() + .rev() + .take_while(|c| c.as_os_str() != "wbuild") + .last() + .expect("We put the wasm project within a `target/.../wbuild` path; qed") + .as_os_str() + .to_str() + .expect("All our profile directory names are ascii; qed") + .to_string(); + (name, false) + }; + match (Profile::iter().find(|p| p.directory() == name), overriden) { + // When not overriden by a env variable we default to using the `Release` profile + // for the wasm build even when the main build uses the debug build. This + // is because the `Debug` profile is too slow for normal development activities. + (Some(Profile::Debug), false) => Profile::Release, + // For any other profile or when overriden we take it at face value. + (Some(profile), _) => profile, + // Invalid profile specified. + (None, _) => { + // We use println! + exit instead of a panic in order to have a cleaner output. + println!( + "Unexpected profile name: `{}`. One of the following is expected: {:?}", + name, + Profile::iter().map(|p| p.directory()).collect::>(), + ); + process::exit(1); + }, } - } else { - true + } + + /// The name of the profile as supplied to the cargo `--profile` cli option. + fn name(&self) -> &'static str { + match self { + Self::Debug => "dev", + Self::Release => "release", + Self::Production => "production", + } + } + + /// The sub directory within `target` where cargo places the build output. + /// + /// # Note + /// + /// Usually this is the same as [`Self::name`] with the exception of the debug + /// profile which is called `dev`. + fn directory(&self) -> &'static str { + match self { + Self::Debug => "debug", + _ => self.name(), + } + } + + /// Whether the resulting binary should be compacted and compressed. + fn wants_compact(&self) -> bool { + !matches!(self, Self::Debug) } } /// Build the project to create the WASM binary. -fn build_project(project: &Path, default_rustflags: &str, cargo_cmd: CargoCommandVersioned) { +fn build_project( + project: &Path, + default_rustflags: &str, + cargo_cmd: CargoCommandVersioned, +) -> Profile { let manifest_path = project.join("Cargo.toml"); let mut build_cmd = cargo_cmd.command(); @@ -467,16 +551,16 @@ fn build_project(project: &Path, default_rustflags: &str, cargo_cmd: CargoComman build_cmd.arg("--color=always"); } - if is_release_build() { - build_cmd.arg("--release"); - }; + let profile = Profile::detect(project); + build_cmd.arg("--profile"); + build_cmd.arg(profile.name()); println!("{}", colorize_info_message("Information that should be included in a bug report.")); println!("{} {:?}", colorize_info_message("Executing build command:"), build_cmd); println!("{} {}", colorize_info_message("Using rustc version:"), cargo_cmd.rustc_version()); match build_cmd.status().map(|s| s.success()) { - Ok(true) => {}, + Ok(true) => profile, // Use `process.exit(1)` to have a clean error output. _ => process::exit(1), } @@ -485,18 +569,17 @@ fn build_project(project: &Path, default_rustflags: &str, cargo_cmd: CargoComman /// Compact the WASM binary using `wasm-gc` and compress it using zstd. fn compact_wasm_file( project: &Path, + profile: Profile, cargo_manifest: &Path, wasm_binary_name: Option, ) -> (Option, Option, WasmBinaryBloaty) { - let is_release_build = is_release_build(); - let target = if is_release_build { "release" } else { "debug" }; let default_wasm_binary_name = get_wasm_binary_name(cargo_manifest); let wasm_file = project .join("target/wasm32-unknown-unknown") - .join(target) + .join(profile.directory()) .join(format!("{}.wasm", default_wasm_binary_name)); - let wasm_compact_file = if is_release_build { + let wasm_compact_file = if profile.wants_compact() { let wasm_compact_file = project.join(format!( "{}.compact.wasm", wasm_binary_name.clone().unwrap_or_else(|| default_wasm_binary_name.clone()), @@ -687,11 +770,13 @@ fn copy_wasm_to_target_directory(cargo_manifest: &Path, wasm_binary: &WasmBinary }; if !target_dir.is_absolute() { - panic!( + // We use println! + exit instead of a panic in order to have a cleaner output. + println!( "Environment variable `{}` with `{}` is not an absolute path!", crate::WASM_TARGET_DIRECTORY, target_dir.display(), ); + process::exit(1); } fs::create_dir_all(&target_dir).expect("Creates `WASM_TARGET_DIRECTORY`."); From 2c4549689dbb86c23725dac2f82af35faa07c9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 31 Jan 2022 21:04:12 +0100 Subject: [PATCH 0473/1472] Bump `strum` from 0.22 -> 0.23 (#10758) --- Cargo.lock | 32 +++---------------- client/beefy/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 8 +++-- .../election-provider-multi-phase/src/lib.rs | 4 +-- primitives/keyring/Cargo.toml | 2 +- 5 files changed, 14 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 773b770362250..a45b3bf3289cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -508,7 +508,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-tracing", - "strum 0.22.0", + "strum", "substrate-prometheus-endpoint", "thiserror", "wasm-timer", @@ -5710,8 +5710,7 @@ dependencies = [ "sp-std", "sp-tracing", "static_assertions", - "strum 0.22.0", - "strum_macros 0.23.1", + "strum", ] [[package]] @@ -9742,7 +9741,7 @@ dependencies = [ "lazy_static", "sp-core", "sp-runtime", - "strum 0.22.0", + "strum", ] [[package]] @@ -10210,34 +10209,13 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "strum" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" -dependencies = [ - "strum_macros 0.22.0", -] - [[package]] name = "strum" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" dependencies = [ - "strum_macros 0.23.1", -] - -[[package]] -name = "strum_macros" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb" -dependencies = [ - "heck 0.3.2", - "proc-macro2", - "quote", - "syn", + "strum_macros", ] [[package]] @@ -10488,7 +10466,7 @@ dependencies = [ "build-helper", "cargo_metadata", "sp-maybe-compressed-blob", - "strum 0.23.0", + "strum", "tempfile", "toml", "walkdir", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 9761f18d78450..3bef549938ccf 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -39,4 +39,4 @@ beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sc-network-test = { version = "0.8.0", path = "../network/test" } -strum = { version = "0.22", features = ["derive"] } +strum = { version = "0.23", features = ["derive"] } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 7add94dc76c80..062e63f5fdf15 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -37,8 +37,7 @@ rand = { version = "0.7.3", default-features = false, optional = true, features "alloc", "small_rng", ] } -strum = { optional = true, version = "0.22.0" } -strum_macros = { optional = true, version = "0.23.1" } +strum = { optional = true, default-features = false, version = "0.23.0", features = ["derive"] } [dev-dependencies] parking_lot = "0.11.2" @@ -70,12 +69,15 @@ std = [ "sp-arithmetic/std", "frame-election-provider-support/std", "log/std", + + "frame-benchmarking/std", + "rand/std", + "strum/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-election-provider-support/runtime-benchmarks", "rand", "strum", - "strum_macros", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 2b48373c5b0ea..0a620e6c12827 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -488,7 +488,7 @@ pub struct SolutionOrSnapshotSize { /// /// Note that this is different from [`pallet::Error`]. #[derive(frame_support::DebugNoBound)] -#[cfg_attr(feature = "runtime-benchmarks", derive(strum_macros::IntoStaticStr))] +#[cfg_attr(feature = "runtime-benchmarks", derive(strum::IntoStaticStr))] pub enum ElectionError { /// An error happened in the feasibility check sub-system. Feasibility(FeasibilityError), @@ -533,7 +533,7 @@ impl From> for ElectionError { /// Errors that can happen in the feasibility check. #[derive(Debug, Eq, PartialEq)] -#[cfg_attr(feature = "runtime-benchmarks", derive(strum_macros::IntoStaticStr))] +#[cfg_attr(feature = "runtime-benchmarks", derive(strum::IntoStaticStr))] pub enum FeasibilityError { /// Wrong number of winners presented. WrongWinnerCount, diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index a457f4983c163..a31dcc51d0fbe 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -18,4 +18,4 @@ targets = ["x86_64-unknown-linux-gnu"] sp-core = { version = "4.1.0-dev", path = "../core" } sp-runtime = { version = "4.1.0-dev", path = "../runtime" } lazy_static = "1.4.0" -strum = { version = "0.22.0", features = ["derive"] } +strum = { version = "0.23.0", features = ["derive"] } From 7daddf614bd743e331cfeed28101b68181f37593 Mon Sep 17 00:00:00 2001 From: Hussein Ait-Lahcen Date: Tue, 1 Feb 2022 10:34:53 +0100 Subject: [PATCH 0474/1472] derive `MaxEncodedLen` for `MultiSignature` (#10765) --- primitives/core/src/ecdsa.rs | 2 +- primitives/core/src/ed25519.rs | 2 +- primitives/core/src/sr25519.rs | 2 +- primitives/runtime/src/lib.rs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index c5e53c7029e66..4d2cae97ef14a 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -187,7 +187,7 @@ impl<'de> Deserialize<'de> for Public { /// A signature (a 512-bit value, plus 8 bits for recovery ID). #[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Encode, Decode, PassByInner, TypeInfo, PartialEq, Eq)] +#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; 65]); impl sp_std::convert::TryFrom<&[u8]> for Signature { diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index bb99a4ae02006..be7547201e84d 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -212,7 +212,7 @@ impl<'de> Deserialize<'de> for Public { /// A signature (a 512-bit value). #[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Encode, Decode, PassByInner, TypeInfo, PartialEq, Eq)] +#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; 64]); impl sp_std::convert::TryFrom<&[u8]> for Signature { diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index 4094c4d1b4405..5e18e02c0ffd8 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -212,7 +212,7 @@ impl<'de> Deserialize<'de> for Public { /// /// Instead of importing it for the local module, alias it to be available as a public type #[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Encode, Decode, PassByInner, TypeInfo, PartialEq, Eq)] +#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; 64]); impl sp_std::convert::TryFrom<&[u8]> for Signature { diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index cb9ba9ff297fb..84817a6be5d71 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -52,7 +52,7 @@ use sp_core::{ }; use sp_std::{convert::TryFrom, prelude::*}; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; pub mod curve; @@ -224,7 +224,7 @@ pub type ConsensusEngineId = [u8; 4]; /// Signature verify that can work with any known signature types.. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(Eq, PartialEq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Eq, PartialEq, Clone, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo)] pub enum MultiSignature { /// An Ed25519 signature. Ed25519(ed25519::Signature), From 70925041649ace60f7f8996f3928617bab0bb7d5 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 1 Feb 2022 14:45:16 +0100 Subject: [PATCH 0475/1472] Add `MaxEncodedLen` to `implement_fixed!` (#10768) Signed-off-by: Oliver Tale-Yazdi --- primitives/arithmetic/src/fixed_point.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/primitives/arithmetic/src/fixed_point.rs b/primitives/arithmetic/src/fixed_point.rs index 206e63af95b1f..1c61d6c3806ae 100644 --- a/primitives/arithmetic/src/fixed_point.rs +++ b/primitives/arithmetic/src/fixed_point.rs @@ -369,6 +369,7 @@ macro_rules! implement_fixed { Default, Copy, Clone, + codec::MaxEncodedLen, PartialEq, Eq, PartialOrd, @@ -667,6 +668,15 @@ macro_rules! implement_fixed { assert!($name::DIV > 0); } + #[test] + fn has_max_encoded_len() { + struct AsMaxEncodedLen { + _data: T, + } + + let _ = AsMaxEncodedLen { _data: $name::min_value() }; + } + #[test] fn from_i129_works() { let a = I129 { value: 1, negative: true }; From 6611740479b52e4c52e178dc1af62c34d0c69e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 1 Feb 2022 20:38:02 +0100 Subject: [PATCH 0476/1472] Release `pallet-contracts-primitives` (#10772) * Bump sp-storage * Bump sp-rpc * Bump sp-io * Bump sp-trie * Bump sp-state-machine * Bump sp-externalities * Bump sp-keystore * Bump sp-application-crypto * Bump pallet-contracts-primitives * Bump sp-core * Bump sp-runtime-interface * Bump sp-wasm-interface * Bump sp-runtime * Bump sp-storage * Update lock file * Revert "Bump sp-storage" This reverts commit f86c6db1ae334e28207b658fd90714ade0332e3b. * Update lock file --- Cargo.lock | 26 +++++++++---------- bin/node-template/node/Cargo.toml | 4 +-- bin/node-template/pallets/template/Cargo.toml | 6 ++--- bin/node-template/runtime/Cargo.toml | 4 +-- bin/node/bench/Cargo.toml | 8 +++--- bin/node/cli/Cargo.toml | 8 +++--- bin/node/executor/Cargo.toml | 14 +++++----- bin/node/inspect/Cargo.toml | 4 +-- bin/node/primitives/Cargo.toml | 6 ++--- bin/node/rpc/Cargo.toml | 4 +-- bin/node/runtime/Cargo.toml | 8 +++--- bin/node/testing/Cargo.toml | 6 ++--- bin/utils/chain-spec-builder/Cargo.toml | 4 +-- client/allocator/Cargo.toml | 4 +-- client/api/Cargo.toml | 14 +++++----- client/authority-discovery/Cargo.toml | 6 ++--- client/basic-authorship/Cargo.toml | 4 +-- client/beefy/Cargo.toml | 8 +++--- client/beefy/rpc/Cargo.toml | 4 +-- client/block-builder/Cargo.toml | 6 ++--- client/chain-spec/Cargo.toml | 4 +-- client/cli/Cargo.toml | 6 ++--- client/consensus/aura/Cargo.toml | 8 +++--- client/consensus/babe/Cargo.toml | 10 +++---- client/consensus/babe/rpc/Cargo.toml | 8 +++--- client/consensus/common/Cargo.toml | 6 ++--- client/consensus/epochs/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 6 ++--- client/consensus/pow/Cargo.toml | 4 +-- client/consensus/slots/Cargo.toml | 6 ++--- client/consensus/uncles/Cargo.toml | 2 +- client/db/Cargo.toml | 8 +++--- client/executor/Cargo.toml | 16 ++++++------ client/executor/common/Cargo.toml | 4 +-- client/executor/runtime-test/Cargo.toml | 6 ++--- client/executor/wasmi/Cargo.toml | 6 ++--- client/executor/wasmtime/Cargo.toml | 8 +++--- client/finality-grandpa/Cargo.toml | 8 +++--- client/finality-grandpa/rpc/Cargo.toml | 6 ++--- client/informant/Cargo.toml | 2 +- client/keystore/Cargo.toml | 6 ++--- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 4 +-- client/network/test/Cargo.toml | 4 +-- client/offchain/Cargo.toml | 4 +-- client/rpc-api/Cargo.toml | 6 ++--- client/rpc/Cargo.toml | 10 +++---- client/service/Cargo.toml | 16 ++++++------ client/service/test/Cargo.toml | 12 ++++----- client/state-db/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/tracing/Cargo.toml | 6 ++--- client/transaction-pool/Cargo.toml | 4 +-- client/transaction-pool/api/Cargo.toml | 2 +- frame/assets/Cargo.toml | 6 ++--- frame/atomic-swap/Cargo.toml | 6 ++--- frame/aura/Cargo.toml | 8 +++--- frame/authority-discovery/Cargo.toml | 8 +++--- frame/authorship/Cargo.toml | 6 ++--- frame/babe/Cargo.toml | 8 +++--- frame/bags-list/Cargo.toml | 10 +++---- frame/bags-list/remote-tests/Cargo.toml | 6 ++--- frame/balances/Cargo.toml | 6 ++--- frame/beefy-mmr/Cargo.toml | 6 ++--- frame/beefy/Cargo.toml | 6 ++--- frame/benchmarking/Cargo.toml | 12 ++++----- frame/bounties/Cargo.toml | 6 ++--- frame/child-bounties/Cargo.toml | 6 ++--- frame/collective/Cargo.toml | 6 ++--- frame/contracts/Cargo.toml | 8 +++--- frame/contracts/common/Cargo.toml | 8 +++--- frame/contracts/rpc/Cargo.toml | 8 +++--- frame/contracts/rpc/runtime-api/Cargo.toml | 4 +-- frame/democracy/Cargo.toml | 6 ++--- .../election-provider-multi-phase/Cargo.toml | 10 +++---- frame/election-provider-support/Cargo.toml | 6 ++--- frame/elections-phragmen/Cargo.toml | 8 +++--- frame/examples/basic/Cargo.toml | 6 ++--- frame/examples/offchain-worker/Cargo.toml | 8 +++--- frame/examples/parallel/Cargo.toml | 6 ++--- frame/executive/Cargo.toml | 10 +++---- frame/gilt/Cargo.toml | 6 ++--- frame/grandpa/Cargo.toml | 8 +++--- frame/identity/Cargo.toml | 6 ++--- frame/im-online/Cargo.toml | 8 +++--- frame/indices/Cargo.toml | 6 ++--- frame/lottery/Cargo.toml | 6 ++--- frame/membership/Cargo.toml | 6 ++--- frame/merkle-mountain-range/Cargo.toml | 6 ++--- .../primitives/Cargo.toml | 4 +-- frame/merkle-mountain-range/rpc/Cargo.toml | 4 +-- frame/multisig/Cargo.toml | 6 ++--- frame/nicks/Cargo.toml | 6 ++--- frame/node-authorization/Cargo.toml | 6 ++--- frame/offences/Cargo.toml | 6 ++--- frame/offences/benchmarking/Cargo.toml | 6 ++--- frame/preimage/Cargo.toml | 8 +++--- frame/proxy/Cargo.toml | 6 ++--- frame/randomness-collective-flip/Cargo.toml | 6 ++--- frame/recovery/Cargo.toml | 6 ++--- frame/scheduler/Cargo.toml | 6 ++--- frame/scored-pool/Cargo.toml | 6 ++--- frame/session/Cargo.toml | 8 +++--- frame/session/benchmarking/Cargo.toml | 6 ++--- frame/society/Cargo.toml | 6 ++--- frame/staking/Cargo.toml | 8 +++--- frame/staking/reward-curve/Cargo.toml | 2 +- frame/sudo/Cargo.toml | 6 ++--- frame/support/Cargo.toml | 8 +++--- frame/support/test/Cargo.toml | 8 +++--- frame/support/test/compile_pass/Cargo.toml | 4 +-- frame/system/Cargo.toml | 8 +++--- frame/system/benchmarking/Cargo.toml | 6 ++--- frame/timestamp/Cargo.toml | 8 +++--- frame/tips/Cargo.toml | 8 +++--- frame/transaction-payment/Cargo.toml | 6 ++--- .../asset-tx-payment/Cargo.toml | 8 +++--- frame/transaction-payment/rpc/Cargo.toml | 6 ++--- .../rpc/runtime-api/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 6 ++--- frame/treasury/Cargo.toml | 6 ++--- frame/try-runtime/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 6 ++--- frame/utility/Cargo.toml | 8 +++--- frame/vesting/Cargo.toml | 6 ++--- primitives/api/Cargo.toml | 6 ++--- primitives/api/test/Cargo.toml | 6 ++--- primitives/application-crypto/Cargo.toml | 6 ++--- primitives/application-crypto/test/Cargo.toml | 8 +++--- primitives/authority-discovery/Cargo.toml | 4 +-- primitives/authorship/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 8 +++--- primitives/block-builder/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 4 +-- primitives/consensus/aura/Cargo.toml | 4 +-- primitives/consensus/babe/Cargo.toml | 8 +++--- primitives/consensus/common/Cargo.toml | 6 ++--- primitives/consensus/pow/Cargo.toml | 4 +-- primitives/consensus/slots/Cargo.toml | 2 +- primitives/consensus/vrf/Cargo.toml | 4 +-- primitives/core/Cargo.toml | 8 +++--- primitives/externalities/Cargo.toml | 4 +-- primitives/finality-grandpa/Cargo.toml | 8 +++--- primitives/inherents/Cargo.toml | 4 +-- primitives/io/Cargo.toml | 16 ++++++------ primitives/keyring/Cargo.toml | 4 +-- primitives/keystore/Cargo.toml | 6 ++--- primitives/npos-elections/Cargo.toml | 4 +-- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- primitives/offchain/Cargo.toml | 4 +-- primitives/rpc/Cargo.toml | 4 +-- primitives/runtime-interface/Cargo.toml | 14 +++++----- .../test-wasm-deprecated/Cargo.toml | 6 ++--- .../runtime-interface/test-wasm/Cargo.toml | 6 ++--- primitives/runtime-interface/test/Cargo.toml | 8 +++--- primitives/runtime/Cargo.toml | 10 +++---- primitives/sandbox/Cargo.toml | 6 ++--- primitives/session/Cargo.toml | 4 +-- primitives/staking/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 10 +++---- primitives/storage/Cargo.toml | 2 +- primitives/tasks/Cargo.toml | 8 +++--- primitives/test-primitives/Cargo.toml | 6 ++--- primitives/timestamp/Cargo.toml | 2 +- primitives/transaction-pool/Cargo.toml | 2 +- .../transaction-storage-proof/Cargo.toml | 6 ++--- primitives/trie/Cargo.toml | 6 ++--- primitives/version/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 8 +++--- test-utils/runtime/Cargo.toml | 16 ++++++------ test-utils/runtime/client/Cargo.toml | 4 +-- .../runtime/transaction-pool/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 10 +++---- utils/frame/frame-utilities-cli/Cargo.toml | 4 +-- utils/frame/generate-bags/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 6 ++--- utils/frame/rpc/support/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 4 +-- utils/frame/try-runtime/cli/Cargo.toml | 12 ++++----- 180 files changed, 564 insertions(+), 564 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a45b3bf3289cc..963082a7e3af9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5618,7 +5618,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" -version = "4.0.0-dev" +version = "5.0.0" dependencies = [ "bitflags", "parity-scale-codec", @@ -9388,7 +9388,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" -version = "4.0.0" +version = "5.0.0" dependencies = [ "parity-scale-codec", "scale-info", @@ -9581,7 +9581,7 @@ dependencies = [ [[package]] name = "sp-core" -version = "4.1.0-dev" +version = "5.0.0" dependencies = [ "base58", "bitflags", @@ -9672,7 +9672,7 @@ dependencies = [ [[package]] name = "sp-externalities" -version = "0.10.0" +version = "0.11.0" dependencies = [ "environmental", "parity-scale-codec", @@ -9713,7 +9713,7 @@ dependencies = [ [[package]] name = "sp-io" -version = "4.0.0" +version = "5.0.0" dependencies = [ "futures 0.3.16", "hash-db", @@ -9746,7 +9746,7 @@ dependencies = [ [[package]] name = "sp-keystore" -version = "0.10.0" +version = "0.11.0" dependencies = [ "async-trait", "futures 0.3.16", @@ -9833,7 +9833,7 @@ dependencies = [ [[package]] name = "sp-rpc" -version = "4.0.0-dev" +version = "5.0.0" dependencies = [ "rustc-hash", "serde", @@ -9843,7 +9843,7 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "4.1.0-dev" +version = "5.0.0" dependencies = [ "either", "hash256-std-hasher", @@ -9870,7 +9870,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "4.1.0-dev" +version = "5.0.0" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -9987,7 +9987,7 @@ dependencies = [ [[package]] name = "sp-state-machine" -version = "0.10.0" +version = "0.11.0" dependencies = [ "hash-db", "hex-literal", @@ -10016,7 +10016,7 @@ version = "4.0.0" [[package]] name = "sp-storage" -version = "4.0.0" +version = "5.0.0" dependencies = [ "impl-serde", "parity-scale-codec", @@ -10102,7 +10102,7 @@ dependencies = [ [[package]] name = "sp-trie" -version = "4.0.0" +version = "5.0.0" dependencies = [ "criterion", "hash-db", @@ -10148,7 +10148,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "4.1.0-dev" +version = "5.0.0" dependencies = [ "impl-trait-for-tuples", "log 0.4.14", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 300a35252c053..1f8ff0ae1e0d4 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -20,7 +20,7 @@ name = "node-template" clap = { version = "3.0", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = ["wasmtime"] } sc-service = { version = "0.10.0-dev", path = "../../../client/service", features = ["wasmtime"] } sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" } @@ -34,7 +34,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo sc-finality-grandpa = { version = "0.10.0-dev", path = "../../../client/finality-grandpa" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } # These dependencies are used for the node template's RPCs diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 4dc4fb3c6e528..0a9d0eb27a2ca 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -22,9 +22,9 @@ frame-system = { default-features = false, version = "4.0.0-dev", path = "../../ frame-benchmarking = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/benchmarking", optional = true } [dev-dependencies] -sp-core = { default-features = false, version = "4.1.0-dev", path = "../../../../primitives/core" } -sp-io = { default-features = false, version = "4.0.0-dev", path = "../../../../primitives/io" } -sp-runtime = { default-features = false, version = "4.1.0-dev", path = "../../../../primitives/runtime" } +sp-core = { default-features = false, version = "5.0.0", path = "../../../../primitives/core" } +sp-io = { default-features = false, version = "5.0.0", path = "../../../../primitives/io" } +sp-runtime = { default-features = false, version = "5.0.0", path = "../../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index eb8fb9eb52a87..98da28c4476d9 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -29,10 +29,10 @@ frame-executive = { version = "4.0.0-dev", default-features = false, path = "../ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/block-builder"} sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/consensus/aura" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents"} sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 6c28f14793a92..9939f188d5d82 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -15,15 +15,15 @@ node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } serde = "1.0.132" serde_json = "1.0.74" derive_more = "0.99.16" kvdb = "0.10.0" kvdb-rocksdb = "0.14.0" -sp-trie = { version = "4.0.0", path = "../../../primitives/trie" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-trie = { version = "5.0.0", path = "../../../primitives/trie" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-basic-authorship = { version = "0.10.0-dev", path = "../../../client/basic-authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 2eb1618a7c986..db198592b37bc 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -47,13 +47,13 @@ sp-authority-discovery = { version = "4.0.0-dev", path = "../../../primitives/au sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } grandpa-primitives = { version = "4.0.0-dev", package = "sp-finality-grandpa", path = "../../../primitives/finality-grandpa" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } -sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } +sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../../primitives/transaction-pool" } sp-transaction-storage-proof = { version = "4.0.0-dev", path = "../../../primitives/transaction-storage-proof" } @@ -102,7 +102,7 @@ sc-cli = { version = "0.10.0-dev", optional = true, path = "../../../client/cli" sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service", features = [ "wasmtime", ] } -sp-trie = { version = "4.0.0", default-features = false, path = "../../../primitives/trie", features = [ +sp-trie = { version = "5.0.0", default-features = false, path = "../../../primitives/trie", features = [ "memory-tracker", ] } diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index e23152e00e5e8..39cf1ee8d8934 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -17,11 +17,11 @@ scale-info = { version = "1.0", features = ["derive"] } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } -sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } +sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } -sp-trie = { version = "4.0.0", path = "../../../primitives/trie" } +sp-trie = { version = "5.0.0", path = "../../../primitives/trie" } frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } [dev-dependencies] @@ -34,10 +34,10 @@ pallet-contracts = { version = "4.0.0-dev", path = "../../../frame/contracts" } pallet-im-online = { version = "4.0.0-dev", path = "../../../frame/im-online" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } pallet-treasury = { version = "4.0.0-dev", path = "../../../frame/treasury" } -sp-application-crypto = { version = "4.0.0", path = "../../../primitives/application-crypto" } +sp-application-crypto = { version = "5.0.0", path = "../../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } -sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-externalities = { version = "0.11.0", path = "../../../primitives/externalities" } sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } wat = "1.0" futures = "0.3.9" diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index bb9af8c66988e..e5b4c41c91b71 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -19,5 +19,5 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index e00f46720c947..5664318513a09 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -16,9 +16,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../../primitives/application-crypto" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../../primitives/application-crypto" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 36d313ebc30ae..c6ba0c9f992d8 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -29,9 +29,9 @@ sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } +sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-frame-rpc-system = { version = "4.0.0-dev", path = "../../../utils/frame/rpc/system" } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index ef1b73aed854b..84eec7662361f 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -30,17 +30,17 @@ sp-block-builder = { path = "../../../primitives/block-builder", default-feature sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents" } node-primitives = { version = "2.0.0", default-features = false, path = "../primitives" } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../../primitives/keyring" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" } -sp-io = { version = "4.0.0", default-features = false, path = "../../../primitives/io" } +sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } # frame dependencies @@ -62,7 +62,7 @@ pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../ pallet-child-bounties = { version = "4.0.0-dev", default-features = false, path = "../../../frame/child-bounties" } pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../../../frame/collective" } pallet-contracts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts" } -pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/common/" } +pallet-contracts-primitives = { version = "5.0.0", default-features = false, path = "../../../frame/contracts/common/" } pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/rpc/runtime-api/" } pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" } pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 29efc0028c159..55ae52b50d9d1 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -28,9 +28,9 @@ sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../../primitives/io" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = [ "wasmtime", ] } diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index 452221ff6e13e..f6af82ba42eb0 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -21,5 +21,5 @@ rand = "0.8" sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } node-cli = { version = "3.0.0-dev", path = "../../node/cli" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index eb8d298e1ec25..6f20449b38bc7 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-wasm-interface = { version = "4.1.0-dev", path = "../../primitives/wasm-interface" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-wasm-interface = { version = "5.0.0", path = "../../primitives/wasm-interface" } log = "0.4.11" thiserror = "1.0.30" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index c18b920cace81..ab6ad96e286f9 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-executor = { version = "0.10.0-dev", path = "../executor" } -sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } +sp-externalities = { version = "0.11.0", path = "../../primitives/externalities" } fnv = "1.0.6" futures = "0.3.1" hash-db = { version = "0.15.2", default-features = false } @@ -27,14 +27,14 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } log = "0.4.8" parking_lot = "0.11.2" sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-keystore = { version = "0.10.0", default-features = false, path = "../../primitives/keystore" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-keystore = { version = "0.11.0", default-features = false, path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } -sp-trie = { version = "4.0.0", path = "../../primitives/trie" } -sp-storage = { version = "4.0.0", path = "../../primitives/storage" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } +sp-trie = { version = "5.0.0", path = "../../primitives/trie" } +sp-storage = { version = "5.0.0", path = "../../primitives/storage" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index ec43112a71450..e3a3ef2a3591b 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -32,9 +32,9 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-authority-discovery = { version = "4.0.0-dev", path = "../../primitives/authority-discovery" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } [dev-dependencies] diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index e1083b15a9700..85592c7c549c0 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -19,8 +19,8 @@ futures-timer = "3.0.1" log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 3bef549938ccf..3ce556e85239b 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -19,12 +19,12 @@ codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive prometheus = { version = "0.10.0-dev", package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } sc-utils = { version = "4.0.0-dev", path = "../utils" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 444f1ff4aaf9e..4a300b26e1238 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -24,8 +24,8 @@ codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } beefy-gadget = { version = "4.0.0-dev", path = "../." } beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 19b8839c12280..e41ab0a5caf15 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -14,11 +14,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-builder" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 0110e82532a5c..d103c2414331b 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } impl-trait-for-tuples = "0.2.1" sc-network = { version = "0.10.0-dev", path = "../network" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.74" -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "2.0.0" } memmap2 = "0.5.0" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index a33b3e13af35c..ca7e0ac768f91 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -39,11 +39,11 @@ sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } -sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } [dev-dependencies] diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index bcae7648ce2e8..4fb621d716a8e 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0", path = "../../../primitives/application-crypto" } +sp-application-crypto = { version = "5.0.0", path = "../../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consensus/aura" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } @@ -26,12 +26,12 @@ thiserror = "1.0" futures = "0.3.9" sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } log = "0.4.8" -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } -sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } async-trait = "0.1.50" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 5dd029f0ad4a9..79cb3a52038a3 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -19,15 +19,15 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ ] } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-application-crypto = { version = "4.0.0", path = "../../../primitives/application-crypto" } -sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-application-crypto = { version = "5.0.0", path = "../../../primitives/application-crypto" } +sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } num-bigint = "0.2.3" num-rational = "0.2.2" num-traits = "0.2.8" serde = { version = "1.0.132", features = ["derive"] } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } -sp-io = { version = "4.0.0", path = "../../../primitives/io" } +sp-io = { version = "5.0.0", path = "../../../primitives/io" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } @@ -40,7 +40,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } sp-consensus-vrf = { version = "0.10.0-dev", path = "../../../primitives/consensus/vrf" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } futures = "0.3.9" diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 4997cfdd1eec0..87ef265ffd9b2 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -21,15 +21,15 @@ jsonrpc-derive = "18.0.0" sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } serde = { version = "1.0.132", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } -sp-runtime = { version = "4.1.0-dev", path = "../../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } futures = "0.3.16" thiserror = "1.0" sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } -sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } -sp-application-crypto = { version = "4.0.0", path = "../../../../primitives/application-crypto" } -sp-keystore = { version = "0.10.0", path = "../../../../primitives/keystore" } +sp-core = { version = "5.0.0", path = "../../../../primitives/core" } +sp-application-crypto = { version = "5.0.0", path = "../../../../primitives/application-crypto" } +sp-keystore = { version = "0.11.0", path = "../../../../primitives/keystore" } [dev-dependencies] sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 72a0544535ad7..a14a367690332 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -20,10 +20,10 @@ futures = { version = "0.3.1", features = ["thread-pool"] } futures-timer = "3.0.1" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } +sp-core = { path = "../../../primitives/core", version = "5.0.0"} sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } -sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } parking_lot = "0.11.2" diff --git a/client/consensus/epochs/Cargo.toml b/client/consensus/epochs/Cargo.toml index bb4a77b559e0a..b377dccfd3689 100644 --- a/client/consensus/epochs/Cargo.toml +++ b/client/consensus/epochs/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-client-api = { path = "../../api" , version = "4.0.0-dev"} sc-consensus = { path = "../common" , version = "0.10.0-dev"} diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index ff2264e641740..c2c36b1fc5867 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -37,9 +37,9 @@ sp-blockchain = { path = "../../../primitives/blockchain", version = "4.0.0-dev" sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } sp-consensus-slots = { path = "../../../primitives/consensus/slots", version = "0.10.0-dev" } sp-inherents = { path = "../../../primitives/inherents", version = "4.0.0-dev" } -sp-runtime = { path = "../../../primitives/runtime", version = "4.1.0-dev" } -sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } -sp-keystore = { path = "../../../primitives/keystore", version = "0.10.0" } +sp-runtime = { path = "../../../primitives/runtime", version = "5.0.0"} +sp-core = { path = "../../../primitives/core", version = "5.0.0"} +sp-keystore = { path = "../../../primitives/keystore", version = "0.11.0"} sp-api = { path = "../../../primitives/api", version = "4.0.0-dev" } sc-transaction-pool-api = { path = "../../../client/transaction-pool/api", version = "4.0.0-dev" } sp-timestamp = { path = "../../../primitives/timestamp", version = "4.0.0-dev" } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index e5bf87487c71b..eb609489290a0 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -14,9 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 60f57449a3a33..b13c1bb6b5b32 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-arithmetic = { version = "4.0.0", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml index b9eaae4773a6a..7482fdc12d081 100644 --- a/client/consensus/uncles/Cargo.toml +++ b/client/consensus/uncles/Cargo.toml @@ -14,6 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } thiserror = "1.0.30" diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 0db0f8309e2eb..f2c21abf6c1d6 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -26,11 +26,11 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } -sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } -sp-trie = { version = "4.0.0", path = "../../primitives/trie" } +sp-trie = { version = "5.0.0", path = "../../primitives/trie" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } parity-db = { version = "0.3.5", optional = true } diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index e10cbf347db59..0d0f2a8bd92ed 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -15,18 +15,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-tasks = { version = "4.0.0-dev", path = "../../primitives/tasks" } -sp-trie = { version = "4.0.0", path = "../../primitives/trie" } +sp-trie = { version = "5.0.0", path = "../../primitives/trie" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } wasmi = "0.9.1" lazy_static = "1.4.0" sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-wasm-interface = { version = "4.1.0-dev", path = "../../primitives/wasm-interface" } -sp-runtime-interface = { version = "4.1.0-dev", path = "../../primitives/runtime-interface" } -sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } +sp-wasm-interface = { version = "5.0.0", path = "../../primitives/wasm-interface" } +sp-runtime-interface = { version = "5.0.0", path = "../../primitives/runtime-interface" } +sp-externalities = { version = "0.11.0", path = "../../primitives/externalities" } sc-executor-common = { version = "0.10.0-dev", path = "common" } sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } @@ -41,8 +41,8 @@ wat = "1.0" hex-literal = "0.3.4" sc-runtime-test = { version = "2.0.0", path = "runtime-test" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } -sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } tracing = "0.1.29" diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 104d24876d9a5..e23db203b3a40 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] wasm-instrument = "0.1" codec = { package = "parity-scale-codec", version = "2.0.0" } wasmi = "0.9.1" -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -sp-wasm-interface = { version = "4.1.0-dev", path = "../../../primitives/wasm-interface" } +sp-wasm-interface = { version = "5.0.0", path = "../../../primitives/wasm-interface" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } sp-serializer = { version = "4.0.0-dev", path = "../../../primitives/serializer" } thiserror = "1.0.30" diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index 1318c7246a848..b6fbe8685e35b 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -13,9 +13,9 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 9dc63747166b5..d333e98bf6cfb 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -19,7 +19,7 @@ wasmi = "0.9.1" codec = { package = "parity-scale-codec", version = "2.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -sp-wasm-interface = { version = "4.1.0-dev", path = "../../../primitives/wasm-interface" } -sp-runtime-interface = { version = "4.1.0-dev", path = "../../../primitives/runtime-interface" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-wasm-interface = { version = "5.0.0", path = "../../../primitives/wasm-interface" } +sp-runtime-interface = { version = "5.0.0", path = "../../../primitives/runtime-interface" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } scoped-tls = "1.0" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 8b3cd1a58e75f..0423b384943e8 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -19,9 +19,9 @@ log = "0.4.8" parity-wasm = "0.42.0" codec = { package = "parity-scale-codec", version = "2.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } -sp-wasm-interface = { version = "4.1.0-dev", path = "../../../primitives/wasm-interface", features = ["wasmtime"] } -sp-runtime-interface = { version = "4.1.0-dev", path = "../../../primitives/runtime-interface" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-wasm-interface = { version = "5.0.0", path = "../../../primitives/wasm-interface", features = ["wasmtime"] } +sp-runtime-interface = { version = "5.0.0", path = "../../../primitives/runtime-interface" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } wasmtime = { version = "0.33.0", default-features = false, features = [ "cache", @@ -32,5 +32,5 @@ wasmtime = { version = "0.33.0", default-features = false, features = [ [dev-dependencies] sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } -sp-io = { version = "4.0.0", path = "../../../primitives/io" } +sp-io = { version = "5.0.0", path = "../../../primitives/io" } wat = "1.0" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 2e6d3407a191f..e6b0b6396681e 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -23,15 +23,15 @@ log = "0.4.8" parking_lot = "0.11.2" rand = "0.8.4" parity-scale-codec = { version = "2.3.1", features = ["derive"] } -sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 39bf398fe3129..2845621cadd6f 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -12,8 +12,8 @@ readme = "README.md" sc-finality-grandpa = { version = "0.10.0-dev", path = "../" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } finality-grandpa = { version = "0.14.4", features = ["derive-codec"] } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" @@ -32,7 +32,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ "test-helpers", ] } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index ce7fe31648a19..78ee90823f226 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -21,5 +21,5 @@ parity-util-mem = { version = "0.10.2", default-features = false, features = ["p sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 56d4ee0d556fa..4d67be4167dd1 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" thiserror = "1.0" -sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } +sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } hex = "0.4.0" parking_lot = "0.11.2" serde_json = "1.0.74" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 9523e32f99e06..7952d97193ea9 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -22,7 +22,7 @@ log = "0.4.8" lru = "0.7.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } tracing = "0.1.29" [dev-dependencies] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 354991b32ba5b..fa1cc715e1512 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -52,8 +52,8 @@ sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } thiserror = "1.0" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 6b6d777e7396e..2750c613d42a2 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -25,8 +25,8 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index dd4bdb71f93b6..5cd823958eed4 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -25,9 +25,9 @@ rand = "0.7.2" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } threadpool = "1.7" hyper = { version = "0.14.16", features = ["stream", "http2"] } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 4b2882ee827f7..8b8b70b9747c9 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -23,12 +23,12 @@ log = "0.4.8" parking_lot = "0.11.2" thiserror = "1.0" -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.74" sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } -sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } +sp-rpc = { version = "5.0.0", path = "../../primitives/rpc" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 87fc263356a72..308d99bc4f376 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -20,16 +20,16 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } futures = "0.3.16" jsonrpc-pubsub = "18.0.0" log = "0.4.8" -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } rpc = { package = "jsonrpc-core", version = "18.0.0" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } serde_json = "1.0.74" sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } -sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } +sp-rpc = { version = "5.0.0", path = "../../primitives/rpc" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } @@ -43,7 +43,7 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/a assert_matches = "1.3.0" lazy_static = "1.4.0" sc-network = { version = "0.10.0-dev", path = "../network" } -sp-io = { version = "4.0.0", path = "../../primitives/io" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index f23bf3f55bbfe..fb6c4a0837616 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -36,21 +36,21 @@ hash-db = "0.15.2" serde = "1.0.132" serde_json = "1.0.74" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } -sp-trie = { version = "4.0.0", path = "../../primitives/trie" } -sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-trie = { version = "5.0.0", path = "../../primitives/trie" } +sp-externalities = { version = "0.11.0", path = "../../primitives/externalities" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } -sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } -sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } +sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } +sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } -sp-storage = { version = "4.0.0", path = "../../primitives/storage" } +sp-storage = { version = "5.0.0", path = "../../primitives/storage" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 84b1d44e7bde6..6395f9d9877dc 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -21,18 +21,18 @@ fdlimit = "0.2.1" parking_lot = "0.11.2" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } -sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } -sp-trie = { version = "4.0.0", path = "../../../primitives/trie" } -sp-storage = { version = "4.0.0", path = "../../../primitives/storage" } +sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } +sp-externalities = { version = "0.11.0", path = "../../../primitives/externalities" } +sp-trie = { version = "5.0.0", path = "../../../primitives/trie" } +sp-storage = { version = "5.0.0", path = "../../../primitives/storage" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../../db" } futures = "0.3.16" sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../../service" } sc-network = { version = "0.10.0-dev", path = "../../network" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index fbde840fbb8e9..fa0c5ed9810c9 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] parking_lot = "0.11.2" log = "0.4.11" sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } parity-util-mem-derive = "0.1.0" diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 0aae985319d43..eab6ffa88f15c 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -26,5 +26,5 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } serde_json = "1.0.74" serde = { version = "1.0.132", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 62c7f7a4becca..b8910199c0ee5 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -29,11 +29,11 @@ tracing = "0.1.29" tracing-log = "0.1.2" tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } -sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-rpc = { version = "5.0.0", path = "../../primitives/rpc" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-tracing-proc-macro = { version = "4.0.0-dev", path = "./proc-macro" } sc-rpc-server = { version = "4.0.0-dev", path = "../rpc-servers" } diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 73ec7cfff7f3d..06fc8298f01c0 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -23,8 +23,8 @@ parking_lot = "0.11.2" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index a544248a4f2cc..9d7e6ea5e0f83 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -14,5 +14,5 @@ log = "0.4.8" serde = { version = "1.0.132", features = ["derive"] } thiserror = "1.0.30" -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index c250a75d4c2f0..c5d60291fc435 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } # Needed for type-safe access to storage DB. frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } # `system` module provides us with all sorts of useful stuff and macros depend on it being around. @@ -25,9 +25,9 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-std = { version = "4.0.0", path = "../../primitives/std" } -sp-io = { version = "4.0.0", path = "../../primitives/io" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 0f478ab5602f9..1dcd6154d0beb 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -17,10 +17,10 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index f5c71a3088585..f869ddb417029 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -13,19 +13,19 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-consensus-aura = { version = "0.10.0-dev", path = "../../primitives/consensus/aura", default-features = false } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } [dev-dependencies] -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index c1233028df4e2..b6e8a400f8652 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authority-discovery" } -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } @@ -23,13 +23,13 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives pallet-session = { version = "4.0.0-dev", features = [ "historical", ], path = "../session", default-features = false } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index c17fc49ecdcc1..31daa74553c23 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -19,14 +19,14 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } impl-trait-for-tuples = "0.2.1" [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 673af5c30ed6d..f48877746b888 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -21,11 +21,11 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-consensus-vrf = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/vrf" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -36,7 +36,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } [features] diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 9e802527f18d4..c35ff6fc6c39d 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } # primitives -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # FRAME @@ -32,13 +32,13 @@ log = { version = "0.4.14", default-features = false } # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking", optional = true, default-features = false } pallet-balances = { version = "4.0.0-dev", path = "../balances", optional = true, default-features = false } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core", optional = true, default-features = false } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io", optional = true, default-features = false } +sp-core = { version = "5.0.0", path = "../../primitives/core", optional = true, default-features = false } +sp-io = { version = "5.0.0", path = "../../primitives/io", optional = true, default-features = false } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing", optional = true, default-features = false } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core"} -sp-io = { version = "4.0.0-dev", path = "../../primitives/io"} +sp-core = { version = "5.0.0", path = "../../primitives/core"} +sp-io = { version = "5.0.0", path = "../../primitives/io"} sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support", features = ["runtime-benchmarks"] } diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index b5122ebbafe76..8f3ce53f8ebb3 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -21,10 +21,10 @@ frame-system = { path = "../../system", version = "4.0.0-dev" } frame-support = { path = "../../support", version = "4.0.0-dev" } # core -sp-storage = { path = "../../../primitives/storage", version = "4.0.0" } -sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } +sp-storage = { path = "../../../primitives/storage", version = "5.0.0"} +sp-core = { path = "../../../primitives/core", version = "5.0.0"} sp-tracing = { path = "../../../primitives/tracing", version = "4.0.0" } -sp-runtime = { path = "../../../primitives/runtime", version = "4.1.0-dev" } +sp-runtime = { path = "../../../primitives/runtime", version = "5.0.0"} sp-std = { path = "../../../primitives/std", version = "4.0.0" } # utils diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 02b94fe606c49..f594e67ab861d 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -16,15 +16,15 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } log = { version = "0.4.14", default-features = false } [dev-dependencies] -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } [features] diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index c793173cc22d8..cfd18b26f9c7a 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -21,9 +21,9 @@ pallet-mmr = { version = "4.0.0-dev", path = "../merkle-mountain-range", default pallet-mmr-primitives = { version = "4.0.0-dev", path = "../merkle-mountain-range/primitives", default-features = false } pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime", default-features = false } +sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } +sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } beefy-merkle-tree = { version = "4.0.0-dev", path = "./primitives", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 52471a332dd76..13ccfb938010e 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -15,7 +15,7 @@ serde = { version = "1.0.132", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime", default-features = false } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } @@ -23,8 +23,8 @@ pallet-session = { version = "4.0.0-dev", path = "../session", default-features beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", default-features = false } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } [features] diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index ce110d8ba511f..9afdc79fae655 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -18,19 +18,19 @@ paste = "1.0" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } -sp-runtime-interface = { version = "4.1.0-dev", path = "../../primitives/runtime-interface", default-features = false } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime", default-features = false } +sp-runtime-interface = { version = "5.0.0", path = "../../primitives/runtime-interface", default-features = false } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } -sp-io = { version = "4.0.0", path = "../../primitives/io", default-features = false } -sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto", default-features = false } -sp-storage = { version = "4.0.0", path = "../../primitives/storage", default-features = false } +sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } +sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto", default-features = false } +sp-storage = { version = "5.0.0", path = "../../primitives/storage", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } log = { version = "0.4.14", default-features = false } [dev-dependencies] hex-literal = "0.3.4" -sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } [features] default = ["std"] diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 73973ab18caaa..477815a306f3c 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -18,12 +18,12 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } -sp-io = { version = "4.0.0", path = "../../primitives/io", default-features = false } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } +sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } +sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 742110a58bff7..0eeefd4de4595 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -18,13 +18,13 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../bounties" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } +sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } +sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index bd0573bace666..334b4945afa2b 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = log = { version = "0.4.14", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index f0d2833c61fd2..f24e393daa2ee 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -36,11 +36,11 @@ rand_pcg = { version = "0.3", optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, path = "common" } +pallet-contracts-primitives = { version = "5.0.0", default-features = false, path = "common" } pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/common/Cargo.toml index 05bfc212e3058..ad934c41a71fc 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-contracts-primitives" -version = "4.0.0-dev" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -19,10 +19,10 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] serde = { version = "1", features = ["derive"], optional = true } # Substrate Dependencies (This crate should not rely on frame) -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core", default-features = false } +sp-core = { version = "5.0.0", path = "../../../primitives/core", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc", optional = true } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-rpc = { version = "5.0.0", path = "../../../primitives/rpc", optional = true } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index 9a88013c34083..52ca0e6d83454 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -20,13 +20,13 @@ jsonrpc-derive = "18.0.0" serde = { version = "1", features = ["derive"] } # Substrate Dependencies -pallet-contracts-primitives = { version = "4.0.0-dev", path = "../common" } +pallet-contracts-primitives = { version = "5.0.0", path = "../common" } pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-rpc = { version = "5.0.0", path = "../../../primitives/rpc" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } [dev-dependencies] serde_json = "1" diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml index bb70d0835d268..8ecdff5175372 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/rpc/runtime-api/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "2", default-features = fals scale-info = { version = "1.0", default-features = false, features = ["derive"] } # Substrate Dependencies -pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, path = "../../common" } +pallet-contracts-primitives = { version = "5.0.0", default-features = false, path = "../../common" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../../primitives/std" } [features] diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 730bc6fffbdf4..125decaca8241 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -19,14 +19,14 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 062e63f5fdf15..c0d85737ec221 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -23,10 +23,10 @@ log = { version = "0.4.14", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } @@ -42,8 +42,8 @@ strum = { optional = true, default-features = false, version = "0.23.0", feature [dev-dependencies] parking_lot = "0.11.2" rand = { version = "0.7.3" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } frame-election-provider-support = { version = "4.0.0-dev", features = [ diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 1cb477d6c79c7..662762ef63068 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -23,9 +23,9 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys [dev-dependencies] sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index 867b1627272a7..f70eb568349b4 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -17,19 +17,19 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 894b9b4d5010d..73c11475fdf61 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -21,12 +21,12 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } -sp-io = { version = "4.0.0", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core", default-features = false } +sp-core = { version = "5.0.0", path = "../../../primitives/core", default-features = false } [features] default = ["std"] diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index 68ad2125eef42..e7ae323050ee1 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -20,10 +20,10 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore", optional = true } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } +sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore", optional = true } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [features] diff --git a/frame/examples/parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml index b3ec1a72506b4..8d291df191368 100644 --- a/frame/examples/parallel/Cargo.toml +++ b/frame/examples/parallel/Cargo.toml @@ -17,9 +17,9 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 1b6a237f3b93f..b261aecdf9262 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -19,16 +19,16 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } [dev-dependencies] hex-literal = "0.3.4" -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index b958b7ba337fe..7ed17d152a01e 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -16,15 +16,15 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 4b2ab7eca8712..002ceed369299 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -15,13 +15,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 00be4d767ec2b..209896ec0e557 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -17,14 +17,14 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } enumflags2 = { version = "0.6.2" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index 9d659d304dbbe..d223e5e8502d3 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -13,14 +13,14 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index a2998c7cfae94..487eb47164228 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../primitives/keyring" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index cef152a185880..2e2c2287a2ab6 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -27,8 +27,8 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " [dev-dependencies] frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 7ded2fd586e19..f2f7607ce9a52 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 495b0add5b1c4..a614ffa977154 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -16,9 +16,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, version = "0.3.2" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index 2e483360facc1..9df5094abd815 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -17,8 +17,8 @@ log = { version = "0.4.14", default-features = false } serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index d6bf66cefefbb..575b2a79fcd28 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -21,8 +21,8 @@ serde = { version = "1.0.132", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index 696f8afe0d85c..dfc05888b1aa9 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -17,14 +17,14 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 221a386c752a4..bf5afd26ebb59 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 610e536a2c818..0d64251885383 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -16,9 +16,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } log = { version = "0.4.14", default-features = false } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 49aa1d770e5b5..6fe36aea89eec 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -18,15 +18,15 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } serde = { version = "1.0.132", optional = true } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } log = { version = "0.4.14", default-features = false } [dev-dependencies] -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index 2764eedc1191b..9742545383227 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -29,7 +29,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, path = "../. pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ "runtime-benchmarks", ], path = "../../staking" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } @@ -37,8 +37,8 @@ frame-election-provider-support = { version = "4.0.0-dev", default-features = fa [dev-dependencies] pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../../primitives/io" } [features] default = ["std"] diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 17fed986f7575..66ef8467be28a 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -14,15 +14,15 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.1.0-dev", default-features = false, optional = true, path = "../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "5.0.0", default-features = false, optional = true, path = "../../primitives/core" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } +sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index a07ecb4997741..f0bd9391789bb 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -17,14 +17,14 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index a29e7ac7b3265..a93585700f2b0 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -16,15 +16,15 @@ targets = ["x86_64-unknown-linux-gnu"] safe-mix = { version = "1.0", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 53fe6851564dd..88da65327e2f0 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 424c3852862ec..d88063d69c5bb 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -14,15 +14,15 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } +sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index b97a7e3664903..af8b0f6aa2643 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index db6f10c728883..a342865615d91 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -20,12 +20,12 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-trie = { version = "4.0.0", default-features = false, path = "../../primitives/trie", optional = true } +sp-trie = { version = "5.0.0", default-features = false, path = "../../primitives/trie", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 10a430d52b0a5..cd33c5b186490 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] rand = { version = "0.7.2", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } @@ -28,8 +28,8 @@ pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ [dev-dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } scale-info = "1.0" -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index fa3f981f19d48..2787453d49d3e 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } rand_chacha = { version = "0.2", default-features = false } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-io ={ version = "4.0.0-dev", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io ={ version = "5.0.0", path = "../../primitives/io" } frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index e0d5dabaa8927..cd1e238dbd019 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -19,8 +19,8 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -28,7 +28,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, features = [ "historical", ], path = "../session" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } log = { version = "0.4.14", default-features = false } @@ -38,7 +38,7 @@ rand_chacha = { version = "0.2", default-features = false, optional = true } [dev-dependencies] sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index 4c1d2b922f6d6..86fdd09076e5d 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -21,4 +21,4 @@ proc-macro2 = "1.0.36" proc-macro-crate = "1.1.0" [dev-dependencies] -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index 504eb37b8d009..063ea52d5b8b5 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index d652e5ea43445..5e8c26b6ae540 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -18,10 +18,10 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-metadata = { version = "14.2.0", default-features = false, features = ["v14"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } @@ -29,7 +29,7 @@ tt-call = "1.0.8" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } -sp-state-machine = { version = "0.10.0", optional = true, path = "../../primitives/state-machine" } +sp-state-machine = { version = "0.11.0", optional = true, path = "../../primitives/state-machine" } bitflags = "1.3" impl-trait-for-tuples = "0.2.1" smallvec = "1.7.0" diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 257cca3218dab..5a27f4f46e10d 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -16,11 +16,11 @@ serde = { version = "1.0.132", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../../primitives/arithmetic" } -sp-io = { version = "4.0.0", path = "../../../primitives/io", default-features = false } -sp-state-machine = { version = "0.10.0", optional = true, path = "../../../primitives/state-machine" } +sp-io = { version = "5.0.0", path = "../../../primitives/io", default-features = false } +sp-state-machine = { version = "0.11.0", optional = true, path = "../../../primitives/state-machine" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } trybuild = "1.0.53" diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index 93443e33503ca..aaa080f84f1a4 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../../primitives/core" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index ae9242087f1a8..f1e7e4e207552 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -16,17 +16,17 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.132", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } log = { version = "0.4.14", default-features = false } [dev-dependencies] criterion = "0.3.3" -sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } +sp-externalities = { version = "0.11.0", path = "../../primitives/externalities" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 4ca250fa0ec7e..fa86250c199e5 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -16,14 +16,14 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } [dev-dependencies] -sp-io = { version = "4.0.0", path = "../../../primitives/io" } +sp-io = { version = "5.0.0", path = "../../../primitives/io" } [features] default = ["std"] diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index b66a91acebaa0..f42a95010587a 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -18,8 +18,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io", optional = true } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io", optional = true } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -28,8 +28,8 @@ sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../ log = { version = "0.4.14", default-features = false } [dev-dependencies] -sp-io ={ version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-io ={ version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index bbe78fd30a56b..182a87048d353 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -18,9 +18,9 @@ log = { version = "0.4.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.132", features = ["derive"], optional = true } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -30,7 +30,7 @@ pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-storage = { version = "4.0.0", path = "../../primitives/storage" } +sp-storage = { version = "5.0.0", path = "../../primitives/storage" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 8cb544159dd70..b9b46380a3864 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -20,9 +20,9 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] serde = { version = "1.0.132", optional = true } smallvec = "1.7.0" -sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } +sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index ab2d3302f95b0..300d05d0ed9a3 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -14,9 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate dependencies -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } @@ -32,7 +32,7 @@ serde = { version = "1.0.132", optional = true } smallvec = "1.7.0" serde_json = "1.0.74" -sp-storage = { version = "4.0.0", default-features = false, path = "../../../primitives/storage" } +sp-storage = { version = "5.0.0", default-features = false, path = "../../../primitives/storage" } pallet-assets = { version = "4.0.0-dev", path = "../../assets" } pallet-authorship = { version = "4.0.0-dev", path = "../../authorship" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 2486654404aef..844e898ed867f 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -20,7 +20,7 @@ jsonrpc-derive = "18.0.0" sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-rpc = { version = "5.0.0", path = "../../../primitives/rpc" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 1ad56280ac082..fed57eb5bf736 100644 --- a/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../../../primitives/runtime" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment" } [features] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index e4351438811f2..5adf5fd2c1f0d 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -20,16 +20,16 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-storage-proof" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = true, path = "../../primitives/transaction-storage-proof" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } +sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } [features] default = ["std"] diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 0a2dab417e348..d126d0ffa34b9 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1.0.132", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.1" sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -31,8 +31,8 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ [dev-dependencies] -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index 905c58ab00bed..0546c0a898fb2 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std" , default-features = false } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" , default-features = false } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" , default-features = false } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 38c519f801674..4e0194b17acbc 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } @@ -24,8 +24,8 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] sp-std = { version = "4.0.0", path = "../../primitives/std" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 85f522975dbbc..ea3977c1b8b29 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -17,15 +17,15 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index e488e282cd459..f7dcfd9fa442f 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -18,15 +18,15 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.0", default-features = false } [dev-dependencies] -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index f2c3e67800dc4..ab81ed85f188d 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../version" } -sp-state-machine = { version = "0.10.0", optional = true, path = "../state-machine" } +sp-state-machine = { version = "0.11.0", optional = true, path = "../state-machine" } hash-db = { version = "0.15.2", optional = true } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 79e302c4c065d..064e6a6c98181 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -16,11 +16,11 @@ sp-api = { version = "4.0.0-dev", path = "../" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } sp-version = { version = "4.0.0-dev", path = "../../version" } sp-tracing = { version = "4.0.0", path = "../../tracing" } -sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } +sp-runtime = { version = "5.0.0", path = "../../runtime" } sp-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } codec = { package = "parity-scale-codec", version = "2.0.0" } -sp-state-machine = { version = "0.10.0", path = "../../state-machine" } +sp-state-machine = { version = "0.11.0", path = "../../state-machine" } trybuild = "1.0.53" rustversion = "1.0.6" @@ -28,7 +28,7 @@ rustversion = "1.0.6" criterion = "0.3.0" futures = "0.3.9" log = "0.4.14" -sp-core = { version = "4.1.0-dev", path = "../../core" } +sp-core = { version = "5.0.0", path = "../../core" } [[bench]] name = "bench" diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index 75766905d14f7..a3dfa8646e793 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-application-crypto" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" description = "Provides facilities for generating application specific crypto wrapper types." @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-io = { version = "4.0.0", default-features = false, path = "../io" } +sp-io = { version = "5.0.0", default-features = false, path = "../io" } [features] default = [ "std" ] diff --git a/primitives/application-crypto/test/Cargo.toml b/primitives/application-crypto/test/Cargo.toml index 178932869611f..515be41be3d2e 100644 --- a/primitives/application-crypto/test/Cargo.toml +++ b/primitives/application-crypto/test/Cargo.toml @@ -13,9 +13,9 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } -sp-keystore = { version = "0.10.0", path = "../../keystore", default-features = false } +sp-core = { version = "5.0.0", default-features = false, path = "../../core" } +sp-keystore = { version = "0.11.0", path = "../../keystore", default-features = false } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } +sp-runtime = { version = "5.0.0", path = "../../runtime" } sp-api = { version = "4.0.0-dev", path = "../../api" } -sp-application-crypto = { version = "4.0.0", path = "../" } +sp-application-crypto = { version = "5.0.0", path = "../" } diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index 2fd2c48476920..7c6aa7a6ea002 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -13,12 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", default-features = false, version = "2.0.0" } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } [features] default = ["std"] diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index 8e97942499aad..4cf8e6e9522d1 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index edcb2244e58fb..9d8ec2a653ea0 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -12,15 +12,15 @@ codec = { version = "2.2.0", package = "parity-scale-codec", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../api", default-features = false } -sp-application-crypto = { version = "4.0.0", path = "../application-crypto", default-features = false } -sp-core = { version = "4.1.0-dev", path = "../core", default-features = false } -sp-runtime = { version = "4.1.0-dev", path = "../runtime", default-features = false } +sp-application-crypto = { version = "5.0.0", path = "../application-crypto", default-features = false } +sp-core = { version = "5.0.0", path = "../core", default-features = false } +sp-runtime = { version = "5.0.0", path = "../runtime", default-features = false } sp-std = { version = "4.0.0", path = "../std", default-features = false } [dev-dependencies] hex = "0.4.3" hex-literal = "0.3" -sp-keystore = { version = "0.10.0", path = "../keystore" } +sp-keystore = { version = "0.11.0", path = "../keystore" } [features] default = ["std"] diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index 5009207a3f5c3..28f76343c7e98 100644 --- a/primitives/block-builder/Cargo.toml +++ b/primitives/block-builder/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 366d0f3c373e2..89737dbac0c6b 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -21,7 +21,7 @@ thiserror = "1.0.30" futures = "0.3.9" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-runtime = { version = "4.1.0-dev", path = "../runtime" } -sp-state-machine = { version = "0.10.0", path = "../state-machine" } +sp-runtime = { version = "5.0.0", path = "../runtime" } +sp-state-machine = { version = "0.11.0", path = "../state-machine" } sp-database = { version = "4.0.0-dev", path = "../database" } sp-api = { version = "4.0.0-dev", path = "../api" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index f15f0008164d6..e78de2db17b39 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -13,12 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../application-crypto" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../timestamp" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 1471ca05f591e..b114d182c730d 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../application-crypto" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } merlin = { version = "2.0", default-features = false } @@ -22,10 +22,10 @@ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-consensus = { version = "0.10.0-dev", optional = true, path = "../common" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } sp-consensus-vrf = { version = "0.10.0-dev", path = "../vrf", default-features = false } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } +sp-core = { version = "5.0.0", default-features = false, path = "../../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } -sp-keystore = { version = "0.10.0", default-features = false, path = "../../keystore", optional = true } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../runtime" } +sp-keystore = { version = "0.11.0", default-features = false, path = "../../keystore", optional = true } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../timestamp", optional = true } serde = { version = "1.0.132", features = ["derive"], optional = true } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 93338d62cfc02..2717de72d1e31 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -20,13 +20,13 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ ] } futures = { version = "0.3.1", features = ["thread-pool"] } log = "0.4.8" -sp-core = { path = "../../core", version = "4.1.0-dev" } +sp-core = { path = "../../core", version = "5.0.0"} sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } -sp-state-machine = { version = "0.10.0", path = "../../state-machine" } +sp-state-machine = { version = "0.11.0", path = "../../state-machine" } futures-timer = "3.0.1" sp-std = { version = "4.0.0", path = "../../std" } sp-version = { version = "4.0.0-dev", path = "../../version" } -sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } +sp-runtime = { version = "5.0.0", path = "../../runtime" } thiserror = "1.0.30" [dev-dependencies] diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index 810e9c23a6599..f70af90afd6d3 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../runtime" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } +sp-core = { version = "5.0.0", default-features = false, path = "../../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } [features] diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index ea2a862189826..18506980ae85d 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0", features = ["derive"], optional = true } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../arithmetic" } [features] diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 7504a159a3db7..3277a3ff96916 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { version = "2.0.0", package = "parity-scale-codec", default-features = false } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } sp-std = { version = "4.0.0", path = "../../std", default-features = false } -sp-core = { version = "4.1.0-dev", path = "../../core", default-features = false } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../runtime" } +sp-core = { version = "5.0.0", path = "../../core", default-features = false } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } [features] default = ["std"] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 43f2b54044c9b..90138ded4cb19 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-core" -version = "4.1.0-dev" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -38,8 +38,8 @@ lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.11.2", optional = true } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } -sp-storage = { version = "4.0.0", default-features = false, path = "../storage" } -sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } +sp-storage = { version = "5.0.0", default-features = false, path = "../storage" } +sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } futures = { version = "0.3.1", optional = true } dyn-clonable = { version = "0.9.0", optional = true } @@ -61,7 +61,7 @@ libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", merlin = { version = "2.0", default-features = false, optional = true } ss58-registry = { version = "1.11.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } -sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../runtime-interface" } +sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../runtime-interface" } [dev-dependencies] sp-serializer = { version = "4.0.0-dev", path = "../serializer" } diff --git a/primitives/externalities/Cargo.toml b/primitives/externalities/Cargo.toml index 6c26b436796ee..7b7beb51e7809 100644 --- a/primitives/externalities/Cargo.toml +++ b/primitives/externalities/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-externalities" -version = "0.10.0" +version = "0.11.0" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2021" @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-storage = { version = "4.0.0", path = "../storage", default-features = false } +sp-storage = { version = "5.0.0", path = "../storage", default-features = false } sp-std = { version = "4.0.0", path = "../std", default-features = false } environmental = { version = "1.1.3", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index e36c088c35838..bb0b8b8509aca 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -21,10 +21,10 @@ grandpa = { package = "finality-grandpa", version = "0.14.1", default-features = log = { version = "0.4.8", optional = true } serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-keystore = { version = "0.10.0", default-features = false, path = "../keystore", optional = true } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-keystore = { version = "0.11.0", default-features = false, path = "../keystore", optional = true } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 02f084b6e6342..f78f4aea14e47 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-runtime = { version = "4.1.0-dev", path = "../runtime", optional = true } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "5.0.0", path = "../runtime", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } impl-trait-for-tuples = "0.2.0" diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index ee3c9e8945eb2..207a1a23e81d9 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-io" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -17,15 +17,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } hash-db = { version = "0.15.2", default-features = false } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-keystore = { version = "0.10.0", default-features = false, optional = true, path = "../keystore" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-keystore = { version = "0.11.0", default-features = false, optional = true, path = "../keystore" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } libsecp256k1 = { version = "0.7", optional = true } -sp-state-machine = { version = "0.10.0", optional = true, path = "../state-machine" } -sp-wasm-interface = { version = "4.1.0-dev", path = "../wasm-interface", default-features = false } -sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../runtime-interface" } -sp-trie = { version = "4.0.0", optional = true, path = "../trie" } -sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } +sp-state-machine = { version = "0.11.0", optional = true, path = "../state-machine" } +sp-wasm-interface = { version = "5.0.0", path = "../wasm-interface", default-features = false } +sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../runtime-interface" } +sp-trie = { version = "5.0.0", optional = true, path = "../trie" } +sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.8", optional = true } futures = { version = "0.3.1", features = ["thread-pool"], optional = true } diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index a31dcc51d0fbe..2f8e935b2457f 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.1.0-dev", path = "../core" } -sp-runtime = { version = "4.1.0-dev", path = "../runtime" } +sp-core = { version = "5.0.0", path = "../core" } +sp-runtime = { version = "5.0.0", path = "../runtime" } lazy_static = "1.4.0" strum = { version = "0.23.0", features = ["derive"] } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 28802cbec35e7..26748d3227d6f 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-keystore" -version = "0.10.0" +version = "0.11.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -22,8 +22,8 @@ thiserror = "1.0" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } merlin = { version = "2.0", default-features = false } -sp-core = { version = "4.1.0-dev", path = "../core" } -sp-externalities = { version = "0.10.0", path = "../externalities", default-features = false } +sp-core = { version = "5.0.0", path = "../core" } +sp-externalities = { version = "0.11.0", path = "../externalities", default-features = false } [dev-dependencies] rand = "0.7.2" diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 062f786aaef1c..f392895a945ee 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -19,8 +19,8 @@ serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-runtime = { version = "4.1.0-dev", path = "../runtime", default-features = false } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "5.0.0", path = "../runtime", default-features = false } [dev-dependencies] substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 3b6103552e214..335195e9bf5b1 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -21,7 +21,7 @@ rand = { version = "0.8", features = ["std", "small_rng"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } -sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } +sp-runtime = { version = "5.0.0", path = "../../runtime" } [[bin]] name = "reduce" diff --git a/primitives/offchain/Cargo.toml b/primitives/offchain/Cargo.toml index 7e0ce31d5d0c4..a96cd852bf24d 100644 --- a/primitives/offchain/Cargo.toml +++ b/primitives/offchain/Cargo.toml @@ -13,9 +13,9 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } [features] default = ["std"] diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index 52fe09b2c7894..137be2c6eee2c 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-rpc" -version = "4.0.0-dev" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.132", features = ["derive"] } -sp-core = { version = "4.1.0-dev", path = "../core" } +sp-core = { version = "5.0.0", path = "../core" } rustc-hash = "1.1.0" [dev-dependencies] diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 137780c3c91e8..89805a9db36dd 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime-interface" -version = "4.1.0-dev" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -14,22 +14,22 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-wasm-interface = { version = "4.1.0-dev", path = "../wasm-interface", default-features = false } +sp-wasm-interface = { version = "5.0.0", path = "../wasm-interface", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } sp-runtime-interface-proc-macro = { version = "4.0.0", path = "proc-macro" } -sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } +sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } static_assertions = "1.0.0" primitive-types = { version = "0.10.1", default-features = false } -sp-storage = { version = "4.0.0", default-features = false, path = "../storage" } +sp-storage = { version = "5.0.0", default-features = false, path = "../storage" } impl-trait-for-tuples = "0.2.1" [dev-dependencies] sp-runtime-interface-test-wasm = { version = "2.0.0", path = "test-wasm" } -sp-state-machine = { version = "0.10.0", path = "../state-machine" } -sp-core = { version = "4.1.0-dev", path = "../core" } -sp-io = { version = "4.0.0-dev", path = "../io" } +sp-state-machine = { version = "0.11.0", path = "../state-machine" } +sp-core = { version = "5.0.0", path = "../core" } +sp-io = { version = "5.0.0", path = "../io" } rustversion = "1.0.6" trybuild = "1.0.53" diff --git a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 032de1d215f25..18046626f6508 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -13,10 +13,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../" } +sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../io" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../io" } +sp-core = { version = "5.0.0", default-features = false, path = "../../core" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index 80ad44569e999..9b6bdf39eb4c0 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -13,10 +13,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../" } +sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-io = { version = "4.0.0-dev", default-features = false, path = "../../io" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } +sp-io = { version = "5.0.0", default-features = false, path = "../../io" } +sp-core = { version = "5.0.0", default-features = false, path = "../../core" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 82c6a21b995cc..107a8fcc7f2a4 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -12,13 +12,13 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "4.1.0-dev", path = "../" } +sp-runtime-interface = { version = "5.0.0", path = "../" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-executor-common = { version = "0.10.0-dev", path = "../../../client/executor/common" } sp-runtime-interface-test-wasm = { version = "2.0.0", path = "../test-wasm" } sp-runtime-interface-test-wasm-deprecated = { version = "2.0.0", path = "../test-wasm-deprecated" } -sp-state-machine = { version = "0.10.0", path = "../../state-machine" } -sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } -sp-io = { version = "4.0.0", path = "../../io" } +sp-state-machine = { version = "0.11.0", path = "../../state-machine" } +sp-runtime = { version = "5.0.0", path = "../../runtime" } +sp-io = { version = "5.0.0", path = "../../io" } tracing = "0.1.29" tracing-core = "0.1.17" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index e6bb5a1c842e5..4f793c8faa947 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime" -version = "4.1.0-dev" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -18,11 +18,11 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.132", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-io = { version = "4.0.0", default-features = false, path = "../io" } +sp-io = { version = "5.0.0", default-features = false, path = "../io" } log = { version = "0.4.14", default-features = false } paste = "1.0" rand = { version = "0.7.2", optional = true } @@ -34,7 +34,7 @@ either = { version = "1.5", default-features = false } [dev-dependencies] serde_json = "1.0.74" rand = "0.7.2" -sp-state-machine = { version = "0.10.0", path = "../state-machine" } +sp-state-machine = { version = "0.11.0", path = "../state-machine" } sp-api = { version = "4.0.0-dev", path = "../api" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index 59941c9648ddd..a72786807330d 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -20,10 +20,10 @@ wasmi = "0.9.0" [dependencies] wasmi = { version = "0.9.0", optional = true } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-io = { version = "4.0.0", default-features = false, path = "../io" } -sp-wasm-interface = { version = "4.1.0-dev", default-features = false, path = "../wasm-interface" } +sp-io = { version = "5.0.0", default-features = false, path = "../io" } +sp-wasm-interface = { version = "5.0.0", default-features = false, path = "../wasm-interface" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } log = { version = "0.4", default-features = false } diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index 293f3642b7f33..4138ecb519df6 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" } -sp-runtime = { version = "4.1.0-dev", optional = true, path = "../runtime" } +sp-runtime = { version = "5.0.0", optional = true, path = "../runtime" } [features] default = [ "std" ] diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 6ae972f1814be..54e556dfae122 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index c885f99fdb839..15720688c0585 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-state-machine" -version = "0.10.0" +version = "0.11.0" authors = ["Parity Technologies "] description = "Substrate State Machine" edition = "2021" @@ -20,20 +20,20 @@ parking_lot = { version = "0.11.2", optional = true } hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.23.0", default-features = false } trie-root = { version = "0.17.0", default-features = false } -sp-trie = { version = "4.0.0", path = "../trie", default-features = false } -sp-core = { version = "4.1.0-dev", path = "../core", default-features = false } +sp-trie = { version = "5.0.0", path = "../trie", default-features = false } +sp-core = { version = "5.0.0", path = "../core", default-features = false } sp-panic-handler = { version = "4.0.0", path = "../panic-handler", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } num-traits = { version = "0.2.8", default-features = false } rand = { version = "0.7.2", optional = true } -sp-externalities = { version = "0.10.0", path = "../externalities", default-features = false } +sp-externalities = { version = "0.11.0", path = "../externalities", default-features = false } smallvec = "1.7.0" sp-std = { version = "4.0.0", default-features = false, path = "../std" } tracing = { version = "0.1.29", optional = true } [dev-dependencies] hex-literal = "0.3.4" -sp-runtime = { version = "4.1.0-dev", path = "../runtime" } +sp-runtime = { version = "5.0.0", path = "../runtime" } pretty_assertions = "1.0.0" rand = "0.7.2" diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index 81e4140bbd36f..d3c22ce70651d 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-storage" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" description = "Storage related primitives" diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index 6ac6c6aa98bec..00943e8657205 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -15,10 +15,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.8", optional = true } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } -sp-io = { version = "4.0.0", default-features = false, path = "../io" } -sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../runtime-interface" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } +sp-io = { version = "5.0.0", default-features = false, path = "../io" } +sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../runtime-interface" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index ab2ef0d54ca4b..41fd6173cd8a5 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -12,11 +12,11 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } serde = { version = "1.0.132", optional = true, features = ["derive"] } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } [features] diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index e42ca738cd55e..f7ac2e663e397 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/transaction-pool/Cargo.toml b/primitives/transaction-pool/Cargo.toml index fab5f90ffffc0..c8f70bdce9de2 100644 --- a/primitives/transaction-pool/Cargo.toml +++ b/primitives/transaction-pool/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } [features] default = [ "std" ] diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index 87f7f81cd5868..9e2898fe267e1 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-trie = { version = "4.0.0", optional = true, path = "../trie" } -sp-core = { version = "4.1.0-dev", path = "../core", optional = true } +sp-trie = { version = "5.0.0", optional = true, path = "../trie" } +sp-core = { version = "5.0.0", path = "../core", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.8", optional = true } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 4564fa86ced95..e79f2ffb7f845 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-trie" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] description = "Patricia trie stuff using a parity-scale-codec node format" repository = "https://github.com/paritytech/substrate/" @@ -25,14 +25,14 @@ hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.23.0", default-features = false } trie-root = { version = "0.17.0", default-features = false } memory-db = { version = "0.28.0", default-features = false } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } +sp-core = { version = "5.0.0", default-features = false, path = "../core" } [dev-dependencies] trie-bench = "0.29.0" trie-standardmap = "0.15.2" criterion = "0.3.3" hex-literal = "0.3.4" -sp-runtime = { version = "4.1.0-dev", path = "../runtime" } +sp-runtime = { version = "5.0.0", path = "../runtime" } [features] default = ["std"] diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 1bb39eca13640..48091ba709cb0 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -19,7 +19,7 @@ serde = { version = "1.0.132", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" } parity-wasm = { version = "0.42.2", optional = true } sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../core/hashing/proc-macro" } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 200c686243e02..bb82629ba01e8 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-wasm-interface" -version = "4.1.0-dev" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 902a14b1b3bdf..5f687b24896d2 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -29,9 +29,9 @@ sc-service = { version = "0.10.0-dev", default-features = false, features = [ ], path = "../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } +sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } -sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } +sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } async-trait = "0.1.50" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index e88f571366020..f1b06d3b3ec2b 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } @@ -23,27 +23,27 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../primitives/keyring" } memory-db = { version = "0.27.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } -sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } +sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime-interface" } -sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../../primitives/runtime-interface" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../frame/support" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../frame/babe" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../frame/system" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../frame/system/rpc/runtime-api" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../frame/timestamp" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } -sp-trie = { version = "4.0.0", default-features = false, path = "../../primitives/trie" } +sp-trie = { version = "5.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } trie-db = { version = "0.23.0", default-features = false } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } -sp-state-machine = { version = "0.10.0", default-features = false, path = "../../primitives/state-machine" } -sp-externalities = { version = "0.10.0", default-features = false, path = "../../primitives/externalities" } +sp-state-machine = { version = "0.11.0", default-features = false, path = "../../primitives/state-machine" } +sp-externalities = { version = "0.11.0", default-features = false, path = "../../primitives/externalities" } # 3rd party cfg-if = "1.0" diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index ba0f01cfced99..fd260453ca181 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -16,9 +16,9 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } substrate-test-client = { version = "2.0.0", path = "../../client" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } substrate-test-runtime = { version = "2.0.0", path = "../../runtime" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index 2a94f24845871..ef2ebd64fb225 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -16,7 +16,7 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../client" } parking_lot = "0.11.2" codec = { package = "parity-scale-codec", version = "2.0.0" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } futures = "0.3.16" diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index a7e5b76ad97ac..971fb31a3f8c9 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } -sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } -sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } +sp-externalities = { version = "0.11.0", path = "../../../primitives/externalities" } +sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } codec = { version = "2.0.0", package = "parity-scale-codec" } clap = { version = "3.0", features = ["derive"] } chrono = "0.4" diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index f330b205ea27f..50a00db1d4d38 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -13,9 +13,9 @@ readme = "README.md" [dependencies] clap = { version = "3.0", features = ["derive"] } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 55670c96f792c..5bda705a581a9 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -17,7 +17,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-staking = { version = "4.0.0-dev", path = "../../../frame/staking" } # primitives -sp-io = { version = "4.0.0", path = "../../../primitives/io" } +sp-io = { version = "5.0.0", path = "../../../primitives/io" } # third party chrono = { version = "0.4.19" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 9e0b17a7b58f8..c1d6f1b1c5f54 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -22,9 +22,9 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } serde_json = "1.0" serde = "1.0.132" -sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } -sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } +sp-io = { version = "5.0.0", path = "../../../primitives/io" } +sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } [dev-dependencies] diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 6ecaabd720595..fcb5a4367386d 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -20,7 +20,7 @@ jsonrpc-client-transports = { version = "18.0.0", features = ["http"] } codec = { package = "parity-scale-codec", version = "2.0.0" } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } -sp-storage = { version = "4.0.0", path = "../../../../primitives/storage" } +sp-storage = { version = "5.0.0", path = "../../../../primitives/storage" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } [dev-dependencies] diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index cb801c6cbf275..8ce72416dac2a 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -20,10 +20,10 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" log = "0.4.8" -sp-runtime = { version = "4.1.0-dev", path = "../../../../primitives/runtime" } +sp-runtime = { version = "5.0.0", path = "../../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } -sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } +sp-core = { version = "5.0.0", path = "../../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../../client/transaction-pool/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../../primitives/block-builder" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 812310ff17d26..541706257ba1c 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -23,12 +23,12 @@ sc-service = { version = "0.10.0-dev", default-features = false, path = "../../. sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } -sp-state-machine = { version = "0.10.0", path = "../../../../primitives/state-machine" } -sp-runtime = { version = "4.1.0-dev", path = "../../../../primitives/runtime" } -sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } -sp-io = { version = "4.0.0-dev", path = "../../../../primitives/io" } -sp-keystore = { version = "0.10.0", path = "../../../../primitives/keystore" } -sp-externalities = { version = "0.10.0", path = "../../../../primitives/externalities" } +sp-state-machine = { version = "0.11.0", path = "../../../../primitives/state-machine" } +sp-runtime = { version = "5.0.0", path = "../../../../primitives/runtime" } +sp-core = { version = "5.0.0", path = "../../../../primitives/core" } +sp-io = { version = "5.0.0", path = "../../../../primitives/io" } +sp-keystore = { version = "0.11.0", path = "../../../../primitives/keystore" } +sp-externalities = { version = "0.11.0", path = "../../../../primitives/externalities" } sp-version = { version = "4.0.0-dev", path = "../../../../primitives/version" } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } From 5948416d0ebd5d3a154088b7be0adf05c16a0812 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Wed, 2 Feb 2022 12:29:36 +0100 Subject: [PATCH 0477/1472] Enable download of future forks (#10739) * Enable download of future forks * Fixed external tests --- client/network/src/protocol/sync.rs | 8 +++- client/network/test/src/lib.rs | 58 ++++++++++++++++---------- client/network/test/src/sync.rs | 63 ++++++++++++++++++++++++----- 3 files changed, 97 insertions(+), 32 deletions(-) diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index d6513ca2e5b9d..fbb4e376b1b4f 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -2418,7 +2418,11 @@ fn fork_sync_request( if !r.peers.contains(id) { continue } - if r.number <= best_num { + // Download the fork only if it is behind or not too far ahead our tip of the chain + // Otherwise it should be downloaded in full sync mode. + if r.number <= best_num || + (r.number - best_num).saturated_into::() < MAX_BLOCKS_TO_REQUEST as u32 + { let parent_status = r.parent_hash.as_ref().map_or(BlockStatus::Unknown, check_block); let count = if parent_status == BlockStatus::Unknown { (r.number - finalized).saturated_into::() // up to the last finalized block @@ -2438,6 +2442,8 @@ fn fork_sync_request( max: Some(count), }, )) + } else { + trace!(target: "sync", "Fork too far in the future: {:?} (#{})", hash, r.number); } } None diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index b2345f3701b0a..3986ac47f3616 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -86,7 +86,6 @@ type AuthorityId = sp_consensus_babe::AuthorityId; #[derive(Clone)] pub struct PassThroughVerifier { finalized: bool, - fork_choice: ForkChoiceStrategy, } impl PassThroughVerifier { @@ -94,15 +93,7 @@ impl PassThroughVerifier { /// /// Every verified block will use `finalized` for the `BlockImportParams`. pub fn new(finalized: bool) -> Self { - Self { finalized, fork_choice: ForkChoiceStrategy::LongestChain } - } - - /// Create a new instance. - /// - /// Every verified block will use `finalized` for the `BlockImportParams` and - /// the given [`ForkChoiceStrategy`]. - pub fn new_with_fork_choice(finalized: bool, fork_choice: ForkChoiceStrategy) -> Self { - Self { finalized, fork_choice } + Self { finalized } } } @@ -121,8 +112,10 @@ impl Verifier for PassThroughVerifier { .or_else(|| l.try_as_raw(OpaqueDigestItemId::Consensus(b"babe"))) }) .map(|blob| vec![(well_known_cache_keys::AUTHORITIES, blob.to_vec())]); + if block.fork_choice.is_none() { + block.fork_choice = Some(ForkChoiceStrategy::LongestChain); + }; block.finalized = self.finalized; - block.fork_choice = Some(self.fork_choice.clone()); Ok((block, maybe_keys)) } } @@ -309,6 +302,33 @@ where false, true, true, + ForkChoiceStrategy::LongestChain, + ) + } + + /// Add blocks to the peer -- edit the block before adding and use custom fork choice rule. + pub fn generate_blocks_with_fork_choice( + &mut self, + count: usize, + origin: BlockOrigin, + edit_block: F, + fork_choice: ForkChoiceStrategy, + ) -> H256 + where + F: FnMut( + BlockBuilder, + ) -> Block, + { + let best_hash = self.client.info().best_hash; + self.generate_blocks_at( + BlockId::Hash(best_hash), + count, + origin, + edit_block, + false, + true, + true, + fork_choice, ) } @@ -323,6 +343,7 @@ where headers_only: bool, inform_sync_about_new_best_block: bool, announce_block: bool, + fork_choice: ForkChoiceStrategy, ) -> H256 where F: FnMut( @@ -346,6 +367,7 @@ where let header = block.header.clone(); let mut import_block = BlockImportParams::new(origin, header.clone()); import_block.body = if headers_only { None } else { Some(block.extrinsics) }; + import_block.fork_choice = Some(fork_choice); let (import_block, cache) = futures::executor::block_on(self.verifier.verify(import_block)).unwrap(); let cache = if let Some(cache) = cache { @@ -442,6 +464,7 @@ where headers_only, inform_sync_about_new_best_block, announce_block, + ForkChoiceStrategy::LongestChain, ) } else { self.generate_blocks_at( @@ -452,6 +475,7 @@ where headers_only, inform_sync_about_new_best_block, announce_block, + ForkChoiceStrategy::LongestChain, ) } } @@ -989,14 +1013,6 @@ where pub struct TestNet { peers: Vec>, - fork_choice: ForkChoiceStrategy, -} - -impl TestNet { - /// Create a `TestNet` that used the given fork choice rule. - pub fn with_fork_choice(fork_choice: ForkChoiceStrategy) -> Self { - Self { peers: Vec::new(), fork_choice } - } } impl TestNetFactory for TestNet { @@ -1006,7 +1022,7 @@ impl TestNetFactory for TestNet { /// Create new test network with peers and given config. fn from_config(_config: &ProtocolConfig) -> Self { - TestNet { peers: Vec::new(), fork_choice: ForkChoiceStrategy::LongestChain } + TestNet { peers: Vec::new() } } fn make_verifier( @@ -1015,7 +1031,7 @@ impl TestNetFactory for TestNet { _config: &ProtocolConfig, _peer_data: &(), ) -> Self::Verifier { - PassThroughVerifier::new_with_fork_choice(false, self.fork_choice.clone()) + PassThroughVerifier::new(false) } fn make_block_import( diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index 5b607a7762b34..84a5c2ca13fa5 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -453,6 +453,38 @@ fn can_sync_small_non_best_forks() { })); } +#[test] +fn can_sync_forks_ahead_of_the_best_chain() { + sp_tracing::try_init_simple(); + let mut net = TestNet::new(2); + net.peer(0).push_blocks(1, false); + net.peer(1).push_blocks(1, false); + + net.block_until_connected(); + // Peer 0 is on 2-block fork which is announced with is_best=false + let fork_hash = net.peer(0).generate_blocks_with_fork_choice( + 2, + BlockOrigin::Own, + |builder| builder.build().unwrap().block, + ForkChoiceStrategy::Custom(false), + ); + // Peer 1 is on 1-block fork + net.peer(1).push_blocks(1, false); + assert!(net.peer(0).client().header(&BlockId::Hash(fork_hash)).unwrap().is_some()); + assert_eq!(net.peer(0).client().info().best_number, 1); + assert_eq!(net.peer(1).client().info().best_number, 2); + + // after announcing, peer 1 downloads the block. + block_on(futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); + + if net.peer(1).client().header(&BlockId::Hash(fork_hash)).unwrap().is_none() { + return Poll::Pending + } + Poll::Ready(()) + })); +} + #[test] fn can_sync_explicit_forks() { sp_tracing::try_init_simple(); @@ -678,7 +710,7 @@ impl BlockAnnounceValidator for FailingBlockAnnounceValidator { #[test] fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { sp_tracing::try_init_simple(); - let mut net = TestNet::with_fork_choice(ForkChoiceStrategy::Custom(false)); + let mut net = TestNet::new(0); net.add_full_peer_with_config(Default::default()); net.add_full_peer_with_config(Default::default()); net.add_full_peer_with_config(FullPeerConfig { @@ -688,16 +720,17 @@ fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { net.block_until_connected(); - let block_hash = net.peer(0).push_blocks(1, false); + // Add blocks but don't set them as best + let block_hash = net.peer(0).generate_blocks_with_fork_choice( + 1, + BlockOrigin::Own, + |builder| builder.build().unwrap().block, + ForkChoiceStrategy::Custom(false), + ); while !net.peer(2).has_block(&block_hash) { net.block_until_idle(); } - - // Peer1 should not have the block, because peer 0 did not reported the block - // as new best. However, peer2 has a special block announcement validator - // that flags all blocks as `is_new_best` and thus, it should have synced the blocks. - assert!(!net.peer(1).has_block(&block_hash)); } /// Waits for some time until the validation is successfull. @@ -721,7 +754,7 @@ impl BlockAnnounceValidator for DeferredBlockAnnounceValidator { #[test] fn wait_until_deferred_block_announce_validation_is_ready() { sp_tracing::try_init_simple(); - let mut net = TestNet::with_fork_choice(ForkChoiceStrategy::Custom(false)); + let mut net = TestNet::new(0); net.add_full_peer_with_config(Default::default()); net.add_full_peer_with_config(FullPeerConfig { block_announce_validator: Some(Box::new(NewBestBlockAnnounceValidator)), @@ -730,7 +763,13 @@ fn wait_until_deferred_block_announce_validation_is_ready() { net.block_until_connected(); - let block_hash = net.peer(0).push_blocks(1, true); + // Add blocks but don't set them as best + let block_hash = net.peer(0).generate_blocks_with_fork_choice( + 1, + BlockOrigin::Own, + |builder| builder.build().unwrap().block, + ForkChoiceStrategy::Custom(false), + ); while !net.peer(1).has_block(&block_hash) { net.block_until_idle(); @@ -847,7 +886,10 @@ fn block_announce_data_is_propagated() { // Wait until peer 1 is connected to both nodes. block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(1).num_peers() == 2 { + if net.peer(1).num_peers() == 2 && + net.peer(0).num_peers() == 1 && + net.peer(2).num_peers() == 1 + { Poll::Ready(()) } else { Poll::Pending @@ -1109,6 +1151,7 @@ fn syncs_indexed_blocks() { false, true, true, + ForkChoiceStrategy::LongestChain, ); let indexed_key = sp_runtime::traits::BlakeTwo256::hash(&42u64.to_le_bytes()); assert!(net From 529c2fd27d3d584951f73ba05bdea357117eadec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 2 Feb 2022 12:34:52 +0100 Subject: [PATCH 0478/1472] wasm-builder: Fall back to `release` profile for unknown profiles (#10775) --- utils/wasm-builder/src/wasm_project.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 541c6290166c3..20e176444c621 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -476,8 +476,21 @@ impl Profile { (Some(Profile::Debug), false) => Profile::Release, // For any other profile or when overriden we take it at face value. (Some(profile), _) => profile, + // For non overriden unknown profiles we fall back to `Release`. + // This allows us to continue building when a custom profile is used for the + // main builds cargo. When explicitly passing a profile via env variable we are + // not doing a fallback. + (None, false) => { + let profile = Profile::Release; + build_helper::warning!( + "Unknown cargo profile `{}`. Defaulted to `{:?}` for the runtime build.", + name, + profile, + ); + profile + }, // Invalid profile specified. - (None, _) => { + (None, true) => { // We use println! + exit instead of a panic in order to have a cleaner output. println!( "Unexpected profile name: `{}`. One of the following is expected: {:?}", @@ -627,8 +640,8 @@ fn compress_wasm(wasm_binary_path: &Path, compressed_binary_out_path: &Path) -> true } else { - println!( - "cargo:warning=Writing uncompressed wasm. Exceeded maximum size {}", + build_helper::warning!( + "Writing uncompressed wasm. Exceeded maximum size {}", CODE_BLOB_BOMB_LIMIT, ); From e570d2ee4225972db1c28a318a04211a65dd8e87 Mon Sep 17 00:00:00 2001 From: Pierre Besson Date: Wed, 2 Feb 2022 13:06:25 +0100 Subject: [PATCH 0479/1472] Substrate alerts rules update (#10642) * .maintain/monitoring: Update substrate prometheus alert rules * match the `substrate_` metrics prefix in alerts instead of `polkadot_`, following changes in #9543 * remove the filtering on polkadot|kusama domain for NumberOfFileDescriptorsHigh alert * .maintain/monitoring: Update substrate Grafana dashboards * match the `substrate_` metrics prefix instead of `polkadot_` in dashboards, following changes in #9543 * .maintain/monitoring: make the NumberOfFileDescriptorsHigh alert only apply for metrics tagged with 'chain' --- .../alerting-rules/alerting-rule-tests.yaml | 144 +++++++++--------- .../alerting-rules/alerting-rules.yaml | 50 +++--- .../substrate-networking.json | 2 +- .../substrate-service-tasks.json | 2 +- 4 files changed, 99 insertions(+), 99 deletions(-) diff --git a/.maintain/monitoring/alerting-rules/alerting-rule-tests.yaml b/.maintain/monitoring/alerting-rules/alerting-rule-tests.yaml index 7ad916f022154..df5e020d067ea 100644 --- a/.maintain/monitoring/alerting-rules/alerting-rule-tests.yaml +++ b/.maintain/monitoring/alerting-rules/alerting-rule-tests.yaml @@ -6,39 +6,39 @@ evaluation_interval: 1m tests: - interval: 1m input_series: - - series: 'polkadot_sub_libp2p_peers_count{ - job="polkadot", - pod="polkadot-abcdef01234-abcdef", - instance="polkadot-abcdef01234-abcdef", + - series: 'substrate_sub_libp2p_peers_count{ + job="substrate", + pod="substrate-abcdef01234-abcdef", + instance="substrate-abcdef01234-abcdef", }' values: '3 2+0x4 1+0x9' # 3 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 - - series: 'polkadot_sub_txpool_validations_scheduled{ - job="polkadot", - pod="polkadot-abcdef01234-abcdef", - instance="polkadot-abcdef01234-abcdef", + - series: 'substrate_sub_txpool_validations_scheduled{ + job="substrate", + pod="substrate-abcdef01234-abcdef", + instance="substrate-abcdef01234-abcdef", }' values: '11+1x10 22+2x30 10043x5' - - series: 'polkadot_sub_txpool_validations_finished{ - job="polkadot", - pod="polkadot-abcdef01234-abcdef", - instance="polkadot-abcdef01234-abcdef", + - series: 'substrate_sub_txpool_validations_finished{ + job="substrate", + pod="substrate-abcdef01234-abcdef", + instance="substrate-abcdef01234-abcdef", }' values: '0+1x42 42x5' - - series: 'polkadot_block_height{ - status="best", job="polkadot", - pod="polkadot-abcdef01234-abcdef", - instance="polkadot-abcdef01234-abcdef", + - series: 'substrate_block_height{ + status="best", job="substrate", + pod="substrate-abcdef01234-abcdef", + instance="substrate-abcdef01234-abcdef", }' values: '1+1x3 4+0x13' # 1 2 3 4 4 4 4 4 4 4 4 4 ... - - series: 'polkadot_block_height{ + - series: 'substrate_block_height{ status="finalized", - job="polkadot", - pod="polkadot-abcdef01234-abcdef", - instance="polkadot-abcdef01234-abcdef", + job="substrate", + pod="substrate-abcdef01234-abcdef", + instance="substrate-abcdef01234-abcdef", }' values: '1+1x3 4+0x13' # 1 2 3 4 4 4 4 4 4 4 4 4 ... @@ -56,13 +56,13 @@ tests: exp_alerts: - exp_labels: severity: warning - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate status: best exp_annotations: message: "Best block on instance - polkadot-abcdef01234-abcdef increases by less than 1 per + substrate-abcdef01234-abcdef increases by less than 1 per minute for more than 3 minutes." - eval_time: 14m @@ -70,23 +70,23 @@ tests: exp_alerts: - exp_labels: severity: warning - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate status: best exp_annotations: message: "Best block on instance - polkadot-abcdef01234-abcdef increases by less than 1 per + substrate-abcdef01234-abcdef increases by less than 1 per minute for more than 3 minutes." - exp_labels: severity: critical - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate status: best exp_annotations: message: "Best block on instance - polkadot-abcdef01234-abcdef increases by less than 1 per + substrate-abcdef01234-abcdef increases by less than 1 per minute for more than 10 minutes." ###################################################################### @@ -101,13 +101,13 @@ tests: exp_alerts: - exp_labels: severity: warning - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate status: finalized exp_annotations: message: "Finalized block on instance - polkadot-abcdef01234-abcdef increases by less than 1 per + substrate-abcdef01234-abcdef increases by less than 1 per minute for more than 3 minutes." - eval_time: 14m @@ -115,23 +115,23 @@ tests: exp_alerts: - exp_labels: severity: warning - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate status: finalized exp_annotations: message: "Finalized block on instance - polkadot-abcdef01234-abcdef increases by less than 1 per + substrate-abcdef01234-abcdef increases by less than 1 per minute for more than 3 minutes." - exp_labels: severity: critical - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate status: finalized exp_annotations: message: "Finalized block on instance - polkadot-abcdef01234-abcdef increases by less than 1 per + substrate-abcdef01234-abcdef increases by less than 1 per minute for more than 10 minutes." ###################################################################### @@ -152,12 +152,12 @@ tests: exp_alerts: - exp_labels: severity: warning - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate exp_annotations: message: "The transaction pool size on node - polkadot-abcdef01234-abcdef has been monotonically + substrate-abcdef01234-abcdef has been monotonically increasing for more than 10 minutes." - eval_time: 43m alertname: TransactionQueueSizeIncreasing @@ -167,21 +167,21 @@ tests: exp_alerts: - exp_labels: severity: warning - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate exp_annotations: message: "The transaction pool size on node - polkadot-abcdef01234-abcdef has been monotonically + substrate-abcdef01234-abcdef has been monotonically increasing for more than 10 minutes." - exp_labels: severity: warning - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate exp_annotations: message: "The transaction pool size on node - polkadot-abcdef01234-abcdef has been monotonically + substrate-abcdef01234-abcdef has been monotonically increasing for more than 30 minutes." - eval_time: 49m alertname: TransactionQueueSizeHigh @@ -191,12 +191,12 @@ tests: exp_alerts: - exp_labels: severity: warning - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate exp_annotations: message: "The transaction pool size on node - polkadot-abcdef01234-abcdef has been above 10_000 for more + substrate-abcdef01234-abcdef has been above 10_000 for more than 5 minutes." ###################################################################### @@ -211,11 +211,11 @@ tests: exp_alerts: - exp_labels: severity: warning - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate exp_annotations: - message: "The node polkadot-abcdef01234-abcdef has less + message: "The node substrate-abcdef01234-abcdef has less than 3 peers for more than 3 minutes" - eval_time: 16m # Values: 3 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 @@ -223,17 +223,17 @@ tests: exp_alerts: - exp_labels: severity: warning - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate exp_annotations: - message: "The node polkadot-abcdef01234-abcdef has less + message: "The node substrate-abcdef01234-abcdef has less than 3 peers for more than 3 minutes" - exp_labels: severity: critical - pod: polkadot-abcdef01234-abcdef - instance: polkadot-abcdef01234-abcdef - job: polkadot + pod: substrate-abcdef01234-abcdef + instance: substrate-abcdef01234-abcdef + job: substrate exp_annotations: - message: "The node polkadot-abcdef01234-abcdef has less + message: "The node substrate-abcdef01234-abcdef has less than 3 peers for more than 15 minutes" diff --git a/.maintain/monitoring/alerting-rules/alerting-rules.yaml b/.maintain/monitoring/alerting-rules/alerting-rules.yaml index 2711610024330..4171f92f68fef 100644 --- a/.maintain/monitoring/alerting-rules/alerting-rules.yaml +++ b/.maintain/monitoring/alerting-rules/alerting-rules.yaml @@ -1,5 +1,5 @@ groups: -- name: polkadot.rules +- name: substrate.rules rules: ############################################################################## @@ -10,7 +10,7 @@ groups: annotations: message: 'Best block on instance {{ $labels.instance }} increases by less than 1 per minute for more than 3 minutes.' - expr: increase(polkadot_block_height{status="best"}[1m]) < 1 + expr: increase(substrate_block_height{status="best"}[1m]) < 1 for: 3m labels: severity: warning @@ -18,7 +18,7 @@ groups: annotations: message: 'Best block on instance {{ $labels.instance }} increases by less than 1 per minute for more than 10 minutes.' - expr: increase(polkadot_block_height{status="best"}[1m]) < 1 + expr: increase(substrate_block_height{status="best"}[1m]) < 1 for: 10m labels: severity: critical @@ -28,7 +28,7 @@ groups: ############################################################################## - alert: BlockFinalizationSlow - expr: increase(polkadot_block_height{status="finalized"}[1m]) < 1 + expr: increase(substrate_block_height{status="finalized"}[1m]) < 1 for: 3m labels: severity: warning @@ -36,7 +36,7 @@ groups: message: 'Finalized block on instance {{ $labels.instance }} increases by less than 1 per minute for more than 3 minutes.' - alert: BlockFinalizationSlow - expr: increase(polkadot_block_height{status="finalized"}[1m]) < 1 + expr: increase(substrate_block_height{status="finalized"}[1m]) < 1 for: 10m labels: severity: critical @@ -47,8 +47,8 @@ groups: # Under the assumption of an average block production of 6 seconds, # "best" and "finalized" being more than 10 blocks apart would imply # more than a 1 minute delay between block production and finalization. - expr: '(polkadot_block_height{status="best"} - ignoring(status) - polkadot_block_height{status="finalized"}) > 10' + expr: '(substrate_block_height{status="best"} - ignoring(status) + substrate_block_height{status="finalized"}) > 10' for: 8m labels: severity: critical @@ -61,8 +61,8 @@ groups: ############################################################################## - alert: TransactionQueueSizeIncreasing - expr: 'increase(polkadot_sub_txpool_validations_scheduled[5m]) - - increase(polkadot_sub_txpool_validations_finished[5m]) > 0' + expr: 'increase(substrate_sub_txpool_validations_scheduled[5m]) - + increase(substrate_sub_txpool_validations_finished[5m]) > 0' for: 10m labels: severity: warning @@ -70,8 +70,8 @@ groups: message: 'The transaction pool size on node {{ $labels.instance }} has been monotonically increasing for more than 10 minutes.' - alert: TransactionQueueSizeIncreasing - expr: 'increase(polkadot_sub_txpool_validations_scheduled[5m]) - - increase(polkadot_sub_txpool_validations_finished[5m]) > 0' + expr: 'increase(substrate_sub_txpool_validations_scheduled[5m]) - + increase(substrate_sub_txpool_validations_finished[5m]) > 0' for: 30m labels: severity: warning @@ -79,8 +79,8 @@ groups: message: 'The transaction pool size on node {{ $labels.instance }} has been monotonically increasing for more than 30 minutes.' - alert: TransactionQueueSizeHigh - expr: 'polkadot_sub_txpool_validations_scheduled - - polkadot_sub_txpool_validations_finished > 10000' + expr: 'substrate_sub_txpool_validations_scheduled - + substrate_sub_txpool_validations_finished > 10000' for: 5m labels: severity: warning @@ -93,7 +93,7 @@ groups: ############################################################################## - alert: NumberOfPeersLow - expr: polkadot_sub_libp2p_peers_count < 3 + expr: substrate_sub_libp2p_peers_count < 3 for: 3m labels: severity: warning @@ -101,7 +101,7 @@ groups: message: 'The node {{ $labels.instance }} has less than 3 peers for more than 3 minutes' - alert: NumberOfPeersLow - expr: polkadot_sub_libp2p_peers_count < 3 + expr: substrate_sub_libp2p_peers_count < 3 for: 15m labels: severity: critical @@ -109,7 +109,7 @@ groups: message: 'The node {{ $labels.instance }} has less than 3 peers for more than 15 minutes' - alert: NoIncomingConnection - expr: increase(polkadot_sub_libp2p_incoming_connections_total[20m]) == 0 + expr: increase(substrate_sub_libp2p_incoming_connections_total[20m]) == 0 labels: severity: warning annotations: @@ -121,7 +121,7 @@ groups: ############################################################################## - alert: NumberOfFileDescriptorsHigh - expr: 'node_filefd_allocated{domain=~"kusama|polkadot"} > 10000' + expr: 'node_filefd_allocated{chain!=""} > 10000' for: 3m labels: severity: warning @@ -134,9 +134,9 @@ groups: ############################################################################## - alert: AuthorityDiscoveryDiscoveryFailureHigh - expr: 'polkadot_authority_discovery_handle_value_found_event_failure / + expr: 'substrate_authority_discovery_handle_value_found_event_failure / ignoring(name) - polkadot_authority_discovery_dht_event_received{name="value_found"} > 0.5' + substrate_authority_discovery_dht_event_received{name="value_found"} > 0.5' for: 2h labels: severity: warning @@ -147,9 +147,9 @@ groups: - alert: UnboundedChannelPersistentlyLarge expr: '( - (polkadot_unbounded_channel_len{action = "send"} - - ignoring(action) polkadot_unbounded_channel_len{action = "received"}) - or on(instance) polkadot_unbounded_channel_len{action = "send"} + (substrate_unbounded_channel_len{action = "send"} - + ignoring(action) substrate_unbounded_channel_len{action = "received"}) + or on(instance) substrate_unbounded_channel_len{action = "send"} ) >= 200' for: 5m labels: @@ -160,9 +160,9 @@ groups: - alert: UnboundedChannelVeryLarge expr: '( - (polkadot_unbounded_channel_len{action = "send"} - - ignoring(action) polkadot_unbounded_channel_len{action = "received"}) - or on(instance) polkadot_unbounded_channel_len{action = "send"} + (substrate_unbounded_channel_len{action = "send"} - + ignoring(action) substrate_unbounded_channel_len{action = "received"}) + or on(instance) substrate_unbounded_channel_len{action = "send"} ) > 15000' labels: severity: warning diff --git a/.maintain/monitoring/grafana-dashboards/substrate-networking.json b/.maintain/monitoring/grafana-dashboards/substrate-networking.json index 46942cf582fc6..abd675ed13ec3 100644 --- a/.maintain/monitoring/grafana-dashboards/substrate-networking.json +++ b/.maintain/monitoring/grafana-dashboards/substrate-networking.json @@ -4,7 +4,7 @@ "name": "VAR_METRIC_NAMESPACE", "type": "constant", "label": "Prefix of the metrics", - "value": "polkadot", + "value": "substrate", "description": "" } ], diff --git a/.maintain/monitoring/grafana-dashboards/substrate-service-tasks.json b/.maintain/monitoring/grafana-dashboards/substrate-service-tasks.json index 2f08ac7bb34c5..ce7e9f78cd8ae 100644 --- a/.maintain/monitoring/grafana-dashboards/substrate-service-tasks.json +++ b/.maintain/monitoring/grafana-dashboards/substrate-service-tasks.json @@ -4,7 +4,7 @@ "name": "VAR_METRIC_NAMESPACE", "type": "constant", "label": "Prefix of the metrics", - "value": "polkadot", + "value": "substrate", "description": "" } ], From 7c6342047c992b6f3fa917d0d0448eb7e89afa6c Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 2 Feb 2022 15:25:13 +0100 Subject: [PATCH 0480/1472] bench-cli: Support `JSON` output (#10771) * Add dependencies Signed-off-by: Oliver Tale-Yazdi * Make benchmark results serializable Signed-off-by: Oliver Tale-Yazdi * Add `--json[-file]` options Signed-off-by: Oliver Tale-Yazdi * Enable JSON output Signed-off-by: Oliver Tale-Yazdi * Use specific serde version Polkadot does not compile otherwise. Signed-off-by: Oliver Tale-Yazdi * Review comments Signed-off-by: Oliver Tale-Yazdi * Review comment: fs::write Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 2 + frame/benchmarking/Cargo.toml | 2 + frame/benchmarking/src/utils.rs | 25 +++++++ utils/frame/benchmarking-cli/Cargo.toml | 1 + utils/frame/benchmarking-cli/src/command.rs | 82 +++++++++++---------- utils/frame/benchmarking-cli/src/lib.rs | 18 +++-- 6 files changed, 84 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 963082a7e3af9..af6cb045f7a6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2038,6 +2038,7 @@ dependencies = [ "parity-scale-codec", "paste 1.0.6", "scale-info", + "serde", "sp-api", "sp-application-crypto", "sp-io", @@ -2066,6 +2067,7 @@ dependencies = [ "sc-executor", "sc-service", "serde", + "serde_json", "sp-core", "sp-externalities", "sp-keystore", diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 9afdc79fae655..0283b3f7c9489 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -27,6 +27,7 @@ sp-storage = { version = "5.0.0", path = "../../primitives/storage", default-fea frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } log = { version = "0.4.14", default-features = false } +serde = { version = "1.0.132", optional = true } [dev-dependencies] hex-literal = "0.3.4" @@ -37,6 +38,7 @@ default = ["std"] std = [ "codec/std", "scale-info/std", + "serde", "sp-runtime-interface/std", "sp-runtime/std", "sp-api/std", diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index bb0b8d36a752e..8c642f74358db 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -22,12 +22,15 @@ use frame_support::{ pallet_prelude::*, traits::StorageInfo, }; +#[cfg(feature = "std")] +use serde::Serialize; use sp_io::hashing::blake2_256; use sp_runtime::traits::TrailingZeroInput; use sp_std::{prelude::Box, vec::Vec}; use sp_storage::TrackedStorageKey; /// An alphabet of possible parameters to use for benchmarking. +#[cfg_attr(feature = "std", derive(Serialize))] #[derive(Encode, Decode, Clone, Copy, PartialEq, Debug)] #[allow(missing_docs)] #[allow(non_camel_case_types)] @@ -68,13 +71,17 @@ impl std::fmt::Display for BenchmarkParameter { } /// The results of a single of benchmark. +#[cfg_attr(feature = "std", derive(Serialize))] #[derive(Encode, Decode, Clone, PartialEq, Debug)] pub struct BenchmarkBatch { /// The pallet containing this benchmark. + #[cfg_attr(feature = "std", serde(with = "serde_as_str"))] pub pallet: Vec, /// The instance of this pallet being benchmarked. + #[cfg_attr(feature = "std", serde(with = "serde_as_str"))] pub instance: Vec, /// The extrinsic (or benchmark name) of this benchmark. + #[cfg_attr(feature = "std", serde(with = "serde_as_str"))] pub benchmark: Vec, /// The results from this benchmark. pub results: Vec, @@ -82,13 +89,17 @@ pub struct BenchmarkBatch { // TODO: could probably make API cleaner here. /// The results of a single of benchmark, where time and db results are separated. +#[cfg_attr(feature = "std", derive(Serialize))] #[derive(Encode, Decode, Clone, PartialEq, Debug)] pub struct BenchmarkBatchSplitResults { /// The pallet containing this benchmark. + #[cfg_attr(feature = "std", serde(with = "serde_as_str"))] pub pallet: Vec, /// The instance of this pallet being benchmarked. + #[cfg_attr(feature = "std", serde(with = "serde_as_str"))] pub instance: Vec, /// The extrinsic (or benchmark name) of this benchmark. + #[cfg_attr(feature = "std", serde(with = "serde_as_str"))] pub benchmark: Vec, /// The extrinsic timing results from this benchmark. pub time_results: Vec, @@ -99,6 +110,7 @@ pub struct BenchmarkBatchSplitResults { /// Result from running benchmarks on a FRAME pallet. /// Contains duration of the function call in nanoseconds along with the benchmark parameters /// used for that benchmark result. +#[cfg_attr(feature = "std", derive(Serialize))] #[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] pub struct BenchmarkResult { pub components: Vec<(BenchmarkParameter, u32)>, @@ -109,6 +121,7 @@ pub struct BenchmarkResult { pub writes: u32, pub repeat_writes: u32, pub proof_size: u32, + #[cfg_attr(feature = "std", serde(skip_serializing))] pub keys: Vec<(Vec, u32, u32, bool)>, } @@ -118,6 +131,18 @@ impl BenchmarkResult { } } +/// Helper module to make serde serialize `Vec` as strings. +#[cfg(feature = "std")] +mod serde_as_str { + pub fn serialize(value: &Vec, serializer: S) -> Result + where + S: serde::Serializer, + { + let s = std::str::from_utf8(value).map_err(serde::ser::Error::custom)?; + serializer.collect_str(s) + } +} + /// Possible errors returned from the benchmarking pipeline. #[derive(Clone, PartialEq, Debug)] pub enum BenchmarkError { diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 971fb31a3f8c9..03a625a155dc9 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -28,6 +28,7 @@ codec = { version = "2.0.0", package = "parity-scale-codec" } clap = { version = "3.0", features = ["derive"] } chrono = "0.4" serde = "1.0.132" +serde_json = "1.0.74" handlebars = "4.1.6" Inflector = "0.11.4" linked-hash-map = "0.5.4" diff --git a/utils/frame/benchmarking-cli/src/command.rs b/utils/frame/benchmarking-cli/src/command.rs index a5046dbaad2ac..a5b53bcf99c76 100644 --- a/utils/frame/benchmarking-cli/src/command.rs +++ b/utils/frame/benchmarking-cli/src/command.rs @@ -35,7 +35,7 @@ use sp_externalities::Extensions; use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStorePtr}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_state_machine::StateMachine; -use std::{fmt::Debug, sync::Arc, time}; +use std::{fmt::Debug, fs, sync::Arc, time}; // This takes multiple benchmark batches and combines all the results where the pallet, instance, // and benchmark are the same. @@ -357,55 +357,61 @@ impl BenchmarkCmd { // are together. let batches: Vec = combine_batches(batches, batches_db); + // Create the weights.rs file. if let Some(output_path) = &self.output { crate::writer::write_results(&batches, &storage_info, output_path, self)?; } + // Jsonify the result and write it to a file or stdout if desired. + if !self.jsonify(&batches)? { + // Print the summary only if `jsonify` did not write to stdout. + self.print_summary(&batches, &storage_info) + } + Ok(()) + } + + /// Jsonifies the passed batches and writes them to stdout or into a file. + /// Can be configured via `--json` and `--json-file`. + /// Returns whether it wrote to stdout. + fn jsonify(&self, batches: &Vec) -> Result { + if self.json_output || self.json_file.is_some() { + let json = serde_json::to_string_pretty(&batches) + .map_err(|e| format!("Serializing into JSON: {:?}", e))?; + + if let Some(path) = &self.json_file { + fs::write(path, json)?; + } else { + println!("{}", json); + return Ok(true) + } + } + + Ok(false) + } + + /// Prints the results as human-readable summary without raw timing data. + fn print_summary( + &self, + batches: &Vec, + storage_info: &Vec, + ) { for batch in batches.into_iter() { // Print benchmark metadata println!( - "Pallet: {:?}, Extrinsic: {:?}, Lowest values: {:?}, Highest values: {:?}, Steps: {:?}, Repeat: {:?}", - String::from_utf8(batch.pallet).expect("Encoded from String; qed"), - String::from_utf8(batch.benchmark).expect("Encoded from String; qed"), - self.lowest_range_values, - self.highest_range_values, - self.steps, - self.repeat, - ); + "Pallet: {:?}, Extrinsic: {:?}, Lowest values: {:?}, Highest values: {:?}, Steps: {:?}, Repeat: {:?}", + String::from_utf8(batch.pallet.clone()).expect("Encoded from String; qed"), + String::from_utf8(batch.benchmark.clone()).expect("Encoded from String; qed"), + self.lowest_range_values, + self.highest_range_values, + self.steps, + self.repeat, + ); // Skip raw data + analysis if there are no results if batch.time_results.is_empty() { continue } - if self.raw_data { - // Print the table header - batch.time_results[0] - .components - .iter() - .for_each(|param| print!("{:?},", param.0)); - - print!("extrinsic_time_ns,storage_root_time_ns,reads,repeat_reads,writes,repeat_writes,proof_size_bytes\n"); - // Print the values - batch.time_results.iter().for_each(|result| { - let parameters = &result.components; - parameters.iter().for_each(|param| print!("{:?},", param.1)); - // Print extrinsic time and storage root time - print!( - "{:?},{:?},{:?},{:?},{:?},{:?},{:?}\n", - result.extrinsic_time, - result.storage_root_time, - result.reads, - result.repeat_reads, - result.writes, - result.repeat_writes, - result.proof_size, - ); - }); - - println!(); - } - if !self.no_storage_info { let mut comments: Vec = Default::default(); crate::writer::add_storage_comments( @@ -460,8 +466,6 @@ impl BenchmarkCmd { println!(""); } } - - Ok(()) } } diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 6afaa2b249fcf..3b0f4843d2065 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -19,7 +19,7 @@ mod command; mod writer; use sc_cli::{ExecutionStrategy, WasmExecutionMethod}; -use std::fmt::Debug; +use std::{fmt::Debug, path::PathBuf}; // Add a more relaxed parsing for pallet names by allowing pallet directory names with `-` to be // used like crate names with `_` @@ -60,9 +60,13 @@ pub struct BenchmarkCmd { #[clap(long, default_value = "1")] pub external_repeat: u32, - /// Print the raw results. - #[clap(long = "raw")] - pub raw_data: bool, + /// Print the raw results in JSON format. + #[clap(long = "json")] + pub json_output: bool, + + /// Write the raw results in JSON format into the give file. + #[clap(long, conflicts_with = "json-output")] + pub json_file: Option, /// Don't print the median-slopes linear regression analysis. #[clap(long)] @@ -74,15 +78,15 @@ pub struct BenchmarkCmd { /// Output the benchmarks to a Rust file at the given path. #[clap(long)] - pub output: Option, + pub output: Option, /// Add a header file to your outputted benchmarks #[clap(long)] - pub header: Option, + pub header: Option, /// Path to Handlebars template file used for outputting benchmark results. (Optional) #[clap(long)] - pub template: Option, + pub template: Option, /// Which analysis function to use when outputting benchmarks: /// * min-squares (default) From d161d54353b64c24fdc458913471f40c2683af32 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 3 Feb 2022 14:02:45 +0100 Subject: [PATCH 0481/1472] Introduce ModuleError struct (#10776) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * better partial eq impl * introduce module error * fmt * import module error * Apply suggestions from code review Co-authored-by: Bastian Köcher * fixes * fmt Co-authored-by: Bastian Köcher --- .../election-provider-multi-phase/src/lib.rs | 4 +- .../src/unsigned.rs | 10 +-- frame/elections-phragmen/src/lib.rs | 6 +- .../procedural/src/pallet/expand/error.rs | 4 +- frame/support/src/error.rs | 4 +- frame/support/test/tests/construct_runtime.rs | 24 ++--- frame/support/test/tests/pallet.rs | 8 +- frame/support/test/tests/pallet_instance.rs | 14 ++- primitives/runtime/src/lib.rs | 87 +++++++++---------- 9 files changed, 84 insertions(+), 77 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 0a620e6c12827..a5ed593e1a4ee 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -255,7 +255,7 @@ use sp_runtime::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, }, - DispatchError, PerThing, Perbill, RuntimeDebug, SaturatedConversion, + DispatchError, ModuleError, PerThing, Perbill, RuntimeDebug, SaturatedConversion, }; use sp_std::prelude::*; @@ -1579,7 +1579,7 @@ impl ElectionProvider for Pallet { /// number. pub fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { let error_number = match error { - DispatchError::Module { error, .. } => error, + DispatchError::Module(ModuleError { error, .. }) => error, _ => 0, }; InvalidTransaction::Custom(error_number) diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 936993b41fb6c..196147f8a4706 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -752,7 +752,7 @@ mod tests { use sp_runtime::{ offchain::storage_lock::{BlockAndTime, StorageLock}, traits::ValidateUnsigned, - PerU16, + ModuleError, PerU16, }; type Assignment = crate::unsigned::Assignment; @@ -922,8 +922,8 @@ mod tests { #[test] #[should_panic(expected = "Invalid unsigned submission must produce invalid block and \ deprive validator from their authoring reward.: \ - Module { index: 2, error: 1, message: \ - Some(\"PreDispatchWrongWinnerCount\") }")] + Module(ModuleError { index: 2, error: 1, message: \ + Some(\"PreDispatchWrongWinnerCount\") })")] fn unfeasible_solution_panics() { ExtBuilder::default().build_and_execute(|| { roll_to(25); @@ -1033,11 +1033,11 @@ mod tests { assert_eq!( MultiPhase::mine_check_save_submit().unwrap_err(), - MinerError::PreDispatchChecksFailed(DispatchError::Module { + MinerError::PreDispatchChecksFailed(DispatchError::Module(ModuleError { index: 2, error: 1, message: Some("PreDispatchWrongWinnerCount"), - }), + })), ); }) } diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index bc6a81125e8bd..4758c793cfefd 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1132,7 +1132,7 @@ mod tests { use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, + BuildStorage, ModuleError, }; use substrate_test_utils::assert_eq_uvec; @@ -2514,7 +2514,7 @@ mod tests { let unwrapped_error = Elections::remove_member(Origin::root(), 4, true).unwrap_err(); assert!(matches!( unwrapped_error.error, - DispatchError::Module { message: Some("InvalidReplacement"), .. } + DispatchError::Module(ModuleError { message: Some("InvalidReplacement"), .. }) )); assert!(unwrapped_error.post_info.actual_weight.is_some()); }); @@ -2537,7 +2537,7 @@ mod tests { let unwrapped_error = Elections::remove_member(Origin::root(), 4, false).unwrap_err(); assert!(matches!( unwrapped_error.error, - DispatchError::Module { message: Some("InvalidReplacement"), .. } + DispatchError::Module(ModuleError { message: Some("InvalidReplacement"), .. }) )); assert!(unwrapped_error.post_info.actual_weight.is_some()); }); diff --git a/frame/support/procedural/src/pallet/expand/error.rs b/frame/support/procedural/src/pallet/expand/error.rs index 4cf572c1797f2..9e2b801083e46 100644 --- a/frame/support/procedural/src/pallet/expand/error.rs +++ b/frame/support/procedural/src/pallet/expand/error.rs @@ -124,11 +124,11 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { >::index::>() .expect("Every active module has an index in the runtime; qed") as u8; - #frame_support::sp_runtime::DispatchError::Module { + #frame_support::sp_runtime::DispatchError::Module(#frame_support::sp_runtime::ModuleError { index, error: err.as_u8(), message: Some(err.as_str()), - } + }) } } ) diff --git a/frame/support/src/error.rs b/frame/support/src/error.rs index abac4a53269a6..4880bba5c5e97 100644 --- a/frame/support/src/error.rs +++ b/frame/support/src/error.rs @@ -153,11 +153,11 @@ macro_rules! decl_error { ::index::<$module<$generic $(, $inst_generic)?>>() .expect("Every active module has an index in the runtime; qed") as u8; - $crate::sp_runtime::DispatchError::Module { + $crate::sp_runtime::DispatchError::Module($crate::sp_runtime::ModuleError { index, error: err.as_u8(), message: Some(err.as_str()), - } + }) } } }; diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 267d560edf92d..b3f8feb8aa4b2 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -27,7 +27,7 @@ use sp_core::{sr25519, H256}; use sp_runtime::{ generic, traits::{BlakeTwo256, Verify}, - DispatchError, + DispatchError, ModuleError, }; use sp_std::cell::RefCell; @@ -363,47 +363,47 @@ mod origin_test { fn check_modules_error_type() { assert_eq!( Module1_1::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 31, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 31, error: 0, message: Some("Something") })), ); assert_eq!( Module2::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 32, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 32, error: 0, message: Some("Something") })), ); assert_eq!( Module1_2::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 33, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 33, error: 0, message: Some("Something") })), ); assert_eq!( NestedModule3::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 34, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 34, error: 0, message: Some("Something") })), ); assert_eq!( Module1_3::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 6, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 6, error: 0, message: Some("Something") })), ); assert_eq!( Module1_4::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 3, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 3, error: 0, message: Some("Something") })), ); assert_eq!( Module1_5::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 4, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 4, error: 0, message: Some("Something") })), ); assert_eq!( Module1_6::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 1, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 1, error: 0, message: Some("Something") })), ); assert_eq!( Module1_7::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 2, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 2, error: 0, message: Some("Something") })), ); assert_eq!( Module1_8::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 12, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 12, error: 0, message: Some("Something") })), ); assert_eq!( Module1_9::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 13, error: 0, message: Some("Something") }), + Err(DispatchError::Module(ModuleError { index: 13, error: 0, message: Some("Something") })), ); } diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index cf882556088ef..451cb2e7b889e 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -29,7 +29,7 @@ use sp_io::{ hashing::{blake2_128, twox_128, twox_64}, TestExternalities, }; -use sp_runtime::DispatchError; +use sp_runtime::{DispatchError, ModuleError}; pub struct SomeType1; impl From for u64 { @@ -654,7 +654,11 @@ fn error_expand() { ); assert_eq!( DispatchError::from(pallet::Error::::InsufficientProposersBalance), - DispatchError::Module { index: 1, error: 0, message: Some("InsufficientProposersBalance") }, + DispatchError::Module(ModuleError { + index: 1, + error: 0, + message: Some("InsufficientProposersBalance") + }), ); } diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 4a8636919b583..30b9bcda88d1e 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -25,7 +25,7 @@ use sp_io::{ hashing::{blake2_128, twox_128, twox_64}, TestExternalities, }; -use sp_runtime::DispatchError; +use sp_runtime::{DispatchError, ModuleError}; #[frame_support::pallet] pub mod pallet { @@ -341,7 +341,11 @@ fn error_expand() { ); assert_eq!( DispatchError::from(pallet::Error::::InsufficientProposersBalance), - DispatchError::Module { index: 1, error: 0, message: Some("InsufficientProposersBalance") }, + DispatchError::Module(ModuleError { + index: 1, + error: 0, + message: Some("InsufficientProposersBalance") + }), ); assert_eq!( @@ -358,7 +362,11 @@ fn error_expand() { DispatchError::from( pallet::Error::::InsufficientProposersBalance ), - DispatchError::Module { index: 2, error: 0, message: Some("InsufficientProposersBalance") }, + DispatchError::Module(ModuleError { + index: 2, + error: 0, + message: Some("InsufficientProposersBalance") + }), ); } diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 84817a6be5d71..6d32d2322c765 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -461,9 +461,29 @@ pub type DispatchResult = sp_std::result::Result<(), DispatchError>; /// about the `Dispatchable` that is only known post dispatch. pub type DispatchResultWithInfo = sp_std::result::Result>; -/// Reason why a dispatch call failed. +/// Reason why a pallet call failed. #[derive(Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct ModuleError { + /// Module index, matching the metadata module index. + pub index: u8, + /// Module specific error value. + pub error: u8, + /// Optional error message. + #[codec(skip)] + #[cfg_attr(feature = "std", serde(skip_deserializing))] + pub message: Option<&'static str>, +} + +impl PartialEq for ModuleError { + fn eq(&self, other: &Self) -> bool { + (self.index == other.index) && (self.error == other.error) + } +} + +/// Reason why a dispatch call failed. +#[derive(Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo, PartialEq)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum DispatchError { /// Some error occurred. Other( @@ -476,16 +496,7 @@ pub enum DispatchError { /// A bad origin. BadOrigin, /// A custom error in a module. - Module { - /// Module index, matching the metadata module index. - index: u8, - /// Module specific error value. - error: u8, - /// Optional error message. - #[codec(skip)] - #[cfg_attr(feature = "std", serde(skip_deserializing))] - message: Option<&'static str>, - }, + Module(ModuleError), /// At least one consumer is remaining so the account cannot be destroyed. ConsumerRemaining, /// There are no providers so the account cannot be created. @@ -515,8 +526,8 @@ impl DispatchError { /// Return the same error but without the attached message. pub fn stripped(self) -> Self { match self { - DispatchError::Module { index, error, message: Some(_) } => - DispatchError::Module { index, error, message: None }, + DispatchError::Module(ModuleError { index, error, message: Some(_) }) => + DispatchError::Module(ModuleError { index, error, message: None }), m => m, } } @@ -624,7 +635,8 @@ impl From for &'static str { DispatchError::Other(msg) => msg, DispatchError::CannotLookup => "Cannot lookup", DispatchError::BadOrigin => "Bad origin", - DispatchError::Module { message, .. } => message.unwrap_or("Unknown module error"), + DispatchError::Module(ModuleError { message, .. }) => + message.unwrap_or("Unknown module error"), DispatchError::ConsumerRemaining => "Consumer remaining", DispatchError::NoProviders => "No providers", DispatchError::TooManyConsumers => "Too many consumers", @@ -650,7 +662,7 @@ impl traits::Printable for DispatchError { Self::Other(err) => err.print(), Self::CannotLookup => "Cannot lookup".print(), Self::BadOrigin => "Bad origin".print(), - Self::Module { index, error, message } => { + Self::Module(ModuleError { index, error, message }) => { index.print(); error.print(); if let Some(msg) = message { @@ -683,30 +695,6 @@ where } } -impl PartialEq for DispatchError { - fn eq(&self, other: &Self) -> bool { - use DispatchError::*; - - match (self, other) { - (CannotLookup, CannotLookup) | - (BadOrigin, BadOrigin) | - (ConsumerRemaining, ConsumerRemaining) | - (NoProviders, NoProviders) => true, - - (Token(l), Token(r)) => l == r, - (Other(l), Other(r)) => l == r, - (Arithmetic(l), Arithmetic(r)) => l == r, - - ( - Module { index: index_l, error: error_l, .. }, - Module { index: index_r, error: error_r, .. }, - ) => (index_l == index_r) && (error_l == error_r), - - _ => false, - } - } -} - /// This type specifies the outcome of dispatching a call to a module. /// /// In case of failure an error specific to the module is returned. @@ -932,11 +920,18 @@ mod tests { #[test] fn dispatch_error_encoding() { - let error = DispatchError::Module { index: 1, error: 2, message: Some("error message") }; + let error = DispatchError::Module(ModuleError { + index: 1, + error: 2, + message: Some("error message"), + }); let encoded = error.encode(); let decoded = DispatchError::decode(&mut &encoded[..]).unwrap(); assert_eq!(encoded, vec![3, 1, 2]); - assert_eq!(decoded, DispatchError::Module { index: 1, error: 2, message: None }); + assert_eq!( + decoded, + DispatchError::Module(ModuleError { index: 1, error: 2, message: None }) + ); } #[test] @@ -948,9 +943,9 @@ mod tests { Other("bar"), CannotLookup, BadOrigin, - Module { index: 1, error: 1, message: None }, - Module { index: 1, error: 2, message: None }, - Module { index: 2, error: 1, message: None }, + Module(ModuleError { index: 1, error: 1, message: None }), + Module(ModuleError { index: 1, error: 2, message: None }), + Module(ModuleError { index: 2, error: 1, message: None }), ConsumerRemaining, NoProviders, Token(TokenError::NoFunds), @@ -975,8 +970,8 @@ mod tests { // Ignores `message` field in `Module` variant. assert_eq!( - Module { index: 1, error: 1, message: Some("foo") }, - Module { index: 1, error: 1, message: None }, + Module(ModuleError { index: 1, error: 1, message: Some("foo") }), + Module(ModuleError { index: 1, error: 1, message: None }), ); } From 59649dd117969467d8046df86afe56810f596545 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 3 Feb 2022 16:58:16 +0000 Subject: [PATCH 0482/1472] Bump sp-keyring (#10790) --- Cargo.lock | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- primitives/keyring/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af6cb045f7a6e..2e254e7d11843 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9738,7 +9738,7 @@ dependencies = [ [[package]] name = "sp-keyring" -version = "4.1.0-dev" +version = "5.0.0" dependencies = [ "lazy_static", "sp-core", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index db198592b37bc..211311c3dac2f 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -52,7 +52,7 @@ sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } +sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../../primitives/transaction-pool" } diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 39cf1ee8d8934..531fffe35529f 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -38,7 +38,7 @@ sp-application-crypto = { version = "5.0.0", path = "../../../primitives/applica sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-externalities = { version = "0.11.0", path = "../../../primitives/externalities" } -sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } +sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } wat = "1.0" futures = "0.3.9" diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 84eec7662361f..647562caff30c 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -35,7 +35,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../../primiti sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } -sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../../primitives/keyring" } +sp-keyring = { version = "5.0.0", optional = true, path = "../../../primitives/keyring" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 55ae52b50d9d1..3275aac0ef1de 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -24,7 +24,7 @@ sc-client-db = { version = "0.10.0-dev", path = "../../../client/db/", features sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } codec = { package = "parity-scale-codec", version = "2.0.0" } -sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } +sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index ca7e0ac768f91..f7af649d3bf3a 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -40,7 +40,7 @@ sc-tracing = { version = "4.0.0-dev", path = "../tracing" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } +sp-keyring = { version = "5.0.0", path = "../../primitives/keyring" } sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 4fb621d716a8e..156842c35842e 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -41,7 +41,7 @@ getrandom = { version = "0.2", features = ["js"], optional = true } [dev-dependencies] sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } +sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } sc-network = { version = "0.10.0-dev", path = "../../network" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 87ef265ffd9b2..56276f07dcdef 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -34,7 +34,7 @@ sp-keystore = { version = "0.11.0", path = "../../../../primitives/keystore" } [dev-dependencies] sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } serde_json = "1.0.74" -sp-keyring = { version = "4.1.0-dev", path = "../../../../primitives/keyring" } +sp-keyring = { version = "5.0.0", path = "../../../../primitives/keyring" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } tempfile = "3.1.0" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index e6b0b6396681e..6d4c3b13662dc 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -54,7 +54,7 @@ finality-grandpa = { version = "0.14.1", features = [ ] } sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-test = { version = "0.8.0", path = "../network/test" } -sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } +sp-keyring = { version = "5.0.0", path = "../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } tokio = "1.15" diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 2845621cadd6f..b544287a6002c 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -34,5 +34,5 @@ sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ ] } sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } -sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } +sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 002ceed369299..eda9d630d4f99 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -33,7 +33,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } grandpa = { package = "finality-grandpa", version = "0.14.1", features = ["derive-codec"] } -sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } +sp-keyring = { version = "5.0.0", path = "../../primitives/keyring" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index 487eb47164228..28a6427f520b8 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../primitives/keyring" } +sp-keyring = { version = "5.0.0", optional = true, path = "../../primitives/keyring" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 2f8e935b2457f..5cf8a574505aa 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-keyring" -version = "4.1.0-dev" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 5f687b24896d2..640623aba6aaf 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -31,7 +31,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } -sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } +sp-keyring = { version = "5.0.0", path = "../../primitives/keyring" } sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } async-trait = "0.1.50" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index f1b06d3b3ec2b..2a9fcaf324264 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -20,7 +20,7 @@ sp-block-builder = { version = "4.0.0-dev", default-features = false, path = ".. codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } -sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../primitives/keyring" } +sp-keyring = { version = "5.0.0", optional = true, path = "../../primitives/keyring" } memory-db = { version = "0.27.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } From 4f672d4efc70d001cc2ee619a5a93fe643c8aa98 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 4 Feb 2022 13:03:28 +0100 Subject: [PATCH 0483/1472] Make `offences` benchmark runnable (#10782) * Make offences benchmark runnable Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_offences --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/offences/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Revert bench-bot This reverts commit 73d0cb2e47e93e035af80013991b6a2e5fe2b1ed. Co-authored-by: Parity Bot --- frame/offences/benchmarking/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index c2e29f0d0fdd3..8688090206c36 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -405,6 +405,7 @@ benchmarks! { } verify { // make sure that all slashes have been applied + #[cfg(test)] assert_eq!( System::::event_count(), 0 + 1 // offence @@ -440,6 +441,7 @@ benchmarks! { } verify { // make sure that all slashes have been applied + #[cfg(test)] assert_eq!( System::::event_count(), 0 + 1 // offence From 929cf109ba692d69f60439147d1e8af14942c64b Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 4 Feb 2022 07:42:13 -0800 Subject: [PATCH 0484/1472] Make some UI test expectations crisper (#10791) * Make some UI test expectations crisper * Update frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs * Update UI test expectations * Missing newlines * More whitespace issues --- .../no_std_genesis_config.rs | 31 +++- .../no_std_genesis_config.stderr | 104 +++++-------- .../undefined_call_part.rs | 31 +++- .../undefined_call_part.stderr | 74 +-------- .../undefined_event_part.rs | 31 +++- .../undefined_event_part.stderr | 102 +++---------- .../undefined_genesis_config_part.rs | 31 +++- .../undefined_genesis_config_part.stderr | 106 +++++-------- .../undefined_inherent_part.rs | 31 +++- .../undefined_inherent_part.stderr | 140 +++++++++++------- .../undefined_origin_part.rs | 31 +++- .../undefined_origin_part.stderr | 106 ++++--------- .../undefined_validate_unsigned_part.rs | 31 +++- .../undefined_validate_unsigned_part.stderr | 105 ++++++------- 14 files changed, 465 insertions(+), 489 deletions(-) diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs index 89774eb8a7702..c06333795e3c5 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs @@ -3,20 +3,47 @@ use sp_runtime::{generic, traits::BlakeTwo256}; use sp_core::sr25519; pub type Signature = sr25519::Signature; -pub type BlockNumber = u64; +pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl test_pallet::Config for Runtime {} +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u32; + type Call = Call; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = frame_support::traits::ConstU32<250>; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + construct_runtime! { pub enum Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{Pallet, Call, Storage, Config, Event}, + System: frame_system::{Pallet, Call, Storage, Config, Event}, Pallet: test_pallet::{Pallet, Config}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr index e458265a07cab..6d5a48bf0909a 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr @@ -1,73 +1,27 @@ error: `Pallet` does not have the std feature enabled, this will cause the `test_pallet::GenesisConfig` type to be undefined. - --> $DIR/no_std_genesis_config.rs:13:1 + --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 | -13 | / construct_runtime! { -14 | | pub enum Runtime where -15 | | Block = Block, -16 | | NodeBlock = Block, +40 | / construct_runtime! { +41 | | pub enum Runtime where +42 | | Block = Block, +43 | | NodeBlock = Block, ... | -21 | | } -22 | | } +48 | | } +49 | | } | |_^ | = note: this error originates in the macro `test_pallet::__substrate_genesis_config_check::is_std_enabled_for_genesis` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/no_std_genesis_config.rs:19:11 - | -19 | System: system::{Pallet, Call, Storage, Config, Event}, - | ^^^^^^ use of undeclared crate or module `system` - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/no_std_genesis_config.rs:13:1 - | -13 | / construct_runtime! { -14 | | pub enum Runtime where -15 | | Block = Block, -16 | | NodeBlock = Block, -... | -21 | | } -22 | | } - | |_^ not found in `system` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this enum - | -1 | use frame_system::RawOrigin; - | - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/no_std_genesis_config.rs:13:1 - | -13 | / construct_runtime! { -14 | | pub enum Runtime where -15 | | Block = Block, -16 | | NodeBlock = Block, -... | -21 | | } -22 | | } - | |_^ not found in `system` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use frame_support_test::Pallet; - | -1 | use frame_system::Pallet; - | -1 | use test_pallet::Pallet; - | - error[E0412]: cannot find type `GenesisConfig` in crate `test_pallet` - --> $DIR/no_std_genesis_config.rs:13:1 + --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 | -13 | / construct_runtime! { -14 | | pub enum Runtime where -15 | | Block = Block, -16 | | NodeBlock = Block, +40 | / construct_runtime! { +41 | | pub enum Runtime where +42 | | Block = Block, +43 | | NodeBlock = Block, ... | -21 | | } -22 | | } +48 | | } +49 | | } | |_^ not found in `test_pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -76,14 +30,22 @@ help: consider importing this struct 1 | use frame_system::GenesisConfig; | -error[E0277]: the trait bound `Runtime: frame_system::pallet::Config` is not satisfied - --> $DIR/no_std_genesis_config.rs:11:6 - | -11 | impl test_pallet::Config for Runtime {} - | ^^^^^^^^^^^^^^^^^^^ the trait `frame_system::pallet::Config` is not implemented for `Runtime` - | -note: required by a bound in `Config` - --> $DIR/lib.rs:30:20 - | -30 | pub trait Config: frame_system::Config {} - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Config` +error[E0283]: type annotations needed + --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 + | +40 | / construct_runtime! { +41 | | pub enum Runtime where +42 | | Block = Block, +43 | | NodeBlock = Block, +... | +48 | | } +49 | | } + | |_^ cannot infer type + | + = note: cannot satisfy `_: std::default::Default` +note: required by `std::default::Default::default` + --> $RUST/core/src/default.rs + | + | fn default() -> Self; + | ^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs index c5b9fcca1f318..1653e830f0b4f 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs @@ -12,20 +12,47 @@ mod pallet { } pub type Signature = sr25519::Signature; -pub type BlockNumber = u64; +pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u32; + type Call = Call; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = frame_support::traits::ConstU32<250>; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + construct_runtime! { pub enum Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{Pallet, Call, Storage, Config, Event}, + System: frame_system::{Pallet, Call, Storage, Config, Event}, Pallet: pallet::{Pallet, Call}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr index c4e567102a892..c162a22bb87b0 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr @@ -1,76 +1,16 @@ error: `Pallet` does not have #[pallet::call] defined, perhaps you should remove `Call` from construct_runtime? - --> $DIR/undefined_call_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_call_part.rs:5:1 | 5 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_call_check::is_call_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_call_part.rs:28:11 - | -28 | System: system::{Pallet, Call, Storage, Config, Event}, - | ^^^^^^ use of undeclared crate or module `system` - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_call_part.rs:22:1 - | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, -... | -30 | | } -31 | | } - | |_^ not found in `system` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this enum - | -1 | use frame_system::RawOrigin; - | - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_call_part.rs:22:1 - | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, -... | -30 | | } -31 | | } - | |_^ not found in `system` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use crate::pallet::Pallet; - | -1 | use frame_support_test::Pallet; - | -1 | use frame_system::Pallet; - | -1 | use test_pallet::Pallet; - | - -error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied - --> $DIR/undefined_call_part.rs:20:6 - | -20 | impl pallet::Config for Runtime {} - | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` - | -note: required by a bound in `pallet::Config` - --> $DIR/undefined_call_part.rs:8:20 - | -8 | pub trait Config: frame_system::Config {} - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs index 6aec45f240c90..b8f91cf4bc690 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs @@ -12,20 +12,47 @@ mod pallet { } pub type Signature = sr25519::Signature; -pub type BlockNumber = u64; +pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u32; + type Call = Call; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = frame_support::traits::ConstU32<250>; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + construct_runtime! { pub enum Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{Pallet, Call, Storage, Config, Event}, + System: frame_system::{Pallet, Call, Storage, Config, Event}, Pallet: pallet::{Pallet, Event}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index da972f6f4b2f4..31229f8c93cb6 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -1,36 +1,30 @@ error: `Pallet` does not have #[pallet::event] defined, perhaps you should remove `Event` from construct_runtime? - --> $DIR/undefined_event_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_event_part.rs:5:1 | 5 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_event_check::is_event_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_event_part.rs:28:11 - | -28 | System: system::{Pallet, Call, Storage, Config, Event}, - | ^^^^^^ use of undeclared crate or module `system` - error[E0412]: cannot find type `Event` in module `pallet` - --> $DIR/undefined_event_part.rs:22:1 + --> tests/construct_runtime_ui/undefined_event_part.rs:49:1 | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -40,15 +34,15 @@ help: consider importing this enum | error[E0412]: cannot find type `Event` in module `pallet` - --> $DIR/undefined_event_part.rs:22:1 + --> tests/construct_runtime_ui/undefined_event_part.rs:49:1 | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -58,57 +52,3 @@ help: consider importing one of these items | 1 | use frame_system::Event; | - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_event_part.rs:22:1 - | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, -... | -30 | | } -31 | | } - | |_^ not found in `system` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this enum - | -1 | use frame_system::RawOrigin; - | - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_event_part.rs:22:1 - | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, -... | -30 | | } -31 | | } - | |_^ not found in `system` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use crate::pallet::Pallet; - | -1 | use frame_support_test::Pallet; - | -1 | use frame_system::Pallet; - | -1 | use test_pallet::Pallet; - | - -error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied - --> $DIR/undefined_event_part.rs:20:6 - | -20 | impl pallet::Config for Runtime {} - | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` - | -note: required by a bound in `pallet::Config` - --> $DIR/undefined_event_part.rs:8:20 - | -8 | pub trait Config: frame_system::Config {} - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs index 5e08fd96fa1ad..a61d545b3279e 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs @@ -12,20 +12,47 @@ mod pallet { } pub type Signature = sr25519::Signature; -pub type BlockNumber = u64; +pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u32; + type Call = Call; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = frame_support::traits::ConstU32<250>; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + construct_runtime! { pub enum Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{Pallet, Call, Storage, Config, Event}, + System: frame_system::{Pallet, Call, Storage, Config, Event}, Pallet: pallet::{Pallet, Config}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr index 8e40773b65736..e8532aa9a064f 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr @@ -1,78 +1,30 @@ error: `Pallet` does not have #[pallet::genesis_config] defined, perhaps you should remove `Config` from construct_runtime? - --> $DIR/undefined_genesis_config_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:5:1 | 5 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_genesis_config_check::is_genesis_config_defined` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_genesis_config_part.rs:28:17 - | -28 | System: system::{Pallet, Call, Storage, Config, Event}, - | ^^^^^^ use of undeclared crate or module `system` - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_genesis_config_part.rs:22:1 - | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, -... | -30 | | } -31 | | } - | |_^ not found in `system` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this enum - | -1 | use frame_system::RawOrigin; - | - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_genesis_config_part.rs:22:1 - | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, -... | -30 | | } -31 | | } - | |_^ not found in `system` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use crate::pallet::Pallet; - | -1 | use frame_support_test::Pallet; - | -1 | use frame_system::Pallet; - | -1 | use test_pallet::Pallet; - | - error[E0412]: cannot find type `GenesisConfig` in module `pallet` - --> $DIR/undefined_genesis_config_part.rs:22:1 + --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -81,14 +33,22 @@ help: consider importing this struct 1 | use frame_system::GenesisConfig; | -error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied - --> $DIR/undefined_genesis_config_part.rs:20:6 - | -20 | impl pallet::Config for Runtime {} - | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` - | -note: required by a bound in `pallet::Config` - --> $DIR/undefined_genesis_config_part.rs:8:20 - | -8 | pub trait Config: frame_system::Config {} - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` +error[E0283]: type annotations needed + --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 + | +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, +... | +57 | | } +58 | | } + | |_^ cannot infer type + | + = note: cannot satisfy `_: std::default::Default` +note: required by `std::default::Default::default` + --> $RUST/core/src/default.rs + | + | fn default() -> Self; + | ^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs index 06c36a30f5506..6e4764286ab41 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs @@ -12,20 +12,47 @@ mod pallet { } pub type Signature = sr25519::Signature; -pub type BlockNumber = u64; +pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u32; + type Call = Call; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = frame_support::traits::ConstU32<250>; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + construct_runtime! { pub enum Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{Pallet, Call, Storage, Config, Event}, + System: frame_system::{Pallet, Call, Storage, Config, Event}, Pallet: pallet::{Pallet, Inherent}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr index ae461473c3b11..9f646469d86a8 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr @@ -1,76 +1,116 @@ error: `Pallet` does not have #[pallet::inherent] defined, perhaps you should remove `Inherent` from construct_runtime? - --> $DIR/undefined_inherent_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_inherent_part.rs:5:1 | 5 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_inherent_check::is_inherent_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_inherent_part.rs:28:11 +error[E0599]: no function or associated item named `create_inherent` found for struct `pallet::Pallet` in the current scope + --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | -28 | System: system::{Pallet, Call, Storage, Config, Event}, - | ^^^^^^ use of undeclared crate or module `system` - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_inherent_part.rs:22:1 - | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +11 | pub struct Pallet(_); + | ------------------------ function or associated item `create_inherent` not found for this +... +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } - | |_^ not found in `system` +57 | | } +58 | | } + | |_^ function or associated item not found in `pallet::Pallet` | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `create_inherent`, perhaps you need to implement it: + candidate #1: `ProvideInherent` = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this enum - | -1 | use frame_system::RawOrigin; - | -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_inherent_part.rs:22:1 +error[E0599]: no function or associated item named `is_inherent` found for struct `pallet::Pallet` in the current scope + --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +11 | pub struct Pallet(_); + | ------------------------ function or associated item `is_inherent` not found for this +... +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } - | |_^ not found in `system` +57 | | } +58 | | } + | |_^ function or associated item not found in `pallet::Pallet` | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `is_inherent`, perhaps you need to implement it: + candidate #1: `ProvideInherent` = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use crate::pallet::Pallet; + +error[E0599]: no function or associated item named `check_inherent` found for struct `pallet::Pallet` in the current scope + --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | -1 | use frame_support_test::Pallet; +11 | pub struct Pallet(_); + | ------------------------ function or associated item `check_inherent` not found for this +... +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, +... | +57 | | } +58 | | } + | |_^ function or associated item not found in `pallet::Pallet` | -1 | use frame_system::Pallet; + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `check_inherent`, perhaps you need to implement it: + candidate #1: `ProvideInherent` + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: no associated item named `INHERENT_IDENTIFIER` found for struct `pallet::Pallet` in the current scope + --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | -1 | use test_pallet::Pallet; +11 | pub struct Pallet(_); + | ------------------------ associated item `INHERENT_IDENTIFIER` not found for this +... +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, +... | +57 | | } +58 | | } + | |_^ associated item not found in `pallet::Pallet` | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `INHERENT_IDENTIFIER`, perhaps you need to implement it: + candidate #1: `ProvideInherent` + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied - --> $DIR/undefined_inherent_part.rs:20:6 +error[E0599]: no function or associated item named `is_inherent_required` found for struct `pallet::Pallet` in the current scope + --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | -20 | impl pallet::Config for Runtime {} - | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` - | -note: required by a bound in `pallet::Config` - --> $DIR/undefined_inherent_part.rs:8:20 +11 | pub struct Pallet(_); + | ------------------------ function or associated item `is_inherent_required` not found for this +... +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, +... | +57 | | } +58 | | } + | |_^ function or associated item not found in `pallet::Pallet` | -8 | pub trait Config: frame_system::Config {} - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `is_inherent_required`, perhaps you need to implement it: + candidate #1: `ProvideInherent` + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs index bec5c27ec0346..9233404a865b9 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs @@ -12,20 +12,47 @@ mod pallet { } pub type Signature = sr25519::Signature; -pub type BlockNumber = u64; +pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u32; + type Call = Call; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = frame_support::traits::ConstU32<250>; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + construct_runtime! { pub enum Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{Pallet, Call, Storage, Config, Event}, + System: frame_system::{Pallet, Call, Storage, Config, Event}, Pallet: pallet::{Pallet, Origin}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr index dbdd9f869a2e3..06e845618d44f 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr @@ -1,54 +1,30 @@ error: `Pallet` does not have #[pallet::origin] defined, perhaps you should remove `Origin` from construct_runtime? - --> $DIR/undefined_origin_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_origin_part.rs:5:1 | 5 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_origin_check::is_origin_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_origin_part.rs:28:11 - | -28 | System: system::{Pallet, Call, Storage, Config, Event}, - | ^^^^^^ use of undeclared crate or module `system` - -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_origin_part.rs:22:1 - | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, -... | -30 | | } -31 | | } - | |_^ not found in `system` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this enum - | -1 | use frame_system::RawOrigin; - | - error[E0412]: cannot find type `Origin` in module `pallet` - --> $DIR/undefined_origin_part.rs:22:1 + --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -58,15 +34,15 @@ help: consider importing this type alias | error[E0412]: cannot find type `Origin` in module `pallet` - --> $DIR/undefined_origin_part.rs:22:1 + --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -77,38 +53,16 @@ help: consider importing one of these items 1 | use frame_system::Origin; | -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_origin_part.rs:22:1 +error[E0282]: type annotations needed + --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } - | |_^ not found in `system` +57 | | } +58 | | } + | |_^ cannot infer type for type parameter `AccountId` declared on the enum `RawOrigin` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use crate::pallet::Pallet; - | -1 | use frame_support_test::Pallet; - | -1 | use frame_system::Pallet; - | -1 | use test_pallet::Pallet; - | - -error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied - --> $DIR/undefined_origin_part.rs:20:6 - | -20 | impl pallet::Config for Runtime {} - | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` - | -note: required by a bound in `pallet::Config` - --> $DIR/undefined_origin_part.rs:8:20 - | -8 | pub trait Config: frame_system::Config {} - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs index 816f52b91cccb..621683aca3754 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs @@ -12,20 +12,47 @@ mod pallet { } pub type Signature = sr25519::Signature; -pub type BlockNumber = u64; +pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u32; + type Call = Call; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = frame_support::traits::ConstU32<250>; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + construct_runtime! { pub enum Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{Pallet, Call, Storage, Config, Event}, + System: frame_system::{Pallet, Call, Storage, Config, Event}, Pallet: pallet::{Pallet, ValidateUnsigned}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr index 8126d2f9a3e0f..94226075d9a4b 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr @@ -1,76 +1,67 @@ error: `Pallet` does not have #[pallet::validate_unsigned] defined, perhaps you should remove `ValidateUnsigned` from construct_runtime? - --> $DIR/undefined_validate_unsigned_part.rs:5:1 + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:5:1 | 5 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } +57 | | } +58 | | } | |_- in this macro invocation | = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_validate_unsigned_part.rs:28:11 +error[E0599]: no variant or associated item named `Pallet` found for enum `Call` in the current scope + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:56:3 | -28 | System: system::{Pallet, Call, Storage, Config, Event}, - | ^^^^^^ use of undeclared crate or module `system` +49 | construct_runtime! { + | ------------------ variant or associated item `Pallet` not found here +... +56 | Pallet: pallet::{Pallet, ValidateUnsigned}, + | ^^^^^^ variant or associated item not found in `Call` -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_validate_unsigned_part.rs:22:1 +error[E0599]: no function or associated item named `pre_dispatch` found for struct `pallet::Pallet` in the current scope + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +11 | pub struct Pallet(_); + | ------------------------ function or associated item `pre_dispatch` not found for this +... +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } - | |_^ not found in `system` - | +57 | | } +58 | | } + | |_^ function or associated item not found in `pallet::Pallet` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `pre_dispatch`, perhaps you need to implement one of them: + candidate #1: `SignedExtension` + candidate #2: `ValidateUnsigned` = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this enum - | -1 | use frame_system::RawOrigin; - | -error[E0433]: failed to resolve: use of undeclared crate or module `system` - --> $DIR/undefined_validate_unsigned_part.rs:22:1 +error[E0599]: no function or associated item named `validate_unsigned` found for struct `pallet::Pallet` in the current scope + --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 | -22 | / construct_runtime! { -23 | | pub enum Runtime where -24 | | Block = Block, -25 | | NodeBlock = Block, +11 | pub struct Pallet(_); + | ------------------------ function or associated item `validate_unsigned` not found for this +... +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, ... | -30 | | } -31 | | } - | |_^ not found in `system` - | +57 | | } +58 | | } + | |_^ function or associated item not found in `pallet::Pallet` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `validate_unsigned`, perhaps you need to implement one of them: + candidate #1: `SignedExtension` + candidate #2: `ValidateUnsigned` = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use crate::pallet::Pallet; - | -1 | use frame_support_test::Pallet; - | -1 | use frame_system::Pallet; - | -1 | use test_pallet::Pallet; - | - -error[E0277]: the trait bound `Runtime: frame_system::Config` is not satisfied - --> $DIR/undefined_validate_unsigned_part.rs:20:6 - | -20 | impl pallet::Config for Runtime {} - | ^^^^^^^^^^^^^^ the trait `frame_system::Config` is not implemented for `Runtime` - | -note: required by a bound in `pallet::Config` - --> $DIR/undefined_validate_unsigned_part.rs:8:20 - | -8 | pub trait Config: frame_system::Config {} - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `pallet::Config` From 7cb0e76b847a49e2a9227e0c039bcbb335c83309 Mon Sep 17 00:00:00 2001 From: Alexander Gryaznov Date: Fri, 4 Feb 2022 20:13:00 +0100 Subject: [PATCH 0485/1472] contracts: `is_contract(address)` and `caller_is_origin()` are added to API (#10789) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * is_contract() and caller_is_origin() added to Ext API * is_contract() exposed in wasm runtime.rs * + test for is_contract() * + seal_is_contract benchmark * caller_is_origin() exposed to wasm/runtime.rs and covered by a test * + seal_caller_is_origin benchmark * Update frame/contracts/src/exec.rs Co-authored-by: Alexander Theißen * Update frame/contracts/src/exec.rs Co-authored-by: Alexander Theißen * Update frame/contracts/src/exec.rs Co-authored-by: Alexander Theißen * Update frame/contracts/src/wasm/runtime.rs Co-authored-by: Alexander Theißen * Update frame/contracts/src/wasm/runtime.rs Co-authored-by: Alexander Theißen * Update frame/contracts/src/wasm/runtime.rs Co-authored-by: Alexander Theißen * Update frame/contracts/src/exec.rs Co-authored-by: Alexander Theißen * identation fix for benchmark macroses; test cosmetic improvement * benchmark fix * + is_contract() wasm test * + caller_is_origin() wasm test * Apply suggestions from code review Co-authored-by: Alexander Theißen * is_contract() to borrow param instead of taking ownership * phrasing improved Co-authored-by: Hernando Castano * fixed wasm tests according to @athei feedback * dead code warnings suppressed by unstable-interface attributes * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Alexander Theißen Co-authored-by: Hernando Castano Co-authored-by: Parity Bot --- frame/contracts/src/benchmarking/mod.rs | 57 ++ frame/contracts/src/exec.rs | 83 +- frame/contracts/src/schedule.rs | 8 + frame/contracts/src/wasm/mod.rs | 82 ++ frame/contracts/src/wasm/runtime.rs | 41 + frame/contracts/src/weights.rs | 1250 ++++++++++++----------- 6 files changed, 917 insertions(+), 604 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 83be846465e47..71045bde21525 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -398,6 +398,63 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + seal_is_contract { + let r in 0 .. API_BENCHMARK_BATCHES; + let accounts = (0 .. r * API_BENCHMARK_BATCH_SIZE) + .map(|n| account::("account", n, 0)) + .collect::>(); + let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); + let accounts_bytes = accounts.iter().map(|a| a.encode()).flatten().collect::>(); + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_is_contract", + params: vec![ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: accounts_bytes + }, + ], + call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, account_len as u32), // address_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let info = instance.info()?; + // every account would be a contract (worst case) + for acc in accounts.iter() { + >::insert(acc, info.clone()); + } + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + + seal_caller_is_origin { + let r in 0 .. API_BENCHMARK_BATCHES; + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_caller_is_origin", + params: vec![], + return_type: Some(ValueType::I32), + }], + call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + Instruction::Call(0), + Instruction::Drop, + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + seal_address { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index e4988eea51d0b..befdf592f51c0 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -158,6 +158,15 @@ pub trait Ext: sealing::Sealed { /// Returns a reference to the account id of the caller. fn caller(&self) -> &AccountIdOf; + /// Check if a contract lives at the specified `address`. + fn is_contract(&self, address: &AccountIdOf) -> bool; + + /// Check if the caller of the current contract is the origin of the whole call stack. + /// + /// This can be checked with `is_contract(self.caller())` as well. + /// However, this function does not require any storage lookup and therefore uses less weight. + fn caller_is_origin(&self) -> bool; + /// Returns a reference to the account id of the current contract. fn address(&self) -> &AccountIdOf; @@ -483,7 +492,7 @@ where T::AccountId: UncheckedFrom + AsRef<[u8]>, E: Executable, { - /// Create an run a new call stack by calling into `dest`. + /// Create and run a new call stack by calling into `dest`. /// /// # Note /// @@ -1024,6 +1033,14 @@ where self.frames().nth(1).map(|f| &f.account_id).unwrap_or(&self.origin) } + fn is_contract(&self, address: &T::AccountId) -> bool { + ContractInfoOf::::contains_key(&address) + } + + fn caller_is_origin(&self) -> bool { + self.caller() == &self.origin + } + fn balance(&self) -> BalanceOf { T::Currency::free_balance(&self.top_frame().account_id) } @@ -1620,6 +1637,70 @@ mod tests { WITNESSED_CALLER_CHARLIE.with(|caller| assert_eq!(*caller.borrow(), Some(dest))); } + #[test] + fn is_contract_returns_proper_values() { + let bob_ch = MockLoader::insert(Call, |ctx, _| { + // Verify that BOB is a contract + assert!(ctx.ext.is_contract(&BOB)); + // Verify that ALICE is not a contract + assert!(!ctx.ext.is_contract(&ALICE)); + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let schedule = ::Schedule::get(); + place_contract(&BOB, bob_ch); + + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); + let result = MockStack::run_call( + ALICE, + BOB, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + &schedule, + 0, + vec![], + None, + ); + assert_matches!(result, Ok(_)); + }); + } + + #[test] + fn caller_is_origin_returns_proper_values() { + let code_charlie = MockLoader::insert(Call, |ctx, _| { + // BOB is not the origin of the stack call + assert!(!ctx.ext.caller_is_origin()); + exec_success() + }); + + let code_bob = MockLoader::insert(Call, |ctx, _| { + // ALICE is the origin of the call stack + assert!(ctx.ext.caller_is_origin()); + // BOB calls CHARLIE + ctx.ext.call(0, CHARLIE, 0, vec![], true) + }); + + ExtBuilder::default().build().execute_with(|| { + let schedule = ::Schedule::get(); + place_contract(&BOB, code_bob); + place_contract(&CHARLIE, code_charlie); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); + // ALICE -> BOB (caller is origin) -> CHARLIE (caller is not origin) + let result = MockStack::run_call( + ALICE, + BOB, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + &schedule, + 0, + vec![0], + None, + ); + assert_matches!(result, Ok(_)); + }); + } + #[test] fn address_returns_proper_values() { let bob_ch = MockLoader::insert(Call, |ctx, _| { diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index f8ca182aea586..266c0a6e2748d 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -256,6 +256,12 @@ pub struct HostFnWeights { /// Weight of calling `seal_caller`. pub caller: Weight, + /// Weight of calling `seal_is_contract`. + pub is_contract: Weight, + + /// Weight of calling `seal_caller_is_origin`. + pub caller_is_origin: Weight, + /// Weight of calling `seal_address`. pub address: Weight, @@ -571,6 +577,8 @@ impl Default for HostFnWeights { fn default() -> Self { Self { caller: cost_batched!(seal_caller), + is_contract: cost_batched!(seal_is_contract), + caller_is_origin: cost_batched!(seal_caller_is_origin), address: cost_batched!(seal_address), gas_left: cost_batched!(seal_gas_left), balance: cost_batched!(seal_balance), diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 41e940bcd9b6c..7c98ee7cf5b1a 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -409,6 +409,12 @@ mod tests { fn caller(&self) -> &AccountIdOf { &ALICE } + fn is_contract(&self, _address: &AccountIdOf) -> bool { + true + } + fn caller_is_origin(&self) -> bool { + false + } fn address(&self) -> &AccountIdOf { &BOB } @@ -2240,4 +2246,80 @@ mod tests { let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0,); } + + #[test] + #[cfg(feature = "unstable-interface")] + fn is_contract_works() { + const CODE_IS_CONTRACT: &str = r#" +;; This runs `is_contract` check on zero account address +(module + (import "__unstable__" "seal_is_contract" (func $seal_is_contract (param i32) (result i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 32) zero-adress + (data (i32.const 0) + "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00" + "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00" + ) + + ;; [32, 36) here we store the return code of the `seal_is_contract` + + (func (export "deploy")) + + (func (export "call") + (i32.store + (i32.const 32) + (call $seal_is_contract + (i32.const 0) ;; ptr to destination address + ) + ) + ;; exit with success and take `seal_is_contract` return code to the output buffer + (call $seal_return (i32.const 0) (i32.const 32) (i32.const 4)) + ) +) +"#; + let output = execute(CODE_IS_CONTRACT, vec![], MockExt::default()).unwrap(); + + // The mock ext just always returns 1u32 (`true`). + assert_eq!( + output, + ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(1u32.encode()) }, + ); + } + + #[test] + #[cfg(feature = "unstable-interface")] + fn caller_is_origin_works() { + const CODE_CALLER_IS_ORIGIN: &str = r#" +;; This runs `caller_is_origin` check on zero account address +(module + (import "__unstable__" "seal_caller_is_origin" (func $seal_caller_is_origin (result i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 4) here the return code of the `seal_caller_is_origin` will be stored + ;; we initialize it with non-zero value to be sure that it's being overwritten below + (data (i32.const 0) "\10\10\10\10") + + (func (export "deploy")) + + (func (export "call") + (i32.store + (i32.const 0) + (call $seal_caller_is_origin) + ) + ;; exit with success and take `seal_caller_is_origin` return code to the output buffer + (call $seal_return (i32.const 0) (i32.const 0) (i32.const 4)) + ) +) +"#; + let output = execute(CODE_CALLER_IS_ORIGIN, vec![], MockExt::default()).unwrap(); + + // The mock ext just always returns 0u32 (`false`) + assert_eq!( + output, + ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(0u32.encode()) }, + ); + } } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 13aa934306978..194d5ffbaaf4f 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -138,6 +138,12 @@ pub enum RuntimeCosts { MeteringBlock(u32), /// Weight of calling `seal_caller`. Caller, + /// Weight of calling `seal_is_contract`. + #[cfg(feature = "unstable-interface")] + IsContract, + /// Weight of calling `seal_caller_is_origin`. + #[cfg(feature = "unstable-interface")] + CallerIsOrigin, /// Weight of calling `seal_address`. Address, /// Weight of calling `seal_gas_left`. @@ -225,6 +231,10 @@ impl RuntimeCosts { let weight = match *self { MeteringBlock(amount) => s.gas.saturating_add(amount.into()), Caller => s.caller, + #[cfg(feature = "unstable-interface")] + IsContract => s.is_contract, + #[cfg(feature = "unstable-interface")] + CallerIsOrigin => s.caller_is_origin, Address => s.address, GasLeft => s.gas_left, Balance => s.balance, @@ -1254,6 +1264,37 @@ define_env!(Env, , )?) }, + // Checks whether a specified address belongs to a contract. + // + // # Parameters + // + // - account_ptr: a pointer to the address of the beneficiary account + // Should be decodable as an `T::AccountId`. Traps otherwise. + // + // Returned value is a u32-encoded boolean: (0 = false, 1 = true). + [__unstable__] seal_is_contract(ctx, account_ptr: u32) -> u32 => { + ctx.charge_gas(RuntimeCosts::IsContract)?; + let address: <::T as frame_system::Config>::AccountId = + ctx.read_sandbox_memory_as(account_ptr)?; + + Ok(ctx.ext.is_contract(&address) as u32) + }, + + // Checks whether the caller of the current contract is the origin of the whole call stack. + // + // Prefer this over `seal_is_contract` when checking whether your contract is being called by a contract + // or a plain account. The reason is that it performs better since it does not need to + // do any storage lookups. + // + // A return value of`true` indicates that this contract is being called by a plain account + // and `false` indicates that the caller is another contract. + // + // Returned value is a u32-encoded boolean: (0 = false, 1 = true). + [__unstable__] seal_caller_is_origin(ctx) -> u32 => { + ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?; + Ok(ctx.ext.caller_is_origin() as u32) + }, + // Stores the address of the current contract into the supplied buffer. // // The value is stored to linear memory at the address pointed to by `out_ptr`. diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 24a42cc10649a..b58660b694ca9 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-02-04, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -55,6 +55,8 @@ pub trait WeightInfo { fn upload_code(c: u32, ) -> Weight; fn remove_code() -> Weight; fn seal_caller(r: u32, ) -> Weight; + fn seal_is_contract(r: u32, ) -> Weight; + fn seal_caller_is_origin(r: u32, ) -> Weight; fn seal_address(r: u32, ) -> Weight; fn seal_gas_left(r: u32, ) -> Weight; fn seal_balance(r: u32, ) -> Weight; @@ -156,14 +158,14 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_642_000 as Weight) + (1_640_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (7_854_000 as Weight) + (6_385_000 as Weight) // Standard Error: 0 - .saturating_add((742_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((748_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -171,17 +173,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { (0 as Weight) - // Standard Error: 6_000 - .saturating_add((2_216_000 as Weight).saturating_mul(q as Weight)) + // Standard Error: 5_000 + .saturating_add((2_304_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (17_413_000 as Weight) - // Standard Error: 39_000 - .saturating_add((64_495_000 as Weight).saturating_mul(c as Weight)) + (22_923_000 as Weight) + // Standard Error: 33_000 + .saturating_add((65_851_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -190,9 +192,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (209_071_000 as Weight) - // Standard Error: 47_000 - .saturating_add((56_555_000 as Weight).saturating_mul(c as Weight)) + (209_577_000 as Weight) + // Standard Error: 53_000 + .saturating_add((61_341_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -204,11 +206,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (210_420_000 as Weight) - // Standard Error: 133_000 - .saturating_add((145_601_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 8_000 - .saturating_add((1_760_000 as Weight).saturating_mul(s as Weight)) + (240_302_000 as Weight) + // Standard Error: 119_000 + .saturating_add((151_894_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 7_000 + .saturating_add((1_740_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -219,9 +221,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (173_397_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_714_000 as Weight).saturating_mul(s as Weight)) + (172_047_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_729_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -230,7 +232,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (140_169_000 as Weight) + (139_349_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -238,9 +240,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (49_076_000 as Weight) - // Standard Error: 37_000 - .saturating_add((67_150_000 as Weight).saturating_mul(c as Weight)) + (50_449_000 as Weight) + // Standard Error: 45_000 + .saturating_add((68_254_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -248,7 +250,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_318_000 as Weight) + (24_576_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -257,9 +259,32 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (208_256_000 as Weight) - // Standard Error: 116_000 - .saturating_add((49_878_000 as Weight).saturating_mul(r as Weight)) + (220_059_000 as Weight) + // Standard Error: 128_000 + .saturating_add((49_607_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + fn seal_is_contract(r: u32, ) -> Weight { + (84_138_000 as Weight) + // Standard Error: 896_000 + .saturating_add((375_553_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + fn seal_caller_is_origin(r: u32, ) -> Weight { + (222_496_000 as Weight) + // Standard Error: 119_000 + .saturating_add((22_340_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -268,9 +293,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (230_530_000 as Weight) - // Standard Error: 132_000 - .saturating_add((47_902_000 as Weight).saturating_mul(r as Weight)) + (221_446_000 as Weight) + // Standard Error: 131_000 + .saturating_add((49_401_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -279,9 +304,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (219_027_000 as Weight) - // Standard Error: 108_000 - .saturating_add((48_039_000 as Weight).saturating_mul(r as Weight)) + (220_964_000 as Weight) + // Standard Error: 132_000 + .saturating_add((49_230_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -290,9 +315,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (219_036_000 as Weight) - // Standard Error: 152_000 - .saturating_add((137_047_000 as Weight).saturating_mul(r as Weight)) + (229_399_000 as Weight) + // Standard Error: 166_000 + .saturating_add((137_407_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -301,9 +326,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (214_401_000 as Weight) - // Standard Error: 96_000 - .saturating_add((48_435_000 as Weight).saturating_mul(r as Weight)) + (220_103_000 as Weight) + // Standard Error: 133_000 + .saturating_add((49_410_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -312,9 +337,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (216_939_000 as Weight) - // Standard Error: 106_000 - .saturating_add((48_198_000 as Weight).saturating_mul(r as Weight)) + (228_143_000 as Weight) + // Standard Error: 151_000 + .saturating_add((48_608_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -323,9 +348,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (216_637_000 as Weight) - // Standard Error: 86_000 - .saturating_add((47_819_000 as Weight).saturating_mul(r as Weight)) + (223_899_000 as Weight) + // Standard Error: 142_000 + .saturating_add((48_841_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -334,9 +359,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (214_863_000 as Weight) - // Standard Error: 110_000 - .saturating_add((48_208_000 as Weight).saturating_mul(r as Weight)) + (224_974_000 as Weight) + // Standard Error: 148_000 + .saturating_add((48_902_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -346,9 +371,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (216_494_000 as Weight) - // Standard Error: 141_000 - .saturating_add((120_736_000 as Weight).saturating_mul(r as Weight)) + (227_556_000 as Weight) + // Standard Error: 151_000 + .saturating_add((121_252_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -357,9 +382,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (123_867_000 as Weight) - // Standard Error: 33_000 - .saturating_add((24_578_000 as Weight).saturating_mul(r as Weight)) + (127_975_000 as Weight) + // Standard Error: 57_000 + .saturating_add((24_843_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -368,9 +393,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (215_578_000 as Weight) - // Standard Error: 108_000 - .saturating_add((47_512_000 as Weight).saturating_mul(r as Weight)) + (224_592_000 as Weight) + // Standard Error: 141_000 + .saturating_add((48_296_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -379,9 +404,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (297_663_000 as Weight) + (296_995_000 as Weight) // Standard Error: 3_000 - .saturating_add((11_863_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((11_884_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -389,10 +414,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(r: u32, ) -> Weight { - (209_709_000 as Weight) - // Standard Error: 75_000 - .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) + fn seal_return(_r: u32, ) -> Weight { + (224_322_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -401,9 +424,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (214_403_000 as Weight) - // Standard Error: 0 - .saturating_add((197_000 as Weight).saturating_mul(n as Weight)) + (216_240_000 as Weight) + // Standard Error: 1_000 + .saturating_add((206_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -414,9 +437,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (214_454_000 as Weight) - // Standard Error: 656_000 - .saturating_add((50_641_000 as Weight).saturating_mul(r as Weight)) + (219_637_000 as Weight) + // Standard Error: 3_916_000 + .saturating_add((51_769_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -428,9 +451,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (214_140_000 as Weight) - // Standard Error: 169_000 - .saturating_add((158_778_000 as Weight).saturating_mul(r as Weight)) + (221_470_000 as Weight) + // Standard Error: 154_000 + .saturating_add((158_758_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -439,9 +462,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (225_998_000 as Weight) - // Standard Error: 171_000 - .saturating_add((280_296_000 as Weight).saturating_mul(r as Weight)) + (228_674_000 as Weight) + // Standard Error: 203_000 + .saturating_add((287_195_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -451,11 +474,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (491_432_000 as Weight) - // Standard Error: 1_992_000 - .saturating_add((288_376_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 392_000 - .saturating_add((82_805_000 as Weight).saturating_mul(n as Weight)) + (507_091_000 as Weight) + // Standard Error: 1_863_000 + .saturating_add((291_858_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 367_000 + .saturating_add((83_459_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -466,17 +489,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (130_861_000 as Weight) - // Standard Error: 74_000 - .saturating_add((40_268_000 as Weight).saturating_mul(r as Weight)) + (133_592_000 as Weight) + // Standard Error: 87_000 + .saturating_add((41_718_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (38_843_000 as Weight) - // Standard Error: 1_044_000 - .saturating_add((408_027_000 as Weight).saturating_mul(r as Weight)) + (44_719_000 as Weight) + // Standard Error: 1_036_000 + .saturating_add((407_521_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -484,25 +507,25 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (610_782_000 as Weight) - // Standard Error: 265_000 - .saturating_add((28_221_000 as Weight).saturating_mul(n as Weight)) + (606_108_000 as Weight) + // Standard Error: 315_000 + .saturating_add((29_136_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (625_031_000 as Weight) - // Standard Error: 319_000 - .saturating_add((11_126_000 as Weight).saturating_mul(n as Weight)) + (634_330_000 as Weight) + // Standard Error: 281_000 + .saturating_add((10_741_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (78_566_000 as Weight) - // Standard Error: 970_000 - .saturating_add((384_877_000 as Weight).saturating_mul(r as Weight)) + (89_750_000 as Weight) + // Standard Error: 924_000 + .saturating_add((382_525_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -510,51 +533,51 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (601_558_000 as Weight) - // Standard Error: 280_000 - .saturating_add((11_378_000 as Weight).saturating_mul(n as Weight)) + (616_463_000 as Weight) + // Standard Error: 260_000 + .saturating_add((10_373_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (112_328_000 as Weight) - // Standard Error: 668_000 - .saturating_add((323_031_000 as Weight).saturating_mul(r as Weight)) + (116_340_000 as Weight) + // Standard Error: 633_000 + .saturating_add((322_054_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (556_303_000 as Weight) - // Standard Error: 346_000 - .saturating_add((64_170_000 as Weight).saturating_mul(n as Weight)) + (563_077_000 as Weight) + // Standard Error: 340_000 + .saturating_add((63_889_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (106_572_000 as Weight) - // Standard Error: 691_000 - .saturating_add((294_964_000 as Weight).saturating_mul(r as Weight)) + (118_832_000 as Weight) + // Standard Error: 595_000 + .saturating_add((291_817_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (508_339_000 as Weight) - // Standard Error: 245_000 - .saturating_add((10_675_000 as Weight).saturating_mul(n as Weight)) + (520_386_000 as Weight) + // Standard Error: 297_000 + .saturating_add((10_076_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (88_096_000 as Weight) - // Standard Error: 927_000 - .saturating_add((415_543_000 as Weight).saturating_mul(r as Weight)) + (85_377_000 as Weight) + // Standard Error: 847_000 + .saturating_add((419_438_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -562,9 +585,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (650_912_000 as Weight) - // Standard Error: 359_000 - .saturating_add((65_030_000 as Weight).saturating_mul(n as Weight)) + (666_218_000 as Weight) + // Standard Error: 294_000 + .saturating_add((64_627_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } @@ -573,9 +596,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (102_673_000 as Weight) - // Standard Error: 1_159_000 - .saturating_add((1_711_312_000 as Weight).saturating_mul(r as Weight)) + (108_224_000 as Weight) + // Standard Error: 1_042_000 + .saturating_add((1_723_539_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -587,8 +610,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_592_000 - .saturating_add((19_565_726_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 7_843_000 + .saturating_add((19_825_093_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -599,13 +622,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (19_665_171_000 as Weight) - // Standard Error: 27_641_000 - .saturating_add((2_089_637_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 9_000 - .saturating_add((20_165_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 10_000 - .saturating_add((31_728_000 as Weight).saturating_mul(o as Weight)) + (20_190_331_000 as Weight) + // Standard Error: 75_647_000 + .saturating_add((2_369_225_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 27_000 + .saturating_add((19_831_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 28_000 + .saturating_add((31_191_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -619,8 +642,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 48_640_000 - .saturating_add((27_307_450_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 50_368_000 + .saturating_add((27_757_564_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -633,13 +656,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (24_821_248_000 as Weight) - // Standard Error: 26_000 - .saturating_add((20_118_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 26_000 - .saturating_add((31_616_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 26_000 - .saturating_add((157_567_000 as Weight).saturating_mul(s as Weight)) + (25_199_228_000 as Weight) + // Standard Error: 36_000 + .saturating_add((19_598_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 36_000 + .saturating_add((30_986_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 36_000 + .saturating_add((158_016_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().writes(206 as Weight)) } @@ -648,9 +671,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (213_816_000 as Weight) - // Standard Error: 147_000 - .saturating_add((80_336_000 as Weight).saturating_mul(r as Weight)) + (222_984_000 as Weight) + // Standard Error: 155_000 + .saturating_add((80_649_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -659,9 +682,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (309_038_000 as Weight) - // Standard Error: 23_000 - .saturating_add((465_306_000 as Weight).saturating_mul(n as Weight)) + (393_726_000 as Weight) + // Standard Error: 36_000 + .saturating_add((463_983_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -670,9 +693,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (212_825_000 as Weight) - // Standard Error: 143_000 - .saturating_add((91_947_000 as Weight).saturating_mul(r as Weight)) + (217_461_000 as Weight) + // Standard Error: 146_000 + .saturating_add((92_540_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -681,9 +704,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (329_548_000 as Weight) + (271_742_000 as Weight) // Standard Error: 19_000 - .saturating_add((306_729_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((307_055_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -692,9 +715,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (215_907_000 as Weight) - // Standard Error: 129_000 - .saturating_add((63_477_000 as Weight).saturating_mul(r as Weight)) + (220_664_000 as Weight) + // Standard Error: 145_000 + .saturating_add((64_516_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -703,9 +726,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (423_811_000 as Weight) - // Standard Error: 16_000 - .saturating_add((119_607_000 as Weight).saturating_mul(n as Weight)) + (287_500_000 as Weight) + // Standard Error: 12_000 + .saturating_add((119_931_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -714,9 +737,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (214_747_000 as Weight) - // Standard Error: 115_000 - .saturating_add((62_904_000 as Weight).saturating_mul(r as Weight)) + (214_922_000 as Weight) + // Standard Error: 122_000 + .saturating_add((64_236_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -725,9 +748,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (437_217_000 as Weight) - // Standard Error: 19_000 - .saturating_add((120_126_000 as Weight).saturating_mul(n as Weight)) + (251_648_000 as Weight) + // Standard Error: 13_000 + .saturating_add((120_105_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -736,266 +759,266 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (195_980_000 as Weight) - // Standard Error: 1_262_000 - .saturating_add((15_428_805_000 as Weight).saturating_mul(r as Weight)) + (124_760_000 as Weight) + // Standard Error: 1_397_000 + .saturating_add((15_387_180_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (74_569_000 as Weight) - // Standard Error: 1_000 - .saturating_add((589_000 as Weight).saturating_mul(r as Weight)) + (75_287_000 as Weight) + // Standard Error: 11_000 + .saturating_add((569_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_212_000 as Weight) - // Standard Error: 0 - .saturating_add((1_325_000 as Weight).saturating_mul(r as Weight)) + (74_251_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_306_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_505_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_423_000 as Weight).saturating_mul(r as Weight)) + (75_072_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_386_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (74_005_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_785_000 as Weight).saturating_mul(r as Weight)) + (73_811_000 as Weight) + // Standard Error: 0 + .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (74_212_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_890_000 as Weight).saturating_mul(r as Weight)) + (73_901_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_886_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (74_102_000 as Weight) - // Standard Error: 2_000 - .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) + (73_720_000 as Weight) + // Standard Error: 1_000 + .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_523_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_456_000 as Weight).saturating_mul(r as Weight)) + (73_534_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_459_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_307_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_594_000 as Weight).saturating_mul(r as Weight)) + (73_281_000 as Weight) + // Standard Error: 8_000 + .saturating_add((1_584_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_272_000 as Weight) - // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) + (76_135_000 as Weight) + // Standard Error: 1_000 + .saturating_add((6_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (73_390_000 as Weight) + (75_938_000 as Weight) // Standard Error: 23_000 - .saturating_add((16_936_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((17_156_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (89_331_000 as Weight) - // Standard Error: 30_000 - .saturating_add((28_104_000 as Weight).saturating_mul(r as Weight)) + (85_864_000 as Weight) + // Standard Error: 28_000 + .saturating_add((28_343_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (117_023_000 as Weight) - // Standard Error: 3_000 - .saturating_add((914_000 as Weight).saturating_mul(p as Weight)) + (119_795_000 as Weight) + // Standard Error: 1_000 + .saturating_add((911_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (74_727_000 as Weight) + (74_750_000 as Weight) // Standard Error: 1_000 - .saturating_add((618_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((613_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_893_000 as Weight) - // Standard Error: 1_000 - .saturating_add((674_000 as Weight).saturating_mul(r as Weight)) + (74_831_000 as Weight) + // Standard Error: 2_000 + .saturating_add((672_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_552_000 as Weight) + (74_314_000 as Weight) // Standard Error: 1_000 - .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((902_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_355_000 as Weight) + (77_040_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_146_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_161_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (77_055_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + (76_770_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_648_000 as Weight) - // Standard Error: 2_000 - .saturating_add((652_000 as Weight).saturating_mul(r as Weight)) + (74_010_000 as Weight) + // Standard Error: 1_000 + .saturating_add((665_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_777_000 as Weight) - // Standard Error: 226_000 - .saturating_add((187_252_000 as Weight).saturating_mul(r as Weight)) + (73_597_000 as Weight) + // Standard Error: 929_000 + .saturating_add((183_940_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_332_000 as Weight) - // Standard Error: 1_000 - .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) + (74_488_000 as Weight) + // Standard Error: 4_000 + .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_265_000 as Weight) - // Standard Error: 1_000 - .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) + (74_024_000 as Weight) + // Standard Error: 5_000 + .saturating_add((908_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_475_000 as Weight) - // Standard Error: 2_000 - .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) + (74_084_000 as Weight) + // Standard Error: 1_000 + .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_297_000 as Weight) - // Standard Error: 1_000 - .saturating_add((918_000 as Weight).saturating_mul(r as Weight)) + (74_250_000 as Weight) + // Standard Error: 2_000 + .saturating_add((916_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_146_000 as Weight) + (74_027_000 as Weight) // Standard Error: 1_000 - .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((883_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_361_000 as Weight) + (74_201_000 as Weight) // Standard Error: 1_000 - .saturating_add((877_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((879_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_554_000 as Weight) + (74_116_000 as Weight) // Standard Error: 1_000 - .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (74_169_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (74_109_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (74_164_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (73_962_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (74_058_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (73_977_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_039_000 as Weight) + (74_046_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (75_055_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (73_912_000 as Weight) + // Standard Error: 0 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (74_536_000 as Weight) - // Standard Error: 4_000 + (73_918_000 as Weight) + // Standard Error: 2_000 .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (74_177_000 as Weight) + (73_953_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_080_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + (74_855_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (74_237_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + (73_917_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_364_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_049_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (73_949_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (74_186_000 as Weight) + (73_726_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_268_000 as Weight) + (73_921_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (74_334_000 as Weight) + (73_924_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_331_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (74_285_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_997_000 as Weight).saturating_mul(r as Weight)) + (73_842_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_011_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (74_002_000 as Weight) + (73_932_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_027_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_057_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (74_281_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_977_000 as Weight).saturating_mul(r as Weight)) + (74_028_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_001_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (74_160_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_038_000 as Weight).saturating_mul(r as Weight)) + (73_784_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_059_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_097_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) + (74_169_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_334_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (74_020_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) + (73_982_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (73_890_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) + (74_310_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_329_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (74_139_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (73_861_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (74_189_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (73_787_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_364_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (74_055_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) + (73_886_000 as Weight) + // Standard Error: 7_000 + .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (74_074_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (73_860_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (74_005_000 as Weight) + (73_917_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } } @@ -1003,14 +1026,14 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_642_000 as Weight) + (1_640_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (7_854_000 as Weight) + (6_385_000 as Weight) // Standard Error: 0 - .saturating_add((742_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((748_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -1018,17 +1041,17 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { (0 as Weight) - // Standard Error: 6_000 - .saturating_add((2_216_000 as Weight).saturating_mul(q as Weight)) + // Standard Error: 5_000 + .saturating_add((2_304_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (17_413_000 as Weight) - // Standard Error: 39_000 - .saturating_add((64_495_000 as Weight).saturating_mul(c as Weight)) + (22_923_000 as Weight) + // Standard Error: 33_000 + .saturating_add((65_851_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1037,9 +1060,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (209_071_000 as Weight) - // Standard Error: 47_000 - .saturating_add((56_555_000 as Weight).saturating_mul(c as Weight)) + (209_577_000 as Weight) + // Standard Error: 53_000 + .saturating_add((61_341_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1051,11 +1074,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (210_420_000 as Weight) - // Standard Error: 133_000 - .saturating_add((145_601_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 8_000 - .saturating_add((1_760_000 as Weight).saturating_mul(s as Weight)) + (240_302_000 as Weight) + // Standard Error: 119_000 + .saturating_add((151_894_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 7_000 + .saturating_add((1_740_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1066,9 +1089,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (173_397_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_714_000 as Weight).saturating_mul(s as Weight)) + (172_047_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_729_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1077,7 +1100,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (140_169_000 as Weight) + (139_349_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1085,9 +1108,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (49_076_000 as Weight) - // Standard Error: 37_000 - .saturating_add((67_150_000 as Weight).saturating_mul(c as Weight)) + (50_449_000 as Weight) + // Standard Error: 45_000 + .saturating_add((68_254_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1095,7 +1118,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_318_000 as Weight) + (24_576_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1104,9 +1127,32 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (208_256_000 as Weight) - // Standard Error: 116_000 - .saturating_add((49_878_000 as Weight).saturating_mul(r as Weight)) + (220_059_000 as Weight) + // Standard Error: 128_000 + .saturating_add((49_607_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + fn seal_is_contract(r: u32, ) -> Weight { + (84_138_000 as Weight) + // Standard Error: 896_000 + .saturating_add((375_553_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + fn seal_caller_is_origin(r: u32, ) -> Weight { + (222_496_000 as Weight) + // Standard Error: 119_000 + .saturating_add((22_340_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1115,9 +1161,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (230_530_000 as Weight) - // Standard Error: 132_000 - .saturating_add((47_902_000 as Weight).saturating_mul(r as Weight)) + (221_446_000 as Weight) + // Standard Error: 131_000 + .saturating_add((49_401_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1126,9 +1172,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (219_027_000 as Weight) - // Standard Error: 108_000 - .saturating_add((48_039_000 as Weight).saturating_mul(r as Weight)) + (220_964_000 as Weight) + // Standard Error: 132_000 + .saturating_add((49_230_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1137,9 +1183,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (219_036_000 as Weight) - // Standard Error: 152_000 - .saturating_add((137_047_000 as Weight).saturating_mul(r as Weight)) + (229_399_000 as Weight) + // Standard Error: 166_000 + .saturating_add((137_407_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1148,9 +1194,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (214_401_000 as Weight) - // Standard Error: 96_000 - .saturating_add((48_435_000 as Weight).saturating_mul(r as Weight)) + (220_103_000 as Weight) + // Standard Error: 133_000 + .saturating_add((49_410_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1159,9 +1205,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (216_939_000 as Weight) - // Standard Error: 106_000 - .saturating_add((48_198_000 as Weight).saturating_mul(r as Weight)) + (228_143_000 as Weight) + // Standard Error: 151_000 + .saturating_add((48_608_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1170,9 +1216,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (216_637_000 as Weight) - // Standard Error: 86_000 - .saturating_add((47_819_000 as Weight).saturating_mul(r as Weight)) + (223_899_000 as Weight) + // Standard Error: 142_000 + .saturating_add((48_841_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1181,9 +1227,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (214_863_000 as Weight) - // Standard Error: 110_000 - .saturating_add((48_208_000 as Weight).saturating_mul(r as Weight)) + (224_974_000 as Weight) + // Standard Error: 148_000 + .saturating_add((48_902_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1193,9 +1239,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (216_494_000 as Weight) - // Standard Error: 141_000 - .saturating_add((120_736_000 as Weight).saturating_mul(r as Weight)) + (227_556_000 as Weight) + // Standard Error: 151_000 + .saturating_add((121_252_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1204,9 +1250,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (123_867_000 as Weight) - // Standard Error: 33_000 - .saturating_add((24_578_000 as Weight).saturating_mul(r as Weight)) + (127_975_000 as Weight) + // Standard Error: 57_000 + .saturating_add((24_843_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1215,9 +1261,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (215_578_000 as Weight) - // Standard Error: 108_000 - .saturating_add((47_512_000 as Weight).saturating_mul(r as Weight)) + (224_592_000 as Weight) + // Standard Error: 141_000 + .saturating_add((48_296_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1226,9 +1272,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (297_663_000 as Weight) + (296_995_000 as Weight) // Standard Error: 3_000 - .saturating_add((11_863_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((11_884_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1236,10 +1282,8 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(r: u32, ) -> Weight { - (209_709_000 as Weight) - // Standard Error: 75_000 - .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) + fn seal_return(_r: u32, ) -> Weight { + (224_322_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1248,9 +1292,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (214_403_000 as Weight) - // Standard Error: 0 - .saturating_add((197_000 as Weight).saturating_mul(n as Weight)) + (216_240_000 as Weight) + // Standard Error: 1_000 + .saturating_add((206_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1261,9 +1305,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (214_454_000 as Weight) - // Standard Error: 656_000 - .saturating_add((50_641_000 as Weight).saturating_mul(r as Weight)) + (219_637_000 as Weight) + // Standard Error: 3_916_000 + .saturating_add((51_769_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1275,9 +1319,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (214_140_000 as Weight) - // Standard Error: 169_000 - .saturating_add((158_778_000 as Weight).saturating_mul(r as Weight)) + (221_470_000 as Weight) + // Standard Error: 154_000 + .saturating_add((158_758_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1286,9 +1330,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (225_998_000 as Weight) - // Standard Error: 171_000 - .saturating_add((280_296_000 as Weight).saturating_mul(r as Weight)) + (228_674_000 as Weight) + // Standard Error: 203_000 + .saturating_add((287_195_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1298,11 +1342,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (491_432_000 as Weight) - // Standard Error: 1_992_000 - .saturating_add((288_376_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 392_000 - .saturating_add((82_805_000 as Weight).saturating_mul(n as Weight)) + (507_091_000 as Weight) + // Standard Error: 1_863_000 + .saturating_add((291_858_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 367_000 + .saturating_add((83_459_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1313,17 +1357,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (130_861_000 as Weight) - // Standard Error: 74_000 - .saturating_add((40_268_000 as Weight).saturating_mul(r as Weight)) + (133_592_000 as Weight) + // Standard Error: 87_000 + .saturating_add((41_718_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (38_843_000 as Weight) - // Standard Error: 1_044_000 - .saturating_add((408_027_000 as Weight).saturating_mul(r as Weight)) + (44_719_000 as Weight) + // Standard Error: 1_036_000 + .saturating_add((407_521_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1331,25 +1375,25 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (610_782_000 as Weight) - // Standard Error: 265_000 - .saturating_add((28_221_000 as Weight).saturating_mul(n as Weight)) + (606_108_000 as Weight) + // Standard Error: 315_000 + .saturating_add((29_136_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (625_031_000 as Weight) - // Standard Error: 319_000 - .saturating_add((11_126_000 as Weight).saturating_mul(n as Weight)) + (634_330_000 as Weight) + // Standard Error: 281_000 + .saturating_add((10_741_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (78_566_000 as Weight) - // Standard Error: 970_000 - .saturating_add((384_877_000 as Weight).saturating_mul(r as Weight)) + (89_750_000 as Weight) + // Standard Error: 924_000 + .saturating_add((382_525_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1357,51 +1401,51 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (601_558_000 as Weight) - // Standard Error: 280_000 - .saturating_add((11_378_000 as Weight).saturating_mul(n as Weight)) + (616_463_000 as Weight) + // Standard Error: 260_000 + .saturating_add((10_373_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (112_328_000 as Weight) - // Standard Error: 668_000 - .saturating_add((323_031_000 as Weight).saturating_mul(r as Weight)) + (116_340_000 as Weight) + // Standard Error: 633_000 + .saturating_add((322_054_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (556_303_000 as Weight) - // Standard Error: 346_000 - .saturating_add((64_170_000 as Weight).saturating_mul(n as Weight)) + (563_077_000 as Weight) + // Standard Error: 340_000 + .saturating_add((63_889_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (106_572_000 as Weight) - // Standard Error: 691_000 - .saturating_add((294_964_000 as Weight).saturating_mul(r as Weight)) + (118_832_000 as Weight) + // Standard Error: 595_000 + .saturating_add((291_817_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (508_339_000 as Weight) - // Standard Error: 245_000 - .saturating_add((10_675_000 as Weight).saturating_mul(n as Weight)) + (520_386_000 as Weight) + // Standard Error: 297_000 + .saturating_add((10_076_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (88_096_000 as Weight) - // Standard Error: 927_000 - .saturating_add((415_543_000 as Weight).saturating_mul(r as Weight)) + (85_377_000 as Weight) + // Standard Error: 847_000 + .saturating_add((419_438_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1409,9 +1453,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (650_912_000 as Weight) - // Standard Error: 359_000 - .saturating_add((65_030_000 as Weight).saturating_mul(n as Weight)) + (666_218_000 as Weight) + // Standard Error: 294_000 + .saturating_add((64_627_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } @@ -1420,9 +1464,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (102_673_000 as Weight) - // Standard Error: 1_159_000 - .saturating_add((1_711_312_000 as Weight).saturating_mul(r as Weight)) + (108_224_000 as Weight) + // Standard Error: 1_042_000 + .saturating_add((1_723_539_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1434,8 +1478,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_592_000 - .saturating_add((19_565_726_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 7_843_000 + .saturating_add((19_825_093_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1446,13 +1490,13 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (19_665_171_000 as Weight) - // Standard Error: 27_641_000 - .saturating_add((2_089_637_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 9_000 - .saturating_add((20_165_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 10_000 - .saturating_add((31_728_000 as Weight).saturating_mul(o as Weight)) + (20_190_331_000 as Weight) + // Standard Error: 75_647_000 + .saturating_add((2_369_225_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 27_000 + .saturating_add((19_831_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 28_000 + .saturating_add((31_191_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1466,8 +1510,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 48_640_000 - .saturating_add((27_307_450_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 50_368_000 + .saturating_add((27_757_564_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1480,13 +1524,13 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (24_821_248_000 as Weight) - // Standard Error: 26_000 - .saturating_add((20_118_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 26_000 - .saturating_add((31_616_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 26_000 - .saturating_add((157_567_000 as Weight).saturating_mul(s as Weight)) + (25_199_228_000 as Weight) + // Standard Error: 36_000 + .saturating_add((19_598_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 36_000 + .saturating_add((30_986_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 36_000 + .saturating_add((158_016_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().writes(206 as Weight)) } @@ -1495,9 +1539,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (213_816_000 as Weight) - // Standard Error: 147_000 - .saturating_add((80_336_000 as Weight).saturating_mul(r as Weight)) + (222_984_000 as Weight) + // Standard Error: 155_000 + .saturating_add((80_649_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1506,9 +1550,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (309_038_000 as Weight) - // Standard Error: 23_000 - .saturating_add((465_306_000 as Weight).saturating_mul(n as Weight)) + (393_726_000 as Weight) + // Standard Error: 36_000 + .saturating_add((463_983_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1517,9 +1561,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (212_825_000 as Weight) - // Standard Error: 143_000 - .saturating_add((91_947_000 as Weight).saturating_mul(r as Weight)) + (217_461_000 as Weight) + // Standard Error: 146_000 + .saturating_add((92_540_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1528,9 +1572,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (329_548_000 as Weight) + (271_742_000 as Weight) // Standard Error: 19_000 - .saturating_add((306_729_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((307_055_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1539,9 +1583,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (215_907_000 as Weight) - // Standard Error: 129_000 - .saturating_add((63_477_000 as Weight).saturating_mul(r as Weight)) + (220_664_000 as Weight) + // Standard Error: 145_000 + .saturating_add((64_516_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1550,9 +1594,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (423_811_000 as Weight) - // Standard Error: 16_000 - .saturating_add((119_607_000 as Weight).saturating_mul(n as Weight)) + (287_500_000 as Weight) + // Standard Error: 12_000 + .saturating_add((119_931_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1561,9 +1605,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (214_747_000 as Weight) - // Standard Error: 115_000 - .saturating_add((62_904_000 as Weight).saturating_mul(r as Weight)) + (214_922_000 as Weight) + // Standard Error: 122_000 + .saturating_add((64_236_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1572,9 +1616,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (437_217_000 as Weight) - // Standard Error: 19_000 - .saturating_add((120_126_000 as Weight).saturating_mul(n as Weight)) + (251_648_000 as Weight) + // Standard Error: 13_000 + .saturating_add((120_105_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1583,265 +1627,265 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (195_980_000 as Weight) - // Standard Error: 1_262_000 - .saturating_add((15_428_805_000 as Weight).saturating_mul(r as Weight)) + (124_760_000 as Weight) + // Standard Error: 1_397_000 + .saturating_add((15_387_180_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (74_569_000 as Weight) - // Standard Error: 1_000 - .saturating_add((589_000 as Weight).saturating_mul(r as Weight)) + (75_287_000 as Weight) + // Standard Error: 11_000 + .saturating_add((569_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_212_000 as Weight) - // Standard Error: 0 - .saturating_add((1_325_000 as Weight).saturating_mul(r as Weight)) + (74_251_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_306_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_505_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_423_000 as Weight).saturating_mul(r as Weight)) + (75_072_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_386_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (74_005_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_785_000 as Weight).saturating_mul(r as Weight)) + (73_811_000 as Weight) + // Standard Error: 0 + .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (74_212_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_890_000 as Weight).saturating_mul(r as Weight)) + (73_901_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_886_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (74_102_000 as Weight) - // Standard Error: 2_000 - .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) + (73_720_000 as Weight) + // Standard Error: 1_000 + .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_523_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_456_000 as Weight).saturating_mul(r as Weight)) + (73_534_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_459_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_307_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_594_000 as Weight).saturating_mul(r as Weight)) + (73_281_000 as Weight) + // Standard Error: 8_000 + .saturating_add((1_584_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_272_000 as Weight) - // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) + (76_135_000 as Weight) + // Standard Error: 1_000 + .saturating_add((6_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (73_390_000 as Weight) + (75_938_000 as Weight) // Standard Error: 23_000 - .saturating_add((16_936_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((17_156_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (89_331_000 as Weight) - // Standard Error: 30_000 - .saturating_add((28_104_000 as Weight).saturating_mul(r as Weight)) + (85_864_000 as Weight) + // Standard Error: 28_000 + .saturating_add((28_343_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (117_023_000 as Weight) - // Standard Error: 3_000 - .saturating_add((914_000 as Weight).saturating_mul(p as Weight)) + (119_795_000 as Weight) + // Standard Error: 1_000 + .saturating_add((911_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (74_727_000 as Weight) + (74_750_000 as Weight) // Standard Error: 1_000 - .saturating_add((618_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((613_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_893_000 as Weight) - // Standard Error: 1_000 - .saturating_add((674_000 as Weight).saturating_mul(r as Weight)) + (74_831_000 as Weight) + // Standard Error: 2_000 + .saturating_add((672_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_552_000 as Weight) + (74_314_000 as Weight) // Standard Error: 1_000 - .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((902_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_355_000 as Weight) + (77_040_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_146_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_161_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (77_055_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + (76_770_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_648_000 as Weight) - // Standard Error: 2_000 - .saturating_add((652_000 as Weight).saturating_mul(r as Weight)) + (74_010_000 as Weight) + // Standard Error: 1_000 + .saturating_add((665_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_777_000 as Weight) - // Standard Error: 226_000 - .saturating_add((187_252_000 as Weight).saturating_mul(r as Weight)) + (73_597_000 as Weight) + // Standard Error: 929_000 + .saturating_add((183_940_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_332_000 as Weight) - // Standard Error: 1_000 - .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) + (74_488_000 as Weight) + // Standard Error: 4_000 + .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_265_000 as Weight) - // Standard Error: 1_000 - .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) + (74_024_000 as Weight) + // Standard Error: 5_000 + .saturating_add((908_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_475_000 as Weight) - // Standard Error: 2_000 - .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) + (74_084_000 as Weight) + // Standard Error: 1_000 + .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_297_000 as Weight) - // Standard Error: 1_000 - .saturating_add((918_000 as Weight).saturating_mul(r as Weight)) + (74_250_000 as Weight) + // Standard Error: 2_000 + .saturating_add((916_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_146_000 as Weight) + (74_027_000 as Weight) // Standard Error: 1_000 - .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((883_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_361_000 as Weight) + (74_201_000 as Weight) // Standard Error: 1_000 - .saturating_add((877_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((879_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_554_000 as Weight) + (74_116_000 as Weight) // Standard Error: 1_000 - .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (74_169_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (74_109_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (74_164_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (73_962_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (74_058_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (73_977_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_039_000 as Weight) + (74_046_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (75_055_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (73_912_000 as Weight) + // Standard Error: 0 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (74_536_000 as Weight) - // Standard Error: 4_000 + (73_918_000 as Weight) + // Standard Error: 2_000 .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (74_177_000 as Weight) + (73_953_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_080_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + (74_855_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (74_237_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + (73_917_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_364_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_049_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (73_949_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (74_186_000 as Weight) + (73_726_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_268_000 as Weight) + (73_921_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (74_334_000 as Weight) + (73_924_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_331_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (74_285_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_997_000 as Weight).saturating_mul(r as Weight)) + (73_842_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_011_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (74_002_000 as Weight) + (73_932_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_027_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_057_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (74_281_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_977_000 as Weight).saturating_mul(r as Weight)) + (74_028_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_001_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (74_160_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_038_000 as Weight).saturating_mul(r as Weight)) + (73_784_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_059_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_097_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) + (74_169_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_334_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (74_020_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) + (73_982_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (73_890_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) + (74_310_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_329_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (74_139_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (73_861_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (74_189_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (73_787_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_364_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (74_055_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) + (73_886_000 as Weight) + // Standard Error: 7_000 + .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (74_074_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (73_860_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (74_005_000 as Weight) + (73_917_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } } From 36c38fb26b362ee0666d655ad5d6ad7279ba7e07 Mon Sep 17 00:00:00 2001 From: girazoki Date: Sat, 5 Feb 2022 12:06:44 +0100 Subject: [PATCH 0486/1472] maybe_total_supply in pallet-assets (#10799) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * maybe_total_supply in pallet-assets * Update frame/assets/src/functions.rs Co-authored-by: Bastian Köcher --- frame/assets/src/functions.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index e02cc7c8bb213..73804fc832c99 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -55,7 +55,12 @@ impl, I: 'static> Pallet { /// Get the total supply of an asset `id`. pub fn total_supply(id: T::AssetId) -> T::Balance { - Asset::::get(id).map(|x| x.supply).unwrap_or_else(Zero::zero) + Self::maybe_total_supply(id).unwrap_or_default() + } + + /// Get the total supply of an asset `id` if the asset exists. + pub fn maybe_total_supply(id: T::AssetId) -> Option { + Asset::::get(id).map(|x| x.supply) } pub(super) fn new_account( From 7e643ceabf11858cd3c059579ab45794793f2a78 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sun, 6 Feb 2022 12:51:12 +0100 Subject: [PATCH 0487/1472] Referenda and Conviction Voting pallets (#10195) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial draft of new referendum state machine. * Docs * Fixes * Fixes * Add conviction-voting pallet * Basic build * Building * Some TODOs * Tests building * Add missing file * Basic lifecycle test * Add couple of tests * Another test * More tests * Fixes * Fixes * Formatting * Fixes * Tests * Fixes * Fixes * More tests * Formatting * First few benchmarks * First few benchmarks * Defered queue servicing * More testing * Benchmarks * Fiddly benchmark * Final nudge benchmarks * Formatting * Formatting * Finished up benchmarks * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_referenda --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/referenda/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Events finished * Missing file * No GenesisConfig for Referenda * Formatting * Docs * Docs * Docs * Per-class conviction voting * New test & mock utils * More tests * Tests * Tests finished 🎉 * Benchmarking stuff * Fixes * Test harness * Test harness * Benchmarks for Conviction=Voting * Benchmarking pipeline complete * Docs * Formatting * Remove unneeded warning * Fix UI tests * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_conviction_voting --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/conviction-voting/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Docs * Update frame/conviction-voting/src/vote.rs Co-authored-by: Shawn Tabrizi * update sp-runtime version * MEL Fixes for Referenda and Conviction Voting (#10725) * free maxencodedlen * more maxencodedlen * more MEL * more mel * disable storage info * More Referenda Patches (#10760) * basic fixes * fix benchmarking * fix license * prevent panic in curve math * fmt * bump crate versions * Update mock.rs Co-authored-by: Parity Bot Co-authored-by: Shawn Tabrizi --- Cargo.lock | 41 + Cargo.toml | 8 +- bin/node/runtime/Cargo.toml | 32 +- bin/node/runtime/src/lib.rs | 81 ++ frame/balances/src/lib.rs | 2 +- frame/conviction-voting/Cargo.toml | 53 + frame/conviction-voting/README.md | 8 + frame/conviction-voting/src/benchmarking.rs | 278 +++++ frame/conviction-voting/src/conviction.rs | 131 +++ frame/conviction-voting/src/lib.rs | 632 +++++++++++ frame/conviction-voting/src/tests.rs | 820 ++++++++++++++ frame/conviction-voting/src/types.rs | 236 ++++ frame/conviction-voting/src/vote.rs | 254 +++++ frame/conviction-voting/src/weights.rs | 201 ++++ frame/democracy/src/lib.rs | 8 - frame/referenda/Cargo.toml | 56 + frame/referenda/README.md | 8 + frame/referenda/src/benchmarking.rs | 520 +++++++++ frame/referenda/src/branch.rs | 172 +++ frame/referenda/src/lib.rs | 1065 +++++++++++++++++++ frame/referenda/src/mock.rs | 460 ++++++++ frame/referenda/src/tests.rs | 511 +++++++++ frame/referenda/src/types.rs | 358 +++++++ frame/referenda/src/weights.rs | 491 +++++++++ frame/scheduler/src/lib.rs | 14 - frame/support/src/dispatch.rs | 50 +- frame/support/src/traits.rs | 6 +- frame/support/src/traits/dispatch.rs | 9 +- frame/support/src/traits/schedule.rs | 4 +- frame/support/src/traits/tokens/currency.rs | 14 +- frame/support/src/traits/voting.rs | 80 +- frame/support/test/tests/system.rs | 18 +- frame/system/src/lib.rs | 25 +- test-utils/runtime/src/lib.rs | 2 +- 34 files changed, 6542 insertions(+), 106 deletions(-) create mode 100644 frame/conviction-voting/Cargo.toml create mode 100644 frame/conviction-voting/README.md create mode 100644 frame/conviction-voting/src/benchmarking.rs create mode 100644 frame/conviction-voting/src/conviction.rs create mode 100644 frame/conviction-voting/src/lib.rs create mode 100644 frame/conviction-voting/src/tests.rs create mode 100644 frame/conviction-voting/src/types.rs create mode 100644 frame/conviction-voting/src/vote.rs create mode 100644 frame/conviction-voting/src/weights.rs create mode 100644 frame/referenda/Cargo.toml create mode 100644 frame/referenda/README.md create mode 100644 frame/referenda/src/benchmarking.rs create mode 100644 frame/referenda/src/branch.rs create mode 100644 frame/referenda/src/lib.rs create mode 100644 frame/referenda/src/mock.rs create mode 100644 frame/referenda/src/tests.rs create mode 100644 frame/referenda/src/types.rs create mode 100644 frame/referenda/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 2e254e7d11843..45158288298b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4871,6 +4871,7 @@ dependencies = [ "pallet-contracts", "pallet-contracts-primitives", "pallet-contracts-rpc-runtime-api", + "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", "pallet-elections-phragmen", @@ -4889,6 +4890,7 @@ dependencies = [ "pallet-proxy", "pallet-randomness-collective-flip", "pallet-recovery", + "pallet-referenda", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", @@ -5672,6 +5674,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-conviction-voting" +version = "4.0.0-dev" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-scheduler", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-democracy" version = "4.0.0-dev" @@ -6122,6 +6143,26 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-referenda" +version = "4.0.0-dev" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-preimage", + "pallet-scheduler", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-scheduler" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 48a36419eb746..a31d8011a9f44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,9 @@ members = [ "frame/authority-discovery", "frame/authorship", "frame/babe", + "frame/bags-list", + "frame/bags-list/fuzzer", + "frame/bags-list/remote-tests", "frame/balances", "frame/beefy", "frame/beefy-mmr", @@ -78,6 +81,7 @@ members = [ "frame/contracts", "frame/contracts/rpc", "frame/contracts/rpc/runtime-api", + "frame/conviction-voting", "frame/democracy", "frame/try-runtime", "frame/election-provider-multi-phase", @@ -104,6 +108,7 @@ members = [ "frame/proxy", "frame/randomness-collective-flip", "frame/recovery", + "frame/referenda", "frame/scheduler", "frame/scored-pool", "frame/session", @@ -133,9 +138,6 @@ members = [ "frame/uniques", "frame/utility", "frame/vesting", - "frame/bags-list", - "frame/bags-list/remote-tests", - "frame/bags-list/fuzzer", "primitives/api", "primitives/api/proc-macro", "primitives/api/test", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 647562caff30c..2aad40b4f121d 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -64,6 +64,7 @@ pallet-collective = { version = "4.0.0-dev", default-features = false, path = ". pallet-contracts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts" } pallet-contracts-primitives = { version = "5.0.0", default-features = false, path = "../../../frame/contracts/common/" } pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/rpc/runtime-api/" } +pallet-conviction-voting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/conviction-voting" } pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" } pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" } pallet-elections-phragmen = { version = "5.0.0-dev", default-features = false, path = "../../../frame/elections-phragmen" } @@ -82,9 +83,8 @@ pallet-preimage = { version = "4.0.0-dev", default-features = false, path = "../ pallet-proxy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/proxy" } pallet-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/randomness-collective-flip" } pallet-recovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/recovery" } -pallet-session = { version = "4.0.0-dev", features = [ - "historical", -], path = "../../../frame/session", default-features = false } +pallet-referenda = { version = "4.0.0-dev", default-features = false, path = "../../../frame/referenda" } +pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = "../../../frame/session", default-features = false } pallet-session-benchmarking = { version = "4.0.0-dev", path = "../../../frame/session/benchmarking", default-features = false, optional = true } pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking/reward-curve" } @@ -125,6 +125,7 @@ std = [ "pallet-contracts/std", "pallet-contracts-primitives/std", "pallet-contracts-rpc-runtime-api/std", + "pallet-conviction-voting/std", "pallet-democracy/std", "pallet-elections-phragmen/std", "frame-executive/std", @@ -170,6 +171,7 @@ std = [ "pallet-utility/std", "sp-version/std", "pallet-society/std", + "pallet-referenda/std", "pallet-recovery/std", "pallet-uniques/std", "pallet-vesting/std", @@ -183,7 +185,6 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-election-provider-multi-phase/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-babe/runtime-benchmarks", @@ -193,7 +194,9 @@ runtime-benchmarks = [ "pallet-child-bounties/runtime-benchmarks", "pallet-collective/runtime-benchmarks", "pallet-contracts/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", + "pallet-election-provider-multi-phase/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", "pallet-gilt/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", @@ -204,9 +207,12 @@ runtime-benchmarks = [ "pallet-membership/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-offences-benchmarking", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-session-benchmarking", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", @@ -216,8 +222,6 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", - "pallet-offences-benchmarking", - "pallet-session-benchmarking", "frame-system-benchmarking", "hex-literal", ] @@ -234,35 +238,37 @@ try-runtime = [ "pallet-child-bounties/try-runtime", "pallet-collective/try-runtime", "pallet-contracts/try-runtime", + "pallet-conviction-voting/try-runtime", "pallet-democracy/try-runtime", + "pallet-election-provider-multi-phase/try-runtime", "pallet-elections-phragmen/try-runtime", + "pallet-gilt/try-runtime", "pallet-grandpa/try-runtime", + "pallet-identity/try-runtime", "pallet-im-online/try-runtime", "pallet-indices/try-runtime", "pallet-lottery/try-runtime", "pallet-membership/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", - "pallet-identity/try-runtime", - "pallet-scheduler/try-runtime", "pallet-offences/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", "pallet-randomness-collective-flip/try-runtime", + "pallet-recovery/try-runtime", + "pallet-referenda/try-runtime", + "pallet-scheduler/try-runtime", "pallet-session/try-runtime", + "pallet-society/try-runtime", "pallet-staking/try-runtime", "pallet-sudo/try-runtime", - "pallet-election-provider-multi-phase/try-runtime", "pallet-timestamp/try-runtime", "pallet-tips/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-treasury/try-runtime", - "pallet-utility/try-runtime", - "pallet-society/try-runtime", - "pallet-recovery/try-runtime", "pallet-uniques/try-runtime", + "pallet-utility/try-runtime", "pallet-vesting/try-runtime", - "pallet-gilt/try-runtime", ] # Make contract callable functions marked as __unstable__ available. Do not enable # on live chains as those are subject to change. diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index e70adc6aa7238..0a13b795919c0 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -698,6 +698,83 @@ impl pallet_bags_list::Config for Runtime { type BagThresholds = BagThresholds; } +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = 30 * DAYS; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = pallet_conviction_voting::weights::SubstrateWeight; + type Event = Event; + type Currency = Balances; + type VoteLockingPeriod = VoteLockingPeriod; + type MaxVotes = ConstU32<512>; + type MaxTurnout = frame_support::traits::TotalIssuanceOf; + type Polls = Referenda; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 100 * DOLLARS; + pub const UndecidingTimeout: BlockNumber = 28 * DAYS; +} + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u8; + type Origin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + static DATA: [(u8, pallet_referenda::TrackInfo); 1] = [( + 0u8, + pallet_referenda::TrackInfo { + name: "root", + max_deciding: 1, + decision_deposit: 10, + prepare_period: 4, + decision_period: 4, + confirm_period: 2, + min_enactment_period: 4, + min_approval: pallet_referenda::Curve::LinearDecreasing { + begin: Perbill::from_percent(100), + delta: Perbill::from_percent(50), + }, + min_turnout: pallet_referenda::Curve::LinearDecreasing { + begin: Perbill::from_percent(100), + delta: Perbill::from_percent(100), + }, + }, + )]; + &DATA[..] + } + fn track_for(id: &Self::Origin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => Ok(0), + _ => Err(()), + } + } else { + Err(()) + } + } +} + +impl pallet_referenda::Config for Runtime { + type WeightInfo = pallet_referenda::weights::SubstrateWeight; + type Call = Call; + type Event = Event; + type Scheduler = Scheduler; + type Currency = pallet_balances::Pallet; + type CancelOrigin = EnsureRoot; + type KillOrigin = EnsureRoot; + type Slash = (); + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; +} + parameter_types! { pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; pub const VotingPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; @@ -1336,6 +1413,8 @@ construct_runtime!( TransactionStorage: pallet_transaction_storage, BagsList: pallet_bags_list, ChildBounties: pallet_child_bounties, + Referenda: pallet_referenda, + ConvictionVoting: pallet_conviction_voting, } ); @@ -1405,6 +1484,7 @@ mod benches { [pallet_bounties, Bounties] [pallet_child_bounties, ChildBounties] [pallet_collective, Council] + [pallet_conviction_voting, ConvictionVoting] [pallet_contracts, Contracts] [pallet_democracy, Democracy] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] @@ -1421,6 +1501,7 @@ mod benches { [pallet_offences, OffencesBench::] [pallet_preimage, Preimage] [pallet_proxy, Proxy] + [pallet_referenda, Referenda] [pallet_scheduler, Scheduler] [pallet_session, SessionBench::] [pallet_staking, Staking] diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 80e8bf577abe6..37114f385aa7f 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -1517,7 +1517,7 @@ where .map_err(|_| Error::::LiquidityRestrictions)?; // TODO: This is over-conservative. There may now be other providers, and - // this pallet may not even be a provider. + // this pallet may not even be a provider. let allow_death = existence_requirement == ExistenceRequirement::AllowDeath; let allow_death = allow_death && system::Pallet::::can_dec_provider(transactor); diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml new file mode 100644 index 0000000000000..ab62065c1c546 --- /dev/null +++ b/frame/conviction-voting/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "pallet-conviction-voting" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet for conviction voting in referenda" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +serde = { version = "1.0.126", optional = true, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ + "derive", +] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +assert_matches = "1.3.0" + +[dev-dependencies] +sp-core = { version = "5.0.0", path = "../../primitives/core" } +pallet-balances = { version = "4.0.0-dev", path = "../balances" } +pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } + +[features] +default = ["std"] +std = [ + "serde", + "codec/std", + "scale-info/std", + "sp-std/std", + "sp-io/std", + "frame-benchmarking/std", + "frame-support/std", + "sp-runtime/std", + "frame-system/std", +] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-system/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/conviction-voting/README.md b/frame/conviction-voting/README.md new file mode 100644 index 0000000000000..5dc5d526d5c23 --- /dev/null +++ b/frame/conviction-voting/README.md @@ -0,0 +1,8 @@ +# Voting Pallet + +- [`assembly::Config`](https://docs.rs/pallet-assembly/latest/pallet_assembly/trait.Config.html) +- [`Call`](https://docs.rs/pallet-assembly/latest/pallet_assembly/enum.Call.html) + +## Overview + +Pallet for voting in referenda. diff --git a/frame/conviction-voting/src/benchmarking.rs b/frame/conviction-voting/src/benchmarking.rs new file mode 100644 index 0000000000000..2beee4f3b49d2 --- /dev/null +++ b/frame/conviction-voting/src/benchmarking.rs @@ -0,0 +1,278 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! ConvictionVoting pallet benchmarking. + +use super::*; + +use assert_matches::assert_matches; +use frame_benchmarking::{account, benchmarks, whitelist_account}; +use frame_support::{ + dispatch::RawOrigin, + traits::{fungible, Currency, Get}, +}; +use sp_runtime::traits::Bounded; +use sp_std::collections::btree_map::BTreeMap; + +use crate::Pallet as ConvictionVoting; + +const SEED: u32 = 0; + +/// Fill all classes as much as possible up to `MaxVotes` and return the Class with the most votes +/// ongoing. +fn fill_voting() -> (ClassOf, BTreeMap, Vec>>) { + let mut r = BTreeMap::, Vec>>::new(); + for class in T::Polls::classes().into_iter() { + for _ in 0..T::MaxVotes::get() { + match T::Polls::create_ongoing(class.clone()) { + Ok(i) => r.entry(class.clone()).or_default().push(i), + Err(()) => break, + } + } + } + let c = r.iter().max_by_key(|(_, ref v)| v.len()).unwrap().0.clone(); + (c, r) +} + +fn funded_account(name: &'static str, index: u32) -> T::AccountId { + let caller: T::AccountId = account(name, index, SEED); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + caller +} + +fn account_vote(b: BalanceOf) -> AccountVote> { + let v = Vote { aye: true, conviction: Conviction::Locked1x }; + + AccountVote::Standard { vote: v, balance: b } +} + +benchmarks! { + where_clause { where T::MaxVotes: core::fmt::Debug } + + vote_new { + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + let account_vote = account_vote::(100u32.into()); + + let (class, all_polls) = fill_voting::(); + let polls = &all_polls[&class]; + let r = polls.len() - 1; + // We need to create existing votes + for i in polls.iter().skip(1) { + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, account_vote.clone())?; + } + let votes = match VotingFor::::get(&caller, &class) { + Voting::Casting(Casting { votes, .. }) => votes, + _ => return Err("Votes are not direct".into()), + }; + assert_eq!(votes.len(), r as usize, "Votes were not recorded."); + + let index = polls[0]; + }: vote(RawOrigin::Signed(caller.clone()), index, account_vote) + verify { + assert_matches!( + VotingFor::::get(&caller, &class), + Voting::Casting(Casting { votes, .. }) if votes.len() == (r + 1) as usize + ); + } + + vote_existing { + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + let old_account_vote = account_vote::(100u32.into()); + + let (class, all_polls) = fill_voting::(); + let polls = &all_polls[&class]; + let r = polls.len(); + // We need to create existing votes + for i in polls.iter() { + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote.clone())?; + } + let votes = match VotingFor::::get(&caller, &class) { + Voting::Casting(Casting { votes, .. }) => votes, + _ => return Err("Votes are not direct".into()), + }; + assert_eq!(votes.len(), r, "Votes were not recorded."); + + let new_account_vote = account_vote::(200u32.into()); + let index = polls[0]; + }: vote(RawOrigin::Signed(caller.clone()), index, new_account_vote) + verify { + assert_matches!( + VotingFor::::get(&caller, &class), + Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize + ); + } + + remove_vote { + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + let old_account_vote = account_vote::(100u32.into()); + + let (class, all_polls) = fill_voting::(); + let polls = &all_polls[&class]; + let r = polls.len(); + // We need to create existing votes + for i in polls.iter() { + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote.clone())?; + } + let votes = match VotingFor::::get(&caller, &class) { + Voting::Casting(Casting { votes, .. }) => votes, + _ => return Err("Votes are not direct".into()), + }; + assert_eq!(votes.len(), r, "Votes were not recorded."); + + let index = polls[0]; + }: _(RawOrigin::Signed(caller.clone()), Some(class.clone()), index) + verify { + assert_matches!( + VotingFor::::get(&caller, &class), + Voting::Casting(Casting { votes, .. }) if votes.len() == (r - 1) as usize + ); + } + + remove_other_vote { + let caller = funded_account::("caller", 0); + let voter = funded_account::("caller", 0); + whitelist_account!(caller); + let old_account_vote = account_vote::(100u32.into()); + + let (class, all_polls) = fill_voting::(); + let polls = &all_polls[&class]; + let r = polls.len(); + // We need to create existing votes + for i in polls.iter() { + ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, old_account_vote.clone())?; + } + let votes = match VotingFor::::get(&caller, &class) { + Voting::Casting(Casting { votes, .. }) => votes, + _ => return Err("Votes are not direct".into()), + }; + assert_eq!(votes.len(), r, "Votes were not recorded."); + + let index = polls[0]; + assert!(T::Polls::end_ongoing(index, false).is_ok()); + }: _(RawOrigin::Signed(caller.clone()), voter.clone(), class.clone(), index) + verify { + assert_matches!( + VotingFor::::get(&voter, &class), + Voting::Casting(Casting { votes, .. }) if votes.len() == (r - 1) as usize + ); + } + + delegate { + let r in 0 .. T::MaxVotes::get().min(T::Polls::max_ongoing().1); + + let all_polls = fill_voting::().1; + let class = T::Polls::max_ongoing().0; + let polls = &all_polls[&class]; + let voter = funded_account::("voter", 0); + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + + let delegated_balance: BalanceOf = 1000u32.into(); + let delegate_vote = account_vote::(delegated_balance); + + // We need to create existing delegations + for i in polls.iter().take(r as usize) { + ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote.clone())?; + } + assert_matches!( + VotingFor::::get(&voter, &class), + Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize + ); + + }: _(RawOrigin::Signed(caller.clone()), class.clone(), voter.clone(), Conviction::Locked1x, delegated_balance) + verify { + assert_matches!(VotingFor::::get(&caller, &class), Voting::Delegating(_)); + } + + undelegate { + let r in 0 .. T::MaxVotes::get().min(T::Polls::max_ongoing().1); + + let all_polls = fill_voting::().1; + let class = T::Polls::max_ongoing().0; + let polls = &all_polls[&class]; + let voter = funded_account::("voter", 0); + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + + let delegated_balance: BalanceOf = 1000u32.into(); + let delegate_vote = account_vote::(delegated_balance); + + ConvictionVoting::::delegate( + RawOrigin::Signed(caller.clone()).into(), + class.clone(), + voter.clone(), + Conviction::Locked1x, + delegated_balance, + )?; + + // We need to create delegations + for i in polls.iter().take(r as usize) { + ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote.clone())?; + } + assert_matches!( + VotingFor::::get(&voter, &class), + Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize + ); + assert_matches!(VotingFor::::get(&caller, &class), Voting::Delegating(_)); + }: _(RawOrigin::Signed(caller.clone()), class.clone()) + verify { + assert_matches!(VotingFor::::get(&caller, &class), Voting::Casting(_)); + } + + unlock { + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + let normal_account_vote = account_vote::(T::Currency::free_balance(&caller) - 100u32.into()); + let big_account_vote = account_vote::(T::Currency::free_balance(&caller)); + + // Fill everything up to the max by filling all classes with votes and voting on them all. + let (class, all_polls) = fill_voting::(); + assert!(all_polls.len() > 0); + for (class, polls) in all_polls.iter() { + assert!(polls.len() > 0); + for i in polls.iter() { + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, normal_account_vote.clone())?; + } + } + + let orig_usable = >::reducible_balance(&caller, false); + let polls = &all_polls[&class]; + + // Vote big on the class with the most ongoing votes of them to bump the lock and make it + // hard to recompute when removed. + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), polls[0], big_account_vote.clone())?; + let now_usable = >::reducible_balance(&caller, false); + assert_eq!(orig_usable - now_usable, 100u32.into()); + + // Remove the vote + ConvictionVoting::::remove_vote(RawOrigin::Signed(caller.clone()).into(), Some(class.clone()), polls[0])?; + + // We can now unlock on `class` from 200 to 100... + }: _(RawOrigin::Signed(caller.clone()), class, caller.clone()) + verify { + assert_eq!(orig_usable, >::reducible_balance(&caller, false)); + } + + impl_benchmark_test_suite!( + ConvictionVoting, + crate::tests::new_test_ext(), + crate::tests::Test + ); +} diff --git a/frame/conviction-voting/src/conviction.rs b/frame/conviction-voting/src/conviction.rs new file mode 100644 index 0000000000000..129f2771124b5 --- /dev/null +++ b/frame/conviction-voting/src/conviction.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The conviction datatype. + +use crate::types::Delegations; +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{Bounded, CheckedDiv, CheckedMul, Zero}, + RuntimeDebug, +}; +use sp_std::{convert::TryFrom, result::Result}; + +/// A value denoting the strength of conviction of a vote. +#[derive( + Encode, + Decode, + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + RuntimeDebug, + TypeInfo, + MaxEncodedLen, +)] +pub enum Conviction { + /// 0.1x votes, unlocked. + None, + /// 1x votes, locked for an enactment period following a successful vote. + Locked1x, + /// 2x votes, locked for 2x enactment periods following a successful vote. + Locked2x, + /// 3x votes, locked for 4x... + Locked3x, + /// 4x votes, locked for 8x... + Locked4x, + /// 5x votes, locked for 16x... + Locked5x, + /// 6x votes, locked for 32x... + Locked6x, +} + +impl Default for Conviction { + fn default() -> Self { + Conviction::None + } +} + +impl From for u8 { + fn from(c: Conviction) -> u8 { + match c { + Conviction::None => 0, + Conviction::Locked1x => 1, + Conviction::Locked2x => 2, + Conviction::Locked3x => 3, + Conviction::Locked4x => 4, + Conviction::Locked5x => 5, + Conviction::Locked6x => 6, + } + } +} + +impl TryFrom for Conviction { + type Error = (); + fn try_from(i: u8) -> Result { + Ok(match i { + 0 => Conviction::None, + 1 => Conviction::Locked1x, + 2 => Conviction::Locked2x, + 3 => Conviction::Locked3x, + 4 => Conviction::Locked4x, + 5 => Conviction::Locked5x, + 6 => Conviction::Locked6x, + _ => return Err(()), + }) + } +} + +impl Conviction { + /// The amount of time (in number of periods) that our conviction implies a successful voter's + /// balance should be locked for. + pub fn lock_periods(self) -> u32 { + match self { + Conviction::None => 0, + Conviction::Locked1x => 1, + Conviction::Locked2x => 2, + Conviction::Locked3x => 4, + Conviction::Locked4x => 8, + Conviction::Locked5x => 16, + Conviction::Locked6x => 32, + } + } + + /// The votes of a voter of the given `balance` with our conviction. + pub fn votes + Zero + Copy + CheckedMul + CheckedDiv + Bounded>( + self, + capital: B, + ) -> Delegations { + let votes = match self { + Conviction::None => capital.checked_div(&10u8.into()).unwrap_or_else(Zero::zero), + x => capital.checked_mul(&u8::from(x).into()).unwrap_or_else(B::max_value), + }; + Delegations { votes, capital } + } +} + +impl Bounded for Conviction { + fn min_value() -> Self { + Conviction::None + } + fn max_value() -> Self { + Conviction::Locked6x + } +} diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs new file mode 100644 index 0000000000000..8e7e0d91b1cf4 --- /dev/null +++ b/frame/conviction-voting/src/lib.rs @@ -0,0 +1,632 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Voting Pallet +//! +//! - [`Config`] +//! - [`Call`] +//! +//! ## Overview +//! +//! Pallet for managing actual voting in polls. + +#![recursion_limit = "256"] +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::{ + ensure, + traits::{ + fungible, Currency, Get, LockIdentifier, LockableCurrency, PollStatus, Polling, + ReservableCurrency, WithdrawReasons, + }, +}; +use sp_runtime::{ + traits::{AtLeast32BitUnsigned, Saturating, Zero}, + ArithmeticError, DispatchError, DispatchResult, Perbill, +}; +use sp_std::prelude::*; + +mod conviction; +mod types; +mod vote; +pub mod weights; +pub use conviction::Conviction; +pub use pallet::*; +pub use types::{Delegations, Tally, UnvoteScope}; +pub use vote::{AccountVote, Casting, Delegating, Vote, Voting}; +pub use weights::WeightInfo; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +const CONVICTION_VOTING_ID: LockIdentifier = *b"pyconvot"; + +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; +type VotingOf = Voting< + BalanceOf, + ::AccountId, + ::BlockNumber, + PollIndexOf, + ::MaxVotes, +>; +#[allow(dead_code)] +type DelegatingOf = Delegating< + BalanceOf, + ::AccountId, + ::BlockNumber, +>; +pub type TallyOf = Tally, ::MaxTurnout>; +pub type VotesOf = BalanceOf; +type PollIndexOf = <::Polls as Polling>>::Index; +#[cfg(feature = "runtime-benchmarks")] +type IndexOf = <::Polls as Polling>>::Index; +type ClassOf = <::Polls as Polling>>::Class; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use sp_runtime::DispatchResult; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + Sized { + // System level stuff. + type Event: From> + IsType<::Event>; + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + /// Currency type with which voting happens. + type Currency: ReservableCurrency + + LockableCurrency + + fungible::Inspect; + + /// The implementation of the logic which conducts polls. + type Polls: Polling, Votes = BalanceOf, Moment = Self::BlockNumber>; + + /// The maximum amount of tokens which may be used for voting. May just be + /// `Currency::total_issuance`, but you might want to reduce this in order to account for + /// funds in the system which are unable to vote (e.g. parachain auction deposits). + type MaxTurnout: Get>; + + /// The maximum number of concurrent votes an account may have. + /// + /// Also used to compute weight, an overly large value can + /// lead to extrinsic with large weight estimation: see `delegate` for instance. + #[pallet::constant] + type MaxVotes: Get; + + /// The minimum period of vote locking. + /// + /// It should be no shorter than enactment period to ensure that in the case of an approval, + /// those successful voters are locked into the consequences that their votes entail. + #[pallet::constant] + type VoteLockingPeriod: Get; + } + + /// All voting for a particular voter in a particular voting class. We store the balance for the + /// number of votes that we have recorded. + #[pallet::storage] + pub type VotingFor = StorageDoubleMap< + _, + Twox64Concat, + T::AccountId, + Twox64Concat, + ClassOf, + VotingOf, + ValueQuery, + >; + + /// The voting classes which have a non-zero lock requirement and the lock amounts which they + /// require. The actual amount locked on behalf of this pallet should always be the maximum of + /// this list. + #[pallet::storage] + pub type ClassLocksFor = + StorageMap<_, Twox64Concat, T::AccountId, Vec<(ClassOf, BalanceOf)>, ValueQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// An account has delegated their vote to another account. \[who, target\] + Delegated(T::AccountId, T::AccountId), + /// An \[account\] has cancelled a previous delegation operation. + Undelegated(T::AccountId), + } + + #[pallet::error] + pub enum Error { + /// Poll is not ongoing. + NotOngoing, + /// The given account did not vote on the poll. + NotVoter, + /// The actor has no permission to conduct the action. + NoPermission, + /// The actor has no permission to conduct the action right now but will do in the future. + NoPermissionYet, + /// The account is already delegating. + AlreadyDelegating, + /// The account currently has votes attached to it and the operation cannot succeed until + /// these are removed, either through `unvote` or `reap_vote`. + AlreadyVoting, + /// Too high a balance was provided that the account cannot afford. + InsufficientFunds, + /// The account is not currently delegating. + NotDelegating, + /// Delegation to oneself makes no sense. + Nonsense, + /// Maximum number of votes reached. + MaxVotesReached, + /// The class must be supplied since it is not easily determinable from the state. + ClassNeeded, + /// The class ID supplied is invalid. + BadClass, + } + + #[pallet::call] + impl Pallet { + /// Vote in a poll. If `vote.is_aye()`, the vote is to enact the proposal; + /// otherwise it is a vote to keep the status quo. + /// + /// The dispatch origin of this call must be _Signed_. + /// + /// - `poll_index`: The index of the poll to vote for. + /// - `vote`: The vote configuration. + /// + /// Weight: `O(R)` where R is the number of polls the voter has voted on. + #[pallet::weight(T::WeightInfo::vote_new().max(T::WeightInfo::vote_existing()))] + pub fn vote( + origin: OriginFor, + #[pallet::compact] poll_index: PollIndexOf, + vote: AccountVote>, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::try_vote(&who, poll_index, vote) + } + + /// Delegate the voting power (with some given conviction) of the sending account for a + /// particular class of polls. + /// + /// The balance delegated is locked for as long as it's delegated, and thereafter for the + /// time appropriate for the conviction's lock period. + /// + /// The dispatch origin of this call must be _Signed_, and the signing account must either: + /// - be delegating already; or + /// - have no voting activity (if there is, then it will need to be removed/consolidated + /// through `reap_vote` or `unvote`). + /// + /// - `to`: The account whose voting the `target` account's voting power will follow. + /// - `class`: The class of polls to delegate. To delegate multiple classes, multiple calls + /// to this function are required. + /// - `conviction`: The conviction that will be attached to the delegated votes. When the + /// account is undelegated, the funds will be locked for the corresponding period. + /// - `balance`: The amount of the account's balance to be used in delegating. This must not + /// be more than the account's current balance. + /// + /// Emits `Delegated`. + /// + /// Weight: `O(R)` where R is the number of polls the voter delegating to has + /// voted on. Weight is initially charged as if maximum votes, but is refunded later. + // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure + // because a valid delegation cover decoding a direct voting with max votes. + #[pallet::weight(T::WeightInfo::delegate(T::MaxVotes::get()))] + pub fn delegate( + origin: OriginFor, + class: ClassOf, + to: T::AccountId, + conviction: Conviction, + balance: BalanceOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + let votes = Self::try_delegate(who, class, to, conviction, balance)?; + + Ok(Some(T::WeightInfo::delegate(votes)).into()) + } + + /// Undelegate the voting power of the sending account for a particular class of polls. + /// + /// Tokens may be unlocked following once an amount of time consistent with the lock period + /// of the conviction with which the delegation was issued. + /// + /// The dispatch origin of this call must be _Signed_ and the signing account must be + /// currently delegating. + /// + /// - `class`: The class of polls to remove the delegation from. + /// + /// Emits `Undelegated`. + /// + /// Weight: `O(R)` where R is the number of polls the voter delegating to has + /// voted on. Weight is initially charged as if maximum votes, but is refunded later. + // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure + // because a valid delegation cover decoding a direct voting with max votes. + #[pallet::weight(T::WeightInfo::undelegate(T::MaxVotes::get().into()))] + pub fn undelegate(origin: OriginFor, class: ClassOf) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + let votes = Self::try_undelegate(who, class)?; + Ok(Some(T::WeightInfo::undelegate(votes)).into()) + } + + /// Remove the lock caused prior voting/delegating which has expired within a particluar + /// class. + /// + /// The dispatch origin of this call must be _Signed_. + /// + /// - `class`: The class of polls to unlock. + /// - `target`: The account to remove the lock on. + /// + /// Weight: `O(R)` with R number of vote of target. + #[pallet::weight(T::WeightInfo::unlock())] + pub fn unlock( + origin: OriginFor, + class: ClassOf, + target: T::AccountId, + ) -> DispatchResult { + ensure_signed(origin)?; + Self::update_lock(&class, &target); + Ok(()) + } + + /// Remove a vote for a poll. + /// + /// If: + /// - the poll was cancelled, or + /// - the poll is ongoing, or + /// - the poll has ended such that + /// - the vote of the account was in opposition to the result; or + /// - there was no conviction to the account's vote; or + /// - the account made a split vote + /// ...then the vote is removed cleanly and a following call to `unlock` may result in more + /// funds being available. + /// + /// If, however, the poll has ended and: + /// - it finished corresponding to the vote of the account, and + /// - the account made a standard vote with conviction, and + /// - the lock period of the conviction is not over + /// ...then the lock will be aggregated into the overall account's lock, which may involve + /// *overlocking* (where the two locks are combined into a single lock that is the maximum + /// of both the amount locked and the time is it locked for). + /// + /// The dispatch origin of this call must be _Signed_, and the signer must have a vote + /// registered for poll `index`. + /// + /// - `index`: The index of poll of the vote to be removed. + /// - `class`: Optional parameter, if given it indicates the class of the poll. For polls + /// which have finished or are cancelled, this must be `Some`. + /// + /// Weight: `O(R + log R)` where R is the number of polls that `target` has voted on. + /// Weight is calculated for the maximum number of vote. + #[pallet::weight(T::WeightInfo::remove_vote())] + pub fn remove_vote( + origin: OriginFor, + class: Option>, + index: PollIndexOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::try_remove_vote(&who, index, class, UnvoteScope::Any) + } + + /// Remove a vote for a poll. + /// + /// If the `target` is equal to the signer, then this function is exactly equivalent to + /// `remove_vote`. If not equal to the signer, then the vote must have expired, + /// either because the poll was cancelled, because the voter lost the poll or + /// because the conviction period is over. + /// + /// The dispatch origin of this call must be _Signed_. + /// + /// - `target`: The account of the vote to be removed; this account must have voted for poll + /// `index`. + /// - `index`: The index of poll of the vote to be removed. + /// - `class`: The class of the poll. + /// + /// Weight: `O(R + log R)` where R is the number of polls that `target` has voted on. + /// Weight is calculated for the maximum number of vote. + #[pallet::weight(T::WeightInfo::remove_other_vote())] + pub fn remove_other_vote( + origin: OriginFor, + target: T::AccountId, + class: ClassOf, + index: PollIndexOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let scope = if target == who { UnvoteScope::Any } else { UnvoteScope::OnlyExpired }; + Self::try_remove_vote(&target, index, Some(class), scope)?; + Ok(()) + } + } +} + +impl Pallet { + /// Actually enact a vote, if legit. + fn try_vote( + who: &T::AccountId, + poll_index: PollIndexOf, + vote: AccountVote>, + ) -> DispatchResult { + ensure!(vote.balance() <= T::Currency::free_balance(who), Error::::InsufficientFunds); + T::Polls::try_access_poll(poll_index, |poll_status| { + let (tally, class) = poll_status.ensure_ongoing().ok_or(Error::::NotOngoing)?; + VotingFor::::try_mutate(who, &class, |voting| { + if let Voting::Casting(Casting { ref mut votes, delegations, .. }) = voting { + match votes.binary_search_by_key(&poll_index, |i| i.0) { + Ok(i) => { + // Shouldn't be possible to fail, but we handle it gracefully. + tally.remove(votes[i].1).ok_or(ArithmeticError::Underflow)?; + if let Some(approve) = votes[i].1.as_standard() { + tally.reduce(approve, *delegations); + } + votes[i].1 = vote; + }, + Err(i) => { + votes + .try_insert(i, (poll_index, vote)) + .map_err(|()| Error::::MaxVotesReached)?; + }, + } + // Shouldn't be possible to fail, but we handle it gracefully. + tally.add(vote).ok_or(ArithmeticError::Overflow)?; + if let Some(approve) = vote.as_standard() { + tally.increase(approve, *delegations); + } + } else { + return Err(Error::::AlreadyDelegating.into()) + } + // Extend the lock to `balance` (rather than setting it) since we don't know what + // other votes are in place. + Self::extend_lock(who, &class, vote.balance()); + Ok(()) + }) + }) + } + + /// Remove the account's vote for the given poll if possible. This is possible when: + /// - The poll has not finished. + /// - The poll has finished and the voter lost their direction. + /// - The poll has finished and the voter's lock period is up. + /// + /// This will generally be combined with a call to `unlock`. + fn try_remove_vote( + who: &T::AccountId, + poll_index: PollIndexOf, + class_hint: Option>, + scope: UnvoteScope, + ) -> DispatchResult { + let class = class_hint + .or_else(|| Some(T::Polls::as_ongoing(poll_index)?.1)) + .ok_or(Error::::ClassNeeded)?; + VotingFor::::try_mutate(who, class, |voting| { + if let Voting::Casting(Casting { ref mut votes, delegations, ref mut prior }) = voting { + let i = votes + .binary_search_by_key(&poll_index, |i| i.0) + .map_err(|_| Error::::NotVoter)?; + let v = votes.remove(i); + + T::Polls::try_access_poll(poll_index, |poll_status| match poll_status { + PollStatus::Ongoing(tally, _) => { + ensure!(matches!(scope, UnvoteScope::Any), Error::::NoPermission); + // Shouldn't be possible to fail, but we handle it gracefully. + tally.remove(v.1).ok_or(ArithmeticError::Underflow)?; + if let Some(approve) = v.1.as_standard() { + tally.reduce(approve, *delegations); + } + Ok(()) + }, + PollStatus::Completed(end, approved) => { + if let Some((lock_periods, balance)) = v.1.locked_if(approved) { + let unlock_at = end.saturating_add( + T::VoteLockingPeriod::get().saturating_mul(lock_periods.into()), + ); + let now = frame_system::Pallet::::block_number(); + if now < unlock_at { + ensure!( + matches!(scope, UnvoteScope::Any), + Error::::NoPermissionYet + ); + prior.accumulate(unlock_at, balance) + } + } + Ok(()) + }, + PollStatus::None => Ok(()), // Poll was cancelled. + }) + } else { + Ok(()) + } + }) + } + + /// Return the number of votes for `who` + fn increase_upstream_delegation( + who: &T::AccountId, + class: &ClassOf, + amount: Delegations>, + ) -> u32 { + VotingFor::::mutate(who, class, |voting| match voting { + Voting::Delegating(Delegating { delegations, .. }) => { + // We don't support second level delegating, so we don't need to do anything more. + *delegations = delegations.saturating_add(amount); + 1 + }, + Voting::Casting(Casting { votes, delegations, .. }) => { + *delegations = delegations.saturating_add(amount); + for &(poll_index, account_vote) in votes.iter() { + if let AccountVote::Standard { vote, .. } = account_vote { + T::Polls::access_poll(poll_index, |poll_status| { + if let PollStatus::Ongoing(tally, _) = poll_status { + tally.increase(vote.aye, amount); + } + }); + } + } + votes.len() as u32 + }, + }) + } + + /// Return the number of votes for `who` + fn reduce_upstream_delegation( + who: &T::AccountId, + class: &ClassOf, + amount: Delegations>, + ) -> u32 { + VotingFor::::mutate(who, class, |voting| match voting { + Voting::Delegating(Delegating { delegations, .. }) => { + // We don't support second level delegating, so we don't need to do anything more. + *delegations = delegations.saturating_sub(amount); + 1 + }, + Voting::Casting(Casting { votes, delegations, .. }) => { + *delegations = delegations.saturating_sub(amount); + for &(poll_index, account_vote) in votes.iter() { + if let AccountVote::Standard { vote, .. } = account_vote { + T::Polls::access_poll(poll_index, |poll_status| { + if let PollStatus::Ongoing(tally, _) = poll_status { + tally.reduce(vote.aye, amount); + } + }); + } + } + votes.len() as u32 + }, + }) + } + + /// Attempt to delegate `balance` times `conviction` of voting power from `who` to `target`. + /// + /// Return the upstream number of votes. + fn try_delegate( + who: T::AccountId, + class: ClassOf, + target: T::AccountId, + conviction: Conviction, + balance: BalanceOf, + ) -> Result { + ensure!(who != target, Error::::Nonsense); + T::Polls::classes().binary_search(&class).map_err(|_| Error::::BadClass)?; + ensure!(balance <= T::Currency::free_balance(&who), Error::::InsufficientFunds); + let votes = + VotingFor::::try_mutate(&who, &class, |voting| -> Result { + let old = sp_std::mem::replace( + voting, + Voting::Delegating(Delegating { + balance, + target: target.clone(), + conviction, + delegations: Default::default(), + prior: Default::default(), + }), + ); + match old { + Voting::Delegating(Delegating { .. }) => Err(Error::::AlreadyDelegating)?, + Voting::Casting(Casting { votes, delegations, prior }) => { + // here we just ensure that we're currently idling with no votes recorded. + ensure!(votes.is_empty(), Error::::AlreadyVoting); + voting.set_common(delegations, prior); + }, + } + + let votes = + Self::increase_upstream_delegation(&target, &class, conviction.votes(balance)); + // Extend the lock to `balance` (rather than setting it) since we don't know what + // other votes are in place. + Self::extend_lock(&who, &class, balance); + Ok(votes) + })?; + Self::deposit_event(Event::::Delegated(who, target)); + Ok(votes) + } + + /// Attempt to end the current delegation. + /// + /// Return the number of votes of upstream. + fn try_undelegate(who: T::AccountId, class: ClassOf) -> Result { + let votes = + VotingFor::::try_mutate(&who, &class, |voting| -> Result { + match sp_std::mem::replace(voting, Voting::default()) { + Voting::Delegating(Delegating { + balance, + target, + conviction, + delegations, + mut prior, + }) => { + // remove any delegation votes to our current target. + let votes = Self::reduce_upstream_delegation( + &target, + &class, + conviction.votes(balance), + ); + let now = frame_system::Pallet::::block_number(); + let lock_periods = conviction.lock_periods().into(); + prior.accumulate( + now.saturating_add( + T::VoteLockingPeriod::get().saturating_mul(lock_periods), + ), + balance, + ); + voting.set_common(delegations, prior); + + Ok(votes) + }, + Voting::Casting(_) => Err(Error::::NotDelegating.into()), + } + })?; + Self::deposit_event(Event::::Undelegated(who)); + Ok(votes) + } + + fn extend_lock(who: &T::AccountId, class: &ClassOf, amount: BalanceOf) { + ClassLocksFor::::mutate(who, |locks| match locks.iter().position(|x| &x.0 == class) { + Some(i) => locks[i].1 = locks[i].1.max(amount), + None => locks.push((class.clone(), amount)), + }); + T::Currency::extend_lock(CONVICTION_VOTING_ID, who, amount, WithdrawReasons::TRANSFER); + } + + /// Rejig the lock on an account. It will never get more stringent (since that would indicate + /// a security hole) but may be reduced from what they are currently. + fn update_lock(class: &ClassOf, who: &T::AccountId) { + let class_lock_needed = VotingFor::::mutate(who, class, |voting| { + voting.rejig(frame_system::Pallet::::block_number()); + voting.locked_balance() + }); + let lock_needed = ClassLocksFor::::mutate(who, |locks| { + locks.retain(|x| &x.0 != class); + if !class_lock_needed.is_zero() { + locks.push((class.clone(), class_lock_needed)); + } + locks.iter().map(|x| x.1).max().unwrap_or(Zero::zero()) + }); + if lock_needed.is_zero() { + T::Currency::remove_lock(CONVICTION_VOTING_ID, who); + } else { + T::Currency::set_lock( + CONVICTION_VOTING_ID, + who, + lock_needed, + WithdrawReasons::TRANSFER, + ); + } + } +} diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs new file mode 100644 index 0000000000000..cedb23b02a8db --- /dev/null +++ b/frame/conviction-voting/src/tests.rs @@ -0,0 +1,820 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The crate's tests. + +use std::collections::BTreeMap; + +use super::*; +use crate as pallet_conviction_voting; +use frame_support::{ + assert_noop, assert_ok, parameter_types, + traits::{ConstU32, ConstU64, Contains, Polling}, +}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Voting: pallet_conviction_voting::{Pallet, Call, Storage, Event}, + } +); + +// Test that a fitlered call can be dispatched. +pub struct BaseFilter; +impl Contains for BaseFilter { + fn contains(call: &Call) -> bool { + !matches!(call, &Call::Balances(pallet_balances::Call::set_balance { .. })) + } +} + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(1_000_000); +} +impl frame_system::Config for Test { + type BaseCallFilter = BaseFilter; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = Call; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type MaxLocks = ConstU32<10>; + type Balance = u64; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TestPollState { + Ongoing(TallyOf, u8), + Completed(u64, bool), +} +use TestPollState::*; + +parameter_types! { + pub static Polls: BTreeMap = vec![ + (1, Completed(1, true)), + (2, Completed(2, false)), + (3, Ongoing(Tally::from_parts(0, 0, 0), 0)), + ].into_iter().collect(); +} + +pub struct TestPolls; +impl Polling> for TestPolls { + type Index = u8; + type Votes = u64; + type Moment = u64; + type Class = u8; + fn classes() -> Vec { + vec![0, 1, 2] + } + fn as_ongoing(index: u8) -> Option<(TallyOf, Self::Class)> { + Polls::get().remove(&index).and_then(|x| { + if let TestPollState::Ongoing(t, c) = x { + Some((t, c)) + } else { + None + } + }) + } + fn access_poll( + index: Self::Index, + f: impl FnOnce(PollStatus<&mut TallyOf, u64, u8>) -> R, + ) -> R { + let mut polls = Polls::get(); + let entry = polls.get_mut(&index); + let r = match entry { + Some(Ongoing(ref mut tally_mut_ref, class)) => + f(PollStatus::Ongoing(tally_mut_ref, *class)), + Some(Completed(when, succeeded)) => f(PollStatus::Completed(*when, *succeeded)), + None => f(PollStatus::None), + }; + Polls::set(polls); + r + } + fn try_access_poll( + index: Self::Index, + f: impl FnOnce(PollStatus<&mut TallyOf, u64, u8>) -> Result, + ) -> Result { + let mut polls = Polls::get(); + let entry = polls.get_mut(&index); + let r = match entry { + Some(Ongoing(ref mut tally_mut_ref, class)) => + f(PollStatus::Ongoing(tally_mut_ref, *class)), + Some(Completed(when, succeeded)) => f(PollStatus::Completed(*when, *succeeded)), + None => f(PollStatus::None), + }?; + Polls::set(polls); + Ok(r) + } + + #[cfg(feature = "runtime-benchmarks")] + fn create_ongoing(class: Self::Class) -> Result { + let mut polls = Polls::get(); + let i = polls.keys().rev().next().map_or(0, |x| x + 1); + polls.insert(i, Ongoing(Tally::default(), class)); + Polls::set(polls); + Ok(i) + } + + #[cfg(feature = "runtime-benchmarks")] + fn end_ongoing(index: Self::Index, approved: bool) -> Result<(), ()> { + let mut polls = Polls::get(); + match polls.get(&index) { + Some(Ongoing(..)) => {}, + _ => return Err(()), + } + let now = frame_system::Pallet::::block_number(); + polls.insert(index, Completed(now, approved)); + Polls::set(polls); + Ok(()) + } +} + +impl Config for Test { + type Event = Event; + type Currency = pallet_balances::Pallet; + type VoteLockingPeriod = ConstU64<3>; + type MaxVotes = ConstU32<3>; + type WeightInfo = (); + type MaxTurnout = frame_support::traits::TotalIssuanceOf; + type Polls = TestPolls; +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { + balances: vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)], + } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +#[test] +fn params_should_work() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + assert_eq!(Balances::total_issuance(), 210); + }); +} + +fn next_block() { + System::set_block_number(System::block_number() + 1); +} + +#[allow(dead_code)] +fn run_to(n: u64) { + while System::block_number() < n { + next_block(); + } +} + +fn aye(amount: u64, conviction: u8) -> AccountVote { + let vote = Vote { aye: true, conviction: conviction.try_into().unwrap() }; + AccountVote::Standard { vote, balance: amount } +} + +fn nay(amount: u64, conviction: u8) -> AccountVote { + let vote = Vote { aye: false, conviction: conviction.try_into().unwrap() }; + AccountVote::Standard { vote, balance: amount } +} + +fn tally(index: u8) -> TallyOf { + >>::as_ongoing(index).expect("No poll").0 +} + +fn class(index: u8) -> u8 { + >>::as_ongoing(index).expect("No poll").1 +} + +#[test] +#[ignore] +#[should_panic(expected = "No poll")] +fn unknown_poll_should_panic() { + let _ = tally(0); +} + +#[test] +#[ignore] +#[should_panic(expected = "No poll")] +fn completed_poll_should_panic() { + let _ = tally(1); +} + +#[test] +fn basic_stuff() { + new_test_ext().execute_with(|| { + assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); + }); +} + +#[test] +fn basic_voting_works() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(2, 5))); + assert_eq!(tally(3), Tally::from_parts(10, 0, 2)); + assert_ok!(Voting::vote(Origin::signed(1), 3, nay(2, 5))); + assert_eq!(tally(3), Tally::from_parts(0, 10, 2)); + assert_eq!(Balances::usable_balance(1), 8); + + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(5, 1))); + assert_eq!(tally(3), Tally::from_parts(5, 0, 5)); + assert_ok!(Voting::vote(Origin::signed(1), 3, nay(5, 1))); + assert_eq!(tally(3), Tally::from_parts(0, 5, 5)); + assert_eq!(Balances::usable_balance(1), 5); + + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); + assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); + assert_ok!(Voting::vote(Origin::signed(1), 3, nay(10, 0))); + assert_eq!(tally(3), Tally::from_parts(0, 1, 10)); + assert_eq!(Balances::usable_balance(1), 0); + + assert_ok!(Voting::remove_vote(Origin::signed(1), None, 3)); + assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); + + assert_ok!(Voting::unlock(Origin::signed(1), class(3), 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn voting_balance_gets_locked() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(2, 5))); + assert_eq!(tally(3), Tally::from_parts(10, 0, 2)); + assert_ok!(Voting::vote(Origin::signed(1), 3, nay(2, 5))); + assert_eq!(tally(3), Tally::from_parts(0, 10, 2)); + assert_eq!(Balances::usable_balance(1), 8); + + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(5, 1))); + assert_eq!(tally(3), Tally::from_parts(5, 0, 5)); + assert_ok!(Voting::vote(Origin::signed(1), 3, nay(5, 1))); + assert_eq!(tally(3), Tally::from_parts(0, 5, 5)); + assert_eq!(Balances::usable_balance(1), 5); + + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); + assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); + assert_ok!(Voting::vote(Origin::signed(1), 3, nay(10, 0))); + assert_eq!(tally(3), Tally::from_parts(0, 1, 10)); + assert_eq!(Balances::usable_balance(1), 0); + + assert_ok!(Voting::remove_vote(Origin::signed(1), None, 3)); + assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); + + assert_ok!(Voting::unlock(Origin::signed(1), class(3), 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn successful_but_zero_conviction_vote_balance_can_be_unlocked() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(1, 1))); + assert_ok!(Voting::vote(Origin::signed(2), 3, nay(20, 0))); + let c = class(3); + Polls::set(vec![(3, Completed(3, false))].into_iter().collect()); + assert_ok!(Voting::remove_vote(Origin::signed(2), Some(c), 3)); + assert_ok!(Voting::unlock(Origin::signed(2), c, 2)); + assert_eq!(Balances::usable_balance(2), 20); + }); +} + +#[test] +fn unsuccessful_conviction_vote_balance_can_be_unlocked() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(1, 1))); + assert_ok!(Voting::vote(Origin::signed(2), 3, nay(20, 0))); + let c = class(3); + Polls::set(vec![(3, Completed(3, false))].into_iter().collect()); + assert_ok!(Voting::remove_vote(Origin::signed(1), Some(c), 3)); + assert_ok!(Voting::unlock(Origin::signed(1), c, 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn successful_conviction_vote_balance_stays_locked_for_correct_time() { + new_test_ext().execute_with(|| { + for i in 1..=5 { + assert_ok!(Voting::vote(Origin::signed(i), 3, aye(10, i as u8))); + } + let c = class(3); + Polls::set(vec![(3, Completed(3, true))].into_iter().collect()); + for i in 1..=5 { + assert_ok!(Voting::remove_vote(Origin::signed(i), Some(c), 3)); + } + for block in 1..=(3 + 5 * 3) { + run_to(block); + for i in 1..=5 { + assert_ok!(Voting::unlock(Origin::signed(i), c, i)); + let expired = block >= (3 << (i - 1)) + 3; + assert_eq!(Balances::usable_balance(i), i * 10 - if expired { 0 } else { 10 }); + } + } + }); +} + +#[test] +fn classwise_delegation_works() { + new_test_ext().execute_with(|| { + Polls::set( + vec![ + (0, Ongoing(Tally::default(), 0)), + (1, Ongoing(Tally::default(), 1)), + (2, Ongoing(Tally::default(), 2)), + (3, Ongoing(Tally::default(), 2)), + ] + .into_iter() + .collect(), + ); + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(Origin::signed(1), 1, 3, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(Origin::signed(1), 2, 4, Conviction::Locked1x, 5)); + assert_eq!(Balances::usable_balance(1), 5); + + assert_ok!(Voting::vote(Origin::signed(2), 0, aye(10, 0))); + assert_ok!(Voting::vote(Origin::signed(2), 1, nay(10, 0))); + assert_ok!(Voting::vote(Origin::signed(2), 2, nay(10, 0))); + assert_ok!(Voting::vote(Origin::signed(3), 0, nay(10, 0))); + assert_ok!(Voting::vote(Origin::signed(3), 1, aye(10, 0))); + assert_ok!(Voting::vote(Origin::signed(3), 2, nay(10, 0))); + assert_ok!(Voting::vote(Origin::signed(4), 0, nay(10, 0))); + assert_ok!(Voting::vote(Origin::signed(4), 1, nay(10, 0))); + assert_ok!(Voting::vote(Origin::signed(4), 2, aye(10, 0))); + // 4 hasn't voted yet + + assert_eq!( + Polls::get(), + vec![ + (0, Ongoing(Tally::from_parts(6, 2, 35), 0)), + (1, Ongoing(Tally::from_parts(6, 2, 35), 1)), + (2, Ongoing(Tally::from_parts(6, 2, 35), 2)), + (3, Ongoing(Tally::from_parts(0, 0, 0), 2)), + ] + .into_iter() + .collect() + ); + + // 4 votes nay to 3. + assert_ok!(Voting::vote(Origin::signed(4), 3, nay(10, 0))); + assert_eq!( + Polls::get(), + vec![ + (0, Ongoing(Tally::from_parts(6, 2, 35), 0)), + (1, Ongoing(Tally::from_parts(6, 2, 35), 1)), + (2, Ongoing(Tally::from_parts(6, 2, 35), 2)), + (3, Ongoing(Tally::from_parts(0, 6, 15), 2)), + ] + .into_iter() + .collect() + ); + + // Redelegate for class 2 to account 3. + assert_ok!(Voting::undelegate(Origin::signed(1), 2)); + assert_ok!(Voting::delegate(Origin::signed(1), 2, 3, Conviction::Locked1x, 5)); + assert_eq!( + Polls::get(), + vec![ + (0, Ongoing(Tally::from_parts(6, 2, 35), 0)), + (1, Ongoing(Tally::from_parts(6, 2, 35), 1)), + (2, Ongoing(Tally::from_parts(1, 7, 35), 2)), + (3, Ongoing(Tally::from_parts(0, 1, 10), 2)), + ] + .into_iter() + .collect() + ); + + // Redelegating with a lower lock does not forget previous lock and updates correctly. + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::undelegate(Origin::signed(1), 1)); + assert_ok!(Voting::undelegate(Origin::signed(1), 2)); + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 3)); + assert_ok!(Voting::delegate(Origin::signed(1), 1, 3, Conviction::Locked1x, 3)); + assert_ok!(Voting::delegate(Origin::signed(1), 2, 4, Conviction::Locked1x, 3)); + assert_eq!( + Polls::get(), + vec![ + (0, Ongoing(Tally::from_parts(4, 2, 33), 0)), + (1, Ongoing(Tally::from_parts(4, 2, 33), 1)), + (2, Ongoing(Tally::from_parts(4, 2, 33), 2)), + (3, Ongoing(Tally::from_parts(0, 4, 13), 2)), + ] + .into_iter() + .collect() + ); + assert_eq!(Balances::usable_balance(1), 5); + + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + // unlock does nothing since the delegation already took place. + assert_eq!(Balances::usable_balance(1), 5); + + // Redelegating with higher amount extends previous lock. + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 6)); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 4); + assert_ok!(Voting::undelegate(Origin::signed(1), 1)); + assert_ok!(Voting::delegate(Origin::signed(1), 1, 3, Conviction::Locked1x, 7)); + assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); + assert_eq!(Balances::usable_balance(1), 3); + assert_ok!(Voting::undelegate(Origin::signed(1), 2)); + assert_ok!(Voting::delegate(Origin::signed(1), 2, 4, Conviction::Locked1x, 8)); + assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_eq!(Balances::usable_balance(1), 2); + assert_eq!( + Polls::get(), + vec![ + (0, Ongoing(Tally::from_parts(7, 2, 36), 0)), + (1, Ongoing(Tally::from_parts(8, 2, 37), 1)), + (2, Ongoing(Tally::from_parts(9, 2, 38), 2)), + (3, Ongoing(Tally::from_parts(0, 9, 18), 2)), + ] + .into_iter() + .collect() + ); + }); +} + +#[test] +fn redelegation_after_vote_ending_should_keep_lock() { + new_test_ext().execute_with(|| { + Polls::set(vec![(0, Ongoing(Tally::default(), 0))].into_iter().collect()); + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::vote(Origin::signed(2), 0, aye(10, 1))); + Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); + assert_eq!(Balances::usable_balance(1), 5); + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::delegate(Origin::signed(1), 0, 3, Conviction::Locked1x, 3)); + assert_eq!(Balances::usable_balance(1), 5); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 5); + }); +} + +#[test] +fn lock_amalgamation_valid_with_multiple_removed_votes() { + new_test_ext().execute_with(|| { + Polls::set( + vec![ + (0, Ongoing(Tally::default(), 0)), + (1, Ongoing(Tally::default(), 0)), + (2, Ongoing(Tally::default(), 0)), + ] + .into_iter() + .collect(), + ); + assert_ok!(Voting::vote(Origin::signed(1), 0, aye(5, 1))); + assert_ok!(Voting::vote(Origin::signed(1), 1, aye(10, 1))); + assert_ok!(Voting::vote(Origin::signed(1), 2, aye(5, 2))); + assert_eq!(Balances::usable_balance(1), 0); + + Polls::set( + vec![(0, Completed(1, true)), (1, Completed(1, true)), (2, Completed(1, true))] + .into_iter() + .collect(), + ); + assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 2)); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + run_to(3); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + run_to(6); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert!(Balances::usable_balance(1) <= 5); + + run_to(7); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn lock_amalgamation_valid_with_multiple_delegations() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 10)); + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked2x, 5)); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 0); + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + + run_to(3); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + run_to(6); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert!(Balances::usable_balance(1) <= 5); + + run_to(7); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn lock_amalgamation_valid_with_move_roundtrip_to_delegation() { + new_test_ext().execute_with(|| { + Polls::set(vec![(0, Ongoing(Tally::default(), 0))].into_iter().collect()); + assert_ok!(Voting::vote(Origin::signed(1), 0, aye(5, 1))); + Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); + assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 5); + + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 10)); + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + Polls::set(vec![(1, Ongoing(Tally::default(), 0))].into_iter().collect()); + assert_ok!(Voting::vote(Origin::signed(1), 1, aye(5, 2))); + Polls::set(vec![(1, Completed(1, true))].into_iter().collect()); + assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 1)); + + run_to(3); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + run_to(6); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert!(Balances::usable_balance(1) <= 5); + + run_to(7); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn lock_amalgamation_valid_with_move_roundtrip_to_casting() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 5); + + Polls::set(vec![(0, Ongoing(Tally::default(), 0))].into_iter().collect()); + assert_ok!(Voting::vote(Origin::signed(1), 0, aye(10, 1))); + Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); + assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); + + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked2x, 10)); + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + + run_to(3); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + run_to(6); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert!(Balances::usable_balance(1) <= 5); + + run_to(7); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn lock_aggregation_over_different_classes_with_delegation_works() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(Origin::signed(1), 1, 2, Conviction::Locked2x, 5)); + assert_ok!(Voting::delegate(Origin::signed(1), 2, 2, Conviction::Locked1x, 10)); + + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::undelegate(Origin::signed(1), 1)); + assert_ok!(Voting::undelegate(Origin::signed(1), 2)); + + run_to(3); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + run_to(6); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_eq!(Balances::usable_balance(1), 5); + + run_to(7); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn lock_aggregation_over_different_classes_with_casting_works() { + new_test_ext().execute_with(|| { + Polls::set( + vec![ + (0, Ongoing(Tally::default(), 0)), + (1, Ongoing(Tally::default(), 1)), + (2, Ongoing(Tally::default(), 2)), + ] + .into_iter() + .collect(), + ); + assert_ok!(Voting::vote(Origin::signed(1), 0, aye(5, 1))); + assert_ok!(Voting::vote(Origin::signed(1), 1, aye(10, 1))); + assert_ok!(Voting::vote(Origin::signed(1), 2, aye(5, 2))); + Polls::set( + vec![(0, Completed(1, true)), (1, Completed(1, true)), (2, Completed(1, true))] + .into_iter() + .collect(), + ); + assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); + assert_ok!(Voting::remove_vote(Origin::signed(1), Some(1), 1)); + assert_ok!(Voting::remove_vote(Origin::signed(1), Some(2), 2)); + + run_to(3); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_eq!(Balances::usable_balance(1), 0); + + run_to(6); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_eq!(Balances::usable_balance(1), 5); + + run_to(7); + assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn errors_with_vote_work() { + new_test_ext().execute_with(|| { + assert_noop!(Voting::vote(Origin::signed(1), 0, aye(10, 0)), Error::::NotOngoing); + assert_noop!(Voting::vote(Origin::signed(1), 1, aye(10, 0)), Error::::NotOngoing); + assert_noop!(Voting::vote(Origin::signed(1), 2, aye(10, 0)), Error::::NotOngoing); + assert_noop!( + Voting::vote(Origin::signed(1), 3, aye(11, 0)), + Error::::InsufficientFunds + ); + + assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::None, 10)); + assert_noop!( + Voting::vote(Origin::signed(1), 3, aye(10, 0)), + Error::::AlreadyDelegating + ); + + assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + Polls::set( + vec![ + (0, Ongoing(Tally::default(), 0)), + (1, Ongoing(Tally::default(), 0)), + (2, Ongoing(Tally::default(), 0)), + (3, Ongoing(Tally::default(), 0)), + ] + .into_iter() + .collect(), + ); + assert_ok!(Voting::vote(Origin::signed(1), 0, aye(10, 0))); + assert_ok!(Voting::vote(Origin::signed(1), 1, aye(10, 0))); + assert_ok!(Voting::vote(Origin::signed(1), 2, aye(10, 0))); + assert_noop!( + Voting::vote(Origin::signed(1), 3, aye(10, 0)), + Error::::MaxVotesReached + ); + }); +} + +#[test] +fn errors_with_delegating_work() { + new_test_ext().execute_with(|| { + assert_noop!( + Voting::delegate(Origin::signed(1), 0, 2, Conviction::None, 11), + Error::::InsufficientFunds + ); + assert_noop!( + Voting::delegate(Origin::signed(1), 3, 2, Conviction::None, 10), + Error::::BadClass + ); + + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); + assert_noop!( + Voting::delegate(Origin::signed(1), 0, 2, Conviction::None, 10), + Error::::AlreadyVoting + ); + + assert_noop!(Voting::undelegate(Origin::signed(1), 0), Error::::NotDelegating); + }); +} + +#[test] +fn remove_other_vote_works() { + new_test_ext().execute_with(|| { + assert_noop!( + Voting::remove_other_vote(Origin::signed(2), 1, 0, 3), + Error::::NotVoter + ); + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 2))); + assert_noop!( + Voting::remove_other_vote(Origin::signed(2), 1, 0, 3), + Error::::NoPermission + ); + Polls::set(vec![(3, Completed(1, true))].into_iter().collect()); + run_to(6); + assert_noop!( + Voting::remove_other_vote(Origin::signed(2), 1, 0, 3), + Error::::NoPermissionYet + ); + run_to(7); + assert_ok!(Voting::remove_other_vote(Origin::signed(2), 1, 0, 3)); + }); +} + +#[test] +fn errors_with_remove_vote_work() { + new_test_ext().execute_with(|| { + assert_noop!(Voting::remove_vote(Origin::signed(1), Some(0), 3), Error::::NotVoter); + assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 2))); + Polls::set(vec![(3, Completed(1, true))].into_iter().collect()); + assert_noop!(Voting::remove_vote(Origin::signed(1), None, 3), Error::::ClassNeeded); + }); +} diff --git a/frame/conviction-voting/src/types.rs b/frame/conviction-voting/src/types.rs new file mode 100644 index 0000000000000..2ad1a164dd143 --- /dev/null +++ b/frame/conviction-voting/src/types.rs @@ -0,0 +1,236 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Miscellaneous additional datatypes. + +use sp_std::marker::PhantomData; + +use super::*; +use crate::{AccountVote, Conviction, Vote}; +use codec::{Codec, Decode, Encode, MaxEncodedLen}; +use frame_support::{ + traits::VoteTally, CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, + RuntimeDebugNoBound, +}; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{Saturating, Zero}, + RuntimeDebug, +}; + +/// Info regarding an ongoing referendum. +#[derive( + CloneNoBound, + DefaultNoBound, + PartialEqNoBound, + EqNoBound, + RuntimeDebugNoBound, + TypeInfo, + Encode, + Decode, + MaxEncodedLen, +)] +#[scale_info(skip_type_params(Total))] +pub struct Tally< + Votes: Clone + Default + PartialEq + Eq + sp_std::fmt::Debug + TypeInfo + Codec, + Total, +> { + /// The number of aye votes, expressed in terms of post-conviction lock-vote. + pub ayes: Votes, + /// The number of nay votes, expressed in terms of post-conviction lock-vote. + pub nays: Votes, + /// The amount of funds currently expressing its opinion. Pre-conviction. + pub turnout: Votes, + /// Dummy. + dummy: PhantomData, +} + +impl< + Votes: Clone + + Default + + PartialEq + + Eq + + sp_std::fmt::Debug + + Copy + + AtLeast32BitUnsigned + + TypeInfo + + Codec, + Total: Get, + > VoteTally for Tally +{ + fn ayes(&self) -> Votes { + self.ayes + } + + fn turnout(&self) -> Perbill { + Perbill::from_rational(self.turnout, Total::get()) + } + + fn approval(&self) -> Perbill { + Perbill::from_rational(self.ayes, self.ayes.saturating_add(self.nays)) + } + + #[cfg(feature = "runtime-benchmarks")] + fn unanimity() -> Self { + Self { ayes: Total::get(), nays: Zero::zero(), turnout: Total::get(), dummy: PhantomData } + } + + #[cfg(feature = "runtime-benchmarks")] + fn from_requirements(turnout: Perbill, approval: Perbill) -> Self { + let turnout = turnout.mul_ceil(Total::get()); + let ayes = approval.mul_ceil(turnout); + Self { ayes, nays: turnout - ayes, turnout, dummy: PhantomData } + } +} + +impl< + Votes: Clone + + Default + + PartialEq + + Eq + + sp_std::fmt::Debug + + Copy + + AtLeast32BitUnsigned + + TypeInfo + + Codec, + Total: Get, + > Tally +{ + /// Create a new tally. + pub fn new(vote: Vote, balance: Votes) -> Self { + let Delegations { votes, capital } = vote.conviction.votes(balance); + Self { + ayes: if vote.aye { votes } else { Zero::zero() }, + nays: if vote.aye { Zero::zero() } else { votes }, + turnout: capital, + dummy: PhantomData, + } + } + + pub fn from_parts(ayes: Votes, nays: Votes, turnout: Votes) -> Self { + Self { ayes, nays, turnout, dummy: PhantomData } + } + + /// Add an account's vote into the tally. + pub fn add(&mut self, vote: AccountVote) -> Option<()> { + match vote { + AccountVote::Standard { vote, balance } => { + let Delegations { votes, capital } = vote.conviction.votes(balance); + self.turnout = self.turnout.checked_add(&capital)?; + match vote.aye { + true => self.ayes = self.ayes.checked_add(&votes)?, + false => self.nays = self.nays.checked_add(&votes)?, + } + }, + AccountVote::Split { aye, nay } => { + let aye = Conviction::None.votes(aye); + let nay = Conviction::None.votes(nay); + self.turnout = self.turnout.checked_add(&aye.capital)?.checked_add(&nay.capital)?; + self.ayes = self.ayes.checked_add(&aye.votes)?; + self.nays = self.nays.checked_add(&nay.votes)?; + }, + } + Some(()) + } + + /// Remove an account's vote from the tally. + pub fn remove(&mut self, vote: AccountVote) -> Option<()> { + match vote { + AccountVote::Standard { vote, balance } => { + let Delegations { votes, capital } = vote.conviction.votes(balance); + self.turnout = self.turnout.checked_sub(&capital)?; + match vote.aye { + true => self.ayes = self.ayes.checked_sub(&votes)?, + false => self.nays = self.nays.checked_sub(&votes)?, + } + }, + AccountVote::Split { aye, nay } => { + let aye = Conviction::None.votes(aye); + let nay = Conviction::None.votes(nay); + self.turnout = self.turnout.checked_sub(&aye.capital)?.checked_sub(&nay.capital)?; + self.ayes = self.ayes.checked_sub(&aye.votes)?; + self.nays = self.nays.checked_sub(&nay.votes)?; + }, + } + Some(()) + } + + /// Increment some amount of votes. + pub fn increase(&mut self, approve: bool, delegations: Delegations) { + self.turnout = self.turnout.saturating_add(delegations.capital); + match approve { + true => self.ayes = self.ayes.saturating_add(delegations.votes), + false => self.nays = self.nays.saturating_add(delegations.votes), + } + } + + /// Decrement some amount of votes. + pub fn reduce(&mut self, approve: bool, delegations: Delegations) { + self.turnout = self.turnout.saturating_sub(delegations.capital); + match approve { + true => self.ayes = self.ayes.saturating_sub(delegations.votes), + false => self.nays = self.nays.saturating_sub(delegations.votes), + } + } +} + +/// Amount of votes and capital placed in delegation for an account. +#[derive( + Encode, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] +pub struct Delegations { + /// The number of votes (this is post-conviction). + pub votes: Balance, + /// The amount of raw capital, used for the turnout. + pub capital: Balance, +} + +impl Saturating for Delegations { + fn saturating_add(self, o: Self) -> Self { + Self { + votes: self.votes.saturating_add(o.votes), + capital: self.capital.saturating_add(o.capital), + } + } + + fn saturating_sub(self, o: Self) -> Self { + Self { + votes: self.votes.saturating_sub(o.votes), + capital: self.capital.saturating_sub(o.capital), + } + } + + fn saturating_mul(self, o: Self) -> Self { + Self { + votes: self.votes.saturating_mul(o.votes), + capital: self.capital.saturating_mul(o.capital), + } + } + + fn saturating_pow(self, exp: usize) -> Self { + Self { votes: self.votes.saturating_pow(exp), capital: self.capital.saturating_pow(exp) } + } +} + +/// Whether an `unvote` operation is able to make actions that are not strictly always in the +/// interest of an account. +pub enum UnvoteScope { + /// Permitted to do everything. + Any, + /// Permitted to do only the changes that do not need the owner's permission. + OnlyExpired, +} diff --git a/frame/conviction-voting/src/vote.rs b/frame/conviction-voting/src/vote.rs new file mode 100644 index 0000000000000..d7ca931de35a1 --- /dev/null +++ b/frame/conviction-voting/src/vote.rs @@ -0,0 +1,254 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The vote datatype. + +use crate::{Conviction, Delegations}; +use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen, Output}; +use frame_support::{pallet_prelude::Get, BoundedVec}; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{Saturating, Zero}, + RuntimeDebug, +}; +use sp_std::{convert::TryFrom, prelude::*, result::Result}; + +/// A number of lock periods, plus a vote, one way or the other. +#[derive(Copy, Clone, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen)] +pub struct Vote { + pub aye: bool, + pub conviction: Conviction, +} + +impl Encode for Vote { + fn encode_to(&self, output: &mut T) { + output.push_byte(u8::from(self.conviction) | if self.aye { 0b1000_0000 } else { 0 }); + } +} + +impl EncodeLike for Vote {} + +impl Decode for Vote { + fn decode(input: &mut I) -> Result { + let b = input.read_byte()?; + Ok(Vote { + aye: (b & 0b1000_0000) == 0b1000_0000, + conviction: Conviction::try_from(b & 0b0111_1111) + .map_err(|_| codec::Error::from("Invalid conviction"))?, + }) + } +} + +impl TypeInfo for Vote { + type Identity = Self; + + fn type_info() -> scale_info::Type { + scale_info::Type::builder() + .path(scale_info::Path::new("Vote", module_path!())) + .composite( + scale_info::build::Fields::unnamed() + .field(|f| f.ty::().docs(&["Raw vote byte, encodes aye + conviction"])), + ) + } +} + +/// A vote for a referendum of a particular account. +#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum AccountVote { + /// A standard vote, one-way (approve or reject) with a given amount of conviction. + Standard { vote: Vote, balance: Balance }, + /// A split vote with balances given for both ways, and with no conviction, useful for + /// parachains when voting. + Split { aye: Balance, nay: Balance }, +} + +impl AccountVote { + /// Returns `Some` of the lock periods that the account is locked for, assuming that the + /// referendum passed iff `approved` is `true`. + pub fn locked_if(self, approved: bool) -> Option<(u32, Balance)> { + // winning side: can only be removed after the lock period ends. + match self { + AccountVote::Standard { vote: Vote { conviction: Conviction::None, .. }, .. } => None, + AccountVote::Standard { vote, balance } if vote.aye == approved => + Some((vote.conviction.lock_periods(), balance)), + _ => None, + } + } + + /// The total balance involved in this vote. + pub fn balance(self) -> Balance { + match self { + AccountVote::Standard { balance, .. } => balance, + AccountVote::Split { aye, nay } => aye.saturating_add(nay), + } + } + + /// Returns `Some` with whether the vote is an aye vote if it is standard, otherwise `None` if + /// it is split. + pub fn as_standard(self) -> Option { + match self { + AccountVote::Standard { vote, .. } => Some(vote.aye), + _ => None, + } + } +} + +/// A "prior" lock, i.e. a lock for some now-forgotten reason. +#[derive( + Encode, + Decode, + Default, + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + RuntimeDebug, + TypeInfo, + MaxEncodedLen, +)] +pub struct PriorLock(BlockNumber, Balance); + +impl PriorLock { + /// Accumulates an additional lock. + pub fn accumulate(&mut self, until: BlockNumber, amount: Balance) { + self.0 = self.0.max(until); + self.1 = self.1.max(amount); + } + + pub fn locked(&self) -> Balance { + self.1 + } + + pub fn rejig(&mut self, now: BlockNumber) { + if now >= self.0 { + self.0 = Zero::zero(); + self.1 = Zero::zero(); + } + } +} + +/// Information concerning the delegation of some voting power. +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct Delegating { + /// The amount of balance delegated. + pub balance: Balance, + /// The account to which the voting power is delegated. + pub target: AccountId, + /// The conviction with which the voting power is delegated. When this gets undelegated, the + /// relevant lock begins. + pub conviction: Conviction, + /// The total amount of delegations that this account has received, post-conviction-weighting. + pub delegations: Delegations, + /// Any pre-existing locks from past voting/delegating activity. + pub prior: PriorLock, +} + +/// Information concerning the direct vote-casting of some voting power. +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(MaxVotes))] +pub struct Casting +where + MaxVotes: Get, +{ + /// The current votes of the account. + pub votes: BoundedVec<(PollIndex, AccountVote), MaxVotes>, + /// The total amount of delegations that this account has received, post-conviction-weighting. + pub delegations: Delegations, + /// Any pre-existing locks from past voting/delegating activity. + pub prior: PriorLock, +} + +/// An indicator for what an account is doing; it can either be delegating or voting. +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(MaxVotes))] +pub enum Voting +where + MaxVotes: Get, +{ + /// The account is voting directly. + Casting(Casting), + /// The account is delegating `balance` of its balance to a `target` account with `conviction`. + Delegating(Delegating), +} + +impl Default + for Voting +where + MaxVotes: Get, +{ + fn default() -> Self { + Voting::Casting(Casting { + votes: Default::default(), + delegations: Default::default(), + prior: PriorLock(Zero::zero(), Default::default()), + }) + } +} + +impl AsMut> + for Voting +where + MaxVotes: Get, +{ + fn as_mut(&mut self) -> &mut PriorLock { + match self { + Voting::Casting(Casting { prior, .. }) => prior, + Voting::Delegating(Delegating { prior, .. }) => prior, + } + } +} + +impl< + Balance: Saturating + Ord + Zero + Copy, + BlockNumber: Ord + Copy + Zero, + AccountId, + PollIndex, + MaxVotes, + > Voting +where + MaxVotes: Get, +{ + pub fn rejig(&mut self, now: BlockNumber) { + AsMut::>::as_mut(self).rejig(now); + } + + /// The amount of this account's balance that much currently be locked due to voting. + pub fn locked_balance(&self) -> Balance { + match self { + Voting::Casting(Casting { votes, prior, .. }) => + votes.iter().map(|i| i.1.balance()).fold(prior.locked(), |a, i| a.max(i)), + Voting::Delegating(Delegating { balance, prior, .. }) => *balance.max(&prior.locked()), + } + } + + pub fn set_common( + &mut self, + delegations: Delegations, + prior: PriorLock, + ) { + let (d, p) = match self { + Voting::Casting(Casting { ref mut delegations, ref mut prior, .. }) => + (delegations, prior), + Voting::Delegating(Delegating { ref mut delegations, ref mut prior, .. }) => + (delegations, prior), + }; + *d = delegations; + *p = prior; + } +} diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs new file mode 100644 index 0000000000000..da15aac0b47ca --- /dev/null +++ b/frame/conviction-voting/src/weights.rs @@ -0,0 +1,201 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_conviction_voting +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-01-09, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// target/release/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_conviction_voting +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/conviction-voting/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_conviction_voting. +pub trait WeightInfo { + fn vote_new() -> Weight; + fn vote_existing() -> Weight; + fn remove_vote() -> Weight; + fn remove_other_vote() -> Weight; + fn delegate(r: u32, ) -> Weight; + fn undelegate(r: u32, ) -> Weight; + fn unlock() -> Weight; +} + +/// Weights for pallet_conviction_voting using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: ConvictionVoting VotingFor (r:1 w:1) + // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn vote_new() -> Weight { + (159_647_000 as Weight) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: ConvictionVoting VotingFor (r:1 w:1) + // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn vote_existing() -> Weight { + (339_851_000 as Weight) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) + } + // Storage: ConvictionVoting VotingFor (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn remove_vote() -> Weight { + (317_673_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: ConvictionVoting VotingFor (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:1 w:0) + fn remove_other_vote() -> Weight { + (52_222_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: ConvictionVoting VotingFor (r:2 w:2) + // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn delegate(r: u32, ) -> Weight { + (61_553_000 as Weight) + // Standard Error: 123_000 + .saturating_add((33_092_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + } + // Storage: ConvictionVoting VotingFor (r:2 w:2) + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn undelegate(r: u32, ) -> Weight { + (42_037_000 as Weight) + // Standard Error: 582_000 + .saturating_add((32_296_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + } + // Storage: ConvictionVoting VotingFor (r:1 w:1) + // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + fn unlock() -> Weight { + (69_017_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: ConvictionVoting VotingFor (r:1 w:1) + // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn vote_new() -> Weight { + (159_647_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: ConvictionVoting VotingFor (r:1 w:1) + // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn vote_existing() -> Weight { + (339_851_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + } + // Storage: ConvictionVoting VotingFor (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn remove_vote() -> Weight { + (317_673_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: ConvictionVoting VotingFor (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:1 w:0) + fn remove_other_vote() -> Weight { + (52_222_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: ConvictionVoting VotingFor (r:2 w:2) + // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn delegate(r: u32, ) -> Weight { + (61_553_000 as Weight) + // Standard Error: 123_000 + .saturating_add((33_092_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + } + // Storage: ConvictionVoting VotingFor (r:2 w:2) + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn undelegate(r: u32, ) -> Weight { + (42_037_000 as Weight) + // Standard Error: 582_000 + .saturating_add((32_296_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + } + // Storage: ConvictionVoting VotingFor (r:1 w:1) + // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + fn unlock() -> Weight { + (69_017_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } +} diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 4580767d875c3..b578df5909306 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -439,14 +439,6 @@ pub mod pallet { ValueQuery, >; - /// Accounts for which there are locks in action which may be removed at some point in the - /// future. The value is the block number at which the lock expires and may be removed. - /// - /// TWOX-NOTE: OK ― `AccountId` is a secure hash. - #[pallet::storage] - #[pallet::getter(fn locks)] - pub type Locks = StorageMap<_, Twox64Concat, T::AccountId, T::BlockNumber>; - /// True if the last referendum tabled was submitted externally. False if it was a public /// proposal. // TODO: There should be any number of tabling origins, not just public and "external" diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml new file mode 100644 index 0000000000000..e979f2b0c4a37 --- /dev/null +++ b/frame/referenda/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "pallet-referenda" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet for inclusive on-chain decisions" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +serde = { version = "1.0.126", optional = true, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ + "derive", +] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +assert_matches = { version = "1.5", optional = true } + +[dev-dependencies] +sp-core = { version = "5.0.0", path = "../../primitives/core" } +pallet-balances = { version = "4.0.0-dev", path = "../balances" } +pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } +pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } +assert_matches = { version = "1.5" } + +[features] +default = ["std"] +std = [ + "serde", + "codec/std", + "scale-info/std", + "sp-std/std", + "sp-io/std", + "frame-benchmarking/std", + "frame-support/std", + "sp-runtime/std", + "frame-system/std", +] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-system/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "assert_matches", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/referenda/README.md b/frame/referenda/README.md new file mode 100644 index 0000000000000..85031a0113033 --- /dev/null +++ b/frame/referenda/README.md @@ -0,0 +1,8 @@ +# Referenda Pallet + +- [`assembly::Config`](https://docs.rs/pallet-assembly/latest/pallet_assembly/trait.Config.html) +- [`Call`](https://docs.rs/pallet-assembly/latest/pallet_assembly/enum.Call.html) + +## Overview + +The Assembly pallet handles the administration of general stakeholder voting. diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs new file mode 100644 index 0000000000000..76a8173f16c9a --- /dev/null +++ b/frame/referenda/src/benchmarking.rs @@ -0,0 +1,520 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Democracy pallet benchmarking. + +use super::*; +use crate::Pallet as Referenda; +use assert_matches::assert_matches; +use frame_benchmarking::{account, benchmarks, whitelist_account}; +use frame_support::{ + assert_ok, + traits::{Currency, EnsureOrigin}, +}; +use frame_system::RawOrigin; +use sp_runtime::traits::{Bounded, Hash}; + +const SEED: u32 = 0; + +#[allow(dead_code)] +fn assert_last_event(generic_event: ::Event) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +fn funded_account(name: &'static str, index: u32) -> T::AccountId { + let caller: T::AccountId = account(name, index, SEED); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + caller +} + +fn create_referendum() -> (T::AccountId, ReferendumIndex) { + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + assert_ok!(Referenda::::submit( + RawOrigin::Signed(caller.clone()).into(), + RawOrigin::Root.into(), + T::Hashing::hash_of(&0), + AtOrAfter::After(0u32.into()) + )); + let index = ReferendumCount::::get() - 1; + (caller, index) +} + +fn place_deposit(index: ReferendumIndex) { + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + assert_ok!(Referenda::::place_decision_deposit( + RawOrigin::Signed(caller.clone()).into(), + index, + )); +} + +fn nudge(index: ReferendumIndex) { + assert_ok!(Referenda::::nudge_referendum(RawOrigin::Root.into(), index)); +} + +fn fill_queue( + index: ReferendumIndex, + spaces: u32, + pass_after: u32, +) -> Vec { + // First, create enough other referendums to fill the track. + let mut others = vec![]; + for _ in 0..info::(index).max_deciding { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + others.push(index); + } + + // We will also need enough referenda which are queued and passing, we want `MaxQueued - 1` + // in order to force the maximum amount of work to insert ours into the queue. + for _ in spaces..T::MaxQueued::get() { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + make_passing_after::(index, Perbill::from_percent(pass_after)); + others.push(index); + } + + // Skip to when they can start being decided. + skip_prepare_period::(index); + + // Manually nudge the other referenda first to ensure that they begin. + others.iter().for_each(|&i| nudge::(i)); + + others +} + +fn info(index: ReferendumIndex) -> &'static TrackInfoOf { + let status = Referenda::::ensure_ongoing(index).unwrap(); + T::Tracks::info(status.track).expect("Id value returned from T::Tracks") +} + +fn make_passing_after(index: ReferendumIndex, period_portion: Perbill) { + let turnout = info::(index).min_turnout.threshold(period_portion); + let approval = info::(index).min_approval.threshold(period_portion); + Referenda::::access_poll(index, |status| { + if let PollStatus::Ongoing(tally, ..) = status { + *tally = T::Tally::from_requirements(turnout, approval); + } + }); +} + +fn make_passing(index: ReferendumIndex) { + Referenda::::access_poll(index, |status| { + if let PollStatus::Ongoing(tally, ..) = status { + *tally = T::Tally::unanimity(); + } + }); +} + +fn make_failing(index: ReferendumIndex) { + Referenda::::access_poll(index, |status| { + if let PollStatus::Ongoing(tally, ..) = status { + *tally = T::Tally::default(); + } + }); +} + +fn skip_prepare_period(index: ReferendumIndex) { + let status = Referenda::::ensure_ongoing(index).unwrap(); + let prepare_period_over = status.submitted + info::(index).prepare_period; + frame_system::Pallet::::set_block_number(prepare_period_over); +} + +fn skip_decision_period(index: ReferendumIndex) { + let status = Referenda::::ensure_ongoing(index).unwrap(); + let decision_period_over = status.deciding.unwrap().since + info::(index).decision_period; + frame_system::Pallet::::set_block_number(decision_period_over); +} + +fn skip_confirm_period(index: ReferendumIndex) { + let status = Referenda::::ensure_ongoing(index).unwrap(); + let confirm_period_over = status.deciding.unwrap().confirming.unwrap(); + frame_system::Pallet::::set_block_number(confirm_period_over); +} + +fn skip_timeout_period(index: ReferendumIndex) { + let status = Referenda::::ensure_ongoing(index).unwrap(); + let timeout_period_over = status.submitted + T::UndecidingTimeout::get(); + frame_system::Pallet::::set_block_number(timeout_period_over); +} + +fn alarm_time(index: ReferendumIndex) -> T::BlockNumber { + let status = Referenda::::ensure_ongoing(index).unwrap(); + status.alarm.unwrap().0 +} + +fn is_confirming(index: ReferendumIndex) -> bool { + let status = Referenda::::ensure_ongoing(index).unwrap(); + matches!( + status, + ReferendumStatus { deciding: Some(DecidingStatus { confirming: Some(_), .. }), .. } + ) +} + +fn is_not_confirming(index: ReferendumIndex) -> bool { + let status = Referenda::::ensure_ongoing(index).unwrap(); + matches!( + status, + ReferendumStatus { deciding: Some(DecidingStatus { confirming: None, .. }), .. } + ) +} + +benchmarks! { + submit { + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + }: _( + RawOrigin::Signed(caller), + RawOrigin::Root.into(), + T::Hashing::hash_of(&0), + AtOrAfter::After(0u32.into()) + ) verify { + let index = ReferendumCount::::get().checked_sub(1).unwrap(); + assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Ongoing(_))); + } + + place_decision_deposit_preparing { + let (caller, index) = create_referendum::(); + }: place_decision_deposit(RawOrigin::Signed(caller), index) + verify { + assert!(Referenda::::ensure_ongoing(index).unwrap().decision_deposit.is_some()); + } + + place_decision_deposit_queued { + let (caller, index) = create_referendum::(); + fill_queue::(index, 1, 90); + }: place_decision_deposit(RawOrigin::Signed(caller), index) + verify { + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert_eq!(TrackQueue::::get(&track)[0], (index, 0u32.into())); + } + + place_decision_deposit_not_queued { + let (caller, index) = create_referendum::(); + fill_queue::(index, 0, 90); + }: place_decision_deposit(RawOrigin::Signed(caller), index) + verify { + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); + } + + place_decision_deposit_passing { + let (caller, index) = create_referendum::(); + skip_prepare_period::(index); + make_passing::(index); + }: place_decision_deposit(RawOrigin::Signed(caller), index) + verify { + assert!(is_confirming::(index)); + } + + place_decision_deposit_failing { + let (caller, index) = create_referendum::(); + skip_prepare_period::(index); + }: place_decision_deposit(RawOrigin::Signed(caller), index) + verify { + assert!(is_not_confirming::(index)); + } + + refund_decision_deposit { + let (caller, index) = create_referendum::(); + place_deposit::(index); + assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); + }: _(RawOrigin::Signed(caller), index) + verify { + assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, _, None))); + } + + cancel { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + }: _(T::CancelOrigin::successful_origin(), index) + verify { + assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(..))); + } + + kill { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + }: _(T::KillOrigin::successful_origin(), index) + verify { + assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Killed(..))); + } + + one_fewer_deciding_queue_empty { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + nudge::(index); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); + assert_eq!(DecidingCount::::get(&track), 1); + }: one_fewer_deciding(RawOrigin::Root, track.clone()) + verify { + assert_eq!(DecidingCount::::get(&track), 0); + } + + one_fewer_deciding_failing { + let (_caller, index) = create_referendum::(); + // No spaces free in the queue. + let queued = fill_queue::(index, 0, 90); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + let deciding_count = DecidingCount::::get(&track); + }: one_fewer_deciding(RawOrigin::Root, track.clone()) + verify { + assert_eq!(DecidingCount::::get(&track), deciding_count); + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); + assert!(queued.into_iter().skip(1).all(|i| Referenda::::ensure_ongoing(i) + .unwrap() + .deciding + .map_or(true, |d| d.confirming.is_none()) + )); + } + + one_fewer_deciding_passing { + let (_caller, index) = create_referendum::(); + // No spaces free in the queue. + let queued = fill_queue::(index, 0, 0); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + let deciding_count = DecidingCount::::get(&track); + }: one_fewer_deciding(RawOrigin::Root, track.clone()) + verify { + assert_eq!(DecidingCount::::get(&track), deciding_count); + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); + assert!(queued.into_iter().skip(1).all(|i| Referenda::::ensure_ongoing(i) + .unwrap() + .deciding + .map_or(true, |d| d.confirming.is_some()) + )); + } + + nudge_referendum_requeued_insertion { + // First create our referendum and place the deposit. It will be failing. + let (_caller, index) = create_referendum::(); + place_deposit::(index); + fill_queue::(index, 0, 90); + + // Now nudge ours, with the track now full and the queue full of referenda with votes, + // ours will not be in the queue. + nudge::(index); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); + + // Now alter the voting, so that ours goes into pole-position and shifts others down. + make_passing::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + let t = TrackQueue::::get(&track); + assert_eq!(t.len() as u32, T::MaxQueued::get()); + assert_eq!(t[t.len() - 1].0, index); + } + + nudge_referendum_requeued_slide { + // First create our referendum and place the deposit. It will be failing. + let (_caller, index) = create_referendum::(); + place_deposit::(index); + fill_queue::(index, 1, 90); + + // Now nudge ours, with the track now full, ours will be queued, but with no votes, it + // will have the worst position. + nudge::(index); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert_eq!(TrackQueue::::get(&track)[0], (index, 0u32.into())); + + // Now alter the voting, so that ours leap-frogs all into the best position. + make_passing::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + let t = TrackQueue::::get(&track); + assert_eq!(t.len() as u32, T::MaxQueued::get()); + assert_eq!(t[t.len() - 1].0, index); + } + + nudge_referendum_queued { + // NOTE: worst possible queue situation is with a queue full of passing refs with one slot + // free and this failing. It would result in `QUEUE_SIZE - 1` items being shifted for the + // insertion at the beginning. + + // First create our referendum and place the deposit. It will be failing. + let (_caller, index) = create_referendum::(); + place_deposit::(index); + fill_queue::(index, 1, 0); + + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); + assert!(TrackQueue::::get(&track).into_iter().all(|(_, v)| v > 0u32.into())); + + // Then nudge ours, with the track now full, ours will be queued. + }: nudge_referendum(RawOrigin::Root, index) + verify { + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert_eq!(TrackQueue::::get(&track)[0], (index, 0u32.into())); + } + + nudge_referendum_not_queued { + // First create our referendum and place the deposit. It will be failing. + let (_caller, index) = create_referendum::(); + place_deposit::(index); + fill_queue::(index, 0, 0); + + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert!(TrackQueue::::get(&track).into_iter().all(|(_, v)| v > 0u32.into())); + + // Then nudge ours, with the track now full, ours will be queued. + }: nudge_referendum(RawOrigin::Root, index) + verify { + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); + } + + nudge_referendum_no_deposit { + let (_caller, index) = create_referendum::(); + skip_prepare_period::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + let status = Referenda::::ensure_ongoing(index).unwrap(); + assert_matches!(status, ReferendumStatus { deciding: None, .. }); + } + + nudge_referendum_preparing { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + let status = Referenda::::ensure_ongoing(index).unwrap(); + assert_matches!(status, ReferendumStatus { deciding: None, .. }); + } + + nudge_referendum_timed_out { + let (_caller, index) = create_referendum::(); + skip_timeout_period::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + let info = ReferendumInfoFor::::get(index).unwrap(); + assert_matches!(info, ReferendumInfo::TimedOut(..)); + } + + nudge_referendum_begin_deciding_failing { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + assert!(is_not_confirming::(index)); + } + + nudge_referendum_begin_deciding_passing { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + make_passing::(index); + skip_prepare_period::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + assert!(is_confirming::(index)); + } + + nudge_referendum_begin_confirming { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + nudge::(index); + assert!(!is_confirming::(index)); + make_passing::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + assert!(is_confirming::(index)); + } + + nudge_referendum_end_confirming { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + make_passing::(index); + nudge::(index); + assert!(is_confirming::(index)); + make_failing::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + assert!(!is_confirming::(index)); + } + + nudge_referendum_continue_not_confirming { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + nudge::(index); + assert!(!is_confirming::(index)); + let old_alarm = alarm_time::(index); + make_passing_after::(index, Perbill::from_percent(50)); + }: nudge_referendum(RawOrigin::Root, index) + verify { + assert_ne!(old_alarm, alarm_time::(index)); + assert!(!is_confirming::(index)); + } + + nudge_referendum_continue_confirming { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + make_passing::(index); + skip_prepare_period::(index); + nudge::(index); + assert!(is_confirming::(index)); + let old_alarm = alarm_time::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + assert!(is_confirming::(index)); + } + + nudge_referendum_approved { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + make_passing::(index); + nudge::(index); + skip_confirm_period::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + let info = ReferendumInfoFor::::get(index).unwrap(); + assert_matches!(info, ReferendumInfo::Approved(..)); + } + + nudge_referendum_rejected { + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + nudge::(index); + skip_decision_period::(index); + }: nudge_referendum(RawOrigin::Root, index) + verify { + let info = ReferendumInfoFor::::get(index).unwrap(); + assert_matches!(info, ReferendumInfo::Rejected(..)); + } + + impl_benchmark_test_suite!( + Referenda, + crate::mock::new_test_ext(), + crate::mock::Test + ); +} diff --git a/frame/referenda/src/branch.rs b/frame/referenda/src/branch.rs new file mode 100644 index 0000000000000..6a4efa31e15e2 --- /dev/null +++ b/frame/referenda/src/branch.rs @@ -0,0 +1,172 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Helpers for managing the different weights in various algorithmic branches. + +use super::Config; +use crate::weights::WeightInfo; + +/// Branches within the `begin_deciding` function. +pub enum BeginDecidingBranch { + Passing, + Failing, +} + +/// Branches within the `service_referendum` function. +pub enum ServiceBranch { + Fail, + NoDeposit, + Preparing, + Queued, + NotQueued, + RequeuedInsertion, + RequeuedSlide, + BeginDecidingPassing, + BeginDecidingFailing, + BeginConfirming, + ContinueConfirming, + EndConfirming, + ContinueNotConfirming, + Approved, + Rejected, + TimedOut, +} + +impl From for ServiceBranch { + fn from(x: BeginDecidingBranch) -> Self { + use BeginDecidingBranch::*; + use ServiceBranch::*; + match x { + Passing => BeginDecidingPassing, + Failing => BeginDecidingFailing, + } + } +} + +impl ServiceBranch { + /// Return the weight of the `nudge` function when it takes the branch denoted by `self`. + pub fn weight_of_nudge(self) -> frame_support::weights::Weight { + use ServiceBranch::*; + match self { + NoDeposit => T::WeightInfo::nudge_referendum_no_deposit(), + Preparing => T::WeightInfo::nudge_referendum_preparing(), + Queued => T::WeightInfo::nudge_referendum_queued(), + NotQueued => T::WeightInfo::nudge_referendum_not_queued(), + RequeuedInsertion => T::WeightInfo::nudge_referendum_requeued_insertion(), + RequeuedSlide => T::WeightInfo::nudge_referendum_requeued_slide(), + BeginDecidingPassing => T::WeightInfo::nudge_referendum_begin_deciding_passing(), + BeginDecidingFailing => T::WeightInfo::nudge_referendum_begin_deciding_failing(), + BeginConfirming => T::WeightInfo::nudge_referendum_begin_confirming(), + ContinueConfirming => T::WeightInfo::nudge_referendum_continue_confirming(), + EndConfirming => T::WeightInfo::nudge_referendum_end_confirming(), + ContinueNotConfirming => T::WeightInfo::nudge_referendum_continue_not_confirming(), + Approved => T::WeightInfo::nudge_referendum_approved(), + Rejected => T::WeightInfo::nudge_referendum_rejected(), + TimedOut | Fail => T::WeightInfo::nudge_referendum_timed_out(), + } + } + + /// Return the maximum possible weight of the `nudge` function. + pub fn max_weight_of_nudge() -> frame_support::weights::Weight { + 0.max(T::WeightInfo::nudge_referendum_no_deposit()) + .max(T::WeightInfo::nudge_referendum_preparing()) + .max(T::WeightInfo::nudge_referendum_queued()) + .max(T::WeightInfo::nudge_referendum_not_queued()) + .max(T::WeightInfo::nudge_referendum_requeued_insertion()) + .max(T::WeightInfo::nudge_referendum_requeued_slide()) + .max(T::WeightInfo::nudge_referendum_begin_deciding_passing()) + .max(T::WeightInfo::nudge_referendum_begin_deciding_failing()) + .max(T::WeightInfo::nudge_referendum_begin_confirming()) + .max(T::WeightInfo::nudge_referendum_continue_confirming()) + .max(T::WeightInfo::nudge_referendum_end_confirming()) + .max(T::WeightInfo::nudge_referendum_continue_not_confirming()) + .max(T::WeightInfo::nudge_referendum_approved()) + .max(T::WeightInfo::nudge_referendum_rejected()) + .max(T::WeightInfo::nudge_referendum_timed_out()) + } + + /// Return the weight of the `place_decision_deposit` function when it takes the branch denoted + /// by `self`. + pub fn weight_of_deposit(self) -> Option { + use ServiceBranch::*; + Some(match self { + Preparing => T::WeightInfo::place_decision_deposit_preparing(), + Queued => T::WeightInfo::place_decision_deposit_queued(), + NotQueued => T::WeightInfo::place_decision_deposit_not_queued(), + BeginDecidingPassing => T::WeightInfo::place_decision_deposit_passing(), + BeginDecidingFailing => T::WeightInfo::place_decision_deposit_failing(), + BeginConfirming | + ContinueConfirming | + EndConfirming | + ContinueNotConfirming | + Approved | + Rejected | + RequeuedInsertion | + RequeuedSlide | + TimedOut | + Fail | + NoDeposit => return None, + }) + } + + /// Return the maximum possible weight of the `place_decision_deposit` function. + pub fn max_weight_of_deposit() -> frame_support::weights::Weight { + 0.max(T::WeightInfo::place_decision_deposit_preparing()) + .max(T::WeightInfo::place_decision_deposit_queued()) + .max(T::WeightInfo::place_decision_deposit_not_queued()) + .max(T::WeightInfo::place_decision_deposit_passing()) + .max(T::WeightInfo::place_decision_deposit_failing()) + } +} + +/// Branches that the `one_fewer_deciding` function may take. +pub enum OneFewerDecidingBranch { + QueueEmpty, + BeginDecidingPassing, + BeginDecidingFailing, +} + +impl From for OneFewerDecidingBranch { + fn from(x: BeginDecidingBranch) -> Self { + use BeginDecidingBranch::*; + use OneFewerDecidingBranch::*; + match x { + Passing => BeginDecidingPassing, + Failing => BeginDecidingFailing, + } + } +} + +impl OneFewerDecidingBranch { + /// Return the weight of the `one_fewer_deciding` function when it takes the branch denoted + /// by `self`. + pub fn weight(self) -> frame_support::weights::Weight { + use OneFewerDecidingBranch::*; + match self { + QueueEmpty => T::WeightInfo::one_fewer_deciding_queue_empty(), + BeginDecidingPassing => T::WeightInfo::one_fewer_deciding_passing(), + BeginDecidingFailing => T::WeightInfo::one_fewer_deciding_failing(), + } + } + + /// Return the maximum possible weight of the `one_fewer_deciding` function. + pub fn max_weight() -> frame_support::weights::Weight { + 0.max(T::WeightInfo::one_fewer_deciding_queue_empty()) + .max(T::WeightInfo::one_fewer_deciding_passing()) + .max(T::WeightInfo::one_fewer_deciding_failing()) + } +} diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs new file mode 100644 index 0000000000000..fb8e9aa6a6db7 --- /dev/null +++ b/frame/referenda/src/lib.rs @@ -0,0 +1,1065 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Referenda Pallet +//! +//! ## Overview +//! +//! A pallet for executing referenda. No voting logic is present here, and the `Polling` and +//! `PollStatus` traits are used to allow the voting logic (likely in a pallet) to be utilized. +//! +//! A referendum is a vote on whether a proposal should be dispatched from a particular origin. The +//! origin is used to determine which one of several _tracks_ that a referendum happens under. +//! Tracks each have their own configuration which governs the voting process and parameters. +//! +//! A referendum's lifecycle has three main stages: Preparation, deciding and conclusion. +//! Referenda are considered "ongoing" immediately after submission until their eventual +//! conclusion, and votes may be cast throughout. +//! +//! In order to progress from preparating to being decided, three things must be in place: +//! - There must have been a *Decision Deposit* placed, an amount determined by the track. Anyone +//! may place this deposit. +//! - A period must have elapsed since submission of the referendum. This period is known as the +//! *Preparation Period* and is determined by the track. +//! - The track must not already be at capacity with referendum being decided. The maximum number of +//! referenda which may be being decided simultaneously is determined by the track. +//! +//! In order to become concluded, one of three things must happen: +//! - The referendum should remain in an unbroken _Passing_ state for a period of time. This +//! is known as the _Confirmation Period_ and is determined by the track. A referendum is considered +//! _Passing_ when there is a sufficiently high turnout and approval, given the amount of time it +//! has been being decided. Generally the threshold for what counts as being "sufficiently high" +//! will reduce over time. The curves setting these thresholds are determined by the track. In this +//! case, the referendum is considered _Approved_ and the proposal is scheduled for dispatch. +//! - The referendum reaches the end of its deciding phase outside not _Passing_. It ends in +//! rejection and the proposal is not dispatched. +//! - The referendum is cancelled. +//! +//! A general time-out is also in place and referenda which exist in preparation for too long may +//! conclude without ever entering into a deciding stage. +//! +//! Once a referendum is concluded, the decision deposit may be refunded. +//! +//! - [`Config`] +//! - [`Call`] + +#![recursion_limit = "256"] +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Codec, Encode}; +use frame_support::{ + ensure, + traits::{ + schedule::{ + v2::{Anon as ScheduleAnon, Named as ScheduleNamed}, + DispatchTime, MaybeHashed, + }, + Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, OriginTrait, PollStatus, + Polling, ReservableCurrency, VoteTally, + }, + BoundedVec, +}; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{AtLeast32BitUnsigned, Dispatchable, One, Saturating, Zero}, + DispatchError, Perbill, +}; +use sp_std::{fmt::Debug, prelude::*}; + +mod branch; +mod types; +pub mod weights; +use branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch}; +pub use pallet::*; +pub use types::{ + AtOrAfter, BalanceOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted, + NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, ReferendumInfoOf, + ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, TrackIdOf, TrackInfo, + TrackInfoOf, TracksInfo, VotesOf, +}; +pub use weights::WeightInfo; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +const ASSEMBLY_ID: LockIdentifier = *b"assembly"; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{pallet_prelude::*, traits::EnsureOrigin, Parameter}; + use frame_system::pallet_prelude::*; + use sp_runtime::DispatchResult; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + Sized { + // System level stuff. + type Call: Parameter + Dispatchable + From>; + type Event: From> + IsType<::Event>; + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + /// The Scheduler. + type Scheduler: ScheduleAnon, PalletsOriginOf, Hash = Self::Hash> + + ScheduleNamed, PalletsOriginOf, Hash = Self::Hash>; + /// Currency type for this pallet. + type Currency: ReservableCurrency + + LockableCurrency; + + // Origins and unbalances. + /// Origin from which any vote may be cancelled. + type CancelOrigin: EnsureOrigin; + /// Origin from which any vote may be killed. + type KillOrigin: EnsureOrigin; + /// Handler for the unbalanced reduction when slashing a preimage deposit. + type Slash: OnUnbalanced>; + /// The counting type for votes. Usually just balance. + type Votes: AtLeast32BitUnsigned + Copy + Parameter + Member; + /// The tallying type. + type Tally: VoteTally + Default + Clone + Codec + Eq + Debug + TypeInfo; + + // Constants + /// The minimum amount to be used as a deposit for a public referendum proposal. + #[pallet::constant] + type SubmissionDeposit: Get>; + + /// Maximum size of the referendum queue for a single track. + #[pallet::constant] + type MaxQueued: Get; + + /// The number of blocks after submission that a referendum must begin being decided by. + /// Once this passes, then anyone may cancel the referendum. + #[pallet::constant] + type UndecidingTimeout: Get; + + /// Quantization level for the referendum wakeup scheduler. A higher number will result in + /// fewer storage reads/writes needed for smaller voters, but also result in delays to the + /// automatic referendum status changes. Explicit servicing instructions are unaffected. + #[pallet::constant] + type AlarmInterval: Get; + + // The other stuff. + /// Information concerning the different referendum tracks. + type Tracks: TracksInfo< + BalanceOf, + Self::BlockNumber, + Origin = ::PalletsOrigin, + >; + } + + /// The next free referendum index, aka the number of referenda started so far. + #[pallet::storage] + pub type ReferendumCount = StorageValue<_, ReferendumIndex, ValueQuery>; + + /// Information concerning any given referendum. + /// + /// TWOX-NOTE: SAFE as indexes are not under an attacker’s control. + #[pallet::storage] + pub type ReferendumInfoFor = + StorageMap<_, Blake2_128Concat, ReferendumIndex, ReferendumInfoOf>; + + /// The sorted list of referenda ready to be decided but not yet being decided, ordered by + /// conviction-weighted approvals. + /// + /// This should be empty if `DecidingCount` is less than `TrackInfo::max_deciding`. + #[pallet::storage] + pub type TrackQueue = StorageMap< + _, + Twox64Concat, + TrackIdOf, + BoundedVec<(ReferendumIndex, T::Votes), T::MaxQueued>, + ValueQuery, + >; + + /// The number of referenda being decided currently. + #[pallet::storage] + pub type DecidingCount = StorageMap<_, Twox64Concat, TrackIdOf, u32, ValueQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A referendum has being submitted. + Submitted { + /// Index of the referendum. + index: ReferendumIndex, + /// The track (and by extension proposal dispatch origin) of this referendum. + track: TrackIdOf, + /// The hash of the proposal up for referendum. + proposal_hash: T::Hash, + }, + /// The decision deposit has been placed. + DecisionDepositPlaced { + /// Index of the referendum. + index: ReferendumIndex, + /// The account who placed the deposit. + who: T::AccountId, + /// The amount placed by the account. + amount: BalanceOf, + }, + /// The decision deposit has been refunded. + DecisionDepositRefunded { + /// Index of the referendum. + index: ReferendumIndex, + /// The account who placed the deposit. + who: T::AccountId, + /// The amount placed by the account. + amount: BalanceOf, + }, + /// A deposit has been slashaed. + DepositSlashed { + /// The account who placed the deposit. + who: T::AccountId, + /// The amount placed by the account. + amount: BalanceOf, + }, + /// A referendum has moved into the deciding phase. + DecisionStarted { + /// Index of the referendum. + index: ReferendumIndex, + /// The track (and by extension proposal dispatch origin) of this referendum. + track: TrackIdOf, + /// The hash of the proposal up for referendum. + proposal_hash: T::Hash, + /// The current tally of votes in this referendum. + tally: T::Tally, + }, + ConfirmStarted { + /// Index of the referendum. + index: ReferendumIndex, + }, + ConfirmAborted { + /// Index of the referendum. + index: ReferendumIndex, + }, + /// A referendum has ended its confirmation phase and is ready for approval. + Confirmed { + /// Index of the referendum. + index: ReferendumIndex, + /// The final tally of votes in this referendum. + tally: T::Tally, + }, + /// A referendum has been approved and its proposal has been scheduled. + Approved { + /// Index of the referendum. + index: ReferendumIndex, + }, + /// A proposal has been rejected by referendum. + Rejected { + /// Index of the referendum. + index: ReferendumIndex, + /// The final tally of votes in this referendum. + tally: T::Tally, + }, + /// A referendum has been timed out without being decided. + TimedOut { + /// Index of the referendum. + index: ReferendumIndex, + /// The final tally of votes in this referendum. + tally: T::Tally, + }, + /// A referendum has been cancelled. + Cancelled { + /// Index of the referendum. + index: ReferendumIndex, + /// The final tally of votes in this referendum. + tally: T::Tally, + }, + /// A referendum has been killed. + Killed { + /// Index of the referendum. + index: ReferendumIndex, + /// The final tally of votes in this referendum. + tally: T::Tally, + }, + } + + #[pallet::error] + pub enum Error { + /// Referendum is not ongoing. + NotOngoing, + /// Referendum's decision deposit is already paid. + HaveDeposit, + /// The track identifier given was invalid. + BadTrack, + /// There are already a full complement of referendums in progress for this track. + Full, + /// The queue of the track is empty. + QueueEmpty, + /// The referendum index provided is invalid in this context. + BadReferendum, + /// There was nothing to do in the advancement. + NothingToDo, + /// No track exists for the proposal origin. + NoTrack, + /// Any deposit cannot be refunded until after the decision is over. + Unfinished, + /// The deposit refunder is not the depositor. + NoPermission, + /// The deposit cannot be refunded since none was made. + NoDeposit, + } + + #[pallet::call] + impl Pallet { + /// Propose a referendum on a privileged action. + /// + /// - `origin`: must be `Signed` and the account must have `SubmissionDeposit` funds + /// available. + /// - `proposal_origin`: The origin from which the proposal should be executed. + /// - `proposal_hash`: The hash of the proposal preimage. + /// - `enactment_moment`: The moment that the proposal should be enacted. + /// + /// Emits `Submitted`. + #[pallet::weight(T::WeightInfo::submit())] + pub fn submit( + origin: OriginFor, + proposal_origin: PalletsOriginOf, + proposal_hash: T::Hash, + enactment_moment: AtOrAfter, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + let track = T::Tracks::track_for(&proposal_origin).map_err(|_| Error::::NoTrack)?; + let submission_deposit = Self::take_deposit(who, T::SubmissionDeposit::get())?; + let index = ReferendumCount::::mutate(|x| { + let r = *x; + *x += 1; + r + }); + let now = frame_system::Pallet::::block_number(); + let nudge_call = Call::nudge_referendum { index }; + let status = ReferendumStatus { + track, + origin: proposal_origin, + proposal_hash: proposal_hash.clone(), + enactment: enactment_moment, + submitted: now, + submission_deposit, + decision_deposit: None, + deciding: None, + tally: Default::default(), + in_queue: false, + alarm: Self::set_alarm(nudge_call, now.saturating_add(T::UndecidingTimeout::get())), + }; + ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); + + Self::deposit_event(Event::::Submitted { index, track, proposal_hash }); + Ok(()) + } + + /// Post the Decision Deposit for a referendum. + /// + /// - `origin`: must be `Signed` and the account must have funds available for the + /// referendum's track's Decision Deposit. + /// - `index`: The index of the submitted referendum whose Decision Deposit is yet to be + /// posted. + /// + /// Emits `DecisionDepositPlaced`. + #[pallet::weight(ServiceBranch::max_weight_of_deposit::())] + pub fn place_decision_deposit( + origin: OriginFor, + index: ReferendumIndex, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + let mut status = Self::ensure_ongoing(index)?; + ensure!(status.decision_deposit.is_none(), Error::::HaveDeposit); + let track = Self::track(status.track).ok_or(Error::::NoTrack)?; + status.decision_deposit = + Some(Self::take_deposit(who.clone(), track.decision_deposit)?); + let now = frame_system::Pallet::::block_number(); + let (info, _, branch) = Self::service_referendum(now, index, status); + ReferendumInfoFor::::insert(index, info); + let e = + Event::::DecisionDepositPlaced { index, who, amount: track.decision_deposit }; + Self::deposit_event(e); + Ok(branch.weight_of_deposit::().into()) + } + + /// Refund the Decision Deposit for a closed referendum back to the depositor. + /// + /// - `origin`: must be `Signed` or `Root`. + /// - `index`: The index of a closed referendum whose Decision Deposit has not yet been + /// refunded. + /// + /// Emits `DecisionDepositRefunded`. + #[pallet::weight(T::WeightInfo::refund_decision_deposit())] + pub fn refund_decision_deposit( + origin: OriginFor, + index: ReferendumIndex, + ) -> DispatchResult { + ensure_signed_or_root(origin)?; + let mut info = ReferendumInfoFor::::get(index).ok_or(Error::::BadReferendum)?; + let deposit = info + .take_decision_deposit() + .map_err(|_| Error::::Unfinished)? + .ok_or(Error::::NoDeposit)?; + Self::refund_deposit(Some(deposit.clone())); + ReferendumInfoFor::::insert(index, info); + let e = Event::::DecisionDepositRefunded { + index, + who: deposit.who, + amount: deposit.amount, + }; + Self::deposit_event(e); + Ok(()) + } + + /// Cancel an ongoing referendum. + /// + /// - `origin`: must be the `CancelOrigin`. + /// - `index`: The index of the referendum to be cancelled. + /// + /// Emits `Cancelled`. + #[pallet::weight(T::WeightInfo::cancel())] + pub fn cancel(origin: OriginFor, index: ReferendumIndex) -> DispatchResult { + T::CancelOrigin::ensure_origin(origin)?; + let status = Self::ensure_ongoing(index)?; + if let Some((_, last_alarm)) = status.alarm { + let _ = T::Scheduler::cancel(last_alarm); + } + Self::note_one_fewer_deciding(status.track); + Self::deposit_event(Event::::Cancelled { index, tally: status.tally }); + let info = ReferendumInfo::Cancelled( + frame_system::Pallet::::block_number(), + status.submission_deposit, + status.decision_deposit, + ); + ReferendumInfoFor::::insert(index, info); + Ok(()) + } + + /// Cancel an ongoing referendum and slash the deposits. + /// + /// - `origin`: must be the `KillOrigin`. + /// - `index`: The index of the referendum to be cancelled. + /// + /// Emits `Killed` and `DepositSlashed`. + #[pallet::weight(T::WeightInfo::kill())] + pub fn kill(origin: OriginFor, index: ReferendumIndex) -> DispatchResult { + T::KillOrigin::ensure_origin(origin)?; + let status = Self::ensure_ongoing(index)?; + if let Some((_, last_alarm)) = status.alarm { + let _ = T::Scheduler::cancel(last_alarm); + } + Self::note_one_fewer_deciding(status.track); + Self::deposit_event(Event::::Killed { index, tally: status.tally }); + Self::slash_deposit(Some(status.submission_deposit.clone())); + Self::slash_deposit(status.decision_deposit.clone()); + let info = ReferendumInfo::Killed(frame_system::Pallet::::block_number()); + ReferendumInfoFor::::insert(index, info); + Ok(()) + } + + /// Advance a referendum onto its next logical state. Only used internally. + /// + /// - `origin`: must be `Root`. + /// - `index`: the referendum to be advanced. + #[pallet::weight(ServiceBranch::max_weight_of_nudge::())] + pub fn nudge_referendum( + origin: OriginFor, + index: ReferendumIndex, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + let now = frame_system::Pallet::::block_number(); + let mut status = Self::ensure_ongoing(index)?; + // This is our wake-up, so we can disregard the alarm. + status.alarm = None; + let (info, dirty, branch) = Self::service_referendum(now, index, status); + if dirty { + ReferendumInfoFor::::insert(index, info); + } + Ok(Some(branch.weight_of_nudge::()).into()) + } + + /// Advance a track onto its next logical state. Only used internally. + /// + /// - `origin`: must be `Root`. + /// - `track`: the track to be advanced. + /// + /// Action item for when there is now one fewer referendum in the deciding phase and the + /// `DecidingCount` is not yet updated. This means that we should either: + /// - begin deciding another referendum (and leave `DecidingCount` alone); or + /// - decrement `DecidingCount`. + #[pallet::weight(OneFewerDecidingBranch::max_weight::())] + pub fn one_fewer_deciding( + origin: OriginFor, + track: TrackIdOf, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + let track_info = T::Tracks::info(track).ok_or(Error::::BadTrack)?; + let mut track_queue = TrackQueue::::get(track); + let branch = + if let Some((index, mut status)) = Self::next_for_deciding(&mut track_queue) { + let now = frame_system::Pallet::::block_number(); + let (maybe_alarm, branch) = + Self::begin_deciding(&mut status, index, now, track_info); + if let Some(set_alarm) = maybe_alarm { + Self::ensure_alarm_at(&mut status, index, set_alarm); + } + ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); + TrackQueue::::insert(track, track_queue); + branch.into() + } else { + DecidingCount::::mutate(track, |x| x.saturating_dec()); + OneFewerDecidingBranch::QueueEmpty + }; + Ok(Some(branch.weight::()).into()) + } + } +} + +impl Polling for Pallet { + type Index = ReferendumIndex; + type Votes = VotesOf; + type Moment = T::BlockNumber; + type Class = TrackIdOf; + + fn classes() -> Vec { + T::Tracks::tracks().iter().map(|x| x.0).collect() + } + + fn access_poll( + index: Self::Index, + f: impl FnOnce(PollStatus<&mut T::Tally, T::BlockNumber, TrackIdOf>) -> R, + ) -> R { + match ReferendumInfoFor::::get(index) { + Some(ReferendumInfo::Ongoing(mut status)) => { + let result = f(PollStatus::Ongoing(&mut status.tally, status.track)); + let now = frame_system::Pallet::::block_number(); + Self::ensure_alarm_at(&mut status, index, now + One::one()); + ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); + result + }, + Some(ReferendumInfo::Approved(end, ..)) => f(PollStatus::Completed(end, true)), + Some(ReferendumInfo::Rejected(end, ..)) => f(PollStatus::Completed(end, false)), + _ => f(PollStatus::None), + } + } + + fn try_access_poll( + index: Self::Index, + f: impl FnOnce( + PollStatus<&mut T::Tally, T::BlockNumber, TrackIdOf>, + ) -> Result, + ) -> Result { + match ReferendumInfoFor::::get(index) { + Some(ReferendumInfo::Ongoing(mut status)) => { + let result = f(PollStatus::Ongoing(&mut status.tally, status.track))?; + let now = frame_system::Pallet::::block_number(); + Self::ensure_alarm_at(&mut status, index, now + One::one()); + ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); + Ok(result) + }, + Some(ReferendumInfo::Approved(end, ..)) => f(PollStatus::Completed(end, true)), + Some(ReferendumInfo::Rejected(end, ..)) => f(PollStatus::Completed(end, false)), + _ => f(PollStatus::None), + } + } + + fn as_ongoing(index: Self::Index) -> Option<(T::Tally, TrackIdOf)> { + Self::ensure_ongoing(index).ok().map(|x| (x.tally, x.track)) + } + + #[cfg(feature = "runtime-benchmarks")] + fn create_ongoing(class: Self::Class) -> Result { + let index = ReferendumCount::::mutate(|x| { + let r = *x; + *x += 1; + r + }); + let now = frame_system::Pallet::::block_number(); + let dummy_account_id = + codec::Decode::decode(&mut sp_runtime::traits::TrailingZeroInput::new(&b"dummy"[..])) + .expect("infinite length input; no invalid inputs for type; qed"); + let mut status = ReferendumStatusOf:: { + track: class, + origin: frame_support::dispatch::RawOrigin::Root.into(), + proposal_hash: ::hash_of(&index), + enactment: AtOrAfter::After(Zero::zero()), + submitted: now, + submission_deposit: Deposit { who: dummy_account_id, amount: Zero::zero() }, + decision_deposit: None, + deciding: None, + tally: Default::default(), + in_queue: false, + alarm: None, + }; + Self::ensure_alarm_at(&mut status, index, sp_runtime::traits::Bounded::max_value()); + ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); + Ok(index) + } + + #[cfg(feature = "runtime-benchmarks")] + fn end_ongoing(index: Self::Index, approved: bool) -> Result<(), ()> { + let mut status = Self::ensure_ongoing(index).map_err(|_| ())?; + Self::ensure_no_alarm(&mut status); + Self::note_one_fewer_deciding(status.track); + let now = frame_system::Pallet::::block_number(); + let info = if approved { + ReferendumInfo::Approved(now, status.submission_deposit, status.decision_deposit) + } else { + ReferendumInfo::Rejected(now, status.submission_deposit, status.decision_deposit) + }; + ReferendumInfoFor::::insert(index, info); + Ok(()) + } + + #[cfg(feature = "runtime-benchmarks")] + fn max_ongoing() -> (Self::Class, u32) { + let r = T::Tracks::tracks() + .iter() + .max_by_key(|(_, info)| info.max_deciding) + .expect("Always one class"); + (r.0.clone(), r.1.max_deciding) + } +} + +impl Pallet { + /// Check that referendum `index` is in the `Ongoing` state and return the `ReferendumStatus` + /// value, or `Err` otherwise. + pub fn ensure_ongoing(index: ReferendumIndex) -> Result, DispatchError> { + match ReferendumInfoFor::::get(index) { + Some(ReferendumInfo::Ongoing(status)) => Ok(status), + _ => Err(Error::::NotOngoing.into()), + } + } + + // Enqueue a proposal from a referendum which has presumably passed. + fn schedule_enactment( + index: ReferendumIndex, + track: &TrackInfoOf, + desired: AtOrAfter, + origin: PalletsOriginOf, + call_hash: T::Hash, + ) { + let now = frame_system::Pallet::::block_number(); + let earliest_allowed = now.saturating_add(track.min_enactment_period); + let desired = desired.evaluate(now); + let ok = T::Scheduler::schedule_named( + (ASSEMBLY_ID, "enactment", index).encode(), + DispatchTime::At(desired.max(earliest_allowed)), + None, + 63, + origin, + MaybeHashed::Hash(call_hash), + ) + .is_ok(); + debug_assert!(ok, "LOGIC ERROR: bake_referendum/schedule_named failed"); + } + + /// Set an alarm to dispatch `call` at block number `when`. + fn set_alarm( + call: impl Into>, + when: T::BlockNumber, + ) -> Option<(T::BlockNumber, ScheduleAddressOf)> { + let alarm_interval = T::AlarmInterval::get().max(One::one()); + let when = (when + alarm_interval - One::one()) / alarm_interval * alarm_interval; + let maybe_result = T::Scheduler::schedule( + DispatchTime::At(when), + None, + 128u8, + frame_system::RawOrigin::Root.into(), + MaybeHashed::Value(call.into()), + ) + .ok() + .map(|x| (when, x)); + debug_assert!( + maybe_result.is_some(), + "Unable to schedule a new alarm at #{:?} (now: #{:?})?!", + when, + frame_system::Pallet::::block_number() + ); + maybe_result + } + + /// Mutate a referendum's `status` into the correct deciding state. + /// + /// - `now` is the current block number. + /// - `track` is the track info for the referendum. + /// + /// This will properly set up the `confirming` item. + fn begin_deciding( + status: &mut ReferendumStatusOf, + index: ReferendumIndex, + now: T::BlockNumber, + track: &TrackInfoOf, + ) -> (Option, BeginDecidingBranch) { + let is_passing = Self::is_passing( + &status.tally, + Zero::zero(), + track.decision_period, + &track.min_turnout, + &track.min_approval, + ); + status.in_queue = false; + Self::deposit_event(Event::::DecisionStarted { + index, + tally: status.tally.clone(), + proposal_hash: status.proposal_hash.clone(), + track: status.track.clone(), + }); + let confirming = if is_passing { + Self::deposit_event(Event::::ConfirmStarted { index }); + Some(now.saturating_add(track.confirm_period)) + } else { + None + }; + let deciding_status = DecidingStatus { since: now, confirming }; + let alarm = Self::decision_time(&deciding_status, &status.tally, track); + status.deciding = Some(deciding_status); + let branch = + if is_passing { BeginDecidingBranch::Passing } else { BeginDecidingBranch::Failing }; + (Some(alarm), branch) + } + + /// If it returns `Some`, deciding has begun and it needs waking at the given block number. The + /// second item is the flag for whether it is confirming or not. + /// + /// If `None`, then it is queued and should be nudged automatically as the queue gets drained. + fn ready_for_deciding( + now: T::BlockNumber, + track: &TrackInfoOf, + index: ReferendumIndex, + status: &mut ReferendumStatusOf, + ) -> (Option, ServiceBranch) { + let deciding_count = DecidingCount::::get(status.track); + if deciding_count < track.max_deciding { + // Begin deciding. + DecidingCount::::insert(status.track, deciding_count.saturating_add(1)); + let r = Self::begin_deciding(status, index, now, track); + (r.0, r.1.into()) + } else { + // Add to queue. + let item = (index, status.tally.ayes()); + status.in_queue = true; + TrackQueue::::mutate(status.track, |q| q.insert_sorted_by_key(item, |x| x.1)); + (None, ServiceBranch::Queued) + } + } + + /// Grab the index and status for the referendum which is the highest priority of those for the + /// given track which are ready for being decided. + fn next_for_deciding( + track_queue: &mut BoundedVec<(u32, VotesOf), T::MaxQueued>, + ) -> Option<(ReferendumIndex, ReferendumStatusOf)> { + loop { + let (index, _) = track_queue.pop()?; + match Self::ensure_ongoing(index) { + Ok(s) => return Some((index, s)), + Err(_) => {}, // referendum already timedout or was cancelled. + } + } + } + + /// Schedule a call to `one_fewer_deciding` function via the dispatchable + /// `defer_one_fewer_deciding`. We could theoretically call it immediately (and it would be + /// overall more efficient), however the weights become rather less easy to measure. + fn note_one_fewer_deciding(track: TrackIdOf) { + // Set an alarm call for the next block to nudge the track along. + let now = frame_system::Pallet::::block_number(); + let next_block = now + One::one(); + let alarm_interval = T::AlarmInterval::get().max(One::one()); + let when = (next_block + alarm_interval - One::one()) / alarm_interval * alarm_interval; + + let maybe_result = T::Scheduler::schedule( + DispatchTime::At(when), + None, + 128u8, + frame_system::RawOrigin::Root.into(), + MaybeHashed::Value(Call::one_fewer_deciding { track }.into()), + ); + debug_assert!( + maybe_result.is_ok(), + "Unable to schedule a new alarm at #{:?} (now: #{:?})?!", + when, + now + ); + } + + /// Ensure that a `service_referendum` alarm happens for the referendum `index` at `alarm`. + /// + /// This will do nothing if the alarm is already set. + /// + /// Returns `false` if nothing changed. + fn ensure_alarm_at( + status: &mut ReferendumStatusOf, + index: ReferendumIndex, + alarm: T::BlockNumber, + ) -> bool { + if status.alarm.as_ref().map_or(true, |&(when, _)| when != alarm) { + // Either no alarm or one that was different + Self::ensure_no_alarm(status); + status.alarm = Self::set_alarm(Call::nudge_referendum { index }, alarm); + true + } else { + false + } + } + + /// Advance the state of a referendum, which comes down to: + /// - If it's ready to be decided, start deciding; + /// - If it's not ready to be decided and non-deciding timeout has passed, fail; + /// - If it's ongoing and passing, ensure confirming; if at end of confirmation period, pass. + /// - If it's ongoing and not passing, stop confirning; if it has reached end time, fail. + /// + /// Weight will be a bit different depending on what it does, but it's designed so as not to + /// differ dramatically, especially if `MaxQueue` is kept small. In particular _there are no + /// balance operations in here_. + /// + /// In terms of storage, every call to it is expected to access: + /// - The scheduler, either to insert, remove or alter an entry; + /// - `TrackQueue`, which should be a `BoundedVec` with a low limit (8-16). + /// - `DecidingCount`. + /// + /// Both of the two storage items will only have as many items as there are different tracks, + /// perhaps around 10 and should be whitelisted. + /// + /// The heaviest branch is likely to be when a proposal is placed into, or moved within, the + /// `TrackQueue`. Basically this happens when a referendum is in the deciding queue and receives + /// a vote, or when it moves into the deciding queue. + fn service_referendum( + now: T::BlockNumber, + index: ReferendumIndex, + mut status: ReferendumStatusOf, + ) -> (ReferendumInfoOf, bool, ServiceBranch) { + let mut dirty = false; + // Should it begin being decided? + let track = match Self::track(status.track) { + Some(x) => x, + None => return (ReferendumInfo::Ongoing(status), false, ServiceBranch::Fail), + }; + let timeout = status.submitted + T::UndecidingTimeout::get(); + // Default the alarm to the submission timeout. + let mut alarm = timeout; + let branch; + match &mut status.deciding { + None => { + // Are we already queued for deciding? + if status.in_queue { + // Does our position in the queue need updating? + let ayes = status.tally.ayes(); + let mut queue = TrackQueue::::get(status.track); + let maybe_old_pos = queue.iter().position(|(x, _)| *x == index); + let new_pos = queue.binary_search_by_key(&ayes, |x| x.1).unwrap_or_else(|x| x); + branch = if maybe_old_pos.is_none() && new_pos > 0 { + // Just insert. + queue.force_insert_keep_right(new_pos, (index, ayes)); + ServiceBranch::RequeuedInsertion + } else if let Some(old_pos) = maybe_old_pos { + // We were in the queue - slide into the correct position. + queue[old_pos].1 = ayes; + queue.slide(old_pos, new_pos); + ServiceBranch::RequeuedSlide + } else { + ServiceBranch::NotQueued + }; + TrackQueue::::insert(status.track, queue); + } else { + // Are we ready for deciding? + branch = if status.decision_deposit.is_some() { + let prepare_end = status.submitted.saturating_add(track.prepare_period); + if now >= prepare_end { + let (maybe_alarm, branch) = + Self::ready_for_deciding(now, &track, index, &mut status); + if let Some(set_alarm) = maybe_alarm { + alarm = alarm.min(set_alarm); + } + dirty = true; + branch + } else { + alarm = alarm.min(prepare_end); + ServiceBranch::Preparing + } + } else { + ServiceBranch::NoDeposit + } + } + // If we didn't move into being decided, then check the timeout. + if status.deciding.is_none() && now >= timeout { + // Too long without being decided - end it. + Self::ensure_no_alarm(&mut status); + Self::deposit_event(Event::::TimedOut { index, tally: status.tally }); + return ( + ReferendumInfo::TimedOut( + now, + status.submission_deposit, + status.decision_deposit, + ), + true, + ServiceBranch::TimedOut, + ) + } + }, + Some(deciding) => { + let is_passing = Self::is_passing( + &status.tally, + now.saturating_sub(deciding.since), + track.decision_period, + &track.min_turnout, + &track.min_approval, + ); + branch = if is_passing { + match deciding.confirming.clone() { + Some(t) if now >= t => { + // Passed! + Self::ensure_no_alarm(&mut status); + Self::note_one_fewer_deciding(status.track); + let (desired, call_hash) = (status.enactment, status.proposal_hash); + Self::schedule_enactment( + index, + track, + desired, + status.origin, + call_hash, + ); + Self::deposit_event(Event::::Confirmed { + index, + tally: status.tally, + }); + return ( + ReferendumInfo::Approved( + now, + status.submission_deposit, + status.decision_deposit, + ), + true, + ServiceBranch::Approved, + ) + }, + Some(_) => ServiceBranch::ContinueConfirming, + None => { + // Start confirming + dirty = true; + deciding.confirming = Some(now.saturating_add(track.confirm_period)); + Self::deposit_event(Event::::ConfirmStarted { index }); + ServiceBranch::BeginConfirming + }, + } + } else { + if now >= deciding.since.saturating_add(track.decision_period) { + // Failed! + Self::ensure_no_alarm(&mut status); + Self::note_one_fewer_deciding(status.track); + Self::deposit_event(Event::::Rejected { index, tally: status.tally }); + return ( + ReferendumInfo::Rejected( + now, + status.submission_deposit, + status.decision_deposit, + ), + true, + ServiceBranch::Rejected, + ) + } + if deciding.confirming.is_some() { + // Stop confirming + dirty = true; + deciding.confirming = None; + Self::deposit_event(Event::::ConfirmAborted { index }); + ServiceBranch::EndConfirming + } else { + ServiceBranch::ContinueNotConfirming + } + }; + alarm = Self::decision_time(&deciding, &status.tally, track); + }, + } + + let dirty_alarm = Self::ensure_alarm_at(&mut status, index, alarm); + (ReferendumInfo::Ongoing(status), dirty_alarm || dirty, branch) + } + + /// Determine the point at which a referendum will be accepted, move into confirmation with the + /// given `tally` or end with rejection (whichever happens sooner). + fn decision_time( + deciding: &DecidingStatusOf, + tally: &T::Tally, + track: &TrackInfoOf, + ) -> T::BlockNumber { + deciding.confirming.unwrap_or_else(|| { + // Set alarm to the point where the current voting would make it pass. + let approval = tally.approval(); + let turnout = tally.turnout(); + let until_approval = track.min_approval.delay(approval); + let until_turnout = track.min_turnout.delay(turnout); + let offset = until_turnout.max(until_approval); + deciding.since.saturating_add(offset * track.decision_period) + }) + } + + /// Cancel the alarm in `status`, if one exists. + fn ensure_no_alarm(status: &mut ReferendumStatusOf) { + if let Some((_, last_alarm)) = status.alarm.take() { + // Incorrect alarm - cancel it. + let _ = T::Scheduler::cancel(last_alarm); + } + } + + /// Reserve a deposit and return the `Deposit` instance. + fn take_deposit( + who: T::AccountId, + amount: BalanceOf, + ) -> Result>, DispatchError> { + T::Currency::reserve(&who, amount)?; + Ok(Deposit { who, amount }) + } + + /// Return a deposit, if `Some`. + fn refund_deposit(deposit: Option>>) { + if let Some(Deposit { who, amount }) = deposit { + T::Currency::unreserve(&who, amount); + } + } + + /// Slash a deposit, if `Some`. + fn slash_deposit(deposit: Option>>) { + if let Some(Deposit { who, amount }) = deposit { + T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); + Self::deposit_event(Event::::DepositSlashed { who, amount }); + } + } + + /// Get the track info value for the track `id`. + fn track(id: TrackIdOf) -> Option<&'static TrackInfoOf> { + let tracks = T::Tracks::tracks(); + let index = tracks.binary_search_by_key(&id, |x| x.0).unwrap_or_else(|x| x); + Some(&tracks[index].1) + } + + /// Determine whether the given `tally` would result in a referendum passing at `elapsed` blocks + /// into a total decision `period`, given the two curves for `turnout_needed` and + /// `approval_needed`. + fn is_passing( + tally: &T::Tally, + elapsed: T::BlockNumber, + period: T::BlockNumber, + turnout_needed: &Curve, + approval_needed: &Curve, + ) -> bool { + let x = Perbill::from_rational(elapsed.min(period), period); + turnout_needed.passing(x, tally.turnout()) && approval_needed.passing(x, tally.approval()) + } +} diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs new file mode 100644 index 0000000000000..063b124f2b71f --- /dev/null +++ b/frame/referenda/src/mock.rs @@ -0,0 +1,460 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The crate's tests. + +use super::*; +use crate as pallet_referenda; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + assert_ok, ord_parameter_types, parameter_types, + traits::{ + ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling, + PreimageRecipient, SortedMembers, + }, + weights::Weight, +}; +use frame_system::{EnsureRoot, EnsureSignedBy}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, Hash, IdentityLookup}, + DispatchResult, Perbill, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Balances: pallet_balances, + Preimage: pallet_preimage, + Scheduler: pallet_scheduler, + Referenda: pallet_referenda, + } +); + +// Test that a fitlered call can be dispatched. +pub struct BaseFilter; +impl Contains for BaseFilter { + fn contains(call: &Call) -> bool { + !matches!(call, &Call::Balances(pallet_balances::Call::set_balance { .. })) + } +} + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(1_000_000); +} +impl frame_system::Config for Test { + type BaseCallFilter = BaseFilter; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = Call; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} +impl pallet_preimage::Config for Test { + type Event = Event; + type WeightInfo = (); + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type MaxSize = ConstU32<4096>; + type BaseDeposit = (); + type ByteDeposit = (); +} +parameter_types! { + pub MaximumSchedulerWeight: Weight = 2_000_000_000_000; +} +impl pallet_scheduler::Config for Test { + type Event = Event; + type Origin = Origin; + type PalletsOrigin = OriginCaller; + type Call = Call; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = ConstU32<100>; + type WeightInfo = (); + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type PreimageProvider = Preimage; + type NoPreimagePostponement = ConstU64<10>; +} +parameter_types! { + pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 10; +} +impl pallet_balances::Config for Test { + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type MaxLocks = MaxLocks; + type Balance = u64; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} +parameter_types! { + pub static AlarmInterval: u64 = 1; + pub const SubmissionDeposit: u64 = 2; + pub const MaxQueued: u32 = 3; + pub const UndecidingTimeout: u64 = 20; +} +ord_parameter_types! { + pub const One: u64 = 1; + pub const Two: u64 = 2; + pub const Three: u64 = 3; + pub const Four: u64 = 4; + pub const Five: u64 = 5; + pub const Six: u64 = 6; +} +pub struct OneToFive; +impl SortedMembers for OneToFive { + fn sorted_members() -> Vec { + vec![1, 2, 3, 4, 5] + } + #[cfg(feature = "runtime-benchmarks")] + fn add(_m: &u64) {} +} + +pub struct TestTracksInfo; +impl TracksInfo for TestTracksInfo { + type Id = u8; + type Origin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, TrackInfo)] { + static DATA: [(u8, TrackInfo); 2] = [ + ( + 0u8, + TrackInfo { + name: "root", + max_deciding: 1, + decision_deposit: 10, + prepare_period: 4, + decision_period: 4, + confirm_period: 2, + min_enactment_period: 4, + min_approval: Curve::LinearDecreasing { + begin: Perbill::from_percent(100), + delta: Perbill::from_percent(50), + }, + min_turnout: Curve::LinearDecreasing { + begin: Perbill::from_percent(100), + delta: Perbill::from_percent(100), + }, + }, + ), + ( + 1u8, + TrackInfo { + name: "none", + max_deciding: 3, + decision_deposit: 1, + prepare_period: 2, + decision_period: 2, + confirm_period: 1, + min_enactment_period: 2, + min_approval: Curve::LinearDecreasing { + begin: Perbill::from_percent(55), + delta: Perbill::from_percent(5), + }, + min_turnout: Curve::LinearDecreasing { + begin: Perbill::from_percent(10), + delta: Perbill::from_percent(10), + }, + }, + ), + ]; + &DATA[..] + } + fn track_for(id: &Self::Origin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => Ok(0), + frame_system::RawOrigin::None => Ok(1), + _ => Err(()), + } + } else { + Err(()) + } + } +} + +impl Config for Test { + type WeightInfo = (); + type Call = Call; + type Event = Event; + type Scheduler = Scheduler; + type Currency = pallet_balances::Pallet; + type CancelOrigin = EnsureSignedBy; + type KillOrigin = EnsureRoot; + type Slash = (); + type Votes = u32; + type Tally = Tally; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = MaxQueued; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TestTracksInfo; +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let balances = vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100), (6, 100)]; + pallet_balances::GenesisConfig:: { balances } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +/// Execute the function two times, with `true` and with `false`. +#[allow(dead_code)] +pub fn new_test_ext_execute_with_cond(execute: impl FnOnce(bool) -> () + Clone) { + new_test_ext().execute_with(|| (execute.clone())(false)); + new_test_ext().execute_with(|| execute(true)); +} + +#[derive(Encode, Debug, Decode, TypeInfo, Eq, PartialEq, Clone, Default, MaxEncodedLen)] +pub struct Tally { + pub ayes: u32, + pub nays: u32, +} + +impl VoteTally for Tally { + fn ayes(&self) -> u32 { + self.ayes + } + + fn turnout(&self) -> Perbill { + Perbill::from_percent(self.ayes + self.nays) + } + + fn approval(&self) -> Perbill { + Perbill::from_rational(self.ayes, self.ayes + self.nays) + } + + #[cfg(feature = "runtime-benchmarks")] + fn unanimity() -> Self { + Self { ayes: 100, nays: 0 } + } + + #[cfg(feature = "runtime-benchmarks")] + fn from_requirements(turnout: Perbill, approval: Perbill) -> Self { + let turnout = turnout.mul_ceil(100u32); + let ayes = approval.mul_ceil(turnout); + Self { ayes, nays: turnout - ayes } + } +} + +pub fn set_balance_proposal(value: u64) -> Vec { + Call::Balances(pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 }) + .encode() +} + +pub fn set_balance_proposal_hash(value: u64) -> H256 { + let c = Call::Balances(pallet_balances::Call::set_balance { + who: 42, + new_free: value, + new_reserved: 0, + }); + >::note_preimage(c.encode().try_into().unwrap()); + BlakeTwo256::hash_of(&c) +} + +#[allow(dead_code)] +pub fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult { + Referenda::submit( + Origin::signed(who), + frame_system::RawOrigin::Root.into(), + set_balance_proposal_hash(value), + AtOrAfter::After(delay), + ) +} + +pub fn next_block() { + System::set_block_number(System::block_number() + 1); + Scheduler::on_initialize(System::block_number()); +} + +pub fn run_to(n: u64) { + while System::block_number() < n { + next_block(); + } +} + +#[allow(dead_code)] +pub fn begin_referendum() -> ReferendumIndex { + System::set_block_number(0); + assert_ok!(propose_set_balance(1, 2, 1)); + run_to(2); + 0 +} + +#[allow(dead_code)] +pub fn tally(r: ReferendumIndex) -> Tally { + Referenda::ensure_ongoing(r).unwrap().tally +} + +pub fn set_tally(index: ReferendumIndex, ayes: u32, nays: u32) { + >::access_poll(index, |status| { + let tally = status.ensure_ongoing().unwrap().0; + tally.ayes = ayes; + tally.nays = nays; + }); +} + +pub fn waiting_since(i: ReferendumIndex) -> u64 { + match ReferendumInfoFor::::get(i).unwrap() { + ReferendumInfo::Ongoing(ReferendumStatus { submitted, deciding: None, .. }) => submitted, + _ => panic!("Not waiting"), + } +} + +pub fn deciding_since(i: ReferendumIndex) -> u64 { + match ReferendumInfoFor::::get(i).unwrap() { + ReferendumInfo::Ongoing(ReferendumStatus { + deciding: Some(DecidingStatus { since, .. }), + .. + }) => since, + _ => panic!("Not deciding"), + } +} + +pub fn deciding_and_failing_since(i: ReferendumIndex) -> u64 { + match ReferendumInfoFor::::get(i).unwrap() { + ReferendumInfo::Ongoing(ReferendumStatus { + deciding: Some(DecidingStatus { since, confirming: None, .. }), + .. + }) => since, + _ => panic!("Not deciding"), + } +} + +pub fn confirming_until(i: ReferendumIndex) -> u64 { + match ReferendumInfoFor::::get(i).unwrap() { + ReferendumInfo::Ongoing(ReferendumStatus { + deciding: Some(DecidingStatus { confirming: Some(until), .. }), + .. + }) => until, + _ => panic!("Not confirming"), + } +} + +pub fn approved_since(i: ReferendumIndex) -> u64 { + match ReferendumInfoFor::::get(i).unwrap() { + ReferendumInfo::Approved(since, ..) => since, + _ => panic!("Not approved"), + } +} + +pub fn rejected_since(i: ReferendumIndex) -> u64 { + match ReferendumInfoFor::::get(i).unwrap() { + ReferendumInfo::Rejected(since, ..) => since, + _ => panic!("Not rejected"), + } +} + +pub fn cancelled_since(i: ReferendumIndex) -> u64 { + match ReferendumInfoFor::::get(i).unwrap() { + ReferendumInfo::Cancelled(since, ..) => since, + _ => panic!("Not cancelled"), + } +} + +pub fn killed_since(i: ReferendumIndex) -> u64 { + match ReferendumInfoFor::::get(i).unwrap() { + ReferendumInfo::Killed(since, ..) => since, + _ => panic!("Not killed"), + } +} + +pub fn timed_out_since(i: ReferendumIndex) -> u64 { + match ReferendumInfoFor::::get(i).unwrap() { + ReferendumInfo::TimedOut(since, ..) => since, + _ => panic!("Not timed out"), + } +} + +fn is_deciding(i: ReferendumIndex) -> bool { + matches!( + ReferendumInfoFor::::get(i), + Some(ReferendumInfo::Ongoing(ReferendumStatus { deciding: Some(_), .. })) + ) +} + +#[derive(Clone, Copy)] +pub enum RefState { + Failing, + Passing, + Confirming { immediate: bool }, +} + +impl RefState { + pub fn create(self) -> ReferendumIndex { + assert_ok!(Referenda::submit( + Origin::signed(1), + frame_support::dispatch::RawOrigin::Root.into(), + set_balance_proposal_hash(1), + AtOrAfter::At(10), + )); + assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + if matches!(self, RefState::Confirming { immediate: true }) { + set_tally(0, 100, 0); + } + let index = ReferendumCount::::get() - 1; + while !is_deciding(index) { + run_to(System::block_number() + 1); + } + if matches!(self, RefState::Confirming { immediate: false }) { + set_tally(0, 100, 0); + run_to(System::block_number() + 1); + } + if matches!(self, RefState::Confirming { .. }) { + assert_eq!(confirming_until(index), System::block_number() + 2); + } + if matches!(self, RefState::Passing) { + set_tally(0, 100, 99); + run_to(System::block_number() + 1); + } + index + } +} diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs new file mode 100644 index 0000000000000..cea071ced12fe --- /dev/null +++ b/frame/referenda/src/tests.rs @@ -0,0 +1,511 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The crate's tests. + +use super::*; +use crate::mock::{RefState::*, *}; +use assert_matches::assert_matches; +use codec::Decode; +use frame_support::{ + assert_noop, assert_ok, + dispatch::{DispatchError::BadOrigin, RawOrigin}, + traits::Contains, +}; +use pallet_balances::Error as BalancesError; + +// TODO: Scheduler should re-use `None` items in its `Agenda`. + +#[test] +fn params_should_work() { + new_test_ext().execute_with(|| { + assert_eq!(ReferendumCount::::get(), 0); + assert_eq!(Balances::free_balance(42), 0); + assert_eq!(Balances::total_issuance(), 600); + }); +} + +#[test] +fn basic_happy_path_works() { + new_test_ext().execute_with(|| { + // #1: submit + assert_ok!(Referenda::submit( + Origin::signed(1), + RawOrigin::Root.into(), + set_balance_proposal_hash(1), + AtOrAfter::At(10), + )); + assert_eq!(Balances::reserved_balance(&1), 2); + assert_eq!(ReferendumCount::::get(), 1); + assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + run_to(4); + assert_eq!(DecidingCount::::get(0), 0); + run_to(5); + // #5: 4 blocks after submit - vote should now be deciding. + assert_eq!(DecidingCount::::get(0), 1); + run_to(6); + // #6: Lots of ayes. Should now be confirming. + set_tally(0, 100, 0); + run_to(7); + assert_eq!(confirming_until(0), 9); + run_to(9); + // #8: Should be confirmed & ended. + assert_eq!(approved_since(0), 9); + assert_ok!(Referenda::refund_decision_deposit(Origin::signed(2), 0)); + run_to(12); + // #9: Should not yet be enacted. + assert_eq!(Balances::free_balance(&42), 0); + run_to(13); + // #10: Proposal should be executed. + assert_eq!(Balances::free_balance(&42), 1); + }); +} + +#[test] +fn insta_confirm_then_kill_works() { + new_test_ext().execute_with(|| { + let r = Confirming { immediate: true }.create(); + run_to(6); + assert_ok!(Referenda::kill(Origin::root(), r)); + assert_eq!(killed_since(r), 6); + }); +} + +#[test] +fn confirm_then_reconfirm_with_elapsed_trigger_works() { + new_test_ext().execute_with(|| { + let r = Confirming { immediate: false }.create(); + assert_eq!(confirming_until(r), 8); + run_to(7); + set_tally(r, 100, 99); + run_to(8); + assert_eq!(deciding_and_failing_since(r), 5); + run_to(11); + assert_eq!(approved_since(r), 11); + }); +} + +#[test] +fn instaconfirm_then_reconfirm_with_elapsed_trigger_works() { + new_test_ext().execute_with(|| { + let r = Confirming { immediate: true }.create(); + run_to(6); + assert_eq!(confirming_until(r), 7); + set_tally(r, 100, 99); + run_to(7); + assert_eq!(deciding_and_failing_since(r), 5); + run_to(11); + assert_eq!(approved_since(r), 11); + }); +} + +#[test] +fn instaconfirm_then_reconfirm_with_voting_trigger_works() { + new_test_ext().execute_with(|| { + let r = Confirming { immediate: true }.create(); + run_to(6); + assert_eq!(confirming_until(r), 7); + set_tally(r, 100, 99); + run_to(7); + assert_eq!(deciding_and_failing_since(r), 5); + run_to(8); + set_tally(r, 100, 0); + run_to(9); + assert_eq!(confirming_until(r), 11); + run_to(11); + assert_eq!(approved_since(r), 11); + }); +} + +#[test] +fn voting_should_extend_for_late_confirmation() { + new_test_ext().execute_with(|| { + let r = Passing.create(); + run_to(10); + assert_eq!(confirming_until(r), 11); + run_to(11); + assert_eq!(approved_since(r), 11); + }); +} + +#[test] +fn should_instafail_during_extension_confirmation() { + new_test_ext().execute_with(|| { + let r = Passing.create(); + run_to(10); + assert_eq!(confirming_until(r), 11); + // Should insta-fail since it's now past the normal voting time. + set_tally(r, 100, 101); + run_to(11); + assert_eq!(rejected_since(r), 11); + }); +} + +#[test] +fn confirming_then_fail_works() { + new_test_ext().execute_with(|| { + let r = Failing.create(); + // Normally ends at 5 + 4 (voting period) = 9. + assert_eq!(deciding_and_failing_since(r), 5); + set_tally(r, 100, 0); + run_to(6); + assert_eq!(confirming_until(r), 8); + set_tally(r, 100, 101); + run_to(9); + assert_eq!(rejected_since(r), 9); + }); +} + +#[test] +fn queueing_works() { + new_test_ext().execute_with(|| { + // Submit a proposal into a track with a queue len of 1. + assert_ok!(Referenda::submit( + Origin::signed(5), + RawOrigin::Root.into(), + set_balance_proposal_hash(0), + AtOrAfter::After(0), + )); + assert_ok!(Referenda::place_decision_deposit(Origin::signed(5), 0)); + + run_to(2); + + // Submit 3 more proposals into the same queue. + for i in 1..=4 { + assert_ok!(Referenda::submit( + Origin::signed(i), + RawOrigin::Root.into(), + set_balance_proposal_hash(i), + AtOrAfter::After(0), + )); + assert_ok!(Referenda::place_decision_deposit(Origin::signed(i), i as u32)); + // TODO: decision deposit after some initial votes with a non-highest voted coming + // first. + } + assert_eq!(ReferendumCount::::get(), 5); + + run_to(5); + // One should be being decided. + assert_eq!(DecidingCount::::get(0), 1); + assert_eq!(deciding_and_failing_since(0), 5); + for i in 1..=4 { + assert_eq!(waiting_since(i), 2); + } + + // Vote to set order. + set_tally(1, 1, 10); + set_tally(2, 2, 20); + set_tally(3, 3, 30); + set_tally(4, 100, 0); + println!("Agenda #6: {:?}", pallet_scheduler::Agenda::::get(6)); + run_to(6); + println!("{:?}", Vec::<_>::from(TrackQueue::::get(0))); + + // Cancel the first. + assert_ok!(Referenda::cancel(Origin::signed(4), 0)); + assert_eq!(cancelled_since(0), 6); + + // The other with the most approvals (#4) should be being decided. + run_to(7); + assert_eq!(DecidingCount::::get(0), 1); + assert_eq!(deciding_since(4), 7); + assert_eq!(confirming_until(4), 9); + + // Vote on the remaining two to change order. + println!("Set tally #1"); + set_tally(1, 30, 31); + println!("{:?}", Vec::<_>::from(TrackQueue::::get(0))); + println!("Set tally #2"); + set_tally(2, 20, 20); + println!("{:?}", Vec::<_>::from(TrackQueue::::get(0))); + + // Let confirmation period end. + run_to(9); + + // #4 should have been confirmed. + assert_eq!(approved_since(4), 9); + + // On to the next block to select the new referendum + run_to(10); + // #1 (the one with the most approvals) should now be being decided. + assert_eq!(deciding_since(1), 10); + + // Let it end unsuccessfully. + run_to(14); + assert_eq!(rejected_since(1), 14); + + // Service queue. + run_to(15); + // #2 should now be being decided. It will (barely) pass. + assert_eq!(deciding_and_failing_since(2), 15); + + // #2 moves into confirming at the last moment with a 50% approval. + run_to(19); + assert_eq!(confirming_until(2), 21); + + // #2 gets approved. + run_to(21); + assert_eq!(approved_since(2), 21); + + // The final one has since timed out. + run_to(22); + assert_eq!(timed_out_since(3), 22); + }); +} + +#[test] +fn auto_timeout_should_happen_with_nothing_but_submit() { + new_test_ext().execute_with(|| { + // #1: submit + assert_ok!(Referenda::submit( + Origin::signed(1), + RawOrigin::Root.into(), + set_balance_proposal_hash(1), + AtOrAfter::At(20), + )); + run_to(20); + assert_matches!(ReferendumInfoFor::::get(0), Some(ReferendumInfo::Ongoing(..))); + run_to(21); + // #11: Timed out - ended. + assert_matches!( + ReferendumInfoFor::::get(0), + Some(ReferendumInfo::TimedOut(21, _, None)) + ); + }); +} + +#[test] +fn tracks_are_distinguished() { + new_test_ext().execute_with(|| { + assert_ok!(Referenda::submit( + Origin::signed(1), + RawOrigin::Root.into(), + set_balance_proposal_hash(1), + AtOrAfter::At(10), + )); + assert_ok!(Referenda::submit( + Origin::signed(2), + RawOrigin::None.into(), + set_balance_proposal_hash(2), + AtOrAfter::At(20), + )); + + assert_ok!(Referenda::place_decision_deposit(Origin::signed(3), 0)); + assert_ok!(Referenda::place_decision_deposit(Origin::signed(4), 1)); + + let mut i = ReferendumInfoFor::::iter().collect::>(); + i.sort_by_key(|x| x.0); + assert_eq!( + i, + vec![ + ( + 0, + ReferendumInfo::Ongoing(ReferendumStatus { + track: 0, + origin: OriginCaller::system(RawOrigin::Root), + proposal_hash: set_balance_proposal_hash(1), + enactment: AtOrAfter::At(10), + submitted: 1, + submission_deposit: Deposit { who: 1, amount: 2 }, + decision_deposit: Some(Deposit { who: 3, amount: 10 }), + deciding: None, + tally: Tally { ayes: 0, nays: 0 }, + in_queue: false, + alarm: Some((5, (5, 0))), + }) + ), + ( + 1, + ReferendumInfo::Ongoing(ReferendumStatus { + track: 1, + origin: OriginCaller::system(RawOrigin::None), + proposal_hash: set_balance_proposal_hash(2), + enactment: AtOrAfter::At(20), + submitted: 1, + submission_deposit: Deposit { who: 2, amount: 2 }, + decision_deposit: Some(Deposit { who: 4, amount: 1 }), + deciding: None, + tally: Tally { ayes: 0, nays: 0 }, + in_queue: false, + alarm: Some((3, (3, 0))), + }) + ), + ] + ); + }); +} + +#[test] +fn submit_errors_work() { + new_test_ext().execute_with(|| { + let h = set_balance_proposal_hash(1); + // No track for Signed origins. + assert_noop!( + Referenda::submit(Origin::signed(1), RawOrigin::Signed(2).into(), h, AtOrAfter::At(10),), + Error::::NoTrack + ); + + // No funds for deposit + assert_noop!( + Referenda::submit(Origin::signed(10), RawOrigin::Root.into(), h, AtOrAfter::At(10),), + BalancesError::::InsufficientBalance + ); + }); +} + +#[test] +fn decision_deposit_errors_work() { + new_test_ext().execute_with(|| { + let e = Error::::NotOngoing; + assert_noop!(Referenda::place_decision_deposit(Origin::signed(2), 0), e); + + let h = set_balance_proposal_hash(1); + assert_ok!(Referenda::submit( + Origin::signed(1), + RawOrigin::Root.into(), + h, + AtOrAfter::At(10), + )); + let e = BalancesError::::InsufficientBalance; + assert_noop!(Referenda::place_decision_deposit(Origin::signed(10), 0), e); + + assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + let e = Error::::HaveDeposit; + assert_noop!(Referenda::place_decision_deposit(Origin::signed(2), 0), e); + }); +} + +#[test] +fn refund_deposit_works() { + new_test_ext().execute_with(|| { + let e = Error::::BadReferendum; + assert_noop!(Referenda::refund_decision_deposit(Origin::signed(1), 0), e); + + let h = set_balance_proposal_hash(1); + assert_ok!(Referenda::submit( + Origin::signed(1), + RawOrigin::Root.into(), + h, + AtOrAfter::At(10), + )); + let e = Error::::NoDeposit; + assert_noop!(Referenda::refund_decision_deposit(Origin::signed(2), 0), e); + + assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + let e = Error::::Unfinished; + assert_noop!(Referenda::refund_decision_deposit(Origin::signed(3), 0), e); + + run_to(11); + assert_ok!(Referenda::refund_decision_deposit(Origin::signed(3), 0)); + }); +} + +#[test] +fn cancel_works() { + new_test_ext().execute_with(|| { + let h = set_balance_proposal_hash(1); + assert_ok!(Referenda::submit( + Origin::signed(1), + RawOrigin::Root.into(), + h, + AtOrAfter::At(10), + )); + assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + + run_to(8); + assert_ok!(Referenda::cancel(Origin::signed(4), 0)); + assert_ok!(Referenda::refund_decision_deposit(Origin::signed(3), 0)); + assert_eq!(cancelled_since(0), 8); + }); +} + +#[test] +fn cancel_errors_works() { + new_test_ext().execute_with(|| { + let h = set_balance_proposal_hash(1); + assert_ok!(Referenda::submit( + Origin::signed(1), + RawOrigin::Root.into(), + h, + AtOrAfter::At(10), + )); + assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_noop!(Referenda::cancel(Origin::signed(1), 0), BadOrigin); + + run_to(11); + assert_noop!(Referenda::cancel(Origin::signed(4), 0), Error::::NotOngoing); + }); +} + +#[test] +fn kill_works() { + new_test_ext().execute_with(|| { + let h = set_balance_proposal_hash(1); + assert_ok!(Referenda::submit( + Origin::signed(1), + RawOrigin::Root.into(), + h, + AtOrAfter::At(10), + )); + assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + + run_to(8); + assert_ok!(Referenda::kill(Origin::root(), 0)); + let e = Error::::NoDeposit; + assert_noop!(Referenda::refund_decision_deposit(Origin::signed(3), 0), e); + assert_eq!(killed_since(0), 8); + }); +} + +#[test] +fn kill_errors_works() { + new_test_ext().execute_with(|| { + let h = set_balance_proposal_hash(1); + assert_ok!(Referenda::submit( + Origin::signed(1), + RawOrigin::Root.into(), + h, + AtOrAfter::At(10), + )); + assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_noop!(Referenda::kill(Origin::signed(4), 0), BadOrigin); + + run_to(11); + assert_noop!(Referenda::kill(Origin::root(), 0), Error::::NotOngoing); + }); +} + +#[test] +fn set_balance_proposal_is_correctly_filtered_out() { + for i in 0..10 { + let call = crate::mock::Call::decode(&mut &set_balance_proposal(i)[..]).unwrap(); + assert!(!::BaseCallFilter::contains(&call)); + } +} + +#[test] +fn curve_handles_all_inputs() { + let test_curve = Curve::LinearDecreasing { begin: Perbill::zero(), delta: Perbill::zero() }; + + let delay = test_curve.delay(Perbill::zero()); + assert_eq!(delay, Perbill::zero()); + + let test_curve = Curve::LinearDecreasing { begin: Perbill::zero(), delta: Perbill::one() }; + + let threshold = test_curve.threshold(Perbill::one()); + assert_eq!(threshold, Perbill::zero()); +} diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs new file mode 100644 index 0000000000000..1b028fdfe9f79 --- /dev/null +++ b/frame/referenda/src/types.rs @@ -0,0 +1,358 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Miscellaneous additional datatypes. + +use super::*; +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use frame_support::{traits::schedule::Anon, Parameter}; +use scale_info::TypeInfo; +use sp_runtime::RuntimeDebug; +use sp_std::fmt::Debug; + +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; +pub type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, +>>::NegativeImbalance; +pub type CallOf = ::Call; +pub type VotesOf = ::Votes; +pub type TallyOf = ::Tally; +pub type PalletsOriginOf = <::Origin as OriginTrait>::PalletsOrigin; +pub type ReferendumInfoOf = ReferendumInfo< + TrackIdOf, + PalletsOriginOf, + ::BlockNumber, + ::Hash, + BalanceOf, + TallyOf, + ::AccountId, + ScheduleAddressOf, +>; +pub type ReferendumStatusOf = ReferendumStatus< + TrackIdOf, + PalletsOriginOf, + ::BlockNumber, + ::Hash, + BalanceOf, + TallyOf, + ::AccountId, + ScheduleAddressOf, +>; +pub type DecidingStatusOf = DecidingStatus<::BlockNumber>; +pub type TrackInfoOf = TrackInfo, ::BlockNumber>; +pub type TrackIdOf = <::Tracks as TracksInfo< + BalanceOf, + ::BlockNumber, +>>::Id; +pub type ScheduleAddressOf = <::Scheduler as Anon< + ::BlockNumber, + CallOf, + PalletsOriginOf, +>>::Address; + +/// A referendum index. +pub type ReferendumIndex = u32; + +pub trait InsertSorted { + /// Inserts an item into a sorted series. + /// + /// Returns `true` if it was inserted, `false` if it would belong beyond the bound of the + /// series. + fn insert_sorted_by_key K, K: PartialOrd + Ord>( + &mut self, + t: T, + f: F, + ) -> bool; +} +impl> InsertSorted for BoundedVec { + fn insert_sorted_by_key K, K: PartialOrd + Ord>( + &mut self, + t: T, + mut f: F, + ) -> bool { + let index = self.binary_search_by_key::(&f(&t), f).unwrap_or_else(|x| x); + self.force_insert_keep_right(index, t) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use frame_support::traits::ConstU32; + + #[test] + fn insert_sorted_works() { + let mut b: BoundedVec> = vec![20, 30, 40].try_into().unwrap(); + assert!(b.insert_sorted_by_key(10, |&x| x)); + assert_eq!(&b[..], &[10, 20, 30, 40][..]); + + assert!(b.insert_sorted_by_key(60, |&x| x)); + assert_eq!(&b[..], &[10, 20, 30, 40, 60][..]); + + assert!(b.insert_sorted_by_key(50, |&x| x)); + assert_eq!(&b[..], &[10, 20, 30, 40, 50, 60][..]); + + assert!(!b.insert_sorted_by_key(9, |&x| x)); + assert_eq!(&b[..], &[10, 20, 30, 40, 50, 60][..]); + + assert!(b.insert_sorted_by_key(11, |&x| x)); + assert_eq!(&b[..], &[11, 20, 30, 40, 50, 60][..]); + + assert!(b.insert_sorted_by_key(21, |&x| x)); + assert_eq!(&b[..], &[20, 21, 30, 40, 50, 60][..]); + + assert!(b.insert_sorted_by_key(61, |&x| x)); + assert_eq!(&b[..], &[21, 30, 40, 50, 60, 61][..]); + + assert!(b.insert_sorted_by_key(51, |&x| x)); + assert_eq!(&b[..], &[30, 40, 50, 51, 60, 61][..]); + } +} + +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct DecidingStatus { + /// When this referendum began being "decided". If confirming, then the + /// end will actually be delayed until the end of the confirmation period. + pub(crate) since: BlockNumber, + /// If `Some`, then the referendum has entered confirmation stage and will end at + /// the block number as long as it doesn't lose its approval in the meantime. + pub(crate) confirming: Option, +} + +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct Deposit { + pub(crate) who: AccountId, + pub(crate) amount: Balance, +} + +#[derive(Clone, Encode, TypeInfo)] +pub struct TrackInfo { + /// Name of this track. TODO was &'static str + pub name: &'static str, + /// A limit for the number of referenda on this track that can be being decided at once. + /// For Root origin this should generally be just one. + pub max_deciding: u32, + /// Amount that must be placed on deposit before a decision can be made. + pub decision_deposit: Balance, + /// Amount of time this must be submitted for before a decision can be made. + pub prepare_period: Moment, + /// Amount of time that a decision may take to be approved prior to cancellation. + pub decision_period: Moment, + /// Amount of time that the approval criteria must hold before it can be approved. + pub confirm_period: Moment, + /// Minimum amount of time that an approved proposal must be in the dispatch queue. + pub min_enactment_period: Moment, + /// Minimum aye votes as percentage of overall conviction-weighted votes needed for + /// approval as a function of time into decision period. + pub min_approval: Curve, + /// Minimum turnout as percentage of overall population that is needed for + /// approval as a function of time into decision period. + pub min_turnout: Curve, +} + +/// Information on the voting tracks. +pub trait TracksInfo { + /// The identifier for a track. + type Id: Copy + Parameter + Ord + PartialOrd + Send + Sync + 'static; + + /// The origin type from which a track is implied. + type Origin; + + /// Return the array of known tracks and their information. + fn tracks() -> &'static [(Self::Id, TrackInfo)]; + + /// Determine the voting track for the given `origin`. + fn track_for(origin: &Self::Origin) -> Result; + + /// Return the track info for track `id`, by default this just looks it up in `Self::tracks()`. + fn info(id: Self::Id) -> Option<&'static TrackInfo> { + Self::tracks().iter().find(|x| &x.0 == &id).map(|x| &x.1) + } +} + +/// Indication of either a specific moment or a delay from a implicitly defined moment. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum AtOrAfter { + /// Indiciates that the event should occur at the moment given. + At(Moment), + /// Indiciates that the event should occur some period of time (defined by the parameter) after + /// a prior event. The prior event is defined by the context, but for the purposes of + /// referendum proposals, the "prior event" is the passing of the referendum. + After(Moment), +} + +impl AtOrAfter { + pub fn evaluate(&self, since: Moment) -> Moment { + match &self { + Self::At(m) => *m, + Self::After(m) => m.saturating_add(since), + } + } +} + +/// Info regarding an ongoing referendum. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct ReferendumStatus< + TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, + Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, +> { + /// The track of this referendum. + pub(crate) track: TrackId, + /// The origin for this referendum. + pub(crate) origin: Origin, + /// The hash of the proposal up for referendum. + pub(crate) proposal_hash: Hash, + /// The time the proposal should be scheduled for enactment. + pub(crate) enactment: AtOrAfter, + /// The time of submission. Once `UndecidingTimeout` passes, it may be closed by anyone if it + /// `deciding` is `None`. + pub(crate) submitted: Moment, + /// The deposit reserved for the submission of this referendum. + pub(crate) submission_deposit: Deposit, + /// The deposit reserved for this referendum to be decided. + pub(crate) decision_deposit: Option>, + /// The status of a decision being made. If `None`, it has not entered the deciding period. + pub(crate) deciding: Option>, + /// The current tally of votes in this referendum. + pub(crate) tally: Tally, + /// Whether we have been placed in the queue for being decided or not. + pub(crate) in_queue: bool, + /// The next scheduled wake-up, if `Some`. + pub(crate) alarm: Option<(Moment, ScheduleAddress)>, +} + +/// Info regarding a referendum, present or past. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum ReferendumInfo< + TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Moment: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, + Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, +> { + /// Referendum has been submitted and is being voted on. + Ongoing( + ReferendumStatus, + ), + /// Referendum finished with approval. Submission deposit is held. + Approved(Moment, Deposit, Option>), + /// Referendum finished with rejection. Submission deposit is held. + Rejected(Moment, Deposit, Option>), + /// Referendum finished with cancelation. Submission deposit is held. + Cancelled(Moment, Deposit, Option>), + /// Referendum finished and was never decided. Submission deposit is held. + TimedOut(Moment, Deposit, Option>), + /// Referendum finished with a kill. + Killed(Moment), +} + +impl< + TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, + Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + > ReferendumInfo +{ + /// Take the Decision Deposit from `self`, if there is one. Returns an `Err` if `self` is not + /// in a valid state for the Decision Deposit to be refunded. + pub fn take_decision_deposit(&mut self) -> Result>, ()> { + use ReferendumInfo::*; + match self { + Ongoing(x) if x.decision_deposit.is_none() => Ok(None), + // Cannot refund deposit if Ongoing as this breaks assumptions. + Ongoing(_) => Err(()), + Approved(_, _, d) | Rejected(_, _, d) | TimedOut(_, _, d) | Cancelled(_, _, d) => + Ok(d.take()), + Killed(_) => Ok(None), + } + } +} + +/// Type for describing a curve over the 2-dimensional space of axes between 0-1, as represented +/// by `(Perbill, Perbill)`. +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[cfg_attr(not(feature = "std"), derive(RuntimeDebug))] +pub enum Curve { + /// Linear curve starting at `(0, begin)`, ending at `(period, begin - delta)`. + LinearDecreasing { begin: Perbill, delta: Perbill }, +} + +impl Curve { + /// Determine the `y` value for the given `x` value. + pub(crate) fn threshold(&self, x: Perbill) -> Perbill { + match self { + Self::LinearDecreasing { begin, delta } => *begin - (*delta * x).min(*begin), + } + } + + /// Determine the smallest `x` value such that `passing` returns `true` when passed along with + /// the given `y` value. + /// + /// ```nocompile + /// let c = Curve::LinearDecreasing { begin: Perbill::one(), delta: Perbill::one() }; + /// // ^^^ Can be any curve. + /// let y = Perbill::from_percent(50); + /// // ^^^ Can be any value. + /// let x = c.delay(y); + /// assert!(c.passing(x, y)); + /// ``` + pub fn delay(&self, y: Perbill) -> Perbill { + match self { + Self::LinearDecreasing { begin, delta } => + if delta.is_zero() { + return *delta + } else { + return (*begin - y.min(*begin)).min(*delta) / *delta + }, + } + } + + /// Return `true` iff the `y` value is greater than the curve at the `x`. + pub fn passing(&self, x: Perbill, y: Perbill) -> bool { + y >= self.threshold(x) + } +} + +#[cfg(feature = "std")] +impl Debug for Curve { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + match self { + Self::LinearDecreasing { begin, delta } => { + write!( + f, + "Linear[(0%, {}%) -> (100%, {}%)]", + *begin * 100u32, + (*begin - *delta) * 100u32, + ) + }, + } + } +} diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs new file mode 100644 index 0000000000000..202901bdd10bd --- /dev/null +++ b/frame/referenda/src/weights.rs @@ -0,0 +1,491 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_referenda +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-12-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// target/release/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_referenda +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/referenda/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_referenda. +pub trait WeightInfo { + fn submit() -> Weight; + fn place_decision_deposit_preparing() -> Weight; + fn place_decision_deposit_queued() -> Weight; + fn place_decision_deposit_not_queued() -> Weight; + fn place_decision_deposit_passing() -> Weight; + fn place_decision_deposit_failing() -> Weight; + fn refund_decision_deposit() -> Weight; + fn cancel() -> Weight; + fn kill() -> Weight; + fn one_fewer_deciding_queue_empty() -> Weight; + fn one_fewer_deciding_failing() -> Weight; + fn one_fewer_deciding_passing() -> Weight; + fn nudge_referendum_requeued_insertion() -> Weight; + fn nudge_referendum_requeued_slide() -> Weight; + fn nudge_referendum_queued() -> Weight; + fn nudge_referendum_not_queued() -> Weight; + fn nudge_referendum_no_deposit() -> Weight; + fn nudge_referendum_preparing() -> Weight; + fn nudge_referendum_timed_out() -> Weight; + fn nudge_referendum_begin_deciding_failing() -> Weight; + fn nudge_referendum_begin_deciding_passing() -> Weight; + fn nudge_referendum_begin_confirming() -> Weight; + fn nudge_referendum_end_confirming() -> Weight; + fn nudge_referendum_continue_not_confirming() -> Weight; + fn nudge_referendum_continue_confirming() -> Weight; + fn nudge_referendum_approved() -> Weight; + fn nudge_referendum_rejected() -> Weight; +} + +/// Weights for pallet_referenda using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Referenda ReferendumCount (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:0 w:1) + fn submit() -> Weight { + (42_395_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn place_decision_deposit_preparing() -> Weight { + (48_113_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:0) + // Storage: Referenda TrackQueue (r:1 w:1) + fn place_decision_deposit_queued() -> Weight { + (53_624_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:0) + // Storage: Referenda TrackQueue (r:1 w:1) + fn place_decision_deposit_not_queued() -> Weight { + (52_560_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn place_decision_deposit_passing() -> Weight { + (54_067_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn place_decision_deposit_failing() -> Weight { + (52_457_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + fn refund_decision_deposit() -> Weight { + (28_504_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn cancel() -> Weight { + (40_425_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn kill() -> Weight { + (65_974_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda TrackQueue (r:1 w:0) + // Storage: Referenda DecidingCount (r:1 w:1) + fn one_fewer_deciding_queue_empty() -> Weight { + (8_904_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn one_fewer_deciding_failing() -> Weight { + (181_387_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn one_fewer_deciding_passing() -> Weight { + (179_753_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_requeued_insertion() -> Weight { + (53_592_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_requeued_slide() -> Weight { + (53_173_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:0) + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_queued() -> Weight { + (55_770_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:0) + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_not_queued() -> Weight { + (53_922_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_no_deposit() -> Weight { + (26_906_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_preparing() -> Weight { + (27_943_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + fn nudge_referendum_timed_out() -> Weight { + (20_256_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_begin_deciding_failing() -> Weight { + (30_964_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_begin_deciding_passing() -> Weight { + (31_763_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_begin_confirming() -> Weight { + (28_892_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_end_confirming() -> Weight { + (29_666_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_continue_not_confirming() -> Weight { + (29_740_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_continue_confirming() -> Weight { + (29_661_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Scheduler Lookup (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn nudge_referendum_approved() -> Weight { + (55_736_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_rejected() -> Weight { + (32_726_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Referenda ReferendumCount (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:0 w:1) + fn submit() -> Weight { + (42_395_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn place_decision_deposit_preparing() -> Weight { + (48_113_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:0) + // Storage: Referenda TrackQueue (r:1 w:1) + fn place_decision_deposit_queued() -> Weight { + (53_624_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:0) + // Storage: Referenda TrackQueue (r:1 w:1) + fn place_decision_deposit_not_queued() -> Weight { + (52_560_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn place_decision_deposit_passing() -> Weight { + (54_067_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn place_decision_deposit_failing() -> Weight { + (52_457_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + fn refund_decision_deposit() -> Weight { + (28_504_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn cancel() -> Weight { + (40_425_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn kill() -> Weight { + (65_974_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda TrackQueue (r:1 w:0) + // Storage: Referenda DecidingCount (r:1 w:1) + fn one_fewer_deciding_queue_empty() -> Weight { + (8_904_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn one_fewer_deciding_failing() -> Weight { + (181_387_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn one_fewer_deciding_passing() -> Weight { + (179_753_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_requeued_insertion() -> Weight { + (53_592_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_requeued_slide() -> Weight { + (53_173_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:0) + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_queued() -> Weight { + (55_770_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:0) + // Storage: Referenda TrackQueue (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_not_queued() -> Weight { + (53_922_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_no_deposit() -> Weight { + (26_906_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_preparing() -> Weight { + (27_943_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + fn nudge_referendum_timed_out() -> Weight { + (20_256_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_begin_deciding_failing() -> Weight { + (30_964_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Referenda DecidingCount (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_begin_deciding_passing() -> Weight { + (31_763_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_begin_confirming() -> Weight { + (28_892_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_end_confirming() -> Weight { + (29_666_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_continue_not_confirming() -> Weight { + (29_740_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_continue_confirming() -> Weight { + (29_661_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Scheduler Lookup (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn nudge_referendum_approved() -> Weight { + (55_736_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn nudge_referendum_rejected() -> Weight { + (32_726_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } +} diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index f9077d4c8c8fa..ec60cedc280b6 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -694,13 +694,6 @@ impl Pallet { }); Agenda::::append(when, s); let index = Agenda::::decode_len(when).unwrap_or(1) as u32 - 1; - if index > T::MaxScheduledPerBlock::get() { - log::warn!( - target: "runtime::scheduler", - "Warning: There are more items queued in the Scheduler than \ - expected from the runtime configuration. An update might be needed.", - ); - } Self::deposit_event(Event::Scheduled { when, index }); Ok((when, index)) @@ -795,13 +788,6 @@ impl Pallet { }; Agenda::::append(when, Some(s)); let index = Agenda::::decode_len(when).unwrap_or(1) as u32 - 1; - if index > T::MaxScheduledPerBlock::get() { - log::warn!( - target: "runtime::scheduler", - "Warning: There are more items queued in the Scheduler than \ - expected from the runtime configuration. An update might be needed.", - ); - } let address = (when, index); Lookup::::insert(&id, &address); Self::deposit_event(Event::Scheduled { when, index }); diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index b5f4ab97767c2..ece5173f2f4ca 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -20,6 +20,7 @@ pub use crate::{ codec::{Codec, Decode, Encode, EncodeAsRef, EncodeLike, HasCompact, Input, Output}, + scale_info::TypeInfo, sp_std::{ fmt, marker, prelude::{Clone, Eq, PartialEq, Vec}, @@ -33,7 +34,7 @@ pub use crate::{ TransactionPriority, WeighData, Weight, WithPostDispatchInfo, }, }; -pub use sp_runtime::{traits::Dispatchable, DispatchError}; +pub use sp_runtime::{traits::Dispatchable, DispatchError, RuntimeDebug}; /// The return type of a `Dispatchable` in frame. When returned explicitly from /// a dispatchable function it allows overriding the default `PostDispatchInfo` @@ -60,6 +61,28 @@ pub trait Callable { // https://github.com/rust-lang/rust/issues/51331 pub type CallableCallFor = >::Call; +/// Origin for the System pallet. +#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo)] +pub enum RawOrigin { + /// The system itself ordained this dispatch to happen: this is the highest privilege level. + Root, + /// It is signed by some public key and we provide the `AccountId`. + Signed(AccountId), + /// It is signed by nobody, can be either: + /// * included and agreed upon by the validators anyway, + /// * or unsigned transaction validated by a pallet. + None, +} + +impl From> for RawOrigin { + fn from(s: Option) -> RawOrigin { + match s { + Some(who) => RawOrigin::Signed(who), + None => RawOrigin::None, + } + } +} + /// 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. @@ -2582,21 +2605,7 @@ mod tests { type DbWeight: Get; } - #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, scale_info::TypeInfo)] - pub enum RawOrigin { - Root, - Signed(AccountId), - None, - } - - impl From> for RawOrigin { - fn from(s: Option) -> RawOrigin { - match s { - Some(who) => RawOrigin::Signed(who), - None => RawOrigin::None, - } - } - } + pub use super::super::RawOrigin; pub type Origin = RawOrigin<::AccountId>; } @@ -2638,7 +2647,7 @@ mod tests { } } - #[derive(scale_info::TypeInfo)] + #[derive(Eq, PartialEq, Clone, crate::RuntimeDebug, scale_info::TypeInfo)] pub struct TraitImpl {} impl Config for TraitImpl {} @@ -2679,8 +2688,15 @@ mod tests { } } + #[derive(TypeInfo, crate::RuntimeDebug, Eq, PartialEq, Clone, Encode, Decode)] pub struct OuterOrigin; + impl From::AccountId>> for OuterOrigin { + fn from(_: RawOrigin<::AccountId>) -> Self { + unimplemented!("Not required in tests!") + } + } + impl crate::traits::OriginTrait for OuterOrigin { type Call = ::Call; type PalletsOrigin = OuterOrigin; diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 1928023cfe66d..5ee2952e445b7 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -23,7 +23,7 @@ pub mod tokens; pub use tokens::{ currency::{ Currency, LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency, - VestingSchedule, + TotalIssuanceOf, VestingSchedule, }, fungible, fungibles, imbalance::{Imbalance, OnUnbalanced, SignedImbalance}, @@ -90,4 +90,6 @@ mod dispatch; pub use dispatch::{EnsureOneOf, EnsureOrigin, OriginTrait, UnfilteredDispatchable}; mod voting; -pub use voting::{CurrencyToVote, SaturatingCurrencyToVote, U128CurrencyToVote}; +pub use voting::{ + CurrencyToVote, PollStatus, Polling, SaturatingCurrencyToVote, U128CurrencyToVote, VoteTally, +}; diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index afac31e662e3f..1a4e9f6f7cc2a 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -17,8 +17,11 @@ //! Traits for dealing with dispatching calls and the origin from which they are dispatched. -use crate::dispatch::DispatchResultWithPostInfo; -use sp_runtime::{traits::BadOrigin, Either}; +use crate::dispatch::{DispatchResultWithPostInfo, Parameter, RawOrigin}; +use sp_runtime::{ + traits::{BadOrigin, Member}, + Either, +}; /// Some sort of check on the origin is performed by this object. pub trait EnsureOrigin { @@ -56,7 +59,7 @@ pub trait OriginTrait: Sized { type Call; /// The caller origin, overarching type of all pallets origins. - type PalletsOrigin; + type PalletsOrigin: Parameter + Member + Into + From>; /// The AccountId used across the system. type AccountId; diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 5ba233c29be1f..3b8e6da3e2ef3 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -125,7 +125,7 @@ pub mod v1 { /// A type that can be used as a scheduler. pub trait Anon { /// An address which can be used for removing a scheduled task. - type Address: Codec + Clone + Eq + EncodeLike + Debug; + type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo; /// Schedule a dispatch to happen at the beginning of some block in the future. /// @@ -280,7 +280,7 @@ pub mod v2 { /// A type that can be used as a scheduler. pub trait Anon { /// An address which can be used for removing a scheduled task. - type Address: Codec + Clone + Eq + EncodeLike + Debug; + type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo; /// A means of expressing a call by the hash of its encoded data. type Hash; diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index d5756ee84c47a..d4b5c0c184f85 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -21,7 +21,10 @@ use super::{ imbalance::{Imbalance, SignedImbalance}, misc::{Balance, ExistenceRequirement, WithdrawReasons}, }; -use crate::dispatch::{DispatchError, DispatchResult}; +use crate::{ + dispatch::{DispatchError, DispatchResult}, + traits::Get, +}; use codec::MaxEncodedLen; use sp_runtime::traits::MaybeSerializeDeserialize; use sp_std::fmt::Debug; @@ -200,6 +203,15 @@ pub trait Currency { ) -> SignedImbalance; } +/// A non-const `Get` implementation parameterised by a `Currency` impl which provides the result +/// of `total_issuance`. +pub struct TotalIssuanceOf, A>(sp_std::marker::PhantomData<(C, A)>); +impl, A> Get for TotalIssuanceOf { + fn get() -> C::Balance { + C::total_issuance() + } +} + #[cfg(feature = "std")] impl Currency for () { type Balance = u32; diff --git a/frame/support/src/traits/voting.rs b/frame/support/src/traits/voting.rs index 719ad7f0f71d0..978c5ce4f6a01 100644 --- a/frame/support/src/traits/voting.rs +++ b/frame/support/src/traits/voting.rs @@ -18,7 +18,14 @@ //! Traits and associated data structures concerned with voting, and moving between tokens and //! votes. -use sp_arithmetic::traits::{SaturatedConversion, UniqueSaturatedFrom, UniqueSaturatedInto}; +use crate::dispatch::{DispatchError, Parameter}; +use codec::HasCompact; +use sp_arithmetic::{ + traits::{SaturatedConversion, UniqueSaturatedFrom, UniqueSaturatedInto}, + Perbill, +}; +use sp_runtime::traits::Member; +use sp_std::prelude::*; /// A trait similar to `Convert` to convert values from `B` an abstract balance type /// into u64 and back from u128. (This conversion is used in election and other places where complex @@ -87,3 +94,74 @@ impl + UniqueSaturatedFrom> CurrencyToVote B::unique_saturated_from(value) } } + +pub trait VoteTally { + fn ayes(&self) -> Votes; + fn turnout(&self) -> Perbill; + fn approval(&self) -> Perbill; + #[cfg(feature = "runtime-benchmarks")] + fn unanimity() -> Self; + #[cfg(feature = "runtime-benchmarks")] + fn from_requirements(turnout: Perbill, approval: Perbill) -> Self; +} + +pub enum PollStatus { + None, + Ongoing(Tally, Class), + Completed(Moment, bool), +} + +impl PollStatus { + pub fn ensure_ongoing(self) -> Option<(Tally, Class)> { + match self { + Self::Ongoing(t, c) => Some((t, c)), + _ => None, + } + } +} + +pub trait Polling { + type Index: Parameter + Member + Ord + PartialOrd + Copy + HasCompact; + type Votes: Parameter + Member + Ord + PartialOrd + Copy + HasCompact; + type Class: Parameter + Member + Ord + PartialOrd; + type Moment; + + /// Provides a vec of values that `T` may take. + fn classes() -> Vec; + + /// `Some` if the referendum `index` can be voted on, along with the tally and class of + /// referendum. + /// + /// Don't use this if you might mutate - use `try_access_poll` instead. + fn as_ongoing(index: Self::Index) -> Option<(Tally, Self::Class)>; + + fn access_poll( + index: Self::Index, + f: impl FnOnce(PollStatus<&mut Tally, Self::Moment, Self::Class>) -> R, + ) -> R; + + fn try_access_poll( + index: Self::Index, + f: impl FnOnce(PollStatus<&mut Tally, Self::Moment, Self::Class>) -> Result, + ) -> Result; + + /// Create an ongoing majority-carries poll of given class lasting given period for the purpose + /// of benchmarking. + /// + /// May return `Err` if it is impossible. + #[cfg(feature = "runtime-benchmarks")] + fn create_ongoing(class: Self::Class) -> Result; + + /// End the given ongoing poll and return the result. + /// + /// Returns `Err` if `index` is not an ongoing poll. + #[cfg(feature = "runtime-benchmarks")] + fn end_ongoing(index: Self::Index, approved: bool) -> Result<(), ()>; + + /// The maximum amount of ongoing polls within any single class. By default it practically + /// unlimited (`u32::max_value()`). + #[cfg(feature = "runtime-benchmarks")] + fn max_ongoing() -> (Self::Class, u32) { + (Self::classes().into_iter().next().expect("Always one class"), u32::max_value()) + } +} diff --git a/frame/support/test/tests/system.rs b/frame/support/test/tests/system.rs index 0083835640cb7..b30fd8d5ec561 100644 --- a/frame/support/test/tests/system.rs +++ b/frame/support/test/tests/system.rs @@ -69,23 +69,7 @@ frame_support::decl_error! { } } -/// Origin for the system module. -#[derive(PartialEq, Eq, Clone, sp_runtime::RuntimeDebug, Encode, Decode, scale_info::TypeInfo)] -pub enum RawOrigin { - Root, - Signed(AccountId), - None, -} - -impl From> for RawOrigin { - fn from(s: Option) -> RawOrigin { - match s { - Some(who) => RawOrigin::Signed(who), - None => RawOrigin::None, - } - } -} - +pub use frame_support::dispatch::RawOrigin; pub type Origin = RawOrigin<::AccountId>; #[allow(dead_code)] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 878edd7840e74..3b4de0c472c47 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -124,6 +124,7 @@ pub use extensions::{ }; // Backward compatible re-export. pub use extensions::check_mortality::CheckMortality as CheckEra; +pub use frame_support::dispatch::RawOrigin; pub use weights::WeightInfo; /// Compute the trie root of a list of extrinsics. @@ -708,28 +709,6 @@ pub struct EventRecord { pub topics: Vec, } -/// Origin for the System pallet. -#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo)] -pub enum RawOrigin { - /// The system itself ordained this dispatch to happen: this is the highest privilege level. - Root, - /// It is signed by some public key and we provide the `AccountId`. - Signed(AccountId), - /// It is signed by nobody, can be either: - /// * included and agreed upon by the validators anyway, - /// * or unsigned transaction validated by a pallet. - None, -} - -impl From> for RawOrigin { - fn from(s: Option) -> RawOrigin { - match s { - Some(who) => RawOrigin::Signed(who), - None => RawOrigin::None, - } - } -} - // Create a Hash with 69 for each byte, // only used to build genesis config. #[cfg(feature = "std")] @@ -1641,7 +1620,7 @@ impl Lookup for ChainContext { /// Prelude to be used alongside pallet macro, for ease of use. pub mod pallet_prelude { - pub use crate::{ensure_none, ensure_root, ensure_signed}; + pub use crate::{ensure_none, ensure_root, ensure_signed, ensure_signed_or_root}; /// Type alias for the `Origin` associated type of system config. pub type OriginFor = ::Origin; diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 5c9dfeca0a334..861d95efb3087 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -426,7 +426,7 @@ impl GetRuntimeBlockType for Runtime { type RuntimeBlock = Block; } -#[derive(Clone, RuntimeDebug)] +#[derive(Clone, RuntimeDebug, Encode, Decode, PartialEq, Eq, TypeInfo)] pub struct Origin; impl From> for Origin { From dc4cf6c2c73ef5af9197b3e73fb590b1a045d93e Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Mon, 7 Feb 2022 10:14:52 +0100 Subject: [PATCH 0488/1472] More efficient WASM instance memory decommit on macos (#10801) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * More efficient WASM instance memory decommit on macos * Apply suggestions from code review Co-authored-by: Alexander Theißen * Updated error message Co-authored-by: Alexander Theißen --- .../executor/wasmtime/src/instance_wrapper.rs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index af21a8080cd58..e27de7817b2bd 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -361,6 +361,33 @@ impl InstanceWrapper { return; } } + } else if #[cfg(target_os = "macos")] { + use std::sync::Once; + + unsafe { + let ptr = self.memory.data_ptr(&self.store); + let len = self.memory.data_size(&self.store); + + // On MacOS we can simply overwrite memory mapping. + if libc::mmap( + ptr as _, + len, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_FIXED | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, + -1, + 0, + ) == libc::MAP_FAILED { + static LOGGED: Once = Once::new(); + LOGGED.call_once(|| { + log::warn!( + "Failed to decommit WASM instance memory through mmap: {}", + std::io::Error::last_os_error(), + ); + }); + } else { + return; + } + } } } @@ -377,3 +404,15 @@ impl InstanceWrapper { &mut self.store } } + +#[test] +fn decommit_works() { + let engine = wasmtime::Engine::default(); + let code = wat::parse_str("(module (memory (export \"memory\") 1 4))").unwrap(); + let module = Module::new(&engine, code).unwrap(); + let mut wrapper = InstanceWrapper::new::<()>(&module, 2, true, None).unwrap(); + unsafe { *wrapper.memory.data_ptr(&wrapper.store) = 42 }; + assert_eq!(unsafe { *wrapper.memory.data_ptr(&wrapper.store) }, 42); + wrapper.decommit(); + assert_eq!(unsafe { *wrapper.memory.data_ptr(&wrapper.store) }, 0); +} From 0e9b6e4250a32e021c281d85e5790b7180bdb752 Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Mon, 7 Feb 2022 13:33:24 +0100 Subject: [PATCH 0489/1472] make inner field of IdentityFields pub (#10773) --- frame/identity/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/identity/src/types.rs b/frame/identity/src/types.rs index ed3caafd3a114..d91adc8cdd768 100644 --- a/frame/identity/src/types.rs +++ b/frame/identity/src/types.rs @@ -245,7 +245,7 @@ pub enum IdentityField { /// Wrapper type for `BitFlags` that implements `Codec`. #[derive(Clone, Copy, PartialEq, Default, RuntimeDebug)] -pub struct IdentityFields(pub(crate) BitFlags); +pub struct IdentityFields(pub BitFlags); impl MaxEncodedLen for IdentityFields { fn max_encoded_len() -> usize { From 57bf92e42c2ca7f3444567b5ce50d2744fe90b4d Mon Sep 17 00:00:00 2001 From: Heorhii Lutsenko Date: Mon, 7 Feb 2022 14:47:56 +0200 Subject: [PATCH 0490/1472] Corrected description of clear_attribute extrinsic (#10729) --- frame/uniques/src/lib.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 6b05aaeec296b..3a0b34e5bf407 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -1003,21 +1003,18 @@ pub mod pallet { Ok(()) } - /// Set an attribute for an asset class or instance. + /// Clear an attribute for an asset class or instance. /// /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the /// asset `class`. /// - /// If the origin is Signed, then funds of signer are reserved according to the formula: - /// `MetadataDepositBase + DepositPerByte * (key.len + value.len)` taking into - /// account any already reserved funds. + /// Any deposit is freed for the asset class owner. /// - /// - `class`: The identifier of the asset class whose instance's metadata to set. - /// - `instance`: The identifier of the asset instance whose metadata to set. + /// - `class`: The identifier of the asset class whose instance's metadata to clear. + /// - `maybe_instance`: The identifier of the asset instance whose metadata to clear. /// - `key`: The key of the attribute. - /// - `value`: The value to which to set the attribute. /// - /// Emits `AttributeSet`. + /// Emits `AttributeCleared`. /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::clear_attribute())] From c8bef76781fad6e88aa85397ece5058db780f12c Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Tue, 8 Feb 2022 16:52:20 +0800 Subject: [PATCH 0491/1472] sp-maybe-compressed-blob: reduce boilerplate code (#10814) Signed-off-by: koushiro --- Cargo.lock | 1 + primitives/maybe-compressed-blob/Cargo.toml | 1 + primitives/maybe-compressed-blob/src/lib.rs | 23 +++++++-------------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45158288298b3..553da394386c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9809,6 +9809,7 @@ dependencies = [ name = "sp-maybe-compressed-blob" version = "4.1.0-dev" dependencies = [ + "thiserror", "zstd", ] diff --git a/primitives/maybe-compressed-blob/Cargo.toml b/primitives/maybe-compressed-blob/Cargo.toml index dbed41571b149..d8814356df4bb 100644 --- a/primitives/maybe-compressed-blob/Cargo.toml +++ b/primitives/maybe-compressed-blob/Cargo.toml @@ -11,4 +11,5 @@ documentation = "https://docs.rs/sp-maybe-compressed-blob" readme = "README.md" [dependencies] +thiserror = "1.0" zstd = { version = "0.9.0", default-features = false } diff --git a/primitives/maybe-compressed-blob/src/lib.rs b/primitives/maybe-compressed-blob/src/lib.rs index 402ed90be21ca..99c12ed39bc04 100644 --- a/primitives/maybe-compressed-blob/src/lib.rs +++ b/primitives/maybe-compressed-blob/src/lib.rs @@ -18,7 +18,10 @@ //! Handling of blobs that may be compressed, based on an 8-byte magic identifier //! at the head. -use std::{borrow::Cow, io::Read}; +use std::{ + borrow::Cow, + io::{Read, Write}, +}; // An arbitrary prefix, that indicates a blob beginning with should be decompressed with // Zstd compression. @@ -34,25 +37,16 @@ const ZSTD_PREFIX: [u8; 8] = [82, 188, 83, 118, 70, 219, 142, 5]; pub const CODE_BLOB_BOMB_LIMIT: usize = 50 * 1024 * 1024; /// A possible bomb was encountered. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, thiserror::Error)] pub enum Error { /// Decoded size was too large, and the code payload may be a bomb. + #[error("Possible compression bomb encountered")] PossibleBomb, /// The compressed value had an invalid format. + #[error("Blob had invalid format")] Invalid, } -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - Error::PossibleBomb => write!(f, "Possible compression bomb encountered"), - Error::Invalid => write!(f, "Blob had invalid format"), - } - } -} - -impl std::error::Error for Error {} - fn read_from_decoder( decoder: impl Read, blob_len: usize, @@ -90,8 +84,6 @@ pub fn decompress(blob: &[u8], bomb_limit: usize) -> Result, Error> { /// this will not compress the blob, as the decoder will not be able to be /// able to differentiate it from a compression bomb. pub fn compress(blob: &[u8], bomb_limit: usize) -> Option> { - use std::io::Write; - if blob.len() > bomb_limit { return None } @@ -109,7 +101,6 @@ pub fn compress(blob: &[u8], bomb_limit: usize) -> Option> { #[cfg(test)] mod tests { use super::*; - use std::io::Write; const BOMB_LIMIT: usize = 10; From aa7a7563bf8cdd3e60a5b1b379f287ae1457b864 Mon Sep 17 00:00:00 2001 From: Yarik Bratashchuk Date: Tue, 8 Feb 2022 13:43:32 +0200 Subject: [PATCH 0492/1472] `seal_delegate_call` api function (support for library contracts) (#10617) * seal_call_code implementation - tests - benchmark * Addressing @xgreenx's comments * Fix test-linux-stable-int * Rename seal_call_code to seal_delegate_call * Pass value unchanged into lib contract * Address @athei's comments - whitespace .wat issues - wrong/missing .wat comments - redundant .wat calls/declarations - change order of functions (seal_delegate_call right after seal_call) in decls, tests, benchmark - fix comments, move doc comments to enum variants - remove unnecessary empty lines - rename runtime cost DelegateCall to DelegateCallBase - do not set CallFlags::ALLOW_REENTRY for delegate_call * Do not pass CallFlags::ALLOWS_REENTRY for delegate_call * Update comment for seal_delegate_call and CallFlags * Addressing @athei's comments (minor) * Allow reentry for a new frame after delegate_call (revert) * Same seal_caller and seal_value_transferred for lib contract - test - refactor frame args due to review - logic for seal_caller (please review) * Put caller on frame for delegate_call, minor fixes * Update comment for delegate_call * Addressing @athei's comments * Update weights generated by benchmark * Improve comments * Address @HCastano's comments * Update weights, thanks @joao-paulo-parity * Improve InvalidCallFlags error comment --- frame/contracts/fixtures/delegate_call.wat | 111 +++++++++++++++ .../contracts/fixtures/delegate_call_lib.wat | 79 +++++++++++ frame/contracts/src/benchmarking/mod.rs | 52 +++++++ frame/contracts/src/exec.rs | 127 +++++++++++++---- frame/contracts/src/lib.rs | 2 + frame/contracts/src/schedule.rs | 4 + frame/contracts/src/tests.rs | 38 ++++++ frame/contracts/src/wasm/mod.rs | 63 +++++++++ frame/contracts/src/wasm/runtime.rs | 128 +++++++++++++++--- frame/contracts/src/weights.rs | 23 ++++ 10 files changed, 576 insertions(+), 51 deletions(-) create mode 100644 frame/contracts/fixtures/delegate_call.wat create mode 100644 frame/contracts/fixtures/delegate_call_lib.wat diff --git a/frame/contracts/fixtures/delegate_call.wat b/frame/contracts/fixtures/delegate_call.wat new file mode 100644 index 0000000000000..e1c5fa813e590 --- /dev/null +++ b/frame/contracts/fixtures/delegate_call.wat @@ -0,0 +1,111 @@ +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32) (result i32))) + (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) + (import "__unstable__" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 3 3)) + + ;; [0, 32) storage key + (data (i32.const 0) "\01") + + ;; [32, 64) storage key + (data (i32.const 32) "\02") + + ;; [64, 96) buffer where input is copied + + ;; [96, 100) size of the input buffer + (data (i32.const 96) "\20") + + ;; [100, 104) size of buffer for seal_get_storage + (data (i32.const 100) "\20") + + ;; [104, 136) seal_get_storage buffer + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + (local $exit_code i32) + + ;; Reading "callee" code_hash + (call $seal_input (i32.const 64) (i32.const 96)) + + ;; assert input size == 32 + (call $assert + (i32.eq + (i32.load (i32.const 96)) + (i32.const 32) + ) + ) + + ;; place a value in storage, the size of which is specified by the call input. + (call $seal_set_storage + (i32.const 0) ;; Pointer to storage key + (i32.const 32) ;; Pointer to initial value + (i32.load (i32.const 100)) ;; Size of value + ) + + (call $assert + (i32.eq + (call $seal_get_storage + (i32.const 0) ;; Pointer to storage key + (i32.const 104) ;; buffer where to copy result + (i32.const 100) ;; pointer to size of buffer + ) + (i32.const 0) ;; ReturnCode::Success + ) + ) + + (call $assert + (i32.eq + (i32.load (i32.const 104)) ;; value received from storage + (i32.load (i32.const 32)) ;; initial value + ) + ) + + ;; Call deployed library contract code. + (set_local $exit_code + (call $seal_delegate_call + (i32.const 0) ;; Set no call flags + (i32.const 64) ;; Pointer to "callee" code_hash. + (i32.const 0) ;; Input is ignored + (i32.const 0) ;; Length of the input + (i32.const 4294967295) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + ) + ) + + ;; Check for success exit status. + (call $assert + (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + ) + + (call $assert + (i32.eq + (call $seal_get_storage + (i32.const 0) ;; Pointer to storage key + (i32.const 104) ;; buffer where to copy result + (i32.const 100) ;; pointer to size of buffer + ) + (i32.const 0) ;; ReturnCode::Success + ) + ) + + ;; Make sure that 'callee' code changed the value + (call $assert + (i32.eq + (i32.load (i32.const 104)) + (i32.const 1) + ) + ) + ) + + (func (export "deploy")) + +) diff --git a/frame/contracts/fixtures/delegate_call_lib.wat b/frame/contracts/fixtures/delegate_call_lib.wat new file mode 100644 index 0000000000000..340b9699f8755 --- /dev/null +++ b/frame/contracts/fixtures/delegate_call_lib.wat @@ -0,0 +1,79 @@ +(module + (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) + (import "seal0" "seal_caller" (func $seal_caller (param i32 i32))) + (import "seal0" "seal_value_transferred" (func $seal_value_transferred (param i32 i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 32) storage key + (data (i32.const 0) "\01") + + ;; [32, 64) buffer for transferred value + + ;; [64, 96) size of the buffer for transferred value + (data (i32.const 64) "\20") + + ;; [96, 128) buffer for the caller + + ;; [128, 160) size of the buffer for caller + (data (i32.const 128) "\20") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + ;; place a value in storage + (call $seal_set_storage + (i32.const 0) ;; Pointer to storage key + (i32.const 0) ;; Pointer to value + (i32.const 32) ;; Size of value + ) + + ;; This stores the value transferred in the buffer + (call $seal_value_transferred (i32.const 32) (i32.const 64)) + + ;; assert len == 8 + (call $assert + (i32.eq + (i32.load (i32.const 64)) + (i32.const 8) + ) + ) + + ;; assert that contents of the buffer is equal to the value + ;; passed to the `caller` contract: 1337 + (call $assert + (i64.eq + (i64.load (i32.const 32)) + (i64.const 1337) + ) + ) + + ;; fill the buffer with the caller. + (call $seal_caller (i32.const 96) (i32.const 128)) + + ;; assert len == 32 + (call $assert + (i32.eq + (i32.load (i32.const 128)) + (i32.const 32) + ) + ) + + ;; assert that the first 64 byte are the beginning of "ALICE", + ;; who is the caller of the `caller` contract + (call $assert + (i64.eq + (i64.load (i32.const 96)) + (i64.const 0x0101010101010101) + ) + ) + ) + + (func (export "deploy")) +) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 71045bde21525..88405eba44205 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1474,6 +1474,58 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + seal_delegate_call { + let r in 0 .. API_BENCHMARK_BATCHES; + let hashes = (0..r * API_BENCHMARK_BATCH_SIZE) + .map(|i| { + let code = WasmModule::::dummy_with_bytes(i); + Contracts::::store_code_raw(code.code, whitelisted_caller())?; + Ok(code.hash) + }) + .collect::, &'static str>>()?; + let hash_len = hashes.get(0).map(|x| x.encode().len()).unwrap_or(0); + let hashes_bytes = hashes.iter().flat_map(|x| x.encode()).collect::>(); + let hashes_len = hashes_bytes.len(); + let hashes_offset = 0; + + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_delegate_call", + params: vec![ + ValueType::I32, + ValueType::I32, + ValueType::I32, + ValueType::I32, + ValueType::I32, + ValueType::I32, + ], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: hashes_offset as u32, + value: hashes_bytes, + }, + ], + call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + Regular(Instruction::I32Const(0)), // flags + Counter(hashes_offset as u32, hash_len as u32), // code_hash_ptr + Regular(Instruction::I32Const(0)), // input_data_ptr + Regular(Instruction::I32Const(0)), // input_data_len + Regular(Instruction::I32Const(u32::max_value() as i32)), // output_ptr + Regular(Instruction::I32Const(0)), // output_len_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let callee = instance.addr.clone(); + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]) + seal_call_per_transfer_input_output_kb { let t in 0 .. 1; let i in 0 .. code::max_pages::() * 64; diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index befdf592f51c0..c6e647e0c8d96 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -104,6 +104,19 @@ pub trait Ext: sealing::Sealed { allows_reentry: bool, ) -> Result; + /// Execute code in the current frame. + /// + /// Returns the original code size of the called contract. + /// + /// # Return Value + /// + /// Result + fn delegate_call( + &mut self, + code: CodeHash, + input_data: Vec, + ) -> Result; + /// Instantiate a contract from the given code. /// /// Returns the original code size of the called contract. @@ -347,6 +360,16 @@ pub struct Frame { nested_storage: storage::meter::NestedMeter, /// If `false` the contract enabled its defense against reentrance attacks. allows_reentry: bool, + /// The caller of the currently executing frame which was spawned by `delegate_call`. + delegate_caller: Option, +} + +/// Used in a delegate call frame arguments in order to override the executable and caller. +struct DelegatedCall { + /// The executable which is run instead of the contracts own `executable`. + executable: E, + /// The account id of the caller contract. + caller: T::AccountId, } /// Parameter passed in when creating a new `Frame`. @@ -358,6 +381,10 @@ enum FrameArgs<'a, T: Config, E> { dest: T::AccountId, /// If `None` the contract info needs to be reloaded from storage. cached_info: Option>, + /// This frame was created by `seal_delegate_call` and hence uses different code than + /// what is stored at [`Self::dest`]. Its caller ([`Frame::delegated_caller`]) is the + /// account which called the caller contract + delegated_call: Option>, }, Instantiate { /// The contract or signed origin which instantiates the new contract. @@ -513,7 +540,7 @@ where debug_message: Option<&'a mut Vec>, ) -> Result { let (mut stack, executable) = Self::new( - FrameArgs::Call { dest, cached_info: None }, + FrameArgs::Call { dest, cached_info: None, delegated_call: None }, origin, gas_meter, storage_meter, @@ -604,33 +631,46 @@ where gas_limit: Weight, schedule: &Schedule, ) -> Result<(Frame, E, Option), ExecError> { - let (account_id, contract_info, executable, entry_point, account_counter) = match frame_args - { - FrameArgs::Call { dest, cached_info } => { - let contract = if let Some(contract) = cached_info { - contract - } else { - >::get(&dest).ok_or(>::ContractNotFound)? - }; - - let executable = E::from_storage(contract.code_hash, schedule, gas_meter)?; - - (dest, contract, executable, ExportedFunction::Call, None) - }, - FrameArgs::Instantiate { sender, trie_seed, executable, salt } => { - let account_id = - >::contract_address(&sender, executable.code_hash(), &salt); - let trie_id = Storage::::generate_trie_id(&account_id, trie_seed); - let contract = Storage::::new_contract( - &account_id, - trie_id, - executable.code_hash().clone(), - )?; - (account_id, contract, executable, ExportedFunction::Constructor, Some(trie_seed)) - }, - }; + let (account_id, contract_info, executable, delegate_caller, entry_point, account_counter) = + match frame_args { + FrameArgs::Call { dest, cached_info, delegated_call } => { + let contract = if let Some(contract) = cached_info { + contract + } else { + >::get(&dest).ok_or(>::ContractNotFound)? + }; + + let (executable, delegate_caller) = + if let Some(DelegatedCall { executable, caller }) = delegated_call { + (executable, Some(caller)) + } else { + (E::from_storage(contract.code_hash, schedule, gas_meter)?, None) + }; + + (dest, contract, executable, delegate_caller, ExportedFunction::Call, None) + }, + FrameArgs::Instantiate { sender, trie_seed, executable, salt } => { + let account_id = + >::contract_address(&sender, executable.code_hash(), &salt); + let trie_id = Storage::::generate_trie_id(&account_id, trie_seed); + let contract = Storage::::new_contract( + &account_id, + trie_id, + executable.code_hash().clone(), + )?; + ( + account_id, + contract, + executable, + None, + ExportedFunction::Constructor, + Some(trie_seed), + ) + }, + }; let frame = Frame { + delegate_caller, value_transferred, contract_info: CachedContract::Cached(contract_info), account_id, @@ -936,8 +976,11 @@ where CachedContract::Cached(contract) => Some(contract.clone()), _ => None, }); - let executable = - self.push_frame(FrameArgs::Call { dest: to, cached_info }, value, gas_limit)?; + let executable = self.push_frame( + FrameArgs::Call { dest: to, cached_info, delegated_call: None }, + value, + gas_limit, + )?; self.run(executable, input_data) }; @@ -950,6 +993,28 @@ where result } + fn delegate_call( + &mut self, + code_hash: CodeHash, + input_data: Vec, + ) -> Result { + let executable = E::from_storage(code_hash, &self.schedule, self.gas_meter())?; + let top_frame = self.top_frame_mut(); + let contract_info = top_frame.contract_info().clone(); + let account_id = top_frame.account_id.clone(); + let value = top_frame.value_transferred.clone(); + let executable = self.push_frame( + FrameArgs::Call { + dest: account_id, + cached_info: Some(contract_info), + delegated_call: Some(DelegatedCall { executable, caller: self.caller().clone() }), + }, + value, + 0, + )?; + self.run(executable, input_data) + } + fn instantiate( &mut self, gas_limit: Weight, @@ -1030,7 +1095,11 @@ where } fn caller(&self) -> &T::AccountId { - self.frames().nth(1).map(|f| &f.account_id).unwrap_or(&self.origin) + if let Some(caller) = &self.top_frame().delegate_caller { + &caller + } else { + self.frames().nth(1).map(|f| &f.account_id).unwrap_or(&self.origin) + } } fn is_contract(&self, address: &T::AccountId) -> bool { diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 9f9cc09f6430a..7e4515868b745 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -570,6 +570,8 @@ pub mod pallet { pub enum Error { /// A new schedule must have a greater version than the current one. InvalidScheduleVersion, + /// Invalid combination of flags supplied to `seal_call` or `seal_delegate_call`. + InvalidCallFlags, /// The executed contract exhausted its gas limit. OutOfGas, /// The output buffer supplied to a contract API call was too small. diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 266c0a6e2748d..e599bdc3125bd 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -358,6 +358,9 @@ pub struct HostFnWeights { /// Weight of calling `seal_call`. pub call: Weight, + /// Weight of calling `seal_delegate_call`. + pub delegate_call: Weight, + /// Weight surcharge that is claimed if `seal_call` does a balance transfer. pub call_transfer_surcharge: Weight, @@ -615,6 +618,7 @@ impl Default for HostFnWeights { take_storage_per_byte: cost_byte_batched!(seal_take_storage_per_kb), transfer: cost_batched!(seal_transfer), call: cost_batched!(seal_call), + delegate_call: cost_batched!(seal_delegate_call), call_transfer_surcharge: cost_batched_args!( seal_call_per_transfer_input_output_kb, 1, diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index d95d434e6a743..6919705206d4a 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -692,6 +692,44 @@ fn deploy_and_call_other_contract() { }); } +#[test] +#[cfg(feature = "unstable-interface")] +fn delegate_call() { + let (caller_wasm, caller_code_hash) = compile_module::("delegate_call").unwrap(); + let (callee_wasm, callee_code_hash) = compile_module::("delegate_call_lib").unwrap(); + let caller_addr = Contracts::contract_address(&ALICE, &caller_code_hash, &[]); + + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Instantiate the 'caller' + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + 300_000, + GAS_LIMIT, + None, + caller_wasm, + vec![], + vec![], + )); + // Only upload 'callee' code + assert_ok!(Contracts::upload_code( + Origin::signed(ALICE), + callee_wasm, + Some(codec::Compact(100_000)), + )); + + assert_ok!(Contracts::call( + Origin::signed(ALICE), + caller_addr.clone(), + 1337, + GAS_LIMIT, + None, + callee_code_hash.as_ref().to_vec(), + )); + }); +} + #[test] fn cannot_self_destruct_through_draning() { let (wasm, code_hash) = compile_module::("drain").unwrap(); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 7c98ee7cf5b1a..3be1062ce969a 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -302,11 +302,18 @@ mod tests { allows_reentry: bool, } + #[derive(Debug, PartialEq, Eq)] + struct CallCodeEntry { + code_hash: H256, + data: Vec, + } + pub struct MockExt { storage: HashMap>, instantiates: Vec, terminations: Vec, calls: Vec, + code_calls: Vec, transfers: Vec, // (topics, data) events: Vec<(Vec, Vec)>, @@ -329,6 +336,7 @@ mod tests { instantiates: Default::default(), terminations: Default::default(), calls: Default::default(), + code_calls: Default::default(), transfers: Default::default(), events: Default::default(), runtime_calls: Default::default(), @@ -354,6 +362,14 @@ mod tests { self.calls.push(CallEntry { to, value, data, allows_reentry }); Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: call_return_data() }) } + fn delegate_call( + &mut self, + code_hash: CodeHash, + data: Vec, + ) -> Result { + self.code_calls.push(CallCodeEntry { code_hash, data }); + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: call_return_data() }) + } fn instantiate( &mut self, gas_limit: Weight, @@ -579,6 +595,53 @@ mod tests { ); } + #[test] + #[cfg(feature = "unstable-interface")] + fn contract_delegate_call() { + const CODE: &str = r#" +(module + ;; seal_delegate_call( + ;; flags: u32, + ;; code_hash_ptr: u32, + ;; input_data_ptr: u32, + ;; input_data_len: u32, + ;; output_ptr: u32, + ;; output_len_ptr: u32 + ;;) -> u32 + (import "__unstable__" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + (func (export "call") + (drop + (call $seal_delegate_call + (i32.const 0) ;; No flags are set + (i32.const 4) ;; Pointer to "callee" code_hash. + (i32.const 36) ;; Pointer to input data buffer address + (i32.const 4) ;; Length of input data buffer + (i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + ) + ) + ) + (func (export "deploy")) + + ;; Callee code_hash + (data (i32.const 4) + "\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11" + "\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11" + ) + + (data (i32.const 36) "\01\02\03\04") +) +"#; + let mut mock_ext = MockExt::default(); + assert_ok!(execute(CODE, vec![], &mut mock_ext)); + + assert_eq!( + &mock_ext.code_calls, + &[CallCodeEntry { code_hash: [0x11; 32].into(), data: vec![1, 2, 3, 4] }] + ); + } + #[test] fn contract_call_forward_input() { const CODE: &str = r#" diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 194d5ffbaaf4f..55ab0dfa0adef 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -190,6 +190,9 @@ pub enum RuntimeCosts { Transfer, /// Weight of calling `seal_call` for the given input size. CallBase(u32), + /// Weight of calling `seal_delegate_call` for the given input size. + #[cfg(feature = "unstable-interface")] + DelegateCallBase(u32), /// Weight of the transfer performed during a call. CallSurchargeTransfer, /// Weight of output received through `seal_call` for the given size. @@ -275,6 +278,9 @@ impl RuntimeCosts { s.call.saturating_add(s.call_per_input_byte.saturating_mul(len.into())), CallSurchargeTransfer => s.call_transfer_surcharge, CallCopyOut(len) => s.call_per_output_byte.saturating_mul(len.into()), + #[cfg(feature = "unstable-interface")] + DelegateCallBase(len) => + s.delegate_call.saturating_add(s.call_per_input_byte.saturating_mul(len.into())), InstantiateBase { input_data_len, salt_len } => s .instantiate .saturating_add(s.instantiate_per_input_byte.saturating_mul(input_data_len.into())) @@ -327,7 +333,7 @@ where } bitflags! { - /// Flags used to change the behaviour of `seal_call`. + /// Flags used to change the behaviour of `seal_call` and `seal_delegate_call`. struct CallFlags: u32 { /// Forward the input of current function to the callee. /// @@ -363,10 +369,34 @@ bitflags! { /// Without this flag any reentrancy into the current contract that originates from /// the callee (or any of its callees) is denied. This includes the first callee: /// You cannot call into yourself with this flag set. + /// + /// # Note + /// + /// For `seal_delegate_call` should be always unset, otherwise + /// [`Error::InvalidCallFlags`] is returned. const ALLOW_REENTRY = 0b0000_1000; } } +/// The kind of call that should be performed. +enum CallType { + /// Execute another instantiated contract + Call { callee_ptr: u32, value_ptr: u32, gas: u64 }, + #[cfg(feature = "unstable-interface")] + /// Execute deployed code in the context (storage, account ID, value) of the caller contract + DelegateCall { code_hash_ptr: u32 }, +} + +impl CallType { + fn cost(&self, input_data_len: u32) -> RuntimeCosts { + match self { + CallType::Call { .. } => RuntimeCosts::CallBase(input_data_len), + #[cfg(feature = "unstable-interface")] + CallType::DelegateCall { .. } => RuntimeCosts::DelegateCallBase(input_data_len), + } + } +} + /// This is only appropriate when writing out data of constant size that does not depend on user /// input. In this case the costs for this copy was already charged as part of the token at /// the beginning of the API entry point. @@ -411,7 +441,7 @@ where // The trap was the result of the execution `return` host function. TrapReason::Return(ReturnData { flags, data }) => { let flags = ReturnFlags::from_bits(flags) - .ok_or_else(|| "used reserved bit in return flags")?; + .ok_or_else(|| Error::::InvalidCallFlags)?; Ok(ExecReturnValue { flags, data: Bytes(data) }) }, TrapReason::Termination => @@ -693,18 +723,13 @@ where fn call( &mut self, flags: CallFlags, - callee_ptr: u32, - gas: u64, - value_ptr: u32, + call_type: CallType, input_data_ptr: u32, input_data_len: u32, output_ptr: u32, output_len_ptr: u32, ) -> Result { - self.charge_gas(RuntimeCosts::CallBase(input_data_len))?; - let callee: <::T as frame_system::Config>::AccountId = - self.read_sandbox_memory_as(callee_ptr)?; - let value: BalanceOf<::T> = self.read_sandbox_memory_as(value_ptr)?; + self.charge_gas(call_type.cost(input_data_len))?; let input_data = if flags.contains(CallFlags::CLONE_INPUT) { self.input_data.as_ref().ok_or_else(|| Error::::InputForwarded)?.clone() } else if flags.contains(CallFlags::FORWARD_INPUT) { @@ -712,12 +737,32 @@ where } else { self.read_sandbox_memory(input_data_ptr, input_data_len)? }; - if value > 0u32.into() { - self.charge_gas(RuntimeCosts::CallSurchargeTransfer)?; - } - let ext = &mut self.ext; - let call_outcome = - ext.call(gas, callee, value, input_data, flags.contains(CallFlags::ALLOW_REENTRY)); + + let call_outcome = match call_type { + CallType::Call { callee_ptr, value_ptr, gas } => { + let callee: <::T as frame_system::Config>::AccountId = + self.read_sandbox_memory_as(callee_ptr)?; + let value: BalanceOf<::T> = self.read_sandbox_memory_as(value_ptr)?; + if value > 0u32.into() { + self.charge_gas(RuntimeCosts::CallSurchargeTransfer)?; + } + self.ext.call( + gas, + callee, + value, + input_data, + flags.contains(CallFlags::ALLOW_REENTRY), + ) + }, + #[cfg(feature = "unstable-interface")] + CallType::DelegateCall { code_hash_ptr } => { + if flags.contains(CallFlags::ALLOW_REENTRY) { + return Err(Error::::InvalidCallFlags.into()) + } + let code_hash = self.read_sandbox_memory_as(code_hash_ptr)?; + self.ext.delegate_call(code_hash, input_data) + }, + }; // `TAIL_CALL` only matters on an `OK` result. Otherwise the call stack comes to // a halt anyways without anymore code being executed. @@ -990,9 +1035,7 @@ define_env!(Env, , ) -> ReturnCode => { ctx.call( CallFlags::ALLOW_REENTRY, - callee_ptr, - gas, - value_ptr, + CallType::Call{callee_ptr, value_ptr, gas}, input_data_ptr, input_data_len, output_ptr, @@ -1041,10 +1084,51 @@ define_env!(Env, , output_len_ptr: u32 ) -> ReturnCode => { ctx.call( - CallFlags::from_bits(flags).ok_or_else(|| "used reserved bit in CallFlags")?, - callee_ptr, - gas, - value_ptr, + CallFlags::from_bits(flags).ok_or_else(|| Error::::InvalidCallFlags)?, + CallType::Call{callee_ptr, value_ptr, gas}, + input_data_ptr, + input_data_len, + output_ptr, + output_len_ptr, + ) + }, + + // Execute code in the context (storage, caller, value) of the current contract. + // + // Reentrancy protection is always disabled since the callee is allowed + // to modify the callers storage. This makes going through a reentrancy attack + // unnecessary for the callee when it wants to exploit the caller. + // + // # Parameters + // + // - flags: See [`CallFlags`] for a documentation of the supported flags. + // - code_hash: a pointer to the hash of the code to be called. + // - input_data_ptr: a pointer to a buffer to be used as input data to the callee. + // - input_data_len: length of the input data buffer. + // - output_ptr: a pointer where the output buffer is copied to. + // - output_len_ptr: in-out pointer to where the length of the buffer is read from + // and the actual length is written to. + // + // # Errors + // + // An error means that the call wasn't successful and no output buffer is returned unless + // stated otherwise. + // + // `ReturnCode::CalleeReverted`: Output buffer is returned. + // `ReturnCode::CalleeTrapped` + // `ReturnCode::CodeNotFound` + [__unstable__] seal_delegate_call( + ctx, + flags: u32, + code_hash_ptr: u32, + input_data_ptr: u32, + input_data_len: u32, + output_ptr: u32, + output_len_ptr: u32 + ) -> ReturnCode => { + ctx.call( + CallFlags::from_bits(flags).ok_or_else(|| Error::::InvalidCallFlags)?, + CallType::DelegateCall{code_hash_ptr}, input_data_ptr, input_data_len, output_ptr, diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index b58660b694ca9..ec6dcd2eee892 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -88,6 +88,7 @@ pub trait WeightInfo { fn seal_take_storage_per_kb(n: u32, ) -> Weight; fn seal_transfer(r: u32, ) -> Weight; fn seal_call(r: u32, ) -> Weight; + fn seal_delegate_call(r: u32, ) -> Weight; fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight; fn seal_instantiate(r: u32, ) -> Weight; fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight; @@ -618,6 +619,17 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + fn seal_delegate_call(r: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 11_788_000 + .saturating_add((19_855_594_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) @@ -1486,6 +1498,17 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + fn seal_delegate_call(r: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 11_788_000 + .saturating_add((19_855_594_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) From 1532b72162240edf0d41ecb39e66e2a1f5a73b6f Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 8 Feb 2022 15:10:35 +0100 Subject: [PATCH 0493/1472] Add Storage Info to Various Pallets (#10810) * atomic swap * bounties * bounties fmt * gilt * indices * nicks * randomness-collective-flip * recovery * reuse maxapprovals * Update tests.rs * Update frame/randomness-collective-flip/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * use the correct bound * complete recovery * use `bounded_vec` macro * Update tests.rs * transaction payment * uniques * mmr * example offchain worker * beefy-mmr * Update frame/recovery/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Use BoundedVec instead of a type-parameterized BoundedString * cargo fmt * Update frame/atomic-swap/src/lib.rs * use config const * Update lib.rs * update mel_bound * fmt Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Keith Yeung --- frame/atomic-swap/src/lib.rs | 13 +++-- frame/bags-list/src/list/mod.rs | 4 +- frame/beefy-mmr/src/lib.rs | 1 - frame/bounties/src/lib.rs | 26 ++++----- frame/contracts/src/wasm/mod.rs | 2 +- .../election-provider-multi-phase/src/lib.rs | 2 +- frame/examples/offchain-worker/src/lib.rs | 15 +++--- frame/examples/offchain-worker/src/tests.rs | 1 + frame/gilt/src/lib.rs | 43 ++++++++++----- frame/grandpa/src/lib.rs | 8 +-- frame/identity/src/types.rs | 8 +-- frame/im-online/src/lib.rs | 3 +- frame/indices/src/lib.rs | 4 +- frame/merkle-mountain-range/src/lib.rs | 4 +- frame/nicks/src/lib.rs | 24 ++++++--- frame/randomness-collective-flip/src/lib.rs | 8 ++- frame/recovery/src/lib.rs | 53 ++++++++++++------- frame/recovery/src/mock.rs | 4 +- frame/recovery/src/tests.rs | 16 ++++-- frame/staking/src/lib.rs | 2 +- frame/transaction-payment/src/lib.rs | 5 +- frame/treasury/src/lib.rs | 2 + frame/uniques/src/lib.rs | 11 ++-- frame/uniques/src/types.rs | 17 +++--- primitives/beefy/src/mmr.rs | 4 +- 25 files changed, 165 insertions(+), 115 deletions(-) diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index e83055b4d283e..e57496954a574 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -45,6 +45,7 @@ mod tests; use codec::{Decode, Encode}; use frame_support::{ dispatch::DispatchResult, + pallet_prelude::MaxEncodedLen, traits::{BalanceStatus, Currency, Get, ReservableCurrency}, weights::Weight, RuntimeDebugNoBound, @@ -59,8 +60,9 @@ use sp_std::{ }; /// Pending atomic swap operation. -#[derive(Clone, Eq, PartialEq, RuntimeDebugNoBound, Encode, Decode, TypeInfo)] +#[derive(Clone, Eq, PartialEq, RuntimeDebugNoBound, Encode, Decode, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(T))] +#[codec(mel_bound())] pub struct PendingSwap { /// Source of the swap. pub source: T::AccountId, @@ -93,8 +95,9 @@ pub trait SwapAction { } /// A swap action that only allows transferring balances. -#[derive(Clone, RuntimeDebug, Eq, PartialEq, Encode, Decode, TypeInfo)] +#[derive(Clone, RuntimeDebug, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(C))] +#[codec(mel_bound())] pub struct BalanceSwapAction> { value: >::Balance, _marker: PhantomData, @@ -165,7 +168,7 @@ pub mod pallet { /// The overarching event type. type Event: From> + IsType<::Event>; /// Swap action. - type SwapAction: SwapAction + Parameter; + type SwapAction: SwapAction + Parameter + MaxEncodedLen; /// Limit of proof size. /// /// Atomic swap is only atomic if once the proof is revealed, both parties can submit the @@ -182,7 +185,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::storage] @@ -193,6 +195,9 @@ pub mod pallet { Blake2_128Concat, HashedProof, PendingSwap, + OptionQuery, + GetDefault, + ConstU32<300_000>, >; #[pallet::error] diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index aba31b67b2863..8cd89b8fff1cc 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -545,7 +545,7 @@ impl List { /// iteration so that there's no incentive to churn ids positioning to improve the chances of /// appearing within the ids set. #[derive(DefaultNoBound, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[codec(mel_bound(T: Config))] +#[codec(mel_bound())] #[scale_info(skip_type_params(T))] #[cfg_attr(feature = "std", derive(frame_support::DebugNoBound, Clone, PartialEq))] pub struct Bag { @@ -748,7 +748,7 @@ impl Bag { /// A Node is the fundamental element comprising the doubly-linked list described by `Bag`. #[derive(Encode, Decode, MaxEncodedLen, TypeInfo)] -#[codec(mel_bound(T: Config))] +#[codec(mel_bound())] #[scale_info(skip_type_params(T))] #[cfg_attr(feature = "std", derive(frame_support::DebugNoBound, Clone, PartialEq))] pub struct Node { diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index d66de51d9af21..38d0a6ac9a7f8 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -119,7 +119,6 @@ pub mod pallet { /// BEEFY-MMR pallet. #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); /// The module's configuration trait. diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index d46180f6bbe19..988b15c58a13f 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -107,7 +107,7 @@ type PositiveImbalanceOf = pallet_treasury::PositiveImbalanceOf; pub type BountyIndex = u32; /// A bounty proposal. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Bounty { /// The account proposing it. proposer: AccountId, @@ -133,7 +133,7 @@ impl } /// The status of a bounty proposal. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum BountyStatus { /// The bounty is proposed and waiting for approval. Proposed, @@ -180,7 +180,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -249,6 +248,8 @@ pub mod pallet { Premature, /// The bounty cannot be closed because it has active child-bounties. HasActiveChildBounty, + /// Too many approvals are already queued. + TooManyQueued, } #[pallet::event] @@ -288,12 +289,14 @@ pub mod pallet { /// The description of each bounty. #[pallet::storage] #[pallet::getter(fn bounty_descriptions)] - pub type BountyDescriptions = StorageMap<_, Twox64Concat, BountyIndex, Vec>; + pub type BountyDescriptions = + StorageMap<_, Twox64Concat, BountyIndex, BoundedVec>; /// Bounty indices that have been approved but not yet funded. #[pallet::storage] #[pallet::getter(fn bounty_approvals)] - pub type BountyApprovals = StorageValue<_, Vec, ValueQuery>; + pub type BountyApprovals = + StorageValue<_, BoundedVec, ValueQuery>; #[pallet::call] impl Pallet { @@ -341,7 +344,8 @@ pub mod pallet { bounty.status = BountyStatus::Approved; - BountyApprovals::::append(bounty_id); + BountyApprovals::::try_append(bounty_id) + .map_err(|()| Error::::TooManyQueued)?; Ok(()) })?; @@ -780,17 +784,15 @@ impl Pallet { description: Vec, value: BalanceOf, ) -> DispatchResult { - ensure!( - description.len() <= T::MaximumReasonLength::get() as usize, - Error::::ReasonTooBig - ); + let bounded_description: BoundedVec<_, _> = + description.try_into().map_err(|()| Error::::ReasonTooBig)?; ensure!(value >= T::BountyValueMinimum::get(), Error::::InvalidValue); let index = Self::bounty_count(); // reserve deposit for new bounty let bond = T::BountyDepositBase::get() + - T::DataDepositPerByte::get() * (description.len() as u32).into(); + T::DataDepositPerByte::get() * (bounded_description.len() as u32).into(); T::Currency::reserve(&proposer, bond) .map_err(|_| Error::::InsufficientProposersBalance)?; @@ -806,7 +808,7 @@ impl Pallet { }; Bounties::::insert(index, &bounty); - BountyDescriptions::::insert(index, description); + BountyDescriptions::::insert(index, bounded_description); Self::deposit_event(Event::::BountyProposed { index }); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 3be1062ce969a..491daa58523e6 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -87,7 +87,7 @@ pub struct PrefabWasmModule { /// /// It is stored in a separate storage entry to avoid loading the code when not necessary. #[derive(Clone, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen)] -#[codec(mel_bound(T: Config))] +#[codec(mel_bound())] #[scale_info(skip_type_params(T))] pub struct OwnerInfo { /// The account that has deployed the contract and hence is allowed to remove it. diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index a5ed593e1a4ee..cad3d12605e48 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -460,7 +460,7 @@ pub struct ReadySolution { /// /// These are stored together because they are often accessed together. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default, TypeInfo)] -#[codec(mel_bound(T: Config))] +#[codec(mel_bound())] #[scale_info(skip_type_params(T))] pub struct RoundSnapshot { /// All of the voters. diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index 08f449f8d51d0..3cf718217b062 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -154,11 +154,14 @@ pub mod pallet { /// multiple pallets send unsigned transactions. #[pallet::constant] type UnsignedPriority: Get; + + /// Maximum number of prices. + #[pallet::constant] + type MaxPrices: Get; } #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] @@ -330,7 +333,7 @@ pub mod pallet { /// This is used to calculate average price, should have bounded size. #[pallet::storage] #[pallet::getter(fn prices)] - pub(super) type Prices = StorageValue<_, Vec, ValueQuery>; + pub(super) type Prices = StorageValue<_, BoundedVec, ValueQuery>; /// Defines the block when next unsigned transaction will be accepted. /// @@ -645,12 +648,8 @@ impl Pallet { fn add_price(maybe_who: Option, price: u32) { log::info!("Adding to the average: {}", price); >::mutate(|prices| { - const MAX_LEN: usize = 64; - - if prices.len() < MAX_LEN { - prices.push(price); - } else { - prices[price as usize % MAX_LEN] = price; + if prices.try_push(price).is_err() { + prices[(price % T::MaxPrices::get()) as usize] = price; } }); diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 76f80deb12f90..e5bd9fabc629b 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -123,6 +123,7 @@ impl Config for Test { type GracePeriod = ConstU64<5>; type UnsignedInterval = ConstU64<128>; type UnsignedPriority = UnsignedPriority; + type MaxPrices = ConstU32<64>; } fn test_pub() -> sp_core::sr25519::Public { diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index ac56dc108b2f6..8956e04857f2c 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -112,7 +112,8 @@ pub mod pallet { + sp_std::fmt::Debug + Default + From - + TypeInfo; + + TypeInfo + + MaxEncodedLen; /// Origin required for setting the target proportion to be under gilt. type AdminOrigin: EnsureOrigin; @@ -178,11 +179,12 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); /// A single bid on a gilt, an item of a *queue* in `Queues`. - #[derive(Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo)] + #[derive( + Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, + )] pub struct GiltBid { /// The amount bid. pub amount: Balance, @@ -191,7 +193,9 @@ pub mod pallet { } /// Information representing an active gilt. - #[derive(Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo)] + #[derive( + Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, + )] pub struct ActiveGilt { /// The proportion of the effective total issuance (i.e. accounting for any eventual gilt /// expansion or contraction that may eventually be claimed). @@ -215,7 +219,9 @@ pub mod pallet { /// `issuance - frozen + proportion * issuance` /// /// where `issuance = total_issuance - IgnoredIssuance` - #[derive(Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo)] + #[derive( + Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, + )] pub struct ActiveGiltsTotal { /// The total amount of funds held in reserve for all active gilts. pub frozen: Balance, @@ -233,12 +239,18 @@ pub mod pallet { /// The vector is indexed by duration in `Period`s, offset by one, so information on the queue /// whose duration is one `Period` would be storage `0`. #[pallet::storage] - pub type QueueTotals = StorageValue<_, Vec<(u32, BalanceOf)>, ValueQuery>; + pub type QueueTotals = + StorageValue<_, BoundedVec<(u32, BalanceOf), T::QueueCount>, ValueQuery>; /// The queues of bids ready to become gilts. Indexed by duration (in `Period`s). #[pallet::storage] - pub type Queues = - StorageMap<_, Blake2_128Concat, u32, Vec, T::AccountId>>, ValueQuery>; + pub type Queues = StorageMap< + _, + Blake2_128Concat, + u32, + BoundedVec, T::AccountId>, T::MaxQueueLen>, + ValueQuery, + >; /// Information relating to the gilts currently active. #[pallet::storage] @@ -265,7 +277,11 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - QueueTotals::::put(vec![(0, BalanceOf::::zero()); T::QueueCount::get() as usize]); + let unbounded = vec![(0, BalanceOf::::zero()); T::QueueCount::get() as usize]; + let bounded: BoundedVec<_, _> = unbounded + .try_into() + .expect("QueueTotals should support up to QueueCount items. qed"); + QueueTotals::::put(bounded); } } @@ -366,7 +382,7 @@ pub mod pallet { T::Currency::unreserve(&bid.who, bid.amount); (0, amount - bid.amount) } else { - q.insert(0, bid); + q.try_insert(0, bid).expect("verified queue was not full above. qed."); (1, amount) }; @@ -379,7 +395,7 @@ pub mod pallet { }, )?; QueueTotals::::mutate(|qs| { - qs.resize(queue_count, (0, Zero::zero())); + qs.bounded_resize(queue_count, (0, Zero::zero())); qs[queue_index].0 += net.0; qs[queue_index].1 = qs[queue_index].1.saturating_add(net.1); }); @@ -415,7 +431,7 @@ pub mod pallet { })?; QueueTotals::::mutate(|qs| { - qs.resize(queue_count, (0, Zero::zero())); + qs.bounded_resize(queue_count, (0, Zero::zero())); qs[queue_index].0 = new_len; qs[queue_index].1 = qs[queue_index].1.saturating_sub(bid.amount); }); @@ -592,7 +608,8 @@ pub mod pallet { if remaining < bid.amount { let overflow = bid.amount - remaining; bid.amount = remaining; - q.push(GiltBid { amount: overflow, who: bid.who.clone() }); + q.try_push(GiltBid { amount: overflow, who: bid.who.clone() }) + .expect("just popped, so there must be space. qed"); } let amount = bid.amount; // Can never overflow due to block above. diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 0aaf0f679ce11..68d4cf26a2e23 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -364,13 +364,9 @@ pub type BoundedAuthorityList = WeakBoundedVec<(AuthorityId, AuthorityWei /// A stored pending change. /// `Limit` is the bound for `next_authorities` #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] -#[codec(mel_bound(Limit: Get))] +#[codec(mel_bound(N: MaxEncodedLen, Limit: Get))] #[scale_info(skip_type_params(Limit))] -pub struct StoredPendingChange -where - Limit: Get, - N: MaxEncodedLen, -{ +pub struct StoredPendingChange { /// The block number this was scheduled at. pub scheduled_at: N, /// The delay in blocks until it will be applied. diff --git a/frame/identity/src/types.rs b/frame/identity/src/types.rs index d91adc8cdd768..cb79ace98d81c 100644 --- a/frame/identity/src/types.rs +++ b/frame/identity/src/types.rs @@ -283,7 +283,7 @@ impl TypeInfo for IdentityFields { #[derive( CloneNoBound, Encode, Decode, Eq, MaxEncodedLen, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo, )] -#[codec(mel_bound(FieldLimit: Get))] +#[codec(mel_bound())] #[cfg_attr(test, derive(frame_support::DefaultNoBound))] #[scale_info(skip_type_params(FieldLimit))] pub struct IdentityInfo> { @@ -339,11 +339,7 @@ pub struct IdentityInfo> { #[derive( CloneNoBound, Encode, Eq, MaxEncodedLen, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo, )] -#[codec(mel_bound( - Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq + Zero + Add, - MaxJudgements: Get, - MaxAdditionalFields: Get, -))] +#[codec(mel_bound())] #[scale_info(skip_type_params(MaxJudgements, MaxAdditionalFields))] pub struct Registration< Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq, diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 5ad27850a2c1f..e2213ef4169b1 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -238,8 +238,7 @@ where /// `MultiAddrEncodingLimit` represents the size limit of the encoding of `MultiAddr` /// `AddressesLimit` represents the size limit of the vector of peers connected #[derive(Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[codec(mel_bound(PeerIdEncodingLimit: Get, - MultiAddrEncodingLimit: Get, AddressesLimit: Get))] +#[codec(mel_bound())] #[scale_info(skip_type_params(PeerIdEncodingLimit, MultiAddrEncodingLimit, AddressesLimit))] pub struct BoundedOpaqueNetworkState where diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index 7d23fa5e8c7f1..9c9e3580f2c04 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -56,7 +56,8 @@ pub mod pallet { + Codec + Default + AtLeast32Bit - + Copy; + + Copy + + MaxEncodedLen; /// The currency trait. type Currency: ReservableCurrency; @@ -74,7 +75,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::call] diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 2a93dc7af2892..f904428e02048 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -84,7 +84,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(PhantomData<(T, I)>); /// This pallet's configuration trait @@ -126,7 +125,8 @@ pub mod pallet { + Default + codec::Codec + codec::EncodeLike - + scale_info::TypeInfo; + + scale_info::TypeInfo + + MaxEncodedLen; /// Data stored in the leaf nodes. /// diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 9e4ecf8b2b1a3..c7c2c675bc014 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -110,11 +110,10 @@ pub mod pallet { /// The lookup table for names. #[pallet::storage] pub(super) type NameOf = - StorageMap<_, Twox64Concat, T::AccountId, (Vec, BalanceOf)>; + StorageMap<_, Twox64Concat, T::AccountId, (BoundedVec, BalanceOf)>; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::call] @@ -139,8 +138,9 @@ pub mod pallet { pub fn set_name(origin: OriginFor, name: Vec) -> DispatchResult { let sender = ensure_signed(origin)?; - ensure!(name.len() >= T::MinLength::get() as usize, Error::::TooShort); - ensure!(name.len() <= T::MaxLength::get() as usize, Error::::TooLong); + let bounded_name: BoundedVec<_, _> = + name.try_into().map_err(|()| Error::::TooLong)?; + ensure!(bounded_name.len() >= T::MinLength::get() as usize, Error::::TooShort); let deposit = if let Some((_, deposit)) = >::get(&sender) { Self::deposit_event(Event::::NameChanged { who: sender.clone() }); @@ -152,7 +152,7 @@ pub mod pallet { deposit }; - >::insert(&sender, (name, deposit)); + >::insert(&sender, (bounded_name, deposit)); Ok(()) } @@ -230,9 +230,11 @@ pub mod pallet { ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; + let bounded_name: BoundedVec<_, _> = + name.try_into().map_err(|()| Error::::TooLong)?; let target = T::Lookup::lookup(target)?; let deposit = >::get(&target).map(|x| x.1).unwrap_or_else(Zero::zero); - >::insert(&target, (name, deposit)); + >::insert(&target, (bounded_name, deposit)); Self::deposit_event(Event::::NameForced { target }); Ok(()) @@ -356,9 +358,15 @@ mod tests { assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); assert_eq!(Balances::reserved_balance(2), 2); - assert_ok!(Nicks::force_name(Origin::signed(1), 2, b"Dr. David Brubeck, III".to_vec())); + assert_noop!( + Nicks::force_name(Origin::signed(1), 2, b"Dr. David Brubeck, III".to_vec()), + Error::::TooLong, + ); + assert_ok!(Nicks::force_name(Origin::signed(1), 2, b"Dr. Brubeck, III".to_vec())); assert_eq!(Balances::reserved_balance(2), 2); - assert_eq!(>::get(2).unwrap(), (b"Dr. David Brubeck, III".to_vec(), 2)); + let (name, amount) = >::get(2).unwrap(); + assert_eq!(name, b"Dr. Brubeck, III".to_vec()); + assert_eq!(amount, 2); }); } diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index a74c58405de4f..b72aa665550cf 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -91,7 +91,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -103,9 +102,7 @@ pub mod pallet { let parent_hash = >::parent_hash(); >::mutate(|ref mut values| { - if values.len() < RANDOM_MATERIAL_LEN as usize { - values.push(parent_hash) - } else { + if values.try_push(parent_hash).is_err() { let index = block_number_to_index::(block_number); values[index] = parent_hash; } @@ -120,7 +117,8 @@ pub mod pallet { /// the oldest hash. #[pallet::storage] #[pallet::getter(fn random_material)] - pub(super) type RandomMaterial = StorageValue<_, Vec, ValueQuery>; + pub(super) type RandomMaterial = + StorageValue<_, BoundedVec>, ValueQuery>; } impl Randomness for Pallet { diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index f5a57843a983b..adc5c0b895c5f 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -154,7 +154,7 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::traits::{CheckedAdd, CheckedMul, Dispatchable, SaturatedConversion}; use sp_std::prelude::*; @@ -163,7 +163,7 @@ use frame_support::{ dispatch::PostDispatchInfo, traits::{BalanceStatus, Currency, ReservableCurrency}, weights::GetDispatchInfo, - RuntimeDebug, + BoundedVec, RuntimeDebug, }; pub use pallet::*; @@ -176,21 +176,23 @@ mod tests; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type FriendsOf = BoundedVec<::AccountId, ::MaxFriends>; + /// An active recovery process. -#[derive(Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo)] -pub struct ActiveRecovery { +#[derive(Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct ActiveRecovery { /// The block number when the recovery process started. created: BlockNumber, /// The amount held in reserve of the `depositor`, /// To be returned once this recovery process is closed. deposit: Balance, /// The friends which have vouched so far. Always sorted. - friends: Vec, + friends: Friends, } /// Configuration for recovering an account. -#[derive(Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo)] -pub struct RecoveryConfig { +#[derive(Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct RecoveryConfig { /// The minimum number of blocks since the start of the recovery process before the account /// can be recovered. delay_period: BlockNumber, @@ -198,7 +200,7 @@ pub struct RecoveryConfig { /// to be returned once this configuration is removed. deposit: Balance, /// The list of friends which can help recover an account. Always sorted. - friends: Vec, + friends: Friends, /// The number of approving friends needed to recover an account. threshold: u16, } @@ -212,7 +214,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); /// Configuration trait. @@ -245,8 +246,13 @@ pub mod pallet { type FriendDepositFactor: Get>; /// The maximum amount of friends allowed in a recovery configuration. + /// + /// NOTE: The threshold programmed in this Pallet uses u16, so it does + /// not really make sense to have a limit here greater than u16::MAX. + /// But also, that is a lot more than you should probably set this value + /// to anyway... #[pallet::constant] - type MaxFriends: Get; + type MaxFriends: Get; /// The base amount of currency needed to reserve for starting a recovery. /// @@ -324,7 +330,7 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - RecoveryConfig, T::AccountId>, + RecoveryConfig, FriendsOf>, >; /// Active recovery attempts. @@ -339,7 +345,7 @@ pub mod pallet { T::AccountId, Twox64Concat, T::AccountId, - ActiveRecovery, T::AccountId>, + ActiveRecovery, FriendsOf>, >; /// The list of allowed proxy accounts. @@ -458,12 +464,12 @@ pub mod pallet { ensure!(threshold >= 1, Error::::ZeroThreshold); ensure!(!friends.is_empty(), Error::::NotEnoughFriends); ensure!(threshold as usize <= friends.len(), Error::::NotEnoughFriends); - let max_friends = T::MaxFriends::get() as usize; - ensure!(friends.len() <= max_friends, Error::::MaxFriends); - ensure!(Self::is_sorted_and_unique(&friends), Error::::NotSorted); + let bounded_friends: FriendsOf = + friends.try_into().map_err(|()| Error::::MaxFriends)?; + ensure!(Self::is_sorted_and_unique(&bounded_friends), Error::::NotSorted); // Total deposit is base fee + number of friends * factor fee let friend_deposit = T::FriendDepositFactor::get() - .checked_mul(&friends.len().saturated_into()) + .checked_mul(&bounded_friends.len().saturated_into()) .ok_or(ArithmeticError::Overflow)?; let total_deposit = T::ConfigDepositBase::get() .checked_add(&friend_deposit) @@ -471,8 +477,12 @@ pub mod pallet { // Reserve the deposit T::Currency::reserve(&who, total_deposit)?; // Create the recovery configuration - let recovery_config = - RecoveryConfig { delay_period, deposit: total_deposit, friends, threshold }; + let recovery_config = RecoveryConfig { + delay_period, + deposit: total_deposit, + friends: bounded_friends, + threshold, + }; // Create the recovery configuration storage item >::insert(&who, recovery_config); @@ -519,7 +529,7 @@ pub mod pallet { let recovery_status = ActiveRecovery { created: >::block_number(), deposit: recovery_deposit, - friends: vec![], + friends: Default::default(), }; // Create the active recovery storage item >::insert(&account, &who, recovery_status); @@ -571,7 +581,10 @@ pub mod pallet { // Either insert the vouch, or return an error that the user already vouched. match active_recovery.friends.binary_search(&who) { Ok(_pos) => Err(Error::::AlreadyVouched)?, - Err(pos) => active_recovery.friends.insert(pos, who.clone()), + Err(pos) => active_recovery + .friends + .try_insert(pos, who.clone()) + .map_err(|()| Error::::MaxFriends)?, } // Update storage with the latest details >::insert(&lost, &rescuer, active_recovery); diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 577aa7dee7117..2088f9eb0937e 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -22,7 +22,7 @@ use super::*; use crate as recovery; use frame_support::{ parameter_types, - traits::{ConstU16, ConstU32, ConstU64, OnFinalize, OnInitialize}, + traits::{ConstU32, ConstU64, OnFinalize, OnInitialize}, }; use sp_core::H256; use sp_runtime::{ @@ -105,7 +105,7 @@ impl Config for Test { type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; - type MaxFriends = ConstU16<3>; + type MaxFriends = ConstU32<3>; type RecoveryDeposit = RecoveryDeposit; } diff --git a/frame/recovery/src/tests.rs b/frame/recovery/src/tests.rs index 7d1da6353a3ad..16fc678d357bb 100644 --- a/frame/recovery/src/tests.rs +++ b/frame/recovery/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for the module. use super::*; -use frame_support::{assert_noop, assert_ok, traits::Currency}; +use frame_support::{assert_noop, assert_ok, bounded_vec, traits::Currency}; use mock::{ new_test_ext, run_to_block, Balances, BalancesCall, Call, Origin, Recovery, RecoveryCall, Test, }; @@ -201,8 +201,12 @@ fn create_recovery_works() { // Base 10 + 1 per friends = 13 total reserved assert_eq!(Balances::reserved_balance(5), 13); // Recovery configuration is correctly stored - let recovery_config = - RecoveryConfig { delay_period, deposit: 13, friends: friends.clone(), threshold }; + let recovery_config = RecoveryConfig { + delay_period, + deposit: 13, + friends: friends.try_into().unwrap(), + threshold, + }; assert_eq!(Recovery::recovery_config(5), Some(recovery_config)); }); } @@ -254,7 +258,8 @@ fn initiate_recovery_works() { // Deposit is reserved assert_eq!(Balances::reserved_balance(1), 10); // Recovery status object is created correctly - let recovery_status = ActiveRecovery { created: 0, deposit: 10, friends: vec![] }; + let recovery_status = + ActiveRecovery { created: 0, deposit: 10, friends: Default::default() }; assert_eq!(>::get(&5, &1), Some(recovery_status)); // Multiple users can attempt to recover the same account assert_ok!(Recovery::initiate_recovery(Origin::signed(2), 5)); @@ -314,7 +319,8 @@ fn vouch_recovery_works() { assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); // Final recovery status object is updated correctly - let recovery_status = ActiveRecovery { created: 0, deposit: 10, friends: vec![2, 3, 4] }; + let recovery_status = + ActiveRecovery { created: 0, deposit: 10, friends: bounded_vec![2, 3, 4] }; assert_eq!(>::get(&5, &1), Some(recovery_status)); }); } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index f1d4cd1e07c2a..17af4829c0ea8 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -576,7 +576,7 @@ where /// A record of the nominations made by a specific account. #[derive(PartialEqNoBound, EqNoBound, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo)] -#[codec(mel_bound(T: Config))] +#[codec(mel_bound())] #[scale_info(skip_type_params(T))] pub struct Nominations { /// The targets of nomination. diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 16d2ff5827c4f..e4d77a05f284b 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -47,7 +47,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ @@ -226,7 +226,7 @@ where } /// Storage releases of the pallet. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] enum Releases { /// Original version of the pallet. V1Ancient, @@ -248,7 +248,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 762c0e592d891..81fca5243afa3 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -193,6 +193,8 @@ pub mod pallet { type SpendFunds: SpendFunds; /// The maximum number of approvals that can wait in the spending queue. + /// + /// NOTE: This parameter is also used within the Bounties Pallet extension if enabled. #[pallet::constant] type MaxApprovals: Get; } diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 3a0b34e5bf407..2956735e5ec3e 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -62,7 +62,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -72,10 +71,16 @@ pub mod pallet { type Event: From> + IsType<::Event>; /// Identifier for the class of asset. - type ClassId: Member + Parameter + Default + Copy + HasCompact; + type ClassId: Member + Parameter + Default + Copy + HasCompact + MaxEncodedLen; /// The type used to identify a unique asset within an asset class. - type InstanceId: Member + Parameter + Default + Copy + HasCompact + From; + type InstanceId: Member + + Parameter + + Default + + Copy + + HasCompact + + From + + MaxEncodedLen; /// The currency mechanism, used for paying for reserves. type Currency: ReservableCurrency; diff --git a/frame/uniques/src/types.rs b/frame/uniques/src/types.rs index 4d1afe694bd8d..b5aee6912fec2 100644 --- a/frame/uniques/src/types.rs +++ b/frame/uniques/src/types.rs @@ -18,7 +18,10 @@ //! Various basic types for use in the assets pallet. use super::*; -use frame_support::{traits::Get, BoundedVec}; +use frame_support::{ + pallet_prelude::{BoundedVec, MaxEncodedLen}, + traits::Get, +}; use scale_info::TypeInfo; pub(super) type DepositBalanceOf = @@ -28,7 +31,7 @@ pub(super) type ClassDetailsFor = pub(super) type InstanceDetailsFor = InstanceDetails<::AccountId, DepositBalanceOf>; -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ClassDetails { /// Can change `owner`, `issuer`, `freezer` and `admin` accounts. pub(super) owner: AccountId, @@ -54,7 +57,7 @@ pub struct ClassDetails { } /// Witness data for the destroy transactions. -#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct DestroyWitness { /// The total number of outstanding instances of this asset class. #[codec(compact)] @@ -78,7 +81,7 @@ impl ClassDetails { } /// Information concerning the ownership of a single unique asset. -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct InstanceDetails { /// The owner of this asset. pub(super) owner: AccountId, @@ -91,8 +94,9 @@ pub struct InstanceDetails { pub(super) deposit: DepositBalance, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(StringLimit))] +#[codec(mel_bound(DepositBalance: MaxEncodedLen))] pub struct ClassMetadata> { /// The balance deposited for this metadata. /// @@ -106,8 +110,9 @@ pub struct ClassMetadata> { pub(super) is_frozen: bool, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(StringLimit))] +#[codec(mel_bound(DepositBalance: MaxEncodedLen))] pub struct InstanceMetadata> { /// The balance deposited for this metadata. /// diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 215214bef2942..29f513629d012 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -26,7 +26,7 @@ //! but we imagine they will be useful for other chains that either want to bridge with Polkadot //! or are completely standalone, but heavily inspired by Polkadot. -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; /// A standard leaf that gets added every block to the MMR constructed by Substrate's `pallet_mmr`. @@ -81,7 +81,7 @@ impl MmrLeafVersion { } /// Details of the next BEEFY authority set. -#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] +#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct BeefyNextAuthoritySet { /// Id of the next set. /// From 8c4002f330f0be837040960409e65bb49f81bee8 Mon Sep 17 00:00:00 2001 From: S E R A Y A Date: Tue, 8 Feb 2022 15:24:20 +0100 Subject: [PATCH 0494/1472] fixed regression in inline docs (#10819) --- frame/nicks/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index c7c2c675bc014..632ff7b0a8083 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -181,7 +181,7 @@ pub mod pallet { /// Remove an account's name and take charge of the deposit. /// - /// Fails if `who` has not been named. The deposit is dealt with through `T::Slashed` + /// Fails if `target` has not been named. The deposit is dealt with through `T::Slashed` /// imbalance handler. /// /// The dispatch origin for this call must match `T::ForceOrigin`. From 9b5b5721a1952c0fe2ef2465eb4dd1085b7edf8e Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Tue, 8 Feb 2022 11:05:34 -0800 Subject: [PATCH 0495/1472] try-runtime-cli: Add to docs (#10822) * try-runtime-cli: Add to docs of pre/post hooks * Add note about --ws-max-out-buffer-capacity 1000 --- utils/frame/try-runtime/cli/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 9a016b2e53696..4c71033288514 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -113,6 +113,8 @@ //! well with try-runtime's expensive RPC queries: //! //! - set `--rpc-max-payload 1000` to ensure large RPC queries can work. +//! - set `--ws-max-out-buffer-capacity 1000` to ensure the websocket connection can handle large +//! RPC queries. //! - set `--rpc-cors all` to ensure ws connections can come through. //! //! Note that *none* of the try-runtime operations need unsafe RPCs. @@ -141,7 +143,9 @@ //! //! These hooks allow you to execute some code, only within the `on-runtime-upgrade` command, before //! and after the migration. If any data needs to be temporarily stored between the pre/post -//! migration hooks, `OnRuntimeUpgradeHelpersExt` can help with that. +//! migration hooks, `OnRuntimeUpgradeHelpersExt` can help with that. Note that you should be +//! mindful with any mutable storage ops in the pre/post migration checks, as you almost certainly +//! will not want to mutate any of the storage that is to be migrated. //! //! #### Logging //! From 4eb7758750fd47bc9da194ee30a7eaf941f99360 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Feb 2022 19:27:08 +0000 Subject: [PATCH 0496/1472] Bump serde from 1.0.132 to 1.0.136 (#10816) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.132 to 1.0.136. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.132...v1.0.136) --- 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 ++++---- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 2 +- frame/conviction-voting/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- frame/merkle-mountain-range/primitives/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/referenda/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/test/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- frame/transaction-payment/asset-tx-payment/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- primitives/application-crypto/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/serializer/Cargo.toml | 2 +- primitives/storage/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 2 +- primitives/version/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 51 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 553da394386c3..feb721e6092cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9104,9 +9104,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.132" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] @@ -9132,9 +9132,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.132" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 9939f188d5d82..18951179235c1 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -17,7 +17,7 @@ node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } -serde = "1.0.132" +serde = "1.0.136" serde_json = "1.0.74" derive_more = "0.99.16" kvdb = "0.10.0" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 211311c3dac2f..4b14fe31e5a56 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -36,7 +36,7 @@ crate-type = ["cdylib", "rlib"] # third-party dependencies clap = { version = "3.0", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "2.0.0" } -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } futures = "0.3.16" hex-literal = "0.3.4" log = "0.4.8" diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 4a300b26e1238..44837fb0e41f5 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -12,7 +12,7 @@ futures = "0.3.16" log = "0.4" parking_lot = "0.11" thiserror = "1.0" -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index d103c2414331b..9b299f00a2147 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -17,7 +17,7 @@ sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } impl-trait-for-tuples = "0.2.1" sc-network = { version = "0.10.0-dev", path = "../network" } sp-core = { version = "5.0.0", path = "../../primitives/core" } -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.74" sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index f7af649d3bf3a..5375400056faf 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -24,7 +24,7 @@ names = { version = "0.12.0", default-features = false } rand = "0.7.3" regex = "1.5.4" rpassword = "5.0.0" -serde = "1.0.132" +serde = "1.0.136" serde_json = "1.0.74" thiserror = "1.0.30" tiny-bip39 = "0.8.2" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 79cb3a52038a3..76ec6a25879f8 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -25,7 +25,7 @@ sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } num-bigint = "0.2.3" num-rational = "0.2.2" num-traits = "0.2.8" -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } sp-io = { version = "5.0.0", path = "../../../primitives/io" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 56276f07dcdef..8ceada5fe1f1d 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -19,7 +19,7 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sp-runtime = { version = "5.0.0", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index fa1cc715e1512..86a0380280471 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -45,7 +45,7 @@ rand = "0.7.2" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.74" smallvec = "1.7.0" sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 8b8b70b9747c9..00b2fa787ca6f 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -27,7 +27,7 @@ sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.74" sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-rpc = { version = "5.0.0", path = "../../primitives/rpc" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index fb6c4a0837616..8424fe31a810a 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -33,7 +33,7 @@ futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.10" hash-db = "0.15.2" -serde = "1.0.132" +serde = "1.0.136" serde_json = "1.0.74" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index eab6ffa88f15c..b413446c321f2 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -24,7 +24,7 @@ sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } serde_json = "1.0.74" -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 2417f3c77b761..595a574021599 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -22,7 +22,7 @@ libp2p = { version = "0.40.0", default-features = false, features = ["dns-async- log = "0.4.8" pin-project = "1.0.10" rand = "0.7.2" -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.74" chrono = "0.4.19" thiserror = "1.0.30" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index b8910199c0ee5..5f7e0831a536a 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -23,7 +23,7 @@ once_cell = "1.8.0" parking_lot = "0.11.2" regex = "1.5.4" rustc-hash = "1.1.0" -serde = "1.0.132" +serde = "1.0.136" thiserror = "1.0.30" tracing = "0.1.29" tracing-log = "0.1.2" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 06fc8298f01c0..42172ce723e1c 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -30,7 +30,7 @@ sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transact sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } linked-hash-map = "0.5.4" retain_mut = "0.1.4" diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 9d7e6ea5e0f83..70f18c345e050 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -11,7 +11,7 @@ description = "Transaction pool client facing API." [dependencies] futures = "0.3.1" log = "0.4.8" -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index cfd18b26f9c7a..f381d4c975776 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -13,7 +13,7 @@ codec = { version = "2.2.0", package = "parity-scale-codec", default-features = libsecp256k1 = { version = "0.7.0", default-features = false } log = { version = "0.4.13", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.132", optional = true } +serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 13ccfb938010e..5844657dd50c4 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -10,7 +10,7 @@ description = "BEEFY FRAME pallet" [dependencies] codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.132", optional = true } +serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 0283b3f7c9489..ad6f99c645173 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -27,7 +27,7 @@ sp-storage = { version = "5.0.0", path = "../../primitives/storage", default-fea frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } log = { version = "0.4.14", default-features = false } -serde = { version = "1.0.132", optional = true } +serde = { version = "1.0.136", optional = true } [dev-dependencies] hex-literal = "0.3.4" diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index ab62065c1c546..7b51e3f8c91ad 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 125decaca8241..743cea074ee26 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index 9df5094abd815..d281f159bebad 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } log = { version = "0.4.14", default-features = false } -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 575b2a79fcd28..7dc891267cebc 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 6fe36aea89eec..053708c8b247b 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -17,7 +17,7 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -serde = { version = "1.0.132", optional = true } +serde = { version = "1.0.136", optional = true } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index e979f2b0c4a37..46ede8c1eed08 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.126", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index cd1e238dbd019..363ffe4428fb4 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.132", optional = true } +serde = { version = "1.0.136", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 5e8c26b6ae540..a5ba2fad18b3f 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-metadata = { version = "14.2.0", default-features = false, features = ["v14"] } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 5a27f4f46e10d..9f26df4869afc 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.132", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../../primitives/arithmetic" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index f1e7e4e207552..5d45544fe7bb0 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 182a87048d353..f898a255b87c8 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.132", features = ["derive"], optional = true } +serde = { version = "1.0.136", features = ["derive"], optional = true } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index b9b46380a3864..1f27e355b1d99 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.132", optional = true } +serde = { version = "1.0.136", optional = true } smallvec = "1.7.0" sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 300d05d0ed9a3..6f42595d200c9 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -26,7 +26,7 @@ pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, # Other dependencies codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.132", optional = true } +serde = { version = "1.0.136", optional = true } [dev-dependencies] smallvec = "1.7.0" diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 5adf5fd2c1f0d..f33607058f37b 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.132", optional = true } +serde = { version = "1.0.136", optional = true } hex-literal = { version = "0.3.4", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index d126d0ffa34b9..a7a210457f021 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = "max-encoded-len", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.132", features = ["derive"], optional = true } +serde = { version = "1.0.136", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.1" sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index a3dfa8646e793..818ddbdcc1824 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-core = { version = "5.0.0", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "5.0.0", default-features = false, path = "../io" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index b1ec8639248e9..e3294ff749855 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -23,7 +23,7 @@ integer-sqrt = "0.1.2" static_assertions = "1.1.0" num-traits = { version = "0.2.8", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } [dev-dependencies] diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index b114d182c730d..b677f44702849 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -27,7 +27,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-keystore = { version = "0.11.0", default-features = false, path = "../../keystore", optional = true } sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../timestamp", optional = true } -serde = { version = "1.0.132", features = ["derive"], optional = true } +serde = { version = "1.0.136", features = ["derive"], optional = true } async-trait = { version = "0.1.50", optional = true } [features] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 90138ded4cb19..bd41635a1d7a1 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } log = { version = "0.4.11", default-features = false } -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } primitive-types = { version = "0.10.1", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.3.0", optional = true } diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index bb0b8b8509aca..a05636d44a563 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.14.1", default-features = false, features = ["derive-codec"] } log = { version = "0.4.8", optional = true } -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "5.0.0", default-features = false, path = "../core" } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index f392895a945ee..88475e10f732c 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index 137be2c6eee2c..240b74baf4747 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.132", features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"] } sp-core = { version = "5.0.0", path = "../core" } rustc-hash = "1.1.0" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 4f793c8faa947..7b58482b2c36e 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "5.0.0", default-features = false, path = "../core" } diff --git a/primitives/serializer/Cargo.toml b/primitives/serializer/Cargo.toml index a0413164eb57a..6a9fb5d90ddb4 100644 --- a/primitives/serializer/Cargo.toml +++ b/primitives/serializer/Cargo.toml @@ -14,5 +14,5 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = "1.0.132" +serde = "1.0.136" serde_json = "1.0.74" diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index d3c22ce70651d..7d1a8c03c0a09 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-std = { version = "4.0.0", default-features = false, path = "../std" } -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } impl-serde = { version = "0.3.1", optional = true } ref-cast = "1.0.0" sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 41fd6173cd8a5..101a9249bf707 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-core = { version = "5.0.0", default-features = false, path = "../core" } -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 48091ba709cb0..053ba49fd82fb 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] impl-serde = { version = "0.3.1", optional = true } -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 640623aba6aaf..a74d7b5835273 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0" } futures = "0.3.16" hex = "0.4" -serde = "1.0.132" +serde = "1.0.136" serde_json = "1.0.74" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } sc-client-db = { version = "0.10.0-dev", features = [ diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 2a9fcaf324264..6529fa71106eb 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -48,7 +48,7 @@ sp-externalities = { version = "0.11.0", default-features = false, path = "../.. # 3rd party cfg-if = "1.0" log = { version = "0.4.14", default-features = false } -serde = { version = "1.0.132", optional = true, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } [dev-dependencies] sc-block-builder = { version = "0.10.0-dev", path = "../../client/block-builder" } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 03a625a155dc9..9e2de0e8c358a 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -27,7 +27,7 @@ sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machi codec = { version = "2.0.0", package = "parity-scale-codec" } clap = { version = "3.0", features = ["derive"] } chrono = "0.4" -serde = "1.0.132" +serde = "1.0.136" serde_json = "1.0.74" handlebars = "4.1.6" Inflector = "0.11.4" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index c1d6f1b1c5f54..cf8a0f6069879 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -20,7 +20,7 @@ frame-support = { path = "../../../frame/support", optional = true, version = "4 log = "0.4.11" codec = { package = "parity-scale-codec", version = "2.0.0" } serde_json = "1.0" -serde = "1.0.132" +serde = "1.0.136" sp-io = { version = "5.0.0", path = "../../../primitives/io" } sp-core = { version = "5.0.0", path = "../../../primitives/core" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 541706257ba1c..12380e2d3272f 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] clap = { version = "3.0", features = ["derive"] } log = "0.4.8" parity-scale-codec = { version = "2.3.1" } -serde = "1.0.132" +serde = "1.0.136" zstd = "0.9.0" sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../../client/service" } From 8a1b8701cbbae1528681d02e73f684db42dbc3d0 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 9 Feb 2022 09:37:43 +0100 Subject: [PATCH 0497/1472] --dev implies --tmp (#10828) --- bin/node-template/README.md | 6 +++--- frame/contracts/README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/node-template/README.md b/bin/node-template/README.md index a04f6a12ed73a..52b117b8a7826 100644 --- a/bin/node-template/README.md +++ b/bin/node-template/README.md @@ -26,7 +26,7 @@ First, complete the [basic Rust setup instructions](./docs/rust-setup.md). Use Rust's native `cargo` command to build and launch the template node: ```sh -cargo run --release -- --dev --tmp +cargo run --release -- --dev ``` ### Build @@ -78,12 +78,12 @@ RUST_BACKTRACE=1 ./target/release/node-template -ldebug --dev > [genesis state](https://github.com/substrate-developer-hub/substrate-node-template/blob/main/node/src/chain_spec.rs#L49). > At the same time the following accounts will be pre-funded: > - Alice -> - Bob +> - Bob > - Alice//stash > - Bob//stash In case of being interested in maintaining the chain' state between runs a base path must be added -so the db can be stored in the provided folder instead of a temporal one. We could use this folder +so the db can be stored in the provided folder instead of a temporal one. We could use this folder to store different chain databases, as a different folder will be created per different chain that is ran. The following commands shows how to use a newly created folder as our db base path. diff --git a/frame/contracts/README.md b/frame/contracts/README.md index 50e43ddb998a7..8a8e4918f2e41 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -101,7 +101,7 @@ by block production. A good starting point for observing them on the console is command line in the root directory of the substrate repository: ```bash -cargo run --release -- --dev --tmp -lerror,runtime::contracts=debug +cargo run --release -- --dev -lerror,runtime::contracts=debug ``` This raises the log level of `runtime::contracts` to `debug` and all other targets From e9d79daaa782f41680ada04719151371a737c6fb Mon Sep 17 00:00:00 2001 From: Koute Date: Wed, 9 Feb 2022 18:12:55 +0900 Subject: [PATCH 0498/1472] Add a new host function for reporting fatal errors; make WASM backtraces readable when printing out errors (#10741) * Add a new host function for reporting fatal errors * Fix one of the wasmtime executor tests * Have `#[runtime_interface(wasm_only)]` actually mean WASM-only, and not no_std-only * Print out errors through `Display` instead of `Debug` * Switch one more trait to require `Error` for its error instead of only `Debug` * Align to review comments --- client/authority-discovery/src/error.rs | 2 +- client/authority-discovery/src/worker.rs | 8 +- client/beefy/src/worker.rs | 2 +- client/consensus/aura/src/import_queue.rs | 4 +- client/consensus/babe/rpc/src/lib.rs | 4 +- client/consensus/babe/src/lib.rs | 18 ++-- client/consensus/common/src/import_queue.rs | 17 +++- .../common/src/import_queue/basic_queue.rs | 4 +- .../manual-seal/src/consensus/babe.rs | 2 +- .../manual-seal/src/finalize_block.rs | 2 +- client/consensus/manual-seal/src/rpc.rs | 5 +- .../consensus/manual-seal/src/seal_block.rs | 7 +- client/consensus/pow/src/lib.rs | 24 ++--- client/consensus/pow/src/worker.rs | 4 +- client/consensus/slots/src/lib.rs | 17 ++-- client/consensus/slots/src/slots.rs | 2 +- client/executor/common/src/error.rs | 44 ++++++++- client/executor/runtime-test/Cargo.toml | 2 +- client/executor/runtime-test/src/lib.rs | 8 ++ client/executor/src/integration_tests/mod.rs | 92 +++++++++++-------- client/executor/src/native_executor.rs | 27 +++--- client/executor/src/wasm_runtime.rs | 4 +- client/executor/wasmi/src/lib.rs | 46 ++++++++-- client/executor/wasmtime/src/host.rs | 15 +++ .../executor/wasmtime/src/instance_wrapper.rs | 44 +++++++-- client/executor/wasmtime/src/tests.rs | 14 +-- client/finality-grandpa/src/aux_schema.rs | 2 +- client/finality-grandpa/src/environment.rs | 12 +-- client/finality-grandpa/src/import.rs | 10 +- client/finality-grandpa/src/lib.rs | 23 ++++- client/finality-grandpa/src/observer.rs | 2 +- client/network/src/protocol.rs | 2 +- client/network/src/protocol/sync.rs | 10 +- .../src/protocol/sync/extra_requests.rs | 2 +- client/network/src/protocol/sync/state.rs | 2 +- client/network/src/protocol/sync/warp.rs | 2 +- client/offchain/src/lib.rs | 2 +- client/rpc-api/src/author/error.rs | 2 +- client/rpc-api/src/errors.rs | 6 +- client/service/src/chain_ops/check_block.rs | 2 +- client/service/src/chain_ops/import_blocks.rs | 2 +- client/service/src/client/call_executor.rs | 4 +- client/service/src/client/client.rs | 6 +- client/service/src/client/wasm_override.rs | 2 +- client/service/src/client/wasm_substitutes.rs | 2 +- client/service/src/lib.rs | 2 +- client/tracing/src/block/mod.rs | 2 +- client/transaction-pool/api/src/lib.rs | 2 +- client/transaction-pool/src/api.rs | 12 +-- client/transaction-pool/src/lib.rs | 10 +- client/transaction-pool/src/revalidation.rs | 2 +- frame/contracts/rpc/src/lib.rs | 4 +- frame/merkle-mountain-range/rpc/src/lib.rs | 4 +- frame/transaction-payment/rpc/src/lib.rs | 4 +- .../api/proc-macro/src/impl_runtime_apis.rs | 2 +- primitives/blockchain/src/error.rs | 2 +- primitives/consensus/common/src/lib.rs | 4 +- primitives/io/Cargo.toml | 19 ++++ primitives/io/src/lib.rs | 40 ++++++-- .../bare_function_interface.rs | 39 ++++++-- .../host_function_interface.rs | 4 +- .../src/runtime_interface/trait_decl_impl.rs | 2 +- .../runtime-interface/proc-macro/src/utils.rs | 91 +++++++++++++----- primitives/runtime/src/traits.rs | 2 +- primitives/wasm-interface/src/lib.rs | 23 +++++ utils/frame/benchmarking-cli/src/command.rs | 8 +- utils/frame/rpc/system/src/lib.rs | 4 +- utils/frame/try-runtime/cli/src/lib.rs | 4 +- 68 files changed, 552 insertions(+), 247 deletions(-) diff --git a/client/authority-discovery/src/error.rs b/client/authority-discovery/src/error.rs index bad53e905cb93..bce39069ef7c7 100644 --- a/client/authority-discovery/src/error.rs +++ b/client/authority-discovery/src/error.rs @@ -38,7 +38,7 @@ pub enum Error { #[error("Failed to hash the authority id to be used as a dht key.")] HashingAuthorityId(#[from] libp2p::core::multiaddr::multihash::Error), - #[error("Failed calling into the Substrate runtime.")] + #[error("Failed calling into the Substrate runtime: {0}")] CallingRuntime(#[from] sp_blockchain::Error), #[error("Received a dht record with a key that does not match any in-flight awaited keys.")] diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index ee5a15b9533b7..019abaac3cfcb 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -187,7 +187,7 @@ where Some(registry) => match Metrics::register(®istry) { Ok(metrics) => Some(metrics), Err(e) => { - error!(target: LOG_TARGET, "Failed to register metrics: {:?}", e); + error!(target: LOG_TARGET, "Failed to register metrics: {}", e); None }, }, @@ -242,7 +242,7 @@ where if let Err(e) = self.publish_ext_addresses(only_if_changed).await { error!( target: LOG_TARGET, - "Failed to publish external addresses: {:?}", e, + "Failed to publish external addresses: {}", e, ); } }, @@ -251,7 +251,7 @@ where if let Err(e) = self.refill_pending_lookups_queue().await { error!( target: LOG_TARGET, - "Failed to request addresses of authorities: {:?}", e, + "Failed to request addresses of authorities: {}", e, ); } }, @@ -426,7 +426,7 @@ where metrics.handle_value_found_event_failure.inc(); } - debug!(target: LOG_TARGET, "Failed to handle Dht value found event: {:?}", e); + debug!(target: LOG_TARGET, "Failed to handle Dht value found event: {}", e); } }, DhtEvent::ValueNotFound(hash) => { diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 0c7d8d4ffdc9c..3f23638758eca 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -378,7 +378,7 @@ where .expect("forwards closure result; the closure always returns Ok; qed."); } }) { - error!(target: "beefy", "🥩 Failed to get hash for block number {}; err: {:?}", + error!(target: "beefy", "🥩 Failed to get hash for block number {}: {}", block_num, err); } diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 593ea193c3d12..56eb45c621a1b 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -205,7 +205,7 @@ where let hash = block.header.hash(); let parent_hash = *block.header.parent_hash(); let authorities = authorities(self.client.as_ref(), &BlockId::Hash(parent_hash)) - .map_err(|e| format!("Could not fetch authorities at {:?}: {:?}", parent_hash, e))?; + .map_err(|e| format!("Could not fetch authorities at {:?}: {}", parent_hash, e))?; let create_inherent_data_providers = self .create_inherent_data_providers @@ -249,7 +249,7 @@ where &BlockId::Hash(parent_hash), |v| v >= 2, ) - .map_err(|e| format!("{:?}", e))? + .map_err(|e| e.to_string())? { self.check_inherents( new_block.clone(), diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 462620f26e5bf..88a176e2de10d 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -104,7 +104,7 @@ where let epoch_start = client .runtime_api() .current_epoch_start(&BlockId::Hash(header.hash())) - .map_err(|err| Error::StringError(format!("{:?}", err)))?; + .map_err(|err| Error::StringError(err.to_string()))?; let epoch = epoch_data(&shared_epoch, &client, &babe_config, *epoch_start, &select_chain) .await?; @@ -209,7 +209,7 @@ where slot.into(), |slot| Epoch::genesis(&babe_config, slot), ) - .map_err(|e| Error::Consensus(ConsensusError::ChainLookup(format!("{:?}", e))))? + .map_err(|e| Error::Consensus(ConsensusError::ChainLookup(e.to_string())))? .ok_or(Error::Consensus(ConsensusError::InvalidAuthoritiesSet)) } diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 3e9cf5aab6494..9ad50eb9c0e5c 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -232,7 +232,7 @@ pub enum Error { #[error("Multiple BABE config change digests, rejecting!")] MultipleConfigChangeDigests, /// Could not extract timestamp and slot - #[error("Could not extract timestamp and slot: {0:?}")] + #[error("Could not extract timestamp and slot: {0}")] Extraction(sp_consensus::Error), /// Could not fetch epoch #[error("Could not fetch epoch at {0:?}")] @@ -274,7 +274,7 @@ pub enum Error { #[error("VRF verification failed: {0:?}")] VRFVerificationFailed(SignatureError), /// Could not fetch parent header - #[error("Could not fetch parent header: {0:?}")] + #[error("Could not fetch parent header: {0}")] FetchParentHeader(sp_blockchain::Error), /// Expected epoch change to happen. #[error("Expected epoch change to happen at {0:?}, s{1}")] @@ -713,7 +713,7 @@ where parent.number().clone(), slot, ) - .map_err(|e| ConsensusError::ChainLookup(format!("{:?}", e)))? + .map_err(|e| ConsensusError::ChainLookup(e.to_string()))? .ok_or(sp_consensus::Error::InvalidAuthoritiesSet) } @@ -1201,7 +1201,7 @@ where ) .await { - warn!(target: "babe", "Error checking/reporting BABE equivocation: {:?}", err); + warn!(target: "babe", "Error checking/reporting BABE equivocation: {}", err); } // if the body is passed through, we need to use the runtime @@ -1551,7 +1551,7 @@ where ) .map_err(|e| { ConsensusError::ClientImport(format!( - "Error importing epoch changes: {:?}", + "Error importing epoch changes: {}", e )) })?; @@ -1559,7 +1559,7 @@ where }; if let Err(e) = prune_and_import() { - debug!(target: "babe", "Failed to launch next epoch: {:?}", e); + debug!(target: "babe", "Failed to launch next epoch: {}", e); *epoch_changes = old_epoch_changes.expect("set `Some` above and not taken; qed"); return Err(e) @@ -1590,7 +1590,7 @@ where parent_weight } else { aux_schema::load_block_weight(&*self.client, last_best) - .map_err(|e| ConsensusError::ChainLookup(format!("{:?}", e)))? + .map_err(|e| ConsensusError::ChainLookup(e.to_string()))? .ok_or_else(|| { ConsensusError::ChainLookup( "No block weight for parent header.".to_string(), @@ -1649,7 +1649,7 @@ where let finalized_slot = { let finalized_header = client .header(BlockId::Hash(info.finalized_hash)) - .map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))? + .map_err(|e| ConsensusError::ClientImport(e.to_string()))? .expect( "best finalized hash was given by client; finalized headers must exist in db; qed", ); @@ -1666,7 +1666,7 @@ where info.finalized_number, finalized_slot, ) - .map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))?; + .map_err(|e| ConsensusError::ClientImport(e.to_string()))?; Ok(()) } diff --git a/client/consensus/common/src/import_queue.rs b/client/consensus/common/src/import_queue.rs index f71996fe2b1fa..8b560d0447411 100644 --- a/client/consensus/common/src/import_queue.rs +++ b/client/consensus/common/src/import_queue.rs @@ -161,21 +161,34 @@ pub enum BlockImportStatus { } /// Block import error. -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum BlockImportError { /// Block missed header, can't be imported + #[error("block is missing a header (origin = {0:?})")] IncompleteHeader(Option), + /// Block verification failed, can't be imported + #[error("block verification failed (origin = {0:?}): {1}")] VerificationFailed(Option, String), + /// Block is known to be Bad + #[error("bad block (origin = {0:?})")] BadBlock(Option), + /// Parent state is missing. + #[error("block is missing parent state")] MissingState, + /// Block has an unknown parent + #[error("block has an unknown parent")] UnknownParent, + /// Block import has been cancelled. This can happen if the parent block fails to be imported. + #[error("import has been cancelled")] Cancelled, + /// Other error. + #[error("consensus error: {0}")] Other(ConsensusError), } @@ -245,7 +258,7 @@ pub(crate) async fn import_single_block_metered< Err(BlockImportError::BadBlock(peer.clone())) }, Err(e) => { - debug!(target: "sync", "Error importing block {}: {:?}: {:?}", number, hash, e); + debug!(target: "sync", "Error importing block {}: {:?}: {}", number, hash, e); Err(BlockImportError::Other(e)) }, }; diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index 0f23d9b546bd6..5134dc041c26b 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -303,11 +303,11 @@ impl BlockImportWorker { .map_err(|e| { debug!( target: "sync", - "Justification import failed with {:?} for hash: {:?} number: {:?} coming from node: {:?}", - e, + "Justification import failed for hash = {:?} with number = {:?} coming from node = {:?} with error: {}", hash, number, who, + e, ); e }) diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 9c2a1638043a7..dd3f9a253478a 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -118,7 +118,7 @@ where pre_digest.slot(), ) .map_err(|e| format!("failed to fetch epoch_descriptor: {}", e))? - .ok_or_else(|| format!("{:?}", sp_consensus::Error::InvalidAuthoritiesSet))?; + .ok_or_else(|| format!("{}", sp_consensus::Error::InvalidAuthoritiesSet))?; // drop the lock drop(epoch_changes); diff --git a/client/consensus/manual-seal/src/finalize_block.rs b/client/consensus/manual-seal/src/finalize_block.rs index bc242ad6085ee..d134ce7734571 100644 --- a/client/consensus/manual-seal/src/finalize_block.rs +++ b/client/consensus/manual-seal/src/finalize_block.rs @@ -48,7 +48,7 @@ where match finalizer.finalize_block(BlockId::Hash(hash), justification, true) { Err(e) => { - log::warn!("Failed to finalize block {:?}", e); + log::warn!("Failed to finalize block {}", e); rpc::send_result(&mut sender, Err(e.into())) }, Ok(()) => { diff --git a/client/consensus/manual-seal/src/rpc.rs b/client/consensus/manual-seal/src/rpc.rs index 7b4063e9b2b1b..4a8dcbc0cb765 100644 --- a/client/consensus/manual-seal/src/rpc.rs +++ b/client/consensus/manual-seal/src/rpc.rs @@ -155,7 +155,10 @@ pub fn send_result( ) { if let Some(sender) = sender.take() { if let Err(err) = sender.send(result) { - log::warn!("Server is shutting down: {:?}", err) + match err { + Ok(value) => log::warn!("Server is shutting down: {:?}", value), + Err(error) => log::warn!("Server is shutting down with error: {}", error), + } } } else { // instant seal doesn't report errors over rpc, simply log them. diff --git a/client/consensus/manual-seal/src/seal_block.rs b/client/consensus/manual-seal/src/seal_block.rs index 99b003c32f136..202b54fe5d0c5 100644 --- a/client/consensus/manual-seal/src/seal_block.rs +++ b/client/consensus/manual-seal/src/seal_block.rs @@ -114,10 +114,7 @@ pub async fn seal_block( let inherent_data = inherent_data_providers.create_inherent_data()?; - let proposer = env - .init(&parent) - .map_err(|err| Error::StringError(format!("{:?}", err))) - .await?; + let proposer = env.init(&parent).map_err(|err| Error::StringError(err.to_string())).await?; let inherents_len = inherent_data.len(); let digest = if let Some(digest_provider) = digest_provider { @@ -133,7 +130,7 @@ pub async fn seal_block( Duration::from_secs(MAX_PROPOSAL_DURATION), None, ) - .map_err(|err| Error::StringError(format!("{:?}", err))) + .map_err(|err| Error::StringError(err.to_string())) .await?; if proposal.block.extrinsics().len() == inherents_len && !create_empty { diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index ef81faff46a93..6d0bc3fc5a192 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -84,24 +84,24 @@ pub enum Error { FailedPreliminaryVerify, #[error("Rejecting block too far in future")] TooFarInFuture, - #[error("Fetching best header failed using select chain: {0:?}")] + #[error("Fetching best header failed using select chain: {0}")] BestHeaderSelectChain(ConsensusError), - #[error("Fetching best header failed: {0:?}")] + #[error("Fetching best header failed: {0}")] BestHeader(sp_blockchain::Error), #[error("Best header does not exist")] NoBestHeader, - #[error("Block proposing error: {0:?}")] + #[error("Block proposing error: {0}")] BlockProposingError(String), - #[error("Fetch best hash failed via select chain: {0:?}")] + #[error("Fetch best hash failed via select chain: {0}")] BestHashSelectChain(ConsensusError), - #[error("Error with block built on {0:?}: {1:?}")] + #[error("Error with block built on {0:?}: {1}")] BlockBuiltError(B::Hash, ConsensusError), #[error("Creating inherents failed: {0}")] CreateInherents(sp_inherents::Error), #[error("Checking inherents failed: {0}")] CheckInherents(sp_inherents::Error), #[error( - "Checking inherents unknown error for identifier: {:?}", + "Checking inherents unknown error for identifier: {}", String::from_utf8_lossy(.0) )] CheckInherentsUnknownError(sp_inherents::InherentIdentifier), @@ -350,7 +350,7 @@ where .select_chain .best_chain() .await - .map_err(|e| format!("Fetch best chain failed via select chain: {:?}", e))?; + .map_err(|e| format!("Fetch best chain failed via select chain: {}", e))?; let best_hash = best_header.hash(); let parent_hash = *block.header.parent_hash(); @@ -565,7 +565,7 @@ where warn!( target: "pow", "Unable to pull new block for authoring. \ - Select best chain error: {:?}", + Select best chain error: {}", err ); continue @@ -596,7 +596,7 @@ where warn!( target: "pow", "Unable to propose new block for authoring. \ - Fetch difficulty failed: {:?}", + Fetch difficulty failed: {}", err, ); continue @@ -612,7 +612,7 @@ where warn!( target: "pow", "Unable to propose new block for authoring. \ - Creating inherent data providers failed: {:?}", + Creating inherent data providers failed: {}", err, ); continue @@ -625,7 +625,7 @@ where warn!( target: "pow", "Unable to propose new block for authoring. \ - Creating inherent data failed: {:?}", + Creating inherent data failed: {}", e, ); continue @@ -661,7 +661,7 @@ where warn!( target: "pow", "Unable to propose new block for authoring. \ - Creating proposal failed: {:?}", + Creating proposal failed: {}", err, ); continue diff --git a/client/consensus/pow/src/worker.rs b/client/consensus/pow/src/worker.rs index 031cf7f6a2940..42f82fb43ef7b 100644 --- a/client/consensus/pow/src/worker.rs +++ b/client/consensus/pow/src/worker.rs @@ -169,7 +169,7 @@ where Err(err) => { warn!( target: "pow", - "Unable to import mined block: {:?}", + "Unable to import mined block: {}", err, ); return false @@ -238,7 +238,7 @@ where Err(err) => { warn!( target: "pow", - "Unable to import mined block: {:?}", + "Unable to import mined block: {}", err, ); false diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index a1b335f7a5940..9fc93788a33e9 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -214,7 +214,7 @@ pub trait SimpleSlotWorker { Err(err) => { warn!( target: logging_target, - "Unable to fetch epoch data at block {:?}: {:?}", + "Unable to fetch epoch data at block {:?}: {}", slot_info.chain_head.hash(), err, ); @@ -274,10 +274,7 @@ pub trait SimpleSlotWorker { let proposer = match self.proposer(&slot_info.chain_head).await { Ok(p) => p, Err(err) => { - warn!( - target: logging_target, - "Unable to author block in slot {:?}: {:?}", slot, err, - ); + warn!(target: logging_target, "Unable to author block in slot {:?}: {}", slot, err,); telemetry!( telemetry; @@ -303,12 +300,12 @@ pub trait SimpleSlotWorker { proposing_remaining_duration.mul_f32(0.98), None, ) - .map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e))); + .map_err(|e| sp_consensus::Error::ClientImport(e.to_string())); let proposal = match futures::future::select(proposing, proposing_remaining).await { Either::Left((Ok(p), _)) => p, Either::Left((Err(err), _)) => { - warn!(target: logging_target, "Proposing failed: {:?}", err); + warn!(target: logging_target, "Proposing failed: {}", err); return None }, @@ -353,7 +350,7 @@ pub trait SimpleSlotWorker { { Ok(bi) => bi, Err(err) => { - warn!(target: logging_target, "Failed to create block import params: {:?}", err); + warn!(target: logging_target, "Failed to create block import params: {}", err); return None }, @@ -388,7 +385,7 @@ pub trait SimpleSlotWorker { Err(err) => { warn!( target: logging_target, - "Error with block built on {:?}: {:?}", parent_hash, err, + "Error with block built on {:?}: {}", parent_hash, err, ); telemetry!( @@ -488,7 +485,7 @@ pub async fn start_slot_worker( let slot_info = match slots.next_slot().await { Ok(r) => r, Err(e) => { - warn!(target: "slots", "Error while polling for next slot: {:?}", e); + warn!(target: "slots", "Error while polling for next slot: {}", e); return }, }; diff --git a/client/consensus/slots/src/slots.rs b/client/consensus/slots/src/slots.rs index 2b792af7da8c4..a7b9f3e3ff611 100644 --- a/client/consensus/slots/src/slots.rs +++ b/client/consensus/slots/src/slots.rs @@ -150,7 +150,7 @@ where Err(e) => { log::warn!( target: "slots", - "Unable to author block in slot. No best block header: {:?}", + "Unable to author block in slot. No best block header: {}", e, ); // Let's try at the next slot.. diff --git a/client/executor/common/src/error.rs b/client/executor/common/src/error.rs index 606f97317b9a8..c5de737376c15 100644 --- a/client/executor/common/src/error.rs +++ b/client/executor/common/src/error.rs @@ -31,9 +31,6 @@ pub enum Error { #[error("Unserializable data encountered")] InvalidData(#[from] sp_serializer::Error), - #[error(transparent)] - Trap(#[from] wasmi::Trap), - #[error(transparent)] Wasmi(#[from] wasmi::Error), @@ -108,6 +105,12 @@ pub enum Error { #[error("Invalid initializer expression provided {0}")] InvalidInitializerExpression(String), + + #[error("Execution aborted due to panic: {0}")] + AbortedDueToPanic(MessageWithBacktrace), + + #[error("Execution aborted due to trap: {0}")] + AbortedDueToTrap(MessageWithBacktrace), } impl wasmi::HostError for Error {} @@ -160,3 +163,38 @@ pub enum WasmError { #[error("{0}")] Other(String), } + +/// An error message with an attached backtrace. +#[derive(Debug)] +pub struct MessageWithBacktrace { + /// The error message. + pub message: String, + + /// The backtrace associated with the error message. + pub backtrace: Option, +} + +impl std::fmt::Display for MessageWithBacktrace { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.write_str(&self.message)?; + if let Some(ref backtrace) = self.backtrace { + fmt.write_str("\nWASM backtrace:\n")?; + backtrace.backtrace_string.fmt(fmt)?; + } + + Ok(()) + } +} + +/// A WASM backtrace. +#[derive(Debug)] +pub struct Backtrace { + /// The string containing the backtrace. + pub backtrace_string: String, +} + +impl std::fmt::Display for Backtrace { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.write_str(&self.backtrace_string) + } +} diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index b6fbe8685e35b..ca1746c842e15 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } +sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io", features = ["improved_panic_error_reporting"] } sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 0655160c1ab7a..bf9f76edd945e 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -341,6 +341,14 @@ sp_core::wasm_export_functions! { fn test_take_i8(value: i8) { assert_eq!(value, -66); } + + fn test_abort_on_panic() { + sp_io::panic_handler::abort_on_panic("test_abort_on_panic called"); + } + + fn test_unreachable_intrinsic() { + core::arch::wasm32::unreachable() + } } #[cfg(not(feature = "std"))] diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 67e9a96cd6bae..462a8ba1b8766 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -22,7 +22,7 @@ mod sandbox; use codec::{Decode, Encode}; use hex_literal::hex; -use sc_executor_common::{runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; +use sc_executor_common::{error::Error, runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; use sc_runtime_test::wasm_binary_unwrap; use sp_core::{ blake2_128, blake2_256, ed25519, map, @@ -122,7 +122,7 @@ fn call_in_wasm( call_data: &[u8], execution_method: WasmExecutionMethod, ext: &mut E, -) -> Result, String> { +) -> Result, Error> { let executor = crate::WasmExecutor::::new(execution_method, Some(1024), 8, None, 2); executor.uncached_call( @@ -148,25 +148,16 @@ fn call_not_existing_function(wasm_method: WasmExecutionMethod) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); - match call_in_wasm( - "test_calling_missing_external", - &[], - wasm_method, - &mut ext, - ) { - Ok(_) => panic!("was expected an `Err`"), - Err(e) => { - match wasm_method { - WasmExecutionMethod::Interpreted => assert_eq!( - &format!("{:?}", e), - "\"Trap: Trap { kind: Host(Other(\\\"Function `missing_external` is only a stub. Calling a stub is not allowed.\\\")) }\"" - ), + match call_in_wasm("test_calling_missing_external", &[], wasm_method, &mut ext).unwrap_err() { + Error::AbortedDueToTrap(error) => { + let expected = match wasm_method { + WasmExecutionMethod::Interpreted => "Trap: Host(Other(\"Function `missing_external` is only a stub. Calling a stub is not allowed.\"))", #[cfg(feature = "wasmtime")] - WasmExecutionMethod::Compiled => assert!( - format!("{:?}", e).contains("Wasm execution trapped: call to a missing function env:missing_external") - ), - } - } + WasmExecutionMethod::Compiled => "call to a missing function env:missing_external" + }; + assert_eq!(error.message, expected); + }, + error => panic!("unexpected error: {:?}", error), } } @@ -175,25 +166,18 @@ fn call_yet_another_not_existing_function(wasm_method: WasmExecutionMethod) { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); - match call_in_wasm( - "test_calling_yet_another_missing_external", - &[], - wasm_method, - &mut ext, - ) { - Ok(_) => panic!("was expected an `Err`"), - Err(e) => { - match wasm_method { - WasmExecutionMethod::Interpreted => assert_eq!( - &format!("{:?}", e), - "\"Trap: Trap { kind: Host(Other(\\\"Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.\\\")) }\"" - ), + match call_in_wasm("test_calling_yet_another_missing_external", &[], wasm_method, &mut ext) + .unwrap_err() + { + Error::AbortedDueToTrap(error) => { + let expected = match wasm_method { + WasmExecutionMethod::Interpreted => "Trap: Host(Other(\"Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.\"))", #[cfg(feature = "wasmtime")] - WasmExecutionMethod::Compiled => assert!( - format!("{:?}", e).contains("Wasm execution trapped: call to a missing function env:yet_another_missing_external") - ), - } - } + WasmExecutionMethod::Compiled => "call to a missing function env:yet_another_missing_external" + }; + assert_eq!(error.message, expected); + }, + error => panic!("unexpected error: {:?}", error), } } @@ -485,6 +469,7 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { "test_exhaust_heap", &[0], ) + .map_err(|e| e.to_string()) .unwrap_err(); assert!(err.contains("Allocator ran out of space")); @@ -691,7 +676,7 @@ fn panic_in_spawned_instance_panics_on_joining_its_result(wasm_method: WasmExecu let error_result = call_in_wasm("test_panic_in_spawned", &[], wasm_method, &mut ext).unwrap_err(); - assert!(error_result.contains("Spawned task")); + assert!(error_result.to_string().contains("Spawned task")); } test_wasm_execution!(memory_is_cleared_between_invocations); @@ -789,3 +774,32 @@ fn take_i8(wasm_method: WasmExecutionMethod) { call_in_wasm("test_take_i8", &(-66_i8).encode(), wasm_method, &mut ext).unwrap(); } + +test_wasm_execution!(abort_on_panic); +fn abort_on_panic(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + + match call_in_wasm("test_abort_on_panic", &[], wasm_method, &mut ext).unwrap_err() { + Error::AbortedDueToPanic(error) => assert_eq!(error.message, "test_abort_on_panic called"), + error => panic!("unexpected error: {:?}", error), + } +} + +test_wasm_execution!(unreachable_intrinsic); +fn unreachable_intrinsic(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + + match call_in_wasm("test_unreachable_intrinsic", &[], wasm_method, &mut ext).unwrap_err() { + Error::AbortedDueToTrap(error) => { + let expected = match wasm_method { + WasmExecutionMethod::Interpreted => "Trap: Unreachable", + #[cfg(feature = "wasmtime")] + WasmExecutionMethod::Compiled => "wasm trap: wasm `unreachable` instruction executed", + }; + assert_eq!(error.message, expected); + }, + error => panic!("unexpected error: {:?}", error), + } +} diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index b36d6f1297e91..1bc87840ba353 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -220,7 +220,7 @@ where allow_missing_host_functions: bool, export_name: &str, call_data: &[u8], - ) -> std::result::Result, String> { + ) -> std::result::Result, Error> { let module = crate::wasm_runtime::create_wasm_runtime_with_code::( self.method, self.default_heap_pages, @@ -228,11 +228,10 @@ where allow_missing_host_functions, self.cache_path.as_deref(), ) - .map_err(|e| format!("Failed to create module: {:?}", e))?; + .map_err(|e| format!("Failed to create module: {}", e))?; - let instance = module - .new_instance() - .map_err(|e| format!("Failed to create instance: {:?}", e))?; + let instance = + module.new_instance().map_err(|e| format!("Failed to create instance: {}", e))?; let mut instance = AssertUnwindSafe(instance); let mut ext = AssertUnwindSafe(ext); @@ -243,7 +242,6 @@ where instance.call_export(export_name, call_data) }) .and_then(|r| r) - .map_err(|e| e.to_string()) } } @@ -281,6 +279,7 @@ where "Core_version", &[], ) + .map_err(|e| e.to_string()) } } @@ -456,12 +455,18 @@ impl RuntimeSpawn for RuntimeInstanceSpawn { // pool of instances should be used. // // https://github.com/paritytech/substrate/issues/7354 - let mut instance = - module.new_instance().expect("Failed to create new instance from module"); + let mut instance = match module.new_instance() { + Ok(instance) => instance, + Err(error) => + panic!("failed to create new instance from module: {}", error), + }; - instance + match instance .call(InvokeMethod::TableWithWrapper { dispatcher_ref, func }, &data[..]) - .expect("Failed to invoke instance.") + { + Ok(result) => result, + Err(error) => panic!("failed to invoke instance: {}", error), + } }); match result { @@ -471,7 +476,7 @@ impl RuntimeSpawn for RuntimeInstanceSpawn { Err(error) => { // If execution is panicked, the `join` in the original runtime code will // panic as well, since the sender is dropped without sending anything. - log::error!("Call error in spawned task: {:?}", error); + log::error!("Call error in spawned task: {}", error); }, } }), diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 0775755aff7cf..2cccb6f9c38b0 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -105,13 +105,13 @@ impl VersionedRuntime { if new_inst { log::warn!( target: "wasm-runtime", - "Fresh runtime instance failed with {:?}", + "Fresh runtime instance failed with {}", e, ) } else { log::warn!( target: "wasm-runtime", - "Evicting failed runtime instance: {:?}", + "Evicting failed runtime instance: {}", e, ); } diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index 78fd300e05e3d..f0488972daca9 100644 --- a/client/executor/wasmi/src/lib.rs +++ b/client/executor/wasmi/src/lib.rs @@ -21,7 +21,7 @@ use codec::{Decode, Encode}; use log::{debug, error, trace}; use sc_executor_common::{ - error::{Error, WasmError}, + error::{Error, MessageWithBacktrace, WasmError}, runtime_blob::{DataSegmentsSnapshot, RuntimeBlob}, sandbox, util::MemoryTransfer, @@ -48,6 +48,7 @@ struct FunctionExecutor { host_functions: Arc>, allow_missing_func_imports: bool, missing_functions: Arc>, + panic_message: Option, } impl FunctionExecutor { @@ -69,6 +70,7 @@ impl FunctionExecutor { host_functions, allow_missing_func_imports, missing_functions, + panic_message: None, }) } } @@ -100,7 +102,10 @@ impl<'a> sandbox::SandboxContext for SandboxContext<'a> { match result { Ok(Some(RuntimeValue::I64(val))) => Ok(val), Ok(_) => return Err("Supervisor function returned unexpected result!".into()), - Err(err) => Err(Error::Trap(err)), + Err(err) => Err(Error::AbortedDueToTrap(MessageWithBacktrace { + message: err.to_string(), + backtrace: None, + })), } } @@ -133,6 +138,10 @@ impl FunctionContext for FunctionExecutor { fn sandbox(&mut self) -> &mut dyn Sandbox { self } + + fn register_panic_error_message(&mut self, message: &str) { + self.panic_message = Some(message.to_owned()); + } } impl Sandbox for FunctionExecutor { @@ -502,12 +511,31 @@ fn call_in_wasm_module( let offset = function_executor.allocate_memory(data.len() as u32)?; function_executor.write_memory(offset, data)?; + fn convert_trap(executor: &mut FunctionExecutor, trap: wasmi::Trap) -> Error { + if let Some(message) = executor.panic_message.take() { + Error::AbortedDueToPanic(MessageWithBacktrace { message, backtrace: None }) + } else { + Error::AbortedDueToTrap(MessageWithBacktrace { + message: trap.to_string(), + backtrace: None, + }) + } + } + let result = match method { - InvokeMethod::Export(method) => module_instance.invoke_export( - method, - &[I32(u32::from(offset) as i32), I32(data.len() as i32)], - &mut function_executor, - ), + InvokeMethod::Export(method) => module_instance + .invoke_export( + method, + &[I32(u32::from(offset) as i32), I32(data.len() as i32)], + &mut function_executor, + ) + .map_err(|error| { + if let wasmi::Error::Trap(trap) = error { + convert_trap(&mut function_executor, trap) + } else { + error.into() + } + }), InvokeMethod::Table(func_ref) => { let func = table .ok_or(Error::NoTable)? @@ -518,7 +546,7 @@ fn call_in_wasm_module( &[I32(u32::from(offset) as i32), I32(data.len() as i32)], &mut function_executor, ) - .map_err(Into::into) + .map_err(|trap| convert_trap(&mut function_executor, trap)) }, InvokeMethod::TableWithWrapper { dispatcher_ref, func } => { let dispatcher = table @@ -531,7 +559,7 @@ fn call_in_wasm_module( &[I32(func as _), I32(u32::from(offset) as i32), I32(data.len() as i32)], &mut function_executor, ) - .map_err(Into::into) + .map_err(|trap| convert_trap(&mut function_executor, trap)) }, }; diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index 5da8ff3259031..b310ada24b629 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -45,6 +45,7 @@ unsafe impl Send for SandboxStore {} pub struct HostState { sandbox_store: SandboxStore, allocator: FreeingBumpHeapAllocator, + panic_message: Option, } impl HostState { @@ -55,8 +56,14 @@ impl HostState { sandbox::SandboxBackend::TryWasmer, )))), allocator, + panic_message: None, } } + + /// Takes the error message out of the host state, leaving a `None` in its place. + pub fn take_panic_message(&mut self) -> Option { + self.panic_message.take() + } } /// A `HostContext` implements `FunctionContext` for making host calls from a Wasmtime @@ -134,6 +141,14 @@ impl<'a> sp_wasm_interface::FunctionContext for HostContext<'a> { fn sandbox(&mut self) -> &mut dyn Sandbox { self } + + fn register_panic_error_message(&mut self, message: &str) { + self.caller + .data_mut() + .host_state_mut() + .expect("host state is not empty when calling a function in wasm; qed") + .panic_message = Some(message.to_owned()); + } } impl<'a> Sandbox for HostContext<'a> { diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index e27de7817b2bd..896b71cea21dd 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -21,7 +21,7 @@ use crate::runtime::{Store, StoreData}; use sc_executor_common::{ - error::{Error, Result}, + error::{Backtrace, Error, MessageWithBacktrace, Result}, wasm_runtime::InvokeMethod, }; use sp_wasm_interface::{HostFunctions, Pointer, Value, WordSize}; @@ -53,25 +53,51 @@ pub struct EntryPoint { impl EntryPoint { /// Call this entry point. - pub fn call( + pub(crate) fn call( &self, - ctx: impl AsContextMut, + store: &mut Store, data_ptr: Pointer, data_len: WordSize, ) -> Result { let data_ptr = u32::from(data_ptr); let data_len = u32::from(data_len); - fn handle_trap(err: wasmtime::Trap) -> Error { - Error::from(format!("Wasm execution trapped: {}", err)) - } - match self.call_type { EntryPointType::Direct { ref entrypoint } => - entrypoint.call(ctx, (data_ptr, data_len)).map_err(handle_trap), + entrypoint.call(&mut *store, (data_ptr, data_len)), EntryPointType::Wrapped { func, ref dispatcher } => - dispatcher.call(ctx, (func, data_ptr, data_len)).map_err(handle_trap), + dispatcher.call(&mut *store, (func, data_ptr, data_len)), } + .map_err(|trap| { + let host_state = store + .data_mut() + .host_state + .as_mut() + .expect("host state cannot be empty while a function is being called; qed"); + + // The logic to print out a backtrace is somewhat complicated, + // so let's get wasmtime to print it out for us. + let mut backtrace_string = trap.to_string(); + let suffix = "\nwasm backtrace:"; + if let Some(index) = backtrace_string.find(suffix) { + // Get rid of the error message and just grab the backtrace, + // since we're storing the error message ourselves separately. + backtrace_string.replace_range(0..index + suffix.len(), ""); + } + + let backtrace = Backtrace { backtrace_string }; + if let Some(error) = host_state.take_panic_message() { + Error::AbortedDueToPanic(MessageWithBacktrace { + message: error, + backtrace: Some(backtrace), + }) + } else { + Error::AbortedDueToTrap(MessageWithBacktrace { + message: trap.display_reason().to_string(), + backtrace: Some(backtrace), + }) + } + }) } pub fn direct( diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index 773e1d707a354..664d05f5387fc 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use codec::{Decode as _, Encode as _}; -use sc_executor_common::{runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; +use sc_executor_common::{error::Error, runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; use sc_runtime_test::wasm_binary_unwrap; use std::sync::Arc; @@ -158,11 +158,13 @@ fn test_stack_depth_reaching() { }; let mut instance = runtime.new_instance().expect("failed to instantiate a runtime"); - let err = instance.call_export("test-many-locals", &[]).unwrap_err(); - - assert!(format!("{:?}", err).starts_with( - "Other(\"Wasm execution trapped: wasm trap: wasm `unreachable` instruction executed" - )); + match instance.call_export("test-many-locals", &[]).unwrap_err() { + Error::AbortedDueToTrap(error) => { + let expected = "wasm trap: wasm `unreachable` instruction executed"; + assert_eq!(error.message, expected); + }, + error => panic!("unexpected error: {:?}", error), + } } #[test] diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/finality-grandpa/src/aux_schema.rs index 2ec48a804c936..0ac9ba9e64bd2 100644 --- a/client/finality-grandpa/src/aux_schema.rs +++ b/client/finality-grandpa/src/aux_schema.rs @@ -100,7 +100,7 @@ where // previously we only supported at most one pending change per fork &|_, _| Ok(false), ) { - warn!(target: "afg", "Error migrating pending authority set change: {:?}.", err); + warn!(target: "afg", "Error migrating pending authority set change: {}", err); warn!(target: "afg", "Node is in a potentially inconsistent state."); } } diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 81bb24f1a5eed..6ffcdc719a166 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -609,7 +609,7 @@ where let tree_route = match tree_route_res { Ok(tree_route) => tree_route, Err(e) => { - debug!(target: "afg", "Encountered error computing ancestry between block {:?} and base {:?}: {:?}", + debug!(target: "afg", "Encountered error computing ancestry between block {:?} and base {:?}: {}", block, base, e); return Err(GrandpaError::NotDescendent) @@ -1098,7 +1098,7 @@ where ) { warn!(target: "afg", "Detected prevote equivocation in the finality worker: {:?}", equivocation); if let Err(err) = self.report_equivocation(equivocation.into()) { - warn!(target: "afg", "Error reporting prevote equivocation: {:?}", err); + warn!(target: "afg", "Error reporting prevote equivocation: {}", err); } } @@ -1109,7 +1109,7 @@ where ) { warn!(target: "afg", "Detected precommit equivocation in the finality worker: {:?}", equivocation); if let Err(err) = self.report_equivocation(equivocation.into()) { - warn!(target: "afg", "Error reporting precommit equivocation: {:?}", err); + warn!(target: "afg", "Error reporting precommit equivocation: {}", err); } } } @@ -1224,7 +1224,7 @@ where .or_else(|| Some((target_header.hash(), *target_header.number()))) }, Err(e) => { - warn!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e); + warn!(target: "afg", "Encountered error finding best chain containing {:?}: {}", block, e); None }, }; @@ -1293,7 +1293,7 @@ where ) { if let Some(sender) = justification_sender { if let Err(err) = sender.notify(justification) { - warn!(target: "afg", "Error creating justification for subscriber: {:?}", err); + warn!(target: "afg", "Error creating justification for subscriber: {}", err); } } } @@ -1344,7 +1344,7 @@ where client .apply_finality(import_op, BlockId::Hash(hash), persisted_justification, true) .map_err(|e| { - warn!(target: "afg", "Error applying finality to block {:?}: {:?}", (hash, number), e); + warn!(target: "afg", "Error applying finality to block {:?}: {}", (hash, number), e); e })?; diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index 71d74045f4760..ae5839d0c24e6 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -598,7 +598,7 @@ where Err(e) => { debug!( target: "afg", - "Restoring old authority set after block import error: {:?}", + "Restoring old authority set after block import error: {}", e, ); pending_changes.revert(); @@ -663,8 +663,12 @@ where import_res.unwrap_or_else(|err| { if needs_justification { - debug!(target: "afg", "Imported block #{} that enacts authority set change with \ - invalid justification: {:?}, requesting justification from peers.", number, err); + debug!( + target: "afg", + "Requesting justification from peers due to imported block #{} that enacts authority set change with invalid justification: {}", + number, + err + ); imported_aux.bad_justification = true; imported_aux.needs_justification = true; } diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index b99f6c0544197..8316e56b5b5e5 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -275,23 +275,38 @@ impl Config { } /// Errors that can occur while voting in GRANDPA. -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// An error within grandpa. + #[error("grandpa error: {0}")] Grandpa(GrandpaError), + /// A network error. + #[error("network error: {0}")] Network(String), + /// A blockchain error. + #[error("blockchain error: {0}")] Blockchain(String), + /// Could not complete a round on disk. + #[error("could not complete a round on disk: {0}")] Client(ClientError), + /// Could not sign outgoing message + #[error("could not sign outgoing message: {0}")] Signing(String), + /// An invariant has been violated (e.g. not finalizing pending change blocks in-order) + #[error("safety invariant has been violated: {0}")] Safety(String), + /// A timer failed to fire. + #[error("a timer failed to fire: {0}")] Timer(io::Error), + /// A runtime api request failed. + #[error("runtime API request failed: {0}")] RuntimeApi(sp_api::ApiError), } @@ -322,7 +337,7 @@ where { fn block_number(&self, hash: Block::Hash) -> Result>, Error> { self.block_number_from_id(&BlockId::Hash(hash)) - .map_err(|e| Error::Blockchain(format!("{:?}", e))) + .map_err(|e| Error::Blockchain(e.to_string())) } } @@ -459,7 +474,7 @@ impl ::std::error::Error for CommandOrError impl fmt::Display for CommandOrError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - CommandOrError::Error(ref e) => write!(f, "{:?}", e), + CommandOrError::Error(ref e) => write!(f, "{}", e), CommandOrError::VoterCommand(ref cmd) => write!(f, "{}", cmd), } } @@ -838,7 +853,7 @@ where Ok(()) => error!(target: "afg", "GRANDPA voter future has concluded naturally, this should be unreachable." ), - Err(e) => error!(target: "afg", "GRANDPA voter error: {:?}", e), + Err(e) => error!(target: "afg", "GRANDPA voter error: {}", e), }); // Make sure that `telemetry_task` doesn't accidentally finish and kill grandpa. diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index ab0c69ef7fc26..a7c951cc33db9 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -203,7 +203,7 @@ where ); let observer_work = observer_work.map_ok(|_| ()).map_err(|e| { - warn!("GRANDPA Observer failed: {:?}", e); + warn!("GRANDPA Observer failed: {}", e); }); Ok(observer_work.map(drop)) diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 5541a0145366f..b39d0d1b8428b 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -886,7 +886,7 @@ impl Protocol { return }, Err(e) => { - warn!("Error reading block header {}: {:?}", hash, e); + warn!("Error reading block header {}: {}", hash, e); return }, }; diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index fbb4e376b1b4f..d98c0d2c04abe 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -665,7 +665,7 @@ impl ChainSync { // There is nothing sync can get from the node that has no blockchain data. match self.block_status(&best_hash) { Err(e) => { - debug!(target:"sync", "Error reading blockchain: {:?}", e); + debug!(target:"sync", "Error reading blockchain: {}", e); Err(BadPeer(who, rep::BLOCKCHAIN_READ_ERROR)) }, Ok(BlockStatus::KnownBad) => { @@ -1192,7 +1192,7 @@ impl ChainSync { (_, Err(e)) => { info!( target: "sync", - "❌ Error answering legitimate blockchain query: {:?}", + "❌ Error answering legitimate blockchain query: {}", e, ); return Err(BadPeer(*who, rep::BLOCKCHAIN_READ_ERROR)) @@ -1629,7 +1629,7 @@ impl ChainSync { trace!(target: "sync", "Obsolete block {:?}", hash); }, e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => { - warn!(target: "sync", "💔 Error importing block {:?}: {:?}", hash, e); + warn!(target: "sync", "💔 Error importing block {:?}: {}", hash, e.unwrap_err()); self.state_sync = None; self.warp_sync = None; output.extend(self.restart()); @@ -1683,7 +1683,7 @@ impl ChainSync { if let Err(err) = r { warn!( target: "sync", - "💔 Error cleaning up pending extra justification data requests: {:?}", + "💔 Error cleaning up pending extra justification data requests: {}", err, ); } @@ -2081,7 +2081,7 @@ impl ChainSync { ) -> impl Iterator), BadPeer>> + 'a { self.blocks.clear(); if let Err(e) = self.reset_sync_start_point() { - warn!(target: "sync", "💔 Unable to restart sync. :{:?}", e); + warn!(target: "sync", "💔 Unable to restart sync: {}", e); } self.pending_requests.set_all(); debug!(target:"sync", "Restarted with {} ({})", self.best_queued_number, self.best_queued_hash); diff --git a/client/network/src/protocol/sync/extra_requests.rs b/client/network/src/protocol/sync/extra_requests.rs index 224fbd1a1e01a..d0bfebab66010 100644 --- a/client/network/src/protocol/sync/extra_requests.rs +++ b/client/network/src/protocol/sync/extra_requests.rs @@ -108,7 +108,7 @@ impl ExtraRequests { // ignore the `Revert` error. }, Err(err) => { - debug!(target: "sync", "Failed to insert request {:?} into tree: {:?}", request, err); + debug!(target: "sync", "Failed to insert request {:?} into tree: {}", request, err); }, _ => (), } diff --git a/client/network/src/protocol/sync/state.rs b/client/network/src/protocol/sync/state.rs index 3de165b83d9e0..0df862a48333f 100644 --- a/client/network/src/protocol/sync/state.rs +++ b/client/network/src/protocol/sync/state.rs @@ -99,7 +99,7 @@ impl StateSync { Err(e) => { debug!( target: "sync", - "StateResponse failed proof verification: {:?}", + "StateResponse failed proof verification: {}", e, ); return ImportResult::BadResponse diff --git a/client/network/src/protocol/sync/warp.rs b/client/network/src/protocol/sync/warp.rs index 6c51d4b3495f0..f12deb2dbb432 100644 --- a/client/network/src/protocol/sync/warp.rs +++ b/client/network/src/protocol/sync/warp.rs @@ -88,7 +88,7 @@ impl WarpSync { Phase::WarpProof { set_id, authorities, last_hash } => { match self.warp_sync_provider.verify(&response, *set_id, authorities.clone()) { Err(e) => { - log::debug!(target: "sync", "Bad warp proof response: {:?}", e); + log::debug!(target: "sync", "Bad warp proof response: {}", e); return WarpProofImportResult::BadResponse }, Ok(VerificationResult::Partial(new_set_id, new_authorities, new_last_hash)) => { diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index cc49c07bffcf4..8d016e945453b 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -194,7 +194,7 @@ where if let Err(e) = run { tracing::error!( target: LOG_TARGET, - "Error running offchain workers at {:?}: {:?}", + "Error running offchain workers at {:?}: {}", at, e ); diff --git a/client/rpc-api/src/author/error.rs b/client/rpc-api/src/author/error.rs index 5b6bec7ed4bdc..eee77edd5e208 100644 --- a/client/rpc-api/src/author/error.rs +++ b/client/rpc-api/src/author/error.rs @@ -103,7 +103,7 @@ impl From for rpc::Error { Error::Verification(e) => rpc::Error { code: rpc::ErrorCode::ServerError(VERIFICATION_ERROR), message: format!("Verification Error: {}", e).into(), - data: Some(format!("{:?}", e).into()), + data: Some(e.to_string().into()), }, Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Custom(e))) => rpc::Error { code: rpc::ErrorCode::ServerError(POOL_INVALID_TX), diff --git a/client/rpc-api/src/errors.rs b/client/rpc-api/src/errors.rs index 42e563342fa4d..e59b1b0eda5ce 100644 --- a/client/rpc-api/src/errors.rs +++ b/client/rpc-api/src/errors.rs @@ -18,11 +18,11 @@ use log::warn; -pub fn internal(e: E) -> jsonrpc_core::Error { - warn!("Unknown error: {:?}", e); +pub fn internal(e: E) -> jsonrpc_core::Error { + warn!("Unknown error: {}", e); jsonrpc_core::Error { code: jsonrpc_core::ErrorCode::InternalError, message: "Unknown error occurred".into(), - data: Some(format!("{:?}", e).into()), + data: Some(e.to_string().into()), } } diff --git a/client/service/src/chain_ops/check_block.rs b/client/service/src/chain_ops/check_block.rs index e12766659d9a9..41a6c73c5f473 100644 --- a/client/service/src/chain_ops/check_block.rs +++ b/client/service/src/chain_ops/check_block.rs @@ -46,6 +46,6 @@ where import_blocks(client, import_queue, reader, true, true) }, Ok(None) => Box::pin(future::err("Unknown block".into())), - Err(e) => Box::pin(future::err(format!("Error reading block: {:?}", e).into())), + Err(e) => Box::pin(future::err(format!("Error reading block: {}", e).into())), } } diff --git a/client/service/src/chain_ops/import_blocks.rs b/client/service/src/chain_ops/import_blocks.rs index aa72b745c7cac..9d74fa1c276fa 100644 --- a/client/service/src/chain_ops/import_blocks.rs +++ b/client/service/src/chain_ops/import_blocks.rs @@ -322,7 +322,7 @@ where for result in results { if let (Err(err), hash) = result { - warn!("There was an error importing block with hash {:?}: {:?}", hash, err); + warn!("There was an error importing block with hash {:?}: {}", hash, err); self.has_error = true; break } diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index a806b2dbb6d49..f271b35a69ced 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -285,7 +285,7 @@ where state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; self.executor .runtime_version(&mut ext, &runtime_code) - .map_err(|e| sp_blockchain::Error::VersionInvalid(format!("{:?}", e)).into()) + .map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string()).into()) } fn prove_execution( @@ -340,7 +340,7 @@ where Block: BlockT, { fn runtime_version(&self, at: &BlockId) -> Result { - CallExecutor::runtime_version(self, at).map_err(|e| format!("{:?}", e)) + CallExecutor::runtime_version(self, at).map_err(|e| e.to_string()) } } diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index e8ca5343aa0d2..071af36a23f96 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1116,7 +1116,7 @@ where }; let runtime_version = RuntimeVersionOf::runtime_version(executor, &mut ext, &runtime_code) - .map_err(|e| sp_blockchain::Error::VersionInvalid(format!("{:?}", e)))?; + .map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string()))?; Ok(runtime_version.state_version()) } else { Err(sp_blockchain::Error::VersionInvalid( @@ -1719,7 +1719,7 @@ where let storage_changes = match self.prepare_block_storage_changes(&mut import_block).map_err(|e| { - warn!("Block prepare storage changes error:\n{:?}", e); + warn!("Block prepare storage changes error: {}", e); ConsensusError::ClientImport(e.to_string()) })? { PrepareStorageChangesResult::Discard(res) => return Ok(res), @@ -1730,7 +1730,7 @@ where self.apply_block(operation, import_block, new_cache, storage_changes) }) .map_err(|e| { - warn!("Block import error:\n{:?}", e); + warn!("Block import error: {}", e); ConsensusError::ClientImport(e.to_string()).into() }) } diff --git a/client/service/src/client/wasm_override.rs b/client/service/src/client/wasm_override.rs index 86365f2d0cab4..267aea0709871 100644 --- a/client/service/src/client/wasm_override.rs +++ b/client/service/src/client/wasm_override.rs @@ -243,7 +243,7 @@ impl WasmOverride { hash: code_hash.into(), }, ) - .map_err(|e| WasmOverrideError::VersionInvalid(format!("{:?}", e)).into()) + .map_err(|e| WasmOverrideError::VersionInvalid(e.to_string()).into()) } } diff --git a/client/service/src/client/wasm_substitutes.rs b/client/service/src/client/wasm_substitutes.rs index a45eefb7b603c..3690672512675 100644 --- a/client/service/src/client/wasm_substitutes.rs +++ b/client/service/src/client/wasm_substitutes.rs @@ -151,6 +151,6 @@ where let mut ext = BasicExternalities::default(); executor .runtime_version(&mut ext, &code.runtime_code(None)) - .map_err(|e| WasmSubstituteError::VersionInvalid(format!("{:?}", e)).into()) + .map_err(|e| WasmSubstituteError::VersionInvalid(e.to_string()).into()) } } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 430a818c0f47c..d158bbc42e947 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -509,7 +509,7 @@ where TransactionImport::Bad }, Err(e) => { - debug!("Error converting pool error: {:?}", e); + debug!("Error converting pool error: {}", e); // it is not bad at least, just some internal node logic error, so peer is // innocent. TransactionImport::KnownGood diff --git a/client/tracing/src/block/mod.rs b/client/tracing/src/block/mod.rs index 067cdafa0ae30..259827e4b47d9 100644 --- a/client/tracing/src/block/mod.rs +++ b/client/tracing/src/block/mod.rs @@ -253,7 +253,7 @@ where self.client.runtime_api().execute_block(&parent_id, block) }) { return Err(Error::Dispatch( - format!("Failed to collect traces and execute block: {:?}", e).to_string(), + format!("Failed to collect traces and execute block: {}", e).to_string(), )) } } diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index 757674a03e850..7c90cd79ccaed 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -355,7 +355,7 @@ impl OffchainSubmitTransaction for TP result.map(|_| ()).map_err(|e| { log::warn!( target: "txpool", - "(offchain call) Error submitting a transaction to the pool: {:?}", + "(offchain call) Error submitting a transaction to the pool: {}", e ) }) diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index de1c79534b386..12909f313d100 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -167,18 +167,14 @@ where &self, at: &BlockId, ) -> error::Result>> { - self.client - .to_number(at) - .map_err(|e| Error::BlockIdConversion(format!("{:?}", e))) + self.client.to_number(at).map_err(|e| Error::BlockIdConversion(e.to_string())) } fn block_id_to_hash( &self, at: &BlockId, ) -> error::Result>> { - self.client - .to_hash(at) - .map_err(|e| Error::BlockIdConversion(format!("{:?}", e))) + self.client.to_hash(at).map_err(|e| Error::BlockIdConversion(e.to_string())) } fn hash_and_length( @@ -224,7 +220,7 @@ where }?; let block_hash = client.to_hash(at) - .map_err(|e| Error::RuntimeApi(format!("{:?}", e)))? + .map_err(|e| Error::RuntimeApi(e.to_string()))? .ok_or_else(|| Error::RuntimeApi(format!("Could not get hash for block `{:?}`.", at)))?; use sp_api::Core; @@ -237,7 +233,7 @@ where .map_err(|e| Error::RuntimeApi(e.to_string())) } else { let block_number = client.to_number(at) - .map_err(|e| Error::RuntimeApi(format!("{:?}", e)))? + .map_err(|e| Error::RuntimeApi(e.to_string()))? .ok_or_else(|| Error::RuntimeApi(format!("Could not get number for block `{:?}`.", at)) )?; diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 260d938217ad4..ec93d1f7c51fe 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -534,7 +534,7 @@ async fn prune_known_txs_for_block { - log::debug!(target: "txpool", "Error retrieving header for {:?}: {:?}", block_id, e); + log::debug!(target: "txpool", "Error retrieving header for {:?}: {}", block_id, e); return hashes }, }; if let Err(e) = pool.prune(&block_id, &BlockId::hash(*header.parent_hash()), &extrinsics).await { - log::error!("Cannot prune known in the pool {:?}!", e); + log::error!("Cannot prune known in the pool: {}", e); } hashes @@ -639,7 +639,7 @@ where .block_body(&BlockId::hash(hash)) .await .unwrap_or_else(|e| { - log::warn!("Failed to fetch block body {:?}!", e); + log::warn!("Failed to fetch block body: {}", e); None }) .unwrap_or_default() @@ -685,7 +685,7 @@ where { log::debug!( target: "txpool", - "[{:?}] Error re-submitting transactions: {:?}", + "[{:?}] Error re-submitting transactions: {}", id, e, ) diff --git a/client/transaction-pool/src/revalidation.rs b/client/transaction-pool/src/revalidation.rs index 22b526e9dfc6d..e3641008a7061 100644 --- a/client/transaction-pool/src/revalidation.rs +++ b/client/transaction-pool/src/revalidation.rs @@ -106,7 +106,7 @@ async fn batch_revalidate( Err(validation_err) => { log::debug!( target: "txpool", - "[{:?}]: Error during revalidation: {:?}. Removing.", + "[{:?}]: Removing due to error during revalidation: {}", ext_hash, validation_err ); diff --git a/frame/contracts/rpc/src/lib.rs b/frame/contracts/rpc/src/lib.rs index 580b74b5ca46d..e83e4e6249b92 100644 --- a/frame/contracts/rpc/src/lib.rs +++ b/frame/contracts/rpc/src/lib.rs @@ -302,11 +302,11 @@ where } /// Converts a runtime trap into an RPC error. -fn runtime_error_into_rpc_err(err: impl std::fmt::Debug) -> Error { +fn runtime_error_into_rpc_err(err: impl std::fmt::Display) -> Error { Error { code: ErrorCode::ServerError(RUNTIME_ERROR), message: "Runtime error".into(), - data: Some(format!("{:?}", err).into()), + data: Some(err.to_string().into()), } } diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index b256ccdd7d327..bf3eb3b694e39 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -144,11 +144,11 @@ fn mmr_error_into_rpc_error(err: MmrError) -> Error { } /// Converts a runtime trap into an RPC error. -fn runtime_error_into_rpc_error(err: impl std::fmt::Debug) -> Error { +fn runtime_error_into_rpc_error(err: impl std::fmt::Display) -> Error { Error { code: ErrorCode::ServerError(RUNTIME_ERROR), message: "Runtime trapped".into(), - data: Some(format!("{:?}", err).into()), + data: Some(err.to_string().into()), } } diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index b2ff31618f78a..29d94fa260105 100644 --- a/frame/transaction-payment/rpc/src/lib.rs +++ b/frame/transaction-payment/rpc/src/lib.rs @@ -103,7 +103,7 @@ where api.query_info(&at, uxt, encoded_len).map_err(|e| RpcError { code: ErrorCode::ServerError(Error::RuntimeError.into()), message: "Unable to query dispatch info.".into(), - data: Some(format!("{:?}", e).into()), + data: Some(e.to_string().into()), }) } @@ -127,7 +127,7 @@ where let fee_details = api.query_fee_details(&at, uxt, encoded_len).map_err(|e| RpcError { code: ErrorCode::ServerError(Error::RuntimeError.into()), message: "Unable to query fee details.".into(), - data: Some(format!("{:?}", e).into()), + data: Some(e.to_string().into()), })?; let try_into_rpc_balance = |value: Balance| { diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index 7241a1c2610de..f6de60e1c99b8 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -297,7 +297,7 @@ fn generate_runtime_api_base_structures() -> Result { let state_version = self.call .runtime_version_at(&at) .map(|v| v.state_version()) - .map_err(|e| format!("Failed to get state version: {:?}", e))?; + .map_err(|e| format!("Failed to get state version: {}", e))?; self.changes.replace(Default::default()).into_storage_changes( backend, diff --git a/primitives/blockchain/src/error.rs b/primitives/blockchain/src/error.rs index bbd65e002a3b3..c82fb9bebf4ee 100644 --- a/primitives/blockchain/src/error.rs +++ b/primitives/blockchain/src/error.rs @@ -69,7 +69,7 @@ pub enum Error { ExtrinsicRootInvalid { received: String, expected: String }, // `inner` cannot be made member, since it lacks `std::error::Error` trait bounds. - #[error("Execution failed: {0:?}")] + #[error("Execution failed: {0}")] Execution(Box), #[error("Blockchain")] diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index 492ad83ddf5bd..edf393fa229ad 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -98,7 +98,7 @@ pub trait Environment { + Unpin + 'static; /// Error which can occur upon creation. - type Error: From + std::fmt::Debug + 'static; + type Error: From + std::error::Error + 'static; /// Initialize the proposal logic on top of a specific header. Provide /// the authorities at that header. @@ -191,7 +191,7 @@ mod private { /// Proposers are generic over bits of "consensus data" which are engine-specific. pub trait Proposer { /// Error type which can occur when proposing or evaluating. - type Error: From + std::fmt::Debug + 'static; + type Error: From + std::error::Error + 'static; /// The transaction type used by the backend. type Transaction: Default + Send + 'static; /// Future that resolves to a committed proposal with an optional proof. diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 207a1a23e81d9..b9cbdbaa70e77 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -66,3 +66,22 @@ with-tracing = [ disable_panic_handler = [] disable_oom = [] disable_allocator = [] + +# This feature flag controls the runtime's behavior when encountering +# a panic or when it runs out of memory, improving the diagnostics. +# +# When enabled the runtime will marshal the relevant error message +# to the host through the `PanicHandler::abort_on_panic` runtime interface. +# This gives the caller direct programmatic access to the error message. +# +# When disabled the error message will only be printed out in the +# logs, with the caller receving a generic "wasm `unreachable` instruction executed" +# error message. +# +# This has no effect if both `disable_panic_handler` and `disable_oom` +# are enabled. +# +# WARNING: Enabling this feature flag requires the `PanicHandler::abort_on_panic` +# host function to be supported by the host. Do *not* enable it for your +# runtime without first upgrading your host client! +improved_panic_error_reporting = [] diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 76ced407090c3..db86fe0964156 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -1290,6 +1290,17 @@ pub trait Allocator { } } +/// WASM-only interface which allows for aborting the execution in case +/// of an unrecoverable error. +#[runtime_interface(wasm_only)] +pub trait PanicHandler { + /// Aborts the current execution with the given error message. + #[trap_on_return] + fn abort_on_panic(&mut self, message: &str) { + self.register_panic_error_message(message); + } +} + /// Interface that provides functions for logging from within the runtime. #[runtime_interface] pub trait Logging { @@ -1588,14 +1599,14 @@ pub trait RuntimeTasks { } /// Allocator used by Substrate when executing the Wasm runtime. -#[cfg(not(feature = "std"))] +#[cfg(all(target_arch = "wasm32", not(feature = "std")))] struct WasmAllocator; -#[cfg(all(not(feature = "disable_allocator"), not(feature = "std")))] +#[cfg(all(target_arch = "wasm32", not(feature = "disable_allocator"), not(feature = "std")))] #[global_allocator] static ALLOCATOR: WasmAllocator = WasmAllocator; -#[cfg(not(feature = "std"))] +#[cfg(all(target_arch = "wasm32", not(feature = "std")))] mod allocator_impl { use super::*; use core::alloc::{GlobalAlloc, Layout}; @@ -1617,16 +1628,30 @@ mod allocator_impl { #[no_mangle] pub fn panic(info: &core::panic::PanicInfo) -> ! { let message = sp_std::alloc::format!("{}", info); - logging::log(LogLevel::Error, "runtime", message.as_bytes()); - core::arch::wasm32::unreachable(); + #[cfg(feature = "improved_panic_error_reporting")] + { + panic_handler::abort_on_panic(&message); + } + #[cfg(not(feature = "improved_panic_error_reporting"))] + { + logging::log(LogLevel::Error, "runtime", message.as_bytes()); + core::arch::wasm32::unreachable(); + } } /// A default OOM handler for WASM environment. #[cfg(all(not(feature = "disable_oom"), not(feature = "std")))] #[alloc_error_handler] pub fn oom(_: core::alloc::Layout) -> ! { - logging::log(LogLevel::Error, "runtime", b"Runtime memory exhausted. Aborting"); - core::arch::wasm32::unreachable(); + #[cfg(feature = "improved_panic_error_reporting")] + { + panic_handler::abort_on_panic("Runtime memory exhausted."); + } + #[cfg(not(feature = "improved_panic_error_reporting"))] + { + logging::log(LogLevel::Error, "runtime", b"Runtime memory exhausted. Aborting"); + core::arch::wasm32::unreachable(); + } } /// Type alias for Externalities implementation used in tests. @@ -1646,6 +1671,7 @@ pub type SubstrateHostFunctions = ( crypto::HostFunctions, hashing::HostFunctions, allocator::HostFunctions, + panic_handler::HostFunctions, logging::HostFunctions, sandbox::HostFunctions, crate::trie::HostFunctions, diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs index a06a1f9bda73e..b5745e25deb4c 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs @@ -32,11 +32,12 @@ use crate::utils::{ create_exchangeable_host_function_ident, create_function_ident_with_version, generate_crate_access, get_function_argument_names, get_function_arguments, - get_runtime_interface, + get_runtime_interface, RuntimeInterfaceFunction, }; use syn::{ - parse_quote, spanned::Spanned, FnArg, Ident, ItemTrait, Result, Signature, TraitItemMethod, + parse_quote, spanned::Spanned, FnArg, Ident, ItemTrait, Result, Signature, Token, + TraitItemMethod, }; use proc_macro2::{Span, TokenStream}; @@ -74,14 +75,14 @@ pub fn generate(trait_def: &ItemTrait, is_wasm_only: bool, tracing: bool) -> Res /// Generates the bare function implementation for the given method for the host and wasm side. fn function_for_method( - method: &TraitItemMethod, + method: &RuntimeInterfaceFunction, latest_version: u32, is_wasm_only: bool, ) -> Result { let std_impl = if !is_wasm_only { function_std_latest_impl(method, latest_version)? } else { quote!() }; - let no_std_impl = function_no_std_impl(method)?; + let no_std_impl = function_no_std_impl(method, is_wasm_only)?; Ok(quote! { #std_impl @@ -91,20 +92,46 @@ fn function_for_method( } /// Generates the bare function implementation for `cfg(not(feature = "std"))`. -fn function_no_std_impl(method: &TraitItemMethod) -> Result { +fn function_no_std_impl( + method: &RuntimeInterfaceFunction, + is_wasm_only: bool, +) -> Result { let function_name = &method.sig.ident; let host_function_name = create_exchangeable_host_function_ident(&method.sig.ident); let args = get_function_arguments(&method.sig); let arg_names = get_function_argument_names(&method.sig); - let return_value = &method.sig.output; + let return_value = if method.should_trap_on_return() { + syn::ReturnType::Type( + ]>::default(), + Box::new(syn::TypeNever { bang_token: ::default() }.into()), + ) + } else { + method.sig.output.clone() + }; + let maybe_unreachable = if method.should_trap_on_return() { + quote! { + ; core::arch::wasm32::unreachable(); + } + } else { + quote! {} + }; + let attrs = method.attrs.iter().filter(|a| !a.path.is_ident("version")); + let cfg_wasm_only = if is_wasm_only { + quote! { #[cfg(target_arch = "wasm32")] } + } else { + quote! {} + }; + Ok(quote! { + #cfg_wasm_only #[cfg(not(feature = "std"))] #( #attrs )* pub fn #function_name( #( #args, )* ) #return_value { // Call the host function #host_function_name.get()( #( #arg_names, )* ) + #maybe_unreachable } }) } diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs index 626e309cc0e1c..1566bbf302c3b 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs @@ -26,7 +26,7 @@ use crate::utils::{ create_host_function_ident, generate_crate_access, get_function_argument_names, get_function_argument_names_and_types_without_ref, get_function_argument_types, get_function_argument_types_ref_and_mut, get_function_argument_types_without_ref, - get_function_arguments, get_runtime_interface, + get_function_arguments, get_runtime_interface, RuntimeInterfaceFunction, }; use syn::{ @@ -205,7 +205,7 @@ fn generate_host_functions_struct( /// implementation of the function. fn generate_host_function_implementation( trait_name: &Ident, - method: &TraitItemMethod, + method: &RuntimeInterfaceFunction, version: u32, is_wasm_only: bool, ) -> Result<(TokenStream, Ident, TokenStream)> { diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs index c48da3b788518..0ae0f5260286c 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs @@ -153,7 +153,7 @@ fn impl_trait_for_externalities(trait_def: &ItemTrait, is_wasm_only: bool) -> Re let crate_ = generate_crate_access(); let interface = get_runtime_interface(trait_def)?; let methods = interface.all_versions().map(|(version, method)| { - let mut cloned = method.clone(); + let mut cloned = (*method).clone(); cloned.attrs.retain(|a| !a.path.is_ident("version")); cloned.sig.ident = create_function_ident_with_version(&cloned.sig.ident, version); cloned diff --git a/primitives/runtime-interface/proc-macro/src/utils.rs b/primitives/runtime-interface/proc-macro/src/utils.rs index bc690eb21a9bd..19f7fea023c30 100644 --- a/primitives/runtime-interface/proc-macro/src/utils.rs +++ b/primitives/runtime-interface/proc-macro/src/utils.rs @@ -39,18 +39,64 @@ mod attributes { syn::custom_keyword!(register_only); } +/// A concrete, specific version of a runtime interface function. +pub struct RuntimeInterfaceFunction { + item: TraitItemMethod, + should_trap_on_return: bool, +} + +impl std::ops::Deref for RuntimeInterfaceFunction { + type Target = TraitItemMethod; + fn deref(&self) -> &Self::Target { + &self.item + } +} + +impl RuntimeInterfaceFunction { + fn new(item: &TraitItemMethod) -> Result { + let mut item = item.clone(); + let mut should_trap_on_return = false; + item.attrs.retain(|attr| { + if attr.path.is_ident("trap_on_return") { + should_trap_on_return = true; + false + } else { + true + } + }); + + if should_trap_on_return { + if !matches!(item.sig.output, syn::ReturnType::Default) { + return Err(Error::new( + item.sig.ident.span(), + "Methods marked as #[trap_on_return] cannot return anything", + )) + } + } + + Ok(Self { item, should_trap_on_return }) + } + + pub fn should_trap_on_return(&self) -> bool { + self.should_trap_on_return + } +} + /// Runtime interface function with all associated versions of this function. -pub struct RuntimeInterfaceFunction<'a> { +struct RuntimeInterfaceFunctionSet { latest_version_to_call: Option, - versions: BTreeMap, + versions: BTreeMap, } -impl<'a> RuntimeInterfaceFunction<'a> { - fn new(version: VersionAttribute, trait_item: &'a TraitItemMethod) -> Self { - Self { +impl RuntimeInterfaceFunctionSet { + fn new(version: VersionAttribute, trait_item: &TraitItemMethod) -> Result { + Ok(Self { latest_version_to_call: version.is_callable().then(|| version.version), - versions: BTreeMap::from([(version.version, trait_item)]), - } + versions: BTreeMap::from([( + version.version, + RuntimeInterfaceFunction::new(trait_item)?, + )]), + }) } /// Returns the latest version of this runtime interface function plus the actual function @@ -59,11 +105,11 @@ impl<'a> RuntimeInterfaceFunction<'a> { /// This isn't required to be the latest version, because a runtime interface function can be /// annotated with `register_only` to ensure that the host exposes the host function but it /// isn't used when compiling the runtime. - pub fn latest_version_to_call(&self) -> Option<(u32, &TraitItemMethod)> { + pub fn latest_version_to_call(&self) -> Option<(u32, &RuntimeInterfaceFunction)> { self.latest_version_to_call.map(|v| { ( v, - *self.versions.get(&v).expect( + self.versions.get(&v).expect( "If latest_version_to_call has a value, the key with this value is in the versions; qed", ), ) @@ -74,7 +120,7 @@ impl<'a> RuntimeInterfaceFunction<'a> { fn add_version( &mut self, version: VersionAttribute, - trait_item: &'a TraitItemMethod, + trait_item: &TraitItemMethod, ) -> Result<()> { if let Some(existing_item) = self.versions.get(&version.version) { let mut err = Error::new(trait_item.span(), "Duplicated version attribute"); @@ -86,7 +132,8 @@ impl<'a> RuntimeInterfaceFunction<'a> { return Err(err) } - self.versions.insert(version.version, trait_item); + self.versions + .insert(version.version, RuntimeInterfaceFunction::new(trait_item)?); if self.latest_version_to_call.map_or(true, |v| v < version.version) && version.is_callable() { @@ -98,22 +145,24 @@ impl<'a> RuntimeInterfaceFunction<'a> { } /// All functions of a runtime interface grouped by the function names. -pub struct RuntimeInterface<'a> { - items: BTreeMap>, +pub struct RuntimeInterface { + items: BTreeMap, } -impl<'a> RuntimeInterface<'a> { +impl RuntimeInterface { /// Returns an iterator over all runtime interface function - /// [`latest_version_to_call`](RuntimeInterfaceFunction::latest_version). - pub fn latest_versions_to_call(&self) -> impl Iterator { + /// [`latest_version_to_call`](RuntimeInterfaceFunctionSet::latest_version). + pub fn latest_versions_to_call( + &self, + ) -> impl Iterator { self.items.iter().filter_map(|(_, item)| item.latest_version_to_call()) } - pub fn all_versions(&self) -> impl Iterator { + pub fn all_versions(&self) -> impl Iterator { self.items .iter() .flat_map(|(_, item)| item.versions.iter()) - .map(|(v, i)| (*v, *i)) + .map(|(v, i)| (*v, i)) } } @@ -288,8 +337,8 @@ fn get_item_version(item: &TraitItemMethod) -> Result> } /// Returns all runtime interface members, with versions. -pub fn get_runtime_interface<'a>(trait_def: &'a ItemTrait) -> Result> { - let mut functions: BTreeMap> = BTreeMap::new(); +pub fn get_runtime_interface(trait_def: &ItemTrait) -> Result { + let mut functions: BTreeMap = BTreeMap::new(); for item in get_trait_methods(trait_def) { let name = item.sig.ident.clone(); @@ -301,7 +350,7 @@ pub fn get_runtime_interface<'a>(trait_def: &'a ItemTrait) -> Result { - entry.insert(RuntimeInterfaceFunction::new(version, item)); + entry.insert(RuntimeInterfaceFunctionSet::new(version, item)?); }, Entry::Occupied(mut entry) => { entry.get_mut().add_version(version, item)?; diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index b2e218cb9db73..6a829ea6bba74 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1585,7 +1585,7 @@ impl Printable for Tuple { #[cfg(feature = "std")] pub trait BlockIdTo { /// The error type that will be returned by the functions. - type Error: std::fmt::Debug; + type Error: std::error::Error; /// Convert the given `block_id` to the corresponding block hash. fn to_hash( diff --git a/primitives/wasm-interface/src/lib.rs b/primitives/wasm-interface/src/lib.rs index 21dbf9609ecf3..d57666f126899 100644 --- a/primitives/wasm-interface/src/lib.rs +++ b/primitives/wasm-interface/src/lib.rs @@ -305,6 +305,29 @@ pub trait FunctionContext { fn deallocate_memory(&mut self, ptr: Pointer) -> Result<()>; /// Provides access to the sandbox. fn sandbox(&mut self) -> &mut dyn Sandbox; + + /// Registers a panic error message within the executor. + /// + /// This is meant to be used in situations where the runtime + /// encounters an unrecoverable error and intends to panic. + /// + /// Panicking in WASM is done through the [`unreachable`](https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-instr-control) + /// instruction which causes an unconditional trap and immediately aborts + /// the execution. It does not however allow for any diagnostics to be + /// passed through to the host, so while we do know that *something* went + /// wrong we don't have any direct indication of what *exactly* went wrong. + /// + /// As a workaround we use this method right before the execution is + /// actually aborted to pass an error message to the host so that it + /// can associate it with the next trap, and return that to the caller. + /// + /// A WASM trap should be triggered immediately after calling this method; + /// otherwise the error message might be associated with a completely + /// unrelated trap. + /// + /// It should only be called once, however calling it more than once + /// is harmless and will overwrite the previously set error message. + fn register_panic_error_message(&mut self, message: &str); } /// Sandbox memory identifier. diff --git a/utils/frame/benchmarking-cli/src/command.rs b/utils/frame/benchmarking-cli/src/command.rs index a5b53bcf99c76..0ced8b28ce016 100644 --- a/utils/frame/benchmarking-cli/src/command.rs +++ b/utils/frame/benchmarking-cli/src/command.rs @@ -165,7 +165,7 @@ impl BenchmarkCmd { sp_core::testing::TaskExecutor::new(), ) .execute(strategy.into()) - .map_err(|e| format!("Error getting benchmark list: {:?}", e))?; + .map_err(|e| format!("Error getting benchmark list: {}", e))?; let (list, storage_info) = <(Vec, Vec) as Decode>::decode(&mut &result[..]) @@ -265,7 +265,7 @@ impl BenchmarkCmd { ) .execute(strategy.into()) .map_err(|e| { - format!("Error executing and verifying runtime benchmark: {:?}", e) + format!("Error executing and verifying runtime benchmark: {}", e) })?; } // Do one loop of DB tracking. @@ -290,7 +290,7 @@ impl BenchmarkCmd { sp_core::testing::TaskExecutor::new(), ) .execute(strategy.into()) - .map_err(|e| format!("Error executing runtime benchmark: {:?}", e))?; + .map_err(|e| format!("Error executing runtime benchmark: {}", e))?; let batch = , String> as Decode>::decode( @@ -322,7 +322,7 @@ impl BenchmarkCmd { sp_core::testing::TaskExecutor::new(), ) .execute(strategy.into()) - .map_err(|e| format!("Error executing runtime benchmark: {:?}", e))?; + .map_err(|e| format!("Error executing runtime benchmark: {}", e))?; let batch = , String> as Decode>::decode( diff --git a/utils/frame/rpc/system/src/lib.rs b/utils/frame/rpc/system/src/lib.rs index df24e208b51a4..eb1b258c97ec6 100644 --- a/utils/frame/rpc/system/src/lib.rs +++ b/utils/frame/rpc/system/src/lib.rs @@ -106,7 +106,7 @@ where let nonce = api.account_nonce(&at, account.clone()).map_err(|e| RpcError { code: ErrorCode::ServerError(Error::RuntimeError.into()), message: "Unable to query nonce.".into(), - data: Some(format!("{:?}", e).into()), + data: Some(e.to_string().into()), })?; Ok(adjust_nonce(&*self.pool, account, nonce)) @@ -141,7 +141,7 @@ where let result = api.apply_extrinsic(&at, uxt).map_err(|e| RpcError { code: ErrorCode::ServerError(Error::RuntimeError.into()), message: "Unable to dry run extrinsic.".into(), - data: Some(format!("{:?}", e).into()), + data: Some(e.to_string().into()), })?; Ok(Encode::encode(&result).into()) diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 4c71033288514..ae7a1c3ae87ca 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -707,7 +707,7 @@ pub(crate) fn state_machine_call(Into::into)?; Ok((changes, encoded_results)) @@ -748,7 +748,7 @@ pub(crate) fn state_machine_call_with_proof(Into::into)?; let proof = proving_backend.extract_proof(); From 3aecef7ee350db9cf53369481ebd1cee26ecc7ff Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Wed, 9 Feb 2022 23:55:26 +0100 Subject: [PATCH 0499/1472] Add db params for export-state CLI command (#10830) --- client/cli/src/commands/export_blocks_cmd.rs | 2 +- client/cli/src/commands/export_state_cmd.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/client/cli/src/commands/export_blocks_cmd.rs b/client/cli/src/commands/export_blocks_cmd.rs index 4e0e155dd51c2..ff35b5a51fcad 100644 --- a/client/cli/src/commands/export_blocks_cmd.rs +++ b/client/cli/src/commands/export_blocks_cmd.rs @@ -76,7 +76,7 @@ impl ExportBlocksCmd { C: BlockBackend + UsageProvider + 'static, <::Number as FromStr>::Err: Debug, { - if let DatabaseSource::RocksDb { ref path, .. } = database_config { + if let Some(path) = database_config.path() { info!("DB path: {}", path.display()); } diff --git a/client/cli/src/commands/export_state_cmd.rs b/client/cli/src/commands/export_state_cmd.rs index 4d67ab5d13c95..b76724caf0fef 100644 --- a/client/cli/src/commands/export_state_cmd.rs +++ b/client/cli/src/commands/export_state_cmd.rs @@ -18,7 +18,7 @@ use crate::{ error, - params::{BlockNumberOrHash, PruningParams, SharedParams}, + params::{BlockNumberOrHash, DatabaseParams, PruningParams, SharedParams}, CliConfiguration, }; use clap::Parser; @@ -42,6 +42,10 @@ pub struct ExportStateCmd { #[allow(missing_docs)] #[clap(flatten)] pub pruning_params: PruningParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub database_params: DatabaseParams, } impl ExportStateCmd { @@ -81,4 +85,8 @@ impl CliConfiguration for ExportStateCmd { fn pruning_params(&self) -> Option<&PruningParams> { Some(&self.pruning_params) } + + fn database_params(&self) -> Option<&DatabaseParams> { + Some(&self.database_params) + } } From 8b2f5379653d9d741f666634ed7f751dd6870381 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 10 Feb 2022 12:08:05 +0100 Subject: [PATCH 0500/1472] Allow `SetBalance` to handle error when trying to kill acount with reference counter. (#10826) * bug found * fix logic * a little simpler * add test --- frame/balances/src/lib.rs | 35 +++++++++++++++++++++-------------- frame/balances/src/tests.rs | 24 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 37114f385aa7f..6bf37dfda037b 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -314,25 +314,32 @@ pub mod pallet { let new_free = if wipeout { Zero::zero() } else { new_free }; let new_reserved = if wipeout { Zero::zero() } else { new_reserved }; - let (free, reserved) = Self::mutate_account(&who, |account| { - if new_free > account.free { - mem::drop(PositiveImbalance::::new(new_free - account.free)); - } else if new_free < account.free { - mem::drop(NegativeImbalance::::new(account.free - new_free)); - } - - if new_reserved > account.reserved { - mem::drop(PositiveImbalance::::new(new_reserved - account.reserved)); - } else if new_reserved < account.reserved { - mem::drop(NegativeImbalance::::new(account.reserved - new_reserved)); - } + // First we try to modify the account's balance to the forced balance. + let (old_free, old_reserved) = Self::mutate_account(&who, |account| { + let old_free = account.free; + let old_reserved = account.reserved; account.free = new_free; account.reserved = new_reserved; - (account.free, account.reserved) + (old_free, old_reserved) })?; - Self::deposit_event(Event::BalanceSet { who, free, reserved }); + + // This will adjust the total issuance, which was not done by the `mutate_account` + // above. + if new_free > old_free { + mem::drop(PositiveImbalance::::new(new_free - old_free)); + } else if new_free < old_free { + mem::drop(NegativeImbalance::::new(old_free - new_free)); + } + + if new_reserved > old_reserved { + mem::drop(PositiveImbalance::::new(new_reserved - old_reserved)); + } else if new_reserved < old_reserved { + mem::drop(NegativeImbalance::::new(old_reserved - new_reserved)); + } + + Self::deposit_event(Event::BalanceSet { who, free: new_free, reserved: new_reserved }); Ok(().into()) } diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 638034d80cd52..8f5470ae3cac2 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -1239,5 +1239,29 @@ macro_rules! decl_tests { assert_eq!(Balances::free_balance(&3), 25); }); } + + #[test] + fn set_balance_handles_killing_account() { + <$ext_builder>::default().build().execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + assert_ok!(frame_system::Pallet::::inc_consumers(&1)); + assert_noop!( + Balances::set_balance(Origin::root(), 1, 0, 0), + DispatchError::ConsumerRemaining, + ); + }); + } + + #[test] + fn set_balance_handles_total_issuance() { + <$ext_builder>::default().build().execute_with(|| { + let old_total_issuance = Balances::total_issuance(); + assert_ok!(Balances::set_balance(Origin::root(), 1337, 69, 42)); + assert_eq!(Balances::total_issuance(), old_total_issuance + 69 + 42); + assert_eq!(Balances::total_balance(&1337), 69 + 42); + assert_eq!(Balances::free_balance(&1337), 69); + assert_eq!(Balances::reserved_balance(&1337), 42); + }); + } } } From 9a6d706d8db00abb6ba183839ec98ecd9924b1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 10 Feb 2022 13:34:35 +0100 Subject: [PATCH 0501/1472] UncheckedExtrinsic: Harden decode and clarify `EXTRINSIC_FORMAT_VERSION` (#10829) * UncheckedExtrinsic: Harden decode and clarify `EXTRINSIC_FORMAT_VERSION` * Apply suggestions from code review --- .../src/generic/unchecked_extrinsic.rs | 53 ++++++++++++++----- primitives/runtime/src/traits.rs | 4 +- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/primitives/runtime/src/generic/unchecked_extrinsic.rs b/primitives/runtime/src/generic/unchecked_extrinsic.rs index d444d0352d5ae..fb333abd6ac6e 100644 --- a/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -31,8 +31,12 @@ use scale_info::{build::Fields, meta_type, Path, StaticTypeInfo, Type, TypeInfo, use sp_io::hashing::blake2_256; use sp_std::{fmt, prelude::*}; -/// Current version of the [`UncheckedExtrinsic`] format. -const EXTRINSIC_VERSION: u8 = 4; +/// Current version of the [`UncheckedExtrinsic`] encoded format. +/// +/// This version needs to be bumped if the encoded representation changes. +/// It ensures that if the representation is changed and the format is not known, +/// the decoding fails. +const EXTRINSIC_FORMAT_VERSION: u8 = 4; /// A extrinsic right from the external world. This is unchecked and so /// can contain a signature. @@ -164,7 +168,7 @@ impl ExtrinsicMetadata where Extra: SignedExtension, { - const VERSION: u8 = EXTRINSIC_VERSION; + const VERSION: u8 = EXTRINSIC_FORMAT_VERSION; type SignedExtensions = Extra; } @@ -235,23 +239,33 @@ where { fn decode(input: &mut I) -> Result { // This is a little more complicated than usual since the binary format must be compatible - // with substrate's generic `Vec` type. Basically this just means accepting that there - // will be a prefix of vector length (we don't need - // to use this). - let _length_do_not_remove_me_see_above: Compact = Decode::decode(input)?; + // with SCALE's generic `Vec` type. Basically this just means accepting that there + // will be a prefix of vector length. + let expected_length: Compact = Decode::decode(input)?; + let before_length = input.remaining_len()?; let version = input.read_byte()?; let is_signed = version & 0b1000_0000 != 0; let version = version & 0b0111_1111; - if version != EXTRINSIC_VERSION { + if version != EXTRINSIC_FORMAT_VERSION { return Err("Invalid transaction version".into()) } - Ok(Self { - signature: if is_signed { Some(Decode::decode(input)?) } else { None }, - function: Decode::decode(input)?, - }) + let signature = is_signed.then(|| Decode::decode(input)).transpose()?; + let function = Decode::decode(input)?; + + if let Some((before_length, after_length)) = + input.remaining_len()?.and_then(|a| before_length.map(|b| (b, a))) + { + let length = before_length.saturating_sub(after_length); + + if length != expected_length.0 as usize { + return Err("Invalid length prefix".into()) + } + } + + Ok(Self { signature, function }) } } @@ -268,11 +282,11 @@ where // 1 byte version id. match self.signature.as_ref() { Some(s) => { - tmp.push(EXTRINSIC_VERSION | 0b1000_0000); + tmp.push(EXTRINSIC_FORMAT_VERSION | 0b1000_0000); s.encode_to(&mut tmp); }, None => { - tmp.push(EXTRINSIC_VERSION & 0b0111_1111); + tmp.push(EXTRINSIC_FORMAT_VERSION & 0b0111_1111); }, } self.function.encode_to(&mut tmp); @@ -409,6 +423,17 @@ mod tests { assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux)); } + #[test] + fn invalid_length_prefix_is_detected() { + let ux = Ex::new_unsigned(vec![0u8; 0]); + let mut encoded = ux.encode(); + + let length = Compact::::decode(&mut &encoded[..]).unwrap(); + Compact(length.0 + 10).encode_to(&mut &mut encoded[..1]); + + assert_eq!(Ex::decode(&mut &encoded[..]), Err("Invalid length prefix".into())); + } + #[test] fn signed_codec_should_work() { let ux = Ex::new_signed( diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 6a829ea6bba74..1cea7c4e805c1 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -748,7 +748,9 @@ pub trait Extrinsic: Sized + MaybeMallocSizeOf { /// Implementor is an [`Extrinsic`] and provides metadata about this extrinsic. pub trait ExtrinsicMetadata { - /// The version of the `Extrinsic`. + /// The format version of the `Extrinsic`. + /// + /// By format is meant the encoded representation of the `Extrinsic`. const VERSION: u8; /// Signed extensions attached to this `Extrinsic`. From 27b8806ed82844bb5283a4dadf853ee518fd042f Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Thu, 10 Feb 2022 13:22:26 -0800 Subject: [PATCH 0502/1472] pallet-staking: Add extrinsic `force_apply_min_commission` (#10786) * pallet-staking: Add extrinsic `force_apply_min_commission` * Add benchmarks * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Bound iteration by max_validator_count * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Only apply to 1 validator * Update doc comments * Uncomment tests * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Accept signed origins * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Remove contains_key check * Add test for try_mutate_exists * Impove try_mutate_exists docs * Delete redundant try_mutate_exists tests; * Delete residual from removed test * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Return an error when the stash does not exist * Update try_mutate_exist doc wording * Update frame/staking/src/pallet/mod.rs * Apply suggestions from code review Co-authored-by: Parity Bot Co-authored-by: Shawn Tabrizi --- frame/staking/src/benchmarking.rs | 29 +++ frame/staking/src/pallet/mod.rs | 22 ++ frame/staking/src/tests.rs | 35 +++ frame/staking/src/weights.rs | 231 +++++++++--------- frame/support/src/storage/mod.rs | 6 + .../support/src/storage/types/counted_map.rs | 2 + frame/support/src/storage/types/double_map.rs | 2 + frame/support/src/storage/types/map.rs | 2 + frame/support/src/storage/types/nmap.rs | 2 + frame/support/src/traits/stored_map.rs | 4 +- 10 files changed, 225 insertions(+), 110 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 564172d912413..65a1ee92e2eab 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -900,6 +900,35 @@ benchmarks! { assert!(!T::SortedListProvider::contains(&stash)); } + force_apply_min_commission { + // Clean up any existing state + clear_validators_and_nominators::(); + + // Create a validator with a commission of 50% + let (stash, controller) = + create_stash_controller::(1, 1, RewardDestination::Staked)?; + let validator_prefs = + ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }; + Staking::::validate(RawOrigin::Signed(controller).into(), validator_prefs)?; + + // Sanity check + assert_eq!( + Validators::::get(&stash), + ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() } + ); + + // Set the min commission to 75% + MinCommission::::set(Perbill::from_percent(75)); + let caller = whitelisted_caller(); + }: _(RawOrigin::Signed(caller), stash.clone()) + verify { + // The validators commission has been bumped to 75% + assert_eq!( + Validators::::get(&stash), + ValidatorPrefs { commission: Perbill::from_percent(75), ..Default::default() } + ); + } + impl_benchmark_test_suite!( Staking, crate::mock::ExtBuilder::default().has_stakers(true), diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 2a870fda063d3..2be75752f101d 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -1616,6 +1616,28 @@ pub mod pallet { Self::chill_stash(&stash); Ok(()) } + + /// Force a validator to have at least the minimum commission. This will not affect a + /// validator who already has a commission greater than or equal to the minimum. Any account + /// can call this. + #[pallet::weight(T::WeightInfo::force_apply_min_commission())] + pub fn force_apply_min_commission( + origin: OriginFor, + validator_stash: T::AccountId, + ) -> DispatchResult { + ensure_signed(origin)?; + let min_commission = MinCommission::::get(); + Validators::::try_mutate_exists(validator_stash, |maybe_prefs| { + maybe_prefs + .as_mut() + .map(|prefs| { + (prefs.commission < min_commission) + .then(|| prefs.commission = min_commission) + }) + .ok_or(Error::::NotStash) + })?; + Ok(()) + } } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 538b75ead340b..4073c069fb6be 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4711,3 +4711,38 @@ mod sorted_list_provider { }); } } + +#[test] +fn force_apply_min_commission_works() { + let prefs = |c| ValidatorPrefs { commission: Perbill::from_percent(c), blocked: false }; + let validators = || Validators::::iter().collect::>(); + ExtBuilder::default().build_and_execute(|| { + assert_ok!(Staking::validate(Origin::signed(30), prefs(10))); + assert_ok!(Staking::validate(Origin::signed(20), prefs(5))); + + // Given + assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]); + MinCommission::::set(Perbill::from_percent(5)); + + // When applying to a commission greater than min + assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 31)); + // Then the commission is not changed + assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]); + + // When applying to a commission that is equal to min + assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 21)); + // Then the commission is not changed + assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]); + + // When applying to a commission that is less than the min + assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 11)); + // Then the commission is bumped to the min + assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(5))]); + + // When applying commission to a validator that doesn't exist then storage is not altered + assert_noop!( + Staking::force_apply_min_commission(Origin::signed(1), 420), + Error::::NotStash + ); + }); +} diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 42f762c721e4c..dcb544283c225 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-02-09, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -33,9 +33,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/staking/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -74,6 +72,7 @@ pub trait WeightInfo { fn get_npos_targets(v: u32, ) -> Weight; fn set_staking_configs() -> Weight; fn chill_other() -> Weight; + fn force_apply_min_commission() -> Weight; } /// Weights for pallet_staking using the Substrate node and recommended hardware. @@ -86,7 +85,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (37_688_000 as Weight) + (37_772_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -96,7 +95,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (63_507_000 as Weight) + (64_816_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -110,7 +109,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (70_634_000 as Weight) + (71_635_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -119,9 +118,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (30_002_000 as Weight) + (30_612_000 as Weight) // Standard Error: 0 - .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((59_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -139,7 +138,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (58_077_000 as Weight) + (59_116_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(11 as Weight)) } @@ -155,16 +154,16 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (44_603_000 as Weight) + (45_505_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (14_580_000 as Weight) - // Standard Error: 13_000 - .saturating_add((8_076_000 as Weight).saturating_mul(k as Weight)) + (12_764_000 as Weight) + // Standard Error: 15_000 + .saturating_add((8_301_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -181,9 +180,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (49_856_000 as Weight) - // Standard Error: 8_000 - .saturating_add((3_430_000 as Weight).saturating_mul(n as Weight)) + (51_439_000 as Weight) + // Standard Error: 10_000 + .saturating_add((3_323_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(6 as Weight)) @@ -196,47 +195,47 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (43_815_000 as Weight) + (44_847_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (7_553_000 as Weight) + (7_795_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (15_177_000 as Weight) + (16_051_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (1_090_000 as Weight) + (1_107_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (1_169_000 as Weight) + (1_126_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (1_089_000 as Weight) + (1_183_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (1_144_000 as Weight) + (1_181_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (1_612_000 as Weight) + (1_705_000 as Weight) // Standard Error: 0 .saturating_add((50_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -255,18 +254,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (56_103_000 as Weight) + (57_431_000 as Weight) // Standard Error: 1_000 - .saturating_add((798_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((801_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (942_911_000 as Weight) - // Standard Error: 55_000 - .saturating_add((4_973_000 as Weight).saturating_mul(s as Weight)) + (950_258_000 as Weight) + // Standard Error: 56_000 + .saturating_add((5_001_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -281,9 +280,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (77_948_000 as Weight) - // Standard Error: 13_000 - .saturating_add((23_507_000 as Weight).saturating_mul(n as Weight)) + (94_238_000 as Weight) + // Standard Error: 15_000 + .saturating_add((23_978_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -301,9 +300,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (94_386_000 as Weight) - // Standard Error: 19_000 - .saturating_add((32_763_000 as Weight).saturating_mul(n as Weight)) + (109_323_000 as Weight) + // Standard Error: 22_000 + .saturating_add((33_887_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -316,9 +315,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (63_577_000 as Weight) + (64_807_000 as Weight) // Standard Error: 2_000 - .saturating_add((47_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((50_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(9 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -333,8 +332,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 57_000 - .saturating_add((19_691_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 61_000 + .saturating_add((20_457_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) .saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -353,9 +352,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (61_871_000 as Weight) + (62_856_000 as Weight) // Standard Error: 0 - .saturating_add((796_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((802_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -380,10 +379,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 823_000 - .saturating_add((218_725_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 41_000 - .saturating_add((31_349_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 804_000 + .saturating_add((226_855_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 40_000 + .saturating_add((31_928_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -401,12 +400,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 86_000 - .saturating_add((18_168_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 86_000 - .saturating_add((21_061_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 2_951_000 - .saturating_add((8_164_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 87_000 + .saturating_add((18_771_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 87_000 + .saturating_add((21_895_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 2_984_000 + .saturating_add((8_282_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(204 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -415,8 +414,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 29_000 - .saturating_add((7_761_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 28_000 + .saturating_add((7_801_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -427,7 +426,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs() -> Weight { - (3_586_000 as Weight) + (3_680_000 as Weight) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -441,10 +440,17 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (54_681_000 as Weight) + (55_459_000 as Weight) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } + // Storage: Staking MinCommission (r:1 w:0) + // Storage: Staking Validators (r:1 w:1) + fn force_apply_min_commission() -> Weight { + (8_939_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } } // For backwards compatibility and tests @@ -456,7 +462,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (37_688_000 as Weight) + (37_772_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -466,7 +472,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (63_507_000 as Weight) + (64_816_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } @@ -480,7 +486,7 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (70_634_000 as Weight) + (71_635_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -489,9 +495,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (30_002_000 as Weight) + (30_612_000 as Weight) // Standard Error: 0 - .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((59_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -509,7 +515,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (58_077_000 as Weight) + (59_116_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } @@ -525,16 +531,16 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (44_603_000 as Weight) + (45_505_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (14_580_000 as Weight) - // Standard Error: 13_000 - .saturating_add((8_076_000 as Weight).saturating_mul(k as Weight)) + (12_764_000 as Weight) + // Standard Error: 15_000 + .saturating_add((8_301_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -551,9 +557,9 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (49_856_000 as Weight) - // Standard Error: 8_000 - .saturating_add((3_430_000 as Weight).saturating_mul(n as Weight)) + (51_439_000 as Weight) + // Standard Error: 10_000 + .saturating_add((3_323_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) @@ -566,47 +572,47 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (43_815_000 as Weight) + (44_847_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (7_553_000 as Weight) + (7_795_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (15_177_000 as Weight) + (16_051_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (1_090_000 as Weight) + (1_107_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (1_169_000 as Weight) + (1_126_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (1_089_000 as Weight) + (1_183_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (1_144_000 as Weight) + (1_181_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (1_612_000 as Weight) + (1_705_000 as Weight) // Standard Error: 0 .saturating_add((50_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -625,18 +631,18 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (56_103_000 as Weight) + (57_431_000 as Weight) // Standard Error: 1_000 - .saturating_add((798_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((801_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (942_911_000 as Weight) - // Standard Error: 55_000 - .saturating_add((4_973_000 as Weight).saturating_mul(s as Weight)) + (950_258_000 as Weight) + // Standard Error: 56_000 + .saturating_add((5_001_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -651,9 +657,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (77_948_000 as Weight) - // Standard Error: 13_000 - .saturating_add((23_507_000 as Weight).saturating_mul(n as Weight)) + (94_238_000 as Weight) + // Standard Error: 15_000 + .saturating_add((23_978_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -671,9 +677,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (94_386_000 as Weight) - // Standard Error: 19_000 - .saturating_add((32_763_000 as Weight).saturating_mul(n as Weight)) + (109_323_000 as Weight) + // Standard Error: 22_000 + .saturating_add((33_887_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -686,9 +692,9 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (63_577_000 as Weight) + (64_807_000 as Weight) // Standard Error: 2_000 - .saturating_add((47_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((50_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(9 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -703,8 +709,8 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 57_000 - .saturating_add((19_691_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 61_000 + .saturating_add((20_457_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) .saturating_add(RocksDbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -723,9 +729,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (61_871_000 as Weight) + (62_856_000 as Weight) // Standard Error: 0 - .saturating_add((796_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((802_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -750,10 +756,10 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 823_000 - .saturating_add((218_725_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 41_000 - .saturating_add((31_349_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 804_000 + .saturating_add((226_855_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 40_000 + .saturating_add((31_928_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -771,12 +777,12 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 86_000 - .saturating_add((18_168_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 86_000 - .saturating_add((21_061_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 2_951_000 - .saturating_add((8_164_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 87_000 + .saturating_add((18_771_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 87_000 + .saturating_add((21_895_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 2_984_000 + .saturating_add((8_282_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(204 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -785,8 +791,8 @@ impl WeightInfo for () { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 29_000 - .saturating_add((7_761_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 28_000 + .saturating_add((7_801_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -797,7 +803,7 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs() -> Weight { - (3_586_000 as Weight) + (3_680_000 as Weight) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -811,8 +817,15 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (54_681_000 as Weight) + (55_459_000 as Weight) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } + // Storage: Staking MinCommission (r:1 w:0) + // Storage: Staking Validators (r:1 w:1) + fn force_apply_min_commission() -> Weight { + (8_939_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } } diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index e50577697a60a..3d777fa3ace50 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -266,6 +266,8 @@ pub trait StorageMap { ) -> R; /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + /// `f` will always be called with an option representing if the storage item exists (`Some`) + /// or if the storage item does not exist (`None`), independent of the `QueryType`. fn try_mutate_exists, R, E, F: FnOnce(&mut Option) -> Result>( key: KeyArg, f: F, @@ -608,6 +610,8 @@ pub trait StorageDoubleMap { F: FnOnce(&mut Option) -> R; /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + /// `f` will always be called with an option representing if the storage item exists (`Some`) + /// or if the storage item does not exist (`None`), independent of the `QueryType`. fn try_mutate_exists(k1: KArg1, k2: KArg2, f: F) -> Result where KArg1: EncodeLike, @@ -735,6 +739,8 @@ pub trait StorageNMap { F: FnOnce(&mut Option) -> R; /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + /// `f` will always be called with an option representing if the storage item exists (`Some`) + /// or if the storage item does not exist (`None`), independent of the `QueryType`. fn try_mutate_exists(key: KArg, f: F) -> Result where KArg: EncodeLikeTuple + TupleToEncodedIter, diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 7f53b196c8151..9c48267af86e0 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -190,6 +190,8 @@ where } /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + /// `f` will always be called with an option representing if the storage item exists (`Some`) + /// or if the storage item does not exist (`None`), independent of the `QueryType`. pub fn try_mutate_exists(key: KeyArg, f: F) -> Result where KeyArg: EncodeLike + Clone, diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 07da0f2239b3b..e864920e488f0 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -264,6 +264,8 @@ where } /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + /// `f` will always be called with an option representing if the storage item exists (`Some`) + /// or if the storage item does not exist (`None`), independent of the `QueryType`. pub fn try_mutate_exists(k1: KArg1, k2: KArg2, f: F) -> Result where KArg1: EncodeLike, diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index d0b82e1a84e5b..01aa2f44abe5e 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -174,6 +174,8 @@ where } /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + /// `f` will always be called with an option representing if the storage item exists (`Some`) + /// or if the storage item does not exist (`None`), independent of the `QueryType`. pub fn try_mutate_exists(key: KeyArg, f: F) -> Result where KeyArg: EncodeLike, diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 03f15e335389b..5b51ed1ffdf49 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -217,6 +217,8 @@ where } /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + /// `f` will always be called with an option representing if the storage item exists (`Some`) + /// or if the storage item does not exist (`None`), independent of the `QueryType`. pub fn try_mutate_exists(key: KArg, f: F) -> Result where KArg: EncodeLikeTuple + TupleToEncodedIter, diff --git a/frame/support/src/traits/stored_map.rs b/frame/support/src/traits/stored_map.rs index 5173eaeb5def0..3c3ff2eb0ed98 100644 --- a/frame/support/src/traits/stored_map.rs +++ b/frame/support/src/traits/stored_map.rs @@ -29,7 +29,9 @@ pub trait StoredMap { fn get(k: &K) -> T; /// Maybe mutate the item only if an `Ok` value is returned from `f`. Do nothing if an `Err` is - /// returned. It is removed or reset to default value if it has been mutated to `None` + /// returned. It is removed or reset to default value if it has been mutated to `None`. + /// `f` will always be called with an option representing if the storage item exists (`Some`) + /// or if the storage item does not exist (`None`), independent of the `QueryType`. fn try_mutate_exists>( k: &K, f: impl FnOnce(&mut Option) -> Result, From 665fc06def5a5aaba8c2661597f2add7bc3991ce Mon Sep 17 00:00:00 2001 From: Yarik Bratashchuk Date: Fri, 11 Feb 2022 09:46:51 +0200 Subject: [PATCH 0503/1472] Upgradable contracts using `set_code` function (#10690) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * poc logic * set_code_hash impl, tests, benchmark * Address @xgreenx's comments * Move func defs closer to set_storage * Check if code exists - increment/decrement codehash refcount * Document error for non-existing code hash * Revert unrelated change * Changes due to @athei's review * Fix error handling - comment errors: ReturnCodes - update mock ext implementation - return Error::CodeNotFound when no code for such hash * Emit ContractCodeUpdated when setting new code_hash * Address @athei's comments * Move related defs to the bottom * Minor comment update Co-authored-by: Alexander Theißen * Improve docs * Improve docs * Update frame/contracts/src/wasm/runtime.rs Co-authored-by: Alexander Theißen * Refactor set_code_hash test * Minor change to benchmark Co-authored-by: Alexander Theißen * Minor change to benchmark Co-authored-by: Alexander Theißen * Minor comment refactor Co-authored-by: Alexander Theißen * Address @HCastano's comments * Update seal_set_code_hash comment Co-authored-by: Hernando Castano * Move set_code_hash after delegate_call * Move function to the bottom * Moved and changed banchmark, added verify block * Bring back previous benchmark * Remove skip_meta for seal_set_code_hash * Bring back skip_meta for seal_set_storage_per_new_kb * Apply weights Co-authored-by: Alexander Theißen Co-authored-by: Hernando Castano --- .../fixtures/new_set_code_hash_contract.wat | 13 + frame/contracts/fixtures/set_code_hash.wat | 43 + frame/contracts/src/benchmarking/mod.rs | 40 + frame/contracts/src/exec.rs | 18 + frame/contracts/src/lib.rs | 10 + frame/contracts/src/schedule.rs | 4 + frame/contracts/src/tests.rs | 61 + frame/contracts/src/wasm/code_cache.rs | 16 + frame/contracts/src/wasm/mod.rs | 174 ++- frame/contracts/src/wasm/runtime.rs | 42 + frame/contracts/src/weights.rs | 1251 +++++++++-------- 11 files changed, 999 insertions(+), 673 deletions(-) create mode 100644 frame/contracts/fixtures/new_set_code_hash_contract.wat create mode 100644 frame/contracts/fixtures/set_code_hash.wat diff --git a/frame/contracts/fixtures/new_set_code_hash_contract.wat b/frame/contracts/fixtures/new_set_code_hash_contract.wat new file mode 100644 index 0000000000000..86ab2737be484 --- /dev/null +++ b/frame/contracts/fixtures/new_set_code_hash_contract.wat @@ -0,0 +1,13 @@ +(module + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 32) return value + (data (i32.const 0) "\02") + + (func (export "deploy")) + + (func (export "call") + (call $seal_return (i32.const 0) (i32.const 0) (i32.const 4)) + ) +) diff --git a/frame/contracts/fixtures/set_code_hash.wat b/frame/contracts/fixtures/set_code_hash.wat new file mode 100644 index 0000000000000..0a7b2e7cbedfa --- /dev/null +++ b/frame/contracts/fixtures/set_code_hash.wat @@ -0,0 +1,43 @@ +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "__unstable__" "seal_set_code_hash" (func $seal_set_code_hash (param i32) (result i32))) + + (import "env" "memory" (memory 1 1)) + + ;; [0, 32) here we store input + + ;; [32, 36) input size + (data (i32.const 32) "\20") + + ;; [36, 40) return value + (data (i32.const 36) "\01") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + (local $exit_code i32) + + (call $seal_input (i32.const 0) (i32.const 32)) + + (set_local $exit_code + (call $seal_set_code_hash (i32.const 0)) ;; Pointer to the input data. + ) + (call $assert + (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + ) + + ;; we return 1 after setting new code_hash + ;; next `call` will NOT return this value, because contract code has been changed + (call $seal_return (i32.const 0) (i32.const 36) (i32.const 4)) + ) + + (func (export "deploy")) +) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 88405eba44205..b18b40d0b3345 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1971,6 +1971,46 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + seal_set_code_hash { + let r in 0 .. API_BENCHMARK_BATCHES; + let code_hashes = (0..r * API_BENCHMARK_BATCH_SIZE) + .map(|i| { + let new_code = WasmModule::::dummy_with_bytes(i); + Contracts::::store_code_raw(new_code.code, whitelisted_caller())?; + Ok(new_code.hash) + }) + .collect::, &'static str>>()?; + let code_hash_len = code_hashes.get(0).map(|x| x.encode().len()).unwrap_or(0); + let code_hashes_bytes = code_hashes.iter().flat_map(|x| x.encode()).collect::>(); + let code_hashes_len = code_hashes_bytes.len(); + + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_set_code_hash", + params: vec![ + ValueType::I32, + ], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: code_hashes_bytes, + }, + ], + call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, code_hash_len as u32), // code_hash_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + // We make the assumption that pushing a constant and dropping a value takes roughly // the same amount of time. We follow that `t.load` and `drop` both have the weight // of this benchmark / 2. We need to make this assumption because there is no way diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index c6e647e0c8d96..bca74cd66ced7 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -18,6 +18,7 @@ use crate::{ gas::GasMeter, storage::{self, Storage, WriteOutcome}, + wasm::{decrement_refcount, increment_refcount}, AccountCounter, BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Error, Event, Pallet as Contracts, Schedule, }; @@ -239,6 +240,9 @@ pub trait Ext: sealing::Sealed { /// Tests sometimes need to modify and inspect the contract info directly. #[cfg(test)] fn contract_info(&mut self) -> &mut ContractInfo; + + /// Sets new code hash for existing contract. + fn set_code_hash(&mut self, hash: CodeHash) -> Result<(), DispatchError>; } /// Describes the different functions that can be exported by an [`Executable`]. @@ -1182,6 +1186,20 @@ where fn contract_info(&mut self) -> &mut ContractInfo { self.top_frame_mut().contract_info() } + + fn set_code_hash(&mut self, hash: CodeHash) -> Result<(), DispatchError> { + increment_refcount::(hash)?; + let top_frame = self.top_frame_mut(); + let prev_hash = top_frame.contract_info().code_hash.clone(); + decrement_refcount::(prev_hash.clone())?; + top_frame.contract_info().code_hash = hash; + Contracts::::deposit_event(Event::ContractCodeUpdated { + contract: top_frame.account_id.clone(), + new_code_hash: hash, + old_code_hash: prev_hash, + }); + Ok(()) + } } fn deposit_event(topics: Vec, event: Event) { diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 7e4515868b745..9e7b61301e7de 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -564,6 +564,16 @@ pub mod pallet { /// A code with the specified hash was removed. CodeRemoved { code_hash: T::Hash }, + + /// A contract's code was updated. + ContractCodeUpdated { + /// The contract that has been updated. + contract: T::AccountId, + /// New code hash that was set for the contract. + new_code_hash: T::Hash, + /// Previous code hash of the contract. + old_code_hash: T::Hash, + }, } #[pallet::error] diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index e599bdc3125bd..c92d2dd616106 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -328,6 +328,9 @@ pub struct HostFnWeights { /// Weight per overwritten byte of an item stored with `seal_set_storage`. pub set_storage_per_old_byte: Weight, + /// Weight of calling `seal_set_code_hash`. + pub set_code_hash: Weight, + /// Weight of calling `seal_clear_storage`. pub clear_storage: Weight, @@ -606,6 +609,7 @@ impl Default for HostFnWeights { ), debug_message: cost_batched!(seal_debug_message), set_storage: cost_batched!(seal_set_storage), + set_code_hash: cost_batched!(seal_set_code_hash), set_storage_per_new_byte: cost_byte_batched!(seal_set_storage_per_new_kb), set_storage_per_old_byte: cost_byte_batched!(seal_set_storage_per_old_kb), clear_storage: cost_batched!(seal_clear_storage), diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 6919705206d4a..486e84da75471 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -3023,3 +3023,64 @@ fn code_rejected_error_works() { ); }); } + +#[test] +#[cfg(feature = "unstable-interface")] +fn set_code_hash() { + let (wasm, code_hash) = compile_module::("set_code_hash").unwrap(); + let (new_wasm, new_code_hash) = compile_module::("new_set_code_hash_contract").unwrap(); + + let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Instantiate the 'caller' + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + 300_000, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + // upload new code + assert_ok!(Contracts::upload_code(Origin::signed(ALICE), new_wasm.clone(), None)); + + // First call sets new code_hash and returns 1 + let result = Contracts::bare_call( + ALICE, + contract_addr.clone(), + 0, + GAS_LIMIT, + None, + new_code_hash.as_ref().to_vec(), + true, + ) + .result + .unwrap(); + assert_return_code!(result, 1); + + // Second calls new contract code that returns 2 + let result = + Contracts::bare_call(ALICE, contract_addr.clone(), 0, GAS_LIMIT, None, vec![], true) + .result + .unwrap(); + assert_return_code!(result, 2); + + // Checking for the last event only + assert_eq!( + System::events().pop().unwrap(), + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::ContractCodeUpdated { + contract: contract_addr.clone(), + new_code_hash: new_code_hash.clone(), + old_code_hash: code_hash.clone(), + }), + topics: vec![], + }, + ); + }); +} diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index a48f9838837c9..9a447066667bd 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -117,6 +117,22 @@ pub fn decrement_refcount(code_hash: CodeHash) -> Result<(), Dispa Ok(()) } +/// Increment the refcount of a code in-storage by one. +/// +/// # Errors +/// +/// [`Error::CodeNotFound`] is returned if the specified `code_hash` does not exist. +pub fn increment_refcount(code_hash: CodeHash) -> Result<(), DispatchError> { + >::mutate(code_hash, |existing| -> Result<(), DispatchError> { + if let Some(info) = existing { + info.refcount = info.refcount.saturating_add(1); + Ok(()) + } else { + Err(Error::::CodeNotFound.into()) + } + }) +} + /// Try to remove code together with all associated information. pub fn try_remove(origin: &T::AccountId, code_hash: CodeHash) -> DispatchResult { >::try_mutate_exists(&code_hash, |existing| { diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 491daa58523e6..3053f33ff033a 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -26,7 +26,10 @@ mod runtime; #[cfg(feature = "runtime-benchmarks")] pub use self::code_cache::reinstrument; -pub use self::runtime::{ReturnCode, Runtime, RuntimeCosts}; +pub use self::{ + code_cache::{decrement_refcount, increment_refcount}, + runtime::{ReturnCode, Runtime, RuntimeCosts}, +}; use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, gas::GasMeter, @@ -322,6 +325,7 @@ mod tests { gas_meter: GasMeter, debug_buffer: Vec, ecdsa_recover: RefCell>, + code_hashes: Vec>, } /// The call is mocked and just returns this hardcoded value. @@ -332,6 +336,7 @@ mod tests { impl Default for MockExt { fn default() -> Self { Self { + code_hashes: Default::default(), storage: Default::default(), instantiates: Default::default(), terminations: Default::default(), @@ -390,6 +395,10 @@ mod tests { ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }, )) } + fn set_code_hash(&mut self, hash: CodeHash) -> Result<(), DispatchError> { + self.code_hashes.push(hash); + Ok(()) + } fn transfer(&mut self, to: &AccountIdOf, value: u64) -> Result<(), DispatchError> { self.transfers.push(TransferEntry { to: to.clone(), value }); Ok(()) @@ -798,6 +807,67 @@ mod tests { ); } + #[test] + #[cfg(feature = "unstable-interface")] + fn contains_storage_works() { + const CODE: &str = r#" +(module + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "__unstable__" "seal_contains_storage" (func $seal_contains_storage (param i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 4) size of input buffer (32 byte as we copy the key here) + (data (i32.const 0) "\20") + + ;; [4, 36) input buffer + + ;; [36, inf) output buffer + + (func (export "call") + ;; Receive key + (call $seal_input + (i32.const 4) ;; Pointer to the input buffer + (i32.const 0) ;; Size of the length buffer + ) + + ;; Load the return value into the output buffer + (i32.store (i32.const 36) + (call $seal_contains_storage + (i32.const 4) ;; The pointer to the storage key to fetch + ) + ) + + ;; Return the contents of the buffer + (call $seal_return + (i32.const 0) ;; flags + (i32.const 36) ;; output buffer ptr + (i32.const 4) ;; result is integer (4 bytes) + ) + ) + + (func (export "deploy")) +) +"#; + + let mut ext = MockExt::default(); + + ext.storage.insert([1u8; 32], vec![42u8]); + ext.storage.insert([2u8; 32], vec![]); + + // value does not exist -> sentinel value returned + let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + + // value did exist -> success + let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1,); + + // value did exist -> success (zero sized type) + let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0,); + } + const CODE_INSTANTIATE: &str = r#" (module ;; seal_instantiate( @@ -2249,67 +2319,6 @@ mod tests { assert_eq!(&result.data.0[4..], &[0u8; 0]); } - #[test] - #[cfg(feature = "unstable-interface")] - fn contains_storage_works() { - const CODE: &str = r#" -(module - (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "__unstable__" "seal_contains_storage" (func $seal_contains_storage (param i32) (result i32))) - (import "env" "memory" (memory 1 1)) - - ;; [0, 4) size of input buffer (32 byte as we copy the key here) - (data (i32.const 0) "\20") - - ;; [4, 36) input buffer - - ;; [36, inf) output buffer - - (func (export "call") - ;; Receive key - (call $seal_input - (i32.const 4) ;; Pointer to the input buffer - (i32.const 0) ;; Size of the length buffer - ) - - ;; Load the return value into the output buffer - (i32.store (i32.const 36) - (call $seal_contains_storage - (i32.const 4) ;; The pointer to the storage key to fetch - ) - ) - - ;; Return the contents of the buffer - (call $seal_return - (i32.const 0) ;; flags - (i32.const 36) ;; output buffer ptr - (i32.const 4) ;; result is integer (4 bytes) - ) - ) - - (func (export "deploy")) -) -"#; - - let mut ext = MockExt::default(); - - ext.storage.insert([1u8; 32], vec![42u8]); - ext.storage.insert([2u8; 32], vec![]); - - // value does not exist -> sentinel value returned - let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); - - // value did exist -> success - let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1,); - - // value did exist -> success (zero sized type) - let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0,); - } - #[test] #[cfg(feature = "unstable-interface")] fn is_contract_works() { @@ -2385,4 +2394,45 @@ mod tests { ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(0u32.encode()) }, ); } + + #[test] + #[cfg(feature = "unstable-interface")] + fn set_code_hash() { + const CODE: &str = r#" +(module + (import "__unstable__" "seal_set_code_hash" (func $seal_set_code_hash (param i32) (result i32))) + (import "env" "memory" (memory 1 1)) + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + (func (export "call") + (local $exit_code i32) + (set_local $exit_code + (call $seal_set_code_hash (i32.const 0)) + ) + (call $assert + (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + ) + ) + + (func (export "deploy")) + + ;; Hash of code. + (data (i32.const 0) + "\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11" + "\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11" + ) +) +"#; + + let mut mock_ext = MockExt::default(); + execute(CODE, [0u8; 32].encode(), &mut mock_ext).unwrap(); + + assert_eq!(mock_ext.code_hashes.pop().unwrap(), H256::from_slice(&[17u8; 32])); + } } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 55ab0dfa0adef..384fbff9809b7 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -222,6 +222,9 @@ pub enum RuntimeCosts { /// Weight charged for calling into the runtime. #[cfg(feature = "unstable-interface")] CallRuntime(Weight), + /// Weight of calling `seal_set_code_hash` + #[cfg(feature = "unstable-interface")] + SetCodeHash, } impl RuntimeCosts { @@ -305,6 +308,8 @@ impl RuntimeCosts { CopyIn(len) => s.return_per_byte.saturating_mul(len.into()), #[cfg(feature = "unstable-interface")] CallRuntime(weight) => weight, + #[cfg(feature = "unstable-interface")] + SetCodeHash => s.set_code_hash, }; RuntimeToken { #[cfg(test)] @@ -1960,4 +1965,41 @@ define_env!(Env, , Err(_) => Ok(ReturnCode::EcdsaRecoverFailed), } }, + + // Replace the contract code at the specified address with new code. + // + // # Note + // + // There are a couple of important considerations which must be taken into account when + // using this API: + // + // 1. The storage at the code address will remain untouched. This means that contract developers + // must ensure that the storage layout of the new code is compatible with that of the old code. + // + // 2. Contracts using this API can't be assumed as having deterministic addresses. Said another way, + // when using this API you lose the guarantee that an address always identifies a specific code hash. + // + // 3. If a contract calls into itself after changing its code the new call would use + // the new code. However, if the original caller panics after returning from the sub call it + // would revert the changes made by `seal_set_code_hash` and the next caller would use + // the old code. + // + // # Parameters + // + // - code_hash_ptr: A pointer to the buffer that contains the new code hash. + // + // # Errors + // + // `ReturnCode::CodeNotFound` + [__unstable__] seal_set_code_hash(ctx, code_hash_ptr: u32) -> ReturnCode => { + ctx.charge_gas(RuntimeCosts::SetCodeHash)?; + let code_hash: CodeHash<::T> = ctx.read_sandbox_memory_as(code_hash_ptr)?; + match ctx.ext.set_code_hash(code_hash) { + Err(err) => { + let code = Runtime::::err_into_return_code(err)?; + Ok(code) + }, + Ok(()) => Ok(ReturnCode::Success) + } + }, ); diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index ec6dcd2eee892..bf35ce511ab26 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-02-04, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-02-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -101,6 +101,7 @@ pub trait WeightInfo { fn seal_hash_blake2_128(r: u32, ) -> Weight; fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight; fn seal_ecdsa_recover(r: u32, ) -> Weight; + fn seal_set_code_hash(r: u32, ) -> Weight; fn instr_i64const(r: u32, ) -> Weight; fn instr_i64load(r: u32, ) -> Weight; fn instr_i64store(r: u32, ) -> Weight; @@ -159,32 +160,32 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_640_000 as Weight) + (1_590_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (6_385_000 as Weight) + (9_975_000 as Weight) // Standard Error: 0 - .saturating_add((748_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((724_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 5_000 - .saturating_add((2_304_000 as Weight).saturating_mul(q as Weight)) + (7_415_000 as Weight) + // Standard Error: 4_000 + .saturating_add((2_303_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (22_923_000 as Weight) - // Standard Error: 33_000 - .saturating_add((65_851_000 as Weight).saturating_mul(c as Weight)) + (18_519_000 as Weight) + // Standard Error: 36_000 + .saturating_add((66_661_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -193,9 +194,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (209_577_000 as Weight) - // Standard Error: 53_000 - .saturating_add((61_341_000 as Weight).saturating_mul(c as Weight)) + (210_319_000 as Weight) + // Standard Error: 41_000 + .saturating_add((54_802_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -207,11 +208,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (240_302_000 as Weight) - // Standard Error: 119_000 - .saturating_add((151_894_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 7_000 - .saturating_add((1_740_000 as Weight).saturating_mul(s as Weight)) + (220_394_000 as Weight) + // Standard Error: 129_000 + .saturating_add((145_155_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 8_000 + .saturating_add((1_741_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -222,9 +223,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (172_047_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_729_000 as Weight).saturating_mul(s as Weight)) + (171_438_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_721_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -233,7 +234,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (139_349_000 as Weight) + (139_529_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -241,9 +242,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (50_449_000 as Weight) - // Standard Error: 45_000 - .saturating_add((68_254_000 as Weight).saturating_mul(c as Weight)) + (51_040_000 as Weight) + // Standard Error: 38_000 + .saturating_add((65_886_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -251,7 +252,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_576_000 as Weight) + (24_347_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -260,9 +261,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (220_059_000 as Weight) - // Standard Error: 128_000 - .saturating_add((49_607_000 as Weight).saturating_mul(r as Weight)) + (217_164_000 as Weight) + // Standard Error: 89_000 + .saturating_add((48_023_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -271,9 +272,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (84_138_000 as Weight) - // Standard Error: 896_000 - .saturating_add((375_553_000 as Weight).saturating_mul(r as Weight)) + (81_537_000 as Weight) + // Standard Error: 847_000 + .saturating_add((367_429_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -283,9 +284,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (222_496_000 as Weight) - // Standard Error: 119_000 - .saturating_add((22_340_000 as Weight).saturating_mul(r as Weight)) + (214_798_000 as Weight) + // Standard Error: 56_000 + .saturating_add((21_100_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -294,9 +295,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (221_446_000 as Weight) - // Standard Error: 131_000 - .saturating_add((49_401_000 as Weight).saturating_mul(r as Weight)) + (216_615_000 as Weight) + // Standard Error: 75_000 + .saturating_add((48_054_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -305,9 +306,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (220_964_000 as Weight) - // Standard Error: 132_000 - .saturating_add((49_230_000 as Weight).saturating_mul(r as Weight)) + (218_034_000 as Weight) + // Standard Error: 87_000 + .saturating_add((47_594_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -316,9 +317,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (229_399_000 as Weight) - // Standard Error: 166_000 - .saturating_add((137_407_000 as Weight).saturating_mul(r as Weight)) + (221_980_000 as Weight) + // Standard Error: 135_000 + .saturating_add((135_618_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -327,9 +328,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (220_103_000 as Weight) - // Standard Error: 133_000 - .saturating_add((49_410_000 as Weight).saturating_mul(r as Weight)) + (217_623_000 as Weight) + // Standard Error: 86_000 + .saturating_add((47_656_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -338,9 +339,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (228_143_000 as Weight) - // Standard Error: 151_000 - .saturating_add((48_608_000 as Weight).saturating_mul(r as Weight)) + (216_826_000 as Weight) + // Standard Error: 88_000 + .saturating_add((47_644_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -349,9 +350,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (223_899_000 as Weight) - // Standard Error: 142_000 - .saturating_add((48_841_000 as Weight).saturating_mul(r as Weight)) + (219_487_000 as Weight) + // Standard Error: 90_000 + .saturating_add((47_167_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -360,9 +361,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (224_974_000 as Weight) - // Standard Error: 148_000 - .saturating_add((48_902_000 as Weight).saturating_mul(r as Weight)) + (218_953_000 as Weight) + // Standard Error: 95_000 + .saturating_add((47_458_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -372,9 +373,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (227_556_000 as Weight) - // Standard Error: 151_000 - .saturating_add((121_252_000 as Weight).saturating_mul(r as Weight)) + (220_132_000 as Weight) + // Standard Error: 144_000 + .saturating_add((120_373_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -383,9 +384,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (127_975_000 as Weight) - // Standard Error: 57_000 - .saturating_add((24_843_000 as Weight).saturating_mul(r as Weight)) + (127_458_000 as Weight) + // Standard Error: 56_000 + .saturating_add((24_015_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -394,9 +395,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (224_592_000 as Weight) - // Standard Error: 141_000 - .saturating_add((48_296_000 as Weight).saturating_mul(r as Weight)) + (220_304_000 as Weight) + // Standard Error: 112_000 + .saturating_add((46_804_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -405,9 +406,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (296_995_000 as Weight) - // Standard Error: 3_000 - .saturating_add((11_884_000 as Weight).saturating_mul(n as Weight)) + (300_916_000 as Weight) + // Standard Error: 8_000 + .saturating_add((10_552_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -415,8 +416,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(_r: u32, ) -> Weight { - (224_322_000 as Weight) + fn seal_return(r: u32, ) -> Weight { + (211_812_000 as Weight) + // Standard Error: 138_000 + .saturating_add((1_698_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -425,9 +428,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (216_240_000 as Weight) - // Standard Error: 1_000 - .saturating_add((206_000 as Weight).saturating_mul(n as Weight)) + (213_994_000 as Weight) + // Standard Error: 0 + .saturating_add((176_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -438,9 +441,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (219_637_000 as Weight) - // Standard Error: 3_916_000 - .saturating_add((51_769_000 as Weight).saturating_mul(r as Weight)) + (215_173_000 as Weight) + // Standard Error: 708_000 + .saturating_add((52_509_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -452,9 +455,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (221_470_000 as Weight) - // Standard Error: 154_000 - .saturating_add((158_758_000 as Weight).saturating_mul(r as Weight)) + (219_521_000 as Weight) + // Standard Error: 171_000 + .saturating_add((156_228_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -463,9 +466,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (228_674_000 as Weight) - // Standard Error: 203_000 - .saturating_add((287_195_000 as Weight).saturating_mul(r as Weight)) + (227_624_000 as Weight) + // Standard Error: 193_000 + .saturating_add((285_058_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -475,11 +478,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (507_091_000 as Weight) - // Standard Error: 1_863_000 - .saturating_add((291_858_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 367_000 - .saturating_add((83_459_000 as Weight).saturating_mul(n as Weight)) + (503_312_000 as Weight) + // Standard Error: 1_729_000 + .saturating_add((288_009_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 340_000 + .saturating_add((80_936_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -490,17 +493,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (133_592_000 as Weight) - // Standard Error: 87_000 - .saturating_add((41_718_000 as Weight).saturating_mul(r as Weight)) + (132_096_000 as Weight) + // Standard Error: 73_000 + .saturating_add((40_337_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (44_719_000 as Weight) - // Standard Error: 1_036_000 - .saturating_add((407_521_000 as Weight).saturating_mul(r as Weight)) + (52_622_000 as Weight) + // Standard Error: 1_006_000 + .saturating_add((404_716_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -508,25 +511,25 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (606_108_000 as Weight) - // Standard Error: 315_000 - .saturating_add((29_136_000 as Weight).saturating_mul(n as Weight)) + (601_324_000 as Weight) + // Standard Error: 264_000 + .saturating_add((27_943_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (634_330_000 as Weight) - // Standard Error: 281_000 - .saturating_add((10_741_000 as Weight).saturating_mul(n as Weight)) + (626_752_000 as Weight) + // Standard Error: 292_000 + .saturating_add((10_616_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (89_750_000 as Weight) - // Standard Error: 924_000 - .saturating_add((382_525_000 as Weight).saturating_mul(r as Weight)) + (80_138_000 as Weight) + // Standard Error: 933_000 + .saturating_add((382_949_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -534,51 +537,51 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (616_463_000 as Weight) - // Standard Error: 260_000 - .saturating_add((10_373_000 as Weight).saturating_mul(n as Weight)) + (603_984_000 as Weight) + // Standard Error: 242_000 + .saturating_add((10_712_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (116_340_000 as Weight) - // Standard Error: 633_000 - .saturating_add((322_054_000 as Weight).saturating_mul(r as Weight)) + (113_136_000 as Weight) + // Standard Error: 635_000 + .saturating_add((324_706_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (563_077_000 as Weight) - // Standard Error: 340_000 - .saturating_add((63_889_000 as Weight).saturating_mul(n as Weight)) + (562_781_000 as Weight) + // Standard Error: 354_000 + .saturating_add((63_275_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (118_832_000 as Weight) - // Standard Error: 595_000 - .saturating_add((291_817_000 as Weight).saturating_mul(r as Weight)) + (112_237_000 as Weight) + // Standard Error: 655_000 + .saturating_add((296_653_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (520_386_000 as Weight) - // Standard Error: 297_000 - .saturating_add((10_076_000 as Weight).saturating_mul(n as Weight)) + (520_002_000 as Weight) + // Standard Error: 232_000 + .saturating_add((9_726_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (85_377_000 as Weight) - // Standard Error: 847_000 - .saturating_add((419_438_000 as Weight).saturating_mul(r as Weight)) + (87_232_000 as Weight) + // Standard Error: 920_000 + .saturating_add((415_305_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -586,9 +589,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (666_218_000 as Weight) - // Standard Error: 294_000 - .saturating_add((64_627_000 as Weight).saturating_mul(n as Weight)) + (648_862_000 as Weight) + // Standard Error: 319_000 + .saturating_add((63_991_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } @@ -597,9 +600,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (108_224_000 as Weight) - // Standard Error: 1_042_000 - .saturating_add((1_723_539_000 as Weight).saturating_mul(r as Weight)) + (99_621_000 as Weight) + // Standard Error: 1_154_000 + .saturating_add((1_732_052_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -611,8 +614,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 7_843_000 - .saturating_add((19_825_093_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 6_293_000 + .saturating_add((19_410_115_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -624,8 +627,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_788_000 - .saturating_add((19_855_594_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 7_155_000 + .saturating_add((19_793_614_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -634,13 +637,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (20_190_331_000 as Weight) - // Standard Error: 75_647_000 - .saturating_add((2_369_225_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 27_000 - .saturating_add((19_831_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 28_000 - .saturating_add((31_191_000 as Weight).saturating_mul(o as Weight)) + (19_711_861_000 as Weight) + // Standard Error: 55_158_000 + .saturating_add((2_509_755_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 19_000 + .saturating_add((17_808_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 21_000 + .saturating_add((28_104_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -654,8 +657,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 50_368_000 - .saturating_add((27_757_564_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 47_294_000 + .saturating_add((26_664_406_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -668,13 +671,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (25_199_228_000 as Weight) + (24_447_236_000 as Weight) // Standard Error: 36_000 - .saturating_add((19_598_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((18_822_000 as Weight).saturating_mul(i as Weight)) // Standard Error: 36_000 - .saturating_add((30_986_000 as Weight).saturating_mul(o as Weight)) + .saturating_add((28_618_000 as Weight).saturating_mul(o as Weight)) // Standard Error: 36_000 - .saturating_add((158_016_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((156_535_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().writes(206 as Weight)) } @@ -683,9 +686,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (222_984_000 as Weight) - // Standard Error: 155_000 - .saturating_add((80_649_000 as Weight).saturating_mul(r as Weight)) + (216_091_000 as Weight) + // Standard Error: 123_000 + .saturating_add((79_416_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -694,9 +697,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (393_726_000 as Weight) - // Standard Error: 36_000 - .saturating_add((463_983_000 as Weight).saturating_mul(n as Weight)) + (223_253_000 as Weight) + // Standard Error: 43_000 + .saturating_add((462_629_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -705,9 +708,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (217_461_000 as Weight) - // Standard Error: 146_000 - .saturating_add((92_540_000 as Weight).saturating_mul(r as Weight)) + (217_285_000 as Weight) + // Standard Error: 147_000 + .saturating_add((91_020_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -716,9 +719,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (271_742_000 as Weight) - // Standard Error: 19_000 - .saturating_add((307_055_000 as Weight).saturating_mul(n as Weight)) + (364_402_000 as Weight) + // Standard Error: 27_000 + .saturating_add((305_342_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -727,9 +730,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (220_664_000 as Weight) - // Standard Error: 145_000 - .saturating_add((64_516_000 as Weight).saturating_mul(r as Weight)) + (214_309_000 as Weight) + // Standard Error: 107_000 + .saturating_add((63_668_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -738,9 +741,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (287_500_000 as Weight) - // Standard Error: 12_000 - .saturating_add((119_931_000 as Weight).saturating_mul(n as Weight)) + (306_968_000 as Weight) + // Standard Error: 13_000 + .saturating_add((118_373_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -749,9 +752,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (214_922_000 as Weight) - // Standard Error: 122_000 - .saturating_add((64_236_000 as Weight).saturating_mul(r as Weight)) + (215_434_000 as Weight) + // Standard Error: 115_000 + .saturating_add((62_560_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -760,9 +763,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (251_648_000 as Weight) - // Standard Error: 13_000 - .saturating_add((120_105_000 as Weight).saturating_mul(n as Weight)) + (226_690_000 as Weight) + // Standard Error: 17_000 + .saturating_add((118_871_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -771,266 +774,278 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (124_760_000 as Weight) - // Standard Error: 1_397_000 - .saturating_add((15_387_180_000 as Weight).saturating_mul(r as Weight)) + (187_068_000 as Weight) + // Standard Error: 1_354_000 + .saturating_add((15_409_805_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Contracts OwnerInfoOf (r:36 w:36) + fn seal_set_code_hash(r: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 2_158_000 + .saturating_add((932_937_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) + } fn instr_i64const(r: u32, ) -> Weight { - (75_287_000 as Weight) - // Standard Error: 11_000 - .saturating_add((569_000 as Weight).saturating_mul(r as Weight)) + (74_317_000 as Weight) + // Standard Error: 1_000 + .saturating_add((597_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_251_000 as Weight) + (74_303_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_306_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_311_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (75_072_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_386_000 as Weight).saturating_mul(r as Weight)) + (74_024_000 as Weight) + // Standard Error: 0 + .saturating_add((1_431_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (73_811_000 as Weight) - // Standard Error: 0 - .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) + (74_108_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_778_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (73_901_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_886_000 as Weight).saturating_mul(r as Weight)) + (73_966_000 as Weight) + // Standard Error: 0 + .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_720_000 as Weight) - // Standard Error: 1_000 - .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) + (73_839_000 as Weight) + // Standard Error: 2_000 + .saturating_add((907_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_534_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_459_000 as Weight).saturating_mul(r as Weight)) + (73_624_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_446_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_281_000 as Weight) - // Standard Error: 8_000 - .saturating_add((1_584_000 as Weight).saturating_mul(r as Weight)) + (73_169_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_602_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_135_000 as Weight) - // Standard Error: 1_000 - .saturating_add((6_000 as Weight).saturating_mul(e as Weight)) + (76_328_000 as Weight) + // Standard Error: 0 + .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (75_938_000 as Weight) - // Standard Error: 23_000 - .saturating_add((17_156_000 as Weight).saturating_mul(r as Weight)) + (74_771_000 as Weight) + // Standard Error: 22_000 + .saturating_add((17_044_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (85_864_000 as Weight) - // Standard Error: 28_000 - .saturating_add((28_343_000 as Weight).saturating_mul(r as Weight)) + (90_179_000 as Weight) + // Standard Error: 31_000 + .saturating_add((27_305_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (119_795_000 as Weight) - // Standard Error: 1_000 - .saturating_add((911_000 as Weight).saturating_mul(p as Weight)) + (117_977_000 as Weight) + // Standard Error: 2_000 + .saturating_add((928_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (74_750_000 as Weight) + (75_093_000 as Weight) // Standard Error: 1_000 - .saturating_add((613_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((610_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_831_000 as Weight) - // Standard Error: 2_000 - .saturating_add((672_000 as Weight).saturating_mul(r as Weight)) + (74_793_000 as Weight) + // Standard Error: 1_000 + .saturating_add((676_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_314_000 as Weight) - // Standard Error: 1_000 - .saturating_add((902_000 as Weight).saturating_mul(r as Weight)) + (74_183_000 as Weight) + // Standard Error: 2_000 + .saturating_add((913_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_040_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_161_000 as Weight).saturating_mul(r as Weight)) + (77_079_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_156_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (76_770_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) + (77_063_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_010_000 as Weight) - // Standard Error: 1_000 - .saturating_add((665_000 as Weight).saturating_mul(r as Weight)) + (74_314_000 as Weight) + // Standard Error: 2_000 + .saturating_add((662_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_597_000 as Weight) - // Standard Error: 929_000 - .saturating_add((183_940_000 as Weight).saturating_mul(r as Weight)) + (73_585_000 as Weight) + // Standard Error: 2_291_000 + .saturating_add((174_749_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_488_000 as Weight) - // Standard Error: 4_000 - .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) + (74_062_000 as Weight) + // Standard Error: 2_000 + .saturating_add((905_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_024_000 as Weight) - // Standard Error: 5_000 - .saturating_add((908_000 as Weight).saturating_mul(r as Weight)) + (74_121_000 as Weight) + // Standard Error: 1_000 + .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_084_000 as Weight) - // Standard Error: 1_000 - .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) + (74_519_000 as Weight) + // Standard Error: 2_000 + .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_250_000 as Weight) - // Standard Error: 2_000 - .saturating_add((916_000 as Weight).saturating_mul(r as Weight)) + (74_357_000 as Weight) + // Standard Error: 1_000 + .saturating_add((914_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_027_000 as Weight) + (74_101_000 as Weight) // Standard Error: 1_000 - .saturating_add((883_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_201_000 as Weight) + (74_442_000 as Weight) // Standard Error: 1_000 - .saturating_add((879_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((875_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_116_000 as Weight) + (74_247_000 as Weight) // Standard Error: 1_000 - .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((891_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (74_109_000 as Weight) + (74_091_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (73_962_000 as Weight) + (74_178_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (73_977_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (74_370_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_046_000 as Weight) + (74_180_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (73_912_000 as Weight) - // Standard Error: 0 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (74_035_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (73_918_000 as Weight) + (74_538_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (73_953_000 as Weight) + (74_035_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_855_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (74_399_000 as Weight) + // Standard Error: 8_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (73_917_000 as Weight) - // Standard Error: 2_000 + (73_987_000 as Weight) + // Standard Error: 1_000 .saturating_add((1_364_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (73_949_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + (74_017_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (73_726_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (74_271_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_330_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (73_921_000 as Weight) - // Standard Error: 1_000 + (74_016_000 as Weight) + // Standard Error: 0 .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (73_924_000 as Weight) + (74_063_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (73_842_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_011_000 as Weight).saturating_mul(r as Weight)) + (74_094_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_002_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (73_932_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_057_000 as Weight).saturating_mul(r as Weight)) + (73_957_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_045_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (74_028_000 as Weight) + (74_067_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_001_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_975_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (73_784_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_059_000 as Weight).saturating_mul(r as Weight)) + (74_092_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_035_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_169_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_334_000 as Weight).saturating_mul(r as Weight)) + (74_059_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (73_982_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) + (74_122_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (74_310_000 as Weight) + (74_296_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_329_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (73_861_000 as Weight) + (73_810_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (73_787_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_364_000 as Weight).saturating_mul(r as Weight)) + (74_101_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_407_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (73_886_000 as Weight) - // Standard Error: 7_000 - .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) + (74_076_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (73_860_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (74_082_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (73_917_000 as Weight) + (74_054_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } } @@ -1038,32 +1053,32 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_640_000 as Weight) + (1_590_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (6_385_000 as Weight) + (9_975_000 as Weight) // Standard Error: 0 - .saturating_add((748_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((724_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 5_000 - .saturating_add((2_304_000 as Weight).saturating_mul(q as Weight)) + (7_415_000 as Weight) + // Standard Error: 4_000 + .saturating_add((2_303_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (22_923_000 as Weight) - // Standard Error: 33_000 - .saturating_add((65_851_000 as Weight).saturating_mul(c as Weight)) + (18_519_000 as Weight) + // Standard Error: 36_000 + .saturating_add((66_661_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1072,9 +1087,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (209_577_000 as Weight) - // Standard Error: 53_000 - .saturating_add((61_341_000 as Weight).saturating_mul(c as Weight)) + (210_319_000 as Weight) + // Standard Error: 41_000 + .saturating_add((54_802_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1086,11 +1101,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (240_302_000 as Weight) - // Standard Error: 119_000 - .saturating_add((151_894_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 7_000 - .saturating_add((1_740_000 as Weight).saturating_mul(s as Weight)) + (220_394_000 as Weight) + // Standard Error: 129_000 + .saturating_add((145_155_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 8_000 + .saturating_add((1_741_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1101,9 +1116,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (172_047_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_729_000 as Weight).saturating_mul(s as Weight)) + (171_438_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_721_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1112,7 +1127,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (139_349_000 as Weight) + (139_529_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1120,9 +1135,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (50_449_000 as Weight) - // Standard Error: 45_000 - .saturating_add((68_254_000 as Weight).saturating_mul(c as Weight)) + (51_040_000 as Weight) + // Standard Error: 38_000 + .saturating_add((65_886_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1130,7 +1145,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_576_000 as Weight) + (24_347_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1139,9 +1154,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (220_059_000 as Weight) - // Standard Error: 128_000 - .saturating_add((49_607_000 as Weight).saturating_mul(r as Weight)) + (217_164_000 as Weight) + // Standard Error: 89_000 + .saturating_add((48_023_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1150,9 +1165,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (84_138_000 as Weight) - // Standard Error: 896_000 - .saturating_add((375_553_000 as Weight).saturating_mul(r as Weight)) + (81_537_000 as Weight) + // Standard Error: 847_000 + .saturating_add((367_429_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1162,9 +1177,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (222_496_000 as Weight) - // Standard Error: 119_000 - .saturating_add((22_340_000 as Weight).saturating_mul(r as Weight)) + (214_798_000 as Weight) + // Standard Error: 56_000 + .saturating_add((21_100_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1173,9 +1188,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (221_446_000 as Weight) - // Standard Error: 131_000 - .saturating_add((49_401_000 as Weight).saturating_mul(r as Weight)) + (216_615_000 as Weight) + // Standard Error: 75_000 + .saturating_add((48_054_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1184,9 +1199,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (220_964_000 as Weight) - // Standard Error: 132_000 - .saturating_add((49_230_000 as Weight).saturating_mul(r as Weight)) + (218_034_000 as Weight) + // Standard Error: 87_000 + .saturating_add((47_594_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1195,9 +1210,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (229_399_000 as Weight) - // Standard Error: 166_000 - .saturating_add((137_407_000 as Weight).saturating_mul(r as Weight)) + (221_980_000 as Weight) + // Standard Error: 135_000 + .saturating_add((135_618_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1206,9 +1221,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (220_103_000 as Weight) - // Standard Error: 133_000 - .saturating_add((49_410_000 as Weight).saturating_mul(r as Weight)) + (217_623_000 as Weight) + // Standard Error: 86_000 + .saturating_add((47_656_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1217,9 +1232,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (228_143_000 as Weight) - // Standard Error: 151_000 - .saturating_add((48_608_000 as Weight).saturating_mul(r as Weight)) + (216_826_000 as Weight) + // Standard Error: 88_000 + .saturating_add((47_644_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1228,9 +1243,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (223_899_000 as Weight) - // Standard Error: 142_000 - .saturating_add((48_841_000 as Weight).saturating_mul(r as Weight)) + (219_487_000 as Weight) + // Standard Error: 90_000 + .saturating_add((47_167_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1239,9 +1254,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (224_974_000 as Weight) - // Standard Error: 148_000 - .saturating_add((48_902_000 as Weight).saturating_mul(r as Weight)) + (218_953_000 as Weight) + // Standard Error: 95_000 + .saturating_add((47_458_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1251,9 +1266,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (227_556_000 as Weight) - // Standard Error: 151_000 - .saturating_add((121_252_000 as Weight).saturating_mul(r as Weight)) + (220_132_000 as Weight) + // Standard Error: 144_000 + .saturating_add((120_373_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1262,9 +1277,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (127_975_000 as Weight) - // Standard Error: 57_000 - .saturating_add((24_843_000 as Weight).saturating_mul(r as Weight)) + (127_458_000 as Weight) + // Standard Error: 56_000 + .saturating_add((24_015_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1273,9 +1288,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (224_592_000 as Weight) - // Standard Error: 141_000 - .saturating_add((48_296_000 as Weight).saturating_mul(r as Weight)) + (220_304_000 as Weight) + // Standard Error: 112_000 + .saturating_add((46_804_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1284,9 +1299,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (296_995_000 as Weight) - // Standard Error: 3_000 - .saturating_add((11_884_000 as Weight).saturating_mul(n as Weight)) + (300_916_000 as Weight) + // Standard Error: 8_000 + .saturating_add((10_552_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1294,8 +1309,10 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(_r: u32, ) -> Weight { - (224_322_000 as Weight) + fn seal_return(r: u32, ) -> Weight { + (211_812_000 as Weight) + // Standard Error: 138_000 + .saturating_add((1_698_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1304,9 +1321,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (216_240_000 as Weight) - // Standard Error: 1_000 - .saturating_add((206_000 as Weight).saturating_mul(n as Weight)) + (213_994_000 as Weight) + // Standard Error: 0 + .saturating_add((176_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1317,9 +1334,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (219_637_000 as Weight) - // Standard Error: 3_916_000 - .saturating_add((51_769_000 as Weight).saturating_mul(r as Weight)) + (215_173_000 as Weight) + // Standard Error: 708_000 + .saturating_add((52_509_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1331,9 +1348,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (221_470_000 as Weight) - // Standard Error: 154_000 - .saturating_add((158_758_000 as Weight).saturating_mul(r as Weight)) + (219_521_000 as Weight) + // Standard Error: 171_000 + .saturating_add((156_228_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1342,9 +1359,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (228_674_000 as Weight) - // Standard Error: 203_000 - .saturating_add((287_195_000 as Weight).saturating_mul(r as Weight)) + (227_624_000 as Weight) + // Standard Error: 193_000 + .saturating_add((285_058_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1354,11 +1371,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (507_091_000 as Weight) - // Standard Error: 1_863_000 - .saturating_add((291_858_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 367_000 - .saturating_add((83_459_000 as Weight).saturating_mul(n as Weight)) + (503_312_000 as Weight) + // Standard Error: 1_729_000 + .saturating_add((288_009_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 340_000 + .saturating_add((80_936_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1369,17 +1386,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (133_592_000 as Weight) - // Standard Error: 87_000 - .saturating_add((41_718_000 as Weight).saturating_mul(r as Weight)) + (132_096_000 as Weight) + // Standard Error: 73_000 + .saturating_add((40_337_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (44_719_000 as Weight) - // Standard Error: 1_036_000 - .saturating_add((407_521_000 as Weight).saturating_mul(r as Weight)) + (52_622_000 as Weight) + // Standard Error: 1_006_000 + .saturating_add((404_716_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1387,25 +1404,25 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (606_108_000 as Weight) - // Standard Error: 315_000 - .saturating_add((29_136_000 as Weight).saturating_mul(n as Weight)) + (601_324_000 as Weight) + // Standard Error: 264_000 + .saturating_add((27_943_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (634_330_000 as Weight) - // Standard Error: 281_000 - .saturating_add((10_741_000 as Weight).saturating_mul(n as Weight)) + (626_752_000 as Weight) + // Standard Error: 292_000 + .saturating_add((10_616_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (89_750_000 as Weight) - // Standard Error: 924_000 - .saturating_add((382_525_000 as Weight).saturating_mul(r as Weight)) + (80_138_000 as Weight) + // Standard Error: 933_000 + .saturating_add((382_949_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1413,51 +1430,51 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (616_463_000 as Weight) - // Standard Error: 260_000 - .saturating_add((10_373_000 as Weight).saturating_mul(n as Weight)) + (603_984_000 as Weight) + // Standard Error: 242_000 + .saturating_add((10_712_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (116_340_000 as Weight) - // Standard Error: 633_000 - .saturating_add((322_054_000 as Weight).saturating_mul(r as Weight)) + (113_136_000 as Weight) + // Standard Error: 635_000 + .saturating_add((324_706_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (563_077_000 as Weight) - // Standard Error: 340_000 - .saturating_add((63_889_000 as Weight).saturating_mul(n as Weight)) + (562_781_000 as Weight) + // Standard Error: 354_000 + .saturating_add((63_275_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (118_832_000 as Weight) - // Standard Error: 595_000 - .saturating_add((291_817_000 as Weight).saturating_mul(r as Weight)) + (112_237_000 as Weight) + // Standard Error: 655_000 + .saturating_add((296_653_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (520_386_000 as Weight) - // Standard Error: 297_000 - .saturating_add((10_076_000 as Weight).saturating_mul(n as Weight)) + (520_002_000 as Weight) + // Standard Error: 232_000 + .saturating_add((9_726_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (85_377_000 as Weight) - // Standard Error: 847_000 - .saturating_add((419_438_000 as Weight).saturating_mul(r as Weight)) + (87_232_000 as Weight) + // Standard Error: 920_000 + .saturating_add((415_305_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1465,9 +1482,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (666_218_000 as Weight) - // Standard Error: 294_000 - .saturating_add((64_627_000 as Weight).saturating_mul(n as Weight)) + (648_862_000 as Weight) + // Standard Error: 319_000 + .saturating_add((63_991_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } @@ -1476,9 +1493,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (108_224_000 as Weight) - // Standard Error: 1_042_000 - .saturating_add((1_723_539_000 as Weight).saturating_mul(r as Weight)) + (99_621_000 as Weight) + // Standard Error: 1_154_000 + .saturating_add((1_732_052_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1490,8 +1507,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 7_843_000 - .saturating_add((19_825_093_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 6_293_000 + .saturating_add((19_410_115_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1503,8 +1520,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_788_000 - .saturating_add((19_855_594_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 7_155_000 + .saturating_add((19_793_614_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1513,13 +1530,13 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (20_190_331_000 as Weight) - // Standard Error: 75_647_000 - .saturating_add((2_369_225_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 27_000 - .saturating_add((19_831_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 28_000 - .saturating_add((31_191_000 as Weight).saturating_mul(o as Weight)) + (19_711_861_000 as Weight) + // Standard Error: 55_158_000 + .saturating_add((2_509_755_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 19_000 + .saturating_add((17_808_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 21_000 + .saturating_add((28_104_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1533,8 +1550,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 50_368_000 - .saturating_add((27_757_564_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 47_294_000 + .saturating_add((26_664_406_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1547,13 +1564,13 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (25_199_228_000 as Weight) + (24_447_236_000 as Weight) // Standard Error: 36_000 - .saturating_add((19_598_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((18_822_000 as Weight).saturating_mul(i as Weight)) // Standard Error: 36_000 - .saturating_add((30_986_000 as Weight).saturating_mul(o as Weight)) + .saturating_add((28_618_000 as Weight).saturating_mul(o as Weight)) // Standard Error: 36_000 - .saturating_add((158_016_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((156_535_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().writes(206 as Weight)) } @@ -1562,9 +1579,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (222_984_000 as Weight) - // Standard Error: 155_000 - .saturating_add((80_649_000 as Weight).saturating_mul(r as Weight)) + (216_091_000 as Weight) + // Standard Error: 123_000 + .saturating_add((79_416_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1573,9 +1590,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (393_726_000 as Weight) - // Standard Error: 36_000 - .saturating_add((463_983_000 as Weight).saturating_mul(n as Weight)) + (223_253_000 as Weight) + // Standard Error: 43_000 + .saturating_add((462_629_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1584,9 +1601,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (217_461_000 as Weight) - // Standard Error: 146_000 - .saturating_add((92_540_000 as Weight).saturating_mul(r as Weight)) + (217_285_000 as Weight) + // Standard Error: 147_000 + .saturating_add((91_020_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1595,9 +1612,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (271_742_000 as Weight) - // Standard Error: 19_000 - .saturating_add((307_055_000 as Weight).saturating_mul(n as Weight)) + (364_402_000 as Weight) + // Standard Error: 27_000 + .saturating_add((305_342_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1606,9 +1623,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (220_664_000 as Weight) - // Standard Error: 145_000 - .saturating_add((64_516_000 as Weight).saturating_mul(r as Weight)) + (214_309_000 as Weight) + // Standard Error: 107_000 + .saturating_add((63_668_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1617,9 +1634,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (287_500_000 as Weight) - // Standard Error: 12_000 - .saturating_add((119_931_000 as Weight).saturating_mul(n as Weight)) + (306_968_000 as Weight) + // Standard Error: 13_000 + .saturating_add((118_373_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1628,9 +1645,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (214_922_000 as Weight) - // Standard Error: 122_000 - .saturating_add((64_236_000 as Weight).saturating_mul(r as Weight)) + (215_434_000 as Weight) + // Standard Error: 115_000 + .saturating_add((62_560_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1639,9 +1656,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (251_648_000 as Weight) - // Standard Error: 13_000 - .saturating_add((120_105_000 as Weight).saturating_mul(n as Weight)) + (226_690_000 as Weight) + // Standard Error: 17_000 + .saturating_add((118_871_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1650,265 +1667,277 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (124_760_000 as Weight) - // Standard Error: 1_397_000 - .saturating_add((15_387_180_000 as Weight).saturating_mul(r as Weight)) + (187_068_000 as Weight) + // Standard Error: 1_354_000 + .saturating_add((15_409_805_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Contracts OwnerInfoOf (r:36 w:36) + fn seal_set_code_hash(r: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 2_158_000 + .saturating_add((932_937_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) + } fn instr_i64const(r: u32, ) -> Weight { - (75_287_000 as Weight) - // Standard Error: 11_000 - .saturating_add((569_000 as Weight).saturating_mul(r as Weight)) + (74_317_000 as Weight) + // Standard Error: 1_000 + .saturating_add((597_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_251_000 as Weight) + (74_303_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_306_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_311_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (75_072_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_386_000 as Weight).saturating_mul(r as Weight)) + (74_024_000 as Weight) + // Standard Error: 0 + .saturating_add((1_431_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (73_811_000 as Weight) - // Standard Error: 0 - .saturating_add((1_783_000 as Weight).saturating_mul(r as Weight)) + (74_108_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_778_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (73_901_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_886_000 as Weight).saturating_mul(r as Weight)) + (73_966_000 as Weight) + // Standard Error: 0 + .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_720_000 as Weight) - // Standard Error: 1_000 - .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) + (73_839_000 as Weight) + // Standard Error: 2_000 + .saturating_add((907_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_534_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_459_000 as Weight).saturating_mul(r as Weight)) + (73_624_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_446_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_281_000 as Weight) - // Standard Error: 8_000 - .saturating_add((1_584_000 as Weight).saturating_mul(r as Weight)) + (73_169_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_602_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_135_000 as Weight) - // Standard Error: 1_000 - .saturating_add((6_000 as Weight).saturating_mul(e as Weight)) + (76_328_000 as Weight) + // Standard Error: 0 + .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (75_938_000 as Weight) - // Standard Error: 23_000 - .saturating_add((17_156_000 as Weight).saturating_mul(r as Weight)) + (74_771_000 as Weight) + // Standard Error: 22_000 + .saturating_add((17_044_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (85_864_000 as Weight) - // Standard Error: 28_000 - .saturating_add((28_343_000 as Weight).saturating_mul(r as Weight)) + (90_179_000 as Weight) + // Standard Error: 31_000 + .saturating_add((27_305_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (119_795_000 as Weight) - // Standard Error: 1_000 - .saturating_add((911_000 as Weight).saturating_mul(p as Weight)) + (117_977_000 as Weight) + // Standard Error: 2_000 + .saturating_add((928_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (74_750_000 as Weight) + (75_093_000 as Weight) // Standard Error: 1_000 - .saturating_add((613_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((610_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_831_000 as Weight) - // Standard Error: 2_000 - .saturating_add((672_000 as Weight).saturating_mul(r as Weight)) + (74_793_000 as Weight) + // Standard Error: 1_000 + .saturating_add((676_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_314_000 as Weight) - // Standard Error: 1_000 - .saturating_add((902_000 as Weight).saturating_mul(r as Weight)) + (74_183_000 as Weight) + // Standard Error: 2_000 + .saturating_add((913_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_040_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_161_000 as Weight).saturating_mul(r as Weight)) + (77_079_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_156_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (76_770_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) + (77_063_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_010_000 as Weight) - // Standard Error: 1_000 - .saturating_add((665_000 as Weight).saturating_mul(r as Weight)) + (74_314_000 as Weight) + // Standard Error: 2_000 + .saturating_add((662_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_597_000 as Weight) - // Standard Error: 929_000 - .saturating_add((183_940_000 as Weight).saturating_mul(r as Weight)) + (73_585_000 as Weight) + // Standard Error: 2_291_000 + .saturating_add((174_749_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_488_000 as Weight) - // Standard Error: 4_000 - .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) + (74_062_000 as Weight) + // Standard Error: 2_000 + .saturating_add((905_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_024_000 as Weight) - // Standard Error: 5_000 - .saturating_add((908_000 as Weight).saturating_mul(r as Weight)) + (74_121_000 as Weight) + // Standard Error: 1_000 + .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_084_000 as Weight) - // Standard Error: 1_000 - .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) + (74_519_000 as Weight) + // Standard Error: 2_000 + .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_250_000 as Weight) - // Standard Error: 2_000 - .saturating_add((916_000 as Weight).saturating_mul(r as Weight)) + (74_357_000 as Weight) + // Standard Error: 1_000 + .saturating_add((914_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_027_000 as Weight) + (74_101_000 as Weight) // Standard Error: 1_000 - .saturating_add((883_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_201_000 as Weight) + (74_442_000 as Weight) // Standard Error: 1_000 - .saturating_add((879_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((875_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_116_000 as Weight) + (74_247_000 as Weight) // Standard Error: 1_000 - .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((891_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (74_109_000 as Weight) + (74_091_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (73_962_000 as Weight) + (74_178_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (73_977_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (74_370_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_046_000 as Weight) + (74_180_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (73_912_000 as Weight) - // Standard Error: 0 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (74_035_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (73_918_000 as Weight) + (74_538_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (73_953_000 as Weight) + (74_035_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_855_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (74_399_000 as Weight) + // Standard Error: 8_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (73_917_000 as Weight) - // Standard Error: 2_000 + (73_987_000 as Weight) + // Standard Error: 1_000 .saturating_add((1_364_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (73_949_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + (74_017_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (73_726_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (74_271_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_330_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (73_921_000 as Weight) - // Standard Error: 1_000 + (74_016_000 as Weight) + // Standard Error: 0 .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (73_924_000 as Weight) + (74_063_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (73_842_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_011_000 as Weight).saturating_mul(r as Weight)) + (74_094_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_002_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (73_932_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_057_000 as Weight).saturating_mul(r as Weight)) + (73_957_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_045_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (74_028_000 as Weight) + (74_067_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_001_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_975_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (73_784_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_059_000 as Weight).saturating_mul(r as Weight)) + (74_092_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_035_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_169_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_334_000 as Weight).saturating_mul(r as Weight)) + (74_059_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (73_982_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) + (74_122_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (74_310_000 as Weight) + (74_296_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_329_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (73_861_000 as Weight) + (73_810_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (73_787_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_364_000 as Weight).saturating_mul(r as Weight)) + (74_101_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_407_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (73_886_000 as Weight) - // Standard Error: 7_000 - .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) + (74_076_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (73_860_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (74_082_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (73_917_000 as Weight) + (74_054_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } } From bc8968f4c84ed4cd80acd4d452874c59b5f2fb3b Mon Sep 17 00:00:00 2001 From: Dmitry Kashitsyn Date: Fri, 11 Feb 2022 15:32:06 +0700 Subject: [PATCH 0504/1472] Separate wasmi and wasmer sandbox implementations into their own modules (#10563) * Moves wasmi specific `ImportResolver` and `MemoryTransfer` impls to submodule * Splits context store environmental, moves impl `Externals` to wasmi backend * Adds wasmer sandbox backend stub module * Move sandbox impl code to backend specific modules * Moves wasmi stuff * Fixes value conversion * Makes it all compile * Remove `with_context_store` * Moves `WasmerBackend` to the impl * Reformat the source * Moves wasmer MemoryWrapper * Reformats the source * Fixes mutability * Moves backend impls to a submodule * Fix visibility * Reformat the source * Feature gate wasmer backend module * Moves wasmi memory allocation to backend module * Rename WasmerBackend to Backend * Refactor dispatch result decoding, get rid of Wasmi types in common sandbox code * Reformat the source * Remove redundant prefixes in backend functions * Remove wasmer-sandbox from default features * Post-review changes * Add conversion soundness proof * Remove redundant prefix * Removes now redundant clone_inner * Add `Error::SandboxBackend`, refactor invoke result * Fix comments * Rename `Error::SandboxBackend` to `Sandbox` * Simplifies logic in `wasmer_backend::invoke` * Fixes memory management --- client/executor/common/src/error.rs | 3 + client/executor/common/src/sandbox.rs | 543 +----------------- .../common/src/sandbox/wasmer_backend.rs | 434 ++++++++++++++ .../common/src/sandbox/wasmi_backend.rs | 323 +++++++++++ client/executor/common/src/util.rs | 191 +----- client/executor/wasmi/src/lib.rs | 6 +- client/executor/wasmtime/src/host.rs | 1 - 7 files changed, 788 insertions(+), 713 deletions(-) create mode 100644 client/executor/common/src/sandbox/wasmer_backend.rs create mode 100644 client/executor/common/src/sandbox/wasmi_backend.rs diff --git a/client/executor/common/src/error.rs b/client/executor/common/src/error.rs index c5de737376c15..5ffcafd7e92c4 100644 --- a/client/executor/common/src/error.rs +++ b/client/executor/common/src/error.rs @@ -34,6 +34,9 @@ pub enum Error { #[error(transparent)] Wasmi(#[from] wasmi::Error), + #[error("Sandbox error: {0}")] + Sandbox(String), + #[error("Error calling api function: {0}")] ApiError(Box), diff --git a/client/executor/common/src/sandbox.rs b/client/executor/common/src/sandbox.rs index 34162b7dc4978..3f46ec53bdfe4 100644 --- a/client/executor/common/src/sandbox.rs +++ b/client/executor/common/src/sandbox.rs @@ -20,24 +20,30 @@ //! //! Sandboxing is backed by wasmi and wasmer, depending on the configuration. +#[cfg(feature = "wasmer-sandbox")] +mod wasmer_backend; + +mod wasmi_backend; + use crate::{ - error::{Error, Result}, + error::{self, Result}, util, }; -use codec::{Decode, Encode}; +use codec::Decode; use sp_core::sandbox as sandbox_primitives; use sp_wasm_interface::{FunctionContext, Pointer, WordSize}; use std::{collections::HashMap, rc::Rc}; -use wasmi::{ - memory_units::Pages, Externals, ImportResolver, MemoryInstance, Module, ModuleInstance, - RuntimeArgs, RuntimeValue, Trap, TrapKind, -}; #[cfg(feature = "wasmer-sandbox")] -use crate::util::wasmer::MemoryWrapper as WasmerMemoryWrapper; -use crate::util::wasmi::MemoryWrapper as WasmiMemoryWrapper; +use wasmer_backend::{ + instantiate as wasmer_instantiate, invoke as wasmer_invoke, new_memory as wasmer_new_memory, + Backend as WasmerBackend, MemoryWrapper as WasmerMemoryWrapper, +}; -environmental::environmental!(SandboxContextStore: trait SandboxContext); +use wasmi_backend::{ + instantiate as wasmi_instantiate, invoke as wasmi_invoke, new_memory as wasmi_new_memory, + MemoryWrapper as WasmiMemoryWrapper, +}; /// Index of a function inside the supervisor. /// @@ -109,63 +115,6 @@ impl Imports { } } -impl ImportResolver for Imports { - fn resolve_func( - &self, - module_name: &str, - field_name: &str, - signature: &::wasmi::Signature, - ) -> std::result::Result { - let idx = self.func_by_name(module_name, field_name).ok_or_else(|| { - wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name)) - })?; - - Ok(wasmi::FuncInstance::alloc_host(signature.clone(), idx.0)) - } - - fn resolve_memory( - &self, - module_name: &str, - field_name: &str, - _memory_type: &::wasmi::MemoryDescriptor, - ) -> std::result::Result { - let mem = self.memory_by_name(module_name, field_name).ok_or_else(|| { - wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name)) - })?; - - let wrapper = mem.as_wasmi().ok_or_else(|| { - wasmi::Error::Instantiation(format!( - "Unsupported non-wasmi export {}:{}", - module_name, field_name - )) - })?; - - // Here we use inner memory reference only to resolve - // the imports without accessing the memory contents. - let mem = unsafe { wrapper.clone_inner() }; - - Ok(mem) - } - - fn resolve_global( - &self, - module_name: &str, - field_name: &str, - _global_type: &::wasmi::GlobalDescriptor, - ) -> std::result::Result { - Err(wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name))) - } - - fn resolve_table( - &self, - module_name: &str, - field_name: &str, - _table_type: &::wasmi::TableDescriptor, - ) -> std::result::Result { - Err(wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name))) - } -} - /// The sandbox context used to execute sandboxed functions. pub trait SandboxContext { /// Invoke a function in the supervisor environment. @@ -205,132 +154,6 @@ pub struct GuestExternals<'a> { state: u32, } -/// Construct trap error from specified message -fn trap(msg: &'static str) -> Trap { - TrapKind::Host(Box::new(Error::Other(msg.into()))).into() -} - -fn deserialize_result( - mut serialized_result: &[u8], -) -> std::result::Result, Trap> { - use self::sandbox_primitives::HostError; - use sp_wasm_interface::ReturnValue; - let result_val = std::result::Result::::decode(&mut serialized_result) - .map_err(|_| trap("Decoding Result failed!"))?; - - match result_val { - Ok(return_value) => Ok(match return_value { - ReturnValue::Unit => None, - ReturnValue::Value(typed_value) => Some(RuntimeValue::from(typed_value)), - }), - Err(HostError) => Err(trap("Supervisor function returned sandbox::HostError")), - } -} - -impl<'a> Externals for GuestExternals<'a> { - fn invoke_index( - &mut self, - index: usize, - args: RuntimeArgs, - ) -> std::result::Result, Trap> { - SandboxContextStore::with(|sandbox_context| { - // Make `index` typesafe again. - let index = GuestFuncIndex(index); - - // Convert function index from guest to supervisor space - let func_idx = self.sandbox_instance - .guest_to_supervisor_mapping - .func_by_guest_index(index) - .expect( - "`invoke_index` is called with indexes registered via `FuncInstance::alloc_host`; - `FuncInstance::alloc_host` is called with indexes that were obtained from `guest_to_supervisor_mapping`; - `func_by_guest_index` called with `index` can't return `None`; - qed" - ); - - // Serialize arguments into a byte vector. - let invoke_args_data: Vec = args - .as_ref() - .iter() - .cloned() - .map(sp_wasm_interface::Value::from) - .collect::>() - .encode(); - - let state = self.state; - - // Move serialized arguments inside the memory, invoke dispatch thunk and - // then free allocated memory. - let invoke_args_len = invoke_args_data.len() as WordSize; - let invoke_args_ptr = sandbox_context - .supervisor_context() - .allocate_memory(invoke_args_len) - .map_err(|_| trap("Can't allocate memory in supervisor for the arguments"))?; - - let deallocate = |supervisor_context: &mut dyn FunctionContext, ptr, fail_msg| { - supervisor_context.deallocate_memory(ptr).map_err(|_| trap(fail_msg)) - }; - - if sandbox_context - .supervisor_context() - .write_memory(invoke_args_ptr, &invoke_args_data) - .is_err() - { - deallocate( - sandbox_context.supervisor_context(), - invoke_args_ptr, - "Failed dealloction after failed write of invoke arguments", - )?; - return Err(trap("Can't write invoke args into memory")) - } - - let result = sandbox_context.invoke( - invoke_args_ptr, - invoke_args_len, - state, - func_idx, - ); - - deallocate( - sandbox_context.supervisor_context(), - invoke_args_ptr, - "Can't deallocate memory for dispatch thunk's invoke arguments", - )?; - let result = result?; - - // dispatch_thunk returns pointer to serialized arguments. - // Unpack pointer and len of the serialized result data. - let (serialized_result_val_ptr, serialized_result_val_len) = { - // Cast to u64 to use zero-extension. - let v = result as u64; - let ptr = (v as u64 >> 32) as u32; - let len = (v & 0xFFFFFFFF) as u32; - (Pointer::new(ptr), len) - }; - - let serialized_result_val = sandbox_context - .supervisor_context() - .read_memory(serialized_result_val_ptr, serialized_result_val_len) - .map_err(|_| trap("Can't read the serialized result from dispatch thunk")); - - deallocate( - sandbox_context.supervisor_context(), - serialized_result_val_ptr, - "Can't deallocate memory for dispatch thunk's result", - ) - .and_then(|_| serialized_result_val) - .and_then(|serialized_result_val| deserialize_result(&serialized_result_val)) - }).expect("SandboxContextStore is set when invoking sandboxed functions; qed") - } -} - -fn with_guest_externals(sandbox_instance: &SandboxInstance, state: u32, f: F) -> R -where - F: FnOnce(&mut GuestExternals) -> R, -{ - f(&mut GuestExternals { sandbox_instance, state }) -} - /// Module instance in terms of selected backend enum BackendInstance { /// Wasmi module instance @@ -370,74 +193,18 @@ impl SandboxInstance { /// these syscall implementations. pub fn invoke( &self, - - // function to call that is exported from the module export_name: &str, - - // arguments passed to the function - args: &[RuntimeValue], - - // arbitraty context data of the call + args: &[sp_wasm_interface::Value], state: u32, - sandbox_context: &mut dyn SandboxContext, - ) -> std::result::Result, wasmi::Error> { + ) -> std::result::Result, error::Error> { match &self.backend_instance { BackendInstance::Wasmi(wasmi_instance) => - with_guest_externals(self, state, |guest_externals| { - let wasmi_result = SandboxContextStore::using(sandbox_context, || { - wasmi_instance.invoke_export(export_name, args, guest_externals) - })?; - - Ok(wasmi_result) - }), + wasmi_invoke(self, wasmi_instance, export_name, args, state, sandbox_context), #[cfg(feature = "wasmer-sandbox")] - BackendInstance::Wasmer(wasmer_instance) => { - let function = wasmer_instance - .exports - .get_function(export_name) - .map_err(|error| wasmi::Error::Function(error.to_string()))?; - - let args: Vec = args - .iter() - .map(|v| match *v { - RuntimeValue::I32(val) => wasmer::Val::I32(val), - RuntimeValue::I64(val) => wasmer::Val::I64(val), - RuntimeValue::F32(val) => wasmer::Val::F32(val.into()), - RuntimeValue::F64(val) => wasmer::Val::F64(val.into()), - }) - .collect(); - - let wasmer_result = SandboxContextStore::using(sandbox_context, || { - function.call(&args).map_err(|error| wasmi::Error::Function(error.to_string())) - })?; - - if wasmer_result.len() > 1 { - return Err(wasmi::Error::Function( - "multiple return types are not supported yet".into(), - )) - } - - wasmer_result - .first() - .map(|wasm_value| { - let wasmer_value = match *wasm_value { - wasmer::Val::I32(val) => RuntimeValue::I32(val), - wasmer::Val::I64(val) => RuntimeValue::I64(val), - wasmer::Val::F32(val) => RuntimeValue::F32(val.into()), - wasmer::Val::F64(val) => RuntimeValue::F64(val.into()), - _ => - return Err(wasmi::Error::Function(format!( - "Unsupported return value: {:?}", - wasm_value, - ))), - }; - - Ok(wasmer_value) - }) - .transpose() - }, + BackendInstance::Wasmer(wasmer_instance) => + wasmer_invoke(wasmer_instance, export_name, args, state, sandbox_context), } } @@ -634,12 +401,6 @@ impl util::MemoryTransfer for Memory { } } -/// Wasmer specific context -#[cfg(feature = "wasmer-sandbox")] -struct WasmerBackend { - store: wasmer::Store, -} - /// Information specific to a particular execution backend enum BackendContext { /// Wasmi specific context @@ -659,13 +420,8 @@ impl BackendContext { SandboxBackend::TryWasmer => BackendContext::Wasmi, #[cfg(feature = "wasmer-sandbox")] - SandboxBackend::Wasmer | SandboxBackend::TryWasmer => { - let compiler = wasmer_compiler_singlepass::Singlepass::default(); - - BackendContext::Wasmer(WasmerBackend { - store: wasmer::Store::new(&wasmer::JIT::new(compiler).engine()), - }) - }, + SandboxBackend::Wasmer | SandboxBackend::TryWasmer => + BackendContext::Wasmer(WasmerBackend::new()), } } } @@ -709,19 +465,10 @@ impl Store

{ }; let memory = match &backend_context { - BackendContext::Wasmi => Memory::Wasmi(WasmiMemoryWrapper::new(MemoryInstance::alloc( - Pages(initial as usize), - maximum.map(|m| Pages(m as usize)), - )?)), + BackendContext::Wasmi => wasmi_new_memory(initial, maximum)?, #[cfg(feature = "wasmer-sandbox")] - BackendContext::Wasmer(context) => { - let ty = wasmer::MemoryType::new(initial, maximum, false); - Memory::Wasmer(WasmerMemoryWrapper::new( - wasmer::Memory::new(&context.store, ty) - .map_err(|_| Error::InvalidMemoryReference)?, - )) - }, + BackendContext::Wasmer(context) => wasmer_new_memory(context, initial, maximum)?, }; let mem_idx = memories.len(); @@ -827,12 +574,11 @@ impl Store
{ sandbox_context: &mut dyn SandboxContext, ) -> std::result::Result { let sandbox_instance = match self.backend_context { - BackendContext::Wasmi => - Self::instantiate_wasmi(wasm, guest_env, state, sandbox_context)?, + BackendContext::Wasmi => wasmi_instantiate(wasm, guest_env, state, sandbox_context)?, #[cfg(feature = "wasmer-sandbox")] BackendContext::Wasmer(ref context) => - Self::instantiate_wasmer(&context, wasm, guest_env, state, sandbox_context)?, + wasmer_instantiate(&context, wasm, guest_env, state, sandbox_context)?, }; Ok(UnregisteredInstance { sandbox_instance }) @@ -850,241 +596,4 @@ impl
Store
{ self.instances.push(Some((sandbox_instance, dispatch_thunk))); instance_idx as u32 } - - fn instantiate_wasmi( - wasm: &[u8], - guest_env: GuestEnvironment, - state: u32, - sandbox_context: &mut dyn SandboxContext, - ) -> std::result::Result, InstantiationError> { - let wasmi_module = - Module::from_buffer(wasm).map_err(|_| InstantiationError::ModuleDecoding)?; - let wasmi_instance = ModuleInstance::new(&wasmi_module, &guest_env.imports) - .map_err(|_| InstantiationError::Instantiation)?; - - let sandbox_instance = Rc::new(SandboxInstance { - // In general, it's not a very good idea to use `.not_started_instance()` for - // anything but for extracting memory and tables. But in this particular case, we - // are extracting for the purpose of running `start` function which should be ok. - backend_instance: BackendInstance::Wasmi(wasmi_instance.not_started_instance().clone()), - guest_to_supervisor_mapping: guest_env.guest_to_supervisor_mapping, - }); - - with_guest_externals(&sandbox_instance, state, |guest_externals| { - SandboxContextStore::using(sandbox_context, || { - wasmi_instance - .run_start(guest_externals) - .map_err(|_| InstantiationError::StartTrapped) - }) - - // Note: no need to run start on wasmtime instance, since it's done - // automatically - })?; - - Ok(sandbox_instance) - } - - #[cfg(feature = "wasmer-sandbox")] - fn instantiate_wasmer( - context: &WasmerBackend, - wasm: &[u8], - guest_env: GuestEnvironment, - state: u32, - sandbox_context: &mut dyn SandboxContext, - ) -> std::result::Result, InstantiationError> { - let module = wasmer::Module::new(&context.store, wasm) - .map_err(|_| InstantiationError::ModuleDecoding)?; - - type Exports = HashMap; - let mut exports_map = Exports::new(); - - for import in module.imports().into_iter() { - match import.ty() { - // Nothing to do here - wasmer::ExternType::Global(_) | wasmer::ExternType::Table(_) => (), - - wasmer::ExternType::Memory(_) => { - let exports = exports_map - .entry(import.module().to_string()) - .or_insert(wasmer::Exports::new()); - - let memory = guest_env - .imports - .memory_by_name(import.module(), import.name()) - .ok_or(InstantiationError::ModuleDecoding)?; - - let mut wasmer_memory_ref = memory.as_wasmer().expect( - "memory is created by wasmer; \ - exported by the same module and backend; \ - thus the operation can't fail; \ - qed", - ); - - // This is safe since we're only instantiating the module and populating - // the export table, so no memory access can happen at this time. - // All subsequent memory accesses should happen through the wrapper, - // that enforces the memory access protocol. - let wasmer_memory = unsafe { wasmer_memory_ref.clone_inner() }; - - exports.insert(import.name(), wasmer::Extern::Memory(wasmer_memory)); - }, - - wasmer::ExternType::Function(func_ty) => { - let guest_func_index = - guest_env.imports.func_by_name(import.module(), import.name()); - - let guest_func_index = if let Some(index) = guest_func_index { - index - } else { - // Missing import (should we abort here?) - continue - }; - - let supervisor_func_index = guest_env - .guest_to_supervisor_mapping - .func_by_guest_index(guest_func_index) - .ok_or(InstantiationError::ModuleDecoding)?; - - let function = Self::wasmer_dispatch_function( - supervisor_func_index, - &context.store, - func_ty, - state, - ); - - let exports = exports_map - .entry(import.module().to_string()) - .or_insert(wasmer::Exports::new()); - - exports.insert(import.name(), wasmer::Extern::Function(function)); - }, - } - } - - let mut import_object = wasmer::ImportObject::new(); - for (module_name, exports) in exports_map.into_iter() { - import_object.register(module_name, exports); - } - - let instance = SandboxContextStore::using(sandbox_context, || { - wasmer::Instance::new(&module, &import_object).map_err(|error| match error { - wasmer::InstantiationError::Link(_) => InstantiationError::Instantiation, - wasmer::InstantiationError::Start(_) => InstantiationError::StartTrapped, - wasmer::InstantiationError::HostEnvInitialization(_) => - InstantiationError::EnvironmentDefinitionCorrupted, - }) - })?; - - Ok(Rc::new(SandboxInstance { - backend_instance: BackendInstance::Wasmer(instance), - guest_to_supervisor_mapping: guest_env.guest_to_supervisor_mapping, - })) - } - - #[cfg(feature = "wasmer-sandbox")] - fn wasmer_dispatch_function( - supervisor_func_index: SupervisorFuncIndex, - store: &wasmer::Store, - func_ty: &wasmer::FunctionType, - state: u32, - ) -> wasmer::Function { - wasmer::Function::new(store, func_ty, move |params| { - SandboxContextStore::with(|sandbox_context| { - use sp_wasm_interface::Value; - - // Serialize arguments into a byte vector. - let invoke_args_data = params - .iter() - .map(|val| match val { - wasmer::Val::I32(val) => Ok(Value::I32(*val)), - wasmer::Val::I64(val) => Ok(Value::I64(*val)), - wasmer::Val::F32(val) => Ok(Value::F32(f32::to_bits(*val))), - wasmer::Val::F64(val) => Ok(Value::F64(f64::to_bits(*val))), - _ => Err(wasmer::RuntimeError::new(format!( - "Unsupported function argument: {:?}", - val - ))), - }) - .collect::, _>>()? - .encode(); - - // Move serialized arguments inside the memory, invoke dispatch thunk and - // then free allocated memory. - let invoke_args_len = invoke_args_data.len() as WordSize; - let invoke_args_ptr = sandbox_context - .supervisor_context() - .allocate_memory(invoke_args_len) - .map_err(|_| { - wasmer::RuntimeError::new( - "Can't allocate memory in supervisor for the arguments", - ) - })?; - - let deallocate = |fe: &mut dyn FunctionContext, ptr, fail_msg| { - fe.deallocate_memory(ptr).map_err(|_| wasmer::RuntimeError::new(fail_msg)) - }; - - if sandbox_context - .supervisor_context() - .write_memory(invoke_args_ptr, &invoke_args_data) - .is_err() - { - deallocate( - sandbox_context.supervisor_context(), - invoke_args_ptr, - "Failed dealloction after failed write of invoke arguments", - )?; - - return Err(wasmer::RuntimeError::new("Can't write invoke args into memory")) - } - - // Perform the actuall call - let serialized_result = sandbox_context - .invoke(invoke_args_ptr, invoke_args_len, state, supervisor_func_index) - .map_err(|e| wasmer::RuntimeError::new(e.to_string()))?; - - // dispatch_thunk returns pointer to serialized arguments. - // Unpack pointer and len of the serialized result data. - let (serialized_result_val_ptr, serialized_result_val_len) = { - // Cast to u64 to use zero-extension. - let v = serialized_result as u64; - let ptr = (v as u64 >> 32) as u32; - let len = (v & 0xFFFFFFFF) as u32; - (Pointer::new(ptr), len) - }; - - let serialized_result_val = sandbox_context - .supervisor_context() - .read_memory(serialized_result_val_ptr, serialized_result_val_len) - .map_err(|_| { - wasmer::RuntimeError::new( - "Can't read the serialized result from dispatch thunk", - ) - }); - - let deserialized_result = deallocate( - sandbox_context.supervisor_context(), - serialized_result_val_ptr, - "Can't deallocate memory for dispatch thunk's result", - ) - .and_then(|_| serialized_result_val) - .and_then(|serialized_result_val| { - deserialize_result(&serialized_result_val) - .map_err(|e| wasmer::RuntimeError::new(e.to_string())) - })?; - - if let Some(value) = deserialized_result { - Ok(vec![match value { - RuntimeValue::I32(val) => wasmer::Val::I32(val), - RuntimeValue::I64(val) => wasmer::Val::I64(val), - RuntimeValue::F32(val) => wasmer::Val::F32(val.into()), - RuntimeValue::F64(val) => wasmer::Val::F64(val.into()), - }]) - } else { - Ok(vec![]) - } - }) - .expect("SandboxContextStore is set when invoking sandboxed functions; qed") - }) - } } diff --git a/client/executor/common/src/sandbox/wasmer_backend.rs b/client/executor/common/src/sandbox/wasmer_backend.rs new file mode 100644 index 0000000000000..dfb26c4a8dedb --- /dev/null +++ b/client/executor/common/src/sandbox/wasmer_backend.rs @@ -0,0 +1,434 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Wasmer specific impls for sandbox + +use crate::{ + error::{Error, Result}, + sandbox::Memory, + util::{checked_range, MemoryTransfer}, +}; +use codec::{Decode, Encode}; +use sp_core::sandbox::HostError; +use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; +use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; +use wasmer::RuntimeError; + +use crate::sandbox::{ + BackendInstance, GuestEnvironment, InstantiationError, SandboxContext, SandboxInstance, + SupervisorFuncIndex, +}; + +environmental::environmental!(SandboxContextStore: trait SandboxContext); + +/// Wasmer specific context +pub struct Backend { + store: wasmer::Store, +} + +impl Backend { + pub fn new() -> Self { + let compiler = wasmer_compiler_singlepass::Singlepass::default(); + + Backend { store: wasmer::Store::new(&wasmer::JIT::new(compiler).engine()) } + } +} + +/// Invoke a function within a sandboxed module +pub fn invoke( + instance: &wasmer::Instance, + export_name: &str, + args: &[Value], + _state: u32, + sandbox_context: &mut dyn SandboxContext, +) -> std::result::Result, Error> { + let function = instance + .exports + .get_function(export_name) + .map_err(|error| Error::Sandbox(error.to_string()))?; + + let args: Vec = args + .iter() + .map(|v| match *v { + Value::I32(val) => wasmer::Val::I32(val), + Value::I64(val) => wasmer::Val::I64(val), + Value::F32(val) => wasmer::Val::F32(f32::from_bits(val)), + Value::F64(val) => wasmer::Val::F64(f64::from_bits(val)), + }) + .collect(); + + let wasmer_result = SandboxContextStore::using(sandbox_context, || { + function.call(&args).map_err(|error| Error::Sandbox(error.to_string())) + })?; + + match wasmer_result.as_ref() { + [] => Ok(None), + + [wasm_value] => { + let wasmer_value = match *wasm_value { + wasmer::Val::I32(val) => Value::I32(val), + wasmer::Val::I64(val) => Value::I64(val), + wasmer::Val::F32(val) => Value::F32(f32::to_bits(val)), + wasmer::Val::F64(val) => Value::F64(f64::to_bits(val)), + _ => + return Err(Error::Sandbox(format!( + "Unsupported return value: {:?}", + wasm_value, + ))), + }; + + Ok(Some(wasmer_value)) + }, + + _ => Err(Error::Sandbox("multiple return types are not supported yet".into())), + } +} + +/// Instantiate a module within a sandbox context +pub fn instantiate( + context: &Backend, + wasm: &[u8], + guest_env: GuestEnvironment, + state: u32, + sandbox_context: &mut dyn SandboxContext, +) -> std::result::Result, InstantiationError> { + let module = wasmer::Module::new(&context.store, wasm) + .map_err(|_| InstantiationError::ModuleDecoding)?; + + type Exports = HashMap; + let mut exports_map = Exports::new(); + + for import in module.imports().into_iter() { + match import.ty() { + // Nothing to do here + wasmer::ExternType::Global(_) | wasmer::ExternType::Table(_) => (), + + wasmer::ExternType::Memory(_) => { + let exports = exports_map + .entry(import.module().to_string()) + .or_insert(wasmer::Exports::new()); + + let memory = guest_env + .imports + .memory_by_name(import.module(), import.name()) + .ok_or(InstantiationError::ModuleDecoding)?; + + let wasmer_memory_ref = memory.as_wasmer().expect( + "memory is created by wasmer; \ + exported by the same module and backend; \ + thus the operation can't fail; \ + qed", + ); + + // This is safe since we're only instantiating the module and populating + // the export table, so no memory access can happen at this time. + // All subsequent memory accesses should happen through the wrapper, + // that enforces the memory access protocol. + // + // We take exclusive lock to ensure that we're the only one here, + // since during instantiation phase the memory should only be created + // and not yet accessed. + let wasmer_memory = wasmer_memory_ref + .buffer + .try_borrow_mut() + .map_err(|_| InstantiationError::EnvironmentDefinitionCorrupted)? + .clone(); + + exports.insert(import.name(), wasmer::Extern::Memory(wasmer_memory)); + }, + + wasmer::ExternType::Function(func_ty) => { + let guest_func_index = + guest_env.imports.func_by_name(import.module(), import.name()); + + let guest_func_index = if let Some(index) = guest_func_index { + index + } else { + // Missing import (should we abort here?) + continue + }; + + let supervisor_func_index = guest_env + .guest_to_supervisor_mapping + .func_by_guest_index(guest_func_index) + .ok_or(InstantiationError::ModuleDecoding)?; + + let function = + dispatch_function(supervisor_func_index, &context.store, func_ty, state); + + let exports = exports_map + .entry(import.module().to_string()) + .or_insert(wasmer::Exports::new()); + + exports.insert(import.name(), wasmer::Extern::Function(function)); + }, + } + } + + let mut import_object = wasmer::ImportObject::new(); + for (module_name, exports) in exports_map.into_iter() { + import_object.register(module_name, exports); + } + + let instance = SandboxContextStore::using(sandbox_context, || { + wasmer::Instance::new(&module, &import_object).map_err(|error| match error { + wasmer::InstantiationError::Link(_) => InstantiationError::Instantiation, + wasmer::InstantiationError::Start(_) => InstantiationError::StartTrapped, + wasmer::InstantiationError::HostEnvInitialization(_) => + InstantiationError::EnvironmentDefinitionCorrupted, + }) + })?; + + Ok(Rc::new(SandboxInstance { + backend_instance: BackendInstance::Wasmer(instance), + guest_to_supervisor_mapping: guest_env.guest_to_supervisor_mapping, + })) +} + +fn dispatch_function( + supervisor_func_index: SupervisorFuncIndex, + store: &wasmer::Store, + func_ty: &wasmer::FunctionType, + state: u32, +) -> wasmer::Function { + wasmer::Function::new(store, func_ty, move |params| { + SandboxContextStore::with(|sandbox_context| { + // Serialize arguments into a byte vector. + let invoke_args_data = params + .iter() + .map(|val| match val { + wasmer::Val::I32(val) => Ok(Value::I32(*val)), + wasmer::Val::I64(val) => Ok(Value::I64(*val)), + wasmer::Val::F32(val) => Ok(Value::F32(f32::to_bits(*val))), + wasmer::Val::F64(val) => Ok(Value::F64(f64::to_bits(*val))), + _ => + Err(RuntimeError::new(format!("Unsupported function argument: {:?}", val))), + }) + .collect::, _>>()? + .encode(); + + // Move serialized arguments inside the memory, invoke dispatch thunk and + // then free allocated memory. + let invoke_args_len = invoke_args_data.len() as WordSize; + let invoke_args_ptr = + sandbox_context.supervisor_context().allocate_memory(invoke_args_len).map_err( + |_| RuntimeError::new("Can't allocate memory in supervisor for the arguments"), + )?; + + let deallocate = |fe: &mut dyn FunctionContext, ptr, fail_msg| { + fe.deallocate_memory(ptr).map_err(|_| RuntimeError::new(fail_msg)) + }; + + if sandbox_context + .supervisor_context() + .write_memory(invoke_args_ptr, &invoke_args_data) + .is_err() + { + deallocate( + sandbox_context.supervisor_context(), + invoke_args_ptr, + "Failed dealloction after failed write of invoke arguments", + )?; + + return Err(RuntimeError::new("Can't write invoke args into memory")) + } + + // Perform the actuall call + let serialized_result = sandbox_context + .invoke(invoke_args_ptr, invoke_args_len, state, supervisor_func_index) + .map_err(|e| RuntimeError::new(e.to_string())); + + deallocate( + sandbox_context.supervisor_context(), + invoke_args_ptr, + "Failed dealloction after invoke", + )?; + + let serialized_result = serialized_result?; + + // dispatch_thunk returns pointer to serialized arguments. + // Unpack pointer and len of the serialized result data. + let (serialized_result_val_ptr, serialized_result_val_len) = { + // Cast to u64 to use zero-extension. + let v = serialized_result as u64; + let ptr = (v as u64 >> 32) as u32; + let len = (v & 0xFFFFFFFF) as u32; + (Pointer::new(ptr), len) + }; + + let serialized_result_val = sandbox_context + .supervisor_context() + .read_memory(serialized_result_val_ptr, serialized_result_val_len) + .map_err(|_| { + RuntimeError::new("Can't read the serialized result from dispatch thunk") + }); + + deallocate( + sandbox_context.supervisor_context(), + serialized_result_val_ptr, + "Can't deallocate memory for dispatch thunk's result", + )?; + + let serialized_result_val = serialized_result_val?; + + let deserialized_result = std::result::Result::::decode( + &mut serialized_result_val.as_slice(), + ) + .map_err(|_| RuntimeError::new("Decoding Result failed!"))? + .map_err(|_| RuntimeError::new("Supervisor function returned sandbox::HostError"))?; + + let result = match deserialized_result { + ReturnValue::Value(Value::I32(val)) => vec![wasmer::Val::I32(val)], + ReturnValue::Value(Value::I64(val)) => vec![wasmer::Val::I64(val)], + ReturnValue::Value(Value::F32(val)) => vec![wasmer::Val::F32(f32::from_bits(val))], + ReturnValue::Value(Value::F64(val)) => vec![wasmer::Val::F64(f64::from_bits(val))], + + ReturnValue::Unit => vec![], + }; + + Ok(result) + }) + .expect("SandboxContextStore is set when invoking sandboxed functions; qed") + }) +} + +/// Allocate new memory region +pub fn new_memory( + context: &Backend, + initial: u32, + maximum: Option, +) -> crate::error::Result { + let ty = wasmer::MemoryType::new(initial, maximum, false); + let memory = Memory::Wasmer(MemoryWrapper::new( + wasmer::Memory::new(&context.store, ty).map_err(|_| Error::InvalidMemoryReference)?, + )); + + Ok(memory) +} + +/// In order to enforce memory access protocol to the backend memory +/// we wrap it with `RefCell` and encapsulate all memory operations. +#[derive(Debug, Clone)] +pub struct MemoryWrapper { + buffer: Rc>, +} + +impl MemoryWrapper { + /// Take ownership of the memory region and return a wrapper object + pub fn new(memory: wasmer::Memory) -> Self { + Self { buffer: Rc::new(RefCell::new(memory)) } + } + + /// Returns linear memory of the wasm instance as a slice. + /// + /// # Safety + /// + /// Wasmer doesn't provide comprehensive documentation about the exact behavior of the data + /// pointer. If a dynamic style heap is used the base pointer of the heap can change. Since + /// growing, we cannot guarantee the lifetime of the returned slice reference. + unsafe fn memory_as_slice(memory: &wasmer::Memory) -> &[u8] { + let ptr = memory.data_ptr() as *const _; + + let len: usize = memory.data_size().try_into().expect( + "maximum memory object size never exceeds pointer size on any architecture; \ + usize by design and definition is enough to store any memory object size \ + possible on current achitecture; thus the conversion can not fail; qed", + ); + + if len == 0 { + &[] + } else { + core::slice::from_raw_parts(ptr, len) + } + } + + /// Returns linear memory of the wasm instance as a slice. + /// + /// # Safety + /// + /// See `[memory_as_slice]`. In addition to those requirements, since a mutable reference is + /// returned it must be ensured that only one mutable and no shared references to memory + /// exists at the same time. + unsafe fn memory_as_slice_mut(memory: &mut wasmer::Memory) -> &mut [u8] { + let ptr = memory.data_ptr(); + + let len: usize = memory.data_size().try_into().expect( + "maximum memory object size never exceeds pointer size on any architecture; \ + usize by design and definition is enough to store any memory object size \ + possible on current achitecture; thus the conversion can not fail; qed", + ); + + if len == 0 { + &mut [] + } else { + core::slice::from_raw_parts_mut(ptr, len) + } + } +} + +impl MemoryTransfer for MemoryWrapper { + fn read(&self, source_addr: Pointer, size: usize) -> Result> { + let memory = self.buffer.borrow(); + + let data_size: usize = memory.data_size().try_into().expect( + "maximum memory object size never exceeds pointer size on any architecture; \ + usize by design and definition is enough to store any memory object size \ + possible on current achitecture; thus the conversion can not fail; qed", + ); + + let range = checked_range(source_addr.into(), size, data_size) + .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; + + let mut buffer = vec![0; range.len()]; + self.read_into(source_addr, &mut buffer)?; + + Ok(buffer) + } + + fn read_into(&self, source_addr: Pointer, destination: &mut [u8]) -> Result<()> { + unsafe { + let memory = self.buffer.borrow(); + + // This should be safe since we don't grow up memory while caching this reference + // and we give up the reference before returning from this function. + let source = Self::memory_as_slice(&memory); + + let range = checked_range(source_addr.into(), destination.len(), source.len()) + .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; + + destination.copy_from_slice(&source[range]); + Ok(()) + } + } + + fn write_from(&self, dest_addr: Pointer, source: &[u8]) -> Result<()> { + unsafe { + let memory = &mut self.buffer.borrow_mut(); + + // This should be safe since we don't grow up memory while caching this reference + // and we give up the reference before returning from this function. + let destination = Self::memory_as_slice_mut(memory); + + let range = checked_range(dest_addr.into(), source.len(), destination.len()) + .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; + + destination[range].copy_from_slice(source); + Ok(()) + } + } +} diff --git a/client/executor/common/src/sandbox/wasmi_backend.rs b/client/executor/common/src/sandbox/wasmi_backend.rs new file mode 100644 index 0000000000000..92bb0e1e398e0 --- /dev/null +++ b/client/executor/common/src/sandbox/wasmi_backend.rs @@ -0,0 +1,323 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Wasmi specific impls for sandbox + +use codec::{Decode, Encode}; +use sp_core::sandbox::HostError; +use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; +use std::rc::Rc; + +use wasmi::{ + memory_units::Pages, ImportResolver, MemoryInstance, Module, ModuleInstance, RuntimeArgs, + RuntimeValue, Trap, TrapKind, +}; + +use crate::{ + error::{self, Error}, + sandbox::{ + BackendInstance, GuestEnvironment, GuestExternals, GuestFuncIndex, Imports, + InstantiationError, Memory, SandboxContext, SandboxInstance, + }, + util::{checked_range, MemoryTransfer}, +}; + +environmental::environmental!(SandboxContextStore: trait SandboxContext); + +/// Construct trap error from specified message +fn trap(msg: &'static str) -> Trap { + TrapKind::Host(Box::new(Error::Other(msg.into()))).into() +} + +impl ImportResolver for Imports { + fn resolve_func( + &self, + module_name: &str, + field_name: &str, + signature: &wasmi::Signature, + ) -> std::result::Result { + let idx = self.func_by_name(module_name, field_name).ok_or_else(|| { + wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name)) + })?; + + Ok(wasmi::FuncInstance::alloc_host(signature.clone(), idx.0)) + } + + fn resolve_memory( + &self, + module_name: &str, + field_name: &str, + _memory_type: &wasmi::MemoryDescriptor, + ) -> std::result::Result { + let mem = self.memory_by_name(module_name, field_name).ok_or_else(|| { + wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name)) + })?; + + let wrapper = mem.as_wasmi().ok_or_else(|| { + wasmi::Error::Instantiation(format!( + "Unsupported non-wasmi export {}:{}", + module_name, field_name + )) + })?; + + // Here we use inner memory reference only to resolve the imports + // without accessing the memory contents. All subsequent memory accesses + // should happen through the wrapper, that enforces the memory access protocol. + let mem = wrapper.0.clone(); + + Ok(mem) + } + + fn resolve_global( + &self, + module_name: &str, + field_name: &str, + _global_type: &wasmi::GlobalDescriptor, + ) -> std::result::Result { + Err(wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name))) + } + + fn resolve_table( + &self, + module_name: &str, + field_name: &str, + _table_type: &wasmi::TableDescriptor, + ) -> std::result::Result { + Err(wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name))) + } +} + +/// Allocate new memory region +pub fn new_memory(initial: u32, maximum: Option) -> crate::error::Result { + let memory = Memory::Wasmi(MemoryWrapper::new( + MemoryInstance::alloc(Pages(initial as usize), maximum.map(|m| Pages(m as usize))) + .map_err(|error| Error::Sandbox(error.to_string()))?, + )); + + Ok(memory) +} + +/// Wasmi provides direct access to its memory using slices. +/// +/// This wrapper limits the scope where the slice can be taken to +#[derive(Debug, Clone)] +pub struct MemoryWrapper(wasmi::MemoryRef); + +impl MemoryWrapper { + /// Take ownership of the memory region and return a wrapper object + fn new(memory: wasmi::MemoryRef) -> Self { + Self(memory) + } +} + +impl MemoryTransfer for MemoryWrapper { + fn read(&self, source_addr: Pointer, size: usize) -> error::Result> { + self.0.with_direct_access(|source| { + let range = checked_range(source_addr.into(), size, source.len()) + .ok_or_else(|| error::Error::Other("memory read is out of bounds".into()))?; + + Ok(Vec::from(&source[range])) + }) + } + + fn read_into(&self, source_addr: Pointer, destination: &mut [u8]) -> error::Result<()> { + self.0.with_direct_access(|source| { + let range = checked_range(source_addr.into(), destination.len(), source.len()) + .ok_or_else(|| error::Error::Other("memory read is out of bounds".into()))?; + + destination.copy_from_slice(&source[range]); + Ok(()) + }) + } + + fn write_from(&self, dest_addr: Pointer, source: &[u8]) -> error::Result<()> { + self.0.with_direct_access_mut(|destination| { + let range = checked_range(dest_addr.into(), source.len(), destination.len()) + .ok_or_else(|| error::Error::Other("memory write is out of bounds".into()))?; + + destination[range].copy_from_slice(source); + Ok(()) + }) + } +} + +impl<'a> wasmi::Externals for GuestExternals<'a> { + fn invoke_index( + &mut self, + index: usize, + args: RuntimeArgs, + ) -> std::result::Result, Trap> { + SandboxContextStore::with(|sandbox_context| { + // Make `index` typesafe again. + let index = GuestFuncIndex(index); + + // Convert function index from guest to supervisor space + let func_idx = self.sandbox_instance + .guest_to_supervisor_mapping + .func_by_guest_index(index) + .expect( + "`invoke_index` is called with indexes registered via `FuncInstance::alloc_host`; + `FuncInstance::alloc_host` is called with indexes that were obtained from `guest_to_supervisor_mapping`; + `func_by_guest_index` called with `index` can't return `None`; + qed" + ); + + // Serialize arguments into a byte vector. + let invoke_args_data: Vec = args + .as_ref() + .iter() + .cloned() + .map(sp_wasm_interface::Value::from) + .collect::>() + .encode(); + + let state = self.state; + + // Move serialized arguments inside the memory, invoke dispatch thunk and + // then free allocated memory. + let invoke_args_len = invoke_args_data.len() as WordSize; + let invoke_args_ptr = sandbox_context + .supervisor_context() + .allocate_memory(invoke_args_len) + .map_err(|_| trap("Can't allocate memory in supervisor for the arguments"))?; + + let deallocate = |supervisor_context: &mut dyn FunctionContext, ptr, fail_msg| { + supervisor_context.deallocate_memory(ptr).map_err(|_| trap(fail_msg)) + }; + + if sandbox_context + .supervisor_context() + .write_memory(invoke_args_ptr, &invoke_args_data) + .is_err() + { + deallocate( + sandbox_context.supervisor_context(), + invoke_args_ptr, + "Failed dealloction after failed write of invoke arguments", + )?; + return Err(trap("Can't write invoke args into memory")) + } + + let result = sandbox_context.invoke( + invoke_args_ptr, + invoke_args_len, + state, + func_idx, + ); + + deallocate( + sandbox_context.supervisor_context(), + invoke_args_ptr, + "Can't deallocate memory for dispatch thunk's invoke arguments", + )?; + let result = result?; + + // dispatch_thunk returns pointer to serialized arguments. + // Unpack pointer and len of the serialized result data. + let (serialized_result_val_ptr, serialized_result_val_len) = { + // Cast to u64 to use zero-extension. + let v = result as u64; + let ptr = (v as u64 >> 32) as u32; + let len = (v & 0xFFFFFFFF) as u32; + (Pointer::new(ptr), len) + }; + + let serialized_result_val = sandbox_context + .supervisor_context() + .read_memory(serialized_result_val_ptr, serialized_result_val_len) + .map_err(|_| trap("Can't read the serialized result from dispatch thunk")); + + deallocate( + sandbox_context.supervisor_context(), + serialized_result_val_ptr, + "Can't deallocate memory for dispatch thunk's result", + ) + .and_then(|_| serialized_result_val) + .and_then(|serialized_result_val| { + let result_val = std::result::Result::::decode(&mut serialized_result_val.as_slice()) + .map_err(|_| trap("Decoding Result failed!"))?; + + match result_val { + Ok(return_value) => Ok(match return_value { + ReturnValue::Unit => None, + ReturnValue::Value(typed_value) => Some(RuntimeValue::from(typed_value)), + }), + Err(HostError) => Err(trap("Supervisor function returned sandbox::HostError")), + } + }) + }).expect("SandboxContextStore is set when invoking sandboxed functions; qed") + } +} + +fn with_guest_externals(sandbox_instance: &SandboxInstance, state: u32, f: F) -> R +where + F: FnOnce(&mut GuestExternals) -> R, +{ + f(&mut GuestExternals { sandbox_instance, state }) +} + +/// Instantiate a module within a sandbox context +pub fn instantiate( + wasm: &[u8], + guest_env: GuestEnvironment, + state: u32, + sandbox_context: &mut dyn SandboxContext, +) -> std::result::Result, InstantiationError> { + let wasmi_module = Module::from_buffer(wasm).map_err(|_| InstantiationError::ModuleDecoding)?; + let wasmi_instance = ModuleInstance::new(&wasmi_module, &guest_env.imports) + .map_err(|_| InstantiationError::Instantiation)?; + + let sandbox_instance = Rc::new(SandboxInstance { + // In general, it's not a very good idea to use `.not_started_instance()` for + // anything but for extracting memory and tables. But in this particular case, we + // are extracting for the purpose of running `start` function which should be ok. + backend_instance: BackendInstance::Wasmi(wasmi_instance.not_started_instance().clone()), + guest_to_supervisor_mapping: guest_env.guest_to_supervisor_mapping, + }); + + with_guest_externals(&sandbox_instance, state, |guest_externals| { + SandboxContextStore::using(sandbox_context, || { + wasmi_instance + .run_start(guest_externals) + .map_err(|_| InstantiationError::StartTrapped) + }) + })?; + + Ok(sandbox_instance) +} + +/// Invoke a function within a sandboxed module +pub fn invoke( + instance: &SandboxInstance, + module: &wasmi::ModuleRef, + export_name: &str, + args: &[Value], + state: u32, + sandbox_context: &mut dyn SandboxContext, +) -> std::result::Result, error::Error> { + with_guest_externals(instance, state, |guest_externals| { + SandboxContextStore::using(sandbox_context, || { + let args = args.iter().cloned().map(Into::into).collect::>(); + + module + .invoke_export(export_name, &args, guest_externals) + .map(|result| result.map(Into::into)) + .map_err(|error| error::Error::Sandbox(error.to_string())) + }) + }) +} diff --git a/client/executor/common/src/util.rs b/client/executor/common/src/util.rs index eddf4230504c7..fbae01b556fb1 100644 --- a/client/executor/common/src/util.rs +++ b/client/executor/common/src/util.rs @@ -18,7 +18,7 @@ //! Utilities used by all backends -use crate::error::{Error, Result}; +use crate::error::Result; use sp_wasm_interface::Pointer; use std::ops::Range; @@ -50,192 +50,3 @@ pub trait MemoryTransfer { /// Returns an error if the write would go out of the memory bounds. fn write_from(&self, dest_addr: Pointer, source: &[u8]) -> Result<()>; } - -/// Safe wrapper over wasmi memory reference -pub mod wasmi { - use super::*; - - /// Wasmi provides direct access to its memory using slices. - /// - /// This wrapper limits the scope where the slice can be taken to - #[derive(Debug, Clone)] - pub struct MemoryWrapper(::wasmi::MemoryRef); - - impl MemoryWrapper { - /// Take ownership of the memory region and return a wrapper object - pub fn new(memory: ::wasmi::MemoryRef) -> Self { - Self(memory) - } - - /// Clone the underlying memory object - /// - /// # Safety - /// - /// The sole purpose of `MemoryRef` is to protect the memory from uncontrolled - /// access. By returning the memory object "as is" we bypass all of the checks. - /// - /// Intended to use only during module initialization. - pub unsafe fn clone_inner(&self) -> ::wasmi::MemoryRef { - self.0.clone() - } - } - - impl super::MemoryTransfer for MemoryWrapper { - fn read(&self, source_addr: Pointer, size: usize) -> Result> { - self.0.with_direct_access(|source| { - let range = checked_range(source_addr.into(), size, source.len()) - .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; - - Ok(Vec::from(&source[range])) - }) - } - - fn read_into(&self, source_addr: Pointer, destination: &mut [u8]) -> Result<()> { - self.0.with_direct_access(|source| { - let range = checked_range(source_addr.into(), destination.len(), source.len()) - .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; - - destination.copy_from_slice(&source[range]); - Ok(()) - }) - } - - fn write_from(&self, dest_addr: Pointer, source: &[u8]) -> Result<()> { - self.0.with_direct_access_mut(|destination| { - let range = checked_range(dest_addr.into(), source.len(), destination.len()) - .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; - - destination[range].copy_from_slice(source); - Ok(()) - }) - } - } -} - -// Routines specific to Wasmer runtime. Since sandbox can be invoked from both -/// wasmi and wasmtime runtime executors, we need to have a way to deal with sanbox -/// backends right from the start. -#[cfg(feature = "wasmer-sandbox")] -pub mod wasmer { - use super::checked_range; - use crate::error::{Error, Result}; - use sp_wasm_interface::Pointer; - use std::{cell::RefCell, convert::TryInto, rc::Rc}; - - /// In order to enforce memory access protocol to the backend memory - /// we wrap it with `RefCell` and encapsulate all memory operations. - #[derive(Debug, Clone)] - pub struct MemoryWrapper { - buffer: Rc>, - } - - impl MemoryWrapper { - /// Take ownership of the memory region and return a wrapper object - pub fn new(memory: wasmer::Memory) -> Self { - Self { buffer: Rc::new(RefCell::new(memory)) } - } - - /// Returns linear memory of the wasm instance as a slice. - /// - /// # Safety - /// - /// Wasmer doesn't provide comprehensive documentation about the exact behavior of the data - /// pointer. If a dynamic style heap is used the base pointer of the heap can change. Since - /// growing, we cannot guarantee the lifetime of the returned slice reference. - unsafe fn memory_as_slice(memory: &wasmer::Memory) -> &[u8] { - let ptr = memory.data_ptr() as *const _; - let len: usize = - memory.data_size().try_into().expect("data size should fit into usize"); - - if len == 0 { - &[] - } else { - core::slice::from_raw_parts(ptr, len) - } - } - - /// Returns linear memory of the wasm instance as a slice. - /// - /// # Safety - /// - /// See `[memory_as_slice]`. In addition to those requirements, since a mutable reference is - /// returned it must be ensured that only one mutable and no shared references to memory - /// exists at the same time. - unsafe fn memory_as_slice_mut(memory: &wasmer::Memory) -> &mut [u8] { - let ptr = memory.data_ptr(); - let len: usize = - memory.data_size().try_into().expect("data size should fit into usize"); - - if len == 0 { - &mut [] - } else { - core::slice::from_raw_parts_mut(ptr, len) - } - } - - /// Clone the underlying memory object - /// - /// # Safety - /// - /// The sole purpose of `MemoryRef` is to protect the memory from uncontrolled - /// access. By returning the memory object "as is" we bypass all of the checks. - /// - /// Intended to use only during module initialization. - /// - /// # Panics - /// - /// Will panic if `MemoryRef` is currently in use. - pub unsafe fn clone_inner(&mut self) -> wasmer::Memory { - // We take exclusive lock to ensure that we're the only one here - self.buffer.borrow_mut().clone() - } - } - - impl super::MemoryTransfer for MemoryWrapper { - fn read(&self, source_addr: Pointer, size: usize) -> Result> { - let memory = self.buffer.borrow(); - - let data_size = memory.data_size().try_into().expect("data size does not fit"); - - let range = checked_range(source_addr.into(), size, data_size) - .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; - - let mut buffer = vec![0; range.len()]; - self.read_into(source_addr, &mut buffer)?; - - Ok(buffer) - } - - fn read_into(&self, source_addr: Pointer, destination: &mut [u8]) -> Result<()> { - unsafe { - let memory = self.buffer.borrow(); - - // This should be safe since we don't grow up memory while caching this reference - // and we give up the reference before returning from this function. - let source = Self::memory_as_slice(&memory); - - let range = checked_range(source_addr.into(), destination.len(), source.len()) - .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; - - destination.copy_from_slice(&source[range]); - Ok(()) - } - } - - fn write_from(&self, dest_addr: Pointer, source: &[u8]) -> Result<()> { - unsafe { - let memory = self.buffer.borrow_mut(); - - // This should be safe since we don't grow up memory while caching this reference - // and we give up the reference before returning from this function. - let destination = Self::memory_as_slice_mut(&memory); - - let range = checked_range(dest_addr.into(), source.len(), destination.len()) - .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; - - destination[range].copy_from_slice(source); - Ok(()) - } - } - } -} diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index f0488972daca9..97c73c3454a4b 100644 --- a/client/executor/wasmi/src/lib.rs +++ b/client/executor/wasmi/src/lib.rs @@ -102,10 +102,7 @@ impl<'a> sandbox::SandboxContext for SandboxContext<'a> { match result { Ok(Some(RuntimeValue::I64(val))) => Ok(val), Ok(_) => return Err("Supervisor function returned unexpected result!".into()), - Err(err) => Err(Error::AbortedDueToTrap(MessageWithBacktrace { - message: err.to_string(), - backtrace: None, - })), + Err(err) => Err(Error::Sandbox(err.to_string())), } } @@ -222,7 +219,6 @@ impl Sandbox for FunctionExecutor { let args = Vec::::decode(&mut args) .map_err(|_| "Can't decode serialized arguments for the invocation")? .into_iter() - .map(Into::into) .collect::>(); let instance = diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index b310ada24b629..23deacbf93623 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -221,7 +221,6 @@ impl<'a> Sandbox for HostContext<'a> { let args = Vec::::decode(&mut args) .map_err(|_| "Can't decode serialized arguments for the invocation")? .into_iter() - .map(Into::into) .collect::>(); let instance = self.sandbox_store().instance(instance_id).map_err(|e| e.to_string())?; From 1986d9a10a2cbf697ea24ed966305f88e156edd5 Mon Sep 17 00:00:00 2001 From: Antonio Yang Date: Fri, 11 Feb 2022 17:14:13 +0800 Subject: [PATCH 0505/1472] Show Network ID when creating and inspecting (#10838) Signed-off-by: Antonio Yang --- client/cli/src/commands/utils.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/client/cli/src/commands/utils.rs b/client/cli/src/commands/utils.rs index 7f0413f596012..d20df01e5a90e 100644 --- a/client/cli/src/commands/utils.rs +++ b/client/cli/src/commands/utils.rs @@ -73,6 +73,7 @@ pub fn print_from_uri( Pair::Public: Into, { let password = password.as_ref().map(|s| s.expose_secret().as_str()); + let network_id = String::from(unwrap_or_default_ss58_version(network_override)); if let Ok((pair, seed)) = Pair::from_phrase(uri, password.clone()) { let public_key = pair.public(); let network_override = unwrap_or_default_ss58_version(network_override); @@ -81,6 +82,7 @@ pub fn print_from_uri( OutputType::Json => { let json = json!({ "secretPhrase": uri, + "networkId": network_id, "secretSeed": format_seed::(seed), "publicKey": format_public_key::(public_key.clone()), "ss58PublicKey": public_key.to_ss58check_with_version(network_override), @@ -95,12 +97,14 @@ pub fn print_from_uri( OutputType::Text => { println!( "Secret phrase: {}\n \ + Network ID: {}\n \ Secret seed: {}\n \ Public key (hex): {}\n \ Account ID: {}\n \ Public key (SS58): {}\n \ SS58 Address: {}", uri, + network_id, format_seed::(seed), format_public_key::(public_key.clone()), format_account_id::(public_key.clone()), @@ -117,6 +121,7 @@ pub fn print_from_uri( OutputType::Json => { let json = json!({ "secretKeyUri": uri, + "networkId": network_id, "secretSeed": if let Some(seed) = seed { format_seed::(seed) } else { "n/a".into() }, "publicKey": format_public_key::(public_key.clone()), "ss58PublicKey": public_key.to_ss58check_with_version(network_override), @@ -131,12 +136,14 @@ pub fn print_from_uri( OutputType::Text => { println!( "Secret Key URI `{}` is account:\n \ + Network ID: {} \n \ Secret seed: {}\n \ Public key (hex): {}\n \ Account ID: {}\n \ Public key (SS58): {}\n \ SS58 Address: {}", uri, + network_id, if let Some(seed) = seed { format_seed::(seed) } else { "n/a".into() }, format_public_key::(public_key.clone()), format_account_id::(public_key.clone()), @@ -167,7 +174,7 @@ pub fn print_from_uri( OutputType::Text => { println!( "Public Key URI `{}` is account:\n \ - Network ID/version: {}\n \ + Network ID/Version: {}\n \ Public key (hex): {}\n \ Account ID: {}\n \ Public key (SS58): {}\n \ @@ -217,7 +224,7 @@ where }, OutputType::Text => { println!( - "Network ID/version: {}\n \ + "Network ID/Version: {}\n \ Public key (hex): {}\n \ Account ID: {}\n \ Public key (SS58): {}\n \ From c3ebcf1cf05349e748d2c6d45479e12cf803e71a Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 11 Feb 2022 20:35:35 +0900 Subject: [PATCH 0506/1472] Reduce overhead of generating network event metrics (#10839) --- client/network/src/service/out_events.rs | 62 +++++++++++++++++------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 5f088b85b1cfc..1fe13bc30faff 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -37,6 +37,7 @@ use futures::{channel::mpsc, prelude::*, ready, stream::FusedStream}; use parking_lot::Mutex; use prometheus_endpoint::{register, CounterVec, GaugeVec, Opts, PrometheusError, Registry, U64}; use std::{ + cell::RefCell, convert::TryFrom as _, fmt, pin::Pin, @@ -187,6 +188,23 @@ struct Metrics { num_channels: GaugeVec, } +thread_local! { + static LABEL_BUFFER: RefCell = RefCell::new(String::new()); +} + +fn format_label(prefix: &str, protocol: &str, callback: impl FnOnce(&str)) { + LABEL_BUFFER.with(|label_buffer| { + let mut label_buffer = label_buffer.borrow_mut(); + label_buffer.clear(); + label_buffer.reserve(prefix.len() + protocol.len() + 2); + label_buffer.push_str(prefix); + label_buffer.push_str("\""); + label_buffer.push_str(protocol); + label_buffer.push_str("\""); + callback(&label_buffer); + }); +} + impl Metrics { fn register(registry: &Registry) -> Result { Ok(Self { @@ -232,20 +250,26 @@ impl Metrics { .inc_by(num); }, Event::NotificationStreamOpened { protocol, .. } => { - self.events_total - .with_label_values(&[&format!("notif-open-{:?}", protocol), "sent", name]) - .inc_by(num); + format_label("notif-open-", &protocol, |protocol_label| { + self.events_total + .with_label_values(&[protocol_label, "sent", name]) + .inc_by(num); + }); }, Event::NotificationStreamClosed { protocol, .. } => { - self.events_total - .with_label_values(&[&format!("notif-closed-{:?}", protocol), "sent", name]) - .inc_by(num); + format_label("notif-closed-", &protocol, |protocol_label| { + self.events_total + .with_label_values(&[protocol_label, "sent", name]) + .inc_by(num); + }); }, Event::NotificationsReceived { messages, .. } => for (protocol, message) in messages { - self.events_total - .with_label_values(&[&format!("notif-{:?}", protocol), "sent", name]) - .inc_by(num); + format_label("notif-", &protocol, |protocol_label| { + self.events_total + .with_label_values(&[protocol_label, "sent", name]) + .inc_by(num); + }); self.notifications_sizes.with_label_values(&[protocol, "sent", name]).inc_by( num.saturating_mul(u64::try_from(message.len()).unwrap_or(u64::MAX)), ); @@ -267,20 +291,22 @@ impl Metrics { .inc(); }, Event::NotificationStreamOpened { protocol, .. } => { - self.events_total - .with_label_values(&[&format!("notif-open-{:?}", protocol), "received", name]) - .inc(); + format_label("notif-open-", &protocol, |protocol_label| { + self.events_total.with_label_values(&[protocol_label, "received", name]).inc(); + }); }, Event::NotificationStreamClosed { protocol, .. } => { - self.events_total - .with_label_values(&[&format!("notif-closed-{:?}", protocol), "received", name]) - .inc(); + format_label("notif-closed-", &protocol, |protocol_label| { + self.events_total.with_label_values(&[protocol_label, "received", name]).inc(); + }); }, Event::NotificationsReceived { messages, .. } => for (protocol, message) in messages { - self.events_total - .with_label_values(&[&format!("notif-{:?}", protocol), "received", name]) - .inc(); + format_label("notif-", &protocol, |protocol_label| { + self.events_total + .with_label_values(&[protocol_label, "received", name]) + .inc(); + }); self.notifications_sizes .with_label_values(&[&protocol, "received", name]) .inc_by(u64::try_from(message.len()).unwrap_or(u64::MAX)); From a9020646e784170050a4e6324dd067ab0e5af448 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 11 Feb 2022 14:17:38 +0100 Subject: [PATCH 0507/1472] Fix reentrancy of FrozenBalance::died hook (#10473) * assets: execute `died` hook outside of mutate Signed-off-by: Oliver Tale-Yazdi * assets: extend tests for `died` hook Signed-off-by: Oliver Tale-Yazdi * assets: update doc of FrozenBalance::died Signed-off-by: Oliver Tale-Yazdi * assets: review fixes - fix cases where `died` should not have been called - use `Option` instead of `DeadConsequence` Signed-off-by: Oliver Tale-Yazdi * assets: update comment in mock.rs Signed-off-by: Oliver Tale-Yazdi * assets: return `Remove` in dead_account The return value is ignored in the only case that it is produced by a call, but having it this way makes it more understandable. Signed-off-by: Oliver Tale-Yazdi --- frame/assets/src/functions.rs | 136 ++++++++++++++++++++++------------ frame/assets/src/mock.rs | 10 +++ frame/assets/src/tests.rs | 47 ++++++++++++ frame/assets/src/types.rs | 8 +- 4 files changed, 148 insertions(+), 53 deletions(-) diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index 73804fc832c99..48a86ca3cfa04 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -84,13 +84,11 @@ impl, I: 'static> Pallet { } pub(super) fn dead_account( - what: T::AssetId, who: &T::AccountId, d: &mut AssetDetails>, reason: &ExistenceReason>, force: bool, ) -> DeadConsequence { - let mut result = Remove; match *reason { ExistenceReason::Consumer => frame_system::Pallet::::dec_consumers(who), ExistenceReason::Sufficient => { @@ -99,11 +97,10 @@ impl, I: 'static> Pallet { }, ExistenceReason::DepositRefunded => {}, ExistenceReason::DepositHeld(_) if !force => return Keep, - ExistenceReason::DepositHeld(_) => result = Keep, + ExistenceReason::DepositHeld(_) => {}, } d.accounts = d.accounts.saturating_sub(1); - T::Freezer::died(what, who); - result + Remove } pub(super) fn can_increase( @@ -323,12 +320,14 @@ impl, I: 'static> Pallet { T::Currency::unreserve(&who, deposit); - if let Remove = Self::dead_account(id, &who, &mut details, &account.reason, false) { + if let Remove = Self::dead_account(&who, &mut details, &account.reason, false) { Account::::remove(id, &who); } else { debug_assert!(false, "refund did not result in dead account?!"); } Asset::::insert(&id, details); + // Executing a hook here is safe, since it is not in a `mutate`. + T::Freezer::died(id, &who); Ok(()) } @@ -461,6 +460,7 @@ impl, I: 'static> Pallet { } let actual = Self::prep_debit(id, target, amount, f)?; + let mut target_died: Option = None; Asset::::try_mutate(id, |maybe_details| -> DispatchResult { let mut details = maybe_details.as_mut().ok_or(Error::::Unknown)?; @@ -475,9 +475,9 @@ impl, I: 'static> Pallet { account.balance = account.balance.saturating_sub(actual); if account.balance < details.min_balance { debug_assert!(account.balance.is_zero(), "checked in prep; qed"); - if let Remove = - Self::dead_account(id, target, &mut details, &account.reason, false) - { + target_died = + Some(Self::dead_account(target, &mut details, &account.reason, false)); + if let Some(Remove) = target_died { return Ok(()) } }; @@ -488,6 +488,10 @@ impl, I: 'static> Pallet { Ok(()) })?; + // Execute hook outside of `mutate`. + if let Some(Remove) = target_died { + T::Freezer::died(id, target); + } Ok(actual) } @@ -507,6 +511,24 @@ impl, I: 'static> Pallet { maybe_need_admin: Option, f: TransferFlags, ) -> Result { + let (balance, died) = + Self::transfer_and_die(id, source, dest, amount, maybe_need_admin, f)?; + if let Some(Remove) = died { + T::Freezer::died(id, source); + } + Ok(balance) + } + + /// Same as `do_transfer` but it does not execute the `FrozenBalance::died` hook and + /// instead returns whether and how the `source` account died in this operation. + fn transfer_and_die( + id: T::AssetId, + source: &T::AccountId, + dest: &T::AccountId, + amount: T::Balance, + maybe_need_admin: Option, + f: TransferFlags, + ) -> Result<(T::Balance, Option), DispatchError> { // Early exist if no-op. if amount.is_zero() { Self::deposit_event(Event::Transferred { @@ -515,7 +537,7 @@ impl, I: 'static> Pallet { to: dest.clone(), amount, }); - return Ok(amount) + return Ok((amount, None)) } // Figure out the debit and credit, together with side-effects. @@ -524,6 +546,7 @@ impl, I: 'static> Pallet { let mut source_account = Account::::get(id, &source).ok_or(Error::::NoAccount)?; + let mut source_died: Option = None; Asset::::try_mutate(id, |maybe_details| -> DispatchResult { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; @@ -576,9 +599,9 @@ impl, I: 'static> Pallet { // Remove source account if it's now dead. if source_account.balance < details.min_balance { debug_assert!(source_account.balance.is_zero(), "checked in prep; qed"); - if let Remove = - Self::dead_account(id, &source, details, &source_account.reason, false) - { + source_died = + Some(Self::dead_account(&source, details, &source_account.reason, false)); + if let Some(Remove) = source_died { Account::::remove(id, &source); return Ok(()) } @@ -593,7 +616,7 @@ impl, I: 'static> Pallet { to: dest.clone(), amount: credit, }); - Ok(credit) + Ok((credit, source_died)) } /// Create a new asset without taking a deposit. @@ -646,41 +669,53 @@ impl, I: 'static> Pallet { witness: DestroyWitness, maybe_check_owner: Option, ) -> Result { - Asset::::try_mutate_exists(id, |maybe_details| { - let mut details = maybe_details.take().ok_or(Error::::Unknown)?; - if let Some(check_owner) = maybe_check_owner { - ensure!(details.owner == check_owner, Error::::NoPermission); - } - ensure!(details.accounts <= witness.accounts, Error::::BadWitness); - ensure!(details.sufficients <= witness.sufficients, Error::::BadWitness); - ensure!(details.approvals <= witness.approvals, Error::::BadWitness); - - for (who, v) in Account::::drain_prefix(id) { - // We have to force this as it's destroying the entire asset class. - // This could mean that some accounts now have irreversibly reserved - // funds. - let _ = Self::dead_account(id, &who, &mut details, &v.reason, true); - } - debug_assert_eq!(details.accounts, 0); - debug_assert_eq!(details.sufficients, 0); + let mut dead_accounts: Vec = vec![]; - let metadata = Metadata::::take(&id); - T::Currency::unreserve( - &details.owner, - details.deposit.saturating_add(metadata.deposit), - ); + let result_witness: DestroyWitness = Asset::::try_mutate_exists( + id, + |maybe_details| -> Result { + let mut details = maybe_details.take().ok_or(Error::::Unknown)?; + if let Some(check_owner) = maybe_check_owner { + ensure!(details.owner == check_owner, Error::::NoPermission); + } + ensure!(details.accounts <= witness.accounts, Error::::BadWitness); + ensure!(details.sufficients <= witness.sufficients, Error::::BadWitness); + ensure!(details.approvals <= witness.approvals, Error::::BadWitness); + + for (who, v) in Account::::drain_prefix(id) { + // We have to force this as it's destroying the entire asset class. + // This could mean that some accounts now have irreversibly reserved + // funds. + let _ = Self::dead_account(&who, &mut details, &v.reason, true); + dead_accounts.push(who); + } + debug_assert_eq!(details.accounts, 0); + debug_assert_eq!(details.sufficients, 0); - for ((owner, _), approval) in Approvals::::drain_prefix((&id,)) { - T::Currency::unreserve(&owner, approval.deposit); - } - Self::deposit_event(Event::Destroyed { asset_id: id }); + let metadata = Metadata::::take(&id); + T::Currency::unreserve( + &details.owner, + details.deposit.saturating_add(metadata.deposit), + ); - Ok(DestroyWitness { - accounts: details.accounts, - sufficients: details.sufficients, - approvals: details.approvals, - }) - }) + for ((owner, _), approval) in Approvals::::drain_prefix((&id,)) { + T::Currency::unreserve(&owner, approval.deposit); + } + Self::deposit_event(Event::Destroyed { asset_id: id }); + + Ok(DestroyWitness { + accounts: details.accounts, + sufficients: details.sufficients, + approvals: details.approvals, + }) + }, + )?; + + // Execute hooks outside of `mutate`. + for who in dead_accounts { + T::Freezer::died(id, &who); + } + Ok(result_witness) } /// Creates an approval from `owner` to spend `amount` of asset `id` tokens by 'delegate' @@ -742,6 +777,8 @@ impl, I: 'static> Pallet { destination: &T::AccountId, amount: T::Balance, ) -> DispatchResult { + let mut owner_died: Option = None; + Approvals::::try_mutate_exists( (id, &owner, delegate), |maybe_approved| -> DispatchResult { @@ -750,7 +787,7 @@ impl, I: 'static> Pallet { approved.amount.checked_sub(&amount).ok_or(Error::::Unapproved)?; let f = TransferFlags { keep_alive: false, best_effort: false, burn_dust: false }; - Self::do_transfer(id, &owner, &destination, amount, None, f)?; + owner_died = Self::transfer_and_die(id, &owner, &destination, amount, None, f)?.1; if remaining.is_zero() { T::Currency::unreserve(&owner, approved.deposit); @@ -766,6 +803,11 @@ impl, I: 'static> Pallet { Ok(()) }, )?; + + // Execute hook outside of `mutate`. + if let Some(Remove) = owner_died { + T::Freezer::died(id, owner); + } Ok(()) } diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 34a4cf9ef38f6..67690e2b28ec1 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -120,19 +120,27 @@ impl FrozenBalance for TestFreezer { fn died(asset: u32, who: &u64) { HOOKS.with(|h| h.borrow_mut().push(Hook::Died(asset, who.clone()))); + // Sanity check: dead accounts have no balance. + assert!(Assets::balance(asset, *who).is_zero()); } } pub(crate) fn set_frozen_balance(asset: u32, who: u64, amount: u64) { FROZEN.with(|f| f.borrow_mut().insert((asset, who), amount)); } + pub(crate) fn clear_frozen_balance(asset: u32, who: u64) { FROZEN.with(|f| f.borrow_mut().remove(&(asset, who))); } + pub(crate) fn hooks() -> Vec { HOOKS.with(|h| h.borrow().clone()) } +pub(crate) fn take_hooks() -> Vec { + HOOKS.with(|h| h.take()) +} + pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); @@ -154,6 +162,8 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { config.assimilate_storage(&mut storage).unwrap(); let mut ext: sp_io::TestExternalities = storage.into(); + // Clear thread local vars for https://github.com/paritytech/substrate/issues/10479. + ext.execute_with(|| take_hooks()); ext.execute_with(|| System::set_block_number(1)); ext } diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index a9f4dafc910c0..7430b742e7d2a 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -125,6 +125,21 @@ fn refunding_asset_deposit_without_burn_should_work() { }); } +/// Refunding reaps an account and calls the `FrozenBalance::died` hook. +#[test] +fn refunding_calls_died_hook() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::touch(Origin::signed(1), 0)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::refund(Origin::signed(1), 0, true)); + + assert_eq!(Asset::::get(0).unwrap().accounts, 0); + assert_eq!(hooks(), vec![Hook::Died(0, 1)]); + }); +} + #[test] fn approval_lifecycle_works() { new_test_ext().execute_with(|| { @@ -389,19 +404,32 @@ fn min_balance_should_work() { ); // When deducting from an account to below minimum, it should be reaped. + // Death by `transfer`. assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 91)); assert!(Assets::maybe_balance(0, 1).is_none()); assert_eq!(Assets::balance(0, 2), 100); assert_eq!(Asset::::get(0).unwrap().accounts, 1); + assert_eq!(take_hooks(), vec![Hook::Died(0, 1)]); + // Death by `force_transfer`. assert_ok!(Assets::force_transfer(Origin::signed(1), 0, 2, 1, 91)); assert!(Assets::maybe_balance(0, 2).is_none()); assert_eq!(Assets::balance(0, 1), 100); assert_eq!(Asset::::get(0).unwrap().accounts, 1); + assert_eq!(take_hooks(), vec![Hook::Died(0, 2)]); + // Death by `burn`. assert_ok!(Assets::burn(Origin::signed(1), 0, 1, 91)); assert!(Assets::maybe_balance(0, 1).is_none()); assert_eq!(Asset::::get(0).unwrap().accounts, 0); + assert_eq!(take_hooks(), vec![Hook::Died(0, 1)]); + + // Death by `transfer_approved`. + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + Balances::make_free_balance_be(&1, 1); + assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 91)); + assert_eq!(take_hooks(), vec![Hook::Died(0, 1)]); }); } @@ -448,6 +476,7 @@ fn transferring_enough_to_kill_source_when_keep_alive_should_fail() { assert_ok!(Assets::transfer_keep_alive(Origin::signed(1), 0, 2, 90)); assert_eq!(Assets::balance(0, 1), 10); assert_eq!(Assets::balance(0, 2), 90); + assert!(hooks().is_empty()); }); } @@ -684,6 +713,24 @@ fn set_metadata_should_work() { }); } +/// Destroying an asset calls the `FrozenBalance::died` hooks of all accounts. +#[test] +fn destroy_calls_died_hooks() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 50)); + // Create account 1 and 2. + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 2, 100)); + // Destroy the asset. + let w = Asset::::get(0).unwrap().destroy_witness(); + assert_ok!(Assets::destroy(Origin::signed(1), 0, w)); + + // Asset is gone and accounts 1 and 2 died. + assert!(Asset::::get(0).is_none()); + assert_eq!(hooks(), vec![Hook::Died(0, 1), Hook::Died(0, 2)]); + }) +} + #[test] fn freezer_should_work() { new_test_ext().execute_with(|| { diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index f8172e0a4a51b..56034e59086b9 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -172,13 +172,9 @@ pub trait FrozenBalance { /// If `None` is returned, then nothing special is enforced. fn frozen_balance(asset: AssetId, who: &AccountId) -> Option; - /// Called when an account has been removed. + /// Called after an account has been removed. /// - /// # Warning - /// - /// This function must never access storage of pallet asset. This function is called while some - /// change are pending. Calling into the pallet asset in this function can result in unexpected - /// state. + /// NOTE: It is possible that the asset does no longer exist when this hook is called. fn died(asset: AssetId, who: &AccountId); } From 22ed351d86b3b04ca1df82fb0036c6376bf1fea0 Mon Sep 17 00:00:00 2001 From: Tarekk Mohamed Abdalla Date: Fri, 11 Feb 2022 16:38:58 +0200 Subject: [PATCH 0508/1472] allow trailing comma (#10841) --- primitives/std/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/primitives/std/src/lib.rs b/primitives/std/src/lib.rs index 6a59dcbe49299..03a079e3965f4 100644 --- a/primitives/std/src/lib.rs +++ b/primitives/std/src/lib.rs @@ -28,9 +28,13 @@ doc = "Substrate's runtime standard library as compiled without Rust's standard library." )] +/// Initialize a key-value collection from array. +/// +/// Creates a vector of given pairs and calls `collect` on the iterator from it. +/// Can be used to create a `HashMap`. #[macro_export] macro_rules! map { - ($( $name:expr => $value:expr ),*) => ( + ($( $name:expr => $value:expr ),* $(,)? ) => ( vec![ $( ( $name, $value ) ),* ].into_iter().collect() ) } From 66b9c363c617d04ef3fba32d06419eb2bbe3c874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Fri, 11 Feb 2022 19:38:39 +0000 Subject: [PATCH 0509/1472] build-script-utils: allow reading the git commit hash from env var (#10845) * build-script-utils: allow reading the git commit hash from env var * build-script-utils: make the env var name substrate specific --- utils/build-script-utils/src/version.rs | 32 +++++++++++++------------ 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/utils/build-script-utils/src/version.rs b/utils/build-script-utils/src/version.rs index e4f1be93cbccb..773949e30d8d4 100644 --- a/utils/build-script-utils/src/version.rs +++ b/utils/build-script-utils/src/version.rs @@ -20,21 +20,23 @@ use std::{borrow::Cow, process::Command}; /// Generate the `cargo:` key output pub fn generate_cargo_keys() { - let output = Command::new("git").args(&["rev-parse", "--short", "HEAD"]).output(); - - let commit = match output { - Ok(o) if o.status.success() => { - let sha = String::from_utf8_lossy(&o.stdout).trim().to_owned(); - Cow::from(sha) - }, - Ok(o) => { - println!("cargo:warning=Git command failed with status: {}", o.status); - Cow::from("unknown") - }, - Err(err) => { - println!("cargo:warning=Failed to execute git command: {}", err); - Cow::from("unknown") - }, + let commit = if let Ok(hash) = std::env::var("SUBSTRATE_CLI_GIT_COMMIT_HASH") { + Cow::from(hash.trim().to_owned()) + } else { + match Command::new("git").args(&["rev-parse", "--short", "HEAD"]).output() { + Ok(o) if o.status.success() => { + let sha = String::from_utf8_lossy(&o.stdout).trim().to_owned(); + Cow::from(sha) + }, + Ok(o) => { + println!("cargo:warning=Git command failed with status: {}", o.status); + Cow::from("unknown") + }, + Err(err) => { + println!("cargo:warning=Failed to execute git command: {}", err); + Cow::from("unknown") + }, + } }; println!("cargo:rustc-env=SUBSTRATE_CLI_IMPL_VERSION={}", get_version(&commit)) From 0a92e3eeb6568cee34bcccdf34529f77db767c46 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 11 Feb 2022 22:28:10 +0100 Subject: [PATCH 0510/1472] Don't create DB leaves when syncing historic blocks (#10844) * Don't create DB leaves when syncing historic blocks * Changed leaves check and added test * fmt --- client/db/src/lib.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index d7550ff9aea17..a2d0cad72845f 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1472,7 +1472,8 @@ impl Backend { } if !existing_header { - { + // Add a new leaf if the block has the potential to be finalized. + if number > last_finalized_num || last_finalized_num.is_zero() { let mut leaves = self.blockchain.leaves.write(); leaves.import(hash, number, parent_hash); leaves.prepare_transaction( @@ -2330,6 +2331,29 @@ pub(crate) mod tests { Ok(header_hash) } + pub fn insert_header_no_head( + backend: &Backend, + number: u64, + parent_hash: H256, + extrinsics_root: H256, + ) -> H256 { + use sp_runtime::testing::Digest; + + let digest = Digest::default(); + let header = Header { + number, + parent_hash, + state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), + digest, + extrinsics_root, + }; + let header_hash = header.hash(); + let mut op = backend.begin_operation().unwrap(); + op.set_block_data(header, None, None, None, NewBlockState::Normal).unwrap(); + backend.commit_operation(op).unwrap(); + header_hash + } + #[test] fn block_hash_inserted_correctly() { let backing = { @@ -3309,4 +3333,19 @@ pub(crate) mod tests { e @ _ => panic!("Unexpected error {:?}", e), } } + + #[test] + fn test_leaves_not_created_for_ancient_blocks() { + let backend: Backend = Backend::new_test(10, 10); + let block0 = insert_header(&backend, 0, Default::default(), None, Default::default()); + + let block1_a = insert_header(&backend, 1, block0, None, Default::default()); + let block2_a = insert_header(&backend, 2, block1_a, None, Default::default()); + backend.finalize_block(BlockId::hash(block1_a), None).unwrap(); + assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a]); + + // Insert a fork prior to finalization point. Leave should not be created. + insert_header_no_head(&backend, 1, block0, [1; 32].into()); + assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a]); + } } From 2d8b02af1852d51b7d6a15d6d98b41b76bac614a Mon Sep 17 00:00:00 2001 From: S E R A Y A Date: Sun, 13 Feb 2022 23:14:32 +0100 Subject: [PATCH 0511/1472] fix broken link (#10846) --- frame/uniques/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/uniques/README.md b/frame/uniques/README.md index b924e338452ff..8d6859d55e23c 100644 --- a/frame/uniques/README.md +++ b/frame/uniques/README.md @@ -73,6 +73,6 @@ and its associated variants for documentation on each function. * [`System`](https://docs.rs/frame-system/latest/frame_system/) * [`Support`](https://docs.rs/frame-support/latest/frame_support/) -* [`Assets`](https://docs.rs/pallet-assets/latest/pallet_assetss/) +* [`Assets`](https://docs.rs/pallet-assets/latest/pallet_assets/) License: Apache-2.0 From 700218cacb44521885ab59ea17f5e7d0d2b8d5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 14 Feb 2022 20:31:52 +0100 Subject: [PATCH 0512/1472] subkey: Support `--version` cli command (#10853) * subkey: Support `--version` cli command * FMT :facepalm: --- bin/utils/subkey/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/utils/subkey/src/lib.rs b/bin/utils/subkey/src/lib.rs index 73698db0b7ea0..3731d9f3ec75c 100644 --- a/bin/utils/subkey/src/lib.rs +++ b/bin/utils/subkey/src/lib.rs @@ -26,7 +26,8 @@ use sc_cli::{ #[clap( name = "subkey", author = "Parity Team ", - about = "Utility for generating and restoring with Substrate keys" + about = "Utility for generating and restoring with Substrate keys", + version )] pub enum Subkey { /// Generate a random node libp2p key, save it to file or print it to stdout From 0ac1a00c54a65416ed44e4c779f1483e32355130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 14 Feb 2022 21:12:25 +0100 Subject: [PATCH 0513/1472] Remove `u32_trait` (#10850) * Remove `u32_trait` This trait only existed because there wasn't any const generic support at time of creation. However, we now have support for it :) * FMT --- bin/node/runtime/src/lib.rs | 30 +- frame/collective/src/lib.rs | 35 +- frame/collective/src/tests.rs | 7 +- .../traits/tokens/imbalance/split_two_ways.rs | 15 +- primitives/core/src/lib.rs | 2 - primitives/core/src/u32_trait.rs | 570 ------------------ 6 files changed, 39 insertions(+), 620 deletions(-) delete mode 100644 primitives/core/src/u32_trait.rs diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0a13b795919c0..0aff3d8046eef 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -53,11 +53,7 @@ pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdj use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; use sp_api::impl_runtime_apis; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; -use sp_core::{ - crypto::KeyTypeId, - u32_trait::{_1, _2, _3, _4, _5}, - OpaqueMetadata, -}; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{ create_runtime_str, @@ -550,7 +546,7 @@ impl pallet_staking::Config for Runtime { /// A super-majority of the council can cancel the slash. type SlashCancelOrigin = EnsureOneOf< EnsureRoot, - pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>, + pallet_collective::EnsureProportionAtLeast, >; type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; @@ -796,30 +792,30 @@ impl pallet_democracy::Config for Runtime { type MinimumDeposit = MinimumDeposit; /// A straight majority of the council can decide what their next motion is. type ExternalOrigin = - pallet_collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>; + pallet_collective::EnsureProportionAtLeast; /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. type ExternalMajorityOrigin = - pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>; + pallet_collective::EnsureProportionAtLeast; /// A unanimous council can have the next scheduled referendum be a straight default-carries /// (NTB) vote. type ExternalDefaultOrigin = - pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilCollective>; + pallet_collective::EnsureProportionAtLeast; /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote /// be tabled immediately and with a shorter voting/enactment period. type FastTrackOrigin = - pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>; + pallet_collective::EnsureProportionAtLeast; type InstantOrigin = - pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>; + pallet_collective::EnsureProportionAtLeast; type InstantAllowed = frame_support::traits::ConstBool; type FastTrackVotingPeriod = FastTrackVotingPeriod; // To cancel a proposal which has been passed, 2/3 of the council must agree to it. type CancellationOrigin = - pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilCollective>; + pallet_collective::EnsureProportionAtLeast; // To cancel a proposal before it has been passed, the technical committee must be unanimous or // Root must agree. type CancelProposalOrigin = EnsureOneOf< EnsureRoot, - pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>, + pallet_collective::EnsureProportionAtLeast, >; type BlacklistOrigin = EnsureRoot; // Any single technical committee member may veto a coming council proposal, however they can @@ -909,7 +905,7 @@ impl pallet_collective::Config for Runtime { type EnsureRootOrHalfCouncil = EnsureOneOf< EnsureRoot, - pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>, + pallet_collective::EnsureProportionMoreThan, >; impl pallet_membership::Config for Runtime { type Event = Event; @@ -951,11 +947,11 @@ impl pallet_treasury::Config for Runtime { type Currency = Balances; type ApproveOrigin = EnsureOneOf< EnsureRoot, - pallet_collective::EnsureProportionAtLeast<_3, _5, AccountId, CouncilCollective>, + pallet_collective::EnsureProportionAtLeast, >; type RejectOrigin = EnsureOneOf< EnsureRoot, - pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>, + pallet_collective::EnsureProportionMoreThan, >; type Event = Event; type OnSlash = (); @@ -1226,7 +1222,7 @@ impl pallet_society::Config for Runtime { type RotationPeriod = RotationPeriod; type MaxLockDuration = MaxLockDuration; type FounderSetOrigin = - pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; + pallet_collective::EnsureProportionMoreThan; type SuspensionJudgementOrigin = pallet_society::EnsureFounder; type MaxCandidateIntake = MaxCandidateIntake; type ChallengePeriod = ChallengePeriod; diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 49328aa0bdc68..e876343ec33da 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -43,7 +43,6 @@ #![recursion_limit = "128"] use scale_info::TypeInfo; -use sp_core::u32_trait::Value as U32; use sp_io::storage; use sp_runtime::{traits::Hash, RuntimeDebug}; use sp_std::{marker::PhantomData, prelude::*, result}; @@ -1011,43 +1010,43 @@ impl< } } -pub struct EnsureMembers(PhantomData<(N, AccountId, I)>); +pub struct EnsureMembers(PhantomData<(AccountId, I)>); impl< O: Into, O>> + From>, - N: U32, AccountId, I, - > EnsureOrigin for EnsureMembers + const N: u32, + > EnsureOrigin for EnsureMembers { type Success = (MemberCount, MemberCount); fn try_origin(o: O) -> Result { o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n >= N::VALUE => Ok((n, m)), + RawOrigin::Members(n, m) if n >= N => Ok((n, m)), r => Err(O::from(r)), }) } #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> O { - O::from(RawOrigin::Members(N::VALUE, N::VALUE)) + O::from(RawOrigin::Members(N, N)) } } -pub struct EnsureProportionMoreThan( - PhantomData<(N, D, AccountId, I)>, +pub struct EnsureProportionMoreThan( + PhantomData<(AccountId, I)>, ); impl< O: Into, O>> + From>, - N: U32, - D: U32, AccountId, I, - > EnsureOrigin for EnsureProportionMoreThan + const N: u32, + const D: u32, + > EnsureOrigin for EnsureProportionMoreThan { type Success = (); fn try_origin(o: O) -> Result { o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n * D::VALUE > N::VALUE * m => Ok(()), + RawOrigin::Members(n, m) if n * D > N * m => Ok(()), r => Err(O::from(r)), }) } @@ -1058,21 +1057,21 @@ impl< } } -pub struct EnsureProportionAtLeast( - PhantomData<(N, D, AccountId, I)>, +pub struct EnsureProportionAtLeast( + PhantomData<(AccountId, I)>, ); impl< O: Into, O>> + From>, - N: U32, - D: U32, AccountId, I, - > EnsureOrigin for EnsureProportionAtLeast + const N: u32, + const D: u32, + > EnsureOrigin for EnsureProportionAtLeast { type Success = (); fn try_origin(o: O) -> Result { o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n * D::VALUE >= N::VALUE * m => Ok(()), + RawOrigin::Members(n, m) if n * D >= N * m => Ok(()), r => Err(O::from(r)), }) } diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index f77e52a9b6fe9..a8abfb0c52358 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -24,10 +24,7 @@ use frame_support::{ Hashable, }; use frame_system::{EventRecord, Phase}; -use sp_core::{ - u32_trait::{_3, _4}, - H256, -}; +use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, @@ -142,7 +139,7 @@ impl Config for Test { } impl mock_democracy::Config for Test { type Event = Event; - type ExternalMajorityOrigin = EnsureProportionAtLeast<_3, _4, u64, Instance1>; + type ExternalMajorityOrigin = EnsureProportionAtLeast; } impl Config for Test { type Origin = Origin; diff --git a/frame/support/src/traits/tokens/imbalance/split_two_ways.rs b/frame/support/src/traits/tokens/imbalance/split_two_ways.rs index a5e42451d82eb..b963895af0de5 100644 --- a/frame/support/src/traits/tokens/imbalance/split_two_ways.rs +++ b/frame/support/src/traits/tokens/imbalance/split_two_ways.rs @@ -18,27 +18,26 @@ //! Means for splitting an imbalance into two and hanlding them differently. use super::super::imbalance::{Imbalance, OnUnbalanced}; -use sp_core::u32_trait::Value as U32; use sp_runtime::traits::Saturating; use sp_std::{marker::PhantomData, ops::Div}; /// Split an unbalanced amount two ways between a common divisor. -pub struct SplitTwoWays( - PhantomData<(Balance, Imbalance, Part1, Target1, Part2, Target2)>, +pub struct SplitTwoWays( + PhantomData<(Balance, Imbalance, Target1, Target2)>, ); impl< Balance: From + Saturating + Div, I: Imbalance, - Part1: U32, Target1: OnUnbalanced, - Part2: U32, Target2: OnUnbalanced, - > OnUnbalanced for SplitTwoWays + const PART1: u32, + const PART2: u32, + > OnUnbalanced for SplitTwoWays { fn on_nonzero_unbalanced(amount: I) { - let total: u32 = Part1::VALUE + Part2::VALUE; - let amount1 = amount.peek().saturating_mul(Part1::VALUE.into()) / total.into(); + let total: u32 = PART1 + PART2; + let amount1 = amount.peek().saturating_mul(PART1.into()) / total.into(); let (imb1, imb2) = amount.split(amount1); Target1::on_unbalanced(imb1); Target2::on_unbalanced(imb2); diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index c794752e9d3d2..d21364d3f8fbb 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -56,8 +56,6 @@ pub use hashing::{blake2_128, blake2_256, keccak_256, twox_128, twox_256, twox_6 pub mod crypto; pub mod hexdisplay; -pub mod u32_trait; - pub mod ecdsa; pub mod ed25519; pub mod hash; diff --git a/primitives/core/src/u32_trait.rs b/primitives/core/src/u32_trait.rs deleted file mode 100644 index ff15080400340..0000000000000 --- a/primitives/core/src/u32_trait.rs +++ /dev/null @@ -1,570 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! An u32 trait with "values" as impl'd types. - -/// A u32 value, wrapped in a trait because we don't yet have const generics. -pub trait Value { - /// The actual value represented by the impl'ing type. - const VALUE: u32; -} - -/// Type representing the value 0 for the `Value` trait. -pub struct _0; -impl Value for _0 { - const VALUE: u32 = 0; -} -/// Type representing the value 1 for the `Value` trait. -pub struct _1; -impl Value for _1 { - const VALUE: u32 = 1; -} -/// Type representing the value 2 for the `Value` trait. -pub struct _2; -impl Value for _2 { - const VALUE: u32 = 2; -} -/// Type representing the value 3 for the `Value` trait. -pub struct _3; -impl Value for _3 { - const VALUE: u32 = 3; -} -/// Type representing the value 4 for the `Value` trait. -pub struct _4; -impl Value for _4 { - const VALUE: u32 = 4; -} -/// Type representing the value 5 for the `Value` trait. -pub struct _5; -impl Value for _5 { - const VALUE: u32 = 5; -} -/// Type representing the value 6 for the `Value` trait. -pub struct _6; -impl Value for _6 { - const VALUE: u32 = 6; -} -/// Type representing the value 7 for the `Value` trait. -pub struct _7; -impl Value for _7 { - const VALUE: u32 = 7; -} -/// Type representing the value 8 for the `Value` trait. -pub struct _8; -impl Value for _8 { - const VALUE: u32 = 8; -} -/// Type representing the value 9 for the `Value` trait. -pub struct _9; -impl Value for _9 { - const VALUE: u32 = 9; -} -/// Type representing the value 10 for the `Value` trait. -pub struct _10; -impl Value for _10 { - const VALUE: u32 = 10; -} -/// Type representing the value 11 for the `Value` trait. -pub struct _11; -impl Value for _11 { - const VALUE: u32 = 11; -} -/// Type representing the value 12 for the `Value` trait. -pub struct _12; -impl Value for _12 { - const VALUE: u32 = 12; -} -/// Type representing the value 13 for the `Value` trait. -pub struct _13; -impl Value for _13 { - const VALUE: u32 = 13; -} -/// Type representing the value 14 for the `Value` trait. -pub struct _14; -impl Value for _14 { - const VALUE: u32 = 14; -} -/// Type representing the value 15 for the `Value` trait. -pub struct _15; -impl Value for _15 { - const VALUE: u32 = 15; -} -/// Type representing the value 16 for the `Value` trait. -pub struct _16; -impl Value for _16 { - const VALUE: u32 = 16; -} -/// Type representing the value 17 for the `Value` trait. -pub struct _17; -impl Value for _17 { - const VALUE: u32 = 17; -} -/// Type representing the value 18 for the `Value` trait. -pub struct _18; -impl Value for _18 { - const VALUE: u32 = 18; -} -/// Type representing the value 19 for the `Value` trait. -pub struct _19; -impl Value for _19 { - const VALUE: u32 = 19; -} -/// Type representing the value 20 for the `Value` trait. -pub struct _20; -impl Value for _20 { - const VALUE: u32 = 20; -} -/// Type representing the value 21 for the `Value` trait. -pub struct _21; -impl Value for _21 { - const VALUE: u32 = 21; -} -/// Type representing the value 22 for the `Value` trait. -pub struct _22; -impl Value for _22 { - const VALUE: u32 = 22; -} -/// Type representing the value 23 for the `Value` trait. -pub struct _23; -impl Value for _23 { - const VALUE: u32 = 23; -} -/// Type representing the value 24 for the `Value` trait. -pub struct _24; -impl Value for _24 { - const VALUE: u32 = 24; -} -/// Type representing the value 25 for the `Value` trait. -pub struct _25; -impl Value for _25 { - const VALUE: u32 = 25; -} -/// Type representing the value 26 for the `Value` trait. -pub struct _26; -impl Value for _26 { - const VALUE: u32 = 26; -} -/// Type representing the value 27 for the `Value` trait. -pub struct _27; -impl Value for _27 { - const VALUE: u32 = 27; -} -/// Type representing the value 28 for the `Value` trait. -pub struct _28; -impl Value for _28 { - const VALUE: u32 = 28; -} -/// Type representing the value 29 for the `Value` trait. -pub struct _29; -impl Value for _29 { - const VALUE: u32 = 29; -} -/// Type representing the value 30 for the `Value` trait. -pub struct _30; -impl Value for _30 { - const VALUE: u32 = 30; -} -/// Type representing the value 31 for the `Value` trait. -pub struct _31; -impl Value for _31 { - const VALUE: u32 = 31; -} -/// Type representing the value 32 for the `Value` trait. -pub struct _32; -impl Value for _32 { - const VALUE: u32 = 32; -} -/// Type representing the value 33 for the `Value` trait. -pub struct _33; -impl Value for _33 { - const VALUE: u32 = 33; -} -/// Type representing the value 34 for the `Value` trait. -pub struct _34; -impl Value for _34 { - const VALUE: u32 = 34; -} -/// Type representing the value 35 for the `Value` trait. -pub struct _35; -impl Value for _35 { - const VALUE: u32 = 35; -} -/// Type representing the value 36 for the `Value` trait. -pub struct _36; -impl Value for _36 { - const VALUE: u32 = 36; -} -/// Type representing the value 37 for the `Value` trait. -pub struct _37; -impl Value for _37 { - const VALUE: u32 = 37; -} -/// Type representing the value 38 for the `Value` trait. -pub struct _38; -impl Value for _38 { - const VALUE: u32 = 38; -} -/// Type representing the value 39 for the `Value` trait. -pub struct _39; -impl Value for _39 { - const VALUE: u32 = 39; -} -/// Type representing the value 40 for the `Value` trait. -pub struct _40; -impl Value for _40 { - const VALUE: u32 = 40; -} -/// Type representing the value 41 for the `Value` trait. -pub struct _41; -impl Value for _41 { - const VALUE: u32 = 41; -} -/// Type representing the value 42 for the `Value` trait. -pub struct _42; -impl Value for _42 { - const VALUE: u32 = 42; -} -/// Type representing the value 43 for the `Value` trait. -pub struct _43; -impl Value for _43 { - const VALUE: u32 = 43; -} -/// Type representing the value 44 for the `Value` trait. -pub struct _44; -impl Value for _44 { - const VALUE: u32 = 44; -} -/// Type representing the value 45 for the `Value` trait. -pub struct _45; -impl Value for _45 { - const VALUE: u32 = 45; -} -/// Type representing the value 46 for the `Value` trait. -pub struct _46; -impl Value for _46 { - const VALUE: u32 = 46; -} -/// Type representing the value 47 for the `Value` trait. -pub struct _47; -impl Value for _47 { - const VALUE: u32 = 47; -} -/// Type representing the value 48 for the `Value` trait. -pub struct _48; -impl Value for _48 { - const VALUE: u32 = 48; -} -/// Type representing the value 49 for the `Value` trait. -pub struct _49; -impl Value for _49 { - const VALUE: u32 = 49; -} -/// Type representing the value 50 for the `Value` trait. -pub struct _50; -impl Value for _50 { - const VALUE: u32 = 50; -} -/// Type representing the value 51 for the `Value` trait. -pub struct _51; -impl Value for _51 { - const VALUE: u32 = 51; -} -/// Type representing the value 52 for the `Value` trait. -pub struct _52; -impl Value for _52 { - const VALUE: u32 = 52; -} -/// Type representing the value 53 for the `Value` trait. -pub struct _53; -impl Value for _53 { - const VALUE: u32 = 53; -} -/// Type representing the value 54 for the `Value` trait. -pub struct _54; -impl Value for _54 { - const VALUE: u32 = 54; -} -/// Type representing the value 55 for the `Value` trait. -pub struct _55; -impl Value for _55 { - const VALUE: u32 = 55; -} -/// Type representing the value 56 for the `Value` trait. -pub struct _56; -impl Value for _56 { - const VALUE: u32 = 56; -} -/// Type representing the value 57 for the `Value` trait. -pub struct _57; -impl Value for _57 { - const VALUE: u32 = 57; -} -/// Type representing the value 58 for the `Value` trait. -pub struct _58; -impl Value for _58 { - const VALUE: u32 = 58; -} -/// Type representing the value 59 for the `Value` trait. -pub struct _59; -impl Value for _59 { - const VALUE: u32 = 59; -} -/// Type representing the value 60 for the `Value` trait. -pub struct _60; -impl Value for _60 { - const VALUE: u32 = 60; -} -/// Type representing the value 61 for the `Value` trait. -pub struct _61; -impl Value for _61 { - const VALUE: u32 = 61; -} -/// Type representing the value 62 for the `Value` trait. -pub struct _62; -impl Value for _62 { - const VALUE: u32 = 62; -} -/// Type representing the value 63 for the `Value` trait. -pub struct _63; -impl Value for _63 { - const VALUE: u32 = 63; -} -/// Type representing the value 64 for the `Value` trait. -pub struct _64; -impl Value for _64 { - const VALUE: u32 = 64; -} -/// Type representing the value 65 for the `Value` trait. -pub struct _65; -impl Value for _65 { - const VALUE: u32 = 65; -} -/// Type representing the value 66 for the `Value` trait. -pub struct _66; -impl Value for _66 { - const VALUE: u32 = 66; -} -/// Type representing the value 67 for the `Value` trait. -pub struct _67; -impl Value for _67 { - const VALUE: u32 = 67; -} -/// Type representing the value 68 for the `Value` trait. -pub struct _68; -impl Value for _68 { - const VALUE: u32 = 68; -} -/// Type representing the value 69 for the `Value` trait. -pub struct _69; -impl Value for _69 { - const VALUE: u32 = 69; -} -/// Type representing the value 70 for the `Value` trait. -pub struct _70; -impl Value for _70 { - const VALUE: u32 = 70; -} -/// Type representing the value 71 for the `Value` trait. -pub struct _71; -impl Value for _71 { - const VALUE: u32 = 71; -} -/// Type representing the value 72 for the `Value` trait. -pub struct _72; -impl Value for _72 { - const VALUE: u32 = 72; -} -/// Type representing the value 73 for the `Value` trait. -pub struct _73; -impl Value for _73 { - const VALUE: u32 = 73; -} -/// Type representing the value 74 for the `Value` trait. -pub struct _74; -impl Value for _74 { - const VALUE: u32 = 74; -} -/// Type representing the value 75 for the `Value` trait. -pub struct _75; -impl Value for _75 { - const VALUE: u32 = 75; -} -/// Type representing the value 76 for the `Value` trait. -pub struct _76; -impl Value for _76 { - const VALUE: u32 = 76; -} -/// Type representing the value 77 for the `Value` trait. -pub struct _77; -impl Value for _77 { - const VALUE: u32 = 77; -} -/// Type representing the value 78 for the `Value` trait. -pub struct _78; -impl Value for _78 { - const VALUE: u32 = 78; -} -/// Type representing the value 79 for the `Value` trait. -pub struct _79; -impl Value for _79 { - const VALUE: u32 = 79; -} -/// Type representing the value 80 for the `Value` trait. -pub struct _80; -impl Value for _80 { - const VALUE: u32 = 80; -} -/// Type representing the value 81 for the `Value` trait. -pub struct _81; -impl Value for _81 { - const VALUE: u32 = 81; -} -/// Type representing the value 82 for the `Value` trait. -pub struct _82; -impl Value for _82 { - const VALUE: u32 = 82; -} -/// Type representing the value 83 for the `Value` trait. -pub struct _83; -impl Value for _83 { - const VALUE: u32 = 83; -} -/// Type representing the value 84 for the `Value` trait. -pub struct _84; -impl Value for _84 { - const VALUE: u32 = 84; -} -/// Type representing the value 85 for the `Value` trait. -pub struct _85; -impl Value for _85 { - const VALUE: u32 = 85; -} -/// Type representing the value 86 for the `Value` trait. -pub struct _86; -impl Value for _86 { - const VALUE: u32 = 86; -} -/// Type representing the value 87 for the `Value` trait. -pub struct _87; -impl Value for _87 { - const VALUE: u32 = 87; -} -/// Type representing the value 88 for the `Value` trait. -pub struct _88; -impl Value for _88 { - const VALUE: u32 = 88; -} -/// Type representing the value 89 for the `Value` trait. -pub struct _89; -impl Value for _89 { - const VALUE: u32 = 89; -} -/// Type representing the value 90 for the `Value` trait. -pub struct _90; -impl Value for _90 { - const VALUE: u32 = 90; -} -/// Type representing the value 91 for the `Value` trait. -pub struct _91; -impl Value for _91 { - const VALUE: u32 = 91; -} -/// Type representing the value 92 for the `Value` trait. -pub struct _92; -impl Value for _92 { - const VALUE: u32 = 92; -} -/// Type representing the value 93 for the `Value` trait. -pub struct _93; -impl Value for _93 { - const VALUE: u32 = 93; -} -/// Type representing the value 94 for the `Value` trait. -pub struct _94; -impl Value for _94 { - const VALUE: u32 = 94; -} -/// Type representing the value 95 for the `Value` trait. -pub struct _95; -impl Value for _95 { - const VALUE: u32 = 95; -} -/// Type representing the value 96 for the `Value` trait. -pub struct _96; -impl Value for _96 { - const VALUE: u32 = 96; -} -/// Type representing the value 97 for the `Value` trait. -pub struct _97; -impl Value for _97 { - const VALUE: u32 = 97; -} -/// Type representing the value 98 for the `Value` trait. -pub struct _98; -impl Value for _98 { - const VALUE: u32 = 98; -} -/// Type representing the value 99 for the `Value` trait. -pub struct _99; -impl Value for _99 { - const VALUE: u32 = 99; -} -/// Type representing the value 100 for the `Value` trait. -pub struct _100; -impl Value for _100 { - const VALUE: u32 = 100; -} -/// Type representing the value 112 for the `Value` trait. -pub struct _112; -impl Value for _112 { - const VALUE: u32 = 112; -} -/// Type representing the value 128 for the `Value` trait. -pub struct _128; -impl Value for _128 { - const VALUE: u32 = 128; -} -/// Type representing the value 160 for the `Value` trait. -pub struct _160; -impl Value for _160 { - const VALUE: u32 = 160; -} -/// Type representing the value 192 for the `Value` trait. -pub struct _192; -impl Value for _192 { - const VALUE: u32 = 192; -} -/// Type representing the value 224 for the `Value` trait. -pub struct _224; -impl Value for _224 { - const VALUE: u32 = 224; -} -/// Type representing the value 256 for the `Value` trait. -pub struct _256; -impl Value for _256 { - const VALUE: u32 = 256; -} -/// Type representing the value 384 for the `Value` trait. -pub struct _384; -impl Value for _384 { - const VALUE: u32 = 384; -} -/// Type representing the value 512 for the `Value` trait. -pub struct _512; -impl Value for _512 { - const VALUE: u32 = 512; -} From 4bc2af13cd81007a2a340d0333062179420d5daf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 14 Feb 2022 21:12:48 +0100 Subject: [PATCH 0514/1472] wasm-builder: Support latest nightly (#10837) * wasm-builder: Support latest nightly With latest nightly, aka rust version 1.60+ namespaced features are added. This changes the handling of optional dependencies. We currently have features that enable optional dependencies when `std` is enabled. This was before no problem, but now the wasm-builder detects them as enabled. To support the transition period until 1.60 is released as stable, this pr adds an heuristic to not enable these optional crates in the wasm build when they are enabled in the `std` feature. This heuristic fails when someones enables these optional dependencies from the outside as well as via the `std` feature, however we hope that no one is doing this at the moment. When namespaced features are enabled, these dependencies needs to be enabled using `dep:dependency-name` to solve this properly. https://doc.rust-lang.org/cargo/reference/unstable.html#namespaced-features * Remove accidentally added features --- Cargo.lock | 1 - bin/node/runtime/Cargo.toml | 4 +--- primitives/keyring/Cargo.toml | 1 - utils/wasm-builder/src/wasm_project.rs | 23 ++++++++++++++++++++--- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index feb721e6092cf..e97c90e49236a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4916,7 +4916,6 @@ dependencies = [ "sp-core", "sp-inherents", "sp-io", - "sp-keyring", "sp-npos-elections", "sp-offchain", "sp-runtime", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 2aad40b4f121d..4f235a51171d2 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -35,7 +35,6 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../../primiti sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } -sp-keyring = { version = "5.0.0", optional = true, path = "../../../primitives/keyring" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } @@ -153,7 +152,6 @@ std = [ "sp-runtime/std", "sp-staking/std", "pallet-staking/std", - "sp-keyring", "sp-session/std", "pallet-sudo/std", "frame-support/std", @@ -178,7 +176,7 @@ std = [ "log/std", "frame-try-runtime/std", "sp-npos-elections/std", - "sp-io/std", + "sp-io/std", "pallet-child-bounties/std", ] runtime-benchmarks = [ diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 5cf8a574505aa..1e5a234d39095 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -13,7 +13,6 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] sp-core = { version = "5.0.0", path = "../core" } sp-runtime = { version = "5.0.0", path = "../runtime" } diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 20e176444c621..e94703b610a48 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -341,13 +341,30 @@ fn project_enabled_features( ) -> Vec { let package = find_package_by_manifest_path(cargo_manifest, crate_metadata); + let std_enabled = package.features.get("std"); + let mut enabled_features = package .features - .keys() - .filter(|f| { + .iter() + .filter(|(f, v)| { let mut feature_env = f.replace("-", "_"); feature_env.make_ascii_uppercase(); + // If this is a feature that corresponds only to an optional dependency + // and this feature is enabled by the `std` feature, we assume that this + // is only done through the `std` feature. This is a bad heuristic and should + // be removed after namespaced features are landed: + // https://doc.rust-lang.org/cargo/reference/unstable.html#namespaced-features + // Then we can just express this directly in the `Cargo.toml` and do not require + // this heuristic anymore. However, for the transition phase between now and namespaced + // features already being present in nightly, we need this code to make + // runtimes compile with all the possible rustc versions. + if v.len() == 1 && v.get(0).map_or(false, |v| *v == format!("dep:{}", f)) { + if std_enabled.as_ref().map(|e| e.iter().any(|ef| ef == *f)).unwrap_or(false) { + return false + } + } + // We don't want to enable the `std`/`default` feature for the wasm build and // we need to check if the feature is enabled by checking the env variable. *f != "std" && @@ -355,7 +372,7 @@ fn project_enabled_features( .map(|v| v == "1") .unwrap_or_default() }) - .cloned() + .map(|d| d.0.clone()) .collect::>(); enabled_features.sort(); From dd8a868ad819666ff81bd94479657be560daf767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 15 Feb 2022 09:56:22 +0100 Subject: [PATCH 0515/1472] contracts: Fix `seal_call` weights (#10796) * Fix call weights * Fix instantiate benchmark * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Remove stale and superflous comments * `decrement_refcount` should be infallible * Don't hardcode increment_refcount, decrement_refcount * Rename CopyIn/CopyOut * Fix warning in tests Co-authored-by: Parity Bot --- frame/contracts/src/benchmarking/mod.rs | 113 +- frame/contracts/src/exec.rs | 61 +- frame/contracts/src/schedule.rs | 48 +- frame/contracts/src/wasm/code_cache.rs | 3 +- frame/contracts/src/wasm/mod.rs | 13 +- frame/contracts/src/wasm/runtime.rs | 89 +- frame/contracts/src/weights.rs | 1270 +++++++++++------------ 7 files changed, 759 insertions(+), 838 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index b18b40d0b3345..3a749095b955e 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -33,6 +33,7 @@ use crate::{ exec::{AccountIdOf, StorageKey}, schedule::{API_BENCHMARK_BATCH_SIZE, INSTR_BENCHMARK_BATCH_SIZE}, storage::Storage, + wasm::CallFlags, Pallet as Contracts, *, }; use codec::{Encode, MaxEncodedLen}; @@ -1526,44 +1527,21 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]) - seal_call_per_transfer_input_output_kb { + seal_call_per_transfer_clone_kb { let t in 0 .. 1; - let i in 0 .. code::max_pages::() * 64; - let o in 0 .. (code::max_pages::() - 1) * 64; - let callee_code = WasmModule::::from(ModuleDefinition { - memory: Some(ImportedMemory::max::()), - imported_functions: vec![ImportedFunction { - module: "seal0", - name: "seal_return", - params: vec![ - ValueType::I32, - ValueType::I32, - ValueType::I32, - ], - return_type: None, - }], - call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // flags - Instruction::I32Const(0), // data_ptr - Instruction::I32Const((o * 1024) as i32), // data_len - Instruction::Call(0), - Instruction::End, - ])), - .. Default::default() - }); + let c in 0 .. code::max_pages::() * 64; let callees = (0..API_BENCHMARK_BATCH_SIZE) - .map(|i| Contract::with_index(i + 1, callee_code.clone(), vec![])) + .map(|i| Contract::with_index(i + 1, >::dummy(), vec![])) .collect::, _>>()?; let callee_len = callees.get(0).map(|i| i.account_id.encode().len()).unwrap_or(0); let callee_bytes = callees.iter().flat_map(|x| x.account_id.encode()).collect::>(); - let callees_len = callee_bytes.len(); let value: BalanceOf = t.into(); let value_bytes = value.encode(); let value_len = value_bytes.len(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", + module: "seal1", name: "seal_call", params: vec![ ValueType::I32, @@ -1574,7 +1552,6 @@ benchmarks! { ValueType::I32, ValueType::I32, ValueType::I32, - ValueType::I32, ], return_type: Some(ValueType::I32), }], @@ -1587,21 +1564,16 @@ benchmarks! { offset: value_len as u32, value: callee_bytes, }, - DataSegment { - offset: (value_len + callees_len) as u32, - value: (o * 1024).to_le_bytes().into(), - }, ], call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ + Regular(Instruction::I32Const(CallFlags::CLONE_INPUT.bits() as i32)), // flags Counter(value_len as u32, callee_len as u32), // callee_ptr - Regular(Instruction::I32Const(callee_len as i32)), // callee_len Regular(Instruction::I64Const(0)), // gas Regular(Instruction::I32Const(0)), // value_ptr - Regular(Instruction::I32Const(value_len as i32)), // value_len Regular(Instruction::I32Const(0)), // input_data_ptr - Regular(Instruction::I32Const((i * 1024) as i32)), // input_data_len - Regular(Instruction::I32Const((value_len + callees_len + 4) as i32)), // output_ptr - Regular(Instruction::I32Const((value_len + callees_len) as i32)), // output_len_ptr + Regular(Instruction::I32Const(0)), // input_data_len + Regular(Instruction::I32Const(SENTINEL as i32)), // output_ptr + Regular(Instruction::I32Const(0)), // output_len_ptr Regular(Instruction::Call(0)), Regular(Instruction::Drop), ])), @@ -1609,7 +1581,8 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + let bytes = vec![42; (c * 1024) as usize]; + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, bytes) // We assume that every instantiate sends at least the minimum balance. seal_instantiate { @@ -1725,52 +1698,28 @@ benchmarks! { } } - seal_instantiate_per_input_output_salt_kb { - let i in 0 .. (code::max_pages::() - 1) * 64; - let o in 0 .. (code::max_pages::() - 1) * 64; + seal_instantiate_per_transfer_salt_kb { + let t in 0 .. 1; let s in 0 .. (code::max_pages::() - 1) * 64; - let callee_code = WasmModule::::from(ModuleDefinition { - memory: Some(ImportedMemory::max::()), - imported_functions: vec![ImportedFunction { - module: "seal0", - name: "seal_return", - params: vec![ - ValueType::I32, - ValueType::I32, - ValueType::I32, - ], - return_type: None, - }], - deploy_body: Some(body::plain(vec![ - Instruction::I32Const(0), // flags - Instruction::I32Const(0), // data_ptr - Instruction::I32Const((o * 1024) as i32), // data_len - Instruction::Call(0), - Instruction::End, - ])), - .. Default::default() - }); + let callee_code = WasmModule::::dummy(); let hash = callee_code.hash.clone(); let hash_bytes = callee_code.hash.encode(); let hash_len = hash_bytes.len(); Contracts::::store_code_raw(callee_code.code, whitelisted_caller())?; - let inputs = (0..API_BENCHMARK_BATCH_SIZE).map(|x| x.encode()).collect::>(); - let input_len = inputs.get(0).map(|x| x.len()).unwrap_or(0); - let input_bytes = inputs.iter().cloned().flatten().collect::>(); - let inputs_len = input_bytes.len(); - let value = T::Currency::minimum_balance(); - assert!(value > 0u32.into()); + let salts = (0..API_BENCHMARK_BATCH_SIZE).map(|x| x.encode()).collect::>(); + let salt_len = salts.get(0).map(|x| x.len()).unwrap_or(0); + let salt_bytes = salts.iter().cloned().flatten().collect::>(); + let salts_len = salt_bytes.len(); + let value: BalanceOf = t.into(); let value_bytes = value.encode(); let value_len = value_bytes.len(); let addr_len = T::AccountId::max_encoded_len(); // offsets where to place static data in contract memory - let input_offset = 0; - let value_offset = inputs_len; + let salt_offset = 0; + let value_offset = salts_len; let hash_offset = value_offset + value_len; let addr_len_offset = hash_offset + hash_len; - let output_len_offset = addr_len_offset + 4; - let output_offset = output_len_offset + 4; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), @@ -1796,8 +1745,8 @@ benchmarks! { }], data_segments: vec![ DataSegment { - offset: input_offset as u32, - value: input_bytes, + offset: salt_offset as u32, + value: salt_bytes, }, DataSegment { offset: value_offset as u32, @@ -1811,10 +1760,6 @@ benchmarks! { offset: addr_len_offset as u32, value: (addr_len as u32).to_le_bytes().into(), }, - DataSegment { - offset: output_len_offset as u32, - value: (o * 1024).to_le_bytes().into(), - }, ], call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ Regular(Instruction::I32Const(hash_offset as i32)), // code_hash_ptr @@ -1822,14 +1767,14 @@ benchmarks! { Regular(Instruction::I64Const(0)), // gas Regular(Instruction::I32Const(value_offset as i32)), // value_ptr Regular(Instruction::I32Const(value_len as i32)), // value_len - Counter(input_offset as u32, input_len as u32), // input_data_ptr - Regular(Instruction::I32Const((i * 1024).max(input_len as u32) as i32)), // input_data_len + Regular(Instruction::I32Const(0)), // input_data_ptr + Regular(Instruction::I32Const(0)), // input_data_len Regular(Instruction::I32Const((addr_len_offset + addr_len) as i32)), // address_ptr Regular(Instruction::I32Const(addr_len_offset as i32)), // address_len_ptr - Regular(Instruction::I32Const(output_offset as i32)), // output_ptr - Regular(Instruction::I32Const(output_len_offset as i32)), // output_len_ptr - Counter(input_offset as u32, input_len as u32), // salt_ptr - Regular(Instruction::I32Const((s * 1024).max(input_len as u32) as i32)), // salt_len + Regular(Instruction::I32Const(SENTINEL as i32)), // output_ptr + Regular(Instruction::I32Const(0)), // output_len_ptr + Counter(salt_offset as u32, salt_len as u32), // salt_ptr + Regular(Instruction::I32Const((s * 1024).max(salt_len as u32) as i32)), // salt_len Regular(Instruction::Call(0)), Regular(Instruction::I32Eqz), Regular(Instruction::If(BlockType::NoResult)), diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index bca74cd66ced7..eb7a68d81ad50 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -18,7 +18,6 @@ use crate::{ gas::GasMeter, storage::{self, Storage, WriteOutcome}, - wasm::{decrement_refcount, increment_refcount}, AccountCounter, BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Error, Event, Pallet as Contracts, Schedule, }; @@ -92,10 +91,6 @@ pub trait Ext: sealing::Sealed { /// Call (possibly transferring some amount of funds) into the specified account. /// /// Returns the original code size of the called contract. - /// - /// # Return Value - /// - /// Result<(ExecReturnValue, CodeSize), (ExecError, CodeSize)> fn call( &mut self, gas_limit: Weight, @@ -108,10 +103,6 @@ pub trait Ext: sealing::Sealed { /// Execute code in the current frame. /// /// Returns the original code size of the called contract. - /// - /// # Return Value - /// - /// Result fn delegate_call( &mut self, code: CodeHash, @@ -123,10 +114,6 @@ pub trait Ext: sealing::Sealed { /// Returns the original code size of the called contract. /// The newly created account will be associated with `code`. `value` specifies the amount of /// value transferred from this to the newly created account. - /// - /// # Return Value - /// - /// Result<(AccountId, ExecReturnValue, CodeSize), (ExecError, CodeSize)> fn instantiate( &mut self, gas_limit: Weight, @@ -269,12 +256,17 @@ pub trait Executable: Sized { gas_meter: &mut GasMeter, ) -> Result; - /// Decrement the refcount by one if the code exists. + /// Increment the refcount of a code in-storage by one. /// - /// # Note + /// This is needed when the code is not set via instantiate but `seal_set_code_hash`. /// - /// Charges weight proportional to the code size from the gas meter. - fn remove_user(code_hash: CodeHash) -> Result<(), DispatchError>; + /// # Errors + /// + /// [`Error::CodeNotFound`] is returned if the specified `code_hash` does not exist. + fn add_user(code_hash: CodeHash) -> Result<(), DispatchError>; + + /// Decrement the refcount by one if the code exists. + fn remove_user(code_hash: CodeHash); /// Execute the specified exported function and return the result. /// @@ -1058,7 +1050,7 @@ where T::Currency::free_balance(&frame.account_id), )?; ContractInfoOf::::remove(&frame.account_id); - E::remove_user(info.code_hash)?; + E::remove_user(info.code_hash); Contracts::::deposit_event(Event::Terminated { contract: frame.account_id.clone(), beneficiary: beneficiary.clone(), @@ -1188,10 +1180,10 @@ where } fn set_code_hash(&mut self, hash: CodeHash) -> Result<(), DispatchError> { - increment_refcount::(hash)?; + E::add_user(hash)?; let top_frame = self.top_frame_mut(); let prev_hash = top_frame.contract_info().code_hash.clone(); - decrement_refcount::(prev_hash.clone())?; + E::remove_user(prev_hash.clone()); top_frame.contract_info().code_hash = hash; Contracts::::deposit_event(Event::ContractCodeUpdated { contract: top_frame.account_id.clone(), @@ -1249,7 +1241,11 @@ mod tests { use pretty_assertions::assert_eq; use sp_core::Bytes; use sp_runtime::{traits::Hash, DispatchError}; - use std::{cell::RefCell, collections::HashMap, rc::Rc}; + use std::{ + cell::RefCell, + collections::hash_map::{Entry, HashMap}, + rc::Rc, + }; type System = frame_system::Pallet; @@ -1311,15 +1307,15 @@ mod tests { }) } - fn increment_refcount(code_hash: CodeHash) { + fn increment_refcount(code_hash: CodeHash) -> Result<(), DispatchError> { LOADER.with(|loader| { let mut loader = loader.borrow_mut(); - loader - .map - .entry(code_hash) - .and_modify(|executable| executable.refcount += 1) - .or_insert_with(|| panic!("code_hash does not exist")); - }); + match loader.map.entry(code_hash) { + Entry::Vacant(_) => Err(>::CodeNotFound)?, + Entry::Occupied(mut entry) => entry.get_mut().refcount += 1, + } + Ok(()) + }) } fn decrement_refcount(code_hash: CodeHash) { @@ -1355,9 +1351,12 @@ mod tests { }) } - fn remove_user(code_hash: CodeHash) -> Result<(), DispatchError> { + fn add_user(code_hash: CodeHash) -> Result<(), DispatchError> { + MockLoader::increment_refcount(code_hash) + } + + fn remove_user(code_hash: CodeHash) { MockLoader::decrement_refcount(code_hash); - Ok(()) } fn execute>( @@ -1367,7 +1366,7 @@ mod tests { input_data: Vec, ) -> ExecResult { if let &Constructor = function { - MockLoader::increment_refcount(self.code_hash); + Self::add_user(self.code_hash).unwrap(); } if function == &self.func_type { (self.func)(MockCtx { ext, input_data }, &self) diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index c92d2dd616106..d6bdf85a4d68e 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -367,20 +367,14 @@ pub struct HostFnWeights { /// Weight surcharge that is claimed if `seal_call` does a balance transfer. pub call_transfer_surcharge: Weight, - /// Weight per input byte supplied to `seal_call`. - pub call_per_input_byte: Weight, - - /// Weight per output byte received through `seal_call`. - pub call_per_output_byte: Weight, + /// Weight per byte that is cloned by supplying the `CLONE_INPUT` flag. + pub call_per_cloned_byte: Weight, /// Weight of calling `seal_instantiate`. pub instantiate: Weight, - /// Weight per input byte supplied to `seal_instantiate`. - pub instantiate_per_input_byte: Weight, - - /// Weight per output byte received through `seal_instantiate`. - pub instantiate_per_output_byte: Weight, + /// Weight surcharge that is claimed if `seal_instantiate` does a balance transfer. + pub instantiate_transfer_surcharge: Weight, /// Weight per salt byte supplied to `seal_instantiate`. pub instantiate_per_salt_byte: Weight, @@ -623,40 +617,16 @@ impl Default for HostFnWeights { transfer: cost_batched!(seal_transfer), call: cost_batched!(seal_call), delegate_call: cost_batched!(seal_delegate_call), - call_transfer_surcharge: cost_batched_args!( - seal_call_per_transfer_input_output_kb, - 1, - 0, - 0 - ), - call_per_input_byte: cost_byte_batched_args!( - seal_call_per_transfer_input_output_kb, - 0, - 1, - 0 - ), - call_per_output_byte: cost_byte_batched_args!( - seal_call_per_transfer_input_output_kb, - 0, - 0, - 1 - ), + call_transfer_surcharge: cost_batched_args!(seal_call_per_transfer_clone_kb, 1, 0), + call_per_cloned_byte: cost_batched_args!(seal_call_per_transfer_clone_kb, 0, 1), instantiate: cost_batched!(seal_instantiate), - instantiate_per_input_byte: cost_byte_batched_args!( - seal_instantiate_per_input_output_salt_kb, - 1, - 0, - 0 - ), - instantiate_per_output_byte: cost_byte_batched_args!( - seal_instantiate_per_input_output_salt_kb, - 0, + instantiate_transfer_surcharge: cost_byte_batched_args!( + seal_instantiate_per_transfer_salt_kb, 1, 0 ), instantiate_per_salt_byte: cost_byte_batched_args!( - seal_instantiate_per_input_output_salt_kb, - 0, + seal_instantiate_per_transfer_salt_kb, 0, 1 ), diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 9a447066667bd..9fc49ac9a502d 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -108,13 +108,12 @@ where /// /// A contract whose refcount dropped to zero isn't automatically removed. A `remove_code` /// transaction must be submitted by the original uploader to do so. -pub fn decrement_refcount(code_hash: CodeHash) -> Result<(), DispatchError> { +pub fn decrement_refcount(code_hash: CodeHash) { >::mutate(code_hash, |existing| { if let Some(info) = existing { info.refcount = info.refcount.saturating_sub(1); } }); - Ok(()) } /// Increment the refcount of a code in-storage by one. diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 3053f33ff033a..2dbaad0d79324 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -25,11 +25,8 @@ mod prepare; mod runtime; #[cfg(feature = "runtime-benchmarks")] -pub use self::code_cache::reinstrument; -pub use self::{ - code_cache::{decrement_refcount, increment_refcount}, - runtime::{ReturnCode, Runtime, RuntimeCosts}, -}; +pub use crate::wasm::code_cache::reinstrument; +pub use crate::wasm::runtime::{CallFlags, ReturnCode, Runtime, RuntimeCosts}; use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, gas::GasMeter, @@ -201,7 +198,11 @@ where code_cache::load(code_hash, schedule, gas_meter) } - fn remove_user(code_hash: CodeHash) -> Result<(), DispatchError> { + fn add_user(code_hash: CodeHash) -> Result<(), DispatchError> { + code_cache::increment_refcount::(code_hash) + } + + fn remove_user(code_hash: CodeHash) { code_cache::decrement_refcount::(code_hash) } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 384fbff9809b7..bb188e10e8fa0 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -136,6 +136,10 @@ pub enum RuntimeCosts { /// Charge the gas meter with the cost of a metering block. The charged costs are /// the supplied cost of the block plus the overhead of the metering itself. MeteringBlock(u32), + /// Weight charged for copying data from the sandbox. + CopyFromContract(u32), + /// Weight charged for copying data to the sandbox. + CopyToContract(u32), /// Weight of calling `seal_caller`. Caller, /// Weight of calling `seal_is_contract`. @@ -162,8 +166,6 @@ pub enum RuntimeCosts { WeightToFee, /// Weight of calling `seal_input` without the weight of copying the input. InputBase, - /// Weight of copying the input data for the given size. - InputCopyOut(u32), /// Weight of calling `seal_return` for the given output size. Return(u32), /// Weight of calling `seal_terminate`. @@ -188,21 +190,19 @@ pub enum RuntimeCosts { TakeStorage(u32), /// Weight of calling `seal_transfer`. Transfer, - /// Weight of calling `seal_call` for the given input size. - CallBase(u32), + /// Base weight of calling `seal_call`. + CallBase, /// Weight of calling `seal_delegate_call` for the given input size. #[cfg(feature = "unstable-interface")] - DelegateCallBase(u32), + DelegateCallBase, /// Weight of the transfer performed during a call. CallSurchargeTransfer, - /// Weight of output received through `seal_call` for the given size. - CallCopyOut(u32), - /// Weight of calling `seal_instantiate` for the given input and salt without output weight. - /// This includes the transfer as an instantiate without a value will always be below - /// the existential deposit and is disregarded as corner case. + /// Weight per byte that is cloned by supplying the `CLONE_INPUT` flag. + CallInputCloned(u32), + /// Weight of calling `seal_instantiate` for the given input length and salt. InstantiateBase { input_data_len: u32, salt_len: u32 }, - /// Weight of output received through `seal_instantiate` for the given size. - InstantiateCopyOut(u32), + /// Weight of the transfer performed during an instantiate. + InstantiateSurchargeTransfer, /// Weight of calling `seal_hash_sha_256` for the given input size. HashSha256(u32), /// Weight of calling `seal_hash_keccak_256` for the given input size. @@ -216,9 +216,6 @@ pub enum RuntimeCosts { EcdsaRecovery, /// Weight charged by a chain extension through `seal_call_chain_extension`. ChainExtension(u64), - /// Weight charged for copying data from the sandbox. - #[cfg(feature = "unstable-interface")] - CopyIn(u32), /// Weight charged for calling into the runtime. #[cfg(feature = "unstable-interface")] CallRuntime(Weight), @@ -236,6 +233,8 @@ impl RuntimeCosts { use self::RuntimeCosts::*; let weight = match *self { MeteringBlock(amount) => s.gas.saturating_add(amount.into()), + CopyFromContract(len) => s.return_per_byte.saturating_mul(len.into()), + CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()), Caller => s.caller, #[cfg(feature = "unstable-interface")] IsContract => s.is_contract, @@ -250,7 +249,6 @@ impl RuntimeCosts { Now => s.now, WeightToFee => s.weight_to_fee, InputBase => s.input, - InputCopyOut(len) => s.input_per_byte.saturating_mul(len.into()), Return(len) => s.r#return.saturating_add(s.return_per_byte.saturating_mul(len.into())), Terminate => s.terminate, Random => s.random, @@ -277,18 +275,16 @@ impl RuntimeCosts { .take_storage .saturating_add(s.take_storage_per_byte.saturating_mul(len.into())), Transfer => s.transfer, - CallBase(len) => - s.call.saturating_add(s.call_per_input_byte.saturating_mul(len.into())), - CallSurchargeTransfer => s.call_transfer_surcharge, - CallCopyOut(len) => s.call_per_output_byte.saturating_mul(len.into()), + CallBase => s.call, #[cfg(feature = "unstable-interface")] - DelegateCallBase(len) => - s.delegate_call.saturating_add(s.call_per_input_byte.saturating_mul(len.into())), + DelegateCallBase => s.delegate_call, + CallSurchargeTransfer => s.call_transfer_surcharge, + CallInputCloned(len) => s.call_per_cloned_byte.saturating_mul(len.into()), InstantiateBase { input_data_len, salt_len } => s .instantiate - .saturating_add(s.instantiate_per_input_byte.saturating_mul(input_data_len.into())) + .saturating_add(s.return_per_byte.saturating_mul(input_data_len.into())) .saturating_add(s.instantiate_per_salt_byte.saturating_mul(salt_len.into())), - InstantiateCopyOut(len) => s.instantiate_per_output_byte.saturating_mul(len.into()), + InstantiateSurchargeTransfer => s.instantiate_transfer_surcharge, HashSha256(len) => s .hash_sha2_256 .saturating_add(s.hash_sha2_256_per_byte.saturating_mul(len.into())), @@ -304,8 +300,7 @@ impl RuntimeCosts { #[cfg(feature = "unstable-interface")] EcdsaRecovery => s.ecdsa_recover, ChainExtension(amount) => amount, - #[cfg(feature = "unstable-interface")] - CopyIn(len) => s.return_per_byte.saturating_mul(len.into()), + #[cfg(feature = "unstable-interface")] CallRuntime(weight) => weight, #[cfg(feature = "unstable-interface")] @@ -319,6 +314,17 @@ impl RuntimeCosts { } } +/// Same as [`Runtime::charge_gas`]. +/// +/// We need this access as a macro because sometimes hiding the lifetimes behind +/// a function won't work out. +macro_rules! charge_gas { + ($runtime:expr, $costs:expr) => {{ + let token = $costs.token(&$runtime.ext.schedule().host_fn_weights); + $runtime.ext.gas_meter().charge(token) + }}; +} + #[cfg_attr(test, derive(Debug, PartialEq, Eq))] #[derive(Copy, Clone)] struct RuntimeToken { @@ -339,7 +345,7 @@ where bitflags! { /// Flags used to change the behaviour of `seal_call` and `seal_delegate_call`. - struct CallFlags: u32 { + pub struct CallFlags: u32 { /// Forward the input of current function to the callee. /// /// Supplied input pointers are ignored when set. @@ -393,11 +399,11 @@ enum CallType { } impl CallType { - fn cost(&self, input_data_len: u32) -> RuntimeCosts { + fn cost(&self) -> RuntimeCosts { match self { - CallType::Call { .. } => RuntimeCosts::CallBase(input_data_len), + CallType::Call { .. } => RuntimeCosts::CallBase, #[cfg(feature = "unstable-interface")] - CallType::DelegateCall { .. } => RuntimeCosts::DelegateCallBase(input_data_len), + CallType::DelegateCall { .. } => RuntimeCosts::DelegateCallBase, } } } @@ -493,8 +499,7 @@ where /// /// Returns `Err(HostError)` if there is not enough gas. pub fn charge_gas(&mut self, costs: RuntimeCosts) -> Result { - let token = costs.token(&self.ext.schedule().host_fn_weights); - self.ext.gas_meter().charge(token) + charge_gas!(self, costs) } /// Adjust a previously charged amount down to its actual amount. @@ -734,12 +739,15 @@ where output_ptr: u32, output_len_ptr: u32, ) -> Result { - self.charge_gas(call_type.cost(input_data_len))?; + self.charge_gas(call_type.cost())?; let input_data = if flags.contains(CallFlags::CLONE_INPUT) { - self.input_data.as_ref().ok_or_else(|| Error::::InputForwarded)?.clone() + let input = self.input_data.as_ref().ok_or_else(|| Error::::InputForwarded)?; + charge_gas!(self, RuntimeCosts::CallInputCloned(input.len() as u32))?; + input.clone() } else if flags.contains(CallFlags::FORWARD_INPUT) { self.input_data.take().ok_or_else(|| Error::::InputForwarded)? } else { + self.charge_gas(RuntimeCosts::CopyFromContract(input_data_len))?; self.read_sandbox_memory(input_data_ptr, input_data_len)? }; @@ -782,7 +790,7 @@ where if let Ok(output) = &call_outcome { self.write_sandbox_output(output_ptr, output_len_ptr, &output.data, true, |len| { - Some(RuntimeCosts::CallCopyOut(len)) + Some(RuntimeCosts::CopyToContract(len)) })?; } Ok(Runtime::::exec_into_return_code(call_outcome)?) @@ -803,8 +811,11 @@ where salt_len: u32, ) -> Result { self.charge_gas(RuntimeCosts::InstantiateBase { input_data_len, salt_len })?; - let code_hash: CodeHash<::T> = self.read_sandbox_memory_as(code_hash_ptr)?; let value: BalanceOf<::T> = self.read_sandbox_memory_as(value_ptr)?; + if value > 0u32.into() { + self.charge_gas(RuntimeCosts::InstantiateSurchargeTransfer)?; + } + let code_hash: CodeHash<::T> = self.read_sandbox_memory_as(code_hash_ptr)?; let input_data = self.read_sandbox_memory(input_data_ptr, input_data_len)?; let salt = self.read_sandbox_memory(salt_ptr, salt_len)?; let instantiate_outcome = self.ext.instantiate(gas, code_hash, value, input_data, &salt); @@ -819,7 +830,7 @@ where )?; } self.write_sandbox_output(output_ptr, output_len_ptr, &output.data, true, |len| { - Some(RuntimeCosts::InstantiateCopyOut(len)) + Some(RuntimeCosts::CopyToContract(len)) })?; } Ok(Runtime::::exec_into_return_code(instantiate_outcome.map(|(_, retval)| retval))?) @@ -1302,7 +1313,7 @@ define_env!(Env, , ctx.charge_gas(RuntimeCosts::InputBase)?; if let Some(input) = ctx.input_data.take() { ctx.write_sandbox_output(out_ptr, out_len_ptr, &input, false, |len| { - Some(RuntimeCosts::InputCopyOut(len)) + Some(RuntimeCosts::CopyToContract(len)) })?; ctx.input_data = Some(input); Ok(()) @@ -1911,7 +1922,7 @@ define_env!(Env, , // deploy a contract using it to a production chain. [__unstable__] seal_call_runtime(ctx, call_ptr: u32, call_len: u32) -> ReturnCode => { use frame_support::{dispatch::GetDispatchInfo, weights::extract_actual_weight}; - ctx.charge_gas(RuntimeCosts::CopyIn(call_len))?; + ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?; let call: ::Call = ctx.read_sandbox_memory_as_unbounded( call_ptr, call_len )?; diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index bf35ce511ab26..c43e98bb8ac4b 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-02-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-02-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -89,9 +89,9 @@ pub trait WeightInfo { fn seal_transfer(r: u32, ) -> Weight; fn seal_call(r: u32, ) -> Weight; fn seal_delegate_call(r: u32, ) -> Weight; - fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight; + fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight; fn seal_instantiate(r: u32, ) -> Weight; - fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight; + fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight; fn seal_hash_sha2_256(r: u32, ) -> Weight; fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight; fn seal_hash_keccak_256(r: u32, ) -> Weight; @@ -160,32 +160,32 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_590_000 as Weight) + (1_560_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (9_975_000 as Weight) + (7_843_000 as Weight) // Standard Error: 0 - .saturating_add((724_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((749_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (7_415_000 as Weight) - // Standard Error: 4_000 - .saturating_add((2_303_000 as Weight).saturating_mul(q as Weight)) + (3_228_000 as Weight) + // Standard Error: 5_000 + .saturating_add((2_257_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (18_519_000 as Weight) - // Standard Error: 36_000 - .saturating_add((66_661_000 as Weight).saturating_mul(c as Weight)) + (20_531_000 as Weight) + // Standard Error: 34_000 + .saturating_add((66_014_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -194,9 +194,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (210_319_000 as Weight) - // Standard Error: 41_000 - .saturating_add((54_802_000 as Weight).saturating_mul(c as Weight)) + (295_703_000 as Weight) + // Standard Error: 53_000 + .saturating_add((57_661_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -208,11 +208,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (220_394_000 as Weight) - // Standard Error: 129_000 - .saturating_add((145_155_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 8_000 - .saturating_add((1_741_000 as Weight).saturating_mul(s as Weight)) + (332_572_000 as Weight) + // Standard Error: 125_000 + .saturating_add((149_095_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 7_000 + .saturating_add((1_779_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -223,9 +223,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (171_438_000 as Weight) + (222_992_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_721_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_759_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -234,7 +234,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (139_529_000 as Weight) + (189_003_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -242,9 +242,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (51_040_000 as Weight) - // Standard Error: 38_000 - .saturating_add((65_886_000 as Weight).saturating_mul(c as Weight)) + (52_521_000 as Weight) + // Standard Error: 36_000 + .saturating_add((66_486_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -252,7 +252,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_347_000 as Weight) + (24_705_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -261,9 +261,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (217_164_000 as Weight) - // Standard Error: 89_000 - .saturating_add((48_023_000 as Weight).saturating_mul(r as Weight)) + (300_165_000 as Weight) + // Standard Error: 125_000 + .saturating_add((49_828_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -272,9 +272,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (81_537_000 as Weight) - // Standard Error: 847_000 - .saturating_add((367_429_000 as Weight).saturating_mul(r as Weight)) + (179_488_000 as Weight) + // Standard Error: 718_000 + .saturating_add((375_855_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -284,9 +284,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (214_798_000 as Weight) - // Standard Error: 56_000 - .saturating_add((21_100_000 as Weight).saturating_mul(r as Weight)) + (295_198_000 as Weight) + // Standard Error: 79_000 + .saturating_add((21_948_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -295,9 +295,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (216_615_000 as Weight) - // Standard Error: 75_000 - .saturating_add((48_054_000 as Weight).saturating_mul(r as Weight)) + (300_366_000 as Weight) + // Standard Error: 111_000 + .saturating_add((49_435_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -306,9 +306,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (218_034_000 as Weight) + (299_800_000 as Weight) // Standard Error: 87_000 - .saturating_add((47_594_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((49_002_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -317,9 +317,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (221_980_000 as Weight) - // Standard Error: 135_000 - .saturating_add((135_618_000 as Weight).saturating_mul(r as Weight)) + (303_057_000 as Weight) + // Standard Error: 175_000 + .saturating_add((139_293_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -328,9 +328,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (217_623_000 as Weight) - // Standard Error: 86_000 - .saturating_add((47_656_000 as Weight).saturating_mul(r as Weight)) + (299_754_000 as Weight) + // Standard Error: 93_000 + .saturating_add((48_945_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -339,9 +339,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (216_826_000 as Weight) - // Standard Error: 88_000 - .saturating_add((47_644_000 as Weight).saturating_mul(r as Weight)) + (302_229_000 as Weight) + // Standard Error: 128_000 + .saturating_add((49_007_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -350,9 +350,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (219_487_000 as Weight) - // Standard Error: 90_000 - .saturating_add((47_167_000 as Weight).saturating_mul(r as Weight)) + (300_772_000 as Weight) + // Standard Error: 114_000 + .saturating_add((48_794_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -361,9 +361,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (218_953_000 as Weight) - // Standard Error: 95_000 - .saturating_add((47_458_000 as Weight).saturating_mul(r as Weight)) + (301_936_000 as Weight) + // Standard Error: 119_000 + .saturating_add((48_839_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -373,9 +373,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (220_132_000 as Weight) - // Standard Error: 144_000 - .saturating_add((120_373_000 as Weight).saturating_mul(r as Weight)) + (304_935_000 as Weight) + // Standard Error: 146_000 + .saturating_add((121_871_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -384,9 +384,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (127_458_000 as Weight) - // Standard Error: 56_000 - .saturating_add((24_015_000 as Weight).saturating_mul(r as Weight)) + (178_176_000 as Weight) + // Standard Error: 52_000 + .saturating_add((24_960_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -395,9 +395,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (220_304_000 as Weight) - // Standard Error: 112_000 - .saturating_add((46_804_000 as Weight).saturating_mul(r as Weight)) + (297_394_000 as Weight) + // Standard Error: 140_000 + .saturating_add((49_199_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -406,9 +406,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (300_916_000 as Weight) - // Standard Error: 8_000 - .saturating_add((10_552_000 as Weight).saturating_mul(n as Weight)) + (374_409_000 as Weight) + // Standard Error: 3_000 + .saturating_add((11_924_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -417,9 +417,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (211_812_000 as Weight) - // Standard Error: 138_000 - .saturating_add((1_698_000 as Weight).saturating_mul(r as Weight)) + (292_278_000 as Weight) + // Standard Error: 114_000 + .saturating_add((1_474_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -428,9 +428,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (213_994_000 as Weight) + (294_714_000 as Weight) // Standard Error: 0 - .saturating_add((176_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((230_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -441,9 +441,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (215_173_000 as Weight) - // Standard Error: 708_000 - .saturating_add((52_509_000 as Weight).saturating_mul(r as Weight)) + (297_589_000 as Weight) + // Standard Error: 2_835_000 + .saturating_add((53_498_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -455,9 +455,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (219_521_000 as Weight) - // Standard Error: 171_000 - .saturating_add((156_228_000 as Weight).saturating_mul(r as Weight)) + (296_371_000 as Weight) + // Standard Error: 220_000 + .saturating_add((160_881_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -466,9 +466,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (227_624_000 as Weight) - // Standard Error: 193_000 - .saturating_add((285_058_000 as Weight).saturating_mul(r as Weight)) + (308_401_000 as Weight) + // Standard Error: 202_000 + .saturating_add((277_771_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -478,11 +478,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (503_312_000 as Weight) - // Standard Error: 1_729_000 - .saturating_add((288_009_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 340_000 - .saturating_add((80_936_000 as Weight).saturating_mul(n as Weight)) + (625_100_000 as Weight) + // Standard Error: 2_053_000 + .saturating_add((284_765_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 404_000 + .saturating_add((85_893_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -493,17 +493,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (132_096_000 as Weight) - // Standard Error: 73_000 - .saturating_add((40_337_000 as Weight).saturating_mul(r as Weight)) + (182_141_000 as Weight) + // Standard Error: 134_000 + .saturating_add((41_928_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (52_622_000 as Weight) - // Standard Error: 1_006_000 - .saturating_add((404_716_000 as Weight).saturating_mul(r as Weight)) + (139_030_000 as Weight) + // Standard Error: 1_038_000 + .saturating_add((405_168_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -511,25 +511,25 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (601_324_000 as Weight) - // Standard Error: 264_000 - .saturating_add((27_943_000 as Weight).saturating_mul(n as Weight)) + (689_591_000 as Weight) + // Standard Error: 275_000 + .saturating_add((31_438_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (626_752_000 as Weight) - // Standard Error: 292_000 - .saturating_add((10_616_000 as Weight).saturating_mul(n as Weight)) + (709_965_000 as Weight) + // Standard Error: 340_000 + .saturating_add((11_182_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (80_138_000 as Weight) - // Standard Error: 933_000 - .saturating_add((382_949_000 as Weight).saturating_mul(r as Weight)) + (169_937_000 as Weight) + // Standard Error: 883_000 + .saturating_add((389_090_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -537,51 +537,51 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (603_984_000 as Weight) - // Standard Error: 242_000 - .saturating_add((10_712_000 as Weight).saturating_mul(n as Weight)) + (695_589_000 as Weight) + // Standard Error: 268_000 + .saturating_add((10_530_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (113_136_000 as Weight) - // Standard Error: 635_000 - .saturating_add((324_706_000 as Weight).saturating_mul(r as Weight)) + (195_080_000 as Weight) + // Standard Error: 607_000 + .saturating_add((328_903_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (562_781_000 as Weight) - // Standard Error: 354_000 - .saturating_add((63_275_000 as Weight).saturating_mul(n as Weight)) + (647_422_000 as Weight) + // Standard Error: 361_000 + .saturating_add((68_849_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (112_237_000 as Weight) - // Standard Error: 655_000 - .saturating_add((296_653_000 as Weight).saturating_mul(r as Weight)) + (198_907_000 as Weight) + // Standard Error: 658_000 + .saturating_add((295_368_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (520_002_000 as Weight) - // Standard Error: 232_000 - .saturating_add((9_726_000 as Weight).saturating_mul(n as Weight)) + (599_284_000 as Weight) + // Standard Error: 243_000 + .saturating_add((9_923_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (87_232_000 as Weight) - // Standard Error: 920_000 - .saturating_add((415_305_000 as Weight).saturating_mul(r as Weight)) + (170_700_000 as Weight) + // Standard Error: 887_000 + .saturating_add((422_448_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -589,9 +589,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (648_862_000 as Weight) - // Standard Error: 319_000 - .saturating_add((63_991_000 as Weight).saturating_mul(n as Weight)) + (743_584_000 as Weight) + // Standard Error: 403_000 + .saturating_add((69_763_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } @@ -600,9 +600,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (99_621_000 as Weight) - // Standard Error: 1_154_000 - .saturating_add((1_732_052_000 as Weight).saturating_mul(r as Weight)) + (208_815_000 as Weight) + // Standard Error: 1_078_000 + .saturating_add((1_719_660_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -614,8 +614,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 6_293_000 - .saturating_add((19_410_115_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 3_471_000 + .saturating_add((27_917_429_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -627,8 +627,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 7_155_000 - .saturating_add((19_793_614_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 13_012_000 + .saturating_add((28_044_371_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -636,14 +636,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (19_711_861_000 as Weight) - // Standard Error: 55_158_000 - .saturating_add((2_509_755_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 19_000 - .saturating_add((17_808_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 21_000 - .saturating_add((28_104_000 as Weight).saturating_mul(o as Weight)) + fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { + (15_964_304_000 as Weight) + // Standard Error: 19_327_000 + .saturating_add((1_629_626_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 8_000 + .saturating_add((11_992_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -657,38 +655,38 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 47_294_000 - .saturating_add((26_664_406_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 50_849_000 + .saturating_add((35_608_311_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((400 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:102 w:102) + // Storage: System Account (r:101 w:101) // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) - fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (24_447_236_000 as Weight) - // Standard Error: 36_000 - .saturating_add((18_822_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 36_000 - .saturating_add((28_618_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 36_000 - .saturating_add((156_535_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(208 as Weight)) - .saturating_add(T::DbWeight::get().writes(206 as Weight)) + fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { + (19_455_191_000 as Weight) + // Standard Error: 57_478_000 + .saturating_add((786_148_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 27_000 + .saturating_add((160_385_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(207 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) + .saturating_add(T::DbWeight::get().writes(205 as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(t as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (216_091_000 as Weight) + (294_686_000 as Weight) // Standard Error: 123_000 - .saturating_add((79_416_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((81_172_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -697,9 +695,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (223_253_000 as Weight) - // Standard Error: 43_000 - .saturating_add((462_629_000 as Weight).saturating_mul(n as Weight)) + (276_895_000 as Weight) + // Standard Error: 35_000 + .saturating_add((469_007_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -708,9 +706,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (217_285_000 as Weight) - // Standard Error: 147_000 - .saturating_add((91_020_000 as Weight).saturating_mul(r as Weight)) + (295_476_000 as Weight) + // Standard Error: 127_000 + .saturating_add((91_822_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -719,9 +717,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (364_402_000 as Weight) - // Standard Error: 27_000 - .saturating_add((305_342_000 as Weight).saturating_mul(n as Weight)) + (402_456_000 as Weight) + // Standard Error: 19_000 + .saturating_add((311_103_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -730,9 +728,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (214_309_000 as Weight) - // Standard Error: 107_000 - .saturating_add((63_668_000 as Weight).saturating_mul(r as Weight)) + (296_702_000 as Weight) + // Standard Error: 142_000 + .saturating_add((64_431_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -741,9 +739,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (306_968_000 as Weight) - // Standard Error: 13_000 - .saturating_add((118_373_000 as Weight).saturating_mul(n as Weight)) + (375_322_000 as Weight) + // Standard Error: 14_000 + .saturating_add((124_338_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -752,9 +750,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (215_434_000 as Weight) - // Standard Error: 115_000 - .saturating_add((62_560_000 as Weight).saturating_mul(r as Weight)) + (294_158_000 as Weight) + // Standard Error: 148_000 + .saturating_add((64_474_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -763,9 +761,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (226_690_000 as Weight) - // Standard Error: 17_000 - .saturating_add((118_871_000 as Weight).saturating_mul(n as Weight)) + (390_049_000 as Weight) + // Standard Error: 16_000 + .saturating_add((124_330_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -774,9 +772,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (187_068_000 as Weight) - // Standard Error: 1_354_000 - .saturating_add((15_409_805_000 as Weight).saturating_mul(r as Weight)) + (233_346_000 as Weight) + // Standard Error: 1_355_000 + .saturating_add((15_405_070_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -793,259 +791,259 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (74_317_000 as Weight) - // Standard Error: 1_000 - .saturating_add((597_000 as Weight).saturating_mul(r as Weight)) + (119_148_000 as Weight) + // Standard Error: 2_000 + .saturating_add((585_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_303_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_311_000 as Weight).saturating_mul(r as Weight)) + (118_413_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_024_000 as Weight) - // Standard Error: 0 - .saturating_add((1_431_000 as Weight).saturating_mul(r as Weight)) + (118_700_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_415_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (74_108_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_778_000 as Weight).saturating_mul(r as Weight)) + (118_736_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_777_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (73_966_000 as Weight) - // Standard Error: 0 - .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) + (118_277_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_839_000 as Weight) - // Standard Error: 2_000 - .saturating_add((907_000 as Weight).saturating_mul(r as Weight)) + (118_360_000 as Weight) + // Standard Error: 0 + .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_624_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_446_000 as Weight).saturating_mul(r as Weight)) + (118_142_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_439_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_169_000 as Weight) + (118_239_000 as Weight) // Standard Error: 5_000 - .saturating_add((1_602_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_553_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_328_000 as Weight) + (120_801_000 as Weight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (74_771_000 as Weight) - // Standard Error: 22_000 - .saturating_add((17_044_000 as Weight).saturating_mul(r as Weight)) + (118_536_000 as Weight) + // Standard Error: 16_000 + .saturating_add((17_082_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (90_179_000 as Weight) - // Standard Error: 31_000 - .saturating_add((27_305_000 as Weight).saturating_mul(r as Weight)) + (130_467_000 as Weight) + // Standard Error: 30_000 + .saturating_add((28_199_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (117_977_000 as Weight) - // Standard Error: 2_000 - .saturating_add((928_000 as Weight).saturating_mul(p as Weight)) + (164_624_000 as Weight) + // Standard Error: 3_000 + .saturating_add((901_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (75_093_000 as Weight) - // Standard Error: 1_000 - .saturating_add((610_000 as Weight).saturating_mul(r as Weight)) + (119_422_000 as Weight) + // Standard Error: 2_000 + .saturating_add((617_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_793_000 as Weight) - // Standard Error: 1_000 - .saturating_add((676_000 as Weight).saturating_mul(r as Weight)) + (119_747_000 as Weight) + // Standard Error: 2_000 + .saturating_add((668_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_183_000 as Weight) - // Standard Error: 2_000 - .saturating_add((913_000 as Weight).saturating_mul(r as Weight)) + (119_410_000 as Weight) + // Standard Error: 3_000 + .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_079_000 as Weight) + (121_657_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_156_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_160_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (77_063_000 as Weight) + (121_531_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_314_000 as Weight) + (118_340_000 as Weight) // Standard Error: 2_000 - .saturating_add((662_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((674_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_585_000 as Weight) - // Standard Error: 2_291_000 - .saturating_add((174_749_000 as Weight).saturating_mul(r as Weight)) + (118_114_000 as Weight) + // Standard Error: 194_000 + .saturating_add((229_474_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_062_000 as Weight) + (119_160_000 as Weight) // Standard Error: 2_000 - .saturating_add((905_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((890_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_121_000 as Weight) - // Standard Error: 1_000 - .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) + (119_199_000 as Weight) + // Standard Error: 3_000 + .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_519_000 as Weight) - // Standard Error: 2_000 + (119_103_000 as Weight) + // Standard Error: 4_000 .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_357_000 as Weight) - // Standard Error: 1_000 - .saturating_add((914_000 as Weight).saturating_mul(r as Weight)) + (119_033_000 as Weight) + // Standard Error: 3_000 + .saturating_add((917_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_101_000 as Weight) - // Standard Error: 1_000 - .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) + (118_950_000 as Weight) + // Standard Error: 4_000 + .saturating_add((879_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_442_000 as Weight) - // Standard Error: 1_000 - .saturating_add((875_000 as Weight).saturating_mul(r as Weight)) + (118_534_000 as Weight) + // Standard Error: 2_000 + .saturating_add((888_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_247_000 as Weight) - // Standard Error: 1_000 - .saturating_add((891_000 as Weight).saturating_mul(r as Weight)) + (119_108_000 as Weight) + // Standard Error: 2_000 + .saturating_add((881_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (74_091_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + (118_677_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (74_178_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + (118_769_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (74_370_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) - } - fn instr_i64ltu(r: u32, ) -> Weight { - (74_180_000 as Weight) + (118_690_000 as Weight) // Standard Error: 1_000 .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } + fn instr_i64ltu(r: u32, ) -> Weight { + (118_899_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) + } fn instr_i64gts(r: u32, ) -> Weight { - (74_035_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) + (118_519_000 as Weight) + // Standard Error: 6_000 + .saturating_add((1_376_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (74_538_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (119_315_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (74_035_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) + (118_171_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_399_000 as Weight) - // Standard Error: 8_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (118_581_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (73_987_000 as Weight) + (118_673_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_364_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_017_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) + (118_618_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (74_271_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_330_000 as Weight).saturating_mul(r as Weight)) + (118_569_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_016_000 as Weight) - // Standard Error: 0 - .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) + (118_261_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (74_063_000 as Weight) - // Standard Error: 1_000 + (118_542_000 as Weight) + // Standard Error: 2_000 .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (74_094_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_002_000 as Weight).saturating_mul(r as Weight)) + (118_648_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_993_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (73_957_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_045_000 as Weight).saturating_mul(r as Weight)) + (118_378_000 as Weight) + // Standard Error: 0 + .saturating_add((2_057_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (74_067_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_975_000 as Weight).saturating_mul(r as Weight)) + (118_813_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_995_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (74_092_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_035_000 as Weight).saturating_mul(r as Weight)) + (118_697_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_025_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_059_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (118_838_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_332_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (74_122_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) + (118_641_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (74_296_000 as Weight) + (118_551_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (73_810_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) + (118_603_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (74_101_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_407_000 as Weight).saturating_mul(r as Weight)) + (118_885_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (74_076_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) + (118_602_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (74_082_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + (118_733_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (74_054_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (118_920_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) } } @@ -1053,32 +1051,32 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_590_000 as Weight) + (1_560_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (9_975_000 as Weight) + (7_843_000 as Weight) // Standard Error: 0 - .saturating_add((724_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((749_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (7_415_000 as Weight) - // Standard Error: 4_000 - .saturating_add((2_303_000 as Weight).saturating_mul(q as Weight)) + (3_228_000 as Weight) + // Standard Error: 5_000 + .saturating_add((2_257_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (18_519_000 as Weight) - // Standard Error: 36_000 - .saturating_add((66_661_000 as Weight).saturating_mul(c as Weight)) + (20_531_000 as Weight) + // Standard Error: 34_000 + .saturating_add((66_014_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1087,9 +1085,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (210_319_000 as Weight) - // Standard Error: 41_000 - .saturating_add((54_802_000 as Weight).saturating_mul(c as Weight)) + (295_703_000 as Weight) + // Standard Error: 53_000 + .saturating_add((57_661_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1101,11 +1099,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (220_394_000 as Weight) - // Standard Error: 129_000 - .saturating_add((145_155_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 8_000 - .saturating_add((1_741_000 as Weight).saturating_mul(s as Weight)) + (332_572_000 as Weight) + // Standard Error: 125_000 + .saturating_add((149_095_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 7_000 + .saturating_add((1_779_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1116,9 +1114,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (171_438_000 as Weight) + (222_992_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_721_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_759_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1127,7 +1125,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (139_529_000 as Weight) + (189_003_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1135,9 +1133,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (51_040_000 as Weight) - // Standard Error: 38_000 - .saturating_add((65_886_000 as Weight).saturating_mul(c as Weight)) + (52_521_000 as Weight) + // Standard Error: 36_000 + .saturating_add((66_486_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1145,7 +1143,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_347_000 as Weight) + (24_705_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1154,9 +1152,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (217_164_000 as Weight) - // Standard Error: 89_000 - .saturating_add((48_023_000 as Weight).saturating_mul(r as Weight)) + (300_165_000 as Weight) + // Standard Error: 125_000 + .saturating_add((49_828_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1165,9 +1163,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (81_537_000 as Weight) - // Standard Error: 847_000 - .saturating_add((367_429_000 as Weight).saturating_mul(r as Weight)) + (179_488_000 as Weight) + // Standard Error: 718_000 + .saturating_add((375_855_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1177,9 +1175,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (214_798_000 as Weight) - // Standard Error: 56_000 - .saturating_add((21_100_000 as Weight).saturating_mul(r as Weight)) + (295_198_000 as Weight) + // Standard Error: 79_000 + .saturating_add((21_948_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1188,9 +1186,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (216_615_000 as Weight) - // Standard Error: 75_000 - .saturating_add((48_054_000 as Weight).saturating_mul(r as Weight)) + (300_366_000 as Weight) + // Standard Error: 111_000 + .saturating_add((49_435_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1199,9 +1197,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (218_034_000 as Weight) + (299_800_000 as Weight) // Standard Error: 87_000 - .saturating_add((47_594_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((49_002_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1210,9 +1208,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (221_980_000 as Weight) - // Standard Error: 135_000 - .saturating_add((135_618_000 as Weight).saturating_mul(r as Weight)) + (303_057_000 as Weight) + // Standard Error: 175_000 + .saturating_add((139_293_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1221,9 +1219,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (217_623_000 as Weight) - // Standard Error: 86_000 - .saturating_add((47_656_000 as Weight).saturating_mul(r as Weight)) + (299_754_000 as Weight) + // Standard Error: 93_000 + .saturating_add((48_945_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1232,9 +1230,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (216_826_000 as Weight) - // Standard Error: 88_000 - .saturating_add((47_644_000 as Weight).saturating_mul(r as Weight)) + (302_229_000 as Weight) + // Standard Error: 128_000 + .saturating_add((49_007_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1243,9 +1241,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (219_487_000 as Weight) - // Standard Error: 90_000 - .saturating_add((47_167_000 as Weight).saturating_mul(r as Weight)) + (300_772_000 as Weight) + // Standard Error: 114_000 + .saturating_add((48_794_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1254,9 +1252,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (218_953_000 as Weight) - // Standard Error: 95_000 - .saturating_add((47_458_000 as Weight).saturating_mul(r as Weight)) + (301_936_000 as Weight) + // Standard Error: 119_000 + .saturating_add((48_839_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1266,9 +1264,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (220_132_000 as Weight) - // Standard Error: 144_000 - .saturating_add((120_373_000 as Weight).saturating_mul(r as Weight)) + (304_935_000 as Weight) + // Standard Error: 146_000 + .saturating_add((121_871_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1277,9 +1275,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (127_458_000 as Weight) - // Standard Error: 56_000 - .saturating_add((24_015_000 as Weight).saturating_mul(r as Weight)) + (178_176_000 as Weight) + // Standard Error: 52_000 + .saturating_add((24_960_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1288,9 +1286,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (220_304_000 as Weight) - // Standard Error: 112_000 - .saturating_add((46_804_000 as Weight).saturating_mul(r as Weight)) + (297_394_000 as Weight) + // Standard Error: 140_000 + .saturating_add((49_199_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1299,9 +1297,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (300_916_000 as Weight) - // Standard Error: 8_000 - .saturating_add((10_552_000 as Weight).saturating_mul(n as Weight)) + (374_409_000 as Weight) + // Standard Error: 3_000 + .saturating_add((11_924_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1310,9 +1308,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (211_812_000 as Weight) - // Standard Error: 138_000 - .saturating_add((1_698_000 as Weight).saturating_mul(r as Weight)) + (292_278_000 as Weight) + // Standard Error: 114_000 + .saturating_add((1_474_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1321,9 +1319,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (213_994_000 as Weight) + (294_714_000 as Weight) // Standard Error: 0 - .saturating_add((176_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((230_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1334,9 +1332,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (215_173_000 as Weight) - // Standard Error: 708_000 - .saturating_add((52_509_000 as Weight).saturating_mul(r as Weight)) + (297_589_000 as Weight) + // Standard Error: 2_835_000 + .saturating_add((53_498_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1348,9 +1346,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (219_521_000 as Weight) - // Standard Error: 171_000 - .saturating_add((156_228_000 as Weight).saturating_mul(r as Weight)) + (296_371_000 as Weight) + // Standard Error: 220_000 + .saturating_add((160_881_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1359,9 +1357,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (227_624_000 as Weight) - // Standard Error: 193_000 - .saturating_add((285_058_000 as Weight).saturating_mul(r as Weight)) + (308_401_000 as Weight) + // Standard Error: 202_000 + .saturating_add((277_771_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1371,11 +1369,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (503_312_000 as Weight) - // Standard Error: 1_729_000 - .saturating_add((288_009_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 340_000 - .saturating_add((80_936_000 as Weight).saturating_mul(n as Weight)) + (625_100_000 as Weight) + // Standard Error: 2_053_000 + .saturating_add((284_765_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 404_000 + .saturating_add((85_893_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1386,17 +1384,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (132_096_000 as Weight) - // Standard Error: 73_000 - .saturating_add((40_337_000 as Weight).saturating_mul(r as Weight)) + (182_141_000 as Weight) + // Standard Error: 134_000 + .saturating_add((41_928_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (52_622_000 as Weight) - // Standard Error: 1_006_000 - .saturating_add((404_716_000 as Weight).saturating_mul(r as Weight)) + (139_030_000 as Weight) + // Standard Error: 1_038_000 + .saturating_add((405_168_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1404,25 +1402,25 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (601_324_000 as Weight) - // Standard Error: 264_000 - .saturating_add((27_943_000 as Weight).saturating_mul(n as Weight)) + (689_591_000 as Weight) + // Standard Error: 275_000 + .saturating_add((31_438_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (626_752_000 as Weight) - // Standard Error: 292_000 - .saturating_add((10_616_000 as Weight).saturating_mul(n as Weight)) + (709_965_000 as Weight) + // Standard Error: 340_000 + .saturating_add((11_182_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (80_138_000 as Weight) - // Standard Error: 933_000 - .saturating_add((382_949_000 as Weight).saturating_mul(r as Weight)) + (169_937_000 as Weight) + // Standard Error: 883_000 + .saturating_add((389_090_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1430,51 +1428,51 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (603_984_000 as Weight) - // Standard Error: 242_000 - .saturating_add((10_712_000 as Weight).saturating_mul(n as Weight)) + (695_589_000 as Weight) + // Standard Error: 268_000 + .saturating_add((10_530_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (113_136_000 as Weight) - // Standard Error: 635_000 - .saturating_add((324_706_000 as Weight).saturating_mul(r as Weight)) + (195_080_000 as Weight) + // Standard Error: 607_000 + .saturating_add((328_903_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (562_781_000 as Weight) - // Standard Error: 354_000 - .saturating_add((63_275_000 as Weight).saturating_mul(n as Weight)) + (647_422_000 as Weight) + // Standard Error: 361_000 + .saturating_add((68_849_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (112_237_000 as Weight) - // Standard Error: 655_000 - .saturating_add((296_653_000 as Weight).saturating_mul(r as Weight)) + (198_907_000 as Weight) + // Standard Error: 658_000 + .saturating_add((295_368_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (520_002_000 as Weight) - // Standard Error: 232_000 - .saturating_add((9_726_000 as Weight).saturating_mul(n as Weight)) + (599_284_000 as Weight) + // Standard Error: 243_000 + .saturating_add((9_923_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (87_232_000 as Weight) - // Standard Error: 920_000 - .saturating_add((415_305_000 as Weight).saturating_mul(r as Weight)) + (170_700_000 as Weight) + // Standard Error: 887_000 + .saturating_add((422_448_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1482,9 +1480,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (648_862_000 as Weight) - // Standard Error: 319_000 - .saturating_add((63_991_000 as Weight).saturating_mul(n as Weight)) + (743_584_000 as Weight) + // Standard Error: 403_000 + .saturating_add((69_763_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } @@ -1493,9 +1491,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (99_621_000 as Weight) - // Standard Error: 1_154_000 - .saturating_add((1_732_052_000 as Weight).saturating_mul(r as Weight)) + (208_815_000 as Weight) + // Standard Error: 1_078_000 + .saturating_add((1_719_660_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1507,8 +1505,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 6_293_000 - .saturating_add((19_410_115_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 3_471_000 + .saturating_add((27_917_429_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1520,8 +1518,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 7_155_000 - .saturating_add((19_793_614_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 13_012_000 + .saturating_add((28_044_371_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1529,14 +1527,12 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (19_711_861_000 as Weight) - // Standard Error: 55_158_000 - .saturating_add((2_509_755_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 19_000 - .saturating_add((17_808_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 21_000 - .saturating_add((28_104_000 as Weight).saturating_mul(o as Weight)) + fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { + (15_964_304_000 as Weight) + // Standard Error: 19_327_000 + .saturating_add((1_629_626_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 8_000 + .saturating_add((11_992_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1550,38 +1546,38 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 47_294_000 - .saturating_add((26_664_406_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 50_849_000 + .saturating_add((35_608_311_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((400 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:102 w:102) + // Storage: System Account (r:101 w:101) // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) - fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (24_447_236_000 as Weight) - // Standard Error: 36_000 - .saturating_add((18_822_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 36_000 - .saturating_add((28_618_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 36_000 - .saturating_add((156_535_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(208 as Weight)) - .saturating_add(RocksDbWeight::get().writes(206 as Weight)) + fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { + (19_455_191_000 as Weight) + // Standard Error: 57_478_000 + .saturating_add((786_148_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 27_000 + .saturating_add((160_385_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(207 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) + .saturating_add(RocksDbWeight::get().writes(205 as Weight)) + .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(t as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (216_091_000 as Weight) + (294_686_000 as Weight) // Standard Error: 123_000 - .saturating_add((79_416_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((81_172_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1590,9 +1586,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (223_253_000 as Weight) - // Standard Error: 43_000 - .saturating_add((462_629_000 as Weight).saturating_mul(n as Weight)) + (276_895_000 as Weight) + // Standard Error: 35_000 + .saturating_add((469_007_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1601,9 +1597,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (217_285_000 as Weight) - // Standard Error: 147_000 - .saturating_add((91_020_000 as Weight).saturating_mul(r as Weight)) + (295_476_000 as Weight) + // Standard Error: 127_000 + .saturating_add((91_822_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1612,9 +1608,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (364_402_000 as Weight) - // Standard Error: 27_000 - .saturating_add((305_342_000 as Weight).saturating_mul(n as Weight)) + (402_456_000 as Weight) + // Standard Error: 19_000 + .saturating_add((311_103_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1623,9 +1619,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (214_309_000 as Weight) - // Standard Error: 107_000 - .saturating_add((63_668_000 as Weight).saturating_mul(r as Weight)) + (296_702_000 as Weight) + // Standard Error: 142_000 + .saturating_add((64_431_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1634,9 +1630,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (306_968_000 as Weight) - // Standard Error: 13_000 - .saturating_add((118_373_000 as Weight).saturating_mul(n as Weight)) + (375_322_000 as Weight) + // Standard Error: 14_000 + .saturating_add((124_338_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1645,9 +1641,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (215_434_000 as Weight) - // Standard Error: 115_000 - .saturating_add((62_560_000 as Weight).saturating_mul(r as Weight)) + (294_158_000 as Weight) + // Standard Error: 148_000 + .saturating_add((64_474_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1656,9 +1652,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (226_690_000 as Weight) - // Standard Error: 17_000 - .saturating_add((118_871_000 as Weight).saturating_mul(n as Weight)) + (390_049_000 as Weight) + // Standard Error: 16_000 + .saturating_add((124_330_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1667,9 +1663,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (187_068_000 as Weight) - // Standard Error: 1_354_000 - .saturating_add((15_409_805_000 as Weight).saturating_mul(r as Weight)) + (233_346_000 as Weight) + // Standard Error: 1_355_000 + .saturating_add((15_405_070_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1686,258 +1682,258 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (74_317_000 as Weight) - // Standard Error: 1_000 - .saturating_add((597_000 as Weight).saturating_mul(r as Weight)) + (119_148_000 as Weight) + // Standard Error: 2_000 + .saturating_add((585_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_303_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_311_000 as Weight).saturating_mul(r as Weight)) + (118_413_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_024_000 as Weight) - // Standard Error: 0 - .saturating_add((1_431_000 as Weight).saturating_mul(r as Weight)) + (118_700_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_415_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (74_108_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_778_000 as Weight).saturating_mul(r as Weight)) + (118_736_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_777_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (73_966_000 as Weight) - // Standard Error: 0 - .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) + (118_277_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_839_000 as Weight) - // Standard Error: 2_000 - .saturating_add((907_000 as Weight).saturating_mul(r as Weight)) + (118_360_000 as Weight) + // Standard Error: 0 + .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_624_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_446_000 as Weight).saturating_mul(r as Weight)) + (118_142_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_439_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_169_000 as Weight) + (118_239_000 as Weight) // Standard Error: 5_000 - .saturating_add((1_602_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_553_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_328_000 as Weight) + (120_801_000 as Weight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (74_771_000 as Weight) - // Standard Error: 22_000 - .saturating_add((17_044_000 as Weight).saturating_mul(r as Weight)) + (118_536_000 as Weight) + // Standard Error: 16_000 + .saturating_add((17_082_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (90_179_000 as Weight) - // Standard Error: 31_000 - .saturating_add((27_305_000 as Weight).saturating_mul(r as Weight)) + (130_467_000 as Weight) + // Standard Error: 30_000 + .saturating_add((28_199_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (117_977_000 as Weight) - // Standard Error: 2_000 - .saturating_add((928_000 as Weight).saturating_mul(p as Weight)) + (164_624_000 as Weight) + // Standard Error: 3_000 + .saturating_add((901_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (75_093_000 as Weight) - // Standard Error: 1_000 - .saturating_add((610_000 as Weight).saturating_mul(r as Weight)) + (119_422_000 as Weight) + // Standard Error: 2_000 + .saturating_add((617_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_793_000 as Weight) - // Standard Error: 1_000 - .saturating_add((676_000 as Weight).saturating_mul(r as Weight)) + (119_747_000 as Weight) + // Standard Error: 2_000 + .saturating_add((668_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_183_000 as Weight) - // Standard Error: 2_000 - .saturating_add((913_000 as Weight).saturating_mul(r as Weight)) + (119_410_000 as Weight) + // Standard Error: 3_000 + .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_079_000 as Weight) + (121_657_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_156_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_160_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (77_063_000 as Weight) + (121_531_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_314_000 as Weight) + (118_340_000 as Weight) // Standard Error: 2_000 - .saturating_add((662_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((674_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_585_000 as Weight) - // Standard Error: 2_291_000 - .saturating_add((174_749_000 as Weight).saturating_mul(r as Weight)) + (118_114_000 as Weight) + // Standard Error: 194_000 + .saturating_add((229_474_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_062_000 as Weight) + (119_160_000 as Weight) // Standard Error: 2_000 - .saturating_add((905_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((890_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_121_000 as Weight) - // Standard Error: 1_000 - .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) + (119_199_000 as Weight) + // Standard Error: 3_000 + .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_519_000 as Weight) - // Standard Error: 2_000 + (119_103_000 as Weight) + // Standard Error: 4_000 .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_357_000 as Weight) - // Standard Error: 1_000 - .saturating_add((914_000 as Weight).saturating_mul(r as Weight)) + (119_033_000 as Weight) + // Standard Error: 3_000 + .saturating_add((917_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_101_000 as Weight) - // Standard Error: 1_000 - .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) + (118_950_000 as Weight) + // Standard Error: 4_000 + .saturating_add((879_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_442_000 as Weight) - // Standard Error: 1_000 - .saturating_add((875_000 as Weight).saturating_mul(r as Weight)) + (118_534_000 as Weight) + // Standard Error: 2_000 + .saturating_add((888_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_247_000 as Weight) - // Standard Error: 1_000 - .saturating_add((891_000 as Weight).saturating_mul(r as Weight)) + (119_108_000 as Weight) + // Standard Error: 2_000 + .saturating_add((881_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (74_091_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + (118_677_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (74_178_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + (118_769_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (74_370_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) - } - fn instr_i64ltu(r: u32, ) -> Weight { - (74_180_000 as Weight) + (118_690_000 as Weight) // Standard Error: 1_000 .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } + fn instr_i64ltu(r: u32, ) -> Weight { + (118_899_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) + } fn instr_i64gts(r: u32, ) -> Weight { - (74_035_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) + (118_519_000 as Weight) + // Standard Error: 6_000 + .saturating_add((1_376_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (74_538_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (119_315_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (74_035_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) + (118_171_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_399_000 as Weight) - // Standard Error: 8_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (118_581_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (73_987_000 as Weight) + (118_673_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_364_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_017_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) + (118_618_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (74_271_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_330_000 as Weight).saturating_mul(r as Weight)) + (118_569_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_016_000 as Weight) - // Standard Error: 0 - .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) + (118_261_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (74_063_000 as Weight) - // Standard Error: 1_000 + (118_542_000 as Weight) + // Standard Error: 2_000 .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (74_094_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_002_000 as Weight).saturating_mul(r as Weight)) + (118_648_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_993_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (73_957_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_045_000 as Weight).saturating_mul(r as Weight)) + (118_378_000 as Weight) + // Standard Error: 0 + .saturating_add((2_057_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (74_067_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_975_000 as Weight).saturating_mul(r as Weight)) + (118_813_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_995_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (74_092_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_035_000 as Weight).saturating_mul(r as Weight)) + (118_697_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_025_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_059_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (118_838_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_332_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (74_122_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) + (118_641_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (74_296_000 as Weight) + (118_551_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (73_810_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) + (118_603_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (74_101_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_407_000 as Weight).saturating_mul(r as Weight)) + (118_885_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (74_076_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) + (118_602_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (74_082_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + (118_733_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (74_054_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (118_920_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) } } From fd2c39705b5781100d6b3628a7e8cf5fed6d340d Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 15 Feb 2022 20:53:45 +0900 Subject: [PATCH 0516/1472] Enable the `parking_lot` feature for `tokio` (#10855) --- bin/node/cli/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 4b14fe31e5a56..74d62ba78c2a0 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -126,7 +126,7 @@ platforms = "2.0" async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" criterion = { version = "0.3.5", features = ["async_tokio"] } -tokio = { version = "1.15", features = ["macros", "time"] } +tokio = { version = "1.15", features = ["macros", "time", "parking_lot"] } jsonrpsee-ws-client = "0.4.1" wait-timeout = "0.2" remote-externalities = { path = "../../../utils/frame/remote-externalities" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 5375400056faf..3fd65d23eb888 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -28,7 +28,7 @@ serde = "1.0.136" serde_json = "1.0.74" thiserror = "1.0.30" tiny-bip39 = "0.8.2" -tokio = { version = "1.15", features = ["signal", "rt-multi-thread"] } +tokio = { version = "1.15", features = ["signal", "rt-multi-thread", "parking_lot"] } parity-scale-codec = "2.3.1" sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index 4246168c3e66c..954bf602f85d6 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -19,7 +19,7 @@ pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} serde_json = "1.0.74" -tokio = "1.15" +tokio = { version = "1.15", features = ["parking_lot"] } http = { package = "jsonrpc-http-server", version = "18.0.0" } ipc = { package = "jsonrpc-ipc-server", version = "18.0.0" } ws = { package = "jsonrpc-ws-server", version = "18.0.0" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 8424fe31a810a..55ca01a2284a5 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -78,7 +78,7 @@ parity-util-mem = { version = "0.10.2", default-features = false, features = [ "primitive-types", ] } async-trait = "0.1.50" -tokio = { version = "1.15", features = ["time", "rt-multi-thread"] } +tokio = { version = "1.15", features = ["time", "rt-multi-thread", "parking_lot"] } tempfile = "3.1.0" directories = "4.0.1" diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 27b5f94305fdd..264cc44d16024 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -18,7 +18,7 @@ prometheus = { version = "0.13.0", default-features = false } futures-util = { version = "0.3.19", default-features = false, features = ["io"] } thiserror = "1.0" async-std = { version = "1.10.0", features = ["unstable"] } -tokio = "1.15" +tokio = { version = "1.15", features = ["parking_lot"] } hyper = { version = "0.14.16", default-features = false, features = ["http1", "server", "tcp"] } [dev-dependencies] From b359b495e0f6aaf7b31e8809d08ebc7348d4f04b Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 15 Feb 2022 13:29:26 +0100 Subject: [PATCH 0517/1472] [ci] fix publish-rustdocs (#10858) --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f6f714ea52b10..8dabbc288cd62 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -756,7 +756,8 @@ publish-rustdoc: # Save README and docs - cp -r ./crate-docs/ /tmp/doc/ - cp README.md /tmp/doc/ - - git checkout gh-pages + # we don't need to commit changes because we copy docs to /tmp + - git checkout gh-pages --force # Install `index-tpl-crud` and generate index.html based on RUSTDOCS_DEPLOY_REFS - which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} From 9d962620db0dc21837ff5c346789adf35a64a678 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 15 Feb 2022 14:19:39 +0100 Subject: [PATCH 0518/1472] Fix beefy mock ecdsa keys (#10854) Compressed ECDSA keys requires to have 0x02 or 0x03 as their first byte in order to allow public key recovery. Nevertheless the test was working because of the `unwrap_or_default()` at the end of the conversion routine (i.e. the invalid keys were converted to an empty vector). --- frame/beefy-mmr/src/mock.rs | 7 +++++-- frame/beefy-mmr/src/tests.rs | 8 ++++---- frame/beefy/src/mock.rs | 7 +++++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 88c182aa57ba4..dcee901ec14ce 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -158,9 +158,12 @@ impl pallet_session::SessionManager for MockSessionManager { // Note, that we can't use `UintAuthorityId` here. Reason is that the implementation // of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for -// ed25519 and sr25519 but *not* for ecdsa. An ecdsa public key is 33 bytes. +// ed25519 and sr25519 but *not* for ecdsa. A compressed ecdsa public key is 33 bytes, +// with the first one containing information to reconstruct the uncompressed key. pub fn mock_beefy_id(id: u8) -> BeefyId { - let buf: [u8; 33] = [id; 33]; + let mut buf: [u8; 33] = [id; 33]; + // Set to something valid. + buf[0] = 0x02; let pk = Public::from_raw(buf); BeefyId::from(pk) } diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index 6a81c5f25252e..452b8736a7916 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -71,7 +71,7 @@ fn should_contain_mmr_digest() { assert_eq!( System::digest().logs, vec![beefy_log(ConsensusLog::MmrRoot( - hex!("f3e3afbfa69e89cd1e99f8d3570155962f3346d1d8758dc079be49ef70387758").into() + hex!("969d516e5279540ef38e4a710fb0645cab4c3b01e528be7285b85ec9c5fb55c8").into() ))] ); @@ -82,13 +82,13 @@ fn should_contain_mmr_digest() { System::digest().logs, vec![ beefy_log(ConsensusLog::MmrRoot( - hex!("f3e3afbfa69e89cd1e99f8d3570155962f3346d1d8758dc079be49ef70387758").into() + hex!("969d516e5279540ef38e4a710fb0645cab4c3b01e528be7285b85ec9c5fb55c8").into() )), beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4),], 1,).unwrap() )), beefy_log(ConsensusLog::MmrRoot( - hex!("7d4ae4524bae75d52b63f08eab173b0c263eb95ae2c55c3a1d871241bd0cc559").into() + hex!("8c42b7b040d262f7f2e26abeb61ab0c3c448f60c7f2f19e6ca0035d9bb3ae7e2").into() )), ] ); @@ -111,7 +111,7 @@ fn should_contain_valid_leaf_data() { beefy_next_authority_set: BeefyNextAuthoritySet { id: 1, len: 2, - root: hex!("01b1a742589773fc054c8f5021a456316ffcec0370b25678b0696e116d1ef9ae") + root: hex!("176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96") .into(), }, parachain_heads: hex!( diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 0d820116d07bf..5fc04f7cbd1d2 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -122,9 +122,12 @@ impl pallet_session::SessionManager for MockSessionManager { // Note, that we can't use `UintAuthorityId` here. Reason is that the implementation // of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for -// ed25519 and sr25519 but *not* for ecdsa. An ecdsa public key is 33 bytes. +// ed25519 and sr25519 but *not* for ecdsa. A compressed ecdsa public key is 33 bytes, +// with the first one containing information to reconstruct the uncompressed key. pub fn mock_beefy_id(id: u8) -> BeefyId { - let buf: [u8; 33] = [id; 33]; + let mut buf: [u8; 33] = [id; 33]; + // Set to something valid. + buf[0] = 0x02; let pk = Public::from_raw(buf); BeefyId::from(pk) } From b9927cdca03830d07bc1cdd8b8d80a3d32f64bd1 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 15 Feb 2022 22:21:34 +0100 Subject: [PATCH 0519/1472] Mark sync_state_genSyncSpec JSON-RPC as safe (#10832) * Mark sync_state_genSyncSpec JSON-RPC as safe * Note that parameter is unused * Ideally I'd wait for compilation to be finished before pushing, but it's really taking a long time * Remove deny_unsafe parameter * Remove unused dependency --- Cargo.lock | 1 - bin/node/rpc/src/lib.rs | 1 - client/sync-state-rpc/Cargo.toml | 1 - client/sync-state-rpc/src/lib.rs | 8 +------- 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e97c90e49236a..635ca97cd1e52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8808,7 +8808,6 @@ dependencies = [ "sc-consensus-babe", "sc-consensus-epochs", "sc-finality-grandpa", - "sc-rpc-api", "serde", "serde_json", "sp-blockchain", diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 30f7a0fdf023c..31f2f41086885 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -165,7 +165,6 @@ where client, shared_authority_set, shared_epoch_changes, - deny_unsafe, )?, )); diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index b413446c321f2..3e064685488d4 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -22,7 +22,6 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-consensus-babe = { version = "0.10.0-dev", path = "../consensus/babe" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } -sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } serde_json = "1.0.74" serde = { version = "1.0.136", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index f416b3a0e8f73..6fc0d17800fed 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -134,7 +134,6 @@ pub struct SyncStateRpcHandler { client: Arc, shared_authority_set: SharedAuthoritySet, shared_epoch_changes: SharedEpochChanges, - deny_unsafe: sc_rpc_api::DenyUnsafe, } impl SyncStateRpcHandler @@ -148,12 +147,11 @@ where client: Arc, shared_authority_set: SharedAuthoritySet, shared_epoch_changes: SharedEpochChanges, - deny_unsafe: sc_rpc_api::DenyUnsafe, ) -> Result> { if sc_chain_spec::get_extension::(chain_spec.extensions()) .is_some() { - Ok(Self { chain_spec, client, shared_authority_set, shared_epoch_changes, deny_unsafe }) + Ok(Self { chain_spec, client, shared_authority_set, shared_epoch_changes }) } else { Err(Error::::LightSyncStateExtensionNotFound) } @@ -185,10 +183,6 @@ where Backend: HeaderBackend + sc_client_api::AuxStore + 'static, { fn system_gen_sync_spec(&self, raw: bool) -> jsonrpc_core::Result { - if let Err(err) = self.deny_unsafe.check_if_safe() { - return Err(err.into()) - } - let mut chain_spec = self.chain_spec.cloned_box(); let sync_state = self.build_sync_state().map_err(map_error::>)?; From ba88ea2b6546596baa248097acb8f755550d987e Mon Sep 17 00:00:00 2001 From: Koute Date: Wed, 16 Feb 2022 13:14:00 +0900 Subject: [PATCH 0520/1472] Reduce CPU overhead of gossip (#10859) --- Cargo.lock | 6 ++-- client/finality-grandpa/Cargo.toml | 1 + .../src/communication/gossip.rs | 34 +++++++++---------- client/network-gossip/Cargo.toml | 1 + client/network-gossip/src/state_machine.rs | 15 +++----- 5 files changed, 28 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 635ca97cd1e52..9dc7cd909ff99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,9 +64,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ "getrandom 0.2.3", "once_cell", @@ -8333,6 +8333,7 @@ dependencies = [ name = "sc-finality-grandpa" version = "0.10.0-dev" dependencies = [ + "ahash", "assert_matches", "async-trait", "dyn-clone", @@ -8491,6 +8492,7 @@ dependencies = [ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ + "ahash", "async-std", "futures 0.3.16", "futures-timer", diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 6d4c3b13662dc..6fecebc3fdf60 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -22,6 +22,7 @@ futures-timer = "3.0.1" log = "0.4.8" parking_lot = "0.11.2" rand = "0.8.4" +ahash = "0.7.6" parity-scale-codec = { version = "2.3.1", features = ["derive"] } sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index ded918c34aa80..7ac4066780d0f 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -84,23 +84,23 @@ //! //! We only send polite messages to peers, -use parity_scale_codec::{Decode, Encode}; -use sc_network::{ObservedRole, PeerId, ReputationChange}; -use sc_network_gossip::{MessageIntent, ValidatorContext}; -use sp_finality_grandpa::AuthorityId; -use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; - +use ahash::{AHashMap, AHashSet}; use log::{debug, trace}; +use parity_scale_codec::{Decode, Encode}; use prometheus_endpoint::{register, CounterVec, Opts, PrometheusError, Registry, U64}; use rand::seq::SliceRandom; +use sc_network::{ObservedRole, PeerId, ReputationChange}; +use sc_network_gossip::{MessageIntent, ValidatorContext}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; +use sp_finality_grandpa::AuthorityId; +use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; use super::{benefit, cost, Round, SetId}; use crate::{environment, CatchUp, CompactCommit, SignedMessage}; use std::{ - collections::{HashMap, HashSet, VecDeque}, + collections::{HashSet, VecDeque}, time::{Duration, Instant}, }; @@ -260,7 +260,7 @@ const KEEP_RECENT_ROUNDS: usize = 3; struct KeepTopics { current_set: SetId, rounds: VecDeque<(Round, SetId)>, - reverse_map: HashMap, SetId)>, + reverse_map: AHashMap, SetId)>, } impl KeepTopics { @@ -268,7 +268,7 @@ impl KeepTopics { KeepTopics { current_set: SetId(0), rounds: VecDeque::with_capacity(KEEP_RECENT_ROUNDS + 2), - reverse_map: HashMap::new(), + reverse_map: Default::default(), } } @@ -290,7 +290,7 @@ impl KeepTopics { let _ = self.rounds.pop_front(); } - let mut map = HashMap::with_capacity(KEEP_RECENT_ROUNDS + 3); + let mut map = AHashMap::with_capacity(KEEP_RECENT_ROUNDS + 3); map.insert(super::global_topic::(self.current_set.0), (None, self.current_set)); for &(round, set) in &self.rounds { @@ -477,10 +477,10 @@ impl PeerInfo { /// The peers we're connected to in gossip. struct Peers { - inner: HashMap>, + inner: AHashMap>, /// The randomly picked set of `LUCKY_PEERS` we'll gossip to in the first stage of round /// gossiping. - first_stage_peers: HashSet, + first_stage_peers: AHashSet, /// The randomly picked set of peers we'll gossip to in the second stage of gossiping if the /// first stage didn't allow us to spread the voting data enough to conclude the round. This /// set should have size `sqrt(connected_peers)`. @@ -492,10 +492,10 @@ struct Peers { impl Default for Peers { fn default() -> Self { Peers { - inner: HashMap::new(), - first_stage_peers: HashSet::new(), - second_stage_peers: HashSet::new(), - lucky_light_peers: HashSet::new(), + inner: Default::default(), + first_stage_peers: Default::default(), + second_stage_peers: Default::default(), + lucky_light_peers: Default::default(), } } } @@ -608,7 +608,7 @@ impl Peers { } }); - let mut first_stage_peers = HashSet::new(); + let mut first_stage_peers = AHashSet::new(); let mut second_stage_peers = HashSet::new(); // we start by allocating authorities to the first stage set and when the minimum of diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 7952d97193ea9..161129c4ce682 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -20,6 +20,7 @@ futures-timer = "3.0.1" libp2p = { version = "0.40.0", default-features = false } log = "0.4.8" lru = "0.7.0" +ahash = "0.7.6" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 7ad9853b3615e..4f06819df64d1 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -18,19 +18,13 @@ use crate::{MessageIntent, Network, ValidationResult, Validator, ValidatorContext}; +use ahash::AHashSet; use libp2p::PeerId; use lru::LruCache; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network::ObservedRole; use sp_runtime::traits::{Block as BlockT, Hash, HashFor}; -use std::{ - borrow::Cow, - collections::{HashMap, HashSet}, - iter, - sync::Arc, - time, - time::Instant, -}; +use std::{borrow::Cow, collections::HashMap, iter, sync::Arc, time, time::Instant}; // FIXME: Add additional spam/DoS attack protection: https://github.com/paritytech/substrate/issues/1115 // NOTE: The current value is adjusted based on largest production network deployment (Kusama) and @@ -56,7 +50,7 @@ mod rep { } struct PeerConsensus { - known_messages: HashSet, + known_messages: AHashSet, } /// Topic stream message with sender. @@ -204,7 +198,8 @@ impl ConsensusGossip { ?role, "Registering peer", ); - self.peers.insert(who.clone(), PeerConsensus { known_messages: HashSet::new() }); + self.peers + .insert(who.clone(), PeerConsensus { known_messages: Default::default() }); let validator = self.validator.clone(); let mut context = NetworkContext { gossip: self, network }; From 42eec5bbf2345551e641ffe6bea43403475d0129 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Wed, 16 Feb 2022 16:26:53 +0800 Subject: [PATCH 0521/1472] sp-core-hashing: use the `digest::Digest` trait to handle the hashing function uniformly (#10835) * sp-core-hashing: use sha3 instead of tiny-keccak Signed-off-by: koushiro * use blake2 instead of blake2-rfc Signed-off-by: koushiro * improve som hashing of sp-core and sp-api-proc-macro Signed-off-by: koushiro * Some nits Signed-off-by: koushiro * cargo fmt Signed-off-by: koushiro --- Cargo.lock | 54 ++++++++++----- primitives/api/proc-macro/Cargo.toml | 2 +- .../api/proc-macro/src/decl_runtime_apis.rs | 6 +- primitives/core/Cargo.toml | 9 --- primitives/core/hashing/Cargo.toml | 14 ++-- primitives/core/hashing/src/lib.rs | 66 +++++++------------ primitives/core/src/ecdsa.rs | 6 +- primitives/core/src/ed25519.rs | 6 +- 8 files changed, 74 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9dc7cd909ff99..e04aec94d76bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -641,6 +641,15 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "blake2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94ba84325db59637ffc528bbe8c7f86c02c57cff5c0e2b9b00f9a851f42f309" +dependencies = [ + "digest 0.10.2", +] + [[package]] name = "blake2-rfc" version = "0.2.18" @@ -1383,9 +1392,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" +checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06" dependencies = [ "generic-array 0.14.4", ] @@ -1603,13 +1612,13 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" +checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837" dependencies = [ "block-buffer 0.10.0", "crypto-common", - "generic-array 0.14.4", + "subtle", ] [[package]] @@ -3852,7 +3861,7 @@ dependencies = [ "pin-project 1.0.10", "rand 0.7.3", "salsa20", - "sha3", + "sha3 0.9.1", ] [[package]] @@ -4491,7 +4500,7 @@ dependencies = [ "generic-array 0.14.4", "multihash-derive", "sha2 0.9.8", - "sha3", + "sha3 0.9.1", "unsigned-varint 0.5.1", ] @@ -9210,13 +9219,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900d964dd36bb15bcf2f2b35694c072feab74969a54f2bbeec7a2d725d2bdcb6" +checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" dependencies = [ "cfg-if 1.0.0", "cpufeatures 0.2.1", - "digest 0.10.1", + "digest 0.10.2", ] [[package]] @@ -9231,6 +9240,16 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha3" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd" +dependencies = [ + "digest 0.10.2", + "keccak", +] + [[package]] name = "sharded-slab" version = "0.1.1" @@ -9317,7 +9336,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6142f7c25e94f6fd25a32c3348ec230df9109b463f59c8c7acc4bd34936babb7" dependencies = [ "aes-gcm", - "blake2", + "blake2 0.9.1", "chacha20poly1305", "rand 0.8.4", "rand_core 0.6.2", @@ -9401,7 +9420,7 @@ dependencies = [ name = "sp-api-proc-macro" version = "4.0.0-dev" dependencies = [ - "blake2-rfc", + "blake2 0.10.2", "proc-macro-crate 1.1.0", "proc-macro2", "quote", @@ -9655,7 +9674,6 @@ dependencies = [ "secrecy", "serde", "serde_json", - "sha2 0.10.0", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-debug-derive", @@ -9668,8 +9686,6 @@ dependencies = [ "substrate-bip39", "thiserror", "tiny-bip39", - "tiny-keccak", - "twox-hash", "wasmi", "zeroize", ] @@ -9678,11 +9694,12 @@ dependencies = [ name = "sp-core-hashing" version = "4.0.0" dependencies = [ - "blake2-rfc", + "blake2 0.10.2", "byteorder", - "sha2 0.10.0", + "digest 0.10.2", + "sha2 0.10.1", + "sha3 0.10.0", "sp-std", - "tiny-keccak", "twox-hash", ] @@ -11153,6 +11170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ "cfg-if 1.0.0", + "digest 0.10.2", "rand 0.8.4", "static_assertions", ] diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index 30ab3ef9562b1..356e15a6fd115 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.36" -blake2-rfc = { version = "0.2.18", default-features = false } +blake2 = { version = "0.10.2", default-features = false } proc-macro-crate = "1.1.0" # Required for the doc tests diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index 85b66eca7061e..6de20df8a41d4 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -39,8 +39,6 @@ use syn::{ use std::collections::HashMap; -use blake2_rfc; - /// The ident used for the block generic parameter. const BLOCK_GENERIC_IDENT: &str = "Block"; @@ -750,8 +748,10 @@ fn parse_runtime_api_version(version: &Attribute) -> Result { /// Generates the identifier as const variable for the given `trait_name` /// by hashing the `trait_name`. fn generate_runtime_api_id(trait_name: &str) -> TokenStream { + use blake2::digest::{consts::U8, Digest}; + let mut res = [0; 8]; - res.copy_from_slice(blake2_rfc::blake2b::blake2b(8, &[], trait_name.as_bytes()).as_bytes()); + res.copy_from_slice(blake2::Blake2b::::digest(trait_name).as_slice()); quote!( const ID: [u8; 8] = [ #( #res ),* ]; ) } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index bd41635a1d7a1..08d5cdb87e60d 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -49,14 +49,11 @@ bitflags = "1.3" # full crypto ed25519-dalek = { version = "1.0.1", default-features = false, features = ["u64_backend", "alloc"], optional = true } blake2-rfc = { version = "0.2.18", default-features = false, optional = true } -tiny-keccak = { version = "2.0.1", features = ["keccak"], optional = true } schnorrkel = { version = "0.9.1", features = [ "preaudit_deprecated", "u64_backend", ], default-features = false, optional = true } -sha2 = { version = "0.10.0", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } -twox-hash = { version = "1.6.2", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", "static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } ss58-registry = { version = "1.11.0", default-features = false } @@ -98,7 +95,6 @@ std = [ "hash-db/std", "sp-std/std", "serde", - "twox-hash/std", "blake2-rfc/std", "ed25519-dalek/std", "hex/std", @@ -107,11 +103,9 @@ std = [ "tiny-bip39", "byteorder/std", "rand", - "sha2/std", "schnorrkel/std", "regex", "num-traits/std", - "tiny-keccak", "sp-core-hashing/std", "sp-debug-derive/std", "sp-externalities", @@ -132,11 +126,8 @@ std = [ full_crypto = [ "ed25519-dalek", "blake2-rfc", - "tiny-keccak", "schnorrkel", "hex", - "sha2", - "twox-hash", "libsecp256k1", "sp-core-hashing", "sp-runtime-interface/disable_target_static_assertions", diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index 8a84e585dad2a..dc5704d2989a2 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -16,16 +16,18 @@ targets = ["x86_64-unknown-linux-gnu"] sp-std = { version = "4.0.0", default-features = false, path = "../../std" } byteorder = { version = "1.3.2", default-features = false } -blake2-rfc = { version = "0.2.18", default-features = false } -tiny-keccak = { version = "2.0.1", features = ["keccak"] } -sha2 = { version = "0.10.0", default-features = false } -twox-hash = { version = "1.6.2", default-features = false } +digest = { version = "0.10.2", default-features = false } +blake2 = { version = "0.10.2", default-features = false } +sha2 = { version = "0.10.1", default-features = false } +sha3 = { version = "0.10.0", default-features = false } +twox-hash = { version = "1.6.2", default-features = false, features = ["digest_0_10"] } [features] default = ["std"] std = [ - "blake2-rfc/std", - "sha2/std", "sp-std/std", + "blake2/std", + "sha2/std", + "sha3/std", "twox-hash/std", ] diff --git a/primitives/core/hashing/src/lib.rs b/primitives/core/hashing/src/lib.rs index 9fa433a32320a..e6ccd5aaa8fb9 100644 --- a/primitives/core/hashing/src/lib.rs +++ b/primitives/core/hashing/src/lib.rs @@ -20,12 +20,17 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -use sha2::{Digest, Sha256}; -use tiny_keccak::{Hasher, Keccak}; +use core::hash::Hasher; + +use byteorder::{ByteOrder, LittleEndian}; +use digest::{ + consts::{U16, U32, U8}, + Digest, +}; /// Do a Blake2 512-bit hash and place result in `dest`. pub fn blake2_512_into(data: &[u8], dest: &mut [u8; 64]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(64, &[], data).as_bytes()); + dest.copy_from_slice(blake2::Blake2b512::digest(data).as_slice()); } /// Do a Blake2 512-bit hash and return result. @@ -37,7 +42,8 @@ pub fn blake2_512(data: &[u8]) -> [u8; 64] { /// Do a Blake2 256-bit hash and place result in `dest`. pub fn blake2_256_into(data: &[u8], dest: &mut [u8; 32]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes()); + type Blake2b256 = blake2::Blake2b; + dest.copy_from_slice(Blake2b256::digest(data).as_slice()); } /// Do a Blake2 256-bit hash and return result. @@ -49,7 +55,8 @@ pub fn blake2_256(data: &[u8]) -> [u8; 32] { /// Do a Blake2 128-bit hash and place result in `dest`. pub fn blake2_128_into(data: &[u8], dest: &mut [u8; 16]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(16, &[], data).as_bytes()); + type Blake2b128 = blake2::Blake2b; + dest.copy_from_slice(Blake2b128::digest(data).as_slice()); } /// Do a Blake2 128-bit hash and return result. @@ -61,7 +68,8 @@ pub fn blake2_128(data: &[u8]) -> [u8; 16] { /// Do a Blake2 64-bit hash and place result in `dest`. pub fn blake2_64_into(data: &[u8], dest: &mut [u8; 8]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(8, &[], data).as_bytes()); + type Blake2b64 = blake2::Blake2b; + dest.copy_from_slice(Blake2b64::digest(data).as_slice()); } /// Do a Blake2 64-bit hash and return result. @@ -73,11 +81,7 @@ pub fn blake2_64(data: &[u8]) -> [u8; 8] { /// Do a XX 64-bit hash and place result in `dest`. pub fn twox_64_into(data: &[u8], dest: &mut [u8; 8]) { - use core::hash::Hasher; - let mut h0 = twox_hash::XxHash::with_seed(0); - h0.write(data); - let r0 = h0.finish(); - use byteorder::{ByteOrder, LittleEndian}; + let r0 = twox_hash::XxHash::with_seed(0).chain_update(data).finish(); LittleEndian::write_u64(&mut dest[0..8], r0); } @@ -90,14 +94,8 @@ pub fn twox_64(data: &[u8]) -> [u8; 8] { /// Do a XX 128-bit hash and place result in `dest`. pub fn twox_128_into(data: &[u8], dest: &mut [u8; 16]) { - use core::hash::Hasher; - let mut h0 = twox_hash::XxHash::with_seed(0); - let mut h1 = twox_hash::XxHash::with_seed(1); - h0.write(data); - h1.write(data); - let r0 = h0.finish(); - let r1 = h1.finish(); - use byteorder::{ByteOrder, LittleEndian}; + let r0 = twox_hash::XxHash::with_seed(0).chain_update(data).finish(); + let r1 = twox_hash::XxHash::with_seed(1).chain_update(data).finish(); LittleEndian::write_u64(&mut dest[0..8], r0); LittleEndian::write_u64(&mut dest[8..16], r1); } @@ -111,20 +109,10 @@ pub fn twox_128(data: &[u8]) -> [u8; 16] { /// Do a XX 256-bit hash and place result in `dest`. pub fn twox_256_into(data: &[u8], dest: &mut [u8; 32]) { - use ::core::hash::Hasher; - use byteorder::{ByteOrder, LittleEndian}; - let mut h0 = twox_hash::XxHash::with_seed(0); - let mut h1 = twox_hash::XxHash::with_seed(1); - let mut h2 = twox_hash::XxHash::with_seed(2); - let mut h3 = twox_hash::XxHash::with_seed(3); - h0.write(data); - h1.write(data); - h2.write(data); - h3.write(data); - let r0 = h0.finish(); - let r1 = h1.finish(); - let r2 = h2.finish(); - let r3 = h3.finish(); + let r0 = twox_hash::XxHash::with_seed(0).chain_update(data).finish(); + let r1 = twox_hash::XxHash::with_seed(1).chain_update(data).finish(); + let r2 = twox_hash::XxHash::with_seed(2).chain_update(data).finish(); + let r3 = twox_hash::XxHash::with_seed(3).chain_update(data).finish(); LittleEndian::write_u64(&mut dest[0..8], r0); LittleEndian::write_u64(&mut dest[8..16], r1); LittleEndian::write_u64(&mut dest[16..24], r2); @@ -140,27 +128,21 @@ pub fn twox_256(data: &[u8]) -> [u8; 32] { /// Do a keccak 256-bit hash and return result. pub fn keccak_256(data: &[u8]) -> [u8; 32] { - let mut keccak = Keccak::v256(); - keccak.update(data); let mut output = [0u8; 32]; - keccak.finalize(&mut output); + output.copy_from_slice(sha3::Keccak256::digest(data).as_slice()); output } /// Do a keccak 512-bit hash and return result. pub fn keccak_512(data: &[u8]) -> [u8; 64] { - let mut keccak = Keccak::v512(); - keccak.update(data); let mut output = [0u8; 64]; - keccak.finalize(&mut output); + output.copy_from_slice(sha3::Keccak512::digest(data).as_slice()); output } /// Do a sha2 256-bit hash and return result. pub fn sha2_256(data: &[u8]) -> [u8; 32] { - let mut hasher = Sha256::new(); - hasher.update(data); let mut output = [0u8; 32]; - output.copy_from_slice(&hasher.finalize()); + output.copy_from_slice(sha2::Sha256::digest(data).as_slice()); output } diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 4d2cae97ef14a..0735c3f40cec2 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -348,11 +348,7 @@ impl<'a> TryFrom<&'a Signature> for (libsecp256k1::Signature, libsecp256k1::Reco /// Derive a single hard junction. #[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { - ("Secp256k1HDKD", secret_seed, cc).using_encoded(|data| { - let mut res = [0u8; 32]; - res.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes()); - res - }) + ("Secp256k1HDKD", secret_seed, cc).using_encoded(|data| sp_core_hashing::blake2_256(data)) } /// An error when deriving a key. diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index be7547201e84d..54f9ed7fc0e30 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -396,11 +396,7 @@ impl From<&Public> for CryptoTypePublicPair { /// Derive a single hard junction. #[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { - ("Ed25519HDKD", secret_seed, cc).using_encoded(|data| { - let mut res = [0u8; 32]; - res.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes()); - res - }) + ("Ed25519HDKD", secret_seed, cc).using_encoded(|data| sp_core_hashing::blake2_256(data)) } /// An error when deriving a key. From 7fa05d45e570845146e4001f2d30f052f59a87bb Mon Sep 17 00:00:00 2001 From: Dmitry Kashitsyn Date: Wed, 16 Feb 2022 16:53:10 +0700 Subject: [PATCH 0522/1472] Use fully qualified sytnax for `retain_mut` (#10865) --- client/consensus/babe/src/lib.rs | 2 +- client/transaction-pool/src/graph/validated_pool.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 9ad50eb9c0e5c..19d9e37cf20ae 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -753,7 +753,7 @@ where slot: Slot, epoch_descriptor: &ViableEpochDescriptor, Epoch>, ) { - self.slot_notification_sinks.lock().retain_mut(|sink| { + RetainMut::retain_mut(&mut *self.slot_notification_sinks.lock(), |sink| { match sink.try_send((slot, epoch_descriptor.clone())) { Ok(()) => true, Err(e) => diff --git a/client/transaction-pool/src/graph/validated_pool.rs b/client/transaction-pool/src/graph/validated_pool.rs index 7e19941b25684..4ddaf8de5c2bc 100644 --- a/client/transaction-pool/src/graph/validated_pool.rs +++ b/client/transaction-pool/src/graph/validated_pool.rs @@ -203,7 +203,7 @@ impl ValidatedPool { let imported = self.pool.write().import(tx)?; if let base::Imported::Ready { ref hash, .. } = imported { - self.import_notification_sinks.lock().retain_mut(|sink| { + RetainMut::retain_mut(&mut *self.import_notification_sinks.lock(), |sink| { match sink.try_send(*hash) { Ok(()) => true, Err(e) => From b2f76e26a9e8cd0d5457058b20bb250d092a16ac Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 16 Feb 2022 18:02:35 +0800 Subject: [PATCH 0523/1472] add llvm (#10864) --- docs/README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.adoc b/docs/README.adoc index 05f81442d4ca8..0b82f0ed82a13 100644 --- a/docs/README.adoc +++ b/docs/README.adoc @@ -190,7 +190,7 @@ You will also need to install the following packages: - Linux: [source, shell] -sudo apt install cmake pkg-config libssl-dev git clang libclang-dev +sudo apt install cmake pkg-config libssl-dev git clang libclang-dev llvm - Linux on ARM: `rust-lld` is required for linking wasm, but is missing on non Tier 1 platforms. From 5cdbaa3e1caac94fa3ede30f9fb08fd1f031b3d4 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 16 Feb 2022 10:40:16 +0000 Subject: [PATCH 0524/1472] refactor election score (#10834) * refactor election score * Test for ord * remove reference * vec -> slice * change iter to iter_by_significance * improve doc * fix typo * add explanation about [u128; 3] * consolidate threshold and epsilon * random fixes * rename * remove Into * make iter_by_sig private * remove vec * Fix tests --- .../src/benchmarking.rs | 9 +- .../election-provider-multi-phase/src/lib.rs | 41 ++++-- .../src/signed.rs | 87 ++++++++---- .../src/unsigned.rs | 63 +++++---- primitives/arithmetic/src/lib.rs | 2 +- .../fuzzer/src/phragmen_balancing.rs | 15 +- .../fuzzer/src/phragmms_balancing.rs | 14 +- primitives/npos-elections/src/lib.rs | 133 ++++++++++++------ primitives/npos-elections/src/tests.rs | 41 +++++- 9 files changed, 281 insertions(+), 124 deletions(-) diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index d37b9451b770f..cc322cbb4d57e 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -148,7 +148,10 @@ fn solution_with_size( let score = solution.clone().score(stake_of, voter_at, target_at).unwrap(); let round = >::round(); - assert!(score[0] > 0, "score is zero, this probably means that the stakes are not set."); + assert!( + score.minimal_stake > 0, + "score is zero, this probably means that the stakes are not set." + ); Ok(RawSolution { solution, score, round }) } @@ -312,7 +315,7 @@ frame_benchmarking::benchmarks! { // the solution will be worse than all of them meaning the score need to be checked against // ~ log2(c) let solution = RawSolution { - score: [(10_000_000u128 - 1).into(), 0, 0], + score: ElectionScore { minimal_stake: 10_000_000u128 - 1, ..Default::default() }, ..Default::default() }; @@ -323,7 +326,7 @@ frame_benchmarking::benchmarks! { let mut signed_submissions = SignedSubmissions::::get(); for i in 0..c { let raw_solution = RawSolution { - score: [(10_000_000 + i).into(), 0, 0], + score: ElectionScore { minimal_stake: 10_000_000u128 + (i as u128), ..Default::default() }, ..Default::default() }; let signed_submission = SignedSubmission { diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index cad3d12605e48..58df7d5a9d754 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -944,8 +944,11 @@ pub mod pallet { // Note: we don't `rotate_round` at this point; the next call to // `ElectionProvider::elect` will succeed and take care of that. - let solution = - ReadySolution { supports, score: [0, 0, 0], compute: ElectionCompute::Emergency }; + let solution = ReadySolution { + supports, + score: Default::default(), + compute: ElectionCompute::Emergency, + }; >::put(solution); Ok(()) @@ -1059,8 +1062,11 @@ pub mod pallet { }, )?; - let solution = - ReadySolution { supports, score: [0, 0, 0], compute: ElectionCompute::Fallback }; + let solution = ReadySolution { + supports, + score: Default::default(), + compute: ElectionCompute::Fallback, + }; >::put(solution); Ok(()) @@ -1138,10 +1144,10 @@ pub mod pallet { .map_err(dispatch_error_to_invalid)?; ValidTransaction::with_tag_prefix("OffchainElection") - // The higher the score[0], the better a solution is. + // The higher the score.minimal_stake, the better a solution is. .priority( T::MinerTxPriority::get() - .saturating_add(raw_solution.score[0].saturated_into()), + .saturating_add(raw_solution.score.minimal_stake.saturated_into()), ) // Used to deduplicate unsigned solutions: each validator should produce one // solution per round at most, and solutions are not propagate. @@ -1430,7 +1436,7 @@ impl Pallet { let submitted_score = raw_solution.score.clone(); ensure!( Self::minimum_untrusted_score().map_or(true, |min_score| { - sp_npos_elections::is_score_better(submitted_score, min_score, Perbill::zero()) + submitted_score.strict_threshold_better(min_score, Perbill::zero()) }), FeasibilityError::UntrustedScoreTooLow ); @@ -1750,7 +1756,7 @@ mod feasibility_check { assert_eq!(MultiPhase::snapshot().unwrap().voters.len(), 8); // Simply faff with the score. - solution.score[0] += 1; + solution.score.minimal_stake += 1; assert_noop!( MultiPhase::feasibility_check(solution, COMPUTE), @@ -1960,7 +1966,10 @@ mod tests { // fill the queue with signed submissions for s in 0..SignedMaxSubmissions::get() { - let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, + ..Default::default() + }; assert_ok!(MultiPhase::submit( crate::mock::Origin::signed(99), Box::new(solution), @@ -2087,13 +2096,19 @@ mod tests { crate::mock::Balancing::set(Some((2, 0))); let (solution, _) = MultiPhase::mine_solution::<::Solver>().unwrap(); - // Default solution has a score of [50, 100, 5000]. - assert_eq!(solution.score, [50, 100, 5000]); + // Default solution's score. + assert!(matches!(solution.score, ElectionScore { minimal_stake: 50, .. })); - >::put([49, 0, 0]); + >::put(ElectionScore { + minimal_stake: 49, + ..Default::default() + }); assert_ok!(MultiPhase::feasibility_check(solution.clone(), ElectionCompute::Signed)); - >::put([51, 0, 0]); + >::put(ElectionScore { + minimal_stake: 51, + ..Default::default() + }); assert_noop!( MultiPhase::feasibility_check(solution, ElectionCompute::Signed), FeasibilityError::UntrustedScoreTooLow, diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 3b314bce80ffe..4362fb5127e74 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -28,7 +28,7 @@ use frame_support::{ traits::{defensive_prelude::*, Currency, Get, OnUnbalanced, ReservableCurrency}, }; use sp_arithmetic::traits::SaturatedConversion; -use sp_npos_elections::{is_score_better, ElectionScore, NposSolution}; +use sp_npos_elections::{ElectionScore, NposSolution}; use sp_runtime::{ traits::{Saturating, Zero}, RuntimeDebug, @@ -293,7 +293,7 @@ impl SignedSubmissions { let threshold = T::SolutionImprovementThreshold::get(); // if we haven't improved on the weakest score, don't change anything. - if !is_score_better(insert_score, weakest_score, threshold) { + if !insert_score.strict_threshold_better(weakest_score, threshold) { return InsertResult::NotInserted } @@ -592,7 +592,7 @@ mod tests { assert_eq!(balances(&99), (100, 0)); // make the solution invalid. - solution.score[0] += 1; + solution.score.minimal_stake += 1; assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); @@ -618,7 +618,7 @@ mod tests { assert_ok!(submit_with_witness(Origin::signed(99), solution.clone())); // make the solution invalid and weaker. - solution.score[0] -= 1; + solution.score.minimal_stake -= 1; assert_ok!(submit_with_witness(Origin::signed(999), solution)); assert_eq!(balances(&99), (95, 5)); assert_eq!(balances(&999), (95, 5)); @@ -641,12 +641,18 @@ mod tests { for s in 0..SignedMaxSubmissions::get() { // score is always getting better - let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, + ..Default::default() + }; assert_ok!(submit_with_witness(Origin::signed(99), solution)); } // weaker. - let solution = RawSolution { score: [4, 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: 4, ..Default::default() }, + ..Default::default() + }; assert_noop!( submit_with_witness(Origin::signed(99), solution), @@ -663,27 +669,33 @@ mod tests { for s in 0..SignedMaxSubmissions::get() { // score is always getting better - let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, + ..Default::default() + }; assert_ok!(submit_with_witness(Origin::signed(99), solution)); } assert_eq!( MultiPhase::signed_submissions() .iter() - .map(|s| s.raw_solution.score[0]) + .map(|s| s.raw_solution.score.minimal_stake) .collect::>(), vec![5, 6, 7, 8, 9] ); // better. - let solution = RawSolution { score: [20, 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: 20, ..Default::default() }, + ..Default::default() + }; assert_ok!(submit_with_witness(Origin::signed(99), solution)); // the one with score 5 was rejected, the new one inserted. assert_eq!( MultiPhase::signed_submissions() .iter() - .map(|s| s.raw_solution.score[0]) + .map(|s| s.raw_solution.score.minimal_stake) .collect::>(), vec![6, 7, 8, 9, 20] ); @@ -698,30 +710,39 @@ mod tests { for s in 1..SignedMaxSubmissions::get() { // score is always getting better - let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, + ..Default::default() + }; assert_ok!(submit_with_witness(Origin::signed(99), solution)); } - let solution = RawSolution { score: [4, 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: 4, ..Default::default() }, + ..Default::default() + }; assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!( MultiPhase::signed_submissions() .iter() - .map(|s| s.raw_solution.score[0]) + .map(|s| s.raw_solution.score.minimal_stake) .collect::>(), vec![4, 6, 7, 8, 9], ); // better. - let solution = RawSolution { score: [5, 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: 5, ..Default::default() }, + ..Default::default() + }; assert_ok!(submit_with_witness(Origin::signed(99), solution)); // the one with score 5 was rejected, the new one inserted. assert_eq!( MultiPhase::signed_submissions() .iter() - .map(|s| s.raw_solution.score[0]) + .map(|s| s.raw_solution.score.minimal_stake) .collect::>(), vec![5, 6, 7, 8, 9], ); @@ -736,7 +757,10 @@ mod tests { for s in 0..SignedMaxSubmissions::get() { // score is always getting better - let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, + ..Default::default() + }; assert_ok!(submit_with_witness(Origin::signed(99), solution)); } @@ -744,7 +768,10 @@ mod tests { assert_eq!(balances(&999).1, 0); // better. - let solution = RawSolution { score: [20, 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: 20, ..Default::default() }, + ..Default::default() + }; assert_ok!(submit_with_witness(Origin::signed(999), solution)); // got one bond back. @@ -760,19 +787,25 @@ mod tests { assert!(MultiPhase::current_phase().is_signed()); for i in 0..SignedMaxSubmissions::get() { - let solution = RawSolution { score: [(5 + i).into(), 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: (5 + i).into(), ..Default::default() }, + ..Default::default() + }; assert_ok!(submit_with_witness(Origin::signed(99), solution)); } assert_eq!( MultiPhase::signed_submissions() .iter() - .map(|s| s.raw_solution.score[0]) + .map(|s| s.raw_solution.score.minimal_stake) .collect::>(), vec![5, 6, 7] ); // 5 is not accepted. This will only cause processing with no benefit. - let solution = RawSolution { score: [5, 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: 5, ..Default::default() }, + ..Default::default() + }; assert_noop!( submit_with_witness(Origin::signed(99), solution), Error::::SignedQueueFull, @@ -800,13 +833,13 @@ mod tests { // make the solution invalidly better and submit. This ought to be slashed. let mut solution_999 = solution.clone(); - solution_999.score[0] += 1; + solution_999.score.minimal_stake += 1; assert_ok!(submit_with_witness(Origin::signed(999), solution_999)); // make the solution invalidly worse and submit. This ought to be suppressed and // returned. let mut solution_9999 = solution.clone(); - solution_9999.score[0] -= 1; + solution_9999.score.minimal_stake -= 1; assert_ok!(submit_with_witness(Origin::signed(9999), solution_9999)); assert_eq!( @@ -889,13 +922,19 @@ mod tests { for s in 0..SignedMaxSubmissions::get() { // score is always getting better - let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() }; + let solution = RawSolution { + score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, + ..Default::default() + }; assert_ok!(submit_with_witness(Origin::signed(99), solution)); } // this solution has a higher score than any in the queue let solution = RawSolution { - score: [(5 + SignedMaxSubmissions::get()).into(), 0, 0], + score: ElectionScore { + minimal_stake: (5 + SignedMaxSubmissions::get()).into(), + ..Default::default() + }, ..Default::default() }; diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 196147f8a4706..510fc9fcdcca9 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -26,10 +26,9 @@ use codec::Encode; use frame_election_provider_support::{NposSolver, PerThing128}; use frame_support::{dispatch::DispatchResult, ensure, traits::Get}; use frame_system::offchain::SubmitTransaction; -use sp_arithmetic::Perbill; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, is_score_better, - ElectionResult, NposSolution, + assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, ElectionResult, + NposSolution, }; use sp_runtime::{ offchain::storage::{MutateStorageError, StorageValueRef}, @@ -624,11 +623,9 @@ impl Pallet { // ensure score is being improved. Panic henceforth. ensure!( - Self::queued_solution().map_or(true, |q: ReadySolution<_>| is_score_better::( - raw_solution.score, - q.score, - T::SolutionImprovementThreshold::get() - )), + Self::queued_solution().map_or(true, |q: ReadySolution<_>| raw_solution + .score + .strict_threshold_better(q.score, T::SolutionImprovementThreshold::get())), Error::::PreDispatchWeakSubmission, ); @@ -748,11 +745,11 @@ mod tests { use frame_support::{ assert_noop, assert_ok, bounded_vec, dispatch::Dispatchable, traits::OffchainWorker, }; - use sp_npos_elections::IndexAssignment; + use sp_npos_elections::{ElectionScore, IndexAssignment}; use sp_runtime::{ offchain::storage_lock::{BlockAndTime, StorageLock}, traits::ValidateUnsigned, - ModuleError, PerU16, + ModuleError, PerU16, Perbill, }; type Assignment = crate::unsigned::Assignment; @@ -760,8 +757,10 @@ mod tests { #[test] fn validate_unsigned_retracts_wrong_phase() { ExtBuilder::default().desired_targets(0).build_and_execute(|| { - let solution = - RawSolution:: { score: [5, 0, 0], ..Default::default() }; + let solution = RawSolution:: { + score: ElectionScore { minimal_stake: 5, ..Default::default() }, + ..Default::default() + }; let call = Call::submit_unsigned { raw_solution: Box::new(solution.clone()), witness: witness(), @@ -833,8 +832,10 @@ mod tests { roll_to(25); assert!(MultiPhase::current_phase().is_unsigned()); - let solution = - RawSolution:: { score: [5, 0, 0], ..Default::default() }; + let solution = RawSolution:: { + score: ElectionScore { minimal_stake: 5, ..Default::default() }, + ..Default::default() + }; let call = Call::submit_unsigned { raw_solution: Box::new(solution.clone()), witness: witness(), @@ -849,7 +850,10 @@ mod tests { assert!(::pre_dispatch(&call).is_ok()); // set a better score - let ready = ReadySolution { score: [10, 0, 0], ..Default::default() }; + let ready = ReadySolution { + score: ElectionScore { minimal_stake: 10, ..Default::default() }, + ..Default::default() + }; >::put(ready); // won't work anymore. @@ -874,7 +878,10 @@ mod tests { roll_to(25); assert!(MultiPhase::current_phase().is_unsigned()); - let raw = RawSolution:: { score: [5, 0, 0], ..Default::default() }; + let raw = RawSolution:: { + score: ElectionScore { minimal_stake: 5, ..Default::default() }, + ..Default::default() + }; let call = Call::submit_unsigned { raw_solution: Box::new(raw.clone()), witness: witness() }; assert_eq!(raw.solution.unique_targets().len(), 0); @@ -900,8 +907,10 @@ mod tests { roll_to(25); assert!(MultiPhase::current_phase().is_unsigned()); - let solution = - RawSolution:: { score: [5, 0, 0], ..Default::default() }; + let solution = RawSolution:: { + score: ElectionScore { minimal_stake: 5, ..Default::default() }, + ..Default::default() + }; let call = Call::submit_unsigned { raw_solution: Box::new(solution.clone()), witness: witness(), @@ -930,8 +939,10 @@ mod tests { assert!(MultiPhase::current_phase().is_unsigned()); // This is in itself an invalid BS solution. - let solution = - RawSolution:: { score: [5, 0, 0], ..Default::default() }; + let solution = RawSolution:: { + score: ElectionScore { minimal_stake: 5, ..Default::default() }, + ..Default::default() + }; let call = Call::submit_unsigned { raw_solution: Box::new(solution.clone()), witness: witness(), @@ -950,8 +961,10 @@ mod tests { assert!(MultiPhase::current_phase().is_unsigned()); // This solution is unfeasible as well, but we won't even get there. - let solution = - RawSolution:: { score: [5, 0, 0], ..Default::default() }; + let solution = RawSolution:: { + score: ElectionScore { minimal_stake: 5, ..Default::default() }, + ..Default::default() + }; let mut correct_witness = witness(); correct_witness.voters += 1; @@ -1070,7 +1083,7 @@ mod tests { Box::new(solution), witness )); - assert_eq!(MultiPhase::queued_solution().unwrap().score[0], 10); + assert_eq!(MultiPhase::queued_solution().unwrap().score.minimal_stake, 10); // trial 1: a solution who's score is only 2, i.e. 20% better in the first element. let result = ElectionResult { @@ -1086,7 +1099,7 @@ mod tests { }; let (solution, _) = MultiPhase::prepare_election_result(result).unwrap(); // 12 is not 50% more than 10 - assert_eq!(solution.score[0], 12); + assert_eq!(solution.score.minimal_stake, 12); assert_noop!( MultiPhase::unsigned_pre_dispatch_checks(&solution), Error::::PreDispatchWeakSubmission, @@ -1107,7 +1120,7 @@ mod tests { ], }; let (solution, witness) = MultiPhase::prepare_election_result(result).unwrap(); - assert_eq!(solution.score[0], 17); + assert_eq!(solution.score.minimal_stake, 17); // and it is fine assert_ok!(MultiPhase::unsigned_pre_dispatch_checks(&solution)); diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index 92f8a708316de..273608a3d1711 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -55,7 +55,7 @@ use traits::{BaseArithmetic, One, SaturatedConversion, Unsigned, Zero}; /// - `Ordering::Equal` otherwise. pub trait ThresholdOrd { /// Compare if `self` is `threshold` greater or less than `other`. - fn tcmp(&self, other: &T, epsilon: T) -> Ordering; + fn tcmp(&self, other: &T, threshold: T) -> Ordering; } impl ThresholdOrd for T diff --git a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs index 8f782405df527..76641fc2c79fe 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs @@ -23,8 +23,8 @@ use common::*; use honggfuzz::fuzz; use rand::{self, SeedableRng}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, is_score_better, seq_phragmen, to_supports, - ElectionResult, EvaluateSupport, VoteWeight, + assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, ElectionResult, + EvaluateSupport, VoteWeight, }; use sp_runtime::Perbill; @@ -60,7 +60,7 @@ fn main() { .unwrap(); let score = to_supports(staked.as_ref()).evaluate(); - if score[0] == 0 { + if score.minimal_stake == 0 { // such cases cannot be improved by balancing. return } @@ -80,7 +80,8 @@ fn main() { to_supports(staked.as_ref()).evaluate() }; - let enhance = is_score_better(balanced_score, unbalanced_score, Perbill::zero()); + let enhance = + balanced_score.strict_threshold_better(unbalanced_score, Perbill::zero()); println!( "iter = {} // {:?} -> {:?} [{}]", @@ -90,9 +91,9 @@ fn main() { // The only guarantee of balancing is such that the first and third element of the // score cannot decrease. assert!( - balanced_score[0] >= unbalanced_score[0] && - balanced_score[1] == unbalanced_score[1] && - balanced_score[2] <= unbalanced_score[2] + balanced_score.minimal_stake >= unbalanced_score.minimal_stake && + balanced_score.sum_stake == unbalanced_score.sum_stake && + balanced_score.sum_stake_squared <= unbalanced_score.sum_stake_squared ); } }); diff --git a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs index f2b12b137883c..09daf3f34d32e 100644 --- a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs @@ -23,8 +23,8 @@ use common::*; use honggfuzz::fuzz; use rand::{self, SeedableRng}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, is_score_better, phragmms, to_supports, ElectionResult, - EvaluateSupport, VoteWeight, + assignment_ratio_to_staked_normalized, phragmms, to_supports, ElectionResult, EvaluateSupport, + VoteWeight, }; use sp_runtime::Perbill; @@ -60,7 +60,7 @@ fn main() { .unwrap(); let score = to_supports(&staked).evaluate(); - if score[0] == 0 { + if score.minimal_stake == 0 { // such cases cannot be improved by balancing. return } @@ -77,7 +77,7 @@ fn main() { to_supports(staked.as_ref()).evaluate() }; - let enhance = is_score_better(balanced_score, unbalanced_score, Perbill::zero()); + let enhance = balanced_score.strict_threshold_better(unbalanced_score, Perbill::zero()); println!( "iter = {} // {:?} -> {:?} [{}]", @@ -87,9 +87,9 @@ fn main() { // The only guarantee of balancing is such that the first and third element of the score // cannot decrease. assert!( - balanced_score[0] >= unbalanced_score[0] && - balanced_score[1] == unbalanced_score[1] && - balanced_score[2] <= unbalanced_score[2] + balanced_score.minimal_stake >= unbalanced_score.minimal_stake && + balanced_score.sum_stake == unbalanced_score.sum_stake && + balanced_score.sum_stake_squared <= unbalanced_score.sum_stake_squared ); }); } diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 7b3b09a4c7346..7bd1a4b7f69b6 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -74,11 +74,12 @@ #![cfg_attr(not(feature = "std"), no_std)] +use scale_info::TypeInfo; use sp_arithmetic::{traits::Zero, Normalizable, PerThing, Rational128, ThresholdOrd}; use sp_core::RuntimeDebug; use sp_std::{cell::RefCell, cmp::Ordering, collections::btree_map::BTreeMap, prelude::*, rc::Rc}; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -144,9 +145,86 @@ pub type VoteWeight = u64; /// A type in which performing operations on vote weights are safe. pub type ExtendedBalance = u128; -/// The score of an assignment. This can be computed from the support map via -/// [`EvaluateSupport::evaluate`]. -pub type ElectionScore = [ExtendedBalance; 3]; +/// The score of an election. This is the main measure of an election's quality. +/// +/// By definition, the order of significance in [`ElectionScore`] is: +/// +/// 1. `minimal_stake`. +/// 2. `sum_stake`. +/// 3. `sum_stake_squared`. +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, Debug, Default)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct ElectionScore { + /// The minimal winner, in terms of total backing stake. + /// + /// This parameter should be maximized. + pub minimal_stake: ExtendedBalance, + /// The sum of the total backing of all winners. + /// + /// This parameter should maximized + pub sum_stake: ExtendedBalance, + /// The sum squared of the total backing of all winners, aka. the variance. + /// + /// Ths parameter should be minimized. + pub sum_stake_squared: ExtendedBalance, +} + +impl ElectionScore { + /// Iterate over the inner items, first visiting the most significant one. + fn iter_by_significance(self) -> impl Iterator { + [self.minimal_stake, self.sum_stake, self.sum_stake_squared].into_iter() + } + + /// Compares two sets of election scores based on desirability, returning true if `self` is + /// strictly `threshold` better than `other`. In other words, each element of `self` must be + /// `self * threshold` better than `other`. + /// + /// Evaluation is done based on the order of significance of the fields of [`ElectionScore`]. + pub fn strict_threshold_better(self, other: Self, threshold: impl PerThing) -> bool { + match self + .iter_by_significance() + .zip(other.iter_by_significance()) + .map(|(this, that)| (this.ge(&that), this.tcmp(&that, threshold.mul_ceil(that)))) + .collect::>() + .as_slice() + { + // threshold better in the `score.minimal_stake`, accept. + [(x, Ordering::Greater), _, _] => { + debug_assert!(x); + true + }, + + // less than threshold better in `score.minimal_stake`, but more than threshold better + // in `score.sum_stake`. + [(true, Ordering::Equal), (_, Ordering::Greater), _] => true, + + // less than threshold better in `score.minimal_stake` and `score.sum_stake`, but more + // than threshold better in `score.sum_stake_squared`. + [(true, Ordering::Equal), (true, Ordering::Equal), (_, Ordering::Less)] => true, + + // anything else is not a good score. + _ => false, + } + } +} + +impl sp_std::cmp::Ord for ElectionScore { + fn cmp(&self, other: &Self) -> Ordering { + // we delegate this to the lexicographic cmp of slices`, and to incorporate that we want the + // third element to be minimized, we swap them. + [self.minimal_stake, self.sum_stake, other.sum_stake_squared].cmp(&[ + other.minimal_stake, + other.sum_stake, + self.sum_stake_squared, + ]) + } +} + +impl sp_std::cmp::PartialOrd for ElectionScore { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} /// A pointer to a candidate struct with interior mutability. pub type CandidatePtr = Rc>>; @@ -353,7 +431,7 @@ pub struct ElectionResult { /// /// This, at the current version, resembles the `Exposure` defined in the Staking pallet, yet they /// do not necessarily have to be the same. -#[derive(RuntimeDebug, Encode, Decode, Clone, Eq, PartialEq, scale_info::TypeInfo)] +#[derive(RuntimeDebug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct Support { /// Total support. @@ -418,49 +496,22 @@ pub trait EvaluateSupport { impl EvaluateSupport for Supports { fn evaluate(&self) -> ElectionScore { - let mut min_support = ExtendedBalance::max_value(); - let mut sum: ExtendedBalance = Zero::zero(); + let mut minimal_stake = ExtendedBalance::max_value(); + let mut sum_stake: ExtendedBalance = Zero::zero(); // NOTE: The third element might saturate but fine for now since this will run on-chain and // need to be fast. - let mut sum_squared: ExtendedBalance = Zero::zero(); + let mut sum_stake_squared: ExtendedBalance = Zero::zero(); + for (_, support) in self { - sum = sum.saturating_add(support.total); + sum_stake = sum_stake.saturating_add(support.total); let squared = support.total.saturating_mul(support.total); - sum_squared = sum_squared.saturating_add(squared); - if support.total < min_support { - min_support = support.total; + sum_stake_squared = sum_stake_squared.saturating_add(squared); + if support.total < minimal_stake { + minimal_stake = support.total; } } - [min_support, sum, sum_squared] - } -} -/// Compares two sets of election scores based on desirability and returns true if `this` is better -/// than `that`. -/// -/// Evaluation is done in a lexicographic manner, and if each element of `this` is `that * epsilon` -/// greater or less than `that`. -/// -/// Note that the third component should be minimized. -pub fn is_score_better(this: ElectionScore, that: ElectionScore, epsilon: P) -> bool { - match this - .iter() - .zip(that.iter()) - .map(|(thi, tha)| (thi.ge(&tha), thi.tcmp(&tha, epsilon.mul_ceil(*tha)))) - .collect::>() - .as_slice() - { - // epsilon better in the score[0], accept. - [(_, Ordering::Greater), _, _] => true, - - // less than epsilon better in score[0], but more than epsilon better in the second. - [(true, Ordering::Equal), (_, Ordering::Greater), _] => true, - - // less than epsilon better in score[0, 1], but more than epsilon better in the third - [(true, Ordering::Equal), (true, Ordering::Equal), (_, Ordering::Less)] => true, - - // anything else is not a good score. - _ => false, + ElectionScore { minimal_stake, sum_stake, sum_stake_squared } } } diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index c6748b29e9851..b199fdd1af77f 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -18,9 +18,9 @@ //! Tests for npos-elections. use crate::{ - balancing, helpers::*, is_score_better, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, - to_support_map, Assignment, ElectionResult, ExtendedBalance, IndexAssignment, NposSolution, - StakedAssignment, Support, Voter, + balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, to_support_map, + Assignment, ElectionResult, ExtendedBalance, IndexAssignment, NposSolution, StakedAssignment, + Support, Voter, }; use rand::{self, SeedableRng}; use sp_arithmetic::{PerU16, Perbill, Percent, Permill}; @@ -792,6 +792,21 @@ mod assignment_convert_normalize { mod score { use super::*; + use crate::ElectionScore; + use sp_arithmetic::PerThing; + + /// NOTE: in tests, we still use the legacy [u128; 3] since it is more compact. Each `u128` + /// corresponds to element at the respective field index of `ElectionScore`. + impl From<[ExtendedBalance; 3]> for ElectionScore { + fn from(t: [ExtendedBalance; 3]) -> Self { + Self { minimal_stake: t[0], sum_stake: t[1], sum_stake_squared: t[2] } + } + } + + fn is_score_better(this: [u128; 3], that: [u128; 3], p: impl PerThing) -> bool { + ElectionScore::from(this).strict_threshold_better(ElectionScore::from(that), p) + } + #[test] fn score_comparison_is_lexicographical_no_epsilon() { let epsilon = Perbill::zero(); @@ -883,6 +898,26 @@ mod score { false, ); } + + #[test] + fn ord_works() { + // equal only when all elements are equal + assert!(ElectionScore::from([10, 5, 15]) == ElectionScore::from([10, 5, 15])); + assert!(ElectionScore::from([10, 5, 15]) != ElectionScore::from([9, 5, 15])); + assert!(ElectionScore::from([10, 5, 15]) != ElectionScore::from([10, 5, 14])); + + // first element greater, rest don't matter + assert!(ElectionScore::from([10, 5, 15]) > ElectionScore::from([8, 5, 25])); + assert!(ElectionScore::from([10, 5, 15]) > ElectionScore::from([9, 20, 5])); + + // second element greater, rest don't matter + assert!(ElectionScore::from([10, 5, 15]) > ElectionScore::from([10, 4, 25])); + assert!(ElectionScore::from([10, 5, 15]) > ElectionScore::from([10, 4, 5])); + + // second element is less, rest don't matter. Note that this is swapped. + assert!(ElectionScore::from([10, 5, 15]) > ElectionScore::from([10, 5, 16])); + assert!(ElectionScore::from([10, 5, 15]) > ElectionScore::from([10, 5, 25])); + } } mod solution_type { From e6def65920d30029e42d498cb07cec5dd433b927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 16 Feb 2022 11:49:31 +0100 Subject: [PATCH 0525/1472] Measure per byte and not kb for certain benchmarks (#10863) --- frame/contracts/src/benchmarking/mod.rs | 28 +- frame/contracts/src/lib.rs | 13 +- frame/contracts/src/tests.rs | 2 +- frame/contracts/src/wasm/code_cache.rs | 6 +- frame/contracts/src/weights.rs | 1244 +++++++++++------------ 5 files changed, 645 insertions(+), 648 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 3a749095b955e..827c729e16150 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -231,8 +231,8 @@ benchmarks! { // first time after a new schedule was deployed: For every new schedule a contract needs // to re-run the instrumentation once. reinstrument { - let c in 0 .. T::Schedule::get().limits.code_len / 1024; - let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024, Location::Call); + let c in 0 .. T::Schedule::get().limits.code_len; + let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); Contracts::::store_code_raw(code, whitelisted_caller())?; let schedule = T::Schedule::get(); let mut gas_meter = GasMeter::new(Weight::MAX); @@ -241,15 +241,15 @@ benchmarks! { Contracts::::reinstrument_module(&mut module, &schedule)?; } - // This benchmarks the overhead of loading a code of size `c` kb from storage and into + // This benchmarks the overhead of loading a code of size `c` byte from storage and into // the sandbox. This does **not** include the actual execution for which the gas meter // is responsible. This is achieved by generating all code to the `deploy` function // which is in the wasm module but not executed on `call`. // The results are supposed to be used as `call_with_code_kb(c) - call_with_code_kb(0)`. - call_with_code_kb { - let c in 0 .. T::Schedule::get().limits.code_len / 1024; + call_with_code_per_byte { + let c in 0 .. T::Schedule::get().limits.code_len; let instance = Contract::::with_caller( - whitelisted_caller(), WasmModule::sized(c * 1024, Location::Deploy), vec![], + whitelisted_caller(), WasmModule::sized(c, Location::Deploy), vec![], )?; let value = T::Currency::minimum_balance(); let origin = RawOrigin::Signed(instance.caller.clone()); @@ -271,13 +271,13 @@ benchmarks! { // We cannot let `c` grow to the maximum code size because the code is not allowed // to be larger than the maximum size **after instrumentation**. instantiate_with_code { - let c in 0 .. Perbill::from_percent(49).mul_ceil(T::Schedule::get().limits.code_len) / 1024; - let s in 0 .. code::max_pages::() * 64; - let salt = vec![42u8; (s * 1024) as usize]; + let c in 0 .. Perbill::from_percent(49).mul_ceil(T::Schedule::get().limits.code_len); + let s in 0 .. code::max_pages::() * 64 * 1024; + let salt = vec![42u8; s as usize]; let value = T::Currency::minimum_balance(); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); - let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024, Location::Call); + let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); let origin = RawOrigin::Signed(caller.clone()); let addr = Contracts::::contract_address(&caller, &hash, &salt); }: _(origin, value, Weight::MAX, None, code, vec![], salt) @@ -299,8 +299,8 @@ benchmarks! { // Instantiate uses a dummy contract constructor to measure the overhead of the instantiate. // `s`: Size of the salt in kilobytes. instantiate { - let s in 0 .. code::max_pages::() * 64; - let salt = vec![42u8; (s * 1024) as usize]; + let s in 0 .. code::max_pages::() * 64 * 1024; + let salt = vec![42u8; s as usize]; let value = T::Currency::minimum_balance(); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); @@ -360,10 +360,10 @@ benchmarks! { // We cannot let `c` grow to the maximum code size because the code is not allowed // to be larger than the maximum size **after instrumentation**. upload_code { - let c in 0 .. Perbill::from_percent(50).mul_ceil(T::Schedule::get().limits.code_len / 1024); + let c in 0 .. Perbill::from_percent(50).mul_ceil(T::Schedule::get().limits.code_len); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); - let WasmModule { code, hash, .. } = WasmModule::::sized(c * 1024, Location::Call); + let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); let origin = RawOrigin::Signed(caller.clone()); }: _(origin, code, None) verify { diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 9e7b61301e7de..037e3f1d33ae3 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -410,10 +410,7 @@ pub mod pallet { /// - The `value` is transferred to the new account. /// - The `deploy` function is executed in the context of the newly-created account. #[pallet::weight( - T::WeightInfo::instantiate_with_code( - code.len() as u32 / 1024, - salt.len() as u32 / 1024, - ) + T::WeightInfo::instantiate_with_code(code.len() as u32, salt.len() as u32) .saturating_add(*gas_limit) )] pub fn instantiate_with_code( @@ -445,7 +442,7 @@ pub mod pallet { } output.gas_meter.into_dispatch_result( output.result.map(|(_address, result)| result), - T::WeightInfo::instantiate_with_code(code_len / 1024, salt_len / 1024), + T::WeightInfo::instantiate_with_code(code_len, salt_len), ) } @@ -455,7 +452,7 @@ pub mod pallet { /// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary /// must be supplied. #[pallet::weight( - T::WeightInfo::instantiate(salt.len() as u32 / 1024).saturating_add(*gas_limit) + T::WeightInfo::instantiate(salt.len() as u32).saturating_add(*gas_limit) )] pub fn instantiate( origin: OriginFor, @@ -485,7 +482,7 @@ pub mod pallet { } output.gas_meter.into_dispatch_result( output.result.map(|(_address, output)| output), - T::WeightInfo::instantiate(salt_len / 1024), + T::WeightInfo::instantiate(salt_len), ) } @@ -505,7 +502,7 @@ pub mod pallet { /// To avoid this situation a constructor could employ access control so that it can /// only be instantiated by permissioned entities. The same is true when uploading /// through [`Self::instantiate_with_code`]. - #[pallet::weight(T::WeightInfo::upload_code(code.len() as u32 / 1024))] + #[pallet::weight(T::WeightInfo::upload_code(code.len() as u32))] pub fn upload_code( origin: OriginFor, code: Vec, diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 486e84da75471..9ea23e974b21d 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -1998,7 +1998,7 @@ fn reinstrument_does_charge() { assert!(result2.gas_consumed > result1.gas_consumed); assert_eq!( result2.gas_consumed, - result1.gas_consumed + ::WeightInfo::reinstrument(code_len / 1024), + result1.gas_consumed + ::WeightInfo::reinstrument(code_len), ); }); } diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 9fc49ac9a502d..ee5cdd5307214 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -216,9 +216,9 @@ impl Token for CodeToken { // point because when charging the general weight for calling the contract we not know the // size of the contract. match *self { - Reinstrument(len) => T::WeightInfo::reinstrument(len / 1024), - Load(len) => T::WeightInfo::call_with_code_kb(len / 1024) - .saturating_sub(T::WeightInfo::call_with_code_kb(0)), + Reinstrument(len) => T::WeightInfo::reinstrument(len), + Load(len) => T::WeightInfo::call_with_code_per_byte(len) + .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)), } } } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index c43e98bb8ac4b..fd32c247ba729 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-02-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-02-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -48,7 +48,7 @@ pub trait WeightInfo { fn on_initialize_per_trie_key(k: u32, ) -> Weight; fn on_initialize_per_queue_item(q: u32, ) -> Weight; fn reinstrument(c: u32, ) -> Weight; - fn call_with_code_kb(c: u32, ) -> Weight; + fn call_with_code_per_byte(c: u32, ) -> Weight; fn instantiate_with_code(c: u32, s: u32, ) -> Weight; fn instantiate(s: u32, ) -> Weight; fn call() -> Weight; @@ -160,32 +160,32 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_560_000 as Weight) + (1_588_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (7_843_000 as Weight) + (6_994_000 as Weight) // Standard Error: 0 - .saturating_add((749_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((743_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (3_228_000 as Weight) - // Standard Error: 5_000 - .saturating_add((2_257_000 as Weight).saturating_mul(q as Weight)) + (2_831_000 as Weight) + // Standard Error: 3_000 + .saturating_add((2_232_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (20_531_000 as Weight) - // Standard Error: 34_000 - .saturating_add((66_014_000 as Weight).saturating_mul(c as Weight)) + (17_839_000 as Weight) + // Standard Error: 0 + .saturating_add((64_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -193,10 +193,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) - fn call_with_code_kb(c: u32, ) -> Weight { - (295_703_000 as Weight) - // Standard Error: 53_000 - .saturating_add((57_661_000 as Weight).saturating_mul(c as Weight)) + fn call_with_code_per_byte(c: u32, ) -> Weight { + (222_400_000 as Weight) + // Standard Error: 0 + .saturating_add((56_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -208,11 +208,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (332_572_000 as Weight) - // Standard Error: 125_000 - .saturating_add((149_095_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 7_000 - .saturating_add((1_779_000 as Weight).saturating_mul(s as Weight)) + (283_144_000 as Weight) + // Standard Error: 0 + .saturating_add((140_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -223,9 +223,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (222_992_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_759_000 as Weight).saturating_mul(s as Weight)) + (171_794_000 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -234,7 +234,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (189_003_000 as Weight) + (140_234_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -242,9 +242,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (52_521_000 as Weight) - // Standard Error: 36_000 - .saturating_add((66_486_000 as Weight).saturating_mul(c as Weight)) + (49_467_000 as Weight) + // Standard Error: 0 + .saturating_add((66_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -252,7 +252,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_705_000 as Weight) + (24_915_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -261,9 +261,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (300_165_000 as Weight) - // Standard Error: 125_000 - .saturating_add((49_828_000 as Weight).saturating_mul(r as Weight)) + (218_957_000 as Weight) + // Standard Error: 114_000 + .saturating_add((49_881_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -272,9 +272,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (179_488_000 as Weight) - // Standard Error: 718_000 - .saturating_add((375_855_000 as Weight).saturating_mul(r as Weight)) + (76_490_000 as Weight) + // Standard Error: 856_000 + .saturating_add((375_305_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -284,9 +284,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (295_198_000 as Weight) - // Standard Error: 79_000 - .saturating_add((21_948_000 as Weight).saturating_mul(r as Weight)) + (213_485_000 as Weight) + // Standard Error: 76_000 + .saturating_add((22_020_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -295,9 +295,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (300_366_000 as Weight) - // Standard Error: 111_000 - .saturating_add((49_435_000 as Weight).saturating_mul(r as Weight)) + (218_468_000 as Weight) + // Standard Error: 108_000 + .saturating_add((49_457_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -306,9 +306,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (299_800_000 as Weight) - // Standard Error: 87_000 - .saturating_add((49_002_000 as Weight).saturating_mul(r as Weight)) + (218_950_000 as Weight) + // Standard Error: 99_000 + .saturating_add((48_859_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -317,9 +317,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (303_057_000 as Weight) - // Standard Error: 175_000 - .saturating_add((139_293_000 as Weight).saturating_mul(r as Weight)) + (226_714_000 as Weight) + // Standard Error: 111_000 + .saturating_add((141_924_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -328,9 +328,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (299_754_000 as Weight) - // Standard Error: 93_000 - .saturating_add((48_945_000 as Weight).saturating_mul(r as Weight)) + (216_673_000 as Weight) + // Standard Error: 90_000 + .saturating_add((49_367_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -339,9 +339,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (302_229_000 as Weight) - // Standard Error: 128_000 - .saturating_add((49_007_000 as Weight).saturating_mul(r as Weight)) + (215_859_000 as Weight) + // Standard Error: 104_000 + .saturating_add((49_334_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -350,9 +350,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (300_772_000 as Weight) - // Standard Error: 114_000 - .saturating_add((48_794_000 as Weight).saturating_mul(r as Weight)) + (216_419_000 as Weight) + // Standard Error: 109_000 + .saturating_add((49_417_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -361,9 +361,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (301_936_000 as Weight) - // Standard Error: 119_000 - .saturating_add((48_839_000 as Weight).saturating_mul(r as Weight)) + (218_799_000 as Weight) + // Standard Error: 108_000 + .saturating_add((48_631_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -373,9 +373,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (304_935_000 as Weight) - // Standard Error: 146_000 - .saturating_add((121_871_000 as Weight).saturating_mul(r as Weight)) + (215_968_000 as Weight) + // Standard Error: 147_000 + .saturating_add((122_978_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -384,9 +384,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (178_176_000 as Weight) - // Standard Error: 52_000 - .saturating_add((24_960_000 as Weight).saturating_mul(r as Weight)) + (127_183_000 as Weight) + // Standard Error: 35_000 + .saturating_add((24_523_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -395,9 +395,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (297_394_000 as Weight) - // Standard Error: 140_000 - .saturating_add((49_199_000 as Weight).saturating_mul(r as Weight)) + (217_535_000 as Weight) + // Standard Error: 91_000 + .saturating_add((48_400_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -406,9 +406,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (374_409_000 as Weight) - // Standard Error: 3_000 - .saturating_add((11_924_000 as Weight).saturating_mul(n as Weight)) + (297_539_000 as Weight) + // Standard Error: 5_000 + .saturating_add((11_870_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -417,9 +417,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (292_278_000 as Weight) - // Standard Error: 114_000 - .saturating_add((1_474_000 as Weight).saturating_mul(r as Weight)) + (211_807_000 as Weight) + // Standard Error: 160_000 + .saturating_add((1_717_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -428,9 +428,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (294_714_000 as Weight) + (213_139_000 as Weight) // Standard Error: 0 - .saturating_add((230_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((197_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -441,9 +441,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (297_589_000 as Weight) - // Standard Error: 2_835_000 - .saturating_add((53_498_000 as Weight).saturating_mul(r as Weight)) + (215_292_000 as Weight) + // Standard Error: 390_000 + .saturating_add((52_831_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -455,9 +455,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (296_371_000 as Weight) - // Standard Error: 220_000 - .saturating_add((160_881_000 as Weight).saturating_mul(r as Weight)) + (215_802_000 as Weight) + // Standard Error: 132_000 + .saturating_add((159_065_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -466,9 +466,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (308_401_000 as Weight) - // Standard Error: 202_000 - .saturating_add((277_771_000 as Weight).saturating_mul(r as Weight)) + (225_069_000 as Weight) + // Standard Error: 201_000 + .saturating_add((292_145_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -478,11 +478,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (625_100_000 as Weight) - // Standard Error: 2_053_000 - .saturating_add((284_765_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 404_000 - .saturating_add((85_893_000 as Weight).saturating_mul(n as Weight)) + (519_617_000 as Weight) + // Standard Error: 1_751_000 + .saturating_add((290_832_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 345_000 + .saturating_add((82_584_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -493,17 +493,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (182_141_000 as Weight) - // Standard Error: 134_000 - .saturating_add((41_928_000 as Weight).saturating_mul(r as Weight)) + (132_245_000 as Weight) + // Standard Error: 75_000 + .saturating_add((41_274_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (139_030_000 as Weight) - // Standard Error: 1_038_000 - .saturating_add((405_168_000 as Weight).saturating_mul(r as Weight)) + (48_288_000 as Weight) + // Standard Error: 1_024_000 + .saturating_add((408_264_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -511,25 +511,25 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (689_591_000 as Weight) - // Standard Error: 275_000 - .saturating_add((31_438_000 as Weight).saturating_mul(n as Weight)) + (607_246_000 as Weight) + // Standard Error: 252_000 + .saturating_add((28_722_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (709_965_000 as Weight) - // Standard Error: 340_000 - .saturating_add((11_182_000 as Weight).saturating_mul(n as Weight)) + (623_983_000 as Weight) + // Standard Error: 305_000 + .saturating_add((11_374_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (169_937_000 as Weight) - // Standard Error: 883_000 - .saturating_add((389_090_000 as Weight).saturating_mul(r as Weight)) + (91_727_000 as Weight) + // Standard Error: 837_000 + .saturating_add((383_577_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -537,51 +537,51 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (695_589_000 as Weight) - // Standard Error: 268_000 - .saturating_add((10_530_000 as Weight).saturating_mul(n as Weight)) + (604_749_000 as Weight) + // Standard Error: 251_000 + .saturating_add((11_086_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (195_080_000 as Weight) - // Standard Error: 607_000 - .saturating_add((328_903_000 as Weight).saturating_mul(r as Weight)) + (107_805_000 as Weight) + // Standard Error: 722_000 + .saturating_add((326_494_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (647_422_000 as Weight) - // Standard Error: 361_000 - .saturating_add((68_849_000 as Weight).saturating_mul(n as Weight)) + (564_604_000 as Weight) + // Standard Error: 360_000 + .saturating_add((65_184_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (198_907_000 as Weight) - // Standard Error: 658_000 - .saturating_add((295_368_000 as Weight).saturating_mul(r as Weight)) + (122_105_000 as Weight) + // Standard Error: 560_000 + .saturating_add((291_458_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (599_284_000 as Weight) - // Standard Error: 243_000 - .saturating_add((9_923_000 as Weight).saturating_mul(n as Weight)) + (512_580_000 as Weight) + // Standard Error: 245_000 + .saturating_add((10_171_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (170_700_000 as Weight) - // Standard Error: 887_000 - .saturating_add((422_448_000 as Weight).saturating_mul(r as Weight)) + (81_220_000 as Weight) + // Standard Error: 933_000 + .saturating_add((418_532_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -589,9 +589,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (743_584_000 as Weight) - // Standard Error: 403_000 - .saturating_add((69_763_000 as Weight).saturating_mul(n as Weight)) + (652_330_000 as Weight) + // Standard Error: 357_000 + .saturating_add((65_711_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } @@ -600,9 +600,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (208_815_000 as Weight) - // Standard Error: 1_078_000 - .saturating_add((1_719_660_000 as Weight).saturating_mul(r as Weight)) + (126_544_000 as Weight) + // Standard Error: 1_198_000 + .saturating_add((1_796_593_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -614,8 +614,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_471_000 - .saturating_add((27_917_429_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 3_033_000 + .saturating_add((19_788_005_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -627,8 +627,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 13_012_000 - .saturating_add((28_044_371_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 6_663_000 + .saturating_add((19_835_985_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -637,11 +637,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (15_964_304_000 as Weight) - // Standard Error: 19_327_000 - .saturating_add((1_629_626_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 8_000 - .saturating_add((11_992_000 as Weight).saturating_mul(c as Weight)) + (10_957_494_000 as Weight) + // Standard Error: 13_908_000 + .saturating_add((1_622_630_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 6_000 + .saturating_add((11_960_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -655,8 +655,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 50_849_000 - .saturating_add((35_608_311_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 48_191_000 + .saturating_add((27_587_375_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -669,11 +669,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (19_455_191_000 as Weight) - // Standard Error: 57_478_000 - .saturating_add((786_148_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 27_000 - .saturating_add((160_385_000 as Weight).saturating_mul(s as Weight)) + (14_504_226_000 as Weight) + // Standard Error: 66_350_000 + .saturating_add((912_874_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 31_000 + .saturating_add((157_415_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(207 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(205 as Weight)) @@ -684,9 +684,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (294_686_000 as Weight) - // Standard Error: 123_000 - .saturating_add((81_172_000 as Weight).saturating_mul(r as Weight)) + (216_771_000 as Weight) + // Standard Error: 127_000 + .saturating_add((79_994_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -695,9 +695,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (276_895_000 as Weight) - // Standard Error: 35_000 - .saturating_add((469_007_000 as Weight).saturating_mul(n as Weight)) + (376_960_000 as Weight) + // Standard Error: 24_000 + .saturating_add((465_507_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -706,9 +706,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (295_476_000 as Weight) - // Standard Error: 127_000 - .saturating_add((91_822_000 as Weight).saturating_mul(r as Weight)) + (212_554_000 as Weight) + // Standard Error: 129_000 + .saturating_add((92_073_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -717,9 +717,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (402_456_000 as Weight) - // Standard Error: 19_000 - .saturating_add((311_103_000 as Weight).saturating_mul(n as Weight)) + (298_638_000 as Weight) + // Standard Error: 23_000 + .saturating_add((307_231_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -728,9 +728,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (296_702_000 as Weight) - // Standard Error: 142_000 - .saturating_add((64_431_000 as Weight).saturating_mul(r as Weight)) + (216_274_000 as Weight) + // Standard Error: 100_000 + .saturating_add((64_205_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -739,9 +739,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (375_322_000 as Weight) - // Standard Error: 14_000 - .saturating_add((124_338_000 as Weight).saturating_mul(n as Weight)) + (294_478_000 as Weight) + // Standard Error: 18_000 + .saturating_add((120_405_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -750,9 +750,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (294_158_000 as Weight) - // Standard Error: 148_000 - .saturating_add((64_474_000 as Weight).saturating_mul(r as Weight)) + (215_874_000 as Weight) + // Standard Error: 115_000 + .saturating_add((63_402_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -761,9 +761,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (390_049_000 as Weight) - // Standard Error: 16_000 - .saturating_add((124_330_000 as Weight).saturating_mul(n as Weight)) + (288_361_000 as Weight) + // Standard Error: 15_000 + .saturating_add((120_795_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -772,9 +772,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (233_346_000 as Weight) - // Standard Error: 1_355_000 - .saturating_add((15_405_070_000 as Weight).saturating_mul(r as Weight)) + (142_940_000 as Weight) + // Standard Error: 1_317_000 + .saturating_add((15_385_437_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -785,265 +785,265 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:36 w:36) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_158_000 - .saturating_add((932_937_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_981_000 + .saturating_add((943_500_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (119_148_000 as Weight) - // Standard Error: 2_000 - .saturating_add((585_000 as Weight).saturating_mul(r as Weight)) + (74_672_000 as Weight) + // Standard Error: 1_000 + .saturating_add((595_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (118_413_000 as Weight) - // Standard Error: 3_000 + (74_346_000 as Weight) + // Standard Error: 1_000 .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (118_700_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_415_000 as Weight).saturating_mul(r as Weight)) + (74_149_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_438_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (118_736_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_777_000 as Weight).saturating_mul(r as Weight)) + (74_186_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_789_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (118_277_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) + (74_040_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_898_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (118_360_000 as Weight) - // Standard Error: 0 - .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) + (73_909_000 as Weight) + // Standard Error: 1_000 + .saturating_add((910_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (118_142_000 as Weight) + (73_873_000 as Weight) // Standard Error: 3_000 - .saturating_add((1_439_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_446_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (118_239_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_553_000 as Weight).saturating_mul(r as Weight)) + (73_438_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_582_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (120_801_000 as Weight) + (75_993_000 as Weight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((8_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (118_536_000 as Weight) - // Standard Error: 16_000 - .saturating_add((17_082_000 as Weight).saturating_mul(r as Weight)) + (73_218_000 as Weight) + // Standard Error: 17_000 + .saturating_add((17_167_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (130_467_000 as Weight) + (85_517_000 as Weight) // Standard Error: 30_000 - .saturating_add((28_199_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((28_885_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (164_624_000 as Weight) + (119_915_000 as Weight) // Standard Error: 3_000 - .saturating_add((901_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((918_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (119_422_000 as Weight) - // Standard Error: 2_000 - .saturating_add((617_000 as Weight).saturating_mul(r as Weight)) + (74_718_000 as Weight) + // Standard Error: 1_000 + .saturating_add((618_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (119_747_000 as Weight) - // Standard Error: 2_000 - .saturating_add((668_000 as Weight).saturating_mul(r as Weight)) + (74_800_000 as Weight) + // Standard Error: 1_000 + .saturating_add((684_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (119_410_000 as Weight) - // Standard Error: 3_000 - .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) + (74_590_000 as Weight) + // Standard Error: 2_000 + .saturating_add((911_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (121_657_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_160_000 as Weight).saturating_mul(r as Weight)) + (76_776_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_159_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (121_531_000 as Weight) - // Standard Error: 1_000 + (77_283_000 as Weight) + // Standard Error: 2_000 .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (118_340_000 as Weight) - // Standard Error: 2_000 - .saturating_add((674_000 as Weight).saturating_mul(r as Weight)) + (74_555_000 as Weight) + // Standard Error: 1_000 + .saturating_add((655_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (118_114_000 as Weight) - // Standard Error: 194_000 - .saturating_add((229_474_000 as Weight).saturating_mul(r as Weight)) + (73_693_000 as Weight) + // Standard Error: 131_000 + .saturating_add((181_095_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (119_160_000 as Weight) - // Standard Error: 2_000 - .saturating_add((890_000 as Weight).saturating_mul(r as Weight)) + (74_457_000 as Weight) + // Standard Error: 1_000 + .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (119_199_000 as Weight) - // Standard Error: 3_000 - .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) + (74_287_000 as Weight) + // Standard Error: 1_000 + .saturating_add((907_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (119_103_000 as Weight) - // Standard Error: 4_000 - .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) + (74_603_000 as Weight) + // Standard Error: 3_000 + .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (119_033_000 as Weight) - // Standard Error: 3_000 - .saturating_add((917_000 as Weight).saturating_mul(r as Weight)) + (74_383_000 as Weight) + // Standard Error: 1_000 + .saturating_add((920_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (118_950_000 as Weight) - // Standard Error: 4_000 - .saturating_add((879_000 as Weight).saturating_mul(r as Weight)) + (74_020_000 as Weight) + // Standard Error: 2_000 + .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (118_534_000 as Weight) - // Standard Error: 2_000 - .saturating_add((888_000 as Weight).saturating_mul(r as Weight)) + (74_108_000 as Weight) + // Standard Error: 4_000 + .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (119_108_000 as Weight) + (74_197_000 as Weight) // Standard Error: 2_000 - .saturating_add((881_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((901_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (118_677_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (73_941_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (118_769_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (73_891_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_383_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (118_690_000 as Weight) + (74_253_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_369_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (118_899_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) + (74_125_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_371_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (118_519_000 as Weight) - // Standard Error: 6_000 - .saturating_add((1_376_000 as Weight).saturating_mul(r as Weight)) + (74_144_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_369_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (119_315_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (74_170_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_375_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (118_171_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) + (74_164_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (118_581_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) + (74_166_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_376_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (118_673_000 as Weight) + (73_920_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_381_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (118_618_000 as Weight) + (74_691_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (118_569_000 as Weight) + (74_198_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (118_261_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + (74_064_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (118_542_000 as Weight) - // Standard Error: 2_000 + (75_744_000 as Weight) + // Standard Error: 8_000 .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (118_648_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_993_000 as Weight).saturating_mul(r as Weight)) + (74_300_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_003_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (118_378_000 as Weight) - // Standard Error: 0 - .saturating_add((2_057_000 as Weight).saturating_mul(r as Weight)) + (74_001_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_051_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (118_813_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_995_000 as Weight).saturating_mul(r as Weight)) + (74_132_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_994_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (118_697_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_025_000 as Weight).saturating_mul(r as Weight)) + (74_241_000 as Weight) + // Standard Error: 3_000 + .saturating_add((2_070_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (118_838_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_332_000 as Weight).saturating_mul(r as Weight)) + (74_069_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (118_641_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (73_978_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (118_551_000 as Weight) + (74_053_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (118_603_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (73_891_000 as Weight) + // Standard Error: 0 + .saturating_add((1_371_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (118_885_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) + (74_062_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (118_602_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + (74_347_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (118_733_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) + (74_116_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (118_920_000 as Weight) + (73_837_000 as Weight) // Standard Error: 3_000 - .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) } } @@ -1051,32 +1051,32 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_560_000 as Weight) + (1_588_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (7_843_000 as Weight) + (6_994_000 as Weight) // Standard Error: 0 - .saturating_add((749_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((743_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (3_228_000 as Weight) - // Standard Error: 5_000 - .saturating_add((2_257_000 as Weight).saturating_mul(q as Weight)) + (2_831_000 as Weight) + // Standard Error: 3_000 + .saturating_add((2_232_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (20_531_000 as Weight) - // Standard Error: 34_000 - .saturating_add((66_014_000 as Weight).saturating_mul(c as Weight)) + (17_839_000 as Weight) + // Standard Error: 0 + .saturating_add((64_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1084,10 +1084,10 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) - fn call_with_code_kb(c: u32, ) -> Weight { - (295_703_000 as Weight) - // Standard Error: 53_000 - .saturating_add((57_661_000 as Weight).saturating_mul(c as Weight)) + fn call_with_code_per_byte(c: u32, ) -> Weight { + (222_400_000 as Weight) + // Standard Error: 0 + .saturating_add((56_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1099,11 +1099,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (332_572_000 as Weight) - // Standard Error: 125_000 - .saturating_add((149_095_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 7_000 - .saturating_add((1_779_000 as Weight).saturating_mul(s as Weight)) + (283_144_000 as Weight) + // Standard Error: 0 + .saturating_add((140_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1114,9 +1114,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (222_992_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_759_000 as Weight).saturating_mul(s as Weight)) + (171_794_000 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1125,7 +1125,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (189_003_000 as Weight) + (140_234_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1133,9 +1133,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (52_521_000 as Weight) - // Standard Error: 36_000 - .saturating_add((66_486_000 as Weight).saturating_mul(c as Weight)) + (49_467_000 as Weight) + // Standard Error: 0 + .saturating_add((66_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1143,7 +1143,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_705_000 as Weight) + (24_915_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1152,9 +1152,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (300_165_000 as Weight) - // Standard Error: 125_000 - .saturating_add((49_828_000 as Weight).saturating_mul(r as Weight)) + (218_957_000 as Weight) + // Standard Error: 114_000 + .saturating_add((49_881_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1163,9 +1163,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (179_488_000 as Weight) - // Standard Error: 718_000 - .saturating_add((375_855_000 as Weight).saturating_mul(r as Weight)) + (76_490_000 as Weight) + // Standard Error: 856_000 + .saturating_add((375_305_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1175,9 +1175,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (295_198_000 as Weight) - // Standard Error: 79_000 - .saturating_add((21_948_000 as Weight).saturating_mul(r as Weight)) + (213_485_000 as Weight) + // Standard Error: 76_000 + .saturating_add((22_020_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1186,9 +1186,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (300_366_000 as Weight) - // Standard Error: 111_000 - .saturating_add((49_435_000 as Weight).saturating_mul(r as Weight)) + (218_468_000 as Weight) + // Standard Error: 108_000 + .saturating_add((49_457_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1197,9 +1197,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (299_800_000 as Weight) - // Standard Error: 87_000 - .saturating_add((49_002_000 as Weight).saturating_mul(r as Weight)) + (218_950_000 as Weight) + // Standard Error: 99_000 + .saturating_add((48_859_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1208,9 +1208,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (303_057_000 as Weight) - // Standard Error: 175_000 - .saturating_add((139_293_000 as Weight).saturating_mul(r as Weight)) + (226_714_000 as Weight) + // Standard Error: 111_000 + .saturating_add((141_924_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1219,9 +1219,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (299_754_000 as Weight) - // Standard Error: 93_000 - .saturating_add((48_945_000 as Weight).saturating_mul(r as Weight)) + (216_673_000 as Weight) + // Standard Error: 90_000 + .saturating_add((49_367_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1230,9 +1230,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (302_229_000 as Weight) - // Standard Error: 128_000 - .saturating_add((49_007_000 as Weight).saturating_mul(r as Weight)) + (215_859_000 as Weight) + // Standard Error: 104_000 + .saturating_add((49_334_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1241,9 +1241,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (300_772_000 as Weight) - // Standard Error: 114_000 - .saturating_add((48_794_000 as Weight).saturating_mul(r as Weight)) + (216_419_000 as Weight) + // Standard Error: 109_000 + .saturating_add((49_417_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1252,9 +1252,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (301_936_000 as Weight) - // Standard Error: 119_000 - .saturating_add((48_839_000 as Weight).saturating_mul(r as Weight)) + (218_799_000 as Weight) + // Standard Error: 108_000 + .saturating_add((48_631_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1264,9 +1264,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (304_935_000 as Weight) - // Standard Error: 146_000 - .saturating_add((121_871_000 as Weight).saturating_mul(r as Weight)) + (215_968_000 as Weight) + // Standard Error: 147_000 + .saturating_add((122_978_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1275,9 +1275,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (178_176_000 as Weight) - // Standard Error: 52_000 - .saturating_add((24_960_000 as Weight).saturating_mul(r as Weight)) + (127_183_000 as Weight) + // Standard Error: 35_000 + .saturating_add((24_523_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1286,9 +1286,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (297_394_000 as Weight) - // Standard Error: 140_000 - .saturating_add((49_199_000 as Weight).saturating_mul(r as Weight)) + (217_535_000 as Weight) + // Standard Error: 91_000 + .saturating_add((48_400_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1297,9 +1297,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (374_409_000 as Weight) - // Standard Error: 3_000 - .saturating_add((11_924_000 as Weight).saturating_mul(n as Weight)) + (297_539_000 as Weight) + // Standard Error: 5_000 + .saturating_add((11_870_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1308,9 +1308,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (292_278_000 as Weight) - // Standard Error: 114_000 - .saturating_add((1_474_000 as Weight).saturating_mul(r as Weight)) + (211_807_000 as Weight) + // Standard Error: 160_000 + .saturating_add((1_717_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1319,9 +1319,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (294_714_000 as Weight) + (213_139_000 as Weight) // Standard Error: 0 - .saturating_add((230_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((197_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1332,9 +1332,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (297_589_000 as Weight) - // Standard Error: 2_835_000 - .saturating_add((53_498_000 as Weight).saturating_mul(r as Weight)) + (215_292_000 as Weight) + // Standard Error: 390_000 + .saturating_add((52_831_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1346,9 +1346,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (296_371_000 as Weight) - // Standard Error: 220_000 - .saturating_add((160_881_000 as Weight).saturating_mul(r as Weight)) + (215_802_000 as Weight) + // Standard Error: 132_000 + .saturating_add((159_065_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1357,9 +1357,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (308_401_000 as Weight) - // Standard Error: 202_000 - .saturating_add((277_771_000 as Weight).saturating_mul(r as Weight)) + (225_069_000 as Weight) + // Standard Error: 201_000 + .saturating_add((292_145_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1369,11 +1369,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (625_100_000 as Weight) - // Standard Error: 2_053_000 - .saturating_add((284_765_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 404_000 - .saturating_add((85_893_000 as Weight).saturating_mul(n as Weight)) + (519_617_000 as Weight) + // Standard Error: 1_751_000 + .saturating_add((290_832_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 345_000 + .saturating_add((82_584_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1384,17 +1384,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (182_141_000 as Weight) - // Standard Error: 134_000 - .saturating_add((41_928_000 as Weight).saturating_mul(r as Weight)) + (132_245_000 as Weight) + // Standard Error: 75_000 + .saturating_add((41_274_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (139_030_000 as Weight) - // Standard Error: 1_038_000 - .saturating_add((405_168_000 as Weight).saturating_mul(r as Weight)) + (48_288_000 as Weight) + // Standard Error: 1_024_000 + .saturating_add((408_264_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1402,25 +1402,25 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (689_591_000 as Weight) - // Standard Error: 275_000 - .saturating_add((31_438_000 as Weight).saturating_mul(n as Weight)) + (607_246_000 as Weight) + // Standard Error: 252_000 + .saturating_add((28_722_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (709_965_000 as Weight) - // Standard Error: 340_000 - .saturating_add((11_182_000 as Weight).saturating_mul(n as Weight)) + (623_983_000 as Weight) + // Standard Error: 305_000 + .saturating_add((11_374_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (169_937_000 as Weight) - // Standard Error: 883_000 - .saturating_add((389_090_000 as Weight).saturating_mul(r as Weight)) + (91_727_000 as Weight) + // Standard Error: 837_000 + .saturating_add((383_577_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1428,51 +1428,51 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (695_589_000 as Weight) - // Standard Error: 268_000 - .saturating_add((10_530_000 as Weight).saturating_mul(n as Weight)) + (604_749_000 as Weight) + // Standard Error: 251_000 + .saturating_add((11_086_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (195_080_000 as Weight) - // Standard Error: 607_000 - .saturating_add((328_903_000 as Weight).saturating_mul(r as Weight)) + (107_805_000 as Weight) + // Standard Error: 722_000 + .saturating_add((326_494_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (647_422_000 as Weight) - // Standard Error: 361_000 - .saturating_add((68_849_000 as Weight).saturating_mul(n as Weight)) + (564_604_000 as Weight) + // Standard Error: 360_000 + .saturating_add((65_184_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (198_907_000 as Weight) - // Standard Error: 658_000 - .saturating_add((295_368_000 as Weight).saturating_mul(r as Weight)) + (122_105_000 as Weight) + // Standard Error: 560_000 + .saturating_add((291_458_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (599_284_000 as Weight) - // Standard Error: 243_000 - .saturating_add((9_923_000 as Weight).saturating_mul(n as Weight)) + (512_580_000 as Weight) + // Standard Error: 245_000 + .saturating_add((10_171_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (170_700_000 as Weight) - // Standard Error: 887_000 - .saturating_add((422_448_000 as Weight).saturating_mul(r as Weight)) + (81_220_000 as Weight) + // Standard Error: 933_000 + .saturating_add((418_532_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1480,9 +1480,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (743_584_000 as Weight) - // Standard Error: 403_000 - .saturating_add((69_763_000 as Weight).saturating_mul(n as Weight)) + (652_330_000 as Weight) + // Standard Error: 357_000 + .saturating_add((65_711_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } @@ -1491,9 +1491,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (208_815_000 as Weight) - // Standard Error: 1_078_000 - .saturating_add((1_719_660_000 as Weight).saturating_mul(r as Weight)) + (126_544_000 as Weight) + // Standard Error: 1_198_000 + .saturating_add((1_796_593_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1505,8 +1505,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_471_000 - .saturating_add((27_917_429_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 3_033_000 + .saturating_add((19_788_005_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1518,8 +1518,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 13_012_000 - .saturating_add((28_044_371_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 6_663_000 + .saturating_add((19_835_985_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1528,11 +1528,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (15_964_304_000 as Weight) - // Standard Error: 19_327_000 - .saturating_add((1_629_626_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 8_000 - .saturating_add((11_992_000 as Weight).saturating_mul(c as Weight)) + (10_957_494_000 as Weight) + // Standard Error: 13_908_000 + .saturating_add((1_622_630_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 6_000 + .saturating_add((11_960_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1546,8 +1546,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 50_849_000 - .saturating_add((35_608_311_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 48_191_000 + .saturating_add((27_587_375_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1560,11 +1560,11 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (19_455_191_000 as Weight) - // Standard Error: 57_478_000 - .saturating_add((786_148_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 27_000 - .saturating_add((160_385_000 as Weight).saturating_mul(s as Weight)) + (14_504_226_000 as Weight) + // Standard Error: 66_350_000 + .saturating_add((912_874_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 31_000 + .saturating_add((157_415_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(207 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(205 as Weight)) @@ -1575,9 +1575,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (294_686_000 as Weight) - // Standard Error: 123_000 - .saturating_add((81_172_000 as Weight).saturating_mul(r as Weight)) + (216_771_000 as Weight) + // Standard Error: 127_000 + .saturating_add((79_994_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1586,9 +1586,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (276_895_000 as Weight) - // Standard Error: 35_000 - .saturating_add((469_007_000 as Weight).saturating_mul(n as Weight)) + (376_960_000 as Weight) + // Standard Error: 24_000 + .saturating_add((465_507_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1597,9 +1597,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (295_476_000 as Weight) - // Standard Error: 127_000 - .saturating_add((91_822_000 as Weight).saturating_mul(r as Weight)) + (212_554_000 as Weight) + // Standard Error: 129_000 + .saturating_add((92_073_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1608,9 +1608,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (402_456_000 as Weight) - // Standard Error: 19_000 - .saturating_add((311_103_000 as Weight).saturating_mul(n as Weight)) + (298_638_000 as Weight) + // Standard Error: 23_000 + .saturating_add((307_231_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1619,9 +1619,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (296_702_000 as Weight) - // Standard Error: 142_000 - .saturating_add((64_431_000 as Weight).saturating_mul(r as Weight)) + (216_274_000 as Weight) + // Standard Error: 100_000 + .saturating_add((64_205_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1630,9 +1630,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (375_322_000 as Weight) - // Standard Error: 14_000 - .saturating_add((124_338_000 as Weight).saturating_mul(n as Weight)) + (294_478_000 as Weight) + // Standard Error: 18_000 + .saturating_add((120_405_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1641,9 +1641,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (294_158_000 as Weight) - // Standard Error: 148_000 - .saturating_add((64_474_000 as Weight).saturating_mul(r as Weight)) + (215_874_000 as Weight) + // Standard Error: 115_000 + .saturating_add((63_402_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1652,9 +1652,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (390_049_000 as Weight) - // Standard Error: 16_000 - .saturating_add((124_330_000 as Weight).saturating_mul(n as Weight)) + (288_361_000 as Weight) + // Standard Error: 15_000 + .saturating_add((120_795_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1663,9 +1663,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (233_346_000 as Weight) - // Standard Error: 1_355_000 - .saturating_add((15_405_070_000 as Weight).saturating_mul(r as Weight)) + (142_940_000 as Weight) + // Standard Error: 1_317_000 + .saturating_add((15_385_437_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1676,264 +1676,264 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:36 w:36) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_158_000 - .saturating_add((932_937_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_981_000 + .saturating_add((943_500_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (119_148_000 as Weight) - // Standard Error: 2_000 - .saturating_add((585_000 as Weight).saturating_mul(r as Weight)) + (74_672_000 as Weight) + // Standard Error: 1_000 + .saturating_add((595_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (118_413_000 as Weight) - // Standard Error: 3_000 + (74_346_000 as Weight) + // Standard Error: 1_000 .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (118_700_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_415_000 as Weight).saturating_mul(r as Weight)) + (74_149_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_438_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (118_736_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_777_000 as Weight).saturating_mul(r as Weight)) + (74_186_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_789_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (118_277_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) + (74_040_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_898_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (118_360_000 as Weight) - // Standard Error: 0 - .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) + (73_909_000 as Weight) + // Standard Error: 1_000 + .saturating_add((910_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (118_142_000 as Weight) + (73_873_000 as Weight) // Standard Error: 3_000 - .saturating_add((1_439_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_446_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (118_239_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_553_000 as Weight).saturating_mul(r as Weight)) + (73_438_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_582_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (120_801_000 as Weight) + (75_993_000 as Weight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((8_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (118_536_000 as Weight) - // Standard Error: 16_000 - .saturating_add((17_082_000 as Weight).saturating_mul(r as Weight)) + (73_218_000 as Weight) + // Standard Error: 17_000 + .saturating_add((17_167_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (130_467_000 as Weight) + (85_517_000 as Weight) // Standard Error: 30_000 - .saturating_add((28_199_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((28_885_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (164_624_000 as Weight) + (119_915_000 as Weight) // Standard Error: 3_000 - .saturating_add((901_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((918_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (119_422_000 as Weight) - // Standard Error: 2_000 - .saturating_add((617_000 as Weight).saturating_mul(r as Weight)) + (74_718_000 as Weight) + // Standard Error: 1_000 + .saturating_add((618_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (119_747_000 as Weight) - // Standard Error: 2_000 - .saturating_add((668_000 as Weight).saturating_mul(r as Weight)) + (74_800_000 as Weight) + // Standard Error: 1_000 + .saturating_add((684_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (119_410_000 as Weight) - // Standard Error: 3_000 - .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) + (74_590_000 as Weight) + // Standard Error: 2_000 + .saturating_add((911_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (121_657_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_160_000 as Weight).saturating_mul(r as Weight)) + (76_776_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_159_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (121_531_000 as Weight) - // Standard Error: 1_000 + (77_283_000 as Weight) + // Standard Error: 2_000 .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (118_340_000 as Weight) - // Standard Error: 2_000 - .saturating_add((674_000 as Weight).saturating_mul(r as Weight)) + (74_555_000 as Weight) + // Standard Error: 1_000 + .saturating_add((655_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (118_114_000 as Weight) - // Standard Error: 194_000 - .saturating_add((229_474_000 as Weight).saturating_mul(r as Weight)) + (73_693_000 as Weight) + // Standard Error: 131_000 + .saturating_add((181_095_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (119_160_000 as Weight) - // Standard Error: 2_000 - .saturating_add((890_000 as Weight).saturating_mul(r as Weight)) + (74_457_000 as Weight) + // Standard Error: 1_000 + .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (119_199_000 as Weight) - // Standard Error: 3_000 - .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) + (74_287_000 as Weight) + // Standard Error: 1_000 + .saturating_add((907_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (119_103_000 as Weight) - // Standard Error: 4_000 - .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) + (74_603_000 as Weight) + // Standard Error: 3_000 + .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (119_033_000 as Weight) - // Standard Error: 3_000 - .saturating_add((917_000 as Weight).saturating_mul(r as Weight)) + (74_383_000 as Weight) + // Standard Error: 1_000 + .saturating_add((920_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (118_950_000 as Weight) - // Standard Error: 4_000 - .saturating_add((879_000 as Weight).saturating_mul(r as Weight)) + (74_020_000 as Weight) + // Standard Error: 2_000 + .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (118_534_000 as Weight) - // Standard Error: 2_000 - .saturating_add((888_000 as Weight).saturating_mul(r as Weight)) + (74_108_000 as Weight) + // Standard Error: 4_000 + .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (119_108_000 as Weight) + (74_197_000 as Weight) // Standard Error: 2_000 - .saturating_add((881_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((901_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (118_677_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (73_941_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (118_769_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (73_891_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_383_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (118_690_000 as Weight) + (74_253_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_369_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (118_899_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) + (74_125_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_371_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (118_519_000 as Weight) - // Standard Error: 6_000 - .saturating_add((1_376_000 as Weight).saturating_mul(r as Weight)) + (74_144_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_369_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (119_315_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (74_170_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_375_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (118_171_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) + (74_164_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (118_581_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) + (74_166_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_376_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (118_673_000 as Weight) + (73_920_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_381_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (118_618_000 as Weight) + (74_691_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (118_569_000 as Weight) + (74_198_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (118_261_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + (74_064_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (118_542_000 as Weight) - // Standard Error: 2_000 + (75_744_000 as Weight) + // Standard Error: 8_000 .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (118_648_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_993_000 as Weight).saturating_mul(r as Weight)) + (74_300_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_003_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (118_378_000 as Weight) - // Standard Error: 0 - .saturating_add((2_057_000 as Weight).saturating_mul(r as Weight)) + (74_001_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_051_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (118_813_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_995_000 as Weight).saturating_mul(r as Weight)) + (74_132_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_994_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (118_697_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_025_000 as Weight).saturating_mul(r as Weight)) + (74_241_000 as Weight) + // Standard Error: 3_000 + .saturating_add((2_070_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (118_838_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_332_000 as Weight).saturating_mul(r as Weight)) + (74_069_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (118_641_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (73_978_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (118_551_000 as Weight) + (74_053_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (118_603_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (73_891_000 as Weight) + // Standard Error: 0 + .saturating_add((1_371_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (118_885_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) + (74_062_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (118_602_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + (74_347_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (118_733_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) + (74_116_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (118_920_000 as Weight) + (73_837_000 as Weight) // Standard Error: 3_000 - .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) } } From 6ab64863c6e653da5cc468257650a970dbc8e9a1 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 16 Feb 2022 08:57:54 -0700 Subject: [PATCH 0526/1472] Tidy Democracy (#10867) * add test * Assorted refactorings * complete test * saturating math * final check * use `default` Co-authored-by: Gav Wood --- frame/democracy/src/lib.rs | 42 ++++++++++++++++++------- frame/democracy/src/tests/delegation.rs | 41 +++++++++++++++++++++++- frame/democracy/src/vote.rs | 9 +++++- 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index b578df5909306..8588f1876d7e3 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -842,7 +842,12 @@ pub mod pallet { >::kill(); let now = >::block_number(); - Self::inject_referendum(now + voting_period, proposal_hash, threshold, delay); + Self::inject_referendum( + now.saturating_add(voting_period), + proposal_hash, + threshold, + delay, + ); Ok(()) } @@ -871,7 +876,8 @@ pub mod pallet { existing_vetoers.binary_search(&who).err().ok_or(Error::::AlreadyVetoed)?; existing_vetoers.insert(insert_position, who.clone()); - let until = >::block_number() + T::CooloffPeriod::get(); + let until = + >::block_number().saturating_add(T::CooloffPeriod::get()); >::insert(&proposal_hash, (until, existing_vetoers)); Self::deposit_event(Event::::Vetoed { who, proposal_hash, until }); @@ -1089,7 +1095,10 @@ pub mod pallet { let now = >::block_number(); let (voting, enactment) = (T::VotingPeriod::get(), T::EnactmentPeriod::get()); let additional = if who == provider { Zero::zero() } else { enactment }; - ensure!(now >= since + voting + additional, Error::::TooEarly); + ensure!( + now >= since.saturating_add(voting).saturating_add(additional), + Error::::TooEarly + ); ensure!(expiry.map_or(true, |e| now > e), Error::::Imminent); let res = @@ -1282,7 +1291,7 @@ impl Pallet { /// Get the amount locked in support of `proposal`; `None` if proposal isn't a valid proposal /// index. pub fn backing_for(proposal: PropIndex) -> Option> { - Self::deposit_of(proposal).map(|(l, d)| d * (l.len() as u32).into()) + Self::deposit_of(proposal).map(|(l, d)| d.saturating_mul((l.len() as u32).into())) } /// Get all referenda ready for tally at block `n`. @@ -1318,7 +1327,7 @@ impl Pallet { delay: T::BlockNumber, ) -> ReferendumIndex { >::inject_referendum( - >::block_number() + T::VotingPeriod::get(), + >::block_number().saturating_add(T::VotingPeriod::get()), proposal_hash, threshold, delay, @@ -1424,7 +1433,9 @@ impl Pallet { }, Some(ReferendumInfo::Finished { end, approved }) => { if let Some((lock_periods, balance)) = votes[i].1.locked_if(approved) { - let unlock_at = end + T::VoteLockingPeriod::get() * lock_periods.into(); + let unlock_at = end.saturating_add( + T::VoteLockingPeriod::get().saturating_mul(lock_periods.into()), + ); let now = frame_system::Pallet::::block_number(); if now < unlock_at { ensure!( @@ -1513,9 +1524,16 @@ impl Pallet { }; sp_std::mem::swap(&mut old, voting); match old { - Voting::Delegating { balance, target, conviction, delegations, prior, .. } => { + Voting::Delegating { + balance, target, conviction, delegations, mut prior, .. + } => { // remove any delegation votes to our current target. Self::reduce_upstream_delegation(&target, conviction.votes(balance)); + let now = frame_system::Pallet::::block_number(); + let lock_periods = conviction.lock_periods().into(); + let unlock_block = now + .saturating_add(T::VoteLockingPeriod::get().saturating_mul(lock_periods)); + prior.accumulate(unlock_block, balance); voting.set_common(delegations, prior); }, Voting::Direct { votes, delegations, prior } => { @@ -1548,7 +1566,9 @@ impl Pallet { Self::reduce_upstream_delegation(&target, conviction.votes(balance)); let now = frame_system::Pallet::::block_number(); let lock_periods = conviction.lock_periods().into(); - prior.accumulate(now + T::VoteLockingPeriod::get() * lock_periods, balance); + let unlock_block = now + .saturating_add(T::VoteLockingPeriod::get().saturating_mul(lock_periods)); + prior.accumulate(unlock_block, balance); voting.set_common(delegations, prior); Ok(votes) @@ -1607,7 +1627,7 @@ impl Pallet { LastTabledWasExternal::::put(true); Self::deposit_event(Event::::ExternalTabled); Self::inject_referendum( - now + T::VotingPeriod::get(), + now.saturating_add(T::VotingPeriod::get()), proposal, threshold, T::EnactmentPeriod::get(), @@ -1639,7 +1659,7 @@ impl Pallet { depositors, }); Self::inject_referendum( - now + T::VotingPeriod::get(), + now.saturating_add(T::VotingPeriod::get()), proposal, VoteThreshold::SuperMajorityApprove, T::EnactmentPeriod::get(), @@ -1693,7 +1713,7 @@ impl Pallet { if status.delay.is_zero() { let _ = Self::do_enact_proposal(status.proposal_hash, index); } else { - let when = now + status.delay; + let when = now.saturating_add(status.delay); // Note that we need the preimage now. Preimages::::mutate_exists( &status.proposal_hash, diff --git a/frame/democracy/src/tests/delegation.rs b/frame/democracy/src/tests/delegation.rs index f644f22951748..3551ca8f91123 100644 --- a/frame/democracy/src/tests/delegation.rs +++ b/frame/democracy/src/tests/delegation.rs @@ -158,7 +158,7 @@ fn conviction_should_be_honored_in_delegation() { // If transactor voted, delegated vote is overwritten. new_test_ext().execute_with(|| { let r = begin_referendum(); - // Delegate, undelegate and vote. + // Delegate and vote. assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked6x, 20)); assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); // Delegated vote is huge. @@ -177,3 +177,42 @@ fn split_vote_delegation_should_be_ignored() { assert_eq!(tally(r), Tally { ayes: 1, nays: 0, turnout: 10 }); }); } + +#[test] +fn redelegation_keeps_lock() { + // If transactor voted, delegated vote is overwritten. + new_test_ext().execute_with(|| { + let r = begin_referendum(); + // Delegate and vote. + assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked6x, 20)); + assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + // Delegated vote is huge. + assert_eq!(tally(r), Tally { ayes: 121, nays: 0, turnout: 30 }); + + let mut prior_lock = vote::PriorLock::default(); + + // Locked balance of delegator exists + assert_eq!(VotingOf::::get(2).locked_balance(), 20); + assert_eq!(VotingOf::::get(2).prior(), &prior_lock); + + // Delegate someone else at a lower conviction and amount + assert_ok!(Democracy::delegate(Origin::signed(2), 3, Conviction::None, 10)); + + // 6x prior should appear w/ locked balance. + prior_lock.accumulate(98, 20); + assert_eq!(VotingOf::::get(2).prior(), &prior_lock); + assert_eq!(VotingOf::::get(2).locked_balance(), 20); + // Unlock shouldn't work + assert_ok!(Democracy::unlock(Origin::signed(2), 2)); + assert_eq!(VotingOf::::get(2).prior(), &prior_lock); + assert_eq!(VotingOf::::get(2).locked_balance(), 20); + + fast_forward_to(100); + + // Now unlock can remove the prior lock and reduce the locked amount. + assert_eq!(VotingOf::::get(2).prior(), &prior_lock); + assert_ok!(Democracy::unlock(Origin::signed(2), 2)); + assert_eq!(VotingOf::::get(2).prior(), &vote::PriorLock::default()); + assert_eq!(VotingOf::::get(2).locked_balance(), 10); + }); +} diff --git a/frame/democracy/src/vote.rs b/frame/democracy/src/vote.rs index e6a252dcf0151..c74623d4dfeb8 100644 --- a/frame/democracy/src/vote.rs +++ b/frame/democracy/src/vote.rs @@ -183,7 +183,7 @@ impl votes.iter().map(|i| i.1.balance()).fold(prior.locked(), |a, i| a.max(i)), - Voting::Delegating { balance, .. } => *balance, + Voting::Delegating { balance, prior, .. } => *balance.max(&prior.locked()), } } @@ -199,4 +199,11 @@ impl &PriorLock { + match self { + Voting::Direct { prior, .. } => prior, + Voting::Delegating { prior, .. } => prior, + } + } } From 36b8970ef68b2f8d031f0aeadbe47d06a2679332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 16 Feb 2022 20:39:22 +0100 Subject: [PATCH 0527/1472] sc-executor: Improve logging (#10869) Improves the logging by switching to `tracing` for a better log output. Besides that, it also adds a trace for the function being executed. --- Cargo.lock | 1 - client/executor/Cargo.toml | 3 +- client/executor/src/native_executor.rs | 58 +++++++++++++++----------- client/executor/src/wasm_runtime.rs | 20 ++++----- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e04aec94d76bc..992a49306f18f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8253,7 +8253,6 @@ dependencies = [ "hex-literal", "lazy_static", "libsecp256k1", - "log 0.4.14", "lru 0.6.6", "parity-scale-codec", "parking_lot 0.11.2", diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 0d0f2a8bd92ed..47ef050050864 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -31,10 +31,10 @@ sc-executor-common = { version = "0.10.0-dev", path = "common" } sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } parking_lot = "0.11.2" -log = "0.4.8" libsecp256k1 = "0.7" sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } lru = "0.6.6" +tracing = "0.1.29" [dev-dependencies] wat = "1.0" @@ -45,7 +45,6 @@ sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } -tracing = "0.1.29" tracing-subscriber = "0.2.19" paste = "1.0" regex = "1" diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 1bc87840ba353..363ea474a7e43 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -35,7 +35,6 @@ use std::{ }; use codec::{Decode, Encode}; -use log::trace; use sc_executor_common::{ runtime_blob::RuntimeBlob, wasm_runtime::{InvokeMethod, WasmInstance, WasmModule}, @@ -301,6 +300,12 @@ where _use_native: bool, _native_call: Option, ) -> (Result>, bool) { + tracing::trace!( + target: "executor", + %method, + "Executing function", + ); + let result = self.with_instance( runtime_code, ext, @@ -422,10 +427,10 @@ impl RuntimeSpawn for RuntimeInstanceSpawn { let async_ext = match new_async_externalities(scheduler.clone()) { Ok(val) => val, Err(e) => { - log::error!( + tracing::error!( target: "executor", - "Failed to setup externalities for async context: {}", - e, + error = %e, + "Failed to setup externalities for async context.", ); // This will drop sender and receiver end will panic @@ -438,10 +443,10 @@ impl RuntimeSpawn for RuntimeInstanceSpawn { )) { Ok(val) => val, Err(e) => { - log::error!( + tracing::error!( target: "executor", - "Failed to setup runtime extension for async externalities: {}", - e, + error = %e, + "Failed to setup runtime extension for async externalities", ); // This will drop sender and receiver end will panic @@ -476,7 +481,7 @@ impl RuntimeSpawn for RuntimeInstanceSpawn { Err(error) => { // If execution is panicked, the `join` in the original runtime code will // panic as well, since the sender is dropped without sending anything. - log::error!("Call error in spawned task: {}", error); + tracing::error!(error = %error, "Call error in spawned task"); }, } }), @@ -518,10 +523,10 @@ fn preregister_builtin_ext(module: Arc) { RuntimeInstanceSpawn::with_externalities_and_module(module, ext) { if let Err(e) = ext.register_extension(RuntimeSpawnExt(Box::new(runtime_spawn))) { - trace!( + tracing::trace!( target: "executor", - "Failed to register `RuntimeSpawnExt` instance on externalities: {:?}", - e, + error = ?e, + "Failed to register `RuntimeSpawnExt` instance on externalities", ) } } @@ -543,6 +548,12 @@ impl CodeExecutor for NativeElseWasmExecut use_native: bool, native_call: Option, ) -> (Result>, bool) { + tracing::trace!( + target: "executor", + function = %method, + "Executing function", + ); + let mut used_native = false; let result = self.wasm.with_instance( runtime_code, @@ -558,11 +569,11 @@ impl CodeExecutor for NativeElseWasmExecut match (use_native, can_call_with, native_call) { (_, false, _) | (false, _, _) => { if !can_call_with { - trace!( + tracing::trace!( target: "executor", - "Request for native execution failed (native: {}, chain: {})", - self.native_version.runtime_version, - onchain_version, + native = %self.native_version.runtime_version, + chain = %onchain_version, + "Request for native execution failed", ); } @@ -572,12 +583,11 @@ impl CodeExecutor for NativeElseWasmExecut }) }, (true, true, Some(call)) => { - trace!( + tracing::trace!( target: "executor", - "Request for native execution with native call succeeded \ - (native: {}, chain: {}).", - self.native_version.runtime_version, - onchain_version, + native = %self.native_version.runtime_version, + chain = %onchain_version, + "Request for native execution with native call succeeded" ); used_native = true; @@ -587,11 +597,11 @@ impl CodeExecutor for NativeElseWasmExecut Ok(res) }, _ => { - trace!( + tracing::trace!( target: "executor", - "Request for native execution succeeded (native: {}, chain: {})", - self.native_version.runtime_version, - onchain_version + native = %self.native_version.runtime_version, + chain = %onchain_version, + "Request for native execution succeeded", ); used_native = true; diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 2cccb6f9c38b0..d996d7b490e88 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -103,23 +103,23 @@ impl VersionedRuntime { let result = f(&self.module, &mut *instance, self.version.as_ref(), ext); if let Err(e) = &result { if new_inst { - log::warn!( + tracing::warn!( target: "wasm-runtime", - "Fresh runtime instance failed with {}", - e, + error = %e, + "Fresh runtime instance failed", ) } else { - log::warn!( + tracing::warn!( target: "wasm-runtime", - "Evicting failed runtime instance: {}", - e, + error = %e, + "Evicting failed runtime instance", ); } } else { *locked = Some(instance); if new_inst { - log::debug!( + tracing::debug!( target: "wasm-runtime", "Allocated WASM instance {}/{}", index + 1, @@ -131,7 +131,7 @@ impl VersionedRuntime { result }, None => { - log::warn!(target: "wasm-runtime", "Ran out of free WASM instances"); + tracing::warn!(target: "wasm-runtime", "Ran out of free WASM instances"); // Allocate a new instance let mut instance = self.module.new_instance()?; @@ -259,7 +259,7 @@ impl RuntimeCache { match result { Ok(ref result) => { - log::debug!( + tracing::debug!( target: "wasm-runtime", "Prepared new runtime version {:?} in {} ms.", result.version, @@ -267,7 +267,7 @@ impl RuntimeCache { ); }, Err(ref err) => { - log::warn!(target: "wasm-runtime", "Cannot create a runtime: {:?}", err); + tracing::warn!(target: "wasm-runtime", error = ?err, "Cannot create a runtime"); }, } From e7be15e245dc28848264861ff5b859116a937b3f Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Thu, 17 Feb 2022 12:37:54 +0100 Subject: [PATCH 0528/1472] Track allowed requests for state/warp sync (#10843) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Track allowed requests for state/warp sync * Added missing allowed_requests resets * Apply suggestions from code review Co-authored-by: Bastian Köcher * fmt Co-authored-by: Bastian Köcher --- client/network/src/protocol/sync.rs | 72 +++++++++++++++++------------ 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index d98c0d2c04abe..f31afc828bd86 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -141,12 +141,12 @@ mod rep { pub const BAD_RESPONSE: Rep = Rep::new(-(1 << 12), "Incomplete response"); } -enum PendingRequests { +enum AllowedRequests { Some(HashSet), All, } -impl PendingRequests { +impl AllowedRequests { fn add(&mut self, id: &PeerId) { if let Self::Some(ref mut set) = self { set.insert(*id); @@ -174,9 +174,13 @@ impl PendingRequests { Self::All => false, } } + + fn clear(&mut self) { + std::mem::take(self); + } } -impl Default for PendingRequests { +impl Default for AllowedRequests { fn default() -> Self { Self::Some(HashSet::default()) } @@ -211,7 +215,7 @@ pub struct ChainSync { /// Fork sync targets. fork_targets: HashMap>, /// A set of peers for which there might be potential block requests - pending_requests: PendingRequests, + allowed_requests: AllowedRequests, /// A type to check incoming block announcements. block_announce_validator: Box + Send>, /// Maximum number of peers to ask the same blocks in parallel. @@ -549,7 +553,7 @@ impl ChainSync { mode, queue_blocks: Default::default(), fork_targets: Default::default(), - pending_requests: Default::default(), + allowed_requests: Default::default(), block_announce_validator, max_parallel_downloads, downloaded_blocks: 0, @@ -730,7 +734,7 @@ impl ChainSync { ) }; - self.pending_requests.add(&who); + self.allowed_requests.add(&who); self.peers.insert( who, PeerSync { @@ -774,7 +778,7 @@ impl ChainSync { state: PeerSyncState::Available, }, ); - self.pending_requests.add(&who); + self.allowed_requests.add(&who); Ok(None) }, } @@ -841,7 +845,7 @@ impl ChainSync { peer.best_number = number; peer.best_hash = *hash; } - self.pending_requests.add(peer_id); + self.allowed_requests.add(peer_id); } } @@ -883,7 +887,7 @@ impl ChainSync { /// Get an iterator over all block requests of all peers. pub fn block_requests(&mut self) -> impl Iterator)> + '_ { - if self.pending_requests.is_empty() || + if self.allowed_requests.is_empty() || self.state_sync.is_some() || self.mode == SyncMode::Warp { @@ -903,11 +907,11 @@ impl ChainSync { let best_queued = self.best_queued_number; let client = &self.client; let queue = &self.queue_blocks; - let pending_requests = self.pending_requests.take(); + let allowed_requests = self.allowed_requests.take(); let max_parallel = if major_sync { 1 } else { self.max_parallel_downloads }; let gap_sync = &mut self.gap_sync; let iter = self.peers.iter_mut().filter_map(move |(id, peer)| { - if !peer.state.is_available() || !pending_requests.contains(id) { + if !peer.state.is_available() || !allowed_requests.contains(id) { return None } @@ -994,7 +998,12 @@ impl ChainSync { /// Get a state request, if any. pub fn state_request(&mut self) -> Option<(PeerId, StateRequest)> { - if self.peers.iter().any(|(_, peer)| peer.state == PeerSyncState::DownloadingState) { + if self.allowed_requests.is_empty() { + return None + } + if (self.state_sync.is_some() || self.warp_sync.is_some()) && + self.peers.iter().any(|(_, peer)| peer.state == PeerSyncState::DownloadingState) + { // Only one pending state request is allowed. return None } @@ -1002,11 +1011,13 @@ impl ChainSync { if sync.is_complete() { return None } + for (id, peer) in self.peers.iter_mut() { if peer.state.is_available() && peer.common_number >= sync.target_block_num() { peer.state = PeerSyncState::DownloadingState; let request = sync.next_request(); trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); + self.allowed_requests.clear(); return Some((*id, request)) } } @@ -1022,6 +1033,7 @@ impl ChainSync { if peer.state.is_available() && peer.best_number >= target { trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); peer.state = PeerSyncState::DownloadingState; + self.allowed_requests.clear(); return Some((*id, request)) } } @@ -1032,16 +1044,14 @@ impl ChainSync { /// Get a warp sync request, if any. pub fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)> { - if self - .peers - .iter() - .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpProof) - { - // Only one pending state request is allowed. - return None - } if let Some(sync) = &self.warp_sync { - if sync.is_complete() { + if self.allowed_requests.is_empty() || + sync.is_complete() || + self.peers + .iter() + .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpProof) + { + // Only one pending state request is allowed. return None } if let Some(request) = sync.next_warp_poof_request() { @@ -1054,6 +1064,7 @@ impl ChainSync { if peer.state.is_available() && peer.best_number >= median { trace!(target: "sync", "New WarpProofRequest for {}", id); peer.state = PeerSyncState::DownloadingWarpProof; + self.allowed_requests.clear(); return Some((*id, request)) } } @@ -1087,7 +1098,7 @@ impl ChainSync { trace!(target: "sync", "Reversing incoming block list"); blocks.reverse() } - self.pending_requests.add(who); + self.allowed_requests.add(who); if let Some(request) = request { match &mut peer.state { PeerSyncState::DownloadingNew(_) => { @@ -1306,6 +1317,7 @@ impl ChainSync { if let Some(peer) = self.peers.get_mut(&who) { if let PeerSyncState::DownloadingState = peer.state { peer.state = PeerSyncState::Available; + self.allowed_requests.set_all(); } } let import_result = if let Some(sync) = &mut self.state_sync { @@ -1368,6 +1380,7 @@ impl ChainSync { if let Some(peer) = self.peers.get_mut(&who) { if let PeerSyncState::DownloadingWarpProof = peer.state { peer.state = PeerSyncState::Available; + self.allowed_requests.set_all(); } } let import_result = if let Some(sync) = &mut self.warp_sync { @@ -1448,7 +1461,7 @@ impl ChainSync { return Ok(OnBlockJustification::Nothing) }; - self.pending_requests.add(&who); + self.allowed_requests.add(&who); if let PeerSyncState::DownloadingJustification(hash) = peer.state { peer.state = PeerSyncState::Available; @@ -1638,7 +1651,7 @@ impl ChainSync { }; } - self.pending_requests.set_all(); + self.allowed_requests.set_all(); output.into_iter() } @@ -1648,7 +1661,7 @@ impl ChainSync { let finalization_result = if success { Ok((hash, number)) } else { Err(()) }; self.extra_justifications .try_finalize_root((hash, number), finalization_result, true); - self.pending_requests.set_all(); + self.allowed_requests.set_all(); } /// Notify about finalization of the given block. @@ -1675,6 +1688,7 @@ impl ChainSync { ); self.state_sync = Some(StateSync::new(self.client.clone(), header, *skip_proofs)); + self.allowed_requests.set_all(); } } } @@ -1725,7 +1739,7 @@ impl ChainSync { peer.common_number = new_common_number; } } - self.pending_requests.set_all(); + self.allowed_requests.set_all(); } /// Checks if there is a slot for a block announce validation. @@ -1994,7 +2008,7 @@ impl ChainSync { peer.update_common_number(number - One::one()); } } - self.pending_requests.add(&who); + self.allowed_requests.add(&who); // known block case if known || self.is_already_downloading(&hash) { @@ -2060,7 +2074,7 @@ impl ChainSync { } self.peers.remove(who); self.extra_justifications.peer_disconnected(who); - self.pending_requests.set_all(); + self.allowed_requests.set_all(); self.fork_targets.retain(|_, target| { target.peers.remove(who); !target.peers.is_empty() @@ -2083,7 +2097,7 @@ impl ChainSync { if let Err(e) = self.reset_sync_start_point() { warn!(target: "sync", "💔 Unable to restart sync: {}", e); } - self.pending_requests.set_all(); + self.allowed_requests.set_all(); debug!(target:"sync", "Restarted with {} ({})", self.best_queued_number, self.best_queued_hash); let old_peers = std::mem::take(&mut self.peers); From d435ffb0ffee9e0743d4b679699e3ecacffd0d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 17 Feb 2022 17:05:18 +0100 Subject: [PATCH 0529/1472] Slots: Ensure that a race betwen finalized and best number is taken care off (#10876) --- client/consensus/slots/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 9fc93788a33e9..fc635e9184051 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -789,7 +789,9 @@ where return false } - let unfinalized_block_length = chain_head_number - finalized_number; + // There can be race between getting the finalized number and getting the best number. + // So, better be safe than sorry. + let unfinalized_block_length = chain_head_number.saturating_sub(finalized_number); let interval = unfinalized_block_length.saturating_sub(self.unfinalized_slack) / self.authoring_bias; let interval = interval.min(self.max_interval); From 13495bee57188ff20c47e12b470a3ca2e671e0d9 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 18 Feb 2022 11:03:18 +0200 Subject: [PATCH 0530/1472] Remove old lock file (#10879) --- primitives/npos-elections/fuzzer/Cargo.lock | 1602 ------------------- 1 file changed, 1602 deletions(-) delete mode 100644 primitives/npos-elections/fuzzer/Cargo.lock diff --git a/primitives/npos-elections/fuzzer/Cargo.lock b/primitives/npos-elections/fuzzer/Cargo.lock deleted file mode 100644 index cd172421aeb28..0000000000000 --- a/primitives/npos-elections/fuzzer/Cargo.lock +++ /dev/null @@ -1,1602 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[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 = "ahash" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f33b5018f120946c1dcf279194f238a9f146725593ead1c08fa47ff22b0b5d3" -dependencies = [ - "const-random", -] - -[[package]] -name = "aho-corasick" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" -dependencies = [ - "memchr", -] - -[[package]] -name = "arbitrary" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cf76cb6e2222ed0ea86b2b0ee2f71c96ec6edd5af42e84d59160e91b836ec4" - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" - -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - -[[package]] -name = "autocfg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" - -[[package]] -name = "backtrace" -version = "0.3.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" -dependencies = [ - "backtrace-sys", - "cfg-if", - "libc", - "rustc-demangle", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "base58" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bitvec" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993f74b4c99c1908d156b8d2e0fb6277736b0ecbd833982fd1241d39b2766a6" - -[[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", -] - -[[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 = "byte-slice-cast" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" - -[[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.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - -[[package]] -name = "cc" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "clear_on_drop" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" -dependencies = [ - "cc", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - -[[package]] -name = "const-random" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" -dependencies = [ - "const-random-macro", - "proc-macro-hack", -] - -[[package]] -name = "const-random-macro" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" -dependencies = [ - "getrandom", - "proc-macro-hack", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-mac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -dependencies = [ - "generic-array", - "subtle 1.0.0", -] - -[[package]] -name = "curve25519-dalek" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7dcd30ba50cdf88b55b033456138b7c0ac4afdc436d82e1b79f370f24cc66d" -dependencies = [ - "byteorder", - "clear_on_drop", - "digest", - "rand_core 0.3.1", - "subtle 2.2.2", -] - -[[package]] -name = "curve25519-dalek" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839" -dependencies = [ - "byteorder", - "digest", - "rand_core 0.5.1", - "subtle 2.2.2", - "zeroize 1.1.0", -] - -[[package]] -name = "derive_more" -version = "0.99.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a806e96c59a76a5ba6e18735b6cf833344671e61e7863f2edb5c518ea2cac95c" -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", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.0-pre.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978710b352437433c97b2bff193f2fb1dfd58a093f863dd95e225a19baa599a2" -dependencies = [ - "clear_on_drop", - "curve25519-dalek 2.0.0", - "rand 0.7.3", - "sha2", -] - -[[package]] -name = "environmental" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516aa8d7a71cb00a1c4146f0798549b93d083d4f189b3ced8f3de6b8f11ee6c4" - -[[package]] -name = "failure" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "fixed-hash" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3367952ceb191f4ab95dd5685dc163ac539e36202f9fcfd0cb22f9f9c542fefc" -dependencies = [ - "byteorder", - "libc", - "rand 0.7.3", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -dependencies = [ - "typenum", -] - -[[package]] -name = "getrandom" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[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.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" -dependencies = [ - "ahash", - "autocfg 0.1.7", -] - -[[package]] -name = "hex" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" - -[[package]] -name = "hmac" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" -dependencies = [ - "crypto-mac", - "digest", -] - -[[package]] -name = "hmac-drbg" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" -dependencies = [ - "digest", - "generic-array", - "hmac", -] - -[[package]] -name = "honggfuzz" -version = "0.5.45" -dependencies = [ - "arbitrary", - "lazy_static", - "memmap", -] - -[[package]] -name = "impl-codec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-serde" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-serde" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bbe9ea9b182f0fb1cabbd61f4ff9b7b7b9197955e95a7e4c27de5055eb29ff8" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "integer-sqrt" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65877bf7d44897a473350b1046277941cee20b263397e90869c50b6e766088b" - -[[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.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" - -[[package]] -name = "libsecp256k1" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" -dependencies = [ - "arrayref", - "crunchy", - "digest", - "hmac-drbg", - "rand 0.7.3", - "sha2", - "subtle 2.2.2", - "typenum", -] - -[[package]] -name = "lock_api" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - -[[package]] -name = "memchr" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" - -[[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.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198831fe8722331a395bc199a5d08efbc197497ef354cb4c77b969c02ffc0fc4" -dependencies = [ - "ahash", - "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 = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0942b357c1b4d0dc43ba724674ec89c3218e6ca2b3e8269e7cb53bcecd2f6e" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.4.2", - "zeroize 1.1.0", -] - -[[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 1.0.0", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -dependencies = [ - "autocfg 1.0.0", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da4dc79f9e6c81bef96148c8f6b8e72ad4541caa4a24373e900a36da07de03a3" -dependencies = [ - "autocfg 1.0.0", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" -dependencies = [ - "autocfg 1.0.0", -] - -[[package]] -name = "once_cell" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" -dependencies = [ - "parking_lot 0.9.0", -] - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "parity-scale-codec" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f509c5e67ca0605ee17dcd3f91ef41cadd685c75a298fb6261b781a5acb3f910" -dependencies = [ - "arrayvec 0.5.1", - "bitvec", - "byte-slice-cast", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0ec292e92e8ec7c58e576adacc1e3f399c597c8f263c42f18420abe58e7245" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "parity-util-mem" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1476e40bf8f5c6776e9600983435821ca86eb9819d74a6207cca69d091406a" -dependencies = [ - "cfg-if", - "impl-trait-for-tuples", - "parity-util-mem-derive", - "parking_lot 0.10.0", - "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.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" - -[[package]] -name = "parking_lot" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -dependencies = [ - "lock_api", - "parking_lot_core 0.6.2", - "rustc_version", -] - -[[package]] -name = "parking_lot" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" -dependencies = [ - "lock_api", - "parking_lot_core 0.7.0", -] - -[[package]] -name = "parking_lot_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -dependencies = [ - "cfg-if", - "cloudabi", - "libc", - "redox_syscall", - "rustc_version", - "smallvec 0.6.13", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" -dependencies = [ - "cfg-if", - "cloudabi", - "libc", - "redox_syscall", - "smallvec 1.3.0", - "winapi", -] - -[[package]] -name = "paste" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e1afe738d71b1ebab5f1207c055054015427dbfc7bbe9ee1266894156ec046" -dependencies = [ - "paste-impl", - "proc-macro-hack", -] - -[[package]] -name = "paste-impl" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d4dc4a7f6f743211c5aab239640a65091535d97d43d92a52bca435a640892bb" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pbkdf2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" -dependencies = [ - "byteorder", - "crypto-mac", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" - -[[package]] -name = "primitive-types" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4336f4f5d5524fa60bcbd6fe626f9223d8142a50e7053e979acdf0da41ab975" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-serde 0.3.0", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.7", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc 0.1.0", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.7", - "rand_core 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_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[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_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "redox_syscall" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" - -[[package]] -name = "regex" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", - "thread_local", -] - -[[package]] -name = "regex-syntax" -version = "0.6.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1132f845907680735a84409c3bebc64d1364a5683ffbce899550cd09d5eaefc1" - -[[package]] -name = "rustc-demangle" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" - -[[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.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "schnorrkel" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eacd8381b3c37840c9c9f40472af529e49975bdcbc24f83c31059fd6539023d3" -dependencies = [ - "curve25519-dalek 1.2.3", - "failure", - "merlin", - "rand 0.6.5", - "rand_core 0.4.2", - "rand_os", - "sha2", - "subtle 2.2.2", - "zeroize 0.9.3", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[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.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sha2" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" -dependencies = [ - "block-buffer", - "digest", - "fake-simd", - "opaque-debug", -] - -[[package]] -name = "smallvec" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -dependencies = [ - "maybe-uninit", -] - -[[package]] -name = "smallvec" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" - -[[package]] -name = "sp-application-crypto" -version = "2.0.0-alpha.3" -dependencies = [ - "parity-scale-codec", - "serde", - "sp-core", - "sp-io", - "sp-std", -] - -[[package]] -name = "sp-arithmetic" -version = "2.0.0-alpha.3" -dependencies = [ - "integer-sqrt", - "num-traits", - "parity-scale-codec", - "serde", - "sp-debug-derive", - "sp-std", -] - -[[package]] -name = "sp-core" -version = "2.0.0-alpha.3" -dependencies = [ - "base58", - "blake2-rfc", - "byteorder", - "ed25519-dalek", - "hash-db", - "hash256-std-hasher", - "hex", - "impl-serde 0.3.0", - "lazy_static", - "libsecp256k1", - "log", - "num-traits", - "parity-scale-codec", - "parity-util-mem", - "parking_lot 0.10.0", - "primitive-types", - "rand 0.7.3", - "regex", - "rustc-hex", - "schnorrkel", - "serde", - "sha2", - "sp-debug-derive", - "sp-externalities", - "sp-runtime-interface", - "sp-std", - "sp-storage", - "substrate-bip39", - "tiny-bip39", - "tiny-keccak", - "twox-hash", - "wasmi", - "zeroize 1.1.0", -] - -[[package]] -name = "sp-debug-derive" -version = "2.0.0-alpha.3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-externalities" -version = "0.8.0-alpha.3" -dependencies = [ - "environmental", - "sp-std", - "sp-storage", -] - -[[package]] -name = "sp-inherents" -version = "2.0.0-alpha.3" -dependencies = [ - "derive_more", - "parity-scale-codec", - "parking_lot 0.10.0", - "sp-core", - "sp-std", -] - -[[package]] -name = "sp-io" -version = "2.0.0-alpha.3" -dependencies = [ - "hash-db", - "libsecp256k1", - "log", - "parity-scale-codec", - "sp-core", - "sp-externalities", - "sp-runtime-interface", - "sp-state-machine", - "sp-std", - "sp-trie", - "sp-wasm-interface", -] - -[[package]] -name = "sp-panic-handler" -version = "2.0.0-alpha.3" -dependencies = [ - "backtrace", - "log", -] - -[[package]] -name = "sp-npos-elections" -version = "2.0.0-alpha.3" -dependencies = [ - "parity-scale-codec", - "serde", - "sp-core", - "sp-npos-elections-compact", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "sp-npos-elections-compact" -version = "2.0.0-rc3" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-npos-elections-fuzzer" -version = "2.0.0" -dependencies = [ - "honggfuzz", - "rand 0.7.3", - "sp-npos-elections", -] - -[[package]] -name = "sp-runtime" -version = "2.0.0-alpha.3" -dependencies = [ - "hash256-std-hasher", - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "parity-util-mem", - "paste", - "rand 0.7.3", - "serde", - "sp-application-crypto", - "sp-arithmetic", - "sp-core", - "sp-inherents", - "sp-io", - "sp-std", -] - -[[package]] -name = "sp-runtime-interface" -version = "2.0.0-alpha.3" -dependencies = [ - "parity-scale-codec", - "primitive-types", - "sp-externalities", - "sp-runtime-interface-proc-macro", - "sp-std", - "sp-wasm-interface", - "static_assertions", -] - -[[package]] -name = "sp-runtime-interface-proc-macro" -version = "2.0.0-alpha.3" -dependencies = [ - "Inflector", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-state-machine" -version = "0.8.0-alpha.3" -dependencies = [ - "hash-db", - "log", - "num-traits", - "parity-scale-codec", - "parking_lot 0.10.0", - "rand 0.7.3", - "sp-core", - "sp-externalities", - "sp-panic-handler", - "sp-trie", - "trie-db", - "trie-root", -] - -[[package]] -name = "sp-std" -version = "2.0.0-alpha.3" - -[[package]] -name = "sp-storage" -version = "2.0.0-alpha.3" -dependencies = [ - "impl-serde 0.2.3", - "serde", - "sp-debug-derive", - "sp-std", -] - -[[package]] -name = "sp-trie" -version = "2.0.0-alpha.3" -dependencies = [ - "hash-db", - "memory-db", - "parity-scale-codec", - "sp-core", - "sp-std", - "trie-db", - "trie-root", -] - -[[package]] -name = "sp-wasm-interface" -version = "2.0.0-alpha.3" -dependencies = [ - "impl-trait-for-tuples", - "parity-scale-codec", - "sp-std", - "wasmi", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "substrate-bip39" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be511be555a3633e71739a79e4ddff6a6aaa6579fa6114182a51d72c3eb93c5" -dependencies = [ - "hmac", - "pbkdf2", - "schnorrkel", - "sha2", -] - -[[package]] -name = "subtle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" - -[[package]] -name = "subtle" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" - -[[package]] -name = "syn" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "synstructure" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "tiny-bip39" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6848cd8f566953ce1e8faeba12ee23cbdbb0437754792cd857d44628b5685e3" -dependencies = [ - "failure", - "hmac", - "once_cell", - "pbkdf2", - "rand 0.7.3", - "rustc-hash", - "sha2", - "unicode-normalization", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2953ca5148619bc99695c1274cb54c5275bbb913c6adad87e72eaf8db9787f69" -dependencies = [ - "crunchy", -] - -[[package]] -name = "toml" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" -dependencies = [ - "serde", -] - -[[package]] -name = "trie-db" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de9222c50cc325855621271157c973da27a0dcd26fa06f8edf81020bd2333df0" -dependencies = [ - "hash-db", - "hashbrown", - "log", - "rustc-hex", - "smallvec 1.3.0", -] - -[[package]] -name = "trie-root" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "652931506d2c1244d7217a70b99f56718a7b4161b37f04e7cd868072a99f68cd" -dependencies = [ - "hash-db", -] - -[[package]] -name = "twox-hash" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" -dependencies = [ - "rand 0.7.3", -] - -[[package]] -name = "typenum" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" - -[[package]] -name = "uint" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75a4cdd7b87b28840dba13c483b9a88ee6bbf16ba5c951ee1ecfcf723078e0d" -dependencies = [ - "byteorder", - "crunchy", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" -dependencies = [ - "smallvec 1.3.0", -] - -[[package]] -name = "unicode-xid" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasmi" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf617d864d25af3587aa745529f7aaa541066c876d57e050c0d0c85c61c92aff" -dependencies = [ - "libc", - "memory_units", - "num-rational", - "num-traits", - "parity-wasm", - "wasmi-validation", -] - -[[package]] -name = "wasmi-validation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93" -dependencies = [ - "parity-wasm", -] - -[[package]] -name = "winapi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -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-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "zeroize" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45af6a010d13e4cf5b54c94ba5a2b2eba5596b9e46bf5875612d332a1f2b3f86" - -[[package]] -name = "zeroize" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] From adc95f06936dbdec9479958b13255fcad033264f Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 18 Feb 2022 21:35:43 +0900 Subject: [PATCH 0531/1472] Further reduce the CPU overhead of networking metrics (#10875) * Simplify `num_connected_peers` * Track requested peer counts * Revert "Track requested peer counts" This reverts commit 9f1c8704353df6afc17ed7e9f4ab8d8e29466ae4. * Remove `substrate_sub_libp2p_peerset_num_requested` metric * Remove two unused functions that I forgot to get rid of in previous commit --- client/network/src/protocol.rs | 8 +------ .../src/protocol/notifications/behaviour.rs | 21 ------------------- client/network/src/service.rs | 4 ---- client/network/src/service/metrics.rs | 5 ----- 4 files changed, 1 insertion(+), 37 deletions(-) diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index b39d0d1b8428b..eb634ca5be764 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -465,12 +465,6 @@ impl Protocol { self.behaviour.open_peers() } - /// Returns the list of all the peers that the peerset currently requests us to be connected - /// to on the default set. - pub fn requested_peers(&self) -> impl Iterator { - self.behaviour.requested_peers(HARDCODED_PEERSETS_SYNC) - } - /// Returns the number of discovered nodes that we keep in memory. pub fn num_discovered_peers(&self) -> usize { self.behaviour.num_discovered_peers() @@ -496,7 +490,7 @@ impl Protocol { /// Returns the number of peers we're connected to. pub fn num_connected_peers(&self) -> usize { - self.peers.values().count() + self.peers.len() } /// Returns the number of peers we're connected to and that are being queried. diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 97047201c308c..b47216473970e 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -251,16 +251,6 @@ impl PeerState { _ => None, } } - - /// True if that node has been requested by the PSM. - fn is_requested(&self) -> bool { - matches!( - self, - Self::PendingRequest { .. } | - Self::Requested | Self::DisabledPendingEnable { .. } | - Self::Enabled { .. } - ) - } } /// State of the handler of a single connection visible from this state machine. @@ -560,17 +550,6 @@ impl Notifications { } } - /// Returns the list of all the peers that the peerset currently requests us to be connected to. - pub fn requested_peers<'a>( - &'a self, - set_id: sc_peerset::SetId, - ) -> impl Iterator + 'a { - self.peers - .iter() - .filter(move |((_, set), state)| *set == set_id && state.is_requested()) - .map(|((id, _), _)| id) - } - /// Returns the list of reserved peers. pub fn reserved_peers<'a>( &'a self, diff --git a/client/network/src/service.rs b/client/network/src/service.rs index b6a1d3c88e7f3..a02aa982318a9 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -2108,10 +2108,6 @@ impl Future for NetworkWorker { .peerset_num_discovered .set(this.network_service.behaviour_mut().user_protocol().num_discovered_peers() as u64); - metrics.peerset_num_requested.set( - this.network_service.behaviour_mut().user_protocol().requested_peers().count() - as u64, - ); metrics.pending_connections.set( Swarm::network_info(&this.network_service).connection_counters().num_pending() as u64, diff --git a/client/network/src/service/metrics.rs b/client/network/src/service/metrics.rs index bf94287d12918..ad30b1b093ff9 100644 --- a/client/network/src/service/metrics.rs +++ b/client/network/src/service/metrics.rs @@ -69,7 +69,6 @@ pub struct Metrics { pub notifications_streams_closed_total: CounterVec, pub notifications_streams_opened_total: CounterVec, pub peerset_num_discovered: Gauge, - pub peerset_num_requested: Gauge, pub pending_connections: Gauge, pub pending_connections_errors_total: CounterVec, pub requests_in_failure_total: CounterVec, @@ -204,10 +203,6 @@ impl Metrics { "substrate_sub_libp2p_peerset_num_discovered", "Number of nodes stored in the peerset manager", )?, registry)?, - peerset_num_requested: prometheus::register(Gauge::new( - "substrate_sub_libp2p_peerset_num_requested", - "Number of nodes that the peerset manager wants us to be connected to", - )?, registry)?, pending_connections: prometheus::register(Gauge::new( "substrate_sub_libp2p_pending_connections", "Number of connections in the process of being established", From f72fe056844a375f16449555d6e20e57dcd16aa6 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sat, 19 Feb 2022 12:02:47 +0100 Subject: [PATCH 0532/1472] Introduce `BoundedVec::iter_mut` (#10884) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Introduce iters into BoundedVec * Fix * Remove unneeded funcs * Update frame/support/src/storage/bounded_vec.rs * Update frame/support/src/storage/bounded_vec.rs Co-authored-by: Bastian Köcher --- frame/support/src/storage/bounded_vec.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 9298a5d98b003..86aa4d405cab2 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -159,6 +159,11 @@ impl BoundedVec { pub fn pop(&mut self) -> Option { self.0.pop() } + + /// Exactly the same semantics as [`slice::iter_mut`]. + pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> { + self.0.iter_mut() + } } impl> From> for Vec { From e01c36244a91aea715bd45c05e3361fe24fd071d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 20 Feb 2022 02:49:49 +0100 Subject: [PATCH 0533/1472] Slots: Log total proposing duration as milliseconds (#10886) Parachains have currently a total proposing time of 500ms, so it this currently always prints `0`. While actually the value is not `0` ;) --- client/consensus/slots/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index fc635e9184051..094d065a1c07c 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -654,10 +654,10 @@ pub fn proposing_remaining_duration( debug!( target: log_target, - "No block for {} slots. Applying {} lenience, total proposing duration: {}", + "No block for {} slots. Applying {} lenience, total proposing duration: {}ms", slot_info.slot.saturating_sub(parent_slot + 1), slot_lenience_type.as_str(), - lenient_proposing_duration.as_secs(), + lenient_proposing_duration.as_millis(), ); lenient_proposing_duration From 917fe4919c70cb022a9c90eb6415cf85cbc67f7b Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Sun, 20 Feb 2022 16:50:25 -0800 Subject: [PATCH 0534/1472] staking: Clarify reward calc docs (#10890) --- frame/staking/src/lib.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 17af4829c0ea8..3738c87dd5b3d 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -221,16 +221,16 @@ //! //! The validator and its nominator split their reward as following: //! -//! The validator can declare an amount, named -//! [`commission`](ValidatorPrefs::commission), that does not get shared -//! with the nominators at each reward payout through its -//! [`ValidatorPrefs`]. This value gets deducted from the total reward -//! that is paid to the validator and its nominators. The remaining portion is split among the -//! validator and all of the nominators that nominated the validator, proportional to the value -//! staked behind this validator (_i.e._ dividing the -//! [`own`](Exposure::own) or -//! [`others`](Exposure::others) by -//! [`total`](Exposure::total) in [`Exposure`]). +//! The validator can declare an amount, named [`commission`](ValidatorPrefs::commission), that does +//! not get shared with the nominators at each reward payout through its [`ValidatorPrefs`]. This +//! value gets deducted from the total reward that is paid to the validator and its nominators. The +//! remaining portion is split pro rata among the validator and the top +//! [`Config::MaxNominatorRewardedPerValidator`] nominators that nominated the validator, +//! proportional to the value staked behind the validator (_i.e._ dividing the +//! [`own`](Exposure::own) or [`others`](Exposure::others) by [`total`](Exposure::total) in +//! [`Exposure`]). Note that the pro rata division of rewards uses the total exposure behind the +//! validator, *not* just the exposure of the validator and the top +//! [`Config::MaxNominatorRewardedPerValidator`] nominators. //! //! All entities who receive a reward have the option to choose their reward destination through the //! [`Payee`] storage item (see From 1db34ffb34a3d5d0fdf823661542b2c4c0aa8501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 21 Feb 2022 13:08:24 +0100 Subject: [PATCH 0535/1472] tracing: Adds `init_for_tests` (#10893) This function is useful for tests. It will enable `TRACE` logging and also uses the libtest aware writer. --- primitives/tracing/src/lib.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/primitives/tracing/src/lib.rs b/primitives/tracing/src/lib.rs index 4cabbbaba6ec9..1efae226a546f 100644 --- a/primitives/tracing/src/lib.rs +++ b/primitives/tracing/src/lib.rs @@ -108,6 +108,7 @@ pub use crate::types::{WASM_NAME_KEY, WASM_TARGET_KEY, WASM_TRACE_IDENTIFIER}; mod types; /// Try to init a simple tracing subscriber with log compatibility layer. +/// /// Ignores any error. Useful for testing. #[cfg(feature = "std")] pub fn try_init_simple() { @@ -117,6 +118,22 @@ pub fn try_init_simple() { .try_init(); } +/// Init a tracing subscriber for logging in tests. +/// +/// Be aware that this enables `TRACE` by default. It also ignores any error +/// while setting up the logger. +/// +/// The logs are not shown by default, logs are only shown when the test fails +/// or if [`nocapture`](https://doc.rust-lang.org/cargo/commands/cargo-test.html#display-options) +/// is being used. +#[cfg(feature = "std")] +pub fn init_for_tests() { + let _ = tracing_subscriber::fmt() + .with_max_level(tracing::Level::TRACE) + .with_test_writer() + .try_init(); +} + /// Runs given code within a tracing span, measuring it's execution time. /// /// If tracing is not enabled, the code is still executed. Pass in level and name or @@ -126,20 +143,20 @@ pub fn try_init_simple() { /// /// ``` /// sp_tracing::within_span! { -/// sp_tracing::Level::TRACE, +/// sp_tracing::Level::TRACE, /// "test-span"; /// 1 + 1; /// // some other complex code /// } /// /// sp_tracing::within_span! { -/// sp_tracing::span!(sp_tracing::Level::WARN, "warn-span", you_can_pass="any params"); +/// sp_tracing::span!(sp_tracing::Level::WARN, "warn-span", you_can_pass="any params"); /// 1 + 1; /// // some other complex code /// } /// /// sp_tracing::within_span! { -/// sp_tracing::debug_span!("debug-span", you_can_pass="any params"); +/// sp_tracing::debug_span!("debug-span", you_can_pass="any params"); /// 1 + 1; /// // some other complex code /// } From b16a721f271df9350e0dd5aca7e4cb1b4f1574d8 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 22 Feb 2022 09:20:29 +0100 Subject: [PATCH 0536/1472] make submissions pub (#10899) --- frame/election-provider-multi-phase/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 58df7d5a9d754..9413984f80dbf 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1233,7 +1233,7 @@ pub mod pallet { /// capacity, it will simply saturate. We can't just iterate over `SignedSubmissionsMap`, /// because iteration is slow. Instead, we store the value here. #[pallet::storage] - pub(crate) type SignedSubmissionNextIndex = StorageValue<_, u32, ValueQuery>; + pub type SignedSubmissionNextIndex = StorageValue<_, u32, ValueQuery>; /// A sorted, bounded set of `(score, index)`, where each `index` points to a value in /// `SignedSubmissions`. @@ -1242,7 +1242,7 @@ pub mod pallet { /// can be quite large, so we're willing to pay the cost of multiple database accesses to access /// them one at a time instead of reading and decoding all of them at once. #[pallet::storage] - pub(crate) type SignedSubmissionIndices = + pub type SignedSubmissionIndices = StorageValue<_, SubmissionIndicesOf, ValueQuery>; /// Unchecked, signed solutions. @@ -1253,7 +1253,7 @@ pub mod pallet { /// Twox note: the key of the map is an auto-incrementing index which users cannot inspect or /// affect; we shouldn't need a cryptographically secure hasher. #[pallet::storage] - pub(crate) type SignedSubmissionsMap = + pub type SignedSubmissionsMap = StorageMap<_, Twox64Concat, u32, SignedSubmissionOf, OptionQuery>; // `SignedSubmissions` items end here. From b46702edbb8c65eb2e3269f8e5cbea4671d1844d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 22 Feb 2022 10:10:38 +0100 Subject: [PATCH 0537/1472] contracts: Allow stack height metering to be disabled (#10877) * Allow stack height metering to be disabled * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- frame/contracts/src/benchmarking/code.rs | 7 +- frame/contracts/src/benchmarking/mod.rs | 6 +- frame/contracts/src/schedule.rs | 12 +- frame/contracts/src/tests.rs | 8 +- frame/contracts/src/wasm/prepare.rs | 9 +- frame/contracts/src/weights.rs | 1158 +++++++++++----------- 6 files changed, 609 insertions(+), 591 deletions(-) diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 4d42349f82a1b..f9d71fde65885 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -566,6 +566,9 @@ fn inject_gas_metering(module: Module) -> Module { } fn inject_stack_metering(module: Module) -> Module { - let height = T::Schedule::get().limits.stack_height; - wasm_instrument::inject_stack_limiter(module, height).unwrap() + if let Some(height) = T::Schedule::get().limits.stack_height { + wasm_instrument::inject_stack_limiter(module, height).unwrap() + } else { + module + } } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 827c729e16150..f5200eef567b9 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -2250,7 +2250,7 @@ benchmarks! { // w_local_get = w_bench - 1 * w_param instr_local_get { let r in 0 .. INSTR_BENCHMARK_BATCHES; - let max_locals = T::Schedule::get().limits.stack_height; + let max_locals = T::Schedule::get().limits.stack_height.unwrap_or(512); let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ RandomGetLocal(0, max_locals), Regular(Instruction::Drop), @@ -2267,7 +2267,7 @@ benchmarks! { // w_local_set = w_bench - 1 * w_param instr_local_set { let r in 0 .. INSTR_BENCHMARK_BATCHES; - let max_locals = T::Schedule::get().limits.stack_height; + let max_locals = T::Schedule::get().limits.stack_height.unwrap_or(512); let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ RandomI64Repeated(1), RandomSetLocal(0, max_locals), @@ -2284,7 +2284,7 @@ benchmarks! { // w_local_tee = w_bench - 2 * w_param instr_local_tee { let r in 0 .. INSTR_BENCHMARK_BATCHES; - let max_locals = T::Schedule::get().limits.stack_height; + let max_locals = T::Schedule::get().limits.stack_height.unwrap_or(512); let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ RandomI64Repeated(1), RandomTeeLocal(0, max_locals), diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index d6bdf85a4d68e..8535166a6ac5c 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -104,7 +104,13 @@ pub struct Limits { /// See to find out /// how the stack frame cost is calculated. Each element can be of one of the /// wasm value types. This means the maximum size per element is 64bit. - pub stack_height: u32, + /// + /// # Note + /// + /// It is safe to disable (pass `None`) the `stack_height` when the execution engine + /// is part of the runtime and hence there can be no indeterminism between different + /// client resident execution engines. + pub stack_height: Option, /// Maximum number of globals a module is allowed to declare. /// @@ -496,8 +502,8 @@ impl Default for Limits { fn default() -> Self { Self { event_topics: 4, - // 512 * sizeof(i64) will give us a 4k stack. - stack_height: 512, + // No stack limit required because we use a runtime resident execution engine. + stack_height: None, globals: 256, parameters: 128, memory_pages: 16, diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 9ea23e974b21d..cdcf41704347e 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -239,7 +239,13 @@ parameter_types! { pub const MaxValueSize: u32 = 16_384; pub const DeletionWeightLimit: Weight = 500_000_000_000; pub const MaxCodeSize: u32 = 2 * 1024; - pub MySchedule: Schedule = >::default(); + pub MySchedule: Schedule = { + let mut schedule = >::default(); + // We want stack height to be always enabled for tests so that this + // instrumentation path is always tested implicitly. + schedule.limits.stack_height = Some(512); + schedule + }; pub const TransactionByteFee: u64 = 0; pub static DepositPerByte: BalanceOf = 1; pub const DepositPerItem: BalanceOf = 2; diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 70c15cb8c4e6e..4571d752a80c6 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -191,10 +191,13 @@ impl<'a, T: Config> ContractModule<'a, T> { } fn inject_stack_height_metering(self) -> Result { - let contract_module = - wasm_instrument::inject_stack_limiter(self.module, self.schedule.limits.stack_height) + if let Some(limit) = self.schedule.limits.stack_height { + let contract_module = wasm_instrument::inject_stack_limiter(self.module, limit) .map_err(|_| "stack height instrumentation failed")?; - Ok(ContractModule { module: contract_module, schedule: self.schedule }) + Ok(ContractModule { module: contract_module, schedule: self.schedule }) + } else { + Ok(ContractModule { module: self.module, schedule: self.schedule }) + } } /// Check that the module has required exported functions. For now diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index fd32c247ba729..7d73a3a1cecc7 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-02-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-02-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -160,32 +160,32 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_588_000 as Weight) + (1_512_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (6_994_000 as Weight) + (8_089_000 as Weight) // Standard Error: 0 - .saturating_add((743_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((741_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (2_831_000 as Weight) - // Standard Error: 3_000 - .saturating_add((2_232_000 as Weight).saturating_mul(q as Weight)) + (0 as Weight) + // Standard Error: 5_000 + .saturating_add((2_287_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (17_839_000 as Weight) + (15_212_000 as Weight) // Standard Error: 0 - .saturating_add((64_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -194,9 +194,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_per_byte(c: u32, ) -> Weight { - (222_400_000 as Weight) + (218_406_000 as Weight) // Standard Error: 0 - .saturating_add((56_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -208,9 +208,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (283_144_000 as Weight) + (265_773_000 as Weight) // Standard Error: 0 - .saturating_add((140_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((127_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) @@ -223,7 +223,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (171_794_000 as Weight) + (173_852_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) @@ -234,7 +234,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (140_234_000 as Weight) + (140_088_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -242,9 +242,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (49_467_000 as Weight) + (44_290_000 as Weight) // Standard Error: 0 - .saturating_add((66_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -252,7 +252,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_915_000 as Weight) + (24_364_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -261,9 +261,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (218_957_000 as Weight) - // Standard Error: 114_000 - .saturating_add((49_881_000 as Weight).saturating_mul(r as Weight)) + (219_617_000 as Weight) + // Standard Error: 119_000 + .saturating_add((50_409_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -272,9 +272,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (76_490_000 as Weight) - // Standard Error: 856_000 - .saturating_add((375_305_000 as Weight).saturating_mul(r as Weight)) + (102_073_000 as Weight) + // Standard Error: 843_000 + .saturating_add((369_025_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -284,9 +284,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (213_485_000 as Weight) - // Standard Error: 76_000 - .saturating_add((22_020_000 as Weight).saturating_mul(r as Weight)) + (213_550_000 as Weight) + // Standard Error: 63_000 + .saturating_add((21_519_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -295,9 +295,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (218_468_000 as Weight) - // Standard Error: 108_000 - .saturating_add((49_457_000 as Weight).saturating_mul(r as Weight)) + (220_649_000 as Weight) + // Standard Error: 95_000 + .saturating_add((50_197_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -306,9 +306,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (218_950_000 as Weight) + (218_190_000 as Weight) // Standard Error: 99_000 - .saturating_add((48_859_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((49_817_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -317,9 +317,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (226_714_000 as Weight) - // Standard Error: 111_000 - .saturating_add((141_924_000 as Weight).saturating_mul(r as Weight)) + (223_133_000 as Weight) + // Standard Error: 188_000 + .saturating_add((142_288_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -328,9 +328,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (216_673_000 as Weight) - // Standard Error: 90_000 - .saturating_add((49_367_000 as Weight).saturating_mul(r as Weight)) + (216_612_000 as Weight) + // Standard Error: 103_000 + .saturating_add((49_956_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -339,9 +339,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (215_859_000 as Weight) - // Standard Error: 104_000 - .saturating_add((49_334_000 as Weight).saturating_mul(r as Weight)) + (218_349_000 as Weight) + // Standard Error: 93_000 + .saturating_add((49_656_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -350,9 +350,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (216_419_000 as Weight) - // Standard Error: 109_000 - .saturating_add((49_417_000 as Weight).saturating_mul(r as Weight)) + (213_151_000 as Weight) + // Standard Error: 110_000 + .saturating_add((50_099_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -361,9 +361,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (218_799_000 as Weight) - // Standard Error: 108_000 - .saturating_add((48_631_000 as Weight).saturating_mul(r as Weight)) + (216_816_000 as Weight) + // Standard Error: 95_000 + .saturating_add((49_724_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -373,9 +373,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (215_968_000 as Weight) - // Standard Error: 147_000 - .saturating_add((122_978_000 as Weight).saturating_mul(r as Weight)) + (223_053_000 as Weight) + // Standard Error: 148_000 + .saturating_add((124_240_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -384,9 +384,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (127_183_000 as Weight) - // Standard Error: 35_000 - .saturating_add((24_523_000 as Weight).saturating_mul(r as Weight)) + (127_253_000 as Weight) + // Standard Error: 27_000 + .saturating_add((25_608_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -395,9 +395,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (217_535_000 as Weight) - // Standard Error: 91_000 - .saturating_add((48_400_000 as Weight).saturating_mul(r as Weight)) + (218_057_000 as Weight) + // Standard Error: 98_000 + .saturating_add((49_061_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -406,9 +406,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (297_539_000 as Weight) - // Standard Error: 5_000 - .saturating_add((11_870_000 as Weight).saturating_mul(n as Weight)) + (293_563_000 as Weight) + // Standard Error: 3_000 + .saturating_add((11_877_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -417,9 +417,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (211_807_000 as Weight) - // Standard Error: 160_000 - .saturating_add((1_717_000 as Weight).saturating_mul(r as Weight)) + (211_511_000 as Weight) + // Standard Error: 70_000 + .saturating_add((2_085_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -428,9 +428,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (213_139_000 as Weight) + (213_876_000 as Weight) // Standard Error: 0 - .saturating_add((197_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((193_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -441,9 +441,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (215_292_000 as Weight) - // Standard Error: 390_000 - .saturating_add((52_831_000 as Weight).saturating_mul(r as Weight)) + (214_736_000 as Weight) + // Standard Error: 206_000 + .saturating_add((53_637_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -455,9 +455,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (215_802_000 as Weight) - // Standard Error: 132_000 - .saturating_add((159_065_000 as Weight).saturating_mul(r as Weight)) + (222_037_000 as Weight) + // Standard Error: 191_000 + .saturating_add((160_114_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -466,9 +466,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (225_069_000 as Weight) - // Standard Error: 201_000 - .saturating_add((292_145_000 as Weight).saturating_mul(r as Weight)) + (219_211_000 as Weight) + // Standard Error: 239_000 + .saturating_add((296_722_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -478,11 +478,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (519_617_000 as Weight) - // Standard Error: 1_751_000 - .saturating_add((290_832_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 345_000 - .saturating_add((82_584_000 as Weight).saturating_mul(n as Weight)) + (519_643_000 as Weight) + // Standard Error: 1_842_000 + .saturating_add((300_853_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 363_000 + .saturating_add((82_577_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -493,17 +493,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (132_245_000 as Weight) - // Standard Error: 75_000 - .saturating_add((41_274_000 as Weight).saturating_mul(r as Weight)) + (132_710_000 as Weight) + // Standard Error: 77_000 + .saturating_add((41_623_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (48_288_000 as Weight) - // Standard Error: 1_024_000 - .saturating_add((408_264_000 as Weight).saturating_mul(r as Weight)) + (40_644_000 as Weight) + // Standard Error: 1_072_000 + .saturating_add((412_308_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -511,25 +511,25 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (607_246_000 as Weight) - // Standard Error: 252_000 - .saturating_add((28_722_000 as Weight).saturating_mul(n as Weight)) + (609_052_000 as Weight) + // Standard Error: 258_000 + .saturating_add((28_633_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (623_983_000 as Weight) - // Standard Error: 305_000 - .saturating_add((11_374_000 as Weight).saturating_mul(n as Weight)) + (629_665_000 as Weight) + // Standard Error: 300_000 + .saturating_add((10_947_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (91_727_000 as Weight) - // Standard Error: 837_000 - .saturating_add((383_577_000 as Weight).saturating_mul(r as Weight)) + (91_519_000 as Weight) + // Standard Error: 889_000 + .saturating_add((386_498_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -537,51 +537,51 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (604_749_000 as Weight) - // Standard Error: 251_000 - .saturating_add((11_086_000 as Weight).saturating_mul(n as Weight)) + (612_224_000 as Weight) + // Standard Error: 269_000 + .saturating_add((10_709_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (107_805_000 as Weight) - // Standard Error: 722_000 - .saturating_add((326_494_000 as Weight).saturating_mul(r as Weight)) + (112_236_000 as Weight) + // Standard Error: 624_000 + .saturating_add((327_655_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (564_604_000 as Weight) - // Standard Error: 360_000 - .saturating_add((65_184_000 as Weight).saturating_mul(n as Weight)) + (567_711_000 as Weight) + // Standard Error: 387_000 + .saturating_add((63_984_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (122_105_000 as Weight) - // Standard Error: 560_000 - .saturating_add((291_458_000 as Weight).saturating_mul(r as Weight)) + (109_996_000 as Weight) + // Standard Error: 681_000 + .saturating_add((298_317_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (512_580_000 as Weight) - // Standard Error: 245_000 - .saturating_add((10_171_000 as Weight).saturating_mul(n as Weight)) + (518_342_000 as Weight) + // Standard Error: 251_000 + .saturating_add((9_666_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (81_220_000 as Weight) - // Standard Error: 933_000 - .saturating_add((418_532_000 as Weight).saturating_mul(r as Weight)) + (75_974_000 as Weight) + // Standard Error: 1_000_000 + .saturating_add((417_954_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -589,9 +589,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (652_330_000 as Weight) - // Standard Error: 357_000 - .saturating_add((65_711_000 as Weight).saturating_mul(n as Weight)) + (653_188_000 as Weight) + // Standard Error: 333_000 + .saturating_add((64_810_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } @@ -600,9 +600,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (126_544_000 as Weight) - // Standard Error: 1_198_000 - .saturating_add((1_796_593_000 as Weight).saturating_mul(r as Weight)) + (127_056_000 as Weight) + // Standard Error: 1_106_000 + .saturating_add((1_784_183_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -614,8 +614,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_033_000 - .saturating_add((19_788_005_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 2_621_000 + .saturating_add((19_757_765_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -627,8 +627,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 6_663_000 - .saturating_add((19_835_985_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 6_286_000 + .saturating_add((19_798_229_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -637,11 +637,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (10_957_494_000 as Weight) - // Standard Error: 13_908_000 - .saturating_add((1_622_630_000 as Weight).saturating_mul(t as Weight)) + (10_922_130_000 as Weight) + // Standard Error: 15_556_000 + .saturating_add((1_672_276_000 as Weight).saturating_mul(t as Weight)) // Standard Error: 6_000 - .saturating_add((11_960_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((11_984_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -655,8 +655,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 48_191_000 - .saturating_add((27_587_375_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 46_147_000 + .saturating_add((27_589_519_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -669,11 +669,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (14_504_226_000 as Weight) - // Standard Error: 66_350_000 - .saturating_add((912_874_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 31_000 - .saturating_add((157_415_000 as Weight).saturating_mul(s as Weight)) + (14_790_752_000 as Weight) + // Standard Error: 37_838_000 + .saturating_add((714_016_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 17_000 + .saturating_add((155_605_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(207 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(205 as Weight)) @@ -684,9 +684,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (216_771_000 as Weight) - // Standard Error: 127_000 - .saturating_add((79_994_000 as Weight).saturating_mul(r as Weight)) + (216_547_000 as Weight) + // Standard Error: 126_000 + .saturating_add((81_132_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -695,9 +695,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (376_960_000 as Weight) - // Standard Error: 24_000 - .saturating_add((465_507_000 as Weight).saturating_mul(n as Weight)) + (459_912_000 as Weight) + // Standard Error: 27_000 + .saturating_add((464_750_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -706,9 +706,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (212_554_000 as Weight) - // Standard Error: 129_000 - .saturating_add((92_073_000 as Weight).saturating_mul(r as Weight)) + (212_653_000 as Weight) + // Standard Error: 147_000 + .saturating_add((93_380_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -717,9 +717,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (298_638_000 as Weight) - // Standard Error: 23_000 - .saturating_add((307_231_000 as Weight).saturating_mul(n as Weight)) + (324_536_000 as Weight) + // Standard Error: 20_000 + .saturating_add((306_160_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -728,9 +728,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (216_274_000 as Weight) - // Standard Error: 100_000 - .saturating_add((64_205_000 as Weight).saturating_mul(r as Weight)) + (218_574_000 as Weight) + // Standard Error: 123_000 + .saturating_add((65_035_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -739,9 +739,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (294_478_000 as Weight) - // Standard Error: 18_000 - .saturating_add((120_405_000 as Weight).saturating_mul(n as Weight)) + (345_804_000 as Weight) + // Standard Error: 14_000 + .saturating_add((118_896_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -750,9 +750,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (215_874_000 as Weight) - // Standard Error: 115_000 - .saturating_add((63_402_000 as Weight).saturating_mul(r as Weight)) + (215_898_000 as Weight) + // Standard Error: 108_000 + .saturating_add((64_332_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -761,9 +761,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (288_361_000 as Weight) - // Standard Error: 15_000 - .saturating_add((120_795_000 as Weight).saturating_mul(n as Weight)) + (351_569_000 as Weight) + // Standard Error: 18_000 + .saturating_add((118_896_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -772,9 +772,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (142_940_000 as Weight) - // Standard Error: 1_317_000 - .saturating_add((15_385_437_000 as Weight).saturating_mul(r as Weight)) + (272_893_000 as Weight) + // Standard Error: 1_438_000 + .saturating_add((15_412_877_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -785,265 +785,265 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:36 w:36) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_981_000 - .saturating_add((943_500_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 2_132_000 + .saturating_add((937_623_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (74_672_000 as Weight) + (74_268_000 as Weight) // Standard Error: 1_000 .saturating_add((595_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_346_000 as Weight) + (74_515_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_300_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_149_000 as Weight) + (74_217_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_438_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_411_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (74_186_000 as Weight) + (73_689_000 as Weight) // Standard Error: 4_000 - .saturating_add((1_789_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_792_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (74_040_000 as Weight) + (73_755_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_898_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_909_000 as Weight) - // Standard Error: 1_000 - .saturating_add((910_000 as Weight).saturating_mul(r as Weight)) + (73_735_000 as Weight) + // Standard Error: 0 + .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_873_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_446_000 as Weight).saturating_mul(r as Weight)) + (73_595_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_448_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_438_000 as Weight) + (73_524_000 as Weight) // Standard Error: 3_000 - .saturating_add((1_582_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_572_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (75_993_000 as Weight) + (76_361_000 as Weight) // Standard Error: 0 - .saturating_add((8_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (73_218_000 as Weight) - // Standard Error: 17_000 - .saturating_add((17_167_000 as Weight).saturating_mul(r as Weight)) + (76_131_000 as Weight) + // Standard Error: 7_000 + .saturating_add((7_271_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (85_517_000 as Weight) - // Standard Error: 30_000 - .saturating_add((28_885_000 as Weight).saturating_mul(r as Weight)) + (87_948_000 as Weight) + // Standard Error: 14_000 + .saturating_add((9_429_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (119_915_000 as Weight) - // Standard Error: 3_000 - .saturating_add((918_000 as Weight).saturating_mul(p as Weight)) + (98_091_000 as Weight) + // Standard Error: 1_000 + .saturating_add((481_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (74_718_000 as Weight) + (74_311_000 as Weight) // Standard Error: 1_000 - .saturating_add((618_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((627_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_800_000 as Weight) + (74_701_000 as Weight) // Standard Error: 1_000 - .saturating_add((684_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((677_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_590_000 as Weight) - // Standard Error: 2_000 - .saturating_add((911_000 as Weight).saturating_mul(r as Weight)) + (74_645_000 as Weight) + // Standard Error: 1_000 + .saturating_add((890_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (76_776_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_159_000 as Weight).saturating_mul(r as Weight)) + (77_130_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_156_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (77_283_000 as Weight) + (77_199_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_555_000 as Weight) - // Standard Error: 1_000 - .saturating_add((655_000 as Weight).saturating_mul(r as Weight)) + (74_024_000 as Weight) + // Standard Error: 2_000 + .saturating_add((675_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_693_000 as Weight) - // Standard Error: 131_000 - .saturating_add((181_095_000 as Weight).saturating_mul(r as Weight)) + (75_226_000 as Weight) + // Standard Error: 170_000 + .saturating_add((186_225_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_457_000 as Weight) - // Standard Error: 1_000 - .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) + (74_307_000 as Weight) + // Standard Error: 2_000 + .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_287_000 as Weight) - // Standard Error: 1_000 - .saturating_add((907_000 as Weight).saturating_mul(r as Weight)) + (74_408_000 as Weight) + // Standard Error: 3_000 + .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_603_000 as Weight) - // Standard Error: 3_000 - .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) + (74_418_000 as Weight) + // Standard Error: 1_000 + .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_383_000 as Weight) - // Standard Error: 1_000 + (74_130_000 as Weight) + // Standard Error: 2_000 .saturating_add((920_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_020_000 as Weight) + (74_318_000 as Weight) // Standard Error: 2_000 - .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((876_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_108_000 as Weight) - // Standard Error: 4_000 - .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) + (74_496_000 as Weight) + // Standard Error: 1_000 + .saturating_add((871_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_197_000 as Weight) - // Standard Error: 2_000 - .saturating_add((901_000 as Weight).saturating_mul(r as Weight)) + (73_938_000 as Weight) + // Standard Error: 0 + .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (73_941_000 as Weight) + (73_943_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (73_891_000 as Weight) + (74_305_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_383_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (74_253_000 as Weight) + (73_948_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_369_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_125_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_371_000 as Weight).saturating_mul(r as Weight)) + (74_188_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (74_144_000 as Weight) + (74_156_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_369_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (74_170_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_375_000 as Weight).saturating_mul(r as Weight)) + (73_972_000 as Weight) + // Standard Error: 0 + .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (74_164_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + (74_082_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_166_000 as Weight) + (74_190_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_376_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (73_920_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_381_000 as Weight).saturating_mul(r as Weight)) + (73_803_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_691_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + (74_063_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (74_198_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (73_750_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_064_000 as Weight) + (73_979_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (75_744_000 as Weight) - // Standard Error: 8_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (74_197_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_332_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (74_300_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_003_000 as Weight).saturating_mul(r as Weight)) + (73_624_000 as Weight) + // Standard Error: 5_000 + .saturating_add((2_020_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (74_001_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_051_000 as Weight).saturating_mul(r as Weight)) + (74_074_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_050_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (74_132_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_994_000 as Weight).saturating_mul(r as Weight)) + (73_766_000 as Weight) + // Standard Error: 5_000 + .saturating_add((2_016_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (74_241_000 as Weight) + (73_978_000 as Weight) // Standard Error: 3_000 - .saturating_add((2_070_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_064_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_069_000 as Weight) + (73_996_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_336_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (73_978_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (74_058_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (74_053_000 as Weight) + (73_983_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_337_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (73_891_000 as Weight) - // Standard Error: 0 - .saturating_add((1_371_000 as Weight).saturating_mul(r as Weight)) + (74_061_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (74_062_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) + (73_940_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (74_347_000 as Weight) + (73_954_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (74_116_000 as Weight) + (74_026_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (73_837_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) + (74_149_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } } @@ -1051,32 +1051,32 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_588_000 as Weight) + (1_512_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (6_994_000 as Weight) + (8_089_000 as Weight) // Standard Error: 0 - .saturating_add((743_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((741_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (2_831_000 as Weight) - // Standard Error: 3_000 - .saturating_add((2_232_000 as Weight).saturating_mul(q as Weight)) + (0 as Weight) + // Standard Error: 5_000 + .saturating_add((2_287_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (17_839_000 as Weight) + (15_212_000 as Weight) // Standard Error: 0 - .saturating_add((64_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1085,9 +1085,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_per_byte(c: u32, ) -> Weight { - (222_400_000 as Weight) + (218_406_000 as Weight) // Standard Error: 0 - .saturating_add((56_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1099,9 +1099,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (283_144_000 as Weight) + (265_773_000 as Weight) // Standard Error: 0 - .saturating_add((140_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((127_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) @@ -1114,7 +1114,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (171_794_000 as Weight) + (173_852_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) @@ -1125,7 +1125,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (140_234_000 as Weight) + (140_088_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1133,9 +1133,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (49_467_000 as Weight) + (44_290_000 as Weight) // Standard Error: 0 - .saturating_add((66_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1143,7 +1143,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_915_000 as Weight) + (24_364_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1152,9 +1152,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (218_957_000 as Weight) - // Standard Error: 114_000 - .saturating_add((49_881_000 as Weight).saturating_mul(r as Weight)) + (219_617_000 as Weight) + // Standard Error: 119_000 + .saturating_add((50_409_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1163,9 +1163,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (76_490_000 as Weight) - // Standard Error: 856_000 - .saturating_add((375_305_000 as Weight).saturating_mul(r as Weight)) + (102_073_000 as Weight) + // Standard Error: 843_000 + .saturating_add((369_025_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1175,9 +1175,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (213_485_000 as Weight) - // Standard Error: 76_000 - .saturating_add((22_020_000 as Weight).saturating_mul(r as Weight)) + (213_550_000 as Weight) + // Standard Error: 63_000 + .saturating_add((21_519_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1186,9 +1186,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (218_468_000 as Weight) - // Standard Error: 108_000 - .saturating_add((49_457_000 as Weight).saturating_mul(r as Weight)) + (220_649_000 as Weight) + // Standard Error: 95_000 + .saturating_add((50_197_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1197,9 +1197,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (218_950_000 as Weight) + (218_190_000 as Weight) // Standard Error: 99_000 - .saturating_add((48_859_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((49_817_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1208,9 +1208,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (226_714_000 as Weight) - // Standard Error: 111_000 - .saturating_add((141_924_000 as Weight).saturating_mul(r as Weight)) + (223_133_000 as Weight) + // Standard Error: 188_000 + .saturating_add((142_288_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1219,9 +1219,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (216_673_000 as Weight) - // Standard Error: 90_000 - .saturating_add((49_367_000 as Weight).saturating_mul(r as Weight)) + (216_612_000 as Weight) + // Standard Error: 103_000 + .saturating_add((49_956_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1230,9 +1230,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (215_859_000 as Weight) - // Standard Error: 104_000 - .saturating_add((49_334_000 as Weight).saturating_mul(r as Weight)) + (218_349_000 as Weight) + // Standard Error: 93_000 + .saturating_add((49_656_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1241,9 +1241,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (216_419_000 as Weight) - // Standard Error: 109_000 - .saturating_add((49_417_000 as Weight).saturating_mul(r as Weight)) + (213_151_000 as Weight) + // Standard Error: 110_000 + .saturating_add((50_099_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1252,9 +1252,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (218_799_000 as Weight) - // Standard Error: 108_000 - .saturating_add((48_631_000 as Weight).saturating_mul(r as Weight)) + (216_816_000 as Weight) + // Standard Error: 95_000 + .saturating_add((49_724_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1264,9 +1264,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (215_968_000 as Weight) - // Standard Error: 147_000 - .saturating_add((122_978_000 as Weight).saturating_mul(r as Weight)) + (223_053_000 as Weight) + // Standard Error: 148_000 + .saturating_add((124_240_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1275,9 +1275,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (127_183_000 as Weight) - // Standard Error: 35_000 - .saturating_add((24_523_000 as Weight).saturating_mul(r as Weight)) + (127_253_000 as Weight) + // Standard Error: 27_000 + .saturating_add((25_608_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1286,9 +1286,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (217_535_000 as Weight) - // Standard Error: 91_000 - .saturating_add((48_400_000 as Weight).saturating_mul(r as Weight)) + (218_057_000 as Weight) + // Standard Error: 98_000 + .saturating_add((49_061_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1297,9 +1297,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (297_539_000 as Weight) - // Standard Error: 5_000 - .saturating_add((11_870_000 as Weight).saturating_mul(n as Weight)) + (293_563_000 as Weight) + // Standard Error: 3_000 + .saturating_add((11_877_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1308,9 +1308,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (211_807_000 as Weight) - // Standard Error: 160_000 - .saturating_add((1_717_000 as Weight).saturating_mul(r as Weight)) + (211_511_000 as Weight) + // Standard Error: 70_000 + .saturating_add((2_085_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1319,9 +1319,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (213_139_000 as Weight) + (213_876_000 as Weight) // Standard Error: 0 - .saturating_add((197_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((193_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1332,9 +1332,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (215_292_000 as Weight) - // Standard Error: 390_000 - .saturating_add((52_831_000 as Weight).saturating_mul(r as Weight)) + (214_736_000 as Weight) + // Standard Error: 206_000 + .saturating_add((53_637_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1346,9 +1346,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (215_802_000 as Weight) - // Standard Error: 132_000 - .saturating_add((159_065_000 as Weight).saturating_mul(r as Weight)) + (222_037_000 as Weight) + // Standard Error: 191_000 + .saturating_add((160_114_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1357,9 +1357,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (225_069_000 as Weight) - // Standard Error: 201_000 - .saturating_add((292_145_000 as Weight).saturating_mul(r as Weight)) + (219_211_000 as Weight) + // Standard Error: 239_000 + .saturating_add((296_722_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1369,11 +1369,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (519_617_000 as Weight) - // Standard Error: 1_751_000 - .saturating_add((290_832_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 345_000 - .saturating_add((82_584_000 as Weight).saturating_mul(n as Weight)) + (519_643_000 as Weight) + // Standard Error: 1_842_000 + .saturating_add((300_853_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 363_000 + .saturating_add((82_577_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1384,17 +1384,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (132_245_000 as Weight) - // Standard Error: 75_000 - .saturating_add((41_274_000 as Weight).saturating_mul(r as Weight)) + (132_710_000 as Weight) + // Standard Error: 77_000 + .saturating_add((41_623_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (48_288_000 as Weight) - // Standard Error: 1_024_000 - .saturating_add((408_264_000 as Weight).saturating_mul(r as Weight)) + (40_644_000 as Weight) + // Standard Error: 1_072_000 + .saturating_add((412_308_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1402,25 +1402,25 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (607_246_000 as Weight) - // Standard Error: 252_000 - .saturating_add((28_722_000 as Weight).saturating_mul(n as Weight)) + (609_052_000 as Weight) + // Standard Error: 258_000 + .saturating_add((28_633_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (623_983_000 as Weight) - // Standard Error: 305_000 - .saturating_add((11_374_000 as Weight).saturating_mul(n as Weight)) + (629_665_000 as Weight) + // Standard Error: 300_000 + .saturating_add((10_947_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (91_727_000 as Weight) - // Standard Error: 837_000 - .saturating_add((383_577_000 as Weight).saturating_mul(r as Weight)) + (91_519_000 as Weight) + // Standard Error: 889_000 + .saturating_add((386_498_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1428,51 +1428,51 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (604_749_000 as Weight) - // Standard Error: 251_000 - .saturating_add((11_086_000 as Weight).saturating_mul(n as Weight)) + (612_224_000 as Weight) + // Standard Error: 269_000 + .saturating_add((10_709_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (107_805_000 as Weight) - // Standard Error: 722_000 - .saturating_add((326_494_000 as Weight).saturating_mul(r as Weight)) + (112_236_000 as Weight) + // Standard Error: 624_000 + .saturating_add((327_655_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (564_604_000 as Weight) - // Standard Error: 360_000 - .saturating_add((65_184_000 as Weight).saturating_mul(n as Weight)) + (567_711_000 as Weight) + // Standard Error: 387_000 + .saturating_add((63_984_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (122_105_000 as Weight) - // Standard Error: 560_000 - .saturating_add((291_458_000 as Weight).saturating_mul(r as Weight)) + (109_996_000 as Weight) + // Standard Error: 681_000 + .saturating_add((298_317_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (512_580_000 as Weight) - // Standard Error: 245_000 - .saturating_add((10_171_000 as Weight).saturating_mul(n as Weight)) + (518_342_000 as Weight) + // Standard Error: 251_000 + .saturating_add((9_666_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (81_220_000 as Weight) - // Standard Error: 933_000 - .saturating_add((418_532_000 as Weight).saturating_mul(r as Weight)) + (75_974_000 as Weight) + // Standard Error: 1_000_000 + .saturating_add((417_954_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1480,9 +1480,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (652_330_000 as Weight) - // Standard Error: 357_000 - .saturating_add((65_711_000 as Weight).saturating_mul(n as Weight)) + (653_188_000 as Weight) + // Standard Error: 333_000 + .saturating_add((64_810_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } @@ -1491,9 +1491,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (126_544_000 as Weight) - // Standard Error: 1_198_000 - .saturating_add((1_796_593_000 as Weight).saturating_mul(r as Weight)) + (127_056_000 as Weight) + // Standard Error: 1_106_000 + .saturating_add((1_784_183_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1505,8 +1505,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_033_000 - .saturating_add((19_788_005_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 2_621_000 + .saturating_add((19_757_765_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1518,8 +1518,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 6_663_000 - .saturating_add((19_835_985_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 6_286_000 + .saturating_add((19_798_229_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1528,11 +1528,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (10_957_494_000 as Weight) - // Standard Error: 13_908_000 - .saturating_add((1_622_630_000 as Weight).saturating_mul(t as Weight)) + (10_922_130_000 as Weight) + // Standard Error: 15_556_000 + .saturating_add((1_672_276_000 as Weight).saturating_mul(t as Weight)) // Standard Error: 6_000 - .saturating_add((11_960_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((11_984_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1546,8 +1546,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 48_191_000 - .saturating_add((27_587_375_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 46_147_000 + .saturating_add((27_589_519_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1560,11 +1560,11 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (14_504_226_000 as Weight) - // Standard Error: 66_350_000 - .saturating_add((912_874_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 31_000 - .saturating_add((157_415_000 as Weight).saturating_mul(s as Weight)) + (14_790_752_000 as Weight) + // Standard Error: 37_838_000 + .saturating_add((714_016_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 17_000 + .saturating_add((155_605_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(207 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(205 as Weight)) @@ -1575,9 +1575,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (216_771_000 as Weight) - // Standard Error: 127_000 - .saturating_add((79_994_000 as Weight).saturating_mul(r as Weight)) + (216_547_000 as Weight) + // Standard Error: 126_000 + .saturating_add((81_132_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1586,9 +1586,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (376_960_000 as Weight) - // Standard Error: 24_000 - .saturating_add((465_507_000 as Weight).saturating_mul(n as Weight)) + (459_912_000 as Weight) + // Standard Error: 27_000 + .saturating_add((464_750_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1597,9 +1597,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (212_554_000 as Weight) - // Standard Error: 129_000 - .saturating_add((92_073_000 as Weight).saturating_mul(r as Weight)) + (212_653_000 as Weight) + // Standard Error: 147_000 + .saturating_add((93_380_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1608,9 +1608,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (298_638_000 as Weight) - // Standard Error: 23_000 - .saturating_add((307_231_000 as Weight).saturating_mul(n as Weight)) + (324_536_000 as Weight) + // Standard Error: 20_000 + .saturating_add((306_160_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1619,9 +1619,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (216_274_000 as Weight) - // Standard Error: 100_000 - .saturating_add((64_205_000 as Weight).saturating_mul(r as Weight)) + (218_574_000 as Weight) + // Standard Error: 123_000 + .saturating_add((65_035_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1630,9 +1630,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (294_478_000 as Weight) - // Standard Error: 18_000 - .saturating_add((120_405_000 as Weight).saturating_mul(n as Weight)) + (345_804_000 as Weight) + // Standard Error: 14_000 + .saturating_add((118_896_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1641,9 +1641,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (215_874_000 as Weight) - // Standard Error: 115_000 - .saturating_add((63_402_000 as Weight).saturating_mul(r as Weight)) + (215_898_000 as Weight) + // Standard Error: 108_000 + .saturating_add((64_332_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1652,9 +1652,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (288_361_000 as Weight) - // Standard Error: 15_000 - .saturating_add((120_795_000 as Weight).saturating_mul(n as Weight)) + (351_569_000 as Weight) + // Standard Error: 18_000 + .saturating_add((118_896_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1663,9 +1663,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (142_940_000 as Weight) - // Standard Error: 1_317_000 - .saturating_add((15_385_437_000 as Weight).saturating_mul(r as Weight)) + (272_893_000 as Weight) + // Standard Error: 1_438_000 + .saturating_add((15_412_877_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1676,264 +1676,264 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:36 w:36) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_981_000 - .saturating_add((943_500_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 2_132_000 + .saturating_add((937_623_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (74_672_000 as Weight) + (74_268_000 as Weight) // Standard Error: 1_000 .saturating_add((595_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_346_000 as Weight) + (74_515_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_300_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_149_000 as Weight) + (74_217_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_438_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_411_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (74_186_000 as Weight) + (73_689_000 as Weight) // Standard Error: 4_000 - .saturating_add((1_789_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_792_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (74_040_000 as Weight) + (73_755_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_898_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_909_000 as Weight) - // Standard Error: 1_000 - .saturating_add((910_000 as Weight).saturating_mul(r as Weight)) + (73_735_000 as Weight) + // Standard Error: 0 + .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_873_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_446_000 as Weight).saturating_mul(r as Weight)) + (73_595_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_448_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_438_000 as Weight) + (73_524_000 as Weight) // Standard Error: 3_000 - .saturating_add((1_582_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_572_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (75_993_000 as Weight) + (76_361_000 as Weight) // Standard Error: 0 - .saturating_add((8_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (73_218_000 as Weight) - // Standard Error: 17_000 - .saturating_add((17_167_000 as Weight).saturating_mul(r as Weight)) + (76_131_000 as Weight) + // Standard Error: 7_000 + .saturating_add((7_271_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (85_517_000 as Weight) - // Standard Error: 30_000 - .saturating_add((28_885_000 as Weight).saturating_mul(r as Weight)) + (87_948_000 as Weight) + // Standard Error: 14_000 + .saturating_add((9_429_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (119_915_000 as Weight) - // Standard Error: 3_000 - .saturating_add((918_000 as Weight).saturating_mul(p as Weight)) + (98_091_000 as Weight) + // Standard Error: 1_000 + .saturating_add((481_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (74_718_000 as Weight) + (74_311_000 as Weight) // Standard Error: 1_000 - .saturating_add((618_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((627_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_800_000 as Weight) + (74_701_000 as Weight) // Standard Error: 1_000 - .saturating_add((684_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((677_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_590_000 as Weight) - // Standard Error: 2_000 - .saturating_add((911_000 as Weight).saturating_mul(r as Weight)) + (74_645_000 as Weight) + // Standard Error: 1_000 + .saturating_add((890_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (76_776_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_159_000 as Weight).saturating_mul(r as Weight)) + (77_130_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_156_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (77_283_000 as Weight) + (77_199_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_555_000 as Weight) - // Standard Error: 1_000 - .saturating_add((655_000 as Weight).saturating_mul(r as Weight)) + (74_024_000 as Weight) + // Standard Error: 2_000 + .saturating_add((675_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_693_000 as Weight) - // Standard Error: 131_000 - .saturating_add((181_095_000 as Weight).saturating_mul(r as Weight)) + (75_226_000 as Weight) + // Standard Error: 170_000 + .saturating_add((186_225_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_457_000 as Weight) - // Standard Error: 1_000 - .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) + (74_307_000 as Weight) + // Standard Error: 2_000 + .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_287_000 as Weight) - // Standard Error: 1_000 - .saturating_add((907_000 as Weight).saturating_mul(r as Weight)) + (74_408_000 as Weight) + // Standard Error: 3_000 + .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_603_000 as Weight) - // Standard Error: 3_000 - .saturating_add((892_000 as Weight).saturating_mul(r as Weight)) + (74_418_000 as Weight) + // Standard Error: 1_000 + .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_383_000 as Weight) - // Standard Error: 1_000 + (74_130_000 as Weight) + // Standard Error: 2_000 .saturating_add((920_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_020_000 as Weight) + (74_318_000 as Weight) // Standard Error: 2_000 - .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((876_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_108_000 as Weight) - // Standard Error: 4_000 - .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) + (74_496_000 as Weight) + // Standard Error: 1_000 + .saturating_add((871_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_197_000 as Weight) - // Standard Error: 2_000 - .saturating_add((901_000 as Weight).saturating_mul(r as Weight)) + (73_938_000 as Weight) + // Standard Error: 0 + .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (73_941_000 as Weight) + (73_943_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (73_891_000 as Weight) + (74_305_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_383_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (74_253_000 as Weight) + (73_948_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_369_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_125_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_371_000 as Weight).saturating_mul(r as Weight)) + (74_188_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (74_144_000 as Weight) + (74_156_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_369_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (74_170_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_375_000 as Weight).saturating_mul(r as Weight)) + (73_972_000 as Weight) + // Standard Error: 0 + .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (74_164_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + (74_082_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_166_000 as Weight) + (74_190_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_376_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (73_920_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_381_000 as Weight).saturating_mul(r as Weight)) + (73_803_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_691_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + (74_063_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (74_198_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (73_750_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_064_000 as Weight) + (73_979_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (75_744_000 as Weight) - // Standard Error: 8_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (74_197_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_332_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (74_300_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_003_000 as Weight).saturating_mul(r as Weight)) + (73_624_000 as Weight) + // Standard Error: 5_000 + .saturating_add((2_020_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (74_001_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_051_000 as Weight).saturating_mul(r as Weight)) + (74_074_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_050_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (74_132_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_994_000 as Weight).saturating_mul(r as Weight)) + (73_766_000 as Weight) + // Standard Error: 5_000 + .saturating_add((2_016_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (74_241_000 as Weight) + (73_978_000 as Weight) // Standard Error: 3_000 - .saturating_add((2_070_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_064_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_069_000 as Weight) + (73_996_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_336_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (73_978_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (74_058_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (74_053_000 as Weight) + (73_983_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_337_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (73_891_000 as Weight) - // Standard Error: 0 - .saturating_add((1_371_000 as Weight).saturating_mul(r as Weight)) + (74_061_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (74_062_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) + (73_940_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (74_347_000 as Weight) + (73_954_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (74_116_000 as Weight) + (74_026_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (73_837_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_377_000 as Weight).saturating_mul(r as Weight)) + (74_149_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } } From 8bb8eff0376ff0706f99dd43bae035da8b7827c5 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Tue, 22 Feb 2022 11:42:46 +0100 Subject: [PATCH 0538/1472] Rename Uniques Error::Unknown to something more sensible (#10895) * Rename Uniques Error::Unknown to something more sensible * Typos * Typos * fmt Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/uniques/src/functions.rs | 14 ++++++---- frame/uniques/src/lib.rs | 51 +++++++++++++++++++--------------- frame/uniques/src/tests.rs | 32 ++++++++++++++------- 3 files changed, 58 insertions(+), 39 deletions(-) diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 5d573e42097e0..40c436bd56b47 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -31,10 +31,11 @@ impl, I: 'static> Pallet { &mut InstanceDetailsFor, ) -> DispatchResult, ) -> DispatchResult { - let class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; ensure!(!class_details.is_frozen, Error::::Frozen); - let mut details = Asset::::get(&class, &instance).ok_or(Error::::Unknown)?; + let mut details = + Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; ensure!(!details.is_frozen, Error::::Frozen); with_details(&class_details, &mut details)?; @@ -92,7 +93,7 @@ impl, I: 'static> Pallet { maybe_check_owner: Option, ) -> Result { Class::::try_mutate_exists(class, |maybe_details| { - let class_details = maybe_details.take().ok_or(Error::::Unknown)?; + let class_details = maybe_details.take().ok_or(Error::::UnknownClass)?; if let Some(check_owner) = maybe_check_owner { ensure!(class_details.owner == check_owner, Error::::NoPermission); } @@ -131,7 +132,7 @@ impl, I: 'static> Pallet { ensure!(!Asset::::contains_key(class, instance), Error::::AlreadyExists); Class::::try_mutate(&class, |maybe_class_details| -> DispatchResult { - let class_details = maybe_class_details.as_mut().ok_or(Error::::Unknown)?; + let class_details = maybe_class_details.as_mut().ok_or(Error::::UnknownClass)?; with_details(&class_details)?; @@ -165,9 +166,10 @@ impl, I: 'static> Pallet { let owner = Class::::try_mutate( &class, |maybe_class_details| -> Result { - let class_details = maybe_class_details.as_mut().ok_or(Error::::Unknown)?; + let class_details = + maybe_class_details.as_mut().ok_or(Error::::UnknownClass)?; let details = - Asset::::get(&class, &instance).ok_or(Error::::Unknown)?; + Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; with_details(&class_details, &details)?; // Return the deposit. diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 2956735e5ec3e..f35bb3fd61a0f 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -303,7 +303,7 @@ pub mod pallet { /// The signing account has no permission to do the operation. NoPermission, /// The given asset ID is unknown. - Unknown, + UnknownClass, /// The asset instance ID has already been used for an asset. AlreadyExists, /// The owner turned out to be different to what was expected. @@ -561,7 +561,8 @@ pub mod pallet { ) -> DispatchResult { let origin = ensure_signed(origin)?; - let mut class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + let mut class_details = + Class::::get(&class).ok_or(Error::::UnknownClass)?; ensure!(class_details.owner == origin, Error::::NoPermission); let deposit = match class_details.free_holding { true => Zero::zero(), @@ -621,8 +622,8 @@ pub mod pallet { let origin = ensure_signed(origin)?; let mut details = - Asset::::get(&class, &instance).ok_or(Error::::Unknown)?; - let class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; + let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; ensure!(class_details.freezer == origin, Error::::NoPermission); details.is_frozen = true; @@ -651,8 +652,8 @@ pub mod pallet { let origin = ensure_signed(origin)?; let mut details = - Asset::::get(&class, &instance).ok_or(Error::::Unknown)?; - let class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; + let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; ensure!(class_details.admin == origin, Error::::NoPermission); details.is_frozen = false; @@ -679,7 +680,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; Class::::try_mutate(class, |maybe_details| { - let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; ensure!(&origin == &details.freezer, Error::::NoPermission); details.is_frozen = true; @@ -706,7 +707,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; Class::::try_mutate(class, |maybe_details| { - let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; ensure!(&origin == &details.admin, Error::::NoPermission); details.is_frozen = false; @@ -736,7 +737,7 @@ pub mod pallet { let owner = T::Lookup::lookup(owner)?; Class::::try_mutate(class, |maybe_details| { - let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; ensure!(&origin == &details.owner, Error::::NoPermission); if details.owner == owner { return Ok(()) @@ -784,7 +785,7 @@ pub mod pallet { let freezer = T::Lookup::lookup(freezer)?; Class::::try_mutate(class, |maybe_details| { - let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; ensure!(&origin == &details.owner, Error::::NoPermission); details.issuer = issuer.clone(); @@ -820,9 +821,9 @@ pub mod pallet { let delegate = T::Lookup::lookup(delegate)?; - let class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; let mut details = - Asset::::get(&class, &instance).ok_or(Error::::Unknown)?; + Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; if let Some(check) = maybe_check { let permitted = &check == &class_details.admin || &check == &details.owner; @@ -870,9 +871,9 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - let class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; let mut details = - Asset::::get(&class, &instance).ok_or(Error::::Unknown)?; + Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; if let Some(check) = maybe_check { let permitted = &check == &class_details.admin || &check == &details.owner; ensure!(permitted, Error::::NoPermission); @@ -925,7 +926,7 @@ pub mod pallet { T::ForceOrigin::ensure_origin(origin)?; Class::::try_mutate(class, |maybe_asset| { - let mut asset = maybe_asset.take().ok_or(Error::::Unknown)?; + let mut asset = maybe_asset.take().ok_or(Error::::UnknownClass)?; let old_owner = asset.owner; let new_owner = T::Lookup::lookup(owner)?; asset.owner = new_owner.clone(); @@ -972,7 +973,8 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let mut class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + let mut class_details = + Class::::get(&class).ok_or(Error::::UnknownClass)?; if let Some(check_owner) = &maybe_check_owner { ensure!(check_owner == &class_details.owner, Error::::NoPermission); } @@ -1033,7 +1035,8 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let mut class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + let mut class_details = + Class::::get(&class).ok_or(Error::::UnknownClass)?; if let Some(check_owner) = &maybe_check_owner { ensure!(check_owner == &class_details.owner, Error::::NoPermission); } @@ -1083,7 +1086,8 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let mut class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + let mut class_details = + Class::::get(&class).ok_or(Error::::UnknownClass)?; if let Some(check_owner) = &maybe_check_owner { ensure!(check_owner == &class_details.owner, Error::::NoPermission); @@ -1142,7 +1146,8 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let mut class_details = Class::::get(&class).ok_or(Error::::Unknown)?; + let mut class_details = + Class::::get(&class).ok_or(Error::::UnknownClass)?; if let Some(check_owner) = &maybe_check_owner { ensure!(check_owner == &class_details.owner, Error::::NoPermission); } @@ -1154,7 +1159,7 @@ pub mod pallet { if metadata.is_some() { class_details.instance_metadatas.saturating_dec(); } - let deposit = metadata.take().ok_or(Error::::Unknown)?.deposit; + let deposit = metadata.take().ok_or(Error::::UnknownClass)?.deposit; T::Currency::unreserve(&class_details.owner, deposit); class_details.total_deposit.saturating_reduce(deposit); @@ -1191,7 +1196,7 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let mut details = Class::::get(&class).ok_or(Error::::Unknown)?; + let mut details = Class::::get(&class).ok_or(Error::::UnknownClass)?; if let Some(check_owner) = &maybe_check_owner { ensure!(check_owner == &details.owner, Error::::NoPermission); } @@ -1245,7 +1250,7 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let details = Class::::get(&class).ok_or(Error::::Unknown)?; + let details = Class::::get(&class).ok_or(Error::::UnknownClass)?; if let Some(check_owner) = &maybe_check_owner { ensure!(check_owner == &details.owner, Error::::NoPermission); } @@ -1254,7 +1259,7 @@ pub mod pallet { let was_frozen = metadata.as_ref().map_or(false, |m| m.is_frozen); ensure!(maybe_check_owner.is_none() || !was_frozen, Error::::Frozen); - let deposit = metadata.take().ok_or(Error::::Unknown)?.deposit; + let deposit = metadata.take().ok_or(Error::::UnknownClass)?.deposit; T::Currency::unreserve(&details.owner, deposit); Self::deposit_event(Event::ClassMetadataCleared { class }); Ok(()) diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 293140d5eda1a..12f39c78bfe3d 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -263,7 +263,7 @@ fn set_class_metadata_should_work() { // Cannot add metadata to unknown asset assert_noop!( Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 20], false), - Error::::Unknown, + Error::::UnknownClass, ); assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); // Cannot add metadata to unowned asset @@ -307,7 +307,10 @@ fn set_class_metadata_should_work() { Uniques::clear_class_metadata(Origin::signed(2), 0), Error::::NoPermission ); - assert_noop!(Uniques::clear_class_metadata(Origin::signed(1), 1), Error::::Unknown); + assert_noop!( + Uniques::clear_class_metadata(Origin::signed(1), 1), + Error::::UnknownClass + ); assert_ok!(Uniques::clear_class_metadata(Origin::signed(1), 0)); assert!(!ClassMetadataOf::::contains_key(0)); }); @@ -361,7 +364,10 @@ fn set_instance_metadata_should_work() { Uniques::clear_metadata(Origin::signed(2), 0, 42), Error::::NoPermission ); - assert_noop!(Uniques::clear_metadata(Origin::signed(1), 1, 42), Error::::Unknown); + assert_noop!( + Uniques::clear_metadata(Origin::signed(1), 1, 42), + Error::::UnknownClass + ); assert_ok!(Uniques::clear_metadata(Origin::signed(1), 0, 42)); assert!(!InstanceMetadataOf::::contains_key(0, 42)); }); @@ -486,7 +492,7 @@ fn burn_works() { assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4)); - assert_noop!(Uniques::burn(Origin::signed(5), 0, 42, Some(5)), Error::::Unknown); + assert_noop!(Uniques::burn(Origin::signed(5), 0, 42, Some(5)), Error::::UnknownClass); assert_ok!(Uniques::mint(Origin::signed(2), 0, 42, 5)); assert_ok!(Uniques::mint(Origin::signed(2), 0, 69, 5)); @@ -525,11 +531,11 @@ fn cancel_approval_works() { assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); assert_noop!( Uniques::cancel_approval(Origin::signed(2), 1, 42, None), - Error::::Unknown + Error::::UnknownClass ); assert_noop!( Uniques::cancel_approval(Origin::signed(2), 0, 43, None), - Error::::Unknown + Error::::UnknownClass ); assert_noop!( Uniques::cancel_approval(Origin::signed(3), 0, 42, None), @@ -557,11 +563,11 @@ fn cancel_approval_works_with_admin() { assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); assert_noop!( Uniques::cancel_approval(Origin::signed(1), 1, 42, None), - Error::::Unknown + Error::::UnknownClass ); assert_noop!( Uniques::cancel_approval(Origin::signed(1), 0, 43, None), - Error::::Unknown + Error::::UnknownClass ); assert_noop!( Uniques::cancel_approval(Origin::signed(1), 0, 42, Some(4)), @@ -583,8 +589,14 @@ fn cancel_approval_works_with_force() { assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); - assert_noop!(Uniques::cancel_approval(Origin::root(), 1, 42, None), Error::::Unknown); - assert_noop!(Uniques::cancel_approval(Origin::root(), 0, 43, None), Error::::Unknown); + assert_noop!( + Uniques::cancel_approval(Origin::root(), 1, 42, None), + Error::::UnknownClass + ); + assert_noop!( + Uniques::cancel_approval(Origin::root(), 0, 43, None), + Error::::UnknownClass + ); assert_noop!( Uniques::cancel_approval(Origin::root(), 0, 42, Some(4)), Error::::WrongDelegate From 542d587c3db7e46b6fff423e8efc4f327f7b79a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 22 Feb 2022 15:15:57 +0100 Subject: [PATCH 0539/1472] state-machine: Move all functionality from trie backend to the essence (#10904) * state-machine: Move all functionality from trie backend to the essence This is required for some future changes of me and it also makes more sense to have all the functionality inside the essence. Besides that it changes the child root cache to directly cache the hash. * Update primitives/state-machine/src/trie_backend_essence.rs Co-authored-by: cheme * FMT Co-authored-by: cheme --- primitives/state-machine/src/trie_backend.rs | 112 +--------- .../state-machine/src/trie_backend_essence.rs | 210 ++++++++++++++---- primitives/trie/src/lib.rs | 8 +- 3 files changed, 174 insertions(+), 156 deletions(-) diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index 37db59416f100..3b985ec2b99f6 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -18,19 +18,13 @@ //! Trie-based state machine backend. use crate::{ - debug, - trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage}, - warn, Backend, StorageKey, StorageValue, + trie_backend_essence::{TrieBackendEssence, TrieBackendStorage}, + Backend, StorageKey, StorageValue, }; -use codec::{Codec, Decode}; +use codec::Codec; use hash_db::Hasher; -use sp_core::storage::{ChildInfo, ChildType, StateVersion}; -use sp_std::{boxed::Box, vec::Vec}; -use sp_trie::{ - child_delta_trie_root, delta_trie_root, empty_child_trie_root, - trie_types::{TrieDB, TrieError}, - LayoutV0, LayoutV1, Trie, -}; +use sp_core::storage::{ChildInfo, StateVersion}; +use sp_std::vec::Vec; /// Patricia trie-based backend. Transaction type is an overlay of changes to commit. pub struct TrieBackend, H: Hasher> { @@ -144,43 +138,11 @@ where } fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { - let collect_all = || -> Result<_, Box>> { - let trie = TrieDB::::new(self.essence(), self.essence.root())?; - let mut v = Vec::new(); - for x in trie.iter()? { - let (key, value) = x?; - v.push((key.to_vec(), value.to_vec())); - } - - Ok(v) - }; - - match collect_all() { - Ok(v) => v, - Err(e) => { - debug!(target: "trie", "Error extracting trie values: {}", e); - Vec::new() - }, - } + self.essence.pairs() } fn keys(&self, prefix: &[u8]) -> Vec { - let collect_all = || -> Result<_, Box>> { - let trie = TrieDB::::new(self.essence(), self.essence.root())?; - let mut v = Vec::new(); - for x in trie.iter()? { - let (key, _) = x?; - if key.starts_with(prefix) { - v.push(key.to_vec()); - } - } - - Ok(v) - }; - - collect_all() - .map_err(|e| debug!(target: "trie", "Error extracting trie keys: {}", e)) - .unwrap_or_default() + self.essence.keys(prefix) } fn storage_root<'a>( @@ -191,25 +153,7 @@ where where H::Out: Ord, { - let mut write_overlay = S::Overlay::default(); - let mut root = *self.essence.root(); - - { - let mut eph = Ephemeral::new(self.essence.backend_storage(), &mut write_overlay); - let res = match state_version { - StateVersion::V0 => - delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), - StateVersion::V1 => - delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), - }; - - match res { - Ok(ret) => root = ret, - Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), - } - } - - (root, write_overlay) + self.essence.storage_root(delta, state_version) } fn child_storage_root<'a>( @@ -221,45 +165,7 @@ where where H::Out: Ord, { - let default_root = match child_info.child_type() { - ChildType::ParentKeyId => empty_child_trie_root::>(), - }; - let mut write_overlay = S::Overlay::default(); - let prefixed_storage_key = child_info.prefixed_storage_key(); - let mut root = match self.storage(prefixed_storage_key.as_slice()) { - Ok(value) => value - .and_then(|r| Decode::decode(&mut &r[..]).ok()) - .unwrap_or_else(|| default_root.clone()), - Err(e) => { - warn!(target: "trie", "Failed to read child storage root: {}", e); - default_root.clone() - }, - }; - - { - let mut eph = Ephemeral::new(self.essence.backend_storage(), &mut write_overlay); - match match state_version { - StateVersion::V0 => child_delta_trie_root::, _, _, _, _, _, _>( - child_info.keyspace(), - &mut eph, - root, - delta, - ), - StateVersion::V1 => child_delta_trie_root::, _, _, _, _, _, _>( - child_info.keyspace(), - &mut eph, - root, - delta, - ), - } { - Ok(ret) => root = ret, - Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), - } - } - - let is_default = root == default_root; - - (root, is_default, write_overlay) + self.essence.child_storage_root(child_info, delta, state_version) } fn as_trie_backend(&self) -> Option<&TrieBackend> { diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 8f3c27f03c748..e33e50641bbde 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -23,10 +23,11 @@ use codec::Encode; use hash_db::{self, AsHashDB, HashDB, HashDBRef, Hasher, Prefix}; #[cfg(feature = "std")] use parking_lot::RwLock; -use sp_core::storage::ChildInfo; +use sp_core::storage::{ChildInfo, ChildType, StateVersion}; use sp_std::{boxed::Box, vec::Vec}; use sp_trie::{ - empty_child_trie_root, read_child_trie_value, read_trie_value, + child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_value, + read_trie_value, trie_types::{TrieDB, TrieError}, DBValue, KeySpacedDB, PrefixedMemoryDB, Trie, TrieDBIterator, TrieDBKeyIterator, }; @@ -58,12 +59,12 @@ pub trait Storage: Send + Sync { /// Local cache for child root. #[cfg(feature = "std")] -pub(crate) struct Cache { - pub child_root: HashMap, Option>>, +pub(crate) struct Cache { + pub child_root: HashMap, Option>, } #[cfg(feature = "std")] -impl Cache { +impl Cache { fn new() -> Self { Cache { child_root: HashMap::new() } } @@ -75,7 +76,7 @@ pub struct TrieBackendEssence, H: Hasher> { root: H::Out, empty: H::Out, #[cfg(feature = "std")] - pub(crate) cache: Arc>, + pub(crate) cache: Arc>>, } impl, H: Hasher> TrieBackendEssence @@ -130,22 +131,26 @@ where } /// Access the root of the child storage in its parent trie - fn child_root(&self, child_info: &ChildInfo) -> Result> { + fn child_root(&self, child_info: &ChildInfo) -> Result> { #[cfg(feature = "std")] { if let Some(result) = self.cache.read().child_root.get(child_info.storage_key()) { - return Ok(result.clone()) + return Ok(*result) } } - let result = self.storage(child_info.prefixed_storage_key().as_slice())?; + let result = self.storage(child_info.prefixed_storage_key().as_slice())?.map(|r| { + let mut hash = H::Out::default(); + + // root is fetched from DB, not writable by runtime, so it's always valid. + hash.as_mut().copy_from_slice(&r[..]); + + hash + }); #[cfg(feature = "std")] { - self.cache - .write() - .child_root - .insert(child_info.storage_key().to_vec(), result.clone()); + self.cache.write().child_root.insert(child_info.storage_key().to_vec(), result); } Ok(result) @@ -163,15 +168,7 @@ where None => return Ok(None), }; - let mut hash = H::Out::default(); - - if child_root.len() != hash.as_ref().len() { - return Err(format!("Invalid child storage hash at {:?}", child_info.storage_key())) - } - // note: child_root and hash must be same size, panics otherwise. - hash.as_mut().copy_from_slice(&child_root[..]); - - self.next_storage_key_from_root(&hash, Some(child_info), key) + self.next_storage_key_from_root(&child_root, Some(child_info), key) } /// Return next key from main trie or child trie by providing corresponding root. @@ -231,9 +228,10 @@ where child_info: &ChildInfo, key: &[u8], ) -> Result> { - let root = self - .child_root(child_info)? - .unwrap_or_else(|| empty_child_trie_root::>().encode()); + let root = match self.child_root(child_info)? { + Some(root) => root, + None => return Ok(None), + }; let map_e = |e| format!("Trie lookup error: {}", e); @@ -253,19 +251,13 @@ where f: impl FnMut(Vec, Vec) -> bool, allow_missing_nodes: bool, ) -> Result { - let mut child_root; let root = if let Some(child_info) = child_info.as_ref() { - if let Some(fetched_child_root) = self.child_root(child_info)? { - child_root = H::Out::default(); - // root is fetched from DB, not writable by runtime, so it's always valid. - child_root.as_mut().copy_from_slice(fetched_child_root.as_slice()); - - &child_root - } else { - return Ok(true) + match self.child_root(child_info)? { + Some(child_root) => child_root, + None => return Ok(true), } } else { - &self.root + self.root }; self.trie_iter_inner(&root, prefix, f, child_info, start_at, allow_missing_nodes) @@ -279,22 +271,21 @@ where prefix: Option<&[u8]>, mut f: F, ) { - let mut child_root = H::Out::default(); let root = if let Some(child_info) = child_info.as_ref() { - let root_vec = match self.child_root(child_info) { - Ok(v) => v.unwrap_or_else(|| empty_child_trie_root::>().encode()), + match self.child_root(child_info) { + Ok(Some(v)) => v, + // If the child trie doesn't exist, there is no need to continue. + Ok(None) => return, Err(e) => { debug!(target: "trie", "Error while iterating child storage: {}", e); return }, - }; - child_root.as_mut().copy_from_slice(&root_vec); - &child_root + } } else { - &self.root + self.root }; - self.trie_iter_key_inner(root, prefix, |k| f(k), child_info) + self.trie_iter_key_inner(&root, prefix, |k| f(k), child_info) } /// Execute given closure for all keys starting with prefix. @@ -304,15 +295,16 @@ where prefix: &[u8], mut f: impl FnMut(&[u8]), ) { - let root_vec = match self.child_root(child_info) { - Ok(v) => v.unwrap_or_else(|| empty_child_trie_root::>().encode()), + let root = match self.child_root(child_info) { + Ok(Some(v)) => v, + // If the child trie doesn't exist, there is no need to continue. + Ok(None) => return, Err(e) => { debug!(target: "trie", "Error while iterating child storage: {}", e); return }, }; - let mut root = H::Out::default(); - root.as_mut().copy_from_slice(&root_vec); + self.trie_iter_key_inner( &root, Some(prefix), @@ -438,6 +430,130 @@ where false, ); } + + /// Returns all `(key, value)` pairs in the trie. + pub fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { + let collect_all = || -> sp_std::result::Result<_, Box>> { + let trie = TrieDB::::new(self, &self.root)?; + let mut v = Vec::new(); + for x in trie.iter()? { + let (key, value) = x?; + v.push((key.to_vec(), value.to_vec())); + } + + Ok(v) + }; + + match collect_all() { + Ok(v) => v, + Err(e) => { + debug!(target: "trie", "Error extracting trie values: {}", e); + Vec::new() + }, + } + } + + /// Returns all keys that start with the given `prefix`. + pub fn keys(&self, prefix: &[u8]) -> Vec { + let collect_all = || -> sp_std::result::Result<_, Box>> { + let trie = TrieDB::::new(self, &self.root)?; + let mut v = Vec::new(); + for x in trie.iter()? { + let (key, _) = x?; + if key.starts_with(prefix) { + v.push(key.to_vec()); + } + } + + Ok(v) + }; + + collect_all() + .map_err(|e| debug!(target: "trie", "Error extracting trie keys: {}", e)) + .unwrap_or_default() + } + + /// Return the storage root after applying the given `delta`. + pub fn storage_root<'a>( + &self, + delta: impl Iterator)>, + state_version: StateVersion, + ) -> (H::Out, S::Overlay) + where + H::Out: Ord, + { + let mut write_overlay = S::Overlay::default(); + let mut root = self.root; + + { + let mut eph = Ephemeral::new(self.backend_storage(), &mut write_overlay); + let res = match state_version { + StateVersion::V0 => + delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), + StateVersion::V1 => + delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), + }; + + match res { + Ok(ret) => root = ret, + Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), + } + } + + (root, write_overlay) + } + + /// Returns the child storage root for the child trie `child_info` after applying the given + /// `delta`. + pub fn child_storage_root<'a>( + &self, + child_info: &ChildInfo, + delta: impl Iterator)>, + state_version: StateVersion, + ) -> (H::Out, bool, S::Overlay) + where + H::Out: Ord, + { + let default_root = match child_info.child_type() { + ChildType::ParentKeyId => empty_child_trie_root::>(), + }; + let mut write_overlay = S::Overlay::default(); + let mut root = match self.child_root(child_info) { + Ok(Some(hash)) => hash, + Ok(None) => default_root, + Err(e) => { + warn!(target: "trie", "Failed to read child storage root: {}", e); + default_root.clone() + }, + }; + + { + let mut eph = Ephemeral::new(self.backend_storage(), &mut write_overlay); + match match state_version { + StateVersion::V0 => + child_delta_trie_root::, _, _, _, _, _, _>( + child_info.keyspace(), + &mut eph, + root, + delta, + ), + StateVersion::V1 => + child_delta_trie_root::, _, _, _, _, _, _>( + child_info.keyspace(), + &mut eph, + root, + delta, + ), + } { + Ok(ret) => root = ret, + Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), + } + } + + let is_default = root == default_root; + + (root, is_default, write_overlay) + } } pub(crate) struct Ephemeral<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> { diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index f598615be9098..c4d4c7210bd46 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -374,18 +374,14 @@ where pub fn read_child_trie_value( keyspace: &[u8], db: &DB, - root_slice: &[u8], + root: &TrieHash, key: &[u8], ) -> Result>, Box>> where DB: hash_db::HashDBRef, { - let mut root = TrieHash::::default(); - // root is fetched from DB, not writable by runtime, so it's always valid. - root.as_mut().copy_from_slice(root_slice); - let db = KeySpacedDB::new(&*db, keyspace); - TrieDB::::new(&db, &root)?.get(key).map(|x| x.map(|val| val.to_vec())) + TrieDB::::new(&db, root)?.get(key).map(|x| x.map(|val| val.to_vec())) } /// Read a value from the child trie with given query. From 46c67a84587a4f02740e956b9736ad0be970c5f9 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Tue, 22 Feb 2022 06:38:34 -0800 Subject: [PATCH 0540/1472] staking: Remove `SessionInterface` supertrait (#10901) --- frame/staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 3738c87dd5b3d..22143ff1ee03f 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -653,7 +653,7 @@ impl UnappliedSlash { /// Means for interacting with a specialized version of the `session` trait. /// /// This is needed because `Staking` sets the `ValidatorIdOf` of the `pallet_session::Config` -pub trait SessionInterface: frame_system::Config { +pub trait SessionInterface { /// Disable the validator at the given index, returns `false` if the validator was already /// disabled or the index is out of bounds. fn disable_validator(validator_index: u32) -> bool; From 42b2d623d058197aebc3c737fb44fbbf278a85b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 22 Feb 2022 19:39:16 +0000 Subject: [PATCH 0541/1472] consensus-slots: cleanup SlotDuration config (#10878) * consensus-slots: cleanup the SlotDuration config * fix tests * address review comments --- Cargo.lock | 2 + bin/node-template/node/src/service.rs | 10 ++- bin/node/cli/src/service.rs | 9 ++- client/consensus/aura/src/lib.rs | 21 +++--- client/consensus/babe/rpc/src/lib.rs | 2 +- client/consensus/babe/src/lib.rs | 72 ++++++++++--------- client/consensus/babe/src/tests.rs | 14 ++-- .../manual-seal/src/consensus/aura.rs | 19 ++--- .../manual-seal/src/consensus/babe.rs | 12 ++-- .../manual-seal/src/consensus/timestamp.rs | 30 +++++--- client/consensus/slots/src/lib.rs | 56 ++------------- primitives/consensus/aura/src/inherents.rs | 7 +- primitives/consensus/aura/src/lib.rs | 27 +------ primitives/consensus/babe/src/inherents.rs | 8 +-- primitives/consensus/babe/src/lib.rs | 9 +-- primitives/consensus/common/src/lib.rs | 6 -- primitives/consensus/slots/Cargo.toml | 8 ++- primitives/consensus/slots/src/lib.rs | 32 +++++++++ primitives/timestamp/src/lib.rs | 8 ++- 19 files changed, 161 insertions(+), 191 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 992a49306f18f..517b92c522d4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9627,6 +9627,8 @@ dependencies = [ "serde", "sp-arithmetic", "sp-runtime", + "sp-std", + "sp-timestamp", ] [[package]] diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 4395718a6d680..fc7dc9b978df3 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -8,7 +8,6 @@ use sc_finality_grandpa::SharedVoterState; use sc_keystore::LocalKeystore; use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; use sc_telemetry::{Telemetry, TelemetryWorker}; -use sp_consensus::SlotData; use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; use std::{sync::Arc, time::Duration}; @@ -111,7 +110,7 @@ pub fn new_partial( telemetry.as_ref().map(|x| x.handle()), )?; - let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration(); + let slot_duration = sc_consensus_aura::slot_duration(&*client)?; let import_queue = sc_consensus_aura::import_queue::(ImportQueueParams { @@ -122,7 +121,7 @@ pub fn new_partial( let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration( + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( *timestamp, slot_duration, ); @@ -260,7 +259,6 @@ pub fn new_full(mut config: Configuration) -> Result sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); let slot_duration = sc_consensus_aura::slot_duration(&*client)?; - let raw_slot_duration = slot_duration.slot_duration(); let aura = sc_consensus_aura::start_aura::( StartAuraParams { @@ -273,9 +271,9 @@ pub fn new_full(mut config: Configuration) -> Result let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration( + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( *timestamp, - raw_slot_duration, + slot_duration, ); Ok((timestamp, slot)) diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 81c68bf5d3aa7..10d39f278f5f3 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -212,7 +212,7 @@ pub fn new_partial( let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); let slot = - sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration( + sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_slot_duration( *timestamp, slot_duration, ); @@ -419,7 +419,7 @@ pub fn new_full_base( let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); let slot = - sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration( + sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_slot_duration( *timestamp, slot_duration, ); @@ -650,7 +650,10 @@ mod tests { .epoch_changes() .shared_data() .epoch_data(&epoch_descriptor, |slot| { - sc_consensus_babe::Epoch::genesis(&babe_link.config(), slot) + sc_consensus_babe::Epoch::genesis( + babe_link.config().genesis_config(), + slot, + ) }) .unwrap(); diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 61c5610883149..d3a6b10589408 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -77,14 +77,11 @@ pub use sp_consensus::SyncOracle; pub use sp_consensus_aura::{ digests::CompatibleDigestItem, inherents::{InherentDataProvider, InherentType as AuraInherent, INHERENT_IDENTIFIER}, - AuraApi, ConsensusLog, AURA_ENGINE_ID, + AuraApi, ConsensusLog, SlotDuration, AURA_ENGINE_ID, }; type AuthorityId

=

::Public; -/// Slot duration type for Aura. -pub type SlotDuration = sc_consensus_slots::SlotDuration; - /// Get the slot duration for Aura. pub fn slot_duration(client: &C) -> CResult where @@ -94,9 +91,7 @@ where C::Api: AuraApi, { let best_block_id = BlockId::Hash(client.usage_info().chain.best_hash); - let slot_duration = client.runtime_api().slot_duration(&best_block_id)?; - - Ok(SlotDuration::new(slot_duration)) + client.runtime_api().slot_duration(&best_block_id).map_err(|err| err.into()) } /// Get slot author for given block along with authorities. @@ -574,7 +569,7 @@ mod tests { use sc_network_test::{Block as TestBlock, *}; use sp_application_crypto::key_types::AURA; use sp_consensus::{ - AlwaysCanAuthor, DisableProofRecording, NoNetwork as DummyOracle, Proposal, SlotData, + AlwaysCanAuthor, DisableProofRecording, NoNetwork as DummyOracle, Proposal, }; use sp_consensus_aura::sr25519::AuthorityPair; use sp_inherents::InherentData; @@ -672,14 +667,14 @@ mod tests { let client = client.as_client(); let slot_duration = slot_duration(&*client).expect("slot duration available"); - assert_eq!(slot_duration.slot_duration().as_millis() as u64, SLOT_DURATION); + assert_eq!(slot_duration.as_millis() as u64, SLOT_DURATION); import_queue::AuraVerifier::new( client, Box::new(|_, _| async { let timestamp = TimestampInherentDataProvider::from_system_time(); - let slot = InherentDataProvider::from_timestamp_and_duration( + let slot = InherentDataProvider::from_timestamp_and_slot_duration( *timestamp, - Duration::from_secs(6), + SlotDuration::from_millis(6000), ); Ok((timestamp, slot)) @@ -762,9 +757,9 @@ mod tests { justification_sync_link: (), create_inherent_data_providers: |_, _| async { let timestamp = TimestampInherentDataProvider::from_system_time(); - let slot = InherentDataProvider::from_timestamp_and_duration( + let slot = InherentDataProvider::from_timestamp_and_slot_duration( *timestamp, - Duration::from_secs(6), + SlotDuration::from_millis(6000), ); Ok((timestamp, slot)) diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 88a176e2de10d..9dd6424a43a98 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -207,7 +207,7 @@ where &parent.hash(), parent.number().clone(), slot.into(), - |slot| Epoch::genesis(&babe_config, slot), + |slot| Epoch::genesis(babe_config.genesis_config(), slot), ) .map_err(|e| Error::Consensus(ConsensusError::ChainLookup(e.to_string())))? .ok_or(Error::Consensus(ConsensusError::InvalidAuthoritiesSet)) diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 19d9e37cf20ae..78fe506dbf341 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -66,9 +66,7 @@ #![forbid(unsafe_code)] #![warn(missing_docs)] -use std::{ - borrow::Cow, collections::HashMap, convert::TryInto, pin::Pin, sync::Arc, time::Duration, u64, -}; +use std::{borrow::Cow, collections::HashMap, convert::TryInto, pin::Pin, sync::Arc, u64}; use codec::{Decode, Encode}; use futures::{ @@ -106,10 +104,10 @@ use sp_block_builder::BlockBuilder as BlockBuilderApi; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult}; use sp_consensus::{ BlockOrigin, CacheKeyId, CanAuthorWith, Environment, Error as ConsensusError, Proposer, - SelectChain, SlotData, + SelectChain, }; use sp_consensus_babe::inherents::BabeInherentData; -use sp_consensus_slots::Slot; +use sp_consensus_slots::{Slot, SlotDuration}; use sp_core::{crypto::ByteArray, ExecutionContext}; use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; @@ -328,17 +326,15 @@ pub struct BabeIntermediate { /// Intermediate key for Babe engine. pub static INTERMEDIATE_KEY: &[u8] = b"babe1"; -/// A slot duration. -/// -/// Create with [`Self::get`]. -// FIXME: Once Rust has higher-kinded types, the duplication between this -// and `super::babe::Config` can be eliminated. -// https://github.com/paritytech/substrate/issues/2434 +/// Configuration for BABE used for defining block verification parameters as +/// well as authoring (e.g. the slot duration). #[derive(Clone)] -pub struct Config(sc_consensus_slots::SlotDuration); +pub struct Config { + genesis_config: BabeGenesisConfiguration, +} impl Config { - /// Fetch the config from the runtime. + /// Create a new config by reading the genesis configuration from the runtime. pub fn get(client: &C) -> ClientResult where C: AuxStore + ProvideRuntimeApi + UsageProvider, @@ -355,7 +351,7 @@ impl Config { let version = runtime_api.api_version::>(&best_block_id)?; - let slot_duration = if version == Some(1) { + let genesis_config = if version == Some(1) { #[allow(deprecated)] { runtime_api.configuration_before_version_2(&best_block_id)?.into() @@ -368,20 +364,17 @@ impl Config { )) }; - Ok(Self(sc_consensus_slots::SlotDuration::new(slot_duration))) + Ok(Config { genesis_config }) } - /// Get the inner slot duration - pub fn slot_duration(&self) -> Duration { - self.0.slot_duration() + /// Get the genesis configuration. + pub fn genesis_config(&self) -> &BabeGenesisConfiguration { + &self.genesis_config } -} -impl std::ops::Deref for Config { - type Target = BabeGenesisConfiguration; - - fn deref(&self) -> &BabeGenesisConfiguration { - &*self.0 + /// Get the slot duration defined in the genesis configuration. + pub fn slot_duration(&self) -> SlotDuration { + SlotDuration::from_millis(self.genesis_config.slot_duration) } } @@ -488,7 +481,6 @@ where { const HANDLE_BUFFER_SIZE: usize = 1024; - let config = babe_link.config; let slot_notification_sinks = Arc::new(Mutex::new(Vec::new())); let worker = BabeSlotWorker { @@ -502,7 +494,7 @@ where keystore, epoch_changes: babe_link.epoch_changes.clone(), slot_notification_sinks: slot_notification_sinks.clone(), - config: config.clone(), + config: babe_link.config.clone(), block_proposal_slot_portion, max_block_proposal_slot_portion, telemetry, @@ -510,7 +502,7 @@ where info!(target: "babe", "👶 Starting BABE Authorship worker"); let inner = sc_consensus_slots::start_slot_worker( - config.0.clone(), + babe_link.config.slot_duration(), select_chain, worker, sync_oracle, @@ -521,7 +513,8 @@ where let (worker_tx, worker_rx) = channel(HANDLE_BUFFER_SIZE); let answer_requests = - answer_requests(worker_rx, config.0, client, babe_link.epoch_changes.clone()); + answer_requests(worker_rx, babe_link.config, client, babe_link.epoch_changes.clone()); + Ok(BabeWorker { inner: Box::pin(future::join(inner, answer_requests).map(|_| ())), slot_notification_sinks, @@ -531,7 +524,7 @@ where async fn answer_requests( mut request_rx: Receiver>, - genesis_config: sc_consensus_slots::SlotDuration, + config: Config, client: Arc, epoch_changes: SharedEpochChanges, ) where @@ -561,7 +554,7 @@ async fn answer_requests( let viable_epoch = epoch_changes .viable_epoch(&epoch_descriptor, |slot| { - Epoch::genesis(&genesis_config, slot) + Epoch::genesis(&config.genesis_config, slot) }) .ok_or_else(|| Error::::FetchEpoch(parent_hash))?; @@ -720,7 +713,9 @@ where fn authorities_len(&self, epoch_descriptor: &Self::EpochData) -> Option { self.epoch_changes .shared_data() - .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) + .viable_epoch(&epoch_descriptor, |slot| { + Epoch::genesis(&self.config.genesis_config, slot) + }) .map(|epoch| epoch.as_ref().authorities.len()) } @@ -735,7 +730,9 @@ where slot, self.epoch_changes .shared_data() - .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&self.config, slot))? + .viable_epoch(&epoch_descriptor, |slot| { + Epoch::genesis(&self.config.genesis_config, slot) + })? .as_ref(), &self.keystore, ); @@ -1165,7 +1162,9 @@ where .map_err(|e| Error::::ForkTree(Box::new(e)))? .ok_or_else(|| Error::::FetchEpoch(parent_hash))?; let viable_epoch = epoch_changes - .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) + .viable_epoch(&epoch_descriptor, |slot| { + Epoch::genesis(&self.config.genesis_config, slot) + }) .ok_or_else(|| Error::::FetchEpoch(parent_hash))?; // We add one to the current slot to allow for some small drift. @@ -1498,7 +1497,9 @@ where old_epoch_changes = Some((*epoch_changes).clone()); let viable_epoch = epoch_changes - .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) + .viable_epoch(&epoch_descriptor, |slot| { + Epoch::genesis(&self.config.genesis_config, slot) + }) .ok_or_else(|| { ConsensusError::ClientImport(Error::::FetchEpoch(parent_hash).into()) })?; @@ -1684,7 +1685,8 @@ pub fn block_import( where Client: AuxStore + HeaderBackend + HeaderMetadata, { - let epoch_changes = aux_schema::load_epoch_changes::(&*client, &config)?; + let epoch_changes = + aux_schema::load_epoch_changes::(&*client, &config.genesis_config)?; let link = BabeLink { epoch_changes: epoch_changes.clone(), config: config.clone() }; // NOTE: this isn't entirely necessary, but since we didn't use to prune the diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 7c04dc03c2f24..d38d57b84f5e1 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -143,7 +143,7 @@ impl DummyProposer { &self.parent_hash, self.parent_number, this_slot, - |slot| Epoch::genesis(&self.factory.config, slot), + |slot| Epoch::genesis(self.factory.config.genesis_config(), slot), ) .expect("client has data to find epoch") .expect("can compute epoch for baked block"); @@ -336,9 +336,9 @@ impl TestNetFactory for BabeTestNet { select_chain: longest_chain, create_inherent_data_providers: Box::new(|_, _| async { let timestamp = TimestampInherentDataProvider::from_system_time(); - let slot = InherentDataProvider::from_timestamp_and_duration( + let slot = InherentDataProvider::from_timestamp_and_slot_duration( *timestamp, - Duration::from_secs(6), + SlotDuration::from_millis(6000), ); Ok((timestamp, slot)) @@ -449,9 +449,9 @@ fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static sync_oracle: DummyOracle, create_inherent_data_providers: Box::new(|_, _| async { let timestamp = TimestampInherentDataProvider::from_system_time(); - let slot = InherentDataProvider::from_timestamp_and_duration( + let slot = InherentDataProvider::from_timestamp_and_slot_duration( *timestamp, - Duration::from_secs(6), + SlotDuration::from_millis(6000), ); Ok((timestamp, slot)) @@ -699,12 +699,12 @@ fn importing_block_one_sets_genesis_epoch() { &mut block_import, ); - let genesis_epoch = Epoch::genesis(&data.link.config, 999.into()); + let genesis_epoch = Epoch::genesis(data.link.config.genesis_config(), 999.into()); let epoch_changes = data.link.epoch_changes.shared_data(); let epoch_for_second_block = epoch_changes .epoch_data_for_child_of(descendent_query(&*client), &block_hash, 1, 1000.into(), |slot| { - Epoch::genesis(&data.link.config, slot) + Epoch::genesis(data.link.config.genesis_config(), slot) }) .unwrap() .unwrap(); diff --git a/client/consensus/manual-seal/src/consensus/aura.rs b/client/consensus/manual-seal/src/consensus/aura.rs index 4497a94bdd429..7b5d6720562be 100644 --- a/client/consensus/manual-seal/src/consensus/aura.rs +++ b/client/consensus/manual-seal/src/consensus/aura.rs @@ -22,13 +22,12 @@ use crate::{ConsensusDataProvider, Error}; use sc_client_api::{AuxStore, UsageProvider}; use sc_consensus::BlockImportParams; -use sc_consensus_aura::slot_duration; use sp_api::{ProvideRuntimeApi, TransactionFor}; use sp_blockchain::{HeaderBackend, HeaderMetadata}; use sp_consensus_aura::{ digests::CompatibleDigestItem, sr25519::{AuthorityId, AuthoritySignature}, - AuraApi, + AuraApi, Slot, SlotDuration, }; use sp_inherents::InherentData; use sp_runtime::{traits::Block as BlockT, Digest, DigestItem}; @@ -37,8 +36,8 @@ use std::{marker::PhantomData, sync::Arc}; /// Consensus data provider for Aura. pub struct AuraConsensusDataProvider { - // slot duration in milliseconds - slot_duration: u64, + // slot duration + slot_duration: SlotDuration, // phantom data for required generics _phantom: PhantomData<(B, C)>, } @@ -52,8 +51,8 @@ where /// Creates a new instance of the [`AuraConsensusDataProvider`], requires that `client` /// implements [`sp_consensus_aura::AuraApi`] pub fn new(client: Arc) -> Self { - let slot_duration = - (*slot_duration(&*client).expect("slot_duration is always present; qed.")).get(); + let slot_duration = sc_consensus_aura::slot_duration(&*client) + .expect("slot_duration is always present; qed."); Self { slot_duration, _phantom: PhantomData } } @@ -76,13 +75,15 @@ where _parent: &B::Header, inherents: &InherentData, ) -> Result { - let time_stamp = - *inherents.timestamp_inherent_data()?.expect("Timestamp is always present; qed"); + let timestamp = + inherents.timestamp_inherent_data()?.expect("Timestamp is always present; qed"); + // we always calculate the new slot number based on the current time-stamp and the slot // duration. let digest_item = >::aura_pre_digest( - (time_stamp / self.slot_duration).into(), + Slot::from_timestamp(timestamp, self.slot_duration), ); + Ok(Digest { logs: vec![digest_item] }) } diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index dd3f9a253478a..53cc58df30a36 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -169,7 +169,9 @@ where .ok_or_else(|| sp_consensus::Error::InvalidAuthoritiesSet)?; let epoch = epoch_changes - .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) + .viable_epoch(&epoch_descriptor, |slot| { + Epoch::genesis(self.config.genesis_config(), slot) + }) .ok_or_else(|| { log::info!(target: "babe", "create_digest: no viable_epoch :("); sp_consensus::Error::InvalidAuthoritiesSet @@ -283,15 +285,17 @@ where let timestamp = inherents .timestamp_inherent_data()? .ok_or_else(|| Error::StringError("No timestamp inherent data".into()))?; - let slot = *timestamp / self.config.slot_duration; + + let slot = Slot::from_timestamp(timestamp, self.config.slot_duration()); + // manually hard code epoch descriptor epoch_descriptor = match epoch_descriptor { ViableEpochDescriptor::Signaled(identifier, _header) => ViableEpochDescriptor::Signaled( identifier, EpochHeader { - start_slot: slot.into(), - end_slot: (slot * self.config.epoch_length).into(), + start_slot: slot, + end_slot: (*slot * self.config.genesis_config().epoch_length).into(), }, ), _ => unreachable!( diff --git a/client/consensus/manual-seal/src/consensus/timestamp.rs b/client/consensus/manual-seal/src/consensus/timestamp.rs index 908d218da05ac..e7f4e709ab996 100644 --- a/client/consensus/manual-seal/src/consensus/timestamp.rs +++ b/client/consensus/manual-seal/src/consensus/timestamp.rs @@ -21,8 +21,6 @@ use crate::Error; use sc_client_api::{AuxStore, UsageProvider}; -use sc_consensus_aura::slot_duration; -use sc_consensus_babe::Config; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_consensus_aura::{ @@ -30,6 +28,7 @@ use sp_consensus_aura::{ AuraApi, }; use sp_consensus_babe::BabeApi; +use sp_consensus_slots::{Slot, SlotDuration}; use sp_inherents::{InherentData, InherentDataProvider, InherentIdentifier}; use sp_runtime::{ generic::BlockId, @@ -53,7 +52,7 @@ pub struct SlotTimestampProvider { // holds the unix millisecnd timestamp for the most recent block unix_millis: atomic::AtomicU64, // configured slot_duration in the runtime - slot_duration: u64, + slot_duration: SlotDuration, } impl SlotTimestampProvider { @@ -64,7 +63,7 @@ impl SlotTimestampProvider { C: AuxStore + HeaderBackend + ProvideRuntimeApi + UsageProvider, C::Api: BabeApi, { - let slot_duration = Config::get(&*client)?.slot_duration; + let slot_duration = sc_consensus_babe::Config::get(&*client)?.slot_duration(); let time = Self::with_header(&client, slot_duration, |header| { let slot_number = *sc_consensus_babe::find_pre_digest::(&header) @@ -83,7 +82,7 @@ impl SlotTimestampProvider { C: AuxStore + HeaderBackend + ProvideRuntimeApi + UsageProvider, C::Api: AuraApi, { - let slot_duration = (*slot_duration(&*client)?).get(); + let slot_duration = sc_consensus_aura::slot_duration(&*client)?; let time = Self::with_header(&client, slot_duration, |header| { let slot_number = *sc_consensus_aura::find_pre_digest::(&header) @@ -94,7 +93,11 @@ impl SlotTimestampProvider { Ok(Self { unix_millis: atomic::AtomicU64::new(time), slot_duration }) } - fn with_header(client: &Arc, slot_duration: u64, func: F) -> Result + fn with_header( + client: &Arc, + slot_duration: SlotDuration, + func: F, + ) -> Result where B: BlockT, C: AuxStore + HeaderBackend + UsageProvider, @@ -110,7 +113,7 @@ impl SlotTimestampProvider { .ok_or_else(|| "best header not found in the db!".to_string())?; let slot = func(header)?; // add the slot duration so there's no collision of slots - (slot * slot_duration) + slot_duration + (slot * slot_duration.as_millis() as u64) + slot_duration.as_millis() as u64 } else { // this is the first block, use the correct time. let now = SystemTime::now(); @@ -123,8 +126,11 @@ impl SlotTimestampProvider { } /// Get the current slot number - pub fn slot(&self) -> u64 { - self.unix_millis.load(atomic::Ordering::SeqCst) / self.slot_duration + pub fn slot(&self) -> Slot { + Slot::from_timestamp( + self.unix_millis.load(atomic::Ordering::SeqCst).into(), + self.slot_duration, + ) } /// Gets the current time stamp. @@ -140,8 +146,10 @@ impl InherentDataProvider for SlotTimestampProvider { inherent_data: &mut InherentData, ) -> Result<(), sp_inherents::Error> { // we update the time here. - let new_time: InherentType = - self.unix_millis.fetch_add(self.slot_duration, atomic::Ordering::SeqCst).into(); + let new_time: InherentType = self + .unix_millis + .fetch_add(self.slot_duration.as_millis() as u64, atomic::Ordering::SeqCst) + .into(); inherent_data.put_data(INHERENT_IDENTIFIER, &new_time)?; Ok(()) } diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 094d065a1c07c..f6129943b2411 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -32,15 +32,14 @@ pub use aux_schema::{check_equivocation, MAX_SLOT_CAPACITY, PRUNING_BOUND}; pub use slots::SlotInfo; use slots::Slots; -use codec::{Decode, Encode}; use futures::{future::Either, Future, TryFutureExt}; use futures_timer::Delay; -use log::{debug, error, info, warn}; +use log::{debug, info, warn}; use sc_consensus::{BlockImport, JustificationSyncLink}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO, CONSENSUS_WARN}; use sp_arithmetic::traits::BaseArithmetic; -use sp_consensus::{CanAuthorWith, Proposer, SelectChain, SlotData, SyncOracle}; -use sp_consensus_slots::Slot; +use sp_consensus::{CanAuthorWith, Proposer, SelectChain, SyncOracle}; +use sp_consensus_slots::{Slot, SlotDuration}; use sp_inherents::CreateInherentDataProviders; use sp_runtime::{ generic::BlockId, @@ -459,8 +458,8 @@ impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F, G, H, I, J); /// /// Every time a new slot is triggered, `worker.on_slot` is called and the future it returns is /// polled until completion, unless we are major syncing. -pub async fn start_slot_worker( - slot_duration: SlotDuration, +pub async fn start_slot_worker( + slot_duration: SlotDuration, client: C, mut worker: W, mut sync_oracle: SO, @@ -471,15 +470,11 @@ pub async fn start_slot_worker( C: SelectChain, W: SlotWorker, SO: SyncOracle + Send, - T: SlotData + Clone, CIDP: CreateInherentDataProviders + Send, CIDP::InherentDataProviders: InherentDataProviderExt + Send, CAW: CanAuthorWith + Send, { - let SlotDuration(slot_duration) = slot_duration; - - let mut slots = - Slots::new(slot_duration.slot_duration(), create_inherent_data_providers, client); + let mut slots = Slots::new(slot_duration.as_duration(), create_inherent_data_providers, client); loop { let slot_info = match slots.next_slot().await { @@ -523,45 +518,6 @@ pub enum CheckedHeader { Checked(H, S), } -#[derive(Debug, thiserror::Error)] -#[allow(missing_docs)] -pub enum Error -where - T: Debug, -{ - #[error("Slot duration is invalid: {0:?}")] - SlotDurationInvalid(SlotDuration), -} - -/// A slot duration. Create with [`Self::new`]. -#[derive(Clone, Copy, Debug, Encode, Decode, Hash, PartialOrd, Ord, PartialEq, Eq)] -pub struct SlotDuration(T); - -impl Deref for SlotDuration { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } -} - -impl SlotData for SlotDuration { - fn slot_duration(&self) -> std::time::Duration { - self.0.slot_duration() - } -} - -impl SlotDuration { - /// Create a new instance of `Self`. - pub fn new(val: T) -> Self { - Self(val) - } - - /// Returns slot data value. - pub fn get(&self) -> T { - self.0.clone() - } -} - /// A unit type wrapper to express the proportion of a slot. pub struct SlotProportion(f32); diff --git a/primitives/consensus/aura/src/inherents.rs b/primitives/consensus/aura/src/inherents.rs index c3fa43bec02b8..ce3d832c78ee9 100644 --- a/primitives/consensus/aura/src/inherents.rs +++ b/primitives/consensus/aura/src/inherents.rs @@ -58,12 +58,11 @@ impl InherentDataProvider { /// Creates the inherent data provider by calculating the slot from the given /// `timestamp` and `duration`. - pub fn from_timestamp_and_duration( + pub fn from_timestamp_and_slot_duration( timestamp: sp_timestamp::Timestamp, - duration: std::time::Duration, + slot_duration: sp_consensus_slots::SlotDuration, ) -> Self { - let slot = - InherentType::from((timestamp.as_duration().as_millis() / duration.as_millis()) as u64); + let slot = InherentType::from_timestamp(timestamp, slot_duration); Self { slot } } diff --git a/primitives/consensus/aura/src/lib.rs b/primitives/consensus/aura/src/lib.rs index cec89d0449d8e..3e47adf0bf92f 100644 --- a/primitives/consensus/aura/src/lib.rs +++ b/primitives/consensus/aura/src/lib.rs @@ -62,7 +62,7 @@ pub mod ed25519 { pub type AuthorityId = app_ed25519::Public; } -pub use sp_consensus_slots::Slot; +pub use sp_consensus_slots::{Slot, SlotDuration}; /// The `ConsensusEngineId` of AuRa. pub const AURA_ENGINE_ID: ConsensusEngineId = [b'a', b'u', b'r', b'a']; @@ -93,28 +93,3 @@ sp_api::decl_runtime_apis! { fn authorities() -> Vec; } } - -/// Aura slot duration. -/// -/// Internally stored as milliseconds. -#[derive(sp_runtime::RuntimeDebug, Encode, Decode, PartialEq, Clone, Copy)] -pub struct SlotDuration(u64); - -impl SlotDuration { - /// Initialize from the given milliseconds. - pub fn from_millis(val: u64) -> Self { - Self(val) - } - - /// Returns the slot duration in milli seconds. - pub fn get(&self) -> u64 { - self.0 - } -} - -#[cfg(feature = "std")] -impl sp_consensus::SlotData for SlotDuration { - fn slot_duration(&self) -> std::time::Duration { - std::time::Duration::from_millis(self.0) - } -} diff --git a/primitives/consensus/babe/src/inherents.rs b/primitives/consensus/babe/src/inherents.rs index 1eadfd85d1147..c26dc514ae158 100644 --- a/primitives/consensus/babe/src/inherents.rs +++ b/primitives/consensus/babe/src/inherents.rs @@ -18,7 +18,6 @@ //! Inherents for BABE use sp_inherents::{Error, InherentData, InherentIdentifier}; - use sp_std::result::Result; /// The BABE inherent identifier. @@ -60,12 +59,11 @@ impl InherentDataProvider { /// Creates the inherent data provider by calculating the slot from the given /// `timestamp` and `duration`. - pub fn from_timestamp_and_duration( + pub fn from_timestamp_and_slot_duration( timestamp: sp_timestamp::Timestamp, - duration: std::time::Duration, + slot_duration: sp_consensus_slots::SlotDuration, ) -> Self { - let slot = - InherentType::from((timestamp.as_duration().as_millis() / duration.as_millis()) as u64); + let slot = InherentType::from_timestamp(timestamp, slot_duration); Self { slot } } diff --git a/primitives/consensus/babe/src/lib.rs b/primitives/consensus/babe/src/lib.rs index e7dfc100825d6..492d1a9a7238f 100644 --- a/primitives/consensus/babe/src/lib.rs +++ b/primitives/consensus/babe/src/lib.rs @@ -79,7 +79,7 @@ pub const MEDIAN_ALGORITHM_CARDINALITY: usize = 1200; // arbitrary suggestion by /// The index of an authority. pub type AuthorityIndex = u32; -pub use sp_consensus_slots::Slot; +pub use sp_consensus_slots::{Slot, SlotDuration}; /// An equivocation proof for multiple block authorships on the same slot (i.e. double vote). pub type EquivocationProof = sp_consensus_slots::EquivocationProof; @@ -237,13 +237,6 @@ impl AllowedSlots { } } -#[cfg(feature = "std")] -impl sp_consensus::SlotData for BabeGenesisConfiguration { - fn slot_duration(&self) -> std::time::Duration { - std::time::Duration::from_millis(self.slot_duration) - } -} - /// Configuration data used by the BABE consensus engine. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index edf393fa229ad..59bbf7618dfc3 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -327,9 +327,3 @@ impl CanAuthorWith for NeverCanAuthor { Err("Authoring is always disabled.".to_string()) } } - -/// A type from which a slot duration can be obtained. -pub trait SlotData { - /// Gets the slot duration. - fn slot_duration(&self) -> sp_std::time::Duration; -} diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index 18506980ae85d..aed2265bddca6 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -16,8 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0", features = ["derive"], optional = true } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../arithmetic" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../timestamp" } [features] default = ["std"] @@ -25,6 +27,8 @@ std = [ "codec/std", "scale-info/std", "serde", - "sp-runtime/std", "sp-arithmetic/std", + "sp-runtime/std", + "sp-std/std", + "sp-timestamp/std", ] diff --git a/primitives/consensus/slots/src/lib.rs b/primitives/consensus/slots/src/lib.rs index e8ab98399414b..21b3cad1e7167 100644 --- a/primitives/consensus/slots/src/lib.rs +++ b/primitives/consensus/slots/src/lib.rs @@ -21,6 +21,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +use sp_timestamp::Timestamp; /// Unit type wrapper that represents a slot. #[derive(Debug, Encode, MaxEncodedLen, Decode, Eq, Clone, Copy, Default, Ord, TypeInfo)] @@ -64,6 +65,11 @@ impl + Copy> core::cmp::PartialOrd for Slot { } impl Slot { + /// Create a new slot by calculating it from the given timestamp and slot duration. + pub const fn from_timestamp(timestamp: Timestamp, slot_duration: SlotDuration) -> Self { + Slot(timestamp.as_millis() / slot_duration.as_millis()) + } + /// Saturating addition. pub fn saturating_add>(self, rhs: T) -> Self { Self(self.0.saturating_add(rhs.into())) @@ -94,6 +100,32 @@ impl From for u64 { } } +/// A slot duration defined in milliseconds. +#[derive(Clone, Copy, Debug, Encode, Decode, Hash, PartialOrd, Ord, PartialEq, Eq, TypeInfo)] +pub struct SlotDuration(u64); + +impl SlotDuration { + /// Initialize from the given milliseconds. + pub const fn from_millis(millis: u64) -> Self { + Self(millis) + } +} + +impl SlotDuration { + /// Returns `self` as a `u64` representing the duration in milliseconds. + pub const fn as_millis(&self) -> u64 { + self.0 + } +} + +#[cfg(feature = "std")] +impl SlotDuration { + /// Returns `self` as [`sp_std::time::Duration`]. + pub const fn as_duration(&self) -> sp_std::time::Duration { + sp_std::time::Duration::from_millis(self.0) + } +} + /// Represents an equivocation proof. An equivocation happens when a validator /// produces more than one block on the same slot. The proof of equivocation /// are the given distinct headers that were signed by the validator and which diff --git a/primitives/timestamp/src/lib.rs b/primitives/timestamp/src/lib.rs index 76725e28ac825..b98a87c37f69d 100644 --- a/primitives/timestamp/src/lib.rs +++ b/primitives/timestamp/src/lib.rs @@ -42,10 +42,16 @@ impl Timestamp { } /// Returns `self` as [`Duration`]. - pub fn as_duration(self) -> Duration { + pub const fn as_duration(self) -> Duration { Duration::from_millis(self.0) } + /// Returns `self` as a `u64` representing the elapsed time since the UNIX_EPOCH in + /// milliseconds. + pub const fn as_millis(&self) -> u64 { + self.0 + } + /// Checked subtraction that returns `None` on an underflow. pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(Self) From f54e1a2f294c9baa1d8d335c18a7c3e49c47cf6b Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 23 Feb 2022 10:17:47 +0100 Subject: [PATCH 0542/1472] Replace libsecp256k1 with k256 in FRAME related code (#10883) * Replace libsecp256k1 with k256 in beefy-mmr * Port of FRAME `contracts` benchmarking from `libsecp256k1` to `k256` * Newtype to allow `Pcg32` rng usage with `k256` in contracts benchmarks * Use `sp-io::crypto` to generate dummy keys in `contracts` bechmarks * More compact code * Cargo fmt * Build `sp-keystore` only for dev profile * Move public key generation back to the `map` --- Cargo.lock | 146 +++++++++++++++++++++++- Cargo.toml | 1 + frame/beefy-mmr/Cargo.toml | 4 +- frame/beefy-mmr/src/lib.rs | 27 +++-- frame/contracts/Cargo.toml | 4 +- frame/contracts/src/benchmarking/mod.rs | 14 +-- frame/contracts/src/tests.rs | 4 +- 7 files changed, 166 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 517b92c522d4b..73b56aa6a377b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -437,6 +437,12 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +[[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" @@ -474,6 +480,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64ct" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874f8444adcb4952a8bc51305c8be95c8ec8237bb0d2e78d2e039f771f8828a0" + [[package]] name = "beef" version = "0.5.1" @@ -1066,6 +1078,12 @@ dependencies = [ "cache-padded", ] +[[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" @@ -1390,6 +1408,18 @@ 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.2", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.2" @@ -1567,6 +1597,15 @@ dependencies = [ "syn", ] +[[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.16" @@ -1749,6 +1788,17 @@ dependencies = [ "memmap2 0.2.1", ] +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "signature", +] + [[package]] name = "ed25519" version = "1.0.3" @@ -1778,6 +1828,24 @@ 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.2", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "enum-as-inner" version = "0.3.3" @@ -1939,6 +2007,16 @@ dependencies = [ "libc", ] +[[package]] +name = "ff" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2958d04124b9f27f175eaeb9a9f383d026098aa837eadd8ba22c11f13a05b9e" +dependencies = [ + "rand_core 0.6.2", + "subtle", +] + [[package]] name = "file-per-thread-logger" version = "0.1.4" @@ -2619,6 +2697,17 @@ dependencies = [ "web-sys", ] +[[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.2", + "subtle", +] + [[package]] name = "h2" version = "0.3.9" @@ -3403,6 +3492,18 @@ dependencies = [ "jsonrpsee-types 0.8.0", ] +[[package]] +name = "k256" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cc5937366afd3b38071f400d1ce5bd8b1d40b5083cc14e6f8dbcc4032a7f5bb" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "sec1", +] + [[package]] name = "keccak" version = "0.1.0" @@ -5523,7 +5624,7 @@ dependencies = [ "frame-system", "hex", "hex-literal", - "libsecp256k1", + "k256", "log 0.4.14", "pallet-beefy", "pallet-mmr", @@ -5603,7 +5704,6 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", - "libsecp256k1", "log 0.4.14", "pallet-balances", "pallet-contracts-primitives", @@ -5620,6 +5720,7 @@ dependencies = [ "smallvec 1.7.0", "sp-core", "sp-io", + "sp-keystore", "sp-runtime", "sp-sandbox", "sp-std", @@ -6865,6 +6966,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] + [[package]] name = "pkg-config" version = "0.3.19" @@ -9027,6 +9139,19 @@ dependencies = [ "untrusted", ] +[[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", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -9285,9 +9410,12 @@ dependencies = [ [[package]] name = "signature" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0242b8e50dd9accdd56170e94ca1ebd223b098eb9c83539a6e367d0f36ae68" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "rand_core 0.6.2", +] [[package]] name = "simba" @@ -10226,6 +10354,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "ss58-registry" version = "1.11.0" diff --git a/Cargo.toml b/Cargo.toml index a31d8011a9f44..d919fc4805631 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -250,6 +250,7 @@ hash-db = { opt-level = 3 } hmac = { opt-level = 3 } httparse = { opt-level = 3 } integer-sqrt = { opt-level = 3 } +k256 = { opt-level = 3 } keccak = { opt-level = 3 } libm = { opt-level = 3 } librocksdb-sys = { opt-level = 3 } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index f381d4c975776..bb30c540ca1c8 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/paritytech/substrate" [dependencies] hex = { version = "0.4", optional = true } codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } -libsecp256k1 = { version = "0.7.0", default-features = false } +k256 = { version = "0.10.2", default-features = false, features = ["arithmetic"] } log = { version = "0.4.13", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } @@ -43,7 +43,7 @@ std = [ "frame-support/std", "frame-system/std", "hex", - "libsecp256k1/std", + "k256/std", "log/std", "pallet-beefy/std", "pallet-mmr-primitives/std", diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 38d0a6ac9a7f8..476589717e06c 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -72,21 +72,20 @@ where pub struct BeefyEcdsaToEthereum; impl Convert> for BeefyEcdsaToEthereum { fn convert(a: beefy_primitives::crypto::AuthorityId) -> Vec { + use k256::{elliptic_curve::sec1::ToEncodedPoint, PublicKey}; use sp_core::crypto::ByteArray; - let compressed_key = a.as_slice(); - - libsecp256k1::PublicKey::parse_slice( - compressed_key, - Some(libsecp256k1::PublicKeyFormat::Compressed), - ) - // uncompress the key - .map(|pub_key| pub_key.serialize().to_vec()) - // now convert to ETH address - .map(|uncompressed| sp_io::hashing::keccak_256(&uncompressed[1..])[12..].to_vec()) - .map_err(|_| { - log::error!(target: "runtime::beefy", "Invalid BEEFY PublicKey format!"); - }) - .unwrap_or_default() + + PublicKey::from_sec1_bytes(a.as_slice()) + .map(|pub_key| { + // uncompress the key + let uncompressed = pub_key.to_encoded_point(false); + // convert to ETH address + sp_io::hashing::keccak_256(&uncompressed.as_bytes()[1..])[12..].to_vec() + }) + .map_err(|_| { + log::error!(target: "runtime::beefy", "Invalid BEEFY PublicKey format!"); + }) + .unwrap_or_default() } } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index f24e393daa2ee..5ab1389f65c1a 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -28,7 +28,6 @@ smallvec = { version = "1", default-features = false, features = [ wasmi-validation = { version = "0.4", default-features = false } # Only used in benchmarking to generate random contract code -libsecp256k1 = { version = "0.7", optional = true, default-features = false, features = ["hmac", "static-context"] } rand = { version = "0.8", optional = true, default-features = false } rand_pcg = { version = "0.3", optional = true } @@ -56,6 +55,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } pallet-randomness-collective-flip = { version = "4.0.0-dev", path = "../randomness-collective-flip" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } [features] default = ["std"] @@ -77,11 +77,9 @@ std = [ "pallet-contracts-proc-macro/full", "log/std", "rand/std", - "libsecp256k1/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", - "libsecp256k1", "rand", "rand_pcg", "unstable-interface", diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index f5200eef567b9..129b4a62581cc 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1866,20 +1866,14 @@ benchmarks! { // It generates different private keys and signatures for the message "Hello world". seal_ecdsa_recover { let r in 0 .. API_BENCHMARK_BATCHES; - use rand::SeedableRng; - let mut rng = rand_pcg::Pcg32::seed_from_u64(123456); let message_hash = sp_io::hashing::blake2_256("Hello world".as_bytes()); + let key_type = sp_core::crypto::KeyTypeId(*b"code"); let signatures = (0..r * API_BENCHMARK_BATCH_SIZE) .map(|i| { - use libsecp256k1::{SecretKey, Message, sign}; - - let private_key = SecretKey::random(&mut rng); - let (signature, recovery_id) = sign(&Message::parse(&message_hash), &private_key); - let mut full_signature = [0; 65]; - full_signature[..64].copy_from_slice(&signature.serialize()); - full_signature[64] = recovery_id.serialize(); - full_signature + let pub_key = sp_io::crypto::ecdsa_generate(key_type, None); + let sig = sp_io::crypto::ecdsa_sign_prehashed(key_type, &pub_key, &message_hash).expect("Generates signature"); + AsRef::<[u8; 65]>::as_ref(&sig).to_vec() }) .collect::>(); let signatures = signatures.iter().flatten().cloned().collect::>(); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index cdcf41704347e..8add424db0892 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -43,12 +43,13 @@ use frame_system::{self as system, EventRecord, Phase}; use pretty_assertions::assert_eq; use sp_core::Bytes; use sp_io::hashing::blake2_256; +use sp_keystore::{testing::KeyStore, KeystoreExt}; use sp_runtime::{ testing::{Header, H256}, traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, AccountId32, }; -use std::cell::RefCell; +use std::{cell::RefCell, sync::Arc}; use crate as pallet_contracts; @@ -328,6 +329,7 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); let mut ext = sp_io::TestExternalities::new(t); + ext.register_extension(KeystoreExt(Arc::new(KeyStore::new()))); ext.execute_with(|| System::set_block_number(1)); ext } From b4ba44d21d9e0a5c15013f60e34daf97e70c5865 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 23 Feb 2022 19:58:33 +0100 Subject: [PATCH 0543/1472] Clean obsolete BABE's weight data (#10748) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Clean obsolete BABE weight data * Take out test assertion from check closure * Optimize metadata access using `HeaderMetadata` trait * Apply suggestions from code review * Introduce finalize and import pre-commit synchronous actions * Do not hold locks between internal methods calls * Remove unused generic bound * Apply suggestions from code review * Register BABE's pre-commit actions on `block_import` instead of `start_babe` * PreCommit actions should be `Fn` instead of `FnMut` * More robust safenet in case of malformed finality notifications Co-authored-by: Bastian Köcher Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- client/api/src/backend.rs | 2 + client/api/src/client.rs | 55 +++++++- client/consensus/babe/src/lib.rs | 105 +++++++++++++-- client/consensus/babe/src/tests.rs | 132 ++++++++++++++----- client/service/src/client/client.rs | 129 +++++++++++------- primitives/blockchain/src/header_metadata.rs | 2 +- 6 files changed, 330 insertions(+), 95 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index bb2579e4a420e..e96616d5416e6 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -75,6 +75,8 @@ pub struct ImportSummary { /// Contains information about the block that just got finalized, /// including tree heads that became stale at the moment of finalization. pub struct FinalizeSummary { + /// Last finalized block header. + pub header: Block::Header, /// Blocks that were finalized. /// The last entry is the one that has been explicitly finalized. pub finalized: Vec, diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 9bb212099565b..949cc42c1c04b 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -27,7 +27,8 @@ use sp_runtime::{ }; use std::{collections::HashSet, convert::TryFrom, fmt, sync::Arc}; -use crate::{blockchain::Info, notifications::StorageEventStream}; +use crate::{blockchain::Info, notifications::StorageEventStream, FinalizeSummary, ImportSummary}; + use sc_transaction_pool_api::ChainEvent; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain; @@ -76,6 +77,34 @@ pub trait BlockchainEvents { ) -> sp_blockchain::Result>; } +/// List of operations to be performed on storage aux data. +/// First tuple element is the encoded data key. +/// Second tuple element is the encoded optional data to write. +/// If `None`, the key and the associated data are deleted from storage. +pub type AuxDataOperations = Vec<(Vec, Option>)>; + +/// Callback invoked before committing the operations created during block import. +/// This gives the opportunity to perform auxiliary pre-commit actions and optionally +/// enqueue further storage write operations to be atomically performed on commit. +pub type OnImportAction = + Box) -> AuxDataOperations) + Send>; + +/// Callback invoked before committing the operations created during block finalization. +/// This gives the opportunity to perform auxiliary pre-commit actions and optionally +/// enqueue further storage write operations to be atomically performed on commit. +pub type OnFinalityAction = + Box) -> AuxDataOperations) + Send>; + +/// Interface to perform auxiliary actions before committing a block import or +/// finality operation. +pub trait PreCommitActions { + /// Actions to be performed on block import. + fn register_import_action(&self, op: OnImportAction); + + /// Actions to be performed on block finalization. + fn register_finality_action(&self, op: OnFinalityAction); +} + /// Interface for fetching block data. pub trait BlockBackend { /// Get block body by ID. Returns `None` if the body is not stored. @@ -300,3 +329,27 @@ impl From> for ChainEvent { Self::Finalized { hash: n.hash, tree_route: n.tree_route } } } + +impl From> for FinalityNotification { + fn from(mut summary: FinalizeSummary) -> Self { + let hash = summary.finalized.pop().unwrap_or_default(); + FinalityNotification { + hash, + header: summary.header, + tree_route: Arc::new(summary.finalized), + stale_heads: Arc::new(summary.stale_heads), + } + } +} + +impl From> for BlockImportNotification { + fn from(summary: ImportSummary) -> Self { + BlockImportNotification { + hash: summary.hash, + origin: summary.origin, + header: summary.header, + is_new_best: summary.is_new_best, + tree_route: summary.tree_route.map(Arc::new), + } + } +} diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 78fe506dbf341..0e9f943eca307 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -66,7 +66,16 @@ #![forbid(unsafe_code)] #![warn(missing_docs)] -use std::{borrow::Cow, collections::HashMap, convert::TryInto, pin::Pin, sync::Arc, u64}; +use std::{ + borrow::Cow, + collections::{HashMap, HashSet}, + convert::TryInto, + future::Future, + pin::Pin, + sync::Arc, + task::{Context, Poll}, + time::Duration, +}; use codec::{Decode, Encode}; use futures::{ @@ -82,7 +91,10 @@ use prometheus_endpoint::Registry; use retain_mut::RetainMut; use schnorrkel::SignatureError; -use sc_client_api::{backend::AuxStore, BlockchainEvents, ProvideUncles, UsageProvider}; +use sc_client_api::{ + backend::AuxStore, AuxDataOperations, BlockchainEvents, FinalityNotification, PreCommitActions, + ProvideUncles, UsageProvider, +}; use sc_consensus::{ block_import::{ BlockCheckParams, BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, @@ -98,7 +110,7 @@ use sc_consensus_slots::{ SlotInfo, StorageChanges, }; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_TRACE}; -use sp_api::{ApiExt, NumberFor, ProvideRuntimeApi}; +use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_application_crypto::AppKey; use sp_block_builder::BlockBuilder as BlockBuilderApi; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult}; @@ -113,7 +125,7 @@ use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvid use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::{BlockId, OpaqueDigestItemId}, - traits::{Block as BlockT, Header, Zero}, + traits::{Block as BlockT, Header, NumberFor, One, SaturatedConversion, Saturating, Zero}, DigestItem, }; @@ -458,6 +470,7 @@ where C: ProvideRuntimeApi + ProvideUncles + BlockchainEvents + + PreCommitActions + HeaderBackend + HeaderMetadata + Send @@ -501,7 +514,8 @@ where }; info!(target: "babe", "👶 Starting BABE Authorship worker"); - let inner = sc_consensus_slots::start_slot_worker( + + let slot_worker = sc_consensus_slots::start_slot_worker( babe_link.config.slot_duration(), select_chain, worker, @@ -515,13 +529,69 @@ where let answer_requests = answer_requests(worker_rx, babe_link.config, client, babe_link.epoch_changes.clone()); + let inner = future::select(Box::pin(slot_worker), Box::pin(answer_requests)); Ok(BabeWorker { - inner: Box::pin(future::join(inner, answer_requests).map(|_| ())), + inner: Box::pin(inner.map(|_| ())), slot_notification_sinks, handle: BabeWorkerHandle(worker_tx), }) } +// Remove obsolete block's weight data by leveraging finality notifications. +// This includes data for all finalized blocks (excluding the most recent one) +// and all stale branches. +fn aux_storage_cleanup, Block: BlockT>( + client: &C, + notification: &FinalityNotification, +) -> AuxDataOperations { + let mut aux_keys = HashSet::new(); + + // Cleans data for finalized block's ancestors down to, and including, the previously + // finalized one. + + let first_new_finalized = notification.tree_route.get(0).unwrap_or(¬ification.hash); + match client.header_metadata(*first_new_finalized) { + Ok(meta) => { + aux_keys.insert(aux_schema::block_weight_key(meta.parent)); + }, + Err(err) => { + warn!(target: "babe", "header lookup fail while cleaning data for block {}: {}", first_new_finalized.to_string(), err.to_string()); + }, + } + + aux_keys.extend(notification.tree_route.iter().map(aux_schema::block_weight_key)); + + // Cleans data for stale branches. + + // A safenet in case of malformed notification. + let height_limit = notification.header.number().saturating_sub( + notification.tree_route.len().saturated_into::>() + One::one(), + ); + for head in notification.stale_heads.iter() { + let mut hash = *head; + // Insert stale blocks hashes until canonical chain is not reached. + // Soon or late we should hit an element already present within the `aux_keys` set. + while aux_keys.insert(aux_schema::block_weight_key(hash)) { + match client.header_metadata(hash) { + Ok(meta) => { + // This should never happen and must be considered a bug. + if meta.number <= height_limit { + warn!(target: "babe", "unexpected canonical chain state or malformed finality notification"); + break + } + hash = meta.parent; + }, + Err(err) => { + warn!(target: "babe", "header lookup fail while cleaning data for block {}: {}", head.to_string(), err.to_string()); + break + }, + } + } + } + + aux_keys.into_iter().map(|val| (val, None)).collect() +} + async fn answer_requests( mut request_rx: Receiver>, config: Config, @@ -604,7 +674,7 @@ impl BabeWorkerHandle { /// Worker for Babe which implements `Future`. This must be polled. #[must_use] pub struct BabeWorker { - inner: Pin + Send + 'static>>, + inner: Pin + Send + 'static>>, slot_notification_sinks: SlotNotificationSinks, handle: BabeWorkerHandle, } @@ -628,13 +698,10 @@ impl BabeWorker { } } -impl futures::Future for BabeWorker { +impl Future for BabeWorker { type Output = (); - fn poll( - mut self: Pin<&mut Self>, - cx: &mut futures::task::Context, - ) -> futures::task::Poll { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { self.inner.as_mut().poll(cx) } } @@ -857,7 +924,7 @@ where self.telemetry.clone() } - fn proposing_remaining_duration(&self, slot_info: &SlotInfo) -> std::time::Duration { + fn proposing_remaining_duration(&self, slot_info: &SlotInfo) -> Duration { let parent_slot = find_pre_digest::(&slot_info.chain_head).ok().map(|d| d.slot()); sc_consensus_slots::proposing_remaining_duration( @@ -1683,7 +1750,11 @@ pub fn block_import( client: Arc, ) -> ClientResult<(BabeBlockImport, BabeLink)> where - Client: AuxStore + HeaderBackend + HeaderMetadata, + Client: AuxStore + + HeaderBackend + + HeaderMetadata + + PreCommitActions + + 'static, { let epoch_changes = aux_schema::load_epoch_changes::(&*client, &config.genesis_config)?; @@ -1694,6 +1765,12 @@ where // startup rather than waiting until importing the next epoch change block. prune_finalized(client.clone(), &mut epoch_changes.shared_data())?; + let client_clone = client.clone(); + let on_finality = move |summary: &FinalityNotification| { + aux_storage_cleanup(client_clone.as_ref(), summary) + }; + client.register_finality_action(Box::new(on_finality)); + let import = BabeBlockImport::new(client, epoch_changes, wrapped_block_import, config); Ok((import, link)) diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index d38d57b84f5e1..d2de05bc91952 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -28,7 +28,7 @@ use log::debug; use rand::RngCore; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; -use sc_client_api::{backend::TransactionFor, BlockchainEvents}; +use sc_client_api::{backend::TransactionFor, BlockchainEvents, Finalizer}; use sc_consensus::{BoxBlockImport, BoxJustificationImport}; use sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging; use sc_keystore::LocalKeystore; @@ -608,8 +608,8 @@ fn propose_and_import_block( slot: Option, proposer_factory: &mut DummyFactory, block_import: &mut BoxBlockImport, -) -> sp_core::H256 { - let mut proposer = futures::executor::block_on(proposer_factory.init(parent)).unwrap(); +) -> Hash { + let mut proposer = block_on(proposer_factory.init(parent)).unwrap(); let slot = slot.unwrap_or_else(|| { let parent_pre_digest = find_pre_digest::(parent).unwrap(); @@ -625,7 +625,7 @@ fn propose_and_import_block( let parent_hash = parent.hash(); - let mut block = futures::executor::block_on(proposer.propose_with(pre_digest)).unwrap().block; + let mut block = block_on(proposer.propose_with(pre_digest)).unwrap().block; let epoch_descriptor = proposer_factory .epoch_changes @@ -673,6 +673,29 @@ fn propose_and_import_block( post_hash } +// Propose and import n valid BABE blocks that are built on top of the given parent. +// The proposer takes care of producing epoch change digests according to the epoch +// duration (which is set to 6 slots in the test runtime). +fn propose_and_import_blocks( + client: &PeersFullClient, + proposer_factory: &mut DummyFactory, + block_import: &mut BoxBlockImport, + parent_id: BlockId, + n: usize, +) -> Vec { + let mut hashes = Vec::with_capacity(n); + let mut parent_header = client.header(&parent_id).unwrap().unwrap(); + + for _ in 0..n { + let block_hash = + propose_and_import_block(&parent_header, None, proposer_factory, block_import); + hashes.push(block_hash); + parent_header = client.header(&BlockId::Hash(block_hash)).unwrap().unwrap(); + } + + hashes +} + #[test] fn importing_block_one_sets_genesis_epoch() { let mut net = BabeTestNet::new(1); @@ -714,8 +737,6 @@ fn importing_block_one_sets_genesis_epoch() { #[test] fn importing_epoch_change_block_prunes_tree() { - use sc_client_api::Finalizer; - let mut net = BabeTestNet::new(1); let peer = net.peer(0); @@ -732,26 +753,8 @@ fn importing_epoch_change_block_prunes_tree() { mutator: Arc::new(|_, _| ()), }; - // This is just boilerplate code for proposing and importing n valid BABE - // blocks that are built on top of the given parent. The proposer takes care - // of producing epoch change digests according to the epoch duration (which - // is set to 6 slots in the test runtime). - let mut propose_and_import_blocks = |parent_id, n| { - let mut hashes = Vec::new(); - let mut parent_header = client.header(&parent_id).unwrap().unwrap(); - - for _ in 0..n { - let block_hash = propose_and_import_block( - &parent_header, - None, - &mut proposer_factory, - &mut block_import, - ); - hashes.push(block_hash); - parent_header = client.header(&BlockId::Hash(block_hash)).unwrap().unwrap(); - } - - hashes + let mut propose_and_import_blocks_wrap = |parent_id, n| { + propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, parent_id, n) }; // This is the block tree that we're going to use in this test. Each node @@ -766,12 +769,12 @@ fn importing_epoch_change_block_prunes_tree() { // Create and import the canon chain and keep track of fork blocks (A, C, D) // from the diagram above. - let canon_hashes = propose_and_import_blocks(BlockId::Number(0), 30); + let canon_hashes = propose_and_import_blocks_wrap(BlockId::Number(0), 30); // Create the forks - let fork_1 = propose_and_import_blocks(BlockId::Hash(canon_hashes[0]), 10); - let fork_2 = propose_and_import_blocks(BlockId::Hash(canon_hashes[12]), 15); - let fork_3 = propose_and_import_blocks(BlockId::Hash(canon_hashes[18]), 10); + let fork_1 = propose_and_import_blocks_wrap(BlockId::Hash(canon_hashes[0]), 10); + let fork_2 = propose_and_import_blocks_wrap(BlockId::Hash(canon_hashes[12]), 15); + let fork_3 = propose_and_import_blocks_wrap(BlockId::Hash(canon_hashes[18]), 10); // We should be tracking a total of 9 epochs in the fork tree assert_eq!(epoch_changes.shared_data().tree().iter().count(), 9); @@ -782,7 +785,7 @@ fn importing_epoch_change_block_prunes_tree() { // We finalize block #13 from the canon chain, so on the next epoch // change the tree should be pruned, to not contain F (#7). client.finalize_block(BlockId::Hash(canon_hashes[12]), None, false).unwrap(); - propose_and_import_blocks(BlockId::Hash(client.chain_info().best_hash), 7); + propose_and_import_blocks_wrap(BlockId::Hash(client.chain_info().best_hash), 7); // at this point no hashes from the first fork must exist on the tree assert!(!epoch_changes @@ -809,7 +812,7 @@ fn importing_epoch_change_block_prunes_tree() { // finalizing block #25 from the canon chain should prune out the second fork client.finalize_block(BlockId::Hash(canon_hashes[24]), None, false).unwrap(); - propose_and_import_blocks(BlockId::Hash(client.chain_info().best_hash), 8); + propose_and_import_blocks_wrap(BlockId::Hash(client.chain_info().best_hash), 8); // at this point no hashes from the second fork must exist on the tree assert!(!epoch_changes @@ -894,3 +897,68 @@ fn babe_transcript_generation_match() { }; debug_assert!(test(orig_transcript) == test(transcript_from_data(new_transcript))); } + +#[test] +fn obsolete_blocks_aux_data_cleanup() { + let mut net = BabeTestNet::new(1); + + let peer = net.peer(0); + let data = peer.data.as_ref().expect("babe link set up during initialization"); + let client = peer.client().as_client(); + + // Register the handler (as done by `babe_start`) + let client_clone = client.clone(); + let on_finality = move |summary: &FinalityNotification| { + aux_storage_cleanup(client_clone.as_ref(), summary) + }; + client.register_finality_action(Box::new(on_finality)); + + let mut proposer_factory = DummyFactory { + client: client.clone(), + config: data.link.config.clone(), + epoch_changes: data.link.epoch_changes.clone(), + mutator: Arc::new(|_, _| ()), + }; + + let mut block_import = data.block_import.lock().take().expect("import set up during init"); + + let mut propose_and_import_blocks_wrap = |parent_id, n| { + propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, parent_id, n) + }; + + let aux_data_check = |hashes: &[Hash], expected: bool| { + hashes.iter().all(|hash| { + aux_schema::load_block_weight(&*peer.client().as_backend(), hash) + .unwrap() + .is_some() == expected + }) + }; + + // Create the following test scenario: + // + // /-----B3 --- B4 ( < fork2 ) + // G --- A1 --- A2 --- A3 --- A4 ( < fork1 ) + // \-----C4 --- C5 ( < fork3 ) + + let fork1_hashes = propose_and_import_blocks_wrap(BlockId::Number(0), 4); + let fork2_hashes = propose_and_import_blocks_wrap(BlockId::Number(2), 2); + let fork3_hashes = propose_and_import_blocks_wrap(BlockId::Number(3), 2); + + // Check that aux data is present for all but the genesis block. + assert!(aux_data_check(&[client.chain_info().genesis_hash], false)); + assert!(aux_data_check(&fork1_hashes, true)); + assert!(aux_data_check(&fork2_hashes, true)); + assert!(aux_data_check(&fork3_hashes, true)); + + // Finalize A3 + client.finalize_block(BlockId::Number(3), None, true).unwrap(); + + // Wiped: A1, A2 + assert!(aux_data_check(&fork1_hashes[..2], false)); + // Present: A3, A4 + assert!(aux_data_check(&fork1_hashes[2..], true)); + // Wiped: B3, B4 + assert!(aux_data_check(&fork2_hashes, false)); + // Present C4, C5 + assert!(aux_data_check(&fork3_hashes, true)); +} diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 071af36a23f96..8497c34f5abbb 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -36,11 +36,12 @@ use sc_client_api::{ client::{ BadBlocks, BlockBackend, BlockImportNotification, BlockOf, BlockchainEvents, ClientInfo, FinalityNotification, FinalityNotifications, ForkBlocks, ImportNotifications, - ProvideUncles, + PreCommitActions, ProvideUncles, }, execution_extensions::ExecutionExtensions, notifications::{StorageEventStream, StorageNotifications}, - CallExecutor, ExecutorProvider, KeyIterator, ProofProvider, UsageProvider, + CallExecutor, ExecutorProvider, KeyIterator, OnFinalityAction, OnImportAction, ProofProvider, + UsageProvider, }; use sc_consensus::{ BlockCheckParams, BlockImportParams, ForkChoiceStrategy, ImportResult, StateAction, @@ -76,8 +77,9 @@ use sp_runtime::{ }; use sp_state_machine::{ prove_child_read, prove_range_read_with_child_with_size, prove_read, - read_range_proof_check_with_child_on_proving_backend, Backend as StateBackend, KeyValueStates, - KeyValueStorageLevel, MAX_NESTED_TRIE_DEPTH, + read_range_proof_check_with_child_on_proving_backend, Backend as StateBackend, + ChildStorageCollection, KeyValueStates, KeyValueStorageLevel, StorageCollection, + MAX_NESTED_TRIE_DEPTH, }; use sp_trie::{CompactProof, StorageProof}; use std::{ @@ -108,7 +110,13 @@ where storage_notifications: Mutex>, import_notification_sinks: NotificationSinks>, finality_notification_sinks: NotificationSinks>, - // holds the block hash currently being imported. TODO: replace this with block queue + // Collects auxiliary operations to be performed atomically together with + // block import operations. + import_actions: Mutex>>, + // Collects auxiliary operations to be performed atomically together with + // block finalization operations. + finality_actions: Mutex>>, + // Holds the block hash currently being imported. TODO: replace this with block queue. importing_block: RwLock>, block_rules: BlockRules, execution_extensions: ExecutionExtensions, @@ -279,11 +287,32 @@ where let r = f(&mut op)?; - let ClientImportOperation { op, notify_imported, notify_finalized } = op; + let ClientImportOperation { mut op, notify_imported, notify_finalized } = op; + + let finality_notification = notify_finalized.map(|summary| summary.into()); + let (import_notification, storage_changes) = match notify_imported { + Some(mut summary) => { + let storage_changes = summary.storage_changes.take(); + (Some(summary.into()), storage_changes) + }, + None => (None, None), + }; + + if let Some(ref notification) = finality_notification { + for action in self.finality_actions.lock().iter_mut() { + op.insert_aux(action(notification))?; + } + } + if let Some(ref notification) = import_notification { + for action in self.import_actions.lock().iter_mut() { + op.insert_aux(action(notification))?; + } + } + self.backend.commit_operation(op)?; - self.notify_finalized(notify_finalized)?; - self.notify_imported(notify_imported)?; + self.notify_finalized(finality_notification)?; + self.notify_imported(import_notification, storage_changes)?; Ok(r) }; @@ -367,6 +396,8 @@ where storage_notifications: Mutex::new(StorageNotifications::new(prometheus_registry)), import_notification_sinks: Default::default(), finality_notification_sinks: Default::default(), + import_actions: Default::default(), + finality_actions: Default::default(), importing_block: Default::default(), block_rules: BlockRules::new(fork_blocks, bad_blocks), execution_extensions, @@ -686,12 +717,21 @@ where // We only notify when we are already synced to the tip of the chain // or if this import triggers a re-org if make_notifications || tree_route.is_some() { + let header = import_headers.into_post(); if finalized { let mut summary = match operation.notify_finalized.take() { - Some(summary) => summary, - None => FinalizeSummary { finalized: Vec::new(), stale_heads: Vec::new() }, + Some(mut summary) => { + summary.header = header.clone(); + summary.finalized.push(hash); + summary + }, + None => FinalizeSummary { + header: header.clone(), + finalized: vec![hash], + stale_heads: Vec::new(), + }, }; - summary.finalized.push(hash); + if parent_exists { // Add to the stale list all heads that are branching from parent besides our // current `head`. @@ -718,7 +758,7 @@ where operation.notify_imported = Some(ImportSummary { hash, origin, - header: import_headers.into_post(), + header, is_new_best, storage_changes, tree_route, @@ -863,7 +903,7 @@ where .backend .blockchain() .number(last_finalized)? - .expect("Finalized block expected to be onchain; qed"); + .expect("Previous finalized block expected to be onchain; qed"); let mut stale_heads = Vec::new(); for head in self.backend.blockchain().leaves()? { let route_from_finalized = @@ -884,7 +924,12 @@ where stale_heads.push(head); } } - operation.notify_finalized = Some(FinalizeSummary { finalized, stale_heads }); + let header = self + .backend + .blockchain() + .header(BlockId::Hash(block))? + .expect("Finalized block expected to be onchain; qed"); + operation.notify_finalized = Some(FinalizeSummary { header, finalized, stale_heads }); } Ok(()) @@ -892,11 +937,11 @@ where fn notify_finalized( &self, - notify_finalized: Option>, + notification: Option>, ) -> sp_blockchain::Result<()> { let mut sinks = self.finality_notification_sinks.lock(); - let mut notify_finalized = match notify_finalized { + let notification = match notification { Some(notify_finalized) => notify_finalized, None => { // Cleanup any closed finality notification sinks @@ -907,30 +952,14 @@ where }, }; - let last = notify_finalized.finalized.pop().expect( - "At least one finalized block shall exist within a valid finalization summary; qed", - ); - - let header = self.header(&BlockId::Hash(last))?.expect( - "Header already known to exist in DB because it is indicated in the tree route; \ - qed", - ); - telemetry!( self.telemetry; SUBSTRATE_INFO; "notify.finalized"; - "height" => format!("{}", header.number()), - "best" => ?last, + "height" => format!("{}", notification.header.number()), + "best" => ?notification.hash, ); - let notification = FinalityNotification { - hash: last, - header, - tree_route: Arc::new(notify_finalized.finalized), - stale_heads: Arc::new(notify_finalized.stale_heads), - }; - sinks.retain(|sink| sink.unbounded_send(notification.clone()).is_ok()); Ok(()) @@ -938,12 +967,13 @@ where fn notify_imported( &self, - notify_import: Option>, + notification: Option>, + storage_changes: Option<(StorageCollection, ChildStorageCollection)>, ) -> sp_blockchain::Result<()> { - let notify_import = match notify_import { + let notification = match notification { Some(notify_import) => notify_import, None => { - // cleanup any closed import notification sinks since we won't + // Cleanup any closed import notification sinks since we won't // be sending any notifications below which would remove any // closed sinks. this is necessary since during initial sync we // won't send any import notifications which could lead to a @@ -954,23 +984,15 @@ where }, }; - if let Some(storage_changes) = notify_import.storage_changes { + if let Some(storage_changes) = storage_changes { // TODO [ToDr] How to handle re-orgs? Should we re-emit all storage changes? self.storage_notifications.lock().trigger( - ¬ify_import.hash, + ¬ification.hash, storage_changes.0.into_iter(), storage_changes.1.into_iter().map(|(sk, v)| (sk, v.into_iter())), ); } - let notification = BlockImportNotification:: { - hash: notify_import.hash, - origin: notify_import.origin, - header: notify_import.header, - is_new_best: notify_import.is_new_best, - tree_route: notify_import.tree_route.map(Arc::new), - }; - self.import_notification_sinks .lock() .retain(|sink| sink.unbounded_send(notification.clone()).is_ok()); @@ -1892,6 +1914,19 @@ where } } +impl PreCommitActions for Client +where + Block: BlockT, +{ + fn register_import_action(&self, action: OnImportAction) { + self.import_actions.lock().push(action); + } + + fn register_finality_action(&self, action: OnFinalityAction) { + self.finality_actions.lock().push(action); + } +} + impl BlockchainEvents for Client where E: CallExecutor, diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index 6e8dc562473d8..c21c82b9fbc23 100644 --- a/primitives/blockchain/src/header_metadata.rs +++ b/primitives/blockchain/src/header_metadata.rs @@ -206,7 +206,7 @@ impl TreeRoute { /// Handles header metadata: hash, number, parent hash, etc. pub trait HeaderMetadata { /// Error used in case the header metadata is not found. - type Error; + type Error: std::error::Error; fn header_metadata( &self, From c48f33d16edc44e12be0b54d66459da430a6d8ff Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 23 Feb 2022 20:58:53 +0100 Subject: [PATCH 0544/1472] Factor DB weights out into their own files (#10908) * Factor DB weights out into their own files Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Fix CI Signed-off-by: Oliver Tale-Yazdi * Weights in own mod Signed-off-by: Oliver Tale-Yazdi --- frame/support/src/weights.rs | 22 +++---- frame/support/src/weights/paritydb_weights.rs | 63 +++++++++++++++++++ frame/support/src/weights/rocksdb_weights.rs | 63 +++++++++++++++++++ 3 files changed, 135 insertions(+), 13 deletions(-) create mode 100644 frame/support/src/weights/paritydb_weights.rs create mode 100644 frame/support/src/weights/rocksdb_weights.rs diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index 65087c85d3265..6c2e693eb476e 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -127,6 +127,9 @@ //! - Ubuntu 19.10 (GNU/Linux 5.3.0-18-generic x86_64) //! - rustc 1.42.0 (b8cedc004 2020-03-09) +mod paritydb_weights; +mod rocksdb_weights; + use crate::dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo}; use codec::{Decode, Encode}; use scale_info::TypeInfo; @@ -152,7 +155,7 @@ pub type Weight = u64; /// These constants are specific to FRAME, and the current implementation of its various components. /// For example: FRAME System, FRAME Executive, our FRAME support libraries, etc... pub mod constants { - use super::{RuntimeDbWeight, Weight}; + use super::Weight; use crate::parameter_types; pub const WEIGHT_PER_SECOND: Weight = 1_000_000_000_000; @@ -165,19 +168,12 @@ pub mod constants { pub const BlockExecutionWeight: Weight = 5 * WEIGHT_PER_MILLIS; /// Executing 10,000 System remarks (no-op) txs takes ~1.26 seconds -> ~125 µs per tx pub const ExtrinsicBaseWeight: Weight = 125 * WEIGHT_PER_MICROS; - /// By default, Substrate uses RocksDB, so this will be the weight used throughout - /// the runtime. - pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 25 * WEIGHT_PER_MICROS, // ~25 µs @ 200,000 items - write: 100 * WEIGHT_PER_MICROS, // ~100 µs @ 200,000 items - }; - /// ParityDB can be enabled with a feature flag, but is still experimental. These weights - /// are available for brave runtime engineers who may want to try this out as default. - pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 8 * WEIGHT_PER_MICROS, // ~8 µs @ 200,000 items - write: 50 * WEIGHT_PER_MICROS, // ~50 µs @ 200,000 items - }; } + + // Expose the DB weights. + pub use super::{ + paritydb_weights::constants::ParityDbWeight, rocksdb_weights::constants::RocksDbWeight, + }; } /// Means of weighing some particular kind of data (`T`). diff --git a/frame/support/src/weights/paritydb_weights.rs b/frame/support/src/weights/paritydb_weights.rs new file mode 100644 index 0000000000000..572187ba78a92 --- /dev/null +++ b/frame/support/src/weights/paritydb_weights.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod constants { + use frame_support::{ + parameter_types, + weights::{constants, RuntimeDbWeight}, + }; + + parameter_types! { + /// ParityDB can be enabled with a feature flag, but is still experimental. These weights + /// are available for brave runtime engineers who may want to try this out as default. + pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 8_000 * constants::WEIGHT_PER_NANOS, + write: 50_000 * constants::WEIGHT_PER_NANOS, + }; + } + + #[cfg(test)] + mod test_db_weights { + use super::constants::ParityDbWeight as W; + use frame_support::weights::constants; + + /// Checks that all weights exist and have sane values. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + // At least 1 µs. + assert!( + W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + "Read weight should be at least 1 µs." + ); + assert!( + W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + "Write weight should be at least 1 µs." + ); + // At most 1 ms. + assert!( + W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + "Read weight should be at most 1 ms." + ); + assert!( + W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + "Write weight should be at most 1 ms." + ); + } + } +} diff --git a/frame/support/src/weights/rocksdb_weights.rs b/frame/support/src/weights/rocksdb_weights.rs new file mode 100644 index 0000000000000..f37964dcbd825 --- /dev/null +++ b/frame/support/src/weights/rocksdb_weights.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod constants { + use frame_support::{ + parameter_types, + weights::{constants, RuntimeDbWeight}, + }; + + parameter_types! { + /// By default, Substrate uses RocksDB, so this will be the weight used throughout + /// the runtime. + pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 25_000 * constants::WEIGHT_PER_NANOS, + write: 100_000 * constants::WEIGHT_PER_NANOS, + }; + } + + #[cfg(test)] + mod test_db_weights { + use super::constants::RocksDbWeight as W; + use frame_support::weights::constants; + + /// Checks that all weights exist and have sane values. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + // At least 1 µs. + assert!( + W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + "Read weight should be at least 1 µs." + ); + assert!( + W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + "Write weight should be at least 1 µs." + ); + // At most 1 ms. + assert!( + W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + "Read weight should be at most 1 ms." + ); + assert!( + W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + "Write weight should be at most 1 ms." + ); + } + } +} From 19460bc5263994321a595f6e35501882cdba6f05 Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 24 Feb 2022 20:30:25 +0900 Subject: [PATCH 0545/1472] Get rid of unnecessary use of `async-std` in non-test code (#10891) --- Cargo.lock | 29 ------------ client/network/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 1 - utils/prometheus/src/lib.rs | 28 +++--------- utils/prometheus/src/networking.rs | 71 ------------------------------ 5 files changed, 7 insertions(+), 124 deletions(-) delete mode 100644 utils/prometheus/src/networking.rs diff --git a/Cargo.lock b/Cargo.lock index 73b56aa6a377b..b7e4210efdd4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -254,23 +254,6 @@ dependencies = [ "event-listener", ] -[[package]] -name = "async-process" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b21b63ab5a0db0369deb913540af2892750e42d949faacc7a61495ac418a1692" -dependencies = [ - "async-io", - "blocking", - "cfg-if 1.0.0", - "event-listener", - "futures-lite", - "libc", - "once_cell", - "signal-hook", - "winapi 0.3.9", -] - [[package]] name = "async-std" version = "1.10.0" @@ -282,7 +265,6 @@ dependencies = [ "async-global-executor", "async-io", "async-lock", - "async-process", "crossbeam-utils 0.8.5", "futures-channel", "futures-core", @@ -9389,16 +9371,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" -[[package]] -name = "signal-hook" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" version = "1.3.0" @@ -10515,7 +10487,6 @@ dependencies = [ name = "substrate-prometheus-endpoint" version = "0.10.0-dev" dependencies = [ - "async-std", "futures-util", "hyper 0.14.16", "log 0.4.14", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 86a0380280471..7a978d0740f6e 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -18,7 +18,6 @@ prost-build = "0.9" [dependencies] async-trait = "0.1" -async-std = "1.10.0" bitflags = "1.3.2" cid = "0.6.0" bytes = "1" @@ -75,6 +74,7 @@ sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } tempfile = "3.1.0" +async-std = "1.10.0" [features] default = [] diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 264cc44d16024..fb998d2809fae 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -17,7 +17,6 @@ log = "0.4.8" prometheus = { version = "0.13.0", default-features = false } futures-util = { version = "0.3.19", default-features = false, features = ["io"] } thiserror = "1.0" -async-std = { version = "1.10.0", features = ["unstable"] } tokio = { version = "1.15", features = ["parking_lot"] } hyper = { version = "0.14.16", default-features = false, features = ["http1", "server", "tcp"] } diff --git a/utils/prometheus/src/lib.rs b/utils/prometheus/src/lib.rs index 3d28d9cd6f1c8..1892741eff5da 100644 --- a/utils/prometheus/src/lib.rs +++ b/utils/prometheus/src/lib.rs @@ -15,7 +15,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use futures_util::future::Future; use hyper::{ http::StatusCode, server::Server, @@ -34,7 +33,6 @@ pub use prometheus::{ use prometheus::{core::Collector, Encoder, TextEncoder}; use std::net::SocketAddr; -mod networking; mod sourced; pub use sourced::{MetricSource, SourcedCounter, SourcedGauge, SourcedMetric}; @@ -85,23 +83,10 @@ async fn request_metrics(req: Request, registry: Registry) -> Result hyper::rt::Executor for Executor -where - T: Future + Send + 'static, - T::Output: Send + 'static, -{ - fn execute(&self, future: T) { - async_std::task::spawn(future); - } -} - /// Initializes the metrics context, and starts an HTTP server /// to serve metrics. pub async fn init_prometheus(prometheus_addr: SocketAddr, registry: Registry) -> Result<(), Error> { - let listener = async_std::net::TcpListener::bind(&prometheus_addr) + let listener = tokio::net::TcpListener::bind(&prometheus_addr) .await .map_err(|_| Error::PortInUse(prometheus_addr))?; @@ -110,12 +95,11 @@ pub async fn init_prometheus(prometheus_addr: SocketAddr, registry: Registry) -> /// Init prometheus using the given listener. async fn init_prometheus_with_listener( - listener: async_std::net::TcpListener, + listener: tokio::net::TcpListener, registry: Registry, ) -> Result<(), Error> { - use networking::Incoming; - - log::info!("〽️ Prometheus exporter started at {}", listener.local_addr()?); + let listener = hyper::server::conn::AddrIncoming::from_listener(listener)?; + log::info!("〽️ Prometheus exporter started at {}", listener.local_addr()); let service = make_service_fn(move |_| { let registry = registry.clone(); @@ -127,7 +111,7 @@ async fn init_prometheus_with_listener( } }); - let server = Server::builder(Incoming(listener.incoming())).executor(Executor).serve(service); + let server = Server::builder(listener).serve(service); let result = server.await.map_err(Into::into); @@ -147,7 +131,7 @@ mod tests { let runtime = tokio::runtime::Runtime::new().expect("Creates the runtime"); let listener = runtime - .block_on(async_std::net::TcpListener::bind("127.0.0.1:0")) + .block_on(tokio::net::TcpListener::bind("127.0.0.1:0")) .expect("Creates listener"); let local_addr = listener.local_addr().expect("Returns the local addr"); diff --git a/utils/prometheus/src/networking.rs b/utils/prometheus/src/networking.rs deleted file mode 100644 index fda20b75740bf..0000000000000 --- a/utils/prometheus/src/networking.rs +++ /dev/null @@ -1,71 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use async_std::pin::Pin; -use futures_util::{ - io::{AsyncRead, AsyncWrite}, - stream::Stream, -}; -use std::task::{Context, Poll}; - -pub struct Incoming<'a>(pub async_std::net::Incoming<'a>); - -impl hyper::server::accept::Accept for Incoming<'_> { - type Conn = TcpStream; - type Error = async_std::io::Error; - - fn poll_accept( - self: Pin<&mut Self>, - cx: &mut Context, - ) -> Poll>> { - Pin::new(&mut Pin::into_inner(self).0) - .poll_next(cx) - .map(|opt| opt.map(|res| res.map(TcpStream))) - } -} - -pub struct TcpStream(pub async_std::net::TcpStream); - -impl tokio::io::AsyncRead for TcpStream { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context, - buf: &mut tokio::io::ReadBuf<'_>, - ) -> Poll> { - Pin::new(&mut Pin::into_inner(self).0) - .poll_read(cx, buf.initialize_unfilled()) - .map_ok(|s| buf.set_filled(s)) - } -} - -impl tokio::io::AsyncWrite for TcpStream { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context, - buf: &[u8], - ) -> Poll> { - Pin::new(&mut Pin::into_inner(self).0).poll_write(cx, buf) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - Pin::new(&mut Pin::into_inner(self).0).poll_flush(cx) - } - - fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - Pin::new(&mut Pin::into_inner(self).0).poll_close(cx) - } -} From 4544e6d2ce398cadc03b56863f57c1ed6f53d046 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 24 Feb 2022 13:05:08 +0100 Subject: [PATCH 0546/1472] No longer generate specs with consensus_engine field (#10346) * No longer generate specs with consensus_engine field * #[allow(unused)] --- client/chain-spec/src/chain_spec.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 2412a7cdf83f0..efb40d46f216a 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -173,9 +173,8 @@ struct ClientSpec { #[serde(flatten)] extensions: E, // Never used, left only for backward compatibility. - // In a future version, a `skip_serializing` attribute should be added in order to no longer - // generate chain specs with this field. - #[serde(default)] + #[serde(default, skip_serializing)] + #[allow(unused)] consensus_engine: (), #[serde(skip_serializing)] #[allow(unused)] From c22fce5a311beede13479c9a00cca85d823b6b00 Mon Sep 17 00:00:00 2001 From: wigy <1888808+wigy-opensource-developer@users.noreply.github.com> Date: Thu, 24 Feb 2022 15:34:34 +0100 Subject: [PATCH 0547/1472] Upgrading parity-scale-codec to v3 (#10825) * Upgraded dependencies * Adapting code to scale v3 * Empty commit to trigger CI * Triggering CI * Fixing UI test * Remove superfluous dev-dep added by #9228 * Cryout for CI --- Cargo.lock | 333 +++++++++++------- bin/node-template/pallets/template/Cargo.toml | 4 +- bin/node-template/runtime/Cargo.toml | 4 +- bin/node/bench/Cargo.toml | 6 +- bin/node/cli/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 4 +- bin/node/inspect/Cargo.toml | 2 +- bin/node/primitives/Cargo.toml | 4 +- bin/node/runtime/Cargo.toml | 4 +- bin/node/testing/Cargo.toml | 2 +- client/api/Cargo.toml | 4 +- client/authority-discovery/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 4 +- client/beefy/Cargo.toml | 4 +- client/beefy/rpc/Cargo.toml | 4 +- client/block-builder/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 4 +- client/consensus/babe/Cargo.toml | 4 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/epochs/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 4 +- client/consensus/slots/Cargo.toml | 2 +- client/db/Cargo.toml | 12 +- client/executor/Cargo.toml | 4 +- client/executor/common/Cargo.toml | 2 +- client/executor/wasmi/Cargo.toml | 2 +- client/executor/wasmtime/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 8 +- client/finality-grandpa/rpc/Cargo.toml | 4 +- client/informant/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/network/Cargo.toml | 4 +- client/network/src/protocol.rs | 2 +- client/network/test/Cargo.toml | 2 +- client/offchain/Cargo.toml | 4 +- client/rpc-api/Cargo.toml | 4 +- client/rpc/Cargo.toml | 4 +- client/service/Cargo.toml | 6 +- client/service/test/Cargo.toml | 4 +- client/state-db/Cargo.toml | 6 +- client/sync-state-rpc/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 7 +- client/utils/Cargo.toml | 2 +- frame/assets/Cargo.toml | 4 +- frame/atomic-swap/Cargo.toml | 4 +- frame/aura/Cargo.toml | 4 +- frame/authority-discovery/Cargo.toml | 4 +- frame/authorship/Cargo.toml | 4 +- frame/babe/Cargo.toml | 4 +- frame/bags-list/Cargo.toml | 4 +- frame/balances/Cargo.toml | 4 +- frame/beefy-mmr/Cargo.toml | 4 +- frame/beefy/Cargo.toml | 4 +- frame/benchmarking/Cargo.toml | 4 +- frame/bounties/Cargo.toml | 4 +- frame/child-bounties/Cargo.toml | 4 +- frame/collective/Cargo.toml | 4 +- frame/contracts/Cargo.toml | 4 +- frame/contracts/common/Cargo.toml | 4 +- frame/contracts/rpc/Cargo.toml | 2 +- frame/contracts/rpc/runtime-api/Cargo.toml | 4 +- frame/conviction-voting/Cargo.toml | 4 +- frame/democracy/Cargo.toml | 4 +- .../election-provider-multi-phase/Cargo.toml | 6 +- frame/election-provider-support/Cargo.toml | 4 +- frame/elections-phragmen/Cargo.toml | 4 +- frame/examples/basic/Cargo.toml | 4 +- frame/examples/offchain-worker/Cargo.toml | 4 +- frame/examples/parallel/Cargo.toml | 4 +- frame/executive/Cargo.toml | 4 +- frame/gilt/Cargo.toml | 4 +- frame/grandpa/Cargo.toml | 6 +- frame/identity/Cargo.toml | 4 +- frame/im-online/Cargo.toml | 4 +- frame/indices/Cargo.toml | 4 +- frame/lottery/Cargo.toml | 4 +- frame/membership/Cargo.toml | 4 +- frame/merkle-mountain-range/Cargo.toml | 4 +- .../primitives/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 4 +- frame/nicks/Cargo.toml | 4 +- frame/node-authorization/Cargo.toml | 4 +- frame/offences/Cargo.toml | 4 +- frame/offences/benchmarking/Cargo.toml | 4 +- frame/preimage/Cargo.toml | 4 +- frame/proxy/Cargo.toml | 4 +- frame/randomness-collective-flip/Cargo.toml | 4 +- frame/recovery/Cargo.toml | 4 +- frame/referenda/Cargo.toml | 4 +- frame/scheduler/Cargo.toml | 4 +- frame/scored-pool/Cargo.toml | 4 +- frame/session/Cargo.toml | 4 +- frame/session/benchmarking/Cargo.toml | 4 +- frame/society/Cargo.toml | 4 +- frame/staking/Cargo.toml | 4 +- frame/sudo/Cargo.toml | 4 +- frame/support/Cargo.toml | 8 +- frame/support/test/Cargo.toml | 4 +- frame/support/test/compile_pass/Cargo.toml | 4 +- frame/support/test/pallet/Cargo.toml | 4 +- .../call_argument_invalid_bound_2.stderr | 4 +- frame/system/Cargo.toml | 4 +- frame/system/benchmarking/Cargo.toml | 4 +- frame/system/rpc/runtime-api/Cargo.toml | 2 +- frame/timestamp/Cargo.toml | 4 +- frame/tips/Cargo.toml | 4 +- frame/transaction-payment/Cargo.toml | 4 +- .../asset-tx-payment/Cargo.toml | 4 +- frame/transaction-payment/rpc/Cargo.toml | 2 +- .../rpc/runtime-api/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 4 +- frame/treasury/Cargo.toml | 4 +- frame/uniques/Cargo.toml | 4 +- frame/utility/Cargo.toml | 4 +- frame/vesting/Cargo.toml | 4 +- primitives/api/Cargo.toml | 2 +- .../api/proc-macro/src/decl_runtime_apis.rs | 2 +- .../api/proc-macro/src/impl_runtime_apis.rs | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/application-crypto/Cargo.toml | 4 +- primitives/arithmetic/Cargo.toml | 6 +- primitives/arithmetic/fuzzer/Cargo.toml | 2 +- primitives/authority-discovery/Cargo.toml | 4 +- primitives/authorship/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 4 +- primitives/block-builder/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 4 +- primitives/consensus/aura/Cargo.toml | 4 +- primitives/consensus/babe/Cargo.toml | 4 +- primitives/consensus/common/Cargo.toml | 2 +- primitives/consensus/pow/Cargo.toml | 2 +- primitives/consensus/slots/Cargo.toml | 4 +- primitives/consensus/vrf/Cargo.toml | 2 +- primitives/core/Cargo.toml | 10 +- primitives/database/Cargo.toml | 4 +- primitives/externalities/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 6 +- primitives/inherents/Cargo.toml | 2 +- primitives/io/Cargo.toml | 4 +- primitives/keystore/Cargo.toml | 4 +- primitives/npos-elections/Cargo.toml | 4 +- primitives/npos-elections/fuzzer/Cargo.toml | 4 +- .../npos-elections/solution-type/Cargo.toml | 4 +- primitives/runtime-interface/Cargo.toml | 4 +- primitives/runtime/Cargo.toml | 6 +- primitives/sandbox/Cargo.toml | 2 +- primitives/session/Cargo.toml | 4 +- primitives/staking/Cargo.toml | 4 +- primitives/state-machine/Cargo.toml | 6 +- primitives/storage/Cargo.toml | 2 +- primitives/tasks/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 4 +- primitives/timestamp/Cargo.toml | 2 +- primitives/tracing/Cargo.toml | 2 +- .../transaction-storage-proof/Cargo.toml | 4 +- primitives/trie/Cargo.toml | 10 +- primitives/version/Cargo.toml | 4 +- primitives/version/proc-macro/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 10 +- test-utils/runtime/client/Cargo.toml | 2 +- .../runtime/transaction-pool/Cargo.toml | 4 +- utils/fork-tree/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 4 +- utils/frame/rpc/support/src/lib.rs | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 176 files changed, 528 insertions(+), 450 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b7e4210efdd4b..58297393c834d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -486,7 +486,7 @@ dependencies = [ "futures 0.3.16", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-chain-spec", "sc-client-api", "sc-keystore", @@ -521,7 +521,7 @@ dependencies = [ "jsonrpc-pubsub", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-rpc", "sc-utils", "serde", @@ -577,9 +577,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.59.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375" +checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" dependencies = [ "bitflags", "cexpr", @@ -602,24 +602,12 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitvec" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium 0.5.3", - "tap", - "wyz", -] - -[[package]] -name = "bitvec" -version = "0.20.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f682656975d3a682daff957be4ddeb65d6ad656737cd821f2d00685ae466af1" +checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b" dependencies = [ "funty", - "radium 0.6.2", + "radium", "tap", "wyz", ] @@ -824,6 +812,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +[[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 = "cache-padded" version = "1.1.1" @@ -881,9 +880,9 @@ dependencies = [ [[package]] name = "cexpr" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] @@ -2011,9 +2010,9 @@ dependencies = [ [[package]] name = "finality-grandpa" -version = "0.14.4" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ac3ff5224ef91f3c97e03eb1de2db82743427e91aaa5ac635f454f0b164f5a" +checksum = "d9def033d8505edf199f6a5d07aa7e6d2d6185b164293b77f0efd108f4f3e11d" dependencies = [ "either", "futures 0.3.16", @@ -2182,9 +2181,9 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "14.2.0" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ed5e5c346de62ca5c184b4325a6600d1eaca210666e4606fe4e449574978d0" +checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" dependencies = [ "cfg-if 1.0.0", "parity-scale-codec", @@ -2404,9 +2403,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "funty" -version = "1.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" @@ -2759,6 +2758,15 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +dependencies = [ + "ahash", +] + [[package]] name = "heck" version = "0.3.2" @@ -3043,9 +3051,9 @@ dependencies = [ [[package]] name = "impl-codec" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ "parity-scale-codec", ] @@ -3524,9 +3532,9 @@ dependencies = [ [[package]] name = "kvdb" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a3f58dc069ec0e205a27f5b45920722a46faed802a0541538241af6228f512" +checksum = "a301d8ecb7989d4a6e2c57a49baca77d353bdbf879909debe3f375fe25d61f86" dependencies = [ "parity-util-mem", "smallvec 1.7.0", @@ -3534,20 +3542,20 @@ dependencies = [ [[package]] name = "kvdb-memorydb" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b6b85fc643f5acd0bffb2cc8a6d150209379267af0d41db72170021841f9f5" +checksum = "ece7e668abd21387aeb6628130a6f4c802787f014fa46bc83221448322250357" dependencies = [ "kvdb", "parity-util-mem", - "parking_lot 0.11.2", + "parking_lot 0.12.0", ] [[package]] name = "kvdb-rocksdb" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1b6ea8f2536f504b645ad78419c8246550e19d2c3419a167080ce08edee35a" +checksum = "a1e72a631a32527fafe22d0751c002e67d28173c49dcaecf79d1aaa323c520e9" dependencies = [ "fs-swap", "kvdb", @@ -3555,7 +3563,7 @@ dependencies = [ "num_cpus", "owning_ref", "parity-util-mem", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "regex", "rocksdb", "smallvec 1.7.0", @@ -4113,14 +4121,17 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "6.20.3" +version = "0.6.1+6.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c309a9d2470844aceb9a4a098cf5286154d20596868b75a6b36357d2bb9ca25d" +checksum = "81bc587013734dadb7cf23468e531aa120788b87243648be42e2d3a072186291" dependencies = [ "bindgen", + "bzip2-sys", "cc", "glob", "libc", + "libz-sys", + "tikv-jemalloc-sys", ] [[package]] @@ -4243,9 +4254,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] @@ -4412,23 +4423,12 @@ dependencies = [ [[package]] name = "memory-db" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de006e09d04fc301a5f7e817b75aa49801c4479a8af753764416b085337ddcc5" -dependencies = [ - "hash-db", - "hashbrown 0.11.2", - "parity-util-mem", -] - -[[package]] -name = "memory-db" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d505169b746dacf02f7d14d8c80b34edfd8212159c63d23c977739a0d960c626" +checksum = "6566c70c1016f525ced45d7b7f97730a2bafb037c788211d0c186ef5b2189f0a" dependencies = [ "hash-db", - "hashbrown 0.11.2", + "hashbrown 0.12.0", "parity-util-mem", ] @@ -4459,6 +4459,12 @@ dependencies = [ "log 0.3.9", ] +[[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.4.4" @@ -5151,13 +5157,12 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "6.1.2" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" dependencies = [ - "bitvec 0.19.5", - "funty", "memchr", + "minimal-lexical", "version_check 0.9.2", ] @@ -5813,7 +5818,7 @@ dependencies = [ "log 0.4.14", "pallet-balances", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "rand 0.7.3", "scale-info", "sp-arithmetic", @@ -6615,12 +6620,12 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "2.3.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" +checksum = "2a7f3fcf5e45fc28b84dcdab6b983e77f197ec01f325a33f404ba6855afd1070" dependencies = [ "arrayvec 0.7.1", - "bitvec 0.20.2", + "bitvec", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", @@ -6629,9 +6634,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "2.3.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" +checksum = "2c6e626dc84025ff56bf1476ed0e30d10c84d7f89a475ef46ebabee1095a8fba" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -6661,15 +6666,15 @@ dependencies = [ [[package]] name = "parity-util-mem" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f4cb4e169446179cbc6b8b6320cc9fca49bd2e94e8db25f25f200a8ea774770" +checksum = "c32561d248d352148124f036cac253a644685a21dc9fea383eb4907d7bd35a8f" dependencies = [ "cfg-if 1.0.0", - "hashbrown 0.11.2", + "hashbrown 0.12.0", "impl-trait-for-tuples", "parity-util-mem-derive", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "primitive-types", "smallvec 1.7.0", "winapi 0.3.9", @@ -6743,10 +6748,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", - "lock_api 0.4.5", + "lock_api 0.4.6", "parking_lot_core 0.8.5", ] +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api 0.4.6", + "parking_lot_core 0.9.1", +] + [[package]] name = "parking_lot_core" version = "0.6.2" @@ -6776,6 +6791,19 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "parking_lot_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.10", + "smallvec 1.7.0", + "windows-sys", +] + [[package]] name = "paste" version = "0.1.18" @@ -7082,9 +7110,9 @@ dependencies = [ [[package]] name = "primitive-types" -version = "0.10.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" dependencies = [ "fixed-hash", "impl-codec", @@ -7272,15 +7300,9 @@ dependencies = [ [[package]] name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - -[[package]] -name = "radium" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" @@ -7705,9 +7727,9 @@ dependencies = [ [[package]] name = "rocksdb" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a62eca5cacf2c8261128631bed9f045598d40bfbe4b29f5163f0f802f8f44a7" +checksum = "620f4129485ff1a7128d184bc687470c21c7951b64779ebc9cfdad3dcd920290" dependencies = [ "libc", "librocksdb-sys", @@ -7934,7 +7956,7 @@ dependencies = [ "futures-timer", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -8040,7 +8062,7 @@ dependencies = [ "hash-db", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-executor", "sc-transaction-pool-api", "sc-utils", @@ -8073,7 +8095,7 @@ dependencies = [ "log 0.4.14", "parity-db", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "quickcheck", "sc-client-api", "sc-state-db", @@ -8098,7 +8120,7 @@ dependencies = [ "futures-timer", "libp2p", "log 0.4.14", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-client-api", "sc-utils", "serde", @@ -8122,7 +8144,7 @@ dependencies = [ "getrandom 0.2.3", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -8164,7 +8186,7 @@ dependencies = [ "num-rational 0.2.4", "num-traits", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "rand 0.7.3", "rand_chacha 0.2.2", "retain_mut", @@ -8290,7 +8312,7 @@ dependencies = [ "futures-timer", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-client-api", "sc-consensus", "sp-api", @@ -8349,7 +8371,7 @@ dependencies = [ "libsecp256k1", "lru 0.6.6", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "paste 1.0.6", "regex", "sc-executor-common", @@ -8445,7 +8467,7 @@ dependencies = [ "futures-timer", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "rand 0.8.4", "sc-block-builder", "sc-chain-spec", @@ -8525,7 +8547,7 @@ version = "4.0.0-dev" dependencies = [ "async-trait", "hex", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "serde_json", "sp-application-crypto", "sp-core", @@ -8558,7 +8580,7 @@ dependencies = [ "log 0.4.14", "lru 0.7.0", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "pin-project 1.0.10", "prost", "prost-build", @@ -8619,7 +8641,7 @@ dependencies = [ "futures-timer", "libp2p", "log 0.4.14", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8651,7 +8673,7 @@ dependencies = [ "num_cpus", "once_cell", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8705,7 +8727,7 @@ dependencies = [ "lazy_static", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -8741,7 +8763,7 @@ dependencies = [ "jsonrpc-pubsub", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-chain-spec", "sc-transaction-pool-api", "serde", @@ -8800,7 +8822,7 @@ dependencies = [ "log 0.4.14", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "pin-project 1.0.10", "rand 0.7.3", "sc-block-builder", @@ -8860,7 +8882,7 @@ dependencies = [ "hex-literal", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -8894,7 +8916,7 @@ dependencies = [ "parity-scale-codec", "parity-util-mem", "parity-util-mem-derive", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-client-api", "sp-core", ] @@ -8927,7 +8949,7 @@ dependencies = [ "futures 0.3.16", "libp2p", "log 0.4.14", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "pin-project 1.0.10", "rand 0.7.3", "serde", @@ -8948,7 +8970,7 @@ dependencies = [ "libc", "log 0.4.14", "once_cell", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "regex", "rustc-hash", "sc-client-api", @@ -8990,7 +9012,7 @@ dependencies = [ "log 0.4.14", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "retain_mut", "sc-block-builder", "sc-client-api", @@ -9030,18 +9052,18 @@ dependencies = [ "futures 0.3.16", "futures-timer", "lazy_static", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "prometheus", "tokio-test", ] [[package]] name = "scale-info" -version = "1.0.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55b744399c25532d63a0d2789b109df8d46fc93752d46b0782991a931a782f" +checksum = "7d3b4d0b178e3af536f7988303bc73a0766c816de2138c08262015f8ec7be568" dependencies = [ - "bitvec 0.20.2", + "bitvec", "cfg-if 1.0.0", "derive_more", "parity-scale-codec", @@ -9051,9 +9073,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "1.0.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baeb2780690380592f86205aa4ee49815feb2acad8c2f59e6dd207148c3f1fcd" +checksum = "b7805950c36512db9e3251c970bb7ac425f326716941862205d612ab3b5e46e2" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -9640,7 +9662,7 @@ dependencies = [ "log 0.4.14", "lru 0.7.0", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sp-api", "sp-consensus", "sp-database", @@ -9766,7 +9788,7 @@ dependencies = [ "num-traits", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "primitive-types", "rand 0.7.3", "regex", @@ -9819,7 +9841,7 @@ name = "sp-database" version = "4.0.0-dev" dependencies = [ "kvdb", - "parking_lot 0.11.2", + "parking_lot 0.12.0", ] [[package]] @@ -9881,7 +9903,7 @@ dependencies = [ "libsecp256k1", "log 0.4.14", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sp-core", "sp-externalities", "sp-keystore", @@ -9913,7 +9935,7 @@ dependencies = [ "futures 0.3.16", "merlin", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "rand 0.7.3", "rand_chacha 0.2.2", "schnorrkel", @@ -10156,7 +10178,7 @@ dependencies = [ "log 0.4.14", "num-traits", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "pretty_assertions", "rand 0.7.3", "smallvec 1.7.0", @@ -10269,7 +10291,7 @@ dependencies = [ "criterion", "hash-db", "hex-literal", - "memory-db 0.28.0", + "memory-db", "parity-scale-codec", "scale-info", "sp-core", @@ -10530,7 +10552,7 @@ dependencies = [ "frame-system-rpc-runtime-api", "futures 0.3.16", "log 0.4.14", - "memory-db 0.27.0", + "memory-db", "pallet-babe", "pallet-timestamp", "parity-scale-codec", @@ -10590,7 +10612,7 @@ version = "2.0.0" dependencies = [ "futures 0.3.16", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "sc-transaction-pool", "sc-transaction-pool-api", "sp-blockchain", @@ -10767,6 +10789,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "tikv-jemalloc-sys" +version = "0.4.2+5.2.1-patched.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5844e429d797c62945a566f8da4e24c7fe3fbd5d6617fd8bf7a0b7dc1ee0f22e" +dependencies = [ + "cc", + "fs_extra", + "libc", +] + [[package]] name = "time" version = "0.1.44" @@ -11133,14 +11166,14 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" [[package]] name = "trie-bench" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ac46f6503d0fa976193db46f9dbb1d454e5dbde76495f1316f576c7f3f0e6b" +checksum = "57ecec5d10427b35e9ae374b059dccc0801d02d832617c04c78afc7a8c5c4a34" dependencies = [ "criterion", "hash-db", "keccak-hasher", - "memory-db 0.28.0", + "memory-db", "parity-scale-codec", "trie-db", "trie-root", @@ -11149,12 +11182,12 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ddae50680c12ef75bfbf58416ca6622fa43d879553f6cb2ed1a817346e1ffe" +checksum = "d32d034c0d3db64b43c31de38e945f15b40cd4ca6d2dcfc26d4798ce8de4ab83" dependencies = [ "hash-db", - "hashbrown 0.11.2", + "hashbrown 0.12.0", "log 0.4.14", "rustc-hex", "smallvec 1.7.0", @@ -11279,7 +11312,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "digest 0.10.2", "rand 0.8.4", "static_assertions", @@ -12185,6 +12218,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" + [[package]] name = "winreg" version = "0.6.2" @@ -12206,9 +12282,12 @@ dependencies = [ [[package]] name = "wyz" -version = "0.2.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" +checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" +dependencies = [ + "tap", +] [[package]] name = "x25519-dalek" diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 0a9d0eb27a2ca..62c1c4310884d 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -13,10 +13,10 @@ repository = "https://github.com/substrate-developer-hub/substrate-node-template targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/support" } frame-system = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/system" } frame-benchmarking = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/benchmarking", optional = true } diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 98da28c4476d9..ca3b4d93e6b67 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -13,8 +13,8 @@ repository = "https://github.com/substrate-developer-hub/substrate-node-template targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } pallet-aura = { version = "4.0.0-dev", default-features = false, path = "../../../frame/aura" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../../frame/balances" } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 18951179235c1..b14e44371d2b9 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -20,8 +20,8 @@ sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machi serde = "1.0.136" serde_json = "1.0.74" derive_more = "0.99.16" -kvdb = "0.10.0" -kvdb-rocksdb = "0.14.0" +kvdb = "0.11.0" +kvdb-rocksdb = "0.15.1" sp-trie = { version = "5.0.0", path = "../../../primitives/trie" } sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } @@ -35,7 +35,7 @@ fs_extra = "1" hex = "0.4.0" rand = { version = "0.7.2", features = ["small_rng"] } lazy_static = "1.4.0" -parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } parity-db = { version = "0.3" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 74d62ba78c2a0..4225d09d594a7 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -35,7 +35,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies clap = { version = "3.0", features = ["derive"], optional = true } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } futures = "0.3.16" hex-literal = "0.3.4" diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 531fffe35529f..16f232d73d3f0 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -12,8 +12,8 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0" } -scale-info = { version = "1.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0" } +scale-info = { version = "2.0.0", features = ["derive"] } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index e5b4c41c91b71..162d56fc763fd 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -12,7 +12,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "3.0", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } thiserror = "1.0" sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 5664318513a09..f95f767b4a83c 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -11,10 +11,10 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../../primitives/application-crypto" } sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 4f235a51171d2..0055230295a1e 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -14,11 +14,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # third-party dependencies -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", "max-encoded-len", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } static_assertions = "1.1.0" hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 3275aac0ef1de..fc9209ce2b638 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -23,7 +23,7 @@ sc-client-db = { version = "0.10.0-dev", path = "../../../client/db/", features ] } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index ab6ad96e286f9..68ab9aed31fe5 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } @@ -25,7 +25,7 @@ futures = "0.3.1" hash-db = { version = "0.15.2", default-features = false } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } log = "0.4.8" -parking_lot = "0.11.2" +parking_lot = "0.12.0" sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-keystore = { version = "0.11.0", default-features = false, path = "../../primitives/keystore" } diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index e3a3ef2a3591b..04dde95837d2a 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -18,7 +18,7 @@ prost-build = "0.9" [dependencies] async-trait = "0.1" -codec = { package = "parity-scale-codec", default-features = false, version = "2.0.0" } +codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0" } thiserror = "1.0" futures = "0.3.9" futures-timer = "3.0.1" diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 85592c7c549c0..bbc66cf09f8bb 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.9" futures-timer = "3.0.1" log = "0.4.8" @@ -33,4 +33,4 @@ sc-proposer-metrics = { version = "0.10.0-dev", path = "../proposer-metrics" } [dev-dependencies] sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -parking_lot = "0.11.2" +parking_lot = "0.12.0" diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 3ce556e85239b..d126d60b8409b 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -11,11 +11,11 @@ description = "BEEFY Client gadget for substrate" fnv = "1.0.6" futures = "0.3" log = "0.4" -parking_lot = "0.11" +parking_lot = "0.12.0" thiserror = "1.0" wasm-timer = "0.2.5" -codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive"] } +codec = { version = "3.0.0", package = "parity-scale-codec", features = ["derive"] } prometheus = { version = "0.10.0-dev", package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 44837fb0e41f5..053aef500b462 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -10,7 +10,7 @@ description = "RPC for the BEEFY Client gadget for substrate" [dependencies] futures = "0.3.16" log = "0.4" -parking_lot = "0.11" +parking_lot = "0.12.0" thiserror = "1.0" serde = { version = "1.0.136", features = ["derive"] } @@ -19,7 +19,7 @@ jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" jsonrpc-pubsub = "18.0.0" -codec = { version = "2.2.0", package = "parity-scale-codec", features = ["derive"] } +codec = { version = "3.0.0", package = "parity-scale-codec", features = ["derive"] } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index e41ab0a5caf15..10c3fbdb9f7fe 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -22,7 +22,7 @@ sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-builder" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sc-client-api = { version = "4.0.0-dev", path = "../api" } -codec = { package = "parity-scale-codec", version = "2.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 9b299f00a2147..9e8e3276e760f 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -21,5 +21,5 @@ serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.74" sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } memmap2 = "0.5.0" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 3fd65d23eb888..708e6317d10ce 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -30,7 +30,7 @@ thiserror = "1.0.30" tiny-bip39 = "0.8.2" tokio = { version = "1.15", features = ["signal", "rt-multi-thread", "parking_lot"] } -parity-scale-codec = "2.3.1" +parity-scale-codec = "3.0.0" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 156842c35842e..9cb241b6c974d 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -18,7 +18,7 @@ sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consen sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } @@ -48,4 +48,4 @@ sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } tempfile = "3.1.0" -parking_lot = "0.11.2" +parking_lot = "0.12.0" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 76ec6a25879f8..4a9f1f00b75ad 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } @@ -44,7 +44,7 @@ sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } futures = "0.3.9" -parking_lot = "0.11.2" +parking_lot = "0.12.0" log = "0.4.8" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } rand = "0.7.2" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index a14a367690332..7add4bb873309 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -26,7 +26,7 @@ sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machi sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -parking_lot = "0.11.2" +parking_lot = "0.12.0" serde = { version = "1.0", features = ["derive"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } async-trait = "0.1.42" diff --git a/client/consensus/epochs/Cargo.toml b/client/consensus/epochs/Cargo.toml index b377dccfd3689..2c5a6dfbffe0f 100644 --- a/client/consensus/epochs/Cargo.toml +++ b/client/consensus/epochs/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index c2c36b1fc5867..83828962f670c 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -19,7 +19,7 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" log = "0.4.8" -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0", features = ["derive"] } assert_matches = "1.3.0" async-trait = "0.1.50" diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index eb609489290a0..7e3d30e8deba2 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } @@ -27,7 +27,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo log = "0.4.8" futures = "0.3.16" futures-timer = "3.0.1" -parking_lot = "0.11.2" +parking_lot = "0.12.0" thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev"} async-trait = "0.1.50" diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index b13c1bb6b5b32..0127010a1714d 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-arithmetic = { version = "4.0.0", path = "../../../primitives/arithmetic" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index f2c21abf6c1d6..82607f56f7d1f 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -13,14 +13,14 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -parking_lot = "0.11.2" +parking_lot = "0.12.0" log = "0.4.8" -kvdb = "0.10.0" -kvdb-rocksdb = { version = "0.14.0", optional = true } -kvdb-memorydb = "0.10.0" +kvdb = "0.11.0" +kvdb-rocksdb = { version = "0.15.1", optional = true } +kvdb-memorydb = "0.11.0" linked-hash-map = "0.5.4" hash-db = "0.15.2" -codec = { package = "parity-scale-codec", version = "2.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } @@ -39,7 +39,7 @@ parity-db = { version = "0.3.5", optional = true } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } quickcheck = "1.0.3" -kvdb-rocksdb = "0.14.0" +kvdb-rocksdb = "0.15.1" tempfile = "3" [features] diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 47ef050050864..6cd1938822d0c 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } sp-io = { version = "5.0.0", path = "../../primitives/io" } sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-tasks = { version = "4.0.0-dev", path = "../../primitives/tasks" } @@ -30,7 +30,7 @@ sp-externalities = { version = "0.11.0", path = "../../primitives/externalities" sc-executor-common = { version = "0.10.0-dev", path = "common" } sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } -parking_lot = "0.11.2" +parking_lot = "0.12.0" libsecp256k1 = "0.7" sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } lru = "0.6.6" diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index e23db203b3a40..3edaaf12e5b0d 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] wasm-instrument = "0.1" -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } wasmi = "0.9.1" sp-core = { version = "5.0.0", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index d333e98bf6cfb..9b25ebcb1174b 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.8" wasmi = "0.9.1" -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sp-wasm-interface = { version = "5.0.0", path = "../../../primitives/wasm-interface" } diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 0423b384943e8..79d5d41087a19 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -17,7 +17,7 @@ libc = "0.2.112" cfg-if = "1.0" log = "0.4.8" parity-wasm = "0.42.0" -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sp-wasm-interface = { version = "5.0.0", path = "../../../primitives/wasm-interface", features = ["wasmtime"] } sp-runtime-interface = { version = "5.0.0", path = "../../../primitives/runtime-interface" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 6fecebc3fdf60..2e2ad8738f35f 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -20,10 +20,10 @@ fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } futures = "0.3.9" futures-timer = "3.0.1" log = "0.4.8" -parking_lot = "0.11.2" +parking_lot = "0.12.0" rand = "0.8.4" ahash = "0.7.6" -parity-scale-codec = { version = "2.3.1", features = ["derive"] } +parity-scale-codec = { version = "3.0.0", features = ["derive"] } sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } @@ -44,12 +44,12 @@ sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } -finality-grandpa = { version = "0.14.4", features = ["derive-codec"] } +finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } async-trait = "0.1.50" [dev-dependencies] assert_matches = "1.3.0" -finality-grandpa = { version = "0.14.1", features = [ +finality-grandpa = { version = "0.15.0", features = [ "derive-codec", "test-helpers", ] } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index b544287a6002c..8650ee0498539 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -14,7 +14,7 @@ sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } -finality-grandpa = { version = "0.14.4", features = ["derive-codec"] } +finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" @@ -24,7 +24,7 @@ serde = { version = "1.0.105", features = ["derive"] } serde_json = "1.0.50" log = "0.4.8" thiserror = "1.0" -parity-scale-codec = { version = "2.0.0", features = ["derive"] } +parity-scale-codec = { version = "3.0.0", features = ["derive"] } sc-client-api = { version = "4.0.0-dev", path = "../../api" } [dev-dependencies] diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index 78ee90823f226..82917c46d3d27 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -17,7 +17,7 @@ ansi_term = "0.12.1" futures = "0.3.9" futures-timer = "3.0.1" log = "0.4.8" -parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 4d67be4167dd1..f2a06244cde02 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -21,7 +21,7 @@ sp-application-crypto = { version = "5.0.0", path = "../../primitives/applicatio sp-core = { version = "5.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } hex = "0.4.0" -parking_lot = "0.11.2" +parking_lot = "0.12.0" serde_json = "1.0.74" [dev-dependencies] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 7a978d0740f6e..0334c5e819df9 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -21,7 +21,7 @@ async-trait = "0.1" bitflags = "1.3.2" cid = "0.6.0" bytes = "1" -codec = { package = "parity-scale-codec", version = "2.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } either = "1.5.3" @@ -36,7 +36,7 @@ linked-hash-map = "0.5.4" linked_hash_set = "0.1.3" lru = "0.7.0" log = "0.4.8" -parking_lot = "0.11.2" +parking_lot = "0.12.0" pin-project = "1.0.10" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } prost = "0.9" diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index eb634ca5be764..c00d4302f827c 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -1666,7 +1666,7 @@ impl NetworkBehaviour for Protocol { } } else { match ( - message::Roles::decode_all(&received_handshake[..]), + message::Roles::decode_all(&mut &received_handshake[..]), self.peers.get(&peer_id), ) { (Ok(roles), _) => CustomMessageOutcome::NotificationStreamOpened { diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 2750c613d42a2..7d0b1921b69eb 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-std = "1.10.0" sc-network = { version = "0.10.0-dev", path = "../" } log = "0.4.8" -parking_lot = "0.11.2" +parking_lot = "0.12.0" futures = "0.3.9" futures-timer = "3.0.1" rand = "0.7.2" diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 5cd823958eed4..054a8c3edf02c 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -14,13 +14,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = "1.1" -codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } hex = "0.4" fnv = "1.0.6" futures = "0.3.16" futures-timer = "3.0.2" num_cpus = "1.13" -parking_lot = "0.11.2" +parking_lot = "0.12.0" rand = "0.7.2" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 00b2fa787ca6f..bbbc9a9983374 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -13,14 +13,14 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.16" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" jsonrpc-pubsub = "18.0.0" log = "0.4.8" -parking_lot = "0.11.2" +parking_lot = "0.12.0" thiserror = "1.0" sp-core = { version = "5.0.0", path = "../../primitives/core" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 308d99bc4f376..cbce14cee20db 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.16" jsonrpc-pubsub = "18.0.0" log = "0.4.8" @@ -35,7 +35,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } hash-db = { version = "0.15.2", default-features = false } -parking_lot = "0.11.2" +parking_lot = "0.12.0" lazy_static = { version = "1.4.0", optional = true } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 55ca01a2284a5..e007486d9ef1a 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -27,7 +27,7 @@ futures = "0.3.16" jsonrpc-pubsub = "18.0" jsonrpc-core = "18.0" rand = "0.7.3" -parking_lot = "0.11.2" +parking_lot = "0.12.0" log = "0.4.11" futures-timer = "3.0.1" exit-future = "0.2.0" @@ -56,7 +56,7 @@ sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../db" } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } sc-executor = { version = "0.10.0-dev", path = "../executor" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } @@ -74,7 +74,7 @@ sc-tracing = { version = "4.0.0-dev", path = "../tracing" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } -parity-util-mem = { version = "0.10.2", default-features = false, features = [ +parity-util-mem = { version = "0.11.0", default-features = false, features = [ "primitive-types", ] } async-trait = "0.1.50" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 6395f9d9877dc..a815d1f5571fc 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -18,7 +18,7 @@ tempfile = "3.1.0" tokio = { version = "1.15.0", features = ["time"] } log = "0.4.8" fdlimit = "0.2.1" -parking_lot = "0.11.2" +parking_lot = "0.12.0" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } @@ -40,5 +40,5 @@ sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-executor = { version = "0.10.0-dev", path = "../../executor" } sp-panic-handler = { version = "4.0.0", path = "../../../primitives/panic-handler" } -parity-scale-codec = "2.3.1" +parity-scale-codec = "3.0.0" sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index fa0c5ed9810c9..bf45ad49043c5 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -parking_lot = "0.11.2" +parking_lot = "0.12.0" log = "0.4.11" sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-core = { version = "5.0.0", path = "../../primitives/core" } -codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } -parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } parity-util-mem-derive = "0.1.0" diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 3e064685488d4..524e9259288a4 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -26,4 +26,4 @@ serde_json = "1.0.74" serde = { version = "1.0.136", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 595a574021599..2339fa277ccad 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -parking_lot = "0.11.2" +parking_lot = "0.12.0" futures = "0.3.9" wasm-timer = "0.2.5" libp2p = { version = "0.40.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 5f7e0831a536a..2d892c926eb61 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -20,7 +20,7 @@ lazy_static = "1.4.0" libc = "0.2.112" log = { version = "0.4.8" } once_cell = "1.8.0" -parking_lot = "0.11.2" +parking_lot = "0.12.0" regex = "1.5.4" rustc-hash = "1.1.0" serde = "1.0.136" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 42172ce723e1c..a5d6d4e1bf74f 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -13,13 +13,13 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } thiserror = "1.0.30" futures = "0.3.16" futures-timer = "3.0.2" log = "0.4.8" -parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } -parking_lot = "0.11.2" +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parking_lot = "0.12.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } @@ -41,7 +41,6 @@ sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/comm substrate-test-runtime-transaction-pool = { version = "2.0.0", path = "../../test-utils/runtime/transaction-pool" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } -codec = { package = "parity-scale-codec", version = "2.0.0" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } criterion = "0.3" diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index 24075f932b508..c5acff24548a5 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" [dependencies] futures = "0.3.9" lazy_static = "1.4.0" -parking_lot = "0.11" +parking_lot = "0.12.0" prometheus = { version = "0.13.0", default-features = false } futures-timer = "3.0.2" diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index c5d60291fc435..02faa20d03f95 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 1dcd6154d0beb..7b737d15d2f59 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index f869ddb417029..3b1a96f66c464 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index b6e8a400f8652..509cea33f6a9b 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -15,10 +15,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authority-discovery" } sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } pallet-session = { version = "4.0.0-dev", features = [ "historical", diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 31daa74553c23..379a1ab97b8bc 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index f48877746b888..88be992250c77 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index c35ff6fc6c39d..18e2c048186c9 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } # primitives sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index f594e67ab861d..f7e7c662b0209 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index bb30c540ca1c8..c5aafa94295ee 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -9,10 +9,10 @@ repository = "https://github.com/paritytech/substrate" [dependencies] hex = { version = "0.4", optional = true } -codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } +codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } k256 = { version = "0.10.2", default-features = false, features = ["arithmetic"] } log = { version = "0.4.13", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 5844657dd50c4..ed5682fdb4742 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -8,8 +8,8 @@ repository = "https://github.com/paritytech/substrate" description = "BEEFY FRAME pallet" [dependencies] -codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index ad6f99c645173..87089247cc952 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] linregress = { version = "0.4.4", optional = true } paste = "1.0" -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } sp-runtime-interface = { version = "5.0.0", path = "../../primitives/runtime-interface", default-features = false } sp-runtime = { version = "5.0.0", path = "../../primitives/runtime", default-features = false } diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 477815a306f3c..cc35d54f25e11 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 0eeefd4de4595..d912bce112b85 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index 334b4945afa2b..c679bb21e820c 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -13,9 +13,9 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 5ab1389f65c1a..cf726b76a5f77 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -14,11 +14,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bitflags = "1.3" -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", "max-encoded-len", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4", default-features = false } wasm-instrument = { version = "0.1", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/common/Cargo.toml index ad934c41a71fc..d19a160fc45ce 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/common/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bitflags = "1.0" -codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1", features = ["derive"], optional = true } # Substrate Dependencies (This crate should not rely on frame) diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index 52ca0e6d83454..57429fed67220 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2" } +codec = { package = "parity-scale-codec", version = "3.0.0" } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml index 8ecdff5175372..071b4bafeef4f 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/rpc/runtime-api/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } # Substrate Dependencies pallet-contracts-primitives = { version = "5.0.0", default-features = false, path = "../../common" } diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index 7b51e3f8c91ad..039fdb07caabc 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 743cea074ee26..e6fe550f8845a 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index c0d85737ec221..e96e9c4464420 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] static_assertions = "1.1.0" -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -40,7 +40,7 @@ rand = { version = "0.7.3", default-features = false, optional = true, features strum = { optional = true, default-features = false, version = "0.23.0", features = ["derive"] } [dev-dependencies] -parking_lot = "0.11.2" +parking_lot = "0.12.0" rand = { version = "0.7.3" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "5.0.0", path = "../../primitives/io" } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 662762ef63068..0d11a4ac503ea 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index f70eb568349b4..3312e4863a649 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 73c11475fdf61..c368af4267c39 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -13,9 +13,9 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4.14", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index e7ae323050ee1..bf6acd652b61b 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } lite-json = { version = "0.1", default-features = false } log = { version = "0.4.14", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/examples/parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml index 8d291df191368..ba3c6de5d17a7 100644 --- a/frame/examples/parallel/Cargo.toml +++ b/frame/examples/parallel/Cargo.toml @@ -12,8 +12,8 @@ description = "FRAME example pallet using runtime worker threads" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index b261aecdf9262..dd37b27d4eb93 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index 7ed17d152a01e..52b5be3a857be 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index eda9d630d4f99..52f7b02a387b1 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } @@ -32,7 +32,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } -grandpa = { package = "finality-grandpa", version = "0.14.1", features = ["derive-codec"] } +grandpa = { package = "finality-grandpa", version = "0.15.0", features = ["derive-codec"] } sp-keyring = { version = "5.0.0", path = "../../primitives/keyring" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 209896ec0e557..61ac2907a9cdb 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } enumflags2 = { version = "0.6.2" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index d223e5e8502d3..119010ef6b049 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index 28a6427f520b8..74d84849c37d2 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-keyring = { version = "5.0.0", optional = true, path = "../../primitives/keyring" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 2e2c2287a2ab6..e43339c1eafa0 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index f2f7607ce9a52..abf27710cf600 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index a614ffa977154..82c08a3c262f6 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -12,8 +12,8 @@ description = "FRAME Merkle Mountain Range pallet." targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, version = "0.3.2" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index d281f159bebad..fe50ca722200d 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -12,7 +12,7 @@ description = "FRAME Merkle Mountain Range primitives." targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4.14", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 7dc891267cebc..6ae0e7a3f076c 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index dfc05888b1aa9..8251c7bc9c71f 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index bf5afd26ebb59..0acdd4b5bb550 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 0d64251885383..63106ec0aa9b4 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -12,8 +12,8 @@ description = "FRAME pallet for node authorization" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 053708c8b247b..f6a1fe7c190f1 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } serde = { version = "1.0.136", optional = true } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index 9742545383227..ebab8114c1bb3 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 66ef8467be28a..9cffedf6c2156 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -10,8 +10,8 @@ description = "FRAME pallet for storing preimages of hashes" readme = "README.md" [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index f0bd9391789bb..8bf0a1469c378 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["max-encoded-len"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["max-encoded-len"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index a93585700f2b0..d6fb14c02d8dd 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] safe-mix = { version = "1.0", default-features = false } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 88da65327e2f0..a629b0bbf0e32 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index 46ede8c1eed08..a3067956db2b0 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index d88063d69c5bb..c45d961bd694b 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -10,8 +10,8 @@ description = "FRAME Scheduler pallet" readme = "README.md" [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index af8b0f6aa2643..934400230f7a3 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index a342865615d91..9bd4d1fc50955 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] log = { version = "0.4.0", default-features = false } impl-trait-for-tuples = "0.2.1" -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index cd33c5b186490..598c3a73e2e3d 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -26,8 +26,8 @@ pallet-session = { version = "4.0.0-dev", default-features = false, path = "../. pallet-staking = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../staking" } [dev-dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } -scale-info = "1.0" +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +scale-info = "2.0.0" sp-core = { version = "5.0.0", path = "../../../primitives/core" } sp-io = { version = "5.0.0", path = "../../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../../balances" } diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index 2787453d49d3e..12fb4202888c8 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 363ffe4428fb4..6e85382ddaa24 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index 063ea52d5b8b5..a4b1d21e9efc8 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index a5ba2fad18b3f..9bb7ae5d8af8d 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -14,9 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } -frame-metadata = { version = "14.2.0", default-features = false, features = ["v14"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +frame-metadata = { version = "15.0.0", default-features = false, features = ["v14"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } @@ -40,7 +40,7 @@ sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/c assert_matches = "1.3.0" pretty_assertions = "1.0.0" frame-system = { version = "4.0.0-dev", path = "../system" } -parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } [features] default = ["std"] diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 9f26df4869afc..56e269b43265e 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -13,8 +13,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", default-features = false, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../../primitives/arithmetic" } sp-io = { version = "5.0.0", path = "../../../primitives/io", default-features = false } sp-state-machine = { version = "0.11.0", optional = true, path = "../../../primitives/state-machine" } diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index aaa080f84f1a4..241ec1b352f48 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -12,8 +12,8 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-core = { version = "5.0.0", default-features = false, path = "../../../../primitives/core" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" } diff --git a/frame/support/test/pallet/Cargo.toml b/frame/support/test/pallet/Cargo.toml index c26fdda4e9624..51b74d5ec55fe 100644 --- a/frame/support/test/pallet/Cargo.toml +++ b/frame/support/test/pallet/Cargo.toml @@ -12,8 +12,8 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index b4a10a6af01f1..e9d267274a6ed 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -49,7 +49,7 @@ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is | = note: required because of the requirements on the impl of `Encode` for `::Bar` note: required by a bound in `encode_to` - --> $CARGO/parity-scale-codec-2.3.1/src/codec.rs + --> $CARGO/parity-scale-codec-3.0.0/src/codec.rs | | fn encode_to(&self, dest: &mut T) { | ^^^^^^ required by this bound in `encode_to` @@ -63,7 +63,7 @@ error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is | = note: required because of the requirements on the impl of `Decode` for `::Bar` note: required by a bound in `parity_scale_codec::Decode::decode` - --> $CARGO/parity-scale-codec-2.3.1/src/codec.rs + --> $CARGO/parity-scale-codec-3.0.0/src/codec.rs | | fn decode(input: &mut I) -> Result; | ^^^^^ required by this bound in `parity_scale_codec::Decode::decode` diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 5d45544fe7bb0..a941f6e95edea 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index fa86250c199e5..858d6954405fe 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } diff --git a/frame/system/rpc/runtime-api/Cargo.toml b/frame/system/rpc/runtime-api/Cargo.toml index 67e627f7dcf98..e2f85000f5d05 100644 --- a/frame/system/rpc/runtime-api/Cargo.toml +++ b/frame/system/rpc/runtime-api/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } [features] default = ["std"] diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index f42a95010587a..8cb78c2164324 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io", optional = true } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index f898a255b87c8..78e260e2368c7 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -13,9 +13,9 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 1f27e355b1d99..fe6b4e0e2c7ca 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } smallvec = "1.7.0" diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 6f42595d200c9..7768ae76847ae 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -24,8 +24,8 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../../ pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = ".." } # Other dependencies -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } [dev-dependencies] diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 844e898ed867f..f5d5036978b44 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index fed57eb5bf736..82bab82a305fa 100644 --- a/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../../../primitives/runtime" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment" } diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index f33607058f37b..e1275e2476f92 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true } hex-literal = { version = "0.3.4", optional = true } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index a7a210457f021..bbcffa68f083d 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -13,11 +13,11 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", "max-encoded-len", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.1" diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 4e0194b17acbc..e0761711501d2 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index ea3977c1b8b29..6397bf028eedc 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index f7dcfd9fa442f..52942c8670a32 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index ab81ed85f188d..c210201a31158 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-core = { version = "5.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index 6de20df8a41d4..bc72aaa81681b 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -181,7 +181,7 @@ fn generate_native_call_generators(decl: &ItemTrait) -> Result { { ::decode_with_depth_limit( #crate_::MAX_EXTRINSIC_DEPTH, - &#crate_::Encode::encode(input)[..], + &mut &#crate_::Encode::encode(input)[..], ).map_err(map_error) } )); diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index f6de60e1c99b8..ae18849d83ccc 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -86,7 +86,7 @@ fn generate_impl_call( let (#( #pnames ),*) : ( #( #ptypes ),* ) = match #c::DecodeLimit::decode_all_with_depth_limit( #c::MAX_EXTRINSIC_DEPTH, - &#input, + &mut #input, ) { Ok(res) => res, Err(e) => panic!("Bad input data provided to {}: {}", #fn_name_str, e), diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 064e6a6c98181..8edb2a31fb550 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -19,7 +19,7 @@ sp-tracing = { version = "4.0.0", path = "../../tracing" } sp-runtime = { version = "5.0.0", path = "../../runtime" } sp-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } sp-state-machine = { version = "0.11.0", path = "../../state-machine" } trybuild = "1.0.53" rustversion = "1.0.6" diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index 818ddbdcc1824..45622d6a53935 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "5.0.0", default-features = false, path = "../core" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "5.0.0", default-features = false, path = "../io" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index e3294ff749855..26b0fbcf98d01 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -15,10 +15,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } integer-sqrt = "0.1.2" static_assertions = "1.1.0" num-traits = { version = "0.2.8", default-features = false } @@ -29,7 +29,7 @@ sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debu [dev-dependencies] rand = "0.7.2" criterion = "0.3" -primitive-types = "0.10.1" +primitive-types = "0.11.1" [features] default = ["std"] diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index 33951687c3138..d715515056bb7 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-arithmetic = { version = "4.0.0", path = ".." } honggfuzz = "0.5.49" -primitive-types = "0.10.1" +primitive-types = "0.11.1" num-bigint = "0.2" [[bin]] diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index 7c6aa7a6ea002..adbeeb473f2af 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } -codec = { package = "parity-scale-codec", default-features = false, version = "2.0.0" } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0" } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index 4cf8e6e9522d1..93b3a43eda173 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } async-trait = { version = "0.1.50", optional = true } [features] diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 9d8ec2a653ea0..b51c5b4948e12 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -8,8 +8,8 @@ repository = "https://github.com/paritytech/substrate" description = "Primitives for BEEFY protocol." [dependencies] -codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../api", default-features = false } sp-application-crypto = { version = "5.0.0", path = "../application-crypto", default-features = false } diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index 28f76343c7e98..6f0fe32db2fa8 100644 --- a/primitives/block-builder/Cargo.toml +++ b/primitives/block-builder/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } [features] diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 89737dbac0c6b..69aa7c049f880 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.11" lru = "0.7.0" -parking_lot = "0.11.2" +parking_lot = "0.12.0" thiserror = "1.0.30" futures = "0.3.9" -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sp-runtime = { version = "5.0.0", path = "../runtime" } sp-state-machine = { version = "0.11.0", path = "../state-machine" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index e78de2db17b39..a51d4aaeabec6 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../application-crypto" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index b677f44702849..cf276c998f115 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../application-crypto" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } merlin = { version = "2.0", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 2717de72d1e31..d6c31876fa8da 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.42" -codec = { package = "parity-scale-codec", version = "2.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = { version = "0.3.1", features = ["thread-pool"] } diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index f70af90afd6d3..d5c8aa9613b39 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -17,7 +17,7 @@ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } sp-core = { version = "5.0.0", default-features = false, path = "../../core" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } [features] default = ["std"] diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index aed2265bddca6..5c8161ddcbe22 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0", features = ["derive"], optional = true } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../arithmetic" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 3277a3ff96916..db453f62e8010 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { version = "2.0.0", package = "parity-scale-codec", default-features = false } +codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } sp-std = { version = "4.0.0", path = "../../std", default-features = false } sp-core = { version = "5.0.0", path = "../../core", default-features = false } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 08d5cdb87e60d..ab0f38ec109c7 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -13,15 +13,15 @@ documentation = "https://docs.rs/sp-core" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", "max-encoded-len", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.11", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } -primitive-types = { version = "0.10.1", default-features = false, features = ["codec", "scale-info"] } +primitive-types = { version = "0.11.1", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.3.0", optional = true } wasmi = { version = "0.9.1", optional = true } hash-db = { version = "0.15.2", default-features = false } @@ -35,12 +35,12 @@ num-traits = { version = "0.2.8", default-features = false } zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } -parking_lot = { version = "0.11.2", optional = true } +parking_lot = { version = "0.12.0", optional = true } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } sp-storage = { version = "5.0.0", default-features = false, path = "../storage" } sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } -parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } futures = { version = "0.3.1", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/database/Cargo.toml b/primitives/database/Cargo.toml index 6c3eea9aa1f98..198f44510209e 100644 --- a/primitives/database/Cargo.toml +++ b/primitives/database/Cargo.toml @@ -11,6 +11,6 @@ documentation = "https://docs.rs/sp-database" readme = "README.md" [dependencies] -parking_lot = "0.11.2" -kvdb = "0.10.0" +parking_lot = "0.12.0" +kvdb = "0.11.0" diff --git a/primitives/externalities/Cargo.toml b/primitives/externalities/Cargo.toml index 7b7beb51e7809..f47f0ba494a71 100644 --- a/primitives/externalities/Cargo.toml +++ b/primitives/externalities/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-storage = { version = "5.0.0", path = "../storage", default-features = false } sp-std = { version = "4.0.0", path = "../std", default-features = false } environmental = { version = "1.1.3", default-features = false } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } [features] default = ["std"] diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index a05636d44a563..a40873ef4c2f3 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -15,9 +15,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } -grandpa = { package = "finality-grandpa", version = "0.14.1", default-features = false, features = ["derive-codec"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +grandpa = { package = "finality-grandpa", version = "0.15.0", default-features = false, features = ["derive-codec"] } log = { version = "0.4.8", optional = true } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index f78f4aea14e47..4fe1c75b52ae2 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-core = { version = "5.0.0", default-features = false, path = "../core" } sp-runtime = { version = "5.0.0", path = "../runtime", optional = true } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } impl-trait-for-tuples = "0.2.0" async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index b9cbdbaa70e77..b28db8c1ff3dc 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } hash-db = { version = "0.15.2", default-features = false } sp-core = { version = "5.0.0", default-features = false, path = "../core" } sp-keystore = { version = "0.11.0", default-features = false, optional = true, path = "../keystore" } @@ -29,7 +29,7 @@ sp-externalities = { version = "0.11.0", optional = true, path = "../externaliti sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.8", optional = true } futures = { version = "0.3.1", features = ["thread-pool"], optional = true } -parking_lot = { version = "0.11.2", optional = true } +parking_lot = { version = "0.12.0", optional = true } tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.17", default-features = false} diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 26748d3227d6f..182a5f494fbca 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" futures = "0.3.1" -parking_lot = { version = "0.11.2", default-features = false } +parking_lot = { version = "0.12.0", default-features = false } serde = { version = "1.0", optional = true } thiserror = "1.0" -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } merlin = { version = "2.0", default-features = false } sp-core = { version = "5.0.0", path = "../core" } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 88475e10f732c..6d70658c27017 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 335195e9bf5b1..0c6c44ced7f4e 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -18,8 +18,8 @@ clap = { version = "3.0", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } sp-runtime = { version = "5.0.0", path = "../../runtime" } diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index cfb3af4552e2e..5b45bb246f396 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -21,8 +21,8 @@ proc-macro2 = "1.0.36" proc-macro-crate = "1.1.0" [dev-dependencies] -parity-scale-codec = "2.3.1" -scale-info = "1.0" +parity-scale-codec = "3.0.0" +scale-info = "2.0.0" sp-arithmetic = { path = "../../arithmetic", version = "4.0.0" } # used by generate_solution_type: sp-npos-elections = { path = "..", version = "4.0.0-dev" } diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 89805a9db36dd..e227a7b63cded 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -19,9 +19,9 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } sp-runtime-interface-proc-macro = { version = "4.0.0", path = "proc-macro" } sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } static_assertions = "1.0.0" -primitive-types = { version = "0.10.1", default-features = false } +primitive-types = { version = "0.11.1", default-features = false } sp-storage = { version = "5.0.0", default-features = false, path = "../storage" } impl-trait-for-tuples = "0.2.1" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 7b58482b2c36e..7c7e74b600531 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-core = { version = "5.0.0", default-features = false, path = "../core" } sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } @@ -27,7 +27,7 @@ log = { version = "0.4.14", default-features = false } paste = "1.0" rand = { version = "0.7.2", optional = true } impl-trait-for-tuples = "0.2.1" -parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } hash256-std-hasher = { version = "0.15.2", default-features = false } either = { version = "1.5", default-features = false } diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index a72786807330d..e04df06f2828e 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -24,7 +24,7 @@ sp-core = { version = "5.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "5.0.0", default-features = false, path = "../io" } sp-wasm-interface = { version = "5.0.0", default-features = false, path = "../wasm-interface" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4", default-features = false } [dev-dependencies] diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index 4138ecb519df6..abc4b60cfc322 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-core = { version = "5.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 54e556dfae122..408dcb8605962 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 15720688c0585..300af627f71ba 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -16,14 +16,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.11", optional = true } thiserror = { version = "1.0.30", optional = true } -parking_lot = { version = "0.11.2", optional = true } +parking_lot = { version = "0.12.0", optional = true } hash-db = { version = "0.15.2", default-features = false } -trie-db = { version = "0.23.0", default-features = false } +trie-db = { version = "0.23.1", default-features = false } trie-root = { version = "0.17.0", default-features = false } sp-trie = { version = "5.0.0", path = "../trie", default-features = false } sp-core = { version = "5.0.0", path = "../core", default-features = false } sp-panic-handler = { version = "4.0.0", path = "../panic-handler", optional = true } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } num-traits = { version = "0.2.8", default-features = false } rand = { version = "0.7.2", optional = true } sp-externalities = { version = "0.11.0", path = "../externalities", default-features = false } diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index 7d1a8c03c0a09..f6fe678c370b7 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -19,7 +19,7 @@ serde = { version = "1.0.136", optional = true, features = ["derive"] } impl-serde = { version = "0.3.1", optional = true } ref-cast = "1.0.0" sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } [features] default = [ "std" ] diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index 00943e8657205..3cf4a583d60e9 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -22,7 +22,7 @@ sp-runtime-interface = { version = "5.0.0", default-features = false, path = ".. sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] -codec = { package = "parity-scale-codec", default-features = false, version = "2.0.0" } +codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0" } [features] default = ["std"] diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 101a9249bf707..2c13f0f8d64f0 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -13,11 +13,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-core = { version = "5.0.0", default-features = false, path = "../core" } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } -parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } [features] default = [ diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index f7ac2e663e397..ec112ac5916f4 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } thiserror = { version = "1.0.30", optional = true } log = { version = "0.4.8", optional = true } diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index 0b5a273e11d39..3c3149a8b4713 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] [dependencies] sp-std = { version = "4.0.0", path = "../std", default-features = false } -codec = { version = "2.0.0", package = "parity-scale-codec", default-features = false, features = [ +codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = [ "derive", ] } tracing = { version = "0.1.29", default-features = false } diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index 9e2898fe267e1..ca285323f2923 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -18,8 +18,8 @@ sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-trie = { version = "5.0.0", optional = true, path = "../trie" } sp-core = { version = "5.0.0", path = "../core", optional = true } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.8", optional = true } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index e79f2ffb7f845..022dd606ba110 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -18,17 +18,17 @@ name = "bench" harness = false [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } hash-db = { version = "0.15.2", default-features = false } -trie-db = { version = "0.23.0", default-features = false } +trie-db = { version = "0.23.1", default-features = false } trie-root = { version = "0.17.0", default-features = false } -memory-db = { version = "0.28.0", default-features = false } +memory-db = { version = "0.29.0", default-features = false } sp-core = { version = "5.0.0", default-features = false, path = "../core" } [dev-dependencies] -trie-bench = "0.29.0" +trie-bench = "0.30.0" trie-standardmap = "0.15.2" criterion = "0.3.3" hex-literal = "0.3.4" diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 053ba49fd82fb..590bf081eb060 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] impl-serde = { version = "0.3.1", optional = true } serde = { version = "1.0.136", optional = true, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" } diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index a706f74f45229..c8f59f4fca257 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.36" -codec = { package = "parity-scale-codec", version = "2.0.0", features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } [dev-dependencies] sp-version = { version = "4.0.0-dev", path = ".." } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index bb82629ba01e8..acf22f189b87b 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -19,7 +19,7 @@ wasmtime = { version = "0.33.0", optional = true, default-features = false } log = { version = "0.4.14", optional = true } impl-trait-for-tuples = "0.2.1" sp-std = { version = "4.0.0", path = "../std", default-features = false } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } [features] default = [ "std" ] diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index a74d7b5835273..ffddda3ac1f53 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -12,7 +12,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.16" hex = "0.4" serde = "1.0.136" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 6529fa71106eb..b955aa07afa7f 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -17,11 +17,11 @@ sp-application-crypto = { version = "5.0.0", default-features = false, path = ". sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-keyring = { version = "5.0.0", optional = true, path = "../../primitives/keyring" } -memory-db = { version = "0.27.0", default-features = false } +memory-db = { version = "0.29.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -39,8 +39,8 @@ pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = ".. sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } sp-trie = { version = "5.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } -trie-db = { version = "0.23.0", default-features = false } -parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } +trie-db = { version = "0.23.1", default-features = false } +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } sp-state-machine = { version = "0.11.0", default-features = false, path = "../../primitives/state-machine" } sp-externalities = { version = "0.11.0", default-features = false, path = "../../primitives/externalities" } diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index fd260453ca181..3491a7a09f9ca 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -21,6 +21,6 @@ substrate-test-runtime = { version = "2.0.0", path = "../../runtime" } sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } futures = "0.3.9" diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index ef2ebd64fb225..edb2efdb273f4 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -13,8 +13,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../client" } -parking_lot = "0.11.2" -codec = { package = "parity-scale-codec", version = "2.0.0" } +parking_lot = "0.12.0" +codec = { package = "parity-scale-codec", version = "3.0.0" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } diff --git a/utils/fork-tree/Cargo.toml b/utils/fork-tree/Cargo.toml index cdfce5592f2fa..4ac176f645bd1 100644 --- a/utils/fork-tree/Cargo.toml +++ b/utils/fork-tree/Cargo.toml @@ -14,4 +14,4 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 9e2de0e8c358a..bbfcbb7e8b818 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -24,7 +24,7 @@ sp-externalities = { version = "0.11.0", path = "../../../primitives/externaliti sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } -codec = { version = "2.0.0", package = "parity-scale-codec" } +codec = { version = "3.0.0", package = "parity-scale-codec" } clap = { version = "3.0", features = ["derive"] } chrono = "0.4" serde = "1.0.136" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index cf8a0f6069879..ec05b7133412a 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -18,7 +18,7 @@ jsonrpsee = { version = "0.8", features = ["ws-client", "macros"] } env_logger = "0.9" frame-support = { path = "../../../frame/support", optional = true, version = "4.0.0-dev" } log = "0.4.11" -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } serde_json = "1.0" serde = "1.0.136" diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index fcb5a4367386d..b255f5ab2a794 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.16" jsonrpc-client-transports = { version = "18.0.0", features = ["http"] } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } sp-storage = { version = "5.0.0", path = "../../../../primitives/storage" } @@ -25,5 +25,5 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } [dev-dependencies] frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } -scale-info = "1.0" +scale-info = "2.0.0" tokio = "1.15" diff --git a/utils/frame/rpc/support/src/lib.rs b/utils/frame/rpc/support/src/lib.rs index 9cf99ddf97b09..5d7cba19f643c 100644 --- a/utils/frame/rpc/support/src/lib.rs +++ b/utils/frame/rpc/support/src/lib.rs @@ -126,7 +126,7 @@ impl StorageQuery { block_index: Option, ) -> Result, RpcError> { let opt: Option = state_client.storage(self.key, block_index).await?; - opt.map(|encoded| V::decode_all(&encoded.0)) + opt.map(|encoded| V::decode_all(&mut &encoded.0[..])) .transpose() .map_err(|decode_err| RpcError::Other(Box::new(decode_err))) } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 8ce72416dac2a..950cbd09b2785 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } -codec = { package = "parity-scale-codec", version = "2.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.16" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 12380e2d3272f..27129f38acc7a 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "3.0", features = ["derive"] } log = "0.4.8" -parity-scale-codec = { version = "2.3.1" } +parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = "0.9.0" From b8c5b846617f837116e63ab1794a5310fb960246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 25 Feb 2022 16:01:33 +0100 Subject: [PATCH 0548/1472] sc-cli: Fix bugs after switching to clap3 (#10920) * sc-cli: Fix bugs after switching to clap3 Before switching to clap3 we support cli options like `--reserved-nodes A B` and after you needed to pass `--reserved-nodes` cli option multiple times `--reserved-nodes A --reserved-nodes B`. This is fixed by setting `multiple_occurrences(true)` option. This also done for all the other `Vec` cli options in `sc-cli`. Besides that `--sync` wasn't supporting case insensitive parsing of the value. This is now also supported. For both regressions a test is added. Besides that the pr removes all the `rename_all = PascalCase` attributes, because they are not needed. All other `ArgEnum`s were checked and all are already using `ignore_case(true)`. * Bring back `PascalCase`, because otherwise it falls back to `kebab-case`... --- client/cli/src/arg_enums.rs | 44 +++++++++++------- client/cli/src/params/network_params.rs | 62 +++++++++++++++++++++++-- client/cli/src/params/shared_params.rs | 2 +- client/network/src/config.rs | 2 +- 4 files changed, 87 insertions(+), 23 deletions(-) diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index 249e3c639e4ef..a5403e3497c94 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -15,8 +15,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// NOTE: we allow missing docs here because arg_enum! creates the function variants without doc -#![allow(missing_docs)] + +//! Definitions of [`ArgEnum`] types. use clap::ArgEnum; @@ -90,6 +90,7 @@ impl Into for WasmExecutionMethod { #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] #[clap(rename_all = "PascalCase")] pub enum TracingReceiver { + /// Output the tracing records using the log. Log, } @@ -101,25 +102,33 @@ impl Into for TracingReceiver { } } -#[allow(missing_docs)] +/// The type of the node key. #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] #[clap(rename_all = "PascalCase")] pub enum NodeKeyType { + /// Use ed25519. Ed25519, } +/// The crypto scheme to use. #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] #[clap(rename_all = "PascalCase")] pub enum CryptoScheme { + /// Use ed25519. Ed25519, + /// Use sr25519. Sr25519, + /// Use Ecdsa, } +/// The type of the output format. #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] #[clap(rename_all = "PascalCase")] pub enum OutputType { + /// Output as json. Json, + /// Output as text. Text, } @@ -127,13 +136,13 @@ pub enum OutputType { #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] #[clap(rename_all = "PascalCase")] pub enum ExecutionStrategy { - // Execute with native build (if available, WebAssembly otherwise). + /// Execute with native build (if available, WebAssembly otherwise). Native, - // Only execute with the WebAssembly build. + /// Only execute with the WebAssembly build. Wasm, - // Execute with both native (where available) and WebAssembly builds. + /// Execute with both native (where available) and WebAssembly builds. Both, - // Execute with the native build if possible; if it fails, then execute with WebAssembly. + /// Execute with the native build if possible; if it fails, then execute with WebAssembly. NativeElseWasm, } @@ -165,12 +174,12 @@ impl ExecutionStrategy { #[derive(Debug, Copy, Clone, PartialEq, ArgEnum)] #[clap(rename_all = "PascalCase")] pub enum RpcMethods { - // Expose every RPC method only when RPC is listening on `localhost`, - // otherwise serve only safe RPC methods. + /// Expose every RPC method only when RPC is listening on `localhost`, + /// otherwise serve only safe RPC methods. Auto, - // Allow only a safe subset of RPC methods. + /// Allow only a safe subset of RPC methods. Safe, - // Expose every RPC method (even potentially unsafe ones). + /// Expose every RPC method (even potentially unsafe ones). Unsafe, } @@ -224,22 +233,25 @@ impl Database { #[derive(Debug, Clone, ArgEnum)] #[clap(rename_all = "PascalCase")] pub enum OffchainWorkerEnabled { + /// Always have offchain worker enabled. Always, + /// Never enable the offchain worker. Never, + /// Only enable the offchain worker when running as validator. WhenValidating, } /// Syncing mode. -#[derive(Debug, Clone, Copy, ArgEnum)] +#[derive(Debug, Clone, Copy, ArgEnum, PartialEq)] #[clap(rename_all = "PascalCase")] pub enum SyncMode { - // Full sync. Donwnload end verify all blocks. + /// Full sync. Download end verify all blocks. Full, - // Download blocks without executing them. Download latest state with proofs. + /// Download blocks without executing them. Download latest state with proofs. Fast, - // Download blocks without executing them. Download latest state without proofs. + /// Download blocks without executing them. Download latest state without proofs. FastUnsafe, - // Prove finality and download the latest state. + /// Prove finality and download the latest state. Warp, } diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 1de2896cba731..7a265c5e27609 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -34,11 +34,11 @@ use std::{borrow::Cow, path::PathBuf}; #[derive(Debug, Clone, Args)] pub struct NetworkParams { /// Specify a list of bootnodes. - #[clap(long, value_name = "ADDR")] + #[clap(long, value_name = "ADDR", multiple_values(true))] pub bootnodes: Vec, /// Specify a list of reserved node addresses. - #[clap(long, value_name = "ADDR")] + #[clap(long, value_name = "ADDR", multiple_values(true))] pub reserved_nodes: Vec, /// Whether to only synchronize the chain with reserved nodes. @@ -54,7 +54,7 @@ pub struct NetworkParams { /// The public address that other nodes will use to connect to it. /// This can be used if there's a proxy in front of this node. - #[clap(long, value_name = "PUBLIC_ADDR")] + #[clap(long, value_name = "PUBLIC_ADDR", multiple_values(true))] pub public_addr: Vec, /// Listen on this multiaddress. @@ -62,7 +62,7 @@ pub struct NetworkParams { /// By default: /// If `--validator` is passed: `/ip4/0.0.0.0/tcp/` and `/ip6/[::]/tcp/`. /// Otherwise: `/ip4/0.0.0.0/tcp//ws` and `/ip6/[::]/tcp//ws`. - #[clap(long, value_name = "LISTEN_ADDR")] + #[clap(long, value_name = "LISTEN_ADDR", multiple_values(true))] pub listen_addr: Vec, /// Specify p2p protocol TCP port. @@ -137,7 +137,7 @@ pub struct NetworkParams { /// - `Fast`: Download blocks and the latest state only. /// /// - `FastUnsafe`: Same as `Fast`, but skip downloading state proofs. - #[clap(long, arg_enum, value_name = "SYNC_MODE", default_value = "Full")] + #[clap(long, arg_enum, value_name = "SYNC_MODE", default_value = "Full", ignore_case(true))] pub sync: SyncMode, } @@ -237,3 +237,55 @@ impl NetworkParams { } } } + +#[cfg(test)] +mod tests { + use super::*; + use clap::Parser; + + #[derive(Parser)] + struct Cli { + #[clap(flatten)] + network_params: NetworkParams, + } + + #[test] + fn reserved_nodes_multiple_values_and_occurrences() { + let params = Cli::try_parse_from([ + "", + "--reserved-nodes", + "/ip4/0.0.0.0/tcp/501/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS", + "/ip4/0.0.0.0/tcp/502/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS", + "--reserved-nodes", + "/ip4/0.0.0.0/tcp/503/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS", + ]) + .expect("Parses network params"); + + let expected = vec![ + MultiaddrWithPeerId::try_from( + "/ip4/0.0.0.0/tcp/501/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS" + .to_string(), + ) + .unwrap(), + MultiaddrWithPeerId::try_from( + "/ip4/0.0.0.0/tcp/502/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS" + .to_string(), + ) + .unwrap(), + MultiaddrWithPeerId::try_from( + "/ip4/0.0.0.0/tcp/503/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS" + .to_string(), + ) + .unwrap(), + ]; + + assert_eq!(expected, params.network_params.reserved_nodes); + } + + #[test] + fn sync_ingores_case() { + let params = Cli::try_parse_from(["", "--sync", "wArP"]).expect("Parses network params"); + + assert_eq!(SyncMode::Warp, params.network_params.sync); + } +} diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index a4f2271e12c48..4066a75a9353b 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -46,7 +46,7 @@ pub struct SharedParams { /// /// Log levels (least to most verbose) are error, warn, info, debug, and trace. /// By default, all targets log `info`. The global log level can be set with -l. - #[clap(short = 'l', long, value_name = "LOG_PATTERN")] + #[clap(short = 'l', long, value_name = "LOG_PATTERN", multiple_values(true))] pub log: Vec, /// Enable detailed log output. diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 3b9c864c37927..a7e4e5cc87668 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -295,7 +295,7 @@ pub fn parse_addr(mut addr: Multiaddr) -> Result<(PeerId, Multiaddr), ParseErr> /// assert_eq!(addr.peer_id.to_base58(), "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"); /// assert_eq!(addr.multiaddr.to_string(), "/ip4/198.51.100.19/tcp/30333"); /// ``` -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)] #[serde(try_from = "String", into = "String")] pub struct MultiaddrWithPeerId { /// Address of the node. From dfe52f7de12a7e308c0bc3a25e211b9cc4d61871 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 25 Feb 2022 20:30:57 +0100 Subject: [PATCH 0549/1472] Storage benchmarking (#10897) * WIP Signed-off-by: Oliver Tale-Yazdi * WIP: DB benchmarking Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * Simplify code Signed-off-by: Oliver Tale-Yazdi * Remove old files Signed-off-by: Oliver Tale-Yazdi * Remove old files Signed-off-by: Oliver Tale-Yazdi * Minimize changes Signed-off-by: Oliver Tale-Yazdi * Add license Signed-off-by: Oliver Tale-Yazdi * Remove dependencies Signed-off-by: Oliver Tale-Yazdi * Extend template Signed-off-by: Oliver Tale-Yazdi * Linter Signed-off-by: Oliver Tale-Yazdi * Linter Signed-off-by: Oliver Tale-Yazdi * Beauty fixes Signed-off-by: Oliver Tale-Yazdi * Remove default Signed-off-by: Oliver Tale-Yazdi * Add feature Signed-off-by: Oliver Tale-Yazdi * Remove seed Signed-off-by: Oliver Tale-Yazdi * CI wakeup Signed-off-by: Oliver Tale-Yazdi * Fmt Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Adding doc Signed-off-by: Oliver Tale-Yazdi * Adding doc Signed-off-by: Oliver Tale-Yazdi * Improve template Signed-off-by: Oliver Tale-Yazdi * Do not expose columns Signed-off-by: Oliver Tale-Yazdi * Fix ColumnId Signed-off-by: Oliver Tale-Yazdi * Nicer template prints Signed-off-by: Oliver Tale-Yazdi * Cleanup Signed-off-by: Oliver Tale-Yazdi * Fix json path Signed-off-by: Oliver Tale-Yazdi * Simplify `bench_write` logic Signed-off-by: Oliver Tale-Yazdi * Invert tx before the second commit Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 31 ++- bin/node/cli/src/cli.rs | 4 + bin/node/cli/src/command.rs | 16 ++ client/cli/src/arg_enums.rs | 2 +- client/cli/src/params/database_params.rs | 2 +- client/cli/src/params/pruning_params.rs | 2 +- client/cli/src/params/shared_params.rs | 2 +- client/db/Cargo.toml | 1 + client/db/src/lib.rs | 20 +- utils/frame/benchmarking-cli/Cargo.toml | 17 +- utils/frame/benchmarking-cli/src/lib.rs | 3 + .../frame/benchmarking-cli/src/storage/cmd.rs | 171 ++++++++++++++++ .../frame/benchmarking-cli/src/storage/mod.rs | 24 +++ .../benchmarking-cli/src/storage/read.rs | 76 +++++++ .../benchmarking-cli/src/storage/record.rs | 191 ++++++++++++++++++ .../benchmarking-cli/src/storage/template.rs | 126 ++++++++++++ .../benchmarking-cli/src/storage/weights.hbs | 107 ++++++++++ .../benchmarking-cli/src/storage/write.rs | 131 ++++++++++++ utils/frame/benchmarking-cli/src/writer.rs | 2 +- 19 files changed, 917 insertions(+), 11 deletions(-) create mode 100644 utils/frame/benchmarking-cli/src/storage/cmd.rs create mode 100644 utils/frame/benchmarking-cli/src/storage/mod.rs create mode 100644 utils/frame/benchmarking-cli/src/storage/read.rs create mode 100644 utils/frame/benchmarking-cli/src/storage/record.rs create mode 100644 utils/frame/benchmarking-cli/src/storage/template.rs create mode 100644 utils/frame/benchmarking-cli/src/storage/weights.hbs create mode 100644 utils/frame/benchmarking-cli/src/storage/write.rs diff --git a/Cargo.lock b/Cargo.lock index 58297393c834d..826ed90d4553b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2127,20 +2127,34 @@ dependencies = [ "frame-benchmarking", "frame-support", "handlebars", + "hash-db", + "hex", + "itertools", + "kvdb", "linked-hash-map", "log 0.4.14", + "memory-db", "parity-scale-codec", + "rand 0.8.4", "sc-cli", + "sc-client-api", "sc-client-db", "sc-executor", "sc-service", "serde", "serde_json", + "serde_nanos", + "sp-api", + "sp-blockchain", "sp-core", + "sp-database", "sp-externalities", "sp-keystore", "sp-runtime", "sp-state-machine", + "sp-std", + "sp-storage", + "sp-trie", ] [[package]] @@ -3151,9 +3165,9 @@ checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" [[package]] name = "itertools" -version = "0.10.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ "either", ] @@ -7414,9 +7428,9 @@ dependencies = [ [[package]] name = "rand_distr" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "051b398806e42b9cd04ad9ec8f81e355d0a382c543ac6672c62f5a5b452ef142" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ "num-traits", "rand 0.8.4", @@ -9289,6 +9303,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_nanos" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e44969a61f5d316be20a42ff97816efb3b407a924d06824c3d8a49fa8450de0e" +dependencies = [ + "serde", +] + [[package]] name = "sha-1" version = "0.8.2" diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 00393c52f8b68..386215854b963 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -42,6 +42,10 @@ pub enum Subcommand { #[clap(name = "benchmark", about = "Benchmark runtime pallets.")] Benchmark(frame_benchmarking_cli::BenchmarkCmd), + /// Sub command for benchmarking the storage speed. + #[clap(name = "benchmark-storage", about = "Benchmark storage speed.")] + BenchmarkStorage(frame_benchmarking_cli::StorageCmd), + /// Try some command against runtime state. #[cfg(feature = "try-runtime")] TryRuntime(try_runtime_cli::TryRuntimeCmd), diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index d9ba53785ba0c..cc6480bb90d55 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -95,6 +95,22 @@ pub fn run() -> Result<()> { You can enable it with `--features runtime-benchmarks`." .into()) }, + Some(Subcommand::BenchmarkStorage(cmd)) => { + if !cfg!(feature = "runtime-benchmarks") { + return Err("Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + .into()) + } + + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?; + let db = backend.expose_db(); + let storage = backend.expose_storage(); + + Ok((cmd.run(config, client, db, storage), task_manager)) + }) + }, Some(Subcommand::Key(cmd)) => cmd.run(&cli), Some(Subcommand::Sign(cmd)) => cmd.run(), Some(Subcommand::Verify(cmd)) => cmd.run(), diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index a5403e3497c94..7c9974fff38a5 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -194,7 +194,7 @@ impl Into for RpcMethods { } /// Database backend -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, PartialEq, Copy)] pub enum Database { /// Facebooks RocksDB RocksDb, diff --git a/client/cli/src/params/database_params.rs b/client/cli/src/params/database_params.rs index dd11c21f432b1..70c929ecf202f 100644 --- a/client/cli/src/params/database_params.rs +++ b/client/cli/src/params/database_params.rs @@ -21,7 +21,7 @@ use clap::Args; use sc_service::TransactionStorageMode; /// Parameters for block import. -#[derive(Debug, Clone, Args)] +#[derive(Debug, Clone, PartialEq, Args)] pub struct DatabaseParams { /// Select database backend to use. #[clap( diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index a8516ee1453ac..de9628ecf7ad9 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -21,7 +21,7 @@ use clap::Args; use sc_service::{KeepBlocks, PruningMode, Role}; /// Parameters to define the pruning mode -#[derive(Debug, Clone, Args)] +#[derive(Debug, Clone, PartialEq, Args)] pub struct PruningParams { /// Specify the state pruning mode, a number of blocks to keep or 'archive'. /// diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 4066a75a9353b..99eddf4e7c4b7 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -22,7 +22,7 @@ use sc_service::config::BasePath; use std::path::PathBuf; /// Shared parameters used by all `CoreParams`. -#[derive(Debug, Clone, Args)] +#[derive(Debug, Clone, PartialEq, Args)] pub struct SharedParams { /// Specify the chain specification. /// diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 82607f56f7d1f..a9fa370a8ead2 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -45,5 +45,6 @@ tempfile = "3" [features] default = [] test-helpers = [] +runtime-benchmarks = [] with-kvdb-rocksdb = ["kvdb-rocksdb"] with-parity-db = ["parity-db"] diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index a2d0cad72845f..3fd3bf8d09042 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -106,7 +106,8 @@ const DEFAULT_CHILD_RATIO: (usize, usize) = (1, 10); pub type DbState = sp_state_machine::TrieBackend>>, HashFor>; -const DB_HASH_LEN: usize = 32; +/// Length of a [`DbHash`]. +pub const DB_HASH_LEN: usize = 32; /// Hash type that this backend uses for the database. pub type DbHash = sp_core::H256; @@ -1050,6 +1051,23 @@ impl Backend { Self::new(db_setting, canonicalization_delay).expect("failed to create test-db") } + /// Expose the Database that is used by this backend. + /// The second argument is the Column that stores the State. + /// + /// Should only be needed for benchmarking. + #[cfg(any(feature = "runtime-benchmarks"))] + pub fn expose_db(&self) -> (Arc>, sp_database::ColumnId) { + (self.storage.db.clone(), columns::STATE) + } + + /// Expose the Storage that is used by this backend. + /// + /// Should only be needed for benchmarking. + #[cfg(any(feature = "runtime-benchmarks"))] + pub fn expose_storage(&self) -> Arc>> { + self.storage.clone() + } + fn from_database( db: Arc>, canonicalization_delay: u64, diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index bbfcbb7e8b818..dc6c5eb221652 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -17,13 +17,21 @@ frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarkin frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } sp-core = { version = "5.0.0", path = "../../../primitives/core" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } +sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } + +sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-externalities = { version = "0.11.0", path = "../../../primitives/externalities" } +sp-database = { version = "4.0.0-dev", path = "../../../primitives/database" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } +sp-storage = { version = "5.0.0", path = "../../../primitives/storage" } sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } +sp-trie = { version = "5.0.0", path = "../../../primitives/trie" } codec = { version = "3.0.0", package = "parity-scale-codec" } clap = { version = "3.0", features = ["derive"] } chrono = "0.4" @@ -33,7 +41,14 @@ handlebars = "4.1.6" Inflector = "0.11.4" linked-hash-map = "0.5.4" log = "0.4.8" +itertools = "0.10.3" +serde_nanos = "0.1.2" +kvdb = "0.11.0" +hash-db = "0.15.2" +hex = "0.4.3" +memory-db = "0.29.0" +rand = { version = "0.8.4", features = ["small_rng"] } [features] -default = ["db"] +default = ["db", "sc-client-db/runtime-benchmarks"] db = ["sc-client-db/with-kvdb-rocksdb", "sc-client-db/with-parity-db"] diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 3b0f4843d2065..56aab0321ccd0 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -16,11 +16,14 @@ // limitations under the License. mod command; +mod storage; mod writer; use sc_cli::{ExecutionStrategy, WasmExecutionMethod}; use std::{fmt::Debug, path::PathBuf}; +pub use storage::StorageCmd; + // Add a more relaxed parsing for pallet names by allowing pallet directory names with `-` to be // used like crate names with `_` fn parse_pallet_name(pallet: &str) -> String { diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs new file mode 100644 index 0000000000000..4376b616286a4 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -0,0 +1,171 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sc_cli::{CliConfiguration, DatabaseParams, PruningParams, Result, SharedParams}; +use sc_client_api::{Backend as ClientBackend, StorageProvider, UsageProvider}; +use sc_client_db::DbHash; +use sc_service::Configuration; +use sp_blockchain::HeaderBackend; +use sp_database::{ColumnId, Database}; +use sp_runtime::traits::{Block as BlockT, HashFor}; +use sp_state_machine::Storage; +use sp_storage::StateVersion; + +use clap::{Args, Parser}; +use log::info; +use rand::prelude::*; +use serde::Serialize; +use std::{fmt::Debug, sync::Arc}; + +use super::{record::StatSelect, template::TemplateData}; + +/// Benchmark the storage of a Substrate node with a live chain snapshot. +#[derive(Debug, Parser)] +pub struct StorageCmd { + #[allow(missing_docs)] + #[clap(flatten)] + pub shared_params: SharedParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub database_params: DatabaseParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub pruning_params: PruningParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub params: StorageParams, +} + +/// Parameters for modifying the benchmark behaviour and the post processing of the results. +#[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] +pub struct StorageParams { + /// Path to write the *weight* file to. Can be a file or directory. + /// For substrate this should be `frame/support/src/weights`. + #[clap(long, default_value = ".")] + pub weight_path: String, + + /// Select a specific metric to calculate the final weight output. + #[clap(long = "metric", default_value = "average")] + pub weight_metric: StatSelect, + + /// Multiply the resulting weight with the given factor. Must be positive. + /// Is calculated before `weight_add`. + #[clap(long = "mul", default_value = "1")] + pub weight_mul: f64, + + /// Add the given offset to the resulting weight. + /// Is calculated after `weight_mul`. + #[clap(long = "add", default_value = "0")] + pub weight_add: u64, + + /// Skip the `read` benchmark. + #[clap(long)] + pub skip_read: bool, + + /// Skip the `write` benchmark. + #[clap(long)] + pub skip_write: bool, + + /// Rounds of warmups before measuring. + /// Only supported for `read` benchmarks. + #[clap(long, default_value = "1")] + pub warmups: u32, + + /// The `StateVersion` to use. Substrate `--dev` should use `V1` and Polkadot `V0`. + /// Selecting the wrong version can corrupt the DB. + #[clap(long, possible_values = ["0", "1"])] + pub state_version: u8, + + /// State cache size. + #[clap(long, default_value = "0")] + pub state_cache_size: usize, +} + +impl StorageCmd { + /// Calls into the Read and Write benchmarking functions. + /// Processes the output and writes it into files and stdout. + pub async fn run( + &self, + cfg: Configuration, + client: Arc, + db: (Arc>, ColumnId), + storage: Arc>>, + ) -> Result<()> + where + BA: ClientBackend, + Block: BlockT, + C: UsageProvider + StorageProvider + HeaderBackend, + { + let mut template = TemplateData::new(&cfg, &self.params); + + if !self.params.skip_read { + let record = self.bench_read(client.clone())?; + record.save_json(&cfg, "read")?; + let stats = record.calculate_stats()?; + info!("Time summary [ns]:\n{:?}\nValue size summary:\n{:?}", stats.0, stats.1); + template.set_stats(Some(stats), None)?; + } + + if !self.params.skip_write { + let record = self.bench_write(client, db, storage)?; + record.save_json(&cfg, "write")?; + let stats = record.calculate_stats()?; + info!("Time summary [ns]:\n{:?}\nValue size summary:\n{:?}", stats.0, stats.1); + template.set_stats(None, Some(stats))?; + } + + template.write(&self.params.weight_path) + } + + /// Returns the specified state version. + pub(crate) fn state_version(&self) -> StateVersion { + match self.params.state_version { + 0 => StateVersion::V0, + 1 => StateVersion::V1, + _ => unreachable!("Clap set to only allow 0 and 1"), + } + } + + /// Creates an rng from a random seed. + pub(crate) fn setup_rng() -> impl rand::Rng { + let seed = rand::thread_rng().gen::(); + info!("Using seed {}", seed); + StdRng::seed_from_u64(seed) + } +} + +// Boilerplate +impl CliConfiguration for StorageCmd { + fn shared_params(&self) -> &SharedParams { + &self.shared_params + } + + fn database_params(&self) -> Option<&DatabaseParams> { + Some(&self.database_params) + } + + fn pruning_params(&self) -> Option<&PruningParams> { + Some(&self.pruning_params) + } + + fn state_cache_size(&self) -> Result { + Ok(self.params.state_cache_size) + } +} diff --git a/utils/frame/benchmarking-cli/src/storage/mod.rs b/utils/frame/benchmarking-cli/src/storage/mod.rs new file mode 100644 index 0000000000000..9849cbcb6097b --- /dev/null +++ b/utils/frame/benchmarking-cli/src/storage/mod.rs @@ -0,0 +1,24 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod cmd; +pub mod read; +pub mod record; +pub mod template; +pub mod write; + +pub use cmd::StorageCmd; diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs new file mode 100644 index 0000000000000..3974c4010f632 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -0,0 +1,76 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sc_cli::Result; +use sc_client_api::{Backend as ClientBackend, StorageProvider, UsageProvider}; +use sp_core::storage::StorageKey; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Header as HeaderT}, +}; + +use log::info; +use rand::prelude::*; +use std::{fmt::Debug, sync::Arc, time::Instant}; + +use super::{cmd::StorageCmd, record::BenchRecord}; + +impl StorageCmd { + /// Benchmarks the time it takes to read a single Storage item. + /// Uses the latest state that is available for the given client. + pub(crate) fn bench_read(&self, client: Arc) -> Result + where + C: UsageProvider + StorageProvider, + B: BlockT + Debug, + BA: ClientBackend, + <::Header as HeaderT>::Number: From, + { + let mut record = BenchRecord::default(); + let block = BlockId::Number(client.usage_info().chain.best_number); + + info!("Preparing keys from block {}", block); + // Load all keys and randomly shuffle them. + let empty_prefix = StorageKey(Vec::new()); + let mut keys = client.storage_keys(&block, &empty_prefix)?; + let mut rng = Self::setup_rng(); + keys.shuffle(&mut rng); + + // Run some rounds of the benchmark as warmup. + for i in 0..self.params.warmups { + info!("Warmup round {}/{}", i + 1, self.params.warmups); + for key in keys.clone() { + let _ = client + .storage(&block, &key) + .expect("Checked above to exist") + .ok_or("Value unexpectedly empty")?; + } + } + + // Interesting part here: + // Read all the keys in the database and measure the time it takes to access each. + info!("Reading {} keys", keys.len()); + for key in keys.clone() { + let start = Instant::now(); + let v = client + .storage(&block, &key) + .expect("Checked above to exist") + .ok_or("Value unexpectedly empty")?; + record.append(v.0.len(), start.elapsed())?; + } + Ok(record) + } +} diff --git a/utils/frame/benchmarking-cli/src/storage/record.rs b/utils/frame/benchmarking-cli/src/storage/record.rs new file mode 100644 index 0000000000000..00a613c713007 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/storage/record.rs @@ -0,0 +1,191 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Calculates statistics and fills out the `weight.hbs` template. + +use sc_cli::Result; +use sc_service::Configuration; + +use log::info; +use serde::Serialize; +use std::{fmt, fs, result, str::FromStr, time::Duration}; + +/// Raw output of a Storage benchmark. +#[derive(Debug, Default, Clone, Serialize)] +pub(crate) struct BenchRecord { + /// Multi-Map of value sizes and the time that it took to access them. + ns_per_size: Vec<(u64, u64)>, +} + +/// Various statistics that help to gauge the quality of the produced weights. +/// Will be written to the weight file and printed to console. +#[derive(Serialize, Default, Clone)] +pub(crate) struct Stats { + /// Sum of all values. + sum: u64, + /// Minimal observed value. + min: u64, + /// Maximal observed value. + max: u64, + + /// Average of all values. + avg: u64, + /// Median of all values. + median: u64, + /// Standard derivation of all values. + stddev: f64, + + /// 99th percentile. At least 99% of all values are below this threshold. + p99: u64, + /// 95th percentile. At least 95% of all values are below this threshold. + p95: u64, + /// 75th percentile. At least 75% of all values are below this threshold. + p75: u64, +} + +/// Selects a specific field from a [`Stats`] object. +/// Not all fields are available. +#[derive(Debug, Clone, Copy, Serialize, PartialEq)] +pub enum StatSelect { + /// Select the maximum. + Maximum, + /// Select the average. + Average, + /// Select the median. + Median, + /// Select the 99th percentile. + P99Percentile, + /// Select the 95th percentile. + P95Percentile, + /// Select the 75th percentile. + P75Percentile, +} + +impl BenchRecord { + /// Appends a new record. Uses safe casts. + pub fn append(&mut self, size: usize, d: Duration) -> Result<()> { + let size: u64 = size.try_into().map_err(|e| format!("Size overflow u64: {}", e))?; + let ns: u64 = d + .as_nanos() + .try_into() + .map_err(|e| format!("Nanoseconds overflow u64: {}", e))?; + self.ns_per_size.push((size, ns)); + Ok(()) + } + + /// Returns the statistics for *time* and *value size*. + pub(crate) fn calculate_stats(self) -> Result<(Stats, Stats)> { + let (size, time): (Vec<_>, Vec<_>) = self.ns_per_size.into_iter().unzip(); + let size = Stats::new(&size)?; + let time = Stats::new(&time)?; + Ok((time, size)) // The swap of time/size here is intentional. + } + + /// Saves the raw results in a json file in the current directory. + /// Prefixes it with the DB name and suffixed with `path_suffix`. + pub fn save_json(&self, cfg: &Configuration, path_suffix: &str) -> Result<()> { + let path = format!("{}_{}.json", cfg.database, path_suffix).to_lowercase(); + let json = serde_json::to_string_pretty(&self) + .map_err(|e| format!("Serializing as JSON: {:?}", e))?; + fs::write(&path, json)?; + info!("Raw data written to {:?}", fs::canonicalize(&path)?); + Ok(()) + } +} + +impl Stats { + /// Calculates statistics and returns them. + pub fn new(xs: &Vec) -> Result { + if xs.is_empty() { + return Err("Empty input is invalid".into()) + } + let (avg, stddev) = Self::avg_and_stddev(&xs); + + Ok(Self { + sum: xs.iter().sum(), + min: *xs.iter().min().expect("Checked for non-empty above"), + max: *xs.iter().max().expect("Checked for non-empty above"), + + avg: avg as u64, + median: Self::percentile(xs.clone(), 0.50), + stddev: (stddev * 100.0).round() / 100.0, // round to 1/100 + + p99: Self::percentile(xs.clone(), 0.99), + p95: Self::percentile(xs.clone(), 0.95), + p75: Self::percentile(xs.clone(), 0.75), + }) + } + + /// Returns the selected stat. + pub(crate) fn select(&self, s: StatSelect) -> u64 { + match s { + StatSelect::Maximum => self.max, + StatSelect::Average => self.avg, + StatSelect::Median => self.median, + StatSelect::P99Percentile => self.p99, + StatSelect::P95Percentile => self.p95, + StatSelect::P75Percentile => self.p75, + } + } + + /// Returns the *average* and the *standard derivation*. + fn avg_and_stddev(xs: &Vec) -> (f64, f64) { + let avg = xs.iter().map(|x| *x as f64).sum::() / xs.len() as f64; + let variance = xs.iter().map(|x| (*x as f64 - avg).powi(2)).sum::() / xs.len() as f64; + (avg, variance.sqrt()) + } + + /// Returns the specified percentile for the given data. + /// This is best effort since it ignores the interpolation case. + fn percentile(mut xs: Vec, p: f64) -> u64 { + xs.sort(); + let index = (xs.len() as f64 * p).ceil() as usize; + xs[index] + } +} + +impl fmt::Debug for Stats { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Total: {}\n", self.sum)?; + write!(f, "Min: {}, Max: {}\n", self.min, self.max)?; + write!(f, "Average: {}, Median: {}, Stddev: {}\n", self.avg, self.median, self.stddev)?; + write!(f, "Percentiles 99th, 95th, 75th: {}, {}, {}", self.p99, self.p95, self.p75) + } +} + +impl Default for StatSelect { + /// Returns the `Average` selector. + fn default() -> Self { + Self::Average + } +} + +impl FromStr for StatSelect { + type Err = &'static str; + + fn from_str(day: &str) -> result::Result { + match day.to_lowercase().as_str() { + "max" => Ok(Self::Maximum), + "average" => Ok(Self::Average), + "median" => Ok(Self::Median), + "p99" => Ok(Self::P99Percentile), + "p95" => Ok(Self::P95Percentile), + "p75" => Ok(Self::P75Percentile), + _ => Err("String was not a StatSelect"), + } + } +} diff --git a/utils/frame/benchmarking-cli/src/storage/template.rs b/utils/frame/benchmarking-cli/src/storage/template.rs new file mode 100644 index 0000000000000..56e0869a914a1 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/storage/template.rs @@ -0,0 +1,126 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sc_cli::Result; +use sc_service::Configuration; + +use log::info; +use serde::Serialize; +use std::{env, fs, path::PathBuf}; + +use super::{cmd::StorageParams, record::Stats}; + +static VERSION: &'static str = env!("CARGO_PKG_VERSION"); +static TEMPLATE: &str = include_str!("./weights.hbs"); + +/// Data consumed by Handlebar to fill out the `weights.hbs` template. +#[derive(Serialize, Default, Debug, Clone)] +pub(crate) struct TemplateData { + /// Name of the database used. + db_name: String, + /// Name of the runtime. Taken from the chain spec. + runtime_name: String, + /// Version of the benchmarking CLI used. + version: String, + /// Date that the template was filled out. + date: String, + /// Command line arguments that were passed to the CLI. + args: Vec, + /// Storage params of the executed command. + params: StorageParams, + /// The weight for one `read`. + read_weight: u64, + /// The weight for one `write`. + write_weight: u64, + /// Stats about a `read` benchmark. Contains *time* and *value size* stats. + /// The *value size* stats are currently not used in the template. + read: Option<(Stats, Stats)>, + /// Stats about a `write` benchmark. Contains *time* and *value size* stats. + /// The *value size* stats are currently not used in the template. + write: Option<(Stats, Stats)>, +} + +impl TemplateData { + /// Returns a new [`Self`] from the given configuration. + pub fn new(cfg: &Configuration, params: &StorageParams) -> Self { + TemplateData { + db_name: format!("{}", cfg.database), + runtime_name: cfg.chain_spec.name().into(), + version: VERSION.into(), + date: chrono::Utc::now().format("%Y-%m-%d (Y/M/D)").to_string(), + args: env::args().collect::>(), + params: params.clone(), + ..Default::default() + } + } + + /// Sets the stats and calculates the final weights. + pub fn set_stats( + &mut self, + read: Option<(Stats, Stats)>, + write: Option<(Stats, Stats)>, + ) -> Result<()> { + if let Some(read) = read { + self.read_weight = calc_weight(&read.0, &self.params)?; + self.read = Some(read); + } + if let Some(write) = write { + self.write_weight = calc_weight(&write.0, &self.params)?; + self.write = Some(write); + } + Ok(()) + } + + /// Filles out the `weights.hbs` HBS template with its own data. + /// Writes the result to `path` which can be a directory or file. + pub fn write(&self, path: &str) -> Result<()> { + let mut handlebars = handlebars::Handlebars::new(); + // Format large integers with underscore. + handlebars.register_helper("underscore", Box::new(crate::writer::UnderscoreHelper)); + // Don't HTML escape any characters. + handlebars.register_escape_fn(|s| -> String { s.to_string() }); + + let out_path = self.build_path(path); + let mut fd = fs::File::create(&out_path)?; + info!("Writing weights to {:?}", fs::canonicalize(&out_path)?); + handlebars + .render_template_to_write(&TEMPLATE, &self, &mut fd) + .map_err(|e| format!("HBS template write: {:?}", e).into()) + } + + /// Builds a path for the weight file. + fn build_path(&self, weight_out: &str) -> PathBuf { + let mut path = PathBuf::from(weight_out); + if path.is_dir() { + path.push(format!("{}_weights.rs", self.db_name.to_lowercase())); + path.set_extension("rs"); + } + path + } +} + +/// Calculates the final weight by multiplying the selected metric with +/// `mul` and adding `add`. +/// Does not use safe casts and can overflow. +fn calc_weight(stat: &Stats, params: &StorageParams) -> Result { + if params.weight_mul.is_sign_negative() || !params.weight_mul.is_normal() { + return Err("invalid floating number for `weight_mul`".into()) + } + let s = stat.select(params.weight_metric) as f64; + let w = s.mul_add(params.weight_mul, params.weight_add as f64).ceil(); + Ok(w as u64) // No safe cast here since there is no `From` for `u64`. +} diff --git a/utils/frame/benchmarking-cli/src/storage/weights.hbs b/utils/frame/benchmarking-cli/src/storage/weights.hbs new file mode 100644 index 0000000000000..ffeb1fe04d81c --- /dev/null +++ b/utils/frame/benchmarking-cli/src/storage/weights.hbs @@ -0,0 +1,107 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} +//! DATE: {{date}} +//! +//! DATABASE: `{{db_name}}`, RUNTIME: `{{runtime_name}}` +//! SKIP-WRITE: `{{params.skip_write}}`, SKIP-READ: `{{params.skip_read}}`, WARMUPS: `{{params.warmups}}` +//! STATE-VERSION: `V{{params.state_version}}`, STATE-CACHE-SIZE: `{{params.state_cache_size}}` +//! WEIGHT-PATH: `{{params.weight_path}}` +//! METRIC: `{{params.weight_metric}}`, WEIGHT-MUL: `{{params.weight_mul}}`, WEIGHT-ADD: `{{params.weight_add}}` + +// Executed Command: +{{#each args as |arg|}} +// {{arg}} +{{/each}} + +/// Storage DB weights for the {{runtime_name}} runtime and {{db_name}}. +pub mod constants { + use frame_support::{parameter_types, weights::{RuntimeDbWeight, constants}}; + + parameter_types! { + {{#if (eq db_name "ParityDb")}} + /// ParityDB can be enabled with a feature flag, but is still experimental. These weights + /// are available for brave runtime engineers who may want to try this out as default. + {{else}} + /// By default, Substrate uses RocksDB, so this will be the weight used throughout + /// the runtime. + {{/if}} + pub const {{db_name}}Weight: RuntimeDbWeight = RuntimeDbWeight { + /// Time to read one storage item. + /// Calculated by multiplying the *{{params.weight_metric}}* of all values with `{{params.weight_mul}}` and adding `{{params.weight_add}}`. + /// + /// Stats [ns]: + /// Min, Max: {{underscore read.0.min}}, {{underscore read.0.max}} + /// Average: {{underscore read.0.avg}} + /// Median: {{underscore read.0.median}} + /// StdDev: {{read.0.stddev}} + /// + /// Percentiles [ns]: + /// 99th: {{underscore read.0.p99}} + /// 95th: {{underscore read.0.p95}} + /// 75th: {{underscore read.0.p75}} + read: {{underscore read_weight}} * constants::WEIGHT_PER_NANOS, + + /// Time to write one storage item. + /// Calculated by multiplying the *{{params.weight_metric}}* of all values with `{{params.weight_mul}}` and adding `{{params.weight_add}}`. + /// + /// Stats [ns]: + /// Min, Max: {{underscore write.0.min}}, {{underscore write.0.max}} + /// Average: {{underscore write.0.avg}} + /// Median: {{underscore write.0.median}} + /// StdDev: {{write.0.stddev}} + /// + /// Percentiles [ns]: + /// 99th: {{underscore write.0.p99}} + /// 95th: {{underscore write.0.p95}} + /// 75th: {{underscore write.0.p75}} + write: {{underscore write_weight}} * constants::WEIGHT_PER_NANOS, + }; + } + + #[cfg(test)] + mod test_db_weights { + use super::constants::{{db_name}}Weight as W; + use frame_support::weights::constants; + + /// Checks that all weights exist and have sane values. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn bound() { + // At least 1 µs. + assert!( + W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + "Read weight should be at least 1 µs." + ); + assert!( + W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + "Write weight should be at least 1 µs." + ); + // At most 1 ms. + assert!( + W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + "Read weight should be at most 1 ms." + ); + assert!( + W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + "Write weight should be at most 1 ms." + ); + } + } +} diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs new file mode 100644 index 0000000000000..eb9ba11f30696 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sc_cli::Result; +use sc_client_api::UsageProvider; +use sc_client_db::{DbHash, DbState, DB_HASH_LEN}; +use sp_api::StateBackend; +use sp_blockchain::HeaderBackend; +use sp_database::{ColumnId, Transaction}; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, HashFor, Header as HeaderT}, +}; +use sp_trie::PrefixedMemoryDB; + +use log::info; +use rand::prelude::*; +use std::{fmt::Debug, sync::Arc, time::Instant}; + +use super::{cmd::StorageCmd, record::BenchRecord}; + +impl StorageCmd { + /// Benchmarks the time it takes to write a single Storage item. + /// Uses the latest state that is available for the given client. + pub(crate) fn bench_write( + &self, + client: Arc, + (db, state_col): (Arc>, ColumnId), + storage: Arc>>, + ) -> Result + where + Block: BlockT

+ Debug, + H: HeaderT, + C: UsageProvider + HeaderBackend, + { + // Store the time that it took to write each value. + let mut record = BenchRecord::default(); + + let supports_rc = db.supports_ref_counting(); + let block = BlockId::Number(client.usage_info().chain.best_number); + let header = client.header(block)?.ok_or("Header not found")?; + let original_root = *header.state_root(); + let trie = DbState::::new(storage.clone(), original_root); + + info!("Preparing keys from block {}", block); + // Load all KV pairs and randomly shuffle them. + let mut kvs = trie.pairs(); + let mut rng = Self::setup_rng(); + kvs.shuffle(&mut rng); + + info!("Writing {} keys", kvs.len()); + // Write each value in one commit. + for (k, original_v) in kvs.iter() { + // Create a random value to overwrite with. + // NOTE: We use a possibly higher entropy than the original value, + // could be improved but acts as an over-estimation which is fine for now. + let mut new_v = vec![0; original_v.len()]; + rng.fill_bytes(&mut new_v[..]); + + // Interesting part here: + let start = Instant::now(); + // Create a TX that will modify the Trie in the DB and + // calculate the root hash of the Trie after the modification. + let replace = vec![(k.as_ref(), Some(new_v.as_ref()))]; + let (_, stx) = trie.storage_root(replace.iter().cloned(), self.state_version()); + // Only the keep the insertions, since we do not want to benchmark pruning. + let tx = convert_tx::(stx.clone(), true, state_col, supports_rc); + db.commit(tx).map_err(|e| format!("Writing to the Database: {}", e))?; + record.append(new_v.len(), start.elapsed())?; + + // Now undo the changes by removing what was added. + let tx = convert_tx::(stx.clone(), false, state_col, supports_rc); + db.commit(tx).map_err(|e| format!("Writing to the Database: {}", e))?; + } + Ok(record) + } +} + +/// Converts a Trie transaction into a DB transaction. +/// Removals are ignored and will not be included in the final tx. +/// `invert_inserts` replaces all inserts with removals. +/// +/// The keys of Trie transactions are prefixed, this is treated differently by each DB. +/// ParityDB can use an optimization where only the last `DB_HASH_LEN` byte are needed. +/// The last `DB_HASH_LEN` byte are the hash of the actual stored data, everything +/// before that is the route in the Patricia Trie. +/// RocksDB cannot do this and needs the whole route, hence no key truncating for RocksDB. +/// +/// TODO: +/// This copies logic from [`sp_client_db::Backend::try_commit_operation`] and should be +/// refactored to use a canonical `sanitize_key` function from `sp_client_db` which +/// does not yet exist. +fn convert_tx( + mut tx: PrefixedMemoryDB>, + invert_inserts: bool, + col: ColumnId, + supports_rc: bool, +) -> Transaction { + let mut ret = Transaction::::default(); + + for (mut k, (v, rc)) in tx.drain().into_iter() { + if supports_rc { + let _prefix = k.drain(0..k.len() - DB_HASH_LEN); + } + + if rc > 0 { + if invert_inserts { + ret.set(col, k.as_ref(), &v); + } else { + ret.remove(col, &k); + } + } + // < 0 means removal - ignored. + // 0 means no modification. + } + ret +} diff --git a/utils/frame/benchmarking-cli/src/writer.rs b/utils/frame/benchmarking-cli/src/writer.rs index 1e31c4e98e56d..17f1221e46d8b 100644 --- a/utils/frame/benchmarking-cli/src/writer.rs +++ b/utils/frame/benchmarking-cli/src/writer.rs @@ -436,7 +436,7 @@ where // A Handlebars helper to add an underscore after every 3rd character, // i.e. a separator for large numbers. #[derive(Clone, Copy)] -struct UnderscoreHelper; +pub(crate) struct UnderscoreHelper; impl handlebars::HelperDef for UnderscoreHelper { fn call<'reg: 'rc, 'rc>( &self, From 970ee8034874ceb10f52491958383ec56e6a793c Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sat, 26 Feb 2022 08:39:56 +0000 Subject: [PATCH 0550/1472] Minor improvements to `bounded_vec` and `defensive`. (#10873) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix a few things in bounded_vec * add test for try_extend * Update frame/support/src/storage/bounded_vec.rs Co-authored-by: Bastian Köcher * some review comments * use swap * remove clone * use pop instead of truncate * remove warn * review comments * Update frame/support/src/storage/bounded_vec.rs Co-authored-by: Bastian Köcher * fix rustdoc * fix links * undo link Co-authored-by: Bastian Köcher --- frame/referenda/src/lib.rs | 2 +- frame/referenda/src/types.rs | 2 +- frame/support/src/storage/bounded_vec.rs | 211 +++++++++++++++-------- frame/support/src/traits.rs | 2 + frame/support/src/traits/misc.rs | 143 +++++---------- 5 files changed, 189 insertions(+), 171 deletions(-) diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index fb8e9aa6a6db7..2d4d29b0bc13f 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -866,7 +866,7 @@ impl Pallet { let new_pos = queue.binary_search_by_key(&ayes, |x| x.1).unwrap_or_else(|x| x); branch = if maybe_old_pos.is_none() && new_pos > 0 { // Just insert. - queue.force_insert_keep_right(new_pos, (index, ayes)); + let _ = queue.force_insert_keep_right(new_pos, (index, ayes)); ServiceBranch::RequeuedInsertion } else if let Some(old_pos) = maybe_old_pos { // We were in the queue - slide into the correct position. diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 1b028fdfe9f79..367fa2a4ba45b 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -86,7 +86,7 @@ impl> InsertSorted for BoundedVec { mut f: F, ) -> bool { let index = self.binary_search_by_key::(&f(&t), f).unwrap_or_else(|x| x); - self.force_insert_keep_right(index, t) + self.force_insert_keep_right(index, t).is_ok() } } diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 86aa4d405cab2..206a7e5d4edea 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -119,7 +119,17 @@ impl BoundedVec { self.0 } - /// Exactly the same semantics as [`Vec::remove`]. + /// Exactly the same semantics as [`slice::sort_by`]. + /// + /// This is safe since sorting cannot change the number of elements in the vector. + pub fn sort_by(&mut self, compare: F) + where + F: FnMut(&T, &T) -> sp_std::cmp::Ordering, + { + self.0.sort_by(compare) + } + + /// Exactly the same semantics as `Vec::remove`. /// /// # Panics /// @@ -128,7 +138,7 @@ impl BoundedVec { self.0.remove(index) } - /// Exactly the same semantics as [`Vec::swap_remove`]. + /// Exactly the same semantics as `slice::swap_remove`. /// /// # Panics /// @@ -137,12 +147,12 @@ impl BoundedVec { self.0.swap_remove(index) } - /// Exactly the same semantics as [`Vec::retain`]. + /// Exactly the same semantics as `Vec::retain`. pub fn retain bool>(&mut self, f: F) { self.0.retain(f) } - /// Exactly the same semantics as [`slice::get_mut`]. + /// Exactly the same semantics as `slice::get_mut`. pub fn get_mut>( &mut self, index: I, @@ -150,12 +160,16 @@ impl BoundedVec { self.0.get_mut(index) } - /// Exactly the same semantics as [`Vec::truncate`]. + /// Exactly the same semantics as `Vec::truncate`. + /// + /// This is safe because `truncate` can never increase the length of the internal vector. pub fn truncate(&mut self, s: usize) { self.0.truncate(s); } - /// Exactly the same semantics as [`Vec::pop`]. + /// Exactly the same semantics as `Vec::pop`. + /// + /// This is safe since popping can only shrink the inner vector. pub fn pop(&mut self) -> Option { self.0.pop() } @@ -191,54 +205,76 @@ impl> BoundedVec { S::get() as usize } - /// Forces the insertion of `s` into `self` retaining all items with index at least `index`. + /// Returns true of this collection is full. + pub fn is_full(&self) -> bool { + self.len() >= Self::bound() + } + + /// Forces the insertion of `element` into `self` retaining all items with index at least + /// `index`. /// /// If `index == 0` and `self.len() == Self::bound()`, then this is a no-op. /// /// If `Self::bound() < index` or `self.len() < index`, then this is also a no-op. /// - /// Returns `true` if the item was inserted. - pub fn force_insert_keep_right(&mut self, index: usize, element: T) -> bool { + /// Returns `Ok(maybe_removed)` if the item was inserted, where `maybe_removed` is + /// `Some(removed)` if an item was removed to make room for the new one. Returns `Err(())` if + /// `element` cannot be inserted. + pub fn force_insert_keep_right( + &mut self, + index: usize, + mut element: T, + ) -> Result, ()> { // Check against panics. if Self::bound() < index || self.len() < index { - return false - } - if self.len() < Self::bound() { + Err(()) + } else if self.len() < Self::bound() { // Cannot panic since self.len() >= index; self.0.insert(index, element); + Ok(None) } else { if index == 0 { - return false + return Err(()) } - self[0] = element; + sp_std::mem::swap(&mut self[0], &mut element); // `[0..index] cannot panic since self.len() >= index. // `rotate_left(1)` cannot panic because there is at least 1 element. self[0..index].rotate_left(1); + Ok(Some(element)) } - true } - /// Forces the insertion of `s` into `self` retaining all items with index at most `index`. + /// Forces the insertion of `element` into `self` retaining all items with index at most + /// `index`. /// /// If `index == Self::bound()` and `self.len() == Self::bound()`, then this is a no-op. /// /// If `Self::bound() < index` or `self.len() < index`, then this is also a no-op. /// - /// Returns `true` if the item was inserted. - pub fn force_insert_keep_left(&mut self, index: usize, element: T) -> bool { + /// Returns `Ok(maybe_removed)` if the item was inserted, where `maybe_removed` is + /// `Some(removed)` if an item was removed to make room for the new one. Returns `Err(())` if + /// `element` cannot be inserted. + pub fn force_insert_keep_left(&mut self, index: usize, element: T) -> Result, ()> { // Check against panics. if Self::bound() < index || self.len() < index || Self::bound() == 0 { - return false + return Err(()) } // Noop condition. if Self::bound() == index && self.len() <= Self::bound() { - return false + return Err(()) } - // Cannot panic since `Self.bound() > 0` - self.0.truncate(Self::bound() - 1); + let maybe_removed = if self.is_full() { + // defensive-only: since we are at capacity, this is a noop. + self.0.truncate(Self::bound()); + // if we truncate anything, it will be the last one. + self.0.pop() + } else { + None + }; + // Cannot panic since `self.len() >= index`; self.0.insert(index, element); - true + Ok(maybe_removed) } /// Move the position of an item from one location to another in the slice. @@ -311,6 +347,20 @@ impl> BoundedVec { self.0.resize(size, value); } + /// Exactly the same semantics as [`Vec::extend`], but returns an error and does nothing if the + /// length of the outcome is larger than the bound. + pub fn try_extend( + &mut self, + with: impl IntoIterator + ExactSizeIterator, + ) -> Result<(), ()> { + if with.len().saturating_add(self.len()) <= Self::bound() { + self.0.extend(with); + Ok(()) + } else { + Err(()) + } + } + /// Consumes self and mutates self via the given `mutate` function. /// /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is @@ -522,7 +572,7 @@ where #[cfg(test)] pub mod test { use super::*; - use crate::{traits::ConstU32, Twox128}; + use crate::{bounded_vec, traits::ConstU32, Twox128}; use sp_io::TestExternalities; crate::generate_storage_alias! { Prefix, Foo => Value>> } @@ -534,7 +584,7 @@ pub mod test { #[test] fn slide_works() { - let mut b: BoundedVec> = vec![0, 1, 2, 3, 4, 5].try_into().unwrap(); + let mut b: BoundedVec> = bounded_vec![0, 1, 2, 3, 4, 5]; assert!(b.slide(1, 5)); assert_eq!(*b, vec![0, 2, 3, 4, 1, 5]); assert!(b.slide(4, 0)); @@ -551,7 +601,7 @@ pub mod test { assert!(!b.slide(7, 0)); assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); - let mut c: BoundedVec> = vec![0, 1, 2].try_into().unwrap(); + let mut c: BoundedVec> = bounded_vec![0, 1, 2]; assert!(!c.slide(1, 5)); assert_eq!(*c, vec![0, 1, 2]); assert!(!c.slide(4, 0)); @@ -564,7 +614,7 @@ pub mod test { #[test] fn slide_noops_work() { - let mut b: BoundedVec> = vec![0, 1, 2, 3, 4, 5].try_into().unwrap(); + let mut b: BoundedVec> = bounded_vec![0, 1, 2, 3, 4, 5]; assert!(!b.slide(3, 3)); assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); assert!(!b.slide(3, 4)); @@ -573,58 +623,59 @@ pub mod test { #[test] fn force_insert_keep_left_works() { - let mut b: BoundedVec> = vec![].try_into().unwrap(); - assert!(!b.force_insert_keep_left(1, 10)); + let mut b: BoundedVec> = bounded_vec![]; + assert_eq!(b.force_insert_keep_left(1, 10), Err(())); assert!(b.is_empty()); - assert!(b.force_insert_keep_left(0, 30)); - assert!(b.force_insert_keep_left(0, 10)); - assert!(b.force_insert_keep_left(1, 20)); - assert!(b.force_insert_keep_left(3, 40)); + assert_eq!(b.force_insert_keep_left(0, 30), Ok(None)); + assert_eq!(b.force_insert_keep_left(0, 10), Ok(None)); + assert_eq!(b.force_insert_keep_left(1, 20), Ok(None)); + assert_eq!(b.force_insert_keep_left(3, 40), Ok(None)); assert_eq!(*b, vec![10, 20, 30, 40]); // at capacity. - assert!(!b.force_insert_keep_left(4, 41)); + assert_eq!(b.force_insert_keep_left(4, 41), Err(())); assert_eq!(*b, vec![10, 20, 30, 40]); - assert!(b.force_insert_keep_left(3, 31)); + assert_eq!(b.force_insert_keep_left(3, 31), Ok(Some(40))); assert_eq!(*b, vec![10, 20, 30, 31]); - assert!(b.force_insert_keep_left(1, 11)); + assert_eq!(b.force_insert_keep_left(1, 11), Ok(Some(31))); assert_eq!(*b, vec![10, 11, 20, 30]); - assert!(b.force_insert_keep_left(0, 1)); + assert_eq!(b.force_insert_keep_left(0, 1), Ok(Some(30))); assert_eq!(*b, vec![1, 10, 11, 20]); - let mut z: BoundedVec> = vec![].try_into().unwrap(); + let mut z: BoundedVec> = bounded_vec![]; assert!(z.is_empty()); - assert!(!z.force_insert_keep_left(0, 10)); + assert_eq!(z.force_insert_keep_left(0, 10), Err(())); assert!(z.is_empty()); } #[test] fn force_insert_keep_right_works() { - let mut b: BoundedVec> = vec![].try_into().unwrap(); - assert!(!b.force_insert_keep_right(1, 10)); + let mut b: BoundedVec> = bounded_vec![]; + assert_eq!(b.force_insert_keep_right(1, 10), Err(())); assert!(b.is_empty()); - assert!(b.force_insert_keep_right(0, 30)); - assert!(b.force_insert_keep_right(0, 10)); - assert!(b.force_insert_keep_right(1, 20)); - assert!(b.force_insert_keep_right(3, 40)); + assert_eq!(b.force_insert_keep_right(0, 30), Ok(None)); + assert_eq!(b.force_insert_keep_right(0, 10), Ok(None)); + assert_eq!(b.force_insert_keep_right(1, 20), Ok(None)); + assert_eq!(b.force_insert_keep_right(3, 40), Ok(None)); assert_eq!(*b, vec![10, 20, 30, 40]); + // at capacity. - assert!(!b.force_insert_keep_right(0, 0)); + assert_eq!(b.force_insert_keep_right(0, 0), Err(())); assert_eq!(*b, vec![10, 20, 30, 40]); - assert!(b.force_insert_keep_right(1, 11)); + assert_eq!(b.force_insert_keep_right(1, 11), Ok(Some(10))); assert_eq!(*b, vec![11, 20, 30, 40]); - assert!(b.force_insert_keep_right(3, 31)); + assert_eq!(b.force_insert_keep_right(3, 31), Ok(Some(11))); assert_eq!(*b, vec![20, 30, 31, 40]); - assert!(b.force_insert_keep_right(4, 41)); + assert_eq!(b.force_insert_keep_right(4, 41), Ok(Some(20))); assert_eq!(*b, vec![30, 31, 40, 41]); - assert!(!b.force_insert_keep_right(5, 69)); + assert_eq!(b.force_insert_keep_right(5, 69), Err(())); assert_eq!(*b, vec![30, 31, 40, 41]); - let mut z: BoundedVec> = vec![].try_into().unwrap(); + let mut z: BoundedVec> = bounded_vec![]; assert!(z.is_empty()); - assert!(!z.force_insert_keep_right(0, 10)); + assert_eq!(z.force_insert_keep_right(0, 10), Err(())); assert!(z.is_empty()); } @@ -636,13 +687,13 @@ pub mod test { #[test] fn decode_len_works() { TestExternalities::default().execute_with(|| { - let bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + let bounded: BoundedVec> = bounded_vec![1, 2, 3]; Foo::put(bounded); assert_eq!(Foo::decode_len().unwrap(), 3); }); TestExternalities::default().execute_with(|| { - let bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + let bounded: BoundedVec> = bounded_vec![1, 2, 3]; FooMap::insert(1, bounded); assert_eq!(FooMap::decode_len(1).unwrap(), 3); assert!(FooMap::decode_len(0).is_none()); @@ -650,7 +701,7 @@ pub mod test { }); TestExternalities::default().execute_with(|| { - let bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + let bounded: BoundedVec> = bounded_vec![1, 2, 3]; FooDoubleMap::insert(1, 1, bounded); assert_eq!(FooDoubleMap::decode_len(1, 1).unwrap(), 3); assert!(FooDoubleMap::decode_len(2, 1).is_none()); @@ -661,7 +712,7 @@ pub mod test { #[test] fn try_insert_works() { - let mut bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; bounded.try_insert(1, 0).unwrap(); assert_eq!(*bounded, vec![1, 0, 2, 3]); @@ -685,13 +736,13 @@ pub mod test { #[test] #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] fn try_inert_panics_if_oob() { - let mut bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; bounded.try_insert(9, 0).unwrap(); } #[test] fn try_push_works() { - let mut bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; bounded.try_push(0).unwrap(); assert_eq!(*bounded, vec![1, 2, 3, 0]); @@ -700,7 +751,7 @@ pub mod test { #[test] fn deref_coercion_works() { - let bounded: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + let bounded: BoundedVec> = bounded_vec![1, 2, 3]; // these methods come from deref-ed vec. assert_eq!(bounded.len(), 3); assert!(bounded.iter().next().is_some()); @@ -709,7 +760,7 @@ pub mod test { #[test] fn try_mutate_works() { - let bounded: BoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; let bounded = bounded.try_mutate(|v| v.push(7)).unwrap(); assert_eq!(bounded.len(), 7); assert!(bounded.try_mutate(|v| v.push(8)).is_none()); @@ -717,13 +768,13 @@ pub mod test { #[test] fn slice_indexing_works() { - let bounded: BoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; assert_eq!(&bounded[0..=2], &[1, 2, 3]); } #[test] fn vec_eq_works() { - let bounded: BoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; assert_eq!(bounded, vec![1, 2, 3, 4, 5, 6]); } @@ -738,7 +789,7 @@ pub mod test { #[test] fn can_be_collected() { - let b1: BoundedVec> = vec![1, 2, 3, 4].try_into().unwrap(); + let b1: BoundedVec> = bounded_vec![1, 2, 3, 4]; let b2: BoundedVec> = b1.iter().map(|x| x + 1).try_collect().unwrap(); assert_eq!(b2, vec![2, 3, 4, 5]); @@ -777,8 +828,8 @@ pub mod test { #[test] fn eq_works() { // of same type - let b1: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); - let b2: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); + let b1: BoundedVec> = bounded_vec![1, 2, 3]; + let b2: BoundedVec> = bounded_vec![1, 2, 3]; assert_eq!(b1, b2); // of different type, but same value and bound. @@ -786,19 +837,41 @@ pub mod test { B1: u32 = 7; B2: u32 = 7; } - let b1: BoundedVec = vec![1, 2, 3].try_into().unwrap(); - let b2: BoundedVec = vec![1, 2, 3].try_into().unwrap(); + let b1: BoundedVec = bounded_vec![1, 2, 3]; + let b2: BoundedVec = bounded_vec![1, 2, 3]; assert_eq!(b1, b2); } #[test] fn ord_works() { use std::cmp::Ordering; - let b1: BoundedVec> = vec![1, 2, 3].try_into().unwrap(); - let b2: BoundedVec> = vec![1, 3, 2].try_into().unwrap(); + let b1: BoundedVec> = bounded_vec![1, 2, 3]; + let b2: BoundedVec> = bounded_vec![1, 3, 2]; // ordering for vec is lexicographic. assert_eq!(b1.cmp(&b2), Ordering::Less); assert_eq!(b1.cmp(&b2), b1.into_inner().cmp(&b2.into_inner())); } + + #[test] + fn try_extend_works() { + let mut b: BoundedVec> = bounded_vec![1, 2, 3]; + + assert!(b.try_extend(vec![4].into_iter()).is_ok()); + assert_eq!(*b, vec![1, 2, 3, 4]); + + assert!(b.try_extend(vec![5].into_iter()).is_ok()); + assert_eq!(*b, vec![1, 2, 3, 4, 5]); + + assert!(b.try_extend(vec![6].into_iter()).is_err()); + assert_eq!(*b, vec![1, 2, 3, 4, 5]); + + let mut b: BoundedVec> = bounded_vec![1, 2, 3]; + assert!(b.try_extend(vec![4, 5].into_iter()).is_ok()); + assert_eq!(*b, vec![1, 2, 3, 4, 5]); + + let mut b: BoundedVec> = bounded_vec![1, 2, 3]; + assert!(b.try_extend(vec![4, 5, 6].into_iter()).is_err()); + assert_eq!(*b, vec![1, 2, 3]); + } } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 5ee2952e445b7..88891c83276bd 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -58,6 +58,8 @@ pub use misc::{ PreimageRecipient, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, UnixTime, WrapperKeepOpaque, WrapperOpaque, }; +#[doc(hidden)] +pub use misc::{DEFENSIVE_OP_INTERNAL_ERROR, DEFENSIVE_OP_PUBLIC_ERROR}; mod stored_map; pub use stored_map::{StorageMapShim, StoredMap}; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index eaada3ea2c363..d2fd438d3a802 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -24,8 +24,34 @@ use sp_arithmetic::traits::{CheckedAdd, CheckedMul, CheckedSub, Saturating}; use sp_runtime::{traits::Block as BlockT, DispatchError}; use sp_std::{cmp::Ordering, prelude::*}; -const DEFENSIVE_OP_PUBLIC_ERROR: &'static str = "a defensive failure has been triggered; please report the block number at https://github.com/paritytech/substrate/issues"; -const DEFENSIVE_OP_INTERNAL_ERROR: &'static str = "Defensive failure has been triggered!"; +#[doc(hidden)] +pub const DEFENSIVE_OP_PUBLIC_ERROR: &'static str = "a defensive failure has been triggered; please report the block number at https://github.com/paritytech/substrate/issues"; +#[doc(hidden)] +pub const DEFENSIVE_OP_INTERNAL_ERROR: &'static str = "Defensive failure has been triggered!"; + +/// Generic function to mark an execution path as ONLY defensive. +/// +/// Similar to mark a match arm or `if/else` branch as `unreachable!`. +#[macro_export] +macro_rules! defensive { + () => { + frame_support::log::error!( + target: "runtime", + "{}", + $crate::traits::misc::DEFENSIVE_OP_PUBLIC_ERROR + ); + debug_assert!(false, "{}", $crate::traits::misc::DEFENSIVE_OP_INTERNAL_ERROR); + }; + ($error:tt) => { + frame_support::log::error!( + target: "runtime", + "{}: {:?}", + $crate::traits::misc::DEFENSIVE_OP_PUBLIC_ERROR, + $error + ); + debug_assert!(false, "{}: {:?}", $crate::traits::misc::DEFENSIVE_OP_INTERNAL_ERROR, $error); + } +} /// Prelude module for all defensive traits to be imported at once. pub mod defensive_prelude { @@ -116,12 +142,7 @@ impl Defensive for Option { match self { Some(inner) => inner, None => { - debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); - frame_support::log::error!( - target: "runtime", - "{}", - DEFENSIVE_OP_PUBLIC_ERROR - ); + defensive!(); or }, } @@ -131,12 +152,7 @@ impl Defensive for Option { match self { Some(inner) => inner, None => { - debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); - frame_support::log::error!( - target: "runtime", - "{}", - DEFENSIVE_OP_PUBLIC_ERROR - ); + defensive!(); f() }, } @@ -149,12 +165,7 @@ impl Defensive for Option { match self { Some(inner) => inner, None => { - debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); - frame_support::log::error!( - target: "runtime", - "{}", - DEFENSIVE_OP_PUBLIC_ERROR - ); + defensive!(); Default::default() }, } @@ -164,12 +175,7 @@ impl Defensive for Option { match self { Some(inner) => Some(inner), None => { - debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); - frame_support::log::error!( - target: "runtime", - "{}", - DEFENSIVE_OP_PUBLIC_ERROR - ); + defensive!(); None }, } @@ -181,13 +187,7 @@ impl Defensive for Result { match self { Ok(inner) => inner, Err(e) => { - debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); - frame_support::log::error!( - target: "runtime", - "{}: {:?}", - DEFENSIVE_OP_PUBLIC_ERROR, - e - ); + defensive!(e); or }, } @@ -197,13 +197,7 @@ impl Defensive for Result { match self { Ok(inner) => inner, Err(e) => { - debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); - frame_support::log::error!( - target: "runtime", - "{}: {:?}", - DEFENSIVE_OP_PUBLIC_ERROR, - e - ); + defensive!(e); f() }, } @@ -216,13 +210,7 @@ impl Defensive for Result { match self { Ok(inner) => inner, Err(e) => { - debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); - frame_support::log::error!( - target: "runtime", - "{}: {:?}", - DEFENSIVE_OP_PUBLIC_ERROR, - e - ); + defensive!(e); Default::default() }, } @@ -232,13 +220,7 @@ impl Defensive for Result { match self { Ok(inner) => Ok(inner), Err(e) => { - debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); - frame_support::log::error!( - target: "runtime", - "{}: {:?}", - DEFENSIVE_OP_PUBLIC_ERROR, - e - ); + defensive!(e); Err(e) }, } @@ -248,13 +230,7 @@ impl Defensive for Result { impl DefensiveResult for Result { fn defensive_map_err F>(self, o: O) -> Result { self.map_err(|e| { - debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); - frame_support::log::error!( - target: "runtime", - "{}: {:?}", - DEFENSIVE_OP_PUBLIC_ERROR, - e - ); + defensive!(e); o(e) }) } @@ -262,13 +238,7 @@ impl DefensiveResult for Result { fn defensive_map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { self.map_or_else( |e| { - debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); - frame_support::log::error!( - target: "runtime", - "{}: {:?}", - DEFENSIVE_OP_PUBLIC_ERROR, - e - ); + defensive!(e); default(e) }, f, @@ -279,13 +249,7 @@ impl DefensiveResult for Result { match self { Ok(inner) => Some(inner), Err(e) => { - debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); - frame_support::log::error!( - target: "runtime", - "{}: {:?}", - DEFENSIVE_OP_PUBLIC_ERROR, - e - ); + defensive!(e); None }, } @@ -295,13 +259,7 @@ impl DefensiveResult for Result { match self { Ok(inner) => Ok(f(inner)), Err(e) => { - debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); - frame_support::log::error!( - target: "runtime", - "{}: {:?}", - DEFENSIVE_OP_PUBLIC_ERROR, - e - ); + defensive!(e); Err(e) }, } @@ -312,12 +270,7 @@ impl DefensiveOption for Option { fn defensive_map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { self.map_or_else( || { - debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); - frame_support::log::error!( - target: "runtime", - "{}", - DEFENSIVE_OP_PUBLIC_ERROR, - ); + defensive!(); default() }, f, @@ -326,12 +279,7 @@ impl DefensiveOption for Option { fn defensive_ok_or_else E>(self, err: F) -> Result { self.ok_or_else(|| { - debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); - frame_support::log::error!( - target: "runtime", - "{}", - DEFENSIVE_OP_PUBLIC_ERROR, - ); + defensive!(); err() }) } @@ -340,12 +288,7 @@ impl DefensiveOption for Option { match self { Some(inner) => Some(f(inner)), None => { - debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); - frame_support::log::error!( - target: "runtime", - "{}", - DEFENSIVE_OP_PUBLIC_ERROR, - ); + defensive!(); None }, } From bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Sat, 26 Feb 2022 22:00:00 +0100 Subject: [PATCH 0551/1472] Replace libsecp256k1 with secp256k1 (#10798) * Replace libsecp256k1 with secp256k1 * Wipe ecdsa secret key from memory on drop * Some comments for a known issue * Safer core crypto primitives `from_slice` constructor Previous version panics if slice lenght is not the expected one. * Unit test fix * Enable use of global secp256k1 context * Better comments for ecdsa `Pair` drop * Replace `libsecp256k1` with `seco256k1` in `beefy-mmr` Used to convert ecdsa public key to ETH address * Replace `libsecp256k1` with `secp256k1` in FRAME `contracts`benchmarks * Temporary rollback of `beefy-mmr` to libsecp256k1 Check for detected build issues * Cargo fmt * Rollback of FRAME `contracts` benchmarks to `libsecp256k1` * Rollback for unrelated changes * Typo fix * Add comments for deprecated `ecdsa_verify` and `secp256k1_ecdsa_recover` --- Cargo.lock | 22 ++- Cargo.toml | 1 + client/authority-discovery/src/tests.rs | 2 +- client/executor/Cargo.toml | 1 - primitives/core/Cargo.toml | 5 +- primitives/core/src/ecdsa.rs | 220 +++++++++++------------- primitives/core/src/ed25519.rs | 7 +- primitives/core/src/sr25519.rs | 7 +- primitives/io/Cargo.toml | 2 + primitives/io/src/lib.rs | 69 ++++---- 10 files changed, 184 insertions(+), 152 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 826ed90d4553b..66910db9d31b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8382,7 +8382,6 @@ version = "0.10.0-dev" dependencies = [ "hex-literal", "lazy_static", - "libsecp256k1", "lru 0.6.6", "parity-scale-codec", "parking_lot 0.12.0", @@ -9170,6 +9169,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secp256k1" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab7883017d5b21f011ef8040ea9c6c7ac90834c0df26a69e4c0b06276151f125" +dependencies = [ + "rand 0.6.5", + "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" @@ -9817,6 +9835,7 @@ dependencies = [ "regex", "scale-info", "schnorrkel", + "secp256k1", "secrecy", "serde", "serde_json", @@ -9927,6 +9946,7 @@ dependencies = [ "log 0.4.14", "parity-scale-codec", "parking_lot 0.12.0", + "secp256k1", "sp-core", "sp-externalities", "sp-keystore", diff --git a/Cargo.toml b/Cargo.toml index d919fc4805631..a12910c52c018 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -265,6 +265,7 @@ percent-encoding = { opt-level = 3 } primitive-types = { opt-level = 3 } ring = { opt-level = 3 } rustls = { opt-level = 3 } +secp256k1 = { opt-level = 3 } sha2 = { opt-level = 3 } sha3 = { opt-level = 3 } smallvec = { opt-level = 3 } diff --git a/client/authority-discovery/src/tests.rs b/client/authority-discovery/src/tests.rs index 3b632d2174002..e9f94b6a186db 100644 --- a/client/authority-discovery/src/tests.rs +++ b/client/authority-discovery/src/tests.rs @@ -105,7 +105,7 @@ fn cryptos_are_compatible() { let sp_core_signature = sp_core_secret.sign(message); // no error expected... assert!(sp_core::ed25519::Pair::verify( - &sp_core::ed25519::Signature::from_slice(&libp2p_signature), + &sp_core::ed25519::Signature::from_slice(&libp2p_signature).unwrap(), message, &sp_core_public )); diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 6cd1938822d0c..5c62de7671001 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -31,7 +31,6 @@ sc-executor-common = { version = "0.10.0-dev", path = "common" } sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } parking_lot = "0.12.0" -libsecp256k1 = "0.7" sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } lru = "0.6.6" tracing = "0.1.29" diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index ab0f38ec109c7..bd1930bf51b6c 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -54,8 +54,9 @@ schnorrkel = { version = "0.9.1", features = [ "u64_backend", ], default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } -libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", "static-context"], optional = true } +libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } +secp256k1 = { version = "0.21.2", default-features = false, features = ["recovery", "global-context"], optional = true } ss58-registry = { version = "1.11.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../runtime-interface" } @@ -106,6 +107,7 @@ std = [ "schnorrkel/std", "regex", "num-traits/std", + "secp256k1/std", "sp-core-hashing/std", "sp-debug-derive/std", "sp-externalities", @@ -129,6 +131,7 @@ full_crypto = [ "schnorrkel", "hex", "libsecp256k1", + "secp256k1", "sp-core-hashing", "sp-runtime-interface/disable_target_static_assertions", "merlin", diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 0735c3f40cec2..9389a277736dd 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -15,9 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// tag::description[] -//! Simple ECDSA API. -// end::description[] +//! Simple ECDSA secp256k1 API. use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -37,9 +35,12 @@ use crate::{ #[cfg(feature = "std")] use bip39::{Language, Mnemonic, MnemonicType}; #[cfg(feature = "full_crypto")] -use core::convert::{TryFrom, TryInto}; +use core::convert::TryFrom; #[cfg(feature = "full_crypto")] -use libsecp256k1::{PublicKey, SecretKey}; +use secp256k1::{ + ecdsa::{RecoverableSignature, RecoveryId}, + Message, PublicKey, SecretKey, SECP256K1, +}; #[cfg(feature = "std")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "full_crypto")] @@ -57,7 +58,17 @@ type Seed = [u8; 32]; /// The ECDSA compressed public key. #[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive( - Clone, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo, Eq, PartialEq, PartialOrd, Ord, + Clone, + Copy, + Encode, + Decode, + PassByInner, + MaxEncodedLen, + TypeInfo, + Eq, + PartialEq, + PartialOrd, + Ord, )] pub struct Public(pub [u8; 33]); @@ -75,10 +86,16 @@ impl Public { /// This will convert the full public key into the compressed format. #[cfg(feature = "std")] pub fn from_full(full: &[u8]) -> Result { - libsecp256k1::PublicKey::parse_slice(full, None) - .map(|k| k.serialize_compressed()) - .map(Self) - .map_err(|_| ()) + let pubkey = if full.len() == 64 { + // Tag it as uncompressed public key. + let mut tagged_full = [0u8; 65]; + tagged_full[0] = 0x04; + tagged_full[1..].copy_from_slice(full); + secp256k1::PublicKey::from_slice(&tagged_full) + } else { + secp256k1::PublicKey::from_slice(full) + }; + pubkey.map(|k| Self(k.serialize())).map_err(|_| ()) } } @@ -296,55 +313,46 @@ impl Signature { /// /// NOTE: No checking goes on to ensure this is a real signature. Only use it if /// you are certain that the array actually is a signature. GIGO! - pub fn from_slice(data: &[u8]) -> Self { + pub fn from_slice(data: &[u8]) -> Option { + if data.len() != 65 { + return None + } let mut r = [0u8; 65]; r.copy_from_slice(data); - Signature(r) + Some(Signature(r)) } /// Recover the public key from this signature and a message. #[cfg(feature = "full_crypto")] pub fn recover>(&self, message: M) -> Option { - let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref())); - let sig: (_, _) = self.try_into().ok()?; - libsecp256k1::recover(&message, &sig.0, &sig.1) - .ok() - .map(|recovered| Public(recovered.serialize_compressed())) + self.recover_prehashed(&blake2_256(message.as_ref())) } /// Recover the public key from this signature and a pre-hashed message. #[cfg(feature = "full_crypto")] pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option { - let message = libsecp256k1::Message::parse(message); - - let sig: (_, _) = self.try_into().ok()?; - - libsecp256k1::recover(&message, &sig.0, &sig.1) + let rid = RecoveryId::from_i32(self.0[64] as i32).ok()?; + let sig = RecoverableSignature::from_compact(&self.0[..64], rid).ok()?; + let message = Message::from_slice(message).expect("Message is 32 bytes; qed"); + SECP256K1 + .recover_ecdsa(&message, &sig) .ok() - .map(|key| Public(key.serialize_compressed())) + .map(|pubkey| Public(pubkey.serialize())) } } #[cfg(feature = "full_crypto")] -impl From<(libsecp256k1::Signature, libsecp256k1::RecoveryId)> for Signature { - fn from(x: (libsecp256k1::Signature, libsecp256k1::RecoveryId)) -> Signature { +impl From for Signature { + fn from(recsig: RecoverableSignature) -> Signature { let mut r = Self::default(); - r.0[0..64].copy_from_slice(&x.0.serialize()[..]); - r.0[64] = x.1.serialize(); + let (recid, sig) = recsig.serialize_compact(); + r.0[..64].copy_from_slice(&sig); + // This is safe due to the limited range of possible valid ids. + r.0[64] = recid.to_i32() as u8; r } } -#[cfg(feature = "full_crypto")] -impl<'a> TryFrom<&'a Signature> for (libsecp256k1::Signature, libsecp256k1::RecoveryId) { - type Error = (); - fn try_from( - x: &'a Signature, - ) -> Result<(libsecp256k1::Signature, libsecp256k1::RecoveryId), Self::Error> { - parse_signature_standard(&x.0).map_err(|_| ()) - } -} - /// Derive a single hard junction. #[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { @@ -362,7 +370,7 @@ pub enum DeriveError { #[cfg(feature = "full_crypto")] #[derive(Clone)] pub struct Pair { - public: PublicKey, + public: Public, secret: SecretKey, } @@ -416,8 +424,9 @@ impl TraitPair for Pair { /// You should never need to use this; generate(), generate_with_phrase fn from_seed_slice(seed_slice: &[u8]) -> Result { let secret = - SecretKey::parse_slice(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?; - let public = PublicKey::from_secret_key(&secret); + SecretKey::from_slice(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?; + let public = PublicKey::from_secret_key(SECP256K1, &secret); + let public = Public(public.serialize()); Ok(Pair { public, secret }) } @@ -427,7 +436,7 @@ impl TraitPair for Pair { path: Iter, _seed: Option, ) -> Result<(Pair, Option), DeriveError> { - let mut acc = self.secret.serialize(); + let mut acc = self.seed(); for j in path { match j { DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), @@ -439,25 +448,19 @@ impl TraitPair for Pair { /// Get the public key. fn public(&self) -> Public { - Public(self.public.serialize_compressed()) + self.public } /// Sign a message. fn sign(&self, message: &[u8]) -> Signature { - let message = libsecp256k1::Message::parse(&blake2_256(message)); - libsecp256k1::sign(&message, &self.secret).into() + self.sign_prehashed(&blake2_256(message)) } /// Verify a signature on a message. Returns true if the signature is good. fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref())); - let sig: (_, _) = match sig.try_into() { - Ok(x) => x, - _ => return false, - }; - match libsecp256k1::recover(&message, &sig.0, &sig.1) { - Ok(actual) => pubkey.0[..] == actual.serialize_compressed()[..], - _ => false, + match sig.recover(message) { + Some(actual) => actual == *pubkey, + None => false, } } @@ -466,17 +469,9 @@ impl TraitPair for Pair { /// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct /// size. Use it only if you're coming from byte buffers and need the speed. fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { - let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref())); - if sig.len() != 65 { - return false - } - let (sig, ri) = match parse_signature_standard(&sig) { - Ok(sigri) => sigri, - _ => return false, - }; - match libsecp256k1::recover(&message, &sig, &ri) { - Ok(actual) => pubkey.as_ref() == &actual.serialize()[1..], - _ => false, + match Signature::from_slice(sig).and_then(|sig| sig.recover(message)) { + Some(actual) => actual.as_ref() == pubkey.as_ref(), + None => false, } } @@ -490,7 +485,7 @@ impl TraitPair for Pair { impl Pair { /// Get the seed for this key. pub fn seed(&self) -> Seed { - self.secret.serialize() + self.secret.serialize_secret() } /// Exactly as `from_string` except that if no matches are found then, the the first 32 @@ -507,57 +502,57 @@ impl Pair { /// Sign a pre-hashed message pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature { - let message = libsecp256k1::Message::parse(message); - libsecp256k1::sign(&message, &self.secret).into() + let message = Message::from_slice(message).expect("Message is 32 bytes; qed"); + SECP256K1.sign_ecdsa_recoverable(&message, &self.secret).into() } /// Verify a signature on a pre-hashed message. Return `true` if the signature is valid /// and thus matches the given `public` key. pub fn verify_prehashed(sig: &Signature, message: &[u8; 32], public: &Public) -> bool { - let message = libsecp256k1::Message::parse(message); - - let sig: (_, _) = match sig.try_into() { - Ok(x) => x, - _ => return false, - }; - - match libsecp256k1::recover(&message, &sig.0, &sig.1) { - Ok(actual) => public.0[..] == actual.serialize_compressed()[..], - _ => false, + match sig.recover_prehashed(message) { + Some(actual) => actual == *public, + None => false, } } /// Verify a signature on a message. Returns true if the signature is good. - /// Parses Signature using parse_overflowing_slice + /// Parses Signature using parse_overflowing_slice. + #[deprecated(note = "please use `verify` instead")] pub fn verify_deprecated>(sig: &Signature, message: M, pubkey: &Public) -> bool { let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref())); - let (sig, ri) = match parse_signature_overflowing(&sig.0) { - Ok(sigri) => sigri, + + let parse_signature_overflowing = |x: [u8; 65]| { + let sig = libsecp256k1::Signature::parse_overflowing_slice(&x[..64]).ok()?; + let rid = libsecp256k1::RecoveryId::parse(x[64]).ok()?; + Some((sig, rid)) + }; + + let (sig, rid) = match parse_signature_overflowing(sig.0) { + Some(sigri) => sigri, _ => return false, }; - match libsecp256k1::recover(&message, &sig, &ri) { - Ok(actual) => pubkey.0[..] == actual.serialize_compressed()[..], + match libsecp256k1::recover(&message, &sig, &rid) { + Ok(actual) => pubkey.0 == actual.serialize_compressed(), _ => false, } } } +// The `secp256k1` backend doesn't implement cleanup for their private keys. +// Currently we should take care of wiping the secret from memory. +// NOTE: this solution is not effective when `Pair` is moved around memory. +// The very same problem affects other cryptographic backends that are just using +// `zeroize`for their secrets. #[cfg(feature = "full_crypto")] -fn parse_signature_standard( - x: &[u8], -) -> Result<(libsecp256k1::Signature, libsecp256k1::RecoveryId), libsecp256k1::Error> { - let sig = libsecp256k1::Signature::parse_standard_slice(&x[..64])?; - let ri = libsecp256k1::RecoveryId::parse(x[64])?; - Ok((sig, ri)) -} - -#[cfg(feature = "full_crypto")] -fn parse_signature_overflowing( - x: &[u8], -) -> Result<(libsecp256k1::Signature, libsecp256k1::RecoveryId), libsecp256k1::Error> { - let sig = libsecp256k1::Signature::parse_overflowing_slice(&x[..64])?; - let ri = libsecp256k1::RecoveryId::parse(x[64])?; - Ok((sig, ri)) +impl Drop for Pair { + fn drop(&mut self) { + let ptr = self.secret.as_mut_ptr(); + for off in 0..self.secret.len() { + unsafe { + core::ptr::write_volatile(ptr.add(off), 0); + } + } + } } impl CryptoType for Public { @@ -578,12 +573,9 @@ impl CryptoType for Pair { #[cfg(test)] mod test { use super::*; - use crate::{ - crypto::{ - set_default_ss58_version, PublicError, Ss58AddressFormat, Ss58AddressFormatRegistry, - DEV_PHRASE, - }, - keccak_256, + use crate::crypto::{ + set_default_ss58_version, PublicError, Ss58AddressFormat, Ss58AddressFormatRegistry, + DEV_PHRASE, }; use hex_literal::hex; use serde_json; @@ -802,22 +794,20 @@ mod test { // `msg` shouldn't be mangled let msg = [0u8; 32]; let sig1 = pair.sign_prehashed(&msg); - let sig2: Signature = - libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), &pair.secret).into(); - + let sig2: Signature = { + let message = Message::from_slice(&msg).unwrap(); + SECP256K1.sign_ecdsa_recoverable(&message, &pair.secret).into() + }; assert_eq!(sig1, sig2); // signature is actually different let sig2 = pair.sign(&msg); - assert_ne!(sig1, sig2); // using pre-hashed `msg` works - let msg = keccak_256(b"this should be hashed"); - let sig1 = pair.sign_prehashed(&msg); - let sig2: Signature = - libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), &pair.secret).into(); - + let msg = b"this should be hashed"; + let sig1 = pair.sign_prehashed(&blake2_256(msg)); + let sig2 = pair.sign(msg); assert_eq!(sig1, sig2); } @@ -826,12 +816,12 @@ mod test { let (pair, _, _) = Pair::generate_with_phrase(Some("password")); // `msg` and `sig` match - let msg = keccak_256(b"this should be hashed"); + let msg = blake2_256(b"this should be hashed"); let sig = pair.sign_prehashed(&msg); assert!(Pair::verify_prehashed(&sig, &msg, &pair.public())); // `msg` and `sig` don't match - let msg = keccak_256(b"this is a different message"); + let msg = blake2_256(b"this is a different message"); assert!(!Pair::verify_prehashed(&sig, &msg, &pair.public())); } @@ -840,7 +830,7 @@ mod test { let (pair, _, _) = Pair::generate_with_phrase(Some("password")); // recovered key matches signing key - let msg = keccak_256(b"this should be hashed"); + let msg = blake2_256(b"this should be hashed"); let sig = pair.sign_prehashed(&msg); let key = sig.recover_prehashed(&msg).unwrap(); assert_eq!(pair.public(), key); @@ -849,7 +839,7 @@ mod test { assert!(Pair::verify_prehashed(&sig, &msg, &key)); // recovered key and signing key don't match - let msg = keccak_256(b"this is a different message"); + let msg = blake2_256(b"this is a different message"); let key = sig.recover_prehashed(&msg).unwrap(); assert_ne!(pair.public(), key); } diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 54f9ed7fc0e30..555c23c6b60cc 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -321,10 +321,13 @@ impl Signature { /// /// NOTE: No checking goes on to ensure this is a real signature. Only use it if /// you are certain that the array actually is a signature. GIGO! - pub fn from_slice(data: &[u8]) -> Self { + pub fn from_slice(data: &[u8]) -> Option { + if data.len() != 64 { + return None + } let mut r = [0u8; 64]; r.copy_from_slice(data); - Signature(r) + Some(Signature(r)) } /// A new instance from an H512. diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index 5e18e02c0ffd8..2f298fa2a2666 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -341,10 +341,13 @@ impl Signature { /// /// NOTE: No checking goes on to ensure this is a real signature. Only use it if /// you are certain that the array actually is a signature. GIGO! - pub fn from_slice(data: &[u8]) -> Self { + pub fn from_slice(data: &[u8]) -> Option { + if data.len() != 64 { + return None + } let mut r = [0u8; 64]; r.copy_from_slice(data); - Signature(r) + Some(Signature(r)) } /// A new instance from an H512. diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index b28db8c1ff3dc..6cc6c47ddc962 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -30,6 +30,7 @@ sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" log = { version = "0.4.8", optional = true } futures = { version = "0.3.1", features = ["thread-pool"], optional = true } parking_lot = { version = "0.12.0", optional = true } +secp256k1 = { version = "0.21.2", features = ["recovery", "global-context"], optional = true } tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.17", default-features = false} @@ -44,6 +45,7 @@ std = [ "sp-trie", "sp-state-machine", "libsecp256k1", + "secp256k1", "sp-runtime-interface/std", "sp-externalities", "sp-wasm-interface/std", diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index db86fe0964156..9f49a098b6add 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -66,6 +66,12 @@ use sp_runtime_interface::{ use codec::{Decode, Encode}; +#[cfg(feature = "std")] +use secp256k1::{ + ecdsa::{RecoverableSignature, RecoveryId}, + Message, SECP256K1, +}; + #[cfg(feature = "std")] use sp_externalities::{Externalities, ExternalitiesExt}; @@ -647,7 +653,7 @@ pub trait Crypto { SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg) .ok() .flatten() - .map(|sig| ed25519::Signature::from_slice(sig.as_slice())) + .and_then(|sig| ed25519::Signature::from_slice(&sig)) } /// Verify `ed25519` signature. @@ -771,7 +777,7 @@ pub trait Crypto { SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg) .ok() .flatten() - .map(|sig| sr25519::Signature::from_slice(sig.as_slice())) + .and_then(|sig| sr25519::Signature::from_slice(&sig)) } /// Verify an `sr25519` signature. @@ -820,7 +826,7 @@ pub trait Crypto { SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg) .ok() .flatten() - .map(|sig| ecdsa::Signature::from_slice(sig.as_slice())) + .and_then(|sig| ecdsa::Signature::from_slice(&sig)) } /// Sign the given a pre-hashed `msg` with the `ecdsa` key that corresponds to the given public @@ -842,7 +848,9 @@ pub trait Crypto { /// Verify `ecdsa` signature. /// /// Returns `true` when the verification was successful. + /// This version is able to handle, non-standard, overflowing signatures. fn ecdsa_verify(sig: &ecdsa::Signature, msg: &[u8], pub_key: &ecdsa::Public) -> bool { + #[allow(deprecated)] ecdsa::Pair::verify_deprecated(sig, msg, pub_key) } @@ -891,18 +899,20 @@ pub trait Crypto { /// /// Returns `Err` if the signature is bad, otherwise the 64-byte pubkey /// (doesn't include the 0x04 prefix). + /// This version is able to handle, non-standard, overflowing signatures. fn secp256k1_ecdsa_recover( sig: &[u8; 65], msg: &[u8; 32], ) -> Result<[u8; 64], EcdsaVerifyError> { - let rs = libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64]) - .map_err(|_| EcdsaVerifyError::BadRS)?; - let v = libsecp256k1::RecoveryId::parse( - if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8 + let rid = libsecp256k1::RecoveryId::parse( + if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8, ) .map_err(|_| EcdsaVerifyError::BadV)?; - let pubkey = libsecp256k1::recover(&libsecp256k1::Message::parse(msg), &rs, &v) - .map_err(|_| EcdsaVerifyError::BadSignature)?; + let sig = libsecp256k1::Signature::parse_overflowing_slice(&sig[..64]) + .map_err(|_| EcdsaVerifyError::BadRS)?; + let msg = libsecp256k1::Message::parse(msg); + let pubkey = + libsecp256k1::recover(&msg, &sig, &rid).map_err(|_| EcdsaVerifyError::BadSignature)?; let mut res = [0u8; 64]; res.copy_from_slice(&pubkey.serialize()[1..65]); Ok(res) @@ -920,16 +930,16 @@ pub trait Crypto { sig: &[u8; 65], msg: &[u8; 32], ) -> Result<[u8; 64], EcdsaVerifyError> { - let rs = libsecp256k1::Signature::parse_standard_slice(&sig[0..64]) + let rid = RecoveryId::from_i32(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as i32) + .map_err(|_| EcdsaVerifyError::BadV)?; + let sig = RecoverableSignature::from_compact(&sig[..64], rid) .map_err(|_| EcdsaVerifyError::BadRS)?; - let v = libsecp256k1::RecoveryId::parse( - if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8 - ) - .map_err(|_| EcdsaVerifyError::BadV)?; - let pubkey = libsecp256k1::recover(&libsecp256k1::Message::parse(msg), &rs, &v) + let msg = Message::from_slice(msg).expect("Message is 32 bytes; qed"); + let pubkey = SECP256K1 + .recover_ecdsa(&msg, &sig) .map_err(|_| EcdsaVerifyError::BadSignature)?; let mut res = [0u8; 64]; - res.copy_from_slice(&pubkey.serialize()[1..65]); + res.copy_from_slice(&pubkey.serialize_uncompressed()[1..]); Ok(res) } @@ -943,14 +953,15 @@ pub trait Crypto { sig: &[u8; 65], msg: &[u8; 32], ) -> Result<[u8; 33], EcdsaVerifyError> { - let rs = libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64]) - .map_err(|_| EcdsaVerifyError::BadRS)?; - let v = libsecp256k1::RecoveryId::parse( - if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8 + let rid = libsecp256k1::RecoveryId::parse( + if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8, ) .map_err(|_| EcdsaVerifyError::BadV)?; - let pubkey = libsecp256k1::recover(&libsecp256k1::Message::parse(msg), &rs, &v) - .map_err(|_| EcdsaVerifyError::BadSignature)?; + let sig = libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64]) + .map_err(|_| EcdsaVerifyError::BadRS)?; + let msg = libsecp256k1::Message::parse(msg); + let pubkey = + libsecp256k1::recover(&msg, &sig, &rid).map_err(|_| EcdsaVerifyError::BadSignature)?; Ok(pubkey.serialize_compressed()) } @@ -965,15 +976,15 @@ pub trait Crypto { sig: &[u8; 65], msg: &[u8; 32], ) -> Result<[u8; 33], EcdsaVerifyError> { - let rs = libsecp256k1::Signature::parse_standard_slice(&sig[0..64]) + let rid = RecoveryId::from_i32(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as i32) + .map_err(|_| EcdsaVerifyError::BadV)?; + let sig = RecoverableSignature::from_compact(&sig[..64], rid) .map_err(|_| EcdsaVerifyError::BadRS)?; - let v = libsecp256k1::RecoveryId::parse( - if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8 - ) - .map_err(|_| EcdsaVerifyError::BadV)?; - let pubkey = libsecp256k1::recover(&libsecp256k1::Message::parse(msg), &rs, &v) + let msg = Message::from_slice(msg).expect("Message is 32 bytes; qed"); + let pubkey = SECP256K1 + .recover_ecdsa(&msg, &sig) .map_err(|_| EcdsaVerifyError::BadSignature)?; - Ok(pubkey.serialize_compressed()) + Ok(pubkey.serialize()) } } From 8da9ad8bc619f2c782ff4a343cd5cdfb346c58b1 Mon Sep 17 00:00:00 2001 From: omadoyeabraham Date: Mon, 28 Feb 2022 10:47:04 +0100 Subject: [PATCH 0552/1472] Integrate try-runtime into substrate node template (#10909) * [10892-integrate-try-runtime-into-node-template] - Integrated try-runtime into node template * [10892-integrate-try-runtime-into-node-template] Added match arms for try-runtime in command.rs * [10892-integrate-try-runtime-into-node-template] Added match arms for try-runtime in command.rs * Added feature flag for try-runtime in node-template/node and enabled try-runtime for node-template/runtime * Added missing type annotations for try-runtime SubCommand in node-template * Added missing type annotations for try-runtime SubCommand in node-template * Implemented frame_try_runtime::TryRuntime for the node-template Runtime --- Cargo.lock | 2 ++ bin/node-template/node/Cargo.toml | 6 ++++++ bin/node-template/node/src/cli.rs | 8 ++++++++ bin/node-template/node/src/command.rs | 17 +++++++++++++++++ bin/node-template/runtime/Cargo.toml | 12 ++++++++++++ bin/node-template/runtime/src/lib.rs | 15 +++++++++++++++ 6 files changed, 60 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 66910db9d31b7..1e44edc89994c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5085,6 +5085,7 @@ dependencies = [ "sp-timestamp", "substrate-build-script-utils", "substrate-frame-rpc-system", + "try-runtime-cli", ] [[package]] @@ -5097,6 +5098,7 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", + "frame-try-runtime", "hex-literal", "pallet-aura", "pallet-balances", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 1f8ff0ae1e0d4..ea14942afee06 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -55,9 +55,15 @@ frame-benchmarking-cli = { version = "4.0.0-dev", path = "../../../utils/frame/b # Local Dependencies node-template-runtime = { version = "4.0.0-dev", path = "../runtime" } +# CLI-specific dependencies +try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../utils/frame/try-runtime/cli" } + [build-dependencies] substrate-build-script-utils = { version = "3.0.0", path = "../../../utils/build-script-utils" } [features] default = [] runtime-benchmarks = ["node-template-runtime/runtime-benchmarks"] +# Enable features that allow the runtime to be tried and debugged. Name might be subject to change +# in the near future. +try-runtime = ["node-template-runtime/try-runtime", "try-runtime-cli"] diff --git a/bin/node-template/node/src/cli.rs b/bin/node-template/node/src/cli.rs index d787f57f071a6..c4d27b71e4994 100644 --- a/bin/node-template/node/src/cli.rs +++ b/bin/node-template/node/src/cli.rs @@ -39,4 +39,12 @@ pub enum Subcommand { /// The custom benchmark subcommand benchmarking runtime pallets. #[clap(name = "benchmark", about = "Benchmark runtime pallets.")] Benchmark(frame_benchmarking_cli::BenchmarkCmd), + + /// Try some command against runtime state. + #[cfg(feature = "try-runtime")] + TryRuntime(try_runtime_cli::TryRuntimeCmd), + + /// Try some command against runtime state. Note: `try-runtime` feature must be enabled. + #[cfg(not(feature = "try-runtime"))] + TryRuntime, } diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index e1cfeaeb801e3..72c7a75b387bb 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -108,6 +108,23 @@ pub fn run() -> sc_cli::Result<()> { `--features runtime-benchmarks`." .into()) }, + #[cfg(feature = "try-runtime")] + Some(Subcommand::TryRuntime(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + // we don't need any of the components of new_partial, just a runtime, or a task + // manager to do `async_run`. + let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry); + let task_manager = + sc_service::TaskManager::new(config.tokio_handle.clone(), registry) + .map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?; + Ok((cmd.run::(config), task_manager)) + }) + }, + #[cfg(not(feature = "try-runtime"))] + Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \ + You can enable it with `--features try-runtime`." + .into()), None => { let runner = cli.create_runner(&cli.run)?; runner.run_node_until_exit(|config| async move { diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index ca3b4d93e6b67..95021227cf4fe 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -23,6 +23,7 @@ pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../. pallet-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/randomness-collective-flip" } pallet-sudo = { version = "4.0.0-dev", default-features = false, path = "../../../frame/sudo" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } +frame-try-runtime = { version = "0.10.0-dev", default-features = false, path = "../../../frame/try-runtime", optional = true } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../../frame/timestamp" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" } frame-executive = { version = "4.0.0-dev", default-features = false, path = "../../../frame/executive" } @@ -94,3 +95,14 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] +try-runtime = [ + "frame-executive/try-runtime", + "frame-try-runtime", + "frame-system/try-runtime", + "pallet-balances/try-runtime", + "pallet-grandpa/try-runtime", + "pallet-randomness-collective-flip/try-runtime", + "pallet-sudo/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", +] diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 0b39d76fe495e..93cf234fa52b8 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -515,4 +515,19 @@ impl_runtime_apis! { Ok(batches) } } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade() -> (Weight, Weight) { + // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to + // have a backtrace here. If any of the pre/post migration checks fail, we shall stop + // right here and right now. + let weight = Executive::try_runtime_upgrade().unwrap(); + (weight, BlockWeights::get().max_block) + } + + fn execute_block_no_check(block: Block) -> Weight { + Executive::execute_block_no_check(block) + } + } } From e073c241c3c9e48e0678581029bac84ba32dbb09 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Mon, 28 Feb 2022 13:58:30 +0000 Subject: [PATCH 0553/1472] doc corrections (#10936) --- frame/election-provider-multi-phase/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 9413984f80dbf..8b4ae60facb5f 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -103,7 +103,7 @@ //! //! Validators will only submit solutions if the one that they have computed is sufficiently better //! than the best queued one (see [`pallet::Config::SolutionImprovementThreshold`]) and will limit -//! the weigh of the solution to [`pallet::Config::MinerMaxWeight`]. +//! the weight of the solution to [`pallet::Config::MinerMaxWeight`]. //! //! The unsigned phase can be made passive depending on how the previous signed phase went, by //! setting the first inner value of [`Phase`] to `false`. For now, the signed phase is always @@ -147,13 +147,13 @@ //! which is capable of connecting to a live network, and generating appropriate `supports` using a //! standard algorithm, and outputting the `supports` in hex format, ready for submission. Note that //! while this binary lives in the Polkadot repository, this particular subcommand of it can work -//! against any substrate based-chain. +//! against any substrate-based chain. //! //! See the `staking-miner` documentation in the Polkadot repository for more information. //! //! ## Feasible Solution (correct solution) //! -//! All submissions must undergo a feasibility check. Signed solutions are checked on by one at the +//! All submissions must undergo a feasibility check. Signed solutions are checked one by one at the //! end of the signed phase, and the unsigned solutions are checked on the spot. A feasible solution //! is as follows: //! From 79d04758ec7feed94842ae9f9955c05c42646070 Mon Sep 17 00:00:00 2001 From: Roman Gafiyatullin Date: Mon, 28 Feb 2022 23:51:35 +0200 Subject: [PATCH 0554/1472] #10576: generic utility to unsubscribe from broadcast upon drop of the rx-side. (#10708) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #10576: refactor `sc-utils::notification` and `sc-client-api::notifications`, so that they use common subscribe/unsubscribe routines * Add some docs. Reorganise `sc-utils::notification` * `sc-clent-api::notifications` and `sc-utils::notification` — ensure the SubscriptionGuard is dropped before the Rx-channel * `sc-utils::pubsub::SubscriptionGuard` make it a bit more ergonomic. Let the `Rx` to be put inside of the `SubscriptionGuard`, so that the latter shall guarantee the order: - first unsubscribe; - then drop the `Rx`. * Being less zealous with splitting the modules into little pieces * rework pubsub: the concrete usage should only define a good registry type * sc-client-api::notifications: make it comply with the reworked pubsub * cargo fmt * make sc-client-api tests work * Address the review notes * cargo fmt * Describe the behaviour of pubsub registry * Doc-comments for module `sc-utils::pubsub` * Fix: it used to send notifications regardless of the filter setup during subscription * `sc-client-api::StorageNotifications` the API does not have to require mut-self-reference. As a result `sc-service::Client` does not have to wrap its `storage_notifications` into a Mutex. * cargo fmt * Several changes addressing the notes by @bckhr. - Remove the `impl Default for StorageNotifications`; - no need for groupping the `remove_from` and `listen_from` into a separate `helpers` module; - remove unnecessary import `use registry::SubscribeOp`. * Add a doc-comment to the `sc-client::notifications::SubscribeOp` * As per @bkchr note on the unproven assertion: behave gracefully upon receiving a duplicate subscription-ID. * sc-utils::pubsub: log when a registry yields an ID that does point to an existing sink * `sc-utils::notifications`: payload materialized lazily * Update Cargo.lock (after adding `log` as a dependency to the `sc-utils`) * `sc-client-api::notifications`: introduce a struct (instead of a type def) for the notification message * Get rid of `sc-utils::pubsub::Channel` trait (instead just use the `sc-utils::mpsc`) * The SubsID is no more generic: the fact it is a `Copy` is known — no need to pass it by ref * sc-utils::pubsub internals do not have to be generic over the channel type * Rename Hub::dispatch into Hub::send * That method was unnecessary (`SubscriberSink::render_notification`) * cargo fmt * No need for a separate UnsubscribeGuard type * Ditch the type-def of SubsID in the sc-utils::pubsub, instead — just use the crate::id_sequence::SeqID * Return the ::Ret when sending an item * Make the `Hub::lock_registry(...)` method more ergonomic * cargo doc links * cargo doc links * Use a simpler name for the type * cargo doc links * Derive `Default` rather than implement it * Derive `Default` rather than implement it * Remove an unnecessary usage of type_name * Define a more cautious order between sinks.remove->registry.unsubscribe and registry.subscribe->sinks.insert * Hub: lock_registry_for_tests->map_registry_for_tests — a safer choice for a public API * Replace Mutex over the shared Registry with a ReentrableMutex+RefCell * sc-utils::pubsub: add tests for a panicking registry * Add the missing copyright headers * Arc> -> Arc<[_]> --- Cargo.lock | 1 + client/api/src/client.rs | 8 +- client/api/src/notifications.rs | 616 ++---------------- client/api/src/notifications/registry.rs | 365 +++++++++++ client/api/src/notifications/tests.rs | 221 +++++++ client/rpc/src/state/state_full.rs | 4 +- client/service/src/client/client.rs | 8 +- client/transaction-pool/api/src/lib.rs | 2 +- client/transaction-pool/tests/pool.rs | 14 +- client/utils/Cargo.toml | 1 + client/utils/src/id_sequence.rs | 54 ++ client/utils/src/lib.rs | 2 + client/utils/src/notification.rs | 143 ++-- client/utils/src/notification/registry.rs | 63 ++ client/utils/src/notification/tests.rs | 52 ++ client/utils/src/pubsub.rs | 263 ++++++++ client/utils/src/pubsub/tests.rs | 123 ++++ .../src/pubsub/tests/normal_operation.rs | 88 +++ .../src/pubsub/tests/panicking_registry.rs | 248 +++++++ 19 files changed, 1604 insertions(+), 672 deletions(-) create mode 100644 client/api/src/notifications/registry.rs create mode 100644 client/api/src/notifications/tests.rs create mode 100644 client/utils/src/id_sequence.rs create mode 100644 client/utils/src/notification/registry.rs create mode 100644 client/utils/src/notification/tests.rs create mode 100644 client/utils/src/pubsub.rs create mode 100644 client/utils/src/pubsub/tests.rs create mode 100644 client/utils/src/pubsub/tests/normal_operation.rs create mode 100644 client/utils/src/pubsub/tests/panicking_registry.rs diff --git a/Cargo.lock b/Cargo.lock index 1e44edc89994c..da474bdcfb210 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9067,6 +9067,7 @@ dependencies = [ "futures 0.3.16", "futures-timer", "lazy_static", + "log 0.4.14", "parking_lot 0.12.0", "prometheus", "tokio-test", diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 949cc42c1c04b..11195e1def28c 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -307,9 +307,9 @@ pub struct FinalityNotification { /// Finalized block header. pub header: Block::Header, /// Path from the old finalized to new finalized parent (implicitly finalized blocks). - pub tree_route: Arc>, + pub tree_route: Arc<[Block::Hash]>, /// Stale branches heads. - pub stale_heads: Arc>, + pub stale_heads: Arc<[Block::Hash]>, } impl TryFrom> for ChainEvent { @@ -336,8 +336,8 @@ impl From> for FinalityNotification { FinalityNotification { hash, header: summary.header, - tree_route: Arc::new(summary.finalized), - stale_heads: Arc::new(summary.stale_heads), + tree_route: Arc::from(summary.finalized), + stale_heads: Arc::from(summary.stale_heads), } } } diff --git a/client/api/src/notifications.rs b/client/api/src/notifications.rs index 8199bc6b97101..36798abc5bde5 100644 --- a/client/api/src/notifications.rs +++ b/client/api/src/notifications.rs @@ -21,30 +21,54 @@ use std::{ collections::{HashMap, HashSet}, pin::Pin, - sync::{Arc, Weak}, + sync::Arc, task::Poll, }; -use fnv::{FnvHashMap, FnvHashSet}; use futures::Stream; -use parking_lot::Mutex; -use prometheus_endpoint::{register, CounterVec, Opts, Registry, U64}; -use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; -use sp_core::{ - hexdisplay::HexDisplay, - storage::{StorageData, StorageKey}, -}; + +use prometheus_endpoint::Registry as PrometheusRegistry; + +use sc_utils::pubsub::{Hub, Receiver}; +use sp_core::storage::{StorageData, StorageKey}; use sp_runtime::traits::Block as BlockT; +mod registry; + +use registry::Registry; + +#[cfg(test)] +mod tests; + +/// A type of a message delivered to the subscribers +#[derive(Debug)] +pub struct StorageNotification { + /// The hash of the block + pub block: Hash, + + /// The set of changes + pub changes: StorageChangeSet, +} + /// Storage change set #[derive(Debug)] pub struct StorageChangeSet { - changes: Arc)>>, - child_changes: Arc)>)>>, + changes: Arc<[(StorageKey, Option)]>, + child_changes: Arc<[(StorageKey, Vec<(StorageKey, Option)>)]>, filter: Keys, child_filters: ChildKeys, } +/// Manages storage listeners. +#[derive(Debug)] +pub struct StorageNotifications(Hub, Registry>); + +/// Type that implements `futures::Stream` of storage change events. +pub struct StorageEventStream(Receiver, Registry>); + +type Keys = Option>; +type ChildKeys = Option>>>; + impl StorageChangeSet { /// Convert the change set into iterator over storage items. pub fn iter<'a>( @@ -80,125 +104,24 @@ impl StorageChangeSet { } } -/// Type that implements `futures::Stream` of storage change events. -pub struct StorageEventStream { - rx: TracingUnboundedReceiver<(H, StorageChangeSet)>, - storage_notifications: Weak>>, - was_triggered: bool, - id: u64, -} - impl Stream for StorageEventStream { - type Item = as Stream>::Item; + type Item = StorageNotification; fn poll_next( - mut self: Pin<&mut Self>, + self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> Poll> { - let result = Stream::poll_next(Pin::new(&mut self.rx), cx); - if result.is_ready() { - self.was_triggered = true; - } - result - } -} - -impl Drop for StorageEventStream { - fn drop(&mut self) { - if let Some(storage_notifications) = self.storage_notifications.upgrade() { - if let Some((keys, child_keys)) = - storage_notifications.lock().remove_subscriber(self.id) - { - if !self.was_triggered { - log::trace!( - target: "storage_notifications", - "Listener was never triggered: id={}, keys={:?}, child_keys={:?}", - self.id, - PrintKeys(&keys), - PrintChildKeys(&child_keys), - ); - } - } - } - } -} - -type SubscriberId = u64; - -type SubscribersGauge = CounterVec; - -/// Manages storage listeners. -#[derive(Debug)] -pub struct StorageNotifications(Arc>>); - -type Keys = Option>; -type ChildKeys = Option>>>; - -#[derive(Debug)] -struct StorageNotificationsImpl { - metrics: Option, - next_id: SubscriberId, - wildcard_listeners: FnvHashSet, - listeners: HashMap>, - child_listeners: HashMap< - StorageKey, - (HashMap>, FnvHashSet), - >, - sinks: FnvHashMap< - SubscriberId, - (TracingUnboundedSender<(Hash, StorageChangeSet)>, Keys, ChildKeys), - >, -} - -impl Default for StorageNotifications { - fn default() -> Self { - Self(Default::default()) - } -} - -impl Default for StorageNotificationsImpl { - fn default() -> Self { - Self { - metrics: Default::default(), - next_id: Default::default(), - wildcard_listeners: Default::default(), - listeners: Default::default(), - child_listeners: Default::default(), - sinks: Default::default(), - } - } -} - -struct PrintKeys<'a>(&'a Keys); -impl<'a> std::fmt::Debug for PrintKeys<'a> { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - if let Some(keys) = self.0 { - fmt.debug_list().entries(keys.iter().map(HexDisplay::from)).finish() - } else { - write!(fmt, "None") - } - } -} - -struct PrintChildKeys<'a>(&'a ChildKeys); -impl<'a> std::fmt::Debug for PrintChildKeys<'a> { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - if let Some(map) = self.0 { - fmt.debug_map() - .entries(map.iter().map(|(key, values)| (HexDisplay::from(key), PrintKeys(values)))) - .finish() - } else { - write!(fmt, "None") - } + Stream::poll_next(Pin::new(&mut self.get_mut().0), cx) } } impl StorageNotifications { /// Initialize a new StorageNotifications /// optionally pass a prometheus registry to send subscriber metrics to - pub fn new(prometheus_registry: Option) -> Self { - StorageNotifications(Arc::new(Mutex::new(StorageNotificationsImpl::new( - prometheus_registry, - )))) + pub fn new(prometheus_registry: Option) -> Self { + let registry = Registry::new(prometheus_registry); + let hub = Hub::new_with_registry("mpsc_storage_notification_items", registry); + + StorageNotifications(hub) } /// Trigger notification to all listeners. @@ -206,467 +129,24 @@ impl StorageNotifications { /// Note the changes are going to be filtered by listener's filter key. /// In fact no event might be sent if clients are not interested in the changes. pub fn trigger( - &mut self, + &self, hash: &Block::Hash, changeset: impl Iterator, Option>)>, child_changeset: impl Iterator< Item = (Vec, impl Iterator, Option>)>), >, ) { - self.0.lock().trigger(hash, changeset, child_changeset); + self.0.send((hash, changeset, child_changeset)) } /// Start listening for particular storage keys. pub fn listen( - &mut self, + &self, filter_keys: Option<&[StorageKey]>, filter_child_keys: Option<&[(StorageKey, Option>)]>, ) -> StorageEventStream { - let (id, rx) = self.0.lock().listen(filter_keys, filter_child_keys); - let storage_notifications = Arc::downgrade(&self.0); - StorageEventStream { rx, storage_notifications, was_triggered: false, id } - } -} - -impl StorageNotificationsImpl { - fn new(prometheus_registry: Option) -> Self { - let metrics = prometheus_registry.and_then(|r| { - CounterVec::new( - Opts::new( - "substrate_storage_notification_subscribers", - "Number of subscribers in storage notification sytem", - ), - &["action"], // added | removed - ) - .and_then(|g| register(g, &r)) - .ok() - }); - - StorageNotificationsImpl { - metrics, - next_id: Default::default(), - wildcard_listeners: Default::default(), - listeners: Default::default(), - child_listeners: Default::default(), - sinks: Default::default(), - } - } - fn trigger( - &mut self, - hash: &Hash, - changeset: impl Iterator, Option>)>, - child_changeset: impl Iterator< - Item = (Vec, impl Iterator, Option>)>), - >, - ) where - Hash: Clone, - { - let has_wildcard = !self.wildcard_listeners.is_empty(); - - // early exit if no listeners - if !has_wildcard && self.listeners.is_empty() && self.child_listeners.is_empty() { - return - } - - let mut subscribers = self.wildcard_listeners.clone(); - let mut changes = Vec::new(); - let mut child_changes = Vec::new(); - - // Collect subscribers and changes - for (k, v) in changeset { - let k = StorageKey(k); - let listeners = self.listeners.get(&k); - - if let Some(ref listeners) = listeners { - subscribers.extend(listeners.iter()); - } - - if has_wildcard || listeners.is_some() { - changes.push((k, v.map(StorageData))); - } - } - for (sk, changeset) in child_changeset { - let sk = StorageKey(sk); - if let Some((cl, cw)) = self.child_listeners.get(&sk) { - let mut changes = Vec::new(); - for (k, v) in changeset { - let k = StorageKey(k); - let listeners = cl.get(&k); - - if let Some(ref listeners) = listeners { - subscribers.extend(listeners.iter()); - } - - subscribers.extend(cw.iter()); - - if !cw.is_empty() || listeners.is_some() { - changes.push((k, v.map(StorageData))); - } - } - if !changes.is_empty() { - child_changes.push((sk, changes)); - } - } - } - - // Don't send empty notifications - if changes.is_empty() && child_changes.is_empty() { - return - } - - let changes = Arc::new(changes); - let child_changes = Arc::new(child_changes); - // Trigger the events - - let to_remove = self - .sinks - .iter() - .filter_map(|(subscriber, &(ref sink, ref filter, ref child_filters))| { - let should_remove = { - if subscribers.contains(subscriber) { - sink.unbounded_send(( - hash.clone(), - StorageChangeSet { - changes: changes.clone(), - child_changes: child_changes.clone(), - filter: filter.clone(), - child_filters: child_filters.clone(), - }, - )) - .is_err() - } else { - sink.is_closed() - } - }; - - if should_remove { - Some(subscriber.clone()) - } else { - None - } - }) - .collect::>(); - - for sub_id in to_remove { - self.remove_subscriber(sub_id); - } - } - - fn remove_subscriber_from( - subscriber: &SubscriberId, - filters: &Keys, - listeners: &mut HashMap>, - wildcards: &mut FnvHashSet, - ) { - match filters { - None => { - wildcards.remove(subscriber); - }, - Some(filters) => - for key in filters.iter() { - let remove_key = match listeners.get_mut(key) { - Some(ref mut set) => { - set.remove(subscriber); - set.is_empty() - }, - None => false, - }; - - if remove_key { - listeners.remove(key); - } - }, - } - } - - fn remove_subscriber(&mut self, subscriber: SubscriberId) -> Option<(Keys, ChildKeys)> { - let (_, filters, child_filters) = self.sinks.remove(&subscriber)?; - Self::remove_subscriber_from( - &subscriber, - &filters, - &mut self.listeners, - &mut self.wildcard_listeners, - ); - if let Some(child_filters) = child_filters.as_ref() { - for (c_key, filters) in child_filters { - if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) { - Self::remove_subscriber_from( - &subscriber, - &filters, - &mut *listeners, - &mut *wildcards, - ); - - if listeners.is_empty() && wildcards.is_empty() { - self.child_listeners.remove(&c_key); - } - } - } - } - if let Some(m) = self.metrics.as_ref() { - m.with_label_values(&[&"removed"]).inc(); - } - - Some((filters, child_filters)) - } - - fn listen_from( - current_id: SubscriberId, - filter_keys: &Option>, - listeners: &mut HashMap>, - wildcards: &mut FnvHashSet, - ) -> Keys { - match filter_keys { - None => { - wildcards.insert(current_id); - None - }, - Some(keys) => Some( - keys.as_ref() - .iter() - .map(|key| { - listeners - .entry(key.clone()) - .or_insert_with(Default::default) - .insert(current_id); - key.clone() - }) - .collect(), - ), - } - } - - fn listen( - &mut self, - filter_keys: Option<&[StorageKey]>, - filter_child_keys: Option<&[(StorageKey, Option>)]>, - ) -> (u64, TracingUnboundedReceiver<(Hash, StorageChangeSet)>) { - self.next_id += 1; - let current_id = self.next_id; - - // add subscriber for every key - let keys = Self::listen_from( - current_id, - &filter_keys, - &mut self.listeners, - &mut self.wildcard_listeners, - ); - let child_keys = filter_child_keys.map(|filter_child_keys| { - filter_child_keys - .iter() - .map(|(c_key, o_keys)| { - let (c_listeners, c_wildcards) = - self.child_listeners.entry(c_key.clone()).or_insert_with(Default::default); - - ( - c_key.clone(), - Self::listen_from(current_id, o_keys, &mut *c_listeners, &mut *c_wildcards), - ) - }) - .collect() - }); - - // insert sink - let (tx, rx) = tracing_unbounded("mpsc_storage_notification_items"); - self.sinks.insert(current_id, (tx, keys, child_keys)); - - if let Some(m) = self.metrics.as_ref() { - m.with_label_values(&[&"added"]).inc(); - } - - (current_id, rx) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash}; - use std::iter::{empty, Empty}; - - type TestChangeSet = ( - Vec<(StorageKey, Option)>, - Vec<(StorageKey, Vec<(StorageKey, Option)>)>, - ); - - #[cfg(test)] - impl From for StorageChangeSet { - fn from(changes: TestChangeSet) -> Self { - // warning hardcoded child trie wildcard to test upon - let child_filters = Some( - [(StorageKey(vec![4]), None), (StorageKey(vec![5]), None)] - .iter() - .cloned() - .collect(), - ); - StorageChangeSet { - changes: Arc::new(changes.0), - child_changes: Arc::new(changes.1), - filter: None, - child_filters, - } - } - } - - #[cfg(test)] - impl PartialEq for StorageChangeSet { - fn eq(&self, other: &Self) -> bool { - self.iter().eq(other.iter()) - } - } - - type Block = RawBlock>; - - #[test] - fn triggering_change_should_notify_wildcard_listeners() { - // given - let mut notifications = StorageNotifications::::default(); - let child_filter = [(StorageKey(vec![4]), None)]; - let mut recv = - futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter[..]))); - - // when - let changeset = vec![(vec![2], Some(vec![3])), (vec![3], None)]; - let c_changeset_1 = vec![(vec![5], Some(vec![4])), (vec![6], None)]; - let c_changeset = vec![(vec![4], c_changeset_1)]; - notifications.trigger( - &Hash::from_low_u64_be(1), - changeset.into_iter(), - c_changeset.into_iter().map(|(a, b)| (a, b.into_iter())), - ); - - // then - assert_eq!( - recv.next().unwrap(), - ( - Hash::from_low_u64_be(1), - ( - vec![ - (StorageKey(vec![2]), Some(StorageData(vec![3]))), - (StorageKey(vec![3]), None), - ], - vec![( - StorageKey(vec![4]), - vec![ - (StorageKey(vec![5]), Some(StorageData(vec![4]))), - (StorageKey(vec![6]), None), - ] - )] - ) - .into() - ) - ); - } - - #[test] - fn should_only_notify_interested_listeners() { - // given - let mut notifications = StorageNotifications::::default(); - let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))]; - let mut recv1 = futures::executor::block_on_stream( - notifications.listen(Some(&[StorageKey(vec![1])]), None), - ); - let mut recv2 = futures::executor::block_on_stream( - notifications.listen(Some(&[StorageKey(vec![2])]), None), - ); - let mut recv3 = futures::executor::block_on_stream( - notifications.listen(Some(&[]), Some(&child_filter)), - ); - - // when - let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)]; - let c_changeset_1 = vec![(vec![5], Some(vec![4])), (vec![6], None)]; - - let c_changeset = vec![(vec![4], c_changeset_1)]; - notifications.trigger( - &Hash::from_low_u64_be(1), - changeset.into_iter(), - c_changeset.into_iter().map(|(a, b)| (a, b.into_iter())), - ); - - // then - assert_eq!( - recv1.next().unwrap(), - (Hash::from_low_u64_be(1), (vec![(StorageKey(vec![1]), None),], vec![]).into()) - ); - assert_eq!( - recv2.next().unwrap(), - ( - Hash::from_low_u64_be(1), - (vec![(StorageKey(vec![2]), Some(StorageData(vec![3]))),], vec![]).into() - ) - ); - assert_eq!( - recv3.next().unwrap(), - ( - Hash::from_low_u64_be(1), - ( - vec![], - vec![( - StorageKey(vec![4]), - vec![(StorageKey(vec![5]), Some(StorageData(vec![4])))] - ),] - ) - .into() - ) - ); - } - - #[test] - fn should_cleanup_subscribers_if_dropped() { - // given - let mut notifications = StorageNotifications::::default(); - { - let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))]; - let _recv1 = futures::executor::block_on_stream( - notifications.listen(Some(&[StorageKey(vec![1])]), None), - ); - let _recv2 = futures::executor::block_on_stream( - notifications.listen(Some(&[StorageKey(vec![2])]), None), - ); - let _recv3 = futures::executor::block_on_stream(notifications.listen(None, None)); - let _recv4 = - futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter))); - assert_eq!(notifications.0.lock().listeners.len(), 2); - assert_eq!(notifications.0.lock().wildcard_listeners.len(), 2); - assert_eq!(notifications.0.lock().child_listeners.len(), 1); - } - - // when - let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)]; - let c_changeset = empty::<(_, Empty<_>)>(); - notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset); - - // then - assert_eq!(notifications.0.lock().listeners.len(), 0); - assert_eq!(notifications.0.lock().wildcard_listeners.len(), 0); - assert_eq!(notifications.0.lock().child_listeners.len(), 0); - } - - #[test] - fn should_cleanup_subscriber_if_stream_is_dropped() { - let mut notifications = StorageNotifications::::default(); - let stream = notifications.listen(None, None); - assert_eq!(notifications.0.lock().sinks.len(), 1); - std::mem::drop(stream); - assert_eq!(notifications.0.lock().sinks.len(), 0); - } - - #[test] - fn should_not_send_empty_notifications() { - // given - let mut recv = { - let mut notifications = StorageNotifications::::default(); - let recv = futures::executor::block_on_stream(notifications.listen(None, None)); - - // when - let changeset = vec![]; - let c_changeset = empty::<(_, Empty<_>)>(); - notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset); - recv - }; + let receiver = self.0.subscribe(registry::SubscribeOp { filter_keys, filter_child_keys }); - // then - assert_eq!(recv.next(), None); + StorageEventStream(receiver) } } diff --git a/client/api/src/notifications/registry.rs b/client/api/src/notifications/registry.rs new file mode 100644 index 0000000000000..b34d5a6b6711e --- /dev/null +++ b/client/api/src/notifications/registry.rs @@ -0,0 +1,365 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; + +use sp_core::hexdisplay::HexDisplay; + +use fnv::{FnvHashMap, FnvHashSet}; +use prometheus_endpoint::{register, CounterVec, Opts, U64}; + +use sc_utils::{ + id_sequence::SeqID as SubscriberId, + pubsub::{Dispatch, Subscribe, Unsubscribe}, +}; + +type SubscribersGauge = CounterVec; + +/// A command to subscribe with the specified filters. +/// +/// Used by the implementation of [`Subscribe`] trait for [`Registry]. +pub(super) struct SubscribeOp<'a> { + pub filter_keys: Option<&'a [StorageKey]>, + pub filter_child_keys: Option<&'a [(StorageKey, Option>)]>, +} + +#[derive(Debug, Default)] +pub(super) struct Registry { + pub(super) metrics: Option, + pub(super) wildcard_listeners: FnvHashSet, + pub(super) listeners: HashMap>, + pub(super) child_listeners: HashMap< + StorageKey, + (HashMap>, FnvHashSet), + >, + pub(super) sinks: FnvHashMap, +} + +#[derive(Debug)] +pub(super) struct SubscriberSink { + subs_id: SubscriberId, + keys: Keys, + child_keys: ChildKeys, + was_triggered: bool, +} + +impl Drop for SubscriberSink { + fn drop(&mut self) { + if !self.was_triggered { + log::trace!( + target: "storage_notifications", + "Listener was never triggered: id={}, keys={:?}, child_keys={:?}", + self.subs_id, + PrintKeys(&self.keys), + PrintChildKeys(&self.child_keys), + ); + } + } +} + +impl SubscriberSink { + fn new(subs_id: SubscriberId, keys: Keys, child_keys: ChildKeys) -> Self { + Self { subs_id, keys, child_keys, was_triggered: false } + } +} + +impl Registry { + pub(super) fn new(prometheus_registry: Option) -> Self { + let metrics = prometheus_registry.and_then(|r| { + CounterVec::new( + Opts::new( + "substrate_storage_notification_subscribers", + "Number of subscribers in storage notification sytem", + ), + &["action"], // added | removed + ) + .and_then(|g| register(g, &r)) + .ok() + }); + + Registry { metrics, ..Default::default() } + } +} + +impl Unsubscribe for Registry { + fn unsubscribe(&mut self, subs_id: SubscriberId) { + self.remove_subscriber(subs_id); + } +} + +impl<'a> Subscribe> for Registry { + fn subscribe(&mut self, subs_op: SubscribeOp<'a>, subs_id: SubscriberId) { + let SubscribeOp { filter_keys, filter_child_keys } = subs_op; + + let keys = Self::listen_from( + subs_id, + filter_keys.as_ref(), + &mut self.listeners, + &mut self.wildcard_listeners, + ); + + let child_keys = filter_child_keys.map(|filter_child_keys| { + filter_child_keys + .iter() + .map(|(c_key, o_keys)| { + let (c_listeners, c_wildcards) = + self.child_listeners.entry(c_key.clone()).or_default(); + + ( + c_key.clone(), + Self::listen_from( + subs_id, + o_keys.as_ref(), + &mut *c_listeners, + &mut *c_wildcards, + ), + ) + }) + .collect() + }); + + if let Some(m) = self.metrics.as_ref() { + m.with_label_values(&[&"added"]).inc(); + } + + if self + .sinks + .insert(subs_id, SubscriberSink::new(subs_id, keys, child_keys)) + .is_some() + { + log::warn!("The `subscribe`-method has been passed a non-unique subs_id (in `sc-client-api::notifications`)"); + } + } +} + +impl<'a, Hash, CS, CCS, CCSI> Dispatch<(&'a Hash, CS, CCS)> for Registry +where + Hash: Clone, + CS: Iterator, Option>)>, + CCS: Iterator, CCSI)>, + CCSI: Iterator, Option>)>, +{ + type Item = StorageNotification; + type Ret = (); + + fn dispatch(&mut self, message: (&'a Hash, CS, CCS), dispatch: F) -> Self::Ret + where + F: FnMut(&SubscriberId, Self::Item), + { + let (hash, changeset, child_changeset) = message; + self.trigger(hash, changeset, child_changeset, dispatch); + } +} + +impl Registry { + pub(super) fn trigger( + &mut self, + hash: &Hash, + changeset: impl Iterator, Option>)>, + child_changeset: impl Iterator< + Item = (Vec, impl Iterator, Option>)>), + >, + mut dispatch: F, + ) where + Hash: Clone, + F: FnMut(&SubscriberId, StorageNotification), + { + let has_wildcard = !self.wildcard_listeners.is_empty(); + + // early exit if no listeners + if !has_wildcard && self.listeners.is_empty() && self.child_listeners.is_empty() { + return + } + + let mut subscribers = self.wildcard_listeners.clone(); + let mut changes = Vec::new(); + let mut child_changes = Vec::new(); + + // Collect subscribers and changes + for (k, v) in changeset { + let k = StorageKey(k); + let listeners = self.listeners.get(&k); + + if let Some(ref listeners) = listeners { + subscribers.extend(listeners.iter()); + } + + if has_wildcard || listeners.is_some() { + changes.push((k, v.map(StorageData))); + } + } + for (sk, changeset) in child_changeset { + let sk = StorageKey(sk); + if let Some((cl, cw)) = self.child_listeners.get(&sk) { + let mut changes = Vec::new(); + for (k, v) in changeset { + let k = StorageKey(k); + let listeners = cl.get(&k); + + if let Some(ref listeners) = listeners { + subscribers.extend(listeners.iter()); + } + + subscribers.extend(cw.iter()); + + if !cw.is_empty() || listeners.is_some() { + changes.push((k, v.map(StorageData))); + } + } + if !changes.is_empty() { + child_changes.push((sk, changes)); + } + } + } + + // Don't send empty notifications + if changes.is_empty() && child_changes.is_empty() { + return + } + + let changes = Arc::<[_]>::from(changes); + let child_changes = Arc::<[_]>::from(child_changes); + + // Trigger the events + self.sinks.iter_mut().for_each(|(subs_id, sink)| { + if subscribers.contains(subs_id) { + sink.was_triggered = true; + + let storage_change_set = StorageChangeSet { + changes: changes.clone(), + child_changes: child_changes.clone(), + filter: sink.keys.clone(), + child_filters: sink.child_keys.clone(), + }; + + let notification = + StorageNotification { block: hash.clone(), changes: storage_change_set }; + + dispatch(subs_id, notification); + } + }); + } +} + +impl Registry { + fn remove_subscriber(&mut self, subscriber: SubscriberId) -> Option<(Keys, ChildKeys)> { + let sink = self.sinks.remove(&subscriber)?; + + Self::remove_subscriber_from( + subscriber, + &sink.keys, + &mut self.listeners, + &mut self.wildcard_listeners, + ); + if let Some(child_filters) = &sink.child_keys { + for (c_key, filters) in child_filters { + if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) { + Self::remove_subscriber_from( + subscriber, + &filters, + &mut *listeners, + &mut *wildcards, + ); + + if listeners.is_empty() && wildcards.is_empty() { + self.child_listeners.remove(&c_key); + } + } + } + } + if let Some(m) = self.metrics.as_ref() { + m.with_label_values(&[&"removed"]).inc(); + } + + Some((sink.keys.clone(), sink.child_keys.clone())) + } + + fn remove_subscriber_from( + subscriber: SubscriberId, + filters: &Keys, + listeners: &mut HashMap>, + wildcards: &mut FnvHashSet, + ) { + match filters { + None => { + wildcards.remove(&subscriber); + }, + Some(filters) => + for key in filters.iter() { + let remove_key = match listeners.get_mut(key) { + Some(ref mut set) => { + set.remove(&subscriber); + set.is_empty() + }, + None => false, + }; + + if remove_key { + listeners.remove(key); + } + }, + } + } + + fn listen_from( + current_id: SubscriberId, + filter_keys: Option>, + listeners: &mut HashMap>, + wildcards: &mut FnvHashSet, + ) -> Keys { + match filter_keys { + None => { + wildcards.insert(current_id); + None + }, + Some(keys) => Some( + keys.as_ref() + .iter() + .map(|key| { + listeners.entry(key.clone()).or_default().insert(current_id); + key.clone() + }) + .collect(), + ), + } + } +} + +pub(super) struct PrintKeys<'a>(pub &'a Keys); +impl<'a> std::fmt::Debug for PrintKeys<'a> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(keys) = self.0 { + fmt.debug_list().entries(keys.iter().map(HexDisplay::from)).finish() + } else { + write!(fmt, "None") + } + } +} + +pub(super) struct PrintChildKeys<'a>(pub &'a ChildKeys); +impl<'a> std::fmt::Debug for PrintChildKeys<'a> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(map) = self.0 { + fmt.debug_map() + .entries(map.iter().map(|(key, values)| (HexDisplay::from(key), PrintKeys(values)))) + .finish() + } else { + write!(fmt, "None") + } + } +} diff --git a/client/api/src/notifications/tests.rs b/client/api/src/notifications/tests.rs new file mode 100644 index 0000000000000..2c728de7428dd --- /dev/null +++ b/client/api/src/notifications/tests.rs @@ -0,0 +1,221 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; + +use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash}; +use std::iter::{empty, Empty}; + +type TestChangeSet = ( + Vec<(StorageKey, Option)>, + Vec<(StorageKey, Vec<(StorageKey, Option)>)>, +); + +impl From for StorageChangeSet { + fn from(changes: TestChangeSet) -> Self { + // warning hardcoded child trie wildcard to test upon + let child_filters = Some( + [(StorageKey(vec![4]), None), (StorageKey(vec![5]), None)] + .iter() + .cloned() + .collect(), + ); + StorageChangeSet { + changes: From::from(changes.0), + child_changes: From::from(changes.1), + filter: None, + child_filters, + } + } +} + +impl PartialEq for StorageChangeSet { + fn eq(&self, other: &Self) -> bool { + self.iter().eq(other.iter()) + } +} + +type Block = RawBlock>; + +#[test] +fn triggering_change_should_notify_wildcard_listeners() { + // given + let notifications = StorageNotifications::::new(None); + let child_filter = [(StorageKey(vec![4]), None)]; + let mut recv = + futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter[..]))); + + // when + let changeset = vec![(vec![2], Some(vec![3])), (vec![3], None)]; + let c_changeset_1 = vec![(vec![5], Some(vec![4])), (vec![6], None)]; + let c_changeset = vec![(vec![4], c_changeset_1)]; + notifications.trigger( + &Hash::from_low_u64_be(1), + changeset.into_iter(), + c_changeset.into_iter().map(|(a, b)| (a, b.into_iter())), + ); + + // then + assert_eq!( + recv.next().map(StorageNotification::into_fields).unwrap(), + ( + Hash::from_low_u64_be(1), + ( + vec![ + (StorageKey(vec![2]), Some(StorageData(vec![3]))), + (StorageKey(vec![3]), None), + ], + vec![( + StorageKey(vec![4]), + vec![ + (StorageKey(vec![5]), Some(StorageData(vec![4]))), + (StorageKey(vec![6]), None), + ] + )] + ) + .into() + ) + ); +} + +#[test] +fn should_only_notify_interested_listeners() { + // given + let notifications = StorageNotifications::::new(None); + let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))]; + let mut recv1 = futures::executor::block_on_stream( + notifications.listen(Some(&[StorageKey(vec![1])]), None), + ); + let mut recv2 = futures::executor::block_on_stream( + notifications.listen(Some(&[StorageKey(vec![2])]), None), + ); + let mut recv3 = + futures::executor::block_on_stream(notifications.listen(Some(&[]), Some(&child_filter))); + + // when + let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)]; + let c_changeset_1 = vec![(vec![5], Some(vec![4])), (vec![6], None)]; + + let c_changeset = vec![(vec![4], c_changeset_1)]; + notifications.trigger( + &Hash::from_low_u64_be(1), + changeset.into_iter(), + c_changeset.into_iter().map(|(a, b)| (a, b.into_iter())), + ); + + // then + assert_eq!( + recv1.next().map(StorageNotification::into_fields).unwrap(), + (Hash::from_low_u64_be(1), (vec![(StorageKey(vec![1]), None),], vec![]).into()) + ); + assert_eq!( + recv2.next().map(StorageNotification::into_fields).unwrap(), + ( + Hash::from_low_u64_be(1), + (vec![(StorageKey(vec![2]), Some(StorageData(vec![3]))),], vec![]).into() + ) + ); + assert_eq!( + recv3.next().map(StorageNotification::into_fields).unwrap(), + ( + Hash::from_low_u64_be(1), + ( + vec![], + vec![( + StorageKey(vec![4]), + vec![(StorageKey(vec![5]), Some(StorageData(vec![4])))] + ),] + ) + .into() + ) + ); +} + +#[test] +fn should_cleanup_subscribers_if_dropped() { + // given + let notifications = StorageNotifications::::new(None); + { + let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))]; + let _recv1 = futures::executor::block_on_stream( + notifications.listen(Some(&[StorageKey(vec![1])]), None), + ); + let _recv2 = futures::executor::block_on_stream( + notifications.listen(Some(&[StorageKey(vec![2])]), None), + ); + let _recv3 = futures::executor::block_on_stream(notifications.listen(None, None)); + let _recv4 = + futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter))); + assert_eq!(notifications.map_registry(|r| r.listeners.len()), 2); + assert_eq!(notifications.map_registry(|r| r.wildcard_listeners.len()), 2); + assert_eq!(notifications.map_registry(|r| r.child_listeners.len()), 1); + } + + // when + let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)]; + let c_changeset = empty::<(_, Empty<_>)>(); + notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset); + + // then + assert_eq!(notifications.map_registry(|r| r.listeners.len()), 0); + assert_eq!(notifications.map_registry(|r| r.wildcard_listeners.len()), 0); + assert_eq!(notifications.map_registry(|r| r.child_listeners.len()), 0); +} + +#[test] +fn should_cleanup_subscriber_if_stream_is_dropped() { + let notifications = StorageNotifications::::new(None); + let stream = notifications.listen(None, None); + assert_eq!(notifications.map_registry(|r| r.sinks.len()), 1); + std::mem::drop(stream); + assert_eq!(notifications.map_registry(|r| r.sinks.len()), 0); +} + +#[test] +fn should_not_send_empty_notifications() { + // given + let mut recv = { + let notifications = StorageNotifications::::new(None); + let recv = futures::executor::block_on_stream(notifications.listen(None, None)); + + // when + let changeset = vec![]; + let c_changeset = empty::<(_, Empty<_>)>(); + notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset); + recv + }; + + // then + assert_eq!(recv.next().map(StorageNotification::into_fields), None); +} + +impl StorageNotifications { + fn map_registry(&self, map: MapF) -> Ret + where + MapF: FnOnce(&Registry) -> Ret, + { + self.0.map_registry_for_tests(map) + } +} + +impl StorageNotification { + fn into_fields(self) -> (H, StorageChangeSet) { + let Self { block, changes } = self; + (block, changes) + } +} diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index b8132094fe8d6..1a35760bd67df 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -51,7 +51,7 @@ use super::{ }; use sc_client_api::{ Backend, BlockBackend, BlockchainEvents, CallExecutor, ExecutorProvider, ProofProvider, - StorageProvider, + StorageNotification, StorageProvider, }; use std::marker::PhantomData; @@ -466,7 +466,7 @@ where ); self.subscriptions.add(subscriber, |sink| { - let stream = stream.map(|(block, changes)| { + let stream = stream.map(|StorageNotification { block, changes }| { Ok(Ok::<_, rpc::Error>(StorageChangeSet { block, changes: changes diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 8497c34f5abbb..004d4b711e091 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -107,7 +107,7 @@ where { backend: Arc, executor: E, - storage_notifications: Mutex>, + storage_notifications: StorageNotifications, import_notification_sinks: NotificationSinks>, finality_notification_sinks: NotificationSinks>, // Collects auxiliary operations to be performed atomically together with @@ -393,7 +393,7 @@ where Ok(Client { backend, executor, - storage_notifications: Mutex::new(StorageNotifications::new(prometheus_registry)), + storage_notifications: StorageNotifications::new(prometheus_registry), import_notification_sinks: Default::default(), finality_notification_sinks: Default::default(), import_actions: Default::default(), @@ -986,7 +986,7 @@ where if let Some(storage_changes) = storage_changes { // TODO [ToDr] How to handle re-orgs? Should we re-emit all storage changes? - self.storage_notifications.lock().trigger( + self.storage_notifications.trigger( ¬ification.hash, storage_changes.0.into_iter(), storage_changes.1.into_iter().map(|(sk, v)| (sk, v.into_iter())), @@ -1951,7 +1951,7 @@ where filter_keys: Option<&[StorageKey]>, child_filter_keys: Option<&[(StorageKey, Option>)]>, ) -> sp_blockchain::Result> { - Ok(self.storage_notifications.lock().listen(filter_keys, child_filter_keys)) + Ok(self.storage_notifications.listen(filter_keys, child_filter_keys)) } } diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index 7c90cd79ccaed..d7b3ddc996362 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -292,7 +292,7 @@ pub enum ChainEvent { /// Hash of just finalized block. hash: B::Hash, /// Path from old finalized to new finalized parent. - tree_route: Arc>, + tree_route: Arc<[B::Hash]>, }, } diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 21a87f6e006ec..08ecdbc86cca4 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -387,7 +387,7 @@ fn should_push_watchers_during_maintenance() { let header_hash = header.hash(); block_on(pool.maintain(block_event(header))); - let event = ChainEvent::Finalized { hash: header_hash.clone(), tree_route: Arc::new(vec![]) }; + let event = ChainEvent::Finalized { hash: header_hash.clone(), tree_route: Arc::from(vec![]) }; block_on(pool.maintain(event)); // then @@ -445,7 +445,7 @@ fn finalization() { let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; block_on(pool.maintain(event)); - let event = ChainEvent::Finalized { hash: header.hash(), tree_route: Arc::new(vec![]) }; + let event = ChainEvent::Finalized { hash: header.hash(), tree_route: Arc::from(vec![]) }; block_on(pool.maintain(event)); let mut stream = futures::executor::block_on_stream(watcher); @@ -493,7 +493,7 @@ fn fork_aware_finalization() { b1 = header.hash(); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 0); - let event = ChainEvent::Finalized { hash: b1, tree_route: Arc::new(vec![]) }; + let event = ChainEvent::Finalized { hash: b1, tree_route: Arc::from(vec![]) }; block_on(pool.maintain(event)); } @@ -537,7 +537,7 @@ fn fork_aware_finalization() { block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 2); - let event = ChainEvent::Finalized { hash: header.hash(), tree_route: Arc::new(vec![]) }; + let event = ChainEvent::Finalized { hash: header.hash(), tree_route: Arc::from(vec![]) }; block_on(pool.maintain(event)); } @@ -554,7 +554,7 @@ fn fork_aware_finalization() { d1 = header.hash(); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 2); - let event = ChainEvent::Finalized { hash: d1, tree_route: Arc::new(vec![]) }; + let event = ChainEvent::Finalized { hash: d1, tree_route: Arc::from(vec![]) }; block_on(pool.maintain(event)); } @@ -567,7 +567,7 @@ fn fork_aware_finalization() { let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 0); - block_on(pool.maintain(ChainEvent::Finalized { hash: e1, tree_route: Arc::new(vec![]) })); + block_on(pool.maintain(ChainEvent::Finalized { hash: e1, tree_route: Arc::from(vec![]) })); } for (canon_watcher, h) in canon_watchers { @@ -637,7 +637,7 @@ fn prune_and_retract_tx_at_same_time() { block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 0); - let event = ChainEvent::Finalized { hash: header.hash(), tree_route: Arc::new(vec![]) }; + let event = ChainEvent::Finalized { hash: header.hash(), tree_route: Arc::from(vec![]) }; block_on(pool.maintain(event)); header.hash() diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index c5acff24548a5..70d6bcd8b0495 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -15,6 +15,7 @@ lazy_static = "1.4.0" parking_lot = "0.12.0" prometheus = { version = "0.13.0", default-features = false } futures-timer = "3.0.2" +log = "0.4" [features] default = ["metered"] diff --git a/client/utils/src/id_sequence.rs b/client/utils/src/id_sequence.rs new file mode 100644 index 0000000000000..2ccb4fc3f32ee --- /dev/null +++ b/client/utils/src/id_sequence.rs @@ -0,0 +1,54 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Produce opaque sequential IDs. + +/// A Sequence of IDs. +#[derive(Debug, Default)] +// The `Clone` trait is intentionally not defined on this type. +pub struct IDSequence { + next_id: u64, +} + +/// A Sequential ID. +/// +/// Its integer value is intentionally not public: it is supposed to be instantiated from within +/// this module only. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct SeqID(u64); + +impl std::fmt::Display for SeqID { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl IDSequence { + /// Create a new ID-sequence. + pub fn new() -> Self { + Default::default() + } + + /// Obtain another ID from this sequence. + pub fn next_id(&mut self) -> SeqID { + let id = SeqID(self.next_id); + self.next_id += 1; + + id + } +} diff --git a/client/utils/src/lib.rs b/client/utils/src/lib.rs index b3fb8400b12f6..0e47330335c27 100644 --- a/client/utils/src/lib.rs +++ b/client/utils/src/lib.rs @@ -36,7 +36,9 @@ //! | entity | Name of channel passed to `tracing_unbounded` | //! | action | One of `send`/`received`/`dropped` | +pub mod id_sequence; pub mod metrics; pub mod mpsc; pub mod notification; +pub mod pubsub; pub mod status_sinks; diff --git a/client/utils/src/notification.rs b/client/utils/src/notification.rs index 21d01c5f99fef..ff527c343f9f2 100644 --- a/client/utils/src/notification.rs +++ b/client/utils/src/notification.rs @@ -26,15 +26,19 @@ //! //! See [`sc-service::builder::RpcExtensionBuilder`] for more details. -use std::{marker::PhantomData, sync::Arc}; +use futures::stream::{FusedStream, Stream}; +use std::{ + pin::Pin, + task::{Context, Poll}, +}; -use crate::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; +use crate::pubsub::{Hub, Receiver}; -use parking_lot::Mutex; +mod registry; +use registry::Registry; -/// Collection of channel sending endpoints shared with the receiver side -/// so they can register themselves. -type SharedSenders = Arc>>>; +#[cfg(test)] +mod tests; /// Trait used to define the "tracing key" string used to tag /// and identify the mpsc channels. @@ -44,108 +48,75 @@ pub trait TracingKeyStr { const TRACING_KEY: &'static str; } -/// The sending half of the notifications channel(s). +/// The receiving half of the notifications channel. /// -/// Used to send notifications from the BEEFY gadget side. +/// The [`NotificationStream`] entity stores the [`Hub`] so it can be +/// used to add more subscriptions. #[derive(Clone)] -pub struct NotificationSender { - subscribers: SharedSenders, +pub struct NotificationStream { + hub: Hub, + _pd: std::marker::PhantomData, } -impl NotificationSender { - /// The `subscribers` should be shared with a corresponding `NotificationStream`. - fn new(subscribers: SharedSenders) -> Self { - Self { subscribers } - } - - /// Send out a notification to all subscribers that a new payload is available for a - /// block. - pub fn notify( - &self, - payload: impl FnOnce() -> Result, - ) -> Result<(), Error> { - let mut subscribers = self.subscribers.lock(); - - // do an initial prune on closed subscriptions - subscribers.retain(|n| !n.is_closed()); - - if !subscribers.is_empty() { - let payload = payload()?; - subscribers.retain(|n| n.unbounded_send(payload.clone()).is_ok()); - } - - Ok(()) - } +/// The receiving half of the notifications channel(s). +#[derive(Debug)] +pub struct NotificationReceiver { + receiver: Receiver, } -/// The receiving half of the notifications channel. -/// -/// The `NotificationStream` entity stores the `SharedSenders` so it can be -/// used to add more subscriptions. -#[derive(Clone)] -pub struct NotificationStream { - subscribers: SharedSenders, - _trace_key: PhantomData, +/// The sending half of the notifications channel(s). +pub struct NotificationSender { + hub: Hub, } -impl NotificationStream { +impl NotificationStream { /// Creates a new pair of receiver and sender of `Payload` notifications. pub fn channel() -> (NotificationSender, Self) { - let subscribers = Arc::new(Mutex::new(vec![])); - let receiver = NotificationStream::new(subscribers.clone()); - let sender = NotificationSender::new(subscribers); + let hub = Hub::new(TK::TRACING_KEY); + let sender = NotificationSender { hub: hub.clone() }; + let receiver = NotificationStream { hub, _pd: Default::default() }; (sender, receiver) } - /// Create a new receiver of `Payload` notifications. - /// - /// The `subscribers` should be shared with a corresponding `NotificationSender`. - fn new(subscribers: SharedSenders) -> Self { - Self { subscribers, _trace_key: PhantomData } - } - /// Subscribe to a channel through which the generic payload can be received. - pub fn subscribe(&self) -> TracingUnboundedReceiver { - let (sender, receiver) = tracing_unbounded(TK::TRACING_KEY); - self.subscribers.lock().push(sender); - receiver + pub fn subscribe(&self) -> NotificationReceiver { + let receiver = self.hub.subscribe(()); + NotificationReceiver { receiver } } } -#[cfg(test)] -mod tests { - use super::*; - use futures::StreamExt; - - #[derive(Clone)] - pub struct DummyTracingKey; - impl TracingKeyStr for DummyTracingKey { - const TRACING_KEY: &'static str = "test_notification_stream"; +impl NotificationSender { + /// Send out a notification to all subscribers that a new payload is available for a + /// block. + pub fn notify( + &self, + payload: impl FnOnce() -> Result, + ) -> Result<(), Error> + where + Payload: Clone, + { + self.hub.send(payload) } +} - type StringStream = NotificationStream; - - #[test] - fn notification_channel_simple() { - let (sender, stream) = StringStream::channel(); +impl Clone for NotificationSender { + fn clone(&self) -> Self { + Self { hub: self.hub.clone() } + } +} - let test_payload = String::from("test payload"); - let closure_payload = test_payload.clone(); +impl Unpin for NotificationReceiver {} - // Create a future to receive a single notification - // from the stream and verify its payload. - let future = stream.subscribe().take(1).for_each(move |payload| { - let test_payload = closure_payload.clone(); - async move { - assert_eq!(payload, test_payload); - } - }); +impl Stream for NotificationReceiver { + type Item = Payload; - // Send notification. - let r: std::result::Result<(), ()> = sender.notify(|| Ok(test_payload)); - r.unwrap(); + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.get_mut().receiver).poll_next(cx) + } +} - // Run receiver future. - tokio_test::block_on(future); +impl FusedStream for NotificationReceiver { + fn is_terminated(&self) -> bool { + self.receiver.is_terminated() } } diff --git a/client/utils/src/notification/registry.rs b/client/utils/src/notification/registry.rs new file mode 100644 index 0000000000000..ebe41452a567e --- /dev/null +++ b/client/utils/src/notification/registry.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::collections::HashSet; + +use crate::{ + id_sequence::SeqID, + pubsub::{Dispatch, Subscribe, Unsubscribe}, +}; + +/// The shared structure to keep track on subscribers. +#[derive(Debug, Default)] +pub(super) struct Registry { + pub(super) subscribers: HashSet, +} + +impl Subscribe<()> for Registry { + fn subscribe(&mut self, _subs_key: (), subs_id: SeqID) { + self.subscribers.insert(subs_id); + } +} +impl Unsubscribe for Registry { + fn unsubscribe(&mut self, subs_id: SeqID) { + self.subscribers.remove(&subs_id); + } +} + +impl Dispatch for Registry +where + MakePayload: FnOnce() -> Result, + Payload: Clone, +{ + type Item = Payload; + type Ret = Result<(), Error>; + + fn dispatch(&mut self, make_payload: MakePayload, mut dispatch: F) -> Self::Ret + where + F: FnMut(&SeqID, Self::Item), + { + if !self.subscribers.is_empty() { + let payload = make_payload()?; + for subs_id in &self.subscribers { + dispatch(subs_id, payload.clone()); + } + } + Ok(()) + } +} diff --git a/client/utils/src/notification/tests.rs b/client/utils/src/notification/tests.rs new file mode 100644 index 0000000000000..a001fa7e89e95 --- /dev/null +++ b/client/utils/src/notification/tests.rs @@ -0,0 +1,52 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; +use futures::StreamExt; + +#[derive(Clone)] +pub struct DummyTracingKey; +impl TracingKeyStr for DummyTracingKey { + const TRACING_KEY: &'static str = "test_notification_stream"; +} + +type StringStream = NotificationStream; + +#[test] +fn notification_channel_simple() { + let (sender, stream) = StringStream::channel(); + + let test_payload = String::from("test payload"); + let closure_payload = test_payload.clone(); + + // Create a future to receive a single notification + // from the stream and verify its payload. + let future = stream.subscribe().take(1).for_each(move |payload| { + let test_payload = closure_payload.clone(); + async move { + assert_eq!(payload, test_payload); + } + }); + + // Send notification. + let r: std::result::Result<(), ()> = sender.notify(|| Ok(test_payload)); + r.unwrap(); + + // Run receiver future. + tokio_test::block_on(future); +} diff --git a/client/utils/src/pubsub.rs b/client/utils/src/pubsub.rs new file mode 100644 index 0000000000000..c8e51e3494b97 --- /dev/null +++ b/client/utils/src/pubsub.rs @@ -0,0 +1,263 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Provides means to implement a typical Pub/Sub mechanism. +//! +//! This module provides a type [`Hub`] which can be used both to subscribe, +//! and to send the broadcast messages. +//! +//! The [`Hub`] type is parametrized by two other types: +//! - `Message` — the type of a message that shall be delivered to the subscribers; +//! - `Registry` — implementation of the subscription/dispatch logic. +//! +//! A Registry is implemented by defining the following traits: +//! - [`Subscribe`]; +//! - [`Dispatch`]; +//! - [`Unsubscribe`]. +//! +//! As a result of subscription `Hub::subscribe` method returns an instance of +//! [`Receiver`]. That can be used as a [`Stream`] to receive the messages. +//! Upon drop the [`Receiver`] shall unregister itself from the `Hub`. + +use std::{ + collections::HashMap, + pin::Pin, + sync::{Arc, Weak}, + task::{Context, Poll}, +}; + +use futures::stream::{FusedStream, Stream}; +// use parking_lot::Mutex; +use parking_lot::ReentrantMutex; +use std::cell::RefCell; + +use crate::{ + id_sequence::SeqID, + mpsc::{TracingUnboundedReceiver, TracingUnboundedSender}, +}; + +#[cfg(test)] +mod tests; + +/// Unsubscribe: unregisters a previously created subscription. +pub trait Unsubscribe { + /// Remove all registrations of the subscriber with ID `subs_id`. + fn unsubscribe(&mut self, subs_id: SeqID); +} + +/// Subscribe using a key of type `K` +pub trait Subscribe { + /// Register subscriber with the ID `subs_id` as having interest to the key `K`. + fn subscribe(&mut self, subs_key: K, subs_id: SeqID); +} + +/// Dispatch a message of type `M`. +pub trait Dispatch { + /// The type of the that shall be sent through the channel as a result of such dispatch. + type Item; + /// The type returned by the `dispatch`-method. + type Ret; + + /// Dispatch the message of type `M`. + /// + /// The implementation is given an instance of `M` and is supposed to invoke `dispatch` for + /// each matching subscriber, with an argument of type `Self::Item` matching that subscriber. + /// + /// Note that this does not have to be of the same type with the item that will be sent through + /// to the subscribers. The subscribers will receive a message of type `Self::Item`. + fn dispatch(&mut self, message: M, dispatch: F) -> Self::Ret + where + F: FnMut(&SeqID, Self::Item); +} + +/// A subscription hub. +/// +/// Does the subscription and dispatch. +/// The exact subscription and routing behaviour is to be implemented by the Registry (of type `R`). +/// The Hub under the hood uses the channel defined in `crate::mpsc` module. +#[derive(Debug)] +pub struct Hub { + tracing_key: &'static str, + shared: Arc>>>, +} + +/// The receiving side of the subscription. +/// +/// The messages are delivered as items of a [`Stream`]. +/// Upon drop this receiver unsubscribes itself from the [`Hub`]. +#[derive(Debug)] +pub struct Receiver +where + R: Unsubscribe, +{ + rx: TracingUnboundedReceiver, + + shared: Weak>>>, + subs_id: SeqID, +} + +#[derive(Debug)] +struct Shared { + id_sequence: crate::id_sequence::IDSequence, + registry: R, + sinks: HashMap>, +} + +impl Hub +where + R: Unsubscribe, +{ + /// Provide access to the registry (for test purposes). + pub fn map_registry_for_tests(&self, map: MapF) -> Ret + where + MapF: FnOnce(&R) -> Ret, + { + let shared_locked = self.shared.lock(); + let shared_borrowed = shared_locked.borrow(); + map(&shared_borrowed.registry) + } +} + +impl Drop for Receiver +where + R: Unsubscribe, +{ + fn drop(&mut self) { + if let Some(shared) = self.shared.upgrade() { + shared.lock().borrow_mut().unsubscribe(self.subs_id); + } + } +} + +impl Hub { + /// Create a new instance of Hub (with default value for the Registry). + pub fn new(tracing_key: &'static str) -> Self + where + R: Default, + { + Self::new_with_registry(tracing_key, Default::default()) + } + + /// Create a new instance of Hub over the initialized Registry. + pub fn new_with_registry(tracing_key: &'static str, registry: R) -> Self { + let shared = + Shared { registry, sinks: Default::default(), id_sequence: Default::default() }; + let shared = Arc::new(ReentrantMutex::new(RefCell::new(shared))); + Self { tracing_key, shared } + } + + /// Subscribe to this Hub using the `subs_key: K`. + /// + /// A subscription with a key `K` is possible if the Registry implements `Subscribe`. + pub fn subscribe(&self, subs_key: K) -> Receiver + where + R: Subscribe + Unsubscribe, + { + let shared_locked = self.shared.lock(); + let mut shared_borrowed = shared_locked.borrow_mut(); + + let subs_id = shared_borrowed.id_sequence.next_id(); + + // The order (registry.subscribe then sinks.insert) is important here: + // assuming that `Subscribe::subscribe` can panic, it is better to at least + // have the sink disposed. + shared_borrowed.registry.subscribe(subs_key, subs_id); + + let (tx, rx) = crate::mpsc::tracing_unbounded(self.tracing_key); + assert!(shared_borrowed.sinks.insert(subs_id, tx).is_none(), "Used IDSequence to create another ID. Should be unique until u64 is overflowed. Should be unique."); + + Receiver { shared: Arc::downgrade(&self.shared), subs_id, rx } + } + + /// Send the message produced with `Trigger`. + /// + /// This is possible if the registry implements `Dispatch`. + pub fn send(&self, trigger: Trigger) -> >::Ret + where + R: Dispatch, + { + let shared_locked = self.shared.lock(); + let mut shared_borrowed = shared_locked.borrow_mut(); + let (registry, sinks) = shared_borrowed.get_mut(); + + let dispatch_result = registry.dispatch(trigger, |subs_id, item| { + if let Some(tx) = sinks.get_mut(&subs_id) { + if let Err(send_err) = tx.unbounded_send(item) { + log::warn!("Sink with SubsID = {} failed to perform unbounded_send: {} ({} as Dispatch<{}, Item = {}>::dispatch(...))", subs_id, send_err, std::any::type_name::(), + std::any::type_name::(), + std::any::type_name::()); + } + } else { + log::warn!( + "No Sink for SubsID = {} ({} as Dispatch<{}, Item = {}>::dispatch(...))", + subs_id, + std::any::type_name::(), + std::any::type_name::(), + std::any::type_name::(), + ); + } + }); + + dispatch_result + } +} + +impl Shared { + fn get_mut(&mut self) -> (&mut R, &mut HashMap>) { + (&mut self.registry, &mut self.sinks) + } + + fn unsubscribe(&mut self, subs_id: SeqID) + where + R: Unsubscribe, + { + // The order (sinks.remove then registry.unsubscribe) is important here: + // assuming that `Unsubscribe::unsubscribe` can panic, it is better to at least + // have the sink disposed. + self.sinks.remove(&subs_id); + self.registry.unsubscribe(subs_id); + } +} + +impl Clone for Hub { + fn clone(&self) -> Self { + Self { tracing_key: self.tracing_key, shared: self.shared.clone() } + } +} + +impl Unpin for Receiver where R: Unsubscribe {} + +impl Stream for Receiver +where + R: Unsubscribe, +{ + type Item = M; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.get_mut().rx).poll_next(cx) + } +} + +impl FusedStream for Receiver +where + R: Unsubscribe, +{ + fn is_terminated(&self) -> bool { + self.rx.is_terminated() + } +} diff --git a/client/utils/src/pubsub/tests.rs b/client/utils/src/pubsub/tests.rs new file mode 100644 index 0000000000000..12945c0d886b8 --- /dev/null +++ b/client/utils/src/pubsub/tests.rs @@ -0,0 +1,123 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use futures::StreamExt; +use tokio_test::block_on; + +use super::*; + +mod normal_operation; +mod panicking_registry; + +const TK: &str = "a_tracing_key"; + +type Message = u64; +type TestHub = Hub; +type TestReceiver = Receiver; + +#[derive(Default)] +struct Registry { + subscribers: HashMap, +} + +struct SubsKey { + _receiver: Option, + panic: SubsKeyPanic, +} + +impl SubsKey { + fn new() -> Self { + Self { _receiver: None, panic: SubsKeyPanic::None } + } + fn with_receiver(self, receiver: TestReceiver) -> Self { + Self { _receiver: Some(receiver), ..self } + } + fn with_panic(self, panic: SubsKeyPanic) -> Self { + Self { panic, ..self } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum SubsKeyPanic { + None, + + OnSubscribePanicBefore, + OnSubscribePanicAfter, + + OnUnsubscribePanicBefore, + OnUnsubscribePanicAfter, + + OnDispatchPanicBefore, + OnDispatchPanicAfter, +} + +impl Hub { + fn subs_count(&self) -> usize { + self.map_registry_for_tests(|r| r.subscribers.len()) + } + fn sink_count(&self) -> usize { + self.shared.lock().borrow().sinks.len() + } +} + +impl Subscribe for Registry { + fn subscribe(&mut self, subs_key: SubsKey, subs_id: SeqID) { + let sk_panic = subs_key.panic; + + if sk_panic == SubsKeyPanic::OnSubscribePanicBefore { + panic!("on-subscribe-panic-before") + } + self.subscribers.insert(subs_id, subs_key); + if sk_panic == SubsKeyPanic::OnSubscribePanicAfter { + panic!("on-subscribe-panic-after") + } + } +} +impl Unsubscribe for Registry { + fn unsubscribe(&mut self, subs_id: SeqID) { + let sk_panic = + self.subscribers.get(&subs_id).map(|sk| sk.panic).unwrap_or(SubsKeyPanic::None); + + if sk_panic == SubsKeyPanic::OnUnsubscribePanicBefore { + panic!("on-unsubscribe-panic-before") + } + self.subscribers.remove(&subs_id); + if sk_panic == SubsKeyPanic::OnUnsubscribePanicAfter { + panic!("on-unsubscribe-panic-after") + } + } +} +impl Dispatch for Registry { + type Item = Message; + type Ret = (); + + fn dispatch(&mut self, message: Message, mut dispatch: F) -> Self::Ret + where + F: FnMut(&SeqID, Self::Item), + { + self.subscribers.iter().for_each(|(id, subs_key)| { + if subs_key.panic == SubsKeyPanic::OnDispatchPanicBefore { + panic!("on-dispatch-panic-before") + } + dispatch(id, message); + if subs_key.panic == SubsKeyPanic::OnDispatchPanicAfter { + panic!("on-dispatch-panic-after") + } + }); + } +} diff --git a/client/utils/src/pubsub/tests/normal_operation.rs b/client/utils/src/pubsub/tests/normal_operation.rs new file mode 100644 index 0000000000000..a13c718d74a8f --- /dev/null +++ b/client/utils/src/pubsub/tests/normal_operation.rs @@ -0,0 +1,88 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; + +#[test] +fn positive_rx_receives_relevant_messages_and_terminates_upon_hub_drop() { + block_on(async { + let hub = TestHub::new(TK); + assert_eq!(hub.subs_count(), 0); + + // No subscribers yet. That message is not supposed to get to anyone. + hub.send(0); + + let mut rx_01 = hub.subscribe(SubsKey::new()); + assert_eq!(hub.subs_count(), 1); + + // That message is sent after subscription. Should be delivered into rx_01. + hub.send(1); + assert_eq!(Some(1), rx_01.next().await); + + // Hub is disposed. The rx_01 should be over after that. + std::mem::drop(hub); + + assert!(!rx_01.is_terminated()); + assert_eq!(None, rx_01.next().await); + assert!(rx_01.is_terminated()); + }); +} + +#[test] +fn positive_subs_count_is_correct_upon_drop_of_rxs() { + block_on(async { + let hub = TestHub::new(TK); + assert_eq!(hub.subs_count(), 0); + + let rx_01 = hub.subscribe(SubsKey::new()); + assert_eq!(hub.subs_count(), 1); + let rx_02 = hub.subscribe(SubsKey::new()); + assert_eq!(hub.subs_count(), 2); + + std::mem::drop(rx_01); + assert_eq!(hub.subs_count(), 1); + std::mem::drop(rx_02); + assert_eq!(hub.subs_count(), 0); + }); +} + +#[test] +fn positive_subs_count_is_correct_upon_drop_of_rxs_on_cloned_hubs() { + block_on(async { + let hub_01 = TestHub::new(TK); + let hub_02 = hub_01.clone(); + assert_eq!(hub_01.subs_count(), 0); + assert_eq!(hub_02.subs_count(), 0); + + let rx_01 = hub_02.subscribe(SubsKey::new()); + assert_eq!(hub_01.subs_count(), 1); + assert_eq!(hub_02.subs_count(), 1); + + let rx_02 = hub_02.subscribe(SubsKey::new()); + assert_eq!(hub_01.subs_count(), 2); + assert_eq!(hub_02.subs_count(), 2); + + std::mem::drop(rx_01); + assert_eq!(hub_01.subs_count(), 1); + assert_eq!(hub_02.subs_count(), 1); + + std::mem::drop(rx_02); + assert_eq!(hub_01.subs_count(), 0); + assert_eq!(hub_02.subs_count(), 0); + }); +} diff --git a/client/utils/src/pubsub/tests/panicking_registry.rs b/client/utils/src/pubsub/tests/panicking_registry.rs new file mode 100644 index 0000000000000..26ce63bd51b01 --- /dev/null +++ b/client/utils/src/pubsub/tests/panicking_registry.rs @@ -0,0 +1,248 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; + +use std::panic::{catch_unwind, AssertUnwindSafe}; + +fn assert_hub_props(hub: &TestHub, sinks_count: usize, subs_count: usize) { + assert_eq!(hub.sink_count(), sinks_count); + assert_eq!(hub.subs_count(), subs_count); +} + +#[test] +fn t01() { + let hub = TestHub::new(TK); + assert_hub_props(&hub, 0, 0); + + let rx_01 = hub.subscribe(SubsKey::new()); + assert_hub_props(&hub, 1, 1); + + std::mem::drop(rx_01); + assert_hub_props(&hub, 0, 0); +} + +#[test] +fn t02() { + block_on(async { + // Create a Hub + let hub = TestHub::new(TK); + assert_hub_props(&hub, 0, 0); + + // Subscribe rx-01 + let rx_01 = hub.subscribe(SubsKey::new()); + assert_hub_props(&hub, 1, 1); + + // Subscribe rx-02 so that its unsubscription will lead to an attempt to drop rx-01 in the + // middle of unsubscription of rx-02 + let rx_02 = hub.subscribe(SubsKey::new().with_receiver(rx_01)); + assert_hub_props(&hub, 2, 2); + + // Subscribe rx-03 in order to see that it will receive messages after the unclean + // unsubscription + let mut rx_03 = hub.subscribe(SubsKey::new()); + assert_hub_props(&hub, 3, 3); + + // drop rx-02 leads to an attempt to unsubscribe rx-01 + assert!(catch_unwind(AssertUnwindSafe(move || { + std::mem::drop(rx_02); + })) + .is_err()); + + // One of the rxes could not unsubscribe + assert_hub_props(&hub, 2, 2); + + // Subscribe rx-04 in order to see that it will receive messages after the unclean + // unsubscription + let mut rx_04 = hub.subscribe(SubsKey::new()); + assert_hub_props(&hub, 3, 3); + + hub.send(2); + + // The messages are still received + assert_eq!(rx_03.next().await, Some(2)); + assert_eq!(rx_04.next().await, Some(2)); + + // Perform a clean unsubscription + std::mem::drop(rx_04); + + hub.send(3); + + // The messages are still received + assert_eq!(rx_03.next().await, Some(3)); + + std::mem::drop(rx_03); + + hub.send(4); + + // The stuck subscription is still there + assert_hub_props(&hub, 1, 1); + }); +} + +async fn add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(hub: &TestHub) { + let rx_01 = hub.subscribe(SubsKey::new()); + let rx_02 = hub.subscribe(SubsKey::new()); + + hub.send(1); + hub.send(2); + hub.send(3); + + assert_eq!(rx_01.take(3).collect::>().await, vec![1, 2, 3]); + + hub.send(4); + hub.send(5); + hub.send(6); + + assert_eq!(rx_02.take(6).collect::>().await, vec![1, 2, 3, 4, 5, 6]); +} + +#[test] +fn t03() { + block_on(async { + // Create a Hub + let hub = TestHub::new(TK); + assert_hub_props(&hub, 0, 0); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 0); + + assert!(catch_unwind(AssertUnwindSafe( + || hub.subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnSubscribePanicBefore)) + )) + .is_err()); + + assert_hub_props(&hub, 0, 0); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 0); + }); +} + +#[test] +fn t04() { + block_on(async { + let hub = TestHub::new(TK); + + assert_hub_props(&hub, 0, 0); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 0); + + assert!(catch_unwind(AssertUnwindSafe( + || hub.subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnSubscribePanicAfter)) + )) + .is_err()); + + // the registry has panicked after it has added a subs-id into its internal storage — the + // sinks do not leak, although the subscriptions storage contains some garbage + assert_hub_props(&hub, 0, 1); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 1); + }) +} + +#[test] +fn t05() { + block_on(async { + let hub = TestHub::new(TK); + + assert_hub_props(&hub, 0, 0); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 0); + + let rx_01 = + hub.subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnUnsubscribePanicBefore)); + + assert_hub_props(&hub, 1, 1); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 1, 1); + + assert!(catch_unwind(AssertUnwindSafe(move || std::mem::drop(rx_01))).is_err()); + + // the registry has panicked on-unsubscribe before it removed the subs-id from its internal + // storage — the sinks do not leak, although the subscriptions storage contains some garbage + assert_hub_props(&hub, 0, 1); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 1); + }) +} + +#[test] +fn t06() { + block_on(async { + let hub = TestHub::new(TK); + + assert_hub_props(&hub, 0, 0); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 0); + + let rx_01 = hub.subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnUnsubscribePanicAfter)); + + assert_hub_props(&hub, 1, 1); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 1, 1); + + assert!(catch_unwind(AssertUnwindSafe(move || std::mem::drop(rx_01))).is_err()); + + // the registry has panicked on-unsubscribe after it removed the subs-id from its internal + // storage — the sinks do not leak, the subscriptions storage does not contain any garbage + assert_hub_props(&hub, 0, 0); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 0); + }) +} + +#[test] +fn t07() { + block_on(async { + let hub = TestHub::new(TK); + + assert_hub_props(&hub, 0, 0); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 0); + + let rx_01 = hub.subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnDispatchPanicBefore)); + assert_hub_props(&hub, 1, 1); + assert!(catch_unwind(AssertUnwindSafe(|| hub.send(1))).is_err()); + assert_hub_props(&hub, 1, 1); + + std::mem::drop(rx_01); + assert_hub_props(&hub, 0, 0); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 0); + }) +} + +#[test] +fn t08() { + block_on(async { + let hub = TestHub::new(TK); + + assert_hub_props(&hub, 0, 0); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 0); + + let rx_01 = hub.subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnDispatchPanicAfter)); + assert_hub_props(&hub, 1, 1); + assert!(catch_unwind(AssertUnwindSafe(|| hub.send(1))).is_err()); + assert_hub_props(&hub, 1, 1); + + std::mem::drop(rx_01); + assert_hub_props(&hub, 0, 0); + add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; + assert_hub_props(&hub, 0, 0); + }) +} From 66ff3a566e6ee7d85f30fc11d45047bd41854b9e Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 28 Feb 2022 21:54:48 +0000 Subject: [PATCH 0555/1472] Bring back MaxNominations as a metadata constant (#10947) --- frame/staking/src/pallet/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 2be75752f101d..f53e6b50d7a39 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -96,6 +96,7 @@ pub mod pallet { >; /// Maximum number of nominations per nominator. + #[pallet::constant] type MaxNominations: Get; /// Tokens have been minted and are unused for validator-reward. From f90dfc63a41f27ed36ba482582d3a913a61217ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 10:22:10 +0100 Subject: [PATCH 0556/1472] Bump futures from 0.3.16 to 0.3.19 (#10930) Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.16 to 0.3.19. - [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.16...0.3.19) --- 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 | 194 +++++++++--------- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 4 +- bin/node/executor/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- client/api/Cargo.toml | 2 +- client/authority-discovery/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/informant/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- client/utils/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/consensus/common/Cargo.toml | 4 +- primitives/core/Cargo.toml | 2 +- primitives/inherents/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- test-utils/runtime/client/Cargo.toml | 2 +- .../runtime/transaction-pool/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- 46 files changed, 144 insertions(+), 144 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da474bdcfb210..e6ae5a1fea5fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -483,7 +483,7 @@ version = "4.0.0-dev" dependencies = [ "beefy-primitives", "fnv", - "futures 0.3.16", + "futures 0.3.19", "log 0.4.14", "parity-scale-codec", "parking_lot 0.12.0", @@ -514,7 +514,7 @@ version = "4.0.0-dev" dependencies = [ "beefy-gadget", "beefy-primitives", - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -1301,7 +1301,7 @@ dependencies = [ "clap 2.34.0", "criterion-plot", "csv", - "futures 0.3.16", + "futures 0.3.19", "itertools", "lazy_static", "num-traits", @@ -1955,7 +1955,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", ] [[package]] @@ -2015,7 +2015,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9def033d8505edf199f6a5d07aa7e6d2d6185b164293b77f0efd108f4f3e11d" dependencies = [ "either", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "log 0.4.14", "num-traits", @@ -2429,9 +2429,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b" +checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" dependencies = [ "futures-channel", "futures-core", @@ -2460,9 +2460,9 @@ checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" [[package]] name = "futures-executor" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c" +checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" dependencies = [ "futures-core", "futures-task", @@ -3054,7 +3054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6d52908d4ea4ab2bc22474ba149bf1011c8e2c3ebc1ff593ae28ac44f494b6" dependencies = [ "async-io", - "futures 0.3.16", + "futures 0.3.19", "futures-lite", "if-addrs", "ipnet", @@ -3209,7 +3209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" dependencies = [ "derive_more", - "futures 0.3.16", + "futures 0.3.19", "hyper 0.14.16", "hyper-tls", "jsonrpc-core", @@ -3228,7 +3228,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "futures-executor", "futures-util", "log 0.4.14", @@ -3243,7 +3243,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-client-transports", ] @@ -3265,7 +3265,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "hyper 0.14.16", "jsonrpc-core", "jsonrpc-server-utils", @@ -3281,7 +3281,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "382bb0206323ca7cda3dcd7e245cea86d37d02457a02a975e3378fb149a48845" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-server-utils", "log 0.4.14", @@ -3296,7 +3296,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-core", "lazy_static", "log 0.4.14", @@ -3312,7 +3312,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" dependencies = [ "bytes 1.1.0", - "futures 0.3.16", + "futures 0.3.19", "globset", "jsonrpc-core", "lazy_static", @@ -3329,7 +3329,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f892c7d766369475ab7b0669f417906302d7c0fb521285c0a0c92e52e7c8e946" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-server-utils", "log 0.4.14", @@ -3367,7 +3367,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3303cdf246e6ab76e2866fb3d9acb6c76a068b1b28bd923a1b7a8122257ad7b5" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "http", "jsonrpsee-core", "jsonrpsee-types 0.8.0", @@ -3470,7 +3470,7 @@ dependencies = [ "arrayvec 0.7.1", "async-trait", "fnv", - "futures 0.3.16", + "futures 0.3.19", "http", "jsonrpsee-types 0.4.1", "log 0.4.14", @@ -3669,7 +3669,7 @@ checksum = "3bec54343492ba5940a6c555e512c6721139835d28c59bc22febece72dfd0d9d" dependencies = [ "atomic", "bytes 1.1.0", - "futures 0.3.16", + "futures 0.3.19", "lazy_static", "libp2p-core", "libp2p-deflate", @@ -3713,7 +3713,7 @@ dependencies = [ "ed25519-dalek", "either", "fnv", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "lazy_static", "libsecp256k1", @@ -3743,7 +3743,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51a800adb195f33de63f4b17b63fe64cfc23bf2c6a0d3d0d5321328664e65197" dependencies = [ "flate2", - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", ] @@ -3754,7 +3754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb8f89d15cb6e3c5bc22afff7513b11bab7856f2872d3cfba86f7f63a06bc498" dependencies = [ "async-std-resolver", - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "log 0.4.14", "smallvec 1.7.0", @@ -3769,7 +3769,7 @@ checksum = "aab3d7210901ea51b7bae2b581aa34521797af8c4ec738c980bda4a06434067f" dependencies = [ "cuckoofilter", "fnv", - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3790,7 +3790,7 @@ dependencies = [ "byteorder", "bytes 1.1.0", "fnv", - "futures 0.3.16", + "futures 0.3.19", "hex_fmt", "libp2p-core", "libp2p-swarm", @@ -3811,7 +3811,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cca1275574183f288ff8b72d535d5ffa5ea9292ef7829af8b47dcb197c7b0dcd" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3833,7 +3833,7 @@ dependencies = [ "bytes 1.1.0", "either", "fnv", - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3857,7 +3857,7 @@ dependencies = [ "async-io", "data-encoding", "dns-parser", - "futures 0.3.16", + "futures 0.3.19", "if-watch", "lazy_static", "libp2p-core", @@ -3891,7 +3891,7 @@ checksum = "7f2cd64ef597f40e14bfce0497f50ecb63dd6d201c61796daeb4227078834fbf" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "log 0.4.14", "nohash-hasher", @@ -3909,7 +3909,7 @@ checksum = "a8772c7a99088221bb7ca9c5c0574bf55046a7ab4c319f3619b275f28c8fb87a" dependencies = [ "bytes 1.1.0", "curve25519-dalek 3.0.2", - "futures 0.3.16", + "futures 0.3.19", "lazy_static", "libp2p-core", "log 0.4.14", @@ -3929,7 +3929,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80ef7b0ec5cf06530d9eb6cf59ae49d46a2c45663bde31c25a12f682664adbcf" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3946,7 +3946,7 @@ checksum = "5fba1a6ff33e4a274c89a3b1d78b9f34f32af13265cc5c46c16938262d4e945a" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "log 0.4.14", "prost", @@ -3961,7 +3961,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "log 0.4.14", "pin-project 1.0.10", "rand 0.7.3", @@ -3977,7 +3977,7 @@ checksum = "2852b61c90fa8ce3c8fcc2aba76e6cefc20d648f9df29157d6b3a916278ef3e3" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "libp2p-core", "libp2p-swarm", @@ -4000,7 +4000,7 @@ checksum = "14a6d2b9e7677eff61dc3d2854876aaf3976d84a01ef6664b610c77a0c9407c5" dependencies = [ "asynchronous-codec 0.6.0", "bimap", - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -4022,7 +4022,7 @@ checksum = "a877a4ced6d46bf84677e1974e8cf61fb434af73b2e96fb48d6cb6223a4634d8" dependencies = [ "async-trait", "bytes 1.1.0", - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -4040,7 +4040,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f5184a508f223bc100a12665517773fb8730e9f36fc09eefb670bf01b107ae9" dependencies = [ "either", - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "log 0.4.14", "rand 0.7.3", @@ -4066,7 +4066,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7399c5b6361ef525d41c11fcf51635724f832baf5819b30d3d873eabb4fbae4b" dependencies = [ "async-io", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "if-watch", "ipnet", @@ -4083,7 +4083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8b7563e46218165dfd60f64b96f7ce84590d75f53ecbdc74a7dd01450dc5973" dependencies = [ "async-std", - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "log 0.4.14", ] @@ -4094,7 +4094,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1008a302b73c5020251f9708c653f5ed08368e530e247cc9cd2f109ff30042cf" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "js-sys", "libp2p-core", "parity-send-wrapper", @@ -4109,7 +4109,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e12df82d1ed64969371a9e65ea92b91064658604cc2576c2757f18ead9a1cf" dependencies = [ "either", - "futures 0.3.16", + "futures 0.3.19", "futures-rustls", "libp2p-core", "log 0.4.14", @@ -4126,7 +4126,7 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e7362abb8867d7187e7e93df17f460d554c997fc5c8ac57dc1259057f6889af" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "libp2p-core", "parking_lot 0.11.2", "thiserror", @@ -4647,7 +4647,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d91ec0a2440aaff5f78ec35631a7027d50386c6163aa975f7caa0d5da4b6ff8" dependencies = [ "bytes 1.1.0", - "futures 0.3.16", + "futures 0.3.19", "log 0.4.14", "pin-project 1.0.10", "smallvec 1.7.0", @@ -4751,7 +4751,7 @@ dependencies = [ "clap 3.0.7", "derive_more", "fs_extra", - "futures 0.3.16", + "futures 0.3.19", "hash-db", "hex", "kvdb", @@ -4793,7 +4793,7 @@ dependencies = [ "frame-benchmarking-cli", "frame-system", "frame-system-rpc-runtime-api", - "futures 0.3.16", + "futures 0.3.19", "hex-literal", "jsonrpsee-ws-client 0.4.1", "log 0.4.14", @@ -4872,7 +4872,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "futures 0.3.16", + "futures 0.3.19", "node-primitives", "node-runtime", "node-testing", @@ -5131,7 +5131,7 @@ version = "3.0.0-dev" dependencies = [ "frame-system", "fs_extra", - "futures 0.3.16", + "futures 0.3.19", "log 0.4.14", "node-executor", "node-primitives", @@ -6672,7 +6672,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "libc", "log 0.4.14", "rand 0.7.3", @@ -7881,7 +7881,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "pin-project 0.4.27", "static_assertions", ] @@ -7940,7 +7940,7 @@ name = "sc-authority-discovery" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "ip_network", "libp2p", @@ -7968,7 +7968,7 @@ dependencies = [ name = "sc-basic-authorship" version = "0.10.0-dev" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "log 0.4.14", "parity-scale-codec", @@ -8038,7 +8038,7 @@ dependencies = [ "chrono", "clap 3.0.7", "fdlimit", - "futures 0.3.16", + "futures 0.3.19", "hex", "libp2p", "log 0.4.14", @@ -8074,7 +8074,7 @@ name = "sc-client-api" version = "4.0.0-dev" dependencies = [ "fnv", - "futures 0.3.16", + "futures 0.3.19", "hash-db", "log 0.4.14", "parity-scale-codec", @@ -8132,7 +8132,7 @@ name = "sc-consensus" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "libp2p", "log 0.4.14", @@ -8156,7 +8156,7 @@ name = "sc-consensus-aura" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.16", + "futures 0.3.19", "getrandom 0.2.3", "log 0.4.14", "parity-scale-codec", @@ -8195,7 +8195,7 @@ version = "0.10.0-dev" dependencies = [ "async-trait", "fork-tree", - "futures 0.3.16", + "futures 0.3.19", "log 0.4.14", "merlin", "num-bigint", @@ -8243,7 +8243,7 @@ dependencies = [ name = "sc-consensus-babe-rpc" version = "0.10.0-dev" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -8286,7 +8286,7 @@ version = "0.10.0-dev" dependencies = [ "assert_matches", "async-trait", - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -8324,7 +8324,7 @@ name = "sc-consensus-pow" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "log 0.4.14", "parity-scale-codec", @@ -8348,7 +8348,7 @@ name = "sc-consensus-slots" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "log 0.4.14", "parity-scale-codec", @@ -8478,7 +8478,7 @@ dependencies = [ "dyn-clone", "finality-grandpa", "fork-tree", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "log 0.4.14", "parity-scale-codec", @@ -8518,7 +8518,7 @@ name = "sc-finality-grandpa-rpc" version = "0.10.0-dev" dependencies = [ "finality-grandpa", - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -8545,7 +8545,7 @@ name = "sc-informant" version = "0.10.0-dev" dependencies = [ "ansi_term", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "log 0.4.14", "parity-util-mem", @@ -8585,7 +8585,7 @@ dependencies = [ "either", "fnv", "fork-tree", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "hex", "ip_network", @@ -8633,7 +8633,7 @@ version = "0.10.0-dev" dependencies = [ "ahash", "async-std", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "libp2p", "log 0.4.14", @@ -8652,7 +8652,7 @@ version = "0.8.0" dependencies = [ "async-std", "async-trait", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "libp2p", "log 0.4.14", @@ -8679,7 +8679,7 @@ version = "4.0.0-dev" dependencies = [ "bytes 1.1.0", "fnv", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "hex", "hyper 0.14.16", @@ -8713,7 +8713,7 @@ dependencies = [ name = "sc-peerset" version = "4.0.0-dev" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "libp2p", "log 0.4.14", "rand 0.7.3", @@ -8735,7 +8735,7 @@ name = "sc-rpc" version = "4.0.0-dev" dependencies = [ "assert_matches", - "futures 0.3.16", + "futures 0.3.19", "hash-db", "jsonrpc-core", "jsonrpc-pubsub", @@ -8771,7 +8771,7 @@ dependencies = [ name = "sc-rpc-api" version = "0.10.0-dev" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -8795,7 +8795,7 @@ dependencies = [ name = "sc-rpc-server" version = "4.0.0-dev" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-http-server", "jsonrpc-ipc-server", @@ -8829,7 +8829,7 @@ dependencies = [ "async-trait", "directories", "exit-future", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "hash-db", "jsonrpc-core", @@ -8892,7 +8892,7 @@ name = "sc-service-test" version = "2.0.0" dependencies = [ "fdlimit", - "futures 0.3.16", + "futures 0.3.19", "hex", "hex-literal", "log 0.4.14", @@ -8961,7 +8961,7 @@ name = "sc-telemetry" version = "4.0.0-dev" dependencies = [ "chrono", - "futures 0.3.16", + "futures 0.3.19", "libp2p", "log 0.4.14", "parking_lot 0.12.0", @@ -9020,7 +9020,7 @@ version = "4.0.0-dev" dependencies = [ "assert_matches", "criterion", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "hex", "linked-hash-map", @@ -9052,7 +9052,7 @@ dependencies = [ name = "sc-transaction-pool-api" version = "4.0.0-dev" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "log 0.4.14", "serde", "sp-blockchain", @@ -9064,7 +9064,7 @@ dependencies = [ name = "sc-utils" version = "4.0.0-dev" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "lazy_static", "log 0.4.14", @@ -9541,7 +9541,7 @@ checksum = "b5c71ed3d54db0a699f4948e1bb3e45b450fa31fe602621dee6680361d569c88" dependencies = [ "base64 0.12.3", "bytes 0.5.6", - "futures 0.3.16", + "futures 0.3.19", "httparse", "log 0.4.14", "rand 0.7.3", @@ -9557,7 +9557,7 @@ dependencies = [ "base64 0.13.0", "bytes 1.1.0", "flate2", - "futures 0.3.16", + "futures 0.3.19", "httparse", "log 0.4.14", "rand 0.8.4", @@ -9597,7 +9597,7 @@ name = "sp-api-test" version = "2.0.1" dependencies = [ "criterion", - "futures 0.3.16", + "futures 0.3.19", "log 0.4.14", "parity-scale-codec", "rustversion", @@ -9702,7 +9702,7 @@ dependencies = [ name = "sp-blockchain" version = "4.0.0-dev" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "log 0.4.14", "lru 0.7.0", "parity-scale-codec", @@ -9720,7 +9720,7 @@ name = "sp-consensus" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.16", + "futures 0.3.19", "futures-timer", "log 0.4.14", "parity-scale-codec", @@ -9819,7 +9819,7 @@ dependencies = [ "criterion", "dyn-clonable", "ed25519-dalek", - "futures 0.3.16", + "futures 0.3.19", "hash-db", "hash256-std-hasher", "hex", @@ -9930,7 +9930,7 @@ name = "sp-inherents" version = "4.0.0-dev" dependencies = [ "async-trait", - "futures 0.3.16", + "futures 0.3.19", "impl-trait-for-tuples", "parity-scale-codec", "sp-core", @@ -9943,7 +9943,7 @@ dependencies = [ name = "sp-io" version = "5.0.0" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "hash-db", "libsecp256k1", "log 0.4.14", @@ -9978,7 +9978,7 @@ name = "sp-keystore" version = "0.11.0" dependencies = [ "async-trait", - "futures 0.3.16", + "futures 0.3.19", "merlin", "parity-scale-codec", "parking_lot 0.12.0", @@ -10517,7 +10517,7 @@ version = "3.0.0" dependencies = [ "frame-support", "frame-system", - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-client-transports", "parity-scale-codec", "sc-rpc-api", @@ -10532,7 +10532,7 @@ name = "substrate-frame-rpc-system" version = "4.0.0-dev" dependencies = [ "frame-system-rpc-runtime-api", - "futures 0.3.16", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -10568,7 +10568,7 @@ name = "substrate-test-client" version = "2.0.1" dependencies = [ "async-trait", - "futures 0.3.16", + "futures 0.3.19", "hex", "parity-scale-codec", "sc-client-api", @@ -10596,7 +10596,7 @@ dependencies = [ "frame-support", "frame-system", "frame-system-rpc-runtime-api", - "futures 0.3.16", + "futures 0.3.19", "log 0.4.14", "memory-db", "pallet-babe", @@ -10638,7 +10638,7 @@ dependencies = [ name = "substrate-test-runtime-client" version = "2.0.0" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "parity-scale-codec", "sc-block-builder", "sc-client-api", @@ -10656,7 +10656,7 @@ dependencies = [ name = "substrate-test-runtime-transaction-pool" version = "2.0.0" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "parity-scale-codec", "parking_lot 0.12.0", "sc-transaction-pool", @@ -10671,7 +10671,7 @@ dependencies = [ name = "substrate-test-utils" version = "4.0.0-dev" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "sc-service", "substrate-test-utils-derive", "tokio", @@ -11358,7 +11358,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "digest 0.10.2", "rand 0.8.4", "static_assertions", @@ -11696,7 +11696,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "js-sys", "parking_lot 0.11.2", "pin-utils", @@ -12352,7 +12352,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7d9028f208dd5e63c614be69f115c1b53cacc1111437d4c765185856666c107" dependencies = [ - "futures 0.3.16", + "futures 0.3.19", "log 0.4.14", "nohash-hasher", "parking_lot 0.11.2", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index b14e44371d2b9..c770ca01ecf0b 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -39,4 +39,4 @@ parity-util-mem = { version = "0.11.0", default-features = false, features = ["p parity-db = { version = "0.3" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } -futures = { version = "0.3.4", features = ["thread-pool"] } +futures = { version = "0.3.19", features = ["thread-pool"] } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 4225d09d594a7..57bbbdddcb2ec 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -37,7 +37,7 @@ crate-type = ["cdylib", "rlib"] clap = { version = "3.0", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } -futures = "0.3.16" +futures = "0.3.19" hex-literal = "0.3.4" log = "0.4.8" rand = "0.8" @@ -116,7 +116,7 @@ sc-service-test = { version = "2.0.0", path = "../../../client/service/test" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -futures = "0.3.16" +futures = "0.3.19" tempfile = "3.1.0" assert_cmd = "2.0.2" nix = "0.23" diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 16f232d73d3f0..6bb762319b27b 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -40,7 +40,7 @@ sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sp-externalities = { version = "0.11.0", path = "../../../primitives/externalities" } sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } wat = "1.0" -futures = "0.3.9" +futures = "0.3.19" [features] wasmtime = ["sc-executor/wasmtime"] diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index fc9209ce2b638..3c0be4e19c9e0 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -48,4 +48,4 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" log = "0.4.8" tempfile = "3.1.0" fs_extra = "1" -futures = "0.3.1" +futures = "0.3.19" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index 68ab9aed31fe5..b82309ef6faf1 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -21,7 +21,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/comm sc-executor = { version = "0.10.0-dev", path = "../executor" } sp-externalities = { version = "0.11.0", path = "../../primitives/externalities" } fnv = "1.0.6" -futures = "0.3.1" +futures = "0.3.19" hash-db = { version = "0.15.2", default-features = false } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } log = "0.4.8" diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 04dde95837d2a..197b8cfd1fbb7 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -20,7 +20,7 @@ prost-build = "0.9" async-trait = "0.1" codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0" } thiserror = "1.0" -futures = "0.3.9" +futures = "0.3.19" futures-timer = "3.0.1" ip_network = "0.4.1" libp2p = { version = "0.40.0", default-features = false, features = ["kad"] } diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index bbc66cf09f8bb..5791b2b4010fc 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.9" +futures = "0.3.19" futures-timer = "3.0.1" log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 053aef500b462..19e1e20c7735b 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/paritytech/substrate" description = "RPC for the BEEFY Client gadget for substrate" [dependencies] -futures = "0.3.16" +futures = "0.3.19" log = "0.4" parking_lot = "0.12.0" thiserror = "1.0" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 708e6317d10ce..47ef9619661c8 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] chrono = "0.4.10" clap = { version = "3.0", features = ["derive"] } fdlimit = "0.2.1" -futures = "0.3.9" +futures = "0.3.19" hex = "0.4.2" libp2p = "0.40.0" log = "0.4.11" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 9cb241b6c974d..b82a71587048a 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -23,7 +23,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } thiserror = "1.0" -futures = "0.3.9" +futures = "0.3.19" sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } log = "0.4.8" sp-core = { version = "5.0.0", path = "../../../primitives/core" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 4a9f1f00b75ad..edcf8759f6a7a 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -43,7 +43,7 @@ sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } -futures = "0.3.9" +futures = "0.3.19" parking_lot = "0.12.0" log = "0.4.8" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 8ceada5fe1f1d..5e9f98d628c71 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -23,7 +23,7 @@ serde = { version = "1.0.136", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sp-runtime = { version = "5.0.0", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } -futures = "0.3.16" +futures = "0.3.19" thiserror = "1.0" sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 7add4bb873309..7677e0569e561 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] thiserror = "1.0.30" libp2p = { version = "0.40.0", default-features = false } log = "0.4.8" -futures = { version = "0.3.1", features = ["thread-pool"] } +futures = { version = "0.3.19", features = ["thread-pool"] } futures-timer = "3.0.1" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 83828962f670c..6b9404ce34c93 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] thiserror = "1.0" -futures = "0.3.9" +futures = "0.3.19" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 7e3d30e8deba2..cb21a45ebdb04 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -25,7 +25,7 @@ sp-consensus-pow = { version = "0.10.0-dev", path = "../../../primitives/consens sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } log = "0.4.8" -futures = "0.3.16" +futures = "0.3.19" futures-timer = "3.0.1" parking_lot = "0.12.0" thiserror = "1.0" diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 0127010a1714d..4f4cf4d58bc38 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -27,7 +27,7 @@ sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -futures = "0.3.9" +futures = "0.3.19" futures-timer = "3.0.1" log = "0.4.11" thiserror = "1.0.30" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 2e2ad8738f35f..5927a9bef4e62 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] thiserror = "1.0" dyn-clone = "1.0" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } -futures = "0.3.9" +futures = "0.3.19" futures-timer = "3.0.1" log = "0.4.8" parking_lot = "0.12.0" diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index 82917c46d3d27..7ab057b5f0dc2 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" -futures = "0.3.9" +futures = "0.3.19" futures-timer = "3.0.1" log = "0.4.8" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 161129c4ce682..d9b52c31f2731 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.9" +futures = "0.3.19" futures-timer = "3.0.1" libp2p = { version = "0.40.0", default-features = false } log = "0.4.8" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 0334c5e819df9..c26d90b8952e9 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -27,7 +27,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ either = "1.5.3" fnv = "1.0.6" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } -futures = "0.3.9" +futures = "0.3.19" futures-timer = "3.0.2" asynchronous-codec = "0.5" hex = "0.4.0" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 7d0b1921b69eb..4a47365e06412 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -17,7 +17,7 @@ async-std = "1.10.0" sc-network = { version = "0.10.0-dev", path = "../" } log = "0.4.8" parking_lot = "0.12.0" -futures = "0.3.9" +futures = "0.3.19" futures-timer = "3.0.1" rand = "0.7.2" libp2p = { version = "0.40.0", default-features = false } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 054a8c3edf02c..654633d6ed7f2 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -17,7 +17,7 @@ bytes = "1.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } hex = "0.4" fnv = "1.0.6" -futures = "0.3.16" +futures = "0.3.19" futures-timer = "3.0.2" num_cpus = "1.13" parking_lot = "0.12.0" diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index ac3590630a1eb..1bbf8bd6e9cba 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.9" +futures = "0.3.19" libp2p = { version = "0.40.0", default-features = false } sc-utils = { version = "4.0.0-dev", path = "../utils"} log = "0.4.8" diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index bbbc9a9983374..cfcadad1361ab 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.16" +futures = "0.3.19" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index 954bf602f85d6..496152ecb7505 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.16" +futures = "0.3.19" jsonrpc-core = "18.0.0" pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } log = "0.4.8" diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index cbce14cee20db..96dfa2c1caa4f 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -17,7 +17,7 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.16" +futures = "0.3.19" jsonrpc-pubsub = "18.0.0" log = "0.4.8" sp-core = { version = "5.0.0", path = "../../primitives/core" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index e007486d9ef1a..1747d8e61ea71 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -23,7 +23,7 @@ test-helpers = [] [dependencies] thiserror = "1.0.30" -futures = "0.3.16" +futures = "0.3.19" jsonrpc-pubsub = "18.0" jsonrpc-core = "18.0" rand = "0.7.3" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index a815d1f5571fc..ac1fb7ad01598 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -26,7 +26,7 @@ sp-externalities = { version = "0.11.0", path = "../../../primitives/externaliti sp-trie = { version = "5.0.0", path = "../../../primitives/trie" } sp-storage = { version = "5.0.0", path = "../../../primitives/storage" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../../db" } -futures = "0.3.16" +futures = "0.3.19" sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../../service" } sc-network = { version = "0.10.0-dev", path = "../../network" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 2339fa277ccad..7bdd60a037e17 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] parking_lot = "0.12.0" -futures = "0.3.9" +futures = "0.3.19" wasm-timer = "0.2.5" libp2p = { version = "0.40.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.8" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index a5d6d4e1bf74f..ac5beeac605f6 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } thiserror = "1.0.30" -futures = "0.3.16" +futures = "0.3.19" futures-timer = "3.0.2" log = "0.4.8" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 70f18c345e050..eb5f0ed6b0b7f 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/paritytech/substrate/" description = "Transaction pool client facing API." [dependencies] -futures = "0.3.1" +futures = "0.3.19" log = "0.4.8" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index 70d6bcd8b0495..a107aab1dbd6a 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -10,7 +10,7 @@ description = "I/O for Substrate runtimes" readme = "README.md" [dependencies] -futures = "0.3.9" +futures = "0.3.19" lazy_static = "1.4.0" parking_lot = "0.12.0" prometheus = { version = "0.13.0", default-features = false } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 8edb2a31fb550..9078c69f994ee 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -26,7 +26,7 @@ rustversion = "1.0.6" [dev-dependencies] criterion = "0.3.0" -futures = "0.3.9" +futures = "0.3.19" log = "0.4.14" sp-core = { version = "5.0.0", path = "../../core" } diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 69aa7c049f880..59d0121647c50 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -18,7 +18,7 @@ log = "0.4.11" lru = "0.7.0" parking_lot = "0.12.0" thiserror = "1.0.30" -futures = "0.3.9" +futures = "0.3.19" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sp-runtime = { version = "5.0.0", path = "../runtime" } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index d6c31876fa8da..4d0d17e1288e0 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -18,7 +18,7 @@ async-trait = "0.1.42" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } -futures = { version = "0.3.1", features = ["thread-pool"] } +futures = { version = "0.3.19", features = ["thread-pool"] } log = "0.4.8" sp-core = { path = "../../core", version = "5.0.0"} sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } @@ -30,7 +30,7 @@ sp-runtime = { version = "5.0.0", path = "../../runtime" } thiserror = "1.0.30" [dev-dependencies] -futures = "0.3.9" +futures = "0.3.19" sp-test-primitives = { version = "2.0.0", path = "../../test-primitives" } [features] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index bd1930bf51b6c..d1a8130579580 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -41,7 +41,7 @@ sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debu sp-storage = { version = "5.0.0", default-features = false, path = "../storage" } sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } -futures = { version = "0.3.1", optional = true } +futures = { version = "0.3.19", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.30", optional = true } bitflags = "1.3" diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 4fe1c75b52ae2..3bbe3caf5615d 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -24,7 +24,7 @@ impl-trait-for-tuples = "0.2.0" async-trait = { version = "0.1.50", optional = true } [dev-dependencies] -futures = "0.3.9" +futures = "0.3.19" [features] default = [ "std" ] diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 6cc6c47ddc962..b955d4c784dad 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -28,7 +28,7 @@ sp-trie = { version = "5.0.0", optional = true, path = "../trie" } sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.8", optional = true } -futures = { version = "0.3.1", features = ["thread-pool"], optional = true } +futures = { version = "0.3.19", features = ["thread-pool"], optional = true } parking_lot = { version = "0.12.0", optional = true } secp256k1 = { version = "0.21.2", features = ["recovery", "global-context"], optional = true } tracing = { version = "0.1.29", default-features = false } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 182a5f494fbca..341d2460765b1 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" -futures = "0.3.1" +futures = "0.3.19" parking_lot = { version = "0.12.0", default-features = false } serde = { version = "1.0", optional = true } thiserror = "1.0" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index ffddda3ac1f53..6deaddd9068f4 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.16" +futures = "0.3.19" hex = "0.4" serde = "1.0.136" serde_json = "1.0.74" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index b955aa07afa7f..79d43bea8520c 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -55,7 +55,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../client/block-builder" sc-executor = { version = "0.10.0-dev", path = "../../client/executor" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime-client = { version = "2.0.0", path = "./client" } -futures = "0.3.9" +futures = "0.3.19" [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../utils/wasm-builder" } diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index 3491a7a09f9ca..552a0581d79e0 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -23,4 +23,4 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } codec = { package = "parity-scale-codec", version = "3.0.0" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } -futures = "0.3.9" +futures = "0.3.19" diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index edb2efdb273f4..b936e6d9cb357 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -19,5 +19,5 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } -futures = "0.3.16" +futures = "0.3.19" thiserror = "1.0" diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index b255f5ab2a794..645e33f4b21a1 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -15,7 +15,7 @@ description = "Substrate RPC for FRAME's support" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.16" +futures = "0.3.19" jsonrpc-client-transports = { version = "18.0.0", features = ["http"] } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = "1" diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 950cbd09b2785..79794d779252c 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.16" +futures = "0.3.19" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" From 8934e6de3f8a5d48af8971c7a0fcc4c668d4f9ce Mon Sep 17 00:00:00 2001 From: Xiankun Cheng Date: Tue, 1 Mar 2022 22:32:22 +1300 Subject: [PATCH 0557/1472] Clean up extra_constant renaming. (#10935) Co-authored-by: Xiankun Cheng --- frame/transaction-payment/src/lib.rs | 5 ++--- frame/vesting/src/lib.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index e4d77a05f284b..37fecf20cc528 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -297,10 +297,9 @@ pub mod pallet { #[pallet::extra_constants] impl Pallet { - // TODO: rename to snake case after https://github.com/paritytech/substrate/issues/8826 fixed. - #[allow(non_snake_case)] + #[pallet::constant_name(WeightToFee)] /// The polynomial that is applied in order to derive fee from weight. - fn WeightToFee() -> Vec>> { + fn weight_to_fee_polynomial() -> Vec>> { T::WeightToFee::polynomial().to_vec() } } diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 747521f4fa536..775902f223ba0 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -171,9 +171,8 @@ pub mod pallet { #[pallet::extra_constants] impl Pallet { - // TODO: rename to snake case after https://github.com/paritytech/substrate/issues/8826 fixed. - #[allow(non_snake_case)] - fn MaxVestingSchedules() -> u32 { + #[pallet::constant_name(MaxVestingSchedules)] + fn max_vesting_schedules() -> u32 { T::MAX_VESTING_SCHEDULES } } From 919e304dd6f3c11a55ee125498e8e531ce343805 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 10:03:31 +0000 Subject: [PATCH 0558/1472] Bump smallvec from 1.7.0 to 1.8.0 (#10949) Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.7.0 to 1.8.0. - [Release notes](https://github.com/servo/rust-smallvec/releases) - [Commits](https://github.com/servo/rust-smallvec/compare/v1.7.0...v1.8.0) --- updated-dependencies: - dependency-name: smallvec 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 | 80 +++++++++---------- client/network/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- 6 files changed, 45 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e6ae5a1fea5fa..08d44487776d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1159,7 +1159,7 @@ dependencies = [ "gimli 0.22.0", "log 0.4.14", "regalloc 0.0.31", - "smallvec 1.7.0", + "smallvec 1.8.0", "target-lexicon 0.11.2", "thiserror", ] @@ -1177,7 +1177,7 @@ dependencies = [ "gimli 0.26.1", "log 0.4.14", "regalloc 0.0.33", - "smallvec 1.7.0", + "smallvec 1.8.0", "target-lexicon 0.12.0", ] @@ -1238,7 +1238,7 @@ checksum = "b608bb7656c554d0a4cf8f50c7a10b857e80306f6ff829ad6d468a7e2323c8d8" dependencies = [ "cranelift-codegen 0.68.0", "log 0.4.14", - "smallvec 1.7.0", + "smallvec 1.8.0", "target-lexicon 0.11.2", ] @@ -1250,7 +1250,7 @@ checksum = "b7cb156de1097f567d46bf57a0cd720a72c3e15e1a2bd8b1041ba2fc894471b7" dependencies = [ "cranelift-codegen 0.80.0", "log 0.4.14", - "smallvec 1.7.0", + "smallvec 1.8.0", "target-lexicon 0.12.0", ] @@ -1276,7 +1276,7 @@ dependencies = [ "cranelift-frontend 0.80.0", "itertools", "log 0.4.14", - "smallvec 1.7.0", + "smallvec 1.8.0", "wasmparser 0.81.0", "wasmtime-types", ] @@ -2223,7 +2223,7 @@ dependencies = [ "pretty_assertions", "scale-info", "serde", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-arithmetic", "sp-core", "sp-core-hashing-proc-macro", @@ -3551,7 +3551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a301d8ecb7989d4a6e2c57a49baca77d353bdbf879909debe3f375fe25d61f86" dependencies = [ "parity-util-mem", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -3580,7 +3580,7 @@ dependencies = [ "parking_lot 0.12.0", "regex", "rocksdb", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -3698,7 +3698,7 @@ dependencies = [ "multiaddr", "parking_lot 0.11.2", "pin-project 1.0.10", - "smallvec 1.7.0", + "smallvec 1.8.0", "wasm-timer", ] @@ -3729,7 +3729,7 @@ dependencies = [ "ring", "rw-stream-sink", "sha2 0.9.8", - "smallvec 1.7.0", + "smallvec 1.8.0", "thiserror", "unsigned-varint 0.7.0", "void", @@ -3757,7 +3757,7 @@ dependencies = [ "futures 0.3.19", "libp2p-core", "log 0.4.14", - "smallvec 1.7.0", + "smallvec 1.8.0", "trust-dns-resolver", ] @@ -3776,7 +3776,7 @@ dependencies = [ "prost", "prost-build", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -3800,7 +3800,7 @@ dependencies = [ "rand 0.7.3", "regex", "sha2 0.9.8", - "smallvec 1.7.0", + "smallvec 1.8.0", "unsigned-varint 0.7.0", "wasm-timer", ] @@ -3818,7 +3818,7 @@ dependencies = [ "lru 0.6.6", "prost", "prost-build", - "smallvec 1.7.0", + "smallvec 1.8.0", "wasm-timer", ] @@ -3841,7 +3841,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "sha2 0.9.8", - "smallvec 1.7.0", + "smallvec 1.8.0", "uint", "unsigned-varint 0.7.0", "void", @@ -3864,7 +3864,7 @@ dependencies = [ "libp2p-swarm", "log 0.4.14", "rand 0.8.4", - "smallvec 1.7.0", + "smallvec 1.8.0", "socket2 0.4.0", "void", ] @@ -3897,7 +3897,7 @@ dependencies = [ "nohash-hasher", "parking_lot 0.11.2", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", "unsigned-varint 0.7.0", ] @@ -3986,7 +3986,7 @@ dependencies = [ "prost", "prost-build", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", "unsigned-varint 0.7.0", "void", "wasm-timer", @@ -4028,7 +4028,7 @@ dependencies = [ "log 0.4.14", "lru 0.7.0", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", "unsigned-varint 0.7.0", "wasm-timer", ] @@ -4044,7 +4044,7 @@ dependencies = [ "libp2p-core", "log 0.4.14", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", "void", "wasm-timer", ] @@ -4650,7 +4650,7 @@ dependencies = [ "futures 0.3.19", "log 0.4.14", "pin-project 1.0.10", - "smallvec 1.7.0", + "smallvec 1.8.0", "unsigned-varint 0.7.0", ] @@ -5416,7 +5416,7 @@ dependencies = [ "scale-info", "serde", "serde_json", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-core", "sp-io", "sp-runtime", @@ -5720,7 +5720,7 @@ dependencies = [ "rand_pcg 0.3.1", "scale-info", "serde", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-core", "sp-io", "sp-keystore", @@ -6494,7 +6494,7 @@ dependencies = [ "scale-info", "serde", "serde_json", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-core", "sp-io", "sp-runtime", @@ -6692,7 +6692,7 @@ dependencies = [ "parity-util-mem-derive", "parking_lot 0.12.0", "primitive-types", - "smallvec 1.7.0", + "smallvec 1.8.0", "winapi 0.3.9", ] @@ -6803,7 +6803,7 @@ dependencies = [ "instant", "libc", "redox_syscall 0.2.10", - "smallvec 1.7.0", + "smallvec 1.8.0", "winapi 0.3.9", ] @@ -6816,7 +6816,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall 0.2.10", - "smallvec 1.7.0", + "smallvec 1.8.0", "windows-sys", ] @@ -7629,7 +7629,7 @@ checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" dependencies = [ "log 0.4.14", "rustc-hash", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -7640,7 +7640,7 @@ checksum = "7d808cff91dfca7b239d40b972ba628add94892b1d9e19a842aedc5cfae8ab1a" dependencies = [ "log 0.4.14", "rustc-hash", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -8608,7 +8608,7 @@ dependencies = [ "sc-utils", "serde", "serde_json", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -9484,9 +9484,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "snap" @@ -10227,7 +10227,7 @@ dependencies = [ "parking_lot 0.12.0", "pretty_assertions", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-core", "sp-externalities", "sp-panic-handler", @@ -11190,7 +11190,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec 1.7.0", + "smallvec 1.8.0", "thread_local", "tracing", "tracing-core", @@ -11236,7 +11236,7 @@ dependencies = [ "hashbrown 0.12.0", "log 0.4.14", "rustc-hex", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -11276,7 +11276,7 @@ dependencies = [ "lazy_static", "log 0.4.14", "rand 0.8.4", - "smallvec 1.7.0", + "smallvec 1.8.0", "thiserror", "tinyvec", "url 2.2.1", @@ -11296,7 +11296,7 @@ dependencies = [ "lru-cache", "parking_lot 0.11.2", "resolv-conf", - "smallvec 1.7.0", + "smallvec 1.8.0", "thiserror", "trust-dns-proto", ] @@ -11737,7 +11737,7 @@ dependencies = [ "enumset", "serde", "serde_bytes", - "smallvec 1.7.0", + "smallvec 1.8.0", "target-lexicon 0.11.2", "thiserror", "wasmer-types", @@ -11757,7 +11757,7 @@ dependencies = [ "more-asserts", "rayon", "serde", - "smallvec 1.7.0", + "smallvec 1.8.0", "tracing", "wasmer-compiler", "wasmer-types", @@ -11777,7 +11777,7 @@ dependencies = [ "more-asserts", "rayon", "serde", - "smallvec 1.7.0", + "smallvec 1.8.0", "wasmer-compiler", "wasmer-types", "wasmer-vm", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index c26d90b8952e9..2e5bb3ea0ee5a 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -46,7 +46,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.74" -smallvec = "1.7.0" +smallvec = "1.8.0" sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 9bb7ae5d8af8d..cd6a082e57cfd 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -32,7 +32,7 @@ once_cell = { version = "1", default-features = false, optional = true } sp-state-machine = { version = "0.11.0", optional = true, path = "../../primitives/state-machine" } bitflags = "1.3" impl-trait-for-tuples = "0.2.1" -smallvec = "1.7.0" +smallvec = "1.8.0" log = { version = "0.4.14", default-features = false } sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index fe6b4e0e2c7ca..0d2388e05bd2f 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } -smallvec = "1.7.0" +smallvec = "1.8.0" sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 7768ae76847ae..b3471b38045f5 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -29,7 +29,7 @@ scale-info = { version = "2.0.0", default-features = false, features = ["derive" serde = { version = "1.0.136", optional = true } [dev-dependencies] -smallvec = "1.7.0" +smallvec = "1.8.0" serde_json = "1.0.74" sp-storage = { version = "5.0.0", default-features = false, path = "../../../primitives/storage" } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 300af627f71ba..9e0c0c026a23b 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -27,7 +27,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = num-traits = { version = "0.2.8", default-features = false } rand = { version = "0.7.2", optional = true } sp-externalities = { version = "0.11.0", path = "../externalities", default-features = false } -smallvec = "1.7.0" +smallvec = "1.8.0" sp-std = { version = "4.0.0", default-features = false, path = "../std" } tracing = { version = "0.1.29", optional = true } From b4c188b3904209aba4b331ab19c46c8d0ff64d3c Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Tue, 1 Mar 2022 14:31:51 +0100 Subject: [PATCH 0559/1472] new pallet: whitelist pallet (#10159) * pallet whitelist * refactor a bit * fmt * address audit * improve tests * return Ok + refund * add test for dispatching failing * add dispatch_whitelisted_call_with_preimage * fmt * better name * Consume all data on decode Signed-off-by: Oliver Tale-Yazdi * Add error docs Signed-off-by: Oliver Tale-Yazdi * Remove phantom data Signed-off-by: Oliver Tale-Yazdi * Use rust 2021 Signed-off-by: Oliver Tale-Yazdi * Update crate features Signed-off-by: Oliver Tale-Yazdi * Fmt Signed-off-by: Oliver Tale-Yazdi * Make compile Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_whitelist --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/whitelist/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Bump Preimage max size Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_whitelist --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/whitelist/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Fmt Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Parity Bot --- Cargo.lock | 19 +++ Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 3 + bin/node/runtime/src/lib.rs | 11 ++ frame/conviction-voting/Cargo.toml | 2 +- frame/referenda/Cargo.toml | 2 +- frame/whitelist/Cargo.toml | 47 ++++++ frame/whitelist/src/benchmarking.rs | 120 ++++++++++++++ frame/whitelist/src/lib.rs | 244 ++++++++++++++++++++++++++++ frame/whitelist/src/mock.rs | 124 ++++++++++++++ frame/whitelist/src/tests.rs | 175 ++++++++++++++++++++ frame/whitelist/src/weights.rs | 126 ++++++++++++++ primitives/runtime/src/lib.rs | 2 +- 13 files changed, 873 insertions(+), 3 deletions(-) create mode 100644 frame/whitelist/Cargo.toml create mode 100644 frame/whitelist/src/benchmarking.rs create mode 100644 frame/whitelist/src/lib.rs create mode 100644 frame/whitelist/src/mock.rs create mode 100644 frame/whitelist/src/tests.rs create mode 100644 frame/whitelist/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 08d44487776d5..2bd91ca7b6b86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5019,6 +5019,7 @@ dependencies = [ "pallet-uniques", "pallet-utility", "pallet-vesting", + "pallet-whitelist", "parity-scale-codec", "scale-info", "sp-api", @@ -6615,6 +6616,24 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-whitelist" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-preimage", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "parity-db" version = "0.3.5" diff --git a/Cargo.toml b/Cargo.toml index a12910c52c018..f24ff6d04980a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -138,6 +138,7 @@ members = [ "frame/uniques", "frame/utility", "frame/vesting", + "frame/whitelist", "primitives/api", "primitives/api/proc-macro", "primitives/api/test", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 0055230295a1e..39c4609c4425f 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -100,6 +100,7 @@ pallet-asset-tx-payment = { version = "4.0.0-dev", default-features = false, pat pallet-transaction-storage = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-storage" } pallet-uniques = { version = "4.0.0-dev", default-features = false, path = "../../../frame/uniques" } pallet-vesting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/vesting" } +pallet-whitelist = { version = "4.0.0-dev", default-features = false, path = "../../../frame/whitelist" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } @@ -220,6 +221,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", "frame-system-benchmarking", "hex-literal", ] @@ -267,6 +269,7 @@ try-runtime = [ "pallet-uniques/try-runtime", "pallet-utility/try-runtime", "pallet-vesting/try-runtime", + "pallet-whitelist/try-runtime", ] # Make contract callable functions marked as __unstable__ available. Do not enable # on live chains as those are subject to change. diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0aff3d8046eef..9ff19760c775f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1357,6 +1357,15 @@ impl pallet_transaction_storage::Config for Runtime { type WeightInfo = pallet_transaction_storage::weights::SubstrateWeight; } +impl pallet_whitelist::Config for Runtime { + type Event = Event; + type Call = Call; + type WhitelistOrigin = EnsureRoot; + type DispatchWhitelistedOrigin = EnsureRoot; + type PreimageProvider = Preimage; + type WeightInfo = pallet_whitelist::weights::SubstrateWeight; +} + construct_runtime!( pub enum Runtime where Block = Block, @@ -1411,6 +1420,7 @@ construct_runtime!( ChildBounties: pallet_child_bounties, Referenda: pallet_referenda, ConvictionVoting: pallet_conviction_voting, + Whitelist: pallet_whitelist, } ); @@ -1509,6 +1519,7 @@ mod benches { [pallet_uniques, Uniques] [pallet_utility, Utility] [pallet_vesting, Vesting] + [pallet_whitelist, Whitelist] ); } diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index 039fdb07caabc..7e99302574354 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-conviction-voting" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index a3067956db2b0..56598af91393e 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-referenda" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" diff --git a/frame/whitelist/Cargo.toml b/frame/whitelist/Cargo.toml new file mode 100644 index 0000000000000..057e7fd71f307 --- /dev/null +++ b/frame/whitelist/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "pallet-whitelist" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet for whitelisting call, and dispatch from specific origin" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.0", default-features = false, features = ["derive"] } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } + +[dev-dependencies] +sp-core = { version = "5.0.0", path = "../../primitives/core" } +pallet-preimage = { version = "4.0.0-dev", path = "../preimage/" } +pallet-balances = { version = "4.0.0-dev", path = "../balances/" } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "sp-std/std", + "sp-io/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", +] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs new file mode 100644 index 0000000000000..c51ea0a0a3246 --- /dev/null +++ b/frame/whitelist/src/benchmarking.rs @@ -0,0 +1,120 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Whitelist pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use core::convert::TryInto; +use frame_benchmarking::benchmarks; +use frame_support::{ensure, traits::PreimageRecipient}; +use sp_runtime::traits::Hash; + +#[cfg(test)] +use crate::Pallet as Whitelist; + +benchmarks! { + whitelist_call { + let origin = T::WhitelistOrigin::successful_origin(); + let call_hash = Default::default(); + }: _(origin, call_hash) + verify { + ensure!( + WhitelistedCall::::contains_key(call_hash), + "call not whitelisted" + ); + ensure!( + T::PreimageProvider::preimage_requested(&call_hash), + "preimage not requested" + ); + } + + remove_whitelisted_call { + let origin = T::WhitelistOrigin::successful_origin(); + let call_hash = Default::default(); + Pallet::::whitelist_call(origin.clone(), call_hash) + .expect("whitelisting call must be successful"); + }: _(origin, call_hash) + verify { + ensure!( + !WhitelistedCall::::contains_key(call_hash), + "whitelist not removed" + ); + ensure!( + !T::PreimageProvider::preimage_requested(&call_hash), + "preimage still requested" + ); + } + + // We benchmark with the maximum possible size for a call. + // If the resulting weight is too big, maybe it worth having a weight which depends + // on the size of the call, with a new witness in parameter. + dispatch_whitelisted_call { + let origin = T::DispatchWhitelistedOrigin::successful_origin(); + // NOTE: we remove `10` because we need some bytes to encode the variants and vec length + let remark_len = >::MaxSize::get() - 10; + let remark = sp_std::vec![1_8; remark_len as usize]; + + let call: ::Call = frame_system::Call::remark { remark }.into(); + let call_weight = call.get_dispatch_info().weight; + let encoded_call = call.encode(); + let call_hash = T::Hashing::hash(&encoded_call[..]); + + Pallet::::whitelist_call(origin.clone(), call_hash) + .expect("whitelisting call must be successful"); + + let encoded_call = encoded_call.try_into().expect("encoded_call must be small enough"); + T::PreimageProvider::note_preimage(encoded_call); + + }: _(origin, call_hash, call_weight) + verify { + ensure!( + !WhitelistedCall::::contains_key(call_hash), + "whitelist not removed" + ); + ensure!( + !T::PreimageProvider::preimage_requested(&call_hash), + "preimage still requested" + ); + } + + dispatch_whitelisted_call_with_preimage { + let n in 1 .. 10_000; + + let origin = T::DispatchWhitelistedOrigin::successful_origin(); + let remark = sp_std::vec![1u8; n as usize]; + + let call: ::Call = frame_system::Call::remark { remark }.into(); + let call_hash = T::Hashing::hash_of(&call); + + Pallet::::whitelist_call(origin.clone(), call_hash) + .expect("whitelisting call must be successful"); + }: _(origin, Box::new(call)) + verify { + ensure!( + !WhitelistedCall::::contains_key(call_hash), + "whitelist not removed" + ); + ensure!( + !T::PreimageProvider::preimage_requested(&call_hash), + "preimage still requested" + ); + } + + impl_benchmark_test_suite!(Whitelist, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs new file mode 100644 index 0000000000000..9f20386da85f5 --- /dev/null +++ b/frame/whitelist/src/lib.rs @@ -0,0 +1,244 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Whitelist Pallet +//! +//! - [`Config`] +//! - [`Call`] +//! +//! ## Overview +//! +//! Allow some configurable origin: [`Config::WhitelistOrigin`] to whitelist some hash of a call, +//! and allow another configurable origin: [`Config::DispatchWhitelistedOrigin`] to dispatch them +//! with the root origin. +//! +//! In the meantime the call corresponding to the hash must have been submitted to the to the +//! pre-image handler [`PreimageProvider`]. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; +pub mod weights; + +use sp_runtime::traits::Dispatchable; +use sp_std::prelude::*; + +use codec::{Decode, DecodeLimit, Encode, FullCodec, MaxEncodedLen}; +use frame_support::{ + ensure, + traits::{PreimageProvider, PreimageRecipient}, + weights::{GetDispatchInfo, PostDispatchInfo}, +}; +use scale_info::TypeInfo; +use sp_api::HashT; +use weights::WeightInfo; + +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +pub use pallet::*; + +#[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub struct Preimage { + preimage: BoundedVec, + deposit: Option<(AccountId, Balance)>, +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// The overarching call type. + type Call: IsType<::Call> + + Dispatchable + + GetDispatchInfo + + FullCodec + + TypeInfo + + From> + + Parameter; + + /// Required origin for whitelisting a call. + type WhitelistOrigin: EnsureOrigin; + + /// Required origin for dispatching whitelisted call with root origin. + type DispatchWhitelistedOrigin: EnsureOrigin; + + /// The handler of pre-images. + // NOTE: recipient is only needed for benchmarks. + type PreimageProvider: PreimageProvider + PreimageRecipient; + + /// The weight information for this pallet. + type WeightInfo: weights::WeightInfo; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + CallWhitelisted { call_hash: T::Hash }, + WhitelistedCallRemoved { call_hash: T::Hash }, + WhitelistedCallDispatched { call_hash: T::Hash, result: DispatchResultWithPostInfo }, + } + + #[pallet::error] + pub enum Error { + /// The preimage of the call hash could not be loaded. + UnavailablePreImage, + /// The call could not be decoded. + UndecodableCall, + /// The weight of the decoded call was higher than the witness. + InvalidCallWeightWitness, + /// The call was not whitelisted. + CallIsNotWhitelisted, + /// The call was already whitelisted; No-Op. + CallAlreadyWhitelisted, + } + + #[pallet::storage] + pub type WhitelistedCall = StorageMap<_, Twox64Concat, T::Hash, (), OptionQuery>; + + #[pallet::call] + impl Pallet { + #[pallet::weight(T::WeightInfo::whitelist_call())] + pub fn whitelist_call(origin: OriginFor, call_hash: T::Hash) -> DispatchResult { + T::WhitelistOrigin::ensure_origin(origin)?; + + ensure!( + !WhitelistedCall::::contains_key(call_hash), + Error::::CallAlreadyWhitelisted, + ); + + WhitelistedCall::::insert(call_hash, ()); + T::PreimageProvider::request_preimage(&call_hash); + + Self::deposit_event(Event::::CallWhitelisted { call_hash }); + + Ok(()) + } + + #[pallet::weight(T::WeightInfo::remove_whitelisted_call())] + pub fn remove_whitelisted_call(origin: OriginFor, call_hash: T::Hash) -> DispatchResult { + T::WhitelistOrigin::ensure_origin(origin)?; + + WhitelistedCall::::take(call_hash).ok_or(Error::::CallIsNotWhitelisted)?; + + T::PreimageProvider::unrequest_preimage(&call_hash); + + Self::deposit_event(Event::::WhitelistedCallRemoved { call_hash }); + + Ok(()) + } + + #[pallet::weight( + T::WeightInfo::dispatch_whitelisted_call().saturating_add(*call_weight_witness) + )] + pub fn dispatch_whitelisted_call( + origin: OriginFor, + call_hash: T::Hash, + call_weight_witness: Weight, + ) -> DispatchResultWithPostInfo { + T::DispatchWhitelistedOrigin::ensure_origin(origin)?; + + ensure!( + WhitelistedCall::::contains_key(call_hash), + Error::::CallIsNotWhitelisted, + ); + + let call = T::PreimageProvider::get_preimage(&call_hash) + .ok_or(Error::::UnavailablePreImage)?; + + let call = ::Call::decode_all_with_depth_limit( + sp_api::MAX_EXTRINSIC_DEPTH, + &mut &call[..], + ) + .map_err(|_| Error::::UndecodableCall)?; + + ensure!( + call.get_dispatch_info().weight <= call_weight_witness, + Error::::InvalidCallWeightWitness + ); + + let actual_weight = Self::clean_and_dispatch(call_hash, call) + .map(|w| w.saturating_add(T::WeightInfo::dispatch_whitelisted_call())); + + Ok(actual_weight.into()) + } + + #[pallet::weight({ + let call_weight = call.get_dispatch_info().weight; + let call_len = call.encoded_size() as u32; + + T::WeightInfo::dispatch_whitelisted_call_with_preimage(call_len) + .saturating_add(call_weight) + })] + pub fn dispatch_whitelisted_call_with_preimage( + origin: OriginFor, + call: Box<::Call>, + ) -> DispatchResultWithPostInfo { + T::DispatchWhitelistedOrigin::ensure_origin(origin)?; + + let call_hash = ::Hashing::hash_of(&call); + + ensure!( + WhitelistedCall::::contains_key(call_hash), + Error::::CallIsNotWhitelisted, + ); + + let call_len = call.encoded_size() as u32; + let actual_weight = Self::clean_and_dispatch(call_hash, *call).map(|w| { + w.saturating_add(T::WeightInfo::dispatch_whitelisted_call_with_preimage(call_len)) + }); + + Ok(actual_weight.into()) + } + } +} + +impl Pallet { + /// Clean whitelisting/preimage and dispatch call. + /// + /// Return the call actual weight of the dispatched call if there is some. + fn clean_and_dispatch(call_hash: T::Hash, call: ::Call) -> Option { + WhitelistedCall::::remove(call_hash); + + T::PreimageProvider::unrequest_preimage(&call_hash); + + let result = call.dispatch(frame_system::Origin::::Root.into()); + + let call_actual_weight = match result { + Ok(call_post_info) => call_post_info.actual_weight, + Err(call_err) => call_err.post_info.actual_weight, + }; + + Self::deposit_event(Event::::WhitelistedCallDispatched { call_hash, result }); + + call_actual_weight + } +} diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs new file mode 100644 index 0000000000000..3009a6f6b5d58 --- /dev/null +++ b/frame/whitelist/src/mock.rs @@ -0,0 +1,124 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Mock for Whitelist Pallet + +#![cfg(test)] + +use crate as pallet_whitelist; + +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64, Nothing}, +}; +use frame_system::EnsureRoot; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Balances: pallet_balances, + Whitelist: pallet_whitelist, + Preimage: pallet_preimage, + } +); + +frame_support::parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(1024); +} +impl frame_system::Config for Test { + type BaseCallFilter = Nothing; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Call = Call; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = u64; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); +} + +parameter_types! { + // Taken from Polkadot as reference. + pub const PreimageMaxSize: u32 = 4096 * 1024; +} + +impl pallet_preimage::Config for Test { + type Event = Event; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type MaxSize = PreimageMaxSize; + type BaseDeposit = ConstU64<1>; + type ByteDeposit = ConstU64<1>; + type WeightInfo = (); +} + +impl pallet_whitelist::Config for Test { + type Event = Event; + type Call = Call; + type WhitelistOrigin = EnsureRoot; + type DispatchWhitelistedOrigin = EnsureRoot; + type PreimageProvider = Preimage; + type WeightInfo = (); +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = GenesisConfig::default().build_storage().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} diff --git a/frame/whitelist/src/tests.rs b/frame/whitelist/src/tests.rs new file mode 100644 index 0000000000000..67bccaeaeebe1 --- /dev/null +++ b/frame/whitelist/src/tests.rs @@ -0,0 +1,175 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Tests for Whitelist Pallet + +use crate::mock::*; +use codec::Encode; +use frame_support::{assert_noop, assert_ok, dispatch::GetDispatchInfo, traits::PreimageProvider}; +use sp_runtime::{traits::Hash, DispatchError}; + +#[test] +fn test_whitelist_call_and_remove() { + new_test_ext().execute_with(|| { + let call = Call::System(frame_system::Call::remark { remark: vec![] }); + let encoded_call = call.encode(); + let call_hash = ::Hashing::hash(&encoded_call[..]); + + assert_noop!( + Whitelist::remove_whitelisted_call(Origin::root(), call_hash), + crate::Error::::CallIsNotWhitelisted, + ); + + assert_noop!( + Whitelist::whitelist_call(Origin::signed(1), call_hash), + DispatchError::BadOrigin, + ); + + assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + + assert!(Preimage::preimage_requested(&call_hash)); + + assert_noop!( + Whitelist::whitelist_call(Origin::root(), call_hash), + crate::Error::::CallAlreadyWhitelisted, + ); + + assert_noop!( + Whitelist::remove_whitelisted_call(Origin::signed(1), call_hash), + DispatchError::BadOrigin, + ); + + assert_ok!(Whitelist::remove_whitelisted_call(Origin::root(), call_hash)); + + assert!(!Preimage::preimage_requested(&call_hash)); + + assert_noop!( + Whitelist::remove_whitelisted_call(Origin::root(), call_hash), + crate::Error::::CallIsNotWhitelisted, + ); + }); +} + +#[test] +fn test_whitelist_call_and_execute() { + new_test_ext().execute_with(|| { + let call = Call::System(frame_system::Call::remark_with_event { remark: vec![1] }); + let call_weight = call.get_dispatch_info().weight; + let encoded_call = call.encode(); + let call_hash = ::Hashing::hash(&encoded_call[..]); + + assert_noop!( + Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + crate::Error::::CallIsNotWhitelisted, + ); + + assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + + assert_noop!( + Whitelist::dispatch_whitelisted_call(Origin::signed(1), call_hash, call_weight), + DispatchError::BadOrigin, + ); + + assert_noop!( + Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + crate::Error::::UnavailablePreImage, + ); + + assert_ok!(Preimage::note_preimage(Origin::root(), encoded_call)); + + assert!(Preimage::preimage_requested(&call_hash)); + + assert_noop!( + Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight - 1), + crate::Error::::InvalidCallWeightWitness, + ); + + assert_ok!(Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight)); + + assert!(!Preimage::preimage_requested(&call_hash)); + + assert_noop!( + Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + crate::Error::::CallIsNotWhitelisted, + ); + }); +} + +#[test] +fn test_whitelist_call_and_execute_failing_call() { + new_test_ext().execute_with(|| { + let call = Call::Whitelist(crate::Call::dispatch_whitelisted_call { + call_hash: Default::default(), + call_weight_witness: 0, + }); + let call_weight = call.get_dispatch_info().weight; + let encoded_call = call.encode(); + let call_hash = ::Hashing::hash(&encoded_call[..]); + + assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + assert_ok!(Preimage::note_preimage(Origin::root(), encoded_call)); + assert!(Preimage::preimage_requested(&call_hash)); + assert_ok!(Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight)); + assert!(!Preimage::preimage_requested(&call_hash)); + }); +} + +#[test] +fn test_whitelist_call_and_execute_without_note_preimage() { + new_test_ext().execute_with(|| { + let call = + Box::new(Call::System(frame_system::Call::remark_with_event { remark: vec![1] })); + let call_hash = ::Hashing::hash_of(&call); + + assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + assert!(Preimage::preimage_requested(&call_hash)); + + assert_ok!(Whitelist::dispatch_whitelisted_call_with_preimage( + Origin::root(), + call.clone() + )); + + assert!(!Preimage::preimage_requested(&call_hash)); + + assert_noop!( + Whitelist::dispatch_whitelisted_call_with_preimage(Origin::root(), call), + crate::Error::::CallIsNotWhitelisted, + ); + }); +} + +#[test] +fn test_whitelist_call_and_execute_decode_consumes_all() { + new_test_ext().execute_with(|| { + let call = Call::System(frame_system::Call::remark_with_event { remark: vec![1] }); + let call_weight = call.get_dispatch_info().weight; + let mut call = call.encode(); + // Appending something does not make the encoded call invalid. + // This tests that the decode function consumes all data. + call.extend(call.clone()); + + let call_hash = ::Hashing::hash(&call[..]); + + assert_ok!(Preimage::note_preimage(Origin::root(), call)); + assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + + assert_noop!( + Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + crate::Error::::UndecodableCall, + ); + }); +} diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs new file mode 100644 index 0000000000000..fdba734db64ba --- /dev/null +++ b/frame/whitelist/src/weights.rs @@ -0,0 +1,126 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_whitelist +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-02-25, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/production/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_whitelist +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/whitelist/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_whitelist. +pub trait WeightInfo { + fn whitelist_call() -> Weight; + fn remove_whitelisted_call() -> Weight; + fn dispatch_whitelisted_call() -> Weight; + fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight; +} + +/// Weights for pallet_whitelist using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Whitelist WhitelistedCall (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn whitelist_call() -> Weight { + (16_254_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Whitelist WhitelistedCall (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn remove_whitelisted_call() -> Weight { + (18_348_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Whitelist WhitelistedCall (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn dispatch_whitelisted_call() -> Weight { + (6_618_241_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Whitelist WhitelistedCall (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { + (20_619_000 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Whitelist WhitelistedCall (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn whitelist_call() -> Weight { + (16_254_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Whitelist WhitelistedCall (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn remove_whitelisted_call() -> Weight { + (18_348_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Whitelist WhitelistedCall (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn dispatch_whitelisted_call() -> Weight { + (6_618_241_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Whitelist WhitelistedCall (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { + (20_619_000 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } +} diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 6d32d2322c765..a428da59f6a0d 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -511,7 +511,7 @@ pub enum DispatchError { /// Result of a `Dispatchable` which contains the `DispatchResult` and additional information about /// the `Dispatchable` that is only known post dispatch. -#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, RuntimeDebug)] +#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct DispatchErrorWithPostInfo where Info: Eq + PartialEq + Clone + Copy + Encode + Decode + traits::Printable, From d14784fee8eddead26efc8617c512cc8775bfde5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 1 Mar 2022 13:35:23 +0000 Subject: [PATCH 0560/1472] Release primitive crates (#10937) * cargo set-version --bump major -p pallet-contracts-primitives * cargo set-version --bump major -p sp-core * cargo set-version --bump major -p sp-runtime-interface * cargo set-version --bump major -p sp-wasm-interface * cargo set-version --bump major -p sp-runtime * cargo set-version --bump major -p sp-storage * cargo set-version --bump major -p sp-rpc * cargo set-version --bump major -p sp-io * cargo set-version --bump major -p sp-trie * cargo set-version -p sp-state-machine -- 0.12.0 * cargo set-version -p sp-externalities -- 0.12.0 * cargo set-version -p sp-keystore -- 0.12.0 * cargo set-version --bump major -p sp-keyring * cargo set-version --bump major -p sp-version * cargo set-version --bump major -p sp-tracing * cargo set-version --bump major -p sp-application-crypto * cargo set-version --bump major -p sp-arithmetic * cargo unleash version bump-major -p sp-runtime-interface-proc-macro * Add codec max-encoded-len feature to sp-arithmetic * cargo unleash version bump-major -p sp-core-hashing-proc-macro --- Cargo.lock | 38 +++++++++---------- bin/node-template/node/Cargo.toml | 4 +- bin/node-template/pallets/template/Cargo.toml | 6 +-- bin/node-template/runtime/Cargo.toml | 6 +-- bin/node/bench/Cargo.toml | 10 ++--- bin/node/cli/Cargo.toml | 12 +++--- bin/node/executor/Cargo.toml | 18 ++++----- bin/node/inspect/Cargo.toml | 4 +- bin/node/primitives/Cargo.toml | 6 +-- bin/node/rpc/Cargo.toml | 4 +- bin/node/runtime/Cargo.toml | 10 ++--- bin/node/testing/Cargo.toml | 8 ++-- bin/utils/chain-spec-builder/Cargo.toml | 4 +- client/allocator/Cargo.toml | 4 +- client/api/Cargo.toml | 14 +++---- client/authority-discovery/Cargo.toml | 8 ++-- client/basic-authorship/Cargo.toml | 4 +- client/beefy/Cargo.toml | 12 +++--- client/beefy/rpc/Cargo.toml | 4 +- client/block-builder/Cargo.toml | 6 +-- client/chain-spec/Cargo.toml | 4 +- client/cli/Cargo.toml | 10 ++--- client/consensus/aura/Cargo.toml | 12 +++--- client/consensus/babe/Cargo.toml | 14 +++---- client/consensus/babe/rpc/Cargo.toml | 10 ++--- client/consensus/common/Cargo.toml | 6 +-- client/consensus/epochs/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 6 +-- client/consensus/pow/Cargo.toml | 4 +- client/consensus/slots/Cargo.toml | 8 ++-- client/consensus/uncles/Cargo.toml | 2 +- client/db/Cargo.toml | 12 +++--- client/executor/Cargo.toml | 20 +++++----- client/executor/common/Cargo.toml | 4 +- client/executor/runtime-test/Cargo.toml | 6 +-- client/executor/wasmi/Cargo.toml | 6 +-- client/executor/wasmtime/Cargo.toml | 8 ++-- client/finality-grandpa/Cargo.toml | 14 +++---- client/finality-grandpa/rpc/Cargo.toml | 8 ++-- client/informant/Cargo.toml | 2 +- client/keystore/Cargo.toml | 6 +-- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 8 ++-- client/network/test/Cargo.toml | 6 +-- client/offchain/Cargo.toml | 6 +-- client/rpc-api/Cargo.toml | 10 ++--- client/rpc/Cargo.toml | 12 +++--- client/service/Cargo.toml | 20 +++++----- client/service/test/Cargo.toml | 14 +++---- client/state-db/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/tracing/Cargo.toml | 8 ++-- client/transaction-pool/Cargo.toml | 6 +-- client/transaction-pool/api/Cargo.toml | 2 +- frame/assets/Cargo.toml | 6 +-- frame/atomic-swap/Cargo.toml | 6 +-- frame/aura/Cargo.toml | 8 ++-- frame/authority-discovery/Cargo.toml | 8 ++-- frame/authorship/Cargo.toml | 6 +-- frame/babe/Cargo.toml | 8 ++-- frame/bags-list/Cargo.toml | 14 +++---- frame/bags-list/remote-tests/Cargo.toml | 8 ++-- frame/balances/Cargo.toml | 6 +-- frame/beefy-mmr/Cargo.toml | 6 +-- frame/beefy/Cargo.toml | 6 +-- frame/benchmarking/Cargo.toml | 12 +++--- frame/bounties/Cargo.toml | 6 +-- frame/child-bounties/Cargo.toml | 6 +-- frame/collective/Cargo.toml | 6 +-- frame/contracts/Cargo.toml | 10 ++--- frame/contracts/common/Cargo.toml | 8 ++-- frame/contracts/rpc/Cargo.toml | 8 ++-- frame/contracts/rpc/runtime-api/Cargo.toml | 4 +- frame/conviction-voting/Cargo.toml | 6 +-- frame/democracy/Cargo.toml | 6 +-- .../election-provider-multi-phase/Cargo.toml | 14 +++---- frame/election-provider-support/Cargo.toml | 8 ++-- frame/elections-phragmen/Cargo.toml | 8 ++-- frame/examples/basic/Cargo.toml | 6 +-- frame/examples/offchain-worker/Cargo.toml | 8 ++-- frame/examples/parallel/Cargo.toml | 6 +-- frame/executive/Cargo.toml | 14 +++---- frame/gilt/Cargo.toml | 8 ++-- frame/grandpa/Cargo.toml | 10 ++--- frame/identity/Cargo.toml | 6 +-- frame/im-online/Cargo.toml | 8 ++-- frame/indices/Cargo.toml | 8 ++-- frame/lottery/Cargo.toml | 6 +-- frame/membership/Cargo.toml | 6 +-- frame/merkle-mountain-range/Cargo.toml | 6 +-- .../primitives/Cargo.toml | 4 +- frame/merkle-mountain-range/rpc/Cargo.toml | 4 +- frame/multisig/Cargo.toml | 6 +-- frame/nicks/Cargo.toml | 6 +-- frame/node-authorization/Cargo.toml | 6 +-- frame/offences/Cargo.toml | 6 +-- frame/offences/benchmarking/Cargo.toml | 6 +-- frame/preimage/Cargo.toml | 8 ++-- frame/proxy/Cargo.toml | 6 +-- frame/randomness-collective-flip/Cargo.toml | 6 +-- frame/recovery/Cargo.toml | 6 +-- frame/referenda/Cargo.toml | 6 +-- frame/scheduler/Cargo.toml | 6 +-- frame/scored-pool/Cargo.toml | 6 +-- frame/session/Cargo.toml | 8 ++-- frame/session/benchmarking/Cargo.toml | 6 +-- frame/society/Cargo.toml | 6 +-- frame/staking/Cargo.toml | 10 ++--- frame/staking/reward-curve/Cargo.toml | 2 +- frame/staking/reward-fn/Cargo.toml | 2 +- frame/sudo/Cargo.toml | 6 +-- frame/support/Cargo.toml | 14 +++---- frame/support/test/Cargo.toml | 12 +++--- frame/support/test/compile_pass/Cargo.toml | 6 +-- frame/system/Cargo.toml | 10 ++--- frame/system/benchmarking/Cargo.toml | 6 +-- frame/timestamp/Cargo.toml | 8 ++-- frame/tips/Cargo.toml | 8 ++-- frame/transaction-payment/Cargo.toml | 6 +-- .../asset-tx-payment/Cargo.toml | 8 ++-- frame/transaction-payment/rpc/Cargo.toml | 6 +-- .../rpc/runtime-api/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 6 +-- frame/treasury/Cargo.toml | 6 +-- frame/try-runtime/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 6 +-- frame/utility/Cargo.toml | 8 ++-- frame/vesting/Cargo.toml | 6 +-- primitives/api/Cargo.toml | 8 ++-- primitives/api/test/Cargo.toml | 10 ++--- primitives/application-crypto/Cargo.toml | 6 +-- primitives/application-crypto/test/Cargo.toml | 8 ++-- primitives/arithmetic/Cargo.toml | 3 +- primitives/arithmetic/fuzzer/Cargo.toml | 2 +- primitives/authority-discovery/Cargo.toml | 4 +- primitives/authorship/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 8 ++-- primitives/block-builder/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 4 +- primitives/consensus/aura/Cargo.toml | 4 +- primitives/consensus/babe/Cargo.toml | 8 ++-- primitives/consensus/common/Cargo.toml | 8 ++-- primitives/consensus/pow/Cargo.toml | 4 +- primitives/consensus/slots/Cargo.toml | 4 +- primitives/consensus/vrf/Cargo.toml | 4 +- primitives/core/Cargo.toml | 10 ++--- primitives/core/hashing/proc-macro/Cargo.toml | 2 +- primitives/externalities/Cargo.toml | 4 +- primitives/finality-grandpa/Cargo.toml | 8 ++-- primitives/inherents/Cargo.toml | 4 +- primitives/io/Cargo.toml | 18 ++++----- primitives/keyring/Cargo.toml | 6 +-- primitives/keystore/Cargo.toml | 6 +-- primitives/npos-elections/Cargo.toml | 6 +-- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- .../npos-elections/solution-type/Cargo.toml | 2 +- primitives/offchain/Cargo.toml | 4 +- primitives/rpc/Cargo.toml | 4 +- primitives/runtime-interface/Cargo.toml | 18 ++++----- .../runtime-interface/proc-macro/Cargo.toml | 2 +- .../test-wasm-deprecated/Cargo.toml | 6 +-- .../runtime-interface/test-wasm/Cargo.toml | 6 +-- primitives/runtime-interface/test/Cargo.toml | 8 ++-- primitives/runtime/Cargo.toml | 14 +++---- primitives/sandbox/Cargo.toml | 6 +-- primitives/session/Cargo.toml | 4 +- primitives/staking/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 10 ++--- primitives/storage/Cargo.toml | 2 +- primitives/tasks/Cargo.toml | 8 ++-- primitives/test-primitives/Cargo.toml | 6 +-- primitives/timestamp/Cargo.toml | 2 +- primitives/tracing/Cargo.toml | 2 +- primitives/transaction-pool/Cargo.toml | 2 +- .../transaction-storage-proof/Cargo.toml | 6 +-- primitives/trie/Cargo.toml | 6 +-- primitives/version/Cargo.toml | 6 +-- primitives/version/proc-macro/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 10 ++--- test-utils/runtime/Cargo.toml | 20 +++++----- test-utils/runtime/client/Cargo.toml | 4 +- .../runtime/transaction-pool/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 14 +++---- utils/frame/frame-utilities-cli/Cargo.toml | 4 +- utils/frame/generate-bags/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 8 ++-- utils/frame/rpc/support/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 6 +-- utils/frame/try-runtime/cli/Cargo.toml | 14 +++---- 190 files changed, 667 insertions(+), 666 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2bd91ca7b6b86..59ff43598faed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5735,7 +5735,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" -version = "5.0.0" +version = "6.0.0" dependencies = [ "bitflags", "parity-scale-codec", @@ -9634,7 +9634,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" -version = "5.0.0" +version = "6.0.0" dependencies = [ "parity-scale-codec", "scale-info", @@ -9658,7 +9658,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" -version = "4.0.0" +version = "5.0.0" dependencies = [ "criterion", "integer-sqrt", @@ -9829,7 +9829,7 @@ dependencies = [ [[package]] name = "sp-core" -version = "5.0.0" +version = "6.0.0" dependencies = [ "base58", "bitflags", @@ -9892,7 +9892,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" -version = "4.0.0-dev" +version = "5.0.0" dependencies = [ "proc-macro2", "quote", @@ -9919,7 +9919,7 @@ dependencies = [ [[package]] name = "sp-externalities" -version = "0.11.0" +version = "0.12.0" dependencies = [ "environmental", "parity-scale-codec", @@ -9960,7 +9960,7 @@ dependencies = [ [[package]] name = "sp-io" -version = "5.0.0" +version = "6.0.0" dependencies = [ "futures 0.3.19", "hash-db", @@ -9984,7 +9984,7 @@ dependencies = [ [[package]] name = "sp-keyring" -version = "5.0.0" +version = "6.0.0" dependencies = [ "lazy_static", "sp-core", @@ -9994,7 +9994,7 @@ dependencies = [ [[package]] name = "sp-keystore" -version = "0.11.0" +version = "0.12.0" dependencies = [ "async-trait", "futures 0.3.19", @@ -10082,7 +10082,7 @@ dependencies = [ [[package]] name = "sp-rpc" -version = "5.0.0" +version = "6.0.0" dependencies = [ "rustc-hash", "serde", @@ -10092,7 +10092,7 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "5.0.0" +version = "6.0.0" dependencies = [ "either", "hash256-std-hasher", @@ -10119,7 +10119,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "5.0.0" +version = "6.0.0" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -10141,7 +10141,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" -version = "4.0.0" +version = "5.0.0" dependencies = [ "Inflector", "proc-macro-crate 1.1.0", @@ -10236,7 +10236,7 @@ dependencies = [ [[package]] name = "sp-state-machine" -version = "0.11.0" +version = "0.12.0" dependencies = [ "hash-db", "hex-literal", @@ -10265,7 +10265,7 @@ version = "4.0.0" [[package]] name = "sp-storage" -version = "5.0.0" +version = "6.0.0" dependencies = [ "impl-serde", "parity-scale-codec", @@ -10317,7 +10317,7 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "4.0.0" +version = "5.0.0" dependencies = [ "parity-scale-codec", "sp-std", @@ -10351,7 +10351,7 @@ dependencies = [ [[package]] name = "sp-trie" -version = "5.0.0" +version = "6.0.0" dependencies = [ "criterion", "hash-db", @@ -10370,7 +10370,7 @@ dependencies = [ [[package]] name = "sp-version" -version = "4.0.0-dev" +version = "5.0.0" dependencies = [ "impl-serde", "parity-scale-codec", @@ -10397,7 +10397,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "5.0.0" +version = "6.0.0" dependencies = [ "impl-trait-for-tuples", "log 0.4.14", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index ea14942afee06..98e8af96d3f8d 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -20,7 +20,7 @@ name = "node-template" clap = { version = "3.0", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = ["wasmtime"] } sc-service = { version = "0.10.0-dev", path = "../../../client/service", features = ["wasmtime"] } sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" } @@ -34,7 +34,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo sc-finality-grandpa = { version = "0.10.0-dev", path = "../../../client/finality-grandpa" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } # These dependencies are used for the node template's RPCs diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 62c1c4310884d..ffc02dbd96f65 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -22,9 +22,9 @@ frame-system = { default-features = false, version = "4.0.0-dev", path = "../../ frame-benchmarking = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/benchmarking", optional = true } [dev-dependencies] -sp-core = { default-features = false, version = "5.0.0", path = "../../../../primitives/core" } -sp-io = { default-features = false, version = "5.0.0", path = "../../../../primitives/io" } -sp-runtime = { default-features = false, version = "5.0.0", path = "../../../../primitives/runtime" } +sp-core = { default-features = false, version = "6.0.0", path = "../../../../primitives/core" } +sp-io = { default-features = false, version = "6.0.0", path = "../../../../primitives/io" } +sp-runtime = { default-features = false, version = "6.0.0", path = "../../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 95021227cf4fe..d20a6c39aa5d9 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -30,14 +30,14 @@ frame-executive = { version = "4.0.0-dev", default-features = false, path = "../ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/block-builder"} sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/consensus/aura" } -sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents"} sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } -sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } +sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } # Used for the node template's RPCs frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system/rpc/runtime-api/" } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index c770ca01ecf0b..2c5dea2cc28a6 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -15,20 +15,20 @@ node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } serde = "1.0.136" serde_json = "1.0.74" derive_more = "0.99.16" kvdb = "0.11.0" kvdb-rocksdb = "0.15.1" -sp-trie = { version = "5.0.0", path = "../../../primitives/trie" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-basic-authorship = { version = "0.10.0-dev", path = "../../../client/basic-authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/timestamp" } -sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } hash-db = "0.15.2" tempfile = "3.1.0" fs_extra = "1" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 57bbbdddcb2ec..b4a91712fd16c 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -47,13 +47,13 @@ sp-authority-discovery = { version = "4.0.0-dev", path = "../../../primitives/au sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } grandpa-primitives = { version = "4.0.0-dev", package = "sp-finality-grandpa", path = "../../../primitives/finality-grandpa" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } -sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } +sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../../primitives/transaction-pool" } sp-transaction-storage-proof = { version = "4.0.0-dev", path = "../../../primitives/transaction-storage-proof" } @@ -102,7 +102,7 @@ sc-cli = { version = "0.10.0-dev", optional = true, path = "../../../client/cli" sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service", features = [ "wasmtime", ] } -sp-trie = { version = "5.0.0", default-features = false, path = "../../../primitives/trie", features = [ +sp-trie = { version = "6.0.0", default-features = false, path = "../../../primitives/trie", features = [ "memory-tracker", ] } @@ -114,7 +114,7 @@ sc-consensus-babe = { version = "0.10.0-dev", path = "../../../client/consensus/ sc-consensus-epochs = { version = "0.10.0-dev", path = "../../../client/consensus/epochs" } sc-service-test = { version = "2.0.0", path = "../../../client/service/test" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } -sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } futures = "0.3.19" tempfile = "3.1.0" diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 6bb762319b27b..e29ffd9b671f3 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -17,11 +17,11 @@ scale-info = { version = "2.0.0", features = ["derive"] } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } -sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } -sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } -sp-trie = { version = "5.0.0", path = "../../../primitives/trie" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } +sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } [dev-dependencies] @@ -34,11 +34,11 @@ pallet-contracts = { version = "4.0.0-dev", path = "../../../frame/contracts" } pallet-im-online = { version = "4.0.0-dev", path = "../../../frame/im-online" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } pallet-treasury = { version = "4.0.0-dev", path = "../../../frame/treasury" } -sp-application-crypto = { version = "5.0.0", path = "../../../primitives/application-crypto" } +sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } -sp-externalities = { version = "0.11.0", path = "../../../primitives/externalities" } -sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } +sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } wat = "1.0" futures = "0.3.19" diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index 162d56fc763fd..5e7ed16efdcf4 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -19,5 +19,5 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index f95f767b4a83c..0d49d4a247c07 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -16,9 +16,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../../primitives/application-crypto" } -sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../../primitives/application-crypto" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index c6ba0c9f992d8..95ea3f8174fad 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -29,9 +29,9 @@ sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-frame-rpc-system = { version = "4.0.0-dev", path = "../../../utils/frame/rpc/system" } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 39c4609c4425f..2d2c903f70ca5 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -30,16 +30,16 @@ sp-block-builder = { path = "../../../primitives/block-builder", default-feature sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents" } node-primitives = { version = "2.0.0", default-features = false, path = "../primitives" } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } -sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } -sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } +sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" } -sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } +sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } # frame dependencies @@ -61,7 +61,7 @@ pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../ pallet-child-bounties = { version = "4.0.0-dev", default-features = false, path = "../../../frame/child-bounties" } pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../../../frame/collective" } pallet-contracts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts" } -pallet-contracts-primitives = { version = "5.0.0", default-features = false, path = "../../../frame/contracts/common/" } +pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../../frame/contracts/common/" } pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/rpc/runtime-api/" } pallet-conviction-voting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/conviction-voting" } pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 3c0be4e19c9e0..36a25ab7d4a7a 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -24,13 +24,13 @@ sc-client-db = { version = "0.10.0-dev", path = "../../../client/db/", features sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } codec = { package = "parity-scale-codec", version = "3.0.0" } -sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } +sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../../primitives/io" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = [ "wasmtime", ] } diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index f6af82ba42eb0..9537317198483 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -21,5 +21,5 @@ rand = "0.8" sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } node-cli = { version = "3.0.0-dev", path = "../../node/cli" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index 6f20449b38bc7..8375c39ba4a14 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-wasm-interface = { version = "5.0.0", path = "../../primitives/wasm-interface" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } log = "0.4.11" thiserror = "1.0.30" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index b82309ef6faf1..3d1802c379f04 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-executor = { version = "0.10.0-dev", path = "../executor" } -sp-externalities = { version = "0.11.0", path = "../../primitives/externalities" } +sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } fnv = "1.0.6" futures = "0.3.19" hash-db = { version = "0.15.2", default-features = false } @@ -27,14 +27,14 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } log = "0.4.8" parking_lot = "0.12.0" sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-keystore = { version = "0.11.0", default-features = false, path = "../../primitives/keystore" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-keystore = { version = "0.12.0", default-features = false, path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } -sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } -sp-trie = { version = "5.0.0", path = "../../primitives/trie" } -sp-storage = { version = "5.0.0", path = "../../primitives/storage" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } +sp-trie = { version = "6.0.0", path = "../../primitives/trie" } +sp-storage = { version = "6.0.0", path = "../../primitives/storage" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 197b8cfd1fbb7..d866bafb29dcf 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -32,12 +32,12 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-authority-discovery = { version = "4.0.0-dev", path = "../../primitives/authority-discovery" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } [dev-dependencies] quickcheck = "1.0.3" -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 5791b2b4010fc..4fd140835525e 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -19,8 +19,8 @@ futures-timer = "3.0.1" log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index d126d60b8409b..f23b3f5dc4a64 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -19,12 +19,12 @@ codec = { version = "3.0.0", package = "parity-scale-codec", features = ["derive prometheus = { version = "0.10.0-dev", package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto" } -sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } +sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } +sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } sc-utils = { version = "4.0.0-dev", path = "../utils" } @@ -36,7 +36,7 @@ sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } [dev-dependencies] -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sc-network-test = { version = "0.8.0", path = "../network/test" } strum = { version = "0.23", features = ["derive"] } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 19e1e20c7735b..071b07b6b2294 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -24,8 +24,8 @@ codec = { version = "3.0.0", package = "parity-scale-codec", features = ["derive sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } beefy-gadget = { version = "4.0.0-dev", path = "../." } beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 10c3fbdb9f7fe..fff7740ff8d04 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -14,11 +14,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-builder" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 9e8e3276e760f..68d591254d213 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } impl-trait-for-tuples = "0.2.1" sc-network = { version = "0.10.0-dev", path = "../network" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.74" -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "3.0.0" } memmap2 = "0.5.0" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 47ef9619661c8..813215321dfc0 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -39,12 +39,12 @@ sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-keyring = { version = "5.0.0", path = "../../primitives/keyring" } -sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } -sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } [dev-dependencies] tempfile = "3.1.0" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index b82a71587048a..6f5ff3c221fac 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "5.0.0", path = "../../../primitives/application-crypto" } +sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consensus/aura" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } @@ -26,12 +26,12 @@ thiserror = "1.0" futures = "0.3.19" sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } log = "0.4.8" -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } -sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } async-trait = "0.1.50" @@ -41,8 +41,8 @@ getrandom = { version = "0.2", features = ["js"], optional = true } [dev-dependencies] sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } -sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } +sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index edcf8759f6a7a..a135807d707e0 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -19,15 +19,15 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ ] } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-application-crypto = { version = "5.0.0", path = "../../../primitives/application-crypto" } -sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } num-bigint = "0.2.3" num-rational = "0.2.2" num-traits = "0.2.8" serde = { version = "1.0.136", features = ["derive"] } -sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } -sp-io = { version = "5.0.0", path = "../../../primitives/io" } +sp-version = { version = "5.0.0", path = "../../../primitives/version" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } @@ -40,7 +40,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } sp-consensus-vrf = { version = "0.10.0-dev", path = "../../../primitives/consensus/vrf" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } futures = "0.3.19" @@ -55,7 +55,7 @@ async-trait = "0.1.50" [dev-dependencies] sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 5e9f98d628c71..7db7edd2de133 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -21,20 +21,20 @@ jsonrpc-derive = "18.0.0" sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } serde = { version = "1.0.136", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } -sp-runtime = { version = "5.0.0", path = "../../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } futures = "0.3.19" thiserror = "1.0" sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } -sp-core = { version = "5.0.0", path = "../../../../primitives/core" } -sp-application-crypto = { version = "5.0.0", path = "../../../../primitives/application-crypto" } -sp-keystore = { version = "0.11.0", path = "../../../../primitives/keystore" } +sp-core = { version = "6.0.0", path = "../../../../primitives/core" } +sp-application-crypto = { version = "6.0.0", path = "../../../../primitives/application-crypto" } +sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } [dev-dependencies] sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } serde_json = "1.0.74" -sp-keyring = { version = "5.0.0", path = "../../../../primitives/keyring" } +sp-keyring = { version = "6.0.0", path = "../../../../primitives/keyring" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } tempfile = "3.1.0" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 7677e0569e561..3c640a2363b6a 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -20,10 +20,10 @@ futures = { version = "0.3.19", features = ["thread-pool"] } futures-timer = "3.0.1" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { path = "../../../primitives/core", version = "5.0.0"} +sp-core = { path = "../../../primitives/core", version = "6.0.0"} sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } -sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } parking_lot = "0.12.0" diff --git a/client/consensus/epochs/Cargo.toml b/client/consensus/epochs/Cargo.toml index 2c5a6dfbffe0f..2caf60547cceb 100644 --- a/client/consensus/epochs/Cargo.toml +++ b/client/consensus/epochs/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-client-api = { path = "../../api" , version = "4.0.0-dev"} sc-consensus = { path = "../common" , version = "0.10.0-dev"} diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 6b9404ce34c93..7aaad863af557 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -37,9 +37,9 @@ sp-blockchain = { path = "../../../primitives/blockchain", version = "4.0.0-dev" sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } sp-consensus-slots = { path = "../../../primitives/consensus/slots", version = "0.10.0-dev" } sp-inherents = { path = "../../../primitives/inherents", version = "4.0.0-dev" } -sp-runtime = { path = "../../../primitives/runtime", version = "5.0.0"} -sp-core = { path = "../../../primitives/core", version = "5.0.0"} -sp-keystore = { path = "../../../primitives/keystore", version = "0.11.0"} +sp-runtime = { path = "../../../primitives/runtime", version = "6.0.0"} +sp-core = { path = "../../../primitives/core", version = "6.0.0"} +sp-keystore = { path = "../../../primitives/keystore", version = "0.12.0"} sp-api = { path = "../../../primitives/api", version = "4.0.0-dev" } sc-transaction-pool-api = { path = "../../../client/transaction-pool/api", version = "4.0.0-dev" } sp-timestamp = { path = "../../../primitives/timestamp", version = "4.0.0-dev" } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index cb21a45ebdb04..553ef60e8145c 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -14,9 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 4f4cf4d58bc38..07e0c291f4a37 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-arithmetic = { version = "4.0.0", path = "../../../primitives/arithmetic" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml index 7482fdc12d081..c512eb7e9f832 100644 --- a/client/consensus/uncles/Cargo.toml +++ b/client/consensus/uncles/Cargo.toml @@ -14,6 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } thiserror = "1.0.30" diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index a9fa370a8ead2..32fa9d463413f 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -25,18 +25,18 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ ] } sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } -sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } +sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } -sp-trie = { version = "5.0.0", path = "../../primitives/trie" } +sp-trie = { version = "6.0.0", path = "../../primitives/trie" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } parity-db = { version = "0.3.5", optional = true } [dev-dependencies] -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } quickcheck = "1.0.3" kvdb-rocksdb = "0.15.1" diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 5c62de7671001..96a9c0ba6e399 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -15,23 +15,23 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-tasks = { version = "4.0.0-dev", path = "../../primitives/tasks" } -sp-trie = { version = "5.0.0", path = "../../primitives/trie" } -sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } +sp-trie = { version = "6.0.0", path = "../../primitives/trie" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } wasmi = "0.9.1" lazy_static = "1.4.0" sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-wasm-interface = { version = "5.0.0", path = "../../primitives/wasm-interface" } -sp-runtime-interface = { version = "5.0.0", path = "../../primitives/runtime-interface" } -sp-externalities = { version = "0.11.0", path = "../../primitives/externalities" } +sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } +sp-runtime-interface = { version = "6.0.0", path = "../../primitives/runtime-interface" } +sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } sc-executor-common = { version = "0.10.0-dev", path = "common" } sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } parking_lot = "0.12.0" -sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } +sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } lru = "0.6.6" tracing = "0.1.29" @@ -40,8 +40,8 @@ wat = "1.0" hex-literal = "0.3.4" sc-runtime-test = { version = "2.0.0", path = "runtime-test" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } -sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } tracing-subscriber = "0.2.19" diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 3edaaf12e5b0d..9282fe3b03dd6 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] wasm-instrument = "0.1" codec = { package = "parity-scale-codec", version = "3.0.0" } wasmi = "0.9.1" -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -sp-wasm-interface = { version = "5.0.0", path = "../../../primitives/wasm-interface" } +sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } sp-serializer = { version = "4.0.0-dev", path = "../../../primitives/serializer" } thiserror = "1.0.30" diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index ca1746c842e15..352ffdf7a65c2 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -13,9 +13,9 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io", features = ["improved_panic_error_reporting"] } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io", features = ["improved_panic_error_reporting"] } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 9b25ebcb1174b..cab254f1c71f6 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -19,7 +19,7 @@ wasmi = "0.9.1" codec = { package = "parity-scale-codec", version = "3.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -sp-wasm-interface = { version = "5.0.0", path = "../../../primitives/wasm-interface" } -sp-runtime-interface = { version = "5.0.0", path = "../../../primitives/runtime-interface" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface" } +sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } scoped-tls = "1.0" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 79d5d41087a19..04163c2c4226d 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -19,9 +19,9 @@ log = "0.4.8" parity-wasm = "0.42.0" codec = { package = "parity-scale-codec", version = "3.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } -sp-wasm-interface = { version = "5.0.0", path = "../../../primitives/wasm-interface", features = ["wasmtime"] } -sp-runtime-interface = { version = "5.0.0", path = "../../../primitives/runtime-interface" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface", features = ["wasmtime"] } +sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } wasmtime = { version = "0.33.0", default-features = false, features = [ "cache", @@ -32,5 +32,5 @@ wasmtime = { version = "0.33.0", default-features = false, features = [ [dev-dependencies] sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } -sp-io = { version = "5.0.0", path = "../../../primitives/io" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } wat = "1.0" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 5927a9bef4e62..34feadac5e414 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -24,15 +24,15 @@ parking_lot = "0.12.0" rand = "0.8.4" ahash = "0.7.6" parity-scale-codec = { version = "3.0.0", features = ["derive"] } -sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto" } -sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } +sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } @@ -55,8 +55,8 @@ finality-grandpa = { version = "0.15.0", features = [ ] } sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-test = { version = "0.8.0", path = "../network/test" } -sp-keyring = { version = "5.0.0", path = "../../primitives/keyring" } +sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } tokio = "1.15" tempfile = "3.1.0" diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 8650ee0498539..5e173e1a15fe4 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -12,8 +12,8 @@ readme = "README.md" sc-finality-grandpa = { version = "0.10.0-dev", path = "../" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" @@ -32,7 +32,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ "test-helpers", ] } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } -sp-keyring = { version = "5.0.0", path = "../../../primitives/keyring" } +sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index 7ab057b5f0dc2..dba0555c68969 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -21,5 +21,5 @@ parity-util-mem = { version = "0.11.0", default-features = false, features = ["p sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index f2a06244cde02..09fca2a843a13 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" thiserror = "1.0" -sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } +sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } hex = "0.4.0" parking_lot = "0.12.0" serde_json = "1.0.74" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index d9b52c31f2731..ade44dc94aa81 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -23,7 +23,7 @@ lru = "0.7.0" ahash = "0.7.6" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } tracing = "0.1.29" [dev-dependencies] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 2e5bb3ea0ee5a..0dbdd3ec50e95 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -47,12 +47,12 @@ sc-peerset = { version = "4.0.0-dev", path = "../peerset" } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.74" smallvec = "1.8.0" -sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } thiserror = "1.0" @@ -70,7 +70,7 @@ libp2p = { version = "0.40.0", default-features = false } quickcheck = "1.0.3" rand = "0.7.2" sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } tempfile = "3.1.0" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 4a47365e06412..be15cbc807e22 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -25,12 +25,12 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } -sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } sc-service = { version = "0.10.0-dev", default-features = false, features = ["test-helpers"], path = "../../service" } async-trait = "0.1.50" diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 654633d6ed7f2..e542759b48096 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -25,9 +25,9 @@ rand = "0.7.2" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } threadpool = "1.7" hyper = { version = "0.14.16", features = ["stream", "http2"] } @@ -40,7 +40,7 @@ sc-client-db = { version = "0.10.0-dev", default-features = true, path = "../db" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } tokio = "1.15" diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index cfcadad1361ab..510c59e5b8aac 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -23,12 +23,12 @@ log = "0.4.8" parking_lot = "0.12.0" thiserror = "1.0" -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.74" sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } -sp-rpc = { version = "5.0.0", path = "../../primitives/rpc" } -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 96dfa2c1caa4f..314c49d2f862c 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -20,16 +20,16 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.19" jsonrpc-pubsub = "18.0.0" log = "0.4.8" -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } rpc = { package = "jsonrpc-core", version = "18.0.0" } -sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } serde_json = "1.0.74" sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-rpc = { version = "5.0.0", path = "../../primitives/rpc" } -sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } +sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } @@ -43,7 +43,7 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/a assert_matches = "1.3.0" lazy_static = "1.4.0" sc-network = { version = "0.10.0-dev", path = "../network" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 1747d8e61ea71..84ac9e3de642b 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -36,21 +36,21 @@ hash-db = "0.15.2" serde = "1.0.136" serde_json = "1.0.74" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } -sp-trie = { version = "5.0.0", path = "../../primitives/trie" } -sp-externalities = { version = "0.11.0", path = "../../primitives/externalities" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-trie = { version = "6.0.0", path = "../../primitives/trie" } +sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } -sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } -sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto" } +sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } +sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } -sp-storage = { version = "5.0.0", path = "../../primitives/storage" } +sp-storage = { version = "6.0.0", path = "../../primitives/storage" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } @@ -71,7 +71,7 @@ sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-offchain = { version = "4.0.0-dev", path = "../offchain" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } parity-util-mem = { version = "0.11.0", default-features = false, features = [ diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index ac1fb7ad01598..0b99b9c5aeb9c 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -21,18 +21,18 @@ fdlimit = "0.2.1" parking_lot = "0.12.0" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } -sp-externalities = { version = "0.11.0", path = "../../../primitives/externalities" } -sp-trie = { version = "5.0.0", path = "../../../primitives/trie" } -sp-storage = { version = "5.0.0", path = "../../../primitives/storage" } +sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } +sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } +sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } +sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../../db" } futures = "0.3.19" sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../../service" } sc-network = { version = "0.10.0-dev", path = "../../network" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } @@ -41,4 +41,4 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-executor = { version = "0.10.0-dev", path = "../../executor" } sp-panic-handler = { version = "4.0.0", path = "../../../primitives/panic-handler" } parity-scale-codec = "3.0.0" -sp-tracing = { version = "4.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index bf45ad49043c5..42ef4338b4066 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] parking_lot = "0.12.0" log = "0.4.11" sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } parity-util-mem-derive = "0.1.0" diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 524e9259288a4..e6072267f9638 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -25,5 +25,5 @@ sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } serde_json = "1.0.74" serde = { version = "1.0.136", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 2d892c926eb61..ab7d231e2c17f 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -28,12 +28,12 @@ thiserror = "1.0.30" tracing = "0.1.29" tracing-log = "0.1.2" tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } -sp-rpc = { version = "5.0.0", path = "../../primitives/rpc" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-tracing-proc-macro = { version = "4.0.0-dev", path = "./proc-macro" } sc-rpc-server = { version = "4.0.0-dev", path = "../rpc-servers" } diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index ac5beeac605f6..4c9a341db6a22 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -23,9 +23,9 @@ parking_lot = "0.12.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index eb5f0ed6b0b7f..b444be6c6e788 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -14,5 +14,5 @@ log = "0.4.8" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 02faa20d03f95..b69b53a095eb4 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } # Needed for type-safe access to storage DB. frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } # `system` module provides us with all sorts of useful stuff and macros depend on it being around. @@ -25,9 +25,9 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-std = { version = "4.0.0", path = "../../primitives/std" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 7b737d15d2f59..9be0868760dd7 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -17,10 +17,10 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index 3b1a96f66c464..d6d792886c2f6 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -13,19 +13,19 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-consensus-aura = { version = "0.10.0-dev", path = "../../primitives/consensus/aura", default-features = false } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } [dev-dependencies] -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index 509cea33f6a9b..c44134190e8a7 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authority-discovery" } -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } @@ -23,13 +23,13 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives pallet-session = { version = "4.0.0-dev", features = [ "historical", ], path = "../session", default-features = false } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 379a1ab97b8bc..adeebf0e4b374 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -19,14 +19,14 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } impl-trait-for-tuples = "0.2.1" [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 88be992250c77..d4447ba338554 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -21,11 +21,11 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-consensus-vrf = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/vrf" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -36,7 +36,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } [features] diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 18e2c048186c9..f96048d7fcb80 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } # primitives -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # FRAME @@ -32,14 +32,14 @@ log = { version = "0.4.14", default-features = false } # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking", optional = true, default-features = false } pallet-balances = { version = "4.0.0-dev", path = "../balances", optional = true, default-features = false } -sp-core = { version = "5.0.0", path = "../../primitives/core", optional = true, default-features = false } -sp-io = { version = "5.0.0", path = "../../primitives/io", optional = true, default-features = false } -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing", optional = true, default-features = false } +sp-core = { version = "6.0.0", path = "../../primitives/core", optional = true, default-features = false } +sp-io = { version = "6.0.0", path = "../../primitives/io", optional = true, default-features = false } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing", optional = true, default-features = false } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core"} -sp-io = { version = "5.0.0", path = "../../primitives/io"} -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-core = { version = "6.0.0", path = "../../primitives/core"} +sp-io = { version = "6.0.0", path = "../../primitives/io"} +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support", features = ["runtime-benchmarks"] } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 8f3ce53f8ebb3..e81c4f1a8d4e8 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -21,10 +21,10 @@ frame-system = { path = "../../system", version = "4.0.0-dev" } frame-support = { path = "../../support", version = "4.0.0-dev" } # core -sp-storage = { path = "../../../primitives/storage", version = "5.0.0"} -sp-core = { path = "../../../primitives/core", version = "5.0.0"} -sp-tracing = { path = "../../../primitives/tracing", version = "4.0.0" } -sp-runtime = { path = "../../../primitives/runtime", version = "5.0.0"} +sp-storage = { path = "../../../primitives/storage", version = "6.0.0"} +sp-core = { path = "../../../primitives/core", version = "6.0.0"} +sp-tracing = { path = "../../../primitives/tracing", version = "5.0.0"} +sp-runtime = { path = "../../../primitives/runtime", version = "6.0.0"} sp-std = { path = "../../../primitives/std", version = "4.0.0" } # utils diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index f7e7c662b0209..d0a6f2699ab38 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -16,15 +16,15 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } log = { version = "0.4.14", default-features = false } [dev-dependencies] -sp-io = { version = "5.0.0", path = "../../primitives/io" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } [features] diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index c5aafa94295ee..c6d3b1b165faa 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -21,9 +21,9 @@ pallet-mmr = { version = "4.0.0-dev", path = "../merkle-mountain-range", default pallet-mmr-primitives = { version = "4.0.0-dev", path = "../merkle-mountain-range/primitives", default-features = false } pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } -sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } -sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime", default-features = false } +sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } +sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } beefy-merkle-tree = { version = "4.0.0-dev", path = "./primitives", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index ed5682fdb4742..dc7ef8eda86b1 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -15,7 +15,7 @@ serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime", default-features = false } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } @@ -23,8 +23,8 @@ pallet-session = { version = "4.0.0-dev", path = "../session", default-features beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", default-features = false } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } [features] diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 87089247cc952..37259f351e9f1 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -18,12 +18,12 @@ paste = "1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } -sp-runtime-interface = { version = "5.0.0", path = "../../primitives/runtime-interface", default-features = false } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime", default-features = false } +sp-runtime-interface = { version = "6.0.0", path = "../../primitives/runtime-interface", default-features = false } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } -sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } -sp-application-crypto = { version = "5.0.0", path = "../../primitives/application-crypto", default-features = false } -sp-storage = { version = "5.0.0", path = "../../primitives/storage", default-features = false } +sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } +sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto", default-features = false } +sp-storage = { version = "6.0.0", path = "../../primitives/storage", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } log = { version = "0.4.14", default-features = false } @@ -31,7 +31,7 @@ serde = { version = "1.0.136", optional = true } [dev-dependencies] hex-literal = "0.3.4" -sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } [features] default = ["std"] diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index cc35d54f25e11..7907df2209a4f 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -18,12 +18,12 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } -sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } -sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } +sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } +sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index d912bce112b85..91df3e051f1be 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -18,13 +18,13 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../bounties" } -sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } -sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } +sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } +sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index c679bb21e820c..190f477dd8932 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = log = { version = "0.4.14", default-features = false } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index cf726b76a5f77..ca7b8ec1aa9f3 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -35,11 +35,11 @@ rand_pcg = { version = "0.3", optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-contracts-primitives = { version = "5.0.0", default-features = false, path = "common" } +pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "common" } pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -55,7 +55,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } pallet-randomness-collective-flip = { version = "4.0.0-dev", path = "../randomness-collective-flip" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } -sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } [features] default = ["std"] diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/common/Cargo.toml index d19a160fc45ce..49d7973ab155f 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-contracts-primitives" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -19,10 +19,10 @@ scale-info = { version = "2.0.0", default-features = false, features = ["derive" serde = { version = "1", features = ["derive"], optional = true } # Substrate Dependencies (This crate should not rely on frame) -sp-core = { version = "5.0.0", path = "../../../primitives/core", default-features = false } +sp-core = { version = "6.0.0", path = "../../../primitives/core", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-rpc = { version = "5.0.0", path = "../../../primitives/rpc", optional = true } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc", optional = true } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index 57429fed67220..e506e78a2fbdc 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -20,13 +20,13 @@ jsonrpc-derive = "18.0.0" serde = { version = "1", features = ["derive"] } # Substrate Dependencies -pallet-contracts-primitives = { version = "5.0.0", path = "../common" } +pallet-contracts-primitives = { version = "6.0.0", path = "../common" } pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-rpc = { version = "5.0.0", path = "../../../primitives/rpc" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [dev-dependencies] serde_json = "1" diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml index 071b4bafeef4f..5c95cfacf76b9 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/rpc/runtime-api/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } # Substrate Dependencies -pallet-contracts-primitives = { version = "5.0.0", default-features = false, path = "../../common" } +pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../common" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../../primitives/std" } [features] diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index 7e99302574354..a2d3bde497c45 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -19,15 +19,15 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } assert_matches = "1.3.0" [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index e6fe550f8845a..dddfcd9e1a31d 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -19,14 +19,14 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index e96e9c4464420..ffaad4f46669b 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -23,12 +23,12 @@ log = { version = "0.4.14", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } # Optional imports for benchmarking @@ -42,10 +42,10 @@ strum = { optional = true, default-features = false, version = "0.23.0", feature [dev-dependencies] parking_lot = "0.12.0" rand = { version = "0.7.3" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } frame-election-provider-support = { version = "4.0.0-dev", features = [ ], path = "../election-provider-support" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 0d11a4ac503ea..9364dd5553ef8 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -16,16 +16,16 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index 3312e4863a649..f772a82d73d87 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -17,19 +17,19 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.14", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index c368af4267c39..837244811e4f2 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -21,12 +21,12 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } -sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../../primitives/core", default-features = false } +sp-core = { version = "6.0.0", path = "../../../primitives/core", default-features = false } [features] default = ["std"] diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index bf6acd652b61b..32ca98f505b04 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -20,10 +20,10 @@ scale-info = { version = "2.0.0", default-features = false, features = ["derive" frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } -sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore", optional = true } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore", optional = true } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [features] diff --git a/frame/examples/parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml index ba3c6de5d17a7..2d5a2432e6619 100644 --- a/frame/examples/parallel/Cargo.toml +++ b/frame/examples/parallel/Cargo.toml @@ -17,9 +17,9 @@ scale-info = { version = "2.0.0", default-features = false, features = ["derive" frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index dd37b27d4eb93..5613b42562364 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -19,19 +19,19 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } -sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-tracing = { version = "5.0.0", default-features = false, path = "../../primitives/tracing" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } [dev-dependencies] hex-literal = "0.3.4" -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } -sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } [features] diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index 52b5be3a857be..f47166fb3d084 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -16,15 +16,15 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } -sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-io = { version = "5.0.0", path = "../../primitives/io" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 52f7b02a387b1..ee5fa5e52b8e2 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -15,13 +15,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -33,7 +33,7 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } grandpa = { package = "finality-grandpa", version = "0.15.0", features = ["derive-codec"] } -sp-keyring = { version = "5.0.0", path = "../../primitives/keyring" } +sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 61ac2907a9cdb..7159c71644fbc 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -17,14 +17,14 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } enumflags2 = { version = "0.6.2" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index 119010ef6b049..86d7d9a053414 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -13,14 +13,14 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index 74d84849c37d2..d651bcc15c06e 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-keyring = { version = "5.0.0", optional = true, path = "../../primitives/keyring" } +sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index e43339c1eafa0..ad94b0935ffd2 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -27,8 +27,8 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " [dev-dependencies] frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index abf27710cf600..6f654bfbe858d 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 82c08a3c262f6..c0e1f6702c73b 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -16,9 +16,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, version = "0.3.2" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index fe50ca722200d..3ce2caa7762c0 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -17,8 +17,8 @@ log = { version = "0.4.14", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 6ae0e7a3f076c..7124682c5689a 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -21,8 +21,8 @@ serde = { version = "1.0.136", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index 8251c7bc9c71f..67da75a137f98 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -17,14 +17,14 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 0acdd4b5bb550..fa6dd3395a097 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 63106ec0aa9b4..67c39ca4e3500 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -16,9 +16,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } log = { version = "0.4.14", default-features = false } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index f6a1fe7c190f1..93ece2ae7fd20 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -18,15 +18,15 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } serde = { version = "1.0.136", optional = true } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } log = { version = "0.4.14", default-features = false } [dev-dependencies] -sp-io = { version = "5.0.0", path = "../../primitives/io" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index ebab8114c1bb3..605e0c60a03c2 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -29,7 +29,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, path = "../. pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ "runtime-benchmarks", ], path = "../../staking" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } @@ -37,8 +37,8 @@ frame-election-provider-support = { version = "4.0.0-dev", default-features = fa [dev-dependencies] pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } [features] default = ["std"] diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 9cffedf6c2156..70c5292f7f8cb 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -14,15 +14,15 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-core = { version = "5.0.0", default-features = false, optional = true, path = "../../primitives/core" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "6.0.0", default-features = false, optional = true, path = "../../primitives/core" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } +sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index 8bf0a1469c378..6f1dd15ed6b39 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -17,14 +17,14 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index d6fb14c02d8dd..d05bcd534ec4d 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -16,15 +16,15 @@ targets = ["x86_64-unknown-linux-gnu"] safe-mix = { version = "1.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index a629b0bbf0e32..6bba8102af2ec 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index 56598af91393e..080e4d7ab7782 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -19,15 +19,15 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } assert_matches = { version = "1.5", optional = true } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index c45d961bd694b..f08a0318a7020 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -14,15 +14,15 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } +sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index 934400230f7a3..203c06065c351 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 9bd4d1fc50955..4302c6a44cb01 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -20,12 +20,12 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-trie = { version = "5.0.0", default-features = false, path = "../../primitives/trie", optional = true } +sp-trie = { version = "6.0.0", default-features = false, path = "../../primitives/trie", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 598c3a73e2e3d..23336e647b021 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] rand = { version = "0.7.2", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } @@ -28,8 +28,8 @@ pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } scale-info = "2.0.0" -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index 12fb4202888c8..cd3afdb9beeb2 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } rand_chacha = { version = "0.2", default-features = false } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-io ={ version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io ={ version = "6.0.0", path = "../../primitives/io" } frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 6e85382ddaa24..abe977a70eaa3 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -19,8 +19,8 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -28,7 +28,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, features = [ "historical", ], path = "../session" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } log = { version = "0.4.14", default-features = false } @@ -37,8 +37,8 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " rand_chacha = { version = "0.2", default-features = false, optional = true } [dev-dependencies] -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index 86fdd09076e5d..82167bd8c8ec4 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -21,4 +21,4 @@ proc-macro2 = "1.0.36" proc-macro-crate = "1.1.0" [dev-dependencies] -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/frame/staking/reward-fn/Cargo.toml b/frame/staking/reward-fn/Cargo.toml index 07dc404c8e357..9a768becae830 100644 --- a/frame/staking/reward-fn/Cargo.toml +++ b/frame/staking/reward-fn/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [lib] [dependencies] -sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../../primitives/arithmetic" } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../../primitives/arithmetic" } log = { version = "0.4.14", default-features = false } [features] diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index a4b1d21e9efc8..17d6ef4da489e 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index cd6a082e57cfd..796df7697d746 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -18,23 +18,23 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-metadata = { version = "15.0.0", default-features = false, features = ["v14"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } -sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-tracing = { version = "5.0.0", default-features = false, path = "../../primitives/tracing" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } tt-call = "1.0.8" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } -sp-state-machine = { version = "0.11.0", optional = true, path = "../../primitives/state-machine" } +sp-state-machine = { version = "0.12.0", optional = true, path = "../../primitives/state-machine" } bitflags = "1.3" impl-trait-for-tuples = "0.2.1" smallvec = "1.8.0" log = { version = "0.4.14", default-features = false } -sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } +sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } [dev-dependencies] assert_matches = "1.3.0" diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 56e269b43265e..ef20915899fd1 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -15,14 +15,14 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.136", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../../primitives/arithmetic" } -sp-io = { version = "5.0.0", path = "../../../primitives/io", default-features = false } -sp-state-machine = { version = "0.11.0", optional = true, path = "../../../primitives/state-machine" } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../../primitives/arithmetic" } +sp-io = { version = "6.0.0", path = "../../../primitives/io", default-features = false } +sp-state-machine = { version = "0.12.0", optional = true, path = "../../../primitives/state-machine" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } +sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } trybuild = "1.0.53" pretty_assertions = "1.0.0" rustversion = "1.0.6" diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index 241ec1b352f48..33ee3e8c2d077 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -14,9 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-core = { version = "5.0.0", default-features = false, path = "../../../../primitives/core" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../../primitives/runtime" } -sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../../primitives/core" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-version = { version = "5.0.0", default-features = false, path = "../../../../primitives/version" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index a941f6e95edea..a5a65e403454b 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -16,17 +16,17 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } -sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } +sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-version = { version = "5.0.0", default-features = false, path = "../../primitives/version" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } log = { version = "0.4.14", default-features = false } [dev-dependencies] criterion = "0.3.3" -sp-externalities = { version = "0.11.0", path = "../../primitives/externalities" } +sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 858d6954405fe..7ca76c260c433 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -16,14 +16,14 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } -sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } [dev-dependencies] -sp-io = { version = "5.0.0", path = "../../../primitives/io" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } [features] default = ["std"] diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 8cb78c2164324..1652be9776744 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -18,8 +18,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io", optional = true } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io", optional = true } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -28,8 +28,8 @@ sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../ log = { version = "0.4.14", default-features = false } [dev-dependencies] -sp-io ={ version = "5.0.0", path = "../../primitives/io" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io ={ version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 78e260e2368c7..017d86ea72b37 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -18,9 +18,9 @@ log = { version = "0.4.0", default-features = false } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -30,7 +30,7 @@ pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-storage = { version = "5.0.0", path = "../../primitives/storage" } +sp-storage = { version = "6.0.0", path = "../../primitives/storage" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 0d2388e05bd2f..5ac9ea1e713cc 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -20,9 +20,9 @@ scale-info = { version = "2.0.0", default-features = false, features = ["derive" serde = { version = "1.0.136", optional = true } smallvec = "1.8.0" -sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } -sp-io = { version = "5.0.0", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } +sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index b3471b38045f5..da30136c067ab 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -14,9 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate dependencies -sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } @@ -32,7 +32,7 @@ serde = { version = "1.0.136", optional = true } smallvec = "1.8.0" serde_json = "1.0.74" -sp-storage = { version = "5.0.0", default-features = false, path = "../../../primitives/storage" } +sp-storage = { version = "6.0.0", default-features = false, path = "../../../primitives/storage" } pallet-assets = { version = "4.0.0-dev", path = "../../assets" } pallet-authorship = { version = "4.0.0-dev", path = "../../authorship" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index f5d5036978b44..64d7007dfe6c2 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -20,7 +20,7 @@ jsonrpc-derive = "18.0.0" sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-rpc = { version = "5.0.0", path = "../../../primitives/rpc" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 82bab82a305fa..d057361e1f5f7 100644 --- a/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment" } [features] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index e1275e2476f92..b4ec343dc6216 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -20,16 +20,16 @@ scale-info = { version = "2.0.0", default-features = false, features = ["derive" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-storage-proof" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = true, path = "../../primitives/transaction-storage-proof" } -sp-core = { version = "5.0.0", path = "../../primitives/core", default-features = false } +sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } [features] default = ["std"] diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index bbcffa68f083d..ca32f4713ee2b 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1.0.136", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.1" sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -31,8 +31,8 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ [dev-dependencies] -sp-io = { version = "5.0.0", path = "../../primitives/io" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index 0546c0a898fb2..e40b92b8e98db 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std" , default-features = false } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" , default-features = false } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" , default-features = false } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index e0761711501d2..6f4e8f91b26fe 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } @@ -24,8 +24,8 @@ log = { version = "0.4.14", default-features = false } [dev-dependencies] sp-std = { version = "4.0.0", path = "../../primitives/std" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 6397bf028eedc..f059937ad2d90 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -17,15 +17,15 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 52942c8670a32..36a877478a4e9 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -18,15 +18,15 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } log = { version = "0.4.0", default-features = false } [dev-dependencies] -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index c210201a31158..a0dd8eeb31e7a 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } -sp-version = { version = "4.0.0-dev", default-features = false, path = "../version" } -sp-state-machine = { version = "0.11.0", optional = true, path = "../state-machine" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-version = { version = "5.0.0", default-features = false, path = "../version" } +sp-state-machine = { version = "0.12.0", optional = true, path = "../state-machine" } hash-db = { version = "0.15.2", optional = true } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 9078c69f994ee..786639f393e92 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -14,13 +14,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", path = "../" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -sp-version = { version = "4.0.0-dev", path = "../../version" } -sp-tracing = { version = "4.0.0", path = "../../tracing" } -sp-runtime = { version = "5.0.0", path = "../../runtime" } +sp-version = { version = "5.0.0", path = "../../version" } +sp-tracing = { version = "5.0.0", path = "../../tracing" } +sp-runtime = { version = "6.0.0", path = "../../runtime" } sp-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } codec = { package = "parity-scale-codec", version = "3.0.0" } -sp-state-machine = { version = "0.11.0", path = "../../state-machine" } +sp-state-machine = { version = "0.12.0", path = "../../state-machine" } trybuild = "1.0.53" rustversion = "1.0.6" @@ -28,7 +28,7 @@ rustversion = "1.0.6" criterion = "0.3.0" futures = "0.3.19" log = "0.4.14" -sp-core = { version = "5.0.0", path = "../../core" } +sp-core = { version = "6.0.0", path = "../../core" } [[bench]] name = "bench" diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index 45622d6a53935..7ac487fe35d2f 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-application-crypto" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" description = "Provides facilities for generating application specific crypto wrapper types." @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-io = { version = "5.0.0", default-features = false, path = "../io" } +sp-io = { version = "6.0.0", default-features = false, path = "../io" } [features] default = [ "std" ] diff --git a/primitives/application-crypto/test/Cargo.toml b/primitives/application-crypto/test/Cargo.toml index 515be41be3d2e..9e93e78f69ffb 100644 --- a/primitives/application-crypto/test/Cargo.toml +++ b/primitives/application-crypto/test/Cargo.toml @@ -13,9 +13,9 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "5.0.0", default-features = false, path = "../../core" } -sp-keystore = { version = "0.11.0", path = "../../keystore", default-features = false } +sp-core = { version = "6.0.0", default-features = false, path = "../../core" } +sp-keystore = { version = "0.12.0", path = "../../keystore", default-features = false } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -sp-runtime = { version = "5.0.0", path = "../../runtime" } +sp-runtime = { version = "6.0.0", path = "../../runtime" } sp-api = { version = "4.0.0-dev", path = "../../api" } -sp-application-crypto = { version = "5.0.0", path = "../" } +sp-application-crypto = { version = "6.0.0", path = "../" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 26b0fbcf98d01..654127671466b 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-arithmetic" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -17,6 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", + "max-encoded-len", ] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } integer-sqrt = "0.1.2" diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index d715515056bb7..e51dd4e415a6c 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -14,7 +14,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-arithmetic = { version = "4.0.0", path = ".." } +sp-arithmetic = { version = "5.0.0", path = ".." } honggfuzz = "0.5.49" primitive-types = "0.11.1" num-bigint = "0.2" diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index adbeeb473f2af..687987ab2ec98 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -13,12 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0" } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } [features] default = ["std"] diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index 93b3a43eda173..75e94b895f120 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index b51c5b4948e12..9012803a902db 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -12,15 +12,15 @@ codec = { version = "3.0.0", package = "parity-scale-codec", default-features = scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../api", default-features = false } -sp-application-crypto = { version = "5.0.0", path = "../application-crypto", default-features = false } -sp-core = { version = "5.0.0", path = "../core", default-features = false } -sp-runtime = { version = "5.0.0", path = "../runtime", default-features = false } +sp-application-crypto = { version = "6.0.0", path = "../application-crypto", default-features = false } +sp-core = { version = "6.0.0", path = "../core", default-features = false } +sp-runtime = { version = "6.0.0", path = "../runtime", default-features = false } sp-std = { version = "4.0.0", path = "../std", default-features = false } [dev-dependencies] hex = "0.4.3" hex-literal = "0.3" -sp-keystore = { version = "0.11.0", path = "../keystore" } +sp-keystore = { version = "0.12.0", path = "../keystore" } [features] default = ["std"] diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index 6f0fe32db2fa8..6d7a0a2789c2a 100644 --- a/primitives/block-builder/Cargo.toml +++ b/primitives/block-builder/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 59d0121647c50..bdb326bdb2e9d 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -21,7 +21,7 @@ thiserror = "1.0.30" futures = "0.3.19" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-runtime = { version = "5.0.0", path = "../runtime" } -sp-state-machine = { version = "0.11.0", path = "../state-machine" } +sp-runtime = { version = "6.0.0", path = "../runtime" } +sp-state-machine = { version = "0.12.0", path = "../state-machine" } sp-database = { version = "4.0.0-dev", path = "../database" } sp-api = { version = "4.0.0-dev", path = "../api" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index a51d4aaeabec6..28f68f15cd9ea 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -13,12 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../application-crypto" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../timestamp" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index cf276c998f115..46bb51a061e6b 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../application-crypto" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } merlin = { version = "2.0", default-features = false } @@ -22,10 +22,10 @@ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-consensus = { version = "0.10.0-dev", optional = true, path = "../common" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } sp-consensus-vrf = { version = "0.10.0-dev", path = "../vrf", default-features = false } -sp-core = { version = "5.0.0", default-features = false, path = "../../core" } +sp-core = { version = "6.0.0", default-features = false, path = "../../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } -sp-keystore = { version = "0.11.0", default-features = false, path = "../../keystore", optional = true } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } +sp-keystore = { version = "0.12.0", default-features = false, path = "../../keystore", optional = true } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../timestamp", optional = true } serde = { version = "1.0.136", features = ["derive"], optional = true } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 4d0d17e1288e0..c712eff28500e 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -20,13 +20,13 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ ] } futures = { version = "0.3.19", features = ["thread-pool"] } log = "0.4.8" -sp-core = { path = "../../core", version = "5.0.0"} +sp-core = { path = "../../core", version = "6.0.0"} sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } -sp-state-machine = { version = "0.11.0", path = "../../state-machine" } +sp-state-machine = { version = "0.12.0", path = "../../state-machine" } futures-timer = "3.0.1" sp-std = { version = "4.0.0", path = "../../std" } -sp-version = { version = "4.0.0-dev", path = "../../version" } -sp-runtime = { version = "5.0.0", path = "../../runtime" } +sp-version = { version = "5.0.0", path = "../../version" } +sp-runtime = { version = "6.0.0", path = "../../runtime" } thiserror = "1.0.30" [dev-dependencies] diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index d5c8aa9613b39..eb2db085c482b 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } -sp-core = { version = "5.0.0", default-features = false, path = "../../core" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../core" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } [features] diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index 5c8161ddcbe22..a334b10d6586b 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0", features = ["derive"], optional = true } -sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../arithmetic" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../arithmetic" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../timestamp" } diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index db453f62e8010..80d2d1ddb09d1 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } sp-std = { version = "4.0.0", path = "../../std", default-features = false } -sp-core = { version = "5.0.0", path = "../../core", default-features = false } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../runtime" } +sp-core = { version = "6.0.0", path = "../../core", default-features = false } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } [features] default = ["std"] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index d1a8130579580..70ae11cf543b1 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-core" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -38,8 +38,8 @@ lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.12.0", optional = true } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } -sp-storage = { version = "5.0.0", default-features = false, path = "../storage" } -sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } +sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } +sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } futures = { version = "0.3.19", optional = true } dyn-clonable = { version = "0.9.0", optional = true } @@ -59,7 +59,7 @@ merlin = { version = "2.0", default-features = false, optional = true } secp256k1 = { version = "0.21.2", default-features = false, features = ["recovery", "global-context"], optional = true } ss58-registry = { version = "1.11.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } -sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../runtime-interface" } +sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } [dev-dependencies] sp-serializer = { version = "4.0.0-dev", path = "../serializer" } @@ -67,7 +67,7 @@ hex-literal = "0.3.4" rand = "0.7.2" criterion = "0.3.3" serde_json = "1.0" -sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "./hashing/proc-macro" } +sp-core-hashing-proc-macro = { version = "5.0.0", path = "./hashing/proc-macro" } [[bench]] name = "bench" diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index fea865ab9e101..b3dc155cd8bf3 100644 --- a/primitives/core/hashing/proc-macro/Cargo.toml +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-core-hashing-proc-macro" -version = "4.0.0-dev" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/externalities/Cargo.toml b/primitives/externalities/Cargo.toml index f47f0ba494a71..4fc8619a9ba5c 100644 --- a/primitives/externalities/Cargo.toml +++ b/primitives/externalities/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-externalities" -version = "0.11.0" +version = "0.12.0" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2021" @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-storage = { version = "5.0.0", path = "../storage", default-features = false } +sp-storage = { version = "6.0.0", path = "../storage", default-features = false } sp-std = { version = "4.0.0", path = "../std", default-features = false } environmental = { version = "1.1.3", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index a40873ef4c2f3..671168ef90b8a 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -21,10 +21,10 @@ grandpa = { package = "finality-grandpa", version = "0.15.0", default-features = log = { version = "0.4.8", optional = true } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } -sp-keystore = { version = "0.11.0", default-features = false, path = "../keystore", optional = true } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-keystore = { version = "0.12.0", default-features = false, path = "../keystore", optional = true } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 3bbe3caf5615d..a90fb67e2385a 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "5.0.0", path = "../runtime", optional = true } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "6.0.0", path = "../runtime", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } impl-trait-for-tuples = "0.2.0" diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index b955d4c784dad..c51e34b861b9b 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-io" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -17,16 +17,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } hash-db = { version = "0.15.2", default-features = false } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } -sp-keystore = { version = "0.11.0", default-features = false, optional = true, path = "../keystore" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-keystore = { version = "0.12.0", default-features = false, optional = true, path = "../keystore" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } libsecp256k1 = { version = "0.7", optional = true } -sp-state-machine = { version = "0.11.0", optional = true, path = "../state-machine" } -sp-wasm-interface = { version = "5.0.0", path = "../wasm-interface", default-features = false } -sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../runtime-interface" } -sp-trie = { version = "5.0.0", optional = true, path = "../trie" } -sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } -sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } +sp-state-machine = { version = "0.12.0", optional = true, path = "../state-machine" } +sp-wasm-interface = { version = "6.0.0", path = "../wasm-interface", default-features = false } +sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } +sp-trie = { version = "6.0.0", optional = true, path = "../trie" } +sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } +sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.8", optional = true } futures = { version = "0.3.19", features = ["thread-pool"], optional = true } parking_lot = { version = "0.12.0", optional = true } diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 1e5a234d39095..6186a51fef853 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-keyring" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "5.0.0", path = "../core" } -sp-runtime = { version = "5.0.0", path = "../runtime" } +sp-core = { version = "6.0.0", path = "../core" } +sp-runtime = { version = "6.0.0", path = "../runtime" } lazy_static = "1.4.0" strum = { version = "0.23.0", features = ["derive"] } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 341d2460765b1..7b1d1dd4ebc4b 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-keystore" -version = "0.11.0" +version = "0.12.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -22,8 +22,8 @@ thiserror = "1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } merlin = { version = "2.0", default-features = false } -sp-core = { version = "5.0.0", path = "../core" } -sp-externalities = { version = "0.11.0", path = "../externalities", default-features = false } +sp-core = { version = "6.0.0", path = "../core" } +sp-externalities = { version = "0.12.0", path = "../externalities", default-features = false } [dev-dependencies] rand = "0.7.2" diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 6d70658c27017..b96b386958597 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -18,9 +18,9 @@ scale-info = { version = "2.0.0", default-features = false, features = ["derive" serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } -sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "5.0.0", path = "../runtime", default-features = false } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "6.0.0", path = "../runtime", default-features = false } [dev-dependencies] substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 0c6c44ced7f4e..6ad59d807fa50 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -21,7 +21,7 @@ rand = { version = "0.8", features = ["std", "small_rng"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } -sp-runtime = { version = "5.0.0", path = "../../runtime" } +sp-runtime = { version = "6.0.0", path = "../../runtime" } [[bin]] name = "reduce" diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index 5b45bb246f396..fcd39437945ff 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -23,7 +23,7 @@ proc-macro-crate = "1.1.0" [dev-dependencies] parity-scale-codec = "3.0.0" scale-info = "2.0.0" -sp-arithmetic = { path = "../../arithmetic", version = "4.0.0" } +sp-arithmetic = { path = "../../arithmetic", version = "5.0.0"} # used by generate_solution_type: sp-npos-elections = { path = "..", version = "4.0.0-dev" } trybuild = "1.0.53" diff --git a/primitives/offchain/Cargo.toml b/primitives/offchain/Cargo.toml index a96cd852bf24d..ff647f0e74205 100644 --- a/primitives/offchain/Cargo.toml +++ b/primitives/offchain/Cargo.toml @@ -13,9 +13,9 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } [features] default = ["std"] diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index 240b74baf4747..f2d048ef713e7 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-rpc" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", features = ["derive"] } -sp-core = { version = "5.0.0", path = "../core" } +sp-core = { version = "6.0.0", path = "../core" } rustc-hash = "1.1.0" [dev-dependencies] diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index e227a7b63cded..883ea28e5e887 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime-interface" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -14,22 +14,22 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-wasm-interface = { version = "5.0.0", path = "../wasm-interface", default-features = false } +sp-wasm-interface = { version = "6.0.0", path = "../wasm-interface", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing" } -sp-runtime-interface-proc-macro = { version = "4.0.0", path = "proc-macro" } -sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } +sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } +sp-runtime-interface-proc-macro = { version = "5.0.0", path = "proc-macro" } +sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } static_assertions = "1.0.0" primitive-types = { version = "0.11.1", default-features = false } -sp-storage = { version = "5.0.0", default-features = false, path = "../storage" } +sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } impl-trait-for-tuples = "0.2.1" [dev-dependencies] sp-runtime-interface-test-wasm = { version = "2.0.0", path = "test-wasm" } -sp-state-machine = { version = "0.11.0", path = "../state-machine" } -sp-core = { version = "5.0.0", path = "../core" } -sp-io = { version = "5.0.0", path = "../io" } +sp-state-machine = { version = "0.12.0", path = "../state-machine" } +sp-core = { version = "6.0.0", path = "../core" } +sp-io = { version = "6.0.0", path = "../io" } rustversion = "1.0.6" trybuild = "1.0.53" diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index f69c49843c1da..57e5448348d6c 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime-interface-proc-macro" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 18046626f6508..1b0c9f57e5c44 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -13,10 +13,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../" } +sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../io" } -sp-core = { version = "5.0.0", default-features = false, path = "../../core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../io" } +sp-core = { version = "6.0.0", default-features = false, path = "../../core" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index 9b6bdf39eb4c0..4dfa0fd015d89 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -13,10 +13,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../" } +sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../io" } -sp-core = { version = "5.0.0", default-features = false, path = "../../core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../io" } +sp-core = { version = "6.0.0", default-features = false, path = "../../core" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 107a8fcc7f2a4..3b51088ea3779 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -12,13 +12,13 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "5.0.0", path = "../" } +sp-runtime-interface = { version = "6.0.0", path = "../" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-executor-common = { version = "0.10.0-dev", path = "../../../client/executor/common" } sp-runtime-interface-test-wasm = { version = "2.0.0", path = "../test-wasm" } sp-runtime-interface-test-wasm-deprecated = { version = "2.0.0", path = "../test-wasm-deprecated" } -sp-state-machine = { version = "0.11.0", path = "../../state-machine" } -sp-runtime = { version = "5.0.0", path = "../../runtime" } -sp-io = { version = "5.0.0", path = "../../io" } +sp-state-machine = { version = "0.12.0", path = "../../state-machine" } +sp-runtime = { version = "6.0.0", path = "../../runtime" } +sp-io = { version = "6.0.0", path = "../../io" } tracing = "0.1.29" tracing-core = "0.1.17" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 7c7e74b600531..91bf6d36b0a70 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -18,11 +18,11 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } -sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-io = { version = "5.0.0", default-features = false, path = "../io" } +sp-io = { version = "6.0.0", default-features = false, path = "../io" } log = { version = "0.4.14", default-features = false } paste = "1.0" rand = { version = "0.7.2", optional = true } @@ -34,10 +34,10 @@ either = { version = "1.5", default-features = false } [dev-dependencies] serde_json = "1.0.74" rand = "0.7.2" -sp-state-machine = { version = "0.11.0", path = "../state-machine" } +sp-state-machine = { version = "0.12.0", path = "../state-machine" } sp-api = { version = "4.0.0-dev", path = "../api" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } zstd = "0.9" [features] diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index e04df06f2828e..22d295f313703 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -20,10 +20,10 @@ wasmi = "0.9.0" [dependencies] wasmi = { version = "0.9.0", optional = true } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-io = { version = "5.0.0", default-features = false, path = "../io" } -sp-wasm-interface = { version = "5.0.0", default-features = false, path = "../wasm-interface" } +sp-io = { version = "6.0.0", default-features = false, path = "../io" } +sp-wasm-interface = { version = "6.0.0", default-features = false, path = "../wasm-interface" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4", default-features = false } diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index abc4b60cfc322..9ffaa2cf3bdd1 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" } -sp-runtime = { version = "5.0.0", optional = true, path = "../runtime" } +sp-runtime = { version = "6.0.0", optional = true, path = "../runtime" } [features] default = [ "std" ] diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 408dcb8605962..2cb1ae0938a8b 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 9e0c0c026a23b..2a6ab80133ee6 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-state-machine" -version = "0.11.0" +version = "0.12.0" authors = ["Parity Technologies "] description = "Substrate State Machine" edition = "2021" @@ -20,20 +20,20 @@ parking_lot = { version = "0.12.0", optional = true } hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.23.1", default-features = false } trie-root = { version = "0.17.0", default-features = false } -sp-trie = { version = "5.0.0", path = "../trie", default-features = false } -sp-core = { version = "5.0.0", path = "../core", default-features = false } +sp-trie = { version = "6.0.0", path = "../trie", default-features = false } +sp-core = { version = "6.0.0", path = "../core", default-features = false } sp-panic-handler = { version = "4.0.0", path = "../panic-handler", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } num-traits = { version = "0.2.8", default-features = false } rand = { version = "0.7.2", optional = true } -sp-externalities = { version = "0.11.0", path = "../externalities", default-features = false } +sp-externalities = { version = "0.12.0", path = "../externalities", default-features = false } smallvec = "1.8.0" sp-std = { version = "4.0.0", default-features = false, path = "../std" } tracing = { version = "0.1.29", optional = true } [dev-dependencies] hex-literal = "0.3.4" -sp-runtime = { version = "5.0.0", path = "../runtime" } +sp-runtime = { version = "6.0.0", path = "../runtime" } pretty_assertions = "1.0.0" rand = "0.7.2" diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index f6fe678c370b7..a304bd660cc1e 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-storage" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" description = "Storage related primitives" diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index 3cf4a583d60e9..7f05afeaf0cec 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -15,10 +15,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.8", optional = true } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } -sp-externalities = { version = "0.11.0", optional = true, path = "../externalities" } -sp-io = { version = "5.0.0", default-features = false, path = "../io" } -sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../runtime-interface" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } +sp-io = { version = "6.0.0", default-features = false, path = "../io" } +sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 2c13f0f8d64f0..0d491ea217c6c 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -12,11 +12,11 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../application-crypto" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } serde = { version = "1.0.136", optional = true, features = ["derive"] } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } [features] diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index ec112ac5916f4..176a4db5cb45b 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index 3c3149a8b4713..3f53cc2e6c5c6 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-tracing" -version = "4.0.0" +version = "5.0.0" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2021" diff --git a/primitives/transaction-pool/Cargo.toml b/primitives/transaction-pool/Cargo.toml index c8f70bdce9de2..544b149ce3a48 100644 --- a/primitives/transaction-pool/Cargo.toml +++ b/primitives/transaction-pool/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } [features] default = [ "std" ] diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index ca285323f2923..803ec67f571c6 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-trie = { version = "5.0.0", optional = true, path = "../trie" } -sp-core = { version = "5.0.0", path = "../core", optional = true } +sp-trie = { version = "6.0.0", optional = true, path = "../trie" } +sp-core = { version = "6.0.0", path = "../core", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.8", optional = true } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 022dd606ba110..240c93233bfdb 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-trie" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] description = "Patricia trie stuff using a parity-scale-codec node format" repository = "https://github.com/paritytech/substrate/" @@ -25,14 +25,14 @@ hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.23.1", default-features = false } trie-root = { version = "0.17.0", default-features = false } memory-db = { version = "0.29.0", default-features = false } -sp-core = { version = "5.0.0", default-features = false, path = "../core" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } [dev-dependencies] trie-bench = "0.30.0" trie-standardmap = "0.15.2" criterion = "0.3.3" hex-literal = "0.3.4" -sp-runtime = { version = "5.0.0", path = "../runtime" } +sp-runtime = { version = "6.0.0", path = "../runtime" } [features] default = ["std"] diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 590bf081eb060..8518dfffa5dba 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-version" -version = "4.0.0-dev" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -19,10 +19,10 @@ serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" } parity-wasm = { version = "0.42.2", optional = true } -sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../core/hashing/proc-macro" } +sp-core-hashing-proc-macro = { version = "5.0.0", path = "../core/hashing/proc-macro" } thiserror = { version = "1.0.30", optional = true } [features] diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index c8f59f4fca257..e54012a516f2a 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -22,4 +22,4 @@ proc-macro2 = "1.0.36" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } [dev-dependencies] -sp-version = { version = "4.0.0-dev", path = ".." } +sp-version = { version = "5.0.0", path = ".." } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index acf22f189b87b..fa6c5ede18546 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-wasm-interface" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 6deaddd9068f4..f3299d800a6f7 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -29,9 +29,9 @@ sc-service = { version = "0.10.0-dev", default-features = false, features = [ ], path = "../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-core = { version = "5.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } -sp-keyring = { version = "5.0.0", path = "../../primitives/keyring" } -sp-runtime = { version = "5.0.0", path = "../../primitives/runtime" } -sp-state-machine = { version = "0.11.0", path = "../../primitives/state-machine" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } async-trait = "0.1.50" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 79d43bea8520c..9bf66a64db421 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -13,37 +13,37 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "5.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } -sp-keyring = { version = "5.0.0", optional = true, path = "../../primitives/keyring" } +sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } memory-db = { version = "0.29.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } -sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../../primitives/runtime-interface" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../../primitives/runtime-interface" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../frame/support" } -sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } +sp-version = { version = "5.0.0", default-features = false, path = "../../primitives/version" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../frame/babe" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../frame/system" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../frame/system/rpc/runtime-api" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../frame/timestamp" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } -sp-trie = { version = "5.0.0", default-features = false, path = "../../primitives/trie" } +sp-trie = { version = "6.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } trie-db = { version = "0.23.1", default-features = false } parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } -sp-state-machine = { version = "0.11.0", default-features = false, path = "../../primitives/state-machine" } -sp-externalities = { version = "0.11.0", default-features = false, path = "../../primitives/externalities" } +sp-state-machine = { version = "0.12.0", default-features = false, path = "../../primitives/state-machine" } +sp-externalities = { version = "0.12.0", default-features = false, path = "../../primitives/externalities" } # 3rd party cfg-if = "1.0" diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index 552a0581d79e0..642d754868f7d 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -16,9 +16,9 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } substrate-test-client = { version = "2.0.0", path = "../../client" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } substrate-test-runtime = { version = "2.0.0", path = "../../runtime" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index b936e6d9cb357..8bc75c9d4c053 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -16,7 +16,7 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../client" } parking_lot = "0.12.0" codec = { package = "parity-scale-codec", version = "3.0.0" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } futures = "0.3.19" diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index dc6c5eb221652..20122c4279366 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } @@ -23,15 +23,15 @@ sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-externalities = { version = "0.11.0", path = "../../../primitives/externalities" } +sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } sp-database = { version = "4.0.0-dev", path = "../../../primitives/database" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-keystore = { version = "0.11.0", path = "../../../primitives/keystore" } -sp-storage = { version = "5.0.0", path = "../../../primitives/storage" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } +sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-state-machine = { version = "0.11.0", path = "../../../primitives/state-machine" } -sp-trie = { version = "5.0.0", path = "../../../primitives/trie" } +sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } +sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } codec = { version = "3.0.0", package = "parity-scale-codec" } clap = { version = "3.0", features = ["derive"] } chrono = "0.4" diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index 50a00db1d4d38..bc673105b78bf 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -13,9 +13,9 @@ readme = "README.md" [dependencies] clap = { version = "3.0", features = ["derive"] } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 5bda705a581a9..7c7fdea056b22 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -17,7 +17,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-staking = { version = "4.0.0-dev", path = "../../../frame/staking" } # primitives -sp-io = { version = "5.0.0", path = "../../../primitives/io" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } # third party chrono = { version = "0.4.19" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index ec05b7133412a..d5042444119dc 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -22,10 +22,10 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } serde_json = "1.0" serde = "1.0.136" -sp-io = { version = "5.0.0", path = "../../../primitives/io" } -sp-core = { version = "5.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "5.0.0", path = "../../../primitives/runtime" } -sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-version = { version = "5.0.0", path = "../../../primitives/version" } [dev-dependencies] tokio = { version = "1.15", features = ["macros", "rt-multi-thread"] } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 645e33f4b21a1..f1cf00153f3b2 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -20,7 +20,7 @@ jsonrpc-client-transports = { version = "18.0.0", features = ["http"] } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } -sp-storage = { version = "5.0.0", path = "../../../../primitives/storage" } +sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } [dev-dependencies] diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 79794d779252c..1015760efee6f 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -20,10 +20,10 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" log = "0.4.8" -sp-runtime = { version = "5.0.0", path = "../../../../primitives/runtime" } +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } -sp-core = { version = "5.0.0", path = "../../../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../../client/transaction-pool/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../../primitives/block-builder" } @@ -31,5 +31,5 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } -sp-tracing = { version = "4.0.0", path = "../../../../primitives/tracing" } +sp-tracing = { version = "5.0.0", path = "../../../../primitives/tracing" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../../client/transaction-pool" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 27129f38acc7a..04b6d336f7406 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -23,13 +23,13 @@ sc-service = { version = "0.10.0-dev", default-features = false, path = "../../. sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } -sp-state-machine = { version = "0.11.0", path = "../../../../primitives/state-machine" } -sp-runtime = { version = "5.0.0", path = "../../../../primitives/runtime" } -sp-core = { version = "5.0.0", path = "../../../../primitives/core" } -sp-io = { version = "5.0.0", path = "../../../../primitives/io" } -sp-keystore = { version = "0.11.0", path = "../../../../primitives/keystore" } -sp-externalities = { version = "0.11.0", path = "../../../../primitives/externalities" } -sp-version = { version = "4.0.0-dev", path = "../../../../primitives/version" } +sp-state-machine = { version = "0.12.0", path = "../../../../primitives/state-machine" } +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +sp-core = { version = "6.0.0", path = "../../../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../../../primitives/io" } +sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } +sp-externalities = { version = "0.12.0", path = "../../../../primitives/externalities" } +sp-version = { version = "5.0.0", path = "../../../../primitives/version" } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } jsonrpsee = { version = "0.4.1", default-features = false, features = ["ws-client"] } From e75de5f0ed73e87f626d69d1479f3abee1aa6892 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 1 Mar 2022 14:41:07 +0000 Subject: [PATCH 0561/1472] Update new whitelist pallet to new primitive versions (#10953) --- frame/whitelist/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/whitelist/Cargo.toml b/frame/whitelist/Cargo.toml index 057e7fd71f307..6bc43ff961781 100644 --- a/frame/whitelist/Cargo.toml +++ b/frame/whitelist/Cargo.toml @@ -17,14 +17,14 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "5.0.0", path = "../../primitives/core" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-preimage = { version = "4.0.0-dev", path = "../preimage/" } pallet-balances = { version = "4.0.0-dev", path = "../balances/" } From 0063f74287d29ff347121fcd23a00f1d8b1e4a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 1 Mar 2022 23:33:47 +0100 Subject: [PATCH 0562/1472] sp-trie: Switch to thiserror and some other small cleanups (#10954) * sp-trie: Switch to thiserror and some other small cleanups * Add some extra method for converting a compact proof to a memory db --- Cargo.lock | 1 + primitives/trie/Cargo.toml | 2 + primitives/trie/src/error.rs | 34 ++--------- primitives/trie/src/node_codec.rs | 10 ++-- primitives/trie/src/storage_proof.rs | 68 +++++++++++++--------- primitives/trie/src/trie_codec.rs | 85 +++++++--------------------- 6 files changed, 74 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59ff43598faed..5c1b6ed88fb4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10362,6 +10362,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-std", + "thiserror", "trie-bench", "trie-db", "trie-root", diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 240c93233bfdb..dfe3150194a3e 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -26,6 +26,7 @@ trie-db = { version = "0.23.1", default-features = false } trie-root = { version = "0.17.0", default-features = false } memory-db = { version = "0.29.0", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../core" } +thiserror = { version = "1.0.30", optional = true } [dev-dependencies] trie-bench = "0.30.0" @@ -45,5 +46,6 @@ std = [ "trie-db/std", "trie-root/std", "sp-core/std", + "thiserror", ] memory-tracker = [] diff --git a/primitives/trie/src/error.rs b/primitives/trie/src/error.rs index b43412ebc7dc4..e0b3642b6db76 100644 --- a/primitives/trie/src/error.rs +++ b/primitives/trie/src/error.rs @@ -15,18 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(feature = "std")] -use std::error::Error as StdError; -#[cfg(feature = "std")] -use std::fmt; - -#[derive(Debug, PartialEq, Eq, Clone)] /// Error for trie node decoding. +#[derive(Debug, PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(thiserror::Error))] pub enum Error { - /// Bad format. + #[cfg_attr(feature = "std", error("Bad format"))] BadFormat, - /// Decoding error. - Decode(codec::Error), + #[cfg_attr(feature = "std", error("Decoding failed: {0}"))] + Decode(#[cfg_attr(feature = "std", source)] codec::Error), } impl From for Error { @@ -34,23 +30,3 @@ impl From for Error { Error::Decode(x) } } - -#[cfg(feature = "std")] -impl StdError for Error { - fn description(&self) -> &str { - match self { - Error::BadFormat => "Bad format error", - Error::Decode(_) => "Decoding error", - } - } -} - -#[cfg(feature = "std")] -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::Decode(e) => write!(f, "Decode error: {}", e), - Error::BadFormat => write!(f, "Bad format"), - } - } -} diff --git a/primitives/trie/src/node_codec.rs b/primitives/trie/src/node_codec.rs index 4aaed2ec7e4ee..bd0ba27483e66 100644 --- a/primitives/trie/src/node_codec.rs +++ b/primitives/trie/src/node_codec.rs @@ -23,7 +23,7 @@ use codec::{Compact, Decode, Encode, Input}; use hash_db::Hasher; use sp_std::{borrow::Borrow, marker::PhantomData, ops::Range, vec::Vec}; use trie_db::{ - self, nibble_ops, + nibble_ops, node::{NibbleSlicePlan, NodeHandlePlan, NodePlan, Value, ValuePlan}, ChildReference, NodeCodec as NodeCodecT, Partial, }; @@ -54,9 +54,7 @@ impl<'a> ByteSliceInput<'a> { impl<'a> Input for ByteSliceInput<'a> { fn remaining_len(&mut self) -> Result, codec::Error> { - let remaining = - if self.offset <= self.data.len() { Some(self.data.len() - self.offset) } else { None }; - Ok(remaining) + Ok(Some(self.data.len().saturating_sub(self.offset))) } fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> { @@ -76,7 +74,9 @@ impl<'a> Input for ByteSliceInput<'a> { } } -/// Concrete implementation of a `NodeCodec` with Parity Codec encoding, generic over the `Hasher` +/// Concrete implementation of a [`NodeCodecT`] with SCALE encoding. +/// +/// It is generic over `H` the [`Hasher`]. #[derive(Default, Clone)] pub struct NodeCodec(PhantomData); diff --git a/primitives/trie/src/storage_proof.rs b/primitives/trie/src/storage_proof.rs index 8caae06d390ce..79da009ae151d 100644 --- a/primitives/trie/src/storage_proof.rs +++ b/primitives/trie/src/storage_proof.rs @@ -35,12 +35,6 @@ pub struct StorageProof { trie_nodes: Vec>, } -/// Storage proof in compact form. -#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] -pub struct CompactProof { - pub encoded_nodes: Vec>, -} - impl StorageProof { /// Constructs a storage proof from a subset of encoded trie nodes in a storage backend. pub fn new(trie_nodes: Vec>) -> Self { @@ -71,7 +65,7 @@ impl StorageProof { self.trie_nodes } - /// Creates a `MemoryDB` from `Self`. + /// Creates a [`MemoryDB`](crate::MemoryDB) from `Self`. pub fn into_memory_db(self) -> crate::MemoryDB { self.into() } @@ -79,10 +73,7 @@ impl StorageProof { /// Merges multiple storage proofs covering potentially different sets of keys into one proof /// covering all keys. The merged proof output may be smaller than the aggregate size of the /// input proofs due to deduplication of trie nodes. - pub fn merge(proofs: I) -> Self - where - I: IntoIterator, - { + pub fn merge(proofs: impl IntoIterator) -> Self { let trie_nodes = proofs .into_iter() .flat_map(|proof| proof.iter_nodes()) @@ -93,12 +84,11 @@ impl StorageProof { Self { trie_nodes } } - /// Encode as a compact proof with default - /// trie layout. + /// Encode as a compact proof with default trie layout. pub fn into_compact_proof( self, root: H::Out, - ) -> Result>> { + ) -> Result> { crate::encode_compact::>(self, root) } @@ -114,6 +104,22 @@ impl StorageProof { } } +impl From for crate::MemoryDB { + fn from(proof: StorageProof) -> Self { + let mut db = crate::MemoryDB::default(); + proof.iter_nodes().for_each(|n| { + db.insert(crate::EMPTY_PREFIX, &n); + }); + db + } +} + +/// Storage proof in compact form. +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] +pub struct CompactProof { + pub encoded_nodes: Vec>, +} + impl CompactProof { /// Return an iterator on the compact encoded nodes. pub fn iter_compact_encoded_nodes(&self) -> impl Iterator { @@ -121,13 +127,10 @@ impl CompactProof { } /// Decode to a full storage_proof. - /// - /// Method use a temporary `HashDB`, and `sp_trie::decode_compact` - /// is often better. pub fn to_storage_proof( &self, expected_root: Option<&H::Out>, - ) -> Result<(StorageProof, H::Out), crate::CompactProofError>> { + ) -> Result<(StorageProof, H::Out), crate::CompactProofError> { let mut db = crate::MemoryDB::::new(&[]); let root = crate::decode_compact::, _, _>( &mut db, @@ -144,6 +147,25 @@ impl CompactProof { root, )) } + + /// Convert self into a [`MemoryDB`](crate::MemoryDB). + /// + /// `expected_root` is the expected root of this compact proof. + /// + /// Returns the memory db and the root of the trie. + pub fn to_memory_db( + &self, + expected_root: Option<&H::Out>, + ) -> Result<(crate::MemoryDB, H::Out), crate::CompactProofError> { + let mut db = crate::MemoryDB::::new(&[]); + let root = crate::decode_compact::, _, _>( + &mut db, + self.iter_compact_encoded_nodes(), + expected_root, + )?; + + Ok((db, root)) + } } /// An iterator over trie nodes constructed from a storage proof. The nodes are not guaranteed to @@ -165,13 +187,3 @@ impl Iterator for StorageProofNodeIterator { self.inner.next() } } - -impl From for crate::MemoryDB { - fn from(proof: StorageProof) -> Self { - let mut db = crate::MemoryDB::default(); - for item in proof.iter_nodes() { - db.insert(crate::EMPTY_PREFIX, &item); - } - db - } -} diff --git a/primitives/trie/src/trie_codec.rs b/primitives/trie/src/trie_codec.rs index 62edc82e4c547..a7f292271565f 100644 --- a/primitives/trie/src/trie_codec.rs +++ b/primitives/trie/src/trie_codec.rs @@ -20,80 +20,34 @@ //! This uses compact proof from trie crate and extends //! it to substrate specific layout and child trie system. -use crate::{ - CompactProof, HashDBT, StorageProof, TrieConfiguration, TrieError, TrieHash, EMPTY_PREFIX, -}; +use crate::{CompactProof, HashDBT, StorageProof, TrieConfiguration, TrieHash, EMPTY_PREFIX}; use sp_std::{boxed::Box, vec::Vec}; -#[cfg(feature = "std")] -use std::error::Error as StdError; -#[cfg(feature = "std")] -use std::fmt; -use trie_db::Trie; +use trie_db::{CError, Trie}; /// Error for trie node decoding. -pub enum Error { - /// Verification failed due to root mismatch. - RootMismatch(TrieHash, TrieHash), - /// Missing nodes in proof. +#[derive(Debug)] +#[cfg_attr(feature = "std", derive(thiserror::Error))] +pub enum Error { + #[cfg_attr(feature = "std", error("Invalid root {0:x?}, expected {1:x?}"))] + RootMismatch(H, H), + #[cfg_attr(feature = "std", error("Missing nodes in the proof"))] IncompleteProof, - /// Compact node is not needed. + #[cfg_attr(feature = "std", error("Child node content with no root in proof"))] ExtraneousChildNode, - /// Child content with root not in proof. - ExtraneousChildProof(TrieHash), - /// Bad child trie root. + #[cfg_attr(feature = "std", error("Proof of child trie {0:x?} not in parent proof"))] + ExtraneousChildProof(H), + #[cfg_attr(feature = "std", error("Invalid root {0:x?}, expected {1:x?}"))] InvalidChildRoot(Vec, Vec), - /// Errors from trie crate. - TrieError(Box>), + #[cfg_attr(feature = "std", error("Trie error: {0:?}"))] + TrieError(Box>), } -impl From>> for Error { - fn from(error: Box>) -> Self { +impl From>> for Error { + fn from(error: Box>) -> Self { Error::TrieError(error) } } -#[cfg(feature = "std")] -impl StdError for Error { - fn description(&self) -> &str { - match self { - Error::InvalidChildRoot(..) => "Invalid child root error", - Error::TrieError(..) => "Trie db error", - Error::RootMismatch(..) => "Trie db error", - Error::IncompleteProof => "Incomplete proof", - Error::ExtraneousChildNode => "Extraneous child node", - Error::ExtraneousChildProof(..) => "Extraneous child proof", - } - } -} - -#[cfg(feature = "std")] -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ::fmt(&self, f) - } -} - -#[cfg(feature = "std")] -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::InvalidChildRoot(k, v) => write!(f, "InvalidChildRoot at {:x?}: {:x?}", k, v), - Error::TrieError(e) => write!(f, "Trie error: {}", e), - Error::IncompleteProof => write!(f, "Incomplete proof"), - Error::ExtraneousChildNode => write!(f, "Child node content with no root in proof"), - Error::ExtraneousChildProof(root) => { - write!(f, "Proof of child trie {:x?} not in parent proof", root.as_ref()) - }, - Error::RootMismatch(root, expected) => write!( - f, - "Verification error, root is {:x?}, expected: {:x?}", - root.as_ref(), - expected.as_ref(), - ), - } - } -} - /// Decode a compact proof. /// /// Takes as input a destination `db` for decoded node and `encoded` @@ -105,7 +59,7 @@ pub fn decode_compact<'a, L, DB, I>( db: &mut DB, encoded: I, expected_root: Option<&TrieHash>, -) -> Result, Error> +) -> Result, Error, CError>> where L: TrieConfiguration, DB: HashDBT + hash_db::HashDBRef, @@ -195,7 +149,10 @@ where /// Then parse all child trie root and compress main trie content first /// then all child trie contents. /// Child trie are ordered by the order of their roots in the top trie. -pub fn encode_compact(proof: StorageProof, root: TrieHash) -> Result> +pub fn encode_compact( + proof: StorageProof, + root: TrieHash, +) -> Result, CError>> where L: TrieConfiguration, { From c6aa3209d6277b853f5eb15d74fb9812024ef23c Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Tue, 1 Mar 2022 15:31:13 -0800 Subject: [PATCH 0563/1472] Only maintain at most 1 `UnlockChunk` per era (#10670) * Only maintain at most 1 `UnlockChunk` per era * Bound `unlocking` * Run cargo +nightly-2021-10-29 fmt * Make benchmarks stuff compile * Update frame/staking/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Remove DerefMut; Implement neccesary methods directly * Doc comments for new BoundedVec methods * Fix benchmarks * wip bonded_vec macro * Correct rust doc * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update staking::Config impls * Add MaxUnlockingChunks to more places * Use defensive saturating add * FMT Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- bin/node/runtime/src/lib.rs | 1 + frame/babe/src/mock.rs | 1 + frame/grandpa/src/mock.rs | 1 + frame/offences/benchmarking/src/mock.rs | 1 + frame/session/benchmarking/src/mock.rs | 1 + frame/staking/src/benchmarking.rs | 10 +- frame/staking/src/lib.rs | 22 +++- frame/staking/src/mock.rs | 1 + frame/staking/src/pallet/impls.rs | 8 +- frame/staking/src/pallet/mod.rs | 40 +++++-- frame/staking/src/tests.rs | 141 ++++++++++++----------- frame/support/src/storage/bounded_vec.rs | 15 ++- 12 files changed, 147 insertions(+), 95 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 9ff19760c775f..0b0c033ae851d 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -558,6 +558,7 @@ impl pallet_staking::Config for Runtime { // Alternatively, use pallet_staking::UseNominatorsMap to just use the nominators map. // Note that the aforementioned does not scale to a very large number of nominators. type SortedListProvider = BagsList; + type MaxUnlockingChunks = ConstU32<32>; type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; } diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 2e4b6023f1e5f..152ec5ab206e7 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -198,6 +198,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; + type MaxUnlockingChunks = ConstU32<32>; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index d07f3136d9a0d..9dac33f979841 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -206,6 +206,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; + type MaxUnlockingChunks = ConstU32<32>; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 3b5e640867c5a..22c9af0f4c3cd 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -176,6 +176,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; + type MaxUnlockingChunks = ConstU32<32>; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 37305437ca095..a9328b6546c91 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -181,6 +181,7 @@ impl pallet_staking::Config for Test { type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; + type MaxUnlockingChunks = ConstU32<32>; type SortedListProvider = pallet_staking::UseNominatorsMap; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 65a1ee92e2eab..7593522055fba 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -618,7 +618,7 @@ benchmarks! { } rebond { - let l in 1 .. MAX_UNLOCKING_CHUNKS as u32; + let l in 1 .. MaxUnlockingChunks::get() as u32; // clean up any existing state. clear_validators_and_nominators::(); @@ -652,7 +652,7 @@ benchmarks! { let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); for _ in 0 .. l { - staking_ledger.unlocking.push(unlock_chunk.clone()) + staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap() } Ledger::::insert(controller.clone(), staking_ledger.clone()); let original_bonded: BalanceOf = staking_ledger.active; @@ -702,7 +702,7 @@ benchmarks! { stash: stash.clone(), active: T::Currency::minimum_balance() - One::one(), total: T::Currency::minimum_balance() - One::one(), - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }; Ledger::::insert(&controller, l); @@ -788,7 +788,7 @@ benchmarks! { #[extra] do_slash { - let l in 1 .. MAX_UNLOCKING_CHUNKS as u32; + let l in 1 .. MaxUnlockingChunks::get() as u32; let (stash, controller) = create_stash_controller::(0, 100, Default::default())?; let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); let unlock_chunk = UnlockChunk::> { @@ -796,7 +796,7 @@ benchmarks! { era: EraIndex::zero(), }; for _ in 0 .. l { - staking_ledger.unlocking.push(unlock_chunk.clone()) + staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap(); } Ledger::::insert(controller, staking_ledger); let slash_amount = T::Currency::minimum_balance() * 10u32.into(); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 22143ff1ee03f..d833ac86fe0bd 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -301,6 +301,7 @@ mod pallet; use codec::{Decode, Encode, HasCompact}; use frame_support::{ + parameter_types, traits::{ConstU32, Currency, Get}, weights::Weight, BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, @@ -347,6 +348,10 @@ type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; +parameter_types! { + pub MaxUnlockingChunks: u32 = 32; +} + /// Information regarding the active era (era in used in session). #[derive(Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ActiveEraInfo { @@ -446,9 +451,10 @@ pub struct StakingLedger { /// rounds. #[codec(compact)] pub active: Balance, - /// Any balance that is becoming free, which may eventually be transferred out - /// of the stash (assuming it doesn't get slashed first). - pub unlocking: Vec>, + /// Any balance that is becoming free, which may eventually be transferred out of the stash + /// (assuming it doesn't get slashed first). It is assumed that this will be treated as a first + /// in, first out queue where the new (higher value) eras get pushed on the back. + pub unlocking: BoundedVec, MaxUnlockingChunks>, /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. pub claimed_rewards: Vec, @@ -463,7 +469,7 @@ impl Self { let mut total = self.total; - let unlocking = self + let unlocking: BoundedVec<_, _> = self .unlocking .into_iter() .filter(|chunk| { @@ -483,7 +489,11 @@ impl>() + .try_into() + .expect( + "filtering items from a bounded vec always leaves length less than bounds. qed", + ); Self { stash: self.stash, diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 95f305dfdd22a..12d3804b4e303 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -271,6 +271,7 @@ impl crate::pallet::pallet::Config for Test { type GenesisElectionProvider = Self::ElectionProvider; // NOTE: consider a macro and use `UseNominatorsMap` as well. type SortedListProvider = BagsList; + type MaxUnlockingChunks = ConstU32<32>; type BenchmarkingConfig = TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index ae20550cd40b6..5cd0d0107f015 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -928,7 +928,7 @@ impl ElectionDataProvider for Pallet { stash: voter.clone(), active: stake, total: stake, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }, ); @@ -946,7 +946,7 @@ impl ElectionDataProvider for Pallet { stash: target.clone(), active: stake, total: stake, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }, ); @@ -983,7 +983,7 @@ impl ElectionDataProvider for Pallet { stash: v.clone(), active: stake, total: stake, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }, ); @@ -1004,7 +1004,7 @@ impl ElectionDataProvider for Pallet { stash: v.clone(), active: stake, total: stake, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }, ); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index f53e6b50d7a39..9d3b438daebb4 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -21,8 +21,8 @@ use frame_election_provider_support::SortedListProvider; use frame_support::{ pallet_prelude::*, traits::{ - Currency, CurrencyToVote, EnsureOrigin, EstimateNextNewSession, Get, LockIdentifier, - LockableCurrency, OnUnbalanced, UnixTime, + Currency, CurrencyToVote, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, + LockIdentifier, LockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, }; @@ -40,12 +40,11 @@ pub use impls::*; use crate::{ log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints, - Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, Releases, - RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, + Exposure, Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, + Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, }; -pub const MAX_UNLOCKING_CHUNKS: usize = 32; const STAKING_ID: LockIdentifier = *b"staking "; #[frame_support::pallet] @@ -157,6 +156,10 @@ pub mod pallet { /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. type SortedListProvider: SortedListProvider; + /// The maximum number of `unlocking` chunks a [`StakingLedger`] can have. Effectively + /// determines how many unique eras a staker may be unbonding in. + type MaxUnlockingChunks: Get; + /// Some parameters of the benchmarking. type BenchmarkingConfig: BenchmarkingConfig; @@ -772,7 +775,7 @@ pub mod pallet { stash, total: value, active: value, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: (last_reward_era..current_era).collect(), }; Self::update_ledger(&controller, &item); @@ -837,7 +840,7 @@ pub mod pallet { /// Once the unlock period is done, you can call `withdraw_unbonded` to actually move /// the funds out of management ready for transfer. /// - /// No more than a limited number of unlocking chunks (see `MAX_UNLOCKING_CHUNKS`) + /// No more than a limited number of unlocking chunks (see `MaxUnlockingChunks`) /// can co-exists at the same time. In that case, [`Call::withdraw_unbonded`] need /// to be called first to remove some of the chunks (if possible). /// @@ -854,7 +857,10 @@ pub mod pallet { ) -> DispatchResult { let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; - ensure!(ledger.unlocking.len() < MAX_UNLOCKING_CHUNKS, Error::::NoMoreChunks,); + ensure!( + ledger.unlocking.len() < MaxUnlockingChunks::get() as usize, + Error::::NoMoreChunks, + ); let mut value = value.min(ledger.active); @@ -881,7 +887,19 @@ pub mod pallet { // Note: in case there is no current era it is fine to bond one era more. let era = Self::current_era().unwrap_or(0) + T::BondingDuration::get(); - ledger.unlocking.push(UnlockChunk { value, era }); + if let Some(mut chunk) = + ledger.unlocking.last_mut().filter(|chunk| chunk.era == era) + { + // To keep the chunk count down, we only keep one chunk per era. Since + // `unlocking` is a FiFo queue, if a chunk exists for `era` we know that it will + // be the last one. + chunk.value = chunk.value.defensive_saturating_add(value) + } else { + ledger + .unlocking + .try_push(UnlockChunk { value, era }) + .map_err(|_| Error::::NoMoreChunks)?; + }; // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); @@ -1348,10 +1366,10 @@ pub mod pallet { /// /// # /// - Time complexity: O(L), where L is unlocking chunks - /// - Bounded by `MAX_UNLOCKING_CHUNKS`. + /// - Bounded by `MaxUnlockingChunks`. /// - Storage changes: Can't increase storage, only decrease it. /// # - #[pallet::weight(T::WeightInfo::rebond(MAX_UNLOCKING_CHUNKS as u32))] + #[pallet::weight(T::WeightInfo::rebond(MaxUnlockingChunks::get() as u32))] pub fn rebond( origin: OriginFor, #[pallet::compact] value: BalanceOf, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 4073c069fb6be..0fc6cd27a266c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -17,10 +17,10 @@ //! Tests for the module. -use super::{Event, *}; +use super::{Event, MaxUnlockingChunks, *}; use frame_election_provider_support::{ElectionProvider, SortedListProvider, Support}; use frame_support::{ - assert_noop, assert_ok, + assert_noop, assert_ok, bounded_vec, dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{Currency, Get, ReservableCurrency}, @@ -104,7 +104,7 @@ fn basic_setup_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![] }) ); @@ -115,7 +115,7 @@ fn basic_setup_works() { stash: 21, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![] }) ); @@ -138,7 +138,7 @@ fn basic_setup_works() { stash: 101, total: 500, active: 500, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![] }) ); @@ -382,7 +382,7 @@ fn staking_should_work() { stash: 3, total: 1500, active: 1500, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![0], }) ); @@ -936,7 +936,7 @@ fn reward_destination_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -959,7 +959,7 @@ fn reward_destination_works() { stash: 11, total: 1000 + total_payout_0, active: 1000 + total_payout_0, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![0], }) ); @@ -987,7 +987,7 @@ fn reward_destination_works() { stash: 11, total: 1000 + total_payout_0, active: 1000 + total_payout_0, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![0, 1], }) ); @@ -1016,7 +1016,7 @@ fn reward_destination_works() { stash: 11, total: 1000 + total_payout_0, active: 1000 + total_payout_0, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![0, 1, 2], }) ); @@ -1081,7 +1081,7 @@ fn bond_extra_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1098,7 +1098,7 @@ fn bond_extra_works() { stash: 11, total: 1000 + 100, active: 1000 + 100, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1112,7 +1112,7 @@ fn bond_extra_works() { stash: 11, total: 1000000, active: 1000000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1150,7 +1150,7 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1168,7 +1168,7 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 1000 + 100, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1189,7 +1189,7 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 1000 + 100, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1207,7 +1207,7 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, - unlocking: vec![UnlockChunk { value: 1000, era: 2 + 3 }], + unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], claimed_rewards: vec![] }), ); @@ -1220,7 +1220,7 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, - unlocking: vec![UnlockChunk { value: 1000, era: 2 + 3 }], + unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], claimed_rewards: vec![] }), ); @@ -1236,7 +1236,7 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, - unlocking: vec![UnlockChunk { value: 1000, era: 2 + 3 }], + unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], claimed_rewards: vec![] }), ); @@ -1252,7 +1252,7 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 100, active: 100, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![] }), ); @@ -1262,23 +1262,35 @@ fn bond_extra_and_withdraw_unbonded_works() { #[test] fn too_many_unbond_calls_should_not_work() { ExtBuilder::default().build_and_execute(|| { - // locked at era 0 until 3 - for _ in 0..MAX_UNLOCKING_CHUNKS - 1 { + let mut current_era = 0; + // locked at era MaxUnlockingChunks - 1 until 3 + for i in 0..MaxUnlockingChunks::get() - 1 { + // There is only 1 chunk per era, so we need to be in a new era to create a chunk. + current_era = i as u32; + mock::start_active_era(current_era); assert_ok!(Staking::unbond(Origin::signed(10), 1)); } - mock::start_active_era(1); + current_era += 1; + mock::start_active_era(current_era); - // locked at era 1 until 4 + // This chunk is locked at `current_era` through `current_era + 2` (because BondingDuration + // == 3). assert_ok!(Staking::unbond(Origin::signed(10), 1)); + assert_eq!( + Staking::ledger(&10).unwrap().unlocking.len(), + MaxUnlockingChunks::get() as usize + ); // can't do more. assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::::NoMoreChunks); - mock::start_active_era(3); + current_era += 2; + mock::start_active_era(current_era); assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::::NoMoreChunks); - // free up. + // free up everything except the most recently added chunk. assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0)); + assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 1); // Can add again. assert_ok!(Staking::unbond(Origin::signed(10), 1)); @@ -1310,7 +1322,7 @@ fn rebond_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1329,7 +1341,7 @@ fn rebond_works() { stash: 11, total: 1000, active: 100, - unlocking: vec![UnlockChunk { value: 900, era: 2 + 3 }], + unlocking: bounded_vec![UnlockChunk { value: 900, era: 2 + 3 }], claimed_rewards: vec![], }) ); @@ -1342,7 +1354,7 @@ fn rebond_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1355,7 +1367,7 @@ fn rebond_works() { stash: 11, total: 1000, active: 100, - unlocking: vec![UnlockChunk { value: 900, era: 5 }], + unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], claimed_rewards: vec![], }) ); @@ -1368,7 +1380,7 @@ fn rebond_works() { stash: 11, total: 1000, active: 600, - unlocking: vec![UnlockChunk { value: 400, era: 5 }], + unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], claimed_rewards: vec![], }) ); @@ -1381,7 +1393,7 @@ fn rebond_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1396,11 +1408,7 @@ fn rebond_works() { stash: 11, total: 1000, active: 100, - unlocking: vec![ - UnlockChunk { value: 300, era: 5 }, - UnlockChunk { value: 300, era: 5 }, - UnlockChunk { value: 300, era: 5 }, - ], + unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], claimed_rewards: vec![], }) ); @@ -1413,10 +1421,7 @@ fn rebond_works() { stash: 11, total: 1000, active: 600, - unlocking: vec![ - UnlockChunk { value: 300, era: 5 }, - UnlockChunk { value: 100, era: 5 }, - ], + unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], claimed_rewards: vec![], }) ); @@ -1443,7 +1448,7 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1458,7 +1463,7 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 600, - unlocking: vec![UnlockChunk { value: 400, era: 2 + 3 },], + unlocking: bounded_vec![UnlockChunk { value: 400, era: 2 + 3 }], claimed_rewards: vec![], }) ); @@ -1473,9 +1478,9 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 300, - unlocking: vec![ + unlocking: bounded_vec![ UnlockChunk { value: 400, era: 2 + 3 }, - UnlockChunk { value: 300, era: 3 + 3 }, + UnlockChunk { value: 300, era: 3 + 3 } ], claimed_rewards: vec![], }) @@ -1491,10 +1496,10 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 100, - unlocking: vec![ + unlocking: bounded_vec![ UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 300, era: 3 + 3 }, - UnlockChunk { value: 200, era: 4 + 3 }, + UnlockChunk { value: 200, era: 4 + 3 } ], claimed_rewards: vec![], }) @@ -1508,9 +1513,9 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 500, - unlocking: vec![ + unlocking: bounded_vec![ UnlockChunk { value: 400, era: 2 + 3 }, - UnlockChunk { value: 100, era: 3 + 3 }, + UnlockChunk { value: 100, era: 3 + 3 } ], claimed_rewards: vec![], }) @@ -1540,7 +1545,7 @@ fn rebond_emits_right_value_in_event() { stash: 11, total: 1000, active: 100, - unlocking: vec![UnlockChunk { value: 900, era: 1 + 3 }], + unlocking: bounded_vec![UnlockChunk { value: 900, era: 1 + 3 }], claimed_rewards: vec![], }) ); @@ -1553,7 +1558,7 @@ fn rebond_emits_right_value_in_event() { stash: 11, total: 1000, active: 200, - unlocking: vec![UnlockChunk { value: 800, era: 1 + 3 }], + unlocking: bounded_vec![UnlockChunk { value: 800, era: 1 + 3 }], claimed_rewards: vec![], }) ); @@ -1568,7 +1573,7 @@ fn rebond_emits_right_value_in_event() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -1604,7 +1609,7 @@ fn reward_to_stake_works() { stash: 21, total: 69, active: 69, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }, ); @@ -1665,7 +1670,7 @@ fn reap_stash_works() { stash: 11, total: 5, active: 5, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }, ); @@ -1784,7 +1789,7 @@ fn bond_with_no_staked_value() { stash: 1, active: 0, total: 5, - unlocking: vec![UnlockChunk { value: 5, era: 3 }], + unlocking: bounded_vec![UnlockChunk { value: 5, era: 3 }], claimed_rewards: vec![], }) ); @@ -3354,7 +3359,7 @@ fn test_payout_stakers() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![1] }) ); @@ -3376,7 +3381,7 @@ fn test_payout_stakers() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: (1..=14).collect() }) ); @@ -3397,7 +3402,7 @@ fn test_payout_stakers() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![15, 98] }) ); @@ -3412,7 +3417,7 @@ fn test_payout_stakers() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![15, 23, 42, 69, 98] }) ); @@ -3607,7 +3612,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { stash: 9, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![], }) ); @@ -3619,7 +3624,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: (0..5).collect(), }) ); @@ -3631,7 +3636,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { stash: 13, total: 1000, active: 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: (15..99).collect(), }) ); @@ -3850,7 +3855,7 @@ fn cannot_rebond_to_lower_than_ed() { stash: 21, total: 10 * 1000, active: 10 * 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![] } ); @@ -3864,7 +3869,7 @@ fn cannot_rebond_to_lower_than_ed() { stash: 21, total: 10 * 1000, active: 0, - unlocking: vec![UnlockChunk { value: 10 * 1000, era: 3 }], + unlocking: bounded_vec![UnlockChunk { value: 10 * 1000, era: 3 }], claimed_rewards: vec![] } ); @@ -3887,7 +3892,7 @@ fn cannot_bond_extra_to_lower_than_ed() { stash: 21, total: 10 * 1000, active: 10 * 1000, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![] } ); @@ -3901,7 +3906,7 @@ fn cannot_bond_extra_to_lower_than_ed() { stash: 21, total: 10 * 1000, active: 0, - unlocking: vec![UnlockChunk { value: 10 * 1000, era: 3 }], + unlocking: bounded_vec![UnlockChunk { value: 10 * 1000, era: 3 }], claimed_rewards: vec![] } ); @@ -3928,7 +3933,7 @@ fn do_not_die_when_active_is_ed() { stash: 21, total: 1000 * ed, active: 1000 * ed, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![] } ); @@ -3945,7 +3950,7 @@ fn do_not_die_when_active_is_ed() { stash: 21, total: ed, active: ed, - unlocking: vec![], + unlocking: Default::default(), claimed_rewards: vec![] } ); diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 206a7e5d4edea..4e513258f9684 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -25,7 +25,7 @@ use crate::{ }; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use core::{ - ops::{Deref, Index, IndexMut}, + ops::{Deref, Index, IndexMut, RangeBounds}, slice::SliceIndex, }; use sp_std::{marker::PhantomData, prelude::*}; @@ -178,6 +178,19 @@ impl BoundedVec { pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> { self.0.iter_mut() } + + /// Exactly the same semantics as [`slice::last_mut`]. + pub fn last_mut(&mut self) -> Option<&mut T> { + self.0.last_mut() + } + + /// Exact same semantics as [`Vec::drain`]. + pub fn drain(&mut self, range: R) -> sp_std::vec::Drain<'_, T> + where + R: RangeBounds, + { + self.0.drain(range) + } } impl> From> for Vec { From a9345510cf5b76d12c8365d618aa562ffe507f25 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Tue, 1 Mar 2022 21:49:23 -0800 Subject: [PATCH 0564/1472] staking: Expose `MaxUnlockingChunks` in metadata as a const (#10958) --- frame/staking/src/pallet/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 9d3b438daebb4..eb8dab7ce6bb6 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -158,6 +158,7 @@ pub mod pallet { /// The maximum number of `unlocking` chunks a [`StakingLedger`] can have. Effectively /// determines how many unique eras a staker may be unbonding in. + #[pallet::constant] type MaxUnlockingChunks: Get; /// Some parameters of the benchmarking. From a7a4c68b092fa64e20d286cf1697ec3378e2ed57 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Wed, 2 Mar 2022 00:40:08 -0800 Subject: [PATCH 0565/1472] Allow trailing commas for `bounded_vec!` (#10959) --- frame/staking/src/tests.rs | 6 +++--- frame/support/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 0fc6cd27a266c..0f979f1d59228 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1480,7 +1480,7 @@ fn rebond_is_fifo() { active: 300, unlocking: bounded_vec![ UnlockChunk { value: 400, era: 2 + 3 }, - UnlockChunk { value: 300, era: 3 + 3 } + UnlockChunk { value: 300, era: 3 + 3 }, ], claimed_rewards: vec![], }) @@ -1499,7 +1499,7 @@ fn rebond_is_fifo() { unlocking: bounded_vec![ UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 300, era: 3 + 3 }, - UnlockChunk { value: 200, era: 4 + 3 } + UnlockChunk { value: 200, era: 4 + 3 }, ], claimed_rewards: vec![], }) @@ -1515,7 +1515,7 @@ fn rebond_is_fifo() { active: 500, unlocking: bounded_vec![ UnlockChunk { value: 400, era: 2 + 3 }, - UnlockChunk { value: 100, era: 3 + 3 } + UnlockChunk { value: 100, era: 3 + 3 }, ], claimed_rewards: vec![], }) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index ef60729f6d861..3988b5e9af219 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -123,7 +123,7 @@ impl TypeId for PalletId { #[macro_export] #[cfg(feature = "std")] macro_rules! bounded_vec { - ($ ($values:expr),* ) => { + ($ ($values:expr),* $(,)?) => { { use $crate::sp_std::convert::TryInto as _; $crate::sp_std::vec![$($values),*].try_into().unwrap() From f4fb93fdccc2edc38a394fc42a93ab73974fc4f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 2 Mar 2022 10:03:10 +0100 Subject: [PATCH 0566/1472] SimpleSlotWorker: Do not implement `SlotWorker` for all types implementing `SimpleSlotWorker` (#10934) Because Rust currently doesn't support specialization, it prevents users from implementing `SlotWorker` for their own types. This pr solves this by removing the generic implementation of `SlotWorker` for `SimpleSlotWorker` and providing some wrapper type for that. --- client/consensus/aura/src/lib.rs | 4 ++-- client/consensus/babe/src/lib.rs | 2 +- client/consensus/slots/src/lib.rs | 13 ++++++++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index d3a6b10589408..4d91eaaae92ab 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -279,7 +279,7 @@ where L: sc_consensus::JustificationSyncLink, BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, { - AuraWorker { + sc_consensus_slots::SimpleSlotWorkerToSlotWorker(AuraWorker { client, block_import, env: proposer_factory, @@ -292,7 +292,7 @@ where block_proposal_slot_portion, max_block_proposal_slot_portion, _key_type: PhantomData::

, - } + }) } struct AuraWorker { diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 0e9f943eca307..442dbab77e120 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -518,7 +518,7 @@ where let slot_worker = sc_consensus_slots::start_slot_worker( babe_link.config.slot_duration(), select_chain, - worker, + sc_consensus_slots::SimpleSlotWorkerToSlotWorker(worker), sync_oracle, create_inherent_data_providers, can_author_with, diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index f6129943b2411..a97469fbcc300 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -401,15 +401,22 @@ pub trait SimpleSlotWorker { } } +/// A type that implements [`SlotWorker`] for a type that implements [`SimpleSlotWorker`]. +/// +/// This is basically a workaround for Rust not supporting specialization. Otherwise we could +/// implement [`SlotWorker`] for any `T` that implements [`SimpleSlotWorker`], but currently +/// that would prevent downstream users to implement [`SlotWorker`] for their own types. +pub struct SimpleSlotWorkerToSlotWorker(pub T); + #[async_trait::async_trait] -impl + Send + Sync> - SlotWorker>::Proof> for T +impl + Send + Sync, B: BlockT> + SlotWorker>::Proof> for SimpleSlotWorkerToSlotWorker { async fn on_slot( &mut self, slot_info: SlotInfo, ) -> Option>::Proof>> { - SimpleSlotWorker::on_slot(self, slot_info).await + self.0.on_slot(slot_info).await } } From 90b89f8f607f9a921a810651e1dd2ae764f089a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Mar 2022 16:39:39 +0100 Subject: [PATCH 0567/1472] Bump digest from 0.10.2 to 0.10.3 (#10960) Bumps [digest](https://github.com/RustCrypto/traits) from 0.10.2 to 0.10.3. - [Release notes](https://github.com/RustCrypto/traits/releases) - [Commits](https://github.com/RustCrypto/traits/compare/digest-v0.10.2...digest-v0.10.3) --- updated-dependencies: - dependency-name: digest 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 | 23 ++++++++++++----------- primitives/core/hashing/Cargo.toml | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c1b6ed88fb4a..3d95343cb0b2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -629,7 +629,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94ba84325db59637ffc528bbe8c7f86c02c57cff5c0e2b9b00f9a851f42f309" dependencies = [ - "digest 0.10.2", + "digest 0.10.3", ] [[package]] @@ -1403,11 +1403,12 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" dependencies = [ "generic-array 0.14.4", + "typenum", ] [[package]] @@ -1632,9 +1633,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ "block-buffer 0.10.0", "crypto-common", @@ -9416,7 +9417,7 @@ checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" dependencies = [ "cfg-if 1.0.0", "cpufeatures 0.2.1", - "digest 0.10.2", + "digest 0.10.3", ] [[package]] @@ -9437,7 +9438,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd" dependencies = [ - "digest 0.10.2", + "digest 0.10.3", "keccak", ] @@ -9883,7 +9884,7 @@ version = "4.0.0" dependencies = [ "blake2 0.10.2", "byteorder", - "digest 0.10.2", + "digest 0.10.3", "sha2 0.10.1", "sha3 0.10.0", "sp-std", @@ -11379,7 +11380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ "cfg-if 1.0.0", - "digest 0.10.2", + "digest 0.10.3", "rand 0.8.4", "static_assertions", ] @@ -11392,9 +11393,9 @@ checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" [[package]] name = "typenum" -version = "1.12.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ucd-trie" diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index dc5704d2989a2..978cb8906d5d9 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-std = { version = "4.0.0", default-features = false, path = "../../std" } byteorder = { version = "1.3.2", default-features = false } -digest = { version = "0.10.2", default-features = false } +digest = { version = "0.10.3", default-features = false } blake2 = { version = "0.10.2", default-features = false } sha2 = { version = "0.10.1", default-features = false } sha3 = { version = "0.10.0", default-features = false } From 7a742c6f7746f12e1340e9f401fadc529575a096 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Mar 2022 21:13:24 +0100 Subject: [PATCH 0568/1472] Bump scale-info from 2.0.0 to 2.0.1 (#10965) Bumps [scale-info](https://github.com/paritytech/scale-info) from 2.0.0 to 2.0.1. - [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/commits) --- updated-dependencies: - dependency-name: scale-info 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 ++-- bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- bin/node/primitives/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- frame/assets/Cargo.toml | 2 +- frame/atomic-swap/Cargo.toml | 2 +- frame/aura/Cargo.toml | 2 +- frame/authority-discovery/Cargo.toml | 2 +- frame/authorship/Cargo.toml | 2 +- frame/babe/Cargo.toml | 2 +- frame/bags-list/Cargo.toml | 2 +- frame/balances/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 2 +- frame/bounties/Cargo.toml | 2 +- frame/child-bounties/Cargo.toml | 2 +- frame/collective/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/rpc/runtime-api/Cargo.toml | 2 +- frame/conviction-voting/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- frame/election-provider-multi-phase/Cargo.toml | 2 +- frame/election-provider-support/Cargo.toml | 2 +- frame/examples/basic/Cargo.toml | 2 +- frame/examples/offchain-worker/Cargo.toml | 2 +- frame/examples/parallel/Cargo.toml | 2 +- frame/executive/Cargo.toml | 2 +- frame/gilt/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/identity/Cargo.toml | 2 +- frame/im-online/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- frame/lottery/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 2 +- frame/nicks/Cargo.toml | 2 +- frame/node-authorization/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/preimage/Cargo.toml | 2 +- frame/proxy/Cargo.toml | 2 +- frame/randomness-collective-flip/Cargo.toml | 2 +- frame/recovery/Cargo.toml | 2 +- frame/referenda/Cargo.toml | 2 +- frame/scheduler/Cargo.toml | 2 +- frame/scored-pool/Cargo.toml | 2 +- frame/session/Cargo.toml | 2 +- frame/session/benchmarking/Cargo.toml | 2 +- frame/society/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/sudo/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/test/Cargo.toml | 2 +- frame/support/test/compile_pass/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- frame/system/benchmarking/Cargo.toml | 2 +- frame/timestamp/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- frame/transaction-payment/asset-tx-payment/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 2 +- frame/utility/Cargo.toml | 2 +- frame/vesting/Cargo.toml | 2 +- primitives/application-crypto/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/authority-discovery/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 2 +- primitives/consensus/aura/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- primitives/npos-elections/solution-type/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/session/Cargo.toml | 2 +- primitives/staking/Cargo.toml | 2 +- primitives/transaction-storage-proof/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 2 +- primitives/version/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- 87 files changed, 88 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d95343cb0b2f..b5c78491628d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9095,9 +9095,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3b4d0b178e3af536f7988303bc73a0766c816de2138c08262015f8ec7be568" +checksum = "0563970d79bcbf3c537ce3ad36d859b30d36fc5b190efd227f1f7a84d7cf0d42" dependencies = [ "bitvec", "cfg-if 1.0.0", diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index ffc02dbd96f65..686dd38b577b1 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/support" } frame-system = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/system" } frame-benchmarking = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/benchmarking", optional = true } diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index d20a6c39aa5d9..f4ff877290822 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } pallet-aura = { version = "4.0.0-dev", default-features = false, path = "../../../frame/aura" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../../frame/balances" } diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index e29ffd9b671f3..21862ecf81b5d 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -scale-info = { version = "2.0.0", features = ["derive"] } +scale-info = { version = "2.0.1", features = ["derive"] } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 0d49d4a247c07..711b30d33933d 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../../primitives/application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 2d2c903f70ca5..e7bd50c3d1897 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } static_assertions = "1.1.0" hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.14", default-features = false } diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index b69b53a095eb4..d3685e6582324 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 9be0868760dd7..361b7d5833e67 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index d6d792886c2f6..96cfade56cc0f 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index c44134190e8a7..d379bdda6cf8a 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -18,7 +18,7 @@ sp-application-crypto = { version = "6.0.0", default-features = false, path = ". codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } pallet-session = { version = "4.0.0-dev", features = [ "historical", diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index adeebf0e4b374..77a44f5b5dd72 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index d4447ba338554..a13a2d71f25d3 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index f96048d7fcb80..87b8d7939e125 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } # primitives sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index d0a6f2699ab38..a0de11638e664 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index c6d3b1b165faa..19703fa79863a 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -12,7 +12,7 @@ hex = { version = "0.4", optional = true } codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } k256 = { version = "0.10.2", default-features = false, features = ["arithmetic"] } log = { version = "0.4.13", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index dc7ef8eda86b1..6ed9e7375bfe3 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -9,7 +9,7 @@ description = "BEEFY FRAME pallet" [dependencies] codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 37259f351e9f1..ce301ff9034a2 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] linregress = { version = "0.4.4", optional = true } paste = "1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } sp-runtime-interface = { version = "6.0.0", path = "../../primitives/runtime-interface", default-features = false } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime", default-features = false } diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 7907df2209a4f..a158895a252be 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 91df3e051f1be..9d2e1031604ec 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index 190f477dd8932..c9793e155c2a1 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index ca7b8ec1aa9f3..2e906b69f32fc 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } log = { version = "0.4", default-features = false } wasm-instrument = { version = "0.1", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml index 5c95cfacf76b9..e50a41624e7e9 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/rpc/runtime-api/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } # Substrate Dependencies pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../common" } diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index a2d3bde497c45..5877bf0c5da2d 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -17,7 +17,7 @@ serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index dddfcd9e1a31d..49b21d0eecdce 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -17,7 +17,7 @@ serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index ffaad4f46669b..38039f6926b15 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -17,7 +17,7 @@ static_assertions = "1.1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 9364dd5553ef8..e66774c6b5e71 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 837244811e4f2..a54301944a017 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4.14", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index 32ca98f505b04..8daf0686d816c 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } lite-json = { version = "0.1", default-features = false } log = { version = "0.4.14", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/examples/parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml index 2d5a2432e6619..367b2e98aaa65 100644 --- a/frame/examples/parallel/Cargo.toml +++ b/frame/examples/parallel/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 5613b42562364..f920affaab202 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index f47166fb3d084..837504e516cee 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index ee5fa5e52b8e2..cad238a4e365f 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 7159c71644fbc..7ebfda7cf176f 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } enumflags2 = { version = "0.6.2" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index 86d7d9a053414..277d4d2fb2de3 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index d651bcc15c06e..690fc9db14f95 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index ad94b0935ffd2..7932abdc21a04 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 6f654bfbe858d..40ad619e904cc 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index c0e1f6702c73b..796ab98dc2c32 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, version = "0.3.2" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index 67da75a137f98..a2188ca18b3b3 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index fa6dd3395a097..9e98864d24f99 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 67c39ca4e3500..6ae1f21336b6c 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 93ece2ae7fd20..01409d78053c5 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } serde = { version = "1.0.136", optional = true } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 70c5292f7f8cb..58809f9e98964 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index 6f1dd15ed6b39..bdc39a81e34a6 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["max-encoded-len"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index d05bcd534ec4d..17d4ff461aa0f 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] safe-mix = { version = "1.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 6bba8102af2ec..0a173fe2c9dab 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index 080e4d7ab7782..d85503a741f43 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -17,7 +17,7 @@ serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index f08a0318a7020..9000d1f693cca 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index 203c06065c351..73fd25158ca88 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 4302c6a44cb01..647b3482b2025 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -17,7 +17,7 @@ log = { version = "0.4.0", default-features = false } impl-trait-for-tuples = "0.2.1" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 23336e647b021..b00d1335d22a2 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -27,7 +27,7 @@ pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } -scale-info = "2.0.0" +scale-info = "2.0.1" sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-io = { version = "6.0.0", path = "../../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../../balances" } diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index cd3afdb9beeb2..1fd9693d0d00f 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index abe977a70eaa3..073d959e2d1dd 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -17,7 +17,7 @@ serde = { version = "1.0.136", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index 17d6ef4da489e..b209351ddaf07 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 796df7697d746..3161e4f4db69b 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-metadata = { version = "15.0.0", default-features = false, features = ["v14"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index ef20915899fd1..d99889cf99bc4 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../../primitives/arithmetic" } sp-io = { version = "6.0.0", path = "../../../primitives/io", default-features = false } sp-state-machine = { version = "0.12.0", optional = true, path = "../../../primitives/state-machine" } diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index 33ee3e8c2d077..5850d2e5db148 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-core = { version = "6.0.0", default-features = false, path = "../../../../primitives/core" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "5.0.0", default-features = false, path = "../../../../primitives/version" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index a5a65e403454b..e9196c4eb94f4 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 7ca76c260c433..c543d5af0412e 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 1652be9776744..72d632faf8583 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io", optional = true } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 017d86ea72b37..dc65d5c28d1c8 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 5ac9ea1e713cc..ea894e7cada66 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } smallvec = "1.8.0" diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index da30136c067ab..ec07fc967c923 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -25,7 +25,7 @@ pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, # Other dependencies codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } [dev-dependencies] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index b4ec343dc6216..eec505708ed7d 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.136", optional = true } hex-literal = { version = "0.3.4", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index ca32f4713ee2b..f848f48acd254 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.1" diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 6f4e8f91b26fe..b0abb814eb5af 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index f059937ad2d90..6235d1ee15556 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 36a877478a4e9..83f897847f79a 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index 7ac487fe35d2f..a8181ca5380c2 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "6.0.0", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 654127671466b..26ee7677363c9 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } integer-sqrt = "0.1.2" static_assertions = "1.1.0" num-traits = { version = "0.2.8", default-features = false } diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index 687987ab2ec98..c452aaa892020 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0" } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 9012803a902db..4aa53aff2c3cb 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -9,7 +9,7 @@ description = "Primitives for BEEFY protocol." [dependencies] codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../api", default-features = false } sp-application-crypto = { version = "6.0.0", path = "../application-crypto", default-features = false } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index 28f68f15cd9ea..2c4a2f0a0de99 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 46bb51a061e6b..189dc5b2e80f7 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } merlin = { version = "2.0", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 70ae11cf543b1..1effb8efbf5ae 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } log = { version = "0.4.11", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index 671168ef90b8a..ebc067e630c15 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.15.0", default-features = false, features = ["derive-codec"] } log = { version = "0.4.8", optional = true } serde = { version = "1.0.136", optional = true, features = ["derive"] } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index b96b386958597..3facf32196c74 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 6ad59d807fa50..afa331b0676e0 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -19,7 +19,7 @@ honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } sp-runtime = { version = "6.0.0", path = "../../runtime" } diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/primitives/npos-elections/solution-type/Cargo.toml index fcd39437945ff..813637e89c338 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/primitives/npos-elections/solution-type/Cargo.toml @@ -22,7 +22,7 @@ proc-macro-crate = "1.1.0" [dev-dependencies] parity-scale-codec = "3.0.0" -scale-info = "2.0.0" +scale-info = "2.0.1" sp-arithmetic = { path = "../../arithmetic", version = "5.0.0"} # used by generate_solution_type: sp-npos-elections = { path = "..", version = "4.0.0-dev" } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 91bf6d36b0a70..5f7b45ba15a8c 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index 9ffaa2cf3bdd1..476bacc88ae34 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 2cb1ae0938a8b..7761519dabefb 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index 803ec67f571c6..966142a7e14fa 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -19,7 +19,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-trie = { version = "6.0.0", optional = true, path = "../trie" } sp-core = { version = "6.0.0", path = "../core", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } log = { version = "0.4.8", optional = true } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index dfe3150194a3e..f434a15b8964a 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -19,7 +19,7 @@ harness = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } hash-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.23.1", default-features = false } diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 8518dfffa5dba..7488d924070cb 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] impl-serde = { version = "0.3.1", optional = true } serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 9bf66a64db421..8c61cbbf8adbe 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -18,7 +18,7 @@ sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = " sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } memory-db = { version = "0.29.0", default-features = false } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index f1cf00153f3b2..0055ef47f8f4e 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -25,5 +25,5 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } [dev-dependencies] frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } -scale-info = "2.0.0" +scale-info = "2.0.1" tokio = "1.15" From e41027bb59f985b32a1100b6790b2c99458b2afc Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Thu, 3 Mar 2022 10:59:42 +0200 Subject: [PATCH 0569/1472] Add pr-custom-review config (#10968) --- .github/pr-custom-review.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/pr-custom-review.yml diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml new file mode 100644 index 0000000000000..615203c11c15b --- /dev/null +++ b/.github/pr-custom-review.yml @@ -0,0 +1,18 @@ +rules: + - name: Changed runtime files + condition: .*/runtime/.*lib.rs + check_type: changed_files + min_approvals: 2 + teams: + - substrateteamleads + + - name: Substrate developers + check_type: changed_files + condition: .* + any: + - min_approvals: 2 + teams: + - core-devs + - min_approvals: 1 + teams: + - substrateteamleads \ No newline at end of file From 21cadf1af453716aea1e5362c83aa314811da657 Mon Sep 17 00:00:00 2001 From: Falco Hirschenberger Date: Thu, 3 Mar 2022 10:17:24 +0100 Subject: [PATCH 0570/1472] Revise how staking configurations are set (#10955) * Revise how staking configurations are set fixes #10938 * Fix and add additional tests * Format * Formatting * Add doc Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/staking/src/tests.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Format * Fix build * Update weights.rs * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Shawn Tabrizi Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Parity Bot --- frame/staking/src/benchmarking.rs | 49 ++++-- frame/staking/src/pallet/mod.rs | 56 +++++-- frame/staking/src/tests.rs | 138 ++++++++++------ frame/staking/src/weights.rs | 253 ++++++++++++++++-------------- 4 files changed, 308 insertions(+), 188 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 7593522055fba..ec7d36c820f3e 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Staking pallet benchmarking. use super::*; -use crate::Pallet as Staking; +use crate::{ConfigOp, Pallet as Staking}; use testing_utils::*; use codec::Decode; @@ -852,16 +852,15 @@ benchmarks! { assert_eq!(targets.len() as u32, v); } - set_staking_configs { - // This function always does the same thing... just write to 4 storage items. - }: _( + set_staking_configs_all_set { + }: set_staking_configs( RawOrigin::Root, - BalanceOf::::max_value(), - BalanceOf::::max_value(), - Some(u32::MAX), - Some(u32::MAX), - Some(Percent::max_value()), - Perbill::max_value() + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(Percent::max_value()), + ConfigOp::Set(Perbill::max_value()) ) verify { assert_eq!(MinNominatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MinValidatorBond::::get(), BalanceOf::::max_value()); @@ -871,6 +870,24 @@ benchmarks! { assert_eq!(MinCommission::::get(), Perbill::from_percent(100)); } + set_staking_configs_all_remove { + }: set_staking_configs( + RawOrigin::Root, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove + ) verify { + assert!(!MinNominatorBond::::exists()); + assert!(!MinValidatorBond::::exists()); + assert!(!MaxNominatorsCount::::exists()); + assert!(!MaxValidatorsCount::::exists()); + assert!(!ChillThreshold::::exists()); + assert!(!MinCommission::::exists()); + } + chill_other { // clean up any existing state. clear_validators_and_nominators::(); @@ -886,12 +903,12 @@ benchmarks! { Staking::::set_staking_configs( RawOrigin::Root.into(), - BalanceOf::::max_value(), - BalanceOf::::max_value(), - Some(0), - Some(0), - Some(Percent::from_percent(0)), - Zero::zero(), + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(0), + ConfigOp::Set(0), + ConfigOp::Set(Percent::from_percent(0)), + ConfigOp::Set(Zero::zero()), )?; let caller = whitelisted_caller(); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index eb8dab7ce6bb6..58f9fd237263b 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -19,6 +19,7 @@ use frame_election_provider_support::SortedListProvider; use frame_support::{ + dispatch::Codec, pallet_prelude::*, traits::{ Currency, CurrencyToVote, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, @@ -32,7 +33,7 @@ use sp_runtime::{ DispatchError, Perbill, Percent, }; use sp_staking::{EraIndex, SessionIndex}; -use sp_std::{convert::From, prelude::*}; +use sp_std::{cmp::max, convert::From, prelude::*}; mod impls; @@ -60,6 +61,17 @@ pub mod pallet { #[pallet::without_storage_info] pub struct Pallet(_); + /// Possible operations on the configuration values of this pallet. + #[derive(TypeInfo, Debug, Clone, Encode, Decode, PartialEq)] + pub enum ConfigOp { + /// Don't change. + Noop, + /// Set the given value. + Set(T), + /// Remove from storage. + Remove, + } + #[pallet::config] pub trait Config: frame_system::Config + SendTransactionTypes> { /// The staking balance. @@ -1532,23 +1544,39 @@ pub mod pallet { /// /// NOTE: Existing nominators and validators will not be affected by this update. /// to kick people under the new limits, `chill_other` should be called. - #[pallet::weight(T::WeightInfo::set_staking_configs())] + // We assume the worst case for this call is either: all items are set or all items are + // removed. + #[pallet::weight(max( + T::WeightInfo::set_staking_configs_all_set(), + T::WeightInfo::set_staking_configs_all_remove() + ))] pub fn set_staking_configs( origin: OriginFor, - min_nominator_bond: BalanceOf, - min_validator_bond: BalanceOf, - max_nominator_count: Option, - max_validator_count: Option, - chill_threshold: Option, - min_commission: Perbill, + min_nominator_bond: ConfigOp>, + min_validator_bond: ConfigOp>, + max_nominator_count: ConfigOp, + max_validator_count: ConfigOp, + chill_threshold: ConfigOp, + min_commission: ConfigOp, ) -> DispatchResult { ensure_root(origin)?; - MinNominatorBond::::set(min_nominator_bond); - MinValidatorBond::::set(min_validator_bond); - MaxNominatorsCount::::set(max_nominator_count); - MaxValidatorsCount::::set(max_validator_count); - ChillThreshold::::set(chill_threshold); - MinCommission::::set(min_commission); + + macro_rules! config_op_exp { + ($storage:ty, $op:ident) => { + match $op { + ConfigOp::Noop => (), + ConfigOp::Set(v) => <$storage>::put(v), + ConfigOp::Remove => <$storage>::kill(), + } + }; + } + + config_op_exp!(MinNominatorBond, min_nominator_bond); + config_op_exp!(MinValidatorBond, min_validator_bond); + config_op_exp!(MaxNominatorsCount, max_nominator_count); + config_op_exp!(MaxValidatorsCount, max_validator_count); + config_op_exp!(ChillThreshold, chill_threshold); + config_op_exp!(MinCommission, min_commission); Ok(()) } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 0f979f1d59228..2b2a32e0edab7 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -17,10 +17,10 @@ //! Tests for the module. -use super::{Event, MaxUnlockingChunks, *}; +use super::{ConfigOp, Event, MaxUnlockingChunks, *}; use frame_election_provider_support::{ElectionProvider, SortedListProvider, Support}; use frame_support::{ - assert_noop, assert_ok, bounded_vec, + assert_noop, assert_ok, assert_storage_noop, bounded_vec, dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{Currency, Get, ReservableCurrency}, @@ -40,6 +40,56 @@ use sp_staking::{ use sp_std::prelude::*; use substrate_test_utils::assert_eq_uvec; +#[test] +fn set_staking_configs_works() { + ExtBuilder::default().build_and_execute(|| { + // setting works + assert_ok!(Staking::set_staking_configs( + Origin::root(), + ConfigOp::Set(1_500), + ConfigOp::Set(2_000), + ConfigOp::Set(10), + ConfigOp::Set(20), + ConfigOp::Set(Percent::from_percent(75)), + ConfigOp::Set(Zero::zero()) + )); + assert_eq!(MinNominatorBond::::get(), 1_500); + assert_eq!(MinValidatorBond::::get(), 2_000); + assert_eq!(MaxNominatorsCount::::get(), Some(10)); + assert_eq!(MaxValidatorsCount::::get(), Some(20)); + assert_eq!(ChillThreshold::::get(), Some(Percent::from_percent(75))); + assert_eq!(MinCommission::::get(), Perbill::from_percent(0)); + + // noop does nothing + assert_storage_noop!(assert_ok!(Staking::set_staking_configs( + Origin::root(), + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop + ))); + + // removing works + assert_ok!(Staking::set_staking_configs( + Origin::root(), + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove + )); + assert_eq!(MinNominatorBond::::get(), 0); + assert_eq!(MinValidatorBond::::get(), 0); + assert_eq!(MaxNominatorsCount::::get(), None); + assert_eq!(MaxValidatorsCount::::get(), None); + assert_eq!(ChillThreshold::::get(), None); + assert_eq!(MinCommission::::get(), Perbill::from_percent(0)); + }); +} + #[test] fn force_unstake_works() { ExtBuilder::default().build_and_execute(|| { @@ -4368,12 +4418,12 @@ fn chill_other_works() { // Change the minimum bond... but no limits. assert_ok!(Staking::set_staking_configs( Origin::root(), - 1_500, - 2_000, - None, - None, - None, - Zero::zero() + ConfigOp::Set(1_500), + ConfigOp::Set(2_000), + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove )); // Still can't chill these users @@ -4389,12 +4439,12 @@ fn chill_other_works() { // Add limits, but no threshold assert_ok!(Staking::set_staking_configs( Origin::root(), - 1_500, - 2_000, - Some(10), - Some(10), - None, - Zero::zero() + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Set(10), + ConfigOp::Set(10), + ConfigOp::Noop, + ConfigOp::Noop )); // Still can't chill these users @@ -4410,12 +4460,12 @@ fn chill_other_works() { // Add threshold, but no limits assert_ok!(Staking::set_staking_configs( Origin::root(), - 1_500, - 2_000, - None, - None, - Some(Percent::from_percent(0)), - Zero::zero() + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Noop, + ConfigOp::Noop )); // Still can't chill these users @@ -4431,12 +4481,12 @@ fn chill_other_works() { // Add threshold and limits assert_ok!(Staking::set_staking_configs( Origin::root(), - 1_500, - 2_000, - Some(10), - Some(10), - Some(Percent::from_percent(75)), - Zero::zero() + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Set(10), + ConfigOp::Set(10), + ConfigOp::Set(Percent::from_percent(75)), + ConfigOp::Noop )); // 16 people total because tests start with 2 active one @@ -4476,12 +4526,12 @@ fn capped_stakers_works() { let max = 10; assert_ok!(Staking::set_staking_configs( Origin::root(), - 10, - 10, - Some(max), - Some(max), - Some(Percent::from_percent(0)), - Zero::zero(), + ConfigOp::Set(10), + ConfigOp::Set(10), + ConfigOp::Set(max), + ConfigOp::Set(max), + ConfigOp::Remove, + ConfigOp::Remove, )); // can create `max - validator_count` validators @@ -4546,12 +4596,12 @@ fn capped_stakers_works() { // No problem when we set to `None` again assert_ok!(Staking::set_staking_configs( Origin::root(), - 10, - 10, - None, - None, - None, - Zero::zero(), + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Noop, + ConfigOp::Noop, )); assert_ok!(Staking::nominate(Origin::signed(last_nominator), vec![1])); assert_ok!(Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default())); @@ -4568,12 +4618,12 @@ fn min_commission_works() { assert_ok!(Staking::set_staking_configs( Origin::root(), - 0, - 0, - None, - None, - None, - Perbill::from_percent(10), + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Set(Perbill::from_percent(10)), )); // can't make it less than 10 now diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index dcb544283c225..9d43cd8822600 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-02-09, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-03-02, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -70,7 +70,8 @@ pub trait WeightInfo { fn new_era(v: u32, n: u32, ) -> Weight; fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight; fn get_npos_targets(v: u32, ) -> Weight; - fn set_staking_configs() -> Weight; + fn set_staking_configs_all_set() -> Weight; + fn set_staking_configs_all_remove() -> Weight; fn chill_other() -> Weight; fn force_apply_min_commission() -> Weight; } @@ -85,7 +86,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (37_772_000 as Weight) + (37_238_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -95,7 +96,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (64_816_000 as Weight) + (64_061_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -109,7 +110,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (71_635_000 as Weight) + (70_069_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -118,9 +119,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (30_612_000 as Weight) + (29_855_000 as Weight) // Standard Error: 0 - .saturating_add((59_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -137,8 +138,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (59_116_000 as Weight) + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + (57_313_000 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(11 as Weight)) } @@ -154,16 +157,16 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (45_505_000 as Weight) + (44_448_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (12_764_000 as Weight) - // Standard Error: 15_000 - .saturating_add((8_301_000 as Weight).saturating_mul(k as Weight)) + (13_902_000 as Weight) + // Standard Error: 12_000 + .saturating_add((7_421_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -180,9 +183,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (51_439_000 as Weight) - // Standard Error: 10_000 - .saturating_add((3_323_000 as Weight).saturating_mul(n as Weight)) + (49_580_000 as Weight) + // Standard Error: 9_000 + .saturating_add((3_362_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(6 as Weight)) @@ -195,49 +198,49 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (44_847_000 as Weight) + (44_180_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (7_795_000 as Weight) + (7_922_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (16_051_000 as Weight) + (15_436_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (1_107_000 as Weight) + (1_091_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (1_126_000 as Weight) + (1_204_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (1_183_000 as Weight) + (1_208_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (1_181_000 as Weight) + (1_220_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (1_705_000 as Weight) + (1_473_000 as Weight) // Standard Error: 0 - .saturating_add((50_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((9_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) @@ -254,18 +257,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (57_431_000 as Weight) + (55_815_000 as Weight) // Standard Error: 1_000 - .saturating_add((801_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((808_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (950_258_000 as Weight) - // Standard Error: 56_000 - .saturating_add((5_001_000 as Weight).saturating_mul(s as Weight)) + (903_077_000 as Weight) + // Standard Error: 53_000 + .saturating_add((4_434_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -280,9 +283,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (94_238_000 as Weight) - // Standard Error: 15_000 - .saturating_add((23_978_000 as Weight).saturating_mul(n as Weight)) + (79_440_000 as Weight) + // Standard Error: 14_000 + .saturating_add((24_005_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -300,9 +303,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (109_323_000 as Weight) - // Standard Error: 22_000 - .saturating_add((33_887_000 as Weight).saturating_mul(n as Weight)) + (99_118_000 as Weight) + // Standard Error: 20_000 + .saturating_add((33_274_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -315,9 +318,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (64_807_000 as Weight) + (63_335_000 as Weight) // Standard Error: 2_000 - .saturating_add((50_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(9 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -332,8 +335,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 61_000 - .saturating_add((20_457_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 58_000 + .saturating_add((20_386_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) .saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -352,9 +355,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (62_856_000 as Weight) + (61_486_000 as Weight) // Standard Error: 0 - .saturating_add((802_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((809_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -379,10 +382,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 804_000 - .saturating_add((226_855_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 40_000 - .saturating_add((31_928_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 878_000 + .saturating_add((212_233_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 44_000 + .saturating_add((30_364_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -400,12 +403,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 87_000 - .saturating_add((18_771_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 87_000 - .saturating_add((21_895_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 2_984_000 - .saturating_add((8_282_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 95_000 + .saturating_add((18_439_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 95_000 + .saturating_add((20_382_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 3_232_000 + .saturating_add((4_870_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(204 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -414,8 +417,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 28_000 - .saturating_add((7_801_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 29_000 + .saturating_add((7_552_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -425,8 +428,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ChillThreshold (r:0 w:1) // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) - fn set_staking_configs() -> Weight { - (3_680_000 as Weight) + fn set_staking_configs_all_set() -> Weight { + (3_597_000 as Weight) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) + } + // Storage: Staking MinCommission (r:0 w:1) + // Storage: Staking MinValidatorBond (r:0 w:1) + // Storage: Staking MaxValidatorsCount (r:0 w:1) + // Storage: Staking ChillThreshold (r:0 w:1) + // Storage: Staking MaxNominatorsCount (r:0 w:1) + // Storage: Staking MinNominatorBond (r:0 w:1) + fn set_staking_configs_all_remove() -> Weight { + (3_198_000 as Weight) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -440,14 +453,14 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (55_459_000 as Weight) + (55_725_000 as Weight) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - (8_939_000 as Weight) + (8_946_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -462,7 +475,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (37_772_000 as Weight) + (37_238_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -472,7 +485,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (64_816_000 as Weight) + (64_061_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } @@ -486,7 +499,7 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (71_635_000 as Weight) + (70_069_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -495,9 +508,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (30_612_000 as Weight) + (29_855_000 as Weight) // Standard Error: 0 - .saturating_add((59_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -514,8 +527,10 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (59_116_000 as Weight) + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + (57_313_000 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } @@ -531,16 +546,16 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (45_505_000 as Weight) + (44_448_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (12_764_000 as Weight) - // Standard Error: 15_000 - .saturating_add((8_301_000 as Weight).saturating_mul(k as Weight)) + (13_902_000 as Weight) + // Standard Error: 12_000 + .saturating_add((7_421_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -557,9 +572,9 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (51_439_000 as Weight) - // Standard Error: 10_000 - .saturating_add((3_323_000 as Weight).saturating_mul(n as Weight)) + (49_580_000 as Weight) + // Standard Error: 9_000 + .saturating_add((3_362_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) @@ -572,49 +587,49 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (44_847_000 as Weight) + (44_180_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (7_795_000 as Weight) + (7_922_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (16_051_000 as Weight) + (15_436_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (1_107_000 as Weight) + (1_091_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (1_126_000 as Weight) + (1_204_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (1_183_000 as Weight) + (1_208_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (1_181_000 as Weight) + (1_220_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (1_705_000 as Weight) + (1_473_000 as Weight) // Standard Error: 0 - .saturating_add((50_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((9_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) @@ -631,18 +646,18 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (57_431_000 as Weight) + (55_815_000 as Weight) // Standard Error: 1_000 - .saturating_add((801_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((808_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (950_258_000 as Weight) - // Standard Error: 56_000 - .saturating_add((5_001_000 as Weight).saturating_mul(s as Weight)) + (903_077_000 as Weight) + // Standard Error: 53_000 + .saturating_add((4_434_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -657,9 +672,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (94_238_000 as Weight) - // Standard Error: 15_000 - .saturating_add((23_978_000 as Weight).saturating_mul(n as Weight)) + (79_440_000 as Weight) + // Standard Error: 14_000 + .saturating_add((24_005_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -677,9 +692,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (109_323_000 as Weight) - // Standard Error: 22_000 - .saturating_add((33_887_000 as Weight).saturating_mul(n as Weight)) + (99_118_000 as Weight) + // Standard Error: 20_000 + .saturating_add((33_274_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -692,9 +707,9 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (64_807_000 as Weight) + (63_335_000 as Weight) // Standard Error: 2_000 - .saturating_add((50_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(9 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -709,8 +724,8 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 61_000 - .saturating_add((20_457_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 58_000 + .saturating_add((20_386_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) .saturating_add(RocksDbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -729,9 +744,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (62_856_000 as Weight) + (61_486_000 as Weight) // Standard Error: 0 - .saturating_add((802_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((809_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -756,10 +771,10 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 804_000 - .saturating_add((226_855_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 40_000 - .saturating_add((31_928_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 878_000 + .saturating_add((212_233_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 44_000 + .saturating_add((30_364_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -777,12 +792,12 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 87_000 - .saturating_add((18_771_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 87_000 - .saturating_add((21_895_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 2_984_000 - .saturating_add((8_282_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 95_000 + .saturating_add((18_439_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 95_000 + .saturating_add((20_382_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 3_232_000 + .saturating_add((4_870_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(204 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -791,8 +806,8 @@ impl WeightInfo for () { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 28_000 - .saturating_add((7_801_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 29_000 + .saturating_add((7_552_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -802,8 +817,18 @@ impl WeightInfo for () { // Storage: Staking ChillThreshold (r:0 w:1) // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) - fn set_staking_configs() -> Weight { - (3_680_000 as Weight) + fn set_staking_configs_all_set() -> Weight { + (3_597_000 as Weight) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + } + // Storage: Staking MinCommission (r:0 w:1) + // Storage: Staking MinValidatorBond (r:0 w:1) + // Storage: Staking MaxValidatorsCount (r:0 w:1) + // Storage: Staking ChillThreshold (r:0 w:1) + // Storage: Staking MaxNominatorsCount (r:0 w:1) + // Storage: Staking MinNominatorBond (r:0 w:1) + fn set_staking_configs_all_remove() -> Weight { + (3_198_000 as Weight) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -817,14 +842,14 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (55_459_000 as Weight) + (55_725_000 as Weight) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - (8_939_000 as Weight) + (8_946_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } From efc28453c4efbb950d097d7314ac789fa6d801df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Mar 2022 10:45:29 +0100 Subject: [PATCH 0571/1472] Bump libc from 0.2.112 to 0.2.119 (#10967) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.112 to 0.2.119. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.112...0.2.119) --- updated-dependencies: - dependency-name: libc 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/executor/wasmtime/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5c78491628d1..fb22dd6530a22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3610,9 +3610,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.112" +version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" [[package]] name = "libgit2-sys" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 04163c2c4226d..13bf196c4d44e 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -libc = "0.2.112" +libc = "0.2.119" cfg-if = "1.0" log = "0.4.8" parity-wasm = "0.42.0" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index ab7d231e2c17f..3c4401e2d342d 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -17,7 +17,7 @@ ansi_term = "0.12.1" atty = "0.2.13" chrono = "0.4.19" lazy_static = "1.4.0" -libc = "0.2.112" +libc = "0.2.119" log = { version = "0.4.8" } once_cell = "1.8.0" parking_lot = "0.12.0" From 574237b7b603823fb9cb675e0e303a76865180e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Mar 2022 10:50:49 +0000 Subject: [PATCH 0572/1472] Bump parity-db from 0.3.5 to 0.3.8 (#10970) Bumps [parity-db](https://github.com/paritytech/parity-db) from 0.3.5 to 0.3.8. - [Release notes](https://github.com/paritytech/parity-db/releases) - [Commits](https://github.com/paritytech/parity-db/commits/v0.3.8) --- updated-dependencies: - dependency-name: parity-db 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/db/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb22dd6530a22..9cb1eae0a91fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6637,9 +6637,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78a95abf24f1097c6e3181abbbbfc3630b3b5e681470940f719b69acb4911c7f" +checksum = "865edee5b792f537356d9e55cbc138e7f4718dc881a7ea45a18b37bf61c21e3d" dependencies = [ "blake2-rfc", "crc32fast", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 32fa9d463413f..7b1e4da20861e 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -33,7 +33,7 @@ sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-trie = { version = "6.0.0", path = "../../primitives/trie" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -parity-db = { version = "0.3.5", optional = true } +parity-db = { version = "0.3.8", optional = true } [dev-dependencies] sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } From 15b8fd5af658810035ec2757b1a977db17f7aab4 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 3 Mar 2022 23:47:10 +0100 Subject: [PATCH 0573/1472] [EPM pallet]: remove `number of signed submissions` (#10945) * [EPM pallet]: remove `number of signed submissions` Closing #9229 * fix tests * remove needless assert * Update frame/election-provider-multi-phase/src/lib.rs * cargo fmt Signed-off-by: Niklas * fix grumbles * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * drop `num_signed_submissions` in WeightInfo too * fix build Co-authored-by: Parity Bot --- .../src/benchmarking.rs | 10 +- .../election-provider-multi-phase/src/lib.rs | 23 +-- .../election-provider-multi-phase/src/mock.rs | 4 +- .../src/signed.rs | 84 ++++------- .../src/unsigned.rs | 2 +- .../src/weights.rs | 134 ++++++++---------- 6 files changed, 101 insertions(+), 156 deletions(-) diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index cc322cbb4d57e..479afd9843386 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -310,7 +310,6 @@ frame_benchmarking::benchmarks! { } submit { - let c in 1 .. (T::SignedMaxSubmissions::get() - 1); // the solution will be worse than all of them meaning the score need to be checked against // ~ log2(c) @@ -324,7 +323,10 @@ frame_benchmarking::benchmarks! { >::put(1); let mut signed_submissions = SignedSubmissions::::get(); - for i in 0..c { + + // Insert `max - 1` submissions because the call to `submit` will insert another + // submission and the score is worse then the previous scores. + for i in 0..(T::SignedMaxSubmissions::get() - 1) { let raw_solution = RawSolution { score: ElectionScore { minimal_stake: 10_000_000u128 + (i as u128), ..Default::default() }, ..Default::default() @@ -342,9 +344,9 @@ frame_benchmarking::benchmarks! { let caller = frame_benchmarking::whitelisted_caller(); T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance() * 10u32.into()); - }: _(RawOrigin::Signed(caller), Box::new(solution), c) + }: _(RawOrigin::Signed(caller), Box::new(solution)) verify { - assert!(>::signed_submissions().len() as u32 == c + 1); + assert!(>::signed_submissions().len() as u32 == T::SignedMaxSubmissions::get()); } submit_unsigned { diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 8b4ae60facb5f..7e211c5ee9211 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -963,25 +963,13 @@ pub mod pallet { /// /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution /// might be rewarded, slashed, or get all or a part of the deposit back. - /// - /// # - /// Queue size must be provided as witness data. - /// # - #[pallet::weight(T::WeightInfo::submit(*num_signed_submissions))] + #[pallet::weight(T::WeightInfo::submit())] pub fn submit( origin: OriginFor, raw_solution: Box>>, - num_signed_submissions: u32, ) -> DispatchResult { let who = ensure_signed(origin)?; - // ensure witness data is correct. - ensure!( - num_signed_submissions >= - >::decode_len().unwrap_or_default() as u32, - Error::::SignedInvalidWitness, - ); - // ensure solution is timely. ensure!(Self::current_phase().is_signed(), Error::::PreDispatchEarlySubmission); @@ -1000,8 +988,7 @@ pub mod pallet { // create the submission let deposit = Self::deposit_for(&raw_solution, size); let reward = { - let call = - Call::submit { raw_solution: raw_solution.clone(), num_signed_submissions }; + let call = Call::submit { raw_solution: raw_solution.clone() }; let call_fee = T::EstimateCallFee::estimate_call_fee(&call, None.into()); T::SignedRewardBase::get().saturating_add(call_fee) }; @@ -1970,11 +1957,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit( - crate::mock::Origin::signed(99), - Box::new(solution), - MultiPhase::signed_submissions().len() as u32 - )); + assert_ok!(MultiPhase::submit(crate::mock::Origin::signed(99), Box::new(solution))); } // an unexpected call to elect. diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 9ac0ecfef5dce..7c7034ac91a83 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -343,11 +343,11 @@ impl multi_phase::weights::WeightInfo for DualMockWeightInfo { <() as multi_phase::weights::WeightInfo>::finalize_signed_phase_reject_solution() } } - fn submit(c: u32) -> Weight { + fn submit() -> Weight { if MockWeightInfo::get() { Zero::zero() } else { - <() as multi_phase::weights::WeightInfo>::submit(c) + <() as multi_phase::weights::WeightInfo>::submit() } } fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight { diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 4362fb5127e74..a233346b4fd77 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -500,18 +500,7 @@ mod tests { }, Error, Phase, }; - use frame_support::{assert_noop, assert_ok, assert_storage_noop, dispatch::DispatchResult}; - - fn submit_with_witness( - origin: Origin, - solution: RawSolution>, - ) -> DispatchResult { - MultiPhase::submit( - origin, - Box::new(solution), - MultiPhase::signed_submissions().len() as u32, - ) - } + use frame_support::{assert_noop, assert_ok, assert_storage_noop}; #[test] fn cannot_submit_too_early() { @@ -524,31 +513,12 @@ mod tests { let solution = raw_solution(); assert_noop!( - submit_with_witness(Origin::signed(10), solution), + MultiPhase::submit(Origin::signed(10), Box::new(solution)), Error::::PreDispatchEarlySubmission, ); }) } - #[test] - fn wrong_witness_fails() { - ExtBuilder::default().build_and_execute(|| { - roll_to(15); - assert!(MultiPhase::current_phase().is_signed()); - - let solution = raw_solution(); - // submit this once correctly - assert_ok!(submit_with_witness(Origin::signed(99), solution.clone())); - assert_eq!(MultiPhase::signed_submissions().len(), 1); - - // now try and cheat by passing a lower queue length - assert_noop!( - MultiPhase::submit(Origin::signed(99), Box::new(solution), 0), - Error::::SignedInvalidWitness, - ); - }) - } - #[test] fn should_pay_deposit() { ExtBuilder::default().build_and_execute(|| { @@ -558,7 +528,7 @@ mod tests { let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); assert_eq!(MultiPhase::signed_submissions().iter().next().unwrap().deposit, 5); @@ -574,7 +544,7 @@ mod tests { let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); assert!(MultiPhase::finalize_signed_phase()); @@ -594,7 +564,7 @@ mod tests { // make the solution invalid. solution.score.minimal_stake += 1; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); // no good solution was stored. @@ -615,11 +585,11 @@ mod tests { assert_eq!(balances(&999), (100, 0)); // submit as correct. - assert_ok!(submit_with_witness(Origin::signed(99), solution.clone())); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution.clone()))); // make the solution invalid and weaker. solution.score.minimal_stake -= 1; - assert_ok!(submit_with_witness(Origin::signed(999), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); assert_eq!(balances(&999), (95, 5)); @@ -645,7 +615,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); } // weaker. @@ -655,7 +625,7 @@ mod tests { }; assert_noop!( - submit_with_witness(Origin::signed(99), solution), + MultiPhase::submit(Origin::signed(99), Box::new(solution)), Error::::SignedQueueFull, ); }) @@ -673,7 +643,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); } assert_eq!( @@ -689,7 +659,7 @@ mod tests { score: ElectionScore { minimal_stake: 20, ..Default::default() }, ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); // the one with score 5 was rejected, the new one inserted. assert_eq!( @@ -714,14 +684,14 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); } let solution = RawSolution { score: ElectionScore { minimal_stake: 4, ..Default::default() }, ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); assert_eq!( MultiPhase::signed_submissions() @@ -736,7 +706,7 @@ mod tests { score: ElectionScore { minimal_stake: 5, ..Default::default() }, ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); // the one with score 5 was rejected, the new one inserted. assert_eq!( @@ -761,7 +731,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); } assert_eq!(balances(&99).1, 2 * 5); @@ -772,7 +742,7 @@ mod tests { score: ElectionScore { minimal_stake: 20, ..Default::default() }, ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(999), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution))); // got one bond back. assert_eq!(balances(&99).1, 2 * 4); @@ -791,7 +761,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + i).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); } assert_eq!( MultiPhase::signed_submissions() @@ -807,7 +777,7 @@ mod tests { ..Default::default() }; assert_noop!( - submit_with_witness(Origin::signed(99), solution), + MultiPhase::submit(Origin::signed(99), Box::new(solution)), Error::::SignedQueueFull, ); }) @@ -829,18 +799,18 @@ mod tests { let solution = raw_solution(); // submit a correct one. - assert_ok!(submit_with_witness(Origin::signed(99), solution.clone())); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution.clone()))); // make the solution invalidly better and submit. This ought to be slashed. let mut solution_999 = solution.clone(); solution_999.score.minimal_stake += 1; - assert_ok!(submit_with_witness(Origin::signed(999), solution_999)); + assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution_999))); // make the solution invalidly worse and submit. This ought to be suppressed and // returned. let mut solution_9999 = solution.clone(); solution_9999.score.minimal_stake -= 1; - assert_ok!(submit_with_witness(Origin::signed(9999), solution_9999)); + assert_ok!(MultiPhase::submit(Origin::signed(9999), Box::new(solution_9999))); assert_eq!( MultiPhase::signed_submissions().iter().map(|x| x.who).collect::>(), @@ -881,14 +851,14 @@ mod tests { assert_eq!(raw.solution.voter_count(), 5); assert_eq!(::SignedMaxWeight::get(), 40); - assert_ok!(submit_with_witness(Origin::signed(99), raw.clone())); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(raw.clone()))); ::set(30); // note: resubmitting the same solution is technically okay as long as the queue has // space. assert_noop!( - submit_with_witness(Origin::signed(99), raw), + MultiPhase::submit(Origin::signed(99), Box::new(raw)), Error::::SignedTooMuchWeight, ); }) @@ -904,7 +874,7 @@ mod tests { assert_eq!(balances(&123), (0, 0)); assert_noop!( - submit_with_witness(Origin::signed(123), solution), + MultiPhase::submit(Origin::signed(123), Box::new(solution)), Error::::SignedCannotPayDeposit, ); @@ -926,7 +896,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); } // this solution has a higher score than any in the queue @@ -940,7 +910,7 @@ mod tests { assert_eq!(balances(&123), (0, 0)); assert_noop!( - submit_with_witness(Origin::signed(123), solution), + MultiPhase::submit(Origin::signed(123), Box::new(solution)), Error::::SignedCannotPayDeposit, ); @@ -969,7 +939,7 @@ mod tests { let solution = raw_solution(); // submit a correct one. - assert_ok!(submit_with_witness(Origin::signed(99), solution.clone())); + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); // _some_ good solution was stored. assert!(MultiPhase::finalize_signed_phase()); diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 510fc9fcdcca9..81ea4453d0964 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -662,7 +662,7 @@ mod max_weight { fn finalize_signed_phase_reject_solution() -> Weight { unreachable!() } - fn submit(c: u32) -> Weight { + fn submit() -> Weight { unreachable!() } fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight { diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 99e149eff2410..54c519681922b 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_election_provider_multi_phase //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-03-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -33,9 +33,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/election-provider-multi-phase/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -53,7 +51,7 @@ pub trait WeightInfo { fn finalize_signed_phase_reject_solution() -> Weight; fn create_snapshot_internal(v: u32, t: u32, ) -> Weight; fn elect_queued(a: u32, d: u32, ) -> Weight; - fn submit(c: u32, ) -> Weight; + fn submit() -> Weight; fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight; fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight; } @@ -70,33 +68,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (12_763_000 as Weight) + (13_342_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (13_195_000 as Weight) + (13_503_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (12_782_000 as Weight) + (13_688_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (27_421_000 as Weight) + (29_124_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (21_325_000 as Weight) + (21_950_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -104,11 +102,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (0 as Weight) + (17_274_000 as Weight) // Standard Error: 1_000 - .saturating_add((216_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((191_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 3_000 - .saturating_add((51_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -121,24 +119,22 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (38_368_000 as Weight) + (145_826_000 as Weight) // Standard Error: 4_000 - .saturating_add((1_414_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 7_000 - .saturating_add((175_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((604_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 6_000 + .saturating_add((72_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } - // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) - fn submit(c: u32, ) -> Weight { - (39_488_000 as Weight) - // Standard Error: 22_000 - .saturating_add((230_000 as Weight).saturating_mul(c as Weight)) + fn submit() -> Weight { + (41_579_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -151,14 +147,14 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_000 - .saturating_add((1_544_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 5_000 - .saturating_add((60_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 9_000 - .saturating_add((6_555_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 14_000 - .saturating_add((1_318_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 3_000 + .saturating_add((882_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 7_000 + .saturating_add((144_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 12_000 + .saturating_add((6_534_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 18_000 + .saturating_add((1_312_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -166,16 +162,14 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { + fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((1_527_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 6_000 - .saturating_add((151_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 10_000 - .saturating_add((5_433_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 15_000 - .saturating_add((1_420_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((835_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 12_000 + .saturating_add((5_395_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 19_000 + .saturating_add((1_243_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) } } @@ -191,33 +185,33 @@ impl WeightInfo for () { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (12_763_000 as Weight) + (13_342_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (13_195_000 as Weight) + (13_503_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (12_782_000 as Weight) + (13_688_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (27_421_000 as Weight) + (29_124_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (21_325_000 as Weight) + (21_950_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -225,11 +219,11 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (0 as Weight) + (17_274_000 as Weight) // Standard Error: 1_000 - .saturating_add((216_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((191_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 3_000 - .saturating_add((51_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -242,24 +236,22 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (38_368_000 as Weight) + (145_826_000 as Weight) // Standard Error: 4_000 - .saturating_add((1_414_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 7_000 - .saturating_add((175_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((604_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 6_000 + .saturating_add((72_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } - // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) - fn submit(c: u32, ) -> Weight { - (39_488_000 as Weight) - // Standard Error: 22_000 - .saturating_add((230_000 as Weight).saturating_mul(c as Weight)) + fn submit() -> Weight { + (41_579_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -272,14 +264,14 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_000 - .saturating_add((1_544_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 5_000 - .saturating_add((60_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 9_000 - .saturating_add((6_555_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 14_000 - .saturating_add((1_318_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 3_000 + .saturating_add((882_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 7_000 + .saturating_add((144_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 12_000 + .saturating_add((6_534_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 18_000 + .saturating_add((1_312_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -287,16 +279,14 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { + fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((1_527_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 6_000 - .saturating_add((151_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 10_000 - .saturating_add((5_433_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 15_000 - .saturating_add((1_420_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((835_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 12_000 + .saturating_add((5_395_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 19_000 + .saturating_add((1_243_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) } } From 9b5e654074655737ac041d059d88bfd68593b069 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 4 Mar 2022 11:30:29 +0100 Subject: [PATCH 0574/1472] Refactored block body database scheme (#10779) * Refactored tx storage database scheme * Bump parity-db * fmt * Fix handling invalid index size + test * Removed superflous result * Minor changes * fmt --- bin/node/cli/benches/block_production.rs | 3 +- bin/node/cli/benches/transaction_pool.rs | 3 +- bin/node/testing/src/bench.rs | 1 - client/cli/src/config.rs | 11 +- client/cli/src/params/database_params.rs | 19 - client/db/src/lib.rs | 473 ++++++++++++----------- client/db/src/parity_db.rs | 18 +- client/db/src/upgrade.rs | 42 +- client/db/src/utils.rs | 17 +- client/service/src/builder.rs | 14 +- client/service/src/config.rs | 4 +- client/service/src/lib.rs | 1 - client/service/test/src/client/mod.rs | 6 +- client/service/test/src/lib.rs | 3 +- test-utils/client/src/lib.rs | 6 +- 15 files changed, 329 insertions(+), 292 deletions(-) diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 69e9e0076a165..77b51fa28dd1a 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -29,7 +29,7 @@ use sc_consensus::{ use sc_service::{ config::{ DatabaseSource, KeepBlocks, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, - PruningMode, TransactionStorageMode, WasmExecutionMethod, + PruningMode, WasmExecutionMethod, }, BasePath, Configuration, Role, }; @@ -76,7 +76,6 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { state_cache_child_ratio: None, state_pruning: PruningMode::ArchiveAll, keep_blocks: KeepBlocks::All, - transaction_storage: TransactionStorageMode::BlockBody, chain_spec: spec, wasm_method: WasmExecutionMethod::Compiled, execution_strategies: ExecutionStrategies { diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index 9baa3e7fc117d..e89527f2333a2 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -25,7 +25,7 @@ use sc_client_api::execution_extensions::ExecutionStrategies; use sc_service::{ config::{ DatabaseSource, KeepBlocks, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, - PruningMode, TransactionPoolOptions, TransactionStorageMode, WasmExecutionMethod, + PruningMode, TransactionPoolOptions, WasmExecutionMethod, }, BasePath, Configuration, Role, }; @@ -67,7 +67,6 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { state_cache_child_ratio: None, state_pruning: PruningMode::ArchiveAll, keep_blocks: KeepBlocks::All, - transaction_storage: TransactionStorageMode::BlockBody, chain_spec: spec, wasm_method: WasmExecutionMethod::Interpreted, // NOTE: we enforce the use of the native runtime to make the errors more debuggable diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 18333280bb8a4..8227582d88a4b 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -393,7 +393,6 @@ impl BenchDb { state_pruning: PruningMode::ArchiveAll, source: database_type.into_settings(dir.into()), keep_blocks: sc_client_db::KeepBlocks::All, - transaction_storage: sc_client_db::TransactionStorageMode::BlockBody, }; let task_executor = TaskExecutor::new(); diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index b5470db91db3a..a40be77f65aa0 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -31,7 +31,7 @@ use sc_service::{ NodeKeyConfig, OffchainWorkerConfig, PrometheusConfig, PruningMode, Role, RpcMethods, TelemetryEndpoints, TransactionPoolOptions, WasmExecutionMethod, }, - ChainSpec, KeepBlocks, TracingReceiver, TransactionStorageMode, + ChainSpec, KeepBlocks, TracingReceiver, }; use sc_tracing::logging::LoggerBuilder; use std::{net::SocketAddr, path::PathBuf}; @@ -198,14 +198,6 @@ pub trait CliConfiguration: Sized { Ok(self.database_params().map(|x| x.database_cache_size()).unwrap_or_default()) } - /// Get the database transaction storage scheme. - fn database_transaction_storage(&self) -> Result { - Ok(self - .database_params() - .map(|x| x.transaction_storage()) - .unwrap_or(TransactionStorageMode::BlockBody)) - } - /// Get the database backend variant. /// /// By default this is retrieved from `DatabaseParams` if it is available. Otherwise its `None`. @@ -519,7 +511,6 @@ pub trait CliConfiguration: Sized { state_cache_child_ratio: self.state_cache_child_ratio()?, state_pruning: self.state_pruning(unsafe_pruning, &role)?, keep_blocks: self.keep_blocks()?, - transaction_storage: self.database_transaction_storage()?, wasm_method: self.wasm_method()?, wasm_runtime_overrides: self.wasm_runtime_overrides(), execution_strategies: self.execution_strategies(is_dev, is_validator)?, diff --git a/client/cli/src/params/database_params.rs b/client/cli/src/params/database_params.rs index 70c929ecf202f..e954b8cc3bc20 100644 --- a/client/cli/src/params/database_params.rs +++ b/client/cli/src/params/database_params.rs @@ -18,7 +18,6 @@ use crate::arg_enums::Database; use clap::Args; -use sc_service::TransactionStorageMode; /// Parameters for block import. #[derive(Debug, Clone, PartialEq, Args)] @@ -36,15 +35,6 @@ pub struct DatabaseParams { /// Limit the memory the database cache can use. #[clap(long = "db-cache", value_name = "MiB")] pub database_cache_size: Option, - - /// Enable storage chain mode - /// - /// This changes the storage format for blocks bodies. - /// If this is enabled, each transaction is stored separately in the - /// transaction database column and is only referenced by hash - /// in the block body column. - #[clap(long)] - pub storage_chain: bool, } impl DatabaseParams { @@ -57,13 +47,4 @@ impl DatabaseParams { pub fn database_cache_size(&self) -> Option { self.database_cache_size } - - /// Transaction storage scheme. - pub fn transaction_storage(&self) -> TransactionStorageMode { - if self.storage_chain { - TransactionStorageMode::StorageChain - } else { - TransactionStorageMode::BlockBody - } - } } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 3fd3bf8d09042..f451062de33ab 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -111,13 +111,18 @@ pub const DB_HASH_LEN: usize = 32; /// Hash type that this backend uses for the database. pub type DbHash = sp_core::H256; -/// This is used as block body when storage-chain mode is enabled. +/// An extrinsic entry in the database. #[derive(Debug, Encode, Decode)] -struct ExtrinsicHeader { - /// Hash of the indexed part - indexed_hash: DbHash, // Zero hash if there's no indexed data - /// The rest of the data. - data: Vec, +enum DbExtrinsic { + /// Extrinsic that contains indexed data. + Indexed { + /// Hash of the indexed part. + hash: DbHash, + /// Extrinsic header. + header: Vec, + }, + /// Complete extrinsic data. + Full(B::Extrinsic), } /// A reference tracking state. @@ -295,8 +300,6 @@ pub struct DatabaseSettings { pub source: DatabaseSource, /// Block pruning mode. pub keep_blocks: KeepBlocks, - /// Block body/Transaction storage scheme. - pub transaction_storage: TransactionStorageMode, } /// Block pruning settings. @@ -308,16 +311,6 @@ pub enum KeepBlocks { Some(u32), } -/// Block body storage scheme. -#[derive(Debug, Clone, Copy)] -pub enum TransactionStorageMode { - /// Store block body as an encoded list of full transactions in the BODY column - BlockBody, - /// Store a list of hashes in the BODY column and each transaction individually - /// in the TRANSACTION column. - StorageChain, -} - /// Where to find the database.. #[derive(Debug, Clone)] pub enum DatabaseSource { @@ -406,6 +399,7 @@ pub(crate) mod columns { pub const OFFCHAIN: u32 = 9; /// Transactions pub const TRANSACTION: u32 = 11; + pub const BODY_INDEX: u32 = 12; } struct PendingBlock { @@ -453,14 +447,10 @@ pub struct BlockchainDb { leaves: RwLock>>, header_metadata_cache: Arc>, header_cache: Mutex>>, - transaction_storage: TransactionStorageMode, } impl BlockchainDb { - fn new( - db: Arc>, - transaction_storage: TransactionStorageMode, - ) -> ClientResult { + fn new(db: Arc>) -> ClientResult { let meta = read_meta::(&*db, columns::HEADER)?; let leaves = LeafSet::read_from_db(&*db, columns::META, meta_keys::LEAF_PREFIX)?; Ok(BlockchainDb { @@ -469,7 +459,6 @@ impl BlockchainDb { meta: Arc::new(RwLock::new(meta)), header_metadata_cache: Arc::new(HeaderMetadataCache::default()), header_cache: Default::default(), - transaction_storage, }) } @@ -558,59 +547,61 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha impl sc_client_api::blockchain::Backend for BlockchainDb { fn body(&self, id: BlockId) -> ClientResult>> { - let body = match read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY, id)? { - Some(body) => body, - None => return Ok(None), - }; - match self.transaction_storage { - TransactionStorageMode::BlockBody => match Decode::decode(&mut &body[..]) { - Ok(body) => Ok(Some(body)), + if let Some(body) = read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY, id)? { + // Plain body + match Decode::decode(&mut &body[..]) { + Ok(body) => return Ok(Some(body)), Err(err) => return Err(sp_blockchain::Error::Backend(format!( "Error decoding body: {}", err ))), - }, - TransactionStorageMode::StorageChain => { - match Vec::::decode(&mut &body[..]) { - Ok(index) => { - let extrinsics: ClientResult> = index - .into_iter() - .map(|ExtrinsicHeader { indexed_hash, data }| { - let decode_result = if indexed_hash != Default::default() { - match self.db.get(columns::TRANSACTION, indexed_hash.as_ref()) { - Some(t) => { - let mut input = - utils::join_input(data.as_ref(), t.as_ref()); - Block::Extrinsic::decode(&mut input) - }, - None => - return Err(sp_blockchain::Error::Backend(format!( - "Missing indexed transaction {:?}", - indexed_hash - ))), - } - } else { - Block::Extrinsic::decode(&mut data.as_ref()) + } + } + + if let Some(index) = read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY_INDEX, id)? { + match Vec::>::decode(&mut &index[..]) { + Ok(index) => { + let mut body = Vec::new(); + for ex in index { + match ex { + DbExtrinsic::Indexed { hash, header } => { + match self.db.get(columns::TRANSACTION, hash.as_ref()) { + Some(t) => { + let mut input = + utils::join_input(header.as_ref(), t.as_ref()); + let ex = Block::Extrinsic::decode(&mut input).map_err( + |err| { + sp_blockchain::Error::Backend(format!( + "Error decoding indexed extrinsic: {}", + err + )) + }, + )?; + body.push(ex); + }, + None => + return Err(sp_blockchain::Error::Backend(format!( + "Missing indexed transaction {:?}", + hash + ))), }; - decode_result.map_err(|err| { - sp_blockchain::Error::Backend(format!( - "Error decoding extrinsic: {}", - err - )) - }) - }) - .collect(); - Ok(Some(extrinsics?)) - }, - Err(err) => - return Err(sp_blockchain::Error::Backend(format!( - "Error decoding body list: {}", - err - ))), - } - }, + }, + DbExtrinsic::Full(ex) => { + body.push(ex); + }, + } + } + return Ok(Some(body)) + }, + Err(err) => + return Err(sp_blockchain::Error::Backend(format!( + "Error decoding body list: {}", + err + ))), + } } + Ok(None) } fn justifications(&self, id: BlockId) -> ClientResult> { @@ -648,37 +639,29 @@ impl sc_client_api::blockchain::Backend for BlockchainDb) -> ClientResult>>> { - match self.transaction_storage { - TransactionStorageMode::BlockBody => Ok(None), - TransactionStorageMode::StorageChain => { - let body = match read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY, id)? { - Some(body) => body, - None => return Ok(None), - }; - match Vec::::decode(&mut &body[..]) { - Ok(index) => { - let mut transactions = Vec::new(); - for ExtrinsicHeader { indexed_hash, .. } in index.into_iter() { - if indexed_hash != Default::default() { - match self.db.get(columns::TRANSACTION, indexed_hash.as_ref()) { - Some(t) => transactions.push(t), - None => - return Err(sp_blockchain::Error::Backend(format!( - "Missing indexed transaction {:?}", - indexed_hash - ))), - } - } + let body = match read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY_INDEX, id)? { + Some(body) => body, + None => return Ok(None), + }; + match Vec::>::decode(&mut &body[..]) { + Ok(index) => { + let mut transactions = Vec::new(); + for ex in index.into_iter() { + if let DbExtrinsic::Indexed { hash, .. } = ex { + match self.db.get(columns::TRANSACTION, hash.as_ref()) { + Some(t) => transactions.push(t), + None => + return Err(sp_blockchain::Error::Backend(format!( + "Missing indexed transaction {:?}", + hash + ))), } - Ok(Some(transactions)) - }, - Err(err) => - return Err(sp_blockchain::Error::Backend(format!( - "Error decoding body list: {}", - err - ))), + } } + Ok(Some(transactions)) }, + Err(err) => + Err(sp_blockchain::Error::Backend(format!("Error decoding body list: {}", err))), } } } @@ -1005,7 +988,6 @@ pub struct Backend { import_lock: Arc>, is_archive: bool, keep_blocks: KeepBlocks, - transaction_storage: TransactionStorageMode, io_stats: FrozenForDuration<(kvdb::IoStats, StateUsageInfo)>, state_usage: Arc, genesis_state: RwLock>>>, @@ -1023,20 +1005,12 @@ impl Backend { /// Create new memory-backed client backend for tests. #[cfg(any(test, feature = "test-helpers"))] pub fn new_test(keep_blocks: u32, canonicalization_delay: u64) -> Self { - Self::new_test_with_tx_storage( - keep_blocks, - canonicalization_delay, - TransactionStorageMode::BlockBody, - ) + Self::new_test_with_tx_storage(keep_blocks, canonicalization_delay) } /// Create new memory-backed client backend for tests. #[cfg(any(test, feature = "test-helpers"))] - pub fn new_test_with_tx_storage( - keep_blocks: u32, - canonicalization_delay: u64, - transaction_storage: TransactionStorageMode, - ) -> Self { + pub fn new_test_with_tx_storage(keep_blocks: u32, canonicalization_delay: u64) -> Self { let db = kvdb_memorydb::create(crate::utils::NUM_COLUMNS); let db = sp_database::as_database(db); let db_setting = DatabaseSettings { @@ -1045,7 +1019,6 @@ impl Backend { state_pruning: PruningMode::keep_blocks(keep_blocks), source: DatabaseSource::Custom(db), keep_blocks: KeepBlocks::Some(keep_blocks), - transaction_storage, }; Self::new(db_setting, canonicalization_delay).expect("failed to create test-db") @@ -1074,7 +1047,7 @@ impl Backend { config: &DatabaseSettings, ) -> ClientResult { let is_archive_pruning = config.state_pruning.is_archive(); - let blockchain = BlockchainDb::new(db.clone(), config.transaction_storage.clone())?; + let blockchain = BlockchainDb::new(db.clone())?; let map_e = |e: sc_state_db::Error| sp_blockchain::Error::from_state_db(e); let state_db: StateDb<_, _> = StateDb::new( config.state_pruning.clone(), @@ -1100,7 +1073,6 @@ impl Backend { io_stats: FrozenForDuration::new(std::time::Duration::from_secs(1)), state_usage: Arc::new(StateUsageStats::new()), keep_blocks: config.keep_blocks.clone(), - transaction_storage: config.transaction_storage.clone(), genesis_state: RwLock::new(None), }; @@ -1334,26 +1306,18 @@ impl Backend { transaction.set_from_vec(columns::HEADER, &lookup_key, pending_block.header.encode()); if let Some(body) = pending_block.body { - match self.transaction_storage { - TransactionStorageMode::BlockBody => { - transaction.set_from_vec(columns::BODY, &lookup_key, body.encode()); - }, - TransactionStorageMode::StorageChain => { - let body = - apply_index_ops::(&mut transaction, body, operation.index_ops); - transaction.set_from_vec(columns::BODY, &lookup_key, body); - }, + // If we have any index operations we save block in the new format with indexed + // extrinsic headers Otherwise we save the body as a single blob. + if operation.index_ops.is_empty() { + transaction.set_from_vec(columns::BODY, &lookup_key, body.encode()); + } else { + let body = + apply_index_ops::(&mut transaction, body, operation.index_ops); + transaction.set_from_vec(columns::BODY_INDEX, &lookup_key, body); } } if let Some(body) = pending_block.indexed_body { - match self.transaction_storage { - TransactionStorageMode::BlockBody => { - debug!(target: "db", "Commit: ignored indexed block body"); - }, - TransactionStorageMode::StorageChain => { - apply_indexed_body::(&mut transaction, body); - }, - } + apply_indexed_body::(&mut transaction, body); } if let Some(justifications) = pending_block.justifications { transaction.set_from_vec( @@ -1691,7 +1655,7 @@ impl Backend { let mut hash = h.clone(); // Follow displaced chains back until we reach a finalized block. // Since leaves are discarded due to finality, they can't have parents - // that are canonical, but not yet finalized. So we stop deletig as soon as + // that are canonical, but not yet finalized. So we stop deleting as soon as // we reach canonical chain. while self.blockchain.hash(number)? != Some(hash.clone()) { let id = BlockId::::hash(hash.clone()); @@ -1714,36 +1678,37 @@ impl Backend { transaction: &mut Transaction, id: BlockId, ) -> ClientResult<()> { - match read_db(&*self.storage.db, columns::KEY_LOOKUP, columns::BODY, id)? { - Some(body) => { - debug!(target: "db", "Removing block #{}", id); - utils::remove_from_db( - transaction, - &*self.storage.db, - columns::KEY_LOOKUP, - columns::BODY, - id, - )?; - match self.transaction_storage { - TransactionStorageMode::BlockBody => {}, - TransactionStorageMode::StorageChain => { - match Vec::::decode(&mut &body[..]) { - Ok(body) => - for ExtrinsicHeader { indexed_hash, .. } in body { - if indexed_hash != Default::default() { - transaction.release(columns::TRANSACTION, indexed_hash); - } - }, - Err(err) => - return Err(sp_blockchain::Error::Backend(format!( - "Error decoding body list: {}", - err - ))), + debug!(target: "db", "Removing block #{}", id); + utils::remove_from_db( + transaction, + &*self.storage.db, + columns::KEY_LOOKUP, + columns::BODY, + id, + )?; + if let Some(index) = + read_db(&*self.storage.db, columns::KEY_LOOKUP, columns::BODY_INDEX, id)? + { + utils::remove_from_db( + transaction, + &*self.storage.db, + columns::KEY_LOOKUP, + columns::BODY_INDEX, + id, + )?; + match Vec::>::decode(&mut &index[..]) { + Ok(index) => + for ex in index { + if let DbExtrinsic::Indexed { hash, .. } = ex { + transaction.release(columns::TRANSACTION, hash); } }, - } - }, - None => return Ok(()), + Err(err) => + return Err(sp_blockchain::Error::Backend(format!( + "Error decoding body list: {}", + err + ))), + } } Ok(()) } @@ -1785,7 +1750,7 @@ fn apply_index_ops( body: Vec, ops: Vec, ) -> Vec { - let mut extrinsic_headers: Vec = Vec::with_capacity(body.len()); + let mut extrinsic_index: Vec> = Vec::with_capacity(body.len()); let mut index_map = HashMap::new(); let mut renewed_map = HashMap::new(); for op in ops { @@ -1799,37 +1764,44 @@ fn apply_index_ops( } } for (index, extrinsic) in body.into_iter().enumerate() { - let extrinsic = extrinsic.encode(); - let extrinsic_header = if let Some(hash) = renewed_map.get(&(index as u32)) { + let db_extrinsic = if let Some(hash) = renewed_map.get(&(index as u32)) { // Bump ref counter + let extrinsic = extrinsic.encode(); transaction.reference(columns::TRANSACTION, DbHash::from_slice(hash.as_ref())); - ExtrinsicHeader { indexed_hash: hash.clone(), data: extrinsic } + DbExtrinsic::Indexed { hash: hash.clone(), header: extrinsic } } else { match index_map.get(&(index as u32)) { - Some((hash, size)) if *size as usize <= extrinsic.len() => { - let offset = extrinsic.len() - *size as usize; - transaction.store( - columns::TRANSACTION, - DbHash::from_slice(hash.as_ref()), - extrinsic[offset..].to_vec(), - ); - ExtrinsicHeader { - indexed_hash: DbHash::from_slice(hash.as_ref()), - data: extrinsic[..offset].to_vec(), + Some((hash, size)) => { + let encoded = extrinsic.encode(); + if *size as usize <= encoded.len() { + let offset = encoded.len() - *size as usize; + transaction.store( + columns::TRANSACTION, + DbHash::from_slice(hash.as_ref()), + encoded[offset..].to_vec(), + ); + DbExtrinsic::Indexed { + hash: DbHash::from_slice(hash.as_ref()), + header: encoded[..offset].to_vec(), + } + } else { + // Invalid indexed slice. Just store full data and don't index anything. + DbExtrinsic::Full(extrinsic) } }, - _ => ExtrinsicHeader { indexed_hash: Default::default(), data: extrinsic }, + _ => DbExtrinsic::Full(extrinsic), } }; - extrinsic_headers.push(extrinsic_header); + extrinsic_index.push(db_extrinsic); } debug!( target: "db", - "DB transaction index: {} inserted, {} renewed", + "DB transaction index: {} inserted, {} renewed, {} full", index_map.len(), - renewed_map.len() + renewed_map.len(), + extrinsic_index.len() - index_map.len() - renewed_map.len(), ); - extrinsic_headers.encode() + extrinsic_index.encode() } fn apply_indexed_body(transaction: &mut Transaction, body: Vec>) { @@ -2417,7 +2389,6 @@ pub(crate) mod tests { state_pruning: PruningMode::keep_blocks(1), source: DatabaseSource::Custom(backing), keep_blocks: KeepBlocks::All, - transaction_storage: TransactionStorageMode::BlockBody, }, 0, ) @@ -3087,46 +3058,43 @@ pub(crate) mod tests { #[test] fn prune_blocks_on_finalize() { - for storage in &[TransactionStorageMode::BlockBody, TransactionStorageMode::StorageChain] { - let backend = Backend::::new_test_with_tx_storage(2, 0, *storage); - let mut blocks = Vec::new(); - let mut prev_hash = Default::default(); - for i in 0..5 { - let hash = insert_block( - &backend, - i, - prev_hash, - None, - Default::default(), - vec![i.into()], - None, - ) - .unwrap(); - blocks.push(hash); - prev_hash = hash; - } + let backend = Backend::::new_test_with_tx_storage(2, 0); + let mut blocks = Vec::new(); + let mut prev_hash = Default::default(); + for i in 0..5 { + let hash = insert_block( + &backend, + i, + prev_hash, + None, + Default::default(), + vec![i.into()], + None, + ) + .unwrap(); + blocks.push(hash); + prev_hash = hash; + } - { - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); - for i in 1..5 { - op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); - } - backend.commit_operation(op).unwrap(); + { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + for i in 1..5 { + op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); } - let bc = backend.blockchain(); - assert_eq!(None, bc.body(BlockId::hash(blocks[0])).unwrap()); - assert_eq!(None, bc.body(BlockId::hash(blocks[1])).unwrap()); - assert_eq!(None, bc.body(BlockId::hash(blocks[2])).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); + backend.commit_operation(op).unwrap(); } + let bc = backend.blockchain(); + assert_eq!(None, bc.body(BlockId::hash(blocks[0])).unwrap()); + assert_eq!(None, bc.body(BlockId::hash(blocks[1])).unwrap()); + assert_eq!(None, bc.body(BlockId::hash(blocks[2])).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); } #[test] fn prune_blocks_on_finalize_with_fork() { - let backend = - Backend::::new_test_with_tx_storage(2, 10, TransactionStorageMode::StorageChain); + let backend = Backend::::new_test_with_tx_storage(2, 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); for i in 0..5 { @@ -3185,10 +3153,86 @@ pub(crate) mod tests { assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); } + #[test] + fn indexed_data_block_body() { + let backend = Backend::::new_test_with_tx_storage(1, 10); + + let x0 = ExtrinsicWrapper::from(0u64).encode(); + let x1 = ExtrinsicWrapper::from(1u64).encode(); + let x0_hash = as sp_core::Hasher>::hash(&x0[1..]); + let x1_hash = as sp_core::Hasher>::hash(&x1[1..]); + let index = vec![ + IndexOperation::Insert { + extrinsic: 0, + hash: x0_hash.as_ref().to_vec(), + size: (x0.len() - 1) as u32, + }, + IndexOperation::Insert { + extrinsic: 1, + hash: x1_hash.as_ref().to_vec(), + size: (x1.len() - 1) as u32, + }, + ]; + let hash = insert_block( + &backend, + 0, + Default::default(), + None, + Default::default(), + vec![0u64.into(), 1u64.into()], + Some(index), + ) + .unwrap(); + let bc = backend.blockchain(); + assert_eq!(bc.indexed_transaction(&x0_hash).unwrap().unwrap(), &x0[1..]); + assert_eq!(bc.indexed_transaction(&x1_hash).unwrap().unwrap(), &x1[1..]); + + // Push one more blocks and make sure block is pruned and transaction index is cleared. + insert_block(&backend, 1, hash, None, Default::default(), vec![], None).unwrap(); + backend.finalize_block(BlockId::Number(1), None).unwrap(); + assert_eq!(bc.body(BlockId::Number(0)).unwrap(), None); + assert_eq!(bc.indexed_transaction(&x0_hash).unwrap(), None); + assert_eq!(bc.indexed_transaction(&x1_hash).unwrap(), None); + } + + #[test] + fn index_invalid_size() { + let backend = Backend::::new_test_with_tx_storage(1, 10); + + let x0 = ExtrinsicWrapper::from(0u64).encode(); + let x1 = ExtrinsicWrapper::from(1u64).encode(); + let x0_hash = as sp_core::Hasher>::hash(&x0[..]); + let x1_hash = as sp_core::Hasher>::hash(&x1[..]); + let index = vec![ + IndexOperation::Insert { + extrinsic: 0, + hash: x0_hash.as_ref().to_vec(), + size: (x0.len()) as u32, + }, + IndexOperation::Insert { + extrinsic: 1, + hash: x1_hash.as_ref().to_vec(), + size: (x1.len() + 1) as u32, + }, + ]; + insert_block( + &backend, + 0, + Default::default(), + None, + Default::default(), + vec![0u64.into(), 1u64.into()], + Some(index), + ) + .unwrap(); + let bc = backend.blockchain(); + assert_eq!(bc.indexed_transaction(&x0_hash).unwrap().unwrap(), &x0[..]); + assert_eq!(bc.indexed_transaction(&x1_hash).unwrap(), None); + } + #[test] fn renew_transaction_storage() { - let backend = - Backend::::new_test_with_tx_storage(2, 10, TransactionStorageMode::StorageChain); + let backend = Backend::::new_test_with_tx_storage(2, 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); let x1 = ExtrinsicWrapper::from(0u64).encode(); @@ -3235,8 +3279,7 @@ pub(crate) mod tests { #[test] fn remove_leaf_block_works() { - let backend = - Backend::::new_test_with_tx_storage(2, 10, TransactionStorageMode::StorageChain); + let backend = Backend::::new_test_with_tx_storage(2, 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); for i in 0..2 { diff --git a/client/db/src/parity_db.rs b/client/db/src/parity_db.rs index ebe2988e27f04..c27d7b0d4b4db 100644 --- a/client/db/src/parity_db.rs +++ b/client/db/src/parity_db.rs @@ -38,20 +38,22 @@ pub fn open>( path: &std::path::Path, db_type: DatabaseType, create: bool, + upgrade: bool, ) -> parity_db::Result>> { let mut config = parity_db::Options::with_columns(path, NUM_COLUMNS as u8); match db_type { DatabaseType::Full => { - let indexes = [ + let compressed = [ columns::STATE, columns::HEADER, columns::BODY, + columns::BODY_INDEX, columns::TRANSACTION, columns::JUSTIFICATIONS, ]; - for i in indexes { + for i in compressed { let mut column = &mut config.columns[i as usize]; column.compression = parity_db::CompressionType::Lz4; } @@ -60,9 +62,21 @@ pub fn open>( state_col.ref_counted = true; state_col.preimage = true; state_col.uniform = true; + + let mut tx_col = &mut config.columns[columns::TRANSACTION as usize]; + tx_col.ref_counted = true; + tx_col.preimage = true; + tx_col.uniform = true; }, } + if upgrade { + log::info!("Upgrading database metadata."); + if let Some(meta) = parity_db::Options::load_metadata(path)? { + config.write_metadata(path, &meta.salt)?; + } + } + let db = if create { parity_db::Db::open_or_create(&config)? } else { diff --git a/client/db/src/upgrade.rs b/client/db/src/upgrade.rs index a42a1960a57c3..ec91a753ed870 100644 --- a/client/db/src/upgrade.rs +++ b/client/db/src/upgrade.rs @@ -33,11 +33,12 @@ use sp_runtime::traits::Block as BlockT; const VERSION_FILE_NAME: &'static str = "db_version"; /// Current db version. -const CURRENT_VERSION: u32 = 3; +const CURRENT_VERSION: u32 = 4; /// Number of columns in v1. const V1_NUM_COLUMNS: u32 = 11; const V2_NUM_COLUMNS: u32 = 12; +const V3_NUM_COLUMNS: u32 = 12; /// Database upgrade errors. #[derive(Debug)] @@ -68,7 +69,7 @@ impl fmt::Display for UpgradeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { UpgradeError::UnknownDatabaseVersion => { - write!(f, "Database version cannot be read from exisiting db_version file") + write!(f, "Database version cannot be read from existing db_version file") }, UpgradeError::MissingDatabaseVersionFile => write!(f, "Missing database version file"), UpgradeError::UnsupportedVersion(version) => { @@ -92,9 +93,16 @@ pub fn upgrade_db(db_path: &Path, db_type: DatabaseType) -> Upgra 0 => return Err(UpgradeError::UnsupportedVersion(db_version)), 1 => { migrate_1_to_2::(db_path, db_type)?; - migrate_2_to_3::(db_path, db_type)? + migrate_2_to_3::(db_path, db_type)?; + migrate_3_to_4::(db_path, db_type)?; + }, + 2 => { + migrate_2_to_3::(db_path, db_type)?; + migrate_3_to_4::(db_path, db_type)?; + }, + 3 => { + migrate_3_to_4::(db_path, db_type)?; }, - 2 => migrate_2_to_3::(db_path, db_type)?, CURRENT_VERSION => (), _ => return Err(UpgradeError::FutureDatabaseVersion(db_version)), } @@ -139,6 +147,15 @@ fn migrate_2_to_3(db_path: &Path, _db_type: DatabaseType) -> Upgr Ok(()) } +/// Migration from version3 to version4: +/// 1) the number of columns has changed from 12 to 13; +/// 2) BODY_INDEX column is added; +fn migrate_3_to_4(db_path: &Path, _db_type: DatabaseType) -> UpgradeResult<()> { + let db_cfg = DatabaseConfig::with_columns(V3_NUM_COLUMNS); + let db = Database::open(&db_cfg, db_path)?; + db.add_column().map_err(Into::into) +} + /// Reads current database version from the file at given path. /// If the file does not exist returns 0. fn current_version(path: &Path) -> UpgradeResult { @@ -173,9 +190,7 @@ fn version_file_path(path: &Path) -> PathBuf { #[cfg(test)] mod tests { use super::*; - use crate::{ - tests::Block, DatabaseSettings, DatabaseSource, KeepBlocks, TransactionStorageMode, - }; + use crate::{tests::Block, DatabaseSettings, DatabaseSource, KeepBlocks}; use sc_state_db::PruningMode; fn create_db(db_path: &Path, version: Option) { @@ -194,7 +209,6 @@ mod tests { state_pruning: PruningMode::ArchiveAll, source: DatabaseSource::RocksDb { path: db_path.to_owned(), cache_size: 128 }, keep_blocks: KeepBlocks::All, - transaction_storage: TransactionStorageMode::BlockBody, }, db_type, ) @@ -229,4 +243,16 @@ mod tests { assert_eq!(current_version(&db_path).unwrap(), CURRENT_VERSION); } } + + #[test] + fn upgrade_to_4_works() { + let db_type = DatabaseType::Full; + for version_from_file in &[None, Some(1), Some(2), Some(3)] { + let db_dir = tempfile::TempDir::new().unwrap(); + let db_path = db_dir.path().join(db_type.as_str()); + create_db(&db_path, *version_from_file); + open_database(&db_path, db_type).unwrap(); + assert_eq!(current_version(&db_path).unwrap(), CURRENT_VERSION); + } + } } diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index c3a60962a67da..7dcb6676a1750 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -40,7 +40,7 @@ use sp_trie::DBValue; feature = "test-helpers", test ))] -pub const NUM_COLUMNS: u32 = 12; +pub const NUM_COLUMNS: u32 = 13; /// Meta column. The set of keys in the column is shared by full && light storages. pub const COLUMN_META: u32 = 0; @@ -252,7 +252,7 @@ impl From for sp_blockchain::Error { #[cfg(feature = "with-parity-db")] impl From for OpenDbError { fn from(err: parity_db::Error) -> Self { - if err.to_string().contains("use open_or_create") { + if matches!(err, parity_db::Error::DatabaseNotFound) { OpenDbError::DoesNotExist } else { OpenDbError::Internal(err.to_string()) @@ -272,8 +272,14 @@ impl From for OpenDbError { #[cfg(feature = "with-parity-db")] fn open_parity_db(path: &Path, db_type: DatabaseType, create: bool) -> OpenDbResult { - let db = crate::parity_db::open(path, db_type, create)?; - Ok(db) + match crate::parity_db::open(path, db_type, create, false) { + Ok(db) => Ok(db), + Err(parity_db::Error::InvalidConfiguration(_)) => { + // Try to update the database with the new config + Ok(crate::parity_db::open(path, db_type, create, true)?) + }, + Err(e) => Err(e.into()), + } } #[cfg(not(feature = "with-parity-db"))] @@ -573,7 +579,7 @@ impl<'a, 'b> codec::Input for JoinInput<'a, 'b> { #[cfg(test)] mod tests { use super::*; - use crate::{KeepBlocks, TransactionStorageMode}; + use crate::KeepBlocks; use codec::Input; use sc_state_db::PruningMode; use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; @@ -689,7 +695,6 @@ mod tests { state_pruning: PruningMode::ArchiveAll, source, keep_blocks: KeepBlocks::All, - transaction_storage: TransactionStorageMode::BlockBody, } } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index bf681aec94c7d..e9c1691107c71 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -19,7 +19,7 @@ use crate::{ build_network_future, client::{Client, ClientConfig}, - config::{Configuration, KeystoreConfig, PrometheusConfig, TransactionStorageMode}, + config::{Configuration, KeystoreConfig, PrometheusConfig}, error::Error, metrics::MetricsService, start_rpc_servers, RpcHandlers, SpawnTaskHandle, TaskManager, TransactionPoolAdapter, @@ -39,7 +39,7 @@ use sc_executor::RuntimeVersionOf; use sc_keystore::LocalKeystore; use sc_network::{ block_request_handler::{self, BlockRequestHandler}, - config::{Role, SyncMode}, + config::Role, light_client_requests::{self, handler::LightClientRequestHandler}, state_request_handler::{self, StateRequestHandler}, warp_request_handler::{self, RequestHandler as WarpSyncRequestHandler, WarpSyncProvider}, @@ -264,7 +264,6 @@ where state_pruning: config.state_pruning.clone(), source: config.database.clone(), keep_blocks: config.keep_blocks.clone(), - transaction_storage: config.transaction_storage.clone(), }; let backend = new_db_backend(db_config)?; @@ -842,7 +841,7 @@ where } }; - let mut 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); @@ -869,13 +868,6 @@ where light_client_request_protocol_config, }; - // Storage chains don't keep full block history and can't be synced in full mode. - // Force fast sync when storage chain mode is enabled. - if matches!(config.transaction_storage, TransactionStorageMode::StorageChain) { - network_params.network_config.sync_mode = - SyncMode::Fast { storage_chain_mode: true, skip_proofs: false }; - } - let has_bootnodes = !network_params.network_config.boot_nodes.is_empty(); let network_mut = sc_network::NetworkWorker::new(network_params)?; let network = network_mut.service().clone(); diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 45a6f832f8ee1..fd32aebdebdd8 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -19,7 +19,7 @@ //! Service configuration. pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStrategy}; -pub use sc_client_db::{Database, DatabaseSource, KeepBlocks, PruningMode, TransactionStorageMode}; +pub use sc_client_db::{Database, DatabaseSource, KeepBlocks, PruningMode}; pub use sc_executor::WasmExecutionMethod; pub use sc_network::{ config::{ @@ -71,8 +71,6 @@ pub struct Configuration { pub state_pruning: PruningMode, /// Number of blocks to keep in the db. pub keep_blocks: KeepBlocks, - /// Transaction storage scheme. - pub transaction_storage: TransactionStorageMode, /// Chain configuration. pub chain_spec: Box, /// Wasm execution method. diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index d158bbc42e947..6d9d99994288c 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -58,7 +58,6 @@ pub use self::{ }; pub use config::{ BasePath, Configuration, DatabaseSource, KeepBlocks, PruningMode, Role, RpcMethods, TaskType, - TransactionStorageMode, }; pub use sc_chain_spec::{ ChainSpec, ChainType, Extension as ChainSpecExtension, GenericChainSpec, NoExtension, diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 2b0ea460c4dd3..c86b23347d417 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -23,9 +23,7 @@ use sc_block_builder::BlockBuilderProvider; use sc_client_api::{ in_mem, BlockBackend, BlockchainEvents, FinalityNotifications, StorageProvider, }; -use sc_client_db::{ - Backend, DatabaseSettings, DatabaseSource, KeepBlocks, PruningMode, TransactionStorageMode, -}; +use sc_client_db::{Backend, DatabaseSettings, DatabaseSource, KeepBlocks, PruningMode}; use sc_consensus::{ BlockCheckParams, BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, }; @@ -1203,7 +1201,6 @@ fn doesnt_import_blocks_that_revert_finality() { state_cache_child_ratio: None, state_pruning: PruningMode::ArchiveAll, keep_blocks: KeepBlocks::All, - transaction_storage: TransactionStorageMode::BlockBody, source: DatabaseSource::RocksDb { path: tmp.path().into(), cache_size: 1024 }, }, u64::MAX, @@ -1419,7 +1416,6 @@ fn returns_status_for_pruned_blocks() { state_cache_child_ratio: None, state_pruning: PruningMode::keep_blocks(1), keep_blocks: KeepBlocks::All, - transaction_storage: TransactionStorageMode::BlockBody, source: DatabaseSource::RocksDb { path: tmp.path().into(), cache_size: 1024 }, }, u64::MAX, diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 67b33dfd55d13..c492ed30f7d91 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -30,7 +30,7 @@ use sc_service::{ client::Client, config::{BasePath, DatabaseSource, KeystoreConfig}, ChainSpecExtension, Configuration, Error, GenericChainSpec, KeepBlocks, Role, RuntimeGenesis, - SpawnTaskHandle, TaskManager, TransactionStorageMode, + SpawnTaskHandle, TaskManager, }; use sc_transaction_pool_api::TransactionPool; use sp_api::BlockId; @@ -235,7 +235,6 @@ fn node_config< state_cache_child_ratio: None, state_pruning: Default::default(), keep_blocks: KeepBlocks::All, - transaction_storage: TransactionStorageMode::BlockBody, chain_spec: Box::new((*spec).clone()), wasm_method: sc_service::config::WasmExecutionMethod::Interpreted, wasm_runtime_overrides: Default::default(), diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 2779656558826..94a350b5f5df3 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -105,11 +105,7 @@ impl /// Create new `TestClientBuilder` with default backend and storage chain mode pub fn with_tx_storage(keep_blocks: u32) -> Self { - let backend = Arc::new(Backend::new_test_with_tx_storage( - keep_blocks, - 0, - sc_client_db::TransactionStorageMode::StorageChain, - )); + let backend = Arc::new(Backend::new_test_with_tx_storage(keep_blocks, 0)); Self::with_backend(backend) } } From e4633560680f8ce077c896815cf23a9d7f04967e Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 4 Mar 2022 13:22:10 +0100 Subject: [PATCH 0575/1472] Deprecate "paritydb-experimental" CLI in favour or "paritydb" (#10975) * Deprecate paritydb-experimental * Updated comment --- client/cli/src/arg_enums.rs | 8 ++++++-- client/cli/src/config.rs | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index 7c9974fff38a5..6b0a029dd4fe5 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -201,8 +201,10 @@ pub enum Database { /// ParityDb. ParityDb, /// Detect whether there is an existing database. Use it, if there is, if not, create new - /// instance of paritydb + /// instance of ParityDb Auto, + /// ParityDb. + ParityDbDeprecated, } impl std::str::FromStr for Database { @@ -212,6 +214,8 @@ impl std::str::FromStr for Database { if s.eq_ignore_ascii_case("rocksdb") { Ok(Self::RocksDb) } else if s.eq_ignore_ascii_case("paritydb-experimental") { + Ok(Self::ParityDbDeprecated) + } else if s.eq_ignore_ascii_case("paritydb") { Ok(Self::ParityDb) } else if s.eq_ignore_ascii_case("auto") { Ok(Self::Auto) @@ -224,7 +228,7 @@ impl std::str::FromStr for Database { impl Database { /// Returns all the variants of this enum to be shown in the cli. pub fn variants() -> &'static [&'static str] { - &["rocksdb", "paritydb-experimental", "auto"] + &["rocksdb", "paritydb", "paritydb-experimental", "auto"] } } diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index a40be77f65aa0..d0f10dc9f6f3a 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -222,6 +222,13 @@ pub trait CliConfiguration: Sized { Ok(match database { Database::RocksDb => DatabaseSource::RocksDb { path: rocksdb_path, cache_size }, Database::ParityDb => DatabaseSource::ParityDb { path: paritydb_path }, + Database::ParityDbDeprecated => { + eprintln!( + "WARNING: \"paritydb-experimental\" database setting is deprecated and will be removed in future releases. \ + Please update your setup to use the new value: \"paritydb\"." + ); + DatabaseSource::ParityDb { path: paritydb_path } + }, Database::Auto => DatabaseSource::Auto { paritydb_path, rocksdb_path, cache_size }, }) } From 47bb6089bb87c66a7600e06419534e9959fdaa6f Mon Sep 17 00:00:00 2001 From: Alexander Gryaznov Date: Fri, 4 Mar 2022 18:28:00 +0300 Subject: [PATCH 0576/1472] [contracts] Stabilize "seal0" `is_contract` and `caller_is_origin` (#10971) * stabilize `seal_is_contract` * stabilize `seal_caller_is_origin` --- frame/contracts/src/benchmarking/mod.rs | 4 ++-- frame/contracts/src/wasm/mod.rs | 6 ++---- frame/contracts/src/wasm/runtime.rs | 8 ++------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 129b4a62581cc..5fdc5c2ab7846 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -409,7 +409,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "seal_is_contract", params: vec![ValueType::I32], return_type: Some(ValueType::I32), @@ -441,7 +441,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "seal_caller_is_origin", params: vec![], return_type: Some(ValueType::I32), diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 2dbaad0d79324..d89e7c1c8037d 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -2321,12 +2321,11 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn is_contract_works() { const CODE_IS_CONTRACT: &str = r#" ;; This runs `is_contract` check on zero account address (module - (import "__unstable__" "seal_is_contract" (func $seal_is_contract (param i32) (result i32))) + (import "seal0" "seal_is_contract" (func $seal_is_contract (param i32) (result i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) @@ -2362,12 +2361,11 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn caller_is_origin_works() { const CODE_CALLER_IS_ORIGIN: &str = r#" ;; This runs `caller_is_origin` check on zero account address (module - (import "__unstable__" "seal_caller_is_origin" (func $seal_caller_is_origin (result i32))) + (import "seal0" "seal_caller_is_origin" (func $seal_caller_is_origin (result i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index bb188e10e8fa0..d008fa3f1dac0 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -143,10 +143,8 @@ pub enum RuntimeCosts { /// Weight of calling `seal_caller`. Caller, /// Weight of calling `seal_is_contract`. - #[cfg(feature = "unstable-interface")] IsContract, /// Weight of calling `seal_caller_is_origin`. - #[cfg(feature = "unstable-interface")] CallerIsOrigin, /// Weight of calling `seal_address`. Address, @@ -236,9 +234,7 @@ impl RuntimeCosts { CopyFromContract(len) => s.return_per_byte.saturating_mul(len.into()), CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()), Caller => s.caller, - #[cfg(feature = "unstable-interface")] IsContract => s.is_contract, - #[cfg(feature = "unstable-interface")] CallerIsOrigin => s.caller_is_origin, Address => s.address, GasLeft => s.gas_left, @@ -1372,7 +1368,7 @@ define_env!(Env, , // Should be decodable as an `T::AccountId`. Traps otherwise. // // Returned value is a u32-encoded boolean: (0 = false, 1 = true). - [__unstable__] seal_is_contract(ctx, account_ptr: u32) -> u32 => { + [seal0] seal_is_contract(ctx, account_ptr: u32) -> u32 => { ctx.charge_gas(RuntimeCosts::IsContract)?; let address: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(account_ptr)?; @@ -1390,7 +1386,7 @@ define_env!(Env, , // and `false` indicates that the caller is another contract. // // Returned value is a u32-encoded boolean: (0 = false, 1 = true). - [__unstable__] seal_caller_is_origin(ctx) -> u32 => { + [seal0] seal_caller_is_origin(ctx) -> u32 => { ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?; Ok(ctx.ext.caller_is_origin() as u32) }, From d5090c66cf013b065bc00c987dfdbf64c85f04b3 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 4 Mar 2022 15:54:23 +0000 Subject: [PATCH 0577/1472] Trie version migration pallet (#10073) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * starting * Updated from other branch. * setting flag * flag in storage struct * fix flagging to access and insert. * added todo to fix * also missing serialize meta to storage proof * extract meta. * Isolate old trie layout. * failing test that requires storing in meta when old hash scheme is used. * old hash compatibility * Db migrate. * runing tests with both states when interesting. * fix chain spec test with serde default. * export state (missing trie function). * Pending using new branch, lacking genericity on layout resolution. * extract and set global meta * Update to branch 4 * fix iterator with root flag (no longer insert node). * fix trie root hashing of root * complete basic backend. * Remove old_hash meta from proof that do not use inner_hashing. * fix trie test for empty (force layout on empty deltas). * Root update fix. * debug on meta * Use trie key iteration that do not include value in proofs. * switch default test ext to use inner hash. * small integration test, and fix tx cache mgmt in ext. test failing * Proof scenario at state-machine level. * trace for db upgrade * try different param * act more like iter_from. * Bigger batches. * Update trie dependency. * drafting codec changes and refact * before removing unused branch no value alt hashing. more work todo rename all flag var to alt_hash, and remove extrinsic replace by storage query at every storage_root call. * alt hashing only for branch with value. * fix trie tests * Hash of value include the encoded size. * removing fields(broken) * fix trie_stream to also include value length in inner hash. * triedbmut only using alt type if inner hashing. * trie_stream to also only use alt hashing type when actually alt hashing. * Refactor meta state, logic should work with change of trie treshold. * Remove NoMeta variant. * Remove state_hashed trigger specific functions. * pending switching to using threshold, new storage root api does not make much sense. * refactoring to use state from backend (not possible payload changes). * Applying from previous state * Remove default from storage, genesis need a special build. * rem empty space * Catch problem: when using triedb with default: we should not revert nodes: otherwhise thing as trie codec cannot decode-encode without changing state. * fix compilation * Right logic to avoid switch on reencode when default layout. * Clean up some todos * remove trie meta from root upstream * update upstream and fix benches. * split some long lines. * UPdate trie crate to work with new design. * Finish update to refactored upstream. * update to latest triedb changes. * Clean up. * fix executor test. * rust fmt from master. * rust format. * rustfmt * fix * start host function driven versioning * update state-machine part * still need access to state version from runtime * state hash in mem: wrong * direction likely correct, but passing call to code exec for genesis init seem awkward. * state version serialize in runtime, wrong approach, just initialize it with no threshold for core api < 4 seems more proper. * stateversion from runtime version (core api >= 4). * update trie, fix tests * unused import * clean some TODOs * Require RuntimeVersionOf for executor * use RuntimeVersionOf to resolve genesis state version. * update runtime version test * fix state-machine tests * TODO * Use runtime version from storage wasm with fast sync. * rustfmt * fmt * fix test * revert useless changes. * clean some unused changes * fmt * removing useless trait function. * remove remaining reference to state_hash * fix some imports * Follow chain state version management. * trie update, fix and constant threshold for trie layouts. * update deps * Update to latest trie pr changes. * fix benches * Verify proof requires right layout. * update trie_root * Update trie deps to latest * Update to latest trie versioning * Removing patch * update lock * extrinsic for sc-service-test using layout v0. * Adding RuntimeVersionOf to CallExecutor works. * fmt * error when resolving version and no wasm in storage. * use existing utils to instantiate runtime code. * migration pallet * Patch to delay runtime switch. * Revert "Patch to delay runtime switch." This reverts commit d35f273b7d67b1b85a9e72973cab13c5c156c1d3. * fix test * fix child migration calls. * useless closure * remove remaining state_hash variables. * Fix and add more tests * Remove outdated comment * useless inner hash * fmt * remote tests * finally ksm works * batches are broken * clean the benchmarks * Apply suggestions from code review Co-authored-by: Guillaume Thiolliere * Apply suggestions from code review Co-authored-by: Guillaume Thiolliere * Update frame/state-trie-migration/src/lib.rs Co-authored-by: Joshy Orndorff * Update frame/state-trie-migration/src/lib.rs * brand new version * fix build * Update frame/state-trie-migration/src/lib.rs Co-authored-by: Guillaume Thiolliere * Update frame/state-trie-migration/src/lib.rs Co-authored-by: Guillaume Thiolliere * Update primitives/storage/src/lib.rs Co-authored-by: cheme * Update frame/state-trie-migration/src/lib.rs Co-authored-by: cheme * Update frame/state-trie-migration/src/lib.rs Co-authored-by: cheme * fmt and opt-in feature to apply state change. * feature gate core version, use new test feature for node and test node * Use a 'State' api version instead of Core one. * fix merge of test function * use blake macro. * Fix state api (require declaring the api in runtime). * Opt out feature, fix macro for io to select a given version instead of latest. * run test nodes on new state. * fix * new test structure * new testing stuff from emeric * Add commit_all, still not working * Fix all tests * add comment * we have PoV tracking baby * document stuff, but proof size is still wrong * FUCK YEAH * a big batch of review comments * add more tests * tweak test * update config * some remote-ext stuff * delete some of the old stuff * sync more files with master to minimize the diff * Fix all tests * make signed migration a bit more relaxed * add witness check to signed submissions * allow custom migration to also go above limit * Fix these pesky tests * ==== removal of the unsigned stuff ==== * Make all tests work again * separate the tests from the logic so it can be reused easier * fix overall build * Update frame/state-trie-migration/src/lib.rs Co-authored-by: cheme * Update frame/state-trie-migration/src/lib.rs Co-authored-by: cheme * Slightly better termination * some final tweaks * Fix tests * Restrict access to signed migrations * address most of the review comments * fix defensive * New simplified code * Fix weights * fmt * Update frame/state-trie-migration/src/lib.rs Co-authored-by: Bastian Köcher * make the tests correctly fail * Fix build * Fix build * try and fix the benchmarks * fix build * Fix cargo file * Fix runtime deposit * make rustdoc happy * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_state_trie_migration --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/state-trie-migration/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: cheme Co-authored-by: Guillaume Thiolliere Co-authored-by: Joshy Orndorff Co-authored-by: Bastian Köcher Co-authored-by: Parity Bot --- Cargo.lock | 31 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 26 +- frame/bags-list/remote-tests/src/migration.rs | 3 +- .../remote-tests/src/sanity_check.rs | 3 +- frame/bags-list/remote-tests/src/snapshot.rs | 2 +- frame/state-trie-migration/Cargo.toml | 57 + frame/state-trie-migration/src/lib.rs | 1557 +++++++++++++++++ frame/state-trie-migration/src/weights.rs | 137 ++ frame/support/src/traits/misc.rs | 8 +- primitives/core/src/lib.rs | 2 +- primitives/state-machine/src/testing.rs | 7 +- .../state-machine/src/trie_backend_essence.rs | 78 +- primitives/storage/src/lib.rs | 13 +- utils/frame/remote-externalities/src/lib.rs | 66 +- utils/frame/try-runtime/cli/src/lib.rs | 1 + 16 files changed, 1954 insertions(+), 41 deletions(-) create mode 100644 frame/state-trie-migration/Cargo.toml create mode 100644 frame/state-trie-migration/src/lib.rs create mode 100644 frame/state-trie-migration/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 9cb1eae0a91fc..bfe1801740264 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5010,6 +5010,7 @@ dependencies = [ "pallet-society", "pallet-staking", "pallet-staking-reward-curve", + "pallet-state-trie-migration", "pallet-sudo", "pallet-timestamp", "pallet-tips", @@ -6419,6 +6420,30 @@ dependencies = [ "sp-arithmetic", ] +[[package]] +name = "pallet-state-trie-migration" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log 0.4.14", + "pallet-balances", + "parity-scale-codec", + "parking_lot 0.12.0", + "remote-externalities", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-tracing", + "thousands", + "tokio", + "zstd", +] + [[package]] name = "pallet-sudo" version = "4.0.0-dev" @@ -10838,6 +10863,12 @@ dependencies = [ "syn", ] +[[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.3" diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index e7bd50c3d1897..0572345fa0c89 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -87,6 +87,7 @@ pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = ". pallet-session-benchmarking = { version = "4.0.0-dev", path = "../../../frame/session/benchmarking", default-features = false, optional = true } pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking/reward-curve" } +pallet-state-trie-migration = { version = "4.0.0-dev", default-features = false, path = "../../../frame/state-trie-migration" } pallet-scheduler = { version = "4.0.0-dev", default-features = false, path = "../../../frame/scheduler" } pallet-society = { version = "4.0.0-dev", default-features = false, path = "../../../frame/society" } pallet-sudo = { version = "4.0.0-dev", default-features = false, path = "../../../frame/sudo" } @@ -153,6 +154,7 @@ std = [ "sp-runtime/std", "sp-staking/std", "pallet-staking/std", + "pallet-state-trie-migration/std", "sp-session/std", "pallet-sudo/std", "frame-support/std", @@ -214,6 +216,7 @@ runtime-benchmarks = [ "pallet-session-benchmarking", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", + "pallet-state-trie-migration/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-tips/runtime-benchmarks", "pallet-transaction-storage/runtime-benchmarks", @@ -261,6 +264,7 @@ try-runtime = [ "pallet-session/try-runtime", "pallet-society/try-runtime", "pallet-staking/try-runtime", + "pallet-state-trie-migration/try-runtime", "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", "pallet-tips/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0b0c033ae851d..f12bf8a88365f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -39,7 +39,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureRoot, + EnsureRoot, EnsureSigned, }; pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; @@ -1367,6 +1367,28 @@ impl pallet_whitelist::Config for Runtime { type WeightInfo = pallet_whitelist::weights::SubstrateWeight; } +parameter_types! { + pub const SignedMigrationMaxLimits: pallet_state_trie_migration::MigrationLimits = + pallet_state_trie_migration::MigrationLimits { size: 1024 * 1024 / 2, item: 512 }; + pub const MigrationSignedDepositPerItem: Balance = 1 * CENTS; + pub const MigrationSignedDepositBase: Balance = 20 * DOLLARS; +} + +impl pallet_state_trie_migration::Config for Runtime { + type Event = Event; + type ControlOrigin = EnsureRoot; + type Currency = Balances; + type SignedDepositPerItem = MigrationSignedDepositPerItem; + type SignedDepositBase = MigrationSignedDepositBase; + type SignedMigrationMaxLimits = SignedMigrationMaxLimits; + // Warning: this is not advised, as it might allow the chain to be temporarily DOS-ed. + // Preferably, if the chain's governance/maintenance team is planning on using a specific + // account for the migration, put it here to make sure only that account can trigger the signed + // migrations. + type SignedFilter = EnsureSigned; + type WeightInfo = (); +} + construct_runtime!( pub enum Runtime where Block = Block, @@ -1418,6 +1440,7 @@ construct_runtime!( Uniques: pallet_uniques, TransactionStorage: pallet_transaction_storage, BagsList: pallet_bags_list, + StateTrieMigration: pallet_state_trie_migration, ChildBounties: pallet_child_bounties, Referenda: pallet_referenda, ConvictionVoting: pallet_conviction_voting, @@ -1512,6 +1535,7 @@ mod benches { [pallet_scheduler, Scheduler] [pallet_session, SessionBench::] [pallet_staking, Staking] + [pallet_state_trie_migration, StateTrieMigration] [frame_system, SystemBench::] [pallet_timestamp, Timestamp] [pallet_tips, Tips] diff --git a/frame/bags-list/remote-tests/src/migration.rs b/frame/bags-list/remote-tests/src/migration.rs index aadbbdae3d61b..4d5169fcc6dfa 100644 --- a/frame/bags-list/remote-tests/src/migration.rs +++ b/frame/bags-list/remote-tests/src/migration.rs @@ -34,8 +34,7 @@ pub async fn execute( .mode(Mode::Online(OnlineConfig { transport: ws_url.to_string().into(), pallets: vec![pallet_staking::Pallet::::name().to_string()], - at: None, - state_snapshot: None, + ..Default::default() })) .build() .await diff --git a/frame/bags-list/remote-tests/src/sanity_check.rs b/frame/bags-list/remote-tests/src/sanity_check.rs index adab1ae5477ea..f2b6881edea7f 100644 --- a/frame/bags-list/remote-tests/src/sanity_check.rs +++ b/frame/bags-list/remote-tests/src/sanity_check.rs @@ -35,8 +35,7 @@ pub async fn execute .mode(Mode::Online(OnlineConfig { transport: ws_url.to_string().into(), pallets: vec![pallet_bags_list::Pallet::::name().to_string()], - at: None, - state_snapshot: None, + ..Default::default() })) .inject_hashed_prefix(&>::prefix_hash()) .inject_hashed_prefix(&>::prefix_hash()) diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index 78f462e55b8f6..241b64b366117 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -35,7 +35,7 @@ pub async fn execute // is bags-list. pallets: vec![pallet_bags_list::Pallet::::name().to_string()], at: None, - state_snapshot: None, + ..Default::default() })) .inject_hashed_prefix(&>::prefix_hash()) .inject_hashed_prefix(&>::prefix_hash()) diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml new file mode 100644 index 0000000000000..fb8bccb52d1f2 --- /dev/null +++ b/frame/state-trie-migration/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "pallet-state-trie-migration" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet migration of trie" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +log = { version = "0.4.14", default-features = false } + +sp-std = { default-features = false, path = "../../primitives/std" } +sp-io = { default-features = false, path = "../../primitives/io" } +sp-core = { default-features = false, path = "../../primitives/core" } +sp-runtime = { default-features = false, path = "../../primitives/runtime" } + +frame-support = { default-features = false, path = "../support" } +frame-system = { default-features = false, path = "../system" } +frame-benchmarking = { default-features = false, path = "../benchmarking", optional = true } + +serde = { version = "1.0.133", optional = true } +thousands = { version = "0.2.0", optional = true } +remote-externalities = { path = "../../utils/frame/remote-externalities", optional = true } +zstd = { version = "0.9.0", optional = true } + +[dev-dependencies] +pallet-balances = { path = "../balances" } +parking_lot = "0.12.0" +sp-tracing = { path = "../../primitives/tracing" } +tokio = { version = "1.10", features = ["macros"] } + +[features] +default = ["std"] +std = [ + "log/std", + "scale-info/std", + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std" +] +runtime-benchmarks = ["frame-benchmarking"] +try-runtime = ["frame-support/try-runtime"] + +remote-test = [ "std", "zstd", "serde", "thousands", "remote-externalities" ] diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs new file mode 100644 index 0000000000000..4de130e9ac06b --- /dev/null +++ b/frame/state-trie-migration/src/lib.rs @@ -0,0 +1,1557 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Pallet State Trie Migration +//! +//! Reads and writes all keys and values in the entire state in a systematic way. This is useful for +//! upgrading a chain to [`sp-core::StateVersion::V1`], where all keys need to be touched. +//! +//! ## Migration Types +//! +//! This pallet provides 2 ways to do this, each of which is suited for a particular use-case, and +//! can be enabled independently. +//! +//! ### Auto migration +//! +//! This system will try and migrate all keys by continuously using `on_initialize`. It is only +//! sensible for a relay chain or a solo chain, where going slightly over weight is not a problem. +//! It can be configured so that the migration takes at most `n` items and tries to not go over `x` +//! bytes, but the latter is not guaranteed. +//! +//! For example, if a chain contains keys of 1 byte size, the `on_initialize` could read up to `x - +//! 1` bytes from `n` different keys, while the next key is suddenly `:code:`, and there is no way +//! to bail out of this. +//! +//! ### Signed migration +//! +//! As a backup, the migration process can be set in motion via signed transactions that basically +//! say in advance how many items and how many bytes they will consume, and pay for it as well. This +//! can be a good safe alternative, if the former system is not desirable. +//! +//! The (minor) caveat of this approach is that we cannot know in advance how many bytes reading a +//! certain number of keys will incur. To overcome this, the runtime needs to configure this pallet +//! with a `SignedDepositPerItem`. This is the per-item deposit that the origin of the signed +//! migration transactions need to have in their account (on top of the normal fee) and if the size +//! witness data that they claim is incorrect, this deposit is slashed. +//! +//! --- +//! +//! Initially, this pallet does not contain any auto migration. They must be manually enabled by the +//! `ControlOrigin`. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +const LOG_TARGET: &'static str = "runtime::state-trie-migration"; + +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: crate::LOG_TARGET, + concat!("[{:?}] 🤖 ", $patter), frame_system::Pallet::::block_number() $(, $values)* + ) + }; +} + +#[frame_support::pallet] +pub mod pallet { + use frame_support::{ + dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, + ensure, + pallet_prelude::*, + traits::{Currency, Get}, + }; + use frame_system::{self, pallet_prelude::*}; + use sp_core::storage::well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX; + use sp_runtime::{ + self, + traits::{Saturating, Zero}, + }; + use sp_std::prelude::*; + + pub(crate) type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + + /// The weight information of this pallet. + pub trait WeightInfo { + fn process_top_key(x: u32) -> Weight; + fn continue_migrate() -> Weight; + fn continue_migrate_wrong_witness() -> Weight; + fn migrate_custom_top_fail() -> Weight; + fn migrate_custom_top_success() -> Weight; + fn migrate_custom_child_fail() -> Weight; + fn migrate_custom_child_success() -> Weight; + } + + impl WeightInfo for () { + fn process_top_key(_: u32) -> Weight { + 1000000 + } + fn continue_migrate() -> Weight { + 1000000 + } + fn continue_migrate_wrong_witness() -> Weight { + 1000000 + } + fn migrate_custom_top_fail() -> Weight { + 1000000 + } + fn migrate_custom_top_success() -> Weight { + 1000000 + } + fn migrate_custom_child_fail() -> Weight { + 1000000 + } + fn migrate_custom_child_success() -> Weight { + 1000000 + } + } + + /// A migration task stored in state. + /// + /// It tracks the last top and child keys read. + #[derive(Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq)] + #[codec(mel_bound(T: Config))] + #[scale_info(skip_type_params(T))] + pub struct MigrationTask { + /// The last top key that we migrated. + /// + /// If it does not exist, it means that the migration is done and no further keys exist. + pub(crate) last_top: Option>, + /// The last child key that we have processed. + /// + /// This is a child key under the current `self.last_top`. + /// + /// If this is set, no further top keys are processed until the child key migration is + /// complete. + pub(crate) last_child: Option>, + + /// A marker to indicate if the previous tick was a child tree migration or not. + pub(crate) prev_tick_child: bool, + + /// Dynamic counter for the number of items that we have processed in this execution from + /// the top trie. + /// + /// It is not written to storage. + #[codec(skip)] + pub(crate) dyn_top_items: u32, + /// Dynamic counter for the number of items that we have processed in this execution from + /// any child trie. + /// + /// It is not written to storage. + #[codec(skip)] + pub(crate) dyn_child_items: u32, + + /// Dynamic counter for for the byte size of items that we have processed in this + /// execution. + /// + /// It is not written to storage. + #[codec(skip)] + pub(crate) dyn_size: u32, + + /// The total size of the migration, over all executions. + /// + /// This only kept around for bookkeeping and debugging. + pub(crate) size: u32, + /// The total count of top keys in the migration, over all executions. + /// + /// This only kept around for bookkeeping and debugging. + pub(crate) top_items: u32, + /// The total count of child keys in the migration, over all executions. + /// + /// This only kept around for bookkeeping and debugging. + pub(crate) child_items: u32, + + #[codec(skip)] + pub(crate) _ph: sp_std::marker::PhantomData, + } + + impl sp_std::fmt::Debug for MigrationTask { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + f.debug_struct("MigrationTask") + .field( + "top", + &self.last_top.as_ref().map(|d| sp_core::hexdisplay::HexDisplay::from(d)), + ) + .field( + "child", + &self.last_child.as_ref().map(|d| sp_core::hexdisplay::HexDisplay::from(d)), + ) + .field("prev_tick_child", &self.prev_tick_child) + .field("dyn_top_items", &self.dyn_top_items) + .field("dyn_child_items", &self.dyn_child_items) + .field("dyn_size", &self.dyn_size) + .field("size", &self.size) + .field("top_items", &self.top_items) + .field("child_items", &self.child_items) + .finish() + } + } + + impl Default for MigrationTask { + fn default() -> Self { + Self { + last_top: Some(Default::default()), + last_child: Default::default(), + dyn_child_items: Default::default(), + dyn_top_items: Default::default(), + dyn_size: Default::default(), + prev_tick_child: Default::default(), + _ph: Default::default(), + size: Default::default(), + top_items: Default::default(), + child_items: Default::default(), + } + } + } + + impl MigrationTask { + /// Return true if the task is finished. + pub(crate) fn finished(&self) -> bool { + self.last_top.is_none() && self.last_child.is_none() + } + + /// Check if there's any work left, or if we have exhausted the limits already. + fn exhausted(&self, limits: MigrationLimits) -> bool { + self.dyn_total_items() >= limits.item || self.dyn_size >= limits.size + } + + /// get the total number of keys affected by the current task. + pub(crate) fn dyn_total_items(&self) -> u32 { + self.dyn_child_items.saturating_add(self.dyn_top_items) + } + + /// Migrate keys until either of the given limits are exhausted, or if no more top keys + /// exist. + /// + /// Note that this can return after the **first** migration tick that causes exhaustion, + /// specifically in the case of the `size` constrain. The reason for this is that before + /// reading a key, we simply cannot know how many bytes it is. In other words, this should + /// not be used in any environment where resources are strictly bounded (e.g. a parachain), + /// but it is acceptable otherwise (relay chain, offchain workers). + pub fn migrate_until_exhaustion(&mut self, limits: MigrationLimits) { + log!(debug, "running migrations on top of {:?} until {:?}", self, limits); + + if limits.item.is_zero() || limits.size.is_zero() { + // handle this minor edge case, else we would call `migrate_tick` at least once. + log!(warn, "limits are zero. stopping"); + return + } + + while !self.exhausted(limits) && !self.finished() { + self.migrate_tick(); + } + + // accumulate dynamic data into the storage items. + self.size = self.size.saturating_add(self.dyn_size); + self.child_items = self.child_items.saturating_add(self.dyn_child_items); + self.top_items = self.top_items.saturating_add(self.dyn_top_items); + log!(debug, "finished with {:?}", self); + } + + /// Migrate AT MOST ONE KEY. This can be either a top or a child key. + /// + /// This function is *the* core of this entire pallet. + fn migrate_tick(&mut self) { + match (self.last_top.as_ref(), self.last_child.as_ref()) { + (Some(_), Some(_)) => { + // we're in the middle of doing work on a child tree. + self.migrate_child(); + }, + (Some(ref top_key), None) => { + // we have a top key and no child key. 3 possibilities exist: + // 1. we continue the top key migrations. + // 2. this is the root of a child key, and we start processing child keys (and + // should call `migrate_child`). + // 3. this is the root of a child key, and we are finishing all child-keys (and + // should call `migrate_top`). + + // NOTE: this block is written intentionally to verbosely for easy of + // verification. + match ( + top_key.starts_with(DEFAULT_CHILD_STORAGE_KEY_PREFIX), + self.prev_tick_child, + ) { + (false, false) => { + // continue the top key migration + self.migrate_top(); + }, + (true, false) => { + self.last_child = Some(Default::default()); + self.migrate_child(); + self.prev_tick_child = true; + }, + (true, true) => { + // we're done with migrating a child-root. + self.prev_tick_child = false; + self.migrate_top(); + }, + (false, true) => { + // should never happen. + log!(error, "LOGIC ERROR: unreachable code [0]."); + Pallet::::halt(); + }, + }; + }, + (None, Some(_)) => { + log!(error, "LOGIC ERROR: unreachable code [1]."); + Pallet::::halt() + }, + (None, None) => { + // nada + }, + } + } + + /// Migrate the current child key, setting it to its new value, if one exists. + /// + /// It updates the dynamic counters. + fn migrate_child(&mut self) { + use sp_io::default_child_storage as child_io; + let (last_child, last_top) = match (&self.last_child, &self.last_top) { + (Some(last_child), Some(last_top)) => (last_child, last_top), + _ => { + // defensive: this function is only called when both of these values exist. + // much that we can do otherwise.. + frame_support::defensive!("cannot migrate child key."); + return + }, + }; + + let child_root = Pallet::::transform_child_key_or_halt(&last_top); + let maybe_current_child = child_io::next_key(child_root, &last_child); + if let Some(ref current_child) = maybe_current_child { + let added_size = if let Some(data) = child_io::get(child_root, ¤t_child) { + child_io::set(child_root, current_child, &data); + data.len() as u32 + } else { + Zero::zero() + }; + self.dyn_size = self.dyn_size.saturating_add(added_size); + self.dyn_child_items.saturating_inc(); + } + + log!(trace, "migrated a child key, next_child_key: {:?}", maybe_current_child); + self.last_child = maybe_current_child; + } + + /// Migrate the current top key, setting it to its new value, if one exists. + /// + /// It updates the dynamic counters. + fn migrate_top(&mut self) { + let last_top = match &self.last_top { + Some(last_top) => last_top, + None => { + // defensive: this function is only called when this value exist. + // much that we can do otherwise.. + frame_support::defensive!("cannot migrate top key."); + return + }, + }; + + let maybe_current_top = sp_io::storage::next_key(last_top); + if let Some(ref current_top) = maybe_current_top { + let added_size = if let Some(data) = sp_io::storage::get(¤t_top) { + sp_io::storage::set(¤t_top, &data); + data.len() as u32 + } else { + Zero::zero() + }; + self.dyn_size = self.dyn_size.saturating_add(added_size); + self.dyn_top_items.saturating_inc(); + } + + log!(trace, "migrated a top key, next_top_key = {:?}", maybe_current_top); + self.last_top = maybe_current_top; + } + } + + /// The limits of a migration. + #[derive(Clone, Copy, Encode, Decode, scale_info::TypeInfo, Default, Debug, PartialEq, Eq)] + pub struct MigrationLimits { + /// The byte size limit. + pub size: u32, + /// The number of keys limit. + pub item: u32, + } + + /// How a migration was computed. + #[derive(Clone, Copy, Encode, Decode, scale_info::TypeInfo, Debug, PartialEq, Eq)] + pub enum MigrationCompute { + /// A signed origin triggered the migration. + Signed, + /// An automatic task triggered the migration. + Auto, + } + + /// Inner events of this pallet. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Given number of `(top, child)` keys were migrated respectively, with the given + /// `compute`. + Migrated { top: u32, child: u32, compute: MigrationCompute }, + /// Some account got slashed by the given amount. + Slashed { who: T::AccountId, amount: BalanceOf }, + /// The auto migration task finished. + AutoMigrationFinished, + /// Migration got halted. + Halted, + } + + /// The outer Pallet struct. + #[pallet::pallet] + #[pallet::generate_store(pub(crate) trait Store)] + #[pallet::without_storage_info] + pub struct Pallet(_); + + /// Configurations of this pallet. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Origin that can control the configurations of this pallet. + type ControlOrigin: frame_support::traits::EnsureOrigin; + + /// Filter on which origin that trigger the manual migrations. + type SignedFilter: EnsureOrigin; + + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// The currency provider type. + type Currency: Currency; + + /// The amount of deposit collected per item in advance, for signed migrations. + /// + /// This should reflect the average storage value size in the worse case. + type SignedDepositPerItem: Get>; + + /// The base value of [`Config::SignedDepositPerItem`]. + /// + /// Final deposit is `items * SignedDepositPerItem + SignedDepositBase`. + type SignedDepositBase: Get>; + + /// The maximum limits that the signed migration could use. + #[pallet::constant] + type SignedMigrationMaxLimits: Get; + + /// The weight information of this pallet. + type WeightInfo: WeightInfo; + } + + /// Migration progress. + /// + /// This stores the snapshot of the last migrated keys. It can be set into motion and move + /// forward by any of the means provided by this pallet. + #[pallet::storage] + #[pallet::getter(fn migration_process)] + pub type MigrationProcess = StorageValue<_, MigrationTask, ValueQuery>; + + /// The limits that are imposed on automatic migrations. + /// + /// If set to None, then no automatic migration happens. + #[pallet::storage] + #[pallet::getter(fn auto_limits)] + pub type AutoLimits = StorageValue<_, Option, ValueQuery>; + + #[pallet::error] + pub enum Error { + /// max signed limits not respected. + MaxSignedLimits, + /// submitter does not have enough funds. + NotEnoughFunds, + /// bad witness data provided. + BadWitness, + /// upper bound of size is exceeded, + SizeUpperBoundExceeded, + } + + #[pallet::call] + impl Pallet { + /// Control the automatic migration. + /// + /// The dispatch origin of this call must be [`Config::ControlOrigin`]. + #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] + pub fn control_auto_migration( + origin: OriginFor, + maybe_config: Option, + ) -> DispatchResultWithPostInfo { + T::ControlOrigin::ensure_origin(origin)?; + AutoLimits::::put(maybe_config); + Ok(().into()) + } + + /// Continue the migration for the given `limits`. + /// + /// The dispatch origin of this call can be any signed account. + /// + /// This transaction has NO MONETARY INCENTIVES. calling it will not reward anyone. Albeit, + /// Upon successful execution, the transaction fee is returned. + /// + /// The (potentially over-estimated) of the byte length of all the data read must be + /// provided for up-front fee-payment and weighing. In essence, the caller is guaranteeing + /// that executing the current `MigrationTask` with the given `limits` will not exceed + /// `real_size_upper` bytes of read data. + /// + /// The `witness_task` is merely a helper to prevent the caller from being slashed or + /// generally trigger a migration that they do not intend. This parameter is just a message + /// from caller, saying that they believed `witness_task` was the last state of the + /// migration, and they only wish for their transaction to do anything, if this assumption + /// holds. In case `witness_task` does not match, the transaction fails. + /// + /// Based on the documentation of [`MigrationTask::migrate_until_exhaustion`], the + /// recommended way of doing this is to pass a `limit` that only bounds `count`, as the + /// `size` limit can always be overwritten. + #[pallet::weight( + // the migration process + Pallet::::dynamic_weight(limits.item, * real_size_upper) + // rest of the operations, like deposit etc. + + T::WeightInfo::continue_migrate() + )] + pub fn continue_migrate( + origin: OriginFor, + limits: MigrationLimits, + real_size_upper: u32, + witness_task: MigrationTask, + ) -> DispatchResultWithPostInfo { + let who = T::SignedFilter::ensure_origin(origin)?; + + let max_limits = T::SignedMigrationMaxLimits::get(); + ensure!( + limits.size <= max_limits.size && limits.item <= max_limits.item, + Error::::MaxSignedLimits, + ); + + // ensure they can pay more than the fee. + let deposit = T::SignedDepositPerItem::get().saturating_mul(limits.item.into()); + ensure!(T::Currency::can_slash(&who, deposit), Error::::NotEnoughFunds); + + let mut task = Self::migration_process(); + ensure!( + task == witness_task, + DispatchErrorWithPostInfo { + error: Error::::BadWitness.into(), + post_info: PostDispatchInfo { + actual_weight: Some(T::WeightInfo::continue_migrate_wrong_witness()), + pays_fee: Pays::Yes + } + } + ); + task.migrate_until_exhaustion(limits); + + // ensure that the migration witness data was correct. + if real_size_upper < task.dyn_size { + // let the imbalance burn. + let (_imbalance, _remainder) = T::Currency::slash(&who, deposit); + Self::deposit_event(Event::::Slashed { who, amount: deposit }); + debug_assert!(_remainder.is_zero()); + return Err(Error::::SizeUpperBoundExceeded.into()) + } + + Self::deposit_event(Event::::Migrated { + top: task.dyn_top_items, + child: task.dyn_child_items, + compute: MigrationCompute::Signed, + }); + + // refund and correct the weight. + let actual_weight = Some( + Pallet::::dynamic_weight(limits.item, task.dyn_size) + .saturating_add(T::WeightInfo::continue_migrate()), + ); + + MigrationProcess::::put(task); + Ok((actual_weight, Pays::No).into()) + } + + /// Migrate the list of top keys by iterating each of them one by one. + /// + /// This does not affect the global migration process tracker ([`MigrationProcess`]), and + /// should only be used in case any keys are leftover due to a bug. + #[pallet::weight( + T::WeightInfo::migrate_custom_top_success() + .max(T::WeightInfo::migrate_custom_top_fail()) + .saturating_add( + Pallet::::dynamic_weight(keys.len() as u32, *witness_size) + ) + )] + pub fn migrate_custom_top( + origin: OriginFor, + keys: Vec>, + witness_size: u32, + ) -> DispatchResultWithPostInfo { + let who = T::SignedFilter::ensure_origin(origin)?; + + // ensure they can pay more than the fee. + let deposit = T::SignedDepositBase::get().saturating_add( + T::SignedDepositPerItem::get().saturating_mul((keys.len() as u32).into()), + ); + ensure!(T::Currency::can_slash(&who, deposit), "not enough funds"); + + let mut dyn_size = 0u32; + for key in &keys { + if let Some(data) = sp_io::storage::get(&key) { + dyn_size = dyn_size.saturating_add(data.len() as u32); + sp_io::storage::set(key, &data); + } + } + + if dyn_size > witness_size { + let (_imbalance, _remainder) = T::Currency::slash(&who, deposit); + Self::deposit_event(Event::::Slashed { who, amount: deposit }); + debug_assert!(_remainder.is_zero()); + Err("wrong witness data".into()) + } else { + Self::deposit_event(Event::::Migrated { + top: keys.len() as u32, + child: 0, + compute: MigrationCompute::Signed, + }); + Ok(PostDispatchInfo { + actual_weight: Some( + T::WeightInfo::migrate_custom_top_success().saturating_add( + Pallet::::dynamic_weight(keys.len() as u32, dyn_size), + ), + ), + pays_fee: Pays::Yes, + }) + } + } + + /// Migrate the list of child keys by iterating each of them one by one. + /// + /// All of the given child keys must be present under one `child_root`. + /// + /// This does not affect the global migration process tracker ([`MigrationProcess`]), and + /// should only be used in case any keys are leftover due to a bug. + #[pallet::weight( + T::WeightInfo::migrate_custom_child_success() + .max(T::WeightInfo::migrate_custom_child_fail()) + .saturating_add( + Pallet::::dynamic_weight(child_keys.len() as u32, *total_size) + ) + )] + pub fn migrate_custom_child( + origin: OriginFor, + root: Vec, + child_keys: Vec>, + total_size: u32, + ) -> DispatchResultWithPostInfo { + use sp_io::default_child_storage as child_io; + let who = T::SignedFilter::ensure_origin(origin)?; + + // ensure they can pay more than the fee. + let deposit = T::SignedDepositBase::get().saturating_add( + T::SignedDepositPerItem::get().saturating_mul((child_keys.len() as u32).into()), + ); + sp_std::if_std! { + println!("+ {:?} / {:?} / {:?}", who, deposit, T::Currency::free_balance(&who)); + } + ensure!(T::Currency::can_slash(&who, deposit), "not enough funds"); + + let mut dyn_size = 0u32; + let transformed_child_key = Self::transform_child_key(&root).ok_or("bad child key")?; + for child_key in &child_keys { + if let Some(data) = child_io::get(transformed_child_key, &child_key) { + dyn_size = dyn_size.saturating_add(data.len() as u32); + child_io::set(transformed_child_key, &child_key, &data); + } + } + + if dyn_size != total_size { + let (_imbalance, _remainder) = T::Currency::slash(&who, deposit); + debug_assert!(_remainder.is_zero()); + Self::deposit_event(Event::::Slashed { who, amount: deposit }); + Err(DispatchErrorWithPostInfo { + error: "bad witness".into(), + post_info: PostDispatchInfo { + actual_weight: Some(T::WeightInfo::migrate_custom_child_fail()), + pays_fee: Pays::Yes, + }, + }) + } else { + Self::deposit_event(Event::::Migrated { + top: 0, + child: child_keys.len() as u32, + compute: MigrationCompute::Signed, + }); + Ok(PostDispatchInfo { + actual_weight: Some( + T::WeightInfo::migrate_custom_child_success().saturating_add( + Pallet::::dynamic_weight(child_keys.len() as u32, total_size), + ), + ), + pays_fee: Pays::Yes, + }) + } + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(_: BlockNumberFor) -> Weight { + if let Some(limits) = Self::auto_limits() { + let mut task = Self::migration_process(); + task.migrate_until_exhaustion(limits); + let weight = Self::dynamic_weight(task.dyn_total_items(), task.dyn_size); + + log!( + info, + "migrated {} top keys, {} child keys, and a total of {} bytes.", + task.dyn_top_items, + task.dyn_child_items, + task.dyn_size, + ); + + if task.finished() { + Self::deposit_event(Event::::AutoMigrationFinished); + AutoLimits::::kill(); + } else { + Self::deposit_event(Event::::Migrated { + top: task.dyn_top_items, + child: task.dyn_child_items, + compute: MigrationCompute::Auto, + }); + } + + MigrationProcess::::put(task); + + weight + } else { + T::DbWeight::get().reads(1) + } + } + } + + impl Pallet { + /// The real weight of a migration of the given number of `items` with total `size`. + fn dynamic_weight(items: u32, size: u32) -> frame_support::pallet_prelude::Weight { + let items = items as Weight; + items + .saturating_mul(::DbWeight::get().reads_writes(1, 1)) + // we assume that the read/write per-byte weight is the same for child and top tree. + .saturating_add(T::WeightInfo::process_top_key(size)) + } + + /// Put a stop to all ongoing migrations. + fn halt() { + AutoLimits::::kill(); + Self::deposit_event(Event::::Halted); + } + + /// Convert a child root key, aka. "Child-bearing top key" into the proper format. + fn transform_child_key(root: &Vec) -> Option<&[u8]> { + use sp_core::storage::{ChildType, PrefixedStorageKey}; + match ChildType::from_prefixed_key(PrefixedStorageKey::new_ref(root)) { + Some((ChildType::ParentKeyId, root)) => Some(root), + _ => None, + } + } + + /// Same as [`child_io_key`], and it halts the auto/unsigned migrations if a bad child root + /// is used. + /// + /// This should be used when we are sure that `root` is a correct default child root. + fn transform_child_key_or_halt(root: &Vec) -> &[u8] { + let key = Self::transform_child_key(root); + if key.is_none() { + Self::halt(); + } + key.unwrap_or_default() + } + + /// Convert a child root to be in the default child-tree. + #[cfg(any(test, feature = "runtime-benchmarks"))] + pub(crate) fn childify(root: &'static str) -> Vec { + let mut string = DEFAULT_CHILD_STORAGE_KEY_PREFIX.to_vec(); + string.extend_from_slice(root.as_ref()); + string + } + } +} + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarks { + use super::{pallet::Pallet as StateTrieMigration, *}; + use frame_support::traits::{Currency, Get}; + use sp_runtime::traits::Saturating; + use sp_std::prelude::*; + + // The size of the key seemingly makes no difference in the read/write time, so we make it + // constant. + const KEY: &'static [u8] = b"key"; + + frame_benchmarking::benchmarks! { + continue_migrate { + // note that this benchmark should migrate nothing, as we only want the overhead weight + // of the bookkeeping, and the migration cost itself is noted via the `dynamic_weight` + // function. + let null = MigrationLimits::default(); + let caller = frame_benchmarking::whitelisted_caller(); + }: _(frame_system::RawOrigin::Signed(caller), null, 0, StateTrieMigration::::migration_process()) + verify { + assert_eq!(StateTrieMigration::::migration_process(), Default::default()) + } + + continue_migrate_wrong_witness { + let null = MigrationLimits::default(); + let caller = frame_benchmarking::whitelisted_caller(); + let bad_witness = MigrationTask { last_top: Some(vec![1u8]), ..Default::default() }; + }: { + assert!( + StateTrieMigration::::continue_migrate( + frame_system::RawOrigin::Signed(caller).into(), + null, + 0, + bad_witness, + ) + .is_err() + ) + } + verify { + assert_eq!(StateTrieMigration::::migration_process(), Default::default()) + } + + migrate_custom_top_success { + let null = MigrationLimits::default(); + let caller = frame_benchmarking::whitelisted_caller(); + let deposit = T::SignedDepositBase::get().saturating_add( + T::SignedDepositPerItem::get().saturating_mul(1u32.into()), + ); + let stash = T::Currency::minimum_balance() * BalanceOf::::from(1000u32) + deposit; + T::Currency::make_free_balance_be(&caller, stash); + }: migrate_custom_top(frame_system::RawOrigin::Signed(caller.clone()), Default::default(), 0) + verify { + assert_eq!(StateTrieMigration::::migration_process(), Default::default()); + assert_eq!(T::Currency::free_balance(&caller), stash) + } + + migrate_custom_top_fail { + let null = MigrationLimits::default(); + let caller = frame_benchmarking::whitelisted_caller(); + let deposit = T::SignedDepositBase::get().saturating_add( + T::SignedDepositPerItem::get().saturating_mul(1u32.into()), + ); + let stash = T::Currency::minimum_balance() * BalanceOf::::from(1000u32) + deposit; + T::Currency::make_free_balance_be(&caller, stash); + // for tests, we need to make sure there is _something_ in storage that is being + // migrated. + sp_io::storage::set(b"foo", vec![1u8;33].as_ref()); + }: { + assert!( + StateTrieMigration::::migrate_custom_top( + frame_system::RawOrigin::Signed(caller.clone()).into(), + vec![b"foo".to_vec()], + 1, + ).is_err() + ) + } + verify { + assert_eq!(StateTrieMigration::::migration_process(), Default::default()); + // must have gotten slashed + assert!(T::Currency::free_balance(&caller) < stash) + } + + migrate_custom_child_success { + let caller = frame_benchmarking::whitelisted_caller(); + let deposit = T::SignedDepositBase::get().saturating_add( + T::SignedDepositPerItem::get().saturating_mul(1u32.into()), + ); + let stash = T::Currency::minimum_balance() * BalanceOf::::from(1000u32) + deposit; + T::Currency::make_free_balance_be(&caller, stash); + }: migrate_custom_child( + frame_system::RawOrigin::Signed(caller.clone()), + StateTrieMigration::::childify(Default::default()), + Default::default(), + 0 + ) + verify { + assert_eq!(StateTrieMigration::::migration_process(), Default::default()); + assert_eq!(T::Currency::free_balance(&caller), stash); + } + + migrate_custom_child_fail { + let caller = frame_benchmarking::whitelisted_caller(); + let deposit = T::SignedDepositBase::get().saturating_add( + T::SignedDepositPerItem::get().saturating_mul(1u32.into()), + ); + let stash = T::Currency::minimum_balance() * BalanceOf::::from(1000u32) + deposit; + T::Currency::make_free_balance_be(&caller, stash); + // for tests, we need to make sure there is _something_ in storage that is being + // migrated. + sp_io::default_child_storage::set(b"top", b"foo", vec![1u8;33].as_ref()); + }: { + assert!( + StateTrieMigration::::migrate_custom_child( + frame_system::RawOrigin::Signed(caller.clone()).into(), + StateTrieMigration::::childify("top"), + vec![b"foo".to_vec()], + 1, + ).is_err() + ) + } + verify { + assert_eq!(StateTrieMigration::::migration_process(), Default::default()); + // must have gotten slashed + assert!(T::Currency::free_balance(&caller) < stash) + } + + process_top_key { + let v in 1 .. (4 * 1024 * 1024); + + let value = sp_std::vec![1u8; v as usize]; + sp_io::storage::set(KEY, &value); + }: { + let data = sp_io::storage::get(KEY).unwrap(); + sp_io::storage::set(KEY, &data); + let _next = sp_io::storage::next_key(KEY); + assert_eq!(data, value); + } + + impl_benchmark_test_suite!( + StateTrieMigration, + crate::mock::new_test_ext(sp_runtime::StateVersion::V0, true, None, None), + crate::mock::Test + ); + } +} + +#[cfg(test)] +mod mock { + use super::*; + use crate as pallet_state_trie_migration; + use frame_support::{parameter_types, traits::Hooks}; + use frame_system::{EnsureRoot, EnsureSigned}; + use sp_core::{ + storage::{ChildInfo, StateVersion}, + H256, + }; + use sp_runtime::{ + traits::{BlakeTwo256, Header as _, IdentityLookup}, + StorageChild, + }; + + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + type Block = frame_system::mocking::MockBlock; + + // Configure a mock runtime to test the pallet. + frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Config, Storage, Event}, + StateTrieMigration: pallet_state_trie_migration::{Pallet, Call, Storage, Event}, + } + ); + + parameter_types! { + pub const BlockHashCount: u32 = 250; + pub const SS58Prefix: u8 = 42; + } + + impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u32; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = sp_runtime::generic::Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + } + + parameter_types! { + pub const ExistentialDeposit: u64 = 1; + pub const OffchainRepeat: u32 = 1; + pub const SignedDepositPerItem: u64 = 1; + pub const SignedDepositBase: u64 = 5; + pub const SignedMigrationMaxLimits: MigrationLimits = MigrationLimits { size: 1024, item: 5 }; + } + + impl pallet_balances::Config for Test { + type Balance = u64; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type WeightInfo = (); + } + + impl pallet_state_trie_migration::Config for Test { + type Event = Event; + type ControlOrigin = EnsureRoot; + type Currency = Balances; + type SignedDepositPerItem = SignedDepositPerItem; + type SignedDepositBase = SignedDepositBase; + type SignedMigrationMaxLimits = SignedMigrationMaxLimits; + type SignedFilter = EnsureSigned; + type WeightInfo = (); + } + + pub fn new_test_ext( + version: StateVersion, + with_pallets: bool, + custom_keys: Option, Vec)>>, + custom_child: Option, Vec, Vec)>>, + ) -> sp_io::TestExternalities { + let minimum_size = sp_core::storage::TRIE_VALUE_NODE_THRESHOLD as usize + 1; + let mut custom_storage = sp_core::storage::Storage { + top: vec![ + (b"key1".to_vec(), vec![1u8; minimum_size + 1]), // 6b657931 + (b"key2".to_vec(), vec![1u8; minimum_size + 2]), // 6b657931 + (b"key3".to_vec(), vec![1u8; minimum_size + 3]), // 6b657931 + (b"key4".to_vec(), vec![1u8; minimum_size + 4]), // 6b657931 + (b"key5".to_vec(), vec![1u8; minimum_size + 5]), // 6b657932 + (b"key6".to_vec(), vec![1u8; minimum_size + 6]), // 6b657934 + (b"key7".to_vec(), vec![1u8; minimum_size + 7]), // 6b657934 + (b"key8".to_vec(), vec![1u8; minimum_size + 8]), // 6b657934 + (b"key9".to_vec(), vec![1u8; minimum_size + 9]), // 6b657934 + (b"CODE".to_vec(), vec![1u8; minimum_size + 100]), // 434f4445 + ] + .into_iter() + .chain(custom_keys.unwrap_or_default()) + .collect(), + children_default: vec![ + ( + b"chk1".to_vec(), // 63686b31 + StorageChild { + data: vec![ + (b"key1".to_vec(), vec![1u8; 55]), + (b"key2".to_vec(), vec![2u8; 66]), + ] + .into_iter() + .collect(), + child_info: ChildInfo::new_default(b"chk1"), + }, + ), + ( + b"chk2".to_vec(), + StorageChild { + data: vec![ + (b"key1".to_vec(), vec![1u8; 54]), + (b"key2".to_vec(), vec![2u8; 64]), + ] + .into_iter() + .collect(), + child_info: ChildInfo::new_default(b"chk2"), + }, + ), + ] + .into_iter() + .chain( + custom_child + .unwrap_or_default() + .into_iter() + .map(|(r, k, v)| { + ( + r.clone(), + StorageChild { + data: vec![(k, v)].into_iter().collect(), + child_info: ChildInfo::new_default(&r), + }, + ) + }) + .collect::>(), + ) + .collect(), + }; + + if with_pallets { + frame_system::GenesisConfig::default() + .assimilate_storage::(&mut custom_storage) + .unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![(1, 1000)] } + .assimilate_storage(&mut custom_storage) + .unwrap(); + } + + sp_tracing::try_init_simple(); + (custom_storage, version).into() + } + + pub(crate) fn run_to_block(n: u32) -> (H256, u64) { + let mut root = Default::default(); + let mut weight_sum = 0; + log::trace!(target: LOG_TARGET, "running from {:?} to {:?}", System::block_number(), n); + while System::block_number() < n { + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + + weight_sum += StateTrieMigration::on_initialize(System::block_number()); + + root = System::finalize().state_root().clone(); + System::on_finalize(System::block_number()); + } + (root, weight_sum) + } +} + +#[cfg(test)] +mod test { + use super::{mock::*, *}; + use sp_runtime::{traits::Bounded, StateVersion}; + + #[test] + fn fails_if_no_migration() { + let mut ext = new_test_ext(StateVersion::V0, false, None, None); + let root1 = ext.execute_with(|| run_to_block(30).0); + + let mut ext2 = new_test_ext(StateVersion::V1, false, None, None); + let root2 = ext2.execute_with(|| run_to_block(30).0); + + // these two roots should not be the same. + assert_ne!(root1, root2); + } + + #[test] + #[ignore] + fn detects_value_in_empty_top_key() { + let limit = MigrationLimits { item: 1, size: 1000 }; + let initial_keys = Some(vec![(vec![], vec![66u8; 77])]); + let mut ext = new_test_ext(StateVersion::V0, false, initial_keys.clone(), None); + + let root_upgraded = ext.execute_with(|| { + sp_io::storage::set(&[], &vec![66u8; 77]); + + AutoLimits::::put(Some(limit)); + let root = run_to_block(30).0; + + // eventually everything is over. + assert!(StateTrieMigration::migration_process().finished()); + root + }); + + let mut ext2 = new_test_ext(StateVersion::V1, false, initial_keys, None); + let root = ext2.execute_with(|| { + AutoLimits::::put(Some(limit)); + run_to_block(30).0 + }); + + assert_eq!(root, root_upgraded); + } + + #[test] + #[ignore] + fn detects_value_in_first_child_key() { + use frame_support::storage::child; + let limit = MigrationLimits { item: 1, size: 1000 }; + let initial_child = Some(vec![(b"chk1".to_vec(), vec![], vec![66u8; 77])]); + let mut ext = new_test_ext(StateVersion::V0, false, None, initial_child.clone()); + + let root_upgraded = ext.execute_with(|| { + AutoLimits::::put(Some(limit)); + let root = run_to_block(30).0; + + // eventually everything is over. + assert!(StateTrieMigration::migration_process().finished()); + root + }); + + let mut ext2 = new_test_ext(StateVersion::V1, false, None, initial_child); + let root = ext2.execute_with(|| { + child::put(&child::ChildInfo::new_default(b"chk1"), &[], &vec![66u8; 77]); + AutoLimits::::put(Some(limit)); + run_to_block(30).0 + }); + + assert_eq!(root, root_upgraded); + } + + #[test] + fn auto_migrate_works() { + let run_with_limits = |limit, from, until| { + let mut ext = new_test_ext(StateVersion::V0, false, None, None); + let root_upgraded = ext.execute_with(|| { + assert_eq!(AutoLimits::::get(), None); + assert_eq!(MigrationProcess::::get(), Default::default()); + + // nothing happens if we don't set the limits. + let _ = run_to_block(from); + assert_eq!(MigrationProcess::::get(), Default::default()); + + // this should allow 1 item per block to be migrated. + AutoLimits::::put(Some(limit)); + + let root = run_to_block(until).0; + + // eventually everything is over. + assert!(matches!( + StateTrieMigration::migration_process(), + MigrationTask { last_child: None, last_top: None, .. } + )); + root + }); + + let mut ext2 = new_test_ext(StateVersion::V1, false, None, None); + let root = ext2.execute_with(|| { + // update ex2 to contain the new items + let _ = run_to_block(from); + AutoLimits::::put(Some(limit)); + run_to_block(until).0 + }); + assert_eq!(root, root_upgraded); + }; + + // single item + run_with_limits(MigrationLimits { item: 1, size: 1000 }, 10, 100); + // multi-item + run_with_limits(MigrationLimits { item: 5, size: 1000 }, 10, 100); + // multi-item, based on size. Note that largest value is 100 bytes. + run_with_limits(MigrationLimits { item: 1000, size: 128 }, 10, 100); + // unbounded + run_with_limits( + MigrationLimits { item: Bounded::max_value(), size: Bounded::max_value() }, + 10, + 100, + ); + } + + #[test] + fn signed_migrate_works() { + new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { + assert_eq!(MigrationProcess::::get(), Default::default()); + + // can't submit if limit is too high. + frame_support::assert_err!( + StateTrieMigration::continue_migrate( + Origin::signed(1), + MigrationLimits { item: 5, size: sp_runtime::traits::Bounded::max_value() }, + Bounded::max_value(), + MigrationProcess::::get() + ), + Error::::MaxSignedLimits, + ); + + // can't submit if poor. + frame_support::assert_err!( + StateTrieMigration::continue_migrate( + Origin::signed(2), + MigrationLimits { item: 5, size: 100 }, + 100, + MigrationProcess::::get() + ), + Error::::NotEnoughFunds, + ); + + // can't submit with bad witness. + frame_support::assert_err_ignore_postinfo!( + StateTrieMigration::continue_migrate( + Origin::signed(1), + MigrationLimits { item: 5, size: 100 }, + 100, + MigrationTask { last_top: Some(vec![1u8]), ..Default::default() } + ), + Error::::BadWitness + ); + + // migrate all keys in a series of submissions + while !MigrationProcess::::get().finished() { + // first we compute the task to get the accurate consumption. + let mut task = StateTrieMigration::migration_process(); + task.migrate_until_exhaustion(SignedMigrationMaxLimits::get()); + + frame_support::assert_ok!(StateTrieMigration::continue_migrate( + Origin::signed(1), + SignedMigrationMaxLimits::get(), + task.dyn_size, + MigrationProcess::::get() + )); + + // no funds should remain reserved. + assert_eq!(Balances::reserved_balance(&1), 0); + + // and the task should be updated + assert!(matches!( + StateTrieMigration::migration_process(), + MigrationTask { size: x, .. } if x > 0, + )); + } + }); + } + + #[test] + fn custom_migrate_top_works() { + let correct_witness = 3 + sp_core::storage::TRIE_VALUE_NODE_THRESHOLD * 3 + 1 + 2 + 3; + new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { + frame_support::assert_ok!(StateTrieMigration::migrate_custom_top( + Origin::signed(1), + vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], + correct_witness, + )); + + // no funds should remain reserved. + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(&1), 1000); + }); + + new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { + // works if the witness is an overestimate + frame_support::assert_ok!(StateTrieMigration::migrate_custom_top( + Origin::signed(1), + vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], + correct_witness + 99, + )); + + // no funds should remain reserved. + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(&1), 1000); + }); + + new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { + assert_eq!(Balances::free_balance(&1), 1000); + + // note that we don't expect this to be a noop -- we do slash. + frame_support::assert_err!( + StateTrieMigration::migrate_custom_top( + Origin::signed(1), + vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], + correct_witness - 1, + ), + "wrong witness data" + ); + + // no funds should remain reserved. + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!( + Balances::free_balance(&1), + 1000 - (3 * SignedDepositPerItem::get() + SignedDepositBase::get()) + ); + }); + } + + #[test] + fn custom_migrate_child_works() { + new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { + frame_support::assert_ok!(StateTrieMigration::migrate_custom_child( + Origin::signed(1), + StateTrieMigration::childify("chk1"), + vec![b"key1".to_vec(), b"key2".to_vec()], + 55 + 66, + )); + + // no funds should remain reserved. + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(&1), 1000); + }); + + new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { + assert_eq!(Balances::free_balance(&1), 1000); + + // note that we don't expect this to be a noop -- we do slash. + assert!(StateTrieMigration::migrate_custom_child( + Origin::signed(1), + StateTrieMigration::childify("chk1"), + vec![b"key1".to_vec(), b"key2".to_vec()], + 999999, // wrong witness + ) + .is_err()); + + // no funds should remain reserved. + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!( + Balances::free_balance(&1), + 1000 - (2 * SignedDepositPerItem::get() + SignedDepositBase::get()) + ); + }); + } +} + +/// Exported set of tests to be called against different runtimes. +#[cfg(feature = "remote-test")] +pub(crate) mod remote_tests { + use crate::{AutoLimits, MigrationLimits, Pallet as StateTrieMigration, LOG_TARGET}; + use codec::Encode; + use frame_benchmarking::Zero; + use frame_support::traits::{Get, Hooks}; + use frame_system::Pallet as System; + use remote_externalities::Mode; + use sp_core::H256; + use sp_runtime::traits::{Block as BlockT, HashFor, Header as _, One}; + use thousands::Separable; + + fn run_to_block>( + n: ::BlockNumber, + ) -> (H256, u64) { + let mut root = Default::default(); + let mut weight_sum = 0; + while System::::block_number() < n { + System::::set_block_number(System::::block_number() + One::one()); + System::::on_initialize(System::::block_number()); + + weight_sum += + StateTrieMigration::::on_initialize(System::::block_number()); + + root = System::::finalize().state_root().clone(); + System::::on_finalize(System::::block_number()); + } + (root, weight_sum) + } + + /// Run the entire migration, against the given `Runtime`, until completion. + /// + /// This will print some very useful statistics, make sure [`crate::LOG_TARGET`] is enabled. + pub(crate) async fn run_with_limits< + Runtime: crate::Config, + Block: BlockT + serde::de::DeserializeOwned, + >( + limits: MigrationLimits, + mode: Mode, + ) { + let mut ext = remote_externalities::Builder::::new() + .mode(mode) + .state_version(sp_core::storage::StateVersion::V0) + .build() + .await + .unwrap(); + + let mut now = ext.execute_with(|| { + AutoLimits::::put(Some(limits)); + // requires the block number type in our tests to be same as with mainnet, u32. + frame_system::Pallet::::block_number() + }); + + let mut duration: ::BlockNumber = Zero::zero(); + // set the version to 1, as if the upgrade happened. + ext.state_version = sp_core::storage::StateVersion::V1; + + let (top_left, child_left) = ext.as_backend().essence().check_migration_state().unwrap(); + assert!( + top_left > 0, + "no node needs migrating, this probably means that state was initialized with `StateVersion::V1`", + ); + + log::info!( + target: LOG_TARGET, + "initial check: top_left: {}, child_left: {}", + top_left.separate_with_commas(), + child_left.separate_with_commas(), + ); + + loop { + let last_state_root = ext.backend.root().clone(); + let ((finished, weight), proof) = ext.execute_and_prove(|| { + let weight = run_to_block::(now + One::one()).1; + if StateTrieMigration::::migration_process().finished() { + return (true, weight) + } + duration += One::one(); + now += One::one(); + (false, weight) + }); + + let compact_proof = + proof.clone().into_compact_proof::>(last_state_root).unwrap(); + log::info!( + target: LOG_TARGET, + "proceeded to #{}, weight: [{} / {}], proof: [{} / {} / {}]", + now, + weight.separate_with_commas(), + ::BlockWeights::get() + .max_block + .separate_with_commas(), + proof.encoded_size().separate_with_commas(), + compact_proof.encoded_size().separate_with_commas(), + zstd::stream::encode_all(&compact_proof.encode()[..], 0) + .unwrap() + .len() + .separate_with_commas(), + ); + ext.commit_all().unwrap(); + + if finished { + break + } + } + + ext.execute_with(|| { + log::info!( + target: LOG_TARGET, + "finished on_initialize migration in {} block, final state of the task: {:?}", + duration, + StateTrieMigration::::migration_process(), + ) + }); + + let (top_left, child_left) = ext.as_backend().essence().check_migration_state().unwrap(); + assert_eq!(top_left, 0); + assert_eq!(child_left, 0); + } +} + +#[cfg(all(test, feature = "remote-test"))] +mod remote_tests_local { + use super::{ + mock::{Call as MockCall, *}, + remote_tests::run_with_limits, + *, + }; + use remote_externalities::{Mode, OfflineConfig, OnlineConfig}; + use sp_runtime::traits::Bounded; + + // we only use the hash type from this, so using the mock should be fine. + type Extrinsic = sp_runtime::testing::TestXt; + type Block = sp_runtime::testing::Block; + + #[tokio::test] + async fn on_initialize_migration() { + sp_tracing::try_init_simple(); + let mode = Mode::OfflineOrElseOnline( + OfflineConfig { state_snapshot: env!("SNAP").to_owned().into() }, + OnlineConfig { + transport: std::env!("WS_API").to_owned().into(), + state_snapshot: Some(env!("SNAP").to_owned().into()), + ..Default::default() + }, + ); + + // item being the bottleneck + run_with_limits::( + MigrationLimits { item: 8 * 1024, size: 128 * 1024 * 1024 }, + mode.clone(), + ) + .await; + // size being the bottleneck + run_with_limits::( + MigrationLimits { item: Bounded::max_value(), size: 64 * 1024 }, + mode, + ) + .await; + } +} diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs new file mode 100644 index 0000000000000..f08b115378f21 --- /dev/null +++ b/frame/state-trie-migration/src/weights.rs @@ -0,0 +1,137 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_state_trie_migration +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-03-04, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/production/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_state_trie_migration +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/state-trie-migration/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_state_trie_migration. +pub trait WeightInfo { + fn continue_migrate() -> Weight; + fn continue_migrate_wrong_witness() -> Weight; + fn migrate_custom_top_success() -> Weight; + fn migrate_custom_top_fail() -> Weight; + fn migrate_custom_child_success() -> Weight; + fn migrate_custom_child_fail() -> Weight; + fn process_top_key(v: u32, ) -> Weight; +} + +/// Weights for pallet_state_trie_migration using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: StateTrieMigration MigrationProcess (r:1 w:1) + fn continue_migrate() -> Weight { + (13_385_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: StateTrieMigration MigrationProcess (r:1 w:0) + fn continue_migrate_wrong_witness() -> Weight { + (1_757_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + } + fn migrate_custom_top_success() -> Weight { + (12_813_000 as Weight) + } + // Storage: unknown [0x666f6f] (r:1 w:1) + fn migrate_custom_top_fail() -> Weight { + (24_961_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + fn migrate_custom_child_success() -> Weight { + (13_132_000 as Weight) + } + // Storage: unknown [0x666f6f] (r:1 w:1) + fn migrate_custom_child_fail() -> Weight { + (29_215_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: unknown [0x6b6579] (r:1 w:1) + fn process_top_key(v: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: StateTrieMigration MigrationProcess (r:1 w:1) + fn continue_migrate() -> Weight { + (13_385_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: StateTrieMigration MigrationProcess (r:1 w:0) + fn continue_migrate_wrong_witness() -> Weight { + (1_757_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + } + fn migrate_custom_top_success() -> Weight { + (12_813_000 as Weight) + } + // Storage: unknown [0x666f6f] (r:1 w:1) + fn migrate_custom_top_fail() -> Weight { + (24_961_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn migrate_custom_child_success() -> Weight { + (13_132_000 as Weight) + } + // Storage: unknown [0x666f6f] (r:1 w:1) + fn migrate_custom_child_fail() -> Weight { + (29_215_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: unknown [0x6b6579] (r:1 w:1) + fn process_top_key(v: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } +} diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index d2fd438d3a802..8c61874003bce 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -38,18 +38,18 @@ macro_rules! defensive { frame_support::log::error!( target: "runtime", "{}", - $crate::traits::misc::DEFENSIVE_OP_PUBLIC_ERROR + $crate::traits::DEFENSIVE_OP_PUBLIC_ERROR ); - debug_assert!(false, "{}", $crate::traits::misc::DEFENSIVE_OP_INTERNAL_ERROR); + debug_assert!(false, "{}", $crate::traits::DEFENSIVE_OP_INTERNAL_ERROR); }; ($error:tt) => { frame_support::log::error!( target: "runtime", "{}: {:?}", - $crate::traits::misc::DEFENSIVE_OP_PUBLIC_ERROR, + $crate::traits::DEFENSIVE_OP_PUBLIC_ERROR, $error ); - debug_assert!(false, "{}: {:?}", $crate::traits::misc::DEFENSIVE_OP_INTERNAL_ERROR, $error); + debug_assert!(false, "{}: {:?}", $crate::traits::DEFENSIVE_OP_INTERNAL_ERROR, $error); } } diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index d21364d3f8fbb..b7c8b69e8a0ab 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -96,7 +96,7 @@ pub enum ExecutionContext { /// We distinguish between major sync and import so that validators who are running /// their initial sync (or catching up after some time offline) can use the faster /// native runtime (since we can reasonably assume the network as a whole has already - /// come to a broad conensus on the block and it probably hasn't been crafted + /// come to a broad consensus on the block and it probably hasn't been crafted /// specifically to attack this node), but when importing blocks at the head of the /// chain in normal operation they can use the safer Wasm version. Syncing, diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index 6be601aa72b34..7f71d24b761a9 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -23,8 +23,8 @@ use std::{ }; use crate::{ - backend::Backend, ext::Ext, InMemoryBackend, InMemoryProvingBackend, OverlayedChanges, - StorageKey, StorageTransactionCache, StorageValue, + backend::Backend, ext::Ext, InMemoryBackend, OverlayedChanges, StorageKey, + StorageTransactionCache, StorageValue, }; use hash_db::Hasher; @@ -100,7 +100,6 @@ where state_version: StateVersion, ) -> Self { assert!(storage.top.keys().all(|key| !is_child_storage_key(key))); - assert!(storage.children_default.keys().all(|key| is_child_storage_key(key))); storage.top.insert(CODE.to_vec(), code.to_vec()); @@ -204,7 +203,7 @@ where /// This implementation will wipe the proof recorded in between calls. Consecutive calls will /// get their own proof from scratch. pub fn execute_and_prove(&mut self, execute: impl FnOnce() -> R) -> (R, StorageProof) { - let proving_backend = InMemoryProvingBackend::new(&self.backend); + let proving_backend = crate::InMemoryProvingBackend::new(&self.backend); let mut proving_ext = Ext::new( &mut self.overlay, &mut self.storage_transaction_cache, diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index e33e50641bbde..b0eb543824379 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -23,21 +23,23 @@ use codec::Encode; use hash_db::{self, AsHashDB, HashDB, HashDBRef, Hasher, Prefix}; #[cfg(feature = "std")] use parking_lot::RwLock; -use sp_core::storage::{ChildInfo, ChildType, StateVersion}; +use sp_core::storage::{ChildInfo, ChildType, PrefixedStorageKey, StateVersion}; use sp_std::{boxed::Box, vec::Vec}; use sp_trie::{ child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_value, read_trie_value, trie_types::{TrieDB, TrieError}, - DBValue, KeySpacedDB, PrefixedMemoryDB, Trie, TrieDBIterator, TrieDBKeyIterator, + DBValue, KeySpacedDB, LayoutV1 as Layout, PrefixedMemoryDB, Trie, TrieDBIterator, + TrieDBKeyIterator, }; #[cfg(feature = "std")] use std::collections::HashMap; #[cfg(feature = "std")] use std::sync::Arc; -// In this module, we only use layout for read operation and empty root, -// where V1 and V0 are equivalent. -use sp_trie::LayoutV1 as Layout; +use trie_db::{ + node::{NodePlan, ValuePlan}, + TrieDBNodeIterator, +}; #[cfg(not(feature = "std"))] macro_rules! format { @@ -431,6 +433,72 @@ where ); } + /// Check remaining state item to migrate. Note this function should be remove when all state + /// migration did finished as it is only an utility. + // original author: @cheme + pub fn check_migration_state(&self) -> Result<(u64, u64)> { + let threshold: u32 = sp_core::storage::TRIE_VALUE_NODE_THRESHOLD; + let mut nb_to_migrate = 0; + let mut nb_to_migrate_child = 0; + + let trie = sp_trie::trie_types::TrieDB::new(self, &self.root) + .map_err(|e| format!("TrieDB creation error: {}", e))?; + let iter_node = TrieDBNodeIterator::new(&trie) + .map_err(|e| format!("TrieDB node iterator error: {}", e))?; + for node in iter_node { + let node = node.map_err(|e| format!("TrieDB node iterator error: {}", e))?; + match node.2.node_plan() { + NodePlan::Leaf { value, .. } | + NodePlan::NibbledBranch { value: Some(value), .. } => + if let ValuePlan::Inline(range) = value { + if (range.end - range.start) as u32 >= threshold { + nb_to_migrate += 1; + } + }, + _ => (), + } + } + + let mut child_roots: Vec<(ChildInfo, Vec)> = Vec::new(); + // get all child trie roots + for key_value in trie.iter().map_err(|e| format!("TrieDB node iterator error: {}", e))? { + let (key, value) = + key_value.map_err(|e| format!("TrieDB node iterator error: {}", e))?; + if key[..] + .starts_with(sp_core::storage::well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX) + { + let prefixed_key = PrefixedStorageKey::new(key); + let (_type, unprefixed) = ChildType::from_prefixed_key(&prefixed_key).unwrap(); + child_roots.push((ChildInfo::new_default(unprefixed), value)); + } + } + for (child_info, root) in child_roots { + let mut child_root = H::Out::default(); + let storage = KeySpacedDB::new(self, child_info.keyspace()); + + child_root.as_mut()[..].copy_from_slice(&root[..]); + let trie = sp_trie::trie_types::TrieDB::new(&storage, &child_root) + .map_err(|e| format!("New child TrieDB error: {}", e))?; + let iter_node = TrieDBNodeIterator::new(&trie) + .map_err(|e| format!("TrieDB node iterator error: {}", e))?; + for node in iter_node { + let node = node.map_err(|e| format!("Child TrieDB node iterator error: {}", e))?; + match node.2.node_plan() { + NodePlan::Leaf { value, .. } | + NodePlan::NibbledBranch { value: Some(value), .. } => + if let ValuePlan::Inline(range) = value { + if (range.end - range.start) as u32 >= threshold { + nb_to_migrate_child += 1; + } + }, + _ => (), + } + } + } + + Ok((nb_to_migrate, nb_to_migrate_child)) + } + /// Returns all `(key, value)` pairs in the trie. pub fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { let collect_all = || -> sp_std::result::Result<_, Box>> { diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index 1e97454b26055..d377ea931df2d 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -119,8 +119,7 @@ impl DerefMut for PrefixedStorageKey { } impl PrefixedStorageKey { - /// Create a prefixed storage key from its byte array - /// representation. + /// Create a prefixed storage key from its byte array representation. pub fn new(inner: Vec) -> Self { PrefixedStorageKey(inner) } @@ -130,9 +129,7 @@ impl PrefixedStorageKey { PrefixedStorageKey::ref_cast(inner) } - /// Get inner key, this should - /// only be needed when writing - /// into parent trie to avoid an + /// Get inner key, this should only be needed when writing into parent trie to avoid an /// allocation. pub fn into_inner(self) -> Vec { self.0 @@ -171,10 +168,8 @@ pub struct StorageChild { pub struct Storage { /// Top trie storage data. pub top: StorageMap, - /// Children trie storage data. - /// The key does not including prefix, for the `default` - /// trie kind, so this is exclusively for the `ChildType::ParentKeyId` - /// tries. + /// Children trie storage data. Key does not include prefix, only for the `default` trie kind, + /// of `ChildType::ParentKeyId` type. pub children_default: std::collections::HashMap, StorageChild>, } diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index d6dfd1c59d4ee..533d65c49c2e1 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -40,7 +40,7 @@ use sp_core::{ }, }; pub use sp_io::TestExternalities; -use sp_runtime::traits::Block as BlockT; +use sp_runtime::{traits::Block as BlockT, StateVersion}; use std::{ fs, path::{Path, PathBuf}, @@ -56,6 +56,7 @@ type ChildKeyValues = Vec<(ChildInfo, Vec)>; const LOG_TARGET: &str = "remote-ext"; const DEFAULT_TARGET: &str = "wss://rpc.polkadot.io:443"; const BATCH_SIZE: usize = 1000; +const PAGE: u32 = 512; #[rpc(client)] pub trait RpcApi { @@ -117,12 +118,6 @@ pub struct OfflineConfig { pub state_snapshot: SnapshotConfig, } -impl> From

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 z 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�E@^ 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

nkyoJ7^W9c3~jN;vc3sOtk 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ψ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

7%jb0-+Ae% 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

B@n*FM}mz*gwh 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

for SnapshotConfig { - fn from(p: P) -> Self { - Self { path: p.into() } - } -} - /// Description of the transport protocol (for online execution). #[derive(Debug, Clone)] pub enum Transport { @@ -187,6 +182,8 @@ pub struct OnlineConfig { pub pallets: Vec, /// Transport config. pub transport: Transport, + /// Lookout for child-keys, and scrape them as well if set to true. + pub scrape_children: bool, } impl OnlineConfig { @@ -205,10 +202,17 @@ impl Default for OnlineConfig { at: None, state_snapshot: None, pallets: vec![], + scrape_children: true, } } } +impl From for OnlineConfig { + fn from(s: String) -> Self { + Self { transport: s.into(), ..Default::default() } + } +} + /// Configuration of the state snapshot. #[derive(Clone)] pub struct SnapshotConfig { @@ -222,6 +226,12 @@ impl SnapshotConfig { } } +impl From for SnapshotConfig { + fn from(s: String) -> Self { + Self::new(s) + } +} + impl Default for SnapshotConfig { fn default() -> Self { Self { path: Path::new("SNAPSHOT").into() } @@ -242,6 +252,8 @@ pub struct Builder { hashed_blacklist: Vec>, /// connectivity mode, online or offline. mode: Mode, + /// The state version being used. + state_version: StateVersion, } // NOTE: ideally we would use `DefaultNoBound` here, but not worth bringing in frame-support for @@ -254,6 +266,7 @@ impl Default for Builder { hashed_prefixes: Default::default(), hashed_keys: Default::default(), hashed_blacklist: Default::default(), + state_version: StateVersion::V1, } } } @@ -306,7 +319,6 @@ impl Builder { prefix: StorageKey, at: B::Hash, ) -> Result, &'static str> { - const PAGE: u32 = 512; let mut last_key: Option = None; let mut all_keys: Vec = vec![]; let keys = loop { @@ -320,6 +332,7 @@ impl Builder { "rpc get_keys failed" })?; let page_len = page.len(); + all_keys.extend(page); if page_len < PAGE as usize { @@ -362,11 +375,12 @@ impl Builder { .cloned() .map(|key| ("state_getStorage", rpc_params![key, at])) .collect::>(); + let values = client.batch_request::>(batch).await.map_err(|e| { log::error!( target: LOG_TARGET, "failed to execute batch: {:?}. Error: {:?}", - chunk_keys, + chunk_keys.iter().map(|k| HexDisplay::from(k)).collect::>(), e ); "batch failed." @@ -693,7 +707,7 @@ impl Builder { // inject manual key values. if !self.hashed_key_values.is_empty() { - log::debug!( + log::info!( target: LOG_TARGET, "extending externalities with {} manually injected key-values", self.hashed_key_values.len() @@ -703,7 +717,7 @@ impl Builder { // exclude manual key values. if !self.hashed_blacklist.is_empty() { - log::debug!( + log::info!( target: LOG_TARGET, "excluding externalities from {} keys", self.hashed_blacklist.len() @@ -795,6 +809,12 @@ impl Builder { self } + /// The state version to use. + pub fn state_version(mut self, version: StateVersion) -> Self { + self.state_version = version; + self + } + /// overwrite the `at` value, if `mode` is set to [`Mode::Online`]. /// /// noop if `mode` is [`Mode::Offline`] @@ -808,8 +828,13 @@ impl Builder { /// Build the test externalities. pub async fn build(self) -> Result { + let state_version = self.state_version; let (top_kv, child_kv) = self.pre_build().await?; - let mut ext = TestExternalities::new_with_code(Default::default(), Default::default()); + let mut ext = TestExternalities::new_with_code_and_state( + Default::default(), + Default::default(), + state_version, + ); info!(target: LOG_TARGET, "injecting a total of {} top keys", top_kv.len()); for (k, v) in top_kv { @@ -1165,4 +1190,21 @@ mod remote_tests { std::fs::remove_file(d.path()).unwrap(); } } + + #[tokio::test] + async fn can_build_child_tree() { + init_logger(); + Builder::::new() + .mode(Mode::Online(OnlineConfig { + // transport: "wss://kusama-rpc.polkadot.io".to_owned().into(), + transport: "ws://kianenigma-archive:9924".to_owned().into(), + // transport: "ws://localhost:9999".to_owned().into(), + pallets: vec!["Crowdloan".to_owned()], + ..Default::default() + })) + .build() + .await + .expect(REMOTE_INACCESSIBLE) + .execute_with(|| {}); + } } diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index ae7a1c3ae87ca..92721228c9291 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -493,6 +493,7 @@ impl State { transport: uri.to_owned().into(), state_snapshot: snapshot_path.as_ref().map(SnapshotConfig::new), pallets: pallets.clone().unwrap_or_default(), + scrape_children: true, at, })) .inject_hashed_key( From a8b6a5d6a378425b6ec24369579155422fe04dc8 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 4 Mar 2022 18:22:52 +0200 Subject: [PATCH 0578/1472] BEEFY and GRANDPA protocol names should use full genesis hash (#10974) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit std::fmt::Display shows formats as reduced hash (e.g. 0xb0a8…dafe) Use hex::encode to format full hash. Signed-off-by: acatangiu --- Cargo.lock | 4 ++ client/beefy/Cargo.toml | 2 + client/beefy/src/lib.rs | 51 +++++++++++++++++-- client/finality-grandpa/Cargo.toml | 3 ++ .../finality-grandpa/src/communication/mod.rs | 6 +-- .../src/communication/tests.rs | 43 ++++++++++++++++ 6 files changed, 103 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bfe1801740264..db6edfa81d539 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -484,6 +484,7 @@ dependencies = [ "beefy-primitives", "fnv", "futures 0.3.19", + "hex", "log 0.4.14", "parity-scale-codec", "parking_lot 0.12.0", @@ -494,6 +495,7 @@ dependencies = [ "sc-network-gossip", "sc-network-test", "sc-utils", + "serde", "sp-api", "sp-application-crypto", "sp-arithmetic", @@ -8525,6 +8527,7 @@ dependencies = [ "fork-tree", "futures 0.3.19", "futures-timer", + "hex", "log 0.4.14", "parity-scale-codec", "parking_lot 0.12.0", @@ -8539,6 +8542,7 @@ dependencies = [ "sc-network-test", "sc-telemetry", "sc-utils", + "serde", "serde_json", "sp-api", "sp-application-crypto", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index f23b3f5dc4a64..1cd0f1fd50d80 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -10,6 +10,7 @@ description = "BEEFY Client gadget for substrate" [dependencies] fnv = "1.0.6" futures = "0.3" +hex = "0.4.2" log = "0.4" parking_lot = "0.12.0" thiserror = "1.0" @@ -39,4 +40,5 @@ beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sc-network-test = { version = "0.8.0", path = "../network/test" } +serde = "1.0.136" strum = { version = "0.23", features = ["derive"] } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 9b2bf383df8ef..29d74c15dd599 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -53,13 +53,13 @@ pub(crate) mod beefy_protocol_name { /// Name of the notifications protocol used by BEEFY. /// /// Must be registered towards the networking in order for BEEFY to properly function. - pub fn standard_name( + pub fn standard_name>( genesis_hash: &Hash, chain_spec: &Box, ) -> std::borrow::Cow<'static, str> { let chain_prefix = match chain_spec.fork_id() { - Some(fork_id) => format!("/{}/{}", genesis_hash, fork_id), - None => format!("/{}", genesis_hash), + Some(fork_id) => format!("/{}/{}", hex::encode(genesis_hash), fork_id), + None => format!("/{}", hex::encode(genesis_hash)), }; format!("{}{}", chain_prefix, NAME).into() } @@ -190,3 +190,48 @@ where worker.run().await } + +#[cfg(test)] +mod tests { + use super::*; + use sc_chain_spec::{ChainSpec, GenericChainSpec}; + use serde::{Deserialize, Serialize}; + use sp_core::H256; + use sp_runtime::{BuildStorage, Storage}; + + #[derive(Debug, Serialize, Deserialize)] + struct Genesis(std::collections::BTreeMap); + impl BuildStorage for Genesis { + fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { + storage.top.extend( + self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes())), + ); + Ok(()) + } + } + + #[test] + fn beefy_protocol_name() { + let chain_spec = GenericChainSpec::::from_json_file(std::path::PathBuf::from( + "../chain-spec/res/chain_spec.json", + )) + .unwrap() + .cloned_box(); + + // Create protocol name using random genesis hash. + let genesis_hash = H256::random(); + let expected = format!("/{}/beefy/1", hex::encode(genesis_hash)); + let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); + assert_eq!(proto_name.to_string(), expected); + + // Create protocol name using hardcoded genesis hash. Verify exact representation. + let genesis_hash = [ + 50, 4, 60, 123, 58, 106, 216, 246, 194, 188, 139, 193, 33, 212, 202, 171, 9, 55, 123, + 94, 8, 43, 12, 251, 187, 57, 173, 19, 188, 74, 205, 147, + ]; + let expected = + "/32043c7b3a6ad8f6c2bc8bc121d4caab09377b5e082b0cfbbb39ad13bc4acd93/beefy/1".to_string(); + let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); + assert_eq!(proto_name.to_string(), expected); + } +} diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 34feadac5e414..9733f35bd0e93 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -19,6 +19,7 @@ dyn-clone = "1.0" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } futures = "0.3.19" futures-timer = "3.0.1" +hex = "0.4.2" log = "0.4.8" parking_lot = "0.12.0" rand = "0.8.4" @@ -58,5 +59,7 @@ sc-network-test = { version = "0.8.0", path = "../network/test" } sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } + +serde = "1.0.136" tokio = "1.15" tempfile = "3.1.0" diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 809e721448bd7..9c05774fffdf6 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -77,13 +77,13 @@ pub mod grandpa_protocol_name { /// Name of the notifications protocol used by GRANDPA. /// /// Must be registered towards the networking in order for GRANDPA to properly function. - pub fn standard_name( + pub fn standard_name>( genesis_hash: &Hash, chain_spec: &Box, ) -> std::borrow::Cow<'static, str> { let chain_prefix = match chain_spec.fork_id() { - Some(fork_id) => format!("/{}/{}", genesis_hash, fork_id), - None => format!("/{}", genesis_hash), + Some(fork_id) => format!("/{}/{}", hex::encode(genesis_hash), fork_id), + None => format!("/{}", hex::encode(genesis_hash)), }; format!("{}{}", chain_prefix, NAME).into() } diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index c135f58a2eec3..e41d21fc0684e 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -535,3 +535,46 @@ fn peer_with_higher_view_leads_to_catch_up_request() { futures::executor::block_on(test); } + +fn local_chain_spec() -> Box { + use sc_chain_spec::{ChainSpec, GenericChainSpec}; + use serde::{Deserialize, Serialize}; + use sp_runtime::{BuildStorage, Storage}; + + #[derive(Debug, Serialize, Deserialize)] + struct Genesis(std::collections::BTreeMap); + impl BuildStorage for Genesis { + fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { + storage.top.extend( + self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes())), + ); + Ok(()) + } + } + let chain_spec = GenericChainSpec::::from_json_file(std::path::PathBuf::from( + "../chain-spec/res/chain_spec.json", + )) + .unwrap(); + chain_spec.cloned_box() +} + +#[test] +fn grandpa_protocol_name() { + let chain_spec = local_chain_spec(); + + // Create protocol name using random genesis hash. + let genesis_hash = sp_core::H256::random(); + let expected = format!("/{}/grandpa/1", hex::encode(genesis_hash)); + let proto_name = grandpa_protocol_name::standard_name(&genesis_hash, &chain_spec); + assert_eq!(proto_name.to_string(), expected); + + // Create protocol name using hardcoded genesis hash. Verify exact representation. + let genesis_hash = [ + 53, 79, 112, 97, 119, 217, 39, 202, 147, 138, 225, 38, 88, 182, 215, 185, 110, 88, 8, 53, + 125, 210, 158, 151, 50, 113, 102, 59, 245, 199, 221, 240, + ]; + let expected = + "/354f706177d927ca938ae12658b6d7b96e5808357dd29e973271663bf5c7ddf0/grandpa/1".to_string(); + let proto_name = grandpa_protocol_name::standard_name(&genesis_hash, &chain_spec); + assert_eq!(proto_name.to_string(), expected); +} From 7a6d95937d62e1b16ea990fb42ac8d5bf7bda16d Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 4 Mar 2022 21:00:45 +0100 Subject: [PATCH 0579/1472] Move weight constants to own mod (#10980) * Move block+ext weights to own mod Signed-off-by: Oliver Tale-Yazdi * Unused import Signed-off-by: Oliver Tale-Yazdi --- frame/support/src/weights.rs | 14 +++--- frame/support/src/weights/block_weights.rs | 46 +++++++++++++++++++ .../support/src/weights/extrinsic_weights.rs | 46 +++++++++++++++++++ 3 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 frame/support/src/weights/block_weights.rs create mode 100644 frame/support/src/weights/extrinsic_weights.rs diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index 6c2e693eb476e..b3ed42bb45fc4 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -127,6 +127,8 @@ //! - Ubuntu 19.10 (GNU/Linux 5.3.0-18-generic x86_64) //! - rustc 1.42.0 (b8cedc004 2020-03-09) +mod block_weights; +mod extrinsic_weights; mod paritydb_weights; mod rocksdb_weights; @@ -156,19 +158,17 @@ pub type Weight = u64; /// For example: FRAME System, FRAME Executive, our FRAME support libraries, etc... pub mod constants { use super::Weight; - use crate::parameter_types; pub const WEIGHT_PER_SECOND: Weight = 1_000_000_000_000; pub const WEIGHT_PER_MILLIS: Weight = WEIGHT_PER_SECOND / 1000; // 1_000_000_000 pub const WEIGHT_PER_MICROS: Weight = WEIGHT_PER_MILLIS / 1000; // 1_000_000 pub const WEIGHT_PER_NANOS: Weight = WEIGHT_PER_MICROS / 1000; // 1_000 - parameter_types! { - /// Importing a block with 0 txs takes ~5 ms - pub const BlockExecutionWeight: Weight = 5 * WEIGHT_PER_MILLIS; - /// Executing 10,000 System remarks (no-op) txs takes ~1.26 seconds -> ~125 µs per tx - pub const ExtrinsicBaseWeight: Weight = 125 * WEIGHT_PER_MICROS; - } + // Expose the Block and Extrinsic base weights. + pub use super::{ + block_weights::constants::BlockExecutionWeight, + extrinsic_weights::constants::ExtrinsicBaseWeight, + }; // Expose the DB weights. pub use super::{ diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs new file mode 100644 index 0000000000000..4db90f0c0207a --- /dev/null +++ b/frame/support/src/weights/block_weights.rs @@ -0,0 +1,46 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod constants { + use frame_support::{ + parameter_types, + weights::{constants, Weight}, + }; + + parameter_types! { + /// Importing a block with 0 Extrinsics. + pub const BlockExecutionWeight: Weight = 5_000_000 * constants::WEIGHT_PER_NANOS; + } + + #[cfg(test)] + mod test_weights { + use frame_support::weights::constants; + + /// Checks that the weight exists and is sane. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + let w = super::constants::BlockExecutionWeight::get(); + + // At least 100 µs. + assert!(w >= 100 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); + // At most 50 ms. + assert!(w <= 50 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms."); + } + } +} diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs new file mode 100644 index 0000000000000..158ba99c6a4c1 --- /dev/null +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -0,0 +1,46 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod constants { + use frame_support::{ + parameter_types, + weights::{constants, Weight}, + }; + + parameter_types! { + /// Executing a NO-OP `System::remarks` Extrinsic. + pub const ExtrinsicBaseWeight: Weight = 125_000 * constants::WEIGHT_PER_NANOS; + } + + #[cfg(test)] + mod test_weights { + use frame_support::weights::constants; + + /// Checks that the weight exists and is sane. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + let w = super::constants::ExtrinsicBaseWeight::get(); + + // At least 10 µs. + assert!(w >= 10 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs."); + // At most 1 ms. + assert!(w <= constants::WEIGHT_PER_MILLIS, "Weight should be at most 1 ms."); + } + } +} From 1ac8f633a19bbe9836cfc0d4d68fc8a700e145f9 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 4 Mar 2022 20:20:19 +0000 Subject: [PATCH 0580/1472] add block usage logs to system pallet (#10940) * add block usage logs to system pallet * add Debug * use % instead of default Debug impl * change formatting * revert --- frame/system/src/lib.rs | 34 +++++++++++++++++++++++++ primitives/arithmetic/src/per_things.rs | 7 +++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 3b4de0c472c47..9b30e7b452276 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1272,6 +1272,40 @@ impl Pallet { /// Remove temporary "environment" entries in storage, compute the storage root and return the /// resulting header for this block. pub fn finalize() -> T::Header { + log::debug!( + target: "runtime::system", + "[{:?}] length: {} (normal {}%, op: {}%, mandatory {}%) / normal weight: {} ({}%) \ + / op weight {} ({}%) / mandatory weight {} ({}%)", + Self::block_number(), + Self::all_extrinsics_len(), + sp_runtime::Percent::from_rational( + Self::all_extrinsics_len(), + *T::BlockLength::get().max.get(DispatchClass::Normal) + ).deconstruct(), + sp_runtime::Percent::from_rational( + Self::all_extrinsics_len(), + *T::BlockLength::get().max.get(DispatchClass::Operational) + ).deconstruct(), + sp_runtime::Percent::from_rational( + Self::all_extrinsics_len(), + *T::BlockLength::get().max.get(DispatchClass::Mandatory) + ).deconstruct(), + Self::block_weight().get(DispatchClass::Normal), + sp_runtime::Percent::from_rational( + *Self::block_weight().get(DispatchClass::Normal), + T::BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap_or(Bounded::max_value()) + ).deconstruct(), + Self::block_weight().get(DispatchClass::Operational), + sp_runtime::Percent::from_rational( + *Self::block_weight().get(DispatchClass::Operational), + T::BlockWeights::get().get(DispatchClass::Operational).max_total.unwrap_or(Bounded::max_value()) + ).deconstruct(), + Self::block_weight().get(DispatchClass::Mandatory), + sp_runtime::Percent::from_rational( + *Self::block_weight().get(DispatchClass::Mandatory), + T::BlockWeights::get().get(DispatchClass::Mandatory).max_total.unwrap_or(Bounded::max_value()) + ).deconstruct(), + ); ExecutionPhase::::kill(); AllExtrinsicsLen::::kill(); diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index fbd45bb693247..c3ccca56ca33f 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -24,7 +24,6 @@ use crate::traits::{ }; use codec::{CompactAs, Encode}; use num_traits::{Pow, SaturatingAdd, SaturatingSub}; -use sp_debug_derive::RuntimeDebug; use sp_std::{ convert::{TryFrom, TryInto}, fmt, ops, @@ -425,7 +424,7 @@ macro_rules! implement_per_thing { /// #[doc = $title] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] - #[derive(Encode, Copy, Clone, PartialEq, Eq, codec::MaxEncodedLen, PartialOrd, Ord, RuntimeDebug, scale_info::TypeInfo)] + #[derive(Encode, Copy, Clone, PartialEq, Eq, codec::MaxEncodedLen, PartialOrd, Ord, sp_std::fmt::Debug, scale_info::TypeInfo)] pub struct $name($type); /// Implementation makes any compact encoding of `PerThing::Inner` valid, @@ -847,7 +846,7 @@ macro_rules! implement_per_thing { #[cfg(test)] mod $test_mod { use codec::{Encode, Decode}; - use super::{$name, Saturating, RuntimeDebug, PerThing}; + use super::{$name, Saturating, PerThing}; use crate::traits::Zero; #[test] @@ -871,7 +870,7 @@ macro_rules! implement_per_thing { assert!(<$upper_type>::from($max) * <$upper_type>::from($max) < <$upper_type>::max_value()); } - #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug)] + #[derive(Encode, Decode, PartialEq, Eq, Debug)] struct WithCompact { data: T, } From 32a4fe01f110a755bf22eb8f803cdfd7052d4f8b Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Sat, 5 Mar 2022 15:51:19 +0800 Subject: [PATCH 0581/1472] Fix the undeterministic storage proof recorded for the same execution (#10915) * Add a test case for the determinism of recorded proof * Replace HashMap with BTreeMap for the actual proof records * cargo +nightly fmt --all * Store the trie nodes in BTreeSet for StorageProof * Nit * Revert the BTreeMap changes and sort when converting to storage proof * Remove PartialEq from StorageProof * Remove unnecessary change * Add `compare` method to StorageProof * FMT * Dummy change to trigger CI * Use `BTreeSet` for StorageProof and keep using `Vec` for CompactProof * Update comment on `iter_nodes` * Revert `PartialEq` removal --- client/executor/src/native_executor.rs | 5 +- client/offchain/src/api/http.rs | 10 ++-- .../state-machine/src/proving_backend.rs | 49 +++++++++++++++---- primitives/trie/src/storage_proof.rs | 31 ++++++------ primitives/trie/src/trie_stream.rs | 2 +- 5 files changed, 65 insertions(+), 32 deletions(-) diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 363ea474a7e43..669780f2a4b6a 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -462,8 +462,9 @@ impl RuntimeSpawn for RuntimeInstanceSpawn { // https://github.com/paritytech/substrate/issues/7354 let mut instance = match module.new_instance() { Ok(instance) => instance, - Err(error) => - panic!("failed to create new instance from module: {}", error), + Err(error) => { + panic!("failed to create new instance from module: {}", error) + }, }; match instance diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index bc8f81f25a643..2a7514116cb5d 100644 --- a/client/offchain/src/api/http.rs +++ b/client/offchain/src/api/http.rs @@ -432,8 +432,9 @@ impl HttpApi { ); }, None => {}, // can happen if we detected an IO error when sending the body - _ => - tracing::error!(target: "offchain-worker::http", "State mismatch between the API and worker"), + _ => { + tracing::error!(target: "offchain-worker::http", "State mismatch between the API and worker") + }, } }, @@ -443,8 +444,9 @@ impl HttpApi { self.requests.insert(id, HttpApiRequest::Fail(error)); }, None => {}, // can happen if we detected an IO error when sending the body - _ => - tracing::error!(target: "offchain-worker::http", "State mismatch between the API and worker"), + _ => { + tracing::error!(target: "offchain-worker::http", "State mismatch between the API and worker") + }, }, None => { diff --git a/primitives/state-machine/src/proving_backend.rs b/primitives/state-machine/src/proving_backend.rs index 934f08492deed..eeffcc8e47052 100644 --- a/primitives/state-machine/src/proving_backend.rs +++ b/primitives/state-machine/src/proving_backend.rs @@ -158,15 +158,13 @@ impl ProofRecorder { /// Convert into a [`StorageProof`]. pub fn to_storage_proof(&self) -> StorageProof { - let trie_nodes = self - .inner - .read() - .records - .iter() - .filter_map(|(_k, v)| v.as_ref().map(|v| v.to_vec())) - .collect(); - - StorageProof::new(trie_nodes) + StorageProof::new( + self.inner + .read() + .records + .iter() + .filter_map(|(_k, v)| v.as_ref().map(|v| v.to_vec())), + ) } /// Reset the internal state. @@ -393,6 +391,7 @@ mod tests { proving_backend::create_proof_check_backend, trie_backend::tests::test_trie, InMemoryBackend, }; + use sp_core::H256; use sp_runtime::traits::BlakeTwo256; use sp_trie::PrefixedMemoryDB; @@ -426,7 +425,6 @@ mod tests { #[test] fn proof_is_invalid_when_does_not_contains_root() { - use sp_core::H256; let result = create_proof_check_backend::( H256::from_low_u64_be(1), StorageProof::empty(), @@ -582,4 +580,35 @@ mod tests { assert!(backend.storage(b"doesnotexist2").unwrap().is_none()); check_estimation(&backend); } + + #[test] + fn proof_recorded_for_same_execution_should_be_deterministic() { + let storage_changes = vec![ + (H256::random(), Some(b"value1".to_vec())), + (H256::random(), Some(b"value2".to_vec())), + (H256::random(), Some(b"value3".to_vec())), + (H256::random(), Some(b"value4".to_vec())), + (H256::random(), Some(b"value5".to_vec())), + (H256::random(), Some(b"value6".to_vec())), + (H256::random(), Some(b"value7".to_vec())), + (H256::random(), Some(b"value8".to_vec())), + ]; + + let proof_recorder = + ProofRecorder:: { inner: Arc::new(RwLock::new(ProofRecorderInner::default())) }; + storage_changes + .clone() + .into_iter() + .for_each(|(key, val)| proof_recorder.record(key, val)); + let proof1 = proof_recorder.to_storage_proof(); + + let proof_recorder = + ProofRecorder:: { inner: Arc::new(RwLock::new(ProofRecorderInner::default())) }; + storage_changes + .into_iter() + .for_each(|(key, val)| proof_recorder.record(key, val)); + let proof2 = proof_recorder.to_storage_proof(); + + assert_eq!(proof1, proof2); + } } diff --git a/primitives/trie/src/storage_proof.rs b/primitives/trie/src/storage_proof.rs index 79da009ae151d..f6139584dbbad 100644 --- a/primitives/trie/src/storage_proof.rs +++ b/primitives/trie/src/storage_proof.rs @@ -18,7 +18,7 @@ use codec::{Decode, Encode}; use hash_db::{HashDB, Hasher}; use scale_info::TypeInfo; -use sp_std::vec::Vec; +use sp_std::{collections::btree_set::BTreeSet, iter::IntoIterator, vec::Vec}; // Note that `LayoutV1` usage here (proof compaction) is compatible // with `LayoutV0`. use crate::LayoutV1 as Layout; @@ -32,13 +32,13 @@ use crate::LayoutV1 as Layout; /// the serialized nodes and performing the key lookups. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] pub struct StorageProof { - trie_nodes: Vec>, + trie_nodes: BTreeSet>, } impl StorageProof { /// Constructs a storage proof from a subset of encoded trie nodes in a storage backend. - pub fn new(trie_nodes: Vec>) -> Self { - StorageProof { trie_nodes } + pub fn new(trie_nodes: impl IntoIterator>) -> Self { + StorageProof { trie_nodes: BTreeSet::from_iter(trie_nodes) } } /// Returns a new empty proof. @@ -46,7 +46,7 @@ impl StorageProof { /// An empty proof is capable of only proving trivial statements (ie. that an empty set of /// key-value pairs exist in storage). pub fn empty() -> Self { - StorageProof { trie_nodes: Vec::new() } + StorageProof { trie_nodes: BTreeSet::new() } } /// Returns whether this is an empty proof. @@ -54,14 +54,14 @@ impl StorageProof { self.trie_nodes.is_empty() } - /// Create an iterator over trie nodes constructed from the proof. The nodes are not guaranteed - /// to be traversed in any particular order. + /// Create an iterator over encoded trie nodes in lexicographical order constructed + /// from the proof. pub fn iter_nodes(self) -> StorageProofNodeIterator { StorageProofNodeIterator::new(self) } /// Convert into plain node vector. - pub fn into_nodes(self) -> Vec> { + pub fn into_nodes(self) -> BTreeSet> { self.trie_nodes } @@ -138,12 +138,13 @@ impl CompactProof { expected_root, )?; Ok(( - StorageProof::new( - db.drain() - .into_iter() - .filter_map(|kv| if (kv.1).1 > 0 { Some((kv.1).0) } else { None }) - .collect(), - ), + StorageProof::new(db.drain().into_iter().filter_map(|kv| { + if (kv.1).1 > 0 { + Some((kv.1).0) + } else { + None + } + })), root, )) } @@ -171,7 +172,7 @@ impl CompactProof { /// An iterator over trie nodes constructed from a storage proof. The nodes are not guaranteed to /// be traversed in any particular order. pub struct StorageProofNodeIterator { - inner: > as IntoIterator>::IntoIter, + inner: > as IntoIterator>::IntoIter, } impl StorageProofNodeIterator { diff --git a/primitives/trie/src/trie_stream.rs b/primitives/trie/src/trie_stream.rs index 7a5c7d003e034..a17d7c25e1b8a 100644 --- a/primitives/trie/src/trie_stream.rs +++ b/primitives/trie/src/trie_stream.rs @@ -26,8 +26,8 @@ use hash_db::Hasher; use sp_std::vec::Vec; use trie_root; -#[derive(Default, Clone)] /// Codec-flavored TrieStream. +#[derive(Default, Clone)] pub struct TrieStream { /// Current node buffer. buffer: Vec, From f6679ddd31f68e9f1578064d58a246130c27026b Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Mon, 7 Mar 2022 09:12:03 +0100 Subject: [PATCH 0582/1472] Minor Uniques pallet improvements and XCM v3 preparations (#10896) * Introduce Helper to Uniques for benchmark stuff * Fixes * Formatting * Featuregate the Helper, include ContainsPair * Introduce & use EnsureOriginWithArg * Benchmarking * Docs * More ContainsBoth helpers * Formatting * Formatting * Fixes Co-authored-by: Shawn Tabrizi --- bin/node/runtime/src/lib.rs | 9 +- frame/support/src/traits.rs | 10 +- frame/support/src/traits/dispatch.rs | 48 +++++ frame/support/src/traits/members.rs | 150 ++++++++++++--- .../support/src/traits/tokens/nonfungible.rs | 9 +- .../support/src/traits/tokens/nonfungibles.rs | 6 +- frame/uniques/src/benchmarking.rs | 73 +++++--- frame/uniques/src/impl_nonfungibles.rs | 15 +- frame/uniques/src/lib.rs | 172 ++++++++++++------ frame/uniques/src/mock.rs | 5 +- frame/uniques/src/tests.rs | 18 ++ frame/uniques/src/weights.rs | 15 ++ 12 files changed, 417 insertions(+), 113 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f12bf8a88365f..e2903c0b314da 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -27,9 +27,9 @@ use frame_election_provider_support::onchain; use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU128, ConstU16, ConstU32, Currency, EnsureOneOf, EqualPrivilegeOnly, Everything, - Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, - U128CurrencyToVote, + AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EnsureOneOf, + EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, + LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, @@ -1348,6 +1348,9 @@ impl pallet_uniques::Config for Runtime { type KeyLimit = KeyLimit; type ValueLimit = ValueLimit; type WeightInfo = pallet_uniques::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type CreateOrigin = AsEnsureOriginWithArg>; } impl pallet_transaction_storage::Config for Runtime { diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 88891c83276bd..a8ce78ae9dabc 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -34,8 +34,9 @@ mod members; #[allow(deprecated)] pub use members::{AllowAll, DenyAll, Filter}; pub use members::{ - AsContains, ChangeMembers, Contains, ContainsLengthBound, Everything, InitializeMembers, - IsInVec, Nothing, SortedMembers, + AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Everything, + EverythingBut, FromContainsPair, InitializeMembers, InsideBoth, IsInVec, Nothing, + SortedMembers, TheseExcept, }; mod validation; @@ -89,7 +90,10 @@ pub use storage::{ }; mod dispatch; -pub use dispatch::{EnsureOneOf, EnsureOrigin, OriginTrait, UnfilteredDispatchable}; +pub use dispatch::{ + AsEnsureOriginWithArg, EnsureOneOf, EnsureOrigin, EnsureOriginWithArg, OriginTrait, + UnfilteredDispatchable, +}; mod voting; pub use voting::{ diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 1a4e9f6f7cc2a..250a31ebfb17a 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -27,10 +27,12 @@ use sp_runtime::{ pub trait EnsureOrigin { /// A return type. type Success; + /// Perform the origin check. fn ensure_origin(o: OuterOrigin) -> Result { Self::try_origin(o).map_err(|_| BadOrigin) } + /// Perform the origin check. fn try_origin(o: OuterOrigin) -> Result; @@ -41,6 +43,52 @@ pub trait EnsureOrigin { fn successful_origin() -> OuterOrigin; } +/// Some sort of check on the origin is performed by this object. +pub trait EnsureOriginWithArg { + /// A return type. + type Success; + + /// Perform the origin check. + fn ensure_origin(o: OuterOrigin, a: &Argument) -> Result { + Self::try_origin(o, a).map_err(|_| BadOrigin) + } + + /// Perform the origin check, returning the origin value if unsuccessful. This allows chaining. + fn try_origin(o: OuterOrigin, a: &Argument) -> Result; + + /// Returns an outer origin capable of passing `try_origin` check. + /// + /// ** Should be used for benchmarking only!!! ** + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin(a: &Argument) -> OuterOrigin; +} + +pub struct AsEnsureOriginWithArg(sp_std::marker::PhantomData); +impl> + EnsureOriginWithArg for AsEnsureOriginWithArg +{ + /// A return type. + type Success = EO::Success; + + /// Perform the origin check. + fn ensure_origin(o: OuterOrigin, _: &Argument) -> Result { + EO::ensure_origin(o) + } + + /// Perform the origin check, returning the origin value if unsuccessful. This allows chaining. + fn try_origin(o: OuterOrigin, _: &Argument) -> Result { + EO::try_origin(o) + } + + /// Returns an outer origin capable of passing `try_origin` check. + /// + /// ** Should be used for benchmarking only!!! ** + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin(_: &Argument) -> OuterOrigin { + EO::successful_origin() + } +} + /// Type that can be dispatched with an origin but without checking the origin filter. /// /// Implemented for pallet dispatchable type by `decl_module` and for runtime dispatchable by diff --git a/frame/support/src/traits/members.rs b/frame/support/src/traits/members.rs index ba72b4819933b..f3c586b64af04 100644 --- a/frame/support/src/traits/members.rs +++ b/frame/support/src/traits/members.rs @@ -25,6 +25,40 @@ pub trait Contains { fn contains(t: &T) -> bool; } +#[impl_trait_for_tuples::impl_for_tuples(1, 30)] +impl Contains for Tuple { + fn contains(t: &T) -> bool { + for_tuples!( #( + if Tuple::contains(t) { return true } + )* ); + false + } +} + +/// A trait for querying whether a type can be said to "contain" a pair-value. +pub trait ContainsPair { + /// Return `true` if this "contains" the pair-value `(a, b)`. + fn contains(a: &A, b: &B) -> bool; +} + +#[impl_trait_for_tuples::impl_for_tuples(0, 30)] +impl ContainsPair for Tuple { + fn contains(a: &A, b: &B) -> bool { + for_tuples!( #( + if Tuple::contains(a, b) { return true } + )* ); + false + } +} + +/// Converter `struct` to use a `ContainsPair` implementation for a `Contains` bound. +pub struct FromContainsPair(PhantomData); +impl> Contains<(A, B)> for FromContainsPair { + fn contains((ref a, ref b): &(A, B)) -> bool { + CP::contains(a, b) + } +} + /// A [`Contains`] implementation that contains every value. pub enum Everything {} impl Contains for Everything { @@ -32,6 +66,11 @@ impl Contains for Everything { true } } +impl ContainsPair for Everything { + fn contains(_: &A, _: &B) -> bool { + true + } +} /// A [`Contains`] implementation that contains no value. pub enum Nothing {} @@ -40,43 +79,112 @@ impl Contains for Nothing { false } } +impl ContainsPair for Nothing { + fn contains(_: &A, _: &B) -> bool { + false + } +} -#[deprecated = "Use `Everything` instead"] -pub type AllowAll = Everything; -#[deprecated = "Use `Nothing` instead"] -pub type DenyAll = Nothing; -#[deprecated = "Use `Contains` instead"] -pub trait Filter { - fn filter(t: &T) -> bool; +/// A [`Contains`] implementation that contains everything except the values in `Exclude`. +pub struct EverythingBut(PhantomData); +impl> Contains for EverythingBut { + fn contains(t: &T) -> bool { + !Exclude::contains(t) + } } -#[allow(deprecated)] -impl> Filter for C { - fn filter(t: &T) -> bool { - Self::contains(t) +impl> ContainsPair for EverythingBut { + fn contains(a: &A, b: &B) -> bool { + !Exclude::contains(a, b) } } -#[impl_trait_for_tuples::impl_for_tuples(1, 30)] -impl Contains for Tuple { +/// A [`Contains`] implementation that contains all members of `These` excepting any members in +/// `Except`. +pub struct TheseExcept(PhantomData<(These, Except)>); +impl, Except: Contains> Contains for TheseExcept { fn contains(t: &T) -> bool { - for_tuples!( #( - if Tuple::contains(t) { return true } - )* ); - false + These::contains(t) && !Except::contains(t) + } +} +impl, Except: ContainsPair> ContainsPair + for TheseExcept +{ + fn contains(a: &A, b: &B) -> bool { + These::contains(a, b) && !Except::contains(a, b) + } +} + +/// A [`Contains`] implementation which contains all members of `These` which are also members of +/// `Those`. +pub struct InsideBoth(PhantomData<(These, Those)>); +impl, Those: Contains> Contains for InsideBoth { + fn contains(t: &T) -> bool { + These::contains(t) && Those::contains(t) + } +} +impl, Those: ContainsPair> ContainsPair + for InsideBoth +{ + fn contains(a: &A, b: &B) -> bool { + These::contains(a, b) && Those::contains(a, b) } } /// Create a type which implements the `Contains` trait for a particular type with syntax similar /// to `matches!`. #[macro_export] -macro_rules! match_type { - ( pub type $n:ident: impl Contains<$t:ty> = { $phead:pat_param $( | $ptail:pat )* } ; ) => { +macro_rules! match_types { + ( + pub type $n:ident: impl Contains<$t:ty> = { + $phead:pat_param $( | $ptail:pat )* + }; + $( $rest:tt )* + ) => { pub struct $n; impl $crate::traits::Contains<$t> for $n { fn contains(l: &$t) -> bool { matches!(l, $phead $( | $ptail )* ) } } + $crate::match_types!( $( $rest )* ); + }; + ( + pub type $n:ident: impl ContainsPair<$a:ty, $b:ty> = { + $phead:pat_param $( | $ptail:pat )* + }; + $( $rest:tt )* + ) => { + pub struct $n; + impl $crate::traits::ContainsPair<$a, $b> for $n { + fn contains(a: &$a, b: &$b) -> bool { + matches!((a, b), $phead $( | $ptail )* ) + } + } + $crate::match_types!( $( $rest )* ); + }; + () => {} +} + +/// Create a type which implements the `Contains` trait for a particular type with syntax similar +/// to `matches!`. +#[macro_export] +#[deprecated = "Use `match_types!` instead"] +macro_rules! match_type { + ($( $x:tt )*) => { $crate::match_types!( $( $x )* ); } +} + +#[deprecated = "Use `Everything` instead"] +pub type AllowAll = Everything; +#[deprecated = "Use `Nothing` instead"] +pub type DenyAll = Nothing; +#[deprecated = "Use `Contains` instead"] +pub trait Filter { + fn filter(t: &T) -> bool; +} +#[allow(deprecated)] +impl> Filter for C { + fn filter(t: &T) -> bool { + Self::contains(t) } } @@ -84,12 +192,12 @@ macro_rules! match_type { mod tests { use super::*; - match_type! { + match_types! { pub type OneOrTenToTwenty: impl Contains = { 1 | 10..=20 }; } #[test] - fn match_type_works() { + fn match_types_works() { for i in 0..=255 { assert_eq!(OneOrTenToTwenty::contains(&i), i == 1 || i >= 10 && i <= 20); } diff --git a/frame/support/src/traits/tokens/nonfungible.rs b/frame/support/src/traits/tokens/nonfungible.rs index 08e9a3a18a4b8..5cf9638131b28 100644 --- a/frame/support/src/traits/tokens/nonfungible.rs +++ b/frame/support/src/traits/tokens/nonfungible.rs @@ -85,7 +85,10 @@ pub trait Mutate: Inspect { /// Burn some asset `instance`. /// /// By default, this is not a supported operation. - fn burn_from(_instance: &Self::InstanceId) -> DispatchResult { + fn burn( + _instance: &Self::InstanceId, + _maybe_check_owner: Option<&AccountId>, + ) -> DispatchResult { Err(TokenError::Unsupported.into()) } @@ -166,8 +169,8 @@ impl< fn mint_into(instance: &Self::InstanceId, who: &AccountId) -> DispatchResult { >::mint_into(&A::get(), instance, who) } - fn burn_from(instance: &Self::InstanceId) -> DispatchResult { - >::burn_from(&A::get(), instance) + fn burn(instance: &Self::InstanceId, maybe_check_owner: Option<&AccountId>) -> DispatchResult { + >::burn(&A::get(), instance, maybe_check_owner) } fn set_attribute(instance: &Self::InstanceId, key: &[u8], value: &[u8]) -> DispatchResult { >::set_attribute(&A::get(), instance, key, value) diff --git a/frame/support/src/traits/tokens/nonfungibles.rs b/frame/support/src/traits/tokens/nonfungibles.rs index 1172fb6022830..8bd731b20342c 100644 --- a/frame/support/src/traits/tokens/nonfungibles.rs +++ b/frame/support/src/traits/tokens/nonfungibles.rs @@ -165,7 +165,11 @@ pub trait Mutate: Inspect { /// Burn some asset `instance` of `class`. /// /// By default, this is not a supported operation. - fn burn_from(_class: &Self::ClassId, _instance: &Self::InstanceId) -> DispatchResult { + fn burn( + _class: &Self::ClassId, + _instance: &Self::InstanceId, + _maybe_check_owner: Option<&AccountId>, + ) -> DispatchResult { Err(TokenError::Unsupported.into()) } diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index f3f9b7b28df72..d6223ec88f81b 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -40,12 +40,13 @@ fn create_class, I: 'static>( ) -> (T::ClassId, T::AccountId, ::Source) { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - let class = Default::default(); + let class = T::Helper::class(0); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - assert!(Uniques::::create( - SystemOrigin::Signed(caller.clone()).into(), + assert!(Uniques::::force_create( + SystemOrigin::Root.into(), class, caller_lookup.clone(), + false, ) .is_ok()); (class, caller, caller_lookup) @@ -53,14 +54,14 @@ fn create_class, I: 'static>( fn add_class_metadata, I: 'static>( ) -> (T::AccountId, ::Source) { - let caller = Class::::get(T::ClassId::default()).unwrap().owner; + let caller = Class::::get(T::Helper::class(0)).unwrap().owner; if caller != whitelisted_caller() { whitelist_account!(caller); } let caller_lookup = T::Lookup::unlookup(caller.clone()); assert!(Uniques::::set_class_metadata( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + T::Helper::class(0), vec![0; T::StringLimit::get() as usize].try_into().unwrap(), false, ) @@ -71,15 +72,15 @@ fn add_class_metadata, I: 'static>( fn mint_instance, I: 'static>( index: u16, ) -> (T::InstanceId, T::AccountId, ::Source) { - let caller = Class::::get(T::ClassId::default()).unwrap().admin; + let caller = Class::::get(T::Helper::class(0)).unwrap().admin; if caller != whitelisted_caller() { whitelist_account!(caller); } let caller_lookup = T::Lookup::unlookup(caller.clone()); - let instance = index.into(); + let instance = T::Helper::instance(index); assert!(Uniques::::mint( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + T::Helper::class(0), instance, caller_lookup.clone(), ) @@ -90,14 +91,14 @@ fn mint_instance, I: 'static>( fn add_instance_metadata, I: 'static>( instance: T::InstanceId, ) -> (T::AccountId, ::Source) { - let caller = Class::::get(T::ClassId::default()).unwrap().owner; + let caller = Class::::get(T::Helper::class(0)).unwrap().owner; if caller != whitelisted_caller() { whitelist_account!(caller); } let caller_lookup = T::Lookup::unlookup(caller.clone()); assert!(Uniques::::set_metadata( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + T::Helper::class(0), instance, vec![0; T::StringLimit::get() as usize].try_into().unwrap(), false, @@ -109,7 +110,7 @@ fn add_instance_metadata, I: 'static>( fn add_instance_attribute, I: 'static>( instance: T::InstanceId, ) -> (BoundedVec, T::AccountId, ::Source) { - let caller = Class::::get(T::ClassId::default()).unwrap().owner; + let caller = Class::::get(T::Helper::class(0)).unwrap().owner; if caller != whitelisted_caller() { whitelist_account!(caller); } @@ -117,7 +118,7 @@ fn add_instance_attribute, I: 'static>( let key: BoundedVec<_, _> = vec![0; T::KeyLimit::get() as usize].try_into().unwrap(); assert!(Uniques::::set_attribute( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + T::Helper::class(0), Some(instance), key.clone(), vec![0; T::ValueLimit::get() as usize].try_into().unwrap(), @@ -136,20 +137,24 @@ fn assert_last_event, I: 'static>(generic_event: >:: benchmarks_instance_pallet! { create { - let caller: T::AccountId = whitelisted_caller(); - let caller_lookup = T::Lookup::unlookup(caller.clone()); + let class = T::Helper::class(0); + let origin = T::CreateOrigin::successful_origin(&class); + let caller = T::CreateOrigin::ensure_origin(origin.clone(), &class).unwrap(); + whitelist_account!(caller); + let admin = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup) + let call = Call::::create { class, admin }; + }: { call.dispatch_bypass_filter(origin)? } verify { - assert_last_event::(Event::Created { class: Default::default(), creator: caller.clone(), owner: caller }.into()); + assert_last_event::(Event::Created { class: T::Helper::class(0), creator: caller.clone(), owner: caller }.into()); } force_create { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - }: _(SystemOrigin::Root, Default::default(), caller_lookup, true) + }: _(SystemOrigin::Root, T::Helper::class(0), caller_lookup, true) verify { - assert_last_event::(Event::ForceCreated { class: Default::default(), owner: caller }.into()); + assert_last_event::(Event::ForceCreated { class: T::Helper::class(0), owner: caller }.into()); } destroy { @@ -163,10 +168,10 @@ benchmarks_instance_pallet! { mint_instance::(i as u16); } for i in 0..m { - add_instance_metadata::((i as u16).into()); + add_instance_metadata::(T::Helper::instance(i as u16)); } for i in 0..a { - add_instance_attribute::((i as u16).into()); + add_instance_attribute::(T::Helper::instance(i as u16)); } let witness = Class::::get(class).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), class, witness) @@ -176,7 +181,7 @@ benchmarks_instance_pallet! { mint { let (class, caller, caller_lookup) = create_class::(); - let instance = Default::default(); + let instance = T::Helper::instance(0); }: _(SystemOrigin::Signed(caller.clone()), class, instance, caller_lookup) verify { assert_last_event::(Event::Issued { class, instance, owner: caller }.into()); @@ -192,7 +197,7 @@ benchmarks_instance_pallet! { transfer { let (class, caller, caller_lookup) = create_class::(); - let (instance, ..) = mint_instance::(Default::default()); + let (instance, ..) = mint_instance::(0); let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); @@ -222,15 +227,15 @@ benchmarks_instance_pallet! { freeze { let (class, caller, caller_lookup) = create_class::(); - let (instance, ..) = mint_instance::(Default::default()); - }: _(SystemOrigin::Signed(caller.clone()), Default::default(), Default::default()) + let (instance, ..) = mint_instance::(0); + }: _(SystemOrigin::Signed(caller.clone()), T::Helper::class(0), T::Helper::instance(0)) verify { - assert_last_event::(Event::Frozen { class: Default::default(), instance: Default::default() }.into()); + assert_last_event::(Event::Frozen { class: T::Helper::class(0), instance: T::Helper::instance(0) }.into()); } thaw { let (class, caller, caller_lookup) = create_class::(); - let (instance, ..) = mint_instance::(Default::default()); + let (instance, ..) = mint_instance::(0); Uniques::::freeze( SystemOrigin::Signed(caller.clone()).into(), class, @@ -262,6 +267,8 @@ benchmarks_instance_pallet! { let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); + let origin = SystemOrigin::Signed(target.clone()).into(); + Uniques::::set_accept_ownership(origin, Some(class.clone()))?; }: _(SystemOrigin::Signed(caller), class, target_lookup) verify { assert_last_event::(Event::OwnerChanged { class, new_owner: target }.into()); @@ -272,7 +279,7 @@ benchmarks_instance_pallet! { let target0 = T::Lookup::unlookup(account("target", 0, SEED)); let target1 = T::Lookup::unlookup(account("target", 1, SEED)); let target2 = T::Lookup::unlookup(account("target", 2, SEED)); - }: _(SystemOrigin::Signed(caller), Default::default(), target0.clone(), target1.clone(), target2.clone()) + }: _(SystemOrigin::Signed(caller), class, target0.clone(), target1.clone(), target2.clone()) verify { assert_last_event::(Event::TeamChanged{ class, @@ -379,5 +386,17 @@ benchmarks_instance_pallet! { assert_last_event::(Event::ApprovalCancelled { class, instance, owner: caller, delegate }.into()); } + set_accept_ownership { + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); + let class = T::Helper::class(0); + }: _(SystemOrigin::Signed(caller.clone()), Some(class.clone())) + verify { + assert_last_event::(Event::OwnershipAcceptanceChanged { + who: caller, + maybe_class: Some(class), + }.into()); + } + impl_benchmark_test_suite!(Uniques, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index a9695e8e898ae..89b95fb770489 100644 --- a/frame/uniques/src/impl_nonfungibles.rs +++ b/frame/uniques/src/impl_nonfungibles.rs @@ -128,8 +128,19 @@ impl, I: 'static> Mutate<::AccountId> for Pallet Self::do_mint(class.clone(), instance.clone(), who.clone(), |_| Ok(())) } - fn burn_from(class: &Self::ClassId, instance: &Self::InstanceId) -> DispatchResult { - Self::do_burn(class.clone(), instance.clone(), |_, _| Ok(())) + fn burn( + class: &Self::ClassId, + instance: &Self::InstanceId, + maybe_check_owner: Option<&T::AccountId>, + ) -> DispatchResult { + Self::do_burn(class.clone(), instance.clone(), |_, d| { + if let Some(check_owner) = maybe_check_owner { + if &d.owner != check_owner { + Err(Error::::NoPermission)?; + } + } + Ok(()) + }) } } diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index f35bb3fd61a0f..1e14825454193 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -41,8 +41,10 @@ mod types; pub mod migration; pub mod weights; -use codec::{Decode, Encode, HasCompact}; -use frame_support::traits::{BalanceStatus::Reserved, Currency, ReservableCurrency}; +use codec::{Decode, Encode}; +use frame_support::traits::{ + BalanceStatus::Reserved, Currency, EnsureOriginWithArg, ReservableCurrency, +}; use frame_system::Config as SystemConfig; use sp_runtime::{ traits::{Saturating, StaticLookup, Zero}, @@ -64,6 +66,21 @@ pub mod pallet { #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); + #[cfg(feature = "runtime-benchmarks")] + pub trait BenchmarkHelper { + fn class(i: u16) -> ClassId; + fn instance(i: u16) -> InstanceId; + } + #[cfg(feature = "runtime-benchmarks")] + impl, InstanceId: From> BenchmarkHelper for () { + fn class(i: u16) -> ClassId { + i.into() + } + fn instance(i: u16) -> InstanceId { + i.into() + } + } + #[pallet::config] /// The module configuration trait. pub trait Config: frame_system::Config { @@ -71,16 +88,10 @@ pub mod pallet { type Event: From> + IsType<::Event>; /// Identifier for the class of asset. - type ClassId: Member + Parameter + Default + Copy + HasCompact + MaxEncodedLen; + type ClassId: Member + Parameter + MaxEncodedLen + Copy; /// The type used to identify a unique asset within an asset class. - type InstanceId: Member - + Parameter - + Default - + Copy - + HasCompact - + From - + MaxEncodedLen; + type InstanceId: Member + Parameter + MaxEncodedLen + Copy; /// The currency mechanism, used for paying for reserves. type Currency: ReservableCurrency; @@ -89,6 +100,14 @@ pub mod pallet { /// attributes. type ForceOrigin: EnsureOrigin; + /// Standard class creation is only allowed if the origin attempting it and the class are + /// in this set. + type CreateOrigin: EnsureOriginWithArg< + Success = Self::AccountId, + Self::Origin, + Self::ClassId, + >; + /// The basic amount of funds that must be reserved for an asset class. #[pallet::constant] type ClassDeposit: Get>; @@ -122,6 +141,10 @@ pub mod pallet { #[pallet::constant] type ValueLimit: Get; + #[cfg(feature = "runtime-benchmarks")] + /// A set of helper functions for benchmarking. + type Helper: BenchmarkHelper; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -135,6 +158,11 @@ pub mod pallet { ClassDetails>, >; + #[pallet::storage] + /// The class, if any, of which an account is willing to take ownership. + pub(super) type OwnershipAcceptance, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, T::AccountId, T::ClassId>; + #[pallet::storage] /// The assets held by any given account; set out this way so that assets owned by a single /// account can be enumerated. @@ -296,6 +324,8 @@ pub mod pallet { maybe_instance: Option, key: BoundedVec, }, + /// Ownership acceptance has changed for an account. + OwnershipAcceptanceChanged { who: T::AccountId, maybe_class: Option }, } #[pallet::error] @@ -320,6 +350,8 @@ pub mod pallet { NoDelegate, /// No approval exists that would allow the transfer. Unapproved, + /// The named owner has not signed ownership of the class is acceptable. + Unaccepted, } impl, I: 'static> Pallet { @@ -327,6 +359,11 @@ pub mod pallet { pub fn owner(class: T::ClassId, instance: T::InstanceId) -> Option { Asset::::get(class, instance).map(|i| i.owner) } + + /// Get the owner of the asset instance, if the asset exists. + pub fn class_owner(class: T::ClassId) -> Option { + Class::::get(class).map(|i| i.owner) + } } #[pallet::call] @@ -350,10 +387,10 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::create())] pub fn create( origin: OriginFor, - #[pallet::compact] class: T::ClassId, + class: T::ClassId, admin: ::Source, ) -> DispatchResult { - let owner = ensure_signed(origin)?; + let owner = T::CreateOrigin::ensure_origin(origin, &class)?; let admin = T::Lookup::lookup(admin)?; Self::do_create_class( @@ -385,7 +422,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_create())] pub fn force_create( origin: OriginFor, - #[pallet::compact] class: T::ClassId, + class: T::ClassId, owner: ::Source, free_holding: bool, ) -> DispatchResult { @@ -424,7 +461,7 @@ pub mod pallet { ))] pub fn destroy( origin: OriginFor, - #[pallet::compact] class: T::ClassId, + class: T::ClassId, witness: DestroyWitness, ) -> DispatchResultWithPostInfo { let maybe_check_owner = match T::ForceOrigin::try_origin(origin) { @@ -455,8 +492,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::mint())] pub fn mint( origin: OriginFor, - #[pallet::compact] class: T::ClassId, - #[pallet::compact] instance: T::InstanceId, + class: T::ClassId, + instance: T::InstanceId, owner: ::Source, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -484,8 +521,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::burn())] pub fn burn( origin: OriginFor, - #[pallet::compact] class: T::ClassId, - #[pallet::compact] instance: T::InstanceId, + class: T::ClassId, + instance: T::InstanceId, check_owner: Option<::Source>, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -520,8 +557,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( origin: OriginFor, - #[pallet::compact] class: T::ClassId, - #[pallet::compact] instance: T::InstanceId, + class: T::ClassId, + instance: T::InstanceId, dest: ::Source, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -556,7 +593,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::redeposit(instances.len() as u32))] pub fn redeposit( origin: OriginFor, - #[pallet::compact] class: T::ClassId, + class: T::ClassId, instances: Vec, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -616,8 +653,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::freeze())] pub fn freeze( origin: OriginFor, - #[pallet::compact] class: T::ClassId, - #[pallet::compact] instance: T::InstanceId, + class: T::ClassId, + instance: T::InstanceId, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -646,8 +683,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::thaw())] pub fn thaw( origin: OriginFor, - #[pallet::compact] class: T::ClassId, - #[pallet::compact] instance: T::InstanceId, + class: T::ClassId, + instance: T::InstanceId, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -673,10 +710,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::freeze_class())] - pub fn freeze_class( - origin: OriginFor, - #[pallet::compact] class: T::ClassId, - ) -> DispatchResult { + pub fn freeze_class(origin: OriginFor, class: T::ClassId) -> DispatchResult { let origin = ensure_signed(origin)?; Class::::try_mutate(class, |maybe_details| { @@ -700,10 +734,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::thaw_class())] - pub fn thaw_class( - origin: OriginFor, - #[pallet::compact] class: T::ClassId, - ) -> DispatchResult { + pub fn thaw_class(origin: OriginFor, class: T::ClassId) -> DispatchResult { let origin = ensure_signed(origin)?; Class::::try_mutate(class, |maybe_details| { @@ -722,7 +753,8 @@ pub mod pallet { /// Origin must be Signed and the sender should be the Owner of the asset `class`. /// /// - `class`: The asset class whose owner should be changed. - /// - `owner`: The new Owner of this asset class. + /// - `owner`: The new Owner of this asset class. They must have called + /// `set_accept_ownership` with `class` in order for this operation to succeed. /// /// Emits `OwnerChanged`. /// @@ -730,12 +762,15 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer_ownership())] pub fn transfer_ownership( origin: OriginFor, - #[pallet::compact] class: T::ClassId, + class: T::ClassId, owner: ::Source, ) -> DispatchResult { let origin = ensure_signed(origin)?; let owner = T::Lookup::lookup(owner)?; + let acceptable_class = OwnershipAcceptance::::get(&owner); + ensure!(acceptable_class.as_ref() == Some(&class), Error::::Unaccepted); + Class::::try_mutate(class, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; ensure!(&origin == &details.owner, Error::::NoPermission); @@ -753,6 +788,7 @@ pub mod pallet { ClassAccount::::remove(&details.owner, &class); ClassAccount::::insert(&owner, &class, ()); details.owner = owner.clone(); + OwnershipAcceptance::::remove(&owner); Self::deposit_event(Event::OwnerChanged { class, new_owner: owner }); Ok(()) @@ -774,7 +810,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_team())] pub fn set_team( origin: OriginFor, - #[pallet::compact] class: T::ClassId, + class: T::ClassId, issuer: ::Source, admin: ::Source, freezer: ::Source, @@ -811,8 +847,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::approve_transfer())] pub fn approve_transfer( origin: OriginFor, - #[pallet::compact] class: T::ClassId, - #[pallet::compact] instance: T::InstanceId, + class: T::ClassId, + instance: T::InstanceId, delegate: ::Source, ) -> DispatchResult { let maybe_check: Option = T::ForceOrigin::try_origin(origin) @@ -863,8 +899,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::cancel_approval())] pub fn cancel_approval( origin: OriginFor, - #[pallet::compact] class: T::ClassId, - #[pallet::compact] instance: T::InstanceId, + class: T::ClassId, + instance: T::InstanceId, maybe_check_delegate: Option<::Source>, ) -> DispatchResult { let maybe_check: Option = T::ForceOrigin::try_origin(origin) @@ -915,7 +951,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_asset_status())] pub fn force_asset_status( origin: OriginFor, - #[pallet::compact] class: T::ClassId, + class: T::ClassId, owner: ::Source, issuer: ::Source, admin: ::Source, @@ -964,7 +1000,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_attribute())] pub fn set_attribute( origin: OriginFor, - #[pallet::compact] class: T::ClassId, + class: T::ClassId, maybe_instance: Option, key: BoundedVec, value: BoundedVec, @@ -1027,7 +1063,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::clear_attribute())] pub fn clear_attribute( origin: OriginFor, - #[pallet::compact] class: T::ClassId, + class: T::ClassId, maybe_instance: Option, key: BoundedVec, ) -> DispatchResult { @@ -1077,8 +1113,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_metadata())] pub fn set_metadata( origin: OriginFor, - #[pallet::compact] class: T::ClassId, - #[pallet::compact] instance: T::InstanceId, + class: T::ClassId, + instance: T::InstanceId, data: BoundedVec, is_frozen: bool, ) -> DispatchResult { @@ -1139,8 +1175,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::clear_metadata())] pub fn clear_metadata( origin: OriginFor, - #[pallet::compact] class: T::ClassId, - #[pallet::compact] instance: T::InstanceId, + class: T::ClassId, + instance: T::InstanceId, ) -> DispatchResult { let maybe_check_owner = T::ForceOrigin::try_origin(origin) .map(|_| None) @@ -1188,7 +1224,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_class_metadata())] pub fn set_class_metadata( origin: OriginFor, - #[pallet::compact] class: T::ClassId, + class: T::ClassId, data: BoundedVec, is_frozen: bool, ) -> DispatchResult { @@ -1242,10 +1278,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::clear_class_metadata())] - pub fn clear_class_metadata( - origin: OriginFor, - #[pallet::compact] class: T::ClassId, - ) -> DispatchResult { + pub fn clear_class_metadata(origin: OriginFor, class: T::ClassId) -> DispatchResult { let maybe_check_owner = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; @@ -1265,5 +1298,40 @@ pub mod pallet { Ok(()) }) } + + /// Set (or reset) the acceptance of ownership for a particular account. + /// + /// Origin must be `Signed` and if `maybe_class` is `Some`, then the signer must have a + /// provider reference. + /// + /// - `maybe_class`: The identifier of the asset class whose ownership the signer is willing + /// to accept, or if `None`, an indication that the signer is willing to accept no + /// ownership transferal. + /// + /// Emits `OwnershipAcceptanceChanged`. + #[pallet::weight(T::WeightInfo::set_accept_ownership())] + pub fn set_accept_ownership( + origin: OriginFor, + maybe_class: Option, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let old = OwnershipAcceptance::::get(&who); + match (old.is_some(), maybe_class.is_some()) { + (false, true) => { + frame_system::Pallet::::inc_consumers(&who)?; + }, + (true, false) => { + frame_system::Pallet::::dec_consumers(&who); + }, + _ => {}, + } + if let Some(class) = maybe_class.as_ref() { + OwnershipAcceptance::::insert(&who, class); + } else { + OwnershipAcceptance::::remove(&who); + } + Self::deposit_event(Event::OwnershipAcceptanceChanged { who, maybe_class }); + Ok(()) + } } } diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index 2a94fcbee347a..265142443ef48 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -22,7 +22,7 @@ use crate as pallet_uniques; use frame_support::{ construct_runtime, - traits::{ConstU32, ConstU64}, + traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, }; use sp_core::H256; use sp_runtime::{ @@ -89,6 +89,7 @@ impl Config for Test { type ClassId = u32; type InstanceId = u32; type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; type ClassDeposit = ConstU64<2>; type InstanceDeposit = ConstU64<1>; @@ -99,6 +100,8 @@ impl Config for Test { type KeyLimit = ConstU32<50>; type ValueLimit = ConstU32<50>; type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 12f39c78bfe3d..364073ad37cde 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -196,6 +196,9 @@ fn origin_guards_should_work() { new_test_ext().execute_with(|| { assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); + + Balances::make_free_balance_be(&2, 100); + assert_ok!(Uniques::set_accept_ownership(Origin::signed(2), Some(0))); assert_noop!( Uniques::transfer_ownership(Origin::signed(2), 0, 2), Error::::NoPermission @@ -218,13 +221,20 @@ fn transfer_owner_should_work() { Balances::make_free_balance_be(&3, 100); assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); assert_eq!(classes(), vec![(1, 0)]); + assert_noop!( + Uniques::transfer_ownership(Origin::signed(1), 0, 2), + Error::::Unaccepted + ); + assert_ok!(Uniques::set_accept_ownership(Origin::signed(2), Some(0))); assert_ok!(Uniques::transfer_ownership(Origin::signed(1), 0, 2)); + assert_eq!(classes(), vec![(2, 0)]); assert_eq!(Balances::total_balance(&1), 98); assert_eq!(Balances::total_balance(&2), 102); assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Balances::reserved_balance(&2), 2); + assert_ok!(Uniques::set_accept_ownership(Origin::signed(1), Some(0))); assert_noop!( Uniques::transfer_ownership(Origin::signed(1), 0, 1), Error::::NoPermission @@ -234,12 +244,20 @@ fn transfer_owner_should_work() { assert_ok!(Uniques::set_class_metadata(Origin::signed(2), 0, bvec![0u8; 20], false)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_ok!(Uniques::set_metadata(Origin::signed(2), 0, 42, bvec![0u8; 20], false)); + assert_ok!(Uniques::set_accept_ownership(Origin::signed(3), Some(0))); assert_ok!(Uniques::transfer_ownership(Origin::signed(2), 0, 3)); assert_eq!(classes(), vec![(3, 0)]); assert_eq!(Balances::total_balance(&2), 57); assert_eq!(Balances::total_balance(&3), 145); assert_eq!(Balances::reserved_balance(&2), 0); assert_eq!(Balances::reserved_balance(&3), 45); + + // 2's acceptence from before is reset when it became owner, so it cannot be transfered + // without a fresh acceptance. + assert_noop!( + Uniques::transfer_ownership(Origin::signed(3), 0, 2), + Error::::Unaccepted + ); }); } diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 1df8fe0ff6650..eb9067b7133a0 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -68,6 +68,7 @@ pub trait WeightInfo { fn clear_class_metadata() -> Weight; fn approve_transfer() -> Weight; fn cancel_approval() -> Weight; + fn set_accept_ownership() -> Weight; } /// Weights for pallet_uniques using the Substrate node and recommended hardware. @@ -249,6 +250,13 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) + fn set_accept_ownership() -> Weight { + (19_417_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } } // For backwards compatibility and tests @@ -429,4 +437,11 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) + fn set_accept_ownership() -> Weight { + (19_417_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } } From 55192ea3f13e8a3d84b228b98922881c2cd94cba Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Tue, 8 Mar 2022 12:31:20 +0000 Subject: [PATCH 0583/1472] election provider support: Update some test only types (#10983) --- frame/election-provider-support/src/lib.rs | 35 ++++------------------ 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 26efe5107b670..ca22e3093855c 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -262,33 +262,6 @@ pub trait ElectionDataProvider { fn clear() {} } -/// An election data provider that should only be used for testing. -#[cfg(feature = "std")] -pub struct TestDataProvider(sp_std::marker::PhantomData); - -#[cfg(feature = "std")] -impl ElectionDataProvider for TestDataProvider<(AccountId, BlockNumber)> { - type AccountId = AccountId; - type BlockNumber = BlockNumber; - type MaxVotesPerVoter = (); - - fn targets(_maybe_max_len: Option) -> data_provider::Result> { - Ok(Default::default()) - } - - fn voters(_maybe_max_len: Option) -> data_provider::Result>> { - Ok(Default::default()) - } - - fn desired_targets() -> data_provider::Result { - Ok(Default::default()) - } - - fn next_election_prediction(now: BlockNumber) -> BlockNumber { - now - } -} - /// Something that can compute the result of an election and pass it back to the caller. /// /// This trait only provides an interface to _request_ an election, i.e. @@ -340,11 +313,15 @@ pub trait InstantElectionProvider: ElectionProvider { pub struct NoElection(sp_std::marker::PhantomData); #[cfg(feature = "std")] -impl ElectionProvider for NoElection<(AccountId, BlockNumber)> { +impl ElectionProvider + for NoElection<(AccountId, BlockNumber, DataProvider)> +where + DataProvider: ElectionDataProvider, +{ type AccountId = AccountId; type BlockNumber = BlockNumber; type Error = &'static str; - type DataProvider = TestDataProvider<(AccountId, BlockNumber)>; + type DataProvider = DataProvider; fn elect() -> Result, Self::Error> { Err(" cannot do anything.") From 8df8d908c4d77a8dd19751784b6aca62159ddda8 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 8 Mar 2022 08:48:30 -0400 Subject: [PATCH 0584/1472] Feedback from @XLC for Referenda Pallet (#10991) * feedback from @xlc * english * fmt Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/referenda/src/benchmarking.rs | 4 +-- frame/referenda/src/lib.rs | 22 +++++++--------- frame/referenda/src/mock.rs | 4 +-- frame/referenda/src/tests.rs | 39 ++++++++++++++++------------ frame/referenda/src/types.rs | 22 +--------------- frame/support/src/traits/schedule.rs | 13 ++++++++-- 6 files changed, 47 insertions(+), 57 deletions(-) diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 76a8173f16c9a..08612e0614aeb 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -48,7 +48,7 @@ fn create_referendum() -> (T::AccountId, ReferendumIndex) { RawOrigin::Signed(caller.clone()).into(), RawOrigin::Root.into(), T::Hashing::hash_of(&0), - AtOrAfter::After(0u32.into()) + DispatchTime::After(0u32.into()) )); let index = ReferendumCount::::get() - 1; (caller, index) @@ -182,7 +182,7 @@ benchmarks! { RawOrigin::Signed(caller), RawOrigin::Root.into(), T::Hashing::hash_of(&0), - AtOrAfter::After(0u32.into()) + DispatchTime::After(0u32.into()) ) verify { let index = ReferendumCount::::get().checked_sub(1).unwrap(); assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Ongoing(_))); diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 2d4d29b0bc13f..fb19d2b9ed248 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -68,8 +68,8 @@ use frame_support::{ v2::{Anon as ScheduleAnon, Named as ScheduleNamed}, DispatchTime, MaybeHashed, }, - Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, OriginTrait, PollStatus, - Polling, ReservableCurrency, VoteTally, + Currency, Get, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, + ReservableCurrency, VoteTally, }, BoundedVec, }; @@ -86,7 +86,7 @@ pub mod weights; use branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch}; pub use pallet::*; pub use types::{ - AtOrAfter, BalanceOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted, + BalanceOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted, NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf, @@ -126,9 +126,7 @@ pub mod pallet { type Scheduler: ScheduleAnon, PalletsOriginOf, Hash = Self::Hash> + ScheduleNamed, PalletsOriginOf, Hash = Self::Hash>; /// Currency type for this pallet. - type Currency: ReservableCurrency - + LockableCurrency; - + type Currency: ReservableCurrency; // Origins and unbalances. /// Origin from which any vote may be cancelled. type CancelOrigin: EnsureOrigin; @@ -175,8 +173,6 @@ pub mod pallet { pub type ReferendumCount = StorageValue<_, ReferendumIndex, ValueQuery>; /// Information concerning any given referendum. - /// - /// TWOX-NOTE: SAFE as indexes are not under an attacker’s control. #[pallet::storage] pub type ReferendumInfoFor = StorageMap<_, Blake2_128Concat, ReferendumIndex, ReferendumInfoOf>; @@ -301,7 +297,7 @@ pub mod pallet { /// Referendum is not ongoing. NotOngoing, /// Referendum's decision deposit is already paid. - HaveDeposit, + HasDeposit, /// The track identifier given was invalid. BadTrack, /// There are already a full complement of referendums in progress for this track. @@ -338,7 +334,7 @@ pub mod pallet { origin: OriginFor, proposal_origin: PalletsOriginOf, proposal_hash: T::Hash, - enactment_moment: AtOrAfter, + enactment_moment: DispatchTime, ) -> DispatchResult { let who = ensure_signed(origin)?; @@ -385,7 +381,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let mut status = Self::ensure_ongoing(index)?; - ensure!(status.decision_deposit.is_none(), Error::::HaveDeposit); + ensure!(status.decision_deposit.is_none(), Error::::HasDeposit); let track = Self::track(status.track).ok_or(Error::::NoTrack)?; status.decision_deposit = Some(Self::take_deposit(who.clone(), track.decision_deposit)?); @@ -598,7 +594,7 @@ impl Polling for Pallet { track: class, origin: frame_support::dispatch::RawOrigin::Root.into(), proposal_hash: ::hash_of(&index), - enactment: AtOrAfter::After(Zero::zero()), + enactment: DispatchTime::After(Zero::zero()), submitted: now, submission_deposit: Deposit { who: dummy_account_id, amount: Zero::zero() }, decision_deposit: None, @@ -651,7 +647,7 @@ impl Pallet { fn schedule_enactment( index: ReferendumIndex, track: &TrackInfoOf, - desired: AtOrAfter, + desired: DispatchTime, origin: PalletsOriginOf, call_hash: T::Hash, ) { diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 063b124f2b71f..fdd14fdadf04d 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -306,7 +306,7 @@ pub fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult { Origin::signed(who), frame_system::RawOrigin::Root.into(), set_balance_proposal_hash(value), - AtOrAfter::After(delay), + DispatchTime::After(delay), ) } @@ -434,7 +434,7 @@ impl RefState { Origin::signed(1), frame_support::dispatch::RawOrigin::Root.into(), set_balance_proposal_hash(1), - AtOrAfter::At(10), + DispatchTime::At(10), )); assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); if matches!(self, RefState::Confirming { immediate: true }) { diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index cea071ced12fe..96edd4ce879ce 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -47,7 +47,7 @@ fn basic_happy_path_works() { Origin::signed(1), RawOrigin::Root.into(), set_balance_proposal_hash(1), - AtOrAfter::At(10), + DispatchTime::At(10), )); assert_eq!(Balances::reserved_balance(&1), 2); assert_eq!(ReferendumCount::::get(), 1); @@ -178,7 +178,7 @@ fn queueing_works() { Origin::signed(5), RawOrigin::Root.into(), set_balance_proposal_hash(0), - AtOrAfter::After(0), + DispatchTime::After(0), )); assert_ok!(Referenda::place_decision_deposit(Origin::signed(5), 0)); @@ -190,7 +190,7 @@ fn queueing_works() { Origin::signed(i), RawOrigin::Root.into(), set_balance_proposal_hash(i), - AtOrAfter::After(0), + DispatchTime::After(0), )); assert_ok!(Referenda::place_decision_deposit(Origin::signed(i), i as u32)); // TODO: decision deposit after some initial votes with a non-highest voted coming @@ -275,7 +275,7 @@ fn auto_timeout_should_happen_with_nothing_but_submit() { Origin::signed(1), RawOrigin::Root.into(), set_balance_proposal_hash(1), - AtOrAfter::At(20), + DispatchTime::At(20), )); run_to(20); assert_matches!(ReferendumInfoFor::::get(0), Some(ReferendumInfo::Ongoing(..))); @@ -295,13 +295,13 @@ fn tracks_are_distinguished() { Origin::signed(1), RawOrigin::Root.into(), set_balance_proposal_hash(1), - AtOrAfter::At(10), + DispatchTime::At(10), )); assert_ok!(Referenda::submit( Origin::signed(2), RawOrigin::None.into(), set_balance_proposal_hash(2), - AtOrAfter::At(20), + DispatchTime::At(20), )); assert_ok!(Referenda::place_decision_deposit(Origin::signed(3), 0)); @@ -318,7 +318,7 @@ fn tracks_are_distinguished() { track: 0, origin: OriginCaller::system(RawOrigin::Root), proposal_hash: set_balance_proposal_hash(1), - enactment: AtOrAfter::At(10), + enactment: DispatchTime::At(10), submitted: 1, submission_deposit: Deposit { who: 1, amount: 2 }, decision_deposit: Some(Deposit { who: 3, amount: 10 }), @@ -334,7 +334,7 @@ fn tracks_are_distinguished() { track: 1, origin: OriginCaller::system(RawOrigin::None), proposal_hash: set_balance_proposal_hash(2), - enactment: AtOrAfter::At(20), + enactment: DispatchTime::At(20), submitted: 1, submission_deposit: Deposit { who: 2, amount: 2 }, decision_deposit: Some(Deposit { who: 4, amount: 1 }), @@ -355,13 +355,18 @@ fn submit_errors_work() { let h = set_balance_proposal_hash(1); // No track for Signed origins. assert_noop!( - Referenda::submit(Origin::signed(1), RawOrigin::Signed(2).into(), h, AtOrAfter::At(10),), + Referenda::submit( + Origin::signed(1), + RawOrigin::Signed(2).into(), + h, + DispatchTime::At(10), + ), Error::::NoTrack ); // No funds for deposit assert_noop!( - Referenda::submit(Origin::signed(10), RawOrigin::Root.into(), h, AtOrAfter::At(10),), + Referenda::submit(Origin::signed(10), RawOrigin::Root.into(), h, DispatchTime::At(10),), BalancesError::::InsufficientBalance ); }); @@ -378,13 +383,13 @@ fn decision_deposit_errors_work() { Origin::signed(1), RawOrigin::Root.into(), h, - AtOrAfter::At(10), + DispatchTime::At(10), )); let e = BalancesError::::InsufficientBalance; assert_noop!(Referenda::place_decision_deposit(Origin::signed(10), 0), e); assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); - let e = Error::::HaveDeposit; + let e = Error::::HasDeposit; assert_noop!(Referenda::place_decision_deposit(Origin::signed(2), 0), e); }); } @@ -400,7 +405,7 @@ fn refund_deposit_works() { Origin::signed(1), RawOrigin::Root.into(), h, - AtOrAfter::At(10), + DispatchTime::At(10), )); let e = Error::::NoDeposit; assert_noop!(Referenda::refund_decision_deposit(Origin::signed(2), 0), e); @@ -422,7 +427,7 @@ fn cancel_works() { Origin::signed(1), RawOrigin::Root.into(), h, - AtOrAfter::At(10), + DispatchTime::At(10), )); assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); @@ -441,7 +446,7 @@ fn cancel_errors_works() { Origin::signed(1), RawOrigin::Root.into(), h, - AtOrAfter::At(10), + DispatchTime::At(10), )); assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); assert_noop!(Referenda::cancel(Origin::signed(1), 0), BadOrigin); @@ -459,7 +464,7 @@ fn kill_works() { Origin::signed(1), RawOrigin::Root.into(), h, - AtOrAfter::At(10), + DispatchTime::At(10), )); assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); @@ -479,7 +484,7 @@ fn kill_errors_works() { Origin::signed(1), RawOrigin::Root.into(), h, - AtOrAfter::At(10), + DispatchTime::At(10), )); assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); assert_noop!(Referenda::kill(Origin::signed(4), 0), BadOrigin); diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 367fa2a4ba45b..8ea9fc3faf3d0 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -185,26 +185,6 @@ pub trait TracksInfo { } } -/// Indication of either a specific moment or a delay from a implicitly defined moment. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub enum AtOrAfter { - /// Indiciates that the event should occur at the moment given. - At(Moment), - /// Indiciates that the event should occur some period of time (defined by the parameter) after - /// a prior event. The prior event is defined by the context, but for the purposes of - /// referendum proposals, the "prior event" is the passing of the referendum. - After(Moment), -} - -impl AtOrAfter { - pub fn evaluate(&self, since: Moment) -> Moment { - match &self { - Self::At(m) => *m, - Self::After(m) => m.saturating_add(since), - } - } -} - /// Info regarding an ongoing referendum. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ReferendumStatus< @@ -224,7 +204,7 @@ pub struct ReferendumStatus< /// The hash of the proposal up for referendum. pub(crate) proposal_hash: Hash, /// The time the proposal should be scheduled for enactment. - pub(crate) enactment: AtOrAfter, + pub(crate) enactment: DispatchTime, /// The time of submission. Once `UndecidingTimeout` passes, it may be closed by anyone if it /// `deciding` is `None`. pub(crate) submitted: Moment, diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 3b8e6da3e2ef3..c2d0d4bc3b81f 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -19,7 +19,7 @@ use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime::{DispatchError, RuntimeDebug}; +use sp_runtime::{traits::Saturating, DispatchError, RuntimeDebug}; use sp_std::{fmt::Debug, prelude::*, result::Result}; /// Information relating to the period of a scheduled task. First item is the length of the @@ -32,7 +32,7 @@ pub type Period = (BlockNumber, u32); pub type Priority = u8; /// The dispatch time of a scheduled task. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum DispatchTime { /// At specified block. At(BlockNumber), @@ -40,6 +40,15 @@ pub enum DispatchTime { After(BlockNumber), } +impl DispatchTime { + pub fn evaluate(&self, since: BlockNumber) -> BlockNumber { + match &self { + Self::At(m) => *m, + Self::After(m) => m.saturating_add(since), + } + } +} + /// The highest priority. We invert the value so that normal sorting will place the highest /// priority at the beginning of the list. pub const HIGHEST_PRIORITY: Priority = 0; From b36030a6e8c21af9f18bb0d6a667188fac0dbc47 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Wed, 9 Mar 2022 16:28:28 +0000 Subject: [PATCH 0585/1472] Make bags-list generic over node value and instantiable (#10997) * make instantiable * update * cargo fmt * Clean up * bags-list: Make it generic over node value * Respond to some feedback * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Add back default impl for weight update worst case * Update to Score in more places' * Use VoteWeight, not u64 to reduce test diff * FMT * FullCodec implies Codec * formatting * Fixup bags list remote test Co-authored-by: doordashcon Co-authored-by: Doordashcon <90750465+Doordashcon@users.noreply.github.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- bin/node/runtime/src/lib.rs | 3 +- frame/bags-list/remote-tests/src/lib.rs | 23 +- frame/bags-list/src/benchmarks.rs | 47 +++-- frame/bags-list/src/lib.rs | 146 +++++++------ frame/bags-list/src/list/mod.rs | 235 +++++++++++---------- frame/bags-list/src/list/tests.rs | 143 ++++++++++--- frame/bags-list/src/mock.rs | 15 +- frame/bags-list/src/tests.rs | 38 ++-- frame/election-provider-support/Cargo.toml | 2 +- frame/election-provider-support/src/lib.rs | 28 +-- frame/staking/src/benchmarking.rs | 2 +- frame/staking/src/mock.rs | 5 +- frame/staking/src/pallet/impls.rs | 19 +- frame/staking/src/pallet/mod.rs | 5 +- 14 files changed, 428 insertions(+), 283 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index e2903c0b314da..8c7a20af15683 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -690,9 +690,10 @@ parameter_types! { impl pallet_bags_list::Config for Runtime { type Event = Event; - type VoteWeightProvider = Staking; + type ScoreProvider = Staking; type WeightInfo = pallet_bags_list::weights::SubstrateWeight; type BagThresholds = BagThresholds; + type Score = sp_npos_elections::VoteWeight; } parameter_types! { diff --git a/frame/bags-list/remote-tests/src/lib.rs b/frame/bags-list/remote-tests/src/lib.rs index 9a88ff24f2f3b..83c322f93134e 100644 --- a/frame/bags-list/remote-tests/src/lib.rs +++ b/frame/bags-list/remote-tests/src/lib.rs @@ -17,6 +17,7 @@ //! Utilities for remote-testing pallet-bags-list. +use frame_election_provider_support::ScoreProvider; use sp_std::prelude::*; /// A common log target to use. @@ -55,8 +56,12 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na let mut rebaggable = 0; let mut active_bags = 0; for vote_weight_thresh in ::BagThresholds::get() { + let vote_weight_thresh_u64: u64 = (*vote_weight_thresh) + .try_into() + .map_err(|_| "runtime must configure score to at most u64 to use this test") + .unwrap(); // threshold in terms of UNITS (e.g. KSM, DOT etc) - let vote_weight_thresh_as_unit = *vote_weight_thresh as f64 / currency_unit as f64; + let vote_weight_thresh_as_unit = vote_weight_thresh_u64 as f64 / currency_unit as f64; let pretty_thresh = format!("Threshold: {}. {}", vote_weight_thresh_as_unit, currency_name); let bag = match pallet_bags_list::Pallet::::list_bags_get(*vote_weight_thresh) { @@ -70,9 +75,13 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na active_bags += 1; for id in bag.std_iter().map(|node| node.std_id().clone()) { - let vote_weight = pallet_staking::Pallet::::weight_of(&id); + let vote_weight = ::ScoreProvider::score(&id); + let vote_weight_thresh_u64: u64 = (*vote_weight_thresh) + .try_into() + .map_err(|_| "runtime must configure score to at most u64 to use this test") + .unwrap(); let vote_weight_as_balance: pallet_staking::BalanceOf = - vote_weight.try_into().map_err(|_| "can't convert").unwrap(); + vote_weight_thresh_u64.try_into().map_err(|_| "can't convert").unwrap(); if vote_weight_as_balance < min_nominator_bond { log::trace!( @@ -87,13 +96,17 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na pallet_bags_list::Node::::get(&id).expect("node in bag must exist."); if node.is_misplaced(vote_weight) { rebaggable += 1; + let notional_bag = pallet_bags_list::notional_bag_for::(vote_weight); + let notional_bag_as_u64: u64 = notional_bag + .try_into() + .map_err(|_| "runtime must configure score to at most u64 to use this test") + .unwrap(); log::trace!( target: LOG_TARGET, "Account {:?} can be rebagged from {:?} to {:?}", id, vote_weight_thresh_as_unit, - pallet_bags_list::notional_bag_for::(vote_weight) as f64 / - currency_unit as f64 + notional_bag_as_u64 as f64 / currency_unit as f64 ); } } diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index cc575d7d1efff..b94a97093d001 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -20,9 +20,10 @@ use super::*; use crate::list::List; use frame_benchmarking::{account, whitelist_account, whitelisted_caller}; -use frame_election_provider_support::VoteWeightProvider; +use frame_election_provider_support::ScoreProvider; use frame_support::{assert_ok, traits::Get}; use frame_system::RawOrigin as SystemOrigin; +use sp_runtime::traits::One; frame_benchmarking::benchmarks! { rebag_non_terminal { @@ -36,7 +37,7 @@ frame_benchmarking::benchmarks! { // clear any pre-existing storage. // NOTE: safe to call outside block production - List::::unsafe_clear(); + List::::unsafe_clear(); // define our origin and destination thresholds. let origin_bag_thresh = T::BagThresholds::get()[0]; @@ -44,21 +45,21 @@ frame_benchmarking::benchmarks! { // seed items in the origin bag. let origin_head: T::AccountId = account("origin_head", 0, 0); - assert_ok!(List::::insert(origin_head.clone(), origin_bag_thresh)); + assert_ok!(List::::insert(origin_head.clone(), origin_bag_thresh)); let origin_middle: T::AccountId = account("origin_middle", 0, 0); // the node we rebag (_R_) - assert_ok!(List::::insert(origin_middle.clone(), origin_bag_thresh)); + assert_ok!(List::::insert(origin_middle.clone(), origin_bag_thresh)); let origin_tail: T::AccountId = account("origin_tail", 0, 0); - assert_ok!(List::::insert(origin_tail.clone(), origin_bag_thresh)); + assert_ok!(List::::insert(origin_tail.clone(), origin_bag_thresh)); // seed items in the destination bag. let dest_head: T::AccountId = account("dest_head", 0, 0); - assert_ok!(List::::insert(dest_head.clone(), dest_bag_thresh)); + assert_ok!(List::::insert(dest_head.clone(), dest_bag_thresh)); // the bags are in the expected state after initial setup. assert_eq!( - List::::get_bags(), + List::::get_bags(), vec![ (origin_bag_thresh, vec![origin_head.clone(), origin_middle.clone(), origin_tail.clone()]), (dest_bag_thresh, vec![dest_head.clone()]) @@ -67,12 +68,12 @@ frame_benchmarking::benchmarks! { let caller = whitelisted_caller(); // update the weight of `origin_middle` to guarantee it will be rebagged into the destination. - T::VoteWeightProvider::set_vote_weight_of(&origin_middle, dest_bag_thresh); + T::ScoreProvider::set_score_of(&origin_middle, dest_bag_thresh); }: rebag(SystemOrigin::Signed(caller), origin_middle.clone()) verify { // check the bags have updated as expected. assert_eq!( - List::::get_bags(), + List::::get_bags(), vec![ ( origin_bag_thresh, @@ -104,18 +105,18 @@ frame_benchmarking::benchmarks! { // seed items in the origin bag. let origin_head: T::AccountId = account("origin_head", 0, 0); - assert_ok!(List::::insert(origin_head.clone(), origin_bag_thresh)); + assert_ok!(List::::insert(origin_head.clone(), origin_bag_thresh)); let origin_tail: T::AccountId = account("origin_tail", 0, 0); // the node we rebag (_R_) - assert_ok!(List::::insert(origin_tail.clone(), origin_bag_thresh)); + assert_ok!(List::::insert(origin_tail.clone(), origin_bag_thresh)); // seed items in the destination bag. let dest_head: T::AccountId = account("dest_head", 0, 0); - assert_ok!(List::::insert(dest_head.clone(), dest_bag_thresh)); + assert_ok!(List::::insert(dest_head.clone(), dest_bag_thresh)); // the bags are in the expected state after initial setup. assert_eq!( - List::::get_bags(), + List::::get_bags(), vec![ (origin_bag_thresh, vec![origin_head.clone(), origin_tail.clone()]), (dest_bag_thresh, vec![dest_head.clone()]) @@ -124,12 +125,12 @@ frame_benchmarking::benchmarks! { let caller = whitelisted_caller(); // update the weight of `origin_tail` to guarantee it will be rebagged into the destination. - T::VoteWeightProvider::set_vote_weight_of(&origin_tail, dest_bag_thresh); + T::ScoreProvider::set_score_of(&origin_tail, dest_bag_thresh); }: rebag(SystemOrigin::Signed(caller), origin_tail.clone()) verify { // check the bags have updated as expected. assert_eq!( - List::::get_bags(), + List::::get_bags(), vec![ (origin_bag_thresh, vec![origin_head.clone()]), (dest_bag_thresh, vec![dest_head.clone(), origin_tail.clone()]) @@ -147,22 +148,22 @@ frame_benchmarking::benchmarks! { // insert the nodes in order let lighter: T::AccountId = account("lighter", 0, 0); - assert_ok!(List::::insert(lighter.clone(), bag_thresh)); + assert_ok!(List::::insert(lighter.clone(), bag_thresh)); let heavier_prev: T::AccountId = account("heavier_prev", 0, 0); - assert_ok!(List::::insert(heavier_prev.clone(), bag_thresh)); + assert_ok!(List::::insert(heavier_prev.clone(), bag_thresh)); let heavier: T::AccountId = account("heavier", 0, 0); - assert_ok!(List::::insert(heavier.clone(), bag_thresh)); + assert_ok!(List::::insert(heavier.clone(), bag_thresh)); let heavier_next: T::AccountId = account("heavier_next", 0, 0); - assert_ok!(List::::insert(heavier_next.clone(), bag_thresh)); + assert_ok!(List::::insert(heavier_next.clone(), bag_thresh)); - T::VoteWeightProvider::set_vote_weight_of(&lighter, bag_thresh - 1); - T::VoteWeightProvider::set_vote_weight_of(&heavier, bag_thresh); + T::ScoreProvider::set_score_of(&lighter, bag_thresh - One::one()); + T::ScoreProvider::set_score_of(&heavier, bag_thresh); assert_eq!( - List::::iter().map(|n| n.id().clone()).collect::>(), + List::::iter().map(|n| n.id().clone()).collect::>(), vec![lighter.clone(), heavier_prev.clone(), heavier.clone(), heavier_next.clone()] ); @@ -170,7 +171,7 @@ frame_benchmarking::benchmarks! { }: _(SystemOrigin::Signed(heavier.clone()), lighter.clone()) verify { assert_eq!( - List::::iter().map(|n| n.id().clone()).collect::>(), + List::::iter().map(|n| n.id().clone()).collect::>(), vec![heavier, lighter, heavier_prev, heavier_next] ) } diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 89c54db87023f..c502245409fdb 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -17,13 +17,14 @@ //! # Bags-List Pallet //! -//! A semi-sorted list, where items hold an `AccountId` based on some `VoteWeight`. The `AccountId` -//! (`id` for short) might be synonym to a `voter` or `nominator` in some context, and `VoteWeight` -//! signifies the chance of each id being included in the final [`SortedListProvider::iter`]. +//! A semi-sorted list, where items hold an `AccountId` based on some `Score`. The +//! `AccountId` (`id` for short) might be synonym to a `voter` or `nominator` in some context, and +//! `Score` signifies the chance of each id being included in the final +//! [`SortedListProvider::iter`]. //! //! It implements [`frame_election_provider_support::SortedListProvider`] to provide a semi-sorted //! list of accounts to another pallet. It needs some other pallet to give it some information about -//! the weights of accounts via [`frame_election_provider_support::VoteWeightProvider`]. +//! the weights of accounts via [`frame_election_provider_support::ScoreProvider`]. //! //! This pallet is not configurable at genesis. Whoever uses it should call appropriate functions of //! the `SortedListProvider` (e.g. `on_insert`, or `unsafe_regenerate`) at their genesis. @@ -33,12 +34,12 @@ //! The data structure exposed by this pallet aims to be optimized for: //! //! - insertions and removals. -//! - iteration over the top* N items by weight, where the precise ordering of items doesn't +//! - iteration over the top* N items by score, where the precise ordering of items doesn't //! particularly matter. //! //! # Details //! -//! - items are kept in bags, which are delineated by their range of weight (See +//! - items are kept in bags, which are delineated by their range of score (See //! [`Config::BagThresholds`]). //! - for iteration, bags are chained together from highest to lowest and elements within the bag //! are iterated from head to tail. @@ -46,14 +47,16 @@ //! it will worsen its position in list iteration; this reduces incentives for some types of spam //! that involve consistently removing and inserting for better position. Further, ordering //! granularity is thus dictated by range between each bag threshold. -//! - if an item's weight changes to a value no longer within the range of its current bag the -//! item's position will need to be updated by an external actor with rebag (update), or removal -//! and insertion. +//! - if an item's score changes to a value no longer within the range of its current bag the item's +//! position will need to be updated by an external actor with rebag (update), or removal and +//! insertion. #![cfg_attr(not(feature = "std"), no_std)] -use frame_election_provider_support::{SortedListProvider, VoteWeight, VoteWeightProvider}; +use codec::FullCodec; +use frame_election_provider_support::{ScoreProvider, SortedListProvider}; use frame_system::ensure_signed; +use sp_runtime::traits::{AtLeast32BitUnsigned, Bounded}; use sp_std::prelude::*; #[cfg(any(feature = "runtime-benchmarks", test))] @@ -92,38 +95,38 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] - pub struct Pallet(_); + pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config { + pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type Event: From> + IsType<::Event>; /// Weight information for extrinsics in this pallet. type WeightInfo: weights::WeightInfo; - /// Something that provides the weights of ids. - type VoteWeightProvider: VoteWeightProvider; + /// Something that provides the scores of ids. + type ScoreProvider: ScoreProvider; /// The list of thresholds separating the various bags. /// - /// Ids are separated into unsorted bags according to their vote weight. This specifies the - /// thresholds separating the bags. An id's bag is the largest bag for which the id's weight + /// Ids are separated into unsorted bags according to their score. This specifies the + /// thresholds separating the bags. An id's bag is the largest bag for which the id's score /// is less than or equal to its upper threshold. /// /// When ids are iterated, higher bags are iterated completely before lower bags. This means - /// that iteration is _semi-sorted_: ids of higher weight tend to come before ids of lower - /// weight, but peer ids within a particular bag are sorted in insertion order. + /// that iteration is _semi-sorted_: ids of higher score tend to come before ids of lower + /// score, but peer ids within a particular bag are sorted in insertion order. /// /// # Expressing the constant /// /// This constant must be sorted in strictly increasing order. Duplicate items are not /// permitted. /// - /// There is an implied upper limit of `VoteWeight::MAX`; that value does not need to be + /// There is an implied upper limit of `Score::MAX`; that value does not need to be /// specified within the bag. For any two threshold lists, if one ends with - /// `VoteWeight::MAX`, the other one does not, and they are otherwise equal, the two lists - /// will behave identically. + /// `Score::MAX`, the other one does not, and they are otherwise equal, the two + /// lists will behave identically. /// /// # Calculation /// @@ -141,52 +144,68 @@ pub mod pallet { /// the procedure given above, then the constant ratio is equal to 2. /// - If `BagThresholds::get().len() == 200`, and the thresholds are determined according to /// the procedure given above, then the constant ratio is approximately equal to 1.248. - /// - If the threshold list begins `[1, 2, 3, ...]`, then an id with weight 0 or 1 will fall - /// into bag 0, an id with weight 2 will fall into bag 1, etc. + /// - If the threshold list begins `[1, 2, 3, ...]`, then an id with score 0 or 1 will fall + /// into bag 0, an id with score 2 will fall into bag 1, etc. /// /// # Migration /// /// In the event that this list ever changes, a copy of the old bags list must be retained. /// With that `List::migrate` can be called, which will perform the appropriate migration. #[pallet::constant] - type BagThresholds: Get<&'static [VoteWeight]>; + type BagThresholds: Get<&'static [Self::Score]>; + + /// The type used to dictate a node position relative to other nodes. + type Score: Clone + + Default + + PartialEq + + Eq + + Ord + + PartialOrd + + sp_std::fmt::Debug + + Copy + + AtLeast32BitUnsigned + + Bounded + + TypeInfo + + FullCodec + + MaxEncodedLen; } /// A single node, within some bag. /// /// Nodes store links forward and back within their respective bags. #[pallet::storage] - pub(crate) type ListNodes = - CountedStorageMap<_, Twox64Concat, T::AccountId, list::Node>; + pub(crate) type ListNodes, I: 'static = ()> = + CountedStorageMap<_, Twox64Concat, T::AccountId, list::Node>; /// A bag stored in storage. /// /// Stores a `Bag` struct, which stores head and tail pointers to itself. #[pallet::storage] - pub(crate) type ListBags = StorageMap<_, Twox64Concat, VoteWeight, list::Bag>; + pub(crate) type ListBags, I: 'static = ()> = + StorageMap<_, Twox64Concat, T::Score, list::Bag>; #[pallet::event] #[pallet::generate_deposit(pub(crate) fn deposit_event)] - pub enum Event { + pub enum Event, I: 'static = ()> { /// Moved an account from one bag to another. - Rebagged { who: T::AccountId, from: VoteWeight, to: VoteWeight }, + Rebagged { who: T::AccountId, from: T::Score, to: T::Score }, } #[pallet::error] #[cfg_attr(test, derive(PartialEq))] - pub enum Error { + pub enum Error { /// Attempted to place node in front of a node in another bag. NotInSameBag, /// Id not found in list. IdNotFound, - /// An Id does not have a greater vote weight than another Id. + /// An Id does not have a greater score than another Id. NotHeavier, } #[pallet::call] - impl Pallet { + impl, I: 'static> Pallet { /// Declare that some `dislocated` account has, through rewards or penalties, sufficiently - /// changed its weight that it should properly fall into a different bag than its current + /// changed its score that it should properly fall into a different bag than its current /// one. /// /// Anyone can call this function about any potentially dislocated account. @@ -196,8 +215,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::rebag_non_terminal().max(T::WeightInfo::rebag_terminal()))] pub fn rebag(origin: OriginFor, dislocated: T::AccountId) -> DispatchResult { ensure_signed(origin)?; - let current_weight = T::VoteWeightProvider::vote_weight(&dislocated); - let _ = Pallet::::do_rebag(&dislocated, current_weight); + let current_score = T::ScoreProvider::score(&dislocated); + let _ = Pallet::::do_rebag(&dislocated, current_score); Ok(()) } @@ -208,16 +227,16 @@ pub mod pallet { /// /// Only works if /// - both nodes are within the same bag, - /// - and `origin` has a greater `VoteWeight` than `lighter`. + /// - and `origin` has a greater `Score` than `lighter`. #[pallet::weight(T::WeightInfo::put_in_front_of())] pub fn put_in_front_of(origin: OriginFor, lighter: T::AccountId) -> DispatchResult { let heavier = ensure_signed(origin)?; - List::::put_in_front_of(&lighter, &heavier).map_err(Into::into) + List::::put_in_front_of(&lighter, &heavier).map_err(Into::into) } } #[pallet::hooks] - impl Hooks> for Pallet { + impl, I: 'static> Hooks> for Pallet { fn integrity_test() { // ensure they are strictly increasing, this also implies that duplicates are detected. assert!( @@ -228,71 +247,70 @@ pub mod pallet { } } -impl Pallet { +impl, I: 'static> Pallet { /// Move an account from one bag to another, depositing an event on success. /// /// If the account changed bags, returns `Some((from, to))`. - pub fn do_rebag( - account: &T::AccountId, - new_weight: VoteWeight, - ) -> Option<(VoteWeight, VoteWeight)> { + pub fn do_rebag(account: &T::AccountId, new_weight: T::Score) -> Option<(T::Score, T::Score)> { // if no voter at that node, don't do anything. // the caller just wasted the fee to call this. - let maybe_movement = list::Node::::get(&account) + let maybe_movement = list::Node::::get(&account) .and_then(|node| List::update_position_for(node, new_weight)); if let Some((from, to)) = maybe_movement { - Self::deposit_event(Event::::Rebagged { who: account.clone(), from, to }); + Self::deposit_event(Event::::Rebagged { who: account.clone(), from, to }); }; maybe_movement } /// Equivalent to `ListBags::get`, but public. Useful for tests in outside of this crate. #[cfg(feature = "std")] - pub fn list_bags_get(weight: VoteWeight) -> Option> { - ListBags::get(weight) + pub fn list_bags_get(score: T::Score) -> Option> { + ListBags::get(score) } } -impl SortedListProvider for Pallet { +impl, I: 'static> SortedListProvider for Pallet { type Error = Error; + type Score = T::Score; + fn iter() -> Box> { - Box::new(List::::iter().map(|n| n.id().clone())) + Box::new(List::::iter().map(|n| n.id().clone())) } fn count() -> u32 { - ListNodes::::count() + ListNodes::::count() } fn contains(id: &T::AccountId) -> bool { - List::::contains(id) + List::::contains(id) } - fn on_insert(id: T::AccountId, weight: VoteWeight) -> Result<(), Error> { - List::::insert(id, weight) + fn on_insert(id: T::AccountId, score: T::Score) -> Result<(), Error> { + List::::insert(id, score) } - fn on_update(id: &T::AccountId, new_weight: VoteWeight) { - Pallet::::do_rebag(id, new_weight); + fn on_update(id: &T::AccountId, new_score: T::Score) { + Pallet::::do_rebag(id, new_score); } fn on_remove(id: &T::AccountId) { - List::::remove(id) + List::::remove(id) } fn unsafe_regenerate( all: impl IntoIterator, - weight_of: Box VoteWeight>, + score_of: Box T::Score>, ) -> u32 { // NOTE: This call is unsafe for the same reason as SortedListProvider::unsafe_regenerate. // I.e. because it can lead to many storage accesses. // So it is ok to call it as caller must ensure the conditions. - List::::unsafe_regenerate(all, weight_of) + List::::unsafe_regenerate(all, score_of) } #[cfg(feature = "std")] fn sanity_check() -> Result<(), &'static str> { - List::::sanity_check() + List::::sanity_check() } #[cfg(not(feature = "std"))] @@ -304,17 +322,17 @@ impl SortedListProvider for Pallet { // NOTE: This call is unsafe for the same reason as SortedListProvider::unsafe_clear. // I.e. because it can lead to many storage accesses. // So it is ok to call it as caller must ensure the conditions. - List::::unsafe_clear() + List::::unsafe_clear() } #[cfg(feature = "runtime-benchmarks")] - fn weight_update_worst_case(who: &T::AccountId, is_increase: bool) -> VoteWeight { + fn score_update_worst_case(who: &T::AccountId, is_increase: bool) -> Self::Score { use frame_support::traits::Get as _; let thresholds = T::BagThresholds::get(); - let node = list::Node::::get(who).unwrap(); + let node = list::Node::::get(who).unwrap(); let current_bag_idx = thresholds .iter() - .chain(sp_std::iter::once(&VoteWeight::MAX)) + .chain(sp_std::iter::once(&T::Score::max_value())) .position(|w| w == &node.bag_upper()) .unwrap(); diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 8cd89b8fff1cc..4921817c7e146 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -26,9 +26,10 @@ use crate::Config; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_election_provider_support::{VoteWeight, VoteWeightProvider}; +use frame_election_provider_support::ScoreProvider; use frame_support::{traits::Get, DefaultNoBound}; use scale_info::TypeInfo; +use sp_runtime::traits::{Bounded, Zero}; use sp_std::{ boxed::Box, collections::{btree_map::BTreeMap, btree_set::BTreeSet}, @@ -46,36 +47,36 @@ pub enum Error { #[cfg(test)] mod tests; -/// Given a certain vote weight, to which bag does it belong to? +/// Given a certain score, to which bag does it belong to? /// /// Bags are identified by their upper threshold; the value returned by this function is guaranteed /// to be a member of `T::BagThresholds`. /// -/// Note that even if the thresholds list does not have `VoteWeight::MAX` as its final member, this -/// function behaves as if it does. -pub fn notional_bag_for(weight: VoteWeight) -> VoteWeight { +/// Note that even if the thresholds list does not have `T::Score::max_value()` as its final member, +/// this function behaves as if it does. +pub fn notional_bag_for, I: 'static>(score: T::Score) -> T::Score { let thresholds = T::BagThresholds::get(); - let idx = thresholds.partition_point(|&threshold| weight > threshold); - thresholds.get(idx).copied().unwrap_or(VoteWeight::MAX) + let idx = thresholds.partition_point(|&threshold| score > threshold); + thresholds.get(idx).copied().unwrap_or(T::Score::max_value()) } /// The **ONLY** entry point of this module. All operations to the bags-list should happen through /// this interface. It is forbidden to access other module members directly. // -// Data structure providing efficient mostly-accurate selection of the top N id by `VoteWeight`. +// Data structure providing efficient mostly-accurate selection of the top N id by `Score`. // // It's implemented as a set of linked lists. Each linked list comprises a bag of ids of -// arbitrary and unbounded length, all having a vote weight within a particular constant range. +// arbitrary and unbounded length, all having a score within a particular constant range. // This structure means that ids can be added and removed in `O(1)` time. // // Iteration is accomplished by chaining the iteration of each bag, from greatest to least. While -// the users within any particular bag are sorted in an entirely arbitrary order, the overall vote -// weight decreases as successive bags are reached. This means that it is valid to truncate +// the users within any particular bag are sorted in an entirely arbitrary order, the overall score +// decreases as successive bags are reached. This means that it is valid to truncate // iteration at any desired point; only those ids in the lowest bag can be excluded. This // satisfies both the desire for fairness and the requirement for efficiency. -pub struct List(PhantomData); +pub struct List, I: 'static = ()>(PhantomData<(T, I)>); -impl List { +impl, I: 'static> List { /// Remove all data associated with the list from storage. /// /// ## WARNING @@ -83,8 +84,8 @@ impl List { /// this function should generally not be used in production as it could lead to a very large /// number of storage accesses. pub(crate) fn unsafe_clear() { - crate::ListBags::::remove_all(None); - crate::ListNodes::::remove_all(); + crate::ListBags::::remove_all(None); + crate::ListNodes::::remove_all(); } /// Regenerate all of the data from the given ids. @@ -98,13 +99,13 @@ impl List { /// Returns the number of ids migrated. pub fn unsafe_regenerate( all: impl IntoIterator, - weight_of: Box VoteWeight>, + score_of: Box T::Score>, ) -> u32 { // NOTE: This call is unsafe for the same reason as SortedListProvider::unsafe_regenerate. // I.e. because it can lead to many storage accesses. // So it is ok to call it as caller must ensure the conditions. Self::unsafe_clear(); - Self::insert_many(all, weight_of) + Self::insert_many(all, score_of) } /// Migrate the list from one set of thresholds to another. @@ -127,7 +128,7 @@ impl List { /// - ids whose bags change at all are implicitly rebagged into the appropriate bag in the new /// threshold set. #[allow(dead_code)] - pub fn migrate(old_thresholds: &[VoteWeight]) -> u32 { + pub fn migrate(old_thresholds: &[T::Score]) -> u32 { let new_thresholds = T::BagThresholds::get(); if new_thresholds == old_thresholds { return 0 @@ -135,11 +136,13 @@ impl List { // we can't check all preconditions, but we can check one debug_assert!( - crate::ListBags::::iter().all(|(threshold, _)| old_thresholds.contains(&threshold)), + crate::ListBags::::iter() + .all(|(threshold, _)| old_thresholds.contains(&threshold)), "not all `bag_upper` currently in storage are members of `old_thresholds`", ); debug_assert!( - crate::ListNodes::::iter().all(|(_, node)| old_thresholds.contains(&node.bag_upper)), + crate::ListNodes::::iter() + .all(|(_, node)| old_thresholds.contains(&node.bag_upper)), "not all `node.bag_upper` currently in storage are members of `old_thresholds`", ); @@ -158,7 +161,7 @@ impl List { let affected_bag = { // this recreates `notional_bag_for` logic, but with the old thresholds. let idx = old_thresholds.partition_point(|&threshold| inserted_bag > threshold); - old_thresholds.get(idx).copied().unwrap_or(VoteWeight::MAX) + old_thresholds.get(idx).copied().unwrap_or(T::Score::max_value()) }; if !affected_old_bags.insert(affected_bag) { // If the previous threshold list was [10, 20], and we insert [3, 5], then there's @@ -166,7 +169,7 @@ impl List { continue } - if let Some(bag) = Bag::::get(affected_bag) { + if let Some(bag) = Bag::::get(affected_bag) { affected_accounts.extend(bag.iter().map(|node| node.id)); } } @@ -178,17 +181,17 @@ impl List { continue } - if let Some(bag) = Bag::::get(removed_bag) { + if let Some(bag) = Bag::::get(removed_bag) { affected_accounts.extend(bag.iter().map(|node| node.id)); } } // migrate the voters whose bag has changed let num_affected = affected_accounts.len() as u32; - let weight_of = T::VoteWeightProvider::vote_weight; + let score_of = T::ScoreProvider::score; let _removed = Self::remove_many(&affected_accounts); debug_assert_eq!(_removed, num_affected); - let _inserted = Self::insert_many(affected_accounts.into_iter(), weight_of); + let _inserted = Self::insert_many(affected_accounts.into_iter(), score_of); debug_assert_eq!(_inserted, num_affected); // we couldn't previously remove the old bags because both insertion and removal assume that @@ -199,10 +202,10 @@ impl List { // lookups. for removed_bag in removed_bags { debug_assert!( - !crate::ListNodes::::iter().any(|(_, node)| node.bag_upper == removed_bag), + !crate::ListNodes::::iter().any(|(_, node)| node.bag_upper == removed_bag), "no id should be present in a removed bag", ); - crate::ListBags::::remove(removed_bag); + crate::ListBags::::remove(removed_bag); } debug_assert_eq!(Self::sanity_check(), Ok(())); @@ -212,14 +215,14 @@ impl List { /// Returns `true` if the list contains `id`, otherwise returns `false`. pub(crate) fn contains(id: &T::AccountId) -> bool { - crate::ListNodes::::contains_key(id) + crate::ListNodes::::contains_key(id) } /// Iterate over all nodes in all bags in the list. /// /// Full iteration can be expensive; it's recommended to limit the number of items with /// `.take(n)`. - pub(crate) fn iter() -> impl Iterator> { + pub(crate) fn iter() -> impl Iterator> { // We need a touch of special handling here: because we permit `T::BagThresholds` to // omit the final bound, we need to ensure that we explicitly include that threshold in the // list. @@ -228,12 +231,14 @@ impl List { // easier; they can just configure `type BagThresholds = ()`. let thresholds = T::BagThresholds::get(); let iter = thresholds.iter().copied(); - let iter: Box> = if thresholds.last() == Some(&VoteWeight::MAX) { + let iter: Box> = if thresholds.last() == + Some(&T::Score::max_value()) + { // in the event that they included it, we can just pass the iterator through unchanged. Box::new(iter.rev()) } else { // otherwise, insert it here. - Box::new(iter.chain(iter::once(VoteWeight::MAX)).rev()) + Box::new(iter.chain(iter::once(T::Score::max_value())).rev()) }; iter.filter_map(Bag::get).flat_map(|bag| bag.iter()) @@ -245,12 +250,12 @@ impl List { /// Returns the final count of number of ids inserted. fn insert_many( ids: impl IntoIterator, - weight_of: impl Fn(&T::AccountId) -> VoteWeight, + score_of: impl Fn(&T::AccountId) -> T::Score, ) -> u32 { let mut count = 0; ids.into_iter().for_each(|v| { - let weight = weight_of(&v); - if Self::insert(v, weight).is_ok() { + let score = score_of(&v); + if Self::insert(v, score).is_ok() { count += 1; } }); @@ -261,13 +266,13 @@ impl List { /// Insert a new id into the appropriate bag in the list. /// /// Returns an error if the list already contains `id`. - pub(crate) fn insert(id: T::AccountId, weight: VoteWeight) -> Result<(), Error> { + pub(crate) fn insert(id: T::AccountId, score: T::Score) -> Result<(), Error> { if Self::contains(&id) { return Err(Error::Duplicate) } - let bag_weight = notional_bag_for::(weight); - let mut bag = Bag::::get_or_make(bag_weight); + let bag_score = notional_bag_for::(score); + let mut bag = Bag::::get_or_make(bag_score); // unchecked insertion is okay; we just got the correct `notional_bag_for`. bag.insert_unchecked(id.clone()); @@ -276,11 +281,12 @@ impl List { crate::log!( debug, - "inserted {:?} with weight {} into bag {:?}, new count is {}", + "inserted {:?} with score {:? + } into bag {:?}, new count is {}", id, - weight, - bag_weight, - crate::ListNodes::::count(), + score, + bag_score, + crate::ListNodes::::count(), ); Ok(()) @@ -301,7 +307,7 @@ impl List { let mut count = 0; for id in ids.into_iter() { - let node = match Node::::get(id) { + let node = match Node::::get(id) { Some(node) => node, None => continue, }; @@ -314,7 +320,7 @@ impl List { // this node is a head or tail, so the bag needs to be updated let bag = bags .entry(node.bag_upper) - .or_insert_with(|| Bag::::get_or_make(node.bag_upper)); + .or_insert_with(|| Bag::::get_or_make(node.bag_upper)); // node.bag_upper must be correct, therefore this bag will contain this node. bag.remove_node_unchecked(&node); } @@ -341,17 +347,17 @@ impl List { /// [`self.insert`]. However, given large quantities of nodes to move, it may be more efficient /// to call [`self.remove_many`] followed by [`self.insert_many`]. pub(crate) fn update_position_for( - node: Node, - new_weight: VoteWeight, - ) -> Option<(VoteWeight, VoteWeight)> { - node.is_misplaced(new_weight).then(move || { + node: Node, + new_score: T::Score, + ) -> Option<(T::Score, T::Score)> { + node.is_misplaced(new_score).then(move || { let old_bag_upper = node.bag_upper; if !node.is_terminal() { // this node is not a head or a tail, so we can just cut it out of the list. update // and put the prev and next of this node, we do `node.put` inside `insert_note`. node.excise(); - } else if let Some(mut bag) = Bag::::get(node.bag_upper) { + } else if let Some(mut bag) = Bag::::get(node.bag_upper) { // this is a head or tail, so the bag must be updated. bag.remove_node_unchecked(&node); bag.put(); @@ -365,8 +371,8 @@ impl List { } // put the node into the appropriate new bag. - let new_bag_upper = notional_bag_for::(new_weight); - let mut bag = Bag::::get_or_make(new_bag_upper); + let new_bag_upper = notional_bag_for::(new_score); + let mut bag = Bag::::get_or_make(new_bag_upper); // prev, next, and bag_upper of the node are updated inside `insert_node`, also // `node.put` is in there. bag.insert_node_unchecked(node); @@ -377,23 +383,22 @@ impl List { } /// Put `heavier_id` to the position directly in front of `lighter_id`. Both ids must be in the - /// same bag and the `weight_of` `lighter_id` must be less than that of `heavier_id`. + /// same bag and the `score_of` `lighter_id` must be less than that of `heavier_id`. pub(crate) fn put_in_front_of( lighter_id: &T::AccountId, heavier_id: &T::AccountId, - ) -> Result<(), crate::pallet::Error> { + ) -> Result<(), crate::pallet::Error> { use crate::pallet; use frame_support::ensure; - let lighter_node = Node::::get(&lighter_id).ok_or(pallet::Error::IdNotFound)?; - let heavier_node = Node::::get(&heavier_id).ok_or(pallet::Error::IdNotFound)?; + let lighter_node = Node::::get(&lighter_id).ok_or(pallet::Error::IdNotFound)?; + let heavier_node = Node::::get(&heavier_id).ok_or(pallet::Error::IdNotFound)?; ensure!(lighter_node.bag_upper == heavier_node.bag_upper, pallet::Error::NotInSameBag); // this is the most expensive check, so we do it last. ensure!( - T::VoteWeightProvider::vote_weight(&heavier_id) > - T::VoteWeightProvider::vote_weight(&lighter_id), + T::ScoreProvider::score(&heavier_id) > T::ScoreProvider::score(&lighter_id), pallet::Error::NotHeavier ); @@ -403,7 +408,7 @@ impl List { // re-fetch `lighter_node` from storage since it may have been updated when `heavier_node` // was removed. - let lighter_node = Node::::get(&lighter_id).ok_or_else(|| { + let lighter_node = Node::::get(&lighter_id).ok_or_else(|| { debug_assert!(false, "id that should exist cannot be found"); crate::log!(warn, "id that should exist cannot be found"); pallet::Error::IdNotFound @@ -422,7 +427,7 @@ impl List { /// - this is a naive function in that it does not check if `node` belongs to the same bag as /// `at`. It is expected that the call site will check preconditions. /// - this will panic if `at.bag_upper` is not a bag that already exists in storage. - fn insert_at_unchecked(mut at: Node, mut node: Node) { + fn insert_at_unchecked(mut at: Node, mut node: Node) { // connect `node` to its new `prev`. node.prev = at.prev.clone(); if let Some(mut prev) = at.prev() { @@ -439,7 +444,7 @@ impl List { // since `node` is always in front of `at` we know that 1) there is always at least 2 // nodes in the bag, and 2) only `node` could be the head and only `at` could be the // tail. - let mut bag = Bag::::get(at.bag_upper) + let mut bag = Bag::::get(at.bag_upper) .expect("given nodes must always have a valid bag. qed."); if node.prev == None { @@ -473,8 +478,8 @@ impl List { ); let iter_count = Self::iter().count() as u32; - let stored_count = crate::ListNodes::::count(); - let nodes_count = crate::ListNodes::::iter().count() as u32; + let stored_count = crate::ListNodes::::count(); + let nodes_count = crate::ListNodes::::iter().count() as u32; ensure!(iter_count == stored_count, "iter_count != stored_count"); ensure!(stored_count == nodes_count, "stored_count != nodes_count"); @@ -482,14 +487,15 @@ impl List { let active_bags = { let thresholds = T::BagThresholds::get().iter().copied(); - let thresholds: Vec = if thresholds.clone().last() == Some(VoteWeight::MAX) { - // in the event that they included it, we don't need to make any changes - thresholds.collect() - } else { - // otherwise, insert it here. - thresholds.chain(iter::once(VoteWeight::MAX)).collect() - }; - thresholds.into_iter().filter_map(|t| Bag::::get(t)) + let thresholds: Vec = + if thresholds.clone().last() == Some(T::Score::max_value()) { + // in the event that they included it, we don't need to make any changes + thresholds.collect() + } else { + // otherwise, insert it here. + thresholds.chain(iter::once(T::Score::max_value())).collect() + }; + thresholds.into_iter().filter_map(|t| Bag::::get(t)) }; let _ = active_bags.clone().map(|b| b.sanity_check()).collect::>()?; @@ -502,7 +508,7 @@ impl List { // check that all nodes are sane. We check the `ListNodes` storage item directly in case we // have some "stale" nodes that are not in a bag. - for (_id, node) in crate::ListNodes::::iter() { + for (_id, node) in crate::ListNodes::::iter() { node.sanity_check()? } @@ -517,21 +523,24 @@ impl List { /// Returns the nodes of all non-empty bags. For testing and benchmarks. #[cfg(any(feature = "std", feature = "runtime-benchmarks"))] #[allow(dead_code)] - pub(crate) fn get_bags() -> Vec<(VoteWeight, Vec)> { + pub(crate) fn get_bags() -> Vec<(T::Score, Vec)> { use frame_support::traits::Get as _; let thresholds = T::BagThresholds::get(); let iter = thresholds.iter().copied(); - let iter: Box> = if thresholds.last() == Some(&VoteWeight::MAX) { + let iter: Box> = if thresholds.last() == + Some(&T::Score::max_value()) + { // in the event that they included it, we can just pass the iterator through unchanged. Box::new(iter) } else { // otherwise, insert it here. - Box::new(iter.chain(sp_std::iter::once(VoteWeight::MAX))) + Box::new(iter.chain(sp_std::iter::once(T::Score::max_value()))) }; iter.filter_map(|t| { - Bag::::get(t).map(|bag| (t, bag.iter().map(|n| n.id().clone()).collect::>())) + Bag::::get(t) + .map(|bag| (t, bag.iter().map(|n| n.id().clone()).collect::>())) }) .collect::>() } @@ -546,37 +555,39 @@ impl List { /// appearing within the ids set. #[derive(DefaultNoBound, Encode, Decode, MaxEncodedLen, TypeInfo)] #[codec(mel_bound())] -#[scale_info(skip_type_params(T))] +#[scale_info(skip_type_params(T, I))] #[cfg_attr(feature = "std", derive(frame_support::DebugNoBound, Clone, PartialEq))] -pub struct Bag { +pub struct Bag, I: 'static = ()> { head: Option, tail: Option, #[codec(skip)] - bag_upper: VoteWeight, + bag_upper: T::Score, + #[codec(skip)] + _phantom: PhantomData, } -impl Bag { +impl, I: 'static> Bag { #[cfg(test)] pub(crate) fn new( head: Option, tail: Option, - bag_upper: VoteWeight, + bag_upper: T::Score, ) -> Self { - Self { head, tail, bag_upper } + Self { head, tail, bag_upper, _phantom: PhantomData } } - /// Get a bag by its upper vote weight. - pub(crate) fn get(bag_upper: VoteWeight) -> Option> { - crate::ListBags::::try_get(bag_upper).ok().map(|mut bag| { + /// Get a bag by its upper score. + pub(crate) fn get(bag_upper: T::Score) -> Option> { + crate::ListBags::::try_get(bag_upper).ok().map(|mut bag| { bag.bag_upper = bag_upper; bag }) } - /// Get a bag by its upper vote weight or make it, appropriately initialized. Does not check if + /// Get a bag by its upper score or make it, appropriately initialized. Does not check if /// if `bag_upper` is a valid threshold. - fn get_or_make(bag_upper: VoteWeight) -> Bag { + fn get_or_make(bag_upper: T::Score) -> Bag { Self::get(bag_upper).unwrap_or(Bag { bag_upper, ..Default::default() }) } @@ -588,24 +599,24 @@ impl Bag { /// Put the bag back into storage. fn put(self) { if self.is_empty() { - crate::ListBags::::remove(self.bag_upper); + crate::ListBags::::remove(self.bag_upper); } else { - crate::ListBags::::insert(self.bag_upper, self); + crate::ListBags::::insert(self.bag_upper, self); } } /// Get the head node in this bag. - fn head(&self) -> Option> { + fn head(&self) -> Option> { self.head.as_ref().and_then(|id| Node::get(id)) } /// Get the tail node in this bag. - fn tail(&self) -> Option> { + fn tail(&self) -> Option> { self.tail.as_ref().and_then(|id| Node::get(id)) } /// Iterate over the nodes in this bag. - pub(crate) fn iter(&self) -> impl Iterator> { + pub(crate) fn iter(&self) -> impl Iterator> { sp_std::iter::successors(self.head(), |prev| prev.next()) } @@ -620,7 +631,13 @@ impl Bag { // insert_node will overwrite `prev`, `next` and `bag_upper` to the proper values. As long // as this bag is the correct one, we're good. All calls to this must come after getting the // correct [`notional_bag_for`]. - self.insert_node_unchecked(Node:: { id, prev: None, next: None, bag_upper: 0 }); + self.insert_node_unchecked(Node:: { + id, + prev: None, + next: None, + bag_upper: Zero::zero(), + _phantom: PhantomData, + }); } /// Insert a node into this bag. @@ -630,7 +647,7 @@ impl Bag { /// /// Storage note: this modifies storage, but only for the node. You still need to call /// `self.put()` after use. - fn insert_node_unchecked(&mut self, mut node: Node) { + fn insert_node_unchecked(&mut self, mut node: Node) { if let Some(tail) = &self.tail { if *tail == node.id { // this should never happen, but this check prevents one path to a worst case @@ -674,7 +691,7 @@ impl Bag { /// /// Storage note: this modifies storage, but only for adjacent nodes. You still need to call /// `self.put()` and `ListNodes::remove(id)` to update storage for the bag and `node`. - fn remove_node_unchecked(&mut self, node: &Node) { + fn remove_node_unchecked(&mut self, node: &Node) { // reassign neighboring nodes. node.excise(); @@ -735,7 +752,7 @@ impl Bag { /// Iterate over the nodes in this bag (public for tests). #[cfg(feature = "std")] #[allow(dead_code)] - pub fn std_iter(&self) -> impl Iterator> { + pub fn std_iter(&self) -> impl Iterator> { sp_std::iter::successors(self.head(), |prev| prev.next()) } @@ -749,24 +766,26 @@ impl Bag { /// A Node is the fundamental element comprising the doubly-linked list described by `Bag`. #[derive(Encode, Decode, MaxEncodedLen, TypeInfo)] #[codec(mel_bound())] -#[scale_info(skip_type_params(T))] +#[scale_info(skip_type_params(T, I))] #[cfg_attr(feature = "std", derive(frame_support::DebugNoBound, Clone, PartialEq))] -pub struct Node { +pub struct Node, I: 'static = ()> { id: T::AccountId, prev: Option, next: Option, - bag_upper: VoteWeight, + bag_upper: T::Score, + #[codec(skip)] + _phantom: PhantomData, } -impl Node { +impl, I: 'static> Node { /// Get a node by id. - pub fn get(id: &T::AccountId) -> Option> { - crate::ListNodes::::try_get(id).ok() + pub fn get(id: &T::AccountId) -> Option> { + crate::ListNodes::::try_get(id).ok() } /// Put the node back into storage. fn put(self) { - crate::ListNodes::::insert(self.id.clone(), self); + crate::ListNodes::::insert(self.id.clone(), self); } /// Update neighboring nodes to point to reach other. @@ -790,22 +809,22 @@ impl Node { /// /// It is naive because it does not check if the node has first been removed from its bag. fn remove_from_storage_unchecked(&self) { - crate::ListNodes::::remove(&self.id) + crate::ListNodes::::remove(&self.id) } /// Get the previous node in the bag. - fn prev(&self) -> Option> { + fn prev(&self) -> Option> { self.prev.as_ref().and_then(|id| Node::get(id)) } /// Get the next node in the bag. - fn next(&self) -> Option> { + fn next(&self) -> Option> { self.next.as_ref().and_then(|id| Node::get(id)) } /// `true` when this voter is in the wrong bag. - pub fn is_misplaced(&self, current_weight: VoteWeight) -> bool { - notional_bag_for::(current_weight) != self.bag_upper + pub fn is_misplaced(&self, current_score: T::Score) -> bool { + notional_bag_for::(current_score) != self.bag_upper } /// `true` when this voter is a bag head or tail. @@ -828,13 +847,13 @@ impl Node { /// The bag this nodes belongs to (public for benchmarks). #[cfg(feature = "runtime-benchmarks")] #[allow(dead_code)] - pub fn bag_upper(&self) -> VoteWeight { + pub fn bag_upper(&self) -> T::Score { self.bag_upper } #[cfg(feature = "std")] fn sanity_check(&self) -> Result<(), &'static str> { - let expected_bag = Bag::::get(self.bag_upper).ok_or("bag not found for node")?; + let expected_bag = Bag::::get(self.bag_upper).ok_or("bag not found for node")?; let id = self.id(); diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index aaa215b0af1ca..9b7a078b44284 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -20,14 +20,20 @@ use crate::{ mock::{test_utils::*, *}, ListBags, ListNodes, }; -use frame_election_provider_support::SortedListProvider; +use frame_election_provider_support::{SortedListProvider, VoteWeight}; use frame_support::{assert_ok, assert_storage_noop}; #[test] fn basic_setup_works() { ExtBuilder::default().build_and_execute(|| { // syntactic sugar to create a raw node - let node = |id, prev, next, bag_upper| Node:: { id, prev, next, bag_upper }; + let node = |id, prev, next, bag_upper| Node:: { + id, + prev, + next, + bag_upper, + _phantom: PhantomData, + }; assert_eq!(ListNodes::::count(), 4); assert_eq!(ListNodes::::iter().count(), 4); @@ -38,11 +44,11 @@ fn basic_setup_works() { // the state of the bags is as expected assert_eq!( ListBags::::get(10).unwrap(), - Bag:: { head: Some(1), tail: Some(1), bag_upper: 0 } + Bag:: { head: Some(1), tail: Some(1), bag_upper: 0, _phantom: PhantomData } ); assert_eq!( ListBags::::get(1_000).unwrap(), - Bag:: { head: Some(2), tail: Some(4), bag_upper: 0 } + Bag:: { head: Some(2), tail: Some(4), bag_upper: 0, _phantom: PhantomData } ); assert_eq!(ListNodes::::get(2).unwrap(), node(2, None, Some(3), 1_000)); @@ -65,24 +71,24 @@ fn basic_setup_works() { #[test] fn notional_bag_for_works() { // under a threshold gives the next threshold. - assert_eq!(notional_bag_for::(0), 10); - assert_eq!(notional_bag_for::(9), 10); + assert_eq!(notional_bag_for::(0), 10); + assert_eq!(notional_bag_for::(9), 10); // at a threshold gives that threshold. - assert_eq!(notional_bag_for::(10), 10); + assert_eq!(notional_bag_for::(10), 10); // above the threshold, gives the next threshold. - assert_eq!(notional_bag_for::(11), 20); + assert_eq!(notional_bag_for::(11), 20); let max_explicit_threshold = *::BagThresholds::get().last().unwrap(); assert_eq!(max_explicit_threshold, 10_000); - // if the max explicit threshold is less than VoteWeight::MAX, + // if the max explicit threshold is less than T::Value::max_value(), assert!(VoteWeight::MAX > max_explicit_threshold); - // then anything above it will belong to the VoteWeight::MAX bag. - assert_eq!(notional_bag_for::(max_explicit_threshold), max_explicit_threshold); - assert_eq!(notional_bag_for::(max_explicit_threshold + 1), VoteWeight::MAX); + // then anything above it will belong to the T::Value::max_value() bag. + assert_eq!(notional_bag_for::(max_explicit_threshold), max_explicit_threshold); + assert_eq!(notional_bag_for::(max_explicit_threshold + 1), VoteWeight::MAX); } #[test] @@ -388,14 +394,26 @@ mod list { #[should_panic = "given nodes must always have a valid bag. qed."] fn put_in_front_of_panics_if_bag_not_found() { ExtBuilder::default().skip_genesis_ids().build_and_execute_no_post_check(|| { - let node_10_no_bag = Node:: { id: 10, prev: None, next: None, bag_upper: 15 }; - let node_11_no_bag = Node:: { id: 11, prev: None, next: None, bag_upper: 15 }; + let node_10_no_bag = Node:: { + id: 10, + prev: None, + next: None, + bag_upper: 15, + _phantom: PhantomData, + }; + let node_11_no_bag = Node:: { + id: 11, + prev: None, + next: None, + bag_upper: 15, + _phantom: PhantomData, + }; // given ListNodes::::insert(10, node_10_no_bag); ListNodes::::insert(11, node_11_no_bag); - StakingMock::set_vote_weight_of(&10, 14); - StakingMock::set_vote_weight_of(&11, 15); + StakingMock::set_score_of(&10, 14); + StakingMock::set_score_of(&11, 15); assert!(!ListBags::::contains_key(15)); assert_eq!(List::::get_bags(), vec![]); @@ -414,8 +432,13 @@ mod list { assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); // implicitly also test that `node`'s `prev`/`next` are correctly re-assigned. - let node_42 = - Node:: { id: 42, prev: Some(1), next: Some(2), bag_upper: 1_000 }; + let node_42 = Node:: { + id: 42, + prev: Some(1), + next: Some(2), + bag_upper: 1_000, + _phantom: PhantomData, + }; assert!(!crate::ListNodes::::contains_key(42)); let node_1 = crate::ListNodes::::get(&1).unwrap(); @@ -438,7 +461,13 @@ mod list { assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); // implicitly also test that `node`'s `prev`/`next` are correctly re-assigned. - let node_42 = Node:: { id: 42, prev: Some(4), next: None, bag_upper: 1_000 }; + let node_42 = Node:: { + id: 42, + prev: Some(4), + next: None, + bag_upper: 1_000, + _phantom: PhantomData, + }; assert!(!crate::ListNodes::::contains_key(42)); let node_2 = crate::ListNodes::::get(&2).unwrap(); @@ -461,7 +490,13 @@ mod list { assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); // implicitly also test that `node`'s `prev`/`next` are correctly re-assigned. - let node_42 = Node:: { id: 42, prev: None, next: Some(2), bag_upper: 1_000 }; + let node_42 = Node:: { + id: 42, + prev: None, + next: Some(2), + bag_upper: 1_000, + _phantom: PhantomData, + }; assert!(!crate::ListNodes::::contains_key(42)); let node_3 = crate::ListNodes::::get(&3).unwrap(); @@ -484,8 +519,13 @@ mod list { assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); // implicitly also test that `node`'s `prev`/`next` are correctly re-assigned. - let node_42 = - Node:: { id: 42, prev: Some(42), next: Some(42), bag_upper: 1_000 }; + let node_42 = Node:: { + id: 42, + prev: Some(42), + next: Some(42), + bag_upper: 1_000, + _phantom: PhantomData, + }; assert!(!crate::ListNodes::::contains_key(42)); let node_4 = crate::ListNodes::::get(&4).unwrap(); @@ -512,7 +552,7 @@ mod bags { let bag = Bag::::get(bag_upper).unwrap(); let bag_ids = bag.iter().map(|n| *n.id()).collect::>(); - assert_eq!(bag, Bag:: { head, tail, bag_upper }); + assert_eq!(bag, Bag:: { head, tail, bag_upper, _phantom: PhantomData }); assert_eq!(bag_ids, ids); }; @@ -543,7 +583,13 @@ mod bags { #[test] fn insert_node_sets_proper_bag() { ExtBuilder::default().build_and_execute_no_post_check(|| { - let node = |id, bag_upper| Node:: { id, prev: None, next: None, bag_upper }; + let node = |id, bag_upper| Node:: { + id, + prev: None, + next: None, + bag_upper, + _phantom: PhantomData, + }; assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); @@ -552,7 +598,7 @@ mod bags { assert_eq!( ListNodes::::get(&42).unwrap(), - Node { bag_upper: 10, prev: Some(1), next: None, id: 42 } + Node { bag_upper: 10, prev: Some(1), next: None, id: 42, _phantom: PhantomData } ); }); } @@ -560,7 +606,13 @@ mod bags { #[test] fn insert_node_happy_paths_works() { ExtBuilder::default().build_and_execute_no_post_check(|| { - let node = |id, bag_upper| Node:: { id, prev: None, next: None, bag_upper }; + let node = |id, bag_upper| Node:: { + id, + prev: None, + next: None, + bag_upper, + _phantom: PhantomData, + }; // when inserting into a bag with 1 node let mut bag_10 = Bag::::get(10).unwrap(); @@ -581,15 +633,26 @@ mod bags { assert_eq!(bag_as_ids(&bag_20), vec![62]); // when inserting a node pointing to the accounts not in the bag - let node_61 = - Node:: { id: 61, prev: Some(21), next: Some(101), bag_upper: 20 }; + let node_61 = Node:: { + id: 61, + prev: Some(21), + next: Some(101), + bag_upper: 20, + _phantom: PhantomData, + }; bag_20.insert_node_unchecked(node_61); // then ids are in order assert_eq!(bag_as_ids(&bag_20), vec![62, 61]); // and when the node is re-fetched all the info is correct assert_eq!( Node::::get(&61).unwrap(), - Node:: { id: 61, prev: Some(62), next: None, bag_upper: 20 } + Node:: { + id: 61, + prev: Some(62), + next: None, + bag_upper: 20, + _phantom: PhantomData, + } ); // state of all bags is as expected @@ -604,7 +667,13 @@ mod bags { // Document improper ways `insert_node` may be getting used. #[test] fn insert_node_bad_paths_documented() { - let node = |id, prev, next, bag_upper| Node:: { id, prev, next, bag_upper }; + let node = |id, prev, next, bag_upper| Node:: { + id, + prev, + next, + bag_upper, + _phantom: PhantomData, + }; ExtBuilder::default().build_and_execute_no_post_check(|| { // when inserting a node with both prev & next pointing at an account in an incorrect // bag. @@ -657,7 +726,10 @@ mod bags { ); // ^^^ despite being the bags head, it has a prev - assert_eq!(bag_1000, Bag { head: Some(2), tail: Some(2), bag_upper: 1_000 }) + assert_eq!( + bag_1000, + Bag { head: Some(2), tail: Some(2), bag_upper: 1_000, _phantom: PhantomData } + ) }); } @@ -669,7 +741,13 @@ mod bags { )] fn insert_node_duplicate_tail_panics_with_debug_assert() { ExtBuilder::default().build_and_execute(|| { - let node = |id, prev, next, bag_upper| Node:: { id, prev, next, bag_upper }; + let node = |id, prev, next, bag_upper| Node:: { + id, + prev, + next, + bag_upper, + _phantom: PhantomData, + }; // given assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])],); @@ -801,6 +879,7 @@ mod bags { prev: None, next: Some(3), bag_upper: 10, // should be 1_000 + _phantom: PhantomData, }; let mut bag_1000 = Bag::::get(1_000).unwrap(); diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index aa3f549e12dec..fce1431054174 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -27,19 +27,21 @@ pub type AccountId = u32; pub type Balance = u32; parameter_types! { - // Set the vote weight for any id who's weight has _not_ been set with `set_vote_weight_of`. + // Set the vote weight for any id who's weight has _not_ been set with `set_score_of`. pub static NextVoteWeight: VoteWeight = 0; pub static NextVoteWeightMap: HashMap = Default::default(); } pub struct StakingMock; -impl frame_election_provider_support::VoteWeightProvider for StakingMock { - fn vote_weight(id: &AccountId) -> VoteWeight { +impl frame_election_provider_support::ScoreProvider for StakingMock { + type Score = VoteWeight; + + fn score(id: &AccountId) -> Self::Score { *NextVoteWeightMap::get().get(id).unwrap_or(&NextVoteWeight::get()) } #[cfg(any(feature = "runtime-benchmarks", test))] - fn set_vote_weight_of(id: &AccountId, weight: VoteWeight) { + fn set_score_of(id: &AccountId, weight: Self::Score) { NEXT_VOTE_WEIGHT_MAP.with(|m| m.borrow_mut().insert(id.clone(), weight)); } } @@ -79,7 +81,8 @@ impl bags_list::Config for Runtime { type Event = Event; type WeightInfo = (); type BagThresholds = BagThresholds; - type VoteWeightProvider = StakingMock; + type ScoreProvider = StakingMock; + type Score = VoteWeight; } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -134,7 +137,7 @@ impl ExtBuilder { ext.execute_with(|| { for (id, weight) in ids_with_weight { frame_support::assert_ok!(List::::insert(*id, *weight)); - StakingMock::set_vote_weight_of(id, *weight); + StakingMock::set_score_of(id, *weight); } }); diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs index 43397b3c120f5..99396c9cbb3e3 100644 --- a/frame/bags-list/src/tests.rs +++ b/frame/bags-list/src/tests.rs @@ -18,7 +18,7 @@ use frame_support::{assert_noop, assert_ok, assert_storage_noop, traits::IntegrityTest}; use super::*; -use frame_election_provider_support::SortedListProvider; +use frame_election_provider_support::{SortedListProvider, VoteWeight}; use list::Bag; use mock::{test_utils::*, *}; @@ -35,7 +35,7 @@ mod pallet { ); // when increasing vote weight to the level of non-existent bag - StakingMock::set_vote_weight_of(&42, 2_000); + StakingMock::set_score_of(&42, 2_000); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); // then a new bag is created and the id moves into it @@ -45,7 +45,7 @@ mod pallet { ); // when decreasing weight within the range of the current bag - StakingMock::set_vote_weight_of(&42, 1_001); + StakingMock::set_score_of(&42, 1_001); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); // then the id does not move @@ -55,7 +55,7 @@ mod pallet { ); // when reducing weight to the level of a non-existent bag - StakingMock::set_vote_weight_of(&42, 30); + StakingMock::set_score_of(&42, 30); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); // then a new bag is created and the id moves into it @@ -65,7 +65,7 @@ mod pallet { ); // when increasing weight to the level of a pre-existing bag - StakingMock::set_vote_weight_of(&42, 500); + StakingMock::set_score_of(&42, 500); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); // then the id moves into that bag @@ -85,7 +85,7 @@ mod pallet { assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); // when - StakingMock::set_vote_weight_of(&4, 10); + StakingMock::set_score_of(&4, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 4)); // then @@ -93,7 +93,7 @@ mod pallet { assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(2), Some(3), 1_000)); // when - StakingMock::set_vote_weight_of(&3, 10); + StakingMock::set_score_of(&3, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 3)); // then @@ -104,7 +104,7 @@ mod pallet { assert_eq!(get_list_as_ids(), vec![2u32, 1, 4, 3]); // when - StakingMock::set_vote_weight_of(&2, 10); + StakingMock::set_score_of(&2, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 2)); // then @@ -119,7 +119,7 @@ mod pallet { fn rebag_head_works() { ExtBuilder::default().build_and_execute(|| { // when - StakingMock::set_vote_weight_of(&2, 10); + StakingMock::set_score_of(&2, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 2)); // then @@ -127,7 +127,7 @@ mod pallet { assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(3), Some(4), 1_000)); // when - StakingMock::set_vote_weight_of(&3, 10); + StakingMock::set_score_of(&3, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 3)); // then @@ -135,7 +135,7 @@ mod pallet { assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(4), Some(4), 1_000)); // when - StakingMock::set_vote_weight_of(&4, 10); + StakingMock::set_score_of(&4, 10); assert_ok!(BagsList::rebag(Origin::signed(0), 4)); // then @@ -241,7 +241,7 @@ mod pallet { // given assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5])]); - StakingMock::set_vote_weight_of(&3, 999); + StakingMock::set_score_of(&3, 999); // when assert_ok!(BagsList::put_in_front_of(Origin::signed(4), 3)); @@ -262,7 +262,7 @@ mod pallet { vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5, 6])] ); - StakingMock::set_vote_weight_of(&5, 999); + StakingMock::set_score_of(&5, 999); // when assert_ok!(BagsList::put_in_front_of(Origin::signed(3), 5)); @@ -281,7 +281,7 @@ mod pallet { // given assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); - StakingMock::set_vote_weight_of(&2, 999); + StakingMock::set_score_of(&2, 999); // when assert_ok!(BagsList::put_in_front_of(Origin::signed(3), 2)); @@ -297,7 +297,7 @@ mod pallet { // given assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); - StakingMock::set_vote_weight_of(&3, 999); + StakingMock::set_score_of(&3, 999); // when assert_ok!(BagsList::put_in_front_of(Origin::signed(4), 3)); @@ -313,7 +313,7 @@ mod pallet { // given assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5])]); - StakingMock::set_vote_weight_of(&2, 999); + StakingMock::set_score_of(&2, 999); // when assert_ok!(BagsList::put_in_front_of(Origin::signed(5), 2)); @@ -329,7 +329,7 @@ mod pallet { // given assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5])]); - StakingMock::set_vote_weight_of(&4, 999); + StakingMock::set_score_of(&4, 999); // when BagsList::put_in_front_of(Origin::signed(2), 4).unwrap(); @@ -359,7 +359,7 @@ mod pallet { // given assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); - StakingMock::set_vote_weight_of(&4, 999); + StakingMock::set_score_of(&4, 999); // when BagsList::put_in_front_of(Origin::signed(2), 4).unwrap(); @@ -375,7 +375,7 @@ mod pallet { // given assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); - StakingMock::set_vote_weight_of(&3, 999); + StakingMock::set_score_of(&3, 999); // then assert_noop!( diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index e66774c6b5e71..b95bd994fa70a 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -18,12 +18,12 @@ scale-info = { version = "2.0.1", default-features = false, features = ["derive" sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-io = { version = "6.0.0", path = "../../primitives/io" } diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index ca22e3093855c..ff57eacf68fa0 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -168,6 +168,7 @@ pub mod onchain; use frame_support::{traits::Get, BoundedVec}; +use sp_runtime::traits::Bounded; use sp_std::{fmt::Debug, prelude::*}; /// Re-export some type as they are used in the interface. @@ -333,9 +334,7 @@ where /// This is generic over `AccountId` and it can represent a validator, a nominator, or any other /// entity. /// -/// To simplify the trait, the `VoteWeight` is hardcoded as the weight of each entity. The weights -/// are ascending, the higher, the better. In the long term, if this trait ends up having use cases -/// outside of the election context, it is easy enough to make it generic over the `VoteWeight`. +/// The scores (see [`Self::Score`]) are ascending, the higher, the better. /// /// Something that implements this trait will do a best-effort sort over ids, and thus can be /// used on the implementing side of [`ElectionDataProvider`]. @@ -343,6 +342,9 @@ pub trait SortedListProvider { /// The list's error type. type Error: sp_std::fmt::Debug; + /// The type used by the list to compare nodes for ordering. + type Score: Bounded; + /// An iterator over the list, which can have `take` called on it. fn iter() -> Box>; @@ -353,10 +355,10 @@ pub trait SortedListProvider { fn contains(id: &AccountId) -> bool; /// Hook for inserting a new id. - fn on_insert(id: AccountId, weight: VoteWeight) -> Result<(), Self::Error>; + fn on_insert(id: AccountId, score: Self::Score) -> Result<(), Self::Error>; /// Hook for updating a single id. - fn on_update(id: &AccountId, weight: VoteWeight); + fn on_update(id: &AccountId, score: Self::Score); /// Hook for removing am id from the list. fn on_remove(id: &AccountId); @@ -371,7 +373,7 @@ pub trait SortedListProvider { /// new list, which can lead to too many storage accesses, exhausting the block weight. fn unsafe_regenerate( all: impl IntoIterator, - weight_of: Box VoteWeight>, + score_of: Box Self::Score>, ) -> u32; /// Remove all items from the list. @@ -388,21 +390,23 @@ pub trait SortedListProvider { /// If `who` changes by the returned amount they are guaranteed to have a worst case change /// in their list position. #[cfg(feature = "runtime-benchmarks")] - fn weight_update_worst_case(_who: &AccountId, _is_increase: bool) -> VoteWeight { - VoteWeight::MAX + fn score_update_worst_case(_who: &AccountId, _is_increase: bool) -> Self::Score { + Self::Score::max_value() } } /// Something that can provide the `VoteWeight` of an account. Similar to [`ElectionProvider`] and /// [`ElectionDataProvider`], this should typically be implementing by whoever is supposed to *use* /// `SortedListProvider`. -pub trait VoteWeightProvider { - /// Get the current `VoteWeight` of `who`. - fn vote_weight(who: &AccountId) -> VoteWeight; +pub trait ScoreProvider { + type Score; + + /// Get the current `Score` of `who`. + fn score(who: &AccountId) -> Self::Score; /// For tests and benchmarks, set the `VoteWeight`. #[cfg(any(feature = "runtime-benchmarks", test))] - fn set_vote_weight_of(_: &AccountId, _: VoteWeight) {} + fn set_score_of(_: &AccountId, _: Self::Score) {} } /// Something that can compute the result to an NPoS solution. diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index ec7d36c820f3e..3e57b647ac80d 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -189,7 +189,7 @@ impl ListScenario { // find a destination weight that will trigger the worst case scenario let dest_weight_as_vote = - T::SortedListProvider::weight_update_worst_case(&origin_stash1, is_increase); + T::SortedListProvider::score_update_worst_case(&origin_stash1, is_increase); let total_issuance = T::Currency::total_issuance(); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 12d3804b4e303..843791a46ade2 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -18,7 +18,7 @@ //! Test utilities use crate::{self as pallet_staking, *}; -use frame_election_provider_support::{onchain, SortedListProvider}; +use frame_election_provider_support::{onchain, SortedListProvider, VoteWeight}; use frame_support::{ assert_ok, parameter_types, traits::{ @@ -240,8 +240,9 @@ parameter_types! { impl pallet_bags_list::Config for Test { type Event = Event; type WeightInfo = (); - type VoteWeightProvider = Staking; + type ScoreProvider = Staking; type BagThresholds = BagThresholds; + type Score = VoteWeight; } impl onchain::Config for Test { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 5cd0d0107f015..a4aadb16ab1b9 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -18,8 +18,8 @@ //! Implementations for the Staking FRAME Pallet. use frame_election_provider_support::{ - data_provider, ElectionDataProvider, ElectionProvider, SortedListProvider, Supports, - VoteWeight, VoteWeightProvider, VoterOf, + data_provider, ElectionDataProvider, ElectionProvider, ScoreProvider, SortedListProvider, + Supports, VoteWeight, VoterOf, }; use frame_support::{ pallet_prelude::*, @@ -1244,13 +1244,15 @@ where } } -impl VoteWeightProvider for Pallet { - fn vote_weight(who: &T::AccountId) -> VoteWeight { +impl ScoreProvider for Pallet { + type Score = VoteWeight; + + fn score(who: &T::AccountId) -> Self::Score { Self::weight_of(who) } #[cfg(feature = "runtime-benchmarks")] - fn set_vote_weight_of(who: &T::AccountId, weight: VoteWeight) { + fn set_score_of(who: &T::AccountId, weight: Self::Score) { // this will clearly results in an inconsistent state, but it should not matter for a // benchmark. let active: BalanceOf = weight.try_into().map_err(|_| ()).unwrap(); @@ -1279,6 +1281,7 @@ impl VoteWeightProvider for Pallet { pub struct UseNominatorsMap(sp_std::marker::PhantomData); impl SortedListProvider for UseNominatorsMap { type Error = (); + type Score = VoteWeight; /// Returns iterator over voter list, which can have `take` called on it. fn iter() -> Box> { @@ -1290,11 +1293,11 @@ impl SortedListProvider for UseNominatorsMap { fn contains(id: &T::AccountId) -> bool { Nominators::::contains_key(id) } - fn on_insert(_: T::AccountId, _weight: VoteWeight) -> Result<(), Self::Error> { + fn on_insert(_: T::AccountId, _weight: Self::Score) -> Result<(), Self::Error> { // nothing to do on insert. Ok(()) } - fn on_update(_: &T::AccountId, _weight: VoteWeight) { + fn on_update(_: &T::AccountId, _weight: Self::Score) { // nothing to do on update. } fn on_remove(_: &T::AccountId) { @@ -1302,7 +1305,7 @@ impl SortedListProvider for UseNominatorsMap { } fn unsafe_regenerate( _: impl IntoIterator, - _: Box VoteWeight>, + _: Box Self::Score>, ) -> u32 { // nothing to do upon regenerate. 0 diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 58f9fd237263b..b50ce5ed4502c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -166,7 +166,10 @@ pub mod pallet { /// Something that can provide a sorted list of voters in a somewhat sorted way. The /// original use case for this was designed with `pallet_bags_list::Pallet` in mind. If /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. - type SortedListProvider: SortedListProvider; + type SortedListProvider: SortedListProvider< + Self::AccountId, + Score = frame_election_provider_support::VoteWeight, + >; /// The maximum number of `unlocking` chunks a [`StakingLedger`] can have. Effectively /// determines how many unique eras a staker may be unbonding in. From 1321c6f0806def1e1ceee9e99a937d540eb25f21 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Thu, 10 Mar 2022 17:02:58 +0800 Subject: [PATCH 0586/1472] sc-finality-grandpa: use the #[from] attriute to remove boilerplate code (#11003) Signed-off-by: koushiro --- client/finality-grandpa/src/lib.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 8316e56b5b5e5..fef16286381ea 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -279,7 +279,7 @@ impl Config { pub enum Error { /// An error within grandpa. #[error("grandpa error: {0}")] - Grandpa(GrandpaError), + Grandpa(#[from] GrandpaError), /// A network error. #[error("network error: {0}")] @@ -291,7 +291,7 @@ pub enum Error { /// Could not complete a round on disk. #[error("could not complete a round on disk: {0}")] - Client(ClientError), + Client(#[from] ClientError), /// Could not sign outgoing message #[error("could not sign outgoing message: {0}")] @@ -310,18 +310,6 @@ pub enum Error { RuntimeApi(sp_api::ApiError), } -impl From for Error { - fn from(e: GrandpaError) -> Self { - Error::Grandpa(e) - } -} - -impl From for Error { - fn from(e: ClientError) -> Self { - Error::Client(e) - } -} - /// Something which can determine if a block is known. pub(crate) trait BlockStatus { /// Return `Ok(Some(number))` or `Ok(None)` depending on whether the block From 5afd5b8a4ee7bfb7d60d114b0968910f12748160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 10 Mar 2022 12:28:00 +0100 Subject: [PATCH 0587/1472] contracts: Add test to verify unique trie ids (#10914) * Add test to verify unique trie ids * Rename trie_seed to nonce * Rename AccountCounter -> Nonce * fmt --- frame/contracts/src/exec.rs | 67 +++++++++++++-------------- frame/contracts/src/lib.rs | 27 +++++++++-- frame/contracts/src/migration.rs | 24 ++++++++++ frame/contracts/src/storage.rs | 7 ++- frame/contracts/src/tests.rs | 77 ++++++++++++++++++++++++++++---- frame/contracts/src/weights.rs | 16 +++---- 6 files changed, 162 insertions(+), 56 deletions(-) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index eb7a68d81ad50..455665687d973 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -18,7 +18,7 @@ use crate::{ gas::GasMeter, storage::{self, Storage, WriteOutcome}, - AccountCounter, BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Error, Event, + BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Error, Event, Nonce, Pallet as Contracts, Schedule, }; use frame_support::{ @@ -315,9 +315,10 @@ pub struct Stack<'a, T: Config, E> { timestamp: MomentOf, /// The block number at the time of call stack instantiation. block_number: T::BlockNumber, - /// The account counter is cached here when accessed. It is written back when the call stack - /// finishes executing. - account_counter: Option, + /// The nonce is cached here when accessed. It is written back when the call stack + /// finishes executing. Please refer to [`Nonce`] to a description of + /// the nonce itself. + nonce: Option, /// The actual call stack. One entry per nested contract called/instantiated. /// This does **not** include the [`Self::first_frame`]. frames: SmallVec, @@ -385,8 +386,8 @@ enum FrameArgs<'a, T: Config, E> { Instantiate { /// The contract or signed origin which instantiates the new contract. sender: T::AccountId, - /// The seed that should be used to derive a new trie id for the contract. - trie_seed: u64, + /// The nonce that should be used to derive a new trie id for the contract. + nonce: u64, /// The executable whose `deploy` function is run. executable: E, /// A salt used in the contract address deriviation of the new contract. @@ -571,7 +572,7 @@ where let (mut stack, executable) = Self::new( FrameArgs::Instantiate { sender: origin.clone(), - trie_seed: Self::initial_trie_seed(), + nonce: Self::initial_nonce(), executable, salt, }, @@ -596,7 +597,7 @@ where value: BalanceOf, debug_message: Option<&'a mut Vec>, ) -> Result<(Self, E), ExecError> { - let (first_frame, executable, account_counter) = + let (first_frame, executable, nonce) = Self::new_frame(args, value, gas_meter, storage_meter, 0, &schedule)?; let stack = Self { origin, @@ -605,7 +606,7 @@ where storage_meter, timestamp: T::Time::now(), block_number: >::block_number(), - account_counter, + nonce, first_frame, frames: Default::default(), debug_message, @@ -627,7 +628,7 @@ where gas_limit: Weight, schedule: &Schedule, ) -> Result<(Frame, E, Option), ExecError> { - let (account_id, contract_info, executable, delegate_caller, entry_point, account_counter) = + let (account_id, contract_info, executable, delegate_caller, entry_point, nonce) = match frame_args { FrameArgs::Call { dest, cached_info, delegated_call } => { let contract = if let Some(contract) = cached_info { @@ -645,10 +646,10 @@ where (dest, contract, executable, delegate_caller, ExportedFunction::Call, None) }, - FrameArgs::Instantiate { sender, trie_seed, executable, salt } => { + FrameArgs::Instantiate { sender, nonce, executable, salt } => { let account_id = >::contract_address(&sender, executable.code_hash(), &salt); - let trie_id = Storage::::generate_trie_id(&account_id, trie_seed); + let trie_id = Storage::::generate_trie_id(&account_id, nonce); let contract = Storage::::new_contract( &account_id, trie_id, @@ -660,7 +661,7 @@ where executable, None, ExportedFunction::Constructor, - Some(trie_seed), + Some(nonce), ) }, }; @@ -676,7 +677,7 @@ where allows_reentry: true, }; - Ok((frame, executable, account_counter)) + Ok((frame, executable, nonce)) } /// Create a subsequent nested frame. @@ -782,9 +783,9 @@ where /// This is called after running the current frame. It commits cached values to storage /// and invalidates all stale references to it that might exist further down the call stack. fn pop_frame(&mut self, persist: bool) { - // Revert the account counter in case of a failed instantiation. + // Revert changes to the nonce in case of a failed instantiation. if !persist && self.top_frame().entry_point == ExportedFunction::Constructor { - self.account_counter.as_mut().map(|c| *c = c.wrapping_sub(1)); + self.nonce.as_mut().map(|c| *c = c.wrapping_sub(1)); } // Pop the current frame from the stack and return it in case it needs to interact @@ -861,8 +862,8 @@ where if let Some(contract) = contract { >::insert(&self.first_frame.account_id, contract); } - if let Some(counter) = self.account_counter { - >::set(counter); + if let Some(nonce) = self.nonce { + >::set(nonce); } } } @@ -920,20 +921,20 @@ where !self.frames().any(|f| &f.account_id == id && !f.allows_reentry) } - /// Increments the cached account id and returns the value to be used for the trie_id. - fn next_trie_seed(&mut self) -> u64 { - let next = if let Some(current) = self.account_counter { + /// Increments and returns the next nonce. Pulls it from storage if it isn't in cache. + fn next_nonce(&mut self) -> u64 { + let next = if let Some(current) = self.nonce { current.wrapping_add(1) } else { - Self::initial_trie_seed() + Self::initial_nonce() }; - self.account_counter = Some(next); + self.nonce = Some(next); next } - /// The account seed to be used to instantiate the account counter cache. - fn initial_trie_seed() -> u64 { - >::get().wrapping_add(1) + /// Pull the current nonce from storage. + fn initial_nonce() -> u64 { + >::get().wrapping_add(1) } } @@ -1020,11 +1021,11 @@ where salt: &[u8], ) -> Result<(AccountIdOf, ExecReturnValue), ExecError> { let executable = E::from_storage(code_hash, &self.schedule, self.gas_meter())?; - let trie_seed = self.next_trie_seed(); + let nonce = self.next_nonce(); let executable = self.push_frame( FrameArgs::Instantiate { sender: self.top_frame().account_id.clone(), - trie_seed, + nonce, executable, salt, }, @@ -2445,7 +2446,7 @@ mod tests { } #[test] - fn account_counter() { + fn nonce() { let fail_code = MockLoader::insert(Constructor, |_, _| exec_trapped()); let success_code = MockLoader::insert(Constructor, |_, _| exec_success()); let succ_fail_code = MockLoader::insert(Constructor, move |ctx, _| { @@ -2495,7 +2496,7 @@ mod tests { None, ) .ok(); - assert_eq!(>::get(), 0); + assert_eq!(>::get(), 0); assert_ok!(MockStack::run_instantiate( ALICE, @@ -2508,7 +2509,7 @@ mod tests { &[], None, )); - assert_eq!(>::get(), 1); + assert_eq!(>::get(), 1); assert_ok!(MockStack::run_instantiate( ALICE, @@ -2521,7 +2522,7 @@ mod tests { &[], None, )); - assert_eq!(>::get(), 2); + assert_eq!(>::get(), 2); assert_ok!(MockStack::run_instantiate( ALICE, @@ -2534,7 +2535,7 @@ mod tests { &[], None, )); - assert_eq!(>::get(), 4); + assert_eq!(>::get(), 4); }); } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 037e3f1d33ae3..4edf43a672152 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -134,7 +134,7 @@ type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; /// The current storage version. -const STORAGE_VERSION: StorageVersion = StorageVersion::new(6); +const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); /// Used as a sentinel value when reading and writing contract memory. /// @@ -665,9 +665,30 @@ pub mod pallet { #[pallet::storage] pub(crate) type OwnerInfoOf = StorageMap<_, Identity, CodeHash, OwnerInfo>; - /// The subtrie counter. + /// This is a **monotonic** counter incremented on contract instantiation. + /// + /// This is used in order to generate unique trie ids for contracts. + /// The trie id of a new contract is calculated from hash(account_id, nonce). + /// The nonce is required because otherwise the following sequence would lead to + /// a possible collision of storage: + /// + /// 1. Create a new contract. + /// 2. Terminate the contract. + /// 3. Immediately recreate the contract with the same account_id. + /// + /// This is bad because the contents of a trie are deleted lazily and there might be + /// storage of the old instantiation still in it when the new contract is created. Please + /// note that we can't replace the counter by the block number because the sequence above + /// can happen in the same block. We also can't keep the account counter in memory only + /// because storage is the only way to communicate across different extrinsics in the + /// same block. + /// + /// # Note + /// + /// Do not use it to determine the number of contracts. It won't be decremented if + /// a contract is destroyed. #[pallet::storage] - pub(crate) type AccountCounter = StorageValue<_, u64, ValueQuery>; + pub(crate) type Nonce = StorageValue<_, u64, ValueQuery>; /// The code associated with a given account. /// diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 59d3721ab13cf..035e3b4409cf9 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -19,6 +19,7 @@ use crate::{BalanceOf, CodeHash, Config, Pallet, TrieId, Weight}; use codec::{Decode, Encode}; use frame_support::{ codec, generate_storage_alias, + pallet_prelude::*, storage::migration, traits::{Get, PalletInfoAccess}, Identity, Twox64Concat, @@ -47,6 +48,11 @@ pub fn migrate() -> Weight { StorageVersion::new(6).put::>(); } + if version < 7 { + weight = weight.saturating_add(v7::migrate::()); + StorageVersion::new(7).put::>(); + } + weight } @@ -249,3 +255,21 @@ mod v6 { weight } } + +/// Rename `AccountCounter` to `Nonce`. +mod v7 { + use super::*; + + pub fn migrate() -> Weight { + generate_storage_alias!( + Contracts, + AccountCounter => Value + ); + generate_storage_alias!( + Contracts, + Nonce => Value + ); + Nonce::set(AccountCounter::take()); + T::DbWeight::get().reads_writes(1, 2) + } +} diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 51a43a1782425..17022e9427664 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -290,10 +290,9 @@ where weight_limit.saturating_sub(weight_per_key.saturating_mul(remaining_key_budget as Weight)) } - /// This generator uses inner counter for account id and applies the hash over `AccountId + - /// accountid_counter`. - pub fn generate_trie_id(account_id: &AccountIdOf, seed: u64) -> TrieId { - let buf: Vec<_> = account_id.as_ref().iter().chain(&seed.to_le_bytes()).cloned().collect(); + /// Generates a unique trie id by returning `hash(account_id ++ nonce)`. + pub fn generate_trie_id(account_id: &AccountIdOf, nonce: u64) -> TrieId { + let buf: Vec<_> = account_id.as_ref().iter().chain(&nonce.to_le_bytes()).cloned().collect(); T::Hashing::hash(&buf).as_ref().into() } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 8add424db0892..4c8c42c77da56 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -74,17 +74,15 @@ frame_support::construct_runtime!( #[macro_use] pub mod test_utils { use super::{Balances, Test}; - use crate::{ - exec::AccountIdOf, storage::Storage, AccountCounter, CodeHash, Config, ContractInfoOf, - }; + use crate::{exec::AccountIdOf, storage::Storage, CodeHash, Config, ContractInfoOf, Nonce}; use frame_support::traits::Currency; pub fn place_contract(address: &AccountIdOf, code_hash: CodeHash) { - let seed = >::mutate(|counter| { + let nonce = >::mutate(|counter| { *counter += 1; *counter }); - let trie_id = Storage::::generate_trie_id(address, seed); + let trie_id = Storage::::generate_trie_id(address, nonce); set_balance(address, ::Currency::minimum_balance() * 10); let contract = Storage::::new_contract(&address, trie_id, code_hash).unwrap(); >::insert(address, contract); @@ -349,6 +347,11 @@ where Ok((wasm_binary, code_hash)) } +fn initialize_block(number: u64) { + System::reset_events(); + System::initialize(&number, &[0u8; 32].into(), &Default::default()); +} + // Perform a call to a plain account. // The actual transfer fails because we can only call contracts. // Then we check that at least the base costs where charged (no runtime gas costs.) @@ -540,9 +543,67 @@ fn run_out_of_gas() { }); } -fn initialize_block(number: u64) { - System::reset_events(); - System::initialize(&number, &[0u8; 32].into(), &Default::default()); +/// Check that contracts with the same account id have different trie ids. +/// Check the `Nonce` storage item for more information. +#[test] +fn instantiate_unique_trie_id() { + let (wasm, code_hash) = compile_module::("self_destruct").unwrap(); + + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + Contracts::upload_code(Origin::signed(ALICE), wasm, None).unwrap(); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Instantiate the contract and store its trie id for later comparison. + assert_ok!(Contracts::instantiate( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + code_hash, + vec![], + vec![], + )); + let trie_id = ContractInfoOf::::get(&addr).unwrap().trie_id; + + // Try to instantiate it again without termination should yield an error. + assert_err_ignore_postinfo!( + Contracts::instantiate( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + code_hash, + vec![], + vec![], + ), + >::DuplicateContract, + ); + + // Terminate the contract. + assert_ok!(Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![] + )); + + // Re-Instantiate after termination. + assert_ok!(Contracts::instantiate( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + code_hash, + vec![], + vec![], + )); + + // Trie ids shouldn't match or we might have a collision + assert_ne!(trie_id, ContractInfoOf::::get(&addr).unwrap().trie_id); + }); } #[test] diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 7d73a3a1cecc7..b438ad51cbfca 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -201,7 +201,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) - // Storage: Contracts AccountCounter (r:1 w:1) + // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) @@ -217,7 +217,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) - // Storage: Contracts AccountCounter (r:1 w:1) + // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) @@ -651,7 +651,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: Contracts AccountCounter (r:1 w:1) + // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) @@ -666,7 +666,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) - // Storage: Contracts AccountCounter (r:1 w:1) + // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { (14_790_752_000 as Weight) @@ -1092,7 +1092,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) - // Storage: Contracts AccountCounter (r:1 w:1) + // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) @@ -1108,7 +1108,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) - // Storage: Contracts AccountCounter (r:1 w:1) + // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) @@ -1542,7 +1542,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: Contracts AccountCounter (r:1 w:1) + // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) @@ -1557,7 +1557,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:101 w:101) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) - // Storage: Contracts AccountCounter (r:1 w:1) + // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { (14_790_752_000 as Weight) From 3d9361d080c48368c2c56b2928374428580efceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 10 Mar 2022 19:26:42 +0100 Subject: [PATCH 0588/1472] sp-core: `full_crypto` doesn't imply `std` (#11006) * sp-core: `full_crypto` doesn't imply `std` This pr changes the feature set of `secp256k1` to not use `global-context` when only the `full_crypto` is enabled. It will be slower when the `std` feature is not enabled as the context always needs to be recreated, but that is fine. * Update client/cli/src/arg_enums.rs Co-authored-by: Davide Galassi Co-authored-by: Davide Galassi --- primitives/core/Cargo.toml | 3 ++- primitives/core/src/ecdsa.rs | 32 ++++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 1effb8efbf5ae..55d00362033d0 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -56,7 +56,7 @@ schnorrkel = { version = "0.9.1", features = [ hex = { version = "0.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } -secp256k1 = { version = "0.21.2", default-features = false, features = ["recovery", "global-context"], optional = true } +secp256k1 = { version = "0.21.2", default-features = false, features = ["recovery", "alloc"], optional = true } ss58-registry = { version = "1.11.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } @@ -108,6 +108,7 @@ std = [ "regex", "num-traits/std", "secp256k1/std", + "secp256k1/global-context", "sp-core-hashing/std", "sp-debug-derive/std", "sp-externalities", diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 9389a277736dd..7a4e4399913dc 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -34,12 +34,14 @@ use crate::{ }; #[cfg(feature = "std")] use bip39::{Language, Mnemonic, MnemonicType}; -#[cfg(feature = "full_crypto")] -use core::convert::TryFrom; +#[cfg(all(feature = "full_crypto", not(feature = "std")))] +use secp256k1::Secp256k1; +#[cfg(feature = "std")] +use secp256k1::SECP256K1; #[cfg(feature = "full_crypto")] use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, - Message, PublicKey, SecretKey, SECP256K1, + Message, PublicKey, SecretKey, }; #[cfg(feature = "std")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; @@ -334,7 +336,13 @@ impl Signature { let rid = RecoveryId::from_i32(self.0[64] as i32).ok()?; let sig = RecoverableSignature::from_compact(&self.0[..64], rid).ok()?; let message = Message::from_slice(message).expect("Message is 32 bytes; qed"); - SECP256K1 + + #[cfg(feature = "std")] + let context = SECP256K1; + #[cfg(not(feature = "std"))] + let context = Secp256k1::verification_only(); + + context .recover_ecdsa(&message, &sig) .ok() .map(|pubkey| Public(pubkey.serialize())) @@ -425,7 +433,13 @@ impl TraitPair for Pair { fn from_seed_slice(seed_slice: &[u8]) -> Result { let secret = SecretKey::from_slice(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?; - let public = PublicKey::from_secret_key(SECP256K1, &secret); + + #[cfg(feature = "std")] + let context = SECP256K1; + #[cfg(not(feature = "std"))] + let context = Secp256k1::signing_only(); + + let public = PublicKey::from_secret_key(&context, &secret); let public = Public(public.serialize()); Ok(Pair { public, secret }) } @@ -503,7 +517,13 @@ impl Pair { /// Sign a pre-hashed message pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature { let message = Message::from_slice(message).expect("Message is 32 bytes; qed"); - SECP256K1.sign_ecdsa_recoverable(&message, &self.secret).into() + + #[cfg(feature = "std")] + let context = SECP256K1; + #[cfg(not(feature = "std"))] + let context = Secp256k1::signing_only(); + + context.sign_ecdsa_recoverable(&message, &self.secret).into() } /// Verify a signature on a pre-hashed message. Return `true` if the signature is valid From f5f286db0da99761792b69bf4a997535dcc8f260 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 11 Mar 2022 02:35:11 +0800 Subject: [PATCH 0589/1472] Remove unused `parent_hash` in `OverlayedChanges::into_storage_changes` (#11011) Ref https://github.com/paritytech/substrate/pull/10922#issuecomment-1064258443 CC @cheme --- primitives/api/proc-macro/src/impl_runtime_apis.rs | 1 - primitives/state-machine/src/ext.rs | 8 +------- primitives/state-machine/src/overlayed_changes/mod.rs | 4 +--- primitives/state-machine/src/testing.rs | 1 - utils/frame/try-runtime/cli/src/commands/follow_chain.rs | 1 - 5 files changed, 2 insertions(+), 13 deletions(-) diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index ae18849d83ccc..dc89c9f592e57 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -301,7 +301,6 @@ fn generate_runtime_api_base_structures() -> Result { self.changes.replace(Default::default()).into_storage_changes( backend, - parent_hash, self.storage_transaction_cache.replace(Default::default()), state_version, ) diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index e87b22d4f9b76..7b7e4b47f19ba 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -660,7 +660,6 @@ where self.overlay .drain_storage_changes( self.backend, - Default::default(), self.storage_transaction_cache, Default::default(), // using any state ) @@ -680,12 +679,7 @@ where } let changes = self .overlay - .drain_storage_changes( - self.backend, - Default::default(), - self.storage_transaction_cache, - state_version, - ) + .drain_storage_changes(self.backend, self.storage_transaction_cache, state_version) .expect(EXT_NOT_ALLOWED_TO_FAIL); self.backend .commit( diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index d75feec0ced9c..59f3e1cffa5f6 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -500,21 +500,19 @@ impl OverlayedChanges { pub fn into_storage_changes, H: Hasher>( mut self, backend: &B, - parent_hash: H::Out, mut cache: StorageTransactionCache, state_version: StateVersion, ) -> Result, DefaultError> where H::Out: Ord + Encode + 'static, { - self.drain_storage_changes(backend, parent_hash, &mut cache, state_version) + self.drain_storage_changes(backend, &mut cache, state_version) } /// Drain all changes into a [`StorageChanges`] instance. Leave empty overlay in place. pub fn drain_storage_changes, H: Hasher>( &mut self, backend: &B, - _parent_hash: H::Out, mut cache: &mut StorageTransactionCache, state_version: StateVersion, ) -> Result, DefaultError> diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index 7f71d24b761a9..bc462ae01ab26 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -179,7 +179,6 @@ where pub fn commit_all(&mut self) -> Result<(), String> { let changes = self.overlay.drain_storage_changes::<_, _>( &self.backend, - Default::default(), &mut Default::default(), self.state_version, )?; diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index 82bc04880106e..7400813b9175e 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -150,7 +150,6 @@ where let storage_changes = changes .drain_storage_changes( &state_ext.backend, - Default::default(), &mut Default::default(), // Note that in case a block contains a runtime upgrade, // state version could potentially be incorrect here, From 5cc2ef8e4c03b64691db367036fedd8f4d7f0326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 11 Mar 2022 23:20:18 +0100 Subject: [PATCH 0590/1472] sp-api: Don't be dirty (#11015) Ensure that the sp api macros don't use functions without providing the full path to the function. This hygiene ensures that we don't actually try to call a method of an imported trait for example. --- .../api/proc-macro/src/decl_runtime_apis.rs | 26 +++--- .../api/proc-macro/src/impl_runtime_apis.rs | 88 ++++++++++--------- 2 files changed, 59 insertions(+), 55 deletions(-) diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index bc72aaa81681b..2301f531590ee 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -378,21 +378,21 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result { #[cfg(any(feature = "std", test))] #[allow(clippy::too_many_arguments)] pub fn #fn_name< - R: #crate_::Encode + #crate_::Decode + PartialEq, + R: #crate_::Encode + #crate_::Decode + std::cmp::PartialEq, NC: FnOnce() -> std::result::Result + std::panic::UnwindSafe, Block: #crate_::BlockT, T: #crate_::CallApiAt, >( call_runtime_at: &T, at: &#crate_::BlockId, - args: Vec, + args: std::vec::Vec, changes: &std::cell::RefCell<#crate_::OverlayedChanges>, storage_transaction_cache: &std::cell::RefCell< #crate_::StorageTransactionCache >, - native_call: Option, + native_call: std::option::Option, context: #crate_::ExecutionContext, - recorder: &Option<#crate_::ProofRecorder>, + recorder: &std::option::Option<#crate_::ProofRecorder>, ) -> std::result::Result<#crate_::NativeOrEncoded, #crate_::ApiError> { let version = call_runtime_at.runtime_version_at(at)?; @@ -412,7 +412,7 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result { recorder, }; - let ret = call_runtime_at.call_api_at(params)?; + let ret = #crate_::CallApiAt::::call_api_at(call_runtime_at, params)?; return Ok(ret) } @@ -429,7 +429,7 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result { recorder, }; - call_runtime_at.call_api_at(params) + #crate_::CallApiAt::::call_api_at(call_runtime_at, params) } )); } @@ -677,13 +677,13 @@ impl<'a> ToClientSideDecl<'a> { #native_handling }, #crate_::NativeOrEncoded::Encoded(r) => { - <#ret_type as #crate_::Decode>::decode(&mut &r[..]) - .map_err(|err| - #crate_::ApiError::FailedToDecodeReturnValue { - function: #function_name, - error: err, - } - ) + std::result::Result::map_err( + <#ret_type as #crate_::Decode>::decode(&mut &r[..]), + |err| #crate_::ApiError::FailedToDecodeReturnValue { + function: #function_name, + error: err, + } + ) } } ) diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index dc89c9f592e57..f594a743fcf94 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -207,7 +207,7 @@ fn generate_runtime_api_base_structures() -> Result { storage_transaction_cache: std::cell::RefCell< #crate_::StorageTransactionCache >, - recorder: Option<#crate_::ProofRecorder>, + recorder: std::option::Option<#crate_::ProofRecorder>, } // `RuntimeApi` itself is not threadsafe. However, an instance is only available in a @@ -233,12 +233,12 @@ fn generate_runtime_api_base_structures() -> Result { &self, call: F, ) -> R where Self: Sized { - self.changes.borrow_mut().start_transaction(); - *self.commit_on_success.borrow_mut() = false; + #crate_::OverlayedChanges::start_transaction(&mut std::cell::RefCell::borrow_mut(&self.changes)); + *std::cell::RefCell::borrow_mut(&self.commit_on_success) = false; let res = call(self); - *self.commit_on_success.borrow_mut() = true; + *std::cell::RefCell::borrow_mut(&self.commit_on_success) = true; - self.commit_or_rollback(matches!(res, #crate_::TransactionOutcome::Commit(_))); + self.commit_or_rollback(std::matches!(res, #crate_::TransactionOutcome::Commit(_))); res.into_inner() } @@ -247,9 +247,8 @@ fn generate_runtime_api_base_structures() -> Result { &self, at: &#crate_::BlockId, ) -> std::result::Result where Self: Sized { - self.call - .runtime_version_at(at) - .map(|v| v.has_api_with(&A::ID, |v| v == A::VERSION)) + #crate_::CallApiAt::::runtime_version_at(self.call, at) + .map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, |v| v == A::VERSION)) } fn has_api_with bool>( @@ -257,51 +256,48 @@ fn generate_runtime_api_base_structures() -> Result { at: &#crate_::BlockId, pred: P, ) -> std::result::Result where Self: Sized { - self.call - .runtime_version_at(at) - .map(|v| v.has_api_with(&A::ID, pred)) + #crate_::CallApiAt::::runtime_version_at(self.call, at) + .map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, pred)) } fn api_version( &self, at: &#crate_::BlockId, ) -> std::result::Result, #crate_::ApiError> where Self: Sized { - self.call - .runtime_version_at(at) - .map(|v| v.api_version(&A::ID)) + #crate_::CallApiAt::::runtime_version_at(self.call, at) + .map(|v| #crate_::RuntimeVersion::api_version(&v, &A::ID)) } fn record_proof(&mut self) { - self.recorder = Some(Default::default()); + self.recorder = std::option::Option::Some(std::default::Default::default()); } - fn proof_recorder(&self) -> Option<#crate_::ProofRecorder> { - self.recorder.clone() + fn proof_recorder(&self) -> std::option::Option<#crate_::ProofRecorder> { + std::clone::Clone::clone(&self.recorder) } - fn extract_proof(&mut self) -> Option<#crate_::StorageProof> { - self.recorder - .take() - .map(|recorder| recorder.to_storage_proof()) + fn extract_proof(&mut self) -> std::option::Option<#crate_::StorageProof> { + std::option::Option::take(&mut self.recorder) + .map(|recorder| #crate_::ProofRecorder::::to_storage_proof(&recorder)) } fn into_storage_changes( &self, backend: &Self::StateBackend, parent_hash: Block::Hash, - ) -> std::result::Result< + ) -> core::result::Result< #crate_::StorageChanges, String > where Self: Sized { - let at = #crate_::BlockId::Hash(parent_hash.clone()); - let state_version = self.call - .runtime_version_at(&at) - .map(|v| v.state_version()) + let at = #crate_::BlockId::Hash(std::clone::Clone::clone(&parent_hash)); + let state_version = #crate_::CallApiAt::::runtime_version_at(self.call, &at) + .map(|v| #crate_::RuntimeVersion::state_version(&v)) .map_err(|e| format!("Failed to get state version: {}", e))?; - self.changes.replace(Default::default()).into_storage_changes( + #crate_::OverlayedChanges::into_storage_changes( + std::cell::RefCell::take(&self.changes), backend, - self.storage_transaction_cache.replace(Default::default()), + core::cell::RefCell::take(&self.storage_transaction_cache), state_version, ) } @@ -321,9 +317,9 @@ fn generate_runtime_api_base_structures() -> Result { RuntimeApiImpl { call: unsafe { std::mem::transmute(call) }, commit_on_success: true.into(), - changes: Default::default(), - recorder: Default::default(), - storage_transaction_cache: Default::default(), + changes: std::default::Default::default(), + recorder: std::default::Default::default(), + storage_transaction_cache: std::default::Default::default(), }.into() } } @@ -331,20 +327,22 @@ fn generate_runtime_api_base_structures() -> Result { #[cfg(any(feature = "std", test))] impl> RuntimeApiImpl { fn call_api_at< - R: #crate_::Encode + #crate_::Decode + PartialEq, + R: #crate_::Encode + #crate_::Decode + std::cmp::PartialEq, F: FnOnce( &C, &std::cell::RefCell<#crate_::OverlayedChanges>, &std::cell::RefCell<#crate_::StorageTransactionCache>, - &Option<#crate_::ProofRecorder>, + &std::option::Option<#crate_::ProofRecorder>, ) -> std::result::Result<#crate_::NativeOrEncoded, E>, E, >( &self, call_api_at: F, ) -> std::result::Result<#crate_::NativeOrEncoded, E> { - if *self.commit_on_success.borrow() { - self.changes.borrow_mut().start_transaction(); + if *std::cell::RefCell::borrow(&self.commit_on_success) { + #crate_::OverlayedChanges::start_transaction( + &mut std::cell::RefCell::borrow_mut(&self.changes) + ); } let res = call_api_at( &self.call, @@ -353,7 +351,7 @@ fn generate_runtime_api_base_structures() -> Result { &self.recorder, ); - self.commit_or_rollback(res.is_ok()); + self.commit_or_rollback(std::result::Result::is_ok(&res)); res } @@ -362,13 +360,19 @@ fn generate_runtime_api_base_structures() -> Result { We only close a transaction when we opened one ourself. Other parts of the runtime that make use of transactions (state-machine) also balance their transactions. The runtime cannot close client initiated - transactions. qed"; - if *self.commit_on_success.borrow() { - if commit { - self.changes.borrow_mut().commit_transaction().expect(proof); + transactions; qed"; + if *std::cell::RefCell::borrow(&self.commit_on_success) { + let res = if commit { + #crate_::OverlayedChanges::commit_transaction( + &mut std::cell::RefCell::borrow_mut(&self.changes) + ) } else { - self.changes.borrow_mut().rollback_transaction().expect(proof); - } + #crate_::OverlayedChanges::rollback_transaction( + &mut std::cell::RefCell::borrow_mut(&self.changes) + ) + }; + + std::result::Result::expect(res, proof); } } } From 89fcb3e4f62d221d4e161a437768e77d6265889e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 12 Mar 2022 15:31:37 +0100 Subject: [PATCH 0591/1472] Update clap to the latest version (#11017) * Update clap to the latest version Besides that it also removes some `structopt` leftovers from some docs. * Fix compile errors * More fixes --- Cargo.lock | 40 ++++++------ bin/node-template/node/Cargo.toml | 2 +- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 4 +- bin/node/cli/build.rs | 4 +- bin/node/inspect/Cargo.toml | 2 +- bin/utils/chain-spec-builder/Cargo.toml | 2 +- bin/utils/subkey/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/cli/src/arg_enums.rs | 8 +++ client/cli/src/lib.rs | 62 +++++++++---------- client/cli/src/params/import_params.rs | 9 +-- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/benchmarking-cli/src/lib.rs | 8 +-- utils/frame/frame-utilities-cli/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- utils/frame/try-runtime/cli/src/lib.rs | 16 ++--- 19 files changed, 87 insertions(+), 86 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db6edfa81d539..1ad59291eca27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -931,7 +931,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 3.0.7", + "clap 3.1.6", "node-cli", "rand 0.8.4", "sc-chain-spec", @@ -1006,9 +1006,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.0.7" +version = "3.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12e8611f9ae4e068fa3e56931fded356ff745e70987ff76924a6e0ab1c8ef2e3" +checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" dependencies = [ "atty", "bitflags", @@ -1018,7 +1018,7 @@ dependencies = [ "os_str_bytes", "strsim", "termcolor", - "textwrap 0.14.2", + "textwrap 0.15.0", ] [[package]] @@ -1027,14 +1027,14 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a394f7ec0715b42a4e52b294984c27c9a61f77c8d82f7774c5198350be143f19" dependencies = [ - "clap 3.0.7", + "clap 3.1.6", ] [[package]] name = "clap_derive" -version = "3.0.5" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a0645a430ec9136d2d701e54a95d557de12649a9dd7109ced3187e648ac824" +checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16" dependencies = [ "heck 0.4.0", "proc-macro-error", @@ -2126,7 +2126,7 @@ version = "4.0.0-dev" dependencies = [ "Inflector", "chrono", - "clap 3.0.7", + "clap 3.1.6", "frame-benchmarking", "frame-support", "handlebars", @@ -4751,7 +4751,7 @@ dependencies = [ name = "node-bench" version = "0.9.0-dev" dependencies = [ - "clap 3.0.7", + "clap 3.1.6", "derive_more", "fs_extra", "futures 0.3.19", @@ -4790,7 +4790,7 @@ version = "3.0.0-dev" dependencies = [ "assert_cmd", "async-std", - "clap 3.0.7", + "clap 3.1.6", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4904,7 +4904,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 3.0.7", + "clap 3.1.6", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -5050,7 +5050,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 3.0.7", + "clap 3.1.6", "generate-bags", "node-runtime", ] @@ -5059,7 +5059,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 3.0.7", + "clap 3.1.6", "frame-benchmarking", "frame-benchmarking-cli", "jsonrpc-core", @@ -8083,7 +8083,7 @@ name = "sc-cli" version = "0.10.0-dev" dependencies = [ "chrono", - "clap 3.0.7", + "clap 3.1.6", "fdlimit", "futures 0.3.19", "hex", @@ -10068,7 +10068,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 3.0.7", + "clap 3.1.6", "honggfuzz", "parity-scale-codec", "rand 0.8.4", @@ -10525,7 +10525,7 @@ dependencies = [ name = "subkey" version = "2.0.1" dependencies = [ - "clap 3.0.7", + "clap 3.1.6", "sc-cli", ] @@ -10553,7 +10553,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 3.0.7", + "clap 3.1.6", "frame-support", "frame-system", "sc-cli", @@ -10843,9 +10843,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.14.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" @@ -11367,7 +11367,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ - "clap 3.0.7", + "clap 3.1.6", "jsonrpsee 0.4.1", "log 0.4.14", "parity-scale-codec", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 98e8af96d3f8d..4549a5b613da2 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] name = "node-template" [dependencies] -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } sp-core = { version = "6.0.0", path = "../../../primitives/core" } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 2c5dea2cc28a6..5b728258dd03b 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -9,7 +9,7 @@ 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] -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } log = "0.4.8" node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index b4a91712fd16c..24e069d21f694 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -34,7 +34,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies -clap = { version = "3.0", features = ["derive"], optional = true } +clap = { version = "3.1.6", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } futures = "0.3.19" @@ -133,7 +133,7 @@ remote-externalities = { path = "../../../utils/frame/remote-externalities" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } [build-dependencies] -clap = { version = "3.0", optional = true } +clap = { version = "3.1.6", optional = true } clap_complete = { version = "3.0", optional = true } node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } frame-benchmarking-cli = { version = "4.0.0-dev", optional = true, path = "../../../utils/frame/benchmarking-cli" } diff --git a/bin/node/cli/build.rs b/bin/node/cli/build.rs index 6a010d8858fe5..6a3d13dda6a00 100644 --- a/bin/node/cli/build.rs +++ b/bin/node/cli/build.rs @@ -25,7 +25,7 @@ fn main() { mod cli { include!("src/cli.rs"); - use clap::{ArgEnum, IntoApp}; + use clap::{ArgEnum, CommandFactory}; use clap_complete::{generate_to, Shell}; use std::{env, fs, path::Path}; use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; @@ -61,6 +61,6 @@ mod cli { fs::create_dir(&path).ok(); - let _ = generate_to(*shell, &mut Cli::into_app(), "substrate-node", &path); + let _ = generate_to(*shell, &mut Cli::command(), "substrate-node", &path); } } diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index 5e7ed16efdcf4..c41681d11be1e 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } thiserror = "1.0" sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index 9537317198483..1ea1c402151dd 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } rand = "0.8" sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } diff --git a/bin/utils/subkey/Cargo.toml b/bin/utils/subkey/Cargo.toml index 85f864cfbfc13..c8132fe7b5b4b 100644 --- a/bin/utils/subkey/Cargo.toml +++ b/bin/utils/subkey/Cargo.toml @@ -17,5 +17,5 @@ path = "src/main.rs" name = "subkey" [dependencies] -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 813215321dfc0..8fdb192b43fb6 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = "0.4.10" -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } fdlimit = "0.2.1" futures = "0.3.19" hex = "0.4.2" diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index 6b0a029dd4fe5..df4b68ff5c325 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -86,6 +86,14 @@ impl Into for WasmExecutionMethod { } } +/// The default [`WasmExecutionMethod`]. +#[cfg(feature = "wasmtime")] +pub const DEFAULT_WASM_EXECUTION_METHOD: &str = "Compiled"; + +/// The default [`WasmExecutionMethod`]. +#[cfg(not(feature = "wasmtime"))] +pub const DEFAULT_WASM_EXECUTION_METHOD: &str = "interpreted-i-know-what-i-do"; + #[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] #[clap(rename_all = "PascalCase")] diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index c242050dbf32a..c920c6cd52cff 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -22,6 +22,9 @@ #![warn(unused_extern_crates)] #![warn(unused_imports)] +use clap::{CommandFactory, FromArgMatches, Parser}; +use sc_service::Configuration; + pub mod arg_enums; mod commands; mod config; @@ -31,33 +34,31 @@ mod runner; pub use arg_enums::*; pub use clap; -use clap::{AppSettings, FromArgMatches, IntoApp, Parser}; pub use commands::*; pub use config::*; pub use error::*; pub use params::*; pub use runner::*; -use sc_service::Configuration; pub use sc_service::{ChainSpec, Role}; pub use sc_tracing::logging::LoggerBuilder; pub use sp_version::RuntimeVersion; /// Substrate client CLI /// -/// This trait needs to be defined on the root structopt of the application. It will provide the -/// implementation name, version, executable name, description, author, support_url, copyright start -/// year and most importantly: how to load the chain spec. -/// -/// StructOpt must not be in scope to use from_args (or the similar methods). This trait provides -/// its own implementation that will fill the necessary field based on the trait's functions. +/// This trait needs to be implemented on the root CLI struct of the application. It will provide +/// the implementation `name`, `version`, `executable name`, `description`, `author`, `support_url`, +/// `copyright start year` and most importantly: how to load the chain spec. pub trait SubstrateCli: Sized { /// Implementation name. fn impl_name() -> String; /// Implementation version. /// - /// By default this will look like this: 2.0.0-b950f731c-x86_64-linux-gnu where the hash is the - /// short commit hash of the commit of in the Git repository. + /// By default this will look like this: + /// + /// `2.0.0-b950f731c-x86_64-linux-gnu` + /// + /// Where the hash is the short commit hash of the commit of in the Git repository. fn impl_version() -> String; /// Executable file name. @@ -88,14 +89,13 @@ pub trait SubstrateCli: Sized { fn load_spec(&self, id: &str) -> std::result::Result, String>; /// Helper function used to parse the command line arguments. This is the equivalent of - /// `structopt`'s `from_iter()` except that it takes a `VersionInfo` argument to provide the - /// name of the application, author, "about" and version. It will also set - /// `AppSettings::GlobalVersion`. + /// [`clap::Parser::parse()`]. /// - /// To allow running the node without subcommand, tt also sets a few more settings: - /// `AppSettings::ArgsNegateSubcommands` and `AppSettings::SubcommandsNegateReqs`. + /// To allow running the node without subcommand, it also sets a few more settings: + /// [`clap::Command::propagate_version`], [`clap::Command::args_conflicts_with_subcommands`], + /// [`clap::Command::subcommand_negates_reqs`]. /// - /// Gets the struct from the command line arguments. Print the + /// Creates `Self` from the command line arguments. Print the /// error message and quit the program in case of failure. fn from_args() -> Self where @@ -105,14 +105,13 @@ pub trait SubstrateCli: Sized { } /// Helper function used to parse the command line arguments. This is the equivalent of - /// `structopt`'s `from_iter()` except that it takes a `VersionInfo` argument to provide the - /// name of the application, author, "about" and version. It will also set - /// `AppSettings::GlobalVersion`. + /// [`clap::Parser::parse_from`]. /// /// To allow running the node without subcommand, it also sets a few more settings: - /// `AppSettings::ArgsNegateSubcommands` and `AppSettings::SubcommandsNegateReqs`. + /// [`clap::Command::propagate_version`], [`clap::Command::args_conflicts_with_subcommands`], + /// [`clap::Command::subcommand_negates_reqs`]. /// - /// Gets the struct from any iterator such as a `Vec` of your making. + /// Creates `Self` from any iterator over arguments. /// Print the error message and quit the program in case of failure. fn from_iter(iter: I) -> Self where @@ -120,7 +119,7 @@ pub trait SubstrateCli: Sized { I: IntoIterator, I::Item: Into + Clone, { - let app = ::into_app(); + let app = ::command(); let mut full_version = Self::impl_version(); full_version.push_str("\n"); @@ -133,11 +132,9 @@ pub trait SubstrateCli: Sized { .author(author.as_str()) .about(about.as_str()) .version(full_version.as_str()) - .setting( - AppSettings::PropagateVersion | - AppSettings::ArgsNegateSubcommands | - AppSettings::SubcommandsNegateReqs, - ); + .propagate_version(true) + .args_conflicts_with_subcommands(true) + .subcommand_negates_reqs(true); let matches = app.try_get_matches_from(iter).unwrap_or_else(|e| e.exit()); @@ -145,14 +142,13 @@ pub trait SubstrateCli: Sized { } /// Helper function used to parse the command line arguments. This is the equivalent of - /// `structopt`'s `from_iter()` except that it takes a `VersionInfo` argument to provide the - /// name of the application, author, "about" and version. It will also set - /// `AppSettings::GlobalVersion`. + /// [`clap::Parser::try_parse_from`] /// /// To allow running the node without subcommand, it also sets a few more settings: - /// `AppSettings::ArgsNegateSubcommands` and `AppSettings::SubcommandsNegateReqs`. + /// [`clap::Command::propagate_version`], [`clap::Command::args_conflicts_with_subcommands`], + /// [`clap::Command::subcommand_negates_reqs`]. /// - /// Gets the struct from any iterator such as a `Vec` of your making. + /// Creates `Self` from any iterator over arguments. /// Print the error message and quit the program in case of failure. /// /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are @@ -165,7 +161,7 @@ pub trait SubstrateCli: Sized { I: IntoIterator, I::Item: Into + Clone, { - let app = ::into_app(); + let app = ::command(); let mut full_version = Self::impl_version(); full_version.push_str("\n"); diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index 1ec79800136d3..1df11cff8d79f 100644 --- a/client/cli/src/params/import_params.rs +++ b/client/cli/src/params/import_params.rs @@ -21,6 +21,7 @@ use crate::{ ExecutionStrategy, WasmExecutionMethod, DEFAULT_EXECUTION_BLOCK_CONSTRUCTION, DEFAULT_EXECUTION_IMPORT_BLOCK, DEFAULT_EXECUTION_IMPORT_BLOCK_VALIDATOR, DEFAULT_EXECUTION_OFFCHAIN_WORKER, DEFAULT_EXECUTION_OTHER, DEFAULT_EXECUTION_SYNCING, + DEFAULT_WASM_EXECUTION_METHOD, }, params::{DatabaseParams, PruningParams}, }; @@ -28,12 +29,6 @@ use clap::Args; use sc_client_api::execution_extensions::ExecutionStrategies; use std::path::PathBuf; -#[cfg(feature = "wasmtime")] -const WASM_METHOD_DEFAULT: &str = "Compiled"; - -#[cfg(not(feature = "wasmtime"))] -const WASM_METHOD_DEFAULT: &str = "interpreted-i-know-what-i-do"; - /// Parameters for block import. #[derive(Debug, Clone, Args)] pub struct ImportParams { @@ -59,7 +54,7 @@ pub struct ImportParams { value_name = "METHOD", possible_values = WasmExecutionMethod::variants(), ignore_case = true, - default_value = WASM_METHOD_DEFAULT + default_value = DEFAULT_WASM_EXECUTION_METHOD, )] pub wasm_method: WasmExecutionMethod, diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index afa331b0676e0..2f2bae2dd44d4 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -14,7 +14,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 20122c4279366..81e7396db3e68 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -33,7 +33,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../../primiti sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } codec = { version = "3.0.0", package = "parity-scale-codec" } -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } chrono = "0.4" serde = "1.0.136" serde_json = "1.0.74" diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 56aab0321ccd0..640b1770f5c3f 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -19,7 +19,7 @@ mod command; mod storage; mod writer; -use sc_cli::{ExecutionStrategy, WasmExecutionMethod}; +use sc_cli::{ExecutionStrategy, WasmExecutionMethod, DEFAULT_WASM_EXECUTION_METHOD}; use std::{fmt::Debug, path::PathBuf}; pub use storage::StorageCmd; @@ -46,11 +46,11 @@ pub struct BenchmarkCmd { pub steps: u32, /// Indicates lowest values for each of the component ranges. - #[clap(long = "low", use_delimiter = true)] + #[clap(long = "low", use_value_delimiter = true)] pub lowest_range_values: Vec, /// Indicates highest values for each of the component ranges. - #[clap(long = "high", use_delimiter = true)] + #[clap(long = "high", use_value_delimiter = true)] pub highest_range_values: Vec, /// Select how many repetitions of this benchmark should run from within the wasm. @@ -130,7 +130,7 @@ pub struct BenchmarkCmd { value_name = "METHOD", possible_values = WasmExecutionMethod::variants(), ignore_case = true, - default_value = "compiled" + default_value = DEFAULT_WASM_EXECUTION_METHOD, )] pub wasm_method: WasmExecutionMethod, diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index bc673105b78bf..43c8b31898959 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" [dependencies] -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml index 11dee7b8b68ec..d5c8cab7ba0d8 100644 --- a/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -14,4 +14,4 @@ node-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runtime" } generate-bags = { version = "4.0.0-dev", path = "../" } # third-party -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 04b6d336f7406..6f72bd3b9d7f2 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.6", features = ["derive"] } log = "0.4.8" parity-scale-codec = "3.0.0" serde = "1.0.136" diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 92721228c9291..2298fa5c042ee 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -270,7 +270,9 @@ use remote_externalities::{ Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, TestExternalities, }; use sc_chain_spec::ChainSpec; -use sc_cli::{CliConfiguration, ExecutionStrategy, WasmExecutionMethod}; +use sc_cli::{ + CliConfiguration, ExecutionStrategy, WasmExecutionMethod, DEFAULT_WASM_EXECUTION_METHOD, +}; use sc_executor::NativeElseWasmExecutor; use sc_service::{Configuration, NativeExecutionDispatch}; use sp_core::{ @@ -394,7 +396,7 @@ pub struct SharedParams { value_name = "METHOD", possible_values = WasmExecutionMethod::variants(), ignore_case = true, - default_value = "Compiled" + default_value = DEFAULT_WASM_EXECUTION_METHOD, )] pub wasm_method: WasmExecutionMethod, @@ -458,15 +460,15 @@ pub enum State { snapshot_path: Option, /// The pallets to scrape. If empty, entire chain state will be scraped. - #[clap(short, long, require_delimiter = true)] - pallets: Option>, + #[clap(short, long, multiple_values = true)] + pallets: Vec, /// Fetch the child-keys as well. /// - /// Default is `false`, if specific `pallets` are specified, true otherwise. In other + /// Default is `false`, if specific `--pallets` are specified, `true` otherwise. In other /// words, if you scrape the whole state the child tree data is included out of the box. /// Otherwise, it must be enabled explicitly using this flag. - #[clap(long, require_delimiter = true)] + #[clap(long)] child_tree: bool, }, } @@ -492,7 +494,7 @@ impl State { .mode(Mode::Online(OnlineConfig { transport: uri.to_owned().into(), state_snapshot: snapshot_path.as_ref().map(SnapshotConfig::new), - pallets: pallets.clone().unwrap_or_default(), + pallets: pallets.clone(), scrape_children: true, at, })) From b797b89a9633c387ebc2f283af83d9cd450f5f50 Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Mon, 14 Mar 2022 10:42:34 +0200 Subject: [PATCH 0592/1472] Move scripts used in CI to the new location (#11008) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move scripts used in CI to the new location - **./scripts/ci/** * Move github scripts * Move more files * Move ci scripts and fix dependencies * Update docs/node-template-release.md Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> * Remove Cargo.lock * Apply suggestions from code review Co-authored-by: Denis Pisarev * Make more paths uniform Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> Co-authored-by: Denis Pisarev --- .github/workflows/check-labels.yml | 2 +- .github/workflows/monthly-tag.yml | 2 +- .gitignore | 2 +- .gitlab-ci.yml | 52 +++++++++---------- docs/CODEOWNERS | 2 +- docs/node-template-release.md | 4 +- {.maintain => scripts/ci}/common/lib.sh | 0 {.maintain => scripts/ci}/deny.toml | 0 .../ci}/docker/subkey.Dockerfile | 2 +- .../ci}/docker/substrate.Dockerfile | 2 +- .../ci}/github/check_labels.sh | 0 .../ci/github}/generate_changelog.sh | 0 .../ci}/gitlab/check_runtime.sh | 0 .../ci}/gitlab/check_signed.sh | 0 .../ci/gitlab}/ensure-deps.sh | 0 .../ci}/gitlab/publish_draft_release.sh | 0 .../ci}/gitlab/skip_if_draft.sh | 0 .../alerting-rules/alerting-rule-tests.yaml | 0 .../alerting-rules/alerting-rules.yaml | 0 .../grafana-dashboards/README_dashboard.md | 0 .../substrate-networking.json | 0 .../substrate-service-tasks.json | 0 .../ci}/node-template-release.sh | 2 +- .../ci}/node-template-release/Cargo.toml | 0 .../ci}/node-template-release/src/main.rs | 0 25 files changed, 35 insertions(+), 35 deletions(-) rename {.maintain => scripts/ci}/common/lib.sh (100%) rename {.maintain => scripts/ci}/deny.toml (100%) rename {.maintain => scripts/ci}/docker/subkey.Dockerfile (93%) rename {.maintain => scripts/ci}/docker/substrate.Dockerfile (96%) rename {.maintain => scripts/ci}/github/check_labels.sh (100%) rename {.maintain/gitlab => scripts/ci/github}/generate_changelog.sh (100%) rename {.maintain => scripts/ci}/gitlab/check_runtime.sh (100%) rename {.maintain => scripts/ci}/gitlab/check_signed.sh (100%) rename {.maintain => scripts/ci/gitlab}/ensure-deps.sh (100%) rename {.maintain => scripts/ci}/gitlab/publish_draft_release.sh (100%) rename {.maintain => scripts/ci}/gitlab/skip_if_draft.sh (100%) rename {.maintain => scripts/ci}/monitoring/alerting-rules/alerting-rule-tests.yaml (100%) rename {.maintain => scripts/ci}/monitoring/alerting-rules/alerting-rules.yaml (100%) rename {.maintain => scripts/ci}/monitoring/grafana-dashboards/README_dashboard.md (100%) rename {.maintain => scripts/ci}/monitoring/grafana-dashboards/substrate-networking.json (100%) rename {.maintain => scripts/ci}/monitoring/grafana-dashboards/substrate-service-tasks.json (100%) rename {.maintain => scripts/ci}/node-template-release.sh (84%) rename {.maintain => scripts/ci}/node-template-release/Cargo.toml (100%) rename {.maintain => scripts/ci}/node-template-release/src/main.rs (100%) diff --git a/.github/workflows/check-labels.yml b/.github/workflows/check-labels.yml index 7180e7b509662..74fdd9b2d8188 100644 --- a/.github/workflows/check-labels.yml +++ b/.github/workflows/check-labels.yml @@ -14,7 +14,7 @@ jobs: ref: ${{ github.event.pull_request.head.ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} - name: Check labels - run: bash ${{ github.workspace }}/.maintain/github/check_labels.sh + run: bash ${{ github.workspace }}/scripts/ci/github/check_labels.sh env: GITHUB_PR: ${{ github.event.pull_request.number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/monthly-tag.yml b/.github/workflows/monthly-tag.yml index 8736a341cecf9..9fed865396013 100644 --- a/.github/workflows/monthly-tag.yml +++ b/.github/workflows/monthly-tag.yml @@ -29,7 +29,7 @@ jobs: echo "" >> Changelog.md echo "## Changes since last snapshot (${{ steps.tags.outputs.old }})" >> Changelog.md echo "" >> Changelog.md - ./.maintain/gitlab/generate_changelog.sh ${{ steps.tags.outputs.old }} >> Changelog.md + ./scripts/ci/github/generate_changelog.sh ${{ steps.tags.outputs.old }} >> Changelog.md - name: Release snapshot id: release-snapshot uses: actions/create-release@latest diff --git a/.gitignore b/.gitignore index f1103fdab93a5..5cd013e054e4f 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ rls*.log .cargo-remote.toml *.bin *.iml -.maintain/node-template-release/Cargo.lock +scripts/ci/node-template-release/Cargo.lock diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8dabbc288cd62..b6f9ff9486069 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,7 +18,7 @@ # script: # - echo "List of shell commands to run in your job" # - echo "You can also just specify a script here, like so:" -# - ./.maintain/gitlab/my_amazing_script.sh +# - ./scripts/ci/gitlab/my_amazing_script.sh stages: - check @@ -165,12 +165,12 @@ default: fi .cargo-check-benches-script: &cargo-check-benches-script - - mkdir -p artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA + - mkdir -p ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA - SKIP_WASM_BUILD=1 time cargo +nightly check --benches --all - 'cargo run --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json - | tee artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::native::sr25519::transfer_keep_alive::paritydb::small.json' + | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::native::sr25519::transfer_keep_alive::paritydb::small.json' - 'cargo run --release -p node-bench -- ::trie::read::small --json - | tee artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json' + | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json' - sccache -s .build-linux-substrate-script: &build-linux-substrate-script @@ -185,7 +185,7 @@ default: tee ./artifacts/substrate/VERSION; fi - sha256sum ./artifacts/substrate/substrate | tee ./artifacts/substrate/substrate.sha256 - - cp -r .maintain/docker/substrate.Dockerfile ./artifacts/substrate/ + - cp -r ./scripts/ci/docker/substrate.Dockerfile ./artifacts/substrate/ - sccache -s #### Vault secrets @@ -241,7 +241,7 @@ skip-if-draft: - echo "Commit message is ${CI_COMMIT_MESSAGE}" - echo "Ref is ${CI_COMMIT_REF_NAME}" - echo "pipeline source is ${CI_PIPELINE_SOURCE}" - - ./.maintain/gitlab/skip_if_draft.sh + - ./scripts/ci/gitlab/skip_if_draft.sh #### stage: check @@ -256,7 +256,7 @@ check-runtime: GITLAB_API: "https://gitlab.parity.io/api/v4" GITHUB_API_PROJECT: "parity%2Finfrastructure%2Fgithub-api" script: - - ./.maintain/gitlab/check_runtime.sh + - ./scripts/ci/gitlab/check_runtime.sh allow_failure: true check-signed-tag: @@ -267,7 +267,7 @@ check-signed-tag: - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 script: - - ./.maintain/gitlab/check_signed.sh + - ./scripts/ci/gitlab/check_signed.sh test-dependency-rules: stage: check @@ -276,7 +276,7 @@ test-dependency-rules: rules: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs script: - - .maintain/ensure-deps.sh + - ./scripts/ci/gitlab/ensure-deps.sh test-prometheus-alerting-rules: stage: check @@ -288,11 +288,11 @@ test-prometheus-alerting-rules: - if: $CI_COMMIT_BRANCH changes: - .gitlab-ci.yml - - .maintain/monitoring/**/* + - ./scripts/ci/monitoring/**/* script: - - promtool check rules .maintain/monitoring/alerting-rules/alerting-rules.yaml - - cat .maintain/monitoring/alerting-rules/alerting-rules.yaml | - promtool test rules .maintain/monitoring/alerting-rules/alerting-rule-tests.yaml + - promtool check rules ./scripts/ci/monitoring/alerting-rules/alerting-rules.yaml + - cat ./scripts/ci/monitoring/alerting-rules/alerting-rules.yaml | + promtool test rules ./scripts/ci/monitoring/alerting-rules/alerting-rule-tests.yaml #### stage: test @@ -301,10 +301,10 @@ cargo-deny: <<: *docker-env <<: *nightly-pipeline script: - - cargo deny check --hide-inclusion-graph -c .maintain/deny.toml + - cargo deny check --hide-inclusion-graph -c ./scripts/ci/deny.toml after_script: - echo "___The complete log is in the artifacts___" - - cargo deny check -c .maintain/deny.toml 2> deny.log + - cargo deny check -c ./scripts/ci/deny.toml 2> deny.log artifacts: name: $CI_COMMIT_SHORT_SHA expire_in: 3 days @@ -404,13 +404,13 @@ test-deterministic-wasm: # build runtime - cargo build --verbose --release -p node-runtime # make checksum - - sha256sum target/release/wbuild/node-runtime/target/wasm32-unknown-unknown/release/node_runtime.wasm > checksum.sha256 + - sha256sum ./target/release/wbuild/node-runtime/target/wasm32-unknown-unknown/release/node_runtime.wasm > checksum.sha256 # clean up – FIXME: can we reuse some of the artifacts? - cargo clean # build again - cargo build --verbose --release -p node-runtime # confirm checksum - - sha256sum -c checksum.sha256 + - sha256sum -c ./checksum.sha256 - sccache -s test-linux-stable: &test-linux @@ -426,8 +426,8 @@ test-linux-stable: &test-linux WASM_BUILD_NO_COLOR: 1 script: # this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests - - time cargo test --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml - - time cargo test -p frame-support-test --features=conditional-storage,no-metadata-docs --manifest-path frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec + - time cargo test --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml + - time cargo test -p frame-support-test --features=conditional-storage,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout - sccache -s @@ -443,7 +443,7 @@ test-frame-examples-compile-to-wasm: RUSTFLAGS: "-Cdebug-assertions=y" RUST_BACKTRACE: 1 script: - - cd frame/examples/offchain-worker/ + - cd ./frame/examples/offchain-worker/ - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features - cd ../basic - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features @@ -475,8 +475,8 @@ check-tracing: <<: *test-refs script: # with-tracing must be explicitly activated, we run a test to ensure this works as expected in both cases - - time cargo +nightly test --manifest-path primitives/tracing/Cargo.toml --no-default-features - - time cargo +nightly test --manifest-path primitives/tracing/Cargo.toml --no-default-features --features=with-tracing + - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features + - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing - sccache -s test-full-crypto-feature: @@ -568,7 +568,7 @@ build-linux-substrate: script: - *build-linux-substrate-script - printf '\n# building node-template\n\n' - - ./.maintain/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz + - ./scripts/ci/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz build-linux-subkey: &build-subkey stage: build @@ -590,7 +590,7 @@ build-linux-subkey: &build-subkey sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | tee ./artifacts/subkey/VERSION; - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 - - cp -r .maintain/docker/subkey.Dockerfile ./artifacts/subkey/ + - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ - sccache -s build-macos-subkey: @@ -784,7 +784,7 @@ publish-draft-release: - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 script: - - ./.maintain/gitlab/publish_draft_release.sh + - ./scripts/ci/gitlab/publish_draft_release.sh allow_failure: true #### stage: deploy @@ -807,4 +807,4 @@ deploy-prometheus-alerting-rules: - if: $CI_COMMIT_REF_NAME == "master" changes: - .gitlab-ci.yml - - .maintain/monitoring/**/* + - ./scripts/ci/monitoring/**/* diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 70009d311f1c6..0b9e6e7783058 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -19,7 +19,7 @@ # - The latest matching rule, if multiple, takes precedence. # CI -/.maintain/ @paritytech/ci +/scripts/ci/ @paritytech/ci /.github/ @paritytech/ci /.gitlab-ci.yml @paritytech/ci diff --git a/docs/node-template-release.md b/docs/node-template-release.md index 25834ae99f438..4f4977a9df03c 100644 --- a/docs/node-template-release.md +++ b/docs/node-template-release.md @@ -7,7 +7,7 @@ the existence of your current git commit ID in the remote repository. Assume you are in root directory of Substrate. Run: ```bash - cd .maintain/ + cd scripts/ci/ ./node-template-release.sh ``` @@ -50,7 +50,7 @@ commit in Substrate remote repository, such as: ``` P.S: This step can be automated if we update `node-template-release` package in - `.maintain/node-template-release`. + `scripts/ci/node-template-release`. 4. Once the three `Cargo.toml`s are updated, compile and confirm that the Node Template builds. Then commit the changes to a new branch in [Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template), and make a PR. diff --git a/.maintain/common/lib.sh b/scripts/ci/common/lib.sh similarity index 100% rename from .maintain/common/lib.sh rename to scripts/ci/common/lib.sh diff --git a/.maintain/deny.toml b/scripts/ci/deny.toml similarity index 100% rename from .maintain/deny.toml rename to scripts/ci/deny.toml diff --git a/.maintain/docker/subkey.Dockerfile b/scripts/ci/docker/subkey.Dockerfile similarity index 93% rename from .maintain/docker/subkey.Dockerfile rename to scripts/ci/docker/subkey.Dockerfile index 5797295806d00..3483502845cf5 100644 --- a/.maintain/docker/subkey.Dockerfile +++ b/scripts/ci/docker/subkey.Dockerfile @@ -8,7 +8,7 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="parity/subkey" \ io.parity.image.description="Subkey: key generating utility for Substrate." \ - io.parity.image.source="https://github.com/paritytech/substrate/blob/${VCS_REF}/.maintain/docker/subkey.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/substrate/blob/${VCS_REF}/scripts/ci/docker/subkey.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ io.parity.image.documentation="https://github.com/paritytech/substrate/tree/${VCS_REF}/subkey" diff --git a/.maintain/docker/substrate.Dockerfile b/scripts/ci/docker/substrate.Dockerfile similarity index 96% rename from .maintain/docker/substrate.Dockerfile rename to scripts/ci/docker/substrate.Dockerfile index e13dfb426adfd..b4c103ed5244b 100644 --- a/.maintain/docker/substrate.Dockerfile +++ b/scripts/ci/docker/substrate.Dockerfile @@ -8,7 +8,7 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="parity/substrate" \ io.parity.image.description="Substrate: The platform for blockchain innovators." \ - io.parity.image.source="https://github.com/paritytech/substrate/blob/${VCS_REF}/.maintain/docker/Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/substrate/blob/${VCS_REF}/scripts/ci/docker/Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ io.parity.image.documentation="https://wiki.parity.io/Parity-Substrate" diff --git a/.maintain/github/check_labels.sh b/scripts/ci/github/check_labels.sh similarity index 100% rename from .maintain/github/check_labels.sh rename to scripts/ci/github/check_labels.sh diff --git a/.maintain/gitlab/generate_changelog.sh b/scripts/ci/github/generate_changelog.sh similarity index 100% rename from .maintain/gitlab/generate_changelog.sh rename to scripts/ci/github/generate_changelog.sh diff --git a/.maintain/gitlab/check_runtime.sh b/scripts/ci/gitlab/check_runtime.sh similarity index 100% rename from .maintain/gitlab/check_runtime.sh rename to scripts/ci/gitlab/check_runtime.sh diff --git a/.maintain/gitlab/check_signed.sh b/scripts/ci/gitlab/check_signed.sh similarity index 100% rename from .maintain/gitlab/check_signed.sh rename to scripts/ci/gitlab/check_signed.sh diff --git a/.maintain/ensure-deps.sh b/scripts/ci/gitlab/ensure-deps.sh similarity index 100% rename from .maintain/ensure-deps.sh rename to scripts/ci/gitlab/ensure-deps.sh diff --git a/.maintain/gitlab/publish_draft_release.sh b/scripts/ci/gitlab/publish_draft_release.sh similarity index 100% rename from .maintain/gitlab/publish_draft_release.sh rename to scripts/ci/gitlab/publish_draft_release.sh diff --git a/.maintain/gitlab/skip_if_draft.sh b/scripts/ci/gitlab/skip_if_draft.sh similarity index 100% rename from .maintain/gitlab/skip_if_draft.sh rename to scripts/ci/gitlab/skip_if_draft.sh diff --git a/.maintain/monitoring/alerting-rules/alerting-rule-tests.yaml b/scripts/ci/monitoring/alerting-rules/alerting-rule-tests.yaml similarity index 100% rename from .maintain/monitoring/alerting-rules/alerting-rule-tests.yaml rename to scripts/ci/monitoring/alerting-rules/alerting-rule-tests.yaml diff --git a/.maintain/monitoring/alerting-rules/alerting-rules.yaml b/scripts/ci/monitoring/alerting-rules/alerting-rules.yaml similarity index 100% rename from .maintain/monitoring/alerting-rules/alerting-rules.yaml rename to scripts/ci/monitoring/alerting-rules/alerting-rules.yaml diff --git a/.maintain/monitoring/grafana-dashboards/README_dashboard.md b/scripts/ci/monitoring/grafana-dashboards/README_dashboard.md similarity index 100% rename from .maintain/monitoring/grafana-dashboards/README_dashboard.md rename to scripts/ci/monitoring/grafana-dashboards/README_dashboard.md diff --git a/.maintain/monitoring/grafana-dashboards/substrate-networking.json b/scripts/ci/monitoring/grafana-dashboards/substrate-networking.json similarity index 100% rename from .maintain/monitoring/grafana-dashboards/substrate-networking.json rename to scripts/ci/monitoring/grafana-dashboards/substrate-networking.json diff --git a/.maintain/monitoring/grafana-dashboards/substrate-service-tasks.json b/scripts/ci/monitoring/grafana-dashboards/substrate-service-tasks.json similarity index 100% rename from .maintain/monitoring/grafana-dashboards/substrate-service-tasks.json rename to scripts/ci/monitoring/grafana-dashboards/substrate-service-tasks.json diff --git a/.maintain/node-template-release.sh b/scripts/ci/node-template-release.sh similarity index 84% rename from .maintain/node-template-release.sh rename to scripts/ci/node-template-release.sh index cb5e72e7fa98f..09ef98e04627a 100755 --- a/.maintain/node-template-release.sh +++ b/scripts/ci/node-template-release.sh @@ -11,6 +11,6 @@ if [ "$#" -ne 1 ]; then fi PATH_TO_ARCHIVE=$1 -cd $PROJECT_ROOT/.maintain/node-template-release +cd $PROJECT_ROOT/scripts/ci/node-template-release cargo run $PROJECT_ROOT/bin/node-template $PROJECT_ROOT/$PATH_TO_ARCHIVE diff --git a/.maintain/node-template-release/Cargo.toml b/scripts/ci/node-template-release/Cargo.toml similarity index 100% rename from .maintain/node-template-release/Cargo.toml rename to scripts/ci/node-template-release/Cargo.toml diff --git a/.maintain/node-template-release/src/main.rs b/scripts/ci/node-template-release/src/main.rs similarity index 100% rename from .maintain/node-template-release/src/main.rs rename to scripts/ci/node-template-release/src/main.rs From 11403bf965dd99d8af11d8f73128f7b4896a65bd Mon Sep 17 00:00:00 2001 From: Georges Date: Mon, 14 Mar 2022 10:00:41 +0000 Subject: [PATCH 0593/1472] Move `sp-npos-elections-solution-type` to `frame-election-provider-support` (#11016) * Move `sp-npos-elections-solution-type` to `frame-election-provider-support` First stab at it, will need to amend some more stuff * Fixing tests * Fixing tests * Fixing cargo.toml for std configuration * fmt * Committing suggested changes renaming, and re exporting macro. * Removing unneeded imports --- Cargo.lock | 47 ++- Cargo.toml | 3 +- bin/node/runtime/src/lib.rs | 2 +- .../election-provider-multi-phase/Cargo.toml | 3 +- .../election-provider-multi-phase/src/mock.rs | 2 +- frame/election-provider-support/Cargo.toml | 1 + .../solution-type/Cargo.toml | 6 +- .../solution-type/fuzzer/Cargo.toml | 30 ++ .../solution-type}/fuzzer/src/compact.rs | 3 +- .../solution-type/src/codec.rs | 0 .../src/from_assignment_helpers.rs | 0 .../solution-type/src/index_assignment.rs | 0 .../solution-type/src/lib.rs | 4 +- .../solution-type/src/mock.rs | 178 +++++++++ .../solution-type/src/single_page.rs | 0 .../solution-type/src/tests.rs | 350 ++++++++++++++++++ .../tests/ui/fail/missing_accuracy.rs | 2 +- .../tests/ui/fail/missing_accuracy.stderr | 0 .../tests/ui/fail/missing_target.rs | 2 +- .../tests/ui/fail/missing_target.stderr | 0 .../tests/ui/fail/missing_voter.rs | 2 +- .../tests/ui/fail/missing_voter.stderr | 0 .../tests/ui/fail/no_annotations.rs | 2 +- .../tests/ui/fail/no_annotations.stderr | 0 .../tests/ui/fail/swap_voter_target.rs | 2 +- .../tests/ui/fail/swap_voter_target.stderr | 0 .../tests/ui/fail/wrong_attribute.rs | 2 +- .../tests/ui/fail/wrong_attribute.stderr | 0 frame/election-provider-support/src/lib.rs | 1 + frame/staking/src/lib.rs | 6 +- primitives/npos-elections/Cargo.toml | 1 - primitives/npos-elections/fuzzer/Cargo.toml | 4 - primitives/npos-elections/src/lib.rs | 7 +- primitives/npos-elections/src/mock.rs | 161 -------- primitives/npos-elections/src/tests.rs | 331 +---------------- 35 files changed, 616 insertions(+), 536 deletions(-) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/Cargo.toml (73%) create mode 100644 frame/election-provider-support/solution-type/fuzzer/Cargo.toml rename {primitives/npos-elections => frame/election-provider-support/solution-type}/fuzzer/src/compact.rs (94%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/src/codec.rs (100%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/src/from_assignment_helpers.rs (100%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/src/index_assignment.rs (100%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/src/lib.rs (98%) create mode 100644 frame/election-provider-support/solution-type/src/mock.rs rename {primitives/npos-elections => frame/election-provider-support}/solution-type/src/single_page.rs (100%) create mode 100644 frame/election-provider-support/solution-type/src/tests.rs rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/missing_accuracy.rs (64%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/missing_accuracy.stderr (100%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/missing_target.rs (63%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/missing_target.stderr (100%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/missing_voter.rs (63%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/missing_voter.stderr (100%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/no_annotations.rs (58%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/no_annotations.stderr (100%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/swap_voter_target.rs (66%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/swap_voter_target.stderr (100%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/wrong_attribute.rs (69%) rename {primitives/npos-elections => frame/election-provider-support}/solution-type/tests/ui/fail/wrong_attribute.stderr (100%) diff --git a/Cargo.lock b/Cargo.lock index 1ad59291eca27..9f4d2f21cf9c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2160,10 +2160,26 @@ dependencies = [ "sp-trie", ] +[[package]] +name = "frame-election-provider-solution-type" +version = "4.0.0-dev" +dependencies = [ + "parity-scale-codec", + "proc-macro-crate 1.1.0", + "proc-macro2", + "quote", + "scale-info", + "sp-arithmetic", + "sp-npos-elections", + "syn", + "trybuild", +] + [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" dependencies = [ + "frame-election-provider-solution-type", "frame-support", "frame-system", "parity-scale-codec", @@ -2176,6 +2192,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "frame-election-solution-type-fuzzer" +version = "2.0.0-alpha.5" +dependencies = [ + "clap 3.0.7", + "frame-election-provider-solution-type", + "honggfuzz", + "parity-scale-codec", + "rand 0.8.4", + "scale-info", + "sp-arithmetic", + "sp-npos-elections", + "sp-runtime", +] + [[package]] name = "frame-executive" version = "4.0.0-dev" @@ -10058,7 +10089,6 @@ dependencies = [ "serde", "sp-arithmetic", "sp-core", - "sp-npos-elections-solution-type", "sp-runtime", "sp-std", "substrate-test-utils", @@ -10077,21 +10107,6 @@ dependencies = [ "sp-runtime", ] -[[package]] -name = "sp-npos-elections-solution-type" -version = "4.0.0-dev" -dependencies = [ - "parity-scale-codec", - "proc-macro-crate 1.1.0", - "proc-macro2", - "quote", - "scale-info", - "sp-arithmetic", - "sp-npos-elections", - "syn", - "trybuild", -] - [[package]] name = "sp-offchain" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index f24ff6d04980a..bce23456b27e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,6 +86,8 @@ members = [ "frame/try-runtime", "frame/election-provider-multi-phase", "frame/election-provider-support", + "frame/election-provider-support/solution-type", + "frame/election-provider-support/solution-type/fuzzer", "frame/examples/basic", "frame/examples/offchain-worker", "frame/examples/parallel", @@ -169,7 +171,6 @@ members = [ "primitives/keystore", "primitives/maybe-compressed-blob", "primitives/npos-elections", - "primitives/npos-elections/solution-type", "primitives/npos-elections/fuzzer", "primitives/offchain", "primitives/panic-handler", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8c7a20af15683..20b718e2fa8f7 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -588,7 +588,7 @@ parameter_types! { .get(DispatchClass::Normal); } -sp_npos_elections::generate_solution_type!( +frame_election_provider_support::generate_solution_type!( #[compact] pub struct NposSolution16::< VoterIndex = u32, diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 38039f6926b15..25f98d965d86b 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -46,8 +46,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } -frame-election-provider-support = { version = "4.0.0-dev", features = [ -], path = "../election-provider-support" } +frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 7c7034ac91a83..7c4ef5d8055c3 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -68,7 +68,7 @@ pub(crate) type BlockNumber = u64; pub(crate) type VoterIndex = u32; pub(crate) type TargetIndex = u16; -sp_npos_elections::generate_solution_type!( +frame_election_provider_support::generate_solution_type!( #[compact] pub struct TestNposSolution::(16) ); diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index b95bd994fa70a..16b79dbb098d4 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -21,6 +21,7 @@ sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = ". sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +frame-election-provider-solution-type = { version = "4.0.0-dev", path = "solution-type" } [dev-dependencies] sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } diff --git a/primitives/npos-elections/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml similarity index 73% rename from primitives/npos-elections/solution-type/Cargo.toml rename to frame/election-provider-support/solution-type/Cargo.toml index 813637e89c338..d489c7b4c10de 100644 --- a/primitives/npos-elections/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "sp-npos-elections-solution-type" +name = "frame-election-provider-solution-type" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" @@ -23,7 +23,7 @@ proc-macro-crate = "1.1.0" [dev-dependencies] parity-scale-codec = "3.0.0" scale-info = "2.0.1" -sp-arithmetic = { path = "../../arithmetic", version = "5.0.0"} +sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } # used by generate_solution_type: -sp-npos-elections = { path = "..", version = "4.0.0-dev" } +sp-npos-elections = { version = "4.0.0-dev", path = "../../../primitives/npos-elections" } trybuild = "1.0.53" diff --git a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml new file mode 100644 index 0000000000000..f52b7f7332620 --- /dev/null +++ b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "frame-election-solution-type-fuzzer" +version = "2.0.0-alpha.5" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Fuzzer for phragmén solution type implementation." +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +clap = { version = "3.0", features = ["derive"] } +honggfuzz = "0.5" +rand = { version = "0.8", features = ["std", "small_rng"] } + +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-election-provider-solution-type = { version = "4.0.0-dev", path = ".." } +sp-arithmetic = { version = "5.0.0", path = "../../../../primitives/arithmetic" } +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +# used by generate_solution_type: +sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/npos-elections" } + +[[bin]] +name = "compact" +path = "src/compact.rs" diff --git a/primitives/npos-elections/fuzzer/src/compact.rs b/frame/election-provider-support/solution-type/fuzzer/src/compact.rs similarity index 94% rename from primitives/npos-elections/fuzzer/src/compact.rs rename to frame/election-provider-support/solution-type/fuzzer/src/compact.rs index 595048575d99c..501d241b2b80b 100644 --- a/primitives/npos-elections/fuzzer/src/compact.rs +++ b/frame/election-provider-support/solution-type/fuzzer/src/compact.rs @@ -1,5 +1,6 @@ +use frame_election_provider_solution_type::generate_solution_type; use honggfuzz::fuzz; -use sp_npos_elections::{generate_solution_type, sp_arithmetic::Percent}; +use sp_arithmetic::Percent; use sp_runtime::codec::{Encode, Error}; fn main() { diff --git a/primitives/npos-elections/solution-type/src/codec.rs b/frame/election-provider-support/solution-type/src/codec.rs similarity index 100% rename from primitives/npos-elections/solution-type/src/codec.rs rename to frame/election-provider-support/solution-type/src/codec.rs diff --git a/primitives/npos-elections/solution-type/src/from_assignment_helpers.rs b/frame/election-provider-support/solution-type/src/from_assignment_helpers.rs similarity index 100% rename from primitives/npos-elections/solution-type/src/from_assignment_helpers.rs rename to frame/election-provider-support/solution-type/src/from_assignment_helpers.rs diff --git a/primitives/npos-elections/solution-type/src/index_assignment.rs b/frame/election-provider-support/solution-type/src/index_assignment.rs similarity index 100% rename from primitives/npos-elections/solution-type/src/index_assignment.rs rename to frame/election-provider-support/solution-type/src/index_assignment.rs diff --git a/primitives/npos-elections/solution-type/src/lib.rs b/frame/election-provider-support/solution-type/src/lib.rs similarity index 98% rename from primitives/npos-elections/solution-type/src/lib.rs rename to frame/election-provider-support/solution-type/src/lib.rs index 6e632d19e171e..3de923cdffd03 100644 --- a/primitives/npos-elections/solution-type/src/lib.rs +++ b/frame/election-provider-support/solution-type/src/lib.rs @@ -57,7 +57,7 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error { /// type, `u8` target type and `Perbill` accuracy with maximum of 4 edges per voter. /// /// ``` -/// # use sp_npos_elections_solution_type::generate_solution_type; +/// # use frame_election_provider_solution_type::generate_solution_type; /// # use sp_arithmetic::per_things::Perbill; /// generate_solution_type!(pub struct TestSolution::< /// VoterIndex = u16, @@ -100,7 +100,7 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error { /// for numbers will be used, similar to how `parity-scale-codec`'s `Compact` works. /// /// ``` -/// # use sp_npos_elections_solution_type::generate_solution_type; +/// # use frame_election_provider_solution_type::generate_solution_type; /// # use sp_npos_elections::NposSolution; /// # use sp_arithmetic::per_things::Perbill; /// generate_solution_type!( diff --git a/frame/election-provider-support/solution-type/src/mock.rs b/frame/election-provider-support/solution-type/src/mock.rs new file mode 100644 index 0000000000000..c3d032f2eb257 --- /dev/null +++ b/frame/election-provider-support/solution-type/src/mock.rs @@ -0,0 +1,178 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Mock file for solution-type. + +#![cfg(test)] + +use std::{collections::HashMap, convert::TryInto, hash::Hash, HashSet}; + +use rand::{seq::SliceRandom, Rng}; + +/// The candidate mask allows easy disambiguation between voters and candidates: accounts +/// for which this bit is set are candidates, and without it, are voters. +pub const CANDIDATE_MASK: AccountId = 1 << ((std::mem::size_of::() * 8) - 1); + +pub type TestAccuracy = sp_runtime::Perbill; + +pub fn p(p: u8) -> TestAccuracy { + TestAccuracy::from_percent(p.into()) +} + +pub type MockAssignment = crate::Assignment; +pub type Voter = (AccountId, VoteWeight, Vec); + +crate::generate_solution_type! { + pub struct TestSolution::< + VoterIndex = u32, + TargetIndex = u16, + Accuracy = TestAccuracy, + >(16) +} + +/// Generate voter and assignment lists. Makes no attempt to be realistic about winner or assignment +/// fairness. +/// +/// Maintains these invariants: +/// +/// - candidate ids have `CANDIDATE_MASK` bit set +/// - voter ids do not have `CANDIDATE_MASK` bit set +/// - assignments have the same ordering as voters +/// - `assignments.distribution.iter().map(|(_, frac)| frac).sum() == One::one()` +/// - a coherent set of winners is chosen. +/// - the winner set is a subset of the candidate set. +/// - `assignments.distribution.iter().all(|(who, _)| winners.contains(who))` +pub fn generate_random_votes( + candidate_count: usize, + voter_count: usize, + mut rng: impl Rng, +) -> (Vec, Vec, Vec) { + // cache for fast generation of unique candidate and voter ids + let mut used_ids = HashSet::with_capacity(candidate_count + voter_count); + + // candidates are easy: just a completely random set of IDs + let mut candidates: Vec = Vec::with_capacity(candidate_count); + while candidates.len() < candidate_count { + let mut new = || rng.gen::() | CANDIDATE_MASK; + let mut id = new(); + // insert returns `false` when the value was already present + while !used_ids.insert(id) { + id = new(); + } + candidates.push(id); + } + + // voters are random ids, random weights, random selection from the candidates + let mut voters = Vec::with_capacity(voter_count); + while voters.len() < voter_count { + let mut new = || rng.gen::() & !CANDIDATE_MASK; + let mut id = new(); + // insert returns `false` when the value was already present + while !used_ids.insert(id) { + id = new(); + } + + let vote_weight = rng.gen(); + + // it's not interesting if a voter chooses 0 or all candidates, so rule those cases out. + // also, let's not generate any cases which result in a compact overflow. + let n_candidates_chosen = + rng.gen_range(1, candidates.len().min(::LIMIT)); + + let mut chosen_candidates = Vec::with_capacity(n_candidates_chosen); + chosen_candidates.extend(candidates.choose_multiple(&mut rng, n_candidates_chosen)); + voters.push((id, vote_weight, chosen_candidates)); + } + + // always generate a sensible number of winners: elections are uninteresting if nobody wins, + // or everybody wins + let num_winners = rng.gen_range(1, candidate_count); + let mut winners: HashSet = HashSet::with_capacity(num_winners); + winners.extend(candidates.choose_multiple(&mut rng, num_winners)); + assert_eq!(winners.len(), num_winners); + + let mut assignments = Vec::with_capacity(voters.len()); + for (voter_id, _, votes) in voters.iter() { + let chosen_winners = votes.iter().filter(|vote| winners.contains(vote)).cloned(); + let num_chosen_winners = chosen_winners.clone().count(); + + // distribute the available stake randomly + let stake_distribution = if num_chosen_winners == 0 { + continue + } else { + let mut available_stake = 1000; + let mut stake_distribution = Vec::with_capacity(num_chosen_winners); + for _ in 0..num_chosen_winners - 1 { + let stake = rng.gen_range(0, available_stake).min(1); + stake_distribution.push(TestAccuracy::from_perthousand(stake)); + available_stake -= stake; + } + stake_distribution.push(TestAccuracy::from_perthousand(available_stake)); + stake_distribution.shuffle(&mut rng); + stake_distribution + }; + + assignments.push(MockAssignment { + who: *voter_id, + distribution: chosen_winners.zip(stake_distribution).collect(), + }); + } + + (voters, assignments, candidates) +} + +fn generate_cache(voters: Voters) -> HashMap +where + Voters: Iterator, + Item: Hash + Eq + Copy, +{ + let mut cache = HashMap::new(); + for (idx, voter_id) in voters.enumerate() { + cache.insert(voter_id, idx); + } + cache +} + +/// Create a function that returns the index of a voter in the voters list. +pub fn make_voter_fn(voters: &[Voter]) -> impl Fn(&AccountId) -> Option +where + usize: TryInto, +{ + let cache = generate_cache(voters.iter().map(|(id, _, _)| *id)); + move |who| { + if cache.get(who).is_none() { + println!("WARNING: voter {} will raise InvalidIndex", who); + } + cache.get(who).cloned().and_then(|i| i.try_into().ok()) + } +} + +/// Create a function that returns the index of a candidate in the candidates list. +pub fn make_target_fn( + candidates: &[AccountId], +) -> impl Fn(&AccountId) -> Option +where + usize: TryInto, +{ + let cache = generate_cache(candidates.iter().cloned()); + move |who| { + if cache.get(who).is_none() { + println!("WARNING: target {} will raise InvalidIndex", who); + } + cache.get(who).cloned().and_then(|i| i.try_into().ok()) + } +} diff --git a/primitives/npos-elections/solution-type/src/single_page.rs b/frame/election-provider-support/solution-type/src/single_page.rs similarity index 100% rename from primitives/npos-elections/solution-type/src/single_page.rs rename to frame/election-provider-support/solution-type/src/single_page.rs diff --git a/frame/election-provider-support/solution-type/src/tests.rs b/frame/election-provider-support/solution-type/src/tests.rs new file mode 100644 index 0000000000000..f173e425b5187 --- /dev/null +++ b/frame/election-provider-support/solution-type/src/tests.rs @@ -0,0 +1,350 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for solution-type. + +#![cfg(test)] + +use crate::{mock::*, IndexAssignment, NposSolution}; +use rand::SeedableRng; +use std::convert::TryInto; + +mod solution_type { + use super::*; + use codec::{Decode, Encode}; + // these need to come from the same dev-dependency `sp-npos-elections`, not from the crate. + use crate::{generate_solution_type, Assignment, Error as NposError, NposSolution}; + use sp_std::{convert::TryInto, fmt::Debug}; + + #[allow(dead_code)] + mod __private { + // This is just to make sure that the solution can be generated in a scope without any + // imports. + use crate::generate_solution_type; + generate_solution_type!( + #[compact] + struct InnerTestSolutionIsolated::(12) + ); + } + + #[test] + fn solution_struct_works_with_and_without_compact() { + // we use u32 size to make sure compact is smaller. + let without_compact = { + generate_solution_type!( + pub struct InnerTestSolution::< + VoterIndex = u32, + TargetIndex = u32, + Accuracy = TestAccuracy, + >(16) + ); + let solution = InnerTestSolution { + votes1: vec![(2, 20), (4, 40)], + votes2: vec![(1, [(10, p(80))], 11), (5, [(50, p(85))], 51)], + ..Default::default() + }; + + solution.encode().len() + }; + + let with_compact = { + generate_solution_type!( + #[compact] + pub struct InnerTestSolutionCompact::< + VoterIndex = u32, + TargetIndex = u32, + Accuracy = TestAccuracy, + >(16) + ); + let compact = InnerTestSolutionCompact { + votes1: vec![(2, 20), (4, 40)], + votes2: vec![(1, [(10, p(80))], 11), (5, [(50, p(85))], 51)], + ..Default::default() + }; + + compact.encode().len() + }; + + assert!(with_compact < without_compact); + } + + #[test] + fn solution_struct_is_codec() { + let solution = TestSolution { + votes1: vec![(2, 20), (4, 40)], + votes2: vec![(1, [(10, p(80))], 11), (5, [(50, p(85))], 51)], + ..Default::default() + }; + + let encoded = solution.encode(); + + assert_eq!(solution, Decode::decode(&mut &encoded[..]).unwrap()); + assert_eq!(solution.voter_count(), 4); + assert_eq!(solution.edge_count(), 2 + 4); + assert_eq!(solution.unique_targets(), vec![10, 11, 20, 40, 50, 51]); + } + + #[test] + fn remove_voter_works() { + let mut solution = TestSolution { + votes1: vec![(0, 2), (1, 6)], + votes2: vec![(2, [(0, p(80))], 1), (3, [(7, p(85))], 8)], + votes3: vec![(4, [(3, p(50)), (4, p(25))], 5)], + ..Default::default() + }; + + assert!(!solution.remove_voter(11)); + assert!(solution.remove_voter(2)); + assert_eq!( + solution, + TestSolution { + votes1: vec![(0, 2), (1, 6)], + votes2: vec![(3, [(7, p(85))], 8)], + votes3: vec![(4, [(3, p(50)), (4, p(25))], 5,)], + ..Default::default() + }, + ); + + assert!(solution.remove_voter(4)); + assert_eq!( + solution, + TestSolution { + votes1: vec![(0, 2), (1, 6)], + votes2: vec![(3, [(7, p(85))], 8)], + ..Default::default() + }, + ); + + assert!(solution.remove_voter(1)); + assert_eq!( + solution, + TestSolution { + votes1: vec![(0, 2)], + votes2: vec![(3, [(7, p(85))], 8),], + ..Default::default() + }, + ); + } + + #[test] + fn from_and_into_assignment_works() { + let voters = vec![2 as AccountId, 4, 1, 5, 3]; + let targets = vec![ + 10 as AccountId, + 11, + 20, // 2 + 30, + 31, // 4 + 32, + 40, // 6 + 50, + 51, // 8 + ]; + + let assignments = vec![ + Assignment { who: 2 as AccountId, distribution: vec![(20u64, p(100))] }, + Assignment { who: 4, distribution: vec![(40, p(100))] }, + Assignment { who: 1, distribution: vec![(10, p(80)), (11, p(20))] }, + Assignment { who: 5, distribution: vec![(50, p(85)), (51, p(15))] }, + Assignment { who: 3, distribution: vec![(30, p(50)), (31, p(25)), (32, p(25))] }, + ]; + + let voter_index = |a: &AccountId| -> Option { + voters.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok() + }; + let target_index = |a: &AccountId| -> Option { + targets.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok() + }; + + let solution = + TestSolution::from_assignment(&assignments, voter_index, target_index).unwrap(); + + // basically number of assignments that it is encoding. + assert_eq!(solution.voter_count(), assignments.len()); + assert_eq!( + solution.edge_count(), + assignments.iter().fold(0, |a, b| a + b.distribution.len()), + ); + + assert_eq!( + solution, + TestSolution { + votes1: vec![(0, 2), (1, 6)], + votes2: vec![(2, [(0, p(80))], 1), (3, [(7, p(85))], 8)], + votes3: vec![(4, [(3, p(50)), (4, p(25))], 5)], + ..Default::default() + } + ); + + assert_eq!(solution.unique_targets(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); + + let voter_at = |a: u32| -> Option { + voters.get(>::try_into(a).unwrap()).cloned() + }; + let target_at = |a: u16| -> Option { + targets.get(>::try_into(a).unwrap()).cloned() + }; + + assert_eq!(solution.into_assignment(voter_at, target_at).unwrap(), assignments); + } + + #[test] + fn unique_targets_len_edge_count_works() { + // we don't really care about voters here so all duplicates. This is not invalid per se. + let solution = TestSolution { + votes1: vec![(99, 1), (99, 2)], + votes2: vec![(99, [(3, p(10))], 7), (99, [(4, p(10))], 8)], + votes3: vec![(99, [(11, p(10)), (12, p(10))], 13)], + // ensure the last one is also counted. + votes16: vec![( + 99, + [ + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + (66, p(10)), + ], + 67, + )], + ..Default::default() + }; + + assert_eq!(solution.unique_targets(), vec![1, 2, 3, 4, 7, 8, 11, 12, 13, 66, 67]); + assert_eq!(solution.edge_count(), 2 + (2 * 2) + 3 + 16); + assert_eq!(solution.voter_count(), 6); + + // this one has some duplicates. + let solution = TestSolution { + votes1: vec![(99, 1), (99, 1)], + votes2: vec![(99, [(3, p(10))], 7), (99, [(4, p(10))], 8)], + votes3: vec![(99, [(11, p(10)), (11, p(10))], 13)], + ..Default::default() + }; + + assert_eq!(solution.unique_targets(), vec![1, 3, 4, 7, 8, 11, 13]); + assert_eq!(solution.edge_count(), 2 + (2 * 2) + 3); + assert_eq!(solution.voter_count(), 5); + } + + #[test] + fn solution_into_assignment_must_report_overflow() { + // in votes2 + let solution = TestSolution { + votes1: Default::default(), + votes2: vec![(0, [(1, p(100))], 2)], + ..Default::default() + }; + + let voter_at = |a: u32| -> Option { Some(a as AccountId) }; + let target_at = |a: u16| -> Option { Some(a as AccountId) }; + + assert_eq!( + solution.into_assignment(&voter_at, &target_at).unwrap_err(), + NposError::SolutionWeightOverflow, + ); + + // in votes3 onwards + let solution = TestSolution { + votes1: Default::default(), + votes2: Default::default(), + votes3: vec![(0, [(1, p(70)), (2, p(80))], 3)], + ..Default::default() + }; + + assert_eq!( + solution.into_assignment(&voter_at, &target_at).unwrap_err(), + NposError::SolutionWeightOverflow, + ); + } + + #[test] + fn target_count_overflow_is_detected() { + let voter_index = |a: &AccountId| -> Option { Some(*a as u32) }; + let target_index = |a: &AccountId| -> Option { Some(*a as u16) }; + + let assignments = vec![Assignment { + who: 1 as AccountId, + distribution: (10..27).map(|i| (i as AccountId, p(i as u8))).collect::>(), + }]; + + let solution = TestSolution::from_assignment(&assignments, voter_index, target_index); + assert_eq!(solution.unwrap_err(), NposError::SolutionTargetOverflow); + } + + #[test] + fn zero_target_count_is_ignored() { + let voters = vec![1 as AccountId, 2]; + let targets = vec![10 as AccountId, 11]; + + let assignments = vec![ + Assignment { who: 1 as AccountId, distribution: vec![(10, p(50)), (11, p(50))] }, + Assignment { who: 2, distribution: vec![] }, + ]; + + let voter_index = |a: &AccountId| -> Option { + voters.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok() + }; + let target_index = |a: &AccountId| -> Option { + targets.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok() + }; + + let solution = + TestSolution::from_assignment(&assignments, voter_index, target_index).unwrap(); + + assert_eq!( + solution, + TestSolution { + votes1: Default::default(), + votes2: vec![(0, [(0, p(50))], 1)], + ..Default::default() + } + ); + } +} + +#[test] +fn index_assignments_generate_same_solution_as_plain_assignments() { + let rng = rand::rngs::SmallRng::seed_from_u64(0); + + let (voters, assignments, candidates) = generate_random_votes(1000, 2500, rng); + let voter_index = make_voter_fn(&voters); + let target_index = make_target_fn(&candidates); + + let solution = + TestSolution::from_assignment(&assignments, &voter_index, &target_index).unwrap(); + + let index_assignments = assignments + .into_iter() + .map(|assignment| IndexAssignment::new(&assignment, &voter_index, &target_index)) + .collect::, _>>() + .unwrap(); + + let index_compact = index_assignments.as_slice().try_into().unwrap(); + + assert_eq!(solution, index_compact); +} diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/missing_accuracy.rs b/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs similarity index 64% rename from primitives/npos-elections/solution-type/tests/ui/fail/missing_accuracy.rs rename to frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs index b74b857e45815..22693cd875e17 100644 --- a/primitives/npos-elections/solution-type/tests/ui/fail/missing_accuracy.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs @@ -1,4 +1,4 @@ -use sp_npos_elections_solution_type::generate_solution_type; +use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< VoterIndex = u16, diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/missing_accuracy.stderr b/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.stderr similarity index 100% rename from primitives/npos-elections/solution-type/tests/ui/fail/missing_accuracy.stderr rename to frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.stderr diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/missing_target.rs b/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs similarity index 63% rename from primitives/npos-elections/solution-type/tests/ui/fail/missing_target.rs rename to frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs index 4c9cd51a32096..8d0ca927c5fb3 100644 --- a/primitives/npos-elections/solution-type/tests/ui/fail/missing_target.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs @@ -1,4 +1,4 @@ -use sp_npos_elections_solution_type::generate_solution_type; +use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< VoterIndex = u16, diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/missing_target.stderr b/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.stderr similarity index 100% rename from primitives/npos-elections/solution-type/tests/ui/fail/missing_target.stderr rename to frame/election-provider-support/solution-type/tests/ui/fail/missing_target.stderr diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/missing_voter.rs b/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs similarity index 63% rename from primitives/npos-elections/solution-type/tests/ui/fail/missing_voter.rs rename to frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs index b87037f77f1e3..ad4b7f5217794 100644 --- a/primitives/npos-elections/solution-type/tests/ui/fail/missing_voter.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs @@ -1,4 +1,4 @@ -use sp_npos_elections_solution_type::generate_solution_type; +use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< u16, diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/missing_voter.stderr b/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.stderr similarity index 100% rename from primitives/npos-elections/solution-type/tests/ui/fail/missing_voter.stderr rename to frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.stderr diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/no_annotations.rs b/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs similarity index 58% rename from primitives/npos-elections/solution-type/tests/ui/fail/no_annotations.rs rename to frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs index cfca2841db633..87673a3823513 100644 --- a/primitives/npos-elections/solution-type/tests/ui/fail/no_annotations.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs @@ -1,4 +1,4 @@ -use sp_npos_elections_solution_type::generate_solution_type; +use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< u16, diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/no_annotations.stderr b/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.stderr similarity index 100% rename from primitives/npos-elections/solution-type/tests/ui/fail/no_annotations.stderr rename to frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.stderr diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/swap_voter_target.rs b/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs similarity index 66% rename from primitives/npos-elections/solution-type/tests/ui/fail/swap_voter_target.rs rename to frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs index 443202d11b39b..f1d5d0e7bf99f 100644 --- a/primitives/npos-elections/solution-type/tests/ui/fail/swap_voter_target.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs @@ -1,4 +1,4 @@ -use sp_npos_elections_solution_type::generate_solution_type; +use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!(pub struct TestSolution::< TargetIndex = u16, diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/swap_voter_target.stderr b/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.stderr similarity index 100% rename from primitives/npos-elections/solution-type/tests/ui/fail/swap_voter_target.stderr rename to frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.stderr diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/wrong_attribute.rs b/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs similarity index 69% rename from primitives/npos-elections/solution-type/tests/ui/fail/wrong_attribute.rs rename to frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs index 3008277e36b74..d04cc4a7a966b 100644 --- a/primitives/npos-elections/solution-type/tests/ui/fail/wrong_attribute.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs @@ -1,4 +1,4 @@ -use sp_npos_elections_solution_type::generate_solution_type; +use frame_election_provider_solution_type::generate_solution_type; generate_solution_type!( #[pages(1)] pub struct TestSolution::< diff --git a/primitives/npos-elections/solution-type/tests/ui/fail/wrong_attribute.stderr b/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.stderr similarity index 100% rename from primitives/npos-elections/solution-type/tests/ui/fail/wrong_attribute.stderr rename to frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.stderr diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index ff57eacf68fa0..1bd10ba09346f 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -172,6 +172,7 @@ use sp_runtime::traits::Bounded; use sp_std::{fmt::Debug, prelude::*}; /// Re-export some type as they are used in the interface. +pub use frame_election_provider_solution_type::generate_solution_type; pub use sp_arithmetic::PerThing; pub use sp_npos_elections::{ Assignment, ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Support, Supports, diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index d833ac86fe0bd..4c1bb438457e5 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -302,7 +302,7 @@ mod pallet; use codec::{Decode, Encode, HasCompact}; use frame_support::{ parameter_types, - traits::{ConstU32, Currency, Get}, + traits::{Currency, Get}, weights::Weight, BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; @@ -861,6 +861,6 @@ pub struct TestBenchmarkingConfig; #[cfg(feature = "std")] impl BenchmarkingConfig for TestBenchmarkingConfig { - type MaxValidators = ConstU32<100>; - type MaxNominators = ConstU32<100>; + type MaxValidators = frame_support::traits::ConstU32<100>; + type MaxNominators = frame_support::traits::ConstU32<100>; } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 3facf32196c74..13edbfe90008b 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -17,7 +17,6 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-runtime = { version = "6.0.0", path = "../runtime", default-features = false } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 2f2bae2dd44d4..71c0c07c3032a 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -35,10 +35,6 @@ path = "src/phragmen_balancing.rs" name = "phragmms_balancing" path = "src/phragmms_balancing.rs" -[[bin]] -name = "compact" -path = "src/compact.rs" - [[bin]] name = "phragmen_pjr" path = "src/phragmen_pjr.rs" diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 7bd1a4b7f69b6..673036c2d19d1 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -77,7 +77,9 @@ use scale_info::TypeInfo; use sp_arithmetic::{traits::Zero, Normalizable, PerThing, Rational128, ThresholdOrd}; use sp_core::RuntimeDebug; -use sp_std::{cell::RefCell, cmp::Ordering, collections::btree_map::BTreeMap, prelude::*, rc::Rc}; +use sp_std::{ + cell::RefCell, cmp::Ordering, collections::btree_map::BTreeMap, prelude::*, rc::Rc, vec, +}; use codec::{Decode, Encode, MaxEncodedLen}; #[cfg(feature = "std")] @@ -117,9 +119,6 @@ pub use sp_arithmetic; #[doc(hidden)] pub use sp_std; -// re-export the solution type macro. -pub use sp_npos_elections_solution_type::generate_solution_type; - /// The errors that might occur in the this crate and solution-type. #[derive(Eq, PartialEq, RuntimeDebug)] pub enum Error { diff --git a/primitives/npos-elections/src/mock.rs b/primitives/npos-elections/src/mock.rs index 85c970d7b418f..dd85ce9b6dfae 100644 --- a/primitives/npos-elections/src/mock.rs +++ b/primitives/npos-elections/src/mock.rs @@ -19,13 +19,6 @@ #![cfg(test)] -use std::{ - collections::{HashMap, HashSet}, - convert::TryInto, - hash::Hash, -}; - -use rand::{self, seq::SliceRandom, Rng}; use sp_arithmetic::{ traits::{One, SaturatedConversion, Zero}, PerThing, @@ -37,27 +30,6 @@ use crate::{seq_phragmen, Assignment, ElectionResult, ExtendedBalance, PerThing1 pub type AccountId = u64; -/// The candidate mask allows easy disambiguation between voters and candidates: accounts -/// for which this bit is set are candidates, and without it, are voters. -pub const CANDIDATE_MASK: AccountId = 1 << ((std::mem::size_of::() * 8) - 1); - -pub type TestAccuracy = sp_runtime::Perbill; - -crate::generate_solution_type! { - pub struct TestSolution::< - VoterIndex = u32, - TargetIndex = u16, - Accuracy = TestAccuracy, - >(16) -} - -pub fn p(p: u8) -> TestAccuracy { - TestAccuracy::from_percent(p.into()) -} - -pub type MockAssignment = crate::Assignment; -pub type Voter = (AccountId, VoteWeight, Vec); - #[derive(Default, Debug)] pub(crate) struct _Candidate { who: A, @@ -412,136 +384,3 @@ pub(crate) fn build_support_map_float( } supports } - -/// Generate voter and assignment lists. Makes no attempt to be realistic about winner or assignment -/// fairness. -/// -/// Maintains these invariants: -/// -/// - candidate ids have `CANDIDATE_MASK` bit set -/// - voter ids do not have `CANDIDATE_MASK` bit set -/// - assignments have the same ordering as voters -/// - `assignments.distribution.iter().map(|(_, frac)| frac).sum() == One::one()` -/// - a coherent set of winners is chosen. -/// - the winner set is a subset of the candidate set. -/// - `assignments.distribution.iter().all(|(who, _)| winners.contains(who))` -pub fn generate_random_votes( - candidate_count: usize, - voter_count: usize, - mut rng: impl Rng, -) -> (Vec, Vec, Vec) { - // cache for fast generation of unique candidate and voter ids - let mut used_ids = HashSet::with_capacity(candidate_count + voter_count); - - // candidates are easy: just a completely random set of IDs - let mut candidates: Vec = Vec::with_capacity(candidate_count); - while candidates.len() < candidate_count { - let mut new = || rng.gen::() | CANDIDATE_MASK; - let mut id = new(); - // insert returns `false` when the value was already present - while !used_ids.insert(id) { - id = new(); - } - candidates.push(id); - } - - // voters are random ids, random weights, random selection from the candidates - let mut voters = Vec::with_capacity(voter_count); - while voters.len() < voter_count { - let mut new = || rng.gen::() & !CANDIDATE_MASK; - let mut id = new(); - // insert returns `false` when the value was already present - while !used_ids.insert(id) { - id = new(); - } - - let vote_weight = rng.gen(); - - // it's not interesting if a voter chooses 0 or all candidates, so rule those cases out. - // also, let's not generate any cases which result in a compact overflow. - let n_candidates_chosen = - rng.gen_range(1, candidates.len().min(::LIMIT)); - - let mut chosen_candidates = Vec::with_capacity(n_candidates_chosen); - chosen_candidates.extend(candidates.choose_multiple(&mut rng, n_candidates_chosen)); - voters.push((id, vote_weight, chosen_candidates)); - } - - // always generate a sensible number of winners: elections are uninteresting if nobody wins, - // or everybody wins - let num_winners = rng.gen_range(1, candidate_count); - let mut winners: HashSet = HashSet::with_capacity(num_winners); - winners.extend(candidates.choose_multiple(&mut rng, num_winners)); - assert_eq!(winners.len(), num_winners); - - let mut assignments = Vec::with_capacity(voters.len()); - for (voter_id, _, votes) in voters.iter() { - let chosen_winners = votes.iter().filter(|vote| winners.contains(vote)).cloned(); - let num_chosen_winners = chosen_winners.clone().count(); - - // distribute the available stake randomly - let stake_distribution = if num_chosen_winners == 0 { - continue - } else { - let mut available_stake = 1000; - let mut stake_distribution = Vec::with_capacity(num_chosen_winners); - for _ in 0..num_chosen_winners - 1 { - let stake = rng.gen_range(0, available_stake).min(1); - stake_distribution.push(TestAccuracy::from_perthousand(stake)); - available_stake -= stake; - } - stake_distribution.push(TestAccuracy::from_perthousand(available_stake)); - stake_distribution.shuffle(&mut rng); - stake_distribution - }; - - assignments.push(MockAssignment { - who: *voter_id, - distribution: chosen_winners.zip(stake_distribution).collect(), - }); - } - - (voters, assignments, candidates) -} - -fn generate_cache(voters: Voters) -> HashMap -where - Voters: Iterator, - Item: Hash + Eq + Copy, -{ - let mut cache = HashMap::new(); - for (idx, voter_id) in voters.enumerate() { - cache.insert(voter_id, idx); - } - cache -} - -/// Create a function that returns the index of a voter in the voters list. -pub fn make_voter_fn(voters: &[Voter]) -> impl Fn(&AccountId) -> Option -where - usize: TryInto, -{ - let cache = generate_cache(voters.iter().map(|(id, _, _)| *id)); - move |who| { - if cache.get(who).is_none() { - println!("WARNING: voter {} will raise InvalidIndex", who); - } - cache.get(who).cloned().and_then(|i| i.try_into().ok()) - } -} - -/// Create a function that returns the index of a candidate in the candidates list. -pub fn make_target_fn( - candidates: &[AccountId], -) -> impl Fn(&AccountId) -> Option -where - usize: TryInto, -{ - let cache = generate_cache(candidates.iter().cloned()); - move |who| { - if cache.get(who).is_none() { - println!("WARNING: target {} will raise InvalidIndex", who); - } - cache.get(who).cloned().and_then(|i| i.try_into().ok()) - } -} diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index b199fdd1af77f..1cf5ea8a24920 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -19,12 +19,9 @@ use crate::{ balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, to_support_map, - Assignment, ElectionResult, ExtendedBalance, IndexAssignment, NposSolution, StakedAssignment, - Support, Voter, + Assignment, ElectionResult, ExtendedBalance, StakedAssignment, Support, Voter, }; -use rand::{self, SeedableRng}; use sp_arithmetic::{PerU16, Perbill, Percent, Permill}; -use std::convert::TryInto; use substrate_test_utils::assert_eq_uvec; #[test] @@ -919,329 +916,3 @@ mod score { assert!(ElectionScore::from([10, 5, 15]) > ElectionScore::from([10, 5, 25])); } } - -mod solution_type { - use super::*; - use codec::{Decode, Encode}; - // these need to come from the same dev-dependency `sp-npos-elections`, not from the crate. - use crate::{generate_solution_type, Assignment, Error as NposError, NposSolution}; - use sp_std::{convert::TryInto, fmt::Debug}; - - #[allow(dead_code)] - mod __private { - // This is just to make sure that the solution can be generated in a scope without any - // imports. - use crate::generate_solution_type; - generate_solution_type!( - #[compact] - struct InnerTestSolutionIsolated::(12) - ); - } - - #[test] - fn solution_struct_works_with_and_without_compact() { - // we use u32 size to make sure compact is smaller. - let without_compact = { - generate_solution_type!( - pub struct InnerTestSolution::< - VoterIndex = u32, - TargetIndex = u32, - Accuracy = TestAccuracy, - >(16) - ); - let solution = InnerTestSolution { - votes1: vec![(2, 20), (4, 40)], - votes2: vec![(1, [(10, p(80))], 11), (5, [(50, p(85))], 51)], - ..Default::default() - }; - - solution.encode().len() - }; - - let with_compact = { - generate_solution_type!( - #[compact] - pub struct InnerTestSolutionCompact::< - VoterIndex = u32, - TargetIndex = u32, - Accuracy = TestAccuracy, - >(16) - ); - let compact = InnerTestSolutionCompact { - votes1: vec![(2, 20), (4, 40)], - votes2: vec![(1, [(10, p(80))], 11), (5, [(50, p(85))], 51)], - ..Default::default() - }; - - compact.encode().len() - }; - - assert!(with_compact < without_compact); - } - - #[test] - fn solution_struct_is_codec() { - let solution = TestSolution { - votes1: vec![(2, 20), (4, 40)], - votes2: vec![(1, [(10, p(80))], 11), (5, [(50, p(85))], 51)], - ..Default::default() - }; - - let encoded = solution.encode(); - - assert_eq!(solution, Decode::decode(&mut &encoded[..]).unwrap()); - assert_eq!(solution.voter_count(), 4); - assert_eq!(solution.edge_count(), 2 + 4); - assert_eq!(solution.unique_targets(), vec![10, 11, 20, 40, 50, 51]); - } - - #[test] - fn remove_voter_works() { - let mut solution = TestSolution { - votes1: vec![(0, 2), (1, 6)], - votes2: vec![(2, [(0, p(80))], 1), (3, [(7, p(85))], 8)], - votes3: vec![(4, [(3, p(50)), (4, p(25))], 5)], - ..Default::default() - }; - - assert!(!solution.remove_voter(11)); - assert!(solution.remove_voter(2)); - assert_eq!( - solution, - TestSolution { - votes1: vec![(0, 2), (1, 6)], - votes2: vec![(3, [(7, p(85))], 8)], - votes3: vec![(4, [(3, p(50)), (4, p(25))], 5,)], - ..Default::default() - }, - ); - - assert!(solution.remove_voter(4)); - assert_eq!( - solution, - TestSolution { - votes1: vec![(0, 2), (1, 6)], - votes2: vec![(3, [(7, p(85))], 8)], - ..Default::default() - }, - ); - - assert!(solution.remove_voter(1)); - assert_eq!( - solution, - TestSolution { - votes1: vec![(0, 2)], - votes2: vec![(3, [(7, p(85))], 8),], - ..Default::default() - }, - ); - } - - #[test] - fn from_and_into_assignment_works() { - let voters = vec![2 as AccountId, 4, 1, 5, 3]; - let targets = vec![ - 10 as AccountId, - 11, - 20, // 2 - 30, - 31, // 4 - 32, - 40, // 6 - 50, - 51, // 8 - ]; - - let assignments = vec![ - Assignment { who: 2 as AccountId, distribution: vec![(20u64, p(100))] }, - Assignment { who: 4, distribution: vec![(40, p(100))] }, - Assignment { who: 1, distribution: vec![(10, p(80)), (11, p(20))] }, - Assignment { who: 5, distribution: vec![(50, p(85)), (51, p(15))] }, - Assignment { who: 3, distribution: vec![(30, p(50)), (31, p(25)), (32, p(25))] }, - ]; - - let voter_index = |a: &AccountId| -> Option { - voters.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok() - }; - let target_index = |a: &AccountId| -> Option { - targets.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok() - }; - - let solution = - TestSolution::from_assignment(&assignments, voter_index, target_index).unwrap(); - - // basically number of assignments that it is encoding. - assert_eq!(solution.voter_count(), assignments.len()); - assert_eq!( - solution.edge_count(), - assignments.iter().fold(0, |a, b| a + b.distribution.len()), - ); - - assert_eq!( - solution, - TestSolution { - votes1: vec![(0, 2), (1, 6)], - votes2: vec![(2, [(0, p(80))], 1), (3, [(7, p(85))], 8)], - votes3: vec![(4, [(3, p(50)), (4, p(25))], 5)], - ..Default::default() - } - ); - - assert_eq!(solution.unique_targets(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); - - let voter_at = |a: u32| -> Option { - voters.get(>::try_into(a).unwrap()).cloned() - }; - let target_at = |a: u16| -> Option { - targets.get(>::try_into(a).unwrap()).cloned() - }; - - assert_eq!(solution.into_assignment(voter_at, target_at).unwrap(), assignments); - } - - #[test] - fn unique_targets_len_edge_count_works() { - // we don't really care about voters here so all duplicates. This is not invalid per se. - let solution = TestSolution { - votes1: vec![(99, 1), (99, 2)], - votes2: vec![(99, [(3, p(10))], 7), (99, [(4, p(10))], 8)], - votes3: vec![(99, [(11, p(10)), (12, p(10))], 13)], - // ensure the last one is also counted. - votes16: vec![( - 99, - [ - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - (66, p(10)), - ], - 67, - )], - ..Default::default() - }; - - assert_eq!(solution.unique_targets(), vec![1, 2, 3, 4, 7, 8, 11, 12, 13, 66, 67]); - assert_eq!(solution.edge_count(), 2 + (2 * 2) + 3 + 16); - assert_eq!(solution.voter_count(), 6); - - // this one has some duplicates. - let solution = TestSolution { - votes1: vec![(99, 1), (99, 1)], - votes2: vec![(99, [(3, p(10))], 7), (99, [(4, p(10))], 8)], - votes3: vec![(99, [(11, p(10)), (11, p(10))], 13)], - ..Default::default() - }; - - assert_eq!(solution.unique_targets(), vec![1, 3, 4, 7, 8, 11, 13]); - assert_eq!(solution.edge_count(), 2 + (2 * 2) + 3); - assert_eq!(solution.voter_count(), 5); - } - - #[test] - fn solution_into_assignment_must_report_overflow() { - // in votes2 - let solution = TestSolution { - votes1: Default::default(), - votes2: vec![(0, [(1, p(100))], 2)], - ..Default::default() - }; - - let voter_at = |a: u32| -> Option { Some(a as AccountId) }; - let target_at = |a: u16| -> Option { Some(a as AccountId) }; - - assert_eq!( - solution.into_assignment(&voter_at, &target_at).unwrap_err(), - NposError::SolutionWeightOverflow, - ); - - // in votes3 onwards - let solution = TestSolution { - votes1: Default::default(), - votes2: Default::default(), - votes3: vec![(0, [(1, p(70)), (2, p(80))], 3)], - ..Default::default() - }; - - assert_eq!( - solution.into_assignment(&voter_at, &target_at).unwrap_err(), - NposError::SolutionWeightOverflow, - ); - } - - #[test] - fn target_count_overflow_is_detected() { - let voter_index = |a: &AccountId| -> Option { Some(*a as u32) }; - let target_index = |a: &AccountId| -> Option { Some(*a as u16) }; - - let assignments = vec![Assignment { - who: 1 as AccountId, - distribution: (10..27).map(|i| (i as AccountId, p(i as u8))).collect::>(), - }]; - - let solution = TestSolution::from_assignment(&assignments, voter_index, target_index); - assert_eq!(solution.unwrap_err(), NposError::SolutionTargetOverflow); - } - - #[test] - fn zero_target_count_is_ignored() { - let voters = vec![1 as AccountId, 2]; - let targets = vec![10 as AccountId, 11]; - - let assignments = vec![ - Assignment { who: 1 as AccountId, distribution: vec![(10, p(50)), (11, p(50))] }, - Assignment { who: 2, distribution: vec![] }, - ]; - - let voter_index = |a: &AccountId| -> Option { - voters.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok() - }; - let target_index = |a: &AccountId| -> Option { - targets.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok() - }; - - let solution = - TestSolution::from_assignment(&assignments, voter_index, target_index).unwrap(); - - assert_eq!( - solution, - TestSolution { - votes1: Default::default(), - votes2: vec![(0, [(0, p(50))], 1)], - ..Default::default() - } - ); - } -} - -#[test] -fn index_assignments_generate_same_solution_as_plain_assignments() { - let rng = rand::rngs::SmallRng::seed_from_u64(0); - - let (voters, assignments, candidates) = generate_random_votes(1000, 2500, rng); - let voter_index = make_voter_fn(&voters); - let target_index = make_target_fn(&candidates); - - let solution = - TestSolution::from_assignment(&assignments, &voter_index, &target_index).unwrap(); - - let index_assignments = assignments - .into_iter() - .map(|assignment| IndexAssignment::new(&assignment, &voter_index, &target_index)) - .collect::, _>>() - .unwrap(); - - let index_compact = index_assignments.as_slice().try_into().unwrap(); - - assert_eq!(solution, index_compact); -} From 345e3b1fcbbb0c479a031c45859d7154e7c4b5f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 14 Mar 2022 12:48:29 +0100 Subject: [PATCH 0594/1472] shell.nix: Update to a newer nightly (#11028) --- shell.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell.nix b/shell.nix index a86af005383f7..023946ce16de4 100644 --- a/shell.nix +++ b/shell.nix @@ -2,10 +2,10 @@ let mozillaOverlay = import (builtins.fetchGit { url = "https://github.com/mozilla/nixpkgs-mozilla.git"; - rev = "4a07484cf0e49047f82d83fd119acffbad3b235f"; + rev = "15b7a05f20aab51c4ffbefddb1b448e862dccb7d"; }); nixpkgs = import { overlays = [ mozillaOverlay ]; }; - rust-nightly = with nixpkgs; ((rustChannelOf { date = "2021-09-10"; channel = "nightly"; }).rust.override { + rust-nightly = with nixpkgs; ((rustChannelOf { date = "2022-02-10"; channel = "nightly"; }).rust.override { extensions = [ "rust-src" ]; targets = [ "wasm32-unknown-unknown" ]; }); From 5463591f60fdc4870165cb2025174153fae0bd7a Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 15 Mar 2022 13:48:29 +0100 Subject: [PATCH 0595/1472] Update lockfile (#11035) Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 9f4d2f21cf9c1..82dea83813d0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2196,7 +2196,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 3.0.7", + "clap 3.1.6", "frame-election-provider-solution-type", "honggfuzz", "parity-scale-codec", From 80a90e70eec6368fc95ae5bdf03ef57fb61ab378 Mon Sep 17 00:00:00 2001 From: Daan Schutte Date: Tue, 15 Mar 2022 17:21:16 +0300 Subject: [PATCH 0596/1472] Additional `benchmark-storage` flags (#11004) * Fix typos * Enable overwriting handlebars template * Optionally name json output or disable json altogether * Don't write to json by default * Include block id in handlebars output * Include warmups for write benchmarks * PR comments * Drop unnecessary file extension * Use more appropriate types * Use more appropriate error message * More use of more appropriate types * Rework write benchmark warmups * Run same benchmark for both read and write --- utils/frame/benchmarking-cli/src/lib.rs | 2 +- .../frame/benchmarking-cli/src/storage/cmd.rs | 63 ++++++++++++++++--- .../benchmarking-cli/src/storage/read.rs | 11 ---- .../benchmarking-cli/src/storage/record.rs | 14 +++-- .../benchmarking-cli/src/storage/template.rs | 32 +++++++--- .../benchmarking-cli/src/storage/weights.hbs | 1 + 6 files changed, 93 insertions(+), 30 deletions(-) diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 640b1770f5c3f..9815fe88a7f02 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -67,7 +67,7 @@ pub struct BenchmarkCmd { #[clap(long = "json")] pub json_output: bool, - /// Write the raw results in JSON format into the give file. + /// Write the raw results in JSON format into the given file. #[clap(long, conflicts_with = "json-output")] pub json_file: Option, diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index 4376b616286a4..ad7d13a2022e4 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -20,6 +20,7 @@ use sc_client_api::{Backend as ClientBackend, StorageProvider, UsageProvider}; use sc_client_db::DbHash; use sc_service::Configuration; use sp_blockchain::HeaderBackend; +use sp_core::storage::StorageKey; use sp_database::{ColumnId, Database}; use sp_runtime::traits::{Block as BlockT, HashFor}; use sp_state_machine::Storage; @@ -29,7 +30,8 @@ use clap::{Args, Parser}; use log::info; use rand::prelude::*; use serde::Serialize; -use std::{fmt::Debug, sync::Arc}; +use sp_runtime::generic::BlockId; +use std::{fmt::Debug, path::PathBuf, sync::Arc}; use super::{record::StatSelect, template::TemplateData}; @@ -58,8 +60,8 @@ pub struct StorageCmd { pub struct StorageParams { /// Path to write the *weight* file to. Can be a file or directory. /// For substrate this should be `frame/support/src/weights`. - #[clap(long, default_value = ".")] - pub weight_path: String, + #[clap(long)] + pub weight_path: Option, /// Select a specific metric to calculate the final weight output. #[clap(long = "metric", default_value = "average")] @@ -83,8 +85,19 @@ pub struct StorageParams { #[clap(long)] pub skip_write: bool, + /// Specify the Handlebars template to use for outputting benchmark results. + #[clap(long)] + pub template_path: Option, + + /// Path to write the raw 'read' results in JSON format to. Can be a file or directory. + #[clap(long)] + pub json_read_path: Option, + + /// Path to write the raw 'write' results in JSON format to. Can be a file or directory. + #[clap(long)] + pub json_write_path: Option, + /// Rounds of warmups before measuring. - /// Only supported for `read` benchmarks. #[clap(long, default_value = "1")] pub warmups: u32, @@ -115,23 +128,32 @@ impl StorageCmd { { let mut template = TemplateData::new(&cfg, &self.params); + let block_id = BlockId::::Number(client.usage_info().chain.best_number); + template.set_block_number(block_id.to_string()); + if !self.params.skip_read { + self.bench_warmup(&client)?; let record = self.bench_read(client.clone())?; - record.save_json(&cfg, "read")?; + if let Some(path) = &self.params.json_read_path { + record.save_json(&cfg, path, "read")?; + } let stats = record.calculate_stats()?; info!("Time summary [ns]:\n{:?}\nValue size summary:\n{:?}", stats.0, stats.1); template.set_stats(Some(stats), None)?; } if !self.params.skip_write { + self.bench_warmup(&client)?; let record = self.bench_write(client, db, storage)?; - record.save_json(&cfg, "write")?; + if let Some(path) = &self.params.json_write_path { + record.save_json(&cfg, path, "write")?; + } let stats = record.calculate_stats()?; info!("Time summary [ns]:\n{:?}\nValue size summary:\n{:?}", stats.0, stats.1); template.set_stats(None, Some(stats))?; } - template.write(&self.params.weight_path) + template.write(&self.params.weight_path, &self.params.template_path) } /// Returns the specified state version. @@ -149,6 +171,33 @@ impl StorageCmd { info!("Using seed {}", seed); StdRng::seed_from_u64(seed) } + + /// Run some rounds of the (read) benchmark as warmup. + /// See `frame_benchmarking_cli::storage::read::bench_read` for detailed comments. + fn bench_warmup(&self, client: &Arc) -> Result<()> + where + C: UsageProvider + StorageProvider, + B: BlockT + Debug, + BA: ClientBackend, + { + let block = BlockId::Number(client.usage_info().chain.best_number); + let empty_prefix = StorageKey(Vec::new()); + let mut keys = client.storage_keys(&block, &empty_prefix)?; + let mut rng = Self::setup_rng(); + keys.shuffle(&mut rng); + + for i in 0..self.params.warmups { + info!("Warmup round {}/{}", i + 1, self.params.warmups); + for key in keys.clone() { + let _ = client + .storage(&block, &key) + .expect("Checked above to exist") + .ok_or("Value unexpectedly empty"); + } + } + + Ok(()) + } } // Boilerplate diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs index 3974c4010f632..ca506202e1067 100644 --- a/utils/frame/benchmarking-cli/src/storage/read.rs +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -49,17 +49,6 @@ impl StorageCmd { let mut rng = Self::setup_rng(); keys.shuffle(&mut rng); - // Run some rounds of the benchmark as warmup. - for i in 0..self.params.warmups { - info!("Warmup round {}/{}", i + 1, self.params.warmups); - for key in keys.clone() { - let _ = client - .storage(&block, &key) - .expect("Checked above to exist") - .ok_or("Value unexpectedly empty")?; - } - } - // Interesting part here: // Read all the keys in the database and measure the time it takes to access each. info!("Reading {} keys", keys.len()); diff --git a/utils/frame/benchmarking-cli/src/storage/record.rs b/utils/frame/benchmarking-cli/src/storage/record.rs index 00a613c713007..667274bef0dd5 100644 --- a/utils/frame/benchmarking-cli/src/storage/record.rs +++ b/utils/frame/benchmarking-cli/src/storage/record.rs @@ -22,7 +22,7 @@ use sc_service::Configuration; use log::info; use serde::Serialize; -use std::{fmt, fs, result, str::FromStr, time::Duration}; +use std::{fmt, fs, path::PathBuf, result, str::FromStr, time::Duration}; /// Raw output of a Storage benchmark. #[derive(Debug, Default, Clone, Serialize)] @@ -95,12 +95,18 @@ impl BenchRecord { Ok((time, size)) // The swap of time/size here is intentional. } - /// Saves the raw results in a json file in the current directory. + /// Unless a path is specified, saves the raw results in a json file in the current directory. /// Prefixes it with the DB name and suffixed with `path_suffix`. - pub fn save_json(&self, cfg: &Configuration, path_suffix: &str) -> Result<()> { - let path = format!("{}_{}.json", cfg.database, path_suffix).to_lowercase(); + pub fn save_json(&self, cfg: &Configuration, out_path: &PathBuf, suffix: &str) -> Result<()> { + let mut path = PathBuf::from(out_path); + if path.is_dir() || path.as_os_str().is_empty() { + path.push(&format!("{}_{}", cfg.database, suffix).to_lowercase()); + path.set_extension("json"); + } + let json = serde_json::to_string_pretty(&self) .map_err(|e| format!("Serializing as JSON: {:?}", e))?; + fs::write(&path, json)?; info!("Raw data written to {:?}", fs::canonicalize(&path)?); Ok(()) diff --git a/utils/frame/benchmarking-cli/src/storage/template.rs b/utils/frame/benchmarking-cli/src/storage/template.rs index 56e0869a914a1..13b825d891a51 100644 --- a/utils/frame/benchmarking-cli/src/storage/template.rs +++ b/utils/frame/benchmarking-cli/src/storage/template.rs @@ -32,6 +32,8 @@ static TEMPLATE: &str = include_str!("./weights.hbs"); pub(crate) struct TemplateData { /// Name of the database used. db_name: String, + /// Block number that was used. + block_number: String, /// Name of the runtime. Taken from the chain spec. runtime_name: String, /// Version of the benchmarking CLI used. @@ -85,28 +87,44 @@ impl TemplateData { Ok(()) } - /// Filles out the `weights.hbs` HBS template with its own data. + /// Sets the block id that was used. + pub fn set_block_number(&mut self, block_number: String) { + self.block_number = block_number + } + + /// Fills out the `weights.hbs` or specified HBS template with its own data. /// Writes the result to `path` which can be a directory or file. - pub fn write(&self, path: &str) -> Result<()> { + pub fn write(&self, path: &Option, hbs_template: &Option) -> Result<()> { let mut handlebars = handlebars::Handlebars::new(); // Format large integers with underscore. handlebars.register_helper("underscore", Box::new(crate::writer::UnderscoreHelper)); // Don't HTML escape any characters. handlebars.register_escape_fn(|s| -> String { s.to_string() }); + // Use custom template if provided. + let template = match hbs_template { + Some(template) if template.is_file() => fs::read_to_string(template)?, + Some(_) => return Err("Handlebars template is not a valid file!".into()), + None => TEMPLATE.to_string(), + }; let out_path = self.build_path(path); let mut fd = fs::File::create(&out_path)?; info!("Writing weights to {:?}", fs::canonicalize(&out_path)?); + handlebars - .render_template_to_write(&TEMPLATE, &self, &mut fd) + .render_template_to_write(&template, &self, &mut fd) .map_err(|e| format!("HBS template write: {:?}", e).into()) } /// Builds a path for the weight file. - fn build_path(&self, weight_out: &str) -> PathBuf { - let mut path = PathBuf::from(weight_out); - if path.is_dir() { - path.push(format!("{}_weights.rs", self.db_name.to_lowercase())); + fn build_path(&self, weight_out: &Option) -> PathBuf { + let mut path = match weight_out { + Some(p) => PathBuf::from(p), + None => PathBuf::new(), + }; + + if path.is_dir() || path.as_os_str().is_empty() { + path.push(format!("{}_weights", self.db_name.to_lowercase())); path.set_extension("rs"); } path diff --git a/utils/frame/benchmarking-cli/src/storage/weights.hbs b/utils/frame/benchmarking-cli/src/storage/weights.hbs index ffeb1fe04d81c..bfb832cb847f9 100644 --- a/utils/frame/benchmarking-cli/src/storage/weights.hbs +++ b/utils/frame/benchmarking-cli/src/storage/weights.hbs @@ -19,6 +19,7 @@ //! DATE: {{date}} //! //! DATABASE: `{{db_name}}`, RUNTIME: `{{runtime_name}}` +//! BLOCK-NUM: `{{block_number}}` //! SKIP-WRITE: `{{params.skip_write}}`, SKIP-READ: `{{params.skip_read}}`, WARMUPS: `{{params.warmups}}` //! STATE-VERSION: `V{{params.state_version}}`, STATE-CACHE-SIZE: `{{params.state_cache_size}}` //! WEIGHT-PATH: `{{params.weight_path}}` From 8b26ac915b3226d2e234b4c03dab32d3793d328a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 15 Mar 2022 16:14:19 +0100 Subject: [PATCH 0597/1472] SharedData: Update locks to mention possible deadlocks (#11034) * SharedData: Update locks to mention possible deadlocks * Update `Cargo.lock` --- client/consensus/common/src/shared_data.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/consensus/common/src/shared_data.rs b/client/consensus/common/src/shared_data.rs index 17217d997e236..fb04966b5db61 100644 --- a/client/consensus/common/src/shared_data.rs +++ b/client/consensus/common/src/shared_data.rs @@ -167,6 +167,13 @@ struct SharedDataInner { /// // As we don't know the order of the threads, we need to check for both combinations /// assert!(*data == "hello world321" || *data == "hello world312"); /// ``` +/// +/// # Deadlock +/// +/// Be aware that this data structure doesn't give you any guarantees that you can not create a +/// deadlock. If you use [`release_mutex`](SharedDataLocked::release_mutex) followed by a call +/// to [`shared_data`](Self::shared_data) in the same thread will make your program dead lock. +/// The same applies when you are using a single threaded executor. pub struct SharedData { inner: Arc>>, cond_var: Arc, From cc282f84ba53ed2a08374d2a655dc8f08cbc5e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 15 Mar 2022 16:26:59 +0100 Subject: [PATCH 0598/1472] Stabilize `seal_delegate_call` (#11037) --- frame/contracts/fixtures/delegate_call.wat | 2 +- frame/contracts/src/benchmarking/mod.rs | 2 +- frame/contracts/src/tests.rs | 1 - frame/contracts/src/wasm/mod.rs | 2 +- frame/contracts/src/wasm/runtime.rs | 7 +------ 5 files changed, 4 insertions(+), 10 deletions(-) diff --git a/frame/contracts/fixtures/delegate_call.wat b/frame/contracts/fixtures/delegate_call.wat index e1c5fa813e590..7fe422af45511 100644 --- a/frame/contracts/fixtures/delegate_call.wat +++ b/frame/contracts/fixtures/delegate_call.wat @@ -2,7 +2,7 @@ (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32) (result i32))) (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) - (import "__unstable__" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) + (import "seal0" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 3 3)) ;; [0, 32) storage key diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 5fdc5c2ab7846..8539978bd6b39 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1492,7 +1492,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "seal_delegate_call", params: vec![ ValueType::I32, diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 4c8c42c77da56..2b01cbe3c7429 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -762,7 +762,6 @@ fn deploy_and_call_other_contract() { } #[test] -#[cfg(feature = "unstable-interface")] fn delegate_call() { let (caller_wasm, caller_code_hash) = compile_module::("delegate_call").unwrap(); let (callee_wasm, callee_code_hash) = compile_module::("delegate_call_lib").unwrap(); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index d89e7c1c8037d..3912a936684c2 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -618,7 +618,7 @@ mod tests { ;; output_ptr: u32, ;; output_len_ptr: u32 ;;) -> u32 - (import "__unstable__" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) + (import "seal0" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) (func (export "call") (drop diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index d008fa3f1dac0..043b45e6a76ed 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -191,7 +191,6 @@ pub enum RuntimeCosts { /// Base weight of calling `seal_call`. CallBase, /// Weight of calling `seal_delegate_call` for the given input size. - #[cfg(feature = "unstable-interface")] DelegateCallBase, /// Weight of the transfer performed during a call. CallSurchargeTransfer, @@ -272,7 +271,6 @@ impl RuntimeCosts { .saturating_add(s.take_storage_per_byte.saturating_mul(len.into())), Transfer => s.transfer, CallBase => s.call, - #[cfg(feature = "unstable-interface")] DelegateCallBase => s.delegate_call, CallSurchargeTransfer => s.call_transfer_surcharge, CallInputCloned(len) => s.call_per_cloned_byte.saturating_mul(len.into()), @@ -389,7 +387,6 @@ bitflags! { enum CallType { /// Execute another instantiated contract Call { callee_ptr: u32, value_ptr: u32, gas: u64 }, - #[cfg(feature = "unstable-interface")] /// Execute deployed code in the context (storage, account ID, value) of the caller contract DelegateCall { code_hash_ptr: u32 }, } @@ -398,7 +395,6 @@ impl CallType { fn cost(&self) -> RuntimeCosts { match self { CallType::Call { .. } => RuntimeCosts::CallBase, - #[cfg(feature = "unstable-interface")] CallType::DelegateCall { .. } => RuntimeCosts::DelegateCallBase, } } @@ -763,7 +759,6 @@ where flags.contains(CallFlags::ALLOW_REENTRY), ) }, - #[cfg(feature = "unstable-interface")] CallType::DelegateCall { code_hash_ptr } => { if flags.contains(CallFlags::ALLOW_REENTRY) { return Err(Error::::InvalidCallFlags.into()) @@ -1129,7 +1124,7 @@ define_env!(Env, , // `ReturnCode::CalleeReverted`: Output buffer is returned. // `ReturnCode::CalleeTrapped` // `ReturnCode::CodeNotFound` - [__unstable__] seal_delegate_call( + [seal0] seal_delegate_call( ctx, flags: u32, code_hash_ptr: u32, From 499acc0e31e06dee9110a9cc169cd7c52f500b10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Mar 2022 09:47:16 +0000 Subject: [PATCH 0599/1472] Bump names from 0.12.0 to 0.13.0 (#11047) Bumps [names](https://github.com/fnichol/names) from 0.12.0 to 0.13.0. - [Release notes](https://github.com/fnichol/names/releases) - [Changelog](https://github.com/fnichol/names/blob/main/CHANGELOG.md) - [Commits](https://github.com/fnichol/names/compare/v0.12.0...v0.13.0) --- updated-dependencies: - dependency-name: names 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 | 4 ++-- client/cli/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82dea83813d0b..903b76bff8023 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4719,9 +4719,9 @@ dependencies = [ [[package]] name = "names" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a8690bf09abf659851e58cd666c3d37ac6af07c2bd7a9e332cfba471715775" +checksum = "e7d66043b25d4a6cccb23619d10c19c25304b355a7dccd4a8e11423dd2382146" dependencies = [ "rand 0.8.4", ] diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 8fdb192b43fb6..c799fd6dee980 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3.19" hex = "0.4.2" libp2p = "0.40.0" log = "0.4.11" -names = { version = "0.12.0", default-features = false } +names = { version = "0.13.0", default-features = false } rand = "0.7.3" regex = "1.5.4" rpassword = "5.0.0" From 027fc0666fa2f981a693a394f76dc9f4b87209a4 Mon Sep 17 00:00:00 2001 From: cheme Date: Wed, 16 Mar 2022 12:43:24 +0100 Subject: [PATCH 0600/1472] State migration rpc (#10981) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * setting flag * flag in storage struct * fix flagging to access and insert. * added todo to fix * also missing serialize meta to storage proof * extract meta. * Isolate old trie layout. * failing test that requires storing in meta when old hash scheme is used. * old hash compatibility * Db migrate. * runing tests with both states when interesting. * fix chain spec test with serde default. * export state (missing trie function). * Pending using new branch, lacking genericity on layout resolution. * extract and set global meta * Update to branch 4 * fix iterator with root flag (no longer insert node). * fix trie root hashing of root * complete basic backend. * Remove old_hash meta from proof that do not use inner_hashing. * fix trie test for empty (force layout on empty deltas). * Root update fix. * debug on meta * Use trie key iteration that do not include value in proofs. * switch default test ext to use inner hash. * small integration test, and fix tx cache mgmt in ext. test failing * Proof scenario at state-machine level. * trace for db upgrade * try different param * act more like iter_from. * Bigger batches. * Update trie dependency. * drafting codec changes and refact * before removing unused branch no value alt hashing. more work todo rename all flag var to alt_hash, and remove extrinsic replace by storage query at every storage_root call. * alt hashing only for branch with value. * fix trie tests * Hash of value include the encoded size. * removing fields(broken) * fix trie_stream to also include value length in inner hash. * triedbmut only using alt type if inner hashing. * trie_stream to also only use alt hashing type when actually alt hashing. * Refactor meta state, logic should work with change of trie treshold. * Remove NoMeta variant. * Remove state_hashed trigger specific functions. * pending switching to using threshold, new storage root api does not make much sense. * refactoring to use state from backend (not possible payload changes). * Applying from previous state * Remove default from storage, genesis need a special build. * rem empty space * Catch problem: when using triedb with default: we should not revert nodes: otherwhise thing as trie codec cannot decode-encode without changing state. * fix compilation * Right logic to avoid switch on reencode when default layout. * Clean up some todos * remove trie meta from root upstream * update upstream and fix benches. * split some long lines. * UPdate trie crate to work with new design. * Finish update to refactored upstream. * update to latest triedb changes. * Clean up. * fix executor test. * rust fmt from master. * rust format. * rustfmt * fix * start host function driven versioning * update state-machine part * still need access to state version from runtime * state hash in mem: wrong * direction likely correct, but passing call to code exec for genesis init seem awkward. * state version serialize in runtime, wrong approach, just initialize it with no threshold for core api < 4 seems more proper. * stateversion from runtime version (core api >= 4). * update trie, fix tests * unused import * clean some TODOs * Require RuntimeVersionOf for executor * use RuntimeVersionOf to resolve genesis state version. * update runtime version test * fix state-machine tests * TODO * Use runtime version from storage wasm with fast sync. * rustfmt * fmt * fix test * revert useless changes. * clean some unused changes * fmt * removing useless trait function. * remove remaining reference to state_hash * fix some imports * Follow chain state version management. * trie update, fix and constant threshold for trie layouts. * update deps * Update to latest trie pr changes. * fix benches * Verify proof requires right layout. * update trie_root * Update trie deps to latest * Update to latest trie versioning * Removing patch * update lock * extrinsic for sc-service-test using layout v0. * Adding RuntimeVersionOf to CallExecutor works. * fmt * error when resolving version and no wasm in storage. * use existing utils to instantiate runtime code. * migration pallet * Patch to delay runtime switch. * Revert "Patch to delay runtime switch." This reverts commit d35f273b7d67b1b85a9e72973cab13c5c156c1d3. * fix test * fix child migration calls. * useless closure * remove remaining state_hash variables. * Fix and add more tests * Remove outdated comment * useless inner hash * fmt * remote tests * finally ksm works * batches are broken * clean the benchmarks * Apply suggestions from code review Co-authored-by: Guillaume Thiolliere * Apply suggestions from code review Co-authored-by: Guillaume Thiolliere * Update frame/state-trie-migration/src/lib.rs Co-authored-by: Joshy Orndorff * Update frame/state-trie-migration/src/lib.rs * brand new version * fix build * Update frame/state-trie-migration/src/lib.rs Co-authored-by: Guillaume Thiolliere * Update frame/state-trie-migration/src/lib.rs Co-authored-by: Guillaume Thiolliere * Update primitives/storage/src/lib.rs Co-authored-by: cheme * Update frame/state-trie-migration/src/lib.rs Co-authored-by: cheme * Update frame/state-trie-migration/src/lib.rs Co-authored-by: cheme * fmt and opt-in feature to apply state change. * feature gate core version, use new test feature for node and test node * Use a 'State' api version instead of Core one. * fix merge of test function * use blake macro. * Fix state api (require declaring the api in runtime). * Opt out feature, fix macro for io to select a given version instead of latest. * run test nodes on new state. * fix * new test structure * new testing stuff from emeric * Add commit_all, still not working * Fix all tests * add comment * we have PoV tracking baby * document stuff, but proof size is still wrong * FUCK YEAH * a big batch of review comments * add more tests * tweak test * update config * some remote-ext stuff * delete some of the old stuff * sync more files with master to minimize the diff * Fix all tests * make signed migration a bit more relaxed * add witness check to signed submissions * allow custom migration to also go above limit * Fix these pesky tests * ==== removal of the unsigned stuff ==== * Make all tests work again * separate the tests from the logic so it can be reused easier * fix overall build * Update frame/state-trie-migration/src/lib.rs Co-authored-by: cheme * Update frame/state-trie-migration/src/lib.rs Co-authored-by: cheme * Slightly better termination * some final tweaks * Fix tests * Restrict access to signed migrations * mig rpc * fix * better rpc name * Make rpc unsafe * address most of the review comments * fix defensive * New simplified code * Fix weights * fmt * Update frame/state-trie-migration/src/lib.rs Co-authored-by: Bastian Köcher * make the tests correctly fail * Fix build * Fix build * try and fix the benchmarks * fix build * Fix cargo file * Fix runtime deposit * make rustdoc happy * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_state_trie_migration --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/state-trie-migration/src/weights.rs --template=./.maintain/frame-weight-template.hbs * update rpc deps, try to process empty keys. * move rpc crate * move check backend out of state machine * Add primitive crate. * module code * fix runtime test * StateMigrationStatusProvider * Pass backend to rpc. * fmt * review changes * move rpc crate * try remove primitive crate * Update utils/frame/rpc/state-trie-migration-rpc/Cargo.toml Co-authored-by: Bastian Köcher * review changes. Co-authored-by: kianenigma Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Guillaume Thiolliere Co-authored-by: Joshy Orndorff Co-authored-by: Bastian Köcher Co-authored-by: Parity Bot --- Cargo.lock | 26 ++- Cargo.toml | 2 + bin/node/cli/src/service.rs | 3 +- bin/node/rpc/Cargo.toml | 1 + bin/node/rpc/src/lib.rs | 5 + frame/state-trie-migration/Cargo.toml | 5 +- frame/state-trie-migration/src/lib.rs | 176 +++++++++--------- primitives/state-machine/Cargo.toml | 2 - .../state-machine/src/trie_backend_essence.rs | 72 +------ .../rpc/state-trie-migration-rpc/Cargo.toml | 38 ++++ .../rpc/state-trie-migration-rpc/README.md | 3 + .../rpc/state-trie-migration-rpc/src/lib.rs | 164 ++++++++++++++++ 12 files changed, 332 insertions(+), 165 deletions(-) create mode 100644 utils/frame/rpc/state-trie-migration-rpc/Cargo.toml create mode 100644 utils/frame/rpc/state-trie-migration-rpc/README.md create mode 100644 utils/frame/rpc/state-trie-migration-rpc/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 903b76bff8023..e2321d7fa99d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4987,6 +4987,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "substrate-frame-rpc-system", + "substrate-state-trie-migration-rpc", ] [[package]] @@ -6472,6 +6473,7 @@ dependencies = [ "sp-runtime", "sp-std", "sp-tracing", + "substrate-state-trie-migration-rpc", "thousands", "tokio", "zstd", @@ -10300,7 +10302,6 @@ dependencies = [ "sp-trie", "thiserror", "tracing", - "trie-db", "trie-root", ] @@ -10628,6 +10629,29 @@ dependencies = [ "tokio", ] +[[package]] +name = "substrate-state-trie-migration-rpc" +version = "4.0.0-dev" +dependencies = [ + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-derive", + "log 0.4.14", + "parity-scale-codec", + "sc-client-api", + "sc-rpc-api", + "scale-info", + "serde", + "serde_json", + "sp-core", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", + "trie-db", +] + [[package]] name = "substrate-test-client" version = "2.0.1" diff --git a/Cargo.toml b/Cargo.toml index bce23456b27e5..13657dd1234a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -119,6 +119,7 @@ members = [ "frame/staking", "frame/staking/reward-curve", "frame/staking/reward-fn", + "frame/state-trie-migration", "frame/sudo", "frame/support", "frame/support/procedural", @@ -210,6 +211,7 @@ members = [ "utils/frame/remote-externalities", "utils/frame/frame-utilities-cli", "utils/frame/try-runtime/cli", + "utils/frame/rpc/state-trie-migration-rpc", "utils/frame/rpc/support", "utils/frame/rpc/system", "utils/frame/generate-bags", diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 10d39f278f5f3..038c14029cf31 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -252,6 +252,7 @@ pub fn new_partial( let keystore = keystore_container.sync_keystore(); let chain_spec = config.chain_spec.cloned_box(); + let rpc_backend = backend.clone(); let rpc_extensions_builder = move |deny_unsafe, subscription_executor| { let deps = node_rpc::FullDeps { client: client.clone(), @@ -273,7 +274,7 @@ pub fn new_partial( }, }; - node_rpc::create_full(deps).map_err(Into::into) + node_rpc::create_full(deps, rpc_backend.clone()).map_err(Into::into) }; (rpc_extensions_builder, rpc_setup) diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 95ea3f8174fad..6c18e70f0d634 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -35,3 +35,4 @@ sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consen sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-frame-rpc-system = { version = "4.0.0-dev", path = "../../../utils/frame/rpc/system" } +substrate-state-trie-migration-rpc = { version = "4.0.0-dev", path = "../../../utils/frame/rpc/state-trie-migration-rpc/" } diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 31f2f41086885..09f350ed3dcf1 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -99,6 +99,7 @@ pub type IoHandler = jsonrpc_core::IoHandler; /// Instantiate all Full RPC extensions. pub fn create_full( deps: FullDeps, + backend: Arc, ) -> Result, Box> where C: ProvideRuntimeApi @@ -159,6 +160,10 @@ where finality_provider, ))); + io.extend_with(substrate_state_trie_migration_rpc::StateMigrationApi::to_delegate( + substrate_state_trie_migration_rpc::MigrationRpc::new(client.clone(), backend, deny_unsafe), + )); + io.extend_with(sc_sync_state_rpc::SyncStateRpcApi::to_delegate( sc_sync_state_rpc::SyncStateRpcHandler::new( chain_spec, diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index fb8bccb52d1f2..762fd85f13b62 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -21,6 +21,7 @@ sp-std = { default-features = false, path = "../../primitives/std" } sp-io = { default-features = false, path = "../../primitives/io" } sp-core = { default-features = false, path = "../../primitives/core" } sp-runtime = { default-features = false, path = "../../primitives/runtime" } +substrate-state-trie-migration-rpc = { optional = true, path = "../../utils/frame/rpc/state-trie-migration-rpc" } frame-support = { default-features = false, path = "../support" } frame-system = { default-features = false, path = "../system" } @@ -49,9 +50,9 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-std/std" + "sp-std/std", ] runtime-benchmarks = ["frame-benchmarking"] try-runtime = ["frame-support/try-runtime"] -remote-test = [ "std", "zstd", "serde", "thousands", "remote-externalities" ] +remote-test = [ "std", "zstd", "serde", "thousands", "remote-externalities", "substrate-state-trie-migration-rpc" ] diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 4de130e9ac06b..a5a077c54e579 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -123,6 +123,13 @@ pub mod pallet { } } + #[derive(Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq)] + pub(crate) enum Progress { + ToStart, + LastKey(Vec), + Complete, + } + /// A migration task stored in state. /// /// It tracks the last top and child keys read. @@ -130,20 +137,13 @@ pub mod pallet { #[codec(mel_bound(T: Config))] #[scale_info(skip_type_params(T))] pub struct MigrationTask { - /// The last top key that we migrated. + /// The current top trie migration progress. + pub(crate) progress_top: Progress, + /// The current child trie migration progress. /// - /// If it does not exist, it means that the migration is done and no further keys exist. - pub(crate) last_top: Option>, - /// The last child key that we have processed. - /// - /// This is a child key under the current `self.last_top`. - /// - /// If this is set, no further top keys are processed until the child key migration is - /// complete. - pub(crate) last_child: Option>, - - /// A marker to indicate if the previous tick was a child tree migration or not. - pub(crate) prev_tick_child: bool, + /// If `ToStart`, no further top keys are processed until the child key migration is + /// `Complete`. + pub(crate) progress_child: Progress, /// Dynamic counter for the number of items that we have processed in this execution from /// the top trie. @@ -182,18 +182,22 @@ pub mod pallet { pub(crate) _ph: sp_std::marker::PhantomData, } + impl sp_std::fmt::Debug for Progress { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + match self { + Progress::ToStart => f.write_str("To start"), + Progress::LastKey(key) => + write!(f, "Last: {:?}", sp_core::hexdisplay::HexDisplay::from(key)), + Progress::Complete => f.write_str("Complete"), + } + } + } + impl sp_std::fmt::Debug for MigrationTask { fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { f.debug_struct("MigrationTask") - .field( - "top", - &self.last_top.as_ref().map(|d| sp_core::hexdisplay::HexDisplay::from(d)), - ) - .field( - "child", - &self.last_child.as_ref().map(|d| sp_core::hexdisplay::HexDisplay::from(d)), - ) - .field("prev_tick_child", &self.prev_tick_child) + .field("top", &self.progress_top) + .field("child", &self.progress_child) .field("dyn_top_items", &self.dyn_top_items) .field("dyn_child_items", &self.dyn_child_items) .field("dyn_size", &self.dyn_size) @@ -207,12 +211,11 @@ pub mod pallet { impl Default for MigrationTask { fn default() -> Self { Self { - last_top: Some(Default::default()), - last_child: Default::default(), + progress_top: Progress::ToStart, + progress_child: Progress::ToStart, dyn_child_items: Default::default(), dyn_top_items: Default::default(), dyn_size: Default::default(), - prev_tick_child: Default::default(), _ph: Default::default(), size: Default::default(), top_items: Default::default(), @@ -224,7 +227,7 @@ pub mod pallet { impl MigrationTask { /// Return true if the task is finished. pub(crate) fn finished(&self) -> bool { - self.last_top.is_none() && self.last_child.is_none() + matches!(self.progress_top, Progress::Complete) } /// Check if there's any work left, or if we have exhausted the limits already. @@ -269,51 +272,36 @@ pub mod pallet { /// /// This function is *the* core of this entire pallet. fn migrate_tick(&mut self) { - match (self.last_top.as_ref(), self.last_child.as_ref()) { - (Some(_), Some(_)) => { + match (&self.progress_top, &self.progress_child) { + (Progress::ToStart, _) => { + self.migrate_top(); + }, + (Progress::LastKey(_), Progress::LastKey(_)) => { // we're in the middle of doing work on a child tree. self.migrate_child(); }, - (Some(ref top_key), None) => { - // we have a top key and no child key. 3 possibilities exist: - // 1. we continue the top key migrations. - // 2. this is the root of a child key, and we start processing child keys (and - // should call `migrate_child`). + (Progress::LastKey(top_key), Progress::ToStart) => { // 3. this is the root of a child key, and we are finishing all child-keys (and // should call `migrate_top`). // NOTE: this block is written intentionally to verbosely for easy of // verification. - match ( - top_key.starts_with(DEFAULT_CHILD_STORAGE_KEY_PREFIX), - self.prev_tick_child, - ) { - (false, false) => { - // continue the top key migration - self.migrate_top(); - }, - (true, false) => { - self.last_child = Some(Default::default()); - self.migrate_child(); - self.prev_tick_child = true; - }, - (true, true) => { - // we're done with migrating a child-root. - self.prev_tick_child = false; - self.migrate_top(); - }, - (false, true) => { - // should never happen. - log!(error, "LOGIC ERROR: unreachable code [0]."); - Pallet::::halt(); - }, - }; + if !top_key.starts_with(DEFAULT_CHILD_STORAGE_KEY_PREFIX) { + // we continue the top key migrations. + // continue the top key migration + self.migrate_top(); + } else { + // this is the root of a child key, and we start processing child keys (and + // should call `migrate_child`). + self.migrate_child(); + } }, - (None, Some(_)) => { - log!(error, "LOGIC ERROR: unreachable code [1]."); - Pallet::::halt() + (Progress::LastKey(_), Progress::Complete) => { + // we're done with migrating a child-root. + self.migrate_top(); + self.progress_child = Progress::ToStart; }, - (None, None) => { + (Progress::Complete, _) => { // nada }, } @@ -324,19 +312,26 @@ pub mod pallet { /// It updates the dynamic counters. fn migrate_child(&mut self) { use sp_io::default_child_storage as child_io; - let (last_child, last_top) = match (&self.last_child, &self.last_top) { - (Some(last_child), Some(last_top)) => (last_child, last_top), + let (maybe_current_child, child_root) = match (&self.progress_child, &self.progress_top) + { + (Progress::LastKey(last_child), Progress::LastKey(last_top)) => { + let child_root = Pallet::::transform_child_key_or_halt(&last_top); + let maybe_current_child = child_io::next_key(child_root, &last_child); + (maybe_current_child, child_root) + }, + (Progress::ToStart, Progress::LastKey(last_top)) => { + let child_root = Pallet::::transform_child_key_or_halt(&last_top); + // Start with the empty key as first key. + (Some(Vec::new()), child_root) + }, _ => { - // defensive: this function is only called when both of these values exist. - // much that we can do otherwise.. + // defensive: there must be an ongoing top migration. frame_support::defensive!("cannot migrate child key."); return }, }; - let child_root = Pallet::::transform_child_key_or_halt(&last_top); - let maybe_current_child = child_io::next_key(child_root, &last_child); - if let Some(ref current_child) = maybe_current_child { + if let Some(current_child) = maybe_current_child.as_ref() { let added_size = if let Some(data) = child_io::get(child_root, ¤t_child) { child_io::set(child_root, current_child, &data); data.len() as u32 @@ -348,25 +343,28 @@ pub mod pallet { } log!(trace, "migrated a child key, next_child_key: {:?}", maybe_current_child); - self.last_child = maybe_current_child; + self.progress_child = match maybe_current_child { + Some(last_child) => Progress::LastKey(last_child), + None => Progress::Complete, + } } /// Migrate the current top key, setting it to its new value, if one exists. /// /// It updates the dynamic counters. fn migrate_top(&mut self) { - let last_top = match &self.last_top { - Some(last_top) => last_top, - None => { - // defensive: this function is only called when this value exist. - // much that we can do otherwise.. + let maybe_current_top = match &self.progress_top { + Progress::LastKey(last_top) => sp_io::storage::next_key(last_top), + // Start with the empty key as first key. + Progress::ToStart => Some(Vec::new()), + Progress::Complete => { + // defensive: there must be an ongoing top migration. frame_support::defensive!("cannot migrate top key."); return }, }; - let maybe_current_top = sp_io::storage::next_key(last_top); - if let Some(ref current_top) = maybe_current_top { + if let Some(current_top) = maybe_current_top.as_ref() { let added_size = if let Some(data) = sp_io::storage::get(¤t_top) { sp_io::storage::set(¤t_top, &data); data.len() as u32 @@ -378,7 +376,10 @@ pub mod pallet { } log!(trace, "migrated a top key, next_top_key = {:?}", maybe_current_top); - self.last_top = maybe_current_top; + self.progress_top = match maybe_current_top { + Some(last_top) => Progress::LastKey(last_top), + None => Progress::Complete, + } } } @@ -811,7 +812,7 @@ mod benchmarks { continue_migrate_wrong_witness { let null = MigrationLimits::default(); let caller = frame_benchmarking::whitelisted_caller(); - let bad_witness = MigrationTask { last_top: Some(vec![1u8]), ..Default::default() }; + let bad_witness = MigrationTask { progress_top: Progress::LastKey(vec![1u8]), ..Default::default() }; }: { assert!( StateTrieMigration::::continue_migrate( @@ -1141,15 +1142,12 @@ mod test { } #[test] - #[ignore] fn detects_value_in_empty_top_key() { let limit = MigrationLimits { item: 1, size: 1000 }; let initial_keys = Some(vec![(vec![], vec![66u8; 77])]); let mut ext = new_test_ext(StateVersion::V0, false, initial_keys.clone(), None); let root_upgraded = ext.execute_with(|| { - sp_io::storage::set(&[], &vec![66u8; 77]); - AutoLimits::::put(Some(limit)); let root = run_to_block(30).0; @@ -1168,9 +1166,7 @@ mod test { } #[test] - #[ignore] fn detects_value_in_first_child_key() { - use frame_support::storage::child; let limit = MigrationLimits { item: 1, size: 1000 }; let initial_child = Some(vec![(b"chk1".to_vec(), vec![], vec![66u8; 77])]); let mut ext = new_test_ext(StateVersion::V0, false, None, initial_child.clone()); @@ -1186,7 +1182,6 @@ mod test { let mut ext2 = new_test_ext(StateVersion::V1, false, None, initial_child); let root = ext2.execute_with(|| { - child::put(&child::ChildInfo::new_default(b"chk1"), &[], &vec![66u8; 77]); AutoLimits::::put(Some(limit)); run_to_block(30).0 }); @@ -1214,7 +1209,7 @@ mod test { // eventually everything is over. assert!(matches!( StateTrieMigration::migration_process(), - MigrationTask { last_child: None, last_top: None, .. } + MigrationTask { progress_top: Progress::Complete, .. } )); root }); @@ -1276,7 +1271,10 @@ mod test { Origin::signed(1), MigrationLimits { item: 5, size: 100 }, 100, - MigrationTask { last_top: Some(vec![1u8]), ..Default::default() } + MigrationTask { + progress_top: Progress::LastKey(vec![1u8]), + ..Default::default() + } ), Error::::BadWitness ); @@ -1451,7 +1449,8 @@ pub(crate) mod remote_tests { // set the version to 1, as if the upgrade happened. ext.state_version = sp_core::storage::StateVersion::V1; - let (top_left, child_left) = ext.as_backend().essence().check_migration_state().unwrap(); + let (top_left, child_left) = + substrate_state_trie_migration_rpc::migration_status(&ext.as_backend()).unwrap(); assert!( top_left > 0, "no node needs migrating, this probably means that state was initialized with `StateVersion::V1`", @@ -1509,7 +1508,8 @@ pub(crate) mod remote_tests { ) }); - let (top_left, child_left) = ext.as_backend().essence().check_migration_state().unwrap(); + let (top_left, child_left) = + substrate_state_trie_migration_rpc::migration_status(&ext.as_backend()).unwrap(); assert_eq!(top_left, 0); assert_eq!(child_left, 0); } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 2a6ab80133ee6..80651130575ea 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -18,7 +18,6 @@ log = { version = "0.4.11", optional = true } thiserror = { version = "1.0.30", optional = true } parking_lot = { version = "0.12.0", optional = true } hash-db = { version = "0.15.2", default-features = false } -trie-db = { version = "0.23.1", default-features = false } trie-root = { version = "0.17.0", default-features = false } sp-trie = { version = "6.0.0", path = "../trie", default-features = false } sp-core = { version = "6.0.0", path = "../core", default-features = false } @@ -47,7 +46,6 @@ std = [ "sp-externalities/std", "sp-std/std", "sp-trie/std", - "trie-db/std", "trie-root/std", "log", "thiserror", diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index b0eb543824379..8531e4907d6a7 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -23,7 +23,7 @@ use codec::Encode; use hash_db::{self, AsHashDB, HashDB, HashDBRef, Hasher, Prefix}; #[cfg(feature = "std")] use parking_lot::RwLock; -use sp_core::storage::{ChildInfo, ChildType, PrefixedStorageKey, StateVersion}; +use sp_core::storage::{ChildInfo, ChildType, StateVersion}; use sp_std::{boxed::Box, vec::Vec}; use sp_trie::{ child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_value, @@ -36,10 +36,6 @@ use sp_trie::{ use std::collections::HashMap; #[cfg(feature = "std")] use std::sync::Arc; -use trie_db::{ - node::{NodePlan, ValuePlan}, - TrieDBNodeIterator, -}; #[cfg(not(feature = "std"))] macro_rules! format { @@ -433,72 +429,6 @@ where ); } - /// Check remaining state item to migrate. Note this function should be remove when all state - /// migration did finished as it is only an utility. - // original author: @cheme - pub fn check_migration_state(&self) -> Result<(u64, u64)> { - let threshold: u32 = sp_core::storage::TRIE_VALUE_NODE_THRESHOLD; - let mut nb_to_migrate = 0; - let mut nb_to_migrate_child = 0; - - let trie = sp_trie::trie_types::TrieDB::new(self, &self.root) - .map_err(|e| format!("TrieDB creation error: {}", e))?; - let iter_node = TrieDBNodeIterator::new(&trie) - .map_err(|e| format!("TrieDB node iterator error: {}", e))?; - for node in iter_node { - let node = node.map_err(|e| format!("TrieDB node iterator error: {}", e))?; - match node.2.node_plan() { - NodePlan::Leaf { value, .. } | - NodePlan::NibbledBranch { value: Some(value), .. } => - if let ValuePlan::Inline(range) = value { - if (range.end - range.start) as u32 >= threshold { - nb_to_migrate += 1; - } - }, - _ => (), - } - } - - let mut child_roots: Vec<(ChildInfo, Vec)> = Vec::new(); - // get all child trie roots - for key_value in trie.iter().map_err(|e| format!("TrieDB node iterator error: {}", e))? { - let (key, value) = - key_value.map_err(|e| format!("TrieDB node iterator error: {}", e))?; - if key[..] - .starts_with(sp_core::storage::well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX) - { - let prefixed_key = PrefixedStorageKey::new(key); - let (_type, unprefixed) = ChildType::from_prefixed_key(&prefixed_key).unwrap(); - child_roots.push((ChildInfo::new_default(unprefixed), value)); - } - } - for (child_info, root) in child_roots { - let mut child_root = H::Out::default(); - let storage = KeySpacedDB::new(self, child_info.keyspace()); - - child_root.as_mut()[..].copy_from_slice(&root[..]); - let trie = sp_trie::trie_types::TrieDB::new(&storage, &child_root) - .map_err(|e| format!("New child TrieDB error: {}", e))?; - let iter_node = TrieDBNodeIterator::new(&trie) - .map_err(|e| format!("TrieDB node iterator error: {}", e))?; - for node in iter_node { - let node = node.map_err(|e| format!("Child TrieDB node iterator error: {}", e))?; - match node.2.node_plan() { - NodePlan::Leaf { value, .. } | - NodePlan::NibbledBranch { value: Some(value), .. } => - if let ValuePlan::Inline(range) = value { - if (range.end - range.start) as u32 >= threshold { - nb_to_migrate_child += 1; - } - }, - _ => (), - } - } - } - - Ok((nb_to_migrate, nb_to_migrate_child)) - } - /// Returns all `(key, value)` pairs in the trie. pub fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { let collect_all = || -> sp_std::result::Result<_, Box>> { diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml new file mode 100644 index 0000000000000..deb641a89a466 --- /dev/null +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "substrate-state-trie-migration-rpc" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Node-specific RPC methods for interaction with state trie migration." +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +serde = { version = "1", features = ["derive"] } +log = { version = "0.4.14", default-features = false } + +sp-std = { path = "../../../../primitives/std" } +sp-io = { path = "../../../../primitives/io" } +sp-core = { path = "../../../../primitives/core" } +sp-state-machine = { path = "../../../../primitives/state-machine" } +sp-trie = { path = "../../../../primitives/trie" } +trie-db = { version = "0.23.1" } + +jsonrpc-core = "18.0.0" +jsonrpc-core-client = "18.0.0" +jsonrpc-derive = "18.0.0" + +# Substrate Dependencies +sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } +sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } + +[dev-dependencies] +serde_json = "1" diff --git a/utils/frame/rpc/state-trie-migration-rpc/README.md b/utils/frame/rpc/state-trie-migration-rpc/README.md new file mode 100644 index 0000000000000..03bbfdf1b5939 --- /dev/null +++ b/utils/frame/rpc/state-trie-migration-rpc/README.md @@ -0,0 +1,3 @@ +Node-specific RPC methods for interaction with trie migration. + +License: Apache-2.0 diff --git a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs new file mode 100644 index 0000000000000..98a3cf964843c --- /dev/null +++ b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -0,0 +1,164 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Rpc for state migration. + +use jsonrpc_core::{Error, ErrorCode, Result}; +use jsonrpc_derive::rpc; +use sc_rpc_api::DenyUnsafe; +use serde::{Deserialize, Serialize}; +use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use std::sync::Arc; + +use sp_core::{ + storage::{ChildInfo, ChildType, PrefixedStorageKey}, + Hasher, +}; +use sp_state_machine::Backend; +use sp_trie::{trie_types::TrieDB, KeySpacedDB, Trie}; +use trie_db::{ + node::{NodePlan, ValuePlan}, + TrieDBNodeIterator, +}; + +fn count_migrate<'a, H: Hasher>( + storage: &'a dyn trie_db::HashDBRef>, + root: &'a H::Out, +) -> std::result::Result<(u64, TrieDB<'a, H>), String> { + let mut nb = 0u64; + let trie = TrieDB::new(storage, root).map_err(|e| format!("TrieDB creation error: {}", e))?; + let iter_node = + TrieDBNodeIterator::new(&trie).map_err(|e| format!("TrieDB node iterator error: {}", e))?; + for node in iter_node { + let node = node.map_err(|e| format!("TrieDB node iterator error: {}", e))?; + match node.2.node_plan() { + NodePlan::Leaf { value, .. } | NodePlan::NibbledBranch { value: Some(value), .. } => + if let ValuePlan::Inline(range) = value { + if (range.end - range.start) as u32 >= + sp_core::storage::TRIE_VALUE_NODE_THRESHOLD + { + nb += 1; + } + }, + _ => (), + } + } + Ok((nb, trie)) +} + +/// Check trie migration status. +pub fn migration_status(backend: &B) -> std::result::Result<(u64, u64), String> +where + H: Hasher, + H::Out: codec::Codec, + B: Backend, +{ + let trie_backend = if let Some(backend) = backend.as_trie_backend() { + backend + } else { + return Err("No access to trie from backend.".to_string()) + }; + let essence = trie_backend.essence(); + let (nb_to_migrate, trie) = count_migrate(essence, &essence.root())?; + + let mut nb_to_migrate_child = 0; + let mut child_roots: Vec<(ChildInfo, Vec)> = Vec::new(); + // get all child trie roots + for key_value in trie.iter().map_err(|e| format!("TrieDB node iterator error: {}", e))? { + let (key, value) = key_value.map_err(|e| format!("TrieDB node iterator error: {}", e))?; + if key[..].starts_with(sp_core::storage::well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX) + { + let prefixed_key = PrefixedStorageKey::new(key); + let (_type, unprefixed) = ChildType::from_prefixed_key(&prefixed_key).unwrap(); + child_roots.push((ChildInfo::new_default(unprefixed), value)); + } + } + for (child_info, root) in child_roots { + let mut child_root = H::Out::default(); + let storage = KeySpacedDB::new(essence, child_info.keyspace()); + + child_root.as_mut()[..].copy_from_slice(&root[..]); + nb_to_migrate_child += count_migrate(&storage, &child_root)?.0; + } + + Ok((nb_to_migrate, nb_to_migrate_child)) +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] +pub struct MigrationStatusResult { + top_remaining_to_migrate: u64, + child_remaining_to_migrate: u64, +} + +/// Migration RPC methods. +#[rpc] +pub trait StateMigrationApi { + /// Check current migration state. + /// + /// This call is performed locally without submitting any transactions. Thus executing this + /// won't change any state. Nonetheless it is a VERY costy call that should be + /// only exposed to trusted peers. + #[rpc(name = "state_trieMigrationStatus")] + fn call(&self, at: Option) -> Result; +} + +/// An implementation of state migration specific RPC methods. +pub struct MigrationRpc { + client: Arc, + backend: Arc, + deny_unsafe: DenyUnsafe, + _marker: std::marker::PhantomData<(B, BA)>, +} + +impl MigrationRpc { + /// Create new state migration rpc for the given reference to the client. + pub fn new(client: Arc, backend: Arc, deny_unsafe: DenyUnsafe) -> Self { + MigrationRpc { client, backend, deny_unsafe, _marker: Default::default() } + } +} + +impl StateMigrationApi<::Hash> for MigrationRpc +where + B: BlockT, + C: Send + Sync + 'static + sc_client_api::HeaderBackend, + BA: 'static + sc_client_api::backend::Backend, +{ + fn call(&self, at: Option<::Hash>) -> Result { + if let Err(err) = self.deny_unsafe.check_if_safe() { + return Err(err.into()) + } + + let block_id = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + let state = self.backend.state_at(block_id).map_err(error_into_rpc_err)?; + let (top, child) = migration_status(&state).map_err(error_into_rpc_err)?; + + Ok(MigrationStatusResult { + top_remaining_to_migrate: top, + child_remaining_to_migrate: child, + }) + } +} + +fn error_into_rpc_err(err: impl std::fmt::Display) -> Error { + Error { + code: ErrorCode::InternalError, + message: "Error while checking migration state".into(), + data: Some(err.to_string().into()), + } +} From 805475c248b8d5b1d85655ce9f6d0b55c9fd3925 Mon Sep 17 00:00:00 2001 From: Falco Hirschenberger Date: Wed, 16 Mar 2022 17:05:34 +0100 Subject: [PATCH 0601/1472] Prevent possible rocksdb-corruption by running benchmark-storage (#11040) * Prevent possible rocksdb-corruption by running benchmark-storage Also adds a `sanitize_key` function to strip path-prefixes from the db-keys (for databases that use prefixed keys such as rocksdb) fixes #10998 * Fix @cheme 's annotations. * Update utils/frame/benchmarking-cli/src/storage/write.rs Co-authored-by: Oliver Tale-Yazdi * Make logic match the name of bool flag `invert_inserts` * Remove unused lifetime Co-authored-by: Oliver Tale-Yazdi --- client/db/src/lib.rs | 8 +-- client/db/src/parity_db.rs | 4 ++ primitives/database/src/lib.rs | 5 ++ .../benchmarking-cli/src/storage/write.rs | 64 ++++++++++--------- 4 files changed, 46 insertions(+), 35 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index f451062de33ab..6a8a025f1f45f 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -107,7 +107,8 @@ pub type DbState = sp_state_machine::TrieBackend>>, HashFor>; /// Length of a [`DbHash`]. -pub const DB_HASH_LEN: usize = 32; +const DB_HASH_LEN: usize = 32; + /// Hash type that this backend uses for the database. pub type DbHash = sp_core::H256; @@ -1351,10 +1352,7 @@ impl Backend { let mut removal: u64 = 0; let mut bytes_removal: u64 = 0; for (mut key, (val, rc)) in operation.db_updates.drain() { - if !self.storage.prefix_keys { - // Strip prefix - key.drain(0..key.len() - DB_HASH_LEN); - }; + self.storage.db.sanitize_key(&mut key); if rc > 0 { ops += 1; bytes += key.len() as u64 + val.len() as u64; diff --git a/client/db/src/parity_db.rs b/client/db/src/parity_db.rs index c27d7b0d4b4db..c81a346bb023f 100644 --- a/client/db/src/parity_db.rs +++ b/client/db/src/parity_db.rs @@ -112,4 +112,8 @@ impl> Database for DbAdapter { fn supports_ref_counting(&self) -> bool { true } + + fn sanitize_key(&self, key: &mut Vec) { + let _prefix = key.drain(0..key.len() - crate::DB_HASH_LEN); + } } diff --git a/primitives/database/src/lib.rs b/primitives/database/src/lib.rs index 2d7c5fd6653e1..3ec62a2b78148 100644 --- a/primitives/database/src/lib.rs +++ b/primitives/database/src/lib.rs @@ -110,6 +110,11 @@ pub trait Database>: Send + Sync { fn supports_ref_counting(&self) -> bool { false } + + /// Remove a possible path-prefix from the key. + /// + /// Not all database implementations use a prefix for keys, so this function may be a noop. + fn sanitize_key(&self, _key: &mut Vec) {} } impl std::fmt::Debug for dyn Database { diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index eb9ba11f30696..94a0eea9728ff 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -17,7 +17,7 @@ use sc_cli::Result; use sc_client_api::UsageProvider; -use sc_client_db::{DbHash, DbState, DB_HASH_LEN}; +use sc_client_db::{DbHash, DbState}; use sp_api::StateBackend; use sp_blockchain::HeaderBackend; use sp_database::{ColumnId, Transaction}; @@ -27,7 +27,7 @@ use sp_runtime::{ }; use sp_trie::PrefixedMemoryDB; -use log::info; +use log::{info, trace}; use rand::prelude::*; use std::{fmt::Debug, sync::Arc, time::Instant}; @@ -50,7 +50,6 @@ impl StorageCmd { // Store the time that it took to write each value. let mut record = BenchRecord::default(); - let supports_rc = db.supports_ref_counting(); let block = BlockId::Number(client.usage_info().chain.best_number); let header = client.header(block)?.ok_or("Header not found")?; let original_root = *header.state_root(); @@ -62,15 +61,34 @@ impl StorageCmd { let mut rng = Self::setup_rng(); kvs.shuffle(&mut rng); + // Generate all random values first; Make sure there are no collisions with existing + // db entries, so we can rollback all additions without corrupting existing entries. + for (k, original_v) in kvs.iter_mut() { + 'retry: loop { + let mut new_v = vec![0; original_v.len()]; + // Create a random value to overwrite with. + // NOTE: We use a possibly higher entropy than the original value, + // could be improved but acts as an over-estimation which is fine for now. + rng.fill_bytes(&mut new_v[..]); + let new_kv = vec![(k.as_ref(), Some(new_v.as_ref()))]; + let (_, mut stx) = trie.storage_root(new_kv.iter().cloned(), self.state_version()); + for (mut k, (_, rc)) in stx.drain().into_iter() { + if rc > 0 { + db.sanitize_key(&mut k); + if db.get(state_col, &k).is_some() { + trace!("Benchmark-store key creation: Key collision detected, retry"); + continue 'retry + } + } + } + *original_v = new_v; + break + } + } + info!("Writing {} keys", kvs.len()); // Write each value in one commit. - for (k, original_v) in kvs.iter() { - // Create a random value to overwrite with. - // NOTE: We use a possibly higher entropy than the original value, - // could be improved but acts as an over-estimation which is fine for now. - let mut new_v = vec![0; original_v.len()]; - rng.fill_bytes(&mut new_v[..]); - + for (k, new_v) in kvs.iter() { // Interesting part here: let start = Instant::now(); // Create a TX that will modify the Trie in the DB and @@ -78,12 +96,12 @@ impl StorageCmd { let replace = vec![(k.as_ref(), Some(new_v.as_ref()))]; let (_, stx) = trie.storage_root(replace.iter().cloned(), self.state_version()); // Only the keep the insertions, since we do not want to benchmark pruning. - let tx = convert_tx::(stx.clone(), true, state_col, supports_rc); + let tx = convert_tx::(db.clone(), stx.clone(), false, state_col); db.commit(tx).map_err(|e| format!("Writing to the Database: {}", e))?; record.append(new_v.len(), start.elapsed())?; // Now undo the changes by removing what was added. - let tx = convert_tx::(stx.clone(), false, state_col, supports_rc); + let tx = convert_tx::(db.clone(), stx.clone(), true, state_col); db.commit(tx).map_err(|e| format!("Writing to the Database: {}", e))?; } Ok(record) @@ -93,35 +111,21 @@ impl StorageCmd { /// Converts a Trie transaction into a DB transaction. /// Removals are ignored and will not be included in the final tx. /// `invert_inserts` replaces all inserts with removals. -/// -/// The keys of Trie transactions are prefixed, this is treated differently by each DB. -/// ParityDB can use an optimization where only the last `DB_HASH_LEN` byte are needed. -/// The last `DB_HASH_LEN` byte are the hash of the actual stored data, everything -/// before that is the route in the Patricia Trie. -/// RocksDB cannot do this and needs the whole route, hence no key truncating for RocksDB. -/// -/// TODO: -/// This copies logic from [`sp_client_db::Backend::try_commit_operation`] and should be -/// refactored to use a canonical `sanitize_key` function from `sp_client_db` which -/// does not yet exist. fn convert_tx( + db: Arc>, mut tx: PrefixedMemoryDB>, invert_inserts: bool, col: ColumnId, - supports_rc: bool, ) -> Transaction { let mut ret = Transaction::::default(); for (mut k, (v, rc)) in tx.drain().into_iter() { - if supports_rc { - let _prefix = k.drain(0..k.len() - DB_HASH_LEN); - } - if rc > 0 { + db.sanitize_key(&mut k); if invert_inserts { - ret.set(col, k.as_ref(), &v); - } else { ret.remove(col, &k); + } else { + ret.set(col, &k, &v); } } // < 0 means removal - ignored. From cf69667d603943badcf7a17e67cbb0a727a65ac0 Mon Sep 17 00:00:00 2001 From: Georges Date: Wed, 16 Mar 2022 21:27:19 +0000 Subject: [PATCH 0602/1472] Moving `NposSolution` to frame (#11031) * Move `sp-npos-elections-solution-type` to `frame-election-provider-support` First stab at it, will need to amend some more stuff * Fixing tests * Fixing tests * Fixing cargo.toml for std configuration * fmt * Committing suggested changes renaming, and re exporting macro. * Removing unneeded imports * Move `NposSolution` to frame * Removing `npos_election` dependencies Implementing _fpes better * some feedback for moving NPoSSolution to frame * fmt * more formatting * Fixed some imports and fmt * Fixing docs Co-authored-by: kianenigma --- Cargo.lock | 4 +- bin/node/runtime/Cargo.toml | 2 - bin/node/runtime/src/lib.rs | 16 +-- .../src/benchmarking.rs | 2 +- .../election-provider-multi-phase/src/lib.rs | 5 +- .../election-provider-multi-phase/src/mock.rs | 4 +- .../src/signed.rs | 3 +- .../src/unsigned.rs | 12 +- .../solution-type/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 1 + .../solution-type/src/codec.rs | 72 +++++----- .../solution-type/src/lib.rs | 14 +- .../solution-type/src/single_page.rs | 62 ++++---- frame/election-provider-support/src/lib.rs | 77 +++++++++- frame/election-provider-support/src/traits.rs | 129 +++++++++++++++++ frame/staking/src/pallet/mod.rs | 8 +- primitives/npos-elections/src/assignments.rs | 43 +----- primitives/npos-elections/src/lib.rs | 18 +-- primitives/npos-elections/src/traits.rs | 132 +----------------- 19 files changed, 313 insertions(+), 293 deletions(-) create mode 100644 frame/election-provider-support/src/traits.rs diff --git a/Cargo.lock b/Cargo.lock index e2321d7fa99d8..d3cc9ab0d4320 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2164,13 +2164,13 @@ dependencies = [ name = "frame-election-provider-solution-type" version = "4.0.0-dev" dependencies = [ + "frame-election-provider-support", "parity-scale-codec", "proc-macro-crate 1.1.0", "proc-macro2", "quote", "scale-info", "sp-arithmetic", - "sp-npos-elections", "syn", "trybuild", ] @@ -2198,6 +2198,7 @@ version = "2.0.0-alpha.5" dependencies = [ "clap 3.1.6", "frame-election-provider-solution-type", + "frame-election-provider-support", "honggfuzz", "parity-scale-codec", "rand 0.8.4", @@ -5065,7 +5066,6 @@ dependencies = [ "sp-core", "sp-inherents", "sp-io", - "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-sandbox", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 0572345fa0c89..686508b47dba1 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -38,7 +38,6 @@ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../.. sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } -sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" } sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } @@ -178,7 +177,6 @@ std = [ "pallet-vesting/std", "log/std", "frame-try-runtime/std", - "sp-npos-elections/std", "sp-io/std", "pallet-child-bounties/std", ] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 20b718e2fa8f7..797e0c079028e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -23,9 +23,11 @@ #![recursion_limit = "256"] use codec::{Decode, Encode, MaxEncodedLen}; -use frame_election_provider_support::onchain; +use frame_election_provider_support::{onchain, ExtendedBalance, VoteWeight}; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, + pallet_prelude::Get, + parameter_types, traits::{ AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EnsureOneOf, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, @@ -598,7 +600,7 @@ frame_election_provider_support::generate_solution_type!( ); parameter_types! { - pub MaxNominations: u32 = ::LIMIT as u32; + pub MaxNominations: u32 = ::LIMIT as u32; } /// The numbers configured here could always be more than the the maximum limits of staking pallet @@ -621,10 +623,8 @@ pub const MINER_MAX_ITERATIONS: u32 = 10; /// A source of random balance for NposSolver, which is meant to be run by the OCW election miner. pub struct OffchainRandomBalancing; -impl frame_support::pallet_prelude::Get> - for OffchainRandomBalancing -{ - fn get() -> Option<(usize, sp_npos_elections::ExtendedBalance)> { +impl Get> for OffchainRandomBalancing { + fn get() -> Option<(usize, ExtendedBalance)> { use sp_runtime::traits::TrailingZeroInput; let iters = match MINER_MAX_ITERATIONS { 0 => 0, @@ -693,7 +693,7 @@ impl pallet_bags_list::Config for Runtime { type ScoreProvider = Staking; type WeightInfo = pallet_bags_list::weights::SubstrateWeight; type BagThresholds = BagThresholds; - type Score = sp_npos_elections::VoteWeight; + type Score = VoteWeight; } parameter_types! { diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 479afd9843386..b331516a4e797 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -28,7 +28,6 @@ use frame_support::{ use frame_system::RawOrigin; use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng}; use sp_arithmetic::{per_things::Percent, traits::One}; -use sp_npos_elections::IndexAssignment; use sp_runtime::InnerOf; const SEED: u32 = 999; @@ -461,6 +460,7 @@ frame_benchmarking::benchmarks! { T::BenchmarkingConfig::DESIRED_TARGETS[1]; // Subtract this percentage from the actual encoded size let f in 0 .. 95; + use frame_election_provider_support::IndexAssignment; // Compute a random solution, then work backwards to get the lists of voters, targets, and // assignments diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 7e211c5ee9211..b366ceb4dafe3 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -231,7 +231,7 @@ use codec::{Decode, Encode}; use frame_election_provider_support::{ - ElectionDataProvider, ElectionProvider, InstantElectionProvider, + ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolution, }; use frame_support::{ dispatch::DispatchResultWithPostInfo, @@ -246,8 +246,7 @@ use sp_arithmetic::{ UpperOf, }; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, ElectionScore, EvaluateSupport, NposSolution, Supports, - VoteWeight, + assignment_ratio_to_staked_normalized, ElectionScore, EvaluateSupport, Supports, VoteWeight, }; use sp_runtime::{ traits::Bounded, diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 7c4ef5d8055c3..d09d45784cba4 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -18,7 +18,7 @@ use super::*; use crate as multi_phase; use frame_election_provider_support::{ - data_provider, onchain, ElectionDataProvider, SequentialPhragmen, + data_provider, onchain, ElectionDataProvider, NposSolution, SequentialPhragmen, }; pub use frame_support::{assert_noop, assert_ok}; use frame_support::{ @@ -38,7 +38,7 @@ use sp_core::{ }; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, ElectionResult, - EvaluateSupport, ExtendedBalance, NposSolution, + EvaluateSupport, ExtendedBalance, }; use sp_runtime::{ testing::Header, diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index a233346b4fd77..82b40e3276036 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -23,12 +23,13 @@ use crate::{ SolutionOrSnapshotSize, Weight, WeightInfo, }; use codec::{Decode, Encode, HasCompact}; +use frame_election_provider_support::NposSolution; use frame_support::{ storage::bounded_btree_map::BoundedBTreeMap, traits::{defensive_prelude::*, Currency, Get, OnUnbalanced, ReservableCurrency}, }; use sp_arithmetic::traits::SaturatedConversion; -use sp_npos_elections::{ElectionScore, NposSolution}; +use sp_npos_elections::ElectionScore; use sp_runtime::{ traits::{Saturating, Zero}, RuntimeDebug, diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 81ea4453d0964..3380a61d4310e 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -23,12 +23,11 @@ use crate::{ WeightInfo, }; use codec::Encode; -use frame_election_provider_support::{NposSolver, PerThing128}; +use frame_election_provider_support::{NposSolution, NposSolver, PerThing128}; use frame_support::{dispatch::DispatchResult, ensure, traits::Get}; use frame_system::offchain::SubmitTransaction; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, ElectionResult, - NposSolution, }; use sp_runtime::{ offchain::storage::{MutateStorageError, StorageValueRef}, @@ -52,9 +51,9 @@ pub type VoterOf = frame_election_provider_support::VoterOf<::Da pub type Assignment = sp_npos_elections::Assignment<::AccountId, SolutionAccuracyOf>; -/// The [`IndexAssignment`][sp_npos_elections::IndexAssignment] type specialized for a particular -/// runtime `T`. -pub type IndexAssignmentOf = sp_npos_elections::IndexAssignmentOf>; +/// The [`IndexAssignment`][frame_election_provider_support::IndexAssignment] type specialized for a +/// particular runtime `T`. +pub type IndexAssignmentOf = frame_election_provider_support::IndexAssignmentOf>; /// Error type of the pallet's [`crate::Config::Solver`]. pub type SolverErrorOf = <::Solver as NposSolver>::Error; @@ -742,10 +741,11 @@ mod tests { }; use codec::Decode; use frame_benchmarking::Zero; + use frame_election_provider_support::IndexAssignment; use frame_support::{ assert_noop, assert_ok, bounded_vec, dispatch::Dispatchable, traits::OffchainWorker, }; - use sp_npos_elections::{ElectionScore, IndexAssignment}; + use sp_npos_elections::ElectionScore; use sp_runtime::{ offchain::storage_lock::{BlockAndTime, StorageLock}, traits::ValidateUnsigned, diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index d489c7b4c10de..09747eebe2dff 100644 --- a/frame/election-provider-support/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -25,5 +25,5 @@ parity-scale-codec = "3.0.0" scale-info = "2.0.1" sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } # used by generate_solution_type: -sp-npos-elections = { version = "4.0.0-dev", path = "../../../primitives/npos-elections" } +frame-election-provider-support = { version = "4.0.0-dev", path = ".." } trybuild = "1.0.53" diff --git a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index f52b7f7332620..f6c2f2fe491e8 100644 --- a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -20,6 +20,7 @@ rand = { version = "0.8", features = ["std", "small_rng"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { version = "4.0.0-dev", path = ".." } +frame-election-provider-support = { version = "4.0.0-dev", path = "../.." } sp-arithmetic = { version = "5.0.0", path = "../../../../primitives/arithmetic" } sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } # used by generate_solution_type: diff --git a/frame/election-provider-support/solution-type/src/codec.rs b/frame/election-provider-support/solution-type/src/codec.rs index 71faa141f0b69..05d753d3d8456 100644 --- a/frame/election-provider-support/solution-type/src/codec.rs +++ b/frame/election-provider-support/solution-type/src/codec.rs @@ -51,14 +51,14 @@ fn decode_impl( quote! { let #name = < - _npos::sp_std::prelude::Vec<(_npos::codec::Compact<#voter_type>, _npos::codec::Compact<#target_type>)> + _feps::sp_std::prelude::Vec<(_feps::codec::Compact<#voter_type>, _feps::codec::Compact<#target_type>)> as - _npos::codec::Decode + _feps::codec::Decode >::decode(value)?; let #name = #name .into_iter() .map(|(v, t)| (v.0, t.0)) - .collect::<_npos::sp_std::prelude::Vec<_>>(); + .collect::<_feps::sp_std::prelude::Vec<_>>(); } }; @@ -73,12 +73,12 @@ fn decode_impl( quote! { let #name = < - _npos::sp_std::prelude::Vec<( - _npos::codec::Compact<#voter_type>, - [(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>); #c-1], - _npos::codec::Compact<#target_type>, + _feps::sp_std::prelude::Vec<( + _feps::codec::Compact<#voter_type>, + [(_feps::codec::Compact<#target_type>, _feps::codec::Compact<#weight_type>); #c-1], + _feps::codec::Compact<#target_type>, )> - as _npos::codec::Decode + as _feps::codec::Decode >::decode(value)?; let #name = #name .into_iter() @@ -87,7 +87,7 @@ fn decode_impl( [ #inner_impl ], t_last.0, )) - .collect::<_npos::sp_std::prelude::Vec<_>>(); + .collect::<_feps::sp_std::prelude::Vec<_>>(); } }) .collect::(); @@ -100,8 +100,8 @@ fn decode_impl( .collect::(); quote!( - impl _npos::codec::Decode for #ident { - fn decode(value: &mut I) -> Result { + impl _feps::codec::Decode for #ident { + fn decode(value: &mut I) -> Result { #decode_impl_single #decode_impl_rest @@ -123,10 +123,10 @@ fn encode_impl(ident: &syn::Ident, count: usize) -> TokenStream2 { let #name = self.#name .iter() .map(|(v, t)| ( - _npos::codec::Compact(v.clone()), - _npos::codec::Compact(t.clone()), + _feps::codec::Compact(v.clone()), + _feps::codec::Compact(t.clone()), )) - .collect::<_npos::sp_std::prelude::Vec<_>>(); + .collect::<_feps::sp_std::prelude::Vec<_>>(); #name.encode_to(&mut r); } }; @@ -139,8 +139,8 @@ fn encode_impl(ident: &syn::Ident, count: usize) -> TokenStream2 { let inners_solution_array = (0..c - 1) .map(|i| { quote! {( - _npos::codec::Compact(inner[#i].0.clone()), - _npos::codec::Compact(inner[#i].1.clone()), + _feps::codec::Compact(inner[#i].0.clone()), + _feps::codec::Compact(inner[#i].1.clone()), ),} }) .collect::(); @@ -149,19 +149,19 @@ fn encode_impl(ident: &syn::Ident, count: usize) -> TokenStream2 { let #name = self.#name .iter() .map(|(v, inner, t_last)| ( - _npos::codec::Compact(v.clone()), + _feps::codec::Compact(v.clone()), [ #inners_solution_array ], - _npos::codec::Compact(t_last.clone()), + _feps::codec::Compact(t_last.clone()), )) - .collect::<_npos::sp_std::prelude::Vec<_>>(); + .collect::<_feps::sp_std::prelude::Vec<_>>(); #name.encode_to(&mut r); } }) .collect::(); quote!( - impl _npos::codec::Encode for #ident { - fn encode(&self) -> _npos::sp_std::prelude::Vec { + impl _feps::codec::Encode for #ident { + fn encode(&self) -> _feps::sp_std::prelude::Vec { let mut r = vec![]; #encode_impl_single #encode_impl_rest @@ -182,8 +182,8 @@ fn scale_info_impl( let name = format!("{}", vote_field(1)); quote! { .field(|f| - f.ty::<_npos::sp_std::prelude::Vec< - (_npos::codec::Compact<#voter_type>, _npos::codec::Compact<#target_type>) + f.ty::<_feps::sp_std::prelude::Vec< + (_feps::codec::Compact<#voter_type>, _feps::codec::Compact<#target_type>) >>() .name(#name) ) @@ -194,10 +194,10 @@ fn scale_info_impl( let name = format!("{}", vote_field(2)); quote! { .field(|f| - f.ty::<_npos::sp_std::prelude::Vec<( - _npos::codec::Compact<#voter_type>, - (_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>), - _npos::codec::Compact<#target_type> + f.ty::<_feps::sp_std::prelude::Vec<( + _feps::codec::Compact<#voter_type>, + (_feps::codec::Compact<#target_type>, _feps::codec::Compact<#weight_type>), + _feps::codec::Compact<#target_type> )>>() .name(#name) ) @@ -209,13 +209,13 @@ fn scale_info_impl( let name = format!("{}", vote_field(c)); quote! { .field(|f| - f.ty::<_npos::sp_std::prelude::Vec<( - _npos::codec::Compact<#voter_type>, + f.ty::<_feps::sp_std::prelude::Vec<( + _feps::codec::Compact<#voter_type>, [ - (_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>); + (_feps::codec::Compact<#target_type>, _feps::codec::Compact<#weight_type>); #c - 1 ], - _npos::codec::Compact<#target_type> + _feps::codec::Compact<#target_type> )>>() .name(#name) ) @@ -224,14 +224,14 @@ fn scale_info_impl( .collect::(); quote!( - impl _npos::scale_info::TypeInfo for #ident { + impl _feps::scale_info::TypeInfo for #ident { type Identity = Self; - fn type_info() -> _npos::scale_info::Type<_npos::scale_info::form::MetaForm> { - _npos::scale_info::Type::builder() - .path(_npos::scale_info::Path::new(stringify!(#ident), module_path!())) + fn type_info() -> _feps::scale_info::Type<_feps::scale_info::form::MetaForm> { + _feps::scale_info::Type::builder() + .path(_feps::scale_info::Path::new(stringify!(#ident), module_path!())) .composite( - _npos::scale_info::build::Fields::named() + _feps::scale_info::build::Fields::named() #scale_info_impl_single #scale_info_impl_double #scale_info_impl_rest diff --git a/frame/election-provider-support/solution-type/src/lib.rs b/frame/election-provider-support/solution-type/src/lib.rs index 3de923cdffd03..6e2788f06007f 100644 --- a/frame/election-provider-support/solution-type/src/lib.rs +++ b/frame/election-provider-support/solution-type/src/lib.rs @@ -88,7 +88,7 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error { /// ``` /// /// The given struct provides function to convert from/to `Assignment` as part of -/// `sp_npos_elections::Solution` trait: +/// `frame_election_provider_support::NposSolution` trait: /// /// - `fn from_assignment<..>(..)` /// - `fn into_assignment<..>(..)` @@ -101,7 +101,7 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error { /// /// ``` /// # use frame_election_provider_solution_type::generate_solution_type; -/// # use sp_npos_elections::NposSolution; +/// # use frame_election_provider_support::NposSolution; /// # use sp_arithmetic::per_things::Perbill; /// generate_solution_type!( /// #[compact] @@ -226,11 +226,11 @@ where } fn imports() -> Result { - match crate_name("sp-npos-elections") { - Ok(FoundCrate::Itself) => Ok(quote! { use crate as _npos; }), - Ok(FoundCrate::Name(sp_npos_elections)) => { - let ident = syn::Ident::new(&sp_npos_elections, Span::call_site()); - Ok(quote!( extern crate #ident as _npos; )) + match crate_name("frame-election-provider-support") { + Ok(FoundCrate::Itself) => Ok(quote! { use crate as _feps; }), + Ok(FoundCrate::Name(frame_election_provider_support)) => { + let ident = syn::Ident::new(&frame_election_provider_support, Span::call_site()); + Ok(quote!( extern crate #ident as _feps; )) }, Err(e) => Err(syn::Error::new(Span::call_site(), e)), } diff --git a/frame/election-provider-support/solution-type/src/single_page.rs b/frame/election-provider-support/solution-type/src/single_page.rs index 01a8a8eba5dcc..c1d897444da31 100644 --- a/frame/election-provider-support/solution-type/src/single_page.rs +++ b/frame/election-provider-support/solution-type/src/single_page.rs @@ -39,7 +39,7 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { let name = vote_field(1); // NOTE: we use the visibility of the struct for the fields as well.. could be made better. quote!( - #vis #name: _npos::sp_std::prelude::Vec<(#voter_type, #target_type)>, + #vis #name: _feps::sp_std::prelude::Vec<(#voter_type, #target_type)>, ) }; @@ -48,7 +48,7 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { let field_name = vote_field(c); let array_len = c - 1; quote!( - #vis #field_name: _npos::sp_std::prelude::Vec<( + #vis #field_name: _feps::sp_std::prelude::Vec<( #voter_type, [(#target_type, #weight_type); #array_len], #target_type @@ -83,9 +83,9 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { Eq, Clone, Debug, - _npos::codec::Encode, - _npos::codec::Decode, - _npos::scale_info::TypeInfo, + _feps::codec::Encode, + _feps::codec::Decode, + _feps::scale_info::TypeInfo, )]) }; @@ -101,8 +101,8 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { #derives_and_maybe_compact_encoding #vis struct #ident { #single #rest } - use _npos::__OrInvalidIndex; - impl _npos::NposSolution for #ident { + use _feps::__OrInvalidIndex; + impl _feps::NposSolution for #ident { const LIMIT: usize = #count; type VoterIndex = #voter_type; type TargetIndex = #target_type; @@ -114,34 +114,34 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { } fn from_assignment( - assignments: &[_npos::Assignment], + assignments: &[_feps::Assignment], voter_index: FV, target_index: FT, - ) -> Result + ) -> Result where - A: _npos::IdentifierT, + A: _feps::IdentifierT, for<'r> FV: Fn(&'r A) -> Option, for<'r> FT: Fn(&'r A) -> Option, { let mut #struct_name: #ident = Default::default(); - for _npos::Assignment { who, distribution } in assignments { + for _feps::Assignment { who, distribution } in assignments { match distribution.len() { 0 => continue, #from_impl _ => { - return Err(_npos::Error::SolutionTargetOverflow); + return Err(_feps::Error::SolutionTargetOverflow); } } }; Ok(#struct_name) } - fn into_assignment( + fn into_assignment( self, voter_at: impl Fn(Self::VoterIndex) -> Option, target_at: impl Fn(Self::TargetIndex) -> Option, - ) -> Result<_npos::sp_std::prelude::Vec<_npos::Assignment>, _npos::Error> { - let mut #assignment_name: _npos::sp_std::prelude::Vec<_npos::Assignment> = Default::default(); + ) -> Result<_feps::sp_std::prelude::Vec<_feps::Assignment>, _feps::Error> { + let mut #assignment_name: _feps::sp_std::prelude::Vec<_feps::Assignment> = Default::default(); #into_impl Ok(#assignment_name) } @@ -158,10 +158,10 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { all_edges } - fn unique_targets(&self) -> _npos::sp_std::prelude::Vec { + fn unique_targets(&self) -> _feps::sp_std::prelude::Vec { // NOTE: this implementation returns the targets sorted, but we don't use it yet per // se, nor is the API enforcing it. - use _npos::sp_std::collections::btree_set::BTreeSet; + use _feps::sp_std::collections::btree_set::BTreeSet; let mut all_targets: BTreeSet = BTreeSet::new(); let mut maybe_insert_target = |t: Self::TargetIndex| { all_targets.insert(t); @@ -173,22 +173,22 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { } } - type __IndexAssignment = _npos::IndexAssignment< - <#ident as _npos::NposSolution>::VoterIndex, - <#ident as _npos::NposSolution>::TargetIndex, - <#ident as _npos::NposSolution>::Accuracy, + type __IndexAssignment = _feps::IndexAssignment< + <#ident as _feps::NposSolution>::VoterIndex, + <#ident as _feps::NposSolution>::TargetIndex, + <#ident as _feps::NposSolution>::Accuracy, >; - impl<'a> _npos::sp_std::convert::TryFrom<&'a [__IndexAssignment]> for #ident { - type Error = _npos::Error; + impl<'a> _feps::sp_std::convert::TryFrom<&'a [__IndexAssignment]> for #ident { + type Error = _feps::Error; fn try_from(index_assignments: &'a [__IndexAssignment]) -> Result { let mut #struct_name = #ident::default(); - for _npos::IndexAssignment { who, distribution } in index_assignments { + for _feps::IndexAssignment { who, distribution } in index_assignments { match distribution.len() { 0 => {} #from_index_impl _ => { - return Err(_npos::Error::SolutionTargetOverflow); + return Err(_feps::Error::SolutionTargetOverflow); } } }; @@ -310,7 +310,7 @@ pub(crate) fn into_impl( let name = vote_field(1); quote!( for (voter_index, target_index) in self.#name { - #assignments.push(_npos::Assignment { + #assignments.push(_feps::Assignment { who: voter_at(voter_index).or_invalid_index()?, distribution: vec![ (target_at(target_index).or_invalid_index()?, #per_thing::one()) @@ -329,25 +329,25 @@ pub(crate) fn into_impl( let mut inners_parsed = inners .iter() .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + sum = _feps::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); let target = target_at(*t_idx).or_invalid_index()?; Ok((target, *p)) }) - .collect::, _npos::Error>>()?; + .collect::, _feps::Error>>()?; if sum >= #per_thing::one() { - return Err(_npos::Error::SolutionWeightOverflow); + return Err(_feps::Error::SolutionWeightOverflow); } // defensive only. Since Percent doesn't have `Sub`. - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + let p_last = _feps::sp_arithmetic::traits::Saturating::saturating_sub( #per_thing::one(), sum, ); inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - #assignments.push(_npos::Assignment { + #assignments.push(_feps::Assignment { who: voter_at(voter_index).or_invalid_index()?, distribution: inners_parsed, }); diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 1bd10ba09346f..ca95eda6b5095 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -167,17 +167,86 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod onchain; -use frame_support::{traits::Get, BoundedVec}; +pub mod traits; +use codec::{Decode, Encode}; +use frame_support::{traits::Get, BoundedVec, RuntimeDebug}; use sp_runtime::traits::Bounded; use sp_std::{fmt::Debug, prelude::*}; -/// Re-export some type as they are used in the interface. +/// Re-export the solution generation macro. pub use frame_election_provider_solution_type::generate_solution_type; +/// Re-export some type as they are used in the interface. pub use sp_arithmetic::PerThing; pub use sp_npos_elections::{ - Assignment, ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Support, Supports, - VoteWeight, + Assignment, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128, Support, + Supports, VoteWeight, }; +pub use traits::NposSolution; + +// re-export for the solution macro, with the dependencies of the macro. +#[doc(hidden)] +pub use codec; +#[doc(hidden)] +pub use scale_info; +#[doc(hidden)] +pub use sp_arithmetic; +#[doc(hidden)] +pub use sp_std; +// Simple Extension trait to easily convert `None` from index closures to `Err`. +// +// This is only generated and re-exported for the solution code to use. +#[doc(hidden)] +pub trait __OrInvalidIndex { + fn or_invalid_index(self) -> Result; +} + +impl __OrInvalidIndex for Option { + fn or_invalid_index(self) -> Result { + self.ok_or(Error::SolutionInvalidIndex) + } +} + +/// The [`IndexAssignment`] type is an intermediate between the assignments list +/// ([`&[Assignment]`][Assignment]) and `SolutionOf`. +/// +/// The voter and target identifiers have already been replaced with appropriate indices, +/// making it fast to repeatedly encode into a `SolutionOf`. This property turns out +/// to be important when trimming for solution length. +#[derive(RuntimeDebug, Clone, Default)] +#[cfg_attr(feature = "std", derive(PartialEq, Eq, Encode, Decode))] +pub struct IndexAssignment { + /// Index of the voter among the voters list. + pub who: VoterIndex, + /// The distribution of the voter's stake among winning targets. + /// + /// Targets are identified by their index in the canonical list. + pub distribution: Vec<(TargetIndex, P)>, +} + +impl IndexAssignment { + pub fn new( + assignment: &Assignment, + voter_index: impl Fn(&AccountId) -> Option, + target_index: impl Fn(&AccountId) -> Option, + ) -> Result { + Ok(Self { + who: voter_index(&assignment.who).or_invalid_index()?, + distribution: assignment + .distribution + .iter() + .map(|(target, proportion)| Some((target_index(target)?, proportion.clone()))) + .collect::>>() + .or_invalid_index()?, + }) + } +} + +/// A type alias for [`IndexAssignment`] made from [`NposSolution`]. +pub type IndexAssignmentOf = IndexAssignment< + ::VoterIndex, + ::TargetIndex, + ::Accuracy, +>; /// Types that are used by the data provider trait. pub mod data_provider { diff --git a/frame/election-provider-support/src/traits.rs b/frame/election-provider-support/src/traits.rs new file mode 100644 index 0000000000000..e1fc0663e7d1e --- /dev/null +++ b/frame/election-provider-support/src/traits.rs @@ -0,0 +1,129 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Traits for the election operations. + +use crate::{Assignment, IdentifierT, IndexAssignmentOf, PerThing128, VoteWeight}; +use codec::Encode; +use scale_info::TypeInfo; +use sp_arithmetic::traits::{Bounded, UniqueSaturatedInto}; +use sp_npos_elections::{ElectionScore, Error, EvaluateSupport}; +use sp_std::{ + convert::{TryFrom, TryInto}, + fmt::Debug, + prelude::*, +}; + +/// An opaque index-based, NPoS solution type. +pub trait NposSolution +where + Self: Sized + for<'a> sp_std::convert::TryFrom<&'a [IndexAssignmentOf], Error = Error>, +{ + /// The maximum number of votes that are allowed. + const LIMIT: usize; + + /// The voter type. Needs to be an index (convert to usize). + type VoterIndex: UniqueSaturatedInto + + TryInto + + TryFrom + + Debug + + Copy + + Clone + + Bounded + + Encode + + TypeInfo; + + /// The target type. Needs to be an index (convert to usize). + type TargetIndex: UniqueSaturatedInto + + TryInto + + TryFrom + + Debug + + Copy + + Clone + + Bounded + + Encode + + TypeInfo; + + /// The weight/accuracy type of each vote. + type Accuracy: PerThing128; + + /// Get the length of all the voters that this type is encoding. + /// + /// This is basically the same as the number of assignments, or number of active voters. + fn voter_count(&self) -> usize; + + /// Get the total count of edges. + /// + /// This is effectively in the range of {[`Self::voter_count`], [`Self::voter_count`] * + /// [`Self::LIMIT`]}. + fn edge_count(&self) -> usize; + + /// Get the number of unique targets in the whole struct. + /// + /// Once presented with a list of winners, this set and the set of winners must be + /// equal. + fn unique_targets(&self) -> Vec; + + /// Get the average edge count. + fn average_edge_count(&self) -> usize { + self.edge_count().checked_div(self.voter_count()).unwrap_or(0) + } + + /// Compute the score of this solution type. + fn score( + self, + stake_of: FS, + voter_at: impl Fn(Self::VoterIndex) -> Option, + target_at: impl Fn(Self::TargetIndex) -> Option, + ) -> Result + where + for<'r> FS: Fn(&'r A) -> VoteWeight, + A: IdentifierT, + { + let ratio = self.into_assignment(voter_at, target_at)?; + let staked = + sp_npos_elections::helpers::assignment_ratio_to_staked_normalized(ratio, stake_of)?; + let supports = sp_npos_elections::to_supports(&staked); + Ok(supports.evaluate()) + } + + /// Remove a certain voter. + /// + /// This will only search until the first instance of `to_remove`, and return true. If + /// no instance is found (no-op), then it returns false. + /// + /// In other words, if this return true, exactly **one** element must have been removed self. + fn remove_voter(&mut self, to_remove: Self::VoterIndex) -> bool; + + /// Build self from a list of assignments. + fn from_assignment( + assignments: &[Assignment], + voter_index: FV, + target_index: FT, + ) -> Result + where + A: IdentifierT, + for<'r> FV: Fn(&'r A) -> Option, + for<'r> FT: Fn(&'r A) -> Option; + + /// Convert self into a `Vec>` + fn into_assignment( + self, + voter_at: impl Fn(Self::VoterIndex) -> Option, + target_at: impl Fn(Self::TargetIndex) -> Option, + ) -> Result>, Error>; +} diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index b50ce5ed4502c..39173bf61c833 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -40,9 +40,9 @@ mod impls; pub use impls::*; use crate::{ - log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints, - Exposure, Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, - Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, + slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints, Exposure, + Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, Releases, + RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, }; @@ -554,7 +554,7 @@ pub mod pallet { } for &(ref stash, ref controller, balance, ref status) in &self.stakers { - log!( + crate::log!( trace, "inserting genesis staker: {:?} => {:?} => {:?}", stash, diff --git a/primitives/npos-elections/src/assignments.rs b/primitives/npos-elections/src/assignments.rs index 5641a33447bad..9422ccdf65884 100644 --- a/primitives/npos-elections/src/assignments.rs +++ b/primitives/npos-elections/src/assignments.rs @@ -17,7 +17,7 @@ //! Structs and helpers for distributing a voter's stake among various winners. -use crate::{Error, ExtendedBalance, IdentifierT, PerThing128, __OrInvalidIndex}; +use crate::{ExtendedBalance, IdentifierT, PerThing128}; #[cfg(feature = "std")] use codec::{Decode, Encode}; use sp_arithmetic::{ @@ -166,44 +166,3 @@ impl StakedAssignment { self.distribution.iter().fold(Zero::zero(), |a, b| a.saturating_add(b.1)) } } -/// The [`IndexAssignment`] type is an intermediate between the assignments list -/// ([`&[Assignment]`][Assignment]) and `SolutionOf`. -/// -/// The voter and target identifiers have already been replaced with appropriate indices, -/// making it fast to repeatedly encode into a `SolutionOf`. This property turns out -/// to be important when trimming for solution length. -#[derive(RuntimeDebug, Clone, Default)] -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Encode, Decode))] -pub struct IndexAssignment { - /// Index of the voter among the voters list. - pub who: VoterIndex, - /// The distribution of the voter's stake among winning targets. - /// - /// Targets are identified by their index in the canonical list. - pub distribution: Vec<(TargetIndex, P)>, -} - -impl IndexAssignment { - pub fn new( - assignment: &Assignment, - voter_index: impl Fn(&AccountId) -> Option, - target_index: impl Fn(&AccountId) -> Option, - ) -> Result { - Ok(Self { - who: voter_index(&assignment.who).or_invalid_index()?, - distribution: assignment - .distribution - .iter() - .map(|(target, proportion)| Some((target_index(target)?, proportion.clone()))) - .collect::>>() - .or_invalid_index()?, - }) - } -} - -/// A type alias for [`IndexAssignment`] made from [`crate::NposSolution`]. -pub type IndexAssignmentOf = IndexAssignment< - ::VoterIndex, - ::TargetIndex, - ::Accuracy, ->; diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 673036c2d19d1..11d531fa56d87 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -100,26 +100,16 @@ pub mod pjr; pub mod reduce; pub mod traits; -pub use assignments::{Assignment, IndexAssignment, IndexAssignmentOf, StakedAssignment}; +pub use assignments::{Assignment, StakedAssignment}; pub use balancing::*; pub use helpers::*; pub use phragmen::*; pub use phragmms::*; pub use pjr::*; pub use reduce::reduce; -pub use traits::{IdentifierT, NposSolution, PerThing128, __OrInvalidIndex}; - -// re-export for the solution macro, with the dependencies of the macro. -#[doc(hidden)] -pub use codec; -#[doc(hidden)] -pub use scale_info; -#[doc(hidden)] -pub use sp_arithmetic; -#[doc(hidden)] -pub use sp_std; - -/// The errors that might occur in the this crate and solution-type. +pub use traits::{IdentifierT, PerThing128}; + +/// The errors that might occur in this crate and `frame-election-provider-solution-type`. #[derive(Eq, PartialEq, RuntimeDebug)] pub enum Error { /// While going from solution indices to ratio, the weight of all the edges has gone above the diff --git a/primitives/npos-elections/src/traits.rs b/primitives/npos-elections/src/traits.rs index 0723948b62269..91026f9de4b6b 100644 --- a/primitives/npos-elections/src/traits.rs +++ b/primitives/npos-elections/src/traits.rs @@ -17,22 +17,9 @@ //! Traits for the npos-election operations. -use crate::{ - Assignment, ElectionScore, Error, EvaluateSupport, ExtendedBalance, IndexAssignmentOf, - VoteWeight, -}; -use codec::Encode; -use scale_info::TypeInfo; -use sp_arithmetic::{ - traits::{Bounded, UniqueSaturatedInto}, - PerThing, -}; -use sp_std::{ - convert::{TryFrom, TryInto}, - fmt::Debug, - ops::Mul, - prelude::*, -}; +use crate::ExtendedBalance; +use sp_arithmetic::PerThing; +use sp_std::{fmt::Debug, ops::Mul, prelude::*}; /// an aggregator trait for a generic type of a voter/target identifier. This usually maps to /// substrate's account id. @@ -42,116 +29,3 @@ impl IdentifierT for T {} /// Aggregator trait for a PerThing that can be multiplied by u128 (ExtendedBalance). pub trait PerThing128: PerThing + Mul {} impl> PerThing128 for T {} - -/// Simple Extension trait to easily convert `None` from index closures to `Err`. -/// -/// This is only generated and re-exported for the solution code to use. -#[doc(hidden)] -pub trait __OrInvalidIndex { - fn or_invalid_index(self) -> Result; -} - -impl __OrInvalidIndex for Option { - fn or_invalid_index(self) -> Result { - self.ok_or(Error::SolutionInvalidIndex) - } -} - -/// An opaque index-based, NPoS solution type. -pub trait NposSolution -where - Self: Sized + for<'a> sp_std::convert::TryFrom<&'a [IndexAssignmentOf], Error = Error>, -{ - /// The maximum number of votes that are allowed. - const LIMIT: usize; - - /// The voter type. Needs to be an index (convert to usize). - type VoterIndex: UniqueSaturatedInto - + TryInto - + TryFrom - + Debug - + Copy - + Clone - + Bounded - + Encode - + TypeInfo; - - /// The target type. Needs to be an index (convert to usize). - type TargetIndex: UniqueSaturatedInto - + TryInto - + TryFrom - + Debug - + Copy - + Clone - + Bounded - + Encode - + TypeInfo; - - /// The weight/accuracy type of each vote. - type Accuracy: PerThing128; - - /// Get the length of all the voters that this type is encoding. - /// - /// This is basically the same as the number of assignments, or number of active voters. - fn voter_count(&self) -> usize; - - /// Get the total count of edges. - /// - /// This is effectively in the range of {[`Self::voter_count`], [`Self::voter_count`] * - /// [`Self::LIMIT`]}. - fn edge_count(&self) -> usize; - - /// Get the number of unique targets in the whole struct. - /// - /// Once presented with a list of winners, this set and the set of winners must be - /// equal. - fn unique_targets(&self) -> Vec; - - /// Get the average edge count. - fn average_edge_count(&self) -> usize { - self.edge_count().checked_div(self.voter_count()).unwrap_or(0) - } - - /// Compute the score of this solution type. - fn score( - self, - stake_of: FS, - voter_at: impl Fn(Self::VoterIndex) -> Option, - target_at: impl Fn(Self::TargetIndex) -> Option, - ) -> Result - where - for<'r> FS: Fn(&'r A) -> VoteWeight, - A: IdentifierT, - { - let ratio = self.into_assignment(voter_at, target_at)?; - let staked = crate::helpers::assignment_ratio_to_staked_normalized(ratio, stake_of)?; - let supports = crate::to_supports(&staked); - Ok(supports.evaluate()) - } - - /// Remove a certain voter. - /// - /// This will only search until the first instance of `to_remove`, and return true. If - /// no instance is found (no-op), then it returns false. - /// - /// In other words, if this return true, exactly **one** element must have been removed self. - fn remove_voter(&mut self, to_remove: Self::VoterIndex) -> bool; - - /// Build self from a list of assignments. - fn from_assignment( - assignments: &[Assignment], - voter_index: FV, - target_index: FT, - ) -> Result - where - A: IdentifierT, - for<'r> FV: Fn(&'r A) -> Option, - for<'r> FT: Fn(&'r A) -> Option; - - /// Convert self into a `Vec>` - fn into_assignment( - self, - voter_at: impl Fn(Self::VoterIndex) -> Option, - target_at: impl Fn(Self::TargetIndex) -> Option, - ) -> Result>, Error>; -} From 89682c1fd676816dc261959fee0c1d6cece98384 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 17 Mar 2022 11:40:31 +0100 Subject: [PATCH 0603/1472] Add execution overhead benchmarking (#10977) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add benchmark-block Signed-off-by: Oliver Tale-Yazdi * Remove first approach This reverts commit 9ce7f32cae12ce637bd3b85d255dd55ba7198f9d. * Add block and extrinsic benchmarks * Doc Signed-off-by: Oliver Tale-Yazdi * Fix template Signed-off-by: Oliver Tale-Yazdi * Beauty fixes Signed-off-by: Oliver Tale-Yazdi * Check for non-empty chain Signed-off-by: Oliver Tale-Yazdi * Add tests for Stats Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Apply suggestions from code review Co-authored-by: Shawn Tabrizi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Push first version again Signed-off-by: Oliver Tale-Yazdi * Push first version again Signed-off-by: Oliver Tale-Yazdi * Cleanup Signed-off-by: Oliver Tale-Yazdi * Cleanup Signed-off-by: Oliver Tale-Yazdi * Cleanup Signed-off-by: Oliver Tale-Yazdi * Beauty fixes Signed-off-by: Oliver Tale-Yazdi * Apply suggestions from code review Co-authored-by: Bastian Köcher * Update utils/frame/benchmarking-cli/src/overhead/template.rs Co-authored-by: Bastian Köcher * Review fixes Signed-off-by: Oliver Tale-Yazdi * Doc + Template fixes Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Comment fix Signed-off-by: Oliver Tale-Yazdi * Add test Signed-off-by: Oliver Tale-Yazdi * Pust merge fixup Signed-off-by: Oliver Tale-Yazdi * Fixup Signed-off-by: Oliver Tale-Yazdi * Move code to better place Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi Co-authored-by: Bastian Köcher --- Cargo.lock | 2 + bin/node/cli/src/cli.rs | 7 + bin/node/cli/src/command.rs | 25 ++- bin/node/cli/src/command_helper.rs | 69 ++++++ bin/node/cli/src/lib.rs | 2 + .../cli/tests/benchmark_overhead_works.rs | 46 ++++ utils/frame/benchmarking-cli/Cargo.toml | 2 + utils/frame/benchmarking-cli/src/lib.rs | 3 + .../benchmarking-cli/src/overhead/bench.rs | 210 ++++++++++++++++++ .../benchmarking-cli/src/overhead/cmd.rs | 118 ++++++++++ .../benchmarking-cli/src/overhead/mod.rs | 22 ++ .../benchmarking-cli/src/overhead/template.rs | 110 +++++++++ .../benchmarking-cli/src/overhead/weights.hbs | 92 ++++++++ .../src/post_processing/mod.rs | 95 ++++++++ .../frame/benchmarking-cli/src/storage/cmd.rs | 27 +-- .../benchmarking-cli/src/storage/record.rs | 59 ++++- .../benchmarking-cli/src/storage/template.rs | 16 +- 17 files changed, 852 insertions(+), 53 deletions(-) create mode 100644 bin/node/cli/src/command_helper.rs create mode 100644 bin/node/cli/tests/benchmark_overhead_works.rs create mode 100644 utils/frame/benchmarking-cli/src/overhead/bench.rs create mode 100644 utils/frame/benchmarking-cli/src/overhead/cmd.rs create mode 100644 utils/frame/benchmarking-cli/src/overhead/mod.rs create mode 100644 utils/frame/benchmarking-cli/src/overhead/template.rs create mode 100644 utils/frame/benchmarking-cli/src/overhead/weights.hbs create mode 100644 utils/frame/benchmarking-cli/src/post_processing/mod.rs diff --git a/Cargo.lock b/Cargo.lock index d3cc9ab0d4320..fb9561dfabdcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2139,6 +2139,7 @@ dependencies = [ "memory-db", "parity-scale-codec", "rand 0.8.4", + "sc-block-builder", "sc-cli", "sc-client-api", "sc-client-db", @@ -2152,6 +2153,7 @@ dependencies = [ "sp-core", "sp-database", "sp-externalities", + "sp-inherents", "sp-keystore", "sp-runtime", "sp-state-machine", diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 386215854b963..a911cc26ef87c 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -42,6 +42,13 @@ pub enum Subcommand { #[clap(name = "benchmark", about = "Benchmark runtime pallets.")] Benchmark(frame_benchmarking_cli::BenchmarkCmd), + /// Sub command for benchmarking the per-block and per-extrinsic execution overhead. + #[clap( + name = "benchmark-overhead", + about = "Benchmark the per-block and per-extrinsic execution overhead." + )] + BenchmarkOverhead(frame_benchmarking_cli::OverheadCmd), + /// Sub command for benchmarking the storage speed. #[clap(name = "benchmark-storage", about = "Benchmark storage speed.")] BenchmarkStorage(frame_benchmarking_cli::StorageCmd), diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index cc6480bb90d55..e208e324ee2aa 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -18,10 +18,13 @@ use crate::{chain_spec, service, service::new_partial, Cli, Subcommand}; use node_executor::ExecutorDispatch; -use node_runtime::{Block, RuntimeApi}; +use node_primitives::Block; +use node_runtime::RuntimeApi; use sc_cli::{ChainSpec, Result, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; +use std::sync::Arc; + impl SubstrateCli for Cli { fn impl_name() -> String { "Substrate Node".into() @@ -95,13 +98,21 @@ pub fn run() -> Result<()> { You can enable it with `--features runtime-benchmarks`." .into()) }, - Some(Subcommand::BenchmarkStorage(cmd)) => { - if !cfg!(feature = "runtime-benchmarks") { - return Err("Benchmarking wasn't enabled when building the node. \ - You can enable it with `--features runtime-benchmarks`." - .into()) - } + Some(Subcommand::BenchmarkOverhead(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|mut config| { + use super::command_helper::{inherent_data, ExtrinsicBuilder}; + // We don't use the authority role since that would start producing blocks + // in the background which would mess with our benchmark. + config.role = sc_service::Role::Full; + let PartialComponents { client, task_manager, .. } = new_partial(&config)?; + let ext_builder = ExtrinsicBuilder::new(client.clone()); + + Ok((cmd.run(config, client, inherent_data()?, Arc::new(ext_builder)), task_manager)) + }) + }, + Some(Subcommand::BenchmarkStorage(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?; diff --git a/bin/node/cli/src/command_helper.rs b/bin/node/cli/src/command_helper.rs new file mode 100644 index 0000000000000..51fe7a5c5a7bf --- /dev/null +++ b/bin/node/cli/src/command_helper.rs @@ -0,0 +1,69 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Contains code to setup the command invocations in [`super::command`] which would +//! otherwise bloat that module. + +use crate::service::{create_extrinsic, FullClient}; + +use node_runtime::SystemCall; +use sc_cli::Result; +use sp_inherents::{InherentData, InherentDataProvider}; +use sp_keyring::Sr25519Keyring; +use sp_runtime::OpaqueExtrinsic; + +use std::{sync::Arc, time::Duration}; + +/// Generates extrinsics for the `benchmark-overhead` command. +pub struct ExtrinsicBuilder { + client: Arc, +} + +impl ExtrinsicBuilder { + /// Creates a new [`Self`] from the given client. + pub fn new(client: Arc) -> Self { + Self { client } + } +} + +impl frame_benchmarking_cli::ExtrinsicBuilder for ExtrinsicBuilder { + fn remark(&self, nonce: u32) -> std::result::Result { + let acc = Sr25519Keyring::Bob.pair(); + let extrinsic: OpaqueExtrinsic = create_extrinsic( + self.client.as_ref(), + acc, + SystemCall::remark { remark: vec![] }, + Some(nonce), + ) + .into(); + + Ok(extrinsic) + } +} + +/// Generates inherent data for the `benchmark-overhead` command. +pub fn inherent_data() -> Result { + let mut inherent_data = InherentData::new(); + let d = Duration::from_millis(0); + let timestamp = sp_timestamp::InherentDataProvider::new(d.into()); + + timestamp + .provide_inherent_data(&mut inherent_data) + .map_err(|e| format!("creating inherent data: {:?}", e))?; + Ok(inherent_data) +} diff --git a/bin/node/cli/src/lib.rs b/bin/node/cli/src/lib.rs index 791140a25484d..06c0bcccbc296 100644 --- a/bin/node/cli/src/lib.rs +++ b/bin/node/cli/src/lib.rs @@ -38,6 +38,8 @@ pub mod service; mod cli; #[cfg(feature = "cli")] mod command; +#[cfg(feature = "cli")] +mod command_helper; #[cfg(feature = "cli")] pub use cli::*; diff --git a/bin/node/cli/tests/benchmark_overhead_works.rs b/bin/node/cli/tests/benchmark_overhead_works.rs new file mode 100644 index 0000000000000..550221ee2f70f --- /dev/null +++ b/bin/node/cli/tests/benchmark_overhead_works.rs @@ -0,0 +1,46 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use assert_cmd::cargo::cargo_bin; +use std::process::Command; +use tempfile::tempdir; + +/// Tests that the `benchmark-overhead` command works for the substrate dev runtime. +#[test] +fn benchmark_overhead_works() { + let tmp_dir = tempdir().expect("could not create a temp dir"); + let base_path = tmp_dir.path(); + + // Only put 10 extrinsics into the block otherwise it takes forever to build it + // especially for a non-release build. + let status = Command::new(cargo_bin("substrate")) + .args(&["benchmark-overhead", "--dev", "-d"]) + .arg(base_path) + .arg("--weight-path") + .arg(base_path) + .args(["--warmup", "10", "--repeat", "10"]) + .args(["--add", "100", "--mul", "1.2", "--metric", "p75"]) + .args(["--max-ext-per-block", "10"]) + .status() + .unwrap(); + assert!(status.success()); + + // Weight files have been created. + assert!(base_path.join("block_weights.rs").exists()); + assert!(base_path.join("extrinsic_weights.rs").exists()); +} diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 81e7396db3e68..5575bb833ca77 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } @@ -26,6 +27,7 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } sp-database = { version = "4.0.0-dev", path = "../../../primitives/database" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 9815fe88a7f02..e06d57963dad3 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -16,12 +16,15 @@ // limitations under the License. mod command; +pub mod overhead; +mod post_processing; mod storage; mod writer; use sc_cli::{ExecutionStrategy, WasmExecutionMethod, DEFAULT_WASM_EXECUTION_METHOD}; use std::{fmt::Debug, path::PathBuf}; +pub use overhead::{ExtrinsicBuilder, OverheadCmd}; pub use storage::StorageCmd; // Add a more relaxed parsing for pallet names by allowing pallet directory names with `-` to be diff --git a/utils/frame/benchmarking-cli/src/overhead/bench.rs b/utils/frame/benchmarking-cli/src/overhead/bench.rs new file mode 100644 index 0000000000000..3e18c6a86db24 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/overhead/bench.rs @@ -0,0 +1,210 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains the core benchmarking logic. + +use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_cli::{Error, Result}; +use sc_client_api::Backend as ClientBackend; +use sp_api::{ApiExt, BlockId, Core, ProvideRuntimeApi}; +use sp_blockchain::{ + ApplyExtrinsicFailed::Validity, + Error::{ApplyExtrinsicFailed, RuntimeApiError}, +}; +use sp_runtime::{ + traits::{Block as BlockT, Zero}, + transaction_validity::{InvalidTransaction, TransactionValidityError}, + OpaqueExtrinsic, +}; + +use clap::Args; +use log::info; +use serde::Serialize; +use std::{marker::PhantomData, sync::Arc, time::Instant}; + +use crate::{overhead::cmd::ExtrinsicBuilder, storage::record::Stats}; + +/// Parameters to configure an *overhead* benchmark. +#[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] +pub struct BenchmarkParams { + /// Rounds of warmups before measuring. + #[clap(long, default_value = "100")] + pub warmup: u32, + + /// How many times the benchmark should be repeated. + #[clap(long, default_value = "1000")] + pub repeat: u32, + + /// Maximal number of extrinsics that should be put into a block. + /// + /// Only useful for debugging. + #[clap(long)] + pub max_ext_per_block: Option, +} + +/// The results of multiple runs in nano seconds. +pub(crate) type BenchRecord = Vec; + +/// Type of a benchmark. +#[derive(Serialize, Clone, PartialEq, Copy)] +pub(crate) enum BenchmarkType { + /// Measure the per-extrinsic execution overhead. + Extrinsic, + /// Measure the per-block execution overhead. + Block, +} + +/// Holds all objects needed to run the *overhead* benchmarks. +pub(crate) struct Benchmark { + client: Arc, + params: BenchmarkParams, + inherent_data: sp_inherents::InherentData, + ext_builder: Arc, + _p: PhantomData<(Block, BA)>, +} + +impl Benchmark +where + Block: BlockT, + BA: ClientBackend, + C: BlockBuilderProvider + ProvideRuntimeApi, + C::Api: ApiExt + BlockBuilderApi, +{ + /// Create a new [`Self`] from the arguments. + pub fn new( + client: Arc, + params: BenchmarkParams, + inherent_data: sp_inherents::InherentData, + ext_builder: Arc, + ) -> Self { + Self { client, params, inherent_data, ext_builder, _p: PhantomData } + } + + /// Run the specified benchmark. + pub fn bench(&self, bench_type: BenchmarkType) -> Result { + let (block, num_ext) = self.build_block(bench_type)?; + let record = self.measure_block(&block, num_ext, bench_type)?; + Stats::new(&record) + } + + /// Builds a block for the given benchmark type. + /// + /// Returns the block and the number of extrinsics in the block + /// that are not inherents. + fn build_block(&self, bench_type: BenchmarkType) -> Result<(Block, u64)> { + let mut builder = self.client.new_block(Default::default())?; + // Create and insert the inherents. + let inherents = builder.create_inherents(self.inherent_data.clone())?; + for inherent in inherents { + builder.push(inherent)?; + } + + // Return early if we just want a block with inherents and no additional extrinsics. + if bench_type == BenchmarkType::Block { + return Ok((builder.build()?.block, 0)) + } + + // Put as many extrinsics into the block as possible and count them. + info!("Building block, this takes some time..."); + let mut num_ext = 0; + for nonce in 0..self.max_ext_per_block() { + let ext = self.ext_builder.remark(nonce)?; + match builder.push(ext.clone()) { + Ok(()) => {}, + Err(ApplyExtrinsicFailed(Validity(TransactionValidityError::Invalid( + InvalidTransaction::ExhaustsResources, + )))) => break, // Block is full + Err(e) => return Err(Error::Client(e)), + } + num_ext += 1; + } + if num_ext == 0 { + return Err("A Block must hold at least one extrinsic".into()) + } + info!("Extrinsics per block: {}", num_ext); + let block = builder.build()?.block; + + Ok((block, num_ext)) + } + + /// Measures the time that it take to execute a block or an extrinsic. + fn measure_block( + &self, + block: &Block, + num_ext: u64, + bench_type: BenchmarkType, + ) -> Result { + let mut record = BenchRecord::new(); + if bench_type == BenchmarkType::Extrinsic && num_ext == 0 { + return Err("Cannot measure the extrinsic time of an empty block".into()) + } + let genesis = BlockId::Number(Zero::zero()); + + info!("Running {} warmups...", self.params.warmup); + for _ in 0..self.params.warmup { + self.client + .runtime_api() + .execute_block(&genesis, block.clone()) + .map_err(|e| Error::Client(RuntimeApiError(e)))?; + } + + info!("Executing block {} times", self.params.repeat); + // Interesting part here: + // Execute a block multiple times and record each execution time. + for _ in 0..self.params.repeat { + let block = block.clone(); + let runtime_api = self.client.runtime_api(); + let start = Instant::now(); + + runtime_api + .execute_block(&genesis, block) + .map_err(|e| Error::Client(RuntimeApiError(e)))?; + + let elapsed = start.elapsed().as_nanos(); + if bench_type == BenchmarkType::Extrinsic { + // Checked for non-zero div above. + record.push((elapsed as f64 / num_ext as f64).ceil() as u64); + } else { + record.push(elapsed as u64); + } + } + + Ok(record) + } + + fn max_ext_per_block(&self) -> u32 { + self.params.max_ext_per_block.unwrap_or(u32::MAX) + } +} + +impl BenchmarkType { + /// Short name of the benchmark type. + pub(crate) fn short_name(&self) -> &'static str { + match self { + Self::Extrinsic => "extrinsic", + Self::Block => "block", + } + } + + /// Long name of the benchmark type. + pub(crate) fn long_name(&self) -> &'static str { + match self { + Self::Extrinsic => "ExtrinsicBase", + Self::Block => "BlockExecution", + } + } +} diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs new file mode 100644 index 0000000000000..8c75627fe2462 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -0,0 +1,118 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains the [`OverheadCmd`] as entry point for the CLI to execute +//! the *overhead* benchmarks. + +use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_cli::{CliConfiguration, Result, SharedParams}; +use sc_client_api::Backend as ClientBackend; +use sc_service::Configuration; +use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; + +use clap::{Args, Parser}; +use log::info; +use serde::Serialize; +use std::{fmt::Debug, sync::Arc}; + +use crate::{ + overhead::{ + bench::{Benchmark, BenchmarkParams, BenchmarkType}, + template::TemplateData, + }, + post_processing::WeightParams, +}; + +/// Benchmarks the per-block and per-extrinsic execution overhead. +#[derive(Debug, Parser)] +pub struct OverheadCmd { + #[allow(missing_docs)] + #[clap(flatten)] + pub shared_params: SharedParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub params: OverheadParams, +} + +/// Configures the benchmark, the post-processing and weight generation. +#[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] +pub struct OverheadParams { + #[allow(missing_docs)] + #[clap(flatten)] + pub weight: WeightParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub bench: BenchmarkParams, +} + +/// Used by the benchmark to build signed extrinsics. +/// +/// The built extrinsics only need to be valid in the first block +/// who's parent block is the genesis block. +pub trait ExtrinsicBuilder { + /// Build a `System::remark` extrinsic. + fn remark(&self, nonce: u32) -> std::result::Result; +} + +impl OverheadCmd { + /// Measures the per-block and per-extrinsic execution overhead. + /// + /// Writes the results to console and into two instances of the + /// `weights.hbs` template, one for each benchmark. + pub async fn run( + &self, + cfg: Configuration, + client: Arc, + inherent_data: sp_inherents::InherentData, + ext_builder: Arc, + ) -> Result<()> + where + Block: BlockT, + BA: ClientBackend, + C: BlockBuilderProvider + ProvideRuntimeApi, + C::Api: ApiExt + BlockBuilderApi, + { + let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data, ext_builder); + + // per-block execution overhead + { + let stats = bench.bench(BenchmarkType::Block)?; + info!("Per-block execution overhead [ns]:\n{:?}", stats); + let template = TemplateData::new(BenchmarkType::Block, &cfg, &self.params, &stats)?; + template.write(&self.params.weight.weight_path)?; + } + // per-extrinsic execution overhead + { + let stats = bench.bench(BenchmarkType::Extrinsic)?; + info!("Per-extrinsic execution overhead [ns]:\n{:?}", stats); + let template = TemplateData::new(BenchmarkType::Extrinsic, &cfg, &self.params, &stats)?; + template.write(&self.params.weight.weight_path)?; + } + + Ok(()) + } +} + +// Boilerplate +impl CliConfiguration for OverheadCmd { + fn shared_params(&self) -> &SharedParams { + &self.shared_params + } +} diff --git a/utils/frame/benchmarking-cli/src/overhead/mod.rs b/utils/frame/benchmarking-cli/src/overhead/mod.rs new file mode 100644 index 0000000000000..abdeac22b7898 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/overhead/mod.rs @@ -0,0 +1,22 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod bench; +pub mod cmd; +mod template; + +pub use cmd::{ExtrinsicBuilder, OverheadCmd}; diff --git a/utils/frame/benchmarking-cli/src/overhead/template.rs b/utils/frame/benchmarking-cli/src/overhead/template.rs new file mode 100644 index 0000000000000..f6fb8ed9d929e --- /dev/null +++ b/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -0,0 +1,110 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Converts a benchmark result into [`TemplateData`] and writes +//! it into the `weights.hbs` template. + +use sc_cli::Result; +use sc_service::Configuration; + +use handlebars::Handlebars; +use log::info; +use serde::Serialize; +use std::{env, fs, path::PathBuf}; + +use crate::{ + overhead::{bench::BenchmarkType, cmd::OverheadParams}, + storage::record::Stats, +}; + +static VERSION: &'static str = env!("CARGO_PKG_VERSION"); +static TEMPLATE: &str = include_str!("./weights.hbs"); + +/// Data consumed by Handlebar to fill out the `weights.hbs` template. +#[derive(Serialize, Debug, Clone)] +pub(crate) struct TemplateData { + /// Short name of the benchmark. Can be "block" or "extrinsic". + long_name: String, + /// Long name of the benchmark. Can be "BlockExecution" or "ExtrinsicBase". + short_name: String, + /// Name of the runtime. Taken from the chain spec. + runtime_name: String, + /// Version of the benchmarking CLI used. + version: String, + /// Date that the template was filled out. + date: String, + /// Command line arguments that were passed to the CLI. + args: Vec, + /// Params of the executed command. + params: OverheadParams, + /// Stats about the benchmark result. + stats: Stats, + /// The resulting weight in ns. + weight: u64, +} + +impl TemplateData { + /// Returns a new [`Self`] from the given params. + pub(crate) fn new( + t: BenchmarkType, + cfg: &Configuration, + params: &OverheadParams, + stats: &Stats, + ) -> Result { + let weight = params.weight.calc_weight(stats)?; + + Ok(TemplateData { + short_name: t.short_name().into(), + long_name: t.long_name().into(), + runtime_name: cfg.chain_spec.name().into(), + version: VERSION.into(), + date: chrono::Utc::now().format("%Y-%m-%d (Y/M/D)").to_string(), + args: env::args().collect::>(), + params: params.clone(), + stats: stats.clone(), + weight, + }) + } + + /// Fill out the `weights.hbs` HBS template with its own data. + /// Writes the result to `path` which can be a directory or a file. + pub fn write(&self, path: &Option) -> Result<()> { + let mut handlebars = Handlebars::new(); + // Format large integers with underscores. + handlebars.register_helper("underscore", Box::new(crate::writer::UnderscoreHelper)); + // Don't HTML escape any characters. + handlebars.register_escape_fn(|s| -> String { s.to_string() }); + + let out_path = self.build_path(path)?; + let mut fd = fs::File::create(&out_path)?; + info!("Writing weights to {:?}", fs::canonicalize(&out_path)?); + handlebars + .render_template_to_write(&TEMPLATE, &self, &mut fd) + .map_err(|e| format!("HBS template write: {:?}", e).into()) + } + + /// Build a path for the weight file. + fn build_path(&self, weight_out: &Option) -> Result { + let mut path = weight_out.clone().unwrap_or(PathBuf::from(".")); + + if !path.is_dir() { + return Err("Need directory as --weight-path".into()) + } + path.push(format!("{}_weights.rs", self.short_name)); + Ok(path) + } +} diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs new file mode 100644 index 0000000000000..0f6b7f3e9119f --- /dev/null +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -0,0 +1,92 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} +//! DATE: {{date}} +//! +//! SHORT-NAME: `{{short_name}}`, LONG-NAME: `{{long_name}}`, RUNTIME: `{{runtime_name}}` +//! WARMUPS: `{{params.bench.warmup}}`, REPEAT: `{{params.bench.repeat}}` +//! WEIGHT-PATH: `{{params.weight.weight_path}}` +//! WEIGHT-METRIC: `{{params.weight.weight_metric}}`, WEIGHT-MUL: `{{params.weight.weight_mul}}`, WEIGHT-ADD: `{{params.weight.weight_add}}` + +// Executed Command: +{{#each args as |arg|}} +// {{arg}} +{{/each}} + +use frame_support::{ + parameter_types, + weights::{constants::WEIGHT_PER_NANOS, Weight}, +}; + +parameter_types! { + {{#if (eq short_name "block")}} + /// Time to execute an empty block. + {{else}} + /// Time to execute a NO-OP extrinsic eg. `System::remark`. + {{/if}} + /// Calculated by multiplying the *{{params.weight.weight_metric}}* with `{{params.weight.weight_mul}}` and adding `{{params.weight.weight_add}}`. + /// + /// Stats [ns]: + /// Min, Max: {{underscore stats.min}}, {{underscore stats.max}} + /// Average: {{underscore stats.avg}} + /// Median: {{underscore stats.median}} + /// StdDev: {{stats.stddev}} + /// + /// Percentiles [ns]: + /// 99th: {{underscore stats.p99}} + /// 95th: {{underscore stats.p95}} + /// 75th: {{underscore stats.p75}} + pub const {{long_name}}Weight: Weight = {{underscore weight}} * WEIGHT_PER_NANOS; +} + +#[cfg(test)] +mod test_weights { + use frame_support::weights::constants; + + /// Checks that the weight exists and is sane. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + let w = super::{{long_name}}Weight::get(); + + {{#if (eq short_name "block")}} + // At least 100 µs. + assert!( + w >= 100 * constants::WEIGHT_PER_MICROS, + "Weight should be at least 100 µs." + ); + // At most 50 ms. + assert!( + w <= 50 * constants::WEIGHT_PER_MILLIS, + "Weight should be at most 50 ms." + ); + {{else}} + // At least 10 µs. + assert!( + w >= 10 * constants::WEIGHT_PER_MICROS, + "Weight should be at least 10 µs." + ); + // At most 1 ms. + assert!( + w <= constants::WEIGHT_PER_MILLIS, + "Weight should be at most 1 ms." + ); + {{/if}} + } +} diff --git a/utils/frame/benchmarking-cli/src/post_processing/mod.rs b/utils/frame/benchmarking-cli/src/post_processing/mod.rs new file mode 100644 index 0000000000000..fb20d9bd0c488 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/post_processing/mod.rs @@ -0,0 +1,95 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Calculates a weight from the statistics of a benchmark result. + +use sc_cli::Result; + +use clap::Args; +use serde::Serialize; +use std::path::PathBuf; + +use crate::storage::record::{StatSelect, Stats}; + +/// Configures the weight generation. +#[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] +pub struct WeightParams { + /// File or directory to write the *weight* files to. + /// + /// For Substrate this should be `frame/support/src/weights`. + #[clap(long)] + pub weight_path: Option, + + /// Select a specific metric to calculate the final weight output. + #[clap(long = "metric", default_value = "average")] + pub weight_metric: StatSelect, + + /// Multiply the resulting weight with the given factor. Must be positive. + /// + /// Is applied before `weight_add`. + #[clap(long = "mul", default_value = "1")] + pub weight_mul: f64, + + /// Add the given offset to the resulting weight. + /// + /// Is applied after `weight_mul`. + #[clap(long = "add", default_value = "0")] + pub weight_add: u64, +} + +/// Calculates the final weight by multiplying the selected metric with +/// `weight_mul` and adding `weight_add`. +/// Does not use safe casts and can overflow. +impl WeightParams { + pub(crate) fn calc_weight(&self, stat: &Stats) -> Result { + if self.weight_mul.is_sign_negative() || !self.weight_mul.is_normal() { + return Err("invalid floating number for `weight_mul`".into()) + } + let s = stat.select(self.weight_metric) as f64; + let w = s.mul_add(self.weight_mul, self.weight_add as f64).ceil(); + Ok(w as u64) // No safe cast here since there is no `From` for `u64`. + } +} + +#[cfg(test)] +mod test_weight_params { + use super::WeightParams; + use crate::storage::record::{StatSelect, Stats}; + + #[test] + fn calc_weight_works() { + let stats = Stats { avg: 113, ..Default::default() }; + let params = WeightParams { + weight_metric: StatSelect::Average, + weight_mul: 0.75, + weight_add: 3, + ..Default::default() + }; + + let want = (113.0f64 * 0.75 + 3.0).ceil() as u64; // Ceil for overestimation. + let got = params.calc_weight(&stats).unwrap(); + assert_eq!(want, got); + } + + #[test] + fn calc_weight_detects_negative_mul() { + let stats = Stats::default(); + let params = WeightParams { weight_mul: -0.75, ..Default::default() }; + + assert!(params.calc_weight(&stats).is_err()); + } +} diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index ad7d13a2022e4..c38e6636e5a3e 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -33,8 +33,8 @@ use serde::Serialize; use sp_runtime::generic::BlockId; use std::{fmt::Debug, path::PathBuf, sync::Arc}; -use super::{record::StatSelect, template::TemplateData}; - +use super::template::TemplateData; +use crate::post_processing::WeightParams; /// Benchmark the storage of a Substrate node with a live chain snapshot. #[derive(Debug, Parser)] pub struct StorageCmd { @@ -58,24 +58,9 @@ pub struct StorageCmd { /// Parameters for modifying the benchmark behaviour and the post processing of the results. #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] pub struct StorageParams { - /// Path to write the *weight* file to. Can be a file or directory. - /// For substrate this should be `frame/support/src/weights`. - #[clap(long)] - pub weight_path: Option, - - /// Select a specific metric to calculate the final weight output. - #[clap(long = "metric", default_value = "average")] - pub weight_metric: StatSelect, - - /// Multiply the resulting weight with the given factor. Must be positive. - /// Is calculated before `weight_add`. - #[clap(long = "mul", default_value = "1")] - pub weight_mul: f64, - - /// Add the given offset to the resulting weight. - /// Is calculated after `weight_mul`. - #[clap(long = "add", default_value = "0")] - pub weight_add: u64, + #[allow(missing_docs)] + #[clap(flatten)] + pub weight_params: WeightParams, /// Skip the `read` benchmark. #[clap(long)] @@ -153,7 +138,7 @@ impl StorageCmd { template.set_stats(None, Some(stats))?; } - template.write(&self.params.weight_path, &self.params.template_path) + template.write(&self.params.weight_params.weight_path, &self.params.template_path) } /// Returns the specified state version. diff --git a/utils/frame/benchmarking-cli/src/storage/record.rs b/utils/frame/benchmarking-cli/src/storage/record.rs index 667274bef0dd5..530fa4cdfe965 100644 --- a/utils/frame/benchmarking-cli/src/storage/record.rs +++ b/utils/frame/benchmarking-cli/src/storage/record.rs @@ -36,25 +36,25 @@ pub(crate) struct BenchRecord { #[derive(Serialize, Default, Clone)] pub(crate) struct Stats { /// Sum of all values. - sum: u64, + pub(crate) sum: u64, /// Minimal observed value. - min: u64, + pub(crate) min: u64, /// Maximal observed value. - max: u64, + pub(crate) max: u64, /// Average of all values. - avg: u64, + pub(crate) avg: u64, /// Median of all values. - median: u64, + pub(crate) median: u64, /// Standard derivation of all values. - stddev: f64, + pub(crate) stddev: f64, /// 99th percentile. At least 99% of all values are below this threshold. - p99: u64, + pub(crate) p99: u64, /// 95th percentile. At least 95% of all values are below this threshold. - p95: u64, + pub(crate) p95: u64, /// 75th percentile. At least 75% of all values are below this threshold. - p75: u64, + pub(crate) p75: u64, } /// Selects a specific field from a [`Stats`] object. @@ -159,8 +159,8 @@ impl Stats { /// This is best effort since it ignores the interpolation case. fn percentile(mut xs: Vec, p: f64) -> u64 { xs.sort(); - let index = (xs.len() as f64 * p).ceil() as usize; - xs[index] + let index = (xs.len() as f64 * p).ceil() as usize - 1; + xs[index.clamp(0, xs.len() - 1)] } } @@ -195,3 +195,40 @@ impl FromStr for StatSelect { } } } + +#[cfg(test)] +mod test_stats { + use super::Stats; + use rand::{seq::SliceRandom, thread_rng}; + + #[test] + fn stats_correct() { + let mut data: Vec = (1..=100).collect(); + data.shuffle(&mut thread_rng()); + let stats = Stats::new(&data).unwrap(); + + assert_eq!(stats.sum, 5050); + assert_eq!(stats.min, 1); + assert_eq!(stats.max, 100); + + assert_eq!(stats.avg, 50); + assert_eq!(stats.median, 50); // 50.5 to be exact. + assert_eq!(stats.stddev, 28.87); // Rounded with 1/100 precision. + + assert_eq!(stats.p99, 99); + assert_eq!(stats.p95, 95); + assert_eq!(stats.p75, 75); + } + + #[test] + fn no_panic_short_lengths() { + // Empty input does error. + assert!(Stats::new(&vec![]).is_err()); + + // Different small input lengths are fine. + for l in 1..10 { + let data = (0..=l).collect(); + assert!(Stats::new(&data).is_ok()); + } + } +} diff --git a/utils/frame/benchmarking-cli/src/storage/template.rs b/utils/frame/benchmarking-cli/src/storage/template.rs index 13b825d891a51..10e6902b934bc 100644 --- a/utils/frame/benchmarking-cli/src/storage/template.rs +++ b/utils/frame/benchmarking-cli/src/storage/template.rs @@ -77,11 +77,11 @@ impl TemplateData { write: Option<(Stats, Stats)>, ) -> Result<()> { if let Some(read) = read { - self.read_weight = calc_weight(&read.0, &self.params)?; + self.read_weight = self.params.weight_params.calc_weight(&read.0)?; self.read = Some(read); } if let Some(write) = write { - self.write_weight = calc_weight(&write.0, &self.params)?; + self.write_weight = self.params.weight_params.calc_weight(&write.0)?; self.write = Some(write); } Ok(()) @@ -130,15 +130,3 @@ impl TemplateData { path } } - -/// Calculates the final weight by multiplying the selected metric with -/// `mul` and adding `add`. -/// Does not use safe casts and can overflow. -fn calc_weight(stat: &Stats, params: &StorageParams) -> Result { - if params.weight_mul.is_sign_negative() || !params.weight_mul.is_normal() { - return Err("invalid floating number for `weight_mul`".into()) - } - let s = stat.select(params.weight_metric) as f64; - let w = s.mul_add(params.weight_mul, params.weight_add as f64).ceil(); - Ok(w as u64) // No safe cast here since there is no `From` for `u64`. -} From 150fea0726b528484d600a56a2dd92a783755518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 17 Mar 2022 12:16:56 +0100 Subject: [PATCH 0604/1472] sc-rpc-api: Remove unused error variants (#11012) --- client/rpc-api/src/author/error.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/client/rpc-api/src/author/error.rs b/client/rpc-api/src/author/error.rs index eee77edd5e208..fe12bd581f120 100644 --- a/client/rpc-api/src/author/error.rs +++ b/client/rpc-api/src/author/error.rs @@ -43,15 +43,9 @@ pub enum Error { /// Incorrect extrinsic format. #[error("Invalid extrinsic format: {}", .0)] BadFormat(#[from] codec::Error), - /// Incorrect seed phrase. - #[error("Invalid seed phrase/SURI")] - BadSeedPhrase, /// Key type ID has an unknown format. #[error("Invalid key type ID format (should be of length four)")] BadKeyType, - /// Key type ID has some unsupported crypto. - #[error("The crypto of key type ID is unknown")] - UnsupportedKeyType, /// Some random issue with the key store. Shouldn't happen. #[error("The key store is unavailable")] KeyStoreUnavailable, @@ -84,8 +78,6 @@ const POOL_TOO_LOW_PRIORITY: i64 = POOL_INVALID_TX + 4; const POOL_CYCLE_DETECTED: i64 = POOL_INVALID_TX + 5; /// The transaction was not included to the pool because of the limits. const POOL_IMMEDIATELY_DROPPED: i64 = POOL_INVALID_TX + 6; -/// The key type crypto is not known. -const UNSUPPORTED_KEY_TYPE: i64 = POOL_INVALID_TX + 7; /// The transaction was not included to the pool since it is unactionable, /// it is not propagable and the local node does not author blocks. const POOL_UNACTIONABLE: i64 = POOL_INVALID_TX + 8; @@ -156,14 +148,6 @@ impl From for rpc::Error { the local node does not author blocks".into(), ), }, - Error::UnsupportedKeyType => rpc::Error { - code: rpc::ErrorCode::ServerError(UNSUPPORTED_KEY_TYPE), - message: "Unknown key type crypto" .into(), - data: Some( - "The crypto for the given key type is unknown, please add the public key to the \ - request to insert the key successfully.".into() - ), - }, Error::UnsafeRpcCalled(e) => e.into(), e => errors::internal(e), } From 96738a1f3dbe4a1fb6abb385920fb403ee961488 Mon Sep 17 00:00:00 2001 From: Georges Date: Thu, 17 Mar 2022 12:52:26 +0000 Subject: [PATCH 0605/1472] Allow `pallet-election-provider` to accept smaller solutions as well (#10905) * Allow `pallet-election-provider` to accept smaller solutions, issue #9478 * Fixing a typo * Adding some more tests Removing a seemingly outdated comment * making it a URL * Updating test name as per suggestion Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Updating documentation to be more explicit And to follow the general guidelines Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fixing formatting Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- .../election-provider-multi-phase/src/lib.rs | 49 ++++++++++++++++--- .../src/unsigned.rs | 7 ++- frame/election-provider-support/src/lib.rs | 6 +++ 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index b366ceb4dafe3..90c540b85d67d 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1346,7 +1346,7 @@ impl Pallet { T::DataProvider::targets(Some(target_limit)).map_err(ElectionError::DataProvider)?; let voters = T::DataProvider::voters(Some(voter_limit)).map_err(ElectionError::DataProvider)?; - let desired_targets = + let mut desired_targets = T::DataProvider::desired_targets().map_err(ElectionError::DataProvider)?; // Defensive-only. @@ -1355,6 +1355,22 @@ impl Pallet { return Err(ElectionError::DataProvider("Snapshot too big for submission.")) } + // If `desired_targets` > `targets.len()`, cap `desired_targets` to that level and emit a + // warning + let max_len = targets + .len() + .try_into() + .map_err(|_| ElectionError::DataProvider("Failed to convert usize"))?; + if desired_targets > max_len { + log!( + warn, + "desired_targets: {} > targets.len(): {}, capping desired_targets", + desired_targets, + max_len + ); + desired_targets = max_len; + } + Ok((targets, voters, desired_targets)) } @@ -1413,9 +1429,6 @@ impl Pallet { let desired_targets = Self::desired_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - // NOTE: this is a bit of duplicate, but we keep it around for veracity. The unsigned path - // already checked this in `unsigned_per_dispatch_checks`. The signed path *could* check it - // upon arrival, thus we would then remove it here. Given overlay it is cheap anyhow ensure!(winners.len() as u32 == desired_targets, FeasibilityError::WrongWinnerCount); // Ensure that the solution's score can pass absolute min-score. @@ -1588,7 +1601,7 @@ mod feasibility_check { raw_solution, roll_to, EpochLength, ExtBuilder, MultiPhase, Runtime, SignedPhase, TargetIndex, UnsignedPhase, VoterIndex, }; - use frame_support::assert_noop; + use frame_support::{assert_noop, assert_ok}; const COMPUTE: ElectionCompute = ElectionCompute::OnChain; @@ -1625,7 +1638,7 @@ mod feasibility_check { } #[test] - fn desired_targets() { + fn desired_targets_gets_capped() { ExtBuilder::default().desired_targets(8).build_and_execute(|| { roll_to(::get() - ::get() - ::get()); assert!(MultiPhase::current_phase().is_signed()); @@ -1633,8 +1646,30 @@ mod feasibility_check { let raw = raw_solution(); assert_eq!(raw.solution.unique_targets().len(), 4); - assert_eq!(MultiPhase::desired_targets().unwrap(), 8); + // desired_targets is capped to the number of targets which is 4 + assert_eq!(MultiPhase::desired_targets().unwrap(), 4); + + // It should succeed + assert_ok!(MultiPhase::feasibility_check(raw, COMPUTE)); + }) + } + + #[test] + fn less_than_desired_targets_fails() { + ExtBuilder::default().desired_targets(8).build_and_execute(|| { + roll_to(::get() - ::get() - ::get()); + assert!(MultiPhase::current_phase().is_signed()); + + let mut raw = raw_solution(); + + assert_eq!(raw.solution.unique_targets().len(), 4); + // desired_targets is capped to the number of targets which is 4 + assert_eq!(MultiPhase::desired_targets().unwrap(), 4); + + // Force the number of winners to be bigger to fail + raw.solution.votes1[0].1 = 4; + // It should succeed assert_noop!( MultiPhase::feasibility_check(raw, COMPUTE), FeasibilityError::WrongWinnerCount, diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 3380a61d4310e..c52a4da22cb87 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -1044,8 +1044,13 @@ mod tests { roll_to(25); assert!(MultiPhase::current_phase().is_unsigned()); + // Force the number of winners to be bigger to fail + let (mut solution, _) = + MultiPhase::mine_solution::<::Solver>().unwrap(); + solution.solution.votes1[0].1 = 4; + assert_eq!( - MultiPhase::mine_check_save_submit().unwrap_err(), + MultiPhase::basic_checks(&solution, "mined").unwrap_err(), MinerError::PreDispatchChecksFailed(DispatchError::Module(ModuleError { index: 2, error: 1, diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index ca95eda6b5095..e1975a2681e6a 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -289,6 +289,12 @@ pub trait ElectionDataProvider { /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. + /// + /// A sensible implementation should use the minimum between this value and + /// [`Self::targets().len()`], since desiring a winner set larger than candidates is not + /// feasible. + /// + /// This is documented further in issue: fn desired_targets() -> data_provider::Result; /// Provide a best effort prediction about when the next election is about to happen. From 8e0dbe7a3ff961634df9db7d384012d5150423c1 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 17 Mar 2022 15:47:42 +0000 Subject: [PATCH 0606/1472] fix sibmit benchmark in election-multi-phase pallet (#11057) --- frame/election-provider-multi-phase/src/benchmarking.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index b331516a4e797..2a9286369f394 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -309,7 +309,6 @@ frame_benchmarking::benchmarks! { } submit { - // the solution will be worse than all of them meaning the score need to be checked against // ~ log2(c) let solution = RawSolution { @@ -341,7 +340,11 @@ frame_benchmarking::benchmarks! { signed_submissions.put(); let caller = frame_benchmarking::whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance() * 10u32.into()); + let deposit = MultiPhase::::deposit_for( + &solution, + MultiPhase::::snapshot_metadata().unwrap_or_default(), + ); + T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance() * 1000u32.into() + deposit); }: _(RawOrigin::Signed(caller), Box::new(solution)) verify { From 627ba73fafc526b85f9ed141c33dc26ada292247 Mon Sep 17 00:00:00 2001 From: AurevoirXavier Date: Fri, 18 Mar 2022 20:35:38 +0800 Subject: [PATCH 0607/1472] Use Lowercase (#11059) --- utils/frame/try-runtime/cli/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 2298fa5c042ee..ef8db7a1e5a0c 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -619,7 +619,7 @@ pub(crate) async fn ensure_matching_spec { // first, deal with spec name - if expected_spec_name == name { + if expected_spec_name.to_lowercase() == name { log::info!(target: LOG_TARGET, "found matching spec name: {:?}", name); } else { let msg = format!( From cdf591a4ec194bf8232915ef109874c3baec39a0 Mon Sep 17 00:00:00 2001 From: AurevoirXavier Date: Fri, 18 Mar 2022 23:03:21 +0800 Subject: [PATCH 0608/1472] Expose `ToOwned` (#11060) --- primitives/std/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/primitives/std/src/lib.rs b/primitives/std/src/lib.rs index 03a079e3965f4..05dff0f3077b6 100644 --- a/primitives/std/src/lib.rs +++ b/primitives/std/src/lib.rs @@ -99,6 +99,7 @@ impl Writer { /// This should include only things which are in the normal std prelude. pub mod prelude { pub use crate::{ + borrow::ToOwned, boxed::Box, clone::Clone, cmp::{Eq, PartialEq, Reverse}, From 2892d23e3f0d254dcd8068852c365e7dcbd48386 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Mar 2022 15:25:16 +0000 Subject: [PATCH 0609/1472] Bump serde_json from 1.0.74 to 1.0.79 (#11020) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.74 to 1.0.79. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.74...v1.0.79) --- 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 ++-- bin/node/bench/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- frame/transaction-payment/asset-tx-payment/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/serializer/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- 24 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb9561dfabdcb..d3b0771c451c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9399,9 +9399,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.74" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ "itoa 1.0.1", "ryu", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 5b728258dd03b..7bdf46e2b6600 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -18,7 +18,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } serde = "1.0.136" -serde_json = "1.0.74" +serde_json = "1.0.79" derive_more = "0.99.16" kvdb = "0.11.0" kvdb-rocksdb = "0.15.1" diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 071b07b6b2294..ebbb9527f9367 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -31,7 +31,7 @@ beefy-gadget = { version = "4.0.0-dev", path = "../." } beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } [dev-dependencies] -serde_json = "1.0.74" +serde_json = "1.0.79" sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ "test-helpers", diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 68d591254d213..e18f9b72c75e4 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -18,7 +18,7 @@ impl-trait-for-tuples = "0.2.1" sc-network = { version = "0.10.0-dev", path = "../network" } sp-core = { version = "6.0.0", path = "../../primitives/core" } serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.74" +serde_json = "1.0.79" sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index c799fd6dee980..665bd6acfaf33 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -25,7 +25,7 @@ rand = "0.7.3" regex = "1.5.4" rpassword = "5.0.0" serde = "1.0.136" -serde_json = "1.0.74" +serde_json = "1.0.79" thiserror = "1.0.30" tiny-bip39 = "0.8.2" tokio = { version = "1.15", features = ["signal", "rt-multi-thread", "parking_lot"] } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 7db7edd2de133..ee6549480a6d2 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -33,7 +33,7 @@ sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } [dev-dependencies] sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } -serde_json = "1.0.74" +serde_json = "1.0.79" sp-keyring = { version = "6.0.0", path = "../../../../primitives/keyring" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 9733f35bd0e93..86cd57fc7c092 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -37,7 +37,7 @@ sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -serde_json = "1.0.74" +serde_json = "1.0.79" sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 09fca2a843a13..844110f668869 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -22,7 +22,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } hex = "0.4.0" parking_lot = "0.12.0" -serde_json = "1.0.74" +serde_json = "1.0.79" [dev-dependencies] tempfile = "3.1.0" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 0dbdd3ec50e95..671271fcb3b77 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -45,7 +45,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.74" +serde_json = "1.0.79" smallvec = "1.8.0" sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index 1bbf8bd6e9cba..12991eac81bdc 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.19" libp2p = { version = "0.40.0", default-features = false } sc-utils = { version = "4.0.0-dev", path = "../utils"} log = "0.4.8" -serde_json = "1.0.74" +serde_json = "1.0.79" wasm-timer = "0.2" [dev-dependencies] diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 510c59e5b8aac..38ac1fc443351 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -28,7 +28,7 @@ sp-version = { version = "5.0.0", path = "../../primitives/version" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.74" +serde_json = "1.0.79" sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index 496152ecb7505..f0c3fd496aa70 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -18,7 +18,7 @@ jsonrpc-core = "18.0.0" pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} -serde_json = "1.0.74" +serde_json = "1.0.79" tokio = { version = "1.15", features = ["parking_lot"] } http = { package = "jsonrpc-http-server", version = "18.0.0" } ipc = { package = "jsonrpc-ipc-server", version = "18.0.0" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 314c49d2f862c..eeeb67f362617 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -23,7 +23,7 @@ log = "0.4.8" sp-core = { version = "6.0.0", path = "../../primitives/core" } rpc = { package = "jsonrpc-core", version = "18.0.0" } sp-version = { version = "5.0.0", path = "../../primitives/version" } -serde_json = "1.0.74" +serde_json = "1.0.79" sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 84ac9e3de642b..737a29f1db0c0 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -34,7 +34,7 @@ exit-future = "0.2.0" pin-project = "1.0.10" hash-db = "0.15.2" serde = "1.0.136" -serde_json = "1.0.74" +serde_json = "1.0.79" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-trie = { version = "6.0.0", path = "../../primitives/trie" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index e6072267f9638..e13631f210bc0 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -22,7 +22,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-consensus-babe = { version = "0.10.0-dev", path = "../consensus/babe" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } -serde_json = "1.0.74" +serde_json = "1.0.79" serde = { version = "1.0.136", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 7bdd60a037e17..6daa75f453629 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -23,6 +23,6 @@ log = "0.4.8" pin-project = "1.0.10" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.74" +serde_json = "1.0.79" chrono = "0.4.19" thiserror = "1.0.30" diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 7124682c5689a..9ac26c2ed54b2 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -27,4 +27,4 @@ sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } [dev-dependencies] -serde_json = "1.0.74" +serde_json = "1.0.79" diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index ea894e7cada66..d37a98deecb2a 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -29,7 +29,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] -serde_json = "1.0.74" +serde_json = "1.0.79" pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index ec07fc967c923..0c2bcb730aa75 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -30,7 +30,7 @@ serde = { version = "1.0.136", optional = true } [dev-dependencies] smallvec = "1.8.0" -serde_json = "1.0.74" +serde_json = "1.0.79" sp-storage = { version = "6.0.0", default-features = false, path = "../../../primitives/storage" } diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index f2d048ef713e7..dcfd48558de25 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -18,4 +18,4 @@ sp-core = { version = "6.0.0", path = "../core" } rustc-hash = "1.1.0" [dev-dependencies] -serde_json = "1.0.74" +serde_json = "1.0.79" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 5f7b45ba15a8c..a0acdaf27dc5b 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -32,7 +32,7 @@ hash256-std-hasher = { version = "0.15.2", default-features = false } either = { version = "1.5", default-features = false } [dev-dependencies] -serde_json = "1.0.74" +serde_json = "1.0.79" rand = "0.7.2" sp-state-machine = { version = "0.12.0", path = "../state-machine" } sp-api = { version = "4.0.0-dev", path = "../api" } diff --git a/primitives/serializer/Cargo.toml b/primitives/serializer/Cargo.toml index 6a9fb5d90ddb4..c81f1cd10a824 100644 --- a/primitives/serializer/Cargo.toml +++ b/primitives/serializer/Cargo.toml @@ -15,4 +15,4 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = "1.0.136" -serde_json = "1.0.74" +serde_json = "1.0.79" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index f3299d800a6f7..1f7115cf16cf8 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.19" hex = "0.4" serde = "1.0.136" -serde_json = "1.0.74" +serde_json = "1.0.79" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } sc-client-db = { version = "0.10.0-dev", features = [ "test-helpers", diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 5575bb833ca77..b28fe195a2f31 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -38,7 +38,7 @@ codec = { version = "3.0.0", package = "parity-scale-codec" } clap = { version = "3.1.6", features = ["derive"] } chrono = "0.4" serde = "1.0.136" -serde_json = "1.0.74" +serde_json = "1.0.79" handlebars = "4.1.6" Inflector = "0.11.4" linked-hash-map = "0.5.4" From c364008a6c7da8456e17967f55edf51e45146998 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Mar 2022 17:16:09 +0000 Subject: [PATCH 0610/1472] Bump proc-macro-crate from 1.1.0 to 1.1.3 (#11063) Bumps [proc-macro-crate](https://github.com/bkchr/proc-macro-crate) from 1.1.0 to 1.1.3. - [Release notes](https://github.com/bkchr/proc-macro-crate/releases) - [Commits](https://github.com/bkchr/proc-macro-crate/commits) --- updated-dependencies: - dependency-name: proc-macro-crate 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 +++++++++---------- client/chain-spec/derive/Cargo.toml | 2 +- client/tracing/proc-macro/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/support/procedural/tools/Cargo.toml | 2 +- primitives/api/proc-macro/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- test-utils/derive/Cargo.toml | 2 +- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3b0771c451c5..70a50a6f3e23b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2168,7 +2168,7 @@ version = "4.0.0-dev" dependencies = [ "frame-election-provider-support", "parity-scale-codec", - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "scale-info", @@ -2290,7 +2290,7 @@ name = "frame-support-procedural-tools" version = "4.0.0-dev" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn", @@ -3448,7 +3448,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4299ebf790ea9de1cb72e73ff2ae44c723ef264299e5e2d5ef46a371eb3ac3d8" dependencies = [ - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn", @@ -4663,7 +4663,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99" dependencies = [ - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro-error", "proc-macro2", "quote", @@ -6441,7 +6441,7 @@ dependencies = [ name = "pallet-staking-reward-curve" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "sp-runtime", @@ -6736,7 +6736,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6e626dc84025ff56bf1476ed0e30d10c84d7f89a475ef46ebabee1095a8fba" dependencies = [ - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn", @@ -7230,9 +7230,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ "thiserror", "toml", @@ -8107,7 +8107,7 @@ dependencies = [ name = "sc-chain-spec-derive" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn", @@ -9092,7 +9092,7 @@ dependencies = [ name = "sc-tracing-proc-macro" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn", @@ -9177,7 +9177,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7805950c36512db9e3251c970bb7ac425f326716941862205d612ab3b5e46e2" dependencies = [ - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn", @@ -9670,7 +9670,7 @@ name = "sp-api-proc-macro" version = "4.0.0-dev" dependencies = [ "blake2 0.10.2", - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn", @@ -10193,7 +10193,7 @@ name = "sp-runtime-interface-proc-macro" version = "5.0.0" dependencies = [ "Inflector", - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn", @@ -10773,7 +10773,7 @@ dependencies = [ name = "substrate-test-utils-derive" version = "0.10.0-dev" dependencies = [ - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn", diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index 1ea9440572d47..9aa1d6c09405c 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro-crate = "1.1.0" +proc-macro-crate = "1.1.3" proc-macro2 = "1.0.36" quote = "1.0.10" syn = "1.0.82" diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index e939d0837b216..645a6ed93a16f 100644 --- a/client/tracing/proc-macro/Cargo.toml +++ b/client/tracing/proc-macro/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro-crate = "1.1.0" +proc-macro-crate = "1.1.3" proc-macro2 = "1.0.36" quote = { version = "1.0.10", features = ["proc-macro"] } syn = { version = "1.0.82", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index 09747eebe2dff..e59bbcc8e7b38 100644 --- a/frame/election-provider-support/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true syn = { version = "1.0.82", features = ["full", "visit"] } quote = "1.0" proc-macro2 = "1.0.36" -proc-macro-crate = "1.1.0" +proc-macro-crate = "1.1.3" [dev-dependencies] parity-scale-codec = "3.0.0" diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index 82167bd8c8ec4..d53fb72b0e08a 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true syn = { version = "1.0.82", features = ["full", "visit"] } quote = "1.0.10" proc-macro2 = "1.0.36" -proc-macro-crate = "1.1.0" +proc-macro-crate = "1.1.3" [dev-dependencies] sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index ae2de2effd4ae..b38071dd31585 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -16,4 +16,4 @@ frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" } proc-macro2 = "1.0.36" quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "visit", "extra-traits"] } -proc-macro-crate = "1.1.0" +proc-macro-crate = "1.1.3" diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index 356e15a6fd115..dc5deb2efa668 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -20,7 +20,7 @@ quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.36" blake2 = { version = "0.10.2", default-features = false } -proc-macro-crate = "1.1.0" +proc-macro-crate = "1.1.3" # Required for the doc tests [features] diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 57e5448348d6c..ef59e0119f9fe 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -20,4 +20,4 @@ syn = { version = "1.0.82", features = ["full", "visit", "fold", "extra-traits"] quote = "1.0.10" proc-macro2 = "1.0.36" Inflector = "0.11.4" -proc-macro-crate = "1.1.0" +proc-macro-crate = "1.1.3" diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index 166d9cc1eff17..16e0b9822f7bb 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -11,7 +11,7 @@ description = "Substrate test utilities macros" [dependencies] quote = "1.0.10" syn = { version = "1.0.82", features = ["full"] } -proc-macro-crate = "1.1.0" +proc-macro-crate = "1.1.3" proc-macro2 = "1.0.36" [lib] From 4c9bf004f07c698451de5bc7749d0e23f08b7eea Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sat, 19 Mar 2022 11:35:39 +0000 Subject: [PATCH 0611/1472] some additional utils for state-trie-migration (#11064) * some additional utils for state-trie-migration' * Update frame/state-trie-migration/src/lib.rs Co-authored-by: cheme Co-authored-by: cheme --- bin/node/runtime/src/lib.rs | 3 -- frame/state-trie-migration/src/lib.rs | 75 ++++++++++++++++++++++----- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 797e0c079028e..d679af6f51c42 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1372,8 +1372,6 @@ impl pallet_whitelist::Config for Runtime { } parameter_types! { - pub const SignedMigrationMaxLimits: pallet_state_trie_migration::MigrationLimits = - pallet_state_trie_migration::MigrationLimits { size: 1024 * 1024 / 2, item: 512 }; pub const MigrationSignedDepositPerItem: Balance = 1 * CENTS; pub const MigrationSignedDepositBase: Balance = 20 * DOLLARS; } @@ -1384,7 +1382,6 @@ impl pallet_state_trie_migration::Config for Runtime { type Currency = Balances; type SignedDepositPerItem = MigrationSignedDepositPerItem; type SignedDepositBase = MigrationSignedDepositBase; - type SignedMigrationMaxLimits = SignedMigrationMaxLimits; // Warning: this is not advised, as it might allow the chain to be temporarily DOS-ed. // Preferably, if the chain's governance/maintenance team is planning on using a specific // account for the migration, put it here to make sure only that account can trigger the signed diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index a5a077c54e579..87be4099c89c8 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -123,10 +123,14 @@ pub mod pallet { } } + /// The progress of either the top or child keys. #[derive(Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq)] - pub(crate) enum Progress { + pub enum Progress { + /// Yet to begin. ToStart, + /// Ongoing, with the last key given. LastKey(Vec), + /// All done. Complete, } @@ -447,10 +451,6 @@ pub mod pallet { /// Final deposit is `items * SignedDepositPerItem + SignedDepositBase`. type SignedDepositBase: Get>; - /// The maximum limits that the signed migration could use. - #[pallet::constant] - type SignedMigrationMaxLimits: Get; - /// The weight information of this pallet. type WeightInfo: WeightInfo; } @@ -470,6 +470,13 @@ pub mod pallet { #[pallet::getter(fn auto_limits)] pub type AutoLimits = StorageValue<_, Option, ValueQuery>; + /// The maximum limits that the signed migration could use. + /// + /// If not set, no signed submission is allowed. + #[pallet::storage] + #[pallet::getter(fn signed_migration_max_limits)] + pub type SignedMigrationMaxLimits = StorageValue<_, MigrationLimits, OptionQuery>; + #[pallet::error] pub enum Error { /// max signed limits not respected. @@ -480,6 +487,8 @@ pub mod pallet { BadWitness, /// upper bound of size is exceeded, SizeUpperBoundExceeded, + /// Signed migration is not allowed because the maximum limit is not set yet. + SignedMigrationNotAllowed, } #[pallet::call] @@ -491,7 +500,7 @@ pub mod pallet { pub fn control_auto_migration( origin: OriginFor, maybe_config: Option, - ) -> DispatchResultWithPostInfo { + ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; AutoLimits::::put(maybe_config); Ok(().into()) @@ -532,7 +541,8 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = T::SignedFilter::ensure_origin(origin)?; - let max_limits = T::SignedMigrationMaxLimits::get(); + let max_limits = + Self::signed_migration_max_limits().ok_or(Error::::SignedMigrationNotAllowed)?; ensure!( limits.size <= max_limits.size && limits.item <= max_limits.item, Error::::MaxSignedLimits, @@ -701,6 +711,40 @@ pub mod pallet { }) } } + + /// Set the maximum limit of the signed migration. + #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] + pub fn set_signed_max_limits( + origin: OriginFor, + limits: MigrationLimits, + ) -> DispatchResult { + let _ = T::ControlOrigin::ensure_origin(origin)?; + SignedMigrationMaxLimits::::put(limits); + Ok(()) + } + + /// Forcefully set the progress the running migration. + /// + /// This is only useful in one case: the next key to migrate is too big to be migrated with + /// a signed account, in a parachain context, and we simply want to skip it. A reasonable + /// example of this would be `:code:`, which is both very expensive to migrate, and commonly + /// used, so probably it is already migrated. + /// + /// In case you mess things up, you can also, in principle, use this to reset the migration + /// process. + #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] + pub fn force_set_progress( + origin: OriginFor, + progress_top: Progress, + progress_child: Progress, + ) -> DispatchResult { + let _ = T::ControlOrigin::ensure_origin(origin)?; + MigrationProcess::::mutate(|task| { + task.progress_top = progress_top; + task.progress_child = progress_child; + }); + Ok(()) + } } #[pallet::hooks] @@ -1000,7 +1044,6 @@ mod mock { pub const OffchainRepeat: u32 = 1; pub const SignedDepositPerItem: u64 = 1; pub const SignedDepositBase: u64 = 5; - pub const SignedMigrationMaxLimits: MigrationLimits = MigrationLimits { size: 1024, item: 5 }; } impl pallet_balances::Config for Test { @@ -1021,7 +1064,6 @@ mod mock { type Currency = Balances; type SignedDepositPerItem = SignedDepositPerItem; type SignedDepositBase = SignedDepositBase; - type SignedMigrationMaxLimits = SignedMigrationMaxLimits; type SignedFilter = EnsureSigned; type WeightInfo = (); } @@ -1104,7 +1146,14 @@ mod mock { } sp_tracing::try_init_simple(); - (custom_storage, version).into() + let mut ext: sp_io::TestExternalities = (custom_storage, version).into(); + + // set some genesis values for this pallet as well. + ext.execute_with(|| { + SignedMigrationMaxLimits::::put(MigrationLimits { size: 1024, item: 5 }); + }); + + ext } pub(crate) fn run_to_block(n: u32) -> (H256, u64) { @@ -1283,11 +1332,13 @@ mod test { while !MigrationProcess::::get().finished() { // first we compute the task to get the accurate consumption. let mut task = StateTrieMigration::migration_process(); - task.migrate_until_exhaustion(SignedMigrationMaxLimits::get()); + task.migrate_until_exhaustion( + StateTrieMigration::signed_migration_max_limits().unwrap(), + ); frame_support::assert_ok!(StateTrieMigration::continue_migrate( Origin::signed(1), - SignedMigrationMaxLimits::get(), + StateTrieMigration::signed_migration_max_limits().unwrap(), task.dyn_size, MigrationProcess::::get() )); From 8cbda809d3495f38ce04eec46e90330db213af8a Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sat, 19 Mar 2022 12:24:41 +0000 Subject: [PATCH 0612/1472] Incorporate the new electing/electable naming into the code (#10956) * Incorporate the new electing/electable naming into the code * Update frame/election-provider-support/src/lib.rs Co-authored-by: Zeke Mostov * Update frame/election-provider-support/src/lib.rs Co-authored-by: Zeke Mostov * Some additional changes * fmt * update codec * revert lock file to master * fix doc test Co-authored-by: Zeke Mostov --- bin/node/runtime/src/lib.rs | 16 +++---- frame/bags-list/remote-tests/src/snapshot.rs | 3 +- .../src/benchmarking.rs | 4 +- .../election-provider-multi-phase/src/lib.rs | 37 +++++++-------- .../election-provider-multi-phase/src/mock.rs | 13 +++-- frame/election-provider-support/src/lib.rs | 17 ++++--- .../election-provider-support/src/onchain.rs | 11 +++-- frame/staking/src/pallet/impls.rs | 4 +- frame/staking/src/tests.rs | 47 ++++++++++--------- 9 files changed, 82 insertions(+), 70 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index d679af6f51c42..64bdcfc870205 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -46,11 +46,12 @@ use frame_system::{ pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; use pallet_contracts::weights::WeightInfo; +use pallet_election_provider_multi_phase::SolutionAccuracyOf; use pallet_grandpa::{ fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, }; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; -use pallet_session::historical as pallet_session_historical; +use pallet_session::historical::{self as pallet_session_historical}; pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; use sp_api::impl_runtime_apis; @@ -668,20 +669,17 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type DataProvider = Staking; type Solution = NposSolution16; type Fallback = pallet_election_provider_multi_phase::NoFallback; - type GovernanceFallback = - frame_election_provider_support::onchain::OnChainSequentialPhragmen; + type GovernanceFallback = onchain::OnChainSequentialPhragmen; type Solver = frame_election_provider_support::SequentialPhragmen< AccountId, - pallet_election_provider_multi_phase::SolutionAccuracyOf, + SolutionAccuracyOf, OffchainRandomBalancing, >; - type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; type ForceOrigin = EnsureRootOrHalfCouncil; + type MaxElectableTargets = ConstU16<{ u16::MAX }>; + type MaxElectingVoters = ConstU32<10_000>; type BenchmarkingConfig = ElectionProviderBenchmarkConfig; - // BagsList allows a practically unbounded count of nominators to participate in NPoS elections. - // To ensure we respect memory limits when using the BagsList this must be set to a number of - // voters we know can fit into a single vec allocation. - type VoterSnapshotPerBlock = ConstU32<10_000>; + type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; } parameter_types! { diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index 241b64b366117..2d996746a29cc 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -56,7 +56,8 @@ pub async fn execute ); let voters = - as ElectionDataProvider>::voters(voter_limit).unwrap(); + as ElectionDataProvider>::electing_voters(voter_limit) + .unwrap(); let mut voters_nominator_only = voters .iter() diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 2a9286369f394..923e9e2d984cc 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -260,8 +260,8 @@ frame_benchmarking::benchmarks! { // we don't directly need the data-provider to be populated, but it is just easy to use it. set_up_data_provider::(v, t); - let targets = T::DataProvider::targets(None)?; - let voters = T::DataProvider::voters(None)?; + let targets = T::DataProvider::electable_targets(None)?; + let voters = T::DataProvider::electing_voters(None)?; let desired_targets = T::DataProvider::desired_targets()?; assert!(>::snapshot().is_none()); }: { diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 90c540b85d67d..b57d24d2d530c 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -69,7 +69,7 @@ //! Upon the end of the signed phase, the solutions are examined from best to worse (i.e. `pop()`ed //! until drained). Each solution undergoes an expensive `Pallet::feasibility_check`, which ensures //! the score claimed by this score was correct, and it is valid based on the election data (i.e. -//! votes and candidates). At each step, if the current best solution passes the feasibility check, +//! votes and targets). At each step, if the current best solution passes the feasibility check, //! it is considered to be the best one. The sender of the origin is rewarded, and the rest of the //! queued solutions get their deposit back and are discarded, without being checked. //! @@ -249,7 +249,6 @@ use sp_npos_elections::{ assignment_ratio_to_staked_normalized, ElectionScore, EvaluateSupport, Supports, VoteWeight, }; use sp_runtime::{ - traits::Bounded, transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, @@ -643,14 +642,15 @@ pub mod pallet { #[pallet::constant] type SignedDepositWeight: Get>; - /// The maximum number of voters to put in the snapshot. At the moment, snapshots are only - /// over a single block, but once multi-block elections are introduced they will take place - /// over multiple blocks. - /// - /// Also, note the data type: If the voters are represented by a `u32` in `type - /// CompactSolution`, the same `u32` is used here to ensure bounds are respected. + /// The maximum number of electing voters to put in the snapshot. At the moment, snapshots + /// are only over a single block, but once multi-block elections are introduced they will + /// take place over multiple blocks. + #[pallet::constant] + type MaxElectingVoters: Get>; + + /// The maximum number of electable targets to put in the snapshot. #[pallet::constant] - type VoterSnapshotPerBlock: Get>; + type MaxElectableTargets: Get>; /// Handler for the slashed deposits. type SlashHandler: OnUnbalanced>; @@ -817,7 +817,7 @@ pub mod pallet { fn integrity_test() { use sp_std::mem::size_of; // The index type of both voters and targets need to be smaller than that of usize (very - // unlikely to be the case, but anyhow). + // unlikely to be the case, but anyhow).. assert!(size_of::>() <= size_of::()); assert!(size_of::>() <= size_of::()); @@ -1338,14 +1338,13 @@ impl Pallet { /// Extracted for easier weight calculation. fn create_snapshot_external( ) -> Result<(Vec, Vec>, u32), ElectionError> { - let target_limit = >::max_value().saturated_into::(); - // for now we have just a single block snapshot. - let voter_limit = T::VoterSnapshotPerBlock::get().saturated_into::(); - - let targets = - T::DataProvider::targets(Some(target_limit)).map_err(ElectionError::DataProvider)?; - let voters = - T::DataProvider::voters(Some(voter_limit)).map_err(ElectionError::DataProvider)?; + let target_limit = T::MaxElectableTargets::get().saturated_into::(); + let voter_limit = T::MaxElectingVoters::get().saturated_into::(); + + let targets = T::DataProvider::electable_targets(Some(target_limit)) + .map_err(ElectionError::DataProvider)?; + let voters = T::DataProvider::electing_voters(Some(voter_limit)) + .map_err(ElectionError::DataProvider)?; let mut desired_targets = T::DataProvider::desired_targets().map_err(ElectionError::DataProvider)?; @@ -2090,7 +2089,7 @@ mod tests { // we have 8 voters in total. assert_eq!(crate::mock::Voters::get().len(), 8); // but we want to take 2. - crate::mock::VoterSnapshotPerBlock::set(2); + crate::mock::MaxElectingVoters::set(2); // Signed phase opens just fine. roll_to(15); diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index d09d45784cba4..89b5b72565dcb 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -263,7 +263,8 @@ parameter_types! { pub static MinerMaxWeight: Weight = BlockWeights::get().max_block; pub static MinerMaxLength: u32 = 256; pub static MockWeightInfo: bool = false; - pub static VoterSnapshotPerBlock: VoterIndex = u32::max_value(); + pub static MaxElectingVoters: VoterIndex = u32::max_value(); + pub static MaxElectableTargets: TargetIndex = TargetIndex::max_value(); pub static EpochLength: u64 = 30; pub static OnChianFallback: bool = true; @@ -413,7 +414,8 @@ impl crate::Config for Runtime { type GovernanceFallback = NoFallback; type ForceOrigin = frame_system::EnsureRoot; type Solution = TestNposSolution; - type VoterSnapshotPerBlock = VoterSnapshotPerBlock; + type MaxElectingVoters = MaxElectingVoters; + type MaxElectableTargets = MaxElectableTargets; type Solver = SequentialPhragmen, Balancing>; } @@ -439,7 +441,8 @@ impl ElectionDataProvider for StakingMock { type AccountId = AccountId; type BlockNumber = u64; type MaxVotesPerVoter = MaxNominations; - fn targets(maybe_max_len: Option) -> data_provider::Result> { + + fn electable_targets(maybe_max_len: Option) -> data_provider::Result> { let targets = Targets::get(); if maybe_max_len.map_or(false, |max_len| targets.len() > max_len) { @@ -449,7 +452,9 @@ impl ElectionDataProvider for StakingMock { Ok(targets) } - fn voters(maybe_max_len: Option) -> data_provider::Result>> { + fn electing_voters( + maybe_max_len: Option, + ) -> data_provider::Result>> { let mut voters = Voters::get(); if let Some(max_len) = maybe_max_len { voters.truncate(max_len) diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index e1975a2681e6a..81fd841a6dc47 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -107,12 +107,12 @@ //! fn desired_targets() -> data_provider::Result { //! Ok(1) //! } -//! fn voters(maybe_max_len: Option) +//! fn electing_voters(maybe_max_len: Option) //! -> data_provider::Result>> //! { //! Ok(Default::default()) //! } -//! fn targets(maybe_max_len: Option) -> data_provider::Result> { +//! fn electable_targets(maybe_max_len: Option) -> data_provider::Result> { //! Ok(vec![10, 20, 30]) //! } //! fn next_election_prediction(now: BlockNumber) -> BlockNumber { @@ -138,7 +138,7 @@ //! type DataProvider = T::DataProvider; //! //! fn elect() -> Result, Self::Error> { -//! Self::DataProvider::targets(None) +//! Self::DataProvider::electable_targets(None) //! .map_err(|_| "failed to elect") //! .map(|t| vec![(t[0], Support::default())]) //! } @@ -265,16 +265,19 @@ pub trait ElectionDataProvider { /// Maximum number of votes per voter that this data provider is providing. type MaxVotesPerVoter: Get; - /// All possible targets for the election, i.e. the candidates. + /// All possible targets for the election, i.e. the targets that could become elected, thus + /// "electable". /// /// If `maybe_max_len` is `Some(v)` then the resulting vector MUST NOT be longer than `v` items /// long. /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. - fn targets(maybe_max_len: Option) -> data_provider::Result>; + fn electable_targets( + maybe_max_len: Option, + ) -> data_provider::Result>; - /// All possible voters for the election. + /// All the voters that participate in the election, thus "electing". /// /// Note that if a notion of self-vote exists, it should be represented here. /// @@ -283,7 +286,7 @@ pub trait ElectionDataProvider { /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. - fn voters(maybe_max_len: Option) -> data_provider::Result>>; + fn electing_voters(maybe_max_len: Option) -> data_provider::Result>>; /// The number of targets to elect. /// diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 41245f67fb02c..7d845c2dc5ab3 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -79,10 +79,11 @@ impl OnChainSequentialPhragmen { maybe_max_voters: Option, maybe_max_targets: Option, ) -> Result, Error> { - let voters = ::DataProvider::voters(maybe_max_voters) - .map_err(Error::DataProvider)?; - let targets = ::DataProvider::targets(maybe_max_targets) + let voters = ::DataProvider::electing_voters(maybe_max_voters) .map_err(Error::DataProvider)?; + let targets = + ::DataProvider::electable_targets(maybe_max_targets) + .map_err(Error::DataProvider)?; let desired_targets = ::DataProvider::desired_targets() .map_err(Error::DataProvider)?; @@ -197,7 +198,7 @@ mod tests { type AccountId = AccountId; type BlockNumber = BlockNumber; type MaxVotesPerVoter = ConstU32<2>; - fn voters(_: Option) -> data_provider::Result>> { + fn electing_voters(_: Option) -> data_provider::Result>> { Ok(vec![ (1, 10, bounded_vec![10, 20]), (2, 20, bounded_vec![30, 20]), @@ -205,7 +206,7 @@ mod tests { ]) } - fn targets(_: Option) -> data_provider::Result> { + fn electable_targets(_: Option) -> data_provider::Result> { Ok(vec![10, 20, 30]) } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index a4aadb16ab1b9..cb024ba2bc524 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -860,7 +860,7 @@ impl ElectionDataProvider for Pallet { Ok(Self::validator_count()) } - fn voters(maybe_max_len: Option) -> data_provider::Result>> { + fn electing_voters(maybe_max_len: Option) -> data_provider::Result>> { // This can never fail -- if `maybe_max_len` is `Some(_)` we handle it. let voters = Self::get_npos_voters(maybe_max_len); debug_assert!(maybe_max_len.map_or(true, |max| voters.len() <= max)); @@ -868,7 +868,7 @@ impl ElectionDataProvider for Pallet { Ok(voters) } - fn targets(maybe_max_len: Option) -> data_provider::Result> { + fn electable_targets(maybe_max_len: Option) -> data_provider::Result> { let target_count = Validators::::count(); // We can't handle this case yet -- return an error. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 2b2a32e0edab7..2d4145242a45c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4055,10 +4055,12 @@ mod election_data_provider { #[test] fn voters_include_self_vote() { ExtBuilder::default().nominate(false).build_and_execute(|| { - assert!(>::iter().map(|(x, _)| x).all(|v| Staking::voters(None) - .unwrap() - .into_iter() - .any(|(w, _, t)| { v == w && t[0] == w }))) + assert!(>::iter().map(|(x, _)| x).all(|v| Staking::electing_voters( + None + ) + .unwrap() + .into_iter() + .any(|(w, _, t)| { v == w && t[0] == w }))) }) } @@ -4067,7 +4069,7 @@ mod election_data_provider { ExtBuilder::default().build_and_execute(|| { assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); assert_eq!( - ::voters(None) + ::electing_voters(None) .unwrap() .iter() .find(|x| x.0 == 101) @@ -4082,7 +4084,7 @@ mod election_data_provider { // 11 is gone. start_active_era(2); assert_eq!( - ::voters(None) + ::electing_voters(None) .unwrap() .iter() .find(|x| x.0 == 101) @@ -4094,7 +4096,7 @@ mod election_data_provider { // resubmit and it is back assert_ok!(Staking::nominate(Origin::signed(100), vec![11, 21])); assert_eq!( - ::voters(None) + ::electing_voters(None) .unwrap() .iter() .find(|x| x.0 == 101) @@ -4118,20 +4120,23 @@ mod election_data_provider { ); // if limits is less.. - assert_eq!(Staking::voters(Some(1)).unwrap().len(), 1); + assert_eq!(Staking::electing_voters(Some(1)).unwrap().len(), 1); // if limit is equal.. - assert_eq!(Staking::voters(Some(5)).unwrap().len(), 5); + assert_eq!(Staking::electing_voters(Some(5)).unwrap().len(), 5); // if limit is more. - assert_eq!(Staking::voters(Some(55)).unwrap().len(), 5); + assert_eq!(Staking::electing_voters(Some(55)).unwrap().len(), 5); // if target limit is more.. - assert_eq!(Staking::targets(Some(6)).unwrap().len(), 4); - assert_eq!(Staking::targets(Some(4)).unwrap().len(), 4); + assert_eq!(Staking::electable_targets(Some(6)).unwrap().len(), 4); + assert_eq!(Staking::electable_targets(Some(4)).unwrap().len(), 4); // if target limit is less, then we return an error. - assert_eq!(Staking::targets(Some(1)).unwrap_err(), "Target snapshot too big"); + assert_eq!( + Staking::electable_targets(Some(1)).unwrap_err(), + "Target snapshot too big" + ); }); } @@ -4165,7 +4170,7 @@ mod election_data_provider { // we take 4 voters: 2 validators and 2 nominators (so nominators quota = 2) assert_eq!( - Staking::voters(Some(3)) + Staking::electing_voters(Some(3)) .unwrap() .iter() .map(|(stash, _, _)| stash) @@ -4204,7 +4209,7 @@ mod election_data_provider { // we take 5 voters assert_eq!( - Staking::voters(Some(5)) + Staking::electing_voters(Some(5)) .unwrap() .iter() .map(|(stash, _, _)| stash) @@ -4225,7 +4230,7 @@ mod election_data_provider { // we take 4 voters assert_eq!( - Staking::voters(Some(4)) + Staking::electing_voters(Some(4)) .unwrap() .iter() .map(|(stash, _, _)| stash) @@ -4666,7 +4671,7 @@ fn change_of_max_nominations() { vec![(70, 3), (101, 2), (60, 1)] ); // 3 validators and 3 nominators - assert_eq!(Staking::voters(None).unwrap().len(), 3 + 3); + assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 3); // abrupt change from 16 to 4, everyone should be fine. MaxNominations::set(4); @@ -4677,7 +4682,7 @@ fn change_of_max_nominations() { .collect::>(), vec![(70, 3), (101, 2), (60, 1)] ); - assert_eq!(Staking::voters(None).unwrap().len(), 3 + 3); + assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 3); // abrupt change from 4 to 3, everyone should be fine. MaxNominations::set(3); @@ -4688,7 +4693,7 @@ fn change_of_max_nominations() { .collect::>(), vec![(70, 3), (101, 2), (60, 1)] ); - assert_eq!(Staking::voters(None).unwrap().len(), 3 + 3); + assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 3); // abrupt change from 3 to 2, this should cause some nominators to be non-decodable, and // thus non-existent unless if they update. @@ -4705,7 +4710,7 @@ fn change_of_max_nominations() { // but its value cannot be decoded and default is returned. assert!(Nominators::::get(70).is_none()); - assert_eq!(Staking::voters(None).unwrap().len(), 3 + 2); + assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 2); assert!(Nominators::::contains_key(101)); // abrupt change from 2 to 1, this should cause some nominators to be non-decodable, and @@ -4722,7 +4727,7 @@ fn change_of_max_nominations() { assert!(Nominators::::contains_key(60)); assert!(Nominators::::get(70).is_none()); assert!(Nominators::::get(60).is_some()); - assert_eq!(Staking::voters(None).unwrap().len(), 3 + 1); + assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 1); // now one of them can revive themselves by re-nominating to a proper value. assert_ok!(Staking::nominate(Origin::signed(71), vec![1])); From b64647c3a27f0461416c768822c670fe6f8564d9 Mon Sep 17 00:00:00 2001 From: Koute Date: Sun, 20 Mar 2022 04:11:02 +0900 Subject: [PATCH 0613/1472] Refactor WASM module instantiation (#10480) * Refactor WASM module instantiation; enable WASM instance pooling * Disable the `uffd` feature on `wasmtime` * Restore the original behavior regarding the initial WASM memory size * Adjust error message * Remove unnecessary import in the benchmarks * Preinstantiate the WASM runtime for a slight speedup * Delete the asserts in `convert_memory_import_into_export` * `return` -> `break` * Revert WASM instance pooling for now * Have `convert_memory_import_into_export` return an error instead of panic * Update the warning when an import is missing * Rustfmt and clippy fix * Fix executor benchmarks' compilation without `wasmtime` being enabled * rustfmt again * Align to review comments * Extend tests so that both imported and exported memories are tested * Increase the number of heap pages for exported memories too * Fix `decommit_works` test --- Cargo.lock | 2 + client/executor/Cargo.toml | 6 + client/executor/benches/bench.rs | 136 ++++++++++++ client/executor/benches/kusama_runtime.wasm | Bin 0 -> 5554150 bytes .../common/src/runtime_blob/runtime_blob.rs | 84 +++++++- client/executor/wasmtime/src/imports.rs | 162 +++----------- .../executor/wasmtime/src/instance_wrapper.rs | 91 ++++---- client/executor/wasmtime/src/runtime.rs | 106 ++++----- client/executor/wasmtime/src/tests.rs | 204 ++++++++++-------- 9 files changed, 468 insertions(+), 323 deletions(-) create mode 100644 client/executor/benches/bench.rs create mode 100755 client/executor/benches/kusama_runtime.wasm diff --git a/Cargo.lock b/Cargo.lock index 70a50a6f3e23b..2760ee0570d45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8464,6 +8464,8 @@ dependencies = [ name = "sc-executor" version = "0.10.0-dev" dependencies = [ + "criterion", + "env_logger 0.9.0", "hex-literal", "lazy_static", "lru 0.6.6", diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 96a9c0ba6e399..cba5892eace13 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -47,6 +47,12 @@ sc-tracing = { version = "4.0.0-dev", path = "../tracing" } tracing-subscriber = "0.2.19" paste = "1.0" regex = "1" +criterion = "0.3" +env_logger = "0.9" + +[[bench]] +name = "bench" +harness = false [features] default = ["std"] diff --git a/client/executor/benches/bench.rs b/client/executor/benches/bench.rs new file mode 100644 index 0000000000000..20632536571b2 --- /dev/null +++ b/client/executor/benches/bench.rs @@ -0,0 +1,136 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use criterion::{criterion_group, criterion_main, Criterion}; + +use sc_executor_common::{runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; +use sc_runtime_test::wasm_binary_unwrap as test_runtime; +use sp_wasm_interface::HostFunctions as _; +use std::sync::Arc; + +enum Method { + Interpreted, + #[cfg(feature = "wasmtime")] + Compiled { + fast_instance_reuse: bool, + }, +} + +// This is just a bog-standard Kusama runtime with the extra `test_empty_return` +// function copy-pasted from the test runtime. +fn kusama_runtime() -> &'static [u8] { + include_bytes!("kusama_runtime.wasm") +} + +fn initialize(runtime: &[u8], method: Method) -> Arc { + let blob = RuntimeBlob::uncompress_if_needed(runtime).unwrap(); + let host_functions = sp_io::SubstrateHostFunctions::host_functions(); + let heap_pages = 2048; + let allow_missing_func_imports = true; + + match method { + Method::Interpreted => sc_executor_wasmi::create_runtime( + blob, + heap_pages, + host_functions, + allow_missing_func_imports, + ) + .map(|runtime| -> Arc { Arc::new(runtime) }), + #[cfg(feature = "wasmtime")] + Method::Compiled { fast_instance_reuse } => + sc_executor_wasmtime::create_runtime::( + blob, + sc_executor_wasmtime::Config { + heap_pages, + max_memory_size: None, + allow_missing_func_imports, + cache_path: None, + semantics: sc_executor_wasmtime::Semantics { + fast_instance_reuse, + deterministic_stack_limit: None, + canonicalize_nans: false, + parallel_compilation: true, + }, + }, + ) + .map(|runtime| -> Arc { Arc::new(runtime) }), + } + .unwrap() +} + +fn bench_call_instance(c: &mut Criterion) { + let _ = env_logger::try_init(); + + #[cfg(feature = "wasmtime")] + { + let runtime = initialize(test_runtime(), Method::Compiled { fast_instance_reuse: true }); + c.bench_function("call_instance_test_runtime_with_fast_instance_reuse", |b| { + let mut instance = runtime.new_instance().unwrap(); + b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()) + }); + } + + #[cfg(feature = "wasmtime")] + { + let runtime = initialize(test_runtime(), Method::Compiled { fast_instance_reuse: false }); + c.bench_function("call_instance_test_runtime_without_fast_instance_reuse", |b| { + let mut instance = runtime.new_instance().unwrap(); + b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()); + }); + } + + #[cfg(feature = "wasmtime")] + { + let runtime = initialize(kusama_runtime(), Method::Compiled { fast_instance_reuse: true }); + c.bench_function("call_instance_kusama_runtime_with_fast_instance_reuse", |b| { + let mut instance = runtime.new_instance().unwrap(); + b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()) + }); + } + + #[cfg(feature = "wasmtime")] + { + let runtime = initialize(kusama_runtime(), Method::Compiled { fast_instance_reuse: false }); + c.bench_function("call_instance_kusama_runtime_without_fast_instance_reuse", |b| { + let mut instance = runtime.new_instance().unwrap(); + b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()); + }); + } + + { + let runtime = initialize(test_runtime(), Method::Interpreted); + c.bench_function("call_instance_test_runtime_interpreted", |b| { + let mut instance = runtime.new_instance().unwrap(); + b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()) + }); + } + + { + let runtime = initialize(kusama_runtime(), Method::Interpreted); + c.bench_function("call_instance_kusama_runtime_interpreted", |b| { + let mut instance = runtime.new_instance().unwrap(); + b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()) + }); + } +} + +criterion_group! { + name = benches; + config = Criterion::default(); + targets = bench_call_instance +} +criterion_main!(benches); diff --git a/client/executor/benches/kusama_runtime.wasm b/client/executor/benches/kusama_runtime.wasm new file mode 100755 index 0000000000000000000000000000000000000000..3470237fb5aeea2fc21c9efc5a214b0754f3afd6 GIT binary patch literal 5554150 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 R@EV##%=Od9YW3M5K^Vb=n#@W3T{1r zPRvX|14gk-zBdr~i0T8%LRFEF`eaIopSe&o?@2zYGTqR5h2^5@o|)YmvlYG%15uHx zIs_{et{3VSNL7JE+qWnPrQX23ig_0b*_3WBU=hg>o&1sj#ZjMlLM% zHd%>dGz>9}$Dw0PMXlj%=@?dF?o2v{6htjWM0osJ(lH$Aqji~djJi)N=op8SJYW?{ z9pi9|aNHOj183A&9iyob2g8Y4!jvdHYOg_QpK_m+bCA^bqtg;h)iz{LmM3_06^W&2 zg=YUfZY{y-VvzWkVWP!!bw`nk$l2^p#l7J^x~MBeNnuan%N(aGFhrR}_AQgnDkNzA z+b;`z1}N9eq?ib)ECUf$a~Bt;lkAF!WElv;hi?T5qt2*WXw{co70}08#r{f*+i0Yw z$B!m8AYjFi9x$nzT4sWb=%=2CR?$y~6VO70pv*ce{t-@6v&6L5QAw96%KKcVugjz>kTmtJb|B@_OlYi-jl7B_sWNt@ph0nNt zFh)19;Qz38U{&_bCq+7f`J~npm2eL7KoFH@;2P}WX!UhAtK5~lUxfV?y;GPEKcr*o z$0aGp_3U^$3{asg6xCcqLYs=>a9!KYQ{=!F((HXZAi7>K&gGPxs8#J1Iu7kpcl01j zH_r1RPWL*Cw`>aWmf^ux97bc}DTZ=3`Q9TozBRPrsY(oXcc|BgIVU2q0PNYo-5(at zt_=Y%LGnyMF{%r^(4=&9z(=i0jtfcJ2JXuZ6uBqU6DHdGG(G_<`)7j~5>Wb_wc9e6 zLMpWn3987drJk-LG0fPnPt4gW2Lr6BL)P^c(S6iUhSy&5wJv$_Y)y|?PitVvy5(m2 zqPzA6%yGF)%$2l9fb=Ymst*@ZNYWDkN_xtKc~GIFep8pLcA4q&VY?Is!5OjY4bJyN z)Bo@pB0V9LF>4MBE1Oh&Oc5Y&-<$36=a2Jh=9fw`;v{;lqRJ`RTKdlrg}Mjl@-oRK zD~EUB@liCJDV)^byF5%~dkS!QgKYT8RE`P(lD%Lsp4{>|c^w`%Y4#P+3Z@q*U` zY-(F-@$?}IzyZe!|LUZ?DfyTzaU|5cH9Q;UXHQf>Xk^aB9u$*c4CAZ~uw`yX_%9u#nsJkjrXuX--<2E~j&G?A zM}_47u%lx5$WI>nVN)RiKj`jAQXU(^LSQqMHMT|TiRV5%sZGmh zY*#Oo`cVi0>W#8d%=7R>%0L0|Aq032@0N*c@*x&StyqtG&-ta!$r*@=Yg#u_*D?!t z=<-;G@U!d?rLKhv$-ESp;SuYM!BkS$GC8J6T~mTuQ<`(T*%U74lRGHokfs&yJ(ZNVPFc<}cW;!0`2;b|O z``4SC7Gr-owL90J+P?bK3R}xN(AAc*ec5(0Qj1qfSC+erpw|oK#&7PD=fZC&fdYMl z8`sT+@CrD!xctSV|Ge;01OzGIlP}ut(X?Cn)a;?<#`4OcZ~b&70ex>Kl~VTft(kJm zU;phleZP5=a>hv`w;hatN<_;x#P0;%mGm6m(VoT~1i$-Rg~-Ldw!5*+E?^GFHwD4O zG`8ehe_aK%etnOI#jooby9#RQpBHc6uAJ5RtkpF9Wshqy(feoroNTYvjkE&_; zkrSVJ_oohh>AjBvBtb!wKGhs-Co!1+ucz^mrochVh3U42 zS@NN@v6v-^Fw*8cYtt&m+v71i&b50xUrFQtkxM{k1sDW?HGGCTugf*;itrm-Y=T%Y zPp;)NXjtz=BNu^Jb{9|dPU{2GKXm6fo2NyzBzs0hrB@quyZv1|hJRaU)x;c~D zYbh%mowFy4j>_?|I$F7)|0Wc7DX+b=q P9{jwFF+}f_6XOoFuw^xPAWY{(;`VMk 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

::on_chain_storage_version(); diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index c823bccf38b1b..dfd7fa094c969 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -45,13 +45,14 @@ #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; -mod migrations; + #[cfg(test)] mod mock; #[cfg(test)] mod tests; mod vesting_info; +pub mod migrations; pub mod weights; use codec::{Decode, Encode, MaxEncodedLen}; @@ -179,29 +180,6 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - if StorageVersion::::get() == Releases::V0 { - migrations::v1::pre_migrate::() - } else { - Ok(()) - } - } - - fn on_runtime_upgrade() -> Weight { - if StorageVersion::::get() == Releases::V0 { - StorageVersion::::put(Releases::V1); - migrations::v1::migrate::().saturating_add(T::DbWeight::get().reads_writes(1, 1)) - } else { - T::DbWeight::get().reads(1) - } - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { - migrations::v1::post_migrate::() - } - fn integrity_test() { assert!(T::MAX_VESTING_SCHEDULES > 0, "`MaxVestingSchedules` must ge greater than 0"); } diff --git a/frame/vesting/src/migrations.rs b/frame/vesting/src/migrations.rs index 688ebf6ad1c93..15668425b4b20 100644 --- a/frame/vesting/src/migrations.rs +++ b/frame/vesting/src/migrations.rs @@ -20,11 +20,11 @@ use super::*; // Migration from single schedule to multiple schedules. -pub(crate) mod v1 { +pub mod v1 { use super::*; #[cfg(feature = "try-runtime")] - pub(crate) fn pre_migrate() -> Result<(), &'static str> { + pub fn pre_migrate() -> Result<(), &'static str> { assert!(StorageVersion::::get() == Releases::V0, "Storage version too high."); log::debug!( @@ -37,7 +37,7 @@ pub(crate) mod v1 { /// Migrate from single schedule to multi schedule storage. /// WARNING: This migration will delete schedules if `MaxVestingSchedules < 1`. - pub(crate) fn migrate() -> Weight { + pub fn migrate() -> Weight { let mut reads_writes = 0; Vesting::::translate::, T::BlockNumber>, _>( @@ -65,7 +65,7 @@ pub(crate) mod v1 { } #[cfg(feature = "try-runtime")] - pub(crate) fn post_migrate() -> Result<(), &'static str> { + pub fn post_migrate() -> Result<(), &'static str> { assert_eq!(StorageVersion::::get(), Releases::V1); for (_key, schedules) in Vesting::::iter() { From 823c2533612e9bab7ac5e4f57a7c5daa762c00a5 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Thu, 20 Jan 2022 12:02:22 +0200 Subject: [PATCH 0443/1472] Relax types on `DigestItemRef`, such that byte slices can be used in addition to vector references (#10536) * Relax types on `DigestItemRef`, such that byte slices can be used in addition to vector references * Apply clippy suggestions --- Cargo.lock | 2 +- bin/node-template/node/Cargo.toml | 2 +- bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 2 +- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- bin/node/inspect/Cargo.toml | 2 +- bin/node/primitives/Cargo.toml | 2 +- bin/node/rpc/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- client/api/Cargo.toml | 2 +- client/authority-discovery/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 2 +- client/beefy/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/block-builder/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/epochs/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 2 +- client/consensus/uncles/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/executor/runtime-test/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/informant/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- frame/assets/Cargo.toml | 2 +- frame/atomic-swap/Cargo.toml | 2 +- frame/aura/Cargo.toml | 2 +- frame/authority-discovery/Cargo.toml | 2 +- frame/authorship/Cargo.toml | 2 +- frame/babe/Cargo.toml | 2 +- frame/bags-list/Cargo.toml | 2 +- frame/bags-list/remote-tests/Cargo.toml | 2 +- frame/balances/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 2 +- frame/bounties/Cargo.toml | 2 +- frame/child-bounties/Cargo.toml | 2 +- frame/collective/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/common/Cargo.toml | 2 +- frame/contracts/rpc/Cargo.toml | 2 +- frame/contracts/rpc/runtime-api/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- frame/election-provider-multi-phase/Cargo.toml | 2 +- frame/election-provider-support/Cargo.toml | 2 +- frame/elections-phragmen/Cargo.toml | 2 +- frame/examples/basic/Cargo.toml | 2 +- frame/examples/offchain-worker/Cargo.toml | 2 +- frame/examples/parallel/Cargo.toml | 2 +- frame/executive/Cargo.toml | 2 +- frame/gilt/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/identity/Cargo.toml | 2 +- frame/im-online/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- frame/lottery/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- frame/merkle-mountain-range/primitives/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 2 +- frame/nicks/Cargo.toml | 2 +- frame/node-authorization/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/offences/benchmarking/Cargo.toml | 2 +- frame/preimage/Cargo.toml | 2 +- frame/proxy/Cargo.toml | 2 +- frame/randomness-collective-flip/Cargo.toml | 2 +- frame/recovery/Cargo.toml | 2 +- frame/scheduler/Cargo.toml | 2 +- frame/scored-pool/Cargo.toml | 2 +- frame/session/Cargo.toml | 2 +- frame/session/benchmarking/Cargo.toml | 2 +- frame/society/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/sudo/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/test/Cargo.toml | 2 +- frame/support/test/compile_pass/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- frame/system/benchmarking/Cargo.toml | 2 +- frame/timestamp/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- .../transaction-payment/asset-tx-payment/Cargo.toml | 2 +- frame/transaction-payment/rpc/Cargo.toml | 2 +- frame/transaction-payment/rpc/runtime-api/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- frame/try-runtime/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 2 +- frame/utility/Cargo.toml | 2 +- frame/vesting/Cargo.toml | 2 +- primitives/api/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/application-crypto/test/Cargo.toml | 2 +- primitives/authority-discovery/Cargo.toml | 2 +- primitives/authorship/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 2 +- primitives/block-builder/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/consensus/aura/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/consensus/common/Cargo.toml | 2 +- primitives/consensus/pow/Cargo.toml | 2 +- primitives/consensus/slots/Cargo.toml | 2 +- primitives/consensus/vrf/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/inherents/Cargo.toml | 2 +- primitives/keyring/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- primitives/offchain/Cargo.toml | 2 +- primitives/runtime-interface/test/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/runtime/src/generic/digest.rs | 12 ++++++------ primitives/session/Cargo.toml | 2 +- primitives/staking/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 2 +- primitives/timestamp/Cargo.toml | 2 +- primitives/transaction-pool/Cargo.toml | 2 +- primitives/transaction-storage-proof/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 2 +- primitives/version/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- test-utils/runtime/client/Cargo.toml | 2 +- test-utils/runtime/transaction-pool/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/frame-utilities-cli/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 159 files changed, 164 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a43c9ded8137..580da5ad074c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9678,7 +9678,7 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "4.0.0" +version = "4.1.0-dev" dependencies = [ "either", "hash256-std-hasher", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index dbf44a75c1399..2b280e1bf00de 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -34,7 +34,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo sc-finality-grandpa = { version = "0.10.0-dev", path = "../../../client/finality-grandpa" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } # These dependencies are used for the node template's RPCs diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index ab69a3fe73ea9..9702501a3e0ea 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -24,7 +24,7 @@ frame-benchmarking = { default-features = false, version = "4.0.0-dev", path = " [dev-dependencies] sp-core = { default-features = false, version = "4.1.0-dev", path = "../../../../primitives/core" } sp-io = { default-features = false, version = "4.0.0-dev", path = "../../../../primitives/io" } -sp-runtime = { default-features = false, version = "4.0.0", path = "../../../../primitives/runtime" } +sp-runtime = { default-features = false, version = "4.1.0-dev", path = "../../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index c56162c8ffed9..b757029f2581d 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -32,7 +32,7 @@ sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = " sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-inherents = { path = "../../../primitives/inherents", default-features = false, version = "4.0.0-dev"} sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 90951d75cfd21..670f6c4d3ed84 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -14,7 +14,7 @@ node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } serde = "1.0.132" serde_json = "1.0.74" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 58b4d98068466..248181ac5c8b8 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -48,7 +48,7 @@ sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consen grandpa-primitives = { version = "4.0.0-dev", package = "sp-finality-grandpa", path = "../../../primitives/finality-grandpa" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 9796ef6c0ad71..e23152e00e5e8 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -36,7 +36,7 @@ pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } pallet-treasury = { version = "4.0.0-dev", path = "../../../frame/treasury" } sp-application-crypto = { version = "4.0.0", path = "../../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } sp-keyring = { version = "4.1.0-dev", path = "../../../primitives/keyring" } wat = "1.0" diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index cb9557b506a14..d72c6f43d005d 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -19,5 +19,5 @@ sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } structopt = "0.3.8" diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 05def58be2341..e00f46720c947 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -18,7 +18,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } sp-application-crypto = { version = "4.0.0", default-features = false, path = "../../../primitives/application-crypto" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 3eed3ad4e0cc0..36d313ebc30ae 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -32,6 +32,6 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-frame-rpc-system = { version = "4.0.0-dev", path = "../../../utils/frame/rpc/system" } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 1cffabe09ae60..ef1b73aed854b 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -33,7 +33,7 @@ sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../. sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../../primitives/keyring" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index d0348b3096bbe..29efc0028c159 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -30,7 +30,7 @@ node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = [ "wasmtime", ] } diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index f1d3969ec27a0..c18b920cace81 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -31,7 +31,7 @@ sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primi sp-keystore = { version = "0.10.0", default-features = false, path = "../../primitives/keystore" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } sp-trie = { version = "4.0.0", path = "../../primitives/trie" } sp-storage = { version = "4.0.0", path = "../../primitives/storage" } diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index ac9f0cdb1828c..c6c523fa5eec7 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -34,7 +34,7 @@ sp-authority-discovery = { version = "4.0.0-dev", path = "../../primitives/autho sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } [dev-dependencies] diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 26a2defbbb4d1..e1083b15a9700 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -19,7 +19,7 @@ futures-timer = "3.0.1" log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index d57d053c16f42..9761f18d78450 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -24,7 +24,7 @@ sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } sc-utils = { version = "4.0.0-dev", path = "../utils" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 0f29804d6780e..a72af62fdeeac 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -26,7 +26,7 @@ sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } beefy-gadget = { version = "4.0.0-dev", path = "../." } beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index ab77bc005f6c2..19b8839c12280 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 769f502dd5ed2..0110e82532a5c 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -19,7 +19,7 @@ sc-network = { version = "0.10.0-dev", path = "../network" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.74" -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "2.0.0" } memmap2 = "0.5.0" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 5b7825182b38f..01f5aab25d5fa 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -29,7 +29,7 @@ sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-network = { version = "0.10.0-dev", path = "../network" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 534aa28920ae1..97409c5944dbb 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -30,7 +30,7 @@ sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 8d0ceb2b615bd..e4d66fcad87cc 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -40,7 +40,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } sp-consensus-vrf = { version = "0.10.0-dev", path = "../../../primitives/consensus/vrf" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } futures = "0.3.9" diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 0806f72e688ec..93be56b9d3601 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -21,7 +21,7 @@ jsonrpc-derive = "18.0.0" sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } serde = { version = "1.0.132", features=["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } -sp-runtime = { version = "4.0.0", path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } futures = "0.3.16" derive_more = "0.99.16" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 0ca0c5675839b..72a0544535ad7 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -23,7 +23,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } parking_lot = "0.11.2" diff --git a/client/consensus/epochs/Cargo.toml b/client/consensus/epochs/Cargo.toml index efd11b8d401d0..bb4a77b559e0a 100644 --- a/client/consensus/epochs/Cargo.toml +++ b/client/consensus/epochs/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } -sp-runtime = { path = "../../../primitives/runtime" , version = "4.0.0"} +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-client-api = { path = "../../api" , version = "4.0.0-dev"} sc-consensus = { path = "../common" , version = "0.10.0-dev"} diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index c55228abb5273..89f3335899f1b 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -37,7 +37,7 @@ sp-blockchain = { path = "../../../primitives/blockchain", version = "4.0.0-dev" sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } sp-consensus-slots = { path = "../../../primitives/consensus/slots", version = "0.10.0-dev" } sp-inherents = { path = "../../../primitives/inherents", version = "4.0.0-dev" } -sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0" } +sp-runtime = { path = "../../../primitives/runtime", version = "4.1.0-dev" } sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } sp-keystore = { path = "../../../primitives/keystore", version = "0.10.0" } sp-api = { path = "../../../primitives/api", version = "4.0.0-dev" } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 19cc5135de039..db9e4e164e4e9 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 782e979ed6ef1..60f57449a3a33 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -21,7 +21,7 @@ sp-arithmetic = { version = "4.0.0", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml index 346d3e34c01b1..b9eaae4773a6a 100644 --- a/client/consensus/uncles/Cargo.toml +++ b/client/consensus/uncles/Cargo.toml @@ -14,6 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } thiserror = "1.0.30" diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 5acc7e9df8b8d..0db0f8309e2eb 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -27,7 +27,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [ sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-trie = { version = "4.0.0", path = "../../primitives/trie" } diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 09f10a9753401..e10cbf347db59 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -42,7 +42,7 @@ hex-literal = "0.3.4" sc-runtime-test = { version = "2.0.0", path = "runtime-test" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } tracing = "0.1.29" diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index 8fbaf2102aeb5..1318c7246a848 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 83ebe617973b6..3f9261c0c17af 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -26,7 +26,7 @@ rand = "0.8.4" parity-scale-codec = { version = "2.3.1", features = ["derive"] } sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "4.0.0", path = "../../primitives/arithmetic" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 2fe7d3683159f..be6dfc371e4ad 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -13,7 +13,7 @@ sc-finality-grandpa = { version = "0.10.0-dev", path = "../" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } finality-grandpa = { version = "0.14.4", features = ["derive-codec"] } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index d6e9c655aad9d..ce7fe31648a19 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -21,5 +21,5 @@ parity-util-mem = { version = "0.10.2", default-features = false, features = ["p sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index c90d1db44afcb..9523e32f99e06 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -22,7 +22,7 @@ log = "0.4.8" lru = "0.7.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } tracing = "0.1.29" [dev-dependencies] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 2df700fae8a32..f378b75990cb9 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -54,7 +54,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } thiserror = "1" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index e2e46a27b2738..6b6d777e7396e 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -25,7 +25,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 4ca1b242a48ec..dd4bdb71f93b6 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -27,7 +27,7 @@ sc-network = { version = "0.10.0-dev", path = "../network" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } threadpool = "1.7" hyper = { version = "0.14.16", features = ["stream", "http2"] } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index aa560bc2e1c13..4b2882ee827f7 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -25,7 +25,7 @@ thiserror = "1.0" sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } -sp-runtime = { path = "../../primitives/runtime", version = "4.0.0" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.74" diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 3a2af0bb211ec..87fc263356a72 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -26,7 +26,7 @@ sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } serde_json = "1.0.74" sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index e9b05c0d28aa6..f23bf3f55bbfe 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -36,7 +36,7 @@ hash-db = "0.15.2" serde = "1.0.132" serde_json = "1.0.74" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sp-trie = { version = "4.0.0", path = "../../primitives/trie" } sp-externalities = { version = "0.10.0", path = "../../primitives/externalities" } sc-utils = { version = "4.0.0-dev", path = "../utils" } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 5073f46eb0ef5..84b1d44e7bde6 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -31,7 +31,7 @@ sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../. sc-network = { version = "0.10.0-dev", path = "../../network" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index e5ac6550d2136..0aae985319d43 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -26,5 +26,5 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } serde_json = "1.0.74" serde = { version = "1.0.132", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 7ea0d80ba1f20..62c7f7a4becca 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -30,7 +30,7 @@ tracing-log = "0.1.2" tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sp-rpc = { version = "4.0.0-dev", path = "../../primitives/rpc" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index a98dfac620c19..73ec7cfff7f3d 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -24,7 +24,7 @@ prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../.. sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", path = "../../primitives/tracing" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index e79aa4c7f804b..95b82e26fc5d7 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -13,7 +13,7 @@ futures = { version = "0.3.1" } log = { version = "0.4.8" } serde = { version = "1.0.132", features = ["derive"] } thiserror = { version = "1.0.30" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } derive_more = { version = "0.99.16" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index c36200fb1ac44..c250a75d4c2f0 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } # Needed for type-safe access to storage DB. frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } # `system` module provides us with all sorts of useful stuff and macros depend on it being around. diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 7a1415946e76e..0f478ab5602f9 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index 34956b1116e91..f5c71a3088585 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -17,7 +17,7 @@ sp-application-crypto = { version = "4.0.0", default-features = false, path = ". codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-consensus-aura = { version = "0.10.0-dev", path = "../../primitives/consensus/aura", default-features = false } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index 4cb40a0f2661f..c1233028df4e2 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -23,7 +23,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives pallet-session = { version = "4.0.0-dev", features = [ "historical", ], path = "../session", default-features = false } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 77be81c082b1f..c17fc49ecdcc1 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } impl-trait-for-tuples = "0.2.1" diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 5242de638c387..673af5c30ed6d 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -25,7 +25,7 @@ sp-application-crypto = { version = "4.0.0", default-features = false, path = ". sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-consensus-vrf = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/vrf" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index e5e746ad1b62e..9e802527f18d4 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } # primitives -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # FRAME diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index b120b32d5d4b1..d8797ad360ba4 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -24,7 +24,7 @@ frame-support = { path = "../../support", version = "4.0.0-dev" } sp-storage = { path = "../../../primitives/storage", version = "4.0.0" } sp-core = { path = "../../../primitives/core", version = "4.1.0-dev" } sp-tracing = { path = "../../../primitives/tracing", version = "4.0.0" } -sp-runtime = { path = "../../../primitives/runtime", version = "4.0.0" } +sp-runtime = { path = "../../../primitives/runtime", version = "4.1.0-dev" } sp-std = { path = "../../../primitives/std", version = "4.0.0" } # utils diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index fdabb4132b1a2..02b94fe606c49 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index b36b3ba873ae9..c793173cc22d8 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -23,7 +23,7 @@ pallet-session = { version = "4.0.0-dev", path = "../session", default-features sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime", default-features = false } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } beefy-merkle-tree = { version = "4.0.0-dev", path = "./primitives", default-features = false } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 753e90faad2ed..52471a332dd76 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -15,7 +15,7 @@ serde = { version = "1.0.132", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime", default-features = false } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index d3dcf589e4465..ce110d8ba511f 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } sp-runtime-interface = { version = "4.1.0-dev", path = "../../primitives/runtime-interface", default-features = false } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime", default-features = false } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } sp-io = { version = "4.0.0", path = "../../primitives/io", default-features = false } sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto", default-features = false } diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 2e328e19b8ecd..73973ab18caaa 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index fcd8e839fb1e5..742110a58bff7 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index cc17a6d7ce604..bd0573bace666 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -19,7 +19,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 64c1de2201553..f0d2833c61fd2 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -40,7 +40,7 @@ pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/common/Cargo.toml index 2b565b4c9e2ca..05bfc212e3058 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/common/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1", features = ["derive"], optional = true } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc", optional = true } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index 51a512277c566..9a88013c34083 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -26,7 +26,7 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } [dev-dependencies] serde_json = "1" diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml index c7251306192e3..bb70d0835d268 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/rpc/runtime-api/Cargo.toml @@ -19,7 +19,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] # Substrate Dependencies pallet-contracts-primitives = { version = "4.0.0-dev", default-features = false, path = "../../common" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../../primitives/std" } [features] diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index ef8e1f3a2f170..730bc6fffbdf4 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index c8ed0c561b467..7add94dc76c80 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -26,7 +26,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 8fabefa7a12cf..1cb477d6c79c7 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -23,7 +23,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys [dev-dependencies] sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../primitives/io" } diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index bcf91ac5c73ca..867b1627272a7 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = "derive", ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 48f505444884a..894b9b4d5010d 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -22,7 +22,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../.. frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } sp-io = { version = "4.0.0", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index 6152b2ca95ee2..68ad2125eef42 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -23,7 +23,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../../ sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore", optional = true } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [features] diff --git a/frame/examples/parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml index 94c18b6c98285..b3ec1a72506b4 100644 --- a/frame/examples/parallel/Cargo.toml +++ b/frame/examples/parallel/Cargo.toml @@ -19,7 +19,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../.. frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 02cb2b22b3886..1b6a237f3b93f 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index 39b9fb5582936..b958b7ba337fe 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 8604c678bf641..4b2ab7eca8712 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -21,7 +21,7 @@ sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 32e62d8aec0b1..00be4d767ec2b 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -18,7 +18,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] enumflags2 = { version = "0.6.2" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index dc839d0d1f9ec..9d659d304dbbe 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -20,7 +20,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index d2c114e605199..a2998c7cfae94 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -18,7 +18,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-keyring = { version = "4.1.0-dev", optional = true, path = "../../primitives/keyring" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 9f31f80173416..cef152a185880 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index fc0d44c766568..7ded2fd586e19 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -19,7 +19,7 @@ log = { version = "0.4.0", default-features = false } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 10476e9a73dd1..495b0add5b1c4 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -18,7 +18,7 @@ mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, ver sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/frame/merkle-mountain-range/primitives/Cargo.toml index 6991ff16939b7..2e483360facc1 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/frame/merkle-mountain-range/primitives/Cargo.toml @@ -18,7 +18,7 @@ serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index cf6aee670b5b4..d6bf66cefefbb 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1.0.132", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index d1c8d8c60c21f..696f8afe0d85c 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 08d529070a5e0..221a386c752a4 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 350914381c1e3..610e536a2c818 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -18,7 +18,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } log = { version = "0.4.14", default-features = false } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 8084a63cc276f..49aa1d770e5b5 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } serde = { version = "1.0.132", optional = true } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index 28e4fde7c3cee..2764eedc1191b 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -29,7 +29,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, path = "../. pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ "runtime-benchmarks", ], path = "../../staking" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 29763d08017f5..17fed986f7575 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -16,7 +16,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-core = { version = "4.1.0-dev", default-features = false, optional = true, path = "../../primitives/core" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index c5d9dc857b8d5..a07ecb4997741 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -18,7 +18,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index 037ce134045ca..a29e7ac7b3265 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] safe-mix = { version = "1.0", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 3ed194225d0ab..53fe6851564dd 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 9cc34f69db793..424c3852862ec 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -16,7 +16,7 @@ log = { version = "0.4.14", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index f570039abc33a..b97a7e3664903 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 57b7fff994792..db6f10c728883 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -22,7 +22,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-trie = { version = "4.0.0", default-features = false, path = "../../primitives/trie", optional = true } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 5f889e66a870e..10a430d52b0a5 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] rand = { version = "0.7.2", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index ad53026f4ce02..fa3f981f19d48 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index c72a1c0ec662a..e0d5dabaa8927 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index bcbdffd6adc31..4c1d2b922f6d6 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -21,4 +21,4 @@ proc-macro2 = "1.0.36" proc-macro-crate = "1.1.0" [dev-dependencies] -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index c553c80d19d21..504eb37b8d009 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index a6bbc73f9ddb6..d652e5ea43445 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -19,7 +19,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-metadata = { version = "14.2.0", default-features = false, features = ["v14"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-tracing = { version = "4.0.0", default-features = false, path = "../../primitives/tracing" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../primitives/arithmetic" } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index f7275cbe2e853..257cca3218dab 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -19,7 +19,7 @@ sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../../ sp-io = { version = "4.0.0", path = "../../../primitives/io", default-features = false } sp-state-machine = { version = "0.10.0", optional = true, path = "../../../primitives/state-machine" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/version" } diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index 21d3be667253d..93443e33503ca 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../../primitives/core" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 7c1526bbd9d40..ae9242087f1a8 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -19,7 +19,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } log = { version = "0.4.14", default-features = false } diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index ff31c6fdbac49..4ca250fa0ec7e 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index e10acdc254572..b66a91acebaa0 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "2.2.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io", optional = true } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 42d58ec38844e..bbe78fd30a56b 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -20,7 +20,7 @@ serde = { version = "1.0.132", features = ["derive"], optional = true } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 9cf6790de46d8..8cb544159dd70 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -22,7 +22,7 @@ smallvec = "1.7.0" sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } sp-io = { version = "4.0.0-dev", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 820c8f00bb8f0..ab2d3302f95b0 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] # Substrate dependencies sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index b8e43848dbf4e..2486654404aef 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -22,5 +22,5 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 6cfe02d15c4f8..1ad56280ac082 100644 --- a/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../../primitives/runtime" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment" } [features] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 68b391387f87d..e4351438811f2 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -20,7 +20,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index a4e211283e13b..0a2dab417e348 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1.0.132", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.1" sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index 860a9e988b117..905c58ab00bed 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } sp-std = { version = "4.0.0", path = "../../primitives/std" , default-features = false } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" , default-features = false } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" , default-features = false } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index a168c96778ad5..38c519f801674 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 62fa402705ef6..85f522975dbbc 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -18,7 +18,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../primitives/core" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index fa0b564c855dc..e488e282cd459 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = ] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index b940ae93baa55..f2c3e67800dc4 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../version" } sp-state-machine = { version = "0.10.0", optional = true, path = "../state-machine" } hash-db = { version = "0.15.2", optional = true } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 38845340027f1..79e302c4c065d 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -16,7 +16,7 @@ sp-api = { version = "4.0.0-dev", path = "../" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } sp-version = { version = "4.0.0-dev", path = "../../version" } sp-tracing = { version = "4.0.0", path = "../../tracing" } -sp-runtime = { version = "4.0.0", path = "../../runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } sp-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/primitives/application-crypto/test/Cargo.toml b/primitives/application-crypto/test/Cargo.toml index 0fdb64c5b2925..178932869611f 100644 --- a/primitives/application-crypto/test/Cargo.toml +++ b/primitives/application-crypto/test/Cargo.toml @@ -16,6 +16,6 @@ targets = ["x86_64-unknown-linux-gnu"] sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } sp-keystore = { version = "0.10.0", path = "../../keystore", default-features = false } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -sp-runtime = { version = "4.0.0", path = "../../runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } sp-api = { version = "4.0.0-dev", path = "../../api" } sp-application-crypto = { version = "4.0.0", path = "../" } diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index 2f1d38c311529..2fd2c48476920 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", default-features = false, version = "2 scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } [features] default = ["std"] diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index 81fa39e93a1ad..8e97942499aad 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 6a74c58d2ceb6..edcb2244e58fb 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -14,7 +14,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-api = { version = "4.0.0-dev", path = "../api", default-features = false } sp-application-crypto = { version = "4.0.0", path = "../application-crypto", default-features = false } sp-core = { version = "4.1.0-dev", path = "../core", default-features = false } -sp-runtime = { version = "4.0.0", path = "../runtime", default-features = false } +sp-runtime = { version = "4.1.0-dev", path = "../runtime", default-features = false } sp-std = { version = "4.0.0", path = "../std", default-features = false } [dev-dependencies] diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index 083865cd2cccb..5009207a3f5c3 100644 --- a/primitives/block-builder/Cargo.toml +++ b/primitives/block-builder/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 57732c360bac7..366d0f3c373e2 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -21,7 +21,7 @@ thiserror = "1.0.30" futures = "0.3.9" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-runtime = { version = "4.0.0", path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../runtime" } sp-state-machine = { version = "0.10.0", path = "../state-machine" } sp-database = { version = "4.0.0-dev", path = "../database" } sp-api = { version = "4.0.0-dev", path = "../api" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index 747a9f546cb03..f15f0008164d6 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../runtime" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../timestamp" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 330ce775eb065..1471ca05f591e 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -25,7 +25,7 @@ sp-consensus-vrf = { version = "0.10.0-dev", path = "../vrf", default-features = sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } sp-keystore = { version = "0.10.0", default-features = false, path = "../../keystore", optional = true } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../timestamp", optional = true } serde = { version = "1.0.132", features = ["derive"], optional = true } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index e638c04a08dce..93338d62cfc02 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -26,7 +26,7 @@ sp-state-machine = { version = "0.10.0", path = "../../state-machine" } futures-timer = "3.0.1" sp-std = { version = "4.0.0", path = "../../std" } sp-version = { version = "4.0.0-dev", path = "../../version" } -sp-runtime = { version = "4.0.0", path = "../../runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } thiserror = "1.0.30" [dev-dependencies] diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index 6e00453da1bd4..810e9c23a6599 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../runtime" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index 23f73454aad94..ea2a862189826 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0", features = ["derive"], optional = true } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../runtime" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../../arithmetic" } [features] diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 586b6354f55ac..7504a159a3db7 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -17,7 +17,7 @@ codec = { version = "2.0.0", package = "parity-scale-codec", default-features = schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } sp-std = { version = "4.0.0", path = "../../std", default-features = false } sp-core = { version = "4.1.0-dev", path = "../../core", default-features = false } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../runtime" } [features] default = ["std"] diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index e12d7a52695df..e36c088c35838 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -24,7 +24,7 @@ sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "4.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-keystore = { version = "0.10.0", default-features = false, path = "../keystore", optional = true } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 1ef0f2012056f..02f084b6e6342 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-runtime = { version = "4.0.0", path = "../runtime", optional = true } +sp-runtime = { version = "4.1.0-dev", path = "../runtime", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } impl-trait-for-tuples = "0.2.0" diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index d9250d0011f13..a457f4983c163 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -16,6 +16,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "4.1.0-dev", path = "../core" } -sp-runtime = { version = "4.0.0", path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../runtime" } lazy_static = "1.4.0" strum = { version = "0.22.0", features = ["derive"] } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index d255688b56c78..062f786aaef1c 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -20,7 +20,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" } sp-arithmetic = { version = "4.0.0", default-features = false, path = "../arithmetic" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } -sp-runtime = { version = "4.0.0", path = "../runtime", default-features = false } +sp-runtime = { version = "4.1.0-dev", path = "../runtime", default-features = false } [dev-dependencies] substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 62bb1090d047f..17423b624760e 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -19,7 +19,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] honggfuzz = "0.5" rand = { version = "0.7.3", features = ["std", "small_rng"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } -sp-runtime = { version = "4.0.0", path = "../../runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } structopt = "0.3.25" [[bin]] diff --git a/primitives/offchain/Cargo.toml b/primitives/offchain/Cargo.toml index 50a6d8344f0d8..7e0ce31d5d0c4 100644 --- a/primitives/offchain/Cargo.toml +++ b/primitives/offchain/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } [features] default = ["std"] diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 06fcf920a6911..82c6a21b995cc 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -18,7 +18,7 @@ sc-executor-common = { version = "0.10.0-dev", path = "../../../client/executor/ sp-runtime-interface-test-wasm = { version = "2.0.0", path = "../test-wasm" } sp-runtime-interface-test-wasm-deprecated = { version = "2.0.0", path = "../test-wasm-deprecated" } sp-state-machine = { version = "0.10.0", path = "../../state-machine" } -sp-runtime = { version = "4.0.0", path = "../../runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } sp-io = { version = "4.0.0", path = "../../io" } tracing = "0.1.29" tracing-core = "0.1.17" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index abf246eece9a0..e6bb5a1c842e5 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime" -version = "4.0.0" +version = "4.1.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/runtime/src/generic/digest.rs b/primitives/runtime/src/generic/digest.rs index f3cb7b99efb61..55e0d69fad33d 100644 --- a/primitives/runtime/src/generic/digest.rs +++ b/primitives/runtime/src/generic/digest.rs @@ -177,16 +177,16 @@ pub enum DigestItemRef<'a> { /// the consensus engine can (and should) read them itself to avoid /// code and state duplication. It is erroneous for a runtime to produce /// these, but this is not (yet) checked. - PreRuntime(&'a ConsensusEngineId, &'a Vec), + PreRuntime(&'a ConsensusEngineId, &'a [u8]), /// A message from the runtime to the consensus engine. This should *never* /// be generated by the native code of any consensus engine, but this is not /// checked (yet). - Consensus(&'a ConsensusEngineId, &'a Vec), + Consensus(&'a ConsensusEngineId, &'a [u8]), /// Put a Seal on it. This is only used by native code, and is never seen /// by runtimes. - Seal(&'a ConsensusEngineId, &'a Vec), + Seal(&'a ConsensusEngineId, &'a [u8]), /// Any 'non-system' digest item, opaque to the native code. - Other(&'a Vec), + Other(&'a [u8]), /// Runtime code or heap pages updated. RuntimeEnvironmentUpdated, } @@ -358,8 +358,8 @@ impl<'a> DigestItemRef<'a> { (OpaqueDigestItemId::Seal(w), &Self::Seal(v, s)) | (OpaqueDigestItemId::PreRuntime(w), &Self::PreRuntime(v, s)) if v == w => - Some(&s[..]), - (OpaqueDigestItemId::Other, &Self::Other(s)) => Some(&s[..]), + Some(s), + (OpaqueDigestItemId::Other, &Self::Other(s)) => Some(s), _ => None, } } diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index cca35710172b5..293f3642b7f33 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -19,7 +19,7 @@ sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" } -sp-runtime = { version = "4.0.0", optional = true, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", optional = true, path = "../runtime" } [features] default = [ "std" ] diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 533e177391b08..6ae972f1814be 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index b9e5c1d4f3f0f..c885f99fdb839 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -33,7 +33,7 @@ tracing = { version = "0.1.29", optional = true } [dev-dependencies] hex-literal = "0.3.4" -sp-runtime = { version = "4.0.0", path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../runtime" } pretty_assertions = "1.0.0" rand = "0.7.2" diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 5a045185e7cec..ab2ef0d54ca4b 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -16,7 +16,7 @@ sp-application-crypto = { version = "4.0.0", default-features = false, path = ". codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" } serde = { version = "1.0.132", optional = true, features = ["derive"] } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } [features] diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 4c5fdefe990a1..e42ca738cd55e 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/transaction-pool/Cargo.toml b/primitives/transaction-pool/Cargo.toml index 2590208078db6..fab5f90ffffc0 100644 --- a/primitives/transaction-pool/Cargo.toml +++ b/primitives/transaction-pool/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } [features] default = [ "std" ] diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index d731808c64c2b..87f7f81cd5868 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-trie = { version = "4.0.0", optional = true, path = "../trie" } sp-core = { version = "4.1.0-dev", path = "../core", optional = true } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 8e54035b3ae7d..4564fa86ced95 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -32,7 +32,7 @@ trie-bench = "0.29.0" trie-standardmap = "0.15.2" criterion = "0.3.3" hex-literal = "0.3.4" -sp-runtime = { version = "4.0.0", path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../runtime" } [features] default = ["std"] diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 7fb55295088ea..1bb39eca13640 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -19,7 +19,7 @@ serde = { version = "1.0.132", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../runtime" } sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" } parity-wasm = { version = "0.42.2", optional = true } sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../core/hashing/proc-macro" } diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 91504df481dfb..902a14b1b3bdf 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -32,6 +32,6 @@ sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/comm sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } -sp-runtime = { version = "4.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../primitives/state-machine" } async-trait = "0.1.50" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index ee38cfd250dcd..e88f571366020 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -31,7 +31,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../.. sp-version = { version = "4.0.0-dev", default-features = false, path = "../../primitives/version" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-runtime = { version = "4.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../primitives/runtime" } pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../frame/babe" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../frame/system" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../frame/system/rpc/runtime-api" } diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index 7babbfb2ed8ee..ba0f01cfced99 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -18,7 +18,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-build substrate-test-client = { version = "2.0.0", path = "../../client" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } substrate-test-runtime = { version = "2.0.0", path = "../../runtime" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } codec = { package = "parity-scale-codec", version = "2.0.0" } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index 8eaaac62c5561..39221a2d15794 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -16,7 +16,7 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../client" } parking_lot = "0.11.2" codec = { package = "parity-scale-codec", version = "2.0.0" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } futures = "0.3.16" diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 61988e24e3b0d..fa91956ec7949 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -22,7 +22,7 @@ sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sp-externalities = { version = "0.10.0", path = "../../../primitives/externalities" } sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } codec = { version = "2.0.0", package = "parity-scale-codec" } structopt = "0.3.25" diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index db9e4a7d90744..d256bba4b5b32 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" [dependencies] sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } structopt = "0.3.25" frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index f4e26b4db39b1..6d926846b4a36 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -24,7 +24,7 @@ serde = "1.0.132" sp-io = { version = "4.0.0-dev", path = "../../../primitives/io" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } -sp-runtime = { version = "4.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", path = "../../../primitives/version" } [dev-dependencies] diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 53ad36a969306..cb801c6cbf275 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -20,7 +20,7 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" log = "0.4.8" -sp-runtime = { version = "4.0.0", path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 0c96d727cee09..2e214ec2307b7 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -23,7 +23,7 @@ sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sp-state-machine = { version = "0.10.0", path = "../../../../primitives/state-machine" } -sp-runtime = { version = "4.0.0", path = "../../../../primitives/runtime" } +sp-runtime = { version = "4.1.0-dev", path = "../../../../primitives/runtime" } sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } sp-io = { version = "4.0.0-dev", path = "../../../../primitives/io" } sp-keystore = { version = "0.10.0", path = "../../../../primitives/keystore" } From f318350b6410ef47e438aae24c0b4779373d0a7b Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 20 Jan 2022 12:16:04 +0100 Subject: [PATCH 0444/1472] Require `MaxEncodedLen` per default (#10662) * Remove generate_storage_info Signed-off-by: Oliver Tale-Yazdi * Add without_storage_info where needed Signed-off-by: Oliver Tale-Yazdi * Update doc tests Signed-off-by: Oliver Tale-Yazdi * Add more without_storage_info Signed-off-by: Oliver Tale-Yazdi * fix TryBuild Signed-off-by: Oliver Tale-Yazdi * fix TryBuild tests Signed-off-by: Oliver Tale-Yazdi --- frame/assets/src/lib.rs | 1 - frame/atomic-swap/src/lib.rs | 1 + frame/aura/src/lib.rs | 1 - frame/authority-discovery/src/lib.rs | 1 - frame/authorship/src/lib.rs | 1 + frame/babe/src/lib.rs | 1 - frame/bags-list/src/lib.rs | 1 - frame/balances/src/lib.rs | 1 - frame/beefy-mmr/src/lib.rs | 1 + frame/beefy/src/lib.rs | 1 + frame/bounties/src/lib.rs | 1 + frame/child-bounties/src/lib.rs | 1 - frame/collective/src/lib.rs | 1 + frame/contracts/src/lib.rs | 1 + frame/democracy/src/lib.rs | 1 + .../election-provider-multi-phase/src/lib.rs | 1 + frame/elections-phragmen/src/lib.rs | 1 + frame/examples/offchain-worker/src/lib.rs | 1 + frame/examples/parallel/src/lib.rs | 1 + frame/gilt/src/lib.rs | 1 + frame/grandpa/src/lib.rs | 1 - frame/identity/src/lib.rs | 1 - frame/im-online/src/lib.rs | 1 - frame/indices/src/lib.rs | 1 + frame/lottery/src/lib.rs | 1 - frame/membership/src/lib.rs | 1 + frame/merkle-mountain-range/src/lib.rs | 1 + frame/multisig/src/lib.rs | 1 + frame/nicks/src/lib.rs | 1 + frame/node-authorization/src/lib.rs | 1 + frame/offences/src/lib.rs | 1 + frame/preimage/src/lib.rs | 1 - frame/proxy/src/lib.rs | 1 - frame/randomness-collective-flip/src/lib.rs | 1 + frame/recovery/src/lib.rs | 1 + frame/scheduler/src/lib.rs | 1 + frame/scored-pool/src/lib.rs | 1 + frame/session/src/lib.rs | 1 + frame/society/src/lib.rs | 1 + frame/staking/src/pallet/mod.rs | 1 + frame/sudo/src/lib.rs | 1 - frame/sudo/src/mock.rs | 1 + .../src/pallet/expand/pallet_struct.rs | 8 +-- .../src/pallet/parse/pallet_struct.rs | 26 ++++---- frame/support/src/lib.rs | 4 +- frame/support/test/tests/pallet.rs | 2 +- .../test/tests/pallet_compatibility.rs | 1 + .../tests/pallet_compatibility_instance.rs | 1 + ...storage_ensure_span_are_ok_on_wrong_gen.rs | 1 + ...age_ensure_span_are_ok_on_wrong_gen.stderr | 62 +++++++++---------- ...ensure_span_are_ok_on_wrong_gen_unnamed.rs | 1 + ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 62 +++++++++---------- .../pallet_ui/storage_info_unsatisfied.rs | 1 - .../pallet_ui/storage_info_unsatisfied.stderr | 10 +-- .../storage_info_unsatisfied_nmap.rs | 1 - .../storage_info_unsatisfied_nmap.stderr | 6 +- frame/system/src/lib.rs | 1 + frame/timestamp/src/lib.rs | 1 - frame/tips/src/lib.rs | 1 + frame/transaction-payment/src/lib.rs | 1 + frame/transaction-storage/src/lib.rs | 1 + frame/treasury/src/lib.rs | 1 - frame/uniques/src/lib.rs | 1 + frame/vesting/src/lib.rs | 1 - 64 files changed, 127 insertions(+), 109 deletions(-) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index be8df104dbf05..71ba7b4d24910 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -172,7 +172,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 8259f53f39507..e83055b4d283e 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -182,6 +182,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::storage] diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 4b1d5aeb4a705..657965c60a3f1 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -81,7 +81,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_storage_info] pub struct Pallet(sp_std::marker::PhantomData); #[pallet::hooks] diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index 03f6e753fd475..a56d8e785f6ac 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -39,7 +39,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 3fa081f5263e3..6b72d6ac5d28b 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -156,6 +156,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index e2cc36ca098fe..f673c8b43bee0 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -115,7 +115,6 @@ pub mod pallet { /// The BABE Pallet #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 98261b6bbafc7..89c54db87023f 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -92,7 +92,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 5235dc97ccb4f..f94afec069422 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -242,7 +242,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(PhantomData<(T, I)>); #[pallet::call] diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 38d0a6ac9a7f8..d66de51d9af21 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -119,6 +119,7 @@ pub mod pallet { /// BEEFY-MMR pallet. #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); /// The module's configuration trait. diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index eb822915ee466..4aa1d1337cd0a 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -51,6 +51,7 @@ pub mod pallet { } #[pallet::pallet] + #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::hooks] diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index d71b58f058823..d46180f6bbe19 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -180,6 +180,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 6bdc1865b8412..36acc7766bf61 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -130,7 +130,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 3f423f35b7e54..3e3b923d6ee37 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -172,6 +172,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] pub struct Pallet(PhantomData<(T, I)>); #[pallet::config] diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 36b0e12dcd7f0..e57b88c5d0389 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -303,6 +303,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::hooks] diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 1e5f3c403006a..1c052ad2d4176 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -246,6 +246,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 8087d22cffe69..4716bcd6c859b 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1205,6 +1205,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(PhantomData); } diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 1e8f61f6b268f..7f576144d1368 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -250,6 +250,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::hooks] diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index 764f6cb9e2d77..08f449f8d51d0 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -158,6 +158,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] diff --git a/frame/examples/parallel/src/lib.rs b/frame/examples/parallel/src/lib.rs index 4ea52173a09aa..7b8948c2ebd09 100644 --- a/frame/examples/parallel/src/lib.rs +++ b/frame/examples/parallel/src/lib.rs @@ -48,6 +48,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); /// A public part of the pallet. diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index 4fd18626d9313..6211b15d8c8c3 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -178,6 +178,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); /// A single bid on a gilt, an item of a *queue* in `Queues`. diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 1f6139cf81fdc..0aaf0f679ce11 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -83,7 +83,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index a2516a1e874e5..51e63541a89b1 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -152,7 +152,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(_); /// Information that is pertinent to identify the entity behind an account. diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index c9377cd274ade..5ad27850a2c1f 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -315,7 +315,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index 0aa931559e0a9..7d23fa5e8c7f1 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -74,6 +74,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::call] diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index b04dbc8455684..c9a508372ca85 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -124,7 +124,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(_); /// The pallet's config trait. diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 016c4b39851af..e8256fab83af2 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -46,6 +46,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] pub struct Pallet(PhantomData<(T, I)>); #[pallet::config] diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 0f5fe751bbd96..2a93dc7af2892 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -84,6 +84,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(PhantomData<(T, I)>); /// This pallet's configuration trait diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 16ee1c500096a..cd59ea881739d 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -153,6 +153,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); /// The set of open multisig operations. diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 24d80f5a95217..9e4ecf8b2b1a3 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -114,6 +114,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::call] diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 87ec3973d0a86..07f2e9de37dde 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -57,6 +57,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); /// The module configuration trait diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index c12f0d1bcc781..6119fce7769e9 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -50,6 +50,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); /// The pallet's config trait. diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 7564629bad299..c34057a1034d3 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -100,7 +100,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(PhantomData); #[pallet::event] diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 68aa580bfe7f6..425af18367854 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -102,7 +102,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(_); /// Configuration trait. diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index fbc8aaaa7ec59..a74c58405de4f 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -91,6 +91,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index b0505cbb7daf9..f5a57843a983b 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -212,6 +212,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); /// Configuration trait. diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 4fd5d50a4de0f..7ecd9024e9f96 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -203,6 +203,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); /// `system::Config` should always be included in our implied traits. diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index e95786e0c08f8..3f0674d720efd 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -129,6 +129,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 7a0783718705a..4cf793a9b4739 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -373,6 +373,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 3d2814ad5232b..a9f83094fd49c 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -371,6 +371,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 8444034ad49d0..20864e4829e66 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -56,6 +56,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index d57c75f23f5a0..d9e72b37f2970 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -121,7 +121,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(PhantomData); #[pallet::call] diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index e6af6978f8c83..410807789069b 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -45,6 +45,7 @@ pub mod logger { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::call] diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 5ec10d733e5e2..61c6d001a6f94 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -99,19 +99,19 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { }; let storage_info_span = - def.pallet_struct.generate_storage_info.unwrap_or(def.pallet_struct.attr_span); + def.pallet_struct.without_storage_info.unwrap_or(def.pallet_struct.attr_span); let storage_names = &def.storages.iter().map(|storage| &storage.ident).collect::>(); let storage_cfg_attrs = &def.storages.iter().map(|storage| &storage.cfg_attrs).collect::>(); - // Depending on the flag `generate_storage_info` and the storage attribute `unbounded`, we use + // Depending on the flag `without_storage_info` and the storage attribute `unbounded`, we use // partial or full storage info from storage. let storage_info_traits = &def .storages .iter() .map(|storage| { - if storage.unbounded || def.pallet_struct.generate_storage_info.is_none() { + if storage.unbounded || def.pallet_struct.without_storage_info.is_some() { quote::quote_spanned!(storage_info_span => PartialStorageInfoTrait) } else { quote::quote_spanned!(storage_info_span => StorageInfoTrait) @@ -123,7 +123,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { .storages .iter() .map(|storage| { - if storage.unbounded || def.pallet_struct.generate_storage_info.is_none() { + if storage.unbounded || def.pallet_struct.without_storage_info.is_some() { quote::quote_spanned!(storage_info_span => partial_storage_info) } else { quote::quote_spanned!(storage_info_span => storage_info) diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index 19d2811687d2e..d98862be8f783 100644 --- a/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -24,7 +24,7 @@ mod keyword { syn::custom_keyword!(pallet); syn::custom_keyword!(Pallet); syn::custom_keyword!(generate_store); - syn::custom_keyword!(generate_storage_info); + syn::custom_keyword!(without_storage_info); syn::custom_keyword!(storage_version); syn::custom_keyword!(Store); } @@ -43,18 +43,18 @@ pub struct PalletStructDef { pub attr_span: proc_macro2::Span, /// Whether to specify the storages max encoded len when implementing `StorageInfoTrait`. /// Contains the span of the attribute. - pub generate_storage_info: Option, + pub without_storage_info: Option, /// The current storage version of the pallet. pub storage_version: Option, } /// Parse for one variant of: /// * `#[pallet::generate_store($vis trait Store)]` -/// * `#[pallet::generate_storage_info]` +/// * `#[pallet::without_storage_info]` /// * `#[pallet::storage_version(STORAGE_VERSION)]` pub enum PalletStructAttr { GenerateStore { span: proc_macro2::Span, vis: syn::Visibility, keyword: keyword::Store }, - GenerateStorageInfoTrait(proc_macro2::Span), + WithoutStorageInfoTrait(proc_macro2::Span), StorageVersion { storage_version: syn::Path, span: proc_macro2::Span }, } @@ -62,7 +62,7 @@ impl PalletStructAttr { fn span(&self) -> proc_macro2::Span { match self { Self::GenerateStore { span, .. } => *span, - Self::GenerateStorageInfoTrait(span) => *span, + Self::WithoutStorageInfoTrait(span) => *span, Self::StorageVersion { span, .. } => *span, } } @@ -86,9 +86,9 @@ impl syn::parse::Parse for PalletStructAttr { generate_content.parse::()?; let keyword = generate_content.parse::()?; Ok(Self::GenerateStore { vis, keyword, span }) - } else if lookahead.peek(keyword::generate_storage_info) { - let span = content.parse::()?.span(); - Ok(Self::GenerateStorageInfoTrait(span)) + } else if lookahead.peek(keyword::without_storage_info) { + let span = content.parse::()?.span(); + Ok(Self::WithoutStorageInfoTrait(span)) } else if lookahead.peek(keyword::storage_version) { let span = content.parse::()?.span(); @@ -117,7 +117,7 @@ impl PalletStructDef { }; let mut store = None; - let mut generate_storage_info = None; + let mut without_storage_info = None; let mut storage_version_found = None; let struct_attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; @@ -126,10 +126,10 @@ impl PalletStructDef { PalletStructAttr::GenerateStore { vis, keyword, .. } if store.is_none() => { store = Some((vis, keyword)); }, - PalletStructAttr::GenerateStorageInfoTrait(span) - if generate_storage_info.is_none() => + PalletStructAttr::WithoutStorageInfoTrait(span) + if without_storage_info.is_none() => { - generate_storage_info = Some(span); + without_storage_info = Some(span); }, PalletStructAttr::StorageVersion { storage_version, .. } if storage_version_found.is_none() => @@ -164,7 +164,7 @@ impl PalletStructDef { pallet, store, attr_span, - generate_storage_info, + without_storage_info, storage_version: storage_version_found, }) } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 64bca7262829e..fc2754c5c555f 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1967,7 +1967,7 @@ pub mod pallet_prelude { /// pub trait Config: frame_system::Config { /// #[pallet::constant] // put the constant in metadata /// type MyGetParam: Get; -/// type Balance: Parameter + From; +/// type Balance: Parameter + MaxEncodedLen + From; /// type Event: From> + IsType<::Event>; /// } /// @@ -2156,7 +2156,7 @@ pub mod pallet_prelude { /// pub trait Config: frame_system::Config { /// #[pallet::constant] /// type MyGetParam: Get; -/// type Balance: Parameter + From; +/// type Balance: Parameter + MaxEncodedLen + From; /// type Event: From> + IsType<::Event>; /// } /// diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 5f9e886dbb672..2cb7b283b66fb 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -156,7 +156,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] - #[pallet::generate_storage_info] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); @@ -450,6 +449,7 @@ pub mod pallet2 { #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index 339a8b6b09248..9327f5b6a3304 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -124,6 +124,7 @@ pub mod pallet { } #[pallet::pallet] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 4fe577f520fa3..3de45df223674 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -109,6 +109,7 @@ pub mod pallet { } #[pallet::pallet] + #[pallet::without_storage_info] pub struct Pallet(PhantomData<(T, I)>); #[pallet::hooks] diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs index 30b6d651f3b89..fe4682c401fa0 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs @@ -7,6 +7,7 @@ mod pallet { pub trait Config: frame_system::Config {} #[pallet::pallet] + #[pallet::without_storage_info] pub struct Pallet(core::marker::PhantomData); #[pallet::hooks] diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index 82fd3ad884f90..35f8bbdbd5248 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -1,97 +1,97 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:10:12 | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` +10 | #[pallet::without_storage_info] + | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 + --> $WORKSPACE/frame/support/src/traits/storage.rs | -88 | fn partial_storage_info() -> Vec; + | fn partial_storage_info() -> Vec; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:10:12 | -9 | #[pallet::pallet] - | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` +10 | #[pallet::without_storage_info] + | ^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 + --> $WORKSPACE/frame/support/src/traits/storage.rs | -88 | fn partial_storage_info() -> Vec; + | fn partial_storage_info() -> Vec; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:9:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:10:12 | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` +10 | #[pallet::without_storage_info] + | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 + --> $WORKSPACE/frame/support/src/traits/storage.rs | -88 | fn partial_storage_info() -> Vec; + | fn partial_storage_info() -> Vec; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 | -20 | #[pallet::storage] +21 | #[pallet::storage] | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` | = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `build_metadata` - --> $DIR/mod.rs:113:2 + --> $WORKSPACE/frame/support/src/storage/types/mod.rs | -113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 | -20 | #[pallet::storage] +21 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `build_metadata` - --> $DIR/mod.rs:113:2 + --> $WORKSPACE/frame/support/src/storage/types/mod.rs | -113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 | -20 | #[pallet::storage] +21 | #[pallet::storage] | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `build_metadata` - --> $DIR/mod.rs:113:2 + --> $WORKSPACE/frame/support/src/storage/types/mod.rs | -113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen.rs:20:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 | -20 | #[pallet::storage] +21 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Encode` for `Bar` @@ -99,7 +99,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `build_metadata` - --> $DIR/mod.rs:113:2 + --> $WORKSPACE/frame/support/src/storage/types/mod.rs | -113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs index ddb19121660da..82512a89fb15a 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs @@ -7,6 +7,7 @@ mod pallet { pub trait Config: frame_system::Config {} #[pallet::pallet] + #[pallet::without_storage_info] pub struct Pallet(core::marker::PhantomData); #[pallet::hooks] diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index eb1404fc62c38..b5f250bb89718 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -1,97 +1,97 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:10:12 | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` +10 | #[pallet::without_storage_info] + | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 + --> $WORKSPACE/frame/support/src/traits/storage.rs | -88 | fn partial_storage_info() -> Vec; + | fn partial_storage_info() -> Vec; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:10:12 | -9 | #[pallet::pallet] - | ^^^^^^ the trait `EncodeLike` is not implemented for `Bar` +10 | #[pallet::without_storage_info] + | ^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 + --> $WORKSPACE/frame/support/src/traits/storage.rs | -88 | fn partial_storage_info() -> Vec; + | fn partial_storage_info() -> Vec; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:9:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:10:12 | -9 | #[pallet::pallet] - | ^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` +10 | #[pallet::without_storage_info] + | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `partial_storage_info` - --> $DIR/storage.rs:88:2 + --> $WORKSPACE/frame/support/src/traits/storage.rs | -88 | fn partial_storage_info() -> Vec; + | fn partial_storage_info() -> Vec; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 | -20 | #[pallet::storage] +21 | #[pallet::storage] | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` | = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `build_metadata` - --> $DIR/mod.rs:113:2 + --> $WORKSPACE/frame/support/src/storage/types/mod.rs | -113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 | -20 | #[pallet::storage] +21 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `build_metadata` - --> $DIR/mod.rs:113:2 + --> $WORKSPACE/frame/support/src/storage/types/mod.rs | -113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 | -20 | #[pallet::storage] +21 | #[pallet::storage] | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `build_metadata` - --> $DIR/mod.rs:113:2 + --> $WORKSPACE/frame/support/src/storage/types/mod.rs | -113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> $DIR/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:20:12 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 | -20 | #[pallet::storage] +21 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Encode` for `Bar` @@ -99,7 +99,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `build_metadata` - --> $DIR/mod.rs:113:2 + --> $WORKSPACE/frame/support/src/storage/types/mod.rs | -113 | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs index 76e3566100640..4d43e3a17a9ec 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.rs @@ -7,7 +7,6 @@ mod pallet { pub trait Config: frame_system::Config {} #[pallet::pallet] - #[pallet::generate_storage_info] pub struct Pallet(core::marker::PhantomData); #[pallet::hooks] diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index 0ffb015e36bca..35537cfbc9e07 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -1,12 +1,12 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied - --> $DIR/storage_info_unsatisfied.rs:10:12 + --> tests/pallet_ui/storage_info_unsatisfied.rs:9:12 | -10 | #[pallet::generate_storage_info] - | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` +9 | #[pallet::pallet] + | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` note: required by `storage_info` - --> $DIR/storage.rs:71:2 + --> $WORKSPACE/frame/support/src/traits/storage.rs | -71 | fn storage_info() -> Vec; + | fn storage_info() -> Vec; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs index 15456c78e9ba9..dd10bc0723fe1 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.rs @@ -10,7 +10,6 @@ mod pallet { pub trait Config: frame_system::Config {} #[pallet::pallet] - #[pallet::generate_storage_info] pub struct Pallet(core::marker::PhantomData); #[pallet::hooks] diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index cb9a0bd559890..fb6580bb5a3e7 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied - --> tests/pallet_ui/storage_info_unsatisfied_nmap.rs:13:12 + --> tests/pallet_ui/storage_info_unsatisfied_nmap.rs:12:12 | -13 | #[pallet::generate_storage_info] - | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` +12 | #[pallet::pallet] + | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 7615424ba57ee..800ffbfd20dc2 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -351,6 +351,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index a0b9babcd9842..d8bfb405e5c7c 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -148,7 +148,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(PhantomData); /// Current time for the current block. diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index 7761800638d37..ae320629dfc34 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -120,6 +120,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 8bda316c501ad..16d2ff5827c4f 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -248,6 +248,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index 23cc9ee0a2389..d95a60b495121 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -129,6 +129,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index c2dd59953be33..762c0e592d891 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -139,7 +139,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(PhantomData<(T, I)>); #[pallet::config] diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index dde30920b227a..6b05aaeec296b 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -62,6 +62,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index dfd7fa094c969..747521f4fa536 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -203,7 +203,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::genesis_config] From 48e0b415b94d8ce14e0ebbbdb813263afa27f02e Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 20 Jan 2022 14:17:16 -0400 Subject: [PATCH 0445/1472] dont increase the allocated size of vec (#10701) --- frame/support/src/storage/bounded_vec.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 6d7206df6db10..6b20ed2bba90f 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -222,16 +222,17 @@ impl> BoundedVec { /// Returns `true` if the item was inserted. pub fn force_insert_keep_left(&mut self, index: usize, element: T) -> bool { // Check against panics. - if Self::bound() < index || self.len() < index { + if Self::bound() < index || self.len() < index || Self::bound() == 0 { return false } // Noop condition. if Self::bound() == index && self.len() <= Self::bound() { return false } - // Cannot panic since self.len() >= index; + // Cannot panic since `Self.bound() > 0` + self.0.truncate(Self::bound() - 1); + // Cannot panic since `self.len() >= index`; self.0.insert(index, element); - self.0.truncate(Self::bound()); true } From 6bbc6885509430aac4b0cba4ac6c1a11fe525307 Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Fri, 21 Jan 2022 17:28:43 +0100 Subject: [PATCH 0446/1472] Fix typo (#10714) --- primitives/state-machine/src/overlayed_changes/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index 89bbb063ef9a7..d75feec0ced9c 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -104,7 +104,7 @@ pub struct OverlayedChanges { stats: StateMachineStats, } -/// Transcation index operation. +/// Transaction index operation. #[derive(Debug, Clone)] pub enum IndexOperation { /// Insert transaction into index. From 9247e150ca0f50841a60a213ad8b15efdbd616fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 21 Jan 2022 17:43:21 +0100 Subject: [PATCH 0447/1472] wasm-builder: Improve workspace handling (#10700) When building a wasm binary from a different repo inside a local workspace, we did not used the correct `Cargo.toml` to find the correct patches and features. The solution to this is to just walk up from the target directory until we find the workspace we are currently compiling. If this heuristic isn't working, we print a warning and let the user set an env variable `WASM_BUILD_WORKSPACE_HINT` to tell the `wasm-builder` where the actual workspace is. --- utils/wasm-builder/src/lib.rs | 7 ++++++ utils/wasm-builder/src/wasm_project.rs | 30 +++++++++++++++++++++----- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/utils/wasm-builder/src/lib.rs b/utils/wasm-builder/src/lib.rs index 899903d96d169..f5e04dd7d774b 100644 --- a/utils/wasm-builder/src/lib.rs +++ b/utils/wasm-builder/src/lib.rs @@ -83,6 +83,10 @@ //! needs to be absolute. //! - `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the Wasm binaries. The //! format needs to be the same as used by cargo, e.g. `nightly-2020-02-20`. +//! - `WASM_BUILD_WORKSPACE_HINT` - Hint the workspace that is being built. This is normally not +//! required as we walk up from the target directory until we find a `Cargo.toml`. If the target +//! directory is changed for the build, this environment variable can be used to point to the +//! actual workspace. //! //! Each project can be skipped individually by using the environment variable //! `SKIP_PROJECT_NAME_WASM_BUILD`. Where `PROJECT_NAME` needs to be replaced by the name of the @@ -138,6 +142,9 @@ const WASM_BUILD_TOOLCHAIN: &str = "WASM_BUILD_TOOLCHAIN"; /// Environment variable that makes sure the WASM build is triggered. const FORCE_WASM_BUILD_ENV: &str = "FORCE_WASM_BUILD"; +/// Environment variable that hints the workspace we are building. +const WASM_BUILD_WORKSPACE_HINT: &str = "WASM_BUILD_WORKSPACE_HINT"; + /// Write to the given `file` if the `content` is different. fn write_file_if_changed(file: impl AsRef, content: impl AsRef) { if fs::read_to_string(file.as_ref()).ok().as_deref() != Some(content.as_ref()) { diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index cf437ee7f0e6c..809a940c74068 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -77,6 +77,15 @@ fn crate_metadata(cargo_manifest: &Path) -> Metadata { let cargo_lock_existed = cargo_lock.exists(); + // If we can find a `Cargo.lock`, we assume that this is the workspace root and there exists a + // `Cargo.toml` that we can use for getting the metadata. + let cargo_manifest = if let Some(mut cargo_lock) = find_cargo_lock(cargo_manifest) { + cargo_lock.set_file_name("Cargo.toml"); + cargo_lock + } else { + cargo_manifest.to_path_buf() + }; + let crate_metadata = MetadataCommand::new() .manifest_path(cargo_manifest) .exec() @@ -151,18 +160,29 @@ fn find_cargo_lock(cargo_manifest: &Path) -> Option { } } - if let Some(path) = find_impl(build_helper::out_dir()) { - return Some(path) + if let Ok(workspace) = env::var(crate::WASM_BUILD_WORKSPACE_HINT) { + let path = PathBuf::from(workspace); + + if path.join("Cargo.lock").exists() { + return Some(path.join("Cargo.lock")) + } else { + build_helper::warning!( + "`{}` env variable doesn't point to a directory that contains a `Cargo.lock`.", + crate::WASM_BUILD_WORKSPACE_HINT, + ); + } } - if let Some(path) = find_impl(cargo_manifest.to_path_buf()) { + if let Some(path) = find_impl(build_helper::out_dir()) { return Some(path) } build_helper::warning!( - "Could not find `Cargo.lock` for `{}`, while searching from `{}`.", + "Could not find `Cargo.lock` for `{}`, while searching from `{}`. \ + To fix this, point the `{}` env variable to the directory of the workspace being compiled.", cargo_manifest.display(), - build_helper::out_dir().display() + build_helper::out_dir().display(), + crate::WASM_BUILD_WORKSPACE_HINT, ); None From 227a94faa19364a6beef666e736484b3ff558132 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 21 Jan 2022 18:08:35 +0100 Subject: [PATCH 0448/1472] Add `MaxEncodeLen` to `implement_per_thing!` (#10715) * fix doc Signed-off-by: Oliver Tale-Yazdi * Add MaxEncodedLen to implement_per_thing! Signed-off-by: Oliver Tale-Yazdi * Test that Percent et.al. can be used in Storage. Signed-off-by: Oliver Tale-Yazdi * Add comment Signed-off-by: Oliver Tale-Yazdi * Revert "Test that Percent et.al. can be used in Storage." This reverts commit 52558afea6f9b53fb07521f1b6393bc320d21dfc. * Test MaxEncodedLen in implement_per_thing! Signed-off-by: Oliver Tale-Yazdi * Revert "Add comment" This reverts commit 27a96f6e527f71a57ace289c041de514edbe9104. --- frame/support/test/tests/pallet.rs | 2 +- primitives/arithmetic/src/per_things.rs | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 2cb7b283b66fb..cf882556088ef 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -432,7 +432,7 @@ pub mod pallet { } // Test that a pallet with non generic event and generic genesis_config is correctly handled -// and that a pallet without the attribute generate_storage_info is correctly handled. +// and that a pallet with the attribute without_storage_info is correctly handled. #[frame_support::pallet] pub mod pallet2 { use super::{SomeAssociation1, SomeType1}; diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index 21ad0dd52099c..fbd45bb693247 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -425,7 +425,7 @@ macro_rules! implement_per_thing { /// #[doc = $title] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] - #[derive(Encode, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, scale_info::TypeInfo)] + #[derive(Encode, Copy, Clone, PartialEq, Eq, codec::MaxEncodedLen, PartialOrd, Ord, RuntimeDebug, scale_info::TypeInfo)] pub struct $name($type); /// Implementation makes any compact encoding of `PerThing::Inner` valid, @@ -905,6 +905,15 @@ macro_rules! implement_per_thing { } } + #[test] + fn has_max_encoded_len() { + struct AsMaxEncodedLen { + _data: T, + } + + let _ = AsMaxEncodedLen { _data: $name(1) }; + } + #[test] fn fail_on_invalid_encoded_value() { let value = <$upper_type>::from($max) * 2; From af5e675dd73788f1a9629c5213252517d8fad354 Mon Sep 17 00:00:00 2001 From: Jimmy Chu Date: Sat, 22 Jan 2022 01:32:45 +0800 Subject: [PATCH 0449/1472] Script for publishing rustdocs at gh-pages (#10604) * wip Signed-off-by: Jimmy Chu * Added the rustdocs-release script Signed-off-by: Jimmy Chu * updated gitlab-ci script Signed-off-by: Jimmy Chu * Updated to set NIGHTLY to false by default Signed-off-by: Jimmy Chu * Added documentation Signed-off-by: Jimmy Chu --- .gitlab-ci.yml | 32 +---- .maintain/rustdocs-release.sh | 244 ++++++++++++++++++++++++++++++++++ docs/rustdocs-release.md | 20 +++ 3 files changed, 269 insertions(+), 27 deletions(-) create mode 100755 .maintain/rustdocs-release.sh create mode 100644 docs/rustdocs-release.md diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b68dd303841d8..a0b71fcff02e5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -747,13 +747,7 @@ publish-rustdoc: image: node:16 variables: GIT_DEPTH: 100 - # --- Following variables are for rustdocs deployment --- - # Space separated values of branches and tags to generate rustdocs - RUSTDOCS_DEPLOY_REFS: "master monthly-2021-09+1 monthly-2021-08 v3.0.0" - # Location of the docs index template - INDEX_TPL: ".maintain/docs-index-tpl.ejs" - # Where the `/latest` symbolic link links to. One of the $RUSTDOCS_DEPLOY_REFS value. - LATEST: "monthly-2021-09+1" + RUSTDOCS_DEPLOY_REFS: "master" rules: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never @@ -783,34 +777,18 @@ publish-rustdoc: - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch origin gh-pages - # Install `ejs` and generate index.html based on RUSTDOCS_DEPLOY_REFS - - yarn global add ejs - - 'ejs ${INDEX_TPL} -i "{\"deploy_refs\":\"${RUSTDOCS_DEPLOY_REFS}\",\"repo_name\":\"${CI_PROJECT_NAME}\",\"latest\":\"${LATEST}\"}" > /tmp/index.html' # Save README and docs - cp -r ./crate-docs/ /tmp/doc/ - cp README.md /tmp/doc/ - git checkout gh-pages - # Remove directories no longer necessary, as specified in $RUSTDOCS_DEPLOY_REFS. - # Also ensure $RUSTDOCS_DEPLOY_REFS is not just empty spaces. - # Even though this block spans multiple lines, they are concatenated to run as a single line - # command, so note for the semi-colons in the inner-most code block. - - if [[ ! -z ${RUSTDOCS_DEPLOY_REFS// } ]]; then - for FILE in *; do - if [[ ! " $RUSTDOCS_DEPLOY_REFS " =~ " $FILE " ]]; then - echo "Removing ${FILE}..."; - rm -rf $FILE; - fi - done - fi - # Move the index page & built back - - mv -f /tmp/index.html . + # Install `index-tpl-crud` and generate index.html based on RUSTDOCS_DEPLOY_REFS + - which index-tpl-crud &> /dev/null || yarn global add @jimmychu0807/index-tpl-crud + - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} # Ensure the destination dir doesn't exist. - rm -rf ${CI_COMMIT_REF_NAME} - mv -f /tmp/doc ${CI_COMMIT_REF_NAME} - # Add the symlink - - '[[ -e "$LATEST" ]] && ln -sf "${LATEST}" latest' # Upload files - - git add --all --force + - git add --all # `git commit` has an exit code of > 0 if there is nothing to commit. # This causes GitLab to exit immediately and marks this job failed. # We don't want to mark the entire job failed if there's nothing to diff --git a/.maintain/rustdocs-release.sh b/.maintain/rustdocs-release.sh new file mode 100755 index 0000000000000..8a250849ee7a6 --- /dev/null +++ b/.maintain/rustdocs-release.sh @@ -0,0 +1,244 @@ +#!/usr/bin/env bash +# set -x + +# This script manages the deployment of Substrate rustdocs to https://paritytech.github.io/substrate/. +# - With `deploy` sub-command, it will checkout the passed-in branch/tag ref, build the rustdocs +# locally (this takes some time), update the `index.html` index page, and push it to remote +# `gh-pages` branch. So users running this command need to have write access to the remote +# `gh-pages` branch. This sub-command depends on [@jimmychu0807/index-tpl-crud](https://www.npmjs.com/package/@jimmychu0807/index-tpl-crud) +# to update the DOM of index.html page. +# - With `remove` sub-command, it will remove the deployed rustdocs from `gh-pages`, and update the +# index.html page as necessary. It may remove the `latest` symbolic link. +# +# Examples: +# # Showing help text +# rustdocs-release.sh -h +# +# # Deploy rustdocs of `monthly-2021-10` tag +# rustdocs-release.sh deploy monthly-2021-10 +# +# # In addition to the above, the `latest` symlink will point to this version of rustdocs +# rustdocs-release.sh deploy -l monthly-2021-10 +# +# # Remove the rustdocs of `monthly-2021-10` from `gh-pages`. +# rustdocs-release.sh remove monthly-2021-10 +# +# Dependencies: +# - @jimmychu0807/index-tpl-crud - https://www.npmjs.com/package/@jimmychu0807/index-tpl-crud +# + +# Script setting +# The git repo http URL +REMOTE_REPO="https://github.com/paritytech/substrate.git" +TMP_PREFIX="/tmp" # tmp location that the built doc is copied to. +DOC_INDEX_PAGE="sc_service/index.html" + +# Set to `true` if using cargo `nightly` toolchain to build the doc. +# Set to `false` to use the default cargo toolchain. This is preferred if you want to build +# the rustdocs with a pinned nightly version set to your default toolchain. +CARGO_NIGHTLY=false + +# Set the git remote name. Most of the time the default is `origin`. +GIT_REMOTE="origin" +LATEST=false + +# Setting the help text +declare -A HELP_TXT +HELP_TXT["deploy"]=$(cat <<-EOH +Build and deploy the rustdocs of the specified branch/tag to \`gh-pages\` branch. + + usage: $0 deploy [-l] + example: $0 deploy -l monthly-2021-10 + + options: + -l The \`latest\` path will be sym'linked to this rustdocs version +EOH +) + +HELP_TXT["remove"]=$(cat <<-EOH +Remove the rustdocs of the specified version from \`gh-pages\` branch. + + usage: $0 remove + example: $0 remove monthly-2021-10 +EOH +) + +set_and_check_rustdoc_ref() { + [[ -z "$1" ]] && { + echo -e "git branch_ref is not specified.\n" + echo "${HELP_TXT[$2]}" + exit 1 + } + BUILD_RUSTDOC_REF=$1 +} + +check_local_change() { + # Check there is no local changes before proceeding + [[ -n $(git status --porcelain) ]] \ + && echo "Local changes exist, please either discard or commit them as this command will change the current checkout branch." \ + && exit 1 +} + +build_rustdocs() { + # Build the docs + time cargo $($CARGO_NIGHTLY && echo "+nightly") doc --workspace --all-features --verbose \ + || { echo "Generate $1 rustdocs failed" && exit 1; } + rm -f target/doc/.lock + + # Moving the built doc to the tmp location + mv target/doc "${2}" + [[ -n "${DOC_INDEX_PAGE}" ]] \ + && echo "" > "${2}/index.html" +} + +upsert_index_page() { + # Check if `index-tpl-crud` exists + which index-tpl-crud &> /dev/null || yarn global add @jimmychu0807/index-tpl-crud + index-tpl-crud upsert $($1 && echo "-l") ./index.html "$2" +} + +rm_index_page() { + which index-tpl-crud &> /dev/null || yarn global add @jimmychu0807/index-tpl-crud + index-tpl-crud rm ./index.html "$1" +} + +git_add_commit_push() { + git add --all + git commit -m "$1" || echo "Nothing to commit" + git push "${GIT_REMOTE}" gh-pages --force +} + +import_gh_key() { + [[ -n $GITHUB_SSH_PRIV_KEY ]] && { + eval $(ssh-agent) + ssh-add - <<< $GITHUB_SSH_PRIV_KEY + } + + # Adding github.com as known_hosts + ssh-keygen -F github.com &>/dev/null || { + [[ -e ~/.ssh ]] || mkdir ~/.ssh + [[ -e ~/.ssh/known_hosts ]] || touch ~/.ssh/known_hosts + ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts + } +} + +deploy_main() { + check_local_change + import_gh_key + + CURRENT_GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + TMP_PROJECT_PATH="${TMP_PREFIX}/${PROJECT_NAME}" + DOC_PATH="${TMP_PROJECT_PATH}/${BUILD_RUSTDOC_REF}" + + # Build the tmp project path + rm -rf "${TMP_PROJECT_PATH}" && mkdir "${TMP_PROJECT_PATH}" + + # Copy .gitignore file to tmp + [[ -e "${PROJECT_PATH}/.gitignore" ]] && cp "${PROJECT_PATH}/.gitignore" "${TMP_PROJECT_PATH}" + + git fetch --all + git checkout -f ${BUILD_RUSTDOC_REF} || { echo "Checkout \`${BUILD_RUSTDOC_REF}\` error." && exit 1; } + build_rustdocs "${BUILD_RUSTDOC_REF}" "${DOC_PATH}" + + # git checkout `gh-pages` branch + git fetch "${GIT_REMOTE}" gh-pages + git checkout gh-pages + # Move the built back + [[ -e "${TMP_PROJECT_PATH}/.gitignore" ]] && cp -f "${TMP_PROJECT_PATH}/.gitignore" . + # Ensure the destination dir doesn't exist under current path. + rm -rf "${BUILD_RUSTDOC_REF}" + mv -f "${DOC_PATH}" "${BUILD_RUSTDOC_REF}" + + upsert_index_page $LATEST "${BUILD_RUSTDOC_REF}" + # Add the latest symlink + $LATEST && rm -rf latest && ln -sf "${BUILD_RUSTDOC_REF}" latest + + git_add_commit_push "___Deployed rustdocs of ${BUILD_RUSTDOC_REF}___" + # Clean up + # Remove the tmp asset created + rm -rf "${TMP_PROJECT_PATH}" + # Resume back previous checkout branch. + git checkout -f "$CURRENT_GIT_BRANCH" +} + +remove_main() { + check_local_change + import_gh_key + + CURRENT_GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + + # git checkout `gh-pages` branch + git fetch "${GIT_REMOTE}" gh-pages + git checkout gh-pages + + rm -rf "${BUILD_RUSTDOC_REF}" + rm_index_page "${BUILD_RUSTDOC_REF}" + # check if the destination of `latest` exists and rmove if not. + [[ -e "latest" ]] || rm latest + + git_add_commit_push "___Removed rustdocs of ${BUILD_RUSTDOC_REF}___" + + # Resume back previous checkout branch. + git checkout -f "$CURRENT_GIT_BRANCH" +} + +# ---- The script execution entry point starts here ---- + +# Arguments handling +SUBCMD=$1 +[[ $SUBCMD == "deploy" || $SUBCMD == "remove" ]] \ + || { echo "Please specify a subcommand of \`deploy\` or \`remove\`" && exit 1 ;} +shift + +# After removing the subcommand, there could only be 1 or 2 parameters afterward +[[ $# -lt 1 || $# -gt 2 ]] && { + echo "${HELP_TXT[${SUBCMD}]}" + exit 1 +} + +# Parsing options and argument for `deploy` subcommand +[[ $SUBCMD == "deploy" ]] && { + while getopts :lh opt; do + case $opt in + l) + LATEST=true + ;; + h) + echo "${HELP_TXT[$SUBCMD]}" + exit 0 + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + exit 1 + ;; + esac + done +} +# Parsing options and argument for `remove` subcommand +[[ $SUBCMD == "remove" ]] && { + while getopts :h opt; do + case $opt in + h) + echo "${HELP_TXT[$SUBCMD]}" + exit 0 + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + exit 1 + ;; + esac + done +} + +shift $(($OPTIND - 1)) +set_and_check_rustdoc_ref ${1:-''} $SUBCMD + +SCRIPT=$(realpath $0) +SCRIPT_PATH=$(dirname $SCRIPT) +PROJECT_PATH=$(dirname ${SCRIPT_PATH}) +PROJECT_NAME=$(basename "$PROJECT_PATH") + +pushd "${PROJECT_PATH}" &>/dev/null +[[ $SUBCMD == "deploy" ]] && deploy_main +[[ $SUBCMD == "remove" ]] && remove_main +popd &>/dev/null diff --git a/docs/rustdocs-release.md b/docs/rustdocs-release.md new file mode 100644 index 0000000000000..5c7e2db40a2cd --- /dev/null +++ b/docs/rustdocs-release.md @@ -0,0 +1,20 @@ +# Rustdocs Release Process + +There is [a script in place](../.maintain/rustdocs-release.sh) to manage the deployment of Substrate rustdocs at +https://paritytech.github.io/substrate, which is pushing the rustdocs file in `gh-pages` branch of +https://github.com/paritytech/substrate. + +The documentation at the top of the `rustdocs-release.sh` explains most of the mechanics of the script. + +Manage the rustdocs deployment with one of the following commands. + +```bash +# Deploy rustdocs of `monthly-2021-10` tag +.maintain/rustdocs-release.sh deploy monthly-2021-10 + +# In addition to the above, the `latest` symlink will point to this version of rustdocs +.maintain/rustdocs-release.sh deploy -l monthly-2021-10 + +# Remove the rustdocs of `monthly-2021-10` from `gh-pages`. +.maintain/rustdocs-release.sh remove monthly-2021-10 +``` From 94dfe152e61e42cd27844a65165cfdedde5232eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 21 Jan 2022 20:21:36 +0100 Subject: [PATCH 0450/1472] Remove some last `AccountId32::default()` leftovers (#10655) * Remove some last `AccountId32::default()` leftovers As we removed `Default` of account id, we have overseen some last bits. This pr removes these last bits. * Fix --- frame/collective/src/lib.rs | 7 +++++-- primitives/core/src/crypto.rs | 10 ++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 3e3b923d6ee37..49328aa0bdc68 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -990,8 +990,8 @@ where pub struct EnsureMember(PhantomData<(AccountId, I)>); impl< O: Into, O>> + From>, - AccountId: Default, I, + AccountId: Decode, > EnsureOrigin for EnsureMember { type Success = AccountId; @@ -1004,7 +1004,10 @@ impl< #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> O { - O::from(RawOrigin::Member(Default::default())) + let zero_account_id = + AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"); + O::from(RawOrigin::Member(zero_account_id)) } } diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 41ee9466ad93b..12f8397eee4a4 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -478,9 +478,7 @@ pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Sen } /// An opaque 32-byte cryptographic identifier. -#[derive( - Clone, Eq, PartialEq, Ord, PartialOrd, Default, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Hash))] pub struct AccountId32([u8; 32]); @@ -541,9 +539,9 @@ impl<'a> sp_std::convert::TryFrom<&'a [u8]> for AccountId32 { type Error = (); fn try_from(x: &'a [u8]) -> Result { if x.len() == 32 { - let mut r = AccountId32::default(); - r.0.copy_from_slice(x); - Ok(r) + let mut data = [0; 32]; + data.copy_from_slice(x); + Ok(AccountId32(data)) } else { Err(()) } From 32b71896df8a832e7c139a842e46710e4d3f70cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 22 Jan 2022 21:15:28 +0100 Subject: [PATCH 0451/1472] wasm-builder: Enable all features when running `cargo metadata` (#10716) This is required for projects like Cumulus that have dependencies on `westend-runtime`, but this runtime is only added when the `runtime-benchmarks` feature is enabled. By having all features "enabled" in `cargo metadata` we ensure that all crates can be found. --- utils/wasm-builder/src/wasm_project.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 809a940c74068..9b5a33b6a6238 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -31,7 +31,7 @@ use toml::value::Table; use build_helper::rerun_if_changed; -use cargo_metadata::{Metadata, MetadataCommand}; +use cargo_metadata::{CargoOpt, Metadata, MetadataCommand}; use walkdir::WalkDir; @@ -88,6 +88,7 @@ fn crate_metadata(cargo_manifest: &Path) -> Metadata { let crate_metadata = MetadataCommand::new() .manifest_path(cargo_manifest) + .features(CargoOpt::AllFeatures) .exec() .expect("`cargo metadata` can not fail on project `Cargo.toml`; qed"); From b57c08be31f0427780b0b1a1e21cea54a996cd7a Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Mon, 24 Jan 2022 10:48:44 +0100 Subject: [PATCH 0452/1472] Fix #10688 being misimplemented (#10721) --- client/network/src/protocol.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 3fb40b7199d68..5541a0145366f 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -827,7 +827,7 @@ impl Protocol { } if status.roles.is_light() && - (self.peers.len() - self.sync.num_peers()) < self.default_peers_set_num_light + (self.peers.len() - self.sync.num_peers()) >= self.default_peers_set_num_light { // Make sure that not all slots are occupied by light clients. debug!(target: "sync", "Too many light nodes, rejecting {}", who); From 48c05c0ab98d34944d395c638188755f3e4694b1 Mon Sep 17 00:00:00 2001 From: Jimmy Chu Date: Mon, 24 Jan 2022 19:11:26 +0800 Subject: [PATCH 0453/1472] Changing the node package to be under @substrate namespace (#10722) Signed-off-by: Jimmy Chu --- .gitlab-ci.yml | 2 +- .maintain/rustdocs-release.sh | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a0b71fcff02e5..b2716b018d6c0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -782,7 +782,7 @@ publish-rustdoc: - cp README.md /tmp/doc/ - git checkout gh-pages # Install `index-tpl-crud` and generate index.html based on RUSTDOCS_DEPLOY_REFS - - which index-tpl-crud &> /dev/null || yarn global add @jimmychu0807/index-tpl-crud + - which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} # Ensure the destination dir doesn't exist. - rm -rf ${CI_COMMIT_REF_NAME} diff --git a/.maintain/rustdocs-release.sh b/.maintain/rustdocs-release.sh index 8a250849ee7a6..2a1e141e63ad2 100755 --- a/.maintain/rustdocs-release.sh +++ b/.maintain/rustdocs-release.sh @@ -5,7 +5,7 @@ # - With `deploy` sub-command, it will checkout the passed-in branch/tag ref, build the rustdocs # locally (this takes some time), update the `index.html` index page, and push it to remote # `gh-pages` branch. So users running this command need to have write access to the remote -# `gh-pages` branch. This sub-command depends on [@jimmychu0807/index-tpl-crud](https://www.npmjs.com/package/@jimmychu0807/index-tpl-crud) +# `gh-pages` branch. This sub-command depends on [@substrate/index-tpl-crud](https://www.npmjs.com/package/@substrate/index-tpl-crud) # to update the DOM of index.html page. # - With `remove` sub-command, it will remove the deployed rustdocs from `gh-pages`, and update the # index.html page as necessary. It may remove the `latest` symbolic link. @@ -24,7 +24,7 @@ # rustdocs-release.sh remove monthly-2021-10 # # Dependencies: -# - @jimmychu0807/index-tpl-crud - https://www.npmjs.com/package/@jimmychu0807/index-tpl-crud +# - @substrate/index-tpl-crud - https://www.npmjs.com/package/@substrate/index-tpl-crud # # Script setting @@ -93,12 +93,12 @@ build_rustdocs() { upsert_index_page() { # Check if `index-tpl-crud` exists - which index-tpl-crud &> /dev/null || yarn global add @jimmychu0807/index-tpl-crud + which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud index-tpl-crud upsert $($1 && echo "-l") ./index.html "$2" } rm_index_page() { - which index-tpl-crud &> /dev/null || yarn global add @jimmychu0807/index-tpl-crud + which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud index-tpl-crud rm ./index.html "$1" } From 542a8585339d2581e641df339d254d7dd22b1456 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 24 Jan 2022 13:35:25 +0100 Subject: [PATCH 0454/1472] Optimized weights (#10692) * Add optimization flags to 'release' profile Signed-off-by: Oliver Tale-Yazdi * Optimized weights Signed-off-by: Oliver Tale-Yazdi * Add missing pallets Signed-off-by: Oliver Tale-Yazdi * Add `production` profile Signed-off-by: Oliver Tale-Yazdi * pallet-collective: fix tests the weight of System.remark went to 0, the collective test uses a remark call to trigger an out-of-gas condition so I replaced it with a `remark_with_event` call. Signed-off-by: Oliver Tale-Yazdi --- Cargo.toml | 11 + frame/assets/src/weights.rs | 145 +-- frame/bags-list/src/weights.rs | 24 +- frame/balances/src/weights.rs | 41 +- frame/benchmarking/src/weights.rs | 64 +- frame/bounties/src/weights.rs | 65 +- frame/child-bounties/src/weights.rs | 57 +- frame/collective/src/tests.rs | 2 +- frame/collective/src/weights.rs | 285 ++-- frame/contracts/src/weights.rs | 1152 +++++++++-------- frame/democracy/src/weights.rs | 213 +-- .../src/weights.rs | 143 +- frame/elections-phragmen/src/weights.rs | 165 +-- frame/gilt/src/weights.rs | 69 +- frame/identity/src/weights.rs | 232 ++-- frame/im-online/src/weights.rs | 27 +- frame/indices/src/weights.rs | 33 +- frame/lottery/src/weights.rs | 38 +- frame/membership/src/weights.rs | 189 +-- frame/multisig/src/weights.rs | 125 +- frame/preimage/src/weights.rs | 48 +- frame/proxy/src/weights.rs | 129 +- frame/scheduler/src/weights.rs | 168 +-- frame/session/src/weights.rs | 21 +- frame/staking/src/weights.rs | 224 ++-- frame/system/src/weights.rs | 67 +- frame/timestamp/src/weights.rs | 21 +- frame/tips/src/weights.rs | 117 +- frame/transaction-storage/src/weights.rs | 27 +- frame/treasury/src/weights.rs | 45 +- frame/uniques/src/weights.rs | 125 +- frame/utility/src/weights.rs | 45 +- frame/vesting/src/weights.rs | 153 +-- 33 files changed, 2162 insertions(+), 2108 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b7051bdd44ef4..48a36419eb746 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -272,6 +272,17 @@ wasmi = { opt-level = 3 } x25519-dalek = { opt-level = 3 } yamux = { opt-level = 3 } zeroize = { opt-level = 3 } + [profile.release] # Substrate runtime requires unwinding. panic = "unwind" + +[profile.production] +inherits = "release" + +# Sacrifice compile speed for execution speed by using optimization flags: + +# https://doc.rust-lang.org/rustc/linker-plugin-lto.html +lto = "fat" +# https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-units +codegen-units = 1 diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 423677cf13808..fb6e68dfc772f 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/assets/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -75,13 +76,13 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (41_651_000 as Weight) + (22_050_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (21_378_000 as Weight) + (11_673_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -92,12 +93,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 32_000 - .saturating_add((21_163_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 32_000 - .saturating_add((26_932_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 329_000 - .saturating_add((29_714_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 36_000 + .saturating_add((14_657_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 36_000 + .saturating_add((17_018_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 362_000 + .saturating_add((16_620_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) @@ -110,14 +111,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (47_913_000 as Weight) + (26_254_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (55_759_000 as Weight) + (30_407_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -125,7 +126,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (83_205_000 as Weight) + (44_220_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -133,7 +134,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (70_665_000 as Weight) + (36_910_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -141,93 +142,93 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (81_458_000 as Weight) + (44_330_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (32_845_000 as Weight) + (17_937_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (33_303_000 as Weight) + (18_224_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (23_434_000 as Weight) + (14_875_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (24_173_000 as Weight) + (14_792_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (27_466_000 as Weight) + (15_794_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (24_608_000 as Weight) + (14_702_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn set_metadata(n: u32, s: u32, ) -> Weight { - (49_515_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 1_000 - .saturating_add((6_000 as Weight).saturating_mul(s as Weight)) + (27_368_000 as Weight) + // Standard Error: 0 + .saturating_add((4_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 0 + .saturating_add((4_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (48_163_000 as Weight) + (28_222_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - (26_722_000 as Weight) + (15_139_000 as Weight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((3_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (47_923_000 as Weight) + (28_065_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (23_081_000 as Weight) + (13_808_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (56_998_000 as Weight) + (31_261_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -236,21 +237,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (107_171_000 as Weight) + (56_329_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (57_358_000 as Weight) + (32_086_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - (58_330_000 as Weight) + (32_502_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -260,13 +261,13 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (41_651_000 as Weight) + (22_050_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (21_378_000 as Weight) + (11_673_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -277,12 +278,12 @@ impl WeightInfo for () { // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 32_000 - .saturating_add((21_163_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 32_000 - .saturating_add((26_932_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 329_000 - .saturating_add((29_714_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 36_000 + .saturating_add((14_657_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 36_000 + .saturating_add((17_018_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 362_000 + .saturating_add((16_620_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) @@ -295,14 +296,14 @@ impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (47_913_000 as Weight) + (26_254_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (55_759_000 as Weight) + (30_407_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -310,7 +311,7 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (83_205_000 as Weight) + (44_220_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -318,7 +319,7 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (70_665_000 as Weight) + (36_910_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -326,93 +327,93 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (81_458_000 as Weight) + (44_330_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (32_845_000 as Weight) + (17_937_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (33_303_000 as Weight) + (18_224_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (23_434_000 as Weight) + (14_875_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (24_173_000 as Weight) + (14_792_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (27_466_000 as Weight) + (15_794_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (24_608_000 as Weight) + (14_702_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn set_metadata(n: u32, s: u32, ) -> Weight { - (49_515_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 1_000 - .saturating_add((6_000 as Weight).saturating_mul(s as Weight)) + (27_368_000 as Weight) + // Standard Error: 0 + .saturating_add((4_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 0 + .saturating_add((4_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (48_163_000 as Weight) + (28_222_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - (26_722_000 as Weight) + (15_139_000 as Weight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((3_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (47_923_000 as Weight) + (28_065_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (23_081_000 as Weight) + (13_808_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (56_998_000 as Weight) + (31_261_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -421,21 +422,21 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (107_171_000 as Weight) + (56_329_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (57_358_000 as Weight) + (32_086_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - (58_330_000 as Weight) + (32_502_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index 5a8f51cc07c76..6cd9449b42862 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_bags_list //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/optimized/substrate // benchmark // --chain=dev // --steps=50 @@ -32,8 +32,10 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/bags-list/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --output=./weights-optimized/frame/bags-list/src//weights.rs +// --template=.maintain/frame-weight-template.hbs +// --header=HEADER-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,7 +59,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (62_060_000 as Weight) + (50_222_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -66,7 +68,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (60_585_000 as Weight) + (47_975_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -76,7 +78,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (69_779_000 as Weight) + (55_539_000 as Weight) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -89,7 +91,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (62_060_000 as Weight) + (50_222_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -98,7 +100,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (60_585_000 as Weight) + (47_975_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -108,7 +110,7 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (69_779_000 as Weight) + (55_539_000 as Weight) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index a272753b73466..f34dd65191e4a 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_balances //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-09-13, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/balances/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -59,43 +60,43 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (70_952_000 as Weight) + (34_668_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (54_410_000 as Weight) + (26_826_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (29_176_000 as Weight) + (17_292_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (35_214_000 as Weight) + (19_988_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (71_780_000 as Weight) + (34_646_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (66_475_000 as Weight) + (32_040_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (27_766_000 as Weight) + (15_743_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -105,43 +106,43 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (70_952_000 as Weight) + (34_668_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (54_410_000 as Weight) + (26_826_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (29_176_000 as Weight) + (17_292_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (35_214_000 as Weight) + (19_988_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (71_780_000 as Weight) + (34_646_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (66_475_000 as Weight) + (32_040_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (27_766_000 as Weight) + (15_743_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index a4d46d24b6e3a..2945daeaf3128 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for frame_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-12-02, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,7 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/benchmarking/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -58,39 +60,37 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn addition(_i: u32, ) -> Weight { - (284_000 as Weight) + (141_000 as Weight) } fn subtraction(_i: u32, ) -> Weight { - (279_000 as Weight) + (136_000 as Weight) } fn multiplication(_i: u32, ) -> Weight { - (278_000 as Weight) + (136_000 as Weight) } fn division(_i: u32, ) -> Weight { - (274_000 as Weight) + (134_000 as Weight) } - fn hashing(i: u32, ) -> Weight { - (33_441_957_000 as Weight) - // Standard Error: 535_000 - .saturating_add((363_000 as Weight).saturating_mul(i as Weight)) + fn hashing(_i: u32, ) -> Weight { + (21_681_881_000 as Weight) } fn sr25519_verification(i: u32, ) -> Weight { - (26_000 as Weight) - // Standard Error: 14_000 - .saturating_add((48_151_000 as Weight).saturating_mul(i as Weight)) + (0 as Weight) + // Standard Error: 6_000 + .saturating_add((42_000_000 as Weight).saturating_mul(i as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_000 - .saturating_add((2_694_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 3_000 + .saturating_add((1_984_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((606_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((363_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } } @@ -98,39 +98,37 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn addition(_i: u32, ) -> Weight { - (284_000 as Weight) + (141_000 as Weight) } fn subtraction(_i: u32, ) -> Weight { - (279_000 as Weight) + (136_000 as Weight) } fn multiplication(_i: u32, ) -> Weight { - (278_000 as Weight) + (136_000 as Weight) } fn division(_i: u32, ) -> Weight { - (274_000 as Weight) + (134_000 as Weight) } - fn hashing(i: u32, ) -> Weight { - (33_441_957_000 as Weight) - // Standard Error: 535_000 - .saturating_add((363_000 as Weight).saturating_mul(i as Weight)) + fn hashing(_i: u32, ) -> Weight { + (21_681_881_000 as Weight) } fn sr25519_verification(i: u32, ) -> Weight { - (26_000 as Weight) - // Standard Error: 14_000 - .saturating_add((48_151_000 as Weight).saturating_mul(i as Weight)) + (0 as Weight) + // Standard Error: 6_000 + .saturating_add((42_000_000 as Weight).saturating_mul(i as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_000 - .saturating_add((2_694_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 3_000 + .saturating_add((1_984_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((606_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((363_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 4cff3180ca795..9c1ce532dff73 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,23 +18,24 @@ //! Autogenerated weights for pallet_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 // --repeat=20 -// --pallet -// pallet_bounties +// --pallet=pallet_bounties // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/bounties/src/ -// --template=./.maintain/frame-weight-template.hbs +// --output=./frame/bounties/src/weights.rs +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -66,7 +67,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(d: u32, ) -> Weight { - (58_161_000 as Weight) + (23_165_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -75,34 +76,34 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (20_000_000 as Weight) + (6_876_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (14_000_000 as Weight) + (5_718_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (62_000_000 as Weight) + (27_021_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (55_000_000 as Weight) + (20_933_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (46_000_000 as Weight) + (17_285_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -111,7 +112,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (185_000_000 as Weight) + (61_264_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -120,7 +121,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (82_000_000 as Weight) + (28_218_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -129,13 +130,13 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (137_000_000 as Weight) + (45_577_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (33_000_000 as Weight) + (14_983_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -144,8 +145,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { (0 as Weight) - // Standard Error: 191_000 - .saturating_add((81_116_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 14_000 + .saturating_add((28_380_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -160,7 +161,7 @@ impl WeightInfo for () { // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(d: u32, ) -> Weight { - (58_161_000 as Weight) + (23_165_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -169,34 +170,34 @@ impl WeightInfo for () { // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (20_000_000 as Weight) + (6_876_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (14_000_000 as Weight) + (5_718_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (62_000_000 as Weight) + (27_021_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (55_000_000 as Weight) + (20_933_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (46_000_000 as Weight) + (17_285_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -205,7 +206,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (185_000_000 as Weight) + (61_264_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -214,7 +215,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (82_000_000 as Weight) + (28_218_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -223,13 +224,13 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (137_000_000 as Weight) + (45_577_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (33_000_000 as Weight) + (14_983_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -238,8 +239,8 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { (0 as Weight) - // Standard Error: 191_000 - .saturating_add((81_116_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 14_000 + .saturating_add((28_380_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index 1662984aa7a3a..73bc535cb300e 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,23 +18,24 @@ //! Autogenerated weights for pallet_child_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-12-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/release/substrate +// ./target/optimized/substrate // benchmark // --chain=dev // --steps=50 // --repeat=20 -// --pallet -// pallet_child_bounties +// --pallet=pallet_child_bounties // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/child-bounties/src/ -// --template=./.maintain/frame-weight-template.hbs +// --output=./weights-optimized/frame/child-bounties/src//weights.rs +// --template=.maintain/frame-weight-template.hbs +// --header=HEADER-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -64,10 +65,8 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBountyCount (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) - fn add_child_bounty(d: u32, ) -> Weight { - (113_579_000 as Weight) - // Standard Error: 1_000 - .saturating_add((4_000 as Weight).saturating_mul(d as Weight)) + fn add_child_bounty(_d: u32, ) -> Weight { + (44_997_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -75,7 +74,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - (24_000_000 as Weight) + (11_848_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -83,7 +82,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (55_000_000 as Weight) + (24_490_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -91,14 +90,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (61_000_000 as Weight) + (28_605_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - (42_000_000 as Weight) + (19_471_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -107,7 +106,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - (153_000_000 as Weight) + (60_737_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -118,7 +117,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - (101_000_000 as Weight) + (43_120_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -129,7 +128,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - (130_000_000 as Weight) + (53_610_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -143,10 +142,8 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBountyCount (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) - fn add_child_bounty(d: u32, ) -> Weight { - (113_579_000 as Weight) - // Standard Error: 1_000 - .saturating_add((4_000 as Weight).saturating_mul(d as Weight)) + fn add_child_bounty(_d: u32, ) -> Weight { + (44_997_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -154,7 +151,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - (24_000_000 as Weight) + (11_848_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -162,7 +159,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (55_000_000 as Weight) + (24_490_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -170,14 +167,14 @@ impl WeightInfo for () { // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (61_000_000 as Weight) + (28_605_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - (42_000_000 as Weight) + (19_471_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -186,7 +183,7 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - (153_000_000 as Weight) + (60_737_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -197,7 +194,7 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - (101_000_000 as Weight) + (43_120_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -208,7 +205,7 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - (130_000_000 as Weight) + (53_610_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 4f40e02732b4c..f77e52a9b6fe9 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -175,7 +175,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { } fn make_proposal(value: u64) -> Call { - Call::System(frame_system::Call::remark { remark: value.encode() }) + Call::System(frame_system::Call::remark_with_event { remark: value.to_be_bytes().to_vec() }) } fn record(event: Event) -> EventRecord { diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index bdb07834a66c9..a559261fdea0f 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/collective/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -60,132 +61,132 @@ pub trait WeightInfo { /// Weights for pallet_collective using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Instance1Collective Members (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:0) - // Storage: Instance1Collective Voting (r:100 w:100) - // Storage: Instance1Collective Prime (r:0 w:1) + // Storage: Council Members (r:1 w:1) + // Storage: Council Proposals (r:1 w:0) + // Storage: Council Voting (r:100 w:100) + // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_000 - .saturating_add((14_084_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 4_000 - .saturating_add((161_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 4_000 - .saturating_add((19_201_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 7_000 + .saturating_add((12_933_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 7_000 + .saturating_add((81_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 7_000 + .saturating_add((15_645_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(p as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } - // Storage: Instance1Collective Members (r:1 w:0) + // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - (22_748_000 as Weight) + (12_975_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((92_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((74_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective ProposalOf (r:1 w:0) + // Storage: Council Members (r:1 w:0) + // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - (27_465_000 as Weight) + (15_120_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((178_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((139_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) } - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective ProposalOf (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:1) - // Storage: Instance1Collective ProposalCount (r:1 w:1) - // Storage: Instance1Collective Voting (r:0 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council ProposalOf (r:1 w:1) + // Storage: Council Proposals (r:1 w:1) + // Storage: Council ProposalCount (r:1 w:1) + // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - (39_869_000 as Weight) + (18_343_000 as Weight) // Standard Error: 0 .saturating_add((8_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((107_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((83_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((406_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((211_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective Voting (r:1 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - (37_387_000 as Weight) + (26_675_000 as Weight) // Standard Error: 2_000 - .saturating_add((223_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((166_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: Instance1Collective Voting (r:1 w:1) - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective Proposals (r:1 w:1) - // Storage: Instance1Collective ProposalOf (r:0 w:1) + // Storage: Council Voting (r:1 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council Proposals (r:1 w:1) + // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - (45_670_000 as Weight) + (28_535_000 as Weight) // Standard Error: 1_000 - .saturating_add((170_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((123_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((358_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((154_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Collective Voting (r:1 w:1) - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective ProposalOf (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:1) + // Storage: Council Voting (r:1 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council ProposalOf (r:1 w:1) + // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - (52_529_000 as Weight) + (27_235_000 as Weight) // Standard Error: 0 - .saturating_add((7_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((6_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((206_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((412_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((201_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Collective Voting (r:1 w:1) - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective Prime (r:1 w:0) - // Storage: Instance1Collective Proposals (r:1 w:1) - // Storage: Instance1Collective ProposalOf (r:0 w:1) + // Storage: Council Voting (r:1 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council Prime (r:1 w:0) + // Storage: Council Proposals (r:1 w:1) + // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - (50_427_000 as Weight) + (29_502_000 as Weight) // Standard Error: 1_000 - .saturating_add((170_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((139_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((354_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((163_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Collective Voting (r:1 w:1) - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective Prime (r:1 w:0) - // Storage: Instance1Collective ProposalOf (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:1) + // Storage: Council Voting (r:1 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council Prime (r:1 w:0) + // Storage: Council ProposalOf (r:1 w:1) + // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - (57_031_000 as Weight) + (28_944_000 as Weight) // Standard Error: 0 - .saturating_add((7_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((208_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((170_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((408_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((208_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Collective Proposals (r:1 w:1) - // Storage: Instance1Collective Voting (r:0 w:1) - // Storage: Instance1Collective ProposalOf (r:0 w:1) + // Storage: Council Proposals (r:1 w:1) + // Storage: Council Voting (r:0 w:1) + // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - (27_458_000 as Weight) + (16_215_000 as Weight) // Standard Error: 1_000 - .saturating_add((402_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((212_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -193,132 +194,132 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Instance1Collective Members (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:0) - // Storage: Instance1Collective Voting (r:100 w:100) - // Storage: Instance1Collective Prime (r:0 w:1) + // Storage: Council Members (r:1 w:1) + // Storage: Council Proposals (r:1 w:0) + // Storage: Council Voting (r:100 w:100) + // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_000 - .saturating_add((14_084_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 4_000 - .saturating_add((161_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 4_000 - .saturating_add((19_201_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 7_000 + .saturating_add((12_933_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 7_000 + .saturating_add((81_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 7_000 + .saturating_add((15_645_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(p as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } - // Storage: Instance1Collective Members (r:1 w:0) + // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - (22_748_000 as Weight) + (12_975_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((92_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((74_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective ProposalOf (r:1 w:0) + // Storage: Council Members (r:1 w:0) + // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - (27_465_000 as Weight) + (15_120_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((178_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((139_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) } - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective ProposalOf (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:1) - // Storage: Instance1Collective ProposalCount (r:1 w:1) - // Storage: Instance1Collective Voting (r:0 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council ProposalOf (r:1 w:1) + // Storage: Council Proposals (r:1 w:1) + // Storage: Council ProposalCount (r:1 w:1) + // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - (39_869_000 as Weight) + (18_343_000 as Weight) // Standard Error: 0 .saturating_add((8_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((107_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((83_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((406_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((211_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective Voting (r:1 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - (37_387_000 as Weight) + (26_675_000 as Weight) // Standard Error: 2_000 - .saturating_add((223_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((166_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: Instance1Collective Voting (r:1 w:1) - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective Proposals (r:1 w:1) - // Storage: Instance1Collective ProposalOf (r:0 w:1) + // Storage: Council Voting (r:1 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council Proposals (r:1 w:1) + // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - (45_670_000 as Weight) + (28_535_000 as Weight) // Standard Error: 1_000 - .saturating_add((170_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((123_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((358_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((154_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Collective Voting (r:1 w:1) - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective ProposalOf (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:1) + // Storage: Council Voting (r:1 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council ProposalOf (r:1 w:1) + // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - (52_529_000 as Weight) + (27_235_000 as Weight) // Standard Error: 0 - .saturating_add((7_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((6_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((206_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((412_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((201_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Collective Voting (r:1 w:1) - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective Prime (r:1 w:0) - // Storage: Instance1Collective Proposals (r:1 w:1) - // Storage: Instance1Collective ProposalOf (r:0 w:1) + // Storage: Council Voting (r:1 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council Prime (r:1 w:0) + // Storage: Council Proposals (r:1 w:1) + // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - (50_427_000 as Weight) + (29_502_000 as Weight) // Standard Error: 1_000 - .saturating_add((170_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((139_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((354_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((163_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Collective Voting (r:1 w:1) - // Storage: Instance1Collective Members (r:1 w:0) - // Storage: Instance1Collective Prime (r:1 w:0) - // Storage: Instance1Collective ProposalOf (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:1) + // Storage: Council Voting (r:1 w:1) + // Storage: Council Members (r:1 w:0) + // Storage: Council Prime (r:1 w:0) + // Storage: Council ProposalOf (r:1 w:1) + // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - (57_031_000 as Weight) + (28_944_000 as Weight) // Standard Error: 0 - .saturating_add((7_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((208_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((170_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((408_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((208_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Collective Proposals (r:1 w:1) - // Storage: Instance1Collective Voting (r:0 w:1) - // Storage: Instance1Collective ProposalOf (r:0 w:1) + // Storage: Council Proposals (r:1 w:1) + // Storage: Council Voting (r:0 w:1) + // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - (27_458_000 as Weight) + (16_215_000 as Weight) // Standard Error: 1_000 - .saturating_add((402_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((212_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 17ee020f01134..655cba5d3b9aa 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-12-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,7 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/contracts/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -153,32 +155,32 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (2_286_000 as Weight) + (1_585_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 3_000 - .saturating_add((2_219_000 as Weight).saturating_mul(k as Weight)) + (7_902_000 as Weight) + // Standard Error: 0 + .saturating_add((751_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (95_627_000 as Weight) - // Standard Error: 2_000 - .saturating_add((242_000 as Weight).saturating_mul(q as Weight)) + (31_473_000 as Weight) + // Standard Error: 1_000 + .saturating_add((104_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (17_037_000 as Weight) - // Standard Error: 98_000 - .saturating_add((88_875_000 as Weight).saturating_mul(c as Weight)) + (15_462_000 as Weight) + // Standard Error: 35_000 + .saturating_add((81_710_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -187,9 +189,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (348_110_000 as Weight) - // Standard Error: 136_000 - .saturating_add((81_086_000 as Weight).saturating_mul(c as Weight)) + (169_561_000 as Weight) + // Standard Error: 56_000 + .saturating_add((60_037_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -201,11 +203,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (414_966_000 as Weight) - // Standard Error: 137_000 - .saturating_add((198_330_000 as Weight).saturating_mul(c as Weight)) + (169_885_000 as Weight) + // Standard Error: 127_000 + .saturating_add((170_680_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 8_000 - .saturating_add((2_180_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_788_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -216,9 +218,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (201_465_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_993_000 as Weight).saturating_mul(s as Weight)) + (150_265_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_722_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -227,7 +229,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (154_139_000 as Weight) + (114_784_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -235,9 +237,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (69_640_000 as Weight) - // Standard Error: 93_000 - .saturating_add((89_969_000 as Weight).saturating_mul(c as Weight)) + (48_072_000 as Weight) + // Standard Error: 36_000 + .saturating_add((83_578_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -245,7 +247,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (31_567_000 as Weight) + (24_739_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -254,9 +256,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (405_395_000 as Weight) - // Standard Error: 167_000 - .saturating_add((79_867_000 as Weight).saturating_mul(r as Weight)) + (174_123_000 as Weight) + // Standard Error: 127_000 + .saturating_add((56_078_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -265,9 +267,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (405_173_000 as Weight) - // Standard Error: 152_000 - .saturating_add((79_619_000 as Weight).saturating_mul(r as Weight)) + (180_168_000 as Weight) + // Standard Error: 122_000 + .saturating_add((56_154_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -276,9 +278,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (406_537_000 as Weight) - // Standard Error: 148_000 - .saturating_add((78_129_000 as Weight).saturating_mul(r as Weight)) + (179_464_000 as Weight) + // Standard Error: 96_000 + .saturating_add((55_350_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -287,9 +289,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (416_289_000 as Weight) - // Standard Error: 165_000 - .saturating_add((218_401_000 as Weight).saturating_mul(r as Weight)) + (181_031_000 as Weight) + // Standard Error: 154_000 + .saturating_add((149_508_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -298,9 +300,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (408_205_000 as Weight) - // Standard Error: 154_000 - .saturating_add((79_563_000 as Weight).saturating_mul(r as Weight)) + (178_709_000 as Weight) + // Standard Error: 107_000 + .saturating_add((56_326_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -309,9 +311,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (408_124_000 as Weight) - // Standard Error: 149_000 - .saturating_add((79_032_000 as Weight).saturating_mul(r as Weight)) + (175_715_000 as Weight) + // Standard Error: 116_000 + .saturating_add((56_755_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -320,9 +322,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (406_141_000 as Weight) - // Standard Error: 150_000 - .saturating_add((78_992_000 as Weight).saturating_mul(r as Weight)) + (178_552_000 as Weight) + // Standard Error: 121_000 + .saturating_add((55_756_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -331,9 +333,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (418_112_000 as Weight) - // Standard Error: 155_000 - .saturating_add((77_902_000 as Weight).saturating_mul(r as Weight)) + (186_172_000 as Weight) + // Standard Error: 106_000 + .saturating_add((55_311_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -343,9 +345,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (411_683_000 as Weight) - // Standard Error: 173_000 - .saturating_add((205_824_000 as Weight).saturating_mul(r as Weight)) + (183_750_000 as Weight) + // Standard Error: 140_000 + .saturating_add((131_877_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -354,9 +356,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (132_178_000 as Weight) - // Standard Error: 84_000 - .saturating_add((38_233_000 as Weight).saturating_mul(r as Weight)) + (97_350_000 as Weight) + // Standard Error: 54_000 + .saturating_add((27_606_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -365,9 +367,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (405_685_000 as Weight) - // Standard Error: 142_000 - .saturating_add((72_826_000 as Weight).saturating_mul(r as Weight)) + (179_058_000 as Weight) + // Standard Error: 106_000 + .saturating_add((53_258_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -376,9 +378,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (490_336_000 as Weight) - // Standard Error: 7_000 - .saturating_add((38_070_000 as Weight).saturating_mul(n as Weight)) + (248_562_000 as Weight) + // Standard Error: 5_000 + .saturating_add((10_515_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -387,9 +389,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (384_543_000 as Weight) - // Standard Error: 105_000 - .saturating_add((15_793_000 as Weight).saturating_mul(r as Weight)) + (161_228_000 as Weight) + // Standard Error: 90_000 + .saturating_add((14_539_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -398,9 +400,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (399_205_000 as Weight) - // Standard Error: 1_000 - .saturating_add((637_000 as Weight).saturating_mul(n as Weight)) + (177_866_000 as Weight) + // Standard Error: 0 + .saturating_add((188_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -411,9 +413,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (396_375_000 as Weight) - // Standard Error: 3_023_000 - .saturating_add((79_797_000 as Weight).saturating_mul(r as Weight)) + (164_572_000 as Weight) + // Standard Error: 1_817_000 + .saturating_add((68_480_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -425,9 +427,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (390_550_000 as Weight) - // Standard Error: 290_000 - .saturating_add((245_730_000 as Weight).saturating_mul(r as Weight)) + (168_658_000 as Weight) + // Standard Error: 189_000 + .saturating_add((166_190_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -436,9 +438,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (408_011_000 as Weight) - // Standard Error: 273_000 - .saturating_add((406_522_000 as Weight).saturating_mul(r as Weight)) + (185_391_000 as Weight) + // Standard Error: 191_000 + .saturating_add((292_609_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -448,11 +450,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (890_741_000 as Weight) - // Standard Error: 2_072_000 - .saturating_add((382_953_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 408_000 - .saturating_add((162_320_000 as Weight).saturating_mul(n as Weight)) + (507_994_000 as Weight) + // Standard Error: 1_569_000 + .saturating_add((276_852_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 309_000 + .saturating_add((79_461_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -463,17 +465,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (153_163_000 as Weight) - // Standard Error: 137_000 - .saturating_add((59_081_000 as Weight).saturating_mul(r as Weight)) + (99_048_000 as Weight) + // Standard Error: 87_000 + .saturating_add((46_088_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (459_368_000 as Weight) - // Standard Error: 560_000 - .saturating_add((330_190_000 as Weight).saturating_mul(r as Weight)) + (142_559_000 as Weight) + // Standard Error: 603_000 + .saturating_add((269_723_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -485,17 +487,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (727_394_000 as Weight) - // Standard Error: 247_000 - .saturating_add((73_350_000 as Weight).saturating_mul(n as Weight)) + (346_704_000 as Weight) + // Standard Error: 200_000 + .saturating_add((29_907_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (163_262_000 as Weight) - // Standard Error: 1_492_000 - .saturating_add((799_087_000 as Weight).saturating_mul(r as Weight)) + (0 as Weight) + // Standard Error: 1_963_000 + .saturating_add((746_581_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -503,18 +505,18 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (288_728_000 as Weight) - // Standard Error: 752_000 - .saturating_add((434_780_000 as Weight).saturating_mul(r as Weight)) + (69_873_000 as Weight) + // Standard Error: 722_000 + .saturating_add((338_292_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (209_606_000 as Weight) - // Standard Error: 1_137_000 - .saturating_add((680_187_000 as Weight).saturating_mul(r as Weight)) + (0 as Weight) + // Standard Error: 1_169_000 + .saturating_add((480_500_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -525,17 +527,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (619_600_000 as Weight) - // Standard Error: 207_000 - .saturating_add((111_030_000 as Weight).saturating_mul(n as Weight)) + (327_625_000 as Weight) + // Standard Error: 146_000 + .saturating_add((55_028_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (279_528_000 as Weight) - // Standard Error: 932_000 - .saturating_add((541_965_000 as Weight).saturating_mul(r as Weight)) + (41_931_000 as Weight) + // Standard Error: 933_000 + .saturating_add((433_619_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -543,9 +545,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (985_732_000 as Weight) - // Standard Error: 446_000 - .saturating_add((123_295_000 as Weight).saturating_mul(n as Weight)) + (639_259_000 as Weight) + // Standard Error: 365_000 + .saturating_add((64_588_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } @@ -554,9 +556,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (284_785_000 as Weight) - // Standard Error: 1_479_000 - .saturating_add((2_527_544_000 as Weight).saturating_mul(r as Weight)) + (71_335_000 as Weight) + // Standard Error: 1_489_000 + .saturating_add((1_765_321_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -568,8 +570,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 5_742_000 - .saturating_add((37_993_391_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 9_243_000 + .saturating_add((16_121_990_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -580,13 +582,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (37_404_660_000 as Weight) - // Standard Error: 92_661_000 - .saturating_add((2_486_257_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 33_000 - .saturating_add((63_001_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 35_000 - .saturating_add((101_347_000 as Weight).saturating_mul(o as Weight)) + (15_978_164_000 as Weight) + // Standard Error: 57_271_000 + .saturating_add((1_179_479_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 20_000 + .saturating_add((17_389_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 21_000 + .saturating_add((28_660_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -600,8 +602,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 119_281_000 - .saturating_add((47_113_525_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 115_056_000 + .saturating_add((23_312_565_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -614,13 +616,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (41_157_901_000 as Weight) - // Standard Error: 147_000 - .saturating_add((64_877_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 147_000 - .saturating_add((102_420_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 147_000 - .saturating_add((201_587_000 as Weight).saturating_mul(s as Weight)) + (18_724_034_000 as Weight) + // Standard Error: 66_000 + .saturating_add((18_363_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 66_000 + .saturating_add((29_093_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 66_000 + .saturating_add((158_645_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().writes(206 as Weight)) } @@ -629,9 +631,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (402_224_000 as Weight) - // Standard Error: 166_000 - .saturating_add((103_985_000 as Weight).saturating_mul(r as Weight)) + (179_769_000 as Weight) + // Standard Error: 121_000 + .saturating_add((80_706_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -640,9 +642,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (663_731_000 as Weight) - // Standard Error: 42_000 - .saturating_add((505_157_000 as Weight).saturating_mul(n as Weight)) + (279_632_000 as Weight) + // Standard Error: 17_000 + .saturating_add((372_618_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -651,9 +653,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (402_638_000 as Weight) - // Standard Error: 165_000 - .saturating_add((117_589_000 as Weight).saturating_mul(r as Weight)) + (182_040_000 as Weight) + // Standard Error: 119_000 + .saturating_add((88_916_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -662,9 +664,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (491_978_000 as Weight) - // Standard Error: 23_000 - .saturating_add((363_687_000 as Weight).saturating_mul(n as Weight)) + (253_225_000 as Weight) + // Standard Error: 16_000 + .saturating_add((247_883_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -673,9 +675,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (402_254_000 as Weight) - // Standard Error: 154_000 - .saturating_add((86_403_000 as Weight).saturating_mul(r as Weight)) + (179_945_000 as Weight) + // Standard Error: 96_000 + .saturating_add((68_362_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -684,9 +686,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (476_405_000 as Weight) - // Standard Error: 18_000 - .saturating_add((163_921_000 as Weight).saturating_mul(n as Weight)) + (191_286_000 as Weight) + // Standard Error: 38_000 + .saturating_add((121_358_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -695,9 +697,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (399_949_000 as Weight) - // Standard Error: 142_000 - .saturating_add((85_448_000 as Weight).saturating_mul(r as Weight)) + (179_381_000 as Weight) + // Standard Error: 101_000 + .saturating_add((68_158_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -706,9 +708,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (475_437_000 as Weight) - // Standard Error: 15_000 - .saturating_add((163_921_000 as Weight).saturating_mul(n as Weight)) + (135_478_000 as Weight) + // Standard Error: 41_000 + .saturating_add((121_422_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -717,266 +719,266 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (373_575_000 as Weight) - // Standard Error: 1_639_000 - .saturating_add((15_530_027_000 as Weight).saturating_mul(r as Weight)) + (123_468_000 as Weight) + // Standard Error: 1_017_000 + .saturating_add((15_542_677_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (52_763_000 as Weight) + (52_702_000 as Weight) // Standard Error: 12_000 - .saturating_add((857_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((844_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (47_313_000 as Weight) + (47_295_000 as Weight) // Standard Error: 10_000 - .saturating_add((2_935_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_045_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (47_147_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_995_000 as Weight).saturating_mul(r as Weight)) + (46_353_000 as Weight) + // Standard Error: 9_000 + .saturating_add((3_047_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (50_124_000 as Weight) + (49_811_000 as Weight) // Standard Error: 11_000 - .saturating_add((2_421_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_408_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (47_288_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_523_000 as Weight).saturating_mul(r as Weight)) + (47_054_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_504_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (50_198_000 as Weight) + (49_912_000 as Weight) // Standard Error: 16_000 - .saturating_add((1_473_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_460_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (44_008_000 as Weight) + (43_860_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_174_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_150_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (37_602_000 as Weight) + (37_009_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_820_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_762_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (46_232_000 as Weight) + (45_776_000 as Weight) // Standard Error: 3_000 .saturating_add((17_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (40_148_000 as Weight) - // Standard Error: 22_000 - .saturating_add((20_585_000 as Weight).saturating_mul(r as Weight)) + (39_611_000 as Weight) + // Standard Error: 17_000 + .saturating_add((20_805_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (43_948_000 as Weight) - // Standard Error: 31_000 - .saturating_add((30_226_000 as Weight).saturating_mul(r as Weight)) + (45_523_000 as Weight) + // Standard Error: 27_000 + .saturating_add((31_622_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (78_722_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_199_000 as Weight).saturating_mul(p as Weight)) + (79_764_000 as Weight) + // Standard Error: 6_000 + .saturating_add((1_198_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (48_083_000 as Weight) - // Standard Error: 12_000 - .saturating_add((805_000 as Weight).saturating_mul(r as Weight)) + (46_510_000 as Weight) + // Standard Error: 11_000 + .saturating_add((810_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (47_710_000 as Weight) + (46_567_000 as Weight) // Standard Error: 11_000 - .saturating_add((843_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((833_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (44_785_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_466_000 as Weight).saturating_mul(r as Weight)) + (43_439_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_463_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (50_106_000 as Weight) - // Standard Error: 20_000 - .saturating_add((1_641_000 as Weight).saturating_mul(r as Weight)) + (46_201_000 as Weight) + // Standard Error: 19_000 + .saturating_add((1_635_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (47_058_000 as Weight) + (42_639_000 as Weight) // Standard Error: 18_000 - .saturating_add((1_707_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_652_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (51_494_000 as Weight) - // Standard Error: 15_000 - .saturating_add((925_000 as Weight).saturating_mul(r as Weight)) + (51_159_000 as Weight) + // Standard Error: 14_000 + .saturating_add((917_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (36_983_000 as Weight) - // Standard Error: 3_602_000 - .saturating_add((634_259_000 as Weight).saturating_mul(r as Weight)) + (36_462_000 as Weight) + // Standard Error: 867_000 + .saturating_add((187_724_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (60_711_000 as Weight) - // Standard Error: 22_000 - .saturating_add((1_157_000 as Weight).saturating_mul(r as Weight)) + (53_776_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_307_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (53_908_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_305_000 as Weight).saturating_mul(r as Weight)) + (53_674_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_304_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (53_939_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_314_000 as Weight).saturating_mul(r as Weight)) + (53_654_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_299_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (54_086_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_309_000 as Weight).saturating_mul(r as Weight)) + (53_493_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_299_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (43_845_000 as Weight) + (43_373_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_493_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_492_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (43_518_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_501_000 as Weight).saturating_mul(r as Weight)) + (43_222_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (53_912_000 as Weight) + (53_706_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_302_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_292_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (49_594_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_890_000 as Weight).saturating_mul(r as Weight)) + (48_994_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (49_659_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) + (49_464_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_876_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (49_401_000 as Weight) + (49_194_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_884_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (49_880_000 as Weight) + (49_291_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_883_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (49_466_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) + (49_227_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_886_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (49_514_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) + (49_219_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (49_588_000 as Weight) + (49_263_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_898_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (49_589_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) + (49_251_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (49_685_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_892_000 as Weight).saturating_mul(r as Weight)) + (49_257_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (49_601_000 as Weight) + (49_219_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (49_430_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) + (49_221_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (49_533_000 as Weight) + (48_936_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_893_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (49_766_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) + (49_266_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (49_315_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_552_000 as Weight).saturating_mul(r as Weight)) + (49_246_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_565_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (49_786_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_203_000 as Weight).saturating_mul(r as Weight)) + (49_181_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_211_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (49_651_000 as Weight) + (49_337_000 as Weight) // Standard Error: 11_000 - .saturating_add((2_461_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_525_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (49_747_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_196_000 as Weight).saturating_mul(r as Weight)) + (49_387_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_241_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (49_719_000 as Weight) + (49_137_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_892_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (49_463_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_896_000 as Weight).saturating_mul(r as Weight)) + (49_366_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (49_379_000 as Weight) + (49_143_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_903_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_912_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (49_404_000 as Weight) + (49_195_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (49_498_000 as Weight) - // Standard Error: 10_000 + (49_228_000 as Weight) + // Standard Error: 11_000 .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (49_541_000 as Weight) + (49_279_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_897_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (49_452_000 as Weight) + (49_091_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (49_350_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) + (49_436_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_883_000 as Weight).saturating_mul(r as Weight)) } } @@ -984,32 +986,32 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (2_286_000 as Weight) + (1_585_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 3_000 - .saturating_add((2_219_000 as Weight).saturating_mul(k as Weight)) + (7_902_000 as Weight) + // Standard Error: 0 + .saturating_add((751_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (95_627_000 as Weight) - // Standard Error: 2_000 - .saturating_add((242_000 as Weight).saturating_mul(q as Weight)) + (31_473_000 as Weight) + // Standard Error: 1_000 + .saturating_add((104_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (17_037_000 as Weight) - // Standard Error: 98_000 - .saturating_add((88_875_000 as Weight).saturating_mul(c as Weight)) + (15_462_000 as Weight) + // Standard Error: 35_000 + .saturating_add((81_710_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1018,9 +1020,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (348_110_000 as Weight) - // Standard Error: 136_000 - .saturating_add((81_086_000 as Weight).saturating_mul(c as Weight)) + (169_561_000 as Weight) + // Standard Error: 56_000 + .saturating_add((60_037_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1032,11 +1034,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (414_966_000 as Weight) - // Standard Error: 137_000 - .saturating_add((198_330_000 as Weight).saturating_mul(c as Weight)) + (169_885_000 as Weight) + // Standard Error: 127_000 + .saturating_add((170_680_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 8_000 - .saturating_add((2_180_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_788_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1047,9 +1049,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (201_465_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_993_000 as Weight).saturating_mul(s as Weight)) + (150_265_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_722_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1058,7 +1060,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (154_139_000 as Weight) + (114_784_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1066,9 +1068,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (69_640_000 as Weight) - // Standard Error: 93_000 - .saturating_add((89_969_000 as Weight).saturating_mul(c as Weight)) + (48_072_000 as Weight) + // Standard Error: 36_000 + .saturating_add((83_578_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1076,7 +1078,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (31_567_000 as Weight) + (24_739_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1085,9 +1087,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (405_395_000 as Weight) - // Standard Error: 167_000 - .saturating_add((79_867_000 as Weight).saturating_mul(r as Weight)) + (174_123_000 as Weight) + // Standard Error: 127_000 + .saturating_add((56_078_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1096,9 +1098,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (405_173_000 as Weight) - // Standard Error: 152_000 - .saturating_add((79_619_000 as Weight).saturating_mul(r as Weight)) + (180_168_000 as Weight) + // Standard Error: 122_000 + .saturating_add((56_154_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1107,9 +1109,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (406_537_000 as Weight) - // Standard Error: 148_000 - .saturating_add((78_129_000 as Weight).saturating_mul(r as Weight)) + (179_464_000 as Weight) + // Standard Error: 96_000 + .saturating_add((55_350_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1118,9 +1120,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (416_289_000 as Weight) - // Standard Error: 165_000 - .saturating_add((218_401_000 as Weight).saturating_mul(r as Weight)) + (181_031_000 as Weight) + // Standard Error: 154_000 + .saturating_add((149_508_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1129,9 +1131,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (408_205_000 as Weight) - // Standard Error: 154_000 - .saturating_add((79_563_000 as Weight).saturating_mul(r as Weight)) + (178_709_000 as Weight) + // Standard Error: 107_000 + .saturating_add((56_326_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1140,9 +1142,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (408_124_000 as Weight) - // Standard Error: 149_000 - .saturating_add((79_032_000 as Weight).saturating_mul(r as Weight)) + (175_715_000 as Weight) + // Standard Error: 116_000 + .saturating_add((56_755_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1151,9 +1153,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (406_141_000 as Weight) - // Standard Error: 150_000 - .saturating_add((78_992_000 as Weight).saturating_mul(r as Weight)) + (178_552_000 as Weight) + // Standard Error: 121_000 + .saturating_add((55_756_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1162,9 +1164,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (418_112_000 as Weight) - // Standard Error: 155_000 - .saturating_add((77_902_000 as Weight).saturating_mul(r as Weight)) + (186_172_000 as Weight) + // Standard Error: 106_000 + .saturating_add((55_311_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1174,9 +1176,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (411_683_000 as Weight) - // Standard Error: 173_000 - .saturating_add((205_824_000 as Weight).saturating_mul(r as Weight)) + (183_750_000 as Weight) + // Standard Error: 140_000 + .saturating_add((131_877_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1185,9 +1187,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (132_178_000 as Weight) - // Standard Error: 84_000 - .saturating_add((38_233_000 as Weight).saturating_mul(r as Weight)) + (97_350_000 as Weight) + // Standard Error: 54_000 + .saturating_add((27_606_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1196,9 +1198,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (405_685_000 as Weight) - // Standard Error: 142_000 - .saturating_add((72_826_000 as Weight).saturating_mul(r as Weight)) + (179_058_000 as Weight) + // Standard Error: 106_000 + .saturating_add((53_258_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1207,9 +1209,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (490_336_000 as Weight) - // Standard Error: 7_000 - .saturating_add((38_070_000 as Weight).saturating_mul(n as Weight)) + (248_562_000 as Weight) + // Standard Error: 5_000 + .saturating_add((10_515_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1218,9 +1220,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (384_543_000 as Weight) - // Standard Error: 105_000 - .saturating_add((15_793_000 as Weight).saturating_mul(r as Weight)) + (161_228_000 as Weight) + // Standard Error: 90_000 + .saturating_add((14_539_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1229,9 +1231,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (399_205_000 as Weight) - // Standard Error: 1_000 - .saturating_add((637_000 as Weight).saturating_mul(n as Weight)) + (177_866_000 as Weight) + // Standard Error: 0 + .saturating_add((188_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1242,9 +1244,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (396_375_000 as Weight) - // Standard Error: 3_023_000 - .saturating_add((79_797_000 as Weight).saturating_mul(r as Weight)) + (164_572_000 as Weight) + // Standard Error: 1_817_000 + .saturating_add((68_480_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1256,9 +1258,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (390_550_000 as Weight) - // Standard Error: 290_000 - .saturating_add((245_730_000 as Weight).saturating_mul(r as Weight)) + (168_658_000 as Weight) + // Standard Error: 189_000 + .saturating_add((166_190_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1267,9 +1269,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (408_011_000 as Weight) - // Standard Error: 273_000 - .saturating_add((406_522_000 as Weight).saturating_mul(r as Weight)) + (185_391_000 as Weight) + // Standard Error: 191_000 + .saturating_add((292_609_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1279,11 +1281,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (890_741_000 as Weight) - // Standard Error: 2_072_000 - .saturating_add((382_953_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 408_000 - .saturating_add((162_320_000 as Weight).saturating_mul(n as Weight)) + (507_994_000 as Weight) + // Standard Error: 1_569_000 + .saturating_add((276_852_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 309_000 + .saturating_add((79_461_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1294,17 +1296,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (153_163_000 as Weight) - // Standard Error: 137_000 - .saturating_add((59_081_000 as Weight).saturating_mul(r as Weight)) + (99_048_000 as Weight) + // Standard Error: 87_000 + .saturating_add((46_088_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (459_368_000 as Weight) - // Standard Error: 560_000 - .saturating_add((330_190_000 as Weight).saturating_mul(r as Weight)) + (142_559_000 as Weight) + // Standard Error: 603_000 + .saturating_add((269_723_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1316,17 +1318,17 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (727_394_000 as Weight) - // Standard Error: 247_000 - .saturating_add((73_350_000 as Weight).saturating_mul(n as Weight)) + (346_704_000 as Weight) + // Standard Error: 200_000 + .saturating_add((29_907_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (163_262_000 as Weight) - // Standard Error: 1_492_000 - .saturating_add((799_087_000 as Weight).saturating_mul(r as Weight)) + (0 as Weight) + // Standard Error: 1_963_000 + .saturating_add((746_581_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1334,18 +1336,18 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (288_728_000 as Weight) - // Standard Error: 752_000 - .saturating_add((434_780_000 as Weight).saturating_mul(r as Weight)) + (69_873_000 as Weight) + // Standard Error: 722_000 + .saturating_add((338_292_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (209_606_000 as Weight) - // Standard Error: 1_137_000 - .saturating_add((680_187_000 as Weight).saturating_mul(r as Weight)) + (0 as Weight) + // Standard Error: 1_169_000 + .saturating_add((480_500_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1356,17 +1358,17 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (619_600_000 as Weight) - // Standard Error: 207_000 - .saturating_add((111_030_000 as Weight).saturating_mul(n as Weight)) + (327_625_000 as Weight) + // Standard Error: 146_000 + .saturating_add((55_028_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (279_528_000 as Weight) - // Standard Error: 932_000 - .saturating_add((541_965_000 as Weight).saturating_mul(r as Weight)) + (41_931_000 as Weight) + // Standard Error: 933_000 + .saturating_add((433_619_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1374,9 +1376,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (985_732_000 as Weight) - // Standard Error: 446_000 - .saturating_add((123_295_000 as Weight).saturating_mul(n as Weight)) + (639_259_000 as Weight) + // Standard Error: 365_000 + .saturating_add((64_588_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } @@ -1385,9 +1387,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (284_785_000 as Weight) - // Standard Error: 1_479_000 - .saturating_add((2_527_544_000 as Weight).saturating_mul(r as Weight)) + (71_335_000 as Weight) + // Standard Error: 1_489_000 + .saturating_add((1_765_321_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1399,8 +1401,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 5_742_000 - .saturating_add((37_993_391_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 9_243_000 + .saturating_add((16_121_990_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1411,13 +1413,13 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (37_404_660_000 as Weight) - // Standard Error: 92_661_000 - .saturating_add((2_486_257_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 33_000 - .saturating_add((63_001_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 35_000 - .saturating_add((101_347_000 as Weight).saturating_mul(o as Weight)) + (15_978_164_000 as Weight) + // Standard Error: 57_271_000 + .saturating_add((1_179_479_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 20_000 + .saturating_add((17_389_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 21_000 + .saturating_add((28_660_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1431,8 +1433,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 119_281_000 - .saturating_add((47_113_525_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 115_056_000 + .saturating_add((23_312_565_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1445,13 +1447,13 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (41_157_901_000 as Weight) - // Standard Error: 147_000 - .saturating_add((64_877_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 147_000 - .saturating_add((102_420_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 147_000 - .saturating_add((201_587_000 as Weight).saturating_mul(s as Weight)) + (18_724_034_000 as Weight) + // Standard Error: 66_000 + .saturating_add((18_363_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 66_000 + .saturating_add((29_093_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 66_000 + .saturating_add((158_645_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().writes(206 as Weight)) } @@ -1460,9 +1462,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (402_224_000 as Weight) - // Standard Error: 166_000 - .saturating_add((103_985_000 as Weight).saturating_mul(r as Weight)) + (179_769_000 as Weight) + // Standard Error: 121_000 + .saturating_add((80_706_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1471,9 +1473,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (663_731_000 as Weight) - // Standard Error: 42_000 - .saturating_add((505_157_000 as Weight).saturating_mul(n as Weight)) + (279_632_000 as Weight) + // Standard Error: 17_000 + .saturating_add((372_618_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1482,9 +1484,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (402_638_000 as Weight) - // Standard Error: 165_000 - .saturating_add((117_589_000 as Weight).saturating_mul(r as Weight)) + (182_040_000 as Weight) + // Standard Error: 119_000 + .saturating_add((88_916_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1493,9 +1495,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (491_978_000 as Weight) - // Standard Error: 23_000 - .saturating_add((363_687_000 as Weight).saturating_mul(n as Weight)) + (253_225_000 as Weight) + // Standard Error: 16_000 + .saturating_add((247_883_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1504,9 +1506,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (402_254_000 as Weight) - // Standard Error: 154_000 - .saturating_add((86_403_000 as Weight).saturating_mul(r as Weight)) + (179_945_000 as Weight) + // Standard Error: 96_000 + .saturating_add((68_362_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1515,9 +1517,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (476_405_000 as Weight) - // Standard Error: 18_000 - .saturating_add((163_921_000 as Weight).saturating_mul(n as Weight)) + (191_286_000 as Weight) + // Standard Error: 38_000 + .saturating_add((121_358_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1526,9 +1528,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (399_949_000 as Weight) - // Standard Error: 142_000 - .saturating_add((85_448_000 as Weight).saturating_mul(r as Weight)) + (179_381_000 as Weight) + // Standard Error: 101_000 + .saturating_add((68_158_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1537,9 +1539,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (475_437_000 as Weight) - // Standard Error: 15_000 - .saturating_add((163_921_000 as Weight).saturating_mul(n as Weight)) + (135_478_000 as Weight) + // Standard Error: 41_000 + .saturating_add((121_422_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1548,265 +1550,265 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (373_575_000 as Weight) - // Standard Error: 1_639_000 - .saturating_add((15_530_027_000 as Weight).saturating_mul(r as Weight)) + (123_468_000 as Weight) + // Standard Error: 1_017_000 + .saturating_add((15_542_677_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (52_763_000 as Weight) + (52_702_000 as Weight) // Standard Error: 12_000 - .saturating_add((857_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((844_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (47_313_000 as Weight) + (47_295_000 as Weight) // Standard Error: 10_000 - .saturating_add((2_935_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_045_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (47_147_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_995_000 as Weight).saturating_mul(r as Weight)) + (46_353_000 as Weight) + // Standard Error: 9_000 + .saturating_add((3_047_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (50_124_000 as Weight) + (49_811_000 as Weight) // Standard Error: 11_000 - .saturating_add((2_421_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_408_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (47_288_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_523_000 as Weight).saturating_mul(r as Weight)) + (47_054_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_504_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (50_198_000 as Weight) + (49_912_000 as Weight) // Standard Error: 16_000 - .saturating_add((1_473_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_460_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (44_008_000 as Weight) + (43_860_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_174_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_150_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (37_602_000 as Weight) + (37_009_000 as Weight) // Standard Error: 16_000 - .saturating_add((2_820_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_762_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (46_232_000 as Weight) + (45_776_000 as Weight) // Standard Error: 3_000 .saturating_add((17_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (40_148_000 as Weight) - // Standard Error: 22_000 - .saturating_add((20_585_000 as Weight).saturating_mul(r as Weight)) + (39_611_000 as Weight) + // Standard Error: 17_000 + .saturating_add((20_805_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (43_948_000 as Weight) - // Standard Error: 31_000 - .saturating_add((30_226_000 as Weight).saturating_mul(r as Weight)) + (45_523_000 as Weight) + // Standard Error: 27_000 + .saturating_add((31_622_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (78_722_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_199_000 as Weight).saturating_mul(p as Weight)) + (79_764_000 as Weight) + // Standard Error: 6_000 + .saturating_add((1_198_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (48_083_000 as Weight) - // Standard Error: 12_000 - .saturating_add((805_000 as Weight).saturating_mul(r as Weight)) + (46_510_000 as Weight) + // Standard Error: 11_000 + .saturating_add((810_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (47_710_000 as Weight) + (46_567_000 as Weight) // Standard Error: 11_000 - .saturating_add((843_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((833_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (44_785_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_466_000 as Weight).saturating_mul(r as Weight)) + (43_439_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_463_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (50_106_000 as Weight) - // Standard Error: 20_000 - .saturating_add((1_641_000 as Weight).saturating_mul(r as Weight)) + (46_201_000 as Weight) + // Standard Error: 19_000 + .saturating_add((1_635_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (47_058_000 as Weight) + (42_639_000 as Weight) // Standard Error: 18_000 - .saturating_add((1_707_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_652_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (51_494_000 as Weight) - // Standard Error: 15_000 - .saturating_add((925_000 as Weight).saturating_mul(r as Weight)) + (51_159_000 as Weight) + // Standard Error: 14_000 + .saturating_add((917_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (36_983_000 as Weight) - // Standard Error: 3_602_000 - .saturating_add((634_259_000 as Weight).saturating_mul(r as Weight)) + (36_462_000 as Weight) + // Standard Error: 867_000 + .saturating_add((187_724_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (60_711_000 as Weight) - // Standard Error: 22_000 - .saturating_add((1_157_000 as Weight).saturating_mul(r as Weight)) + (53_776_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_307_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (53_908_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_305_000 as Weight).saturating_mul(r as Weight)) + (53_674_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_304_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (53_939_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_314_000 as Weight).saturating_mul(r as Weight)) + (53_654_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_299_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (54_086_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_309_000 as Weight).saturating_mul(r as Weight)) + (53_493_000 as Weight) + // Standard Error: 9_000 + .saturating_add((1_299_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (43_845_000 as Weight) + (43_373_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_493_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_492_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (43_518_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_501_000 as Weight).saturating_mul(r as Weight)) + (43_222_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (53_912_000 as Weight) + (53_706_000 as Weight) // Standard Error: 9_000 - .saturating_add((1_302_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_292_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (49_594_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_890_000 as Weight).saturating_mul(r as Weight)) + (48_994_000 as Weight) + // Standard Error: 10_000 + .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (49_659_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) + (49_464_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_876_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (49_401_000 as Weight) + (49_194_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_884_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (49_880_000 as Weight) + (49_291_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_883_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (49_466_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) + (49_227_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_886_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (49_514_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) + (49_219_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (49_588_000 as Weight) + (49_263_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_898_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (49_589_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) + (49_251_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (49_685_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_892_000 as Weight).saturating_mul(r as Weight)) + (49_257_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (49_601_000 as Weight) + (49_219_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (49_430_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_894_000 as Weight).saturating_mul(r as Weight)) + (49_221_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (49_533_000 as Weight) + (48_936_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_893_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (49_766_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) + (49_266_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (49_315_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_552_000 as Weight).saturating_mul(r as Weight)) + (49_246_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_565_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (49_786_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_203_000 as Weight).saturating_mul(r as Weight)) + (49_181_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_211_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (49_651_000 as Weight) + (49_337_000 as Weight) // Standard Error: 11_000 - .saturating_add((2_461_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_525_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (49_747_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_196_000 as Weight).saturating_mul(r as Weight)) + (49_387_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_241_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (49_719_000 as Weight) + (49_137_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_892_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (49_463_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_896_000 as Weight).saturating_mul(r as Weight)) + (49_366_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (49_379_000 as Weight) + (49_143_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_903_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_912_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (49_404_000 as Weight) + (49_195_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (49_498_000 as Weight) - // Standard Error: 10_000 + (49_228_000 as Weight) + // Standard Error: 11_000 .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (49_541_000 as Weight) + (49_279_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_897_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (49_452_000 as Weight) + (49_091_000 as Weight) // Standard Error: 11_000 - .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (49_350_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_902_000 as Weight).saturating_mul(r as Weight)) + (49_436_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_883_000 as Weight).saturating_mul(r as Weight)) } } diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index aa8e68f57053c..22743124253b4 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-09-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/democracy/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -81,15 +82,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (67_388_000 as Weight) + (42_599_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (41_157_000 as Weight) - // Standard Error: 0 - .saturating_add((157_000 as Weight).saturating_mul(s as Weight)) + (25_521_000 as Weight) + // Standard Error: 1_000 + .saturating_add((171_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -97,9 +98,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (46_406_000 as Weight) + (34_035_000 as Weight) // Standard Error: 1_000 - .saturating_add((170_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -107,16 +108,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (46_071_000 as Weight) + (33_910_000 as Weight) // Standard Error: 1_000 - .saturating_add((166_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((147_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (27_699_000 as Weight) + (14_874_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -127,16 +128,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (82_703_000 as Weight) - // Standard Error: 4_000 - .saturating_add((500_000 as Weight).saturating_mul(p as Weight)) + (49_557_000 as Weight) + // Standard Error: 3_000 + .saturating_add((267_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (13_747_000 as Weight) + (7_540_000 as Weight) // Standard Error: 0 .saturating_add((76_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -144,28 +145,28 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (3_070_000 as Weight) + (1_272_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (3_080_000 as Weight) + (1_274_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (29_129_000 as Weight) + (15_216_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (30_105_000 as Weight) + (16_713_000 as Weight) // Standard Error: 0 - .saturating_add((104_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((92_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -173,56 +174,58 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (55_228_000 as Weight) - // Standard Error: 1_000 - .saturating_add((457_000 as Weight).saturating_mul(p as Weight)) + (37_990_000 as Weight) + // Standard Error: 2_000 + .saturating_add((259_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (17_319_000 as Weight) + (9_756_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (29_738_000 as Weight) + (19_408_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_153_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((650_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - // Storage: Democracy LowestUnbaked (r:1 w:0) + // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (2_165_000 as Weight) + (2_134_000 as Weight) // Standard Error: 3_000 - .saturating_add((5_577_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_041_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: Democracy LowestUnbaked (r:1 w:0) + // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy LastTabledWasExternal (r:1 w:0) // Storage: Democracy NextExternal (r:1 w:0) // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - (9_396_000 as Weight) - // Standard Error: 4_000 - .saturating_add((5_604_000 as Weight).saturating_mul(r as Weight)) + (6_357_000 as Weight) + // Standard Error: 3_000 + .saturating_add((3_054_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy VotingOf (r:3 w:3) // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (57_783_000 as Weight) - // Standard Error: 4_000 - .saturating_add((7_623_000 as Weight).saturating_mul(r as Weight)) + (30_822_000 as Weight) + // Standard Error: 3_000 + .saturating_add((3_826_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(4 as Weight)) @@ -231,9 +234,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (26_027_000 as Weight) - // Standard Error: 4_000 - .saturating_add((7_593_000 as Weight).saturating_mul(r as Weight)) + (15_307_000 as Weight) + // Standard Error: 3_000 + .saturating_add((3_827_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -241,12 +244,12 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (2_780_000 as Weight) + (1_624_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (46_416_000 as Weight) + (22_731_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -254,7 +257,7 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (29_735_000 as Weight) + (15_518_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -263,7 +266,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (41_276_000 as Weight) + (23_749_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -273,9 +276,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (40_348_000 as Weight) + (21_818_000 as Weight) // Standard Error: 1_000 - .saturating_add((60_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((66_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -283,27 +286,27 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (37_475_000 as Weight) + (21_491_000 as Weight) // Standard Error: 1_000 - .saturating_add((151_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((121_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (19_970_000 as Weight) + (11_767_000 as Weight) // Standard Error: 1_000 - .saturating_add((153_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((115_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (20_094_000 as Weight) + (11_959_000 as Weight) // Standard Error: 1_000 - .saturating_add((157_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((111_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -316,15 +319,15 @@ impl WeightInfo for () { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (67_388_000 as Weight) + (42_599_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (41_157_000 as Weight) - // Standard Error: 0 - .saturating_add((157_000 as Weight).saturating_mul(s as Weight)) + (25_521_000 as Weight) + // Standard Error: 1_000 + .saturating_add((171_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -332,9 +335,9 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (46_406_000 as Weight) + (34_035_000 as Weight) // Standard Error: 1_000 - .saturating_add((170_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -342,16 +345,16 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (46_071_000 as Weight) + (33_910_000 as Weight) // Standard Error: 1_000 - .saturating_add((166_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((147_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (27_699_000 as Weight) + (14_874_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -362,16 +365,16 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (82_703_000 as Weight) - // Standard Error: 4_000 - .saturating_add((500_000 as Weight).saturating_mul(p as Weight)) + (49_557_000 as Weight) + // Standard Error: 3_000 + .saturating_add((267_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (13_747_000 as Weight) + (7_540_000 as Weight) // Standard Error: 0 .saturating_add((76_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -379,28 +382,28 @@ impl WeightInfo for () { } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (3_070_000 as Weight) + (1_272_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (3_080_000 as Weight) + (1_274_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (29_129_000 as Weight) + (15_216_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (30_105_000 as Weight) + (16_713_000 as Weight) // Standard Error: 0 - .saturating_add((104_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((92_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -408,56 +411,58 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (55_228_000 as Weight) - // Standard Error: 1_000 - .saturating_add((457_000 as Weight).saturating_mul(p as Weight)) + (37_990_000 as Weight) + // Standard Error: 2_000 + .saturating_add((259_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (17_319_000 as Weight) + (9_756_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (29_738_000 as Weight) + (19_408_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_153_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((650_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } - // Storage: Democracy LowestUnbaked (r:1 w:0) + // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (2_165_000 as Weight) + (2_134_000 as Weight) // Standard Error: 3_000 - .saturating_add((5_577_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_041_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: Democracy LowestUnbaked (r:1 w:0) + // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy LastTabledWasExternal (r:1 w:0) // Storage: Democracy NextExternal (r:1 w:0) // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - (9_396_000 as Weight) - // Standard Error: 4_000 - .saturating_add((5_604_000 as Weight).saturating_mul(r as Weight)) + (6_357_000 as Weight) + // Standard Error: 3_000 + .saturating_add((3_054_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy VotingOf (r:3 w:3) // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (57_783_000 as Weight) - // Standard Error: 4_000 - .saturating_add((7_623_000 as Weight).saturating_mul(r as Weight)) + (30_822_000 as Weight) + // Standard Error: 3_000 + .saturating_add((3_826_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) @@ -466,9 +471,9 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (26_027_000 as Weight) - // Standard Error: 4_000 - .saturating_add((7_593_000 as Weight).saturating_mul(r as Weight)) + (15_307_000 as Weight) + // Standard Error: 3_000 + .saturating_add((3_827_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -476,12 +481,12 @@ impl WeightInfo for () { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (2_780_000 as Weight) + (1_624_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (46_416_000 as Weight) + (22_731_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -489,7 +494,7 @@ impl WeightInfo for () { } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (29_735_000 as Weight) + (15_518_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -498,7 +503,7 @@ impl WeightInfo for () { // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (41_276_000 as Weight) + (23_749_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -508,9 +513,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (40_348_000 as Weight) + (21_818_000 as Weight) // Standard Error: 1_000 - .saturating_add((60_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((66_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -518,27 +523,27 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (37_475_000 as Weight) + (21_491_000 as Weight) // Standard Error: 1_000 - .saturating_add((151_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((121_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (19_970_000 as Weight) + (11_767_000 as Weight) // Standard Error: 1_000 - .saturating_add((153_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((115_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (20_094_000 as Weight) + (11_959_000 as Weight) // Standard Error: 1_000 - .saturating_add((157_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((111_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 7bb3303cba2ef..8e627b246d376 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_election_provider_multi_phase //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-09-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/optimized/substrate // benchmark // --chain=dev // --steps=50 @@ -32,9 +32,10 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/election-provider-multi-phase/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --output=./weights-optimized/frame/election-provider-multi-phase/src//weights.rs +// --template=.maintain/frame-weight-template.hbs +// --header=HEADER-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -69,33 +70,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (22_784_000 as Weight) + (12_360_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (32_763_000 as Weight) + (12_981_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (29_117_000 as Weight) + (12_684_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (48_996_000 as Weight) + (27_272_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (32_508_000 as Weight) + (20_798_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -103,11 +104,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (96_001_000 as Weight) + (13_760_000 as Weight) // Standard Error: 1_000 - .saturating_add((307_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 2_000 - .saturating_add((133_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((201_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 3_000 + .saturating_add((49_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -120,11 +121,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (100_505_000 as Weight) - // Standard Error: 6_000 - .saturating_add((1_665_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 10_000 - .saturating_add((443_000 as Weight).saturating_mul(d as Weight)) + (108_461_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_318_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 5_000 + .saturating_add((194_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -135,9 +136,9 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit(c: u32, ) -> Weight { - (74_088_000 as Weight) - // Standard Error: 59_000 - .saturating_add((187_000 as Weight).saturating_mul(c as Weight)) + (39_721_000 as Weight) + // Standard Error: 24_000 + .saturating_add((298_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -150,14 +151,14 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 5_000 - .saturating_add((1_970_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 10_000 - .saturating_add((173_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 18_000 - .saturating_add((9_783_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 27_000 - .saturating_add((2_224_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 4_000 + .saturating_add((1_612_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 8_000 + .saturating_add((105_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 13_000 + .saturating_add((7_024_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 20_000 + .saturating_add((1_361_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -167,14 +168,14 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_000 - .saturating_add((1_910_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 7_000 - .saturating_add((111_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 2_000 + .saturating_add((1_639_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 5_000 + .saturating_add((138_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 8_000 + .saturating_add((5_665_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 13_000 - .saturating_add((7_741_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 19_000 - .saturating_add((1_844_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((980_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) } } @@ -190,33 +191,33 @@ impl WeightInfo for () { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (22_784_000 as Weight) + (12_360_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (32_763_000 as Weight) + (12_981_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (29_117_000 as Weight) + (12_684_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (48_996_000 as Weight) + (27_272_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (32_508_000 as Weight) + (20_798_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -224,11 +225,11 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (96_001_000 as Weight) + (13_760_000 as Weight) // Standard Error: 1_000 - .saturating_add((307_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 2_000 - .saturating_add((133_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((201_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 3_000 + .saturating_add((49_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -241,11 +242,11 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (100_505_000 as Weight) - // Standard Error: 6_000 - .saturating_add((1_665_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 10_000 - .saturating_add((443_000 as Weight).saturating_mul(d as Weight)) + (108_461_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_318_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 5_000 + .saturating_add((194_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -256,9 +257,9 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit(c: u32, ) -> Weight { - (74_088_000 as Weight) - // Standard Error: 59_000 - .saturating_add((187_000 as Weight).saturating_mul(c as Weight)) + (39_721_000 as Weight) + // Standard Error: 24_000 + .saturating_add((298_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -271,14 +272,14 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 5_000 - .saturating_add((1_970_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 10_000 - .saturating_add((173_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 18_000 - .saturating_add((9_783_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 27_000 - .saturating_add((2_224_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 4_000 + .saturating_add((1_612_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 8_000 + .saturating_add((105_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 13_000 + .saturating_add((7_024_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 20_000 + .saturating_add((1_361_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -288,14 +289,14 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_000 - .saturating_add((1_910_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 7_000 - .saturating_add((111_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 2_000 + .saturating_add((1_639_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 5_000 + .saturating_add((138_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 8_000 + .saturating_add((5_665_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 13_000 - .saturating_add((7_741_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 19_000 - .saturating_add((1_844_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((980_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) } } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 0bfc3d2ea87a7..57cb1b718fb7b 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/optimized/substrate // benchmark // --chain=dev // --steps=50 @@ -32,9 +32,10 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/elections-phragmen/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --output=./weights-optimized/frame/elections-phragmen/src//weights.rs +// --template=.maintain/frame-weight-template.hbs +// --header=HEADER-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -53,8 +54,8 @@ pub trait WeightInfo { fn renounce_candidacy_candidate(c: u32, ) -> Weight; fn renounce_candidacy_members() -> Weight; fn renounce_candidacy_runners_up() -> Weight; - fn remove_member_with_replacement() -> Weight; fn remove_member_without_replacement() -> Weight; + fn remove_member_with_replacement() -> Weight; fn remove_member_wrong_refund() -> Weight; fn clean_defunct_voters(v: u32, d: u32, ) -> Weight; fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight; @@ -69,9 +70,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_equal(v: u32, ) -> Weight { - (42_509_000 as Weight) + (24_231_000 as Weight) // Standard Error: 4_000 - .saturating_add((372_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((305_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -81,9 +82,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_more(v: u32, ) -> Weight { - (65_311_000 as Weight) + (37_524_000 as Weight) // Standard Error: 6_000 - .saturating_add((419_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((285_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -93,16 +94,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_less(v: u32, ) -> Weight { - (65_444_000 as Weight) - // Standard Error: 5_000 - .saturating_add((376_000 as Weight).saturating_mul(v as Weight)) + (37_350_000 as Weight) + // Standard Error: 7_000 + .saturating_add((311_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (61_585_000 as Weight) + (35_119_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -110,53 +111,54 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) fn submit_candidacy(c: u32, ) -> Weight { - (53_333_000 as Weight) + (36_110_000 as Weight) // Standard Error: 1_000 - .saturating_add((267_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((193_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (49_128_000 as Weight) + (30_976_000 as Weight) // Standard Error: 1_000 - .saturating_add((144_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((129_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Elections Members (r:1 w:1) // Storage: Elections RunnersUp (r:1 w:1) - // Storage: Instance1Collective Prime (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:0) - // Storage: Instance1Collective Members (r:0 w:1) + // Storage: Council Prime (r:1 w:1) + // Storage: Council Proposals (r:1 w:0) + // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (70_685_000 as Weight) + (44_456_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (49_766_000 as Weight) + (31_990_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Benchmark Override (r:0 w:0) + fn remove_member_without_replacement() -> Weight { + (2_000_000_000_000 as Weight) + } // Storage: Elections RunnersUp (r:1 w:1) // Storage: Elections Members (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: Instance1Collective Prime (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:0) - // Storage: Instance1Collective Members (r:0 w:1) + // Storage: Council Prime (r:1 w:1) + // Storage: Council Proposals (r:1 w:0) + // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (76_153_000 as Weight) + (51_221_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } - fn remove_member_without_replacement() -> Weight { - T::BlockWeights::get().max_block - } // Storage: Elections RunnersUp (r:1 w:0) fn remove_member_wrong_refund() -> Weight { - (6_697_000 as Weight) + (4_773_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Elections Voting (r:251 w:250) @@ -167,8 +169,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:250 w:250) fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 60_000 - .saturating_add((107_467_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 31_000 + .saturating_add((51_744_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -177,19 +179,19 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Members (r:1 w:1) // Storage: Elections RunnersUp (r:1 w:1) // Storage: Elections Voting (r:502 w:0) - // Storage: Instance1Collective Proposals (r:1 w:0) + // Storage: Council Proposals (r:1 w:0) // Storage: Elections ElectionRounds (r:1 w:1) - // Storage: Instance1Collective Members (r:0 w:1) - // Storage: Instance1Collective Prime (r:0 w:1) + // Storage: Council Members (r:0 w:1) + // Storage: Council Prime (r:0 w:1) // Storage: System Account (r:2 w:2) fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_846_000 - .saturating_add((39_843_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 768_000 - .saturating_add((60_623_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 52_000 - .saturating_add((3_884_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 1_744_000 + .saturating_add((29_677_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 725_000 + .saturating_add((51_480_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 49_000 + .saturating_add((3_491_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) @@ -204,9 +206,9 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_equal(v: u32, ) -> Weight { - (42_509_000 as Weight) + (24_231_000 as Weight) // Standard Error: 4_000 - .saturating_add((372_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((305_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -216,9 +218,9 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_more(v: u32, ) -> Weight { - (65_311_000 as Weight) + (37_524_000 as Weight) // Standard Error: 6_000 - .saturating_add((419_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((285_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -228,16 +230,16 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_less(v: u32, ) -> Weight { - (65_444_000 as Weight) - // Standard Error: 5_000 - .saturating_add((376_000 as Weight).saturating_mul(v as Weight)) + (37_350_000 as Weight) + // Standard Error: 7_000 + .saturating_add((311_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (61_585_000 as Weight) + (35_119_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -245,55 +247,54 @@ impl WeightInfo for () { // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) fn submit_candidacy(c: u32, ) -> Weight { - (53_333_000 as Weight) + (36_110_000 as Weight) // Standard Error: 1_000 - .saturating_add((267_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((193_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (49_128_000 as Weight) + (30_976_000 as Weight) // Standard Error: 1_000 - .saturating_add((144_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((129_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Elections Members (r:1 w:1) // Storage: Elections RunnersUp (r:1 w:1) - // Storage: Instance1Collective Prime (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:0) - // Storage: Instance1Collective Members (r:0 w:1) + // Storage: Council Prime (r:1 w:1) + // Storage: Council Proposals (r:1 w:0) + // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (70_685_000 as Weight) + (44_456_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (49_766_000 as Weight) + (31_990_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: Benchmark Override (r:0 w:0) + fn remove_member_without_replacement() -> Weight { + (2_000_000_000_000 as Weight) + } // Storage: Elections RunnersUp (r:1 w:1) // Storage: Elections Members (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: Instance1Collective Prime (r:1 w:1) - // Storage: Instance1Collective Proposals (r:1 w:0) - // Storage: Instance1Collective Members (r:0 w:1) + // Storage: Council Prime (r:1 w:1) + // Storage: Council Proposals (r:1 w:0) + // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (76_153_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) - } - fn remove_member_without_replacement() -> Weight { - (76_153_000 as Weight) + (51_221_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Elections RunnersUp (r:1 w:0) fn remove_member_wrong_refund() -> Weight { - (6_697_000 as Weight) + (4_773_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Elections Voting (r:251 w:250) @@ -304,8 +305,8 @@ impl WeightInfo for () { // Storage: System Account (r:250 w:250) fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 60_000 - .saturating_add((107_467_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 31_000 + .saturating_add((51_744_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -314,19 +315,19 @@ impl WeightInfo for () { // Storage: Elections Members (r:1 w:1) // Storage: Elections RunnersUp (r:1 w:1) // Storage: Elections Voting (r:502 w:0) - // Storage: Instance1Collective Proposals (r:1 w:0) + // Storage: Council Proposals (r:1 w:0) // Storage: Elections ElectionRounds (r:1 w:1) - // Storage: Instance1Collective Members (r:0 w:1) - // Storage: Instance1Collective Prime (r:0 w:1) + // Storage: Council Members (r:0 w:1) + // Storage: Council Prime (r:0 w:1) // Storage: System Account (r:2 w:2) fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_846_000 - .saturating_add((39_843_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 768_000 - .saturating_add((60_623_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 52_000 - .saturating_add((3_884_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 1_744_000 + .saturating_add((29_677_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 725_000 + .saturating_add((51_480_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 49_000 + .saturating_add((3_491_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) diff --git a/frame/gilt/src/weights.rs b/frame/gilt/src/weights.rs index fd4dcd1b5d5ae..b56b6051a9aee 100644 --- a/frame/gilt/src/weights.rs +++ b/frame/gilt/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_gilt //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/gilt/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -61,44 +62,44 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - (59_219_000 as Weight) + (32_876_000 as Weight) // Standard Error: 0 - .saturating_add((156_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((97_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - (184_943_000 as Weight) + (125_854_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - (59_352_000 as Weight) + (33_643_000 as Weight) // Standard Error: 0 - .saturating_add((129_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - (5_444_000 as Weight) + (2_570_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - (71_399_000 as Weight) + (40_854_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - (3_044_000 as Weight) + (1_598_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) @@ -106,9 +107,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - (54_478_000 as Weight) - // Standard Error: 2_000 - .saturating_add((10_150_000 as Weight).saturating_mul(b as Weight)) + (34_848_000 as Weight) + // Standard Error: 1_000 + .saturating_add((3_951_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(b as Weight))) @@ -118,9 +119,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - (20_099_000 as Weight) - // Standard Error: 7_000 - .saturating_add((16_603_000 as Weight).saturating_mul(q as Weight)) + (9_735_000 as Weight) + // Standard Error: 6_000 + .saturating_add((7_873_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(q as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -133,44 +134,44 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - (59_219_000 as Weight) + (32_876_000 as Weight) // Standard Error: 0 - .saturating_add((156_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((97_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - (184_943_000 as Weight) + (125_854_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - (59_352_000 as Weight) + (33_643_000 as Weight) // Standard Error: 0 - .saturating_add((129_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - (5_444_000 as Weight) + (2_570_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - (71_399_000 as Weight) + (40_854_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - (3_044_000 as Weight) + (1_598_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) @@ -178,9 +179,9 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - (54_478_000 as Weight) - // Standard Error: 2_000 - .saturating_add((10_150_000 as Weight).saturating_mul(b as Weight)) + (34_848_000 as Weight) + // Standard Error: 1_000 + .saturating_add((3_951_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(b as Weight))) @@ -190,9 +191,9 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - (20_099_000 as Weight) - // Standard Error: 7_000 - .saturating_add((16_603_000 as Weight).saturating_mul(q as Weight)) + (9_735_000 as Weight) + // Standard Error: 6_000 + .saturating_add((7_873_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(q as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 9f04007431be8..1d0a7825ec403 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_identity //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,7 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/identity/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -67,19 +69,19 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:1) fn add_registrar(r: u32, ) -> Weight { - (19_176_000 as Weight) - // Standard Error: 5_000 - .saturating_add((313_000 as Weight).saturating_mul(r as Weight)) + (12_513_000 as Weight) + // Standard Error: 4_000 + .saturating_add((257_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn set_identity(r: u32, x: u32, ) -> Weight { - (44_668_000 as Weight) - // Standard Error: 12_000 - .saturating_add((244_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_000 - .saturating_add((811_000 as Weight).saturating_mul(x as Weight)) + (27_904_000 as Weight) + // Standard Error: 7_000 + .saturating_add((215_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 0 + .saturating_add((294_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -87,9 +89,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) fn set_subs_new(s: u32, ) -> Weight { - (38_917_000 as Weight) - // Standard Error: 3_000 - .saturating_add((5_331_000 as Weight).saturating_mul(s as Weight)) + (24_530_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_914_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -99,9 +101,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) fn set_subs_old(p: u32, ) -> Weight { - (36_057_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_756_000 as Weight).saturating_mul(p as Weight)) + (23_957_000 as Weight) + // Standard Error: 0 + .saturating_add((954_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -110,13 +112,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (44_348_000 as Weight) - // Standard Error: 9_000 - .saturating_add((183_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_000 - .saturating_add((1_724_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 1_000 - .saturating_add((439_000 as Weight).saturating_mul(x as Weight)) + (31_213_000 as Weight) + // Standard Error: 8_000 + .saturating_add((99_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 0 + .saturating_add((931_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 0 + .saturating_add((188_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -124,56 +126,56 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn request_judgement(r: u32, x: u32, ) -> Weight { - (46_592_000 as Weight) - // Standard Error: 5_000 - .saturating_add((321_000 as Weight).saturating_mul(r as Weight)) + (30_691_000 as Weight) + // Standard Error: 4_000 + .saturating_add((269_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((858_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((338_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn cancel_request(r: u32, x: u32, ) -> Weight { - (43_556_000 as Weight) - // Standard Error: 6_000 - .saturating_add((174_000 as Weight).saturating_mul(r as Weight)) + (27_356_000 as Weight) + // Standard Error: 3_000 + .saturating_add((179_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((850_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((335_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fee(r: u32, ) -> Weight { - (7_971_000 as Weight) - // Standard Error: 4_000 - .saturating_add((283_000 as Weight).saturating_mul(r as Weight)) + (4_761_000 as Weight) + // Standard Error: 2_000 + .saturating_add((202_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_account_id(r: u32, ) -> Weight { - (8_234_000 as Weight) - // Standard Error: 4_000 - .saturating_add((280_000 as Weight).saturating_mul(r as Weight)) + (4_801_000 as Weight) + // Standard Error: 3_000 + .saturating_add((211_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fields(r: u32, ) -> Weight { - (8_126_000 as Weight) - // Standard Error: 4_000 - .saturating_add((275_000 as Weight).saturating_mul(r as Weight)) + (4_756_000 as Weight) + // Standard Error: 2_000 + .saturating_add((204_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn provide_judgement(r: u32, x: u32, ) -> Weight { - (30_949_000 as Weight) - // Standard Error: 5_000 - .saturating_add((286_000 as Weight).saturating_mul(r as Weight)) + (21_047_000 as Weight) + // Standard Error: 3_000 + .saturating_add((246_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((856_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -182,11 +184,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (63_792_000 as Weight) - // Standard Error: 11_000 - .saturating_add((242_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_000 - .saturating_add((1_738_000 as Weight).saturating_mul(s as Weight)) + (41_324_000 as Weight) + // Standard Error: 7_000 + .saturating_add((192_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 0 + .saturating_add((951_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -195,18 +197,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn add_sub(s: u32, ) -> Weight { - (48_751_000 as Weight) + (31_405_000 as Weight) // Standard Error: 1_000 - .saturating_add((193_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((160_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) fn rename_sub(s: u32, ) -> Weight { - (15_892_000 as Weight) + (10_622_000 as Weight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((47_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -214,18 +216,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn remove_sub(s: u32, ) -> Weight { - (49_746_000 as Weight) + (32_765_000 as Weight) // Standard Error: 1_000 - .saturating_add((181_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn quit_sub(s: u32, ) -> Weight { - (32_286_000 as Weight) + (21_925_000 as Weight) // Standard Error: 1_000 - .saturating_add((166_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((156_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -235,19 +237,19 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:1) fn add_registrar(r: u32, ) -> Weight { - (19_176_000 as Weight) - // Standard Error: 5_000 - .saturating_add((313_000 as Weight).saturating_mul(r as Weight)) + (12_513_000 as Weight) + // Standard Error: 4_000 + .saturating_add((257_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn set_identity(r: u32, x: u32, ) -> Weight { - (44_668_000 as Weight) - // Standard Error: 12_000 - .saturating_add((244_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_000 - .saturating_add((811_000 as Weight).saturating_mul(x as Weight)) + (27_904_000 as Weight) + // Standard Error: 7_000 + .saturating_add((215_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 0 + .saturating_add((294_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -255,9 +257,9 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) fn set_subs_new(s: u32, ) -> Weight { - (38_917_000 as Weight) - // Standard Error: 3_000 - .saturating_add((5_331_000 as Weight).saturating_mul(s as Weight)) + (24_530_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_914_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -267,9 +269,9 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) fn set_subs_old(p: u32, ) -> Weight { - (36_057_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_756_000 as Weight).saturating_mul(p as Weight)) + (23_957_000 as Weight) + // Standard Error: 0 + .saturating_add((954_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -278,13 +280,13 @@ impl WeightInfo for () { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (44_348_000 as Weight) - // Standard Error: 9_000 - .saturating_add((183_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_000 - .saturating_add((1_724_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 1_000 - .saturating_add((439_000 as Weight).saturating_mul(x as Weight)) + (31_213_000 as Weight) + // Standard Error: 8_000 + .saturating_add((99_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 0 + .saturating_add((931_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 0 + .saturating_add((188_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -292,56 +294,56 @@ impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn request_judgement(r: u32, x: u32, ) -> Weight { - (46_592_000 as Weight) - // Standard Error: 5_000 - .saturating_add((321_000 as Weight).saturating_mul(r as Weight)) + (30_691_000 as Weight) + // Standard Error: 4_000 + .saturating_add((269_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((858_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((338_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn cancel_request(r: u32, x: u32, ) -> Weight { - (43_556_000 as Weight) - // Standard Error: 6_000 - .saturating_add((174_000 as Weight).saturating_mul(r as Weight)) + (27_356_000 as Weight) + // Standard Error: 3_000 + .saturating_add((179_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((850_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((335_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fee(r: u32, ) -> Weight { - (7_971_000 as Weight) - // Standard Error: 4_000 - .saturating_add((283_000 as Weight).saturating_mul(r as Weight)) + (4_761_000 as Weight) + // Standard Error: 2_000 + .saturating_add((202_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_account_id(r: u32, ) -> Weight { - (8_234_000 as Weight) - // Standard Error: 4_000 - .saturating_add((280_000 as Weight).saturating_mul(r as Weight)) + (4_801_000 as Weight) + // Standard Error: 3_000 + .saturating_add((211_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fields(r: u32, ) -> Weight { - (8_126_000 as Weight) - // Standard Error: 4_000 - .saturating_add((275_000 as Weight).saturating_mul(r as Weight)) + (4_756_000 as Weight) + // Standard Error: 2_000 + .saturating_add((204_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn provide_judgement(r: u32, x: u32, ) -> Weight { - (30_949_000 as Weight) - // Standard Error: 5_000 - .saturating_add((286_000 as Weight).saturating_mul(r as Weight)) + (21_047_000 as Weight) + // Standard Error: 3_000 + .saturating_add((246_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((856_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -350,11 +352,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (63_792_000 as Weight) - // Standard Error: 11_000 - .saturating_add((242_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_000 - .saturating_add((1_738_000 as Weight).saturating_mul(s as Weight)) + (41_324_000 as Weight) + // Standard Error: 7_000 + .saturating_add((192_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 0 + .saturating_add((951_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -363,18 +365,18 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn add_sub(s: u32, ) -> Weight { - (48_751_000 as Weight) + (31_405_000 as Weight) // Standard Error: 1_000 - .saturating_add((193_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((160_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) fn rename_sub(s: u32, ) -> Weight { - (15_892_000 as Weight) + (10_622_000 as Weight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((47_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -382,18 +384,18 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn remove_sub(s: u32, ) -> Weight { - (49_746_000 as Weight) + (32_765_000 as Weight) // Standard Error: 1_000 - .saturating_add((181_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn quit_sub(s: u32, ) -> Weight { - (32_286_000 as Weight) + (21_925_000 as Weight) // Standard Error: 1_000 - .saturating_add((166_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((156_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index 19ac7e8ffc0fc..4fa5727251b3a 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_im_online //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/optimized/substrate // benchmark // --chain=dev // --steps=50 @@ -32,9 +32,10 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/im-online/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --output=./weights-optimized/frame/im-online/src//weights.rs +// --template=.maintain/frame-weight-template.hbs +// --header=HEADER-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,11 +58,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - (93_400_000 as Weight) + (73_594_000 as Weight) // Standard Error: 0 - .saturating_add((144_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((128_000 as Weight).saturating_mul(k as Weight)) // Standard Error: 0 - .saturating_add((335_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((295_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -75,11 +76,11 @@ impl WeightInfo for () { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - (93_400_000 as Weight) + (73_594_000 as Weight) // Standard Error: 0 - .saturating_add((144_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((128_000 as Weight).saturating_mul(k as Weight)) // Standard Error: 0 - .saturating_add((335_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((295_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 590aa11dec840..569af75af6dc8 100644 --- a/frame/indices/src/weights.rs +++ b/frame/indices/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_indices //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/indices/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,33 +58,33 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - (38_814_000 as Weight) + (20_754_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (47_274_000 as Weight) + (26_655_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - (39_692_000 as Weight) + (22_112_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (40_250_000 as Weight) + (22_175_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - (37_358_000 as Weight) + (24_344_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -93,33 +94,33 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - (38_814_000 as Weight) + (20_754_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (47_274_000 as Weight) + (26_655_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - (39_692_000 as Weight) + (22_112_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (40_250_000 as Weight) + (22_175_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - (37_358_000 as Weight) + (24_344_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index 53ec2aa231568..080222125c844 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_lottery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-11, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,7 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/lottery/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -63,28 +65,28 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (52_219_000 as Weight) + (38_270_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (13_249_000 as Weight) + (8_830_000 as Weight) // Standard Error: 7_000 - .saturating_add((378_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((291_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (44_636_000 as Weight) + (31_404_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (5_654_000 as Weight) + (3_825_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -94,7 +96,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (72_990_000 as Weight) + (49_760_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -105,7 +107,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (75_323_000 as Weight) + (53_159_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -121,28 +123,28 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (52_219_000 as Weight) + (38_270_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (13_249_000 as Weight) + (8_830_000 as Weight) // Standard Error: 7_000 - .saturating_add((378_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((291_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (44_636_000 as Weight) + (31_404_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (5_654_000 as Weight) + (3_825_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -152,7 +154,7 @@ impl WeightInfo for () { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (72_990_000 as Weight) + (49_760_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -163,7 +165,7 @@ impl WeightInfo for () { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (75_323_000 as Weight) + (53_159_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 5b34529c7c182..59215d3a5bff6 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_membership //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/membership/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,79 +58,79 @@ pub trait WeightInfo { /// Weights for pallet_membership using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Instance1Membership Members (r:1 w:1) - // Storage: Instance2Collective Proposals (r:1 w:0) - // Storage: Instance2Collective Members (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:1) + // Storage: TechnicalCommittee Proposals (r:1 w:0) + // Storage: TechnicalCommittee Members (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - (23_668_000 as Weight) - // Standard Error: 3_000 - .saturating_add((142_000 as Weight).saturating_mul(m as Weight)) + (14_403_000 as Weight) + // Standard Error: 1_000 + .saturating_add((94_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Membership Members (r:1 w:1) - // Storage: Instance2Collective Proposals (r:1 w:0) - // Storage: Instance1Membership Prime (r:1 w:0) - // Storage: Instance2Collective Members (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:1) + // Storage: TechnicalCommittee Proposals (r:1 w:0) + // Storage: TechnicalMembership Prime (r:1 w:0) + // Storage: TechnicalCommittee Members (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - (29_149_000 as Weight) + (17_005_000 as Weight) // Standard Error: 0 - .saturating_add((111_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((90_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Membership Members (r:1 w:1) - // Storage: Instance2Collective Proposals (r:1 w:0) - // Storage: Instance1Membership Prime (r:1 w:0) - // Storage: Instance2Collective Members (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:1) + // Storage: TechnicalCommittee Proposals (r:1 w:0) + // Storage: TechnicalMembership Prime (r:1 w:0) + // Storage: TechnicalCommittee Members (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - (29_289_000 as Weight) + (17_210_000 as Weight) // Standard Error: 0 - .saturating_add((126_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((98_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Membership Members (r:1 w:1) - // Storage: Instance2Collective Proposals (r:1 w:0) - // Storage: Instance1Membership Prime (r:1 w:0) - // Storage: Instance2Collective Members (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:1) + // Storage: TechnicalCommittee Proposals (r:1 w:0) + // Storage: TechnicalMembership Prime (r:1 w:0) + // Storage: TechnicalCommittee Members (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - (30_178_000 as Weight) - // Standard Error: 1_000 - .saturating_add((286_000 as Weight).saturating_mul(m as Weight)) + (17_425_000 as Weight) + // Standard Error: 0 + .saturating_add((194_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Membership Members (r:1 w:1) - // Storage: Instance2Collective Proposals (r:1 w:0) - // Storage: Instance1Membership Prime (r:1 w:1) - // Storage: Instance2Collective Members (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:1) + // Storage: TechnicalCommittee Proposals (r:1 w:0) + // Storage: TechnicalMembership Prime (r:1 w:1) + // Storage: TechnicalCommittee Members (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - (31_049_000 as Weight) + (17_948_000 as Weight) // Standard Error: 0 - .saturating_add((121_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((95_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } - // Storage: Instance1Membership Members (r:1 w:0) - // Storage: Instance1Membership Prime (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:0) + // Storage: TechnicalMembership Prime (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - (8_006_000 as Weight) + (4_579_000 as Weight) // Standard Error: 0 - .saturating_add((89_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((71_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - // Storage: Instance1Membership Prime (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Prime (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - (3_452_000 as Weight) + (1_481_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -138,79 +139,79 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Instance1Membership Members (r:1 w:1) - // Storage: Instance2Collective Proposals (r:1 w:0) - // Storage: Instance2Collective Members (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:1) + // Storage: TechnicalCommittee Proposals (r:1 w:0) + // Storage: TechnicalCommittee Members (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - (23_668_000 as Weight) - // Standard Error: 3_000 - .saturating_add((142_000 as Weight).saturating_mul(m as Weight)) + (14_403_000 as Weight) + // Standard Error: 1_000 + .saturating_add((94_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Membership Members (r:1 w:1) - // Storage: Instance2Collective Proposals (r:1 w:0) - // Storage: Instance1Membership Prime (r:1 w:0) - // Storage: Instance2Collective Members (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:1) + // Storage: TechnicalCommittee Proposals (r:1 w:0) + // Storage: TechnicalMembership Prime (r:1 w:0) + // Storage: TechnicalCommittee Members (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - (29_149_000 as Weight) + (17_005_000 as Weight) // Standard Error: 0 - .saturating_add((111_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((90_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Membership Members (r:1 w:1) - // Storage: Instance2Collective Proposals (r:1 w:0) - // Storage: Instance1Membership Prime (r:1 w:0) - // Storage: Instance2Collective Members (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:1) + // Storage: TechnicalCommittee Proposals (r:1 w:0) + // Storage: TechnicalMembership Prime (r:1 w:0) + // Storage: TechnicalCommittee Members (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - (29_289_000 as Weight) + (17_210_000 as Weight) // Standard Error: 0 - .saturating_add((126_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((98_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Membership Members (r:1 w:1) - // Storage: Instance2Collective Proposals (r:1 w:0) - // Storage: Instance1Membership Prime (r:1 w:0) - // Storage: Instance2Collective Members (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:1) + // Storage: TechnicalCommittee Proposals (r:1 w:0) + // Storage: TechnicalMembership Prime (r:1 w:0) + // Storage: TechnicalCommittee Members (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - (30_178_000 as Weight) - // Standard Error: 1_000 - .saturating_add((286_000 as Weight).saturating_mul(m as Weight)) + (17_425_000 as Weight) + // Standard Error: 0 + .saturating_add((194_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Instance1Membership Members (r:1 w:1) - // Storage: Instance2Collective Proposals (r:1 w:0) - // Storage: Instance1Membership Prime (r:1 w:1) - // Storage: Instance2Collective Members (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:1) + // Storage: TechnicalCommittee Proposals (r:1 w:0) + // Storage: TechnicalMembership Prime (r:1 w:1) + // Storage: TechnicalCommittee Members (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - (31_049_000 as Weight) + (17_948_000 as Weight) // Standard Error: 0 - .saturating_add((121_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((95_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } - // Storage: Instance1Membership Members (r:1 w:0) - // Storage: Instance1Membership Prime (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Members (r:1 w:0) + // Storage: TechnicalMembership Prime (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - (8_006_000 as Weight) + (4_579_000 as Weight) // Standard Error: 0 - .saturating_add((89_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((71_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } - // Storage: Instance1Membership Prime (r:0 w:1) - // Storage: Instance2Collective Prime (r:0 w:1) + // Storage: TechnicalMembership Prime (r:0 w:1) + // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - (3_452_000 as Weight) + (1_481_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index eb78a88f1531c..5dc40197db554 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_multisig //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/multisig/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -61,18 +62,18 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn as_multi_threshold_1(z: u32, ) -> Weight { - (19_405_000 as Weight) + (16_904_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - (54_364_000 as Weight) + (30_172_000 as Weight) // Standard Error: 0 - .saturating_add((163_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((142_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -80,32 +81,32 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - (59_545_000 as Weight) - // Standard Error: 0 - .saturating_add((168_000 as Weight).saturating_mul(s as Weight)) + (33_039_000 as Weight) + // Standard Error: 1_000 + .saturating_add((140_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - (32_721_000 as Weight) + (20_752_000 as Weight) // Standard Error: 0 - .saturating_add((176_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((133_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - (56_596_000 as Weight) + (33_198_000 as Weight) // Standard Error: 1_000 - .saturating_add((183_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((135_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -113,29 +114,29 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - (72_391_000 as Weight) + (39_407_000 as Weight) // Standard Error: 1_000 - .saturating_add((268_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((230_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - (52_543_000 as Weight) - // Standard Error: 0 - .saturating_add((164_000 as Weight).saturating_mul(s as Weight)) + (28_365_000 as Weight) + // Standard Error: 1_000 + .saturating_add((156_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - (30_764_000 as Weight) + (17_960_000 as Weight) // Standard Error: 0 - .saturating_add((180_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -143,18 +144,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - (113_631_000 as Weight) - // Standard Error: 3_000 - .saturating_add((283_000 as Weight).saturating_mul(s as Weight)) + (56_920_000 as Weight) + // Standard Error: 1_000 + .saturating_add((243_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - (86_310_000 as Weight) - // Standard Error: 0 - .saturating_add((166_000 as Weight).saturating_mul(s as Weight)) + (45_336_000 as Weight) + // Standard Error: 1_000 + .saturating_add((155_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -163,18 +164,18 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn as_multi_threshold_1(z: u32, ) -> Weight { - (19_405_000 as Weight) + (16_904_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - (54_364_000 as Weight) + (30_172_000 as Weight) // Standard Error: 0 - .saturating_add((163_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((142_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -182,32 +183,32 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - (59_545_000 as Weight) - // Standard Error: 0 - .saturating_add((168_000 as Weight).saturating_mul(s as Weight)) + (33_039_000 as Weight) + // Standard Error: 1_000 + .saturating_add((140_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - (32_721_000 as Weight) + (20_752_000 as Weight) // Standard Error: 0 - .saturating_add((176_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((133_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - (56_596_000 as Weight) + (33_198_000 as Weight) // Standard Error: 1_000 - .saturating_add((183_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((135_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -215,29 +216,29 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - (72_391_000 as Weight) + (39_407_000 as Weight) // Standard Error: 1_000 - .saturating_add((268_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((230_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - (52_543_000 as Weight) - // Standard Error: 0 - .saturating_add((164_000 as Weight).saturating_mul(s as Weight)) + (28_365_000 as Weight) + // Standard Error: 1_000 + .saturating_add((156_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - (30_764_000 as Weight) + (17_960_000 as Weight) // Standard Error: 0 - .saturating_add((180_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -245,18 +246,18 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - (113_631_000 as Weight) - // Standard Error: 3_000 - .saturating_add((283_000 as Weight).saturating_mul(s as Weight)) + (56_920_000 as Weight) + // Standard Error: 1_000 + .saturating_add((243_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - (86_310_000 as Weight) - // Standard Error: 0 - .saturating_add((166_000 as Weight).saturating_mul(s as Weight)) + (45_336_000 as Weight) + // Standard Error: 1_000 + .saturating_add((155_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index fab5cdfb67361..b0f22a49297b6 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-12-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,7 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/preimage/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -91,58 +93,58 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (60_560_000 as Weight) + (38_155_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (37_575_000 as Weight) + (24_132_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (56_868_000 as Weight) + (36_703_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (37_058_000 as Weight) + (23_056_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (21_500_000 as Weight) + (12_937_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (7_798_000 as Weight) + (4_460_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (37_771_000 as Weight) + (23_761_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (22_913_000 as Weight) + (13_829_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (7_608_000 as Weight) + (4_595_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -180,58 +182,58 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (60_560_000 as Weight) + (38_155_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (37_575_000 as Weight) + (24_132_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (56_868_000 as Weight) + (36_703_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (37_058_000 as Weight) + (23_056_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (21_500_000 as Weight) + (12_937_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (7_798_000 as Weight) + (4_460_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (37_771_000 as Weight) + (23_761_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (22_913_000 as Weight) + (13_829_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (7_608_000 as Weight) + (4_595_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index bde4fd761179c..4628ada8d3c8b 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_proxy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/proxy/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,38 +63,42 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - (23_213_000 as Weight) + (13_623_000 as Weight) // Standard Error: 2_000 - .saturating_add((153_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((121_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - (53_286_000 as Weight) + (29_560_000 as Weight) // Standard Error: 2_000 - .saturating_add((549_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((259_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((138_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((121_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) - fn remove_announcement(a: u32, _p: u32, ) -> Weight { - (36_864_000 as Weight) - // Standard Error: 2_000 - .saturating_add((550_000 as Weight).saturating_mul(a as Weight)) + fn remove_announcement(a: u32, p: u32, ) -> Weight { + (21_004_000 as Weight) + // Standard Error: 1_000 + .saturating_add((266_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 1_000 + .saturating_add((13_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) - fn reject_announcement(a: u32, _p: u32, ) -> Weight { - (36_755_000 as Weight) + fn reject_announcement(a: u32, p: u32, ) -> Weight { + (20_992_000 as Weight) // Standard Error: 1_000 - .saturating_add((550_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((266_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 1_000 + .saturating_add((14_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -101,52 +106,52 @@ impl WeightInfo for SubstrateWeight { // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - (50_765_000 as Weight) + (28_118_000 as Weight) // Standard Error: 2_000 - .saturating_add((547_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((250_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((141_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((118_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - (35_556_000 as Weight) - // Standard Error: 3_000 - .saturating_add((211_000 as Weight).saturating_mul(p as Weight)) + (23_077_000 as Weight) + // Standard Error: 2_000 + .saturating_add((159_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - (35_284_000 as Weight) - // Standard Error: 3_000 - .saturating_add((229_000 as Weight).saturating_mul(p as Weight)) + (19_919_000 as Weight) + // Standard Error: 2_000 + .saturating_add((155_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - (34_449_000 as Weight) + (19_625_000 as Weight) // Standard Error: 2_000 - .saturating_add((146_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - (49_149_000 as Weight) + (26_066_000 as Weight) // Standard Error: 2_000 - .saturating_add((15_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((37_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - (36_399_000 as Weight) + (21_294_000 as Weight) // Standard Error: 2_000 - .saturating_add((152_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((112_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -156,38 +161,42 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - (23_213_000 as Weight) + (13_623_000 as Weight) // Standard Error: 2_000 - .saturating_add((153_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((121_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - (53_286_000 as Weight) + (29_560_000 as Weight) // Standard Error: 2_000 - .saturating_add((549_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((259_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((138_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((121_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) - fn remove_announcement(a: u32, _p: u32, ) -> Weight { - (36_864_000 as Weight) - // Standard Error: 2_000 - .saturating_add((550_000 as Weight).saturating_mul(a as Weight)) + fn remove_announcement(a: u32, p: u32, ) -> Weight { + (21_004_000 as Weight) + // Standard Error: 1_000 + .saturating_add((266_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 1_000 + .saturating_add((13_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) - fn reject_announcement(a: u32, _p: u32, ) -> Weight { - (36_755_000 as Weight) + fn reject_announcement(a: u32, p: u32, ) -> Weight { + (20_992_000 as Weight) // Standard Error: 1_000 - .saturating_add((550_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((266_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 1_000 + .saturating_add((14_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -195,52 +204,52 @@ impl WeightInfo for () { // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - (50_765_000 as Weight) + (28_118_000 as Weight) // Standard Error: 2_000 - .saturating_add((547_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((250_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((141_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((118_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - (35_556_000 as Weight) - // Standard Error: 3_000 - .saturating_add((211_000 as Weight).saturating_mul(p as Weight)) + (23_077_000 as Weight) + // Standard Error: 2_000 + .saturating_add((159_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - (35_284_000 as Weight) - // Standard Error: 3_000 - .saturating_add((229_000 as Weight).saturating_mul(p as Weight)) + (19_919_000 as Weight) + // Standard Error: 2_000 + .saturating_add((155_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - (34_449_000 as Weight) + (19_625_000 as Weight) // Standard Error: 2_000 - .saturating_add((146_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - (49_149_000 as Weight) + (26_066_000 as Weight) // Standard Error: 2_000 - .saturating_add((15_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((37_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - (36_399_000 as Weight) + (21_294_000 as Weight) // Standard Error: 2_000 - .saturating_add((152_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((112_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index b8209c6031c89..281b25977cf49 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-12-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,7 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/scheduler/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -68,9 +70,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (8_183_000 as Weight) - // Standard Error: 36_000 - .saturating_add((34_670_000 as Weight).saturating_mul(s as Weight)) + (10_798_000 as Weight) + // Standard Error: 13_000 + .saturating_add((17_708_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -81,9 +83,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (11_520_000 as Weight) - // Standard Error: 30_000 - .saturating_add((26_386_000 as Weight).saturating_mul(s as Weight)) + (8_722_000 as Weight) + // Standard Error: 10_000 + .saturating_add((13_706_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -93,9 +95,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (8_222_000 as Weight) - // Standard Error: 33_000 - .saturating_add((28_925_000 as Weight).saturating_mul(s as Weight)) + (9_414_000 as Weight) + // Standard Error: 9_000 + .saturating_add((15_176_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -105,9 +107,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (11_610_000 as Weight) - // Standard Error: 26_000 - .saturating_add((23_857_000 as Weight).saturating_mul(s as Weight)) + (9_572_000 as Weight) + // Standard Error: 12_000 + .saturating_add((12_505_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -117,9 +119,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (11_067_000 as Weight) - // Standard Error: 15_000 - .saturating_add((11_728_000 as Weight).saturating_mul(s as Weight)) + (6_900_000 as Weight) + // Standard Error: 4_000 + .saturating_add((5_486_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -128,9 +130,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (13_045_000 as Weight) - // Standard Error: 5_000 - .saturating_add((6_378_000 as Weight).saturating_mul(s as Weight)) + (8_346_000 as Weight) + // Standard Error: 3_000 + .saturating_add((3_079_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -138,9 +140,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (13_496_000 as Weight) - // Standard Error: 27_000 - .saturating_add((17_932_000 as Weight).saturating_mul(s as Weight)) + (13_462_000 as Weight) + // Standard Error: 5_000 + .saturating_add((8_230_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -148,9 +150,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (17_074_000 as Weight) - // Standard Error: 16_000 - .saturating_add((11_982_000 as Weight).saturating_mul(s as Weight)) + (13_046_000 as Weight) + // Standard Error: 4_000 + .saturating_add((5_782_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -159,53 +161,53 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (18_730_000 as Weight) - // Standard Error: 10_000 - .saturating_add((9_909_000 as Weight).saturating_mul(s as Weight)) + (13_481_000 as Weight) + // Standard Error: 3_000 + .saturating_add((4_385_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (17_844_000 as Weight) - // Standard Error: 9_000 - .saturating_add((7_719_000 as Weight).saturating_mul(s as Weight)) + (13_081_000 as Weight) + // Standard Error: 4_000 + .saturating_add((3_434_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (23_361_000 as Weight) + (13_863_000 as Weight) // Standard Error: 1_000 - .saturating_add((82_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((87_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (22_359_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_219_000 as Weight).saturating_mul(s as Weight)) + (13_695_000 as Weight) + // Standard Error: 1_000 + .saturating_add((594_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (28_499_000 as Weight) + (16_506_000 as Weight) // Standard Error: 1_000 - .saturating_add((98_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((99_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (24_995_000 as Weight) + (15_685_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_223_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((604_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -218,9 +220,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (8_183_000 as Weight) - // Standard Error: 36_000 - .saturating_add((34_670_000 as Weight).saturating_mul(s as Weight)) + (10_798_000 as Weight) + // Standard Error: 13_000 + .saturating_add((17_708_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -231,9 +233,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (11_520_000 as Weight) - // Standard Error: 30_000 - .saturating_add((26_386_000 as Weight).saturating_mul(s as Weight)) + (8_722_000 as Weight) + // Standard Error: 10_000 + .saturating_add((13_706_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -243,9 +245,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (8_222_000 as Weight) - // Standard Error: 33_000 - .saturating_add((28_925_000 as Weight).saturating_mul(s as Weight)) + (9_414_000 as Weight) + // Standard Error: 9_000 + .saturating_add((15_176_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -255,9 +257,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (11_610_000 as Weight) - // Standard Error: 26_000 - .saturating_add((23_857_000 as Weight).saturating_mul(s as Weight)) + (9_572_000 as Weight) + // Standard Error: 12_000 + .saturating_add((12_505_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -267,9 +269,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (11_067_000 as Weight) - // Standard Error: 15_000 - .saturating_add((11_728_000 as Weight).saturating_mul(s as Weight)) + (6_900_000 as Weight) + // Standard Error: 4_000 + .saturating_add((5_486_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -278,9 +280,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (13_045_000 as Weight) - // Standard Error: 5_000 - .saturating_add((6_378_000 as Weight).saturating_mul(s as Weight)) + (8_346_000 as Weight) + // Standard Error: 3_000 + .saturating_add((3_079_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -288,9 +290,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (13_496_000 as Weight) - // Standard Error: 27_000 - .saturating_add((17_932_000 as Weight).saturating_mul(s as Weight)) + (13_462_000 as Weight) + // Standard Error: 5_000 + .saturating_add((8_230_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -298,9 +300,9 @@ impl WeightInfo for () { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (17_074_000 as Weight) - // Standard Error: 16_000 - .saturating_add((11_982_000 as Weight).saturating_mul(s as Weight)) + (13_046_000 as Weight) + // Standard Error: 4_000 + .saturating_add((5_782_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -309,53 +311,53 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (18_730_000 as Weight) - // Standard Error: 10_000 - .saturating_add((9_909_000 as Weight).saturating_mul(s as Weight)) + (13_481_000 as Weight) + // Standard Error: 3_000 + .saturating_add((4_385_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (17_844_000 as Weight) - // Standard Error: 9_000 - .saturating_add((7_719_000 as Weight).saturating_mul(s as Weight)) + (13_081_000 as Weight) + // Standard Error: 4_000 + .saturating_add((3_434_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (23_361_000 as Weight) + (13_863_000 as Weight) // Standard Error: 1_000 - .saturating_add((82_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((87_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (22_359_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_219_000 as Weight).saturating_mul(s as Weight)) + (13_695_000 as Weight) + // Standard Error: 1_000 + .saturating_add((594_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (28_499_000 as Weight) + (16_506_000 as Weight) // Standard Error: 1_000 - .saturating_add((98_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((99_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (24_995_000 as Weight) + (15_685_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_223_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((604_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index 35c9cc7230fb4..2cf5cd9c41929 100644 --- a/frame/session/src/weights.rs +++ b/frame/session/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_session //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/session/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,7 +57,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - (64_427_000 as Weight) + (42_449_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -64,7 +65,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - (42_497_000 as Weight) + (32_778_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -76,7 +77,7 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - (64_427_000 as Weight) + (42_449_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -84,7 +85,7 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - (42_497_000 as Weight) + (32_778_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 4f5af6fcd5f8e..7721fbbd23714 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-29, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,7 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/staking/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -84,7 +86,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (63_660_000 as Weight) + (38_457_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -94,7 +96,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (103_672_000 as Weight) + (65_678_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -108,7 +110,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (110_884_000 as Weight) + (71_544_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -117,9 +119,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (46_379_000 as Weight) + (30_127_000 as Weight) // Standard Error: 0 - .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((59_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -137,7 +139,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (91_303_000 as Weight) + (59_131_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(11 as Weight)) } @@ -153,16 +155,16 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (66_587_000 as Weight) + (45_519_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (21_153_000 as Weight) - // Standard Error: 16_000 - .saturating_add((13_502_000 as Weight).saturating_mul(k as Weight)) + (16_645_000 as Weight) + // Standard Error: 12_000 + .saturating_add((8_194_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -173,15 +175,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:1 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking CounterForNominators (r:1 w:1) // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListNodes (r:2 w:2) // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (75_456_000 as Weight) + (50_227_000 as Weight) // Standard Error: 12_000 - .saturating_add((5_051_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((3_546_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(6 as Weight)) @@ -194,49 +196,49 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (65_332_000 as Weight) + (44_294_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (11_757_000 as Weight) + (7_556_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (24_252_000 as Weight) + (15_826_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (2_252_000 as Weight) + (1_141_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (2_431_000 as Weight) + (1_152_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (2_397_000 as Weight) + (1_169_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (2_423_000 as Weight) + (1_134_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (2_876_000 as Weight) + (1_641_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) @@ -253,18 +255,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (87_540_000 as Weight) + (57_227_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_791_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((817_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (2_769_801_000 as Weight) - // Standard Error: 181_000 - .saturating_add((16_225_000 as Weight).saturating_mul(s as Weight)) + (950_241_000 as Weight) + // Standard Error: 56_000 + .saturating_add((4_960_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -279,9 +281,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (103_452_000 as Weight) - // Standard Error: 19_000 - .saturating_add((42_909_000 as Weight).saturating_mul(n as Weight)) + (73_561_000 as Weight) + // Standard Error: 13_000 + .saturating_add((24_039_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -299,9 +301,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (145_995_000 as Weight) - // Standard Error: 27_000 - .saturating_add((55_974_000 as Weight).saturating_mul(n as Weight)) + (105_296_000 as Weight) + // Standard Error: 18_000 + .saturating_add((33_989_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -314,9 +316,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (101_568_000 as Weight) - // Standard Error: 2_000 - .saturating_add((66_000 as Weight).saturating_mul(l as Weight)) + (65_108_000 as Weight) + // Standard Error: 3_000 + .saturating_add((72_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(9 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -331,8 +333,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 69_000 - .saturating_add((29_939_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 54_000 + .saturating_add((19_731_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) .saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -351,9 +353,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (96_886_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_790_000 as Weight).saturating_mul(s as Weight)) + (63_115_000 as Weight) + // Standard Error: 0 + .saturating_add((812_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -378,10 +380,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 873_000 - .saturating_add((286_141_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 43_000 - .saturating_add((44_712_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 800_000 + .saturating_add((219_877_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 40_000 + .saturating_add((31_701_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -399,10 +401,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 87_000 - .saturating_add((24_049_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 87_000 - .saturating_add((27_514_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 88_000 + .saturating_add((18_183_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 88_000 + .saturating_add((21_345_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(204 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -411,8 +413,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 32_000 - .saturating_add((10_128_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 25_000 + .saturating_add((7_691_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -423,7 +425,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs() -> Weight { - (6_187_000 as Weight) + (3_324_000 as Weight) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -437,7 +439,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (78_282_000 as Weight) + (54_254_000 as Weight) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -452,7 +454,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (63_660_000 as Weight) + (38_457_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -462,7 +464,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (103_672_000 as Weight) + (65_678_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } @@ -476,7 +478,7 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (110_884_000 as Weight) + (71_544_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -485,9 +487,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (46_379_000 as Weight) + (30_127_000 as Weight) // Standard Error: 0 - .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((59_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -505,7 +507,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (91_303_000 as Weight) + (59_131_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } @@ -521,16 +523,16 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (66_587_000 as Weight) + (45_519_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (21_153_000 as Weight) - // Standard Error: 16_000 - .saturating_add((13_502_000 as Weight).saturating_mul(k as Weight)) + (16_645_000 as Weight) + // Standard Error: 12_000 + .saturating_add((8_194_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -541,15 +543,15 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:1 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking CounterForNominators (r:1 w:1) // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListNodes (r:2 w:2) // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (75_456_000 as Weight) + (50_227_000 as Weight) // Standard Error: 12_000 - .saturating_add((5_051_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((3_546_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) @@ -562,49 +564,49 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (65_332_000 as Weight) + (44_294_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (11_757_000 as Weight) + (7_556_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (24_252_000 as Weight) + (15_826_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (2_252_000 as Weight) + (1_141_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (2_431_000 as Weight) + (1_152_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (2_397_000 as Weight) + (1_169_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (2_423_000 as Weight) + (1_134_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (2_876_000 as Weight) + (1_641_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) @@ -621,18 +623,18 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (87_540_000 as Weight) + (57_227_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_791_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((817_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (2_769_801_000 as Weight) - // Standard Error: 181_000 - .saturating_add((16_225_000 as Weight).saturating_mul(s as Weight)) + (950_241_000 as Weight) + // Standard Error: 56_000 + .saturating_add((4_960_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -647,9 +649,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (103_452_000 as Weight) - // Standard Error: 19_000 - .saturating_add((42_909_000 as Weight).saturating_mul(n as Weight)) + (73_561_000 as Weight) + // Standard Error: 13_000 + .saturating_add((24_039_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -667,9 +669,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (145_995_000 as Weight) - // Standard Error: 27_000 - .saturating_add((55_974_000 as Weight).saturating_mul(n as Weight)) + (105_296_000 as Weight) + // Standard Error: 18_000 + .saturating_add((33_989_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -682,9 +684,9 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (101_568_000 as Weight) - // Standard Error: 2_000 - .saturating_add((66_000 as Weight).saturating_mul(l as Weight)) + (65_108_000 as Weight) + // Standard Error: 3_000 + .saturating_add((72_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(9 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -699,8 +701,8 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 69_000 - .saturating_add((29_939_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 54_000 + .saturating_add((19_731_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) .saturating_add(RocksDbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -719,9 +721,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (96_886_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_790_000 as Weight).saturating_mul(s as Weight)) + (63_115_000 as Weight) + // Standard Error: 0 + .saturating_add((812_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -746,10 +748,10 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 873_000 - .saturating_add((286_141_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 43_000 - .saturating_add((44_712_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 800_000 + .saturating_add((219_877_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 40_000 + .saturating_add((31_701_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -767,10 +769,10 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1000 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 87_000 - .saturating_add((24_049_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 87_000 - .saturating_add((27_514_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 88_000 + .saturating_add((18_183_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 88_000 + .saturating_add((21_345_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(204 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -779,8 +781,8 @@ impl WeightInfo for () { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 32_000 - .saturating_add((10_128_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 25_000 + .saturating_add((7_691_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -791,7 +793,7 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs() -> Weight { - (6_187_000 as Weight) + (3_324_000 as Weight) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -805,7 +807,7 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (78_282_000 as Weight) + (54_254_000 as Weight) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index ff6900032d961..1fc35a41752a8 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for frame_system //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/optimized/substrate // benchmark // --chain=dev // --steps=50 @@ -32,9 +32,10 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/system/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --output=./weights-optimized/frame/system/src//weights.rs +// --template=.maintain/frame-weight-template.hbs +// --header=HEADER-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,80 +57,80 @@ pub trait WeightInfo { /// Weights for frame_system using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - fn remark(b: u32, ) -> Weight { - (574_000 as Weight) - // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) + fn remark(_b: u32, ) -> Weight { + (0 as Weight) } fn remark_with_event(b: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) } + // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (1_891_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (2_821_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn set_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((848_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((385_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_storage(i: u32, ) -> Weight { - (308_000 as Weight) + (0 as Weight) // Standard Error: 0 - .saturating_add((559_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((286_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_prefix(p: u32, ) -> Weight { - (7_616_000 as Weight) - // Standard Error: 1_000 - .saturating_add((783_000 as Weight).saturating_mul(p as Weight)) + (1_292_000 as Weight) + // Standard Error: 0 + .saturating_add((633_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } } // For backwards compatibility and tests impl WeightInfo for () { - fn remark(b: u32, ) -> Weight { - (574_000 as Weight) - // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) + fn remark(_b: u32, ) -> Weight { + (0 as Weight) } fn remark_with_event(b: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) } + // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (1_891_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (2_821_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn set_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((848_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((385_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_storage(i: u32, ) -> Weight { - (308_000 as Weight) + (0 as Weight) // Standard Error: 0 - .saturating_add((559_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((286_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_prefix(p: u32, ) -> Weight { - (7_616_000 as Weight) - // Standard Error: 1_000 - .saturating_add((783_000 as Weight).saturating_mul(p as Weight)) + (1_292_000 as Weight) + // Standard Error: 0 + .saturating_add((633_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } } diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index fb452ebe35953..b0f4b9d30588d 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_timestamp //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/timestamp/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,12 +56,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - (10_391_000 as Weight) + (5_191_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (4_843_000 as Weight) + (2_563_000 as Weight) } } @@ -69,11 +70,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - (10_391_000 as Weight) + (5_191_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (4_843_000 as Weight) + (2_563_000 as Weight) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 29e85ccad8510..154b6a67d8541 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_tips //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/tips/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,60 +57,60 @@ pub trait WeightInfo { /// Weights for pallet_tips using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Treasury Reasons (r:1 w:1) - // Storage: Treasury Tips (r:1 w:1) + // Storage: Tips Reasons (r:1 w:1) + // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - (50_921_000 as Weight) + (26_318_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - // Storage: Treasury Tips (r:1 w:1) - // Storage: Treasury Reasons (r:0 w:1) + // Storage: Tips Tips (r:1 w:1) + // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - (46_352_000 as Weight) + (24_688_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Members (r:1 w:0) - // Storage: Treasury Reasons (r:1 w:1) - // Storage: Treasury Tips (r:0 w:1) + // Storage: Tips Reasons (r:1 w:1) + // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - (33_338_000 as Weight) - // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) + (17_395_000 as Weight) // Standard Error: 0 - .saturating_add((115_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((3_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 4_000 + .saturating_add((197_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Members (r:1 w:0) - // Storage: Treasury Tips (r:1 w:1) + // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - (22_702_000 as Weight) - // Standard Error: 0 - .saturating_add((538_000 as Weight).saturating_mul(t as Weight)) + (10_783_000 as Weight) + // Standard Error: 6_000 + .saturating_add((568_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: Treasury Tips (r:1 w:1) + // Storage: Tips Tips (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: System Account (r:1 w:1) - // Storage: Treasury Reasons (r:0 w:1) + // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - (84_094_000 as Weight) - // Standard Error: 0 - .saturating_add((283_000 as Weight).saturating_mul(t as Weight)) + (41_658_000 as Weight) + // Standard Error: 13_000 + .saturating_add((391_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Treasury Tips (r:1 w:1) - // Storage: Treasury Reasons (r:0 w:1) + // Storage: Tips Tips (r:1 w:1) + // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - (24_891_000 as Weight) - // Standard Error: 0 - .saturating_add((6_000 as Weight).saturating_mul(t as Weight)) + (14_935_000 as Weight) + // Standard Error: 6_000 + .saturating_add((40_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -117,60 +118,60 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Treasury Reasons (r:1 w:1) - // Storage: Treasury Tips (r:1 w:1) + // Storage: Tips Reasons (r:1 w:1) + // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - (50_921_000 as Weight) + (26_318_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } - // Storage: Treasury Tips (r:1 w:1) - // Storage: Treasury Reasons (r:0 w:1) + // Storage: Tips Tips (r:1 w:1) + // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - (46_352_000 as Weight) + (24_688_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Members (r:1 w:0) - // Storage: Treasury Reasons (r:1 w:1) - // Storage: Treasury Tips (r:0 w:1) + // Storage: Tips Reasons (r:1 w:1) + // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - (33_338_000 as Weight) + (17_395_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 0 - .saturating_add((115_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((3_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 4_000 + .saturating_add((197_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Members (r:1 w:0) - // Storage: Treasury Tips (r:1 w:1) + // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - (22_702_000 as Weight) - // Standard Error: 0 - .saturating_add((538_000 as Weight).saturating_mul(t as Weight)) + (10_783_000 as Weight) + // Standard Error: 6_000 + .saturating_add((568_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: Treasury Tips (r:1 w:1) + // Storage: Tips Tips (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: System Account (r:1 w:1) - // Storage: Treasury Reasons (r:0 w:1) + // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - (84_094_000 as Weight) - // Standard Error: 0 - .saturating_add((283_000 as Weight).saturating_mul(t as Weight)) + (41_658_000 as Weight) + // Standard Error: 13_000 + .saturating_add((391_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Treasury Tips (r:1 w:1) - // Storage: Treasury Reasons (r:0 w:1) + // Storage: Tips Tips (r:1 w:1) + // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - (24_891_000 as Weight) - // Standard Error: 0 - .saturating_add((6_000 as Weight).saturating_mul(t as Weight)) + (14_935_000 as Weight) + // Standard Error: 6_000 + .saturating_add((40_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index ffea996b83d99..bdf4d2cf62221 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_transaction_storage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/optimized/substrate // benchmark // --chain=dev // --steps=50 @@ -32,9 +32,10 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/transaction-storage/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --output=./weights-optimized/frame/transaction-storage/src//weights.rs +// --template=.maintain/frame-weight-template.hbs +// --header=HEADER-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,7 +63,7 @@ impl WeightInfo for SubstrateWeight { fn store(l: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((8_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -73,7 +74,7 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - (67_532_000 as Weight) + (43_773_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -83,7 +84,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - (182_886_000 as Weight) + (139_490_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -100,7 +101,7 @@ impl WeightInfo for () { fn store(l: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((8_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -111,7 +112,7 @@ impl WeightInfo for () { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - (67_532_000 as Weight) + (43_773_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -121,7 +122,7 @@ impl WeightInfo for () { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - (182_886_000 as Weight) + (139_490_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index 79635ac2a725d..ebe823ddb8cef 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_treasury //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/treasury/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,34 +58,34 @@ impl WeightInfo for SubstrateWeight { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (41_567_000 as Weight) + (21_666_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (38_993_000 as Weight) + (25_008_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (13_543_000 as Weight) + (8_032_000 as Weight) // Standard Error: 1_000 - .saturating_add((55_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((66_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Treasury Approvals (r:1 w:1) - // Storage: Treasury BountyApprovals (r:1 w:1) + // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (51_708_000 as Weight) - // Standard Error: 21_000 - .saturating_add((57_926_000 as Weight).saturating_mul(p as Weight)) + (25_541_000 as Weight) + // Standard Error: 19_000 + .saturating_add((27_399_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -97,34 +98,34 @@ impl WeightInfo for () { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (41_567_000 as Weight) + (21_666_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (38_993_000 as Weight) + (25_008_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (13_543_000 as Weight) + (8_032_000 as Weight) // Standard Error: 1_000 - .saturating_add((55_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((66_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Treasury Approvals (r:1 w:1) - // Storage: Treasury BountyApprovals (r:1 w:1) + // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (51_708_000 as Weight) - // Standard Error: 21_000 - .saturating_add((57_926_000 as Weight).saturating_mul(p as Weight)) + (25_541_000 as Weight) + // Standard Error: 19_000 + .saturating_add((27_399_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 3a67eb09017be..190ce74bbaa57 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-02, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/uniques/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -75,14 +76,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (41_109_000 as Weight) + (23_715_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (22_986_000 as Weight) + (12_854_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -95,12 +96,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 14_000 - .saturating_add((14_879_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 14_000 - .saturating_add((1_058_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 14_000 - .saturating_add((956_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 13_000 + .saturating_add((9_291_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 13_000 + .saturating_add((957_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 13_000 + .saturating_add((862_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -112,7 +113,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (51_248_000 as Weight) + (29_659_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -120,7 +121,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (53_172_000 as Weight) + (31_363_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -128,7 +129,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (39_680_000 as Weight) + (23_596_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -136,8 +137,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 12_000 - .saturating_add((22_759_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 11_000 + .saturating_add((11_793_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -146,26 +147,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (27_833_000 as Weight) + (17_708_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (27_739_000 as Weight) + (17_959_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_class() -> Weight { - (20_890_000 as Weight) + (14_034_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_class() -> Weight { - (20_848_000 as Weight) + (13_751_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -173,20 +174,20 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (51_523_000 as Weight) + (31_328_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (22_034_000 as Weight) + (14_586_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_asset_status() -> Weight { - (25_877_000 as Weight) + (16_374_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -194,7 +195,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (63_365_000 as Weight) + (36_952_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -202,49 +203,49 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (56_849_000 as Weight) + (35_230_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (47_982_000 as Weight) + (28_148_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (47_340_000 as Weight) + (29_027_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_class_metadata() -> Weight { - (46_897_000 as Weight) + (27_535_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_class_metadata() -> Weight { - (41_745_000 as Weight) + (26_707_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (29_828_000 as Weight) + (19_108_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (29_759_000 as Weight) + (19_779_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -255,14 +256,14 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (41_109_000 as Weight) + (23_715_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (22_986_000 as Weight) + (12_854_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -275,12 +276,12 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 14_000 - .saturating_add((14_879_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 14_000 - .saturating_add((1_058_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 14_000 - .saturating_add((956_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 13_000 + .saturating_add((9_291_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 13_000 + .saturating_add((957_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 13_000 + .saturating_add((862_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -292,7 +293,7 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (51_248_000 as Weight) + (29_659_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -300,7 +301,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (53_172_000 as Weight) + (31_363_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -308,7 +309,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (39_680_000 as Weight) + (23_596_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -316,8 +317,8 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 12_000 - .saturating_add((22_759_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 11_000 + .saturating_add((11_793_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -326,26 +327,26 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (27_833_000 as Weight) + (17_708_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (27_739_000 as Weight) + (17_959_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_class() -> Weight { - (20_890_000 as Weight) + (14_034_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_class() -> Weight { - (20_848_000 as Weight) + (13_751_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -353,20 +354,20 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (51_523_000 as Weight) + (31_328_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (22_034_000 as Weight) + (14_586_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_asset_status() -> Weight { - (25_877_000 as Weight) + (16_374_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -374,7 +375,7 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (63_365_000 as Weight) + (36_952_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -382,49 +383,49 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (56_849_000 as Weight) + (35_230_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (47_982_000 as Weight) + (28_148_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (47_340_000 as Weight) + (29_027_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_class_metadata() -> Weight { - (46_897_000 as Weight) + (27_535_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_class_metadata() -> Weight { - (41_745_000 as Weight) + (26_707_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (29_828_000 as Weight) + (19_108_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (29_759_000 as Weight) + (19_779_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 15798007a9ba3..3d80691210de0 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_utility //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-10-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/utility/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,39 +56,39 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn batch(c: u32, ) -> Weight { - (18_293_000 as Weight) - // Standard Error: 3_000 - .saturating_add((5_530_000 as Weight).saturating_mul(c as Weight)) + (15_877_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_341_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (3_387_000 as Weight) + (1_754_000 as Weight) } fn batch_all(c: u32, ) -> Weight { - (19_223_000 as Weight) - // Standard Error: 4_000 - .saturating_add((5_998_000 as Weight).saturating_mul(c as Weight)) + (16_581_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_476_000 as Weight).saturating_mul(c as Weight)) } fn dispatch_as() -> Weight { - (14_340_000 as Weight) + (8_294_000 as Weight) } } // For backwards compatibility and tests impl WeightInfo for () { fn batch(c: u32, ) -> Weight { - (18_293_000 as Weight) - // Standard Error: 3_000 - .saturating_add((5_530_000 as Weight).saturating_mul(c as Weight)) + (15_877_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_341_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (3_387_000 as Weight) + (1_754_000 as Weight) } fn batch_all(c: u32, ) -> Weight { - (19_223_000 as Weight) - // Standard Error: 4_000 - .saturating_add((5_998_000 as Weight).saturating_mul(c as Weight)) + (16_581_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_476_000 as Weight).saturating_mul(c as Weight)) } fn dispatch_as() -> Weight { - (14_340_000 as Weight) + (8_294_000 as Weight) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index 660f839655579..caf1880daefda 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_vesting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-01-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/lto-fat-cg1/substrate // benchmark // --chain=dev // --steps=50 @@ -33,8 +33,9 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/vesting/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --template=.maintain/frame-weight-template.hbs +// --header=LICENSE-APACHE2 +// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -61,22 +62,22 @@ impl WeightInfo for SubstrateWeight { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - (50_642_000 as Weight) + (27_545_000 as Weight) // Standard Error: 1_000 - .saturating_add((144_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 3_000 - .saturating_add((177_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((111_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((78_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - (50_830_000 as Weight) + (27_638_000 as Weight) // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 3_000 - .saturating_add((112_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((102_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((41_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -84,11 +85,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - (52_151_000 as Weight) + (27_571_000 as Weight) // Standard Error: 1_000 - .saturating_add((130_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 3_000 - .saturating_add((162_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((105_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((76_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -96,11 +97,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - (51_009_000 as Weight) - // Standard Error: 4_000 - .saturating_add((123_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 9_000 - .saturating_add((118_000 as Weight).saturating_mul(s as Weight)) + (27_470_000 as Weight) + // Standard Error: 1_000 + .saturating_add((99_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -108,11 +109,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - (89_517_000 as Weight) - // Standard Error: 5_000 - .saturating_add((114_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 10_000 - .saturating_add((23_000 as Weight).saturating_mul(s as Weight)) + (42_886_000 as Weight) + // Standard Error: 1_000 + .saturating_add((100_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 3_000 + .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -120,11 +121,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - (87_903_000 as Weight) - // Standard Error: 6_000 - .saturating_add((121_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 12_000 - .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) + (42_528_000 as Weight) + // Standard Error: 1_000 + .saturating_add((104_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 3_000 + .saturating_add((46_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -132,11 +133,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (54_463_000 as Weight) + (28_372_000 as Weight) + // Standard Error: 1_000 + .saturating_add((110_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((123_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 5_000 - .saturating_add((149_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((71_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -144,11 +145,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (53_674_000 as Weight) + (28_117_000 as Weight) // Standard Error: 1_000 - .saturating_add((137_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 4_000 - .saturating_add((152_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((108_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((76_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -159,22 +160,22 @@ impl WeightInfo for () { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - (50_642_000 as Weight) + (27_545_000 as Weight) // Standard Error: 1_000 - .saturating_add((144_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 3_000 - .saturating_add((177_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((111_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((78_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - (50_830_000 as Weight) + (27_638_000 as Weight) // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 3_000 - .saturating_add((112_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((102_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((41_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -182,11 +183,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - (52_151_000 as Weight) + (27_571_000 as Weight) // Standard Error: 1_000 - .saturating_add((130_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 3_000 - .saturating_add((162_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((105_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((76_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -194,11 +195,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - (51_009_000 as Weight) - // Standard Error: 4_000 - .saturating_add((123_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 9_000 - .saturating_add((118_000 as Weight).saturating_mul(s as Weight)) + (27_470_000 as Weight) + // Standard Error: 1_000 + .saturating_add((99_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -206,11 +207,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - (89_517_000 as Weight) - // Standard Error: 5_000 - .saturating_add((114_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 10_000 - .saturating_add((23_000 as Weight).saturating_mul(s as Weight)) + (42_886_000 as Weight) + // Standard Error: 1_000 + .saturating_add((100_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 3_000 + .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -218,11 +219,11 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - (87_903_000 as Weight) - // Standard Error: 6_000 - .saturating_add((121_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 12_000 - .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) + (42_528_000 as Weight) + // Standard Error: 1_000 + .saturating_add((104_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 3_000 + .saturating_add((46_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -230,11 +231,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (54_463_000 as Weight) + (28_372_000 as Weight) + // Standard Error: 1_000 + .saturating_add((110_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((123_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 5_000 - .saturating_add((149_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((71_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -242,11 +243,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (53_674_000 as Weight) + (28_117_000 as Weight) // Standard Error: 1_000 - .saturating_add((137_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 4_000 - .saturating_add((152_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((108_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((76_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } From b0c14750c8403760c1bac61f20db512d129b1686 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 24 Jan 2022 17:18:13 +0100 Subject: [PATCH 0455/1472] Proposal: Defensive trait for infallible frame operations (#10626) * add a blueprint of how defensive traits could look like * add something for arithmetic as well * add some use cases in different pallets * some build fixing * Some new stuff and examples * Fix deadly bug * add more doc. * undo faulty change to assets pallet * Update frame/support/src/traits/misc.rs Co-authored-by: Oliver Tale-Yazdi * some review comments * remove draft comment * Fix ident test * Fix proxy tests as well * a few new ideas * Fix build * Fix doc Co-authored-by: Oliver Tale-Yazdi --- frame/balances/src/lib.rs | 24 +- frame/democracy/src/lib.rs | 3 +- .../src/signed.rs | 4 +- frame/election-provider-support/src/lib.rs | 2 +- frame/elections-phragmen/src/lib.rs | 8 +- frame/gilt/src/lib.rs | 11 +- frame/identity/src/benchmarking.rs | 2 +- frame/proxy/src/benchmarking.rs | 16 +- frame/staking/src/pallet/impls.rs | 10 +- frame/support/src/traits.rs | 11 +- frame/support/src/traits/misc.rs | 355 ++++++++++++++++++ 11 files changed, 402 insertions(+), 44 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index f94afec069422..8a6d54b54c8dc 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -170,7 +170,7 @@ use frame_support::{ pallet_prelude::DispatchResult, traits::{ tokens::{fungible, BalanceStatus as Status, DepositConsequence, WithdrawConsequence}, - Currency, ExistenceRequirement, + Currency, DefensiveSaturating, ExistenceRequirement, ExistenceRequirement::{AllowDeath, KeepAlive}, Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency, OnUnbalanced, ReservableCurrency, SignedImbalance, StoredMap, TryDrop, WithdrawReasons, @@ -1783,7 +1783,7 @@ where account.reserved -= actual; // defensive only: this can never fail since total issuance which is at least // free+reserved fits into the same data type. - account.free = account.free.saturating_add(actual); + account.free = account.free.defensive_saturating_add(actual); actual }) { Ok(x) => x, @@ -1896,7 +1896,7 @@ where match reserves.binary_search_by_key(id, |data| data.id) { Ok(index) => { // this add can't overflow but just to be defensive. - reserves[index].amount = reserves[index].amount.saturating_add(value); + reserves[index].amount = reserves[index].amount.defensive_saturating_add(value); }, Err(index) => { reserves @@ -1929,8 +1929,8 @@ where let remain = >::unreserve(who, to_change); - // remain should always be zero but just to be defensive here - let actual = to_change.saturating_sub(remain); + // remain should always be zero but just to be defensive here. + let actual = to_change.defensive_saturating_sub(remain); // `actual <= to_change` and `to_change <= amount`; qed; reserves[index].amount -= actual; @@ -1976,8 +1976,8 @@ where let (imb, remain) = >::slash_reserved(who, to_change); - // remain should always be zero but just to be defensive here - let actual = to_change.saturating_sub(remain); + // remain should always be zero but just to be defensive here. + let actual = to_change.defensive_saturating_sub(remain); // `actual <= to_change` and `to_change <= amount`; qed; reserves[index].amount -= actual; @@ -2036,12 +2036,12 @@ where )?; // remain should always be zero but just to be defensive - // here - let actual = to_change.saturating_sub(remain); + // here. + let actual = to_change.defensive_saturating_sub(remain); // this add can't overflow but just to be defensive. reserves[index].amount = - reserves[index].amount.saturating_add(actual); + reserves[index].amount.defensive_saturating_add(actual); Ok(actual) }, @@ -2056,7 +2056,7 @@ where // remain should always be zero but just to be defensive // here - let actual = to_change.saturating_sub(remain); + let actual = to_change.defensive_saturating_sub(remain); reserves .try_insert( @@ -2079,7 +2079,7 @@ where )?; // remain should always be zero but just to be defensive here - to_change.saturating_sub(remain) + to_change.defensive_saturating_sub(remain) }; // `actual <= to_change` and `to_change <= amount`; qed; diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 1c052ad2d4176..4580767d875c3 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -156,6 +156,7 @@ use codec::{Decode, Encode, Input}; use frame_support::{ ensure, traits::{ + defensive_prelude::*, schedule::{DispatchTime, Named as ScheduleNamed}, BalanceStatus, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, ReservableCurrency, WithdrawReasons, @@ -1630,7 +1631,7 @@ impl Pallet { let mut public_props = Self::public_props(); if let Some((winner_index, _)) = public_props.iter().enumerate().max_by_key( // defensive only: All current public proposals have an amount locked - |x| Self::backing_for((x.1).0).unwrap_or_else(Zero::zero), + |x| Self::backing_for((x.1).0).defensive_unwrap_or_else(Zero::zero), ) { let (prop_index, proposal, _) = public_props.swap_remove(winner_index); >::put(public_props); diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index c2cb5cf44823e..3b314bce80ffe 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -25,7 +25,7 @@ use crate::{ use codec::{Decode, Encode, HasCompact}; use frame_support::{ storage::bounded_btree_map::BoundedBTreeMap, - traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, + traits::{defensive_prelude::*, Currency, Get, OnUnbalanced, ReservableCurrency}, }; use sp_arithmetic::traits::SaturatedConversion; use sp_npos_elections::{is_score_better, ElectionScore, NposSolution}; @@ -365,7 +365,7 @@ impl Pallet { let active_voters = raw_solution.solution.voter_count() as u32; let feasibility_weight = { // defensive only: at the end of signed phase, snapshot will exits. - let desired_targets = Self::desired_targets().unwrap_or_default(); + let desired_targets = Self::desired_targets().defensive_unwrap_or_default(); T::WeightInfo::feasibility_check(voters, targets, active_voters, desired_targets) }; // the feasibility check itself has some weight diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index d10504c88cc67..889606da3428a 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -343,7 +343,7 @@ impl ElectionProvider for NoElection<(AccountId, BlockNu /// used on the implementing side of [`ElectionDataProvider`]. pub trait SortedListProvider { /// The list's error type. - type Error; + type Error: sp_std::fmt::Debug; /// An iterator over the list, which can have `take` called on it. fn iter() -> Box>; diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 7f576144d1368..2c53bb2222b76 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -102,9 +102,9 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::WithPostDispatchInfo, traits::{ - ChangeMembers, Contains, ContainsLengthBound, Currency, CurrencyToVote, Get, - InitializeMembers, LockIdentifier, LockableCurrency, OnUnbalanced, ReservableCurrency, - SortedMembers, StorageVersion, WithdrawReasons, + defensive_prelude::*, ChangeMembers, Contains, ContainsLengthBound, Currency, + CurrencyToVote, Get, InitializeMembers, LockIdentifier, LockableCurrency, OnUnbalanced, + ReservableCurrency, SortedMembers, StorageVersion, WithdrawReasons, }, weights::Weight, }; @@ -1028,7 +1028,7 @@ impl Pallet { candidates_and_deposit .iter() .find_map(|(c, d)| if c == x { Some(*d) } else { None }) - .unwrap_or_default() + .defensive_unwrap_or_default() }; // fetch deposits from the one recorded one. This will make sure that a candidate who // submitted candidacy before a change to candidacy deposit will have the correct amount diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index 6211b15d8c8c3..ac56dc108b2f6 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -79,7 +79,7 @@ pub mod pallet { pub use crate::weights::WeightInfo; use frame_support::{ pallet_prelude::*, - traits::{Currency, OnUnbalanced, ReservableCurrency}, + traits::{Currency, DefensiveSaturating, OnUnbalanced, ReservableCurrency}, }; use frame_system::pallet_prelude::*; use sp_arithmetic::{PerThing, Perquintill}; @@ -599,10 +599,12 @@ pub mod pallet { remaining -= amount; // Should never underflow since it should track the total of the // bids exactly, but we'll be defensive. - qs[queue_index].1 = qs[queue_index].1.saturating_sub(bid.amount); + qs[queue_index].1 = + qs[queue_index].1.defensive_saturating_sub(bid.amount); // Now to activate the bid... - let nongilt_issuance = total_issuance.saturating_sub(totals.frozen); + let nongilt_issuance = + total_issuance.defensive_saturating_sub(totals.frozen); let effective_issuance = totals .proportion .left_from_one() @@ -613,7 +615,8 @@ pub mod pallet { let who = bid.who; let index = totals.index; totals.frozen += bid.amount; - totals.proportion = totals.proportion.saturating_add(proportion); + totals.proportion = + totals.proportion.defensive_saturating_add(proportion); totals.index += 1; let e = Event::GiltIssued { index, expiry, who: who.clone(), amount }; diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 2f52aff394b7e..2145779ecf541 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -75,7 +75,7 @@ fn create_sub_accounts( } // Set identity so `set_subs` does not fail. - let _ = T::Currency::make_free_balance_be(&who, BalanceOf::::max_value()); + let _ = T::Currency::make_free_balance_be(&who, BalanceOf::::max_value() / 2u32.into()); let info = create_identity_info::(1); Identity::::set_identity(who_origin.clone().into(), Box::new(info))?; diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index ceed2e6ab22dc..f3098c6ad1274 100644 --- a/frame/proxy/src/benchmarking.rs +++ b/frame/proxy/src/benchmarking.rs @@ -33,7 +33,7 @@ fn assert_last_event(generic_event: ::Event) { fn add_proxies(n: u32, maybe_who: Option) -> Result<(), &'static str> { let caller = maybe_who.unwrap_or_else(|| whitelisted_caller()); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); for i in 0..n { Proxy::::add_proxy( RawOrigin::Signed(caller.clone()).into(), @@ -51,12 +51,12 @@ fn add_announcements( maybe_real: Option, ) -> Result<(), &'static str> { let caller = maybe_who.unwrap_or_else(|| account("caller", 0, SEED)); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); let real = if let Some(real) = maybe_real { real } else { let real = account("real", 0, SEED); - T::Currency::make_free_balance_be(&real, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&real, BalanceOf::::max_value() / 2u32.into()); Proxy::::add_proxy( RawOrigin::Signed(real.clone()).into(), caller.clone(), @@ -80,7 +80,7 @@ benchmarks! { let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); @@ -95,7 +95,7 @@ benchmarks! { // In this case the caller is the "target" proxy let caller: T::AccountId = account("anonymous", 0, SEED); let delegate: T::AccountId = account("target", p - 1, SEED); - T::Currency::make_free_balance_be(&delegate, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&delegate, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); @@ -115,7 +115,7 @@ benchmarks! { let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); @@ -136,7 +136,7 @@ benchmarks! { let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); @@ -157,7 +157,7 @@ benchmarks! { let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); add_announcements::(a, Some(caller.clone()), None)?; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 68b5c19027a9b..a72d2774dee2a 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -24,8 +24,8 @@ use frame_election_provider_support::{ use frame_support::{ pallet_prelude::*, traits::{ - Currency, CurrencyToVote, EstimateNextNewSession, Get, Imbalance, LockableCurrency, - OnUnbalanced, UnixTime, WithdrawReasons, + Currency, CurrencyToVote, Defensive, EstimateNextNewSession, Get, Imbalance, + LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, }, weights::{Weight, WithPostDispatchInfo}, }; @@ -775,10 +775,8 @@ impl Pallet { pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { if !Nominators::::contains_key(who) { // maybe update sorted list. Error checking is defensive-only - this should never fail. - if T::SortedListProvider::on_insert(who.clone(), Self::weight_of(who)).is_err() { - log!(warn, "attempt to insert duplicate nominator ({:#?})", who); - debug_assert!(false, "attempt to insert duplicate nominator"); - }; + let _ = T::SortedListProvider::on_insert(who.clone(), Self::weight_of(who)) + .defensive_unwrap_or_default(); debug_assert_eq!(T::SortedListProvider::sanity_check(), Ok(())); } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 85a0698759b69..1928023cfe66d 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -50,12 +50,13 @@ pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter mod misc; pub use misc::{ + defensive_prelude::{self, *}, Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, - ConstU32, ConstU64, ConstU8, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, - ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, - Len, OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider, PreimageRecipient, - PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, UnixTime, WrapperKeepOpaque, - WrapperOpaque, + ConstU32, ConstU64, ConstU8, DefensiveSaturating, EnsureInherentsAreFirst, EqualPrivilegeOnly, + EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, + IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider, + PreimageRecipient, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, UnixTime, + WrapperKeepOpaque, WrapperOpaque, }; mod stored_map; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index df21624c3cea0..eaada3ea2c363 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -20,9 +20,363 @@ use crate::dispatch::Parameter; use codec::{CompactLen, Decode, DecodeAll, Encode, EncodeLike, Input, MaxEncodedLen}; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; +use sp_arithmetic::traits::{CheckedAdd, CheckedMul, CheckedSub, Saturating}; use sp_runtime::{traits::Block as BlockT, DispatchError}; use sp_std::{cmp::Ordering, prelude::*}; +const DEFENSIVE_OP_PUBLIC_ERROR: &'static str = "a defensive failure has been triggered; please report the block number at https://github.com/paritytech/substrate/issues"; +const DEFENSIVE_OP_INTERNAL_ERROR: &'static str = "Defensive failure has been triggered!"; + +/// Prelude module for all defensive traits to be imported at once. +pub mod defensive_prelude { + pub use super::{Defensive, DefensiveOption, DefensiveResult}; +} + +/// A trait to handle errors and options when you are really sure that a condition must hold, but +/// not brave enough to `expect` on it, or a default fallback value makes more sense. +/// +/// This trait mostly focuses on methods that eventually unwrap the inner value. See +/// [`DefensiveResult`] and [`DefensiveOption`] for methods that specifically apply to the +/// respective types. +/// +/// Each function in this trait will have two side effects, aside from behaving exactly as the name +/// would suggest: +/// +/// 1. It panics on `#[debug_assertions]`, so if the infallible code is reached in any of the tests, +/// you realize. +/// 2. It will log an error using the runtime logging system. This might help you detect such bugs +/// in production as well. Note that the log message, as of now, are not super expressive. Your +/// best shot of fully diagnosing the error would be to infer the block number of which the log +/// message was emitted, then re-execute that block using `check-block` or `try-runtime` +/// subcommands in substrate client. +pub trait Defensive { + /// Exactly the same as `unwrap_or`, but it does the defensive warnings explained in the trait + /// docs. + fn defensive_unwrap_or(self, other: T) -> T; + + /// Exactly the same as `unwrap_or_else`, but it does the defensive warnings explained in the + /// trait docs. + fn defensive_unwrap_or_else T>(self, f: F) -> T; + + /// Exactly the same as `unwrap_or_default`, but it does the defensive warnings explained in the + /// trait docs. + fn defensive_unwrap_or_default(self) -> T + where + T: Default; + + /// Does not alter the inner value at all, but it will log warnings if the inner value is `None` + /// or `Err`. + /// + /// In some ways, this is like `.defensive_map(|x| x)`. + /// + /// This is useful as: + /// ```nocompile + /// if let Some(inner) = maybe_value().defensive() { + /// .. + /// } + /// ``` + fn defensive(self) -> Self; +} + +/// Subset of methods similar to [`Defensive`] that can only work for a `Result`. +pub trait DefensiveResult { + /// Defensively map the error into another return type, but you are really sure that this + /// conversion should never be needed. + fn defensive_map_err F>(self, o: O) -> Result; + + /// Defensively map and unpack the value to something else (`U`), or call the default callback + /// if `Err`, which should never happen. + fn defensive_map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U; + + /// Defensively transform this result into an option, discarding the `Err` variant if it + /// happens, which should never happen. + fn defensive_ok(self) -> Option; + + /// Exactly the same as `map`, but it prints the appropriate warnings if the value being mapped + /// is `Err`. + fn defensive_map U>(self, f: F) -> Result; +} + +/// Subset of methods similar to [`Defensive`] that can only work for a `Option`. +pub trait DefensiveOption { + /// Potentially map and unpack the value to something else (`U`), or call the default callback + /// if `None`, which should never happen. + fn defensive_map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U; + + /// Defensively transform this option to a result. + fn defensive_ok_or_else E>(self, err: F) -> Result; + + /// Exactly the same as `map`, but it prints the appropriate warnings if the value being mapped + /// is `None`. + fn defensive_map U>(self, f: F) -> Option; +} + +impl Defensive for Option { + fn defensive_unwrap_or(self, or: T) -> T { + match self { + Some(inner) => inner, + None => { + debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); + frame_support::log::error!( + target: "runtime", + "{}", + DEFENSIVE_OP_PUBLIC_ERROR + ); + or + }, + } + } + + fn defensive_unwrap_or_else T>(self, f: F) -> T { + match self { + Some(inner) => inner, + None => { + debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); + frame_support::log::error!( + target: "runtime", + "{}", + DEFENSIVE_OP_PUBLIC_ERROR + ); + f() + }, + } + } + + fn defensive_unwrap_or_default(self) -> T + where + T: Default, + { + match self { + Some(inner) => inner, + None => { + debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); + frame_support::log::error!( + target: "runtime", + "{}", + DEFENSIVE_OP_PUBLIC_ERROR + ); + Default::default() + }, + } + } + + fn defensive(self) -> Self { + match self { + Some(inner) => Some(inner), + None => { + debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); + frame_support::log::error!( + target: "runtime", + "{}", + DEFENSIVE_OP_PUBLIC_ERROR + ); + None + }, + } + } +} + +impl Defensive for Result { + fn defensive_unwrap_or(self, or: T) -> T { + match self { + Ok(inner) => inner, + Err(e) => { + debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); + frame_support::log::error!( + target: "runtime", + "{}: {:?}", + DEFENSIVE_OP_PUBLIC_ERROR, + e + ); + or + }, + } + } + + fn defensive_unwrap_or_else T>(self, f: F) -> T { + match self { + Ok(inner) => inner, + Err(e) => { + debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); + frame_support::log::error!( + target: "runtime", + "{}: {:?}", + DEFENSIVE_OP_PUBLIC_ERROR, + e + ); + f() + }, + } + } + + fn defensive_unwrap_or_default(self) -> T + where + T: Default, + { + match self { + Ok(inner) => inner, + Err(e) => { + debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); + frame_support::log::error!( + target: "runtime", + "{}: {:?}", + DEFENSIVE_OP_PUBLIC_ERROR, + e + ); + Default::default() + }, + } + } + + fn defensive(self) -> Self { + match self { + Ok(inner) => Ok(inner), + Err(e) => { + debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); + frame_support::log::error!( + target: "runtime", + "{}: {:?}", + DEFENSIVE_OP_PUBLIC_ERROR, + e + ); + Err(e) + }, + } + } +} + +impl DefensiveResult for Result { + fn defensive_map_err F>(self, o: O) -> Result { + self.map_err(|e| { + debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); + frame_support::log::error!( + target: "runtime", + "{}: {:?}", + DEFENSIVE_OP_PUBLIC_ERROR, + e + ); + o(e) + }) + } + + fn defensive_map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { + self.map_or_else( + |e| { + debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); + frame_support::log::error!( + target: "runtime", + "{}: {:?}", + DEFENSIVE_OP_PUBLIC_ERROR, + e + ); + default(e) + }, + f, + ) + } + + fn defensive_ok(self) -> Option { + match self { + Ok(inner) => Some(inner), + Err(e) => { + debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); + frame_support::log::error!( + target: "runtime", + "{}: {:?}", + DEFENSIVE_OP_PUBLIC_ERROR, + e + ); + None + }, + } + } + + fn defensive_map U>(self, f: F) -> Result { + match self { + Ok(inner) => Ok(f(inner)), + Err(e) => { + debug_assert!(false, "{}: {:?}", DEFENSIVE_OP_INTERNAL_ERROR, e); + frame_support::log::error!( + target: "runtime", + "{}: {:?}", + DEFENSIVE_OP_PUBLIC_ERROR, + e + ); + Err(e) + }, + } + } +} + +impl DefensiveOption for Option { + fn defensive_map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { + self.map_or_else( + || { + debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); + frame_support::log::error!( + target: "runtime", + "{}", + DEFENSIVE_OP_PUBLIC_ERROR, + ); + default() + }, + f, + ) + } + + fn defensive_ok_or_else E>(self, err: F) -> Result { + self.ok_or_else(|| { + debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); + frame_support::log::error!( + target: "runtime", + "{}", + DEFENSIVE_OP_PUBLIC_ERROR, + ); + err() + }) + } + + fn defensive_map U>(self, f: F) -> Option { + match self { + Some(inner) => Some(f(inner)), + None => { + debug_assert!(false, "{}", DEFENSIVE_OP_INTERNAL_ERROR); + frame_support::log::error!( + target: "runtime", + "{}", + DEFENSIVE_OP_PUBLIC_ERROR, + ); + None + }, + } + } +} + +/// A variant of [`Defensive`] with the same rationale, for the arithmetic operations where in +/// case an infallible operation fails, it saturates. +pub trait DefensiveSaturating { + /// Add `self` and `other` defensively. + fn defensive_saturating_add(self, other: Self) -> Self; + /// Subtract `other` from `self` defensively. + fn defensive_saturating_sub(self, other: Self) -> Self; + /// Multiply `self` and `other` defensively. + fn defensive_saturating_mul(self, other: Self) -> Self; +} + +// NOTE: A bit unfortunate, since T has to be bound by all the traits needed. Could make it +// `DefensiveSaturating` to mitigate. +impl DefensiveSaturating for T { + fn defensive_saturating_add(self, other: Self) -> Self { + self.checked_add(&other).defensive_unwrap_or_else(|| self.saturating_add(other)) + } + fn defensive_saturating_sub(self, other: Self) -> Self { + self.checked_sub(&other).defensive_unwrap_or_else(|| self.saturating_sub(other)) + } + fn defensive_saturating_mul(self, other: Self) -> Self { + self.checked_mul(&other).defensive_unwrap_or_else(|| self.saturating_mul(other)) + } +} + /// Try and collect into a collection `C`. pub trait TryCollect { type Error; @@ -72,6 +426,7 @@ impl Get for GetDefault { macro_rules! impl_const_get { ($name:ident, $t:ty) => { + #[derive($crate::RuntimeDebug)] pub struct $name; impl Get<$t> for $name { fn get() -> $t { From 511e8c860aa448c6899f884eebe64131a65300b8 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Tue, 25 Jan 2022 00:28:46 +0800 Subject: [PATCH 0456/1472] use clap3 instead of structopt (#10632) * use clap3 instead of structopt Signed-off-by: koushiro * format Signed-off-by: koushiro * update ss58-registry and revert some nits Signed-off-by: koushiro * Fix clippy and doc Signed-off-by: koushiro * update clap to 3.0.7 Signed-off-by: koushiro * Apply review suggestions Signed-off-by: koushiro * remove useless option long name Signed-off-by: koushiro * cargo fmt Signed-off-by: koushiro --- .maintain/node-template-release/Cargo.toml | 2 +- .maintain/node-template-release/src/main.rs | 13 +- Cargo.lock | 152 ++++++++++-------- bin/node-template/node/Cargo.toml | 6 +- bin/node-template/node/src/cli.rs | 13 +- bin/node/bench/Cargo.toml | 6 +- bin/node/bench/src/main.rs | 16 +- bin/node/cli/Cargo.toml | 25 ++- bin/node/cli/build.rs | 8 +- bin/node/cli/src/cli.rs | 31 ++-- bin/node/inspect/Cargo.toml | 2 +- bin/node/inspect/src/cli.rs | 16 +- bin/utils/chain-spec-builder/Cargo.toml | 5 +- bin/utils/chain-spec-builder/src/main.rs | 32 ++-- bin/utils/subkey/Cargo.toml | 2 +- bin/utils/subkey/src/lib.rs | 8 +- client/cli/Cargo.toml | 49 +++--- client/cli/src/arg_enums.rs | 141 ++++++++-------- client/cli/src/commands/build_spec_cmd.rs | 12 +- client/cli/src/commands/check_block_cmd.rs | 12 +- client/cli/src/commands/export_blocks_cmd.rs | 18 +-- client/cli/src/commands/export_state_cmd.rs | 10 +- client/cli/src/commands/generate.rs | 21 ++- client/cli/src/commands/generate_node_key.rs | 10 +- client/cli/src/commands/import_blocks_cmd.rs | 14 +- client/cli/src/commands/insert_key.rs | 24 ++- client/cli/src/commands/inspect_key.rs | 27 ++-- client/cli/src/commands/inspect_node_key.rs | 14 +- client/cli/src/commands/key.rs | 6 +- client/cli/src/commands/purge_chain_cmd.rs | 10 +- client/cli/src/commands/revert_cmd.rs | 10 +- client/cli/src/commands/run_cmd.rs | 97 +++++------ client/cli/src/commands/sign.rs | 21 ++- client/cli/src/commands/vanity.rs | 17 +- client/cli/src/commands/verify.rs | 12 +- client/cli/src/error.rs | 2 +- client/cli/src/lib.rs | 61 +++---- client/cli/src/params/database_params.rs | 14 +- client/cli/src/params/import_params.rs | 67 +++----- client/cli/src/params/keystore_params.rs | 25 ++- client/cli/src/params/mod.rs | 30 ++-- client/cli/src/params/network_params.rs | 40 ++--- client/cli/src/params/node_key_params.rs | 25 ++- .../cli/src/params/offchain_worker_params.rs | 12 +- client/cli/src/params/pruning_params.rs | 8 +- client/cli/src/params/shared_params.rs | 28 ++-- .../cli/src/params/transaction_pool_params.rs | 8 +- frame/bags-list/remote-tests/Cargo.toml | 4 +- primitives/core/Cargo.toml | 16 +- primitives/npos-elections/fuzzer/Cargo.toml | 7 +- .../npos-elections/fuzzer/src/common.rs | 12 +- .../npos-elections/fuzzer/src/phragmen_pjr.rs | 13 +- .../npos-elections/fuzzer/src/reduce.rs | 7 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/benchmarking-cli/src/lib.rs | 59 ++++--- utils/frame/frame-utilities-cli/Cargo.toml | 3 +- .../frame-utilities-cli/src/pallet_id.rs | 16 +- utils/frame/generate-bags/Cargo.toml | 1 - .../generate-bags/node-runtime/Cargo.toml | 2 +- .../generate-bags/node-runtime/src/main.rs | 13 +- utils/frame/try-runtime/cli/Cargo.toml | 7 +- .../cli/src/commands/execute_block.rs | 16 +- .../cli/src/commands/follow_chain.rs | 8 +- .../cli/src/commands/offchain_worker.rs | 14 +- .../cli/src/commands/on_runtime_upgrade.rs | 4 +- utils/frame/try-runtime/cli/src/lib.rs | 46 +++--- 66 files changed, 662 insertions(+), 770 deletions(-) diff --git a/.maintain/node-template-release/Cargo.toml b/.maintain/node-template-release/Cargo.toml index 26256e8363301..667281f6dcad7 100644 --- a/.maintain/node-template-release/Cargo.toml +++ b/.maintain/node-template-release/Cargo.toml @@ -9,7 +9,7 @@ license = "GPL-3.0" toml = "0.4" tar = "0.4" glob = "0.2" -structopt = "0.3" +clap = { version = "3.0", features = ["derive"] } tempfile = "3" fs_extra = "1" git2 = "0.8" diff --git a/.maintain/node-template-release/src/main.rs b/.maintain/node-template-release/src/main.rs index 7dcb1f0f4d816..62e9b66715768 100644 --- a/.maintain/node-template-release/src/main.rs +++ b/.maintain/node-template-release/src/main.rs @@ -1,4 +1,4 @@ -use structopt::StructOpt; +use clap::Parser; use std::{ collections::HashMap, @@ -26,13 +26,13 @@ const SUBSTRATE_GIT_URL: &str = "https://github.com/paritytech/substrate.git"; type CargoToml = HashMap; -#[derive(StructOpt)] +#[derive(Parser)] struct Options { /// The path to the `node-template` source. - #[structopt(parse(from_os_str))] + #[clap(parse(from_os_str))] node_template: PathBuf, /// The path where to output the generated `tar.gz` file. - #[structopt(parse(from_os_str))] + #[clap(parse(from_os_str))] output: PathBuf, } @@ -209,7 +209,7 @@ fn build_and_test(path: &Path, cargo_tomls: &[PathBuf]) { } fn main() { - let options = Options::from_args(); + let options = Options::parse(); let build_dir = tempfile::tempdir().expect("Creates temp build dir"); @@ -261,8 +261,7 @@ fn main() { // adding root rustfmt to node template build path let node_template_rustfmt_toml_path = node_template_path.join("rustfmt.toml"); - let root_rustfmt_toml = - &options.node_template.join("../../rustfmt.toml"); + let root_rustfmt_toml = &options.node_template.join("../../rustfmt.toml"); if root_rustfmt_toml.exists() { fs::copy(&root_rustfmt_toml, &node_template_rustfmt_toml_path) .expect("Copying rustfmt.toml."); diff --git a/Cargo.lock b/Cargo.lock index 580da5ad074c3..39cb42be7a857 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -928,13 +928,13 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", + "clap 3.0.7", "node-cli", - "rand 0.7.3", + "rand 0.8.4", "sc-chain-spec", "sc-keystore", "sp-core", "sp-keystore", - "structopt", ] [[package]] @@ -996,13 +996,48 @@ 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", + "textwrap 0.11.0", "unicode-width", - "vec_map", +] + +[[package]] +name = "clap" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12e8611f9ae4e068fa3e56931fded356ff745e70987ff76924a6e0ab1c8ef2e3" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap 0.14.2", +] + +[[package]] +name = "clap_complete" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a394f7ec0715b42a4e52b294984c27c9a61f77c8d82f7774c5198350be143f19" +dependencies = [ + "clap 3.0.7", +] + +[[package]] +name = "clap_derive" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a0645a430ec9136d2d701e54a95d557de12649a9dd7109ced3187e648ac824" +dependencies = [ + "heck 0.4.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1256,7 +1291,7 @@ checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ "atty", "cast", - "clap", + "clap 2.34.0", "criterion-plot", "csv", "futures 0.3.16", @@ -1483,7 +1518,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", + "strsim", "syn", ] @@ -1741,7 +1776,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" dependencies = [ - "heck", + "heck 0.3.2", "proc-macro2", "quote", "syn", @@ -2020,6 +2055,7 @@ version = "4.0.0-dev" dependencies = [ "Inflector", "chrono", + "clap 3.0.7", "frame-benchmarking", "frame-support", "handlebars", @@ -2036,7 +2072,6 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-state-machine", - "structopt", ] [[package]] @@ -2450,7 +2485,6 @@ dependencies = [ "num-format", "pallet-staking", "sp-io", - "structopt", ] [[package]] @@ -2653,6 +2687,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.1.18" @@ -4516,6 +4556,7 @@ dependencies = [ name = "node-bench" version = "0.9.0-dev" dependencies = [ + "clap 3.0.7", "derive_more", "fs_extra", "futures 0.3.16", @@ -4545,7 +4586,6 @@ dependencies = [ "sp-timestamp", "sp-tracing", "sp-trie", - "structopt", "tempfile", ] @@ -4555,6 +4595,8 @@ version = "3.0.0-dev" dependencies = [ "assert_cmd", "async-std", + "clap 3.0.7", + "clap_complete", "criterion", "frame-benchmarking-cli", "frame-system", @@ -4576,7 +4618,7 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "platforms", - "rand 0.7.3", + "rand 0.8.4", "regex", "remote-externalities", "sc-authority-discovery", @@ -4622,7 +4664,6 @@ dependencies = [ "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", - "structopt", "substrate-build-script-utils", "substrate-frame-cli", "tempfile", @@ -4668,6 +4709,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ + "clap 3.0.7", "derive_more", "parity-scale-codec", "sc-cli", @@ -4677,7 +4719,6 @@ dependencies = [ "sp-blockchain", "sp-core", "sp-runtime", - "structopt", ] [[package]] @@ -4811,15 +4852,16 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ + "clap 3.0.7", "generate-bags", "node-runtime", - "structopt", ] [[package]] name = "node-template" version = "3.0.0" dependencies = [ + "clap 3.0.7", "frame-benchmarking", "frame-benchmarking-cli", "jsonrpc-core", @@ -4848,7 +4890,6 @@ dependencies = [ "sp-finality-grandpa", "sp-runtime", "sp-timestamp", - "structopt", "substrate-build-script-utils", "substrate-frame-rpc-system", ] @@ -5140,6 +5181,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + [[package]] name = "output_vt100" version = "0.1.2" @@ -5323,7 +5373,6 @@ dependencies = [ name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" dependencies = [ - "clap", "frame-election-provider-support", "frame-support", "frame-system", @@ -5336,7 +5385,6 @@ dependencies = [ "sp-std", "sp-storage", "sp-tracing", - "structopt", "tokio", ] @@ -6912,7 +6960,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" dependencies = [ "bytes 1.1.0", - "heck", + "heck 0.3.2", "itertools", "lazy_static", "log 0.4.14", @@ -7695,6 +7743,7 @@ name = "sc-cli" version = "0.10.0-dev" dependencies = [ "chrono", + "clap 3.0.7", "fdlimit", "futures 0.3.16", "hex", @@ -7721,7 +7770,6 @@ dependencies = [ "sp-panic-handler", "sp-runtime", "sp-version", - "structopt", "tempfile", "thiserror", "tiny-bip39", @@ -9624,13 +9672,13 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ + "clap 3.0.7", "honggfuzz", "parity-scale-codec", - "rand 0.7.3", + "rand 0.8.4", "scale-info", "sp-npos-elections", "sp-runtime", - "structopt", ] [[package]] @@ -10001,9 +10049,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "ss58-registry" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83f0afe7e571565ef9aae7b0e4fb30fcaec4ebb9aea2f00489b772782aa03a4" +checksum = "1230685dc82f8699110640244d361a7099c602f08bddc5c90765a5153b4881dc" dependencies = [ "Inflector", "proc-macro2", @@ -10038,42 +10086,12 @@ dependencies = [ "rand 0.8.4", ] -[[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.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c" -dependencies = [ - "clap", - "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", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "strum" version = "0.22.0" @@ -10089,7 +10107,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb" dependencies = [ - "heck", + "heck 0.3.2", "proc-macro2", "quote", "syn", @@ -10101,7 +10119,7 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38" dependencies = [ - "heck", + "heck 0.3.2", "proc-macro2", "quote", "rustversion", @@ -10112,8 +10130,8 @@ dependencies = [ name = "subkey" version = "2.0.1" dependencies = [ + "clap 3.0.7", "sc-cli", - "structopt", ] [[package]] @@ -10140,12 +10158,12 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ + "clap 3.0.7", "frame-support", "frame-system", "sc-cli", "sp-core", "sp-runtime", - "structopt", ] [[package]] @@ -10428,6 +10446,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" + [[package]] name = "thiserror" version = "1.0.30" @@ -10920,6 +10944,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ + "clap 3.0.7", "jsonrpsee", "log 0.4.14", "parity-scale-codec", @@ -10936,7 +10961,6 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-version", - "structopt", "zstd", ] @@ -11146,12 +11170,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" -[[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.1.5" diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 2b280e1bf00de..6b69d691d9450 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] name = "node-template" [dependencies] -structopt = "0.3.25" +clap = { version = "3.0", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } @@ -59,6 +59,4 @@ substrate-build-script-utils = { version = "3.0.0", path = "../../../utils/build [features] default = [] -runtime-benchmarks = [ - "node-template-runtime/runtime-benchmarks", -] +runtime-benchmarks = ["node-template-runtime/runtime-benchmarks"] diff --git a/bin/node-template/node/src/cli.rs b/bin/node-template/node/src/cli.rs index 8ed1d35ba5f92..d787f57f071a6 100644 --- a/bin/node-template/node/src/cli.rs +++ b/bin/node-template/node/src/cli.rs @@ -1,19 +1,20 @@ use sc_cli::RunCmd; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, clap::Parser)] pub struct Cli { - #[structopt(subcommand)] + #[clap(subcommand)] pub subcommand: Option, - #[structopt(flatten)] + #[clap(flatten)] pub run: RunCmd, } -#[derive(Debug, StructOpt)] +#[derive(Debug, clap::Subcommand)] pub enum Subcommand { /// Key management cli utilities + #[clap(subcommand)] Key(sc_cli::KeySubcommand), + /// Build a chain specification. BuildSpec(sc_cli::BuildSpecCmd), @@ -36,6 +37,6 @@ pub enum Subcommand { Revert(sc_cli::RevertCmd), /// The custom benchmark subcommand benchmarking runtime pallets. - #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] + #[clap(name = "benchmark", about = "Benchmark runtime pallets.")] Benchmark(frame_benchmarking_cli::BenchmarkCmd), } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 670f6c4d3ed84..6c28f14793a92 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -9,6 +9,7 @@ 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] +clap = { version = "3.0", features = ["derive"] } log = "0.4.8" node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } @@ -18,7 +19,6 @@ sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } serde = "1.0.132" serde_json = "1.0.74" -structopt = "0.3" derive_more = "0.99.16" kvdb = "0.10.0" kvdb-rocksdb = "0.14.0" @@ -35,9 +35,7 @@ fs_extra = "1" hex = "0.4.0" rand = { version = "0.7.2", features = ["small_rng"] } lazy_static = "1.4.0" -parity-util-mem = { version = "0.10.2", default-features = false, features = [ - "primitive-types", -] } +parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } parity-db = { version = "0.3" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } diff --git a/bin/node/bench/src/main.rs b/bin/node/bench/src/main.rs index f1800214e3e81..0e50447d464fb 100644 --- a/bin/node/bench/src/main.rs +++ b/bin/node/bench/src/main.rs @@ -28,7 +28,7 @@ mod tempdb; mod trie; mod txpool; -use structopt::StructOpt; +use clap::Parser; use node_testing::bench::{BlockType, DatabaseType as BenchDataBaseType, KeyTypes, Profile}; @@ -42,19 +42,19 @@ use crate::{ txpool::PoolBenchmarkDescription, }; -#[derive(Debug, StructOpt)] -#[structopt(name = "node-bench", about = "Node integration benchmarks")] +#[derive(Debug, Parser)] +#[clap(name = "node-bench", about = "Node integration benchmarks")] struct Opt { /// Show list of all available benchmarks. /// /// Will output ("name", "path"). Benchmarks can then be filtered by path. - #[structopt(short, long)] + #[clap(short, long)] list: bool, /// Machine readable json output. /// /// This also suppresses all regular output (except to stderr) - #[structopt(short, long)] + #[clap(short, long)] json: bool, /// Filter benchmarks. @@ -63,7 +63,7 @@ struct Opt { filter: Option, /// Number of transactions for block import with `custom` size. - #[structopt(long)] + #[clap(long)] transactions: Option, /// Mode @@ -72,12 +72,12 @@ struct Opt { /// /// "profile" mode adds pauses between measurable runs, /// so that actual interval can be selected in the profiler of choice. - #[structopt(short, long, default_value = "regular")] + #[clap(short, long, default_value = "regular")] mode: BenchmarkMode, } fn main() { - let opt = Opt::from_args(); + let opt = Opt::parse(); if !opt.json { sp_tracing::try_init_simple(); diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 248181ac5c8b8..2eb1618a7c986 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -34,13 +34,13 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies +clap = { version = "3.0", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "2.0.0" } serde = { version = "1.0.132", features = ["derive"] } futures = "0.3.16" hex-literal = "0.3.4" log = "0.4.8" -rand = "0.7.2" -structopt = { version = "0.3.25", optional = true } +rand = "0.8" # primitives sp-authority-discovery = { version = "4.0.0-dev", path = "../../../primitives/authority-discovery" } @@ -97,12 +97,8 @@ node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../utils/frame/try-runtime/cli" } [target.'cfg(any(target_arch="x86_64", target_arch="aarch64"))'.dependencies] -node-executor = { version = "3.0.0-dev", path = "../executor", features = [ - "wasmtime", -] } -sc-cli = { version = "0.10.0-dev", optional = true, path = "../../../client/cli", features = [ - "wasmtime", -] } +node-executor = { version = "3.0.0-dev", path = "../executor", features = ["wasmtime"] } +sc-cli = { version = "0.10.0-dev", optional = true, path = "../../../client/cli", features = ["wasmtime"] } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service", features = [ "wasmtime", ] } @@ -129,7 +125,7 @@ regex = "1" platforms = "2.0" async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" -criterion = { version = "0.3.5", features = [ "async_tokio" ] } +criterion = { version = "0.3.5", features = ["async_tokio"] } tokio = { version = "1.15", features = ["macros", "time"] } jsonrpsee-ws-client = "0.4.1" wait-timeout = "0.2" @@ -137,7 +133,8 @@ remote-externalities = { path = "../../../utils/frame/remote-externalities" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } [build-dependencies] -structopt = { version = "0.3.25", optional = true } +clap = { version = "3.0", optional = true } +clap_complete = { version = "3.0", optional = true } node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } frame-benchmarking-cli = { version = "4.0.0-dev", optional = true, path = "../../../utils/frame/benchmarking-cli" } substrate-build-script-utils = { version = "3.0.0", optional = true, path = "../../../utils/build-script-utils" } @@ -155,14 +152,12 @@ cli = [ "frame-benchmarking-cli", "substrate-frame-cli", "sc-service/db", - "structopt", + "clap", + "clap_complete", "substrate-build-script-utils", "try-runtime-cli", ] -runtime-benchmarks = [ - "node-runtime/runtime-benchmarks", - "frame-benchmarking-cli", -] +runtime-benchmarks = ["node-runtime/runtime-benchmarks", "frame-benchmarking-cli"] # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. try-runtime = ["node-runtime/try-runtime", "try-runtime-cli"] diff --git a/bin/node/cli/build.rs b/bin/node/cli/build.rs index e0d5dcea62eda..6a010d8858fe5 100644 --- a/bin/node/cli/build.rs +++ b/bin/node/cli/build.rs @@ -25,7 +25,8 @@ fn main() { mod cli { include!("src/cli.rs"); - use sc_cli::structopt::clap::Shell; + use clap::{ArgEnum, IntoApp}; + use clap_complete::{generate_to, Shell}; use std::{env, fs, path::Path}; use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; @@ -37,9 +38,8 @@ mod cli { } /// Build shell completion scripts for all known shells - /// Full list in https://github.com/kbknapp/clap-rs/blob/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9/src/app/parser.rs#L123 fn build_shell_completion() { - for shell in &[Shell::Bash, Shell::Fish, Shell::Zsh, Shell::Elvish, Shell::PowerShell] { + for shell in Shell::value_variants() { build_completion(shell); } } @@ -61,6 +61,6 @@ mod cli { fs::create_dir(&path).ok(); - Cli::clap().gen_completions("substrate-node", *shell, &path); + let _ = generate_to(*shell, &mut Cli::into_app(), "substrate-node", &path); } } diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 59d219a01090e..00393c52f8b68 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -16,35 +16,30 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use sc_cli::{KeySubcommand, RunCmd, SignCmd, VanityCmd, VerifyCmd}; -use structopt::StructOpt; - /// An overarching CLI command definition. -#[derive(Debug, StructOpt)] +#[derive(Debug, clap::Parser)] pub struct Cli { /// Possible subcommand with parameters. - #[structopt(subcommand)] + #[clap(subcommand)] pub subcommand: Option, + #[allow(missing_docs)] - #[structopt(flatten)] - pub run: RunCmd, + #[clap(flatten)] + pub run: sc_cli::RunCmd, } /// Possible subcommands of the main binary. -#[derive(Debug, StructOpt)] +#[derive(Debug, clap::Subcommand)] pub enum Subcommand { - /// Key management cli utilities - Key(KeySubcommand), - /// The custom inspect subcommmand for decoding blocks and extrinsics. - #[structopt( + #[clap( name = "inspect", about = "Decode given block or extrinsic using current native runtime." )] Inspect(node_inspect::cli::InspectCmd), /// The custom benchmark subcommmand benchmarking runtime pallets. - #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] + #[clap(name = "benchmark", about = "Benchmark runtime pallets.")] Benchmark(frame_benchmarking_cli::BenchmarkCmd), /// Try some command against runtime state. @@ -55,14 +50,18 @@ pub enum Subcommand { #[cfg(not(feature = "try-runtime"))] TryRuntime, + /// 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(VerifyCmd), + Verify(sc_cli::VerifyCmd), /// Generate a seed that provides a vanity address. - Vanity(VanityCmd), + Vanity(sc_cli::VanityCmd), /// Sign a message, with a given (secret) key. - Sign(SignCmd), + Sign(sc_cli::SignCmd), /// Build a chain specification. BuildSpec(sc_cli::BuildSpecCmd), diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index d72c6f43d005d..49470a7e7b058 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +clap = { version = "3.0", features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0" } derive_more = "0.99" sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } @@ -20,4 +21,3 @@ sc-service = { version = "0.10.0-dev", default-features = false, path = "../../. sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } -structopt = "0.3.8" diff --git a/bin/node/inspect/src/cli.rs b/bin/node/inspect/src/cli.rs index 6e019ca5b2084..cc1f232e1fe0f 100644 --- a/bin/node/inspect/src/cli.rs +++ b/bin/node/inspect/src/cli.rs @@ -19,27 +19,25 @@ //! Structs to easily compose inspect sub-command for CLI. use sc_cli::{ImportParams, SharedParams}; -use std::fmt::Debug; -use structopt::StructOpt; /// The `inspect` command used to print decoded chain data. -#[derive(Debug, StructOpt)] +#[derive(Debug, clap::Parser)] pub struct InspectCmd { #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(subcommand)] pub command: InspectSubCmd, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub import_params: ImportParams, } /// A possible inspect sub-commands. -#[derive(Debug, StructOpt)] +#[derive(Debug, clap::Subcommand)] pub enum InspectSubCmd { /// Decode block with native version of runtime and print out the details. Block { @@ -48,7 +46,7 @@ pub enum InspectSubCmd { /// Can be either a block hash (no 0x prefix) or a number to retrieve existing block, /// or a 0x-prefixed bytes hex string, representing SCALE encoding of /// a block. - #[structopt(value_name = "HASH or NUMBER or BYTES")] + #[clap(value_name = "HASH or NUMBER or BYTES")] input: String, }, /// Decode extrinsic with native version of runtime and print out the details. @@ -58,7 +56,7 @@ pub enum InspectSubCmd { /// Can be either a block hash (no 0x prefix) or number and the index, in the form /// of `{block}:{index}` or a 0x-prefixed bytes hex string, /// representing SCALE encoding of an extrinsic. - #[structopt(value_name = "BLOCK:INDEX or BYTES")] + #[clap(value_name = "BLOCK:INDEX or BYTES")] input: String, }, } diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index f9bb4f94491a8..452221ff6e13e 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -15,10 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" +clap = { version = "3.0", features = ["derive"] } +rand = "0.8" + sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } node-cli = { version = "3.0.0-dev", path = "../../node/cli" } sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } -rand = "0.7.2" -structopt = "0.3.25" diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index 013fbeccfe0d7..3e8b1f4ea7523 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -23,8 +23,8 @@ use std::{ }; use ansi_term::Style; +use clap::Parser; use rand::{distributions::Alphanumeric, rngs::OsRng, Rng}; -use structopt::StructOpt; use node_cli::chain_spec::{self, AccountId}; use sc_keystore::LocalKeystore; @@ -36,52 +36,52 @@ use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; /// A utility to easily create a testnet chain spec definition with a given set /// of authorities and endowed accounts and/or generate random accounts. -#[derive(StructOpt)] -#[structopt(rename_all = "kebab-case")] +#[derive(Parser)] +#[clap(rename_all = "kebab-case")] enum ChainSpecBuilder { /// Create a new chain spec with the given authorities, endowed and sudo /// accounts. New { /// Authority key seed. - #[structopt(long, short, required = true)] + #[clap(long, short, required = true)] authority_seeds: Vec, /// Active nominators (SS58 format), each backing a random subset of the aforementioned /// authorities. - #[structopt(long, short, default_value = "0")] + #[clap(long, short, default_value = "0")] nominator_accounts: Vec, /// Endowed account address (SS58 format). - #[structopt(long, short)] + #[clap(long, short)] endowed_accounts: Vec, /// Sudo account address (SS58 format). - #[structopt(long, short)] + #[clap(long, short)] sudo_account: String, /// The path where the chain spec should be saved. - #[structopt(long, short, default_value = "./chain_spec.json")] + #[clap(long, short, default_value = "./chain_spec.json")] chain_spec_path: PathBuf, }, /// Create a new chain spec with the given number of authorities and endowed /// accounts. Random keys will be generated as required. Generate { /// The number of authorities. - #[structopt(long, short)] + #[clap(long, short)] authorities: usize, /// The number of nominators backing the aforementioned authorities. /// /// Will nominate a random subset of `authorities`. - #[structopt(long, short, default_value = "0")] + #[clap(long, short, default_value = "0")] nominators: usize, /// The number of endowed accounts. - #[structopt(long, short, default_value = "0")] + #[clap(long, short, default_value = "0")] endowed: usize, /// The path where the chain spec should be saved. - #[structopt(long, short, default_value = "./chain_spec.json")] + #[clap(long, short, default_value = "./chain_spec.json")] chain_spec_path: PathBuf, /// Path to use when saving generated keystores for each authority. /// /// At this path, a new folder will be created for each authority's /// keystore named `auth-$i` where `i` is the authority index, i.e. /// `auth-0`, `auth-1`, etc. - #[structopt(long, short)] + #[clap(long, short)] keystore_path: Option, }, } @@ -236,13 +236,15 @@ fn main() -> Result<(), String> { the chain spec builder binary in `--release` mode.\n", ); - let builder = ChainSpecBuilder::from_args(); + let builder = ChainSpecBuilder::parse(); let chain_spec_path = builder.chain_spec_path().to_path_buf(); let (authority_seeds, nominator_accounts, endowed_accounts, sudo_account) = match builder { ChainSpecBuilder::Generate { authorities, nominators, endowed, keystore_path, .. } => { let authorities = authorities.max(1); - let rand_str = || -> String { OsRng.sample_iter(&Alphanumeric).take(32).collect() }; + let rand_str = || -> String { + OsRng.sample_iter(&Alphanumeric).take(32).map(char::from).collect() + }; let authority_seeds = (0..authorities).map(|_| rand_str()).collect::>(); let nominator_seeds = (0..nominators).map(|_| rand_str()).collect::>(); diff --git a/bin/utils/subkey/Cargo.toml b/bin/utils/subkey/Cargo.toml index d3c38edb5771d..85f864cfbfc13 100644 --- a/bin/utils/subkey/Cargo.toml +++ b/bin/utils/subkey/Cargo.toml @@ -17,5 +17,5 @@ path = "src/main.rs" name = "subkey" [dependencies] +clap = { version = "3.0", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } -structopt = "0.3.25" diff --git a/bin/utils/subkey/src/lib.rs b/bin/utils/subkey/src/lib.rs index 9a33ef2d2d6dd..73698db0b7ea0 100644 --- a/bin/utils/subkey/src/lib.rs +++ b/bin/utils/subkey/src/lib.rs @@ -16,14 +16,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use clap::Parser; use sc_cli::{ Error, GenerateCmd, GenerateNodeKeyCmd, InspectKeyCmd, InspectNodeKeyCmd, SignCmd, VanityCmd, VerifyCmd, }; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] -#[structopt( +#[derive(Debug, Parser)] +#[clap( name = "subkey", author = "Parity Team ", about = "Utility for generating and restoring with Substrate keys" @@ -54,7 +54,7 @@ pub enum Subkey { /// Run the subkey command, given the appropriate runtime. pub fn run() -> Result<(), Error> { - match Subkey::from_args() { + match Subkey::parse() { Subkey::GenerateNodeKey(cmd) => cmd.run(), Subkey::Generate(cmd) => cmd.run(), Subkey::Inspect(cmd) => cmd.run(), diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 01f5aab25d5fa..a33b3e13af35c 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -13,42 +13,41 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.11" -regex = "1.5.4" -tokio = { version = "1.15", features = [ "signal", "rt-multi-thread" ] } -futures = "0.3.9" +chrono = "0.4.10" +clap = { version = "3.0", features = ["derive"] } fdlimit = "0.2.1" -libp2p = "0.40.0" -parity-scale-codec = "2.3.1" +futures = "0.3.9" hex = "0.4.2" +libp2p = "0.40.0" +log = "0.4.11" +names = { version = "0.12.0", default-features = false } rand = "0.7.3" -tiny-bip39 = "0.8.2" +regex = "1.5.4" +rpassword = "5.0.0" +serde = "1.0.132" serde_json = "1.0.74" -sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } +thiserror = "1.0.30" +tiny-bip39 = "0.8.2" +tokio = { version = "1.15", features = ["signal", "rt-multi-thread"] } + +parity-scale-codec = "2.3.1" sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } -sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } -sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } -sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } -sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../service" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } -sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } -names = { version = "0.12.0", default-features = false } -structopt = "0.3.25" sc-tracing = { version = "4.0.0-dev", path = "../tracing" } -chrono = "0.4.10" -serde = "1.0.132" -thiserror = "1.0.30" -rpassword = "5.0.0" +sc-utils = { version = "4.0.0-dev", path = "../utils" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } +sp-keyring = { version = "4.1.0-dev", path = "../../primitives/keyring" } +sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } +sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } +sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } +sp-version = { version = "4.0.0-dev", path = "../../primitives/version" } [dev-dependencies] tempfile = "3.1.0" [features] -wasmtime = [ - "sc-service/wasmtime", -] +wasmtime = ["sc-service/wasmtime"] diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index c13361a9ac2ba..249e3c639e4ef 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -18,7 +18,7 @@ // NOTE: we allow missing docs here because arg_enum! creates the function variants without doc #![allow(missing_docs)] -use structopt::clap::arg_enum; +use clap::ArgEnum; /// How to execute Wasm runtime code. #[derive(Debug, Clone, Copy)] @@ -86,12 +86,11 @@ impl Into for WasmExecutionMethod { } } -arg_enum! { - #[allow(missing_docs)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub enum TracingReceiver { - Log, - } +#[allow(missing_docs)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] +#[clap(rename_all = "PascalCase")] +pub enum TracingReceiver { + Log, } impl Into for TracingReceiver { @@ -102,44 +101,40 @@ impl Into for TracingReceiver { } } -arg_enum! { - #[allow(missing_docs)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub enum NodeKeyType { - Ed25519 - } +#[allow(missing_docs)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] +#[clap(rename_all = "PascalCase")] +pub enum NodeKeyType { + Ed25519, } -arg_enum! { - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub enum CryptoScheme { - Ed25519, - Sr25519, - Ecdsa, - } +#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] +#[clap(rename_all = "PascalCase")] +pub enum CryptoScheme { + Ed25519, + Sr25519, + Ecdsa, } -arg_enum! { - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub enum OutputType { - Json, - Text, - } +#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] +#[clap(rename_all = "PascalCase")] +pub enum OutputType { + Json, + Text, } -arg_enum! { - /// How to execute blocks - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub enum ExecutionStrategy { - // Execute with native build (if available, WebAssembly otherwise). - Native, - // Only execute with the WebAssembly build. - Wasm, - // Execute with both native (where available) and WebAssembly builds. - Both, - // Execute with the native build if possible; if it fails, then execute with WebAssembly. - NativeElseWasm, - } +/// How to execute blocks +#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] +#[clap(rename_all = "PascalCase")] +pub enum ExecutionStrategy { + // Execute with native build (if available, WebAssembly otherwise). + Native, + // Only execute with the WebAssembly build. + Wasm, + // Execute with both native (where available) and WebAssembly builds. + Both, + // Execute with the native build if possible; if it fails, then execute with WebAssembly. + NativeElseWasm, } impl Into for ExecutionStrategy { @@ -165,19 +160,18 @@ impl ExecutionStrategy { } } -arg_enum! { - /// Available RPC methods. - #[allow(missing_docs)] - #[derive(Debug, Copy, Clone, PartialEq)] - pub enum RpcMethods { - // Expose every RPC method only when RPC is listening on `localhost`, - // otherwise serve only safe RPC methods. - Auto, - // Allow only a safe subset of RPC methods. - Safe, - // Expose every RPC method (even potentially unsafe ones). - Unsafe, - } +/// Available RPC methods. +#[allow(missing_docs)] +#[derive(Debug, Copy, Clone, PartialEq, ArgEnum)] +#[clap(rename_all = "PascalCase")] +pub enum RpcMethods { + // Expose every RPC method only when RPC is listening on `localhost`, + // otherwise serve only safe RPC methods. + Auto, + // Allow only a safe subset of RPC methods. + Safe, + // Expose every RPC method (even potentially unsafe ones). + Unsafe, } impl Into for RpcMethods { @@ -225,31 +219,28 @@ impl Database { } } -arg_enum! { - /// Whether off-chain workers are enabled. - #[allow(missing_docs)] - #[derive(Debug, Clone)] - pub enum OffchainWorkerEnabled { - Always, - Never, - WhenValidating, - } +/// Whether off-chain workers are enabled. +#[allow(missing_docs)] +#[derive(Debug, Clone, ArgEnum)] +#[clap(rename_all = "PascalCase")] +pub enum OffchainWorkerEnabled { + Always, + Never, + WhenValidating, } -arg_enum! { - /// Syncing mode. - #[allow(missing_docs)] - #[derive(Debug, Clone, Copy)] - pub enum SyncMode { - // Full sync. Donwnload end verify all blocks. - Full, - // Download blocks without executing them. Download latest state with proofs. - Fast, - // Download blocks without executing them. Download latest state without proofs. - FastUnsafe, - // Prove finality and download the latest state. - Warp, - } +/// Syncing mode. +#[derive(Debug, Clone, Copy, ArgEnum)] +#[clap(rename_all = "PascalCase")] +pub enum SyncMode { + // Full sync. Donwnload end verify all blocks. + Full, + // Download blocks without executing them. Download latest state with proofs. + Fast, + // Download blocks without executing them. Download latest state without proofs. + FastUnsafe, + // Prove finality and download the latest state. + Warp, } impl Into for SyncMode { diff --git a/client/cli/src/commands/build_spec_cmd.rs b/client/cli/src/commands/build_spec_cmd.rs index ad7cf455eb3b2..3196a3e7b915f 100644 --- a/client/cli/src/commands/build_spec_cmd.rs +++ b/client/cli/src/commands/build_spec_cmd.rs @@ -21,6 +21,7 @@ use crate::{ params::{NodeKeyParams, SharedParams}, CliConfiguration, }; +use clap::Parser; use log::info; use sc_network::config::build_multiaddr; use sc_service::{ @@ -28,28 +29,27 @@ use sc_service::{ ChainSpec, }; use std::io::Write; -use structopt::StructOpt; /// The `build-spec` command used to build a specification. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Parser)] pub struct BuildSpecCmd { /// Force raw genesis storage output. - #[structopt(long = "raw")] + #[clap(long)] pub raw: bool, /// Disable adding the default bootnode to the specification. /// /// By default the `/ip4/127.0.0.1/tcp/30333/p2p/NODE_PEER_ID` bootnode is added to the /// specification when no bootnode exists. - #[structopt(long = "disable-default-bootnode")] + #[clap(long)] pub disable_default_bootnode: bool, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub node_key_params: NodeKeyParams, } diff --git a/client/cli/src/commands/check_block_cmd.rs b/client/cli/src/commands/check_block_cmd.rs index b5642cf4b629b..b7e69b1360a0a 100644 --- a/client/cli/src/commands/check_block_cmd.rs +++ b/client/cli/src/commands/check_block_cmd.rs @@ -21,30 +21,30 @@ use crate::{ params::{BlockNumberOrHash, ImportParams, SharedParams}, CliConfiguration, }; +use clap::Parser; use sc_client_api::{BlockBackend, HeaderBackend}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::{fmt::Debug, str::FromStr, sync::Arc}; -use structopt::StructOpt; /// The `check-block` command used to validate blocks. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Parser)] pub struct CheckBlockCmd { /// Block hash or number - #[structopt(value_name = "HASH or NUMBER")] + #[clap(value_name = "HASH or NUMBER")] pub input: BlockNumberOrHash, /// The default number of 64KB pages to ever allocate for Wasm execution. /// /// Don't alter this unless you know what you're doing. - #[structopt(long = "default-heap-pages", value_name = "COUNT")] + #[clap(long, value_name = "COUNT")] pub default_heap_pages: Option, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub import_params: ImportParams, } diff --git a/client/cli/src/commands/export_blocks_cmd.rs b/client/cli/src/commands/export_blocks_cmd.rs index af7de3c12e77b..4e0e155dd51c2 100644 --- a/client/cli/src/commands/export_blocks_cmd.rs +++ b/client/cli/src/commands/export_blocks_cmd.rs @@ -21,46 +21,46 @@ use crate::{ params::{DatabaseParams, GenericNumber, PruningParams, SharedParams}, CliConfiguration, }; +use clap::Parser; use log::info; use sc_client_api::{BlockBackend, UsageProvider}; use sc_service::{chain_ops::export_blocks, config::DatabaseSource}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::{fmt::Debug, fs, io, path::PathBuf, str::FromStr, sync::Arc}; -use structopt::StructOpt; /// The `export-blocks` command used to export blocks. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Parser)] pub struct ExportBlocksCmd { /// Output file name or stdout if unspecified. - #[structopt(parse(from_os_str))] + #[clap(parse(from_os_str))] pub output: Option, /// Specify starting block number. /// /// Default is 1. - #[structopt(long = "from", value_name = "BLOCK")] + #[clap(long, value_name = "BLOCK")] pub from: Option, /// Specify last block number. /// /// Default is best block. - #[structopt(long = "to", value_name = "BLOCK")] + #[clap(long, value_name = "BLOCK")] pub to: Option, /// Use binary output rather than JSON. - #[structopt(long)] + #[clap(long)] pub binary: bool, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub pruning_params: PruningParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub database_params: DatabaseParams, } diff --git a/client/cli/src/commands/export_state_cmd.rs b/client/cli/src/commands/export_state_cmd.rs index b322265aee2b5..4d67ab5d13c95 100644 --- a/client/cli/src/commands/export_state_cmd.rs +++ b/client/cli/src/commands/export_state_cmd.rs @@ -21,26 +21,26 @@ use crate::{ params::{BlockNumberOrHash, PruningParams, SharedParams}, CliConfiguration, }; +use clap::Parser; use log::info; use sc_client_api::{StorageProvider, UsageProvider}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::{fmt::Debug, io::Write, str::FromStr, sync::Arc}; -use structopt::StructOpt; /// The `export-state` command used to export the state of a given block into /// a chain spec. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Parser)] pub struct ExportStateCmd { /// Block hash or number. - #[structopt(value_name = "HASH or NUMBER")] + #[clap(value_name = "HASH or NUMBER")] pub input: Option, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub pruning_params: PruningParams, } diff --git a/client/cli/src/commands/generate.rs b/client/cli/src/commands/generate.rs index ce4c24fc7d8c9..9c1e5b689584b 100644 --- a/client/cli/src/commands/generate.rs +++ b/client/cli/src/commands/generate.rs @@ -21,30 +21,30 @@ use crate::{ NetworkSchemeFlag, OutputTypeFlag, }; use bip39::{Language, Mnemonic, MnemonicType}; -use structopt::StructOpt; +use clap::Parser; /// The `generate` command -#[derive(Debug, StructOpt, Clone)] -#[structopt(name = "generate", about = "Generate a random account")] +#[derive(Debug, Clone, Parser)] +#[clap(name = "generate", about = "Generate a random account")] pub struct GenerateCmd { /// The number of words in the phrase to generate. One of 12 (default), 15, 18, 21 and 24. - #[structopt(long, short = "w", value_name = "WORDS")] + #[clap(short = 'w', long, value_name = "WORDS")] words: Option, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub keystore_params: KeystoreParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub network_scheme: NetworkSchemeFlag, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub output_scheme: OutputTypeFlag, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub crypto_scheme: CryptoSchemeFlag, } @@ -78,12 +78,11 @@ impl GenerateCmd { #[cfg(test)] mod tests { - use super::GenerateCmd; - use structopt::StructOpt; + use super::*; #[test] fn generate() { - let generate = GenerateCmd::from_iter(&["generate", "--password", "12345"]); + let generate = GenerateCmd::parse_from(&["generate", "--password", "12345"]); assert!(generate.run().is_ok()) } } diff --git a/client/cli/src/commands/generate_node_key.rs b/client/cli/src/commands/generate_node_key.rs index 2221c8a99ded1..8c634dca9acf2 100644 --- a/client/cli/src/commands/generate_node_key.rs +++ b/client/cli/src/commands/generate_node_key.rs @@ -18,13 +18,13 @@ //! Implementation of the `generate-node-key` subcommand use crate::Error; +use clap::Parser; use libp2p::identity::{ed25519 as libp2p_ed25519, PublicKey}; use std::{fs, path::PathBuf}; -use structopt::StructOpt; /// The `generate-node-key` command -#[derive(Debug, StructOpt)] -#[structopt( +#[derive(Debug, Parser)] +#[clap( name = "generate-node-key", about = "Generate a random node libp2p key, save it to \ file or print it to stdout and print its peer ID to stderr" @@ -33,7 +33,7 @@ pub struct GenerateNodeKeyCmd { /// Name of file to save secret key to. /// /// If not given, the secret key is printed to stdout. - #[structopt(long)] + #[clap(long)] file: Option, } @@ -66,7 +66,7 @@ mod tests { fn generate_node_key() { let mut file = Builder::new().prefix("keyfile").tempfile().unwrap(); let file_path = file.path().display().to_string(); - let generate = GenerateNodeKeyCmd::from_iter(&["generate-node-key", "--file", &file_path]); + let generate = GenerateNodeKeyCmd::parse_from(&["generate-node-key", "--file", &file_path]); assert!(generate.run().is_ok()); let mut buf = String::new(); assert!(file.read_to_string(&mut buf).is_ok()); diff --git a/client/cli/src/commands/import_blocks_cmd.rs b/client/cli/src/commands/import_blocks_cmd.rs index d0a0b39a5bf8c..fece33ba23a2c 100644 --- a/client/cli/src/commands/import_blocks_cmd.rs +++ b/client/cli/src/commands/import_blocks_cmd.rs @@ -21,6 +21,7 @@ use crate::{ params::{ImportParams, SharedParams}, CliConfiguration, }; +use clap::Parser; use sc_client_api::HeaderBackend; use sc_service::chain_ops::import_blocks; use sp_runtime::traits::Block as BlockT; @@ -31,31 +32,30 @@ use std::{ path::PathBuf, sync::Arc, }; -use structopt::StructOpt; /// The `import-blocks` command used to import blocks. -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct ImportBlocksCmd { /// Input file or stdin if unspecified. - #[structopt(parse(from_os_str))] + #[clap(parse(from_os_str))] pub input: Option, /// The default number of 64KB pages to ever allocate for Wasm execution. /// /// Don't alter this unless you know what you're doing. - #[structopt(long = "default-heap-pages", value_name = "COUNT")] + #[clap(long, value_name = "COUNT")] pub default_heap_pages: Option, /// Try importing blocks from binary format rather than JSON. - #[structopt(long)] + #[clap(long)] pub binary: bool, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub import_params: ImportParams, } diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index cf40fb7ec4bfd..852b4e50376ff 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -20,42 +20,37 @@ use crate::{ utils, with_crypto_scheme, CryptoScheme, Error, KeystoreParams, SharedParams, SubstrateCli, }; +use clap::Parser; use sc_keystore::LocalKeystore; use sc_service::config::{BasePath, KeystoreConfig}; use sp_core::crypto::{KeyTypeId, SecretString}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use std::{convert::TryFrom, sync::Arc}; -use structopt::StructOpt; /// The `insert` command -#[derive(Debug, StructOpt, Clone)] -#[structopt(name = "insert", about = "Insert a key to the keystore of a node.")] +#[derive(Debug, Clone, Parser)] +#[clap(name = "insert", about = "Insert a key to the keystore of a node.")] pub struct InsertKeyCmd { /// The secret key URI. /// If the value is a file, the file content is used as URI. /// If not given, you will be prompted for the URI. - #[structopt(long)] + #[clap(long)] suri: Option, /// Key type, examples: "gran", or "imon" - #[structopt(long)] + #[clap(long)] key_type: String, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub keystore_params: KeystoreParams, /// The cryptography scheme that should be used to generate the key out of the given URI. - #[structopt( - long, - value_name = "SCHEME", - possible_values = &CryptoScheme::variants(), - case_insensitive = true, - )] + #[clap(long, value_name = "SCHEME", arg_enum, ignore_case = true)] pub scheme: CryptoScheme, } @@ -100,7 +95,6 @@ mod tests { use super::*; use sc_service::{ChainSpec, ChainType, GenericChainSpec, NoExtension}; use sp_core::{sr25519::Pair, ByteArray, Pair as _}; - use structopt::StructOpt; use tempfile::TempDir; struct Cli; @@ -156,7 +150,7 @@ mod tests { let path_str = format!("{}", path.path().display()); let (key, uri, _) = Pair::generate_with_phrase(None); - let inspect = InsertKeyCmd::from_iter(&[ + let inspect = InsertKeyCmd::parse_from(&[ "insert-key", "-d", &path_str, diff --git a/client/cli/src/commands/inspect_key.rs b/client/cli/src/commands/inspect_key.rs index 34f51dc5ec42f..61fa8d2157e3b 100644 --- a/client/cli/src/commands/inspect_key.rs +++ b/client/cli/src/commands/inspect_key.rs @@ -21,13 +21,13 @@ use crate::{ utils::{self, print_from_public, print_from_uri}, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, NetworkSchemeFlag, OutputTypeFlag, }; +use clap::Parser; use sp_core::crypto::{ExposeSecret, SecretString, SecretUri, Ss58Codec}; use std::str::FromStr; -use structopt::StructOpt; /// The `inspect` command -#[derive(Debug, StructOpt)] -#[structopt( +#[derive(Debug, Parser)] +#[clap( name = "inspect", about = "Gets a public key and a SS58 address from the provided Secret URI" )] @@ -44,23 +44,23 @@ pub struct InspectKeyCmd { uri: Option, /// Is the given `uri` a hex encoded public key? - #[structopt(long)] + #[clap(long)] public: bool, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub keystore_params: KeystoreParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub network_scheme: NetworkSchemeFlag, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub output_scheme: OutputTypeFlag, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub crypto_scheme: CryptoSchemeFlag, /// Expect that `--uri` has the given public key/account-id. @@ -72,7 +72,7 @@ pub struct InspectKeyCmd { /// /// If there is no derivation in `--uri`, the public key will be checked against the public key /// of `--uri` directly. - #[structopt(long, conflicts_with = "public")] + #[clap(long, conflicts_with = "public")] pub expect_public: Option, } @@ -158,7 +158,6 @@ mod tests { use super::*; use sp_core::crypto::{ByteArray, Pair}; use sp_runtime::traits::IdentifyAccount; - use structopt::StructOpt; #[test] fn inspect() { @@ -166,10 +165,10 @@ mod tests { "remember fiber forum demise paper uniform squirrel feel access exclude casual effort"; let seed = "0xad1fb77243b536b90cfe5f0d351ab1b1ac40e3890b41dc64f766ee56340cfca5"; - let inspect = InspectKeyCmd::from_iter(&["inspect-key", words, "--password", "12345"]); + let inspect = InspectKeyCmd::parse_from(&["inspect-key", words, "--password", "12345"]); assert!(inspect.run().is_ok()); - let inspect = InspectKeyCmd::from_iter(&["inspect-key", seed]); + let inspect = InspectKeyCmd::parse_from(&["inspect-key", seed]); assert!(inspect.run().is_ok()); } @@ -177,14 +176,14 @@ mod tests { fn inspect_public_key() { let public = "0x12e76e0ae8ce41b6516cce52b3f23a08dcb4cfeed53c6ee8f5eb9f7367341069"; - let inspect = InspectKeyCmd::from_iter(&["inspect-key", "--public", public]); + let inspect = InspectKeyCmd::parse_from(&["inspect-key", "--public", public]); assert!(inspect.run().is_ok()); } #[test] fn inspect_with_expected_public_key() { let check_cmd = |seed, expected_public, success| { - let inspect = InspectKeyCmd::from_iter(&[ + let inspect = InspectKeyCmd::parse_from(&[ "inspect-key", "--expect-public", expected_public, diff --git a/client/cli/src/commands/inspect_node_key.rs b/client/cli/src/commands/inspect_node_key.rs index a5793873dd68f..4c0798cc0635c 100644 --- a/client/cli/src/commands/inspect_node_key.rs +++ b/client/cli/src/commands/inspect_node_key.rs @@ -18,23 +18,23 @@ //! Implementation of the `inspect-node-key` subcommand use crate::{Error, NetworkSchemeFlag}; +use clap::Parser; use libp2p::identity::{ed25519, PublicKey}; use std::{fs, path::PathBuf}; -use structopt::StructOpt; /// The `inspect-node-key` command -#[derive(Debug, StructOpt)] -#[structopt( +#[derive(Debug, Parser)] +#[clap( name = "inspect-node-key", about = "Print the peer ID corresponding to the node key in the given file." )] pub struct InspectNodeKeyCmd { /// Name of file to read the secret key from. - #[structopt(long)] + #[clap(long)] file: PathBuf, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub network_scheme: NetworkSchemeFlag, } @@ -63,11 +63,11 @@ mod tests { fn inspect_node_key() { let path = tempfile::tempdir().unwrap().into_path().join("node-id").into_os_string(); let path = path.to_str().unwrap(); - let cmd = GenerateNodeKeyCmd::from_iter(&["generate-node-key", "--file", path.clone()]); + let cmd = GenerateNodeKeyCmd::parse_from(&["generate-node-key", "--file", path.clone()]); assert!(cmd.run().is_ok()); - let cmd = InspectNodeKeyCmd::from_iter(&["inspect-node-key", "--file", path]); + let cmd = InspectNodeKeyCmd::parse_from(&["inspect-node-key", "--file", path]); assert!(cmd.run().is_ok()); } } diff --git a/client/cli/src/commands/key.rs b/client/cli/src/commands/key.rs index 0bfc68f8c32e2..e0f3524196e2c 100644 --- a/client/cli/src/commands/key.rs +++ b/client/cli/src/commands/key.rs @@ -17,16 +17,14 @@ //! Key related CLI utilities -use crate::{Error, SubstrateCli}; -use structopt::StructOpt; - use super::{ generate::GenerateCmd, generate_node_key::GenerateNodeKeyCmd, insert_key::InsertKeyCmd, inspect_key::InspectKeyCmd, inspect_node_key::InspectNodeKeyCmd, }; +use crate::{Error, SubstrateCli}; /// Key utilities for the cli. -#[derive(Debug, StructOpt)] +#[derive(Debug, clap::Subcommand)] pub enum KeySubcommand { /// Generate a random node libp2p key, save it to file or print it to stdout /// and print its peer ID to stderr. diff --git a/client/cli/src/commands/purge_chain_cmd.rs b/client/cli/src/commands/purge_chain_cmd.rs index eb19762df7d8a..7dd7c1f5a5a5a 100644 --- a/client/cli/src/commands/purge_chain_cmd.rs +++ b/client/cli/src/commands/purge_chain_cmd.rs @@ -21,27 +21,27 @@ use crate::{ params::{DatabaseParams, SharedParams}, CliConfiguration, }; +use clap::Parser; use sc_service::DatabaseSource; use std::{ fmt::Debug, fs, io::{self, Write}, }; -use structopt::StructOpt; /// The `purge-chain` command used to remove the whole chain. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Parser)] pub struct PurgeChainCmd { /// Skip interactive prompt by answering yes automatically. - #[structopt(short = "y")] + #[clap(short = 'y')] pub yes: bool, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub database_params: DatabaseParams, } diff --git a/client/cli/src/commands/revert_cmd.rs b/client/cli/src/commands/revert_cmd.rs index a671469ba7fdf..c207d198d5a27 100644 --- a/client/cli/src/commands/revert_cmd.rs +++ b/client/cli/src/commands/revert_cmd.rs @@ -21,25 +21,25 @@ use crate::{ params::{GenericNumber, PruningParams, SharedParams}, CliConfiguration, }; +use clap::Parser; use sc_client_api::{Backend, UsageProvider}; use sc_service::chain_ops::revert_chain; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::{fmt::Debug, str::FromStr, sync::Arc}; -use structopt::StructOpt; /// The `revert` command used revert the chain to a previous state. -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct RevertCmd { /// Number of blocks to revert. - #[structopt(default_value = "256")] + #[clap(default_value = "256")] pub num: GenericNumber, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub pruning_params: PruningParams, } diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 08b8fd87e2c82..b9318813b0480 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -25,6 +25,7 @@ use crate::{ }, CliConfiguration, }; +use clap::Parser; use regex::Regex; use sc_service::{ config::{BasePath, PrometheusConfig, TransactionPoolOptions}, @@ -32,26 +33,25 @@ use sc_service::{ }; use sc_telemetry::TelemetryEndpoints; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -use structopt::StructOpt; /// The `run` command used to run a node. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Parser)] pub struct RunCmd { /// Enable validator mode. /// /// The node will be started with the authority role and actively /// participate in any consensus task that it can (e.g. depending on /// availability of local keys). - #[structopt(long)] + #[clap(long)] pub validator: bool, /// Disable GRANDPA voter when running in validator mode, otherwise disable the GRANDPA /// observer. - #[structopt(long)] + #[clap(long)] pub no_grandpa: bool, /// Experimental: Run in light client mode. - #[structopt(long = "light")] + #[clap(long)] pub light: bool, /// Listen to all RPC interfaces. @@ -60,13 +60,13 @@ pub struct RunCmd { /// proxy server to filter out dangerous methods. More details: /// . /// Use `--unsafe-rpc-external` to suppress the warning if you understand the risks. - #[structopt(long = "rpc-external")] + #[clap(long)] pub rpc_external: bool, /// Listen to all RPC interfaces. /// /// Same as `--rpc-external`. - #[structopt(long)] + #[clap(long)] pub unsafe_rpc_external: bool, /// RPC methods to expose. @@ -75,11 +75,11 @@ pub struct RunCmd { /// - `Safe`: Exposes only a safe subset of RPC methods, denying unsafe RPC methods. /// - `Auto`: Acts as `Safe` if RPC is served externally, e.g. when `--{rpc,ws}-external` is /// passed, otherwise acts as `Unsafe`. - #[structopt( + #[clap( long, value_name = "METHOD SET", - possible_values = &RpcMethods::variants(), - case_insensitive = true, + arg_enum, + ignore_case = true, default_value = "Auto", verbatim_doc_comment )] @@ -91,44 +91,44 @@ pub struct RunCmd { /// proxy server to filter out dangerous methods. More details: /// . /// Use `--unsafe-ws-external` to suppress the warning if you understand the risks. - #[structopt(long = "ws-external")] + #[clap(long)] pub ws_external: bool, /// Listen to all Websocket interfaces. /// /// Same as `--ws-external` but doesn't warn you about it. - #[structopt(long = "unsafe-ws-external")] + #[clap(long)] pub unsafe_ws_external: bool, /// Set the the maximum RPC payload size for both requests and responses (both http and ws), in /// megabytes. Default is 15MiB. - #[structopt(long = "rpc-max-payload")] + #[clap(long)] pub rpc_max_payload: Option, /// Expose Prometheus exporter on all interfaces. /// /// Default is local. - #[structopt(long = "prometheus-external")] + #[clap(long)] pub prometheus_external: bool, /// Specify IPC RPC server path - #[structopt(long = "ipc-path", value_name = "PATH")] + #[clap(long, value_name = "PATH")] pub ipc_path: Option, /// Specify HTTP RPC server TCP port. - #[structopt(long = "rpc-port", value_name = "PORT")] + #[clap(long, value_name = "PORT")] pub rpc_port: Option, /// Specify WebSockets RPC server TCP port. - #[structopt(long = "ws-port", value_name = "PORT")] + #[clap(long, value_name = "PORT")] pub ws_port: Option, /// Maximum number of WS RPC server connections. - #[structopt(long = "ws-max-connections", value_name = "COUNT")] + #[clap(long, value_name = "COUNT")] pub ws_max_connections: Option, /// Set the the maximum WebSocket output buffer size in MiB. Default is 16. - #[structopt(long = "ws-max-out-buffer-capacity")] + #[clap(long)] pub ws_max_out_buffer_capacity: Option, /// Specify browser Origins allowed to access the HTTP & WS RPC servers. @@ -137,29 +137,29 @@ pub struct RunCmd { /// value). Value of `all` will disable origin validation. Default is to /// allow localhost and origins. When running in /// --dev mode the default is to allow all origins. - #[structopt(long = "rpc-cors", value_name = "ORIGINS", parse(try_from_str = parse_cors))] + #[clap(long, value_name = "ORIGINS", parse(from_str = parse_cors))] pub rpc_cors: Option, /// Specify Prometheus exporter TCP Port. - #[structopt(long = "prometheus-port", value_name = "PORT")] + #[clap(long, value_name = "PORT")] pub prometheus_port: Option, /// Do not expose a Prometheus exporter endpoint. /// /// Prometheus metric endpoint is enabled by default. - #[structopt(long = "no-prometheus")] + #[clap(long)] pub no_prometheus: bool, /// The human-readable name for this node. /// /// The node name will be reported to the telemetry server, if enabled. - #[structopt(long = "name", value_name = "NAME")] + #[clap(long, value_name = "NAME")] pub name: Option, /// Disable connecting to the Substrate telemetry server. /// /// Telemetry is on by default on global chains. - #[structopt(long = "no-telemetry")] + #[clap(long)] pub no_telemetry: bool, /// The URL of the telemetry server to connect to. @@ -168,78 +168,78 @@ pub struct RunCmd { /// telemetry endpoints. Verbosity levels range from 0-9, with 0 denoting /// the least verbosity. /// Expected format is 'URL VERBOSITY', e.g. `--telemetry-url 'wss://foo/bar 0'`. - #[structopt(long = "telemetry-url", value_name = "URL VERBOSITY", parse(try_from_str = parse_telemetry_endpoints))] + #[clap(long = "telemetry-url", value_name = "URL VERBOSITY", parse(try_from_str = parse_telemetry_endpoints))] pub telemetry_endpoints: Vec<(String, u8)>, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub offchain_worker_params: OffchainWorkerParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub import_params: ImportParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub network_params: NetworkParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub pool_config: TransactionPoolParams, /// Shortcut for `--name Alice --validator` with session keys for `Alice` added to keystore. - #[structopt(long, conflicts_with_all = &["bob", "charlie", "dave", "eve", "ferdie", "one", "two"])] + #[clap(long, conflicts_with_all = &["bob", "charlie", "dave", "eve", "ferdie", "one", "two"])] pub alice: bool, /// Shortcut for `--name Bob --validator` with session keys for `Bob` added to keystore. - #[structopt(long, conflicts_with_all = &["alice", "charlie", "dave", "eve", "ferdie", "one", "two"])] + #[clap(long, conflicts_with_all = &["alice", "charlie", "dave", "eve", "ferdie", "one", "two"])] pub bob: bool, /// Shortcut for `--name Charlie --validator` with session keys for `Charlie` added to /// keystore. - #[structopt(long, conflicts_with_all = &["alice", "bob", "dave", "eve", "ferdie", "one", "two"])] + #[clap(long, conflicts_with_all = &["alice", "bob", "dave", "eve", "ferdie", "one", "two"])] pub charlie: bool, /// Shortcut for `--name Dave --validator` with session keys for `Dave` added to keystore. - #[structopt(long, conflicts_with_all = &["alice", "bob", "charlie", "eve", "ferdie", "one", "two"])] + #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "eve", "ferdie", "one", "two"])] pub dave: bool, /// Shortcut for `--name Eve --validator` with session keys for `Eve` added to keystore. - #[structopt(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "ferdie", "one", "two"])] + #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "ferdie", "one", "two"])] pub eve: bool, /// Shortcut for `--name Ferdie --validator` with session keys for `Ferdie` added to keystore. - #[structopt(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "one", "two"])] + #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "one", "two"])] pub ferdie: bool, /// Shortcut for `--name One --validator` with session keys for `One` added to keystore. - #[structopt(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "two"])] + #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "two"])] pub one: bool, /// Shortcut for `--name Two --validator` with session keys for `Two` added to keystore. - #[structopt(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "one"])] + #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "one"])] pub two: bool, /// Enable authoring even when offline. - #[structopt(long = "force-authoring")] + #[clap(long)] pub force_authoring: bool, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub keystore_params: KeystoreParams, /// The size of the instances cache for each runtime. /// /// The default value is 8 and the values higher than 256 are ignored. - #[structopt(long)] + #[clap(long)] pub max_runtime_instances: Option, /// Maximum number of different runtimes that can be cached. - #[structopt(long, default_value = "2")] + #[clap(long, default_value = "2")] pub runtime_cache_size: u8, /// Run a temporary node. @@ -251,7 +251,7 @@ pub struct RunCmd { /// which includes: database, node key and keystore. /// /// When `--dev` is given and no explicit `--base-path`, this option is implied. - #[structopt(long, conflicts_with = "base-path")] + #[clap(long, conflicts_with = "base-path")] pub tmp: bool, } @@ -562,8 +562,7 @@ fn parse_telemetry_endpoints(s: &str) -> std::result::Result<(String, u8), Telem /// CORS setting /// -/// The type is introduced to overcome `Option>` -/// handling of `structopt`. +/// The type is introduced to overcome `Option>` handling of `clap`. #[derive(Clone, Debug)] pub enum Cors { /// All hosts allowed. @@ -582,7 +581,7 @@ impl From for Option> { } /// Parse cors origins. -fn parse_cors(s: &str) -> std::result::Result> { +fn parse_cors(s: &str) -> Cors { let mut is_all = false; let mut origins = Vec::new(); for part in s.split(',') { @@ -595,7 +594,11 @@ fn parse_cors(s: &str) -> std::result::Result> } } - Ok(if is_all { Cors::All } else { Cors::List(origins) }) + if is_all { + Cors::All + } else { + Cors::List(origins) + } } #[cfg(test)] diff --git a/client/cli/src/commands/sign.rs b/client/cli/src/commands/sign.rs index 8d331d7994595..e0a5fce353ef4 100644 --- a/client/cli/src/commands/sign.rs +++ b/client/cli/src/commands/sign.rs @@ -18,34 +18,34 @@ //! Implementation of the `sign` subcommand use crate::{error, utils, with_crypto_scheme, CryptoSchemeFlag, KeystoreParams}; +use clap::Parser; use sp_core::crypto::SecretString; -use structopt::StructOpt; /// The `sign` command -#[derive(Debug, StructOpt, Clone)] -#[structopt(name = "sign", about = "Sign a message, with a given (secret) key")] +#[derive(Debug, Clone, Parser)] +#[clap(name = "sign", about = "Sign a message, with a given (secret) key")] pub struct SignCmd { /// The secret key URI. /// If the value is a file, the file content is used as URI. /// If not given, you will be prompted for the URI. - #[structopt(long)] + #[clap(long)] suri: Option, /// Message to sign, if not provided you will be prompted to /// pass the message via STDIN - #[structopt(long)] + #[clap(long)] message: Option, /// The message on STDIN is hex-encoded data - #[structopt(long)] + #[clap(long)] hex: bool, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub keystore_params: KeystoreParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub crypto_scheme: CryptoSchemeFlag, } @@ -75,14 +75,13 @@ fn sign( #[cfg(test)] mod test { - use super::SignCmd; - use structopt::StructOpt; + use super::*; #[test] fn sign() { let seed = "0xad1fb77243b536b90cfe5f0d351ab1b1ac40e3890b41dc64f766ee56340cfca5"; - let sign = SignCmd::from_iter(&[ + let sign = SignCmd::parse_from(&[ "sign", "--suri", seed, diff --git a/client/cli/src/commands/vanity.rs b/client/cli/src/commands/vanity.rs index f2959a33dbfdf..834b220df6388 100644 --- a/client/cli/src/commands/vanity.rs +++ b/client/cli/src/commands/vanity.rs @@ -21,30 +21,30 @@ use crate::{ error, utils, with_crypto_scheme, CryptoSchemeFlag, NetworkSchemeFlag, OutputTypeFlag, }; +use clap::Parser; use rand::{rngs::OsRng, RngCore}; use sp_core::crypto::{unwrap_or_default_ss58_version, Ss58AddressFormat, Ss58Codec}; use sp_runtime::traits::IdentifyAccount; -use structopt::StructOpt; use utils::print_from_uri; /// The `vanity` command -#[derive(Debug, StructOpt, Clone)] -#[structopt(name = "vanity", about = "Generate a seed that provides a vanity address")] +#[derive(Debug, Clone, Parser)] +#[clap(name = "vanity", about = "Generate a seed that provides a vanity address")] pub struct VanityCmd { /// Desired pattern - #[structopt(long, parse(try_from_str = assert_non_empty_string))] + #[clap(long, parse(try_from_str = assert_non_empty_string))] pattern: String, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] network_scheme: NetworkSchemeFlag, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] output_scheme: OutputTypeFlag, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] crypto_scheme: CryptoSchemeFlag, } @@ -166,13 +166,12 @@ mod tests { crypto::{default_ss58_version, Ss58AddressFormatRegistry, Ss58Codec}, sr25519, Pair, }; - use structopt::StructOpt; #[cfg(feature = "bench")] use test::Bencher; #[test] fn vanity() { - let vanity = VanityCmd::from_iter(&["vanity", "--pattern", "j"]); + let vanity = VanityCmd::parse_from(&["vanity", "--pattern", "j"]); assert!(vanity.run().is_ok()); } diff --git a/client/cli/src/commands/verify.rs b/client/cli/src/commands/verify.rs index 9ffd5d9d4844e..a8879f42caafc 100644 --- a/client/cli/src/commands/verify.rs +++ b/client/cli/src/commands/verify.rs @@ -19,12 +19,12 @@ //! implementation of the `verify` subcommand use crate::{error, utils, with_crypto_scheme, CryptoSchemeFlag}; +use clap::Parser; use sp_core::crypto::{ByteArray, Ss58Codec}; -use structopt::StructOpt; /// The `verify` command -#[derive(Debug, StructOpt, Clone)] -#[structopt( +#[derive(Debug, Clone, Parser)] +#[clap( name = "verify", about = "Verify a signature for a message, provided on STDIN, with a given (public or secret) key" )] @@ -39,15 +39,15 @@ pub struct VerifyCmd { /// Message to verify, if not provided you will be prompted to /// pass the message via STDIN - #[structopt(long)] + #[clap(long)] message: Option, /// The message on STDIN is hex-encoded data - #[structopt(long)] + #[clap(long)] hex: bool, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub crypto_scheme: CryptoSchemeFlag, } diff --git a/client/cli/src/error.rs b/client/cli/src/error.rs index 7f3bd84148d12..69b2eeaaf6186 100644 --- a/client/cli/src/error.rs +++ b/client/cli/src/error.rs @@ -31,7 +31,7 @@ pub enum Error { Io(#[from] std::io::Error), #[error(transparent)] - Cli(#[from] structopt::clap::Error), + Cli(#[from] clap::Error), #[error(transparent)] Service(#[from] sc_service::Error), diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index 8760e955c69ba..c242050dbf32a 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -30,6 +30,8 @@ mod params; mod runner; pub use arg_enums::*; +pub use clap; +use clap::{AppSettings, FromArgMatches, IntoApp, Parser}; pub use commands::*; pub use config::*; pub use error::*; @@ -39,12 +41,6 @@ use sc_service::Configuration; pub use sc_service::{ChainSpec, Role}; pub use sc_tracing::logging::LoggerBuilder; pub use sp_version::RuntimeVersion; -use std::io::Write; -pub use structopt; -use structopt::{ - clap::{self, AppSettings}, - StructOpt, -}; /// Substrate client CLI /// @@ -103,7 +99,7 @@ pub trait SubstrateCli: Sized { /// error message and quit the program in case of failure. fn from_args() -> Self where - Self: StructOpt + Sized, + Self: Parser + Sized, { ::from_iter(&mut std::env::args_os()) } @@ -120,11 +116,11 @@ pub trait SubstrateCli: Sized { /// Print the error message and quit the program in case of failure. fn from_iter(iter: I) -> Self where - Self: StructOpt + Sized, + Self: Parser + Sized, I: IntoIterator, I::Item: Into + Clone, { - let app = ::clap(); + let app = ::into_app(); let mut full_version = Self::impl_version(); full_version.push_str("\n"); @@ -137,34 +133,15 @@ pub trait SubstrateCli: Sized { .author(author.as_str()) .about(about.as_str()) .version(full_version.as_str()) - .settings(&[ - AppSettings::GlobalVersion, - AppSettings::ArgsNegateSubcommands, - AppSettings::SubcommandsNegateReqs, - AppSettings::ColoredHelp, - ]); - - let matches = match app.get_matches_from_safe(iter) { - Ok(matches) => matches, - Err(mut e) => { - // To support pipes, we can not use `writeln!` as any error - // results in a "broken pipe" error. - // - // Instead we write directly to `stdout` and ignore any error - // as we exit afterwards anyway. - e.message.extend("\n".chars()); - - if e.use_stderr() { - let _ = std::io::stderr().write_all(e.message.as_bytes()); - std::process::exit(1); - } else { - let _ = std::io::stdout().write_all(e.message.as_bytes()); - std::process::exit(0); - } - }, - }; - - ::from_clap(&matches) + .setting( + AppSettings::PropagateVersion | + AppSettings::ArgsNegateSubcommands | + AppSettings::SubcommandsNegateReqs, + ); + + let matches = app.try_get_matches_from(iter).unwrap_or_else(|e| e.exit()); + + ::from_arg_matches(&matches).unwrap_or_else(|e| e.exit()) } /// Helper function used to parse the command line arguments. This is the equivalent of @@ -180,15 +157,15 @@ pub trait SubstrateCli: Sized { /// /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are /// used. It will return a [`clap::Error`], where the [`clap::Error::kind`] is a - /// [`clap::ErrorKind::HelpDisplayed`] or [`clap::ErrorKind::VersionDisplayed`] respectively. + /// [`clap::ErrorKind::DisplayHelp`] or [`clap::ErrorKind::DisplayVersion`] respectively. /// You must call [`clap::Error::exit`] or perform a [`std::process::exit`]. fn try_from_iter(iter: I) -> clap::Result where - Self: StructOpt + Sized, + Self: Parser + Sized, I: IntoIterator, I::Item: Into + Clone, { - let app = ::clap(); + let app = ::into_app(); let mut full_version = Self::impl_version(); full_version.push_str("\n"); @@ -202,9 +179,9 @@ pub trait SubstrateCli: Sized { .about(about.as_str()) .version(full_version.as_str()); - let matches = app.get_matches_from_safe(iter)?; + let matches = app.try_get_matches_from(iter)?; - Ok(::from_clap(&matches)) + ::from_arg_matches(&matches) } /// Returns the client ID: `{impl_name}/v{impl_version}` diff --git a/client/cli/src/params/database_params.rs b/client/cli/src/params/database_params.rs index f034ae00473ca..dd11c21f432b1 100644 --- a/client/cli/src/params/database_params.rs +++ b/client/cli/src/params/database_params.rs @@ -17,24 +17,24 @@ // along with this program. If not, see . use crate::arg_enums::Database; +use clap::Args; use sc_service::TransactionStorageMode; -use structopt::StructOpt; /// Parameters for block import. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct DatabaseParams { /// Select database backend to use. - #[structopt( + #[clap( long, alias = "db", value_name = "DB", - case_insensitive = true, - possible_values = &Database::variants(), + ignore_case = true, + possible_values = Database::variants(), )] pub database: Option, /// Limit the memory the database cache can use. - #[structopt(long = "db-cache", value_name = "MiB")] + #[clap(long = "db-cache", value_name = "MiB")] pub database_cache_size: Option, /// Enable storage chain mode @@ -43,7 +43,7 @@ pub struct DatabaseParams { /// If this is enabled, each transaction is stored separately in the /// transaction database column and is only referenced by hash /// in the block body column. - #[structopt(long)] + #[clap(long)] pub storage_chain: bool, } diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index 7e1478d71e3fc..1ec79800136d3 100644 --- a/client/cli/src/params/import_params.rs +++ b/client/cli/src/params/import_params.rs @@ -24,9 +24,9 @@ use crate::{ }, params::{DatabaseParams, PruningParams}, }; +use clap::Args; use sc_client_api::execution_extensions::ExecutionStrategies; use std::path::PathBuf; -use structopt::StructOpt; #[cfg(feature = "wasmtime")] const WASM_METHOD_DEFAULT: &str = "Compiled"; @@ -35,14 +35,14 @@ const WASM_METHOD_DEFAULT: &str = "Compiled"; const WASM_METHOD_DEFAULT: &str = "interpreted-i-know-what-i-do"; /// Parameters for block import. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct ImportParams { #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub pruning_params: PruningParams, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub database_params: DatabaseParams, /// Force start with unsafe pruning settings. @@ -50,15 +50,15 @@ pub struct ImportParams { /// When running as a validator it is highly recommended to disable state /// pruning (i.e. 'archive') which is the default. The node will refuse to /// start as a validator if pruning is enabled unless this option is set. - #[structopt(long = "unsafe-pruning")] + #[clap(long)] pub unsafe_pruning: bool, /// Method for executing Wasm runtime code. - #[structopt( + #[clap( long = "wasm-execution", value_name = "METHOD", - possible_values = &WasmExecutionMethod::variants(), - case_insensitive = true, + possible_values = WasmExecutionMethod::variants(), + ignore_case = true, default_value = WASM_METHOD_DEFAULT )] pub wasm_method: WasmExecutionMethod, @@ -66,15 +66,15 @@ pub struct ImportParams { /// Specify the path where local WASM runtimes are stored. /// /// These runtimes will override on-chain runtimes when the version matches. - #[structopt(long, value_name = "PATH", parse(from_os_str))] + #[clap(long, value_name = "PATH", parse(from_os_str))] pub wasm_runtime_overrides: Option, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub execution_strategies: ExecutionStrategiesParams, /// Specify the state cache size. - #[structopt(long = "state-cache-size", value_name = "Bytes", default_value = "67108864")] + #[clap(long, value_name = "Bytes", default_value = "67108864")] pub state_cache_size: usize, } @@ -127,62 +127,37 @@ impl ImportParams { } /// Execution strategies parameters. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct ExecutionStrategiesParams { /// The means of execution used when calling into the runtime for importing blocks as /// part of an initial sync. - #[structopt( - long = "execution-syncing", - value_name = "STRATEGY", - possible_values = &ExecutionStrategy::variants(), - case_insensitive = true, - )] + #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] pub execution_syncing: Option, /// The means of execution used when calling into the runtime for general block import /// (including locally authored blocks). - #[structopt( - long = "execution-import-block", - value_name = "STRATEGY", - possible_values = &ExecutionStrategy::variants(), - case_insensitive = true, - )] + #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] pub execution_import_block: Option, /// The means of execution used when calling into the runtime while constructing blocks. - #[structopt( - long = "execution-block-construction", - value_name = "STRATEGY", - possible_values = &ExecutionStrategy::variants(), - case_insensitive = true, - )] + #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] pub execution_block_construction: Option, /// The means of execution used when calling into the runtime while using an off-chain worker. - #[structopt( - long = "execution-offchain-worker", - value_name = "STRATEGY", - possible_values = &ExecutionStrategy::variants(), - case_insensitive = true, - )] + #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] pub execution_offchain_worker: Option, /// The means of execution used when calling into the runtime while not syncing, importing or /// constructing blocks. - #[structopt( - long = "execution-other", - value_name = "STRATEGY", - possible_values = &ExecutionStrategy::variants(), - case_insensitive = true, - )] + #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] pub execution_other: Option, /// The execution strategy that should be used by all execution contexts. - #[structopt( - long = "execution", + #[clap( + long, value_name = "STRATEGY", - possible_values = &ExecutionStrategy::variants(), - case_insensitive = true, + arg_enum, + ignore_case = true, conflicts_with_all = &[ "execution-other", "execution-offchain-worker", diff --git a/client/cli/src/params/keystore_params.rs b/client/cli/src/params/keystore_params.rs index 5dbab5d9e8e34..72b09134f57a4 100644 --- a/client/cli/src/params/keystore_params.rs +++ b/client/cli/src/params/keystore_params.rs @@ -17,50 +17,47 @@ // along with this program. If not, see . use crate::{error, error::Result}; +use clap::Args; use sc_service::config::KeystoreConfig; use sp_core::crypto::SecretString; use std::{ fs, path::{Path, PathBuf}, }; -use structopt::StructOpt; /// default sub directory for the key store const DEFAULT_KEYSTORE_CONFIG_PATH: &'static str = "keystore"; /// Parameters of the keystore -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct KeystoreParams { /// Specify custom URIs to connect to for keystore-services - #[structopt(long = "keystore-uri")] + #[clap(long)] pub keystore_uri: Option, /// Specify custom keystore path. - #[structopt(long = "keystore-path", value_name = "PATH", parse(from_os_str))] + #[clap(long, value_name = "PATH", parse(from_os_str))] pub keystore_path: Option, /// Use interactive shell for entering the password used by the keystore. - #[structopt( - long = "password-interactive", - conflicts_with_all = &[ "password", "password-filename" ] - )] + #[clap(long, conflicts_with_all = &["password", "password-filename"])] pub password_interactive: bool, /// Password used by the keystore. This allows appending an extra user-defined secret to the /// seed. - #[structopt( - long = "password", + #[clap( + long, parse(try_from_str = secret_string_from_str), - conflicts_with_all = &[ "password-interactive", "password-filename" ] + conflicts_with_all = &["password-interactive", "password-filename"] )] pub password: Option, /// File that contains the password used by the keystore. - #[structopt( - long = "password-filename", + #[clap( + long, value_name = "PATH", parse(from_os_str), - conflicts_with_all = &[ "password-interactive", "password" ] + conflicts_with_all = &["password-interactive", "password"] )] pub password_filename: Option, } diff --git a/client/cli/src/params/mod.rs b/client/cli/src/params/mod.rs index e6f81079263de..e0571aa4bbbf8 100644 --- a/client/cli/src/params/mod.rs +++ b/client/cli/src/params/mod.rs @@ -26,13 +26,13 @@ mod shared_params; mod transaction_pool_params; use crate::arg_enums::{CryptoScheme, OutputType}; +use clap::Args; use sp_core::crypto::Ss58AddressFormat; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor}, }; use std::{convert::TryFrom, fmt::Debug, str::FromStr}; -use structopt::StructOpt; pub use crate::params::{ database_params::*, import_params::*, keystore_params::*, network_params::*, @@ -115,44 +115,32 @@ impl BlockNumberOrHash { } /// Optional flag for specifying crypto algorithm -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct CryptoSchemeFlag { /// cryptography scheme - #[structopt( - long, - value_name = "SCHEME", - possible_values = &CryptoScheme::variants(), - case_insensitive = true, - default_value = "Sr25519" - )] + #[clap(long, value_name = "SCHEME", arg_enum, ignore_case = true, default_value = "Sr25519")] pub scheme: CryptoScheme, } /// Optional flag for specifying output type -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct OutputTypeFlag { /// output format - #[structopt( - long, - value_name = "FORMAT", - possible_values = &OutputType::variants(), - case_insensitive = true, - default_value = "Text" - )] + #[clap(long, value_name = "FORMAT", arg_enum, ignore_case = true, default_value = "Text")] pub output_type: OutputType, } /// Optional flag for specifying network scheme -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct NetworkSchemeFlag { /// network address format - #[structopt( + #[clap( + short = 'n', long, value_name = "NETWORK", - short = "n", possible_values = &Ss58AddressFormat::all_names()[..], + ignore_case = true, parse(try_from_str = Ss58AddressFormat::try_from), - case_insensitive = true, )] pub network: Option, } diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 86060486144ac..1de2896cba731 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -17,6 +17,7 @@ // along with this program. If not, see . use crate::{arg_enums::SyncMode, params::node_key_params::NodeKeyParams}; +use clap::Args; use sc_network::{ config::{ NetworkConfiguration, NodeKeyConfig, NonReservedPeerMode, SetConfig, TransportConfig, @@ -28,17 +29,16 @@ use sc_service::{ ChainSpec, ChainType, }; use std::{borrow::Cow, path::PathBuf}; -use structopt::StructOpt; /// Parameters used to create the network configuration. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct NetworkParams { /// Specify a list of bootnodes. - #[structopt(long = "bootnodes", value_name = "ADDR")] + #[clap(long, value_name = "ADDR")] pub bootnodes: Vec, /// Specify a list of reserved node addresses. - #[structopt(long = "reserved-nodes", value_name = "ADDR")] + #[clap(long, value_name = "ADDR")] pub reserved_nodes: Vec, /// Whether to only synchronize the chain with reserved nodes. @@ -49,12 +49,12 @@ pub struct NetworkParams { /// In particular, if you are a validator your node might still connect to other /// validator nodes and collator nodes regardless of whether they are defined as /// reserved nodes. - #[structopt(long = "reserved-only")] + #[clap(long)] pub reserved_only: bool, /// The public address that other nodes will use to connect to it. /// This can be used if there's a proxy in front of this node. - #[structopt(long, value_name = "PUBLIC_ADDR")] + #[clap(long, value_name = "PUBLIC_ADDR")] pub public_addr: Vec, /// Listen on this multiaddress. @@ -62,60 +62,60 @@ pub struct NetworkParams { /// By default: /// If `--validator` is passed: `/ip4/0.0.0.0/tcp/` and `/ip6/[::]/tcp/`. /// Otherwise: `/ip4/0.0.0.0/tcp//ws` and `/ip6/[::]/tcp//ws`. - #[structopt(long = "listen-addr", value_name = "LISTEN_ADDR")] + #[clap(long, value_name = "LISTEN_ADDR")] pub listen_addr: Vec, /// Specify p2p protocol TCP port. - #[structopt(long = "port", value_name = "PORT", conflicts_with_all = &[ "listen-addr" ])] + #[clap(long, value_name = "PORT", conflicts_with_all = &[ "listen-addr" ])] pub port: Option, /// Always forbid connecting to private IPv4 addresses (as specified in /// [RFC1918](https://tools.ietf.org/html/rfc1918)), unless the address was passed with /// `--reserved-nodes` or `--bootnodes`. Enabled by default for chains marked as "live" in /// their chain specifications. - #[structopt(long = "no-private-ipv4", conflicts_with_all = &["allow-private-ipv4"])] + #[clap(long, conflicts_with_all = &["allow-private-ipv4"])] pub no_private_ipv4: bool, /// Always accept connecting to private IPv4 addresses (as specified in /// [RFC1918](https://tools.ietf.org/html/rfc1918)). Enabled by default for chains marked as /// "local" in their chain specifications, or when `--dev` is passed. - #[structopt(long = "allow-private-ipv4", conflicts_with_all = &["no-private-ipv4"])] + #[clap(long, conflicts_with_all = &["no-private-ipv4"])] pub allow_private_ipv4: bool, /// Specify the number of outgoing connections we're trying to maintain. - #[structopt(long = "out-peers", value_name = "COUNT", default_value = "25")] + #[clap(long, value_name = "COUNT", default_value = "25")] pub out_peers: u32, /// Maximum number of inbound full nodes peers. - #[structopt(long = "in-peers", value_name = "COUNT", default_value = "25")] + #[clap(long, value_name = "COUNT", default_value = "25")] pub in_peers: u32, /// Maximum number of inbound light nodes peers. - #[structopt(long = "in-peers-light", value_name = "COUNT", default_value = "100")] + #[clap(long, value_name = "COUNT", default_value = "100")] pub in_peers_light: u32, /// Disable mDNS discovery. /// /// By default, the network will use mDNS to discover other nodes on the /// local network. This disables it. Automatically implied when using --dev. - #[structopt(long = "no-mdns")] + #[clap(long)] pub no_mdns: bool, /// Maximum number of peers from which to ask for the same blocks in parallel. /// /// This allows downloading announced blocks from multiple peers. Decrease to save /// traffic and risk increased latency. - #[structopt(long = "max-parallel-downloads", value_name = "COUNT", default_value = "5")] + #[clap(long, value_name = "COUNT", default_value = "5")] pub max_parallel_downloads: u32, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub node_key_params: NodeKeyParams, /// Enable peer discovery on local networks. /// /// By default this option is `true` for `--dev` or when the chain type is /// `Local`/`Development` and false otherwise. - #[structopt(long)] + #[clap(long)] pub discover_local: bool, /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in @@ -123,11 +123,11 @@ pub struct NetworkParams { /// /// See the S/Kademlia paper for more information on the high level design as well as its /// security improvements. - #[structopt(long)] + #[clap(long)] pub kademlia_disjoint_query_paths: bool, /// Join the IPFS network and serve transactions over bitswap protocol. - #[structopt(long)] + #[clap(long)] pub ipfs_server: bool, /// Blockchain syncing mode. @@ -137,7 +137,7 @@ pub struct NetworkParams { /// - `Fast`: Download blocks and the latest state only. /// /// - `FastUnsafe`: Same as `Fast`, but skip downloading state proofs. - #[structopt(long, value_name = "SYNC_MODE", default_value = "Full")] + #[clap(long, arg_enum, value_name = "SYNC_MODE", default_value = "Full")] pub sync: SyncMode, } diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index 23f3fba1cdb04..f31fd854cbb56 100644 --- a/client/cli/src/params/node_key_params.rs +++ b/client/cli/src/params/node_key_params.rs @@ -16,10 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use clap::Args; use sc_network::config::{identity::ed25519, NodeKeyConfig}; use sp_core::H256; use std::{path::PathBuf, str::FromStr}; -use structopt::StructOpt; use crate::{arg_enums::NodeKeyType, error}; @@ -30,7 +30,7 @@ const NODE_KEY_ED25519_FILE: &str = "secret_ed25519"; /// Parameters used to create the `NodeKeyConfig`, which determines the keypair /// used for libp2p networking. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct NodeKeyParams { /// The secret key to use for libp2p networking. /// @@ -46,7 +46,7 @@ pub struct NodeKeyParams { /// WARNING: Secrets provided as command-line arguments are easily exposed. /// Use of this option should be limited to development and testing. To use /// an externally managed secret key, use `--node-key-file` instead. - #[structopt(long = "node-key", value_name = "KEY")] + #[clap(long, value_name = "KEY")] pub node_key: Option, /// The type of secret key to use for libp2p networking. @@ -66,13 +66,7 @@ pub struct NodeKeyParams { /// /// The node's secret key determines the corresponding public key and hence the /// node's peer ID in the context of libp2p. - #[structopt( - long = "node-key-type", - value_name = "TYPE", - possible_values = &NodeKeyType::variants(), - case_insensitive = true, - default_value = "Ed25519" - )] + #[clap(long, value_name = "TYPE", arg_enum, ignore_case = true, default_value = "Ed25519")] pub node_key_type: NodeKeyType, /// The file from which to read the node's secret key to use for libp2p networking. @@ -85,7 +79,7 @@ pub struct NodeKeyParams { /// /// If the file does not exist, it is created with a newly generated secret key of /// the chosen type. - #[structopt(long = "node-key-file", value_name = "FILE")] + #[clap(long, value_name = "FILE")] pub node_key_file: Option, } @@ -128,14 +122,15 @@ fn parse_ed25519_secret(hex: &str) -> error::Result error::Result<()> { - NodeKeyType::variants().iter().try_for_each(|t| { - let node_key_type = NodeKeyType::from_str(t).unwrap(); + NodeKeyType::value_variants().iter().try_for_each(|t| { + let node_key_type = *t; let sk = match node_key_type { NodeKeyType::Ed25519 => ed25519::SecretKey::generate().as_ref().to_vec(), }; @@ -194,8 +189,8 @@ mod tests { where F: Fn(NodeKeyParams) -> error::Result<()>, { - NodeKeyType::variants().iter().try_for_each(|t| { - let node_key_type = NodeKeyType::from_str(t).unwrap(); + NodeKeyType::value_variants().iter().try_for_each(|t| { + let node_key_type = *t; f(NodeKeyParams { node_key_type, node_key: None, node_key_file: None }) }) } diff --git a/client/cli/src/params/offchain_worker_params.rs b/client/cli/src/params/offchain_worker_params.rs index ac71d3a7580e7..3ab507f108598 100644 --- a/client/cli/src/params/offchain_worker_params.rs +++ b/client/cli/src/params/offchain_worker_params.rs @@ -23,23 +23,23 @@ //! targeted at handling input parameter parsing providing //! a reasonable abstraction. +use clap::Args; use sc_network::config::Role; use sc_service::config::OffchainWorkerConfig; -use structopt::StructOpt; use crate::{error, OffchainWorkerEnabled}; /// Offchain worker related parameters. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct OffchainWorkerParams { /// Should execute offchain workers on every block. /// /// By default it's only enabled for nodes that are authoring new blocks. - #[structopt( + #[clap( long = "offchain-worker", value_name = "ENABLED", - possible_values = &OffchainWorkerEnabled::variants(), - case_insensitive = true, + arg_enum, + ignore_case = true, default_value = "WhenValidating" )] pub enabled: OffchainWorkerEnabled, @@ -48,7 +48,7 @@ pub struct OffchainWorkerParams { /// /// Enables a runtime to write directly to a offchain workers /// DB during block import. - #[structopt(long = "enable-offchain-indexing", value_name = "ENABLE_OFFCHAIN_INDEXING")] + #[clap(long = "enable-offchain-indexing", value_name = "ENABLE_OFFCHAIN_INDEXING")] pub indexing_enabled: bool, } diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index facf982ef8dd5..a8516ee1453ac 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -17,23 +17,23 @@ // along with this program. If not, see . use crate::error; +use clap::Args; use sc_service::{KeepBlocks, PruningMode, Role}; -use structopt::StructOpt; /// Parameters to define the pruning mode -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct PruningParams { /// Specify the state pruning mode, a number of blocks to keep or 'archive'. /// /// Default is to keep all block states if the node is running as a /// validator (i.e. 'archive'), otherwise state is only kept for the last /// 256 blocks. - #[structopt(long = "pruning", value_name = "PRUNING_MODE")] + #[clap(long, value_name = "PRUNING_MODE")] pub pruning: Option, /// Specify the number of finalized blocks to keep in the database. /// /// Default is to keep all blocks. - #[structopt(long, value_name = "COUNT")] + #[clap(long, value_name = "COUNT")] pub keep_blocks: Option, } diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index d385efad42784..a4f2271e12c48 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -17,36 +17,36 @@ // along with this program. If not, see . use crate::arg_enums::TracingReceiver; +use clap::Args; use sc_service::config::BasePath; use std::path::PathBuf; -use structopt::StructOpt; /// Shared parameters used by all `CoreParams`. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct SharedParams { /// Specify the chain specification. /// /// It can be one of the predefined ones (dev, local, or staging) or it can be a path to a file /// with the chainspec (such as one exported by the `build-spec` subcommand). - #[structopt(long, value_name = "CHAIN_SPEC")] + #[clap(long, value_name = "CHAIN_SPEC")] pub chain: Option, /// Specify the development chain. /// /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, /// `--alice`, and `--tmp` flags, unless explicitly overridden. - #[structopt(long, conflicts_with_all = &["chain"])] + #[clap(long, conflicts_with_all = &["chain"])] pub dev: bool, /// Specify custom base path. - #[structopt(long, short = "d", value_name = "PATH", parse(from_os_str))] + #[clap(long, short = 'd', value_name = "PATH", parse(from_os_str))] pub base_path: Option, /// Sets a custom logging filter. Syntax is =, e.g. -lsync=debug. /// /// Log levels (least to most verbose) are error, warn, info, debug, and trace. /// By default, all targets log `info`. The global log level can be set with -l. - #[structopt(short = "l", long, value_name = "LOG_PATTERN")] + #[clap(short = 'l', long, value_name = "LOG_PATTERN")] pub log: Vec, /// Enable detailed log output. @@ -54,11 +54,11 @@ pub struct SharedParams { /// This includes displaying the log target, log level and thread name. /// /// This is automatically enabled when something is logged with any higher level than `info`. - #[structopt(long)] + #[clap(long)] pub detailed_log_output: bool, /// Disable log color output. - #[structopt(long)] + #[clap(long)] pub disable_log_color: bool, /// Enable feature to dynamically update and reload the log filter. @@ -68,21 +68,15 @@ pub struct SharedParams { /// /// The `system_addLogFilter` and `system_resetLogFilter` RPCs will have no effect with this /// option not being set. - #[structopt(long)] + #[clap(long)] pub enable_log_reloading: bool, /// Sets a custom profiling filter. Syntax is the same as for logging: = - #[structopt(long = "tracing-targets", value_name = "TARGETS")] + #[clap(long, value_name = "TARGETS")] pub tracing_targets: Option, /// Receiver to process tracing messages. - #[structopt( - long = "tracing-receiver", - value_name = "RECEIVER", - possible_values = &TracingReceiver::variants(), - case_insensitive = true, - default_value = "Log" - )] + #[clap(long, value_name = "RECEIVER", arg_enum, ignore_case = true, default_value = "Log")] pub tracing_receiver: TracingReceiver, } diff --git a/client/cli/src/params/transaction_pool_params.rs b/client/cli/src/params/transaction_pool_params.rs index dee8f57eb39c8..efb78430ced55 100644 --- a/client/cli/src/params/transaction_pool_params.rs +++ b/client/cli/src/params/transaction_pool_params.rs @@ -16,18 +16,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use clap::Args; use sc_service::config::TransactionPoolOptions; -use structopt::StructOpt; /// Parameters used to create the pool configuration. -#[derive(Debug, StructOpt, Clone)] +#[derive(Debug, Clone, Args)] pub struct TransactionPoolParams { /// Maximum number of transactions in the transaction pool. - #[structopt(long = "pool-limit", value_name = "COUNT", default_value = "8192")] + #[clap(long, value_name = "COUNT", default_value = "8192")] pub pool_limit: usize, /// Maximum number of kilobytes of all transactions stored in the pool. - #[structopt(long = "pool-kbytes", value_name = "COUNT", default_value = "20480")] + #[clap(long, value_name = "COUNT", default_value = "20480")] pub pool_kbytes: usize, } diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index d8797ad360ba4..b5122ebbafe76 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -31,7 +31,5 @@ sp-std = { path = "../../../primitives/std", version = "4.0.0" } remote-externalities = { path = "../../../utils/frame/remote-externalities", version = "0.10.0-dev" } # others -tokio = { version = "1", features = ["macros"] } log = "0.4.14" -structopt = "0.3.25" -clap = "2.34.0" +tokio = { version = "1", features = ["macros"] } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 83228b9251ddf..43f2b54044c9b 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -21,10 +21,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] log = { version = "0.4.11", default-features = false } serde = { version = "1.0.132", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } -primitive-types = { version = "0.10.1", default-features = false, features = [ - "codec", - "scale-info" -] } +primitive-types = { version = "0.10.1", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.3.0", optional = true } wasmi = { version = "0.9.1", optional = true } hash-db = { version = "0.15.2", default-features = false } @@ -43,19 +40,14 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } sp-storage = { version = "4.0.0", default-features = false, path = "../storage" } sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" } -parity-util-mem = { version = "0.10.2", default-features = false, features = [ - "primitive-types", -] } +parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } futures = { version = "0.3.1", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.30", optional = true } bitflags = "1.3" # full crypto -ed25519-dalek = { version = "1.0.1", default-features = false, features = [ - "u64_backend", - "alloc", -], optional = true } +ed25519-dalek = { version = "1.0.1", default-features = false, features = ["u64_backend", "alloc"], optional = true } blake2-rfc = { version = "0.2.18", default-features = false, optional = true } tiny-keccak = { version = "2.0.1", features = ["keccak"], optional = true } schnorrkel = { version = "0.9.1", features = [ @@ -67,7 +59,7 @@ hex = { version = "0.4", default-features = false, optional = true } twox-hash = { version = "1.6.2", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", "static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } -ss58-registry = { version = "1.10.0", default-features = false } +ss58-registry = { version = "1.11.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "4.1.0-dev", default-features = false, path = "../runtime-interface" } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 17423b624760e..3b6103552e214 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -14,13 +14,14 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] +clap = { version = "3.0", features = ["derive"] } +honggfuzz = "0.5" +rand = { version = "0.8", features = ["std", "small_rng"] } + codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -honggfuzz = "0.5" -rand = { version = "0.7.3", features = ["std", "small_rng"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } sp-runtime = { version = "4.1.0-dev", path = "../../runtime" } -structopt = "0.3.25" [[bin]] name = "reduce" diff --git a/primitives/npos-elections/fuzzer/src/common.rs b/primitives/npos-elections/fuzzer/src/common.rs index 7ca66f72dd92b..ab765d20640e2 100644 --- a/primitives/npos-elections/fuzzer/src/common.rs +++ b/primitives/npos-elections/fuzzer/src/common.rs @@ -68,7 +68,7 @@ pub fn generate_random_npos_inputs( // always generate a sensible desired number of candidates: elections are uninteresting if we // desire 0 candidates, or a number of candidates >= the actual number of candidates present - let rounds = rng.gen_range(1, candidate_count); + let rounds = rng.gen_range(1..candidate_count); // candidates are easy: just a completely random set of IDs let mut candidates: Vec = Vec::with_capacity(candidate_count); @@ -95,7 +95,7 @@ pub fn generate_random_npos_inputs( let vote_weight = rng.gen(); // it's not interesting if a voter chooses 0 or all candidates, so rule those cases out. - let n_candidates_chosen = rng.gen_range(1, candidates.len()); + let n_candidates_chosen = rng.gen_range(1..candidates.len()); let mut chosen_candidates = Vec::with_capacity(n_candidates_chosen); chosen_candidates.extend(candidates.choose_multiple(&mut rng, n_candidates_chosen)); @@ -132,25 +132,25 @@ pub fn generate_random_npos_result( (1..=target_count).for_each(|acc| { candidates.push(acc); - let stake_var = rng.gen_range(ed, 100 * ed); + let stake_var = rng.gen_range(ed..100 * ed); stake_of.insert(acc, base_stake + stake_var); }); let mut voters = Vec::with_capacity(voter_count as usize); (prefix..=(prefix + voter_count)).for_each(|acc| { - let edge_per_this_voter = rng.gen_range(1, candidates.len()); + let edge_per_this_voter = rng.gen_range(1..candidates.len()); // all possible targets let mut all_targets = candidates.clone(); // we remove and pop into `targets` `edge_per_this_voter` times. let targets = (0..edge_per_this_voter) .map(|_| { let upper = all_targets.len() - 1; - let idx = rng.gen_range(0, upper); + let idx = rng.gen_range(0..upper); all_targets.remove(idx) }) .collect::>(); - let stake_var = rng.gen_range(ed, 100 * ed); + let stake_var = rng.gen_range(ed..100 * ed); let stake = base_stake + stake_var; stake_of.insert(acc, stake); voters.push((acc, stake, targets)); diff --git a/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs b/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs index 59763a58686dd..2396fdfa3b40e 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs @@ -42,7 +42,7 @@ use honggfuzz::fuzz; #[cfg(not(fuzzing))] -use structopt::StructOpt; +use clap::Parser; mod common; use common::{generate_random_npos_inputs, to_range}; @@ -67,24 +67,25 @@ fn main() { } #[cfg(not(fuzzing))] -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] +#[clap(author, version, about)] struct Opt { /// How many candidates participate in this election - #[structopt(short, long)] + #[clap(short, long)] candidates: Option, /// How many voters participate in this election - #[structopt(short, long)] + #[clap(short, long)] voters: Option, /// Random seed to use in this election - #[structopt(long)] + #[clap(long)] seed: Option, } #[cfg(not(fuzzing))] fn main() { - let opt = Opt::from_args(); + let opt = Opt::parse(); // candidates and voters by default use the maxima, which turn out to be one less than // the constant. iteration( diff --git a/primitives/npos-elections/fuzzer/src/reduce.rs b/primitives/npos-elections/fuzzer/src/reduce.rs index ad3f7dc260ef5..a77b40ca56d54 100644 --- a/primitives/npos-elections/fuzzer/src/reduce.rs +++ b/primitives/npos-elections/fuzzer/src/reduce.rs @@ -79,8 +79,7 @@ fn generate_random_phragmen_assignment( let mut targets_to_chose_from = all_targets.clone(); let targets_to_chose = if edge_per_voter_var > 0 { rng.gen_range( - avg_edge_per_voter - edge_per_voter_var, - avg_edge_per_voter + edge_per_voter_var, + avg_edge_per_voter - edge_per_voter_var..avg_edge_per_voter + edge_per_voter_var, ) } else { avg_edge_per_voter @@ -89,11 +88,11 @@ fn generate_random_phragmen_assignment( let distribution = (0..targets_to_chose) .map(|_| { let target = - targets_to_chose_from.remove(rng.gen_range(0, targets_to_chose_from.len())); + targets_to_chose_from.remove(rng.gen_range(0..targets_to_chose_from.len())); if winners.iter().all(|w| *w != target) { winners.push(target.clone()); } - (target, rng.gen_range(1 * KSM, 100 * KSM)) + (target, rng.gen_range(1 * KSM..100 * KSM)) }) .collect::>(); diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index fa91956ec7949..a7e5b76ad97ac 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -25,7 +25,7 @@ sp-keystore = { version = "0.10.0", path = "../../../primitives/keystore" } sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.10.0", path = "../../../primitives/state-machine" } codec = { version = "2.0.0", package = "parity-scale-codec" } -structopt = "0.3.25" +clap = { version = "3.0", features = ["derive"] } chrono = "0.4" serde = "1.0.132" handlebars = "4.1.6" diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 664e526ae0d7b..6afaa2b249fcf 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -28,124 +28,119 @@ fn parse_pallet_name(pallet: &str) -> String { } /// The `benchmark` command used to benchmark FRAME Pallets. -#[derive(Debug, structopt::StructOpt)] +#[derive(Debug, clap::Parser)] pub struct BenchmarkCmd { /// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`). - #[structopt(short, long, parse(from_str = parse_pallet_name), required_unless = "list")] + #[clap(short, long, parse(from_str = parse_pallet_name), required_unless_present = "list")] pub pallet: Option, /// Select an extrinsic inside the pallet to benchmark, or `*` for all. - #[structopt(short, long, required_unless = "list")] + #[clap(short, long, required_unless_present = "list")] pub extrinsic: Option, /// Select how many samples we should take across the variable components. - #[structopt(short, long, default_value = "1")] + #[clap(short, long, default_value = "1")] pub steps: u32, /// Indicates lowest values for each of the component ranges. - #[structopt(long = "low", use_delimiter = true)] + #[clap(long = "low", use_delimiter = true)] pub lowest_range_values: Vec, /// Indicates highest values for each of the component ranges. - #[structopt(long = "high", use_delimiter = true)] + #[clap(long = "high", use_delimiter = true)] pub highest_range_values: Vec, /// Select how many repetitions of this benchmark should run from within the wasm. - #[structopt(short, long, default_value = "1")] + #[clap(short, long, default_value = "1")] pub repeat: u32, /// Select how many repetitions of this benchmark should run from the client. /// /// NOTE: Using this alone may give slower results, but will afford you maximum Wasm memory. - #[structopt(long, default_value = "1")] + #[clap(long, default_value = "1")] pub external_repeat: u32, /// Print the raw results. - #[structopt(long = "raw")] + #[clap(long = "raw")] pub raw_data: bool, /// Don't print the median-slopes linear regression analysis. - #[structopt(long)] + #[clap(long)] pub no_median_slopes: bool, /// Don't print the min-squares linear regression analysis. - #[structopt(long)] + #[clap(long)] pub no_min_squares: bool, /// Output the benchmarks to a Rust file at the given path. - #[structopt(long)] + #[clap(long)] pub output: Option, /// Add a header file to your outputted benchmarks - #[structopt(long)] + #[clap(long)] pub header: Option, /// Path to Handlebars template file used for outputting benchmark results. (Optional) - #[structopt(long)] + #[clap(long)] pub template: Option, /// Which analysis function to use when outputting benchmarks: /// * min-squares (default) /// * median-slopes /// * max (max of min squares and median slopes for each value) - #[structopt(long)] + #[clap(long)] pub output_analysis: Option, /// Set the heap pages while running benchmarks. If not set, the default value from the client /// is used. - #[structopt(long)] + #[clap(long)] pub heap_pages: Option, /// Disable verification logic when running benchmarks. - #[structopt(long)] + #[clap(long)] pub no_verify: bool, /// Display and run extra benchmarks that would otherwise not be needed for weight /// construction. - #[structopt(long)] + #[clap(long)] pub extra: bool, /// Estimate PoV size. - #[structopt(long)] + #[clap(long)] pub record_proof: bool, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: sc_cli::SharedParams, /// The execution strategy that should be used for benchmarks - #[structopt( - long = "execution", - value_name = "STRATEGY", - possible_values = &ExecutionStrategy::variants(), - case_insensitive = true, - )] + #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] pub execution: Option, /// Method for executing Wasm runtime code. - #[structopt( + #[clap( long = "wasm-execution", value_name = "METHOD", - possible_values = &WasmExecutionMethod::variants(), - case_insensitive = true, + possible_values = WasmExecutionMethod::variants(), + ignore_case = true, default_value = "compiled" )] pub wasm_method: WasmExecutionMethod, /// Limit the memory the database cache can use. - #[structopt(long = "db-cache", value_name = "MiB", default_value = "1024")] + #[clap(long = "db-cache", value_name = "MiB", default_value = "1024")] pub database_cache_size: u32, /// List the benchmarks that match your query rather than running them. /// /// When nothing is provided, we list all benchmarks. - #[structopt(long)] + #[clap(long)] pub list: bool, /// If enabled, the storage info is not displayed in the output next to the analysis. /// /// This is independent of the storage info appearing in the *output file*. Use a Handlebar /// template for that purpose. - #[structopt(long)] + #[clap(long)] pub no_storage_info: bool, } diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index d256bba4b5b32..f330b205ea27f 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -11,10 +11,11 @@ documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" [dependencies] +clap = { version = "3.0", features = ["derive"] } + sp-core = { version = "4.1.0-dev", path = "../../../primitives/core" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } -structopt = "0.3.25" frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } diff --git a/utils/frame/frame-utilities-cli/src/pallet_id.rs b/utils/frame/frame-utilities-cli/src/pallet_id.rs index 2e139c639fd43..c39bee8b87463 100644 --- a/utils/frame/frame-utilities-cli/src/pallet_id.rs +++ b/utils/frame/frame-utilities-cli/src/pallet_id.rs @@ -17,6 +17,7 @@ //! Implementation of the `palletid` subcommand +use clap::Parser; use frame_support::PalletId; use sc_cli::{ utils::print_from_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, @@ -24,35 +25,34 @@ use sc_cli::{ }; use sp_core::crypto::{unwrap_or_default_ss58_version, Ss58AddressFormat, Ss58Codec}; use sp_runtime::traits::AccountIdConversion; -use structopt::StructOpt; /// The `palletid` command -#[derive(Debug, StructOpt)] -#[structopt(name = "palletid", about = "Inspect a module ID address")] +#[derive(Debug, Parser)] +#[clap(name = "palletid", about = "Inspect a module ID address")] pub struct PalletIdCmd { /// The module ID used to derive the account id: String, /// network address format - #[structopt( + #[clap( long, value_name = "NETWORK", possible_values = &Ss58AddressFormat::all_names()[..], parse(try_from_str = Ss58AddressFormat::try_from), - case_insensitive = true, + ignore_case = true, )] pub network: Option, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub output_scheme: OutputTypeFlag, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub crypto_scheme: CryptoSchemeFlag, #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub keystore_params: KeystoreParams, } diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 594683938517b..55670c96f792c 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -23,4 +23,3 @@ sp-io = { version = "4.0.0", path = "../../../primitives/io" } chrono = { version = "0.4.19" } git2 = { version = "0.13.25", default-features = false } num-format = { version = "0.4.0" } -structopt = "0.3.25" diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml index b5a7e0b898c92..11dee7b8b68ec 100644 --- a/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -14,4 +14,4 @@ node-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runtime" } generate-bags = { version = "4.0.0-dev", path = "../" } # third-party -structopt = "0.3.25" +clap = { version = "3.0", features = ["derive"] } diff --git a/utils/frame/generate-bags/node-runtime/src/main.rs b/utils/frame/generate-bags/node-runtime/src/main.rs index 72d1f0d8d22b9..12bcf8d28cf2b 100644 --- a/utils/frame/generate-bags/node-runtime/src/main.rs +++ b/utils/frame/generate-bags/node-runtime/src/main.rs @@ -17,30 +17,31 @@ //! Make the set of bag thresholds to be used with pallet-bags-list. +use clap::Parser; use generate_bags::generate_thresholds; use std::path::PathBuf; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] +// #[clap(author, version, about)] struct Opt { /// How many bags to generate. - #[structopt(long, default_value = "200")] + #[clap(long, default_value = "200")] n_bags: usize, /// Where to write the output. output: PathBuf, /// The total issuance of the currency used to create `VoteWeight`. - #[structopt(short, long)] + #[clap(short, long)] total_issuance: u128, /// The minimum account balance (i.e. existential deposit) for the currency used to create /// `VoteWeight`. - #[structopt(short, long)] + #[clap(short, long)] minimum_balance: u128, } fn main() -> Result<(), std::io::Error> { - let Opt { n_bags, output, total_issuance, minimum_balance } = Opt::from_args(); + let Opt { n_bags, output, total_issuance, minimum_balance } = Opt::parse(); generate_thresholds::(n_bags, &output, total_issuance, minimum_balance) } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 2e214ec2307b7..812310ff17d26 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -13,10 +13,11 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +clap = { version = "3.0", features = ["derive"] } log = "0.4.8" parity-scale-codec = { version = "2.3.1" } serde = "1.0.132" -structopt = "0.3.25" +zstd = "0.9.0" sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../../client/service" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } @@ -31,6 +32,4 @@ sp-externalities = { version = "0.10.0", path = "../../../../primitives/external sp-version = { version = "4.0.0-dev", path = "../../../../primitives/version" } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } -jsonrpsee = { version = "0.4.1", default-features = false, features = ["ws-client"]} - -zstd = "0.9.0" +jsonrpsee = { version = "0.4.1", default-features = false, features = ["ws-client"] } diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index 68c33b17b99de..b1a56f7e8f8eb 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -26,25 +26,25 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use std::{fmt::Debug, str::FromStr}; /// Configurations of the [`Command::ExecuteBlock`]. -#[derive(Debug, Clone, structopt::StructOpt)] +#[derive(Debug, Clone, clap::Parser)] pub struct ExecuteBlockCmd { /// Overwrite the wasm code in state or not. - #[structopt(long)] + #[clap(long)] overwrite_wasm_code: bool, /// If set, then the state root check is disabled by the virtue of calling into /// `TryRuntime_execute_block_no_check` instead of /// `Core_execute_block`. - #[structopt(long)] + #[clap(long)] no_check: bool, /// The block hash at which to fetch the block. /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::at` is. Only use this (with care) when combined with a snapshot. - #[structopt( + #[clap( long, - multiple = false, + multiple_values = false, parse(try_from_str = crate::parse::hash) )] block_at: Option, @@ -53,9 +53,9 @@ pub struct ExecuteBlockCmd { /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::uri` is. Only use this (with care) when combined with a snapshot. - #[structopt( + #[clap( long, - multiple = false, + multiple_values = false, parse(try_from_str = crate::parse::url) )] block_ws_uri: Option, @@ -65,7 +65,7 @@ pub struct ExecuteBlockCmd { /// For this command only, if the `live` is used, then state of the parent block is fetched. /// /// If `block_at` is provided, then the [`State::Live::at`] is being ignored. - #[structopt(subcommand)] + #[clap(subcommand)] state: State, } diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index 445756f9eed99..82bc04880106e 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -35,14 +35,10 @@ const SUB: &'static str = "chain_subscribeFinalizedHeads"; const UN_SUB: &'static str = "chain_unsubscribeFinalizedHeads"; /// Configurations of the [`Command::FollowChain`]. -#[derive(Debug, Clone, structopt::StructOpt)] +#[derive(Debug, Clone, clap::Parser)] pub struct FollowChainCmd { /// The url to connect to. - #[structopt( - short, - long, - parse(try_from_str = parse::url), - )] + #[clap(short, long, parse(try_from_str = parse::url))] uri: String, } diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index 47af85560398e..72136e9236de5 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -28,19 +28,19 @@ use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; use std::{fmt::Debug, str::FromStr}; /// Configurations of the [`Command::OffchainWorker`]. -#[derive(Debug, Clone, structopt::StructOpt)] +#[derive(Debug, Clone, clap::Parser)] pub struct OffchainWorkerCmd { /// Overwrite the wasm code in state or not. - #[structopt(long)] + #[clap(long)] overwrite_wasm_code: bool, /// The block hash at which to fetch the header. /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::at` is. Only use this (with care) when combined with a snapshot. - #[structopt( + #[clap( long, - multiple = false, + multiple_values = false, parse(try_from_str = parse::hash) )] header_at: Option, @@ -49,15 +49,15 @@ pub struct OffchainWorkerCmd { /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::uri` is. Only use this (with care) when combined with a snapshot. - #[structopt( + #[clap( long, - multiple = false, + multiple_values = false, parse(try_from_str = parse::url) )] header_ws_uri: Option, /// The state type to use. - #[structopt(subcommand)] + #[clap(subcommand)] pub state: State, } diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 30e638217448f..616498da02497 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -28,10 +28,10 @@ use crate::{ }; /// Configurations of the [`Command::OnRuntimeUpgrade`]. -#[derive(Debug, Clone, structopt::StructOpt)] +#[derive(Debug, Clone, clap::Parser)] pub struct OnRuntimeUpgradeCmd { /// The state type to use. - #[structopt(subcommand)] + #[clap(subcommand)] pub state: State, } diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 32c814b0443d0..9a016b2e53696 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -293,7 +293,7 @@ pub(crate) mod parse; pub(crate) const LOG_TARGET: &'static str = "try-runtime::cli"; /// Possible commands of `try-runtime`. -#[derive(Debug, Clone, structopt::StructOpt)] +#[derive(Debug, Clone, clap::Subcommand)] pub enum Command { /// Execute the migrations of the "local runtime". /// @@ -373,70 +373,64 @@ pub enum Command { } /// Shared parameters of the `try-runtime` commands -#[derive(Debug, Clone, structopt::StructOpt)] +#[derive(Debug, Clone, clap::Parser)] pub struct SharedParams { /// Shared parameters of substrate cli. #[allow(missing_docs)] - #[structopt(flatten)] + #[clap(flatten)] pub shared_params: sc_cli::SharedParams, /// The execution strategy that should be used. - #[structopt( - long = "execution", - value_name = "STRATEGY", - possible_values = &ExecutionStrategy::variants(), - case_insensitive = true, - default_value = "Wasm", - )] + #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true, default_value = "Wasm")] pub execution: ExecutionStrategy, /// Type of wasm execution used. - #[structopt( + #[clap( long = "wasm-execution", value_name = "METHOD", - possible_values = &WasmExecutionMethod::variants(), - case_insensitive = true, + possible_values = WasmExecutionMethod::variants(), + ignore_case = true, default_value = "Compiled" )] pub wasm_method: WasmExecutionMethod, /// The number of 64KB pages to allocate for Wasm execution. Defaults to /// [`sc_service::Configuration.default_heap_pages`]. - #[structopt(long)] + #[clap(long)] pub heap_pages: Option, /// When enabled, the spec name check will not panic, and instead only show a warning. - #[structopt(long)] + #[clap(long)] pub no_spec_name_check: bool, } /// Our `try-runtime` command. /// /// See [`Command`] for more info. -#[derive(Debug, Clone, structopt::StructOpt)] +#[derive(Debug, Clone, clap::Parser)] pub struct TryRuntimeCmd { - #[structopt(flatten)] + #[clap(flatten)] pub shared: SharedParams, - #[structopt(subcommand)] + #[clap(subcommand)] pub command: Command, } /// The source of runtime *state* to use. -#[derive(Debug, Clone, structopt::StructOpt)] +#[derive(Debug, Clone, clap::Subcommand)] pub enum State { /// Use a state snapshot as the source of runtime state. /// /// This can be crated by passing a value to [`State::Live::snapshot_path`]. Snap { - #[structopt(short, long)] + #[clap(short, long)] snapshot_path: PathBuf, }, /// Use a live chain as the source of runtime state. Live { /// The url to connect to. - #[structopt( + #[clap( short, long, parse(try_from_str = parse::url), @@ -447,20 +441,20 @@ pub enum State { /// /// If non provided, then the latest finalized head is used. This is particularly useful /// for [`Command::OnRuntimeUpgrade`]. - #[structopt( + #[clap( short, long, - multiple = false, + multiple_values = false, parse(try_from_str = parse::hash), )] at: Option, /// An optional state snapshot file to WRITE to. Not written if set to `None`. - #[structopt(short, long)] + #[clap(short, long)] snapshot_path: Option, /// The pallets to scrape. If empty, entire chain state will be scraped. - #[structopt(short, long, require_delimiter = true)] + #[clap(short, long, require_delimiter = true)] pallets: Option>, /// Fetch the child-keys as well. @@ -468,7 +462,7 @@ pub enum State { /// Default is `false`, if specific `pallets` are specified, true otherwise. In other /// words, if you scrape the whole state the child tree data is included out of the box. /// Otherwise, it must be enabled explicitly using this flag. - #[structopt(long, require_delimiter = true)] + #[clap(long, require_delimiter = true)] child_tree: bool, }, } From 28819000207c9bcdf37e31d7d167cd1d420faa7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 24 Jan 2022 21:14:31 +0100 Subject: [PATCH 0457/1472] Pre-Charge max size when contracts access storage (#10691) * Fix seal_get_storage * Fix seal_take_storage * Add more benchmarks * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Fix seal_set_storage * Fix seal_contains_storage and seal_clear_storage * Fix benchmarks * cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Get rid of mem::size_of in benchmarks * Fix up code loading * Apply suggestions from code review Co-authored-by: Hernando Castano * Fix test to call same function twice * Replaced u32::MAX by SENTINEL const * Fix seal_contains_storage benchmark * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot Co-authored-by: Hernando Castano --- frame/contracts/src/benchmarking/mod.rs | 270 ++++- frame/contracts/src/chain_extension.rs | 2 +- frame/contracts/src/exec.rs | 22 +- frame/contracts/src/lib.rs | 10 +- frame/contracts/src/schedule.rs | 18 +- frame/contracts/src/storage.rs | 38 +- frame/contracts/src/tests.rs | 2 +- frame/contracts/src/wasm/code_cache.rs | 35 +- frame/contracts/src/wasm/mod.rs | 25 +- frame/contracts/src/wasm/runtime.rs | 142 ++- frame/contracts/src/weights.rs | 1331 ++++++++++++----------- 11 files changed, 1055 insertions(+), 840 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 6d4ae959f31e8..3537af3d0cf78 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -35,7 +35,7 @@ use crate::{ storage::Storage, Pallet as Contracts, *, }; -use codec::Encode; +use codec::{Encode, MaxEncodedLen}; use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_support::weights::Weight; use frame_system::RawOrigin; @@ -778,9 +778,10 @@ benchmarks! { seal_set_storage { let r in 0 .. API_BENCHMARK_BATCHES; let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) - .flat_map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) + .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) .collect::>(); - let key_len = sp_std::mem::size_of::<::Output>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let key_bytes = keys.iter().flatten().cloned().collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -792,7 +793,7 @@ benchmarks! { data_segments: vec![ DataSegment { offset: 0, - value: keys, + value: key_bytes, }, ], call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ @@ -805,13 +806,28 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; + let info = instance.info()?; + for key in keys { + Storage::::write( + &info.trie_id, + key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + Some(vec![]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; + } let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - seal_set_storage_per_kb { + #[skip_meta] + seal_set_storage_per_new_kb { let n in 0 .. T::Schedule::get().limits.payload_len / 1024; - let key = T::Hashing::hash_of(&1u32).as_ref().to_vec(); - let key_len = key.len(); + let keys = (0 .. API_BENCHMARK_BATCH_SIZE) + .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) + .collect::>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let key_bytes = keys.iter().flatten().cloned().collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -823,19 +839,76 @@ benchmarks! { data_segments: vec![ DataSegment { offset: 0, - value: key, + value: key_bytes, }, ], - call_body: Some(body::repeated(API_BENCHMARK_BATCH_SIZE, &[ - Instruction::I32Const(0), // key_ptr - Instruction::I32Const(0), // value_ptr - Instruction::I32Const((n * 1024) as i32), // value_len - Instruction::Call(0), - Instruction::Drop, + call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, key_len as u32), // key_ptr + Regular(Instruction::I32Const(0)), // value_ptr + Regular(Instruction::I32Const((n * 1024) as i32)), // value_len + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let info = instance.info()?; + for key in keys { + Storage::::write( + &info.trie_id, + key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + Some(vec![]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; + } + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + + #[skip_meta] + seal_set_storage_per_old_kb { + let n in 0 .. T::Schedule::get().limits.payload_len / 1024; + let keys = (0 .. API_BENCHMARK_BATCH_SIZE) + .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) + .collect::>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let key_bytes = keys.iter().flatten().cloned().collect::>(); + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_set_storage", + params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: key_bytes, + }, + ], + call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, key_len as u32), // key_ptr + Regular(Instruction::I32Const(0)), // value_ptr + Regular(Instruction::I32Const(0)), // value_len + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; + let info = instance.info()?; + for key in keys { + Storage::::write( + &info.trie_id, + key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + Some(vec![42u8; (n * 1024) as usize]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; + } let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -849,7 +922,7 @@ benchmarks! { .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); - let key_len = sp_std::mem::size_of::<::Output>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -877,7 +950,7 @@ benchmarks! { Storage::::write( &info.trie_id, key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![42; T::Schedule::get().limits.payload_len as usize]), + Some(vec![]), None, false, ) @@ -887,6 +960,50 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[skip_meta] + seal_clear_storage_per_kb { + let n in 0 .. T::Schedule::get().limits.payload_len / 1024; + let keys = (0 .. API_BENCHMARK_BATCH_SIZE) + .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) + .collect::>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let key_bytes = keys.iter().flatten().cloned().collect::>(); + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_clear_storage", + params: vec![ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: key_bytes, + }, + ], + call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, key_len as u32), // key_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let info = instance.info()?; + for key in keys { + Storage::::write( + &info.trie_id, + key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + Some(vec![42u8; (n * 1024) as usize]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; + } + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + // We make sure that all storage accesses are to unique keys. #[skip_meta] seal_get_storage { @@ -894,7 +1011,7 @@ benchmarks! { let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) .collect::>(); - let key_len = sp_std::mem::size_of::<::Output>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { @@ -940,6 +1057,58 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[skip_meta] + seal_get_storage_per_kb { + let n in 0 .. T::Schedule::get().limits.payload_len / 1024; + let keys = (0 .. API_BENCHMARK_BATCH_SIZE) + .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) + .collect::>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let key_bytes = keys.iter().flatten().cloned().collect::>(); + let key_bytes_len = key_bytes.len(); + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "seal0", + name: "seal_get_storage", + params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: key_bytes, + }, + DataSegment { + offset: key_bytes_len as u32, + value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), + }, + ], + call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, key_len as u32), // key_ptr + Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr + Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let info = instance.info()?; + for key in keys { + Storage::::write( + &info.trie_id, + key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + Some(vec![42u8; (n * 1024) as usize]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; + } + >::insert(&instance.account_id, info.clone()); + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + // We make sure that all storage accesses are to unique keys. #[skip_meta] seal_contains_storage { @@ -947,7 +1116,7 @@ benchmarks! { let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) .collect::>(); - let key_len = sp_std::mem::size_of::<::Output>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { @@ -977,7 +1146,7 @@ benchmarks! { Storage::::write( &info.trie_id, key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![42; T::Schedule::get().limits.payload_len as usize]), + Some(vec![]), None, false, ) @@ -987,48 +1156,47 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - seal_get_storage_per_kb { + #[skip_meta] + seal_contains_storage_per_kb { let n in 0 .. T::Schedule::get().limits.payload_len / 1024; - let key = T::Hashing::hash_of(&1u32).as_ref().to_vec(); - let key_len = key.len(); + let keys = (0 .. API_BENCHMARK_BATCH_SIZE) + .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) + .collect::>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let key_bytes = keys.iter().flatten().cloned().collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", - name: "seal_get_storage", - params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + module: "__unstable__", + name: "seal_contains_storage", + params: vec![ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ DataSegment { offset: 0, - value: key.clone(), - }, - DataSegment { - offset: key_len as u32, - value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), + value: key_bytes, }, ], - call_body: Some(body::repeated(API_BENCHMARK_BATCH_SIZE, &[ - // call at key_ptr - Instruction::I32Const(0), // key_ptr - Instruction::I32Const((key_len + 4) as i32), // out_ptr - Instruction::I32Const(key_len as i32), // out_len_ptr - Instruction::Call(0), - Instruction::Drop, + call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, key_len as u32), // key_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; - Storage::::write( - &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![42u8; (n * 1024) as usize]), - None, - false, - ) - .map_err(|_| "Failed to write to storage during setup.")?; + for key in keys { + Storage::::write( + &info.trie_id, + key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + Some(vec![42u8; (n * 1024) as usize]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; + } >::insert(&instance.account_id, info.clone()); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1039,7 +1207,7 @@ benchmarks! { let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) .collect::>(); - let key_len = sp_std::mem::size_of::<::Output>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { @@ -1091,7 +1259,7 @@ benchmarks! { let keys = (0 .. API_BENCHMARK_BATCH_SIZE) .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) .collect::>(); - let key_len = sp_std::mem::size_of::<::Output>(); + let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { @@ -1238,7 +1406,7 @@ benchmarks! { Regular(Instruction::I32Const(value_len as i32)), // value_len Regular(Instruction::I32Const(0)), // input_data_ptr Regular(Instruction::I32Const(0)), // input_data_len - Regular(Instruction::I32Const(u32::max_value() as i32)), // output_ptr + Regular(Instruction::I32Const(SENTINEL as i32)), // output_ptr Regular(Instruction::I32Const(0)), // output_len_ptr Regular(Instruction::Call(0)), Regular(Instruction::Drop), @@ -1361,7 +1529,7 @@ benchmarks! { assert!(value > 0u32.into()); let value_bytes = value.encode(); let value_len = value_bytes.len(); - let addr_len = sp_std::mem::size_of::(); + let addr_len = T::AccountId::max_encoded_len(); // offsets where to place static data in contract memory let value_offset = 0; @@ -1415,7 +1583,7 @@ benchmarks! { Regular(Instruction::I32Const(0)), // input_data_len Regular(Instruction::I32Const(addr_offset as i32)), // address_ptr Regular(Instruction::I32Const(addr_len_offset as i32)), // address_len_ptr - Regular(Instruction::I32Const(u32::max_value() as i32)), // output_ptr + Regular(Instruction::I32Const(SENTINEL as i32)), // output_ptr Regular(Instruction::I32Const(0)), // output_len_ptr Regular(Instruction::I32Const(0)), // salt_ptr Regular(Instruction::I32Const(0)), // salt_ptr_len @@ -1485,7 +1653,7 @@ benchmarks! { assert!(value > 0u32.into()); let value_bytes = value.encode(); let value_len = value_bytes.len(); - let addr_len = sp_std::mem::size_of::(); + let addr_len = T::AccountId::max_encoded_len(); // offsets where to place static data in contract memory let input_offset = 0; diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index b0e08df3adbb0..ed447719933be 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -329,7 +329,7 @@ where /// /// If the contract supplied buffer is smaller than the passed `buffer` an `Err` is returned. /// If `allow_skip` is set to true the contract is allowed to skip the copying of the buffer - /// by supplying the guard value of `u32::MAX` as `out_ptr`. The + /// by supplying the guard value of `pallet-contracts::SENTINEL` as `out_ptr`. The /// `weight_per_byte` is only charged when the write actually happens and is not skipped or /// failed due to a too small output buffer. pub fn write( diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 679a6adde9221..e4988eea51d0b 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -24,7 +24,7 @@ use crate::{ use frame_support::{ dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable}, storage::{with_transaction, TransactionOutcome}, - traits::{Contains, Currency, ExistenceRequirement, Get, OriginTrait, Randomness, Time}, + traits::{Contains, Currency, ExistenceRequirement, OriginTrait, Randomness, Time}, weights::Weight, }; use frame_system::RawOrigin; @@ -140,11 +140,11 @@ pub trait Ext: sealing::Sealed { /// was deleted. fn get_storage(&mut self, key: &StorageKey) -> Option>; - /// Returns true iff some storage entry exists under the supplied `key` + /// Returns `Some(len)` (in bytes) if a storage item exists at `key`. /// - /// Returns `false` if the `key` wasn't previously set by `set_storage` or + /// Returns `None` if the `key` wasn't previously set by `set_storage` or /// was deleted. - fn contains_storage(&mut self, key: &StorageKey) -> bool; + fn get_storage_size(&mut self, key: &StorageKey) -> Option; /// Sets the storage entry by the given key to the specified value. If `value` is `None` then /// the storage entry is deleted. @@ -996,8 +996,8 @@ where Storage::::read(&self.top_frame_mut().contract_info().trie_id, key) } - fn contains_storage(&mut self, key: &StorageKey) -> bool { - Storage::::contains(&self.top_frame_mut().contract_info().trie_id, key) + fn get_storage_size(&mut self, key: &StorageKey) -> Option { + Storage::::size(&self.top_frame_mut().contract_info().trie_id, key) } fn set_storage( @@ -1056,7 +1056,7 @@ where } fn max_value_size(&self) -> u32 { - T::Schedule::get().limits.payload_len + self.schedule.limits.payload_len } fn get_weight_price(&self, weight: Weight) -> BalanceOf { @@ -2432,16 +2432,16 @@ mod tests { } #[test] - fn contains_storage_works() { + fn get_storage_size_works() { let code_hash = MockLoader::insert(Call, |ctx, _| { assert_eq!( ctx.ext.set_storage([1; 32], Some(vec![1, 2, 3]), false), Ok(WriteOutcome::New) ); assert_eq!(ctx.ext.set_storage([2; 32], Some(vec![]), false), Ok(WriteOutcome::New)); - assert_eq!(ctx.ext.contains_storage(&[1; 32]), true); - assert_eq!(ctx.ext.contains_storage(&[1; 32]), true); - assert_eq!(ctx.ext.contains_storage(&[3; 32]), false); + assert_eq!(ctx.ext.get_storage_size(&[1; 32]), Some(3)); + assert_eq!(ctx.ext.get_storage_size(&[2; 32]), Some(0)); + assert_eq!(ctx.ext.get_storage_size(&[3; 32]), None); exec_success() }); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index e57b88c5d0389..9f9cc09f6430a 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -136,6 +136,14 @@ type BalanceOf = /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(6); +/// Used as a sentinel value when reading and writing contract memory. +/// +/// It is usually used to signal `None` to a contract when only a primitive is allowed +/// and we don't want to go through encoding a full Rust type. Using `u32::Max` is a safe +/// sentinel because contracts are never allowed to use such a large amount of resources +/// that this value makes sense for a memory location or length. +const SENTINEL: u32 = u32::MAX; + /// Provides the contract address generation method. /// /// See [`DefaultAddressGenerator`] for the default implementation. @@ -831,7 +839,7 @@ where module: &mut PrefabWasmModule, schedule: &Schedule, ) -> frame_support::dispatch::DispatchResult { - self::wasm::reinstrument(module, schedule) + self::wasm::reinstrument(module, schedule).map(|_| ()) } /// Internal function that does the actual call. diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 459bd950ce462..f8ca182aea586 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -316,15 +316,24 @@ pub struct HostFnWeights { /// Weight of calling `seal_set_storage`. pub set_storage: Weight, - /// Weight per byte of an item stored with `seal_set_storage`. - pub set_storage_per_byte: Weight, + /// Weight per written byten of an item stored with `seal_set_storage`. + pub set_storage_per_new_byte: Weight, + + /// Weight per overwritten byte of an item stored with `seal_set_storage`. + pub set_storage_per_old_byte: Weight, /// Weight of calling `seal_clear_storage`. pub clear_storage: Weight, + /// Weight of calling `seal_clear_storage` per byte of the stored item. + pub clear_storage_per_byte: Weight, + /// Weight of calling `seal_contains_storage`. pub contains_storage: Weight, + /// Weight of calling `seal_contains_storage` per byte of the stored item. + pub contains_storage_per_byte: Weight, + /// Weight of calling `seal_get_storage`. pub get_storage: Weight, @@ -586,9 +595,12 @@ impl Default for HostFnWeights { ), debug_message: cost_batched!(seal_debug_message), set_storage: cost_batched!(seal_set_storage), - set_storage_per_byte: cost_byte_batched!(seal_set_storage_per_kb), + set_storage_per_new_byte: cost_byte_batched!(seal_set_storage_per_new_kb), + set_storage_per_old_byte: cost_byte_batched!(seal_set_storage_per_old_kb), clear_storage: cost_batched!(seal_clear_storage), + clear_storage_per_byte: cost_byte_batched!(seal_clear_storage_per_kb), contains_storage: cost_batched!(seal_contains_storage), + contains_storage_per_byte: cost_byte_batched!(seal_contains_storage_per_kb), get_storage: cost_batched!(seal_get_storage), get_storage_per_byte: cost_byte_batched!(seal_get_storage_per_kb), take_storage: cost_batched!(seal_take_storage), diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index b84cd1d2538e1..de65059b5b175 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -22,7 +22,7 @@ pub mod meter; use crate::{ exec::{AccountIdOf, StorageKey}, weights::WeightInfo, - BalanceOf, CodeHash, Config, ContractInfoOf, DeletionQueue, Error, TrieId, + BalanceOf, CodeHash, Config, ContractInfoOf, DeletionQueue, Error, TrieId, SENTINEL, }; use codec::{Decode, Encode}; use frame_support::{ @@ -87,6 +87,33 @@ pub enum WriteOutcome { Taken(Vec), } +impl WriteOutcome { + /// Extracts the size of the overwritten value or `0` if there + /// was no value in storage. + pub fn old_len(&self) -> u32 { + match self { + Self::New => 0, + Self::Overwritten(len) => *len, + Self::Taken(value) => value.len() as u32, + } + } + + /// Extracts the size of the overwritten value or `SENTINEL` if there + /// was no value in storage. + /// + /// # Note + /// + /// We cannot use `0` as sentinel value because there could be a zero sized + /// storage entry which is different from a non existing one. + pub fn old_len_with_sentinel(&self) -> u32 { + match self { + Self::New => SENTINEL, + Self::Overwritten(len) => *len, + Self::Taken(value) => value.len() as u32, + } + } +} + pub struct Storage(PhantomData); impl Storage @@ -102,9 +129,12 @@ where child::get_raw(&child_trie_info(trie_id), &blake2_256(key)) } - /// Returns `true` iff the `key` exists in storage. - pub fn contains(trie_id: &TrieId, key: &StorageKey) -> bool { - child::exists(&child_trie_info(trie_id), &blake2_256(key)) + /// Returns `Some(len)` (in bytes) if a storage item exists at `key`. + /// + /// Returns `None` if the `key` wasn't previously set by `set_storage` or + /// was deleted. + pub fn size(trie_id: &TrieId, key: &StorageKey) -> Option { + child::len(&child_trie_info(trie_id), &blake2_256(key)) } /// Update a storage entry into a contract's kv storage. diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index fd5c8cfd34ec9..3d39bc6d78d93 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -294,7 +294,7 @@ pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]); pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]); -pub const GAS_LIMIT: Weight = 10_000_000_000; +pub const GAS_LIMIT: Weight = 100_000_000_000; pub struct ExtBuilder { existential_deposit: u64, diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index e3fe48ac12c24..a48f9838837c9 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -38,7 +38,6 @@ use crate::{ use frame_support::{ dispatch::{DispatchError, DispatchResult}, ensure, - storage::StorageMap, traits::ReservableCurrency, }; use sp_core::crypto::UncheckedFrom; @@ -149,52 +148,38 @@ pub fn load( where T::AccountId: UncheckedFrom + AsRef<[u8]>, { - gas_meter.charge(CodeToken::Load(estimate_code_size::, _>(&code_hash)?))?; + let charged = gas_meter.charge(CodeToken::Load(schedule.limits.code_len))?; let mut prefab_module = >::get(code_hash).ok_or_else(|| Error::::CodeNotFound)?; + gas_meter.adjust_gas(charged, CodeToken::Load(prefab_module.code.len() as u32)); prefab_module.code_hash = code_hash; if prefab_module.instruction_weights_version < schedule.instruction_weights.version { // The instruction weights have changed. // We need to re-instrument the code with the new instruction weights. - gas_meter.charge(CodeToken::Reinstrument(estimate_code_size::, _>( - &code_hash, - )?))?; - reinstrument(&mut prefab_module, schedule)?; + let charged = gas_meter.charge(CodeToken::Reinstrument(schedule.limits.code_len))?; + let code_size = reinstrument(&mut prefab_module, schedule)?; + gas_meter.adjust_gas(charged, CodeToken::Reinstrument(code_size)); } Ok(prefab_module) } /// Instruments the passed prefab wasm module with the supplied schedule. +/// +/// Returns the size in bytes of the uninstrumented code. pub fn reinstrument( prefab_module: &mut PrefabWasmModule, schedule: &Schedule, -) -> Result<(), DispatchError> { +) -> Result { let original_code = >::get(&prefab_module.code_hash).ok_or_else(|| Error::::CodeNotFound)?; + let original_code_len = original_code.len(); prefab_module.code = prepare::reinstrument_contract::(original_code, schedule)?; prefab_module.instruction_weights_version = schedule.instruction_weights.version; >::insert(&prefab_module.code_hash, &*prefab_module); - Ok(()) -} - -/// Get the size of the code stored at `code_hash` without loading it. -/// -/// The returned value is slightly too large when using it for the [`PrefabWasmModule`] -/// because it has other fields in addition to the code itself. However, those are negligible -/// when compared to the code size. Additionally, charging too much weight is completely safe. -fn estimate_code_size(code_hash: &CodeHash) -> Result -where - T: Config, - M: StorageMap, V>, - V: codec::FullCodec, -{ - let key = M::hashed_key_for(code_hash); - let mut data = [0u8; 0]; - let len = sp_io::storage::read(&key, &mut data, 0).ok_or_else(|| Error::::CodeNotFound)?; - Ok(len) + Ok(original_code_len as u32) } /// Costs for operations that are related to code handling. diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index ee778982cdbd4..41e940bcd9b6c 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -385,8 +385,8 @@ mod tests { fn get_storage(&mut self, key: &StorageKey) -> Option> { self.storage.get(key).cloned() } - fn contains_storage(&mut self, key: &StorageKey) -> bool { - self.storage.contains_key(key) + fn get_storage_size(&mut self, key: &StorageKey) -> Option { + self.storage.get(key).map(|val| val.len() as u32) } fn set_storage( &mut self, @@ -2023,7 +2023,7 @@ mod tests { // value did not exist before -> sentinel returned let input = ([1u8; 32], [42u8, 48]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), u32::MAX); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); assert_eq!(ext.storage.get(&[1u8; 32]).unwrap(), &[42u8, 48]); // value do exist -> length of old value returned @@ -2083,7 +2083,7 @@ mod tests { // value does not exist -> sentinel returned let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), u32::MAX); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); assert_eq!(ext.storage.get(&[3u8; 32]), None); // value did exist -> length returned @@ -2228,25 +2228,16 @@ mod tests { ext.storage.insert([1u8; 32], vec![42u8]); ext.storage.insert([2u8; 32], vec![]); - // value does not exist -> error returned + // value does not exist -> sentinel value returned let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); - assert_eq!( - u32::from_le_bytes(result.data.0.try_into().unwrap()), - ReturnCode::KeyNotFound as u32 - ); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); // value did exist -> success let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); - assert_eq!( - u32::from_le_bytes(result.data.0.try_into().unwrap()), - ReturnCode::Success as u32 - ); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1,); // value did exist -> success (zero sized type) let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); - assert_eq!( - u32::from_le_bytes(result.data.0.try_into().unwrap()), - ReturnCode::Success as u32 - ); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0,); } } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 98d9d9a40cda9..13aa934306978 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -21,9 +21,8 @@ use crate::{ exec::{ExecError, ExecResult, Ext, StorageKey, TopicOf}, gas::{ChargedAmount, Token}, schedule::HostFnWeights, - storage::WriteOutcome, wasm::env_def::ConvertibleToWasm, - BalanceOf, CodeHash, Config, Error, + BalanceOf, CodeHash, Config, Error, SENTINEL, }; use bitflags::bitflags; use codec::{Decode, DecodeAll, Encode, MaxEncodedLen}; @@ -169,23 +168,18 @@ pub enum RuntimeCosts { DepositEvent { num_topic: u32, len: u32 }, /// Weight of calling `seal_debug_message`. DebugMessage, - /// Weight of calling `seal_set_storage` for the given storage item size. - SetStorage(u32), - /// Weight of calling `seal_clear_storage`. - ClearStorage, - /// Weight of calling `seal_contains_storage`. + /// Weight of calling `seal_set_storage` for the given storage item sizes. + SetStorage { old_bytes: u32, new_bytes: u32 }, + /// Weight of calling `seal_clear_storage` per cleared byte. + ClearStorage(u32), + /// Weight of calling `seal_contains_storage` per byte of the checked item. #[cfg(feature = "unstable-interface")] - ContainsStorage, - /// Weight of calling `seal_get_storage` without output weight. - GetStorageBase, - /// Weight of an item received via `seal_get_storage` for the given size. - GetStorageCopyOut(u32), - /// Weight of calling `seal_take_storage` without output weight. + ContainsStorage(u32), + /// Weight of calling `seal_get_storage` with the specified size in storage. + GetStorage(u32), + /// Weight of calling `seal_take_storage` for the given size. #[cfg(feature = "unstable-interface")] - TakeStorageBase, - /// Weight of an item received via `seal_take_storage` for the given size. - #[cfg(feature = "unstable-interface")] - TakeStorageCopyOut(u32), + TakeStorage(u32), /// Weight of calling `seal_transfer`. Transfer, /// Weight of calling `seal_call` for the given input size. @@ -249,17 +243,23 @@ impl RuntimeCosts { .saturating_add(s.deposit_event_per_topic.saturating_mul(num_topic.into())) .saturating_add(s.deposit_event_per_byte.saturating_mul(len.into())), DebugMessage => s.debug_message, - SetStorage(len) => - s.set_storage.saturating_add(s.set_storage_per_byte.saturating_mul(len.into())), - ClearStorage => s.clear_storage, - #[cfg(feature = "unstable-interface")] - ContainsStorage => s.contains_storage, - GetStorageBase => s.get_storage, - GetStorageCopyOut(len) => s.get_storage_per_byte.saturating_mul(len.into()), + SetStorage { new_bytes, old_bytes } => s + .set_storage + .saturating_add(s.set_storage_per_new_byte.saturating_mul(new_bytes.into())) + .saturating_add(s.set_storage_per_old_byte.saturating_mul(old_bytes.into())), + ClearStorage(len) => s + .clear_storage + .saturating_add(s.clear_storage_per_byte.saturating_mul(len.into())), #[cfg(feature = "unstable-interface")] - TakeStorageBase => s.take_storage, + ContainsStorage(len) => s + .contains_storage + .saturating_add(s.contains_storage_per_byte.saturating_mul(len.into())), + GetStorage(len) => + s.get_storage.saturating_add(s.get_storage_per_byte.saturating_mul(len.into())), #[cfg(feature = "unstable-interface")] - TakeStorageCopyOut(len) => s.take_storage_per_byte.saturating_mul(len.into()), + TakeStorage(len) => s + .take_storage + .saturating_add(s.take_storage_per_byte.saturating_mul(len.into())), Transfer => s.transfer, CallBase(len) => s.call.saturating_add(s.call_per_input_byte.saturating_mul(len.into())), @@ -534,7 +534,7 @@ where /// length of the buffer located at `out_ptr`. If that buffer is large enough the actual /// `buf.len()` is written to this location. /// - /// If `out_ptr` is set to the sentinel value of `u32::MAX` and `allow_skip` is true the + /// If `out_ptr` is set to the sentinel value of `SENTINEL` and `allow_skip` is true the /// operation is skipped and `Ok` is returned. This is supposed to help callers to make copying /// output optional. For example to skip copying back the output buffer of an `seal_call` /// when the caller is not interested in the result. @@ -553,7 +553,7 @@ where allow_skip: bool, create_token: impl FnOnce(u32) -> Option, ) -> Result<(), DispatchError> { - if allow_skip && out_ptr == u32::MAX { + if allow_skip && out_ptr == SENTINEL { return Ok(()) } @@ -648,48 +648,36 @@ where } } - /// Extracts the size of the overwritten value or `u32::MAX` if there - /// was no value in storage. - /// - /// # Note - /// - /// We cannot use `0` as sentinel value because there could be a zero sized - /// storage entry which is different from a non existing one. - fn overwritten_len(outcome: WriteOutcome) -> u32 { - match outcome { - WriteOutcome::New => u32::MAX, - WriteOutcome::Overwritten(len) => len, - WriteOutcome::Taken(value) => value.len() as u32, - } - } - fn set_storage( &mut self, key_ptr: u32, value_ptr: u32, value_len: u32, ) -> Result { - self.charge_gas(RuntimeCosts::SetStorage(value_len))?; - if value_len > self.ext.max_value_size() { + let max_size = self.ext.max_value_size(); + let charged = self + .charge_gas(RuntimeCosts::SetStorage { new_bytes: value_len, old_bytes: max_size })?; + if value_len > max_size { Err(Error::::ValueTooLarge)?; } let mut key: StorageKey = [0; 32]; self.read_sandbox_memory_into_buf(key_ptr, &mut key)?; let value = Some(self.read_sandbox_memory(value_ptr, value_len)?); - self.ext - .set_storage(key, value, false) - .map(Self::overwritten_len) - .map_err(Into::into) + let write_outcome = self.ext.set_storage(key, value, false)?; + self.adjust_gas( + charged, + RuntimeCosts::SetStorage { new_bytes: value_len, old_bytes: write_outcome.old_len() }, + ); + Ok(write_outcome.old_len_with_sentinel()) } fn clear_storage(&mut self, key_ptr: u32) -> Result { - self.charge_gas(RuntimeCosts::ClearStorage)?; + let charged = self.charge_gas(RuntimeCosts::ClearStorage(self.ext.max_value_size()))?; let mut key: StorageKey = [0; 32]; self.read_sandbox_memory_into_buf(key_ptr, &mut key)?; - self.ext - .set_storage(key, None, false) - .map(Self::overwritten_len) - .map_err(Into::into) + let outcome = self.ext.set_storage(key, None, false)?; + self.adjust_gas(charged, RuntimeCosts::ClearStorage(outcome.old_len())); + Ok(outcome.old_len_with_sentinel()) } fn call( @@ -827,7 +815,7 @@ define_env!(Env, , // # Return Value // // Returns the size of the pre-existing value at the specified key if any. Otherwise - // `u32::MAX` is returned as a sentinel value. + // `SENTINEL` is returned as a sentinel value. [__unstable__] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) -> u32 => { ctx.set_storage(key_ptr, value_ptr, value_len) }, @@ -849,7 +837,7 @@ define_env!(Env, , // # Return Value // // Returns the size of the pre-existing value at the specified key if any. Otherwise - // `u32::MAX` is returned as a sentinel value. + // `SENTINEL` is returned as a sentinel value. [__unstable__] seal_clear_storage(ctx, key_ptr: u32) -> u32 => { ctx.clear_storage(key_ptr).map_err(Into::into) }, @@ -867,39 +855,39 @@ define_env!(Env, , // // `ReturnCode::KeyNotFound` [seal0] seal_get_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { - ctx.charge_gas(RuntimeCosts::GetStorageBase)?; + let charged = ctx.charge_gas(RuntimeCosts::GetStorage(ctx.ext.max_value_size()))?; let mut key: StorageKey = [0; 32]; ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; if let Some(value) = ctx.ext.get_storage(&key) { - ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, |len| { - Some(RuntimeCosts::GetStorageCopyOut(len)) - })?; + ctx.adjust_gas(charged, RuntimeCosts::GetStorage(value.len() as u32)); + ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, already_charged)?; Ok(ReturnCode::Success) } else { + ctx.adjust_gas(charged, RuntimeCosts::GetStorage(0)); Ok(ReturnCode::KeyNotFound) } }, // Checks whether there is a value stored under the given key. // - // Returns `ReturnCode::Success` if there is a key in storage. Otherwise an error - // is returned. - // // # Parameters // // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. // - // # Errors + // # Return Value // - // `ReturnCode::KeyNotFound` - [__unstable__] seal_contains_storage(ctx, key_ptr: u32) -> ReturnCode => { - ctx.charge_gas(RuntimeCosts::ContainsStorage)?; + // Returns the size of the pre-existing value at the specified key if any. Otherwise + // `SENTINEL` is returned as a sentinel value. + [__unstable__] seal_contains_storage(ctx, key_ptr: u32) -> u32 => { + let charged = ctx.charge_gas(RuntimeCosts::ContainsStorage(ctx.ext.max_value_size()))?; let mut key: StorageKey = [0; 32]; ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; - if ctx.ext.contains_storage(&key) { - Ok(ReturnCode::Success) + if let Some(len) = ctx.ext.get_storage_size(&key) { + ctx.adjust_gas(charged, RuntimeCosts::ContainsStorage(len)); + Ok(len) } else { - Ok(ReturnCode::KeyNotFound) + ctx.adjust_gas(charged, RuntimeCosts::ContainsStorage(0)); + Ok(SENTINEL) } }, @@ -916,15 +904,15 @@ define_env!(Env, , // // `ReturnCode::KeyNotFound` [__unstable__] seal_take_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { - ctx.charge_gas(RuntimeCosts::TakeStorageBase)?; + let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?; let mut key: StorageKey = [0; 32]; ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; - if let WriteOutcome::Taken(value) = ctx.ext.set_storage(key, None, true)? { - ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, |len| { - Some(RuntimeCosts::TakeStorageCopyOut(len)) - })?; + if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage(key, None, true)? { + ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(value.len() as u32)); + ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, already_charged)?; Ok(ReturnCode::Success) } else { + ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(0)); Ok(ReturnCode::KeyNotFound) } }, @@ -1006,7 +994,7 @@ define_env!(Env, , // // The callees output buffer is copied to `output_ptr` and its length to `output_len_ptr`. // The copy of the output buffer can be skipped by supplying the sentinel value - // of `u32::MAX` to `output_ptr`. + // of `SENTINEL` to `output_ptr`. // // # Parameters // @@ -1103,7 +1091,7 @@ define_env!(Env, , // by the code hash. The address of this new account is copied to `address_ptr` and its length // to `address_len_ptr`. The constructors output buffer is copied to `output_ptr` and its // length to `output_len_ptr`. The copy of the output buffer and address can be skipped by - // supplying the sentinel value of `u32::MAX` to `output_ptr` or `address_ptr`. + // supplying the sentinel value of `SENTINEL` to `output_ptr` or `address_ptr`. // // `value` must be at least the minimum balance. Otherwise the instantiation fails and the // contract is not created. diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 655cba5d3b9aa..2d74df9627db9 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-01-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/lto-fat-cg1/substrate +// target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -33,9 +33,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/contracts/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=LICENSE-APACHE2 -// --raw +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -76,11 +74,14 @@ pub trait WeightInfo { fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight; fn seal_debug_message(r: u32, ) -> Weight; fn seal_set_storage(r: u32, ) -> Weight; - fn seal_set_storage_per_kb(n: u32, ) -> Weight; + fn seal_set_storage_per_new_kb(n: u32, ) -> Weight; + fn seal_set_storage_per_old_kb(n: u32, ) -> Weight; fn seal_clear_storage(r: u32, ) -> Weight; + fn seal_clear_storage_per_kb(n: u32, ) -> Weight; fn seal_get_storage(r: u32, ) -> Weight; - fn seal_contains_storage(r: u32, ) -> Weight; fn seal_get_storage_per_kb(n: u32, ) -> Weight; + fn seal_contains_storage(r: u32, ) -> Weight; + fn seal_contains_storage_per_kb(n: u32, ) -> Weight; fn seal_take_storage(r: u32, ) -> Weight; fn seal_take_storage_per_kb(n: u32, ) -> Weight; fn seal_transfer(r: u32, ) -> Weight; @@ -155,32 +156,32 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_585_000 as Weight) + (1_636_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (7_902_000 as Weight) + (7_840_000 as Weight) // Standard Error: 0 - .saturating_add((751_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((752_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (31_473_000 as Weight) + (31_915_000 as Weight) // Standard Error: 1_000 - .saturating_add((104_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((98_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (15_462_000 as Weight) - // Standard Error: 35_000 - .saturating_add((81_710_000 as Weight).saturating_mul(c as Weight)) + (18_897_000 as Weight) + // Standard Error: 32_000 + .saturating_add((69_663_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -189,9 +190,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (169_561_000 as Weight) - // Standard Error: 56_000 - .saturating_add((60_037_000 as Weight).saturating_mul(c as Weight)) + (204_947_000 as Weight) + // Standard Error: 54_000 + .saturating_add((58_293_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -203,11 +204,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (169_885_000 as Weight) - // Standard Error: 127_000 - .saturating_add((170_680_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 8_000 - .saturating_add((1_788_000 as Weight).saturating_mul(s as Weight)) + (211_187_000 as Weight) + // Standard Error: 114_000 + .saturating_add((156_529_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 7_000 + .saturating_add((1_830_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -218,9 +219,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (150_265_000 as Weight) + (150_485_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_722_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_769_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -229,7 +230,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (114_784_000 as Weight) + (117_274_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -237,9 +238,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (48_072_000 as Weight) - // Standard Error: 36_000 - .saturating_add((83_578_000 as Weight).saturating_mul(c as Weight)) + (51_126_000 as Weight) + // Standard Error: 49_000 + .saturating_add((72_622_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -247,7 +248,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_739_000 as Weight) + (24_221_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -256,9 +257,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (174_123_000 as Weight) - // Standard Error: 127_000 - .saturating_add((56_078_000 as Weight).saturating_mul(r as Weight)) + (219_790_000 as Weight) + // Standard Error: 126_000 + .saturating_add((56_383_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -267,9 +268,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (180_168_000 as Weight) - // Standard Error: 122_000 - .saturating_add((56_154_000 as Weight).saturating_mul(r as Weight)) + (218_377_000 as Weight) + // Standard Error: 117_000 + .saturating_add((57_243_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -278,9 +279,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (179_464_000 as Weight) - // Standard Error: 96_000 - .saturating_add((55_350_000 as Weight).saturating_mul(r as Weight)) + (217_999_000 as Weight) + // Standard Error: 104_000 + .saturating_add((56_674_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -289,9 +290,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (181_031_000 as Weight) - // Standard Error: 154_000 - .saturating_add((149_508_000 as Weight).saturating_mul(r as Weight)) + (226_932_000 as Weight) + // Standard Error: 155_000 + .saturating_add((147_401_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -300,9 +301,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (178_709_000 as Weight) - // Standard Error: 107_000 - .saturating_add((56_326_000 as Weight).saturating_mul(r as Weight)) + (233_107_000 as Weight) + // Standard Error: 110_000 + .saturating_add((55_334_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -311,9 +312,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (175_715_000 as Weight) - // Standard Error: 116_000 - .saturating_add((56_755_000 as Weight).saturating_mul(r as Weight)) + (235_364_000 as Weight) + // Standard Error: 122_000 + .saturating_add((54_700_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -322,9 +323,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (178_552_000 as Weight) - // Standard Error: 121_000 - .saturating_add((55_756_000 as Weight).saturating_mul(r as Weight)) + (232_875_000 as Weight) + // Standard Error: 108_000 + .saturating_add((54_510_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -333,9 +334,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (186_172_000 as Weight) - // Standard Error: 106_000 - .saturating_add((55_311_000 as Weight).saturating_mul(r as Weight)) + (226_089_000 as Weight) + // Standard Error: 126_000 + .saturating_add((54_899_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -345,9 +346,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (183_750_000 as Weight) - // Standard Error: 140_000 - .saturating_add((131_877_000 as Weight).saturating_mul(r as Weight)) + (234_746_000 as Weight) + // Standard Error: 146_000 + .saturating_add((132_861_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -356,9 +357,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (97_350_000 as Weight) - // Standard Error: 54_000 - .saturating_add((27_606_000 as Weight).saturating_mul(r as Weight)) + (96_247_000 as Weight) + // Standard Error: 70_000 + .saturating_add((27_918_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -367,9 +368,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (179_058_000 as Weight) - // Standard Error: 106_000 - .saturating_add((53_258_000 as Weight).saturating_mul(r as Weight)) + (221_631_000 as Weight) + // Standard Error: 139_000 + .saturating_add((54_382_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -378,9 +379,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (248_562_000 as Weight) - // Standard Error: 5_000 - .saturating_add((10_515_000 as Weight).saturating_mul(n as Weight)) + (306_449_000 as Weight) + // Standard Error: 3_000 + .saturating_add((11_919_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -389,9 +390,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (161_228_000 as Weight) - // Standard Error: 90_000 - .saturating_add((14_539_000 as Weight).saturating_mul(r as Weight)) + (222_176_000 as Weight) + // Standard Error: 72_000 + .saturating_add((3_223_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -400,9 +401,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (177_866_000 as Weight) + (211_079_000 as Weight) // Standard Error: 0 - .saturating_add((188_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((237_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -413,9 +414,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (164_572_000 as Weight) - // Standard Error: 1_817_000 - .saturating_add((68_480_000 as Weight).saturating_mul(r as Weight)) + (213_994_000 as Weight) + // Standard Error: 104_000 + .saturating_add((64_453_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -427,9 +428,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (168_658_000 as Weight) - // Standard Error: 189_000 - .saturating_add((166_190_000 as Weight).saturating_mul(r as Weight)) + (228_281_000 as Weight) + // Standard Error: 150_000 + .saturating_add((166_949_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -438,9 +439,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (185_391_000 as Weight) - // Standard Error: 191_000 - .saturating_add((292_609_000 as Weight).saturating_mul(r as Weight)) + (230_348_000 as Weight) + // Standard Error: 163_000 + .saturating_add((288_679_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -450,11 +451,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (507_994_000 as Weight) - // Standard Error: 1_569_000 - .saturating_add((276_852_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 309_000 - .saturating_add((79_461_000 as Weight).saturating_mul(n as Weight)) + (601_613_000 as Weight) + // Standard Error: 1_566_000 + .saturating_add((279_038_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 308_000 + .saturating_add((84_818_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -465,79 +466,95 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (99_048_000 as Weight) - // Standard Error: 87_000 - .saturating_add((46_088_000 as Weight).saturating_mul(r as Weight)) + (113_578_000 as Weight) + // Standard Error: 67_000 + .saturating_add((44_899_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (142_559_000 as Weight) - // Standard Error: 603_000 - .saturating_add((269_723_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) + (59_019_000 as Weight) + // Standard Error: 995_000 + .saturating_add((414_759_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:2 w:2) - // Storage: Contracts ContractInfoOf (r:1 w:1) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) - fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (346_704_000 as Weight) - // Standard Error: 200_000 - .saturating_add((29_907_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + // Storage: Skipped Metadata (r:0 w:0) + fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { + (620_483_000 as Weight) + // Standard Error: 242_000 + .saturating_add((30_945_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(105 as Weight)) + .saturating_add(T::DbWeight::get().writes(103 as Weight)) + } + // Storage: Skipped Metadata (r:0 w:0) + fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { + (632_391_000 as Weight) + // Standard Error: 317_000 + .saturating_add((11_431_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(105 as Weight)) + .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 1_963_000 - .saturating_add((746_581_000 as Weight).saturating_mul(r as Weight)) + (96_628_000 as Weight) + // Standard Error: 878_000 + .saturating_add((387_212_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + fn seal_clear_storage_per_kb(n: u32, ) -> Weight { + (625_960_000 as Weight) + // Standard Error: 270_000 + .saturating_add((11_170_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(105 as Weight)) + .saturating_add(T::DbWeight::get().writes(103 as Weight)) + } + // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (69_873_000 as Weight) - // Standard Error: 722_000 - .saturating_add((338_292_000 as Weight).saturating_mul(r as Weight)) + (115_155_000 as Weight) + // Standard Error: 741_000 + .saturating_add((331_711_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + fn seal_get_storage_per_kb(n: u32, ) -> Weight { + (582_560_000 as Weight) + // Standard Error: 360_000 + .saturating_add((68_427_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(104 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 1_169_000 - .saturating_add((480_500_000 as Weight).saturating_mul(r as Weight)) + (130_096_000 as Weight) + // Standard Error: 555_000 + .saturating_add((294_514_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:0) - // Storage: Contracts ContractInfoOf (r:1 w:1) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) - fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (327_625_000 as Weight) - // Standard Error: 146_000 - .saturating_add((55_028_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) + // Storage: Skipped Metadata (r:0 w:0) + fn seal_contains_storage_per_kb(n: u32, ) -> Weight { + (528_701_000 as Weight) + // Standard Error: 246_000 + .saturating_add((10_375_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (41_931_000 as Weight) - // Standard Error: 933_000 - .saturating_add((433_619_000 as Weight).saturating_mul(r as Weight)) + (95_349_000 as Weight) + // Standard Error: 906_000 + .saturating_add((430_051_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -545,9 +562,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (639_259_000 as Weight) - // Standard Error: 365_000 - .saturating_add((64_588_000 as Weight).saturating_mul(n as Weight)) + (676_606_000 as Weight) + // Standard Error: 389_000 + .saturating_add((70_517_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } @@ -556,9 +573,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (71_335_000 as Weight) - // Standard Error: 1_489_000 - .saturating_add((1_765_321_000 as Weight).saturating_mul(r as Weight)) + (131_194_000 as Weight) + // Standard Error: 1_256_000 + .saturating_add((1_772_590_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -569,9 +586,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 9_243_000 - .saturating_add((16_121_990_000 as Weight).saturating_mul(r as Weight)) + (2_463_174_000 as Weight) + // Standard Error: 19_404_000 + .saturating_add((19_548_986_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -582,13 +599,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (15_978_164_000 as Weight) - // Standard Error: 57_271_000 - .saturating_add((1_179_479_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 20_000 - .saturating_add((17_389_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 21_000 - .saturating_add((28_660_000 as Weight).saturating_mul(o as Weight)) + (21_356_548_000 as Weight) + // Standard Error: 31_719_000 + .saturating_add((1_874_230_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 11_000 + .saturating_add((23_243_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 12_000 + .saturating_add((34_825_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -602,8 +619,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 115_056_000 - .saturating_add((23_312_565_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 49_981_000 + .saturating_add((28_988_348_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -616,13 +633,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (18_724_034_000 as Weight) - // Standard Error: 66_000 - .saturating_add((18_363_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 66_000 - .saturating_add((29_093_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 66_000 - .saturating_add((158_645_000 as Weight).saturating_mul(s as Weight)) + (24_726_887_000 as Weight) + // Standard Error: 32_000 + .saturating_add((23_702_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 32_000 + .saturating_add((35_841_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 32_000 + .saturating_add((161_159_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().writes(206 as Weight)) } @@ -631,9 +648,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (179_769_000 as Weight) - // Standard Error: 121_000 - .saturating_add((80_706_000 as Weight).saturating_mul(r as Weight)) + (221_804_000 as Weight) + // Standard Error: 150_000 + .saturating_add((84_131_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -642,9 +659,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (279_632_000 as Weight) - // Standard Error: 17_000 - .saturating_add((372_618_000 as Weight).saturating_mul(n as Weight)) + (357_186_000 as Weight) + // Standard Error: 23_000 + .saturating_add((469_081_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -653,9 +670,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (182_040_000 as Weight) - // Standard Error: 119_000 - .saturating_add((88_916_000 as Weight).saturating_mul(r as Weight)) + (220_729_000 as Weight) + // Standard Error: 166_000 + .saturating_add((101_538_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -664,9 +681,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (253_225_000 as Weight) - // Standard Error: 16_000 - .saturating_add((247_883_000 as Weight).saturating_mul(n as Weight)) + (272_756_000 as Weight) + // Standard Error: 18_000 + .saturating_add((311_130_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -675,9 +692,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (179_945_000 as Weight) - // Standard Error: 96_000 - .saturating_add((68_362_000 as Weight).saturating_mul(r as Weight)) + (215_784_000 as Weight) + // Standard Error: 150_000 + .saturating_add((68_809_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -686,9 +703,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (191_286_000 as Weight) - // Standard Error: 38_000 - .saturating_add((121_358_000 as Weight).saturating_mul(n as Weight)) + (256_009_000 as Weight) + // Standard Error: 12_000 + .saturating_add((124_552_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -697,9 +714,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (179_381_000 as Weight) - // Standard Error: 101_000 - .saturating_add((68_158_000 as Weight).saturating_mul(r as Weight)) + (216_413_000 as Weight) + // Standard Error: 134_000 + .saturating_add((68_281_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -708,9 +725,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (135_478_000 as Weight) - // Standard Error: 41_000 - .saturating_add((121_422_000 as Weight).saturating_mul(n as Weight)) + (254_477_000 as Weight) + // Standard Error: 13_000 + .saturating_add((124_483_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -719,266 +736,266 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (123_468_000 as Weight) - // Standard Error: 1_017_000 - .saturating_add((15_542_677_000 as Weight).saturating_mul(r as Weight)) + (179_001_000 as Weight) + // Standard Error: 1_674_000 + .saturating_add((15_397_995_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (52_702_000 as Weight) + (46_905_000 as Weight) // Standard Error: 12_000 - .saturating_add((844_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((794_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (47_295_000 as Weight) - // Standard Error: 10_000 - .saturating_add((3_045_000 as Weight).saturating_mul(r as Weight)) + (53_636_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_476_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (46_353_000 as Weight) - // Standard Error: 9_000 - .saturating_add((3_047_000 as Weight).saturating_mul(r as Weight)) + (53_199_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_547_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (49_811_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_408_000 as Weight).saturating_mul(r as Weight)) + (37_268_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_987_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (47_054_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_504_000 as Weight).saturating_mul(r as Weight)) + (37_138_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_057_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (49_912_000 as Weight) - // Standard Error: 16_000 - .saturating_add((1_460_000 as Weight).saturating_mul(r as Weight)) + (39_353_000 as Weight) + // Standard Error: 17_000 + .saturating_add((1_939_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (43_860_000 as Weight) + (38_883_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_150_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (37_009_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_762_000 as Weight).saturating_mul(r as Weight)) + (45_030_000 as Weight) + // Standard Error: 21_000 + .saturating_add((2_398_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (45_776_000 as Weight) + (47_281_000 as Weight) // Standard Error: 3_000 - .saturating_add((17_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((29_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (39_611_000 as Weight) - // Standard Error: 17_000 - .saturating_add((20_805_000 as Weight).saturating_mul(r as Weight)) + (49_074_000 as Weight) + // Standard Error: 20_000 + .saturating_add((19_991_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (45_523_000 as Weight) - // Standard Error: 27_000 - .saturating_add((31_622_000 as Weight).saturating_mul(r as Weight)) + (50_071_000 as Weight) + // Standard Error: 29_000 + .saturating_add((30_156_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (79_764_000 as Weight) - // Standard Error: 6_000 - .saturating_add((1_198_000 as Weight).saturating_mul(p as Weight)) + (84_902_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_124_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (46_510_000 as Weight) - // Standard Error: 11_000 - .saturating_add((810_000 as Weight).saturating_mul(r as Weight)) + (39_054_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (46_567_000 as Weight) - // Standard Error: 11_000 - .saturating_add((833_000 as Weight).saturating_mul(r as Weight)) + (39_190_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (43_439_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_463_000 as Weight).saturating_mul(r as Weight)) + (41_830_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_878_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (46_201_000 as Weight) - // Standard Error: 19_000 - .saturating_add((1_635_000 as Weight).saturating_mul(r as Weight)) + (40_764_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_931_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (42_639_000 as Weight) - // Standard Error: 18_000 - .saturating_add((1_652_000 as Weight).saturating_mul(r as Weight)) + (46_309_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_745_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (51_159_000 as Weight) - // Standard Error: 14_000 - .saturating_add((917_000 as Weight).saturating_mul(r as Weight)) + (47_071_000 as Weight) + // Standard Error: 12_000 + .saturating_add((797_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (36_462_000 as Weight) - // Standard Error: 867_000 - .saturating_add((187_724_000 as Weight).saturating_mul(r as Weight)) + (49_773_000 as Weight) + // Standard Error: 1_442_000 + .saturating_add((227_666_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (53_776_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_307_000 as Weight).saturating_mul(r as Weight)) + (43_879_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_486_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (53_674_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_304_000 as Weight).saturating_mul(r as Weight)) + (43_883_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_484_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (53_654_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_299_000 as Weight).saturating_mul(r as Weight)) + (43_415_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_495_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (53_493_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_299_000 as Weight).saturating_mul(r as Weight)) + (43_567_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_493_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (43_373_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_492_000 as Weight).saturating_mul(r as Weight)) + (41_332_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_912_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (43_222_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_498_000 as Weight).saturating_mul(r as Weight)) + (41_331_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_911_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (53_706_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_292_000 as Weight).saturating_mul(r as Weight)) + (43_704_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_487_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (48_994_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) + (37_103_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_467_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (49_464_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_876_000 as Weight).saturating_mul(r as Weight)) + (36_680_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_487_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (49_194_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_884_000 as Weight).saturating_mul(r as Weight)) + (36_659_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (49_291_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_883_000 as Weight).saturating_mul(r as Weight)) + (36_491_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (49_227_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_886_000 as Weight).saturating_mul(r as Weight)) + (36_440_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (49_219_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) + (36_477_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_500_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (49_263_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (36_561_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (49_251_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (36_418_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (49_257_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (36_835_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_484_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (49_219_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) + (36_873_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (49_221_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) + (37_013_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_466_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (48_936_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) + (36_885_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (49_266_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (36_696_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_487_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (49_246_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_565_000 as Weight).saturating_mul(r as Weight)) + (36_924_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_118_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (49_181_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_211_000 as Weight).saturating_mul(r as Weight)) + (36_819_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_784_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (49_337_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_525_000 as Weight).saturating_mul(r as Weight)) + (36_855_000 as Weight) + // Standard Error: 17_000 + .saturating_add((3_047_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (49_387_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_241_000 as Weight).saturating_mul(r as Weight)) + (36_890_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_816_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (49_137_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) + (36_749_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_475_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (49_366_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (36_928_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (49_143_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_912_000 as Weight).saturating_mul(r as Weight)) + (36_868_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_470_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (49_195_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) + (36_919_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_470_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (49_228_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) + (36_934_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (49_279_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) + (36_705_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (49_091_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) + (36_684_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_477_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (49_436_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_883_000 as Weight).saturating_mul(r as Weight)) + (36_844_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_477_000 as Weight).saturating_mul(r as Weight)) } } @@ -986,32 +1003,32 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_585_000 as Weight) + (1_636_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (7_902_000 as Weight) + (7_840_000 as Weight) // Standard Error: 0 - .saturating_add((751_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((752_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (31_473_000 as Weight) + (31_915_000 as Weight) // Standard Error: 1_000 - .saturating_add((104_000 as Weight).saturating_mul(q as Weight)) + .saturating_add((98_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (15_462_000 as Weight) - // Standard Error: 35_000 - .saturating_add((81_710_000 as Weight).saturating_mul(c as Weight)) + (18_897_000 as Weight) + // Standard Error: 32_000 + .saturating_add((69_663_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1020,9 +1037,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_kb(c: u32, ) -> Weight { - (169_561_000 as Weight) - // Standard Error: 56_000 - .saturating_add((60_037_000 as Weight).saturating_mul(c as Weight)) + (204_947_000 as Weight) + // Standard Error: 54_000 + .saturating_add((58_293_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1034,11 +1051,11 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (169_885_000 as Weight) - // Standard Error: 127_000 - .saturating_add((170_680_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 8_000 - .saturating_add((1_788_000 as Weight).saturating_mul(s as Weight)) + (211_187_000 as Weight) + // Standard Error: 114_000 + .saturating_add((156_529_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 7_000 + .saturating_add((1_830_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -1049,9 +1066,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (150_265_000 as Weight) + (150_485_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_722_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_769_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -1060,7 +1077,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (114_784_000 as Weight) + (117_274_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1068,9 +1085,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (48_072_000 as Weight) - // Standard Error: 36_000 - .saturating_add((83_578_000 as Weight).saturating_mul(c as Weight)) + (51_126_000 as Weight) + // Standard Error: 49_000 + .saturating_add((72_622_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1078,7 +1095,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_739_000 as Weight) + (24_221_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1087,9 +1104,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (174_123_000 as Weight) - // Standard Error: 127_000 - .saturating_add((56_078_000 as Weight).saturating_mul(r as Weight)) + (219_790_000 as Weight) + // Standard Error: 126_000 + .saturating_add((56_383_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1098,9 +1115,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (180_168_000 as Weight) - // Standard Error: 122_000 - .saturating_add((56_154_000 as Weight).saturating_mul(r as Weight)) + (218_377_000 as Weight) + // Standard Error: 117_000 + .saturating_add((57_243_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1109,9 +1126,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (179_464_000 as Weight) - // Standard Error: 96_000 - .saturating_add((55_350_000 as Weight).saturating_mul(r as Weight)) + (217_999_000 as Weight) + // Standard Error: 104_000 + .saturating_add((56_674_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1120,9 +1137,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (181_031_000 as Weight) - // Standard Error: 154_000 - .saturating_add((149_508_000 as Weight).saturating_mul(r as Weight)) + (226_932_000 as Weight) + // Standard Error: 155_000 + .saturating_add((147_401_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1131,9 +1148,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (178_709_000 as Weight) - // Standard Error: 107_000 - .saturating_add((56_326_000 as Weight).saturating_mul(r as Weight)) + (233_107_000 as Weight) + // Standard Error: 110_000 + .saturating_add((55_334_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1142,9 +1159,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (175_715_000 as Weight) - // Standard Error: 116_000 - .saturating_add((56_755_000 as Weight).saturating_mul(r as Weight)) + (235_364_000 as Weight) + // Standard Error: 122_000 + .saturating_add((54_700_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1153,9 +1170,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (178_552_000 as Weight) - // Standard Error: 121_000 - .saturating_add((55_756_000 as Weight).saturating_mul(r as Weight)) + (232_875_000 as Weight) + // Standard Error: 108_000 + .saturating_add((54_510_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1164,9 +1181,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (186_172_000 as Weight) - // Standard Error: 106_000 - .saturating_add((55_311_000 as Weight).saturating_mul(r as Weight)) + (226_089_000 as Weight) + // Standard Error: 126_000 + .saturating_add((54_899_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1176,9 +1193,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (183_750_000 as Weight) - // Standard Error: 140_000 - .saturating_add((131_877_000 as Weight).saturating_mul(r as Weight)) + (234_746_000 as Weight) + // Standard Error: 146_000 + .saturating_add((132_861_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1187,9 +1204,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (97_350_000 as Weight) - // Standard Error: 54_000 - .saturating_add((27_606_000 as Weight).saturating_mul(r as Weight)) + (96_247_000 as Weight) + // Standard Error: 70_000 + .saturating_add((27_918_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1198,9 +1215,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (179_058_000 as Weight) - // Standard Error: 106_000 - .saturating_add((53_258_000 as Weight).saturating_mul(r as Weight)) + (221_631_000 as Weight) + // Standard Error: 139_000 + .saturating_add((54_382_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1209,9 +1226,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (248_562_000 as Weight) - // Standard Error: 5_000 - .saturating_add((10_515_000 as Weight).saturating_mul(n as Weight)) + (306_449_000 as Weight) + // Standard Error: 3_000 + .saturating_add((11_919_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1220,9 +1237,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (161_228_000 as Weight) - // Standard Error: 90_000 - .saturating_add((14_539_000 as Weight).saturating_mul(r as Weight)) + (222_176_000 as Weight) + // Standard Error: 72_000 + .saturating_add((3_223_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1231,9 +1248,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (177_866_000 as Weight) + (211_079_000 as Weight) // Standard Error: 0 - .saturating_add((188_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((237_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1244,9 +1261,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (164_572_000 as Weight) - // Standard Error: 1_817_000 - .saturating_add((68_480_000 as Weight).saturating_mul(r as Weight)) + (213_994_000 as Weight) + // Standard Error: 104_000 + .saturating_add((64_453_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1258,9 +1275,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (168_658_000 as Weight) - // Standard Error: 189_000 - .saturating_add((166_190_000 as Weight).saturating_mul(r as Weight)) + (228_281_000 as Weight) + // Standard Error: 150_000 + .saturating_add((166_949_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1269,9 +1286,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (185_391_000 as Weight) - // Standard Error: 191_000 - .saturating_add((292_609_000 as Weight).saturating_mul(r as Weight)) + (230_348_000 as Weight) + // Standard Error: 163_000 + .saturating_add((288_679_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1281,11 +1298,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (507_994_000 as Weight) - // Standard Error: 1_569_000 - .saturating_add((276_852_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 309_000 - .saturating_add((79_461_000 as Weight).saturating_mul(n as Weight)) + (601_613_000 as Weight) + // Standard Error: 1_566_000 + .saturating_add((279_038_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 308_000 + .saturating_add((84_818_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1296,79 +1313,95 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (99_048_000 as Weight) - // Standard Error: 87_000 - .saturating_add((46_088_000 as Weight).saturating_mul(r as Weight)) + (113_578_000 as Weight) + // Standard Error: 67_000 + .saturating_add((44_899_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (142_559_000 as Weight) - // Standard Error: 603_000 - .saturating_add((269_723_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + (59_019_000 as Weight) + // Standard Error: 995_000 + .saturating_add((414_759_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:2 w:2) - // Storage: Contracts ContractInfoOf (r:1 w:1) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:1) - fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (346_704_000 as Weight) - // Standard Error: 200_000 - .saturating_add((29_907_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + // Storage: Skipped Metadata (r:0 w:0) + fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { + (620_483_000 as Weight) + // Standard Error: 242_000 + .saturating_add((30_945_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(105 as Weight)) + .saturating_add(RocksDbWeight::get().writes(103 as Weight)) + } + // Storage: Skipped Metadata (r:0 w:0) + fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { + (632_391_000 as Weight) + // Standard Error: 317_000 + .saturating_add((11_431_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(105 as Weight)) + .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 1_963_000 - .saturating_add((746_581_000 as Weight).saturating_mul(r as Weight)) + (96_628_000 as Weight) + // Standard Error: 878_000 + .saturating_add((387_212_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + fn seal_clear_storage_per_kb(n: u32, ) -> Weight { + (625_960_000 as Weight) + // Standard Error: 270_000 + .saturating_add((11_170_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(105 as Weight)) + .saturating_add(RocksDbWeight::get().writes(103 as Weight)) + } + // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (69_873_000 as Weight) - // Standard Error: 722_000 - .saturating_add((338_292_000 as Weight).saturating_mul(r as Weight)) + (115_155_000 as Weight) + // Standard Error: 741_000 + .saturating_add((331_711_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + fn seal_get_storage_per_kb(n: u32, ) -> Weight { + (582_560_000 as Weight) + // Standard Error: 360_000 + .saturating_add((68_427_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(104 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 1_169_000 - .saturating_add((480_500_000 as Weight).saturating_mul(r as Weight)) + (130_096_000 as Weight) + // Standard Error: 555_000 + .saturating_add((294_514_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: System Account (r:1 w:0) - // Storage: Contracts ContractInfoOf (r:1 w:1) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x7afa01283080ef247df84e0ba38ea5a587d25ce6633a6bfbba02068c14023441] (r:1 w:0) - fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (327_625_000 as Weight) - // Standard Error: 146_000 - .saturating_add((55_028_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + // Storage: Skipped Metadata (r:0 w:0) + fn seal_contains_storage_per_kb(n: u32, ) -> Weight { + (528_701_000 as Weight) + // Standard Error: 246_000 + .saturating_add((10_375_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (41_931_000 as Weight) - // Standard Error: 933_000 - .saturating_add((433_619_000 as Weight).saturating_mul(r as Weight)) + (95_349_000 as Weight) + // Standard Error: 906_000 + .saturating_add((430_051_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1376,9 +1409,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (639_259_000 as Weight) - // Standard Error: 365_000 - .saturating_add((64_588_000 as Weight).saturating_mul(n as Weight)) + (676_606_000 as Weight) + // Standard Error: 389_000 + .saturating_add((70_517_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } @@ -1387,9 +1420,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (71_335_000 as Weight) - // Standard Error: 1_489_000 - .saturating_add((1_765_321_000 as Weight).saturating_mul(r as Weight)) + (131_194_000 as Weight) + // Standard Error: 1_256_000 + .saturating_add((1_772_590_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1400,9 +1433,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 9_243_000 - .saturating_add((16_121_990_000 as Weight).saturating_mul(r as Weight)) + (2_463_174_000 as Weight) + // Standard Error: 19_404_000 + .saturating_add((19_548_986_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1413,13 +1446,13 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_input_output_kb(t: u32, i: u32, o: u32, ) -> Weight { - (15_978_164_000 as Weight) - // Standard Error: 57_271_000 - .saturating_add((1_179_479_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 20_000 - .saturating_add((17_389_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 21_000 - .saturating_add((28_660_000 as Weight).saturating_mul(o as Weight)) + (21_356_548_000 as Weight) + // Standard Error: 31_719_000 + .saturating_add((1_874_230_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 11_000 + .saturating_add((23_243_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 12_000 + .saturating_add((34_825_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1433,8 +1466,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 115_056_000 - .saturating_add((23_312_565_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 49_981_000 + .saturating_add((28_988_348_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1447,13 +1480,13 @@ impl WeightInfo for () { // Storage: Contracts AccountCounter (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_input_output_salt_kb(i: u32, o: u32, s: u32, ) -> Weight { - (18_724_034_000 as Weight) - // Standard Error: 66_000 - .saturating_add((18_363_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 66_000 - .saturating_add((29_093_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 66_000 - .saturating_add((158_645_000 as Weight).saturating_mul(s as Weight)) + (24_726_887_000 as Weight) + // Standard Error: 32_000 + .saturating_add((23_702_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 32_000 + .saturating_add((35_841_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 32_000 + .saturating_add((161_159_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().writes(206 as Weight)) } @@ -1462,9 +1495,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (179_769_000 as Weight) - // Standard Error: 121_000 - .saturating_add((80_706_000 as Weight).saturating_mul(r as Weight)) + (221_804_000 as Weight) + // Standard Error: 150_000 + .saturating_add((84_131_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1473,9 +1506,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (279_632_000 as Weight) - // Standard Error: 17_000 - .saturating_add((372_618_000 as Weight).saturating_mul(n as Weight)) + (357_186_000 as Weight) + // Standard Error: 23_000 + .saturating_add((469_081_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1484,9 +1517,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (182_040_000 as Weight) - // Standard Error: 119_000 - .saturating_add((88_916_000 as Weight).saturating_mul(r as Weight)) + (220_729_000 as Weight) + // Standard Error: 166_000 + .saturating_add((101_538_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1495,9 +1528,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (253_225_000 as Weight) - // Standard Error: 16_000 - .saturating_add((247_883_000 as Weight).saturating_mul(n as Weight)) + (272_756_000 as Weight) + // Standard Error: 18_000 + .saturating_add((311_130_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1506,9 +1539,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (179_945_000 as Weight) - // Standard Error: 96_000 - .saturating_add((68_362_000 as Weight).saturating_mul(r as Weight)) + (215_784_000 as Weight) + // Standard Error: 150_000 + .saturating_add((68_809_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1517,9 +1550,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (191_286_000 as Weight) - // Standard Error: 38_000 - .saturating_add((121_358_000 as Weight).saturating_mul(n as Weight)) + (256_009_000 as Weight) + // Standard Error: 12_000 + .saturating_add((124_552_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1528,9 +1561,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (179_381_000 as Weight) - // Standard Error: 101_000 - .saturating_add((68_158_000 as Weight).saturating_mul(r as Weight)) + (216_413_000 as Weight) + // Standard Error: 134_000 + .saturating_add((68_281_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1539,9 +1572,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (135_478_000 as Weight) - // Standard Error: 41_000 - .saturating_add((121_422_000 as Weight).saturating_mul(n as Weight)) + (254_477_000 as Weight) + // Standard Error: 13_000 + .saturating_add((124_483_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1550,265 +1583,265 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (123_468_000 as Weight) - // Standard Error: 1_017_000 - .saturating_add((15_542_677_000 as Weight).saturating_mul(r as Weight)) + (179_001_000 as Weight) + // Standard Error: 1_674_000 + .saturating_add((15_397_995_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (52_702_000 as Weight) + (46_905_000 as Weight) // Standard Error: 12_000 - .saturating_add((844_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((794_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (47_295_000 as Weight) - // Standard Error: 10_000 - .saturating_add((3_045_000 as Weight).saturating_mul(r as Weight)) + (53_636_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_476_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (46_353_000 as Weight) - // Standard Error: 9_000 - .saturating_add((3_047_000 as Weight).saturating_mul(r as Weight)) + (53_199_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_547_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (49_811_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_408_000 as Weight).saturating_mul(r as Weight)) + (37_268_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_987_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (47_054_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_504_000 as Weight).saturating_mul(r as Weight)) + (37_138_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_057_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (49_912_000 as Weight) - // Standard Error: 16_000 - .saturating_add((1_460_000 as Weight).saturating_mul(r as Weight)) + (39_353_000 as Weight) + // Standard Error: 17_000 + .saturating_add((1_939_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (43_860_000 as Weight) + (38_883_000 as Weight) // Standard Error: 17_000 - .saturating_add((2_150_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (37_009_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_762_000 as Weight).saturating_mul(r as Weight)) + (45_030_000 as Weight) + // Standard Error: 21_000 + .saturating_add((2_398_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (45_776_000 as Weight) + (47_281_000 as Weight) // Standard Error: 3_000 - .saturating_add((17_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((29_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (39_611_000 as Weight) - // Standard Error: 17_000 - .saturating_add((20_805_000 as Weight).saturating_mul(r as Weight)) + (49_074_000 as Weight) + // Standard Error: 20_000 + .saturating_add((19_991_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (45_523_000 as Weight) - // Standard Error: 27_000 - .saturating_add((31_622_000 as Weight).saturating_mul(r as Weight)) + (50_071_000 as Weight) + // Standard Error: 29_000 + .saturating_add((30_156_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (79_764_000 as Weight) - // Standard Error: 6_000 - .saturating_add((1_198_000 as Weight).saturating_mul(p as Weight)) + (84_902_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_124_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (46_510_000 as Weight) - // Standard Error: 11_000 - .saturating_add((810_000 as Weight).saturating_mul(r as Weight)) + (39_054_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (46_567_000 as Weight) - // Standard Error: 11_000 - .saturating_add((833_000 as Weight).saturating_mul(r as Weight)) + (39_190_000 as Weight) + // Standard Error: 14_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (43_439_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_463_000 as Weight).saturating_mul(r as Weight)) + (41_830_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_878_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (46_201_000 as Weight) - // Standard Error: 19_000 - .saturating_add((1_635_000 as Weight).saturating_mul(r as Weight)) + (40_764_000 as Weight) + // Standard Error: 13_000 + .saturating_add((1_931_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (42_639_000 as Weight) - // Standard Error: 18_000 - .saturating_add((1_652_000 as Weight).saturating_mul(r as Weight)) + (46_309_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_745_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (51_159_000 as Weight) - // Standard Error: 14_000 - .saturating_add((917_000 as Weight).saturating_mul(r as Weight)) + (47_071_000 as Weight) + // Standard Error: 12_000 + .saturating_add((797_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (36_462_000 as Weight) - // Standard Error: 867_000 - .saturating_add((187_724_000 as Weight).saturating_mul(r as Weight)) + (49_773_000 as Weight) + // Standard Error: 1_442_000 + .saturating_add((227_666_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (53_776_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_307_000 as Weight).saturating_mul(r as Weight)) + (43_879_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_486_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (53_674_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_304_000 as Weight).saturating_mul(r as Weight)) + (43_883_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_484_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (53_654_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_299_000 as Weight).saturating_mul(r as Weight)) + (43_415_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_495_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (53_493_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_299_000 as Weight).saturating_mul(r as Weight)) + (43_567_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_493_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (43_373_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_492_000 as Weight).saturating_mul(r as Weight)) + (41_332_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_912_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (43_222_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_498_000 as Weight).saturating_mul(r as Weight)) + (41_331_000 as Weight) + // Standard Error: 12_000 + .saturating_add((1_911_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (53_706_000 as Weight) - // Standard Error: 9_000 - .saturating_add((1_292_000 as Weight).saturating_mul(r as Weight)) + (43_704_000 as Weight) + // Standard Error: 11_000 + .saturating_add((1_487_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (48_994_000 as Weight) - // Standard Error: 10_000 - .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) + (37_103_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_467_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (49_464_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_876_000 as Weight).saturating_mul(r as Weight)) + (36_680_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_487_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (49_194_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_884_000 as Weight).saturating_mul(r as Weight)) + (36_659_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_494_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (49_291_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_883_000 as Weight).saturating_mul(r as Weight)) + (36_491_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_495_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (49_227_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_886_000 as Weight).saturating_mul(r as Weight)) + (36_440_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (49_219_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) + (36_477_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_500_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (49_263_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (36_561_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_498_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (49_251_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (36_418_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_501_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (49_257_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (36_835_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_484_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (49_219_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_885_000 as Weight).saturating_mul(r as Weight)) + (36_873_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (49_221_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) + (37_013_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_466_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (48_936_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) + (36_885_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (49_266_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (36_696_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_487_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (49_246_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_565_000 as Weight).saturating_mul(r as Weight)) + (36_924_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_118_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (49_181_000 as Weight) - // Standard Error: 10_000 - .saturating_add((2_211_000 as Weight).saturating_mul(r as Weight)) + (36_819_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_784_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (49_337_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_525_000 as Weight).saturating_mul(r as Weight)) + (36_855_000 as Weight) + // Standard Error: 17_000 + .saturating_add((3_047_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (49_387_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_241_000 as Weight).saturating_mul(r as Weight)) + (36_890_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_816_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (49_137_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) + (36_749_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_475_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (49_366_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_882_000 as Weight).saturating_mul(r as Weight)) + (36_928_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_469_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (49_143_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_912_000 as Weight).saturating_mul(r as Weight)) + (36_868_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_470_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (49_195_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_891_000 as Weight).saturating_mul(r as Weight)) + (36_919_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_470_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (49_228_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_900_000 as Weight).saturating_mul(r as Weight)) + (36_934_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_471_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (49_279_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_888_000 as Weight).saturating_mul(r as Weight)) + (36_705_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_492_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (49_091_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_909_000 as Weight).saturating_mul(r as Weight)) + (36_684_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_477_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (49_436_000 as Weight) - // Standard Error: 11_000 - .saturating_add((1_883_000 as Weight).saturating_mul(r as Weight)) + (36_844_000 as Weight) + // Standard Error: 17_000 + .saturating_add((2_477_000 as Weight).saturating_mul(r as Weight)) } } From 31d90c202d6df9ce3837ee55587b604619a912ba Mon Sep 17 00:00:00 2001 From: Enoch Chejieh Date: Tue, 25 Jan 2022 10:04:07 +0100 Subject: [PATCH 0458/1472] chore: add example for balance AccountStore (#10361) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: modified example for balance AccountStore * add example for account store balance * add example for account store balance * Update frame/balances/src/lib.rs * Update frame/balances/src/lib.rs * balance account store example * balance account store example * Update frame/balances/src/lib.rs * Update frame/balances/src/lib.rs * balance account store example Co-authored-by: Bastian Köcher Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/balances/src/lib.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 8a6d54b54c8dc..80e8bf577abe6 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -488,8 +488,29 @@ pub mod pallet { #[pallet::getter(fn total_issuance)] pub type TotalIssuance, I: 'static = ()> = StorageValue<_, T::Balance, ValueQuery>; - /// The balance of an account. + /// The Balances pallet example of storing the balance of an account. /// + /// # Example + /// + /// ```nocompile + /// impl pallet_balances::Config for Runtime { + /// type AccountStore = StorageMapShim, frame_system::Provider, AccountId, Self::AccountData> + /// } + /// ``` + /// + /// You can also store the balance of an account in the `System` pallet. + /// + /// # Example + /// + /// ```nocompile + /// impl pallet_balances::Config for Runtime { + /// type AccountStore = System + /// } + /// ``` + /// + /// But this comes with tradeoffs, storing account balances in the system pallet stores + /// `frame_system` data alongside the account data contrary to storing account balances in the + /// `Balances` pallet, which uses a `StorageMap` to store balances data only. /// NOTE: This is only used in the case that this pallet is used to store balances. #[pallet::storage] pub type Account, I: 'static = ()> = StorageMap< From 9e9e4d3963ac43d167bd52458bcfe860aabe7e0b Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 25 Jan 2022 15:44:10 +0100 Subject: [PATCH 0459/1472] Use proper bounded vector type for nominations (#10601) * Use proper bounded vector type for nominations * add docs and tweak chill_other for cleanup purposes * Fix the build * remove TODO * add a bit more doc * even more docs gushc * Update frame/staking/src/pallet/mod.rs Co-authored-by: Zeke Mostov * Update frame/staking/src/pallet/mod.rs Co-authored-by: Zeke Mostov * Fix the nasty bug * also bound the Snapshot type * fix doc test * document bounded_vec * self-review * remove unused * Fix build * frame-support: repetition overload for bounded_vec Signed-off-by: Oliver Tale-Yazdi * fix * remove the need to allocate into unbounded voters etc etc * Don't expect * unbreal the build again * handle macro a bit better Co-authored-by: Zeke Mostov Co-authored-by: Oliver Tale-Yazdi --- bin/node/cli/src/chain_spec.rs | 6 +- bin/node/runtime/src/lib.rs | 8 +- frame/babe/src/mock.rs | 2 +- .../src/benchmarking.rs | 26 +++-- .../src/helpers.rs | 12 +-- .../election-provider-multi-phase/src/lib.rs | 19 ++-- .../election-provider-multi-phase/src/mock.rs | 71 +++++++------ .../src/unsigned.rs | 14 ++- frame/election-provider-support/src/lib.rs | 44 +++++--- .../election-provider-support/src/onchain.rs | 21 ++-- frame/elections-phragmen/src/lib.rs | 4 +- frame/grandpa/src/mock.rs | 2 +- frame/offences/benchmarking/src/lib.rs | 8 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/session/benchmarking/src/lib.rs | 10 +- frame/session/benchmarking/src/mock.rs | 2 +- frame/staking/src/benchmarking.rs | 28 ++--- frame/staking/src/lib.rs | 9 +- frame/staking/src/mock.rs | 5 +- frame/staking/src/pallet/impls.rs | 41 ++++--- frame/staking/src/pallet/mod.rs | 97 +++++++++-------- frame/staking/src/tests.rs | 100 +++++++++++++++++- frame/support/src/lib.rs | 23 ++++ frame/support/src/storage/bounded_vec.rs | 13 +++ .../support/src/storage/types/counted_map.rs | 7 ++ frame/system/src/lib.rs | 5 - .../npos-elections/fuzzer/src/common.rs | 18 +--- .../fuzzer/src/phragmen_balancing.rs | 11 +- .../fuzzer/src/phragmms_balancing.rs | 13 +-- primitives/npos-elections/src/lib.rs | 4 +- primitives/npos-elections/src/mock.rs | 2 +- primitives/npos-elections/src/phragmen.rs | 2 +- primitives/npos-elections/src/phragmms.rs | 14 +-- primitives/npos-elections/src/tests.rs | 28 ++--- 34 files changed, 419 insertions(+), 252 deletions(-) diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 747bc71c5007c..6fd57e31e466e 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -23,8 +23,8 @@ use hex_literal::hex; use node_runtime::{ constants::currency::*, wasm_binary_unwrap, AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, Block, CouncilConfig, DemocracyConfig, ElectionsConfig, GrandpaConfig, - ImOnlineConfig, IndicesConfig, SessionConfig, SessionKeys, SocietyConfig, StakerStatus, - StakingConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, MAX_NOMINATIONS, + ImOnlineConfig, IndicesConfig, MaxNominations, SessionConfig, SessionKeys, SocietyConfig, + StakerStatus, StakingConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, }; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use sc_chain_spec::ChainSpecExtension; @@ -278,7 +278,7 @@ pub fn testnet_genesis( .map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)) .chain(initial_nominators.iter().map(|x| { use rand::{seq::SliceRandom, Rng}; - let limit = (MAX_NOMINATIONS as usize).min(initial_authorities.len()); + let limit = (MaxNominations::get() as usize).min(initial_authorities.len()); let count = rng.gen::() % limit; let nominations = initial_authorities .as_slice() diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 6034b86987ffb..8f00dd8f64b4c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -541,7 +541,7 @@ impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { } impl pallet_staking::Config for Runtime { - const MAX_NOMINATIONS: u32 = MAX_NOMINATIONS; + type MaxNominations = MaxNominations; type Currency = Balances; type UnixTime = Timestamp; type CurrencyToVote = U128CurrencyToVote; @@ -605,7 +605,9 @@ sp_npos_elections::generate_solution_type!( >(16) ); -pub const MAX_NOMINATIONS: u32 = ::LIMIT as u32; +parameter_types! { + pub MaxNominations: u32 = ::LIMIT as u32; +} /// The numbers configured here could always be more than the the maximum limits of staking pallet /// to ensure election snapshot will not run out of memory. For now, we set them to smaller values @@ -1792,7 +1794,7 @@ mod tests { #[test] fn perbill_as_onchain_accuracy() { type OnChainAccuracy = ::Accuracy; - let maximum_chain_accuracy: Vec> = (0..MAX_NOMINATIONS) + let maximum_chain_accuracy: Vec> = (0..MaxNominations::get()) .map(|_| >::from(OnChainAccuracy::one().deconstruct())) .collect(); let _: UpperOf = diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index fa7a7b185b342..2e4b6023f1e5f 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -178,7 +178,7 @@ impl onchain::Config for Test { } impl pallet_staking::Config for Test { - const MAX_NOMINATIONS: u32 = 16; + type MaxNominations = ConstU32<16>; type RewardRemainder = (); type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type Event = Event; diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index d605c5131cf77..d37b9451b770f 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -20,7 +20,11 @@ use super::*; use crate::{unsigned::IndexAssignmentOf, Pallet as MultiPhase}; use frame_benchmarking::account; -use frame_support::{assert_ok, traits::Hooks}; +use frame_support::{ + assert_ok, + traits::{Hooks, TryCollect}, + BoundedVec, +}; use frame_system::RawOrigin; use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng}; use sp_arithmetic::{per_things::Percent, traits::One}; @@ -69,11 +73,12 @@ fn solution_with_size( let active_voters = (0..active_voters_count) .map(|i| { // chose a random subset of winners. - let winner_votes = winners + let winner_votes: BoundedVec<_, _> = winners .as_slice() .choose_multiple(&mut rng, >::LIMIT) .cloned() - .collect::>(); + .try_collect() + .expect(">::LIMIT is the correct bound; qed."); let voter = frame_benchmarking::account::("Voter", i, SEED); (voter, stake, winner_votes) }) @@ -87,10 +92,11 @@ fn solution_with_size( .collect::>(); let rest_voters = (active_voters_count..size.voters) .map(|i| { - let votes = (&non_winners) + let votes: BoundedVec<_, _> = (&non_winners) .choose_multiple(&mut rng, >::LIMIT) .cloned() - .collect::>(); + .try_collect() + .expect(">::LIMIT is the correct bound; qed."); let voter = frame_benchmarking::account::("Voter", i, SEED); (voter, stake, votes) }) @@ -152,7 +158,7 @@ fn set_up_data_provider(v: u32, t: u32) { info, "setting up with voters = {} [degree = {}], targets = {}", v, - T::DataProvider::MAXIMUM_VOTES_PER_VOTER, + ::MaxVotesPerVoter::get(), t ); @@ -165,14 +171,16 @@ fn set_up_data_provider(v: u32, t: u32) { }) .collect::>(); // we should always have enough voters to fill. - assert!(targets.len() > T::DataProvider::MAXIMUM_VOTES_PER_VOTER as usize); - targets.truncate(T::DataProvider::MAXIMUM_VOTES_PER_VOTER as usize); + assert!( + targets.len() > ::MaxVotesPerVoter::get() as usize + ); + targets.truncate(::MaxVotesPerVoter::get() as usize); // fill voters. (0..v).for_each(|i| { let voter = frame_benchmarking::account::("Voter", i, SEED); let weight = T::Currency::minimum_balance().saturated_into::() * 1000; - T::DataProvider::add_voter(voter, weight, targets.clone()); + T::DataProvider::add_voter(voter, weight, targets.clone().try_into().unwrap()); }); } diff --git a/frame/election-provider-multi-phase/src/helpers.rs b/frame/election-provider-multi-phase/src/helpers.rs index 9bd5b5dbabd25..48da194cc65d9 100644 --- a/frame/election-provider-multi-phase/src/helpers.rs +++ b/frame/election-provider-multi-phase/src/helpers.rs @@ -17,7 +17,7 @@ //! Some helper functions/macros for this crate. -use super::{Config, SolutionTargetIndexOf, SolutionVoterIndexOf, VoteWeight}; +use crate::{unsigned::VoterOf, Config, SolutionTargetIndexOf, SolutionVoterIndexOf, VoteWeight}; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; #[macro_export] @@ -34,7 +34,7 @@ macro_rules! log { /// /// This can be used to efficiently build index getter closures. pub fn generate_voter_cache( - snapshot: &Vec<(T::AccountId, VoteWeight, Vec)>, + snapshot: &Vec>, ) -> BTreeMap { let mut cache: BTreeMap = BTreeMap::new(); snapshot.iter().enumerate().for_each(|(i, (x, _, _))| { @@ -97,7 +97,7 @@ pub fn voter_index_fn_usize( /// Not meant to be used in production. #[cfg(test)] pub fn voter_index_fn_linear( - snapshot: &Vec<(T::AccountId, VoteWeight, Vec)>, + snapshot: &Vec>, ) -> impl Fn(&T::AccountId) -> Option> + '_ { move |who| { snapshot @@ -148,7 +148,7 @@ pub fn target_index_fn_linear( /// Create a function that can map a voter index ([`SolutionVoterIndexOf`]) to the actual voter /// account using a linearly indexible snapshot. pub fn voter_at_fn( - snapshot: &Vec<(T::AccountId, VoteWeight, Vec)>, + snapshot: &Vec>, ) -> impl Fn(SolutionVoterIndexOf) -> Option + '_ { move |i| { as TryInto>::try_into(i) @@ -174,7 +174,7 @@ pub fn target_at_fn( /// This is not optimized and uses a linear search. #[cfg(test)] pub fn stake_of_fn_linear( - snapshot: &Vec<(T::AccountId, VoteWeight, Vec)>, + snapshot: &Vec>, ) -> impl Fn(&T::AccountId) -> VoteWeight + '_ { move |who| { snapshot @@ -192,7 +192,7 @@ pub fn stake_of_fn_linear( /// The cache need must be derived from the same snapshot. Zero is returned if a voter is /// non-existent. pub fn stake_of_fn<'a, T: Config>( - snapshot: &'a Vec<(T::AccountId, VoteWeight, Vec)>, + snapshot: &'a Vec>, cache: &'a BTreeMap, ) -> impl Fn(&T::AccountId) -> VoteWeight + 'a { move |who| { diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 4716bcd6c859b..f1d1d78912c46 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -269,6 +269,7 @@ const LOG_TARGET: &'static str = "runtime::election-provider"; pub mod signed; pub mod unsigned; pub mod weights; +use unsigned::VoterOf; pub use weights::WeightInfo; pub use signed::{ @@ -448,11 +449,13 @@ pub struct ReadySolution { /// /// These are stored together because they are often accessed together. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default, TypeInfo)] -pub struct RoundSnapshot { +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub struct RoundSnapshot { /// All of the voters. - pub voters: Vec<(A, VoteWeight, Vec)>, + pub voters: Vec>, /// All of the targets. - pub targets: Vec, + pub targets: Vec, } /// Encodes the length of a solution or a snapshot. @@ -820,7 +823,7 @@ pub mod pallet { // NOTE that this pallet does not really need to enforce this in runtime. The // solution cannot represent any voters more than `LIMIT` anyhow. assert_eq!( - ::MAXIMUM_VOTES_PER_VOTER, + ::MaxVotesPerVoter::get(), as NposSolution>::LIMIT as u32, ); } @@ -1140,7 +1143,7 @@ pub mod pallet { /// This is created at the beginning of the signed phase and cleared upon calling `elect`. #[pallet::storage] #[pallet::getter(fn snapshot)] - pub type Snapshot = StorageValue<_, RoundSnapshot>; + pub type Snapshot = StorageValue<_, RoundSnapshot>; /// Desired number of targets to elect for this round. /// @@ -1257,7 +1260,7 @@ impl Pallet { /// Extracted for easier weight calculation. fn create_snapshot_internal( targets: Vec, - voters: Vec>, + voters: Vec>, desired_targets: u32, ) { let metadata = @@ -1270,7 +1273,7 @@ impl Pallet { // instead of using storage APIs, we do a manual encoding into a fixed-size buffer. // `encoded_size` encodes it without storing it anywhere, this should not cause any // allocation. - let snapshot = RoundSnapshot { voters, targets }; + let snapshot = RoundSnapshot:: { voters, targets }; let size = snapshot.encoded_size(); log!(debug, "snapshot pre-calculated size {:?}", size); let mut buffer = Vec::with_capacity(size); @@ -1288,7 +1291,7 @@ impl Pallet { /// /// Extracted for easier weight calculation. fn create_snapshot_external( - ) -> Result<(Vec, Vec>, u32), ElectionError> { + ) -> Result<(Vec, Vec>, u32), ElectionError> { let target_limit = >::max_value().saturated_into::(); // for now we have just a single block snapshot. let voter_limit = T::VoterSnapshotPerBlock::get().saturated_into::(); diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 409ebd3f1e10d..1be93c363e321 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -22,11 +22,12 @@ use frame_election_provider_support::{ }; pub use frame_support::{assert_noop, assert_ok}; use frame_support::{ - parameter_types, + bounded_vec, parameter_types, traits::{ConstU32, Hooks}, weights::Weight, + BoundedVec, }; -use multi_phase::unsigned::{IndexAssignmentOf, Voter}; +use multi_phase::unsigned::{IndexAssignmentOf, VoterOf}; use parking_lot::RwLock; use sp_core::{ offchain::{ @@ -100,7 +101,7 @@ pub fn roll_to_with_ocw(n: BlockNumber) { } pub struct TrimHelpers { - pub voters: Vec>, + pub voters: Vec>, pub assignments: Vec>, pub encoded_size_of: Box]) -> Result>, @@ -131,13 +132,8 @@ pub fn trim_helpers() -> TrimHelpers { let desired_targets = MultiPhase::desired_targets().unwrap(); - let ElectionResult { mut assignments, .. } = seq_phragmen::<_, SolutionAccuracyOf>( - desired_targets as usize, - targets.clone(), - voters.clone(), - None, - ) - .unwrap(); + let ElectionResult::<_, SolutionAccuracyOf> { mut assignments, .. } = + seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None).unwrap(); // sort by decreasing order of stake assignments.sort_unstable_by_key(|assignment| { @@ -163,14 +159,8 @@ pub fn raw_solution() -> RawSolution> { let RoundSnapshot { voters, targets } = MultiPhase::snapshot().unwrap(); let desired_targets = MultiPhase::desired_targets().unwrap(); - let ElectionResult { winners: _, assignments } = - seq_phragmen::<_, SolutionAccuracyOf>( - desired_targets as usize, - targets.clone(), - voters.clone(), - None, - ) - .unwrap(); + let ElectionResult::<_, SolutionAccuracyOf> { winners: _, assignments } = + seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None).unwrap(); // closures let cache = helpers::generate_voter_cache::(&voters); @@ -246,16 +236,16 @@ impl pallet_balances::Config for Runtime { parameter_types! { pub static Targets: Vec = vec![10, 20, 30, 40]; - pub static Voters: Vec<(AccountId, VoteWeight, Vec)> = vec![ - (1, 10, vec![10, 20]), - (2, 10, vec![30, 40]), - (3, 10, vec![40]), - (4, 10, vec![10, 20, 30, 40]), + pub static Voters: Vec> = vec![ + (1, 10, bounded_vec![10, 20]), + (2, 10, bounded_vec![30, 40]), + (3, 10, bounded_vec![40]), + (4, 10, bounded_vec![10, 20, 30, 40]), // self votes. - (10, 10, vec![10]), - (20, 20, vec![20]), - (30, 30, vec![30]), - (40, 40, vec![40]), + (10, 10, bounded_vec![10]), + (20, 20, bounded_vec![20]), + (30, 30, bounded_vec![30]), + (40, 40, bounded_vec![40]), ]; pub static DesiredTargets: u32 = 2; @@ -436,6 +426,10 @@ where pub type Extrinsic = sp_runtime::testing::TestXt; +parameter_types! { + pub MaxNominations: u32 = ::LIMIT as u32; +} + #[derive(Default)] pub struct ExtBuilder {} @@ -443,7 +437,7 @@ pub struct StakingMock; impl ElectionDataProvider for StakingMock { type AccountId = AccountId; type BlockNumber = u64; - const MAXIMUM_VOTES_PER_VOTER: u32 = ::LIMIT as u32; + type MaxVotesPerVoter = MaxNominations; fn targets(maybe_max_len: Option) -> data_provider::Result> { let targets = Targets::get(); @@ -454,9 +448,7 @@ impl ElectionDataProvider for StakingMock { Ok(targets) } - fn voters( - maybe_max_len: Option, - ) -> data_provider::Result)>> { + fn voters(maybe_max_len: Option) -> data_provider::Result>> { let mut voters = Voters::get(); if let Some(max_len) = maybe_max_len { voters.truncate(max_len) @@ -475,7 +467,7 @@ impl ElectionDataProvider for StakingMock { #[cfg(feature = "runtime-benchmarks")] fn put_snapshot( - voters: Vec<(AccountId, VoteWeight, Vec)>, + voters: Vec>, targets: Vec, _target_stake: Option, ) { @@ -490,7 +482,11 @@ impl ElectionDataProvider for StakingMock { } #[cfg(feature = "runtime-benchmarks")] - fn add_voter(voter: AccountId, weight: VoteWeight, targets: Vec) { + fn add_voter( + voter: AccountId, + weight: VoteWeight, + targets: frame_support::BoundedVec, + ) { let mut current = Voters::get(); current.push((voter, weight, targets)); Voters::set(current); @@ -505,7 +501,7 @@ impl ElectionDataProvider for StakingMock { // to be on-par with staking, we add a self vote as well. the stake is really not that // important. let mut current = Voters::get(); - current.push((target, ExistentialDeposit::get() as u64, vec![target])); + current.push((target, ExistentialDeposit::get() as u64, bounded_vec![target])); Voters::set(current); } } @@ -540,7 +536,12 @@ impl ExtBuilder { ::set(t); self } - pub fn add_voter(self, who: AccountId, stake: Balance, targets: Vec) -> Self { + pub fn add_voter( + self, + who: AccountId, + stake: Balance, + targets: BoundedVec, + ) -> Self { VOTERS.with(|v| v.borrow_mut().push((who, stake, targets))); self } diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index da56dd4d073df..936993b41fb6c 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -47,11 +47,7 @@ pub(crate) const OFFCHAIN_CACHED_CALL: &[u8] = b"parity/multi-phase-unsigned-ele /// A voter's fundamental data: their ID, their stake, and the list of candidates for whom they /// voted. -pub type Voter = ( - ::AccountId, - sp_npos_elections::VoteWeight, - Vec<::AccountId>, -); +pub type VoterOf = frame_election_provider_support::VoterOf<::DataProvider>; /// The relative distribution of a voter's stake among the winning targets. pub type Assignment = @@ -749,7 +745,9 @@ mod tests { }; use codec::Decode; use frame_benchmarking::Zero; - use frame_support::{assert_noop, assert_ok, dispatch::Dispatchable, traits::OffchainWorker}; + use frame_support::{ + assert_noop, assert_ok, bounded_vec, dispatch::Dispatchable, traits::OffchainWorker, + }; use sp_npos_elections::IndexAssignment; use sp_runtime::{ offchain::storage_lock::{BlockAndTime, StorageLock}, @@ -1048,8 +1046,8 @@ mod tests { fn unsigned_per_dispatch_checks_can_only_submit_threshold_better() { ExtBuilder::default() .desired_targets(1) - .add_voter(7, 2, vec![10]) - .add_voter(8, 5, vec![10]) + .add_voter(7, 2, bounded_vec![10]) + .add_voter(8, 5, bounded_vec![10]) .solution_improvement_threshold(Perbill::from_percent(50)) .build_and_execute(|| { roll_to(25); diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 889606da3428a..3374e1e97b8be 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -80,6 +80,7 @@ //! ```rust //! # use frame_election_provider_support::{*, data_provider}; //! # use sp_npos_elections::{Support, Assignment}; +//! # use frame_support::traits::ConstU32; //! //! type AccountId = u64; //! type Balance = u64; @@ -101,13 +102,13 @@ //! impl ElectionDataProvider for Pallet { //! type AccountId = AccountId; //! type BlockNumber = BlockNumber; -//! const MAXIMUM_VOTES_PER_VOTER: u32 = 1; +//! type MaxVotesPerVoter = ConstU32<1>; //! //! fn desired_targets() -> data_provider::Result { //! Ok(1) //! } //! fn voters(maybe_max_len: Option) -//! -> data_provider::Result)>> +//! -> data_provider::Result>> //! { //! Ok(Default::default()) //! } @@ -166,7 +167,7 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod onchain; -use frame_support::traits::Get; +use frame_support::{traits::Get, BoundedVec}; use sp_std::{fmt::Debug, prelude::*}; /// Re-export some type as they are used in the interface. @@ -191,7 +192,7 @@ pub trait ElectionDataProvider { type BlockNumber; /// Maximum number of votes per voter that this data provider is providing. - const MAXIMUM_VOTES_PER_VOTER: u32; + type MaxVotesPerVoter: Get; /// All possible targets for the election, i.e. the candidates. /// @@ -211,9 +212,7 @@ pub trait ElectionDataProvider { /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. - fn voters( - maybe_max_len: Option, - ) -> data_provider::Result)>>; + fn voters(maybe_max_len: Option) -> data_provider::Result>>; /// The number of targets to elect. /// @@ -233,7 +232,7 @@ pub trait ElectionDataProvider { /// else a noop. #[cfg(any(feature = "runtime-benchmarks", test))] fn put_snapshot( - _voters: Vec<(Self::AccountId, VoteWeight, Vec)>, + _voters: Vec>, _targets: Vec, _target_stake: Option, ) { @@ -244,7 +243,12 @@ pub trait ElectionDataProvider { /// /// Same as `put_snapshot`, but can add a single voter one by one. #[cfg(any(feature = "runtime-benchmarks", test))] - fn add_voter(_voter: Self::AccountId, _weight: VoteWeight, _targets: Vec) {} + fn add_voter( + _voter: Self::AccountId, + _weight: VoteWeight, + _targets: BoundedVec, + ) { + } /// Utility function only to be used in benchmarking scenarios, to be implemented optionally, /// else a noop. @@ -266,19 +270,20 @@ pub struct TestDataProvider(sp_std::marker::PhantomData); impl ElectionDataProvider for TestDataProvider<(AccountId, BlockNumber)> { type AccountId = AccountId; type BlockNumber = BlockNumber; + type MaxVotesPerVoter = (); - const MAXIMUM_VOTES_PER_VOTER: u32 = 0; fn targets(_maybe_max_len: Option) -> data_provider::Result> { Ok(Default::default()) } - fn voters( - _maybe_max_len: Option, - ) -> data_provider::Result)>> { + + fn voters(_maybe_max_len: Option) -> data_provider::Result>> { Ok(Default::default()) } + fn desired_targets() -> data_provider::Result { Ok(Default::default()) } + fn next_election_prediction(now: BlockNumber) -> BlockNumber { now } @@ -421,7 +426,7 @@ pub trait NposSolver { fn solve( to_elect: usize, targets: Vec, - voters: Vec<(Self::AccountId, VoteWeight, Vec)>, + voters: Vec<(Self::AccountId, VoteWeight, impl IntoIterator)>, ) -> Result, Self::Error>; } @@ -443,7 +448,7 @@ impl< fn solve( winners: usize, targets: Vec, - voters: Vec<(Self::AccountId, VoteWeight, Vec)>, + voters: Vec<(Self::AccountId, VoteWeight, impl IntoIterator)>, ) -> Result, Self::Error> { sp_npos_elections::seq_phragmen(winners, targets, voters, Balancing::get()) } @@ -467,8 +472,15 @@ impl< fn solve( winners: usize, targets: Vec, - voters: Vec<(Self::AccountId, VoteWeight, Vec)>, + voters: Vec<(Self::AccountId, VoteWeight, impl IntoIterator)>, ) -> Result, Self::Error> { sp_npos_elections::phragmms(winners, targets, voters, Balancing::get()) } } + +/// A voter, at the level of abstraction of this crate. +pub type Voter = (AccountId, VoteWeight, BoundedVec); + +/// Same as [`Voter`], but parameterized by an [`ElectionDataProvider`]. +pub type VoterOf = + Voter<::AccountId, ::MaxVotesPerVoter>; diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index d325daf514757..808b49ba6234d 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -87,9 +87,8 @@ impl ElectionProvider for OnChainSequentialPhragmen { let stake_of = |w: &T::AccountId| -> VoteWeight { stake_map.get(w).cloned().unwrap_or_default() }; - let ElectionResult { winners: _, assignments } = - seq_phragmen::<_, T::Accuracy>(desired_targets as usize, targets, voters, None) - .map_err(Error::from)?; + let ElectionResult::<_, T::Accuracy> { winners: _, assignments } = + seq_phragmen(desired_targets as usize, targets, voters, None).map_err(Error::from)?; let staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?; @@ -161,18 +160,22 @@ mod tests { type OnChainPhragmen = OnChainSequentialPhragmen; mod mock_data_provider { + use frame_support::{bounded_vec, traits::ConstU32}; + use super::*; - use crate::data_provider; + use crate::{data_provider, VoterOf}; pub struct DataProvider; impl ElectionDataProvider for DataProvider { type AccountId = AccountId; type BlockNumber = BlockNumber; - const MAXIMUM_VOTES_PER_VOTER: u32 = 2; - fn voters( - _: Option, - ) -> data_provider::Result)>> { - Ok(vec![(1, 10, vec![10, 20]), (2, 20, vec![30, 20]), (3, 30, vec![10, 30])]) + type MaxVotesPerVoter = ConstU32<2>; + fn voters(_: Option) -> data_provider::Result>> { + Ok(vec![ + (1, 10, bounded_vec![10, 20]), + (2, 20, bounded_vec![30, 20]), + (3, 30, bounded_vec![10, 30]), + ]) } fn targets(_: Option) -> data_provider::Result> { diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 2c53bb2222b76..bc6a81125e8bd 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -926,13 +926,13 @@ impl Pallet { let weight_candidates = candidates_and_deposit.len() as u32; let weight_voters = voters_and_votes.len() as u32; let weight_edges = num_edges; - let _ = sp_npos_elections::seq_phragmen::( + let _ = sp_npos_elections::seq_phragmen( num_to_elect, candidate_ids, voters_and_votes.clone(), None, ) - .map(|ElectionResult { winners, assignments: _ }| { + .map(|ElectionResult:: { winners, assignments: _ }| { // this is already sorted by id. let old_members_ids_sorted = >::take().into_iter().map(|m| m.who).collect::>(); diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 34787c93bb9ce..d07f3136d9a0d 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -186,7 +186,7 @@ impl onchain::Config for Test { } impl pallet_staking::Config for Test { - const MAX_NOMINATIONS: u32 = 16; + type MaxNominations = ConstU32<16>; type RewardRemainder = (); type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type Event = Event; diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 4d6a182034c9e..c2e29f0d0fdd3 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -24,7 +24,7 @@ mod mock; use sp_std::{prelude::*, vec}; use frame_benchmarking::{account, benchmarks}; -use frame_support::traits::{Currency, ValidatorSet, ValidatorSetWithIdentification}; +use frame_support::traits::{Currency, Get, ValidatorSet, ValidatorSetWithIdentification}; use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; use sp_runtime::{ @@ -275,7 +275,7 @@ benchmarks! { let r in 1 .. MAX_REPORTERS; // we skip 1 offender, because in such case there is no slashing let o in 2 .. MAX_OFFENDERS; - let n in 0 .. MAX_NOMINATORS.min(::MAX_NOMINATIONS); + let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); // Make r reporters let mut reporters = vec![]; @@ -381,7 +381,7 @@ benchmarks! { } report_offence_grandpa { - let n in 0 .. MAX_NOMINATORS.min(::MAX_NOMINATIONS); + let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); // for grandpa equivocation reports the number of reporters // and offenders is always 1 @@ -416,7 +416,7 @@ benchmarks! { } report_offence_babe { - let n in 0 .. MAX_NOMINATORS.min(::MAX_NOMINATIONS); + let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); // for babe equivocation reports the number of reporters // and offenders is always 1 diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 598ba650dfffb..3b5e640867c5a 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -156,7 +156,7 @@ impl onchain::Config for Test { } impl pallet_staking::Config for Test { - const MAX_NOMINATIONS: u32 = 16; + type MaxNominations = ConstU32<16>; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index 7beb4631e0518..265c35cbe4908 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -28,7 +28,7 @@ use sp_std::{prelude::*, vec}; use frame_benchmarking::benchmarks; use frame_support::{ codec::Decode, - traits::{KeyOwnerProofSystem, OnInitialize}, + traits::{Get, KeyOwnerProofSystem, OnInitialize}, }; use frame_system::RawOrigin; use pallet_session::{historical::Pallet as Historical, Pallet as Session, *}; @@ -53,10 +53,10 @@ impl OnInitialize for Pallet { benchmarks! { set_keys { - let n = ::MAX_NOMINATIONS; + let n = ::MaxNominations::get(); let (v_stash, _) = create_validator_with_nominators::( n, - ::MAX_NOMINATIONS, + ::MaxNominations::get(), false, RewardDestination::Staked, )?; @@ -70,10 +70,10 @@ benchmarks! { }: _(RawOrigin::Signed(v_controller), keys, proof) purge_keys { - let n = ::MAX_NOMINATIONS; + let n = ::MaxNominations::get(); let (v_stash, _) = create_validator_with_nominators::( n, - ::MAX_NOMINATIONS, + ::MaxNominations::get(), false, RewardDestination::Staked )?; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 1f00236605130..37305437ca095 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -162,7 +162,7 @@ impl onchain::Config for Test { } impl pallet_staking::Config for Test { - const MAX_NOMINATIONS: u32 = 16; + type MaxNominations = ConstU32<16>; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 8328adc00a978..564172d912413 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -355,17 +355,17 @@ benchmarks! { kick { // scenario: we want to kick `k` nominators from nominating us (we are a validator). // we'll assume that `k` is under 128 for the purposes of determining the slope. - // each nominator should have `T::MAX_NOMINATIONS` validators nominated, and our validator + // each nominator should have `T::MaxNominations::get()` validators nominated, and our validator // should be somewhere in there. let k in 1 .. 128; - // these are the other validators; there are `T::MAX_NOMINATIONS - 1` of them, so - // there are a total of `T::MAX_NOMINATIONS` validators in the system. - let rest_of_validators = create_validators_with_seed::(T::MAX_NOMINATIONS - 1, 100, 415)?; + // these are the other validators; there are `T::MaxNominations::get() - 1` of them, so + // there are a total of `T::MaxNominations::get()` validators in the system. + let rest_of_validators = create_validators_with_seed::(T::MaxNominations::get() - 1, 100, 415)?; // this is the validator that will be kicking. let (stash, controller) = create_stash_controller::( - T::MAX_NOMINATIONS - 1, + T::MaxNominations::get() - 1, 100, Default::default(), )?; @@ -380,7 +380,7 @@ benchmarks! { for i in 0 .. k { // create a nominator stash. let (n_stash, n_controller) = create_stash_controller::( - T::MAX_NOMINATIONS + i, + T::MaxNominations::get() + i, 100, Default::default(), )?; @@ -415,9 +415,9 @@ benchmarks! { } } - // Worst case scenario, T::MAX_NOMINATIONS + // Worst case scenario, T::MaxNominations::get() nominate { - let n in 1 .. T::MAX_NOMINATIONS; + let n in 1 .. T::MaxNominations::get(); // clean up any existing state. clear_validators_and_nominators::(); @@ -428,7 +428,7 @@ benchmarks! { // we are just doing an insert into the origin position. let scenario = ListScenario::::new(origin_weight, true)?; let (stash, controller) = create_stash_controller_with_balance::( - SEED + T::MAX_NOMINATIONS + 1, // make sure the account does not conflict with others + SEED + T::MaxNominations::get() + 1, // make sure the account does not conflict with others origin_weight, Default::default(), ).unwrap(); @@ -724,7 +724,7 @@ benchmarks! { create_validators_with_nominators_for_era::( v, n, - ::MAX_NOMINATIONS as usize, + ::MaxNominations::get() as usize, false, None, )?; @@ -742,7 +742,7 @@ benchmarks! { create_validators_with_nominators_for_era::( v, n, - ::MAX_NOMINATIONS as usize, + ::MaxNominations::get() as usize, false, None, )?; @@ -822,7 +822,7 @@ benchmarks! { let s in 1 .. 20; let validators = create_validators_with_nominators_for_era::( - v, n, T::MAX_NOMINATIONS as usize, false, None + v, n, T::MaxNominations::get() as usize, false, None )? .into_iter() .map(|v| T::Lookup::lookup(v).unwrap()) @@ -845,7 +845,7 @@ benchmarks! { let n = MaxNominators::::get(); let _ = create_validators_with_nominators_for_era::( - v, n, T::MAX_NOMINATIONS as usize, false, None + v, n, T::MaxNominations::get() as usize, false, None )?; }: { let targets = >::get_npos_targets(); @@ -923,7 +923,7 @@ mod tests { create_validators_with_nominators_for_era::( v, n, - ::MAX_NOMINATIONS as usize, + ::MaxNominations::get() as usize, false, None, ) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index efe67c8b00c85..f1d4cd1e07c2a 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -303,6 +303,7 @@ use codec::{Decode, Encode, HasCompact}; use frame_support::{ traits::{ConstU32, Currency, Get}, weights::Weight, + BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -574,10 +575,12 @@ where } /// A record of the nominations made by a specific account. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct Nominations { +#[derive(PartialEqNoBound, EqNoBound, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo)] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub struct Nominations { /// The targets of nomination. - pub targets: Vec, + pub targets: BoundedVec, /// The era the nominations were submitted. /// /// Except for initial nominations which are considered submitted at era 0. diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 3bf46588044a6..95f305dfdd22a 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -234,6 +234,7 @@ const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; + pub static MaxNominations: u32 = 16; } impl pallet_bags_list::Config for Test { @@ -249,7 +250,7 @@ impl onchain::Config for Test { } impl crate::pallet::pallet::Config for Test { - const MAX_NOMINATIONS: u32 = 16; + type MaxNominations = MaxNominations; type Currency = Balances; type UnixTime = Timestamp; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; @@ -533,7 +534,7 @@ fn post_conditions() { } fn check_count() { - let nominator_count = Nominators::::iter().count() as u32; + let nominator_count = Nominators::::iter_keys().count() as u32; let validator_count = Validators::::iter().count() as u32; assert_eq!(nominator_count, Nominators::::count()); assert_eq!(validator_count, Validators::::count()); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index a72d2774dee2a..ae20550cd40b6 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -19,7 +19,7 @@ use frame_election_provider_support::{ data_provider, ElectionDataProvider, ElectionProvider, SortedListProvider, Supports, - VoteWeight, VoteWeightProvider, + VoteWeight, VoteWeightProvider, VoterOf, }; use frame_support::{ pallet_prelude::*, @@ -661,9 +661,7 @@ impl Pallet { /// /// All nominations that have been submitted before the last non-zero slash of the validator are /// auto-chilled, but still count towards the limit imposed by `maybe_max_len`. - pub fn get_npos_voters( - maybe_max_len: Option, - ) -> Vec<(T::AccountId, VoteWeight, Vec)> { + pub fn get_npos_voters(maybe_max_len: Option) -> Vec> { let max_allowed_len = { let nominator_count = Nominators::::count() as usize; let validator_count = Validators::::count() as usize; @@ -677,8 +675,13 @@ impl Pallet { let mut validators_taken = 0u32; for (validator, _) in >::iter().take(max_allowed_len) { // Append self vote. - let self_vote = - (validator.clone(), Self::weight_of(&validator), vec![validator.clone()]); + let self_vote = ( + validator.clone(), + Self::weight_of(&validator), + vec![validator.clone()] + .try_into() + .expect("`MaxVotesPerVoter` must be greater than or equal to 1"), + ); all_voters.push(self_vote); validators_taken.saturating_inc(); } @@ -724,7 +727,12 @@ impl Pallet { nominators_taken.saturating_inc(); } } else { - log!(error, "DEFENSIVE: invalid item in `SortedListProvider`: {:?}", nominator) + // this can only happen if: 1. there a pretty bad bug in the bags-list (or whatever + // is the sorted list) logic and the state of the two pallets is no longer + // compatible, or because the nominators is not decodable since they have more + // nomination than `T::MaxNominations`. This can rarely happen, and is not really an + // emergency or bug if it does. + log!(warn, "DEFENSIVE: invalid item in `SortedListProvider`: {:?}, this nominator probably has too many nominations now", nominator) } } @@ -772,7 +780,7 @@ impl Pallet { /// NOTE: you must ALWAYS use this function to add nominator or update their targets. Any access /// to `Nominators` or `VoterList` outside of this function is almost certainly /// wrong. - pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { + pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { if !Nominators::::contains_key(who) { // maybe update sorted list. Error checking is defensive-only - this should never fail. let _ = T::SortedListProvider::on_insert(who.clone(), Self::weight_of(who)) @@ -845,16 +853,14 @@ impl Pallet { impl ElectionDataProvider for Pallet { type AccountId = T::AccountId; type BlockNumber = BlockNumberFor; - const MAXIMUM_VOTES_PER_VOTER: u32 = T::MAX_NOMINATIONS; + type MaxVotesPerVoter = T::MaxNominations; fn desired_targets() -> data_provider::Result { Self::register_weight(T::DbWeight::get().reads(1)); Ok(Self::validator_count()) } - fn voters( - maybe_max_len: Option, - ) -> data_provider::Result)>> { + fn voters(maybe_max_len: Option) -> data_provider::Result>> { // This can never fail -- if `maybe_max_len` is `Some(_)` we handle it. let voters = Self::get_npos_voters(maybe_max_len); debug_assert!(maybe_max_len.map_or(true, |max| voters.len() <= max)); @@ -907,7 +913,11 @@ impl ElectionDataProvider for Pallet { } #[cfg(feature = "runtime-benchmarks")] - fn add_voter(voter: T::AccountId, weight: VoteWeight, targets: Vec) { + fn add_voter( + voter: T::AccountId, + weight: VoteWeight, + targets: BoundedVec, + ) { let stake = >::try_from(weight).unwrap_or_else(|_| { panic!("cannot convert a VoteWeight into BalanceOf, benchmark needs reconfiguring.") }); @@ -922,6 +932,7 @@ impl ElectionDataProvider for Pallet { claimed_rewards: vec![], }, ); + Self::do_add_nominator(&voter, Nominations { targets, submitted_in: 0, suppressed: false }); } @@ -957,7 +968,7 @@ impl ElectionDataProvider for Pallet { #[cfg(feature = "runtime-benchmarks")] fn put_snapshot( - voters: Vec<(T::AccountId, VoteWeight, Vec)>, + voters: Vec>, targets: Vec, target_stake: Option, ) { @@ -999,7 +1010,7 @@ impl ElectionDataProvider for Pallet { ); Self::do_add_nominator( &v, - Nominations { targets: t, submitted_in: 0, suppressed: false }, + Nominations { targets: t.try_into().unwrap(), submitted_in: 0, suppressed: false }, ); }); } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 20864e4829e66..2a870fda063d3 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -32,7 +32,7 @@ use sp_runtime::{ DispatchError, Perbill, Percent, }; use sp_staking::{EraIndex, SessionIndex}; -use sp_std::{convert::From, prelude::*, result}; +use sp_std::{convert::From, prelude::*}; mod impls; @@ -50,6 +50,8 @@ const STAKING_ID: LockIdentifier = *b"staking "; #[frame_support::pallet] pub mod pallet { + use frame_election_provider_support::ElectionDataProvider; + use crate::BenchmarkingConfig; use super::*; @@ -94,7 +96,7 @@ pub mod pallet { >; /// Maximum number of nominations per nominator. - const MAX_NOMINATIONS: u32; + type MaxNominations: Get; /// Tokens have been minted and are unused for validator-reward. /// See [Era payout](./index.html#era-payout). @@ -161,15 +163,6 @@ pub mod pallet { type WeightInfo: WeightInfo; } - #[pallet::extra_constants] - impl Pallet { - // TODO: rename to snake case after https://github.com/paritytech/substrate/issues/8826 fixed. - #[allow(non_snake_case)] - fn MaxNominations() -> u32 { - T::MAX_NOMINATIONS - } - } - #[pallet::type_value] pub(crate) fn HistoryDepthOnEmpty() -> u32 { 84u32 @@ -246,11 +239,26 @@ pub mod pallet { #[pallet::storage] pub type MaxValidatorsCount = StorageValue<_, u32, OptionQuery>; - /// The map from nominator stash key to the set of stash keys of all validators to nominate. + /// The map from nominator stash key to their nomination preferences, namely the validators that + /// they wish to support. + /// + /// Note that the keys of this storage map might become non-decodable in case the + /// [`Config::MaxNominations`] configuration is decreased. In this rare case, these nominators + /// are still existent in storage, their key is correct and retrievable (i.e. `contains_key` + /// indicates that they exist), but their value cannot be decoded. Therefore, the non-decodable + /// nominators will effectively not-exist, until they re-submit their preferences such that it + /// is within the bounds of the newly set `Config::MaxNominations`. + /// + /// This implies that `::iter_keys().count()` and `::iter().count()` might return different + /// values for this map. Moreover, the main `::count()` is aligned with the former, namely the + /// number of keys that exist. + /// + /// Lastly, if any of the nominators become non-decodable, they can be chilled immediately via + /// [`Call::chill_other`] dispatchable by anyone. #[pallet::storage] #[pallet::getter(fn nominators)] pub type Nominators = - CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations>; + CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations>; /// The maximum nominator count before we stop allowing new validators to join. /// @@ -681,6 +689,14 @@ pub mod pallet { } fn integrity_test() { + // ensure that we funnel the correct value to the `DataProvider::MaxVotesPerVoter`; + assert_eq!( + T::MaxNominations::get(), + ::MaxVotesPerVoter::get() + ); + // and that MaxNominations is always greater than 1, since we count on this. + assert!(!T::MaxNominations::get().is_zero()); + sp_std::if_std! { sp_io::TestExternalities::new_empty().execute_with(|| assert!( @@ -978,7 +994,7 @@ pub mod pallet { /// /// # /// - The transaction's complexity is proportional to the size of `targets` (N) - /// which is capped at CompactAssignments::LIMIT (MAX_NOMINATIONS). + /// which is capped at CompactAssignments::LIMIT (T::MaxNominations). /// - Both the reads and writes follow a similar pattern. /// # #[pallet::weight(T::WeightInfo::nominate(targets.len() as u32))] @@ -1006,11 +1022,11 @@ pub mod pallet { } ensure!(!targets.is_empty(), Error::::EmptyTargets); - ensure!(targets.len() <= T::MAX_NOMINATIONS as usize, Error::::TooManyTargets); + ensure!(targets.len() <= T::MaxNominations::get() as usize, Error::::TooManyTargets); - let old = Nominators::::get(stash).map_or_else(Vec::new, |x| x.targets); + let old = Nominators::::get(stash).map_or_else(Vec::new, |x| x.targets.into_inner()); - let targets = targets + let targets: BoundedVec<_, _> = targets .into_iter() .map(|t| T::Lookup::lookup(t).map_err(DispatchError::from)) .map(|n| { @@ -1022,11 +1038,13 @@ pub mod pallet { } }) }) - .collect::, _>>()?; + .collect::, _>>()? + .try_into() + .map_err(|_| Error::::TooManyNominators)?; let nominations = Nominations { targets, - // Initial nominations are considered submitted at era 0. See `Nominations` doc + // Initial nominations are considered submitted at era 0. See `Nominations` doc. submitted_in: Self::current_era().unwrap_or(0), suppressed: false, }; @@ -1216,11 +1234,6 @@ pub mod pallet { /// Set the validators who cannot be slashed (if any). /// /// The dispatch origin must be Root. - /// - /// # - /// - O(V) - /// - Write: Invulnerables - /// # #[pallet::weight(T::WeightInfo::set_invulnerables(invulnerables.len() as u32))] pub fn set_invulnerables( origin: OriginFor, @@ -1234,13 +1247,6 @@ pub mod pallet { /// Force a current staker to become completely unstaked, immediately. /// /// The dispatch origin must be Root. - /// - /// # - /// O(S) where S is the number of slashing spans to be removed - /// Reads: Bonded, Slashing Spans, Account, Locks - /// Writes: Bonded, Slashing Spans (if S > 0), Ledger, Payee, Validators, Nominators, - /// Account, Locks Writes Each: SpanSlash * S - /// # #[pallet::weight(T::WeightInfo::force_unstake(*num_slashing_spans))] pub fn force_unstake( origin: OriginFor, @@ -1266,11 +1272,6 @@ pub mod pallet { /// The election process starts multiple blocks before the end of the era. /// If this is called just before a new era is triggered, the election process may not /// have enough blocks to get a result. - /// - /// # - /// - Weight: O(1) - /// - Write: ForceEra - /// # #[pallet::weight(T::WeightInfo::force_new_era_always())] pub fn force_new_era_always(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; @@ -1283,14 +1284,6 @@ pub mod pallet { /// Can be called by the `T::SlashCancelOrigin`. /// /// Parameters: era and indices of the slashes for that era to kill. - /// - /// # - /// Complexity: O(U + S) - /// with U unapplied slashes weighted with U=1000 - /// and S is the number of slash indices to be canceled. - /// - Read: Unapplied Slashes - /// - Write: Unapplied Slashes - /// # #[pallet::weight(T::WeightInfo::cancel_deferred_slash(slash_indices.len() as u32))] pub fn cancel_deferred_slash( origin: OriginFor, @@ -1550,6 +1543,11 @@ pub mod pallet { /// /// If the caller is different than the controller being targeted, the following conditions /// must be met: + /// + /// * `controller` must belong to a nominator who has become non-decodable, + /// + /// Or: + /// /// * A `ChillThreshold` must be set and checked which defines how close to the max /// nominators or validators we must reach before users can start chilling one-another. /// * A `MaxNominatorCount` and `MaxValidatorCount` must be set which is used to determine @@ -1568,6 +1566,11 @@ pub mod pallet { let stash = ledger.stash; // In order for one user to chill another user, the following conditions must be met: + // + // * `controller` belongs to a nominator who has become non-decodable, + // + // Or + // // * A `ChillThreshold` is set which defines how close to the max nominators or // validators we must reach before users can start chilling one-another. // * A `MaxNominatorCount` and `MaxValidatorCount` which is used to determine how close @@ -1577,6 +1580,12 @@ pub mod pallet { // threshold bond required. // // Otherwise, if caller is the same as the controller, this is just like `chill`. + + if Nominators::::contains_key(&stash) && Nominators::::get(&stash).is_none() { + Self::chill_stash(&stash); + return Ok(()) + } + if caller != controller { let threshold = ChillThreshold::::get().ok_or(Error::::CannotChillOther)?; let min_active_bond = if Nominators::::contains_key(&stash) { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 8d465c8c93dc4..538b75ead340b 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4248,7 +4248,11 @@ fn count_check_works() { Validators::::insert(987654321, ValidatorPrefs::default()); Nominators::::insert( 987654321, - Nominations { targets: vec![], submitted_in: Default::default(), suppressed: false }, + Nominations { + targets: Default::default(), + submitted_in: Default::default(), + suppressed: false, + }, ); }) } @@ -4589,6 +4593,100 @@ fn min_commission_works() { }) } +#[test] +fn change_of_max_nominations() { + use frame_election_provider_support::ElectionDataProvider; + ExtBuilder::default() + .add_staker(60, 61, 10, StakerStatus::Nominator(vec![1])) + .add_staker(70, 71, 10, StakerStatus::Nominator(vec![1, 2, 3])) + .balance_factor(10) + .build_and_execute(|| { + // pre-condition + assert_eq!(MaxNominations::get(), 16); + + assert_eq!( + Nominators::::iter() + .map(|(k, n)| (k, n.targets.len())) + .collect::>(), + vec![(70, 3), (101, 2), (60, 1)] + ); + // 3 validators and 3 nominators + assert_eq!(Staking::voters(None).unwrap().len(), 3 + 3); + + // abrupt change from 16 to 4, everyone should be fine. + MaxNominations::set(4); + + assert_eq!( + Nominators::::iter() + .map(|(k, n)| (k, n.targets.len())) + .collect::>(), + vec![(70, 3), (101, 2), (60, 1)] + ); + assert_eq!(Staking::voters(None).unwrap().len(), 3 + 3); + + // abrupt change from 4 to 3, everyone should be fine. + MaxNominations::set(3); + + assert_eq!( + Nominators::::iter() + .map(|(k, n)| (k, n.targets.len())) + .collect::>(), + vec![(70, 3), (101, 2), (60, 1)] + ); + assert_eq!(Staking::voters(None).unwrap().len(), 3 + 3); + + // abrupt change from 3 to 2, this should cause some nominators to be non-decodable, and + // thus non-existent unless if they update. + MaxNominations::set(2); + + assert_eq!( + Nominators::::iter() + .map(|(k, n)| (k, n.targets.len())) + .collect::>(), + vec![(101, 2), (60, 1)] + ); + // 70 is still in storage.. + assert!(Nominators::::contains_key(70)); + // but its value cannot be decoded and default is returned. + assert!(Nominators::::get(70).is_none()); + + assert_eq!(Staking::voters(None).unwrap().len(), 3 + 2); + assert!(Nominators::::contains_key(101)); + + // abrupt change from 2 to 1, this should cause some nominators to be non-decodable, and + // thus non-existent unless if they update. + MaxNominations::set(1); + + assert_eq!( + Nominators::::iter() + .map(|(k, n)| (k, n.targets.len())) + .collect::>(), + vec![(60, 1)] + ); + assert!(Nominators::::contains_key(70)); + assert!(Nominators::::contains_key(60)); + assert!(Nominators::::get(70).is_none()); + assert!(Nominators::::get(60).is_some()); + assert_eq!(Staking::voters(None).unwrap().len(), 3 + 1); + + // now one of them can revive themselves by re-nominating to a proper value. + assert_ok!(Staking::nominate(Origin::signed(71), vec![1])); + assert_eq!( + Nominators::::iter() + .map(|(k, n)| (k, n.targets.len())) + .collect::>(), + vec![(70, 1), (60, 1)] + ); + + // or they can be chilled by any account. + assert!(Nominators::::contains_key(101)); + assert!(Nominators::::get(101).is_none()); + assert_ok!(Staking::chill_other(Origin::signed(70), 100)); + assert!(!Nominators::::contains_key(101)); + assert!(Nominators::::get(101).is_none()); + }) +} + mod sorted_list_provider { use super::*; use frame_election_provider_support::SortedListProvider; diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index fc2754c5c555f..ef60729f6d861 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -114,6 +114,29 @@ impl TypeId for PalletId { const TYPE_ID: [u8; 4] = *b"modl"; } +/// Build a bounded vec from the given literals. +/// +/// The type of the outcome must be known. +/// +/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding +/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. +#[macro_export] +#[cfg(feature = "std")] +macro_rules! bounded_vec { + ($ ($values:expr),* ) => { + { + use $crate::sp_std::convert::TryInto as _; + $crate::sp_std::vec![$($values),*].try_into().unwrap() + } + }; + ( $value:expr ; $repetition:expr ) => { + { + use $crate::sp_std::convert::TryInto as _; + $crate::sp_std::vec![$value ; $repetition].try_into().unwrap() + } + } +} + /// Generate a new type alias for [`storage::types::StorageValue`], /// [`storage::types::StorageMap`], [`storage::types::StorageDoubleMap`] /// and [`storage::types::StorageNMap`]. diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 6b20ed2bba90f..9298a5d98b003 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -664,6 +664,19 @@ pub mod test { assert_eq!(*bounded, vec![1, 0, 2, 3]); } + #[test] + fn constructor_macro_works() { + use frame_support::bounded_vec; + + // With values. Use some brackets to make sure the macro doesn't expand. + let bv: BoundedVec<(u32, u32), ConstU32<3>> = bounded_vec![(1, 2), (1, 2), (1, 2)]; + assert_eq!(bv, vec![(1, 2), (1, 2), (1, 2)]); + + // With repetition. + let bv: BoundedVec<(u32, u32), ConstU32<3>> = bounded_vec![(1, 2); 3]; + assert_eq!(bv, vec![(1, 2), (1, 2), (1, 2)]); + } + #[test] #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] fn try_inert_panics_if_oob() { diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 0f98b13282a74..7f53b196c8151 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -401,6 +401,13 @@ where ) -> crate::storage::PrefixIterator<(Key, Value), OnRemovalCounterUpdate> { ::Map::iter_from(starting_raw_key).convert_on_removal() } + + /// Enumerate all keys in the counted map. + /// + /// If you alter the map while doing this, you'll get undefined results. + pub fn iter_keys() -> crate::storage::KeyPrefixIterator { + ::Map::iter_keys() + } } impl StorageEntryMetadataBuilder diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 800ffbfd20dc2..878edd7840e74 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -479,11 +479,6 @@ pub mod pallet { } /// Make some on-chain remark and emit event. - /// - /// # - /// - `O(b)` where b is the length of the remark. - /// - 1 event. - /// # #[pallet::weight(T::SystemWeightInfo::remark_with_event(remark.len() as u32))] pub fn remark_with_event( origin: OriginFor, diff --git a/primitives/npos-elections/fuzzer/src/common.rs b/primitives/npos-elections/fuzzer/src/common.rs index ab765d20640e2..1bef899d5e54c 100644 --- a/primitives/npos-elections/fuzzer/src/common.rs +++ b/primitives/npos-elections/fuzzer/src/common.rs @@ -158,20 +158,10 @@ pub fn generate_random_npos_result( ( match election_type { - ElectionType::Phragmen(conf) => seq_phragmen::( - to_elect, - candidates.clone(), - voters.clone(), - conf, - ) - .unwrap(), - ElectionType::Phragmms(conf) => phragmms::( - to_elect, - candidates.clone(), - voters.clone(), - conf, - ) - .unwrap(), + ElectionType::Phragmen(conf) => + seq_phragmen(to_elect, candidates.clone(), voters.clone(), conf).unwrap(), + ElectionType::Phragmms(conf) => + phragmms(to_elect, candidates.clone(), voters.clone(), conf).unwrap(), }, candidates, voters, diff --git a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs index 2af6a4c0f8151..8f782405df527 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs @@ -24,7 +24,7 @@ use honggfuzz::fuzz; use rand::{self, SeedableRng}; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, is_score_better, seq_phragmen, to_supports, - EvaluateSupport, VoteWeight, + ElectionResult, EvaluateSupport, VoteWeight, }; use sp_runtime::Perbill; @@ -68,13 +68,8 @@ fn main() { }; if iterations > 0 { - let balanced = seq_phragmen::( - to_elect, - candidates, - voters, - Some((iterations, 0)), - ) - .unwrap(); + let balanced: ElectionResult = + seq_phragmen(to_elect, candidates, voters, Some((iterations, 0))).unwrap(); let balanced_score = { let staked = assignment_ratio_to_staked_normalized( diff --git a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs index 0cd49c3f80442..f2b12b137883c 100644 --- a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs @@ -23,8 +23,8 @@ use common::*; use honggfuzz::fuzz; use rand::{self, SeedableRng}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, is_score_better, phragmms, to_supports, EvaluateSupport, - VoteWeight, + assignment_ratio_to_staked_normalized, is_score_better, phragmms, to_supports, ElectionResult, + EvaluateSupport, VoteWeight, }; use sp_runtime::Perbill; @@ -67,13 +67,8 @@ fn main() { score }; - let balanced = phragmms::( - to_elect, - candidates, - voters, - Some((iterations, 0)), - ) - .unwrap(); + let balanced: ElectionResult = + phragmms(to_elect, candidates, voters, Some((iterations, 0))).unwrap(); let balanced_score = { let staked = diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index bb1c38d3077c4..7b3b09a4c7346 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -471,7 +471,7 @@ pub fn is_score_better(this: ElectionScore, that: ElectionScore, ep /// - It drops duplicate targets within a voter. pub fn setup_inputs( initial_candidates: Vec, - initial_voters: Vec<(AccountId, VoteWeight, Vec)>, + initial_voters: Vec<(AccountId, VoteWeight, impl IntoIterator)>, ) -> (Vec>, Vec>) { // used to cache and access candidates index. let mut c_idx_cache = BTreeMap::::new(); @@ -496,7 +496,7 @@ pub fn setup_inputs( let voters = initial_voters .into_iter() .filter_map(|(who, voter_stake, votes)| { - let mut edges: Vec> = Vec::with_capacity(votes.len()); + let mut edges: Vec> = Vec::new(); for v in votes { if edges.iter().any(|e| e.who == v) { // duplicate edge. diff --git a/primitives/npos-elections/src/mock.rs b/primitives/npos-elections/src/mock.rs index 8e8e7ebc1c0c6..85c970d7b418f 100644 --- a/primitives/npos-elections/src/mock.rs +++ b/primitives/npos-elections/src/mock.rs @@ -344,7 +344,7 @@ pub(crate) fn run_and_compare( FS: Fn(&AccountId) -> VoteWeight, { // run fixed point code. - let ElectionResult { winners, assignments } = seq_phragmen::<_, Output>( + let ElectionResult::<_, Output> { winners, assignments } = seq_phragmen( to_elect, candidates.clone(), voters diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index c582c5910d69a..e8e925935f774 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -70,7 +70,7 @@ const DEN: ExtendedBalance = ExtendedBalance::max_value(); pub fn seq_phragmen( to_elect: usize, candidates: Vec, - voters: Vec<(AccountId, VoteWeight, Vec)>, + voters: Vec<(AccountId, VoteWeight, impl IntoIterator)>, balancing: Option<(usize, ExtendedBalance)>, ) -> Result, crate::Error> { let (candidates, voters) = setup_inputs(candidates, voters); diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index 7c51da9ee92e0..6220cacd157b2 100644 --- a/primitives/npos-elections/src/phragmms.rs +++ b/primitives/npos-elections/src/phragmms.rs @@ -44,7 +44,7 @@ use sp_std::{prelude::*, rc::Rc}; pub fn phragmms( to_elect: usize, candidates: Vec, - voters: Vec<(AccountId, VoteWeight, Vec)>, + voters: Vec<(AccountId, VoteWeight, impl IntoIterator)>, balancing: Option<(usize, ExtendedBalance)>, ) -> Result, crate::Error> { let (candidates, mut voters) = setup_inputs(candidates, voters); @@ -351,8 +351,8 @@ mod tests { let candidates = vec![1, 2, 3]; let voters = vec![(10, 10, vec![1, 2]), (20, 20, vec![1, 3]), (30, 30, vec![2, 3])]; - let ElectionResult { winners, assignments } = - phragmms::<_, Perbill>(2, candidates, voters, Some((2, 0))).unwrap(); + let ElectionResult::<_, Perbill> { winners, assignments } = + phragmms(2, candidates, voters, Some((2, 0))).unwrap(); assert_eq!(winners, vec![(3, 30), (2, 30)]); assert_eq!( assignments, @@ -383,8 +383,8 @@ mod tests { (130, 1000, vec![61, 71]), ]; - let ElectionResult { winners, assignments: _ } = - phragmms::<_, Perbill>(4, candidates, voters, Some((2, 0))).unwrap(); + let ElectionResult::<_, Perbill> { winners, assignments: _ } = + phragmms(4, candidates, voters, Some((2, 0))).unwrap(); assert_eq!(winners, vec![(11, 3000), (31, 2000), (51, 1500), (61, 1500),]); } @@ -396,8 +396,8 @@ mod tests { // give a bit more to 1 and 3. voters.push((2, u64::MAX, vec![1, 3])); - let ElectionResult { winners, assignments: _ } = - phragmms::<_, Perbill>(2, candidates, voters, Some((2, 0))).unwrap(); + let ElectionResult::<_, Perbill> { winners, assignments: _ } = + phragmms(2, candidates, voters, Some((2, 0))).unwrap(); assert_eq!(winners.into_iter().map(|(w, _)| w).collect::>(), vec![1u32, 3]); } } diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index e7d0078b1fbe0..c6748b29e9851 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -230,7 +230,7 @@ fn phragmen_poc_works() { let voters = vec![(10, vec![1, 2]), (20, vec![1, 3]), (30, vec![2, 3])]; let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30)]); - let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>( + let ElectionResult::<_, Perbill> { winners, assignments } = seq_phragmen( 2, candidates, voters @@ -285,7 +285,7 @@ fn phragmen_poc_works_with_balancing() { let voters = vec![(10, vec![1, 2]), (20, vec![1, 3]), (30, vec![2, 3])]; let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30)]); - let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>( + let ElectionResult::<_, Perbill> { winners, assignments } = seq_phragmen( 2, candidates, voters @@ -372,7 +372,7 @@ fn phragmen_accuracy_on_large_scale_only_candidates() { (5, (u64::MAX - 2).into()), ]); - let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>( + let ElectionResult::<_, Perbill> { winners, assignments } = seq_phragmen( 2, candidates.clone(), auto_generate_self_voters(&candidates) @@ -403,7 +403,7 @@ fn phragmen_accuracy_on_large_scale_voters_and_candidates() { (14, u64::MAX.into()), ]); - let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>( + let ElectionResult::<_, Perbill> { winners, assignments } = seq_phragmen( 2, candidates, voters @@ -435,7 +435,7 @@ fn phragmen_accuracy_on_small_scale_self_vote() { let voters = auto_generate_self_voters(&candidates); let stake_of = create_stake_of(&[(40, 0), (10, 1), (20, 2), (30, 1)]); - let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>( + let ElectionResult::<_, Perbill> { winners, assignments } = seq_phragmen( 3, candidates, voters @@ -465,7 +465,7 @@ fn phragmen_accuracy_on_small_scale_no_self_vote() { (3, 1), ]); - let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>( + let ElectionResult::<_, Perbill> { winners, assignments } = seq_phragmen( 3, candidates, voters @@ -501,7 +501,7 @@ fn phragmen_large_scale_test() { (50, 990000000000000000), ]); - let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>( + let ElectionResult::<_, Perbill> { winners, assignments } = seq_phragmen( 2, candidates, voters @@ -528,7 +528,7 @@ fn phragmen_large_scale_test_2() { let stake_of = create_stake_of(&[(2, c_budget.into()), (4, c_budget.into()), (50, nom_budget.into())]); - let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>( + let ElectionResult::<_, Perbill> { winners, assignments } = seq_phragmen( 2, candidates, voters @@ -597,7 +597,7 @@ fn elect_has_no_entry_barrier() { let voters = vec![(1, vec![10]), (2, vec![20])]; let stake_of = create_stake_of(&[(1, 10), (2, 10)]); - let ElectionResult { winners, assignments: _ } = seq_phragmen::<_, Perbill>( + let ElectionResult::<_, Perbill> { winners, assignments: _ } = seq_phragmen( 3, candidates, voters @@ -618,7 +618,7 @@ fn phragmen_self_votes_should_be_kept() { let voters = vec![(5, vec![5]), (10, vec![10]), (20, vec![20]), (1, vec![10, 20])]; let stake_of = create_stake_of(&[(5, 5), (10, 10), (20, 20), (1, 8)]); - let result = seq_phragmen::<_, Perbill>( + let result: ElectionResult<_, Perbill> = seq_phragmen( 2, candidates, voters @@ -664,8 +664,8 @@ fn duplicate_target_is_ignored() { let candidates = vec![1, 2, 3]; let voters = vec![(10, 100, vec![1, 1, 2, 3]), (20, 100, vec![2, 3]), (30, 50, vec![1, 1, 2])]; - let ElectionResult { winners, assignments } = - seq_phragmen::<_, Perbill>(2, candidates, voters, None).unwrap(); + let ElectionResult::<_, Perbill> { winners, assignments } = + seq_phragmen(2, candidates, voters, None).unwrap(); assert_eq!(winners, vec![(2, 140), (3, 110)]); assert_eq!( @@ -682,8 +682,8 @@ fn duplicate_target_is_ignored_when_winner() { let candidates = vec![1, 2, 3]; let voters = vec![(10, 100, vec![1, 1, 2, 3]), (20, 100, vec![1, 2])]; - let ElectionResult { winners, assignments } = - seq_phragmen::<_, Perbill>(2, candidates, voters, None).unwrap(); + let ElectionResult::<_, Perbill> { winners, assignments } = + seq_phragmen(2, candidates, voters, None).unwrap(); assert_eq!(winners, vec![(1, 100), (2, 100)]); assert_eq!( From f2f99707af3c3c0ba7b5d0cf1bbd48d8408474c2 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Wed, 26 Jan 2022 03:48:46 +0800 Subject: [PATCH 0460/1472] use `thiserror` instead of `derive_more` for error handling (#10696) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * use thiserror instead of derive_more for error handling Signed-off-by: koushiro * Update utils/prometheus/src/lib.rs * Update utils/prometheus/src/lib.rs Co-authored-by: Bastian Köcher --- Cargo.lock | 30 ++++---- bin/node/inspect/Cargo.toml | 2 +- bin/node/inspect/src/lib.rs | 19 ++---- client/authority-discovery/Cargo.toml | 2 +- client/authority-discovery/src/error.rs | 68 ++++++++++++------- client/beefy/rpc/Cargo.toml | 1 - client/beefy/rpc/src/lib.rs | 8 +-- client/consensus/aura/Cargo.toml | 2 +- client/consensus/aura/src/lib.rs | 19 +++--- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 4 +- client/consensus/babe/rpc/src/lib.rs | 6 +- client/consensus/babe/src/lib.rs | 61 ++++++++--------- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/manual-seal/src/error.rs | 50 ++++++++------ client/consensus/pow/Cargo.toml | 2 +- client/consensus/pow/src/lib.rs | 41 ++++++----- client/executor/common/Cargo.toml | 1 - client/executor/common/src/error.rs | 28 +++++--- client/finality-grandpa/Cargo.toml | 3 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/finality-grandpa/rpc/src/error.rs | 12 ++-- client/finality-grandpa/src/authorities.rs | 19 +++--- client/finality-grandpa/src/finality_proof.rs | 9 +-- client/finality-grandpa/src/warp_proof.rs | 17 +++-- client/keystore/Cargo.toml | 2 +- client/keystore/src/lib.rs | 30 +++----- client/network/Cargo.toml | 3 +- client/network/src/bitswap.rs | 26 ++++--- client/network/src/block_request_handler.rs | 23 ++++--- client/network/src/error.rs | 39 ++++------- .../src/light_client_requests/handler.rs | 18 ++--- .../src/protocol/notifications/handler.rs | 4 +- .../notifications/upgrade/notifications.rs | 15 ++-- client/network/src/request_responses.rs | 23 ++++--- client/network/src/service.rs | 4 +- client/network/src/state_request_handler.rs | 23 ++++--- client/network/src/warp_request_handler.rs | 29 ++++---- client/transaction-pool/api/Cargo.toml | 9 ++- client/transaction-pool/api/src/error.rs | 3 +- client/transaction-pool/src/lib.rs | 8 +-- primitives/keystore/Cargo.toml | 10 +-- primitives/keystore/src/lib.rs | 10 +-- .../runtime/transaction-pool/Cargo.toml | 2 +- .../runtime/transaction-pool/src/lib.rs | 11 +-- utils/prometheus/Cargo.toml | 2 +- utils/prometheus/src/lib.rs | 27 +++----- 47 files changed, 376 insertions(+), 355 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39cb42be7a857..a8092fffa7c07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -520,7 +520,6 @@ version = "4.0.0-dev" dependencies = [ "beefy-gadget", "beefy-primitives", - "derive_more", "futures 0.3.16", "jsonrpc-core", "jsonrpc-core-client", @@ -4710,7 +4709,6 @@ name = "node-inspect" version = "0.9.0-dev" dependencies = [ "clap 3.0.7", - "derive_more", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4719,6 +4717,7 @@ dependencies = [ "sp-blockchain", "sp-core", "sp-runtime", + "thiserror", ] [[package]] @@ -7647,7 +7646,6 @@ name = "sc-authority-discovery" version = "0.10.0-dev" dependencies = [ "async-trait", - "derive_more", "futures 0.3.16", "futures-timer", "ip_network", @@ -7669,6 +7667,7 @@ dependencies = [ "sp-tracing", "substrate-prometheus-endpoint", "substrate-test-runtime-client", + "thiserror", ] [[package]] @@ -7863,7 +7862,6 @@ name = "sc-consensus-aura" version = "0.10.0-dev" dependencies = [ "async-trait", - "derive_more", "futures 0.3.16", "getrandom 0.2.3", "log 0.4.14", @@ -7894,6 +7892,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", + "thiserror", ] [[package]] @@ -7901,7 +7900,6 @@ name = "sc-consensus-babe" version = "0.10.0-dev" dependencies = [ "async-trait", - "derive_more", "fork-tree", "futures 0.3.16", "log 0.4.14", @@ -7944,13 +7942,13 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", + "thiserror", ] [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" dependencies = [ - "derive_more", "futures 0.3.16", "jsonrpc-core", "jsonrpc-core-client", @@ -7973,6 +7971,7 @@ dependencies = [ "sp-runtime", "substrate-test-runtime-client", "tempfile", + "thiserror", ] [[package]] @@ -7993,7 +7992,6 @@ version = "0.10.0-dev" dependencies = [ "assert_matches", "async-trait", - "derive_more", "futures 0.3.16", "jsonrpc-core", "jsonrpc-core-client", @@ -8023,6 +8021,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", + "thiserror", "tokio", ] @@ -8031,7 +8030,6 @@ name = "sc-consensus-pow" version = "0.10.0-dev" dependencies = [ "async-trait", - "derive_more", "futures 0.3.16", "futures-timer", "log 0.4.14", @@ -8048,6 +8046,7 @@ dependencies = [ "sp-inherents", "sp-runtime", "substrate-prometheus-endpoint", + "thiserror", ] [[package]] @@ -8128,7 +8127,6 @@ dependencies = [ name = "sc-executor-common" version = "0.10.0-dev" dependencies = [ - "derive_more", "environmental", "parity-scale-codec", "sc-allocator", @@ -8184,7 +8182,6 @@ version = "0.10.0-dev" dependencies = [ "assert_matches", "async-trait", - "derive_more", "dyn-clone", "finality-grandpa", "fork-tree", @@ -8219,6 +8216,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", + "thiserror", "tokio", ] @@ -8226,7 +8224,6 @@ dependencies = [ name = "sc-finality-grandpa-rpc" version = "0.10.0-dev" dependencies = [ - "derive_more", "finality-grandpa", "futures 0.3.16", "jsonrpc-core", @@ -8247,6 +8244,7 @@ dependencies = [ "sp-keyring", "sp-runtime", "substrate-test-runtime-client", + "thiserror", ] [[package]] @@ -8270,7 +8268,6 @@ name = "sc-keystore" version = "4.0.0-dev" dependencies = [ "async-trait", - "derive_more", "hex", "parking_lot 0.11.2", "serde_json", @@ -8278,6 +8275,7 @@ dependencies = [ "sp-core", "sp-keystore", "tempfile", + "thiserror", ] [[package]] @@ -8291,7 +8289,6 @@ dependencies = [ "bitflags", "bytes 1.1.0", "cid", - "derive_more", "either", "fnv", "fork-tree", @@ -8762,7 +8759,6 @@ dependencies = [ name = "sc-transaction-pool-api" version = "4.0.0-dev" dependencies = [ - "derive_more", "futures 0.3.16", "log 0.4.14", "serde", @@ -9632,7 +9628,6 @@ name = "sp-keystore" version = "0.10.0" dependencies = [ "async-trait", - "derive_more", "futures 0.3.16", "merlin", "parity-scale-codec", @@ -9643,6 +9638,7 @@ dependencies = [ "serde", "sp-core", "sp-externalities", + "thiserror", ] [[package]] @@ -10211,11 +10207,11 @@ name = "substrate-prometheus-endpoint" version = "0.10.0-dev" dependencies = [ "async-std", - "derive_more", "futures-util", "hyper 0.14.16", "log 0.4.14", "prometheus", + "thiserror", "tokio", ] @@ -10312,7 +10308,6 @@ dependencies = [ name = "substrate-test-runtime-transaction-pool" version = "2.0.0" dependencies = [ - "derive_more", "futures 0.3.16", "parity-scale-codec", "parking_lot 0.11.2", @@ -10321,6 +10316,7 @@ dependencies = [ "sp-blockchain", "sp-runtime", "substrate-test-runtime-client", + "thiserror", ] [[package]] diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index 49470a7e7b058..bb9af8c66988e 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "3.0", features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0" } -derive_more = "0.99" +thiserror = "1.0" sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } diff --git a/bin/node/inspect/src/lib.rs b/bin/node/inspect/src/lib.rs index ff1eecd219a97..b37c5aa7ca2e8 100644 --- a/bin/node/inspect/src/lib.rs +++ b/bin/node/inspect/src/lib.rs @@ -78,26 +78,19 @@ impl PrettyPrinter for DebugPrinter { } /// Aggregated error for `Inspector` operations. -#[derive(Debug, derive_more::From, derive_more::Display)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// Could not decode Block or Extrinsic. - Codec(codec::Error), + #[error(transparent)] + Codec(#[from] codec::Error), /// Error accessing blockchain DB. - Blockchain(sp_blockchain::Error), + #[error(transparent)] + Blockchain(#[from] sp_blockchain::Error), /// Given block has not been found. + #[error("{0}")] NotFound(String), } -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match *self { - Self::Codec(ref e) => Some(e), - Self::Blockchain(ref e) => Some(e), - Self::NotFound(_) => None, - } - } -} - /// A helper trait to access block headers and bodies. pub trait ChainAccess: HeaderBackend + BlockBackend {} diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index c6c523fa5eec7..ec43112a71450 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -19,7 +19,7 @@ prost-build = "0.9" [dependencies] async-trait = "0.1" codec = { package = "parity-scale-codec", default-features = false, version = "2.0.0" } -derive_more = "0.99.16" +thiserror = "1.0" futures = "0.3.9" futures-timer = "3.0.1" ip_network = "0.4.1" diff --git a/client/authority-discovery/src/error.rs b/client/authority-discovery/src/error.rs index 26ee02ef85321..bad53e905cb93 100644 --- a/client/authority-discovery/src/error.rs +++ b/client/authority-discovery/src/error.rs @@ -24,40 +24,56 @@ use sp_core::crypto::CryptoTypePublicPair; pub type Result = std::result::Result; /// Error type for the authority discovery module. -#[derive(Debug, derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] pub enum Error { - /// Received dht value found event with records with different keys. + #[error("Received dht value found event with records with different keys.")] ReceivingDhtValueFoundEventWithDifferentKeys, - /// Received dht value found event with no records. + + #[error("Received dht value found event with no records.")] ReceivingDhtValueFoundEventWithNoRecords, - /// Failed to verify a dht payload with the given signature. + + #[error("Failed to verify a dht payload with the given signature.")] VerifyingDhtPayload, - /// Failed to hash the authority id to be used as a dht key. - HashingAuthorityId(libp2p::core::multiaddr::multihash::Error), - /// Failed calling into the Substrate runtime. - CallingRuntime(sp_blockchain::Error), - /// Received a dht record with a key that does not match any in-flight awaited keys. + + #[error("Failed to hash the authority id to be used as a dht key.")] + HashingAuthorityId(#[from] libp2p::core::multiaddr::multihash::Error), + + #[error("Failed calling into the Substrate runtime.")] + CallingRuntime(#[from] sp_blockchain::Error), + + #[error("Received a dht record with a key that does not match any in-flight awaited keys.")] ReceivingUnexpectedRecord, - /// Failed to encode a protobuf payload. - EncodingProto(prost::EncodeError), - /// Failed to decode a protobuf payload. - DecodingProto(prost::DecodeError), - /// Failed to encode or decode scale payload. - EncodingDecodingScale(codec::Error), - /// Failed to parse a libp2p multi address. - ParsingMultiaddress(libp2p::core::multiaddr::Error), - /// Failed to parse a libp2p key. - ParsingLibp2pIdentity(sc_network::DecodingError), - /// Failed to sign using a specific public key. + + #[error("Failed to encode a protobuf payload.")] + EncodingProto(#[from] prost::EncodeError), + + #[error("Failed to decode a protobuf payload.")] + DecodingProto(#[from] prost::DecodeError), + + #[error("Failed to encode or decode scale payload.")] + EncodingDecodingScale(#[from] codec::Error), + + #[error("Failed to parse a libp2p multi address.")] + ParsingMultiaddress(#[from] libp2p::core::multiaddr::Error), + + #[error("Failed to parse a libp2p key.")] + ParsingLibp2pIdentity(#[from] sc_network::DecodingError), + + #[error("Failed to sign using a specific public key.")] MissingSignature(CryptoTypePublicPair), - /// Failed to sign using all public keys. + + #[error("Failed to sign using all public keys.")] Signing, - /// Failed to register Prometheus metric. - Prometheus(prometheus_endpoint::PrometheusError), - /// Received authority record that contains addresses with multiple peer ids + + #[error("Failed to register Prometheus metric.")] + Prometheus(#[from] prometheus_endpoint::PrometheusError), + + #[error("Received authority record that contains addresses with multiple peer ids")] ReceivingDhtValueFoundEventWithDifferentPeerIds, - /// Received authority record without any addresses having a peer id + + #[error("Received authority record without any addresses having a peer id")] ReceivingDhtValueFoundEventWithNoPeerIds, - /// Received authority record without a valid signature for the remote peer id. + + #[error("Received authority record without a valid signature for the remote peer id.")] MissingPeerIdSignature, } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index a72af62fdeeac..444f1ff4aaf9e 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -8,7 +8,6 @@ repository = "https://github.com/paritytech/substrate" description = "RPC for the BEEFY Client gadget for substrate" [dependencies] -derive_more = "0.99" futures = "0.3.16" log = "0.4" parking_lot = "0.11" diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index dc9ee8b94701b..4c1bc03e222e7 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -36,15 +36,15 @@ mod notification; type FutureResult = jsonrpc_core::BoxFuture>; -#[derive(Debug, derive_more::Display, derive_more::From, thiserror::Error)] +#[derive(Debug, thiserror::Error)] /// Top-level error type for the RPC handler pub enum Error { /// The BEEFY RPC endpoint is not ready. - #[display(fmt = "BEEFY RPC endpoint not ready")] + #[error("BEEFY RPC endpoint not ready")] EndpointNotReady, /// The BEEFY RPC background task failed to spawn. - #[display(fmt = "BEEFY RPC background task failed to spawn")] - RpcTaskFailure(SpawnError), + #[error("BEEFY RPC background task failed to spawn")] + RpcTaskFailure(#[from] SpawnError), } /// The error codes returned by jsonrpc. diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 97409c5944dbb..bcae7648ce2e8 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } -derive_more = "0.99.16" +thiserror = "1.0" futures = "0.3.9" sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } log = "0.4.8" diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index d7fe613139382..61c5610883149 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -491,33 +491,34 @@ fn aura_err(error: Error) -> Error { } /// Aura Errors -#[derive(derive_more::Display, Debug)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// Multiple Aura pre-runtime headers - #[display(fmt = "Multiple Aura pre-runtime headers")] + #[error("Multiple Aura pre-runtime headers")] MultipleHeaders, /// No Aura pre-runtime digest found - #[display(fmt = "No Aura pre-runtime digest found")] + #[error("No Aura pre-runtime digest found")] NoDigestFound, /// Header is unsealed - #[display(fmt = "Header {:?} is unsealed", _0)] + #[error("Header {0:?} is unsealed")] HeaderUnsealed(B::Hash), /// Header has a bad seal - #[display(fmt = "Header {:?} has a bad seal", _0)] + #[error("Header {0:?} has a bad seal")] HeaderBadSeal(B::Hash), /// Slot Author not found - #[display(fmt = "Slot Author not found")] + #[error("Slot Author not found")] SlotAuthorNotFound, /// Bad signature - #[display(fmt = "Bad signature on {:?}", _0)] + #[error("Bad signature on {0:?}")] BadSignature(B::Hash), /// Client Error + #[error(transparent)] Client(sp_blockchain::Error), /// Unknown inherent error for identifier - #[display(fmt = "Unknown inherent error for identifier: {}", "String::from_utf8_lossy(_0)")] + #[error("Unknown inherent error for identifier: {}", String::from_utf8_lossy(.0))] UnknownInherentError(sp_inherents::InherentIdentifier), - #[display(fmt = "Inherent error: {}", _0)] /// Inherents Error + #[error("Inherent error: {0}")] Inherent(sp_inherents::Error), } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index e4d66fcad87cc..5dd029f0ad4a9 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -49,7 +49,7 @@ log = "0.4.8" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } rand = "0.7.2" merlin = "2.0" -derive_more = "0.99.16" +thiserror = "1.0" retain_mut = "0.1.4" async-trait = "0.1.50" diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 93be56b9d3601..4997cfdd1eec0 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -19,12 +19,12 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } -serde = { version = "1.0.132", features=["derive"] } +serde = { version = "1.0.132", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sp-runtime = { version = "4.1.0-dev", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } futures = "0.3.16" -derive_more = "0.99.16" +thiserror = "1.0" sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } sp-core = { version = "4.1.0-dev", path = "../../../../primitives/core" } diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index c9d2f9b76c2a2..462620f26e5bf 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -166,11 +166,13 @@ pub struct EpochAuthorship { } /// Errors encountered by the RPC -#[derive(Debug, derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// Consensus error - Consensus(ConsensusError), + #[error(transparent)] + Consensus(#[from] ConsensusError), /// Errors that can be formatted as a String + #[error("{0}")] StringError(String), } diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index a86eac35a1000..3e9cf5aab6494 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -217,95 +217,94 @@ impl Epoch { } /// Errors encountered by the babe authorship task. -#[derive(derive_more::Display, Debug)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// Multiple BABE pre-runtime digests - #[display(fmt = "Multiple BABE pre-runtime digests, rejecting!")] + #[error("Multiple BABE pre-runtime digests, rejecting!")] MultiplePreRuntimeDigests, /// No BABE pre-runtime digest found - #[display(fmt = "No BABE pre-runtime digest found")] + #[error("No BABE pre-runtime digest found")] NoPreRuntimeDigest, /// Multiple BABE epoch change digests - #[display(fmt = "Multiple BABE epoch change digests, rejecting!")] + #[error("Multiple BABE epoch change digests, rejecting!")] MultipleEpochChangeDigests, /// Multiple BABE config change digests - #[display(fmt = "Multiple BABE config change digests, rejecting!")] + #[error("Multiple BABE config change digests, rejecting!")] MultipleConfigChangeDigests, /// Could not extract timestamp and slot - #[display(fmt = "Could not extract timestamp and slot: {:?}", _0)] + #[error("Could not extract timestamp and slot: {0:?}")] Extraction(sp_consensus::Error), /// Could not fetch epoch - #[display(fmt = "Could not fetch epoch at {:?}", _0)] + #[error("Could not fetch epoch at {0:?}")] FetchEpoch(B::Hash), /// Header rejected: too far in the future - #[display(fmt = "Header {:?} rejected: too far in the future", _0)] + #[error("Header {0:?} rejected: too far in the future")] TooFarInFuture(B::Hash), /// Parent unavailable. Cannot import - #[display(fmt = "Parent ({}) of {} unavailable. Cannot import", _0, _1)] + #[error("Parent ({0}) of {1} unavailable. Cannot import")] ParentUnavailable(B::Hash, B::Hash), /// Slot number must increase - #[display(fmt = "Slot number must increase: parent slot: {}, this slot: {}", _0, _1)] + #[error("Slot number must increase: parent slot: {0}, this slot: {1}")] SlotMustIncrease(Slot, Slot), /// Header has a bad seal - #[display(fmt = "Header {:?} has a bad seal", _0)] + #[error("Header {0:?} has a bad seal")] HeaderBadSeal(B::Hash), /// Header is unsealed - #[display(fmt = "Header {:?} is unsealed", _0)] + #[error("Header {0:?} is unsealed")] HeaderUnsealed(B::Hash), /// Slot author not found - #[display(fmt = "Slot author not found")] + #[error("Slot author not found")] SlotAuthorNotFound, /// Secondary slot assignments are disabled for the current epoch. - #[display(fmt = "Secondary slot assignments are disabled for the current epoch.")] + #[error("Secondary slot assignments are disabled for the current epoch.")] SecondarySlotAssignmentsDisabled, /// Bad signature - #[display(fmt = "Bad signature on {:?}", _0)] + #[error("Bad signature on {0:?}")] BadSignature(B::Hash), /// Invalid author: Expected secondary author - #[display(fmt = "Invalid author: Expected secondary author: {:?}, got: {:?}.", _0, _1)] + #[error("Invalid author: Expected secondary author: {0:?}, got: {1:?}.")] InvalidAuthor(AuthorityId, AuthorityId), /// No secondary author expected. - #[display(fmt = "No secondary author expected.")] + #[error("No secondary author expected.")] NoSecondaryAuthorExpected, /// VRF verification of block by author failed - #[display( - fmt = "VRF verification of block by author {:?} failed: threshold {} exceeded", - _0, - _1 - )] + #[error("VRF verification of block by author {0:?} failed: threshold {1} exceeded")] VRFVerificationOfBlockFailed(AuthorityId, u128), /// VRF verification failed - #[display(fmt = "VRF verification failed: {:?}", _0)] + #[error("VRF verification failed: {0:?}")] VRFVerificationFailed(SignatureError), /// Could not fetch parent header - #[display(fmt = "Could not fetch parent header: {:?}", _0)] + #[error("Could not fetch parent header: {0:?}")] FetchParentHeader(sp_blockchain::Error), /// Expected epoch change to happen. - #[display(fmt = "Expected epoch change to happen at {:?}, s{}", _0, _1)] + #[error("Expected epoch change to happen at {0:?}, s{1}")] ExpectedEpochChange(B::Hash, Slot), /// Unexpected config change. - #[display(fmt = "Unexpected config change")] + #[error("Unexpected config change")] UnexpectedConfigChange, /// Unexpected epoch change - #[display(fmt = "Unexpected epoch change")] + #[error("Unexpected epoch change")] UnexpectedEpochChange, /// Parent block has no associated weight - #[display(fmt = "Parent block of {} has no associated weight", _0)] + #[error("Parent block of {0} has no associated weight")] ParentBlockNoAssociatedWeight(B::Hash), /// Check inherents error - #[display(fmt = "Checking inherents failed: {}", _0)] + #[error("Checking inherents failed: {0}")] CheckInherents(sp_inherents::Error), /// Unhandled check inherents error - #[display(fmt = "Checking inherents unhandled error: {}", "String::from_utf8_lossy(_0)")] + #[error("Checking inherents unhandled error: {}", String::from_utf8_lossy(.0))] CheckInherentsUnhandled(sp_inherents::InherentIdentifier), /// Create inherents error. - #[display(fmt = "Creating inherents failed: {}", _0)] + #[error("Creating inherents failed: {0}")] CreateInherents(sp_inherents::Error), /// Client error + #[error(transparent)] Client(sp_blockchain::Error), /// Runtime Api error. + #[error(transparent)] RuntimeApi(sp_api::ApiError), /// Fork tree error + #[error(transparent)] ForkTree(Box>), } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 89f3335899f1b..ff2264e641740 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -derive_more = "0.99.16" +thiserror = "1.0" futures = "0.3.9" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/client/consensus/manual-seal/src/error.rs b/client/consensus/manual-seal/src/error.rs index 3a67b36bc62bc..2f946f3de3ccc 100644 --- a/client/consensus/manual-seal/src/error.rs +++ b/client/consensus/manual-seal/src/error.rs @@ -38,40 +38,52 @@ mod codes { } /// errors encountered by background block authorship task -#[derive(Debug, derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// An error occurred while importing the block - #[display(fmt = "Block import failed: {:?}", _0)] + #[error("Block import failed: {0:?}")] BlockImportError(ImportResult), /// Transaction pool is empty, cannot create a block - #[display(fmt = "Transaction pool is empty, set create_empty to true,\ - if you want to create empty blocks")] + #[error( + "Transaction pool is empty, set create_empty to true, if you want to create empty blocks" + )] EmptyTransactionPool, /// encountered during creation of Proposer. - #[display(fmt = "Consensus Error: {}", _0)] - ConsensusError(ConsensusError), + #[error("Consensus Error: {0}")] + ConsensusError(#[from] ConsensusError), /// Failed to create Inherents data - #[display(fmt = "Inherents Error: {}", _0)] - InherentError(InherentsError), + #[error("Inherents Error: {0}")] + InherentError(#[from] InherentsError), /// error encountered during finalization - #[display(fmt = "Finalization Error: {}", _0)] - BlockchainError(BlockchainError), + #[error("Finalization Error: {0}")] + BlockchainError(#[from] BlockchainError), /// Supplied parent_hash doesn't exist in chain - #[display(fmt = "Supplied parent_hash: {} doesn't exist in chain", _0)] - #[from(ignore)] + #[error("Supplied parent_hash: {0} doesn't exist in chain")] BlockNotFound(String), /// Some string error - #[display(fmt = "{}", _0)] + #[error("{0}")] StringError(String), /// send error - #[display(fmt = "Consensus process is terminating")] - Canceled(oneshot::Canceled), + #[error("Consensus process is terminating")] + Canceled(#[from] oneshot::Canceled), /// send error - #[display(fmt = "Consensus process is terminating")] - SendError(SendError), + #[error("Consensus process is terminating")] + SendError(#[from] SendError), /// Some other error. - #[display(fmt = "Other error: {}", _0)] - Other(Box), + #[error("Other error: {0}")] + Other(#[from] Box), +} + +impl From for Error { + fn from(err: ImportResult) -> Self { + Error::BlockImportError(err) + } +} + +impl From for Error { + fn from(s: String) -> Self { + Error::StringError(s) + } } impl Error { diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index db9e4e164e4e9..e5bf87487c71b 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -28,6 +28,6 @@ log = "0.4.8" futures = "0.3.16" futures-timer = "3.0.1" parking_lot = "0.11.2" -derive_more = "0.99.16" +thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev"} async-trait = "0.1.50" diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 0bcb9f3d00a54..ef81faff46a93 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -72,45 +72,50 @@ use std::{ time::Duration, }; -#[derive(derive_more::Display, Debug)] +#[derive(Debug, thiserror::Error)] pub enum Error { - #[display(fmt = "Header uses the wrong engine {:?}", _0)] + #[error("Header uses the wrong engine {0:?}")] WrongEngine([u8; 4]), - #[display(fmt = "Header {:?} is unsealed", _0)] + #[error("Header {0:?} is unsealed")] HeaderUnsealed(B::Hash), - #[display(fmt = "PoW validation error: invalid seal")] + #[error("PoW validation error: invalid seal")] InvalidSeal, - #[display(fmt = "PoW validation error: preliminary verification failed")] + #[error("PoW validation error: preliminary verification failed")] FailedPreliminaryVerify, - #[display(fmt = "Rejecting block too far in future")] + #[error("Rejecting block too far in future")] TooFarInFuture, - #[display(fmt = "Fetching best header failed using select chain: {:?}", _0)] + #[error("Fetching best header failed using select chain: {0:?}")] BestHeaderSelectChain(ConsensusError), - #[display(fmt = "Fetching best header failed: {:?}", _0)] + #[error("Fetching best header failed: {0:?}")] BestHeader(sp_blockchain::Error), - #[display(fmt = "Best header does not exist")] + #[error("Best header does not exist")] NoBestHeader, - #[display(fmt = "Block proposing error: {:?}", _0)] + #[error("Block proposing error: {0:?}")] BlockProposingError(String), - #[display(fmt = "Fetch best hash failed via select chain: {:?}", _0)] + #[error("Fetch best hash failed via select chain: {0:?}")] BestHashSelectChain(ConsensusError), - #[display(fmt = "Error with block built on {:?}: {:?}", _0, _1)] + #[error("Error with block built on {0:?}: {1:?}")] BlockBuiltError(B::Hash, ConsensusError), - #[display(fmt = "Creating inherents failed: {}", _0)] + #[error("Creating inherents failed: {0}")] CreateInherents(sp_inherents::Error), - #[display(fmt = "Checking inherents failed: {}", _0)] + #[error("Checking inherents failed: {0}")] CheckInherents(sp_inherents::Error), - #[display( - fmt = "Checking inherents unknown error for identifier: {:?}", - "String::from_utf8_lossy(_0)" + #[error( + "Checking inherents unknown error for identifier: {:?}", + String::from_utf8_lossy(.0) )] CheckInherentsUnknownError(sp_inherents::InherentIdentifier), - #[display(fmt = "Multiple pre-runtime digests")] + #[error("Multiple pre-runtime digests")] MultiplePreRuntimeDigests, + #[error(transparent)] Client(sp_blockchain::Error), + #[error(transparent)] Codec(codec::Error), + #[error("{0}")] Environment(String), + #[error("{0}")] Runtime(RuntimeString), + #[error("{0}")] Other(String), } diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 8e4b11f8f8fae..104d24876d9a5 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -14,7 +14,6 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -derive_more = "0.99.16" wasm-instrument = "0.1" codec = { package = "parity-scale-codec", version = "2.0.0" } wasmi = "0.9.1" diff --git a/client/executor/common/src/error.rs b/client/executor/common/src/error.rs index 90e658a896281..606f97317b9a8 100644 --- a/client/executor/common/src/error.rs +++ b/client/executor/common/src/error.rs @@ -125,28 +125,38 @@ impl From for Error { } /// Type for errors occurring during Wasm runtime construction. -#[derive(Debug, derive_more::Display)] +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] pub enum WasmError { - /// Code could not be read from the state. + #[error("Code could not be read from the state.")] CodeNotFound, - /// Failure to reinitialize runtime instance from snapshot. + + #[error("Failure to reinitialize runtime instance from snapshot.")] ApplySnapshotFailed, + /// Failure to erase the wasm memory. /// /// Depending on the implementation might mean failure of allocating memory. + #[error("Failure to erase the wasm memory: {0}")] ErasingFailed(String), - /// Wasm code failed validation. + + #[error("Wasm code failed validation.")] InvalidModule, - /// Wasm code could not be deserialized. + + #[error("Wasm code could not be deserialized.")] CantDeserializeWasm, - /// The module does not export a linear memory named `memory`. + + #[error("The module does not export a linear memory named `memory`.")] InvalidMemory, - /// The number of heap pages requested is disallowed by the module. + + #[error("The number of heap pages requested is disallowed by the module.")] InvalidHeapPages, + /// Instantiation error. + #[error("{0}")] Instantiation(String), + /// Other error happenend. + #[error("{0}")] Other(String), } - -impl std::error::Error for WasmError {} diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 3f9261c0c17af..2e6d3407a191f 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -13,9 +13,8 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] -derive_more = "0.99.16" +thiserror = "1.0" dyn-clone = "1.0" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } futures = "0.3.9" diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index be6dfc371e4ad..39bf398fe3129 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -23,7 +23,7 @@ futures = "0.3.16" serde = { version = "1.0.105", features = ["derive"] } serde_json = "1.0.50" log = "0.4.8" -derive_more = "0.99.2" +thiserror = "1.0" parity-scale-codec = { version = "2.0.0", features = ["derive"] } sc-client-api = { version = "4.0.0-dev", path = "../../api" } diff --git a/client/finality-grandpa/rpc/src/error.rs b/client/finality-grandpa/rpc/src/error.rs index 1c1361bcaeda7..845b4d99dcc1a 100644 --- a/client/finality-grandpa/rpc/src/error.rs +++ b/client/finality-grandpa/rpc/src/error.rs @@ -16,21 +16,21 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#[derive(derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] /// Top-level error type for the RPC handler pub enum Error { /// The GRANDPA RPC endpoint is not ready. - #[display(fmt = "GRANDPA RPC endpoint not ready")] + #[error("GRANDPA RPC endpoint not ready")] EndpointNotReady, /// GRANDPA reports the authority set id to be larger than 32-bits. - #[display(fmt = "GRANDPA reports authority set id unreasonably large")] + #[error("GRANDPA reports authority set id unreasonably large")] AuthoritySetIdReportedAsUnreasonablyLarge, /// GRANDPA reports voter state with round id or weights larger than 32-bits. - #[display(fmt = "GRANDPA reports voter state as unreasonably large")] + #[error("GRANDPA reports voter state as unreasonably large")] VoterStateReportsUnreasonablyLargeNumbers, /// GRANDPA prove finality failed. - #[display(fmt = "GRANDPA prove finality rpc failed: {}", _0)] - ProveFinalityFailed(sc_finality_grandpa::FinalityProofError), + #[error("GRANDPA prove finality rpc failed: {0}")] + ProveFinalityFailed(#[from] sc_finality_grandpa::FinalityProofError), } /// The error codes returned by jsonrpc. diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index aa8be83b9529a..033a1c4bbb239 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -32,23 +32,22 @@ use sp_finality_grandpa::{AuthorityId, AuthorityList}; use crate::SetId; /// Error type returned on operations on the `AuthoritySet`. -#[derive(Debug, derive_more::Display)] +#[derive(Debug, thiserror::Error)] pub enum Error { - #[display(fmt = "Invalid authority set, either empty or with an authority weight set to 0.")] + #[error("Invalid authority set, either empty or with an authority weight set to 0.")] InvalidAuthoritySet, - #[display(fmt = "Client error during ancestry lookup: {}", _0)] + #[error("Client error during ancestry lookup: {0}")] Client(E), - #[display(fmt = "Duplicate authority set change.")] + #[error("Duplicate authority set change.")] DuplicateAuthoritySetChange, - #[display(fmt = "Multiple pending forced authority set changes are not allowed.")] + #[error("Multiple pending forced authority set changes are not allowed.")] MultiplePendingForcedAuthoritySetChanges, - #[display( - fmt = "A pending forced authority set change could not be applied since it must be applied \ - after the pending standard change at #{}", - _0 + #[error( + "A pending forced authority set change could not be applied since it must be applied \ + after the pending standard change at #{0}" )] ForcedAuthoritySetChangeDependencyUnsatisfied(N), - #[display(fmt = "Invalid operation in the pending changes tree: {}", _0)] + #[error("Invalid operation in the pending changes tree: {0}")] ForkTree(fork_tree::Error), } diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index cc6853bee3b07..03a4f2ff450a3 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -132,17 +132,18 @@ pub struct FinalityProof { } /// Errors occurring when trying to prove finality -#[derive(Debug, derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] pub enum FinalityProofError { /// The requested block has not yet been finalized. - #[display(fmt = "Block not yet finalized")] + #[error("Block not yet finalized")] BlockNotYetFinalized, /// The requested block is not covered by authority set changes. Likely this means the block is /// in the latest authority set, and the subscription API is more appropriate. - #[display(fmt = "Block not covered by authority set changes")] + #[error("Block not covered by authority set changes")] BlockNotInAuthoritySetChanges, /// Errors originating from the client. - Client(sp_blockchain::Error), + #[error(transparent)] + Client(#[from] sp_blockchain::Error), } fn prove_finality( diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index 39d570d22bd7d..bdb8e36373de3 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -34,26 +34,25 @@ use sp_runtime::{ use std::{collections::HashMap, sync::Arc}; /// Warp proof processing error. -#[derive(Debug, derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// Decoding error. - #[display(fmt = "Failed to decode block hash: {}.", _0)] - DecodeScale(codec::Error), + #[error("Failed to decode block hash: {0}.")] + DecodeScale(#[from] codec::Error), /// Client backend error. - Client(sp_blockchain::Error), + #[error("{0}")] + Client(#[from] sp_blockchain::Error), /// Invalid request data. - #[from(ignore)] + #[error("{0}")] InvalidRequest(String), /// Invalid warp proof. - #[from(ignore)] + #[error("{0}")] InvalidProof(String), /// Missing header or authority set change data. - #[display(fmt = "Missing required data to be able to answer request.")] + #[error("Missing required data to be able to answer request.")] MissingData, } -impl std::error::Error for Error {} - /// The maximum size in bytes of the `WarpSyncProof`. pub(super) const MAX_WARP_SYNC_PROOF_SIZE: usize = 8 * 1024 * 1024; diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 7fe9e182efbdf..56d4ee0d556fa 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" -derive_more = "0.99.16" +thiserror = "1.0" sp-application-crypto = { version = "4.0.0", path = "../../primitives/application-crypto" } sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-keystore = { version = "0.10.0", path = "../../primitives/keystore" } diff --git a/client/keystore/src/lib.rs b/client/keystore/src/lib.rs index 359326bb4cae0..cf94a16f08d86 100644 --- a/client/keystore/src/lib.rs +++ b/client/keystore/src/lib.rs @@ -28,29 +28,31 @@ mod local; pub use local::LocalKeystore; /// Keystore error. -#[derive(Debug, derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// IO error. - Io(io::Error), + #[error(transparent)] + Io(#[from] io::Error), /// JSON error. - Json(serde_json::Error), + #[error(transparent)] + Json(#[from] serde_json::Error), /// Invalid password. - #[display( - fmt = "Requested public key and public key of the loaded private key do not match. \n + #[error( + "Requested public key and public key of the loaded private key do not match. \n This means either that the keystore password is incorrect or that the private key was stored under a wrong public key." )] PublicKeyMismatch, /// Invalid BIP39 phrase - #[display(fmt = "Invalid recovery phrase (BIP39) data")] + #[error("Invalid recovery phrase (BIP39) data")] InvalidPhrase, /// Invalid seed - #[display(fmt = "Invalid seed")] + #[error("Invalid seed")] InvalidSeed, /// Public key type is not supported - #[display(fmt = "Key crypto type is not supported")] + #[error("Key crypto type is not supported")] KeyNotSupported(KeyTypeId), /// Keystore unavailable - #[display(fmt = "Keystore unavailable")] + #[error("Keystore unavailable")] Unavailable, } @@ -69,13 +71,3 @@ impl From for TraitError { } } } - -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Error::Io(ref err) => Some(err), - Error::Json(ref err) => Some(err), - _ => None, - } - } -} diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index f378b75990cb9..354991b32ba5b 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -25,7 +25,6 @@ bytes = "1" codec = { package = "parity-scale-codec", version = "2.0.0", features = [ "derive", ] } -derive_more = "0.99.16" either = "1.5.3" fnv = "1.0.6" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } @@ -57,7 +56,7 @@ sp-core = { version = "4.1.0-dev", path = "../../primitives/core" } sp-runtime = { version = "4.1.0-dev", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } -thiserror = "1" +thiserror = "1.0" unsigned-varint = { version = "0.6.0", features = [ "futures", "asynchronous_codec", diff --git a/client/network/src/bitswap.rs b/client/network/src/bitswap.rs index e6cb1d9d79e3a..e7c37968b5f99 100644 --- a/client/network/src/bitswap.rs +++ b/client/network/src/bitswap.rs @@ -313,21 +313,29 @@ impl NetworkBehaviour for Bitswap { } /// Bitswap protocol error. -#[derive(derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] pub enum BitswapError { /// Protobuf decoding error. - #[display(fmt = "Failed to decode request: {}.", _0)] - DecodeProto(prost::DecodeError), + #[error("Failed to decode request: {0}.")] + DecodeProto(#[from] prost::DecodeError), + /// Protobuf encoding error. - #[display(fmt = "Failed to encode response: {}.", _0)] - EncodeProto(prost::EncodeError), + #[error("Failed to encode response: {0}.")] + EncodeProto(#[from] prost::EncodeError), + /// Client backend error. - Client(sp_blockchain::Error), + #[error(transparent)] + Client(#[from] sp_blockchain::Error), + /// Error parsing CID - BadCid(cid::Error), + #[error(transparent)] + BadCid(#[from] cid::Error), + /// Packet read error. - Read(io::Error), + #[error(transparent)] + Read(#[from] io::Error), + /// Error sending response. - #[display(fmt = "Failed to send response.")] + #[error("Failed to send response.")] SendResponse, } diff --git a/client/network/src/block_request_handler.rs b/client/network/src/block_request_handler.rs index 9d963480a7e01..2f17cdac0744b 100644 --- a/client/network/src/block_request_handler.rs +++ b/client/network/src/block_request_handler.rs @@ -379,19 +379,20 @@ impl BlockRequestHandler { } } -#[derive(derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] enum HandleRequestError { - #[display(fmt = "Failed to decode request: {}.", _0)] - DecodeProto(prost::DecodeError), - #[display(fmt = "Failed to encode response: {}.", _0)] - EncodeProto(prost::EncodeError), - #[display(fmt = "Failed to decode block hash: {}.", _0)] - DecodeScale(codec::Error), - #[display(fmt = "Missing `BlockRequest::from_block` field.")] + #[error("Failed to decode request: {0}.")] + DecodeProto(#[from] prost::DecodeError), + #[error("Failed to encode response: {0}.")] + EncodeProto(#[from] prost::EncodeError), + #[error("Failed to decode block hash: {0}.")] + DecodeScale(#[from] codec::Error), + #[error("Missing `BlockRequest::from_block` field.")] MissingFromField, - #[display(fmt = "Failed to parse BlockRequest::direction.")] + #[error("Failed to parse BlockRequest::direction.")] ParseDirection, - Client(sp_blockchain::Error), - #[display(fmt = "Failed to send response.")] + #[error(transparent)] + Client(#[from] sp_blockchain::Error), + #[error("Failed to send response.")] SendResponse, } diff --git a/client/network/src/error.rs b/client/network/src/error.rs index 1dafddd7bcc55..716235193a80f 100644 --- a/client/network/src/error.rs +++ b/client/network/src/error.rs @@ -27,18 +27,18 @@ use std::{borrow::Cow, fmt}; pub type Result = std::result::Result; /// Error type for the network. -#[derive(derive_more::Display, derive_more::From)] +#[derive(thiserror::Error)] pub enum Error { /// Io error - Io(std::io::Error), + #[error(transparent)] + Io(#[from] std::io::Error), + /// Client error - Client(Box), + #[error(transparent)] + Client(#[from] Box), /// The same bootnode (based on address) is registered with two different peer ids. - #[display( - fmt = "The same bootnode (`{}`) is registered with two different peer ids: `{}` and `{}`", - address, - first_id, - second_id + #[error( + "The same bootnode (`{address}`) is registered with two different peer ids: `{first_id}` and `{second_id}`" )] DuplicateBootnode { /// The address of the bootnode. @@ -49,11 +49,11 @@ pub enum Error { second_id: PeerId, }, /// Prometheus metrics error. - Prometheus(prometheus_endpoint::PrometheusError), + #[error(transparent)] + Prometheus(#[from] prometheus_endpoint::PrometheusError), /// The network addresses are invalid because they don't match the transport. - #[display( - fmt = "The following addresses are invalid because they don't match the transport: {:?}", - addresses + #[error( + "The following addresses are invalid because they don't match the transport: {addresses:?}" )] AddressesForAnotherTransport { /// Transport used. @@ -62,7 +62,7 @@ pub enum Error { addresses: Vec, }, /// The same request-response protocol has been registered multiple times. - #[display(fmt = "Request-response protocol registered multiple times: {}", protocol)] + #[error("Request-response protocol registered multiple times: {protocol}")] DuplicateRequestResponseProtocol { /// Name of the protocol registered multiple times. protocol: Cow<'static, str>, @@ -75,16 +75,3 @@ impl fmt::Debug for Error { fmt::Display::fmt(self, f) } } - -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::Io(ref err) => Some(err), - Self::Client(ref err) => Some(err), - Self::Prometheus(ref err) => Some(err), - Self::DuplicateBootnode { .. } | - Self::AddressesForAnotherTransport { .. } | - Self::DuplicateRequestResponseProtocol { .. } => None, - } - } -} diff --git a/client/network/src/light_client_requests/handler.rs b/client/network/src/light_client_requests/handler.rs index b5c6ccb196d5b..fb258304f2e8f 100644 --- a/client/network/src/light_client_requests/handler.rs +++ b/client/network/src/light_client_requests/handler.rs @@ -284,20 +284,20 @@ impl LightClientRequestHandler { } } -#[derive(derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] enum HandleRequestError { - #[display(fmt = "Failed to decode request: {}.", _0)] - DecodeProto(prost::DecodeError), - #[display(fmt = "Failed to encode response: {}.", _0)] - EncodeProto(prost::EncodeError), - #[display(fmt = "Failed to send response.")] + #[error("Failed to decode request: {0}.")] + DecodeProto(#[from] prost::DecodeError), + #[error("Failed to encode response: {0}.")] + EncodeProto(#[from] prost::EncodeError), + #[error("Failed to send response.")] SendResponse, /// A bad request has been received. - #[display(fmt = "bad request: {}", _0)] + #[error("bad request: {0}")] BadRequest(&'static str), /// Encoding or decoding of some data failed. - #[display(fmt = "codec error: {}", _0)] - Codec(codec::Error), + #[error("codec error: {0}")] + Codec(#[from] codec::Error), } fn fmt_keys(first: Option<&Vec>, last: Option<&Vec>) -> String { diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index 158ab2ae379c6..91225f54203af 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -457,9 +457,9 @@ impl<'a> Ready<'a> { } /// Error specific to the collection of protocols. -#[derive(Debug, derive_more::Display, derive_more::Error)] +#[derive(Debug, thiserror::Error)] pub enum NotifsHandlerError { - /// Channel of synchronous notifications is full. + #[error("Channel of synchronous notifications is full.")] SyncNotificationsClogged, } diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 5171d459fa400..53270975a5b0d 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -457,13 +457,14 @@ where } /// Error generated by sending on a notifications out substream. -#[derive(Debug, derive_more::From, derive_more::Display)] +#[derive(Debug, thiserror::Error)] pub enum NotificationsHandshakeError { /// I/O error on the substream. - Io(io::Error), + #[error(transparent)] + Io(#[from] io::Error), /// Initial message or handshake was too large. - #[display(fmt = "Initial message or handshake was too large: {}", requested)] + #[error("Initial message or handshake was too large: {requested}")] TooLarge { /// Size requested by the remote. requested: usize, @@ -472,7 +473,8 @@ pub enum NotificationsHandshakeError { }, /// Error while decoding the variable-length integer. - VarintDecode(unsigned_varint::decode::Error), + #[error(transparent)] + VarintDecode(#[from] unsigned_varint::decode::Error), } impl From for NotificationsHandshakeError { @@ -489,10 +491,11 @@ impl From for NotificationsHandshakeError { } /// Error generated by sending on a notifications out substream. -#[derive(Debug, derive_more::From, derive_more::Display)] +#[derive(Debug, thiserror::Error)] pub enum NotificationsOutError { /// I/O error on the substream. - Io(io::Error), + #[error(transparent)] + Io(#[from] io::Error), } #[cfg(test)] diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 24b3d3df00b2d..58007c7bc5ce1 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -884,34 +884,35 @@ impl NetworkBehaviour for RequestResponsesBehaviour { } /// Error when registering a protocol. -#[derive(Debug, derive_more::Display, derive_more::Error)] +#[derive(Debug, thiserror::Error)] pub enum RegisterError { /// A protocol has been specified multiple times. - DuplicateProtocol(#[error(ignore)] Cow<'static, str>), + #[error("{0}")] + DuplicateProtocol(Cow<'static, str>), } /// Error in a request. -#[derive(Debug, derive_more::Display, derive_more::Error)] +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] pub enum RequestFailure { - /// We are not currently connected to the requested peer. + #[error("We are not currently connected to the requested peer.")] NotConnected, - /// Given protocol hasn't been registered. + #[error("Given protocol hasn't been registered.")] UnknownProtocol, - /// Remote has closed the substream before answering, thereby signaling that it considers the - /// request as valid, but refused to answer it. + #[error("Remote has closed the substream before answering, thereby signaling that it considers the request as valid, but refused to answer it.")] Refused, - /// The remote replied, but the local node is no longer interested in the response. + #[error("The remote replied, but the local node is no longer interested in the response.")] Obsolete, /// Problem on the network. - #[display(fmt = "Problem on the network: {}", _0)] + #[error("Problem on the network: {0}")] Network(OutboundFailure), } /// Error when processing a request sent by a remote. -#[derive(Debug, derive_more::Display, derive_more::Error)] +#[derive(Debug, thiserror::Error)] pub enum ResponseFailure { /// Problem on the network. - #[display(fmt = "Problem on the network: {}", _0)] + #[error("Problem on the network: {0}")] Network(InboundFailure), } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 9c8c58ef49e4d..b6a1d3c88e7f3 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -1391,7 +1391,7 @@ impl<'a> NotificationSenderReady<'a> { } /// Error returned by [`NetworkService::send_notification`]. -#[derive(Debug, derive_more::Display, derive_more::Error)] +#[derive(Debug, thiserror::Error)] pub enum NotificationSenderError { /// The notification receiver has been closed, usually because the underlying connection /// closed. @@ -1399,8 +1399,10 @@ pub enum NotificationSenderError { /// Some of the notifications most recently sent may not have been received. However, /// the peer may still be connected and a new `NotificationSender` for the same /// protocol obtained from [`NetworkService::notification_sender`]. + #[error("The notification receiver has been closed")] Closed, /// Protocol name hasn't been registered. + #[error("Protocol name hasn't been registered")] BadProtocol, } diff --git a/client/network/src/state_request_handler.rs b/client/network/src/state_request_handler.rs index 89f1f2b363c4c..10a77061a031d 100644 --- a/client/network/src/state_request_handler.rs +++ b/client/network/src/state_request_handler.rs @@ -241,15 +241,20 @@ impl StateRequestHandler { } } -#[derive(derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] enum HandleRequestError { - #[display(fmt = "Failed to decode request: {}.", _0)] - DecodeProto(prost::DecodeError), - #[display(fmt = "Failed to encode response: {}.", _0)] - EncodeProto(prost::EncodeError), - #[display(fmt = "Failed to decode block hash: {}.", _0)] - InvalidHash(codec::Error), - Client(sp_blockchain::Error), - #[display(fmt = "Failed to send response.")] + #[error("Failed to decode request: {0}.")] + DecodeProto(#[from] prost::DecodeError), + + #[error("Failed to encode response: {0}.")] + EncodeProto(#[from] prost::EncodeError), + + #[error("Failed to decode block hash: {0}.")] + InvalidHash(#[from] codec::Error), + + #[error(transparent)] + Client(#[from] sp_blockchain::Error), + + #[error("Failed to send response.")] SendResponse, } diff --git a/client/network/src/warp_request_handler.rs b/client/network/src/warp_request_handler.rs index ca5a93b752b62..4c839825ff5ec 100644 --- a/client/network/src/warp_request_handler.rs +++ b/client/network/src/warp_request_handler.rs @@ -149,18 +149,23 @@ impl RequestHandler { } } -#[derive(Debug, derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] enum HandleRequestError { - #[display(fmt = "Failed to decode request: {}.", _0)] - DecodeProto(prost::DecodeError), - #[display(fmt = "Failed to encode response: {}.", _0)] - EncodeProto(prost::EncodeError), - #[display(fmt = "Failed to decode block hash: {}.", _0)] - DecodeScale(codec::Error), - Client(sp_blockchain::Error), - #[from(ignore)] - #[display(fmt = "Invalid request {}.", _0)] - InvalidRequest(Box), - #[display(fmt = "Failed to send response.")] + #[error("Failed to decode request: {0}.")] + DecodeProto(#[from] prost::DecodeError), + + #[error("Failed to encode response: {0}.")] + EncodeProto(#[from] prost::EncodeError), + + #[error("Failed to decode block hash: {0}.")] + DecodeScale(#[from] codec::Error), + + #[error(transparent)] + Client(#[from] sp_blockchain::Error), + + #[error("Invalid request {0}.")] + InvalidRequest(#[from] Box), + + #[error("Failed to send response.")] SendResponse, } diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 95b82e26fc5d7..a544248a4f2cc 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -9,11 +9,10 @@ repository = "https://github.com/paritytech/substrate/" description = "Transaction pool client facing API." [dependencies] -futures = { version = "0.3.1" } -log = { version = "0.4.8" } +futures = "0.3.1" +log = "0.4.8" serde = { version = "1.0.132", features = ["derive"] } -thiserror = { version = "1.0.30" } -sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } +thiserror = "1.0.30" -derive_more = { version = "0.99.16" } +sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/client/transaction-pool/api/src/error.rs b/client/transaction-pool/api/src/error.rs index f1ac2798e62d3..b093657f739b1 100644 --- a/client/transaction-pool/api/src/error.rs +++ b/client/transaction-pool/api/src/error.rs @@ -26,7 +26,7 @@ use sp_runtime::transaction_validity::{ pub type Result = std::result::Result; /// Transaction pool error type. -#[derive(Debug, thiserror::Error, derive_more::From)] +#[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { #[error("Unknown transaction validity: {0:?}")] @@ -64,7 +64,6 @@ pub enum Error { #[error("Transaction cannot be propagated and the local node does not author blocks")] Unactionable, - #[from(ignore)] #[error("{0}")] InvalidBlockId(String), diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 2d07815e4baac..b5af2d12d65c9 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -47,8 +47,8 @@ use std::{ use graph::{ExtrinsicHash, IsValidator}; use sc_transaction_pool_api::{ - ChainEvent, ImportNotificationStream, MaintainedTransactionPool, PoolFuture, PoolStatus, - ReadyTransactions, TransactionFor, TransactionPool, TransactionSource, + error::Error as TxPoolError, ChainEvent, ImportNotificationStream, MaintainedTransactionPool, + PoolFuture, PoolStatus, ReadyTransactions, TransactionFor, TransactionPool, TransactionSource, TransactionStatusStreamFor, TxHash, }; use sp_core::traits::SpawnEssentialNamed; @@ -418,8 +418,8 @@ where .validate_transaction_blocking(at, TransactionSource::Local, xt.clone())? .map_err(|e| { Self::Error::Pool(match e { - TransactionValidityError::Invalid(i) => i.into(), - TransactionValidityError::Unknown(u) => u.into(), + TransactionValidityError::Invalid(i) => TxPoolError::InvalidTransaction(i), + TransactionValidityError::Unknown(u) => TxPoolError::UnknownTransaction(u), }) })?; diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index e918f5d2c6d75..28802cbec35e7 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -14,13 +14,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" -derive_more = "0.99.16" +futures = "0.3.1" +parking_lot = { version = "0.11.2", default-features = false } +serde = { version = "1.0", optional = true } +thiserror = "1.0" + codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -futures = { version = "0.3.1" } schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } merlin = { version = "2.0", default-features = false } -parking_lot = { version = "0.11.2", default-features = false } -serde = { version = "1.0", optional = true} sp-core = { version = "4.1.0-dev", path = "../core" } sp-externalities = { version = "0.10.0", path = "../externalities", default-features = false } @@ -28,7 +29,6 @@ sp-externalities = { version = "0.10.0", path = "../externalities", default-feat rand = "0.7.2" rand_chacha = "0.2.2" - [features] default = ["std"] std = [ diff --git a/primitives/keystore/src/lib.rs b/primitives/keystore/src/lib.rs index 6c27e3df7ce0d..6540e71bc3fe0 100644 --- a/primitives/keystore/src/lib.rs +++ b/primitives/keystore/src/lib.rs @@ -29,19 +29,19 @@ use sp_core::{ use std::sync::Arc; /// CryptoStore error -#[derive(Debug, derive_more::Display)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// Public key type is not supported - #[display(fmt = "Key not supported: {:?}", _0)] + #[error("Key not supported: {0:?}")] KeyNotSupported(KeyTypeId), /// Validation error - #[display(fmt = "Validation error: {}", _0)] + #[error("Validation error: {0}")] ValidationError(String), /// Keystore unavailable - #[display(fmt = "Keystore unavailable")] + #[error("Keystore unavailable")] Unavailable, /// Programming errors - #[display(fmt = "An unknown keystore error occurred: {}", _0)] + #[error("An unknown keystore error occurred: {0}")] Other(String), } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index 39221a2d15794..2a94f24845871 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -20,4 +20,4 @@ sp-runtime = { version = "4.1.0-dev", path = "../../../primitives/runtime" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } futures = "0.3.16" -derive_more = "0.99.16" +thiserror = "1.0" diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index ba317f57f531a..4008427623499 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -40,8 +40,9 @@ use substrate_test_runtime_client::{ }; /// Error type used by [`TestApi`]. -#[derive(Debug, derive_more::From, derive_more::Display)] -pub struct Error(sc_transaction_pool_api::error::Error); +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +pub struct Error(#[from] sc_transaction_pool_api::error::Error); impl sc_transaction_pool_api::error::IntoPoolError for Error { fn into_pool_error(self) -> Result { @@ -49,12 +50,6 @@ impl sc_transaction_pool_api::error::IntoPoolError for Error { } } -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - Some(&self.0) - } -} - pub enum IsBestBlock { Yes, No, diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 4ae38f6455327..27b5f94305fdd 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] log = "0.4.8" prometheus = { version = "0.13.0", default-features = false } futures-util = { version = "0.3.19", default-features = false, features = ["io"] } -derive_more = "0.99" +thiserror = "1.0" async-std = { version = "1.10.0", features = ["unstable"] } tokio = "1.15" hyper = { version = "0.14.16", default-features = false, features = ["http1", "server", "tcp"] } diff --git a/utils/prometheus/src/lib.rs b/utils/prometheus/src/lib.rs index f1d87ac9f729c..3d28d9cd6f1c8 100644 --- a/utils/prometheus/src/lib.rs +++ b/utils/prometheus/src/lib.rs @@ -47,27 +47,22 @@ pub fn register( Ok(metric) } -#[derive(Debug, derive_more::Display, derive_more::From)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// Hyper internal error. - Hyper(hyper::Error), + #[error(transparent)] + Hyper(#[from] hyper::Error), + /// Http request error. - Http(hyper::http::Error), + #[error(transparent)] + Http(#[from] hyper::http::Error), + /// i/o error. - Io(std::io::Error), - #[display(fmt = "Prometheus port {} already in use.", _0)] - PortInUse(SocketAddr), -} + #[error(transparent)] + Io(#[from] std::io::Error), -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Error::Hyper(error) => Some(error), - Error::Http(error) => Some(error), - Error::Io(error) => Some(error), - Error::PortInUse(_) => None, - } - } + #[error("Prometheus port {0} already in use.")] + PortInUse(SocketAddr), } async fn request_metrics(req: Request, registry: Registry) -> Result, Error> { From e4f9551a4d63f2f1761082439590d9865adf4dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 25 Jan 2022 20:57:56 +0100 Subject: [PATCH 0461/1472] basic-authorship: Add new metrics for block size limit and weight limit (#10697) * basic-authorship: Add new metriscs for block size limit and weight limit * Review feedback --- .../basic-authorship/src/basic_authorship.rs | 28 +++++++++------ client/proposer-metrics/src/lib.rs | 36 +++++++++++++++++-- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 5ab207e39e583..23725e5138697 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -47,7 +47,7 @@ use sp_runtime::{ use std::{marker::PhantomData, pin::Pin, sync::Arc, time}; use prometheus_endpoint::Registry as PrometheusRegistry; -use sc_proposer_metrics::MetricsLink as PrometheusMetrics; +use sc_proposer_metrics::{EndProposingReason, MetricsLink as PrometheusMetrics}; /// Default block size limit in bytes used by [`Proposer`]. /// @@ -412,16 +412,21 @@ where debug!("Attempting to push transactions from the pool."); debug!("Pool status: {:?}", self.transaction_pool.status()); let mut transaction_pushed = false; - let mut hit_block_size_limit = false; - while let Some(pending_tx) = pending_iterator.next() { + let end_reason = loop { + let pending_tx = if let Some(pending_tx) = pending_iterator.next() { + pending_tx + } else { + break EndProposingReason::NoMoreTransactions + }; + let now = (self.now)(); if now > deadline { debug!( "Consensus deadline reached when pushing block transactions, \ proceeding with proposing." ); - break + break EndProposingReason::HitDeadline } let pending_tx_data = pending_tx.data().clone(); @@ -448,8 +453,7 @@ where continue } else { debug!("Reached block size limit, proceeding with proposing."); - hit_block_size_limit = true; - break + break EndProposingReason::HitBlockSizeLimit } } @@ -473,8 +477,8 @@ where so we will try a bit more before quitting." ); } else { - debug!("Block is full, proceed with proposing."); - break + debug!("Reached block weight limit, proceeding with proposing."); + break EndProposingReason::HitBlockWeightLimit } }, Err(e) if skipped > 0 => { @@ -491,9 +495,9 @@ where unqueue_invalid.push(pending_tx_hash); }, } - } + }; - if hit_block_size_limit && !transaction_pushed { + if matches!(end_reason, EndProposingReason::HitBlockSizeLimit) && !transaction_pushed { warn!( "Hit block size limit of `{}` without including any transaction!", block_size_limit, @@ -507,6 +511,8 @@ where self.metrics.report(|metrics| { metrics.number_of_transactions.set(block.extrinsics().len() as u64); metrics.block_constructed.observe(block_timer.elapsed().as_secs_f64()); + + metrics.report_end_proposing_reason(end_reason); }); info!( @@ -518,7 +524,7 @@ where block.extrinsics().len(), block.extrinsics() .iter() - .map(|xt| format!("{}", BlakeTwo256::hash_of(xt))) + .map(|xt| BlakeTwo256::hash_of(xt).to_string()) .collect::>() .join(", ") ); diff --git a/client/proposer-metrics/src/lib.rs b/client/proposer-metrics/src/lib.rs index a34660faab5d3..c27d16ea04d7d 100644 --- a/client/proposer-metrics/src/lib.rs +++ b/client/proposer-metrics/src/lib.rs @@ -19,7 +19,8 @@ //! Prometheus basic proposer metrics. use prometheus_endpoint::{ - register, Gauge, Histogram, HistogramOpts, PrometheusError, Registry, U64, + prometheus::CounterVec, register, Gauge, Histogram, HistogramOpts, Opts, PrometheusError, + Registry, U64, }; /// Optional shareable link to basic authorship metrics. @@ -38,15 +39,24 @@ impl MetricsLink { } pub fn report(&self, do_this: impl FnOnce(&Metrics) -> O) -> Option { - Some(do_this(self.0.as_ref()?)) + self.0.as_ref().map(do_this) } } +/// The reason why proposing a block ended. +pub enum EndProposingReason { + NoMoreTransactions, + HitDeadline, + HitBlockSizeLimit, + HitBlockWeightLimit, +} + /// Authorship metrics. #[derive(Clone)] pub struct Metrics { pub block_constructed: Histogram, pub number_of_transactions: Gauge, + pub end_proposing_reason: CounterVec, pub create_inherents_time: Histogram, pub create_block_proposal_time: Histogram, } @@ -82,6 +92,28 @@ impl Metrics { ))?, registry, )?, + end_proposing_reason: register( + CounterVec::new( + Opts::new( + "substrate_proposer_end_proposal_reason", + "The reason why the block proposing was ended. This doesn't include errors.", + ), + &["reason"], + )?, + registry, + )?, }) } + + /// Report the reason why the proposing ended. + pub fn report_end_proposing_reason(&self, reason: EndProposingReason) { + let reason = match reason { + EndProposingReason::HitDeadline => "hit_deadline", + EndProposingReason::NoMoreTransactions => "no_more_transactions", + EndProposingReason::HitBlockSizeLimit => "hit_block_size_limit", + EndProposingReason::HitBlockWeightLimit => "hit_block_weight_limit", + }; + + self.end_proposing_reason.with_label_values(&[reason]).inc(); + } } From 293fbeb6903904a7d02d462d9cf8614715c1f117 Mon Sep 17 00:00:00 2001 From: Alexander Popiak Date: Wed, 26 Jan 2022 12:12:20 +0100 Subject: [PATCH 0462/1472] add CheckNonZeroSender in node-template-runtime (#10735) --- bin/node-template/runtime/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 2aa6bf1f1ae71..0b39d76fe495e 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -299,6 +299,7 @@ pub type Header = generic::Header; pub type Block = generic::Block; /// The SignedExtension to the basic transaction logic. pub type SignedExtra = ( + frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, frame_system::CheckGenesis, From b62e6183cfbdd0c7f901ef851084f07241ac22c0 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 26 Jan 2022 18:03:37 +0100 Subject: [PATCH 0463/1472] [ci] pipeline chores (#10734) * [ci] pipeline chores --- .gitlab-ci.yml | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b2716b018d6c0..f6f714ea52b10 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -209,18 +209,6 @@ default: AWS_SECRET_ACCESS_KEY: vault: cicd/gitlab/$CI_PROJECT_PATH/AWS_SECRET_ACCESS_KEY@kv file: false - AWX_TOKEN: - vault: cicd/gitlab/$CI_PROJECT_PATH/AWX_TOKEN@kv - file: false - CRATES_TOKEN: - vault: cicd/gitlab/$CI_PROJECT_PATH/CRATES_TOKEN@kv - file: false - DOCKER_CHAOS_TOKEN: - vault: cicd/gitlab/$CI_PROJECT_PATH/DOCKER_CHAOS_TOKEN@kv - file: false - DOCKER_CHAOS_USER: - vault: cicd/gitlab/$CI_PROJECT_PATH/DOCKER_CHAOS_USER@kv - file: false GITHUB_EMAIL: vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_EMAIL@kv file: false @@ -239,22 +227,13 @@ default: MATRIX_ROOM_ID: vault: cicd/gitlab/$CI_PROJECT_PATH/MATRIX_ROOM_ID@kv file: false - PIPELINE_TOKEN: - vault: cicd/gitlab/$CI_PROJECT_PATH/PIPELINE_TOKEN@kv - file: false - VALIDATOR_KEYS: - vault: cicd/gitlab/$CI_PROJECT_PATH/VALIDATOR_KEYS@kv - file: false - VALIDATOR_KEYS_CHAOS: - vault: cicd/gitlab/$CI_PROJECT_PATH/VALIDATOR_KEYS_CHAOS@kv - file: false + #### stage: .pre skip-if-draft: image: paritytech/tools:latest <<: *kubernetes-env - <<: *vault-secrets stage: .pre rules: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs @@ -270,7 +249,6 @@ check-runtime: stage: check image: paritytech/tools:latest <<: *kubernetes-env - <<: *vault-secrets rules: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs variables: @@ -285,7 +263,6 @@ check-signed-tag: stage: check image: paritytech/tools:latest <<: *kubernetes-env - <<: *vault-secrets rules: - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 @@ -548,7 +525,6 @@ cargo-check-macos: stage: build <<: *docker-env <<: *test-refs-no-trigger-prs-only - <<: *vault-secrets script: - git clone --depth=1 From 71baca710bae30b4779ea3452e41afb1de6bd1fe Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Wed, 26 Jan 2022 15:47:17 -0700 Subject: [PATCH 0464/1472] Update Node Template (#10710) * update node template from downsteam template version = 4.0.0-dev rust setup updated * Update bin/node-template/runtime/Cargo.toml Co-authored-by: Shawn Tabrizi * Review Rust setup README * Apply suggestions from code review Co-authored-by: Shawn Tabrizi Co-authored-by: Sacha Lansky --- Cargo.lock | 6 +- bin/node-template/README.md | 17 +- bin/node-template/docs/rust-setup.md | 219 +++++++++++++++--- bin/node-template/node/Cargo.toml | 5 +- bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 11 +- 6 files changed, 203 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8092fffa7c07..0dbafc147f6bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4858,7 +4858,7 @@ dependencies = [ [[package]] name = "node-template" -version = "3.0.0" +version = "4.0.0-dev" dependencies = [ "clap 3.0.7", "frame-benchmarking", @@ -4895,7 +4895,7 @@ dependencies = [ [[package]] name = "node-template-runtime" -version = "3.0.0" +version = "4.0.0-dev" dependencies = [ "frame-benchmarking", "frame-executive", @@ -6200,7 +6200,7 @@ dependencies = [ [[package]] name = "pallet-template" -version = "3.0.0" +version = "4.0.0-dev" dependencies = [ "frame-benchmarking", "frame-support", diff --git a/bin/node-template/README.md b/bin/node-template/README.md index bb4df52f41a8f..a04f6a12ed73a 100644 --- a/bin/node-template/README.md +++ b/bin/node-template/README.md @@ -72,20 +72,20 @@ Start the development chain with detailed logging: ```bash RUST_BACKTRACE=1 ./target/release/node-template -ldebug --dev ``` + > Development chain means that the state of our chain will be in a tmp folder while the nodes are -> running. Also, **alice** account will be authority and sudo account as declared in the [genesis -> state](https://github.com/substrate-developer-hub/substrate-node-template/blob/main/node/src/chain_spec.rs#L49). -> At the same time the following accounts will be prefunded: +> running. Also, **alice** account will be authority and sudo account as declared in the +> [genesis state](https://github.com/substrate-developer-hub/substrate-node-template/blob/main/node/src/chain_spec.rs#L49). +> At the same time the following accounts will be pre-funded: > - Alice > - Bob > - Alice//stash > - Bob//stash -In case of being interested in maintaining the chain' state futher in time a base path other than -a temporary directory must be added so the db can be stored in the provided folder. We could use -this folder to store different chain databases, as a different folder will be created per different - chain that is ran. The following commands shows how to use a newly created folder as our db base - path. +In case of being interested in maintaining the chain' state between runs a base path must be added +so the db can be stored in the provided folder instead of a temporal one. We could use this folder +to store different chain databases, as a different folder will be created per different chain that +is ran. The following commands shows how to use a newly created folder as our db base path. ```bash // Create a folder to use as the db base path @@ -103,6 +103,7 @@ $ ls ./my-chain-state/chains/dev db keystore network ``` + ### Connect with Polkadot-JS Apps Front-end Once the node template is running locally, you can connect it with **Polkadot-JS Apps** front-end diff --git a/bin/node-template/docs/rust-setup.md b/bin/node-template/docs/rust-setup.md index 4b96da1146b8e..ea133ca847af7 100644 --- a/bin/node-template/docs/rust-setup.md +++ b/bin/node-template/docs/rust-setup.md @@ -2,32 +2,21 @@ title: Installation --- -This page will guide you through the steps needed to prepare a computer for development with the -Substrate Node Template. Since Substrate is built with -[the Rust programming language](https://www.rust-lang.org/), the first thing you will need to do is -prepare the computer for Rust development - these steps will vary based on the computer's operating -system. Once Rust is configured, you will use its toolchains to interact with Rust projects; the -commands for Rust's toolchains will be the same for all supported, Unix-based operating systems. +This guide is for reference only, please check the latest information on getting starting with Substrate +[here](https://docs.substrate.io/v3/getting-started/installation/). -## Unix-Based Operating Systems +This page will guide you through the **2 steps** needed to prepare a computer for **Substrate** development. +Since Substrate is built with [the Rust programming language](https://www.rust-lang.org/), the first +thing you will need to do is prepare the computer for Rust development - these steps will vary based +on the computer's operating system. Once Rust is configured, you will use its toolchains to interact +with Rust projects; the commands for Rust's toolchains will be the same for all supported, +Unix-based operating systems. -Substrate development is easiest on Unix-based operating systems like macOS or Linux. The examples -in the Substrate [Tutorials](https://docs.substrate.io/tutorials/v3) and -[How-to Guides](https://docs.substrate.io/how-to-guides/v3) use Unix-style terminals to demonstrate -how to interact with Substrate from the command line. - -### macOS +## Build dependencies -Open the Terminal application and execute the following commands: - -```bash -# Install Homebrew if necessary https://brew.sh/ -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" - -# Make sure Homebrew is up-to-date, install openssl and cmake -brew update -brew install openssl cmake -``` +Substrate development is easiest on Unix-based operating systems like macOS or Linux. The examples +in the [Substrate Docs](https://docs.substrate.io) use Unix-style terminals to demonstrate how to +interact with Substrate from the command line. ### Ubuntu/Debian @@ -36,7 +25,7 @@ Use a terminal shell to execute the following commands: ```bash sudo apt update # May prompt for location information -sudo apt install -y cmake pkg-config libssl-dev git build-essential clang libclang-dev curl +sudo apt install -y git clang curl libssl-dev llvm libudev-dev ``` ### Arch Linux @@ -44,39 +33,193 @@ sudo apt install -y cmake pkg-config libssl-dev git build-essential clang libcla Run these commands from a terminal: ```bash -pacman -Syu --needed --noconfirm cmake gcc openssl-1.0 pkgconf git clang -export OPENSSL_LIB_DIR="/usr/lib/openssl-1.0" -export OPENSSL_INCLUDE_DIR="/usr/include/openssl-1.0" +pacman -Syu --needed --noconfirm curl git clang ``` -### Fedora/RHEL/CentOS +### Fedora -Use a terminal to run the following commands: +Run these commands from a terminal: ```bash -# Update sudo dnf update -# Install packages -sudo dnf install cmake pkgconfig rocksdb rocksdb-devel llvm git libcurl libcurl-devel curl-devel clang +sudo dnf install clang curl git openssl-devel +``` + +### OpenSUSE + +Run these commands from a terminal: + +```bash +sudo zypper install clang curl git openssl-devel llvm-devel libudev-devel +``` + +### macOS + +> **Apple M1 ARM** +> If you have an Apple M1 ARM system on a chip, make sure that you have Apple Rosetta 2 +> installed through `softwareupdate --install-rosetta`. This is only needed to run the +> `protoc` tool during the build. The build itself and the target binaries would remain native. + +Open the Terminal application and execute the following commands: + +```bash +# Install Homebrew if necessary https://brew.sh/ +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + +# Make sure Homebrew is up-to-date, install openssl +brew update +brew install openssl ``` -## Rust Developer Environment +### Windows + +**_PLEASE NOTE:_** Native development of Substrate is _not_ very well supported! It is _highly_ +recommend to use [Windows Subsystem Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) +(WSL) and follow the instructions for [Ubuntu/Debian](#ubuntudebian). +Please refer to the separate +[guide for native Windows development](https://docs.substrate.io/v3/getting-started/windows-users/). -This project uses [`rustup`](https://rustup.rs/) to help manage the Rust toolchain. First install -and configure `rustup`: +## Rust developer environment + +This guide uses installer and the `rustup` tool to manage the Rust toolchain. +First install and configure `rustup`: ```bash # Install -curl https://sh.rustup.rs -sSf | sh +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Configure source ~/.cargo/env ``` -Finally, configure the Rust toolchain: +Configure the Rust toolchain to default to the latest stable version, add nightly and the nightly wasm target: ```bash rustup default stable +rustup update +rustup update nightly +rustup target add wasm32-unknown-unknown --toolchain nightly +``` + +## Test your set-up + +Now the best way to ensure that you have successfully prepared a computer for Substrate +development is to follow the steps in [our first Substrate tutorial](https://docs.substrate.io/tutorials/v3/create-your-first-substrate-chain/). + +## Troubleshooting Substrate builds + +Sometimes you can't get the Substrate node template +to compile out of the box. Here are some tips to help you work through that. + +### Rust configuration check + +To see what Rust toolchain you are presently using, run: + +```bash +rustup show +``` + +This will show something like this (Ubuntu example) output: + +```text +Default host: x86_64-unknown-linux-gnu +rustup home: /home/user/.rustup + +installed toolchains +-------------------- + +stable-x86_64-unknown-linux-gnu (default) +nightly-2020-10-06-x86_64-unknown-linux-gnu +nightly-x86_64-unknown-linux-gnu + +installed targets for active toolchain +-------------------------------------- + +wasm32-unknown-unknown +x86_64-unknown-linux-gnu + +active toolchain +---------------- + +stable-x86_64-unknown-linux-gnu (default) +rustc 1.50.0 (cb75ad5db 2021-02-10) +``` + +As you can see above, the default toolchain is stable, and the +`nightly-x86_64-unknown-linux-gnu` toolchain as well as its `wasm32-unknown-unknown` target is installed. +You also see that `nightly-2020-10-06-x86_64-unknown-linux-gnu` is installed, but is not used unless explicitly defined as illustrated in the [specify your nightly version](#specifying-nightly-version) +section. + +### WebAssembly compilation + +Substrate uses [WebAssembly](https://webassembly.org) (Wasm) to produce portable blockchain +runtimes. You will need to configure your Rust compiler to use +[`nightly` builds](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) to allow you to +compile Substrate runtime code to the Wasm target. + +> There are upstream issues in Rust that need to be resolved before all of Substrate can use the stable Rust toolchain. +> [This is our tracking issue](https://github.com/paritytech/substrate/issues/1252) if you're curious as to why and how this will be resolved. + +#### Latest nightly for Substrate `master` + +Developers who are building Substrate _itself_ should always use the latest bug-free versions of +Rust stable and nightly. This is because the Substrate codebase follows the tip of Rust nightly, +which means that changes in Substrate often depend on upstream changes in the Rust nightly compiler. +To ensure your Rust compiler is always up to date, you should run: + +```bash +rustup update rustup update nightly -rustup update stable rustup target add wasm32-unknown-unknown --toolchain nightly ``` + +> NOTE: It may be necessary to occasionally rerun `rustup update` if a change in the upstream Substrate +> codebase depends on a new feature of the Rust compiler. When you do this, both your nightly +> and stable toolchains will be pulled to the most recent release, and for nightly, it is +> generally _not_ expected to compile WASM without error (although it very often does). +> Be sure to [specify your nightly version](#specifying-nightly-version) if you get WASM build errors +> from `rustup` and [downgrade nightly as needed](#downgrading-rust-nightly). + +#### Rust nightly toolchain + +If you want to guarantee that your build works on your computer as you update Rust and other +dependencies, you should use a specific Rust nightly version that is known to be +compatible with the version of Substrate they are using; this version will vary from project to +project and different projects may use different mechanisms to communicate this version to +developers. For instance, the Polkadot client specifies this information in its +[release notes](https://github.com/paritytech/polkadot/releases). + +```bash +# Specify the specific nightly toolchain in the date below: +rustup install nightly- +``` + +#### Wasm toolchain + +Now, configure the nightly version to work with the Wasm compilation target: + +```bash +rustup target add wasm32-unknown-unknown --toolchain nightly- +``` + +### Specifying nightly version + +Use the `WASM_BUILD_TOOLCHAIN` environment variable to specify the Rust nightly version a Substrate +project should use for Wasm compilation: + +```bash +WASM_BUILD_TOOLCHAIN=nightly- cargo build --release +``` + +> Note that this only builds _the runtime_ with the specified nightly. The rest of project will be +> compiled with **your default toolchain**, i.e. the latest installed stable toolchain. + +### Downgrading Rust nightly + +If your computer is configured to use the latest Rust nightly and you would like to downgrade to a +specific nightly version, follow these steps: + +```bash +rustup uninstall nightly +rustup install nightly- +rustup target add wasm32-unknown-unknown --toolchain nightly- +``` diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 6b69d691d9450..300a35252c053 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node-template" -version = "3.0.0" +version = "4.0.0-dev" description = "A fresh FRAME-based Substrate node, ready for hacking." authors = ["Substrate DevHub "] homepage = "https://substrate.io/" @@ -52,7 +52,8 @@ pallet-transaction-payment-rpc = { version = "4.0.0-dev", path = "../../../frame frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } frame-benchmarking-cli = { version = "4.0.0-dev", path = "../../../utils/frame/benchmarking-cli" } -node-template-runtime = { version = "3.0.0", path = "../runtime" } +# Local Dependencies +node-template-runtime = { version = "4.0.0-dev", path = "../runtime" } [build-dependencies] substrate-build-script-utils = { version = "3.0.0", path = "../../../utils/build-script-utils" } diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 9702501a3e0ea..4dc4fb3c6e528 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-template" -version = "3.0.0" +version = "4.0.0-dev" description = "FRAME pallet template for defining custom runtime logic." authors = ["Substrate DevHub "] homepage = "https://substrate.io/" diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index b757029f2581d..eb8fb9eb52a87 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "node-template-runtime" -version = "3.0.0" -description = "A fresh FRAME-based Substrate runtime, ready for hacking." +version = "4.0.0-dev" +description = "A fresh FRAME-based Substrate node, ready for hacking." authors = ["Substrate DevHub "] homepage = "https://substrate.io/" edition = "2021" @@ -27,10 +27,10 @@ pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = ".. pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" } frame-executive = { version = "4.0.0-dev", default-features = false, path = "../../../frame/executive" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-block-builder = { path = "../../../primitives/block-builder", default-features = false, version = "4.0.0-dev"} +sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/block-builder"} sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/consensus/aura" } sp-core = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/core" } -sp-inherents = { path = "../../../primitives/inherents", default-features = false, version = "4.0.0-dev"} +sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents"} sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } sp-runtime = { version = "4.1.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } @@ -47,7 +47,8 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system/benchmarking", optional = true } hex-literal = { version = "0.3.4", optional = true } -pallet-template = { version = "3.0.0", default-features = false, path = "../pallets/template" } +# Local Dependencies +pallet-template = { version = "4.0.0-dev", default-features = false, path = "../pallets/template" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } From da534d7f945c72b373f157826a95786543a6ec9c Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 27 Jan 2022 11:00:48 +0100 Subject: [PATCH 0465/1472] better way to resolve `Phase::Emergency` via governance (#10663) * better way to resolve Phase::Emergency via governance * Update frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Zeke Mostov * review grumbles * Update frame/election-provider-support/src/onchain.rs Co-authored-by: Shawn Tabrizi * revert usize -> u32 Co-authored-by: Zeke Mostov Co-authored-by: Shawn Tabrizi --- bin/node/runtime/src/lib.rs | 14 +++-- .../election-provider-multi-phase/src/lib.rs | 60 ++++++++++++++++++- .../election-provider-multi-phase/src/mock.rs | 1 + frame/election-provider-support/src/lib.rs | 16 +++++ .../election-provider-support/src/onchain.rs | 53 ++++++++++++---- 5 files changed, 122 insertions(+), 22 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8f00dd8f64b4c..e70adc6aa7238 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -23,6 +23,7 @@ #![recursion_limit = "256"] use codec::{Decode, Encode, MaxEncodedLen}; +use frame_election_provider_support::onchain; use frame_support::{ construct_runtime, parameter_types, traits::{ @@ -528,12 +529,6 @@ parameter_types! { pub OffchainRepeat: BlockNumber = 5; } -use frame_election_provider_support::onchain; -impl onchain::Config for Runtime { - type Accuracy = Perbill; - type DataProvider = Staking; -} - pub struct StakingBenchmarkingConfig; impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { type MaxNominators = ConstU32<1000>; @@ -649,6 +644,11 @@ impl frame_support::pallet_prelude::Get::DataProvider; +} + impl pallet_election_provider_multi_phase::Config for Runtime { type Event = Event; type Currency = Balances; @@ -671,6 +671,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type DataProvider = Staking; type Solution = NposSolution16; type Fallback = pallet_election_provider_multi_phase::NoFallback; + type GovernanceFallback = + frame_election_provider_support::onchain::OnChainSequentialPhragmen; type Solver = frame_election_provider_support::SequentialPhragmen< AccountId, pallet_election_provider_multi_phase::SolutionAccuracyOf, diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index f1d1d78912c46..2b48373c5b0ea 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -230,7 +230,9 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; -use frame_election_provider_support::{ElectionDataProvider, ElectionProvider}; +use frame_election_provider_support::{ + ElectionDataProvider, ElectionProvider, InstantElectionProvider, +}; use frame_support::{ dispatch::DispatchResultWithPostInfo, ensure, @@ -322,6 +324,15 @@ impl ElectionProvider for NoFallback { } } +impl InstantElectionProvider for NoFallback { + fn instant_elect( + _: Option, + _: Option, + ) -> Result, Self::Error> { + Err("NoFallback.") + } +} + /// Current phase of the pallet. #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] pub enum Phase { @@ -555,7 +566,7 @@ pub use pallet::*; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_election_provider_support::NposSolver; + use frame_election_provider_support::{InstantElectionProvider, NposSolver}; use frame_support::{pallet_prelude::*, traits::EstimateCallFee}; use frame_system::pallet_prelude::*; @@ -672,13 +683,23 @@ pub mod pallet { + NposSolution + TypeInfo; - /// Configuration for the fallback + /// Configuration for the fallback. type Fallback: ElectionProvider< AccountId = Self::AccountId, BlockNumber = Self::BlockNumber, DataProvider = Self::DataProvider, >; + /// Configuration of the governance-only fallback. + /// + /// As a side-note, it is recommend for test-nets to use `type ElectionProvider = + /// OnChainSeqPhragmen<_>` if the test-net is not expected to have thousands of nominators. + type GovernanceFallback: InstantElectionProvider< + AccountId = Self::AccountId, + BlockNumber = Self::BlockNumber, + DataProvider = Self::DataProvider, + >; + /// OCW election solution miner algorithm implementation. type Solver: NposSolver; @@ -1013,6 +1034,37 @@ pub mod pallet { }); Ok(()) } + + /// Trigger the governance fallback. + /// + /// This can only be called when [`Phase::Emergency`] is enabled, as an alternative to + /// calling [`Call::set_emergency_election_result`]. + #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] + pub fn governance_fallback( + origin: OriginFor, + maybe_max_voters: Option, + maybe_max_targets: Option, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + ensure!(Self::current_phase().is_emergency(), >::CallNotAllowed); + + let maybe_max_voters = maybe_max_voters.map(|x| x as usize); + let maybe_max_targets = maybe_max_targets.map(|x| x as usize); + + let supports = + T::GovernanceFallback::instant_elect(maybe_max_voters, maybe_max_targets).map_err( + |e| { + log!(error, "GovernanceFallback failed: {:?}", e); + Error::::FallbackFailed + }, + )?; + + let solution = + ReadySolution { supports, score: [0, 0, 0], compute: ElectionCompute::Fallback }; + + >::put(solution); + Ok(()) + } } #[pallet::event] @@ -1063,6 +1115,8 @@ pub mod pallet { InvalidSubmissionIndex, /// The call is not allowed at this point. CallNotAllowed, + /// The fallback failed + FallbackFailed, } #[pallet::validate_unsigned] diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 1be93c363e321..9ac0ecfef5dce 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -410,6 +410,7 @@ impl crate::Config for Runtime { type WeightInfo = DualMockWeightInfo; type BenchmarkingConfig = TestBenchmarkingConfig; type Fallback = MockFallback; + type GovernanceFallback = NoFallback; type ForceOrigin = frame_system::EnsureRoot; type Solution = TestNposSolution; type VoterSnapshotPerBlock = VoterSnapshotPerBlock; diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 3374e1e97b8be..26efe5107b670 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -319,6 +319,22 @@ pub trait ElectionProvider { fn elect() -> Result, Self::Error>; } +/// A sub-trait of the [`ElectionProvider`] for cases where we need to be sure an election needs to +/// happen instantly, not asynchronously. +/// +/// The same `DataProvider` is assumed to be used. +/// +/// Consequently, allows for control over the amount of data that is being fetched from the +/// [`ElectionProvider::DataProvider`]. +pub trait InstantElectionProvider: ElectionProvider { + /// Elect a new set of winners, instantly, with the given given limits set on the + /// `DataProvider`. + fn instant_elect( + maybe_max_voters: Option, + maybe_max_targets: Option, + ) -> Result, Self::Error>; +} + /// An election provider to be used only for testing. #[cfg(feature = "std")] pub struct NoElection(sp_std::marker::PhantomData); diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 808b49ba6234d..41245f67fb02c 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -17,7 +17,7 @@ //! An implementation of [`ElectionProvider`] that does an on-chain sequential phragmen. -use crate::{ElectionDataProvider, ElectionProvider}; +use crate::{ElectionDataProvider, ElectionProvider, InstantElectionProvider}; use frame_support::{traits::Get, weights::DispatchClass}; use sp_npos_elections::*; use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; @@ -47,8 +47,14 @@ impl From for Error { /// implementation ignores the additional data of the election data provider and gives no insight on /// how much weight was consumed. /// -/// Finally, this implementation does not impose any limits on the number of voters and targets that -/// are provided. +/// Finally, the [`ElectionProvider`] implementation of this type does not impose any limits on the +/// number of voters and targets that are fetched. This could potentially make this unsuitable for +/// execution onchain. On the other hand, the [`InstantElectionProvider`] implementation does limit +/// these inputs. +/// +/// It is advisable to use the former ([`ElectionProvider::elect`]) only at genesis, or for testing, +/// the latter [`InstantElectionProvider::instant_elect`] for onchain operations, with thoughtful +/// bounds. pub struct OnChainSequentialPhragmen(PhantomData); /// Configuration trait of [`OnChainSequentialPhragmen`]. @@ -68,16 +74,17 @@ pub trait Config: frame_system::Config { >; } -impl ElectionProvider for OnChainSequentialPhragmen { - type AccountId = T::AccountId; - type BlockNumber = T::BlockNumber; - type Error = Error; - type DataProvider = T::DataProvider; - - fn elect() -> Result, Self::Error> { - let voters = Self::DataProvider::voters(None).map_err(Error::DataProvider)?; - let targets = Self::DataProvider::targets(None).map_err(Error::DataProvider)?; - let desired_targets = Self::DataProvider::desired_targets().map_err(Error::DataProvider)?; +impl OnChainSequentialPhragmen { + fn elect_with( + maybe_max_voters: Option, + maybe_max_targets: Option, + ) -> Result, Error> { + let voters = ::DataProvider::voters(maybe_max_voters) + .map_err(Error::DataProvider)?; + let targets = ::DataProvider::targets(maybe_max_targets) + .map_err(Error::DataProvider)?; + let desired_targets = ::DataProvider::desired_targets() + .map_err(Error::DataProvider)?; let stake_map: BTreeMap = voters .iter() @@ -102,6 +109,26 @@ impl ElectionProvider for OnChainSequentialPhragmen { } } +impl ElectionProvider for OnChainSequentialPhragmen { + type AccountId = T::AccountId; + type BlockNumber = T::BlockNumber; + type Error = Error; + type DataProvider = T::DataProvider; + + fn elect() -> Result, Self::Error> { + Self::elect_with(None, None) + } +} + +impl InstantElectionProvider for OnChainSequentialPhragmen { + fn instant_elect( + maybe_max_voters: Option, + maybe_max_targets: Option, + ) -> Result, Self::Error> { + Self::elect_with(maybe_max_voters, maybe_max_targets) + } +} + #[cfg(test)] mod tests { use super::*; From 3c1d5b9a53ee1f6c045296666772e3b78f6da733 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 27 Jan 2022 18:21:58 +0100 Subject: [PATCH 0466/1472] Add stale branches heads to finality notifications (#10639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add stale branches heads to finality notifications Warning. Previous implementation was sending a notification for each block between the previous (explicitly) finalized block and the new finalized one (with an hardcoded limit of 256). Now finality notification is sent only for the new finalized head and it contains the hash of the new finalized head, new finalized head header, a list of all the implicitly finalized blocks and a list of stale branches heads (i.e. the branches heads that are not part of the canonical chain anymore). * Add implicitly finalized blocks list to `ChainEvent::Finalized` message The list contains all the blocks between the previously finalized block up to the parent of the currently finalized one, sorted by block number. `Finalized` messages handler, part of the `MaintainedTransactionPool` implementation for `BasicPool`, still propagate full set of finalized blocks to the txpool by iterating over implicitly finalized blocks list. * Rust fmt * Greedy evaluation of `stale_heads` during finalization * Fix outdated assumption in a comment * Removed a test optimization that is no more relevant The loop was there to prevent sending to `peer.network.on_block_finalized` the full list of finalized blocks. Now only the finalized heads are received. * Last finalized block lookup not required anymore * Tests for block finality notifications payloads * Document a bit tricky condition to avoid duplicate finalization notifications * More idiomatic way to skip an iterator entry Co-authored-by: Bastian Köcher * Cargo fmt iteration * Typo fix Co-authored-by: Bastian Köcher * Fix potential failure when a finalized orphan block is imported * Apply suggestions from code review Co-authored-by: Bastian Köcher * Apply suggestions from code review Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- client/api/src/backend.rs | 18 +- client/api/src/client.rs | 10 +- .../src/protocol/sync/extra_requests.rs | 4 +- client/network/test/src/lib.rs | 8 +- client/service/src/client/client.rs | 162 ++++++++++++------ client/service/src/lib.rs | 25 +-- client/service/test/src/client/mod.rs | 151 +++++++++++++++- client/transaction-pool/api/src/lib.rs | 6 +- client/transaction-pool/src/lib.rs | 16 +- client/transaction-pool/tests/pool.rs | 14 +- 10 files changed, 303 insertions(+), 111 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 004c0574fcbe8..bb2579e4a420e 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -70,14 +70,26 @@ pub struct ImportSummary { pub tree_route: Option>, } -/// Import operation wrapper +/// Finalization operation summary. +/// +/// Contains information about the block that just got finalized, +/// including tree heads that became stale at the moment of finalization. +pub struct FinalizeSummary { + /// Blocks that were finalized. + /// The last entry is the one that has been explicitly finalized. + pub finalized: Vec, + /// Heads that became stale during this finalization operation. + pub stale_heads: Vec, +} + +/// Import operation wrapper. pub struct ClientImportOperation> { /// DB Operation. pub op: B::BlockImportOperation, /// Summary of imported block. pub notify_imported: Option>, - /// A list of hashes of blocks that got finalized. - pub notify_finalized: Vec, + /// Summary of finalized block. + pub notify_finalized: Option>, } /// Helper function to apply auxiliary data insertion into an operation. diff --git a/client/api/src/client.rs b/client/api/src/client.rs index b6a5fbfad47a5..9bb212099565b 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -273,10 +273,14 @@ pub struct BlockImportNotification { /// Summary of a finalized block. #[derive(Clone, Debug)] pub struct FinalityNotification { - /// Imported block header hash. + /// Finalized block header hash. pub hash: Block::Hash, - /// Imported block header. + /// Finalized block header. pub header: Block::Header, + /// Path from the old finalized to new finalized parent (implicitly finalized blocks). + pub tree_route: Arc>, + /// Stale branches heads. + pub stale_heads: Arc>, } impl TryFrom> for ChainEvent { @@ -293,6 +297,6 @@ impl TryFrom> for ChainEvent { impl From> for ChainEvent { fn from(n: FinalityNotification) -> Self { - Self::Finalized { hash: n.hash } + Self::Finalized { hash: n.hash, tree_route: n.tree_route } } } diff --git a/client/network/src/protocol/sync/extra_requests.rs b/client/network/src/protocol/sync/extra_requests.rs index 680094a74143e..224fbd1a1e01a 100644 --- a/client/network/src/protocol/sync/extra_requests.rs +++ b/client/network/src/protocol/sync/extra_requests.rs @@ -173,9 +173,7 @@ impl ExtraRequests { } if best_finalized_number > self.best_seen_finalized_number { - // normally we'll receive finality notifications for every block => finalize would be - // enough but if many blocks are finalized at once, some notifications may be omitted - // => let's use finalize_with_ancestors here + // we receive finality notification only for the finalized branch head. match self.tree.finalize_with_ancestors( best_finalized_hash, best_finalized_number, diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index d9e27ce575110..b2345f3701b0a 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -976,14 +976,10 @@ where peer.network.service().announce_block(notification.hash, None); } - // We poll `finality_notification_stream`, but we only take the last event. - let mut last = None; - while let Poll::Ready(Some(item)) = + // We poll `finality_notification_stream`. + while let Poll::Ready(Some(notification)) = peer.finality_notification_stream.as_mut().poll_next(cx) { - last = Some(item); - } - if let Some(notification) = last { peer.network.on_block_finalized(notification.hash, notification.header); } } diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 7673a7b4c5387..e8ca5343aa0d2 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -30,8 +30,8 @@ use rand::Rng; use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider, RecordProof}; use sc_client_api::{ backend::{ - self, apply_aux, BlockImportOperation, ClientImportOperation, Finalizer, ImportSummary, - LockImportRun, NewBlockState, StorageProvider, + self, apply_aux, BlockImportOperation, ClientImportOperation, FinalizeSummary, Finalizer, + ImportSummary, LockImportRun, NewBlockState, StorageProvider, }, client::{ BadBlocks, BlockBackend, BlockImportNotification, BlockOf, BlockchainEvents, ClientInfo, @@ -274,7 +274,7 @@ where let mut op = ClientImportOperation { op: self.backend.begin_operation()?, notify_imported: None, - notify_finalized: Vec::new(), + notify_finalized: None, }; let r = f(&mut op)?; @@ -622,18 +622,6 @@ where None }, }; - // Ensure parent chain is finalized to maintain invariant that - // finality is called sequentially. This will also send finality - // notifications for top 250 newly finalized blocks. - if finalized && parent_exists { - self.apply_finality_with_block_hash( - operation, - parent_hash, - None, - info.best_hash, - make_notifications, - )?; - } operation.op.update_cache(new_cache); storage_changes @@ -641,6 +629,18 @@ where None => None, }; + // Ensure parent chain is finalized to maintain invariant that finality is called + // sequentially. + if finalized && parent_exists { + self.apply_finality_with_block_hash( + operation, + parent_hash, + None, + info.best_hash, + make_notifications, + )?; + } + let is_new_best = !gap_block && (finalized || match fork_choice { @@ -683,11 +683,36 @@ where operation.op.insert_aux(aux)?; - // we only notify when we are already synced to the tip of the chain + // We only notify when we are already synced to the tip of the chain // or if this import triggers a re-org if make_notifications || tree_route.is_some() { if finalized { - operation.notify_finalized.push(hash); + let mut summary = match operation.notify_finalized.take() { + Some(summary) => summary, + None => FinalizeSummary { finalized: Vec::new(), stale_heads: Vec::new() }, + }; + summary.finalized.push(hash); + if parent_exists { + // Add to the stale list all heads that are branching from parent besides our + // current `head`. + for head in self + .backend + .blockchain() + .leaves()? + .into_iter() + .filter(|h| *h != parent_hash) + { + let route_from_parent = sp_blockchain::tree_route( + self.backend.blockchain(), + parent_hash, + head, + )?; + if route_from_parent.retracted().is_empty() { + summary.stale_heads.push(head); + } + } + } + operation.notify_finalized = Some(summary); } operation.notify_imported = Some(ImportSummary { @@ -831,58 +856,82 @@ where operation.op.mark_finalized(BlockId::Hash(block), justification)?; if notify { - // sometimes when syncing, tons of blocks can be finalized at once. - // we'll send notifications spuriously in that case. - const MAX_TO_NOTIFY: usize = 256; - let enacted = route_from_finalized.enacted(); - let start = enacted.len() - std::cmp::min(enacted.len(), MAX_TO_NOTIFY); - for finalized in &enacted[start..] { - operation.notify_finalized.push(finalized.hash); + let finalized = + route_from_finalized.enacted().iter().map(|elem| elem.hash).collect::>(); + + let last_finalized_number = self + .backend + .blockchain() + .number(last_finalized)? + .expect("Finalized block expected to be onchain; qed"); + let mut stale_heads = Vec::new(); + for head in self.backend.blockchain().leaves()? { + let route_from_finalized = + sp_blockchain::tree_route(self.backend.blockchain(), block, head)?; + let retracted = route_from_finalized.retracted(); + let pivot = route_from_finalized.common_block(); + // It is not guaranteed that `backend.blockchain().leaves()` doesn't return + // heads that were in a stale state before this finalization and thus already + // included in previous notifications. We want to skip such heads. + // Given the "route" from the currently finalized block to the head under + // analysis, the condition for it to be added to the new stale heads list is: + // `!retracted.is_empty() && last_finalized_number <= pivot.number` + // 1. "route" has some "retractions". + // 2. previously finalized block number is not greater than the "route" pivot: + // - if `last_finalized_number <= pivot.number` then this is a new stale head; + // - else the stale head was already included by some previous finalization. + if !retracted.is_empty() && last_finalized_number <= pivot.number { + stale_heads.push(head); + } } + operation.notify_finalized = Some(FinalizeSummary { finalized, stale_heads }); } Ok(()) } - fn notify_finalized(&self, notify_finalized: Vec) -> sp_blockchain::Result<()> { + fn notify_finalized( + &self, + notify_finalized: Option>, + ) -> sp_blockchain::Result<()> { let mut sinks = self.finality_notification_sinks.lock(); - if notify_finalized.is_empty() { - // cleanup any closed finality notification sinks - // since we won't be running the loop below which - // would also remove any closed sinks. - sinks.retain(|sink| !sink.is_closed()); - - return Ok(()) - } + let mut notify_finalized = match notify_finalized { + Some(notify_finalized) => notify_finalized, + None => { + // Cleanup any closed finality notification sinks + // since we won't be running the loop below which + // would also remove any closed sinks. + sinks.retain(|sink| !sink.is_closed()); + return Ok(()) + }, + }; - // We assume the list is sorted and only want to inform the - // telemetry once about the finalized block. - if let Some(last) = notify_finalized.last() { - let header = self.header(&BlockId::Hash(*last))?.expect( - "Header already known to exist in DB because it is indicated in the tree route; \ - qed", - ); + let last = notify_finalized.finalized.pop().expect( + "At least one finalized block shall exist within a valid finalization summary; qed", + ); - telemetry!( - self.telemetry; - SUBSTRATE_INFO; - "notify.finalized"; - "height" => format!("{}", header.number()), - "best" => ?last, - ); - } + let header = self.header(&BlockId::Hash(last))?.expect( + "Header already known to exist in DB because it is indicated in the tree route; \ + qed", + ); - for finalized_hash in notify_finalized { - let header = self.header(&BlockId::Hash(finalized_hash))?.expect( - "Header already known to exist in DB because it is indicated in the tree route; \ - qed", - ); + telemetry!( + self.telemetry; + SUBSTRATE_INFO; + "notify.finalized"; + "height" => format!("{}", header.number()), + "best" => ?last, + ); - let notification = FinalityNotification { header, hash: finalized_hash }; + let notification = FinalityNotification { + hash: last, + header, + tree_route: Arc::new(notify_finalized.finalized), + stale_heads: Arc::new(notify_finalized.stale_heads), + }; - sinks.retain(|sink| sink.unbounded_send(notification.clone()).is_ok()); - } + sinks.retain(|sink| sink.unbounded_send(notification.clone()).is_ok()); Ok(()) } @@ -901,7 +950,6 @@ where // temporary leak of closed/discarded notification sinks (e.g. // from consensus code). self.import_notification_sinks.lock().retain(|sink| !sink.is_closed()); - return Ok(()) }, }; diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 9710ba9e3d84f..430a818c0f47c 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -34,10 +34,10 @@ mod client; mod metrics; mod task_manager; -use std::{collections::HashMap, io, net::SocketAddr, pin::Pin, task::Poll}; +use std::{collections::HashMap, io, net::SocketAddr, pin::Pin}; use codec::{Decode, Encode}; -use futures::{stream, Future, FutureExt, Stream, StreamExt}; +use futures::{Future, FutureExt, StreamExt}; use log::{debug, error, warn}; use sc_network::PeerId; use sc_utils::mpsc::TracingUnboundedReceiver; @@ -152,26 +152,7 @@ async fn build_network_future< let starting_block = client.info().best_number; // Stream of finalized blocks reported by the client. - let mut finality_notification_stream = { - let mut finality_notification_stream = client.finality_notification_stream().fuse(); - - // We tweak the `Stream` in order to merge together multiple items if they happen to be - // ready. This way, we only get the latest finalized block. - stream::poll_fn(move |cx| { - let mut last = None; - while let Poll::Ready(Some(item)) = - Pin::new(&mut finality_notification_stream).poll_next(cx) - { - last = Some(item); - } - if let Some(last) = last { - Poll::Ready(Some(last)) - } else { - Poll::Pending - } - }) - .fuse() - }; + let mut finality_notification_stream = client.finality_notification_stream().fuse(); loop { futures::select! { diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 535edfadaf29d..2b0ea460c4dd3 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -20,7 +20,9 @@ use futures::executor::block_on; use hex_literal::hex; use parity_scale_codec::{Decode, Encode, Joiner}; use sc_block_builder::BlockBuilderProvider; -use sc_client_api::{in_mem, BlockBackend, BlockchainEvents, StorageProvider}; +use sc_client_api::{ + in_mem, BlockBackend, BlockchainEvents, FinalityNotifications, StorageProvider, +}; use sc_client_db::{ Backend, DatabaseSettings, DatabaseSource, KeepBlocks, PruningMode, TransactionStorageMode, }; @@ -165,6 +167,24 @@ fn block1(genesis_hash: Hash, backend: &InMemoryBackend) -> (Vec, + finalized: &[Hash], + stale_heads: &[Hash], +) { + match notifications.try_next() { + Ok(Some(notif)) => { + let stale_heads_expected: HashSet<_> = stale_heads.iter().collect(); + let stale_heads: HashSet<_> = notif.stale_heads.iter().collect(); + assert_eq!(notif.tree_route.as_ref(), &finalized[..finalized.len() - 1]); + assert_eq!(notif.hash, *finalized.last().unwrap()); + assert_eq!(stale_heads, stale_heads_expected); + }, + Ok(None) => panic!("unexpected notification result, client send channel was closed"), + Err(_) => assert!(finalized.is_empty()), + } +} + #[test] fn construct_genesis_should_work_with_native() { let mut storage = GenesisConfig::new( @@ -822,8 +842,12 @@ fn best_containing_on_longest_chain_with_max_depth_higher_than_best() { #[test] fn import_with_justification() { + // block tree: + // G -> A1 -> A2 -> A3 let mut client = substrate_test_runtime_client::new(); + let mut finality_notifications = client.finality_notification_stream(); + // G -> A1 let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); @@ -855,6 +879,10 @@ fn import_with_justification() { assert_eq!(client.justifications(&BlockId::Hash(a1.hash())).unwrap(), None); assert_eq!(client.justifications(&BlockId::Hash(a2.hash())).unwrap(), None); + + finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[]); + finality_notification_check(&mut finality_notifications, &[a3.hash()], &[]); + assert!(finality_notifications.try_next().is_err()); } #[test] @@ -864,6 +892,9 @@ fn importing_diverged_finalized_block_should_trigger_reorg() { // G -> A1 -> A2 // \ // -> B1 + + let mut finality_notifications = client.finality_notification_stream(); + let a1 = client .new_block_at(&BlockId::Number(0), Default::default(), false) .unwrap() @@ -902,6 +933,9 @@ fn importing_diverged_finalized_block_should_trigger_reorg() { assert_eq!(client.chain_info().best_hash, b1.hash()); assert_eq!(client.chain_info().finalized_hash, b1.hash()); + + finality_notification_check(&mut finality_notifications, &[b1.hash()], &[a2.hash()]); + assert!(finality_notifications.try_next().is_err()); } #[test] @@ -911,6 +945,9 @@ fn finalizing_diverged_block_should_trigger_reorg() { // G -> A1 -> A2 // \ // -> B1 -> B2 + + let mut finality_notifications = client.finality_notification_stream(); + let a1 = client .new_block_at(&BlockId::Number(0), Default::default(), false) .unwrap() @@ -975,6 +1012,113 @@ fn finalizing_diverged_block_should_trigger_reorg() { block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap(); assert_eq!(client.chain_info().best_hash, b3.hash()); + + finality_notification_check(&mut finality_notifications, &[b1.hash()], &[a2.hash()]); + assert!(finality_notifications.try_next().is_err()); +} + +#[test] +fn finality_notifications_content() { + let (mut client, _select_chain) = TestClientBuilder::new().build_with_longest_chain(); + + // -> D3 -> D4 + // G -> A1 -> A2 -> A3 + // -> B1 -> B2 + // -> C1 + + let mut finality_notifications = client.finality_notification_stream(); + + let a1 = client + .new_block_at(&BlockId::Number(0), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); + + let a2 = client + .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); + + let a3 = client + .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); + + let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + // needed to make sure B1 gets a different hash from A1 + b1.push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 1, + nonce: 0, + }) + .unwrap(); + let b1 = b1.build().unwrap().block; + block_on(client.import(BlockOrigin::Own, b1.clone())).unwrap(); + + let b2 = client + .new_block_at(&BlockId::Hash(b1.hash()), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); + + let mut c1 = client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + // needed to make sure B1 gets a different hash from A1 + c1.push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 2, + nonce: 0, + }) + .unwrap(); + let c1 = c1.build().unwrap().block; + block_on(client.import(BlockOrigin::Own, c1.clone())).unwrap(); + + let mut d3 = client + .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .unwrap(); + // needed to make sure D3 gets a different hash from A3 + d3.push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 2, + nonce: 0, + }) + .unwrap(); + let d3 = d3.build().unwrap().block; + block_on(client.import(BlockOrigin::Own, d3.clone())).unwrap(); + + let d4 = client + .new_block_at(&BlockId::Hash(d3.hash()), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + + // Postpone import to test behavior of import of finalized block. + + ClientExt::finalize_block(&client, BlockId::Hash(a2.hash()), None).unwrap(); + + // Import and finalize D4 + block_on(client.import_as_final(BlockOrigin::Own, d4.clone())).unwrap(); + + finality_notification_check( + &mut finality_notifications, + &[a1.hash(), a2.hash()], + &[c1.hash(), b2.hash()], + ); + finality_notification_check(&mut finality_notifications, &[d3.hash(), d4.hash()], &[a3.hash()]); + assert!(finality_notifications.try_next().is_err()); } #[test] @@ -1069,6 +1213,8 @@ fn doesnt_import_blocks_that_revert_finality() { let mut client = TestClientBuilder::with_backend(backend).build(); + let mut finality_notifications = client.finality_notification_stream(); + // -> C1 // / // G -> A1 -> A2 @@ -1150,6 +1296,9 @@ fn doesnt_import_blocks_that_revert_finality() { ConsensusError::ClientImport(sp_blockchain::Error::NotInFinalizedChain.to_string()); assert_eq!(import_err.to_string(), expected_err.to_string()); + + finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[b2.hash()]); + assert!(finality_notifications.try_next().is_err()); } #[test] diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index f19a994b1b947..757674a03e850 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -278,7 +278,7 @@ impl ReadyTransactions for std::iter::Empty { /// Events that the transaction pool listens for. pub enum ChainEvent { - /// New best block have been added to the chain + /// New best block have been added to the chain. NewBestBlock { /// Hash of the block. hash: B::Hash, @@ -289,8 +289,10 @@ pub enum ChainEvent { }, /// An existing block has been finalized. Finalized { - /// Hash of just finalized block + /// Hash of just finalized block. hash: B::Hash, + /// Path from old finalized to new finalized parent. + tree_route: Arc>, }, } diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index b5af2d12d65c9..260d938217ad4 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -709,15 +709,17 @@ where } .boxed() }, - ChainEvent::Finalized { hash } => { + ChainEvent::Finalized { hash, tree_route } => { let pool = self.pool.clone(); async move { - if let Err(e) = pool.validated_pool().on_block_finalized(hash).await { - log::warn!( - target: "txpool", - "Error [{}] occurred while attempting to notify watchers of finalization {}", - e, hash - ) + for hash in tree_route.iter().chain(&[hash]) { + if let Err(e) = pool.validated_pool().on_block_finalized(*hash).await { + log::warn!( + target: "txpool", + "Error [{}] occurred while attempting to notify watchers of finalization {}", + e, hash + ) + } } } .boxed() diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 4aeaf79a61540..21a87f6e006ec 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -387,7 +387,7 @@ fn should_push_watchers_during_maintenance() { let header_hash = header.hash(); block_on(pool.maintain(block_event(header))); - let event = ChainEvent::Finalized { hash: header_hash.clone() }; + let event = ChainEvent::Finalized { hash: header_hash.clone(), tree_route: Arc::new(vec![]) }; block_on(pool.maintain(event)); // then @@ -445,7 +445,7 @@ fn finalization() { let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; block_on(pool.maintain(event)); - let event = ChainEvent::Finalized { hash: header.hash() }; + let event = ChainEvent::Finalized { hash: header.hash(), tree_route: Arc::new(vec![]) }; block_on(pool.maintain(event)); let mut stream = futures::executor::block_on_stream(watcher); @@ -493,7 +493,7 @@ fn fork_aware_finalization() { b1 = header.hash(); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 0); - let event = ChainEvent::Finalized { hash: b1 }; + let event = ChainEvent::Finalized { hash: b1, tree_route: Arc::new(vec![]) }; block_on(pool.maintain(event)); } @@ -537,7 +537,7 @@ fn fork_aware_finalization() { block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 2); - let event = ChainEvent::Finalized { hash: header.hash() }; + let event = ChainEvent::Finalized { hash: header.hash(), tree_route: Arc::new(vec![]) }; block_on(pool.maintain(event)); } @@ -554,7 +554,7 @@ fn fork_aware_finalization() { d1 = header.hash(); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 2); - let event = ChainEvent::Finalized { hash: d1 }; + let event = ChainEvent::Finalized { hash: d1, tree_route: Arc::new(vec![]) }; block_on(pool.maintain(event)); } @@ -567,7 +567,7 @@ fn fork_aware_finalization() { let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 0); - block_on(pool.maintain(ChainEvent::Finalized { hash: e1 })); + block_on(pool.maintain(ChainEvent::Finalized { hash: e1, tree_route: Arc::new(vec![]) })); } for (canon_watcher, h) in canon_watchers { @@ -637,7 +637,7 @@ fn prune_and_retract_tx_at_same_time() { block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 0); - let event = ChainEvent::Finalized { hash: header.hash() }; + let event = ChainEvent::Finalized { hash: header.hash(), tree_route: Arc::new(vec![]) }; block_on(pool.maintain(event)); header.hash() From 8c3992521c135b8c07e5ec767bbcfabdcc06e090 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 28 Jan 2022 10:04:52 +0100 Subject: [PATCH 0467/1472] remote ext: make it possible to use an existing ws connection (#10737) * remote ext: make it possible to pass ws client * grumbles: introduce `map_uri` --- Cargo.lock | 216 +++++++++++++++--- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/remote-externalities/src/lib.rs | 70 ++++-- .../frame/remote-externalities/src/rpc_api.rs | 4 +- 4 files changed, 232 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0dbafc147f6bb..b57f06c50ed22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1438,7 +1438,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" dependencies = [ - "sct", + "sct 0.6.0", ] [[package]] @@ -2425,8 +2425,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a1387e07917c711fb4ee4f48ea0adb04a3c9739e53ef85bf43ae1edc2937a8b" dependencies = [ "futures-io", - "rustls", - "webpki", + "rustls 0.19.1", + "webpki 0.21.4", ] [[package]] @@ -2874,11 +2874,11 @@ dependencies = [ "futures-util", "hyper 0.14.16", "log 0.4.14", - "rustls", - "rustls-native-certs", + "rustls 0.19.1", + "rustls-native-certs 0.5.0", "tokio", - "tokio-rustls", - "webpki", + "tokio-rustls 0.22.0", + "webpki 0.21.4", ] [[package]] @@ -3240,19 +3240,73 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373a33d987866ccfe1af4bc11b089dce941764313f9fd8b7cf13fcb51b72dc5" dependencies = [ - "jsonrpsee-proc-macros", - "jsonrpsee-types", + "jsonrpsee-types 0.4.1", "jsonrpsee-utils", - "jsonrpsee-ws-client", + "jsonrpsee-ws-client 0.4.1", +] + +[[package]] +name = "jsonrpsee" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05fd8cd6c6b1bbd06881d2cf88f1fc83cc36c98f2219090f839115fb4a956cb9" +dependencies = [ + "jsonrpsee-core", + "jsonrpsee-proc-macros", + "jsonrpsee-types 0.8.0", + "jsonrpsee-ws-client 0.8.0", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3303cdf246e6ab76e2866fb3d9acb6c76a068b1b28bd923a1b7a8122257ad7b5" +dependencies = [ + "futures 0.3.16", + "http", + "jsonrpsee-core", + "jsonrpsee-types 0.8.0", + "pin-project 1.0.10", + "rustls-native-certs 0.6.1", + "soketto 0.7.1", + "thiserror", + "tokio", + "tokio-rustls 0.23.2", + "tokio-util", + "tracing", + "webpki-roots 0.22.2", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f220b5a238dc7992b90f1144fbf6eaa585872c9376afe6fe6863ffead6191bf3" +dependencies = [ + "anyhow", + "arrayvec 0.7.1", + "async-trait", + "beef", + "futures-channel", + "futures-util", + "hyper 0.14.16", + "jsonrpsee-types 0.8.0", + "rustc-hash", + "serde", + "serde_json", + "soketto 0.7.1", + "thiserror", + "tokio", + "tracing", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.4.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d802063f7a3c867456955f9d2f15eb3ee0edb5ec9ec2b5526324756759221c0f" +checksum = "4299ebf790ea9de1cb72e73ff2ae44c723ef264299e5e2d5ef46a371eb3ac3d8" dependencies = [ - "log 0.4.14", "proc-macro-crate 1.1.0", "proc-macro2", "quote", @@ -3274,10 +3328,24 @@ dependencies = [ "log 0.4.14", "serde", "serde_json", - "soketto 0.7.0", + "soketto 0.7.1", "thiserror", ] +[[package]] +name = "jsonrpsee-types" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b3f601bbbe45cd63f5407b6f7d7950e08a7d4f82aa699ff41a4a5e9e54df58" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + [[package]] name = "jsonrpsee-utils" version = "0.4.1" @@ -3286,7 +3354,7 @@ checksum = "0109c4f972058f3b1925b73a17210aff7b63b65967264d0045d15ee88fe84f0c" dependencies = [ "arrayvec 0.7.1", "beef", - "jsonrpsee-types", + "jsonrpsee-types 0.4.1", ] [[package]] @@ -3300,19 +3368,30 @@ dependencies = [ "fnv", "futures 0.3.16", "http", - "jsonrpsee-types", + "jsonrpsee-types 0.4.1", "log 0.4.14", "pin-project 1.0.10", - "rustls-native-certs", + "rustls-native-certs 0.5.0", "serde", "serde_json", - "soketto 0.7.0", + "soketto 0.7.1", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.22.0", "tokio-util", ] +[[package]] +name = "jsonrpsee-ws-client" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aff425cee7c779e33920913bc695447416078ee6d119f443f3060feffa4e86b5" +dependencies = [ + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types 0.8.0", +] + [[package]] name = "keccak" version = "0.1.0" @@ -3920,9 +3999,9 @@ dependencies = [ "log 0.4.14", "quicksink", "rw-stream-sink", - "soketto 0.7.0", + "soketto 0.7.1", "url 2.2.1", - "webpki-roots", + "webpki-roots 0.21.0", ] [[package]] @@ -4602,7 +4681,7 @@ dependencies = [ "frame-system-rpc-runtime-api", "futures 0.3.16", "hex-literal", - "jsonrpsee-ws-client", + "jsonrpsee-ws-client 0.4.1", "log 0.4.14", "nix", "node-executor", @@ -7427,7 +7506,7 @@ version = "0.10.0-dev" dependencies = [ "env_logger 0.9.0", "frame-support", - "jsonrpsee", + "jsonrpsee 0.8.0", "log 0.4.14", "pallet-elections-phragmen", "parity-scale-codec", @@ -7559,8 +7638,20 @@ dependencies = [ "base64 0.13.0", "log 0.4.14", "ring", - "sct", - "webpki", + "sct 0.6.0", + "webpki 0.21.4", +] + +[[package]] +name = "rustls" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" +dependencies = [ + "log 0.4.14", + "ring", + "sct 0.7.0", + "webpki 0.22.0", ] [[package]] @@ -7570,11 +7661,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" dependencies = [ "openssl-probe", - "rustls", + "rustls 0.19.1", "schannel", "security-framework", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64 0.13.0", +] + [[package]] name = "rustversion" version = "1.0.6" @@ -8855,6 +8967,16 @@ dependencies = [ "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 = "secrecy" version = "0.8.0" @@ -9202,9 +9324,9 @@ dependencies = [ [[package]] name = "soketto" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "083624472e8817d44d02c0e55df043737ff11f279af924abdf93845717c2b75c" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ "base64 0.13.0", "bytes 1.1.0", @@ -10647,9 +10769,20 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ - "rustls", + "rustls 0.19.1", + "tokio", + "webpki 0.21.4", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +dependencies = [ + "rustls 0.20.2", "tokio", - "webpki", + "webpki 0.22.0", ] [[package]] @@ -10941,7 +11074,7 @@ name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ "clap 3.0.7", - "jsonrpsee", + "jsonrpsee 0.4.1", "log 0.4.14", "parity-scale-codec", "remote-externalities", @@ -11755,13 +11888,32 @@ dependencies = [ "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.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" dependencies = [ - "webpki", + "webpki 0.21.4", +] + +[[package]] +name = "webpki-roots" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +dependencies = [ + "webpki 0.22.0", ] [[package]] diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 6d926846b4a36..9e0b17a7b58f8 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.4.1", features = ["ws-client", "macros"] } +jsonrpsee = { version = "0.8", features = ["ws-client", "macros"] } env_logger = "0.9" frame-support = { path = "../../../frame/support", optional = true, version = "4.0.0-dev" } diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 16aa60db1841c..d6dfd1c59d4ee 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -23,9 +23,9 @@ use codec::{Decode, Encode}; use jsonrpsee::{ + core::{client::ClientT, Error as RpcError}, proc_macros::rpc, rpc_params, - types::{traits::Client, Error as RpcError}, ws_client::{WsClient, WsClientBuilder}, }; @@ -44,6 +44,7 @@ use sp_runtime::traits::Block as BlockT; use std::{ fs, path::{Path, PathBuf}, + sync::Arc, }; pub mod rpc_api; @@ -123,21 +124,52 @@ impl> From

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%0Awg^OTaNBpG1ENFs8${1Qd{SLUE8nF(ExA z=rt}4iSLg|L*nC`q#^O;QE5ngcB3>Tz6pK8ZyJ37b15Z2z?+zyNgA>^G-lb?cs`Hv zoqlWBmB423g!FlaYvM0734m-lQrZws-m<@KOO=w?((09uS(vq`(q*bpz|-TGxEPrH zhqV$aiz+2NRVo!q;tz_2XHIHSz{Cm_jGWo+&1UQc0_D&Q>ty@^HoM`|;xZr%C+iWC z+RCT!ym$<}ir(XbuRNBSGGexu{0BXcS?G{%>nyNB1?K__wU-O6J}=-xhjtcTDA1#?iP3%pQbXPk zLN~y67+8Cu$9j7UTv<q!Gh$DhE79?NosBStE zJK7oV*=VX*`WtI1jat?FD3ty@A4Q)Ro8Gx77kFW=5iX;VB27h�VEt2a-MtWsMOo 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

{qt^mN8-tXrcIZg*u^;V4||( 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

I0%%1?tE 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

6qrq9yfh73kB)lN+ec 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%0Ay+$#vj9XOpHGUq$b86IHAEL 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%0A%UVQS>zB^Vo7|)KeDmX8N*mIZO@#uSf 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

l*E$vGr!b0mzpPvxmv|Kn@YID>qCb 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

V_ga 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

`Dr66(fQTy| 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

6{u>RgkeeoM-jy+Hb*aa*^iCl~@))V-T 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 Result<(), WasmError> { + let import_section = match self.raw_module.import_section_mut() { + Some(import_section) => import_section, + None => return Ok(()), + }; + + let import_entries = import_section.entries_mut(); + for index in 0..import_entries.len() { + let entry = &import_entries[index]; + let memory_ty = match entry.external() { + External::Memory(memory_ty) => *memory_ty, + _ => continue, + }; + + let memory_name = entry.field().to_owned(); + import_entries.remove(index); + + self.raw_module + .insert_section(Section::Memory(MemorySection::with_entries(vec![memory_ty]))) + .map_err(|error| { + WasmError::Other(format!( + "can't convert a memory import into an export: failed to insert a new memory section: {}", + error + )) + })?; + + if self.raw_module.export_section_mut().is_none() { + // A module without an export section is somewhat unrealistic, but let's do this + // just in case to cover all of our bases. + self.raw_module + .insert_section(Section::Export(Default::default())) + .expect("an export section can be always inserted if it doesn't exist; qed"); + } + self.raw_module + .export_section_mut() + .expect("export section already existed or we just added it above, so it always exists; qed") + .entries_mut() + .push(ExportEntry::new(memory_name, Internal::Memory(0))); + + break + } + + Ok(()) + } + + /// Increases the number of memory pages requested by the WASM blob by + /// the given amount of `extra_heap_pages`. + /// + /// Will return an error in case there is no memory section present, + /// or if the memory section is empty. + /// + /// Only modifies the initial size of the memory; the maximum is unmodified + /// unless it's smaller than the initial size, in which case it will be increased + /// so that it's at least as big as the initial size. + pub fn add_extra_heap_pages_to_memory_section( + &mut self, + extra_heap_pages: u32, + ) -> Result<(), WasmError> { + let memory_section = self + .raw_module + .memory_section_mut() + .ok_or_else(|| WasmError::Other("no memory section found".into()))?; + + if memory_section.entries().is_empty() { + return Err(WasmError::Other("memory section is empty".into())) + } + for memory_ty in memory_section.entries_mut() { + let min = memory_ty.limits().initial().saturating_add(extra_heap_pages); + let max = memory_ty.limits().maximum().map(|max| std::cmp::max(min, max)); + *memory_ty = MemoryType::new(min, max); + } + Ok(()) + } + /// Returns an iterator of all globals which were exported by [`expose_mutable_globals`]. pub(super) fn exported_internal_global_names<'module>( &'module self, diff --git a/client/executor/wasmtime/src/imports.rs b/client/executor/wasmtime/src/imports.rs index 636a5761c9475..4aad571029313 100644 --- a/client/executor/wasmtime/src/imports.rs +++ b/client/executor/wasmtime/src/imports.rs @@ -16,37 +16,24 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{ - host::HostContext, - runtime::{Store, StoreData}, -}; +use crate::{host::HostContext, runtime::StoreData}; use sc_executor_common::error::WasmError; use sp_wasm_interface::{FunctionContext, HostFunctions}; -use std::{collections::HashMap, convert::TryInto}; -use wasmtime::{Extern, ExternType, Func, FuncType, ImportType, Memory, MemoryType, Module, Trap}; - -pub struct Imports { - /// Contains the index into `externs` where the memory import is stored if any. `None` if there - /// is none. - pub memory_import_index: Option, - pub externs: Vec, -} +use std::collections::HashMap; +use wasmtime::{ExternType, FuncType, ImportType, Linker, Module, Trap}; -/// Goes over all imports of a module and prepares a vector of `Extern`s that can be used for -/// instantiation of the module. Returns an error if there are imports that cannot be satisfied. -pub(crate) fn resolve_imports( - store: &mut Store, +/// Goes over all imports of a module and prepares the given linker for instantiation of the module. +/// Returns an error if there are imports that cannot be satisfied. +pub(crate) fn prepare_imports( + linker: &mut Linker, module: &Module, - heap_pages: u64, allow_missing_func_imports: bool, -) -> Result +) -> Result<(), WasmError> where H: HostFunctions, { - let mut externs = vec![]; - let mut memory_import_index = None; let mut pending_func_imports = HashMap::new(); - for (index, import_ty) in module.imports().enumerate() { + for import_ty in module.imports() { let name = import_name(&import_ty)?; if import_ty.module() != "env" { @@ -57,41 +44,36 @@ where ))) } - if name == "memory" { - memory_import_index = Some(index); - externs.push((index, resolve_memory_import(store, &import_ty, heap_pages)?)); - continue - } - match import_ty.ty() { ExternType::Func(func_ty) => { - pending_func_imports.insert(name.to_owned(), (index, import_ty, func_ty)); + pending_func_imports.insert(name.to_owned(), (import_ty, func_ty)); }, _ => return Err(WasmError::Other(format!( - "host doesn't provide any non function imports besides 'memory': {}:{}", + "host doesn't provide any non function imports: {}:{}", import_ty.module(), name, ))), }; } - let mut registry = Registry { store, externs, pending_func_imports }; - + let mut registry = Registry { linker, pending_func_imports }; H::register_static(&mut registry)?; - let mut externs = registry.externs; if !registry.pending_func_imports.is_empty() { if allow_missing_func_imports { - for (_, (index, import_ty, func_ty)) in registry.pending_func_imports { - externs.push(( - index, - MissingHostFuncHandler::new(&import_ty)?.into_extern(store, &func_ty), - )); + for (name, (import_ty, func_ty)) in registry.pending_func_imports { + let error = format!("call to a missing function {}:{}", import_ty.module(), name); + log::debug!("Missing import: '{}' {:?}", name, func_ty); + linker + .func_new("env", &name, func_ty.clone(), move |_, _, _| { + Err(Trap::new(error.clone())) + }) + .expect("adding a missing import stub can only fail when the item already exists, and it is missing here; qed"); } } else { let mut names = Vec::new(); - for (name, (_, import_ty, _)) in registry.pending_func_imports { + for (name, (import_ty, _)) in registry.pending_func_imports { names.push(format!("'{}:{}'", import_ty.module(), name)); } let names = names.join(", "); @@ -102,16 +84,12 @@ where } } - externs.sort_unstable_by_key(|&(index, _)| index); - let externs = externs.into_iter().map(|(_, ext)| ext).collect(); - - Ok(Imports { memory_import_index, externs }) + Ok(()) } struct Registry<'a, 'b> { - store: &'a mut Store, - externs: Vec<(usize, Extern)>, - pending_func_imports: HashMap, FuncType)>, + linker: &'a mut Linker, + pending_func_imports: HashMap, FuncType)>, } impl<'a, 'b> sp_wasm_interface::HostFunctionRegistry for Registry<'a, 'b> { @@ -131,9 +109,13 @@ impl<'a, 'b> sp_wasm_interface::HostFunctionRegistry for Registry<'a, 'b> { fn_name: &str, func: impl wasmtime::IntoFunc, ) -> Result<(), Self::Error> { - if let Some((index, _, _)) = self.pending_func_imports.remove(fn_name) { - let func = Func::wrap(&mut *self.store, func); - self.externs.push((index, Extern::Func(func))); + if self.pending_func_imports.remove(fn_name).is_some() { + self.linker.func_wrap("env", fn_name, func).map_err(|error| { + WasmError::Other(format!( + "failed to register host function '{}' with the WASM linker: {}", + fn_name, error + )) + })?; } Ok(()) @@ -149,85 +131,3 @@ fn import_name<'a, 'b: 'a>(import: &'a ImportType<'b>) -> Result<&'a str, WasmEr })?; Ok(name) } - -fn resolve_memory_import( - store: &mut Store, - import_ty: &ImportType, - heap_pages: u64, -) -> Result { - let requested_memory_ty = match import_ty.ty() { - ExternType::Memory(memory_ty) => memory_ty, - _ => - return Err(WasmError::Other(format!( - "this import must be of memory type: {}:{}", - import_ty.module(), - import_name(&import_ty)?, - ))), - }; - - // Increment the min (a.k.a initial) number of pages by `heap_pages` and check if it exceeds the - // maximum specified by the import. - let initial = requested_memory_ty.minimum().saturating_add(heap_pages); - if let Some(max) = requested_memory_ty.maximum() { - if initial > max { - return Err(WasmError::Other(format!( - "incremented number of pages by heap_pages (total={}) is more than maximum requested\ - by the runtime wasm module {}", - initial, - max, - ))) - } - } - - // Note that the return value of `maximum` and `minimum`, while a u64, - // will always fit into a u32 for 32-bit memories. - // 64-bit memories are part of the memory64 proposal for WebAssembly which is not standardized - // yet. - let minimum: u32 = initial.try_into().map_err(|_| { - WasmError::Other(format!( - "minimum number of memory pages ({}) doesn't fit into u32", - initial - )) - })?; - let maximum: Option = match requested_memory_ty.maximum() { - Some(max) => Some(max.try_into().map_err(|_| { - WasmError::Other(format!( - "maximum number of memory pages ({}) doesn't fit into u32", - max - )) - })?), - None => None, - }; - - let memory_ty = MemoryType::new(minimum, maximum); - let memory = Memory::new(store, memory_ty).map_err(|e| { - WasmError::Other(format!( - "failed to create a memory during resolving of memory import: {}", - e, - )) - })?; - Ok(Extern::Memory(memory)) -} - -/// A `Callable` handler for missing functions. -struct MissingHostFuncHandler { - module: String, - name: String, -} - -impl MissingHostFuncHandler { - fn new(import_ty: &ImportType) -> Result { - Ok(Self { - module: import_ty.module().to_string(), - name: import_name(import_ty)?.to_string(), - }) - } - - fn into_extern(self, store: &mut Store, func_ty: &FuncType) -> Extern { - let Self { module, name } = self; - let func = Func::new(store, func_ty.clone(), move |_, _, _| { - Err(Trap::new(format!("call to a missing function {}:{}", module, name))) - }); - Extern::Func(func) - } -} diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index 896b71cea21dd..6abcbca1bba6f 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -21,12 +21,13 @@ use crate::runtime::{Store, StoreData}; use sc_executor_common::{ - error::{Backtrace, Error, MessageWithBacktrace, Result}, + error::{Backtrace, Error, MessageWithBacktrace, Result, WasmError}, wasm_runtime::InvokeMethod, }; -use sp_wasm_interface::{HostFunctions, Pointer, Value, WordSize}; +use sp_wasm_interface::{Pointer, Value, WordSize}; use wasmtime::{ - AsContext, AsContextMut, Extern, Func, Global, Instance, Memory, Module, Table, Val, + AsContext, AsContextMut, Engine, Extern, Func, Global, Instance, InstancePre, Memory, Table, + Val, }; /// Invoked entrypoint format. @@ -162,62 +163,41 @@ fn extern_func(extern_: &Extern) -> Option<&Func> { } } +pub(crate) fn create_store(engine: &wasmtime::Engine, max_memory_size: Option) -> Store { + let limits = if let Some(max_memory_size) = max_memory_size { + wasmtime::StoreLimitsBuilder::new().memory_size(max_memory_size).build() + } else { + Default::default() + }; + + let mut store = + Store::new(engine, StoreData { limits, host_state: None, memory: None, table: None }); + if max_memory_size.is_some() { + store.limiter(|s| &mut s.limits); + } + store +} + impl InstanceWrapper { - /// Create a new instance wrapper from the given wasm module. - pub fn new( - module: &Module, - heap_pages: u64, - allow_missing_func_imports: bool, + pub(crate) fn new( + engine: &Engine, + instance_pre: &InstancePre, max_memory_size: Option, - ) -> Result - where - H: HostFunctions, - { - let limits = if let Some(max_memory_size) = max_memory_size { - wasmtime::StoreLimitsBuilder::new().memory_size(max_memory_size).build() - } else { - Default::default() - }; - - let mut store = Store::new( - module.engine(), - StoreData { limits, host_state: None, memory: None, table: None }, - ); - if max_memory_size.is_some() { - store.limiter(|s| &mut s.limits); - } - - // Scan all imports, find the matching host functions, and create stubs that adapt arguments - // and results. - let imports = crate::imports::resolve_imports::( - &mut store, - module, - heap_pages, - allow_missing_func_imports, - )?; - - let instance = Instance::new(&mut store, module, &imports.externs) - .map_err(|e| Error::from(format!("cannot instantiate: {}", e)))?; - - let memory = match imports.memory_import_index { - Some(memory_idx) => extern_memory(&imports.externs[memory_idx]) - .expect("only memory can be at the `memory_idx`; qed") - .clone(), - None => { - let memory = get_linear_memory(&instance, &mut store)?; - if !memory.grow(&mut store, heap_pages).is_ok() { - return Err("failed top increase the linear memory size".into()) - } - memory - }, - }; - + ) -> Result { + let mut store = create_store(engine, max_memory_size); + let instance = instance_pre.instantiate(&mut store).map_err(|error| { + WasmError::Other( + format!("failed to instantiate a new WASM module instance: {}", error,), + ) + })?; + + let memory = get_linear_memory(&instance, &mut store)?; let table = get_table(&instance, &mut store); store.data_mut().memory = Some(memory); store.data_mut().table = table; - Ok(Self { instance, memory, store }) + Ok(InstanceWrapper { instance, memory, store }) } /// Resolves a substrate entrypoint by the given name. @@ -435,8 +415,11 @@ impl InstanceWrapper { fn decommit_works() { let engine = wasmtime::Engine::default(); let code = wat::parse_str("(module (memory (export \"memory\") 1 4))").unwrap(); - let module = Module::new(&engine, code).unwrap(); - let mut wrapper = InstanceWrapper::new::<()>(&module, 2, true, None).unwrap(); + let module = wasmtime::Module::new(&engine, code).unwrap(); + let linker = wasmtime::Linker::new(&engine); + let mut store = create_store(&engine, None); + let instance_pre = linker.instantiate_pre(&mut store, &module).unwrap(); + let mut wrapper = InstanceWrapper::new(&engine, &instance_pre, None).unwrap(); unsafe { *wrapper.memory.data_ptr(&wrapper.store) = 42 }; assert_eq!(unsafe { *wrapper.memory.data_ptr(&wrapper.store) }, 42); wrapper.decommit(); diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 6533aa194e4c4..acf54e04e07fd 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -23,7 +23,6 @@ use crate::{ instance_wrapper::{EntryPoint, InstanceWrapper}, util, }; -use core::marker::PhantomData; use sc_allocator::FreeingBumpHeapAllocator; use sc_executor_common::{ @@ -80,35 +79,25 @@ impl StoreData { pub(crate) type Store = wasmtime::Store; -enum Strategy { +enum Strategy { FastInstanceReuse { instance_wrapper: InstanceWrapper, globals_snapshot: GlobalsSnapshot, data_segments_snapshot: Arc, heap_base: u32, }, - RecreateInstance(InstanceCreator), + RecreateInstance(InstanceCreator), } -struct InstanceCreator { - module: Arc, - heap_pages: u64, - allow_missing_func_imports: bool, +struct InstanceCreator { + engine: wasmtime::Engine, + instance_pre: Arc>, max_memory_size: Option, - phantom: PhantomData, } -impl InstanceCreator -where - H: HostFunctions, -{ +impl InstanceCreator { fn instantiate(&mut self) -> Result { - InstanceWrapper::new::( - &*self.module, - self.heap_pages, - self.allow_missing_func_imports, - self.max_memory_size, - ) + InstanceWrapper::new(&self.engine, &self.instance_pre, self.max_memory_size) } } @@ -144,23 +133,19 @@ struct InstanceSnapshotData { /// A `WasmModule` implementation using wasmtime to compile the runtime module to machine code /// and execute the compiled code. -pub struct WasmtimeRuntime { - module: Arc, +pub struct WasmtimeRuntime { + engine: wasmtime::Engine, + instance_pre: Arc>, snapshot_data: Option, config: Config, - phantom: PhantomData, } -impl WasmModule for WasmtimeRuntime -where - H: HostFunctions, -{ +impl WasmModule for WasmtimeRuntime { fn new_instance(&self) -> Result> { let strategy = if let Some(ref snapshot_data) = self.snapshot_data { - let mut instance_wrapper = InstanceWrapper::new::( - &self.module, - self.config.heap_pages, - self.config.allow_missing_func_imports, + let mut instance_wrapper = InstanceWrapper::new( + &self.engine, + &self.instance_pre, self.config.max_memory_size, )?; let heap_base = instance_wrapper.extract_heap_base()?; @@ -174,19 +159,17 @@ where &mut InstanceGlobals { instance: &mut instance_wrapper }, ); - Strategy::::FastInstanceReuse { + Strategy::FastInstanceReuse { instance_wrapper, globals_snapshot, data_segments_snapshot: snapshot_data.data_segments_snapshot.clone(), heap_base, } } else { - Strategy::::RecreateInstance(InstanceCreator { - module: self.module.clone(), - heap_pages: self.config.heap_pages, - allow_missing_func_imports: self.config.allow_missing_func_imports, + Strategy::RecreateInstance(InstanceCreator { + engine: self.engine.clone(), + instance_pre: self.instance_pre.clone(), max_memory_size: self.config.max_memory_size, - phantom: PhantomData, }) }; @@ -196,14 +179,11 @@ where /// A `WasmInstance` implementation that reuses compiled module and spawns instances /// to execute the compiled code. -pub struct WasmtimeInstance { - strategy: Strategy, +pub struct WasmtimeInstance { + strategy: Strategy, } -impl WasmInstance for WasmtimeInstance -where - H: HostFunctions, -{ +impl WasmInstance for WasmtimeInstance { fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result> { match &mut self.strategy { Strategy::FastInstanceReuse { @@ -498,7 +478,7 @@ enum CodeSupplyMode<'a> { pub fn create_runtime( blob: RuntimeBlob, config: Config, -) -> std::result::Result, WasmError> +) -> std::result::Result where H: HostFunctions, { @@ -520,7 +500,7 @@ where pub unsafe fn create_runtime_from_artifact( compiled_artifact: &[u8], config: Config, -) -> std::result::Result, WasmError> +) -> std::result::Result where H: HostFunctions, { @@ -534,7 +514,7 @@ where unsafe fn do_create_runtime( code_supply_mode: CodeSupplyMode<'_>, config: Config, -) -> std::result::Result, WasmError> +) -> std::result::Result where H: HostFunctions, { @@ -550,27 +530,39 @@ where } let engine = Engine::new(&wasmtime_config) - .map_err(|e| WasmError::Other(format!("cannot create the engine for runtime: {}", e)))?; + .map_err(|e| WasmError::Other(format!("cannot create the wasmtime engine: {}", e)))?; let (module, snapshot_data) = match code_supply_mode { CodeSupplyMode::Verbatim { blob } => { - let blob = instrument(blob, &config.semantics)?; + let mut blob = instrument(blob, &config.semantics)?; + + // We don't actually need the memory to be imported so we can just convert any memory + // import into an export with impunity. This simplifies our code since `wasmtime` will + // now automatically take care of creating the memory for us, and it also allows us + // to potentially enable `wasmtime`'s instance pooling at a later date. (Imported + // memories are ineligible for pooling.) + blob.convert_memory_import_into_export()?; + blob.add_extra_heap_pages_to_memory_section( + config + .heap_pages + .try_into() + .map_err(|e| WasmError::Other(format!("invalid `heap_pages`: {}", e)))?, + )?; + + let serialized_blob = blob.clone().serialize(); + + let module = wasmtime::Module::new(&engine, &serialized_blob) + .map_err(|e| WasmError::Other(format!("cannot create module: {}", e)))?; if config.semantics.fast_instance_reuse { let data_segments_snapshot = DataSegmentsSnapshot::take(&blob).map_err(|e| { WasmError::Other(format!("cannot take data segments snapshot: {}", e)) })?; let data_segments_snapshot = Arc::new(data_segments_snapshot); - let mutable_globals = ExposedMutableGlobalsSet::collect(&blob); - let module = wasmtime::Module::new(&engine, &blob.serialize()) - .map_err(|e| WasmError::Other(format!("cannot create module: {}", e)))?; - (module, Some(InstanceSnapshotData { data_segments_snapshot, mutable_globals })) } else { - let module = wasmtime::Module::new(&engine, &blob.serialize()) - .map_err(|e| WasmError::Other(format!("cannot create module: {}", e)))?; (module, None) } }, @@ -584,7 +576,15 @@ where }, }; - Ok(WasmtimeRuntime { module: Arc::new(module), snapshot_data, config, phantom: PhantomData }) + let mut linker = wasmtime::Linker::new(&engine); + crate::imports::prepare_imports::(&mut linker, &module, config.allow_missing_func_imports)?; + + let mut store = crate::instance_wrapper::create_store(module.engine(), config.max_memory_size); + let instance_pre = linker + .instantiate_pre(&mut store, &module) + .map_err(|e| WasmError::Other(format!("cannot preinstantiate module: {}", e)))?; + + Ok(WasmtimeRuntime { engine, instance_pre: Arc::new(instance_pre), snapshot_data, config }) } fn instrument( diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index 664d05f5387fc..a4ca0959da869 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -24,7 +24,7 @@ use std::sync::Arc; type HostFunctions = sp_io::SubstrateHostFunctions; struct RuntimeBuilder { - code: Option<&'static str>, + code: Option, fast_instance_reuse: bool, canonicalize_nans: bool, deterministic_stack: bool, @@ -46,7 +46,7 @@ impl RuntimeBuilder { } } - fn use_wat(&mut self, code: &'static str) { + fn use_wat(&mut self, code: String) { self.code = Some(code); } @@ -152,7 +152,7 @@ fn test_stack_depth_reaching() { let runtime = { let mut builder = RuntimeBuilder::new_on_demand(); - builder.use_wat(TEST_GUARD_PAGE_SKIP); + builder.use_wat(TEST_GUARD_PAGE_SKIP.to_string()); builder.deterministic_stack(true); builder.build() }; @@ -168,10 +168,19 @@ fn test_stack_depth_reaching() { } #[test] -fn test_max_memory_pages() { +fn test_max_memory_pages_imported_memory() { + test_max_memory_pages(true); +} + +#[test] +fn test_max_memory_pages_exported_memory() { + test_max_memory_pages(false); +} + +fn test_max_memory_pages(import_memory: bool) { fn try_instantiate( max_memory_size: Option, - wat: &'static str, + wat: String, ) -> Result<(), Box> { let runtime = { let mut builder = RuntimeBuilder::new_on_demand(); @@ -184,31 +193,48 @@ fn test_max_memory_pages() { Ok(()) } + fn memory(initial: u32, maximum: Option, import: bool) -> String { + let memory = if let Some(maximum) = maximum { + format!("(memory $0 {} {})", initial, maximum) + } else { + format!("(memory $0 {})", initial) + }; + + if import { + format!("(import \"env\" \"memory\" {})", memory) + } else { + format!("{}\n(export \"memory\" (memory $0))", memory) + } + } + const WASM_PAGE_SIZE: usize = 65536; // check the old behavior if preserved. That is, if no limit is set we allow 4 GiB of memory. try_instantiate( None, - r#" - (module - ;; we want to allocate the maximum number of pages supported in wasm for this test. - ;; - ;; However, due to a bug in wasmtime (I think wasmi is also affected) it is only possible - ;; to allocate 65536 - 1 pages. - ;; - ;; Then, during creation of the Substrate Runtime instance, 1024 (heap_pages) pages are - ;; mounted. - ;; - ;; Thus 65535 = 64511 + 1024 - (import "env" "memory" (memory 64511)) - - (global (export "__heap_base") i32 (i32.const 0)) - (func (export "main") - (param i32 i32) (result i64) - (i64.const 0) + format!( + r#" + (module + {} + (global (export "__heap_base") i32 (i32.const 0)) + (func (export "main") + (param i32 i32) (result i64) + (i64.const 0) + ) ) - ) - "#, + "#, + /* + We want to allocate the maximum number of pages supported in wasm for this test. + However, due to a bug in wasmtime (I think wasmi is also affected) it is only possible + to allocate 65536 - 1 pages. + + Then, during creation of the Substrate Runtime instance, 1024 (heap_pages) pages are + mounted. + + Thus 65535 = 64511 + 1024 + */ + memory(64511, None, import_memory) + ), ) .unwrap(); @@ -217,94 +243,104 @@ fn test_max_memory_pages() { // max_memory_size = (1 (initial) + 1024 (heap_pages)) * WASM_PAGE_SIZE try_instantiate( Some((1 + 1024) * WASM_PAGE_SIZE), - r#" - (module - - (import "env" "memory" (memory 1)) ;; <- 1 initial, max is not specified - - (global (export "__heap_base") i32 (i32.const 0)) - (func (export "main") - (param i32 i32) (result i64) - (i64.const 0) + format!( + r#" + (module + {} + (global (export "__heap_base") i32 (i32.const 0)) + (func (export "main") + (param i32 i32) (result i64) + (i64.const 0) + ) ) - ) - "#, + "#, + // 1 initial, max is not specified. + memory(1, None, import_memory) + ), ) .unwrap(); // max is specified explicitly to 2048 pages. try_instantiate( Some((1 + 1024) * WASM_PAGE_SIZE), - r#" - (module - - (import "env" "memory" (memory 1 2048)) ;; <- max is 2048 - - (global (export "__heap_base") i32 (i32.const 0)) - (func (export "main") - (param i32 i32) (result i64) - (i64.const 0) + format!( + r#" + (module + {} + (global (export "__heap_base") i32 (i32.const 0)) + (func (export "main") + (param i32 i32) (result i64) + (i64.const 0) + ) ) - ) - "#, + "#, + // Max is 2048. + memory(1, Some(2048), import_memory) + ), ) .unwrap(); // memory grow should work as long as it doesn't exceed 1025 pages in total. try_instantiate( Some((0 + 1024 + 25) * WASM_PAGE_SIZE), - r#" - (module - (import "env" "memory" (memory 0)) ;; <- zero starting pages. - - (global (export "__heap_base") i32 (i32.const 0)) - (func (export "main") - (param i32 i32) (result i64) - - ;; assert(memory.grow returns != -1) - (if - (i32.eq - (memory.grow - (i32.const 25) + format!( + r#" + (module + {} + (global (export "__heap_base") i32 (i32.const 0)) + (func (export "main") + (param i32 i32) (result i64) + + ;; assert(memory.grow returns != -1) + (if + (i32.eq + (memory.grow + (i32.const 25) + ) + (i32.const -1) ) - (i32.const -1) + (unreachable) ) - (unreachable) - ) - (i64.const 0) + (i64.const 0) + ) ) - ) - "#, + "#, + // Zero starting pages. + memory(0, None, import_memory) + ), ) .unwrap(); // We start with 1025 pages and try to grow at least one. try_instantiate( Some((1 + 1024) * WASM_PAGE_SIZE), - r#" - (module - (import "env" "memory" (memory 1)) ;; <- initial=1, meaning after heap pages mount the - ;; total will be already 1025 - (global (export "__heap_base") i32 (i32.const 0)) - (func (export "main") - (param i32 i32) (result i64) - - ;; assert(memory.grow returns == -1) - (if - (i32.ne - (memory.grow - (i32.const 1) + format!( + r#" + (module + {} + (global (export "__heap_base") i32 (i32.const 0)) + (func (export "main") + (param i32 i32) (result i64) + + ;; assert(memory.grow returns == -1) + (if + (i32.ne + (memory.grow + (i32.const 1) + ) + (i32.const -1) ) - (i32.const -1) + (unreachable) ) - (unreachable) - ) - (i64.const 0) + (i64.const 0) + ) ) - ) - "#, + "#, + // Initial=1, meaning after heap pages mount the total will be already 1025. + memory(1, None, import_memory) + ), ) .unwrap(); } From babf752334dd484e5d0900d2a4f7be1a9ac31c2e Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Sat, 19 Mar 2022 13:19:00 -0600 Subject: [PATCH 0614/1472] Add github issue form templates (#11061) * add issue form templates * Apply suggestions from code review Co-authored-by: Sacha Lansky Co-authored-by: Sacha Lansky --- .github/ISSUE_TEMPLATE/bug.yaml | 34 +++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 7 ++++ .github/ISSUE_TEMPLATE/feature.yaml | 52 +++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug.yaml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature.yaml diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml new file mode 100644 index 0000000000000..ae40df08eca76 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -0,0 +1,34 @@ +name: Bug Report +description: Let us know about an issue you experienced with this software +# labels: ["some existing label","another one"] +body: + - type: checkboxes + attributes: + label: Is there an existing issue? + description: Please search to see if an issue already exists and leave a comment that you also experienced this issue or add your specifics that are related to an existing issue. + options: + - label: I have searched the existing issues + required: true + - type: checkboxes + attributes: + label: Experiencing problems? Have you tried our Stack Exchange first? + description: Please search to see if an post already exists, and ask if not. Please do not file support issues here. + options: + - label: This is not a support question. + required: true + - type: textarea + id: bug + attributes: + label: Description of bug + # description: What seems to be the problem? + # placeholder: Describe the problem. + validations: + required: true + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: Provide the steps that led to the discovery of the issue. + # placeholder: Describe what you were doing so we can reproduce the problem. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000000..e422e317411f3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,7 @@ +blank_issues_enabled: true +contact_links: + - name: Support & Troubleshooting with the Substrate Stack Exchange Community + url: https://substrate.stackexchange.com + about: | + For general problems with Substrate or related technologies, please search here first + for solutions, by keyword and tags. If you discover no solution, please then ask and questions in our community! We highly encourage everyone also share their understanding by answering questions for others. diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml new file mode 100644 index 0000000000000..92b2fea3e88da --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -0,0 +1,52 @@ +name: Feature Request +description: Submit your requests and suggestions to improve! +body: + - type: checkboxes + attributes: + label: Is there an existing issue? + description: Please search to see if an issue already exists and leave a comment that you also experienced this issue or add your specifics that are related to an existing issue. + options: + - label: I have searched the existing issues + required: true + - type: checkboxes + attributes: + label: Experiencing problems? Have you tried our Stack Exchange first? + description: Please search to see if an post already exists, and ask if not. Please do not file support issues here. + options: + - label: This is not a support question. + required: true + - type: textarea + id: content + attributes: + label: Motivation + description: Please give precedence as to what lead you to file this issue. + # placeholder: Describe ... + validations: + required: false + - type: textarea + id: content + attributes: + label: Request + description: Please describe what is needed. + # placeholder: Describe what you would like to see added or changed. + validations: + required: true + - type: textarea + id: content + attributes: + label: Solution + description: If possible, please describe what a solution could be. + # placeholder: Describe what you would like to see added or changed. + validations: + required: false + - type: dropdown + id: help + attributes: + label: Are you willing to help with this request? + multiple: true + options: + - Yes! + - No. + - Maybe (please elaborate above) + validations: + required: true From 81d253ed66c2597d5ca6a1852c80a6ecb03ce45f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Mar 2022 21:07:18 +0000 Subject: [PATCH 0615/1472] Bump cargo_metadata from 0.14.1 to 0.14.2 (#11066) Bumps [cargo_metadata](https://github.com/oli-obk/cargo_metadata) from 0.14.1 to 0.14.2. - [Release notes](https://github.com/oli-obk/cargo_metadata/releases) - [Commits](https://github.com/oli-obk/cargo_metadata/compare/0.14.1...0.14.2) --- updated-dependencies: - dependency-name: cargo_metadata 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 ++-- utils/wasm-builder/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2760ee0570d45..e847dcd23d325 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -851,9 +851,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ae6de944143141f6155a473a6b02f66c7c3f9f47316f802f80204ebfe6e12" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index ce9687f9ae0ef..66c04432c5dec 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] build-helper = "0.1.1" -cargo_metadata = "0.14.1" +cargo_metadata = "0.14.2" tempfile = "3.1.0" toml = "0.5.4" walkdir = "2.3.2" From 6506784c95c2b6ee1db19cdbfc8142e9c7a071dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 19 Mar 2022 23:58:32 +0100 Subject: [PATCH 0616/1472] sc-consensus-aura: Remove obsolete dependency (#11074) --- Cargo.lock | 3 --- client/consensus/aura/Cargo.toml | 3 --- 2 files changed, 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e847dcd23d325..3de4fc3f7020a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2646,10 +2646,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if 1.0.0", - "js-sys", "libc", "wasi 0.10.0+wasi-snapshot-preview1", - "wasm-bindgen", ] [[package]] @@ -8239,7 +8237,6 @@ version = "0.10.0-dev" dependencies = [ "async-trait", "futures 0.3.19", - "getrandom 0.2.3", "log 0.4.14", "parity-scale-codec", "parking_lot 0.12.0", diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 6f5ff3c221fac..2ad61f2bc48d9 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -35,9 +35,6 @@ sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } async-trait = "0.1.50" -# We enable it only for web-wasm check -# See https://docs.rs/getrandom/0.2.1/getrandom/#webassembly-support -getrandom = { version = "0.2", features = ["js"], optional = true } [dev-dependencies] sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } From 4ad64453048066ee34153db0da576ec95338fdb6 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Mon, 21 Mar 2022 16:37:59 +0800 Subject: [PATCH 0617/1472] pallet-whitelist: add sp-api/std to std feature to fix compile error (#11077) Signed-off-by: koushiro --- frame/whitelist/Cargo.toml | 11 ++++++----- frame/whitelist/src/benchmarking.rs | 7 ++++--- frame/whitelist/src/lib.rs | 17 +++++++---------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/frame/whitelist/Cargo.toml b/frame/whitelist/Cargo.toml index 6bc43ff961781..5f414e5d32033 100644 --- a/frame/whitelist/Cargo.toml +++ b/frame/whitelist/Cargo.toml @@ -17,25 +17,26 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } + frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] sp-core = { version = "6.0.0", path = "../../primitives/core" } -pallet-preimage = { version = "4.0.0-dev", path = "../preimage/" } -pallet-balances = { version = "4.0.0-dev", path = "../balances/" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +pallet-balances = { version = "4.0.0-dev", path = "../balances" } +pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } [features] default = ["std"] std = [ "codec/std", "scale-info/std", - "sp-std/std", - "sp-io/std", + "sp-api/std", "sp-runtime/std", + "sp-std/std", "frame-support/std", "frame-system/std", ] diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index c51ea0a0a3246..50809ddef7ec1 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -20,10 +20,11 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use core::convert::TryInto; use frame_benchmarking::benchmarks; -use frame_support::{ensure, traits::PreimageRecipient}; -use sp_runtime::traits::Hash; +use frame_support::{ + ensure, + traits::{EnsureOrigin, Get, PreimageRecipient}, +}; #[cfg(test)] use crate::Pallet as Whitelist; diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index 9f20386da85f5..c2de16964a494 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -39,21 +39,15 @@ mod mock; mod tests; pub mod weights; -use sp_runtime::traits::Dispatchable; -use sp_std::prelude::*; - use codec::{Decode, DecodeLimit, Encode, FullCodec, MaxEncodedLen}; use frame_support::{ ensure, traits::{PreimageProvider, PreimageRecipient}, - weights::{GetDispatchInfo, PostDispatchInfo}, + weights::{GetDispatchInfo, PostDispatchInfo, Weight}, }; use scale_info::TypeInfo; -use sp_api::HashT; -use weights::WeightInfo; - -use frame_support::pallet_prelude::*; -use frame_system::pallet_prelude::*; +use sp_runtime::traits::{Dispatchable, Hash}; +use sp_std::prelude::*; pub use pallet::*; @@ -66,6 +60,9 @@ pub struct Preimage { #[frame_support::pallet] pub mod pallet { use super::*; + use crate::weights::WeightInfo; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; #[pallet::config] pub trait Config: frame_system::Config { @@ -92,7 +89,7 @@ pub mod pallet { type PreimageProvider: PreimageProvider + PreimageRecipient; /// The weight information for this pallet. - type WeightInfo: weights::WeightInfo; + type WeightInfo: WeightInfo; } #[pallet::pallet] From 28eaae58daa52341c2128531be510ac039437f5c Mon Sep 17 00:00:00 2001 From: zqhxuyuan Date: Mon, 21 Mar 2022 16:41:37 +0800 Subject: [PATCH 0618/1472] add MaxEncodedLen trait to Time (#11078) --- frame/support/src/traits/misc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 8c61874003bce..2a0d6f0523e71 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -510,7 +510,7 @@ pub trait HandleLifetime { impl HandleLifetime for () {} pub trait Time { - type Moment: sp_arithmetic::traits::AtLeast32Bit + Parameter + Default + Copy; + type Moment: sp_arithmetic::traits::AtLeast32Bit + Parameter + Default + Copy + MaxEncodedLen; fn now() -> Self::Moment; } From 5917c0e1a0b3746b08fc86f26e270fcca1492bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 21 Mar 2022 11:35:49 +0100 Subject: [PATCH 0619/1472] pallet-macro: Ensure that building with `missing_docs` works (#11075) * pallet-macro: Ensure that building with `missing_docs` works Before this pr it was failing when compiling with `missing_docs`, because the macro was generating functions etc without the appropriate docs. In the case of this pr it is mainly about hiding these functions in the docs as they are internal api anyway. * Fix UI test --- .../support/procedural/src/pallet/expand/call.rs | 5 ++++- .../procedural/src/pallet/expand/error.rs | 2 ++ .../src/pallet/expand/pallet_struct.rs | 2 ++ .../procedural/src/pallet/expand/storage.rs | 2 ++ frame/support/test/Cargo.toml | 2 +- frame/support/test/pallet/src/lib.rs | 16 ++++++++++++++++ .../call_argument_invalid_bound_2.stderr | 6 +++--- 7 files changed, 30 insertions(+), 5 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 355d4f87d3db9..2d7c550a44869 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -178,7 +178,10 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { #( #( #[doc = #fn_doc] )* #fn_name { - #( #args_compact_attr #args_name_stripped: #args_type ),* + #( + #[allow(missing_docs)] + #args_compact_attr #args_name_stripped: #args_type + ),* }, )* } diff --git a/frame/support/procedural/src/pallet/expand/error.rs b/frame/support/procedural/src/pallet/expand/error.rs index 9e2b801083e46..184fa86d3ae19 100644 --- a/frame/support/procedural/src/pallet/expand/error.rs +++ b/frame/support/procedural/src/pallet/expand/error.rs @@ -90,6 +90,7 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { } impl<#type_impl_gen> #error_ident<#type_use_gen> #config_where_clause { + #[doc(hidden)] pub fn as_u8(&self) -> u8 { match &self { Self::__Ignore(_, _) => unreachable!("`__Ignore` can never be constructed"), @@ -97,6 +98,7 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { } } + #[doc(hidden)] pub fn as_str(&self) -> &'static str { match &self { Self::__Ignore(_, _) => unreachable!("`__Ignore` can never be constructed"), diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 61c6d001a6f94..52586a70a521a 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -81,6 +81,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { let error_ident = &error_def.error; quote::quote_spanned!(def.pallet_struct.attr_span => impl<#type_impl_gen> #pallet_ident<#type_use_gen> #config_where_clause { + #[doc(hidden)] pub fn error_metadata() -> Option<#frame_support::metadata::PalletErrorMetadata> { Some(#frame_support::metadata::PalletErrorMetadata { ty: #frame_support::scale_info::meta_type::<#error_ident<#type_use_gen>>() @@ -91,6 +92,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { } else { quote::quote_spanned!(def.pallet_struct.attr_span => impl<#type_impl_gen> #pallet_ident<#type_use_gen> #config_where_clause { + #[doc(hidden)] pub fn error_metadata() -> Option<#frame_support::metadata::PalletErrorMetadata> { None } diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index f45223c1cc842..d59dd46051392 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -406,6 +406,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { quote::quote_spanned!(storage_def.attr_span => #(#cfg_attrs)* + #[doc(hidden)] #prefix_struct_vis struct #counter_prefix_struct_ident<#type_use_gen>( core::marker::PhantomData<(#type_use_gen,)> ); @@ -439,6 +440,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { #maybe_counter #(#cfg_attrs)* + #[doc(hidden)] #prefix_struct_vis struct #prefix_struct_ident<#type_use_gen>( core::marker::PhantomData<(#type_use_gen,)> ); diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index d99889cf99bc4..383b7cf812b41 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -23,7 +23,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../../pri sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } -trybuild = "1.0.53" +trybuild = { version = "1.0.53", features = [ "diff" ] } pretty_assertions = "1.0.0" rustversion = "1.0.6" frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/support/test/pallet/src/lib.rs b/frame/support/test/pallet/src/lib.rs index 25741313c2a03..37678e056f3e1 100644 --- a/frame/support/test/pallet/src/lib.rs +++ b/frame/support/test/pallet/src/lib.rs @@ -14,6 +14,12 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + +//! Testing pallet macro + +// Ensure docs are propagated properly by the macros. +#![warn(missing_docs)] + pub use pallet::*; #[frame_support::pallet] @@ -29,6 +35,10 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config {} + /// I'm the documentation + #[pallet::storage] + pub type Value = StorageValue; + #[pallet::genesis_config] #[cfg_attr(feature = "std", derive(Default))] pub struct GenesisConfig {} @@ -37,4 +47,10 @@ pub mod pallet { impl GenesisBuild for GenesisConfig { fn build(&self) {} } + + #[pallet::error] + pub enum Error { + /// Something failed + Test, + } } diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index e9d267274a6ed..aff0661620874 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -56,10 +56,10 @@ note: required by a bound in `encode_to` = note: this error originates in the derive macro `frame_support::codec::Encode` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:17:12 | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` +17 | #[pallet::call] + | ^^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` | = note: required because of the requirements on the impl of `Decode` for `::Bar` note: required by a bound in `parity_scale_codec::Decode::decode` From 5d630dd5d0387e297617b407db3deae7bf584df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 21 Mar 2022 13:15:37 +0100 Subject: [PATCH 0620/1472] import-blocks: Do not read `stdin` to memory (#11072) * import-blocks: Do not read `stdin` to memory This fixes a bug with `import-blocks` reading the entire `stdin` before starting to import the blocks. However, for huge files that uses quite a lot of memory. We can just read from `stdin` step by step as we do it with a file. This ensures that we don't read the entire input at once into memory. * FMT * Fix warning --- client/cli/src/commands/import_blocks_cmd.rs | 8 ++------ client/service/src/chain_ops/import_blocks.rs | 15 ++++++++------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/client/cli/src/commands/import_blocks_cmd.rs b/client/cli/src/commands/import_blocks_cmd.rs index fece33ba23a2c..749824834bf7b 100644 --- a/client/cli/src/commands/import_blocks_cmd.rs +++ b/client/cli/src/commands/import_blocks_cmd.rs @@ -72,13 +72,9 @@ impl ImportBlocksCmd { B: BlockT + for<'de> serde::Deserialize<'de>, IQ: sc_service::ImportQueue + 'static, { - let file: Box = match &self.input { + let file: Box = match &self.input { Some(filename) => Box::new(fs::File::open(filename)?), - None => { - let mut buffer = Vec::new(); - io::stdin().read_to_end(&mut buffer)?; - Box::new(io::Cursor::new(buffer)) - }, + None => Box::new(io::stdin()), }; import_blocks(client, import_queue, file, false, self.binary) diff --git a/client/service/src/chain_ops/import_blocks.rs b/client/service/src/chain_ops/import_blocks.rs index 9d74fa1c276fa..dc03cdcedae06 100644 --- a/client/service/src/chain_ops/import_blocks.rs +++ b/client/service/src/chain_ops/import_blocks.rs @@ -36,7 +36,7 @@ use sp_runtime::{ }; use std::{ convert::{TryFrom, TryInto}, - io::{Read, Seek}, + io::Read, pin::Pin, task::Poll, time::{Duration, Instant}, @@ -63,7 +63,7 @@ pub fn build_spec(spec: &dyn ChainSpec, raw: bool) -> error::Result { /// SignedBlock and return it. enum BlockIter where - R: std::io::Read + std::io::Seek, + R: std::io::Read, { Binary { // Total number of blocks we are expecting to decode. @@ -83,7 +83,7 @@ where impl BlockIter where - R: Read + Seek + 'static, + R: Read + 'static, B: BlockT + MaybeSerializeDeserialize, { fn new(input: R, binary: bool) -> Result { @@ -119,7 +119,7 @@ where impl Iterator for BlockIter where - R: Read + Seek + 'static, + R: Read + 'static, B: BlockT + MaybeSerializeDeserialize, { type Item = Result, String>; @@ -267,10 +267,11 @@ impl Speedometer { /// Different State that the `import_blocks` future could be in. enum ImportState where - R: Read + Seek + 'static, + R: Read + 'static, B: BlockT + MaybeSerializeDeserialize, { - /// We are reading from the BlockIter structure, adding those blocks to the queue if possible. + /// We are reading from the [`BlockIter`] structure, adding those blocks to the queue if + /// possible. Reading { block_iter: BlockIter }, /// The queue is full (contains at least MAX_PENDING_BLOCKS blocks) and we are waiting for it /// to catch up. @@ -291,7 +292,7 @@ where pub fn import_blocks( client: Arc, mut import_queue: IQ, - input: impl Read + Seek + Send + 'static, + input: impl Read + Send + 'static, force: bool, binary: bool, ) -> Pin> + Send>> From 1bd5d786fda99d5a0c27c339226789ac047ea4ae Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Mon, 21 Mar 2022 08:21:53 -0400 Subject: [PATCH 0621/1472] Don't return the same block twice in ancestor binary search (#11067) * Don't return the same block in ancestor search * Add regression test for ancestor search repeat --- client/network/src/protocol/sync.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index f31afc828bd86..749366f6c1653 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -2320,7 +2320,11 @@ fn handle_ancestor_search_state( } assert!(right >= left); let middle = left + (right - left) / two; - Some((AncestorSearchState::BinarySearch(left, right), middle)) + if middle == curr_block_num { + None + } else { + Some((AncestorSearchState::BinarySearch(left, right), middle)) + } }, } } @@ -3238,4 +3242,9 @@ mod test { sync.on_block_data(&peer_id1, Some(request), response).unwrap(); assert_eq!(sync.best_queued_number, 4); } + #[test] + fn ancestor_search_repeat() { + let state = AncestorSearchState::::BinarySearch(1, 3); + assert!(handle_ancestor_search_state(&state, 2, true).is_none()); + } } From ec0258e48f21705ed92499d71fe9ee17f57af616 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Tue, 22 Mar 2022 03:47:05 -0400 Subject: [PATCH 0622/1472] Don't ban peers for small duplicate requests (#11084) * Don't ban peers for small duplicate requests * Address review comment --- client/network/src/block_request_handler.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/client/network/src/block_request_handler.rs b/client/network/src/block_request_handler.rs index 2f17cdac0744b..e1fe9ebf8d060 100644 --- a/client/network/src/block_request_handler.rs +++ b/client/network/src/block_request_handler.rs @@ -54,6 +54,10 @@ mod rep { /// Reputation change when a peer sent us the same request multiple times. pub const SAME_REQUEST: Rep = Rep::new_fatal("Same block request multiple times"); + + /// Reputation change when a peer sent us the same "small" request multiple times. + pub const SAME_SMALL_REQUEST: Rep = + Rep::new(-(1 << 10), "same small block request multiple times"); } /// Generates a [`ProtocolConfig`] for the block request protocol, refusing incoming requests. @@ -200,8 +204,16 @@ impl BlockRequestHandler { Some(SeenRequestsValue::Fulfilled(ref mut requests)) => { *requests = requests.saturating_add(1); + let small_request = attributes + .difference(BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION) + .is_empty(); + if *requests > MAX_NUMBER_OF_SAME_REQUESTS_PER_PEER { - reputation_change = Some(rep::SAME_REQUEST); + reputation_change = Some(if small_request { + rep::SAME_SMALL_REQUEST + } else { + rep::SAME_REQUEST + }); } }, None => { From c558351a601f8b6f68aec7e1469972f6d265b0c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 22 Mar 2022 09:23:47 +0100 Subject: [PATCH 0623/1472] Add `dev_getBlockStats` RPC (#10939) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add chain_getBlockStats rpc * Fix broken doc link * Apply suggestions from code review Co-authored-by: Niklas Adolfsson * Apply suggestions from code review Co-authored-by: Bastian Köcher * fmt * Fix compilation * Move Blockstats * Apply suggestions from code review Co-authored-by: David * fmt Co-authored-by: ascjones Co-authored-by: Niklas Adolfsson Co-authored-by: Bastian Köcher Co-authored-by: David --- Cargo.lock | 1 + bin/node/rpc/src/lib.rs | 7 +- client/rpc-api/Cargo.toml | 1 + client/rpc-api/src/dev/error.rs | 71 +++++++++++++++++++ client/rpc-api/src/dev/mod.rs | 64 +++++++++++++++++ client/rpc-api/src/lib.rs | 1 + client/rpc/src/dev/mod.rs | 118 ++++++++++++++++++++++++++++++++ client/rpc/src/dev/tests.rs | 58 ++++++++++++++++ client/rpc/src/lib.rs | 1 + 9 files changed, 319 insertions(+), 3 deletions(-) create mode 100644 client/rpc-api/src/dev/error.rs create mode 100644 client/rpc-api/src/dev/mod.rs create mode 100644 client/rpc/src/dev/mod.rs create mode 100644 client/rpc/src/dev/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 3de4fc3f7020a..3d9068f8ebd7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8864,6 +8864,7 @@ dependencies = [ "parking_lot 0.12.0", "sc-chain-spec", "sc-transaction-pool-api", + "scale-info", "serde", "serde_json", "sp-core", diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 09f350ed3dcf1..b8349e26cd1da 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -103,6 +103,7 @@ pub fn create_full( ) -> Result, Box> where C: ProvideRuntimeApi + + sc_client_api::BlockBackend + HeaderBackend + AuxStore + HeaderMetadata @@ -123,6 +124,7 @@ where use pallet_contracts_rpc::{Contracts, ContractsApi}; use pallet_mmr_rpc::{Mmr, MmrApi}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; + use sc_rpc::dev::{Dev, DevApi}; use substrate_frame_rpc_system::{FullSystem, SystemApi}; let mut io = jsonrpc_core::IoHandler::default(); @@ -159,19 +161,18 @@ where subscription_executor, finality_provider, ))); - io.extend_with(substrate_state_trie_migration_rpc::StateMigrationApi::to_delegate( substrate_state_trie_migration_rpc::MigrationRpc::new(client.clone(), backend, deny_unsafe), )); - io.extend_with(sc_sync_state_rpc::SyncStateRpcApi::to_delegate( sc_sync_state_rpc::SyncStateRpcHandler::new( chain_spec, - client, + client.clone(), shared_authority_set, shared_epoch_changes, )?, )); + io.extend_with(DevApi::to_delegate(Dev::new(client, deny_unsafe))); Ok(io) } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 38ac1fc443351..06deb0eef0ce3 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -23,6 +23,7 @@ log = "0.4.8" parking_lot = "0.12.0" thiserror = "1.0" +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-version = { version = "5.0.0", path = "../../primitives/version" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } diff --git a/client/rpc-api/src/dev/error.rs b/client/rpc-api/src/dev/error.rs new file mode 100644 index 0000000000000..1a14b0d78994e --- /dev/null +++ b/client/rpc-api/src/dev/error.rs @@ -0,0 +1,71 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Error helpers for Dev RPC module. + +use crate::errors; +use jsonrpc_core as rpc; + +/// Dev RPC Result type. +pub type Result = std::result::Result; + +/// Dev RPC future Result type. +pub type FutureResult = jsonrpc_core::BoxFuture>; + +/// Dev RPC errors. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Failed to query specified block or its parent: Probably an invalid hash. + #[error("Error while querying block: {0}")] + BlockQueryError(Box), + /// The re-execution of the specified block failed. + #[error("Failed to re-execute the specified block")] + BlockExecutionFailed, + /// The witness compaction failed. + #[error("Failed to create to compact the witness")] + WitnessCompactionFailed, + /// The method is marked as unsafe but unsafe flag wasn't supplied on the CLI. + #[error(transparent)] + UnsafeRpcCalled(#[from] crate::policy::UnsafeRpcError), +} + +/// Base error code for all dev errors. +const BASE_ERROR: i64 = 6000; + +impl From for rpc::Error { + fn from(e: Error) -> Self { + match e { + Error::BlockQueryError(_) => rpc::Error { + code: rpc::ErrorCode::ServerError(BASE_ERROR + 1), + message: e.to_string(), + data: None, + }, + Error::BlockExecutionFailed => rpc::Error { + code: rpc::ErrorCode::ServerError(BASE_ERROR + 3), + message: e.to_string(), + data: None, + }, + Error::WitnessCompactionFailed => rpc::Error { + code: rpc::ErrorCode::ServerError(BASE_ERROR + 4), + message: e.to_string(), + data: None, + }, + e => errors::internal(e), + } + } +} diff --git a/client/rpc-api/src/dev/mod.rs b/client/rpc-api/src/dev/mod.rs new file mode 100644 index 0000000000000..b1ae8934af8a1 --- /dev/null +++ b/client/rpc-api/src/dev/mod.rs @@ -0,0 +1,64 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate dev API containing RPCs that are mainly meant for debugging and stats collection for +//! developers. The endpoints in this RPC module are not meant to be available to non-local users +//! and are all marked `unsafe`. + +pub mod error; + +use self::error::Result; +use codec::{Decode, Encode}; +use jsonrpc_derive::rpc; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; + +/// Statistics of a block returned by the `dev_getBlockStats` RPC. +#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BlockStats { + /// The length in bytes of the storage proof produced by executing the block. + pub witness_len: u64, + /// The length in bytes of the storage proof after compaction. + pub witness_compact_len: u64, + /// Length of the block in bytes. + /// + /// This information can also be acquired by downloading the whole block. This merely + /// saves some complexity on the client side. + pub block_len: u64, + /// Number of extrinsics in the block. + /// + /// This information can also be acquired by downloading the whole block. This merely + /// saves some complexity on the client side. + pub num_extrinsics: u64, +} + +/// Substrate dev API. +/// +/// This API contains unstable and unsafe methods only meant for development nodes. They +/// are all flagged as unsafe for this reason. +#[rpc] +pub trait DevApi { + /// Reexecute the specified `block_hash` and gather statistics while doing so. + /// + /// This function requires the specified block and its parent to be available + /// at the queried node. If either the specified block or the parent is pruned, + /// this function will return `None`. + #[rpc(name = "dev_getBlockStats")] + fn block_stats(&self, block_hash: Hash) -> Result>; +} diff --git a/client/rpc-api/src/lib.rs b/client/rpc-api/src/lib.rs index 2b2e09e709aa9..e06f30bf9cd87 100644 --- a/client/rpc-api/src/lib.rs +++ b/client/rpc-api/src/lib.rs @@ -35,6 +35,7 @@ pub use policy::{DenyUnsafe, UnsafeRpcError}; pub mod author; pub mod chain; pub mod child_state; +pub mod dev; pub mod offchain; pub mod state; pub mod system; diff --git a/client/rpc/src/dev/mod.rs b/client/rpc/src/dev/mod.rs new file mode 100644 index 0000000000000..d782a03feae43 --- /dev/null +++ b/client/rpc/src/dev/mod.rs @@ -0,0 +1,118 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Implementation of the [`DevApi`] trait providing debug utilities for Substrate based +//! blockchains. + +#[cfg(test)] +mod tests; + +pub use sc_rpc_api::dev::{BlockStats, DevApi}; + +use sc_client_api::{BlockBackend, HeaderBackend}; +use sc_rpc_api::{ + dev::error::{Error, Result}, + DenyUnsafe, +}; +use sp_api::{ApiExt, Core, ProvideRuntimeApi}; +use sp_core::Encode; +use sp_runtime::{ + generic::{BlockId, DigestItem}, + traits::{Block as BlockT, Header}, +}; +use std::{ + marker::{PhantomData, Send, Sync}, + sync::Arc, +}; + +type HasherOf = <::Header as Header>::Hashing; + +/// The Dev API. All methods are unsafe. +pub struct Dev { + client: Arc, + deny_unsafe: DenyUnsafe, + _phantom: PhantomData, +} + +impl Dev { + /// Create a new Dev API. + pub fn new(client: Arc, deny_unsafe: DenyUnsafe) -> Self { + Self { client, deny_unsafe, _phantom: PhantomData::default() } + } +} + +impl DevApi for Dev +where + Block: BlockT + 'static, + Client: BlockBackend + + HeaderBackend + + ProvideRuntimeApi + + Send + + Sync + + 'static, + Client::Api: Core, +{ + fn block_stats(&self, hash: Block::Hash) -> Result> { + self.deny_unsafe.check_if_safe()?; + + let block = { + let block = self + .client + .block(&BlockId::Hash(hash)) + .map_err(|e| Error::BlockQueryError(Box::new(e)))?; + if let Some(block) = block { + let (mut header, body) = block.block.deconstruct(); + // Remove the `Seal` to ensure we have the number of digests as expected by the + // runtime. + header.digest_mut().logs.retain(|item| !matches!(item, DigestItem::Seal(_, _))); + Block::new(header, body) + } else { + return Ok(None) + } + }; + let parent_header = { + let parent_hash = *block.header().parent_hash(); + let parent_header = self + .client + .header(BlockId::Hash(parent_hash)) + .map_err(|e| Error::BlockQueryError(Box::new(e)))?; + if let Some(header) = parent_header { + header + } else { + return Ok(None) + } + }; + let block_len = block.encoded_size() as u64; + let num_extrinsics = block.extrinsics().len() as u64; + let pre_root = *parent_header.state_root(); + let mut runtime_api = self.client.runtime_api(); + runtime_api.record_proof(); + runtime_api + .execute_block(&BlockId::Hash(parent_header.hash()), block) + .map_err(|_| Error::BlockExecutionFailed)?; + let witness = runtime_api + .extract_proof() + .expect("We enabled proof recording. A proof must be available; qed"); + let witness_len = witness.encoded_size() as u64; + let witness_compact_len = witness + .into_compact_proof::>(pre_root) + .map_err(|_| Error::WitnessCompactionFailed)? + .encoded_size() as u64; + Ok(Some(BlockStats { witness_len, witness_compact_len, block_len, num_extrinsics })) + } +} diff --git a/client/rpc/src/dev/tests.rs b/client/rpc/src/dev/tests.rs new file mode 100644 index 0000000000000..1d31abe38b640 --- /dev/null +++ b/client/rpc/src/dev/tests.rs @@ -0,0 +1,58 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; +use assert_matches::assert_matches; +use futures::executor; +use sc_block_builder::BlockBuilderProvider; +use sp_blockchain::HeaderBackend; +use sp_consensus::BlockOrigin; +use substrate_test_runtime_client::{prelude::*, runtime::Block}; + +#[test] +fn block_stats_work() { + let mut client = Arc::new(substrate_test_runtime_client::new()); + let api = >::new(client.clone(), DenyUnsafe::No); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); + + // Can't gather stats for a block without a parent. + assert_eq!(api.block_stats(client.genesis_hash()).unwrap(), None); + + assert_eq!( + api.block_stats(client.info().best_hash).unwrap(), + Some(BlockStats { + witness_len: 597, + witness_compact_len: 500, + block_len: 99, + num_extrinsics: 0, + }), + ); +} + +#[test] +fn deny_unsafe_works() { + let mut client = Arc::new(substrate_test_runtime_client::new()); + let api = >::new(client.clone(), DenyUnsafe::Yes); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); + + assert_matches!(api.block_stats(client.info().best_hash), Err(Error::UnsafeRpcCalled(_))); +} diff --git a/client/rpc/src/lib.rs b/client/rpc/src/lib.rs index 3966baf13c756..59a1d542d365a 100644 --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -34,6 +34,7 @@ pub use sc_rpc_api::{DenyUnsafe, Metadata}; pub mod author; pub mod chain; +pub mod dev; pub mod offchain; pub mod state; pub mod system; From c9fc99d296a6bd3ac4a47d77cc855a1380b7cf69 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Tue, 22 Mar 2022 21:45:35 +1300 Subject: [PATCH 0624/1472] Add ProxyRemoved event (#11085) --- frame/proxy/src/lib.rs | 19 ++++++++++++++++++- frame/proxy/src/tests.rs | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 425af18367854..84f1a84badc90 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -570,6 +570,13 @@ pub mod pallet { proxy_type: T::ProxyType, delay: T::BlockNumber, }, + /// A proxy was removed. + ProxyRemoved { + delegator: T::AccountId, + delegatee: T::AccountId, + proxy_type: T::ProxyType, + delay: T::BlockNumber, + }, } /// Old name generated by `decl_event`. @@ -712,7 +719,11 @@ impl Pallet { ) -> DispatchResult { Proxies::::try_mutate_exists(delegator, |x| { let (mut proxies, old_deposit) = x.take().ok_or(Error::::NotFound)?; - let proxy_def = ProxyDefinition { delegate: delegatee, proxy_type, delay }; + let proxy_def = ProxyDefinition { + delegate: delegatee.clone(), + proxy_type: proxy_type.clone(), + delay, + }; let i = proxies.binary_search(&proxy_def).ok().ok_or(Error::::NotFound)?; proxies.remove(i); let new_deposit = Self::deposit(proxies.len() as u32); @@ -724,6 +735,12 @@ impl Pallet { if !proxies.is_empty() { *x = Some((proxies, new_deposit)) } + Self::deposit_event(Event::::ProxyRemoved { + delegator: delegator.clone(), + delegatee, + proxy_type, + delay, + }); Ok(()) }) } diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index b4f30ab4029ab..a0807f1d3d0b6 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -436,13 +436,49 @@ fn add_remove_proxies_works() { Error::::NotFound ); assert_ok!(Proxy::remove_proxy(Origin::signed(1), 4, ProxyType::JustUtility, 0)); + System::assert_last_event( + ProxyEvent::ProxyRemoved { + delegator: 1, + delegatee: 4, + proxy_type: ProxyType::JustUtility, + delay: 0, + } + .into(), + ); assert_eq!(Balances::reserved_balance(1), 4); assert_ok!(Proxy::remove_proxy(Origin::signed(1), 3, ProxyType::Any, 0)); assert_eq!(Balances::reserved_balance(1), 3); + System::assert_last_event( + ProxyEvent::ProxyRemoved { + delegator: 1, + delegatee: 3, + proxy_type: ProxyType::Any, + delay: 0, + } + .into(), + ); assert_ok!(Proxy::remove_proxy(Origin::signed(1), 2, ProxyType::Any, 0)); assert_eq!(Balances::reserved_balance(1), 2); + System::assert_last_event( + ProxyEvent::ProxyRemoved { + delegator: 1, + delegatee: 2, + proxy_type: ProxyType::Any, + delay: 0, + } + .into(), + ); assert_ok!(Proxy::remove_proxy(Origin::signed(1), 2, ProxyType::JustTransfer, 0)); assert_eq!(Balances::reserved_balance(1), 0); + System::assert_last_event( + ProxyEvent::ProxyRemoved { + delegator: 1, + delegatee: 2, + proxy_type: ProxyType::JustTransfer, + delay: 0, + } + .into(), + ); assert_noop!( Proxy::add_proxy(Origin::signed(1), 1, ProxyType::Any, 0), Error::::NoSelfProxy From 715d004061cccbe900d9b2e6d3d624087a34eeef Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 22 Mar 2022 10:53:49 +0100 Subject: [PATCH 0625/1472] Do not upgrade db_version on metadata reading failure. (#11081) --- Cargo.lock | 4 ++-- client/db/Cargo.toml | 2 +- client/db/src/parity_db.rs | 2 +- client/db/src/utils.rs | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d9068f8ebd7c..8e725af983a5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6697,9 +6697,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "865edee5b792f537356d9e55cbc138e7f4718dc881a7ea45a18b37bf61c21e3d" +checksum = "3d121a9af17a43efd0a38c6afa508b927ba07785bd4709efb2ac03bf77efef8d" dependencies = [ "blake2-rfc", "crc32fast", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 7b1e4da20861e..105bc43c61bc9 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -33,7 +33,7 @@ sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-trie = { version = "6.0.0", path = "../../primitives/trie" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -parity-db = { version = "0.3.8", optional = true } +parity-db = { version = "0.3.9", optional = true } [dev-dependencies] sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } diff --git a/client/db/src/parity_db.rs b/client/db/src/parity_db.rs index c81a346bb023f..f88e6f2e91678 100644 --- a/client/db/src/parity_db.rs +++ b/client/db/src/parity_db.rs @@ -73,7 +73,7 @@ pub fn open>( if upgrade { log::info!("Upgrading database metadata."); if let Some(meta) = parity_db::Options::load_metadata(path)? { - config.write_metadata(path, &meta.salt)?; + config.write_metadata_with_version(path, &meta.salt, Some(meta.version))?; } } diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index 7dcb6676a1750..29aa8424221a6 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -275,6 +275,7 @@ fn open_parity_db(path: &Path, db_type: DatabaseType, create: boo match crate::parity_db::open(path, db_type, create, false) { Ok(db) => Ok(db), Err(parity_db::Error::InvalidConfiguration(_)) => { + log::warn!("Invalid parity db configuration, attempting database metadata update."); // Try to update the database with the new config Ok(crate::parity_db::open(path, db_type, create, true)?) }, From 77c15d2546276a865b6e8f1c5d4b1d0ec1961e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 22 Mar 2022 13:25:34 +0100 Subject: [PATCH 0626/1472] warp-sync: Return an error when trying to enable it for archive nodes. (#11086) * warp-sync: Return an error when trying to enable it for archive nodes. * Fix checks * Ups * FMT --- client/network/src/config.rs | 14 +++++++++++++- client/service/src/builder.rs | 14 +++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/client/network/src/config.rs b/client/network/src/config.rs index a7e4e5cc87668..eedf3fc22b961 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -377,8 +377,8 @@ impl From for ParseErr { } } -#[derive(Clone, Debug, Eq, PartialEq)] /// Sync operation mode. +#[derive(Clone, Debug, Eq, PartialEq)] pub enum SyncMode { /// Full block download and verification. Full, @@ -393,6 +393,18 @@ pub enum SyncMode { Warp, } +impl SyncMode { + /// Returns if `self` is [`Self::Warp`]. + pub fn is_warp(&self) -> bool { + matches!(self, Self::Warp) + } + + /// Returns if `self` is [`Self::Fast`]. + pub fn is_fast(&self) -> bool { + matches!(self, Self::Fast { .. }) + } +} + impl Default for SyncMode { fn default() -> Self { Self::Full diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index e9c1691107c71..f4ff932435755 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -39,7 +39,7 @@ use sc_executor::RuntimeVersionOf; use sc_keystore::LocalKeystore; use sc_network::{ block_request_handler::{self, BlockRequestHandler}, - config::Role, + config::{Role, SyncMode}, light_client_requests::{self, handler::LightClientRequestHandler}, state_request_handler::{self, StateRequestHandler}, warp_request_handler::{self, RequestHandler as WarpSyncRequestHandler, WarpSyncProvider}, @@ -767,6 +767,18 @@ where warp_sync, } = params; + if warp_sync.is_none() && config.network.sync_mode.is_warp() { + return Err("Warp sync enabled, but no warp sync provider configured.".into()) + } + + if config.state_pruning.is_archive() { + match config.network.sync_mode { + SyncMode::Fast { .. } => return Err("Fast sync doesn't work for archive nodes".into()), + SyncMode::Warp => return Err("Warp sync doesn't work for archive nodes".into()), + SyncMode::Full => {}, + }; + } + let transaction_pool_adapter = Arc::new(TransactionPoolAdapter { imports_external_transactions: !matches!(config.role, Role::Light), pool: transaction_pool, From 096f205d82303a889cf566792262e8ffe61bb7fb Mon Sep 17 00:00:00 2001 From: Georges Date: Wed, 23 Mar 2022 09:14:44 +0000 Subject: [PATCH 0627/1472] Implementing `MaxEncodedLen` for `generate_solution_type` (#11032) * Move `sp-npos-elections-solution-type` to `frame-election-provider-support` First stab at it, will need to amend some more stuff * Fixing tests * Fixing tests * Fixing cargo.toml for std configuration * Implementing `MaxEncodedLen` on `generate_solution_type` * Full implementation of `max_encoded_len` * Fixing implementation bug adding some comments and documentation * fmt * Committing suggested changes renaming, and re exporting macro. * Removing unneeded imports * Implementing `MaxEncodedLen` on `generate_solution_type` * Full implementation of `max_encoded_len` * Fixing implementation bug adding some comments and documentation * Move `NposSolution` to frame * Implementing `MaxEncodedLen` on `generate_solution_type` * Full implementation of `max_encoded_len` * Fixing implementation bug adding some comments and documentation * Fixing test * Removing unneeded dependencies * `VoterSnapshotPerBlock` -> `MaxElectingVoters` * rename `SizeBound` to `MaxVoters` * Removing TODO and change bound * renaming `size_bound` to `max_voters` * Enabling tests for `solution-type` These got dropped off after the crate was moved from `sp_npos_elections` * Adding tests for `MaxEncodedLen` of solution_type * Better rustdocs. Better indenting and comments. Removing unneeded imports in tests. --- Cargo.lock | 3 + bin/node/runtime/src/lib.rs | 4 +- .../election-provider-multi-phase/src/mock.rs | 7 +- frame/election-provider-support/Cargo.toml | 1 + .../solution-type/Cargo.toml | 1 + .../solution-type/fuzzer/Cargo.toml | 1 + .../solution-type/fuzzer/src/compact.rs | 1 + .../solution-type/src/lib.rs | 35 ++++++-- .../solution-type/src/single_page.rs | 22 +++++ .../tests/ui/fail/missing_accuracy.rs | 1 + .../tests/ui/fail/missing_size_bound.rs | 10 +++ .../tests/ui/fail/missing_size_bound.stderr | 5 ++ .../tests/ui/fail/missing_target.rs | 1 + .../tests/ui/fail/missing_voter.rs | 1 + .../tests/ui/fail/no_annotations.rs | 1 + .../tests/ui/fail/swap_voter_target.rs | 1 + .../tests/ui/fail/wrong_attribute.rs | 1 + frame/election-provider-support/src/lib.rs | 5 ++ .../{solution-type => }/src/mock.rs | 11 ++- .../{solution-type => }/src/tests.rs | 84 ++++++++++++++++++- 20 files changed, 184 insertions(+), 12 deletions(-) create mode 100644 frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.rs create mode 100644 frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.stderr rename frame/election-provider-support/{solution-type => }/src/mock.rs (96%) rename frame/election-provider-support/{solution-type => }/src/tests.rs (80%) diff --git a/Cargo.lock b/Cargo.lock index 8e725af983a5d..1b478fcc18a78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2167,6 +2167,7 @@ name = "frame-election-provider-solution-type" version = "4.0.0-dev" dependencies = [ "frame-election-provider-support", + "frame-support", "parity-scale-codec", "proc-macro-crate 1.1.3", "proc-macro2", @@ -2185,6 +2186,7 @@ dependencies = [ "frame-support", "frame-system", "parity-scale-codec", + "rand 0.7.3", "scale-info", "sp-arithmetic", "sp-core", @@ -2201,6 +2203,7 @@ dependencies = [ "clap 3.1.6", "frame-election-provider-solution-type", "frame-election-provider-support", + "frame-support", "honggfuzz", "parity-scale-codec", "rand 0.8.4", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 64bdcfc870205..b7137de48fb15 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -597,11 +597,13 @@ frame_election_provider_support::generate_solution_type!( VoterIndex = u32, TargetIndex = u16, Accuracy = sp_runtime::PerU16, + MaxVoters = MaxElectingVoters, >(16) ); parameter_types! { pub MaxNominations: u32 = ::LIMIT as u32; + pub MaxElectingVoters: u32 = 10_000; } /// The numbers configured here could always be more than the the maximum limits of staking pallet @@ -677,7 +679,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime { >; type ForceOrigin = EnsureRootOrHalfCouncil; type MaxElectableTargets = ConstU16<{ u16::MAX }>; - type MaxElectingVoters = ConstU32<10_000>; + type MaxElectingVoters = MaxElectingVoters; type BenchmarkingConfig = ElectionProviderBenchmarkConfig; type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 89b5b72565dcb..e2384d2f15761 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -70,7 +70,12 @@ pub(crate) type TargetIndex = u16; frame_election_provider_support::generate_solution_type!( #[compact] - pub struct TestNposSolution::(16) + pub struct TestNposSolution::< + VoterIndex = VoterIndex, + TargetIndex = TargetIndex, + Accuracy = PerU16, + MaxVoters = ConstU32::<20> + >(16) ); /// All events of this pallet. diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 16b79dbb098d4..be0c05e46df32 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -24,6 +24,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys frame-election-provider-solution-type = { version = "4.0.0-dev", path = "solution-type" } [dev-dependencies] +rand = "0.7.3" sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-io = { version = "6.0.0", path = "../../primitives/io" } diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index e59bbcc8e7b38..ca3038c9145ce 100644 --- a/frame/election-provider-support/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -26,4 +26,5 @@ scale-info = "2.0.1" sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } # used by generate_solution_type: frame-election-provider-support = { version = "4.0.0-dev", path = ".." } +frame-support = { version = "4.0.0-dev", path = "../../support" } trybuild = "1.0.53" diff --git a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index f6c2f2fe491e8..e2bae3f72a4f7 100644 --- a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -25,6 +25,7 @@ sp-arithmetic = { version = "5.0.0", path = "../../../../primitives/arithmetic" sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } # used by generate_solution_type: sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/npos-elections" } +frame-support = { version = "4.0.0-dev", path = "../../../support" } [[bin]] name = "compact" diff --git a/frame/election-provider-support/solution-type/fuzzer/src/compact.rs b/frame/election-provider-support/solution-type/fuzzer/src/compact.rs index 501d241b2b80b..e7ef440ff2195 100644 --- a/frame/election-provider-support/solution-type/fuzzer/src/compact.rs +++ b/frame/election-provider-support/solution-type/fuzzer/src/compact.rs @@ -8,6 +8,7 @@ fn main() { VoterIndex = u32, TargetIndex = u32, Accuracy = Percent, + MaxVoters = frame_support::traits::ConstU32::<100_000>, >(16)); loop { fuzz!(|fuzzer_data: &[u8]| { diff --git a/frame/election-provider-support/solution-type/src/lib.rs b/frame/election-provider-support/solution-type/src/lib.rs index 6e2788f06007f..57d939377b62c 100644 --- a/frame/election-provider-support/solution-type/src/lib.rs +++ b/frame/election-provider-support/solution-type/src/lib.rs @@ -49,6 +49,12 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error { /// compact encoding. /// - The accuracy of the ratios. This must be one of the `PerThing` types defined in /// `sp-arithmetic`. +/// - The maximum number of voters. This must be of type `Get`. Check +/// for more details. This is used to bound the struct, by leveraging the fact that `votes1.len() +/// < votes2.len() < ... < votesn.len()` (the details of the struct is explained further below). +/// We know that `sum_i votes_i.len() <= MaxVoters`, and we know that the maximum size of the +/// struct would be achieved if all voters fall in the last bucket. One can also check the tests +/// and more specifically `max_encoded_len_exact` for a concrete example. /// /// Moreover, the maximum number of edges per voter (distribution per assignment) also need to be /// specified. Attempting to convert from/to an assignment with more distributions will fail. @@ -59,10 +65,12 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error { /// ``` /// # use frame_election_provider_solution_type::generate_solution_type; /// # use sp_arithmetic::per_things::Perbill; +/// # use frame_support::traits::ConstU32; /// generate_solution_type!(pub struct TestSolution::< /// VoterIndex = u16, /// TargetIndex = u8, /// Accuracy = Perbill, +/// MaxVoters = ConstU32::<10>, /// >(4)); /// ``` /// @@ -103,9 +111,15 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error { /// # use frame_election_provider_solution_type::generate_solution_type; /// # use frame_election_provider_support::NposSolution; /// # use sp_arithmetic::per_things::Perbill; +/// # use frame_support::traits::ConstU32; /// generate_solution_type!( /// #[compact] -/// pub struct TestSolutionCompact::(8) +/// pub struct TestSolutionCompact::< +/// VoterIndex = u16, +/// TargetIndex = u8, +/// Accuracy = Perbill, +/// MaxVoters = ConstU32::<10>, +/// >(8) /// ); /// ``` #[proc_macro] @@ -129,6 +143,7 @@ struct SolutionDef { voter_type: syn::Type, target_type: syn::Type, weight_type: syn::Type, + max_voters: syn::Type, count: usize, compact_encoding: bool, } @@ -167,11 +182,11 @@ impl Parse for SolutionDef { let _ = ::parse(input)?; let generics: syn::AngleBracketedGenericArguments = input.parse()?; - if generics.args.len() != 3 { - return Err(syn_err("Must provide 3 generic args.")) + if generics.args.len() != 4 { + return Err(syn_err("Must provide 4 generic args.")) } - let expected_types = ["VoterIndex", "TargetIndex", "Accuracy"]; + let expected_types = ["VoterIndex", "TargetIndex", "Accuracy", "MaxVoters"]; let mut types: Vec = generics .args @@ -197,6 +212,7 @@ impl Parse for SolutionDef { }) .collect::>()?; + let max_voters = types.pop().expect("Vector of length 4 can be popped; qed"); let weight_type = types.pop().expect("Vector of length 3 can be popped; qed"); let target_type = types.pop().expect("Vector of length 2 can be popped; qed"); let voter_type = types.pop().expect("Vector of length 1 can be popped; qed"); @@ -205,7 +221,16 @@ impl Parse for SolutionDef { let count_expr: syn::ExprParen = input.parse()?; let count = parse_parenthesized_number::(count_expr)?; - Ok(Self { vis, ident, voter_type, target_type, weight_type, count, compact_encoding }) + Ok(Self { + vis, + ident, + voter_type, + target_type, + weight_type, + max_voters, + count, + compact_encoding, + }) } } diff --git a/frame/election-provider-support/solution-type/src/single_page.rs b/frame/election-provider-support/solution-type/src/single_page.rs index c1d897444da31..5a3ddc22f61c8 100644 --- a/frame/election-provider-support/solution-type/src/single_page.rs +++ b/frame/election-provider-support/solution-type/src/single_page.rs @@ -28,6 +28,7 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { voter_type, target_type, weight_type, + max_voters, compact_encoding, } = def; @@ -178,6 +179,27 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { <#ident as _feps::NposSolution>::TargetIndex, <#ident as _feps::NposSolution>::Accuracy, >; + impl _feps::codec::MaxEncodedLen for #ident { + fn max_encoded_len() -> usize { + use frame_support::traits::Get; + use _feps::codec::Encode; + let s: u32 = #max_voters::get(); + let max_element_size = + // the first voter.. + #voter_type::max_encoded_len() + // #count - 1 tuples.. + .saturating_add( + (#count - 1).saturating_mul( + #target_type::max_encoded_len().saturating_add(#weight_type::max_encoded_len()))) + // and the last target. + .saturating_add(#target_type::max_encoded_len()); + // The assumption is that it contains #count-1 empty elements + // and then last element with full size + #count + .saturating_mul(_feps::codec::Compact(0u32).encoded_size()) + .saturating_add((s as usize).saturating_mul(max_element_size)) + } + } impl<'a> _feps::sp_std::convert::TryFrom<&'a [__IndexAssignment]> for #ident { type Error = _feps::Error; fn try_from(index_assignments: &'a [__IndexAssignment]) -> Result { diff --git a/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs b/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs index 22693cd875e17..52ae9623fd384 100644 --- a/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/missing_accuracy.rs @@ -4,6 +4,7 @@ generate_solution_type!(pub struct TestSolution::< VoterIndex = u16, TargetIndex = u8, Perbill, + MaxVoters = ConstU32::<10>, >(8)); fn main() {} diff --git a/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.rs b/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.rs new file mode 100644 index 0000000000000..fe8ac04cc8d61 --- /dev/null +++ b/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.rs @@ -0,0 +1,10 @@ +use frame_election_provider_solution_type::generate_solution_type; + +generate_solution_type!(pub struct TestSolution::< + VoterIndex = u16, + TargetIndex = u8, + Accuracy = Perbill, + ConstU32::<10>, +>(8)); + +fn main() {} diff --git a/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.stderr b/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.stderr new file mode 100644 index 0000000000000..c685ab816d399 --- /dev/null +++ b/frame/election-provider-support/solution-type/tests/ui/fail/missing_size_bound.stderr @@ -0,0 +1,5 @@ +error: Expected binding: `MaxVoters = ...` + --> tests/ui/fail/missing_size_bound.rs:7:2 + | +7 | ConstU32::<10>, + | ^^^^^^^^^^^^^^ diff --git a/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs b/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs index 8d0ca927c5fb3..b457c4abada6c 100644 --- a/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/missing_target.rs @@ -4,6 +4,7 @@ generate_solution_type!(pub struct TestSolution::< VoterIndex = u16, u8, Accuracy = Perbill, + MaxVoters = ConstU32::<10>, >(8)); fn main() {} diff --git a/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs b/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs index ad4b7f5217794..3d12e3e6b5ec4 100644 --- a/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/missing_voter.rs @@ -4,6 +4,7 @@ generate_solution_type!(pub struct TestSolution::< u16, TargetIndex = u8, Accuracy = Perbill, + MaxVoters = ConstU32::<10>, >(8)); fn main() {} diff --git a/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs b/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs index 87673a3823513..9aab15e7ec9a1 100644 --- a/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/no_annotations.rs @@ -4,6 +4,7 @@ generate_solution_type!(pub struct TestSolution::< u16, u8, Perbill, + MaxVoters = ConstU32::<10>, >(8)); fn main() {} diff --git a/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs b/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs index f1d5d0e7bf99f..4275aae045a60 100644 --- a/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/swap_voter_target.rs @@ -4,6 +4,7 @@ generate_solution_type!(pub struct TestSolution::< TargetIndex = u16, VoterIndex = u8, Accuracy = Perbill, + MaxVoters = ConstU32::<10>, >(8)); fn main() {} diff --git a/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs b/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs index d04cc4a7a966b..a51cc724ad158 100644 --- a/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs +++ b/frame/election-provider-support/solution-type/tests/ui/fail/wrong_attribute.rs @@ -5,6 +5,7 @@ generate_solution_type!( VoterIndex = u8, TargetIndex = u16, Accuracy = Perbill, + MaxVoters = ConstU32::<10>, >(8) ); diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 81fd841a6dc47..2cc27472e8846 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -192,6 +192,11 @@ pub use scale_info; pub use sp_arithmetic; #[doc(hidden)] pub use sp_std; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; // Simple Extension trait to easily convert `None` from index closures to `Err`. // // This is only generated and re-exported for the solution code to use. diff --git a/frame/election-provider-support/solution-type/src/mock.rs b/frame/election-provider-support/src/mock.rs similarity index 96% rename from frame/election-provider-support/solution-type/src/mock.rs rename to frame/election-provider-support/src/mock.rs index c3d032f2eb257..1ea8dddf7eb17 100644 --- a/frame/election-provider-support/solution-type/src/mock.rs +++ b/frame/election-provider-support/src/mock.rs @@ -19,10 +19,16 @@ #![cfg(test)] -use std::{collections::HashMap, convert::TryInto, hash::Hash, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + convert::TryInto, + hash::Hash, +}; use rand::{seq::SliceRandom, Rng}; +pub type AccountId = u64; + /// The candidate mask allows easy disambiguation between voters and candidates: accounts /// for which this bit is set are candidates, and without it, are voters. pub const CANDIDATE_MASK: AccountId = 1 << ((std::mem::size_of::() * 8) - 1); @@ -34,13 +40,14 @@ pub fn p(p: u8) -> TestAccuracy { } pub type MockAssignment = crate::Assignment; -pub type Voter = (AccountId, VoteWeight, Vec); +pub type Voter = (AccountId, crate::VoteWeight, Vec); crate::generate_solution_type! { pub struct TestSolution::< VoterIndex = u32, TargetIndex = u16, Accuracy = TestAccuracy, + MaxVoters = frame_support::traits::ConstU32::<20>, >(16) } diff --git a/frame/election-provider-support/solution-type/src/tests.rs b/frame/election-provider-support/src/tests.rs similarity index 80% rename from frame/election-provider-support/solution-type/src/tests.rs rename to frame/election-provider-support/src/tests.rs index f173e425b5187..7b4e46d836176 100644 --- a/frame/election-provider-support/solution-type/src/tests.rs +++ b/frame/election-provider-support/src/tests.rs @@ -20,13 +20,15 @@ #![cfg(test)] use crate::{mock::*, IndexAssignment, NposSolution}; +use frame_support::traits::ConstU32; use rand::SeedableRng; use std::convert::TryInto; mod solution_type { use super::*; - use codec::{Decode, Encode}; - // these need to come from the same dev-dependency `sp-npos-elections`, not from the crate. + use codec::{Decode, Encode, MaxEncodedLen}; + // these need to come from the same dev-dependency `frame-election-provider-support`, not from + // the crate. use crate::{generate_solution_type, Assignment, Error as NposError, NposSolution}; use sp_std::{convert::TryInto, fmt::Debug}; @@ -37,7 +39,12 @@ mod solution_type { use crate::generate_solution_type; generate_solution_type!( #[compact] - struct InnerTestSolutionIsolated::(12) + struct InnerTestSolutionIsolated::< + VoterIndex = u32, + TargetIndex = u8, + Accuracy = sp_runtime::Percent, + MaxVoters = crate::tests::ConstU32::<20>, + >(12) ); } @@ -50,6 +57,7 @@ mod solution_type { VoterIndex = u32, TargetIndex = u32, Accuracy = TestAccuracy, + MaxVoters = ConstU32::<20>, >(16) ); let solution = InnerTestSolution { @@ -68,6 +76,7 @@ mod solution_type { VoterIndex = u32, TargetIndex = u32, Accuracy = TestAccuracy, + MaxVoters = ConstU32::<20>, >(16) ); let compact = InnerTestSolutionCompact { @@ -82,6 +91,75 @@ mod solution_type { assert!(with_compact < without_compact); } + #[test] + fn max_encoded_len_too_small() { + generate_solution_type!( + pub struct InnerTestSolution::< + VoterIndex = u32, + TargetIndex = u32, + Accuracy = TestAccuracy, + MaxVoters = ConstU32::<1>, + >(3) + ); + let solution = InnerTestSolution { + votes1: vec![(2, 20), (4, 40)], + votes2: vec![(1, [(10, p(80))], 11), (5, [(50, p(85))], 51)], + ..Default::default() + }; + + // We actually have 4 voters, but the bound is 1 voter, so the implemented bound is too + // small. + assert!(solution.encode().len() > InnerTestSolution::max_encoded_len()); + } + + #[test] + fn max_encoded_len_upper_bound() { + generate_solution_type!( + pub struct InnerTestSolution::< + VoterIndex = u32, + TargetIndex = u32, + Accuracy = TestAccuracy, + MaxVoters = ConstU32::<4>, + >(3) + ); + let solution = InnerTestSolution { + votes1: vec![(2, 20), (4, 40)], + votes2: vec![(1, [(10, p(80))], 11), (5, [(50, p(85))], 51)], + ..Default::default() + }; + + // We actually have 4 voters, and the bound is 4 voters, so the implemented bound should be + // larger than the encoded len. + assert!(solution.encode().len() < InnerTestSolution::max_encoded_len()); + } + + #[test] + fn max_encoded_len_exact() { + generate_solution_type!( + pub struct InnerTestSolution::< + VoterIndex = u32, + TargetIndex = u32, + Accuracy = TestAccuracy, + MaxVoters = ConstU32::<4>, + >(3) + ); + let solution = InnerTestSolution { + votes1: vec![], + votes2: vec![], + votes3: vec![ + (1, [(10, p(50)), (11, p(20))], 12), + (2, [(20, p(50)), (21, p(20))], 22), + (3, [(30, p(50)), (31, p(20))], 32), + (4, [(40, p(50)), (41, p(20))], 42), + ], + }; + + // We have 4 voters, the bound is 4 voters, and all the voters voted for 3 targets, which is + // the max number of targets. This should represent the upper bound that `max_encoded_len` + // represents. + assert_eq!(solution.encode().len(), InnerTestSolution::max_encoded_len()); + } + #[test] fn solution_struct_is_codec() { let solution = TestSolution { From 7a09b82772b0597cdae224f4b124d660dda9e82b Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 23 Mar 2022 14:17:26 +0000 Subject: [PATCH 0628/1472] Store validator self-vote in bags-list, and allow them to be trimmed for election (#10821) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement the new validator-in-bags-list scenario + migration * Apply suggestions from code review Co-authored-by: Zeke Mostov * some review comments * guard the migration * some review comments * Fix tests 🤦‍♂️ * Fix build * fix weight_of_fn * reformat line width * make const * use weight of fn cached * SortedListProvider -> VoterList * Fix all build and docs * check post migration Co-authored-by: Zeke Mostov --- bin/node/runtime/src/lib.rs | 4 +- frame/babe/src/mock.rs | 2 +- frame/bags-list/remote-tests/src/lib.rs | 2 +- frame/bags-list/remote-tests/src/migration.rs | 11 +- frame/bags-list/remote-tests/src/snapshot.rs | 5 +- frame/grandpa/src/mock.rs | 2 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/session/benchmarking/src/mock.rs | 2 +- frame/session/src/migrations/v1.rs | 4 +- frame/staking/src/benchmarking.rs | 50 +++-- frame/staking/src/lib.rs | 3 +- frame/staking/src/migrations.rs | 83 ++++++++- frame/staking/src/mock.rs | 10 +- frame/staking/src/pallet/impls.rs | 176 ++++++++++-------- frame/staking/src/pallet/mod.rs | 35 ++-- frame/staking/src/testing_utils.rs | 4 +- frame/staking/src/tests.rs | 114 ++++++------ 17 files changed, 305 insertions(+), 204 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index b7137de48fb15..a6d97cb299b24 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -558,9 +558,7 @@ impl pallet_staking::Config for Runtime { type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainSequentialPhragmen; - // Alternatively, use pallet_staking::UseNominatorsMap to just use the nominators map. - // Note that the aforementioned does not scale to a very large number of nominators. - type SortedListProvider = BagsList; + type VoterList = BagsList; type MaxUnlockingChunks = ConstU32<32>; type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 152ec5ab206e7..e74288577c9ef 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -197,7 +197,7 @@ impl pallet_staking::Config for Test { type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; - type SortedListProvider = pallet_staking::UseNominatorsMap; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/bags-list/remote-tests/src/lib.rs b/frame/bags-list/remote-tests/src/lib.rs index 83c322f93134e..caf7a2a547e09 100644 --- a/frame/bags-list/remote-tests/src/lib.rs +++ b/frame/bags-list/remote-tests/src/lib.rs @@ -48,7 +48,7 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na let min_nominator_bond = >::get(); log::info!(target: LOG_TARGET, "min nominator bond is {:?}", min_nominator_bond); - let voter_list_count = ::SortedListProvider::count(); + let voter_list_count = ::VoterList::count(); // go through every bag to track the total number of voters within bags and log some info about // how voters are distributed within the bags. diff --git a/frame/bags-list/remote-tests/src/migration.rs b/frame/bags-list/remote-tests/src/migration.rs index 4d5169fcc6dfa..c4cd73c45d377 100644 --- a/frame/bags-list/remote-tests/src/migration.rs +++ b/frame/bags-list/remote-tests/src/migration.rs @@ -17,7 +17,6 @@ //! Test to check the migration of the voter bag. use crate::{RuntimeT, LOG_TARGET}; -use frame_election_provider_support::SortedListProvider; use frame_support::traits::PalletInfoAccess; use pallet_staking::Nominators; use remote_externalities::{Builder, Mode, OnlineConfig}; @@ -45,16 +44,16 @@ pub async fn execute( let pre_migrate_nominator_count = >::iter().count() as u32; log::info!(target: LOG_TARGET, "Nominator count: {}", pre_migrate_nominator_count); - // run the actual migration, - let moved = ::SortedListProvider::unsafe_regenerate( + use frame_election_provider_support::SortedListProvider; + // run the actual migration + let moved = ::VoterList::unsafe_regenerate( pallet_staking::Nominators::::iter().map(|(n, _)| n), pallet_staking::Pallet::::weight_of_fn(), ); log::info!(target: LOG_TARGET, "Moved {} nominators", moved); - let voter_list_len = - ::SortedListProvider::iter().count() as u32; - let voter_list_count = ::SortedListProvider::count(); + let voter_list_len = ::VoterList::iter().count() as u32; + let voter_list_count = ::VoterList::count(); // and confirm it is equal to the length of the `VoterList`. assert_eq!(pre_migrate_nominator_count, voter_list_len); assert_eq!(pre_migrate_nominator_count, voter_list_count); diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index 2d996746a29cc..408f5f2bd8aa2 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -16,6 +16,7 @@ //! Test to execute the snapshot using the voter bag. +use frame_election_provider_support::SortedListProvider; use frame_support::traits::PalletInfoAccess; use remote_externalities::{Builder, Mode, OnlineConfig}; use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; @@ -48,11 +49,11 @@ pub async fn execute .unwrap(); ext.execute_with(|| { - use frame_election_provider_support::{ElectionDataProvider, SortedListProvider}; + use frame_election_provider_support::ElectionDataProvider; log::info!( target: crate::LOG_TARGET, "{} nodes in bags list.", - ::SortedListProvider::count(), + ::VoterList::count(), ); let voters = diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 9dac33f979841..6490a2b6992bf 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -205,7 +205,7 @@ impl pallet_staking::Config for Test { type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; - type SortedListProvider = pallet_staking::UseNominatorsMap; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 22c9af0f4c3cd..4359b7745ddd6 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -175,7 +175,7 @@ impl pallet_staking::Config for Test { type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; - type SortedListProvider = pallet_staking::UseNominatorsMap; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index a9328b6546c91..5ebc75245630c 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -182,7 +182,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type MaxUnlockingChunks = ConstU32<32>; - type SortedListProvider = pallet_staking::UseNominatorsMap; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/session/src/migrations/v1.rs b/frame/session/src/migrations/v1.rs index 2a69cd6d6a550..3c687ea7d9d66 100644 --- a/frame/session/src/migrations/v1.rs +++ b/frame/session/src/migrations/v1.rs @@ -87,7 +87,7 @@ pub fn migrate ListScenario { /// - the destination bag has at least one node, which will need its next pointer updated. /// /// NOTE: while this scenario specifically targets a worst case for the bags-list, it should - /// also elicit a worst case for other known `SortedListProvider` implementations; although - /// this may not be true against unknown `SortedListProvider` implementations. + /// also elicit a worst case for other known `VoterList` implementations; although + /// this may not be true against unknown `VoterList` implementations. fn new(origin_weight: BalanceOf, is_increase: bool) -> Result { ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0"); @@ -189,7 +189,7 @@ impl ListScenario { // find a destination weight that will trigger the worst case scenario let dest_weight_as_vote = - T::SortedListProvider::score_update_worst_case(&origin_stash1, is_increase); + T::VoterList::score_update_worst_case(&origin_stash1, is_increase); let total_issuance = T::Currency::total_issuance(); @@ -316,7 +316,7 @@ benchmarks! { let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); let stash = scenario.origin_stash1.clone(); - assert!(T::SortedListProvider::contains(&stash)); + assert!(T::VoterList::contains(&stash)); let ed = T::Currency::minimum_balance(); let mut ledger = Ledger::::get(&controller).unwrap(); @@ -328,28 +328,24 @@ benchmarks! { }: withdraw_unbonded(RawOrigin::Signed(controller.clone()), s) verify { assert!(!Ledger::::contains_key(controller)); - assert!(!T::SortedListProvider::contains(&stash)); + assert!(!T::VoterList::contains(&stash)); } validate { - // clean up any existing state. - clear_validators_and_nominators::(); - - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); - - // setup a worst case scenario where the user calling validate was formerly a nominator so - // they must be removed from the list. - let scenario = ListScenario::::new(origin_weight, true)?; - let controller = scenario.origin_controller1.clone(); - let stash = scenario.origin_stash1.clone(); - assert!(T::SortedListProvider::contains(&stash)); + let (stash, controller) = create_stash_controller::( + T::MaxNominations::get() - 1, + 100, + Default::default(), + )?; + // because it is chilled. + assert!(!T::VoterList::contains(&stash)); let prefs = ValidatorPrefs::default(); whitelist_account!(controller); }: _(RawOrigin::Signed(controller), prefs) verify { assert!(Validators::::contains_key(&stash)); - assert!(!T::SortedListProvider::contains(&stash)); + assert!(T::VoterList::contains(&stash)); } kick { @@ -434,14 +430,14 @@ benchmarks! { ).unwrap(); assert!(!Nominators::::contains_key(&stash)); - assert!(!T::SortedListProvider::contains(&stash)); + assert!(!T::VoterList::contains(&stash)); let validators = create_validators::(n, 100).unwrap(); whitelist_account!(controller); }: _(RawOrigin::Signed(controller), validators) verify { assert!(Nominators::::contains_key(&stash)); - assert!(T::SortedListProvider::contains(&stash)) + assert!(T::VoterList::contains(&stash)) } chill { @@ -455,12 +451,12 @@ benchmarks! { let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); let stash = scenario.origin_stash1.clone(); - assert!(T::SortedListProvider::contains(&stash)); + assert!(T::VoterList::contains(&stash)); whitelist_account!(controller); }: _(RawOrigin::Signed(controller)) verify { - assert!(!T::SortedListProvider::contains(&stash)); + assert!(!T::VoterList::contains(&stash)); } set_payee { @@ -523,13 +519,13 @@ benchmarks! { let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); let stash = scenario.origin_stash1.clone(); - assert!(T::SortedListProvider::contains(&stash)); + assert!(T::VoterList::contains(&stash)); add_slashing_spans::(&stash, s); }: _(RawOrigin::Root, stash.clone(), s) verify { assert!(!Ledger::::contains_key(&controller)); - assert!(!T::SortedListProvider::contains(&stash)); + assert!(!T::VoterList::contains(&stash)); } cancel_deferred_slash { @@ -708,13 +704,13 @@ benchmarks! { Ledger::::insert(&controller, l); assert!(Bonded::::contains_key(&stash)); - assert!(T::SortedListProvider::contains(&stash)); + assert!(T::VoterList::contains(&stash)); whitelist_account!(controller); }: _(RawOrigin::Signed(controller), stash.clone(), s) verify { assert!(!Bonded::::contains_key(&stash)); - assert!(!T::SortedListProvider::contains(&stash)); + assert!(!T::VoterList::contains(&stash)); } new_era { @@ -899,7 +895,7 @@ benchmarks! { let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); let stash = scenario.origin_stash1.clone(); - assert!(T::SortedListProvider::contains(&stash)); + assert!(T::VoterList::contains(&stash)); Staking::::set_staking_configs( RawOrigin::Root.into(), @@ -914,7 +910,7 @@ benchmarks! { let caller = whitelisted_caller(); }: _(RawOrigin::Signed(caller), controller.clone()) verify { - assert!(!T::SortedListProvider::contains(&stash)); + assert!(!T::VoterList::contains(&stash)); } force_apply_min_commission { diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 4c1bb438457e5..2a0716721dd51 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -780,7 +780,8 @@ enum Releases { V5_0_0, // blockable validators. V6_0_0, // removal of all storage associated with offchain phragmen. V7_0_0, // keep track of number of nominators / validators in map - V8_0_0, // populate `SortedListProvider`. + V8_0_0, // populate `VoterList`. + V9_0_0, // inject validators into `VoterList` as well. } impl Default for Releases { diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 3991c4a66076f..96c905f4e5942 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -17,13 +17,83 @@ //! Storage migrations for the Staking pallet. use super::*; +use frame_election_provider_support::SortedListProvider; +use frame_support::traits::OnRuntimeUpgrade; + +pub mod v9 { + use super::*; + + /// Migration implementation that injects all validators into sorted list. + /// + /// This is only useful for chains that started their `VoterList` just based on nominators. + pub struct InjectValidatorsIntoVoterList(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for InjectValidatorsIntoVoterList { + fn on_runtime_upgrade() -> Weight { + if StorageVersion::::get() == Releases::V8_0_0 { + let prev_count = T::VoterList::count(); + let weight_of_cached = Pallet::::weight_of_fn(); + for (v, _) in Validators::::iter() { + let weight = weight_of_cached(&v); + let _ = T::VoterList::on_insert(v.clone(), weight).map_err(|err| { + log!(warn, "failed to insert {:?} into VoterList: {:?}", v, err) + }); + } + + log!( + info, + "injected a total of {} new voters, prev count: {} next count: {}, updating to version 9", + Validators::::count(), + prev_count, + T::VoterList::count(), + ); + + StorageVersion::::put(crate::Releases::V9_0_0); + T::BlockWeights::get().max_block + } else { + log!( + warn, + "InjectValidatorsIntoVoterList being executed on the wrong storage \ + version, expected Releases::V8_0_0" + ); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + use frame_support::traits::OnRuntimeUpgradeHelpersExt; + frame_support::ensure!( + StorageVersion::::get() == crate::Releases::V8_0_0, + "must upgrade linearly" + ); + + let prev_count = T::VoterList::count(); + Self::set_temp_storage(prev_count, "prev"); + Ok(()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + use frame_support::traits::OnRuntimeUpgradeHelpersExt; + let post_count = T::VoterList::count(); + let prev_count = Self::get_temp_storage::("prev").unwrap(); + let validators = Validators::::count(); + assert!(post_count == prev_count + validators); + + frame_support::ensure!( + StorageVersion::::get() == crate::Releases::V9_0_0, + "must upgrade " + ); + Ok(()) + } + } +} pub mod v8 { + use crate::{Config, Nominators, Pallet, StorageVersion, Weight}; use frame_election_provider_support::SortedListProvider; use frame_support::traits::Get; - use crate::{Config, Nominators, Pallet, StorageVersion, Weight}; - #[cfg(feature = "try-runtime")] pub fn pre_migrate() -> Result<(), &'static str> { frame_support::ensure!( @@ -35,16 +105,16 @@ pub mod v8 { Ok(()) } - /// Migration to sorted [`SortedListProvider`]. + /// Migration to sorted `VoterList`. pub fn migrate() -> Weight { if StorageVersion::::get() == crate::Releases::V7_0_0 { crate::log!(info, "migrating staking to Releases::V8_0_0"); - let migrated = T::SortedListProvider::unsafe_regenerate( + let migrated = T::VoterList::unsafe_regenerate( Nominators::::iter().map(|(id, _)| id), Pallet::::weight_of_fn(), ); - debug_assert_eq!(T::SortedListProvider::sanity_check(), Ok(())); + debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); StorageVersion::::put(crate::Releases::V8_0_0); crate::log!( @@ -61,8 +131,7 @@ pub mod v8 { #[cfg(feature = "try-runtime")] pub fn post_migrate() -> Result<(), &'static str> { - T::SortedListProvider::sanity_check() - .map_err(|_| "SortedListProvider is not in a sane state.")?; + T::VoterList::sanity_check().map_err(|_| "VoterList is not in a sane state.")?; crate::log!(info, "👜 staking bags-list migration passes POST migrate checks ✅",); Ok(()) } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 843791a46ade2..bb71232c34673 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -270,8 +270,8 @@ impl crate::pallet::pallet::Config for Test { type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; - // NOTE: consider a macro and use `UseNominatorsMap` as well. - type SortedListProvider = BagsList; + // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. + type VoterList = BagsList; type MaxUnlockingChunks = ConstU32<32>; type BenchmarkingConfig = TestBenchmarkingConfig; type WeightInfo = (); @@ -541,9 +541,9 @@ fn check_count() { assert_eq!(nominator_count, Nominators::::count()); assert_eq!(validator_count, Validators::::count()); - // the voters that the `SortedListProvider` list is storing for us. - let external_voters = ::SortedListProvider::count(); - assert_eq!(external_voters, nominator_count); + // the voters that the `VoterList` list is storing for us. + let external_voters = ::VoterList::count(); + assert_eq!(external_voters, nominator_count + validator_count); } fn check_ledgers() { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index cb024ba2bc524..9d5a3ed484184 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -49,6 +49,14 @@ use crate::{ use super::{pallet::*, STAKING_ID}; +/// The maximum number of iterations that we do whilst iterating over `T::VoterList` in +/// `get_npos_voters`. +/// +/// In most cases, if we want n items, we iterate exactly n times. In rare cases, if a voter is +/// invalid (for any reason) the iteration continues. With this constant, we iterate at most 2 * n +/// times and then give up. +const NPOS_MAX_ITERATIONS_COEFFICIENT: u32 = 2; + impl Pallet { /// The total balance that can be slashed from a stash account as of right now. pub fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf { @@ -649,90 +657,77 @@ impl Pallet { /// Get all of the voters that are eligible for the npos election. /// - /// `maybe_max_len` can imposes a cap on the number of voters returned; First all the validator - /// are included in no particular order, then remainder is taken from the nominators, as - /// returned by [`Config::SortedListProvider`]. - /// - /// This will use nominators, and all the validators will inject a self vote. + /// `maybe_max_len` can imposes a cap on the number of voters returned; /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. /// /// ### Slashing /// - /// All nominations that have been submitted before the last non-zero slash of the validator are - /// auto-chilled, but still count towards the limit imposed by `maybe_max_len`. + /// All votes that have been submitted before the last non-zero slash of the corresponding + /// target are *auto-chilled*, but still count towards the limit imposed by `maybe_max_len`. pub fn get_npos_voters(maybe_max_len: Option) -> Vec> { let max_allowed_len = { - let nominator_count = Nominators::::count() as usize; - let validator_count = Validators::::count() as usize; - let all_voter_count = validator_count.saturating_add(nominator_count); + let all_voter_count = T::VoterList::count() as usize; maybe_max_len.unwrap_or(all_voter_count).min(all_voter_count) }; let mut all_voters = Vec::<_>::with_capacity(max_allowed_len); - // first, grab all validators in no particular order, capped by the maximum allowed length. - let mut validators_taken = 0u32; - for (validator, _) in >::iter().take(max_allowed_len) { - // Append self vote. - let self_vote = ( - validator.clone(), - Self::weight_of(&validator), - vec![validator.clone()] - .try_into() - .expect("`MaxVotesPerVoter` must be greater than or equal to 1"), - ); - all_voters.push(self_vote); - validators_taken.saturating_inc(); - } - - // .. and grab whatever we have left from nominators. - let nominators_quota = (max_allowed_len as u32).saturating_sub(validators_taken); + // cache a few things. + let weight_of = Self::weight_of_fn(); let slashing_spans = >::iter().collect::>(); - // track the count of nominators added to `all_voters + let mut voters_seen = 0u32; + let mut validators_taken = 0u32; let mut nominators_taken = 0u32; - // track every nominator iterated over, but not necessarily added to `all_voters` - let mut nominators_seen = 0u32; - // cache the total-issuance once in this function - let weight_of = Self::weight_of_fn(); - - let mut nominators_iter = T::SortedListProvider::iter(); - while nominators_taken < nominators_quota && nominators_seen < nominators_quota * 2 { - let nominator = match nominators_iter.next() { - Some(nominator) => { - nominators_seen.saturating_inc(); - nominator + let mut sorted_voters = T::VoterList::iter(); + while all_voters.len() < max_allowed_len && + voters_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * max_allowed_len as u32) + { + let voter = match sorted_voters.next() { + Some(voter) => { + voters_seen.saturating_inc(); + voter }, None => break, }; if let Some(Nominations { submitted_in, mut targets, suppressed: _ }) = - >::get(&nominator) + >::get(&voter) { - log!( - trace, - "fetched nominator {:?} with weight {:?}", - nominator, - weight_of(&nominator) - ); + // if this voter is a nominator: targets.retain(|stash| { slashing_spans .get(stash) .map_or(true, |spans| submitted_in >= spans.last_nonzero_slash()) }); if !targets.len().is_zero() { - all_voters.push((nominator.clone(), weight_of(&nominator), targets)); + all_voters.push((voter.clone(), weight_of(&voter), targets)); nominators_taken.saturating_inc(); } + } else if Validators::::contains_key(&voter) { + // if this voter is a validator: + let self_vote = ( + voter.clone(), + weight_of(&voter), + vec![voter.clone()] + .try_into() + .expect("`MaxVotesPerVoter` must be greater than or equal to 1"), + ); + all_voters.push(self_vote); + validators_taken.saturating_inc(); } else { - // this can only happen if: 1. there a pretty bad bug in the bags-list (or whatever - // is the sorted list) logic and the state of the two pallets is no longer - // compatible, or because the nominators is not decodable since they have more - // nomination than `T::MaxNominations`. This can rarely happen, and is not really an - // emergency or bug if it does. - log!(warn, "DEFENSIVE: invalid item in `SortedListProvider`: {:?}, this nominator probably has too many nominations now", nominator) + // this can only happen if: 1. there a bug in the bags-list (or whatever is the + // sorted list) logic and the state of the two pallets is no longer compatible, or + // because the nominators is not decodable since they have more nomination than + // `T::MaxNominations`. The latter can rarely happen, and is not really an emergency + // or bug if it does. + log!( + warn, + "DEFENSIVE: invalid item in `VoterList`: {:?}, this nominator probably has too many nominations now", + voter + ) } } @@ -752,6 +747,7 @@ impl Pallet { validators_taken, nominators_taken ); + all_voters } @@ -773,7 +769,7 @@ impl Pallet { } /// This function will add a nominator to the `Nominators` storage map, - /// and [`SortedListProvider`]. + /// and `VoterList`. /// /// If the nominator already exists, their nominations will be updated. /// @@ -782,18 +778,21 @@ impl Pallet { /// wrong. pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { if !Nominators::::contains_key(who) { - // maybe update sorted list. Error checking is defensive-only - this should never fail. - let _ = T::SortedListProvider::on_insert(who.clone(), Self::weight_of(who)) + // maybe update sorted list. + let _ = T::VoterList::on_insert(who.clone(), Self::weight_of(who)) .defensive_unwrap_or_default(); - - debug_assert_eq!(T::SortedListProvider::sanity_check(), Ok(())); } - Nominators::::insert(who, nominations); + + debug_assert_eq!( + Nominators::::count() + Validators::::count(), + T::VoterList::count() + ); + debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); } /// This function will remove a nominator from the `Nominators` storage map, - /// and [`SortedListProvider`]. + /// and `VoterList`. /// /// Returns true if `who` was removed from `Nominators`, otherwise false. /// @@ -801,15 +800,21 @@ impl Pallet { /// `Nominators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_remove_nominator(who: &T::AccountId) -> bool { - if Nominators::::contains_key(who) { + let outcome = if Nominators::::contains_key(who) { Nominators::::remove(who); - T::SortedListProvider::on_remove(who); - debug_assert_eq!(T::SortedListProvider::sanity_check(), Ok(())); - debug_assert_eq!(Nominators::::count(), T::SortedListProvider::count()); + T::VoterList::on_remove(who); true } else { false - } + }; + + debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); + debug_assert_eq!( + Nominators::::count() + Validators::::count(), + T::VoterList::count() + ); + + outcome } /// This function will add a validator to the `Validators` storage map. @@ -820,7 +825,18 @@ impl Pallet { /// `Validators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_add_validator(who: &T::AccountId, prefs: ValidatorPrefs) { + if !Validators::::contains_key(who) { + // maybe update sorted list. + let _ = T::VoterList::on_insert(who.clone(), Self::weight_of(who)) + .defensive_unwrap_or_default(); + } Validators::::insert(who, prefs); + + debug_assert_eq!( + Nominators::::count() + Validators::::count(), + T::VoterList::count() + ); + debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); } /// This function will remove a validator from the `Validators` storage map. @@ -831,12 +847,21 @@ impl Pallet { /// `Validators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_remove_validator(who: &T::AccountId) -> bool { - if Validators::::contains_key(who) { + let outcome = if Validators::::contains_key(who) { Validators::::remove(who); + T::VoterList::on_remove(who); true } else { false - } + }; + + debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); + debug_assert_eq!( + Nominators::::count() + Validators::::count(), + T::VoterList::count() + ); + + outcome } /// Register some amount of weight directly with the system pallet. @@ -963,7 +988,7 @@ impl ElectionDataProvider for Pallet { >::remove_all(); >::remove_all(); - T::SortedListProvider::unsafe_clear(); + T::VoterList::unsafe_clear(); } #[cfg(feature = "runtime-benchmarks")] @@ -1278,20 +1303,24 @@ impl ScoreProvider for Pallet { /// A simple voter list implementation that does not require any additional pallets. Note, this /// does not provided nominators in sorted ordered. If you desire nominators in a sorted order take /// a look at [`pallet-bags-list]. -pub struct UseNominatorsMap(sp_std::marker::PhantomData); -impl SortedListProvider for UseNominatorsMap { +pub struct UseNominatorsAndValidatorsMap(sp_std::marker::PhantomData); +impl SortedListProvider for UseNominatorsAndValidatorsMap { type Error = (); type Score = VoteWeight; /// Returns iterator over voter list, which can have `take` called on it. fn iter() -> Box> { - Box::new(Nominators::::iter().map(|(n, _)| n)) + Box::new( + Validators::::iter() + .map(|(v, _)| v) + .chain(Nominators::::iter().map(|(n, _)| n)), + ) } fn count() -> u32 { - Nominators::::count() + Nominators::::count().saturating_add(Validators::::count()) } fn contains(id: &T::AccountId) -> bool { - Nominators::::contains_key(id) + Nominators::::contains_key(id) || Validators::::contains_key(id) } fn on_insert(_: T::AccountId, _weight: Self::Score) -> Result<(), Self::Error> { // nothing to do on insert. @@ -1318,5 +1347,6 @@ impl SortedListProvider for UseNominatorsMap { // NOTE: Caller must ensure this doesn't lead to too many storage accesses. This is a // condition of SortedListProvider::unsafe_clear. Nominators::::remove_all(); + Validators::::remove_all(); } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 39173bf61c833..306bd34390d82 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -17,7 +17,7 @@ //! Staking FRAME Pallet. -use frame_election_provider_support::SortedListProvider; +use frame_election_provider_support::{SortedListProvider, VoteWeight}; use frame_support::{ dispatch::Codec, pallet_prelude::*, @@ -163,13 +163,12 @@ pub mod pallet { /// After the threshold is reached a new era will be forced. type OffendingValidatorsThreshold: Get; - /// Something that can provide a sorted list of voters in a somewhat sorted way. The - /// original use case for this was designed with `pallet_bags_list::Pallet` in mind. If - /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. - type SortedListProvider: SortedListProvider< - Self::AccountId, - Score = frame_election_provider_support::VoteWeight, - >; + /// Something that provides a best-effort sorted list of voters aka electing nominators, + /// used for NPoS election. + /// + /// The changes to nominators are reported to this. Moreover, each validator's self-vote is + /// also reported as one independent vote. + type VoterList: SortedListProvider; /// The maximum number of `unlocking` chunks a [`StakingLedger`] can have. Effectively /// determines how many unique eras a staker may be unbonding in. @@ -584,10 +583,10 @@ pub mod pallet { }); } - // all voters are reported to the `SortedListProvider`. + // all voters are reported to the `VoterList`. assert_eq!( - T::SortedListProvider::count(), - Nominators::::count(), + T::VoterList::count(), + Nominators::::count() + Validators::::count(), "not all genesis stakers were inserted into sorted list provider, something is wrong." ); } @@ -837,9 +836,9 @@ pub mod pallet { // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); // update this staker in the sorted list, if they exist in it. - if T::SortedListProvider::contains(&stash) { - T::SortedListProvider::on_update(&stash, Self::weight_of(&ledger.stash)); - debug_assert_eq!(T::SortedListProvider::sanity_check(), Ok(())); + if T::VoterList::contains(&stash) { + T::VoterList::on_update(&stash, Self::weight_of(&ledger.stash)); + debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); } Self::deposit_event(Event::::Bonded(stash.clone(), extra)); @@ -920,8 +919,8 @@ pub mod pallet { Self::update_ledger(&controller, &ledger); // update this staker in the sorted list, if they exist in it. - if T::SortedListProvider::contains(&ledger.stash) { - T::SortedListProvider::on_update(&ledger.stash, Self::weight_of(&ledger.stash)); + if T::VoterList::contains(&ledger.stash) { + T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash)); } Self::deposit_event(Event::::Unbonded(ledger.stash, value)); @@ -1403,8 +1402,8 @@ pub mod pallet { // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); - if T::SortedListProvider::contains(&ledger.stash) { - T::SortedListProvider::on_update(&ledger.stash, Self::weight_of(&ledger.stash)); + if T::VoterList::contains(&ledger.stash) { + T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash)); } let removed_chunks = 1u32 // for the case where the last iterated chunk is not removed diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 8e6bd88468930..5f9f378b10619 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -38,11 +38,11 @@ const SEED: u32 = 0; pub fn clear_validators_and_nominators() { Validators::::remove_all(); - // whenever we touch nominators counter we should update `T::SortedListProvider` as well. + // whenever we touch nominators counter we should update `T::VoterList` as well. Nominators::::remove_all(); // NOTE: safe to call outside block production - T::SortedListProvider::unsafe_clear(); + T::VoterList::unsafe_clear(); } /// Grab a funded user. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 2d4145242a45c..11dfe3e4777f8 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4113,11 +4113,7 @@ mod election_data_provider { .set_status(41, StakerStatus::Validator) .build_and_execute(|| { // sum of all nominators who'd be voters (1), plus the self-votes (4). - assert_eq!( - ::SortedListProvider::count() + - >::iter().count() as u32, - 5 - ); + assert_eq!(::VoterList::count(), 5); // if limits is less.. assert_eq!(Staking::electing_voters(Some(1)).unwrap().len(), 1); @@ -4140,43 +4136,43 @@ mod election_data_provider { }); } + // Tests the criteria that in `ElectionDataProvider::voters` function, we try to get at most + // `maybe_max_len` voters, and if some of them end up being skipped, we iterate at most `2 * + // maybe_max_len`. #[test] - fn only_iterates_max_2_times_nominators_quota() { + fn only_iterates_max_2_times_max_allowed_len() { ExtBuilder::default() - .nominate(true) // add nominator 101, who nominates [11, 21] + .nominate(false) // the other nominators only nominate 21 .add_staker(61, 60, 2_000, StakerStatus::::Nominator(vec![21])) .add_staker(71, 70, 2_000, StakerStatus::::Nominator(vec![21])) .add_staker(81, 80, 2_000, StakerStatus::::Nominator(vec![21])) .build_and_execute(|| { - // given our nominators ordered by stake, - assert_eq!( - ::SortedListProvider::iter().collect::>(), - vec![61, 71, 81, 101] - ); - - // and total voters + // all voters ordered by stake, assert_eq!( - ::SortedListProvider::count() + - >::iter().count() as u32, - 7 + ::VoterList::iter().collect::>(), + vec![61, 71, 81, 11, 21, 31] ); - // roll to session 5 run_to_block(25); // slash 21, the only validator nominated by our first 3 nominators add_slash(&21); - // we take 4 voters: 2 validators and 2 nominators (so nominators quota = 2) + // we want 2 voters now, and in maximum we allow 4 iterations. This is what happens: + // 61 is pruned; + // 71 is pruned; + // 81 is pruned; + // 11 is taken; + // we finish since the 2x limit is reached. assert_eq!( - Staking::electing_voters(Some(3)) + Staking::electing_voters(Some(2)) .unwrap() .iter() .map(|(stash, _, _)| stash) .copied() .collect::>(), - vec![31, 11], // 2 validators, but no nominators because we hit the quota + vec![11], ); }); } @@ -4189,46 +4185,35 @@ mod election_data_provider { #[test] fn get_max_len_voters_even_if_some_nominators_are_slashed() { ExtBuilder::default() - .nominate(true) // add nominator 101, who nominates [11, 21] + .nominate(false) .add_staker(61, 60, 20, StakerStatus::::Nominator(vec![21])) - // 61 only nominates validator 21 ^^ .add_staker(71, 70, 10, StakerStatus::::Nominator(vec![11, 21])) + .add_staker(81, 80, 10, StakerStatus::::Nominator(vec![11, 21])) .build_and_execute(|| { - // given our nominators ordered by stake, + // given our voters ordered by stake, assert_eq!( - ::SortedListProvider::iter().collect::>(), - vec![101, 61, 71] + ::VoterList::iter().collect::>(), + vec![11, 21, 31, 61, 71, 81] ); - // and total voters - assert_eq!( - ::SortedListProvider::count() + - >::iter().count() as u32, - 6 - ); - - // we take 5 voters + // we take 4 voters assert_eq!( - Staking::electing_voters(Some(5)) + Staking::electing_voters(Some(4)) .unwrap() .iter() .map(|(stash, _, _)| stash) .copied() .collect::>(), - // then - vec![ - 31, 21, 11, // 3 nominators - 101, 61 // 2 validators, and 71 is excluded - ], + vec![11, 21, 31, 61], ); // roll to session 5 run_to_block(25); - // slash 21, the only validator nominated by 61 + // slash 21, the only validator nominated by 61. add_slash(&21); - // we take 4 voters + // we take 4 voters; 71 and 81 are replacing the ejected ones. assert_eq!( Staking::electing_voters(Some(4)) .unwrap() @@ -4236,10 +4221,7 @@ mod election_data_provider { .map(|(stash, _, _)| stash) .copied() .collect::>(), - vec![ - 31, 11, // 2 validators (21 was slashed) - 101, 71 // 2 nominators, excluding 61 - ], + vec![11, 31, 71, 81], ); }); } @@ -4755,19 +4737,45 @@ mod sorted_list_provider { fn re_nominate_does_not_change_counters_or_list() { ExtBuilder::default().nominate(true).build_and_execute(|| { // given - let pre_insert_nominator_count = Nominators::::iter().count() as u32; - assert_eq!(::SortedListProvider::count(), pre_insert_nominator_count); - assert!(Nominators::::contains_key(101)); - assert_eq!(::SortedListProvider::iter().collect::>(), vec![101]); + let pre_insert_voter_count = + (Nominators::::count() + Validators::::count()) as u32; + assert_eq!(::VoterList::count(), pre_insert_voter_count); + + assert_eq!( + ::VoterList::iter().collect::>(), + vec![11, 21, 31, 101] + ); // when account 101 renominates assert_ok!(Staking::nominate(Origin::signed(100), vec![41])); // then counts don't change - assert_eq!(::SortedListProvider::count(), pre_insert_nominator_count); - assert_eq!(Nominators::::iter().count() as u32, pre_insert_nominator_count); + assert_eq!(::VoterList::count(), pre_insert_voter_count); + // and the list is the same + assert_eq!( + ::VoterList::iter().collect::>(), + vec![11, 21, 31, 101] + ); + }); + } + + #[test] + fn re_validate_does_not_change_counters_or_list() { + ExtBuilder::default().nominate(false).build_and_execute(|| { + // given + let pre_insert_voter_count = + (Nominators::::count() + Validators::::count()) as u32; + assert_eq!(::VoterList::count(), pre_insert_voter_count); + + assert_eq!(::VoterList::iter().collect::>(), vec![11, 21, 31]); + + // when account 11 re-validates + assert_ok!(Staking::validate(Origin::signed(10), Default::default())); + + // then counts don't change + assert_eq!(::VoterList::count(), pre_insert_voter_count); // and the list is the same - assert_eq!(::SortedListProvider::iter().collect::>(), vec![101]); + assert_eq!(::VoterList::iter().collect::>(), vec![11, 21, 31]); }); } } From 97ee3d1de19e3f7442b6c0aa4ad360a49d5ea663 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 23 Mar 2022 18:10:13 -0400 Subject: [PATCH 0629/1472] Fix `generate_storage_alias!` (#11102) * add test * fix issues * make order intuitive --- frame/support/src/lib.rs | 42 ++++++++++++------- .../support/src/storage/bounded_btree_map.rs | 4 +- .../support/src/storage/bounded_btree_set.rs | 4 +- frame/support/src/storage/bounded_vec.rs | 4 +- .../src/storage/generator/double_map.rs | 2 +- frame/support/src/storage/generator/map.rs | 2 +- frame/support/src/storage/generator/nmap.rs | 6 +-- frame/support/src/storage/mod.rs | 6 +-- frame/support/src/storage/types/nmap.rs | 2 +- frame/support/src/storage/weak_bounded_vec.rs | 4 +- 10 files changed, 45 insertions(+), 31 deletions(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 3988b5e9af219..5f62995c52272 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -154,8 +154,8 @@ macro_rules! bounded_vec { /// // to `Vec` /// generate_storage_alias!( /// OtherPrefix, OtherStorageName => DoubleMap< -/// (u32, Twox64Concat), -/// (u32, Twox64Concat), +/// (Twox64Concat, u32), +/// (Twox64Concat, u32), /// Vec /// > /// ); @@ -165,8 +165,8 @@ macro_rules! bounded_vec { /// generate_storage_alias!(Prefix, ValueName => Value); /// generate_storage_alias!( /// Prefix, SomeStorageName => DoubleMap< -/// (u32, Twox64Concat), -/// (u32, Twox64Concat), +/// (Twox64Concat, u32), +/// (Twox64Concat, u32), /// Vec, /// ValueQuery /// > @@ -175,14 +175,14 @@ macro_rules! bounded_vec { /// // generate a map from `Config::AccountId` (with hasher `Twox64Concat`) to `Vec` /// trait Config { type AccountId: codec::FullCodec; } /// generate_storage_alias!( -/// Prefix, GenericStorage => Map<(T::AccountId, Twox64Concat), Vec> +/// Prefix, GenericStorage => Map<(Twox64Concat, T::AccountId), Vec> /// ); /// # fn main() {} /// ``` #[macro_export] macro_rules! generate_storage_alias { // without generic for $name. - ($pallet:ident, $name:ident => Map<($key:ty, $hasher:ty), $value:ty $(, $querytype:ty)?>) => { + ($pallet:ident, $name:ident => Map<($hasher:ty, $key:ty), $value:ty $(, $querytype:ty)?>) => { $crate::paste::paste! { $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); type $name = $crate::storage::types::StorageMap< @@ -197,7 +197,7 @@ macro_rules! generate_storage_alias { ( $pallet:ident, $name:ident - => DoubleMap<($key1:ty, $hasher1:ty), ($key2:ty, $hasher2:ty), $value:ty $(, $querytype:ty)?> + => DoubleMap<($hasher1:ty, $key1:ty), ($hasher2:ty, $key2:ty), $value:ty $(, $querytype:ty)?> ) => { $crate::paste::paste! { $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); @@ -215,7 +215,7 @@ macro_rules! generate_storage_alias { ( $pallet:ident, $name:ident - => NMap, $value:ty $(, $querytype:ty)?> + => NMap, $value:ty $(, $querytype:ty)?> ) => { $crate::paste::paste! { $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); @@ -243,15 +243,15 @@ macro_rules! generate_storage_alias { ( $pallet:ident, $name:ident<$t:ident : $bounds:tt> - => Map<($key:ty, $hasher:ty), $value:ty $(, $querytype:ty)?> + => Map<($hasher:ty, $key:ty), $value:ty $(, $querytype:ty)?> ) => { $crate::paste::paste! { $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); #[allow(type_alias_bounds)] type $name<$t : $bounds> = $crate::storage::types::StorageMap< [<$name Instance>], - $key, $hasher, + $key, $value, $( $querytype )? >; @@ -260,17 +260,17 @@ macro_rules! generate_storage_alias { ( $pallet:ident, $name:ident<$t:ident : $bounds:tt> - => DoubleMap<($key1:ty, $hasher1:ty), ($key2:ty, $hasher2:ty), $value:ty $(, $querytype:ty)?> + => DoubleMap<($hasher1:ty, $key1:ty), ($hasher2:ty, $key2:ty), $value:ty $(, $querytype:ty)?> ) => { $crate::paste::paste! { $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); #[allow(type_alias_bounds)] type $name<$t : $bounds> = $crate::storage::types::StorageDoubleMap< [<$name Instance>], - $key1, $hasher1, - $key2, + $key1, $hasher2, + $key2, $value, $( $querytype )? >; @@ -279,7 +279,7 @@ macro_rules! generate_storage_alias { ( $pallet:ident, $name:ident<$t:ident : $bounds:tt> - => NMap<$(($key:ty, $hasher:ty),)+ $value:ty $(, $querytype:ty)?> + => NMap<$(($hasher:ty, $key:ty),)+ $value:ty $(, $querytype:ty)?> ) => { $crate::paste::paste! { $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); @@ -945,6 +945,20 @@ pub mod tests { } } + #[test] + fn generate_storage_alias_works() { + new_test_ext().execute_with(|| { + generate_storage_alias!( + Test, + GenericData2 => Map<(Blake2_128Concat, T::BlockNumber), T::BlockNumber> + ); + + assert_eq!(Module::::generic_data2(5), None); + GenericData2::::insert(5, 5); + assert_eq!(Module::::generic_data2(5), Some(5)); + }); + } + #[test] fn map_issue_3318() { new_test_ext().execute_with(|| { diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index ed132adac657e..6190552476a45 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -344,10 +344,10 @@ pub mod test { use sp_io::TestExternalities; crate::generate_storage_alias! { Prefix, Foo => Value>> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedBTreeMap>> } + crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), BoundedBTreeMap>> } crate::generate_storage_alias! { Prefix, - FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedBTreeMap>> + FooDoubleMap => DoubleMap<(Twox128, u32), (Twox128, u32), BoundedBTreeMap>> } fn map_from_keys(keys: &[K]) -> BTreeMap diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index 7d543549c6bae..543b997e94e34 100644 --- a/frame/support/src/storage/bounded_btree_set.rs +++ b/frame/support/src/storage/bounded_btree_set.rs @@ -327,10 +327,10 @@ pub mod test { use sp_std::convert::TryInto; crate::generate_storage_alias! { Prefix, Foo => Value>> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedBTreeSet>> } + crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), BoundedBTreeSet>> } crate::generate_storage_alias! { Prefix, - FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedBTreeSet>> + FooDoubleMap => DoubleMap<(Twox128, u32), (Twox128, u32), BoundedBTreeSet>> } fn set_from_keys(keys: &[T]) -> BTreeSet diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 4e513258f9684..cf585af395587 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -589,10 +589,10 @@ pub mod test { use sp_io::TestExternalities; crate::generate_storage_alias! { Prefix, Foo => Value>> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedVec>> } + crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), BoundedVec>> } crate::generate_storage_alias! { Prefix, - FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedVec>> + FooDoubleMap => DoubleMap<(Twox128, u32), (Twox128, u32), BoundedVec>> } #[test] diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index d63dda7d5b320..12e1764bfb65d 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -527,7 +527,7 @@ mod test_iterators { use crate::hash::Identity; crate::generate_storage_alias!( MyModule, - MyDoubleMap => DoubleMap<(u64, Identity), (u64, Identity), u64> + MyDoubleMap => DoubleMap<(Identity, u64), (Identity, u64), u64> ); MyDoubleMap::insert(1, 10, 100); diff --git a/frame/support/src/storage/generator/map.rs b/frame/support/src/storage/generator/map.rs index 4157edefeac4b..da48952bcba87 100644 --- a/frame/support/src/storage/generator/map.rs +++ b/frame/support/src/storage/generator/map.rs @@ -384,7 +384,7 @@ mod test_iterators { fn map_iter_from() { sp_io::TestExternalities::default().execute_with(|| { use crate::hash::Identity; - crate::generate_storage_alias!(MyModule, MyMap => Map<(u64, Identity), u64>); + crate::generate_storage_alias!(MyModule, MyMap => Map<(Identity, u64), u64>); MyMap::insert(1, 10); MyMap::insert(2, 20); diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 1ad308bb22c78..be085ca2d9db6 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -477,7 +477,7 @@ mod test_iterators { use crate::{hash::Identity, storage::Key as NMapKey}; crate::generate_storage_alias!( MyModule, - MyNMap => NMap, u64> + MyNMap => NMap, u64> ); MyNMap::insert((1, 1, 1), 11); @@ -519,8 +519,8 @@ mod test_iterators { { crate::generate_storage_alias!(Test, NMap => DoubleMap< - (u16, crate::Blake2_128Concat), - (u32, crate::Twox64Concat), + (crate::Blake2_128Concat, u16), + (crate::Twox64Concat, u32), u64 >); diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 3d777fa3ace50..226682eecf10b 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -1618,7 +1618,7 @@ mod test { use crate::{hash::Identity, storage::generator::map::StorageMap}; crate::generate_storage_alias! { MyModule, - MyStorageMap => Map<(u64, Identity), u64> + MyStorageMap => Map<(Identity, u64), u64> } MyStorageMap::insert(1, 10); @@ -1735,10 +1735,10 @@ mod test { } crate::generate_storage_alias! { Prefix, Foo => Value>> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedVec>> } + crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), BoundedVec>> } crate::generate_storage_alias! { Prefix, - FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedVec>> + FooDoubleMap => DoubleMap<(Twox128, u32), (Twox128, u32), BoundedVec>> } #[test] diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 5b51ed1ffdf49..561bf5298e183 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -569,7 +569,7 @@ mod test { { crate::generate_storage_alias!(test, Foo => NMap< - Key<(u16, Blake2_128Concat)>, + Key<(Blake2_128Concat, u16)>, u32 >); diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index db62d73035397..4b3d87f776b4a 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -323,10 +323,10 @@ pub mod test { use sp_std::convert::TryInto; crate::generate_storage_alias! { Prefix, Foo => Value>> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), WeakBoundedVec>> } + crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), WeakBoundedVec>> } crate::generate_storage_alias! { Prefix, - FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), WeakBoundedVec>> + FooDoubleMap => DoubleMap<(Twox128, u32), (Twox128, u32), WeakBoundedVec>> } #[test] From 6c92fc317bb9dd0b11f4c436fae972bff4d58c66 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 24 Mar 2022 09:11:14 +0100 Subject: [PATCH 0630/1472] Allow pallet error enum variants to contain fields (#10242) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow pallet errors to contain at most one field * Update docs on pallet::error * Reword documentation * cargo fmt * Introduce CompactPalletError trait and require #[pallet::error] fields to implement them * cargo fmt * Do not assume tuple variants * Add CompactPalletError derive macro * Check for error type compactness in construct_runtime * cargo fmt * Derive CompactPalletError instead of implementing it directly during macro expansion * Implement CompactPalletError on OptionBool instead of Option * Check for type idents instead of variant ident * Add doc comments for ErrorCompactnessTest * Add an trait implementation of ErrorCompactnessTest for () * Convert the error field of DispatchError to a 4-element byte array * Add static check for pallet error size * Rename to MAX_PALLET_ERROR_ENCODED_SIZE * Remove ErrorCompactnessTest trait * Remove check_compactness * Return only the most significant byte when constructing a custom InvalidTransaction * Rename CompactPalletError to PalletError * Use counter to generate unique idents for assert macros * Make declarative pallet macros compile with pallet error size checks * Remove unused doc comment * Try and fix build errors * Fix build errors * Add macro_use for some test modules * Test fix * Fix compilation errors * Remove unneeded #[macro_use] * Resolve import ambiguity * Make path to pallet Error enum more specific * Fix test expectation * Disambiguate imports * Fix test expectations * Revert appending pallet module name to path * Rename bags_list::list::Error to BagError * Fixes * Fixes * Fixes * Fix test expectations * Fix test expectation * Add more implementations for PalletError * Lift the 1-field requirement for nested pallet errors * Fix UI test expectation * Remove PalletError impl for OptionBool * Use saturating operations * cargo fmt * Delete obsolete test * Fix test expectation * Try and use assert macro in const context * Pull out the pallet error size check macro * Fix UI test for const assertion * cargo fmt * Apply clippy suggestion * Fix doc comment * Docs for create_tt_return_macro * Ensure TryInto is imported in earlier Rust editions * Apply suggestions from code review Co-authored-by: Bastian Köcher * Fix up comments and names * Implement PalletError for Never * cargo fmt * Don't compile example code * Bump API version for block builder * Factor in codec attributes while derving PalletError * Rename module and fix unit test * Add missing attribute * Check API version and convert ApplyExtrinsicResult accordingly * Rename BagError to ListError Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Use codec crate re-exported from frame support * Add links to types mentioned in doc comments Co-authored-by: Bastian Köcher * cargo fmt * cargo fmt * Re-add attribute for hidden docs Co-authored-by: Bastian Köcher Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- client/block-builder/src/lib.rs | 30 ++- client/rpc/src/state/tests.rs | 2 +- frame/bags-list/src/lib.rs | 6 +- frame/bags-list/src/list/mod.rs | 6 +- frame/bags-list/src/list/tests.rs | 2 +- frame/bags-list/src/tests.rs | 2 +- .../election-provider-multi-phase/src/lib.rs | 2 +- .../src/unsigned.rs | 4 +- frame/scheduler/src/mock.rs | 4 +- frame/sudo/src/mock.rs | 1 - .../procedural/src/construct_runtime/mod.rs | 34 +++ frame/support/procedural/src/lib.rs | 19 +- .../procedural/src/pallet/expand/error.rs | 96 ++++++-- .../procedural/src/pallet/parse/error.rs | 25 +- frame/support/procedural/src/pallet_error.rs | 197 ++++++++++++++++ frame/support/procedural/src/tt_macro.rs | 110 +++++++++ frame/support/src/dispatch.rs | 4 + frame/support/src/error.rs | 54 +---- frame/support/src/lib.rs | 55 ++++- frame/support/src/traits.rs | 3 + frame/support/src/traits/error.rs | 95 ++++++++ frame/support/test/tests/construct_runtime.rs | 154 +++++-------- .../pallet_error_too_large.rs | 85 +++++++ .../pallet_error_too_large.stderr | 13 ++ frame/support/test/tests/origin.rs | 214 ++++++++++++++++++ frame/support/test/tests/pallet.rs | 10 +- frame/support/test/tests/pallet_instance.rs | 4 +- ... => error_does_not_derive_pallet_error.rs} | 14 +- .../error_does_not_derive_pallet_error.stderr | 12 + .../tests/pallet_ui/error_no_fieldless.stderr | 5 - .../pallet_ui/pass/error_nested_types.rs | 41 ++++ frame/utility/src/tests.rs | 1 - primitives/block-builder/src/lib.rs | 10 +- primitives/runtime/src/legacy.rs | 20 ++ .../runtime/src/legacy/byte_sized_error.rs | 100 ++++++++ primitives/runtime/src/lib.rs | 23 +- primitives/runtime/src/traits.rs | 6 + utils/frame/rpc/system/src/lib.rs | 41 +++- 38 files changed, 1263 insertions(+), 241 deletions(-) create mode 100644 frame/support/procedural/src/pallet_error.rs create mode 100644 frame/support/procedural/src/tt_macro.rs create mode 100644 frame/support/src/traits/error.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr create mode 100644 frame/support/test/tests/origin.rs rename frame/support/test/tests/pallet_ui/{error_no_fieldless.rs => error_does_not_derive_pallet_error.rs} (50%) create mode 100644 frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr delete mode 100644 frame/support/test/tests/pallet_ui/error_no_fieldless.stderr create mode 100644 frame/support/test/tests/pallet_ui/pass/error_nested_types.rs create mode 100644 primitives/runtime/src/legacy.rs create mode 100644 primitives/runtime/src/legacy/byte_sized_error.rs diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index a4c6f5aad2aeb..3f9fecbccbb9e 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -35,6 +35,7 @@ use sp_blockchain::{ApplyExtrinsicFailed, Error}; use sp_core::ExecutionContext; use sp_runtime::{ generic::BlockId, + legacy, traits::{Block as BlockT, Hash, HashFor, Header as HeaderT, NumberFor, One}, Digest, }; @@ -135,6 +136,7 @@ where pub struct BlockBuilder<'a, Block: BlockT, A: ProvideRuntimeApi, B> { extrinsics: Vec, api: ApiRef<'a, A::Api>, + version: u32, block_id: BlockId, parent_hash: Block::Hash, backend: &'a B, @@ -183,10 +185,15 @@ where api.initialize_block_with_context(&block_id, ExecutionContext::BlockConstruction, &header)?; + let version = api + .api_version::>(&block_id)? + .ok_or_else(|| Error::VersionInvalid("BlockBuilderApi".to_string()))?; + Ok(Self { parent_hash, extrinsics: Vec::new(), api, + version, block_id, backend, estimated_header_size, @@ -199,13 +206,26 @@ where pub fn push(&mut self, xt: ::Extrinsic) -> Result<(), Error> { let block_id = &self.block_id; let extrinsics = &mut self.extrinsics; + let version = self.version; self.api.execute_in_transaction(|api| { - match api.apply_extrinsic_with_context( - block_id, - ExecutionContext::BlockConstruction, - xt.clone(), - ) { + let res = if version < 6 { + #[allow(deprecated)] + api.apply_extrinsic_before_version_6_with_context( + block_id, + ExecutionContext::BlockConstruction, + xt.clone(), + ) + .map(legacy::byte_sized_error::convert_to_latest) + } else { + api.apply_extrinsic_with_context( + block_id, + ExecutionContext::BlockConstruction, + xt.clone(), + ) + }; + + match res { Ok(Ok(_)) => { extrinsics.push(xt); TransactionOutcome::Commit(Ok(())) diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 9dbe02cdb7d64..287dfac8c6ba0 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -527,7 +527,7 @@ fn should_return_runtime_version() { let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\ - [\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",5],\ + [\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\ [\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",2],\ [\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\ \"transactionVersion\":1,\"stateVersion\":1}"; diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index c502245409fdb..aa9f1c80dfdbc 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -70,7 +70,7 @@ pub mod mock; mod tests; pub mod weights; -pub use list::{notional_bag_for, Bag, Error, List, Node}; +pub use list::{notional_bag_for, Bag, List, ListError, Node}; pub use pallet::*; pub use weights::WeightInfo; @@ -270,7 +270,7 @@ impl, I: 'static> Pallet { } impl, I: 'static> SortedListProvider for Pallet { - type Error = Error; + type Error = ListError; type Score = T::Score; @@ -286,7 +286,7 @@ impl, I: 'static> SortedListProvider for Pallet List::::contains(id) } - fn on_insert(id: T::AccountId, score: T::Score) -> Result<(), Error> { + fn on_insert(id: T::AccountId, score: T::Score) -> Result<(), ListError> { List::::insert(id, score) } diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 4921817c7e146..4e1287458bcb4 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -39,7 +39,7 @@ use sp_std::{ }; #[derive(Debug, PartialEq, Eq)] -pub enum Error { +pub enum ListError { /// A duplicate id has been detected. Duplicate, } @@ -266,9 +266,9 @@ impl, I: 'static> List { /// Insert a new id into the appropriate bag in the list. /// /// Returns an error if the list already contains `id`. - pub(crate) fn insert(id: T::AccountId, score: T::Score) -> Result<(), Error> { + pub(crate) fn insert(id: T::AccountId, score: T::Score) -> Result<(), ListError> { if Self::contains(&id) { - return Err(Error::Duplicate) + return Err(ListError::Duplicate) } let bag_score = notional_bag_for::(score); diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index 9b7a078b44284..c8e233f1e62cc 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -248,7 +248,7 @@ mod list { // then assert_storage_noop!(assert_eq!( List::::insert(3, 20).unwrap_err(), - Error::Duplicate + ListError::Duplicate )); }); } diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs index 99396c9cbb3e3..0d6ba4721b9a2 100644 --- a/frame/bags-list/src/tests.rs +++ b/frame/bags-list/src/tests.rs @@ -518,7 +518,7 @@ mod sorted_list_provider { // then assert_storage_noop!(assert_eq!( BagsList::on_insert(3, 20).unwrap_err(), - Error::Duplicate + ListError::Duplicate )); }); } diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index b57d24d2d530c..ddc06ce0aecfd 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1583,7 +1583,7 @@ impl ElectionProvider for Pallet { /// number. pub fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { let error_number = match error { - DispatchError::Module(ModuleError { error, .. }) => error, + DispatchError::Module(ModuleError { error, .. }) => error[0], _ => 0, }; InvalidTransaction::Custom(error_number) diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index c52a4da22cb87..d210852bac19e 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -931,7 +931,7 @@ mod tests { #[test] #[should_panic(expected = "Invalid unsigned submission must produce invalid block and \ deprive validator from their authoring reward.: \ - Module(ModuleError { index: 2, error: 1, message: \ + Module(ModuleError { index: 2, error: [1, 0, 0, 0], message: \ Some(\"PreDispatchWrongWinnerCount\") })")] fn unfeasible_solution_panics() { ExtBuilder::default().build_and_execute(|| { @@ -1053,7 +1053,7 @@ mod tests { MultiPhase::basic_checks(&solution, "mined").unwrap_err(), MinerError::PreDispatchChecksFailed(DispatchError::Module(ModuleError { index: 2, - error: 1, + error: [1, 0, 0, 0], message: Some("PreDispatchWrongWinnerCount"), })), ); diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 869425c2ff530..ecd04c3e48b52 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -38,7 +38,7 @@ use sp_runtime::{ // Logger module to track execution. #[frame_support::pallet] pub mod logger { - use super::*; + use super::{OriginCaller, OriginTrait}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use std::cell::RefCell; @@ -71,7 +71,7 @@ pub mod logger { #[pallet::call] impl Pallet where - ::Origin: OriginTrait, + ::Origin: OriginTrait, { #[pallet::weight(*weight)] pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index 410807789069b..2e2a4abafcd98 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -34,7 +34,6 @@ use sp_runtime::{ // Logger module to track execution. #[frame_support::pallet] pub mod logger { - use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 249eb072001c9..2a86869382c93 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -241,6 +241,7 @@ fn construct_runtime_final_expansion( expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate); let integrity_test = decl_integrity_test(&scrate); + let static_assertions = decl_static_assertions(&name, &pallets, &scrate); let res = quote!( #scrate_decl @@ -282,6 +283,8 @@ fn construct_runtime_final_expansion( #validate_unsigned #integrity_test + + #static_assertions ); Ok(res) @@ -471,3 +474,34 @@ fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { } ) } + +fn decl_static_assertions( + runtime: &Ident, + pallet_decls: &[Pallet], + scrate: &TokenStream2, +) -> TokenStream2 { + let error_encoded_size_check = pallet_decls.iter().map(|decl| { + let path = &decl.path; + let assert_message = format!( + "The maximum encoded size of the error type in the `{}` pallet exceeds \ + `MAX_MODULE_ERROR_ENCODED_SIZE`", + decl.name, + ); + + quote! { + #scrate::tt_call! { + macro = [{ #path::tt_error_token }] + frame_support = [{ #scrate }] + ~~> #scrate::assert_error_encoded_size! { + path = [{ #path }] + runtime = [{ #runtime }] + assert_message = [{ #assert_message }] + } + } + } + }); + + quote! { + #(#error_encoded_size_check)* + } +} diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index e2233fff72285..92564e94493c1 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -28,9 +28,11 @@ mod dummy_part_checker; mod key_prefix; mod match_and_insert; mod pallet; +mod pallet_error; mod partial_eq_no_bound; mod storage; mod transactional; +mod tt_macro; use proc_macro::TokenStream; use std::{cell::RefCell, str::FromStr}; @@ -41,9 +43,9 @@ thread_local! { static COUNTER: RefCell = RefCell::new(Counter(0)); } -/// Counter to generate a relatively unique identifier for macros querying for the existence of -/// pallet parts. This is necessary because declarative macros gets hoisted to the crate root, -/// which shares the namespace with other pallets containing the very same query macros. +/// Counter to generate a relatively unique identifier for macros. This is necessary because +/// declarative macros gets hoisted to the crate root, which shares the namespace with other pallets +/// containing the very same macros. struct Counter(u64); impl Counter { @@ -562,3 +564,14 @@ pub fn __generate_dummy_part_checker(input: TokenStream) -> TokenStream { pub fn match_and_insert(input: TokenStream) -> TokenStream { match_and_insert::match_and_insert(input) } + +#[proc_macro_derive(PalletError, attributes(codec))] +pub fn derive_pallet_error(input: TokenStream) -> TokenStream { + pallet_error::derive_pallet_error(input) +} + +/// Internal macro used by `frame_support` to create tt-call-compliant macros +#[proc_macro] +pub fn __create_tt_macro(input: TokenStream) -> TokenStream { + tt_macro::create_tt_return_macro(input) +} diff --git a/frame/support/procedural/src/pallet/expand/error.rs b/frame/support/procedural/src/pallet/expand/error.rs index 184fa86d3ae19..86b06d737decf 100644 --- a/frame/support/procedural/src/pallet/expand/error.rs +++ b/frame/support/procedural/src/pallet/expand/error.rs @@ -15,20 +15,48 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::pallet::Def; +use crate::{ + pallet::{parse::error::VariantField, Def}, + COUNTER, +}; use frame_support_procedural_tools::get_doc_literals; +use syn::spanned::Spanned; /// /// * impl various trait on Error pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { - let error = if let Some(error) = &def.error { error } else { return Default::default() }; + let count = COUNTER.with(|counter| counter.borrow_mut().inc()); + let error_token_unique_id = + syn::Ident::new(&format!("__tt_error_token_{}", count), def.item.span()); - let error_ident = &error.error; let frame_support = &def.frame_support; let frame_system = &def.frame_system; + let config_where_clause = &def.config.where_clause; + + let error = if let Some(error) = &def.error { + error + } else { + return quote::quote! { + #[macro_export] + #[doc(hidden)] + macro_rules! #error_token_unique_id { + { + $caller:tt + frame_support = [{ $($frame_support:ident)::* }] + } => { + $($frame_support::)*tt_return! { + $caller + } + }; + } + + pub use #error_token_unique_id as tt_error_token; + } + }; + + let error_ident = &error.error; let type_impl_gen = &def.type_impl_generics(error.attr_span); let type_use_gen = &def.type_use_generics(error.attr_span); - let config_where_clause = &def.config.where_clause; let phantom_variant: syn::Variant = syn::parse_quote!( #[doc(hidden)] @@ -39,13 +67,19 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { ) ); - let as_u8_matches = error.variants.iter().enumerate().map( - |(i, (variant, _))| quote::quote_spanned!(error.attr_span => Self::#variant => #i as u8,), - ); - - let as_str_matches = error.variants.iter().map(|(variant, _)| { - let variant_str = format!("{}", variant); - quote::quote_spanned!(error.attr_span => Self::#variant => #variant_str,) + let as_str_matches = error.variants.iter().map(|(variant, field_ty, _)| { + let variant_str = variant.to_string(); + match field_ty { + Some(VariantField { is_named: true }) => { + quote::quote_spanned!(error.attr_span => Self::#variant { .. } => #variant_str,) + }, + Some(VariantField { is_named: false }) => { + quote::quote_spanned!(error.attr_span => Self::#variant(..) => #variant_str,) + }, + None => { + quote::quote_spanned!(error.attr_span => Self::#variant => #variant_str,) + }, + } }); let error_item = { @@ -62,9 +96,14 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" }; // derive TypeInfo for error metadata - error_item - .attrs - .push(syn::parse_quote!( #[derive(#frame_support::scale_info::TypeInfo)] )); + error_item.attrs.push(syn::parse_quote! { + #[derive( + #frame_support::codec::Encode, + #frame_support::codec::Decode, + #frame_support::scale_info::TypeInfo, + #frame_support::PalletError, + )] + }); error_item.attrs.push(syn::parse_quote!( #[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)] )); @@ -90,14 +129,6 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { } impl<#type_impl_gen> #error_ident<#type_use_gen> #config_where_clause { - #[doc(hidden)] - pub fn as_u8(&self) -> u8 { - match &self { - Self::__Ignore(_, _) => unreachable!("`__Ignore` can never be constructed"), - #( #as_u8_matches )* - } - } - #[doc(hidden)] pub fn as_str(&self) -> &'static str { match &self { @@ -120,18 +151,37 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { #config_where_clause { fn from(err: #error_ident<#type_use_gen>) -> Self { + use #frame_support::codec::Encode; let index = < ::PalletInfo as #frame_support::traits::PalletInfo >::index::>() .expect("Every active module has an index in the runtime; qed") as u8; + let mut encoded = err.encode(); + encoded.resize(#frame_support::MAX_MODULE_ERROR_ENCODED_SIZE, 0); #frame_support::sp_runtime::DispatchError::Module(#frame_support::sp_runtime::ModuleError { index, - error: err.as_u8(), + error: core::convert::TryInto::try_into(encoded).expect("encoded error is resized to be equal to the maximum encoded error size; qed"), message: Some(err.as_str()), }) } } + + #[macro_export] + #[doc(hidden)] + macro_rules! #error_token_unique_id { + { + $caller:tt + frame_support = [{ $($frame_support:ident)::* }] + } => { + $($frame_support::)*tt_return! { + $caller + error = [{ #error_ident }] + } + }; + } + + pub use #error_token_unique_id as tt_error_token; ) } diff --git a/frame/support/procedural/src/pallet/parse/error.rs b/frame/support/procedural/src/pallet/parse/error.rs index 419770386bf69..0ec49aa0adb49 100644 --- a/frame/support/procedural/src/pallet/parse/error.rs +++ b/frame/support/procedural/src/pallet/parse/error.rs @@ -18,20 +18,26 @@ use super::helper; use frame_support_procedural_tools::get_doc_literals; use quote::ToTokens; -use syn::spanned::Spanned; +use syn::{spanned::Spanned, Fields}; /// List of additional token to be used for parsing. mod keyword { syn::custom_keyword!(Error); } +/// Records information about the error enum variants. +pub struct VariantField { + /// Whether or not the field is named, i.e. whether it is a tuple variant or struct variant. + pub is_named: bool, +} + /// This checks error declaration as a enum declaration with only variants without fields nor /// discriminant. pub struct ErrorDef { /// The index of error item in pallet module. pub index: usize, - /// Variants ident and doc literals (ordered as declaration order) - pub variants: Vec<(syn::Ident, Vec)>, + /// Variants ident, optional field and doc literals (ordered as declaration order) + pub variants: Vec<(syn::Ident, Option, Vec)>, /// A set of usage of instance, must be check for consistency with trait. pub instances: Vec, /// The keyword error used (contains span). @@ -70,18 +76,19 @@ impl ErrorDef { .variants .iter() .map(|variant| { - if !matches!(variant.fields, syn::Fields::Unit) { - let msg = "Invalid pallet::error, unexpected fields, must be `Unit`"; - return Err(syn::Error::new(variant.fields.span(), msg)) - } + let field_ty = match &variant.fields { + Fields::Unit => None, + Fields::Named(_) => Some(VariantField { is_named: true }), + Fields::Unnamed(_) => Some(VariantField { is_named: false }), + }; if variant.discriminant.is_some() { - let msg = "Invalid pallet::error, unexpected discriminant, discriminant \ + let msg = "Invalid pallet::error, unexpected discriminant, discriminants \ are not supported"; let span = variant.discriminant.as_ref().unwrap().0.span(); return Err(syn::Error::new(span, msg)) } - Ok((variant.ident.clone(), get_doc_literals(&variant.attrs))) + Ok((variant.ident.clone(), field_ty, get_doc_literals(&variant.attrs))) }) .collect::>()?; diff --git a/frame/support/procedural/src/pallet_error.rs b/frame/support/procedural/src/pallet_error.rs new file mode 100644 index 0000000000000..216168131e43d --- /dev/null +++ b/frame/support/procedural/src/pallet_error.rs @@ -0,0 +1,197 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_support_procedural_tools::generate_crate_access_2018; +use quote::ToTokens; +use std::str::FromStr; + +// Derive `PalletError` +pub fn derive_pallet_error(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let syn::DeriveInput { ident: name, generics, data, .. } = match syn::parse(input) { + Ok(input) => input, + Err(e) => return e.to_compile_error().into(), + }; + + let frame_support = match generate_crate_access_2018("frame-support") { + Ok(c) => c, + Err(e) => return e.into_compile_error().into(), + }; + let frame_support = &frame_support; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let max_encoded_size = match data { + syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { + syn::Fields::Named(syn::FieldsNamed { named: fields, .. }) | + syn::Fields::Unnamed(syn::FieldsUnnamed { unnamed: fields, .. }) => { + let maybe_field_tys = fields + .iter() + .map(|f| generate_field_types(f, &frame_support)) + .collect::>>(); + let field_tys = match maybe_field_tys { + Ok(tys) => tys.into_iter().flatten(), + Err(e) => return e.into_compile_error().into(), + }; + quote::quote! { + 0_usize + #( + .saturating_add(< + #field_tys as #frame_support::traits::PalletError + >::MAX_ENCODED_SIZE) + )* + } + }, + syn::Fields::Unit => quote::quote!(0), + }, + syn::Data::Enum(syn::DataEnum { variants, .. }) => { + let field_tys = variants + .iter() + .map(|variant| generate_variant_field_types(variant, &frame_support)) + .collect::>>, syn::Error>>(); + + let field_tys = match field_tys { + Ok(tys) => tys.into_iter().flatten().collect::>(), + Err(e) => return e.to_compile_error().into(), + }; + + // We start with `1`, because the discriminant of an enum is stored as u8 + if field_tys.is_empty() { + quote::quote!(1) + } else { + let variant_sizes = field_tys.into_iter().map(|variant_field_tys| { + quote::quote! { + 1_usize + #(.saturating_add(< + #variant_field_tys as #frame_support::traits::PalletError + >::MAX_ENCODED_SIZE))* + } + }); + + quote::quote! {{ + let mut size = 1_usize; + let mut tmp = 0_usize; + #( + tmp = #variant_sizes; + size = if tmp > size { tmp } else { size }; + tmp = 0_usize; + )* + size + }} + } + }, + syn::Data::Union(syn::DataUnion { union_token, .. }) => { + let msg = "Cannot derive `PalletError` for union; please implement it directly"; + return syn::Error::new(union_token.span, msg).into_compile_error().into() + }, + }; + + quote::quote!( + const _: () = { + impl #impl_generics #frame_support::traits::PalletError + for #name #ty_generics #where_clause + { + const MAX_ENCODED_SIZE: usize = #max_encoded_size; + } + }; + ) + .into() +} + +fn generate_field_types( + field: &syn::Field, + scrate: &syn::Ident, +) -> syn::Result> { + let attrs = &field.attrs; + + for attr in attrs { + if attr.path.is_ident("codec") { + match attr.parse_meta()? { + syn::Meta::List(ref meta_list) if meta_list.nested.len() == 1 => { + match meta_list + .nested + .first() + .expect("Just checked that there is one item; qed") + { + syn::NestedMeta::Meta(syn::Meta::Path(path)) + if path.get_ident().map_or(false, |i| i == "skip") => + return Ok(None), + + syn::NestedMeta::Meta(syn::Meta::Path(path)) + if path.get_ident().map_or(false, |i| i == "compact") => + { + let field_ty = &field.ty; + return Ok(Some(quote::quote!(#scrate::codec::Compact<#field_ty>))) + }, + + syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue { + path, + lit: syn::Lit::Str(lit_str), + .. + })) if path.get_ident().map_or(false, |i| i == "encoded_as") => { + let ty = proc_macro2::TokenStream::from_str(&lit_str.value())?; + return Ok(Some(ty)) + }, + + _ => (), + } + }, + _ => (), + } + } + } + + Ok(Some(field.ty.to_token_stream())) +} + +fn generate_variant_field_types( + variant: &syn::Variant, + scrate: &syn::Ident, +) -> syn::Result>> { + let attrs = &variant.attrs; + + for attr in attrs { + if attr.path.is_ident("codec") { + match attr.parse_meta()? { + syn::Meta::List(ref meta_list) if meta_list.nested.len() == 1 => { + match meta_list + .nested + .first() + .expect("Just checked that there is one item; qed") + { + syn::NestedMeta::Meta(syn::Meta::Path(path)) + if path.get_ident().map_or(false, |i| i == "skip") => + return Ok(None), + + _ => (), + } + }, + _ => (), + } + } + } + + match &variant.fields { + syn::Fields::Named(syn::FieldsNamed { named: fields, .. }) | + syn::Fields::Unnamed(syn::FieldsUnnamed { unnamed: fields, .. }) => { + let field_tys = fields + .iter() + .map(|field| generate_field_types(field, scrate)) + .collect::>>()?; + Ok(Some(field_tys.into_iter().flatten().collect())) + }, + syn::Fields::Unit => Ok(None), + } +} diff --git a/frame/support/procedural/src/tt_macro.rs b/frame/support/procedural/src/tt_macro.rs new file mode 100644 index 0000000000000..0a270a7173cfc --- /dev/null +++ b/frame/support/procedural/src/tt_macro.rs @@ -0,0 +1,110 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of the `create_tt_return_macro` macro + +use crate::COUNTER; +use frame_support_procedural_tools::generate_crate_access_2018; +use proc_macro2::{Ident, TokenStream}; +use quote::format_ident; + +struct CreateTtReturnMacroDef { + name: Ident, + args: Vec<(Ident, TokenStream)>, +} + +impl syn::parse::Parse for CreateTtReturnMacroDef { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let name = input.parse()?; + let _ = input.parse::()?; + + let mut args = Vec::new(); + while !input.is_empty() { + let mut value; + let key: Ident = input.parse()?; + let _ = input.parse::()?; + let _: syn::token::Bracket = syn::bracketed!(value in input); + let _: syn::token::Brace = syn::braced!(value in value); + let value: TokenStream = value.parse()?; + + args.push((key, value)) + } + + Ok(Self { name, args }) + } +} + +/// A proc macro that accepts a name and any number of key-value pairs, to be used to create a +/// declarative macro that follows tt-call conventions and simply calls [`tt_call::tt_return`], +/// accepting an optional `frame-support` argument and returning the key-value pairs that were +/// supplied to the proc macro. +/// +/// # Example +/// ```ignore +/// __create_tt_macro! { +/// my_tt_macro, +/// foo = [{ bar }] +/// } +/// +/// // Creates the following declarative macro: +/// +/// macro_rules! my_tt_macro { +/// { +/// $caller:tt +/// $(frame_support = [{ $($frame_support:ident)::* }])? +/// } => { +/// frame_support::tt_return! { +/// $caller +/// foo = [{ bar }] +/// } +/// } +/// } +/// ``` +pub fn create_tt_return_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let CreateTtReturnMacroDef { name, args } = + syn::parse_macro_input!(input as CreateTtReturnMacroDef); + + let frame_support = match generate_crate_access_2018("frame-support") { + Ok(i) => i, + Err(e) => return e.into_compile_error().into(), + }; + let (keys, values): (Vec<_>, Vec<_>) = args.into_iter().unzip(); + let count = COUNTER.with(|counter| counter.borrow_mut().inc()); + let unique_name = format_ident!("{}_{}", name, count); + + let decl_macro = quote::quote! { + #[macro_export] + #[doc(hidden)] + macro_rules! #unique_name { + { + $caller:tt + $(frame_support = [{ $($frame_support:ident)::* }])? + } => { + #frame_support::tt_return! { + $caller + #( + #keys = [{ #values }] + )* + } + } + } + + pub use #unique_name as #name; + }; + + decl_macro.into() +} diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index ece5173f2f4ca..7ccf796167297 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -2003,6 +2003,10 @@ macro_rules! decl_module { pub type Pallet<$trait_instance $(, $instance $( = $module_default_instance)?)?> = $mod_type<$trait_instance $(, $instance)?>; + $crate::__create_tt_macro! { + tt_error_token, + } + $crate::decl_module! { @impl_on_initialize { $system } diff --git a/frame/support/src/error.rs b/frame/support/src/error.rs index 4880bba5c5e97..764376a4e1dc2 100644 --- a/frame/support/src/error.rs +++ b/frame/support/src/error.rs @@ -85,7 +85,12 @@ macro_rules! decl_error { } ) => { $(#[$attr])* - #[derive($crate::scale_info::TypeInfo)] + #[derive( + $crate::codec::Encode, + $crate::codec::Decode, + $crate::scale_info::TypeInfo, + $crate::PalletError, + )] #[scale_info(skip_type_params($generic $(, $inst_generic)?), capture_docs = "always")] pub enum $error<$generic: $trait $(, $inst_generic: $instance)?> $( where $( $where_ty: $where_bound ),* )? @@ -114,17 +119,6 @@ macro_rules! decl_error { impl<$generic: $trait $(, $inst_generic: $instance)?> $error<$generic $(, $inst_generic)?> $( where $( $where_ty: $where_bound ),* )? { - fn as_u8(&self) -> u8 { - $crate::decl_error! { - @GENERATE_AS_U8 - self - $error - {} - 0, - $( $name ),* - } - } - fn as_str(&self) -> &'static str { match self { Self::__Ignore(_, _) => unreachable!("`__Ignore` can never be constructed"), @@ -149,47 +143,19 @@ macro_rules! decl_error { $( where $( $where_ty: $where_bound ),* )? { fn from(err: $error<$generic $(, $inst_generic)?>) -> Self { + use $crate::codec::Encode; let index = <$generic::PalletInfo as $crate::traits::PalletInfo> ::index::<$module<$generic $(, $inst_generic)?>>() .expect("Every active module has an index in the runtime; qed") as u8; + let mut error = err.encode(); + error.resize($crate::MAX_MODULE_ERROR_ENCODED_SIZE, 0); $crate::sp_runtime::DispatchError::Module($crate::sp_runtime::ModuleError { index, - error: err.as_u8(), + error: core::convert::TryInto::try_into(error).expect("encoded error is resized to be equal to the maximum encoded error size; qed"), message: Some(err.as_str()), }) } } }; - (@GENERATE_AS_U8 - $self:ident - $error:ident - { $( $generated:tt )* } - $index:expr, - $name:ident - $( , $rest:ident )* - ) => { - $crate::decl_error! { - @GENERATE_AS_U8 - $self - $error - { - $( $generated )* - $error::$name => $index, - } - $index + 1, - $( $rest ),* - } - }; - (@GENERATE_AS_U8 - $self:ident - $error:ident - { $( $generated:tt )* } - $index:expr, - ) => { - match $self { - $error::__Ignore(_, _) => unreachable!("`__Ignore` can never be constructed"), - $( $generated )* - } - } } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 5f62995c52272..70a79c07189dc 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -93,7 +93,9 @@ pub use self::{ StorageMap, StorageNMap, StoragePrefixedMap, StorageValue, }, }; -pub use sp_runtime::{self, print, traits::Printable, ConsensusEngineId}; +pub use sp_runtime::{ + self, print, traits::Printable, ConsensusEngineId, MAX_MODULE_ERROR_ENCODED_SIZE, +}; use codec::{Decode, Encode}; use scale_info::TypeInfo; @@ -103,7 +105,7 @@ use sp_runtime::TypeId; pub const LOG_TARGET: &'static str = "runtime::frame-support"; /// A type that cannot be instantiated. -#[derive(Debug, PartialEq, Eq, Clone, TypeInfo)] +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] pub enum Never {} /// A pallet identifier. These are per pallet and should be stored in a registry somewhere. @@ -598,11 +600,12 @@ pub fn debug(data: &impl sp_std::fmt::Debug) { #[doc(inline)] pub use frame_support_procedural::{ - construct_runtime, decl_storage, match_and_insert, transactional, RuntimeDebugNoBound, + construct_runtime, decl_storage, match_and_insert, transactional, PalletError, + RuntimeDebugNoBound, }; #[doc(hidden)] -pub use frame_support_procedural::__generate_dummy_part_checker; +pub use frame_support_procedural::{__create_tt_macro, __generate_dummy_part_checker}; /// Derive [`Clone`] but do not bound any generic. /// @@ -847,6 +850,32 @@ macro_rules! assert_ok { }; } +/// Assert that the maximum encoding size does not exceed the value defined in +/// [`MAX_MODULE_ERROR_ENCODED_SIZE`] during compilation. +/// +/// This macro is intended to be used in conjunction with `tt_call!`. +#[macro_export] +macro_rules! assert_error_encoded_size { + { + path = [{ $($path:ident)::+ }] + runtime = [{ $runtime:ident }] + assert_message = [{ $assert_message:literal }] + error = [{ $error:ident }] + } => { + const _: () = assert!( + < + $($path::)+$error<$runtime> as $crate::traits::PalletError + >::MAX_ENCODED_SIZE <= $crate::MAX_MODULE_ERROR_ENCODED_SIZE, + $assert_message + ); + }; + { + path = [{ $($path:ident)::+ }] + runtime = [{ $runtime:ident }] + assert_message = [{ $assert_message:literal }] + } => {}; +} + #[cfg(feature = "std")] #[doc(hidden)] pub use serde::{Deserialize, Serialize}; @@ -1375,6 +1404,7 @@ pub mod pallet_prelude { TransactionTag, TransactionValidity, TransactionValidityError, UnknownTransaction, ValidTransaction, }, + MAX_MODULE_ERROR_ENCODED_SIZE, }; pub use sp_std::marker::PhantomData; } @@ -1652,10 +1682,25 @@ pub mod pallet_prelude { /// pub enum Error { /// /// $some_optional_doc /// $SomeFieldLessVariant, +/// /// $some_more_optional_doc +/// $SomeVariantWithOneField(FieldType), /// ... /// } /// ``` -/// I.e. a regular rust enum named `Error`, with generic `T` and fieldless variants. +/// I.e. a regular rust enum named `Error`, with generic `T` and fieldless or multiple-field +/// variants. +/// +/// Any field type in the enum variants must implement [`scale_info::TypeInfo`] in order to be +/// properly used in the metadata, and its encoded size should be as small as possible, +/// preferably 1 byte in size in order to reduce storage size. The error enum itself has an +/// absolute maximum encoded size specified by [`MAX_MODULE_ERROR_ENCODED_SIZE`]. +/// +/// Field types in enum variants must also implement [`PalletError`](traits::PalletError), +/// otherwise the pallet will fail to compile. Rust primitive types have already implemented +/// the [`PalletError`](traits::PalletError) trait along with some commonly used stdlib types +/// such as `Option` and `PhantomData`, and hence in most use cases, a manual implementation is +/// not necessary and is discouraged. +/// /// The generic `T` mustn't bound anything and where clause is not allowed. But bounds and /// where clause shouldn't be needed for any usecase. /// diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index a8ce78ae9dabc..40afc0d337f43 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -46,6 +46,9 @@ pub use validation::{ ValidatorSetWithIdentification, VerifySeal, }; +mod error; +pub use error::PalletError; + mod filter; pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter, IntegrityTest}; diff --git a/frame/support/src/traits/error.rs b/frame/support/src/traits/error.rs new file mode 100644 index 0000000000000..8e26891669e65 --- /dev/null +++ b/frame/support/src/traits/error.rs @@ -0,0 +1,95 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Traits for describing and constraining pallet error types. +use codec::{Compact, Decode, Encode}; +use sp_std::marker::PhantomData; + +/// Trait indicating that the implementing type is going to be included as a field in a variant of +/// the `#[pallet::error]` enum type. +/// +/// ## Notes +/// +/// The pallet error enum has a maximum encoded size as defined by +/// [`frame_support::MAX_MODULE_ERROR_ENCODED_SIZE`]. If the pallet error type exceeds this size +/// limit, a static assertion during compilation will fail. The compilation error will be in the +/// format of `error[E0080]: evaluation of constant value failed` due to the usage of +/// const assertions. +pub trait PalletError: Encode + Decode { + /// The maximum encoded size for the implementing type. + /// + /// This will be used to check whether the pallet error type is less than or equal to + /// [`frame_support::MAX_MODULE_ERROR_ENCODED_SIZE`], and if it is, a compilation error will be + /// thrown. + const MAX_ENCODED_SIZE: usize; +} + +macro_rules! impl_for_types { + (size: $size:expr, $($typ:ty),+) => { + $( + impl PalletError for $typ { + const MAX_ENCODED_SIZE: usize = $size; + } + )+ + }; +} + +impl_for_types!(size: 0, (), crate::Never); +impl_for_types!(size: 1, u8, i8, bool); +impl_for_types!(size: 2, u16, i16, Compact); +impl_for_types!(size: 4, u32, i32, Compact); +impl_for_types!(size: 5, Compact); +impl_for_types!(size: 8, u64, i64); +impl_for_types!(size: 9, Compact); +// Contains a u64 for secs and u32 for nanos, hence 12 bytes +impl_for_types!(size: 12, core::time::Duration); +impl_for_types!(size: 16, u128, i128); +impl_for_types!(size: 17, Compact); + +impl PalletError for PhantomData { + const MAX_ENCODED_SIZE: usize = 0; +} + +impl PalletError for core::ops::Range { + const MAX_ENCODED_SIZE: usize = T::MAX_ENCODED_SIZE.saturating_mul(2); +} + +impl PalletError for [T; N] { + const MAX_ENCODED_SIZE: usize = T::MAX_ENCODED_SIZE.saturating_mul(N); +} + +impl PalletError for Option { + const MAX_ENCODED_SIZE: usize = T::MAX_ENCODED_SIZE.saturating_add(1); +} + +impl PalletError for Result { + const MAX_ENCODED_SIZE: usize = if T::MAX_ENCODED_SIZE > E::MAX_ENCODED_SIZE { + T::MAX_ENCODED_SIZE + } else { + E::MAX_ENCODED_SIZE + } + .saturating_add(1); +} + +#[impl_trait_for_tuples::impl_for_tuples(1, 18)] +impl PalletError for Tuple { + const MAX_ENCODED_SIZE: usize = { + let mut size = 0_usize; + for_tuples!( #(size = size.saturating_add(Tuple::MAX_ENCODED_SIZE);)* ); + size + }; +} diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index b3f8feb8aa4b2..804deb08919a4 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -271,139 +271,95 @@ pub type Header = generic::Header; pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; -mod origin_test { - use super::{module3, nested, system, Block, UncheckedExtrinsic}; - use frame_support::traits::{Contains, OriginTrait}; - - impl nested::module3::Config for RuntimeOriginTest {} - impl module3::Config for RuntimeOriginTest {} - - pub struct BaseCallFilter; - impl Contains for BaseCallFilter { - fn contains(c: &Call) -> bool { - match c { - Call::NestedModule3(_) => true, - _ => false, - } - } - } - - impl system::Config for RuntimeOriginTest { - type BaseCallFilter = BaseCallFilter; - type Hash = super::H256; - type Origin = Origin; - type BlockNumber = super::BlockNumber; - type AccountId = u32; - type Event = Event; - type PalletInfo = PalletInfo; - type Call = Call; - type DbWeight = (); - } - - frame_support::construct_runtime!( - pub enum RuntimeOriginTest where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic - { - System: system::{Pallet, Event, Origin}, - NestedModule3: nested::module3::{Pallet, Origin, Call}, - Module3: module3::{Pallet, Origin, Call}, - } - ); - - #[test] - fn origin_default_filter() { - let accepted_call = nested::module3::Call::fail {}.into(); - let rejected_call = module3::Call::fail {}.into(); - - assert_eq!(Origin::root().filter_call(&accepted_call), true); - assert_eq!(Origin::root().filter_call(&rejected_call), true); - assert_eq!(Origin::none().filter_call(&accepted_call), true); - assert_eq!(Origin::none().filter_call(&rejected_call), false); - assert_eq!(Origin::signed(0).filter_call(&accepted_call), true); - assert_eq!(Origin::signed(0).filter_call(&rejected_call), false); - assert_eq!(Origin::from(Some(0)).filter_call(&accepted_call), true); - assert_eq!(Origin::from(Some(0)).filter_call(&rejected_call), false); - assert_eq!(Origin::from(None).filter_call(&accepted_call), true); - assert_eq!(Origin::from(None).filter_call(&rejected_call), false); - assert_eq!(Origin::from(super::nested::module3::Origin).filter_call(&accepted_call), true); - assert_eq!(Origin::from(super::nested::module3::Origin).filter_call(&rejected_call), false); - - let mut origin = Origin::from(Some(0)); - origin.add_filter(|c| matches!(c, Call::Module3(_))); - assert_eq!(origin.filter_call(&accepted_call), false); - assert_eq!(origin.filter_call(&rejected_call), false); - - // Now test for root origin and filters: - let mut origin = Origin::from(Some(0)); - origin.set_caller_from(Origin::root()); - assert!(matches!(origin.caller, OriginCaller::system(super::system::RawOrigin::Root))); - - // Root origin bypass all filter. - assert_eq!(origin.filter_call(&accepted_call), true); - assert_eq!(origin.filter_call(&rejected_call), true); - - origin.set_caller_from(Origin::from(Some(0))); - - // Back to another signed origin, the filtered are now effective again - assert_eq!(origin.filter_call(&accepted_call), true); - assert_eq!(origin.filter_call(&rejected_call), false); - - origin.set_caller_from(Origin::root()); - origin.reset_filter(); - - // Root origin bypass all filter, even when they are reset. - assert_eq!(origin.filter_call(&accepted_call), true); - assert_eq!(origin.filter_call(&rejected_call), true); - } -} - #[test] fn check_modules_error_type() { assert_eq!( Module1_1::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 31, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 31, + error: [0; 4], + message: Some("Something") + })), ); assert_eq!( Module2::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 32, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 32, + error: [0; 4], + message: Some("Something") + })), ); assert_eq!( Module1_2::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 33, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 33, + error: [0; 4], + message: Some("Something") + })), ); assert_eq!( NestedModule3::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 34, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 34, + error: [0; 4], + message: Some("Something") + })), ); assert_eq!( Module1_3::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 6, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 6, + error: [0; 4], + message: Some("Something") + })), ); assert_eq!( Module1_4::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 3, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 3, + error: [0; 4], + message: Some("Something") + })), ); assert_eq!( Module1_5::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 4, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 4, + error: [0; 4], + message: Some("Something") + })), ); assert_eq!( Module1_6::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 1, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 1, + error: [0; 4], + message: Some("Something") + })), ); assert_eq!( Module1_7::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 2, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 2, + error: [0; 4], + message: Some("Something") + })), ); assert_eq!( Module1_8::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 12, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 12, + error: [0; 4], + message: Some("Something") + })), ); assert_eq!( Module1_9::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { index: 13, error: 0, message: Some("Something") })), + Err(DispatchError::Module(ModuleError { + index: 13, + error: [0; 4], + message: Some("Something") + })), ); } diff --git a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs new file mode 100644 index 0000000000000..827d8a58af733 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs @@ -0,0 +1,85 @@ +use frame_support::construct_runtime; +use sp_runtime::{generic, traits::BlakeTwo256}; +use sp_core::sr25519; + +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::error] + pub enum Error { + MyError(crate::Nested1), + } +} + +#[derive(scale_info::TypeInfo, frame_support::PalletError, codec::Encode, codec::Decode)] +pub enum Nested1 { + Nested2(Nested2) +} + +#[derive(scale_info::TypeInfo, frame_support::PalletError, codec::Encode, codec::Decode)] +pub enum Nested2 { + Nested3(Nested3) +} + +#[derive(scale_info::TypeInfo, frame_support::PalletError, codec::Encode, codec::Decode)] +pub enum Nested3 { + Nested4(Nested4) +} + +#[derive(scale_info::TypeInfo, frame_support::PalletError, codec::Encode, codec::Decode)] +pub enum Nested4 { + Num(u8) +} + +pub type Signature = sr25519::Signature; +pub type BlockNumber = u32; +pub type Header = generic::Header; +pub type Block = generic::Block; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + +impl pallet::Config for Runtime {} + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u32; + type Call = Call; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = frame_support::traits::ConstU32<250>; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + Pallet: pallet::{Pallet}, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr new file mode 100644 index 0000000000000..161873866b6f3 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr @@ -0,0 +1,13 @@ +error[E0080]: evaluation of constant value failed + --> tests/construct_runtime_ui/pallet_error_too_large.rs:74:1 + | +74 | / construct_runtime! { +75 | | pub enum Runtime where +76 | | Block = Block, +77 | | NodeBlock = Block, +... | +82 | | } +83 | | } + | |_^ the evaluated program panicked at 'The maximum encoded size of the error type in the `Pallet` pallet exceeds `MAX_MODULE_ERROR_ENCODED_SIZE`', $DIR/tests/construct_runtime_ui/pallet_error_too_large.rs:74:1 + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/origin.rs b/frame/support/test/tests/origin.rs new file mode 100644 index 0000000000000..1def44c15b48f --- /dev/null +++ b/frame/support/test/tests/origin.rs @@ -0,0 +1,214 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Origin tests for construct_runtime macro + +#![recursion_limit = "128"] + +use frame_support::traits::{Contains, OriginTrait}; +use scale_info::TypeInfo; +use sp_core::{sr25519, H256}; +use sp_runtime::{generic, traits::BlakeTwo256}; + +mod system; + +mod nested { + use super::*; + + pub mod module { + use super::*; + + pub trait Config: system::Config {} + + frame_support::decl_module! { + pub struct Module for enum Call + where origin: ::Origin, system=system + { + #[weight = 0] + pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { + Err(Error::::Something.into()) + } + } + } + + #[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo)] + pub struct Origin; + + frame_support::decl_event! { + pub enum Event { + A, + } + } + + frame_support::decl_error! { + pub enum Error for Module { + Something + } + } + + frame_support::decl_storage! { + trait Store for Module as Module {} + add_extra_genesis { + build(|_config| {}) + } + } + } +} + +pub mod module { + use super::*; + + pub trait Config: system::Config {} + + frame_support::decl_module! { + pub struct Module for enum Call + where origin: ::Origin, system=system + { + #[weight = 0] + pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { + Err(Error::::Something.into()) + } + #[weight = 0] + pub fn aux_1(_origin, #[compact] _data: u32) -> frame_support::dispatch::DispatchResult { + unreachable!() + } + #[weight = 0] + pub fn aux_2(_origin, _data: i32, #[compact] _data2: u32) -> frame_support::dispatch::DispatchResult { + unreachable!() + } + #[weight = 0] + fn aux_3(_origin, _data: i32, _data2: String) -> frame_support::dispatch::DispatchResult { + unreachable!() + } + #[weight = 3] + fn aux_4(_origin) -> frame_support::dispatch::DispatchResult { unreachable!() } + #[weight = (5, frame_support::weights::DispatchClass::Operational)] + fn operational(_origin) { unreachable!() } + } + } + + #[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo)] + pub struct Origin(pub core::marker::PhantomData); + + frame_support::decl_event! { + pub enum Event { + A, + } + } + + frame_support::decl_error! { + pub enum Error for Module { + Something + } + } + + frame_support::decl_storage! { + trait Store for Module as Module {} + add_extra_genesis { + build(|_config| {}) + } + } +} + +impl nested::module::Config for RuntimeOriginTest {} +impl module::Config for RuntimeOriginTest {} + +pub struct BaseCallFilter; +impl Contains for BaseCallFilter { + fn contains(c: &Call) -> bool { + match c { + Call::NestedModule(_) => true, + _ => false, + } + } +} + +impl system::Config for RuntimeOriginTest { + type BaseCallFilter = BaseCallFilter; + type Hash = H256; + type Origin = Origin; + type BlockNumber = BlockNumber; + type AccountId = u32; + type Event = Event; + type PalletInfo = PalletInfo; + type Call = Call; + type DbWeight = (); +} + +frame_support::construct_runtime!( + pub enum RuntimeOriginTest where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Pallet, Event, Origin}, + NestedModule: nested::module::{Pallet, Origin, Call}, + Module: module::{Pallet, Origin, Call}, + } +); + +pub type Signature = sr25519::Signature; +pub type BlockNumber = u64; +pub type Header = generic::Header; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type Block = generic::Block; + +#[test] +fn origin_default_filter() { + let accepted_call = nested::module::Call::fail {}.into(); + let rejected_call = module::Call::fail {}.into(); + + assert_eq!(Origin::root().filter_call(&accepted_call), true); + assert_eq!(Origin::root().filter_call(&rejected_call), true); + assert_eq!(Origin::none().filter_call(&accepted_call), true); + assert_eq!(Origin::none().filter_call(&rejected_call), false); + assert_eq!(Origin::signed(0).filter_call(&accepted_call), true); + assert_eq!(Origin::signed(0).filter_call(&rejected_call), false); + assert_eq!(Origin::from(Some(0)).filter_call(&accepted_call), true); + assert_eq!(Origin::from(Some(0)).filter_call(&rejected_call), false); + assert_eq!(Origin::from(None).filter_call(&accepted_call), true); + assert_eq!(Origin::from(None).filter_call(&rejected_call), false); + assert_eq!(Origin::from(nested::module::Origin).filter_call(&accepted_call), true); + assert_eq!(Origin::from(nested::module::Origin).filter_call(&rejected_call), false); + + let mut origin = Origin::from(Some(0)); + origin.add_filter(|c| matches!(c, Call::Module(_))); + assert_eq!(origin.filter_call(&accepted_call), false); + assert_eq!(origin.filter_call(&rejected_call), false); + + // Now test for root origin and filters: + let mut origin = Origin::from(Some(0)); + origin.set_caller_from(Origin::root()); + assert!(matches!(origin.caller, OriginCaller::system(system::RawOrigin::Root))); + + // Root origin bypass all filter. + assert_eq!(origin.filter_call(&accepted_call), true); + assert_eq!(origin.filter_call(&rejected_call), true); + + origin.set_caller_from(Origin::from(Some(0))); + + // Back to another signed origin, the filtered are now effective again + assert_eq!(origin.filter_call(&accepted_call), true); + assert_eq!(origin.filter_call(&rejected_call), false); + + origin.set_caller_from(Origin::root()); + origin.reset_filter(); + + // Root origin bypass all filter, even when they are reset. + assert_eq!(origin.filter_call(&accepted_call), true); + assert_eq!(origin.filter_call(&rejected_call), true); +} diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 451cb2e7b889e..83f6a722f93aa 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -20,7 +20,7 @@ use frame_support::{ storage::unhashed, traits::{ ConstU32, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, - OnRuntimeUpgrade, PalletInfoAccess, StorageVersion, + OnRuntimeUpgrade, PalletError, PalletInfoAccess, StorageVersion, }, weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, RuntimeDbWeight}, }; @@ -229,9 +229,14 @@ pub mod pallet { } #[pallet::error] + #[derive(PartialEq, Eq)] pub enum Error { /// doc comment put into metadata InsufficientProposersBalance, + Code(u8), + #[codec(skip)] + Skipped(u128), + CompactU8(#[codec(compact)] u8), } #[pallet::event] @@ -656,10 +661,11 @@ fn error_expand() { DispatchError::from(pallet::Error::::InsufficientProposersBalance), DispatchError::Module(ModuleError { index: 1, - error: 0, + error: [0, 0, 0, 0], message: Some("InsufficientProposersBalance") }), ); + assert_eq!( as PalletError>::MAX_ENCODED_SIZE, 3); } #[test] diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 30b9bcda88d1e..118794e2fa20a 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -343,7 +343,7 @@ fn error_expand() { DispatchError::from(pallet::Error::::InsufficientProposersBalance), DispatchError::Module(ModuleError { index: 1, - error: 0, + error: [0; 4], message: Some("InsufficientProposersBalance") }), ); @@ -364,7 +364,7 @@ fn error_expand() { ), DispatchError::Module(ModuleError { index: 2, - error: 0, + error: [0; 4], message: Some("InsufficientProposersBalance") }), ); diff --git a/frame/support/test/tests/pallet_ui/error_no_fieldless.rs b/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.rs similarity index 50% rename from frame/support/test/tests/pallet_ui/error_no_fieldless.rs rename to frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.rs index c9d444d6f90dd..254d65866774f 100644 --- a/frame/support/test/tests/pallet_ui/error_no_fieldless.rs +++ b/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.rs @@ -1,25 +1,19 @@ #[frame_support::pallet] mod pallet { - use frame_support::pallet_prelude::Hooks; - use frame_system::pallet_prelude::BlockNumberFor; - #[pallet::config] pub trait Config: frame_system::Config {} #[pallet::pallet] pub struct Pallet(core::marker::PhantomData); - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet {} - #[pallet::error] pub enum Error { - U8(u8), + CustomError(crate::MyError), } } +#[derive(scale_info::TypeInfo, codec::Encode, codec::Decode)] +enum MyError {} + fn main() { } diff --git a/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr b/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr new file mode 100644 index 0000000000000..2a8149e309ac1 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `MyError: PalletError` is not satisfied + --> tests/pallet_ui/error_does_not_derive_pallet_error.rs:1:1 + | +1 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PalletError` is not implemented for `MyError` + | +note: required by `MAX_ENCODED_SIZE` + --> $WORKSPACE/frame/support/src/traits/error.rs + | + | const MAX_ENCODED_SIZE: usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `frame_support::PalletError` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/pallet_ui/error_no_fieldless.stderr b/frame/support/test/tests/pallet_ui/error_no_fieldless.stderr deleted file mode 100644 index 1d69fbeff9aac..0000000000000 --- a/frame/support/test/tests/pallet_ui/error_no_fieldless.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Invalid pallet::error, unexpected fields, must be `Unit` - --> $DIR/error_no_fieldless.rs:20:5 - | -20 | U8(u8), - | ^^^^ diff --git a/frame/support/test/tests/pallet_ui/pass/error_nested_types.rs b/frame/support/test/tests/pallet_ui/pass/error_nested_types.rs new file mode 100644 index 0000000000000..1b6f584af23b9 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pass/error_nested_types.rs @@ -0,0 +1,41 @@ +use codec::{Decode, Encode}; +use frame_support::PalletError; + +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::error] + pub enum Error { + CustomError(crate::MyError), + } +} + +#[derive(Encode, Decode, PalletError, scale_info::TypeInfo)] +pub enum MyError { + Foo, + Bar, + Baz(NestedError), + Struct(MyStruct), + Wrapper(Wrapper), +} + +#[derive(Encode, Decode, PalletError, scale_info::TypeInfo)] +pub enum NestedError { + Quux +} + +#[derive(Encode, Decode, PalletError, scale_info::TypeInfo)] +pub struct MyStruct { + field: u8, +} + +#[derive(Encode, Decode, PalletError, scale_info::TypeInfo)] +pub struct Wrapper(bool); + +fn main() { +} diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 9a1e11f54d6e3..44b07f70db14c 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -38,7 +38,6 @@ use sp_runtime::{ // example module to test behaviors. #[frame_support::pallet] pub mod example { - use super::*; use frame_support::{dispatch::WithPostDispatchInfo, pallet_prelude::*}; use frame_system::pallet_prelude::*; diff --git a/primitives/block-builder/src/lib.rs b/primitives/block-builder/src/lib.rs index 229f115c6667f..1b74c27b7ae43 100644 --- a/primitives/block-builder/src/lib.rs +++ b/primitives/block-builder/src/lib.rs @@ -20,11 +20,14 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_inherents::{CheckInherentsResult, InherentData}; -use sp_runtime::{traits::Block as BlockT, ApplyExtrinsicResult}; +use sp_runtime::{ + legacy::byte_sized_error::ApplyExtrinsicResult as ApplyExtrinsicResultBeforeV6, + traits::Block as BlockT, ApplyExtrinsicResult, +}; sp_api::decl_runtime_apis! { /// The `BlockBuilder` api trait that provides the required functionality for building a block. - #[api_version(5)] + #[api_version(6)] pub trait BlockBuilder { /// Apply the given extrinsic. /// @@ -32,6 +35,9 @@ sp_api::decl_runtime_apis! { /// this block or not. fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult; + #[changed_in(6)] + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResultBeforeV6; + /// Finish the current block. #[renamed("finalise_block", 3)] fn finalize_block() -> ::Header; diff --git a/primitives/runtime/src/legacy.rs b/primitives/runtime/src/legacy.rs new file mode 100644 index 0000000000000..7bc7c88a7e10d --- /dev/null +++ b/primitives/runtime/src/legacy.rs @@ -0,0 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Runtime types that existed in old API versions. + +pub mod byte_sized_error; diff --git a/primitives/runtime/src/legacy/byte_sized_error.rs b/primitives/runtime/src/legacy/byte_sized_error.rs new file mode 100644 index 0000000000000..049abff69ff1a --- /dev/null +++ b/primitives/runtime/src/legacy/byte_sized_error.rs @@ -0,0 +1,100 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Runtime types that existed prior to BlockBuilder API version 6. + +use crate::{ArithmeticError, TokenError}; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +/// [`ModuleError`] type definition before BlockBuilder API version 6. +#[derive(Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct ModuleError { + /// Module index, matching the metadata module index. + pub index: u8, + /// Module specific error value. + pub error: u8, + /// Optional error message. + #[codec(skip)] + #[cfg_attr(feature = "std", serde(skip_deserializing))] + pub message: Option<&'static str>, +} + +impl PartialEq for ModuleError { + fn eq(&self, other: &Self) -> bool { + (self.index == other.index) && (self.error == other.error) + } +} + +/// [`DispatchError`] type definition before BlockBuilder API version 6. +#[derive(Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo, PartialEq)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum DispatchError { + /// Some error occurred. + Other( + #[codec(skip)] + #[cfg_attr(feature = "std", serde(skip_deserializing))] + &'static str, + ), + /// Failed to lookup some data. + CannotLookup, + /// A bad origin. + BadOrigin, + /// A custom error in a module. + Module(ModuleError), + /// At least one consumer is remaining so the account cannot be destroyed. + ConsumerRemaining, + /// There are no providers so the account cannot be created. + NoProviders, + /// There are too many consumers so the account cannot be created. + TooManyConsumers, + /// An error to do with tokens. + Token(TokenError), + /// An arithmetic error. + Arithmetic(ArithmeticError), +} + +/// [`DispatchOutcome`] type definition before BlockBuilder API version 6. +pub type DispatchOutcome = Result<(), DispatchError>; + +/// [`ApplyExtrinsicResult`] type definition before BlockBuilder API version 6. +pub type ApplyExtrinsicResult = + Result; + +/// Convert the legacy `ApplyExtrinsicResult` type to the latest version. +pub fn convert_to_latest(old: ApplyExtrinsicResult) -> crate::ApplyExtrinsicResult { + old.map(|outcome| { + outcome.map_err(|e| match e { + DispatchError::Other(s) => crate::DispatchError::Other(s), + DispatchError::CannotLookup => crate::DispatchError::CannotLookup, + DispatchError::BadOrigin => crate::DispatchError::BadOrigin, + DispatchError::Module(err) => crate::DispatchError::Module(crate::ModuleError { + index: err.index, + error: [err.error, 0, 0, 0], + message: err.message, + }), + DispatchError::ConsumerRemaining => crate::DispatchError::ConsumerRemaining, + DispatchError::NoProviders => crate::DispatchError::NoProviders, + DispatchError::TooManyConsumers => crate::DispatchError::TooManyConsumers, + DispatchError::Token(err) => crate::DispatchError::Token(err), + DispatchError::Arithmetic(err) => crate::DispatchError::Arithmetic(err), + }) + }) +} diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index a428da59f6a0d..337fac5812aed 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -57,6 +57,7 @@ use scale_info::TypeInfo; pub mod curve; pub mod generic; +pub mod legacy; mod multiaddress; pub mod offchain; pub mod runtime_logger; @@ -97,6 +98,10 @@ pub use sp_arithmetic::{ pub use either::Either; +/// The number of bytes of the module-specific `error` field defined in [`ModuleError`]. +/// In FRAME, this is the maximum encoded size of a pallet error type. +pub const MAX_MODULE_ERROR_ENCODED_SIZE: usize = 4; + /// An abstraction over justification for a block's validity under a consensus algorithm. /// /// Essentially a finality proof. The exact formulation will vary between consensus @@ -468,7 +473,7 @@ pub struct ModuleError { /// Module index, matching the metadata module index. pub index: u8, /// Module specific error value. - pub error: u8, + pub error: [u8; MAX_MODULE_ERROR_ENCODED_SIZE], /// Optional error message. #[codec(skip)] #[cfg_attr(feature = "std", serde(skip_deserializing))] @@ -922,15 +927,15 @@ mod tests { fn dispatch_error_encoding() { let error = DispatchError::Module(ModuleError { index: 1, - error: 2, + error: [2, 0, 0, 0], message: Some("error message"), }); let encoded = error.encode(); let decoded = DispatchError::decode(&mut &encoded[..]).unwrap(); - assert_eq!(encoded, vec![3, 1, 2]); + assert_eq!(encoded, vec![3, 1, 2, 0, 0, 0]); assert_eq!( decoded, - DispatchError::Module(ModuleError { index: 1, error: 2, message: None }) + DispatchError::Module(ModuleError { index: 1, error: [2, 0, 0, 0], message: None }) ); } @@ -943,9 +948,9 @@ mod tests { Other("bar"), CannotLookup, BadOrigin, - Module(ModuleError { index: 1, error: 1, message: None }), - Module(ModuleError { index: 1, error: 2, message: None }), - Module(ModuleError { index: 2, error: 1, message: None }), + Module(ModuleError { index: 1, error: [1, 0, 0, 0], message: None }), + Module(ModuleError { index: 1, error: [2, 0, 0, 0], message: None }), + Module(ModuleError { index: 2, error: [1, 0, 0, 0], message: None }), ConsumerRemaining, NoProviders, Token(TokenError::NoFunds), @@ -970,8 +975,8 @@ mod tests { // Ignores `message` field in `Module` variant. assert_eq!( - Module(ModuleError { index: 1, error: 1, message: Some("foo") }), - Module(ModuleError { index: 1, error: 1, message: None }), + Module(ModuleError { index: 1, error: [1, 0, 0, 0], message: Some("foo") }), + Module(ModuleError { index: 1, error: [1, 0, 0, 0], message: None }), ); } diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 1cea7c4e805c1..ba4ca790a9198 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1554,6 +1554,12 @@ impl Printable for &[u8] { } } +impl Printable for [u8; N] { + fn print(&self) { + sp_io::misc::print_hex(&self[..]); + } +} + impl Printable for &str { fn print(&self) { sp_io::misc::print_utf8(self.as_bytes()); diff --git a/utils/frame/rpc/system/src/lib.rs b/utils/frame/rpc/system/src/lib.rs index eb1b258c97ec6..0eae4d061afbb 100644 --- a/utils/frame/rpc/system/src/lib.rs +++ b/utils/frame/rpc/system/src/lib.rs @@ -25,10 +25,11 @@ use jsonrpc_core::{Error as RpcError, ErrorCode}; use jsonrpc_derive::rpc; use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; +use sp_api::ApiExt; use sp_block_builder::BlockBuilder; use sp_blockchain::HeaderBackend; use sp_core::{hexdisplay::HexDisplay, Bytes}; -use sp_runtime::{generic::BlockId, traits}; +use sp_runtime::{generic::BlockId, legacy, traits}; pub use self::gen_client::Client as SystemClient; pub use frame_system_rpc_runtime_api::AccountNonceApi; @@ -135,14 +136,40 @@ where .map_err(|e| RpcError { code: ErrorCode::ServerError(Error::DecodeError.into()), message: "Unable to dry run extrinsic.".into(), - data: Some(format!("{:?}", e).into()), + data: Some(e.to_string().into()), })?; - let result = api.apply_extrinsic(&at, uxt).map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to dry run extrinsic.".into(), - data: Some(e.to_string().into()), - })?; + let api_version = api + .api_version::>(&at) + .map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to dry run extrinsic.".into(), + data: Some(e.to_string().into()), + })? + .ok_or_else(|| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to dry run extrinsic.".into(), + data: Some( + format!("Could not find `BlockBuilder` api for block `{:?}`.", at).into(), + ), + })?; + + let result = if api_version < 6 { + #[allow(deprecated)] + api.apply_extrinsic_before_version_6(&at, uxt) + .map(legacy::byte_sized_error::convert_to_latest) + .map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to dry run extrinsic.".into(), + data: Some(e.to_string().into()), + })? + } else { + api.apply_extrinsic(&at, uxt).map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to dry run extrinsic.".into(), + data: Some(e.to_string().into()), + })? + }; Ok(Encode::encode(&result).into()) }; From 56c28e858b2c3d7a6649988bdf3f48fd2eeb6fc5 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 24 Mar 2022 09:51:55 +0100 Subject: [PATCH 0631/1472] BABE's revert procedure (#11022) * First rough draft for BABE revert * Proper babe revert test * Cleanup * Test trivial cleanup * Fix to make clippy happy * Check polkadot companion * Check cumulus companion * Remove babe's blocks weight on revert * Handle "empty" blockchain edge case * Run companions * Simplify the filter predicate * Saturating sub is not required * Run pipeline * Run pipeline again... --- bin/node-template/node/src/command.rs | 2 +- bin/node/cli/src/command.rs | 8 ++- client/cli/src/commands/revert_cmd.rs | 16 ++++- client/consensus/babe/src/lib.rs | 79 ++++++++++++++++++++- client/consensus/babe/src/tests.rs | 82 ++++++++++++++++++++++ client/consensus/epochs/src/lib.rs | 51 +++++++++++--- utils/fork-tree/src/lib.rs | 98 +++++++++++++++++++++++++-- 7 files changed, 314 insertions(+), 22 deletions(-) diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index 72c7a75b387bb..66ee9fe45a55c 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -95,7 +95,7 @@ pub fn run() -> sc_cli::Result<()> { runner.async_run(|config| { let PartialComponents { client, task_manager, backend, .. } = service::new_partial(&config)?; - Ok((cmd.run(client, backend), task_manager)) + Ok((cmd.run(client, backend, None), task_manager)) }) }, Some(Subcommand::Benchmark(cmd)) => diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index e208e324ee2aa..3c2039fde4757 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -168,7 +168,13 @@ pub fn run() -> Result<()> { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?; - Ok((cmd.run(client, backend), task_manager)) + let revert_aux = Box::new(|client, backend, blocks| { + sc_consensus_babe::revert(client, backend, blocks)?; + // TODO: grandpa revert + Ok(()) + }); + + Ok((cmd.run(client, backend, Some(revert_aux)), task_manager)) }) }, #[cfg(feature = "try-runtime")] diff --git a/client/cli/src/commands/revert_cmd.rs b/client/cli/src/commands/revert_cmd.rs index c207d198d5a27..f65e348b37b89 100644 --- a/client/cli/src/commands/revert_cmd.rs +++ b/client/cli/src/commands/revert_cmd.rs @@ -24,7 +24,7 @@ use crate::{ use clap::Parser; use sc_client_api::{Backend, UsageProvider}; use sc_service::chain_ops::revert_chain; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use std::{fmt::Debug, str::FromStr, sync::Arc}; /// The `revert` command used revert the chain to a previous state. @@ -43,9 +43,18 @@ pub struct RevertCmd { pub pruning_params: PruningParams, } +/// Revert handler for auxiliary data (e.g. consensus). +type AuxRevertHandler = + Box, Arc, NumberFor) -> error::Result<()>>; + impl RevertCmd { /// Run the revert command - pub async fn run(&self, client: Arc, backend: Arc) -> error::Result<()> + pub async fn run( + &self, + client: Arc, + backend: Arc, + aux_revert: Option>, + ) -> error::Result<()> where B: BlockT, BA: Backend, @@ -53,6 +62,9 @@ impl RevertCmd { <<::Header as HeaderT>::Number as FromStr>::Err: Debug, { let blocks = self.num.parse()?; + if let Some(aux_revert) = aux_revert { + aux_revert(client.clone(), backend.clone(), blocks)?; + } revert_chain(client, backend, blocks)?; Ok(()) diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 442dbab77e120..4f3139a013d4b 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -92,8 +92,8 @@ use retain_mut::RetainMut; use schnorrkel::SignatureError; use sc_client_api::{ - backend::AuxStore, AuxDataOperations, BlockchainEvents, FinalityNotification, PreCommitActions, - ProvideUncles, UsageProvider, + backend::AuxStore, AuxDataOperations, Backend as BackendT, BlockchainEvents, + FinalityNotification, PreCommitActions, ProvideUncles, UsageProvider, }; use sc_consensus::{ block_import::{ @@ -113,7 +113,9 @@ use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_TRACE} use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_application_crypto::AppKey; use sp_block_builder::BlockBuilder as BlockBuilderApi; -use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult}; +use sp_blockchain::{ + Backend as _, Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult, +}; use sp_consensus::{ BlockOrigin, CacheKeyId, CanAuthorWith, Environment, Error as ConsensusError, Proposer, SelectChain, @@ -1830,3 +1832,74 @@ where Ok(BasicQueue::new(verifier, Box::new(block_import), justification_import, spawner, registry)) } + +/// Reverts aux data. +pub fn revert( + client: Arc, + backend: Arc, + blocks: NumberFor, +) -> ClientResult<()> +where + Block: BlockT, + Client: AuxStore + + HeaderMetadata + + HeaderBackend + + ProvideRuntimeApi + + UsageProvider, + Client::Api: BabeApi, + Backend: BackendT, +{ + let best_number = client.info().best_number; + let finalized = client.info().finalized_number; + let revertible = blocks.min(best_number - finalized); + + let number = best_number - revertible; + let hash = client + .block_hash_from_id(&BlockId::Number(number))? + .ok_or(ClientError::Backend(format!( + "Unexpected hash lookup failure for block number: {}", + number + )))?; + + // Revert epoch changes tree. + + let config = Config::get(&*client)?; + let epoch_changes = + aux_schema::load_epoch_changes::(&*client, config.genesis_config())?; + let mut epoch_changes = epoch_changes.shared_data(); + + if number == Zero::zero() { + // Special case, no epoch changes data were present on genesis. + *epoch_changes = EpochChangesFor::::default(); + } else { + epoch_changes.revert(descendent_query(&*client), hash, number); + } + + // Remove block weights added after the revert point. + + let mut weight_keys = HashSet::with_capacity(revertible.saturated_into()); + let leaves = backend.blockchain().leaves()?.into_iter().filter(|&leaf| { + sp_blockchain::tree_route(&*client, hash, leaf) + .map(|route| route.retracted().is_empty()) + .unwrap_or_default() + }); + for leaf in leaves { + let mut hash = leaf; + // Insert parent after parent until we don't hit an already processed + // branch or we reach a direct child of the rollback point. + while weight_keys.insert(aux_schema::block_weight_key(hash)) { + let meta = client.header_metadata(hash)?; + if meta.number <= number + One::one() { + // We've reached a child of the revert point, stop here. + break + } + hash = client.header_metadata(hash)?.parent; + } + } + let weight_keys: Vec<_> = weight_keys.iter().map(|val| val.as_slice()).collect(); + + // Write epoch changes and remove weights in one shot. + aux_schema::write_epoch_changes::(&epoch_changes, |values| { + client.insert_aux(values, weight_keys.iter()) + }) +} diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index d2de05bc91952..080387c88655c 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -735,6 +735,88 @@ fn importing_block_one_sets_genesis_epoch() { assert_eq!(epoch_for_second_block, genesis_epoch); } +#[test] +fn revert_prunes_epoch_changes_and_removes_weights() { + let mut net = BabeTestNet::new(1); + + let peer = net.peer(0); + let data = peer.data.as_ref().expect("babe link set up during initialization"); + + let client = peer.client().as_client(); + let backend = peer.client().as_backend(); + let mut block_import = data.block_import.lock().take().expect("import set up during init"); + let epoch_changes = data.link.epoch_changes.clone(); + + let mut proposer_factory = DummyFactory { + client: client.clone(), + config: data.link.config.clone(), + epoch_changes: data.link.epoch_changes.clone(), + mutator: Arc::new(|_, _| ()), + }; + + let mut propose_and_import_blocks_wrap = |parent_id, n| { + propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, parent_id, n) + }; + + // Test scenario. + // Information for epoch 19 is produced on three different forks at block #13. + // One branch starts before the revert point (epoch data should be maintained). + // One branch starts after the revert point (epoch data should be removed). + // + // *----------------- F(#13) --#18 < fork #2 + // / + // A(#1) ---- B(#7) ----#8----+-----#12----- C(#13) ---- D(#19) ------#21 < canon + // \ ^ \ + // \ revert *---- G(#13) ---- H(#19) ---#20 < fork #3 + // \ to #10 + // *-----E(#7)---#11 < fork #1 + let canon = propose_and_import_blocks_wrap(BlockId::Number(0), 21); + let fork1 = propose_and_import_blocks_wrap(BlockId::Hash(canon[0]), 10); + let fork2 = propose_and_import_blocks_wrap(BlockId::Hash(canon[7]), 10); + let fork3 = propose_and_import_blocks_wrap(BlockId::Hash(canon[11]), 8); + + // We should be tracking a total of 9 epochs in the fork tree + assert_eq!(epoch_changes.shared_data().tree().iter().count(), 8); + // And only one root + assert_eq!(epoch_changes.shared_data().tree().roots().count(), 1); + + // Revert canon chain to block #10 (best(21) - 11) + revert(client.clone(), backend, 11).expect("revert should work for baked test scenario"); + + // Load and check epoch changes. + + let actual_nodes = aux_schema::load_epoch_changes::( + &*client, + data.link.config.genesis_config(), + ) + .expect("load epoch changes") + .shared_data() + .tree() + .iter() + .map(|(h, _, _)| *h) + .collect::>(); + + let expected_nodes = vec![ + canon[0], // A + canon[6], // B + fork2[4], // F + fork1[5], // E + ]; + + assert_eq!(actual_nodes, expected_nodes); + + let weight_data_check = |hashes: &[Hash], expected: bool| { + hashes.iter().all(|hash| { + aux_schema::load_block_weight(&*client, hash).unwrap().is_some() == expected + }) + }; + assert!(weight_data_check(&canon[..10], true)); + assert!(weight_data_check(&canon[10..], false)); + assert!(weight_data_check(&fork1, true)); + assert!(weight_data_check(&fork2, true)); + assert!(weight_data_check(&fork3, false)); +} + #[test] fn importing_epoch_change_block_prunes_tree() { let mut net = BabeTestNet::new(1); diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index b380d8ed54904..90081bf9af442 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -21,7 +21,7 @@ pub mod migration; use codec::{Decode, Encode}; -use fork_tree::ForkTree; +use fork_tree::{FilterAction, ForkTree}; use sc_client_api::utils::is_descendent_of; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; use sp_runtime::traits::{Block as BlockT, NumberFor, One, Zero}; @@ -660,15 +660,6 @@ where parent_number: Number, slot: E::Slot, ) -> Result>, fork_tree::Error> { - // find_node_where will give you the node in the fork-tree which is an ancestor - // of the `parent_hash` by default. if the last epoch was signalled at the parent_hash, - // then it won't be returned. we need to create a new fake chain head hash which - // "descends" from our parent-hash. - let fake_head_hash = fake_head_hash(parent_hash); - - let is_descendent_of = - descendent_of_builder.build_is_descendent_of(Some((fake_head_hash, *parent_hash))); - if parent_number == Zero::zero() { // need to insert the genesis epoch. return Ok(Some(ViableEpochDescriptor::UnimportedGenesis(slot))) @@ -683,6 +674,15 @@ where } } + // find_node_where will give you the node in the fork-tree which is an ancestor + // of the `parent_hash` by default. if the last epoch was signalled at the parent_hash, + // then it won't be returned. we need to create a new fake chain head hash which + // "descends" from our parent-hash. + let fake_head_hash = fake_head_hash(parent_hash); + + let is_descendent_of = + descendent_of_builder.build_is_descendent_of(Some((fake_head_hash, *parent_hash))); + // We want to find the deepest node in the tree which is an ancestor // of our block and where the start slot of the epoch was before the // slot of our block. The genesis special-case doesn't need to look @@ -798,6 +798,37 @@ where }); self.epochs.insert((hash, number), persisted); } + + /// Revert to a specified block given its `hash` and `number`. + /// This removes all the epoch changes information that were announced by + /// all the given block descendents. + pub fn revert>( + &mut self, + descendent_of_builder: D, + hash: Hash, + number: Number, + ) { + let is_descendent_of = descendent_of_builder.build_is_descendent_of(None); + + let filter = |node_hash: &Hash, node_num: &Number, _: &PersistedEpochHeader| { + if number >= *node_num && + (is_descendent_of(node_hash, &hash).unwrap_or_default() || *node_hash == hash) + { + // Continue the search in this subtree. + FilterAction::KeepNode + } else if number < *node_num && is_descendent_of(&hash, node_hash).unwrap_or_default() { + // Found a node to be removed. + FilterAction::Remove + } else { + // Not a parent or child of the one we're looking for, stop processing this branch. + FilterAction::KeepTree + } + }; + + self.inner.drain_filter(filter).for_each(|(h, n, _)| { + self.epochs.remove(&(h, n)); + }); + } } /// Type alias to produce the epoch-changes tree from a block type. diff --git a/utils/fork-tree/src/lib.rs b/utils/fork-tree/src/lib.rs index a718ff26213e4..1d9b39f7dc04b 100644 --- a/utils/fork-tree/src/lib.rs +++ b/utils/fork-tree/src/lib.rs @@ -69,6 +69,17 @@ pub enum FinalizationResult { Unchanged, } +/// Filtering action. +#[derive(Debug, PartialEq)] +pub enum FilterAction { + /// Remove the node and its subtree. + Remove, + /// Maintain the node. + KeepNode, + /// Maintain the node and its subtree. + KeepTree, +} + /// A tree data structure that stores several nodes across multiple branches. /// Top-level branches are called roots. The tree has functionality for /// finalizing nodes, which means that that node is traversed, and all competing @@ -624,6 +635,29 @@ where (None, false) => Ok(FinalizationResult::Unchanged), } } + + /// Remove from the tree some nodes (and their subtrees) using a `filter` predicate. + /// The `filter` is called over tree nodes and returns a filter action: + /// - `Remove` if the node and its subtree should be removed; + /// - `KeepNode` if we should maintain the node and keep processing the tree. + /// - `KeepTree` if we should maintain the node and its entire subtree. + /// An iterator over all the pruned nodes is returned. + pub fn drain_filter(&mut self, mut filter: F) -> impl Iterator + where + F: FnMut(&H, &N, &V) -> FilterAction, + { + let mut removed = Vec::new(); + let mut i = 0; + while i < self.roots.len() { + if self.roots[i].drain_filter(&mut filter, &mut removed) { + removed.push(self.roots.remove(i)); + } else { + i += 1; + } + } + self.rebalance(); + RemovedIterator { stack: removed } + } } // Workaround for: https://github.com/rust-lang/rust/issues/34537 @@ -849,6 +883,34 @@ mod node_implementation { }, } } + + /// Calls a `filter` predicate for the given node. + /// The `filter` is called over tree nodes and returns a filter action: + /// - `Remove` if the node and its subtree should be removed; + /// - `KeepNode` if we should maintain the node and keep processing the tree; + /// - `KeepTree` if we should maintain the node and its entire subtree. + /// Pruned subtrees are added to the `removed` list. + /// Returns a booleans indicateing if this node (and its subtree) should be removed. + pub fn drain_filter(&mut self, filter: &mut F, removed: &mut Vec>) -> bool + where + F: FnMut(&H, &N, &V) -> FilterAction, + { + match filter(&self.hash, &self.number, &self.data) { + FilterAction::KeepNode => { + let mut i = 0; + while i < self.children.len() { + if self.children[i].drain_filter(filter, removed) { + removed.push(self.children.remove(i)); + } else { + i += 1; + } + } + false + }, + FilterAction::KeepTree => false, + FilterAction::Remove => true, + } + } } } @@ -895,6 +957,8 @@ impl Iterator for RemovedIterator { #[cfg(test)] mod test { + use crate::FilterAction; + use super::{Error, FinalizationResult, ForkTree}; #[derive(Debug, PartialEq)] @@ -919,11 +983,11 @@ mod test { // / - G // / / // A - F - H - I - // \ - // - L - M \ - // - O - // \ - // — J - K + // \ \ + // \ - L - M + // \ \ + // \ - O + // - J - K // // (where N is not a part of fork tree) // @@ -1458,4 +1522,28 @@ mod test { ["A", "F", "H", "L", "O", "P", "M", "I", "G", "B", "C", "D", "E", "J", "K"] ); } + + #[test] + fn tree_drain_filter() { + let (mut tree, _) = test_fork_tree(); + + let filter = |h: &&str, _: &u64, _: &()| match *h { + "A" | "B" | "F" | "G" => FilterAction::KeepNode, + "C" => FilterAction::KeepTree, + "H" | "J" => FilterAction::Remove, + _ => panic!("Unexpected filtering for node: {}", *h), + }; + + let removed = tree.drain_filter(filter); + + assert_eq!( + tree.iter().map(|(h, _, _)| *h).collect::>(), + ["A", "B", "C", "D", "E", "F", "G"] + ); + + assert_eq!( + removed.map(|(h, _, _)| h).collect::>(), + ["J", "K", "H", "L", "M", "O", "I"] + ); + } } From dfb2a8cc35244a688e0b052eafb96c6e534ca5a4 Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 24 Mar 2022 22:19:17 +0900 Subject: [PATCH 0632/1472] Add extra WASM heap pages when precompiling the runtime blob (#11107) * Add extra WASM heap pages when precompiling the runtime blob * Fix compilation * Fix rustdoc * Fix rustdoc for real this time * Fix benches compilation * Improve the builder in `sc-executor-wasmtime`'s tests --- client/executor/benches/bench.rs | 2 +- client/executor/src/wasm_runtime.rs | 2 +- client/executor/wasmtime/src/runtime.rs | 47 ++++----- client/executor/wasmtime/src/tests.rs | 124 ++++++++++++++---------- 4 files changed, 100 insertions(+), 75 deletions(-) diff --git a/client/executor/benches/bench.rs b/client/executor/benches/bench.rs index 20632536571b2..49ea8be50624e 100644 --- a/client/executor/benches/bench.rs +++ b/client/executor/benches/bench.rs @@ -55,11 +55,11 @@ fn initialize(runtime: &[u8], method: Method) -> Arc { sc_executor_wasmtime::create_runtime::( blob, sc_executor_wasmtime::Config { - heap_pages, max_memory_size: None, allow_missing_func_imports, cache_path: None, semantics: sc_executor_wasmtime::Semantics { + extra_heap_pages: heap_pages, fast_instance_reuse, deterministic_stack_limit: None, canonicalize_nans: false, diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index d996d7b490e88..952130e980874 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -317,11 +317,11 @@ where WasmExecutionMethod::Compiled => sc_executor_wasmtime::create_runtime::( blob, sc_executor_wasmtime::Config { - heap_pages, max_memory_size: None, allow_missing_func_imports, cache_path: cache_path.map(ToOwned::to_owned), semantics: sc_executor_wasmtime::Semantics { + extra_heap_pages: heap_pages, fast_instance_reuse: true, deterministic_stack_limit: None, canonicalize_nans: false, diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index acf54e04e07fd..cbe1359d28a6c 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -414,20 +414,22 @@ pub struct Semantics { /// Configures wasmtime to use multiple threads for compiling. pub parallel_compilation: bool, + + /// The number of extra WASM pages which will be allocated + /// on top of what is requested by the WASM blob itself. + pub extra_heap_pages: u64, } pub struct Config { - /// The number of wasm pages to be mounted after instantiation. - pub heap_pages: u64, - /// The total amount of memory in bytes an instance can request. /// /// If specified, the runtime will be able to allocate only that much of wasm memory. - /// This is the total number and therefore the [`Config::heap_pages`] is accounted for. + /// This is the total number and therefore the [`Semantics::extra_heap_pages`] is accounted + /// for. /// /// That means that the initial number of pages of a linear memory plus the - /// [`Config::heap_pages`] multiplied by the wasm page size (64KiB) should be less than or - /// equal to `max_memory_size`, otherwise the instance won't be created. + /// [`Semantics::extra_heap_pages`] multiplied by the wasm page size (64KiB) should be less + /// than or equal to `max_memory_size`, otherwise the instance won't be created. /// /// Moreover, `memory.grow` will fail (return -1) if the sum of sizes of currently mounted /// and additional pages exceeds `max_memory_size`. @@ -534,21 +536,7 @@ where let (module, snapshot_data) = match code_supply_mode { CodeSupplyMode::Verbatim { blob } => { - let mut blob = instrument(blob, &config.semantics)?; - - // We don't actually need the memory to be imported so we can just convert any memory - // import into an export with impunity. This simplifies our code since `wasmtime` will - // now automatically take care of creating the memory for us, and it also allows us - // to potentially enable `wasmtime`'s instance pooling at a later date. (Imported - // memories are ineligible for pooling.) - blob.convert_memory_import_into_export()?; - blob.add_extra_heap_pages_to_memory_section( - config - .heap_pages - .try_into() - .map_err(|e| WasmError::Other(format!("invalid `heap_pages`: {}", e)))?, - )?; - + let blob = prepare_blob_for_compilation(blob, &config.semantics)?; let serialized_blob = blob.clone().serialize(); let module = wasmtime::Module::new(&engine, &serialized_blob) @@ -587,7 +575,7 @@ where Ok(WasmtimeRuntime { engine, instance_pre: Arc::new(instance_pre), snapshot_data, config }) } -fn instrument( +fn prepare_blob_for_compilation( mut blob: RuntimeBlob, semantics: &Semantics, ) -> std::result::Result { @@ -600,6 +588,19 @@ fn instrument( blob.expose_mutable_globals(); } + // We don't actually need the memory to be imported so we can just convert any memory + // import into an export with impunity. This simplifies our code since `wasmtime` will + // now automatically take care of creating the memory for us, and it also allows us + // to potentially enable `wasmtime`'s instance pooling at a later date. (Imported + // memories are ineligible for pooling.) + blob.convert_memory_import_into_export()?; + blob.add_extra_heap_pages_to_memory_section( + semantics + .extra_heap_pages + .try_into() + .map_err(|e| WasmError::Other(format!("invalid `extra_heap_pages`: {}", e)))?, + )?; + Ok(blob) } @@ -609,7 +610,7 @@ pub fn prepare_runtime_artifact( blob: RuntimeBlob, semantics: &Semantics, ) -> std::result::Result, WasmError> { - let blob = instrument(blob, semantics)?; + let blob = prepare_blob_for_compilation(blob, semantics)?; let engine = Engine::new(&common_config(semantics)?) .map_err(|e| WasmError::Other(format!("cannot create the engine: {}", e)))?; diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index a4ca0959da869..d5b92f2f24a76 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -28,8 +28,9 @@ struct RuntimeBuilder { fast_instance_reuse: bool, canonicalize_nans: bool, deterministic_stack: bool, - heap_pages: u64, + extra_heap_pages: u64, max_memory_size: Option, + precompile_runtime: bool, } impl RuntimeBuilder { @@ -41,34 +42,44 @@ impl RuntimeBuilder { fast_instance_reuse: false, canonicalize_nans: false, deterministic_stack: false, - heap_pages: 1024, + extra_heap_pages: 1024, max_memory_size: None, + precompile_runtime: false, } } - fn use_wat(&mut self, code: String) { + fn use_wat(&mut self, code: String) -> &mut Self { self.code = Some(code); + self } - fn canonicalize_nans(&mut self, canonicalize_nans: bool) { + fn canonicalize_nans(&mut self, canonicalize_nans: bool) -> &mut Self { self.canonicalize_nans = canonicalize_nans; + self } - fn deterministic_stack(&mut self, deterministic_stack: bool) { + fn deterministic_stack(&mut self, deterministic_stack: bool) -> &mut Self { self.deterministic_stack = deterministic_stack; + self } - fn max_memory_size(&mut self, max_memory_size: Option) { + fn precompile_runtime(&mut self, precompile_runtime: bool) -> &mut Self { + self.precompile_runtime = precompile_runtime; + self + } + + fn max_memory_size(&mut self, max_memory_size: Option) -> &mut Self { self.max_memory_size = max_memory_size; + self } - fn build(self) -> Arc { + fn build(&mut self) -> Arc { let blob = { let wasm: Vec; let wasm = match self.code { None => wasm_binary_unwrap(), - Some(wat) => { + Some(ref wat) => { wasm = wat::parse_str(wat).expect("wat parsing failed"); &wasm }, @@ -78,27 +89,31 @@ impl RuntimeBuilder { .expect("failed to create a runtime blob out of test runtime") }; - let rt = crate::create_runtime::( - blob, - crate::Config { - heap_pages: self.heap_pages, - max_memory_size: self.max_memory_size, - allow_missing_func_imports: true, - cache_path: None, - semantics: crate::Semantics { - fast_instance_reuse: self.fast_instance_reuse, - deterministic_stack_limit: match self.deterministic_stack { - true => Some(crate::DeterministicStackLimit { - logical_max: 65536, - native_stack_max: 256 * 1024 * 1024, - }), - false => None, - }, - canonicalize_nans: self.canonicalize_nans, - parallel_compilation: true, + let config = crate::Config { + max_memory_size: self.max_memory_size, + allow_missing_func_imports: true, + cache_path: None, + semantics: crate::Semantics { + fast_instance_reuse: self.fast_instance_reuse, + deterministic_stack_limit: match self.deterministic_stack { + true => Some(crate::DeterministicStackLimit { + logical_max: 65536, + native_stack_max: 256 * 1024 * 1024, + }), + false => None, }, + canonicalize_nans: self.canonicalize_nans, + parallel_compilation: true, + extra_heap_pages: self.extra_heap_pages, }, - ) + }; + + let rt = if self.precompile_runtime { + let artifact = crate::prepare_runtime_artifact(blob, &config.semantics).unwrap(); + unsafe { crate::create_runtime_from_artifact::(&artifact, config) } + } else { + crate::create_runtime::(blob, config) + } .expect("cannot create runtime"); Arc::new(rt) as Arc @@ -107,11 +122,7 @@ impl RuntimeBuilder { #[test] fn test_nan_canonicalization() { - let runtime = { - let mut builder = RuntimeBuilder::new_on_demand(); - builder.canonicalize_nans(true); - builder.build() - }; + let runtime = RuntimeBuilder::new_on_demand().canonicalize_nans(true).build(); let mut instance = runtime.new_instance().expect("failed to instantiate a runtime"); @@ -150,12 +161,10 @@ fn test_nan_canonicalization() { fn test_stack_depth_reaching() { const TEST_GUARD_PAGE_SKIP: &str = include_str!("test-guard-page-skip.wat"); - let runtime = { - let mut builder = RuntimeBuilder::new_on_demand(); - builder.use_wat(TEST_GUARD_PAGE_SKIP.to_string()); - builder.deterministic_stack(true); - builder.build() - }; + let runtime = RuntimeBuilder::new_on_demand() + .use_wat(TEST_GUARD_PAGE_SKIP.to_string()) + .deterministic_stack(true) + .build(); let mut instance = runtime.new_instance().expect("failed to instantiate a runtime"); match instance.call_export("test-many-locals", &[]).unwrap_err() { @@ -168,26 +177,36 @@ fn test_stack_depth_reaching() { } #[test] -fn test_max_memory_pages_imported_memory() { - test_max_memory_pages(true); +fn test_max_memory_pages_imported_memory_without_precompilation() { + test_max_memory_pages(true, false); +} + +#[test] +fn test_max_memory_pages_exported_memory_without_precompilation() { + test_max_memory_pages(false, false); } #[test] -fn test_max_memory_pages_exported_memory() { - test_max_memory_pages(false); +fn test_max_memory_pages_imported_memory_with_precompilation() { + test_max_memory_pages(true, true); } -fn test_max_memory_pages(import_memory: bool) { +#[test] +fn test_max_memory_pages_exported_memory_with_precompilation() { + test_max_memory_pages(false, true); +} + +fn test_max_memory_pages(import_memory: bool, precompile_runtime: bool) { fn try_instantiate( max_memory_size: Option, wat: String, + precompile_runtime: bool, ) -> Result<(), Box> { - let runtime = { - let mut builder = RuntimeBuilder::new_on_demand(); - builder.use_wat(wat); - builder.max_memory_size(max_memory_size); - builder.build() - }; + let runtime = RuntimeBuilder::new_on_demand() + .use_wat(wat) + .max_memory_size(max_memory_size) + .precompile_runtime(precompile_runtime) + .build(); let mut instance = runtime.new_instance()?; let _ = instance.call_export("main", &[])?; Ok(()) @@ -235,6 +254,7 @@ fn test_max_memory_pages(import_memory: bool) { */ memory(64511, None, import_memory) ), + precompile_runtime, ) .unwrap(); @@ -257,6 +277,7 @@ fn test_max_memory_pages(import_memory: bool) { // 1 initial, max is not specified. memory(1, None, import_memory) ), + precompile_runtime, ) .unwrap(); @@ -277,6 +298,7 @@ fn test_max_memory_pages(import_memory: bool) { // Max is 2048. memory(1, Some(2048), import_memory) ), + precompile_runtime, ) .unwrap(); @@ -309,6 +331,7 @@ fn test_max_memory_pages(import_memory: bool) { // Zero starting pages. memory(0, None, import_memory) ), + precompile_runtime, ) .unwrap(); @@ -341,6 +364,7 @@ fn test_max_memory_pages(import_memory: bool) { // Initial=1, meaning after heap pages mount the total will be already 1025. memory(1, None, import_memory) ), + precompile_runtime, ) .unwrap(); } @@ -353,7 +377,6 @@ fn test_instances_without_reuse_are_not_leaked() { let runtime = crate::create_runtime::( RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), crate::Config { - heap_pages: 2048, max_memory_size: None, allow_missing_func_imports: true, cache_path: None, @@ -362,6 +385,7 @@ fn test_instances_without_reuse_are_not_leaked() { deterministic_stack_limit: None, canonicalize_nans: false, parallel_compilation: true, + extra_heap_pages: 2048, }, }, ) From 666f39b8a22108f57732215de006518738034ba2 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Fri, 25 Mar 2022 00:36:58 +0800 Subject: [PATCH 0633/1472] pallet-referenda: make the pallet instanceable (#11089) Signed-off-by: koushiro --- frame/referenda/src/branch.rs | 14 +- frame/referenda/src/lib.rs | 244 ++++++++++++++++++---------------- frame/referenda/src/types.rs | 43 +++--- 3 files changed, 160 insertions(+), 141 deletions(-) diff --git a/frame/referenda/src/branch.rs b/frame/referenda/src/branch.rs index 6a4efa31e15e2..f381f5fe5b709 100644 --- a/frame/referenda/src/branch.rs +++ b/frame/referenda/src/branch.rs @@ -59,7 +59,7 @@ impl From for ServiceBranch { impl ServiceBranch { /// Return the weight of the `nudge` function when it takes the branch denoted by `self`. - pub fn weight_of_nudge(self) -> frame_support::weights::Weight { + pub fn weight_of_nudge, I: 'static>(self) -> frame_support::weights::Weight { use ServiceBranch::*; match self { NoDeposit => T::WeightInfo::nudge_referendum_no_deposit(), @@ -81,7 +81,7 @@ impl ServiceBranch { } /// Return the maximum possible weight of the `nudge` function. - pub fn max_weight_of_nudge() -> frame_support::weights::Weight { + pub fn max_weight_of_nudge, I: 'static>() -> frame_support::weights::Weight { 0.max(T::WeightInfo::nudge_referendum_no_deposit()) .max(T::WeightInfo::nudge_referendum_preparing()) .max(T::WeightInfo::nudge_referendum_queued()) @@ -101,7 +101,9 @@ impl ServiceBranch { /// Return the weight of the `place_decision_deposit` function when it takes the branch denoted /// by `self`. - pub fn weight_of_deposit(self) -> Option { + pub fn weight_of_deposit, I: 'static>( + self, + ) -> Option { use ServiceBranch::*; Some(match self { Preparing => T::WeightInfo::place_decision_deposit_preparing(), @@ -124,7 +126,7 @@ impl ServiceBranch { } /// Return the maximum possible weight of the `place_decision_deposit` function. - pub fn max_weight_of_deposit() -> frame_support::weights::Weight { + pub fn max_weight_of_deposit, I: 'static>() -> frame_support::weights::Weight { 0.max(T::WeightInfo::place_decision_deposit_preparing()) .max(T::WeightInfo::place_decision_deposit_queued()) .max(T::WeightInfo::place_decision_deposit_not_queued()) @@ -154,7 +156,7 @@ impl From for OneFewerDecidingBranch { impl OneFewerDecidingBranch { /// Return the weight of the `one_fewer_deciding` function when it takes the branch denoted /// by `self`. - pub fn weight(self) -> frame_support::weights::Weight { + pub fn weight, I: 'static>(self) -> frame_support::weights::Weight { use OneFewerDecidingBranch::*; match self { QueueEmpty => T::WeightInfo::one_fewer_deciding_queue_empty(), @@ -164,7 +166,7 @@ impl OneFewerDecidingBranch { } /// Return the maximum possible weight of the `one_fewer_deciding` function. - pub fn max_weight() -> frame_support::weights::Weight { + pub fn max_weight, I: 'static>() -> frame_support::weights::Weight { 0.max(T::WeightInfo::one_fewer_deciding_queue_empty()) .max(T::WeightInfo::one_fewer_deciding_passing()) .max(T::WeightInfo::one_fewer_deciding_failing()) diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index fb19d2b9ed248..067775fd336d0 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -83,15 +83,18 @@ use sp_std::{fmt::Debug, prelude::*}; mod branch; mod types; pub mod weights; -use branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch}; -pub use pallet::*; -pub use types::{ - BalanceOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted, - NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, ReferendumInfoOf, - ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, TrackIdOf, TrackInfo, - TrackInfoOf, TracksInfo, VotesOf, + +use self::branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch}; +pub use self::{ + pallet::*, + types::{ + BalanceOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted, + NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, ReferendumInfoOf, + ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, TrackIdOf, TrackInfo, + TrackInfoOf, TracksInfo, VotesOf, + }, + weights::WeightInfo, }; -pub use weights::WeightInfo; #[cfg(test)] mod mock; @@ -106,25 +109,33 @@ const ASSEMBLY_ID: LockIdentifier = *b"assembly"; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, traits::EnsureOrigin, Parameter}; + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - use sp_runtime::DispatchResult; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] - pub struct Pallet(_); + pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + Sized { + pub trait Config: frame_system::Config + Sized { // System level stuff. - type Call: Parameter + Dispatchable + From>; - type Event: From> + IsType<::Event>; + type Call: Parameter + Dispatchable + From>; + type Event: From> + IsType<::Event>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// The Scheduler. - type Scheduler: ScheduleAnon, PalletsOriginOf, Hash = Self::Hash> - + ScheduleNamed, PalletsOriginOf, Hash = Self::Hash>; + type Scheduler: ScheduleAnon< + Self::BlockNumber, + CallOf, + PalletsOriginOf, + Hash = Self::Hash, + > + ScheduleNamed< + Self::BlockNumber, + CallOf, + PalletsOriginOf, + Hash = Self::Hash, + >; /// Currency type for this pallet. type Currency: ReservableCurrency; // Origins and unbalances. @@ -133,7 +144,7 @@ pub mod pallet { /// Origin from which any vote may be killed. type KillOrigin: EnsureOrigin; /// Handler for the unbalanced reduction when slashing a preimage deposit. - type Slash: OnUnbalanced>; + type Slash: OnUnbalanced>; /// The counting type for votes. Usually just balance. type Votes: AtLeast32BitUnsigned + Copy + Parameter + Member; /// The tallying type. @@ -142,7 +153,7 @@ pub mod pallet { // Constants /// The minimum amount to be used as a deposit for a public referendum proposal. #[pallet::constant] - type SubmissionDeposit: Get>; + type SubmissionDeposit: Get>; /// Maximum size of the referendum queue for a single track. #[pallet::constant] @@ -162,7 +173,7 @@ pub mod pallet { // The other stuff. /// Information concerning the different referendum tracks. type Tracks: TracksInfo< - BalanceOf, + BalanceOf, Self::BlockNumber, Origin = ::PalletsOrigin, >; @@ -170,39 +181,40 @@ pub mod pallet { /// The next free referendum index, aka the number of referenda started so far. #[pallet::storage] - pub type ReferendumCount = StorageValue<_, ReferendumIndex, ValueQuery>; + pub type ReferendumCount = StorageValue<_, ReferendumIndex, ValueQuery>; /// Information concerning any given referendum. #[pallet::storage] - pub type ReferendumInfoFor = - StorageMap<_, Blake2_128Concat, ReferendumIndex, ReferendumInfoOf>; + pub type ReferendumInfoFor, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, ReferendumIndex, ReferendumInfoOf>; /// The sorted list of referenda ready to be decided but not yet being decided, ordered by /// conviction-weighted approvals. /// /// This should be empty if `DecidingCount` is less than `TrackInfo::max_deciding`. #[pallet::storage] - pub type TrackQueue = StorageMap< + pub type TrackQueue, I: 'static = ()> = StorageMap< _, Twox64Concat, - TrackIdOf, + TrackIdOf, BoundedVec<(ReferendumIndex, T::Votes), T::MaxQueued>, ValueQuery, >; /// The number of referenda being decided currently. #[pallet::storage] - pub type DecidingCount = StorageMap<_, Twox64Concat, TrackIdOf, u32, ValueQuery>; + pub type DecidingCount, I: 'static = ()> = + StorageMap<_, Twox64Concat, TrackIdOf, u32, ValueQuery>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { + pub enum Event, I: 'static = ()> { /// A referendum has being submitted. Submitted { /// Index of the referendum. index: ReferendumIndex, /// The track (and by extension proposal dispatch origin) of this referendum. - track: TrackIdOf, + track: TrackIdOf, /// The hash of the proposal up for referendum. proposal_hash: T::Hash, }, @@ -213,7 +225,7 @@ pub mod pallet { /// The account who placed the deposit. who: T::AccountId, /// The amount placed by the account. - amount: BalanceOf, + amount: BalanceOf, }, /// The decision deposit has been refunded. DecisionDepositRefunded { @@ -222,21 +234,21 @@ pub mod pallet { /// The account who placed the deposit. who: T::AccountId, /// The amount placed by the account. - amount: BalanceOf, + amount: BalanceOf, }, /// A deposit has been slashaed. DepositSlashed { /// The account who placed the deposit. who: T::AccountId, /// The amount placed by the account. - amount: BalanceOf, + amount: BalanceOf, }, /// A referendum has moved into the deciding phase. DecisionStarted { /// Index of the referendum. index: ReferendumIndex, /// The track (and by extension proposal dispatch origin) of this referendum. - track: TrackIdOf, + track: TrackIdOf, /// The hash of the proposal up for referendum. proposal_hash: T::Hash, /// The current tally of votes in this referendum. @@ -293,7 +305,7 @@ pub mod pallet { } #[pallet::error] - pub enum Error { + pub enum Error { /// Referendum is not ongoing. NotOngoing, /// Referendum's decision deposit is already paid. @@ -319,7 +331,7 @@ pub mod pallet { } #[pallet::call] - impl Pallet { + impl, I: 'static> Pallet { /// Propose a referendum on a privileged action. /// /// - `origin`: must be `Signed` and the account must have `SubmissionDeposit` funds @@ -338,9 +350,10 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; - let track = T::Tracks::track_for(&proposal_origin).map_err(|_| Error::::NoTrack)?; + let track = + T::Tracks::track_for(&proposal_origin).map_err(|_| Error::::NoTrack)?; let submission_deposit = Self::take_deposit(who, T::SubmissionDeposit::get())?; - let index = ReferendumCount::::mutate(|x| { + let index = ReferendumCount::::mutate(|x| { let r = *x; *x += 1; r @@ -360,9 +373,9 @@ pub mod pallet { in_queue: false, alarm: Self::set_alarm(nudge_call, now.saturating_add(T::UndecidingTimeout::get())), }; - ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); + ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); - Self::deposit_event(Event::::Submitted { index, track, proposal_hash }); + Self::deposit_event(Event::::Submitted { index, track, proposal_hash }); Ok(()) } @@ -374,24 +387,24 @@ pub mod pallet { /// posted. /// /// Emits `DecisionDepositPlaced`. - #[pallet::weight(ServiceBranch::max_weight_of_deposit::())] + #[pallet::weight(ServiceBranch::max_weight_of_deposit::())] pub fn place_decision_deposit( origin: OriginFor, index: ReferendumIndex, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let mut status = Self::ensure_ongoing(index)?; - ensure!(status.decision_deposit.is_none(), Error::::HasDeposit); - let track = Self::track(status.track).ok_or(Error::::NoTrack)?; + ensure!(status.decision_deposit.is_none(), Error::::HasDeposit); + let track = Self::track(status.track).ok_or(Error::::NoTrack)?; status.decision_deposit = Some(Self::take_deposit(who.clone(), track.decision_deposit)?); let now = frame_system::Pallet::::block_number(); let (info, _, branch) = Self::service_referendum(now, index, status); - ReferendumInfoFor::::insert(index, info); + ReferendumInfoFor::::insert(index, info); let e = - Event::::DecisionDepositPlaced { index, who, amount: track.decision_deposit }; + Event::::DecisionDepositPlaced { index, who, amount: track.decision_deposit }; Self::deposit_event(e); - Ok(branch.weight_of_deposit::().into()) + Ok(branch.weight_of_deposit::().into()) } /// Refund the Decision Deposit for a closed referendum back to the depositor. @@ -407,14 +420,15 @@ pub mod pallet { index: ReferendumIndex, ) -> DispatchResult { ensure_signed_or_root(origin)?; - let mut info = ReferendumInfoFor::::get(index).ok_or(Error::::BadReferendum)?; + let mut info = + ReferendumInfoFor::::get(index).ok_or(Error::::BadReferendum)?; let deposit = info .take_decision_deposit() - .map_err(|_| Error::::Unfinished)? - .ok_or(Error::::NoDeposit)?; + .map_err(|_| Error::::Unfinished)? + .ok_or(Error::::NoDeposit)?; Self::refund_deposit(Some(deposit.clone())); - ReferendumInfoFor::::insert(index, info); - let e = Event::::DecisionDepositRefunded { + ReferendumInfoFor::::insert(index, info); + let e = Event::::DecisionDepositRefunded { index, who: deposit.who, amount: deposit.amount, @@ -437,13 +451,13 @@ pub mod pallet { let _ = T::Scheduler::cancel(last_alarm); } Self::note_one_fewer_deciding(status.track); - Self::deposit_event(Event::::Cancelled { index, tally: status.tally }); + Self::deposit_event(Event::::Cancelled { index, tally: status.tally }); let info = ReferendumInfo::Cancelled( frame_system::Pallet::::block_number(), status.submission_deposit, status.decision_deposit, ); - ReferendumInfoFor::::insert(index, info); + ReferendumInfoFor::::insert(index, info); Ok(()) } @@ -461,11 +475,11 @@ pub mod pallet { let _ = T::Scheduler::cancel(last_alarm); } Self::note_one_fewer_deciding(status.track); - Self::deposit_event(Event::::Killed { index, tally: status.tally }); + Self::deposit_event(Event::::Killed { index, tally: status.tally }); Self::slash_deposit(Some(status.submission_deposit.clone())); Self::slash_deposit(status.decision_deposit.clone()); let info = ReferendumInfo::Killed(frame_system::Pallet::::block_number()); - ReferendumInfoFor::::insert(index, info); + ReferendumInfoFor::::insert(index, info); Ok(()) } @@ -473,7 +487,7 @@ pub mod pallet { /// /// - `origin`: must be `Root`. /// - `index`: the referendum to be advanced. - #[pallet::weight(ServiceBranch::max_weight_of_nudge::())] + #[pallet::weight(ServiceBranch::max_weight_of_nudge::())] pub fn nudge_referendum( origin: OriginFor, index: ReferendumIndex, @@ -485,9 +499,9 @@ pub mod pallet { status.alarm = None; let (info, dirty, branch) = Self::service_referendum(now, index, status); if dirty { - ReferendumInfoFor::::insert(index, info); + ReferendumInfoFor::::insert(index, info); } - Ok(Some(branch.weight_of_nudge::()).into()) + Ok(Some(branch.weight_of_nudge::()).into()) } /// Advance a track onto its next logical state. Only used internally. @@ -499,14 +513,14 @@ pub mod pallet { /// `DecidingCount` is not yet updated. This means that we should either: /// - begin deciding another referendum (and leave `DecidingCount` alone); or /// - decrement `DecidingCount`. - #[pallet::weight(OneFewerDecidingBranch::max_weight::())] + #[pallet::weight(OneFewerDecidingBranch::max_weight::())] pub fn one_fewer_deciding( origin: OriginFor, - track: TrackIdOf, + track: TrackIdOf, ) -> DispatchResultWithPostInfo { ensure_root(origin)?; - let track_info = T::Tracks::info(track).ok_or(Error::::BadTrack)?; - let mut track_queue = TrackQueue::::get(track); + let track_info = T::Tracks::info(track).ok_or(Error::::BadTrack)?; + let mut track_queue = TrackQueue::::get(track); let branch = if let Some((index, mut status)) = Self::next_for_deciding(&mut track_queue) { let now = frame_system::Pallet::::block_number(); @@ -515,23 +529,23 @@ pub mod pallet { if let Some(set_alarm) = maybe_alarm { Self::ensure_alarm_at(&mut status, index, set_alarm); } - ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); - TrackQueue::::insert(track, track_queue); + ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); + TrackQueue::::insert(track, track_queue); branch.into() } else { - DecidingCount::::mutate(track, |x| x.saturating_dec()); + DecidingCount::::mutate(track, |x| x.saturating_dec()); OneFewerDecidingBranch::QueueEmpty }; - Ok(Some(branch.weight::()).into()) + Ok(Some(branch.weight::()).into()) } } } -impl Polling for Pallet { +impl, I: 'static> Polling for Pallet { type Index = ReferendumIndex; - type Votes = VotesOf; + type Votes = VotesOf; type Moment = T::BlockNumber; - type Class = TrackIdOf; + type Class = TrackIdOf; fn classes() -> Vec { T::Tracks::tracks().iter().map(|x| x.0).collect() @@ -539,14 +553,14 @@ impl Polling for Pallet { fn access_poll( index: Self::Index, - f: impl FnOnce(PollStatus<&mut T::Tally, T::BlockNumber, TrackIdOf>) -> R, + f: impl FnOnce(PollStatus<&mut T::Tally, T::BlockNumber, TrackIdOf>) -> R, ) -> R { - match ReferendumInfoFor::::get(index) { + match ReferendumInfoFor::::get(index) { Some(ReferendumInfo::Ongoing(mut status)) => { let result = f(PollStatus::Ongoing(&mut status.tally, status.track)); let now = frame_system::Pallet::::block_number(); Self::ensure_alarm_at(&mut status, index, now + One::one()); - ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); + ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); result }, Some(ReferendumInfo::Approved(end, ..)) => f(PollStatus::Completed(end, true)), @@ -558,15 +572,15 @@ impl Polling for Pallet { fn try_access_poll( index: Self::Index, f: impl FnOnce( - PollStatus<&mut T::Tally, T::BlockNumber, TrackIdOf>, + PollStatus<&mut T::Tally, T::BlockNumber, TrackIdOf>, ) -> Result, ) -> Result { - match ReferendumInfoFor::::get(index) { + match ReferendumInfoFor::::get(index) { Some(ReferendumInfo::Ongoing(mut status)) => { let result = f(PollStatus::Ongoing(&mut status.tally, status.track))?; let now = frame_system::Pallet::::block_number(); Self::ensure_alarm_at(&mut status, index, now + One::one()); - ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); + ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); Ok(result) }, Some(ReferendumInfo::Approved(end, ..)) => f(PollStatus::Completed(end, true)), @@ -575,13 +589,13 @@ impl Polling for Pallet { } } - fn as_ongoing(index: Self::Index) -> Option<(T::Tally, TrackIdOf)> { + fn as_ongoing(index: Self::Index) -> Option<(T::Tally, TrackIdOf)> { Self::ensure_ongoing(index).ok().map(|x| (x.tally, x.track)) } #[cfg(feature = "runtime-benchmarks")] fn create_ongoing(class: Self::Class) -> Result { - let index = ReferendumCount::::mutate(|x| { + let index = ReferendumCount::::mutate(|x| { let r = *x; *x += 1; r @@ -590,7 +604,7 @@ impl Polling for Pallet { let dummy_account_id = codec::Decode::decode(&mut sp_runtime::traits::TrailingZeroInput::new(&b"dummy"[..])) .expect("infinite length input; no invalid inputs for type; qed"); - let mut status = ReferendumStatusOf:: { + let mut status = ReferendumStatusOf:: { track: class, origin: frame_support::dispatch::RawOrigin::Root.into(), proposal_hash: ::hash_of(&index), @@ -604,7 +618,7 @@ impl Polling for Pallet { alarm: None, }; Self::ensure_alarm_at(&mut status, index, sp_runtime::traits::Bounded::max_value()); - ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); + ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); Ok(index) } @@ -619,7 +633,7 @@ impl Polling for Pallet { } else { ReferendumInfo::Rejected(now, status.submission_deposit, status.decision_deposit) }; - ReferendumInfoFor::::insert(index, info); + ReferendumInfoFor::::insert(index, info); Ok(()) } @@ -633,20 +647,22 @@ impl Polling for Pallet { } } -impl Pallet { +impl, I: 'static> Pallet { /// Check that referendum `index` is in the `Ongoing` state and return the `ReferendumStatus` /// value, or `Err` otherwise. - pub fn ensure_ongoing(index: ReferendumIndex) -> Result, DispatchError> { - match ReferendumInfoFor::::get(index) { + pub fn ensure_ongoing( + index: ReferendumIndex, + ) -> Result, DispatchError> { + match ReferendumInfoFor::::get(index) { Some(ReferendumInfo::Ongoing(status)) => Ok(status), - _ => Err(Error::::NotOngoing.into()), + _ => Err(Error::::NotOngoing.into()), } } // Enqueue a proposal from a referendum which has presumably passed. fn schedule_enactment( index: ReferendumIndex, - track: &TrackInfoOf, + track: &TrackInfoOf, desired: DispatchTime, origin: PalletsOriginOf, call_hash: T::Hash, @@ -668,9 +684,9 @@ impl Pallet { /// Set an alarm to dispatch `call` at block number `when`. fn set_alarm( - call: impl Into>, + call: impl Into>, when: T::BlockNumber, - ) -> Option<(T::BlockNumber, ScheduleAddressOf)> { + ) -> Option<(T::BlockNumber, ScheduleAddressOf)> { let alarm_interval = T::AlarmInterval::get().max(One::one()); let when = (when + alarm_interval - One::one()) / alarm_interval * alarm_interval; let maybe_result = T::Scheduler::schedule( @@ -698,10 +714,10 @@ impl Pallet { /// /// This will properly set up the `confirming` item. fn begin_deciding( - status: &mut ReferendumStatusOf, + status: &mut ReferendumStatusOf, index: ReferendumIndex, now: T::BlockNumber, - track: &TrackInfoOf, + track: &TrackInfoOf, ) -> (Option, BeginDecidingBranch) { let is_passing = Self::is_passing( &status.tally, @@ -711,14 +727,14 @@ impl Pallet { &track.min_approval, ); status.in_queue = false; - Self::deposit_event(Event::::DecisionStarted { + Self::deposit_event(Event::::DecisionStarted { index, tally: status.tally.clone(), proposal_hash: status.proposal_hash.clone(), track: status.track.clone(), }); let confirming = if is_passing { - Self::deposit_event(Event::::ConfirmStarted { index }); + Self::deposit_event(Event::::ConfirmStarted { index }); Some(now.saturating_add(track.confirm_period)) } else { None @@ -737,21 +753,21 @@ impl Pallet { /// If `None`, then it is queued and should be nudged automatically as the queue gets drained. fn ready_for_deciding( now: T::BlockNumber, - track: &TrackInfoOf, + track: &TrackInfoOf, index: ReferendumIndex, - status: &mut ReferendumStatusOf, + status: &mut ReferendumStatusOf, ) -> (Option, ServiceBranch) { - let deciding_count = DecidingCount::::get(status.track); + let deciding_count = DecidingCount::::get(status.track); if deciding_count < track.max_deciding { // Begin deciding. - DecidingCount::::insert(status.track, deciding_count.saturating_add(1)); + DecidingCount::::insert(status.track, deciding_count.saturating_add(1)); let r = Self::begin_deciding(status, index, now, track); (r.0, r.1.into()) } else { // Add to queue. let item = (index, status.tally.ayes()); status.in_queue = true; - TrackQueue::::mutate(status.track, |q| q.insert_sorted_by_key(item, |x| x.1)); + TrackQueue::::mutate(status.track, |q| q.insert_sorted_by_key(item, |x| x.1)); (None, ServiceBranch::Queued) } } @@ -759,8 +775,8 @@ impl Pallet { /// Grab the index and status for the referendum which is the highest priority of those for the /// given track which are ready for being decided. fn next_for_deciding( - track_queue: &mut BoundedVec<(u32, VotesOf), T::MaxQueued>, - ) -> Option<(ReferendumIndex, ReferendumStatusOf)> { + track_queue: &mut BoundedVec<(u32, VotesOf), T::MaxQueued>, + ) -> Option<(ReferendumIndex, ReferendumStatusOf)> { loop { let (index, _) = track_queue.pop()?; match Self::ensure_ongoing(index) { @@ -773,7 +789,7 @@ impl Pallet { /// Schedule a call to `one_fewer_deciding` function via the dispatchable /// `defer_one_fewer_deciding`. We could theoretically call it immediately (and it would be /// overall more efficient), however the weights become rather less easy to measure. - fn note_one_fewer_deciding(track: TrackIdOf) { + fn note_one_fewer_deciding(track: TrackIdOf) { // Set an alarm call for the next block to nudge the track along. let now = frame_system::Pallet::::block_number(); let next_block = now + One::one(); @@ -801,7 +817,7 @@ impl Pallet { /// /// Returns `false` if nothing changed. fn ensure_alarm_at( - status: &mut ReferendumStatusOf, + status: &mut ReferendumStatusOf, index: ReferendumIndex, alarm: T::BlockNumber, ) -> bool { @@ -839,8 +855,8 @@ impl Pallet { fn service_referendum( now: T::BlockNumber, index: ReferendumIndex, - mut status: ReferendumStatusOf, - ) -> (ReferendumInfoOf, bool, ServiceBranch) { + mut status: ReferendumStatusOf, + ) -> (ReferendumInfoOf, bool, ServiceBranch) { let mut dirty = false; // Should it begin being decided? let track = match Self::track(status.track) { @@ -857,7 +873,7 @@ impl Pallet { if status.in_queue { // Does our position in the queue need updating? let ayes = status.tally.ayes(); - let mut queue = TrackQueue::::get(status.track); + let mut queue = TrackQueue::::get(status.track); let maybe_old_pos = queue.iter().position(|(x, _)| *x == index); let new_pos = queue.binary_search_by_key(&ayes, |x| x.1).unwrap_or_else(|x| x); branch = if maybe_old_pos.is_none() && new_pos > 0 { @@ -872,7 +888,7 @@ impl Pallet { } else { ServiceBranch::NotQueued }; - TrackQueue::::insert(status.track, queue); + TrackQueue::::insert(status.track, queue); } else { // Are we ready for deciding? branch = if status.decision_deposit.is_some() { @@ -897,7 +913,7 @@ impl Pallet { if status.deciding.is_none() && now >= timeout { // Too long without being decided - end it. Self::ensure_no_alarm(&mut status); - Self::deposit_event(Event::::TimedOut { index, tally: status.tally }); + Self::deposit_event(Event::::TimedOut { index, tally: status.tally }); return ( ReferendumInfo::TimedOut( now, @@ -931,7 +947,7 @@ impl Pallet { status.origin, call_hash, ); - Self::deposit_event(Event::::Confirmed { + Self::deposit_event(Event::::Confirmed { index, tally: status.tally, }); @@ -950,7 +966,7 @@ impl Pallet { // Start confirming dirty = true; deciding.confirming = Some(now.saturating_add(track.confirm_period)); - Self::deposit_event(Event::::ConfirmStarted { index }); + Self::deposit_event(Event::::ConfirmStarted { index }); ServiceBranch::BeginConfirming }, } @@ -959,7 +975,7 @@ impl Pallet { // Failed! Self::ensure_no_alarm(&mut status); Self::note_one_fewer_deciding(status.track); - Self::deposit_event(Event::::Rejected { index, tally: status.tally }); + Self::deposit_event(Event::::Rejected { index, tally: status.tally }); return ( ReferendumInfo::Rejected( now, @@ -974,7 +990,7 @@ impl Pallet { // Stop confirming dirty = true; deciding.confirming = None; - Self::deposit_event(Event::::ConfirmAborted { index }); + Self::deposit_event(Event::::ConfirmAborted { index }); ServiceBranch::EndConfirming } else { ServiceBranch::ContinueNotConfirming @@ -993,7 +1009,7 @@ impl Pallet { fn decision_time( deciding: &DecidingStatusOf, tally: &T::Tally, - track: &TrackInfoOf, + track: &TrackInfoOf, ) -> T::BlockNumber { deciding.confirming.unwrap_or_else(|| { // Set alarm to the point where the current voting would make it pass. @@ -1007,7 +1023,7 @@ impl Pallet { } /// Cancel the alarm in `status`, if one exists. - fn ensure_no_alarm(status: &mut ReferendumStatusOf) { + fn ensure_no_alarm(status: &mut ReferendumStatusOf) { if let Some((_, last_alarm)) = status.alarm.take() { // Incorrect alarm - cancel it. let _ = T::Scheduler::cancel(last_alarm); @@ -1017,29 +1033,29 @@ impl Pallet { /// Reserve a deposit and return the `Deposit` instance. fn take_deposit( who: T::AccountId, - amount: BalanceOf, - ) -> Result>, DispatchError> { + amount: BalanceOf, + ) -> Result>, DispatchError> { T::Currency::reserve(&who, amount)?; Ok(Deposit { who, amount }) } /// Return a deposit, if `Some`. - fn refund_deposit(deposit: Option>>) { + fn refund_deposit(deposit: Option>>) { if let Some(Deposit { who, amount }) = deposit { T::Currency::unreserve(&who, amount); } } /// Slash a deposit, if `Some`. - fn slash_deposit(deposit: Option>>) { + fn slash_deposit(deposit: Option>>) { if let Some(Deposit { who, amount }) = deposit { T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); - Self::deposit_event(Event::::DepositSlashed { who, amount }); + Self::deposit_event(Event::::DepositSlashed { who, amount }); } } /// Get the track info value for the track `id`. - fn track(id: TrackIdOf) -> Option<&'static TrackInfoOf> { + fn track(id: TrackIdOf) -> Option<&'static TrackInfoOf> { let tracks = T::Tracks::tracks(); let index = tracks.binary_search_by_key(&id, |x| x.0).unwrap_or_else(|x| x); Some(&tracks[index].1) diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 8ea9fc3faf3d0..622075100631b 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -24,44 +24,45 @@ use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; use sp_std::fmt::Debug; -pub type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; -pub type NegativeImbalanceOf = <::Currency as Currency< +pub type BalanceOf = + <>::Currency as Currency<::AccountId>>::Balance; +pub type NegativeImbalanceOf = <>::Currency as Currency< ::AccountId, >>::NegativeImbalance; -pub type CallOf = ::Call; -pub type VotesOf = ::Votes; -pub type TallyOf = ::Tally; +pub type CallOf = >::Call; +pub type VotesOf = >::Votes; +pub type TallyOf = >::Tally; pub type PalletsOriginOf = <::Origin as OriginTrait>::PalletsOrigin; -pub type ReferendumInfoOf = ReferendumInfo< - TrackIdOf, +pub type ReferendumInfoOf = ReferendumInfo< + TrackIdOf, PalletsOriginOf, ::BlockNumber, ::Hash, - BalanceOf, - TallyOf, + BalanceOf, + TallyOf, ::AccountId, - ScheduleAddressOf, + ScheduleAddressOf, >; -pub type ReferendumStatusOf = ReferendumStatus< - TrackIdOf, +pub type ReferendumStatusOf = ReferendumStatus< + TrackIdOf, PalletsOriginOf, ::BlockNumber, ::Hash, - BalanceOf, - TallyOf, + BalanceOf, + TallyOf, ::AccountId, - ScheduleAddressOf, + ScheduleAddressOf, >; pub type DecidingStatusOf = DecidingStatus<::BlockNumber>; -pub type TrackInfoOf = TrackInfo, ::BlockNumber>; -pub type TrackIdOf = <::Tracks as TracksInfo< - BalanceOf, +pub type TrackInfoOf = + TrackInfo, ::BlockNumber>; +pub type TrackIdOf = <>::Tracks as TracksInfo< + BalanceOf, ::BlockNumber, >>::Id; -pub type ScheduleAddressOf = <::Scheduler as Anon< +pub type ScheduleAddressOf = <>::Scheduler as Anon< ::BlockNumber, - CallOf, + CallOf, PalletsOriginOf, >>::Address; From 676932fb5543d5b316b4e494631d8e48f98b760d Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 24 Mar 2022 22:12:48 +0100 Subject: [PATCH 0634/1472] Clear storage before running the bench (#11109) Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi --- frame/bags-list/src/benchmarks.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index b94a97093d001..bcfd1e3392b0e 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -144,6 +144,10 @@ frame_benchmarking::benchmarks! { // - both heavier's `prev` and `next` are nodes that will need to be read and written. // - `lighter` is the bag's `head`, so the bag will need to be read and written. + // clear any pre-existing storage. + // NOTE: safe to call outside block production + List::::unsafe_clear(); + let bag_thresh = T::BagThresholds::get()[0]; // insert the nodes in order From 08fd14d8d1b34798390d454632e0b6ab794d17ac Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 25 Mar 2022 12:27:43 +0100 Subject: [PATCH 0635/1472] Add `benchmark-block` command (#11091) * Add benchmark-block command Signed-off-by: Oliver Tale-Yazdi * Apply suggestions from code review Co-authored-by: Shawn Tabrizi * Beauty fixes Signed-off-by: Oliver Tale-Yazdi * Beauty fixes Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi Co-authored-by: parity-processbot <> --- Cargo.lock | 2 + bin/node/cli/src/cli.rs | 7 + bin/node/cli/src/command.rs | 7 + utils/frame/benchmarking-cli/Cargo.toml | 2 + .../frame/benchmarking-cli/src/block/bench.rs | 176 ++++++++++++++++++ utils/frame/benchmarking-cli/src/block/cmd.rs | 101 ++++++++++ utils/frame/benchmarking-cli/src/block/mod.rs | 24 +++ utils/frame/benchmarking-cli/src/lib.rs | 2 + .../benchmarking-cli/src/overhead/cmd.rs | 10 +- 9 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 utils/frame/benchmarking-cli/src/block/bench.rs create mode 100644 utils/frame/benchmarking-cli/src/block/cmd.rs create mode 100644 utils/frame/benchmarking-cli/src/block/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 1b478fcc18a78..1731ded2906cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2129,6 +2129,7 @@ dependencies = [ "clap 3.1.6", "frame-benchmarking", "frame-support", + "frame-system", "handlebars", "hash-db", "hex", @@ -2160,6 +2161,7 @@ dependencies = [ "sp-std", "sp-storage", "sp-trie", + "thousands", ] [[package]] diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index a911cc26ef87c..952c6311f8b38 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -42,6 +42,13 @@ pub enum Subcommand { #[clap(name = "benchmark", about = "Benchmark runtime pallets.")] Benchmark(frame_benchmarking_cli::BenchmarkCmd), + /// Benchmark the execution time of historic blocks and compare it to their consumed weight. + #[clap( + name = "benchmark-block", + about = "Benchmark the execution time of historic blocks and compare it to their consumed weight." + )] + BenchmarkBlock(frame_benchmarking_cli::BlockCmd), + /// Sub command for benchmarking the per-block and per-extrinsic execution overhead. #[clap( name = "benchmark-overhead", diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 3c2039fde4757..bd324b20fb019 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -98,6 +98,13 @@ pub fn run() -> Result<()> { You can enable it with `--features runtime-benchmarks`." .into()) }, + Some(Subcommand::BenchmarkBlock(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, .. } = new_partial(&config)?; + Ok((cmd.run(client), task_manager)) + }) + }, Some(Subcommand::BenchmarkOverhead(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|mut config| { diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index b28fe195a2f31..11bba2b37957f 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } +frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } @@ -50,6 +51,7 @@ hash-db = "0.15.2" hex = "0.4.3" memory-db = "0.29.0" rand = { version = "0.8.4", features = ["small_rng"] } +thousands = "0.2.0" [features] default = ["db", "sc-client-db/runtime-benchmarks"] diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs new file mode 100644 index 0000000000000..d3c1c97b04ab2 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -0,0 +1,176 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains the core benchmarking logic. + +use codec::DecodeAll; +use frame_support::weights::constants::WEIGHT_PER_NANOS; +use frame_system::ConsumedWeight; +use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_cli::{Error, Result}; +use sc_client_api::{Backend as ClientBackend, BlockBackend, StorageProvider, UsageProvider}; +use sp_api::{ApiExt, Core, HeaderT, ProvideRuntimeApi}; +use sp_blockchain::Error::RuntimeApiError; +use sp_runtime::{generic::BlockId, traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; +use sp_storage::StorageKey; + +use clap::Args; +use log::{info, warn}; +use serde::Serialize; +use std::{fmt::Debug, marker::PhantomData, sync::Arc, time::Instant}; +use thousands::Separable; + +use crate::storage::record::{StatSelect, Stats}; + +/// Log target for printing block weight info. +const LOG_TARGET: &'static str = "benchmark::block::weight"; + +/// Parameters for modifying the benchmark behaviour. +#[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] +pub struct BenchmarkParams { + /// Number of the first block to consider. + #[clap(long)] + pub from: u32, + + /// Last block number to consider. + #[clap(long)] + pub to: u32, + + /// Number of times that the benchmark should be repeated for each block. + #[clap(long, default_value = "10")] + pub repeat: u32, +} + +/// Convenience closure for the [`Benchmark::run()`] function. +pub struct Benchmark { + client: Arc, + params: BenchmarkParams, + _p: PhantomData<(Block, BA, C)>, +} + +/// Helper for nano seconds. +type NanoSeconds = u64; + +impl Benchmark +where + Block: BlockT, + BA: ClientBackend, + C: BlockBuilderProvider + + ProvideRuntimeApi + + StorageProvider + + UsageProvider + + BlockBackend, + C::Api: ApiExt + BlockBuilderApi, +{ + /// Returns a new [`Self`] from the arguments. + pub fn new(client: Arc, params: BenchmarkParams) -> Self { + Self { client, params, _p: PhantomData } + } + + /// Benchmark the execution speed of historic blocks and log the results. + pub fn run(&self) -> Result<()> { + if self.params.from == 0 { + return Err("Cannot benchmark the genesis block".into()) + } + + for i in self.params.from..=self.params.to { + let block_num = BlockId::Number(i.into()); + let parent_num = BlockId::Number(((i - 1) as u32).into()); + let consumed = self.consumed_weight(&block_num)?; + + let block = + self.client.block(&block_num)?.ok_or(format!("Block {} not found", block_num))?; + let block = self.unsealed(block.block); + let took = self.measure_block(&block, &parent_num)?; + + self.log_weight(i, block.extrinsics().len(), consumed, took); + } + + Ok(()) + } + + /// Return the average *execution* aka. *import* time of the block. + fn measure_block(&self, block: &Block, parent_num: &BlockId) -> Result { + let mut record = Vec::::default(); + // Interesting part here: + // Execute the block multiple times and collect stats about its execution time. + for _ in 0..self.params.repeat { + let block = block.clone(); + let runtime_api = self.client.runtime_api(); + let start = Instant::now(); + + runtime_api + .execute_block(&parent_num, block) + .map_err(|e| Error::Client(RuntimeApiError(e)))?; + + record.push(start.elapsed().as_nanos() as NanoSeconds); + } + + let took = Stats::new(&record)?.select(StatSelect::Average); + Ok(took) + } + + /// Returns the total nanoseconds of a [`frame_system::ConsumedWeight`] for a block number. + /// + /// This is the post-dispatch corrected weight and is only available + /// after executing the block. + fn consumed_weight(&self, block: &BlockId) -> Result { + // Hard-coded key for System::BlockWeight. It could also be passed in as argument + // for the benchmark, but I think this should work as well. + let hash = hex::decode("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96")?; + let key = StorageKey(hash); + + let mut raw_weight = &self + .client + .storage(&block, &key)? + .ok_or(format!("Could not find System::BlockWeight for block: {}", block))? + .0[..]; + + let weight = ConsumedWeight::decode_all(&mut raw_weight)?; + // Should be divisible, but still use floats in case we ever change that. + Ok((weight.total() as f64 / WEIGHT_PER_NANOS as f64).floor() as NanoSeconds) + } + + /// Prints the weight info of a block to the console. + fn log_weight(&self, num: u32, num_ext: usize, consumed: NanoSeconds, took: NanoSeconds) { + // The ratio of weight that the block used vs what it consumed. + // This should in general not exceed 100% (minus outliers). + let percent = (took as f64 / consumed as f64) * 100.0; + + let msg = format!( + "Block {} with {: >5} tx used {: >6.2}% of its weight ({: >14} of {: >14} ns)", + num, + num_ext, + percent, + took.separate_with_commas(), + consumed.separate_with_commas() + ); + + if took <= consumed { + info!(target: LOG_TARGET, "{}", msg); + } else { + warn!(target: LOG_TARGET, "{} - OVER WEIGHT!", msg); + } + } + + /// Removes the consensus seal from the block. + fn unsealed(&self, block: Block) -> Block { + let (mut header, exts) = block.deconstruct(); + header.digest_mut().logs.retain(|item| !matches!(item, DigestItem::Seal(_, _))); + Block::new(header, exts) + } +} diff --git a/utils/frame/benchmarking-cli/src/block/cmd.rs b/utils/frame/benchmarking-cli/src/block/cmd.rs new file mode 100644 index 0000000000000..4618c1dd894e1 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/block/cmd.rs @@ -0,0 +1,101 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains the [`BlockCmd`] as entry point for the CLI to execute +//! the *block* benchmark. + +use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; +use sc_client_api::{Backend as ClientBackend, BlockBackend, StorageProvider, UsageProvider}; +use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; + +use clap::Parser; +use std::{fmt::Debug, sync::Arc}; + +use super::bench::{Benchmark, BenchmarkParams}; + +/// Benchmark the execution time historic blocks. +/// +/// This can be used to verify that blocks do not use more weight than they consumed +/// in their `WeightInfo`. Example: +/// +/// Let's say you are on a Substrate chain and want to verify that the first 3 blocks +/// did not use more weight than declared which would otherwise be an issue. +/// To test this with a dev node, first create one with a temp directory: +/// +/// $ substrate --dev -d /tmp/my-dev --execution wasm --wasm-execution compiled +/// +/// And wait some time to let it produce 3 blocks. Then benchmark them with: +/// +/// $ substrate benchmark-block --from 1 --to 3 --dev -d /tmp/my-dev +/// --execution wasm --wasm-execution compiled --pruning archive +/// +/// The output will be similar to this: +/// +/// Block 1 with 1 tx used 77.34% of its weight ( 5,308,964 of 6,864,645 ns) +/// Block 2 with 1 tx used 77.99% of its weight ( 5,353,992 of 6,864,645 ns) +/// Block 3 with 1 tx used 75.91% of its weight ( 5,305,938 of 6,989,645 ns) +/// +/// The percent number is important and indicates how much weight +/// was used as compared to the consumed weight. +/// This number should be below 100% for reference hardware. +#[derive(Debug, Parser)] +pub struct BlockCmd { + #[allow(missing_docs)] + #[clap(flatten)] + pub shared_params: SharedParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub import_params: ImportParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub params: BenchmarkParams, +} + +impl BlockCmd { + /// Benchmark the execution time of historic blocks and compare it to their consumed weight. + /// + /// Output will be printed to console. + pub async fn run(&self, client: Arc) -> Result<()> + where + Block: BlockT, + BA: ClientBackend, + C: BlockBuilderProvider + + BlockBackend + + ProvideRuntimeApi + + StorageProvider + + UsageProvider, + C::Api: ApiExt + BlockBuilderApi, + { + // Put everything in the benchmark type to have the generic types handy. + Benchmark::new(client, self.params.clone()).run() + } +} + +// Boilerplate +impl CliConfiguration for BlockCmd { + fn shared_params(&self) -> &SharedParams { + &self.shared_params + } + + fn import_params(&self) -> Option<&ImportParams> { + Some(&self.import_params) + } +} diff --git a/utils/frame/benchmarking-cli/src/block/mod.rs b/utils/frame/benchmarking-cli/src/block/mod.rs new file mode 100644 index 0000000000000..97fdb6ad2c20c --- /dev/null +++ b/utils/frame/benchmarking-cli/src/block/mod.rs @@ -0,0 +1,24 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Crate to benchmark the execution time of historic blocks +//! and compare it to their consumed weight. + +mod bench; +mod cmd; + +pub use cmd::BlockCmd; diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index e06d57963dad3..288e6b4b86156 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod block; mod command; pub mod overhead; mod post_processing; @@ -24,6 +25,7 @@ mod writer; use sc_cli::{ExecutionStrategy, WasmExecutionMethod, DEFAULT_WASM_EXECUTION_METHOD}; use std::{fmt::Debug, path::PathBuf}; +pub use block::BlockCmd; pub use overhead::{ExtrinsicBuilder, OverheadCmd}; pub use storage::StorageCmd; diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 8c75627fe2462..f74c32ba72a86 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -19,7 +19,7 @@ //! the *overhead* benchmarks. use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; -use sc_cli::{CliConfiguration, Result, SharedParams}; +use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; use sc_client_api::Backend as ClientBackend; use sc_service::Configuration; use sp_api::{ApiExt, ProvideRuntimeApi}; @@ -45,6 +45,10 @@ pub struct OverheadCmd { #[clap(flatten)] pub shared_params: SharedParams, + #[allow(missing_docs)] + #[clap(flatten)] + pub import_params: ImportParams, + #[allow(missing_docs)] #[clap(flatten)] pub params: OverheadParams, @@ -115,4 +119,8 @@ impl CliConfiguration for OverheadCmd { fn shared_params(&self) -> &SharedParams { &self.shared_params } + + fn import_params(&self) -> Option<&ImportParams> { + Some(&self.import_params) + } } From 26ea75756b44de8b83f927c63c6ed46a0f040386 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Fri, 25 Mar 2022 09:42:54 -0400 Subject: [PATCH 0636/1472] Improve Bounties and Child Bounties Deposit Logic (#11014) * basic idea * make tests better * update bounties pallet to also have similar logic * new test verifies logic for bounty pallet * add test for new child logic * better name * make `node` compile with bounties changes * * formatting * use uniform notion of parent and child, no "master" or "general" entity * README updated to match comments * Revert "* formatting" This reverts commit 1ab729e7c23b5db24a8e229d487bbc2ed81d38c3. * update bounties logic to use bounds * fix child * bounties test for max * update tests * check min bound * update node * remove stale comment * Update frame/bounties/src/lib.rs Co-authored-by: Dan Shields --- bin/node/runtime/src/lib.rs | 34 +-- frame/bounties/src/lib.rs | 32 ++- frame/bounties/src/tests.rs | 134 +++++++++-- frame/child-bounties/src/lib.rs | 35 ++- frame/child-bounties/src/tests.rs | 358 +++++++++++++++++++++++------- 5 files changed, 460 insertions(+), 133 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index a6d97cb299b24..47bdedbab83a3 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -220,7 +220,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = frame_system::weights::SubstrateWeight; type SS58Prefix = ConstU16<42>; type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet_randomness_collective_flip::Config for Runtime {} @@ -827,7 +827,7 @@ impl pallet_democracy::Config for Runtime { type Slash = Treasury; type Scheduler = Scheduler; type PalletsOrigin = OriginCaller; - type MaxVotes = frame_support::traits::ConstU32<100>; + type MaxVotes = ConstU32<100>; type WeightInfo = pallet_democracy::weights::SubstrateWeight; type MaxProposals = MaxProposals; } @@ -929,17 +929,9 @@ parameter_types! { pub const TipFindersFee: Percent = Percent::from_percent(20); pub const TipReportDepositBase: Balance = 1 * DOLLARS; pub const DataDepositPerByte: Balance = 1 * CENTS; - pub const BountyDepositBase: Balance = 1 * DOLLARS; - pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS; pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS; pub const MaximumReasonLength: u32 = 300; - pub const BountyCuratorDeposit: Permill = Permill::from_percent(50); - pub const BountyValueMinimum: Balance = 5 * DOLLARS; pub const MaxApprovals: u32 = 100; - pub const MaxActiveChildBountyCount: u32 = 5; - pub const ChildBountyValueMinimum: Balance = 1 * DOLLARS; - pub const ChildBountyCuratorDepositBase: Permill = Permill::from_percent(10); } impl pallet_treasury::Config for Runtime { @@ -966,12 +958,25 @@ impl pallet_treasury::Config for Runtime { type MaxApprovals = MaxApprovals; } +parameter_types! { + pub const BountyCuratorDeposit: Permill = Permill::from_percent(50); + pub const BountyValueMinimum: Balance = 5 * DOLLARS; + pub const BountyDepositBase: Balance = 1 * DOLLARS; + pub const CuratorDepositMultiplier: Permill = Permill::from_percent(50); + pub const CuratorDepositMin: Balance = 1 * DOLLARS; + pub const CuratorDepositMax: Balance = 100 * DOLLARS; + pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS; + pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS; +} + impl pallet_bounties::Config for Runtime { type Event = Event; type BountyDepositBase = BountyDepositBase; type BountyDepositPayoutDelay = BountyDepositPayoutDelay; type BountyUpdatePeriod = BountyUpdatePeriod; - type BountyCuratorDeposit = BountyCuratorDeposit; + type CuratorDepositMultiplier = CuratorDepositMultiplier; + type CuratorDepositMin = CuratorDepositMin; + type CuratorDepositMax = CuratorDepositMax; type BountyValueMinimum = BountyValueMinimum; type DataDepositPerByte = DataDepositPerByte; type MaximumReasonLength = MaximumReasonLength; @@ -979,11 +984,14 @@ impl pallet_bounties::Config for Runtime { type ChildBountyManager = ChildBounties; } +parameter_types! { + pub const ChildBountyValueMinimum: Balance = 1 * DOLLARS; +} + impl pallet_child_bounties::Config for Runtime { type Event = Event; - type MaxActiveChildBountyCount = MaxActiveChildBountyCount; + type MaxActiveChildBountyCount = ConstU32<5>; type ChildBountyValueMinimum = ChildBountyValueMinimum; - type ChildBountyCuratorDepositBase = ChildBountyCuratorDepositBase; type WeightInfo = pallet_child_bounties::weights::SubstrateWeight; } diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 988b15c58a13f..98f2da305a06d 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -196,10 +196,20 @@ pub mod pallet { #[pallet::constant] type BountyUpdatePeriod: Get; - /// Percentage of the curator fee that will be reserved upfront as deposit for bounty - /// curator. + /// The curator deposit is calculated as a percentage of the curator fee. + /// + /// This deposit has optional upper and lower bounds with `CuratorDepositMax` and + /// `CuratorDepositMin`. + #[pallet::constant] + type CuratorDepositMultiplier: Get; + + /// Maximum amount of funds that should be placed in a deposit for making a proposal. #[pallet::constant] - type BountyCuratorDeposit: Get; + type CuratorDepositMax: Get>>; + + /// Minimum amount of funds that should be placed in a deposit for making a proposal. + #[pallet::constant] + type CuratorDepositMin: Get>>; /// Minimum value for a bounty. #[pallet::constant] @@ -502,7 +512,7 @@ pub mod pallet { BountyStatus::CuratorProposed { ref curator } => { ensure!(signer == *curator, Error::::RequireCurator); - let deposit = T::BountyCuratorDeposit::get() * bounty.fee; + let deposit = Self::calculate_curator_deposit(&bounty.fee); T::Currency::reserve(curator, deposit)?; bounty.curator_deposit = deposit; @@ -762,7 +772,19 @@ pub mod pallet { } impl Pallet { - // Add public immutables and private mutables. + pub fn calculate_curator_deposit(fee: &BalanceOf) -> BalanceOf { + let mut deposit = T::CuratorDepositMultiplier::get() * *fee; + + if let Some(max_deposit) = T::CuratorDepositMax::get() { + deposit = deposit.min(max_deposit) + } + + if let Some(min_deposit) = T::CuratorDepositMin::get() { + deposit = deposit.max(min_deposit) + } + + deposit + } /// The account ID of the treasury pot. /// diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index 3206fce9912fa..9a84bd687abc1 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -60,6 +60,8 @@ parameter_types! { pub const AvailableBlockRatio: Perbill = Perbill::one(); } +type Balance = u64; + impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -91,7 +93,7 @@ impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); type ReserveIdentifier = [u8; 8]; - type Balance = u64; + type Balance = Balance; type Event = Event; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; @@ -125,15 +127,23 @@ impl pallet_treasury::Config for Test { type SpendFunds = Bounties; type MaxApprovals = ConstU32<100>; } + parameter_types! { - pub const BountyCuratorDeposit: Permill = Permill::from_percent(50); + // This will be 50% of the bounty fee. + pub const CuratorDepositMultiplier: Permill = Permill::from_percent(50); + pub const CuratorDepositMax: Balance = 1_000; + pub const CuratorDepositMin: Balance = 3; + } + impl Config for Test { type Event = Event; type BountyDepositBase = ConstU64<80>; type BountyDepositPayoutDelay = ConstU64<3>; type BountyUpdatePeriod = ConstU64<20>; - type BountyCuratorDeposit = BountyCuratorDeposit; + type CuratorDepositMultiplier = CuratorDepositMultiplier; + type CuratorDepositMax = CuratorDepositMax; + type CuratorDepositMin = CuratorDepositMin; type BountyValueMinimum = ConstU64<1>; type DataDepositPerByte = ConstU64<1>; type MaximumReasonLength = ConstU32<16384>; @@ -543,13 +553,14 @@ fn assign_curator_works() { Error::::InvalidFee ); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 4)); + let fee = 4; + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); assert_eq!( Bounties::bounties(0).unwrap(), Bounty { proposer: 0, - fee: 4, + fee, curator_deposit: 0, value: 50, bond: 85, @@ -567,20 +578,22 @@ fn assign_curator_works() { assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + let expected_deposit = Bounties::calculate_curator_deposit(&fee); + assert_eq!( Bounties::bounties(0).unwrap(), Bounty { proposer: 0, - fee: 4, - curator_deposit: 2, + fee, + curator_deposit: expected_deposit, value: 50, bond: 85, status: BountyStatus::Active { curator: 4, update_due: 22 }, } ); - assert_eq!(Balances::free_balance(&4), 8); - assert_eq!(Balances::reserved_balance(&4), 2); + assert_eq!(Balances::free_balance(&4), 10 - expected_deposit); + assert_eq!(Balances::reserved_balance(&4), expected_deposit); }); } @@ -596,17 +609,17 @@ fn unassign_curator_works() { System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 4)); + let fee = 4; + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); assert_noop!(Bounties::unassign_curator(Origin::signed(1), 0), BadOrigin); - assert_ok!(Bounties::unassign_curator(Origin::signed(4), 0)); assert_eq!( Bounties::bounties(0).unwrap(), Bounty { proposer: 0, - fee: 4, + fee, curator_deposit: 0, value: 50, bond: 85, @@ -614,19 +627,17 @@ fn unassign_curator_works() { } ); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 4)); - + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); - + let expected_deposit = Bounties::calculate_curator_deposit(&fee); assert_ok!(Bounties::unassign_curator(Origin::root(), 0)); assert_eq!( Bounties::bounties(0).unwrap(), Bounty { proposer: 0, - fee: 4, + fee, curator_deposit: 0, value: 50, bond: 85, @@ -634,8 +645,8 @@ fn unassign_curator_works() { } ); - assert_eq!(Balances::free_balance(&4), 8); - assert_eq!(Balances::reserved_balance(&4), 0); // slashed 2 + assert_eq!(Balances::free_balance(&4), 10 - expected_deposit); + assert_eq!(Balances::reserved_balance(&4), 0); // slashed curator deposit }); } @@ -652,10 +663,12 @@ fn award_and_claim_bounty_works() { System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 4)); + let fee = 4; + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); - assert_eq!(Balances::free_balance(4), 8); // inital 10 - 2 deposit + let expected_deposit = Bounties::calculate_curator_deposit(&fee); + assert_eq!(Balances::free_balance(4), 10 - expected_deposit); assert_noop!( Bounties::award_bounty(Origin::signed(1), 0, 3), @@ -668,8 +681,8 @@ fn award_and_claim_bounty_works() { Bounties::bounties(0).unwrap(), Bounty { proposer: 0, - fee: 4, - curator_deposit: 2, + fee, + curator_deposit: expected_deposit, value: 50, bond: 85, status: BountyStatus::PendingPayout { curator: 4, beneficiary: 3, unlock_at: 5 }, @@ -1034,3 +1047,78 @@ fn unassign_curator_self() { assert_eq!(Balances::reserved_balance(1), 0); // not slashed }); } + +#[test] +fn accept_curator_handles_different_deposit_calculations() { + // This test will verify that a bounty with and without a fee results + // in a different curator deposit: one using the value, and one using the fee. + new_test_ext().execute_with(|| { + // Case 1: With a fee + let user = 1; + let bounty_index = 0; + let value = 88; + let fee = 42; + + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + Balances::make_free_balance_be(&user, 100); + assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); + assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); + + let expected_deposit = CuratorDepositMultiplier::get() * fee; + assert_eq!(Balances::free_balance(&user), 100 - expected_deposit); + assert_eq!(Balances::reserved_balance(&user), expected_deposit); + + // Case 2: Lower bound + let user = 2; + let bounty_index = 1; + let value = 35; + let fee = 0; + + Balances::make_free_balance_be(&Treasury::account_id(), 101); + Balances::make_free_balance_be(&user, 100); + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); + + System::set_block_number(3); + >::on_initialize(3); + + assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); + assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); + + let expected_deposit = CuratorDepositMin::get(); + assert_eq!(Balances::free_balance(&user), 100 - expected_deposit); + assert_eq!(Balances::reserved_balance(&user), expected_deposit); + + // Case 3: Upper bound + let user = 3; + let bounty_index = 2; + let value = 1_000_000; + let fee = 50_000; + let starting_balance = fee * 2; + + Balances::make_free_balance_be(&Treasury::account_id(), value * 2); + Balances::make_free_balance_be(&user, starting_balance); + Balances::make_free_balance_be(&0, starting_balance); + + assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); + + System::set_block_number(3); + >::on_initialize(3); + + assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); + assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); + + let expected_deposit = CuratorDepositMax::get(); + assert_eq!(Balances::free_balance(&user), starting_balance - expected_deposit); + assert_eq!(Balances::reserved_balance(&user), expected_deposit); + }); +} diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 36acc7766bf61..2fea61c045cf6 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -66,7 +66,7 @@ use frame_support::traits::{ use sp_runtime::{ traits::{AccountIdConversion, BadOrigin, CheckedSub, Saturating, StaticLookup, Zero}, - DispatchResult, Permill, RuntimeDebug, + DispatchResult, RuntimeDebug, }; use frame_support::pallet_prelude::*; @@ -144,11 +144,6 @@ pub mod pallet { #[pallet::constant] type ChildBountyValueMinimum: Get>; - /// Percentage of child-bounty value to be reserved as curator deposit - /// when curator fee is zero. - #[pallet::constant] - type ChildBountyCuratorDepositBase: Get; - /// The overarching event type. type Event: From> + IsType<::Event>; @@ -392,7 +387,7 @@ pub mod pallet { ) -> DispatchResult { let signer = ensure_signed(origin)?; - let _ = Self::ensure_bounty_active(parent_bounty_id)?; + let (parent_curator, _) = Self::ensure_bounty_active(parent_bounty_id)?; // Mutate child-bounty. ChildBounties::::try_mutate_exists( parent_bounty_id, @@ -406,11 +401,13 @@ pub mod pallet { { ensure!(signer == *curator, BountiesError::::RequireCurator); - // Reserve child-bounty curator deposit. Curator deposit - // is reserved based on a percentage of child-bounty - // value instead of fee, to avoid no deposit in case the - // fee is set as zero. - let deposit = T::ChildBountyCuratorDepositBase::get() * child_bounty.value; + // Reserve child-bounty curator deposit. + let deposit = Self::calculate_curator_deposit( + &parent_curator, + curator, + &child_bounty.fee, + ); + T::Currency::reserve(curator, deposit)?; child_bounty.curator_deposit = deposit; @@ -770,6 +767,20 @@ pub mod pallet { } impl Pallet { + // This function will calculate the deposit of a curator. + fn calculate_curator_deposit( + parent_curator: &T::AccountId, + child_curator: &T::AccountId, + bounty_fee: &BalanceOf, + ) -> BalanceOf { + if parent_curator == child_curator { + return Zero::zero() + } + + // We just use the same logic from the parent bounties pallet. + pallet_bounties::Pallet::::calculate_curator_deposit(bounty_fee) + } + /// The account ID of a child-bounty account. pub fn child_bounty_account_id(id: BountyIndex) -> T::AccountId { // This function is taken from the parent (bounties) pallet, but the diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index a6748c47b73d8..61545561a26c3 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -65,6 +65,8 @@ parameter_types! { pub const AvailableBlockRatio: Perbill = Perbill::one(); } +type Balance = u64; + impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -96,7 +98,7 @@ impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); type ReserveIdentifier = [u8; 8]; - type Balance = u64; + type Balance = Balance; type Event = Event; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; @@ -130,28 +132,30 @@ impl pallet_treasury::Config for Test { type MaxApprovals = ConstU32<100>; } parameter_types! { - pub const BountyCuratorDeposit: Permill = Permill::from_percent(50); + // This will be 50% of the bounty fee. + pub const CuratorDepositMultiplier: Permill = Permill::from_percent(50); + pub const CuratorDepositMax: Balance = 1_000; + pub const CuratorDepositMin: Balance = 3; + } impl pallet_bounties::Config for Test { type Event = Event; type BountyDepositBase = ConstU64<80>; type BountyDepositPayoutDelay = ConstU64<3>; type BountyUpdatePeriod = ConstU64<10>; - type BountyCuratorDeposit = BountyCuratorDeposit; + type CuratorDepositMultiplier = CuratorDepositMultiplier; + type CuratorDepositMax = CuratorDepositMax; + type CuratorDepositMin = CuratorDepositMin; type BountyValueMinimum = ConstU64<5>; type DataDepositPerByte = ConstU64<1>; type MaximumReasonLength = ConstU32<300>; type WeightInfo = (); type ChildBountyManager = ChildBounties; } -parameter_types! { - pub const ChildBountyCuratorDepositBase: Permill = Permill::from_percent(10); -} impl pallet_child_bounties::Config for Test { type Event = Event; type MaxActiveChildBountyCount = ConstU32<2>; type ChildBountyValueMinimum = ConstU64<1>; - type ChildBountyCuratorDepositBase = ChildBountyCuratorDepositBase; type WeightInfo = (); } @@ -197,10 +201,10 @@ fn minting_works() { fn add_child_bounty() { new_test_ext().execute_with(|| { // TestProcedure. - // 1, Create bounty & move to active state with enough bounty fund & master-curator. - // 2, Master-curator adds child-bounty child-bounty-1, test for error like RequireCurator + // 1, Create bounty & move to active state with enough bounty fund & parent curator. + // 2, Parent curator adds child-bounty child-bounty-1, test for error like RequireCurator // ,InsufficientProposersBalance, InsufficientBountyBalance with invalid arguments. - // 3, Master-curator adds child-bounty child-bounty-1, moves to "Approved" state & + // 3, Parent curator adds child-bounty child-bounty-1, moves to "Approved" state & // test for the event Added. // 4, Test for DB state of `Bounties` & `ChildBounties`. // 5, Observe fund transaction moment between Bounty, Child-bounty, @@ -217,27 +221,30 @@ fn add_child_bounty() { System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 4)); + let fee = 8; + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); Balances::make_free_balance_be(&4, 10); assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); - assert_eq!(Balances::free_balance(&4), 8); - assert_eq!(Balances::reserved_balance(&4), 2); + // This verifies that the accept curator logic took a deposit. + let expected_deposit = CuratorDepositMultiplier::get() * fee; + assert_eq!(Balances::reserved_balance(&4), expected_deposit); + assert_eq!(Balances::free_balance(&4), 10 - expected_deposit); // Add child-bounty. - // Acc-4 is the master curator. + // Acc-4 is the parent curator. // Call from invalid origin & check for error "RequireCurator". assert_noop!( ChildBounties::add_child_bounty(Origin::signed(0), 0, 10, b"12345-p1".to_vec()), BountiesError::RequireCurator, ); - // Update the master curator balance. + // Update the parent curator balance. Balances::make_free_balance_be(&4, 101); - // Master curator fee is reserved on parent bounty account. + // parent curator fee is reserved on parent bounty account. assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); @@ -258,7 +265,7 @@ fn add_child_bounty() { assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); assert_eq!(Balances::free_balance(4), 101); - assert_eq!(Balances::reserved_balance(4), 2); + assert_eq!(Balances::reserved_balance(4), expected_deposit); // DB check. // Check the child-bounty status. @@ -285,8 +292,8 @@ fn add_child_bounty() { fn child_bounty_assign_curator() { new_test_ext().execute_with(|| { // TestProcedure - // 1, Create bounty & move to active state with enough bounty fund & master-curator. - // 2, Master-curator adds child-bounty child-bounty-1, moves to "Active" state. + // 1, Create bounty & move to active state with enough bounty fund & parent curator. + // 2, Parent curator adds child-bounty child-bounty-1, moves to "Active" state. // 3, Test for DB state of `ChildBounties`. // Make the parent bounty. @@ -302,21 +309,22 @@ fn child_bounty_assign_curator() { System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 4)); - + let fee = 4; + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); // Bounty account status before adding child-bounty. assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); - // Check the balance of master curator. - // Curator deposit is reserved for master curator on parent bounty. - assert_eq!(Balances::free_balance(4), 99); - assert_eq!(Balances::reserved_balance(4), 2); + // Check the balance of parent curator. + // Curator deposit is reserved for parent curator on parent bounty. + let expected_deposit = Bounties::calculate_curator_deposit(&fee); + assert_eq!(Balances::free_balance(4), 101 - expected_deposit); + assert_eq!(Balances::reserved_balance(4), expected_deposit); // Add child-bounty. - // Acc-4 is the master curator & make sure enough deposit. + // Acc-4 is the parent curator & make sure enough deposit. assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); @@ -329,22 +337,23 @@ fn child_bounty_assign_curator() { assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 10); assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + let fee = 6u64; + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, - fee: 2, + fee, curator_deposit: 0, status: ChildBountyStatus::CuratorProposed { curator: 8 }, } ); - // Check the balance of master curator. - assert_eq!(Balances::free_balance(4), 99); - assert_eq!(Balances::reserved_balance(4), 2); + // Check the balance of parent curator. + assert_eq!(Balances::free_balance(4), 101 - expected_deposit); + assert_eq!(Balances::reserved_balance(4), expected_deposit); assert_noop!( ChildBounties::accept_curator(Origin::signed(3), 0, 0), @@ -353,20 +362,22 @@ fn child_bounty_assign_curator() { assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + let expected_child_deposit = CuratorDepositMultiplier::get() * fee; + assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, - fee: 2, - curator_deposit: 1, + fee, + curator_deposit: expected_child_deposit, status: ChildBountyStatus::Active { curator: 8 }, } ); - // Deposit for child-bounty curator is reserved. - assert_eq!(Balances::free_balance(8), 100); - assert_eq!(Balances::reserved_balance(8), 1); + // Deposit for child-bounty curator deposit is reserved. + assert_eq!(Balances::free_balance(8), 101 - expected_child_deposit); + assert_eq!(Balances::reserved_balance(8), expected_child_deposit); // Bounty account status at exit. assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 40); @@ -411,7 +422,8 @@ fn award_claim_child_bounty() { assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose and accept curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + let fee = 8; + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); // Award child-bounty. @@ -423,13 +435,14 @@ fn award_claim_child_bounty() { assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + let expected_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, - fee: 2, - curator_deposit: 1, + fee, + curator_deposit: expected_deposit, status: ChildBountyStatus::PendingPayout { curator: 8, beneficiary: 7, @@ -450,11 +463,11 @@ fn award_claim_child_bounty() { assert_ok!(ChildBounties::claim_child_bounty(Origin::signed(7), 0, 0)); // Ensure child-bounty curator is paid with curator fee & deposit refund. - assert_eq!(Balances::free_balance(8), 103); + assert_eq!(Balances::free_balance(8), 101 + fee); assert_eq!(Balances::reserved_balance(8), 0); // Ensure executor is paid with beneficiary amount. - assert_eq!(Balances::free_balance(7), 8); + assert_eq!(Balances::free_balance(7), 10 - fee); assert_eq!(Balances::reserved_balance(7), 0); // Child-bounty account status. @@ -591,8 +604,8 @@ fn close_child_bounty_pending() { System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - + let parent_fee = 6; + assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, parent_fee)); assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); // Child-bounty. @@ -601,8 +614,10 @@ fn close_child_bounty_pending() { assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose and accept curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + let child_fee = 4; + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, child_fee)); assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + let expected_child_deposit = CuratorDepositMin::get(); assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); @@ -616,8 +631,8 @@ fn close_child_bounty_pending() { assert_eq!(ChildBounties::parent_child_bounties(0), 1); // Ensure no changes in child-bounty curator balance. - assert_eq!(Balances::free_balance(8), 100); - assert_eq!(Balances::reserved_balance(8), 1); + assert_eq!(Balances::reserved_balance(8), expected_child_deposit); + assert_eq!(Balances::free_balance(8), 101 - expected_child_deposit); // Child-bounty account status. assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 10); @@ -755,7 +770,6 @@ fn child_bounty_active_unassign_curator() { >::on_initialize(2); assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); // Create Child-bounty. @@ -766,16 +780,18 @@ fn child_bounty_active_unassign_curator() { >::on_initialize(3); // Propose and accept curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + let fee = 6; + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, - fee: 2, - curator_deposit: 1, + fee, + curator_deposit: expected_child_deposit, status: ChildBountyStatus::Active { curator: 8 }, } ); @@ -792,27 +808,29 @@ fn child_bounty_active_unassign_curator() { ChildBounty { parent_bounty: 0, value: 10, - fee: 2, + fee, curator_deposit: 0, status: ChildBountyStatus::Added, } ); // Ensure child-bounty curator was slashed. - assert_eq!(Balances::free_balance(8), 100); + assert_eq!(Balances::free_balance(8), 101 - expected_child_deposit); assert_eq!(Balances::reserved_balance(8), 0); // slashed // Propose and accept curator for child-bounty again. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 7, 2)); + let fee = 2; + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 7, fee)); assert_ok!(ChildBounties::accept_curator(Origin::signed(7), 0, 0)); + let expected_child_deposit = CuratorDepositMin::get(); assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, - fee: 2, - curator_deposit: 1, + fee, + curator_deposit: expected_child_deposit, status: ChildBountyStatus::Active { curator: 7 }, } ); @@ -820,7 +838,7 @@ fn child_bounty_active_unassign_curator() { System::set_block_number(5); >::on_initialize(5); - // Unassign curator again - from master curator. + // Unassign curator again - from parent curator. assert_ok!(ChildBounties::unassign_curator(Origin::signed(4), 0, 0)); // Verify updated child-bounty status. @@ -836,7 +854,7 @@ fn child_bounty_active_unassign_curator() { ); // Ensure child-bounty curator was slashed. - assert_eq!(Balances::free_balance(7), 100); + assert_eq!(Balances::free_balance(7), 101 - expected_child_deposit); assert_eq!(Balances::reserved_balance(7), 0); // slashed // Propose and accept curator for child-bounty again. @@ -848,8 +866,8 @@ fn child_bounty_active_unassign_curator() { ChildBounty { parent_bounty: 0, value: 10, - fee: 2, - curator_deposit: 1, + fee, + curator_deposit: expected_child_deposit, status: ChildBountyStatus::Active { curator: 6 }, } ); @@ -877,16 +895,18 @@ fn child_bounty_active_unassign_curator() { assert_eq!(Balances::reserved_balance(6), 0); // Propose and accept curator for child-bounty one last time. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 6, 2)); + let fee = 2; + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 6, fee)); assert_ok!(ChildBounties::accept_curator(Origin::signed(6), 0, 0)); + let expected_child_deposit = CuratorDepositMin::get(); assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, - fee: 2, - curator_deposit: 1, + fee, + curator_deposit: expected_child_deposit, status: ChildBountyStatus::Active { curator: 6 }, } ); @@ -920,7 +940,7 @@ fn child_bounty_active_unassign_curator() { ); // Ensure child-bounty curator was slashed. - assert_eq!(Balances::free_balance(6), 100); // slashed + assert_eq!(Balances::free_balance(6), 101 - expected_child_deposit); // slashed assert_eq!(Balances::reserved_balance(6), 0); }); } @@ -960,16 +980,18 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { >::on_initialize(3); // Propose and accept curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + let fee = 8; + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, - fee: 2, - curator_deposit: 1, + fee, + curator_deposit: expected_child_deposit, status: ChildBountyStatus::Active { curator: 8 }, } ); @@ -999,14 +1021,14 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { ChildBounty { parent_bounty: 0, value: 10, - fee: 2, + fee, curator_deposit: 0, status: ChildBountyStatus::Added, } ); // Ensure child-bounty curator was slashed. - assert_eq!(Balances::free_balance(8), 100); + assert_eq!(Balances::free_balance(8), 101 - expected_child_deposit); assert_eq!(Balances::reserved_balance(8), 0); // slashed System::set_block_number(6); @@ -1020,16 +1042,18 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { >::on_initialize(7); // Propose and accept curator for child-bounty again. - assert_ok!(ChildBounties::propose_curator(Origin::signed(5), 0, 0, 7, 2)); + let fee = 2; + assert_ok!(ChildBounties::propose_curator(Origin::signed(5), 0, 0, 7, fee)); assert_ok!(ChildBounties::accept_curator(Origin::signed(7), 0, 0)); + let expected_deposit = CuratorDepositMin::get(); assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, - fee: 2, - curator_deposit: 1, + fee, + curator_deposit: expected_deposit, status: ChildBountyStatus::Active { curator: 7 }, } ); @@ -1048,7 +1072,7 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { System::set_block_number(9); >::on_initialize(9); - // Unassign curator again - from master curator. + // Unassign curator again - from parent curator. assert_ok!(ChildBounties::unassign_curator(Origin::signed(7), 0, 0)); // Verify updated child-bounty status. @@ -1157,25 +1181,26 @@ fn children_curator_fee_calculation_test() { System::set_block_number(4); >::on_initialize(4); - // Propose curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + let fee = 6; + // Propose curator for child-bounty. + assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); // Check curator fee added to the sum. - assert_eq!(ChildBounties::children_curator_fees(0), 2); - + assert_eq!(ChildBounties::children_curator_fees(0), fee); // Accept curator for child-bounty. assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); - // Award child-bounty. assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + let expected_child_deposit = CuratorDepositMultiplier::get() * fee; + assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, - fee: 2, - curator_deposit: 1, + fee, + curator_deposit: expected_child_deposit, status: ChildBountyStatus::PendingPayout { curator: 8, beneficiary: 7, @@ -1201,7 +1226,7 @@ fn children_curator_fee_calculation_test() { assert_ok!(Bounties::claim_bounty(Origin::signed(9), 0)); // Ensure parent-bounty curator received correctly reduced fee. - assert_eq!(Balances::free_balance(4), 105); // 101 + 6 - 2 + assert_eq!(Balances::free_balance(4), 101 + 6 - fee); // 101 + 6 - 2 assert_eq!(Balances::reserved_balance(4), 0); // Verify parent-bounty beneficiary balance. @@ -1209,3 +1234,176 @@ fn children_curator_fee_calculation_test() { assert_eq!(Balances::reserved_balance(9), 0); }); } + +#[test] +fn accept_curator_handles_different_deposit_calculations() { + // This test will verify that a bounty with and without a fee results + // in a different curator deposit, and if the child curator matches the parent curator. + new_test_ext().execute_with(|| { + // Setup a parent bounty. + let parent_curator = 0; + let parent_index = 0; + let parent_value = 1_000_000; + let parent_fee = 10_000; + + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), parent_value * 3); + Balances::make_free_balance_be(&parent_curator, parent_fee * 100); + assert_ok!(Bounties::propose_bounty( + Origin::signed(parent_curator), + parent_value, + b"12345".to_vec() + )); + assert_ok!(Bounties::approve_bounty(Origin::root(), parent_index)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_ok!(Bounties::propose_curator( + Origin::root(), + parent_index, + parent_curator, + parent_fee + )); + assert_ok!(Bounties::accept_curator(Origin::signed(parent_curator), parent_index)); + + // Now we can start creating some child bounties. + // Case 1: Parent and child curator are not the same. + + let child_index = 0; + let child_curator = 1; + let child_value = 1_000; + let child_fee = 100; + let starting_balance = 100 * child_fee + child_value; + + Balances::make_free_balance_be(&child_curator, starting_balance); + assert_ok!(ChildBounties::add_child_bounty( + Origin::signed(parent_curator), + parent_index, + child_value, + b"12345-p1".to_vec() + )); + System::set_block_number(3); + >::on_initialize(3); + assert_ok!(ChildBounties::propose_curator( + Origin::signed(parent_curator), + parent_index, + child_index, + child_curator, + child_fee + )); + assert_ok!(ChildBounties::accept_curator( + Origin::signed(child_curator), + parent_index, + child_index + )); + + let expected_deposit = CuratorDepositMultiplier::get() * child_fee; + assert_eq!(Balances::free_balance(child_curator), starting_balance - expected_deposit); + assert_eq!(Balances::reserved_balance(child_curator), expected_deposit); + + // Case 2: Parent and child curator are the same. + + let child_index = 1; + let child_curator = parent_curator; // The same as parent bounty curator + let child_value = 1_000; + let child_fee = 10; + + let free_before = Balances::free_balance(&parent_curator); + let reserved_before = Balances::reserved_balance(&parent_curator); + + assert_ok!(ChildBounties::add_child_bounty( + Origin::signed(parent_curator), + parent_index, + child_value, + b"12345-p1".to_vec() + )); + System::set_block_number(4); + >::on_initialize(4); + assert_ok!(ChildBounties::propose_curator( + Origin::signed(parent_curator), + parent_index, + child_index, + child_curator, + child_fee + )); + assert_ok!(ChildBounties::accept_curator( + Origin::signed(child_curator), + parent_index, + child_index + )); + + // No expected deposit + assert_eq!(Balances::free_balance(child_curator), free_before); + assert_eq!(Balances::reserved_balance(child_curator), reserved_before); + + // Case 3: Upper Limit + + let child_index = 2; + let child_curator = 2; + let child_value = 10_000; + let child_fee = 5_000; + + Balances::make_free_balance_be(&child_curator, starting_balance); + assert_ok!(ChildBounties::add_child_bounty( + Origin::signed(parent_curator), + parent_index, + child_value, + b"12345-p1".to_vec() + )); + System::set_block_number(5); + >::on_initialize(5); + assert_ok!(ChildBounties::propose_curator( + Origin::signed(parent_curator), + parent_index, + child_index, + child_curator, + child_fee + )); + assert_ok!(ChildBounties::accept_curator( + Origin::signed(child_curator), + parent_index, + child_index + )); + + let expected_deposit = CuratorDepositMax::get(); + assert_eq!(Balances::free_balance(child_curator), starting_balance - expected_deposit); + assert_eq!(Balances::reserved_balance(child_curator), expected_deposit); + + // There is a max number of child bounties at a time. + assert_ok!(ChildBounties::impl_close_child_bounty(parent_index, child_index)); + + // Case 4: Lower Limit + + let child_index = 3; + let child_curator = 3; + let child_value = 10_000; + let child_fee = 0; + + Balances::make_free_balance_be(&child_curator, starting_balance); + assert_ok!(ChildBounties::add_child_bounty( + Origin::signed(parent_curator), + parent_index, + child_value, + b"12345-p1".to_vec() + )); + System::set_block_number(5); + >::on_initialize(5); + assert_ok!(ChildBounties::propose_curator( + Origin::signed(parent_curator), + parent_index, + child_index, + child_curator, + child_fee + )); + assert_ok!(ChildBounties::accept_curator( + Origin::signed(child_curator), + parent_index, + child_index + )); + + let expected_deposit = CuratorDepositMin::get(); + assert_eq!(Balances::free_balance(child_curator), starting_balance - expected_deposit); + assert_eq!(Balances::reserved_balance(child_curator), expected_deposit); + }); +} From 318dea38c9d8af7b526b35a619c393b08ad236ce Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Fri, 25 Mar 2022 21:45:01 +0800 Subject: [PATCH 0637/1472] pallet-conviction-voting: make the pallet instantiable (#11088) * pallet-conviction-voting: make the pallet instanceable Signed-off-by: koushiro * Add default type param for some type alias Signed-off-by: koushiro --- frame/conviction-voting/src/conviction.rs | 4 +- frame/conviction-voting/src/lib.rs | 185 ++++++++++++---------- frame/conviction-voting/src/tests.rs | 5 +- frame/conviction-voting/src/types.rs | 5 +- 4 files changed, 109 insertions(+), 90 deletions(-) diff --git a/frame/conviction-voting/src/conviction.rs b/frame/conviction-voting/src/conviction.rs index 129f2771124b5..1feff35b19fcc 100644 --- a/frame/conviction-voting/src/conviction.rs +++ b/frame/conviction-voting/src/conviction.rs @@ -17,14 +17,14 @@ //! The conviction datatype. -use crate::types::Delegations; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ traits::{Bounded, CheckedDiv, CheckedMul, Zero}, RuntimeDebug, }; -use sp_std::{convert::TryFrom, result::Result}; + +use crate::types::Delegations; /// A value denoting the strength of conviction of a vote. #[derive( diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index 8e7e0d91b1cf4..af91e99fb3796 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -28,6 +28,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::{ + dispatch::{DispatchError, DispatchResult}, ensure, traits::{ fungible, Currency, Get, LockIdentifier, LockableCurrency, PollStatus, Polling, @@ -36,7 +37,7 @@ use frame_support::{ }; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Saturating, Zero}, - ArithmeticError, DispatchError, DispatchResult, Perbill, + ArithmeticError, Perbill, }; use sp_std::prelude::*; @@ -44,11 +45,14 @@ mod conviction; mod types; mod vote; pub mod weights; -pub use conviction::Conviction; -pub use pallet::*; -pub use types::{Delegations, Tally, UnvoteScope}; -pub use vote::{AccountVote, Casting, Delegating, Vote, Voting}; -pub use weights::WeightInfo; + +pub use self::{ + conviction::Conviction, + pallet::*, + types::{Delegations, Tally, UnvoteScope}, + vote::{AccountVote, Casting, Delegating, Vote, Voting}, + weights::WeightInfo, +}; #[cfg(test)] mod tests; @@ -58,44 +62,43 @@ pub mod benchmarking; const CONVICTION_VOTING_ID: LockIdentifier = *b"pyconvot"; -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; -type VotingOf = Voting< - BalanceOf, +type BalanceOf = + <>::Currency as Currency<::AccountId>>::Balance; +type VotingOf = Voting< + BalanceOf, ::AccountId, ::BlockNumber, - PollIndexOf, - ::MaxVotes, + PollIndexOf, + >::MaxVotes, >; #[allow(dead_code)] -type DelegatingOf = Delegating< - BalanceOf, +type DelegatingOf = Delegating< + BalanceOf, ::AccountId, ::BlockNumber, >; -pub type TallyOf = Tally, ::MaxTurnout>; -pub type VotesOf = BalanceOf; -type PollIndexOf = <::Polls as Polling>>::Index; +pub type TallyOf = Tally, >::MaxTurnout>; +pub type VotesOf = BalanceOf; +type PollIndexOf = <>::Polls as Polling>>::Index; #[cfg(feature = "runtime-benchmarks")] -type IndexOf = <::Polls as Polling>>::Index; -type ClassOf = <::Polls as Polling>>::Class; +type IndexOf = <>::Polls as Polling>>::Index; +type ClassOf = <>::Polls as Polling>>::Class; #[frame_support::pallet] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - use sp_runtime::DispatchResult; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] - pub struct Pallet(_); + pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + Sized { + pub trait Config: frame_system::Config + Sized { // System level stuff. - type Event: From> + IsType<::Event>; + type Event: From> + IsType<::Event>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// Currency type with which voting happens. @@ -104,12 +107,16 @@ pub mod pallet { + fungible::Inspect; /// The implementation of the logic which conducts polls. - type Polls: Polling, Votes = BalanceOf, Moment = Self::BlockNumber>; + type Polls: Polling< + TallyOf, + Votes = BalanceOf, + Moment = Self::BlockNumber, + >; /// The maximum amount of tokens which may be used for voting. May just be /// `Currency::total_issuance`, but you might want to reduce this in order to account for /// funds in the system which are unable to vote (e.g. parachain auction deposits). - type MaxTurnout: Get>; + type MaxTurnout: Get>; /// The maximum number of concurrent votes an account may have. /// @@ -129,13 +136,13 @@ pub mod pallet { /// All voting for a particular voter in a particular voting class. We store the balance for the /// number of votes that we have recorded. #[pallet::storage] - pub type VotingFor = StorageDoubleMap< + pub type VotingFor, I: 'static = ()> = StorageDoubleMap< _, Twox64Concat, T::AccountId, Twox64Concat, - ClassOf, - VotingOf, + ClassOf, + VotingOf, ValueQuery, >; @@ -143,12 +150,17 @@ pub mod pallet { /// require. The actual amount locked on behalf of this pallet should always be the maximum of /// this list. #[pallet::storage] - pub type ClassLocksFor = - StorageMap<_, Twox64Concat, T::AccountId, Vec<(ClassOf, BalanceOf)>, ValueQuery>; + pub type ClassLocksFor, I: 'static = ()> = StorageMap< + _, + Twox64Concat, + T::AccountId, + Vec<(ClassOf, BalanceOf)>, + ValueQuery, + >; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { + pub enum Event, I: 'static = ()> { /// An account has delegated their vote to another account. \[who, target\] Delegated(T::AccountId, T::AccountId), /// An \[account\] has cancelled a previous delegation operation. @@ -156,7 +168,7 @@ pub mod pallet { } #[pallet::error] - pub enum Error { + pub enum Error { /// Poll is not ongoing. NotOngoing, /// The given account did not vote on the poll. @@ -185,7 +197,7 @@ pub mod pallet { } #[pallet::call] - impl Pallet { + impl, I: 'static> Pallet { /// Vote in a poll. If `vote.is_aye()`, the vote is to enact the proposal; /// otherwise it is a vote to keep the status quo. /// @@ -198,8 +210,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::vote_new().max(T::WeightInfo::vote_existing()))] pub fn vote( origin: OriginFor, - #[pallet::compact] poll_index: PollIndexOf, - vote: AccountVote>, + #[pallet::compact] poll_index: PollIndexOf, + vote: AccountVote>, ) -> DispatchResult { let who = ensure_signed(origin)?; Self::try_vote(&who, poll_index, vote) @@ -233,10 +245,10 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::delegate(T::MaxVotes::get()))] pub fn delegate( origin: OriginFor, - class: ClassOf, + class: ClassOf, to: T::AccountId, conviction: Conviction, - balance: BalanceOf, + balance: BalanceOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let votes = Self::try_delegate(who, class, to, conviction, balance)?; @@ -261,7 +273,10 @@ pub mod pallet { // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure // because a valid delegation cover decoding a direct voting with max votes. #[pallet::weight(T::WeightInfo::undelegate(T::MaxVotes::get().into()))] - pub fn undelegate(origin: OriginFor, class: ClassOf) -> DispatchResultWithPostInfo { + pub fn undelegate( + origin: OriginFor, + class: ClassOf, + ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let votes = Self::try_undelegate(who, class)?; Ok(Some(T::WeightInfo::undelegate(votes)).into()) @@ -279,7 +294,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::unlock())] pub fn unlock( origin: OriginFor, - class: ClassOf, + class: ClassOf, target: T::AccountId, ) -> DispatchResult { ensure_signed(origin)?; @@ -319,8 +334,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_vote())] pub fn remove_vote( origin: OriginFor, - class: Option>, - index: PollIndexOf, + class: Option>, + index: PollIndexOf, ) -> DispatchResult { let who = ensure_signed(origin)?; Self::try_remove_vote(&who, index, class, UnvoteScope::Any) @@ -346,8 +361,8 @@ pub mod pallet { pub fn remove_other_vote( origin: OriginFor, target: T::AccountId, - class: ClassOf, - index: PollIndexOf, + class: ClassOf, + index: PollIndexOf, ) -> DispatchResult { let who = ensure_signed(origin)?; let scope = if target == who { UnvoteScope::Any } else { UnvoteScope::OnlyExpired }; @@ -357,17 +372,17 @@ pub mod pallet { } } -impl Pallet { +impl, I: 'static> Pallet { /// Actually enact a vote, if legit. fn try_vote( who: &T::AccountId, - poll_index: PollIndexOf, - vote: AccountVote>, + poll_index: PollIndexOf, + vote: AccountVote>, ) -> DispatchResult { - ensure!(vote.balance() <= T::Currency::free_balance(who), Error::::InsufficientFunds); + ensure!(vote.balance() <= T::Currency::free_balance(who), Error::::InsufficientFunds); T::Polls::try_access_poll(poll_index, |poll_status| { - let (tally, class) = poll_status.ensure_ongoing().ok_or(Error::::NotOngoing)?; - VotingFor::::try_mutate(who, &class, |voting| { + let (tally, class) = poll_status.ensure_ongoing().ok_or(Error::::NotOngoing)?; + VotingFor::::try_mutate(who, &class, |voting| { if let Voting::Casting(Casting { ref mut votes, delegations, .. }) = voting { match votes.binary_search_by_key(&poll_index, |i| i.0) { Ok(i) => { @@ -381,7 +396,7 @@ impl Pallet { Err(i) => { votes .try_insert(i, (poll_index, vote)) - .map_err(|()| Error::::MaxVotesReached)?; + .map_err(|()| Error::::MaxVotesReached)?; }, } // Shouldn't be possible to fail, but we handle it gracefully. @@ -390,7 +405,7 @@ impl Pallet { tally.increase(approve, *delegations); } } else { - return Err(Error::::AlreadyDelegating.into()) + return Err(Error::::AlreadyDelegating.into()) } // Extend the lock to `balance` (rather than setting it) since we don't know what // other votes are in place. @@ -408,23 +423,23 @@ impl Pallet { /// This will generally be combined with a call to `unlock`. fn try_remove_vote( who: &T::AccountId, - poll_index: PollIndexOf, - class_hint: Option>, + poll_index: PollIndexOf, + class_hint: Option>, scope: UnvoteScope, ) -> DispatchResult { let class = class_hint .or_else(|| Some(T::Polls::as_ongoing(poll_index)?.1)) - .ok_or(Error::::ClassNeeded)?; - VotingFor::::try_mutate(who, class, |voting| { + .ok_or(Error::::ClassNeeded)?; + VotingFor::::try_mutate(who, class, |voting| { if let Voting::Casting(Casting { ref mut votes, delegations, ref mut prior }) = voting { let i = votes .binary_search_by_key(&poll_index, |i| i.0) - .map_err(|_| Error::::NotVoter)?; + .map_err(|_| Error::::NotVoter)?; let v = votes.remove(i); T::Polls::try_access_poll(poll_index, |poll_status| match poll_status { PollStatus::Ongoing(tally, _) => { - ensure!(matches!(scope, UnvoteScope::Any), Error::::NoPermission); + ensure!(matches!(scope, UnvoteScope::Any), Error::::NoPermission); // Shouldn't be possible to fail, but we handle it gracefully. tally.remove(v.1).ok_or(ArithmeticError::Underflow)?; if let Some(approve) = v.1.as_standard() { @@ -441,7 +456,7 @@ impl Pallet { if now < unlock_at { ensure!( matches!(scope, UnvoteScope::Any), - Error::::NoPermissionYet + Error::::NoPermissionYet ); prior.accumulate(unlock_at, balance) } @@ -459,10 +474,10 @@ impl Pallet { /// Return the number of votes for `who` fn increase_upstream_delegation( who: &T::AccountId, - class: &ClassOf, - amount: Delegations>, + class: &ClassOf, + amount: Delegations>, ) -> u32 { - VotingFor::::mutate(who, class, |voting| match voting { + VotingFor::::mutate(who, class, |voting| match voting { Voting::Delegating(Delegating { delegations, .. }) => { // We don't support second level delegating, so we don't need to do anything more. *delegations = delegations.saturating_add(amount); @@ -487,10 +502,10 @@ impl Pallet { /// Return the number of votes for `who` fn reduce_upstream_delegation( who: &T::AccountId, - class: &ClassOf, - amount: Delegations>, + class: &ClassOf, + amount: Delegations>, ) -> u32 { - VotingFor::::mutate(who, class, |voting| match voting { + VotingFor::::mutate(who, class, |voting| match voting { Voting::Delegating(Delegating { delegations, .. }) => { // We don't support second level delegating, so we don't need to do anything more. *delegations = delegations.saturating_sub(amount); @@ -517,16 +532,16 @@ impl Pallet { /// Return the upstream number of votes. fn try_delegate( who: T::AccountId, - class: ClassOf, + class: ClassOf, target: T::AccountId, conviction: Conviction, - balance: BalanceOf, + balance: BalanceOf, ) -> Result { - ensure!(who != target, Error::::Nonsense); - T::Polls::classes().binary_search(&class).map_err(|_| Error::::BadClass)?; - ensure!(balance <= T::Currency::free_balance(&who), Error::::InsufficientFunds); + ensure!(who != target, Error::::Nonsense); + T::Polls::classes().binary_search(&class).map_err(|_| Error::::BadClass)?; + ensure!(balance <= T::Currency::free_balance(&who), Error::::InsufficientFunds); let votes = - VotingFor::::try_mutate(&who, &class, |voting| -> Result { + VotingFor::::try_mutate(&who, &class, |voting| -> Result { let old = sp_std::mem::replace( voting, Voting::Delegating(Delegating { @@ -538,10 +553,10 @@ impl Pallet { }), ); match old { - Voting::Delegating(Delegating { .. }) => Err(Error::::AlreadyDelegating)?, + Voting::Delegating(Delegating { .. }) => Err(Error::::AlreadyDelegating)?, Voting::Casting(Casting { votes, delegations, prior }) => { // here we just ensure that we're currently idling with no votes recorded. - ensure!(votes.is_empty(), Error::::AlreadyVoting); + ensure!(votes.is_empty(), Error::::AlreadyVoting); voting.set_common(delegations, prior); }, } @@ -553,16 +568,16 @@ impl Pallet { Self::extend_lock(&who, &class, balance); Ok(votes) })?; - Self::deposit_event(Event::::Delegated(who, target)); + Self::deposit_event(Event::::Delegated(who, target)); Ok(votes) } /// Attempt to end the current delegation. /// /// Return the number of votes of upstream. - fn try_undelegate(who: T::AccountId, class: ClassOf) -> Result { + fn try_undelegate(who: T::AccountId, class: ClassOf) -> Result { let votes = - VotingFor::::try_mutate(&who, &class, |voting| -> Result { + VotingFor::::try_mutate(&who, &class, |voting| -> Result { match sp_std::mem::replace(voting, Voting::default()) { Voting::Delegating(Delegating { balance, @@ -589,29 +604,31 @@ impl Pallet { Ok(votes) }, - Voting::Casting(_) => Err(Error::::NotDelegating.into()), + Voting::Casting(_) => Err(Error::::NotDelegating.into()), } })?; - Self::deposit_event(Event::::Undelegated(who)); + Self::deposit_event(Event::::Undelegated(who)); Ok(votes) } - fn extend_lock(who: &T::AccountId, class: &ClassOf, amount: BalanceOf) { - ClassLocksFor::::mutate(who, |locks| match locks.iter().position(|x| &x.0 == class) { - Some(i) => locks[i].1 = locks[i].1.max(amount), - None => locks.push((class.clone(), amount)), + fn extend_lock(who: &T::AccountId, class: &ClassOf, amount: BalanceOf) { + ClassLocksFor::::mutate(who, |locks| { + match locks.iter().position(|x| &x.0 == class) { + Some(i) => locks[i].1 = locks[i].1.max(amount), + None => locks.push((class.clone(), amount)), + } }); T::Currency::extend_lock(CONVICTION_VOTING_ID, who, amount, WithdrawReasons::TRANSFER); } /// Rejig the lock on an account. It will never get more stringent (since that would indicate /// a security hole) but may be reduced from what they are currently. - fn update_lock(class: &ClassOf, who: &T::AccountId) { - let class_lock_needed = VotingFor::::mutate(who, class, |voting| { + fn update_lock(class: &ClassOf, who: &T::AccountId) { + let class_lock_needed = VotingFor::::mutate(who, class, |voting| { voting.rejig(frame_system::Pallet::::block_number()); voting.locked_balance() }); - let lock_needed = ClassLocksFor::::mutate(who, |locks| { + let lock_needed = ClassLocksFor::::mutate(who, |locks| { locks.retain(|x| &x.0 != class); if !class_lock_needed.is_zero() { locks.push((class.clone(), class_lock_needed)); diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index cedb23b02a8db..6a8bad5d8944e 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -19,8 +19,6 @@ use std::collections::BTreeMap; -use super::*; -use crate as pallet_conviction_voting; use frame_support::{ assert_noop, assert_ok, parameter_types, traits::{ConstU32, ConstU64, Contains, Polling}, @@ -31,6 +29,9 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, }; +use super::*; +use crate as pallet_conviction_voting; + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; diff --git a/frame/conviction-voting/src/types.rs b/frame/conviction-voting/src/types.rs index 2ad1a164dd143..e2b5844ddd5df 100644 --- a/frame/conviction-voting/src/types.rs +++ b/frame/conviction-voting/src/types.rs @@ -19,8 +19,6 @@ use sp_std::marker::PhantomData; -use super::*; -use crate::{AccountVote, Conviction, Vote}; use codec::{Codec, Decode, Encode, MaxEncodedLen}; use frame_support::{ traits::VoteTally, CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, @@ -32,6 +30,9 @@ use sp_runtime::{ RuntimeDebug, }; +use super::*; +use crate::{AccountVote, Conviction, Vote}; + /// Info regarding an ongoing referendum. #[derive( CloneNoBound, From 411d9bb4c551c65acb55bc67443f05fe631f9330 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 25 Mar 2022 17:31:42 +0200 Subject: [PATCH 0638/1472] Implement Lean BEEFY (#10882) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplified BEEFY worker logic based on the invariant that GRANDPA will always finalize 1st block of each new session, meaning BEEFY worker is guaranteed to receive finality notification for the BEEFY mandatory blocks. Under these conditions the current design is as follows: - session changes are detected based on BEEFY Digest present in BEEFY mandatory blocks, - on each new session new `Rounds` of voting is created, with old rounds being dropped (for gossip rounds, last 3 are still alive so votes are still being gossiped), - after processing finality for a block, the worker votes if a new voting target has become available as a result of said block finality processing, - incoming votes as well as self-created votes are processed and signed commitments are created for completed BEEFY voting rounds, - the worker votes if a new voting target becomes available once a round successfully completes. On worker startup, the current validator set is retrieved from the BEEFY pallet. If it is the genesis validator set, worker starts voting right away considering Block #1 as session start. Otherwise (not genesis), the worker will vote starting with mandatory block of the next session. Later on when we add the BEEFY initial-sync (catch-up) logic, the worker will sync all past mandatory blocks Signed Commitments and will be able to start voting right away. BEEFY mandatory block is the block with header containing the BEEFY `AuthoritiesChange` Digest, this block is guaranteed to be finalized by GRANDPA. This session-boundary block is signed by the ending-session's validator set. Next blocks will be signed by the new session's validator set. This behavior is consistent with what GRANDPA does as well. Also drop the limit N on active gossip rounds. In an adversarial network, a bad actor could create and gossip N invalid votes with round numbers larger than the current correct round number. This would lead to votes for correct rounds to no longer be gossiped. Add unit-tests for all components, including full voter consensus tests. Signed-off-by: Adrian Catangiu Co-authored-by: Tomasz Drwięga Co-authored-by: David Salami --- Cargo.lock | 10 + client/beefy/Cargo.toml | 14 +- client/beefy/src/gossip.rs | 306 ++++++----- client/beefy/src/lib.rs | 73 +-- client/beefy/src/metrics.rs | 13 +- client/beefy/src/round.rs | 358 +++++++++---- client/beefy/src/tests.rs | 590 ++++++++++++++++++++ client/beefy/src/worker.rs | 978 ++++++++++++++++++++++++---------- frame/beefy/src/lib.rs | 28 +- primitives/beefy/Cargo.toml | 5 + test-utils/runtime/Cargo.toml | 2 + test-utils/runtime/src/lib.rs | 6 + 12 files changed, 1815 insertions(+), 568 deletions(-) create mode 100644 client/beefy/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 1731ded2906cf..81a53ed858859 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -484,12 +484,15 @@ dependencies = [ "beefy-primitives", "fnv", "futures 0.3.19", + "futures-timer", "hex", "log 0.4.14", "parity-scale-codec", "parking_lot 0.12.0", "sc-chain-spec", "sc-client-api", + "sc-consensus", + "sc-finality-grandpa", "sc-keystore", "sc-network", "sc-network-gossip", @@ -500,13 +503,19 @@ dependencies = [ "sp-application-crypto", "sp-arithmetic", "sp-blockchain", + "sp-consensus", "sp-core", + "sp-finality-grandpa", + "sp-keyring", "sp-keystore", "sp-runtime", "sp-tracing", "strum", "substrate-prometheus-endpoint", + "substrate-test-runtime-client", + "tempfile", "thiserror", + "tokio", "wasm-timer", ] @@ -10688,6 +10697,7 @@ dependencies = [ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ + "beefy-primitives", "cfg-if 1.0.0", "frame-support", "frame-system", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 1cd0f1fd50d80..02be645b3fc08 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -10,6 +10,7 @@ description = "BEEFY Client gadget for substrate" [dependencies] fnv = "1.0.6" futures = "0.3" +futures-timer = "3.0.1" hex = "0.4.2" log = "0.4" parking_lot = "0.12.0" @@ -23,22 +24,31 @@ sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } -sc-utils = { version = "4.0.0-dev", path = "../utils" } sc-client-api = { version = "4.0.0-dev", path = "../api" } +sc-finality-grandpa = { version = "0.10.0-dev", path = "../../client/finality-grandpa" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } +sc-utils = { version = "4.0.0-dev", path = "../utils" } beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } [dev-dependencies] -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sc-network-test = { version = "0.8.0", path = "../network/test" } +sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } +sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } + serde = "1.0.136" strum = { version = "0.23", features = ["derive"] } +tokio = "1.15" +tempfile = "3.1.0" diff --git a/client/beefy/src/gossip.rs b/client/beefy/src/gossip.rs index 37358441ef88a..54d283fede32e 100644 --- a/client/beefy/src/gossip.rs +++ b/client/beefy/src/gossip.rs @@ -35,9 +35,6 @@ use beefy_primitives::{ use crate::keystore::BeefyKeystore; -// Limit BEEFY gossip by keeping only a bound number of voting rounds alive. -const MAX_LIVE_GOSSIP_ROUNDS: usize = 3; - // Timeout for rebroadcasting messages. const REBROADCAST_AFTER: Duration = Duration::from_secs(60 * 5); @@ -52,13 +49,50 @@ where /// A type that represents hash of the message. pub type MessageHash = [u8; 8]; -type KnownVotes = BTreeMap, fnv::FnvHashSet>; +struct KnownVotes { + last_done: Option>, + live: BTreeMap, fnv::FnvHashSet>, +} + +impl KnownVotes { + pub fn new() -> Self { + Self { last_done: None, live: BTreeMap::new() } + } + + /// Create new round votes set if not already present. + fn insert(&mut self, round: NumberFor) { + self.live.entry(round).or_default(); + } + + /// Remove `round` and older from live set, update `last_done` accordingly. + fn conclude(&mut self, round: NumberFor) { + self.live.retain(|&number, _| number > round); + self.last_done = self.last_done.max(Some(round)); + } + + /// Return true if `round` is newer than previously concluded rounds. + /// + /// Latest concluded round is still considered alive to allow proper gossiping for it. + fn is_live(&self, round: &NumberFor) -> bool { + Some(*round) >= self.last_done + } + + /// Add new _known_ `hash` to the round's known votes. + fn add_known(&mut self, round: &NumberFor, hash: MessageHash) { + self.live.get_mut(round).map(|known| known.insert(hash)); + } + + /// Check if `hash` is already part of round's known votes. + fn is_known(&self, round: &NumberFor, hash: &MessageHash) -> bool { + self.live.get(round).map(|known| known.contains(hash)).unwrap_or(false) + } +} /// BEEFY gossip validator /// /// Validate BEEFY gossip messages and limit the number of live BEEFY voting rounds. /// -/// Allows messages from last [`MAX_LIVE_GOSSIP_ROUNDS`] to flow, everything else gets +/// Allows messages for 'rounds >= last concluded' to flow, everything else gets /// rejected/expired. /// ///All messaging is handled in a single BEEFY global topic. @@ -78,57 +112,25 @@ where pub fn new() -> GossipValidator { GossipValidator { topic: topic::(), - known_votes: RwLock::new(BTreeMap::new()), + known_votes: RwLock::new(KnownVotes::new()), next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), } } /// Note a voting round. /// - /// Noting `round` will keep `round` live. - /// - /// We retain the [`MAX_LIVE_GOSSIP_ROUNDS`] most **recent** voting rounds as live. - /// As long as a voting round is live, it will be gossiped to peer nodes. + /// Noting round will start a live `round`. pub(crate) fn note_round(&self, round: NumberFor) { - debug!(target: "beefy", "🥩 About to note round #{}", round); - - let mut live = self.known_votes.write(); - - if !live.contains_key(&round) { - live.insert(round, Default::default()); - } - - if live.len() > MAX_LIVE_GOSSIP_ROUNDS { - let to_remove = live.iter().next().map(|x| x.0).copied(); - if let Some(first) = to_remove { - live.remove(&first); - } - } - } - - fn add_known(known_votes: &mut KnownVotes, round: &NumberFor, hash: MessageHash) { - known_votes.get_mut(round).map(|known| known.insert(hash)); - } - - // Note that we will always keep the most recent unseen round alive. - // - // This is a preliminary fix and the detailed description why we are - // doing this can be found as part of the issue below - // - // https://github.com/paritytech/grandpa-bridge-gadget/issues/237 - // - fn is_live(known_votes: &KnownVotes, round: &NumberFor) -> bool { - let unseen_round = if let Some(max_known_round) = known_votes.keys().last() { - round > max_known_round - } else { - known_votes.is_empty() - }; - - known_votes.contains_key(round) || unseen_round + debug!(target: "beefy", "🥩 About to note gossip round #{}", round); + self.known_votes.write().insert(round); } - fn is_known(known_votes: &KnownVotes, round: &NumberFor, hash: &MessageHash) -> bool { - known_votes.get(round).map(|known| known.contains(hash)).unwrap_or(false) + /// Conclude a voting round. + /// + /// This can be called once round is complete so we stop gossiping for it. + pub(crate) fn conclude_round(&self, round: NumberFor) { + debug!(target: "beefy", "🥩 About to drop gossip round #{}", round); + self.known_votes.write().conclude(round); } } @@ -152,17 +154,17 @@ where { let known_votes = self.known_votes.read(); - if !GossipValidator::::is_live(&known_votes, &round) { + if !known_votes.is_live(&round) { return ValidationResult::Discard } - if GossipValidator::::is_known(&known_votes, &round, &msg_hash) { + if known_votes.is_known(&round, &msg_hash) { return ValidationResult::ProcessAndKeep(self.topic) } } if BeefyKeystore::verify(&msg.id, &msg.signature, &msg.commitment.encode()) { - GossipValidator::::add_known(&mut *self.known_votes.write(), &round, msg_hash); + self.known_votes.write().add_known(&round, msg_hash); return ValidationResult::ProcessAndKeep(self.topic) } else { // TODO: report peer @@ -182,7 +184,7 @@ where }; let round = msg.commitment.block_number; - let expired = !GossipValidator::::is_live(&known_votes, &round); + let expired = !known_votes.is_live(&round); trace!(target: "beefy", "🥩 Message for round #{} expired: {}", round, expired); @@ -212,11 +214,11 @@ where let msg = match VoteMessage::, Public, Signature>::decode(&mut data) { Ok(vote) => vote, - Err(_) => return true, + Err(_) => return false, }; let round = msg.commitment.block_number; - let allowed = GossipValidator::::is_live(&known_votes, &round); + let allowed = known_votes.is_live(&round); debug!(target: "beefy", "🥩 Message for round #{} allowed: {}", round, allowed); @@ -240,60 +242,58 @@ mod tests { use super::*; #[test] - fn note_round_works() { - let gv = GossipValidator::::new(); - - gv.note_round(1u64); - - let live = gv.known_votes.read(); - assert!(GossipValidator::::is_live(&live, &1u64)); - - drop(live); - - gv.note_round(3u64); - gv.note_round(7u64); - gv.note_round(10u64); - - let live = gv.known_votes.read(); - - assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); - - assert!(!GossipValidator::::is_live(&live, &1u64)); - assert!(GossipValidator::::is_live(&live, &3u64)); - assert!(GossipValidator::::is_live(&live, &7u64)); - assert!(GossipValidator::::is_live(&live, &10u64)); + fn known_votes_insert_remove() { + let mut kv = KnownVotes::::new(); + + kv.insert(1); + kv.insert(1); + kv.insert(2); + assert_eq!(kv.live.len(), 2); + + let mut kv = KnownVotes::::new(); + kv.insert(1); + kv.insert(2); + kv.insert(3); + + assert!(kv.last_done.is_none()); + kv.conclude(2); + assert_eq!(kv.live.len(), 1); + assert!(!kv.live.contains_key(&2)); + assert_eq!(kv.last_done, Some(2)); + + kv.conclude(1); + assert_eq!(kv.last_done, Some(2)); + + kv.conclude(3); + assert_eq!(kv.last_done, Some(3)); + assert!(kv.live.is_empty()); } #[test] - fn keeps_most_recent_max_rounds() { + fn note_and_drop_round_works() { let gv = GossipValidator::::new(); - gv.note_round(3u64); - gv.note_round(7u64); - gv.note_round(10u64); gv.note_round(1u64); - let live = gv.known_votes.read(); - - assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + assert!(gv.known_votes.read().is_live(&1u64)); - assert!(GossipValidator::::is_live(&live, &3u64)); - assert!(!GossipValidator::::is_live(&live, &1u64)); - - drop(live); + gv.note_round(3u64); + gv.note_round(7u64); + gv.note_round(10u64); - gv.note_round(23u64); - gv.note_round(15u64); - gv.note_round(20u64); - gv.note_round(2u64); + assert_eq!(gv.known_votes.read().live.len(), 4); - let live = gv.known_votes.read(); + gv.conclude_round(7u64); - assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + let votes = gv.known_votes.read(); - assert!(GossipValidator::::is_live(&live, &15u64)); - assert!(GossipValidator::::is_live(&live, &20u64)); - assert!(GossipValidator::::is_live(&live, &23u64)); + // rounds 1 and 3 are outdated, don't gossip anymore + assert!(!votes.is_live(&1u64)); + assert!(!votes.is_live(&3u64)); + // latest concluded round is still gossiped + assert!(votes.is_live(&7u64)); + // round 10 is alive and in-progress + assert!(votes.is_live(&10u64)); } #[test] @@ -304,22 +304,18 @@ mod tests { gv.note_round(7u64); gv.note_round(10u64); - let live = gv.known_votes.read(); - - assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); - - drop(live); + assert_eq!(gv.known_votes.read().live.len(), 3); // note round #7 again -> should not change anything gv.note_round(7u64); - let live = gv.known_votes.read(); + let votes = gv.known_votes.read(); - assert_eq!(live.len(), MAX_LIVE_GOSSIP_ROUNDS); + assert_eq!(votes.live.len(), 3); - assert!(GossipValidator::::is_live(&live, &3u64)); - assert!(GossipValidator::::is_live(&live, &7u64)); - assert!(GossipValidator::::is_live(&live, &10u64)); + assert!(votes.is_live(&3u64)); + assert!(votes.is_live(&7u64)); + assert!(votes.is_live(&10u64)); } struct TestContext; @@ -349,29 +345,32 @@ mod tests { beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() } + fn dummy_vote(block_number: u64) -> VoteMessage { + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, MmrRootHash::default().encode()); + let commitment = Commitment { payload, block_number, validator_set_id: 0 }; + let signature = sign_commitment(&Keyring::Alice, &commitment); + + VoteMessage { commitment, id: Keyring::Alice.public(), signature } + } + #[test] fn should_avoid_verifying_signatures_twice() { let gv = GossipValidator::::new(); let sender = sc_network::PeerId::random(); let mut context = TestContext; - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, MmrRootHash::default().encode()); - let commitment = Commitment { payload, block_number: 3_u64, validator_set_id: 0 }; - - let signature = sign_commitment(&Keyring::Alice, &commitment); - - let vote = VoteMessage { commitment, id: Keyring::Alice.public(), signature }; + let vote = dummy_vote(3); gv.note_round(3u64); gv.note_round(7u64); gv.note_round(10u64); - // first time the cache should be populated. + // first time the cache should be populated let res = gv.validate(&mut context, &sender, &vote.encode()); assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); assert_eq!( - gv.known_votes.read().get(&vote.commitment.block_number).map(|x| x.len()), + gv.known_votes.read().live.get(&vote.commitment.block_number).map(|x| x.len()), Some(1) ); @@ -380,17 +379,84 @@ mod tests { assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); - // next we should quickly reject if the round is not live. - gv.note_round(11_u64); - gv.note_round(12_u64); + // next we should quickly reject if the round is not live + gv.conclude_round(7_u64); - assert!(!GossipValidator::::is_live( - &*gv.known_votes.read(), - &vote.commitment.block_number - )); + assert!(!gv.known_votes.read().is_live(&vote.commitment.block_number)); let res = gv.validate(&mut context, &sender, &vote.encode()); assert!(matches!(res, ValidationResult::Discard)); } + + #[test] + fn messages_allowed_and_expired() { + let gv = GossipValidator::::new(); + let sender = sc_network::PeerId::random(); + let topic = Default::default(); + let intent = MessageIntent::Broadcast; + + // note round 2 and 3, then conclude 2 + gv.note_round(2u64); + gv.note_round(3u64); + gv.conclude_round(2u64); + let mut allowed = gv.message_allowed(); + let mut expired = gv.message_expired(); + + // check bad vote format + assert!(!allowed(&sender, intent, &topic, &mut [0u8; 16])); + assert!(expired(topic, &mut [0u8; 16])); + + // inactive round 1 -> expired + let vote = dummy_vote(1); + let mut encoded_vote = vote.encode(); + assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); + assert!(expired(topic, &mut encoded_vote)); + + // active round 2 -> !expired - concluded but still gossiped + let vote = dummy_vote(2); + let mut encoded_vote = vote.encode(); + assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); + assert!(!expired(topic, &mut encoded_vote)); + + // in progress round 3 -> !expired + let vote = dummy_vote(3); + let mut encoded_vote = vote.encode(); + assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); + assert!(!expired(topic, &mut encoded_vote)); + + // unseen round 4 -> !expired + let vote = dummy_vote(3); + let mut encoded_vote = vote.encode(); + assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); + assert!(!expired(topic, &mut encoded_vote)); + } + + #[test] + fn messages_rebroadcast() { + let gv = GossipValidator::::new(); + let sender = sc_network::PeerId::random(); + let topic = Default::default(); + + let vote = dummy_vote(1); + let mut encoded_vote = vote.encode(); + + // re-broadcasting only allowed at `REBROADCAST_AFTER` intervals + let intent = MessageIntent::PeriodicRebroadcast; + let mut allowed = gv.message_allowed(); + + // rebroadcast not allowed so soon after GossipValidator creation + assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); + + // hack the inner deadline to be `now` + *gv.next_rebroadcast.lock() = Instant::now(); + + // still not allowed on old `allowed` closure result + assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); + + // renew closure result + let mut allowed = gv.message_allowed(); + // rebroadcast should be allowed now + assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); + } } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 29d74c15dd599..8a6e175f58321 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -18,14 +18,14 @@ use std::sync::Arc; -use log::debug; use prometheus::Registry; use sc_client_api::{Backend, BlockchainEvents, Finalizer}; -use sc_network_gossip::{GossipEngine, Network as GossipNetwork}; +use sc_network_gossip::Network as GossipNetwork; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; +use sp_consensus::SyncOracle; use sp_keystore::SyncCryptoStorePtr; use sp_runtime::traits::Block; @@ -41,6 +41,10 @@ mod round; mod worker; pub mod notification; + +#[cfg(test)] +mod tests; + pub use beefy_protocol_name::standard_name as protocol_standard_name; pub(crate) mod beefy_protocol_name { @@ -112,7 +116,7 @@ where BE: Backend, C: Client, C::Api: BeefyApi, - N: GossipNetwork + Clone + Send + 'static, + N: GossipNetwork + Clone + SyncOracle + Send + Sync + 'static, { /// BEEFY client pub client: Arc, @@ -134,6 +138,7 @@ where pub protocol_name: std::borrow::Cow<'static, str>, } +#[cfg(not(test))] /// Start the BEEFY gadget. /// /// This is a thin shim around running and awaiting a BEEFY worker. @@ -143,7 +148,7 @@ where BE: Backend, C: Client, C::Api: BeefyApi, - N: GossipNetwork + Clone + Send + 'static, + N: GossipNetwork + Clone + SyncOracle + Send + Sync + 'static, { let BeefyParams { client, @@ -157,18 +162,24 @@ where protocol_name, } = beefy_params; + let sync_oracle = network.clone(); let gossip_validator = Arc::new(gossip::GossipValidator::new()); - let gossip_engine = GossipEngine::new(network, protocol_name, gossip_validator.clone(), None); + let gossip_engine = sc_network_gossip::GossipEngine::new( + network, + protocol_name, + gossip_validator.clone(), + None, + ); let metrics = prometheus_registry.as_ref().map(metrics::Metrics::register).and_then( |result| match result { Ok(metrics) => { - debug!(target: "beefy", "🥩 Registered metrics"); + log::debug!(target: "beefy", "🥩 Registered metrics"); Some(metrics) }, Err(err) => { - debug!(target: "beefy", "🥩 Failed to register metrics: {:?}", err); + log::debug!(target: "beefy", "🥩 Failed to register metrics: {:?}", err); None }, }, @@ -184,54 +195,10 @@ where gossip_validator, min_block_delta, metrics, + sync_oracle, }; - let worker = worker::BeefyWorker::<_, _, _>::new(worker_params); + let worker = worker::BeefyWorker::<_, _, _, _>::new(worker_params); worker.run().await } - -#[cfg(test)] -mod tests { - use super::*; - use sc_chain_spec::{ChainSpec, GenericChainSpec}; - use serde::{Deserialize, Serialize}; - use sp_core::H256; - use sp_runtime::{BuildStorage, Storage}; - - #[derive(Debug, Serialize, Deserialize)] - struct Genesis(std::collections::BTreeMap); - impl BuildStorage for Genesis { - fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { - storage.top.extend( - self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes())), - ); - Ok(()) - } - } - - #[test] - fn beefy_protocol_name() { - let chain_spec = GenericChainSpec::::from_json_file(std::path::PathBuf::from( - "../chain-spec/res/chain_spec.json", - )) - .unwrap() - .cloned_box(); - - // Create protocol name using random genesis hash. - let genesis_hash = H256::random(); - let expected = format!("/{}/beefy/1", hex::encode(genesis_hash)); - let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); - assert_eq!(proto_name.to_string(), expected); - - // Create protocol name using hardcoded genesis hash. Verify exact representation. - let genesis_hash = [ - 50, 4, 60, 123, 58, 106, 216, 246, 194, 188, 139, 193, 33, 212, 202, 171, 9, 55, 123, - 94, 8, 43, 12, 251, 187, 57, 173, 19, 188, 74, 205, 147, - ]; - let expected = - "/32043c7b3a6ad8f6c2bc8bc121d4caab09377b5e082b0cfbbb39ad13bc4acd93/beefy/1".to_string(); - let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); - assert_eq!(proto_name.to_string(), expected); - } -} diff --git a/client/beefy/src/metrics.rs b/client/beefy/src/metrics.rs index 4b2a5c8dfd5c9..20fa98e52fdd5 100644 --- a/client/beefy/src/metrics.rs +++ b/client/beefy/src/metrics.rs @@ -18,7 +18,9 @@ //! BEEFY Prometheus metrics definition -use prometheus::{register, Counter, Gauge, PrometheusError, Registry, U64}; +#[cfg(not(test))] +use prometheus::{register, PrometheusError, Registry}; +use prometheus::{Counter, Gauge, U64}; /// BEEFY metrics exposed through Prometheus pub(crate) struct Metrics { @@ -37,6 +39,7 @@ pub(crate) struct Metrics { } impl Metrics { + #[cfg(not(test))] pub(crate) fn register(registry: &Registry) -> Result { Ok(Self { beefy_validator_set_id: register( @@ -97,3 +100,11 @@ macro_rules! metric_inc { } }}; } + +#[cfg(test)] +#[macro_export] +macro_rules! metric_get { + ($self:ident, $m:ident) => {{ + $self.metrics.as_ref().map(|metrics| metrics.$m.clone()) + }}; +} diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index e5404cfa6d216..eba769b2356f0 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -16,7 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{collections::BTreeMap, hash::Hash}; +use std::{ + collections::{BTreeMap, HashMap}, + hash::Hash, +}; use log::{debug, trace}; @@ -24,25 +27,33 @@ use beefy_primitives::{ crypto::{Public, Signature}, ValidatorSet, ValidatorSetId, }; -use sp_arithmetic::traits::AtLeast32BitUnsigned; -use sp_runtime::traits::MaybeDisplay; +use sp_runtime::traits::{Block, NumberFor}; +/// Tracks for each round which validators have voted/signed and +/// whether the local `self` validator has voted/signed. +/// +/// Does not do any validation on votes or signatures, layers above need to handle that (gossip). #[derive(Default)] struct RoundTracker { - votes: Vec<(Public, Signature)>, + self_vote: bool, + votes: HashMap, } impl RoundTracker { - fn add_vote(&mut self, vote: (Public, Signature)) -> bool { - // this needs to handle equivocations in the future - if self.votes.contains(&vote) { + fn add_vote(&mut self, vote: (Public, Signature), self_vote: bool) -> bool { + if self.votes.contains_key(&vote.0) { return false } - self.votes.push(vote); + self.self_vote = self.self_vote || self_vote; + self.votes.insert(vote.0, vote.1); true } + fn has_self_vote(&self) -> bool { + self.self_vote + } + fn is_done(&self, threshold: usize) -> bool { self.votes.len() >= threshold } @@ -53,74 +64,125 @@ fn threshold(authorities: usize) -> usize { authorities - faulty } -pub(crate) struct Rounds { - rounds: BTreeMap<(Payload, Number), RoundTracker>, +/// Keeps track of all voting rounds (block numbers) within a session. +/// Only round numbers > `best_done` are of interest, all others are considered stale. +/// +/// Does not do any validation on votes or signatures, layers above need to handle that (gossip). +pub(crate) struct Rounds { + rounds: BTreeMap<(Payload, NumberFor), RoundTracker>, + best_done: Option>, + session_start: NumberFor, validator_set: ValidatorSet, + prev_validator_set: ValidatorSet, } -impl Rounds +impl Rounds where - P: Ord + Hash, - N: Ord + AtLeast32BitUnsigned + MaybeDisplay, + P: Ord + Hash + Clone, + B: Block, { - pub(crate) fn new(validator_set: ValidatorSet) -> Self { - Rounds { rounds: BTreeMap::new(), validator_set } + pub(crate) fn new( + session_start: NumberFor, + validator_set: ValidatorSet, + prev_validator_set: ValidatorSet, + ) -> Self { + Rounds { + rounds: BTreeMap::new(), + best_done: None, + session_start, + validator_set, + prev_validator_set, + } } } -impl Rounds +impl Rounds where - H: Ord + Hash + Clone, - N: Ord + AtLeast32BitUnsigned + MaybeDisplay + Clone, + P: Ord + Hash + Clone, + B: Block, { - pub(crate) fn validator_set_id(&self) -> ValidatorSetId { - self.validator_set.id() + pub(crate) fn validator_set_id_for(&self, block_number: NumberFor) -> ValidatorSetId { + if block_number > self.session_start { + self.validator_set.id() + } else { + self.prev_validator_set.id() + } } - pub(crate) fn validators(&self) -> &[Public] { - self.validator_set.validators() + pub(crate) fn validators_for(&self, block_number: NumberFor) -> &[Public] { + if block_number > self.session_start { + self.validator_set.validators() + } else { + self.prev_validator_set.validators() + } } - pub(crate) fn add_vote(&mut self, round: &(H, N), vote: (Public, Signature)) -> bool { - if self.validator_set.validators().iter().any(|id| vote.0 == *id) { - self.rounds.entry(round.clone()).or_default().add_vote(vote) - } else { + pub(crate) fn validator_set(&self) -> &ValidatorSet { + &self.validator_set + } + + pub(crate) fn session_start(&self) -> &NumberFor { + &self.session_start + } + + pub(crate) fn should_self_vote(&self, round: &(P, NumberFor)) -> bool { + Some(round.1.clone()) > self.best_done && + self.rounds.get(round).map(|tracker| !tracker.has_self_vote()).unwrap_or(true) + } + + pub(crate) fn add_vote( + &mut self, + round: &(P, NumberFor), + vote: (Public, Signature), + self_vote: bool, + ) -> bool { + if Some(round.1.clone()) <= self.best_done { + debug!( + target: "beefy", + "🥩 received vote for old stale round {:?}, ignoring", + round.1 + ); + false + } else if !self.validator_set.validators().iter().any(|id| vote.0 == *id) { + debug!( + target: "beefy", + "🥩 received vote {:?} from validator that is not in the validator set, ignoring", + vote + ); false + } else { + self.rounds.entry(round.clone()).or_default().add_vote(vote, self_vote) } } - pub(crate) fn is_done(&self, round: &(H, N)) -> bool { + pub(crate) fn try_conclude( + &mut self, + round: &(P, NumberFor), + ) -> Option>> { let done = self .rounds .get(round) .map(|tracker| tracker.is_done(threshold(self.validator_set.len()))) .unwrap_or(false); - - debug!(target: "beefy", "🥩 Round #{} done: {}", round.1, done); - - done - } - - pub(crate) fn drop(&mut self, round: &(H, N)) -> Option>> { - trace!(target: "beefy", "🥩 About to drop round #{}", round.1); - - let signatures = self.rounds.remove(round)?.votes; - - Some( - self.validator_set - .validators() - .iter() - .map(|authority_id| { - signatures.iter().find_map(|(id, sig)| { - if id == authority_id { - Some(sig.clone()) - } else { - None - } - }) - }) - .collect(), - ) + trace!(target: "beefy", "🥩 Round #{} done: {}", round.1, done); + + if done { + // remove this and older (now stale) rounds + let signatures = self.rounds.remove(round)?.votes; + self.rounds.retain(|&(_, number), _| number > round.1); + self.best_done = self.best_done.clone().max(Some(round.1.clone())); + trace!(target: "beefy", "🥩 Concluded round #{}", round.1); + + Some( + self.validator_set + .validators() + .iter() + .map(|authority_id| signatures.get(authority_id).cloned()) + .collect(), + ) + } else { + None + } } } @@ -128,13 +190,52 @@ where mod tests { use sc_network_test::Block; use sp_core::H256; - use sp_runtime::traits::NumberFor; use beefy_primitives::{crypto::Public, ValidatorSet}; - use super::Rounds; + use super::{threshold, RoundTracker, Rounds}; use crate::keystore::tests::Keyring; + #[test] + fn round_tracker() { + let mut rt = RoundTracker::default(); + let bob_vote = (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")); + let threshold = 2; + + // self vote not added yet + assert!(!rt.has_self_vote()); + + // adding new vote allowed + assert!(rt.add_vote(bob_vote.clone(), false)); + // adding existing vote not allowed + assert!(!rt.add_vote(bob_vote, false)); + + // self vote still not added yet + assert!(!rt.has_self_vote()); + + // vote is not done + assert!(!rt.is_done(threshold)); + + let alice_vote = (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")); + // adding new vote (self vote this time) allowed + assert!(rt.add_vote(alice_vote, true)); + + // self vote registered + assert!(rt.has_self_vote()); + // vote is now done + assert!(rt.is_done(threshold)); + } + + #[test] + fn vote_threshold() { + assert_eq!(threshold(1), 1); + assert_eq!(threshold(2), 2); + assert_eq!(threshold(3), 3); + assert_eq!(threshold(4), 3); + assert_eq!(threshold(100), 67); + assert_eq!(threshold(300), 201); + } + #[test] fn new_rounds() { sp_tracing::try_init_simple(); @@ -145,116 +246,175 @@ mod tests { ) .unwrap(); - let rounds = Rounds::>::new(validators); - - assert_eq!(42, rounds.validator_set_id()); + let session_start = 1u64.into(); + let rounds = Rounds::::new(session_start, validators.clone(), validators); + assert_eq!(42, rounds.validator_set_id_for(session_start)); + assert_eq!(1, *rounds.session_start()); assert_eq!( &vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], - rounds.validators() + rounds.validators_for(session_start) ); } #[test] - fn add_vote() { + fn add_and_conclude_votes() { sp_tracing::try_init_simple(); let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + vec![ + Keyring::Alice.public(), + Keyring::Bob.public(), + Keyring::Charlie.public(), + Keyring::Eve.public(), + ], Default::default(), ) .unwrap(); + let round = (H256::from_low_u64_le(1), 1); - let mut rounds = Rounds::>::new(validators); + let session_start = 1u64.into(); + let mut rounds = Rounds::::new(session_start, validators.clone(), validators); + // no self vote yet, should self vote + assert!(rounds.should_self_vote(&round)); + + // add 1st good vote assert!(rounds.add_vote( - &(H256::from_low_u64_le(1), 1), - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")) + &round, + (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), + true )); + // round not concluded + assert!(rounds.try_conclude(&round).is_none()); + // self vote already present, should not self vote + assert!(!rounds.should_self_vote(&round)); - assert!(!rounds.is_done(&(H256::from_low_u64_le(1), 1))); - - // invalid vote + // double voting not allowed assert!(!rounds.add_vote( - &(H256::from_low_u64_le(1), 1), - (Keyring::Dave.public(), Keyring::Dave.sign(b"I am committed")) + &round, + (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), + true )); - assert!(!rounds.is_done(&(H256::from_low_u64_le(1), 1))); + // invalid vote (Dave is not a validator) + assert!(!rounds.add_vote( + &round, + (Keyring::Dave.public(), Keyring::Dave.sign(b"I am committed")), + false + )); + assert!(rounds.try_conclude(&round).is_none()); + // add 2nd good vote assert!(rounds.add_vote( - &(H256::from_low_u64_le(1), 1), - (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")) + &round, + (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")), + false )); + // round not concluded + assert!(rounds.try_conclude(&round).is_none()); - assert!(!rounds.is_done(&(H256::from_low_u64_le(1), 1))); - + // add 3rd good vote assert!(rounds.add_vote( - &(H256::from_low_u64_le(1), 1), - (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am committed")) + &round, + (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am committed")), + false )); + // round concluded + assert!(rounds.try_conclude(&round).is_some()); - assert!(rounds.is_done(&(H256::from_low_u64_le(1), 1))); + // Eve is a validator, but round was concluded, adding vote disallowed + assert!(!rounds.add_vote( + &round, + (Keyring::Eve.public(), Keyring::Eve.sign(b"I am committed")), + false + )); } #[test] - fn drop() { + fn multiple_rounds() { sp_tracing::try_init_simple(); let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + vec![ + Keyring::Alice.public(), + Keyring::Bob.public(), + Keyring::Charlie.public(), + Keyring::Dave.public(), + ], Default::default(), ) .unwrap(); - let mut rounds = Rounds::>::new(validators); + let session_start = 1u64.into(); + let mut rounds = Rounds::::new(session_start, validators.clone(), validators); // round 1 - rounds.add_vote( + assert!(rounds.add_vote( &(H256::from_low_u64_le(1), 1), (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), - ); - rounds.add_vote( + true, + )); + assert!(rounds.add_vote( &(H256::from_low_u64_le(1), 1), (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")), - ); + false, + )); + assert!(rounds.add_vote( + &(H256::from_low_u64_le(1), 1), + (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am committed")), + false, + )); // round 2 - rounds.add_vote( + assert!(rounds.add_vote( &(H256::from_low_u64_le(2), 2), (Keyring::Alice.public(), Keyring::Alice.sign(b"I am again committed")), - ); - rounds.add_vote( + true, + )); + assert!(rounds.add_vote( &(H256::from_low_u64_le(2), 2), (Keyring::Bob.public(), Keyring::Bob.sign(b"I am again committed")), - ); + false, + )); + assert!(rounds.add_vote( + &(H256::from_low_u64_le(2), 2), + (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am again committed")), + false, + )); // round 3 - rounds.add_vote( + assert!(rounds.add_vote( &(H256::from_low_u64_le(3), 3), (Keyring::Alice.public(), Keyring::Alice.sign(b"I am still committed")), - ); - rounds.add_vote( + true, + )); + assert!(rounds.add_vote( &(H256::from_low_u64_le(3), 3), (Keyring::Bob.public(), Keyring::Bob.sign(b"I am still committed")), - ); - + false, + )); + assert!(rounds.add_vote( + &(H256::from_low_u64_le(3), 3), + (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am still committed")), + false, + )); assert_eq!(3, rounds.rounds.len()); - // drop unknown round - assert!(rounds.drop(&(H256::from_low_u64_le(5), 5)).is_none()); + // conclude unknown round + assert!(rounds.try_conclude(&(H256::from_low_u64_le(5), 5)).is_none()); assert_eq!(3, rounds.rounds.len()); - // drop round 2 - let signatures = rounds.drop(&(H256::from_low_u64_le(2), 2)).unwrap(); - - assert_eq!(2, rounds.rounds.len()); + // conclude round 2 + let signatures = rounds.try_conclude(&(H256::from_low_u64_le(2), 2)).unwrap(); + assert_eq!(1, rounds.rounds.len()); assert_eq!( signatures, vec![ Some(Keyring::Alice.sign(b"I am again committed")), Some(Keyring::Bob.sign(b"I am again committed")), + Some(Keyring::Charlie.sign(b"I am again committed")), None ] ); diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs new file mode 100644 index 0000000000000..92b5ad91c11e1 --- /dev/null +++ b/client/beefy/src/tests.rs @@ -0,0 +1,590 @@ +// This file is part of Substrate. + +// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Tests and test helpers for BEEFY. + +use futures::{future, stream::FuturesUnordered, Future, StreamExt}; +use parking_lot::Mutex; +use serde::{Deserialize, Serialize}; +use std::{sync::Arc, task::Poll}; +use tokio::{runtime::Runtime, time::Duration}; + +use sc_chain_spec::{ChainSpec, GenericChainSpec}; +use sc_client_api::HeaderBackend; +use sc_consensus::BoxJustificationImport; +use sc_keystore::LocalKeystore; +use sc_network::{config::ProtocolConfig, NetworkService}; +use sc_network_gossip::GossipEngine; +use sc_network_test::{ + Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, + PeersFullClient, TestNetFactory, +}; +use sc_utils::notification::NotificationReceiver; + +use beefy_primitives::{ + crypto::AuthorityId, ConsensusLog, MmrRootHash, ValidatorSet, BEEFY_ENGINE_ID, + KEY_TYPE as BeefyKeyType, +}; +use sp_consensus::BlockOrigin; +use sp_core::H256; +use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_runtime::{ + codec::Encode, generic::BlockId, traits::Header as HeaderT, BuildStorage, DigestItem, Storage, +}; + +use substrate_test_runtime_client::{runtime::Header, Backend, ClientExt}; + +use crate::{ + beefy_protocol_name, + keystore::tests::Keyring as BeefyKeyring, + notification::*, + worker::{tests::TestModifiers, BeefyWorker}, +}; + +const BEEFY_PROTOCOL_NAME: &'static str = "/beefy/1"; + +type BeefyValidatorSet = ValidatorSet; +type BeefyPeer = Peer; + +#[derive(Debug, Serialize, Deserialize)] +struct Genesis(std::collections::BTreeMap); +impl BuildStorage for Genesis { + fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { + storage + .top + .extend(self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes()))); + Ok(()) + } +} + +#[test] +fn beefy_protocol_name() { + let chain_spec = GenericChainSpec::::from_json_file(std::path::PathBuf::from( + "../chain-spec/res/chain_spec.json", + )) + .unwrap() + .cloned_box(); + + // Create protocol name using random genesis hash. + let genesis_hash = H256::random(); + let expected = format!("/{}/beefy/1", hex::encode(genesis_hash)); + let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); + assert_eq!(proto_name.to_string(), expected); + + // Create protocol name using hardcoded genesis hash. Verify exact representation. + let genesis_hash = [ + 50, 4, 60, 123, 58, 106, 216, 246, 194, 188, 139, 193, 33, 212, 202, 171, 9, 55, 123, 94, + 8, 43, 12, 251, 187, 57, 173, 19, 188, 74, 205, 147, + ]; + let expected = + "/32043c7b3a6ad8f6c2bc8bc121d4caab09377b5e082b0cfbbb39ad13bc4acd93/beefy/1".to_string(); + let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); + assert_eq!(proto_name.to_string(), expected); +} + +// TODO: compiler warns us about unused `signed_commitment_stream`, will use in later tests +#[allow(dead_code)] +#[derive(Clone)] +pub(crate) struct BeefyLinkHalf { + signed_commitment_stream: BeefySignedCommitmentStream, + beefy_best_block_stream: BeefyBestBlockStream, +} + +#[derive(Default)] +pub(crate) struct PeerData { + pub(crate) beefy_link_half: Mutex>, + pub(crate) test_modifiers: Option, +} + +impl PeerData { + pub(crate) fn use_validator_set(&mut self, validator_set: &ValidatorSet) { + if let Some(tm) = self.test_modifiers.as_mut() { + tm.active_validators = validator_set.clone(); + } else { + self.test_modifiers = Some(TestModifiers { + active_validators: validator_set.clone(), + corrupt_mmr_roots: false, + }); + } + } +} + +pub(crate) struct BeefyTestNet { + peers: Vec, +} + +impl BeefyTestNet { + pub(crate) fn new(n_authority: usize, n_full: usize) -> Self { + let mut net = BeefyTestNet { peers: Vec::with_capacity(n_authority + n_full) }; + for _ in 0..n_authority { + net.add_authority_peer(); + } + for _ in 0..n_full { + net.add_full_peer(); + } + net + } + + pub(crate) fn add_authority_peer(&mut self) { + self.add_full_peer_with_config(FullPeerConfig { + notifications_protocols: vec![BEEFY_PROTOCOL_NAME.into()], + is_authority: true, + ..Default::default() + }) + } + + pub(crate) fn generate_blocks( + &mut self, + count: usize, + session_length: u64, + validator_set: &BeefyValidatorSet, + ) { + self.peer(0).generate_blocks(count, BlockOrigin::File, |builder| { + let mut block = builder.build().unwrap().block; + + let block_num = *block.header.number(); + let num_byte = block_num.to_le_bytes().into_iter().next().unwrap(); + let mmr_root = MmrRootHash::repeat_byte(num_byte); + + add_mmr_digest(&mut block.header, mmr_root); + + if block_num % session_length == 0 { + add_auth_change_digest(&mut block.header, validator_set.clone()); + } + + block + }); + } +} + +impl TestNetFactory for BeefyTestNet { + type Verifier = PassThroughVerifier; + type BlockImport = PeersClient; + type PeerData = PeerData; + + /// Create new test network with peers and given config. + fn from_config(_config: &ProtocolConfig) -> Self { + BeefyTestNet { peers: Vec::new() } + } + + fn make_verifier( + &self, + _client: PeersClient, + _cfg: &ProtocolConfig, + _: &PeerData, + ) -> Self::Verifier { + PassThroughVerifier::new(false) // use non-instant finality. + } + + fn make_block_import( + &self, + client: PeersClient, + ) -> ( + BlockImportAdapter, + Option>, + Self::PeerData, + ) { + (client.as_block_import(), None, PeerData::default()) + } + + fn peer(&mut self, i: usize) -> &mut BeefyPeer { + &mut self.peers[i] + } + + fn peers(&self) -> &Vec { + &self.peers + } + + fn mut_peers)>(&mut self, closure: F) { + closure(&mut self.peers); + } + + fn add_full_peer(&mut self) { + self.add_full_peer_with_config(FullPeerConfig { + notifications_protocols: vec![BEEFY_PROTOCOL_NAME.into()], + is_authority: false, + ..Default::default() + }) + } +} + +fn add_mmr_digest(header: &mut Header, mmr_hash: MmrRootHash) { + header.digest_mut().push(DigestItem::Consensus( + BEEFY_ENGINE_ID, + ConsensusLog::::MmrRoot(mmr_hash).encode(), + )); +} + +fn add_auth_change_digest(header: &mut Header, new_auth_set: BeefyValidatorSet) { + header.digest_mut().push(DigestItem::Consensus( + BEEFY_ENGINE_ID, + ConsensusLog::::AuthoritiesChange(new_auth_set).encode(), + )); +} + +pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { + keys.iter().map(|key| key.clone().public().into()).collect() +} + +pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> SyncCryptoStorePtr { + let keystore = Arc::new(LocalKeystore::in_memory()); + SyncCryptoStore::ecdsa_generate_new(&*keystore, BeefyKeyType, Some(&authority.to_seed())) + .expect("Creates authority key"); + keystore +} + +pub(crate) fn create_beefy_worker( + peer: &BeefyPeer, + key: &BeefyKeyring, + min_block_delta: u32, +) -> BeefyWorker>> { + let keystore = create_beefy_keystore(*key); + + let (signed_commitment_sender, signed_commitment_stream) = + BeefySignedCommitmentStream::::channel(); + let (beefy_best_block_sender, beefy_best_block_stream) = + BeefyBestBlockStream::::channel(); + + let beefy_link_half = BeefyLinkHalf { signed_commitment_stream, beefy_best_block_stream }; + *peer.data.beefy_link_half.lock() = Some(beefy_link_half); + let test_modifiers = peer.data.test_modifiers.clone().unwrap(); + + let network = peer.network_service().clone(); + let sync_oracle = network.clone(); + let gossip_validator = Arc::new(crate::gossip::GossipValidator::new()); + let gossip_engine = + GossipEngine::new(network, BEEFY_PROTOCOL_NAME, gossip_validator.clone(), None); + let worker_params = crate::worker::WorkerParams { + client: peer.client().as_client(), + backend: peer.client().as_backend(), + key_store: Some(keystore).into(), + signed_commitment_sender, + beefy_best_block_sender, + gossip_engine, + gossip_validator, + min_block_delta, + metrics: None, + sync_oracle, + }; + + BeefyWorker::<_, _, _, _>::new(worker_params, test_modifiers) +} + +// Spawns beefy voters. Returns a future to spawn on the runtime. +fn initialize_beefy( + net: &mut BeefyTestNet, + peers: &[BeefyKeyring], + min_block_delta: u32, +) -> impl Future { + let voters = FuturesUnordered::new(); + + for (peer_id, key) in peers.iter().enumerate() { + let worker = create_beefy_worker(&net.peers[peer_id], key, min_block_delta); + let gadget = worker.run(); + + fn assert_send(_: &T) {} + assert_send(&gadget); + voters.push(gadget); + } + + voters.for_each(|_| async move {}) +} + +fn block_until(future: impl Future + Unpin, net: &Arc>, runtime: &mut Runtime) { + let drive_to_completion = futures::future::poll_fn(|cx| { + net.lock().poll(cx); + Poll::<()>::Pending + }); + runtime.block_on(future::select(future, drive_to_completion)); +} + +fn run_for(duration: Duration, net: &Arc>, runtime: &mut Runtime) { + let sleep = runtime.spawn(async move { tokio::time::sleep(duration).await }); + block_until(sleep, net, runtime); +} + +pub(crate) fn get_beefy_streams( + net: &mut BeefyTestNet, + peers: &[BeefyKeyring], +) -> (Vec>, Vec>>) { + let mut best_block_streams = Vec::new(); + let mut signed_commitment_streams = Vec::new(); + for peer_id in 0..peers.len() { + let beefy_link_half = + net.peer(peer_id).data.beefy_link_half.lock().as_ref().unwrap().clone(); + let BeefyLinkHalf { signed_commitment_stream, beefy_best_block_stream } = beefy_link_half; + best_block_streams.push(beefy_best_block_stream.subscribe()); + signed_commitment_streams.push(signed_commitment_stream.subscribe()); + } + (best_block_streams, signed_commitment_streams) +} + +fn wait_for_best_beefy_blocks( + streams: Vec>, + net: &Arc>, + runtime: &mut Runtime, + expected_beefy_blocks: &[u64], +) { + let mut wait_for = Vec::new(); + let len = expected_beefy_blocks.len(); + streams.into_iter().enumerate().for_each(|(i, stream)| { + let mut expected = expected_beefy_blocks.iter(); + wait_for.push(Box::pin(stream.take(len).for_each(move |best_beefy_hash| { + let expected = expected.next(); + async move { + let block_id = BlockId::hash(best_beefy_hash); + let header = + net.lock().peer(i).client().as_client().expect_header(block_id).unwrap(); + let best_beefy = *header.number(); + + assert_eq!(expected, Some(best_beefy).as_ref()); + } + }))); + }); + let wait_for = futures::future::join_all(wait_for); + block_until(wait_for, net, runtime); +} + +fn wait_for_beefy_signed_commitments( + streams: Vec>>, + net: &Arc>, + runtime: &mut Runtime, + expected_commitment_block_nums: &[u64], +) { + let mut wait_for = Vec::new(); + let len = expected_commitment_block_nums.len(); + streams.into_iter().for_each(|stream| { + let mut expected = expected_commitment_block_nums.iter(); + wait_for.push(Box::pin(stream.take(len).for_each(move |signed_commitment| { + let expected = expected.next(); + async move { + let commitment_block_num = signed_commitment.commitment.block_number; + assert_eq!(expected, Some(commitment_block_num).as_ref()); + // TODO: also verify commitment payload, validator set id, and signatures. + } + }))); + }); + let wait_for = futures::future::join_all(wait_for); + block_until(wait_for, net, runtime); +} + +fn streams_empty_after_timeout( + streams: Vec>, + net: &Arc>, + runtime: &mut Runtime, + timeout: Option, +) where + T: std::fmt::Debug, + T: std::cmp::PartialEq, +{ + if let Some(timeout) = timeout { + run_for(timeout, net, runtime); + } + streams.into_iter().for_each(|mut stream| { + runtime.block_on(future::poll_fn(move |cx| { + assert_eq!(stream.poll_next_unpin(cx), Poll::Pending); + Poll::Ready(()) + })); + }); +} + +fn finalize_block_and_wait_for_beefy( + net: &Arc>, + peers: &[BeefyKeyring], + runtime: &mut Runtime, + finalize_targets: &[u64], + expected_beefy: &[u64], +) { + let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); + + for block in finalize_targets { + let finalize = BlockId::number(*block); + for i in 0..peers.len() { + net.lock().peer(i).client().as_client().finalize_block(finalize, None).unwrap(); + } + } + + if expected_beefy.is_empty() { + // run for 1 second then verify no new best beefy block available + let timeout = Some(Duration::from_millis(500)); + streams_empty_after_timeout(best_blocks, &net, runtime, timeout); + streams_empty_after_timeout(signed_commitments, &net, runtime, None); + } else { + // run until expected beefy blocks are received + wait_for_best_beefy_blocks(best_blocks, &net, runtime, expected_beefy); + wait_for_beefy_signed_commitments(signed_commitments, &net, runtime, expected_beefy); + } +} + +#[test] +fn beefy_finalizing_blocks() { + sp_tracing::try_init_simple(); + + let mut runtime = Runtime::new().unwrap(); + let peers = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let session_len = 10; + let min_block_delta = 4; + + let mut net = BeefyTestNet::new(2, 0); + + for i in 0..peers.len() { + net.peer(i).data.use_validator_set(&validator_set); + } + runtime.spawn(initialize_beefy(&mut net, peers, min_block_delta)); + + // push 42 blocks including `AuthorityChange` digests every 10 blocks. + net.generate_blocks(42, session_len, &validator_set); + net.block_until_sync(); + + let net = Arc::new(Mutex::new(net)); + + // Minimum BEEFY block delta is 4. + + // finalize block #5 -> BEEFY should finalize #1 (mandatory) and #5 from diff-power-of-two rule. + finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[5], &[1, 5]); + + // GRANDPA finalize #10 -> BEEFY finalize #10 (mandatory) + finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[10]); + + // GRANDPA finalize #18 -> BEEFY finalize #14, then #18 (diff-power-of-two rule) + finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[18], &[14, 18]); + + // GRANDPA finalize #20 -> BEEFY finalize #20 (mandatory) + finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[20], &[20]); + + // GRANDPA finalize #21 -> BEEFY finalize nothing (yet) because min delta is 4 + finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[21], &[]); +} + +#[test] +fn lagging_validators() { + sp_tracing::try_init_simple(); + + let mut runtime = Runtime::new().unwrap(); + let peers = &[BeefyKeyring::Charlie, BeefyKeyring::Dave]; + let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let session_len = 30; + let min_block_delta = 1; + + let mut net = BeefyTestNet::new(2, 0); + for i in 0..peers.len() { + net.peer(i).data.use_validator_set(&validator_set); + } + runtime.spawn(initialize_beefy(&mut net, peers, min_block_delta)); + + // push 42 blocks including `AuthorityChange` digests every 30 blocks. + net.generate_blocks(42, session_len, &validator_set); + net.block_until_sync(); + + let net = Arc::new(Mutex::new(net)); + + // finalize block #15 -> BEEFY should finalize #1 (mandatory) and #9, #13, #14, #15 from + // diff-power-of-two rule. + finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[15], &[1, 9, 13, 14, 15]); + + // Charlie finalizes #25, Dave lags behind + let finalize = BlockId::number(25); + let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); + net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); + // verify nothing gets finalized by BEEFY + let timeout = Some(Duration::from_millis(500)); + streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); + streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); + + // Dave catches up and also finalizes #25 + let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); + net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); + // expected beefy finalizes block #17 from diff-power-of-two + wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[23, 24, 25]); + wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[23, 24, 25]); + + // Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32 + finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[30, 32], &[30, 31, 32]); +} + +#[test] +fn correct_beefy_payload() { + sp_tracing::try_init_simple(); + + let mut runtime = Runtime::new().unwrap(); + let peers = + &[BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave]; + let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let session_len = 20; + let min_block_delta = 2; + + let mut net = BeefyTestNet::new(4, 0); + for i in 0..peers.len() { + net.peer(i).data.use_validator_set(&validator_set); + } + + // Dave will vote on bad mmr roots + net.peer(3).data.test_modifiers.as_mut().map(|tm| tm.corrupt_mmr_roots = true); + runtime.spawn(initialize_beefy(&mut net, peers, min_block_delta)); + + // push 10 blocks + net.generate_blocks(12, session_len, &validator_set); + net.block_until_sync(); + + let net = Arc::new(Mutex::new(net)); + // with 3 good voters and 1 bad one, consensus should happen and best blocks produced. + finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[1, 9]); + + let (best_blocks, signed_commitments) = + get_beefy_streams(&mut *net.lock(), &[BeefyKeyring::Alice]); + + // now 2 good validators and 1 bad one are voting + net.lock() + .peer(0) + .client() + .as_client() + .finalize_block(BlockId::number(11), None) + .unwrap(); + net.lock() + .peer(1) + .client() + .as_client() + .finalize_block(BlockId::number(11), None) + .unwrap(); + net.lock() + .peer(3) + .client() + .as_client() + .finalize_block(BlockId::number(11), None) + .unwrap(); + + // verify consensus is _not_ reached + let timeout = Some(Duration::from_millis(500)); + streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); + streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); + + // 3rd good validator catches up and votes as well + let (best_blocks, signed_commitments) = + get_beefy_streams(&mut *net.lock(), &[BeefyKeyring::Alice]); + net.lock() + .peer(2) + .client() + .as_client() + .finalize_block(BlockId::number(11), None) + .unwrap(); + + // verify consensus is reached + wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[11]); + wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[11]); +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 3f23638758eca..85674c09a278b 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{collections::BTreeSet, fmt::Debug, marker::PhantomData, sync::Arc}; +use std::{collections::BTreeSet, fmt::Debug, marker::PhantomData, sync::Arc, time::Duration}; use codec::{Codec, Decode, Encode}; use futures::{future, FutureExt, StreamExt}; @@ -28,6 +28,7 @@ use sc_network_gossip::GossipEngine; use sp_api::BlockId; use sp_arithmetic::traits::AtLeast32Bit; +use sp_consensus::SyncOracle; use sp_runtime::{ generic::OpaqueDigestItemId, traits::{Block, Header, NumberFor}, @@ -35,7 +36,7 @@ use sp_runtime::{ }; use beefy_primitives::{ - crypto::{AuthorityId, Public, Signature}, + crypto::{AuthorityId, Signature}, known_payload_ids, BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, SignedCommitment, ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, }; @@ -47,10 +48,11 @@ use crate::{ metric_inc, metric_set, metrics::Metrics, notification::{BeefyBestBlockSender, BeefySignedCommitmentSender}, - round, Client, + round::Rounds, + Client, }; -pub(crate) struct WorkerParams +pub(crate) struct WorkerParams where B: Block, { @@ -63,14 +65,16 @@ where pub gossip_validator: Arc>, pub min_block_delta: u32, pub metrics: Option, + pub sync_oracle: SO, } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker +pub(crate) struct BeefyWorker where B: Block, BE: Backend, C: Client, + SO: SyncOracle + Send + Sync + Clone + 'static, { client: Arc, backend: Arc, @@ -81,26 +85,32 @@ where /// Min delta in block numbers between two blocks, BEEFY should vote on min_block_delta: u32, metrics: Option, - rounds: Option>>, + rounds: Option>, finality_notifications: FinalityNotifications, /// Best block we received a GRANDPA notification for - best_grandpa_block: NumberFor, + best_grandpa_block_header: ::Header, /// Best block a BEEFY voting round has been concluded for best_beefy_block: Option>, /// Used to keep RPC worker up to date on latest/best beefy beefy_best_block_sender: BeefyBestBlockSender, /// Validator set id for the last signed commitment last_signed_id: u64, + /// Handle to the sync oracle + sync_oracle: SO, // keep rustc happy _backend: PhantomData, + #[cfg(test)] + // behavior modifiers used in tests + test_res: tests::TestModifiers, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, C: Client, C::Api: BeefyApi, + SO: SyncOracle + Send + Sync + Clone + 'static, { /// Return a new BEEFY worker instance. /// @@ -108,7 +118,12 @@ where /// BEEFY pallet has been deployed on-chain. /// /// The BEEFY pallet is needed in order to keep track of the BEEFY authority set. - pub(crate) fn new(worker_params: WorkerParams) -> Self { + pub(crate) fn new( + worker_params: WorkerParams, + #[cfg(test)] + // behavior modifiers used in tests + test_res: tests::TestModifiers, + ) -> Self { let WorkerParams { client, backend, @@ -119,8 +134,13 @@ where gossip_validator, min_block_delta, metrics, + sync_oracle, } = worker_params; + let last_finalized_header = client + .expect_header(BlockId::number(client.info().finalized_number)) + .expect("latest block always has header available; qed."); + BeefyWorker { client: client.clone(), backend, @@ -128,200 +148,176 @@ where signed_commitment_sender, gossip_engine: Arc::new(Mutex::new(gossip_engine)), gossip_validator, - min_block_delta, + // always target at least one block better than current best beefy + min_block_delta: min_block_delta.max(1), metrics, rounds: None, finality_notifications: client.finality_notification_stream(), - best_grandpa_block: client.info().finalized_number, + best_grandpa_block_header: last_finalized_header, best_beefy_block: None, last_signed_id: 0, beefy_best_block_sender, + sync_oracle, _backend: PhantomData, + #[cfg(test)] + test_res, } } } -impl BeefyWorker +impl BeefyWorker where B: Block, BE: Backend, C: Client, C::Api: BeefyApi, + SO: SyncOracle + Send + Sync + Clone + 'static, { - /// Return `true`, if we should vote on block `number` - fn should_vote_on(&self, number: NumberFor) -> bool { - let best_beefy_block = if let Some(block) = self.best_beefy_block { - block - } else { - debug!(target: "beefy", "🥩 Missing best BEEFY block - won't vote for: {:?}", number); - return false - }; - - let target = vote_target(self.best_grandpa_block, best_beefy_block, self.min_block_delta); - - trace!(target: "beefy", "🥩 should_vote_on: #{:?}, next_block_to_vote_on: #{:?}", number, target); - - metric_set!(self, beefy_should_vote_on, target); - - number == target - } - - /// Return the current active validator set at header `header`. - /// - /// Note that the validator set could be `None`. This is the case if we don't find - /// a BEEFY authority set change and we can't fetch the authority set from the - /// BEEFY on-chain state. - /// - /// Such a failure is usually an indication that the BEEFY pallet has not been deployed (yet). - fn validator_set(&self, header: &B::Header) -> Option> { - let new = if let Some(new) = find_authorities_change::(header) { - Some(new) + /// Return `Some(number)` if we should be voting on block `number` now, + /// return `None` if there is no block we should vote on now. + fn current_vote_target(&self) -> Option> { + let rounds = if let Some(r) = &self.rounds { + r } else { - let at = BlockId::hash(header.hash()); - self.client.runtime_api().validator_set(&at).ok().flatten() + debug!(target: "beefy", "🥩 No voting round started"); + return None }; - trace!(target: "beefy", "🥩 active validator set: {:?}", new); - - new + let best_finalized = *self.best_grandpa_block_header.number(); + // `target` is guaranteed > `best_beefy` since `min_block_delta` is at least `1`. + let target = vote_target( + best_finalized, + self.best_beefy_block, + *rounds.session_start(), + self.min_block_delta, + ); + trace!( + target: "beefy", + "🥩 best beefy: #{:?}, best finalized: #{:?}, current_vote_target: {:?}", + self.best_beefy_block, + best_finalized, + target + ); + if let Some(target) = &target { + metric_set!(self, beefy_should_vote_on, target); + } + target } /// Verify `active` validator set for `block` against the key store /// - /// The critical case is, if we do have a public key in the key store which is not - /// part of the active validator set. + /// We want to make sure that we have _at least one_ key in our keystore that + /// is part of the validator set, that's because if there are no local keys + /// then we can't perform our job as a validator. /// /// Note that for a non-authority node there will be no keystore, and we will /// return an error and don't check. The error can usually be ignored. fn verify_validator_set( &self, block: &NumberFor, - active: &ValidatorSet, + active: &ValidatorSet, ) -> Result<(), error::Error> { - let active: BTreeSet<&Public> = active.validators().iter().collect(); + let active: BTreeSet<&AuthorityId> = active.validators().iter().collect(); let public_keys = self.key_store.public_keys()?; - let store: BTreeSet<&Public> = public_keys.iter().collect(); + let store: BTreeSet<&AuthorityId> = public_keys.iter().collect(); - let missing: Vec<_> = store.difference(&active).cloned().collect(); - - if !missing.is_empty() { - debug!(target: "beefy", "🥩 for block {:?} public key missing in validator set: {:?}", block, missing); + if store.intersection(&active).count() == 0 { + let msg = "no authority public key found in store".to_string(); + debug!(target: "beefy", "🥩 for block {:?} {}", block, msg); + Err(error::Error::Keystore(msg)) + } else { + Ok(()) } - - Ok(()) } - fn handle_finality_notification(&mut self, notification: FinalityNotification) { - trace!(target: "beefy", "🥩 Finality notification: {:?}", notification); - - // update best GRANDPA finalized block we have seen - self.best_grandpa_block = *notification.header.number(); - - if let Some(active) = self.validator_set(¬ification.header) { - // Authority set change or genesis set id triggers new voting rounds - // - // TODO: (grandpa-bridge-gadget#366) Enacting a new authority set will also - // implicitly 'conclude' the currently active BEEFY voting round by starting a - // new one. This should be replaced by proper round life-cycle handling. - if self.rounds.is_none() || - active.id() != self.rounds.as_ref().unwrap().validator_set_id() || - (active.id() == GENESIS_AUTHORITY_SET_ID && self.best_beefy_block.is_none()) - { - debug!(target: "beefy", "🥩 New active validator set id: {:?}", active); - metric_set!(self, beefy_validator_set_id, active.id()); - - // BEEFY should produce a signed commitment for each session - if active.id() != self.last_signed_id + 1 && active.id() != GENESIS_AUTHORITY_SET_ID - { - metric_inc!(self, beefy_skipped_sessions); - } - - if log_enabled!(target: "beefy", log::Level::Debug) { - // verify the new validator set - only do it if we're also logging the warning - let _ = self.verify_validator_set(notification.header.number(), &active); - } - - let id = active.id(); - self.rounds = Some(round::Rounds::new(active)); - - debug!(target: "beefy", "🥩 New Rounds for id: {:?}", id); - - self.best_beefy_block = Some(*notification.header.number()); + /// Set best BEEFY block to `block_num`. + /// + /// Also sends/updates the best BEEFY block hash to the RPC worker. + fn set_best_beefy_block(&mut self, block_num: NumberFor) { + if Some(block_num) > self.best_beefy_block { + // Try to get block hash ourselves. + let block_hash = match self.client.hash(block_num) { + Ok(h) => h, + Err(e) => { + error!(target: "beefy", "🥩 Failed to get hash for block number {}: {}", + block_num, e); + None + }, + }; + // Update RPC worker with new best BEEFY block hash. + block_hash.map(|hash| { self.beefy_best_block_sender - .notify(|| Ok::<_, ()>(notification.hash.clone())) - .expect("forwards closure result; the closure always returns Ok; qed."); - - // this metric is kind of 'fake'. Best BEEFY block should only be updated once we - // have a signed commitment for the block. Remove once the above TODO is done. - metric_set!(self, beefy_best_block, *notification.header.number()); - } + .notify(|| Ok::<_, ()>(hash)) + .expect("forwards closure result; the closure always returns Ok; qed.") + }); + // Set new best BEEFY block number. + self.best_beefy_block = Some(block_num); + metric_set!(self, beefy_best_block, block_num); + } else { + debug!(target: "beefy", "🥩 Can't set best beefy to older: {}", block_num); } + } - if self.should_vote_on(*notification.header.number()) { - let (validators, validator_set_id) = if let Some(rounds) = &self.rounds { - (rounds.validators(), rounds.validator_set_id()) - } else { - debug!(target: "beefy", "🥩 Missing validator set - can't vote for: {:?}", notification.header.hash()); - return - }; - let authority_id = if let Some(id) = self.key_store.authority_id(validators) { - debug!(target: "beefy", "🥩 Local authority id: {:?}", id); - id - } else { - debug!(target: "beefy", "🥩 Missing validator id - can't vote for: {:?}", notification.header.hash()); - return - }; - - let mmr_root = - if let Some(hash) = find_mmr_root_digest::(¬ification.header) { - hash - } else { - warn!(target: "beefy", "🥩 No MMR root digest found for: {:?}", notification.header.hash()); - return - }; - - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, mmr_root.encode()); - let commitment = Commitment { - payload, - block_number: notification.header.number(), - validator_set_id, - }; - let encoded_commitment = commitment.encode(); + /// Handle session changes by starting new voting round for mandatory blocks. + fn init_session_at(&mut self, active: ValidatorSet, session_start: NumberFor) { + debug!(target: "beefy", "🥩 New active validator set: {:?}", active); + metric_set!(self, beefy_validator_set_id, active.id()); + // BEEFY should produce a signed commitment for each session + if active.id() != self.last_signed_id + 1 && active.id() != GENESIS_AUTHORITY_SET_ID { + metric_inc!(self, beefy_skipped_sessions); + } - let signature = match self.key_store.sign(&authority_id, &*encoded_commitment) { - Ok(sig) => sig, - Err(err) => { - warn!(target: "beefy", "🥩 Error signing commitment: {:?}", err); - return - }, - }; + if log_enabled!(target: "beefy", log::Level::Debug) { + // verify the new validator set - only do it if we're also logging the warning + let _ = self.verify_validator_set(&session_start, &active); + } - trace!( - target: "beefy", - "🥩 Produced signature using {:?}, is_valid: {:?}", - authority_id, - BeefyKeystore::verify(&authority_id, &signature, &*encoded_commitment) - ); + let prev_validator_set = if let Some(r) = &self.rounds { + r.validator_set().clone() + } else { + // no previous rounds present use new validator set instead (genesis case) + active.clone() + }; + let id = active.id(); + self.rounds = Some(Rounds::new(session_start, active, prev_validator_set)); + info!(target: "beefy", "🥩 New Rounds for validator set id: {:?} with session_start {:?}", id, session_start); + } - let message = VoteMessage { commitment, id: authority_id, signature }; + fn handle_finality_notification(&mut self, notification: &FinalityNotification) { + trace!(target: "beefy", "🥩 Finality notification: {:?}", notification); + let number = *notification.header.number(); - let encoded_message = message.encode(); + // On start-up ignore old finality notifications that we're not interested in. + if number <= *self.best_grandpa_block_header.number() { + debug!(target: "beefy", "🥩 Got unexpected finality for old block #{:?}", number); + return + } - metric_inc!(self, beefy_votes_sent); + // update best GRANDPA finalized block we have seen + self.best_grandpa_block_header = notification.header.clone(); - debug!(target: "beefy", "🥩 Sent vote message: {:?}", message); + self.handle_finality(¬ification.header); + } - self.handle_vote( - (message.commitment.payload, *message.commitment.block_number), - (message.id, message.signature), - ); + fn handle_finality(&mut self, header: &B::Header) { + // Check for and handle potential new session. + if let Some(new_validator_set) = find_authorities_change::(header) { + self.init_session_at(new_validator_set, *header.number()); + } - self.gossip_engine.lock().gossip_message(topic::(), encoded_message, false); + // Vote if there's now a new vote target. + if let Some(target_number) = self.current_vote_target() { + self.do_vote(target_number); } } - fn handle_vote(&mut self, round: (Payload, NumberFor), vote: (Public, Signature)) { + fn handle_vote( + &mut self, + round: (Payload, NumberFor), + vote: (AuthorityId, Signature), + self_vote: bool, + ) { self.gossip_validator.note_round(round.1); let rounds = if let Some(rounds) = self.rounds.as_mut() { @@ -331,12 +327,12 @@ where return }; - let vote_added = rounds.add_vote(&round, vote); + if rounds.add_vote(&round, vote, self_vote) { + if let Some(signatures) = rounds.try_conclude(&round) { + self.gossip_validator.conclude_round(round.1); - if vote_added && rounds.is_done(&round) { - if let Some(signatures) = rounds.drop(&round) { // id is stored for skipped session metric calculation - self.last_signed_id = rounds.validator_set_id(); + self.last_signed_id = rounds.validator_set_id_for(round.1); let block_num = round.1; let commitment = Commitment { @@ -351,48 +347,167 @@ where info!(target: "beefy", "🥩 Round #{} concluded, committed: {:?}.", round.1, signed_commitment); - if self - .backend - .append_justification( - BlockId::Number(block_num), - ( - BEEFY_ENGINE_ID, - VersionedFinalityProof::V1(signed_commitment.clone()).encode(), - ), - ) - .is_err() - { - // just a trace, because until the round lifecycle is improved, we will - // conclude certain rounds multiple times. - trace!(target: "beefy", "🥩 Failed to append justification: {:?}", signed_commitment); + if let Err(e) = self.backend.append_justification( + BlockId::Number(block_num), + ( + BEEFY_ENGINE_ID, + VersionedFinalityProof::V1(signed_commitment.clone()).encode(), + ), + ) { + trace!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, signed_commitment); } self.signed_commitment_sender .notify(|| Ok::<_, ()>(signed_commitment)) .expect("forwards closure result; the closure always returns Ok; qed."); - self.best_beefy_block = Some(block_num); - if let Err(err) = self.client.hash(block_num).map(|h| { - if let Some(hash) = h { - self.beefy_best_block_sender - .notify(|| Ok::<_, ()>(hash)) - .expect("forwards closure result; the closure always returns Ok; qed."); - } - }) { - error!(target: "beefy", "🥩 Failed to get hash for block number {}: {}", - block_num, err); - } + self.set_best_beefy_block(block_num); - metric_set!(self, beefy_best_block, block_num); + // Vote if there's now a new vote target. + if let Some(target_number) = self.current_vote_target() { + self.do_vote(target_number); + } } } } + /// Create and gossip Signed Commitment for block number `target_number`. + /// + /// Also handle this self vote by calling `self.handle_vote()` for it. + fn do_vote(&mut self, target_number: NumberFor) { + trace!(target: "beefy", "🥩 Try voting on {}", target_number); + + // Most of the time we get here, `target` is actually `best_grandpa`, + // avoid asking `client` for header in that case. + let target_header = if target_number == *self.best_grandpa_block_header.number() { + self.best_grandpa_block_header.clone() + } else { + match self.client.expect_header(BlockId::Number(target_number)) { + Ok(h) => h, + Err(err) => { + debug!( + target: "beefy", + "🥩 Could not get header for block #{:?} (error: {:?}), skipping vote..", + target_number, + err + ); + return + }, + } + }; + let target_hash = target_header.hash(); + + let mmr_root = if let Some(hash) = self.extract_mmr_root_digest(&target_header) { + hash + } else { + warn!(target: "beefy", "🥩 No MMR root digest found for: {:?}", target_hash); + return + }; + let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, mmr_root.encode()); + + let (validators, validator_set_id) = if let Some(rounds) = &self.rounds { + if !rounds.should_self_vote(&(payload.clone(), target_number)) { + debug!(target: "beefy", "🥩 Don't double vote for block number: {:?}", target_number); + return + } + (rounds.validators_for(target_number), rounds.validator_set_id_for(target_number)) + } else { + debug!(target: "beefy", "🥩 Missing validator set - can't vote for: {:?}", target_hash); + return + }; + let authority_id = if let Some(id) = self.key_store.authority_id(validators) { + debug!(target: "beefy", "🥩 Local authority id: {:?}", id); + id + } else { + debug!(target: "beefy", "🥩 Missing validator id - can't vote for: {:?}", target_hash); + return + }; + + let commitment = Commitment { payload, block_number: target_number, validator_set_id }; + let encoded_commitment = commitment.encode(); + + let signature = match self.key_store.sign(&authority_id, &*encoded_commitment) { + Ok(sig) => sig, + Err(err) => { + warn!(target: "beefy", "🥩 Error signing commitment: {:?}", err); + return + }, + }; + + trace!( + target: "beefy", + "🥩 Produced signature using {:?}, is_valid: {:?}", + authority_id, + BeefyKeystore::verify(&authority_id, &signature, &*encoded_commitment) + ); + + let message = VoteMessage { commitment, id: authority_id, signature }; + + let encoded_message = message.encode(); + + metric_inc!(self, beefy_votes_sent); + + debug!(target: "beefy", "🥩 Sent vote message: {:?}", message); + + self.handle_vote( + (message.commitment.payload, message.commitment.block_number), + (message.id, message.signature), + true, + ); + + self.gossip_engine.lock().gossip_message(topic::(), encoded_message, false); + } + + /// Wait for BEEFY runtime pallet to be available. + #[cfg(not(test))] + async fn wait_for_runtime_pallet(&mut self) { + self.client + .finality_notification_stream() + .take_while(|notif| { + let at = BlockId::hash(notif.header.hash()); + if let Some(active) = self.client.runtime_api().validator_set(&at).ok().flatten() { + if active.id() == GENESIS_AUTHORITY_SET_ID { + // When starting from genesis, there is no session boundary digest. + // Just initialize `rounds` to Block #1 as BEEFY mandatory block. + self.init_session_at(active, 1u32.into()); + } + // In all other cases, we just go without `rounds` initialized, meaning the + // worker won't vote until it witnesses a session change. + // Once we'll implement 'initial sync' (catch-up), the worker will be able to + // start voting right away. + self.handle_finality_notification(notif); + future::ready(false) + } else { + trace!(target: "beefy", "🥩 Finality notification: {:?}", notif); + trace!(target: "beefy", "🥩 Waiting for BEEFY pallet to become available..."); + future::ready(true) + } + }) + .for_each(|_| future::ready(())) + .await; + // get a new stream that provides _new_ notifications (from here on out) + self.finality_notifications = self.client.finality_notification_stream(); + } + + /// For tests don't use runtime pallet. Start rounds from block #1. + #[cfg(test)] + async fn wait_for_runtime_pallet(&mut self) { + let active = self.test_res.active_validators.clone(); + self.init_session_at(active, 1u32.into()); + } + + /// Main loop for BEEFY worker. + /// + /// Wait for BEEFY runtime pallet to be available, then start the main async loop + /// which is driven by finality notifications and gossiped votes. pub(crate) async fn run(mut self) { + info!(target: "beefy", "🥩 run BEEFY worker, best grandpa: #{:?}.", self.best_grandpa_block_header.number()); + self.wait_for_runtime_pallet().await; + let mut votes = Box::pin(self.gossip_engine.lock().messages_for(topic::()).filter_map( |notification| async move { debug!(target: "beefy", "🥩 Got vote message: {:?}", notification); - VoteMessage::, Public, Signature>::decode( + VoteMessage::, AuthorityId, Signature>::decode( &mut ¬ification.message[..], ) .ok() @@ -400,13 +515,18 @@ where )); loop { + while self.sync_oracle.is_major_syncing() { + debug!(target: "beefy", "Waiting for major sync to complete..."); + futures_timer::Delay::new(Duration::from_secs(5)).await; + } + let engine = self.gossip_engine.clone(); let gossip_engine = future::poll_fn(|cx| engine.lock().poll_unpin(cx)); futures::select! { notification = self.finality_notifications.next().fuse() => { if let Some(notification) = notification { - self.handle_finality_notification(notification); + self.handle_finality_notification(¬ification); } else { return; } @@ -416,6 +536,7 @@ where self.handle_vote( (vote.commitment.payload, vote.commitment.block_number), (vote.id, vote.signature), + false ); } else { return; @@ -428,20 +549,36 @@ where } } } + + /// Simple wrapper over mmr root extraction. + #[cfg(not(test))] + fn extract_mmr_root_digest(&self, header: &B::Header) -> Option { + find_mmr_root_digest::(header) + } + + /// For tests, have the option to modify mmr root. + #[cfg(test)] + fn extract_mmr_root_digest(&self, header: &B::Header) -> Option { + let mut mmr_root = find_mmr_root_digest::(header); + if self.test_res.corrupt_mmr_roots { + mmr_root.as_mut().map(|hash| *hash ^= MmrRootHash::random()); + } + mmr_root + } } /// Extract the MMR root hash from a digest in the given header, if it exists. -fn find_mmr_root_digest(header: &B::Header) -> Option +fn find_mmr_root_digest(header: &B::Header) -> Option where B: Block, - Id: Codec, { - header.digest().logs().iter().find_map(|log| { - match log.try_to::>(OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID)) { - Some(ConsensusLog::MmrRoot(root)) => Some(root), - _ => None, - } - }) + let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); + + let filter = |log: ConsensusLog| match log { + ConsensusLog::MmrRoot(root) => Some(root), + _ => None, + }; + header.digest().convert_first(|l| l.try_to(id).and_then(filter)) } /// Scan the `header` digest log for a BEEFY validator set change. Return either the new @@ -456,119 +593,402 @@ where ConsensusLog::AuthoritiesChange(validator_set) => Some(validator_set), _ => None, }; - header.digest().convert_first(|l| l.try_to(id).and_then(filter)) } -/// Calculate next block number to vote on -fn vote_target(best_grandpa: N, best_beefy: N, min_delta: u32) -> N +/// Calculate next block number to vote on. +/// +/// Return `None` if there is no voteable target yet. +fn vote_target( + best_grandpa: N, + best_beefy: Option, + session_start: N, + min_delta: u32, +) -> Option where N: AtLeast32Bit + Copy + Debug, { - let diff = best_grandpa.saturating_sub(best_beefy); - let diff = diff.saturated_into::(); - let target = best_beefy + min_delta.max(diff.next_power_of_two()).into(); - - trace!( - target: "beefy", - "🥩 vote target - diff: {:?}, next_power_of_two: {:?}, target block: #{:?}", - diff, - diff.next_power_of_two(), - target, - ); - - target + // if the mandatory block (session_start) does not have a beefy justification yet, + // we vote on it + let target = match best_beefy { + None => { + trace!( + target: "beefy", + "🥩 vote target - mandatory block: #{:?}", + session_start, + ); + session_start + }, + Some(bbb) if bbb < session_start => { + trace!( + target: "beefy", + "🥩 vote target - mandatory block: #{:?}", + session_start, + ); + session_start + }, + Some(bbb) => { + let diff = best_grandpa.saturating_sub(bbb) + 1u32.into(); + let diff = diff.saturated_into::() / 2; + let target = bbb + min_delta.max(diff.next_power_of_two()).into(); + + trace!( + target: "beefy", + "🥩 vote target - diff: {:?}, next_power_of_two: {:?}, target block: #{:?}", + diff, + diff.next_power_of_two(), + target, + ); + + target + }, + }; + + // Don't vote for targets until they've been finalized + // (`target` can be > `best_grandpa` when `min_delta` is big enough). + if target > best_grandpa { + None + } else { + Some(target) + } } #[cfg(test)] -mod tests { - use super::vote_target; +pub(crate) mod tests { + use super::*; + use crate::{ + keystore::tests::Keyring, + tests::{create_beefy_worker, get_beefy_streams, make_beefy_ids, BeefyTestNet}, + }; + + use futures::{executor::block_on, future::poll_fn, task::Poll}; + + use sc_client_api::HeaderBackend; + use sc_network::NetworkService; + use sc_network_test::{PeersFullClient, TestNetFactory}; + use sp_api::HeaderT; + use substrate_test_runtime_client::{ + runtime::{Block, Digest, DigestItem, Header, H256}, + Backend, + }; + + #[derive(Clone)] + pub struct TestModifiers { + pub active_validators: ValidatorSet, + pub corrupt_mmr_roots: bool, + } #[test] fn vote_on_min_block_delta() { - let t = vote_target(1u32, 0, 4); - assert_eq!(4, t); - let t = vote_target(2u32, 0, 4); - assert_eq!(4, t); - let t = vote_target(3u32, 0, 4); - assert_eq!(4, t); - let t = vote_target(4u32, 0, 4); - assert_eq!(4, t); - - let t = vote_target(4u32, 4, 4); - assert_eq!(8, t); - - let t = vote_target(10u32, 10, 4); - assert_eq!(14, t); - let t = vote_target(11u32, 10, 4); - assert_eq!(14, t); - let t = vote_target(12u32, 10, 4); - assert_eq!(14, t); - let t = vote_target(13u32, 10, 4); - assert_eq!(14, t); - - let t = vote_target(10u32, 10, 8); - assert_eq!(18, t); - let t = vote_target(11u32, 10, 8); - assert_eq!(18, t); - let t = vote_target(12u32, 10, 8); - assert_eq!(18, t); - let t = vote_target(13u32, 10, 8); - assert_eq!(18, t); + let t = vote_target(1u32, Some(1), 1, 4); + assert_eq!(None, t); + let t = vote_target(2u32, Some(1), 1, 4); + assert_eq!(None, t); + let t = vote_target(4u32, Some(2), 1, 4); + assert_eq!(None, t); + let t = vote_target(6u32, Some(2), 1, 4); + assert_eq!(Some(6), t); + + let t = vote_target(9u32, Some(4), 1, 4); + assert_eq!(Some(8), t); + + let t = vote_target(10u32, Some(10), 1, 8); + assert_eq!(None, t); + let t = vote_target(12u32, Some(10), 1, 8); + assert_eq!(None, t); + let t = vote_target(18u32, Some(10), 1, 8); + assert_eq!(Some(18), t); } #[test] fn vote_on_power_of_two() { - let t = vote_target(1008u32, 1000, 4); - assert_eq!(1008, t); + let t = vote_target(1008u32, Some(1000), 1, 4); + assert_eq!(Some(1004), t); - let t = vote_target(1016u32, 1000, 4); - assert_eq!(1016, t); + let t = vote_target(1016u32, Some(1000), 1, 4); + assert_eq!(Some(1008), t); - let t = vote_target(1032u32, 1000, 4); - assert_eq!(1032, t); + let t = vote_target(1032u32, Some(1000), 1, 4); + assert_eq!(Some(1016), t); - let t = vote_target(1064u32, 1000, 4); - assert_eq!(1064, t); + let t = vote_target(1064u32, Some(1000), 1, 4); + assert_eq!(Some(1032), t); - let t = vote_target(1128u32, 1000, 4); - assert_eq!(1128, t); + let t = vote_target(1128u32, Some(1000), 1, 4); + assert_eq!(Some(1064), t); - let t = vote_target(1256u32, 1000, 4); - assert_eq!(1256, t); + let t = vote_target(1256u32, Some(1000), 1, 4); + assert_eq!(Some(1128), t); - let t = vote_target(1512u32, 1000, 4); - assert_eq!(1512, t); + let t = vote_target(1512u32, Some(1000), 1, 4); + assert_eq!(Some(1256), t); - let t = vote_target(1024u32, 0, 4); - assert_eq!(1024, t); + let t = vote_target(1024u32, Some(1), 1, 4); + assert_eq!(Some(513), t); } #[test] fn vote_on_target_block() { - let t = vote_target(1008u32, 1002, 4); - assert_eq!(1010, t); - let t = vote_target(1010u32, 1002, 4); - assert_eq!(1010, t); - - let t = vote_target(1016u32, 1006, 4); - assert_eq!(1022, t); - let t = vote_target(1022u32, 1006, 4); - assert_eq!(1022, t); - - let t = vote_target(1032u32, 1012, 4); - assert_eq!(1044, t); - let t = vote_target(1044u32, 1012, 4); - assert_eq!(1044, t); - - let t = vote_target(1064u32, 1014, 4); - assert_eq!(1078, t); - let t = vote_target(1078u32, 1014, 4); - assert_eq!(1078, t); - - let t = vote_target(1128u32, 1008, 4); - assert_eq!(1136, t); - let t = vote_target(1136u32, 1008, 4); - assert_eq!(1136, t); + let t = vote_target(1008u32, Some(1002), 1, 4); + assert_eq!(Some(1006), t); + let t = vote_target(1010u32, Some(1002), 1, 4); + assert_eq!(Some(1006), t); + + let t = vote_target(1016u32, Some(1006), 1, 4); + assert_eq!(Some(1014), t); + let t = vote_target(1022u32, Some(1006), 1, 4); + assert_eq!(Some(1014), t); + + let t = vote_target(1032u32, Some(1012), 1, 4); + assert_eq!(Some(1028), t); + let t = vote_target(1044u32, Some(1012), 1, 4); + assert_eq!(Some(1028), t); + + let t = vote_target(1064u32, Some(1014), 1, 4); + assert_eq!(Some(1046), t); + let t = vote_target(1078u32, Some(1014), 1, 4); + assert_eq!(Some(1046), t); + + let t = vote_target(1128u32, Some(1008), 1, 4); + assert_eq!(Some(1072), t); + let t = vote_target(1136u32, Some(1008), 1, 4); + assert_eq!(Some(1072), t); + } + + #[test] + fn vote_on_mandatory_block() { + let t = vote_target(1008u32, Some(1002), 1004, 4); + assert_eq!(Some(1004), t); + let t = vote_target(1016u32, Some(1006), 1007, 4); + assert_eq!(Some(1007), t); + let t = vote_target(1064u32, Some(1014), 1063, 4); + assert_eq!(Some(1063), t); + let t = vote_target(1320u32, Some(1012), 1234, 4); + assert_eq!(Some(1234), t); + + let t = vote_target(1128u32, Some(1008), 1008, 4); + assert_eq!(Some(1072), t); + } + + #[test] + fn extract_authorities_change_digest() { + let mut header = Header::new( + 1u32.into(), + Default::default(), + Default::default(), + Default::default(), + Digest::default(), + ); + + // verify empty digest shows nothing + assert!(find_authorities_change::(&header).is_none()); + + let peers = &[Keyring::One, Keyring::Two]; + let id = 42; + let validator_set = ValidatorSet::new(make_beefy_ids(peers), id).unwrap(); + header.digest_mut().push(DigestItem::Consensus( + BEEFY_ENGINE_ID, + ConsensusLog::::AuthoritiesChange(validator_set.clone()).encode(), + )); + + // verify validator set is correctly extracted from digest + let extracted = find_authorities_change::(&header); + assert_eq!(extracted, Some(validator_set)); + } + + #[test] + fn extract_mmr_root_digest() { + let mut header = Header::new( + 1u32.into(), + Default::default(), + Default::default(), + Default::default(), + Digest::default(), + ); + + // verify empty digest shows nothing + assert!(find_mmr_root_digest::(&header).is_none()); + + let mmr_root_hash = H256::random(); + header.digest_mut().push(DigestItem::Consensus( + BEEFY_ENGINE_ID, + ConsensusLog::::MmrRoot(mmr_root_hash.clone()).encode(), + )); + + // verify validator set is correctly extracted from digest + let extracted = find_mmr_root_digest::(&header); + assert_eq!(extracted, Some(mmr_root_hash)); + } + + #[test] + fn should_vote_target() { + let keys = &[Keyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1, 0); + net.peer(0).data.use_validator_set(&validator_set); + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + + // rounds not initialized -> should vote: `None` + assert_eq!(worker.current_vote_target(), None); + + let set_up = |worker: &mut BeefyWorker< + Block, + PeersFullClient, + Backend, + Arc>, + >, + best_grandpa: u64, + best_beefy: Option, + session_start: u64, + min_delta: u32| { + let grandpa_header = Header::new( + best_grandpa, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ); + worker.best_grandpa_block_header = grandpa_header; + worker.best_beefy_block = best_beefy; + worker.min_block_delta = min_delta; + worker.rounds = + Some(Rounds::new(session_start, validator_set.clone(), validator_set.clone())); + }; + + // under min delta + set_up(&mut worker, 1, Some(1), 1, 4); + assert_eq!(worker.current_vote_target(), None); + set_up(&mut worker, 5, Some(2), 1, 4); + assert_eq!(worker.current_vote_target(), None); + + // vote on min delta + set_up(&mut worker, 9, Some(4), 1, 4); + assert_eq!(worker.current_vote_target(), Some(8)); + set_up(&mut worker, 18, Some(10), 1, 8); + assert_eq!(worker.current_vote_target(), Some(18)); + + // vote on power of two + set_up(&mut worker, 1008, Some(1000), 1, 1); + assert_eq!(worker.current_vote_target(), Some(1004)); + set_up(&mut worker, 1016, Some(1000), 1, 2); + assert_eq!(worker.current_vote_target(), Some(1008)); + + // nothing new to vote on + set_up(&mut worker, 1000, Some(1000), 1, 1); + assert_eq!(worker.current_vote_target(), None); + + // vote on mandatory + set_up(&mut worker, 1008, None, 1000, 8); + assert_eq!(worker.current_vote_target(), Some(1000)); + set_up(&mut worker, 1008, Some(1000), 1001, 8); + assert_eq!(worker.current_vote_target(), Some(1001)); + } + + #[test] + fn keystore_vs_validator_set() { + let keys = &[Keyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1, 0); + net.peer(0).data.use_validator_set(&validator_set); + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + + // keystore doesn't contain other keys than validators' + assert_eq!(worker.verify_validator_set(&1, &validator_set), Ok(())); + + // unknown `Bob` key + let keys = &[Keyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let err_msg = "no authority public key found in store".to_string(); + let expected = Err(error::Error::Keystore(err_msg)); + assert_eq!(worker.verify_validator_set(&1, &validator_set), expected); + + // worker has no keystore + worker.key_store = None.into(); + let expected_err = Err(error::Error::Keystore("no Keystore".into())); + assert_eq!(worker.verify_validator_set(&1, &validator_set), expected_err); + } + + #[test] + fn setting_best_beefy_block() { + let keys = &[Keyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1, 0); + net.peer(0).data.use_validator_set(&validator_set); + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + + let (mut best_block_streams, _) = get_beefy_streams(&mut net, keys); + let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); + + // no 'best beefy block' + assert_eq!(worker.best_beefy_block, None); + block_on(poll_fn(move |cx| { + assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); + Poll::Ready(()) + })); + + // unknown hash for block #1 + let (mut best_block_streams, _) = get_beefy_streams(&mut net, keys); + let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); + worker.set_best_beefy_block(1); + assert_eq!(worker.best_beefy_block, Some(1)); + block_on(poll_fn(move |cx| { + assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); + Poll::Ready(()) + })); + + // generate 2 blocks, try again expect success + let (mut best_block_streams, _) = get_beefy_streams(&mut net, keys); + let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); + net.generate_blocks(2, 10, &validator_set); + + worker.set_best_beefy_block(2); + assert_eq!(worker.best_beefy_block, Some(2)); + block_on(poll_fn(move |cx| { + match best_block_stream.poll_next_unpin(cx) { + // expect Some(hash-of-block-2) + Poll::Ready(Some(hash)) => { + let block_num = net.peer(0).client().as_client().number(hash).unwrap(); + assert_eq!(block_num, Some(2)); + }, + v => panic!("unexpected value: {:?}", v), + } + Poll::Ready(()) + })); + } + + #[test] + fn setting_initial_session() { + let keys = &[Keyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1, 0); + net.peer(0).data.use_validator_set(&validator_set); + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + + assert!(worker.rounds.is_none()); + + // verify setting the correct validator sets and boundary for genesis session + worker.init_session_at(validator_set.clone(), 1); + + let worker_rounds = worker.rounds.as_ref().unwrap(); + assert_eq!(worker_rounds.validator_set(), &validator_set); + assert_eq!(worker_rounds.session_start(), &1); + // in genesis case both current and prev validator sets are the same + assert_eq!(worker_rounds.validator_set_id_for(1), validator_set.id()); + assert_eq!(worker_rounds.validator_set_id_for(2), validator_set.id()); + + // new validator set + let keys = &[Keyring::Bob]; + let new_validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); + + // verify setting the correct validator sets and boundary for non-genesis session + worker.init_session_at(new_validator_set.clone(), 11); + + let worker_rounds = worker.rounds.as_ref().unwrap(); + assert_eq!(worker_rounds.validator_set(), &new_validator_set); + assert_eq!(worker_rounds.session_start(), &11); + // mandatory block gets prev set, further blocks get new set + assert_eq!(worker_rounds.validator_set_id_for(11), validator_set.id()); + assert_eq!(worker_rounds.validator_set_id_for(12), new_validator_set.id()); + assert_eq!(worker_rounds.validator_set_id_for(13), new_validator_set.id()); } } diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 4aa1d1337cd0a..744a06561e8c2 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -105,20 +105,20 @@ impl Pallet { } fn change_authorities(new: Vec, queued: Vec) { - // As in GRANDPA, we trigger a validator set change only if the the validator - // set has actually changed. - if new != Self::authorities() { - >::put(&new); - - let next_id = Self::validator_set_id() + 1u64; - >::put(next_id); - if let Some(validator_set) = ValidatorSet::::new(new, next_id) { - let log = DigestItem::Consensus( - BEEFY_ENGINE_ID, - ConsensusLog::AuthoritiesChange(validator_set).encode(), - ); - >::deposit_log(log); - } + // Always issue a change if `session` says that the validators have changed. + // Even if their session keys are the same as before, the underlying economic + // identities have changed. Furthermore, the digest below is used to signal + // BEEFY mandatory blocks. + >::put(&new); + + let next_id = Self::validator_set_id() + 1u64; + >::put(next_id); + if let Some(validator_set) = ValidatorSet::::new(new, next_id) { + let log = DigestItem::Consensus( + BEEFY_ENGINE_ID, + ConsensusLog::AuthoritiesChange(validator_set).encode(), + ); + >::deposit_log(log); } >::put(&queued); diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 4aa53aff2c3cb..cf901f4a34fc6 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -4,8 +4,13 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate" description = "Primitives for BEEFY protocol." +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 8c61cbbf8adbe..ad7dca5e08fb1 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -13,6 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] +beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } @@ -65,6 +66,7 @@ default = [ "std", ] std = [ + "beefy-primitives/std", "sp-application-crypto/std", "sp-consensus-aura/std", "sp-consensus-babe/std", diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 861d95efb3087..743652a0ee899 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -926,6 +926,12 @@ cfg_if! { } } + impl beefy_primitives::BeefyApi for RuntimeApi { + fn validator_set() -> Option> { + None + } + } + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { fn account_nonce(_account: AccountId) -> Index { 0 From b8aea6225c4c97ddebd5b502b17952fa45e359b2 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 25 Mar 2022 19:38:39 +0000 Subject: [PATCH 0639/1472] Remove unneeded code (#11117) * Remove unneeded code * Remove unused imports Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/whitelist/src/lib.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index c2de16964a494..239f0fd280160 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -39,7 +39,7 @@ mod mock; mod tests; pub mod weights; -use codec::{Decode, DecodeLimit, Encode, FullCodec, MaxEncodedLen}; +use codec::{DecodeLimit, Encode, FullCodec}; use frame_support::{ ensure, traits::{PreimageProvider, PreimageRecipient}, @@ -51,12 +51,6 @@ use sp_std::prelude::*; pub use pallet::*; -#[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct Preimage { - preimage: BoundedVec, - deposit: Option<(AccountId, Balance)>, -} - #[frame_support::pallet] pub mod pallet { use super::*; From 69079b58579ea36812c4a375a118f27aac0fb281 Mon Sep 17 00:00:00 2001 From: Georges Date: Fri, 25 Mar 2022 20:15:50 +0000 Subject: [PATCH 0640/1472] Add a bounded fallback on failed elections (#10988) * Allow `pallet-election-provider` to accept smaller solutions, issue #9478 * Fixing a typo * Adding some more tests Removing a seemingly outdated comment * making it a URL * Updating test name as per suggestion Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Updating documentation to be more explicit And to follow the general guidelines Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fixing formatting * `Fallback` now of type `InstantElectionProvider` Some cleanups * Allow `pallet-election-provider` to accept smaller solutions, issue #9478 * Fixing a typo * Adding some more tests Removing a seemingly outdated comment * making it a URL * Updating test name as per suggestion Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Updating documentation to be more explicit And to follow the general guidelines Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fixing formatting * `Fallback` now of type `InstantElectionProvider` Some cleanups * Merging types into one type with generics * Removing `ConstUSize` and use `ConstU32` * cleaning up the code * deprecating `OnChainSequentialPhragmen` Renaming it to `UnboundedSequentialPhragmen` which should only be used at genesis and for testing. Use preferrably `BoundedOnChainSequentialPhragmen` * Amending docs * Adding some explicit imports * Implementing generic `BoundedOnchainExecution` Removing the deprecated `OnChainSequentialPhragmen` * Use the right Balancing strategy * Refactoring `onchain::Config` Creating `onchain::ExecutionConfig` * Merge master * fmt * Name cleanups after review suggestions * cosmetics * renaming `instant_elect` to `elect_with_bounds` Other corresponding changes as per @kianenigma feedback * `BoundedOnchainExecution` -> `BoundedExecution` And `UnboundedOnchainExecution` -> `UnboundedExecution` * feedback from kian * fmt + unneeded import Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: kianenigma --- bin/node/runtime/src/lib.rs | 34 ++-- frame/babe/src/mock.rs | 10 +- .../election-provider-multi-phase/src/lib.rs | 26 ++- .../election-provider-multi-phase/src/mock.rs | 30 ++- frame/election-provider-support/src/lib.rs | 20 +- .../election-provider-support/src/onchain.rs | 189 +++++++++++------- frame/grandpa/src/mock.rs | 10 +- .../merkle-mountain-range/src/mmr/storage.rs | 7 +- frame/offences/benchmarking/src/mock.rs | 10 +- frame/session/benchmarking/src/mock.rs | 10 +- frame/staking/src/mock.rs | 12 +- 11 files changed, 223 insertions(+), 135 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 47bdedbab83a3..565f151ce2a08 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -23,7 +23,7 @@ #![recursion_limit = "256"] use codec::{Decode, Encode, MaxEncodedLen}; -use frame_election_provider_support::{onchain, ExtendedBalance, VoteWeight}; +use frame_election_provider_support::{onchain, ExtendedBalance, SequentialPhragmen, VoteWeight}; use frame_support::{ construct_runtime, pallet_prelude::Get, @@ -557,7 +557,7 @@ impl pallet_staking::Config for Runtime { type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; - type GenesisElectionProvider = onchain::OnChainSequentialPhragmen; + type GenesisElectionProvider = onchain::UnboundedExecution; type VoterList = BagsList; type MaxUnlockingChunks = ConstU32<32>; type WeightInfo = pallet_staking::weights::SubstrateWeight; @@ -642,9 +642,19 @@ impl Get> for OffchainRandomBalancing { } } -impl onchain::Config for Runtime { - type Accuracy = Perbill; - type DataProvider = ::DataProvider; +pub struct OnChainSeqPhragmen; +impl onchain::ExecutionConfig for OnChainSeqPhragmen { + type System = Runtime; + type Solver = SequentialPhragmen< + AccountId, + pallet_election_provider_multi_phase::SolutionAccuracyOf, + >; + type DataProvider = ::DataProvider; +} + +impl onchain::BoundedExecutionConfig for OnChainSeqPhragmen { + type VotersBound = ConstU32<20_000>; + type TargetsBound = ConstU32<2_000>; } impl pallet_election_provider_multi_phase::Config for Runtime { @@ -668,13 +678,9 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type RewardHandler = (); // nothing to do upon rewards type DataProvider = Staking; type Solution = NposSolution16; - type Fallback = pallet_election_provider_multi_phase::NoFallback; - type GovernanceFallback = onchain::OnChainSequentialPhragmen; - type Solver = frame_election_provider_support::SequentialPhragmen< - AccountId, - SolutionAccuracyOf, - OffchainRandomBalancing, - >; + type Fallback = onchain::BoundedExecution; + type GovernanceFallback = onchain::BoundedExecution; + type Solver = SequentialPhragmen, OffchainRandomBalancing>; type ForceOrigin = EnsureRootOrHalfCouncil; type MaxElectableTargets = ConstU16<{ u16::MAX }>; type MaxElectingVoters = MaxElectingVoters; @@ -1899,6 +1905,7 @@ impl_runtime_apis! { #[cfg(test)] mod tests { use super::*; + use frame_election_provider_support::NposSolution; use frame_system::offchain::CreateSignedTransaction; use sp_runtime::UpperOf; @@ -1915,7 +1922,8 @@ mod tests { #[test] fn perbill_as_onchain_accuracy() { - type OnChainAccuracy = ::Accuracy; + type OnChainAccuracy = + <::Solution as NposSolution>::Accuracy; let maximum_chain_accuracy: Vec> = (0..MaxNominations::get()) .map(|_| >::from(OnChainAccuracy::one().deconstruct())) .collect(); diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index e74288577c9ef..37d8e9e37a5f4 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -19,7 +19,7 @@ use crate::{self as pallet_babe, Config, CurrentSlot}; use codec::Encode; -use frame_election_provider_support::onchain; +use frame_election_provider_support::{onchain, SequentialPhragmen}; use frame_support::{ parameter_types, traits::{ConstU128, ConstU32, ConstU64, GenesisBuild, KeyOwnerProofSystem, OnInitialize}, @@ -172,8 +172,10 @@ parameter_types! { pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(16); } -impl onchain::Config for Test { - type Accuracy = Perbill; +pub struct OnChainSeqPhragmen; +impl onchain::ExecutionConfig for OnChainSeqPhragmen { + type System = Test; + type Solver = SequentialPhragmen; type DataProvider = Staking; } @@ -195,7 +197,7 @@ impl pallet_staking::Config for Test { type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; - type ElectionProvider = onchain::OnChainSequentialPhragmen; + type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index ddc06ce0aecfd..e67a5cab8d643 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -242,7 +242,7 @@ use frame_support::{ use frame_system::{ensure_none, offchain::SendTransactionTypes}; use scale_info::TypeInfo; use sp_arithmetic::{ - traits::{CheckedAdd, Saturating, Zero}, + traits::{Bounded, CheckedAdd, Saturating, Zero}, UpperOf, }; use sp_npos_elections::{ @@ -323,10 +323,7 @@ impl ElectionProvider for NoFallback { } impl InstantElectionProvider for NoFallback { - fn instant_elect( - _: Option, - _: Option, - ) -> Result, Self::Error> { + fn elect_with_bounds(_: usize, _: usize) -> Result, Self::Error> { Err("NoFallback.") } } @@ -683,7 +680,7 @@ pub mod pallet { + TypeInfo; /// Configuration for the fallback. - type Fallback: ElectionProvider< + type Fallback: InstantElectionProvider< AccountId = Self::AccountId, BlockNumber = Self::BlockNumber, DataProvider = Self::DataProvider, @@ -692,7 +689,7 @@ pub mod pallet { /// Configuration of the governance-only fallback. /// /// As a side-note, it is recommend for test-nets to use `type ElectionProvider = - /// OnChainSeqPhragmen<_>` if the test-net is not expected to have thousands of nominators. + /// BoundedExecution<_>` if the test-net is not expected to have thousands of nominators. type GovernanceFallback: InstantElectionProvider< AccountId = Self::AccountId, BlockNumber = Self::BlockNumber, @@ -1040,13 +1037,14 @@ pub mod pallet { let maybe_max_voters = maybe_max_voters.map(|x| x as usize); let maybe_max_targets = maybe_max_targets.map(|x| x as usize); - let supports = - T::GovernanceFallback::instant_elect(maybe_max_voters, maybe_max_targets).map_err( - |e| { - log!(error, "GovernanceFallback failed: {:?}", e); - Error::::FallbackFailed - }, - )?; + let supports = T::GovernanceFallback::elect_with_bounds( + maybe_max_voters.unwrap_or(Bounded::max_value()), + maybe_max_targets.unwrap_or(Bounded::max_value()), + ) + .map_err(|e| { + log!(error, "GovernanceFallback failed: {:?}", e); + Error::::FallbackFailed + })?; let solution = ReadySolution { supports, diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index e2384d2f15761..1b3c4d9306246 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -272,11 +272,13 @@ parameter_types! { pub static MaxElectableTargets: TargetIndex = TargetIndex::max_value(); pub static EpochLength: u64 = 30; - pub static OnChianFallback: bool = true; + pub static OnChainFallback: bool = true; } -impl onchain::Config for Runtime { - type Accuracy = sp_runtime::Perbill; +pub struct OnChainSeqPhragmen; +impl onchain::ExecutionConfig for OnChainSeqPhragmen { + type System = Runtime; + type Solver = SequentialPhragmen, Balancing>; type DataProvider = StakingMock; } @@ -288,11 +290,23 @@ impl ElectionProvider for MockFallback { type DataProvider = StakingMock; fn elect() -> Result, Self::Error> { - if OnChianFallback::get() { - onchain::OnChainSequentialPhragmen::::elect() - .map_err(|_| "OnChainSequentialPhragmen failed") + Self::elect_with_bounds(Bounded::max_value(), Bounded::max_value()) + } +} + +impl InstantElectionProvider for MockFallback { + fn elect_with_bounds( + max_voters: usize, + max_targets: usize, + ) -> Result, Self::Error> { + if OnChainFallback::get() { + onchain::UnboundedExecution::::elect_with_bounds( + max_voters, + max_targets, + ) + .map_err(|_| "UnboundedExecution failed") } else { - super::NoFallback::::elect() + super::NoFallback::::elect_with_bounds(max_voters, max_targets) } } } @@ -532,7 +546,7 @@ impl ExtBuilder { self } pub fn onchain_fallback(self, onchain: bool) -> Self { - ::set(onchain); + ::set(onchain); self } pub fn miner_weight(self, weight: Weight) -> Self { diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 2cc27472e8846..d79b5289dffe3 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -168,6 +168,7 @@ pub mod onchain; pub mod traits; +#[cfg(feature = "std")] use codec::{Decode, Encode}; use frame_support::{traits::Get, BoundedVec, RuntimeDebug}; use sp_runtime::traits::Bounded; @@ -368,9 +369,10 @@ pub trait ElectionProvider { BlockNumber = Self::BlockNumber, >; - /// Elect a new set of winners. + /// Elect a new set of winners, without specifying any bounds on the amount of data fetched from + /// [`Self::DataProvider`]. An implementation could nonetheless impose its own custom limits. /// - /// The result is returned in a target major format, namely as vector of supports. + /// The result is returned in a target major format, namely as *vector of supports*. /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. @@ -385,11 +387,17 @@ pub trait ElectionProvider { /// Consequently, allows for control over the amount of data that is being fetched from the /// [`ElectionProvider::DataProvider`]. pub trait InstantElectionProvider: ElectionProvider { - /// Elect a new set of winners, instantly, with the given given limits set on the + /// Elect a new set of winners, but unlike [`ElectionProvider::elect`] which cannot enforce + /// bounds, this trait method can enforce bounds on the amount of data provided by the /// `DataProvider`. - fn instant_elect( - maybe_max_voters: Option, - maybe_max_targets: Option, + /// + /// An implementing type, if itself bounded, should choose the minimum of the two bounds to + /// choose the final value of `max_voters` and `max_targets`. In other words, an implementation + /// should guarantee that `max_voter` and `max_targets` provided to this method are absolutely + /// respected. + fn elect_with_bounds( + max_voters: usize, + max_targets: usize, ) -> Result, Self::Error>; } diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 7d845c2dc5ab3..57fd931a467d1 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! An implementation of [`ElectionProvider`] that does an on-chain sequential phragmen. +//! An implementation of [`ElectionProvider`] that uses an `NposSolver` to do the election. -use crate::{ElectionDataProvider, ElectionProvider, InstantElectionProvider}; +use crate::{ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolver}; use frame_support::{traits::Get, weights::DispatchClass}; use sp_npos_elections::*; use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; @@ -41,92 +41,141 @@ impl From for Error { /// /// This will accept voting data on the fly and produce the results immediately. /// -/// ### Warning -/// -/// This can be very expensive to run frequently on-chain. Use with care. Moreover, this -/// implementation ignores the additional data of the election data provider and gives no insight on -/// how much weight was consumed. -/// /// Finally, the [`ElectionProvider`] implementation of this type does not impose any limits on the /// number of voters and targets that are fetched. This could potentially make this unsuitable for -/// execution onchain. On the other hand, the [`InstantElectionProvider`] implementation does limit -/// these inputs. +/// execution onchain. One could, however, impose bounds on it by using for example +/// `BoundedExecution` which will the bounds provided in the configuration. +/// +/// On the other hand, the [`InstantElectionProvider`] implementation does limit these inputs, +/// either via using `BoundedExecution` and imposing the bounds there, or dynamically via calling +/// `elect_with_bounds` providing these bounds. If you use `elect_with_bounds` along with +/// `InstantElectionProvider`, the bound that would be used is the minimum of the 2 bounds. /// /// It is advisable to use the former ([`ElectionProvider::elect`]) only at genesis, or for testing, -/// the latter [`InstantElectionProvider::instant_elect`] for onchain operations, with thoughtful -/// bounds. -pub struct OnChainSequentialPhragmen(PhantomData); +/// the latter [`InstantElectionProvider::elect_with_bounds`] for onchain operations, with +/// thoughtful bounds. +/// +/// Please use `BoundedExecution` at all times except at genesis or for testing, with thoughtful +/// bounds in order to bound the potential execution time. Limit the use `UnboundedExecution` at +/// genesis or for testing, as it does not bound the inputs. However, this can be used with +/// `[InstantElectionProvider::elect_with_bounds`] that dynamically imposes limits. +pub struct BoundedExecution(PhantomData); -/// Configuration trait of [`OnChainSequentialPhragmen`]. +/// An unbounded variant of [`BoundedExecution`]. /// -/// Note that this is similar to a pallet traits, but [`OnChainSequentialPhragmen`] is not a pallet. +/// ### Warning /// -/// WARNING: the user of this pallet must ensure that the `Accuracy` type will work nicely with the -/// normalization operation done inside `seq_phragmen`. See -/// [`sp_npos_elections::Assignment::try_normalize`] for more info. -pub trait Config: frame_system::Config { - /// The accuracy used to compute the election: - type Accuracy: PerThing128; +/// This can be very expensive to run frequently on-chain. Use with care. Moreover, this +/// implementation ignores the additional data of the election data provider and gives no insight on +/// how much weight was consumed. +pub struct UnboundedExecution(PhantomData); + +/// Configuration trait of [`UnboundedExecution`]. +pub trait ExecutionConfig { + /// Something that implements the system pallet configs. This is to enable to register extra + /// weight. + type System: frame_system::Config; + /// `NposSolver` that should be used, an example would be `PhragMMS`. + type Solver: NposSolver< + AccountId = ::AccountId, + Error = sp_npos_elections::Error, + >; /// Something that provides the data for election. type DataProvider: ElectionDataProvider< - AccountId = Self::AccountId, - BlockNumber = Self::BlockNumber, + AccountId = ::AccountId, + BlockNumber = ::BlockNumber, >; } -impl OnChainSequentialPhragmen { - fn elect_with( - maybe_max_voters: Option, - maybe_max_targets: Option, - ) -> Result, Error> { - let voters = ::DataProvider::electing_voters(maybe_max_voters) - .map_err(Error::DataProvider)?; - let targets = - ::DataProvider::electable_targets(maybe_max_targets) - .map_err(Error::DataProvider)?; - let desired_targets = ::DataProvider::desired_targets() - .map_err(Error::DataProvider)?; - - let stake_map: BTreeMap = voters - .iter() - .map(|(validator, vote_weight, _)| (validator.clone(), *vote_weight)) - .collect(); - - let stake_of = - |w: &T::AccountId| -> VoteWeight { stake_map.get(w).cloned().unwrap_or_default() }; - - let ElectionResult::<_, T::Accuracy> { winners: _, assignments } = - seq_phragmen(desired_targets as usize, targets, voters, None).map_err(Error::from)?; - - let staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?; - - let weight = T::BlockWeights::get().max_block; - frame_system::Pallet::::register_extra_weight_unchecked( - weight, - DispatchClass::Mandatory, - ); - - Ok(to_supports(&staked)) +/// Configuration trait of [`BoundedExecution`]. +pub trait BoundedExecutionConfig: ExecutionConfig { + /// Bounds the number of voters. + type VotersBound: Get; + /// Bounds the number of targets. + type TargetsBound: Get; +} + +fn elect_with( + maybe_max_voters: Option, + maybe_max_targets: Option, +) -> Result::AccountId>, Error> { + let voters = T::DataProvider::electing_voters(maybe_max_voters).map_err(Error::DataProvider)?; + let targets = + T::DataProvider::electable_targets(maybe_max_targets).map_err(Error::DataProvider)?; + let desired_targets = T::DataProvider::desired_targets().map_err(Error::DataProvider)?; + + let stake_map: BTreeMap<_, _> = voters + .iter() + .map(|(validator, vote_weight, _)| (validator.clone(), *vote_weight)) + .collect(); + + let stake_of = |w: &::AccountId| -> VoteWeight { + stake_map.get(w).cloned().unwrap_or_default() + }; + + let ElectionResult { winners: _, assignments } = + T::Solver::solve(desired_targets as usize, targets, voters).map_err(Error::from)?; + + let staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?; + + let weight = ::BlockWeights::get().max_block; + frame_system::Pallet::::register_extra_weight_unchecked( + weight, + DispatchClass::Mandatory, + ); + + Ok(to_supports(&staked)) +} + +impl ElectionProvider for UnboundedExecution { + type AccountId = ::AccountId; + type BlockNumber = ::BlockNumber; + type Error = Error; + type DataProvider = T::DataProvider; + + fn elect() -> Result::AccountId>, Self::Error> { + // This should not be called if not in `std` mode (and therefore neither in genesis nor in + // testing) + if cfg!(not(feature = "std")) { + frame_support::log::error!( + "Please use `InstantElectionProvider` instead to provide bounds on election if not in \ + genesis or testing mode" + ); + } + + elect_with::(None, None) } } -impl ElectionProvider for OnChainSequentialPhragmen { - type AccountId = T::AccountId; - type BlockNumber = T::BlockNumber; +impl InstantElectionProvider for UnboundedExecution { + fn elect_with_bounds( + max_voters: usize, + max_targets: usize, + ) -> Result, Self::Error> { + elect_with::(Some(max_voters), Some(max_targets)) + } +} + +impl ElectionProvider for BoundedExecution { + type AccountId = ::AccountId; + type BlockNumber = ::BlockNumber; type Error = Error; type DataProvider = T::DataProvider; - fn elect() -> Result, Self::Error> { - Self::elect_with(None, None) + fn elect() -> Result::AccountId>, Self::Error> { + elect_with::(Some(T::VotersBound::get() as usize), Some(T::TargetsBound::get() as usize)) } } -impl InstantElectionProvider for OnChainSequentialPhragmen { - fn instant_elect( - maybe_max_voters: Option, - maybe_max_targets: Option, +impl InstantElectionProvider for BoundedExecution { + fn elect_with_bounds( + max_voters: usize, + max_targets: usize, ) -> Result, Self::Error> { - Self::elect_with(maybe_max_voters, maybe_max_targets) + elect_with::( + Some(max_voters.min(T::VotersBound::get() as usize)), + Some(max_targets.min(T::TargetsBound::get() as usize)), + ) } } @@ -135,7 +184,6 @@ mod tests { use super::*; use sp_npos_elections::Support; use sp_runtime::Perbill; - type AccountId = u64; type BlockNumber = u64; @@ -180,12 +228,13 @@ mod tests { type MaxConsumers = frame_support::traits::ConstU32<16>; } - impl Config for Runtime { - type Accuracy = Perbill; + impl ExecutionConfig for Runtime { + type System = Self; + type Solver = crate::SequentialPhragmen; type DataProvider = mock_data_provider::DataProvider; } - type OnChainPhragmen = OnChainSequentialPhragmen; + type OnChainPhragmen = UnboundedExecution; mod mock_data_provider { use frame_support::{bounded_vec, traits::ConstU32}; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 6490a2b6992bf..0296cd2e28d88 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -22,7 +22,7 @@ use crate::{self as pallet_grandpa, AuthorityId, AuthorityList, Config, ConsensusLog}; use ::grandpa as finality_grandpa; use codec::Encode; -use frame_election_provider_support::onchain; +use frame_election_provider_support::{onchain, SequentialPhragmen}; use frame_support::{ parameter_types, traits::{ @@ -180,8 +180,10 @@ parameter_types! { pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); } -impl onchain::Config for Test { - type Accuracy = Perbill; +pub struct OnChainSeqPhragmen; +impl onchain::ExecutionConfig for OnChainSeqPhragmen { + type System = Test; + type Solver = SequentialPhragmen<::AccountId, Perbill>; type DataProvider = Staking; } @@ -203,7 +205,7 @@ impl pallet_staking::Config for Test { type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; - type ElectionProvider = onchain::OnChainSequentialPhragmen; + type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index a48f60183d679..535057ca80da7 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -18,7 +18,6 @@ //! A MMR storage implementations. use codec::Encode; -use frame_support::log; use mmr_lib::helper; use sp_io::offchain_index; use sp_std::iter::Peekable; @@ -93,7 +92,7 @@ where } sp_std::if_std! { - log::trace!("elems: {:?}", elems.iter().map(|elem| elem.hash()).collect::>()); + frame_support::log::trace!("elems: {:?}", elems.iter().map(|elem| elem.hash()).collect::>()); } let leaves = NumberOfLeaves::::get(); @@ -152,8 +151,8 @@ fn peaks_to_prune_and_store( let peaks_before = if old_size == 0 { vec![] } else { helper::get_peaks(old_size) }; let peaks_after = helper::get_peaks(new_size); sp_std::if_std! { - log::trace!("peaks_before: {:?}", peaks_before); - log::trace!("peaks_after: {:?}", peaks_after); + frame_support::log::trace!("peaks_before: {:?}", peaks_before); + frame_support::log::trace!("peaks_after: {:?}", peaks_after); } let mut peaks_before = peaks_before.into_iter().peekable(); let mut peaks_after = peaks_after.into_iter().peekable(); diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 4359b7745ddd6..1a4414de0b0b0 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -20,7 +20,7 @@ #![cfg(test)] use super::*; -use frame_election_provider_support::onchain; +use frame_election_provider_support::{onchain, SequentialPhragmen}; use frame_support::{ parameter_types, traits::{ConstU32, ConstU64}, @@ -150,8 +150,10 @@ parameter_types! { pub type Extrinsic = sp_runtime::testing::TestXt; -impl onchain::Config for Test { - type Accuracy = Perbill; +pub struct OnChainSeqPhragmen; +impl onchain::ExecutionConfig for OnChainSeqPhragmen { + type System = Test; + type Solver = SequentialPhragmen; type DataProvider = Staking; } @@ -173,7 +175,7 @@ impl pallet_staking::Config for Test { type NextNewSession = Session; type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); - type ElectionProvider = onchain::OnChainSequentialPhragmen; + type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 5ebc75245630c..24b42b3e9f4b5 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -19,7 +19,7 @@ #![cfg(test)] -use frame_election_provider_support::onchain; +use frame_election_provider_support::{onchain, SequentialPhragmen}; use frame_support::{ parameter_types, traits::{ConstU32, ConstU64}, @@ -156,8 +156,10 @@ where type Extrinsic = Extrinsic; } -impl onchain::Config for Test { - type Accuracy = sp_runtime::Perbill; +pub struct OnChainSeqPhragmen; +impl onchain::ExecutionConfig for OnChainSeqPhragmen { + type System = Test; + type Solver = SequentialPhragmen; type DataProvider = Staking; } @@ -179,7 +181,7 @@ impl pallet_staking::Config for Test { type NextNewSession = Session; type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); - type ElectionProvider = onchain::OnChainSequentialPhragmen; + type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type MaxUnlockingChunks = ConstU32<32>; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index bb71232c34673..bb90aded852ee 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -18,7 +18,9 @@ //! Test utilities use crate::{self as pallet_staking, *}; -use frame_election_provider_support::{onchain, SortedListProvider, VoteWeight}; +use frame_election_provider_support::{ + onchain, SequentialPhragmen, SortedListProvider, VoteWeight, +}; use frame_support::{ assert_ok, parameter_types, traits::{ @@ -245,8 +247,10 @@ impl pallet_bags_list::Config for Test { type Score = VoteWeight; } -impl onchain::Config for Test { - type Accuracy = Perbill; +pub struct OnChainSeqPhragmen; +impl onchain::ExecutionConfig for OnChainSeqPhragmen { + type System = Test; + type Solver = SequentialPhragmen; type DataProvider = Staking; } @@ -268,7 +272,7 @@ impl crate::pallet::pallet::Config for Test { type NextNewSession = Session; type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; - type ElectionProvider = onchain::OnChainSequentialPhragmen; + type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. type VoterList = BagsList; From 4b8cbaa8eb0e9734095425da0e9f952004b5450f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Mar 2022 08:19:07 +0100 Subject: [PATCH 0641/1472] Bump handlebars from 4.1.6 to 4.2.2 (#11073) Bumps [handlebars](https://github.com/sunng87/handlebars-rust) from 4.1.6 to 4.2.2. - [Release notes](https://github.com/sunng87/handlebars-rust/releases) - [Changelog](https://github.com/sunng87/handlebars-rust/blob/master/CHANGELOG.md) - [Commits](https://github.com/sunng87/handlebars-rust/compare/v4.1.6...v4.2.2) --- updated-dependencies: - dependency-name: handlebars 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 | 4 ++-- utils/frame/benchmarking-cli/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81a53ed858859..2a761b9a761ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2779,9 +2779,9 @@ checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" [[package]] name = "handlebars" -version = "4.1.6" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167fa173496c9eadd8749cca6f8339ac88e248f3ad2442791d0b743318a94fc0" +checksum = "99d6a30320f094710245150395bc763ad23128d6a1ebbad7594dc4164b62c56b" dependencies = [ "log 0.4.14", "pest", diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 11bba2b37957f..5cb81232085a4 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -40,7 +40,7 @@ clap = { version = "3.1.6", features = ["derive"] } chrono = "0.4" serde = "1.0.136" serde_json = "1.0.79" -handlebars = "4.1.6" +handlebars = "4.2.2" Inflector = "0.11.4" linked-hash-map = "0.5.4" log = "0.4.8" From d26123aec44e3df00b921ab0d27cbc1de0b11fa9 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sun, 27 Mar 2022 02:43:47 -0400 Subject: [PATCH 0642/1472] remove misleading sentence (#11125) --- frame/support/src/storage/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 226682eecf10b..4a0eebf567993 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -517,9 +517,6 @@ pub trait IterableStorageNMap: StorageN /// An implementation of a map with a two keys. /// -/// It provides an important ability to efficiently remove all entries -/// that have a common first key. -/// /// Details on implementation can be found at [`generator::StorageDoubleMap`]. pub trait StorageDoubleMap { /// The type that get/take returns. From 6615ae4751ab35a913ac32a3ba210b35899db3d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 27 Mar 2022 21:19:55 +0200 Subject: [PATCH 0643/1472] Bump zeroize from 1.4.3 to 1.5.4 (#11123) Bumps [zeroize](https://github.com/RustCrypto/utils) from 1.4.3 to 1.5.4. - [Release notes](https://github.com/RustCrypto/utils/releases) - [Commits](https://github.com/RustCrypto/utils/compare/zeroize-v1.4.3...zeroize-v1.5.4) --- updated-dependencies: - dependency-name: zeroize 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 ++++---- client/network/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a761b9a761ed..ac30433c5ea28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12474,18 +12474,18 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.4.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" +checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.2.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ "proc-macro2", "quote", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 671271fcb3b77..d6bc90016ab82 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -61,7 +61,7 @@ unsigned-varint = { version = "0.6.0", features = [ "asynchronous_codec", ] } void = "1.0.2" -zeroize = "1.4.3" +zeroize = "1.5.4" libp2p = "0.40.0" [dev-dependencies] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 55d00362033d0..413a11c9dc0a4 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -32,7 +32,7 @@ substrate-bip39 = { version = "0.4.4", optional = true } tiny-bip39 = { version = "0.8.2", optional = true } regex = { version = "1.5.4", optional = true } num-traits = { version = "0.2.8", default-features = false } -zeroize = { version = "1.4.3", default-features = false } +zeroize = { version = "1.5.4", default-features = false } secrecy = { version = "0.8.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.12.0", optional = true } From 65b44e91bedd6961ef30cef08e89273b7d98b4ed Mon Sep 17 00:00:00 2001 From: Alexander Popiak Date: Sun, 27 Mar 2022 23:35:52 +0200 Subject: [PATCH 0644/1472] add notes and warnings to ProvideInherent docs (#9730) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add notes and warnings to ProvideInherent docs * rephrase ProvideInherent doc comments * more comment refinement * remove multiple inherents note * remove repetition Co-authored-by: Bastian Köcher * replace inherent example in docs * add note about who checks is_inherent_required * Apply suggestions from code review Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- frame/support/src/inherent.rs | 35 ++++++++++++++++++++++++--------- primitives/inherents/src/lib.rs | 12 +++++------ 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/frame/support/src/inherent.rs b/frame/support/src/inherent.rs index 59d55b1df3f3c..0aa6b9d3f75a9 100644 --- a/frame/support/src/inherent.rs +++ b/frame/support/src/inherent.rs @@ -24,9 +24,12 @@ pub use sp_inherents::{ CheckInherentsResult, InherentData, InherentIdentifier, IsFatalError, MakeFatalError, }; -/// A pallet that provides or verifies an inherent extrinsic. +/// A pallet that provides or verifies an inherent extrinsic will implement this trait. /// -/// The pallet may provide the inherent, verify an inherent, or both provide and verify. +/// The pallet may provide an inherent, verify an inherent, or both provide and verify. +/// +/// Briefly, inherent extrinsics ("inherents") are extrinsics that are added to a block by the block +/// producer. See [`sp_inherents`] for more documentation on inherents. pub trait ProvideInherent { /// The call type of the pallet. type Call; @@ -36,6 +39,12 @@ pub trait ProvideInherent { const INHERENT_IDENTIFIER: self::InherentIdentifier; /// Create an inherent out of the given `InherentData`. + /// + /// NOTE: All checks necessary to ensure that the inherent is correct and that can be done in + /// the runtime should happen in the returned `Call`. + /// E.g. if this provides the timestamp, the call will check that the given timestamp is + /// increasing the old timestamp by more than a minimum and it will also check that the + /// timestamp hasn't already been set in the current block. fn create_inherent(data: &InherentData) -> Option; /// Determines whether this inherent is required in this block. @@ -44,15 +53,17 @@ pub trait ProvideInherent { /// implementation returns this. /// /// - `Ok(Some(e))` indicates that this inherent is required in this block. `construct_runtime!` - /// will call this function from in its implementation of `fn check_extrinsics`. + /// will call this function in its implementation of `fn check_extrinsics`. /// If the inherent is not present, it will return `e`. /// /// - `Err(_)` indicates that this function failed and further operations should be aborted. /// - /// NOTE: If inherent is required then the runtime asserts that the block contains at least + /// NOTE: If the inherent is required then the runtime asserts that the block contains at least /// one inherent for which: /// * type is [`Self::Call`], /// * [`Self::is_inherent`] returns true. + /// + /// NOTE: This is currently only checked by block producers, not all full nodes. fn is_inherent_required(_: &InherentData) -> Result, Self::Error> { Ok(None) } @@ -64,21 +75,27 @@ pub trait ProvideInherent { /// included in the block by its author. Whereas the second parameter represents the inherent /// data that the verifying node calculates. /// - /// NOTE: A block can contains multiple inherent. + /// This is intended to allow for checks that cannot be done within the runtime such as, e.g., + /// the timestamp. + /// + /// # Warning + /// + /// This check is not guaranteed to be run by all full nodes and cannot be relied upon for + /// ensuring that the block is correct. fn check_inherent(_: &Self::Call, _: &InherentData) -> Result<(), Self::Error> { Ok(()) } /// Return whether the call is an inherent call. /// - /// NOTE: Signed extrinsics are not inherent, but signed extrinsic with the given call variant - /// can be dispatched. + /// NOTE: Signed extrinsics are not inherents, but a signed extrinsic with the given call + /// variant can be dispatched. /// /// # Warning /// - /// In FRAME, inherent are enforced to be before other extrinsics, for this reason, + /// In FRAME, inherents are enforced to be executed before other extrinsics. For this reason, /// pallets with unsigned transactions **must ensure** that no unsigned transaction call /// is an inherent call, when implementing `ValidateUnsigned::validate_unsigned`. - /// Otherwise block producer can produce invalid blocks by including them after non inherent. + /// Otherwise block producers can produce invalid blocks by including them after non inherents. fn is_inherent(call: &Self::Call) -> bool; } diff --git a/primitives/inherents/src/lib.rs b/primitives/inherents/src/lib.rs index cd04a1bc3b3dd..a3ef963c47b39 100644 --- a/primitives/inherents/src/lib.rs +++ b/primitives/inherents/src/lib.rs @@ -15,14 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Substrate inherent extrinsics +//! Substrate Inherent Extrinsics //! //! Inherent extrinsics are extrinsics that are inherently added to each block. However, it is up to -//! runtime implementation to require an inherent for each block or to make it optional. Inherents -//! are mainly used to pass data from the block producer to the runtime. So, inherents require some -//! part that is running on the client side and some part that is running on the runtime side. Any -//! data that is required by an inherent is passed as [`InherentData`] from the client to the -//! runtime when the inherents are constructed. +//! the runtime implementation to require an inherent for each block or to make it optional. +//! Inherents are mainly used to pass data from the block producer to the runtime. So, inherents +//! require some part that is running on the client side and some part that is running on the +//! runtime side. Any data that is required by an inherent is passed as [`InherentData`] from the +//! client to the runtime when the inherents are constructed. //! //! The process of constructing and applying inherents is the following: //! From a5f3dbe4fa0417be6f1b13934c38db74cbb1b34d Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 29 Mar 2022 06:42:01 +0900 Subject: [PATCH 0645/1472] Bump `tokio` to 1.17.0 (#10894) * Bump `tokio` to 0.17.0 * Revert version changes to scale-info Co-authored-by: Keith Yeung --- Cargo.lock | 23 +++++++++++---------- bin/node/cli/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- test-utils/Cargo.toml | 2 +- test-utils/test-crate/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 4 ++-- 14 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac30433c5ea28..873da8abaca39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3010,7 +3010,7 @@ dependencies = [ "httpdate", "itoa 0.4.8", "pin-project-lite 0.2.6", - "socket2 0.4.0", + "socket2 0.4.4", "tokio", "tower-service", "tracing", @@ -3914,7 +3914,7 @@ dependencies = [ "log 0.4.14", "rand 0.8.4", "smallvec 1.8.0", - "socket2 0.4.0", + "socket2 0.4.4", "void", ] @@ -4122,7 +4122,7 @@ dependencies = [ "libc", "libp2p-core", "log 0.4.14", - "socket2 0.4.0", + "socket2 0.4.4", ] [[package]] @@ -4559,9 +4559,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.13" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" dependencies = [ "libc", "log 0.4.14", @@ -9623,9 +9623,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", "winapi 0.3.9", @@ -11024,19 +11024,20 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" dependencies = [ "bytes 1.1.0", "libc", "memchr", - "mio 0.7.13", + "mio 0.8.0", "num_cpus", "once_cell", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "pin-project-lite 0.2.6", "signal-hook-registry", + "socket2 0.4.4", "tokio-macros", "winapi 0.3.9", ] diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 24e069d21f694..0e8cdfd7c3fe5 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -126,7 +126,7 @@ platforms = "2.0" async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" criterion = { version = "0.3.5", features = ["async_tokio"] } -tokio = { version = "1.15", features = ["macros", "time", "parking_lot"] } +tokio = { version = "1.17.0", features = ["macros", "time", "parking_lot"] } jsonrpsee-ws-client = "0.4.1" wait-timeout = "0.2" remote-externalities = { path = "../../../utils/frame/remote-externalities" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 665bd6acfaf33..0fbb06e8aa4a9 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -28,7 +28,7 @@ serde = "1.0.136" serde_json = "1.0.79" thiserror = "1.0.30" tiny-bip39 = "0.8.2" -tokio = { version = "1.15", features = ["signal", "rt-multi-thread", "parking_lot"] } +tokio = { version = "1.17.0", features = ["signal", "rt-multi-thread", "parking_lot"] } parity-scale-codec = "3.0.0" sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 7aaad863af557..62650d50ce4ac 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -47,7 +47,7 @@ sp-timestamp = { path = "../../../primitives/timestamp", version = "4.0.0-dev" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } [dev-dependencies] -tokio = { version = "1.15.0", features = ["rt-multi-thread", "macros"] } +tokio = { version = "1.17.0", features = ["rt-multi-thread", "macros"] } sc-basic-authorship = { path = "../../basic-authorship", version = "0.10.0-dev" } substrate-test-runtime-client = { path = "../../../test-utils/runtime/client", version = "2.0.0" } substrate-test-runtime-transaction-pool = { path = "../../../test-utils/runtime/transaction-pool", version = "2.0.0" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 86cd57fc7c092..b8b41ba703655 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -61,5 +61,5 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/ru sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } serde = "1.0.136" -tokio = "1.15" +tokio = "1.17.0" tempfile = "3.1.0" diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index e542759b48096..3edba1f45704a 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -43,7 +43,7 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/a sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -tokio = "1.15" +tokio = "1.17.0" lazy_static = "1.4.0" [features] diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index f0c3fd496aa70..6b2c9f5aa3738 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -19,7 +19,7 @@ pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} serde_json = "1.0.79" -tokio = { version = "1.15", features = ["parking_lot"] } +tokio = { version = "1.17.0", features = ["parking_lot"] } http = { package = "jsonrpc-http-server", version = "18.0.0" } ipc = { package = "jsonrpc-ipc-server", version = "18.0.0" } ws = { package = "jsonrpc-ws-server", version = "18.0.0" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 737a29f1db0c0..2cb23fed40f22 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -78,7 +78,7 @@ parity-util-mem = { version = "0.11.0", default-features = false, features = [ "primitive-types", ] } async-trait = "0.1.50" -tokio = { version = "1.15", features = ["time", "rt-multi-thread", "parking_lot"] } +tokio = { version = "1.17.0", features = ["time", "rt-multi-thread", "parking_lot"] } tempfile = "3.1.0" directories = "4.0.1" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 0b99b9c5aeb9c..fa3c49a2340ad 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] hex = "0.4" hex-literal = "0.3.4" tempfile = "3.1.0" -tokio = { version = "1.15.0", features = ["time"] } +tokio = { version = "1.17.0", features = ["time"] } log = "0.4.8" fdlimit = "0.2.1" parking_lot = "0.12.0" diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index 756de58032803..9f66fa812bb4b 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.16" substrate-test-utils-derive = { version = "0.10.0-dev", path = "./derive" } -tokio = { version = "1.10", features = ["macros", "time"] } +tokio = { version = "1.17.0", features = ["macros", "time"] } [dev-dependencies] sc-service = { version = "0.10.0-dev", path = "../client/service" } diff --git a/test-utils/test-crate/Cargo.toml b/test-utils/test-crate/Cargo.toml index 4e07f92e86ea4..f6fea8407eaa7 100644 --- a/test-utils/test-crate/Cargo.toml +++ b/test-utils/test-crate/Cargo.toml @@ -12,6 +12,6 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] -tokio = { version = "1.15", features = ["macros"] } +tokio = { version = "1.17.0", features = ["macros"] } test-utils = { version = "4.0.0-dev", path = "..", package = "substrate-test-utils" } sc-service = { version = "0.10.0-dev", path = "../../client/service" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index d5042444119dc..fc44c63b8acd4 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -28,7 +28,7 @@ sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-version = { version = "5.0.0", path = "../../../primitives/version" } [dev-dependencies] -tokio = { version = "1.15", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", version = "5.0.0-dev" } frame-support = { path = "../../../frame/support", version = "4.0.0-dev" } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 0055ef47f8f4e..91ec47e34bd37 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -26,4 +26,4 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } [dev-dependencies] frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } scale-info = "2.0.1" -tokio = "1.15" +tokio = "1.17.0" diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index fb998d2809fae..4940712f2f4d9 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -17,9 +17,9 @@ log = "0.4.8" prometheus = { version = "0.13.0", default-features = false } futures-util = { version = "0.3.19", default-features = false, features = ["io"] } thiserror = "1.0" -tokio = { version = "1.15", features = ["parking_lot"] } +tokio = { version = "1.17.0", features = ["parking_lot"] } hyper = { version = "0.14.16", default-features = false, features = ["http1", "server", "tcp"] } [dev-dependencies] hyper = { version = "0.14.16", features = ["client"] } -tokio = { version = "1.15", features = ["rt-multi-thread"] } +tokio = { version = "1.17.0", features = ["rt-multi-thread"] } From 297a5e4a548744a07aabb6a8e200f808c54231f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Mar 2022 23:43:30 +0200 Subject: [PATCH 0646/1472] Bump libc from 0.2.119 to 0.2.121 (#11127) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.119 to 0.2.121. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.119...0.2.121) --- updated-dependencies: - dependency-name: libc 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/executor/wasmtime/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 873da8abaca39..2fe01c905d7cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3658,9 +3658,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.119" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "libgit2-sys" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 13bf196c4d44e..f0155204f5442 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -libc = "0.2.119" +libc = "0.2.121" cfg-if = "1.0" log = "0.4.8" parity-wasm = "0.42.0" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 3c4401e2d342d..76cdcb4e4b021 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -17,7 +17,7 @@ ansi_term = "0.12.1" atty = "0.2.13" chrono = "0.4.19" lazy_static = "1.4.0" -libc = "0.2.119" +libc = "0.2.121" log = { version = "0.4.8" } once_cell = "1.8.0" parking_lot = "0.12.0" From 09073d367745837ba81f1bbd749a0fea3439b5ba Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 29 Mar 2022 14:07:51 +0200 Subject: [PATCH 0647/1472] Spellcheck HBS templates and add test (#11119) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Spellcheck HBS templates and fix vars Signed-off-by: Oliver Tale-Yazdi * Add test for benchmark-storage Signed-off-by: Oliver Tale-Yazdi * Fmt templates Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Review fixes Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- bin/node/cli/tests/benchmark_storage_works.rs | 52 +++++++++++++++++++ .../benchmarking-cli/src/overhead/weights.hbs | 28 +++------- .../benchmarking-cli/src/storage/weights.hbs | 31 ++++++----- 3 files changed, 77 insertions(+), 34 deletions(-) create mode 100644 bin/node/cli/tests/benchmark_storage_works.rs diff --git a/bin/node/cli/tests/benchmark_storage_works.rs b/bin/node/cli/tests/benchmark_storage_works.rs new file mode 100644 index 0000000000000..1628f9a7e97ba --- /dev/null +++ b/bin/node/cli/tests/benchmark_storage_works.rs @@ -0,0 +1,52 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use assert_cmd::cargo::cargo_bin; +use std::{ + path::Path, + process::{Command, ExitStatus}, +}; +use tempfile::tempdir; + +/// Tests that the `benchmark-storage` command works for the dev runtime. +#[test] +fn benchmark_storage_works() { + let tmp_dir = tempdir().expect("could not create a temp dir"); + let base_path = tmp_dir.path(); + + // Benchmarking the storage works and creates the correct weight file. + assert!(benchmark_storage("rocksdb", base_path).success()); + assert!(base_path.join("rocksdb_weights.rs").exists()); + + assert!(benchmark_storage("paritydb", base_path).success()); + assert!(base_path.join("paritydb_weights.rs").exists()); +} + +fn benchmark_storage(db: &str, base_path: &Path) -> ExitStatus { + Command::new(cargo_bin("substrate")) + .args(&["benchmark-storage", "--dev"]) + .arg("--db") + .arg(db) + .arg("--weight-path") + .arg(base_path) + .args(["--state-version", "1"]) + .args(["--warmups", "0"]) + .args(["--add", "100", "--mul", "1.2", "--metric", "p75"]) + .status() + .unwrap() +} diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index 0f6b7f3e9119f..ad33f55a9f363 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -37,17 +37,17 @@ parameter_types! { {{#if (eq short_name "block")}} /// Time to execute an empty block. {{else}} - /// Time to execute a NO-OP extrinsic eg. `System::remark`. + /// Time to execute a NO-OP extrinsic, for example `System::remark`. {{/if}} /// Calculated by multiplying the *{{params.weight.weight_metric}}* with `{{params.weight.weight_mul}}` and adding `{{params.weight.weight_add}}`. /// - /// Stats [ns]: + /// Stats [NS]: /// Min, Max: {{underscore stats.min}}, {{underscore stats.max}} /// Average: {{underscore stats.avg}} /// Median: {{underscore stats.median}} - /// StdDev: {{stats.stddev}} + /// Std-Dev: {{stats.stddev}} /// - /// Percentiles [ns]: + /// Percentiles [NS]: /// 99th: {{underscore stats.p99}} /// 95th: {{underscore stats.p95}} /// 75th: {{underscore stats.p75}} @@ -67,26 +67,14 @@ mod test_weights { {{#if (eq short_name "block")}} // At least 100 µs. - assert!( - w >= 100 * constants::WEIGHT_PER_MICROS, - "Weight should be at least 100 µs." - ); + assert!(w >= 100 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); // At most 50 ms. - assert!( - w <= 50 * constants::WEIGHT_PER_MILLIS, - "Weight should be at most 50 ms." - ); + assert!(w <= 50 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms."); {{else}} // At least 10 µs. - assert!( - w >= 10 * constants::WEIGHT_PER_MICROS, - "Weight should be at least 10 µs." - ); + assert!(w >= 10 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs."); // At most 1 ms. - assert!( - w <= constants::WEIGHT_PER_MILLIS, - "Weight should be at most 1 ms." - ); + assert!(w <= constants::WEIGHT_PER_MILLIS, "Weight should be at most 1 ms."); {{/if}} } } diff --git a/utils/frame/benchmarking-cli/src/storage/weights.hbs b/utils/frame/benchmarking-cli/src/storage/weights.hbs index bfb832cb847f9..63f896e1104b8 100644 --- a/utils/frame/benchmarking-cli/src/storage/weights.hbs +++ b/utils/frame/benchmarking-cli/src/storage/weights.hbs @@ -22,52 +22,55 @@ //! BLOCK-NUM: `{{block_number}}` //! SKIP-WRITE: `{{params.skip_write}}`, SKIP-READ: `{{params.skip_read}}`, WARMUPS: `{{params.warmups}}` //! STATE-VERSION: `V{{params.state_version}}`, STATE-CACHE-SIZE: `{{params.state_cache_size}}` -//! WEIGHT-PATH: `{{params.weight_path}}` -//! METRIC: `{{params.weight_metric}}`, WEIGHT-MUL: `{{params.weight_mul}}`, WEIGHT-ADD: `{{params.weight_add}}` +//! WEIGHT-PATH: `{{params.weight_params.weight_path}}` +//! METRIC: `{{params.weight_params.weight_metric}}`, WEIGHT-MUL: `{{params.weight_params.weight_mul}}`, WEIGHT-ADD: `{{params.weight_params.weight_add}}` // Executed Command: {{#each args as |arg|}} // {{arg}} {{/each}} -/// Storage DB weights for the {{runtime_name}} runtime and {{db_name}}. +/// Storage DB weights for the `{{runtime_name}}` runtime and `{{db_name}}`. pub mod constants { - use frame_support::{parameter_types, weights::{RuntimeDbWeight, constants}}; + use frame_support::{ + parameter_types, + weights::{constants, RuntimeDbWeight}, + }; parameter_types! { {{#if (eq db_name "ParityDb")}} - /// ParityDB can be enabled with a feature flag, but is still experimental. These weights + /// `ParityDB` can be enabled with a feature flag, but is still experimental. These weights /// are available for brave runtime engineers who may want to try this out as default. {{else}} - /// By default, Substrate uses RocksDB, so this will be the weight used throughout + /// By default, Substrate uses `RocksDB`, so this will be the weight used throughout /// the runtime. {{/if}} pub const {{db_name}}Weight: RuntimeDbWeight = RuntimeDbWeight { /// Time to read one storage item. - /// Calculated by multiplying the *{{params.weight_metric}}* of all values with `{{params.weight_mul}}` and adding `{{params.weight_add}}`. + /// Calculated by multiplying the *{{params.weight_params.weight_metric}}* of all values with `{{params.weight_params.weight_mul}}` and adding `{{params.weight_params.weight_add}}`. /// - /// Stats [ns]: + /// Stats [NS]: /// Min, Max: {{underscore read.0.min}}, {{underscore read.0.max}} /// Average: {{underscore read.0.avg}} /// Median: {{underscore read.0.median}} - /// StdDev: {{read.0.stddev}} + /// Std-Dev: {{read.0.stddev}} /// - /// Percentiles [ns]: + /// Percentiles [NS]: /// 99th: {{underscore read.0.p99}} /// 95th: {{underscore read.0.p95}} /// 75th: {{underscore read.0.p75}} read: {{underscore read_weight}} * constants::WEIGHT_PER_NANOS, /// Time to write one storage item. - /// Calculated by multiplying the *{{params.weight_metric}}* of all values with `{{params.weight_mul}}` and adding `{{params.weight_add}}`. + /// Calculated by multiplying the *{{params.weight_params.weight_metric}}* of all values with `{{params.weight_params.weight_mul}}` and adding `{{params.weight_params.weight_add}}`. /// - /// Stats [ns]: + /// Stats [NS]: /// Min, Max: {{underscore write.0.min}}, {{underscore write.0.max}} /// Average: {{underscore write.0.avg}} /// Median: {{underscore write.0.median}} - /// StdDev: {{write.0.stddev}} + /// Std-Dev: {{write.0.stddev}} /// - /// Percentiles [ns]: + /// Percentiles [NS]: /// 99th: {{underscore write.0.p99}} /// 95th: {{underscore write.0.p95}} /// 75th: {{underscore write.0.p75}} From 71bb50c0ee15f80f98810248cc3461789d91065f Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 29 Mar 2022 23:19:19 +0900 Subject: [PATCH 0648/1472] Update `lru`, `regex` and `thread_local` (#11135) * Update `lru` to 0.7.3 * Update `regex` to 1.5.5 * Update `thread_local` to 1.1.4 --- Cargo.lock | 22 +++++++++++----------- bin/node/cli/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/executor/Cargo.toml | 4 ++-- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/panic-handler/Cargo.toml | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2fe01c905d7cb..03a04cedcbf27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4075,7 +4075,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "lru 0.7.0", + "lru 0.7.3", "rand 0.7.3", "smallvec 1.8.0", "unsigned-varint 0.7.0", @@ -4354,9 +4354,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c748cfe47cb8da225c37595b3108bea1c198c84aaae8ea0ba76d01dda9fc803" +checksum = "fcb87f3080f6d1d69e8c564c0fcfde1d7aa8cc451ce40cae89479111f03bc0eb" dependencies = [ "hashbrown 0.11.2", ] @@ -7739,9 +7739,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -8479,7 +8479,7 @@ dependencies = [ "env_logger 0.9.0", "hex-literal", "lazy_static", - "lru 0.6.6", + "lru 0.7.3", "parity-scale-codec", "parking_lot 0.12.0", "paste 1.0.6", @@ -8690,7 +8690,7 @@ dependencies = [ "linked-hash-map", "linked_hash_set", "log 0.4.14", - "lru 0.7.0", + "lru 0.7.3", "parity-scale-codec", "parking_lot 0.12.0", "pin-project 1.0.10", @@ -8734,7 +8734,7 @@ dependencies = [ "futures-timer", "libp2p", "log 0.4.14", - "lru 0.7.0", + "lru 0.7.3", "quickcheck", "sc-network", "sp-runtime", @@ -9802,7 +9802,7 @@ version = "4.0.0-dev" dependencies = [ "futures 0.3.19", "log 0.4.14", - "lru 0.7.0", + "lru 0.7.3", "parity-scale-codec", "parking_lot 0.12.0", "sp-api", @@ -10931,9 +10931,9 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ "once_cell", ] diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 0e8cdfd7c3fe5..a1aa695bf3a15 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -121,7 +121,7 @@ tempfile = "3.1.0" assert_cmd = "2.0.2" nix = "0.23" serde_json = "1.0" -regex = "1" +regex = "1.5.5" platforms = "2.0" async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 0fbb06e8aa4a9..7725e25c0b815 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -22,7 +22,7 @@ libp2p = "0.40.0" log = "0.4.11" names = { version = "0.13.0", default-features = false } rand = "0.7.3" -regex = "1.5.4" +regex = "1.5.5" rpassword = "5.0.0" serde = "1.0.136" serde_json = "1.0.79" diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index cba5892eace13..34416b1e0d460 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -32,7 +32,7 @@ sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } parking_lot = "0.12.0" sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } -lru = "0.6.6" +lru = "0.7.3" tracing = "0.1.29" [dev-dependencies] @@ -46,7 +46,7 @@ sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/may sc-tracing = { version = "4.0.0-dev", path = "../tracing" } tracing-subscriber = "0.2.19" paste = "1.0" -regex = "1" +regex = "1.5.5" criterion = "0.3" env_logger = "0.9" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index ade44dc94aa81..c8410d6d18783 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.19" futures-timer = "3.0.1" libp2p = { version = "0.40.0", default-features = false } log = "0.4.8" -lru = "0.7.0" +lru = "0.7.3" ahash = "0.7.6" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index d6bc90016ab82..cd33830c1efe0 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -34,7 +34,7 @@ hex = "0.4.0" ip_network = "0.4.1" linked-hash-map = "0.5.4" linked_hash_set = "0.1.3" -lru = "0.7.0" +lru = "0.7.3" log = "0.4.8" parking_lot = "0.12.0" pin-project = "1.0.10" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 76cdcb4e4b021..599e310a85157 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -21,7 +21,7 @@ libc = "0.2.121" log = { version = "0.4.8" } once_cell = "1.8.0" parking_lot = "0.12.0" -regex = "1.5.4" +regex = "1.5.5" rustc-hash = "1.1.0" serde = "1.0.136" thiserror = "1.0.30" diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index bdb326bdb2e9d..4c9946b7a3127 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.11" -lru = "0.7.0" +lru = "0.7.3" parking_lot = "0.12.0" thiserror = "1.0.30" futures = "0.3.19" diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml index abab34d29519b..0155b6532876c 100644 --- a/primitives/panic-handler/Cargo.toml +++ b/primitives/panic-handler/Cargo.toml @@ -15,5 +15,5 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] backtrace = "0.3.63" -regex = "1.5.4" +regex = "1.5.5" lazy_static = "1.4.0" From 62fa7d2aaeaabdc478ae3b0fab2929a0fcc89e40 Mon Sep 17 00:00:00 2001 From: Alexander Gryaznov Date: Tue, 29 Mar 2022 17:14:49 +0200 Subject: [PATCH 0649/1472] contracts: add `seal_code_hash` and `seal_own_code_hash` to API (#10933) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `seal_origin` + tests added * `seal_origin` benchmark added * `seal_code_hash` + tests added * `seal_code_hash` benchmark added * `seal_own_code_hash` + tests added * `seal_own_code_hash` benchmark added * fmt lil fix * akward accident bug fix * Apply suggestions from code review Co-authored-by: Alexander Theißen * Apply suggestions from code review Co-authored-by: Alexander Theißen * benchmark fix * `WasmModule::getter()` to take `module_name` arg * test enhanced * fixes based on review feedback * Apply suggestions from code review Co-authored-by: Alexander Theißen * Hash left as const to return a ref to it from mock * HASH test val to local const in mock * Apply suggestions from code review Co-authored-by: Alexander Theißen * fixes to benchmarks according to review feedback * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * removed `seal_origin` from API Co-authored-by: Alexander Theißen Co-authored-by: Parity Bot --- frame/contracts/src/benchmarking/code.rs | 4 +- frame/contracts/src/benchmarking/mod.rs | 71 +- frame/contracts/src/exec.rs | 72 ++ frame/contracts/src/schedule.rs | 8 + frame/contracts/src/wasm/mod.rs | 120 ++- frame/contracts/src/wasm/runtime.rs | 48 + frame/contracts/src/weights.rs | 1242 +++++++++++----------- 7 files changed, 951 insertions(+), 614 deletions(-) diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index f9d71fde65885..2544fd6b7f922 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -339,12 +339,12 @@ where /// Creates a wasm module that calls the imported function named `getter_name` `repeat` /// times. The imported function is expected to have the "getter signature" of /// (out_ptr: u32, len_ptr: u32) -> (). - pub fn getter(getter_name: &'static str, repeat: u32) -> Self { + pub fn getter(module_name: &'static str, getter_name: &'static str, repeat: u32) -> Self { let pages = max_pages::(); ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", + module: module_name, name: getter_name, params: vec![ValueType::I32, ValueType::I32], return_type: None, diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 8539978bd6b39..de83f51a01528 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -394,7 +394,7 @@ benchmarks! { seal_caller { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal_caller", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_caller", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -436,6 +436,59 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + seal_code_hash { + let r in 0 .. API_BENCHMARK_BATCHES; + let accounts = (0 .. r * API_BENCHMARK_BATCH_SIZE) + .map(|n| account::("account", n, 0)) + .collect::>(); + let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); + let accounts_bytes = accounts.iter().map(|a| a.encode()).flatten().collect::>(); + let accounts_len = accounts_bytes.len(); + let pages = code::max_pages::(); + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_code_hash", + params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: 32u32.to_le_bytes().to_vec(), // output length + }, + DataSegment { + offset: 36, + value: accounts_bytes, + }, + ], + call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + Counter(36, account_len as u32), // address_ptr + Regular(Instruction::I32Const(4)), // ptr to output data + Regular(Instruction::I32Const(0)), // ptr to output length + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let info = instance.info()?; + // every account would be a contract (worst case) + for acc in accounts.iter() { + >::insert(acc, info.clone()); + } + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + + seal_own_code_hash { + let r in 0 .. API_BENCHMARK_BATCHES; + let instance = Contract::::new(WasmModule::getter( + "__unstable__", "seal_own_code_hash", r * API_BENCHMARK_BATCH_SIZE + ), vec![])?; + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + seal_caller_is_origin { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -459,7 +512,7 @@ benchmarks! { seal_address { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal_address", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_address", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -467,7 +520,7 @@ benchmarks! { seal_gas_left { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal_gas_left", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_gas_left", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -475,7 +528,7 @@ benchmarks! { seal_balance { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal_balance", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_balance", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -483,7 +536,7 @@ benchmarks! { seal_value_transferred { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal_value_transferred", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_value_transferred", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -491,7 +544,7 @@ benchmarks! { seal_minimum_balance { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal_minimum_balance", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_minimum_balance", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -499,7 +552,7 @@ benchmarks! { seal_block_number { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal_block_number", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_block_number", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -507,7 +560,7 @@ benchmarks! { seal_now { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal_now", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_now", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -2341,7 +2394,7 @@ benchmarks! { } // w_memory_grow = w_bench - 2 * w_param - // We can only allow allocate as much memory as it is allowed in a a contract. + // We can only allow allocate as much memory as it is allowed in a contract. // Therefore the repeat count is limited by the maximum memory any contract can have. // Using a contract with more memory will skew the benchmark because the runtime of grow // depends on how much memory is already allocated. diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 455665687d973..e73b29e54378b 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -162,6 +162,14 @@ pub trait Ext: sealing::Sealed { /// Check if a contract lives at the specified `address`. fn is_contract(&self, address: &AccountIdOf) -> bool; + /// Returns the code hash of the contract for the given `address`. + /// + /// Returns `None` if the `address` does not belong to a contract. + fn code_hash(&self, address: &AccountIdOf) -> Option>; + + /// Returns the code hash of the contract being executed. + fn own_code_hash(&mut self) -> &CodeHash; + /// Check if the caller of the current contract is the origin of the whole call stack. /// /// This can be checked with `is_contract(self.caller())` as well. @@ -1103,6 +1111,14 @@ where ContractInfoOf::::contains_key(&address) } + fn code_hash(&self, address: &T::AccountId) -> Option> { + >::get(&address).map(|contract| contract.code_hash) + } + + fn own_code_hash(&mut self) -> &CodeHash { + &self.top_frame_mut().contract_info().code_hash + } + fn caller_is_origin(&self) -> bool { self.caller() == &self.origin } @@ -1753,6 +1769,62 @@ mod tests { }); } + #[test] + fn code_hash_returns_proper_values() { + let code_bob = MockLoader::insert(Call, |ctx, _| { + // ALICE is not a contract and hence she does not have a code_hash + assert!(ctx.ext.code_hash(&ALICE).is_none()); + // BOB is a contract and hence he has a code_hash + assert!(ctx.ext.code_hash(&BOB).is_some()); + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let schedule = ::Schedule::get(); + place_contract(&BOB, code_bob); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); + // ALICE (not contract) -> BOB (contract) + let result = MockStack::run_call( + ALICE, + BOB, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + &schedule, + 0, + vec![0], + None, + ); + assert_matches!(result, Ok(_)); + }); + } + + #[test] + fn own_code_hash_returns_proper_values() { + let bob_ch = MockLoader::insert(Call, |ctx, _| { + let code_hash = ctx.ext.code_hash(&BOB).unwrap(); + assert_eq!(*ctx.ext.own_code_hash(), code_hash); + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let schedule = ::Schedule::get(); + place_contract(&BOB, bob_ch); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); + // ALICE (not contract) -> BOB (contract) + let result = MockStack::run_call( + ALICE, + BOB, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + &schedule, + 0, + vec![0], + None, + ); + assert_matches!(result, Ok(_)); + }); + } + #[test] fn caller_is_origin_returns_proper_values() { let code_charlie = MockLoader::insert(Call, |ctx, _| { diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 8535166a6ac5c..b0c58d721d578 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -265,6 +265,12 @@ pub struct HostFnWeights { /// Weight of calling `seal_is_contract`. pub is_contract: Weight, + /// Weight of calling `seal_code_hash`. + pub code_hash: Weight, + + /// Weight of calling `seal_own_code_hash`. + pub own_code_hash: Weight, + /// Weight of calling `seal_caller_is_origin`. pub caller_is_origin: Weight, @@ -584,6 +590,8 @@ impl Default for HostFnWeights { Self { caller: cost_batched!(seal_caller), is_contract: cost_batched!(seal_is_contract), + code_hash: cost_batched!(seal_code_hash), + own_code_hash: cost_batched!(seal_own_code_hash), caller_is_origin: cost_batched!(seal_caller_is_origin), address: cost_batched!(seal_address), gas_left: cost_batched!(seal_gas_left), diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 3912a936684c2..c38613cb68102 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -438,6 +438,13 @@ mod tests { fn is_contract(&self, _address: &AccountIdOf) -> bool { true } + fn code_hash(&self, _address: &AccountIdOf) -> Option> { + Some(H256::from_slice(&[0x11; 32])) + } + fn own_code_hash(&mut self) -> &CodeHash { + const HASH: H256 = H256::repeat_byte(0x10); + &HASH + } fn caller_is_origin(&self) -> bool { false } @@ -1155,7 +1162,7 @@ mod tests { ); } - /// calls `seal_caller` and compares the result with the constant 42. + /// calls `seal_caller` and compares the result with the constant (ALICE's address part). const CODE_CALLER: &str = r#" (module (import "seal0" "seal_caller" (func $seal_caller (param i32 i32))) @@ -1185,7 +1192,7 @@ mod tests { ) ) - ;; assert that the first 64 byte are the beginning of "ALICE" + ;; assert that the first 8 bytes are the beginning of "ALICE" (call $assert (i64.eq (i64.load (i32.const 0)) @@ -1203,7 +1210,7 @@ mod tests { assert_ok!(execute(CODE_CALLER, vec![], MockExt::default())); } - /// calls `seal_address` and compares the result with the constant 69. + /// calls `seal_address` and compares the result with the constant (BOB's address part). const CODE_ADDRESS: &str = r#" (module (import "seal0" "seal_address" (func $seal_address (param i32 i32))) @@ -1233,7 +1240,7 @@ mod tests { ) ) - ;; assert that the first 64 byte are the beginning of "BOB" + ;; assert that the first 8 bytes are the beginning of "BOB" (call $assert (i64.eq (i64.load (i32.const 0)) @@ -2361,6 +2368,111 @@ mod tests { } #[test] + #[cfg(feature = "unstable-interface")] + fn code_hash_works() { + /// calls `seal_code_hash` and compares the result with the constant. + const CODE_CODE_HASH: &str = r#" +(module + (import "__unstable__" "seal_code_hash" (func $seal_code_hash (param i32 i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; size of our buffer is 32 bytes + (data (i32.const 32) "\20") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + ;; fill the buffer with the code hash. + (call $seal_code_hash + (i32.const 0) ;; input: address_ptr (before call) + (i32.const 0) ;; output: code_hash_ptr (after call) + (i32.const 32) ;; same 32 bytes length for input and output + ) + + ;; assert size == 32 + (call $assert + (i32.eq + (i32.load (i32.const 32)) + (i32.const 32) + ) + ) + + ;; assert that the first 8 bytes are "1111111111111111" + (call $assert + (i64.eq + (i64.load (i32.const 0)) + (i64.const 0x1111111111111111) + ) + ) + drop + ) + + (func (export "deploy")) +) +"#; + assert_ok!(execute(CODE_CODE_HASH, vec![], MockExt::default())); + } + + #[test] + #[cfg(feature = "unstable-interface")] + fn own_code_hash_works() { + /// calls `seal_own_code_hash` and compares the result with the constant. + const CODE_OWN_CODE_HASH: &str = r#" +(module + (import "__unstable__" "seal_own_code_hash" (func $seal_own_code_hash (param i32 i32))) + (import "env" "memory" (memory 1 1)) + + ;; size of our buffer is 32 bytes + (data (i32.const 32) "\20") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + ;; fill the buffer with the code hash + (call $seal_own_code_hash + (i32.const 0) ;; output: code_hash_ptr + (i32.const 32) ;; 32 bytes length of code_hash output + ) + + ;; assert size == 32 + (call $assert + (i32.eq + (i32.load (i32.const 32)) + (i32.const 32) + ) + ) + + ;; assert that the first 8 bytes are "1010101010101010" + (call $assert + (i64.eq + (i64.load (i32.const 0)) + (i64.const 0x1010101010101010) + ) + ) + ) + + (func (export "deploy")) +) +"#; + assert_ok!(execute(CODE_OWN_CODE_HASH, vec![], MockExt::default())); + } + + #[test] + #[cfg(feature = "unstable-interface")] fn caller_is_origin_works() { const CODE_CALLER_IS_ORIGIN: &str = r#" ;; This runs `caller_is_origin` check on zero account address diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 043b45e6a76ed..975cfcdd12db8 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -144,6 +144,12 @@ pub enum RuntimeCosts { Caller, /// Weight of calling `seal_is_contract`. IsContract, + /// Weight of calling `seal_code_hash`. + #[cfg(feature = "unstable-interface")] + CodeHash, + /// Weight of calling `seal_own_code_hash`. + #[cfg(feature = "unstable-interface")] + OwnCodeHash, /// Weight of calling `seal_caller_is_origin`. CallerIsOrigin, /// Weight of calling `seal_address`. @@ -234,6 +240,10 @@ impl RuntimeCosts { CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()), Caller => s.caller, IsContract => s.is_contract, + #[cfg(feature = "unstable-interface")] + CodeHash => s.code_hash, + #[cfg(feature = "unstable-interface")] + OwnCodeHash => s.own_code_hash, CallerIsOrigin => s.caller_is_origin, Address => s.address, GasLeft => s.gas_left, @@ -1371,6 +1381,44 @@ define_env!(Env, , Ok(ctx.ext.is_contract(&address) as u32) }, + // Retrieve the code hash for a specified contract address. + // + // # Parameters + // + // - `account_ptr`: a pointer to the address in question. + // Should be decodable as an `T::AccountId`. Traps otherwise. + // - `out_ptr`: pointer to the linear memory where the returning value is written to. + // - `out_len_ptr`: in-out pointer into linear memory where the buffer length + // is read from and the value length is written to. + // + // # Errors + // + // `ReturnCode::KeyNotFound` + [__unstable__] seal_code_hash(ctx, account_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { + ctx.charge_gas(RuntimeCosts::CodeHash)?; + let address: <::T as frame_system::Config>::AccountId = + ctx.read_sandbox_memory_as(account_ptr)?; + if let Some(value) = ctx.ext.code_hash(&address) { + ctx.write_sandbox_output(out_ptr, out_len_ptr, &value.encode(), false, already_charged)?; + Ok(ReturnCode::Success) + } else { + Ok(ReturnCode::KeyNotFound) + } + }, + + // Retrieve the code hash of the currently executing contract. + // + // # Parameters + // + // - `out_ptr`: pointer to the linear memory where the returning value is written to. + // - `out_len_ptr`: in-out pointer into linear memory where the buffer length + // is read from and the value length is written to. + [__unstable__] seal_own_code_hash(ctx, out_ptr: u32, out_len_ptr: u32) => { + ctx.charge_gas(RuntimeCosts::OwnCodeHash)?; + let code_hash_encoded = &ctx.ext.own_code_hash().encode(); + Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, code_hash_encoded, false, already_charged)?) + }, + // Checks whether the caller of the current contract is the origin of the whole call stack. // // Prefer this over `seal_is_contract` when checking whether your contract is being called by a contract diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index b438ad51cbfca..43f00196ab3b2 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-02-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-03-21, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -56,6 +56,8 @@ pub trait WeightInfo { fn remove_code() -> Weight; fn seal_caller(r: u32, ) -> Weight; fn seal_is_contract(r: u32, ) -> Weight; + fn seal_code_hash(r: u32, ) -> Weight; + fn seal_own_code_hash(r: u32, ) -> Weight; fn seal_caller_is_origin(r: u32, ) -> Weight; fn seal_address(r: u32, ) -> Weight; fn seal_gas_left(r: u32, ) -> Weight; @@ -160,14 +162,14 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_512_000 as Weight) + (1_569_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (8_089_000 as Weight) + (9_620_000 as Weight) // Standard Error: 0 - .saturating_add((741_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((748_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -175,17 +177,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { (0 as Weight) - // Standard Error: 5_000 - .saturating_add((2_287_000 as Weight).saturating_mul(q as Weight)) + // Standard Error: 4_000 + .saturating_add((1_795_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (15_212_000 as Weight) + (12_256_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -194,9 +196,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_per_byte(c: u32, ) -> Weight { - (218_406_000 as Weight) + (213_494_000 as Weight) // Standard Error: 0 - .saturating_add((55_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -208,9 +210,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (265_773_000 as Weight) + (231_180_000 as Weight) // Standard Error: 0 - .saturating_add((127_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((125_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) @@ -223,7 +225,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (173_852_000 as Weight) + (172_238_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) @@ -234,7 +236,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (140_088_000 as Weight) + (140_912_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -242,9 +244,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (44_290_000 as Weight) + (42_493_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -252,7 +254,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_364_000 as Weight) + (24_533_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -261,9 +263,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (219_617_000 as Weight) - // Standard Error: 119_000 - .saturating_add((50_409_000 as Weight).saturating_mul(r as Weight)) + (220_009_000 as Weight) + // Standard Error: 80_000 + .saturating_add((47_887_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -272,9 +274,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (102_073_000 as Weight) - // Standard Error: 843_000 - .saturating_add((369_025_000 as Weight).saturating_mul(r as Weight)) + (71_779_000 as Weight) + // Standard Error: 900_000 + .saturating_add((371_278_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + fn seal_code_hash(r: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 2_329_000 + .saturating_add((451_731_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -283,10 +297,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + fn seal_own_code_hash(r: u32, ) -> Weight { + (227_824_000 as Weight) + // Standard Error: 128_000 + .saturating_add((52_843_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (213_550_000 as Weight) - // Standard Error: 63_000 - .saturating_add((21_519_000 as Weight).saturating_mul(r as Weight)) + (213_057_000 as Weight) + // Standard Error: 43_000 + .saturating_add((21_023_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -295,9 +320,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (220_649_000 as Weight) - // Standard Error: 95_000 - .saturating_add((50_197_000 as Weight).saturating_mul(r as Weight)) + (219_066_000 as Weight) + // Standard Error: 117_000 + .saturating_add((48_056_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -306,9 +331,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (218_190_000 as Weight) - // Standard Error: 99_000 - .saturating_add((49_817_000 as Weight).saturating_mul(r as Weight)) + (218_844_000 as Weight) + // Standard Error: 101_000 + .saturating_add((47_325_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -317,9 +342,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (223_133_000 as Weight) - // Standard Error: 188_000 - .saturating_add((142_288_000 as Weight).saturating_mul(r as Weight)) + (219_234_000 as Weight) + // Standard Error: 171_000 + .saturating_add((142_534_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -328,9 +353,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (216_612_000 as Weight) - // Standard Error: 103_000 - .saturating_add((49_956_000 as Weight).saturating_mul(r as Weight)) + (215_128_000 as Weight) + // Standard Error: 119_000 + .saturating_add((48_392_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -339,9 +364,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (218_349_000 as Weight) - // Standard Error: 93_000 - .saturating_add((49_656_000 as Weight).saturating_mul(r as Weight)) + (214_603_000 as Weight) + // Standard Error: 115_000 + .saturating_add((48_041_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -350,9 +375,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (213_151_000 as Weight) - // Standard Error: 110_000 - .saturating_add((50_099_000 as Weight).saturating_mul(r as Weight)) + (214_091_000 as Weight) + // Standard Error: 126_000 + .saturating_add((48_067_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -361,9 +386,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (216_816_000 as Weight) - // Standard Error: 95_000 - .saturating_add((49_724_000 as Weight).saturating_mul(r as Weight)) + (214_418_000 as Weight) + // Standard Error: 100_000 + .saturating_add((47_791_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -373,9 +398,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (223_053_000 as Weight) - // Standard Error: 148_000 - .saturating_add((124_240_000 as Weight).saturating_mul(r as Weight)) + (229_261_000 as Weight) + // Standard Error: 150_000 + .saturating_add((121_988_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -384,9 +409,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (127_253_000 as Weight) - // Standard Error: 27_000 - .saturating_add((25_608_000 as Weight).saturating_mul(r as Weight)) + (127_983_000 as Weight) + // Standard Error: 56_000 + .saturating_add((24_016_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -395,9 +420,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (218_057_000 as Weight) - // Standard Error: 98_000 - .saturating_add((49_061_000 as Weight).saturating_mul(r as Weight)) + (216_634_000 as Weight) + // Standard Error: 114_000 + .saturating_add((46_864_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -406,9 +431,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (293_563_000 as Weight) - // Standard Error: 3_000 - .saturating_add((11_877_000 as Weight).saturating_mul(n as Weight)) + (285_180_000 as Weight) + // Standard Error: 4_000 + .saturating_add((11_899_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -416,10 +441,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(r: u32, ) -> Weight { - (211_511_000 as Weight) - // Standard Error: 70_000 - .saturating_add((2_085_000 as Weight).saturating_mul(r as Weight)) + fn seal_return(_r: u32, ) -> Weight { + (215_379_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -428,9 +451,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (213_876_000 as Weight) + (213_957_000 as Weight) // Standard Error: 0 - .saturating_add((193_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((201_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -441,9 +464,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (214_736_000 as Weight) - // Standard Error: 206_000 - .saturating_add((53_637_000 as Weight).saturating_mul(r as Weight)) + (215_782_000 as Weight) + // Standard Error: 149_000 + .saturating_add((52_421_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -455,9 +478,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (222_037_000 as Weight) - // Standard Error: 191_000 - .saturating_add((160_114_000 as Weight).saturating_mul(r as Weight)) + (217_910_000 as Weight) + // Standard Error: 149_000 + .saturating_add((157_525_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -466,9 +489,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (219_211_000 as Weight) - // Standard Error: 239_000 - .saturating_add((296_722_000 as Weight).saturating_mul(r as Weight)) + (230_787_000 as Weight) + // Standard Error: 210_000 + .saturating_add((296_973_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -478,11 +501,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (519_643_000 as Weight) - // Standard Error: 1_842_000 - .saturating_add((300_853_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 363_000 - .saturating_add((82_577_000 as Weight).saturating_mul(n as Weight)) + (539_238_000 as Weight) + // Standard Error: 1_701_000 + .saturating_add((294_348_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 335_000 + .saturating_add((82_116_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -493,17 +516,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (132_710_000 as Weight) - // Standard Error: 77_000 - .saturating_add((41_623_000 as Weight).saturating_mul(r as Weight)) + (135_081_000 as Weight) + // Standard Error: 94_000 + .saturating_add((39_247_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (40_644_000 as Weight) - // Standard Error: 1_072_000 - .saturating_add((412_308_000 as Weight).saturating_mul(r as Weight)) + (41_752_000 as Weight) + // Standard Error: 1_107_000 + .saturating_add((403_473_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -511,25 +534,25 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (609_052_000 as Weight) - // Standard Error: 258_000 - .saturating_add((28_633_000 as Weight).saturating_mul(n as Weight)) + (602_028_000 as Weight) + // Standard Error: 255_000 + .saturating_add((28_303_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (629_665_000 as Weight) - // Standard Error: 300_000 - .saturating_add((10_947_000 as Weight).saturating_mul(n as Weight)) + (620_964_000 as Weight) + // Standard Error: 308_000 + .saturating_add((11_338_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (91_519_000 as Weight) - // Standard Error: 889_000 - .saturating_add((386_498_000 as Weight).saturating_mul(r as Weight)) + (88_113_000 as Weight) + // Standard Error: 851_000 + .saturating_add((381_671_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -537,51 +560,51 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (612_224_000 as Weight) - // Standard Error: 269_000 - .saturating_add((10_709_000 as Weight).saturating_mul(n as Weight)) + (603_193_000 as Weight) + // Standard Error: 262_000 + .saturating_add((10_286_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (112_236_000 as Weight) - // Standard Error: 624_000 - .saturating_add((327_655_000 as Weight).saturating_mul(r as Weight)) + (112_477_000 as Weight) + // Standard Error: 666_000 + .saturating_add((324_824_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (567_711_000 as Weight) - // Standard Error: 387_000 - .saturating_add((63_984_000 as Weight).saturating_mul(n as Weight)) + (564_781_000 as Weight) + // Standard Error: 403_000 + .saturating_add((63_824_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (109_996_000 as Weight) - // Standard Error: 681_000 - .saturating_add((298_317_000 as Weight).saturating_mul(r as Weight)) + (115_207_000 as Weight) + // Standard Error: 672_000 + .saturating_add((290_919_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (518_342_000 as Weight) - // Standard Error: 251_000 - .saturating_add((9_666_000 as Weight).saturating_mul(n as Weight)) + (511_026_000 as Weight) + // Standard Error: 224_000 + .saturating_add((10_138_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(104 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (75_974_000 as Weight) - // Standard Error: 1_000_000 - .saturating_add((417_954_000 as Weight).saturating_mul(r as Weight)) + (79_113_000 as Weight) + // Standard Error: 904_000 + .saturating_add((417_022_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -589,9 +612,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (653_188_000 as Weight) - // Standard Error: 333_000 - .saturating_add((64_810_000 as Weight).saturating_mul(n as Weight)) + (651_769_000 as Weight) + // Standard Error: 338_000 + .saturating_add((65_576_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().writes(103 as Weight)) } @@ -600,9 +623,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (127_056_000 as Weight) - // Standard Error: 1_106_000 - .saturating_add((1_784_183_000 as Weight).saturating_mul(r as Weight)) + (93_588_000 as Weight) + // Standard Error: 1_444_000 + .saturating_add((1_803_217_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -614,8 +637,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_621_000 - .saturating_add((19_757_765_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 3_050_000 + .saturating_add((19_925_209_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -627,8 +650,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 6_286_000 - .saturating_add((19_798_229_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 7_377_000 + .saturating_add((19_978_301_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -637,11 +660,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (10_922_130_000 as Weight) - // Standard Error: 15_556_000 - .saturating_add((1_672_276_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 6_000 - .saturating_add((11_984_000 as Weight).saturating_mul(c as Weight)) + (11_124_804_000 as Weight) + // Standard Error: 21_475_000 + .saturating_add((1_635_442_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 9_000 + .saturating_add((11_981_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(105 as Weight)) .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(101 as Weight)) @@ -655,8 +678,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 46_147_000 - .saturating_add((27_589_519_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 47_682_000 + .saturating_add((27_883_754_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -669,11 +692,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (14_790_752_000 as Weight) - // Standard Error: 37_838_000 - .saturating_add((714_016_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 17_000 - .saturating_add((155_605_000 as Weight).saturating_mul(s as Weight)) + (14_824_308_000 as Weight) + // Standard Error: 39_823_000 + .saturating_add((880_630_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 18_000 + .saturating_add((156_232_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(207 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(205 as Weight)) @@ -684,9 +707,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (216_547_000 as Weight) - // Standard Error: 126_000 - .saturating_add((81_132_000 as Weight).saturating_mul(r as Weight)) + (218_378_000 as Weight) + // Standard Error: 131_000 + .saturating_add((78_260_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -695,9 +718,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (459_912_000 as Weight) - // Standard Error: 27_000 - .saturating_add((464_750_000 as Weight).saturating_mul(n as Weight)) + (202_849_000 as Weight) + // Standard Error: 61_000 + .saturating_add((466_532_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -706,9 +729,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (212_653_000 as Weight) + (220_258_000 as Weight) // Standard Error: 147_000 - .saturating_add((93_380_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((90_363_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -717,9 +740,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (324_536_000 as Weight) - // Standard Error: 20_000 - .saturating_add((306_160_000 as Weight).saturating_mul(n as Weight)) + (232_371_000 as Weight) + // Standard Error: 23_000 + .saturating_add((307_036_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -728,9 +751,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (218_574_000 as Weight) - // Standard Error: 123_000 - .saturating_add((65_035_000 as Weight).saturating_mul(r as Weight)) + (217_991_000 as Weight) + // Standard Error: 124_000 + .saturating_add((62_273_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -739,9 +762,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (345_804_000 as Weight) - // Standard Error: 14_000 - .saturating_add((118_896_000 as Weight).saturating_mul(n as Weight)) + (396_282_000 as Weight) + // Standard Error: 13_000 + .saturating_add((119_575_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -750,9 +773,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (215_898_000 as Weight) - // Standard Error: 108_000 - .saturating_add((64_332_000 as Weight).saturating_mul(r as Weight)) + (217_578_000 as Weight) + // Standard Error: 104_000 + .saturating_add((62_189_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -761,9 +784,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (351_569_000 as Weight) - // Standard Error: 18_000 - .saturating_add((118_896_000 as Weight).saturating_mul(n as Weight)) + (358_167_000 as Weight) + // Standard Error: 15_000 + .saturating_add((119_692_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -772,9 +795,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (272_893_000 as Weight) - // Standard Error: 1_438_000 - .saturating_add((15_412_877_000 as Weight).saturating_mul(r as Weight)) + (292_884_000 as Weight) + // Standard Error: 683_000 + .saturating_add((3_824_902_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -785,265 +808,265 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:36 w:36) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_132_000 - .saturating_add((937_623_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 2_302_000 + .saturating_add((922_467_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (74_268_000 as Weight) + (74_516_000 as Weight) // Standard Error: 1_000 - .saturating_add((595_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((592_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_515_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_300_000 as Weight).saturating_mul(r as Weight)) + (74_430_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_320_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_217_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_411_000 as Weight).saturating_mul(r as Weight)) + (74_440_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_428_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (73_689_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_792_000 as Weight).saturating_mul(r as Weight)) + (74_151_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_782_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (73_755_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) + (74_225_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_887_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_735_000 as Weight) - // Standard Error: 0 - .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) + (73_987_000 as Weight) + // Standard Error: 1_000 + .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_595_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_448_000 as Weight).saturating_mul(r as Weight)) + (73_305_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_465_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_524_000 as Weight) + (73_037_000 as Weight) // Standard Error: 3_000 - .saturating_add((1_572_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_605_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_361_000 as Weight) + (76_434_000 as Weight) // Standard Error: 0 .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (76_131_000 as Weight) - // Standard Error: 7_000 - .saturating_add((7_271_000 as Weight).saturating_mul(r as Weight)) + (75_461_000 as Weight) + // Standard Error: 10_000 + .saturating_add((7_446_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (87_948_000 as Weight) - // Standard Error: 14_000 - .saturating_add((9_429_000 as Weight).saturating_mul(r as Weight)) + (87_222_000 as Weight) + // Standard Error: 15_000 + .saturating_add((9_406_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (98_091_000 as Weight) + (97_204_000 as Weight) // Standard Error: 1_000 - .saturating_add((481_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((472_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (74_311_000 as Weight) + (75_299_000 as Weight) // Standard Error: 1_000 - .saturating_add((627_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((601_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_701_000 as Weight) - // Standard Error: 1_000 - .saturating_add((677_000 as Weight).saturating_mul(r as Weight)) + (74_827_000 as Weight) + // Standard Error: 3_000 + .saturating_add((686_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_645_000 as Weight) - // Standard Error: 1_000 - .saturating_add((890_000 as Weight).saturating_mul(r as Weight)) + (74_624_000 as Weight) + // Standard Error: 2_000 + .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_130_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_156_000 as Weight).saturating_mul(r as Weight)) + (77_435_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_201_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (77_199_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) + (76_693_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_410_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_024_000 as Weight) - // Standard Error: 2_000 - .saturating_add((675_000 as Weight).saturating_mul(r as Weight)) + (74_244_000 as Weight) + // Standard Error: 1_000 + .saturating_add((660_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (75_226_000 as Weight) - // Standard Error: 170_000 - .saturating_add((186_225_000 as Weight).saturating_mul(r as Weight)) + (73_527_000 as Weight) + // Standard Error: 931_000 + .saturating_add((184_946_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_307_000 as Weight) - // Standard Error: 2_000 - .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) + (74_181_000 as Weight) + // Standard Error: 6_000 + .saturating_add((906_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_408_000 as Weight) - // Standard Error: 3_000 - .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) + (74_339_000 as Weight) + // Standard Error: 1_000 + .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_418_000 as Weight) - // Standard Error: 1_000 - .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) + (74_444_000 as Weight) + // Standard Error: 3_000 + .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_130_000 as Weight) - // Standard Error: 2_000 - .saturating_add((920_000 as Weight).saturating_mul(r as Weight)) + (74_572_000 as Weight) + // Standard Error: 1_000 + .saturating_add((908_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_318_000 as Weight) + (74_349_000 as Weight) // Standard Error: 2_000 - .saturating_add((876_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((881_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_496_000 as Weight) + (74_426_000 as Weight) // Standard Error: 1_000 - .saturating_add((871_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((875_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (73_938_000 as Weight) - // Standard Error: 0 - .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) + (74_172_000 as Weight) + // Standard Error: 2_000 + .saturating_add((906_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (73_943_000 as Weight) + (74_169_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (74_305_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) + (74_205_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (73_948_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + (74_237_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_188_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + (74_181_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (74_156_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) + (74_038_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (73_972_000 as Weight) - // Standard Error: 0 - .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) + (73_881_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (74_082_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (73_969_000 as Weight) + // Standard Error: 0 + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_190_000 as Weight) - // Standard Error: 1_000 + (74_497_000 as Weight) + // Standard Error: 3_000 .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (73_803_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + (74_275_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_063_000 as Weight) - // Standard Error: 1_000 + (74_349_000 as Weight) + // Standard Error: 3_000 .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (73_750_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) + (74_192_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (73_979_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) + (74_271_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (74_197_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_332_000 as Weight).saturating_mul(r as Weight)) + (73_971_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (73_624_000 as Weight) - // Standard Error: 5_000 - .saturating_add((2_020_000 as Weight).saturating_mul(r as Weight)) + (74_546_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_995_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (74_074_000 as Weight) + (74_194_000 as Weight) // Standard Error: 2_000 .saturating_add((2_050_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (73_766_000 as Weight) - // Standard Error: 5_000 - .saturating_add((2_016_000 as Weight).saturating_mul(r as Weight)) + (74_106_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_997_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (73_978_000 as Weight) - // Standard Error: 3_000 - .saturating_add((2_064_000 as Weight).saturating_mul(r as Weight)) + (74_219_000 as Weight) + // Standard Error: 5_000 + .saturating_add((2_061_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (73_996_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_336_000 as Weight).saturating_mul(r as Weight)) + (74_157_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (74_058_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) + (74_135_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_336_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (73_983_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_337_000 as Weight).saturating_mul(r as Weight)) + (74_038_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (74_061_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) + (74_011_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (73_940_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (74_054_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (73_954_000 as Weight) + (73_900_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (74_026_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + (73_948_000 as Weight) + // Standard Error: 0 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (74_149_000 as Weight) + (73_972_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } } @@ -1051,14 +1074,14 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_512_000 as Weight) + (1_569_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (8_089_000 as Weight) + (9_620_000 as Weight) // Standard Error: 0 - .saturating_add((741_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((748_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -1066,17 +1089,17 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { (0 as Weight) - // Standard Error: 5_000 - .saturating_add((2_287_000 as Weight).saturating_mul(q as Weight)) + // Standard Error: 4_000 + .saturating_add((1_795_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (15_212_000 as Weight) + (12_256_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1085,9 +1108,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_per_byte(c: u32, ) -> Weight { - (218_406_000 as Weight) + (213_494_000 as Weight) // Standard Error: 0 - .saturating_add((55_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1099,9 +1122,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (265_773_000 as Weight) + (231_180_000 as Weight) // Standard Error: 0 - .saturating_add((127_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((125_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) @@ -1114,7 +1137,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (173_852_000 as Weight) + (172_238_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) @@ -1125,7 +1148,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (140_088_000 as Weight) + (140_912_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1133,9 +1156,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (44_290_000 as Weight) + (42_493_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1143,7 +1166,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_364_000 as Weight) + (24_533_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1152,9 +1175,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (219_617_000 as Weight) - // Standard Error: 119_000 - .saturating_add((50_409_000 as Weight).saturating_mul(r as Weight)) + (220_009_000 as Weight) + // Standard Error: 80_000 + .saturating_add((47_887_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1163,9 +1186,21 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (102_073_000 as Weight) - // Standard Error: 843_000 - .saturating_add((369_025_000 as Weight).saturating_mul(r as Weight)) + (71_779_000 as Weight) + // Standard Error: 900_000 + .saturating_add((371_278_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + fn seal_code_hash(r: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 2_329_000 + .saturating_add((451_731_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1174,10 +1209,21 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + fn seal_own_code_hash(r: u32, ) -> Weight { + (227_824_000 as Weight) + // Standard Error: 128_000 + .saturating_add((52_843_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (213_550_000 as Weight) - // Standard Error: 63_000 - .saturating_add((21_519_000 as Weight).saturating_mul(r as Weight)) + (213_057_000 as Weight) + // Standard Error: 43_000 + .saturating_add((21_023_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1186,9 +1232,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (220_649_000 as Weight) - // Standard Error: 95_000 - .saturating_add((50_197_000 as Weight).saturating_mul(r as Weight)) + (219_066_000 as Weight) + // Standard Error: 117_000 + .saturating_add((48_056_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1197,9 +1243,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (218_190_000 as Weight) - // Standard Error: 99_000 - .saturating_add((49_817_000 as Weight).saturating_mul(r as Weight)) + (218_844_000 as Weight) + // Standard Error: 101_000 + .saturating_add((47_325_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1208,9 +1254,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (223_133_000 as Weight) - // Standard Error: 188_000 - .saturating_add((142_288_000 as Weight).saturating_mul(r as Weight)) + (219_234_000 as Weight) + // Standard Error: 171_000 + .saturating_add((142_534_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1219,9 +1265,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (216_612_000 as Weight) - // Standard Error: 103_000 - .saturating_add((49_956_000 as Weight).saturating_mul(r as Weight)) + (215_128_000 as Weight) + // Standard Error: 119_000 + .saturating_add((48_392_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1230,9 +1276,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (218_349_000 as Weight) - // Standard Error: 93_000 - .saturating_add((49_656_000 as Weight).saturating_mul(r as Weight)) + (214_603_000 as Weight) + // Standard Error: 115_000 + .saturating_add((48_041_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1241,9 +1287,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (213_151_000 as Weight) - // Standard Error: 110_000 - .saturating_add((50_099_000 as Weight).saturating_mul(r as Weight)) + (214_091_000 as Weight) + // Standard Error: 126_000 + .saturating_add((48_067_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1252,9 +1298,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (216_816_000 as Weight) - // Standard Error: 95_000 - .saturating_add((49_724_000 as Weight).saturating_mul(r as Weight)) + (214_418_000 as Weight) + // Standard Error: 100_000 + .saturating_add((47_791_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1264,9 +1310,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (223_053_000 as Weight) - // Standard Error: 148_000 - .saturating_add((124_240_000 as Weight).saturating_mul(r as Weight)) + (229_261_000 as Weight) + // Standard Error: 150_000 + .saturating_add((121_988_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1275,9 +1321,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (127_253_000 as Weight) - // Standard Error: 27_000 - .saturating_add((25_608_000 as Weight).saturating_mul(r as Weight)) + (127_983_000 as Weight) + // Standard Error: 56_000 + .saturating_add((24_016_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1286,9 +1332,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (218_057_000 as Weight) - // Standard Error: 98_000 - .saturating_add((49_061_000 as Weight).saturating_mul(r as Weight)) + (216_634_000 as Weight) + // Standard Error: 114_000 + .saturating_add((46_864_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1297,9 +1343,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (293_563_000 as Weight) - // Standard Error: 3_000 - .saturating_add((11_877_000 as Weight).saturating_mul(n as Weight)) + (285_180_000 as Weight) + // Standard Error: 4_000 + .saturating_add((11_899_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1307,10 +1353,8 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(r: u32, ) -> Weight { - (211_511_000 as Weight) - // Standard Error: 70_000 - .saturating_add((2_085_000 as Weight).saturating_mul(r as Weight)) + fn seal_return(_r: u32, ) -> Weight { + (215_379_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1319,9 +1363,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (213_876_000 as Weight) + (213_957_000 as Weight) // Standard Error: 0 - .saturating_add((193_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((201_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1332,9 +1376,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (214_736_000 as Weight) - // Standard Error: 206_000 - .saturating_add((53_637_000 as Weight).saturating_mul(r as Weight)) + (215_782_000 as Weight) + // Standard Error: 149_000 + .saturating_add((52_421_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1346,9 +1390,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (222_037_000 as Weight) - // Standard Error: 191_000 - .saturating_add((160_114_000 as Weight).saturating_mul(r as Weight)) + (217_910_000 as Weight) + // Standard Error: 149_000 + .saturating_add((157_525_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1357,9 +1401,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (219_211_000 as Weight) - // Standard Error: 239_000 - .saturating_add((296_722_000 as Weight).saturating_mul(r as Weight)) + (230_787_000 as Weight) + // Standard Error: 210_000 + .saturating_add((296_973_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1369,11 +1413,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:100 w:100) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (519_643_000 as Weight) - // Standard Error: 1_842_000 - .saturating_add((300_853_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 363_000 - .saturating_add((82_577_000 as Weight).saturating_mul(n as Weight)) + (539_238_000 as Weight) + // Standard Error: 1_701_000 + .saturating_add((294_348_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 335_000 + .saturating_add((82_116_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1384,17 +1428,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (132_710_000 as Weight) - // Standard Error: 77_000 - .saturating_add((41_623_000 as Weight).saturating_mul(r as Weight)) + (135_081_000 as Weight) + // Standard Error: 94_000 + .saturating_add((39_247_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (40_644_000 as Weight) - // Standard Error: 1_072_000 - .saturating_add((412_308_000 as Weight).saturating_mul(r as Weight)) + (41_752_000 as Weight) + // Standard Error: 1_107_000 + .saturating_add((403_473_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1402,25 +1446,25 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (609_052_000 as Weight) - // Standard Error: 258_000 - .saturating_add((28_633_000 as Weight).saturating_mul(n as Weight)) + (602_028_000 as Weight) + // Standard Error: 255_000 + .saturating_add((28_303_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (629_665_000 as Weight) - // Standard Error: 300_000 - .saturating_add((10_947_000 as Weight).saturating_mul(n as Weight)) + (620_964_000 as Weight) + // Standard Error: 308_000 + .saturating_add((11_338_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (91_519_000 as Weight) - // Standard Error: 889_000 - .saturating_add((386_498_000 as Weight).saturating_mul(r as Weight)) + (88_113_000 as Weight) + // Standard Error: 851_000 + .saturating_add((381_671_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1428,51 +1472,51 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (612_224_000 as Weight) - // Standard Error: 269_000 - .saturating_add((10_709_000 as Weight).saturating_mul(n as Weight)) + (603_193_000 as Weight) + // Standard Error: 262_000 + .saturating_add((10_286_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (112_236_000 as Weight) - // Standard Error: 624_000 - .saturating_add((327_655_000 as Weight).saturating_mul(r as Weight)) + (112_477_000 as Weight) + // Standard Error: 666_000 + .saturating_add((324_824_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (567_711_000 as Weight) - // Standard Error: 387_000 - .saturating_add((63_984_000 as Weight).saturating_mul(n as Weight)) + (564_781_000 as Weight) + // Standard Error: 403_000 + .saturating_add((63_824_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (109_996_000 as Weight) - // Standard Error: 681_000 - .saturating_add((298_317_000 as Weight).saturating_mul(r as Weight)) + (115_207_000 as Weight) + // Standard Error: 672_000 + .saturating_add((290_919_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (518_342_000 as Weight) - // Standard Error: 251_000 - .saturating_add((9_666_000 as Weight).saturating_mul(n as Weight)) + (511_026_000 as Weight) + // Standard Error: 224_000 + .saturating_add((10_138_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(104 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (75_974_000 as Weight) - // Standard Error: 1_000_000 - .saturating_add((417_954_000 as Weight).saturating_mul(r as Weight)) + (79_113_000 as Weight) + // Standard Error: 904_000 + .saturating_add((417_022_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1480,9 +1524,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (653_188_000 as Weight) - // Standard Error: 333_000 - .saturating_add((64_810_000 as Weight).saturating_mul(n as Weight)) + (651_769_000 as Weight) + // Standard Error: 338_000 + .saturating_add((65_576_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().writes(103 as Weight)) } @@ -1491,9 +1535,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (127_056_000 as Weight) - // Standard Error: 1_106_000 - .saturating_add((1_784_183_000 as Weight).saturating_mul(r as Weight)) + (93_588_000 as Weight) + // Standard Error: 1_444_000 + .saturating_add((1_803_217_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1505,8 +1549,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_621_000 - .saturating_add((19_757_765_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 3_050_000 + .saturating_add((19_925_209_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1518,8 +1562,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 6_286_000 - .saturating_add((19_798_229_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 7_377_000 + .saturating_add((19_978_301_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1528,11 +1572,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (10_922_130_000 as Weight) - // Standard Error: 15_556_000 - .saturating_add((1_672_276_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 6_000 - .saturating_add((11_984_000 as Weight).saturating_mul(c as Weight)) + (11_124_804_000 as Weight) + // Standard Error: 21_475_000 + .saturating_add((1_635_442_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 9_000 + .saturating_add((11_981_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(105 as Weight)) .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(101 as Weight)) @@ -1546,8 +1590,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:100 w:100) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 46_147_000 - .saturating_add((27_589_519_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 47_682_000 + .saturating_add((27_883_754_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1560,11 +1604,11 @@ impl WeightInfo for () { // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (14_790_752_000 as Weight) - // Standard Error: 37_838_000 - .saturating_add((714_016_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 17_000 - .saturating_add((155_605_000 as Weight).saturating_mul(s as Weight)) + (14_824_308_000 as Weight) + // Standard Error: 39_823_000 + .saturating_add((880_630_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 18_000 + .saturating_add((156_232_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(207 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(205 as Weight)) @@ -1575,9 +1619,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (216_547_000 as Weight) - // Standard Error: 126_000 - .saturating_add((81_132_000 as Weight).saturating_mul(r as Weight)) + (218_378_000 as Weight) + // Standard Error: 131_000 + .saturating_add((78_260_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1586,9 +1630,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (459_912_000 as Weight) - // Standard Error: 27_000 - .saturating_add((464_750_000 as Weight).saturating_mul(n as Weight)) + (202_849_000 as Weight) + // Standard Error: 61_000 + .saturating_add((466_532_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1597,9 +1641,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (212_653_000 as Weight) + (220_258_000 as Weight) // Standard Error: 147_000 - .saturating_add((93_380_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((90_363_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1608,9 +1652,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (324_536_000 as Weight) - // Standard Error: 20_000 - .saturating_add((306_160_000 as Weight).saturating_mul(n as Weight)) + (232_371_000 as Weight) + // Standard Error: 23_000 + .saturating_add((307_036_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1619,9 +1663,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (218_574_000 as Weight) - // Standard Error: 123_000 - .saturating_add((65_035_000 as Weight).saturating_mul(r as Weight)) + (217_991_000 as Weight) + // Standard Error: 124_000 + .saturating_add((62_273_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1630,9 +1674,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (345_804_000 as Weight) - // Standard Error: 14_000 - .saturating_add((118_896_000 as Weight).saturating_mul(n as Weight)) + (396_282_000 as Weight) + // Standard Error: 13_000 + .saturating_add((119_575_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1641,9 +1685,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (215_898_000 as Weight) - // Standard Error: 108_000 - .saturating_add((64_332_000 as Weight).saturating_mul(r as Weight)) + (217_578_000 as Weight) + // Standard Error: 104_000 + .saturating_add((62_189_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1652,9 +1696,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (351_569_000 as Weight) - // Standard Error: 18_000 - .saturating_add((118_896_000 as Weight).saturating_mul(n as Weight)) + (358_167_000 as Weight) + // Standard Error: 15_000 + .saturating_add((119_692_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1663,9 +1707,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (272_893_000 as Weight) - // Standard Error: 1_438_000 - .saturating_add((15_412_877_000 as Weight).saturating_mul(r as Weight)) + (292_884_000 as Weight) + // Standard Error: 683_000 + .saturating_add((3_824_902_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1676,264 +1720,264 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:36 w:36) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_132_000 - .saturating_add((937_623_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 2_302_000 + .saturating_add((922_467_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (74_268_000 as Weight) + (74_516_000 as Weight) // Standard Error: 1_000 - .saturating_add((595_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((592_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_515_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_300_000 as Weight).saturating_mul(r as Weight)) + (74_430_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_320_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_217_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_411_000 as Weight).saturating_mul(r as Weight)) + (74_440_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_428_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (73_689_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_792_000 as Weight).saturating_mul(r as Weight)) + (74_151_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_782_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (73_755_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_899_000 as Weight).saturating_mul(r as Weight)) + (74_225_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_887_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_735_000 as Weight) - // Standard Error: 0 - .saturating_add((903_000 as Weight).saturating_mul(r as Weight)) + (73_987_000 as Weight) + // Standard Error: 1_000 + .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_595_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_448_000 as Weight).saturating_mul(r as Weight)) + (73_305_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_465_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_524_000 as Weight) + (73_037_000 as Weight) // Standard Error: 3_000 - .saturating_add((1_572_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_605_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_361_000 as Weight) + (76_434_000 as Weight) // Standard Error: 0 .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (76_131_000 as Weight) - // Standard Error: 7_000 - .saturating_add((7_271_000 as Weight).saturating_mul(r as Weight)) + (75_461_000 as Weight) + // Standard Error: 10_000 + .saturating_add((7_446_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (87_948_000 as Weight) - // Standard Error: 14_000 - .saturating_add((9_429_000 as Weight).saturating_mul(r as Weight)) + (87_222_000 as Weight) + // Standard Error: 15_000 + .saturating_add((9_406_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (98_091_000 as Weight) + (97_204_000 as Weight) // Standard Error: 1_000 - .saturating_add((481_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((472_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (74_311_000 as Weight) + (75_299_000 as Weight) // Standard Error: 1_000 - .saturating_add((627_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((601_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_701_000 as Weight) - // Standard Error: 1_000 - .saturating_add((677_000 as Weight).saturating_mul(r as Weight)) + (74_827_000 as Weight) + // Standard Error: 3_000 + .saturating_add((686_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_645_000 as Weight) - // Standard Error: 1_000 - .saturating_add((890_000 as Weight).saturating_mul(r as Weight)) + (74_624_000 as Weight) + // Standard Error: 2_000 + .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_130_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_156_000 as Weight).saturating_mul(r as Weight)) + (77_435_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_201_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (77_199_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_366_000 as Weight).saturating_mul(r as Weight)) + (76_693_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_410_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_024_000 as Weight) - // Standard Error: 2_000 - .saturating_add((675_000 as Weight).saturating_mul(r as Weight)) + (74_244_000 as Weight) + // Standard Error: 1_000 + .saturating_add((660_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (75_226_000 as Weight) - // Standard Error: 170_000 - .saturating_add((186_225_000 as Weight).saturating_mul(r as Weight)) + (73_527_000 as Weight) + // Standard Error: 931_000 + .saturating_add((184_946_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_307_000 as Weight) - // Standard Error: 2_000 - .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) + (74_181_000 as Weight) + // Standard Error: 6_000 + .saturating_add((906_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_408_000 as Weight) - // Standard Error: 3_000 - .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) + (74_339_000 as Weight) + // Standard Error: 1_000 + .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_418_000 as Weight) - // Standard Error: 1_000 - .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) + (74_444_000 as Weight) + // Standard Error: 3_000 + .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_130_000 as Weight) - // Standard Error: 2_000 - .saturating_add((920_000 as Weight).saturating_mul(r as Weight)) + (74_572_000 as Weight) + // Standard Error: 1_000 + .saturating_add((908_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_318_000 as Weight) + (74_349_000 as Weight) // Standard Error: 2_000 - .saturating_add((876_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((881_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_496_000 as Weight) + (74_426_000 as Weight) // Standard Error: 1_000 - .saturating_add((871_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((875_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (73_938_000 as Weight) - // Standard Error: 0 - .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) + (74_172_000 as Weight) + // Standard Error: 2_000 + .saturating_add((906_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (73_943_000 as Weight) + (74_169_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_367_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (74_305_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) + (74_205_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (73_948_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + (74_237_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_188_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + (74_181_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (74_156_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) + (74_038_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (73_972_000 as Weight) - // Standard Error: 0 - .saturating_add((1_365_000 as Weight).saturating_mul(r as Weight)) + (73_881_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (74_082_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (73_969_000 as Weight) + // Standard Error: 0 + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_190_000 as Weight) - // Standard Error: 1_000 + (74_497_000 as Weight) + // Standard Error: 3_000 .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (73_803_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + (74_275_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_063_000 as Weight) - // Standard Error: 1_000 + (74_349_000 as Weight) + // Standard Error: 3_000 .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (73_750_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) + (74_192_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (73_979_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) + (74_271_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (74_197_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_332_000 as Weight).saturating_mul(r as Weight)) + (73_971_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (73_624_000 as Weight) - // Standard Error: 5_000 - .saturating_add((2_020_000 as Weight).saturating_mul(r as Weight)) + (74_546_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_995_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (74_074_000 as Weight) + (74_194_000 as Weight) // Standard Error: 2_000 .saturating_add((2_050_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (73_766_000 as Weight) - // Standard Error: 5_000 - .saturating_add((2_016_000 as Weight).saturating_mul(r as Weight)) + (74_106_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_997_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (73_978_000 as Weight) - // Standard Error: 3_000 - .saturating_add((2_064_000 as Weight).saturating_mul(r as Weight)) + (74_219_000 as Weight) + // Standard Error: 5_000 + .saturating_add((2_061_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (73_996_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_336_000 as Weight).saturating_mul(r as Weight)) + (74_157_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (74_058_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) + (74_135_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_336_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (73_983_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_337_000 as Weight).saturating_mul(r as Weight)) + (74_038_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (74_061_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) + (74_011_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (73_940_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (74_054_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (73_954_000 as Weight) + (73_900_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (74_026_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + (73_948_000 as Weight) + // Standard Error: 0 + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (74_149_000 as Weight) + (73_972_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } } From 41567c30da77a2546a90c1049042ebd7b0b09bc4 Mon Sep 17 00:00:00 2001 From: wigy <1888808+wigy-opensource-developer@users.noreply.github.com> Date: Tue, 29 Mar 2022 20:33:20 +0000 Subject: [PATCH 0650/1472] Unignore test (#11097) --- client/network/src/service/tests.rs | 53 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 3dfd7392cd4dd..03d647eade173 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -186,7 +186,6 @@ fn build_nodes_one_proto() -> ( (node1, events_stream1, node2, events_stream2) } -#[ignore] #[test] fn notifications_state_consistent() { // Runs two nodes and ensures that events are propagated out of the API in a consistent @@ -272,38 +271,38 @@ fn notifications_state_consistent() { match next_event { future::Either::Left(Event::NotificationStreamOpened { remote, protocol, .. - }) => { - something_happened = true; - assert!(!node1_to_node2_open); - node1_to_node2_open = true; - assert_eq!(remote, *node2.local_peer_id()); - assert_eq!(protocol, PROTOCOL_NAME); - }, + }) => + if protocol == PROTOCOL_NAME { + something_happened = true; + assert!(!node1_to_node2_open); + node1_to_node2_open = true; + assert_eq!(remote, *node2.local_peer_id()); + }, future::Either::Right(Event::NotificationStreamOpened { remote, protocol, .. - }) => { - something_happened = true; - assert!(!node2_to_node1_open); - node2_to_node1_open = true; - assert_eq!(remote, *node1.local_peer_id()); - assert_eq!(protocol, PROTOCOL_NAME); - }, + }) => + if protocol == PROTOCOL_NAME { + something_happened = true; + assert!(!node2_to_node1_open); + node2_to_node1_open = true; + assert_eq!(remote, *node1.local_peer_id()); + }, future::Either::Left(Event::NotificationStreamClosed { remote, protocol, .. - }) => { - assert!(node1_to_node2_open); - node1_to_node2_open = false; - assert_eq!(remote, *node2.local_peer_id()); - assert_eq!(protocol, PROTOCOL_NAME); - }, + }) => + if protocol == PROTOCOL_NAME { + assert!(node1_to_node2_open); + node1_to_node2_open = false; + assert_eq!(remote, *node2.local_peer_id()); + }, future::Either::Right(Event::NotificationStreamClosed { remote, protocol, .. - }) => { - assert!(node2_to_node1_open); - node2_to_node1_open = false; - assert_eq!(remote, *node1.local_peer_id()); - assert_eq!(protocol, PROTOCOL_NAME); - }, + }) => + if protocol == PROTOCOL_NAME { + assert!(node2_to_node1_open); + node2_to_node1_open = false; + assert_eq!(remote, *node1.local_peer_id()); + }, future::Either::Left(Event::NotificationsReceived { remote, .. }) => { assert!(node1_to_node2_open); assert_eq!(remote, *node2.local_peer_id()); From f2d34943b1e74a212e18dd1483755e72bb0f2f45 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 30 Mar 2022 20:16:19 +0200 Subject: [PATCH 0651/1472] Fix Phragmen benchmark (#11137) * Fix phragmen benchmark Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_elections_phragmen --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/elections-phragmen/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- frame/elections-phragmen/src/benchmarking.rs | 29 ++--- frame/elections-phragmen/src/weights.rs | 112 +++++++++---------- 2 files changed, 71 insertions(+), 70 deletions(-) diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index ae98de4be7e4e..05e9df60c7fbe 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -39,7 +39,9 @@ type Lookup = <::Lookup as StaticLookup>::Source; /// grab new account with infinite balance. fn endowed_account(name: &'static str, index: u32) -> T::AccountId { let account: T::AccountId = account(name, index, 0); - let amount = default_stake::(BALANCE_FACTOR); + // Fund each account with at-least his stake but still a sane amount as to not mess up + // the vote calculation. + let amount = default_stake::(MAX_VOTERS) * BalanceOf::::from(BALANCE_FACTOR); let _ = T::Currency::make_free_balance_be(&account, amount); // important to increase the total issuance since T::CurrencyToVote will need it to be sane for // phragmen to work. @@ -54,9 +56,9 @@ fn as_lookup(account: T::AccountId) -> Lookup { } /// Get a reasonable amount of stake based on the execution trait's configuration -fn default_stake(factor: u32) -> BalanceOf { - let factor = BalanceOf::::from(factor); - T::Currency::minimum_balance() * factor +fn default_stake(num_votes: u32) -> BalanceOf { + let min = T::Currency::minimum_balance(); + Elections::::deposit_of(num_votes as usize).max(min) } /// Get the current number of candidates. @@ -88,7 +90,7 @@ fn submit_candidates_with_self_vote( prefix: &'static str, ) -> Result, &'static str> { let candidates = submit_candidates::(c, prefix)?; - let stake = default_stake::(BALANCE_FACTOR); + let stake = default_stake::(c); let _ = candidates .iter() .map(|c| submit_voter::(c.clone(), vec![c.clone()], stake).map(|_| ())) @@ -112,7 +114,7 @@ fn distribute_voters( num_voters: u32, votes: usize, ) -> Result<(), &'static str> { - let stake = default_stake::(BALANCE_FACTOR); + let stake = default_stake::(num_voters); for i in 0..num_voters { // to ensure that votes are different all_candidates.rotate_left(1); @@ -160,7 +162,7 @@ benchmarks! { let all_candidates = submit_candidates::(v, "candidates")?; let caller = endowed_account::("caller", 0); - let stake = default_stake::(BALANCE_FACTOR); + let stake = default_stake::(v); // original votes. let mut votes = all_candidates; @@ -173,14 +175,15 @@ benchmarks! { }: vote(RawOrigin::Signed(caller), votes, stake) vote_more { - let v in 2 .. (MAXIMUM_VOTE as u32); + let v in 2 .. (MAXIMUM_VOTE as u32); clean::(); // create a bunch of candidates. let all_candidates = submit_candidates::(v, "candidates")?; let caller = endowed_account::("caller", 0); - let stake = default_stake::(BALANCE_FACTOR); + // Multiply the stake with 10 since we want to be able to divide it by 10 again. + let stake = default_stake::(v) * BalanceOf::::from(10u32); // original votes. let mut votes = all_candidates.iter().skip(1).cloned().collect::>(); @@ -194,14 +197,14 @@ benchmarks! { }: vote(RawOrigin::Signed(caller), votes, stake / >::from(10u32)) vote_less { - let v in 2 .. (MAXIMUM_VOTE as u32); + let v in 2 .. (MAXIMUM_VOTE as u32); clean::(); // create a bunch of candidates. let all_candidates = submit_candidates::(v, "candidates")?; let caller = endowed_account::("caller", 0); - let stake = default_stake::(BALANCE_FACTOR); + let stake = default_stake::(v); // original votes. let mut votes = all_candidates; @@ -224,7 +227,7 @@ benchmarks! { let caller = endowed_account::("caller", 0); - let stake = default_stake::(BALANCE_FACTOR); + let stake = default_stake::(v); submit_voter::(caller.clone(), all_candidates, stake)?; whitelist!(caller); @@ -238,7 +241,7 @@ benchmarks! { let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get(); clean::(); - let stake = default_stake::(BALANCE_FACTOR); + let stake = default_stake::(c); // create m members and runners combined. let _ = fill_seats_up_to::(m)?; diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 22c1c1cbeb406..e973334b833cc 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-03-29, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // --chain=dev // --steps=50 @@ -33,9 +33,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/elections-phragmen/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -70,9 +68,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_equal(v: u32, ) -> Weight { - (23_406_000 as Weight) + (22_981_000 as Weight) // Standard Error: 6_000 - .saturating_add((270_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((232_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -82,9 +80,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_more(v: u32, ) -> Weight { - (35_660_000 as Weight) - // Standard Error: 6_000 - .saturating_add((316_000 as Weight).saturating_mul(v as Weight)) + (36_170_000 as Weight) + // Standard Error: 8_000 + .saturating_add((219_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -94,16 +92,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_less(v: u32, ) -> Weight { - (35_999_000 as Weight) - // Standard Error: 6_000 - .saturating_add((299_000 as Weight).saturating_mul(v as Weight)) + (35_798_000 as Weight) + // Standard Error: 8_000 + .saturating_add((241_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (33_692_000 as Weight) + (33_060_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -111,17 +109,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) fn submit_candidacy(c: u32, ) -> Weight { - (35_506_000 as Weight) - // Standard Error: 1_000 - .saturating_add((192_000 as Weight).saturating_mul(c as Weight)) + (35_384_000 as Weight) + // Standard Error: 0 + .saturating_add((124_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (31_402_000 as Weight) + (31_555_000 as Weight) // Standard Error: 1_000 - .saturating_add((113_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((78_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -131,13 +129,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (42_727_000 as Weight) + (41_531_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (30_638_000 as Weight) + (30_762_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -152,13 +150,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (49_317_000 as Weight) + (48_287_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Elections RunnersUp (r:1 w:0) fn remove_member_wrong_refund() -> Weight { - (4_688_000 as Weight) + (4_747_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Elections Voting (r:251 w:250) @@ -169,8 +167,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:250 w:250) fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 36_000 - .saturating_add((51_016_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 37_000 + .saturating_add((49_564_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -186,12 +184,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_760_000 - .saturating_add((29_569_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 732_000 - .saturating_add((51_842_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 49_000 - .saturating_add((3_546_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 1_656_000 + .saturating_add((29_011_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 689_000 + .saturating_add((49_204_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 47_000 + .saturating_add((3_352_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) @@ -206,9 +204,9 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_equal(v: u32, ) -> Weight { - (23_406_000 as Weight) + (22_981_000 as Weight) // Standard Error: 6_000 - .saturating_add((270_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((232_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -218,9 +216,9 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_more(v: u32, ) -> Weight { - (35_660_000 as Weight) - // Standard Error: 6_000 - .saturating_add((316_000 as Weight).saturating_mul(v as Weight)) + (36_170_000 as Weight) + // Standard Error: 8_000 + .saturating_add((219_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -230,16 +228,16 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_less(v: u32, ) -> Weight { - (35_999_000 as Weight) - // Standard Error: 6_000 - .saturating_add((299_000 as Weight).saturating_mul(v as Weight)) + (35_798_000 as Weight) + // Standard Error: 8_000 + .saturating_add((241_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (33_692_000 as Weight) + (33_060_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -247,17 +245,17 @@ impl WeightInfo for () { // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) fn submit_candidacy(c: u32, ) -> Weight { - (35_506_000 as Weight) - // Standard Error: 1_000 - .saturating_add((192_000 as Weight).saturating_mul(c as Weight)) + (35_384_000 as Weight) + // Standard Error: 0 + .saturating_add((124_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (31_402_000 as Weight) + (31_555_000 as Weight) // Standard Error: 1_000 - .saturating_add((113_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((78_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -267,13 +265,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (42_727_000 as Weight) + (41_531_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (30_638_000 as Weight) + (30_762_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -288,13 +286,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (49_317_000 as Weight) + (48_287_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Elections RunnersUp (r:1 w:0) fn remove_member_wrong_refund() -> Weight { - (4_688_000 as Weight) + (4_747_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Elections Voting (r:251 w:250) @@ -305,8 +303,8 @@ impl WeightInfo for () { // Storage: System Account (r:250 w:250) fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 36_000 - .saturating_add((51_016_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 37_000 + .saturating_add((49_564_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -322,12 +320,12 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_760_000 - .saturating_add((29_569_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 732_000 - .saturating_add((51_842_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 49_000 - .saturating_add((3_546_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 1_656_000 + .saturating_add((29_011_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 689_000 + .saturating_add((49_204_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 47_000 + .saturating_add((3_352_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) From b2543516dc83bb1dda2d27d40ace959d994799c9 Mon Sep 17 00:00:00 2001 From: Georges Date: Thu, 31 Mar 2022 13:54:44 +0100 Subject: [PATCH 0652/1472] Enforce `MaxEncodedLen` impl for `NposSolution` (#11103) * Fail if `MaxVoters` too small * Fixing benchmarking test, better naming of error * reverting accidental change * use fully qualified syntax no need to interate to calculate len * Fail directly if too many voters --- .../election-provider-multi-phase/src/mock.rs | 2 +- .../solution-type/src/single_page.rs | 6 +++++ frame/election-provider-support/src/lib.rs | 3 ++- frame/election-provider-support/src/mock.rs | 2 +- frame/election-provider-support/src/tests.rs | 27 +++++++++++++++++++ primitives/npos-elections/src/lib.rs | 4 ++- 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 1b3c4d9306246..d6f040363dba0 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -74,7 +74,7 @@ frame_election_provider_support::generate_solution_type!( VoterIndex = VoterIndex, TargetIndex = TargetIndex, Accuracy = PerU16, - MaxVoters = ConstU32::<20> + MaxVoters = ConstU32::<2_000> >(16) ); diff --git a/frame/election-provider-support/solution-type/src/single_page.rs b/frame/election-provider-support/solution-type/src/single_page.rs index 5a3ddc22f61c8..a20f0542984dc 100644 --- a/frame/election-provider-support/solution-type/src/single_page.rs +++ b/frame/election-provider-support/solution-type/src/single_page.rs @@ -124,6 +124,11 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { for<'r> FV: Fn(&'r A) -> Option, for<'r> FT: Fn(&'r A) -> Option, { + // Make sure that the voter bound is binding. + // `assignments.len()` actually represents the number of voters + if assignments.len() as u32 > <#max_voters as _feps::Get>::get() { + return Err(_feps::Error::TooManyVoters); + } let mut #struct_name: #ident = Default::default(); for _feps::Assignment { who, distribution } in assignments { match distribution.len() { @@ -134,6 +139,7 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { } } }; + Ok(#struct_name) } diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index d79b5289dffe3..453cef8956fe5 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -170,12 +170,13 @@ pub mod onchain; pub mod traits; #[cfg(feature = "std")] use codec::{Decode, Encode}; -use frame_support::{traits::Get, BoundedVec, RuntimeDebug}; +use frame_support::{BoundedVec, RuntimeDebug}; use sp_runtime::traits::Bounded; use sp_std::{fmt::Debug, prelude::*}; /// Re-export the solution generation macro. pub use frame_election_provider_solution_type::generate_solution_type; +pub use frame_support::traits::Get; /// Re-export some type as they are used in the interface. pub use sp_arithmetic::PerThing; pub use sp_npos_elections::{ diff --git a/frame/election-provider-support/src/mock.rs b/frame/election-provider-support/src/mock.rs index 1ea8dddf7eb17..d10b1724c95d8 100644 --- a/frame/election-provider-support/src/mock.rs +++ b/frame/election-provider-support/src/mock.rs @@ -47,7 +47,7 @@ crate::generate_solution_type! { VoterIndex = u32, TargetIndex = u16, Accuracy = TestAccuracy, - MaxVoters = frame_support::traits::ConstU32::<20>, + MaxVoters = frame_support::traits::ConstU32::<2_500>, >(16) } diff --git a/frame/election-provider-support/src/tests.rs b/frame/election-provider-support/src/tests.rs index 7b4e46d836176..f88f3653c681c 100644 --- a/frame/election-provider-support/src/tests.rs +++ b/frame/election-provider-support/src/tests.rs @@ -91,6 +91,33 @@ mod solution_type { assert!(with_compact < without_compact); } + #[test] + fn from_assignment_fail_too_many_voters() { + let rng = rand::rngs::SmallRng::seed_from_u64(0); + + // This will produce 24 voters.. + let (voters, assignments, candidates) = generate_random_votes(10, 25, rng); + let voter_index = make_voter_fn(&voters); + let target_index = make_target_fn(&candidates); + + // Limit the voters to 20.. + generate_solution_type!( + pub struct InnerTestSolution::< + VoterIndex = u32, + TargetIndex = u16, + Accuracy = TestAccuracy, + MaxVoters = frame_support::traits::ConstU32::<20>, + >(16) + ); + + // 24 > 20, so this should fail. + assert_eq!( + InnerTestSolution::from_assignment(&assignments, &voter_index, &target_index) + .unwrap_err(), + NposError::TooManyVoters, + ); + } + #[test] fn max_encoded_len_too_small() { generate_solution_type!( diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 11d531fa56d87..93fb24eb4a3ca 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -119,12 +119,14 @@ pub enum Error { SolutionTargetOverflow, /// One of the index functions returned none. SolutionInvalidIndex, - /// One of the page indices was invalid + /// One of the page indices was invalid. SolutionInvalidPageIndex, /// An error occurred in some arithmetic operation. ArithmeticError(&'static str), /// The data provided to create support map was invalid. InvalidSupportEdge, + /// The number of voters is bigger than the `MaxVoters` bound. + TooManyVoters, } /// A type which is used in the API of this crate as a numeric weight of a vote, most often the From 64f1663a18b511a43280aa457da9183a62b70477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 31 Mar 2022 15:13:34 +0200 Subject: [PATCH 0653/1472] frame-support: Rename tests to express what they are doing (#11147) Fixes: https://github.com/paritytech/substrate/issues/11145 --- frame/support/src/storage/bounded_vec.rs | 2 +- frame/support/src/storage/weak_bounded_vec.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index cf585af395587..137015098cfa6 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -693,7 +693,7 @@ pub mod test { } #[test] - fn try_append_is_correct() { + fn bound_returns_correct_value() { assert_eq!(BoundedVec::>::bound(), 7); } diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 4b3d87f776b4a..aa6dc88eaa4f4 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -330,7 +330,7 @@ pub mod test { } #[test] - fn try_append_is_correct() { + fn bound_returns_correct_value() { assert_eq!(WeakBoundedVec::>::bound(), 7); } From 2287cd80830b081bd51bd8c313c6213d312e541e Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 31 Mar 2022 15:16:34 +0100 Subject: [PATCH 0654/1472] add iter-from for bags-list (#11104) * add iter-from for bags-list * Fix * Apply suggestions from code review Co-authored-by: Oliver Tale-Yazdi * Fix Co-authored-by: Oliver Tale-Yazdi --- frame/bags-list/src/lib.rs | 8 +++++- frame/bags-list/src/list/mod.rs | 29 ++++++++++++++++++++++ frame/bags-list/src/tests.rs | 21 ++++++++++++++++ frame/election-provider-support/src/lib.rs | 5 ++++ frame/staking/src/pallet/impls.rs | 18 +++++++++++++- 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index aa9f1c80dfdbc..94553433e230d 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -271,13 +271,19 @@ impl, I: 'static> Pallet { impl, I: 'static> SortedListProvider for Pallet { type Error = ListError; - type Score = T::Score; fn iter() -> Box> { Box::new(List::::iter().map(|n| n.id().clone())) } + fn iter_from( + start: &T::AccountId, + ) -> Result>, Self::Error> { + let iter = List::::iter_from(start)?; + Ok(Box::new(iter.map(|n| n.id().clone()))) + } + fn count() -> u32 { ListNodes::::count() } diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 4e1287458bcb4..db8c06a38d674 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -42,6 +42,8 @@ use sp_std::{ pub enum ListError { /// A duplicate id has been detected. Duplicate, + /// Given node id was not found. + NodeNotFound, } #[cfg(test)] @@ -244,6 +246,33 @@ impl, I: 'static> List { iter.filter_map(Bag::get).flat_map(|bag| bag.iter()) } + /// Same as `iter`, but we start from a specific node. + /// + /// All items after this node are returned, excluding `start` itself. + pub(crate) fn iter_from( + start: &T::AccountId, + ) -> Result>, ListError> { + // We chain two iterators: + // 1. from the given `start` till the end of the bag + // 2. all the bags that come after `start`'s bag. + + let start_node = Node::::get(start).ok_or(ListError::NodeNotFound)?; + let start_node_upper = start_node.bag_upper; + let start_bag = sp_std::iter::successors(start_node.next(), |prev| prev.next()); + + let thresholds = T::BagThresholds::get(); + let idx = thresholds.partition_point(|&threshold| start_node_upper > threshold); + let leftover_bags = thresholds + .into_iter() + .take(idx) + .copied() + .rev() + .filter_map(Bag::get) + .flat_map(|bag| bag.iter()); + + Ok(start_bag.chain(leftover_bags)) + } + /// Insert several ids into the appropriate bags in the list. Continues with insertions /// if duplicates are detected. /// diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs index 0d6ba4721b9a2..941623229dc27 100644 --- a/frame/bags-list/src/tests.rs +++ b/frame/bags-list/src/tests.rs @@ -458,6 +458,27 @@ mod sorted_list_provider { }); } + #[test] + fn iter_from_works() { + ExtBuilder::default().add_ids(vec![(5, 5), (6, 15)]).build_and_execute(|| { + // given + assert_eq!( + List::::get_bags(), + vec![(10, vec![1, 5]), (20, vec![6]), (1000, vec![2, 3, 4])] + ); + + assert_eq!(BagsList::iter_from(&2).unwrap().collect::>(), vec![3, 4, 6, 1, 5]); + assert_eq!(BagsList::iter_from(&3).unwrap().collect::>(), vec![4, 6, 1, 5]); + assert_eq!(BagsList::iter_from(&4).unwrap().collect::>(), vec![6, 1, 5]); + assert_eq!(BagsList::iter_from(&6).unwrap().collect::>(), vec![1, 5]); + assert_eq!(BagsList::iter_from(&1).unwrap().collect::>(), vec![5]); + assert!(BagsList::iter_from(&5).unwrap().collect::>().is_empty()); + assert!(BagsList::iter_from(&7).is_err()); + + assert_storage_noop!(assert!(BagsList::iter_from(&8).is_err())); + }); + } + #[test] fn count_works() { ExtBuilder::default().build_and_execute(|| { diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 453cef8956fe5..19735cf6035ac 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -441,6 +441,11 @@ pub trait SortedListProvider { /// An iterator over the list, which can have `take` called on it. fn iter() -> Box>; + /// Returns an iterator over the list, starting right after from the given voter. + /// + /// May return an error if `start` is invalid. + fn iter_from(start: &AccountId) -> Result>, Self::Error>; + /// The current count of ids in the list. fn count() -> u32; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 9d5a3ed484184..90f19c6badd8f 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1308,7 +1308,6 @@ impl SortedListProvider for UseNominatorsAndValidatorsM type Error = (); type Score = VoteWeight; - /// Returns iterator over voter list, which can have `take` called on it. fn iter() -> Box> { Box::new( Validators::::iter() @@ -1316,6 +1315,23 @@ impl SortedListProvider for UseNominatorsAndValidatorsM .chain(Nominators::::iter().map(|(n, _)| n)), ) } + fn iter_from( + start: &T::AccountId, + ) -> Result>, Self::Error> { + if Validators::::contains_key(start) { + let start_key = Validators::::hashed_key_for(start); + Ok(Box::new( + Validators::::iter_from(start_key) + .map(|(n, _)| n) + .chain(Nominators::::iter().map(|(x, _)| x)), + )) + } else if Nominators::::contains_key(start) { + let start_key = Nominators::::hashed_key_for(start); + Ok(Box::new(Nominators::::iter_from(start_key).map(|(n, _)| n))) + } else { + Err(()) + } + } fn count() -> u32 { Nominators::::count().saturating_add(Validators::::count()) } From 56dc6d1a3d9ae166f47368f9006ff4fe5457d889 Mon Sep 17 00:00:00 2001 From: David Salami <31099392+Wizdave97@users.noreply.github.com> Date: Fri, 1 Apr 2022 09:50:11 +0100 Subject: [PATCH 0655/1472] Refactor Beefy MMR and remove parachain specific implementations (#10664) * refactor beefy mmr * use plain vector of bytes for leaf extra * update comment * update comments * remove unused vars * Use sp_std::vec::Vec Co-authored-by: Adrian Catangiu * make extra data generic * fix tests * refactor beefy-mmr * Update frame/beefy-mmr/src/lib.rs * minor fix * fmt * Update frame/beefy-mmr/src/lib.rs Co-authored-by: Adrian Catangiu --- frame/beefy-mmr/src/lib.rs | 55 +++++++----------------------------- frame/beefy-mmr/src/mock.rs | 23 +++++++++++---- frame/beefy-mmr/src/tests.rs | 18 +++++------- primitives/beefy/src/mmr.rs | 21 ++++++++++++-- 4 files changed, 52 insertions(+), 65 deletions(-) diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 476589717e06c..9ee7bd770f64c 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -29,17 +29,16 @@ //! The MMR leaf contains: //! 1. Block number and parent block hash. //! 2. Merkle Tree Root Hash of next BEEFY validator set. -//! 3. Merkle Tree Root Hash of current parachain heads state. +//! 3. Arbitrary extra leaf data to be used by downstream pallets to include custom data. //! //! and thanks to versioning can be easily updated in the future. -use sp_runtime::traits::{Convert, Hash}; +use sp_runtime::traits::{Convert, Hash, Member}; use sp_std::prelude::*; -use beefy_primitives::mmr::{BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}; +use beefy_primitives::mmr::{BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}; use pallet_mmr::primitives::LeafDataProvider; -use codec::Encode; use frame_support::traits::Get; pub use pallet::*; @@ -90,23 +89,6 @@ impl Convert> for BeefyEcdsaToEth } type MerkleRootOf = ::Hash; -type ParaId = u32; -type ParaHead = Vec; - -/// A type that is able to return current list of parachain heads that end up in the MMR leaf. -pub trait ParachainHeadsProvider { - /// Return a list of tuples containing a `ParaId` and Parachain Header data (ParaHead). - /// - /// The returned data does not have to be sorted. - fn parachain_heads() -> Vec<(ParaId, ParaHead)>; -} - -/// A default implementation for runtimes without parachains. -impl ParachainHeadsProvider for () { - fn parachain_heads() -> Vec<(ParaId, ParaHead)> { - Default::default() - } -} #[frame_support::pallet] pub mod pallet { @@ -138,12 +120,11 @@ pub mod pallet { /// efficiency reasons. type BeefyAuthorityToMerkleLeaf: Convert<::BeefyId, Vec>; - /// Retrieve a list of current parachain heads. - /// - /// The trait is implemented for `paras` module, but since not all chains might have - /// parachains, and we want to keep the MMR leaf structure uniform, it's possible to use - /// `()` as well to simply put dummy data to the leaf. - type ParachainHeads: ParachainHeadsProvider; + /// The type expected for the leaf extra data + type LeafExtra: Member + codec::FullCodec; + + /// Retrieve arbitrary data that should be added to the mmr leaf + type BeefyDataProvider: BeefyDataProvider; } /// Details of next BEEFY authority set. @@ -163,13 +144,14 @@ where ::BlockNumber, ::Hash, MerkleRootOf, + T::LeafExtra, >; fn leaf_data() -> Self::LeafData { MmrLeaf { version: T::LeafVersion::get(), parent_number_and_hash: frame_system::Pallet::::leaf_data(), - parachain_heads: Pallet::::parachain_heads_merkle_root(), + leaf_extra: T::BeefyDataProvider::extra_data(), beefy_next_authority_set: Pallet::::update_beefy_next_authority_set(), } } @@ -188,23 +170,6 @@ impl Pallet where MerkleRootOf: From + Into, { - /// Returns latest root hash of a merkle tree constructed from all active parachain headers. - /// - /// The leafs are sorted by `ParaId` to allow more efficient lookups and non-existence proofs. - /// - /// NOTE this does not include parathreads - only parachains are part of the merkle tree. - /// - /// NOTE This is an initial and inefficient implementation, which re-constructs - /// the merkle tree every block. Instead we should update the merkle root in - /// [Self::on_initialize] call of this pallet and update the merkle tree efficiently (use - /// on-chain storage to persist inner nodes). - fn parachain_heads_merkle_root() -> MerkleRootOf { - let mut para_heads = T::ParachainHeads::parachain_heads(); - para_heads.sort(); - let para_heads = para_heads.into_iter().map(|pair| pair.encode()); - beefy_merkle_tree::merkle_root::(para_heads).into() - } - /// Returns details of the next BEEFY authority set. /// /// Details contain authority set id, authority set length and a merkle root, diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index dcee901ec14ce..f6a35f68a4a1f 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -18,6 +18,7 @@ use std::vec; use beefy_primitives::mmr::MmrLeafVersion; +use codec::Encode; use frame_support::{ construct_runtime, parameter_types, sp_io::TestExternalities, @@ -34,7 +35,9 @@ use sp_runtime::{ use crate as pallet_beefy_mmr; -pub use beefy_primitives::{crypto::AuthorityId as BeefyId, ConsensusLog, BEEFY_ENGINE_ID}; +pub use beefy_primitives::{ + crypto::AuthorityId as BeefyId, mmr::BeefyDataProvider, ConsensusLog, BEEFY_ENGINE_ID, +}; impl_opaque_keys! { pub struct MockSessionKeys { @@ -102,6 +105,7 @@ pub type MmrLeaf = beefy_primitives::mmr::MmrLeaf< ::BlockNumber, ::Hash, ::Hash, + Vec, >; impl pallet_mmr::Config for Test { @@ -131,13 +135,20 @@ impl pallet_beefy_mmr::Config for Test { type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; - type ParachainHeads = DummyParaHeads; + type LeafExtra = Vec; + + type BeefyDataProvider = DummyDataProvider; } -pub struct DummyParaHeads; -impl pallet_beefy_mmr::ParachainHeadsProvider for DummyParaHeads { - fn parachain_heads() -> Vec<(pallet_beefy_mmr::ParaId, pallet_beefy_mmr::ParaHead)> { - vec![(15, vec![1, 2, 3]), (5, vec![4, 5, 6])] +pub struct DummyDataProvider; +impl BeefyDataProvider> for DummyDataProvider { + fn extra_data() -> Vec { + let mut col = vec![(15, vec![1, 2, 3]), (5, vec![4, 5, 6])]; + col.sort(); + beefy_merkle_tree::merkle_root::, _, _>( + col.into_iter().map(|pair| pair.encode()), + ) + .to_vec() } } diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index 452b8736a7916..fd383adb1d4a2 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -71,7 +71,7 @@ fn should_contain_mmr_digest() { assert_eq!( System::digest().logs, vec![beefy_log(ConsensusLog::MmrRoot( - hex!("969d516e5279540ef38e4a710fb0645cab4c3b01e528be7285b85ec9c5fb55c8").into() + hex!("fa0275b19b2565089f7e2377ee73b9050e8d53bce108ef722a3251fd9d371d4b").into() ))] ); @@ -82,13 +82,13 @@ fn should_contain_mmr_digest() { System::digest().logs, vec![ beefy_log(ConsensusLog::MmrRoot( - hex!("969d516e5279540ef38e4a710fb0645cab4c3b01e528be7285b85ec9c5fb55c8").into() + hex!("fa0275b19b2565089f7e2377ee73b9050e8d53bce108ef722a3251fd9d371d4b").into() )), beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4),], 1,).unwrap() )), beefy_log(ConsensusLog::MmrRoot( - hex!("8c42b7b040d262f7f2e26abeb61ab0c3c448f60c7f2f19e6ca0035d9bb3ae7e2").into() + hex!("85554fa7d4e863cce3cdce668c1ae82c0174ad37f8d1399284018bec9f9971c3").into() )), ] ); @@ -114,10 +114,8 @@ fn should_contain_valid_leaf_data() { root: hex!("176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96") .into(), }, - parachain_heads: hex!( - "ed893c8f8cc87195a5d4d2805b011506322036bcace79642aa3e94ab431e442e" - ) - .into(), + leaf_extra: hex!("55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648") + .to_vec(), } ); @@ -138,10 +136,8 @@ fn should_contain_valid_leaf_data() { root: hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5") .into(), }, - parachain_heads: hex!( - "ed893c8f8cc87195a5d4d2805b011506322036bcace79642aa3e94ab431e442e" - ) - .into(), + leaf_extra: hex!("55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648") + .to_vec() } ); } diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 29f513629d012..426a1ba5ff80b 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -26,12 +26,26 @@ //! but we imagine they will be useful for other chains that either want to bridge with Polkadot //! or are completely standalone, but heavily inspired by Polkadot. +use crate::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +/// A provider for extra data that gets added to the Mmr leaf +pub trait BeefyDataProvider { + /// Return a vector of bytes, ideally should be a merkle root hash + fn extra_data() -> ExtraData; +} + +/// A default implementation for runtimes. +impl BeefyDataProvider> for () { + fn extra_data() -> Vec { + Vec::new() + } +} + /// A standard leaf that gets added every block to the MMR constructed by Substrate's `pallet_mmr`. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] -pub struct MmrLeaf { +pub struct MmrLeaf { /// Version of the leaf format. /// /// Can be used to enable future format migrations and compatibility. @@ -41,8 +55,9 @@ pub struct MmrLeaf { pub parent_number_and_hash: (BlockNumber, Hash), /// A merkle root of the next BEEFY authority set. pub beefy_next_authority_set: BeefyNextAuthoritySet, - /// A merkle root of all registered parachain heads. - pub parachain_heads: MerkleRoot, + /// Arbitrary extra leaf data to be used by downstream pallets to include custom data in the + /// [`MmrLeaf`] + pub leaf_extra: ExtraData, } /// A MMR leaf versioning scheme. From 62fcc8abb7679221814fd3a76d36ad5eafb65657 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sat, 2 Apr 2022 13:12:54 -0400 Subject: [PATCH 0656/1472] Add Limit to Tranasctional Layers (#10808) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * introduce hard limit to transactional * add single layer transactional * remove single_transactional * Update mod.rs * add tests * maybe fix contracts cc @athei * fmt * fix contract logic * Update frame/contracts/src/exec.rs Co-authored-by: Alexander Theißen * Update exec.rs * add unchecked and custom errors * Update lib.rs * Apply suggestions from code review Co-authored-by: Alexander Theißen * Replace storage access by atomics Co-authored-by: Alexander Theißen --- frame/contracts/src/exec.rs | 29 ++- frame/support/procedural/src/transactional.rs | 4 +- frame/support/src/storage/mod.rs | 208 +++++++++++++----- .../support/test/tests/storage_transaction.rs | 108 +++++---- primitives/runtime/src/lib.rs | 33 +++ 5 files changed, 273 insertions(+), 109 deletions(-) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index e73b29e54378b..7aa5c0b731fad 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -774,14 +774,27 @@ where // All changes performed by the contract are executed under a storage transaction. // This allows for roll back on error. Changes to the cached contract_info are - // comitted or rolled back when popping the frame. - let (success, output) = with_transaction(|| { - let output = do_transaction(); - match &output { - Ok(result) if !result.did_revert() => TransactionOutcome::Commit((true, output)), - _ => TransactionOutcome::Rollback((false, output)), - } - }); + // committed or rolled back when popping the frame. + // + // `with_transactional` may return an error caused by a limit in the + // transactional storage depth. + let transaction_outcome = + with_transaction(|| -> TransactionOutcome> { + let output = do_transaction(); + match &output { + Ok(result) if !result.did_revert() => + TransactionOutcome::Commit(Ok((true, output))), + _ => TransactionOutcome::Rollback(Ok((false, output))), + } + }); + + let (success, output) = match transaction_outcome { + // `with_transactional` executed successfully, and we have the expected output. + Ok((success, output)) => (success, output), + // `with_transactional` returned an error, and we propagate that error and note no state + // has changed. + Err(error) => (false, Err(error.into())), + }; self.pop_frame(success); output } diff --git a/frame/support/procedural/src/transactional.rs b/frame/support/procedural/src/transactional.rs index 66a8d083fb562..ba75fbc9737aa 100644 --- a/frame/support/procedural/src/transactional.rs +++ b/frame/support/procedural/src/transactional.rs @@ -49,7 +49,9 @@ pub fn require_transactional(_attr: TokenStream, input: TokenStream) -> Result = RefCell::new(0); + pub fn get_transaction_level() -> Layer { + NUM_LEVELS.load(Ordering::SeqCst) } - pub fn require_transaction() { - let level = TRANSACTION_LEVEL.with(|v| *v.borrow()); - if level == 0 { - panic!("Require transaction not called within with_transaction"); - } + /// Increments the transaction level. Returns an error if levels go past the limit. + /// + /// Returns a guard that when dropped decrements the transaction level automatically. + pub fn inc_transaction_level() -> Result { + NUM_LEVELS + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |existing_levels| { + if existing_levels >= TRANSACTIONAL_LIMIT { + return None + } + // Cannot overflow because of check above. + Some(existing_levels + 1) + }) + .map_err(|_| ())?; + Ok(StorageLayerGuard) } - pub struct TransactionLevelGuard; + fn dec_transaction_level() { + NUM_LEVELS + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |existing_levels| { + if existing_levels == 0 { + log::warn!( + "We are underflowing with calculating transactional levels. Not great, but let's not panic...", + ); + None + } else { + // Cannot underflow because of checks above. + Some(existing_levels - 1) + } + }) + .ok(); + } - impl Drop for TransactionLevelGuard { - fn drop(&mut self) { - TRANSACTION_LEVEL.with(|v| *v.borrow_mut() -= 1); - } + pub fn is_transactional() -> bool { + get_transaction_level() > 0 } - /// Increments the transaction level. - /// - /// Returns a guard that when dropped decrements the transaction level automatically. - pub fn inc_transaction_level() -> TransactionLevelGuard { - TRANSACTION_LEVEL.with(|v| { - let mut val = v.borrow_mut(); - *val += 1; - if *val > 10 { - log::warn!( - "Detected with_transaction with nest level {}. Nested usage of with_transaction is not recommended.", - *val - ); - } - }); + pub struct StorageLayerGuard; - TransactionLevelGuard + impl Drop for StorageLayerGuard { + fn drop(&mut self) { + dec_transaction_level() + } } } -/// Assert this method is called within a storage transaction. -/// This will **panic** if is not called within a storage transaction. -/// -/// This assertion is enabled for native execution and when `debug_assertions` are enabled. -pub fn require_transaction() { - #[cfg(all(feature = "std", any(test, debug_assertions)))] - debug_helper::require_transaction(); +/// Check if the current call is within a transactional layer. +pub fn is_transactional() -> bool { + transaction_level_tracker::is_transactional() } /// Execute the supplied function in a new storage transaction. @@ -100,15 +113,55 @@ pub fn require_transaction() { /// All changes to storage performed by the supplied function are discarded if the returned /// outcome is `TransactionOutcome::Rollback`. /// -/// Transactions can be nested to any depth. Commits happen to the parent transaction. -pub fn with_transaction(f: impl FnOnce() -> TransactionOutcome) -> R { +/// Transactions can be nested up to `TRANSACTIONAL_LIMIT` times; more than that will result in an +/// error. +/// +/// Commits happen to the parent transaction. +pub fn with_transaction(f: impl FnOnce() -> TransactionOutcome>) -> Result +where + E: From, +{ use sp_io::storage::{commit_transaction, rollback_transaction, start_transaction}; use TransactionOutcome::*; + let _guard = transaction_level_tracker::inc_transaction_level() + .map_err(|()| TransactionalError::LimitReached.into())?; + start_transaction(); - #[cfg(all(feature = "std", any(test, debug_assertions)))] - let _guard = debug_helper::inc_transaction_level(); + match f() { + Commit(res) => { + commit_transaction(); + res + }, + Rollback(res) => { + rollback_transaction(); + res + }, + } +} + +/// Same as [`with_transaction`] but without a limit check on nested transactional layers. +/// +/// This is mostly for backwards compatibility before there was a transactional layer limit. +/// It is recommended to only use [`with_transaction`] to avoid users from generating too many +/// transactional layers. +pub fn with_transaction_unchecked(f: impl FnOnce() -> TransactionOutcome) -> R { + use sp_io::storage::{commit_transaction, rollback_transaction, start_transaction}; + use TransactionOutcome::*; + + let maybe_guard = transaction_level_tracker::inc_transaction_level(); + + if maybe_guard.is_err() { + log::warn!( + "The transactional layer limit has been reached, and new transactional layers are being + spawned with `with_transaction_unchecked`. This could be caused by someone trying to + attack your chain, and you should investigate usage of `with_transaction_unchecked` and + potentially migrate to `with_transaction`, which enforces a transactional limit.", + ); + } + + start_transaction(); match f() { Commit(res) => { @@ -1418,12 +1471,13 @@ pub fn storage_prefix(pallet_name: &[u8], storage_name: &[u8]) -> [u8; 32] { #[cfg(test)] mod test { use super::*; - use crate::{assert_ok, hash::Identity, Twox128}; + use crate::{assert_noop, assert_ok, hash::Identity, Twox128}; use bounded_vec::BoundedVec; use frame_support::traits::ConstU32; use generator::StorageValue as _; use sp_core::hashing::twox_128; use sp_io::TestExternalities; + use sp_runtime::DispatchResult; use weak_bounded_vec::WeakBoundedVec; #[test] @@ -1535,25 +1589,67 @@ mod test { } #[test] - #[should_panic(expected = "Require transaction not called within with_transaction")] - fn require_transaction_should_panic() { + fn is_transactional_should_return_false() { TestExternalities::default().execute_with(|| { - require_transaction(); + assert!(!is_transactional()); }); } #[test] - fn require_transaction_should_not_panic_in_with_transaction() { + fn is_transactional_should_not_error_in_with_transaction() { TestExternalities::default().execute_with(|| { - with_transaction(|| { - require_transaction(); - TransactionOutcome::Commit(()) - }); - - with_transaction(|| { - require_transaction(); - TransactionOutcome::Rollback(()) - }); + assert_ok!(with_transaction(|| -> TransactionOutcome { + assert!(is_transactional()); + TransactionOutcome::Commit(Ok(())) + })); + + assert_noop!( + with_transaction(|| -> TransactionOutcome { + assert!(is_transactional()); + TransactionOutcome::Rollback(Err("revert".into())) + }), + "revert" + ); + }); + } + + fn recursive_transactional(num: u32) -> DispatchResult { + if num == 0 { + return Ok(()) + } + + with_transaction(|| -> TransactionOutcome { + let res = recursive_transactional(num - 1); + TransactionOutcome::Commit(res) + }) + } + + #[test] + fn transaction_limit_should_work() { + TestExternalities::default().execute_with(|| { + assert_eq!(transaction_level_tracker::get_transaction_level(), 0); + + assert_ok!(with_transaction(|| -> TransactionOutcome { + assert_eq!(transaction_level_tracker::get_transaction_level(), 1); + TransactionOutcome::Commit(Ok(())) + })); + + assert_ok!(with_transaction(|| -> TransactionOutcome { + assert_eq!(transaction_level_tracker::get_transaction_level(), 1); + let res = with_transaction(|| -> TransactionOutcome { + assert_eq!(transaction_level_tracker::get_transaction_level(), 2); + TransactionOutcome::Commit(Ok(())) + }); + TransactionOutcome::Commit(res) + })); + + assert_ok!(recursive_transactional(255)); + assert_noop!( + recursive_transactional(256), + sp_runtime::TransactionalError::LimitReached + ); + + assert_eq!(transaction_level_tracker::get_transaction_level(), 0); }); } diff --git a/frame/support/test/tests/storage_transaction.rs b/frame/support/test/tests/storage_transaction.rs index 0f1c3a2e0c536..848a91a7f5a86 100644 --- a/frame/support/test/tests/storage_transaction.rs +++ b/frame/support/test/tests/storage_transaction.rs @@ -16,12 +16,13 @@ // limitations under the License. use frame_support::{ - assert_noop, assert_ok, + assert_noop, assert_ok, assert_storage_noop, dispatch::{DispatchError, DispatchResult}, storage::{with_transaction, TransactionOutcome::*}, transactional, StorageMap, StorageValue, }; use sp_io::TestExternalities; +use sp_runtime::TransactionOutcome; use sp_std::result; pub trait Config: frame_support_test::Config {} @@ -67,13 +68,13 @@ fn storage_transaction_basic_commit() { assert_eq!(Value::get(), 0); assert!(!Map::contains_key("val0")); - with_transaction(|| { + assert_ok!(with_transaction(|| -> TransactionOutcome { Value::set(99); Map::insert("val0", 99); assert_eq!(Value::get(), 99); assert_eq!(Map::get("val0"), 99); - Commit(()) - }); + Commit(Ok(())) + })); assert_eq!(Value::get(), 99); assert_eq!(Map::get("val0"), 99); @@ -86,13 +87,26 @@ fn storage_transaction_basic_rollback() { assert_eq!(Value::get(), 0); assert_eq!(Map::get("val0"), 0); - with_transaction(|| { - Value::set(99); - Map::insert("val0", 99); - assert_eq!(Value::get(), 99); - assert_eq!(Map::get("val0"), 99); - Rollback(()) - }); + assert_noop!( + with_transaction(|| -> TransactionOutcome { + Value::set(99); + Map::insert("val0", 99); + assert_eq!(Value::get(), 99); + assert_eq!(Map::get("val0"), 99); + Rollback(Err("revert".into())) + }), + "revert" + ); + + assert_storage_noop!(assert_ok!(with_transaction( + || -> TransactionOutcome { + Value::set(99); + Map::insert("val0", 99); + assert_eq!(Value::get(), 99); + assert_eq!(Map::get("val0"), 99); + Rollback(Ok(())) + } + ))); assert_eq!(Value::get(), 0); assert_eq!(Map::get("val0"), 0); @@ -105,32 +119,35 @@ fn storage_transaction_rollback_then_commit() { Value::set(1); Map::insert("val1", 1); - with_transaction(|| { + assert_ok!(with_transaction(|| -> TransactionOutcome { Value::set(2); Map::insert("val1", 2); Map::insert("val2", 2); - with_transaction(|| { - Value::set(3); - Map::insert("val1", 3); - Map::insert("val2", 3); - Map::insert("val3", 3); + assert_noop!( + with_transaction(|| -> TransactionOutcome { + Value::set(3); + Map::insert("val1", 3); + Map::insert("val2", 3); + Map::insert("val3", 3); - assert_eq!(Value::get(), 3); - assert_eq!(Map::get("val1"), 3); - assert_eq!(Map::get("val2"), 3); - assert_eq!(Map::get("val3"), 3); + assert_eq!(Value::get(), 3); + assert_eq!(Map::get("val1"), 3); + assert_eq!(Map::get("val2"), 3); + assert_eq!(Map::get("val3"), 3); - Rollback(()) - }); + Rollback(Err("revert".into())) + }), + "revert" + ); assert_eq!(Value::get(), 2); assert_eq!(Map::get("val1"), 2); assert_eq!(Map::get("val2"), 2); assert_eq!(Map::get("val3"), 0); - Commit(()) - }); + Commit(Ok(())) + })); assert_eq!(Value::get(), 2); assert_eq!(Map::get("val1"), 2); @@ -145,32 +162,35 @@ fn storage_transaction_commit_then_rollback() { Value::set(1); Map::insert("val1", 1); - with_transaction(|| { - Value::set(2); - Map::insert("val1", 2); - Map::insert("val2", 2); + assert_noop!( + with_transaction(|| -> TransactionOutcome { + Value::set(2); + Map::insert("val1", 2); + Map::insert("val2", 2); + + assert_ok!(with_transaction(|| -> TransactionOutcome { + Value::set(3); + Map::insert("val1", 3); + Map::insert("val2", 3); + Map::insert("val3", 3); - with_transaction(|| { - Value::set(3); - Map::insert("val1", 3); - Map::insert("val2", 3); - Map::insert("val3", 3); + assert_eq!(Value::get(), 3); + assert_eq!(Map::get("val1"), 3); + assert_eq!(Map::get("val2"), 3); + assert_eq!(Map::get("val3"), 3); + + Commit(Ok(())) + })); assert_eq!(Value::get(), 3); assert_eq!(Map::get("val1"), 3); assert_eq!(Map::get("val2"), 3); assert_eq!(Map::get("val3"), 3); - Commit(()) - }); - - assert_eq!(Value::get(), 3); - assert_eq!(Map::get("val1"), 3); - assert_eq!(Map::get("val2"), 3); - assert_eq!(Map::get("val3"), 3); - - Rollback(()) - }); + Rollback(Err("revert".into())) + }), + "revert" + ); assert_eq!(Value::get(), 1); assert_eq!(Map::get("val1"), 1); diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 337fac5812aed..c09db5124cc1f 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -486,6 +486,31 @@ impl PartialEq for ModuleError { } } +/// Errors related to transactional storage layers. +#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum TransactionalError { + /// Too many transactional layers have been spawned. + LimitReached, + /// A transactional layer was expected, but does not exist. + NoLayer, +} + +impl From for &'static str { + fn from(e: TransactionalError) -> &'static str { + match e { + TransactionalError::LimitReached => "Too many transactional layers have been spawned", + TransactionalError::NoLayer => "A transactional layer was expected, but does not exist", + } + } +} + +impl From for DispatchError { + fn from(e: TransactionalError) -> DispatchError { + Self::Transactional(e) + } +} + /// Reason why a dispatch call failed. #[derive(Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo, PartialEq)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] @@ -512,6 +537,9 @@ pub enum DispatchError { Token(TokenError), /// An arithmetic error. Arithmetic(ArithmeticError), + /// The number of transactional layers has been reached, or we are not in a transactional + /// layer. + Transactional(TransactionalError), } /// Result of a `Dispatchable` which contains the `DispatchResult` and additional information about @@ -647,6 +675,7 @@ impl From for &'static str { DispatchError::TooManyConsumers => "Too many consumers", DispatchError::Token(e) => e.into(), DispatchError::Arithmetic(e) => e.into(), + DispatchError::Transactional(e) => e.into(), } } } @@ -685,6 +714,10 @@ impl traits::Printable for DispatchError { "Arithmetic error: ".print(); <&'static str>::from(*e).print(); }, + Self::Transactional(e) => { + "Transactional error: ".print(); + <&'static str>::from(*e).print(); + }, } } } From 284d38f9451b8fe52d780227ebb8d4776f2db017 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Apr 2022 19:34:13 +0000 Subject: [PATCH 0657/1472] Bump futures from 0.3.19 to 0.3.21 (#11133) Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.19 to 0.3.21. - [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.19...0.3.21) --- 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 | 220 +++++++++--------- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 4 +- bin/node/executor/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- client/api/Cargo.toml | 2 +- client/authority-discovery/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/informant/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- client/utils/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/consensus/common/Cargo.toml | 4 +- primitives/core/Cargo.toml | 2 +- primitives/inherents/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- test-utils/runtime/client/Cargo.toml | 2 +- .../runtime/transaction-pool/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- 46 files changed, 157 insertions(+), 157 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03a04cedcbf27..6fb6f5814565a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -483,7 +483,7 @@ version = "4.0.0-dev" dependencies = [ "beefy-primitives", "fnv", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "hex", "log 0.4.14", @@ -525,7 +525,7 @@ version = "4.0.0-dev" dependencies = [ "beefy-gadget", "beefy-primitives", - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -1312,7 +1312,7 @@ dependencies = [ "clap 2.34.0", "criterion-plot", "csv", - "futures 0.3.19", + "futures 0.3.21", "itertools", "lazy_static", "num-traits", @@ -1967,7 +1967,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", ] [[package]] @@ -2027,7 +2027,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9def033d8505edf199f6a5d07aa7e6d2d6185b164293b77f0efd108f4f3e11d" dependencies = [ "either", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "log 0.4.14", "num-traits", @@ -2480,9 +2480,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -2495,9 +2495,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -2505,15 +2505,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -2523,9 +2523,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-lite" @@ -2544,9 +2544,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ "proc-macro2", "quote", @@ -2566,15 +2566,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-timer" @@ -2584,9 +2584,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures 0.1.31", "futures-channel", @@ -3103,7 +3103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6d52908d4ea4ab2bc22474ba149bf1011c8e2c3ebc1ff593ae28ac44f494b6" dependencies = [ "async-io", - "futures 0.3.19", + "futures 0.3.21", "futures-lite", "if-addrs", "ipnet", @@ -3258,7 +3258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" dependencies = [ "derive_more", - "futures 0.3.19", + "futures 0.3.21", "hyper 0.14.16", "hyper-tls", "jsonrpc-core", @@ -3277,7 +3277,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "futures-executor", "futures-util", "log 0.4.14", @@ -3292,7 +3292,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-client-transports", ] @@ -3314,7 +3314,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "hyper 0.14.16", "jsonrpc-core", "jsonrpc-server-utils", @@ -3330,7 +3330,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "382bb0206323ca7cda3dcd7e245cea86d37d02457a02a975e3378fb149a48845" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-core", "jsonrpc-server-utils", "log 0.4.14", @@ -3345,7 +3345,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-core", "lazy_static", "log 0.4.14", @@ -3361,7 +3361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" dependencies = [ "bytes 1.1.0", - "futures 0.3.19", + "futures 0.3.21", "globset", "jsonrpc-core", "lazy_static", @@ -3378,7 +3378,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f892c7d766369475ab7b0669f417906302d7c0fb521285c0a0c92e52e7c8e946" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-core", "jsonrpc-server-utils", "log 0.4.14", @@ -3416,7 +3416,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3303cdf246e6ab76e2866fb3d9acb6c76a068b1b28bd923a1b7a8122257ad7b5" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "http", "jsonrpsee-core", "jsonrpsee-types 0.8.0", @@ -3519,7 +3519,7 @@ dependencies = [ "arrayvec 0.7.1", "async-trait", "fnv", - "futures 0.3.19", + "futures 0.3.21", "http", "jsonrpsee-types 0.4.1", "log 0.4.14", @@ -3718,7 +3718,7 @@ checksum = "3bec54343492ba5940a6c555e512c6721139835d28c59bc22febece72dfd0d9d" dependencies = [ "atomic", "bytes 1.1.0", - "futures 0.3.19", + "futures 0.3.21", "lazy_static", "libp2p-core", "libp2p-deflate", @@ -3762,7 +3762,7 @@ dependencies = [ "ed25519-dalek", "either", "fnv", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "lazy_static", "libsecp256k1", @@ -3792,7 +3792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51a800adb195f33de63f4b17b63fe64cfc23bf2c6a0d3d0d5321328664e65197" dependencies = [ "flate2", - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", ] @@ -3803,7 +3803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb8f89d15cb6e3c5bc22afff7513b11bab7856f2872d3cfba86f7f63a06bc498" dependencies = [ "async-std-resolver", - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "log 0.4.14", "smallvec 1.8.0", @@ -3818,7 +3818,7 @@ checksum = "aab3d7210901ea51b7bae2b581aa34521797af8c4ec738c980bda4a06434067f" dependencies = [ "cuckoofilter", "fnv", - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3839,7 +3839,7 @@ dependencies = [ "byteorder", "bytes 1.1.0", "fnv", - "futures 0.3.19", + "futures 0.3.21", "hex_fmt", "libp2p-core", "libp2p-swarm", @@ -3860,7 +3860,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cca1275574183f288ff8b72d535d5ffa5ea9292ef7829af8b47dcb197c7b0dcd" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3882,7 +3882,7 @@ dependencies = [ "bytes 1.1.0", "either", "fnv", - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3906,7 +3906,7 @@ dependencies = [ "async-io", "data-encoding", "dns-parser", - "futures 0.3.19", + "futures 0.3.21", "if-watch", "lazy_static", "libp2p-core", @@ -3940,7 +3940,7 @@ checksum = "7f2cd64ef597f40e14bfce0497f50ecb63dd6d201c61796daeb4227078834fbf" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "log 0.4.14", "nohash-hasher", @@ -3958,7 +3958,7 @@ checksum = "a8772c7a99088221bb7ca9c5c0574bf55046a7ab4c319f3619b275f28c8fb87a" dependencies = [ "bytes 1.1.0", "curve25519-dalek 3.0.2", - "futures 0.3.19", + "futures 0.3.21", "lazy_static", "libp2p-core", "log 0.4.14", @@ -3978,7 +3978,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80ef7b0ec5cf06530d9eb6cf59ae49d46a2c45663bde31c25a12f682664adbcf" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3995,7 +3995,7 @@ checksum = "5fba1a6ff33e4a274c89a3b1d78b9f34f32af13265cc5c46c16938262d4e945a" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "log 0.4.14", "prost", @@ -4010,7 +4010,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "log 0.4.14", "pin-project 1.0.10", "rand 0.7.3", @@ -4026,7 +4026,7 @@ checksum = "2852b61c90fa8ce3c8fcc2aba76e6cefc20d648f9df29157d6b3a916278ef3e3" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "libp2p-core", "libp2p-swarm", @@ -4049,7 +4049,7 @@ checksum = "14a6d2b9e7677eff61dc3d2854876aaf3976d84a01ef6664b610c77a0c9407c5" dependencies = [ "asynchronous-codec 0.6.0", "bimap", - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -4071,7 +4071,7 @@ checksum = "a877a4ced6d46bf84677e1974e8cf61fb434af73b2e96fb48d6cb6223a4634d8" dependencies = [ "async-trait", "bytes 1.1.0", - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -4089,7 +4089,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f5184a508f223bc100a12665517773fb8730e9f36fc09eefb670bf01b107ae9" dependencies = [ "either", - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "log 0.4.14", "rand 0.7.3", @@ -4115,7 +4115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7399c5b6361ef525d41c11fcf51635724f832baf5819b30d3d873eabb4fbae4b" dependencies = [ "async-io", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "if-watch", "ipnet", @@ -4132,7 +4132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8b7563e46218165dfd60f64b96f7ce84590d75f53ecbdc74a7dd01450dc5973" dependencies = [ "async-std", - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "log 0.4.14", ] @@ -4143,7 +4143,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1008a302b73c5020251f9708c653f5ed08368e530e247cc9cd2f109ff30042cf" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "js-sys", "libp2p-core", "parity-send-wrapper", @@ -4158,7 +4158,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e12df82d1ed64969371a9e65ea92b91064658604cc2576c2757f18ead9a1cf" dependencies = [ "either", - "futures 0.3.19", + "futures 0.3.21", "futures-rustls", "libp2p-core", "log 0.4.14", @@ -4175,7 +4175,7 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e7362abb8867d7187e7e93df17f460d554c997fc5c8ac57dc1259057f6889af" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "libp2p-core", "parking_lot 0.11.2", "thiserror", @@ -4696,7 +4696,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d91ec0a2440aaff5f78ec35631a7027d50386c6163aa975f7caa0d5da4b6ff8" dependencies = [ "bytes 1.1.0", - "futures 0.3.19", + "futures 0.3.21", "log 0.4.14", "pin-project 1.0.10", "smallvec 1.8.0", @@ -4800,7 +4800,7 @@ dependencies = [ "clap 3.1.6", "derive_more", "fs_extra", - "futures 0.3.19", + "futures 0.3.21", "hash-db", "hex", "kvdb", @@ -4842,7 +4842,7 @@ dependencies = [ "frame-benchmarking-cli", "frame-system", "frame-system-rpc-runtime-api", - "futures 0.3.19", + "futures 0.3.21", "hex-literal", "jsonrpsee-ws-client 0.4.1", "log 0.4.14", @@ -4921,7 +4921,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "futures 0.3.19", + "futures 0.3.21", "node-primitives", "node-runtime", "node-testing", @@ -5182,7 +5182,7 @@ version = "3.0.0-dev" dependencies = [ "frame-system", "fs_extra", - "futures 0.3.19", + "futures 0.3.21", "log 0.4.14", "node-executor", "node-primitives", @@ -6766,7 +6766,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "libc", "log 0.4.14", "rand 0.7.3", @@ -7975,7 +7975,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "pin-project 0.4.27", "static_assertions", ] @@ -8034,7 +8034,7 @@ name = "sc-authority-discovery" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "ip_network", "libp2p", @@ -8062,7 +8062,7 @@ dependencies = [ name = "sc-basic-authorship" version = "0.10.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "log 0.4.14", "parity-scale-codec", @@ -8132,7 +8132,7 @@ dependencies = [ "chrono", "clap 3.1.6", "fdlimit", - "futures 0.3.19", + "futures 0.3.21", "hex", "libp2p", "log 0.4.14", @@ -8168,7 +8168,7 @@ name = "sc-client-api" version = "4.0.0-dev" dependencies = [ "fnv", - "futures 0.3.19", + "futures 0.3.21", "hash-db", "log 0.4.14", "parity-scale-codec", @@ -8226,7 +8226,7 @@ name = "sc-consensus" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "libp2p", "log 0.4.14", @@ -8250,7 +8250,7 @@ name = "sc-consensus-aura" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.19", + "futures 0.3.21", "log 0.4.14", "parity-scale-codec", "parking_lot 0.12.0", @@ -8288,7 +8288,7 @@ version = "0.10.0-dev" dependencies = [ "async-trait", "fork-tree", - "futures 0.3.19", + "futures 0.3.21", "log 0.4.14", "merlin", "num-bigint", @@ -8336,7 +8336,7 @@ dependencies = [ name = "sc-consensus-babe-rpc" version = "0.10.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -8379,7 +8379,7 @@ version = "0.10.0-dev" dependencies = [ "assert_matches", "async-trait", - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -8417,7 +8417,7 @@ name = "sc-consensus-pow" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "log 0.4.14", "parity-scale-codec", @@ -8441,7 +8441,7 @@ name = "sc-consensus-slots" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "log 0.4.14", "parity-scale-codec", @@ -8573,7 +8573,7 @@ dependencies = [ "dyn-clone", "finality-grandpa", "fork-tree", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "hex", "log 0.4.14", @@ -8615,7 +8615,7 @@ name = "sc-finality-grandpa-rpc" version = "0.10.0-dev" dependencies = [ "finality-grandpa", - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -8642,7 +8642,7 @@ name = "sc-informant" version = "0.10.0-dev" dependencies = [ "ansi_term", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "log 0.4.14", "parity-util-mem", @@ -8682,7 +8682,7 @@ dependencies = [ "either", "fnv", "fork-tree", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "hex", "ip_network", @@ -8730,7 +8730,7 @@ version = "0.10.0-dev" dependencies = [ "ahash", "async-std", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "libp2p", "log 0.4.14", @@ -8749,7 +8749,7 @@ version = "0.8.0" dependencies = [ "async-std", "async-trait", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "libp2p", "log 0.4.14", @@ -8776,7 +8776,7 @@ version = "4.0.0-dev" dependencies = [ "bytes 1.1.0", "fnv", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "hex", "hyper 0.14.16", @@ -8810,7 +8810,7 @@ dependencies = [ name = "sc-peerset" version = "4.0.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "libp2p", "log 0.4.14", "rand 0.7.3", @@ -8832,7 +8832,7 @@ name = "sc-rpc" version = "4.0.0-dev" dependencies = [ "assert_matches", - "futures 0.3.19", + "futures 0.3.21", "hash-db", "jsonrpc-core", "jsonrpc-pubsub", @@ -8868,7 +8868,7 @@ dependencies = [ name = "sc-rpc-api" version = "0.10.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -8893,7 +8893,7 @@ dependencies = [ name = "sc-rpc-server" version = "4.0.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-core", "jsonrpc-http-server", "jsonrpc-ipc-server", @@ -8927,7 +8927,7 @@ dependencies = [ "async-trait", "directories", "exit-future", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "hash-db", "jsonrpc-core", @@ -8990,7 +8990,7 @@ name = "sc-service-test" version = "2.0.0" dependencies = [ "fdlimit", - "futures 0.3.19", + "futures 0.3.21", "hex", "hex-literal", "log 0.4.14", @@ -9059,7 +9059,7 @@ name = "sc-telemetry" version = "4.0.0-dev" dependencies = [ "chrono", - "futures 0.3.19", + "futures 0.3.21", "libp2p", "log 0.4.14", "parking_lot 0.12.0", @@ -9118,7 +9118,7 @@ version = "4.0.0-dev" dependencies = [ "assert_matches", "criterion", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "hex", "linked-hash-map", @@ -9150,7 +9150,7 @@ dependencies = [ name = "sc-transaction-pool-api" version = "4.0.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "log 0.4.14", "serde", "sp-blockchain", @@ -9162,7 +9162,7 @@ dependencies = [ name = "sc-utils" version = "4.0.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "lazy_static", "log 0.4.14", @@ -9639,7 +9639,7 @@ checksum = "b5c71ed3d54db0a699f4948e1bb3e45b450fa31fe602621dee6680361d569c88" dependencies = [ "base64 0.12.3", "bytes 0.5.6", - "futures 0.3.19", + "futures 0.3.21", "httparse", "log 0.4.14", "rand 0.7.3", @@ -9655,7 +9655,7 @@ dependencies = [ "base64 0.13.0", "bytes 1.1.0", "flate2", - "futures 0.3.19", + "futures 0.3.21", "httparse", "log 0.4.14", "rand 0.8.4", @@ -9695,7 +9695,7 @@ name = "sp-api-test" version = "2.0.1" dependencies = [ "criterion", - "futures 0.3.19", + "futures 0.3.21", "log 0.4.14", "parity-scale-codec", "rustversion", @@ -9800,7 +9800,7 @@ dependencies = [ name = "sp-blockchain" version = "4.0.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "log 0.4.14", "lru 0.7.3", "parity-scale-codec", @@ -9818,7 +9818,7 @@ name = "sp-consensus" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.19", + "futures 0.3.21", "futures-timer", "log 0.4.14", "parity-scale-codec", @@ -9917,7 +9917,7 @@ dependencies = [ "criterion", "dyn-clonable", "ed25519-dalek", - "futures 0.3.19", + "futures 0.3.21", "hash-db", "hash256-std-hasher", "hex", @@ -10028,7 +10028,7 @@ name = "sp-inherents" version = "4.0.0-dev" dependencies = [ "async-trait", - "futures 0.3.19", + "futures 0.3.21", "impl-trait-for-tuples", "parity-scale-codec", "sp-core", @@ -10041,7 +10041,7 @@ dependencies = [ name = "sp-io" version = "6.0.0" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "hash-db", "libsecp256k1", "log 0.4.14", @@ -10076,7 +10076,7 @@ name = "sp-keystore" version = "0.12.0" dependencies = [ "async-trait", - "futures 0.3.19", + "futures 0.3.21", "merlin", "parity-scale-codec", "parking_lot 0.12.0", @@ -10599,7 +10599,7 @@ version = "3.0.0" dependencies = [ "frame-support", "frame-system", - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-client-transports", "parity-scale-codec", "sc-rpc-api", @@ -10614,7 +10614,7 @@ name = "substrate-frame-rpc-system" version = "4.0.0-dev" dependencies = [ "frame-system-rpc-runtime-api", - "futures 0.3.19", + "futures 0.3.21", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -10673,7 +10673,7 @@ name = "substrate-test-client" version = "2.0.1" dependencies = [ "async-trait", - "futures 0.3.19", + "futures 0.3.21", "hex", "parity-scale-codec", "sc-client-api", @@ -10702,7 +10702,7 @@ dependencies = [ "frame-support", "frame-system", "frame-system-rpc-runtime-api", - "futures 0.3.19", + "futures 0.3.21", "log 0.4.14", "memory-db", "pallet-babe", @@ -10744,7 +10744,7 @@ dependencies = [ name = "substrate-test-runtime-client" version = "2.0.0" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "parity-scale-codec", "sc-block-builder", "sc-client-api", @@ -10762,7 +10762,7 @@ dependencies = [ name = "substrate-test-runtime-transaction-pool" version = "2.0.0" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "parity-scale-codec", "parking_lot 0.12.0", "sc-transaction-pool", @@ -10777,7 +10777,7 @@ dependencies = [ name = "substrate-test-utils" version = "4.0.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "sc-service", "substrate-test-utils-derive", "tokio", @@ -11809,7 +11809,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "js-sys", "parking_lot 0.11.2", "pin-utils", @@ -12465,7 +12465,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7d9028f208dd5e63c614be69f115c1b53cacc1111437d4c765185856666c107" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "log 0.4.14", "nohash-hasher", "parking_lot 0.11.2", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 7bdf46e2b6600..45a959ac16b14 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -39,4 +39,4 @@ parity-util-mem = { version = "0.11.0", default-features = false, features = ["p parity-db = { version = "0.3" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } -futures = { version = "0.3.19", features = ["thread-pool"] } +futures = { version = "0.3.21", features = ["thread-pool"] } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index a1aa695bf3a15..d25c1b1f0bf81 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -37,7 +37,7 @@ crate-type = ["cdylib", "rlib"] clap = { version = "3.1.6", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } -futures = "0.3.19" +futures = "0.3.21" hex-literal = "0.3.4" log = "0.4.8" rand = "0.8" @@ -116,7 +116,7 @@ sc-service-test = { version = "2.0.0", path = "../../../client/service/test" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -futures = "0.3.19" +futures = "0.3.21" tempfile = "3.1.0" assert_cmd = "2.0.2" nix = "0.23" diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 21862ecf81b5d..3425a0df65d9b 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -40,7 +40,7 @@ sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } wat = "1.0" -futures = "0.3.19" +futures = "0.3.21" [features] wasmtime = ["sc-executor/wasmtime"] diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 36a25ab7d4a7a..02d13f0c64718 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -48,4 +48,4 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" log = "0.4.8" tempfile = "3.1.0" fs_extra = "1" -futures = "0.3.19" +futures = "0.3.21" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index 3d1802c379f04..d209a311f45b9 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -21,7 +21,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/comm sc-executor = { version = "0.10.0-dev", path = "../executor" } sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } fnv = "1.0.6" -futures = "0.3.19" +futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } log = "0.4.8" diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index d866bafb29dcf..ba432d073698a 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -20,7 +20,7 @@ prost-build = "0.9" async-trait = "0.1" codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0" } thiserror = "1.0" -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" libp2p = { version = "0.40.0", default-features = false, features = ["kad"] } diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 4fd140835525e..20560d4c834e7 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.8" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index ebbb9527f9367..47f2558c5ee71 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/paritytech/substrate" description = "RPC for the BEEFY Client gadget for substrate" [dependencies] -futures = "0.3.19" +futures = "0.3.21" log = "0.4" parking_lot = "0.12.0" thiserror = "1.0" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 7725e25c0b815..1fabbca46968e 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] chrono = "0.4.10" clap = { version = "3.1.6", features = ["derive"] } fdlimit = "0.2.1" -futures = "0.3.19" +futures = "0.3.21" hex = "0.4.2" libp2p = "0.40.0" log = "0.4.11" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 2ad61f2bc48d9..ac90d35dbce3c 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -23,7 +23,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } thiserror = "1.0" -futures = "0.3.19" +futures = "0.3.21" sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } log = "0.4.8" sp-core = { version = "6.0.0", path = "../../../primitives/core" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index a135807d707e0..20cc359849f52 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -43,7 +43,7 @@ sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } -futures = "0.3.19" +futures = "0.3.21" parking_lot = "0.12.0" log = "0.4.8" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index ee6549480a6d2..cce4544f09705 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -23,7 +23,7 @@ serde = { version = "1.0.136", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } -futures = "0.3.19" +futures = "0.3.21" thiserror = "1.0" sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 3c640a2363b6a..4bd5cff457f5c 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] thiserror = "1.0.30" libp2p = { version = "0.40.0", default-features = false } log = "0.4.8" -futures = { version = "0.3.19", features = ["thread-pool"] } +futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 62650d50ce4ac..360cfe862f875 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] thiserror = "1.0" -futures = "0.3.19" +futures = "0.3.21" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 553ef60e8145c..4ddbf0c0ead7f 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -25,7 +25,7 @@ sp-consensus-pow = { version = "0.10.0-dev", path = "../../../primitives/consens sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } log = "0.4.8" -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.1" parking_lot = "0.12.0" thiserror = "1.0" diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 07e0c291f4a37..2884f8443e30e 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -27,7 +27,7 @@ sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.11" thiserror = "1.0.30" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index b8b41ba703655..58dc22192c0c1 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] thiserror = "1.0" dyn-clone = "1.0" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.1" hex = "0.4.2" log = "0.4.8" diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index dba0555c68969..e58763a4ebcc9 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.8" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index c8410d6d18783..51f5b658402ef 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.1" libp2p = { version = "0.40.0", default-features = false } log = "0.4.8" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index cd33830c1efe0..be69663b9a544 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -27,7 +27,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ either = "1.5.3" fnv = "1.0.6" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.2" asynchronous-codec = "0.5" hex = "0.4.0" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index be15cbc807e22..b9505f97d14c0 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -17,7 +17,7 @@ async-std = "1.10.0" sc-network = { version = "0.10.0-dev", path = "../" } log = "0.4.8" parking_lot = "0.12.0" -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.1" rand = "0.7.2" libp2p = { version = "0.40.0", default-features = false } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 3edba1f45704a..6cb1f83e360be 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -17,7 +17,7 @@ bytes = "1.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } hex = "0.4" fnv = "1.0.6" -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.2" num_cpus = "1.13" parking_lot = "0.12.0" diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index 12991eac81bdc..b292f300ba353 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.19" +futures = "0.3.21" libp2p = { version = "0.40.0", default-features = false } sc-utils = { version = "4.0.0-dev", path = "../utils"} log = "0.4.8" diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 06deb0eef0ce3..20a18ec6c61cc 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.19" +futures = "0.3.21" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index 6b2c9f5aa3738..c5af4ba200fe0 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.19" +futures = "0.3.21" jsonrpc-core = "18.0.0" pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } log = "0.4.8" diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index eeeb67f362617..4fea6501f693d 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -17,7 +17,7 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.19" +futures = "0.3.21" jsonrpc-pubsub = "18.0.0" log = "0.4.8" sp-core = { version = "6.0.0", path = "../../primitives/core" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 2cb23fed40f22..47474217ebd2a 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -23,7 +23,7 @@ test-helpers = [] [dependencies] thiserror = "1.0.30" -futures = "0.3.19" +futures = "0.3.21" jsonrpc-pubsub = "18.0" jsonrpc-core = "18.0" rand = "0.7.3" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index fa3c49a2340ad..ab92de4e84f8b 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -26,7 +26,7 @@ sp-externalities = { version = "0.12.0", path = "../../../primitives/externaliti sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../../db" } -futures = "0.3.19" +futures = "0.3.21" sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../../service" } sc-network = { version = "0.10.0-dev", path = "../../network" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 6daa75f453629..67583e325f34c 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] parking_lot = "0.12.0" -futures = "0.3.19" +futures = "0.3.21" wasm-timer = "0.2.5" libp2p = { version = "0.40.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.8" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 4c9a341db6a22..df309760b847b 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } thiserror = "1.0.30" -futures = "0.3.19" +futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.8" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index b444be6c6e788..8dd5e7253f965 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/paritytech/substrate/" description = "Transaction pool client facing API." [dependencies] -futures = "0.3.19" +futures = "0.3.21" log = "0.4.8" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index a107aab1dbd6a..2f1338577e375 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -10,7 +10,7 @@ description = "I/O for Substrate runtimes" readme = "README.md" [dependencies] -futures = "0.3.19" +futures = "0.3.21" lazy_static = "1.4.0" parking_lot = "0.12.0" prometheus = { version = "0.13.0", default-features = false } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 786639f393e92..9f9f399234db4 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -26,7 +26,7 @@ rustversion = "1.0.6" [dev-dependencies] criterion = "0.3.0" -futures = "0.3.19" +futures = "0.3.21" log = "0.4.14" sp-core = { version = "6.0.0", path = "../../core" } diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 4c9946b7a3127..a79bc9c5591cf 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -18,7 +18,7 @@ log = "0.4.11" lru = "0.7.3" parking_lot = "0.12.0" thiserror = "1.0.30" -futures = "0.3.19" +futures = "0.3.21" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sp-runtime = { version = "6.0.0", path = "../runtime" } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index c712eff28500e..35bd7f33fbf47 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -18,7 +18,7 @@ async-trait = "0.1.42" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } -futures = { version = "0.3.19", features = ["thread-pool"] } +futures = { version = "0.3.21", features = ["thread-pool"] } log = "0.4.8" sp-core = { path = "../../core", version = "6.0.0"} sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } @@ -30,7 +30,7 @@ sp-runtime = { version = "6.0.0", path = "../../runtime" } thiserror = "1.0.30" [dev-dependencies] -futures = "0.3.19" +futures = "0.3.21" sp-test-primitives = { version = "2.0.0", path = "../../test-primitives" } [features] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 413a11c9dc0a4..74a159b2e7d39 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -41,7 +41,7 @@ sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debu sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } -futures = { version = "0.3.19", optional = true } +futures = { version = "0.3.21", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.30", optional = true } bitflags = "1.3" diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index a90fb67e2385a..f7beb7bdfcf54 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -24,7 +24,7 @@ impl-trait-for-tuples = "0.2.0" async-trait = { version = "0.1.50", optional = true } [dev-dependencies] -futures = "0.3.19" +futures = "0.3.21" [features] default = [ "std" ] diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index c51e34b861b9b..bdae6174a87cb 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -28,7 +28,7 @@ sp-trie = { version = "6.0.0", optional = true, path = "../trie" } sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.8", optional = true } -futures = { version = "0.3.19", features = ["thread-pool"], optional = true } +futures = { version = "0.3.21", features = ["thread-pool"], optional = true } parking_lot = { version = "0.12.0", optional = true } secp256k1 = { version = "0.21.2", features = ["recovery", "global-context"], optional = true } tracing = { version = "0.1.29", default-features = false } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 7b1d1dd4ebc4b..f201cb8518bc6 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" -futures = "0.3.19" +futures = "0.3.21" parking_lot = { version = "0.12.0", default-features = false } serde = { version = "1.0", optional = true } thiserror = "1.0" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 1f7115cf16cf8..f99300f27eacb 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.19" +futures = "0.3.21" hex = "0.4" serde = "1.0.136" serde_json = "1.0.79" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index ad7dca5e08fb1..cbefed27ca9bd 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -56,7 +56,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../client/block-builder" sc-executor = { version = "0.10.0-dev", path = "../../client/executor" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime-client = { version = "2.0.0", path = "./client" } -futures = "0.3.19" +futures = "0.3.21" [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../utils/wasm-builder" } diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index 642d754868f7d..a22d9f302a9e9 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -23,4 +23,4 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } codec = { package = "parity-scale-codec", version = "3.0.0" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } -futures = "0.3.19" +futures = "0.3.21" diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index 8bc75c9d4c053..59d576acdcb8f 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -19,5 +19,5 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } -futures = "0.3.19" +futures = "0.3.21" thiserror = "1.0" diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 91ec47e34bd37..fe304370727f0 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -15,7 +15,7 @@ description = "Substrate RPC for FRAME's support" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.19" +futures = "0.3.21" jsonrpc-client-transports = { version = "18.0.0", features = ["http"] } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = "1" diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 1015760efee6f..31a6f93e847b1 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.19" +futures = "0.3.21" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" From 01a3ad65d933cc58e79c04d114edb4d6c69b470a Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Mon, 4 Apr 2022 03:44:29 +0800 Subject: [PATCH 0658/1472] Remove useless imports (#11136) Because `TryInto`/`TryFrom` are in prelude by default from edition 2021 Signed-off-by: koushiro --- bin/node/cli/src/service.rs | 2 +- bin/node/cli/tests/common.rs | 1 - bin/node/cli/tests/running_the_node_and_interrupt.rs | 5 +---- bin/node/cli/tests/telemetry.rs | 2 +- bin/node/cli/tests/temp_base_path_works.rs | 1 - client/allocator/src/freeing_bump.rs | 1 - client/api/src/client.rs | 2 +- client/authority-discovery/src/worker.rs | 10 +++------- client/beefy/src/keystore.rs | 2 -- client/cli/src/commands/insert_key.rs | 2 +- client/cli/src/commands/utils.rs | 2 +- client/cli/src/commands/verify.rs | 2 +- client/cli/src/error.rs | 6 +++--- client/cli/src/params/mod.rs | 2 +- client/consensus/aura/src/lib.rs | 11 ++--------- client/consensus/babe/src/lib.rs | 3 +-- client/consensus/manual-seal/src/error.rs | 2 +- client/consensus/pow/src/lib.rs | 4 ++-- client/db/src/utils.rs | 2 +- client/executor/common/src/sandbox/wasmer_backend.rs | 2 +- client/finality-grandpa/rpc/src/lib.rs | 2 +- client/informant/src/display.rs | 6 +----- client/network-gossip/src/bridge.rs | 1 - client/network/src/config.rs | 1 - client/network/src/protocol.rs | 1 - .../protocol/notifications/upgrade/notifications.rs | 2 +- client/network/src/request_responses.rs | 1 - client/network/src/service.rs | 1 - client/network/src/service/out_events.rs | 1 - client/offchain/src/api.rs | 7 ++----- client/offchain/src/api/http.rs | 1 - client/offchain/src/api/timestamp.rs | 5 +---- client/rpc/src/author/mod.rs | 2 +- client/service/src/chain_ops/import_blocks.rs | 1 - client/service/src/config.rs | 2 +- client/service/src/metrics.rs | 2 +- client/transaction-pool/src/lib.rs | 1 - client/transaction-pool/tests/pool.rs | 4 +--- frame/assets/src/lib.rs | 2 +- frame/bags-list/fuzzer/src/main.rs | 1 - frame/bags-list/remote-tests/src/sanity_check.rs | 1 - frame/contracts/src/tests.rs | 1 - frame/conviction-voting/src/vote.rs | 2 +- frame/election-provider-support/src/mock.rs | 1 - frame/election-provider-support/src/tests.rs | 3 +-- frame/election-provider-support/src/traits.rs | 8 ++------ frame/im-online/src/lib.rs | 2 +- frame/preimage/src/lib.rs | 2 +- frame/proxy/src/lib.rs | 2 +- frame/randomness-collective-flip/src/lib.rs | 1 - frame/staking/reward-curve/src/lib.rs | 1 - frame/staking/src/lib.rs | 2 +- frame/staking/src/pallet/mod.rs | 2 +- .../procedural/src/construct_runtime/expand/event.rs | 2 +- .../procedural/src/construct_runtime/expand/origin.rs | 4 ++-- frame/support/procedural/src/pallet/expand/error.rs | 2 +- frame/support/src/error.rs | 2 +- frame/support/src/lib.rs | 2 -- frame/support/src/storage/bounded_btree_map.rs | 5 +---- frame/support/src/storage/bounded_btree_set.rs | 6 +----- frame/support/src/storage/weak_bounded_vec.rs | 3 +-- frame/uniques/src/benchmarking.rs | 2 +- frame/vesting/src/lib.rs | 2 +- primitives/application-crypto/src/lib.rs | 8 ++++---- primitives/arithmetic/fuzzer/src/biguint.rs | 1 - primitives/arithmetic/fuzzer/src/normalize.rs | 1 - primitives/arithmetic/src/biguint.rs | 3 +-- primitives/arithmetic/src/fixed_point.rs | 1 - primitives/arithmetic/src/helpers_128bit.rs | 1 - primitives/arithmetic/src/lib.rs | 2 +- primitives/arithmetic/src/per_things.rs | 1 - primitives/arithmetic/src/traits.rs | 8 ++------ primitives/consensus/common/src/error.rs | 4 ++-- primitives/consensus/vrf/src/schnorrkel.rs | 1 - primitives/core/src/crypto.rs | 4 ++-- primitives/core/src/ecdsa.rs | 4 ++-- primitives/core/src/ed25519.rs | 6 ++---- primitives/core/src/offchain/mod.rs | 5 +---- primitives/core/src/sr25519.rs | 6 ++---- primitives/rpc/src/number.rs | 5 +---- .../runtime-interface/proc-macro/src/pass_by/enum_.rs | 2 +- primitives/runtime-interface/src/pass_by.rs | 4 ++-- primitives/runtime-interface/test-wasm/src/lib.rs | 2 +- primitives/runtime/src/curve.rs | 4 ---- primitives/runtime/src/generic/header.rs | 2 +- primitives/runtime/src/lib.rs | 2 +- primitives/runtime/src/traits.rs | 8 +------- primitives/std/src/lib.rs | 1 - primitives/storage/src/lib.rs | 2 +- primitives/wasm-interface/src/lib.rs | 2 +- utils/prometheus/src/lib.rs | 1 - 91 files changed, 81 insertions(+), 176 deletions(-) diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 038c14029cf31..03e7311fb3c01 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -562,7 +562,7 @@ mod tests { RuntimeAppPublic, }; use sp_timestamp; - use std::{borrow::Cow, convert::TryInto, sync::Arc}; + use std::{borrow::Cow, sync::Arc}; type AccountPublic = ::Signer; diff --git a/bin/node/cli/tests/common.rs b/bin/node/cli/tests/common.rs index 8391cff355969..c17cabfa1d38a 100644 --- a/bin/node/cli/tests/common.rs +++ b/bin/node/cli/tests/common.rs @@ -26,7 +26,6 @@ use nix::{ use node_primitives::Block; use remote_externalities::rpc_api; use std::{ - convert::TryInto, ops::{Deref, DerefMut}, path::Path, process::{Child, Command, ExitStatus}, diff --git a/bin/node/cli/tests/running_the_node_and_interrupt.rs b/bin/node/cli/tests/running_the_node_and_interrupt.rs index edce2bbc6e4c5..703123faf0e62 100644 --- a/bin/node/cli/tests/running_the_node_and_interrupt.rs +++ b/bin/node/cli/tests/running_the_node_and_interrupt.rs @@ -25,10 +25,7 @@ use nix::{ }, unistd::Pid, }; -use std::{ - convert::TryInto, - process::{Child, Command}, -}; +use std::process::{Child, Command}; use tempfile::tempdir; pub mod common; diff --git a/bin/node/cli/tests/telemetry.rs b/bin/node/cli/tests/telemetry.rs index 212fec7a02cf6..64da4bd4b68f1 100644 --- a/bin/node/cli/tests/telemetry.rs +++ b/bin/node/cli/tests/telemetry.rs @@ -21,7 +21,7 @@ use nix::{ sys::signal::{kill, Signal::SIGINT}, unistd::Pid, }; -use std::{convert::TryInto, process}; +use std::process; pub mod common; pub mod websocket_server; diff --git a/bin/node/cli/tests/temp_base_path_works.rs b/bin/node/cli/tests/temp_base_path_works.rs index a5b9b7499fc49..306c490c2f760 100644 --- a/bin/node/cli/tests/temp_base_path_works.rs +++ b/bin/node/cli/tests/temp_base_path_works.rs @@ -25,7 +25,6 @@ use nix::{ }; use regex::Regex; use std::{ - convert::TryInto, io::Read, path::PathBuf, process::{Command, Stdio}, diff --git a/client/allocator/src/freeing_bump.rs b/client/allocator/src/freeing_bump.rs index d7152f5a209ea..7eeda45370b87 100644 --- a/client/allocator/src/freeing_bump.rs +++ b/client/allocator/src/freeing_bump.rs @@ -71,7 +71,6 @@ use crate::Error; pub use sp_core::MAX_POSSIBLE_ALLOCATION; use sp_wasm_interface::{Pointer, WordSize}; use std::{ - convert::{TryFrom, TryInto}, mem, ops::{Index, IndexMut, Range}, }; diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 11195e1def28c..9c55be3238130 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -25,7 +25,7 @@ use sp_runtime::{ traits::{Block as BlockT, NumberFor}, Justifications, }; -use std::{collections::HashSet, convert::TryFrom, fmt, sync::Arc}; +use std::{collections::HashSet, fmt, sync::Arc}; use crate::{blockchain::Info, notifications::StorageEventStream, FinalizeSummary, ImportSummary}; diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index 019abaac3cfcb..726c032281cd8 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -24,7 +24,6 @@ use crate::{ use std::{ collections::{HashMap, HashSet}, - convert::TryInto, marker::PhantomData, sync::Arc, time::Duration, @@ -581,14 +580,11 @@ where .authorities(&id) .map_err(|e| Error::CallingRuntime(e.into()))? .into_iter() - .map(std::convert::Into::into) + .map(Into::into) .collect::>(); - let intersection = local_pub_keys - .intersection(&authorities) - .cloned() - .map(std::convert::Into::into) - .collect(); + let intersection = + local_pub_keys.intersection(&authorities).cloned().map(Into::into).collect(); Ok(intersection) } diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index 32478a11434fa..b0259a42075ea 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -16,8 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::convert::{From, TryInto}; - use sp_application_crypto::RuntimeAppPublic; use sp_core::keccak_256; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index 852b4e50376ff..68201d7b4bffc 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -25,7 +25,7 @@ use sc_keystore::LocalKeystore; use sc_service::config::{BasePath, KeystoreConfig}; use sp_core::crypto::{KeyTypeId, SecretString}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; -use std::{convert::TryFrom, sync::Arc}; +use std::sync::Arc; /// The `insert` command #[derive(Debug, Clone, Parser)] diff --git a/client/cli/src/commands/utils.rs b/client/cli/src/commands/utils.rs index d20df01e5a90e..fa776c25a2eda 100644 --- a/client/cli/src/commands/utils.rs +++ b/client/cli/src/commands/utils.rs @@ -31,7 +31,7 @@ use sp_core::{ Pair, }; use sp_runtime::{traits::IdentifyAccount, MultiSigner}; -use std::{convert::TryFrom, io::Read, path::PathBuf}; +use std::{io::Read, path::PathBuf}; /// Public key type for Runtime pub type PublicFor

=

::Public; diff --git a/client/cli/src/commands/verify.rs b/client/cli/src/commands/verify.rs index a8879f42caafc..b004a948a7a48 100644 --- a/client/cli/src/commands/verify.rs +++ b/client/cli/src/commands/verify.rs @@ -66,7 +66,7 @@ impl VerifyCmd { fn verify(sig_data: Vec, message: Vec, uri: &str) -> error::Result<()> where Pair: sp_core::Pair, - Pair::Signature: for<'a> std::convert::TryFrom<&'a [u8]>, + Pair::Signature: for<'a> TryFrom<&'a [u8]>, { let signature = Pair::Signature::try_from(&sig_data).map_err(|_| error::Error::SignatureFormatInvalid)?; diff --git a/client/cli/src/error.rs b/client/cli/src/error.rs index 69b2eeaaf6186..f38a95e0115f1 100644 --- a/client/cli/src/error.rs +++ b/client/cli/src/error.rs @@ -80,19 +80,19 @@ pub enum Error { GlobalLoggerError(#[from] sc_tracing::logging::Error), } -impl std::convert::From<&str> for Error { +impl From<&str> for Error { fn from(s: &str) -> Error { Error::Input(s.to_string()) } } -impl std::convert::From for Error { +impl From for Error { fn from(s: String) -> Error { Error::Input(s) } } -impl std::convert::From for Error { +impl From for Error { fn from(e: crypto::PublicError) -> Error { Error::InvalidUri(e) } diff --git a/client/cli/src/params/mod.rs b/client/cli/src/params/mod.rs index e0571aa4bbbf8..33e714ec138b0 100644 --- a/client/cli/src/params/mod.rs +++ b/client/cli/src/params/mod.rs @@ -32,7 +32,7 @@ use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor}, }; -use std::{convert::TryFrom, fmt::Debug, str::FromStr}; +use std::{fmt::Debug, str::FromStr}; pub use crate::params::{ database_params::*, import_params::*, keystore_params::*, network_params::*, diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 4d91eaaae92ab..f6ea2e08e1e88 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -30,14 +30,7 @@ //! //! NOTE: Aura itself is designed to be generic over the crypto used. #![forbid(missing_docs, unsafe_code)] -use std::{ - convert::{TryFrom, TryInto}, - fmt::Debug, - hash::Hash, - marker::PhantomData, - pin::Pin, - sync::Arc, -}; +use std::{fmt::Debug, hash::Hash, marker::PhantomData, pin::Pin, sync::Arc}; use futures::prelude::*; use log::{debug, trace}; @@ -517,7 +510,7 @@ pub enum Error { Inherent(sp_inherents::Error), } -impl std::convert::From> for String { +impl From> for String { fn from(error: Error) -> String { error.to_string() } diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 4f3139a013d4b..818384a5c3d7e 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -69,7 +69,6 @@ use std::{ borrow::Cow, collections::{HashMap, HashSet}, - convert::TryInto, future::Future, pin::Pin, sync::Arc, @@ -320,7 +319,7 @@ pub enum Error { ForkTree(Box>), } -impl std::convert::From> for String { +impl From> for String { fn from(error: Error) -> String { error.to_string() } diff --git a/client/consensus/manual-seal/src/error.rs b/client/consensus/manual-seal/src/error.rs index 2f946f3de3ccc..7c3211203bf54 100644 --- a/client/consensus/manual-seal/src/error.rs +++ b/client/consensus/manual-seal/src/error.rs @@ -102,7 +102,7 @@ impl Error { } } -impl std::convert::From for jsonrpc_core::Error { +impl From for jsonrpc_core::Error { fn from(error: Error) -> Self { jsonrpc_core::Error { code: jsonrpc_core::ErrorCode::ServerError(error.to_code()), diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 6d0bc3fc5a192..8885099ceb514 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -119,13 +119,13 @@ pub enum Error { Other(String), } -impl std::convert::From> for String { +impl From> for String { fn from(error: Error) -> String { error.to_string() } } -impl std::convert::From> for ConsensusError { +impl From> for ConsensusError { fn from(error: Error) -> ConsensusError { ConsensusError::ClientImport(error.to_string()) } diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index 29aa8424221a6..1798838ecc155 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -19,7 +19,7 @@ //! Db-based backend utility structures and functions, used by both //! full and light storages. -use std::{convert::TryInto, fmt, fs, io, path::Path, sync::Arc}; +use std::{fmt, fs, io, path::Path, sync::Arc}; use log::{debug, info}; diff --git a/client/executor/common/src/sandbox/wasmer_backend.rs b/client/executor/common/src/sandbox/wasmer_backend.rs index dfb26c4a8dedb..904afc9470400 100644 --- a/client/executor/common/src/sandbox/wasmer_backend.rs +++ b/client/executor/common/src/sandbox/wasmer_backend.rs @@ -26,7 +26,7 @@ use crate::{ use codec::{Decode, Encode}; use sp_core::sandbox::HostError; use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; -use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; +use std::{cell::RefCell, collections::HashMap, rc::Rc}; use wasmer::RuntimeError; use crate::sandbox::{ diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index bde2e5612b2e6..9c51bc3d226a7 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -171,7 +171,7 @@ where mod tests { use super::*; use jsonrpc_core::{types::Params, Notification, Output}; - use std::{collections::HashSet, convert::TryInto, sync::Arc}; + use std::{collections::HashSet, sync::Arc}; use parity_scale_codec::{Decode, Encode}; use sc_block_builder::{BlockBuilder, RecordProof}; diff --git a/client/informant/src/display.rs b/client/informant/src/display.rs index 8d76939fddd6f..77b28dec55651 100644 --- a/client/informant/src/display.rs +++ b/client/informant/src/display.rs @@ -22,11 +22,7 @@ use log::info; use sc_client_api::ClientInfo; use sc_network::{NetworkStatus, SyncState, WarpSyncPhase, WarpSyncProgress}; use sp_runtime::traits::{Block as BlockT, CheckedDiv, NumberFor, Saturating, Zero}; -use std::{ - convert::{TryFrom, TryInto}, - fmt, - time::Instant, -}; +use std::{fmt, time::Instant}; /// State of the informant display system. /// diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index f72cd15616515..2e09e7cc614a4 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -303,7 +303,6 @@ mod tests { use sp_runtime::{testing::H256, traits::Block as BlockT}; use std::{ borrow::Cow, - convert::TryInto, sync::{Arc, Mutex}, }; use substrate_test_runtime_client::runtime::Block; diff --git a/client/network/src/config.rs b/client/network/src/config.rs index eedf3fc22b961..7c2dfef7fe89c 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -50,7 +50,6 @@ use sp_runtime::traits::Block as BlockT; use std::{ borrow::Cow, collections::HashMap, - convert::TryFrom, error::Error, fs, future::Future, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index c00d4302f827c..80694210e77dc 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -60,7 +60,6 @@ use sp_runtime::{ use std::{ borrow::Cow, collections::{HashMap, HashSet, VecDeque}, - convert::TryFrom as _, io, iter, num::NonZeroUsize, pin::Pin, diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 53270975a5b0d..3fbb59d399a0e 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -41,7 +41,7 @@ use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use log::{error, warn}; use std::{ borrow::Cow, - convert::{Infallible, TryFrom as _}, + convert::Infallible, io, mem, pin::Pin, task::{Context, Poll}, diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 58007c7bc5ce1..4613a15af9366 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -56,7 +56,6 @@ use libp2p::{ use std::{ borrow::Cow, collections::{hash_map::Entry, HashMap}, - convert::TryFrom as _, io, iter, pin::Pin, task::{Context, Poll}, diff --git a/client/network/src/service.rs b/client/network/src/service.rs index a02aa982318a9..e89be325fa486 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -73,7 +73,6 @@ use std::{ borrow::Cow, cmp, collections::{HashMap, HashSet}, - convert::TryFrom as _, fs, iter, marker::PhantomData, num::NonZeroUsize, diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 1fe13bc30faff..3bff5a16fd0c2 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -38,7 +38,6 @@ use parking_lot::Mutex; use prometheus_endpoint::{register, CounterVec, GaugeVec, Opts, PrometheusError, Registry, U64}; use std::{ cell::RefCell, - convert::TryFrom as _, fmt, pin::Pin, sync::Arc, diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 30c7969279ee2..c80b511c84d17 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{collections::HashSet, convert::TryFrom, str::FromStr, sync::Arc, thread::sleep}; +use std::{collections::HashSet, str::FromStr, sync::Arc, thread::sleep}; use crate::NetworkProvider; use codec::{Decode, Encode}; @@ -327,10 +327,7 @@ mod tests { use sc_client_db::offchain::LocalStorage; use sc_network::{NetworkStateInfo, PeerId}; use sp_core::offchain::{DbExternalities, Externalities}; - use std::{ - convert::{TryFrom, TryInto}, - time::SystemTime, - }; + use std::time::SystemTime; pub(super) struct TestNetwork(); diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index 2a7514116cb5d..012de78c5f645 100644 --- a/client/offchain/src/api/http.rs +++ b/client/offchain/src/api/http.rs @@ -37,7 +37,6 @@ use once_cell::sync::Lazy; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_core::offchain::{HttpError, HttpRequestId, HttpRequestStatus, Timestamp}; use std::{ - convert::TryFrom, fmt, io::Read as _, pin::Pin, diff --git a/client/offchain/src/api/timestamp.rs b/client/offchain/src/api/timestamp.rs index 6622331f570df..4b3f5efddf275 100644 --- a/client/offchain/src/api/timestamp.rs +++ b/client/offchain/src/api/timestamp.rs @@ -19,10 +19,7 @@ //! Helper methods dedicated to timestamps. use sp_core::offchain::Timestamp; -use std::{ - convert::TryInto, - time::{Duration, SystemTime}, -}; +use std::time::{Duration, SystemTime}; /// Returns the current time as a `Timestamp`. pub fn now() -> Timestamp { diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 2b604d2897c58..5064e61342101 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -21,7 +21,7 @@ #[cfg(test)] mod tests; -use std::{convert::TryInto, sync::Arc}; +use std::sync::Arc; use sp_blockchain::HeaderBackend; diff --git a/client/service/src/chain_ops/import_blocks.rs b/client/service/src/chain_ops/import_blocks.rs index dc03cdcedae06..c0612124dd0c2 100644 --- a/client/service/src/chain_ops/import_blocks.rs +++ b/client/service/src/chain_ops/import_blocks.rs @@ -35,7 +35,6 @@ use sp_runtime::{ }, }; use std::{ - convert::{TryFrom, TryInto}, io::Read, pin::Pin, task::Poll, diff --git a/client/service/src/config.rs b/client/service/src/config.rs index fd32aebdebdd8..7c7bb480aa5c3 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -294,7 +294,7 @@ impl BasePath { } } -impl std::convert::From for BasePath { +impl From for BasePath { fn from(path: PathBuf) -> Self { BasePath::new(path) } diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index 02e3ab95f1187..9fbf2c3ea3fca 100644 --- a/client/service/src/metrics.rs +++ b/client/service/src/metrics.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{convert::TryFrom, time::SystemTime}; +use std::time::SystemTime; use crate::config::Configuration; use futures_timer::Delay; diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index ec93d1f7c51fe..9fd2ef1deef43 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -40,7 +40,6 @@ pub use graph::{base_pool::Limit as PoolLimit, ChainApi, Options, Pool, Transact use parking_lot::Mutex; use std::{ collections::{HashMap, HashSet}, - convert::TryInto, pin::Pin, sync::Arc, }; diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 08ecdbc86cca4..2243f140cb22d 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -36,7 +36,7 @@ use sp_runtime::{ traits::Block as _, transaction_validity::{InvalidTransaction, TransactionSource, ValidTransaction}, }; -use std::{collections::BTreeSet, convert::TryInto, sync::Arc}; +use std::{collections::BTreeSet, sync::Arc}; use substrate_test_runtime_client::{ runtime::{Block, Extrinsic, Hash, Header, Index, Transfer}, AccountKeyring::*, @@ -864,8 +864,6 @@ fn ready_set_should_eventually_resolve_when_block_update_arrives() { #[test] fn should_not_accept_old_signatures() { - use std::convert::TryFrom; - let client = Arc::new(substrate_test_runtime_client::new()); let pool = Arc::new( diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 71ba7b4d24910..9b0f23a0a1783 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -147,7 +147,7 @@ use sp_runtime::{ }, ArithmeticError, TokenError, }; -use sp_std::{borrow::Borrow, convert::TryInto, prelude::*}; +use sp_std::{borrow::Borrow, prelude::*}; use frame_support::{ dispatch::{DispatchError, DispatchResult}, diff --git a/frame/bags-list/fuzzer/src/main.rs b/frame/bags-list/fuzzer/src/main.rs index 3ff59b450befa..6f538eb28e7e4 100644 --- a/frame/bags-list/fuzzer/src/main.rs +++ b/frame/bags-list/fuzzer/src/main.rs @@ -30,7 +30,6 @@ use frame_election_provider_support::{SortedListProvider, VoteWeight}; use honggfuzz::fuzz; use pallet_bags_list::mock::{AccountId, BagsList, ExtBuilder}; -use std::convert::From; const ID_RANGE: AccountId = 25_000; diff --git a/frame/bags-list/remote-tests/src/sanity_check.rs b/frame/bags-list/remote-tests/src/sanity_check.rs index f2b6881edea7f..1027efb8539ee 100644 --- a/frame/bags-list/remote-tests/src/sanity_check.rs +++ b/frame/bags-list/remote-tests/src/sanity_check.rs @@ -23,7 +23,6 @@ use frame_support::{ }; use remote_externalities::{Builder, Mode, OnlineConfig}; use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; -use sp_std::prelude::*; /// Execute the sanity check of the bags-list. pub async fn execute( diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 2b01cbe3c7429..ce59f5bb858ac 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -96,7 +96,6 @@ pub mod test_utils { } macro_rules! assert_return_code { ( $x:expr , $y:expr $(,)? ) => {{ - use sp_std::convert::TryInto; assert_eq!(u32::from_le_bytes($x.data[..].try_into().unwrap()), $y as u32); }}; } diff --git a/frame/conviction-voting/src/vote.rs b/frame/conviction-voting/src/vote.rs index d7ca931de35a1..e608a6dcfd01b 100644 --- a/frame/conviction-voting/src/vote.rs +++ b/frame/conviction-voting/src/vote.rs @@ -25,7 +25,7 @@ use sp_runtime::{ traits::{Saturating, Zero}, RuntimeDebug, }; -use sp_std::{convert::TryFrom, prelude::*, result::Result}; +use sp_std::prelude::*; /// A number of lock periods, plus a vote, one way or the other. #[derive(Copy, Clone, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen)] diff --git a/frame/election-provider-support/src/mock.rs b/frame/election-provider-support/src/mock.rs index d10b1724c95d8..7c834f06f3cdf 100644 --- a/frame/election-provider-support/src/mock.rs +++ b/frame/election-provider-support/src/mock.rs @@ -21,7 +21,6 @@ use std::{ collections::{HashMap, HashSet}, - convert::TryInto, hash::Hash, }; diff --git a/frame/election-provider-support/src/tests.rs b/frame/election-provider-support/src/tests.rs index f88f3653c681c..1ccff79f3efd4 100644 --- a/frame/election-provider-support/src/tests.rs +++ b/frame/election-provider-support/src/tests.rs @@ -22,7 +22,6 @@ use crate::{mock::*, IndexAssignment, NposSolution}; use frame_support::traits::ConstU32; use rand::SeedableRng; -use std::convert::TryInto; mod solution_type { use super::*; @@ -30,7 +29,7 @@ mod solution_type { // these need to come from the same dev-dependency `frame-election-provider-support`, not from // the crate. use crate::{generate_solution_type, Assignment, Error as NposError, NposSolution}; - use sp_std::{convert::TryInto, fmt::Debug}; + use sp_std::fmt::Debug; #[allow(dead_code)] mod __private { diff --git a/frame/election-provider-support/src/traits.rs b/frame/election-provider-support/src/traits.rs index e1fc0663e7d1e..ed812e2e0f2c4 100644 --- a/frame/election-provider-support/src/traits.rs +++ b/frame/election-provider-support/src/traits.rs @@ -22,16 +22,12 @@ use codec::Encode; use scale_info::TypeInfo; use sp_arithmetic::traits::{Bounded, UniqueSaturatedInto}; use sp_npos_elections::{ElectionScore, Error, EvaluateSupport}; -use sp_std::{ - convert::{TryFrom, TryInto}, - fmt::Debug, - prelude::*, -}; +use sp_std::{fmt::Debug, prelude::*}; /// An opaque index-based, NPoS solution type. pub trait NposSolution where - Self: Sized + for<'a> sp_std::convert::TryFrom<&'a [IndexAssignmentOf], Error = Error>, + Self: Sized + for<'a> TryFrom<&'a [IndexAssignmentOf], Error = Error>, { /// The maximum number of votes that are allowed. const LIMIT: usize; diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index e2213ef4169b1..5ef515db0b236 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -104,7 +104,7 @@ use sp_staking::{ offence::{Kind, Offence, ReportOffence}, SessionIndex, }; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; pub use weights::WeightInfo; pub mod sr25519 { diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index c34057a1034d3..a5d8ee28b5952 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -37,7 +37,7 @@ mod tests; pub mod weights; use sp_runtime::traits::{BadOrigin, Hash, Saturating}; -use sp_std::{convert::TryFrom, prelude::*}; +use sp_std::prelude::*; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 84f1a84badc90..891315c92aa39 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -48,7 +48,7 @@ use sp_runtime::{ traits::{Dispatchable, Hash, Saturating, TrailingZeroInput, Zero}, DispatchResult, }; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; pub use weights::WeightInfo; pub use pallet::*; diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index b72aa665550cf..f709578f6941a 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -71,7 +71,6 @@ use safe_mix::TripletMix; use codec::Encode; use frame_support::traits::Randomness; use sp_runtime::traits::{Hash, Saturating}; -use sp_std::prelude::*; const RANDOM_MATERIAL_LEN: u32 = 81; diff --git a/frame/staking/reward-curve/src/lib.rs b/frame/staking/reward-curve/src/lib.rs index 9b2f3100b487e..e66f6fde37599 100644 --- a/frame/staking/reward-curve/src/lib.rs +++ b/frame/staking/reward-curve/src/lib.rs @@ -24,7 +24,6 @@ use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use proc_macro_crate::{crate_name, FoundCrate}; use quote::{quote, ToTokens}; -use std::convert::TryInto; use syn::parse::{Parse, ParseStream}; /// Accepts a number of expressions to create a instance of PiecewiseLinear which represents the diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 2a0716721dd51..872ed2e1af404 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -316,7 +316,7 @@ use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, EraIndex, SessionIndex, }; -use sp_std::{collections::btree_map::BTreeMap, convert::From, prelude::*}; +use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub use weights::WeightInfo; pub use pallet::{pallet::*, *}; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 306bd34390d82..fa8c453c2b0fe 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -33,7 +33,7 @@ use sp_runtime::{ DispatchError, Perbill, Percent, }; use sp_staking::{EraIndex, SessionIndex}; -use sp_std::{cmp::max, convert::From, prelude::*}; +use sp_std::{cmp::max, prelude::*}; mod impls; diff --git a/frame/support/procedural/src/construct_runtime/expand/event.rs b/frame/support/procedural/src/construct_runtime/expand/event.rs index ef071a9fc7ef5..b242f9641562c 100644 --- a/frame/support/procedural/src/construct_runtime/expand/event.rs +++ b/frame/support/procedural/src/construct_runtime/expand/event.rs @@ -127,7 +127,7 @@ fn expand_event_conversion( Event::#variant_name(x) } } - impl #scrate::sp_std::convert::TryInto<#pallet_event> for Event { + impl TryInto<#pallet_event> for Event { type Error = (); fn try_into(self) -> #scrate::sp_std::result::Result<#pallet_event, Self::Error> { diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index 077bef3744a5a..342a002b52b9d 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -230,7 +230,7 @@ pub fn expand_outer_origin( } } - impl #scrate::sp_std::convert::TryFrom for #system_path::Origin<#runtime> { + impl TryFrom for #system_path::Origin<#runtime> { type Error = OriginCaller; fn try_from(x: OriginCaller) -> #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, OriginCaller> @@ -359,7 +359,7 @@ fn expand_origin_pallet_conversions( } } - impl #scrate::sp_std::convert::TryFrom for #pallet_origin { + impl TryFrom for #pallet_origin { type Error = OriginCaller; fn try_from( x: OriginCaller, diff --git a/frame/support/procedural/src/pallet/expand/error.rs b/frame/support/procedural/src/pallet/expand/error.rs index 86b06d737decf..124e8b312ce39 100644 --- a/frame/support/procedural/src/pallet/expand/error.rs +++ b/frame/support/procedural/src/pallet/expand/error.rs @@ -162,7 +162,7 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::sp_runtime::DispatchError::Module(#frame_support::sp_runtime::ModuleError { index, - error: core::convert::TryInto::try_into(encoded).expect("encoded error is resized to be equal to the maximum encoded error size; qed"), + error: TryInto::try_into(encoded).expect("encoded error is resized to be equal to the maximum encoded error size; qed"), message: Some(err.as_str()), }) } diff --git a/frame/support/src/error.rs b/frame/support/src/error.rs index 764376a4e1dc2..0ffe4334e2e30 100644 --- a/frame/support/src/error.rs +++ b/frame/support/src/error.rs @@ -152,7 +152,7 @@ macro_rules! decl_error { $crate::sp_runtime::DispatchError::Module($crate::sp_runtime::ModuleError { index, - error: core::convert::TryInto::try_into(error).expect("encoded error is resized to be equal to the maximum encoded error size; qed"), + error: TryInto::try_into(error).expect("encoded error is resized to be equal to the maximum encoded error size; qed"), message: Some(err.as_str()), }) } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 70a79c07189dc..714449eec7847 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -127,13 +127,11 @@ impl TypeId for PalletId { macro_rules! bounded_vec { ($ ($values:expr),* $(,)?) => { { - use $crate::sp_std::convert::TryInto as _; $crate::sp_std::vec![$($values),*].try_into().unwrap() } }; ( $value:expr ; $repetition:expr ) => { { - use $crate::sp_std::convert::TryInto as _; $crate::sp_std::vec![$value ; $repetition].try_into().unwrap() } } diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index 6190552476a45..eca4b17821c77 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -22,10 +22,7 @@ use crate::{ traits::{Get, TryCollect}, }; use codec::{Decode, Encode, MaxEncodedLen}; -use sp_std::{ - borrow::Borrow, collections::btree_map::BTreeMap, convert::TryFrom, marker::PhantomData, - ops::Deref, -}; +use sp_std::{borrow::Borrow, collections::btree_map::BTreeMap, marker::PhantomData, ops::Deref}; /// A bounded map based on a B-Tree. /// diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index 543b997e94e34..f38952bf545d9 100644 --- a/frame/support/src/storage/bounded_btree_set.rs +++ b/frame/support/src/storage/bounded_btree_set.rs @@ -22,10 +22,7 @@ use crate::{ traits::{Get, TryCollect}, }; use codec::{Decode, Encode, MaxEncodedLen}; -use sp_std::{ - borrow::Borrow, collections::btree_set::BTreeSet, convert::TryFrom, marker::PhantomData, - ops::Deref, -}; +use sp_std::{borrow::Borrow, collections::btree_set::BTreeSet, marker::PhantomData, ops::Deref}; /// A bounded set based on a B-Tree. /// @@ -324,7 +321,6 @@ pub mod test { use crate::Twox128; use frame_support::traits::ConstU32; use sp_io::TestExternalities; - use sp_std::convert::TryInto; crate::generate_storage_alias! { Prefix, Foo => Value>> } crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), BoundedBTreeSet>> } diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index aa6dc88eaa4f4..21cc487b49082 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -27,7 +27,7 @@ use core::{ ops::{Deref, Index, IndexMut}, slice::SliceIndex, }; -use sp_std::{convert::TryFrom, marker::PhantomData, prelude::*}; +use sp_std::{marker::PhantomData, prelude::*}; /// A weakly bounded vector. /// @@ -320,7 +320,6 @@ pub mod test { use crate::Twox128; use frame_support::traits::ConstU32; use sp_io::TestExternalities; - use sp_std::convert::TryInto; crate::generate_storage_alias! { Prefix, Foo => Value>> } crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), WeakBoundedVec>> } diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index d6223ec88f81b..19d3dfac6e5ac 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -30,7 +30,7 @@ use frame_support::{ }; use frame_system::RawOrigin as SystemOrigin; use sp_runtime::traits::Bounded; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; use crate::Pallet as Uniques; diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 775902f223ba0..13841a0443ceb 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -74,7 +74,7 @@ use sp_runtime::{ }, RuntimeDebug, }; -use sp_std::{convert::TryInto, fmt::Debug, prelude::*}; +use sp_std::{fmt::Debug, prelude::*}; pub use vesting_info::*; pub use weights::WeightInfo; diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index b12fe72b271a6..05f89c40ef99f 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -42,7 +42,7 @@ pub use scale_info; #[cfg(feature = "std")] pub use serde; #[doc(hidden)] -pub use sp_std::{convert::TryFrom, ops::Deref, vec::Vec}; +pub use sp_std::{ops::Deref, vec::Vec}; pub mod ecdsa; pub mod ed25519; @@ -363,7 +363,7 @@ macro_rules! app_crypto_public_common { } } - impl<'a> $crate::TryFrom<&'a [u8]> for Public { + impl<'a> TryFrom<&'a [u8]> for Public { type Error = (); fn try_from(data: &'a [u8]) -> Result { @@ -518,7 +518,7 @@ macro_rules! app_crypto_signature_common { type Generic = $sig; } - impl<'a> $crate::TryFrom<&'a [u8]> for Signature { + impl<'a> TryFrom<&'a [u8]> for Signature { type Error = (); fn try_from(data: &'a [u8]) -> Result { @@ -526,7 +526,7 @@ macro_rules! app_crypto_signature_common { } } - impl $crate::TryFrom<$crate::Vec> for Signature { + impl TryFrom<$crate::Vec> for Signature { type Error = (); fn try_from(data: $crate::Vec) -> Result { diff --git a/primitives/arithmetic/fuzzer/src/biguint.rs b/primitives/arithmetic/fuzzer/src/biguint.rs index e4c088a2e8ab3..f49743a4b8a69 100644 --- a/primitives/arithmetic/fuzzer/src/biguint.rs +++ b/primitives/arithmetic/fuzzer/src/biguint.rs @@ -29,7 +29,6 @@ use honggfuzz::fuzz; use sp_arithmetic::biguint::{BigUint, Single}; -use std::convert::TryFrom; fn main() { loop { diff --git a/primitives/arithmetic/fuzzer/src/normalize.rs b/primitives/arithmetic/fuzzer/src/normalize.rs index e4f90dbc1c415..dd717115a5c9c 100644 --- a/primitives/arithmetic/fuzzer/src/normalize.rs +++ b/primitives/arithmetic/fuzzer/src/normalize.rs @@ -25,7 +25,6 @@ use honggfuzz::fuzz; use sp_arithmetic::Normalizable; -use std::convert::TryInto; type Ty = u64; diff --git a/primitives/arithmetic/src/biguint.rs b/primitives/arithmetic/src/biguint.rs index b26ac4294d111..33f0960ee378c 100644 --- a/primitives/arithmetic/src/biguint.rs +++ b/primitives/arithmetic/src/biguint.rs @@ -19,7 +19,7 @@ use codec::{Decode, Encode}; use num_traits::{One, Zero}; -use sp_std::{cell::RefCell, cmp::Ordering, convert::TryFrom, ops, prelude::*, vec}; +use sp_std::{cell::RefCell, cmp::Ordering, ops, prelude::*, vec}; // A sensible value for this would be half of the dword size of the host machine. Since the // runtime is compiled to 32bit webassembly, using 32 and 64 for single and double respectively @@ -664,7 +664,6 @@ pub mod tests { #[test] fn can_try_build_numbers_from_types() { - use sp_std::convert::TryFrom; assert_eq!(u64::try_from(with_limbs(1)).unwrap(), 1); assert_eq!(u64::try_from(with_limbs(2)).unwrap(), u32::MAX as u64 + 2); assert_eq!(u64::try_from(with_limbs(3)).unwrap_err(), "cannot fit a number into u64"); diff --git a/primitives/arithmetic/src/fixed_point.rs b/primitives/arithmetic/src/fixed_point.rs index 1c61d6c3806ae..3ecfb60ee0f52 100644 --- a/primitives/arithmetic/src/fixed_point.rs +++ b/primitives/arithmetic/src/fixed_point.rs @@ -27,7 +27,6 @@ use crate::{ }; use codec::{CompactAs, Decode, Encode}; use sp_std::{ - convert::{TryFrom, TryInto}, fmt::Debug, ops::{self, Add, Div, Mul, Sub}, prelude::*, diff --git a/primitives/arithmetic/src/helpers_128bit.rs b/primitives/arithmetic/src/helpers_128bit.rs index af9729c9702c3..735b11287cbe4 100644 --- a/primitives/arithmetic/src/helpers_128bit.rs +++ b/primitives/arithmetic/src/helpers_128bit.rs @@ -24,7 +24,6 @@ use crate::biguint; use num_traits::Zero; use sp_std::{ cmp::{max, min}, - convert::TryInto, mem, }; diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index 273608a3d1711..729da123757c7 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -44,7 +44,7 @@ pub use fixed_point::{FixedI128, FixedI64, FixedPointNumber, FixedPointOperand, pub use per_things::{InnerOf, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, UpperOf}; pub use rational::{Rational128, RationalInfinite}; -use sp_std::{cmp::Ordering, convert::TryInto, fmt::Debug, prelude::*}; +use sp_std::{cmp::Ordering, fmt::Debug, prelude::*}; use traits::{BaseArithmetic, One, SaturatedConversion, Unsigned, Zero}; /// Trait for comparing two numbers with an threshold. diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index c3ccca56ca33f..1b9e6d91a2cd3 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -25,7 +25,6 @@ use crate::traits::{ use codec::{CompactAs, Encode}; use num_traits::{Pow, SaturatingAdd, SaturatingSub}; use sp_std::{ - convert::{TryFrom, TryInto}, fmt, ops, ops::{Add, Sub}, prelude::*, diff --git a/primitives/arithmetic/src/traits.rs b/primitives/arithmetic/src/traits.rs index 447f8cef51f9a..748aaed2a7cf5 100644 --- a/primitives/arithmetic/src/traits.rs +++ b/primitives/arithmetic/src/traits.rs @@ -23,12 +23,8 @@ pub use num_traits::{ checked_pow, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, One, Signed, Unsigned, Zero, }; -use sp_std::{ - self, - convert::{TryFrom, TryInto}, - ops::{ - Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Shl, Shr, Sub, SubAssign, - }, +use sp_std::ops::{ + Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Shl, Shr, Sub, SubAssign, }; /// A meta trait for arithmetic type operations, regardless of any limitation on size. diff --git a/primitives/consensus/common/src/error.rs b/primitives/consensus/common/src/error.rs index 280ff2322898d..0656b5761fb38 100644 --- a/primitives/consensus/common/src/error.rs +++ b/primitives/consensus/common/src/error.rs @@ -86,13 +86,13 @@ pub enum Error { CannotSign(Vec, String), } -impl core::convert::From for Error { +impl From for Error { fn from(p: Public) -> Self { Self::InvalidAuthority(p) } } -impl core::convert::From for Error { +impl From for Error { fn from(s: String) -> Self { Self::StateUnavailable(s) } diff --git a/primitives/consensus/vrf/src/schnorrkel.rs b/primitives/consensus/vrf/src/schnorrkel.rs index 1ef23427e0ed0..094a398893ff6 100644 --- a/primitives/consensus/vrf/src/schnorrkel.rs +++ b/primitives/consensus/vrf/src/schnorrkel.rs @@ -21,7 +21,6 @@ use codec::{Decode, Encode, EncodeLike}; use schnorrkel::errors::MultiSignatureStage; use sp_core::U512; use sp_std::{ - convert::TryFrom, ops::{Deref, DerefMut}, prelude::*, }; diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 12f8397eee4a4..f994da1515350 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -38,7 +38,7 @@ pub use secrecy::SecretString; use sp_runtime_interface::pass_by::PassByInner; #[doc(hidden)] pub use sp_std::ops::Deref; -use sp_std::{convert::TryFrom, hash::Hash, str, vec::Vec}; +use sp_std::{hash::Hash, str, vec::Vec}; /// Trait to zeroize a memory buffer. pub use zeroize::Zeroize; @@ -535,7 +535,7 @@ impl From<[u8; 32]> for AccountId32 { } } -impl<'a> sp_std::convert::TryFrom<&'a [u8]> for AccountId32 { +impl<'a> TryFrom<&'a [u8]> for AccountId32 { type Error = (); fn try_from(x: &'a [u8]) -> Result { if x.len() == 32 { diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 7a4e4399913dc..6343e3f4dfd0d 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -137,7 +137,7 @@ impl AsMut<[u8]> for Public { } } -impl sp_std::convert::TryFrom<&[u8]> for Public { +impl TryFrom<&[u8]> for Public { type Error = (); fn try_from(data: &[u8]) -> Result { @@ -209,7 +209,7 @@ impl<'de> Deserialize<'de> for Public { #[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; 65]); -impl sp_std::convert::TryFrom<&[u8]> for Signature { +impl TryFrom<&[u8]> for Signature { type Error = (); fn try_from(data: &[u8]) -> Result { diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 555c23c6b60cc..0bde9e2e5303a 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -39,8 +39,6 @@ use crate::crypto::{DeriveJunction, Pair as TraitPair, SecretStringError}; #[cfg(feature = "std")] use bip39::{Language, Mnemonic, MnemonicType}; #[cfg(feature = "full_crypto")] -use core::convert::TryFrom; -#[cfg(feature = "full_crypto")] use ed25519_dalek::{Signer as _, Verifier as _}; #[cfg(feature = "std")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; @@ -116,7 +114,7 @@ impl Deref for Public { } } -impl sp_std::convert::TryFrom<&[u8]> for Public { +impl TryFrom<&[u8]> for Public { type Error = (); fn try_from(data: &[u8]) -> Result { @@ -215,7 +213,7 @@ impl<'de> Deserialize<'de> for Public { #[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; 64]); -impl sp_std::convert::TryFrom<&[u8]> for Signature { +impl TryFrom<&[u8]> for Signature { type Error = (); fn try_from(data: &[u8]) -> Result { diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index b9e310dc1fb10..4ffadc3e4031d 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -21,10 +21,7 @@ use crate::{OpaquePeerId, RuntimeDebug}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime_interface::pass_by::{PassByCodec, PassByEnum, PassByInner}; -use sp_std::{ - convert::TryFrom, - prelude::{Box, Vec}, -}; +use sp_std::prelude::{Box, Vec}; pub use crate::crypto::KeyTypeId; diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index 2f298fa2a2666..ef033c2099b5f 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -35,8 +35,6 @@ use schnorrkel::{ #[cfg(feature = "full_crypto")] use sp_std::vec::Vec; #[cfg(feature = "std")] -use std::convert::TryFrom; -#[cfg(feature = "std")] use substrate_bip39::mini_secret_from_entropy; use crate::{ @@ -142,7 +140,7 @@ impl std::str::FromStr for Public { } } -impl sp_std::convert::TryFrom<&[u8]> for Public { +impl TryFrom<&[u8]> for Public { type Error = (); fn try_from(data: &[u8]) -> Result { @@ -215,7 +213,7 @@ impl<'de> Deserialize<'de> for Public { #[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; 64]); -impl sp_std::convert::TryFrom<&[u8]> for Signature { +impl TryFrom<&[u8]> for Signature { type Error = (); fn try_from(data: &[u8]) -> Result { diff --git a/primitives/rpc/src/number.rs b/primitives/rpc/src/number.rs index 5a433a9598e01..81084a09d4ac8 100644 --- a/primitives/rpc/src/number.rs +++ b/primitives/rpc/src/number.rs @@ -20,10 +20,7 @@ use serde::{Deserialize, Serialize}; use sp_core::U256; -use std::{ - convert::{TryFrom, TryInto}, - fmt::Debug, -}; +use std::fmt::Debug; /// A number type that can be serialized both as a number or a string that encodes a number in a /// string. diff --git a/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs b/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs index 1fd22c6a25383..7c3f066f6c83b 100644 --- a/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs +++ b/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs @@ -51,7 +51,7 @@ pub fn derive_impl(input: DeriveInput) -> Result { type PassBy = #crate_::pass_by::Enum<#ident>; } - impl #crate_::sp_std::convert::TryFrom for #ident { + impl TryFrom for #ident { type Error = (); fn try_from(inner: u8) -> #crate_::sp_std::result::Result { diff --git a/primitives/runtime-interface/src/pass_by.rs b/primitives/runtime-interface/src/pass_by.rs index fb2d6b818d174..5d895ff5b3f82 100644 --- a/primitives/runtime-interface/src/pass_by.rs +++ b/primitives/runtime-interface/src/pass_by.rs @@ -33,7 +33,7 @@ use crate::wasm::*; #[cfg(feature = "std")] use sp_wasm_interface::{FunctionContext, Pointer, Result}; -use sp_std::{convert::TryFrom, marker::PhantomData}; +use sp_std::marker::PhantomData; #[cfg(not(feature = "std"))] use sp_std::vec::Vec; @@ -382,7 +382,7 @@ impl, I: RIType> RIType for Inner { /// } /// } /// -/// impl std::convert::TryFrom for Test { +/// impl TryFrom for Test { /// type Error = (); /// /// fn try_from(val: u8) -> Result { diff --git a/primitives/runtime-interface/test-wasm/src/lib.rs b/primitives/runtime-interface/test-wasm/src/lib.rs index 0c8a9c04ab1e9..f518a2e17498c 100644 --- a/primitives/runtime-interface/test-wasm/src/lib.rs +++ b/primitives/runtime-interface/test-wasm/src/lib.rs @@ -22,7 +22,7 @@ use sp_runtime_interface::runtime_interface; #[cfg(not(feature = "std"))] -use sp_std::{convert::TryFrom, mem, prelude::*}; +use sp_std::{mem, prelude::*}; use sp_core::{sr25519::Public, wasm_export_functions}; diff --git a/primitives/runtime/src/curve.rs b/primitives/runtime/src/curve.rs index b5532c3d8cef7..c6bfa66017870 100644 --- a/primitives/runtime/src/curve.rs +++ b/primitives/runtime/src/curve.rs @@ -110,8 +110,6 @@ where #[test] fn test_multiply_by_rational_saturating() { - use std::convert::TryInto; - let div = 100u32; for value in 0..=div { for p in 0..=div { @@ -132,8 +130,6 @@ fn test_multiply_by_rational_saturating() { #[test] fn test_calculate_for_fraction_times_denominator() { - use std::convert::TryInto; - let curve = PiecewiseLinear { points: &[ (Perbill::from_parts(0_000_000_000), Perbill::from_parts(0_500_000_000)), diff --git a/primitives/runtime/src/generic/header.rs b/primitives/runtime/src/generic/header.rs index 3e1a673d257a1..a7b43608f2b78 100644 --- a/primitives/runtime/src/generic/header.rs +++ b/primitives/runtime/src/generic/header.rs @@ -29,7 +29,7 @@ use crate::{ #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_core::U256; -use sp_std::{convert::TryFrom, fmt::Debug}; +use sp_std::fmt::Debug; /// Abstraction over a block header for a substrate chain. #[derive(Encode, Decode, PartialEq, Eq, Clone, sp_core::RuntimeDebug, TypeInfo)] diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index c09db5124cc1f..39e606eb9b5f4 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -50,7 +50,7 @@ use sp_core::{ hash::{H256, H512}, sr25519, }; -use sp_std::{convert::TryFrom, prelude::*}; +use sp_std::prelude::*; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index ba4ca790a9198..9c71b2023d3f8 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -37,13 +37,7 @@ pub use sp_arithmetic::traits::{ UniqueSaturatedFrom, UniqueSaturatedInto, Zero, }; use sp_core::{self, storage::StateVersion, Hasher, RuntimeDebug, TypeId}; -use sp_std::{ - self, - convert::{TryFrom, TryInto}, - fmt::Debug, - marker::PhantomData, - prelude::*, -}; +use sp_std::{self, fmt::Debug, marker::PhantomData, prelude::*}; #[cfg(feature = "std")] use std::fmt::Display; #[cfg(feature = "std")] diff --git a/primitives/std/src/lib.rs b/primitives/std/src/lib.rs index 05dff0f3077b6..6653c3d7eadec 100644 --- a/primitives/std/src/lib.rs +++ b/primitives/std/src/lib.rs @@ -103,7 +103,6 @@ pub mod prelude { boxed::Box, clone::Clone, cmp::{Eq, PartialEq, Reverse}, - convert::{TryFrom, TryInto}, iter::IntoIterator, vec::Vec, }; diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index d377ea931df2d..fecd2b24dbb00 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -423,7 +423,7 @@ impl From for u8 { } } -impl sp_std::convert::TryFrom for StateVersion { +impl TryFrom for StateVersion { type Error = (); fn try_from(val: u8) -> sp_std::result::Result { match val { diff --git a/primitives/wasm-interface/src/lib.rs b/primitives/wasm-interface/src/lib.rs index d57666f126899..6dfc3116ddc48 100644 --- a/primitives/wasm-interface/src/lib.rs +++ b/primitives/wasm-interface/src/lib.rs @@ -73,7 +73,7 @@ impl From for u8 { } } -impl sp_std::convert::TryFrom for ValueType { +impl TryFrom for ValueType { type Error = (); fn try_from(val: u8) -> sp_std::result::Result { diff --git a/utils/prometheus/src/lib.rs b/utils/prometheus/src/lib.rs index 1892741eff5da..3ea9d45d48b11 100644 --- a/utils/prometheus/src/lib.rs +++ b/utils/prometheus/src/lib.rs @@ -122,7 +122,6 @@ async fn init_prometheus_with_listener( mod tests { use super::*; use hyper::{Client, Uri}; - use std::convert::TryFrom; #[test] fn prometheus_works() { From 1373db0655258202f441c8545374b7352a8e808f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Apr 2022 11:21:45 +0200 Subject: [PATCH 0659/1472] Bump backtrace from 0.3.63 to 0.3.64 (#11157) Bumps [backtrace](https://github.com/rust-lang/backtrace-rs) from 0.3.63 to 0.3.64. - [Release notes](https://github.com/rust-lang/backtrace-rs/releases) - [Commits](https://github.com/rust-lang/backtrace-rs/compare/0.3.63...0.3.64) --- updated-dependencies: - dependency-name: backtrace 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 ++-- primitives/panic-handler/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fb6f5814565a..74ad907f55d3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -400,9 +400,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" +checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" dependencies = [ "addr2line", "cc", diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml index 0155b6532876c..7b2023eff0bfc 100644 --- a/primitives/panic-handler/Cargo.toml +++ b/primitives/panic-handler/Cargo.toml @@ -14,6 +14,6 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -backtrace = "0.3.63" +backtrace = "0.3.64" regex = "1.5.5" lazy_static = "1.4.0" From 51d47a8a27c7e3b5227ab51591e119e481ec4d6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Apr 2022 11:22:18 +0200 Subject: [PATCH 0660/1472] Bump dyn-clone from 1.0.4 to 1.0.5 (#11048) Bumps [dyn-clone](https://github.com/dtolnay/dyn-clone) from 1.0.4 to 1.0.5. - [Release notes](https://github.com/dtolnay/dyn-clone/releases) - [Commits](https://github.com/dtolnay/dyn-clone/compare/1.0.4...1.0.5) --- updated-dependencies: - dependency-name: dyn-clone 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 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74ad907f55d3f..690661dacaee8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1751,9 +1751,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" +checksum = "21e50f3adc76d6a43f5ed73b698a87d0760ca74617f60f7c3b879003536fdd28" [[package]] name = "dynasm" From 5c898d36d81fa1bde73728ba4b75020df303cccf Mon Sep 17 00:00:00 2001 From: moh-eulith <101080211+moh-eulith@users.noreply.github.com> Date: Mon, 4 Apr 2022 05:23:17 -0400 Subject: [PATCH 0661/1472] Update kvdb-rocksdb to 0.15.2 (#11144) --- Cargo.lock | 4 ++-- client/db/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 690661dacaee8..23f11860ca6f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3616,9 +3616,9 @@ dependencies = [ [[package]] name = "kvdb-rocksdb" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e72a631a32527fafe22d0751c002e67d28173c49dcaecf79d1aaa323c520e9" +checksum = "ca7fbdfd71cd663dceb0faf3367a99f8cf724514933e9867cec4995b6027cbc1" dependencies = [ "fs-swap", "kvdb", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 105bc43c61bc9..12bb29958cfec 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] parking_lot = "0.12.0" log = "0.4.8" kvdb = "0.11.0" -kvdb-rocksdb = { version = "0.15.1", optional = true } +kvdb-rocksdb = { version = "0.15.2", optional = true } kvdb-memorydb = "0.11.0" linked-hash-map = "0.5.4" hash-db = "0.15.2" From 0d888039be6afc8950c087257c8e32448ec193b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 4 Apr 2022 13:19:46 +0200 Subject: [PATCH 0662/1472] Revert "Replace storage access by atomics" (#11156) This reverts commit a69b8eb4a28f365a4a4b2fc295a693ec4d3d3cd5. --- frame/support/src/storage/mod.rs | 54 +++++++++++++++++--------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index c9814e28a7ae4..106d3e3f459aa 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -48,46 +48,48 @@ pub mod unhashed; pub mod weak_bounded_vec; mod transaction_level_tracker { - use core::sync::atomic::{AtomicU32, Ordering}; - type Layer = u32; - static NUM_LEVELS: AtomicU32 = AtomicU32::new(0); + const TRANSACTION_LEVEL_KEY: &'static [u8] = b":transaction_level:"; const TRANSACTIONAL_LIMIT: Layer = 255; pub fn get_transaction_level() -> Layer { - NUM_LEVELS.load(Ordering::SeqCst) + crate::storage::unhashed::get_or_default::(TRANSACTION_LEVEL_KEY) + } + + fn set_transaction_level(level: &Layer) { + crate::storage::unhashed::put::(TRANSACTION_LEVEL_KEY, level); + } + + fn kill_transaction_level() { + crate::storage::unhashed::kill(TRANSACTION_LEVEL_KEY); } /// Increments the transaction level. Returns an error if levels go past the limit. /// /// Returns a guard that when dropped decrements the transaction level automatically. pub fn inc_transaction_level() -> Result { - NUM_LEVELS - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |existing_levels| { - if existing_levels >= TRANSACTIONAL_LIMIT { - return None - } - // Cannot overflow because of check above. - Some(existing_levels + 1) - }) - .map_err(|_| ())?; + let existing_levels = get_transaction_level(); + if existing_levels >= TRANSACTIONAL_LIMIT { + return Err(()) + } + // Cannot overflow because of check above. + set_transaction_level(&(existing_levels + 1)); Ok(StorageLayerGuard) } fn dec_transaction_level() { - NUM_LEVELS - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |existing_levels| { - if existing_levels == 0 { - log::warn!( - "We are underflowing with calculating transactional levels. Not great, but let's not panic...", - ); - None - } else { - // Cannot underflow because of checks above. - Some(existing_levels - 1) - } - }) - .ok(); + let existing_levels = get_transaction_level(); + if existing_levels == 0 { + log::warn!( + "We are underflowing with calculating transactional levels. Not great, but let's not panic...", + ); + } else if existing_levels == 1 { + // Don't leave any trace of this storage item. + kill_transaction_level(); + } else { + // Cannot underflow because of checks above. + set_transaction_level(&(existing_levels - 1)); + } } pub fn is_transactional() -> bool { From 6f411cdb9cb68d1a5b140d448e9259ba9c926962 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 4 Apr 2022 16:29:29 +0200 Subject: [PATCH 0663/1472] Remove not required DigestItem conversion (#11165) --- frame/aura/src/lib.rs | 4 ++-- frame/babe/src/lib.rs | 2 +- frame/grandpa/src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 657965c60a3f1..0f474770017d5 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -153,7 +153,7 @@ impl Pallet { AURA_ENGINE_ID, ConsensusLog::AuthoritiesChange(new.into_inner()).encode(), ); - >::deposit_log(log.into()); + >::deposit_log(log); } fn initialize_authorities(authorities: &[T::AuthorityId]) { @@ -225,7 +225,7 @@ impl OneSessionHandler for Pallet { ConsensusLog::::OnDisabled(i as AuthorityIndex).encode(), ); - >::deposit_log(log.into()); + >::deposit_log(log); } } diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index f673c8b43bee0..87ae762707ccd 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -627,7 +627,7 @@ impl Pallet { fn deposit_consensus(new: U) { let log = DigestItem::Consensus(BABE_ENGINE_ID, new.encode()); - >::deposit_log(log.into()) + >::deposit_log(log) } fn deposit_randomness(randomness: &schnorrkel::Randomness) { diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 68d4cf26a2e23..e30d65acbc6a6 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -498,7 +498,7 @@ impl Pallet { /// Deposit one of this module's logs. fn deposit_log(log: ConsensusLog) { let log = DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode()); - >::deposit_log(log.into()); + >::deposit_log(log); } // Perform module initialization, abstracted so that it can be called either through genesis From ad95f431e93ec16ef46cef06d47fb83a44148b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 4 Apr 2022 22:28:57 +0200 Subject: [PATCH 0664/1472] transactional: Fix some nitpicks (#11163) * transactional: Fix some nitpicks This fixes some nitpicks related to the transactional storage stuff from me. As everything was merged too fast, here are some nitpicks from me. First, the entire functionality is moved into its own file to have a clear separation. Secondly I changed the `set_transactional_level` to not take `Layer` by reference. Besides that I have added some docs etc. * Add some comment * Move tests * :facepalm: --- frame/support/procedural/src/transactional.rs | 2 +- frame/support/src/storage/mod.rs | 212 +--------------- frame/support/src/storage/transactional.rs | 232 ++++++++++++++++++ 3 files changed, 242 insertions(+), 204 deletions(-) create mode 100644 frame/support/src/storage/transactional.rs diff --git a/frame/support/procedural/src/transactional.rs b/frame/support/procedural/src/transactional.rs index ba75fbc9737aa..eb77a320a509f 100644 --- a/frame/support/procedural/src/transactional.rs +++ b/frame/support/procedural/src/transactional.rs @@ -49,7 +49,7 @@ pub fn require_transactional(_attr: TokenStream, input: TokenStream) -> Result Layer { - crate::storage::unhashed::get_or_default::(TRANSACTION_LEVEL_KEY) - } - - fn set_transaction_level(level: &Layer) { - crate::storage::unhashed::put::(TRANSACTION_LEVEL_KEY, level); - } - - fn kill_transaction_level() { - crate::storage::unhashed::kill(TRANSACTION_LEVEL_KEY); - } - - /// Increments the transaction level. Returns an error if levels go past the limit. - /// - /// Returns a guard that when dropped decrements the transaction level automatically. - pub fn inc_transaction_level() -> Result { - let existing_levels = get_transaction_level(); - if existing_levels >= TRANSACTIONAL_LIMIT { - return Err(()) - } - // Cannot overflow because of check above. - set_transaction_level(&(existing_levels + 1)); - Ok(StorageLayerGuard) - } - - fn dec_transaction_level() { - let existing_levels = get_transaction_level(); - if existing_levels == 0 { - log::warn!( - "We are underflowing with calculating transactional levels. Not great, but let's not panic...", - ); - } else if existing_levels == 1 { - // Don't leave any trace of this storage item. - kill_transaction_level(); - } else { - // Cannot underflow because of checks above. - set_transaction_level(&(existing_levels - 1)); - } - } - - pub fn is_transactional() -> bool { - get_transaction_level() > 0 - } - - pub struct StorageLayerGuard; - - impl Drop for StorageLayerGuard { - fn drop(&mut self) { - dec_transaction_level() - } - } -} - -/// Check if the current call is within a transactional layer. -pub fn is_transactional() -> bool { - transaction_level_tracker::is_transactional() -} - -/// Execute the supplied function in a new storage transaction. -/// -/// All changes to storage performed by the supplied function are discarded if the returned -/// outcome is `TransactionOutcome::Rollback`. -/// -/// Transactions can be nested up to `TRANSACTIONAL_LIMIT` times; more than that will result in an -/// error. -/// -/// Commits happen to the parent transaction. -pub fn with_transaction(f: impl FnOnce() -> TransactionOutcome>) -> Result -where - E: From, -{ - use sp_io::storage::{commit_transaction, rollback_transaction, start_transaction}; - use TransactionOutcome::*; - - let _guard = transaction_level_tracker::inc_transaction_level() - .map_err(|()| TransactionalError::LimitReached.into())?; - - start_transaction(); - - match f() { - Commit(res) => { - commit_transaction(); - res - }, - Rollback(res) => { - rollback_transaction(); - res - }, - } -} - -/// Same as [`with_transaction`] but without a limit check on nested transactional layers. -/// -/// This is mostly for backwards compatibility before there was a transactional layer limit. -/// It is recommended to only use [`with_transaction`] to avoid users from generating too many -/// transactional layers. -pub fn with_transaction_unchecked(f: impl FnOnce() -> TransactionOutcome) -> R { - use sp_io::storage::{commit_transaction, rollback_transaction, start_transaction}; - use TransactionOutcome::*; - - let maybe_guard = transaction_level_tracker::inc_transaction_level(); - - if maybe_guard.is_err() { - log::warn!( - "The transactional layer limit has been reached, and new transactional layers are being - spawned with `with_transaction_unchecked`. This could be caused by someone trying to - attack your chain, and you should investigate usage of `with_transaction_unchecked` and - potentially migrate to `with_transaction`, which enforces a transactional limit.", - ); - } - - start_transaction(); - - match f() { - Commit(res) => { - commit_transaction(); - res - }, - Rollback(res) => { - rollback_transaction(); - res - }, - } -} - /// A trait for working with macro-generated storage values under the substrate storage API. /// /// Details on implementation can be found at [`generator::StorageValue`]. @@ -1473,13 +1345,12 @@ pub fn storage_prefix(pallet_name: &[u8], storage_name: &[u8]) -> [u8; 32] { #[cfg(test)] mod test { use super::*; - use crate::{assert_noop, assert_ok, hash::Identity, Twox128}; + use crate::{assert_ok, hash::Identity, Twox128}; use bounded_vec::BoundedVec; use frame_support::traits::ConstU32; use generator::StorageValue as _; use sp_core::hashing::twox_128; use sp_io::TestExternalities; - use sp_runtime::DispatchResult; use weak_bounded_vec::WeakBoundedVec; #[test] @@ -1590,71 +1461,6 @@ mod test { }); } - #[test] - fn is_transactional_should_return_false() { - TestExternalities::default().execute_with(|| { - assert!(!is_transactional()); - }); - } - - #[test] - fn is_transactional_should_not_error_in_with_transaction() { - TestExternalities::default().execute_with(|| { - assert_ok!(with_transaction(|| -> TransactionOutcome { - assert!(is_transactional()); - TransactionOutcome::Commit(Ok(())) - })); - - assert_noop!( - with_transaction(|| -> TransactionOutcome { - assert!(is_transactional()); - TransactionOutcome::Rollback(Err("revert".into())) - }), - "revert" - ); - }); - } - - fn recursive_transactional(num: u32) -> DispatchResult { - if num == 0 { - return Ok(()) - } - - with_transaction(|| -> TransactionOutcome { - let res = recursive_transactional(num - 1); - TransactionOutcome::Commit(res) - }) - } - - #[test] - fn transaction_limit_should_work() { - TestExternalities::default().execute_with(|| { - assert_eq!(transaction_level_tracker::get_transaction_level(), 0); - - assert_ok!(with_transaction(|| -> TransactionOutcome { - assert_eq!(transaction_level_tracker::get_transaction_level(), 1); - TransactionOutcome::Commit(Ok(())) - })); - - assert_ok!(with_transaction(|| -> TransactionOutcome { - assert_eq!(transaction_level_tracker::get_transaction_level(), 1); - let res = with_transaction(|| -> TransactionOutcome { - assert_eq!(transaction_level_tracker::get_transaction_level(), 2); - TransactionOutcome::Commit(Ok(())) - }); - TransactionOutcome::Commit(res) - })); - - assert_ok!(recursive_transactional(255)); - assert_noop!( - recursive_transactional(256), - sp_runtime::TransactionalError::LimitReached - ); - - assert_eq!(transaction_level_tracker::get_transaction_level(), 0); - }); - } - #[test] fn key_prefix_iterator_works() { TestExternalities::default().execute_with(|| { diff --git a/frame/support/src/storage/transactional.rs b/frame/support/src/storage/transactional.rs new file mode 100644 index 0000000000000..d1c59d44e2581 --- /dev/null +++ b/frame/support/src/storage/transactional.rs @@ -0,0 +1,232 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Provides functionality around the transaction storage. +//! +//! Transactional storage provides functionality to run an entire code block +//! in a storage transaction. This means that either the entire changes to the +//! storage are committed or everything is thrown away. This simplifies the +//! writing of functionality that may bail at any point of operation. Otherwise +//! you would need to first verify all storage accesses and then do the storage +//! modifications. +//! +//! [`with_transaction`] provides a way to run a given closure in a transactional context. + +use sp_io::storage::{commit_transaction, rollback_transaction, start_transaction}; +use sp_runtime::{DispatchError, TransactionOutcome, TransactionalError}; + +/// The type that is being used to store the current number of active layers. +type Layer = u32; +/// The key that is holds the current number of active layers. +const TRANSACTION_LEVEL_KEY: &[u8] = b":transaction_level:"; +/// The maximum number of nested layers. +const TRANSACTIONAL_LIMIT: Layer = 255; + +/// Returns the current number of nested transactional layers. +fn get_transaction_level() -> Layer { + crate::storage::unhashed::get_or_default::(TRANSACTION_LEVEL_KEY) +} + +/// Set the current number of nested transactional layers. +fn set_transaction_level(level: Layer) { + crate::storage::unhashed::put::(TRANSACTION_LEVEL_KEY, &level); +} + +/// Kill the transactional layers storage. +fn kill_transaction_level() { + crate::storage::unhashed::kill(TRANSACTION_LEVEL_KEY); +} + +/// Increments the transaction level. Returns an error if levels go past the limit. +/// +/// Returns a guard that when dropped decrements the transaction level automatically. +fn inc_transaction_level() -> Result { + let existing_levels = get_transaction_level(); + if existing_levels >= TRANSACTIONAL_LIMIT { + return Err(()) + } + // Cannot overflow because of check above. + set_transaction_level(existing_levels + 1); + Ok(StorageLayerGuard) +} + +fn dec_transaction_level() { + let existing_levels = get_transaction_level(); + if existing_levels == 0 { + log::warn!( + "We are underflowing with calculating transactional levels. Not great, but let's not panic...", + ); + } else if existing_levels == 1 { + // Don't leave any trace of this storage item. + kill_transaction_level(); + } else { + // Cannot underflow because of checks above. + set_transaction_level(existing_levels - 1); + } +} + +struct StorageLayerGuard; + +impl Drop for StorageLayerGuard { + fn drop(&mut self) { + dec_transaction_level() + } +} + +/// Check if the current call is within a transactional layer. +pub fn is_transactional() -> bool { + get_transaction_level() > 0 +} + +/// Execute the supplied function in a new storage transaction. +/// +/// All changes to storage performed by the supplied function are discarded if the returned +/// outcome is `TransactionOutcome::Rollback`. +/// +/// Transactions can be nested up to `TRANSACTIONAL_LIMIT` times; more than that will result in an +/// error. +/// +/// Commits happen to the parent transaction. +pub fn with_transaction(f: impl FnOnce() -> TransactionOutcome>) -> Result +where + E: From, +{ + // This needs to happen before `start_transaction` below. + // Otherwise we may rollback the increase, then decrease as the guard goes out of scope + // and then end in some bad state. + let _guard = inc_transaction_level().map_err(|()| TransactionalError::LimitReached.into())?; + + start_transaction(); + + match f() { + TransactionOutcome::Commit(res) => { + commit_transaction(); + res + }, + TransactionOutcome::Rollback(res) => { + rollback_transaction(); + res + }, + } +} + +/// Same as [`with_transaction`] but without a limit check on nested transactional layers. +/// +/// This is mostly for backwards compatibility before there was a transactional layer limit. +/// It is recommended to only use [`with_transaction`] to avoid users from generating too many +/// transactional layers. +pub fn with_transaction_unchecked(f: impl FnOnce() -> TransactionOutcome) -> R { + // This needs to happen before `start_transaction` below. + // Otherwise we may rollback the increase, then decrease as the guard goes out of scope + // and then end in some bad state. + let maybe_guard = inc_transaction_level(); + + if maybe_guard.is_err() { + log::warn!( + "The transactional layer limit has been reached, and new transactional layers are being + spawned with `with_transaction_unchecked`. This could be caused by someone trying to + attack your chain, and you should investigate usage of `with_transaction_unchecked` and + potentially migrate to `with_transaction`, which enforces a transactional limit.", + ); + } + + start_transaction(); + + match f() { + TransactionOutcome::Commit(res) => { + commit_transaction(); + res + }, + TransactionOutcome::Rollback(res) => { + rollback_transaction(); + res + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{assert_noop, assert_ok}; + use sp_io::TestExternalities; + use sp_runtime::DispatchResult; + + #[test] + fn is_transactional_should_return_false() { + TestExternalities::default().execute_with(|| { + assert!(!is_transactional()); + }); + } + + #[test] + fn is_transactional_should_not_error_in_with_transaction() { + TestExternalities::default().execute_with(|| { + assert_ok!(with_transaction(|| -> TransactionOutcome { + assert!(is_transactional()); + TransactionOutcome::Commit(Ok(())) + })); + + assert_noop!( + with_transaction(|| -> TransactionOutcome { + assert!(is_transactional()); + TransactionOutcome::Rollback(Err("revert".into())) + }), + "revert" + ); + }); + } + + fn recursive_transactional(num: u32) -> DispatchResult { + if num == 0 { + return Ok(()) + } + + with_transaction(|| -> TransactionOutcome { + let res = recursive_transactional(num - 1); + TransactionOutcome::Commit(res) + }) + } + + #[test] + fn transaction_limit_should_work() { + TestExternalities::default().execute_with(|| { + assert_eq!(get_transaction_level(), 0); + + assert_ok!(with_transaction(|| -> TransactionOutcome { + assert_eq!(get_transaction_level(), 1); + TransactionOutcome::Commit(Ok(())) + })); + + assert_ok!(with_transaction(|| -> TransactionOutcome { + assert_eq!(get_transaction_level(), 1); + let res = with_transaction(|| -> TransactionOutcome { + assert_eq!(get_transaction_level(), 2); + TransactionOutcome::Commit(Ok(())) + }); + TransactionOutcome::Commit(res) + })); + + assert_ok!(recursive_transactional(255)); + assert_noop!( + recursive_transactional(256), + sp_runtime::TransactionalError::LimitReached + ); + + assert_eq!(get_transaction_level(), 0); + }); + } +} From 9bf7aaa2f5411db7f6efd5aa00360d04f09d1b53 Mon Sep 17 00:00:00 2001 From: Zhenghao Lu <54395432+EmisonLu@users.noreply.github.com> Date: Tue, 5 Apr 2022 16:39:46 +0800 Subject: [PATCH 0665/1472] Correct a spelling mistake (#11167) --- client/executor/wasmtime/src/runtime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index cbe1359d28a6c..fa3b567cc0abc 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -386,7 +386,7 @@ pub struct Semantics { // I.e. if [`CodeSupplyMode::Verbatim`] is used. pub fast_instance_reuse: bool, - /// Specifiying `Some` will enable deterministic stack height. That is, all executor + /// Specifying `Some` will enable deterministic stack height. That is, all executor /// invocations will reach stack overflow at the exactly same point across different wasmtime /// versions and architectures. /// From 585e7e8cc2a24874898e6490ea96462db7d9c3ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 5 Apr 2022 19:01:45 +0200 Subject: [PATCH 0666/1472] Upgrade to wasmer 2.2 (#11168) --- Cargo.lock | 389 ++++++++++++------ client/executor/common/Cargo.toml | 5 +- client/executor/common/src/sandbox.rs | 2 + .../common/src/sandbox/wasmer_backend.rs | 6 +- .../src/communication/gossip.rs | 2 +- client/finality-grandpa/src/justification.rs | 2 +- 6 files changed, 270 insertions(+), 136 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 23f11860ca6f8..17931984c41e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -795,6 +795,27 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytecheck" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314889ea31cda264cb7c3d6e6e5c9415a987ecb0e72c17c00d36fbb881d34abe" +dependencies = [ + "bytecheck_derive", + "ptr_meta", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a2b3b92c135dae665a6f760205b89187638e83bed17ef3e44e83c712cf30600" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "byteorder" version = "1.3.4" @@ -1140,11 +1161,11 @@ checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" [[package]] name = "cranelift-bforest" -version = "0.68.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9221545c0507dc08a62b2d8b5ffe8e17ac580b0a74d1813b496b8d70b070fbd0" +checksum = "7e6bea67967505247f54fa2c85cf4f6e0e31c4e5692c9b70e4ae58e339067333" dependencies = [ - "cranelift-entity 0.68.0", + "cranelift-entity 0.76.0", ] [[package]] @@ -1158,21 +1179,19 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.68.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9936ea608b6cd176f107037f6adbb4deac933466fc7231154f96598b2d3ab1" +checksum = "48194035d2752bdd5bdae429e3ab88676e95f52a2b1355a5d4e809f9e39b1d74" dependencies = [ - "byteorder", - "cranelift-bforest 0.68.0", - "cranelift-codegen-meta 0.68.0", - "cranelift-codegen-shared 0.68.0", - "cranelift-entity 0.68.0", - "gimli 0.22.0", + "cranelift-bforest 0.76.0", + "cranelift-codegen-meta 0.76.0", + "cranelift-codegen-shared 0.76.0", + "cranelift-entity 0.76.0", + "gimli 0.25.0", "log 0.4.14", "regalloc 0.0.31", "smallvec 1.8.0", - "target-lexicon 0.11.2", - "thiserror", + "target-lexicon", ] [[package]] @@ -1189,17 +1208,17 @@ dependencies = [ "log 0.4.14", "regalloc 0.0.33", "smallvec 1.8.0", - "target-lexicon 0.12.0", + "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.68.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef2b2768568306540f4c8db3acce9105534d34c4a1e440529c1e702d7f8c8d7" +checksum = "976efb22fcab4f2cd6bd4e9913764616a54d895c1a23530128d04e03633c555f" dependencies = [ - "cranelift-codegen-shared 0.68.0", - "cranelift-entity 0.68.0", + "cranelift-codegen-shared 0.76.0", + "cranelift-entity 0.76.0", ] [[package]] @@ -1213,9 +1232,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.68.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6759012d6d19c4caec95793f052613e9d4113e925e7f14154defbac0f1d4c938" +checksum = "9dabb5fe66e04d4652e434195b45ae65b5c8172d520247b8f66d8df42b2b45dc" [[package]] name = "cranelift-codegen-shared" @@ -1225,12 +1244,9 @@ checksum = "981da52d8f746af1feb96290c83977ff8d41071a7499e991d8abae0d4869f564" [[package]] name = "cranelift-entity" -version = "0.68.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86badbce14e15f52a45b666b38abe47b204969dd7f8fb7488cb55dd46b361fa6" -dependencies = [ - "serde", -] +checksum = "3329733e4d4b8e91c809efcaa4faee80bf66f20164e3dd16d707346bd3494799" [[package]] name = "cranelift-entity" @@ -1243,14 +1259,14 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.68.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b608bb7656c554d0a4cf8f50c7a10b857e80306f6ff829ad6d468a7e2323c8d8" +checksum = "279afcc0d3e651b773f94837c3d581177b348c8d69e928104b2e9fccb226f921" dependencies = [ - "cranelift-codegen 0.68.0", + "cranelift-codegen 0.76.0", "log 0.4.14", "smallvec 1.8.0", - "target-lexicon 0.11.2", + "target-lexicon", ] [[package]] @@ -1262,7 +1278,7 @@ dependencies = [ "cranelift-codegen 0.80.0", "log 0.4.14", "smallvec 1.8.0", - "target-lexicon 0.12.0", + "target-lexicon", ] [[package]] @@ -1273,7 +1289,7 @@ checksum = "166028ca0343a6ee7bddac0e70084e142b23f99c701bd6f6ea9123afac1a7a46" dependencies = [ "cranelift-codegen 0.80.0", "libc", - "target-lexicon 0.12.0", + "target-lexicon", ] [[package]] @@ -1757,9 +1773,9 @@ checksum = "21e50f3adc76d6a43f5ed73b698a87d0760ca74617f60f7c3b879003536fdd28" [[package]] name = "dynasm" -version = "1.1.0" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc2d9a5e44da60059bd38db2d05cbb478619541b8c79890547861ec1e3194f0" +checksum = "add9a102807b524ec050363f09e06f1504214b0e1c7797f64261c891022dce8b" dependencies = [ "bitflags", "byteorder", @@ -1772,13 +1788,13 @@ dependencies = [ [[package]] name = "dynasmrt" -version = "1.1.0" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42276e3f205fe63887cca255aa9a65a63fb72764c30b9a6252a7c7e46994f689" +checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" dependencies = [ "byteorder", "dynasm", - "memmap2 0.2.1", + "memmap2 0.5.0", ] [[package]] @@ -1851,6 +1867,26 @@ dependencies = [ "syn", ] +[[package]] +name = "enum-iterator" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "enumflags2" version = "0.6.4" @@ -2676,9 +2712,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.22.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" +checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" dependencies = [ "fallible-iterator", "indexmap", @@ -3684,16 +3720,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "libloading" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" -dependencies = [ - "cfg-if 1.0.0", - "winapi 0.3.9", -] - [[package]] name = "libloading" version = "0.7.0" @@ -4343,6 +4369,27 @@ dependencies = [ "value-bag", ] +[[package]] +name = "loupe" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d" +dependencies = [ + "indexmap", + "loupe-derive", + "rustversion", +] + +[[package]] +name = "loupe-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "lru" version = "0.6.6" @@ -5327,21 +5374,23 @@ dependencies = [ [[package]] name = "object" -version = "0.22.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" dependencies = [ "crc32fast", "indexmap", + "memchr", ] [[package]] name = "object" -version = "0.27.1" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456" dependencies = [ "crc32fast", + "hashbrown 0.11.2", "indexmap", "memchr", ] @@ -7365,6 +7414,26 @@ dependencies = [ "cc", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -7776,6 +7845,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "region" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi 0.3.9", +] + [[package]] name = "remote-externalities" version = "0.10.0-dev" @@ -7804,6 +7885,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" +dependencies = [ + "bytecheck", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -7835,6 +7925,31 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rkyv" +version = "0.7.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f08c8062c1fe1253064043b8fc07bfea1b9702b71b4a86c11ea3588183b12e1" +dependencies = [ + "bytecheck", + "hashbrown 0.12.0", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e289706df51226e84814bf6ba1a9e1013112ae29bc7a9878f73fce360520c403" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "rocksdb" version = "0.18.0" @@ -8524,7 +8639,6 @@ dependencies = [ "thiserror", "wasm-instrument", "wasmer", - "wasmer-compiler-singlepass", "wasmi", ] @@ -9257,6 +9371,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "sec1" version = "0.2.1" @@ -10855,15 +10975,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95" - -[[package]] -name = "target-lexicon" -version = "0.12.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834" +checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1" [[package]] name = "tempfile" @@ -11232,6 +11346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ "cfg-if 1.0.0", + "log 0.4.14", "pin-project-lite 0.2.6", "tracing-attributes", "tracing-core", @@ -11471,9 +11586,9 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "digest 0.10.3", - "rand 0.8.4", + "rand 0.6.5", "static_assertions", ] @@ -11820,21 +11935,25 @@ dependencies = [ [[package]] name = "wasmer" -version = "1.0.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a70cfae554988d904d64ca17ab0e7cd652ee5c8a0807094819c1ea93eb9d6866" +checksum = "f727a39e7161f7438ddb8eafe571b67c576a8c2fb459f666d9053b5bba4afdea" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "indexmap", + "js-sys", + "loupe", "more-asserts", - "target-lexicon 0.11.2", + "target-lexicon", "thiserror", + "wasm-bindgen", "wasmer-compiler", "wasmer-compiler-cranelift", + "wasmer-compiler-singlepass", "wasmer-derive", "wasmer-engine", - "wasmer-engine-jit", - "wasmer-engine-native", + "wasmer-engine-dylib", + "wasmer-engine-universal", "wasmer-types", "wasmer-vm", "wat", @@ -11843,34 +11962,38 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "1.0.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b7732a9cab472bd921d5a0c422f45b3d03f62fa2c40a89e0770cef6d47e383e" +checksum = "4e9951599222eb12bd13d4d91bcded0a880e4c22c2dfdabdf5dc7e5e803b7bf3" dependencies = [ "enumset", + "loupe", + "rkyv", "serde", "serde_bytes", "smallvec 1.8.0", - "target-lexicon 0.11.2", + "target-lexicon", "thiserror", "wasmer-types", "wasmer-vm", - "wasmparser 0.65.0", + "wasmparser 0.78.2", ] [[package]] name = "wasmer-compiler-cranelift" -version = "1.0.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb9395f094e1d81534f4c5e330ed4cdb424e8df870d29ad585620284f5fddb" +checksum = "44c83273bce44e668f3a2b9ccb7f1193db918b1d6806f64acc5ff71f6ece5f20" dependencies = [ - "cranelift-codegen 0.68.0", - "cranelift-frontend 0.68.0", - "gimli 0.22.0", + "cranelift-codegen 0.76.0", + "cranelift-entity 0.76.0", + "cranelift-frontend 0.76.0", + "gimli 0.25.0", + "loupe", "more-asserts", "rayon", - "serde", "smallvec 1.8.0", + "target-lexicon", "tracing", "wasmer-compiler", "wasmer-types", @@ -11879,17 +12002,17 @@ dependencies = [ [[package]] name = "wasmer-compiler-singlepass" -version = "1.0.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426ae6ef0f606ca815510f3e2ef6f520e217514bfb7a664defe180b9a9e75d07" +checksum = "5432e993840cdb8e6875ddc8c9eea64e7a129579b4706bd91b8eb474d9c4a860" dependencies = [ "byteorder", "dynasm", "dynasmrt", "lazy_static", + "loupe", "more-asserts", "rayon", - "serde", "smallvec 1.8.0", "wasmer-compiler", "wasmer-types", @@ -11898,9 +12021,9 @@ dependencies = [ [[package]] name = "wasmer-derive" -version = "1.0.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b86dcd2c3efdb8390728a2b56f762db07789aaa5aa872a9dc776ba3a7912ed" +checksum = "458dbd9718a837e6dbc52003aef84487d79eedef5fa28c7d28b6784be98ac08e" dependencies = [ "proc-macro-error", "proc-macro2", @@ -11910,19 +12033,20 @@ dependencies = [ [[package]] name = "wasmer-engine" -version = "1.0.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efe4667d6bd888f26ae8062a63a9379fa697415b4b4e380f33832e8418fd71b5" +checksum = "6ed603a6d037ebbb14014d7f739ae996a78455a4b86c41cfa4e81c590a1253b9" dependencies = [ "backtrace", - "bincode", + "enumset", "lazy_static", - "memmap2 0.2.1", + "loupe", + "memmap2 0.5.0", "more-asserts", "rustc-demangle", "serde", "serde_bytes", - "target-lexicon 0.11.2", + "target-lexicon", "thiserror", "wasmer-compiler", "wasmer-types", @@ -11930,51 +12054,57 @@ dependencies = [ ] [[package]] -name = "wasmer-engine-jit" -version = "1.0.2" +name = "wasmer-engine-dylib" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26770be802888011b4a3072f2a282fc2faa68aa48c71b3db6252a3937a85f3da" +checksum = "ccd7fdc60e252a795c849b3f78a81a134783051407e7e279c10b7019139ef8dc" dependencies = [ - "bincode", - "cfg-if 0.1.10", - "region", + "cfg-if 1.0.0", + "enum-iterator", + "enumset", + "leb128", + "libloading 0.7.0", + "loupe", + "object 0.28.3", + "rkyv", "serde", - "serde_bytes", + "tempfile", + "tracing", "wasmer-compiler", "wasmer-engine", + "wasmer-object", "wasmer-types", "wasmer-vm", - "winapi 0.3.9", + "which", ] [[package]] -name = "wasmer-engine-native" -version = "1.0.2" +name = "wasmer-engine-universal" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb4083a6c69f2cd4b000b82a80717f37c6cc2e536aee3a8ffe9af3edc276a8b" +checksum = "dcff0cd2c01a8de6009fd863b14ea883132a468a24f2d2ee59dc34453d3a31b5" dependencies = [ - "bincode", - "cfg-if 0.1.10", + "cfg-if 1.0.0", + "enum-iterator", + "enumset", "leb128", - "libloading 0.6.7", - "serde", - "tempfile", - "tracing", + "loupe", + "region 3.0.0", + "rkyv", "wasmer-compiler", "wasmer-engine", - "wasmer-object", "wasmer-types", "wasmer-vm", - "which", + "winapi 0.3.9", ] [[package]] name = "wasmer-object" -version = "1.0.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf8e0c12b82ff81ebecd30d7e118be5fec871d6de885a90eeb105df0a769a7b" +checksum = "24ce18ac2877050e59580d27ee1a88f3192d7a31e77fbba0852abc7888d6e0b5" dependencies = [ - "object 0.22.0", + "object 0.28.3", "thiserror", "wasmer-compiler", "wasmer-types", @@ -11982,29 +12112,34 @@ dependencies = [ [[package]] name = "wasmer-types" -version = "1.0.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f4ac28c2951cd792c18332f03da523ed06b170f5cf6bb5b1bdd7e36c2a8218" +checksum = "659fa3dd6c76f62630deff4ac8c7657b07f0b1e4d7e0f8243a552b9d9b448e24" dependencies = [ - "cranelift-entity 0.68.0", + "indexmap", + "loupe", + "rkyv", "serde", "thiserror", ] [[package]] name = "wasmer-vm" -version = "1.0.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7635ba0b6d2fd325f588d69a950ad9fa04dddbf6ad08b6b2a183146319bf6ae" +checksum = "afdc46158517c2769f9938bc222a7d41b3bb330824196279d8aa2d667cd40641" dependencies = [ "backtrace", "cc", - "cfg-if 0.1.10", + "cfg-if 1.0.0", + "enum-iterator", "indexmap", "libc", + "loupe", "memoffset", "more-asserts", - "region", + "region 3.0.0", + "rkyv", "serde", "thiserror", "wasmer-types", @@ -12039,9 +12174,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.65.0" +version = "0.78.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc2fe6350834b4e528ba0901e7aa405d78b89dc1fa3145359eb4de0e323fcf" +checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" [[package]] name = "wasmparser" @@ -12068,10 +12203,10 @@ dependencies = [ "paste 1.0.6", "psm", "rayon", - "region", + "region 2.2.0", "rustc-demangle", "serde", - "target-lexicon 0.12.0", + "target-lexicon", "wasmparser 0.81.0", "wasmtime-cache", "wasmtime-cranelift", @@ -12117,7 +12252,7 @@ dependencies = [ "log 0.4.14", "more-asserts", "object 0.27.1", - "target-lexicon 0.12.0", + "target-lexicon", "thiserror", "wasmparser 0.81.0", "wasmtime-environ", @@ -12137,7 +12272,7 @@ dependencies = [ "more-asserts", "object 0.27.1", "serde", - "target-lexicon 0.12.0", + "target-lexicon", "thiserror", "wasmparser 0.81.0", "wasmtime-types", @@ -12155,10 +12290,10 @@ dependencies = [ "cfg-if 1.0.0", "gimli 0.26.1", "object 0.27.1", - "region", + "region 2.2.0", "rustix", "serde", - "target-lexicon 0.12.0", + "target-lexicon", "thiserror", "wasmtime-environ", "wasmtime-runtime", @@ -12183,7 +12318,7 @@ dependencies = [ "memoffset", "more-asserts", "rand 0.8.4", - "region", + "region 2.2.0", "rustix", "thiserror", "wasmtime-environ", diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 9282fe3b03dd6..149d9fdc236cd 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -24,13 +24,10 @@ sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/ sp-serializer = { version = "4.0.0-dev", path = "../../../primitives/serializer" } thiserror = "1.0.30" environmental = "1.1.3" - -wasmer = { version = "1.0", optional = true } -wasmer-compiler-singlepass = { version = "1.0", optional = true } +wasmer = { version = "2.2", optional = true, features = ["singlepass"] } [features] default = [] wasmer-sandbox = [ "wasmer", - "wasmer-compiler-singlepass", ] diff --git a/client/executor/common/src/sandbox.rs b/client/executor/common/src/sandbox.rs index 3f46ec53bdfe4..a2c1f602b1c9a 100644 --- a/client/executor/common/src/sandbox.rs +++ b/client/executor/common/src/sandbox.rs @@ -251,6 +251,8 @@ pub enum InstantiationError { /// Module is well-formed, instantiated and linked, but while executing the start function /// a trap was generated. StartTrapped, + /// The code was compiled with a CPU feature not available on the host. + CpuFeature, } fn decode_environment_definition( diff --git a/client/executor/common/src/sandbox/wasmer_backend.rs b/client/executor/common/src/sandbox/wasmer_backend.rs index 904afc9470400..44b43757148de 100644 --- a/client/executor/common/src/sandbox/wasmer_backend.rs +++ b/client/executor/common/src/sandbox/wasmer_backend.rs @@ -43,9 +43,8 @@ pub struct Backend { impl Backend { pub fn new() -> Self { - let compiler = wasmer_compiler_singlepass::Singlepass::default(); - - Backend { store: wasmer::Store::new(&wasmer::JIT::new(compiler).engine()) } + let compiler = wasmer::Singlepass::default(); + Backend { store: wasmer::Store::new(&wasmer::Universal::new(compiler).engine()) } } } @@ -191,6 +190,7 @@ pub fn instantiate( wasmer::InstantiationError::Start(_) => InstantiationError::StartTrapped, wasmer::InstantiationError::HostEnvInitialization(_) => InstantiationError::EnvironmentDefinitionCorrupted, + wasmer::InstantiationError::CpuFeature(_) => InstantiationError::CpuFeature, }) })?; diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 7ac4066780d0f..c39e2e82a621e 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -799,7 +799,7 @@ impl Inner { Some(ref mut v) => if v.set_id == set_id { let diff_authorities = self.authorities.iter().collect::>() != - authorities.iter().collect(); + authorities.iter().collect::>(); if diff_authorities { debug!(target: "afg", diff --git a/client/finality-grandpa/src/justification.rs b/client/finality-grandpa/src/justification.rs index 5ee5f278ed8b6..39f24cb8ea57d 100644 --- a/client/finality-grandpa/src/justification.rs +++ b/client/finality-grandpa/src/justification.rs @@ -185,7 +185,7 @@ impl GrandpaJustification { } } - let ancestry_hashes = + let ancestry_hashes: HashSet<_> = self.votes_ancestries.iter().map(|h: &Block::Header| h.hash()).collect(); if visited_hashes != ancestry_hashes { From d4ca1fdd6c8ab9c43c4349761b0b63e47be1081b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Apr 2022 21:14:49 +0000 Subject: [PATCH 0667/1472] Bump enumflags2 from 0.6.4 to 0.7.4 (#11108) * Bump enumflags2 from 0.6.4 to 0.7.4 Bumps [enumflags2](https://github.com/NieDzejkob/enumflags2) from 0.6.4 to 0.7.4. - [Release notes](https://github.com/NieDzejkob/enumflags2/releases) - [Commits](https://github.com/NieDzejkob/enumflags2/compare/v0.6.4...v0.7.4) --- updated-dependencies: - dependency-name: enumflags2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * use `#[bitflags]` attribute macro Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn Tabrizi --- Cargo.lock | 12 ++++++------ frame/identity/Cargo.toml | 2 +- frame/identity/src/types.rs | 5 +++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 17931984c41e4..bd6db80272113 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1889,18 +1889,18 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.6.4" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0" +checksum = "1b3ab37dc79652c9d85f1f7b6070d77d321d2467f5fe7b00d6b7a86c57b092ae" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.6.4" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" +checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ "proc-macro2", "quote", @@ -11586,9 +11586,9 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "digest 0.10.3", - "rand 0.6.5", + "rand 0.8.4", "static_assertions", ] diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 7ebfda7cf176f..5dff7acc73e26 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -enumflags2 = { version = "0.6.2" } +enumflags2 = { version = "0.7.4" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/identity/src/types.rs b/frame/identity/src/types.rs index cb79ace98d81c..18fc54c941cbd 100644 --- a/frame/identity/src/types.rs +++ b/frame/identity/src/types.rs @@ -17,7 +17,7 @@ use super::*; use codec::{Decode, Encode, MaxEncodedLen}; -use enumflags2::BitFlags; +use enumflags2::{bitflags, BitFlags}; use frame_support::{ traits::{ConstU32, Get}, BoundedVec, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, @@ -230,8 +230,9 @@ impl Date: Wed, 6 Apr 2022 09:55:55 +0200 Subject: [PATCH 0668/1472] Change default execution strategies to `Wasm` (#11170) This pr changes all default execution strategies to `Wasm`. This is basically a deprecation of the native runtime. While the native runtime isn't removed and can still be used, it will not be used anymore by default. This will also improve the usage for people who want to run random commits, which most often forget to run with `--execution wasm`. Otherwise they often run into storage root mismatches because of using the native runtime. --- client/cli/src/arg_enums.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index df4b68ff5c325..a09b7f824c7ba 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -281,14 +281,14 @@ impl Into for SyncMode { } /// Default value for the `--execution-syncing` parameter. -pub const DEFAULT_EXECUTION_SYNCING: ExecutionStrategy = ExecutionStrategy::NativeElseWasm; +pub const DEFAULT_EXECUTION_SYNCING: ExecutionStrategy = ExecutionStrategy::Wasm; /// Default value for the `--execution-import-block` parameter. -pub const DEFAULT_EXECUTION_IMPORT_BLOCK: ExecutionStrategy = ExecutionStrategy::NativeElseWasm; +pub const DEFAULT_EXECUTION_IMPORT_BLOCK: ExecutionStrategy = ExecutionStrategy::Wasm; /// Default value for the `--execution-import-block` parameter when the node is a validator. pub const DEFAULT_EXECUTION_IMPORT_BLOCK_VALIDATOR: ExecutionStrategy = ExecutionStrategy::Wasm; /// Default value for the `--execution-block-construction` parameter. pub const DEFAULT_EXECUTION_BLOCK_CONSTRUCTION: ExecutionStrategy = ExecutionStrategy::Wasm; /// Default value for the `--execution-offchain-worker` parameter. -pub const DEFAULT_EXECUTION_OFFCHAIN_WORKER: ExecutionStrategy = ExecutionStrategy::Native; +pub const DEFAULT_EXECUTION_OFFCHAIN_WORKER: ExecutionStrategy = ExecutionStrategy::Wasm; /// Default value for the `--execution-other` parameter. -pub const DEFAULT_EXECUTION_OTHER: ExecutionStrategy = ExecutionStrategy::Native; +pub const DEFAULT_EXECUTION_OTHER: ExecutionStrategy = ExecutionStrategy::Wasm; From 184d29caf8302053fac74ad74cd68bf43572108e Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 6 Apr 2022 10:19:14 +0200 Subject: [PATCH 0669/1472] Fix fork-tree descendent check (#11150) * Fix fork-tree descendent check * Add test assertions for the fix * Improve documentation * Nitpicks --- utils/fork-tree/src/lib.rs | 76 +++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/utils/fork-tree/src/lib.rs b/utils/fork-tree/src/lib.rs index 1d9b39f7dc04b..c23a4f55f44a1 100644 --- a/utils/fork-tree/src/lib.rs +++ b/utils/fork-tree/src/lib.rs @@ -509,14 +509,14 @@ where } /// Checks if any node in the tree is finalized by either finalizing the - /// node itself or a child node that's not in the tree, guaranteeing that - /// the node being finalized isn't a descendent of any of the node's - /// children. Returns `Some(true)` if the node being finalized is a root, - /// `Some(false)` if the node being finalized is not a root, and `None` if - /// no node in the tree is finalized. The given `predicate` is checked on - /// the prospective finalized root and must pass for finalization to occur. - /// The given function `is_descendent_of` should return `true` if the second - /// hash (target) is a descendent of the first hash (base). + /// node itself or a node's descendent that's not in the tree, guaranteeing + /// that the node being finalized isn't a descendent of (or equal to) any of + /// the node's children. Returns `Some(true)` if the node being finalized is + /// a root, `Some(false)` if the node being finalized is not a root, and + /// `None` if no node in the tree is finalized. The given `predicate` is + /// checked on the prospective finalized root and must pass for finalization + /// to occur. The given function `is_descendent_of` should return `true` if + /// the second hash (target) is a descendent of the first hash (base). pub fn finalizes_any_with_descendent_if( &self, hash: &H, @@ -541,8 +541,10 @@ where for node in self.node_iter() { if predicate(&node.data) { if node.hash == *hash || is_descendent_of(&node.hash, hash)? { - for node in node.children.iter() { - if node.number <= number && is_descendent_of(&node.hash, &hash)? { + for child in node.children.iter() { + if child.number <= number && + (child.hash == *hash || is_descendent_of(&child.hash, hash)?) + { return Err(Error::UnfinalizedAncestor) } } @@ -556,12 +558,12 @@ where } /// Finalize a root in the tree by either finalizing the node itself or a - /// child node that's not in the tree, guaranteeing that the node being - /// finalized isn't a descendent of any of the root's children. The given - /// `predicate` is checked on the prospective finalized root and must pass for - /// finalization to occur. The given function `is_descendent_of` should - /// return `true` if the second hash (target) is a descendent of the first - /// hash (base). + /// node's descendent that's not in the tree, guaranteeing that the node + /// being finalized isn't a descendent of (or equal to) any of the root's + /// children. The given `predicate` is checked on the prospective finalized + /// root and must pass for finalization to occur. The given function + /// `is_descendent_of` should return `true` if the second hash (target) is a + /// descendent of the first hash (base). pub fn finalize_with_descendent_if( &mut self, hash: &H, @@ -587,8 +589,10 @@ where for (i, root) in self.roots.iter().enumerate() { if predicate(&root.data) { if root.hash == *hash || is_descendent_of(&root.hash, hash)? { - for node in root.children.iter() { - if node.number <= number && is_descendent_of(&node.hash, &hash)? { + for child in root.children.iter() { + if child.number <= number && + (child.hash == *hash || is_descendent_of(&child.hash, hash)?) + { return Err(Error::UnfinalizedAncestor) } } @@ -606,12 +610,11 @@ where node.data }); - // if the block being finalized is earlier than a given root, then it - // must be its ancestor, otherwise we can prune the root. if there's a - // root at the same height then the hashes must match. otherwise the - // node being finalized is higher than the root so it must be its - // descendent (in this case the node wasn't finalized earlier presumably - // because the predicate didn't pass). + // Retain only roots that are descendents of the finalized block (this + // happens if the node has been properly finalized) or that are + // ancestors (or equal) to the finalized block (in this case the node + // wasn't finalized earlier presumably because the predicate didn't + // pass). let mut changed = false; let roots = std::mem::take(&mut self.roots); @@ -1275,18 +1278,31 @@ mod test { Ok(None), ); + // finalizing "D" is not allowed since it is not a root. + assert_eq!( + tree.finalize_with_descendent_if(&"D", 10, &is_descendent_of, |c| c.effective <= 10), + Err(Error::UnfinalizedAncestor) + ); + // finalizing "D" will finalize a block from the tree, but it can't be applied yet - // since it is not a root change + // since it is not a root change. assert_eq!( tree.finalizes_any_with_descendent_if(&"D", 10, &is_descendent_of, |c| c.effective == - 10,), + 10), Ok(Some(false)), ); + // finalizing "E" is not allowed since there are not finalized anchestors. + assert_eq!( + tree.finalizes_any_with_descendent_if(&"E", 15, &is_descendent_of, |c| c.effective == + 10), + Err(Error::UnfinalizedAncestor) + ); + // finalizing "B" doesn't finalize "A0" since the predicate doesn't pass, // although it will clear out "A1" from the tree assert_eq!( - tree.finalize_with_descendent_if(&"B", 2, &is_descendent_of, |c| c.effective <= 2,), + tree.finalize_with_descendent_if(&"B", 2, &is_descendent_of, |c| c.effective <= 2), Ok(FinalizationResult::Changed(None)), ); @@ -1307,7 +1323,7 @@ mod test { ); assert_eq!( - tree.finalize_with_descendent_if(&"C", 5, &is_descendent_of, |c| c.effective <= 5,), + tree.finalize_with_descendent_if(&"C", 5, &is_descendent_of, |c| c.effective <= 5), Ok(FinalizationResult::Changed(Some(Change { effective: 5 }))), ); @@ -1326,12 +1342,12 @@ mod test { // it will work with "G" though since it is not in the same branch as "E" assert_eq!( tree.finalizes_any_with_descendent_if(&"G", 100, &is_descendent_of, |c| c.effective <= - 100,), + 100), Ok(Some(true)), ); assert_eq!( - tree.finalize_with_descendent_if(&"G", 100, &is_descendent_of, |c| c.effective <= 100,), + tree.finalize_with_descendent_if(&"G", 100, &is_descendent_of, |c| c.effective <= 100), Ok(FinalizationResult::Changed(Some(Change { effective: 10 }))), ); From c4dd1bef02b7607018969e79bb16d33c6576ed33 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 6 Apr 2022 16:23:57 +0200 Subject: [PATCH 0670/1472] Grandpa revert procedure (#11162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Grandpa revert procedure * Trigger ci pipeline * Test rename * Update client/finality-grandpa/src/authorities.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- bin/node-template/node/src/command.rs | 6 +- bin/node/cli/src/command.rs | 15 ++- client/consensus/babe/src/lib.rs | 4 +- client/finality-grandpa/src/authorities.rs | 33 +++++- client/finality-grandpa/src/lib.rs | 49 +++++++- client/finality-grandpa/src/tests.rs | 127 ++++++++++++++++++++- client/network/test/src/lib.rs | 2 +- 7 files changed, 224 insertions(+), 12 deletions(-) diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index 66ee9fe45a55c..f033e779543a0 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -95,7 +95,11 @@ pub fn run() -> sc_cli::Result<()> { runner.async_run(|config| { let PartialComponents { client, task_manager, backend, .. } = service::new_partial(&config)?; - Ok((cmd.run(client, backend, None), task_manager)) + let aux_revert = Box::new(move |client, _, blocks| { + sc_finality_grandpa::revert(client, blocks)?; + Ok(()) + }); + Ok((cmd.run(client, backend, Some(aux_revert)), task_manager)) }) }, Some(Subcommand::Benchmark(cmd)) => diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index bd324b20fb019..db243ff6f597b 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -16,7 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{chain_spec, service, service::new_partial, Cli, Subcommand}; +use crate::{ + chain_spec, service, + service::{new_partial, FullClient}, + Cli, Subcommand, +}; use node_executor::ExecutorDispatch; use node_primitives::Block; use node_runtime::RuntimeApi; @@ -175,13 +179,12 @@ pub fn run() -> Result<()> { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?; - let revert_aux = Box::new(|client, backend, blocks| { - sc_consensus_babe::revert(client, backend, blocks)?; - // TODO: grandpa revert + let aux_revert = Box::new(move |client: Arc, backend, blocks| { + sc_consensus_babe::revert(client.clone(), backend, blocks)?; + grandpa::revert(client, blocks)?; Ok(()) }); - - Ok((cmd.run(client, backend, Some(revert_aux)), task_manager)) + Ok((cmd.run(client, backend, Some(aux_revert)), task_manager)) }) }, #[cfg(feature = "try-runtime")] diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 818384a5c3d7e..3d3a7f24df816 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1832,7 +1832,9 @@ where Ok(BasicQueue::new(verifier, Box::new(block_import), justification_import, spawner, registry)) } -/// Reverts aux data. +/// Reverts protocol aux data to at most the last finalized block. +/// In particular, epoch-changes and block weights announced after the revert +/// point are removed. pub fn revert( client: Arc, backend: Arc, diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 033a1c4bbb239..668fe5f269051 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -21,7 +21,7 @@ use std::{cmp::Ord, fmt::Debug, ops::Add}; use finality_grandpa::voter_set::VoterSet; -use fork_tree::ForkTree; +use fork_tree::{FilterAction, ForkTree}; use log::debug; use parity_scale_codec::{Decode, Encode}; use parking_lot::MappedMutexGuard; @@ -220,6 +220,37 @@ where pub(crate) fn current(&self) -> (u64, &[(AuthorityId, u64)]) { (self.set_id, &self.current_authorities[..]) } + + /// Revert to a specified block given its `hash` and `number`. + /// This removes all the authority set changes that were announced after + /// the revert point. + /// Revert point is identified by `number` and `hash`. + pub(crate) fn revert(&mut self, hash: H, number: N, is_descendent_of: &F) + where + F: Fn(&H, &H) -> Result, + { + let mut filter = |node_hash: &H, node_num: &N, _: &PendingChange| { + if number >= *node_num && + (is_descendent_of(node_hash, &hash).unwrap_or_default() || *node_hash == hash) + { + // Continue the search in this subtree. + FilterAction::KeepNode + } else if number < *node_num && is_descendent_of(&hash, node_hash).unwrap_or_default() { + // Found a node to be removed. + FilterAction::Remove + } else { + // Not a parent or child of the one we're looking for, stop processing this branch. + FilterAction::KeepTree + } + }; + + // Remove standard changes. + let _ = self.pending_standard_changes.drain_filter(&mut filter); + + // Remove forced changes. + self.pending_forced_changes + .retain(|change| !is_descendent_of(&hash, &change.canon_hash).unwrap_or_default()); + } } impl AuthoritySet diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index fef16286381ea..34d5b6bb1f70c 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -63,6 +63,7 @@ use parking_lot::RwLock; use prometheus_endpoint::{PrometheusError, Registry}; use sc_client_api::{ backend::{AuxStore, Backend}, + utils::is_descendent_of, BlockchainEvents, CallExecutor, ExecutionStrategy, ExecutorProvider, Finalizer, LockImportRun, StorageProvider, TransactionFor, }; @@ -71,7 +72,7 @@ use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppKey; -use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; +use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult}; use sp_consensus::SelectChain; use sp_core::crypto::ByteArray; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; @@ -1162,3 +1163,49 @@ fn local_authority_id( .map(|(p, _)| p.clone()) }) } + +/// Reverts protocol aux data to at most the last finalized block. +/// In particular, standard and forced authority set changes announced after the +/// revert point are removed. +pub fn revert(client: Arc, blocks: NumberFor) -> ClientResult<()> +where + Block: BlockT, + Client: AuxStore + + HeaderMetadata + + HeaderBackend + + ProvideRuntimeApi, +{ + let best_number = client.info().best_number; + let finalized = client.info().finalized_number; + let revertible = blocks.min(best_number - finalized); + + let number = best_number - revertible; + let hash = client + .block_hash_from_id(&BlockId::Number(number))? + .ok_or(ClientError::Backend(format!( + "Unexpected hash lookup failure for block number: {}", + number + )))?; + + let info = client.info(); + let persistent_data: PersistentData = + aux_schema::load_persistent(&*client, info.genesis_hash, Zero::zero(), || unreachable!())?; + + let shared_authority_set = persistent_data.authority_set; + let mut authority_set = shared_authority_set.inner(); + + let is_descendent_of = is_descendent_of(&*client, None); + authority_set.revert(hash, number, &is_descendent_of); + + // The following has the side effect to properly reset the current voter state. + let (set_id, set_ref) = authority_set.current(); + let new_set = Some(NewAuthoritySet { + canon_hash: info.finalized_hash, + canon_number: info.finalized_number, + set_id, + authorities: set_ref.to_vec(), + }); + aux_schema::update_authority_set::(&authority_set, new_set.as_ref(), |values| { + client.insert_aux(values, None) + }) +} diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 2e545b6e88ebf..5083cbfc21d1d 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -57,7 +57,7 @@ use tokio::runtime::{Handle, Runtime}; use authorities::AuthoritySet; use communication::grandpa_protocol_name; -use sc_block_builder::BlockBuilderProvider; +use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; use sc_consensus::LongestChain; use sc_keystore::LocalKeystore; use sp_application_crypto::key_types::GRANDPA; @@ -1685,3 +1685,128 @@ fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { let equivocation_proof = sp_finality_grandpa::Equivocation::Prevote(equivocation); assert!(environment.report_equivocation(equivocation_proof).is_ok()); } + +#[test] +fn revert_prunes_authority_changes() { + sp_tracing::try_init_simple(); + let runtime = Runtime::new().unwrap(); + + let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; + + type TestBlockBuilder<'a> = + BlockBuilder<'a, Block, PeersFullClient, substrate_test_runtime_client::Backend>; + let edit_block = |builder: TestBlockBuilder| { + let mut block = builder.build().unwrap().block; + add_scheduled_change( + &mut block, + ScheduledChange { next_authorities: make_ids(peers), delay: 0 }, + ); + block + }; + + let api = TestApi::new(make_ids(peers)); + let mut net = GrandpaTestNet::new(api, 3, 0); + runtime.spawn(initialize_grandpa(&mut net, peers)); + + let peer = net.peer(0); + let client = peer.client().as_client(); + + // Test scenario: (X) = auth-change, 24 = revert-point + // + // +---------(27) + // / + // 0---(21)---23---24---25---(28)---30 + // ^ \ + // revert-point +------(29) + + // Construct canonical chain + + // add 20 blocks + peer.push_blocks(20, false); + // at block 21 we add an authority transition + peer.generate_blocks(1, BlockOrigin::File, edit_block); + // add more blocks on top of it (until we have 24) + peer.push_blocks(3, false); + // add more blocks on top of it (until we have 27) + peer.push_blocks(3, false); + // at block 28 we add an authority transition + peer.generate_blocks(1, BlockOrigin::File, edit_block); + // add more blocks on top of it (until we have 30) + peer.push_blocks(2, false); + + // Fork before revert point + + // add more blocks on top of block 23 (until we have 26) + let hash = peer.generate_blocks_at( + BlockId::Number(23), + 3, + BlockOrigin::File, + |builder| { + let mut block = builder.build().unwrap().block; + block.header.digest_mut().push(DigestItem::Other(vec![1])); + block + }, + false, + false, + true, + ForkChoiceStrategy::LongestChain, + ); + // at block 27 of the fork add an authority transition + peer.generate_blocks_at( + BlockId::Hash(hash), + 1, + BlockOrigin::File, + edit_block, + false, + false, + true, + ForkChoiceStrategy::LongestChain, + ); + + // Fork after revert point + + // add more block on top of block 25 (until we have 28) + let hash = peer.generate_blocks_at( + BlockId::Number(25), + 3, + BlockOrigin::File, + |builder| { + let mut block = builder.build().unwrap().block; + block.header.digest_mut().push(DigestItem::Other(vec![2])); + block + }, + false, + false, + true, + ForkChoiceStrategy::LongestChain, + ); + // at block 29 of the fork add an authority transition + peer.generate_blocks_at( + BlockId::Hash(hash), + 1, + BlockOrigin::File, + edit_block, + false, + false, + true, + ForkChoiceStrategy::LongestChain, + ); + + revert(client.clone(), 6).unwrap(); + + let persistent_data: PersistentData = aux_schema::load_persistent( + &*client, + client.info().genesis_hash, + Zero::zero(), + || unreachable!(), + ) + .unwrap(); + let changes_num: Vec<_> = persistent_data + .authority_set + .inner() + .pending_standard_changes + .iter() + .map(|(_, n, _)| *n) + .collect(); + assert_eq!(changes_num, [21, 27]); +} diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 3986ac47f3616..552879f35d934 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -334,7 +334,7 @@ where /// Add blocks to the peer -- edit the block before adding. The chain will /// start at the given block iD. - fn generate_blocks_at( + pub fn generate_blocks_at( &mut self, at: BlockId, count: usize, From c89d524dea7bfb474f2e036ebc486fca9c81533f Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 6 Apr 2022 18:20:15 +0200 Subject: [PATCH 0671/1472] [ci] Remove vault (#11179) * [ci] Remove vault * remove anchors --- .gitlab-ci.yml | 47 ----------------------------------------------- 1 file changed, 47 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b6f9ff9486069..d196ade85a6fb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -39,9 +39,6 @@ variables: &default-vars DOCKER_OS: "debian:stretch" ARCH: "x86_64" CI_IMAGE: "paritytech/ci-linux:production" - VAULT_SERVER_URL: "https://vault.parity-mgmt-vault.parity.io" - VAULT_AUTH_PATH: "gitlab-parity-io-jwt" - VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" default: cache: {} @@ -188,46 +185,6 @@ default: - cp -r ./scripts/ci/docker/substrate.Dockerfile ./artifacts/substrate/ - sccache -s -#### Vault secrets -.vault-secrets: &vault-secrets - secrets: - DOCKER_HUB_USER: - vault: cicd/gitlab/parity/DOCKER_HUB_USER@kv - file: false - DOCKER_HUB_PASS: - vault: cicd/gitlab/parity/DOCKER_HUB_PASS@kv - file: false - GITHUB_PR_TOKEN: - vault: cicd/gitlab/parity/GITHUB_PR_TOKEN@kv - file: false - GITHUB_TOKEN: - vault: cicd/gitlab/parity/GITHUB_TOKEN@kv - file: false - AWS_ACCESS_KEY_ID: - vault: cicd/gitlab/$CI_PROJECT_PATH/AWS_ACCESS_KEY_ID@kv - file: false - AWS_SECRET_ACCESS_KEY: - vault: cicd/gitlab/$CI_PROJECT_PATH/AWS_SECRET_ACCESS_KEY@kv - file: false - GITHUB_EMAIL: - vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_EMAIL@kv - file: false - GITHUB_RELEASE_TOKEN: - vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_RELEASE_TOKEN@kv - file: false - GITHUB_SSH_PRIV_KEY: - vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_SSH_PRIV_KEY@kv - file: false - GITHUB_USER: - vault: cicd/gitlab/$CI_PROJECT_PATH/GITHUB_USER@kv - file: false - MATRIX_ACCESS_TOKEN: - vault: cicd/gitlab/$CI_PROJECT_PATH/MATRIX_ACCESS_TOKEN@kv - file: false - MATRIX_ROOM_ID: - vault: cicd/gitlab/$CI_PROJECT_PATH/MATRIX_ROOM_ID@kv - file: false - #### stage: .pre @@ -638,7 +595,6 @@ build-rustdoc: .build-push-docker-image: &build-push-docker-image <<: *build-refs <<: *kubernetes-env - <<: *vault-secrets image: quay.io/buildah/stable variables: &docker-build-vars <<: *default-vars @@ -697,7 +653,6 @@ publish-s3-release: stage: publish <<: *build-refs <<: *kubernetes-env - <<: *vault-secrets needs: - job: build-linux-substrate artifacts: true @@ -719,7 +674,6 @@ publish-s3-release: publish-rustdoc: stage: publish <<: *kubernetes-env - <<: *vault-secrets image: node:16 variables: GIT_DEPTH: 100 @@ -778,7 +732,6 @@ publish-rustdoc: publish-draft-release: stage: publish - <<: *vault-secrets image: paritytech/tools:latest rules: - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ From 1dd1f2125c2936b006c85699433c3942c80d09fd Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 7 Apr 2022 08:47:36 +0200 Subject: [PATCH 0672/1472] chore: update jsonrpsee to `v0.10.1` (#11173) * fix(bin/node): remove unsed dep jsonrpsee * chore(remote ext): update jsonrpsee v0.10.1 * chore(try runtime): update jsonrpsee v0.10.1 * Update utils/frame/try-runtime/cli/src/commands/follow_chain.rs * cargo fmt --- Cargo.lock | 125 +++++------------- bin/node/cli/Cargo.toml | 1 - client/informant/src/display.rs | 2 +- client/network/src/config.rs | 2 +- client/network/src/lib.rs | 4 +- client/peerset/src/lib.rs | 4 +- client/peerset/src/peersstate.rs | 8 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- .../cli/src/commands/follow_chain.rs | 12 +- 10 files changed, 54 insertions(+), 108 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd6db80272113..0a1a1e0b17bec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2803,7 +2803,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.6.7", "tracing", ] @@ -3404,7 +3404,7 @@ dependencies = [ "log 0.4.14", "tokio", "tokio-stream", - "tokio-util", + "tokio-util 0.6.7", "unicase 2.6.0", ] @@ -3425,53 +3425,42 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373a33d987866ccfe1af4bc11b089dce941764313f9fd8b7cf13fcb51b72dc5" -dependencies = [ - "jsonrpsee-types 0.4.1", - "jsonrpsee-utils", - "jsonrpsee-ws-client 0.4.1", -] - -[[package]] -name = "jsonrpsee" -version = "0.8.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05fd8cd6c6b1bbd06881d2cf88f1fc83cc36c98f2219090f839115fb4a956cb9" +checksum = "91dc760c341fa81173f9a434931aaf32baad5552b0230cc6c93e8fb7eaad4c19" dependencies = [ "jsonrpsee-core", "jsonrpsee-proc-macros", - "jsonrpsee-types 0.8.0", - "jsonrpsee-ws-client 0.8.0", + "jsonrpsee-types", + "jsonrpsee-ws-client", ] [[package]] name = "jsonrpsee-client-transport" -version = "0.8.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3303cdf246e6ab76e2866fb3d9acb6c76a068b1b28bd923a1b7a8122257ad7b5" +checksum = "765f7a36d5087f74e3b3b47805c2188fef8eb54afcb587b078d9f8ebfe9c7220" dependencies = [ "futures 0.3.21", "http", "jsonrpsee-core", - "jsonrpsee-types 0.8.0", + "jsonrpsee-types", "pin-project 1.0.10", "rustls-native-certs 0.6.1", "soketto 0.7.1", "thiserror", "tokio", "tokio-rustls 0.23.2", - "tokio-util", + "tokio-util 0.7.1", "tracing", "webpki-roots 0.22.2", ] [[package]] name = "jsonrpsee-core" -version = "0.8.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f220b5a238dc7992b90f1144fbf6eaa585872c9376afe6fe6863ffead6191bf3" +checksum = "82ef77ecd20c2254d54f5da8c0738eacca61e6b6511268a8f2753e3148c6c706" dependencies = [ "anyhow", "arrayvec 0.7.1", @@ -3480,7 +3469,7 @@ dependencies = [ "futures-channel", "futures-util", "hyper 0.14.16", - "jsonrpsee-types 0.8.0", + "jsonrpsee-types", "rustc-hash", "serde", "serde_json", @@ -3492,9 +3481,9 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.8.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4299ebf790ea9de1cb72e73ff2ae44c723ef264299e5e2d5ef46a371eb3ac3d8" +checksum = "b7291c72805bc7d413b457e50d8ef3e87aa554da65ecbbc278abb7dfc283e7f0" dependencies = [ "proc-macro-crate 1.1.3", "proc-macro2", @@ -3504,28 +3493,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f778cf245158fbd8f5d50823a2e9e4c708a40be164766bd35e9fb1d86715b2" -dependencies = [ - "anyhow", - "async-trait", - "beef", - "futures-channel", - "futures-util", - "hyper 0.14.16", - "log 0.4.14", - "serde", - "serde_json", - "soketto 0.7.1", - "thiserror", -] - -[[package]] -name = "jsonrpsee-types" -version = "0.8.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b3f601bbbe45cd63f5407b6f7d7950e08a7d4f82aa699ff41a4a5e9e54df58" +checksum = "38b6aa52f322cbf20c762407629b8300f39bcc0cf0619840d9252a2f65fd2dd9" dependencies = [ "anyhow", "beef", @@ -3535,50 +3505,15 @@ dependencies = [ "tracing", ] -[[package]] -name = "jsonrpsee-utils" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0109c4f972058f3b1925b73a17210aff7b63b65967264d0045d15ee88fe84f0c" -dependencies = [ - "arrayvec 0.7.1", - "beef", - "jsonrpsee-types 0.4.1", -] - -[[package]] -name = "jsonrpsee-ws-client" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559aa56fc402af206c00fc913dc2be1d9d788dcde045d14df141a535245d35ef" -dependencies = [ - "arrayvec 0.7.1", - "async-trait", - "fnv", - "futures 0.3.21", - "http", - "jsonrpsee-types 0.4.1", - "log 0.4.14", - "pin-project 1.0.10", - "rustls-native-certs 0.5.0", - "serde", - "serde_json", - "soketto 0.7.1", - "thiserror", - "tokio", - "tokio-rustls 0.22.0", - "tokio-util", -] - [[package]] name = "jsonrpsee-ws-client" -version = "0.8.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff425cee7c779e33920913bc695447416078ee6d119f443f3060feffa4e86b5" +checksum = "dd66d18bab78d956df24dd0d2e41e4c00afbb818fda94a98264bdd12ce8506ac" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", - "jsonrpsee-types 0.8.0", + "jsonrpsee-types", ] [[package]] @@ -4891,7 +4826,6 @@ dependencies = [ "frame-system-rpc-runtime-api", "futures 0.3.21", "hex-literal", - "jsonrpsee-ws-client 0.4.1", "log 0.4.14", "nix", "node-executor", @@ -7863,7 +7797,7 @@ version = "0.10.0-dev" dependencies = [ "env_logger 0.9.0", "frame-support", - "jsonrpsee 0.8.0", + "jsonrpsee", "log 0.4.14", "pallet-elections-phragmen", "parity-scale-codec", @@ -11317,13 +11251,26 @@ checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" dependencies = [ "bytes 1.1.0", "futures-core", - "futures-io", "futures-sink", "log 0.4.14", "pin-project-lite 0.2.6", "tokio", ] +[[package]] +name = "tokio-util" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" +dependencies = [ + "bytes 1.1.0", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite 0.2.6", + "tokio", +] + [[package]] name = "toml" version = "0.5.8" @@ -11540,7 +11487,7 @@ name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ "clap 3.1.6", - "jsonrpsee 0.4.1", + "jsonrpsee", "log 0.4.14", "parity-scale-codec", "remote-externalities", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index d25c1b1f0bf81..4eb5983b6488e 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -127,7 +127,6 @@ async-std = { version = "1.10.0", features = ["attributes"] } soketto = "0.4.2" criterion = { version = "0.3.5", features = ["async_tokio"] } tokio = { version = "1.17.0", features = ["macros", "time", "parking_lot"] } -jsonrpsee-ws-client = "0.4.1" wait-timeout = "0.2" remote-externalities = { path = "../../../utils/frame/remote-externalities" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } diff --git a/client/informant/src/display.rs b/client/informant/src/display.rs index 77b28dec55651..446ddf47b4cab 100644 --- a/client/informant/src/display.rs +++ b/client/informant/src/display.rs @@ -30,7 +30,7 @@ use std::{fmt, time::Instant}; /// like: /// /// > Syncing 5.4 bps, target=#531028 (4 peers), best: #90683 (0x4ca8…51b8), -/// > finalized #360 (0x6f24…a38b), ⬇ 5.5kiB/s ⬆ 0.9kiB/s +/// > finalized #360 (0x6f24…a38b), ⬇ 5.5kiB/s ⬆ 0.9kiB/s /// /// # Usage /// diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 7c2dfef7fe89c..40aefe9a3ec2d 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -579,7 +579,7 @@ pub struct NonDefaultSetConfig { /// considered established once this protocol is open. /// /// > **Note**: This field isn't present for the default set, as this is handled internally - /// > by the networking code. + /// > by the networking code. pub notifications_protocol: Cow<'static, str>, /// If the remote reports that it doesn't support the protocol indicated in the /// `notifications_protocol` field, then each of these fallback names will be tried one by diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 27e9a7547b44f..d9f5b3de1bb10 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -103,8 +103,8 @@ //! protocol ID. //! //! > **Note**: It is possible for the same connection to be used for multiple chains. For example, -//! > one can use both the `/dot/sync/2` and `/sub/sync/2` protocols on the same -//! > connection, provided that the remote supports them. +//! > one can use both the `/dot/sync/2` and `/sub/sync/2` protocols on the same +//! > connection, provided that the remote supports them. //! //! Substrate uses the following standard libp2p protocols: //! diff --git a/client/peerset/src/lib.rs b/client/peerset/src/lib.rs index c777cfec19d25..859319fab1320 100644 --- a/client/peerset/src/lib.rs +++ b/client/peerset/src/lib.rs @@ -129,7 +129,7 @@ impl PeersetHandle { /// Has no effect if the node was already a reserved peer. /// /// > **Note**: Keep in mind that the networking has to know an address for this node, - /// > otherwise it will not be able to connect to it. + /// > otherwise it will not be able to connect to it. pub fn add_reserved_peer(&self, set_id: SetId, peer_id: PeerId) { let _ = self.tx.unbounded_send(Action::AddReservedPeer(set_id, peer_id)); } @@ -232,7 +232,7 @@ pub struct SetConfig { /// List of bootstrap nodes to initialize the set with. /// /// > **Note**: Keep in mind that the networking has to know an address for these nodes, - /// > otherwise it will not be able to connect to them. + /// > otherwise it will not be able to connect to them. pub bootnodes: Vec, /// Lists of nodes we should always be connected to. diff --git a/client/peerset/src/peersstate.rs b/client/peerset/src/peersstate.rs index 272b903c1da2b..ca22cac324088 100644 --- a/client/peerset/src/peersstate.rs +++ b/client/peerset/src/peersstate.rs @@ -25,8 +25,8 @@ //! slots. //! //! > Note: This module is purely dedicated to managing slots and reputations. Features such as -//! > for example connecting to some nodes in priority should be added outside of this -//! > module, rather than inside. +//! > for example connecting to some nodes in priority should be added outside of this +//! > module, rather than inside. use libp2p::PeerId; use log::error; @@ -50,8 +50,8 @@ pub struct PeersState { /// List of nodes that we know about. /// /// > **Note**: This list should really be ordered by decreasing reputation, so that we can - /// easily select the best node to connect to. As a first draft, however, we don't - /// sort, to make the logic easier. + /// > easily select the best node to connect to. As a first draft, however, we don't sort, to + /// > make the logic easier. nodes: HashMap, /// Configuration of each set. The size of this `Vec` is never modified. diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index fc44c63b8acd4..343dda6892759 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.8", features = ["ws-client", "macros"] } +jsonrpsee = { version = "0.10.1", features = ["ws-client", "macros"] } env_logger = "0.9" frame-support = { path = "../../../frame/support", optional = true, version = "4.0.0-dev" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 6f72bd3b9d7f2..3f0ee257d9756 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -32,4 +32,4 @@ sp-externalities = { version = "0.12.0", path = "../../../../primitives/external sp-version = { version = "5.0.0", path = "../../../../primitives/version" } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } -jsonrpsee = { version = "0.4.1", default-features = false, features = ["ws-client"] } +jsonrpsee = { version = "0.10.1", default-features = false, features = ["ws-client"] } diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index 7400813b9175e..db305fa590760 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -20,7 +20,7 @@ use crate::{ state_machine_call_with_proof, SharedParams, LOG_TARGET, }; use jsonrpsee::{ - types::{traits::SubscriptionClient, Subscription}, + core::client::{Subscription, SubscriptionClientT}, ws_client::WsClientBuilder, }; use parity_scale_codec::Decode; @@ -76,13 +76,13 @@ where loop { let header = match subscription.next().await { - Ok(Some(header)) => header, - Ok(None) => { - log::warn!("subscription returned `None`. Probably decoding has failed."); + Some(Ok(header)) => header, + None => { + log::warn!("subscription closed"); break }, - Err(why) => { - log::warn!("subscription returned error: {:?}.", why); + Some(Err(why)) => { + log::warn!("subscription returned error: {:?}. Probably decoding has failed.", why); continue }, }; From e6ae0b0b8ae8ff7ea8020348bc671e1cfb1f3eff Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 7 Apr 2022 09:46:51 +0200 Subject: [PATCH 0673/1472] relax input conditions of fixed::checked_from_integer (#11159) * relax input conditions of fixed::checked_from_integer * Fix build --- frame/transaction-payment/src/lib.rs | 2 +- primitives/arithmetic/src/fixed_point.rs | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 37fecf20cc528..12edb6f2c390b 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -348,7 +348,7 @@ pub mod pallet { // loss. assert!( ::max_value() >= - Multiplier::checked_from_integer( + Multiplier::checked_from_integer::( T::BlockWeights::get().max_block.try_into().unwrap() ) .unwrap(), diff --git a/primitives/arithmetic/src/fixed_point.rs b/primitives/arithmetic/src/fixed_point.rs index 3ecfb60ee0f52..7ce17bb72611f 100644 --- a/primitives/arithmetic/src/fixed_point.rs +++ b/primitives/arithmetic/src/fixed_point.rs @@ -121,7 +121,8 @@ pub trait FixedPointNumber: /// Creates `self` from an integer number `int`. /// /// Returns `None` if `int` exceeds accuracy. - fn checked_from_integer(int: Self::Inner) -> Option { + fn checked_from_integer>(int: N) -> Option { + let int: Self::Inner = int.into(); int.checked_mul(&Self::DIV).map(Self::from_inner) } @@ -898,31 +899,32 @@ macro_rules! implement_fixed { let accuracy = $name::accuracy(); // Case where integer fits. - let a = $name::checked_from_integer(42).expect("42 * accuracy <= inner_max; qed"); + let a = $name::checked_from_integer::<$inner_type>(42) + .expect("42 * accuracy <= inner_max; qed"); assert_eq!(a.into_inner(), 42 * accuracy); // Max integer that fit. - let a = $name::checked_from_integer(inner_max / accuracy) + let a = $name::checked_from_integer::<$inner_type>(inner_max / accuracy) .expect("(inner_max / accuracy) * accuracy <= inner_max; qed"); assert_eq!(a.into_inner(), (inner_max / accuracy) * accuracy); // Case where integer doesn't fit, so it returns `None`. - let a = $name::checked_from_integer(inner_max / accuracy + 1); + let a = $name::checked_from_integer::<$inner_type>(inner_max / accuracy + 1); assert_eq!(a, None); if $name::SIGNED { // Case where integer fits. - let a = $name::checked_from_integer(0.saturating_sub(42)) + let a = $name::checked_from_integer::<$inner_type>(0.saturating_sub(42)) .expect("-42 * accuracy >= inner_min; qed"); assert_eq!(a.into_inner(), 0 - 42 * accuracy); // Min integer that fit. - let a = $name::checked_from_integer(inner_min / accuracy) + let a = $name::checked_from_integer::<$inner_type>(inner_min / accuracy) .expect("(inner_min / accuracy) * accuracy <= inner_min; qed"); assert_eq!(a.into_inner(), (inner_min / accuracy) * accuracy); // Case where integer doesn't fit, so it returns `None`. - let a = $name::checked_from_integer(inner_min / accuracy - 1); + let a = $name::checked_from_integer::<$inner_type>(inner_min / accuracy - 1); assert_eq!(a, None); } } From a1497f5942a04bd1a4e7c5a5b276ad2d1f863557 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Thu, 7 Apr 2022 11:24:59 +0000 Subject: [PATCH 0674/1472] Apply `WeightToFeePolynomial`s to `pallet_transaction_payment`'s length fee (#10785) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Apply WeightToFeePolynomials to length fee * Remove TransactionByteFee * Add test cases for ConstantModifierFee * Restore import * Use pallet::constant_name * Remove irrelevant TODO comment * Update frame/support/src/weights.rs * Update frame/transaction-payment/src/lib.rs * Update frame/transaction-payment/src/lib.rs * Update frame/transaction-payment/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * s/ConstantModifierFee/ConstantMultiplier/ * Impl LengthToFee for test configs * fmt * Remove unused import * Impl WeightToFeePolynomial for byte fee in ExtBuilder * Remove unused import * fix doc Co-authored-by: Bastian Köcher Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Shawn Tabrizi --- bin/node-template/runtime/src/lib.rs | 6 +-- bin/node/runtime/src/lib.rs | 4 +- frame/balances/src/tests_composite.rs | 2 +- frame/balances/src/tests_local.rs | 2 +- frame/balances/src/tests_reentrancy.rs | 2 +- frame/executive/src/lib.rs | 6 ++- frame/support/src/weights.rs | 42 +++++++++++++++- .../asset-tx-payment/src/tests.rs | 2 +- frame/transaction-payment/src/lib.rs | 49 ++++++++++++------- frame/transaction-payment/src/payment.rs | 3 +- 10 files changed, 85 insertions(+), 33 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 93cf234fa52b8..40adbb0388111 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -249,15 +249,11 @@ impl pallet_balances::Config for Runtime { type WeightInfo = pallet_balances::weights::SubstrateWeight; } -parameter_types! { - pub const TransactionByteFee: Balance = 1; -} - impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 565f151ce2a08..57584bed39b2c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -35,7 +35,7 @@ use frame_support::{ }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, - DispatchClass, IdentityFee, Weight, + ConstantMultiplier, DispatchClass, IdentityFee, Weight, }, PalletId, RuntimeDebug, }; @@ -444,9 +444,9 @@ parameter_types! { impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; + type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = TargetedFeeAdjustment; } diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index a24be44927375..4a2cc1d91936d 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -78,9 +78,9 @@ impl frame_system::Config for Test { impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; - type TransactionByteFee = ConstU64<1>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index ae56f3b1f0f2c..cfc7f84ab3a38 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -79,9 +79,9 @@ impl frame_system::Config for Test { impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; - type TransactionByteFee = ConstU64<1>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 4303efc2322c5..7037e9615afd8 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -85,9 +85,9 @@ impl frame_system::Config for Test { impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; - type TransactionByteFee = ConstU64<1>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index d19ea8127bad3..de1cc3b916404 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -576,7 +576,9 @@ mod tests { ConstU32, ConstU64, ConstU8, Currency, LockIdentifier, LockableCurrency, WithdrawReasons, }, - weights::{IdentityFee, RuntimeDbWeight, Weight, WeightToFeePolynomial}, + weights::{ + ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFeePolynomial, + }, }; use frame_system::{Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo}; use pallet_balances::Call as BalancesCall; @@ -787,9 +789,9 @@ mod tests { } impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; + type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = (); } impl custom::Config for Runtime {} diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index b3ed42bb45fc4..4c3fcaa0fd423 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -132,7 +132,10 @@ mod extrinsic_weights; mod paritydb_weights; mod rocksdb_weights; -use crate::dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo}; +use crate::{ + dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo}, + traits::Get, +}; use codec::{Decode, Encode}; use scale_info::TypeInfo; #[cfg(feature = "std")] @@ -709,6 +712,34 @@ where } } +/// Implementor of [`WeightToFeePolynomial`] that uses a constant multiplier. +/// # Example +/// +/// ``` +/// # use frame_support::traits::ConstU128; +/// # use frame_support::weights::ConstantMultiplier; +/// // Results in a multiplier of 10 for each unit of weight (or length) +/// type LengthToFee = ConstantMultiplier::>; +/// ``` +pub struct ConstantMultiplier(sp_std::marker::PhantomData<(T, M)>); + +impl WeightToFeePolynomial for ConstantMultiplier +where + T: BaseArithmetic + From + Copy + Unsigned, + M: Get, +{ + type Balance = T; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec!(WeightToFeeCoefficient { + coeff_integer: M::get(), + coeff_frac: Perbill::zero(), + negative: false, + degree: 1, + }) + } +} + /// A struct holding value for each `DispatchClass`. #[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] pub struct PerDispatchClass { @@ -983,4 +1014,13 @@ mod tests { assert_eq!(IdentityFee::::calc(&50), 50); assert_eq!(IdentityFee::::calc(&Weight::max_value()), Balance::max_value()); } + + #[test] + fn constant_fee_works() { + use crate::traits::ConstU128; + assert_eq!(ConstantMultiplier::>::calc(&0), 0); + assert_eq!(ConstantMultiplier::>::calc(&50), 500); + assert_eq!(ConstantMultiplier::>::calc(&16), 16384); + assert_eq!(ConstantMultiplier::>::calc(&2), u128::MAX); + } } diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index f2a1ad1406575..d72a288ac7a33 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -145,8 +145,8 @@ impl WeightToFeePolynomial for WeightToFee { impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type WeightToFee = WeightToFee; + type LengthToFee = WeightToFee; type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 12edb6f2c390b..1462faaa07062 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -260,10 +260,6 @@ pub mod pallet { /// might be refunded. In the end the fees can be deposited. type OnChargeTransaction: OnChargeTransaction; - /// The fee to be paid for making a transaction; the per-byte portion. - #[pallet::constant] - type TransactionByteFee: Get>; - /// A fee mulitplier for `Operational` extrinsics to compute "virtual tip" to boost their /// `priority` /// @@ -291,6 +287,9 @@ pub mod pallet { /// Convert a weight value into a deductible fee based on the currency type. type WeightToFee: WeightToFeePolynomial>; + /// Convert a length value into a deductible fee based on the currency type. + type LengthToFee: WeightToFeePolynomial>; + /// Update the multiplier of the next block, based on the previous block's weight. type FeeMultiplierUpdate: MultiplierUpdate; } @@ -302,6 +301,12 @@ pub mod pallet { fn weight_to_fee_polynomial() -> Vec>> { T::WeightToFee::polynomial().to_vec() } + + /// The polynomial that is applied in order to derive fee from length. + #[pallet::constant_name(LengthToFee)] + fn length_to_fee_polynomial() -> Vec>> { + T::LengthToFee::polynomial().to_vec() + } } #[pallet::type_value] @@ -510,25 +515,18 @@ where class: DispatchClass, ) -> FeeDetails> { if pays_fee == Pays::Yes { - let len = >::from(len); - let per_byte = T::TransactionByteFee::get(); - - // length fee. this is not adjusted. - let fixed_len_fee = per_byte.saturating_mul(len); - // the adjustable part of the fee. let unadjusted_weight_fee = Self::weight_to_fee(weight); let multiplier = Self::next_fee_multiplier(); // final adjusted weight fee. let adjusted_weight_fee = multiplier.saturating_mul_int(unadjusted_weight_fee); + // length fee. this is adjusted via `LengthToFee`. + let len_fee = Self::length_to_fee(len); + let base_fee = Self::weight_to_fee(T::BlockWeights::get().get(class).base_extrinsic); FeeDetails { - inclusion_fee: Some(InclusionFee { - base_fee, - len_fee: fixed_len_fee, - adjusted_weight_fee, - }), + inclusion_fee: Some(InclusionFee { base_fee, len_fee, adjusted_weight_fee }), tip, } } else { @@ -536,6 +534,10 @@ where } } + fn length_to_fee(length: u32) -> BalanceOf { + T::LengthToFee::calc(&(length as Weight)) + } + fn weight_to_fee(weight: Weight) -> BalanceOf { // cap the weight to the maximum defined in runtime, otherwise it will be the // `Bounded` maximum of its data type, which is not desired. @@ -835,8 +837,8 @@ mod tests { } parameter_types! { - pub static TransactionByteFee: u64 = 1; pub static WeightToFee: u64 = 1; + pub static TransactionByteFee: u64 = 1; pub static OperationalFeeMultiplier: u8 = 5; } @@ -892,6 +894,19 @@ mod tests { } } + impl WeightToFeePolynomial for TransactionByteFee { + type Balance = u64; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: TRANSACTION_BYTE_FEE.with(|v| *v.borrow()), + negative: false, + }] + } + } + thread_local! { static TIP_UNBALANCED_AMOUNT: RefCell = RefCell::new(0); static FEE_UNBALANCED_AMOUNT: RefCell = RefCell::new(0); @@ -913,9 +928,9 @@ mod tests { impl Config for Runtime { type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = WeightToFee; + type LengthToFee = TransactionByteFee; type FeeMultiplierUpdate = (); } diff --git a/frame/transaction-payment/src/payment.rs b/frame/transaction-payment/src/payment.rs index 58e6ef63109a3..5b4a613102792 100644 --- a/frame/transaction-payment/src/payment.rs +++ b/frame/transaction-payment/src/payment.rs @@ -12,7 +12,7 @@ use sp_runtime::{ use sp_std::{fmt::Debug, marker::PhantomData}; use frame_support::{ - traits::{Currency, ExistenceRequirement, Get, Imbalance, OnUnbalanced, WithdrawReasons}, + traits::{Currency, ExistenceRequirement, Imbalance, OnUnbalanced, WithdrawReasons}, unsigned::TransactionValidityError, }; @@ -73,7 +73,6 @@ pub struct CurrencyAdapter(PhantomData<(C, OU)>); impl OnChargeTransaction for CurrencyAdapter where T: Config, - T::TransactionByteFee: Get<::AccountId>>::Balance>, C: Currency<::AccountId>, C::PositiveImbalance: Imbalance< ::AccountId>>::Balance, From f4e80d444523646c14def0ebbeee1d2bae47bfcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 7 Apr 2022 15:00:30 +0200 Subject: [PATCH 0675/1472] Improve docs of `remove_all` and `remove_prefix` (#11182) These docs didn't mention how the removal works internally. This is important for the user to know that calling such a method multiple times in the same block leads always to the same result. --- frame/support/src/storage/mod.rs | 34 +++++++++++++++++-- frame/support/src/storage/types/double_map.rs | 21 ++++++++++-- frame/support/src/storage/types/map.rs | 6 ++++ frame/support/src/storage/types/nmap.rs | 25 ++++++++++++-- primitives/io/src/lib.rs | 10 +++--- 5 files changed, 84 insertions(+), 12 deletions(-) diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index f3eb94498ed92..066422ad456aa 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -502,7 +502,18 @@ pub trait StorageDoubleMap { KArg1: EncodeLike, KArg2: EncodeLike; - /// Remove all values under the first key. + /// Remove all values under the first key `k1` in the overlay and up to `limit` in the + /// backend. + /// + /// All values in the client overlay will be deleted, if there is some `limit` then up to + /// `limit` values are deleted from the client backend, if `limit` is none then all values in + /// the client backend are deleted. + /// + /// # Note + /// + /// Calling this multiple times per block with a `limit` set leads always to the same keys being + /// removed and the same result being returned. This happens because the keys to delete in the + /// overlay are not taken into account when deleting keys in the backend. fn remove_prefix(k1: KArg1, limit: Option) -> sp_io::KillStorageResult where KArg1: ?Sized + EncodeLike; @@ -632,7 +643,18 @@ pub trait StorageNMap { /// Remove the value under a key. fn remove + TupleToEncodedIter>(key: KArg); - /// Remove all values under the partial prefix key. + /// Remove all values starting with `partial_key` in the overlay and up to `limit` in the + /// backend. + /// + /// All values in the client overlay will be deleted, if there is some `limit` then up to + /// `limit` values are deleted from the client backend, if `limit` is none then all values in + /// the client backend are deleted. + /// + /// # Note + /// + /// Calling this multiple times per block with a `limit` set leads always to the same keys being + /// removed and the same result being returned. This happens because the keys to delete in the + /// overlay are not taken into account when deleting keys in the backend. fn remove_prefix(partial_key: KP, limit: Option) -> sp_io::KillStorageResult where K: HasKeyPrefix; @@ -1076,11 +1098,17 @@ pub trait StoragePrefixedMap { crate::storage::storage_prefix(Self::module_prefix(), Self::storage_prefix()) } - /// Remove all values of the storage in the overlay and up to `limit` in the backend. + /// Remove all values in the overlay and up to `limit` in the backend. /// /// All values in the client overlay will be deleted, if there is some `limit` then up to /// `limit` values are deleted from the client backend, if `limit` is none then all values in /// the client backend are deleted. + /// + /// # Note + /// + /// Calling this multiple times per block with a `limit` set leads always to the same keys being + /// removed and the same result being returned. This happens because the keys to delete in the + /// overlay are not taken into account when deleting keys in the backend. fn remove_all(limit: Option) -> sp_io::KillStorageResult { sp_io::storage::clear_prefix(&Self::final_prefix(), limit) } diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index e864920e488f0..42b903128934d 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -217,7 +217,18 @@ where >::remove(k1, k2) } - /// Remove all values under the first key. + /// Remove all values under `k1` in the overlay and up to `limit` in the + /// backend. + /// + /// All values in the client overlay will be deleted, if there is some `limit` then up to + /// `limit` values are deleted from the client backend, if `limit` is none then all values in + /// the client backend are deleted. + /// + /// # Note + /// + /// Calling this multiple times per block with a `limit` set leads always to the same keys being + /// removed and the same result being returned. This happens because the keys to delete in the + /// overlay are not taken into account when deleting keys in the backend. pub fn remove_prefix(k1: KArg1, limit: Option) -> sp_io::KillStorageResult where KArg1: ?Sized + EncodeLike, @@ -337,11 +348,17 @@ where >(key1, key2) } - /// Remove all values of the storage in the overlay and up to `limit` in the backend. + /// Remove all values in the overlay and up to `limit` in the backend. /// /// All values in the client overlay will be deleted, if there is some `limit` then up to /// `limit` values are deleted from the client backend, if `limit` is none then all values in /// the client backend are deleted. + /// + /// # Note + /// + /// Calling this multiple times per block with a `limit` set leads always to the same keys being + /// removed and the same result being returned. This happens because the keys to delete in the + /// overlay are not taken into account when deleting keys in the backend. pub fn remove_all(limit: Option) -> sp_io::KillStorageResult { >::remove_all(limit) } diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 01aa2f44abe5e..bc32c58da8db6 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -241,6 +241,12 @@ where /// All values in the client overlay will be deleted, if there is some `limit` then up to /// `limit` values are deleted from the client backend, if `limit` is none then all values in /// the client backend are deleted. + /// + /// # Note + /// + /// Calling this multiple times per block with a `limit` set leads always to the same keys being + /// removed and the same result being returned. This happens because the keys to delete in the + /// overlay are not taken into account when deleting keys in the backend. pub fn remove_all(limit: Option) -> sp_io::KillStorageResult { >::remove_all(limit) } diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 561bf5298e183..aff32f2110009 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -173,7 +173,18 @@ where >::remove(key) } - /// Remove all values under the first key. + /// Remove all values starting with `partial_key` in the overlay and up to `limit` in the + /// backend. + /// + /// All values in the client overlay will be deleted, if there is some `limit` then up to + /// `limit` values are deleted from the client backend, if `limit` is none then all values in + /// the client backend are deleted. + /// + /// # Note + /// + /// Calling this multiple times per block with a `limit` set leads always to the same keys being + /// removed and the same result being returned. This happens because the keys to delete in the + /// overlay are not taken into account when deleting keys in the backend. pub fn remove_prefix(partial_key: KP, limit: Option) -> sp_io::KillStorageResult where Key: HasKeyPrefix, @@ -277,7 +288,17 @@ where >::migrate_keys::<_>(key, hash_fns) } - /// Remove all value of the storage. + /// Remove all values in the overlay and up to `limit` in the backend. + /// + /// All values in the client overlay will be deleted, if there is some `limit` then up to + /// `limit` values are deleted from the client backend, if `limit` is none then all values in + /// the client backend are deleted. + /// + /// # Note + /// + /// Calling this multiple times per block with a `limit` set leads always to the same keys being + /// removed and the same result being returned. This happens because the keys to delete in the + /// overlay are not taken into account when deleting keys in the backend. pub fn remove_all(limit: Option) -> sp_io::KillStorageResult { >::remove_all(limit) } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 9f49a098b6add..2ff49b5048810 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -158,9 +158,7 @@ pub trait Storage { /// The limit can be used to partially delete a prefix storage in case it is too large /// to delete in one go (block). /// - /// It returns a boolean false iff some keys are remaining in - /// the prefix after the functions returns. Also returns a `u32` with - /// the number of keys removed from the process. + /// Returns [`KillStorageResult`] to inform about the result. /// /// # Note /// @@ -171,8 +169,10 @@ pub trait Storage { /// /// Calling this function multiple times per block for the same `prefix` does /// not make much sense because it is not cumulative when called inside the same block. - /// Use this function to distribute the deletion of a single child trie across multiple - /// blocks. + /// The deletion would always start from `prefix` resulting in the same keys being deleted + /// every time this function is called with the exact same arguments per block. This happens + /// because the keys in the overlay are not taken into account when deleting keys in the + /// backend. #[version(2)] fn clear_prefix(&mut self, prefix: &[u8], limit: Option) -> KillStorageResult { let (all_removed, num_removed) = Externalities::clear_prefix(*self, prefix, limit); From f98ef8abfc54bb7801b21be899e63f5058350e14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Thu, 7 Apr 2022 11:23:33 -0300 Subject: [PATCH 0676/1472] update pr-custom-review.yml (#11169) syntax in accordance to https://github.com/paritytech/pr-custom-review/tree/5814820aa0e5d35412f31dc02f9d130a8b138cae#configuration-syntax rules in accordance to https://github.com/paritytech/pr-custom-review/blob/da1d81b9fd39705cc8b37f59235283801c818708/rules.md --- .github/pr-custom-review.yml | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml index 615203c11c15b..7ce8146571cd3 100644 --- a/.github/pr-custom-review.yml +++ b/.github/pr-custom-review.yml @@ -1,18 +1,16 @@ +# 🔒 PROTECTED: Changes to locks-review-team should be approved by the current locks-review-team +locks-review-team: locks-review +team-leads-team: polkadot-review +action-review-team: ci + rules: - - name: Changed runtime files - condition: .*/runtime/.*lib.rs + - name: Core developers check_type: changed_files + condition: .* min_approvals: 2 teams: - - substrateteamleads + - core-devs - - name: Substrate developers - check_type: changed_files - condition: .* - any: - - min_approvals: 2 - teams: - - core-devs - - min_approvals: 1 - teams: - - substrateteamleads \ No newline at end of file +prevent_review_request: + teams: + - core-devs From 174735ea1bb5fc4513519c45181d8df63d86f613 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 7 Apr 2022 21:33:11 +0200 Subject: [PATCH 0677/1472] Sub-commands for `benchmark` (#11164) * Restructure benchmark commands Signed-off-by: Oliver Tale-Yazdi * Add benchmark block test Signed-off-by: Oliver Tale-Yazdi * Fixup imports Signed-off-by: Oliver Tale-Yazdi * CI Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Extend error message Signed-off-by: Oliver Tale-Yazdi * Apply suggestions from code review Co-authored-by: Zeke Mostov * Review fixes Signed-off-by: Oliver Tale-Yazdi * Add commands to node-template Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Zeke Mostov --- Cargo.lock | 4 + bin/node-template/node/Cargo.toml | 4 + bin/node-template/node/src/cli.rs | 4 +- bin/node-template/node/src/command.rs | 46 +++- bin/node-template/node/src/command_helper.rs | 131 ++++++++++++ bin/node-template/node/src/main.rs | 1 + bin/node-template/node/src/service.rs | 2 +- bin/node-template/runtime/src/lib.rs | 3 + bin/node/cli/src/cli.rs | 23 +- bin/node/cli/src/command.rs | 70 +++--- bin/node/cli/src/command_helper.rs | 12 +- bin/node/cli/tests/benchmark_block_works.rs | 48 +++++ .../cli/tests/benchmark_overhead_works.rs | 4 +- bin/node/cli/tests/benchmark_storage_works.rs | 4 +- .../frame/benchmarking-cli/src/block/bench.rs | 2 +- utils/frame/benchmarking-cli/src/block/cmd.rs | 4 +- utils/frame/benchmarking-cli/src/lib.rs | 201 +++++++----------- .../benchmarking-cli/src/overhead/bench.rs | 3 +- .../benchmarking-cli/src/overhead/cmd.rs | 8 +- .../benchmarking-cli/src/overhead/template.rs | 4 +- .../src/{ => pallet}/command.rs | 22 +- .../frame/benchmarking-cli/src/pallet/mod.rs | 150 +++++++++++++ .../src/{ => pallet}/template.hbs | 0 .../src/{ => pallet}/writer.rs | 44 +--- .../frame/benchmarking-cli/src/shared/mod.rs | 65 ++++++ .../benchmarking-cli/src/shared/record.rs | 72 +++++++ .../{storage/record.rs => shared/stats.rs} | 74 ++----- .../mod.rs => shared/weight_params.rs} | 8 +- .../frame/benchmarking-cli/src/storage/cmd.rs | 7 +- .../frame/benchmarking-cli/src/storage/mod.rs | 1 - .../benchmarking-cli/src/storage/read.rs | 3 +- .../benchmarking-cli/src/storage/template.rs | 5 +- .../benchmarking-cli/src/storage/write.rs | 3 +- 33 files changed, 690 insertions(+), 342 deletions(-) create mode 100644 bin/node-template/node/src/command_helper.rs create mode 100644 bin/node/cli/tests/benchmark_block_works.rs rename utils/frame/benchmarking-cli/src/{ => pallet}/command.rs (95%) create mode 100644 utils/frame/benchmarking-cli/src/pallet/mod.rs rename utils/frame/benchmarking-cli/src/{ => pallet}/template.hbs (100%) rename utils/frame/benchmarking-cli/src/{ => pallet}/writer.rs (93%) create mode 100644 utils/frame/benchmarking-cli/src/shared/mod.rs create mode 100644 utils/frame/benchmarking-cli/src/shared/record.rs rename utils/frame/benchmarking-cli/src/{storage/record.rs => shared/stats.rs} (70%) rename utils/frame/benchmarking-cli/src/{post_processing/mod.rs => shared/weight_params.rs} (92%) diff --git a/Cargo.lock b/Cargo.lock index 0a1a1e0b17bec..1ecb25b7b4b1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5089,8 +5089,10 @@ dependencies = [ "clap 3.1.6", "frame-benchmarking", "frame-benchmarking-cli", + "frame-system", "jsonrpc-core", "node-template-runtime", + "pallet-transaction-payment", "pallet-transaction-payment-rpc", "sc-basic-authorship", "sc-cli", @@ -5113,6 +5115,8 @@ dependencies = [ "sp-consensus-aura", "sp-core", "sp-finality-grandpa", + "sp-inherents", + "sp-keyring", "sp-runtime", "sp-timestamp", "substrate-build-script-utils", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 4549a5b613da2..e642ce3c0411e 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -36,6 +36,10 @@ sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/final sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } +sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } +sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } +pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" } # These dependencies are used for the node template's RPCs jsonrpc-core = "18.0.0" diff --git a/bin/node-template/node/src/cli.rs b/bin/node-template/node/src/cli.rs index c4d27b71e4994..710c7f3f9e145 100644 --- a/bin/node-template/node/src/cli.rs +++ b/bin/node-template/node/src/cli.rs @@ -36,8 +36,8 @@ pub enum Subcommand { /// Revert the chain to a previous state. Revert(sc_cli::RevertCmd), - /// The custom benchmark subcommand benchmarking runtime pallets. - #[clap(name = "benchmark", about = "Benchmark runtime pallets.")] + /// Sub-commands concerned with benchmarking. + #[clap(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), /// Try some command against runtime state. diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index f033e779543a0..ede969b3572c8 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -1,11 +1,14 @@ use crate::{ chain_spec, cli::{Cli, Subcommand}, + command_helper::{inherent_benchmark_data, BenchmarkExtrinsicBuilder}, service, }; +use frame_benchmarking_cli::BenchmarkCmd; use node_template_runtime::Block; use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; +use std::sync::Arc; impl SubstrateCli for Cli { fn impl_name() -> String { @@ -102,16 +105,41 @@ pub fn run() -> sc_cli::Result<()> { Ok((cmd.run(client, backend, Some(aux_revert)), task_manager)) }) }, - Some(Subcommand::Benchmark(cmd)) => - if cfg!(feature = "runtime-benchmarks") { - let runner = cli.create_runner(cmd)?; + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + + runner.sync_run(|config| { + let PartialComponents { client, backend, .. } = service::new_partial(&config)?; + + // This switch needs to be in the client, since the client decides + // which sub-commands it wants to support. + match cmd { + BenchmarkCmd::Pallet(cmd) => { + if !cfg!(feature = "runtime-benchmarks") { + return Err( + "Runtime benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + .into(), + ) + } + + cmd.run::(config) + }, + BenchmarkCmd::Block(cmd) => cmd.run(client), + BenchmarkCmd::Storage(cmd) => { + let db = backend.expose_db(); + let storage = backend.expose_storage(); - runner.sync_run(|config| cmd.run::(config)) - } else { - Err("Benchmarking wasn't enabled when building the node. You can enable it with \ - `--features runtime-benchmarks`." - .into()) - }, + cmd.run(config, client, db, storage) + }, + BenchmarkCmd::Overhead(cmd) => { + let ext_builder = BenchmarkExtrinsicBuilder::new(client.clone()); + + cmd.run(config, client, inherent_benchmark_data()?, Arc::new(ext_builder)) + }, + } + }) + }, #[cfg(feature = "try-runtime")] Some(Subcommand::TryRuntime(cmd)) => { let runner = cli.create_runner(cmd)?; diff --git a/bin/node-template/node/src/command_helper.rs b/bin/node-template/node/src/command_helper.rs new file mode 100644 index 0000000000000..287e81b1e96bd --- /dev/null +++ b/bin/node-template/node/src/command_helper.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Contains code to setup the command invocations in [`super::command`] which would +//! otherwise bloat that module. + +use crate::service::FullClient; + +use node_template_runtime as runtime; +use runtime::SystemCall; +use sc_cli::Result; +use sc_client_api::BlockBackend; +use sp_core::{Encode, Pair}; +use sp_inherents::{InherentData, InherentDataProvider}; +use sp_keyring::Sr25519Keyring; +use sp_runtime::{OpaqueExtrinsic, SaturatedConversion}; + +use std::{sync::Arc, time::Duration}; + +/// Generates extrinsics for the `benchmark overhead` command. +/// +/// Note: Should only be used for benchmarking. +pub struct BenchmarkExtrinsicBuilder { + client: Arc, +} + +impl BenchmarkExtrinsicBuilder { + /// Creates a new [`Self`] from the given client. + pub fn new(client: Arc) -> Self { + Self { client } + } +} + +impl frame_benchmarking_cli::ExtrinsicBuilder for BenchmarkExtrinsicBuilder { + fn remark(&self, nonce: u32) -> std::result::Result { + let acc = Sr25519Keyring::Bob.pair(); + let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic( + self.client.as_ref(), + acc, + SystemCall::remark { remark: vec![] }.into(), + nonce, + ) + .into(); + + Ok(extrinsic) + } +} + +/// Create a transaction using the given `call`. +/// +/// Note: Should only be used for benchmarking. +pub fn create_benchmark_extrinsic( + client: &FullClient, + sender: sp_core::sr25519::Pair, + call: runtime::Call, + nonce: u32, +) -> runtime::UncheckedExtrinsic { + let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); + let best_hash = client.chain_info().best_hash; + let best_block = client.chain_info().best_number; + + let period = runtime::BlockHashCount::get() + .checked_next_power_of_two() + .map(|c| c / 2) + .unwrap_or(2) as u64; + let extra: runtime::SignedExtra = ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(sp_runtime::generic::Era::mortal( + period, + best_block.saturated_into(), + )), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(0), + ); + + let raw_payload = runtime::SignedPayload::from_raw( + call.clone(), + extra.clone(), + ( + (), + runtime::VERSION.spec_version, + runtime::VERSION.transaction_version, + genesis_hash, + best_hash, + (), + (), + (), + ), + ); + let signature = raw_payload.using_encoded(|e| sender.sign(e)); + + runtime::UncheckedExtrinsic::new_signed( + call.clone(), + sp_runtime::AccountId32::from(sender.public()).into(), + runtime::Signature::Sr25519(signature.clone()), + extra.clone(), + ) +} + +/// Generates inherent data for the `benchmark overhead` command. +/// +/// Note: Should only be used for benchmarking. +pub fn inherent_benchmark_data() -> Result { + let mut inherent_data = InherentData::new(); + let d = Duration::from_millis(0); + let timestamp = sp_timestamp::InherentDataProvider::new(d.into()); + + timestamp + .provide_inherent_data(&mut inherent_data) + .map_err(|e| format!("creating inherent data: {:?}", e))?; + Ok(inherent_data) +} diff --git a/bin/node-template/node/src/main.rs b/bin/node-template/node/src/main.rs index 4449d28b9fa41..0f2fbd5a909c6 100644 --- a/bin/node-template/node/src/main.rs +++ b/bin/node-template/node/src/main.rs @@ -6,6 +6,7 @@ mod chain_spec; mod service; mod cli; mod command; +mod command_helper; mod rpc; fn main() -> sc_cli::Result<()> { diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index fc7dc9b978df3..e2a8cb4ed834b 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -31,7 +31,7 @@ impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { } } -type FullClient = +pub(crate) type FullClient = sc_service::TFullClient>; type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 40adbb0388111..780a84572d582 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -33,6 +33,7 @@ pub use frame_support::{ }, StorageValue, }; +pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_timestamp::Call as TimestampCall; use pallet_transaction_payment::CurrencyAdapter; @@ -306,6 +307,8 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +/// The payload being signed in transactions. +pub type SignedPayload = generic::SignedPayload; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 952c6311f8b38..7430cc46f4cc7 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -38,28 +38,11 @@ pub enum Subcommand { )] Inspect(node_inspect::cli::InspectCmd), - /// The custom benchmark subcommmand benchmarking runtime pallets. - #[clap(name = "benchmark", about = "Benchmark runtime pallets.")] + /// Sub-commands concerned with benchmarking. + /// The pallet benchmarking moved to the `pallet` sub-command. + #[clap(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), - /// Benchmark the execution time of historic blocks and compare it to their consumed weight. - #[clap( - name = "benchmark-block", - about = "Benchmark the execution time of historic blocks and compare it to their consumed weight." - )] - BenchmarkBlock(frame_benchmarking_cli::BlockCmd), - - /// Sub command for benchmarking the per-block and per-extrinsic execution overhead. - #[clap( - name = "benchmark-overhead", - about = "Benchmark the per-block and per-extrinsic execution overhead." - )] - BenchmarkOverhead(frame_benchmarking_cli::OverheadCmd), - - /// Sub command for benchmarking the storage speed. - #[clap(name = "benchmark-storage", about = "Benchmark storage speed.")] - BenchmarkStorage(frame_benchmarking_cli::StorageCmd), - /// Try some command against runtime state. #[cfg(feature = "try-runtime")] TryRuntime(try_runtime_cli::TryRuntimeCmd), diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index db243ff6f597b..c752b1c30ae26 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -16,11 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use super::command_helper::{inherent_benchmark_data, BenchmarkExtrinsicBuilder}; use crate::{ chain_spec, service, service::{new_partial, FullClient}, Cli, Subcommand, }; +use frame_benchmarking_cli::*; use node_executor::ExecutorDispatch; use node_primitives::Block; use node_runtime::RuntimeApi; @@ -92,45 +94,39 @@ pub fn run() -> Result<()> { runner.sync_run(|config| cmd.run::(config)) }, - Some(Subcommand::Benchmark(cmd)) => - if cfg!(feature = "runtime-benchmarks") { - let runner = cli.create_runner(cmd)?; - - runner.sync_run(|config| cmd.run::(config)) - } else { - Err("Benchmarking wasn't enabled when building the node. \ - You can enable it with `--features runtime-benchmarks`." - .into()) - }, - Some(Subcommand::BenchmarkBlock(cmd)) => { + Some(Subcommand::Benchmark(cmd)) => { let runner = cli.create_runner(cmd)?; - runner.async_run(|config| { - let PartialComponents { client, task_manager, .. } = new_partial(&config)?; - Ok((cmd.run(client), task_manager)) - }) - }, - Some(Subcommand::BenchmarkOverhead(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.async_run(|mut config| { - use super::command_helper::{inherent_data, ExtrinsicBuilder}; - // We don't use the authority role since that would start producing blocks - // in the background which would mess with our benchmark. - config.role = sc_service::Role::Full; - - let PartialComponents { client, task_manager, .. } = new_partial(&config)?; - let ext_builder = ExtrinsicBuilder::new(client.clone()); - - Ok((cmd.run(config, client, inherent_data()?, Arc::new(ext_builder)), task_manager)) - }) - }, - Some(Subcommand::BenchmarkStorage(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.async_run(|config| { - let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?; - let db = backend.expose_db(); - let storage = backend.expose_storage(); - Ok((cmd.run(config, client, db, storage), task_manager)) + runner.sync_run(|config| { + let PartialComponents { client, backend, .. } = new_partial(&config)?; + + // This switch needs to be in the client, since the client decides + // which sub-commands it wants to support. + match cmd { + BenchmarkCmd::Pallet(cmd) => { + if !cfg!(feature = "runtime-benchmarks") { + return Err( + "Runtime benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + .into(), + ) + } + + cmd.run::(config) + }, + BenchmarkCmd::Block(cmd) => cmd.run(client), + BenchmarkCmd::Storage(cmd) => { + let db = backend.expose_db(); + let storage = backend.expose_storage(); + + cmd.run(config, client, db, storage) + }, + BenchmarkCmd::Overhead(cmd) => { + let ext_builder = BenchmarkExtrinsicBuilder::new(client.clone()); + + cmd.run(config, client, inherent_benchmark_data()?, Arc::new(ext_builder)) + }, + } }) }, Some(Subcommand::Key(cmd)) => cmd.run(&cli), diff --git a/bin/node/cli/src/command_helper.rs b/bin/node/cli/src/command_helper.rs index 51fe7a5c5a7bf..84d85ee367cab 100644 --- a/bin/node/cli/src/command_helper.rs +++ b/bin/node/cli/src/command_helper.rs @@ -29,19 +29,19 @@ use sp_runtime::OpaqueExtrinsic; use std::{sync::Arc, time::Duration}; -/// Generates extrinsics for the `benchmark-overhead` command. -pub struct ExtrinsicBuilder { +/// Generates extrinsics for the `benchmark overhead` command. +pub struct BenchmarkExtrinsicBuilder { client: Arc, } -impl ExtrinsicBuilder { +impl BenchmarkExtrinsicBuilder { /// Creates a new [`Self`] from the given client. pub fn new(client: Arc) -> Self { Self { client } } } -impl frame_benchmarking_cli::ExtrinsicBuilder for ExtrinsicBuilder { +impl frame_benchmarking_cli::ExtrinsicBuilder for BenchmarkExtrinsicBuilder { fn remark(&self, nonce: u32) -> std::result::Result { let acc = Sr25519Keyring::Bob.pair(); let extrinsic: OpaqueExtrinsic = create_extrinsic( @@ -56,8 +56,8 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for ExtrinsicBuilder { } } -/// Generates inherent data for the `benchmark-overhead` command. -pub fn inherent_data() -> Result { +/// Generates inherent data for the `benchmark overhead` command. +pub fn inherent_benchmark_data() -> Result { let mut inherent_data = InherentData::new(); let d = Duration::from_millis(0); let timestamp = sp_timestamp::InherentDataProvider::new(d.into()); diff --git a/bin/node/cli/tests/benchmark_block_works.rs b/bin/node/cli/tests/benchmark_block_works.rs new file mode 100644 index 0000000000000..37a4db25f363b --- /dev/null +++ b/bin/node/cli/tests/benchmark_block_works.rs @@ -0,0 +1,48 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// Unix only since it uses signals from [`common::run_node_for_a_while`]. +#![cfg(unix)] + +use assert_cmd::cargo::cargo_bin; +use std::process::Command; +use tempfile::tempdir; + +pub mod common; + +/// `benchmark block` works for the dev runtime using the wasm executor. +#[tokio::test] +async fn benchmark_block_works() { + let base_dir = tempdir().expect("could not create a temp dir"); + + common::run_node_for_a_while(base_dir.path(), &["--dev"]).await; + + // Invoke `benchmark block` with all options to make sure that they are valid. + let status = Command::new(cargo_bin("substrate")) + .args(["benchmark", "block", "--dev"]) + .arg("-d") + .arg(base_dir.path()) + .args(["--pruning", "archive"]) + .args(["--from", "1", "--to", "1"]) + .args(["--repeat", "1"]) + .args(["--execution", "wasm", "--wasm-execution", "compiled"]) + .status() + .unwrap(); + + assert!(status.success()) +} diff --git a/bin/node/cli/tests/benchmark_overhead_works.rs b/bin/node/cli/tests/benchmark_overhead_works.rs index 550221ee2f70f..44dcebfbc0c35 100644 --- a/bin/node/cli/tests/benchmark_overhead_works.rs +++ b/bin/node/cli/tests/benchmark_overhead_works.rs @@ -20,7 +20,7 @@ use assert_cmd::cargo::cargo_bin; use std::process::Command; use tempfile::tempdir; -/// Tests that the `benchmark-overhead` command works for the substrate dev runtime. +/// Tests that the `benchmark overhead` command works for the substrate dev runtime. #[test] fn benchmark_overhead_works() { let tmp_dir = tempdir().expect("could not create a temp dir"); @@ -29,7 +29,7 @@ fn benchmark_overhead_works() { // Only put 10 extrinsics into the block otherwise it takes forever to build it // especially for a non-release build. let status = Command::new(cargo_bin("substrate")) - .args(&["benchmark-overhead", "--dev", "-d"]) + .args(&["benchmark", "overhead", "--dev", "-d"]) .arg(base_path) .arg("--weight-path") .arg(base_path) diff --git a/bin/node/cli/tests/benchmark_storage_works.rs b/bin/node/cli/tests/benchmark_storage_works.rs index 1628f9a7e97ba..30f860e48459f 100644 --- a/bin/node/cli/tests/benchmark_storage_works.rs +++ b/bin/node/cli/tests/benchmark_storage_works.rs @@ -23,7 +23,7 @@ use std::{ }; use tempfile::tempdir; -/// Tests that the `benchmark-storage` command works for the dev runtime. +/// Tests that the `benchmark storage` command works for the dev runtime. #[test] fn benchmark_storage_works() { let tmp_dir = tempdir().expect("could not create a temp dir"); @@ -39,7 +39,7 @@ fn benchmark_storage_works() { fn benchmark_storage(db: &str, base_path: &Path) -> ExitStatus { Command::new(cargo_bin("substrate")) - .args(&["benchmark-storage", "--dev"]) + .args(&["benchmark", "storage", "--dev"]) .arg("--db") .arg(db) .arg("--weight-path") diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index d3c1c97b04ab2..e48a7e8b3c6f5 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -34,7 +34,7 @@ use serde::Serialize; use std::{fmt::Debug, marker::PhantomData, sync::Arc, time::Instant}; use thousands::Separable; -use crate::storage::record::{StatSelect, Stats}; +use crate::shared::{StatSelect, Stats}; /// Log target for printing block weight info. const LOG_TARGET: &'static str = "benchmark::block::weight"; diff --git a/utils/frame/benchmarking-cli/src/block/cmd.rs b/utils/frame/benchmarking-cli/src/block/cmd.rs index 4618c1dd894e1..e4e1716b1c5ac 100644 --- a/utils/frame/benchmarking-cli/src/block/cmd.rs +++ b/utils/frame/benchmarking-cli/src/block/cmd.rs @@ -29,7 +29,7 @@ use std::{fmt::Debug, sync::Arc}; use super::bench::{Benchmark, BenchmarkParams}; -/// Benchmark the execution time historic blocks. +/// Benchmark the execution time of historic blocks. /// /// This can be used to verify that blocks do not use more weight than they consumed /// in their `WeightInfo`. Example: @@ -73,7 +73,7 @@ impl BlockCmd { /// Benchmark the execution time of historic blocks and compare it to their consumed weight. /// /// Output will be printed to console. - pub async fn run(&self, client: Arc) -> Result<()> + pub fn run(&self, client: Arc) -> Result<()> where Block: BlockT, BA: ClientBackend, diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 288e6b4b86156..2543a63b2f159 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -15,144 +15,85 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Contains the root [`BenchmarkCmd`] command and exports its sub-commands. + mod block; -mod command; -pub mod overhead; -mod post_processing; +mod overhead; +mod pallet; +mod shared; mod storage; -mod writer; - -use sc_cli::{ExecutionStrategy, WasmExecutionMethod, DEFAULT_WASM_EXECUTION_METHOD}; -use std::{fmt::Debug, path::PathBuf}; pub use block::BlockCmd; pub use overhead::{ExtrinsicBuilder, OverheadCmd}; +pub use pallet::PalletCmd; pub use storage::StorageCmd; -// Add a more relaxed parsing for pallet names by allowing pallet directory names with `-` to be -// used like crate names with `_` -fn parse_pallet_name(pallet: &str) -> String { - pallet.replace("-", "_") +use sc_cli::{CliConfiguration, DatabaseParams, ImportParams, PruningParams, Result, SharedParams}; + +/// The root `benchmarking` command. +/// +/// Has no effect itself besides printing a help menu of the sub-commands. +#[derive(Debug, clap::Subcommand)] +pub enum BenchmarkCmd { + Pallet(PalletCmd), + Storage(StorageCmd), + Overhead(OverheadCmd), + Block(BlockCmd), } -/// The `benchmark` command used to benchmark FRAME Pallets. -#[derive(Debug, clap::Parser)] -pub struct BenchmarkCmd { - /// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`). - #[clap(short, long, parse(from_str = parse_pallet_name), required_unless_present = "list")] - pub pallet: Option, - - /// Select an extrinsic inside the pallet to benchmark, or `*` for all. - #[clap(short, long, required_unless_present = "list")] - pub extrinsic: Option, - - /// Select how many samples we should take across the variable components. - #[clap(short, long, default_value = "1")] - pub steps: u32, - - /// Indicates lowest values for each of the component ranges. - #[clap(long = "low", use_value_delimiter = true)] - pub lowest_range_values: Vec, - - /// Indicates highest values for each of the component ranges. - #[clap(long = "high", use_value_delimiter = true)] - pub highest_range_values: Vec, - - /// Select how many repetitions of this benchmark should run from within the wasm. - #[clap(short, long, default_value = "1")] - pub repeat: u32, - - /// Select how many repetitions of this benchmark should run from the client. - /// - /// NOTE: Using this alone may give slower results, but will afford you maximum Wasm memory. - #[clap(long, default_value = "1")] - pub external_repeat: u32, - - /// Print the raw results in JSON format. - #[clap(long = "json")] - pub json_output: bool, - - /// Write the raw results in JSON format into the given file. - #[clap(long, conflicts_with = "json-output")] - pub json_file: Option, - - /// Don't print the median-slopes linear regression analysis. - #[clap(long)] - pub no_median_slopes: bool, - - /// Don't print the min-squares linear regression analysis. - #[clap(long)] - pub no_min_squares: bool, - - /// Output the benchmarks to a Rust file at the given path. - #[clap(long)] - pub output: Option, - - /// Add a header file to your outputted benchmarks - #[clap(long)] - pub header: Option, - - /// Path to Handlebars template file used for outputting benchmark results. (Optional) - #[clap(long)] - pub template: Option, - - /// Which analysis function to use when outputting benchmarks: - /// * min-squares (default) - /// * median-slopes - /// * max (max of min squares and median slopes for each value) - #[clap(long)] - pub output_analysis: Option, - - /// Set the heap pages while running benchmarks. If not set, the default value from the client - /// is used. - #[clap(long)] - pub heap_pages: Option, - - /// Disable verification logic when running benchmarks. - #[clap(long)] - pub no_verify: bool, - - /// Display and run extra benchmarks that would otherwise not be needed for weight - /// construction. - #[clap(long)] - pub extra: bool, - - /// Estimate PoV size. - #[clap(long)] - pub record_proof: bool, - - #[allow(missing_docs)] - #[clap(flatten)] - pub shared_params: sc_cli::SharedParams, - - /// The execution strategy that should be used for benchmarks - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] - pub execution: Option, - - /// Method for executing Wasm runtime code. - #[clap( - long = "wasm-execution", - value_name = "METHOD", - possible_values = WasmExecutionMethod::variants(), - ignore_case = true, - default_value = DEFAULT_WASM_EXECUTION_METHOD, - )] - pub wasm_method: WasmExecutionMethod, - - /// Limit the memory the database cache can use. - #[clap(long = "db-cache", value_name = "MiB", default_value = "1024")] - pub database_cache_size: u32, - - /// List the benchmarks that match your query rather than running them. - /// - /// When nothing is provided, we list all benchmarks. - #[clap(long)] - pub list: bool, +/// Unwraps a [`BenchmarkCmd`] into its concrete sub-command. +macro_rules! unwrap_cmd { + { + $self:expr, + $cmd:ident, + $code:expr + } => { + match $self { + BenchmarkCmd::Pallet($cmd) => $code, + BenchmarkCmd::Storage($cmd) => $code, + BenchmarkCmd::Overhead($cmd) => $code, + BenchmarkCmd::Block($cmd) => $code, + } + } +} - /// If enabled, the storage info is not displayed in the output next to the analysis. - /// - /// This is independent of the storage info appearing in the *output file*. Use a Handlebar - /// template for that purpose. - #[clap(long)] - pub no_storage_info: bool, +/// Forward the [`CliConfiguration`] trait implementation. +/// +/// Each time a sub-command exposes a new config option, it must be added here. +impl CliConfiguration for BenchmarkCmd { + fn shared_params(&self) -> &SharedParams { + unwrap_cmd! { + self, cmd, cmd.shared_params() + } + } + + fn import_params(&self) -> Option<&ImportParams> { + unwrap_cmd! { + self, cmd, cmd.import_params() + } + } + + fn database_params(&self) -> Option<&DatabaseParams> { + unwrap_cmd! { + self, cmd, cmd.database_params() + } + } + + fn pruning_params(&self) -> Option<&PruningParams> { + unwrap_cmd! { + self, cmd, cmd.pruning_params() + } + } + + fn state_cache_size(&self) -> Result { + unwrap_cmd! { + self, cmd, cmd.state_cache_size() + } + } + + fn chain_id(&self, is_dev: bool) -> Result { + unwrap_cmd! { + self, cmd, cmd.chain_id(is_dev) + } + } } diff --git a/utils/frame/benchmarking-cli/src/overhead/bench.rs b/utils/frame/benchmarking-cli/src/overhead/bench.rs index 3e18c6a86db24..68f3f6597b466 100644 --- a/utils/frame/benchmarking-cli/src/overhead/bench.rs +++ b/utils/frame/benchmarking-cli/src/overhead/bench.rs @@ -36,7 +36,8 @@ use log::info; use serde::Serialize; use std::{marker::PhantomData, sync::Arc, time::Instant}; -use crate::{overhead::cmd::ExtrinsicBuilder, storage::record::Stats}; +use super::cmd::ExtrinsicBuilder; +use crate::shared::Stats; /// Parameters to configure an *overhead* benchmark. #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index f74c32ba72a86..3cf281986861f 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -35,10 +35,10 @@ use crate::{ bench::{Benchmark, BenchmarkParams, BenchmarkType}, template::TemplateData, }, - post_processing::WeightParams, + shared::WeightParams, }; -/// Benchmarks the per-block and per-extrinsic execution overhead. +/// Benchmark the execution overhead per-block and per-extrinsic. #[derive(Debug, Parser)] pub struct OverheadCmd { #[allow(missing_docs)] @@ -76,11 +76,11 @@ pub trait ExtrinsicBuilder { } impl OverheadCmd { - /// Measures the per-block and per-extrinsic execution overhead. + /// Measure the per-block and per-extrinsic execution overhead. /// /// Writes the results to console and into two instances of the /// `weights.hbs` template, one for each benchmark. - pub async fn run( + pub fn run( &self, cfg: Configuration, client: Arc, diff --git a/utils/frame/benchmarking-cli/src/overhead/template.rs b/utils/frame/benchmarking-cli/src/overhead/template.rs index f6fb8ed9d929e..d5f90d4873866 100644 --- a/utils/frame/benchmarking-cli/src/overhead/template.rs +++ b/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -28,7 +28,7 @@ use std::{env, fs, path::PathBuf}; use crate::{ overhead::{bench::BenchmarkType, cmd::OverheadParams}, - storage::record::Stats, + shared::{Stats, UnderscoreHelper}, }; static VERSION: &'static str = env!("CARGO_PKG_VERSION"); @@ -85,7 +85,7 @@ impl TemplateData { pub fn write(&self, path: &Option) -> Result<()> { let mut handlebars = Handlebars::new(); // Format large integers with underscores. - handlebars.register_helper("underscore", Box::new(crate::writer::UnderscoreHelper)); + handlebars.register_helper("underscore", Box::new(UnderscoreHelper)); // Don't HTML escape any characters. handlebars.register_escape_fn(|s| -> String { s.to_string() }); diff --git a/utils/frame/benchmarking-cli/src/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs similarity index 95% rename from utils/frame/benchmarking-cli/src/command.rs rename to utils/frame/benchmarking-cli/src/pallet/command.rs index 0ced8b28ce016..89b8d018bcb5c 100644 --- a/utils/frame/benchmarking-cli/src/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::BenchmarkCmd; +use super::{writer, PalletCmd}; use codec::{Decode, Encode}; use frame_benchmarking::{ Analysis, BenchmarkBatch, BenchmarkBatchSplitResults, BenchmarkList, BenchmarkParameter, @@ -87,7 +87,13 @@ fn combine_batches( .collect::>() } -impl BenchmarkCmd { +/// Explains possible reasons why the metadata for the benchmarking could not be found. +const ERROR_METADATA_NOT_FOUND: &'static str = "Did not find the benchmarking metadata. \ +This could mean that you either did not build the node correctly with the \ +`--features runtime-benchmarks` flag, or the chain spec that you are using was \ +not created by a node that was compiled with the flag"; + +impl PalletCmd { /// Runs the command and benchmarks the chain. pub fn run(&self, config: Configuration) -> Result<()> where @@ -165,7 +171,7 @@ impl BenchmarkCmd { sp_core::testing::TaskExecutor::new(), ) .execute(strategy.into()) - .map_err(|e| format!("Error getting benchmark list: {}", e))?; + .map_err(|e| format!("{}: {}", ERROR_METADATA_NOT_FOUND, e))?; let (list, storage_info) = <(Vec, Vec) as Decode>::decode(&mut &result[..]) @@ -359,7 +365,7 @@ impl BenchmarkCmd { // Create the weights.rs file. if let Some(output_path) = &self.output { - crate::writer::write_results(&batches, &storage_info, output_path, self)?; + writer::write_results(&batches, &storage_info, output_path, self)?; } // Jsonify the result and write it to a file or stdout if desired. @@ -414,11 +420,7 @@ impl BenchmarkCmd { if !self.no_storage_info { let mut comments: Vec = Default::default(); - crate::writer::add_storage_comments( - &mut comments, - &batch.db_results, - &storage_info, - ); + writer::add_storage_comments(&mut comments, &batch.db_results, &storage_info); println!("Raw Storage Info\n========"); for comment in comments { println!("{}", comment); @@ -469,7 +471,7 @@ impl BenchmarkCmd { } } -impl CliConfiguration for BenchmarkCmd { +impl CliConfiguration for PalletCmd { fn shared_params(&self) -> &SharedParams { &self.shared_params } diff --git a/utils/frame/benchmarking-cli/src/pallet/mod.rs b/utils/frame/benchmarking-cli/src/pallet/mod.rs new file mode 100644 index 0000000000000..48ddcc7ce8eec --- /dev/null +++ b/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -0,0 +1,150 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod command; +mod writer; + +use sc_cli::{ExecutionStrategy, WasmExecutionMethod, DEFAULT_WASM_EXECUTION_METHOD}; +use std::{fmt::Debug, path::PathBuf}; + +// Add a more relaxed parsing for pallet names by allowing pallet directory names with `-` to be +// used like crate names with `_` +fn parse_pallet_name(pallet: &str) -> String { + pallet.replace("-", "_") +} + +/// Benchmark the extrinsic weight of FRAME Pallets. +#[derive(Debug, clap::Parser)] +pub struct PalletCmd { + /// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`). + #[clap(short, long, parse(from_str = parse_pallet_name), required_unless_present = "list")] + pub pallet: Option, + + /// Select an extrinsic inside the pallet to benchmark, or `*` for all. + #[clap(short, long, required_unless_present = "list")] + pub extrinsic: Option, + + /// Select how many samples we should take across the variable components. + #[clap(short, long, default_value = "1")] + pub steps: u32, + + /// Indicates lowest values for each of the component ranges. + #[clap(long = "low", use_value_delimiter = true)] + pub lowest_range_values: Vec, + + /// Indicates highest values for each of the component ranges. + #[clap(long = "high", use_value_delimiter = true)] + pub highest_range_values: Vec, + + /// Select how many repetitions of this benchmark should run from within the wasm. + #[clap(short, long, default_value = "1")] + pub repeat: u32, + + /// Select how many repetitions of this benchmark should run from the client. + /// + /// NOTE: Using this alone may give slower results, but will afford you maximum Wasm memory. + #[clap(long, default_value = "1")] + pub external_repeat: u32, + + /// Print the raw results in JSON format. + #[clap(long = "json")] + pub json_output: bool, + + /// Write the raw results in JSON format into the given file. + #[clap(long, conflicts_with = "json-output")] + pub json_file: Option, + + /// Don't print the median-slopes linear regression analysis. + #[clap(long)] + pub no_median_slopes: bool, + + /// Don't print the min-squares linear regression analysis. + #[clap(long)] + pub no_min_squares: bool, + + /// Output the benchmarks to a Rust file at the given path. + #[clap(long)] + pub output: Option, + + /// Add a header file to your outputted benchmarks. + #[clap(long)] + pub header: Option, + + /// Path to Handlebars template file used for outputting benchmark results. (Optional) + #[clap(long)] + pub template: Option, + + /// Which analysis function to use when outputting benchmarks: + /// * min-squares (default) + /// * median-slopes + /// * max (max of min squares and median slopes for each value) + #[clap(long)] + pub output_analysis: Option, + + /// Set the heap pages while running benchmarks. If not set, the default value from the client + /// is used. + #[clap(long)] + pub heap_pages: Option, + + /// Disable verification logic when running benchmarks. + #[clap(long)] + pub no_verify: bool, + + /// Display and run extra benchmarks that would otherwise not be needed for weight + /// construction. + #[clap(long)] + pub extra: bool, + + /// Estimate PoV size. + #[clap(long)] + pub record_proof: bool, + + #[allow(missing_docs)] + #[clap(flatten)] + pub shared_params: sc_cli::SharedParams, + + /// The execution strategy that should be used for benchmarks. + #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + pub execution: Option, + + /// Method for executing Wasm runtime code. + #[clap( + long = "wasm-execution", + value_name = "METHOD", + possible_values = WasmExecutionMethod::variants(), + ignore_case = true, + default_value = DEFAULT_WASM_EXECUTION_METHOD, + )] + pub wasm_method: WasmExecutionMethod, + + /// Limit the memory the database cache can use. + #[clap(long = "db-cache", value_name = "MiB", default_value = "1024")] + pub database_cache_size: u32, + + /// List the benchmarks that match your query rather than running them. + /// + /// When nothing is provided, we list all benchmarks. + #[clap(long)] + pub list: bool, + + /// If enabled, the storage info is not displayed in the output next to the analysis. + /// + /// This is independent of the storage info appearing in the *output file*. Use a Handlebar + /// template for that purpose. + #[clap(long)] + pub no_storage_info: bool, +} diff --git a/utils/frame/benchmarking-cli/src/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs similarity index 100% rename from utils/frame/benchmarking-cli/src/template.hbs rename to utils/frame/benchmarking-cli/src/pallet/template.hbs diff --git a/utils/frame/benchmarking-cli/src/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs similarity index 93% rename from utils/frame/benchmarking-cli/src/writer.rs rename to utils/frame/benchmarking-cli/src/pallet/writer.rs index 17f1221e46d8b..cd97b3efbd9db 100644 --- a/utils/frame/benchmarking-cli/src/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -26,7 +26,7 @@ use std::{ use inflector::Inflector; use serde::Serialize; -use crate::BenchmarkCmd; +use crate::{shared::UnderscoreHelper, PalletCmd}; use frame_benchmarking::{ Analysis, AnalysisChoice, BenchmarkBatchSplitResults, BenchmarkResult, BenchmarkSelector, RegressionModel, @@ -68,7 +68,7 @@ struct BenchmarkData { comments: Vec, } -// This forwards some specific metadata from the `BenchmarkCmd` +// This forwards some specific metadata from the `PalletCmd` #[derive(Serialize, Default, Debug, Clone)] struct CmdData { steps: u32, @@ -255,7 +255,7 @@ pub fn write_results( batches: &[BenchmarkBatchSplitResults], storage_info: &[StorageInfo], path: &PathBuf, - cmd: &BenchmarkCmd, + cmd: &PalletCmd, ) -> Result<(), std::io::Error> { // Use custom template if provided. let template: String = match &cmd.template { @@ -416,44 +416,6 @@ pub(crate) fn add_storage_comments( } } -// Add an underscore after every 3rd character, i.e. a separator for large numbers. -fn underscore(i: Number) -> String -where - Number: std::string::ToString, -{ - let mut s = String::new(); - let i_str = i.to_string(); - let a = i_str.chars().rev().enumerate(); - for (idx, val) in a { - if idx != 0 && idx % 3 == 0 { - s.insert(0, '_'); - } - s.insert(0, val); - } - s -} - -// A Handlebars helper to add an underscore after every 3rd character, -// i.e. a separator for large numbers. -#[derive(Clone, Copy)] -pub(crate) struct UnderscoreHelper; -impl handlebars::HelperDef for UnderscoreHelper { - fn call<'reg: 'rc, 'rc>( - &self, - h: &handlebars::Helper, - _: &handlebars::Handlebars, - _: &handlebars::Context, - _rc: &mut handlebars::RenderContext, - out: &mut dyn handlebars::Output, - ) -> handlebars::HelperResult { - use handlebars::JsonRender; - let param = h.param(0).unwrap(); - let underscore_param = underscore(param.value().render()); - out.write(&underscore_param)?; - Ok(()) - } -} - // A helper to join a string of vectors. #[derive(Clone, Copy)] struct JoinHelper; diff --git a/utils/frame/benchmarking-cli/src/shared/mod.rs b/utils/frame/benchmarking-cli/src/shared/mod.rs new file mode 100644 index 0000000000000..f08d79b9aafca --- /dev/null +++ b/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -0,0 +1,65 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Code that is shared among all benchmarking sub-commands. + +pub mod record; +pub mod stats; +pub mod weight_params; + +pub use record::BenchRecord; +pub use stats::{StatSelect, Stats}; +pub use weight_params::WeightParams; + +/// A Handlebars helper to add an underscore after every 3rd character, +/// i.e. a separator for large numbers. +#[derive(Clone, Copy)] +pub struct UnderscoreHelper; + +impl handlebars::HelperDef for UnderscoreHelper { + fn call<'reg: 'rc, 'rc>( + &self, + h: &handlebars::Helper, + _: &handlebars::Handlebars, + _: &handlebars::Context, + _rc: &mut handlebars::RenderContext, + out: &mut dyn handlebars::Output, + ) -> handlebars::HelperResult { + use handlebars::JsonRender; + let param = h.param(0).unwrap(); + let underscore_param = underscore(param.value().render()); + out.write(&underscore_param)?; + Ok(()) + } +} + +/// Add an underscore after every 3rd character, i.e. a separator for large numbers. +fn underscore(i: Number) -> String +where + Number: std::string::ToString, +{ + let mut s = String::new(); + let i_str = i.to_string(); + let a = i_str.chars().rev().enumerate(); + for (idx, val) in a { + if idx != 0 && idx % 3 == 0 { + s.insert(0, '_'); + } + s.insert(0, val); + } + s +} diff --git a/utils/frame/benchmarking-cli/src/shared/record.rs b/utils/frame/benchmarking-cli/src/shared/record.rs new file mode 100644 index 0000000000000..79ab37f651528 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/shared/record.rs @@ -0,0 +1,72 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Defines the [`BenchRecord`] and its facilities for computing [`super::Stats`]. + +use sc_cli::Result; +use sc_service::Configuration; + +use log::info; +use serde::Serialize; +use std::{fs, path::PathBuf, time::Duration}; + +use super::Stats; + +/// Raw output of a Storage benchmark. +#[derive(Debug, Default, Clone, Serialize)] +pub struct BenchRecord { + /// Multi-Map of value sizes and the time that it took to access them. + ns_per_size: Vec<(u64, u64)>, +} + +impl BenchRecord { + /// Appends a new record. Uses safe casts. + pub fn append(&mut self, size: usize, d: Duration) -> Result<()> { + let size: u64 = size.try_into().map_err(|e| format!("Size overflow u64: {}", e))?; + let ns: u64 = d + .as_nanos() + .try_into() + .map_err(|e| format!("Nanoseconds overflow u64: {}", e))?; + self.ns_per_size.push((size, ns)); + Ok(()) + } + + /// Returns the statistics for *time* and *value size*. + pub fn calculate_stats(self) -> Result<(Stats, Stats)> { + let (size, time): (Vec<_>, Vec<_>) = self.ns_per_size.into_iter().unzip(); + let size = Stats::new(&size)?; + let time = Stats::new(&time)?; + Ok((time, size)) // The swap of time/size here is intentional. + } + + /// Unless a path is specified, saves the raw results in a json file in the current directory. + /// Prefixes it with the DB name and suffixed with `path_suffix`. + pub fn save_json(&self, cfg: &Configuration, out_path: &PathBuf, suffix: &str) -> Result<()> { + let mut path = PathBuf::from(out_path); + if path.is_dir() || path.as_os_str().is_empty() { + path.push(&format!("{}_{}", cfg.database, suffix).to_lowercase()); + path.set_extension("json"); + } + + let json = serde_json::to_string_pretty(&self) + .map_err(|e| format!("Serializing as JSON: {:?}", e))?; + + fs::write(&path, json)?; + info!("Raw data written to {:?}", fs::canonicalize(&path)?); + Ok(()) + } +} diff --git a/utils/frame/benchmarking-cli/src/storage/record.rs b/utils/frame/benchmarking-cli/src/shared/stats.rs similarity index 70% rename from utils/frame/benchmarking-cli/src/storage/record.rs rename to utils/frame/benchmarking-cli/src/shared/stats.rs index 530fa4cdfe965..7785965fed4a7 100644 --- a/utils/frame/benchmarking-cli/src/storage/record.rs +++ b/utils/frame/benchmarking-cli/src/shared/stats.rs @@ -15,46 +15,38 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Calculates statistics and fills out the `weight.hbs` template. +//! Handles statistics that were generated from benchmarking results and +//! that can be used to fill out weight templates. use sc_cli::Result; -use sc_service::Configuration; -use log::info; use serde::Serialize; -use std::{fmt, fs, path::PathBuf, result, str::FromStr, time::Duration}; - -/// Raw output of a Storage benchmark. -#[derive(Debug, Default, Clone, Serialize)] -pub(crate) struct BenchRecord { - /// Multi-Map of value sizes and the time that it took to access them. - ns_per_size: Vec<(u64, u64)>, -} +use std::{fmt, result, str::FromStr}; /// Various statistics that help to gauge the quality of the produced weights. /// Will be written to the weight file and printed to console. #[derive(Serialize, Default, Clone)] -pub(crate) struct Stats { +pub struct Stats { /// Sum of all values. - pub(crate) sum: u64, + pub sum: u64, /// Minimal observed value. - pub(crate) min: u64, + pub min: u64, /// Maximal observed value. - pub(crate) max: u64, + pub max: u64, /// Average of all values. - pub(crate) avg: u64, + pub avg: u64, /// Median of all values. - pub(crate) median: u64, + pub median: u64, /// Standard derivation of all values. - pub(crate) stddev: f64, + pub stddev: f64, /// 99th percentile. At least 99% of all values are below this threshold. - pub(crate) p99: u64, + pub p99: u64, /// 95th percentile. At least 95% of all values are below this threshold. - pub(crate) p95: u64, + pub p95: u64, /// 75th percentile. At least 75% of all values are below this threshold. - pub(crate) p75: u64, + pub p75: u64, } /// Selects a specific field from a [`Stats`] object. @@ -75,44 +67,6 @@ pub enum StatSelect { P75Percentile, } -impl BenchRecord { - /// Appends a new record. Uses safe casts. - pub fn append(&mut self, size: usize, d: Duration) -> Result<()> { - let size: u64 = size.try_into().map_err(|e| format!("Size overflow u64: {}", e))?; - let ns: u64 = d - .as_nanos() - .try_into() - .map_err(|e| format!("Nanoseconds overflow u64: {}", e))?; - self.ns_per_size.push((size, ns)); - Ok(()) - } - - /// Returns the statistics for *time* and *value size*. - pub(crate) fn calculate_stats(self) -> Result<(Stats, Stats)> { - let (size, time): (Vec<_>, Vec<_>) = self.ns_per_size.into_iter().unzip(); - let size = Stats::new(&size)?; - let time = Stats::new(&time)?; - Ok((time, size)) // The swap of time/size here is intentional. - } - - /// Unless a path is specified, saves the raw results in a json file in the current directory. - /// Prefixes it with the DB name and suffixed with `path_suffix`. - pub fn save_json(&self, cfg: &Configuration, out_path: &PathBuf, suffix: &str) -> Result<()> { - let mut path = PathBuf::from(out_path); - if path.is_dir() || path.as_os_str().is_empty() { - path.push(&format!("{}_{}", cfg.database, suffix).to_lowercase()); - path.set_extension("json"); - } - - let json = serde_json::to_string_pretty(&self) - .map_err(|e| format!("Serializing as JSON: {:?}", e))?; - - fs::write(&path, json)?; - info!("Raw data written to {:?}", fs::canonicalize(&path)?); - Ok(()) - } -} - impl Stats { /// Calculates statistics and returns them. pub fn new(xs: &Vec) -> Result { @@ -137,7 +91,7 @@ impl Stats { } /// Returns the selected stat. - pub(crate) fn select(&self, s: StatSelect) -> u64 { + pub fn select(&self, s: StatSelect) -> u64 { match s { StatSelect::Maximum => self.max, StatSelect::Average => self.avg, diff --git a/utils/frame/benchmarking-cli/src/post_processing/mod.rs b/utils/frame/benchmarking-cli/src/shared/weight_params.rs similarity index 92% rename from utils/frame/benchmarking-cli/src/post_processing/mod.rs rename to utils/frame/benchmarking-cli/src/shared/weight_params.rs index fb20d9bd0c488..4dd80cd41ff3d 100644 --- a/utils/frame/benchmarking-cli/src/post_processing/mod.rs +++ b/utils/frame/benchmarking-cli/src/shared/weight_params.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Calculates a weight from the statistics of a benchmark result. +//! Calculates a weight from the [`super::Stats`] of a benchmark result. use sc_cli::Result; @@ -23,7 +23,7 @@ use clap::Args; use serde::Serialize; use std::path::PathBuf; -use crate::storage::record::{StatSelect, Stats}; +use super::{StatSelect, Stats}; /// Configures the weight generation. #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] @@ -55,7 +55,7 @@ pub struct WeightParams { /// `weight_mul` and adding `weight_add`. /// Does not use safe casts and can overflow. impl WeightParams { - pub(crate) fn calc_weight(&self, stat: &Stats) -> Result { + pub fn calc_weight(&self, stat: &Stats) -> Result { if self.weight_mul.is_sign_negative() || !self.weight_mul.is_normal() { return Err("invalid floating number for `weight_mul`".into()) } @@ -68,7 +68,7 @@ impl WeightParams { #[cfg(test)] mod test_weight_params { use super::WeightParams; - use crate::storage::record::{StatSelect, Stats}; + use crate::shared::{StatSelect, Stats}; #[test] fn calc_weight_works() { diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index c38e6636e5a3e..c2cc219ef1528 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -34,8 +34,9 @@ use sp_runtime::generic::BlockId; use std::{fmt::Debug, path::PathBuf, sync::Arc}; use super::template::TemplateData; -use crate::post_processing::WeightParams; -/// Benchmark the storage of a Substrate node with a live chain snapshot. +use crate::shared::WeightParams; + +/// Benchmark the storage speed of a chain snapshot. #[derive(Debug, Parser)] pub struct StorageCmd { #[allow(missing_docs)] @@ -99,7 +100,7 @@ pub struct StorageParams { impl StorageCmd { /// Calls into the Read and Write benchmarking functions. /// Processes the output and writes it into files and stdout. - pub async fn run( + pub fn run( &self, cfg: Configuration, client: Arc, diff --git a/utils/frame/benchmarking-cli/src/storage/mod.rs b/utils/frame/benchmarking-cli/src/storage/mod.rs index 9849cbcb6097b..0c722fdd47029 100644 --- a/utils/frame/benchmarking-cli/src/storage/mod.rs +++ b/utils/frame/benchmarking-cli/src/storage/mod.rs @@ -17,7 +17,6 @@ pub mod cmd; pub mod read; -pub mod record; pub mod template; pub mod write; diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs index ca506202e1067..f58f3c3de0c19 100644 --- a/utils/frame/benchmarking-cli/src/storage/read.rs +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -27,7 +27,8 @@ use log::info; use rand::prelude::*; use std::{fmt::Debug, sync::Arc, time::Instant}; -use super::{cmd::StorageCmd, record::BenchRecord}; +use super::cmd::StorageCmd; +use crate::shared::BenchRecord; impl StorageCmd { /// Benchmarks the time it takes to read a single Storage item. diff --git a/utils/frame/benchmarking-cli/src/storage/template.rs b/utils/frame/benchmarking-cli/src/storage/template.rs index 10e6902b934bc..26aa8a962301b 100644 --- a/utils/frame/benchmarking-cli/src/storage/template.rs +++ b/utils/frame/benchmarking-cli/src/storage/template.rs @@ -22,7 +22,8 @@ use log::info; use serde::Serialize; use std::{env, fs, path::PathBuf}; -use super::{cmd::StorageParams, record::Stats}; +use super::cmd::StorageParams; +use crate::shared::{Stats, UnderscoreHelper}; static VERSION: &'static str = env!("CARGO_PKG_VERSION"); static TEMPLATE: &str = include_str!("./weights.hbs"); @@ -97,7 +98,7 @@ impl TemplateData { pub fn write(&self, path: &Option, hbs_template: &Option) -> Result<()> { let mut handlebars = handlebars::Handlebars::new(); // Format large integers with underscore. - handlebars.register_helper("underscore", Box::new(crate::writer::UnderscoreHelper)); + handlebars.register_helper("underscore", Box::new(UnderscoreHelper)); // Don't HTML escape any characters. handlebars.register_escape_fn(|s| -> String { s.to_string() }); // Use custom template if provided. diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index 94a0eea9728ff..d5d5bc2fffa5b 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -31,7 +31,8 @@ use log::{info, trace}; use rand::prelude::*; use std::{fmt::Debug, sync::Arc, time::Instant}; -use super::{cmd::StorageCmd, record::BenchRecord}; +use super::cmd::StorageCmd; +use crate::shared::BenchRecord; impl StorageCmd { /// Benchmarks the time it takes to write a single Storage item. From 78b1ad3c754514135bc0026407f7d2bf3bacae27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Fri, 8 Apr 2022 04:38:51 -0300 Subject: [PATCH 0678/1472] fix .github/pr-custom-review.yml (#11187) --- .github/pr-custom-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml index 7ce8146571cd3..518faf15a6113 100644 --- a/.github/pr-custom-review.yml +++ b/.github/pr-custom-review.yml @@ -11,6 +11,6 @@ rules: teams: - core-devs -prevent_review_request: +prevent-review-request: teams: - core-devs From 1e3b992499de49b91403dbd1e4a7ba76552e89d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Apr 2022 10:41:21 +0200 Subject: [PATCH 0679/1472] Bump impl-trait-for-tuples from 0.2.1 to 0.2.2 (#11171) Bumps [impl-trait-for-tuples](https://github.com/bkchr/impl-trait-for-tuples) from 0.2.1 to 0.2.2. - [Release notes](https://github.com/bkchr/impl-trait-for-tuples/releases) - [Commits](https://github.com/bkchr/impl-trait-for-tuples/compare/v0.2.1...v0.2.2) --- updated-dependencies: - dependency-name: impl-trait-for-tuples 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/chain-spec/Cargo.toml | 2 +- frame/authorship/Cargo.toml | 2 +- frame/session/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- primitives/inherents/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ecb25b7b4b1e..8c9227ea80ef4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3168,9 +3168,9 @@ dependencies = [ [[package]] name = "impl-trait-for-tuples" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5dacb10c5b3bb92d46ba347505a9041e676bb20ad220101326bffb0c93031ee" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ "proc-macro2", "quote", diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index e18f9b72c75e4..bd19fd59d699e 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } -impl-trait-for-tuples = "0.2.1" +impl-trait-for-tuples = "0.2.2" sc-network = { version = "0.10.0-dev", path = "../network" } sp-core = { version = "6.0.0", path = "../../primitives/core" } serde = { version = "1.0.136", features = ["derive"] } diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 77a44f5b5dd72..4557ee65f1a6b 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -22,7 +22,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -impl-trait-for-tuples = "0.2.1" +impl-trait-for-tuples = "0.2.2" [dev-dependencies] sp-core = { version = "6.0.0", path = "../../primitives/core" } diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 647b3482b2025..28f2df47027bc 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.0", default-features = false } -impl-trait-for-tuples = "0.2.1" +impl-trait-for-tuples = "0.2.2" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 3161e4f4db69b..ec596494c601b 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -31,7 +31,7 @@ paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } sp-state-machine = { version = "0.12.0", optional = true, path = "../../primitives/state-machine" } bitflags = "1.3" -impl-trait-for-tuples = "0.2.1" +impl-trait-for-tuples = "0.2.2" smallvec = "1.8.0" log = { version = "0.4.14", default-features = false } sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index f848f48acd254..85745c6c99fd4 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -impl-trait-for-tuples = "0.2.1" +impl-trait-for-tuples = "0.2.2" sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index f7beb7bdfcf54..0e701a397d7d9 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -20,7 +20,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-runtime = { version = "6.0.0", path = "../runtime", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } -impl-trait-for-tuples = "0.2.0" +impl-trait-for-tuples = "0.2.2" async-trait = { version = "0.1.50", optional = true } [dev-dependencies] diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 883ea28e5e887..102592288af14 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = static_assertions = "1.0.0" primitive-types = { version = "0.11.1", default-features = false } sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } -impl-trait-for-tuples = "0.2.1" +impl-trait-for-tuples = "0.2.2" [dev-dependencies] sp-runtime-interface-test-wasm = { version = "2.0.0", path = "test-wasm" } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index a0acdaf27dc5b..22d2ea62ae45f 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -26,7 +26,7 @@ sp-io = { version = "6.0.0", default-features = false, path = "../io" } log = { version = "0.4.14", default-features = false } paste = "1.0" rand = { version = "0.7.2", optional = true } -impl-trait-for-tuples = "0.2.1" +impl-trait-for-tuples = "0.2.2" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } hash256-std-hasher = { version = "0.15.2", default-features = false } either = { version = "1.5", default-features = false } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index fa6c5ede18546..5fa0627490a22 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] wasmi = { version = "0.9.1", optional = true } wasmtime = { version = "0.33.0", optional = true, default-features = false } log = { version = "0.4.14", optional = true } -impl-trait-for-tuples = "0.2.1" +impl-trait-for-tuples = "0.2.2" sp-std = { version = "4.0.0", path = "../std", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } From 2cdd27dda74f44f7a5ba4fa1a0be5982fb7ae528 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Apr 2022 10:18:25 +0000 Subject: [PATCH 0680/1472] Bump lru from 0.7.3 to 0.7.5 (#11190) Bumps [lru](https://github.com/jeromefroe/lru-rs) from 0.7.3 to 0.7.5. - [Release notes](https://github.com/jeromefroe/lru-rs/releases) - [Changelog](https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/jeromefroe/lru-rs/compare/0.7.3...0.7.5) --- updated-dependencies: - dependency-name: lru 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 +++++++------- client/executor/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c9227ea80ef4..c64800e002339 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4036,7 +4036,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log 0.4.14", - "lru 0.7.3", + "lru 0.7.5", "rand 0.7.3", "smallvec 1.8.0", "unsigned-varint 0.7.0", @@ -4336,9 +4336,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb87f3080f6d1d69e8c564c0fcfde1d7aa8cc451ce40cae89479111f03bc0eb" +checksum = "32613e41de4c47ab04970c348ca7ae7382cf116625755af070b008a15516a889" dependencies = [ "hashbrown 0.11.2", ] @@ -8532,7 +8532,7 @@ dependencies = [ "env_logger 0.9.0", "hex-literal", "lazy_static", - "lru 0.7.3", + "lru 0.7.5", "parity-scale-codec", "parking_lot 0.12.0", "paste 1.0.6", @@ -8742,7 +8742,7 @@ dependencies = [ "linked-hash-map", "linked_hash_set", "log 0.4.14", - "lru 0.7.3", + "lru 0.7.5", "parity-scale-codec", "parking_lot 0.12.0", "pin-project 1.0.10", @@ -8786,7 +8786,7 @@ dependencies = [ "futures-timer", "libp2p", "log 0.4.14", - "lru 0.7.3", + "lru 0.7.5", "quickcheck", "sc-network", "sp-runtime", @@ -9860,7 +9860,7 @@ version = "4.0.0-dev" dependencies = [ "futures 0.3.21", "log 0.4.14", - "lru 0.7.3", + "lru 0.7.5", "parity-scale-codec", "parking_lot 0.12.0", "sp-api", diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 34416b1e0d460..8e10de1b04a95 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -32,7 +32,7 @@ sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } parking_lot = "0.12.0" sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } -lru = "0.7.3" +lru = "0.7.5" tracing = "0.1.29" [dev-dependencies] diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 51f5b658402ef..9854575ab6b02 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.21" futures-timer = "3.0.1" libp2p = { version = "0.40.0", default-features = false } log = "0.4.8" -lru = "0.7.3" +lru = "0.7.5" ahash = "0.7.6" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index be69663b9a544..6d70d41964de4 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -34,7 +34,7 @@ hex = "0.4.0" ip_network = "0.4.1" linked-hash-map = "0.5.4" linked_hash_set = "0.1.3" -lru = "0.7.3" +lru = "0.7.5" log = "0.4.8" parking_lot = "0.12.0" pin-project = "1.0.10" diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index a79bc9c5591cf..c6fcdd3cb1c02 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.11" -lru = "0.7.3" +lru = "0.7.5" parking_lot = "0.12.0" thiserror = "1.0.30" futures = "0.3.21" From 994bb57b77b2845e9e1b48d8eb77c9160366d525 Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 8 Apr 2022 20:26:47 +0900 Subject: [PATCH 0681/1472] Catch panics on the FFI boundary between the runtime and the host for `wasmtime` (#11189) * Catch panics on the FFI boundary between the runtime and the host for `wasmtime` * Use an already existing test runtime function * Merge the tests together --- client/executor/runtime-test/src/lib.rs | 4 ++- client/executor/src/integration_tests/mod.rs | 19 +++++++++++--- .../host_function_interface.rs | 26 +++++++++++++++---- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index bf9f76edd945e..0c61d6fcd38a2 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -113,7 +113,9 @@ sp_core::wasm_export_functions! { } } - fn test_exhaust_heap() -> Vec { Vec::with_capacity(16777216) } + fn test_allocate_vec(size: u32) -> Vec { + Vec::with_capacity(size as usize) + } fn test_fp_f32add(a: [u8; 4], b: [u8; 4]) -> [u8; 4] { let a = f32::from_le_bytes(a); diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 462a8ba1b8766..75b458a399e3f 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -466,13 +466,24 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), &mut ext.ext(), true, - "test_exhaust_heap", - &[0], + "test_allocate_vec", + &16777216_u32.encode(), ) - .map_err(|e| e.to_string()) .unwrap_err(); - assert!(err.contains("Allocator ran out of space")); + match err { + #[cfg(feature = "wasmtime")] + Error::AbortedDueToTrap(error) if wasm_method == WasmExecutionMethod::Compiled => { + assert_eq!( + error.message, + r#"host code panicked while being called by the runtime: Failed to allocate memory: "Allocator ran out of space""# + ); + }, + Error::RuntimePanicked(error) if wasm_method == WasmExecutionMethod::Interpreted => { + assert_eq!(error, r#"Failed to allocate memory: "Allocator ran out of space""#); + }, + error => panic!("unexpected error: {:?}", error), + } } fn mk_test_runtime(wasm_method: WasmExecutionMethod, pages: u64) -> Arc { diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs index 1566bbf302c3b..03da0bed59815 100644 --- a/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs +++ b/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs @@ -374,11 +374,27 @@ fn generate_host_function_implementation( -> std::result::Result<#ffi_return_ty, #crate_::sp_wasm_interface::wasmtime::Trap> { T::with_function_context(caller, move |__function_context__| { - #struct_name::call( - __function_context__, - #(#ffi_names,)* - ) - }).map_err(#crate_::sp_wasm_interface::wasmtime::Trap::new) + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + #struct_name::call( + __function_context__, + #(#ffi_names,)* + ).map_err(#crate_::sp_wasm_interface::wasmtime::Trap::new) + })); + match result { + Ok(result) => result, + Err(panic) => { + let message = + if let Some(message) = panic.downcast_ref::() { + format!("host code panicked while being called by the runtime: {}", message) + } else if let Some(message) = panic.downcast_ref::<&'static str>() { + format!("host code panicked while being called by the runtime: {}", message) + } else { + "host code panicked while being called by the runtime".to_owned() + }; + return Err(#crate_::sp_wasm_interface::wasmtime::Trap::new(message)); + } + } + }) } )?; }; From 87ebfdbcf8242c04856e3881a78ea0bc369d77a2 Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Fri, 8 Apr 2022 18:39:10 +0300 Subject: [PATCH 0682/1472] Add GHA for custom PR review (#10951) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add GHA for custom PR review * Change FILES rule settings * Update rules according to feedback * Update .github/pr-custom-review.yml Co-authored-by: Denis Pisarev <17856421+TriplEight@users.noreply.github.com> * CI: PRCR new 🔒 team is locks-review * CI: rename a confusing step * Update .github/workflows/pr-custom-review.yml Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> * CI: use a proper new team for as per discussion with @drahnr it was decided to create a dedicated team for reviewing runtime files * Update pr-custom-review.yml * Update .github/workflows/pr-custom-review.yml Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> * Update .github/workflows/pr-custom-review.yml Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> Co-authored-by: Denis Pisarev <17856421+TriplEight@users.noreply.github.com> Co-authored-by: TriplEight Co-authored-by: Denis Pisarev Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> --- .github/workflows/pr-custom-review.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/pr-custom-review.yml diff --git a/.github/workflows/pr-custom-review.yml b/.github/workflows/pr-custom-review.yml new file mode 100644 index 0000000000000..d113d39067846 --- /dev/null +++ b/.github/workflows/pr-custom-review.yml @@ -0,0 +1,23 @@ +name: Check reviews + +on: + pull_request: + branches: + - master + - main + types: + - opened + - reopened + - synchronize + - review_requested + - review_request_removed + pull_request_review: + +jobs: + pr-custom-review: + runs-on: ubuntu-latest + steps: + - name: pr-custom-review + uses: paritytech/pr-custom-review@v2 + with: + token: ${{ secrets.PRCR_TOKEN }} From 26eff96fed52fb2001f37f17e743939b0e2384bb Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Sat, 9 Apr 2022 14:08:46 +0200 Subject: [PATCH 0683/1472] Remove useless trait bound and `move` instructions (#11193) * Remove useless trait bound and `move` instructions * cargo fmt --- bin/node-template/node/src/command.rs | 2 +- bin/node/cli/src/command.rs | 2 +- client/finality-grandpa/src/lib.rs | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index ede969b3572c8..0c850b322a7d2 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -98,7 +98,7 @@ pub fn run() -> sc_cli::Result<()> { runner.async_run(|config| { let PartialComponents { client, task_manager, backend, .. } = service::new_partial(&config)?; - let aux_revert = Box::new(move |client, _, blocks| { + let aux_revert = Box::new(|client, _, blocks| { sc_finality_grandpa::revert(client, blocks)?; Ok(()) }); diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index c752b1c30ae26..ea91bb90b2f2c 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -175,7 +175,7 @@ pub fn run() -> Result<()> { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?; - let aux_revert = Box::new(move |client: Arc, backend, blocks| { + let aux_revert = Box::new(|client: Arc, backend, blocks| { sc_consensus_babe::revert(client.clone(), backend, blocks)?; grandpa::revert(client, blocks)?; Ok(()) diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 34d5b6bb1f70c..17e04affa0f98 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -1170,10 +1170,7 @@ fn local_authority_id( pub fn revert(client: Arc, blocks: NumberFor) -> ClientResult<()> where Block: BlockT, - Client: AuxStore - + HeaderMetadata - + HeaderBackend - + ProvideRuntimeApi, + Client: AuxStore + HeaderMetadata + HeaderBackend, { let best_number = client.info().best_number; let finalized = client.info().finalized_number; From 07551d4e88f820701f1225cbbaccea14c870d2e1 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 11 Apr 2022 09:45:45 +0200 Subject: [PATCH 0684/1472] Normalization of CLI options format (CamelCase => kebab-case) (#11194) * Convert cli options from 'CamelCase' to 'kebab-case' * Remove not required 'as_str' for 'ExecutionStrategy' option --- client/cli/src/arg_enums.rs | 30 ++++++------------- client/cli/src/commands/run_cmd.rs | 10 +++---- client/cli/src/params/mod.rs | 4 +-- client/cli/src/params/network_params.rs | 18 +++++++---- client/cli/src/params/node_key_params.rs | 2 +- .../cli/src/params/offchain_worker_params.rs | 2 +- client/cli/src/params/shared_params.rs | 2 +- utils/frame/try-runtime/cli/src/lib.rs | 2 +- 8 files changed, 32 insertions(+), 38 deletions(-) diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index a09b7f824c7ba..ac50413803278 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -88,7 +88,7 @@ impl Into for WasmExecutionMethod { /// The default [`WasmExecutionMethod`]. #[cfg(feature = "wasmtime")] -pub const DEFAULT_WASM_EXECUTION_METHOD: &str = "Compiled"; +pub const DEFAULT_WASM_EXECUTION_METHOD: &str = "compiled"; /// The default [`WasmExecutionMethod`]. #[cfg(not(feature = "wasmtime"))] @@ -96,7 +96,7 @@ pub const DEFAULT_WASM_EXECUTION_METHOD: &str = "interpreted-i-know-what-i-do"; #[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "PascalCase")] +#[clap(rename_all = "kebab-case")] pub enum TracingReceiver { /// Output the tracing records using the log. Log, @@ -112,7 +112,7 @@ impl Into for TracingReceiver { /// The type of the node key. #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "PascalCase")] +#[clap(rename_all = "kebab-case")] pub enum NodeKeyType { /// Use ed25519. Ed25519, @@ -120,7 +120,7 @@ pub enum NodeKeyType { /// The crypto scheme to use. #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "PascalCase")] +#[clap(rename_all = "kebab-case")] pub enum CryptoScheme { /// Use ed25519. Ed25519, @@ -132,7 +132,7 @@ pub enum CryptoScheme { /// The type of the output format. #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "PascalCase")] +#[clap(rename_all = "kebab-case")] pub enum OutputType { /// Output as json. Json, @@ -142,7 +142,7 @@ pub enum OutputType { /// How to execute blocks #[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "PascalCase")] +#[clap(rename_all = "kebab-case")] pub enum ExecutionStrategy { /// Execute with native build (if available, WebAssembly otherwise). Native, @@ -165,22 +165,10 @@ impl Into for ExecutionStrategy { } } -impl ExecutionStrategy { - /// Returns the variant as `'&static str`. - pub fn as_str(&self) -> &'static str { - match self { - Self::Native => "Native", - Self::Wasm => "Wasm", - Self::Both => "Both", - Self::NativeElseWasm => "NativeElseWasm", - } - } -} - /// Available RPC methods. #[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, ArgEnum)] -#[clap(rename_all = "PascalCase")] +#[clap(rename_all = "kebab-case")] pub enum RpcMethods { /// Expose every RPC method only when RPC is listening on `localhost`, /// otherwise serve only safe RPC methods. @@ -243,7 +231,7 @@ impl Database { /// Whether off-chain workers are enabled. #[allow(missing_docs)] #[derive(Debug, Clone, ArgEnum)] -#[clap(rename_all = "PascalCase")] +#[clap(rename_all = "kebab-case")] pub enum OffchainWorkerEnabled { /// Always have offchain worker enabled. Always, @@ -255,7 +243,7 @@ pub enum OffchainWorkerEnabled { /// Syncing mode. #[derive(Debug, Clone, Copy, ArgEnum, PartialEq)] -#[clap(rename_all = "PascalCase")] +#[clap(rename_all = "kebab-case")] pub enum SyncMode { /// Full sync. Download end verify all blocks. Full, diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index b9318813b0480..dea1e2a6dae5b 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -71,16 +71,16 @@ pub struct RunCmd { /// RPC methods to expose. /// - /// - `Unsafe`: Exposes every RPC method. - /// - `Safe`: Exposes only a safe subset of RPC methods, denying unsafe RPC methods. - /// - `Auto`: Acts as `Safe` if RPC is served externally, e.g. when `--{rpc,ws}-external` is - /// passed, otherwise acts as `Unsafe`. + /// - `unsafe`: Exposes every RPC method. + /// - `safe`: Exposes only a safe subset of RPC methods, denying unsafe RPC methods. + /// - `auto`: Acts as `safe` if RPC is served externally, e.g. when `--{rpc,ws}-external` is + /// passed, otherwise acts as `unsafe`. #[clap( long, value_name = "METHOD SET", arg_enum, ignore_case = true, - default_value = "Auto", + default_value = "auto", verbatim_doc_comment )] pub rpc_methods: RpcMethods, diff --git a/client/cli/src/params/mod.rs b/client/cli/src/params/mod.rs index 33e714ec138b0..9fccce606b4e4 100644 --- a/client/cli/src/params/mod.rs +++ b/client/cli/src/params/mod.rs @@ -118,7 +118,7 @@ impl BlockNumberOrHash { #[derive(Debug, Clone, Args)] pub struct CryptoSchemeFlag { /// cryptography scheme - #[clap(long, value_name = "SCHEME", arg_enum, ignore_case = true, default_value = "Sr25519")] + #[clap(long, value_name = "SCHEME", arg_enum, ignore_case = true, default_value = "sr25519")] pub scheme: CryptoScheme, } @@ -126,7 +126,7 @@ pub struct CryptoSchemeFlag { #[derive(Debug, Clone, Args)] pub struct OutputTypeFlag { /// output format - #[clap(long, value_name = "FORMAT", arg_enum, ignore_case = true, default_value = "Text")] + #[clap(long, value_name = "FORMAT", arg_enum, ignore_case = true, default_value = "text")] pub output_type: OutputType, } diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 7a265c5e27609..ac5039fb89754 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -132,12 +132,18 @@ pub struct NetworkParams { /// Blockchain syncing mode. /// - /// - `Full`: Download and validate full blockchain history. - /// - /// - `Fast`: Download blocks and the latest state only. - /// - /// - `FastUnsafe`: Same as `Fast`, but skip downloading state proofs. - #[clap(long, arg_enum, value_name = "SYNC_MODE", default_value = "Full", ignore_case(true))] + /// - `full`: Download and validate full blockchain history. + /// - `fast`: Download blocks and the latest state only. + /// - `fast-unsafe`: Same as `fast`, but skip downloading state proofs. + /// - `warp`: Download the latest state and proof. + #[clap( + long, + arg_enum, + value_name = "SYNC_MODE", + default_value = "full", + ignore_case = true, + verbatim_doc_comment + )] pub sync: SyncMode, } diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index f31fd854cbb56..699d0c4ece8dc 100644 --- a/client/cli/src/params/node_key_params.rs +++ b/client/cli/src/params/node_key_params.rs @@ -66,7 +66,7 @@ pub struct NodeKeyParams { /// /// The node's secret key determines the corresponding public key and hence the /// node's peer ID in the context of libp2p. - #[clap(long, value_name = "TYPE", arg_enum, ignore_case = true, default_value = "Ed25519")] + #[clap(long, value_name = "TYPE", arg_enum, ignore_case = true, default_value = "ed25519")] pub node_key_type: NodeKeyType, /// The file from which to read the node's secret key to use for libp2p networking. diff --git a/client/cli/src/params/offchain_worker_params.rs b/client/cli/src/params/offchain_worker_params.rs index 3ab507f108598..f01c75a5aa70d 100644 --- a/client/cli/src/params/offchain_worker_params.rs +++ b/client/cli/src/params/offchain_worker_params.rs @@ -40,7 +40,7 @@ pub struct OffchainWorkerParams { value_name = "ENABLED", arg_enum, ignore_case = true, - default_value = "WhenValidating" + default_value = "when-validating" )] pub enabled: OffchainWorkerEnabled, diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 99eddf4e7c4b7..01df2cf9abba4 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -76,7 +76,7 @@ pub struct SharedParams { pub tracing_targets: Option, /// Receiver to process tracing messages. - #[clap(long, value_name = "RECEIVER", arg_enum, ignore_case = true, default_value = "Log")] + #[clap(long, value_name = "RECEIVER", arg_enum, ignore_case = true, default_value = "log")] pub tracing_receiver: TracingReceiver, } diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index ef8db7a1e5a0c..a9047259838cf 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -387,7 +387,7 @@ pub struct SharedParams { pub shared_params: sc_cli::SharedParams, /// The execution strategy that should be used. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true, default_value = "Wasm")] + #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true, default_value = "wasm")] pub execution: ExecutionStrategy, /// Type of wasm execution used. From 3b3905d1091f23e1e709437fed02c2cbbb13c7a3 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Mon, 11 Apr 2022 20:35:25 +1200 Subject: [PATCH 0685/1472] add sort & try_append to bounded_vec (#11196) --- frame/support/src/storage/bounded_vec.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 137015098cfa6..92ca167f98436 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -129,6 +129,16 @@ impl BoundedVec { self.0.sort_by(compare) } + /// Exactly the same semantics as [`slice::sort`]. + /// + /// This is safe since sorting cannot change the number of elements in the vector. + pub fn sort(&mut self) + where + T: sp_std::cmp::Ord, + { + self.0.sort() + } + /// Exactly the same semantics as `Vec::remove`. /// /// # Panics @@ -374,6 +384,17 @@ impl> BoundedVec { } } + /// Exactly the same semantics as [`Vec::append`], but returns an error and does nothing if the + /// length of the outcome is larger than the bound. + pub fn try_append(&mut self, other: &mut Vec) -> Result<(), ()> { + if other.len().saturating_add(self.len()) <= Self::bound() { + self.0.append(other); + Ok(()) + } else { + Err(()) + } + } + /// Consumes self and mutates self via the given `mutate` function. /// /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is From 4c82679622903e72451c5552da192de314d7a9e3 Mon Sep 17 00:00:00 2001 From: Dominique Date: Mon, 11 Apr 2022 10:36:13 +0200 Subject: [PATCH 0686/1472] Updated docs for method `set_payee` & `set_controller` (#11192) * Updated docs for method 'set_payee' * Updated docs for method 'set_controller' --- frame/staking/src/pallet/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index fa8c453c2b0fe..498d861660961 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -1109,7 +1109,7 @@ pub mod pallet { /// (Re-)set the payment target for a controller. /// - /// Effects will be felt at the beginning of the next era. + /// Effects will be felt instantly (as soon as this function is completed successfully). /// /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. /// @@ -1137,7 +1137,7 @@ pub mod pallet { /// (Re-)set the controller of a stash. /// - /// Effects will be felt at the beginning of the next era. + /// Effects will be felt instantly (as soon as this function is completed successfully). /// /// The dispatch origin for this call must be _Signed_ by the stash, not the controller. /// From b64713874935cc05f23d2f46787fee000d51895b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 11 Apr 2022 11:21:54 +0200 Subject: [PATCH 0687/1472] Prepare for rust stable 1.60 (#11138) * Prepare for rust stable 1.59 Besides preparing the UI tests this also adds a new script update-rust-stable.sh script for simplifying the update of a rust stable version. This script will run all UI tests for the new rust stable version and updating the expected output. * Ensure we run the UI tests in CI * use staging ci image * More test updates * Unignore test (#11097) * empty commit for pipeline rerun * empty commit for pipeline rerun * Try to make clippy happy * More clippy fixes * FMT * ci image production Co-authored-by: alvicsam Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> --- .gitlab-ci.yml | 2 + .maintain/update-rust-stable.sh | 42 ++++++++ bin/node/cli/benches/transaction_pool.rs | 6 +- client/network/src/service.rs | 2 +- client/offchain/src/lib.rs | 4 +- client/service/src/client/call_executor.rs | 42 ++++---- client/service/src/client/wasm_override.rs | 2 +- docs/CONTRIBUTING.adoc | 8 ++ .../solution-type/src/lib.rs | 5 + .../test/tests/construct_runtime_ui.rs | 5 + .../no_std_genesis_config.stderr | 31 +++--- .../undefined_genesis_config_part.stderr | 31 +++--- frame/support/test/tests/decl_module_ui.rs | 5 + frame/support/test/tests/decl_storage_ui.rs | 5 + .../support/test/tests/derive_no_bound_ui.rs | 5 + .../tests/derive_no_bound_ui/clone.stderr | 14 +-- .../tests/derive_no_bound_ui/default.stderr | 14 +-- frame/support/test/tests/pallet_ui.rs | 5 + .../call_argument_invalid_bound.stderr | 14 +-- .../call_argument_invalid_bound_2.stderr | 68 +++++-------- .../error_does_not_derive_pallet_error.stderr | 17 ++-- .../pallet_ui/event_field_not_member.stderr | 14 +-- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 99 ++++++------------- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 99 ++++++------------- .../pallet_ui/storage_info_unsatisfied.stderr | 17 ++-- .../storage_info_unsatisfied_nmap.stderr | 5 - primitives/api/test/tests/trybuild.rs | 5 + .../ui/changed_in_no_default_method.stderr | 4 +- .../ui/impl_incorrect_method_signature.stderr | 32 +++--- .../tests/ui/mock_only_self_reference.stderr | 42 ++++---- ...reference_in_impl_runtime_apis_call.stderr | 32 +++--- primitives/runtime-interface/tests/ui.rs | 5 + .../state-machine/src/in_memory_backend.rs | 2 +- .../state-machine/src/trie_backend_essence.rs | 9 +- primitives/version/src/embed.rs | 3 +- utils/frame/remote-externalities/src/lib.rs | 2 +- 36 files changed, 329 insertions(+), 368 deletions(-) create mode 100755 .maintain/update-rust-stable.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d196ade85a6fb..029c486365088 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -381,6 +381,8 @@ test-linux-stable: &test-linux RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" RUST_BACKTRACE: 1 WASM_BUILD_NO_COLOR: 1 + # Ensure we run the UI tests. + RUN_UI_TESTS: 1 script: # this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests - time cargo test --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml diff --git a/.maintain/update-rust-stable.sh b/.maintain/update-rust-stable.sh new file mode 100755 index 0000000000000..b253bb4105313 --- /dev/null +++ b/.maintain/update-rust-stable.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# +# Script for updating the UI tests for a new rust stable version. +# +# It needs to be called like this: +# +# update-rust-stable.sh 1.61 +# +# This will run all UI tests with the rust stable 1.61. The script +# requires that rustup is installed. +set -e + +if [ "$#" -ne 1 ]; then + echo "Please specify the rust version to use. E.g. update-rust-stable.sh 1.61" + exit +fi + +RUST_VERSION=$1 + +if ! command -v rustup &> /dev/null +then + echo "rustup needs to be installed" + exit +fi + +rustup install $RUST_VERSION +rustup component add rust-src --toolchain $RUST_VERSION + +# Ensure we run the ui tests +export RUN_UI_TESTS=1 +# We don't need any wasm files for ui tests +export SKIP_WASM_BUILD=1 +# Let trybuild overwrite the .stderr files +export TRYBUILD=overwrite + +# Run all the relevant UI tests +# +# Any new UI tests in different crates need to be added here as well. +rustup run $RUST_VERSION cargo test -p sp-runtime-interface ui +rustup run $RUST_VERSION cargo test -p sp-api-test ui +rustup run $RUST_VERSION cargo test -p frame-election-provider-solution-type ui +rustup run $RUST_VERSION cargo test -p frame-support-test ui diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index e89527f2333a2..9a602e286bbae 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -126,7 +126,7 @@ fn create_account_extrinsics( accounts .iter() .enumerate() - .map(|(i, a)| { + .flat_map(|(i, a)| { vec![ // Reset the nonce by removing any funds create_extrinsic( @@ -162,7 +162,6 @@ fn create_account_extrinsics( ), ] }) - .flatten() .map(OpaqueExtrinsic::from) .collect() } @@ -174,7 +173,7 @@ fn create_benchmark_extrinsics( ) -> Vec { accounts .iter() - .map(|account| { + .flat_map(|account| { (0..extrinsics_per_account).map(move |nonce| { create_extrinsic( client, @@ -187,7 +186,6 @@ fn create_benchmark_extrinsics( ) }) }) - .flatten() .map(OpaqueExtrinsic::from) .collect() } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index e89be325fa486..7239c9f6f9e6a 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -572,7 +572,7 @@ impl NetworkWorker { .collect(); let endpoint = if let Some(e) = - swarm.behaviour_mut().node(peer_id).map(|i| i.endpoint()).flatten() + swarm.behaviour_mut().node(peer_id).and_then(|i| i.endpoint()) { e.clone().into() } else { diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 8d016e945453b..d54d491b04c43 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -74,11 +74,11 @@ where H: ExHashT, { fn set_authorized_peers(&self, peers: HashSet) { - self.set_authorized_peers(peers) + NetworkService::set_authorized_peers(self, peers) } fn set_authorized_only(&self, reserved_only: bool) { - self.set_authorized_only(reserved_only) + NetworkService::set_authorized_only(self, reserved_only) } } diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index f271b35a69ced..0f13b08d0ce8e 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -91,28 +91,26 @@ where B: backend::Backend, { let spec = CallExecutor::runtime_version(self, id)?; - let code = if let Some(d) = self - .wasm_override - .as_ref() - .as_ref() - .map(|o| o.get(&spec.spec_version, onchain_code.heap_pages, &spec.spec_name)) - .flatten() - { - log::debug!(target: "wasm_overrides", "using WASM override for block {}", id); - d - } else if let Some(s) = - self.wasm_substitutes.get(spec.spec_version, onchain_code.heap_pages, id) - { - log::debug!(target: "wasm_substitutes", "Using WASM substitute for block {:?}", id); - s - } else { - log::debug!( - target: "wasm_overrides", - "No WASM override available for block {}, using onchain code", - id - ); - onchain_code - }; + let code = + if let Some(d) = + self.wasm_override.as_ref().as_ref().and_then(|o| { + o.get(&spec.spec_version, onchain_code.heap_pages, &spec.spec_name) + }) { + log::debug!(target: "wasm_overrides", "using WASM override for block {}", id); + d + } else if let Some(s) = + self.wasm_substitutes.get(spec.spec_version, onchain_code.heap_pages, id) + { + log::debug!(target: "wasm_substitutes", "Using WASM substitute for block {:?}", id); + s + } else { + log::debug!( + target: "wasm_overrides", + "No WASM override available for block {}, using onchain code", + id + ); + onchain_code + }; Ok(code) } diff --git a/client/service/src/client/wasm_override.rs b/client/service/src/client/wasm_override.rs index 267aea0709871..fa35be9fcac87 100644 --- a/client/service/src/client/wasm_override.rs +++ b/client/service/src/client/wasm_override.rs @@ -186,7 +186,7 @@ impl WasmOverride { for entry in fs::read_dir(dir).map_err(handle_err)? { let entry = entry.map_err(handle_err)?; let path = entry.path(); - match path.extension().map(|e| e.to_str()).flatten() { + match path.extension().and_then(|e| e.to_str()) { Some("wasm") => { let code = fs::read(&path).map_err(handle_err)?; let code_hash = make_hash(&code); diff --git a/docs/CONTRIBUTING.adoc b/docs/CONTRIBUTING.adoc index 5b1920e775bbd..d39b8a6d729ff 100644 --- a/docs/CONTRIBUTING.adoc +++ b/docs/CONTRIBUTING.adoc @@ -111,6 +111,14 @@ Please label issues with the following labels: Declaring formal releases remains the prerogative of the project maintainer(s). +== UI tests + +UI tests are used for macros to ensure that the output of a macro doesn't change and is in the expected format. These UI tests are sensible to any changes +in the macro generated code or to switching the rust stable version. The tests are only run when the `RUN_UI_TESTS` environment variable is set. So, when +the CI is for example complaining about failing UI tests and it is expected that they fail these tests need to be executed locally. To simplify the updating +of the UI test ouput there is the `.maintain/update-rust-stable.sh` script. This can be run with `.maintain/update-rust-stable.sh CURRENT_STABLE_VERSION` +and then it will run all UI tests to update the expected output. + == Changes to this arrangement This is an experiment and feedback is welcome! This document may also be subject to pull-requests or changes by contributors where you believe you have something valuable to add or change. diff --git a/frame/election-provider-support/solution-type/src/lib.rs b/frame/election-provider-support/solution-type/src/lib.rs index 57d939377b62c..7c5cb960d2430 100644 --- a/frame/election-provider-support/solution-type/src/lib.rs +++ b/frame/election-provider-support/solution-type/src/lib.rs @@ -265,6 +265,11 @@ fn imports() -> Result { mod tests { #[test] fn ui_fail() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if std::env::var("RUN_UI_TESTS").is_err() { + return + } + let cases = trybuild::TestCases::new(); cases.compile_fail("tests/ui/fail/*.rs"); } diff --git a/frame/support/test/tests/construct_runtime_ui.rs b/frame/support/test/tests/construct_runtime_ui.rs index 66636416c1f51..38aa780766835 100644 --- a/frame/support/test/tests/construct_runtime_ui.rs +++ b/frame/support/test/tests/construct_runtime_ui.rs @@ -21,6 +21,11 @@ use std::env; #[cfg(not(feature = "disable-ui-tests"))] #[test] fn ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if env::var("RUN_UI_TESTS").is_err() { + return + } + // As trybuild is using `cargo check`, we don't need the real WASM binaries. env::set_var("SKIP_WASM_BUILD", "1"); diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr index 6d5a48bf0909a..404c0c3627b7b 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr @@ -31,21 +31,16 @@ help: consider importing this struct | error[E0283]: type annotations needed - --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 - | -40 | / construct_runtime! { -41 | | pub enum Runtime where -42 | | Block = Block, -43 | | NodeBlock = Block, -... | -48 | | } -49 | | } - | |_^ cannot infer type - | - = note: cannot satisfy `_: std::default::Default` -note: required by `std::default::Default::default` - --> $RUST/core/src/default.rs - | - | fn default() -> Self; - | ^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 + | +40 | / construct_runtime! { +41 | | pub enum Runtime where +42 | | Block = Block, +43 | | NodeBlock = Block, +... | +48 | | } +49 | | } + | |_^ cannot infer type + | + = note: cannot satisfy `_: std::default::Default` + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr index e8532aa9a064f..fa1cee1ac7e2f 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr @@ -34,21 +34,16 @@ help: consider importing this struct | error[E0283]: type annotations needed - --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 - | -49 | / construct_runtime! { -50 | | pub enum Runtime where -51 | | Block = Block, -52 | | NodeBlock = Block, -... | -57 | | } -58 | | } - | |_^ cannot infer type - | - = note: cannot satisfy `_: std::default::Default` -note: required by `std::default::Default::default` - --> $RUST/core/src/default.rs - | - | fn default() -> Self; - | ^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 + | +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, +... | +57 | | } +58 | | } + | |_^ cannot infer type + | + = note: cannot satisfy `_: std::default::Default` + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/decl_module_ui.rs b/frame/support/test/tests/decl_module_ui.rs index 829850ec2d476..292451335e7ea 100644 --- a/frame/support/test/tests/decl_module_ui.rs +++ b/frame/support/test/tests/decl_module_ui.rs @@ -19,6 +19,11 @@ #[cfg(not(feature = "disable-ui-tests"))] #[test] fn decl_module_ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if std::env::var("RUN_UI_TESTS").is_err() { + return + } + // As trybuild is using `cargo check`, we don't need the real WASM binaries. std::env::set_var("SKIP_WASM_BUILD", "1"); diff --git a/frame/support/test/tests/decl_storage_ui.rs b/frame/support/test/tests/decl_storage_ui.rs index d4db02ad19a0e..34dfea8601ab9 100644 --- a/frame/support/test/tests/decl_storage_ui.rs +++ b/frame/support/test/tests/decl_storage_ui.rs @@ -19,6 +19,11 @@ #[cfg(not(feature = "disable-ui-tests"))] #[test] fn decl_storage_ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if std::env::var("RUN_UI_TESTS").is_err() { + return + } + // As trybuild is using `cargo check`, we don't need the real WASM binaries. std::env::set_var("SKIP_WASM_BUILD", "1"); diff --git a/frame/support/test/tests/derive_no_bound_ui.rs b/frame/support/test/tests/derive_no_bound_ui.rs index 91e530d1d8da7..d714e1113625a 100644 --- a/frame/support/test/tests/derive_no_bound_ui.rs +++ b/frame/support/test/tests/derive_no_bound_ui.rs @@ -19,6 +19,11 @@ #[cfg(not(feature = "disable-ui-tests"))] #[test] fn derive_no_bound_ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if std::env::var("RUN_UI_TESTS").is_err() { + return + } + // As trybuild is using `cargo check`, we don't need the real WASM binaries. std::env::set_var("SKIP_WASM_BUILD", "1"); diff --git a/frame/support/test/tests/derive_no_bound_ui/clone.stderr b/frame/support/test/tests/derive_no_bound_ui/clone.stderr index 45428a8728c21..7744586e56bf4 100644 --- a/frame/support/test/tests/derive_no_bound_ui/clone.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/clone.stderr @@ -1,11 +1,5 @@ error[E0277]: the trait bound `::C: Clone` is not satisfied - --> tests/derive_no_bound_ui/clone.rs:7:2 - | -7 | c: T::C, - | ^ the trait `Clone` is not implemented for `::C` - | -note: required by `clone` - --> $RUST/core/src/clone.rs - | - | fn clone(&self) -> Self; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/derive_no_bound_ui/clone.rs:7:2 + | +7 | c: T::C, + | ^ the trait `Clone` is not implemented for `::C` diff --git a/frame/support/test/tests/derive_no_bound_ui/default.stderr b/frame/support/test/tests/derive_no_bound_ui/default.stderr index 7608f877a3b56..d56dd438f2a7f 100644 --- a/frame/support/test/tests/derive_no_bound_ui/default.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/default.stderr @@ -1,11 +1,5 @@ error[E0277]: the trait bound `::C: std::default::Default` is not satisfied - --> $DIR/default.rs:7:2 - | -7 | c: T::C, - | ^ the trait `std::default::Default` is not implemented for `::C` - | -note: required by `std::default::Default::default` - --> $DIR/default.rs:116:5 - | -116 | fn default() -> Self; - | ^^^^^^^^^^^^^^^^^^^^^ + --> tests/derive_no_bound_ui/default.rs:7:2 + | +7 | c: T::C, + | ^ the trait `std::default::Default` is not implemented for `::C` diff --git a/frame/support/test/tests/pallet_ui.rs b/frame/support/test/tests/pallet_ui.rs index a77d76deff8dc..2db1d3cb0543a 100644 --- a/frame/support/test/tests/pallet_ui.rs +++ b/frame/support/test/tests/pallet_ui.rs @@ -19,6 +19,11 @@ #[cfg(not(feature = "disable-ui-tests"))] #[test] fn pallet_ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if std::env::var("RUN_UI_TESTS").is_err() { + return + } + // As trybuild is using `cargo check`, we don't need the real WASM binaries. std::env::set_var("SKIP_WASM_BUILD", "1"); diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index 9701b1bdd06f3..3a636d9f659c7 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -9,16 +9,10 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` = note: required for the cast to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound.rs:20:36 - | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `Clone` is not implemented for `::Bar` - | -note: required by `clone` - --> $RUST/core/src/clone.rs - | - | fn clone(&self) -> Self; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/call_argument_invalid_bound.rs:20:36 + | +20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^ the trait `Clone` is not implemented for `::Bar` error[E0369]: binary operation `==` cannot be applied to type `&::Bar` --> tests/pallet_ui/call_argument_invalid_bound.rs:20:36 diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index aff0661620874..f182382d18f11 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -9,16 +9,10 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` = note: required for the cast to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 - | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `Clone` is not implemented for `::Bar` - | -note: required by `clone` - --> $RUST/core/src/clone.rs - | - | fn clone(&self) -> Self; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 + | +20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^ the trait `Clone` is not implemented for `::Bar` error[E0369]: binary operation `==` cannot be applied to type `&::Bar` --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 @@ -32,38 +26,26 @@ help: consider further restricting this bound | +++++++++++++++++++++ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:1:1 - | -1 | #[frame_support::pallet] - | ^----------------------- - | | - | _in this procedural macro expansion - | | -2 | | mod pallet { -3 | | use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; -4 | | use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; -... | -16 | | -17 | | #[pallet::call] - | |__________________^ the trait `WrapperTypeEncode` is not implemented for `::Bar` - | - = note: required because of the requirements on the impl of `Encode` for `::Bar` -note: required by a bound in `encode_to` - --> $CARGO/parity-scale-codec-3.0.0/src/codec.rs - | - | fn encode_to(&self, dest: &mut T) { - | ^^^^^^ required by this bound in `encode_to` - = note: this error originates in the derive macro `frame_support::codec::Encode` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 + | +1 | / #[frame_support::pallet] +2 | | mod pallet { +3 | | use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; +4 | | use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; +... | +16 | | +17 | | #[pallet::call] + | |__________________- required by a bound introduced by this call +... +20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar` + | + = note: required because of the requirements on the impl of `Encode` for `::Bar` error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:17:12 - | -17 | #[pallet::call] - | ^^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` - | - = note: required because of the requirements on the impl of `Decode` for `::Bar` -note: required by a bound in `parity_scale_codec::Decode::decode` - --> $CARGO/parity-scale-codec-3.0.0/src/codec.rs - | - | fn decode(input: &mut I) -> Result; - | ^^^^^ required by this bound in `parity_scale_codec::Decode::decode` + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:17:12 + | +17 | #[pallet::call] + | ^^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` + | + = note: required because of the requirements on the impl of `Decode` for `::Bar` diff --git a/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr b/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr index 2a8149e309ac1..0f2ea7e161c4e 100644 --- a/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr +++ b/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr @@ -1,12 +1,7 @@ error[E0277]: the trait bound `MyError: PalletError` is not satisfied - --> tests/pallet_ui/error_does_not_derive_pallet_error.rs:1:1 - | -1 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PalletError` is not implemented for `MyError` - | -note: required by `MAX_ENCODED_SIZE` - --> $WORKSPACE/frame/support/src/traits/error.rs - | - | const MAX_ENCODED_SIZE: usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `frame_support::PalletError` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/pallet_ui/error_does_not_derive_pallet_error.rs:1:1 + | +1 | #[frame_support::pallet] + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PalletError` is not implemented for `MyError` + | + = note: this error originates in the derive macro `frame_support::PalletError` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr index ff184db988e3c..3db258a819fcb 100644 --- a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr +++ b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr @@ -1,14 +1,8 @@ error[E0277]: the trait bound `::Bar: Clone` is not satisfied - --> tests/pallet_ui/event_field_not_member.rs:23:7 - | -23 | B { b: T::Bar }, - | ^ the trait `Clone` is not implemented for `::Bar` - | -note: required by `clone` - --> $RUST/core/src/clone.rs - | - | fn clone(&self) -> Self; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/event_field_not_member.rs:23:7 + | +23 | B { b: T::Bar }, + | ^ the trait `Clone` is not implemented for `::Bar` error[E0369]: binary operation `==` cannot be applied to type `&::Bar` --> tests/pallet_ui/event_field_not_member.rs:23:7 diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index 35f8bbdbd5248..87528751a0a7a 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -7,11 +7,6 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $WORKSPACE/frame/support/src/traits/storage.rs - | - | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:10:12 @@ -22,11 +17,6 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $WORKSPACE/frame/support/src/traits/storage.rs - | - | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:10:12 @@ -38,68 +28,43 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $WORKSPACE/frame/support/src/traits/storage.rs - | - | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 - | -21 | #[pallet::storage] - | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `build_metadata` - --> $WORKSPACE/frame/support/src/storage/types/mod.rs - | - | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 + | +21 | #[pallet::storage] + | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 - | -21 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Decode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `build_metadata` - --> $WORKSPACE/frame/support/src/storage/types/mod.rs - | - | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 + | +21 | #[pallet::storage] + | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Decode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 - | -21 | #[pallet::storage] - | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `build_metadata` - --> $WORKSPACE/frame/support/src/storage/types/mod.rs - | - | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 + | +21 | #[pallet::storage] + | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 - | -21 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Encode` for `Bar` - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `build_metadata` - --> $WORKSPACE/frame/support/src/storage/types/mod.rs - | - | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 + | +21 | #[pallet::storage] + | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Encode` for `Bar` + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index b5f250bb89718..6c3f6dc662fbc 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -7,11 +7,6 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $WORKSPACE/frame/support/src/traits/storage.rs - | - | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:10:12 @@ -22,11 +17,6 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $WORKSPACE/frame/support/src/traits/storage.rs - | - | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:10:12 @@ -38,68 +28,43 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `partial_storage_info` - --> $WORKSPACE/frame/support/src/traits/storage.rs - | - | fn partial_storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 - | -21 | #[pallet::storage] - | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `build_metadata` - --> $WORKSPACE/frame/support/src/storage/types/mod.rs - | - | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 + | +21 | #[pallet::storage] + | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 - | -21 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Decode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `build_metadata` - --> $WORKSPACE/frame/support/src/storage/types/mod.rs - | - | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 + | +21 | #[pallet::storage] + | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Decode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 - | -21 | #[pallet::storage] - | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `build_metadata` - --> $WORKSPACE/frame/support/src/storage/types/mod.rs - | - | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 + | +21 | #[pallet::storage] + | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 - | -21 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `Encode` for `Bar` - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `build_metadata` - --> $WORKSPACE/frame/support/src/storage/types/mod.rs - | - | fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 + | +21 | #[pallet::storage] + | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `Encode` for `Bar` + = note: required because of the requirements on the impl of `FullEncode` for `Bar` + = note: required because of the requirements on the impl of `FullCodec` for `Bar` + = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index 35537cfbc9e07..68856f122c7ac 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -1,12 +1,7 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied - --> tests/pallet_ui/storage_info_unsatisfied.rs:9:12 - | -9 | #[pallet::pallet] - | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` - | - = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` -note: required by `storage_info` - --> $WORKSPACE/frame/support/src/traits/storage.rs - | - | fn storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/pallet_ui/storage_info_unsatisfied.rs:9:12 + | +9 | #[pallet::pallet] + | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` + | + = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index fb6580bb5a3e7..226cb40f1d48b 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -6,8 +6,3 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied | = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` -note: required by `storage_info` - --> $WORKSPACE/frame/support/src/traits/storage.rs - | - | fn storage_info() -> Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/primitives/api/test/tests/trybuild.rs b/primitives/api/test/tests/trybuild.rs index 9e3af145dc566..f3d6aa59a0336 100644 --- a/primitives/api/test/tests/trybuild.rs +++ b/primitives/api/test/tests/trybuild.rs @@ -20,6 +20,11 @@ use std::env; #[rustversion::attr(not(stable), ignore)] #[test] fn ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if env::var("RUN_UI_TESTS").is_err() { + return + } + // As trybuild is using `cargo check`, we don't need the real WASM binaries. env::set_var("SKIP_WASM_BUILD", "1"); diff --git a/primitives/api/test/tests/ui/changed_in_no_default_method.stderr b/primitives/api/test/tests/ui/changed_in_no_default_method.stderr index ed4c0f9088573..096b1091e6f41 100644 --- a/primitives/api/test/tests/ui/changed_in_no_default_method.stderr +++ b/primitives/api/test/tests/ui/changed_in_no_default_method.stderr @@ -1,6 +1,6 @@ error: There is no 'default' method with this name (without `changed_in` attribute). -The 'default' method is used to call into the latest implementation. - --> $DIR/changed_in_no_default_method.rs:15:6 + The 'default' method is used to call into the latest implementation. + --> tests/ui/changed_in_no_default_method.rs:15:6 | 15 | fn test(data: u64); | ^^^^ diff --git a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr index 2fb06c3565ea2..b1478e2f53344 100644 --- a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr +++ b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr @@ -1,28 +1,23 @@ error[E0053]: method `test` has an incompatible type for trait - --> $DIR/impl_incorrect_method_signature.rs:19:17 + --> tests/ui/impl_incorrect_method_signature.rs:19:17 | -13 | fn test(data: u64); - | --- type in trait -... 19 | fn test(data: String) {} | ^^^^^^ | | | expected `u64`, found struct `std::string::String` | help: change the parameter type to match the trait: `u64` | +note: type in trait + --> tests/ui/impl_incorrect_method_signature.rs:13:17 + | +13 | fn test(data: u64); + | ^^^ = note: expected fn pointer `fn(u64)` found fn pointer `fn(std::string::String)` error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait - --> $DIR/impl_incorrect_method_signature.rs:17:1 + --> tests/ui/impl_incorrect_method_signature.rs:17:1 | -11 | / sp_api::decl_runtime_apis! { -12 | | pub trait Api { -13 | | fn test(data: u64); -14 | | } -15 | | } - | |_- type in trait -16 | 17 | sp_api::impl_runtime_apis! { | -^^^^^^^^^^^^^^^^^^^^^^^^^ | | @@ -36,12 +31,21 @@ error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for tr 33 | | } | |_- help: change the parameter type to match the trait: `std::option::Option` | +note: type in trait + --> tests/ui/impl_incorrect_method_signature.rs:11:1 + | +11 | / sp_api::decl_runtime_apis! { +12 | | pub trait Api { +13 | | fn test(data: u64); +14 | | } +15 | | } + | |_^ = note: expected fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option, Vec<_>) -> Result<_, _>` found fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option, Vec<_>) -> Result<_, _>` = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/impl_incorrect_method_signature.rs:17:1 + --> tests/ui/impl_incorrect_method_signature.rs:17:1 | 17 | / sp_api::impl_runtime_apis! { 18 | | impl self::Api for Runtime { @@ -55,7 +59,7 @@ error[E0308]: mismatched types = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/impl_incorrect_method_signature.rs:19:11 + --> tests/ui/impl_incorrect_method_signature.rs:19:11 | 19 | fn test(data: String) {} | ^^^^ expected `u64`, found struct `std::string::String` diff --git a/primitives/api/test/tests/ui/mock_only_self_reference.stderr b/primitives/api/test/tests/ui/mock_only_self_reference.stderr index 1b1d2553940a5..c67de70b9c140 100644 --- a/primitives/api/test/tests/ui/mock_only_self_reference.stderr +++ b/primitives/api/test/tests/ui/mock_only_self_reference.stderr @@ -1,26 +1,18 @@ error: Only `&self` is supported! - --> $DIR/mock_only_self_reference.rs:14:11 + --> tests/ui/mock_only_self_reference.rs:14:11 | 14 | fn test(self, data: u64) {} | ^^^^ error: Only `&self` is supported! - --> $DIR/mock_only_self_reference.rs:16:12 + --> tests/ui/mock_only_self_reference.rs:16:12 | 16 | fn test2(&mut self, data: u64) {} | ^ error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait - --> $DIR/mock_only_self_reference.rs:12:1 + --> tests/ui/mock_only_self_reference.rs:12:1 | -3 | / sp_api::decl_runtime_apis! { -4 | | pub trait Api { -5 | | fn test(data: u64); -6 | | fn test2(data: u64); -7 | | } -8 | | } - | |_- type in trait -... 12 | sp_api::mock_impl_runtime_apis! { | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | @@ -34,12 +26,8 @@ error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for tr 18 | | } | |_- help: change the parameter type to match the trait: `Option` | - = note: expected fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option, Vec<_>) -> Result<_, _>` - found fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option<()>, Vec<_>) -> Result<_, _>` - = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0053]: method `Api_test2_runtime_api_impl` has an incompatible type for trait - --> $DIR/mock_only_self_reference.rs:12:1 +note: type in trait + --> tests/ui/mock_only_self_reference.rs:3:1 | 3 | / sp_api::decl_runtime_apis! { 4 | | pub trait Api { @@ -47,8 +35,14 @@ error[E0053]: method `Api_test2_runtime_api_impl` has an incompatible type for t 6 | | fn test2(data: u64); 7 | | } 8 | | } - | |_- type in trait -... + | |_^ + = note: expected fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option, Vec<_>) -> Result<_, _>` + found fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option<()>, Vec<_>) -> Result<_, _>` + = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0053]: method `Api_test2_runtime_api_impl` has an incompatible type for trait + --> tests/ui/mock_only_self_reference.rs:12:1 + | 12 | sp_api::mock_impl_runtime_apis! { | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | @@ -62,6 +56,16 @@ error[E0053]: method `Api_test2_runtime_api_impl` has an incompatible type for t 18 | | } | |_- help: change the parameter type to match the trait: `Option` | +note: type in trait + --> tests/ui/mock_only_self_reference.rs:3:1 + | +3 | / sp_api::decl_runtime_apis! { +4 | | pub trait Api { +5 | | fn test(data: u64); +6 | | fn test2(data: u64); +7 | | } +8 | | } + | |_^ = note: expected fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option, Vec<_>) -> Result<_, _>` found fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option<()>, Vec<_>) -> Result<_, _>` = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index d11aebbf149bb..dbc0f6def3aa5 100644 --- a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -1,28 +1,23 @@ error[E0053]: method `test` has an incompatible type for trait - --> $DIR/type_reference_in_impl_runtime_apis_call.rs:19:17 + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:19:17 | -13 | fn test(data: u64); - | --- type in trait -... 19 | fn test(data: &u64) { | ^^^^ | | | expected `u64`, found `&u64` | help: change the parameter type to match the trait: `u64` | +note: type in trait + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:13:17 + | +13 | fn test(data: u64); + | ^^^ = note: expected fn pointer `fn(u64)` found fn pointer `fn(&u64)` error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait - --> $DIR/type_reference_in_impl_runtime_apis_call.rs:17:1 + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:17:1 | -11 | / sp_api::decl_runtime_apis! { -12 | | pub trait Api { -13 | | fn test(data: u64); -14 | | } -15 | | } - | |_- type in trait -16 | 17 | sp_api::impl_runtime_apis! { | -^^^^^^^^^^^^^^^^^^^^^^^^^ | | @@ -36,12 +31,21 @@ error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for tr 35 | | } | |_- help: change the parameter type to match the trait: `std::option::Option` | +note: type in trait + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:11:1 + | +11 | / sp_api::decl_runtime_apis! { +12 | | pub trait Api { +13 | | fn test(data: u64); +14 | | } +15 | | } + | |_^ = note: expected fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option, Vec<_>) -> Result<_, _>` found fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option<&u64>, Vec<_>) -> Result<_, _>` = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/type_reference_in_impl_runtime_apis_call.rs:17:1 + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:17:1 | 17 | / sp_api::impl_runtime_apis! { 18 | | impl self::Api for Runtime { @@ -55,7 +59,7 @@ error[E0308]: mismatched types = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/type_reference_in_impl_runtime_apis_call.rs:19:11 + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:19:11 | 19 | fn test(data: &u64) { | ^^^^^^^ expected `u64`, found `&u64` diff --git a/primitives/runtime-interface/tests/ui.rs b/primitives/runtime-interface/tests/ui.rs index 9e3af145dc566..f3d6aa59a0336 100644 --- a/primitives/runtime-interface/tests/ui.rs +++ b/primitives/runtime-interface/tests/ui.rs @@ -20,6 +20,11 @@ use std::env; #[rustversion::attr(not(stable), ignore)] #[test] fn ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if env::var("RUN_UI_TESTS").is_err() { + return + } + // As trybuild is using `cargo check`, we don't need the real WASM binaries. env::set_var("SKIP_WASM_BUILD", "1"); diff --git a/primitives/state-machine/src/in_memory_backend.rs b/primitives/state-machine/src/in_memory_backend.rs index 4605d07b2ab63..2d8173452abfe 100644 --- a/primitives/state-machine/src/in_memory_backend.rs +++ b/primitives/state-machine/src/in_memory_backend.rs @@ -59,7 +59,7 @@ where ) { let (top, child) = changes.into_iter().partition::, _>(|v| v.0.is_none()); let (root, transaction) = self.full_storage_root( - top.iter().map(|(_, v)| v).flatten().map(|(k, v)| (&k[..], v.as_deref())), + top.iter().flat_map(|(_, v)| v).map(|(k, v)| (&k[..], v.as_deref())), child.iter().filter_map(|v| { v.0.as_ref().map(|c| (c, v.1.iter().map(|(k, v)| (&k[..], v.as_deref())))) }), diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 8531e4907d6a7..418e6f3d2dce1 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -580,16 +580,15 @@ impl<'a, S: 'a + TrieBackendStorage, H: Hasher> hash_db::HashDB for Ephemeral<'a, S, H> { fn get(&self, key: &H::Out, prefix: Prefix) -> Option { - if let Some(val) = HashDB::get(self.overlay, key, prefix) { - Some(val) - } else { - match self.storage.get(&key, prefix) { + match HashDB::get(self.overlay, key, prefix) { + Some(val) => Some(val), + None => match self.storage.get(&key, prefix) { Ok(x) => x, Err(e) => { warn!(target: "trie", "Failed to read from DB: {}", e); None }, - } + }, } } diff --git a/primitives/version/src/embed.rs b/primitives/version/src/embed.rs index e6b468e2e58cc..c71849238fe33 100644 --- a/primitives/version/src/embed.rs +++ b/primitives/version/src/embed.rs @@ -44,8 +44,7 @@ pub fn embed_runtime_version( .apis .iter() .map(Encode::encode) - .map(|v| v.into_iter()) - .flatten() + .flat_map(|v| v.into_iter()) .collect::>(); module.set_custom_section("runtime_apis", apis); diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 533d65c49c2e1..018ad2f4e0ad8 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -848,7 +848,7 @@ impl Builder { info!( target: LOG_TARGET, "injecting a total of {} child keys", - child_kv.iter().map(|(_, kv)| kv).flatten().count() + child_kv.iter().flat_map(|(_, kv)| kv).count(), ); for (info, key_values) in child_kv { From 5597a93a8c8b1ab578693c68549e3ce1902f3eaf Mon Sep 17 00:00:00 2001 From: Koute Date: Mon, 11 Apr 2022 18:46:53 +0900 Subject: [PATCH 0688/1472] Add new hardware and software metrics (#11062) * Add new hardware and software metrics * Move sysinfo tests into `mod tests` * Correct a typo in a comment * Remove unnecessary `nix` dependency * Fix the version tests * Add a `--disable-hardware-benchmarks` CLI argument * Disable hardware benchmarks in the integration tests * Remove unused import * Fix benchmarks compilation * Move code to a new `sc-sysinfo` crate * Correct `impl_version` comment * Move `--disable-hardware-benchmarks` to the chain-specific bin crate * Move printing out of hardware bench results to `sc-sysinfo` * Move hardware benchmarks to a separate messages; trigger them manually * Rename some of the fields in the `HwBench` struct * Revert changes to the telemetry crate; manually send hwbench messages * Move sysinfo logs into the sysinfo crate * Move the `TARGET_OS_*` constants into the sysinfo crate * Minor cleanups * Move the `HwBench` struct to the sysinfo crate * Derive `Clone` for `HwBench` * Fix broken telemetry connection notification stream * Prevent the telemetry connection notifiers from leaking if they're disconnected * Turn the telemetry notification failure log into a debug log * Rename `--disable-hardware-benchmarks` to `--no-hardware-benchmarks` --- Cargo.lock | 30 +- Cargo.toml | 1 + bin/node/cli/Cargo.toml | 1 + bin/node/cli/benches/block_production.rs | 3 +- bin/node/cli/benches/transaction_pool.rs | 2 +- bin/node/cli/src/chain_spec.rs | 2 +- bin/node/cli/src/cli.rs | 10 + bin/node/cli/src/command.rs | 3 +- bin/node/cli/src/service.rs | 34 +- bin/node/cli/tests/check_block_works.rs | 2 +- bin/node/cli/tests/export_import_flow.rs | 2 +- bin/node/cli/tests/inspect_works.rs | 2 +- bin/node/cli/tests/purge_chain_works.rs | 2 +- .../tests/running_the_node_and_interrupt.rs | 3 +- bin/node/cli/tests/telemetry.rs | 1 + bin/node/cli/tests/temp_base_path_works.rs | 2 +- bin/node/cli/tests/version.rs | 24 +- client/cli/src/lib.rs | 2 +- client/service/Cargo.toml | 1 + client/service/src/builder.rs | 12 +- client/sysinfo/Cargo.toml | 26 ++ client/sysinfo/README.md | 4 + client/sysinfo/build.rs | 31 ++ client/sysinfo/src/lib.rs | 111 +++++ client/sysinfo/src/sysinfo.rs | 393 ++++++++++++++++++ client/sysinfo/src/sysinfo_linux.rs | 101 +++++ client/telemetry/src/lib.rs | 32 ++ client/telemetry/src/node.rs | 16 +- utils/build-script-utils/src/version.rs | 18 +- 29 files changed, 808 insertions(+), 63 deletions(-) create mode 100644 client/sysinfo/Cargo.toml create mode 100644 client/sysinfo/README.md create mode 100644 client/sysinfo/build.rs create mode 100644 client/sysinfo/src/lib.rs create mode 100644 client/sysinfo/src/sysinfo.rs create mode 100644 client/sysinfo/src/sysinfo_linux.rs diff --git a/Cargo.lock b/Cargo.lock index c64800e002339..609ccb0baeef9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2842,12 +2842,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "hashbrown" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" - [[package]] name = "hashbrown" version = "0.11.2" @@ -3179,12 +3173,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg 1.0.1", - "hashbrown 0.9.1", + "hashbrown 0.11.2", "serde", ] @@ -4863,6 +4857,7 @@ dependencies = [ "sc-service", "sc-service-test", "sc-sync-state-rpc", + "sc-sysinfo", "sc-telemetry", "sc-transaction-pool", "sc-transaction-pool-api", @@ -9002,6 +8997,7 @@ dependencies = [ "sc-offchain", "sc-rpc", "sc-rpc-server", + "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", @@ -9106,6 +9102,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sc-sysinfo" +version = "6.0.0-dev" +dependencies = [ + "futures 0.3.19", + "libc", + "log 0.4.14", + "rand 0.7.3", + "rand_pcg 0.2.1", + "regex", + "sc-telemetry", + "serde", + "serde_json", + "sp-core", +] + [[package]] name = "sc-telemetry" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 13657dd1234a5..576bae6b574b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ members = [ "client/service", "client/service/test", "client/state-db", + "client/sysinfo", "client/sync-state-rpc", "client/telemetry", "client/tracing", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 4eb5983b6488e..dda6b57d0244b 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -76,6 +76,7 @@ sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-authority-discovery = { version = "0.10.0-dev", path = "../../../client/authority-discovery" } sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state-rpc" } +sc-sysinfo = { version = "6.0.0-dev", path = "../../../client/sysinfo" } # frame dependencies frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 77b51fa28dd1a..ebb89c07da221 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -110,7 +110,8 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { wasm_runtime_overrides: None, }; - node_cli::service::new_full_base(config, |_, _| ()).expect("creating a full node doesn't fail") + node_cli::service::new_full_base(config, false, |_, _| ()) + .expect("creating a full node doesn't fail") } fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index 9a602e286bbae..a889399eda83a 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -102,7 +102,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { wasm_runtime_overrides: None, }; - node_cli::service::new_full_base(config, |_, _| ()).expect("Creates node") + node_cli::service::new_full_base(config, false, |_, _| ()).expect("Creates node") } fn create_accounts(num: usize) -> Vec { diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 11516f964903a..1212d3b3d07ed 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -471,7 +471,7 @@ pub(crate) mod tests { sc_service_test::connectivity(integration_test_config_with_two_authorities(), |config| { let NewFullBase { task_manager, client, network, transaction_pool, .. } = - new_full_base(config, |_, _| ())?; + new_full_base(config, false, |_, _| ())?; Ok(sc_service_test::TestNetComponents::new( task_manager, client, diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 7430cc46f4cc7..5b5db62199bbd 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -26,6 +26,16 @@ pub struct Cli { #[allow(missing_docs)] #[clap(flatten)] pub run: sc_cli::RunCmd, + + /// Disable automatic hardware benchmarks. + /// + /// By default these benchmarks are automatically ran at startup and measure + /// the CPU speed, the memory bandwidth and the disk speed. + /// + /// The results are then printed out in the logs, and also sent as part of + /// telemetry, if telemetry is enabled. + #[clap(long)] + pub no_hardware_benchmarks: bool, } /// Possible subcommands of the main binary. diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index ea91bb90b2f2c..880b7d7b7ecb7 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -86,7 +86,8 @@ pub fn run() -> Result<()> { 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) + service::new_full(config, cli.no_hardware_benchmarks) + .map_err(sc_cli::Error::Service) }) }, Some(Subcommand::Inspect(cmd)) => { diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 03e7311fb3c01..2742e7b113d6d 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -309,11 +309,21 @@ pub struct NewFullBase { /// Creates a full service from the configuration. pub fn new_full_base( mut config: Configuration, + disable_hardware_benchmarks: bool, with_startup_data: impl FnOnce( &sc_consensus_babe::BabeBlockImport, &sc_consensus_babe::BabeLink, ), ) -> Result { + let hwbench = if !disable_hardware_benchmarks { + config.database.path().map(|database_path| { + let _ = std::fs::create_dir_all(&database_path); + sc_sysinfo::gather_hwbench(Some(database_path)) + }) + } else { + None + }; + let sc_service::PartialComponents { client, backend, @@ -383,6 +393,19 @@ pub fn new_full_base( telemetry: telemetry.as_mut(), })?; + if let Some(hwbench) = hwbench { + sc_sysinfo::print_hwbench(&hwbench); + + if let Some(ref mut telemetry) = telemetry { + let telemetry_handle = telemetry.handle(); + task_manager.spawn_handle().spawn( + "telemetry_hwbench", + None, + sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), + ); + } + } + let (block_import, grandpa_link, babe_link) = import_setup; (with_startup_data)(&block_import, &babe_link); @@ -530,8 +553,12 @@ pub fn new_full_base( } /// Builds a new service for a full client. -pub fn new_full(config: Configuration) -> Result { - new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| task_manager) +pub fn new_full( + config: Configuration, + disable_hardware_benchmarks: bool, +) -> Result { + new_full_base(config, disable_hardware_benchmarks, |_, _| ()) + .map(|NewFullBase { task_manager, .. }| task_manager) } #[cfg(test)] @@ -598,6 +625,7 @@ mod tests { let NewFullBase { task_manager, client, network, transaction_pool, .. } = new_full_base( config, + false, |block_import: &sc_consensus_babe::BabeBlockImport, babe_link: &sc_consensus_babe::BabeLink| { setup_handles = Some((block_import.clone(), babe_link.clone())); @@ -775,7 +803,7 @@ mod tests { crate::chain_spec::tests::integration_test_config_with_two_authorities(), |config| { let NewFullBase { task_manager, client, network, transaction_pool, .. } = - new_full_base(config, |_, _| ())?; + new_full_base(config, false, |_, _| ())?; Ok(sc_service_test::TestNetComponents::new( task_manager, client, diff --git a/bin/node/cli/tests/check_block_works.rs b/bin/node/cli/tests/check_block_works.rs index ac853b201b8c6..c5447fd2311c6 100644 --- a/bin/node/cli/tests/check_block_works.rs +++ b/bin/node/cli/tests/check_block_works.rs @@ -28,7 +28,7 @@ pub mod common; async fn check_block_works() { let base_path = tempdir().expect("could not create a temp dir"); - common::run_node_for_a_while(base_path.path(), &["--dev"]).await; + common::run_node_for_a_while(base_path.path(), &["--dev", "--no-hardware-benchmarks"]).await; let status = Command::new(cargo_bin("substrate")) .args(&["check-block", "--dev", "--pruning", "archive", "-d"]) diff --git a/bin/node/cli/tests/export_import_flow.rs b/bin/node/cli/tests/export_import_flow.rs index 2a2133bbfe4fe..48fccc8ca0293 100644 --- a/bin/node/cli/tests/export_import_flow.rs +++ b/bin/node/cli/tests/export_import_flow.rs @@ -188,7 +188,7 @@ async fn export_import_revert() { let exported_blocks_file = base_path.path().join("exported_blocks"); let db_path = base_path.path().join("db"); - common::run_node_for_a_while(base_path.path(), &["--dev"]).await; + common::run_node_for_a_while(base_path.path(), &["--dev", "--no-hardware-benchmarks"]).await; let mut executor = ExportImportRevertExecutor::new(&base_path, &exported_blocks_file, &db_path); diff --git a/bin/node/cli/tests/inspect_works.rs b/bin/node/cli/tests/inspect_works.rs index 28ad88dd501d1..6f73cc69582a9 100644 --- a/bin/node/cli/tests/inspect_works.rs +++ b/bin/node/cli/tests/inspect_works.rs @@ -28,7 +28,7 @@ pub mod common; async fn inspect_works() { let base_path = tempdir().expect("could not create a temp dir"); - common::run_node_for_a_while(base_path.path(), &["--dev"]).await; + common::run_node_for_a_while(base_path.path(), &["--dev", "--no-hardware-benchmarks"]).await; let status = Command::new(cargo_bin("substrate")) .args(&["inspect", "--dev", "--pruning", "archive", "-d"]) diff --git a/bin/node/cli/tests/purge_chain_works.rs b/bin/node/cli/tests/purge_chain_works.rs index 1a62aec287447..811762a714a9d 100644 --- a/bin/node/cli/tests/purge_chain_works.rs +++ b/bin/node/cli/tests/purge_chain_works.rs @@ -27,7 +27,7 @@ pub mod common; async fn purge_chain_works() { let base_path = tempdir().expect("could not create a temp dir"); - common::run_node_for_a_while(base_path.path(), &["--dev"]).await; + common::run_node_for_a_while(base_path.path(), &["--dev", "--no-hardware-benchmarks"]).await; let status = Command::new(cargo_bin("substrate")) .args(&["purge-chain", "--dev", "-d"]) diff --git a/bin/node/cli/tests/running_the_node_and_interrupt.rs b/bin/node/cli/tests/running_the_node_and_interrupt.rs index 703123faf0e62..ecdb4d7671b01 100644 --- a/bin/node/cli/tests/running_the_node_and_interrupt.rs +++ b/bin/node/cli/tests/running_the_node_and_interrupt.rs @@ -38,6 +38,7 @@ async fn running_the_node_works_and_can_be_interrupted() { Command::new(cargo_bin("substrate")) .args(&["--dev", "-d"]) .arg(base_path.path()) + .arg("--no-hardware-benchmarks") .spawn() .unwrap(), ); @@ -61,7 +62,7 @@ async fn running_the_node_works_and_can_be_interrupted() { async fn running_two_nodes_with_the_same_ws_port_should_work() { fn start_node() -> Child { Command::new(cargo_bin("substrate")) - .args(&["--dev", "--tmp", "--ws-port=45789"]) + .args(&["--dev", "--tmp", "--ws-port=45789", "--no-hardware-benchmarks"]) .spawn() .unwrap() } diff --git a/bin/node/cli/tests/telemetry.rs b/bin/node/cli/tests/telemetry.rs index 64da4bd4b68f1..bef4e4ea03048 100644 --- a/bin/node/cli/tests/telemetry.rs +++ b/bin/node/cli/tests/telemetry.rs @@ -71,6 +71,7 @@ async fn telemetry_works() { let mut substrate = substrate .args(&["--dev", "--tmp", "--telemetry-url"]) .arg(format!("ws://{} 10", addr)) + .arg("--no-hardware-benchmarks") .stdout(process::Stdio::piped()) .stderr(process::Stdio::piped()) .stdin(process::Stdio::null()) diff --git a/bin/node/cli/tests/temp_base_path_works.rs b/bin/node/cli/tests/temp_base_path_works.rs index 306c490c2f760..df293161e3234 100644 --- a/bin/node/cli/tests/temp_base_path_works.rs +++ b/bin/node/cli/tests/temp_base_path_works.rs @@ -36,7 +36,7 @@ pub mod common; async fn temp_base_path_works() { let mut cmd = Command::new(cargo_bin("substrate")); let mut child = common::KillChildOnDrop( - cmd.args(&["--dev", "--tmp"]) + cmd.args(&["--dev", "--tmp", "--no-hardware-benchmarks"]) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() diff --git a/bin/node/cli/tests/version.rs b/bin/node/cli/tests/version.rs index 133eb65f4acef..f5a6f3a53d598 100644 --- a/bin/node/cli/tests/version.rs +++ b/bin/node/cli/tests/version.rs @@ -17,13 +17,11 @@ // along with this program. If not, see . use assert_cmd::cargo::cargo_bin; -use platforms::*; use regex::Regex; use std::process::Command; fn expected_regex() -> Regex { - Regex::new(r"^substrate (\d+\.\d+\.\d+(?:-.+?)?)-([a-f\d]+|unknown)-(.+?)-(.+?)(?:-(.+))?$") - .unwrap() + Regex::new(r"^substrate (.+)-([a-f\d]+)$").unwrap() } #[test] @@ -37,33 +35,17 @@ fn version_is_full() { let captures = expected.captures(output.as_str()).expect("could not parse version in output"); assert_eq!(&captures[1], env!("CARGO_PKG_VERSION")); - assert_eq!(&captures[3], TARGET_ARCH.as_str()); - assert_eq!(&captures[4], TARGET_OS.as_str()); - assert_eq!(captures.get(5).map(|x| x.as_str()), TARGET_ENV.map(|x| x.as_str())); } #[test] fn test_regex_matches_properly() { let expected = expected_regex(); - let captures = expected.captures("substrate 2.0.0-da487d19d-x86_64-linux-gnu").unwrap(); + let captures = expected.captures("substrate 2.0.0-da487d19d").unwrap(); assert_eq!(&captures[1], "2.0.0"); assert_eq!(&captures[2], "da487d19d"); - assert_eq!(&captures[3], "x86_64"); - assert_eq!(&captures[4], "linux"); - assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu")); - let captures = expected.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux-gnu").unwrap(); + let captures = expected.captures("substrate 2.0.0-alpha.5-da487d19d").unwrap(); assert_eq!(&captures[1], "2.0.0-alpha.5"); assert_eq!(&captures[2], "da487d19d"); - assert_eq!(&captures[3], "x86_64"); - assert_eq!(&captures[4], "linux"); - assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu")); - - let captures = expected.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux").unwrap(); - assert_eq!(&captures[1], "2.0.0-alpha.5"); - assert_eq!(&captures[2], "da487d19d"); - assert_eq!(&captures[3], "x86_64"); - assert_eq!(&captures[4], "linux"); - assert_eq!(captures.get(5).map(|x| x.as_str()), None); } diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index c920c6cd52cff..849a2d2cceb1f 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -56,7 +56,7 @@ pub trait SubstrateCli: Sized { /// /// By default this will look like this: /// - /// `2.0.0-b950f731c-x86_64-linux-gnu` + /// `2.0.0-b950f731c` /// /// Where the hash is the short commit hash of the commit of in the Git repository. fn impl_version() -> String; diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 47474217ebd2a..c40559bdb5059 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -72,6 +72,7 @@ sc-offchain = { version = "4.0.0-dev", path = "../offchain" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sc-sysinfo = { version = "6.0.0-dev", path = "../sysinfo" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } parity-util-mem = { version = "0.11.0", default-features = false, features = [ diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index f4ff932435755..882d7666dbe63 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -487,8 +487,13 @@ where ) .map_err(|e| Error::Application(Box::new(e)))?; + let sysinfo = sc_sysinfo::gather_sysinfo(); + sc_sysinfo::print_sysinfo(&sysinfo); + let telemetry = telemetry - .map(|telemetry| init_telemetry(&mut config, network.clone(), client.clone(), telemetry)) + .map(|telemetry| { + init_telemetry(&mut config, network.clone(), client.clone(), telemetry, Some(sysinfo)) + }) .transpose()?; info!("📦 Highest known block at #{}", chain_info.best_number); @@ -609,12 +614,16 @@ fn init_telemetry>( network: Arc::Hash>>, client: Arc, telemetry: &mut Telemetry, + sysinfo: Option, ) -> sc_telemetry::Result { let genesis_hash = client.block_hash(Zero::zero()).ok().flatten().unwrap_or_default(); let connection_message = ConnectionMessage { name: config.network.node_name.to_owned(), implementation: config.impl_name.to_owned(), version: config.impl_version.to_owned(), + target_os: sc_sysinfo::TARGET_OS.into(), + target_arch: sc_sysinfo::TARGET_ARCH.into(), + target_env: sc_sysinfo::TARGET_ENV.into(), config: String::new(), chain: config.chain_spec.name().to_owned(), genesis_hash: format!("{:?}", genesis_hash), @@ -625,6 +634,7 @@ fn init_telemetry>( .unwrap_or(0) .to_string(), network_id: network.local_peer_id().to_base58(), + sysinfo, }; telemetry.start_telemetry(connection_message)?; diff --git a/client/sysinfo/Cargo.toml b/client/sysinfo/Cargo.toml new file mode 100644 index 0000000000000..8efe583fb9335 --- /dev/null +++ b/client/sysinfo/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "sc-sysinfo" +version = "6.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "A crate that provides basic hardware and software telemetry information." +documentation = "https://docs.rs/sc-sysinfo" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +futures = "0.3.19" +log = "0.4.11" +rand = "0.7.3" +rand_pcg = "0.2.1" +regex = "1" +libc = "0.2" +serde = { version = "1.0.136", features = ["derive"] } +serde_json = "1.0.79" +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } diff --git a/client/sysinfo/README.md b/client/sysinfo/README.md new file mode 100644 index 0000000000000..4a2189c5ed8db --- /dev/null +++ b/client/sysinfo/README.md @@ -0,0 +1,4 @@ +This crate contains the code necessary to gather basic hardware +and software telemetry information about the node on which we're running. + +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/client/sysinfo/build.rs b/client/sysinfo/build.rs new file mode 100644 index 0000000000000..6d288107445aa --- /dev/null +++ b/client/sysinfo/build.rs @@ -0,0 +1,31 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +fn main() { + let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR is always set in build scripts; qed"); + let out_dir = std::path::PathBuf::from(out_dir); + let target_os = std::env::var("CARGO_CFG_TARGET_OS") + .expect("CARGO_CFG_TARGET_OS is always set in build scripts; qed"); + let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH") + .expect("CARGO_CFG_TARGET_ARCH is always set in build scripts; qed"); + let target_env = std::env::var("CARGO_CFG_TARGET_ENV") + .expect("CARGO_CFG_TARGET_ENV is always set in build scripts; qed"); + std::fs::write(out_dir.join("target_os.txt"), target_os).unwrap(); + std::fs::write(out_dir.join("target_arch.txt"), target_arch).unwrap(); + std::fs::write(out_dir.join("target_env.txt"), target_env).unwrap(); +} diff --git a/client/sysinfo/src/lib.rs b/client/sysinfo/src/lib.rs new file mode 100644 index 0000000000000..be13efb82c66f --- /dev/null +++ b/client/sysinfo/src/lib.rs @@ -0,0 +1,111 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! This crate contains the code necessary to gather basic hardware +//! and software telemetry information about the node on which we're running. + +use futures::prelude::*; + +mod sysinfo; +#[cfg(target_os = "linux")] +mod sysinfo_linux; + +pub use sysinfo::{gather_hwbench, gather_sysinfo}; + +/// The operating system part of the current target triplet. +pub const TARGET_OS: &str = include_str!(concat!(env!("OUT_DIR"), "/target_os.txt")); + +/// The CPU ISA architecture part of the current target triplet. +pub const TARGET_ARCH: &str = include_str!(concat!(env!("OUT_DIR"), "/target_arch.txt")); + +/// The environment part of the current target triplet. +pub const TARGET_ENV: &str = include_str!(concat!(env!("OUT_DIR"), "/target_env.txt")); + +/// Hardware benchmark results for the node. +#[derive(Clone, Debug, serde::Serialize)] +pub struct HwBench { + /// The CPU speed, as measured in how many MB/s it can hash using the BLAKE2b-256 hash. + pub cpu_hashrate_score: u64, + /// Memory bandwidth in MB/s, calculated by measuring the throughput of `memcpy`. + pub memory_memcpy_score: u64, + /// Sequential disk write speed in MB/s. + pub disk_sequential_write_score: Option, + /// Random disk write speed in MB/s. + pub disk_random_write_score: Option, +} + +/// Prints out the system software/hardware information in the logs. +pub fn print_sysinfo(sysinfo: &sc_telemetry::SysInfo) { + log::info!("💻 Operating system: {}", TARGET_OS); + log::info!("💻 CPU architecture: {}", TARGET_ARCH); + if !TARGET_ENV.is_empty() { + log::info!("💻 Target environment: {}", TARGET_ENV); + } + + if let Some(ref cpu) = sysinfo.cpu { + log::info!("💻 CPU: {}", cpu); + } + if let Some(core_count) = sysinfo.core_count { + log::info!("💻 CPU cores: {}", core_count); + } + if let Some(memory) = sysinfo.memory { + log::info!("💻 Memory: {}MB", memory / (1024 * 1024)); + } + if let Some(ref linux_kernel) = sysinfo.linux_kernel { + log::info!("💻 Kernel: {}", linux_kernel); + } + if let Some(ref linux_distro) = sysinfo.linux_distro { + log::info!("💻 Linux distribution: {}", linux_distro); + } + if let Some(is_virtual_machine) = sysinfo.is_virtual_machine { + log::info!("💻 Virtual machine: {}", if is_virtual_machine { "yes" } else { "no" }); + } +} + +/// Prints out the results of the hardware benchmarks in the logs. +pub fn print_hwbench(hwbench: &HwBench) { + log::info!("🏁 CPU score: {}MB/s", hwbench.cpu_hashrate_score); + log::info!("🏁 Memory score: {}MB/s", hwbench.memory_memcpy_score); + + if let Some(score) = hwbench.disk_sequential_write_score { + log::info!("🏁 Disk score (seq. writes): {}MB/s", score); + } + if let Some(score) = hwbench.disk_random_write_score { + log::info!("🏁 Disk score (rand. writes): {}MB/s", score); + } +} + +/// Initializes the hardware benchmarks telemetry. +pub fn initialize_hwbench_telemetry( + telemetry_handle: sc_telemetry::TelemetryHandle, + hwbench: HwBench, +) -> impl std::future::Future { + let mut connect_stream = telemetry_handle.on_connect_stream(); + async move { + let payload = serde_json::to_value(&hwbench) + .expect("the `HwBench` can always be serialized into a JSON object; qed"); + let mut payload = match payload { + serde_json::Value::Object(map) => map, + _ => unreachable!("the `HwBench` always serializes into a JSON object; qed"), + }; + payload.insert("msg".into(), "sysinfo.hwbench".into()); + while connect_stream.next().await.is_some() { + telemetry_handle.send_telemetry(sc_telemetry::SUBSTRATE_INFO, payload.clone()); + } + } +} diff --git a/client/sysinfo/src/sysinfo.rs b/client/sysinfo/src/sysinfo.rs new file mode 100644 index 0000000000000..ceb28447002cf --- /dev/null +++ b/client/sysinfo/src/sysinfo.rs @@ -0,0 +1,393 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::HwBench; +use rand::{seq::SliceRandom, Rng}; +use sc_telemetry::SysInfo; +use std::{ + fs::File, + io::{Seek, SeekFrom, Write}, + ops::{Deref, DerefMut}, + path::{Path, PathBuf}, + time::{Duration, Instant}, +}; + +#[inline(always)] +pub(crate) fn benchmark( + name: &str, + size: usize, + max_iterations: usize, + max_duration: Duration, + mut run: impl FnMut() -> Result<(), E>, +) -> Result { + // Run the benchmark once as a warmup to get the code into the L1 cache. + run()?; + + // Then run it multiple times and average the result. + let timestamp = Instant::now(); + let mut elapsed = Duration::default(); + let mut count = 0; + for _ in 0..max_iterations { + run()?; + + count += 1; + elapsed = timestamp.elapsed(); + + if elapsed >= max_duration { + break + } + } + + let score = (((size * count) as f64 / elapsed.as_secs_f64()) / (1024.0 * 1024.0)) as u64; + log::trace!( + "Calculated {} of {}MB/s in {} iterations in {}ms", + name, + score, + count, + elapsed.as_millis() + ); + Ok(score) +} + +/// Gathers information about node's hardware and software. +pub fn gather_sysinfo() -> SysInfo { + #[allow(unused_mut)] + let mut sysinfo = SysInfo { + cpu: None, + memory: None, + core_count: None, + linux_kernel: None, + linux_distro: None, + is_virtual_machine: None, + }; + + #[cfg(target_os = "linux")] + crate::sysinfo_linux::gather_linux_sysinfo(&mut sysinfo); + + sysinfo +} + +#[inline(never)] +fn clobber(slice: &mut [u8]) { + assert!(!slice.is_empty()); + + // Discourage the compiler from optimizing out our benchmarks. + // + // Volatile reads and writes are guaranteed to not be elided nor reordered, + // so we can use them to effectively clobber a piece of memory and prevent + // the compiler from optimizing out our technically unnecessary code. + // + // This is not totally bulletproof in theory, but should work in practice. + // + // SAFETY: We've checked that the slice is not empty, so reading and writing + // its first element is always safe. + unsafe { + let value = std::ptr::read_volatile(slice.as_ptr()); + std::ptr::write_volatile(slice.as_mut_ptr(), value); + } +} + +// This benchmarks the CPU speed as measured by calculating BLAKE2b-256 hashes, in MB/s. +fn benchmark_cpu() -> u64 { + // In general the results of this benchmark are somewhat sensitive to how much + // data we hash at the time. The smaller this is the *less* MB/s we can hash, + // the bigger this is the *more* MB/s we can hash, up until a certain point + // where we can achieve roughly ~100% of what the hasher can do. If we'd plot + // this on a graph with the number of bytes we want to hash on the X axis + // and the speed in MB/s on the Y axis then we'd essentially see it grow + // logarithmically. + // + // In practice however we might not always have enough data to hit the maximum + // possible speed that the hasher can achieve, so the size set here should be + // picked in such a way as to still measure how fast the hasher is at hashing, + // but without hitting its theoretical maximum speed. + const SIZE: usize = 32 * 1024; + const MAX_ITERATIONS: usize = 4 * 1024; + const MAX_DURATION: Duration = Duration::from_millis(100); + + let mut buffer = Vec::new(); + buffer.resize(SIZE, 0x66); + let mut hash = Default::default(); + + let run = || -> Result<(), ()> { + clobber(&mut buffer); + hash = sp_core::hashing::blake2_256(&buffer); + clobber(&mut hash); + + Ok(()) + }; + + benchmark("CPU score", SIZE, MAX_ITERATIONS, MAX_DURATION, run) + .expect("benchmark cannot fail; qed") +} + +// This benchmarks the effective `memcpy` memory bandwidth available in MB/s. +// +// It doesn't technically measure the absolute maximum memory bandwidth available, +// but that's fine, because real code most of the time isn't optimized to take +// advantage of the full memory bandwidth either. +fn benchmark_memory() -> u64 { + // Ideally this should be at least as big as the CPU's L3 cache, + // and it should be big enough so that the `memcpy` takes enough + // time to be actually measurable. + // + // As long as it's big enough increasing it further won't change + // the benchmark's results. + const SIZE: usize = 64 * 1024 * 1024; + const MAX_ITERATIONS: usize = 32; + const MAX_DURATION: Duration = Duration::from_millis(100); + + let mut src = Vec::new(); + let mut dst = Vec::new(); + + // Prefault the pages; we want to measure the memory bandwidth, + // not how fast the kernel can supply us with fresh memory pages. + src.resize(SIZE, 0x66); + dst.resize(SIZE, 0x77); + + let run = || -> Result<(), ()> { + clobber(&mut src); + clobber(&mut dst); + + // SAFETY: Both vectors are of the same type and of the same size, + // so copying data between them is safe. + unsafe { + // We use `memcpy` directly here since `copy_from_slice` isn't actually + // guaranteed to be turned into a `memcpy`. + libc::memcpy(dst.as_mut_ptr().cast(), src.as_ptr().cast(), SIZE); + } + + clobber(&mut dst); + clobber(&mut src); + + Ok(()) + }; + + benchmark("memory score", SIZE, MAX_ITERATIONS, MAX_DURATION, run) + .expect("benchmark cannot fail; qed") +} + +struct TemporaryFile { + fp: Option, + path: PathBuf, +} + +impl Drop for TemporaryFile { + fn drop(&mut self) { + let _ = self.fp.take(); + + // Remove the file. + // + // This has to be done *after* the benchmark, + // otherwise it changes the results as the data + // doesn't actually get properly flushed to the disk, + // since the file's not there anymore. + if let Err(error) = std::fs::remove_file(&self.path) { + log::warn!("Failed to remove the file used for the disk benchmark: {}", error); + } + } +} + +impl Deref for TemporaryFile { + type Target = File; + fn deref(&self) -> &Self::Target { + self.fp.as_ref().expect("`fp` is None only during `drop`") + } +} + +impl DerefMut for TemporaryFile { + fn deref_mut(&mut self) -> &mut Self::Target { + self.fp.as_mut().expect("`fp` is None only during `drop`") + } +} + +fn rng() -> rand_pcg::Pcg64 { + rand_pcg::Pcg64::new(0xcafef00dd15ea5e5, 0xa02bdbf7bb3c0a7ac28fa16a64abf96) +} + +fn random_data(size: usize) -> Vec { + let mut buffer = Vec::new(); + buffer.resize(size, 0); + rng().fill(&mut buffer[..]); + buffer +} + +pub fn benchmark_disk_sequential_writes(directory: &Path) -> Result { + const SIZE: usize = 64 * 1024 * 1024; + const MAX_ITERATIONS: usize = 32; + const MAX_DURATION: Duration = Duration::from_millis(300); + + let buffer = random_data(SIZE); + let path = directory.join(".disk_bench_seq_wr.tmp"); + + let fp = + File::create(&path).map_err(|error| format!("failed to create a test file: {}", error))?; + + let mut fp = TemporaryFile { fp: Some(fp), path }; + + fp.sync_all() + .map_err(|error| format!("failed to fsync the test file: {}", error))?; + + let run = || { + // Just dump everything to the disk in one go. + fp.write_all(&buffer) + .map_err(|error| format!("failed to write to the test file: {}", error))?; + + // And then make sure it was actually written to disk. + fp.sync_all() + .map_err(|error| format!("failed to fsync the test file: {}", error))?; + + // Rewind to the beginning for the next iteration of the benchmark. + fp.seek(SeekFrom::Start(0)) + .map_err(|error| format!("failed to seek to the start of the test file: {}", error))?; + + Ok(()) + }; + + benchmark("disk sequential write score", SIZE, MAX_ITERATIONS, MAX_DURATION, run) +} + +pub fn benchmark_disk_random_writes(directory: &Path) -> Result { + const SIZE: usize = 64 * 1024 * 1024; + const MAX_ITERATIONS: usize = 32; + const MAX_DURATION: Duration = Duration::from_millis(300); + + let buffer = random_data(SIZE); + let path = directory.join(".disk_bench_rand_wr.tmp"); + + let fp = + File::create(&path).map_err(|error| format!("failed to create a test file: {}", error))?; + + let mut fp = TemporaryFile { fp: Some(fp), path }; + + // Since we want to test random writes we need an existing file + // through which we can seek, so here we just populate it with some data. + fp.write_all(&buffer) + .map_err(|error| format!("failed to write to the test file: {}", error))?; + + fp.sync_all() + .map_err(|error| format!("failed to fsync the test file: {}", error))?; + + // Generate a list of random positions at which we'll issue writes. + let mut positions = Vec::with_capacity(SIZE / 4096); + { + let mut position = 0; + while position < SIZE { + positions.push(position); + position += 4096; + } + } + + positions.shuffle(&mut rng()); + + let run = || { + for &position in &positions { + fp.seek(SeekFrom::Start(position as u64)) + .map_err(|error| format!("failed to seek in the test file: {}", error))?; + + // Here we deliberately only write half of the chunk since we don't + // want the OS' disk scheduler to coalesce our writes into one single + // sequential write. + // + // Also the chunk's size is deliberately exactly half of a modern disk's + // sector size to trigger an RMW cycle. + let chunk = &buffer[position..position + 2048]; + fp.write_all(&chunk) + .map_err(|error| format!("failed to write to the test file: {}", error))?; + } + + fp.sync_all() + .map_err(|error| format!("failed to fsync the test file: {}", error))?; + + Ok(()) + }; + + // We only wrote half of the bytes hence `SIZE / 2`. + benchmark("disk random write score", SIZE / 2, MAX_ITERATIONS, MAX_DURATION, run) +} + +/// Benchmarks the hardware and returns the results of those benchmarks. +/// +/// Optionally accepts a path to a `scratch_directory` to use to benchmark the disk. +pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { + #[allow(unused_mut)] + let mut hwbench = HwBench { + cpu_hashrate_score: benchmark_cpu(), + memory_memcpy_score: benchmark_memory(), + disk_sequential_write_score: None, + disk_random_write_score: None, + }; + + if let Some(scratch_directory) = scratch_directory { + hwbench.disk_sequential_write_score = + match benchmark_disk_sequential_writes(scratch_directory) { + Ok(score) => Some(score), + Err(error) => { + log::warn!("Failed to run the sequential write disk benchmark: {}", error); + None + }, + }; + + hwbench.disk_random_write_score = match benchmark_disk_random_writes(scratch_directory) { + Ok(score) => Some(score), + Err(error) => { + log::warn!("Failed to run the random write disk benchmark: {}", error); + None + }, + }; + } + + hwbench +} + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(target_os = "linux")] + #[test] + fn test_gather_sysinfo_linux() { + let sysinfo = gather_sysinfo(); + assert!(sysinfo.cpu.unwrap().len() > 0); + assert!(sysinfo.core_count.unwrap() > 0); + assert!(sysinfo.memory.unwrap() > 0); + assert_ne!(sysinfo.is_virtual_machine, None); + assert_ne!(sysinfo.linux_kernel, None); + assert_ne!(sysinfo.linux_distro, None); + } + + #[test] + fn test_benchmark_cpu() { + assert_ne!(benchmark_cpu(), 0); + } + + #[test] + fn test_benchmark_memory() { + assert_ne!(benchmark_memory(), 0); + } + + #[test] + fn test_benchmark_disk_sequential_writes() { + assert!(benchmark_disk_sequential_writes("./".as_ref()).unwrap() > 0); + } + + #[test] + fn test_benchmark_disk_random_writes() { + assert!(benchmark_disk_random_writes("./".as_ref()).unwrap() > 0); + } +} diff --git a/client/sysinfo/src/sysinfo_linux.rs b/client/sysinfo/src/sysinfo_linux.rs new file mode 100644 index 0000000000000..41ab6014cbef0 --- /dev/null +++ b/client/sysinfo/src/sysinfo_linux.rs @@ -0,0 +1,101 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use regex::Regex; +use sc_telemetry::SysInfo; +use std::collections::HashSet; + +fn read_file(path: &str) -> Option { + match std::fs::read_to_string(path) { + Ok(data) => Some(data), + Err(error) => { + log::warn!("Failed to read '{}': {}", path, error); + None + }, + } +} + +fn extract(data: &str, regex: &str) -> Option +where + T: std::str::FromStr, +{ + Regex::new(regex) + .expect("regex is correct; qed") + .captures(&data)? + .get(1)? + .as_str() + .parse() + .ok() +} + +const LINUX_REGEX_CPU: &str = r#"(?m)^model name\s*:\s*([^\n]+)"#; +const LINUX_REGEX_PHYSICAL_ID: &str = r#"(?m)^physical id\s*:\s*(\d+)"#; +const LINUX_REGEX_CORE_ID: &str = r#"(?m)^core id\s*:\s*(\d+)"#; +const LINUX_REGEX_HYPERVISOR: &str = r#"(?m)^flags\s*:.+?\bhypervisor\b"#; +const LINUX_REGEX_MEMORY: &str = r#"(?m)^MemTotal:\s*(\d+) kB"#; +const LINUX_REGEX_DISTRO: &str = r#"(?m)^PRETTY_NAME\s*=\s*"?(.+?)"?$"#; + +pub fn gather_linux_sysinfo(sysinfo: &mut SysInfo) { + if let Some(data) = read_file("/proc/cpuinfo") { + sysinfo.cpu = extract(&data, LINUX_REGEX_CPU); + sysinfo.is_virtual_machine = + Some(Regex::new(LINUX_REGEX_HYPERVISOR).unwrap().is_match(&data)); + + // The /proc/cpuinfo returns a list of all of the hardware threads. + // + // Here we extract all of the unique {CPU ID, core ID} pairs to get + // the total number of cores. + let mut set: HashSet<(u32, u32)> = HashSet::new(); + for chunk in data.split("\n\n") { + let pid = extract(chunk, LINUX_REGEX_PHYSICAL_ID); + let cid = extract(chunk, LINUX_REGEX_CORE_ID); + if let (Some(pid), Some(cid)) = (pid, cid) { + set.insert((pid, cid)); + } + } + + if !set.is_empty() { + sysinfo.core_count = Some(set.len() as u32); + } + } + + if let Some(data) = read_file("/proc/meminfo") { + sysinfo.memory = extract(&data, LINUX_REGEX_MEMORY).map(|memory: u64| memory * 1024); + } + + if let Some(data) = read_file("/etc/os-release") { + sysinfo.linux_distro = extract(&data, LINUX_REGEX_DISTRO); + } + + // NOTE: We don't use the `nix` crate to call this since it doesn't + // currently check for errors. + unsafe { + // SAFETY: The `utsname` is full of byte arrays, so this is safe. + let mut uname: libc::utsname = std::mem::zeroed(); + if libc::uname(&mut uname) < 0 { + log::warn!("uname failed: {}", std::io::Error::last_os_error()); + } else { + let length = + uname.release.iter().position(|&byte| byte == 0).unwrap_or(uname.release.len()); + let release = std::slice::from_raw_parts(uname.release.as_ptr().cast(), length); + if let Ok(release) = std::str::from_utf8(release) { + sysinfo.linux_kernel = Some(release.into()); + } + } + } +} diff --git a/client/telemetry/src/lib.rs b/client/telemetry/src/lib.rs index 68128e0207085..d570701a3d9ec 100644 --- a/client/telemetry/src/lib.rs +++ b/client/telemetry/src/lib.rs @@ -101,6 +101,38 @@ pub struct ConnectionMessage { pub startup_time: String, /// Node's network ID. pub network_id: String, + + /// Node's OS. + pub target_os: String, + + /// Node's ISA. + pub target_arch: String, + + /// Node's target platform ABI or libc. + pub target_env: String, + + /// Node's software and hardware information. + pub sysinfo: Option, +} + +/// Hardware and software information for the node. +/// +/// Gathering most of this information is highly OS-specific, +/// so most of the fields here are optional. +#[derive(Debug, Serialize)] +pub struct SysInfo { + /// The exact CPU model. + pub cpu: Option, + /// The total amount of memory, in bytes. + pub memory: Option, + /// The number of physical CPU cores. + pub core_count: Option, + /// The Linux kernel version. + pub linux_kernel: Option, + /// The exact Linux distribution used. + pub linux_distro: Option, + /// Whether the node's running under a virtual machine. + pub is_virtual_machine: Option, } /// Telemetry worker. diff --git a/client/telemetry/src/node.rs b/client/telemetry/src/node.rs index ec857ede70fdb..f3d746abb2b18 100644 --- a/client/telemetry/src/node.rs +++ b/client/telemetry/src/node.rs @@ -179,8 +179,20 @@ where Poll::Ready(Ok(sink)) => { log::debug!(target: "telemetry", "✅ Connected to {}", self.addr); - for sender in self.telemetry_connection_notifier.iter_mut() { - let _ = sender.send(()); + { + let mut index = 0; + while index < self.telemetry_connection_notifier.len() { + let sender = &mut self.telemetry_connection_notifier[index]; + if let Err(error) = sender.try_send(()) { + if !error.is_disconnected() { + log::debug!(target: "telemetry", "Failed to send a telemetry connection notification: {}", error); + } else { + self.telemetry_connection_notifier.swap_remove(index); + continue + } + } + index += 1; + } } let buf = self diff --git a/utils/build-script-utils/src/version.rs b/utils/build-script-utils/src/version.rs index 773949e30d8d4..9432f23e9b8ee 100644 --- a/utils/build-script-utils/src/version.rs +++ b/utils/build-script-utils/src/version.rs @@ -15,7 +15,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use platforms::*; use std::{borrow::Cow, process::Command}; /// Generate the `cargo:` key output @@ -42,26 +41,13 @@ pub fn generate_cargo_keys() { println!("cargo:rustc-env=SUBSTRATE_CLI_IMPL_VERSION={}", get_version(&commit)) } -fn get_platform() -> String { - let env_dash = if TARGET_ENV.is_some() { "-" } else { "" }; - - format!( - "{}-{}{}{}", - TARGET_ARCH.as_str(), - TARGET_OS.as_str(), - env_dash, - TARGET_ENV.map(|x| x.as_str()).unwrap_or(""), - ) -} - fn get_version(impl_commit: &str) -> String { let commit_dash = if impl_commit.is_empty() { "" } else { "-" }; format!( - "{}{}{}-{}", + "{}{}{}", std::env::var("CARGO_PKG_VERSION").unwrap_or_default(), commit_dash, - impl_commit, - get_platform(), + impl_commit ) } From 2cdae822589863846dbe589015c5397545d26abb Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Tue, 12 Apr 2022 17:26:34 +1200 Subject: [PATCH 0689/1472] add has_identity (#11197) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add has_identity * Update frame/identity/src/lib.rs Co-authored-by: Bastian Köcher * update * update Co-authored-by: Bastian Köcher --- Cargo.lock | 2 +- frame/identity/src/lib.rs | 6 ++++++ frame/identity/src/tests.rs | 17 +++++++++++++++++ frame/identity/src/types.rs | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 609ccb0baeef9..29e4c2c1ad320 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9106,7 +9106,7 @@ dependencies = [ name = "sc-sysinfo" version = "6.0.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "libc", "log 0.4.14", "rand 0.7.3", diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 51e63541a89b1..904b71654b416 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -978,4 +978,10 @@ impl Pallet { .filter_map(|a| SuperOf::::get(&a).map(|x| (a, x.1))) .collect() } + + /// Check if the account has corresponding identity information by the identity field. + pub fn has_identity(who: &T::AccountId, fields: u64) -> bool { + IdentityOf::::get(who) + .map_or(false, |registration| (registration.info.fields().0.bits() & fields) == fields) + } } diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index bf41b451cbaa3..8cb0563ebeaa1 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -500,3 +500,20 @@ fn setting_account_id_should_work() { assert_ok!(Identity::set_account_id(Origin::signed(4), 0, 3)); }); } + +#[test] +fn test_has_identity() { + new_test_ext().execute_with(|| { + assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert!(Identity::has_identity(&10, IdentityField::Display as u64)); + assert!(Identity::has_identity(&10, IdentityField::Legal as u64)); + assert!(Identity::has_identity( + &10, + IdentityField::Display as u64 | IdentityField::Legal as u64 + )); + assert!(!Identity::has_identity( + &10, + IdentityField::Display as u64 | IdentityField::Legal as u64 | IdentityField::Web as u64 + )); + }); +} diff --git a/frame/identity/src/types.rs b/frame/identity/src/types.rs index 18fc54c941cbd..cb8091fe18747 100644 --- a/frame/identity/src/types.rs +++ b/frame/identity/src/types.rs @@ -53,6 +53,12 @@ pub enum Data { ShaThree256([u8; 32]), } +impl Data { + pub fn is_none(&self) -> bool { + self == &Data::None + } +} + impl Decode for Data { fn decode(input: &mut I) -> sp_std::result::Result { let b = input.read_byte()?; @@ -333,6 +339,37 @@ pub struct IdentityInfo> { pub twitter: Data, } +impl> IdentityInfo { + pub(crate) fn fields(&self) -> IdentityFields { + let mut res = >::empty(); + if !self.display.is_none() { + res.insert(IdentityField::Display); + } + if !self.legal.is_none() { + res.insert(IdentityField::Legal); + } + if !self.web.is_none() { + res.insert(IdentityField::Web); + } + if !self.riot.is_none() { + res.insert(IdentityField::Riot); + } + if !self.email.is_none() { + res.insert(IdentityField::Email); + } + if self.pgp_fingerprint.is_some() { + res.insert(IdentityField::PgpFingerprint); + } + if !self.image.is_none() { + res.insert(IdentityField::Image); + } + if !self.twitter.is_none() { + res.insert(IdentityField::Twitter); + } + IdentityFields(res) + } +} + /// Information concerning the identity of the controller of an account. /// /// NOTE: This is stored separately primarily to facilitate the addition of extra fields in a From ebef053858dbb1c5f1880c1688a9e48b498e1fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 12 Apr 2022 13:12:53 +0200 Subject: [PATCH 0690/1472] Finality notification: Optimize calculation of stale heads (#11200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Finality notification: Optimize calculation of stale heads While looking into some problem on Versi where a collator seemed to be stuck. I found out that it was not stuck but there was a huge gap between last finalized and best block. This lead to a lot leaves and it was basically trapped inside some loop of reading block headers from the db to find the stale heads. While looking into this I found out that `leaves` already supports the feature to give us the stale heads relative easily. However, the semantics change a little bit. Instead of returning all stale heads of blocks that are not reachable anymore after finalizing a block, we currently only return heads with a number lower than the finalized block. This should be no problem, because these other leaves that are stale will be returned later when a block gets finalized which number is bigger than the block number of these leaves. While doing that, I also changed `tree_route` of the `FinalityNotification` to include the `old_finalized`. Based on the comment I assumed that this was already part of it. However, if wanted, I can revert this change. * FMT * Update client/service/src/client/client.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Do not include the last finalized block * Rename function * FMT * Fix tests * Update figure Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- client/api/src/client.rs | 2 + client/api/src/in_mem.rs | 14 +++++++ client/api/src/leaves.rs | 20 +++++++++- client/consensus/babe/src/tests.rs | 4 +- client/db/src/lib.rs | 13 +++++++ client/service/src/client/client.rs | 41 +++++++------------- client/service/test/src/client/mod.rs | 30 +++++++++----- primitives/blockchain/src/backend.rs | 8 ++++ primitives/blockchain/src/header_metadata.rs | 5 +++ 9 files changed, 99 insertions(+), 38 deletions(-) diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 9c55be3238130..183ce610e7b7c 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -307,6 +307,8 @@ pub struct FinalityNotification { /// Finalized block header. pub header: Block::Header, /// Path from the old finalized to new finalized parent (implicitly finalized blocks). + /// + /// This maps to the range `(old_finalized, new_finalized]`. pub tree_route: Arc<[Block::Hash]>, /// Stale branches heads. pub stale_heads: Arc<[Block::Hash]>, diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index d989004ee2178..51370f47e7d14 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -444,6 +444,20 @@ impl blockchain::Backend for Blockchain { Ok(self.storage.read().leaves.hashes()) } + fn displaced_leaves_after_finalizing( + &self, + block_number: NumberFor, + ) -> sp_blockchain::Result> { + Ok(self + .storage + .read() + .leaves + .displaced_by_finalize_height(block_number) + .leaves() + .cloned() + .collect::>()) + } + fn children(&self, _parent_hash: Block::Hash) -> sp_blockchain::Result> { unimplemented!() } diff --git a/client/api/src/leaves.rs b/client/api/src/leaves.rs index 2a3b95188e68e..5859290777433 100644 --- a/client/api/src/leaves.rs +++ b/client/api/src/leaves.rs @@ -56,7 +56,7 @@ impl FinalizationDisplaced { } /// Iterate over all displaced leaves. - pub fn leaves(&self) -> impl IntoIterator { + pub fn leaves(&self) -> impl Iterator { self.leaves.values().flatten() } } @@ -145,6 +145,24 @@ where FinalizationDisplaced { leaves: below_boundary } } + /// The same as [`Self::finalize_height`], but it only simulates the operation. + /// + /// This means that no changes are done. + /// + /// Returns the leaves that would be displaced by finalizing the given block. + pub fn displaced_by_finalize_height(&self, number: N) -> FinalizationDisplaced { + let boundary = if number == N::zero() { + return FinalizationDisplaced { leaves: BTreeMap::new() } + } else { + number - N::one() + }; + + let below_boundary = self.storage.range(&Reverse(boundary)..); + FinalizationDisplaced { + leaves: below_boundary.map(|(k, v)| (k.clone(), v.clone())).collect(), + } + } + /// Undo all pending operations. /// /// This returns an `Undo` struct, where any diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 080387c88655c..aa2d824b8ccb9 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -1018,12 +1018,12 @@ fn obsolete_blocks_aux_data_cleanup() { // Create the following test scenario: // - // /-----B3 --- B4 ( < fork2 ) + // /--- --B3 --- B4 ( < fork2 ) // G --- A1 --- A2 --- A3 --- A4 ( < fork1 ) // \-----C4 --- C5 ( < fork3 ) let fork1_hashes = propose_and_import_blocks_wrap(BlockId::Number(0), 4); - let fork2_hashes = propose_and_import_blocks_wrap(BlockId::Number(2), 2); + let fork2_hashes = propose_and_import_blocks_wrap(BlockId::Number(0), 2); let fork3_hashes = propose_and_import_blocks_wrap(BlockId::Number(3), 2); // Check that aux data is present for all but the genesis block. diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 6a8a025f1f45f..e753ab9acba2b 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -627,6 +627,19 @@ impl sc_client_api::blockchain::Backend for BlockchainDb, + ) -> ClientResult> { + Ok(self + .leaves + .read() + .displaced_by_finalize_height(block_number) + .leaves() + .cloned() + .collect::>()) + } + fn children(&self, parent_hash: Block::Hash) -> ClientResult> { children::read_children(&*self.db, columns::META, meta_keys::CHILDREN_PREFIX, parent_hash) } diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 004d4b711e091..dfa392bc96bde 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -899,36 +899,25 @@ where let finalized = route_from_finalized.enacted().iter().map(|elem| elem.hash).collect::>(); - let last_finalized_number = self - .backend - .blockchain() - .number(last_finalized)? - .expect("Previous finalized block expected to be onchain; qed"); - let mut stale_heads = Vec::new(); - for head in self.backend.blockchain().leaves()? { - let route_from_finalized = - sp_blockchain::tree_route(self.backend.blockchain(), block, head)?; - let retracted = route_from_finalized.retracted(); - let pivot = route_from_finalized.common_block(); - // It is not guaranteed that `backend.blockchain().leaves()` doesn't return - // heads that were in a stale state before this finalization and thus already - // included in previous notifications. We want to skip such heads. - // Given the "route" from the currently finalized block to the head under - // analysis, the condition for it to be added to the new stale heads list is: - // `!retracted.is_empty() && last_finalized_number <= pivot.number` - // 1. "route" has some "retractions". - // 2. previously finalized block number is not greater than the "route" pivot: - // - if `last_finalized_number <= pivot.number` then this is a new stale head; - // - else the stale head was already included by some previous finalization. - if !retracted.is_empty() && last_finalized_number <= pivot.number { - stale_heads.push(head); - } - } + let block_number = route_from_finalized + .last() + .expect( + "The block to finalize is always the latest \ + block in the route to the finalized block; qed", + ) + .number; + + // The stale heads are the leaves that will be displaced after the + // block is finalized. + let stale_heads = + self.backend.blockchain().displaced_leaves_after_finalizing(block_number)?; + let header = self .backend .blockchain() .header(BlockId::Hash(block))? - .expect("Finalized block expected to be onchain; qed"); + .expect("Block to finalize expected to be onchain; qed"); + operation.notify_finalized = Some(FinalizeSummary { header, finalized, stale_heads }); } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index c86b23347d417..6aa047c6393da 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1011,12 +1011,16 @@ fn finalizing_diverged_block_should_trigger_reorg() { assert_eq!(client.chain_info().best_hash, b3.hash()); - finality_notification_check(&mut finality_notifications, &[b1.hash()], &[a2.hash()]); + ClientExt::finalize_block(&client, BlockId::Hash(b3.hash()), None).unwrap(); + + finality_notification_check(&mut finality_notifications, &[b1.hash()], &[]); + finality_notification_check(&mut finality_notifications, &[b2.hash(), b3.hash()], &[a2.hash()]); assert!(finality_notifications.try_next().is_err()); } #[test] fn finality_notifications_content() { + sp_tracing::try_init_simple(); let (mut client, _select_chain) = TestClientBuilder::new().build_with_longest_chain(); // -> D3 -> D4 @@ -1110,12 +1114,8 @@ fn finality_notifications_content() { // Import and finalize D4 block_on(client.import_as_final(BlockOrigin::Own, d4.clone())).unwrap(); - finality_notification_check( - &mut finality_notifications, - &[a1.hash(), a2.hash()], - &[c1.hash(), b2.hash()], - ); - finality_notification_check(&mut finality_notifications, &[d3.hash(), d4.hash()], &[a3.hash()]); + finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[c1.hash()]); + finality_notification_check(&mut finality_notifications, &[d3.hash(), d4.hash()], &[b2.hash()]); assert!(finality_notifications.try_next().is_err()); } @@ -1214,7 +1214,7 @@ fn doesnt_import_blocks_that_revert_finality() { // -> C1 // / - // G -> A1 -> A2 + // G -> A1 -> A2 -> A3 // \ // -> B1 -> B2 -> B3 @@ -1294,7 +1294,19 @@ fn doesnt_import_blocks_that_revert_finality() { assert_eq!(import_err.to_string(), expected_err.to_string()); - finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[b2.hash()]); + let a3 = client + .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); + ClientExt::finalize_block(&client, BlockId::Hash(a3.hash()), None).unwrap(); + + finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[]); + + finality_notification_check(&mut finality_notifications, &[a3.hash()], &[b2.hash()]); + assert!(finality_notifications.try_next().is_err()); } diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index 3c6419648388e..84b34105e59b8 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -100,6 +100,14 @@ pub trait Backend: /// Results must be ordered best (longest, highest) chain first. fn leaves(&self) -> Result>; + /// Returns displaced leaves after the given block would be finalized. + /// + /// The returned leaves do not contain the leaves from the same height as `block_number`. + fn displaced_leaves_after_finalizing( + &self, + block_number: NumberFor, + ) -> Result>; + /// Return hashes of all blocks that are children of the block with `parent_hash`. fn children(&self, parent_hash: Block::Hash) -> Result>; diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index c21c82b9fbc23..858dcf6c92e80 100644 --- a/primitives/blockchain/src/header_metadata.rs +++ b/primitives/blockchain/src/header_metadata.rs @@ -201,6 +201,11 @@ impl TreeRoute { pub fn enacted(&self) -> &[HashAndNumber] { &self.route[self.pivot + 1..] } + + /// Returns the last block. + pub fn last(&self) -> Option<&HashAndNumber> { + self.route.last() + } } /// Handles header metadata: hash, number, parent hash, etc. From 32af9fc9f18fc7ffff6bd6af08924b1bb0d3f185 Mon Sep 17 00:00:00 2001 From: Denis Pisarev Date: Tue, 12 Apr 2022 15:53:03 +0200 Subject: [PATCH 0691/1472] CI: rename ambiguous jobs (#11207) --- .github/workflows/pr-custom-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-custom-review.yml b/.github/workflows/pr-custom-review.yml index d113d39067846..322403da03b47 100644 --- a/.github/workflows/pr-custom-review.yml +++ b/.github/workflows/pr-custom-review.yml @@ -1,4 +1,4 @@ -name: Check reviews +name: Assign reviewers on: pull_request: From de8b34c814089e9561cbc1cdb4399bfc91d4cd46 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Wed, 13 Apr 2022 04:43:10 +0800 Subject: [PATCH 0692/1472] Bump soketto to v0.7.1 (#11203) Signed-off-by: koushiro --- Cargo.lock | 35 +++----------------------- bin/node/cli/Cargo.toml | 2 +- bin/node/cli/tests/websocket_server.rs | 4 +-- 3 files changed, 7 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29e4c2c1ad320..3435608ebc7b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -450,12 +450,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - [[package]] name = "base64" version = "0.13.0" @@ -832,12 +826,6 @@ dependencies = [ "iovec", ] -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - [[package]] name = "bytes" version = "1.1.0" @@ -3441,7 +3429,7 @@ dependencies = [ "jsonrpsee-types", "pin-project 1.0.10", "rustls-native-certs 0.6.1", - "soketto 0.7.1", + "soketto", "thiserror", "tokio", "tokio-rustls 0.23.2", @@ -3467,7 +3455,7 @@ dependencies = [ "rustc-hash", "serde", "serde_json", - "soketto 0.7.1", + "soketto", "thiserror", "tokio", "tracing", @@ -4119,7 +4107,7 @@ dependencies = [ "log 0.4.14", "quicksink", "rw-stream-sink", - "soketto 0.7.1", + "soketto", "url 2.2.1", "webpki-roots 0.21.0", ] @@ -4863,7 +4851,7 @@ dependencies = [ "sc-transaction-pool-api", "serde", "serde_json", - "soketto 0.4.2", + "soketto", "sp-api", "sp-authority-discovery", "sp-authorship", @@ -9701,21 +9689,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "soketto" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5c71ed3d54db0a699f4948e1bb3e45b450fa31fe602621dee6680361d569c88" -dependencies = [ - "base64 0.12.3", - "bytes 0.5.6", - "futures 0.3.21", - "httparse", - "log 0.4.14", - "rand 0.7.3", - "sha-1 0.9.4", -] - [[package]] name = "soketto" version = "0.7.1" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index dda6b57d0244b..bb4ec763a3051 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -125,7 +125,7 @@ serde_json = "1.0" regex = "1.5.5" platforms = "2.0" async-std = { version = "1.10.0", features = ["attributes"] } -soketto = "0.4.2" +soketto = "0.7.1" criterion = { version = "0.3.5", features = ["async_tokio"] } tokio = { version = "1.17.0", features = ["macros", "time", "parking_lot"] } wait-timeout = "0.2" diff --git a/bin/node/cli/tests/websocket_server.rs b/bin/node/cli/tests/websocket_server.rs index 6eecfaf6de53f..513497c6cddb5 100644 --- a/bin/node/cli/tests/websocket_server.rs +++ b/bin/node/cli/tests/websocket_server.rs @@ -123,12 +123,12 @@ impl WsServer { let mut server = Server::new(pending_incoming); let websocket_key = match server.receive_request().await { - Ok(req) => req.into_key(), + Ok(req) => req.key(), Err(err) => return Err(Box::new(err) as Box<_>), }; match server - .send_response(&{ Response::Accept { key: &websocket_key, protocol: None } }) + .send_response(&{ Response::Accept { key: websocket_key, protocol: None } }) .await { Ok(()) => {}, From 2b4818aeb3488658ae85a5e64e9b656945553a72 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 13 Apr 2022 13:13:06 +0300 Subject: [PATCH 0693/1472] Expose MMR root through runtime API - use it in BEEFY client (#11183) * beefy-gadget: allow custom runtime api provider * beefy-gadget: use mock runtime api in tests * pallet-mmr: expose mmr root from state through runtime API * beefy-gadget: get mmr root from runtime state * pallet-beefy-mmr: remove MmrRoot from header digests * frame/mmr: move mmr primitives out of frame * frame/mmr: completely move primitives out of frame * address review comments * beefy-mmr: bring back mmr root from header digest * clippy fixes for rustc 1.60 * address review comments --- Cargo.lock | 37 ++- Cargo.toml | 2 +- bin/node/runtime/src/lib.rs | 6 +- client/beefy/Cargo.toml | 1 + client/beefy/src/lib.rs | 22 +- client/beefy/src/metrics.rs | 5 +- client/beefy/src/tests.rs | 250 +++++++++++------- client/beefy/src/worker.rs | 135 +++++----- client/db/src/lib.rs | 1 + frame/beefy-mmr/Cargo.toml | 2 - frame/beefy-mmr/src/lib.rs | 4 +- frame/beefy-mmr/src/tests.rs | 2 +- frame/merkle-mountain-range/Cargo.toml | 5 +- frame/merkle-mountain-range/rpc/Cargo.toml | 3 +- frame/merkle-mountain-range/rpc/src/lib.rs | 6 +- frame/merkle-mountain-range/src/lib.rs | 36 ++- frame/merkle-mountain-range/src/mmr/mod.rs | 4 +- frame/merkle-mountain-range/src/mock.rs | 4 +- frame/merkle-mountain-range/src/tests.rs | 2 +- .../merkle-mountain-range}/Cargo.toml | 19 +- .../merkle-mountain-range}/src/lib.rs | 192 +++++++------- 21 files changed, 403 insertions(+), 335 deletions(-) rename {frame/merkle-mountain-range/primitives => primitives/merkle-mountain-range}/Cargo.toml (68%) rename {frame/merkle-mountain-range/primitives => primitives/merkle-mountain-range}/src/lib.rs (95%) diff --git a/Cargo.lock b/Cargo.lock index 3435608ebc7b8..5731874d8ca81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -502,6 +502,7 @@ dependencies = [ "sp-finality-grandpa", "sp-keyring", "sp-keystore", + "sp-mmr-primitives", "sp-runtime", "sp-tracing", "strum", @@ -5652,7 +5653,6 @@ dependencies = [ "log 0.4.14", "pallet-beefy", "pallet-mmr", - "pallet-mmr-primitives", "pallet-session", "parity-scale-codec", "scale-info", @@ -6081,27 +6081,11 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", - "pallet-mmr-primitives", "parity-scale-codec", "scale-info", "sp-core", "sp-io", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-mmr-primitives" -version = "4.0.0-dev" -dependencies = [ - "frame-support", - "frame-system", - "hex-literal", - "log 0.4.14", - "parity-scale-codec", - "serde", - "sp-api", - "sp-core", + "sp-mmr-primitives", "sp-runtime", "sp-std", ] @@ -6113,13 +6097,13 @@ dependencies = [ "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", - "pallet-mmr-primitives", "parity-scale-codec", "serde", "serde_json", "sp-api", "sp-blockchain", "sp-core", + "sp-mmr-primitives", "sp-runtime", ] @@ -10140,6 +10124,21 @@ dependencies = [ "zstd", ] +[[package]] +name = "sp-mmr-primitives" +version = "4.0.0-dev" +dependencies = [ + "hex-literal", + "log 0.4.14", + "parity-scale-codec", + "serde", + "sp-api", + "sp-core", + "sp-debug-derive", + "sp-runtime", + "sp-std", +] + [[package]] name = "sp-npos-elections" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 576bae6b574b2..45df7258ef253 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,7 +101,6 @@ members = [ "frame/lottery", "frame/membership", "frame/merkle-mountain-range", - "frame/merkle-mountain-range/primitives", "frame/merkle-mountain-range/rpc", "frame/multisig", "frame/nicks", @@ -172,6 +171,7 @@ members = [ "primitives/keyring", "primitives/keystore", "primitives/maybe-compressed-blob", + "primitives/merkle-mountain-range", "primitives/npos-elections", "primitives/npos-elections/fuzzer", "primitives/offchain", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 57584bed39b2c..f422d1ffc45b8 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1261,7 +1261,7 @@ impl pallet_mmr::Config for Runtime { const INDEXING_PREFIX: &'static [u8] = b"mmr"; type Hashing = ::Hashing; type Hash = ::Hash; - type LeafData = frame_system::Pallet; + type LeafData = pallet_mmr::ParentNumberAndHash; type OnNewRoot = (); type WeightInfo = (); } @@ -1804,6 +1804,10 @@ impl_runtime_apis! { let node = mmr::DataOrHash::Data(leaf.into_opaque_leaf()); pallet_mmr::verify_leaf_proof::(root, node, proof) } + + fn mmr_root() -> Result { + Ok(Mmr::mmr_root()) + } } impl sp_session::SessionKeys for Runtime { diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 02be645b3fc08..96248249200af 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -27,6 +27,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-mmr-primitives = { version = "4.0.0-dev", path = "../../primitives/merkle-mountain-range" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 8a6e175f58321..5d8aa5c866c4a 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -27,9 +27,10 @@ use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_consensus::SyncOracle; use sp_keystore::SyncCryptoStorePtr; +use sp_mmr_primitives::MmrApi; use sp_runtime::traits::Block; -use beefy_primitives::BeefyApi; +use beefy_primitives::{BeefyApi, MmrRootHash}; use crate::notification::{BeefyBestBlockSender, BeefySignedCommitmentSender}; @@ -87,7 +88,7 @@ pub fn beefy_peers_set_config( /// of today, Rust does not allow a type alias to be used as a trait bound. Tracking /// issue is . pub trait Client: - BlockchainEvents + HeaderBackend + Finalizer + ProvideRuntimeApi + Send + Sync + BlockchainEvents + HeaderBackend + Finalizer + Send + Sync where B: Block, BE: Backend, @@ -110,18 +111,21 @@ where } /// BEEFY gadget initialization parameters. -pub struct BeefyParams +pub struct BeefyParams where B: Block, BE: Backend, C: Client, - C::Api: BeefyApi, + R: ProvideRuntimeApi, + R::Api: BeefyApi + MmrApi, N: GossipNetwork + Clone + SyncOracle + Send + Sync + 'static, { /// BEEFY client pub client: Arc, /// Client Backend pub backend: Arc, + /// Runtime Api Provider + pub runtime: Arc, /// Local key store pub key_store: Option, /// Gossip network @@ -138,21 +142,22 @@ where pub protocol_name: std::borrow::Cow<'static, str>, } -#[cfg(not(test))] /// Start the BEEFY gadget. /// /// This is a thin shim around running and awaiting a BEEFY worker. -pub async fn start_beefy_gadget(beefy_params: BeefyParams) +pub async fn start_beefy_gadget(beefy_params: BeefyParams) where B: Block, BE: Backend, C: Client, - C::Api: BeefyApi, + R: ProvideRuntimeApi, + R::Api: BeefyApi + MmrApi, N: GossipNetwork + Clone + SyncOracle + Send + Sync + 'static, { let BeefyParams { client, backend, + runtime, key_store, network, signed_commitment_sender, @@ -188,6 +193,7 @@ where let worker_params = worker::WorkerParams { client, backend, + runtime, key_store: key_store.into(), signed_commitment_sender, beefy_best_block_sender, @@ -198,7 +204,7 @@ where sync_oracle, }; - let worker = worker::BeefyWorker::<_, _, _, _>::new(worker_params); + let worker = worker::BeefyWorker::<_, _, _, _, _>::new(worker_params); worker.run().await } diff --git a/client/beefy/src/metrics.rs b/client/beefy/src/metrics.rs index 20fa98e52fdd5..a6d29dbf88abb 100644 --- a/client/beefy/src/metrics.rs +++ b/client/beefy/src/metrics.rs @@ -18,9 +18,7 @@ //! BEEFY Prometheus metrics definition -#[cfg(not(test))] -use prometheus::{register, PrometheusError, Registry}; -use prometheus::{Counter, Gauge, U64}; +use prometheus::{register, Counter, Gauge, PrometheusError, Registry, U64}; /// BEEFY metrics exposed through Prometheus pub(crate) struct Metrics { @@ -39,7 +37,6 @@ pub(crate) struct Metrics { } impl Metrics { - #[cfg(not(test))] pub(crate) fn register(registry: &Registry) -> Result { Ok(Self { beefy_validator_set_id: register( diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 92b5ad91c11e1..e568daba8e112 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -28,18 +28,20 @@ use sc_chain_spec::{ChainSpec, GenericChainSpec}; use sc_client_api::HeaderBackend; use sc_consensus::BoxJustificationImport; use sc_keystore::LocalKeystore; -use sc_network::{config::ProtocolConfig, NetworkService}; -use sc_network_gossip::GossipEngine; +use sc_network::config::ProtocolConfig; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, - PeersFullClient, TestNetFactory, + TestNetFactory, }; use sc_utils::notification::NotificationReceiver; use beefy_primitives::{ - crypto::AuthorityId, ConsensusLog, MmrRootHash, ValidatorSet, BEEFY_ENGINE_ID, + crypto::AuthorityId, BeefyApi, ConsensusLog, MmrRootHash, ValidatorSet, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, }; +use sp_mmr_primitives::{EncodableOpaqueLeaf, Error as MmrError, LeafIndex, MmrApi, Proof}; + +use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; use sp_core::H256; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; @@ -47,19 +49,16 @@ use sp_runtime::{ codec::Encode, generic::BlockId, traits::Header as HeaderT, BuildStorage, DigestItem, Storage, }; -use substrate_test_runtime_client::{runtime::Header, Backend, ClientExt}; +use substrate_test_runtime_client::{runtime::Header, ClientExt}; -use crate::{ - beefy_protocol_name, - keystore::tests::Keyring as BeefyKeyring, - notification::*, - worker::{tests::TestModifiers, BeefyWorker}, -}; +use crate::{beefy_protocol_name, keystore::tests::Keyring as BeefyKeyring, notification::*}; -const BEEFY_PROTOCOL_NAME: &'static str = "/beefy/1"; +pub(crate) const BEEFY_PROTOCOL_NAME: &'static str = "/beefy/1"; +const GOOD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0xbf); +const BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x42); -type BeefyValidatorSet = ValidatorSet; -type BeefyPeer = Peer; +pub(crate) type BeefyValidatorSet = ValidatorSet; +pub(crate) type BeefyPeer = Peer; #[derive(Debug, Serialize, Deserialize)] struct Genesis(std::collections::BTreeMap); @@ -101,27 +100,13 @@ fn beefy_protocol_name() { #[allow(dead_code)] #[derive(Clone)] pub(crate) struct BeefyLinkHalf { - signed_commitment_stream: BeefySignedCommitmentStream, - beefy_best_block_stream: BeefyBestBlockStream, + pub signed_commitment_stream: BeefySignedCommitmentStream, + pub beefy_best_block_stream: BeefyBestBlockStream, } #[derive(Default)] pub(crate) struct PeerData { pub(crate) beefy_link_half: Mutex>, - pub(crate) test_modifiers: Option, -} - -impl PeerData { - pub(crate) fn use_validator_set(&mut self, validator_set: &ValidatorSet) { - if let Some(tm) = self.test_modifiers.as_mut() { - tm.active_validators = validator_set.clone(); - } else { - self.test_modifiers = Some(TestModifiers { - active_validators: validator_set.clone(), - corrupt_mmr_roots: false, - }); - } - } } pub(crate) struct BeefyTestNet { @@ -153,17 +138,19 @@ impl BeefyTestNet { count: usize, session_length: u64, validator_set: &BeefyValidatorSet, + include_mmr_digest: bool, ) { self.peer(0).generate_blocks(count, BlockOrigin::File, |builder| { let mut block = builder.build().unwrap().block; - let block_num = *block.header.number(); - let num_byte = block_num.to_le_bytes().into_iter().next().unwrap(); - let mmr_root = MmrRootHash::repeat_byte(num_byte); - - add_mmr_digest(&mut block.header, mmr_root); + if include_mmr_digest { + let block_num = *block.header.number(); + let num_byte = block_num.to_le_bytes().into_iter().next().unwrap(); + let mmr_root = MmrRootHash::repeat_byte(num_byte); + add_mmr_digest(&mut block.header, mmr_root); + } - if block_num % session_length == 0 { + if *block.header.number() % session_length == 0 { add_auth_change_digest(&mut block.header, validator_set.clone()); } @@ -223,6 +210,79 @@ impl TestNetFactory for BeefyTestNet { } } +macro_rules! create_test_api { + ( $api_name:ident, mmr_root: $mmr_root:expr, $($inits:expr),+ ) => { + pub(crate) mod $api_name { + use super::*; + + #[derive(Clone, Default)] + pub(crate) struct TestApi {} + + // compiler gets confused and warns us about unused inner + #[allow(dead_code)] + pub(crate) struct RuntimeApi { + inner: TestApi, + } + + impl ProvideRuntimeApi for TestApi { + type Api = RuntimeApi; + fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { + RuntimeApi { inner: self.clone() }.into() + } + } + sp_api::mock_impl_runtime_apis! { + impl BeefyApi for RuntimeApi { + fn validator_set() -> Option { + BeefyValidatorSet::new(make_beefy_ids(&[$($inits),+]), 0) + } + } + + impl MmrApi for RuntimeApi { + fn generate_proof(_leaf_index: LeafIndex) + -> Result<(EncodableOpaqueLeaf, Proof), MmrError> { + unimplemented!() + } + + fn verify_proof(_leaf: EncodableOpaqueLeaf, _proof: Proof) + -> Result<(), MmrError> { + unimplemented!() + } + + fn verify_proof_stateless( + _root: MmrRootHash, + _leaf: EncodableOpaqueLeaf, + _proof: Proof + ) -> Result<(), MmrError> { + unimplemented!() + } + + fn mmr_root() -> Result { + Ok($mmr_root) + } + } + } + } + }; +} + +create_test_api!(two_validators, mmr_root: GOOD_MMR_ROOT, BeefyKeyring::Alice, BeefyKeyring::Bob); +create_test_api!( + four_validators, + mmr_root: GOOD_MMR_ROOT, + BeefyKeyring::Alice, + BeefyKeyring::Bob, + BeefyKeyring::Charlie, + BeefyKeyring::Dave +); +create_test_api!( + bad_four_validators, + mmr_root: BAD_MMR_ROOT, + BeefyKeyring::Alice, + BeefyKeyring::Bob, + BeefyKeyring::Charlie, + BeefyKeyring::Dave +); + fn add_mmr_digest(header: &mut Header, mmr_hash: MmrRootHash) { header.digest_mut().push(DigestItem::Consensus( BEEFY_ENGINE_ID, @@ -248,54 +308,43 @@ pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> SyncCryptoStoreP keystore } -pub(crate) fn create_beefy_worker( - peer: &BeefyPeer, - key: &BeefyKeyring, - min_block_delta: u32, -) -> BeefyWorker>> { - let keystore = create_beefy_keystore(*key); - - let (signed_commitment_sender, signed_commitment_stream) = - BeefySignedCommitmentStream::::channel(); - let (beefy_best_block_sender, beefy_best_block_stream) = - BeefyBestBlockStream::::channel(); - - let beefy_link_half = BeefyLinkHalf { signed_commitment_stream, beefy_best_block_stream }; - *peer.data.beefy_link_half.lock() = Some(beefy_link_half); - let test_modifiers = peer.data.test_modifiers.clone().unwrap(); - - let network = peer.network_service().clone(); - let sync_oracle = network.clone(); - let gossip_validator = Arc::new(crate::gossip::GossipValidator::new()); - let gossip_engine = - GossipEngine::new(network, BEEFY_PROTOCOL_NAME, gossip_validator.clone(), None); - let worker_params = crate::worker::WorkerParams { - client: peer.client().as_client(), - backend: peer.client().as_backend(), - key_store: Some(keystore).into(), - signed_commitment_sender, - beefy_best_block_sender, - gossip_engine, - gossip_validator, - min_block_delta, - metrics: None, - sync_oracle, - }; - - BeefyWorker::<_, _, _, _>::new(worker_params, test_modifiers) -} - // Spawns beefy voters. Returns a future to spawn on the runtime. -fn initialize_beefy( +fn initialize_beefy( net: &mut BeefyTestNet, - peers: &[BeefyKeyring], + peers: Vec<(usize, &BeefyKeyring, Arc)>, min_block_delta: u32, -) -> impl Future { +) -> impl Future +where + API: ProvideRuntimeApi + Default + Sync + Send, + API::Api: BeefyApi + MmrApi, +{ let voters = FuturesUnordered::new(); - for (peer_id, key) in peers.iter().enumerate() { - let worker = create_beefy_worker(&net.peers[peer_id], key, min_block_delta); - let gadget = worker.run(); + for (peer_id, key, api) in peers.into_iter() { + let peer = &net.peers[peer_id]; + + let keystore = create_beefy_keystore(*key); + + let (signed_commitment_sender, signed_commitment_stream) = + BeefySignedCommitmentStream::::channel(); + let (beefy_best_block_sender, beefy_best_block_stream) = + BeefyBestBlockStream::::channel(); + let beefy_link_half = BeefyLinkHalf { signed_commitment_stream, beefy_best_block_stream }; + *peer.data.beefy_link_half.lock() = Some(beefy_link_half); + + let beefy_params = crate::BeefyParams { + client: peer.client().as_client(), + backend: peer.client().as_backend(), + runtime: api.clone(), + key_store: Some(keystore), + network: peer.network_service().clone(), + signed_commitment_sender, + beefy_best_block_sender, + min_block_delta, + prometheus_registry: None, + protocol_name: BEEFY_PROTOCOL_NAME.into(), + }; + let gadget = crate::start_beefy_gadget::<_, _, _, _, _>(beefy_params); fn assert_send(_: &T) {} assert_send(&gadget); @@ -443,13 +492,12 @@ fn beefy_finalizing_blocks() { let mut net = BeefyTestNet::new(2, 0); - for i in 0..peers.len() { - net.peer(i).data.use_validator_set(&validator_set); - } - runtime.spawn(initialize_beefy(&mut net, peers, min_block_delta)); + let api = Arc::new(two_validators::TestApi {}); + let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); + runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); // push 42 blocks including `AuthorityChange` digests every 10 blocks. - net.generate_blocks(42, session_len, &validator_set); + net.generate_blocks(42, session_len, &validator_set, true); net.block_until_sync(); let net = Arc::new(Mutex::new(net)); @@ -477,19 +525,18 @@ fn lagging_validators() { sp_tracing::try_init_simple(); let mut runtime = Runtime::new().unwrap(); - let peers = &[BeefyKeyring::Charlie, BeefyKeyring::Dave]; + let peers = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); let session_len = 30; let min_block_delta = 1; let mut net = BeefyTestNet::new(2, 0); - for i in 0..peers.len() { - net.peer(i).data.use_validator_set(&validator_set); - } - runtime.spawn(initialize_beefy(&mut net, peers, min_block_delta)); + let api = Arc::new(two_validators::TestApi {}); + let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); + runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); // push 42 blocks including `AuthorityChange` digests every 30 blocks. - net.generate_blocks(42, session_len, &validator_set); + net.generate_blocks(42, session_len, &validator_set, true); net.block_until_sync(); let net = Arc::new(Mutex::new(net)); @@ -498,7 +545,7 @@ fn lagging_validators() { // diff-power-of-two rule. finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[15], &[1, 9, 13, 14, 15]); - // Charlie finalizes #25, Dave lags behind + // Alice finalizes #25, Bob lags behind let finalize = BlockId::number(25); let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); @@ -507,7 +554,7 @@ fn lagging_validators() { streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); - // Dave catches up and also finalizes #25 + // Bob catches up and also finalizes #25 let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); // expected beefy finalizes block #17 from diff-power-of-two @@ -530,16 +577,23 @@ fn correct_beefy_payload() { let min_block_delta = 2; let mut net = BeefyTestNet::new(4, 0); - for i in 0..peers.len() { - net.peer(i).data.use_validator_set(&validator_set); - } + + // Alice, Bob, Charlie will vote on good payloads + let good_api = Arc::new(four_validators::TestApi {}); + let good_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie] + .iter() + .enumerate() + .map(|(id, key)| (id, key, good_api.clone())) + .collect(); + runtime.spawn(initialize_beefy(&mut net, good_peers, min_block_delta)); // Dave will vote on bad mmr roots - net.peer(3).data.test_modifiers.as_mut().map(|tm| tm.corrupt_mmr_roots = true); - runtime.spawn(initialize_beefy(&mut net, peers, min_block_delta)); + let bad_api = Arc::new(bad_four_validators::TestApi {}); + let bad_peers = vec![(3, &BeefyKeyring::Dave, bad_api)]; + runtime.spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); // push 10 blocks - net.generate_blocks(12, session_len, &validator_set); + net.generate_blocks(12, session_len, &validator_set, false); net.block_until_sync(); let net = Arc::new(Mutex::new(net)); diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 85674c09a278b..128850a5f172f 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -26,9 +26,10 @@ use parking_lot::Mutex; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications}; use sc_network_gossip::GossipEngine; -use sp_api::BlockId; +use sp_api::{BlockId, ProvideRuntimeApi}; use sp_arithmetic::traits::AtLeast32Bit; use sp_consensus::SyncOracle; +use sp_mmr_primitives::MmrApi; use sp_runtime::{ generic::OpaqueDigestItemId, traits::{Block, Header, NumberFor}, @@ -52,12 +53,10 @@ use crate::{ Client, }; -pub(crate) struct WorkerParams -where - B: Block, -{ +pub(crate) struct WorkerParams { pub client: Arc, pub backend: Arc, + pub runtime: Arc, pub key_store: BeefyKeystore, pub signed_commitment_sender: BeefySignedCommitmentSender, pub beefy_best_block_sender: BeefyBestBlockSender, @@ -69,15 +68,10 @@ where } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker -where - B: Block, - BE: Backend, - C: Client, - SO: SyncOracle + Send + Sync + Clone + 'static, -{ +pub(crate) struct BeefyWorker { client: Arc, backend: Arc, + runtime: Arc, key_store: BeefyKeystore, signed_commitment_sender: BeefySignedCommitmentSender, gossip_engine: Arc>>, @@ -99,17 +93,15 @@ where sync_oracle: SO, // keep rustc happy _backend: PhantomData, - #[cfg(test)] - // behavior modifiers used in tests - test_res: tests::TestModifiers, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, C: Client, - C::Api: BeefyApi, + R: ProvideRuntimeApi, + R::Api: BeefyApi + MmrApi, SO: SyncOracle + Send + Sync + Clone + 'static, { /// Return a new BEEFY worker instance. @@ -118,15 +110,11 @@ where /// BEEFY pallet has been deployed on-chain. /// /// The BEEFY pallet is needed in order to keep track of the BEEFY authority set. - pub(crate) fn new( - worker_params: WorkerParams, - #[cfg(test)] - // behavior modifiers used in tests - test_res: tests::TestModifiers, - ) -> Self { + pub(crate) fn new(worker_params: WorkerParams) -> Self { let WorkerParams { client, backend, + runtime, key_store, signed_commitment_sender, beefy_best_block_sender, @@ -144,6 +132,7 @@ where BeefyWorker { client: client.clone(), backend, + runtime, key_store, signed_commitment_sender, gossip_engine: Arc::new(Mutex::new(gossip_engine)), @@ -159,20 +148,9 @@ where beefy_best_block_sender, sync_oracle, _backend: PhantomData, - #[cfg(test)] - test_res, } } -} -impl BeefyWorker -where - B: Block, - BE: Backend, - C: Client, - C::Api: BeefyApi, - SO: SyncOracle + Send + Sync + Clone + 'static, -{ /// Return `Some(number)` if we should be voting on block `number` now, /// return `None` if there is no block we should vote on now. fn current_vote_target(&self) -> Option> { @@ -396,7 +374,7 @@ where }; let target_hash = target_header.hash(); - let mmr_root = if let Some(hash) = self.extract_mmr_root_digest(&target_header) { + let mmr_root = if let Some(hash) = self.get_mmr_root_digest(&target_header) { hash } else { warn!(target: "beefy", "🥩 No MMR root digest found for: {:?}", target_hash); @@ -458,13 +436,12 @@ where } /// Wait for BEEFY runtime pallet to be available. - #[cfg(not(test))] async fn wait_for_runtime_pallet(&mut self) { self.client .finality_notification_stream() .take_while(|notif| { let at = BlockId::hash(notif.header.hash()); - if let Some(active) = self.client.runtime_api().validator_set(&at).ok().flatten() { + if let Some(active) = self.runtime.runtime_api().validator_set(&at).ok().flatten() { if active.id() == GENESIS_AUTHORITY_SET_ID { // When starting from genesis, there is no session boundary digest. // Just initialize `rounds` to Block #1 as BEEFY mandatory block. @@ -488,13 +465,6 @@ where self.finality_notifications = self.client.finality_notification_stream(); } - /// For tests don't use runtime pallet. Start rounds from block #1. - #[cfg(test)] - async fn wait_for_runtime_pallet(&mut self) { - let active = self.test_res.active_validators.clone(); - self.init_session_at(active, 1u32.into()); - } - /// Main loop for BEEFY worker. /// /// Wait for BEEFY runtime pallet to be available, then start the main async loop @@ -550,20 +520,15 @@ where } } - /// Simple wrapper over mmr root extraction. - #[cfg(not(test))] - fn extract_mmr_root_digest(&self, header: &B::Header) -> Option { - find_mmr_root_digest::(header) - } - - /// For tests, have the option to modify mmr root. - #[cfg(test)] - fn extract_mmr_root_digest(&self, header: &B::Header) -> Option { - let mut mmr_root = find_mmr_root_digest::(header); - if self.test_res.corrupt_mmr_roots { - mmr_root.as_mut().map(|hash| *hash ^= MmrRootHash::random()); - } - mmr_root + /// Simple wrapper that gets MMR root from header digests or from client state. + fn get_mmr_root_digest(&self, header: &B::Header) -> Option { + find_mmr_root_digest::(header).or_else(|| { + self.runtime + .runtime_api() + .mmr_root(&BlockId::hash(header.hash())) + .ok() + .and_then(|r| r.ok()) + }) } } @@ -658,11 +623,16 @@ pub(crate) mod tests { use super::*; use crate::{ keystore::tests::Keyring, - tests::{create_beefy_worker, get_beefy_streams, make_beefy_ids, BeefyTestNet}, + notification::{BeefyBestBlockStream, BeefySignedCommitmentStream}, + tests::{ + create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi, + BeefyPeer, BeefyTestNet, BEEFY_PROTOCOL_NAME, + }, }; use futures::{executor::block_on, future::poll_fn, task::Poll}; + use crate::tests::BeefyLinkHalf; use sc_client_api::HeaderBackend; use sc_network::NetworkService; use sc_network_test::{PeersFullClient, TestNetFactory}; @@ -672,10 +642,40 @@ pub(crate) mod tests { Backend, }; - #[derive(Clone)] - pub struct TestModifiers { - pub active_validators: ValidatorSet, - pub corrupt_mmr_roots: bool, + fn create_beefy_worker( + peer: &BeefyPeer, + key: &Keyring, + min_block_delta: u32, + ) -> BeefyWorker>> { + let keystore = create_beefy_keystore(*key); + + let (signed_commitment_sender, signed_commitment_stream) = + BeefySignedCommitmentStream::::channel(); + let (beefy_best_block_sender, beefy_best_block_stream) = + BeefyBestBlockStream::::channel(); + let beefy_link_half = BeefyLinkHalf { signed_commitment_stream, beefy_best_block_stream }; + *peer.data.beefy_link_half.lock() = Some(beefy_link_half); + + let api = Arc::new(TestApi {}); + let network = peer.network_service().clone(); + let sync_oracle = network.clone(); + let gossip_validator = Arc::new(crate::gossip::GossipValidator::new()); + let gossip_engine = + GossipEngine::new(network, BEEFY_PROTOCOL_NAME, gossip_validator.clone(), None); + let worker_params = crate::worker::WorkerParams { + client: peer.client().as_client(), + backend: peer.client().as_backend(), + runtime: api, + key_store: Some(keystore).into(), + signed_commitment_sender, + beefy_best_block_sender, + gossip_engine, + gossip_validator, + min_block_delta, + metrics: None, + sync_oracle, + }; + BeefyWorker::<_, _, _, _, _>::new(worker_params) } #[test] @@ -825,7 +825,6 @@ pub(crate) mod tests { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1, 0); - net.peer(0).data.use_validator_set(&validator_set); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); // rounds not initialized -> should vote: `None` @@ -833,8 +832,9 @@ pub(crate) mod tests { let set_up = |worker: &mut BeefyWorker< Block, - PeersFullClient, Backend, + PeersFullClient, + TestApi, Arc>, >, best_grandpa: u64, @@ -889,7 +889,6 @@ pub(crate) mod tests { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1, 0); - net.peer(0).data.use_validator_set(&validator_set); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); // keystore doesn't contain other keys than validators' @@ -913,7 +912,6 @@ pub(crate) mod tests { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1, 0); - net.peer(0).data.use_validator_set(&validator_set); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); let (mut best_block_streams, _) = get_beefy_streams(&mut net, keys); @@ -939,7 +937,7 @@ pub(crate) mod tests { // generate 2 blocks, try again expect success let (mut best_block_streams, _) = get_beefy_streams(&mut net, keys); let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); - net.generate_blocks(2, 10, &validator_set); + net.generate_blocks(2, 10, &validator_set, false); worker.set_best_beefy_block(2); assert_eq!(worker.best_beefy_block, Some(2)); @@ -961,7 +959,6 @@ pub(crate) mod tests { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1, 0); - net.peer(0).data.use_validator_set(&validator_set); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); assert!(worker.rounds.is_none()); diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index e753ab9acba2b..735058897340e 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -106,6 +106,7 @@ const DEFAULT_CHILD_RATIO: (usize, usize) = (1, 10); pub type DbState = sp_state_machine::TrieBackend>>, HashFor>; +#[cfg(feature = "with-parity-db")] /// Length of a [`DbHash`]. const DB_HASH_LEN: usize = 32; diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 19703fa79863a..a32b1dc6dbd64 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -18,7 +18,6 @@ serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } pallet-mmr = { version = "4.0.0-dev", path = "../merkle-mountain-range", default-features = false } -pallet-mmr-primitives = { version = "4.0.0-dev", path = "../merkle-mountain-range/primitives", default-features = false } pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } @@ -46,7 +45,6 @@ std = [ "k256/std", "log/std", "pallet-beefy/std", - "pallet-mmr-primitives/std", "pallet-mmr/std", "pallet-session/std", "serde", diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 9ee7bd770f64c..640ebeb7d49cc 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -37,7 +37,7 @@ use sp_runtime::traits::{Convert, Hash, Member}; use sp_std::prelude::*; use beefy_primitives::mmr::{BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}; -use pallet_mmr::primitives::LeafDataProvider; +use pallet_mmr::{LeafDataProvider, ParentNumberAndHash}; use frame_support::traits::Get; @@ -150,7 +150,7 @@ where fn leaf_data() -> Self::LeafData { MmrLeaf { version: T::LeafVersion::get(), - parent_number_and_hash: frame_system::Pallet::::leaf_data(), + parent_number_and_hash: ParentNumberAndHash::::leaf_data(), leaf_extra: T::BeefyDataProvider::extra_data(), beefy_next_authority_set: Pallet::::update_beefy_next_authority_set(), } diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index fd383adb1d4a2..37f571cd842ee 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -49,7 +49,7 @@ fn offchain_key(pos: usize) -> Vec { } fn read_mmr_leaf(ext: &mut TestExternalities, index: usize) -> MmrLeaf { - type Node = pallet_mmr_primitives::DataOrHash; + type Node = pallet_mmr::primitives::DataOrHash; ext.persist_offchain_overlay(); let offchain_db = ext.offchain_db(); offchain_db diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 796ab98dc2c32..8b67174e8385d 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -18,6 +18,7 @@ mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, ver sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/merkle-mountain-range" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -25,8 +26,6 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "./primitives" } - [dev-dependencies] env_logger = "0.9" hex-literal = "0.3" @@ -39,12 +38,12 @@ std = [ "mmr-lib/std", "sp-core/std", "sp-io/std", + "sp-mmr-primitives/std", "sp-runtime/std", "sp-std/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", - "pallet-mmr-primitives/std", ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 9ac26c2ed54b2..94c895ea91517 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -22,9 +22,8 @@ serde = { version = "1.0.136", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/merkle-mountain-range" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } - [dev-dependencies] serde_json = "1.0.79" diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index bf3eb3b694e39..99359bfea8eb6 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -26,13 +26,13 @@ use jsonrpc_core::{Error, ErrorCode, Result}; use jsonrpc_derive::rpc; use serde::{Deserialize, Serialize}; -use pallet_mmr_primitives::{Error as MmrError, Proof}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::Bytes; +use sp_mmr_primitives::{Error as MmrError, LeafIndex, Proof}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; -pub use pallet_mmr_primitives::{LeafIndex, MmrApi as MmrRuntimeApi}; +pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; /// Retrieved MMR leaf and its proof. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] @@ -42,7 +42,7 @@ pub struct LeafProof { pub block_hash: BlockHash, /// SCALE-encoded leaf data. pub leaf: Bytes, - /// SCALE-encoded proof data. See [pallet_mmr_primitives::Proof]. + /// SCALE-encoded proof data. See [sp_mmr_primitives::Proof]. pub proof: Bytes, } diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index f904428e02048..855eb0a7436dc 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -58,7 +58,7 @@ use codec::Encode; use frame_support::weights::Weight; -use sp_runtime::traits; +use sp_runtime::traits::{self, One, Saturating}; #[cfg(any(feature = "runtime-benchmarks", test))] mod benchmarking; @@ -70,7 +70,30 @@ mod mock; mod tests; pub use pallet::*; -pub use pallet_mmr_primitives::{self as primitives, NodeIndex}; +pub use sp_mmr_primitives::{self as primitives, Error, LeafDataProvider, LeafIndex, NodeIndex}; + +/// The most common use case for MMRs is to store historical block hashes, +/// so that any point in time in the future we can receive a proof about some past +/// blocks without using excessive on-chain storage. +/// +/// Hence we implement the [LeafDataProvider] for [ParentNumberAndHash] which is a +/// crate-local wrapper over [frame_system::Pallet]. Since the current block hash +/// is not available (since the block is not finished yet), +/// we use the `parent_hash` here along with parent block number. +pub struct ParentNumberAndHash { + _phanthom: sp_std::marker::PhantomData, +} + +impl LeafDataProvider for ParentNumberAndHash { + type LeafData = (::BlockNumber, ::Hash); + + fn leaf_data() -> Self::LeafData { + ( + frame_system::Pallet::::block_number().saturating_sub(One::one()), + frame_system::Pallet::::parent_hash(), + ) + } +} pub trait WeightInfo { fn on_initialize(peaks: NodeIndex) -> Weight; @@ -161,7 +184,7 @@ pub mod pallet { /// Current size of the MMR (number of leaves). #[pallet::storage] #[pallet::getter(fn mmr_leaves)] - pub type NumberOfLeaves = StorageValue<_, NodeIndex, ValueQuery>; + pub type NumberOfLeaves = StorageValue<_, LeafIndex, ValueQuery>; /// Hashes of the nodes in the MMR. /// @@ -240,7 +263,7 @@ impl, I: 'static> Pallet { /// all the leaves to be present. /// It may return an error or panic if used incorrectly. pub fn generate_proof( - leaf_index: NodeIndex, + leaf_index: LeafIndex, ) -> Result<(LeafOf, primitives::Proof<>::Hash>), primitives::Error> { let mmr: ModuleMmr = mmr::Mmr::new(Self::mmr_leaves()); mmr.generate_proof(leaf_index) @@ -272,4 +295,9 @@ impl, I: 'static> Pallet { Err(primitives::Error::Verify.log_debug("The proof is incorrect.")) } } + + /// Return the on-chain MMR root hash. + pub fn mmr_root() -> >::Hash { + Self::mmr_root_hash() + } } diff --git a/frame/merkle-mountain-range/src/mmr/mod.rs b/frame/merkle-mountain-range/src/mmr/mod.rs index 1a729b08b966f..1cb4e8535b991 100644 --- a/frame/merkle-mountain-range/src/mmr/mod.rs +++ b/frame/merkle-mountain-range/src/mmr/mod.rs @@ -19,7 +19,7 @@ mod mmr; pub mod storage; pub mod utils; -use crate::primitives::FullLeaf; +use sp_mmr_primitives::{DataOrHash, FullLeaf}; use sp_runtime::traits; pub use self::mmr::{verify_leaf_proof, Mmr}; @@ -28,7 +28,7 @@ pub use self::mmr::{verify_leaf_proof, Mmr}; pub type NodeOf = Node<>::Hashing, L>; /// A node stored in the MMR. -pub type Node = crate::primitives::DataOrHash; +pub type Node = DataOrHash; /// Default Merging & Hashing behavior for MMR. pub struct Hasher(sp_std::marker::PhantomData<(H, L)>); diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index 56d3c9c0d77d8..b2b6821fcd054 100644 --- a/frame/merkle-mountain-range/src/mock.rs +++ b/frame/merkle-mountain-range/src/mock.rs @@ -20,8 +20,8 @@ use crate::*; use codec::{Decode, Encode}; use frame_support::traits::{ConstU32, ConstU64}; -use pallet_mmr_primitives::{Compact, LeafDataProvider}; use sp_core::H256; +use sp_mmr_primitives::{Compact, LeafDataProvider}; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup, Keccak256}, @@ -74,7 +74,7 @@ impl Config for Test { type Hashing = Keccak256; type Hash = H256; - type LeafData = Compact, LeafData)>; + type LeafData = Compact, LeafData)>; type OnNewRoot = (); type WeightInfo = (); } diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 576a7ace8f1c0..70d1395aa94d5 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -19,11 +19,11 @@ use crate::{mmr::utils, mock::*, *}; use frame_support::traits::OnInitialize; use mmr_lib::helper; -use pallet_mmr_primitives::{Compact, Proof}; use sp_core::{ offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt}, H256, }; +use sp_mmr_primitives::{Compact, Proof}; pub(crate) fn new_test_ext() -> sp_io::TestExternalities { frame_system::GenesisConfig::default().build_storage::().unwrap().into() diff --git a/frame/merkle-mountain-range/primitives/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml similarity index 68% rename from frame/merkle-mountain-range/primitives/Cargo.toml rename to primitives/merkle-mountain-range/Cargo.toml index 3ce2caa7762c0..ddb820f9e6cc4 100644 --- a/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "pallet-mmr-primitives" +name = "sp-mmr-primitives" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" -description = "FRAME Merkle Mountain Range primitives." +description = "Merkle Mountain Range primitives." [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -16,13 +16,11 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = log = { version = "0.4.14", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } -sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } - -frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] hex-literal = "0.3" @@ -35,8 +33,7 @@ std = [ "serde", "sp-api/std", "sp-core/std", + "sp-debug-derive/std", "sp-runtime/std", "sp-std/std", - "frame-support/std", - "frame-system/std", ] diff --git a/frame/merkle-mountain-range/primitives/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs similarity index 95% rename from frame/merkle-mountain-range/primitives/src/lib.rs rename to primitives/merkle-mountain-range/src/lib.rs index cc78dfefefe60..a27536b8d35b7 100644 --- a/frame/merkle-mountain-range/primitives/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -20,8 +20,8 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] -use frame_support::RuntimeDebug; -use sp_runtime::traits::{self, One, Saturating}; +use sp_debug_derive::RuntimeDebug; +use sp_runtime::traits; use sp_std::fmt; #[cfg(not(feature = "std"))] use sp_std::prelude::Vec; @@ -57,21 +57,6 @@ impl LeafDataProvider for () { } } -/// The most common use case for MMRs is to store historical block hashes, -/// so that any point in time in the future we can receive a proof about some past -/// blocks without using excessive on-chain storage. -/// -/// Hence we implement the [LeafDataProvider] for [frame_system::Pallet]. Since the -/// current block hash is not available (since the block is not finished yet), -/// we use the `parent_hash` here along with parent block number. -impl LeafDataProvider for frame_system::Pallet { - type LeafData = (::BlockNumber, ::Hash); - - fn leaf_data() -> Self::LeafData { - (Self::block_number().saturating_sub(One::one()), Self::parent_hash()) - } -} - /// New MMR root notification hook. pub trait OnNewRoot { /// Function called by the pallet in case new MMR root has been computed. @@ -83,6 +68,17 @@ impl OnNewRoot for () { fn on_new_root(_root: &Hash) {} } +/// A MMR proof data for one of the leaves. +#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq)] +pub struct Proof { + /// The index of the leaf the proof is for. + pub leaf_index: LeafIndex, + /// Number of leaves in MMR, when the proof was generated. + pub leaf_count: NodeIndex, + /// Proof elements (hashes of siblings of inner nodes on the path to the leaf). + pub items: Vec, +} + /// A full leaf content stored in the offchain-db. pub trait FullLeaf: Clone + PartialEq + fmt::Debug { /// Encode the leaf either in it's full or compact form. @@ -97,6 +93,80 @@ impl FullLeaf } } +/// A helper type to allow using arbitrary SCALE-encoded leaf data in the RuntimeApi. +/// +/// The point is to be able to verify MMR proofs from external MMRs, where we don't +/// know the exact leaf type, but it's enough for us to have it SCALE-encoded. +/// +/// Note the leaf type should be encoded in its compact form when passed through this type. +/// See [FullLeaf] documentation for details. +/// +/// This type does not implement SCALE encoding/decoding on purpose to avoid confusion, +/// it would have to be SCALE-compatible with the concrete leaf type, but due to SCALE limitations +/// it's not possible to know how many bytes the encoding of concrete leaf type uses. +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[derive(RuntimeDebug, Clone, PartialEq)] +pub struct OpaqueLeaf( + /// Raw bytes of the leaf type encoded in its compact form. + /// + /// NOTE it DOES NOT include length prefix (like `Vec` encoding would). + #[cfg_attr(feature = "std", serde(with = "sp_core::bytes"))] + pub Vec, +); + +impl OpaqueLeaf { + /// Convert a concrete MMR leaf into an opaque type. + pub fn from_leaf(leaf: &T) -> Self { + let encoded_leaf = leaf.using_encoded(|d| d.to_vec(), true); + OpaqueLeaf::from_encoded_leaf(encoded_leaf) + } + + /// Create a `OpaqueLeaf` given raw bytes of compact-encoded leaf. + pub fn from_encoded_leaf(encoded_leaf: Vec) -> Self { + OpaqueLeaf(encoded_leaf) + } + + /// Attempt to decode the leaf into expected concrete type. + pub fn try_decode(&self) -> Option { + codec::Decode::decode(&mut &*self.0).ok() + } +} + +impl FullLeaf for OpaqueLeaf { + fn using_encoded R>(&self, f: F, _compact: bool) -> R { + f(&self.0) + } +} + +/// A type-safe wrapper for the concrete leaf type. +/// +/// This structure serves merely to avoid passing raw `Vec` around. +/// It must be `Vec`-encoding compatible. +/// +/// It is different from [`OpaqueLeaf`], because it does implement `Codec` +/// and the encoding has to match raw `Vec` encoding. +#[derive(codec::Encode, codec::Decode, RuntimeDebug, PartialEq, Eq)] +pub struct EncodableOpaqueLeaf(pub Vec); + +impl EncodableOpaqueLeaf { + /// Convert a concrete leaf into encodable opaque version. + pub fn from_leaf(leaf: &T) -> Self { + let opaque = OpaqueLeaf::from_leaf(leaf); + Self::from_opaque_leaf(opaque) + } + + /// Given an opaque leaf, make it encodable. + pub fn from_opaque_leaf(opaque: OpaqueLeaf) -> Self { + Self(opaque.0) + } + + /// Try to convert into a [OpaqueLeaf]. + pub fn into_opaque_leaf(self) -> OpaqueLeaf { + // wrap into `OpaqueLeaf` type + OpaqueLeaf::from_encoded_leaf(self.0) + } +} + /// An element representing either full data or it's hash. /// /// See [Compact] to see how it may be used in practice to reduce the size @@ -281,17 +351,6 @@ impl_leaf_data_for_tuple!(A:0, B:1, C:2); impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3); impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3, E:4); -/// A MMR proof data for one of the leaves. -#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq)] -pub struct Proof { - /// The index of the leaf the proof is for. - pub leaf_index: LeafIndex, - /// Number of leaves in MMR, when the proof was generated. - pub leaf_count: NodeIndex, - /// Proof elements (hashes of siblings of inner nodes on the path to the leaf). - pub items: Vec, -} - /// Merkle Mountain Range operation error. #[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] pub enum Error { @@ -334,80 +393,6 @@ impl Error { } } -/// A helper type to allow using arbitrary SCALE-encoded leaf data in the RuntimeApi. -/// -/// The point is to be able to verify MMR proofs from external MMRs, where we don't -/// know the exact leaf type, but it's enough for us to have it SCALE-encoded. -/// -/// Note the leaf type should be encoded in its compact form when passed through this type. -/// See [FullLeaf] documentation for details. -/// -/// This type does not implement SCALE encoding/decoding on purpose to avoid confusion, -/// it would have to be SCALE-compatible with the concrete leaf type, but due to SCALE limitations -/// it's not possible to know how many bytes the encoding of concrete leaf type uses. -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[derive(RuntimeDebug, Clone, PartialEq)] -pub struct OpaqueLeaf( - /// Raw bytes of the leaf type encoded in its compact form. - /// - /// NOTE it DOES NOT include length prefix (like `Vec` encoding would). - #[cfg_attr(feature = "std", serde(with = "sp_core::bytes"))] - pub Vec, -); - -impl OpaqueLeaf { - /// Convert a concrete MMR leaf into an opaque type. - pub fn from_leaf(leaf: &T) -> Self { - let encoded_leaf = leaf.using_encoded(|d| d.to_vec(), true); - OpaqueLeaf::from_encoded_leaf(encoded_leaf) - } - - /// Create a `OpaqueLeaf` given raw bytes of compact-encoded leaf. - pub fn from_encoded_leaf(encoded_leaf: Vec) -> Self { - OpaqueLeaf(encoded_leaf) - } - - /// Attempt to decode the leaf into expected concrete type. - pub fn try_decode(&self) -> Option { - codec::Decode::decode(&mut &*self.0).ok() - } -} - -impl FullLeaf for OpaqueLeaf { - fn using_encoded R>(&self, f: F, _compact: bool) -> R { - f(&self.0) - } -} - -/// A type-safe wrapper for the concrete leaf type. -/// -/// This structure serves merely to avoid passing raw `Vec` around. -/// It must be `Vec`-encoding compatible. -/// -/// It is different from [`OpaqueLeaf`], because it does implement `Codec` -/// and the encoding has to match raw `Vec` encoding. -#[derive(codec::Encode, codec::Decode, RuntimeDebug, PartialEq, Eq)] -pub struct EncodableOpaqueLeaf(pub Vec); - -impl EncodableOpaqueLeaf { - /// Convert a concrete leaf into encodable opaque version. - pub fn from_leaf(leaf: &T) -> Self { - let opaque = OpaqueLeaf::from_leaf(leaf); - Self::from_opaque_leaf(opaque) - } - - /// Given an opaque leaf, make it encodable. - pub fn from_opaque_leaf(opaque: OpaqueLeaf) -> Self { - Self(opaque.0) - } - - /// Try to convert into a [OpaqueLeaf]. - pub fn into_opaque_leaf(self) -> OpaqueLeaf { - // wrap into `OpaqueLeaf` type - OpaqueLeaf::from_encoded_leaf(self.0) - } -} - sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. pub trait MmrApi { @@ -429,6 +414,9 @@ sp_api::decl_runtime_apis! { /// The leaf data is expected to be encoded in it's compact form. fn verify_proof_stateless(root: Hash, leaf: EncodableOpaqueLeaf, proof: Proof) -> Result<(), Error>; + + /// Return the on-chain MMR root hash. + fn mmr_root() -> Result; } } From 32510e13afa84a2fa917a94e5d7e18d480a34a22 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 13 Apr 2022 13:55:14 +0200 Subject: [PATCH 0694/1472] Fix WASM block producer panic (#11206) * Box events Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * Revert "Box events" This reverts commit 9fb1887cd23eb272844d63640b0b2d9ba3e549a1. * Revert "Fix tests" This reverts commit 981c50f23a7c514c9527299734bc6bc5b77a817f. * Use simpler approach Signed-off-by: Oliver Tale-Yazdi * Update doc Signed-off-by: Oliver Tale-Yazdi --- frame/system/src/lib.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 9b30e7b452276..0eefc23a6b5d6 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -591,11 +591,14 @@ pub mod pallet { /// Events deposited for the current block. /// - /// NOTE: This storage item is explicitly unbounded since it is never intended to be read - /// from within the runtime. + /// NOTE: The item is unbound and should therefore never be read on chain. + /// It could otherwise inflate the PoV size of a block. + /// + /// Events have a large in-memory size. Box the events to not go out-of-memory + /// just in case someone still reads them from within the runtime. #[pallet::storage] pub(super) type Events = - StorageValue<_, Vec>, ValueQuery>; + StorageValue<_, Vec>>, ValueQuery>; /// The number of events in the `Events` list. #[pallet::storage] @@ -1213,7 +1216,7 @@ impl Pallet { old_event_count }; - Events::::append(&event); + Events::::append(event); for topic in topics { >::append(topic, &(block_number, event_idx)); @@ -1380,14 +1383,16 @@ impl Pallet { /// items for any behavior like this. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] pub fn events() -> Vec> { - Self::read_events_no_consensus() + // Dereferencing the events here is fine since we are not in the + // memory-restricted runtime. + Self::read_events_no_consensus().into_iter().map(|e| *e).collect() } /// Get the current events deposited by the runtime. /// /// Should only be called if you know what you are doing and outside of the runtime block /// execution else it can have a large impact on the PoV size of a block. - pub fn read_events_no_consensus() -> Vec> { + pub fn read_events_no_consensus() -> Vec>> { Events::::get() } From 1f4cd993939fbb35d4ff87f6810dcf766105afd6 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 13 Apr 2022 14:22:25 +0200 Subject: [PATCH 0695/1472] [ci] fix publish-docker-substrate job (#11218) --- .gitlab-ci.yml | 48 ++++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 029c486365088..62684ffebd987 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,6 +41,13 @@ variables: &default-vars CI_IMAGE: "paritytech/ci-linux:production" default: + retry: + max: 2 + when: + - runner_system_failure + - unknown_failure + - api_failure + interruptible: true cache: {} .collect-artifacts: &collect-artifacts @@ -60,13 +67,6 @@ default: - artifacts/ .kubernetes-env: &kubernetes-env - retry: - max: 2 - when: - - runner_system_failure - - unknown_failure - - api_failure - interruptible: true tags: - kubernetes-parity-build @@ -81,13 +81,6 @@ default: image: "${CI_IMAGE}" before_script: - *rust-info-script - retry: - max: 2 - when: - - runner_system_failure - - unknown_failure - - api_failure - interruptible: true tags: - linux-docker @@ -170,21 +163,6 @@ default: | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json' - sccache -s -.build-linux-substrate-script: &build-linux-substrate-script - - WASM_BUILD_NO_COLOR=1 time cargo build --release --verbose - - mv ./target/release/substrate ./artifacts/substrate/. - - echo -n "Substrate version = " - - if [ "${CI_COMMIT_TAG}" ]; then - echo "${CI_COMMIT_TAG}" | tee ./artifacts/substrate/VERSION; - else - ./artifacts/substrate/substrate --version | - sed -n -E 's/^substrate ([0-9.]+.*-[0-9a-f]{7,13})-.*$/\1/p' | - tee ./artifacts/substrate/VERSION; - fi - - sha256sum ./artifacts/substrate/substrate | tee ./artifacts/substrate/substrate.sha256 - - cp -r ./scripts/ci/docker/substrate.Dockerfile ./artifacts/substrate/ - - sccache -s - #### stage: .pre @@ -525,7 +503,17 @@ build-linux-substrate: before_script: - mkdir -p ./artifacts/substrate/ script: - - *build-linux-substrate-script + - WASM_BUILD_NO_COLOR=1 time cargo build --release --verbose + - mv ./target/release/substrate ./artifacts/substrate/. + - echo -n "Substrate version = " + - if [ "${CI_COMMIT_TAG}" ]; then + echo "${CI_COMMIT_TAG}" | tee ./artifacts/substrate/VERSION; + else + ./artifacts/substrate/substrate --version | + cut -d ' ' -f 2 | tee ./artifacts/substrate/VERSION; + fi + - sha256sum ./artifacts/substrate/substrate | tee ./artifacts/substrate/substrate.sha256 + - cp -r ./scripts/ci/docker/substrate.Dockerfile ./artifacts/substrate/ - printf '\n# building node-template\n\n' - ./scripts/ci/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz From 8fb46c34832657562870f36ee4b816c1f6e55c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 13 Apr 2022 16:53:35 +0200 Subject: [PATCH 0696/1472] Document the chain spec format (#11208) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Document the chain spec format * Update client/chain-spec/src/lib.rs Co-authored-by: Pierre Krieger * Update client/chain-spec/src/lib.rs Co-authored-by: Pierre Krieger * Apply suggestions from code review Co-authored-by: Sacha Lansky * Update client/chain-spec/src/lib.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Update client/chain-spec/src/lib.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Mention extensions Co-authored-by: Pierre Krieger Co-authored-by: Sacha Lansky Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- client/chain-spec/src/lib.rs | 90 +++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/client/chain-spec/src/lib.rs b/client/chain-spec/src/lib.rs index eb72592b54a99..73d3e1af15492 100644 --- a/client/chain-spec/src/lib.rs +++ b/client/chain-spec/src/lib.rs @@ -53,19 +53,19 @@ //! //! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)] //! pub struct ClientParams { -//! max_block_size: usize, -//! max_extrinsic_size: usize, +//! max_block_size: usize, +//! max_extrinsic_size: usize, //! } //! //! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)] //! pub struct PoolParams { -//! max_transaction_size: usize, +//! max_transaction_size: usize, //! } //! //! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup, ChainSpecExtension)] //! pub struct Extension { -//! pub client: ClientParams, -//! pub pool: PoolParams, +//! pub client: ClientParams, +//! pub pool: PoolParams, //! } //! //! pub type BlockNumber = u64; @@ -88,24 +88,92 @@ //! //! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)] //! pub struct ClientParams { -//! max_block_size: usize, -//! max_extrinsic_size: usize, +//! max_block_size: usize, +//! max_extrinsic_size: usize, //! } //! //! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)] //! pub struct PoolParams { -//! max_transaction_size: usize, +//! max_transaction_size: usize, //! } //! //! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecExtension)] //! pub struct Extension { -//! pub client: ClientParams, -//! #[forks] -//! pub pool: Forks, +//! pub client: ClientParams, +//! #[forks] +//! pub pool: Forks, //! } //! //! pub type MyChainSpec = GenericChainSpec; //! ``` +//! +//! # Substrate chain specification format +//! +//! The Substrate chain specification is a `json` file that describes the basics of a chain. Most +//! importantly it lays out the genesis storage which leads to the genesis hash. The default +//! Substrate chain specification format is the following: +//! +//! ```json +//! // The human readable name of the chain. +//! "name": "Flaming Fir", +//! // The id of the chain. +//! "id": "flamingfir9", +//! // The chain type of this chain. +//! // Possible values are `Live`, `Development`, `Local`. +//! "chainType": "Live", +//! // A list of multi addresses that belong to boot nodes of the chain. +//! "bootNodes": [ +//! "/dns/0.flamingfir.paritytech.net/tcp/30333/p2p/12D3KooWLK2gMLhWsYJzjW3q35zAs9FDDVqfqVfVuskiGZGRSMvR", +//! ], +//! // Optional list of "multi address, verbosity" of telemetry endpoints. +//! // The verbosity goes from `0` to `9`. With `0` being the mode with the lowest verbosity. +//! "telemetryEndpoints": [ +//! [ +//! "/dns/telemetry.polkadot.io/tcp/443/x-parity-wss/%2Fsubmit%2F", +//! 0 +//! ] +//! ], +//! // Optional networking protocol id that identifies the chain. +//! "protocolId": "fir9", +//! // Optional fork id. Should most likely be left empty. +//! // Can be used to signal a fork on the network level when two chains have the +//! // same genesis hash. +//! "forkId": "random_fork", +//! // Custom properties. +//! "properties": { +//! "tokenDecimals": 15, +//! "tokenSymbol": "FIR" +//! }, +//! // Deprecated field. Should be ignored. +//! "consensusEngine": null, +//! // The genesis declaration of the chain. +//! // +//! // `runtime`, `raw`, `stateRootHash` denote the type of the genesis declaration. +//! // +//! // These declarations are in the following formats: +//! // - `runtime` is a `json` object that can be parsed by a compatible `GenesisConfig`. This +//! // `GenesisConfig` is declared by a runtime and opaque to the node. +//! // - `raw` is a `json` object with two fields `top` and `children_default`. Each of these +//! // fields is a map of `key => value`. These key/value pairs represent the genesis storage. +//! // - `stateRootHash` is a single hex encoded hash that represents the genesis hash. The hash +//! // type depends on the hash used by the chain. +//! // +//! "genesis": { "runtime": {} }, +//! /// Optional map of `block_number` to `wasm_code`. +//! /// +//! /// The given `wasm_code` will be used to substitute the on-chain wasm code starting with the +//! /// given block number until the `spec_version` on-chain changes. The given `wasm_code` should +//! /// be as close as possible to the on-chain wasm code. A substitute should be used to fix a bug +//! /// that can not be fixed with a runtime upgrade, if for example the runtime is constantly +//! /// panicking. Introducing new runtime apis isn't supported, because the node +//! /// will read the runtime version from the on-chain wasm code. Use this functionality only when +//! /// there is no other way around it and only patch the problematic bug, the rest should be done +//! /// with a on-chain runtime upgrade. +//! "codeSubstitutes": [], +//! ``` +//! +//! The chain spec can be extended with other fields that are opaque to the default chain spec. +//! Specific node implementations will need to be able to deserialize these extensions. mod chain_spec; mod extension; From aee9383c359616494930d764b9b727e1bd498937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 13 Apr 2022 17:01:36 +0200 Subject: [PATCH 0697/1472] authority-discovery: Fix flaky test (#11219) It can happen that `+ 1` overflows `p.signature[1]` ;D (I have seen this in the CI). --- client/authority-discovery/src/worker/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index 904c674d269bc..a1a699bc30dd2 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -625,7 +625,7 @@ fn reject_address_with_invalid_peer_signature() { )); // tamper with the signature let mut record = schema::SignedAuthorityRecord::decode(kv_pairs[0].1.as_slice()).unwrap(); - record.peer_signature.as_mut().map(|p| p.signature[1] += 1); + record.peer_signature.as_mut().map(|p| p.signature[1] = !p.signature[1]); record.encode(&mut kv_pairs[0].1).unwrap(); let cached_remote_addresses = tester.process_value_found(false, kv_pairs); From 9b1cd4bb10185d48cfc6b43bd5716ea6347c7b0a Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Thu, 14 Apr 2022 17:18:54 +0800 Subject: [PATCH 0698/1472] Make the generic of CliConfiguration explicit (#11223) Othewise the compiler will complain if someone passes something that implements `CliConfiguration` but `DVC` is not the default `()`. --- client/cli/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index 849a2d2cceb1f..244f6e167f9d5 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -196,7 +196,10 @@ pub trait SubstrateCli: Sized { /// Create a runner for the command provided in argument. This will create a Configuration and /// a tokio runtime - fn create_runner(&self, command: &T) -> error::Result> { + fn create_runner, DVC: DefaultConfigurationValues>( + &self, + command: &T, + ) -> error::Result> { let tokio_runtime = build_runtime()?; let config = command.create_configuration(self, tokio_runtime.handle().clone())?; From a0fc2ecd43e3c216925b8484381851981b426a68 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Thu, 14 Apr 2022 16:07:36 +0300 Subject: [PATCH 0699/1472] Update wasmtime to 0.35.3 (#11058) * Update wasmtime to 0.35.2 and default `zstd` features in all crates * Update wasmtime to 0.35.3 --- Cargo.lock | 163 +++++++++++--------- client/executor/wasmtime/Cargo.toml | 2 +- frame/state-trie-migration/Cargo.toml | 2 +- primitives/maybe-compressed-blob/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 7 files changed, 93 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5731874d8ca81..440d549af1a35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1159,11 +1159,11 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.80.0" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9516ba6b2ba47b4cbf63b713f75b432fafa0a0e0464ec8381ec76e6efe931ab3" +checksum = "38faa2a16616c8e78a18d37b4726b98bfd2de192f2fdc8a39ddf568a408a0f75" dependencies = [ - "cranelift-entity 0.80.0", + "cranelift-entity 0.82.3", ] [[package]] @@ -1185,17 +1185,17 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.80.0" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489e5d0081f7edff6be12d71282a8bf387b5df64d5592454b75d662397f2d642" +checksum = "26f192472a3ba23860afd07d2b0217dc628f21fcc72617aa1336d98e1671f33b" dependencies = [ - "cranelift-bforest 0.80.0", - "cranelift-codegen-meta 0.80.0", - "cranelift-codegen-shared 0.80.0", - "cranelift-entity 0.80.0", + "cranelift-bforest 0.82.3", + "cranelift-codegen-meta 0.82.3", + "cranelift-codegen-shared 0.82.3", + "cranelift-entity 0.82.3", "gimli 0.26.1", "log 0.4.14", - "regalloc 0.0.33", + "regalloc 0.0.34", "smallvec 1.8.0", "target-lexicon", ] @@ -1212,11 +1212,11 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.80.0" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36ee1140371bb0f69100e734b30400157a4adf7b86148dee8b0a438763ead48" +checksum = "0f32ddb89e9b89d3d9b36a5b7d7ea3261c98235a76ac95ba46826b8ec40b1a24" dependencies = [ - "cranelift-codegen-shared 0.80.0", + "cranelift-codegen-shared 0.82.3", ] [[package]] @@ -1227,9 +1227,9 @@ checksum = "9dabb5fe66e04d4652e434195b45ae65b5c8172d520247b8f66d8df42b2b45dc" [[package]] name = "cranelift-codegen-shared" -version = "0.80.0" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "981da52d8f746af1feb96290c83977ff8d41071a7499e991d8abae0d4869f564" +checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc" [[package]] name = "cranelift-entity" @@ -1239,9 +1239,9 @@ checksum = "3329733e4d4b8e91c809efcaa4faee80bf66f20164e3dd16d707346bd3494799" [[package]] name = "cranelift-entity" -version = "0.80.0" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2906740053dd3bcf95ce53df0fd9b5649c68ae4bd9adada92b406f059eae461" +checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf" dependencies = [ "serde", ] @@ -1260,11 +1260,11 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.80.0" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cb156de1097f567d46bf57a0cd720a72c3e15e1a2bd8b1041ba2fc894471b7" +checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" dependencies = [ - "cranelift-codegen 0.80.0", + "cranelift-codegen 0.82.3", "log 0.4.14", "smallvec 1.8.0", "target-lexicon", @@ -1272,28 +1272,28 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.80.0" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "166028ca0343a6ee7bddac0e70084e142b23f99c701bd6f6ea9123afac1a7a46" +checksum = "501241b0cdf903412ec9075385ac9f2b1eb18a89044d1538e97fab603231f70c" dependencies = [ - "cranelift-codegen 0.80.0", + "cranelift-codegen 0.82.3", "libc", "target-lexicon", ] [[package]] name = "cranelift-wasm" -version = "0.80.0" +version = "0.82.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5012a1cde0c8b3898770b711490d803018ae9bec2d60674ba0e5b2058a874f80" +checksum = "16d9e4211bbc3268042a96dd4de5bd979cda22434991d035f5f8eacba987fad2" dependencies = [ - "cranelift-codegen 0.80.0", - "cranelift-entity 0.80.0", - "cranelift-frontend 0.80.0", + "cranelift-codegen 0.82.3", + "cranelift-entity 0.82.3", + "cranelift-frontend 0.82.3", "itertools", "log 0.4.14", "smallvec 1.8.0", - "wasmparser 0.81.0", + "wasmparser 0.83.0", "wasmtime-types", ] @@ -3191,12 +3191,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "0.4.4" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ef6787e7f0faedc040f95716bdd0e62bcfcf4ba93da053b62dea2691c13864" -dependencies = [ - "winapi 0.3.9", -] +checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6" [[package]] name = "iovec" @@ -4228,9 +4225,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.0.36" +version = "0.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a261afc61b7a5e323933b402ca6a1765183687c614789b1e4db7762ed4230bca" +checksum = "5284f00d480e1c39af34e72f8ad60b94f47007e3481cd3b731c1d67190ddc7b7" [[package]] name = "lite-json" @@ -5319,9 +5316,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "oorandom" @@ -7702,9 +7699,9 @@ dependencies = [ [[package]] name = "regalloc" -version = "0.0.33" +version = "0.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d808cff91dfca7b239d40b972ba628add94892b1d9e19a842aedc5cfae8ab1a" +checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" dependencies = [ "log 0.4.14", "rustc-hash", @@ -7913,9 +7910,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.31.3" +version = "0.33.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2dcfc2778a90e38f56a708bfc90572422e11d6c7ee233d053d1f782cf9df6d2" +checksum = "03627528abcc4a365554d32a9f3bbf67f7694c102cfeda792dc86a2d6057cc85" dependencies = [ "bitflags", "errno", @@ -12115,34 +12112,33 @@ checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" [[package]] name = "wasmparser" -version = "0.81.0" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc" +checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" [[package]] name = "wasmtime" -version = "0.33.0" +version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414be1bc5ca12e755ffd3ff7acc3a6d1979922f8237fc34068b2156cebcc3270" +checksum = "21ffb4705016d5ca91e18a72ed6822dab50e6d5ddd7045461b17ef19071cdef1" dependencies = [ "anyhow", "backtrace", "bincode", "cfg-if 1.0.0", - "cpp_demangle", "indexmap", "lazy_static", "libc", "log 0.4.14", "object 0.27.1", + "once_cell", "paste 1.0.6", "psm", "rayon", "region 2.2.0", - "rustc-demangle", "serde", "target-lexicon", - "wasmparser 0.81.0", + "wasmparser 0.83.0", "wasmtime-cache", "wasmtime-cranelift", "wasmtime-environ", @@ -12153,9 +12149,9 @@ dependencies = [ [[package]] name = "wasmtime-cache" -version = "0.33.0" +version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9b4cd1949206fda9241faf8c460a7d797aa1692594d3dd6bc1cbfa57ee20d0" +checksum = "85c6ab24291fa7cb3a181f5669f6c72599b7ef781669759b45c7828c5999d0c0" dependencies = [ "anyhow", "base64 0.13.0", @@ -12173,14 +12169,14 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "0.33.0" +version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4693d33725773615a4c9957e4aa731af57b27dca579702d1d8ed5750760f1a9" +checksum = "f04c810078a491b7bc4866ebe045f714d2b95e6b539e1f64009a4a7606be11de" dependencies = [ "anyhow", - "cranelift-codegen 0.80.0", - "cranelift-entity 0.80.0", - "cranelift-frontend 0.80.0", + "cranelift-codegen 0.82.3", + "cranelift-entity 0.82.3", + "cranelift-frontend 0.82.3", "cranelift-native", "cranelift-wasm", "gimli 0.26.1", @@ -12189,18 +12185,18 @@ dependencies = [ "object 0.27.1", "target-lexicon", "thiserror", - "wasmparser 0.81.0", + "wasmparser 0.83.0", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.33.0" +version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b17e47116a078b9770e6fb86cff8b9a660826623cebcfff251b047c8d8993ef" +checksum = "61448266ea164b1ac406363cdcfac81c7c44db4d94c7a81c8620ac6c5c6cdf59" dependencies = [ "anyhow", - "cranelift-entity 0.80.0", + "cranelift-entity 0.82.3", "gimli 0.26.1", "indexmap", "log 0.4.14", @@ -12209,44 +12205,58 @@ dependencies = [ "serde", "target-lexicon", "thiserror", - "wasmparser 0.81.0", + "wasmparser 0.83.0", "wasmtime-types", ] [[package]] name = "wasmtime-jit" -version = "0.33.0" +version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60ea5b380bdf92e32911400375aeefb900ac9d3f8e350bb6ba555a39315f2ee7" +checksum = "156b4623c6b0d4b8c24afb846c20525922f538ef464cc024abab7ea8de2109a2" dependencies = [ "addr2line", "anyhow", "bincode", "cfg-if 1.0.0", + "cpp_demangle", "gimli 0.26.1", + "log 0.4.14", "object 0.27.1", "region 2.2.0", + "rustc-demangle", "rustix", "serde", "target-lexicon", "thiserror", "wasmtime-environ", + "wasmtime-jit-debug", "wasmtime-runtime", "winapi 0.3.9", ] +[[package]] +name = "wasmtime-jit-debug" +version = "0.35.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5dc31f811760a6c76b2672c404866fd19b75e5fb3b0075a3e377a6846490654" +dependencies = [ + "lazy_static", + "object 0.27.1", + "rustix", +] + [[package]] name = "wasmtime-runtime" -version = "0.33.0" +version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abc7cd79937edd6e238b337608ebbcaf9c086a8457f01dfd598324f7fa56d81a" +checksum = "f907beaff69d4d920fa4688411ee4cc75c0f01859e424677f9e426e2ef749864" dependencies = [ "anyhow", "backtrace", "cc", "cfg-if 1.0.0", "indexmap", - "lazy_static", "libc", "log 0.4.14", "mach", @@ -12257,19 +12267,20 @@ dependencies = [ "rustix", "thiserror", "wasmtime-environ", + "wasmtime-jit-debug", "winapi 0.3.9", ] [[package]] name = "wasmtime-types" -version = "0.33.0" +version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9e5e51a461a2cf2b69e1fc48f325b17d78a8582816e18479e8ead58844b23f8" +checksum = "514ef0e5fd197b9609dc9eb74beba0c84d5a12b2417cbae55534633329ba4852" dependencies = [ - "cranelift-entity 0.80.0", + "cranelift-entity 0.82.3", "serde", "thiserror", - "wasmparser 0.81.0", + "wasmparser 0.83.0", ] [[package]] @@ -12566,18 +12577,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.9.0+zstd.1.5.0" +version = "0.10.0+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07749a5dc2cb6b36661290245e350f15ec3bbb304e493db54a1d354480522ccd" +checksum = "3b1365becbe415f3f0fcd024e2f7b45bacfb5bdd055f0dc113571394114e7bdd" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.1+zstd.1.5.0" +version = "4.1.4+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91c90f2c593b003603e5e0493c837088df4469da25aafff8bce42ba48caf079" +checksum = "2f7cd17c9af1a4d6c24beb1cc54b17e2ef7b593dc92f19e9d9acad8b182bbaee" dependencies = [ "libc", "zstd-sys", @@ -12585,9 +12596,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.1+zstd.1.5.0" +version = "1.6.3+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33" +checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" dependencies = [ "cc", "libc", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index f0155204f5442..233c2e7d8f098 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -23,7 +23,7 @@ sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interf sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -wasmtime = { version = "0.33.0", default-features = false, features = [ +wasmtime = { version = "0.35.3", default-features = false, features = [ "cache", "cranelift", "jitdump", diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index 762fd85f13b62..0124ba5b83283 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -30,7 +30,7 @@ frame-benchmarking = { default-features = false, path = "../benchmarking", optio serde = { version = "1.0.133", optional = true } thousands = { version = "0.2.0", optional = true } remote-externalities = { path = "../../utils/frame/remote-externalities", optional = true } -zstd = { version = "0.9.0", optional = true } +zstd = { version = "0.10.0", default-features = false, optional = true } [dev-dependencies] pallet-balances = { path = "../balances" } diff --git a/primitives/maybe-compressed-blob/Cargo.toml b/primitives/maybe-compressed-blob/Cargo.toml index d8814356df4bb..3baecaf8e79a8 100644 --- a/primitives/maybe-compressed-blob/Cargo.toml +++ b/primitives/maybe-compressed-blob/Cargo.toml @@ -12,4 +12,4 @@ readme = "README.md" [dependencies] thiserror = "1.0" -zstd = { version = "0.9.0", default-features = false } +zstd = { version = "0.10.0", default-features = false } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 22d2ea62ae45f..9e9b01ebea3d2 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -38,7 +38,7 @@ sp-state-machine = { version = "0.12.0", path = "../state-machine" } sp-api = { version = "4.0.0-dev", path = "../api" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } -zstd = "0.9" +zstd = { version = "0.10.0", default-features = false } [features] bench = [] diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 5fa0627490a22..775ab1c5b7060 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] wasmi = { version = "0.9.1", optional = true } -wasmtime = { version = "0.33.0", optional = true, default-features = false } +wasmtime = { version = "0.35.3", optional = true, default-features = false } log = { version = "0.4.14", optional = true } impl-trait-for-tuples = "0.2.2" sp-std = { version = "4.0.0", path = "../std", default-features = false } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 3f0ee257d9756..abbbe882c2fac 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -17,7 +17,7 @@ clap = { version = "3.1.6", features = ["derive"] } log = "0.4.8" parity-scale-codec = "3.0.0" serde = "1.0.136" -zstd = "0.9.0" +zstd = { version = "0.10.0", default-features = false } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../../client/service" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } From 7f954511c6de6c004598a4b40b601cd43143c1ab Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Thu, 14 Apr 2022 17:25:54 +0100 Subject: [PATCH 0700/1472] Rb staking pallet validator commission change event (#10827) * commission-changed-event-and-deposit * deposit_event fix * commission_changed_event_works * fmt * CommissionChanged -> ValidatorPrefsUpdated * event ValidatorPrefs * updated commet * fmt * Update frame/staking/src/pallet/mod.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/staking/src/pallet/mod.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/staking/src/tests.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- frame/staking/src/pallet/mod.rs | 6 +++++- frame/staking/src/tests.rs | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 498d861660961..1a8fd59d23987 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -628,6 +628,8 @@ pub mod pallet { Chilled(T::AccountId), /// The stakers' rewards are getting paid. \[era_index, validator_stash\] PayoutStarted(EraIndex, T::AccountId), + /// A validator has set their preferences. + ValidatorPrefsSet(T::AccountId, ValidatorPrefs), } #[pallet::error] @@ -1016,7 +1018,9 @@ pub mod pallet { } Self::do_remove_nominator(stash); - Self::do_add_validator(stash, prefs); + Self::do_add_validator(stash, prefs.clone()); + Self::deposit_event(Event::::ValidatorPrefsSet(ledger.stash, prefs)); + Ok(()) } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 11dfe3e4777f8..7161418afc76e 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4598,11 +4598,21 @@ fn capped_stakers_works() { #[test] fn min_commission_works() { ExtBuilder::default().build_and_execute(|| { + // account 10 controls the stash from account 11 assert_ok!(Staking::validate( Origin::signed(10), ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } )); + // event emitted should be correct + assert_eq!( + *staking_events().last().unwrap(), + Event::ValidatorPrefsSet( + 11, + ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } + ) + ); + assert_ok!(Staking::set_staking_configs( Origin::root(), ConfigOp::Remove, From c4f3d028621edb293d2c423516221aa396f76a2d Mon Sep 17 00:00:00 2001 From: stanly-johnson Date: Thu, 14 Apr 2022 23:41:42 +0400 Subject: [PATCH 0701/1472] pallet_assets : Remove event for no_op (#11023) * remove no_op event * ensure no transferred event emitted Co-authored-by: Oliver Tale-Yazdi --- frame/assets/src/functions.rs | 8 +------- frame/assets/src/tests.rs | 8 ++------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index 48a86ca3cfa04..0be79619e0967 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -529,14 +529,8 @@ impl, I: 'static> Pallet { maybe_need_admin: Option, f: TransferFlags, ) -> Result<(T::Balance, Option), DispatchError> { - // Early exist if no-op. + // Early exit if no-op. if amount.is_zero() { - Self::deposit_event(Event::Transferred { - asset_id: id, - from: source.clone(), - to: dest.clone(), - amount, - }); return Ok((amount, None)) } diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 7430b742e7d2a..db0d6a5f212f9 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -620,12 +620,8 @@ fn transferring_less_than_one_unit_is_fine() { assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 0)); - System::assert_last_event(mock::Event::Assets(crate::Event::Transferred { - asset_id: 0, - from: 1, - to: 2, - amount: 0, - })); + // `ForceCreated` and `Issued` but no `Transferred` event. + assert_eq!(System::events().len(), 2); }); } From c9af3c6ae49c3720f4320ebbd6c5f936951dfdcf Mon Sep 17 00:00:00 2001 From: Georges Date: Fri, 15 Apr 2022 11:15:01 +0100 Subject: [PATCH 0702/1472] Adding benchmarking for new `frame_election_provider_support` (#11149) * First stab at adding benchmarking for `election-provider-support` onchain * Adding `BoundedPhragMMS` and fixing stuff * Fixing node runtime * Fixing tests * Finalising all benchmarking stuff * better comments * Better benchmarking config * Better `WeightInfo` and benchmarking * Fixing tests * Adding some documentation * Fixing some typos * Incorporating review feedback * cleanup of rustdocs * rustdoc changes * changes after code review * Fixing some errors. * Fixing dependencies post merge * Bringing back `UnboundedExecution` * Better rustdoc and naming * Cargo.toml formatting --- Cargo.lock | 14 +++ Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 2 + bin/node/runtime/src/lib.rs | 11 +- frame/babe/src/mock.rs | 3 +- .../election-provider-multi-phase/Cargo.toml | 10 +- .../election-provider-multi-phase/src/mock.rs | 5 +- .../benchmarking/Cargo.toml | 38 ++++++ .../benchmarking/src/lib.rs | 91 ++++++++++++++ frame/election-provider-support/src/lib.rs | 19 ++- .../election-provider-support/src/onchain.rs | 115 ++++++++++++------ .../election-provider-support/src/weights.rs | 94 ++++++++++++++ frame/grandpa/src/mock.rs | 5 +- frame/offences/benchmarking/src/mock.rs | 3 +- frame/session/benchmarking/src/mock.rs | 3 +- frame/staking/src/mock.rs | 3 +- primitives/npos-elections/src/balancing.rs | 2 +- primitives/npos-elections/src/phragmms.rs | 2 +- 18 files changed, 366 insertions(+), 55 deletions(-) create mode 100644 frame/election-provider-support/benchmarking/Cargo.toml create mode 100644 frame/election-provider-support/benchmarking/src/lib.rs create mode 100644 frame/election-provider-support/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 440d549af1a35..2fa738118247e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4998,6 +4998,7 @@ dependencies = [ "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", + "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-gilt", "pallet-grandpa", @@ -5851,6 +5852,7 @@ dependencies = [ "frame-system", "log 0.4.14", "pallet-balances", + "pallet-election-provider-support-benchmarking", "parity-scale-codec", "parking_lot 0.12.0", "rand 0.7.3", @@ -5866,6 +5868,18 @@ dependencies = [ "strum", ] +[[package]] +name = "pallet-election-provider-support-benchmarking" +version = "4.0.0-dev" +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" diff --git a/Cargo.toml b/Cargo.toml index 45df7258ef253..c281913cd55ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,6 +87,7 @@ members = [ "frame/try-runtime", "frame/election-provider-multi-phase", "frame/election-provider-support", + "frame/election-provider-support/benchmarking", "frame/election-provider-support/solution-type", "frame/election-provider-support/solution-type/fuzzer", "frame/examples/basic", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 686508b47dba1..41b2402d33a53 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -65,6 +65,7 @@ pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", default-features = f pallet-conviction-voting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/conviction-voting" } pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" } pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" } +pallet-election-provider-support-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-support/benchmarking", optional = true } pallet-elections-phragmen = { version = "5.0.0-dev", default-features = false, path = "../../../frame/elections-phragmen" } pallet-gilt = { version = "4.0.0-dev", default-features = false, path = "../../../frame/gilt" } pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../../frame/grandpa" } @@ -196,6 +197,7 @@ runtime-benchmarks = [ "pallet-conviction-voting/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", "pallet-election-provider-multi-phase/runtime-benchmarks", + "pallet-election-provider-support-benchmarking/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", "pallet-gilt/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f422d1ffc45b8..f37345014f3a1 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -643,17 +643,18 @@ impl Get> for OffchainRandomBalancing { } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Runtime; type Solver = SequentialPhragmen< AccountId, pallet_election_provider_multi_phase::SolutionAccuracyOf, >; type DataProvider = ::DataProvider; + type WeightInfo = frame_election_provider_support::weights::SubstrateWeight; } -impl onchain::BoundedExecutionConfig for OnChainSeqPhragmen { - type VotersBound = ConstU32<20_000>; +impl onchain::BoundedConfig for OnChainSeqPhragmen { + type VotersBound = MaxElectingVoters; type TargetsBound = ConstU32<2_000>; } @@ -1531,6 +1532,7 @@ mod benches { [pallet_contracts, Contracts] [pallet_democracy, Democracy] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] + [pallet_election_provider_support_benchmarking, EPSBench::] [pallet_elections_phragmen, Elections] [pallet_gilt, Gilt] [pallet_grandpa, Grandpa] @@ -1851,6 +1853,7 @@ impl_runtime_apis! { // which is why we need these two lines below. use pallet_session_benchmarking::Pallet as SessionBench; use pallet_offences_benchmarking::Pallet as OffencesBench; + use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; use baseline::Pallet as BaselineBench; @@ -1872,11 +1875,13 @@ impl_runtime_apis! { // which is why we need these two lines below. use pallet_session_benchmarking::Pallet as SessionBench; use pallet_offences_benchmarking::Pallet as OffencesBench; + use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; use baseline::Pallet as BaselineBench; impl pallet_session_benchmarking::Config for Runtime {} impl pallet_offences_benchmarking::Config for Runtime {} + impl pallet_election_provider_support_benchmarking::Config for Runtime {} impl frame_system_benchmarking::Config for Runtime {} impl baseline::Config for Runtime {} diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 37d8e9e37a5f4..15f53e7da0823 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -173,10 +173,11 @@ parameter_types! { } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Test; type Solver = SequentialPhragmen; type DataProvider = Staking; + type WeightInfo = (); } impl pallet_staking::Config for Test { diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 25f98d965d86b..48134966a9253 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -17,7 +17,9 @@ static_assertions = "1.1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = [ + "derive", +] } log = { version = "0.4.14", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -33,11 +35,14 @@ frame-election-provider-support = { version = "4.0.0-dev", default-features = fa # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +pallet-election-provider-support-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support/benchmarking", optional = true } rand = { version = "0.7.3", default-features = false, optional = true, features = [ "alloc", "small_rng", ] } -strum = { optional = true, default-features = false, version = "0.23.0", features = ["derive"] } +strum = { optional = true, default-features = false, version = "0.23.0", features = [ + "derive", +] } [dev-dependencies] parking_lot = "0.12.0" @@ -46,7 +51,6 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } -frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index d6f040363dba0..7c06ff6bee546 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -276,10 +276,11 @@ parameter_types! { } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Runtime; type Solver = SequentialPhragmen, Balancing>; type DataProvider = StakingMock; + type WeightInfo = (); } pub struct MockFallback; @@ -304,7 +305,7 @@ impl InstantElectionProvider for MockFallback { max_voters, max_targets, ) - .map_err(|_| "UnboundedExecution failed") + .map_err(|_| "onchain::UnboundedExecution failed.") } else { super::NoFallback::::elect_with_bounds(max_voters, max_targets) } diff --git a/frame/election-provider-support/benchmarking/Cargo.toml b/frame/election-provider-support/benchmarking/Cargo.toml new file mode 100644 index 0000000000000..e9719be139a6d --- /dev/null +++ b/frame/election-provider-support/benchmarking/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "pallet-election-provider-support-benchmarking" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Benchmarking for election provider support onchain config trait" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } +sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } +frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = ".." } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true } + + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-npos-elections/std", + "sp-runtime/std", + "frame-benchmarking/std", + "frame-system/std", +] + +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-election-provider-support/runtime-benchmarks", +] diff --git a/frame/election-provider-support/benchmarking/src/lib.rs b/frame/election-provider-support/benchmarking/src/lib.rs new file mode 100644 index 0000000000000..547e35bed36e8 --- /dev/null +++ b/frame/election-provider-support/benchmarking/src/lib.rs @@ -0,0 +1,91 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Election provider support pallet benchmarking. +//! This is separated into its own crate to avoid bloating the size of the runtime. + +#![cfg(feature = "runtime-benchmarks")] +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Decode; +use frame_benchmarking::{benchmarks, Vec}; +use frame_election_provider_support::{NposSolver, PhragMMS, SequentialPhragmen}; + +pub struct Pallet(frame_system::Pallet); +pub trait Config: frame_system::Config {} + +const VOTERS: [u32; 2] = [1_000, 2_000]; +const TARGETS: [u32; 2] = [500, 1_000]; +const VOTES_PER_VOTER: [u32; 2] = [5, 16]; + +const SEED: u32 = 999; +fn set_up_voters_targets( + voters_len: u32, + targets_len: u32, + degree: usize, +) -> (Vec<(AccountId, u64, impl IntoIterator)>, Vec) { + // fill targets. + let mut targets = (0..targets_len) + .map(|i| frame_benchmarking::account::("Target", i, SEED)) + .collect::>(); + assert!(targets.len() > degree, "we should always have enough voters to fill"); + targets.truncate(degree); + + // fill voters. + let voters = (0..voters_len) + .map(|i| { + let voter = frame_benchmarking::account::("Voter", i, SEED); + (voter, 1_000, targets.clone()) + }) + .collect::>(); + + (voters, targets) +} + +benchmarks! { + phragmen { + // number of votes in snapshot. + let v in (VOTERS[0]) .. VOTERS[1]; + // number of targets in snapshot. + let t in (TARGETS[0]) .. TARGETS[1]; + // number of votes per voter (ie the degree). + let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; + + let (voters, targets) = set_up_voters_targets::(v, t, d as usize); + }: { + assert!( + SequentialPhragmen:: + ::solve(d as usize, targets, voters).is_ok() + ); + } + + phragmms { + // number of votes in snapshot. + let v in (VOTERS[0]) .. VOTERS[1]; + // number of targets in snapshot. + let t in (TARGETS[0]) .. TARGETS[1]; + // number of votes per voter (ie the degree). + let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; + + let (voters, targets) = set_up_voters_targets::(v, t, d as usize); + }: { + assert!( + PhragMMS:: + ::solve(d as usize, targets, voters).is_ok() + ); + } +} diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 19735cf6035ac..37ea2fcc59091 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -170,7 +170,7 @@ pub mod onchain; pub mod traits; #[cfg(feature = "std")] use codec::{Decode, Encode}; -use frame_support::{BoundedVec, RuntimeDebug}; +use frame_support::{weights::Weight, BoundedVec, RuntimeDebug}; use sp_runtime::traits::Bounded; use sp_std::{fmt::Debug, prelude::*}; @@ -195,6 +195,9 @@ pub use sp_arithmetic; #[doc(hidden)] pub use sp_std; +pub mod weights; +pub use weights::WeightInfo; + #[cfg(test)] mod mock; #[cfg(test)] @@ -523,6 +526,12 @@ pub trait NposSolver { targets: Vec, voters: Vec<(Self::AccountId, VoteWeight, impl IntoIterator)>, ) -> Result, Self::Error>; + + /// Measure the weight used in the calculation of the solver. + /// - `voters` is the number of voters. + /// - `targets` is the number of targets. + /// - `vote_degree` is the degree ie the maximum numbers of votes per voter. + fn weight(voters: u32, targets: u32, vote_degree: u32) -> Weight; } /// A wrapper for [`sp_npos_elections::seq_phragmen`] that implements [`NposSolver`]. See the @@ -547,6 +556,10 @@ impl< ) -> Result, Self::Error> { sp_npos_elections::seq_phragmen(winners, targets, voters, Balancing::get()) } + + fn weight(voters: u32, targets: u32, vote_degree: u32) -> Weight { + T::phragmen(voters, targets, vote_degree) + } } /// A wrapper for [`sp_npos_elections::phragmms()`] that implements [`NposSolver`]. See the @@ -571,6 +584,10 @@ impl< ) -> Result, Self::Error> { sp_npos_elections::phragmms(winners, targets, voters, Balancing::get()) } + + fn weight(voters: u32, targets: u32, vote_degree: u32) -> Weight { + T::phragmms(voters, targets, vote_degree) + } } /// A voter, at the level of abstraction of this crate. diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 57fd931a467d1..62e76c3888822 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -15,9 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! An implementation of [`ElectionProvider`] that uses an `NposSolver` to do the election. +//! An implementation of [`ElectionProvider`] that uses an `NposSolver` to do the election. As the +//! name suggests, this is meant to be used onchain. Given how heavy the calculations are, please be +//! careful when using it onchain. -use crate::{ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolver}; +use crate::{ + Debug, ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolver, WeightInfo, +}; use frame_support::{traits::Get, weights::DispatchClass}; use sp_npos_elections::*; use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; @@ -41,39 +45,32 @@ impl From for Error { /// /// This will accept voting data on the fly and produce the results immediately. /// -/// Finally, the [`ElectionProvider`] implementation of this type does not impose any limits on the +/// The [`ElectionProvider`] implementation of this type does not impose any dynamic limits on the /// number of voters and targets that are fetched. This could potentially make this unsuitable for -/// execution onchain. One could, however, impose bounds on it by using for example -/// `BoundedExecution` which will the bounds provided in the configuration. +/// execution onchain. One could, however, impose bounds on it by using `BoundedExecution` using the +/// `MaxVoters` and `MaxTargets` bonds in the `BoundedConfig` trait. /// -/// On the other hand, the [`InstantElectionProvider`] implementation does limit these inputs, -/// either via using `BoundedExecution` and imposing the bounds there, or dynamically via calling -/// `elect_with_bounds` providing these bounds. If you use `elect_with_bounds` along with -/// `InstantElectionProvider`, the bound that would be used is the minimum of the 2 bounds. -/// -/// It is advisable to use the former ([`ElectionProvider::elect`]) only at genesis, or for testing, -/// the latter [`InstantElectionProvider::elect_with_bounds`] for onchain operations, with -/// thoughtful bounds. +/// On the other hand, the [`InstantElectionProvider`] implementation does limit these inputs +/// dynamically. If you use `elect_with_bounds` along with `InstantElectionProvider`, the bound that +/// would be used is the minimum of the dynamic bounds given as arguments to `elect_with_bounds` and +/// the trait bounds (`MaxVoters` and `MaxTargets`). /// /// Please use `BoundedExecution` at all times except at genesis or for testing, with thoughtful /// bounds in order to bound the potential execution time. Limit the use `UnboundedExecution` at /// genesis or for testing, as it does not bound the inputs. However, this can be used with /// `[InstantElectionProvider::elect_with_bounds`] that dynamically imposes limits. -pub struct BoundedExecution(PhantomData); +pub struct BoundedExecution(PhantomData); /// An unbounded variant of [`BoundedExecution`]. /// /// ### Warning /// -/// This can be very expensive to run frequently on-chain. Use with care. Moreover, this -/// implementation ignores the additional data of the election data provider and gives no insight on -/// how much weight was consumed. -pub struct UnboundedExecution(PhantomData); - -/// Configuration trait of [`UnboundedExecution`]. -pub trait ExecutionConfig { - /// Something that implements the system pallet configs. This is to enable to register extra - /// weight. +/// This can be very expensive to run frequently on-chain. Use with care. +pub struct UnboundedExecution(PhantomData); + +/// Configuration trait for an onchain election execution. +pub trait Config { + /// Needed for weight registration. type System: frame_system::Config; /// `NposSolver` that should be used, an example would be `PhragMMS`. type Solver: NposSolver< @@ -85,17 +82,18 @@ pub trait ExecutionConfig { AccountId = ::AccountId, BlockNumber = ::BlockNumber, >; + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; } -/// Configuration trait of [`BoundedExecution`]. -pub trait BoundedExecutionConfig: ExecutionConfig { +pub trait BoundedConfig: Config { /// Bounds the number of voters. type VotersBound: Get; /// Bounds the number of targets. type TargetsBound: Get; } -fn elect_with( +fn elect_with( maybe_max_voters: Option, maybe_max_targets: Option, ) -> Result::AccountId>, Error> { @@ -104,6 +102,9 @@ fn elect_with( T::DataProvider::electable_targets(maybe_max_targets).map_err(Error::DataProvider)?; let desired_targets = T::DataProvider::desired_targets().map_err(Error::DataProvider)?; + let voters_len = voters.len() as u32; + let targets_len = targets.len() as u32; + let stake_map: BTreeMap<_, _> = voters .iter() .map(|(validator, vote_weight, _)| (validator.clone(), *vote_weight)) @@ -118,7 +119,11 @@ fn elect_with( let staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?; - let weight = ::BlockWeights::get().max_block; + let weight = T::Solver::weight::( + voters_len, + targets_len, + ::MaxVotesPerVoter::get(), + ); frame_system::Pallet::::register_extra_weight_unchecked( weight, DispatchClass::Mandatory, @@ -127,13 +132,13 @@ fn elect_with( Ok(to_supports(&staked)) } -impl ElectionProvider for UnboundedExecution { +impl ElectionProvider for UnboundedExecution { type AccountId = ::AccountId; type BlockNumber = ::BlockNumber; type Error = Error; type DataProvider = T::DataProvider; - fn elect() -> Result::AccountId>, Self::Error> { + fn elect() -> Result, Self::Error> { // This should not be called if not in `std` mode (and therefore neither in genesis nor in // testing) if cfg!(not(feature = "std")) { @@ -147,7 +152,7 @@ impl ElectionProvider for UnboundedExecution { } } -impl InstantElectionProvider for UnboundedExecution { +impl InstantElectionProvider for UnboundedExecution { fn elect_with_bounds( max_voters: usize, max_targets: usize, @@ -156,18 +161,18 @@ impl InstantElectionProvider for UnboundedExecution { } } -impl ElectionProvider for BoundedExecution { +impl ElectionProvider for BoundedExecution { type AccountId = ::AccountId; type BlockNumber = ::BlockNumber; type Error = Error; type DataProvider = T::DataProvider; - fn elect() -> Result::AccountId>, Self::Error> { + fn elect() -> Result, Self::Error> { elect_with::(Some(T::VotersBound::get() as usize), Some(T::TargetsBound::get() as usize)) } } -impl InstantElectionProvider for BoundedExecution { +impl InstantElectionProvider for BoundedExecution { fn elect_with_bounds( max_voters: usize, max_targets: usize, @@ -182,6 +187,8 @@ impl InstantElectionProvider for BoundedExecution #[cfg(test)] mod tests { use super::*; + use crate::{PhragMMS, SequentialPhragmen}; + use frame_support::traits::ConstU32; use sp_npos_elections::Support; use sp_runtime::Perbill; type AccountId = u64; @@ -228,13 +235,32 @@ mod tests { type MaxConsumers = frame_support::traits::ConstU32<16>; } - impl ExecutionConfig for Runtime { - type System = Self; - type Solver = crate::SequentialPhragmen; + struct PhragmenParams; + struct PhragMMSParams; + + impl Config for PhragmenParams { + type System = Runtime; + type Solver = SequentialPhragmen; type DataProvider = mock_data_provider::DataProvider; + type WeightInfo = (); } - type OnChainPhragmen = UnboundedExecution; + impl BoundedConfig for PhragmenParams { + type VotersBound = ConstU32<600>; + type TargetsBound = ConstU32<400>; + } + + impl Config for PhragMMSParams { + type System = Runtime; + type Solver = PhragMMS; + type DataProvider = mock_data_provider::DataProvider; + type WeightInfo = (); + } + + impl BoundedConfig for PhragMMSParams { + type VotersBound = ConstU32<600>; + type TargetsBound = ConstU32<400>; + } mod mock_data_provider { use frame_support::{bounded_vec, traits::ConstU32}; @@ -273,7 +299,20 @@ mod tests { fn onchain_seq_phragmen_works() { sp_io::TestExternalities::new_empty().execute_with(|| { assert_eq!( - OnChainPhragmen::elect().unwrap(), + BoundedExecution::::elect().unwrap(), + vec![ + (10, Support { total: 25, voters: vec![(1, 10), (3, 15)] }), + (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }) + ] + ); + }) + } + + #[test] + fn onchain_phragmms_works() { + sp_io::TestExternalities::new_empty().execute_with(|| { + assert_eq!( + BoundedExecution::::elect().unwrap(), vec![ (10, Support { total: 25, voters: vec![(1, 10), (3, 15)] }), (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }) diff --git a/frame/election-provider-support/src/weights.rs b/frame/election-provider-support/src/weights.rs new file mode 100644 index 0000000000000..f288ae63bb5da --- /dev/null +++ b/frame/election-provider-support/src/weights.rs @@ -0,0 +1,94 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_election_provider_support_onchain_benchmarking +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-04-04, STEPS: `1`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/substrate +// benchmark +// --chain=dev +// --steps=1 +// --repeat=1 +// --pallet=pallet_election_provider_support_benchmarking +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=frame/election-provider-support/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_election_provider_support_benchmarking. +pub trait WeightInfo { + fn phragmen(v: u32, t: u32, d: u32, ) -> Weight; + fn phragmms(v: u32, t: u32, d: u32, ) -> Weight; +} + +/// Weights for pallet_election_provider_support_benchmarking using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 667_000 + .saturating_add((32_973_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 1_334_000 + .saturating_add((1_334_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 60_644_000 + .saturating_add((2_636_364_000 as Weight).saturating_mul(d as Weight)) + } + fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 73_000 + .saturating_add((21_073_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 146_000 + .saturating_add((65_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 6_649_000 + .saturating_add((1_711_424_000 as Weight).saturating_mul(d as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 667_000 + .saturating_add((32_973_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 1_334_000 + .saturating_add((1_334_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 60_644_000 + .saturating_add((2_636_364_000 as Weight).saturating_mul(d as Weight)) + } + fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 73_000 + .saturating_add((21_073_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 146_000 + .saturating_add((65_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 6_649_000 + .saturating_add((1_711_424_000 as Weight).saturating_mul(d as Weight)) + } +} diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 0296cd2e28d88..67d5a3d7fd373 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -181,10 +181,11 @@ parameter_types! { } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Test; - type Solver = SequentialPhragmen<::AccountId, Perbill>; + type Solver = SequentialPhragmen; type DataProvider = Staking; + type WeightInfo = (); } impl pallet_staking::Config for Test { diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 1a4414de0b0b0..74cc29586920d 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -151,10 +151,11 @@ parameter_types! { pub type Extrinsic = sp_runtime::testing::TestXt; pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Test; type Solver = SequentialPhragmen; type DataProvider = Staking; + type WeightInfo = (); } impl pallet_staking::Config for Test { diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 24b42b3e9f4b5..5acc484f9ba62 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -157,10 +157,11 @@ where } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Test; type Solver = SequentialPhragmen; type DataProvider = Staking; + type WeightInfo = (); } impl pallet_staking::Config for Test { diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index bb90aded852ee..09809483ec155 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -248,10 +248,11 @@ impl pallet_bags_list::Config for Test { } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Test; type Solver = SequentialPhragmen; type DataProvider = Staking; + type WeightInfo = (); } impl crate::pallet::pallet::Config for Test { diff --git a/primitives/npos-elections/src/balancing.rs b/primitives/npos-elections/src/balancing.rs index 98f193e9e6116..54b8ee4bf243e 100644 --- a/primitives/npos-elections/src/balancing.rs +++ b/primitives/npos-elections/src/balancing.rs @@ -37,7 +37,7 @@ use sp_std::prelude::*; /// /// In almost all cases, a balanced solution will have a better score than an unbalanced solution, /// yet this is not 100% guaranteed because the first element of a [`crate::ElectionScore`] does not -/// directly related to balancing. +/// directly relate to balancing. /// /// Note that some reference implementation adopt an approach in which voters are balanced randomly /// per round. To advocate determinism, we don't do this. In each round, all voters are exactly diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index 6220cacd157b2..aa4c558bea1da 100644 --- a/primitives/npos-elections/src/phragmms.rs +++ b/primitives/npos-elections/src/phragmms.rs @@ -37,7 +37,7 @@ use sp_std::{prelude::*, rc::Rc}; /// - The algorithm is a _best-effort_ to elect `to_elect`. If less candidates are provided, less /// winners are returned, without an error. /// -/// This can only fail of the normalization fails. This can happen if for any of the resulting +/// This can only fail if the normalization fails. This can happen if for any of the resulting /// assignments, `assignment.distribution.map(|p| p.deconstruct()).sum()` fails to fit inside /// `UpperOf

`. A user of this crate may statically assert that this can never happen and safely /// `expect` this to return `Ok`. From 1e0807fb477b21edd373eb88778336d5ff23d3a7 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 15 Apr 2022 14:09:16 +0200 Subject: [PATCH 0703/1472] Add `benchmark machine` placeholder (#11198) * Move new_rng to shared code Signed-off-by: Oliver Tale-Yazdi * Add bechmark machine command Signed-off-by: Oliver Tale-Yazdi * Use sc-sysinfo Signed-off-by: Oliver Tale-Yazdi * Add --no-hardware-benchmarks Signed-off-by: Oliver Tale-Yazdi * Lockfile Signed-off-by: Oliver Tale-Yazdi * Do not create components if not needed Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * Revert "Add --no-hardware-benchmarks" This reverts commit d4ee98222bf1a5ea62ac60dd7d5c62070e2d7f70. * Fix tests Signed-off-by: Oliver Tale-Yazdi * Update Cargo deps Signed-off-by: Oliver Tale-Yazdi * Move sr255119::verify bench to sc-sysinfo Signed-off-by: Oliver Tale-Yazdi * Move sr255119::verify bench to sc-sysinfo Signed-off-by: Oliver Tale-Yazdi * Switch benchmarks to return f64 Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Hide command until completed Signed-off-by: Oliver Tale-Yazdi * Use concrete rand implementation Signed-off-by: Oliver Tale-Yazdi * Put clobber into a function Signed-off-by: Oliver Tale-Yazdi * Add test Signed-off-by: Oliver Tale-Yazdi * Add comment Signed-off-by: Oliver Tale-Yazdi * Update cargo to match polkadot Signed-off-by: Oliver Tale-Yazdi * Remove doc that does not format in the console Signed-off-by: Oliver Tale-Yazdi * Limit benchmark by time Signed-off-by: Oliver Tale-Yazdi * Add ExecutionLimit and make function infallible Signed-off-by: Oliver Tale-Yazdi * CI Signed-off-by: Oliver Tale-Yazdi * Add doc Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 86 ++++++++++++++++-- bin/node-template/node/src/command.rs | 11 ++- bin/node/cli/src/command.rs | 10 +- bin/node/cli/tests/benchmark_block_works.rs | 2 +- bin/node/cli/tests/benchmark_machine_works.rs | 32 +++++++ client/sysinfo/Cargo.toml | 2 + client/sysinfo/src/lib.rs | 38 +++++++- client/sysinfo/src/sysinfo.rs | 91 +++++++++++++++---- utils/frame/benchmarking-cli/Cargo.toml | 5 +- utils/frame/benchmarking-cli/src/lib.rs | 5 + .../frame/benchmarking-cli/src/machine/mod.rs | 86 ++++++++++++++++++ .../frame/benchmarking-cli/src/shared/mod.rs | 10 ++ .../frame/benchmarking-cli/src/storage/cmd.rs | 11 +-- .../benchmarking-cli/src/storage/read.rs | 4 +- .../benchmarking-cli/src/storage/write.rs | 4 +- 15 files changed, 351 insertions(+), 46 deletions(-) create mode 100644 bin/node/cli/tests/benchmark_machine_works.rs create mode 100644 utils/frame/benchmarking-cli/src/machine/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 2fa738118247e..52c6daad6b422 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1677,6 +1677,17 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +dependencies = [ + "libc", + "redox_users 0.3.5", + "winapi 0.3.9", +] + [[package]] name = "dirs-sys" version = "0.3.6" @@ -1684,7 +1695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.0", "winapi 0.3.9", ] @@ -1695,7 +1706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.0", "winapi 0.3.9", ] @@ -1844,6 +1855,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "enum-as-inner" version = "0.3.3" @@ -2009,9 +2026,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.4.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" dependencies = [ "instant", ] @@ -2173,13 +2190,16 @@ dependencies = [ "log 0.4.14", "memory-db", "parity-scale-codec", + "prettytable-rs", "rand 0.8.4", + "rand_pcg 0.3.1", "sc-block-builder", "sc-cli", "sc-client-api", "sc-client-db", "sc-executor", "sc-service", + "sc-sysinfo", "serde", "serde_json", "serde_nanos", @@ -2192,9 +2212,9 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-state-machine", - "sp-std", "sp-storage", "sp-trie", + "tempfile", "thousands", ] @@ -7183,6 +7203,20 @@ dependencies = [ "output_vt100", ] +[[package]] +name = "prettytable-rs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e" +dependencies = [ + "atty", + "csv", + "encode_unicode", + "lazy_static", + "term", + "unicode-width", +] + [[package]] name = "primitive-types" version = "0.11.1" @@ -7670,6 +7704,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +dependencies = [ + "getrandom 0.1.16", + "redox_syscall 0.1.57", + "rust-argon2", +] + [[package]] name = "redox_users" version = "0.4.0" @@ -7886,6 +7931,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rust-argon2" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +dependencies = [ + "base64 0.13.0", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils 0.8.5", +] + [[package]] name = "rustc-demangle" version = "0.1.18" @@ -9099,6 +9156,8 @@ dependencies = [ "serde", "serde_json", "sp-core", + "sp-io", + "sp-std", ] [[package]] @@ -10914,18 +10973,29 @@ checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1" [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if 1.0.0", + "fastrand", "libc", - "rand 0.8.4", "redox_syscall 0.2.10", "remove_dir_all", "winapi 0.3.9", ] +[[package]] +name = "term" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" +dependencies = [ + "byteorder", + "dirs", + "winapi 0.3.9", +] + [[package]] name = "termcolor" version = "1.1.2" diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index 0c850b322a7d2..afa4612f1ee4a 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -109,8 +109,6 @@ pub fn run() -> sc_cli::Result<()> { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| { - let PartialComponents { client, backend, .. } = service::new_partial(&config)?; - // This switch needs to be in the client, since the client decides // which sub-commands it wants to support. match cmd { @@ -125,18 +123,25 @@ pub fn run() -> sc_cli::Result<()> { cmd.run::(config) }, - BenchmarkCmd::Block(cmd) => cmd.run(client), + BenchmarkCmd::Block(cmd) => { + let PartialComponents { client, .. } = service::new_partial(&config)?; + cmd.run(client) + }, BenchmarkCmd::Storage(cmd) => { + let PartialComponents { client, backend, .. } = + service::new_partial(&config)?; let db = backend.expose_db(); let storage = backend.expose_storage(); cmd.run(config, client, db, storage) }, BenchmarkCmd::Overhead(cmd) => { + let PartialComponents { client, .. } = service::new_partial(&config)?; let ext_builder = BenchmarkExtrinsicBuilder::new(client.clone()); cmd.run(config, client, inherent_benchmark_data()?, Arc::new(ext_builder)) }, + BenchmarkCmd::Machine(cmd) => cmd.run(&config), } }) }, diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 880b7d7b7ecb7..e2c772e809200 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -99,8 +99,6 @@ pub fn run() -> Result<()> { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| { - let PartialComponents { client, backend, .. } = new_partial(&config)?; - // This switch needs to be in the client, since the client decides // which sub-commands it wants to support. match cmd { @@ -115,18 +113,24 @@ pub fn run() -> Result<()> { cmd.run::(config) }, - BenchmarkCmd::Block(cmd) => cmd.run(client), + BenchmarkCmd::Block(cmd) => { + let PartialComponents { client, .. } = new_partial(&config)?; + cmd.run(client) + }, BenchmarkCmd::Storage(cmd) => { + let PartialComponents { client, backend, .. } = new_partial(&config)?; let db = backend.expose_db(); let storage = backend.expose_storage(); cmd.run(config, client, db, storage) }, BenchmarkCmd::Overhead(cmd) => { + let PartialComponents { client, .. } = new_partial(&config)?; let ext_builder = BenchmarkExtrinsicBuilder::new(client.clone()); cmd.run(config, client, inherent_benchmark_data()?, Arc::new(ext_builder)) }, + BenchmarkCmd::Machine(cmd) => cmd.run(&config), } }) }, diff --git a/bin/node/cli/tests/benchmark_block_works.rs b/bin/node/cli/tests/benchmark_block_works.rs index 37a4db25f363b..359abf3e4265f 100644 --- a/bin/node/cli/tests/benchmark_block_works.rs +++ b/bin/node/cli/tests/benchmark_block_works.rs @@ -30,7 +30,7 @@ pub mod common; async fn benchmark_block_works() { let base_dir = tempdir().expect("could not create a temp dir"); - common::run_node_for_a_while(base_dir.path(), &["--dev"]).await; + common::run_node_for_a_while(base_dir.path(), &["--dev", "--no-hardware-benchmarks"]).await; // Invoke `benchmark block` with all options to make sure that they are valid. let status = Command::new(cargo_bin("substrate")) diff --git a/bin/node/cli/tests/benchmark_machine_works.rs b/bin/node/cli/tests/benchmark_machine_works.rs new file mode 100644 index 0000000000000..df407e988f636 --- /dev/null +++ b/bin/node/cli/tests/benchmark_machine_works.rs @@ -0,0 +1,32 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use assert_cmd::cargo::cargo_bin; +use std::process::Command; + +/// Tests that the `benchmark machine` command works for the substrate dev runtime. +#[test] +fn benchmark_machine_works() { + let status = Command::new(cargo_bin("substrate")) + .args(["benchmark", "machine", "--dev"]) + .args(["--verify-duration", "0.1"]) + .status() + .unwrap(); + + assert!(status.success()); +} diff --git a/client/sysinfo/Cargo.toml b/client/sysinfo/Cargo.toml index 8efe583fb9335..540918cb37c01 100644 --- a/client/sysinfo/Cargo.toml +++ b/client/sysinfo/Cargo.toml @@ -23,4 +23,6 @@ libc = "0.2" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-std = { version = "4.0.0", path = "../../primitives/std" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } diff --git a/client/sysinfo/src/lib.rs b/client/sysinfo/src/lib.rs index be13efb82c66f..911e725dcdd4e 100644 --- a/client/sysinfo/src/lib.rs +++ b/client/sysinfo/src/lib.rs @@ -20,12 +20,16 @@ //! and software telemetry information about the node on which we're running. use futures::prelude::*; +use std::time::Duration; mod sysinfo; #[cfg(target_os = "linux")] mod sysinfo_linux; -pub use sysinfo::{gather_hwbench, gather_sysinfo}; +pub use sysinfo::{ + benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes, + benchmark_memory, benchmark_sr25519_verify, gather_hwbench, gather_sysinfo, +}; /// The operating system part of the current target triplet. pub const TARGET_OS: &str = include_str!(concat!(env!("OUT_DIR"), "/target_os.txt")); @@ -49,6 +53,38 @@ pub struct HwBench { pub disk_random_write_score: Option, } +/// Limit the execution time of a benchmark. +pub enum ExecutionLimit { + /// Limit by the maximal duration. + MaxDuration(Duration), + + /// Limit by the maximal number of iterations. + MaxIterations(usize), + + /// Limit by the maximal duration and maximal number of iterations. + Both { max_iterations: usize, max_duration: Duration }, +} + +impl ExecutionLimit { + /// Returns the duration limit or `MAX` if none is present. + pub fn max_duration(&self) -> Duration { + match self { + Self::MaxDuration(d) => *d, + Self::Both { max_duration, .. } => *max_duration, + _ => Duration::from_secs(u64::MAX), + } + } + + /// Returns the iterations limit or `MAX` if none is present. + pub fn max_iterations(&self) -> usize { + match self { + Self::MaxIterations(d) => *d, + Self::Both { max_iterations, .. } => *max_iterations, + _ => usize::MAX, + } + } +} + /// Prints out the system software/hardware information in the logs. pub fn print_sysinfo(sysinfo: &sc_telemetry::SysInfo) { log::info!("💻 Operating system: {}", TARGET_OS); diff --git a/client/sysinfo/src/sysinfo.rs b/client/sysinfo/src/sysinfo.rs index ceb28447002cf..65d7a9e41b406 100644 --- a/client/sysinfo/src/sysinfo.rs +++ b/client/sysinfo/src/sysinfo.rs @@ -16,9 +16,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::HwBench; -use rand::{seq::SliceRandom, Rng}; +use crate::{ExecutionLimit, HwBench}; + use sc_telemetry::SysInfo; +use sp_core::{sr25519, Pair}; +use sp_io::crypto::sr25519_verify; +use sp_std::prelude::*; + +use rand::{seq::SliceRandom, Rng, RngCore}; use std::{ fs::File, io::{Seek, SeekFrom, Write}, @@ -34,7 +39,7 @@ pub(crate) fn benchmark( max_iterations: usize, max_duration: Duration, mut run: impl FnMut() -> Result<(), E>, -) -> Result { +) -> Result { // Run the benchmark once as a warmup to get the code into the L1 cache. run()?; @@ -53,11 +58,11 @@ pub(crate) fn benchmark( } } - let score = (((size * count) as f64 / elapsed.as_secs_f64()) / (1024.0 * 1024.0)) as u64; + let score = ((size * count) as f64 / elapsed.as_secs_f64()) / (1024.0 * 1024.0); log::trace!( "Calculated {} of {}MB/s in {} iterations in {}ms", name, - score, + score as u64, count, elapsed.as_millis() ); @@ -83,7 +88,7 @@ pub fn gather_sysinfo() -> SysInfo { } #[inline(never)] -fn clobber(slice: &mut [u8]) { +fn clobber_slice(slice: &mut [T]) { assert!(!slice.is_empty()); // Discourage the compiler from optimizing out our benchmarks. @@ -102,8 +107,17 @@ fn clobber(slice: &mut [u8]) { } } +#[inline(never)] +fn clobber_value(input: &mut T) { + // Look into `clobber_slice` for a comment. + unsafe { + let value = std::ptr::read_volatile(input); + std::ptr::write_volatile(input, value); + } +} + // This benchmarks the CPU speed as measured by calculating BLAKE2b-256 hashes, in MB/s. -fn benchmark_cpu() -> u64 { +pub fn benchmark_cpu() -> u64 { // In general the results of this benchmark are somewhat sensitive to how much // data we hash at the time. The smaller this is the *less* MB/s we can hash, // the bigger this is the *more* MB/s we can hash, up until a certain point @@ -125,15 +139,15 @@ fn benchmark_cpu() -> u64 { let mut hash = Default::default(); let run = || -> Result<(), ()> { - clobber(&mut buffer); + clobber_slice(&mut buffer); hash = sp_core::hashing::blake2_256(&buffer); - clobber(&mut hash); + clobber_slice(&mut hash); Ok(()) }; benchmark("CPU score", SIZE, MAX_ITERATIONS, MAX_DURATION, run) - .expect("benchmark cannot fail; qed") + .expect("benchmark cannot fail; qed") as u64 } // This benchmarks the effective `memcpy` memory bandwidth available in MB/s. @@ -141,7 +155,7 @@ fn benchmark_cpu() -> u64 { // It doesn't technically measure the absolute maximum memory bandwidth available, // but that's fine, because real code most of the time isn't optimized to take // advantage of the full memory bandwidth either. -fn benchmark_memory() -> u64 { +pub fn benchmark_memory() -> u64 { // Ideally this should be at least as big as the CPU's L3 cache, // and it should be big enough so that the `memcpy` takes enough // time to be actually measurable. @@ -161,8 +175,8 @@ fn benchmark_memory() -> u64 { dst.resize(SIZE, 0x77); let run = || -> Result<(), ()> { - clobber(&mut src); - clobber(&mut dst); + clobber_slice(&mut src); + clobber_slice(&mut dst); // SAFETY: Both vectors are of the same type and of the same size, // so copying data between them is safe. @@ -172,14 +186,14 @@ fn benchmark_memory() -> u64 { libc::memcpy(dst.as_mut_ptr().cast(), src.as_ptr().cast(), SIZE); } - clobber(&mut dst); - clobber(&mut src); + clobber_slice(&mut dst); + clobber_slice(&mut src); Ok(()) }; benchmark("memory score", SIZE, MAX_ITERATIONS, MAX_DURATION, run) - .expect("benchmark cannot fail; qed") + .expect("benchmark cannot fail; qed") as u64 } struct TemporaryFile { @@ -260,6 +274,7 @@ pub fn benchmark_disk_sequential_writes(directory: &Path) -> Result }; benchmark("disk sequential write score", SIZE, MAX_ITERATIONS, MAX_DURATION, run) + .map(|s| s as u64) } pub fn benchmark_disk_random_writes(directory: &Path) -> Result { @@ -319,6 +334,45 @@ pub fn benchmark_disk_random_writes(directory: &Path) -> Result { // We only wrote half of the bytes hence `SIZE / 2`. benchmark("disk random write score", SIZE / 2, MAX_ITERATIONS, MAX_DURATION, run) + .map(|s| s as u64) +} + +/// Benchmarks the verification speed of sr25519 signatures. +/// +/// Returns the throughput in MB/s by convention. +/// The values are rather small (0.4-0.8) so it is advised to convert them into KB/s. +pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> f64 { + const INPUT_SIZE: usize = 32; + const ITERATION_SIZE: usize = 2048; + let pair = sr25519::Pair::from_string("//Alice", None).unwrap(); + + let mut rng = rng(); + let mut msgs = Vec::new(); + let mut sigs = Vec::new(); + + for _ in 0..ITERATION_SIZE { + let mut msg = vec![0u8; INPUT_SIZE]; + rng.fill_bytes(&mut msg[..]); + + sigs.push(pair.sign(&msg)); + msgs.push(msg); + } + + let run = || -> Result<(), String> { + for (sig, msg) in sigs.iter().zip(msgs.iter()) { + let mut ok = sr25519_verify(&sig, &msg[..], &pair.public()); + clobber_value(&mut ok); + } + Ok(()) + }; + benchmark( + "sr25519 verification score", + INPUT_SIZE * ITERATION_SIZE, + limit.max_iterations(), + limit.max_duration(), + run, + ) + .expect("sr25519 verification cannot fail; qed") } /// Benchmarks the hardware and returns the results of those benchmarks. @@ -390,4 +444,9 @@ mod tests { fn test_benchmark_disk_random_writes() { assert!(benchmark_disk_random_writes("./".as_ref()).unwrap() > 0); } + + #[test] + fn test_benchmark_sr25519_verify() { + assert!(benchmark_sr25519_verify(ExecutionLimit::MaxIterations(1)) > 0.0); + } } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 5cb81232085a4..858d16558e821 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -23,6 +23,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } +sc-sysinfo = { version = "6.0.0-dev", path = "../../../client/sysinfo" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } @@ -32,7 +33,6 @@ sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } codec = { version = "3.0.0", package = "parity-scale-codec" } @@ -52,6 +52,9 @@ hex = "0.4.3" memory-db = "0.29.0" rand = { version = "0.8.4", features = ["small_rng"] } thousands = "0.2.0" +prettytable-rs = "0.8.0" +tempfile = "3.2.0" +rand_pcg = "0.3.1" [features] default = ["db", "sc-client-db/runtime-benchmarks"] diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 2543a63b2f159..75e2edc042a26 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -18,12 +18,14 @@ //! Contains the root [`BenchmarkCmd`] command and exports its sub-commands. mod block; +mod machine; mod overhead; mod pallet; mod shared; mod storage; pub use block::BlockCmd; +pub use machine::MachineCmd; pub use overhead::{ExtrinsicBuilder, OverheadCmd}; pub use pallet::PalletCmd; pub use storage::StorageCmd; @@ -39,6 +41,8 @@ pub enum BenchmarkCmd { Storage(StorageCmd), Overhead(OverheadCmd), Block(BlockCmd), + #[clap(hide = true)] // Hidden until fully completed. + Machine(MachineCmd), } /// Unwraps a [`BenchmarkCmd`] into its concrete sub-command. @@ -53,6 +57,7 @@ macro_rules! unwrap_cmd { BenchmarkCmd::Storage($cmd) => $code, BenchmarkCmd::Overhead($cmd) => $code, BenchmarkCmd::Block($cmd) => $code, + BenchmarkCmd::Machine($cmd) => $code, } } } diff --git a/utils/frame/benchmarking-cli/src/machine/mod.rs b/utils/frame/benchmarking-cli/src/machine/mod.rs new file mode 100644 index 0000000000000..ee6bf765d01c4 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -0,0 +1,86 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains the [`MachineCmd`] as entry point for the node +//! and the core benchmarking logic. + +use sc_cli::{CliConfiguration, Result, SharedParams}; +use sc_service::Configuration; +use sc_sysinfo::{ + benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes, + benchmark_memory, benchmark_sr25519_verify, ExecutionLimit, +}; + +use clap::Parser; +use log::info; +use prettytable::{cell, row, table}; +use std::{fmt::Debug, fs, time::Duration}; + +/// Command to benchmark the hardware. +/// +/// Runs multiple benchmarks and prints their output to console. +/// Can be used to gauge if the hardware is fast enough to keep up with a chain's requirements. +/// This command must be integrated by the client since the client can set compiler flags +/// which influence the results. +/// +/// You can use the `--base-path` flag to set a location for the disk benchmarks. +#[derive(Debug, Parser)] +pub struct MachineCmd { + #[allow(missing_docs)] + #[clap(flatten)] + pub shared_params: SharedParams, + + /// Time limit for the verification benchmark. + #[clap(long, default_value = "2.0", value_name = "SECONDS")] + pub verify_duration: f32, +} + +impl MachineCmd { + /// Execute the benchmark and print the results. + pub fn run(&self, cfg: &Configuration) -> Result<()> { + // Ensure that the dir exists since the node is not started to take care of it. + let dir = cfg.database.path().ok_or("No DB directory provided")?; + fs::create_dir_all(dir)?; + + info!("Running machine benchmarks..."); + let write = benchmark_disk_sequential_writes(dir)?; + let read = benchmark_disk_random_writes(dir)?; + let verify_limit = + ExecutionLimit::MaxDuration(Duration::from_secs_f32(self.verify_duration)); + let verify = benchmark_sr25519_verify(verify_limit) * 1024.0; + + // Use a table for nicer console output. + let table = table!( + ["Category", "Function", "Score", "Unit"], + ["CPU", "BLAKE2-256", benchmark_cpu(), "MB/s"], + ["CPU", "SR25519 Verify", format!("{:.1}", verify), "KB/s"], + ["Memory", "Copy", benchmark_memory(), "MB/s"], + ["Disk", "Seq Write", write, "MB/s"], + ["Disk", "Rnd Write", read, "MB/s"] + ); + + info!("\n{}", table); + Ok(()) + } +} + +// Boilerplate +impl CliConfiguration for MachineCmd { + fn shared_params(&self) -> &SharedParams { + &self.shared_params + } +} diff --git a/utils/frame/benchmarking-cli/src/shared/mod.rs b/utils/frame/benchmarking-cli/src/shared/mod.rs index f08d79b9aafca..853fbdef8e87f 100644 --- a/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -25,6 +25,8 @@ pub use record::BenchRecord; pub use stats::{StatSelect, Stats}; pub use weight_params::WeightParams; +use rand::prelude::*; + /// A Handlebars helper to add an underscore after every 3rd character, /// i.e. a separator for large numbers. #[derive(Clone, Copy)] @@ -63,3 +65,11 @@ where } s } + +/// Returns an rng and the seed that was used to create it. +/// +/// Uses a random seed if none is provided. +pub fn new_rng(seed: Option) -> (impl rand::Rng, u64) { + let seed = seed.unwrap_or(rand::thread_rng().gen::()); + (rand_pcg::Pcg64::seed_from_u64(seed), seed) +} diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index c2cc219ef1528..23222dbd120ab 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -34,7 +34,7 @@ use sp_runtime::generic::BlockId; use std::{fmt::Debug, path::PathBuf, sync::Arc}; use super::template::TemplateData; -use crate::shared::WeightParams; +use crate::shared::{new_rng, WeightParams}; /// Benchmark the storage speed of a chain snapshot. #[derive(Debug, Parser)] @@ -151,13 +151,6 @@ impl StorageCmd { } } - /// Creates an rng from a random seed. - pub(crate) fn setup_rng() -> impl rand::Rng { - let seed = rand::thread_rng().gen::(); - info!("Using seed {}", seed); - StdRng::seed_from_u64(seed) - } - /// Run some rounds of the (read) benchmark as warmup. /// See `frame_benchmarking_cli::storage::read::bench_read` for detailed comments. fn bench_warmup(&self, client: &Arc) -> Result<()> @@ -169,7 +162,7 @@ impl StorageCmd { let block = BlockId::Number(client.usage_info().chain.best_number); let empty_prefix = StorageKey(Vec::new()); let mut keys = client.storage_keys(&block, &empty_prefix)?; - let mut rng = Self::setup_rng(); + let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); for i in 0..self.params.warmups { diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs index f58f3c3de0c19..c1dc6daba0953 100644 --- a/utils/frame/benchmarking-cli/src/storage/read.rs +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -28,7 +28,7 @@ use rand::prelude::*; use std::{fmt::Debug, sync::Arc, time::Instant}; use super::cmd::StorageCmd; -use crate::shared::BenchRecord; +use crate::shared::{new_rng, BenchRecord}; impl StorageCmd { /// Benchmarks the time it takes to read a single Storage item. @@ -47,7 +47,7 @@ impl StorageCmd { // Load all keys and randomly shuffle them. let empty_prefix = StorageKey(Vec::new()); let mut keys = client.storage_keys(&block, &empty_prefix)?; - let mut rng = Self::setup_rng(); + let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); // Interesting part here: diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index d5d5bc2fffa5b..ab25109a35d49 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -32,7 +32,7 @@ use rand::prelude::*; use std::{fmt::Debug, sync::Arc, time::Instant}; use super::cmd::StorageCmd; -use crate::shared::BenchRecord; +use crate::shared::{new_rng, BenchRecord}; impl StorageCmd { /// Benchmarks the time it takes to write a single Storage item. @@ -59,7 +59,7 @@ impl StorageCmd { info!("Preparing keys from block {}", block); // Load all KV pairs and randomly shuffle them. let mut kvs = trie.pairs(); - let mut rng = Self::setup_rng(); + let (mut rng, _) = new_rng(None); kvs.shuffle(&mut rng); // Generate all random values first; Make sure there are no collisions with existing From b7697f085d7bad89e5a794780c8903ee18dcebd8 Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Sat, 16 Apr 2022 02:55:37 -0700 Subject: [PATCH 0704/1472] Child bounties comments (#11053) * * formatting * use uniform notion of parent and child, no "master" or "general" entity * README updated to match comments * `parent_index` used over simply `index` * rm `parent_*` change * parent_bounty_id * parent_index rm * fmt * Apply suggestions from code review --- frame/bounties/README.md | 46 ++++++++++++++++++----------- frame/bounties/src/lib.rs | 24 ++++++++++----- frame/child-bounties/README.md | 30 ++++++++++++------- frame/child-bounties/src/lib.rs | 52 ++++++++++++++++----------------- 4 files changed, 90 insertions(+), 62 deletions(-) diff --git a/frame/bounties/README.md b/frame/bounties/README.md index bf63fca5f34b2..232334cb1edd6 100644 --- a/frame/bounties/README.md +++ b/frame/bounties/README.md @@ -2,28 +2,38 @@ ## Bounty -**Note :: This pallet is tightly coupled with pallet-treasury** +> NOTE: This pallet is tightly coupled with pallet-treasury. -A Bounty Spending is a reward for a specified body of work - or specified set of objectives - that -needs to be executed for a predefined Treasury amount to be paid out. A curator is assigned after -the bounty is approved and funded by Council, to be delegated with the responsibility of assigning a -payout address once the specified set of objectives is completed. +A Bounty Spending is a reward for a specified body of work - or specified set of objectives - +that needs to be executed for a predefined Treasury amount to be paid out. A curator is assigned +after the bounty is approved and funded by Council, to be delegated with the responsibility of +assigning a payout address once the specified set of objectives is completed. -After the Council has activated a bounty, it delegates the work that requires expertise to a curator -in exchange of a deposit. Once the curator accepts the bounty, they get to close the active bounty. -Closing the active bounty enacts a delayed payout to the payout address, the curator fee and the -return of the curator deposit. The delay allows for intervention through regular democracy. The -Council gets to unassign the curator, resulting in a new curator election. The Council also gets to -cancel the bounty if deemed necessary before assigning a curator or once the bounty is active or -payout is pending, resulting in the slash of the curator's deposit. +After the Council has activated a bounty, it delegates the work that requires expertise to a +curator in exchange of a deposit. Once the curator accepts the bounty, they get to close the +active bounty. Closing the active bounty enacts a delayed payout to the payout address, the +curator fee and the return of the curator deposit. The delay allows for intervention through +regular democracy. The Council gets to unassign the curator, resulting in a new curator +election. The Council also gets to cancel the bounty if deemed necessary before assigning a +curator or once the bounty is active or payout is pending, resulting in the slash of the +curator's deposit. + +This pallet may opt into using a [`ChildBountyManager`] that enables bounties to be split into +sub-bounties, as children of anh established bounty (called the parent in the context of it's +children). + +> NOTE: The parent bounty cannot be closed if it has a non-zero number of it has active child +> bounties associated with it. ### Terminology -- **Bounty spending proposal:** A proposal to reward a predefined body of work upon completion by - the Treasury. +Bounty: + +- **Bounty spending proposal:** A proposal to reward a predefined body of work upon completion + by the Treasury. - **Proposer:** An account proposing a bounty spending. -- **Curator:** An account managing the bounty and assigning a payout address receiving the reward - for the completion of work. +- **Curator:** An account managing the bounty and assigning a payout address receiving the + reward for the completion of work. - **Deposit:** The amount held on deposit for placing a bounty proposal plus the amount held on deposit per byte within the bounty description. - **Curator deposit:** The payment from a candidate willing to curate an approved bounty. The @@ -31,7 +41,8 @@ payout is pending, resulting in the slash of the curator's deposit. - **Bounty value:** The total amount that should be paid to the Payout Address if the bounty is rewarded. - **Payout address:** The account to which the total or part of the bounty is assigned to. -- **Payout Delay:** The delay period for which a bounty beneficiary needs to wait before claiming. +- **Payout Delay:** The delay period for which a bounty beneficiary needs to wait before + claiming. - **Curator fee:** The reserved upfront payment for a curator for work related to the bounty. ## Interface @@ -39,6 +50,7 @@ payout is pending, resulting in the slash of the curator's deposit. ### Dispatchable Functions Bounty protocol: + - `propose_bounty` - Propose a specific treasury amount to be earmarked for a predefined set of tasks and stake the required deposit. - `approve_bounty` - Accept a specific treasury amount to be earmarked for a predefined body of diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 98f2da305a06d..886c758bbe42e 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -35,10 +35,17 @@ //! curator or once the bounty is active or payout is pending, resulting in the slash of the //! curator's deposit. //! +//! This pallet may opt into using a [`ChildBountyManager`] that enables bounties to be split into +//! sub-bounties, as children of anh established bounty (called the parent in the context of it's +//! children). +//! +//! > NOTE: The parent bounty cannot be closed if it has a non-zero number of it has active child +//! > bounties associated with it. //! //! ### Terminology //! //! Bounty: +//! //! - **Bounty spending proposal:** A proposal to reward a predefined body of work upon completion //! by the Treasury. //! - **Proposer:** An account proposing a bounty spending. @@ -60,6 +67,7 @@ //! ### Dispatchable Functions //! //! Bounty protocol: +//! //! - `propose_bounty` - Propose a specific treasury amount to be earmarked for a predefined set of //! tasks and stake the required deposit. //! - `approve_bounty` - Accept a specific treasury amount to be earmarked for a predefined body of @@ -165,9 +173,9 @@ pub enum BountyStatus { }, } -/// The child-bounty manager. +/// The child bounty manager. pub trait ChildBountyManager { - /// Get the active child-bounties for a parent bounty. + /// Get the active child bounties for a parent bounty. fn child_bounties_count(bounty_id: BountyIndex) -> BountyIndex; /// Get total curator fees of children-bounty curators. @@ -231,7 +239,7 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; - /// The child-bounty manager. + /// The child bounty manager. type ChildBountyManager: ChildBountyManager>; } @@ -256,7 +264,7 @@ pub mod pallet { PendingPayout, /// The bounties cannot be claimed/closed because it's still in the countdown period. Premature, - /// The bounty cannot be closed because it has active child-bounties. + /// The bounty cannot be closed because it has active child bounties. HasActiveChildBounty, /// Too many approvals are already queued. TooManyQueued, @@ -552,7 +560,7 @@ pub mod pallet { Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; - // Ensure no active child-bounties before processing the call. + // Ensure no active child bounties before processing the call. ensure!( T::ChildBountyManager::child_bounties_count(bounty_id) == 0, Error::::HasActiveChildBounty @@ -610,8 +618,8 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&curator, bounty.curator_deposit); debug_assert!(err_amount.is_zero()); - // Get total child-bounties curator fees, and subtract it from master curator - // fee. + // Get total child bounties curator fees, and subtract it from the parent + // curator fee (the fee in present referenced bounty, `self`). let children_fee = T::ChildBountyManager::children_curator_fees(bounty_id); debug_assert!(children_fee <= fee); @@ -663,7 +671,7 @@ pub mod pallet { |maybe_bounty| -> DispatchResultWithPostInfo { let bounty = maybe_bounty.as_ref().ok_or(Error::::InvalidIndex)?; - // Ensure no active child-bounties before processing the call. + // Ensure no active child bounties before processing the call. ensure!( T::ChildBountyManager::child_bounties_count(bounty_id) == 0, Error::::HasActiveChildBounty diff --git a/frame/child-bounties/README.md b/frame/child-bounties/README.md index e07996d54957a..695b6616b1751 100644 --- a/frame/child-bounties/README.md +++ b/frame/child-bounties/README.md @@ -1,21 +1,29 @@ -# Child Bounties Pallet (pallet-child-bounties) +# Child Bounties Pallet ( `pallet-child-bounties` ) ## Child Bounty -> NOTE: This pallet is tightly coupled with pallet-treasury and pallet-bounties. +> NOTE: This pallet is tightly coupled with `pallet-treasury` and `pallet-bounties`. -With child bounties, a large bounty proposal can be divided into smaller chunks, for parallel execution, and for efficient governance and tracking of spent funds. - -A child-bounty is a smaller piece of work, extracted from a parent bounty. A curator is assigned after the child-bounty is created by the parent bounty curator, to be delegated with the responsibility of assigning a payout address once the specified set of tasks is completed. +With child bounties, a large bounty proposal can be divided into smaller chunks, +for parallel execution, and for efficient governance and tracking of spent funds. +A child bounty is a smaller piece of work, extracted from a parent bounty. +A curator is assigned after the child bounty is created by the parent bounty curator, +to be delegated with the responsibility of assigning a payout address once +the specified set of tasks is completed. ## Interface ### Dispatchable Functions -- `add_child_bounty` - Add a child-bounty for a parent-bounty to for dividing the work in smaller tasks. -- `propose_curator` - Assign an account to a child-bounty as candidate curator. -- `accept_curator` - Accept a child-bounty assignment from the parent-bounty curator, setting a curator deposit. +Child Bounty protocol: + +- `add_child_bounty` - Add a child bounty for a parent bounty to for dividing the work in + smaller tasks. +- `propose_curator` - Assign an account to a child bounty as candidate curator. +- `accept_curator` - Accept a child bounty assignment from the parent bounty curator, + setting a curator deposit. - `award_child_bounty` - Close and pay out the specified amount for the completed work. -- `claim_child_bounty` - Claim a specific child-bounty amount from the payout address. -- `unassign_curator` - Unassign an accepted curator from a specific child-bounty. -- `close_child_bounty` - Cancel the child-bounty for a specific treasury amount and close the bounty. +- `claim_child_bounty` - Claim a specific child bounty amount from the payout address. +- `unassign_curator` - Unassign an accepted curator from a specific child bounty. +- `close_child_bounty` - Cancel the child bounty for a specific treasury amount + and close the bounty. diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 2fea61c045cf6..0bbd4512443d7 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Child Bounties Pallet ( pallet-child-bounties ) +//! # Child Bounties Pallet ( `pallet-child-bounties` ) //! //! ## Child Bounty //! -//! > NOTE: This pallet is tightly coupled with pallet-treasury and pallet-bounties. +//! > NOTE: This pallet is tightly coupled with `pallet-treasury` and `pallet-bounties`. //! //! With child bounties, a large bounty proposal can be divided into smaller chunks, //! for parallel execution, and for efficient governance and tracking of spent funds. -//! A child-bounty is a smaller piece of work, extracted from a parent bounty. -//! A curator is assigned after the child-bounty is created by the parent bounty curator, +//! A child bounty is a smaller piece of work, extracted from a parent bounty. +//! A curator is assigned after the child bounty is created by the parent bounty curator, //! to be delegated with the responsibility of assigning a payout address once the specified //! set of tasks is completed. //! @@ -33,22 +33,22 @@ //! ### Dispatchable Functions //! //! Child Bounty protocol: -//! - `add_child_bounty` - Add a child-bounty for a parent-bounty to for dividing the work in +//! - `add_child_bounty` - Add a child bounty for a parent bounty to for dividing the work in //! smaller tasks. -//! - `propose_curator` - Assign an account to a child-bounty as candidate curator. -//! - `accept_curator` - Accept a child-bounty assignment from the parent-bounty curator, setting a +//! - `propose_curator` - Assign an account to a child bounty as candidate curator. +//! - `accept_curator` - Accept a child bounty assignment from the parent bounty curator, setting a //! curator deposit. //! - `award_child_bounty` - Close and pay out the specified amount for the completed work. -//! - `claim_child_bounty` - Claim a specific child-bounty amount from the payout address. -//! - `unassign_curator` - Unassign an accepted curator from a specific child-bounty. -//! - `close_child_bounty` - Cancel the child-bounty for a specific treasury amount and close the +//! - `claim_child_bounty` - Claim a specific child bounty amount from the payout address. +//! - `unassign_curator` - Unassign an accepted curator from a specific child bounty. +//! - `close_child_bounty` - Cancel the child bounty for a specific treasury amount and close the //! bounty. // Most of the business logic in this pallet has been // originally contributed by "https://github.com/shamb0", // as part of the PR - https://github.com/paritytech/substrate/pull/7965. // The code has been moved here and then refactored in order to -// extract child-bounties as a separate pallet. +// extract child bounties as a separate pallet. #![cfg_attr(not(feature = "std"), no_std)] @@ -101,7 +101,7 @@ pub struct ChildBounty { pub enum ChildBountyStatus { /// The child-bounty is added and waiting for curator assignment. Added, - /// A curator has been proposed by the parent-bounty curator. Waiting for + /// A curator has been proposed by the parent bounty curator. Waiting for /// acceptance from the child-bounty curator. CuratorProposed { /// The assigned child-bounty curator of this bounty. @@ -136,7 +136,7 @@ pub mod pallet { pub trait Config: frame_system::Config + pallet_treasury::Config + pallet_bounties::Config { - /// Maximum number of child-bounties that can be added to a parent bounty. + /// Maximum number of child bounties that can be added to a parent bounty. #[pallet::constant] type MaxActiveChildBountyCount: Get; @@ -157,7 +157,7 @@ pub mod pallet { ParentBountyNotActive, /// The bounty balance is not enough to add new child-bounty. InsufficientBountyBalance, - /// Number of child-bounties exceeds limit `MaxActiveChildBountyCount`. + /// Number of child bounties exceeds limit `MaxActiveChildBountyCount`. TooManyChildBounties, } @@ -184,14 +184,14 @@ pub mod pallet { #[pallet::getter(fn child_bounty_count)] pub type ChildBountyCount = StorageValue<_, BountyIndex, ValueQuery>; - /// Number of child-bounties per parent bounty. + /// Number of child bounties per parent bounty. /// Map of parent bounty index to number of child bounties. #[pallet::storage] #[pallet::getter(fn parent_child_bounties)] pub type ParentChildBounties = StorageMap<_, Twox64Concat, BountyIndex, u32, ValueQuery>; - /// Child-bounties that have been added. + /// Child bounties that have been added. #[pallet::storage] #[pallet::getter(fn child_bounties)] pub type ChildBounties = StorageDoubleMap< @@ -226,7 +226,7 @@ pub mod pallet { /// parent bounty to child-bounty account, if parent bounty has enough /// funds, else the call fails. /// - /// Upper bound to maximum number of active child-bounties that can be + /// Upper bound to maximum number of active child bounties that can be /// added are managed via runtime trait config /// [`Config::MaxActiveChildBountyCount`]. /// @@ -427,12 +427,12 @@ pub mod pallet { /// the curator of the parent bounty, or any signed origin. /// /// For the origin other than T::RejectOrigin and the child-bounty - /// curator, parent-bounty must be in active state, for this call to + /// curator, parent bounty must be in active state, for this call to /// work. We allow child-bounty curator and T::RejectOrigin to execute - /// this call irrespective of the parent-bounty state. + /// this call irrespective of the parent bounty state. /// /// If this function is called by the `RejectOrigin` or the - /// parent-bounty curator, we assume that the child-bounty curator is + /// parent bounty curator, we assume that the child-bounty curator is /// malicious or inactive. As a result, child-bounty curator deposit is /// slashed. /// @@ -486,7 +486,7 @@ pub mod pallet { }, ChildBountyStatus::CuratorProposed { ref curator } => { // A child-bounty curator has been proposed, but not accepted yet. - // Either `RejectOrigin`, parent-bounty curator or the proposed + // Either `RejectOrigin`, parent bounty curator or the proposed // child-bounty curator can unassign the child-bounty curator. ensure!( maybe_sender.map_or(true, |sender| { @@ -524,7 +524,7 @@ pub mod pallet { update_due < frame_system::Pallet::::block_number() { // Slash the child-bounty curator if - // + the call is made by the parent-bounty curator. + // + the call is made by the parent bounty curator. // + or the curator is inactive. slash_curator(curator, &mut child_bounty.curator_deposit); // Continue to change bounty status below. @@ -556,7 +556,7 @@ pub mod pallet { /// /// The beneficiary will be able to claim the funds after a delay. /// - /// The dispatch origin for this call must be the master curator or + /// The dispatch origin for this call must be the parent curator or /// curator of this child-bounty. /// /// Parent bounty must be in active state, for this child-bounty call to @@ -835,7 +835,7 @@ impl Pallet { // Nothing extra to do besides the removal of the child-bounty below. }, ChildBountyStatus::Active { curator } => { - // Cancelled by master curator or RejectOrigin, + // Cancelled by parent curator or RejectOrigin, // refund deposit of the working child-bounty curator. let _ = T::Currency::unreserve(curator, child_bounty.curator_deposit); // Then execute removal of the child-bounty below. @@ -850,7 +850,7 @@ impl Pallet { }, } - // Revert the curator fee back to parent-bounty curator & + // Revert the curator fee back to parent bounty curator & // reduce the active child-bounty count. ChildrenCuratorFees::::mutate(parent_bounty_id, |value| { *value = value.saturating_sub(child_bounty.fee) @@ -888,7 +888,7 @@ impl Pallet { } // Implement ChildBountyManager to connect with the bounties pallet. This is -// where we pass the active child-bounties and child curator fees to the parent +// where we pass the active child bounties and child curator fees to the parent // bounty. impl pallet_bounties::ChildBountyManager> for Pallet { fn child_bounties_count( From a5cd3852d144289777dd4b914b6b3aa7d13bcd85 Mon Sep 17 00:00:00 2001 From: Alexander Gryaznov Date: Sat, 16 Apr 2022 15:51:40 +0300 Subject: [PATCH 0705/1472] Add `frame_support::crypto::ecdsa::Public.to_eth_address()` (`k256`-based) and use it in pallets (#11087) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `ecdsa::Public::to_eth_address` + test, beefy-mmr `convert()` to use it, contracts Ext interface * `seal_ecdsa_to_eth_address` all but benchmark done * `seal_ecdsa_to_eth_address` + wasm test * `seal_ecdsa_to_eth_address` + benchmark * fixed dependencies * Apply suggestions from code review Co-authored-by: Alexander Theißen * fixes from review #1 * ecdsa::Public(*pk).to_eth_address() moved to frame_support and contracts to use it * beefy-mmr to use newly added frame_support function for convertion * a doc fix * import fix * benchmark fix-1 (still fails) * benchmark fixed * Apply suggestions from code review Co-authored-by: Alexander Theißen * fixes on Alex T feedback * to_eth_address() put into extension trait for sp-core::ecdsa::Public * Update frame/support/src/crypto/ecdsa.rs Co-authored-by: Alexander Theißen * Update frame/contracts/src/wasm/mod.rs Co-authored-by: Alexander Theißen * fixes on issues pointed out in review * benchmark errors fixed * fmt fix * EcdsaRecoverFailed err docs updated * Apply suggestions from code review Co-authored-by: Bastian Köcher * make applied suggestions compile * get rid of unwrap() in runtime * Remove expect Co-authored-by: Alexander Theißen Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- Cargo.lock | 43 +++++++--------------- frame/beefy-mmr/Cargo.toml | 2 - frame/beefy-mmr/src/lib.rs | 19 ++++------ frame/contracts/src/benchmarking/mod.rs | 38 +++++++++++++++++++ frame/contracts/src/exec.rs | 43 +++++++++++++++++++++- frame/contracts/src/schedule.rs | 4 ++ frame/contracts/src/wasm/mod.rs | 39 ++++++++++++++++++++ frame/contracts/src/wasm/runtime.rs | 48 +++++++++++++++++++++--- frame/contracts/src/weights.rs | 23 ++++++++++++ frame/support/Cargo.toml | 1 + frame/support/src/crypto.rs | 21 +++++++++++ frame/support/src/crypto/ecdsa.rs | 49 +++++++++++++++++++++++++ frame/support/src/lib.rs | 1 + 13 files changed, 283 insertions(+), 48 deletions(-) create mode 100644 frame/support/src/crypto.rs create mode 100644 frame/support/src/crypto/ecdsa.rs diff --git a/Cargo.lock b/Cargo.lock index 52c6daad6b422..3e37bcfd167e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -456,12 +456,6 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" -[[package]] -name = "base64ct" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874f8444adcb4952a8bc51305c8be95c8ec8237bb0d2e78d2e039f771f8828a0" - [[package]] name = "beef" version = "0.5.1" @@ -1805,6 +1799,7 @@ checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" dependencies = [ "der", "elliptic-curve", + "rfc6979", "signature", ] @@ -2311,6 +2306,7 @@ dependencies = [ "frame-support-procedural", "frame-system", "impl-trait-for-tuples", + "k256", "log 0.4.14", "once_cell", "parity-scale-codec", @@ -5667,7 +5663,6 @@ dependencies = [ "frame-system", "hex", "hex-literal", - "k256", "log 0.4.14", "pallet-beefy", "pallet-mmr", @@ -7071,17 +7066,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs8" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" -dependencies = [ - "der", - "spki", - "zeroize", -] - [[package]] name = "pkg-config" version = "0.3.19" @@ -7871,6 +7855,17 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "448296241d034b96c11173591deaa1302f2c17b56092106c1f92c1bc0183a8c9" +[[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 = "ring" version = "0.16.20" @@ -9377,7 +9372,6 @@ checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" dependencies = [ "der", "generic-array 0.14.4", - "pkcs8", "subtle", "zeroize", ] @@ -9662,6 +9656,7 @@ 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.2", ] @@ -10588,16 +10583,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "spki" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "ss58-registry" version = "1.11.0" diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index a32b1dc6dbd64..9da8198b405f7 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -10,7 +10,6 @@ repository = "https://github.com/paritytech/substrate" [dependencies] hex = { version = "0.4", optional = true } codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } -k256 = { version = "0.10.2", default-features = false, features = ["arithmetic"] } log = { version = "0.4.13", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } @@ -42,7 +41,6 @@ std = [ "frame-support/std", "frame-system/std", "hex", - "k256/std", "log/std", "pallet-beefy/std", "pallet-mmr/std", diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 640ebeb7d49cc..8b904d6aefd5f 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -39,7 +39,7 @@ use sp_std::prelude::*; use beefy_primitives::mmr::{BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}; use pallet_mmr::{LeafDataProvider, ParentNumberAndHash}; -use frame_support::traits::Get; +use frame_support::{crypto::ecdsa::ECDSAExt, traits::Get}; pub use pallet::*; @@ -71,19 +71,16 @@ where pub struct BeefyEcdsaToEthereum; impl Convert> for BeefyEcdsaToEthereum { fn convert(a: beefy_primitives::crypto::AuthorityId) -> Vec { - use k256::{elliptic_curve::sec1::ToEncodedPoint, PublicKey}; - use sp_core::crypto::ByteArray; - - PublicKey::from_sec1_bytes(a.as_slice()) - .map(|pub_key| { - // uncompress the key - let uncompressed = pub_key.to_encoded_point(false); - // convert to ETH address - sp_io::hashing::keccak_256(&uncompressed.as_bytes()[1..])[12..].to_vec() - }) + sp_core::ecdsa::Public::try_from(a.as_ref()) .map_err(|_| { log::error!(target: "runtime::beefy", "Invalid BEEFY PublicKey format!"); }) + .unwrap_or(sp_core::ecdsa::Public::from_raw([0u8; 33])) + .to_eth_address() + .map(|v| v.to_vec()) + .map_err(|_| { + log::error!(target: "runtime::beefy", "Failed to convert BEEFY PublicKey to ETH address!"); + }) .unwrap_or_default() } } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index de83f51a01528..e67436fbc9d37 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1963,6 +1963,44 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + // Only calling the function itself for the list of + // generated different ECDSA keys. + seal_ecdsa_to_eth_address { + let r in 0 .. API_BENCHMARK_BATCHES; + let key_type = sp_core::crypto::KeyTypeId(*b"code"); + let pub_keys_bytes = (0..r * API_BENCHMARK_BATCH_SIZE) + .map(|_| { + sp_io::crypto::ecdsa_generate(key_type, None).0 + }) + .flatten() + .collect::>(); + let pub_keys_bytes_len = pub_keys_bytes.len() as i32; + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "seal_ecdsa_to_eth_address", + params: vec![ValueType::I32, ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: pub_keys_bytes, + }, + ], + call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, 33), // pub_key_ptr + Regular(Instruction::I32Const(pub_keys_bytes_len)), // out_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + seal_set_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; let code_hashes = (0..r * API_BENCHMARK_BATCH_SIZE) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 7aa5c0b731fad..54a5223b53d21 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -22,6 +22,7 @@ use crate::{ Pallet as Contracts, Schedule, }; use frame_support::{ + crypto::ecdsa::ECDSAExt, dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable}, storage::{with_transaction, TransactionOutcome}, traits::{Contains, Currency, ExistenceRequirement, OriginTrait, Randomness, Time}, @@ -30,7 +31,7 @@ use frame_support::{ use frame_system::RawOrigin; use pallet_contracts_primitives::ExecReturnValue; use smallvec::{Array, SmallVec}; -use sp_core::crypto::UncheckedFrom; +use sp_core::{crypto::UncheckedFrom, ecdsa::Public as ECDSAPublic}; use sp_io::crypto::secp256k1_ecdsa_recover_compressed; use sp_runtime::traits::Convert; use sp_std::{marker::PhantomData, mem, prelude::*}; @@ -232,6 +233,9 @@ pub trait Ext: sealing::Sealed { /// Recovers ECDSA compressed public key based on signature and message hash. fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()>; + /// Returns Ethereum address from the ECDSA compressed public key. + fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()>; + /// Tests sometimes need to modify and inspect the contract info directly. #[cfg(test)] fn contract_info(&mut self) -> &mut ContractInfo; @@ -1204,6 +1208,10 @@ where secp256k1_ecdsa_recover_compressed(&signature, &message_hash).map_err(|_| ()) } + fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()> { + ECDSAPublic(*pk).to_eth_address() + } + #[cfg(test)] fn contract_info(&mut self) -> &mut ContractInfo { self.top_frame_mut().contract_info() @@ -1267,6 +1275,7 @@ mod tests { use codec::{Decode, Encode}; use frame_support::{assert_err, assert_ok}; use frame_system::{EventRecord, Phase}; + use hex_literal::hex; use pallet_contracts_primitives::ReturnFlags; use pretty_assertions::assert_eq; use sp_core::Bytes; @@ -2718,4 +2727,36 @@ mod tests { )); }); } + #[test] + fn ecdsa_to_eth_address_returns_proper_value() { + let bob_ch = MockLoader::insert(Call, |ctx, _| { + let pubkey_compressed: [u8; 33] = + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91")[..] + .try_into() + .unwrap(); + assert_eq!( + ctx.ext.ecdsa_to_eth_address(&pubkey_compressed).unwrap(), + hex!("09231da7b19A016f9e576d23B16277062F4d46A8")[..] + ); + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let schedule = ::Schedule::get(); + place_contract(&BOB, bob_ch); + + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); + let result = MockStack::run_call( + ALICE, + BOB, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + &schedule, + 0, + vec![], + None, + ); + assert_matches!(result, Ok(_)); + }); + } } diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index b0c58d721d578..bbbeb72f2cdf6 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -418,6 +418,9 @@ pub struct HostFnWeights { /// Weight of calling `seal_ecdsa_recover`. pub ecdsa_recover: Weight, + /// Weight of calling `seal_ecdsa_to_eth_address`. + pub ecdsa_to_eth_address: Weight, + /// The type parameter is used in the default implementation. #[codec(skip)] pub _phantom: PhantomData, @@ -653,6 +656,7 @@ impl Default for HostFnWeights { hash_blake2_128: cost_batched!(seal_hash_blake2_128), hash_blake2_128_per_byte: cost_byte_batched!(seal_hash_blake2_128_per_kb), ecdsa_recover: cost_batched!(seal_ecdsa_recover), + ecdsa_to_eth_address: cost_batched!(seal_ecdsa_to_eth_address), _phantom: PhantomData, } } diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index c38613cb68102..f12df06b938c8 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -503,6 +503,9 @@ mod tests { fn contract_info(&mut self) -> &mut crate::ContractInfo { unimplemented!() } + fn ecdsa_to_eth_address(&self, _pk: &[u8; 33]) -> Result<[u8; 20], ()> { + Ok([2u8; 20]) + } } fn execute>(wat: &str, input_data: Vec, mut ext: E) -> ExecResult { @@ -1085,6 +1088,42 @@ mod tests { assert_eq!(mock_ext.ecdsa_recover.into_inner(), [([1; 65], [1; 32])]); } + #[test] + #[cfg(feature = "unstable-interface")] + fn contract_ecdsa_to_eth_address() { + /// calls `seal_ecdsa_to_eth_address` for the contstant and ensures the result equals the + /// expected one. + const CODE_ECDSA_TO_ETH_ADDRESS: &str = r#" +(module + (import "__unstable__" "seal_ecdsa_to_eth_address" (func $seal_ecdsa_to_eth_address (param i32 i32) (result i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "env" "memory" (memory 1 1)) + + (func (export "call") + ;; fill the buffer with the eth address. + (call $seal_ecdsa_to_eth_address (i32.const 0) (i32.const 0)) + + ;; Return the contents of the buffer + (call $seal_return + (i32.const 0) + (i32.const 0) + (i32.const 20) + ) + + ;; seal_return doesn't return, so this is effectively unreachable. + (unreachable) + ) + (func (export "deploy")) +) +"#; + + let output = execute(CODE_ECDSA_TO_ETH_ADDRESS, vec![], MockExt::default()).unwrap(); + assert_eq!( + output, + ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes([0x02; 20].to_vec()) } + ); + } + const CODE_GET_STORAGE: &str = r#" (module (import "seal0" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32) (result i32))) diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 975cfcdd12db8..876bd8848b0b1 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -71,7 +71,9 @@ pub enum ReturnCode { /// The call dispatched by `seal_call_runtime` was executed but returned an error. #[cfg(feature = "unstable-interface")] CallRuntimeReturnedError = 10, - /// ECDSA pubkey recovery failed. Most probably wrong recovery id or signature. + /// ECDSA pubkey recovery failed (most probably wrong recovery id or signature), or + /// ECDSA compressed pubkey conversion into Ethereum address failed (most probably + /// wrong pubkey provided). #[cfg(feature = "unstable-interface")] EcdsaRecoverFailed = 11, } @@ -225,6 +227,9 @@ pub enum RuntimeCosts { /// Weight of calling `seal_set_code_hash` #[cfg(feature = "unstable-interface")] SetCodeHash, + /// Weight of calling `ecdsa_to_eth_address` + #[cfg(feature = "unstable-interface")] + EcdsaToEthAddress, } impl RuntimeCosts { @@ -309,6 +314,8 @@ impl RuntimeCosts { CallRuntime(weight) => weight, #[cfg(feature = "unstable-interface")] SetCodeHash => s.set_code_hash, + #[cfg(feature = "unstable-interface")] + EcdsaToEthAddress => s.ecdsa_to_eth_address, }; RuntimeToken { #[cfg(test)] @@ -1984,12 +1991,12 @@ define_env!(Env, , // # Parameters // // - `signature_ptr`: the pointer into the linear memory where the signature - // is placed. Should be decodable as a 65 bytes. Traps otherwise. + // is placed. Should be decodable as a 65 bytes. Traps otherwise. // - `message_hash_ptr`: the pointer into the linear memory where the message // hash is placed. Should be decodable as a 32 bytes. Traps otherwise. // - `output_ptr`: the pointer into the linear memory where the output - // data is placed. The buffer should be 33 bytes. Traps otherwise. - // The function will write the result directly into this buffer. + // data is placed. The buffer should be 33 bytes. The function + // will write the result directly into this buffer. // // # Errors // @@ -2036,7 +2043,7 @@ define_env!(Env, , // // # Parameters // - // - code_hash_ptr: A pointer to the buffer that contains the new code hash. + // - `code_hash_ptr`: A pointer to the buffer that contains the new code hash. // // # Errors // @@ -2052,4 +2059,35 @@ define_env!(Env, , Ok(()) => Ok(ReturnCode::Success) } }, + + // Calculates Ethereum address from the ECDSA compressed public key and stores + // it into the supplied buffer. + // + // # Parameters + // + // - `key_ptr`: a pointer to the ECDSA compressed public key. Should be decodable as a 33 bytes value. + // Traps otherwise. + // - `out_ptr`: the pointer into the linear memory where the output + // data is placed. The function will write the result + // directly into this buffer. + // + // The value is stored to linear memory at the address pointed to by `out_ptr`. + // If the available space at `out_ptr` is less than the size of the value a trap is triggered. + // + // # Errors + // + // `ReturnCode::EcdsaRecoverFailed` + [__unstable__] seal_ecdsa_to_eth_address(ctx, key_ptr: u32, out_ptr: u32) -> ReturnCode => { + ctx.charge_gas(RuntimeCosts::EcdsaToEthAddress)?; + let mut compressed_key: [u8; 33] = [0;33]; + ctx.read_sandbox_memory_into_buf(key_ptr, &mut compressed_key)?; + let result = ctx.ext.ecdsa_to_eth_address(&compressed_key); + match result { + Ok(eth_address) => { + ctx.write_sandbox_memory(out_ptr, eth_address.as_ref())?; + Ok(ReturnCode::Success) + }, + Err(_) => Ok(ReturnCode::EcdsaRecoverFailed), + } + }, ); diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 43f00196ab3b2..85ff2548ca698 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -103,6 +103,7 @@ pub trait WeightInfo { fn seal_hash_blake2_128(r: u32, ) -> Weight; fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight; fn seal_ecdsa_recover(r: u32, ) -> Weight; + fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight; fn seal_set_code_hash(r: u32, ) -> Weight; fn instr_i64const(r: u32, ) -> Weight; fn instr_i64load(r: u32, ) -> Weight; @@ -805,6 +806,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { + (272_893_000 as Weight) + // Standard Error: 1_438_000 + .saturating_add((15_412_877_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts OwnerInfoOf (r:36 w:36) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) @@ -1717,6 +1729,17 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { + (272_893_000 as Weight) + // Standard Error: 1_438_000 + .saturating_add((15_412_877_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts OwnerInfoOf (r:36 w:36) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index ec596494c601b..ce04fddb8521f 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -35,6 +35,7 @@ impl-trait-for-tuples = "0.2.2" smallvec = "1.8.0" log = { version = "0.4.14", default-features = false } sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } +k256 = { version = "0.10.2", default-features = false, features = ["ecdsa"] } [dev-dependencies] assert_matches = "1.3.0" diff --git a/frame/support/src/crypto.rs b/frame/support/src/crypto.rs new file mode 100644 index 0000000000000..182a784649d02 --- /dev/null +++ b/frame/support/src/crypto.rs @@ -0,0 +1,21 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Utilities for dealing with crypto primitives. Sometimes we need to use these from inside WASM +//! contracts, where crypto calculations have weak performance. + +pub mod ecdsa; diff --git a/frame/support/src/crypto/ecdsa.rs b/frame/support/src/crypto/ecdsa.rs new file mode 100644 index 0000000000000..a4a04acabe1df --- /dev/null +++ b/frame/support/src/crypto/ecdsa.rs @@ -0,0 +1,49 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Simple ECDSA secp256k1 API. +//! +//! Provides an extension trait for [`sp_core::ecdsa::Public`] to do certain operations. + +use sp_core::{crypto::ByteArray, ecdsa::Public}; + +/// Extension trait for [`Public`] to be used from inside the runtime. +/// +/// # Note +/// +/// This is needed because host functions cannot be called from within +/// `sp_core` due to cyclic dependencies on `sp_io`. +pub trait ECDSAExt { + /// Returns Ethereum address calculated from this ECDSA public key. + fn to_eth_address(&self) -> Result<[u8; 20], ()>; +} + +impl ECDSAExt for Public { + fn to_eth_address(&self) -> Result<[u8; 20], ()> { + use k256::{elliptic_curve::sec1::ToEncodedPoint, PublicKey}; + + PublicKey::from_sec1_bytes(self.as_slice()).map_err(drop).and_then(|pub_key| { + // uncompress the key + let uncompressed = pub_key.to_encoded_point(false); + // convert to ETH address + <[u8; 20]>::try_from( + sp_io::hashing::keccak_256(&uncompressed.as_bytes()[1..])[12..].as_ref(), + ) + .map_err(drop) + }) + } +} diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 714449eec7847..4484ff6b6b295 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -64,6 +64,7 @@ pub mod event; pub mod inherent; #[macro_use] pub mod error; +pub mod crypto; pub mod instances; pub mod migrations; pub mod traits; From 0a7e5ea46a17d71818eef8216e24eef0565bab57 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Mon, 18 Apr 2022 12:39:32 +0200 Subject: [PATCH 0706/1472] Remark storage (#10698) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remark storage * Fixed benches * Update frame/remark/src/lib.rs Co-authored-by: Bastian Köcher * Fixed build * Fixed build Co-authored-by: Bastian Köcher --- Cargo.lock | 17 ++++++ Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 3 + bin/node/runtime/src/lib.rs | 7 +++ frame/remark/Cargo.toml | 42 ++++++++++++++ frame/remark/README.md | 6 ++ frame/remark/src/benchmarking.rs | 47 +++++++++++++++ frame/remark/src/lib.rs | 85 ++++++++++++++++++++++++++++ frame/remark/src/mock.rs | 79 ++++++++++++++++++++++++++ frame/remark/src/tests.rs | 55 ++++++++++++++++++ frame/remark/src/weights.rs | 71 +++++++++++++++++++++++ frame/transaction-storage/src/lib.rs | 2 +- 12 files changed, 414 insertions(+), 1 deletion(-) create mode 100644 frame/remark/Cargo.toml create mode 100644 frame/remark/README.md create mode 100644 frame/remark/src/benchmarking.rs create mode 100644 frame/remark/src/lib.rs create mode 100644 frame/remark/src/mock.rs create mode 100644 frame/remark/src/tests.rs create mode 100644 frame/remark/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 3e37bcfd167e4..84872ce141da4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5032,6 +5032,7 @@ dependencies = [ "pallet-randomness-collective-flip", "pallet-recovery", "pallet-referenda", + "pallet-remark", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", @@ -6306,6 +6307,22 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-remark" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-scheduler" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index c281913cd55ed..5cc90ec6f183b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,6 +112,7 @@ members = [ "frame/randomness-collective-flip", "frame/recovery", "frame/referenda", + "frame/remark", "frame/scheduler", "frame/scored-pool", "frame/session", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 41b2402d33a53..75f860eb240e8 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -83,6 +83,7 @@ pallet-proxy = { version = "4.0.0-dev", default-features = false, path = "../../ pallet-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/randomness-collective-flip" } pallet-recovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/recovery" } pallet-referenda = { version = "4.0.0-dev", default-features = false, path = "../../../frame/referenda" } +pallet-remark = { version = "4.0.0-dev", default-features = false, path = "../../../frame/remark" } pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = "../../../frame/session", default-features = false } pallet-session-benchmarking = { version = "4.0.0-dev", path = "../../../frame/session/benchmarking", default-features = false, optional = true } pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" } @@ -173,6 +174,7 @@ std = [ "sp-version/std", "pallet-society/std", "pallet-referenda/std", + "pallet-remark/std", "pallet-recovery/std", "pallet-uniques/std", "pallet-vesting/std", @@ -213,6 +215,7 @@ runtime-benchmarks = [ "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-referenda/runtime-benchmarks", + "pallet-remark/runtime-benchmarks", "pallet-session-benchmarking", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f37345014f3a1..dca386b303610 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -778,6 +778,11 @@ impl pallet_referenda::Config for Runtime { type Tracks = TracksInfo; } +impl pallet_remark::Config for Runtime { + type WeightInfo = pallet_remark::weights::SubstrateWeight; + type Event = Event; +} + parameter_types! { pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; pub const VotingPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; @@ -1457,6 +1462,7 @@ construct_runtime!( StateTrieMigration: pallet_state_trie_migration, ChildBounties: pallet_child_bounties, Referenda: pallet_referenda, + Remark: pallet_remark, ConvictionVoting: pallet_conviction_voting, Whitelist: pallet_whitelist, } @@ -1547,6 +1553,7 @@ mod benches { [pallet_preimage, Preimage] [pallet_proxy, Proxy] [pallet_referenda, Referenda] + [pallet_remark, Remark] [pallet_scheduler, Scheduler] [pallet_session, SessionBench::] [pallet_staking, Staking] diff --git a/frame/remark/Cargo.toml b/frame/remark/Cargo.toml new file mode 100644 index 0000000000000..82c76d679cc10 --- /dev/null +++ b/frame/remark/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "pallet-remark" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Remark storage pallet" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +serde = { version = "1.0.136", optional = true } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } + +[dev-dependencies] +sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } + +[features] +default = ["std"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] +std = [ + "serde", + "codec/std", + "scale-info/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", + "sp-io/std", + "sp-std/std", +] diff --git a/frame/remark/README.md b/frame/remark/README.md new file mode 100644 index 0000000000000..f2341d6a0eaec --- /dev/null +++ b/frame/remark/README.md @@ -0,0 +1,6 @@ +# Remark Storage Pallet + +Allows storing arbitrary data off chain. + + +License: Apache-2.0 diff --git a/frame/remark/src/benchmarking.rs b/frame/remark/src/benchmarking.rs new file mode 100644 index 0000000000000..d30a8aa5df07d --- /dev/null +++ b/frame/remark/src/benchmarking.rs @@ -0,0 +1,47 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmarks for remarks pallet + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use frame_benchmarking::{benchmarks, whitelisted_caller}; +use frame_system::{EventRecord, Pallet as System, RawOrigin}; +use sp_std::*; + +#[cfg(test)] +use crate::Pallet as Remark; + +fn assert_last_event(generic_event: ::Event) { + let events = System::::events(); + let system_event: ::Event = generic_event.into(); + let EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + +benchmarks! { + store { + let l in 1 .. 1024*1024; + let caller: T::AccountId = whitelisted_caller(); + }: _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize]) + verify { + assert_last_event::(Event::Stored { sender: caller, content_hash: sp_io::hashing::blake2_256(&vec![0u8; l as usize]).into() }.into()); + } + + impl_benchmark_test_suite!(Remark, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/remark/src/lib.rs b/frame/remark/src/lib.rs new file mode 100644 index 0000000000000..6803b2a60085f --- /dev/null +++ b/frame/remark/src/lib.rs @@ -0,0 +1,85 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Remark storage pallet. Indexes remarks and stores them off chain. + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +mod benchmarking; +pub mod weights; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +use sp_std::prelude::*; + +// Re-export pallet items so that they can be accessed from the crate namespace. +pub use pallet::*; +pub use weights::WeightInfo; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::error] + pub enum Error { + /// Attempting to store empty data. + Empty, + /// Attempted to call `store` outside of block execution. + BadContext, + } + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + /// Index and store data off chain. + #[pallet::weight(T::WeightInfo::store(remark.len() as u32))] + pub fn store(origin: OriginFor, remark: Vec) -> DispatchResultWithPostInfo { + ensure!(!remark.is_empty(), Error::::Empty); + let sender = ensure_signed(origin)?; + let content_hash = sp_io::hashing::blake2_256(&remark); + let extrinsic_index = >::extrinsic_index() + .ok_or_else(|| Error::::BadContext)?; + sp_io::transaction_index::index(extrinsic_index, remark.len() as u32, content_hash); + Self::deposit_event(Event::Stored { sender, content_hash: content_hash.into() }); + Ok(().into()) + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Stored data off chain. + Stored { sender: T::AccountId, content_hash: sp_core::H256 }, + } +} diff --git a/frame/remark/src/mock.rs b/frame/remark/src/mock.rs new file mode 100644 index 0000000000000..67a0399e9c386 --- /dev/null +++ b/frame/remark/src/mock.rs @@ -0,0 +1,79 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Test environment for remarks pallet. + +use crate as pallet_remark; +use frame_support::traits::{ConstU16, ConstU32, ConstU64}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +pub type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Remark: pallet_remark::{ Pallet, Call, Event }, + } +); + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = ConstU64<250>; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<42>; + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_remark::Config for Test { + type Event = Event; + type WeightInfo = (); +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = GenesisConfig { system: Default::default() }.build_storage().unwrap(); + t.into() +} diff --git a/frame/remark/src/tests.rs b/frame/remark/src/tests.rs new file mode 100644 index 0000000000000..60a376c5afca5 --- /dev/null +++ b/frame/remark/src/tests.rs @@ -0,0 +1,55 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for remarks pallet. + +use super::{Error, Event, Pallet as Remark}; +use crate::mock::*; +use frame_support::{assert_noop, assert_ok}; +use frame_system::RawOrigin; + +#[test] +fn generates_event() { + new_test_ext().execute_with(|| { + let caller = 1; + let data = vec![0u8; 100]; + System::set_block_number(System::block_number() + 1); //otherwise event won't be registered. + assert_ok!(Remark::::store(RawOrigin::Signed(caller.clone()).into(), data.clone(),)); + let events = System::events(); + let system_event: ::Event = Event::Stored { + content_hash: sp_io::hashing::blake2_256(&data).into(), + sender: caller, + } + .into(); + let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); + }); +} + +#[test] +fn does_not_store_empty() { + new_test_ext().execute_with(|| { + let caller = 1; + let data = vec![]; + System::set_block_number(System::block_number() + 1); //otherwise event won't be registered. + assert_noop!( + Remark::::store(RawOrigin::Signed(caller.clone()).into(), data.clone(),), + Error::::Empty + ); + assert!(System::events().is_empty()); + }); +} diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs new file mode 100644 index 0000000000000..50b0fc3ebfc19 --- /dev/null +++ b/frame/remark/src/weights.rs @@ -0,0 +1,71 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_remark +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-03-11, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_remark +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/remark/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_remark. +pub trait WeightInfo { + fn store(l: u32, ) -> Weight; +} + +/// Weights for pallet_remark using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn store(l: u32, ) -> Weight { + (18_328_000 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn store(l: u32, ) -> Weight { + (18_328_000 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + } +} diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index d95a60b495121..e9aa786766dac 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -170,7 +170,7 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// Index and store data on chain. Minimum data size is 1 bytes, maximum is + /// Index and store data off chain. Minimum data size is 1 bytes, maximum is /// `MaxTransactionSize`. Data will be removed after `STORAGE_PERIOD` blocks, unless `renew` /// is called. # /// - n*log(n) of data size, as all data is pushed to an in-memory trie. From 930c8ce755e49d7e91b74c0ef59cb3c1ee61fc32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Apr 2022 12:03:46 +0000 Subject: [PATCH 0707/1472] Bump async-std from 1.10.0 to 1.11.0 (#11160) Bumps [async-std](https://github.com/async-rs/async-std) from 1.10.0 to 1.11.0. - [Release notes](https://github.com/async-rs/async-std/releases) - [Changelog](https://github.com/async-rs/async-std/blob/master/CHANGELOG.md) - [Commits](https://github.com/async-rs/async-std/compare/v1.10.0...v1.11.0) --- updated-dependencies: - dependency-name: async-std 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 | 4 ++-- bin/node/cli/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84872ce141da4..c7b3997b1d055 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -256,9 +256,9 @@ dependencies = [ [[package]] name = "async-std" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" +checksum = "52580991739c5cdb36cde8b2a516371c0a3b70dda36d916cc08b82372916808c" dependencies = [ "async-attributes", "async-channel", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index bb4ec763a3051..1c6acce2c01df 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -124,7 +124,7 @@ nix = "0.23" serde_json = "1.0" regex = "1.5.5" platforms = "2.0" -async-std = { version = "1.10.0", features = ["attributes"] } +async-std = { version = "1.11.0", features = ["attributes"] } soketto = "0.7.1" criterion = { version = "0.3.5", features = ["async_tokio"] } tokio = { version = "1.17.0", features = ["macros", "time", "parking_lot"] } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 9854575ab6b02..6e566a100bae5 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -27,6 +27,6 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } tracing = "0.1.29" [dev-dependencies] -async-std = "1.10.0" +async-std = "1.11.0" quickcheck = "1.0.3" substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 6d70d41964de4..f0a6a949d1641 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -74,7 +74,7 @@ sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } tempfile = "3.1.0" -async-std = "1.10.0" +async-std = "1.11.0" [features] default = [] diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index b9505f97d14c0..3c72bd404492e 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-std = "1.10.0" +async-std = "1.11.0" sc-network = { version = "0.10.0-dev", path = "../" } log = "0.4.8" parking_lot = "0.12.0" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index c40559bdb5059..490ef1cbb16b0 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -86,4 +86,4 @@ directories = "4.0.1" [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime/" } -async-std = { version = "1.10.0", default-features = false } +async-std = { version = "1.11.0", default-features = false } From c5fc77a862b8cbe2169076f40ce5b5829e172613 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Apr 2022 14:32:20 +0000 Subject: [PATCH 0708/1472] Bump sha2 from 0.10.1 to 0.10.2 (#11161) Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.10.1 to 0.10.2. - [Release notes](https://github.com/RustCrypto/hashes/releases) - [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.10.1...sha2-v0.10.2) --- updated-dependencies: - dependency-name: sha2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- primitives/core/hashing/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7b3997b1d055..ab768fad79889 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9612,9 +9612,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ "cfg-if 1.0.0", "cpufeatures 0.2.1", @@ -10072,7 +10072,7 @@ dependencies = [ "blake2 0.10.2", "byteorder", "digest 0.10.3", - "sha2 0.10.1", + "sha2 0.10.2", "sha3 0.10.0", "sp-std", "twox-hash", diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index 978cb8906d5d9..0aee960f9e13d 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -18,7 +18,7 @@ byteorder = { version = "1.3.2", default-features = false } digest = { version = "0.10.3", default-features = false } blake2 = { version = "0.10.2", default-features = false } -sha2 = { version = "0.10.1", default-features = false } +sha2 = { version = "0.10.2", default-features = false } sha3 = { version = "0.10.0", default-features = false } twox-hash = { version = "1.6.2", default-features = false, features = ["digest_0_10"] } From 9461b2de04210c6c193726a745c3ec6552b4ce9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Apr 2022 16:45:38 +0200 Subject: [PATCH 0709/1472] Bump ss58-registry from 1.11.0 to 1.15.0 (#11224) Bumps [ss58-registry](https://github.com/paritytech/ss58-registry) from 1.11.0 to 1.15.0. - [Release notes](https://github.com/paritytech/ss58-registry/releases) - [Changelog](https://github.com/paritytech/ss58-registry/blob/main/CHANGELOG.md) - [Commits](https://github.com/paritytech/ss58-registry/compare/v1.11.0...v1.15.0) --- updated-dependencies: - dependency-name: ss58-registry 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 | 4 ++-- primitives/core/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab768fad79889..796a3e3d271ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10602,9 +10602,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "ss58-registry" -version = "1.11.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1230685dc82f8699110640244d361a7099c602f08bddc5c90765a5153b4881dc" +checksum = "2f9799e6d412271cb2414597581128b03f3285f260ea49f5363d07df6a332b3e" dependencies = [ "Inflector", "proc-macro2", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 74a159b2e7d39..402e3ebf07df1 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -57,7 +57,7 @@ hex = { version = "0.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } secp256k1 = { version = "0.21.2", default-features = false, features = ["recovery", "alloc"], optional = true } -ss58-registry = { version = "1.11.0", default-features = false } +ss58-registry = { version = "1.15.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } From 977ce49622aaa380f1e67c1483fecb5ff448e6a6 Mon Sep 17 00:00:00 2001 From: Georges Date: Wed, 20 Apr 2022 13:15:18 +0100 Subject: [PATCH 0710/1472] Split `SolutionImprovementThresholds` into two types (#11221) * Splitting `SolutionImprovementThreshold` in 2 One for Signed phase and one for Unsigned phase. * Adding some tests * Fixes after code review. - Removing `GetDefault`. - Shorter naming. - More explicit test. --- bin/node/runtime/src/lib.rs | 5 +- .../election-provider-multi-phase/src/lib.rs | 13 +++-- .../election-provider-multi-phase/src/mock.rs | 16 ++++-- .../src/signed.rs | 52 ++++++++++++++++++- .../src/unsigned.rs | 4 +- 5 files changed, 75 insertions(+), 15 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index dca386b303610..1da670b389192 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -574,7 +574,7 @@ parameter_types! { pub const SignedDepositBase: Balance = 1 * DOLLARS; pub const SignedDepositByte: Balance = 1 * CENTS; - pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(1u32, 10_000); + pub BetterUnsignedThreshold: Perbill = Perbill::from_rational(1u32, 10_000); // miner configs pub const MultiPhaseUnsignedPriority: TransactionPriority = StakingUnsignedPriority::get() - 1u64; @@ -664,7 +664,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type EstimateCallFee = TransactionPayment; type SignedPhase = SignedPhase; type UnsignedPhase = UnsignedPhase; - type SolutionImprovementThreshold = SolutionImprovementThreshold; + type BetterUnsignedThreshold = BetterUnsignedThreshold; + type BetterSignedThreshold = (); type OffchainRepeat = OffchainRepeat; type MinerMaxWeight = MinerMaxWeight; type MinerMaxLength = MinerMaxLength; diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index e67a5cab8d643..5dc44d38fc365 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -102,8 +102,8 @@ //! valid if propagated, and it acts similar to an inherent. //! //! Validators will only submit solutions if the one that they have computed is sufficiently better -//! than the best queued one (see [`pallet::Config::SolutionImprovementThreshold`]) and will limit -//! the weight of the solution to [`pallet::Config::MinerMaxWeight`]. +//! than the best queued one (see [`pallet::Config::BetterUnsignedThreshold`]) and will limit the +//! weight of the solution to [`pallet::Config::MinerMaxWeight`]. //! //! The unsigned phase can be made passive depending on how the previous signed phase went, by //! setting the first inner value of [`Phase`] to `false`. For now, the signed phase is always @@ -585,9 +585,14 @@ pub mod pallet { type SignedPhase: Get; /// The minimum amount of improvement to the solution score that defines a solution as - /// "better" (in any phase). + /// "better" in the Signed phase. #[pallet::constant] - type SolutionImprovementThreshold: Get; + type BetterSignedThreshold: Get; + + /// The minimum amount of improvement to the solution score that defines a solution as + /// "better" in the Unsigned phase. + #[pallet::constant] + type BetterUnsignedThreshold: Get; /// The repeat threshold of the offchain worker. /// diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 7c06ff6bee546..2c9d7bb34dba5 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -20,7 +20,7 @@ use crate as multi_phase; use frame_election_provider_support::{ data_provider, onchain, ElectionDataProvider, NposSolution, SequentialPhragmen, }; -pub use frame_support::{assert_noop, assert_ok}; +pub use frame_support::{assert_noop, assert_ok, pallet_prelude::GetDefault}; use frame_support::{ bounded_vec, parameter_types, traits::{ConstU32, Hooks}, @@ -263,7 +263,8 @@ parameter_types! { pub static SignedRewardBase: Balance = 7; pub static SignedMaxWeight: Weight = BlockWeights::get().max_block; pub static MinerTxPriority: u64 = 100; - pub static SolutionImprovementThreshold: Perbill = Perbill::zero(); + pub static BetterSignedThreshold: Perbill = Perbill::zero(); + pub static BetterUnsignedThreshold: Perbill = Perbill::zero(); pub static OffchainRepeat: BlockNumber = 5; pub static MinerMaxWeight: Weight = BlockWeights::get().max_block; pub static MinerMaxLength: u32 = 256; @@ -414,7 +415,8 @@ impl crate::Config for Runtime { type EstimateCallFee = frame_support::traits::ConstU32<8>; type SignedPhase = SignedPhase; type UnsignedPhase = UnsignedPhase; - type SolutionImprovementThreshold = SolutionImprovementThreshold; + type BetterUnsignedThreshold = BetterUnsignedThreshold; + type BetterSignedThreshold = BetterSignedThreshold; type OffchainRepeat = OffchainRepeat; type MinerMaxWeight = MinerMaxWeight; type MinerMaxLength = MinerMaxLength; @@ -537,8 +539,12 @@ impl ExtBuilder { ::set(p); self } - pub fn solution_improvement_threshold(self, p: Perbill) -> Self { - ::set(p); + pub fn better_signed_threshold(self, p: Perbill) -> Self { + ::set(p); + self + } + pub fn better_unsigned_threshold(self, p: Perbill) -> Self { + ::set(p); self } pub fn phases(self, signed: BlockNumber, unsigned: BlockNumber) -> Self { diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 82b40e3276036..465528068e71a 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -291,7 +291,7 @@ impl SignedSubmissions { None => return InsertResult::NotInserted, Some((score, _)) => *score, }; - let threshold = T::SolutionImprovementThreshold::get(); + let threshold = T::BetterSignedThreshold::get(); // if we haven't improved on the weakest score, don't change anything. if !insert_score.strict_threshold_better(weakest_score, threshold) { @@ -499,7 +499,7 @@ mod tests { balances, raw_solution, roll_to, ExtBuilder, MultiPhase, Origin, Runtime, SignedMaxSubmissions, SignedMaxWeight, }, - Error, Phase, + Error, Perbill, Phase, }; use frame_support::{assert_noop, assert_ok, assert_storage_noop}; @@ -632,6 +632,54 @@ mod tests { }) } + #[test] + fn cannot_submit_worse_with_full_queue_depends_on_threshold() { + ExtBuilder::default() + .signed_max_submission(1) + .better_signed_threshold(Perbill::from_percent(20)) + .build_and_execute(|| { + roll_to(15); + assert!(MultiPhase::current_phase().is_signed()); + + let mut solution = RawSolution { + score: ElectionScore { + minimal_stake: 5u128, + sum_stake: 0u128, + sum_stake_squared: 10u128, + }, + ..Default::default() + }; + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + + // This is 10% better, so does not meet the 20% threshold and is therefore rejected. + solution = RawSolution { + score: ElectionScore { + minimal_stake: 5u128, + sum_stake: 0u128, + sum_stake_squared: 9u128, + }, + ..Default::default() + }; + + assert_noop!( + MultiPhase::submit(Origin::signed(99), Box::new(solution)), + Error::::SignedQueueFull, + ); + + // This is however 30% better and should therefore be accepted. + solution = RawSolution { + score: ElectionScore { + minimal_stake: 5u128, + sum_stake: 0u128, + sum_stake_squared: 7u128, + }, + ..Default::default() + }; + + assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + }) + } + #[test] fn weakest_is_removed_if_better_provided() { ExtBuilder::default().build_and_execute(|| { diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index d210852bac19e..d184c3acfe91b 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -624,7 +624,7 @@ impl Pallet { ensure!( Self::queued_solution().map_or(true, |q: ReadySolution<_>| raw_solution .score - .strict_threshold_better(q.score, T::SolutionImprovementThreshold::get())), + .strict_threshold_better(q.score, T::BetterUnsignedThreshold::get())), Error::::PreDispatchWeakSubmission, ); @@ -1066,7 +1066,7 @@ mod tests { .desired_targets(1) .add_voter(7, 2, bounded_vec![10]) .add_voter(8, 5, bounded_vec![10]) - .solution_improvement_threshold(Perbill::from_percent(50)) + .better_unsigned_threshold(Perbill::from_percent(50)) .build_and_execute(|| { roll_to(25); assert!(MultiPhase::current_phase().is_unsigned()); From 580ebae17fa30082604f1c9720f6f4a1cfe95b50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Apr 2022 15:39:28 +0200 Subject: [PATCH 0711/1472] Bump log from 0.4.14 to 0.4.16 (#11236) Bumps [log](https://github.com/rust-lang/log) from 0.4.14 to 0.4.16. - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/commits) --- updated-dependencies: - dependency-name: log 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 | 355 +++++++++--------- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- client/allocator/Cargo.toml | 2 +- client/api/Cargo.toml | 2 +- client/authority-discovery/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/executor/wasmi/Cargo.toml | 2 +- client/executor/wasmtime/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/informant/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/proposer-metrics/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- client/state-db/Cargo.toml | 2 +- client/sysinfo/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- frame/babe/Cargo.toml | 2 +- frame/bags-list/Cargo.toml | 2 +- frame/bags-list/remote-tests/Cargo.toml | 2 +- frame/balances/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 2 +- frame/bounties/Cargo.toml | 2 +- frame/child-bounties/Cargo.toml | 2 +- frame/collective/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 2 +- frame/examples/basic/Cargo.toml | 2 +- frame/examples/offchain-worker/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/im-online/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/node-authorization/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/scheduler/Cargo.toml | 2 +- frame/session/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/staking/reward-fn/Cargo.toml | 2 +- frame/state-trie-migration/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- frame/timestamp/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 2 +- frame/vesting/Cargo.toml | 2 +- primitives/api/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/consensus/common/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/merkle-mountain-range/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/tasks/Cargo.toml | 2 +- primitives/timestamp/Cargo.toml | 2 +- .../transaction-storage-proof/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 2 +- 86 files changed, 263 insertions(+), 262 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 796a3e3d271ce..b7bb085b0962f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -226,7 +226,7 @@ dependencies = [ "fastrand", "futures-lite", "libc", - "log 0.4.14", + "log 0.4.16", "nb-connect", "once_cell", "parking", @@ -272,7 +272,7 @@ dependencies = [ "futures-lite", "gloo-timers", "kv-log-macro", - "log 0.4.14", + "log 0.4.16", "memchr", "num_cpus", "once_cell", @@ -474,7 +474,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "hex", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "sc-chain-spec", @@ -519,7 +519,7 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "jsonrpc-pubsub", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "sc-rpc", @@ -539,7 +539,7 @@ dependencies = [ "env_logger 0.9.0", "hex", "hex-literal", - "log 0.4.14", + "log 0.4.16", "tiny-keccak", ] @@ -1171,7 +1171,7 @@ dependencies = [ "cranelift-codegen-shared 0.76.0", "cranelift-entity 0.76.0", "gimli 0.25.0", - "log 0.4.14", + "log 0.4.16", "regalloc 0.0.31", "smallvec 1.8.0", "target-lexicon", @@ -1188,7 +1188,7 @@ dependencies = [ "cranelift-codegen-shared 0.82.3", "cranelift-entity 0.82.3", "gimli 0.26.1", - "log 0.4.14", + "log 0.4.16", "regalloc 0.0.34", "smallvec 1.8.0", "target-lexicon", @@ -1247,7 +1247,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279afcc0d3e651b773f94837c3d581177b348c8d69e928104b2e9fccb226f921" dependencies = [ "cranelift-codegen 0.76.0", - "log 0.4.14", + "log 0.4.16", "smallvec 1.8.0", "target-lexicon", ] @@ -1259,7 +1259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" dependencies = [ "cranelift-codegen 0.82.3", - "log 0.4.14", + "log 0.4.16", "smallvec 1.8.0", "target-lexicon", ] @@ -1285,7 +1285,7 @@ dependencies = [ "cranelift-entity 0.82.3", "cranelift-frontend 0.82.3", "itertools", - "log 0.4.14", + "log 0.4.16", "smallvec 1.8.0", "wasmparser 0.83.0", "wasmtime-types", @@ -1937,7 +1937,7 @@ checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ "atty", "humantime 1.3.0", - "log 0.4.14", + "log 0.4.16", "regex", "termcolor", ] @@ -1948,7 +1948,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ - "log 0.4.14", + "log 0.4.16", "regex", ] @@ -1960,7 +1960,7 @@ checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime 2.1.0", - "log 0.4.14", + "log 0.4.16", "regex", "termcolor", ] @@ -2054,7 +2054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fdbe0d94371f9ce939b555dd342d0686cc4c0cadbcd4b61d70af5ff97eb4126" dependencies = [ "env_logger 0.7.1", - "log 0.4.14", + "log 0.4.16", ] [[package]] @@ -2066,7 +2066,7 @@ dependencies = [ "either", "futures 0.3.21", "futures-timer", - "log 0.4.14", + "log 0.4.16", "num-traits", "parity-scale-codec", "parking_lot 0.11.2", @@ -2151,7 +2151,7 @@ dependencies = [ "frame-system", "hex-literal", "linregress", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "paste 1.0.6", "scale-info", @@ -2182,7 +2182,7 @@ dependencies = [ "itertools", "kvdb", "linked-hash-map", - "log 0.4.14", + "log 0.4.16", "memory-db", "parity-scale-codec", "prettytable-rs", @@ -2307,7 +2307,7 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "k256", - "log 0.4.14", + "log 0.4.16", "once_cell", "parity-scale-codec", "parity-util-mem", @@ -2411,7 +2411,7 @@ version = "4.0.0-dev" dependencies = [ "criterion", "frame-support", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "scale-info", "serde", @@ -2746,7 +2746,7 @@ dependencies = [ "bitflags", "libc", "libgit2-sys", - "log 0.4.14", + "log 0.4.16", "url 2.2.1", ] @@ -2765,7 +2765,7 @@ dependencies = [ "aho-corasick", "bstr", "fnv", - "log 0.4.14", + "log 0.4.16", "regex", ] @@ -2824,7 +2824,7 @@ version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d6a30320f094710245150395bc763ad23128d6a1ebbad7594dc4164b62c56b" dependencies = [ - "log 0.4.14", + "log 0.4.16", "pest", "pest_derive", "quick-error 2.0.0", @@ -3061,7 +3061,7 @@ dependencies = [ "ct-logs", "futures-util", "hyper 0.14.16", - "log 0.4.14", + "log 0.4.16", "rustls 0.19.1", "rustls-native-certs 0.5.0", "tokio", @@ -3143,7 +3143,7 @@ dependencies = [ "if-addrs", "ipnet", "libc", - "log 0.4.14", + "log 0.4.16", "winapi 0.3.9", ] @@ -3295,7 +3295,7 @@ dependencies = [ "hyper-tls", "jsonrpc-core", "jsonrpc-pubsub", - "log 0.4.14", + "log 0.4.16", "serde", "serde_json", "tokio", @@ -3312,7 +3312,7 @@ dependencies = [ "futures 0.3.21", "futures-executor", "futures-util", - "log 0.4.14", + "log 0.4.16", "serde", "serde_derive", "serde_json", @@ -3350,7 +3350,7 @@ dependencies = [ "hyper 0.14.16", "jsonrpc-core", "jsonrpc-server-utils", - "log 0.4.14", + "log 0.4.16", "net2", "parking_lot 0.11.2", "unicase 2.6.0", @@ -3365,7 +3365,7 @@ dependencies = [ "futures 0.3.21", "jsonrpc-core", "jsonrpc-server-utils", - "log 0.4.14", + "log 0.4.16", "parity-tokio-ipc", "parking_lot 0.11.2", "tower-service", @@ -3380,7 +3380,7 @@ dependencies = [ "futures 0.3.21", "jsonrpc-core", "lazy_static", - "log 0.4.14", + "log 0.4.16", "parking_lot 0.11.2", "rand 0.7.3", "serde", @@ -3397,7 +3397,7 @@ dependencies = [ "globset", "jsonrpc-core", "lazy_static", - "log 0.4.14", + "log 0.4.16", "tokio", "tokio-stream", "tokio-util 0.6.7", @@ -3413,7 +3413,7 @@ dependencies = [ "futures 0.3.21", "jsonrpc-core", "jsonrpc-server-utils", - "log 0.4.14", + "log 0.4.16", "parity-ws", "parking_lot 0.11.2", "slab", @@ -3557,7 +3557,7 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" dependencies = [ - "log 0.4.14", + "log 0.4.16", ] [[package]] @@ -3589,7 +3589,7 @@ checksum = "ca7fbdfd71cd663dceb0faf3367a99f8cf724514933e9867cec4995b6027cbc1" dependencies = [ "fs-swap", "kvdb", - "log 0.4.14", + "log 0.4.16", "num_cpus", "owning_ref", "parity-util-mem", @@ -3723,7 +3723,7 @@ dependencies = [ "futures-timer", "lazy_static", "libsecp256k1", - "log 0.4.14", + "log 0.4.16", "multiaddr", "multihash 0.14.0", "multistream-select", @@ -3762,7 +3762,7 @@ dependencies = [ "async-std-resolver", "futures 0.3.21", "libp2p-core", - "log 0.4.14", + "log 0.4.16", "smallvec 1.8.0", "trust-dns-resolver", ] @@ -3778,7 +3778,7 @@ dependencies = [ "futures 0.3.21", "libp2p-core", "libp2p-swarm", - "log 0.4.14", + "log 0.4.16", "prost", "prost-build", "rand 0.7.3", @@ -3800,7 +3800,7 @@ dependencies = [ "hex_fmt", "libp2p-core", "libp2p-swarm", - "log 0.4.14", + "log 0.4.16", "prost", "prost-build", "rand 0.7.3", @@ -3820,7 +3820,7 @@ dependencies = [ "futures 0.3.21", "libp2p-core", "libp2p-swarm", - "log 0.4.14", + "log 0.4.16", "lru 0.6.6", "prost", "prost-build", @@ -3842,7 +3842,7 @@ dependencies = [ "futures 0.3.21", "libp2p-core", "libp2p-swarm", - "log 0.4.14", + "log 0.4.16", "prost", "prost-build", "rand 0.7.3", @@ -3868,7 +3868,7 @@ dependencies = [ "lazy_static", "libp2p-core", "libp2p-swarm", - "log 0.4.14", + "log 0.4.16", "rand 0.8.4", "smallvec 1.8.0", "socket2 0.4.4", @@ -3899,7 +3899,7 @@ dependencies = [ "bytes 1.1.0", "futures 0.3.21", "libp2p-core", - "log 0.4.14", + "log 0.4.16", "nohash-hasher", "parking_lot 0.11.2", "rand 0.7.3", @@ -3918,7 +3918,7 @@ dependencies = [ "futures 0.3.21", "lazy_static", "libp2p-core", - "log 0.4.14", + "log 0.4.16", "prost", "prost-build", "rand 0.8.4", @@ -3938,7 +3938,7 @@ dependencies = [ "futures 0.3.21", "libp2p-core", "libp2p-swarm", - "log 0.4.14", + "log 0.4.16", "rand 0.7.3", "void", "wasm-timer", @@ -3954,7 +3954,7 @@ dependencies = [ "bytes 1.1.0", "futures 0.3.21", "libp2p-core", - "log 0.4.14", + "log 0.4.16", "prost", "prost-build", "unsigned-varint 0.7.0", @@ -3968,7 +3968,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" dependencies = [ "futures 0.3.21", - "log 0.4.14", + "log 0.4.16", "pin-project 1.0.10", "rand 0.7.3", "salsa20", @@ -3987,7 +3987,7 @@ dependencies = [ "futures-timer", "libp2p-core", "libp2p-swarm", - "log 0.4.14", + "log 0.4.16", "pin-project 1.0.10", "prost", "prost-build", @@ -4009,7 +4009,7 @@ dependencies = [ "futures 0.3.21", "libp2p-core", "libp2p-swarm", - "log 0.4.14", + "log 0.4.16", "prost", "prost-build", "rand 0.8.4", @@ -4031,7 +4031,7 @@ dependencies = [ "futures 0.3.21", "libp2p-core", "libp2p-swarm", - "log 0.4.14", + "log 0.4.16", "lru 0.7.5", "rand 0.7.3", "smallvec 1.8.0", @@ -4048,7 +4048,7 @@ dependencies = [ "either", "futures 0.3.21", "libp2p-core", - "log 0.4.14", + "log 0.4.16", "rand 0.7.3", "smallvec 1.8.0", "void", @@ -4078,7 +4078,7 @@ dependencies = [ "ipnet", "libc", "libp2p-core", - "log 0.4.14", + "log 0.4.16", "socket2 0.4.4", ] @@ -4091,7 +4091,7 @@ dependencies = [ "async-std", "futures 0.3.21", "libp2p-core", - "log 0.4.14", + "log 0.4.16", ] [[package]] @@ -4118,7 +4118,7 @@ dependencies = [ "futures 0.3.21", "futures-rustls", "libp2p-core", - "log 0.4.14", + "log 0.4.16", "quicksink", "rw-stream-sink", "soketto", @@ -4287,14 +4287,14 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" dependencies = [ - "log 0.4.14", + "log 0.4.16", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" dependencies = [ "cfg-if 1.0.0", "value-bag", @@ -4528,7 +4528,7 @@ dependencies = [ "iovec", "kernel32-sys", "libc", - "log 0.4.14", + "log 0.4.16", "miow 0.2.2", "net2", "slab", @@ -4542,7 +4542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" dependencies = [ "libc", - "log 0.4.14", + "log 0.4.16", "miow 0.3.6", "ntapi", "winapi 0.3.9", @@ -4555,7 +4555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" dependencies = [ "lazycell", - "log 0.4.14", + "log 0.4.16", "mio 0.6.23", "slab", ] @@ -4675,7 +4675,7 @@ checksum = "7d91ec0a2440aaff5f78ec35631a7027d50386c6163aa975f7caa0d5da4b6ff8" dependencies = [ "bytes 1.1.0", "futures 0.3.21", - "log 0.4.14", + "log 0.4.16", "pin-project 1.0.10", "smallvec 1.8.0", "unsigned-varint 0.7.0", @@ -4727,7 +4727,7 @@ checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" dependencies = [ "lazy_static", "libc", - "log 0.4.14", + "log 0.4.16", "openssl", "openssl-probe", "openssl-sys", @@ -4784,7 +4784,7 @@ dependencies = [ "kvdb", "kvdb-rocksdb", "lazy_static", - "log 0.4.14", + "log 0.4.16", "node-primitives", "node-runtime", "node-testing", @@ -4822,7 +4822,7 @@ dependencies = [ "frame-system-rpc-runtime-api", "futures 0.3.21", "hex-literal", - "log 0.4.14", + "log 0.4.16", "nix", "node-executor", "node-inspect", @@ -4996,7 +4996,7 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "hex-literal", - "log 0.4.14", + "log 0.4.16", "node-primitives", "pallet-asset-tx-payment", "pallet-assets", @@ -5167,7 +5167,7 @@ dependencies = [ "frame-system", "fs_extra", "futures 0.3.21", - "log 0.4.14", + "log 0.4.16", "node-executor", "node-primitives", "node-runtime", @@ -5550,7 +5550,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-authorship", "pallet-balances", "pallet-offences", @@ -5579,7 +5579,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "parity-scale-codec", "scale-info", @@ -5607,7 +5607,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-bags-list", "pallet-staking", "remote-externalities", @@ -5626,7 +5626,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-transaction-payment", "parity-scale-codec", "scale-info", @@ -5664,7 +5664,7 @@ dependencies = [ "frame-system", "hex", "hex-literal", - "log 0.4.14", + "log 0.4.16", "pallet-beefy", "pallet-mmr", "pallet-session", @@ -5685,7 +5685,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "pallet-treasury", "parity-scale-codec", @@ -5703,7 +5703,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "pallet-bounties", "pallet-treasury", @@ -5722,7 +5722,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "scale-info", "sp-core", @@ -5742,7 +5742,7 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "pallet-contracts-primitives", "pallet-contracts-proc-macro", @@ -5866,7 +5866,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "pallet-election-provider-support-benchmarking", "parity-scale-codec", @@ -5903,7 +5903,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "parity-scale-codec", "scale-info", @@ -5922,7 +5922,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "parity-scale-codec", "scale-info", @@ -5939,7 +5939,7 @@ dependencies = [ "frame-support", "frame-system", "lite-json", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "scale-info", "sp-core", @@ -5990,7 +5990,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-authorship", "pallet-balances", "pallet-offences", @@ -6035,7 +6035,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-authorship", "pallet-session", "parity-scale-codec", @@ -6089,7 +6089,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "scale-info", "sp-core", @@ -6171,7 +6171,7 @@ version = "4.0.0-dev" dependencies = [ "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "scale-info", "sp-core", @@ -6186,7 +6186,7 @@ version = "4.0.0-dev" dependencies = [ "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "parity-scale-codec", "scale-info", @@ -6330,7 +6330,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-preimage", "parity-scale-codec", "scale-info", @@ -6363,7 +6363,7 @@ dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "log 0.4.14", + "log 0.4.16", "pallet-timestamp", "parity-scale-codec", "scale-info", @@ -6424,7 +6424,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-authorship", "pallet-bags-list", "pallet-balances", @@ -6461,7 +6461,7 @@ dependencies = [ name = "pallet-staking-reward-fn" version = "4.0.0-dev" dependencies = [ - "log 0.4.14", + "log 0.4.16", "sp-arithmetic", ] @@ -6472,7 +6472,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "parity-scale-codec", "parking_lot 0.12.0", @@ -6525,7 +6525,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "scale-info", "sp-core", @@ -6543,7 +6543,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "pallet-treasury", "parity-scale-codec", @@ -6645,7 +6645,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "parity-scale-codec", "scale-info", @@ -6678,7 +6678,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.14", + "log 0.4.16", "pallet-balances", "parity-scale-codec", "scale-info", @@ -6717,7 +6717,7 @@ dependencies = [ "fs2", "hex", "libc", - "log 0.4.14", + "log 0.4.16", "lz4", "memmap2 0.2.1", "parking_lot 0.11.2", @@ -6765,7 +6765,7 @@ checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6" dependencies = [ "futures 0.3.21", "libc", - "log 0.4.14", + "log 0.4.16", "rand 0.7.3", "tokio", "winapi 0.3.9", @@ -6822,7 +6822,7 @@ dependencies = [ "byteorder", "bytes 0.4.12", "httparse", - "log 0.4.14", + "log 0.4.16", "mio 0.6.23", "mio-extras", "rand 0.7.3", @@ -7131,7 +7131,7 @@ checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" dependencies = [ "cfg-if 0.1.10", "libc", - "log 0.4.14", + "log 0.4.16", "wepoll-sys", "winapi 0.3.9", ] @@ -7323,7 +7323,7 @@ dependencies = [ "heck 0.3.2", "itertools", "lazy_static", - "log 0.4.14", + "log 0.4.16", "multimap", "petgraph", "prost", @@ -7404,7 +7404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ "env_logger 0.8.4", - "log 0.4.14", + "log 0.4.16", "rand 0.8.4", ] @@ -7752,7 +7752,7 @@ version = "0.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" dependencies = [ - "log 0.4.14", + "log 0.4.16", "rustc-hash", "smallvec 1.8.0", ] @@ -7763,7 +7763,7 @@ version = "0.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" dependencies = [ - "log 0.4.14", + "log 0.4.16", "rustc-hash", "smallvec 1.8.0", ] @@ -7826,7 +7826,7 @@ dependencies = [ "env_logger 0.9.0", "frame-support", "jsonrpsee", - "log 0.4.14", + "log 0.4.16", "pallet-elections-phragmen", "parity-scale-codec", "serde", @@ -8012,7 +8012,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ "base64 0.13.0", - "log 0.4.14", + "log 0.4.16", "ring", "sct 0.6.0", "webpki 0.21.4", @@ -8024,7 +8024,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" dependencies = [ - "log 0.4.14", + "log 0.4.16", "ring", "sct 0.7.0", "webpki 0.22.0", @@ -8123,7 +8123,7 @@ dependencies = [ name = "sc-allocator" version = "4.1.0-dev" dependencies = [ - "log 0.4.14", + "log 0.4.16", "sp-core", "sp-wasm-interface", "thiserror", @@ -8138,7 +8138,7 @@ dependencies = [ "futures-timer", "ip_network", "libp2p", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "prost", "prost-build", @@ -8164,7 +8164,7 @@ version = "0.10.0-dev" dependencies = [ "futures 0.3.21", "futures-timer", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "sc-block-builder", @@ -8235,7 +8235,7 @@ dependencies = [ "futures 0.3.21", "hex", "libp2p", - "log 0.4.14", + "log 0.4.16", "names", "parity-scale-codec", "rand 0.7.3", @@ -8270,7 +8270,7 @@ dependencies = [ "fnv", "futures 0.3.21", "hash-db", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "sc-executor", @@ -8302,7 +8302,7 @@ dependencies = [ "kvdb-memorydb", "kvdb-rocksdb", "linked-hash-map", - "log 0.4.14", + "log 0.4.16", "parity-db", "parity-scale-codec", "parking_lot 0.12.0", @@ -8329,7 +8329,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "libp2p", - "log 0.4.14", + "log 0.4.16", "parking_lot 0.12.0", "sc-client-api", "sc-utils", @@ -8351,7 +8351,7 @@ version = "0.10.0-dev" dependencies = [ "async-trait", "futures 0.3.21", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "sc-block-builder", @@ -8389,7 +8389,7 @@ dependencies = [ "async-trait", "fork-tree", "futures 0.3.21", - "log 0.4.14", + "log 0.4.16", "merlin", "num-bigint", "num-rational 0.2.4", @@ -8483,7 +8483,7 @@ dependencies = [ "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sc-basic-authorship", "sc-client-api", @@ -8519,7 +8519,7 @@ dependencies = [ "async-trait", "futures 0.3.21", "futures-timer", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "sc-client-api", @@ -8543,7 +8543,7 @@ dependencies = [ "async-trait", "futures 0.3.21", "futures-timer", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sc-client-api", "sc-consensus", @@ -8631,7 +8631,7 @@ dependencies = [ name = "sc-executor-wasmi" version = "0.10.0-dev" dependencies = [ - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sc-allocator", "sc-executor-common", @@ -8648,7 +8648,7 @@ version = "0.10.0-dev" dependencies = [ "cfg-if 1.0.0", "libc", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parity-wasm 0.42.2", "sc-allocator", @@ -8675,7 +8675,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "hex", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "rand 0.8.4", @@ -8719,7 +8719,7 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "jsonrpc-pubsub", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sc-block-builder", "sc-client-api", @@ -8743,7 +8743,7 @@ dependencies = [ "ansi_term", "futures 0.3.21", "futures-timer", - "log 0.4.14", + "log 0.4.16", "parity-util-mem", "sc-client-api", "sc-network", @@ -8788,7 +8788,7 @@ dependencies = [ "libp2p", "linked-hash-map", "linked_hash_set", - "log 0.4.14", + "log 0.4.16", "lru 0.7.5", "parity-scale-codec", "parking_lot 0.12.0", @@ -8832,7 +8832,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "libp2p", - "log 0.4.14", + "log 0.4.16", "lru 0.7.5", "quickcheck", "sc-network", @@ -8851,7 +8851,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "libp2p", - "log 0.4.14", + "log 0.4.16", "parking_lot 0.12.0", "rand 0.7.3", "sc-block-builder", @@ -8911,7 +8911,7 @@ version = "4.0.0-dev" dependencies = [ "futures 0.3.21", "libp2p", - "log 0.4.14", + "log 0.4.16", "rand 0.7.3", "sc-utils", "serde_json", @@ -8922,7 +8922,7 @@ dependencies = [ name = "sc-proposer-metrics" version = "0.10.0-dev" dependencies = [ - "log 0.4.14", + "log 0.4.16", "substrate-prometheus-endpoint", ] @@ -8936,7 +8936,7 @@ dependencies = [ "jsonrpc-core", "jsonrpc-pubsub", "lazy_static", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "sc-block-builder", @@ -8972,7 +8972,7 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "jsonrpc-pubsub", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "sc-chain-spec", @@ -8998,7 +8998,7 @@ dependencies = [ "jsonrpc-ipc-server", "jsonrpc-pubsub", "jsonrpc-ws-server", - "log 0.4.14", + "log 0.4.16", "serde_json", "substrate-prometheus-endpoint", "tokio", @@ -9031,7 +9031,7 @@ dependencies = [ "hash-db", "jsonrpc-core", "jsonrpc-pubsub", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parity-util-mem", "parking_lot 0.12.0", @@ -9093,7 +9093,7 @@ dependencies = [ "futures 0.3.21", "hex", "hex-literal", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "sc-block-builder", @@ -9125,7 +9125,7 @@ dependencies = [ name = "sc-state-db" version = "0.10.0-dev" dependencies = [ - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parity-util-mem", "parity-util-mem-derive", @@ -9160,7 +9160,7 @@ version = "6.0.0-dev" dependencies = [ "futures 0.3.21", "libc", - "log 0.4.14", + "log 0.4.16", "rand 0.7.3", "rand_pcg 0.2.1", "regex", @@ -9179,7 +9179,7 @@ dependencies = [ "chrono", "futures 0.3.21", "libp2p", - "log 0.4.14", + "log 0.4.16", "parking_lot 0.12.0", "pin-project 1.0.10", "rand 0.7.3", @@ -9199,7 +9199,7 @@ dependencies = [ "criterion", "lazy_static", "libc", - "log 0.4.14", + "log 0.4.16", "once_cell", "parking_lot 0.12.0", "regex", @@ -9240,7 +9240,7 @@ dependencies = [ "futures-timer", "hex", "linked-hash-map", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parity-util-mem", "parking_lot 0.12.0", @@ -9269,7 +9269,7 @@ name = "sc-transaction-pool-api" version = "4.0.0-dev" dependencies = [ "futures 0.3.21", - "log 0.4.14", + "log 0.4.16", "serde", "sp-blockchain", "sp-runtime", @@ -9283,7 +9283,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "lazy_static", - "log 0.4.14", + "log 0.4.16", "parking_lot 0.12.0", "prometheus", "tokio-test", @@ -9766,7 +9766,7 @@ dependencies = [ "flate2", "futures 0.3.21", "httparse", - "log 0.4.14", + "log 0.4.16", "rand 0.8.4", "sha-1 0.9.4", ] @@ -9776,7 +9776,7 @@ name = "sp-api" version = "4.0.0-dev" dependencies = [ "hash-db", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sp-api-proc-macro", "sp-core", @@ -9805,7 +9805,7 @@ version = "2.0.1" dependencies = [ "criterion", "futures 0.3.21", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "rustversion", "sc-block-builder", @@ -9910,7 +9910,7 @@ name = "sp-blockchain" version = "4.0.0-dev" dependencies = [ "futures 0.3.21", - "log 0.4.14", + "log 0.4.16", "lru 0.7.5", "parity-scale-codec", "parking_lot 0.12.0", @@ -9929,7 +9929,7 @@ dependencies = [ "async-trait", "futures 0.3.21", "futures-timer", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sp-core", "sp-inherents", @@ -10034,7 +10034,7 @@ dependencies = [ "impl-serde", "lazy_static", "libsecp256k1", - "log 0.4.14", + "log 0.4.16", "merlin", "num-traits", "parity-scale-codec", @@ -10120,7 +10120,7 @@ name = "sp-finality-grandpa" version = "4.0.0-dev" dependencies = [ "finality-grandpa", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "scale-info", "serde", @@ -10153,7 +10153,7 @@ dependencies = [ "futures 0.3.21", "hash-db", "libsecp256k1", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parking_lot 0.12.0", "secp256k1", @@ -10211,7 +10211,7 @@ name = "sp-mmr-primitives" version = "4.0.0-dev" dependencies = [ "hex-literal", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "serde", "sp-api", @@ -10284,7 +10284,7 @@ dependencies = [ "either", "hash256-std-hasher", "impl-trait-for-tuples", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "parity-util-mem", "paste 1.0.6", @@ -10380,7 +10380,7 @@ name = "sp-sandbox" version = "0.10.0-dev" dependencies = [ "assert_matches", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sp-core", "sp-io", @@ -10427,7 +10427,7 @@ version = "0.12.0" dependencies = [ "hash-db", "hex-literal", - "log 0.4.14", + "log 0.4.16", "num-traits", "parity-scale-codec", "parking_lot 0.12.0", @@ -10465,7 +10465,7 @@ dependencies = [ name = "sp-tasks" version = "4.0.0-dev" dependencies = [ - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sp-core", "sp-externalities", @@ -10492,7 +10492,7 @@ version = "4.0.0-dev" dependencies = [ "async-trait", "futures-timer", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sp-api", "sp-inherents", @@ -10525,7 +10525,7 @@ name = "sp-transaction-storage-proof" version = "4.0.0-dev" dependencies = [ "async-trait", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "scale-info", "sp-core", @@ -10587,7 +10587,7 @@ name = "sp-wasm-interface" version = "6.0.0" dependencies = [ "impl-trait-for-tuples", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sp-std", "wasmi", @@ -10732,7 +10732,7 @@ dependencies = [ "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sc-client-api", "sc-rpc-api", @@ -10753,7 +10753,7 @@ version = "0.10.0-dev" dependencies = [ "futures-util", "hyper 0.14.16", - "log 0.4.14", + "log 0.4.16", "prometheus", "thiserror", "tokio", @@ -10766,7 +10766,7 @@ dependencies = [ "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "sc-client-api", "sc-rpc-api", @@ -10817,7 +10817,7 @@ dependencies = [ "frame-system", "frame-system-rpc-runtime-api", "futures 0.3.21", - "log 0.4.14", + "log 0.4.16", "memory-db", "pallet-babe", "pallet-timestamp", @@ -11190,7 +11190,7 @@ checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ "bytes 0.4.12", "futures 0.1.31", - "log 0.4.14", + "log 0.4.16", ] [[package]] @@ -11223,7 +11223,7 @@ dependencies = [ "crossbeam-utils 0.7.2", "futures 0.1.31", "lazy_static", - "log 0.4.14", + "log 0.4.16", "mio 0.6.23", "num_cpus", "parking_lot 0.9.0", @@ -11323,7 +11323,7 @@ dependencies = [ "bytes 1.1.0", "futures-core", "futures-sink", - "log 0.4.14", + "log 0.4.16", "pin-project-lite 0.2.6", "tokio", ] @@ -11364,7 +11364,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ "cfg-if 1.0.0", - "log 0.4.14", + "log 0.4.16", "pin-project-lite 0.2.6", "tracing-attributes", "tracing-core", @@ -11407,7 +11407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" dependencies = [ "lazy_static", - "log 0.4.14", + "log 0.4.16", "tracing-core", ] @@ -11480,7 +11480,7 @@ checksum = "d32d034c0d3db64b43c31de38e945f15b40cd4ca6d2dcfc26d4798ce8de4ab83" dependencies = [ "hash-db", "hashbrown 0.12.0", - "log 0.4.14", + "log 0.4.16", "rustc-hex", "smallvec 1.8.0", ] @@ -11520,7 +11520,7 @@ dependencies = [ "idna 0.2.2", "ipnet", "lazy_static", - "log 0.4.14", + "log 0.4.16", "rand 0.8.4", "smallvec 1.8.0", "thiserror", @@ -11538,7 +11538,7 @@ dependencies = [ "futures-util", "ipconfig", "lazy_static", - "log 0.4.14", + "log 0.4.16", "lru-cache", "parking_lot 0.11.2", "resolv-conf", @@ -11559,7 +11559,7 @@ version = "0.10.0-dev" dependencies = [ "clap 3.1.6", "jsonrpsee", - "log 0.4.14", + "log 0.4.16", "parity-scale-codec", "remote-externalities", "sc-chain-spec", @@ -11765,11 +11765,12 @@ dependencies = [ [[package]] name = "value-bag" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b676010e055c99033117c2343b33a40a30b91fecd6c49055ac9cd2d6c305ab1" +checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" dependencies = [ "ctor", + "version_check 0.9.2", ] [[package]] @@ -11834,7 +11835,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ - "log 0.4.14", + "log 0.4.16", "try-lock", ] @@ -11868,7 +11869,7 @@ checksum = "f34c405b4f0658583dba0c1c7c9b694f3cac32655db463b56c254a1c75269523" dependencies = [ "bumpalo", "lazy_static", - "log 0.4.14", + "log 0.4.16", "proc-macro2", "quote", "syn", @@ -11922,7 +11923,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0c32691b6c7e6c14e7f8fd55361a9088b507aa49620fcd06c09b3a1082186b9" dependencies = [ - "log 0.4.14", + "log 0.4.16", "parity-wasm 0.32.0", "rustc-demangle", ] @@ -12215,7 +12216,7 @@ dependencies = [ "indexmap", "lazy_static", "libc", - "log 0.4.14", + "log 0.4.16", "object 0.27.1", "once_cell", "paste 1.0.6", @@ -12244,7 +12245,7 @@ dependencies = [ "bincode", "directories-next", "file-per-thread-logger", - "log 0.4.14", + "log 0.4.16", "rustix", "serde", "sha2 0.9.8", @@ -12266,7 +12267,7 @@ dependencies = [ "cranelift-native", "cranelift-wasm", "gimli 0.26.1", - "log 0.4.14", + "log 0.4.16", "more-asserts", "object 0.27.1", "target-lexicon", @@ -12285,7 +12286,7 @@ dependencies = [ "cranelift-entity 0.82.3", "gimli 0.26.1", "indexmap", - "log 0.4.14", + "log 0.4.16", "more-asserts", "object 0.27.1", "serde", @@ -12307,7 +12308,7 @@ dependencies = [ "cfg-if 1.0.0", "cpp_demangle", "gimli 0.26.1", - "log 0.4.14", + "log 0.4.16", "object 0.27.1", "region 2.2.0", "rustc-demangle", @@ -12344,7 +12345,7 @@ dependencies = [ "cfg-if 1.0.0", "indexmap", "libc", - "log 0.4.14", + "log 0.4.16", "mach", "memoffset", "more-asserts", @@ -12633,7 +12634,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7d9028f208dd5e63c614be69f115c1b53cacc1111437d4c765185856666c107" dependencies = [ "futures 0.3.21", - "log 0.4.14", + "log 0.4.16", "nohash-hasher", "parking_lot 0.11.2", "rand 0.8.4", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 45a959ac16b14..2675c12d0d3b4 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] clap = { version = "3.1.6", features = ["derive"] } -log = "0.4.8" +log = "0.4.16" node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 1c6acce2c01df..5562efa1846e1 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -39,7 +39,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } futures = "0.3.21" hex-literal = "0.3.4" -log = "0.4.8" +log = "0.4.16" rand = "0.8" # primitives diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 75f860eb240e8..19d911a16552d 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } static_assertions = "1.1.0" hex-literal = { version = "0.3.4", optional = true } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } # primitives sp-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/authority-discovery" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 02d13f0c64718..fc072312debaa 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -45,7 +45,7 @@ sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-bu sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -log = "0.4.8" +log = "0.4.16" tempfile = "3.1.0" fs_extra = "1" futures = "0.3.21" diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index 8375c39ba4a14..190a150b57fff 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -16,5 +16,5 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } -log = "0.4.11" +log = "0.4.16" thiserror = "1.0.30" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index d209a311f45b9..8230f0baf3e72 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -24,7 +24,7 @@ fnv = "1.0.6" futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -log = "0.4.8" +log = "0.4.16" parking_lot = "0.12.0" sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index ba432d073698a..effc8cd715e1d 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -24,7 +24,7 @@ futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" libp2p = { version = "0.40.0", default-features = false, features = ["kad"] } -log = "0.4.8" +log = "0.4.16" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } prost = "0.9" rand = "0.7.2" diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 20560d4c834e7..6e0c15e1af2cc 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.8" +log = "0.4.16" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 1fabbca46968e..6a4d4b74f963e 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -19,7 +19,7 @@ fdlimit = "0.2.1" futures = "0.3.21" hex = "0.4.2" libp2p = "0.40.0" -log = "0.4.11" +log = "0.4.16" names = { version = "0.13.0", default-features = false } rand = "0.7.3" regex = "1.5.5" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index ac90d35dbce3c..beaa29d364672 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -25,7 +25,7 @@ sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/conse thiserror = "1.0" futures = "0.3.21" sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -log = "0.4.8" +log = "0.4.16" sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 20cc359849f52..48313cd0437e0 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -45,7 +45,7 @@ fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } futures = "0.3.21" parking_lot = "0.12.0" -log = "0.4.8" +log = "0.4.16" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } rand = "0.7.2" merlin = "2.0" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 4bd5cff457f5c..f4f7626ab6b7e 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] thiserror = "1.0.30" libp2p = { version = "0.40.0", default-features = false } -log = "0.4.8" +log = "0.4.16" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" sc-client-api = { version = "4.0.0-dev", path = "../../api" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 360cfe862f875..c1568ea488337 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.21" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" -log = "0.4.8" +log = "0.4.16" codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0", features = ["derive"] } assert_matches = "1.3.0" diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 4ddbf0c0ead7f..fc0151d293bbd 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -24,7 +24,7 @@ sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-consensus-pow = { version = "0.10.0-dev", path = "../../../primitives/consensus/pow" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -log = "0.4.8" +log = "0.4.16" futures = "0.3.21" futures-timer = "3.0.1" parking_lot = "0.12.0" diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 2884f8443e30e..8689818de8c17 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -29,7 +29,7 @@ sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.11" +log = "0.4.16" thiserror = "1.0.30" async-trait = "0.1.50" diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 12bb29958cfec..071e7aa78ddac 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] parking_lot = "0.12.0" -log = "0.4.8" +log = "0.4.16" kvdb = "0.11.0" kvdb-rocksdb = { version = "0.15.2", optional = true } kvdb-memorydb = "0.11.0" diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index cab254f1c71f6..99b8010c07502 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.8" +log = "0.4.16" wasmi = "0.9.1" codec = { package = "parity-scale-codec", version = "3.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 233c2e7d8f098..15f3a40cd46b1 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] libc = "0.2.121" cfg-if = "1.0" -log = "0.4.8" +log = "0.4.16" parity-wasm = "0.42.0" codec = { package = "parity-scale-codec", version = "3.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 58dc22192c0c1..2d011fb96be59 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -20,7 +20,7 @@ fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } futures = "0.3.21" futures-timer = "3.0.1" hex = "0.4.2" -log = "0.4.8" +log = "0.4.16" parking_lot = "0.12.0" rand = "0.8.4" ahash = "0.7.6" diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index e58763a4ebcc9..9ba994b5a66c7 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] ansi_term = "0.12.1" futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.8" +log = "0.4.16" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 6e566a100bae5..2989ff5b51412 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] futures = "0.3.21" futures-timer = "3.0.1" libp2p = { version = "0.40.0", default-features = false } -log = "0.4.8" +log = "0.4.16" lru = "0.7.5" ahash = "0.7.6" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index f0a6a949d1641..6fe804ce52413 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -35,7 +35,7 @@ ip_network = "0.4.1" linked-hash-map = "0.5.4" linked_hash_set = "0.1.3" lru = "0.7.5" -log = "0.4.8" +log = "0.4.16" parking_lot = "0.12.0" pin-project = "1.0.10" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 3c72bd404492e..642654bcb2de5 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-std = "1.11.0" sc-network = { version = "0.10.0-dev", path = "../" } -log = "0.4.8" +log = "0.4.16" parking_lot = "0.12.0" futures = "0.3.21" futures-timer = "3.0.1" diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index b292f300ba353..5cda0913da1a1 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] futures = "0.3.21" libp2p = { version = "0.40.0", default-features = false } sc-utils = { version = "4.0.0-dev", path = "../utils"} -log = "0.4.8" +log = "0.4.16" serde_json = "1.0.79" wasm-timer = "0.2" diff --git a/client/proposer-metrics/Cargo.toml b/client/proposer-metrics/Cargo.toml index 1a4b1fd4ce2c9..fc80d5b14fd8f 100644 --- a/client/proposer-metrics/Cargo.toml +++ b/client/proposer-metrics/Cargo.toml @@ -13,5 +13,5 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.8" +log = "0.4.16" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 20a18ec6c61cc..21354737ce2cb 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -19,7 +19,7 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" jsonrpc-pubsub = "18.0.0" -log = "0.4.8" +log = "0.4.16" parking_lot = "0.12.0" thiserror = "1.0" diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index c5af4ba200fe0..12f5c23493ad8 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] futures = "0.3.21" jsonrpc-core = "18.0.0" pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } -log = "0.4.8" +log = "0.4.16" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} serde_json = "1.0.79" tokio = { version = "1.17.0", features = ["parking_lot"] } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 4fea6501f693d..0035ddaa94502 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -19,7 +19,7 @@ sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" jsonrpc-pubsub = "18.0.0" -log = "0.4.8" +log = "0.4.16" sp-core = { version = "6.0.0", path = "../../primitives/core" } rpc = { package = "jsonrpc-core", version = "18.0.0" } sp-version = { version = "5.0.0", path = "../../primitives/version" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 490ef1cbb16b0..575305a597798 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -28,7 +28,7 @@ jsonrpc-pubsub = "18.0" jsonrpc-core = "18.0" rand = "0.7.3" parking_lot = "0.12.0" -log = "0.4.11" +log = "0.4.16" futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.10" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index ab92de4e84f8b..854e8f5b74659 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -16,7 +16,7 @@ hex = "0.4" hex-literal = "0.3.4" tempfile = "3.1.0" tokio = { version = "1.17.0", features = ["time"] } -log = "0.4.8" +log = "0.4.16" fdlimit = "0.2.1" parking_lot = "0.12.0" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 42ef4338b4066..3ca5a9065045f 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] parking_lot = "0.12.0" -log = "0.4.11" +log = "0.4.16" sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-core = { version = "6.0.0", path = "../../primitives/core" } codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } diff --git a/client/sysinfo/Cargo.toml b/client/sysinfo/Cargo.toml index 540918cb37c01..15e9545094cbf 100644 --- a/client/sysinfo/Cargo.toml +++ b/client/sysinfo/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.19" -log = "0.4.11" +log = "0.4.16" rand = "0.7.3" rand_pcg = "0.2.1" regex = "1" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 67583e325f34c..bb517290cef51 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -19,7 +19,7 @@ parking_lot = "0.12.0" futures = "0.3.21" wasm-timer = "0.2.5" libp2p = { version = "0.40.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } -log = "0.4.8" +log = "0.4.16" pin-project = "1.0.10" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 599e310a85157..121d55ca930b8 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -18,7 +18,7 @@ atty = "0.2.13" chrono = "0.4.19" lazy_static = "1.4.0" libc = "0.2.121" -log = { version = "0.4.8" } +log = { version = "0.4.16" } once_cell = "1.8.0" parking_lot = "0.12.0" regex = "1.5.5" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index df309760b847b..f651b2022032a 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } thiserror = "1.0.30" futures = "0.3.21" futures-timer = "3.0.2" -log = "0.4.8" +log = "0.4.16" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } parking_lot = "0.12.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 8dd5e7253f965..84395aaf2eace 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -10,7 +10,7 @@ description = "Transaction pool client facing API." [dependencies] futures = "0.3.21" -log = "0.4.8" +log = "0.4.16" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index a13a2d71f25d3..2c3af69b3b4a1 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -29,7 +29,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 87b8d7939e125..8a47fd7d9e7d2 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -27,7 +27,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } # third party -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking", optional = true, default-features = false } diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index e81c4f1a8d4e8..05675741ae51b 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -31,5 +31,5 @@ sp-std = { path = "../../../primitives/std", version = "4.0.0" } remote-externalities = { path = "../../../utils/frame/remote-externalities", version = "0.10.0-dev" } # others -log = "0.4.14" +log = "0.4.16" tokio = { version = "1", features = ["macros"] } diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index a0de11638e664..46a15f9c6d7ef 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -20,7 +20,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] sp-io = { version = "6.0.0", path = "../../primitives/io" } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 9da8198b405f7..40e16ad780a61 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/paritytech/substrate" [dependencies] hex = { version = "0.4", optional = true } codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } -log = { version = "0.4.13", default-features = false } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index ce301ff9034a2..aa551095d1d7e 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -26,7 +26,7 @@ sp-application-crypto = { version = "6.0.0", path = "../../primitives/applicatio sp-storage = { version = "6.0.0", path = "../../primitives/storage", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } serde = { version = "1.0.136", optional = true } [dev-dependencies] diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index a158895a252be..2eb8f486d3556 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -25,7 +25,7 @@ pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../ sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 9d2e1031604ec..b6a38fb22548d 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -26,7 +26,7 @@ pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../ sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index c9793e155c2a1..7e1186143270c 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 48134966a9253..50afd274c3f7d 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index a54301944a017..d9051dff8f2cb 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true } diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index 8daf0686d816c..ede25c2c939df 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } lite-json = { version = "0.1", default-features = false } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index cad238a4e365f..7312ae7da4cf8 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -28,7 +28,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index 277d4d2fb2de3..8ac2da0fbb053 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -24,7 +24,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 40ad619e904cc..a6ea127b79cba 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -log = { version = "0.4.0", default-features = false } +log = { version = "0.4.16", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 6ae1f21336b6c..cfd1939d36ed7 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -20,7 +20,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [features] default = ["std"] diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 01409d78053c5..bb728bd05f2a1 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -22,7 +22,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] sp-io = { version = "6.0.0", path = "../../primitives/io" } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 9000d1f693cca..577deb84e559a 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 28f2df47027bc..d1407f1509307 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { version = "0.4.0", default-features = false } +log = { version = "0.4.16", default-features = false } impl-trait-for-tuples = "0.2.2" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 073d959e2d1dd..66ac5e0ff1b36 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -30,7 +30,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, features = [ pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/staking/reward-fn/Cargo.toml b/frame/staking/reward-fn/Cargo.toml index 9a768becae830..f396030a1ae9a 100644 --- a/frame/staking/reward-fn/Cargo.toml +++ b/frame/staking/reward-fn/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../../primitives/arithmetic" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [features] default = ["std"] diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index 0124ba5b83283..0c6ad240281e1 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } sp-std = { default-features = false, path = "../../primitives/std" } sp-io = { default-features = false, path = "../../primitives/io" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index ce04fddb8521f..f0d663f7a26fa 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -33,7 +33,7 @@ sp-state-machine = { version = "0.12.0", optional = true, path = "../../primitiv bitflags = "1.3" impl-trait-for-tuples = "0.2.2" smallvec = "1.8.0" -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } k256 = { version = "0.10.2", default-features = false, features = ["ecdsa"] } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index e9196c4eb94f4..935038837d955 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -22,7 +22,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = fa sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-version = { version = "5.0.0", default-features = false, path = "../../primitives/version" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] criterion = "0.3.3" diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 72d632faf8583..83eb8a38eca77 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -25,7 +25,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../primitives/timestamp" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] sp-io ={ version = "6.0.0", path = "../../primitives/io" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index dc65d5c28d1c8..6cfdd2d1e7062 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.0", default-features = false } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index b0abb814eb5af..e8b95b8cb80c7 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -20,7 +20,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] sp-std = { version = "4.0.0", path = "../../primitives/std" } diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 83f897847f79a..01ce92c6eaa4f 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -22,7 +22,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -log = { version = "0.4.0", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index a0dd8eeb31e7a..3a94cd8e0bd88 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -23,7 +23,7 @@ sp-state-machine = { version = "0.12.0", optional = true, path = "../state-machi hash-db = { version = "0.15.2", optional = true } thiserror = { version = "1.0.30", optional = true } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } [dev-dependencies] sp-test-primitives = { version = "2.0.0", path = "../test-primitives" } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 9f9f399234db4..2acf09d46c886 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -27,7 +27,7 @@ rustversion = "1.0.6" [dev-dependencies] criterion = "0.3.0" futures = "0.3.21" -log = "0.4.14" +log = "0.4.16" sp-core = { version = "6.0.0", path = "../../core" } [[bench]] diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index c6fcdd3cb1c02..f242132798efa 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.11" +log = "0.4.16" lru = "0.7.5" parking_lot = "0.12.0" thiserror = "1.0.30" diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 35bd7f33fbf47..afbe437a16fa4 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = { version = "0.3.21", features = ["thread-pool"] } -log = "0.4.8" +log = "0.4.16" sp-core = { path = "../../core", version = "6.0.0"} sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } sp-state-machine = { version = "0.12.0", path = "../../state-machine" } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 402e3ebf07df1..9c79cb4843401 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "max-encoded-len", ] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -log = { version = "0.4.11", default-features = false } +log = { version = "0.4.16", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } primitive-types = { version = "0.11.1", default-features = false, features = ["codec", "scale-info"] } diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index ebc067e630c15..e6464207e67f2 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.15.0", default-features = false, features = ["derive-codec"] } -log = { version = "0.4.8", optional = true } +log = { version = "0.4.16", optional = true } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index bdae6174a87cb..9964fe2eea318 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -27,7 +27,7 @@ sp-runtime-interface = { version = "6.0.0", default-features = false, path = ".. sp-trie = { version = "6.0.0", optional = true, path = "../trie" } sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } -log = { version = "0.4.8", optional = true } +log = { version = "0.4.16", optional = true } futures = { version = "0.3.21", features = ["thread-pool"], optional = true } parking_lot = { version = "0.12.0", optional = true } secp256k1 = { version = "0.21.2", features = ["recovery", "global-context"], optional = true } diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index ddb820f9e6cc4..d6e244d50c495 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 9e9b01ebea3d2..2d6080f7af849 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -23,7 +23,7 @@ sp-application-crypto = { version = "6.0.0", default-features = false, path = ". sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } paste = "1.0" rand = { version = "0.7.2", optional = true } impl-trait-for-tuples = "0.2.2" diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 80651130575ea..0080c72b1f0d0 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { version = "0.4.11", optional = true } +log = { version = "0.4.16", optional = true } thiserror = { version = "1.0.30", optional = true } parking_lot = { version = "0.12.0", optional = true } hash-db = { version = "0.15.2", default-features = false } diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index 7f05afeaf0cec..bf97212d08914 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { version = "0.4.8", optional = true } +log = { version = "0.4.16", optional = true } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 176a4db5cb45b..db753b0b708d9 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -19,7 +19,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } thiserror = { version = "1.0.30", optional = true } -log = { version = "0.4.8", optional = true } +log = { version = "0.4.16", optional = true } futures-timer = { version = "3.0.2", optional = true } async-trait = { version = "0.1.50", optional = true } diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index 966142a7e14fa..7e8949d3da4b4 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -20,7 +20,7 @@ sp-trie = { version = "6.0.0", optional = true, path = "../trie" } sp-core = { version = "6.0.0", path = "../core", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -log = { version = "0.4.8", optional = true } +log = { version = "0.4.16", optional = true } async-trait = { version = "0.1.50", optional = true } [features] diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 775ab1c5b7060..3473370179b83 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] wasmi = { version = "0.9.1", optional = true } wasmtime = { version = "0.35.3", optional = true, default-features = false } -log = { version = "0.4.14", optional = true } +log = { version = "0.4.16", optional = true } impl-trait-for-tuples = "0.2.2" sp-std = { version = "4.0.0", path = "../std", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index cbefed27ca9bd..64767877548a9 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -48,7 +48,7 @@ sp-externalities = { version = "0.12.0", default-features = false, path = "../.. # 3rd party cfg-if = "1.0" -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } [dev-dependencies] diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 858d16558e821..8a3773fb10022 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -43,7 +43,7 @@ serde_json = "1.0.79" handlebars = "4.2.2" Inflector = "0.11.4" linked-hash-map = "0.5.4" -log = "0.4.8" +log = "0.4.16" itertools = "0.10.3" serde_nanos = "0.1.2" kvdb = "0.11.0" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 343dda6892759..7ca5b2f255e28 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -17,7 +17,7 @@ jsonrpsee = { version = "0.10.1", features = ["ws-client", "macros"] } env_logger = "0.9" frame-support = { path = "../../../frame/support", optional = true, version = "4.0.0-dev" } -log = "0.4.11" +log = "0.4.16" codec = { package = "parity-scale-codec", version = "3.0.0" } serde_json = "1.0" serde = "1.0.136" diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index deb641a89a466..3913bae425757 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } serde = { version = "1", features = ["derive"] } -log = { version = "0.4.14", default-features = false } +log = { version = "0.4.16", default-features = false } sp-std = { path = "../../../../primitives/std" } sp-io = { path = "../../../../primitives/io" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 31a6f93e847b1..9f3f2c6f266c5 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.21" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" -log = "0.4.8" +log = "0.4.16" sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index abbbe882c2fac..70c890a220a3a 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "3.1.6", features = ["derive"] } -log = "0.4.8" +log = "0.4.16" parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = { version = "0.10.0", default-features = false } diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 4940712f2f4d9..a9c3fd03e1688 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.8" +log = "0.4.16" prometheus = { version = "0.13.0", default-features = false } futures-util = { version = "0.3.19", default-features = false, features = ["io"] } thiserror = "1.0" From c66c1a2b9fa91d4a8421e6871b7d47ab3789328b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Apr 2022 22:46:34 +0200 Subject: [PATCH 0712/1472] Bump trybuild from 1.0.53 to 1.0.60 (#11237) Bumps [trybuild](https://github.com/dtolnay/trybuild) from 1.0.53 to 1.0.60. - [Release notes](https://github.com/dtolnay/trybuild/releases) - [Commits](https://github.com/dtolnay/trybuild/compare/1.0.53...1.0.60) --- updated-dependencies: - dependency-name: trybuild 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 | 7 ++++--- frame/election-provider-support/solution-type/Cargo.toml | 2 +- frame/support/test/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b7bb085b0962f..3d46093c38c4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11579,14 +11579,15 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.53" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d664de8ea7e531ad4c0f5a834f20b8cb2b8e6dfe88d05796ee7887518ed67b9" +checksum = "0da18123d1316f5a65fc9b94e30a0fcf58afb1daff1b8e18f41dc30f5bfc38c8" dependencies = [ "dissimilar", "glob", - "lazy_static", + "once_cell", "serde", + "serde_derive", "serde_json", "termcolor", "toml", diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index ca3038c9145ce..5f4454eda48df 100644 --- a/frame/election-provider-support/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -27,4 +27,4 @@ sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } # used by generate_solution_type: frame-election-provider-support = { version = "4.0.0-dev", path = ".." } frame-support = { version = "4.0.0-dev", path = "../../support" } -trybuild = "1.0.53" +trybuild = "1.0.60" diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 383b7cf812b41..f5f690a0468af 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -23,7 +23,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../../pri sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } -trybuild = { version = "1.0.53", features = [ "diff" ] } +trybuild = { version = "1.0.60", features = [ "diff" ] } pretty_assertions = "1.0.0" rustversion = "1.0.6" frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 2acf09d46c886..a36e68ecf9fe0 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -21,7 +21,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } codec = { package = "parity-scale-codec", version = "3.0.0" } sp-state-machine = { version = "0.12.0", path = "../../state-machine" } -trybuild = "1.0.53" +trybuild = "1.0.60" rustversion = "1.0.6" [dev-dependencies] diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 102592288af14..c9419f73722c6 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -31,7 +31,7 @@ sp-state-machine = { version = "0.12.0", path = "../state-machine" } sp-core = { version = "6.0.0", path = "../core" } sp-io = { version = "6.0.0", path = "../io" } rustversion = "1.0.6" -trybuild = "1.0.53" +trybuild = "1.0.60" [features] default = [ "std" ] From 7dd9798a5521343ae30ed3ac52212109febbab64 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Wed, 20 Apr 2022 13:56:07 -0700 Subject: [PATCH 0713/1472] Configurable call fee refund for signed submissions (#11002) * Refund call fee for all non-invalid signed submissions * Clean up * Fix benchmarks * Remove reward from struct * WIP SignedMaxRefunds * Apply suggestions from code review * Add test for ejected call_fee refunds * Add test for number of calls refunded * Account for read op in mutate * Apply suggestions from code review * Add to node runtime * Don't refund ejected solutions * Update frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Inegrity test SignedMaxRefunds * Use reward handle to refund call fee * Fix node runtime build * Drain in order of submission * Update frame/election-provider-multi-phase/src/signed.rs * save * Update frame/election-provider-multi-phase/src/signed.rs Co-authored-by: Niklas Adolfsson * Update frame/election-provider-multi-phase/src/signed.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Niklas Adolfsson Co-authored-by: Shawn Tabrizi --- bin/node/runtime/src/lib.rs | 1 + .../src/benchmarking.rs | 18 ++- .../election-provider-multi-phase/src/lib.rs | 24 +++- .../election-provider-multi-phase/src/mock.rs | 2 + .../src/signed.rs | 123 ++++++++++++++---- 5 files changed, 133 insertions(+), 35 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1da670b389192..c523ccc86fc7a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -674,6 +674,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type SignedRewardBase = SignedRewardBase; type SignedDepositBase = SignedDepositBase; type SignedDepositByte = SignedDepositByte; + type SignedMaxRefunds = ConstU32<3>; type SignedDepositWeight = (); type SignedMaxWeight = MinerMaxWeight; type SlashHandler = (); // burn slashes diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 923e9e2d984cc..6dfb2ac794810 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -225,14 +225,24 @@ frame_benchmarking::benchmarks! { compute: Default::default() }; let deposit: BalanceOf = 10u32.into(); - let reward: BalanceOf = 20u32.into(); + + let reward: BalanceOf = T::SignedRewardBase::get(); + let call_fee: BalanceOf = 30u32.into(); assert_ok!(T::Currency::reserve(&receiver, deposit)); assert_eq!(T::Currency::free_balance(&receiver), initial_balance - 10u32.into()); }: { - >::finalize_signed_phase_accept_solution(ready, &receiver, deposit, reward) + >::finalize_signed_phase_accept_solution( + ready, + &receiver, + deposit, + call_fee + ) } verify { - assert_eq!(T::Currency::free_balance(&receiver), initial_balance + 20u32.into()); + assert_eq!( + T::Currency::free_balance(&receiver), + initial_balance + reward + call_fee + ); assert_eq!(T::Currency::reserved_balance(&receiver), 0u32.into()); } @@ -333,7 +343,7 @@ frame_benchmarking::benchmarks! { raw_solution, who: account("submitters", i, SEED), deposit: Default::default(), - reward: Default::default(), + call_fee: Default::default(), }; signed_submissions.insert(signed_submission); } diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 5dc44d38fc365..a9e341bad600f 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -242,7 +242,7 @@ use frame_support::{ use frame_system::{ensure_none, offchain::SendTransactionTypes}; use scale_info::TypeInfo; use sp_arithmetic::{ - traits::{Bounded, CheckedAdd, Saturating, Zero}, + traits::{Bounded, CheckedAdd, Zero}, UpperOf, }; use sp_npos_elections::{ @@ -628,6 +628,10 @@ pub mod pallet { #[pallet::constant] type SignedMaxWeight: Get; + /// The maximum amount of unchecked solutions to refund the call fee for. + #[pallet::constant] + type SignedMaxRefunds: Get; + /// Base reward for a signed solution #[pallet::constant] type SignedRewardBase: Get>; @@ -848,6 +852,11 @@ pub mod pallet { ::MaxVotesPerVoter::get(), as NposSolution>::LIMIT as u32, ); + + // While it won't cause any failures, setting `SignedMaxRefunds` gt + // `SignedMaxSubmissions` is a red flag that the developer does not understand how to + // configure this pallet. + assert!(T::SignedMaxSubmissions::get() >= T::SignedMaxRefunds::get()); } } @@ -988,14 +997,17 @@ pub mod pallet { // create the submission let deposit = Self::deposit_for(&raw_solution, size); - let reward = { + let call_fee = { let call = Call::submit { raw_solution: raw_solution.clone() }; - let call_fee = T::EstimateCallFee::estimate_call_fee(&call, None.into()); - T::SignedRewardBase::get().saturating_add(call_fee) + T::EstimateCallFee::estimate_call_fee(&call, None.into()) }; - let submission = - SignedSubmission { who: who.clone(), deposit, raw_solution: *raw_solution, reward }; + let submission = SignedSubmission { + who: who.clone(), + deposit, + raw_solution: *raw_solution, + call_fee, + }; // insert the submission if the queue has space or it's better than the weakest // eject the weakest if the queue was full diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 2c9d7bb34dba5..38d9c8dfc1b7e 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -257,6 +257,7 @@ parameter_types! { pub static SignedPhase: BlockNumber = 10; pub static UnsignedPhase: BlockNumber = 5; pub static SignedMaxSubmissions: u32 = 5; + pub static SignedMaxRefunds: u32 = 1; pub static SignedDepositBase: Balance = 5; pub static SignedDepositByte: Balance = 0; pub static SignedDepositWeight: Balance = 0; @@ -427,6 +428,7 @@ impl crate::Config for Runtime { type SignedDepositWeight = (); type SignedMaxWeight = SignedMaxWeight; type SignedMaxSubmissions = SignedMaxSubmissions; + type SignedMaxRefunds = SignedMaxRefunds; type SlashHandler = (); type RewardHandler = (); type DataProvider = StakingMock; diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 465528068e71a..5f61eb7575da4 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -38,6 +38,7 @@ use sp_std::{ cmp::Ordering, collections::{btree_map::BTreeMap, btree_set::BTreeSet}, ops::Deref, + vec::Vec, }; /// A raw, unchecked signed submission. @@ -51,8 +52,8 @@ pub struct SignedSubmission { pub deposit: Balance, /// The raw solution itself. pub raw_solution: RawSolution, - /// The reward that should potentially be paid for this solution, if accepted. - pub reward: Balance, + // The estimated fee `who` paid to submit the solution. + pub call_fee: Balance, } impl Ord for SignedSubmission @@ -235,20 +236,33 @@ impl SignedSubmissions { } /// Empty the set of signed submissions, returning an iterator of signed submissions in - /// arbitrary order. + /// order of submission. /// /// Note that if the iterator is dropped without consuming all elements, not all may be removed /// from the underlying `SignedSubmissionsMap`, putting the storages into an invalid state. /// /// Note that, like `put`, this function consumes `Self` and modifies storage. - fn drain(mut self) -> impl Iterator> { + fn drain_submitted_order(mut self) -> impl Iterator> { + let mut keys = SignedSubmissionsMap::::iter_keys() + .filter(|k| { + if self.deletion_overlay.contains(k) { + // Remove submissions that should be deleted. + SignedSubmissionsMap::::remove(k); + false + } else { + true + } + }) + .chain(self.insertion_overlay.keys().copied()) + .collect::>(); + keys.sort(); + SignedSubmissionIndices::::kill(); SignedSubmissionNextIndex::::kill(); - let insertion_overlay = sp_std::mem::take(&mut self.insertion_overlay); - SignedSubmissionsMap::::drain() - .filter(move |(k, _v)| !self.deletion_overlay.contains(k)) - .map(|(_k, v)| v) - .chain(insertion_overlay.into_iter().map(|(_k, v)| v)) + + keys.into_iter().filter_map(move |index| { + SignedSubmissionsMap::::take(index).or_else(|| self.insertion_overlay.remove(&index)) + }) } /// Decode the length of the signed submissions without actually reading the entire struct into @@ -362,7 +376,7 @@ impl Pallet { Self::snapshot_metadata().unwrap_or_default(); while let Some(best) = all_submissions.pop_last() { - let SignedSubmission { raw_solution, who, deposit, reward } = best; + let SignedSubmission { raw_solution, who, deposit, call_fee } = best; let active_voters = raw_solution.solution.voter_count() as u32; let feasibility_weight = { // defensive only: at the end of signed phase, snapshot will exits. @@ -377,7 +391,7 @@ impl Pallet { ready_solution, &who, deposit, - reward, + call_fee, ); found_solution = true; @@ -396,10 +410,23 @@ impl Pallet { // Any unprocessed solution is pointless to even consider. Feasible or malicious, // they didn't end up being used. Unreserve the bonds. let discarded = all_submissions.len(); - for SignedSubmission { who, deposit, .. } in all_submissions.drain() { + let mut refund_count = 0; + let max_refunds = T::SignedMaxRefunds::get(); + + for SignedSubmission { who, deposit, call_fee, .. } in + all_submissions.drain_submitted_order() + { + if refund_count < max_refunds { + // Refund fee + let positive_imbalance = T::Currency::deposit_creating(&who, call_fee); + T::RewardHandler::on_unbalanced(positive_imbalance); + refund_count += 1; + } + + // Unreserve deposit let _remaining = T::Currency::unreserve(&who, deposit); - weight = weight.saturating_add(T::DbWeight::get().writes(1)); debug_assert!(_remaining.is_zero()); + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)); } debug_assert!(!SignedSubmissionIndices::::exists()); @@ -424,20 +451,22 @@ impl Pallet { ready_solution: ReadySolution, who: &T::AccountId, deposit: BalanceOf, - reward: BalanceOf, + call_fee: BalanceOf, ) { // write this ready solution. >::put(ready_solution); + let reward = T::SignedRewardBase::get(); // emit reward event Self::deposit_event(crate::Event::Rewarded { account: who.clone(), value: reward }); - // unreserve deposit. + // Unreserve deposit. let _remaining = T::Currency::unreserve(who, deposit); debug_assert!(_remaining.is_zero()); - // Reward. - let positive_imbalance = T::Currency::deposit_creating(who, reward); + // Reward and refund the call fee. + let positive_imbalance = + T::Currency::deposit_creating(who, reward.saturating_add(call_fee)); T::RewardHandler::on_unbalanced(positive_imbalance); } @@ -496,8 +525,8 @@ mod tests { use super::*; use crate::{ mock::{ - balances, raw_solution, roll_to, ExtBuilder, MultiPhase, Origin, Runtime, - SignedMaxSubmissions, SignedMaxWeight, + balances, raw_solution, roll_to, Balances, ExtBuilder, MultiPhase, Origin, Runtime, + SignedMaxRefunds, SignedMaxSubmissions, SignedMaxWeight, }, Error, Perbill, Phase, }; @@ -599,8 +628,8 @@ mod tests { // 99 is rewarded. assert_eq!(balances(&99), (100 + 7 + 8, 0)); - // 999 gets everything back. - assert_eq!(balances(&999), (100, 0)); + // 999 gets everything back, including the call fee. + assert_eq!(balances(&999), (100 + 8, 0)); }) } @@ -632,6 +661,44 @@ mod tests { }) } + #[test] + fn call_fee_refund_is_limited_by_signed_max_refunds() { + ExtBuilder::default().build_and_execute(|| { + roll_to(15); + assert!(MultiPhase::current_phase().is_signed()); + assert_eq!(SignedMaxRefunds::get(), 1); + assert!(SignedMaxSubmissions::get() > 2); + + for s in 0..SignedMaxSubmissions::get() { + let account = 99 + s as u64; + Balances::make_free_balance_be(&account, 100); + // score is always decreasing + let mut solution = raw_solution(); + solution.score.minimal_stake -= s as u128; + + assert_ok!(MultiPhase::submit(Origin::signed(account), Box::new(solution))); + assert_eq!(balances(&account), (95, 5)); + } + + assert!(MultiPhase::finalize_signed_phase()); + + for s in 0..SignedMaxSubmissions::get() { + let account = 99 + s as u64; + // lower accounts have higher scores + if s == 0 { + // winning solution always gets call fee + reward + assert_eq!(balances(&account), (100 + 8 + 7, 0)) + } else if s == 1 { + // 1 runner up gets their call fee refunded + assert_eq!(balances(&account), (100 + 8, 0)) + } else { + // all other solutions don't get a call fee refund + assert_eq!(balances(&account), (100, 0)); + } + } + }); + } + #[test] fn cannot_submit_worse_with_full_queue_depends_on_threshold() { ExtBuilder::default() @@ -687,12 +754,15 @@ mod tests { assert!(MultiPhase::current_phase().is_signed()); for s in 0..SignedMaxSubmissions::get() { + let account = 99 + s as u64; + Balances::make_free_balance_be(&account, 100); // score is always getting better let solution = RawSolution { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(Origin::signed(account), Box::new(solution))); + assert_eq!(balances(&account), (95, 5)); } assert_eq!( @@ -708,7 +778,7 @@ mod tests { score: ElectionScore { minimal_stake: 20, ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution))); // the one with score 5 was rejected, the new one inserted. assert_eq!( @@ -718,6 +788,9 @@ mod tests { .collect::>(), vec![6, 7, 8, 9, 20] ); + + // the submitter of the ejected solution does *not* get a call fee refund + assert_eq!(balances(&(99 + 0)), (100, 0)); }) } @@ -873,8 +946,8 @@ mod tests { assert_eq!(balances(&99), (100 + 7 + 8, 0)); // 999 is slashed. assert_eq!(balances(&999), (95, 0)); - // 9999 gets everything back. - assert_eq!(balances(&9999), (100, 0)); + // 9999 gets everything back, including the call fee. + assert_eq!(balances(&9999), (100 + 8, 0)); }) } From 6091c6ba54516b65071095b146beee796372c59f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 20 Apr 2022 23:03:34 +0200 Subject: [PATCH 0714/1472] Aura: Expose `SimpleSlotWorker` (#11247) Instead of just returning `SlotWorker` from `build_aura_worker` we now return `SimpleSlotWorker`. This is required for some future changes in Cumulus. --- client/consensus/aura/src/lib.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index f6ea2e08e1e88..d803aa4ae97f8 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -40,7 +40,8 @@ use codec::{Codec, Decode, Encode}; use sc_client_api::{backend::AuxStore, BlockOf, UsageProvider}; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy, StateAction}; use sc_consensus_slots::{ - BackoffAuthoringBlocksStrategy, InherentDataProviderExt, SlotInfo, StorageChanges, + BackoffAuthoringBlocksStrategy, InherentDataProviderExt, SimpleSlotWorkerToSlotWorker, + SlotInfo, StorageChanges, }; use sc_telemetry::TelemetryHandle; use sp_api::ProvideRuntimeApi; @@ -201,7 +202,7 @@ where Ok(sc_consensus_slots::start_slot_worker( slot_duration, select_chain, - worker, + SimpleSlotWorkerToSlotWorker(worker), sync_oracle, create_inherent_data_providers, can_author_with, @@ -256,7 +257,15 @@ pub fn build_aura_worker( telemetry, force_authoring, }: BuildAuraWorkerParams, -) -> impl sc_consensus_slots::SlotWorker>::Proof> +) -> impl sc_consensus_slots::SimpleSlotWorker< + B, + Proposer = PF::Proposer, + BlockImport = I, + SyncOracle = SO, + JustificationSyncLink = L, + Claim = P::Public, + EpochData = Vec>, +> where B: BlockT, C: ProvideRuntimeApi + BlockOf + AuxStore + HeaderBackend + Send + Sync, @@ -272,7 +281,7 @@ where L: sc_consensus::JustificationSyncLink, BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, { - sc_consensus_slots::SimpleSlotWorkerToSlotWorker(AuraWorker { + AuraWorker { client, block_import, env: proposer_factory, @@ -285,7 +294,7 @@ where block_proposal_slot_portion, max_block_proposal_slot_portion, _key_type: PhantomData::

, - }) + } } struct AuraWorker { @@ -448,11 +457,10 @@ where } fn proposer(&mut self, block: &B::Header) -> Self::CreateProposer { - Box::pin( - self.env - .init(block) - .map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e)).into()), - ) + self.env + .init(block) + .map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e)).into()) + .boxed() } fn telemetry(&self) -> Option { From 286775ab33e643db2f205b273bd4e35929b1c2b5 Mon Sep 17 00:00:00 2001 From: Dmitry Kashitsyn Date: Thu, 21 Apr 2022 15:06:04 +0600 Subject: [PATCH 0715/1472] Split `SandboxInstance::get_global_val` implementation per backend (#11234) --- client/executor/common/src/sandbox.rs | 30 +++++-------------- .../common/src/sandbox/wasmer_backend.rs | 14 +++++++++ .../common/src/sandbox/wasmi_backend.rs | 5 ++++ 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/client/executor/common/src/sandbox.rs b/client/executor/common/src/sandbox.rs index a2c1f602b1c9a..98eafaf32b8f9 100644 --- a/client/executor/common/src/sandbox.rs +++ b/client/executor/common/src/sandbox.rs @@ -36,13 +36,14 @@ use std::{collections::HashMap, rc::Rc}; #[cfg(feature = "wasmer-sandbox")] use wasmer_backend::{ - instantiate as wasmer_instantiate, invoke as wasmer_invoke, new_memory as wasmer_new_memory, - Backend as WasmerBackend, MemoryWrapper as WasmerMemoryWrapper, + get_global as wasmer_get_global, instantiate as wasmer_instantiate, invoke as wasmer_invoke, + new_memory as wasmer_new_memory, Backend as WasmerBackend, + MemoryWrapper as WasmerMemoryWrapper, }; use wasmi_backend::{ - instantiate as wasmi_instantiate, invoke as wasmi_invoke, new_memory as wasmi_new_memory, - MemoryWrapper as WasmiMemoryWrapper, + get_global as wasmi_get_global, instantiate as wasmi_instantiate, invoke as wasmi_invoke, + new_memory as wasmi_new_memory, MemoryWrapper as WasmiMemoryWrapper, }; /// Index of a function inside the supervisor. @@ -213,27 +214,10 @@ impl SandboxInstance { /// Returns `Some(_)` if the global could be found. pub fn get_global_val(&self, name: &str) -> Option { match &self.backend_instance { - BackendInstance::Wasmi(wasmi_instance) => { - let wasmi_global = wasmi_instance.export_by_name(name)?.as_global()?.get(); - - Some(wasmi_global.into()) - }, + BackendInstance::Wasmi(wasmi_instance) => wasmi_get_global(wasmi_instance, name), #[cfg(feature = "wasmer-sandbox")] - BackendInstance::Wasmer(wasmer_instance) => { - use sp_wasm_interface::Value; - - let global = wasmer_instance.exports.get_global(name).ok()?; - let wasmtime_value = match global.get() { - wasmer::Val::I32(val) => Value::I32(val), - wasmer::Val::I64(val) => Value::I64(val), - wasmer::Val::F32(val) => Value::F32(f32::to_bits(val)), - wasmer::Val::F64(val) => Value::F64(f64::to_bits(val)), - _ => None?, - }; - - Some(wasmtime_value) - }, + BackendInstance::Wasmer(wasmer_instance) => wasmer_get_global(wasmer_instance, name), } } } diff --git a/client/executor/common/src/sandbox/wasmer_backend.rs b/client/executor/common/src/sandbox/wasmer_backend.rs index 44b43757148de..fd2f317457f88 100644 --- a/client/executor/common/src/sandbox/wasmer_backend.rs +++ b/client/executor/common/src/sandbox/wasmer_backend.rs @@ -432,3 +432,17 @@ impl MemoryTransfer for MemoryWrapper { } } } + +/// Get global value by name +pub fn get_global(instance: &wasmer::Instance, name: &str) -> Option { + let global = instance.exports.get_global(name).ok()?; + let wasmtime_value = match global.get() { + wasmer::Val::I32(val) => Value::I32(val), + wasmer::Val::I64(val) => Value::I64(val), + wasmer::Val::F32(val) => Value::F32(f32::to_bits(val)), + wasmer::Val::F64(val) => Value::F64(f64::to_bits(val)), + _ => None?, + }; + + Some(wasmtime_value) +} diff --git a/client/executor/common/src/sandbox/wasmi_backend.rs b/client/executor/common/src/sandbox/wasmi_backend.rs index 92bb0e1e398e0..0954287f52f6b 100644 --- a/client/executor/common/src/sandbox/wasmi_backend.rs +++ b/client/executor/common/src/sandbox/wasmi_backend.rs @@ -321,3 +321,8 @@ pub fn invoke( }) }) } + +/// Get global value by name +pub fn get_global(instance: &wasmi::ModuleRef, name: &str) -> Option { + Some(instance.export_by_name(name)?.as_global()?.get().into()) +} From 137e6c3ea4150a81f0dfee3a45189c2d988e6b85 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Apr 2022 09:37:41 +0000 Subject: [PATCH 0716/1472] Bump proc-macro2 from 1.0.36 to 1.0.37 (#11191) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.36 to 1.0.37. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.36...1.0.37) --- 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 | 8 ++++---- client/chain-spec/derive/Cargo.toml | 2 +- client/tracing/proc-macro/Cargo.toml | 2 +- frame/election-provider-support/solution-type/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/tools/Cargo.toml | 2 +- frame/support/procedural/tools/derive/Cargo.toml | 2 +- primitives/api/proc-macro/Cargo.toml | 2 +- primitives/core/hashing/proc-macro/Cargo.toml | 2 +- primitives/runtime-interface/proc-macro/Cargo.toml | 2 +- primitives/version/proc-macro/Cargo.toml | 2 +- test-utils/derive/Cargo.toml | 2 +- 13 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d46093c38c4a..a1a23117235e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7282,9 +7282,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" dependencies = [ "unicode-xid", ] @@ -11691,9 +11691,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "universal-hash" diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index 9aa1d6c09405c..8cb5db5e42d91 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -16,7 +16,7 @@ proc-macro = true [dependencies] proc-macro-crate = "1.1.3" -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" quote = "1.0.10" syn = "1.0.82" diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index 645a6ed93a16f..b55c3482be3f4 100644 --- a/client/tracing/proc-macro/Cargo.toml +++ b/client/tracing/proc-macro/Cargo.toml @@ -16,6 +16,6 @@ proc-macro = true [dependencies] proc-macro-crate = "1.1.3" -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" quote = { version = "1.0.10", features = ["proc-macro"] } syn = { version = "1.0.82", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index 5f4454eda48df..a4e7256127115 100644 --- a/frame/election-provider-support/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] syn = { version = "1.0.82", features = ["full", "visit"] } quote = "1.0" -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" proc-macro-crate = "1.1.3" [dev-dependencies] diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index d53fb72b0e08a..dd8361ece6386 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] syn = { version = "1.0.82", features = ["full", "visit"] } quote = "1.0.10" -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" proc-macro-crate = "1.1.3" [dev-dependencies] diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 4e9618b5bc167..8f7438710dfdb 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -16,7 +16,7 @@ proc-macro = true [dependencies] frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" quote = "1.0.10" Inflector = "0.11.4" syn = { version = "1.0.82", features = ["full"] } diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index b38071dd31585..00c453b1f1928 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" } -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "visit", "extra-traits"] } proc-macro-crate = "1.1.3" diff --git a/frame/support/procedural/tools/derive/Cargo.toml b/frame/support/procedural/tools/derive/Cargo.toml index 5ed1b506dfb97..8d536be1cb725 100644 --- a/frame/support/procedural/tools/derive/Cargo.toml +++ b/frame/support/procedural/tools/derive/Cargo.toml @@ -15,6 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" quote = { version = "1.0.10", features = ["proc-macro"] } syn = { version = "1.0.82", features = ["proc-macro" ,"full", "extra-traits", "parsing"] } diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index dc5deb2efa668..24ce1360c80f7 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" blake2 = { version = "0.10.2", default-features = false } proc-macro-crate = "1.1.3" diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index b3dc155cd8bf3..9a5f991d04362 100644 --- a/primitives/core/hashing/proc-macro/Cargo.toml +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -18,5 +18,5 @@ proc-macro = true [dependencies] syn = { version = "1.0.82", features = ["full", "parsing"] } quote = "1.0.6" -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" sp-core-hashing = { version = "4.0.0", path = "../", default-features = false } diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index ef59e0119f9fe..3c66f371b7a0c 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -18,6 +18,6 @@ proc-macro = true [dependencies] syn = { version = "1.0.82", features = ["full", "visit", "fold", "extra-traits"] } quote = "1.0.10" -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" Inflector = "0.11.4" proc-macro-crate = "1.1.3" diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index e54012a516f2a..b9ab7cee0ad2c 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } [dev-dependencies] diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index 16e0b9822f7bb..afa729c5163e9 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -12,7 +12,7 @@ description = "Substrate test utilities macros" quote = "1.0.10" syn = { version = "1.0.82", features = ["full"] } proc-macro-crate = "1.1.3" -proc-macro2 = "1.0.36" +proc-macro2 = "1.0.37" [lib] proc-macro = true From f160775e154d949e14c1495496873444dba561f4 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Thu, 21 Apr 2022 06:50:17 -0700 Subject: [PATCH 0717/1472] staking: Fix `Reward` usage (#10887) * staking: Fix `Reward` usage * Some small fixes * Check on_unbalanced was called * Improve tests * Add not for Reward; FMT * :facepalm: Co-authored-by: parity-processbot <> --- frame/staking/src/mock.rs | 10 +++++++- frame/staking/src/pallet/impls.rs | 4 ++++ frame/staking/src/pallet/mod.rs | 2 ++ frame/staking/src/tests.rs | 40 +++++++++++++++++++++++++++---- 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 09809483ec155..324a367f48e00 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -237,6 +237,7 @@ const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub static MaxNominations: u32 = 16; + pub static RewardOnUnbalanceWasCalled: bool = false; } impl pallet_bags_list::Config for Test { @@ -255,6 +256,13 @@ impl onchain::Config for OnChainSeqPhragmen { type WeightInfo = (); } +pub struct MockReward {} +impl OnUnbalanced> for MockReward { + fn on_unbalanced(_: PositiveImbalanceOf) { + RewardOnUnbalanceWasCalled::set(true); + } +} + impl crate::pallet::pallet::Config for Test { type MaxNominations = MaxNominations; type Currency = Balances; @@ -263,7 +271,7 @@ impl crate::pallet::pallet::Config for Test { type RewardRemainder = RewardRemainderMock; type Event = Event; type Slash = (); - type Reward = (); + type Reward = MockReward; type SessionsPerEra = SessionsPerEra; type SlashDeferDuration = SlashDeferDuration; type SlashCancelOrigin = frame_system::EnsureRoot; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 90f19c6badd8f..96af7009bed0c 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -174,11 +174,13 @@ impl Pallet { Self::deposit_event(Event::::PayoutStarted(era, ledger.stash.clone())); + let mut total_imbalance = PositiveImbalanceOf::::zero(); // We can now make total validator payout: if let Some(imbalance) = Self::make_payout(&ledger.stash, validator_staking_payout + validator_commission_payout) { Self::deposit_event(Event::::Rewarded(ledger.stash, imbalance.peek())); + total_imbalance.subsume(imbalance); } // Track the number of payout ops to nominators. Note: @@ -199,9 +201,11 @@ impl Pallet { nominator_payout_count += 1; let e = Event::::Rewarded(nominator.who.clone(), imbalance.peek()); Self::deposit_event(e); + total_imbalance.subsume(imbalance); } } + T::Reward::on_unbalanced(total_imbalance); debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerValidator::get()); Ok(Some(T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count)).into()) } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 1a8fd59d23987..d24509033e024 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -121,6 +121,8 @@ pub mod pallet { type Slash: OnUnbalanced>; /// Handler for the unbalanced increment when rewarding a staker. + /// NOTE: in most cases, the implementation of `OnUnbalanced` should modify the total + /// issuance. type Reward: OnUnbalanced>; /// Number of sessions per era. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 7161418afc76e..f0de26b588577 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3370,26 +3370,47 @@ fn set_history_depth_works() { #[test] fn test_payout_stakers() { - // Here we will test validator can set `max_nominators_payout` and it works. - // We also test that `payout_extra_nominators` works. + // Test that payout_stakers work in general, including that only the top + // `T::MaxNominatorRewardedPerValidator` nominators are rewarded. ExtBuilder::default().has_stakers(false).build_and_execute(|| { let balance = 1000; + // Track the exposure of the validator and all nominators. + let mut total_exposure = balance; + // Track the exposure of the validator and the nominators that will get paid out. + let mut payout_exposure = balance; // Create a validator: bond_validator(11, 10, balance); // Default(64) + assert_eq!(Validators::::count(), 1); // Create nominators, targeting stash of validators for i in 0..100 { - bond_nominator(1000 + i, 100 + i, balance + i as Balance, vec![11]); + let bond_amount = balance + i as Balance; + bond_nominator(1000 + i, 100 + i, bond_amount, vec![11]); + total_exposure += bond_amount; + if i >= 36 { + payout_exposure += bond_amount; + }; } + let payout_exposure_part = Perbill::from_rational(payout_exposure, total_exposure); mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); // compute and ensure the reward amount is greater than zero. - let _ = current_total_payout_for_duration(reward_time_per_era()); + let payout = current_total_payout_for_duration(reward_time_per_era()); + let actual_paid_out = payout_exposure_part * payout; mock::start_active_era(2); + + let pre_payout_total_issuance = Balances::total_issuance(); + RewardOnUnbalanceWasCalled::set(false); assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); + assert_eq_error_rate!( + Balances::total_issuance(), + pre_payout_total_issuance + actual_paid_out, + 1 + ); + assert!(RewardOnUnbalanceWasCalled::get()); // Top 64 nominators of validator 11 automatically paid out, including the validator // Validator payout goes to controller. @@ -3418,10 +3439,19 @@ fn test_payout_stakers() { Staking::reward_by_ids(vec![(11, 1)]); // compute and ensure the reward amount is greater than zero. - let _ = current_total_payout_for_duration(reward_time_per_era()); + let payout = current_total_payout_for_duration(reward_time_per_era()); + let actual_paid_out = payout_exposure_part * payout; + let pre_payout_total_issuance = Balances::total_issuance(); mock::start_active_era(i); + RewardOnUnbalanceWasCalled::set(false); assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, i - 1)); + assert_eq_error_rate!( + Balances::total_issuance(), + pre_payout_total_issuance + actual_paid_out, + 1 + ); + assert!(RewardOnUnbalanceWasCalled::get()); } // We track rewards in `claimed_rewards` vec From 438b1f2d2b8173328151d99968fa487b23b5c84a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 21 Apr 2022 20:58:03 +0300 Subject: [PATCH 0718/1472] adjust BEEFY client logging (#11261) Move gossip filter logging to level=trace because it's very spammy. Move some debug-relevant logs from trace to debug. Signed-off-by: acatangiu --- client/beefy/src/gossip.rs | 2 +- client/beefy/src/round.rs | 2 +- client/beefy/src/worker.rs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/client/beefy/src/gossip.rs b/client/beefy/src/gossip.rs index 54d283fede32e..02d5efe9e0e58 100644 --- a/client/beefy/src/gossip.rs +++ b/client/beefy/src/gossip.rs @@ -220,7 +220,7 @@ where let round = msg.commitment.block_number; let allowed = known_votes.is_live(&round); - debug!(target: "beefy", "🥩 Message for round #{} allowed: {}", round, allowed); + trace!(target: "beefy", "🥩 Message for round #{} allowed: {}", round, allowed); allowed }) diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index eba769b2356f0..a5a15bac5f8f9 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -171,7 +171,7 @@ where let signatures = self.rounds.remove(round)?.votes; self.rounds.retain(|&(_, number), _| number > round.1); self.best_done = self.best_done.clone().max(Some(round.1.clone())); - trace!(target: "beefy", "🥩 Concluded round #{}", round.1); + debug!(target: "beefy", "🥩 Concluded round #{}", round.1); Some( self.validator_set diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 128850a5f172f..696bee9d7ee76 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -263,7 +263,7 @@ where } fn handle_finality_notification(&mut self, notification: &FinalityNotification) { - trace!(target: "beefy", "🥩 Finality notification: {:?}", notification); + debug!(target: "beefy", "🥩 Finality notification: {:?}", notification); let number = *notification.header.number(); // On start-up ignore old finality notifications that we're not interested in. @@ -332,7 +332,7 @@ where VersionedFinalityProof::V1(signed_commitment.clone()).encode(), ), ) { - trace!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, signed_commitment); + debug!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, signed_commitment); } self.signed_commitment_sender .notify(|| Ok::<_, ()>(signed_commitment)) @@ -352,7 +352,7 @@ where /// /// Also handle this self vote by calling `self.handle_vote()` for it. fn do_vote(&mut self, target_number: NumberFor) { - trace!(target: "beefy", "🥩 Try voting on {}", target_number); + debug!(target: "beefy", "🥩 Try voting on {}", target_number); // Most of the time we get here, `target` is actually `best_grandpa`, // avoid asking `client` for header in that case. @@ -455,7 +455,7 @@ where future::ready(false) } else { trace!(target: "beefy", "🥩 Finality notification: {:?}", notif); - trace!(target: "beefy", "🥩 Waiting for BEEFY pallet to become available..."); + debug!(target: "beefy", "🥩 Waiting for BEEFY pallet to become available..."); future::ready(true) } }) @@ -475,7 +475,7 @@ where let mut votes = Box::pin(self.gossip_engine.lock().messages_for(topic::()).filter_map( |notification| async move { - debug!(target: "beefy", "🥩 Got vote message: {:?}", notification); + trace!(target: "beefy", "🥩 Got vote message: {:?}", notification); VoteMessage::, AuthorityId, Signature>::decode( &mut ¬ification.message[..], @@ -577,7 +577,7 @@ where // we vote on it let target = match best_beefy { None => { - trace!( + debug!( target: "beefy", "🥩 vote target - mandatory block: #{:?}", session_start, @@ -585,7 +585,7 @@ where session_start }, Some(bbb) if bbb < session_start => { - trace!( + debug!( target: "beefy", "🥩 vote target - mandatory block: #{:?}", session_start, @@ -597,7 +597,7 @@ where let diff = diff.saturated_into::() / 2; let target = bbb + min_delta.max(diff.next_power_of_two()).into(); - trace!( + debug!( target: "beefy", "🥩 vote target - diff: {:?}, next_power_of_two: {:?}, target block: #{:?}", diff, From 4289b32f052e4ac0ce4c049000c0ef8bd5365a53 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Thu, 21 Apr 2022 15:53:54 -0700 Subject: [PATCH 0719/1472] staking: Proportional ledger slashing (#10982) * staking: Proportional ledger slashing * Some comment cleanup * Update frame/staking/src/pallet/mod.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fix benchmarks * FMT * Try fill in all staking configs * round of feedback and imp from kian * demonstrate per_thing usage * Update some tests * FMT * Test that era offset works correctly * Update mocks * Remove unnescary docs * Remove unlock_era * Update frame/staking/src/lib.rs * Adjust tests to account for only remove when < ED * Remove stale TODOs * Remove dupe test Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: kianenigma --- bin/node/runtime/src/lib.rs | 2 + frame/babe/src/mock.rs | 2 + frame/grandpa/src/mock.rs | 2 + frame/offences/benchmarking/src/mock.rs | 2 + frame/session/benchmarking/src/mock.rs | 2 + frame/staking/src/benchmarking.rs | 3 +- frame/staking/src/lib.rs | 161 +++++++++++------- frame/staking/src/mock.rs | 14 ++ frame/staking/src/pallet/impls.rs | 9 +- frame/staking/src/pallet/mod.rs | 25 ++- frame/staking/src/slashing.rs | 17 +- frame/staking/src/tests.rs | 215 +++++++++++++++++++++++- primitives/staking/src/lib.rs | 25 +++ 13 files changed, 402 insertions(+), 77 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index c523ccc86fc7a..c88dc8d731d03 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -537,6 +537,7 @@ impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { impl pallet_staking::Config for Runtime { type MaxNominations = MaxNominations; type Currency = Balances; + type CurrencyBalance = Balance; type UnixTime = Timestamp; type CurrencyToVote = U128CurrencyToVote; type RewardRemainder = Treasury; @@ -560,6 +561,7 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = onchain::UnboundedExecution; type VoterList = BagsList; type MaxUnlockingChunks = ConstU32<32>; + type OnStakerSlash = (); type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; } diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 15f53e7da0823..5677eb7e28e49 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -186,6 +186,7 @@ impl pallet_staking::Config for Test { type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type Event = Event; type Currency = Balances; + type CurrencyBalance = ::Balance; type Slash = (); type Reward = (); type SessionsPerEra = SessionsPerEra; @@ -202,6 +203,7 @@ impl pallet_staking::Config for Test { type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 67d5a3d7fd373..5700fbe3aa36e 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -194,6 +194,7 @@ impl pallet_staking::Config for Test { type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type Event = Event; type Currency = Balances; + type CurrencyBalance = ::Balance; type Slash = (); type Reward = (); type SessionsPerEra = SessionsPerEra; @@ -210,6 +211,7 @@ impl pallet_staking::Config for Test { type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 74cc29586920d..fba8c567059c2 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -161,6 +161,7 @@ impl onchain::Config for OnChainSeqPhragmen { impl pallet_staking::Config for Test { type MaxNominations = ConstU32<16>; type Currency = Balances; + type CurrencyBalance = ::Balance; type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = (); @@ -180,6 +181,7 @@ impl pallet_staking::Config for Test { type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 5acc484f9ba62..6835736aa8e00 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -167,6 +167,7 @@ impl onchain::Config for OnChainSeqPhragmen { impl pallet_staking::Config for Test { type MaxNominations = ConstU32<16>; type Currency = Balances; + type CurrencyBalance = ::Balance; type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = (); @@ -186,6 +187,7 @@ impl pallet_staking::Config for Test { type GenesisElectionProvider = Self::ElectionProvider; type MaxUnlockingChunks = ConstU32<32>; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 983f1bd54deb7..6c1589417f15a 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -802,7 +802,8 @@ benchmarks! { &stash, slash_amount, &mut BalanceOf::::zero(), - &mut NegativeImbalanceOf::::zero() + &mut NegativeImbalanceOf::::zero(), + EraIndex::zero() ); } verify { let balance_after = T::Currency::free_balance(&stash); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 872ed2e1af404..8003b9814c8e6 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -302,7 +302,7 @@ mod pallet; use codec::{Decode, Encode, HasCompact}; use frame_support::{ parameter_types, - traits::{Currency, Get}, + traits::{Currency, Defensive, Get}, weights::Weight, BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; @@ -310,7 +310,7 @@ use scale_info::TypeInfo; use sp_runtime::{ curve::PiecewiseLinear, traits::{AtLeast32BitUnsigned, Convert, Saturating, Zero}, - Perbill, RuntimeDebug, + Perbill, Perquintill, RuntimeDebug, }; use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, @@ -338,8 +338,7 @@ macro_rules! log { pub type RewardPoint = u32; /// The balance type of this pallet. -pub type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; +pub type BalanceOf = ::CurrencyBalance; type PositiveImbalanceOf = <::Currency as Currency< ::AccountId, @@ -440,31 +439,30 @@ pub struct UnlockChunk { /// The ledger of a (bonded) stash. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct StakingLedger { +#[scale_info(skip_type_params(T))] +pub struct StakingLedger { /// The stash account whose balance is actually locked and at stake. - pub stash: AccountId, + pub stash: T::AccountId, /// The total amount of the stash's balance that we are currently accounting for. /// It's just `active` plus all the `unlocking` balances. #[codec(compact)] - pub total: Balance, + pub total: BalanceOf, /// The total amount of the stash's balance that will be at stake in any forthcoming /// rounds. #[codec(compact)] - pub active: Balance, + pub active: BalanceOf, /// Any balance that is becoming free, which may eventually be transferred out of the stash /// (assuming it doesn't get slashed first). It is assumed that this will be treated as a first /// in, first out queue where the new (higher value) eras get pushed on the back. - pub unlocking: BoundedVec, MaxUnlockingChunks>, + pub unlocking: BoundedVec>, MaxUnlockingChunks>, /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. pub claimed_rewards: Vec, } -impl - StakingLedger -{ +impl StakingLedger { /// Initializes the default object using the given `validator`. - pub fn default_from(stash: AccountId) -> Self { + pub fn default_from(stash: T::AccountId) -> Self { Self { stash, total: Zero::zero(), @@ -507,8 +505,8 @@ impl (Self, Balance) { - let mut unlocking_balance: Balance = Zero::zero(); + fn rebond(mut self, value: BalanceOf) -> (Self, BalanceOf) { + let mut unlocking_balance = BalanceOf::::zero(); while let Some(last) = self.unlocking.last_mut() { if unlocking_balance + last.value <= value { @@ -530,57 +528,96 @@ impl StakingLedger -where - Balance: AtLeast32BitUnsigned + Saturating + Copy, -{ - /// Slash the validator for a given amount of balance. This can grow the value - /// of the slash in the case that the validator has less than `minimum_balance` - /// active funds. Returns the amount of funds actually slashed. + /// Slash the staker for a given amount of balance. This can grow the value of the slash in the + /// case that either the active bonded or some unlocking chunks become dust after slashing. + /// Returns the amount of funds actually slashed. /// - /// Slashes from `active` funds first, and then `unlocking`, starting with the - /// chunks that are closest to unlocking. - fn slash(&mut self, mut value: Balance, minimum_balance: Balance) -> Balance { - let pre_total = self.total; - let total = &mut self.total; - let active = &mut self.active; - - let slash_out_of = - |total_remaining: &mut Balance, target: &mut Balance, value: &mut Balance| { - let mut slash_from_target = (*value).min(*target); - - if !slash_from_target.is_zero() { - *target -= slash_from_target; - - // Don't leave a dust balance in the staking system. - if *target <= minimum_balance { - slash_from_target += *target; - *value += sp_std::mem::replace(target, Zero::zero()); - } - - *total_remaining = total_remaining.saturating_sub(slash_from_target); - *value -= slash_from_target; - } - }; - - slash_out_of(total, active, &mut value); - - let i = self - .unlocking - .iter_mut() - .map(|chunk| { - slash_out_of(total, &mut chunk.value, &mut value); - chunk.value - }) - .take_while(|value| value.is_zero()) // Take all fully-consumed chunks out. - .count(); + /// # Note + /// + /// This calls `Config::OnStakerSlash::on_slash` with information as to how the slash + /// was applied. + fn slash( + &mut self, + slash_amount: BalanceOf, + minimum_balance: BalanceOf, + slash_era: EraIndex, + ) -> BalanceOf { + use sp_staking::OnStakerSlash as _; + + if slash_amount.is_zero() { + return Zero::zero() + } - // Kill all drained chunks. - let _ = self.unlocking.drain(..i); + let mut remaining_slash = slash_amount; + let pre_slash_total = self.total; + + let era_after_slash = slash_era + 1; + let chunk_unlock_era_after_slash = era_after_slash + T::BondingDuration::get(); + + // Calculate the total balance of active funds and unlocking funds in the affected range. + let (affected_balance, slash_chunks_priority): (_, Box>) = { + if let Some(start_index) = + self.unlocking.iter().position(|c| c.era >= chunk_unlock_era_after_slash) + { + // The indices of the first chunk after the slash up through the most recent chunk. + // (The most recent chunk is at greatest from this era) + let affected_indices = start_index..self.unlocking.len(); + let unbonding_affected_balance = + affected_indices.clone().fold(BalanceOf::::zero(), |sum, i| { + if let Some(chunk) = self.unlocking.get_mut(i).defensive() { + sum.saturating_add(chunk.value) + } else { + sum + } + }); + ( + self.active.saturating_add(unbonding_affected_balance), + Box::new(affected_indices.chain((0..start_index).rev())), + ) + } else { + (self.active, Box::new((0..self.unlocking.len()).rev())) + } + }; + + // Helper to update `target` and the ledgers total after accounting for slashing `target`. + let ratio = Perquintill::from_rational(slash_amount, affected_balance); + let mut slash_out_of = |target: &mut BalanceOf, slash_remaining: &mut BalanceOf| { + let mut slash_from_target = + if slash_amount < affected_balance { ratio * (*target) } else { *slash_remaining } + .min(*target); + + // slash out from *target exactly `slash_from_target`. + *target = *target - slash_from_target; + if *target < minimum_balance { + // Slash the rest of the target if its dust + slash_from_target = + sp_std::mem::replace(target, Zero::zero()).saturating_add(slash_from_target) + } - pre_total.saturating_sub(*total) + self.total = self.total.saturating_sub(slash_from_target); + *slash_remaining = slash_remaining.saturating_sub(slash_from_target); + }; + + // If this is *not* a proportional slash, the active will always wiped to 0. + slash_out_of(&mut self.active, &mut remaining_slash); + + let mut slashed_unlocking = BTreeMap::<_, _>::new(); + for i in slash_chunks_priority { + if let Some(chunk) = self.unlocking.get_mut(i).defensive() { + slash_out_of(&mut chunk.value, &mut remaining_slash); + // write the new slashed value of this chunk to the map. + slashed_unlocking.insert(chunk.era, chunk.value); + if remaining_slash.is_zero() { + break + } + } else { + break + } + } + self.unlocking.retain(|c| !c.value.is_zero()); + T::OnStakerSlash::on_slash(&self.stash, self.active, &slashed_unlocking); + pre_slash_total.saturating_sub(self.total) } } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 324a367f48e00..24572855264c4 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -238,6 +238,7 @@ parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub static MaxNominations: u32 = 16; pub static RewardOnUnbalanceWasCalled: bool = false; + pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); } impl pallet_bags_list::Config for Test { @@ -263,9 +264,21 @@ impl OnUnbalanced> for MockReward { } } +pub struct OnStakerSlashMock(core::marker::PhantomData); +impl sp_staking::OnStakerSlash for OnStakerSlashMock { + fn on_slash( + _pool_account: &AccountId, + slashed_bonded: Balance, + slashed_chunks: &BTreeMap, + ) { + LedgerSlashPerEra::set((slashed_bonded, slashed_chunks.clone())); + } +} + impl crate::pallet::pallet::Config for Test { type MaxNominations = MaxNominations; type Currency = Balances; + type CurrencyBalance = ::Balance; type UnixTime = Timestamp; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = RewardRemainderMock; @@ -286,6 +299,7 @@ impl crate::pallet::pallet::Config for Test { // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. type VoterList = BagsList; type MaxUnlockingChunks = ConstU32<32>; + type OnStakerSlash = OnStakerSlashMock; type BenchmarkingConfig = TestBenchmarkingConfig; type WeightInfo = (); } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 96af7009bed0c..ea4235f274da3 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -213,10 +213,7 @@ impl Pallet { /// Update the ledger for a controller. /// /// This will also update the stash lock. - pub(crate) fn update_ledger( - controller: &T::AccountId, - ledger: &StakingLedger>, - ) { + pub(crate) fn update_ledger(controller: &T::AccountId, ledger: &StakingLedger) { T::Currency::set_lock(STAKING_ID, &ledger.stash, ledger.total, WithdrawReasons::all()); >::insert(controller, ledger); } @@ -606,7 +603,7 @@ impl Pallet { for era in (*earliest)..keep_from { let era_slashes = ::UnappliedSlashes::take(&era); for slash in era_slashes { - slashing::apply_slash::(slash); + slashing::apply_slash::(slash, era); } } @@ -1248,7 +1245,7 @@ where unapplied.reporters = details.reporters.clone(); if slash_defer_duration == 0 { // Apply right away. - slashing::apply_slash::(unapplied); + slashing::apply_slash::(unapplied, slash_era); { let slash_cost = (6, 5); let reward_cost = (2, 2); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index d24509033e024..f57d5bd7c7a0a 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -75,8 +75,22 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + SendTransactionTypes> { /// The staking balance. - type Currency: LockableCurrency; - + type Currency: LockableCurrency< + Self::AccountId, + Moment = Self::BlockNumber, + Balance = Self::CurrencyBalance, + >; + /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to + /// `From`. + type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned + + codec::FullCodec + + Copy + + MaybeSerializeDeserialize + + sp_std::fmt::Debug + + Default + + From + + TypeInfo + + MaxEncodedLen; /// Time used for computing era duration. /// /// It is guaranteed to start being called from the first `on_finalize`. Thus value at @@ -177,6 +191,10 @@ pub mod pallet { #[pallet::constant] type MaxUnlockingChunks: Get; + /// A hook called when any staker is slashed. Mostly likely this can be a no-op unless + /// other pallets exist that are affected by slashing per-staker. + type OnStakerSlash: sp_staking::OnStakerSlash>; + /// Some parameters of the benchmarking. type BenchmarkingConfig: BenchmarkingConfig; @@ -239,8 +257,7 @@ pub mod pallet { /// Map from all (unlocked) "controller" accounts to the info regarding the staking. #[pallet::storage] #[pallet::getter(fn ledger)] - pub type Ledger = - StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger>>; + pub type Ledger = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger>; /// Where the reward payment should be made. Keyed by stash. #[pallet::storage] diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 2f381ad631fe5..9fc50eaf538f6 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -598,6 +598,7 @@ pub fn do_slash( value: BalanceOf, reward_payout: &mut BalanceOf, slashed_imbalance: &mut NegativeImbalanceOf, + slash_era: EraIndex, ) { let controller = match >::bonded(stash) { None => return, // defensive: should always exist. @@ -609,7 +610,7 @@ pub fn do_slash( None => return, // nothing to do. }; - let value = ledger.slash(value, T::Currency::minimum_balance()); + let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era); if !value.is_zero() { let (imbalance, missing) = T::Currency::slash(stash, value); @@ -628,7 +629,10 @@ pub fn do_slash( } /// Apply a previously-unapplied slash. -pub(crate) fn apply_slash(unapplied_slash: UnappliedSlash>) { +pub(crate) fn apply_slash( + unapplied_slash: UnappliedSlash>, + slash_era: EraIndex, +) { let mut slashed_imbalance = NegativeImbalanceOf::::zero(); let mut reward_payout = unapplied_slash.payout; @@ -637,10 +641,17 @@ pub(crate) fn apply_slash(unapplied_slash: UnappliedSlash(&nominator, nominator_slash, &mut reward_payout, &mut slashed_imbalance); + do_slash::( + &nominator, + nominator_slash, + &mut reward_payout, + &mut slashed_imbalance, + slash_era, + ); } pay_reporters::(reward_payout, slashed_imbalance, &unapplied_slash.reporters); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index f0de26b588577..21d4714985c6b 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2104,7 +2104,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { &[Perbill::from_percent(100)], ); - assert_eq!(Balances::total_balance(&11), stake - 1); + assert_eq!(Balances::total_balance(&11), stake); assert_eq!(Balances::total_balance(&2), 1); }) } @@ -4854,3 +4854,216 @@ fn force_apply_min_commission_works() { ); }); } + +#[test] +fn ledger_slash_works() { + let c = |era, value| UnlockChunk:: { era, value }; + // Given + let mut ledger = StakingLedger:: { + stash: 123, + total: 10, + active: 10, + unlocking: bounded_vec![], + claimed_rewards: vec![], + }; + + assert_eq!(BondingDuration::get(), 3); + + // When we slash a ledger with no unlocking chunks + assert_eq!(ledger.slash(5, 1, 0), 5); + // Then + assert_eq!(ledger.total, 5); + assert_eq!(ledger.active, 5); + assert_eq!(LedgerSlashPerEra::get().0, 5); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); + + // When we slash a ledger with no unlocking chunks and the slash amount is greater then the + // total + assert_eq!(ledger.slash(11, 1, 0), 5); + // Then + assert_eq!(ledger.total, 0); + assert_eq!(ledger.active, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); + + // Given + ledger.unlocking = bounded_vec![c(4, 10), c(5, 10)]; + ledger.total = 2 * 10; + ledger.active = 0; + // When all the chunks overlap with the slash eras + assert_eq!(ledger.slash(20, 0, 0), 20); + // Then + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.total = 4 * 100; + ledger.active = 0; + // When the first 2 chunks don't overlap with the affected range of unlock eras. + assert_eq!(ledger.slash(140, 0, 2), 140); + // Then + assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]); + assert_eq!(ledger.total, 4 * 100 - 140); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + // 900 + ledger.total = 40 + 10 + 100 + 250 + 500; + // When we have a partial slash that touches all chunks + assert_eq!(ledger.slash(900 / 2, 0, 0), 450); + // Then + assert_eq!(ledger.active, 500 / 2); + assert_eq!(ledger.unlocking, vec![c(4, 40 / 2), c(5, 100 / 2), c(6, 10 / 2), c(7, 250 / 2)]); + assert_eq!(ledger.total, 900 / 2); + assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 40 / 2), (5, 100 / 2), (6, 10 / 2), (7, 250 / 2)]) + ); + + // slash 1/4th with not chunk. + ledger.unlocking = bounded_vec![]; + ledger.active = 500; + ledger.total = 500; + // When we have a partial slash that touches all chunks + assert_eq!(ledger.slash(500 / 4, 0, 0), 500 / 4); + // Then + assert_eq!(ledger.active, 3 * 500 / 4); + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, ledger.active); + assert_eq!(LedgerSlashPerEra::get().0, 3 * 500 / 4); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); + + // Given we have the same as above, + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + ledger.total = 40 + 10 + 100 + 250 + 500; // 900 + assert_eq!(ledger.total, 900); + // When we have a higher min balance + assert_eq!( + ledger.slash( + 900 / 2, + 25, /* min balance - chunks with era 0 & 2 will be slashed to <=25, causing it to + * get swept */ + 0 + ), + 475 + ); + let dust = (10 / 2) + (40 / 2); + assert_eq!(ledger.active, 500 / 2); + assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 250 / 2)]); + assert_eq!(ledger.total, 900 / 2 - dust); + assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 250 / 2)]) + ); + + // Given + // slash order --------------------NA--------2----------0----------1---- + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + ledger.total = 40 + 10 + 100 + 250 + 500; // 900 + assert_eq!( + ledger.slash( + 500 + 10 + 250 + 100 / 2, // active + era 6 + era 7 + era 5 / 2 + 0, + 2 /* slash era 2+4 first, so the affected parts are era 2+4, era 3+4 and + * ledge.active. This will cause the affected to go to zero, and then we will + * start slashing older chunks */ + ), + 500 + 250 + 10 + 100 / 2 + ); + // Then + assert_eq!(ledger.active, 0); + assert_eq!(ledger.unlocking, vec![c(4, 40), c(5, 100 / 2)]); + assert_eq!(ledger.total, 90); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 100 / 2), (6, 0), (7, 0)])); + + // Given + // iteration order------------------NA---------2----------0----------1---- + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.active = 100; + ledger.total = 5 * 100; + // When + assert_eq!( + ledger.slash( + 351, // active + era 6 + era 7 + era 5 / 2 + 1 + 50, // min balance - everything slashed below 50 will get dusted + 2 /* slash era 2+4 first, so the affected parts are era 2+4, era 3+4 and + * ledge.active. This will cause the affected to go to zero, and then we will + * start slashing older chunks */ + ), + 400 + ); + // Then + assert_eq!(ledger.active, 0); + assert_eq!(ledger.unlocking, vec![c(4, 100)]); + assert_eq!(ledger.total, 100); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 0), (6, 0), (7, 0)])); + + // Tests for saturating arithmetic + + // Given + let slash = u64::MAX as Balance * 2; + let value = slash + - (9 * 4) // The value of the other parts of ledger that will get slashed + + 1; + + ledger.active = 10; + ledger.unlocking = bounded_vec![c(4, 10), c(5, 10), c(6, 10), c(7, value)]; + ledger.total = value + 40; + // When + let slash_amount = ledger.slash(slash, 0, 0); + assert_eq_error_rate!(slash_amount, slash, 5); + // Then + assert_eq!(ledger.active, 0); // slash of 9 + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0), (6, 0), (7, 0)])); + + // Given + let slash = u64::MAX as Balance * 2; + let value = u64::MAX as Balance * 2; + let unit = 100; + // slash * value that will saturate + assert!(slash.checked_mul(value).is_none()); + // but slash * unit won't. + assert!(slash.checked_mul(unit).is_some()); + ledger.unlocking = bounded_vec![c(4, unit), c(5, value), c(6, unit), c(7, unit)]; + //--------------------------------------note value^^^ + ledger.active = unit; + ledger.total = unit * 4 + value; + // When + assert_eq!(ledger.slash(slash, 0, 0), slash - 43); + // Then + // The amount slashed out of `unit` + let affected_balance = value + unit * 4; + let ratio = Perquintill::from_rational(slash, affected_balance); + // `unit` after the slash is applied + let unit_slashed = { + let unit_slash = ratio * unit; + unit - unit_slash + }; + let value_slashed = { + let value_slash = ratio * value; + value - value_slash + }; + assert_eq!(ledger.active, unit_slashed); + assert_eq!(ledger.unlocking, vec![c(5, value_slashed)]); + assert_eq!(ledger.total, value_slashed); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 0)]) + ); +} diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index 15208df62cc66..57d858be1e0ef 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -19,6 +19,7 @@ //! A crate which contains primitives that are useful for implementation that uses staking //! approaches in general. Definitions related to sessions, slashing, etc go here. +use sp_std::collections::btree_map::BTreeMap; pub mod offence; @@ -27,3 +28,27 @@ pub type SessionIndex = u32; /// Counter for the number of eras that have passed. pub type EraIndex = u32; + +/// Trait describing something that implements a hook for any operations to perform when a staker is +/// slashed. +pub trait OnStakerSlash { + /// A hook for any operations to perform when a staker is slashed. + /// + /// # Arguments + /// + /// * `stash` - The stash of the staker whom the slash was applied to. + /// * `slashed_active` - The new bonded balance of the staker after the slash was applied. + /// * `slashed_unlocking` - a map of slashed eras, and the balance of that unlocking chunk after + /// the slash is applied. Any era not present in the map is not affected at all. + fn on_slash( + stash: &AccountId, + slashed_active: Balance, + slashed_unlocking: &BTreeMap, + ); +} + +impl OnStakerSlash for () { + fn on_slash(_: &AccountId, _: Balance, _: &BTreeMap) { + // Nothing to do here + } +} From 02b7dc67d239cf09dee0f9e7e8cf2f0212e39e5f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Apr 2022 10:39:33 +0200 Subject: [PATCH 0720/1472] Bump tracing-core from 0.1.21 to 0.1.26 (#11258) Bumps [tracing-core](https://github.com/tokio-rs/tracing) from 0.1.21 to 0.1.26. - [Release notes](https://github.com/tokio-rs/tracing/releases) - [Commits](https://github.com/tokio-rs/tracing/compare/tracing-core-0.1.21...tracing-core-0.1.26) --- updated-dependencies: - dependency-name: tracing-core 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 | 11 +++++++++-- primitives/io/Cargo.toml | 2 +- primitives/runtime-interface/test/Cargo.toml | 2 +- primitives/tracing/Cargo.toml | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1a23117235e0..486cb083bca99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11383,11 +11383,12 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" dependencies = [ "lazy_static", + "valuable", ] [[package]] @@ -11764,6 +11765,12 @@ dependencies = [ "percent-encoding 2.1.0", ] +[[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.8" diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 9964fe2eea318..6d0ac398e473d 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -32,7 +32,7 @@ futures = { version = "0.3.21", features = ["thread-pool"], optional = true } parking_lot = { version = "0.12.0", optional = true } secp256k1 = { version = "0.21.2", features = ["recovery", "global-context"], optional = true } tracing = { version = "0.1.29", default-features = false } -tracing-core = { version = "0.1.17", default-features = false} +tracing-core = { version = "0.1.26", default-features = false} [features] default = ["std"] diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 3b51088ea3779..60962bb16caf5 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -21,4 +21,4 @@ sp-state-machine = { version = "0.12.0", path = "../../state-machine" } sp-runtime = { version = "6.0.0", path = "../../runtime" } sp-io = { version = "6.0.0", path = "../../io" } tracing = "0.1.29" -tracing-core = "0.1.17" +tracing-core = "0.1.26" diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index 3f53cc2e6c5c6..d305b756e2d68 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -23,7 +23,7 @@ codec = { version = "3.0.0", package = "parity-scale-codec", default-features = "derive", ] } tracing = { version = "0.1.29", default-features = false } -tracing-core = { version = "0.1.21", default-features = false } +tracing-core = { version = "0.1.26", default-features = false } tracing-subscriber = { version = "0.2.25", optional = true, features = [ "tracing-log", ] } From 662598908902ec8879fcd6a950324ef6735ea1f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 22 Apr 2022 16:58:53 +0200 Subject: [PATCH 0721/1472] BABE: Fix aux data cleaning (#11263) With the latest optimizations of the `FinalityNotification` generation, the aux data pruning started to print a warning. The problem here was that we printed a warning and stopped the adding of blocks to prune when we hit the `heigh_limit`. This is now wrong, as we could for example have two 512 long forks and then we start finalizing one of them. The second fork head would be part of the stale heads at some point (in the current implementation when we finalize second fork head number + 1), but then we would actually need to go back into the past than `heigh_limit` (which was actually last_finalized - 1). We now go back until we reach the canonical chain. Also fixed some wrong comment that was added by be about the content of the `finalized` blocks in the `FinalityNotification`. --- client/api/src/client.rs | 2 +- client/consensus/babe/src/lib.rs | 59 +++++++++++++++++++----------- client/consensus/babe/src/tests.rs | 9 +++++ 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 183ce610e7b7c..c4b01fbd0abbd 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -308,7 +308,7 @@ pub struct FinalityNotification { pub header: Block::Header, /// Path from the old finalized to new finalized parent (implicitly finalized blocks). /// - /// This maps to the range `(old_finalized, new_finalized]`. + /// This maps to the range `(old_finalized, new_finalized)`. pub tree_route: Arc<[Block::Hash]>, /// Stale branches heads. pub stale_heads: Arc<[Block::Hash]>, diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 3d3a7f24df816..be5c2809bd796 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -541,49 +541,66 @@ where // Remove obsolete block's weight data by leveraging finality notifications. // This includes data for all finalized blocks (excluding the most recent one) // and all stale branches. -fn aux_storage_cleanup, Block: BlockT>( +fn aux_storage_cleanup + HeaderBackend, Block: BlockT>( client: &C, notification: &FinalityNotification, ) -> AuxDataOperations { let mut aux_keys = HashSet::new(); - // Cleans data for finalized block's ancestors down to, and including, the previously - // finalized one. - - let first_new_finalized = notification.tree_route.get(0).unwrap_or(¬ification.hash); - match client.header_metadata(*first_new_finalized) { + let first = notification.tree_route.first().unwrap_or(¬ification.hash); + match client.header_metadata(*first) { Ok(meta) => { aux_keys.insert(aux_schema::block_weight_key(meta.parent)); }, - Err(err) => { - warn!(target: "babe", "header lookup fail while cleaning data for block {}: {}", first_new_finalized.to_string(), err.to_string()); - }, + Err(err) => warn!( + target: "babe", + "Failed to lookup metadata for block `{:?}`: {}", + first, + err, + ), } - aux_keys.extend(notification.tree_route.iter().map(aux_schema::block_weight_key)); + // Cleans data for finalized block's ancestors + aux_keys.extend( + notification + .tree_route + .iter() + // Ensure we don't prune latest finalized block. + // This should not happen, but better be safe than sorry! + .filter(|h| **h != notification.hash) + .map(aux_schema::block_weight_key), + ); // Cleans data for stale branches. - // A safenet in case of malformed notification. - let height_limit = notification.header.number().saturating_sub( - notification.tree_route.len().saturated_into::>() + One::one(), - ); for head in notification.stale_heads.iter() { let mut hash = *head; - // Insert stale blocks hashes until canonical chain is not reached. - // Soon or late we should hit an element already present within the `aux_keys` set. + // Insert stale blocks hashes until canonical chain is reached. + // If we reach a block that is already part of the `aux_keys` we can stop the processing the + // head. while aux_keys.insert(aux_schema::block_weight_key(hash)) { match client.header_metadata(hash) { Ok(meta) => { - // This should never happen and must be considered a bug. - if meta.number <= height_limit { - warn!(target: "babe", "unexpected canonical chain state or malformed finality notification"); + hash = meta.parent; + + // If the parent is part of the canonical chain or there doesn't exist a block + // hash for the parent number (bug?!), we can abort adding blocks. + if client + .hash(meta.number.saturating_sub(1u32.into())) + .ok() + .flatten() + .map_or(true, |h| h == hash) + { break } - hash = meta.parent; }, Err(err) => { - warn!(target: "babe", "header lookup fail while cleaning data for block {}: {}", head.to_string(), err.to_string()); + warn!( + target: "babe", + "Header lookup fail while cleaning data for block {:?}: {}", + hash, + err, + ); break }, } diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index aa2d824b8ccb9..db19deda06fd8 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -1043,4 +1043,13 @@ fn obsolete_blocks_aux_data_cleanup() { assert!(aux_data_check(&fork2_hashes, false)); // Present C4, C5 assert!(aux_data_check(&fork3_hashes, true)); + + client.finalize_block(BlockId::Number(4), None, true).unwrap(); + + // Wiped: A3 + assert!(aux_data_check(&fork1_hashes[2..3], false)); + // Present: A4 + assert!(aux_data_check(&fork1_hashes[3..], true)); + // Present C4, C5 + assert!(aux_data_check(&fork3_hashes, true)); } From 52cc538d8e51ca7af1bfa0138b76c1b358c70692 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Mon, 25 Apr 2022 07:16:38 +0300 Subject: [PATCH 0722/1472] More efficient identity and multiplier weight to fee (#11226) --- frame/support/src/weights.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index 4c3fcaa0fd423..5b4a13e7f9457 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -710,6 +710,10 @@ where degree: 1, }) } + + fn calc(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(*weight) + } } /// Implementor of [`WeightToFeePolynomial`] that uses a constant multiplier. @@ -738,6 +742,10 @@ where degree: 1, }) } + + fn calc(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(*weight).saturating_mul(M::get()) + } } /// A struct holding value for each `DispatchClass`. From 2d9b803899d7e1a1f5c764746e9aa1fd386a0c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 25 Apr 2022 17:07:09 +0200 Subject: [PATCH 0723/1472] cumulus-companion: Fix CI when there is no Polkadot companion (#11280) This tries to fix the CI if there is no polkadot companion. Currently we don't update Polkadot master in Cumulus, which means we may use some old commit that isn't compiling with the latest Substrate master anymore. This can happen if there was a pr that had a companion in Polkadot, but no companion was required for Cumulus. Then Cumulus will still point to some old Polkadot commit that isn't compiling anymore with the latest Substrate commit. So, we need to tell the script to use the latest master of Polkadot. If there is a companion for Polkadot, it would simply override the extra dependency patch later on. --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 62684ffebd987..1c3e81ca71f3d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -474,6 +474,7 @@ cargo-check-macos: "$DEPENDENT_REPO" "$GITHUB_PR_TOKEN" "$CARGO_UPDATE_CRATES" + "$EXTRA_DEPENDENCIES" # Individual jobs are set up for each dependent project so that they can be ran in parallel. # Arguably we could generate a job for each companion in the PR's description using Gitlab's @@ -490,6 +491,7 @@ check-dependent-cumulus: variables: DEPENDENT_REPO: cumulus CARGO_UPDATE_CRATES: "sp-io polkadot-runtime-common" + EXTRA_DEPENDENCIES: polkadot build-linux-substrate: From d79a2afd565d93bcc369aa7c80c0f4261e051929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 25 Apr 2022 20:12:06 +0200 Subject: [PATCH 0724/1472] pallet-asset: Fix transfer of a large amount of an asset (#11241) * pallet-asset: Fix transfer of a large amount of an asset Before this pr transferring a large amount of an asset would check that transferring the asset would not overflow the supply of the asset. However, it doesn't make sense to check for asset supply overflow when we just transfer from one account to another account and don't increase the supply in any way. It also required to extend the `can_deposit` method of `fungible` and `fungibles` with a `mint` parameter. If this parameter is set to `true`, it means we want to mint the amount of an asset before transferring it into an account. For `can_withdraw` we don't need to add an extra parameter, because withdrawing should never be able to underflow the supply. If that would happen, it would mean that somewhere the supply wasn't increased while increasing the balance of an account. * Update frame/assets/src/functions.rs * Update frame/assets/src/functions.rs * Update frame/assets/src/functions.rs Co-authored-by: Shawn Tabrizi * FMT Co-authored-by: Shawn Tabrizi --- frame/assets/src/functions.rs | 14 +++++++++++--- frame/assets/src/impl_fungibles.rs | 3 ++- frame/assets/src/tests.rs | 10 ++++++++++ frame/balances/src/lib.rs | 9 +++++---- frame/support/src/traits/tokens/fungible.rs | 14 ++++++++++---- frame/support/src/traits/tokens/fungibles.rs | 10 +++++++++- 6 files changed, 47 insertions(+), 13 deletions(-) diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index 0be79619e0967..a6abfd9e0409c 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -103,16 +103,24 @@ impl, I: 'static> Pallet { Remove } + /// Returns `true` when the balance of `account` can be increased by `amount`. + /// + /// - `id`: The id of the asset that should be increased. + /// - `who`: The account of which the balance should be increased. + /// - `amount`: The amount by which the balance should be increased. + /// - `increase_supply`: Will the supply of the asset be increased by `amount` at the same time + /// as crediting the `account`. pub(super) fn can_increase( id: T::AssetId, who: &T::AccountId, amount: T::Balance, + increase_supply: bool, ) -> DepositConsequence { let details = match Asset::::get(id) { Some(details) => details, None => return DepositConsequence::UnknownAsset, }; - if details.supply.checked_add(&amount).is_none() { + if increase_supply && details.supply.checked_add(&amount).is_none() { return DepositConsequence::Overflow } if let Some(balance) = Self::maybe_balance(id, who) { @@ -283,7 +291,7 @@ impl, I: 'static> Pallet { (true, Some(dust)) => (amount, Some(dust)), _ => (debit, None), }; - Self::can_increase(id, &dest, credit).into_result()?; + Self::can_increase(id, &dest, credit, false).into_result()?; Ok((credit, maybe_burn)) } @@ -379,7 +387,7 @@ impl, I: 'static> Pallet { return Ok(()) } - Self::can_increase(id, beneficiary, amount).into_result()?; + Self::can_increase(id, beneficiary, amount, true).into_result()?; Asset::::try_mutate(id, |maybe_details| -> DispatchResult { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 49caac83f4c4a..6b263bc0c7bef 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -47,8 +47,9 @@ impl, I: 'static> fungibles::Inspect<::AccountId asset: Self::AssetId, who: &::AccountId, amount: Self::Balance, + mint: bool, ) -> DepositConsequence { - Pallet::::can_increase(asset, who, amount) + Pallet::::can_increase(asset, who, amount, mint) } fn can_withdraw( diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index db0d6a5f212f9..50ab04111edff 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -967,3 +967,13 @@ fn querying_allowance_should_work() { assert_eq!(Assets::allowance(0, &1, &2), 0); }); } + +#[test] +fn transfer_large_asset() { + new_test_ext().execute_with(|| { + let amount = u64::pow(2, 63) + 2; + assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, amount)); + assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, amount - 1)); + }) +} diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 6bf37dfda037b..0eab933f7757d 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -810,12 +810,13 @@ impl, I: 'static> Pallet { _who: &T::AccountId, amount: T::Balance, account: &AccountData, + mint: bool, ) -> DepositConsequence { if amount.is_zero() { return DepositConsequence::Success } - if TotalIssuance::::get().checked_add(&amount).is_none() { + if mint && TotalIssuance::::get().checked_add(&amount).is_none() { return DepositConsequence::Overflow } @@ -1093,8 +1094,8 @@ impl, I: 'static> fungible::Inspect for Pallet liquid.saturating_sub(must_remain_to_exist) } } - fn can_deposit(who: &T::AccountId, amount: Self::Balance) -> DepositConsequence { - Self::deposit_consequence(who, amount, &Self::account(who)) + fn can_deposit(who: &T::AccountId, amount: Self::Balance, mint: bool) -> DepositConsequence { + Self::deposit_consequence(who, amount, &Self::account(who), mint) } fn can_withdraw( who: &T::AccountId, @@ -1110,7 +1111,7 @@ impl, I: 'static> fungible::Mutate for Pallet { return Ok(()) } Self::try_mutate_account(who, |account, _is_new| -> DispatchResult { - Self::deposit_consequence(who, amount, &account).into_result()?; + Self::deposit_consequence(who, amount, &account, true).into_result()?; account.free += amount; Ok(()) })?; diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs index 712103a1e8837..7422a9d651874 100644 --- a/frame/support/src/traits/tokens/fungible.rs +++ b/frame/support/src/traits/tokens/fungible.rs @@ -50,7 +50,11 @@ pub trait Inspect { fn reducible_balance(who: &AccountId, keep_alive: bool) -> Self::Balance; /// Returns `true` if the balance of `who` may be increased by `amount`. - fn can_deposit(who: &AccountId, amount: Self::Balance) -> DepositConsequence; + /// + /// - `who`: The account of which the balance should be increased by `amount`. + /// - `amount`: How much should the balance be increased? + /// - `mint`: Will `amount` be minted to deposit it into `account`? + fn can_deposit(who: &AccountId, amount: Self::Balance, mint: bool) -> DepositConsequence; /// Returns `Failed` if the balance of `who` may not be decreased by `amount`, otherwise /// the consequence. @@ -86,7 +90,9 @@ pub trait Mutate: Inspect { amount: Self::Balance, ) -> Result { let extra = Self::can_withdraw(&source, amount).into_result()?; - Self::can_deposit(&dest, amount.saturating_add(extra)).into_result()?; + // As we first burn and then mint, we don't need to check if `mint` fits into the supply. + // If we can withdraw/burn it, we can also mint it again. + Self::can_deposit(&dest, amount.saturating_add(extra), false).into_result()?; let actual = Self::burn_from(source, amount)?; debug_assert!( actual == amount.saturating_add(extra), @@ -216,8 +222,8 @@ impl< fn reducible_balance(who: &AccountId, keep_alive: bool) -> Self::Balance { >::reducible_balance(A::get(), who, keep_alive) } - fn can_deposit(who: &AccountId, amount: Self::Balance) -> DepositConsequence { - >::can_deposit(A::get(), who, amount) + fn can_deposit(who: &AccountId, amount: Self::Balance, mint: bool) -> DepositConsequence { + >::can_deposit(A::get(), who, amount, mint) } fn can_withdraw(who: &AccountId, amount: Self::Balance) -> WithdrawConsequence { >::can_withdraw(A::get(), who, amount) diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 8e68b36d60c7a..2abadf037687d 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -53,10 +53,16 @@ pub trait Inspect { fn reducible_balance(asset: Self::AssetId, who: &AccountId, keep_alive: bool) -> Self::Balance; /// Returns `true` if the `asset` balance of `who` may be increased by `amount`. + /// + /// - `asset`: The asset that should be deposited. + /// - `who`: The account of which the balance should be increased by `amount`. + /// - `amount`: How much should the balance be increased? + /// - `mint`: Will `amount` be minted to deposit it into `account`? fn can_deposit( asset: Self::AssetId, who: &AccountId, amount: Self::Balance, + mint: bool, ) -> DepositConsequence; /// Returns `Failed` if the `asset` balance of `who` may not be decreased by `amount`, otherwise @@ -137,7 +143,9 @@ pub trait Mutate: Inspect { amount: Self::Balance, ) -> Result { let extra = Self::can_withdraw(asset, &source, amount).into_result()?; - Self::can_deposit(asset, &dest, amount.saturating_add(extra)).into_result()?; + // As we first burn and then mint, we don't need to check if `mint` fits into the supply. + // If we can withdraw/burn it, we can also mint it again. + Self::can_deposit(asset, &dest, amount.saturating_add(extra), false).into_result()?; let actual = Self::burn_from(asset, source, amount)?; debug_assert!( actual == amount.saturating_add(extra), From 59a21506a26229a52ffcc2d11d878c49ceedb992 Mon Sep 17 00:00:00 2001 From: tgmichel Date: Mon, 25 Apr 2022 21:07:26 +0200 Subject: [PATCH 0725/1472] Add `chain-info` Subcommand (#11250) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add `blockchain-info` Subcommand * Update comment * Cleanup * Cleanup * Use `sync_run` * Use `sc_client_db` utility fns instead service backend * Use service `Backend` builder * Impl `From` * Rename to `chain-info` * fmt * Copyright year Co-authored-by: Bastian Köcher * Expose `DatabaseParams` Co-authored-by: Bastian Köcher --- Cargo.lock | 1 + bin/node-template/node/src/cli.rs | 3 + bin/node-template/node/src/command.rs | 4 + bin/node/cli/src/cli.rs | 3 + bin/node/cli/src/command.rs | 4 + client/cli/Cargo.toml | 1 + client/cli/src/commands/chain_info_cmd.rs | 103 ++++++++++++++++++++++ client/cli/src/commands/mod.rs | 3 +- 8 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 client/cli/src/commands/chain_info_cmd.rs diff --git a/Cargo.lock b/Cargo.lock index 486cb083bca99..48fe7cc122607 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8242,6 +8242,7 @@ dependencies = [ "regex", "rpassword", "sc-client-api", + "sc-client-db", "sc-keystore", "sc-network", "sc-service", diff --git a/bin/node-template/node/src/cli.rs b/bin/node-template/node/src/cli.rs index 710c7f3f9e145..4ab4d34210c98 100644 --- a/bin/node-template/node/src/cli.rs +++ b/bin/node-template/node/src/cli.rs @@ -47,4 +47,7 @@ pub enum Subcommand { /// Try some command against runtime state. Note: `try-runtime` feature must be enabled. #[cfg(not(feature = "try-runtime"))] TryRuntime, + + /// Db meta columns information. + ChainInfo(sc_cli::ChainInfoCmd), } diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index afa4612f1ee4a..809257f79007c 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -162,6 +162,10 @@ pub fn run() -> sc_cli::Result<()> { Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \ You can enable it with `--features try-runtime`." .into()), + Some(Subcommand::ChainInfo(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run::(&config)) + }, None => { let runner = cli.create_runner(&cli.run)?; runner.run_node_until_exit(|config| async move { diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 5b5db62199bbd..5b2977599bab0 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -94,4 +94,7 @@ pub enum Subcommand { /// Revert the chain to a previous state. Revert(sc_cli::RevertCmd), + + /// Db meta columns information. + ChainInfo(sc_cli::ChainInfoCmd), } diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index e2c772e809200..b98a38d2dbf5f 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -206,5 +206,9 @@ pub fn run() -> Result<()> { Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \ You can enable it with `--features try-runtime`." .into()), + Some(Subcommand::ChainInfo(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run::(&config)) + }, } } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 6a4d4b74f963e..adf88b8c88a2c 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -32,6 +32,7 @@ tokio = { version = "1.17.0", features = ["signal", "rt-multi-thread", "parking_ parity-scale-codec = "3.0.0" sc-client-api = { version = "4.0.0-dev", path = "../api" } +sc-client-db = { version = "0.10.0-dev", path = "../db" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../service" } diff --git a/client/cli/src/commands/chain_info_cmd.rs b/client/cli/src/commands/chain_info_cmd.rs new file mode 100644 index 0000000000000..0e57d1677efbb --- /dev/null +++ b/client/cli/src/commands/chain_info_cmd.rs @@ -0,0 +1,103 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{CliConfiguration, DatabaseParams, PruningParams, Result as CliResult, SharedParams}; +use parity_scale_codec::{Decode, Encode}; +use sc_client_api::{backend::Backend as BackendT, blockchain::HeaderBackend}; +use sp_blockchain::Info; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; +use std::{fmt::Debug, io}; + +/// The `chain-info` subcommand used to output db meta columns information. +#[derive(Debug, Clone, clap::Parser)] +pub struct ChainInfoCmd { + #[allow(missing_docs)] + #[clap(flatten)] + pub pruning_params: PruningParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub shared_params: SharedParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub database_params: DatabaseParams, +} + +/// Serializable `chain-info` subcommand output. +#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, serde::Serialize)] +struct ChainInfo { + /// Best block hash. + best_hash: B::Hash, + /// Best block number. + best_number: <::Header as HeaderT>::Number, + /// Genesis block hash. + genesis_hash: B::Hash, + /// The head of the finalized chain. + finalized_hash: B::Hash, + /// Last finalized block number. + finalized_number: <::Header as HeaderT>::Number, +} + +impl From> for ChainInfo { + fn from(info: Info) -> Self { + ChainInfo:: { + best_hash: info.best_hash, + best_number: info.best_number, + genesis_hash: info.genesis_hash, + finalized_hash: info.finalized_hash, + finalized_number: info.finalized_number, + } + } +} + +impl ChainInfoCmd { + /// Run the `chain-info` subcommand + pub fn run(&self, config: &sc_service::Configuration) -> CliResult<()> + where + B: BlockT, + { + let db_config = sc_client_db::DatabaseSettings { + state_cache_size: config.state_cache_size, + state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), + state_pruning: config.state_pruning.clone(), + source: config.database.clone(), + keep_blocks: config.keep_blocks.clone(), + }; + let backend = sc_service::new_db_backend::(db_config)?; + let info: ChainInfo = backend.blockchain().info().into(); + let mut out = io::stdout(); + serde_json::to_writer_pretty(&mut out, &info) + .map_err(|e| format!("Error writing JSON: {}", e))?; + Ok(()) + } +} + +impl CliConfiguration for ChainInfoCmd { + fn shared_params(&self) -> &SharedParams { + &self.shared_params + } + + fn pruning_params(&self) -> Option<&PruningParams> { + Some(&self.pruning_params) + } + + fn database_params(&self) -> Option<&DatabaseParams> { + Some(&self.database_params) + } +} diff --git a/client/cli/src/commands/mod.rs b/client/cli/src/commands/mod.rs index 2b46e1d99caa2..8e84afa34e24a 100644 --- a/client/cli/src/commands/mod.rs +++ b/client/cli/src/commands/mod.rs @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . mod build_spec_cmd; +mod chain_info_cmd; mod check_block_cmd; mod export_blocks_cmd; mod export_state_cmd; @@ -35,7 +36,7 @@ mod vanity; mod verify; pub use self::{ - build_spec_cmd::BuildSpecCmd, check_block_cmd::CheckBlockCmd, + build_spec_cmd::BuildSpecCmd, chain_info_cmd::ChainInfoCmd, check_block_cmd::CheckBlockCmd, export_blocks_cmd::ExportBlocksCmd, export_state_cmd::ExportStateCmd, generate::GenerateCmd, generate_node_key::GenerateNodeKeyCmd, import_blocks_cmd::ImportBlocksCmd, insert_key::InsertKeyCmd, inspect_key::InspectKeyCmd, inspect_node_key::InspectNodeKeyCmd, From 6f11d9281c06c6dd980e1c2ee2d7d680cb7682bb Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 26 Apr 2022 17:05:51 +0900 Subject: [PATCH 0726/1472] Turn on logger's interest cache (#11264) --- Cargo.lock | 6 ++++-- client/tracing/Cargo.toml | 2 +- client/tracing/src/logging/mod.rs | 5 ++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48fe7cc122607..58cb4ed0e99ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11404,12 +11404,14 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ + "ahash", "lazy_static", "log 0.4.16", + "lru 0.7.5", "tracing-core", ] diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 121d55ca930b8..4178e26fe7bf6 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -26,7 +26,7 @@ rustc-hash = "1.1.0" serde = "1.0.136" thiserror = "1.0.30" tracing = "0.1.29" -tracing-log = "0.1.2" +tracing-log = { version = "0.1.3", features = ["interest-cache"] } tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index c325a3f73c413..f5cdda4d35442 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -155,7 +155,10 @@ where let max_level_hint = Layer::::max_level_hint(&env_filter); let max_level = to_log_level_filter(max_level_hint); - tracing_log::LogTracer::builder().with_max_level(max_level).init()?; + tracing_log::LogTracer::builder() + .with_max_level(max_level) + .with_interest_cache(tracing_log::InterestCacheConfig::default()) + .init()?; // If we're only logging `INFO` entries then we'll use a simplified logging format. let detailed_output = match max_level_hint { From 62b856c5cd654d6c3927be1fe7f8078099ead8a5 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Tue, 26 Apr 2022 17:25:41 +0800 Subject: [PATCH 0727/1472] sp-sandbox: move the sandbox module of `sp-core` into `sp-sandbox` (#11027) * sp-sandbox: move the sandbox module of sp-core into sp-sandbox Signed-off-by: koushiro * Fix Signed-off-by: koushiro * Fix Signed-off-by: koushiro --- Cargo.lock | 6 +-- client/executor/Cargo.toml | 29 ++++++------ client/executor/common/Cargo.toml | 13 +++--- client/executor/common/src/sandbox.rs | 24 +++++----- .../common/src/sandbox/wasmer_backend.rs | 23 +++++----- .../common/src/sandbox/wasmi_backend.rs | 6 +-- client/executor/runtime-test/Cargo.toml | 7 +-- client/executor/wasmi/Cargo.toml | 9 ++-- client/executor/wasmi/src/lib.rs | 44 ++++++++++--------- client/executor/wasmtime/Cargo.toml | 21 ++++----- client/executor/wasmtime/src/host.rs | 34 +++++++------- primitives/core/src/lib.rs | 1 - primitives/sandbox/Cargo.toml | 15 ++++--- primitives/sandbox/src/embedded_executor.rs | 34 +++++++++----- .../src/sandbox.rs => sandbox/src/env.rs} | 10 +++-- primitives/sandbox/src/host_executor.rs | 44 +++++++++---------- primitives/sandbox/src/lib.rs | 25 ++++++----- 17 files changed, 183 insertions(+), 162 deletions(-) mode change 100755 => 100644 primitives/sandbox/src/embedded_executor.rs rename primitives/{core/src/sandbox.rs => sandbox/src/env.rs} (92%) mode change 100755 => 100644 primitives/sandbox/src/host_executor.rs mode change 100755 => 100644 primitives/sandbox/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 58cb4ed0e99ad..d58c66096848c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8618,8 +8618,8 @@ dependencies = [ "environmental", "parity-scale-codec", "sc-allocator", - "sp-core", "sp-maybe-compressed-blob", + "sp-sandbox", "sp-serializer", "sp-wasm-interface", "thiserror", @@ -8637,8 +8637,8 @@ dependencies = [ "sc-allocator", "sc-executor-common", "scoped-tls", - "sp-core", "sp-runtime-interface", + "sp-sandbox", "sp-wasm-interface", "wasmi", ] @@ -8655,9 +8655,9 @@ dependencies = [ "sc-allocator", "sc-executor-common", "sc-runtime-test", - "sp-core", "sp-io", "sp-runtime-interface", + "sp-sandbox", "sp-wasm-interface", "wasmtime", "wat", diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 8e10de1b04a95..ad2288b9272d3 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -14,26 +14,27 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +lazy_static = "1.4.0" +lru = "0.7.5" +parking_lot = "0.12.0" +tracing = "0.1.29" +wasmi = "0.9.1" + codec = { package = "parity-scale-codec", version = "3.0.0" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sc-executor-common = { version = "0.10.0-dev", path = "common" } +sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } +sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } +sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } +sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } +sp-runtime-interface = { version = "6.0.0", path = "../../primitives/runtime-interface" } sp-tasks = { version = "4.0.0-dev", path = "../../primitives/tasks" } sp-trie = { version = "6.0.0", path = "../../primitives/trie" } sp-version = { version = "5.0.0", path = "../../primitives/version" } -sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } -wasmi = "0.9.1" -lazy_static = "1.4.0" -sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } -sp-runtime-interface = { version = "6.0.0", path = "../../primitives/runtime-interface" } -sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } -sc-executor-common = { version = "0.10.0-dev", path = "common" } -sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } -sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } -parking_lot = "0.12.0" -sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } -lru = "0.7.5" -tracing = "0.1.29" [dev-dependencies] wat = "1.0" diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 149d9fdc236cd..677148f709e6b 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -14,17 +14,18 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +environmental = "1.1.3" +thiserror = "1.0.30" wasm-instrument = "0.1" -codec = { package = "parity-scale-codec", version = "3.0.0" } wasmi = "0.9.1" -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +wasmer = { version = "2.2", features = ["singlepass"], optional = true } + +codec = { package = "parity-scale-codec", version = "3.0.0" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } +sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-serializer = { version = "4.0.0-dev", path = "../../../primitives/serializer" } -thiserror = "1.0.30" -environmental = "1.1.3" -wasmer = { version = "2.2", optional = true, features = ["singlepass"] } +sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface" } [features] default = [] diff --git a/client/executor/common/src/sandbox.rs b/client/executor/common/src/sandbox.rs index 98eafaf32b8f9..fe14c0865cfde 100644 --- a/client/executor/common/src/sandbox.rs +++ b/client/executor/common/src/sandbox.rs @@ -22,26 +22,26 @@ #[cfg(feature = "wasmer-sandbox")] mod wasmer_backend; - mod wasmi_backend; +use std::{collections::HashMap, rc::Rc}; + +use codec::Decode; +use sp_sandbox::env as sandbox_env; +use sp_wasm_interface::{FunctionContext, Pointer, WordSize}; + use crate::{ error::{self, Result}, util, }; -use codec::Decode; -use sp_core::sandbox as sandbox_primitives; -use sp_wasm_interface::{FunctionContext, Pointer, WordSize}; -use std::{collections::HashMap, rc::Rc}; #[cfg(feature = "wasmer-sandbox")] -use wasmer_backend::{ +use self::wasmer_backend::{ get_global as wasmer_get_global, instantiate as wasmer_instantiate, invoke as wasmer_invoke, new_memory as wasmer_new_memory, Backend as WasmerBackend, MemoryWrapper as WasmerMemoryWrapper, }; - -use wasmi_backend::{ +use self::wasmi_backend::{ get_global as wasmi_get_global, instantiate as wasmi_instantiate, invoke as wasmi_invoke, new_memory as wasmi_new_memory, MemoryWrapper as WasmiMemoryWrapper, }; @@ -243,7 +243,7 @@ fn decode_environment_definition( mut raw_env_def: &[u8], memories: &[Option], ) -> std::result::Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> { - let env_def = sandbox_primitives::EnvironmentDefinition::decode(&mut raw_env_def) + let env_def = sandbox_env::EnvironmentDefinition::decode(&mut raw_env_def) .map_err(|_| InstantiationError::EnvironmentDefinitionCorrupted)?; let mut func_map = HashMap::new(); @@ -255,12 +255,12 @@ fn decode_environment_definition( let field = entry.field_name.clone(); match entry.entity { - sandbox_primitives::ExternEntity::Function(func_idx) => { + sandbox_env::ExternEntity::Function(func_idx) => { let externals_idx = guest_to_supervisor_mapping.define(SupervisorFuncIndex(func_idx as usize)); func_map.insert((module, field), externals_idx); }, - sandbox_primitives::ExternEntity::Memory(memory_idx) => { + sandbox_env::ExternEntity::Memory(memory_idx) => { let memory_ref = memories .get(memory_idx as usize) .cloned() @@ -446,7 +446,7 @@ impl Store

{ let backend_context = &self.backend_context; let maximum = match maximum { - sandbox_primitives::MEM_UNLIMITED => None, + sandbox_env::MEM_UNLIMITED => None, specified_limit => Some(specified_limit), }; diff --git a/client/executor/common/src/sandbox/wasmer_backend.rs b/client/executor/common/src/sandbox/wasmer_backend.rs index fd2f317457f88..ab585c7d15431 100644 --- a/client/executor/common/src/sandbox/wasmer_backend.rs +++ b/client/executor/common/src/sandbox/wasmer_backend.rs @@ -18,20 +18,21 @@ //! Wasmer specific impls for sandbox -use crate::{ - error::{Error, Result}, - sandbox::Memory, - util::{checked_range, MemoryTransfer}, -}; -use codec::{Decode, Encode}; -use sp_core::sandbox::HostError; -use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; use std::{cell::RefCell, collections::HashMap, rc::Rc}; + use wasmer::RuntimeError; -use crate::sandbox::{ - BackendInstance, GuestEnvironment, InstantiationError, SandboxContext, SandboxInstance, - SupervisorFuncIndex, +use codec::{Decode, Encode}; +use sp_sandbox::HostError; +use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; + +use crate::{ + error::{Error, Result}, + sandbox::{ + BackendInstance, GuestEnvironment, InstantiationError, Memory, SandboxContext, + SandboxInstance, SupervisorFuncIndex, + }, + util::{checked_range, MemoryTransfer}, }; environmental::environmental!(SandboxContextStore: trait SandboxContext); diff --git a/client/executor/common/src/sandbox/wasmi_backend.rs b/client/executor/common/src/sandbox/wasmi_backend.rs index 0954287f52f6b..9c7c154b5b135 100644 --- a/client/executor/common/src/sandbox/wasmi_backend.rs +++ b/client/executor/common/src/sandbox/wasmi_backend.rs @@ -18,11 +18,11 @@ //! Wasmi specific impls for sandbox -use codec::{Decode, Encode}; -use sp_core::sandbox::HostError; -use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; use std::rc::Rc; +use codec::{Decode, Encode}; +use sp_sandbox::HostError; +use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; use wasmi::{ memory_units::Pages, ImportResolver, MemoryInstance, Module, ModuleInstance, RuntimeArgs, RuntimeValue, Trap, TrapKind, diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index 352ffdf7a65c2..507b35114d630 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -13,24 +13,25 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +paste = "1.0.6" + sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io", features = ["improved_panic_error_reporting"] } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } -paste = "1.0.6" [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } [features] -default = [ "std" ] +default = ["std"] std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-sandbox/std", "sp-std/std", - "sp-tasks/std", + "sp-tasks/std", ] diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 99b8010c07502..ed653dca0aaab 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -15,11 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.16" +scoped-tls = "1.0" wasmi = "0.9.1" + codec = { package = "parity-scale-codec", version = "3.0.0" } -sc-executor-common = { version = "0.10.0-dev", path = "../common" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface" } +sc-executor-common = { version = "0.10.0-dev", path = "../common" } +sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -scoped-tls = "1.0" +sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface" } diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index 97c73c3454a4b..ec98dc0df3954 100644 --- a/client/executor/wasmi/src/lib.rs +++ b/client/executor/wasmi/src/lib.rs @@ -18,8 +18,17 @@ //! This crate provides an implementation of `WasmModule` that is baked by wasmi. -use codec::{Decode, Encode}; +use std::{cell::RefCell, rc::Rc, str, sync::Arc}; + use log::{debug, error, trace}; +use wasmi::{ + memory_units::Pages, + FuncInstance, ImportsBuilder, MemoryInstance, MemoryRef, Module, ModuleInstance, ModuleRef, + RuntimeValue::{self, I32, I64}, + TableRef, +}; + +use codec::{Decode, Encode}; use sc_executor_common::{ error::{Error, MessageWithBacktrace, WasmError}, runtime_blob::{DataSegmentsSnapshot, RuntimeBlob}, @@ -27,18 +36,11 @@ use sc_executor_common::{ util::MemoryTransfer, wasm_runtime::{InvokeMethod, WasmInstance, WasmModule}, }; -use sp_core::sandbox as sandbox_primitives; use sp_runtime_interface::unpack_ptr_and_len; +use sp_sandbox::env as sandbox_env; use sp_wasm_interface::{ Function, FunctionContext, MemoryId, Pointer, Result as WResult, Sandbox, WordSize, }; -use std::{cell::RefCell, rc::Rc, str, sync::Arc}; -use wasmi::{ - memory_units::Pages, - FuncInstance, ImportsBuilder, MemoryInstance, MemoryRef, Module, ModuleInstance, ModuleRef, - RuntimeValue::{self, I32, I64}, - TableRef, -}; struct FunctionExecutor { sandbox_store: Rc>>, @@ -155,15 +157,15 @@ impl Sandbox for FunctionExecutor { let len = buf_len as usize; let buffer = match sandboxed_memory.read(Pointer::new(offset as u32), len) { - Err(_) => return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), + Err(_) => return Ok(sandbox_env::ERR_OUT_OF_BOUNDS), Ok(buffer) => buffer, }; if let Err(_) = self.memory.set(buf_ptr.into(), &buffer) { - return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS) + return Ok(sandbox_env::ERR_OUT_OF_BOUNDS) } - Ok(sandbox_primitives::ERR_OK) + Ok(sandbox_env::ERR_OK) } fn memory_set( @@ -179,15 +181,15 @@ impl Sandbox for FunctionExecutor { let len = val_len as usize; let buffer = match self.memory.get(val_ptr.into(), len) { - Err(_) => return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), + Err(_) => return Ok(sandbox_env::ERR_OUT_OF_BOUNDS), Ok(buffer) => buffer, }; if let Err(_) = sandboxed_memory.write_from(Pointer::new(offset as u32), &buffer) { - return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS) + return Ok(sandbox_env::ERR_OUT_OF_BOUNDS) } - Ok(sandbox_primitives::ERR_OK) + Ok(sandbox_env::ERR_OK) } fn memory_teardown(&mut self, memory_id: MemoryId) -> WResult<()> { @@ -236,7 +238,7 @@ impl Sandbox for FunctionExecutor { state, &mut SandboxContext { dispatch_thunk, executor: self }, ) { - Ok(None) => Ok(sandbox_primitives::ERR_OK), + Ok(None) => Ok(sandbox_env::ERR_OK), Ok(Some(val)) => { // Serialize return value and write it back into the memory. sp_wasm_interface::ReturnValue::Value(val.into()).using_encoded(|val| { @@ -244,10 +246,10 @@ impl Sandbox for FunctionExecutor { Err("Return value buffer is too small")?; } self.write_memory(return_val, val).map_err(|_| "Return value buffer is OOB")?; - Ok(sandbox_primitives::ERR_OK) + Ok(sandbox_env::ERR_OK) }) }, - Err(_) => Ok(sandbox_primitives::ERR_EXECUTION), + Err(_) => Ok(sandbox_env::ERR_EXECUTION), } } @@ -280,7 +282,7 @@ impl Sandbox for FunctionExecutor { let guest_env = match sandbox::GuestEnvironment::decode(&*self.sandbox_store.borrow(), raw_env_def) { Ok(guest_env) => guest_env, - Err(_) => return Ok(sandbox_primitives::ERR_MODULE as u32), + Err(_) => return Ok(sandbox_env::ERR_MODULE as u32), }; let store = self.sandbox_store.clone(); @@ -294,8 +296,8 @@ impl Sandbox for FunctionExecutor { let instance_idx_or_err_code = match result.map(|i| i.register(&mut store.borrow_mut(), dispatch_thunk)) { Ok(instance_idx) => instance_idx, - Err(sandbox::InstantiationError::StartTrapped) => sandbox_primitives::ERR_EXECUTION, - Err(_) => sandbox_primitives::ERR_MODULE, + Err(sandbox::InstantiationError::StartTrapped) => sandbox_env::ERR_EXECUTION, + Err(_) => sandbox_env::ERR_MODULE, }; Ok(instance_idx_or_err_code) diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 15f3a40cd46b1..5871629f47c0a 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -13,22 +13,23 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -libc = "0.2.121" cfg-if = "1.0" +libc = "0.2.121" log = "0.4.16" parity-wasm = "0.42.0" +wasmtime = { version = "0.35.3", default-features = false, features = [ + "cache", + "cranelift", + "jitdump", + "parallel-compilation", +] } + codec = { package = "parity-scale-codec", version = "3.0.0" } +sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } -sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface", features = ["wasmtime"] } sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } -wasmtime = { version = "0.35.3", default-features = false, features = [ - "cache", - "cranelift", - "jitdump", - "parallel-compilation", -] } +sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } +sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface", features = ["wasmtime"] } [dev-dependencies] sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index 23deacbf93623..376eba86829a7 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -19,18 +19,20 @@ //! This module defines `HostState` and `HostContext` structs which provide logic and state //! required for execution of host. -use crate::{runtime::StoreData, util}; -use codec::{Decode, Encode}; use log::trace; +use wasmtime::{Caller, Func, Val}; + +use codec::{Decode, Encode}; use sc_allocator::FreeingBumpHeapAllocator; use sc_executor_common::{ error::Result, sandbox::{self, SupervisorFuncIndex}, util::MemoryTransfer, }; -use sp_core::sandbox as sandbox_primitives; +use sp_sandbox::env as sandbox_env; use sp_wasm_interface::{FunctionContext, MemoryId, Pointer, Sandbox, WordSize}; -use wasmtime::{Caller, Func, Val}; + +use crate::{runtime::StoreData, util}; // The sandbox store is inside of a Option>> so that we can temporarily borrow it. struct SandboxStore(Option>>); @@ -164,15 +166,15 @@ impl<'a> Sandbox for HostContext<'a> { let len = buf_len as usize; let buffer = match sandboxed_memory.read(Pointer::new(offset as u32), len) { - Err(_) => return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), + Err(_) => return Ok(sandbox_env::ERR_OUT_OF_BOUNDS), Ok(buffer) => buffer, }; if util::write_memory_from(&mut self.caller, buf_ptr, &buffer).is_err() { - return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS) + return Ok(sandbox_env::ERR_OUT_OF_BOUNDS) } - Ok(sandbox_primitives::ERR_OK) + Ok(sandbox_env::ERR_OK) } fn memory_set( @@ -187,15 +189,15 @@ impl<'a> Sandbox for HostContext<'a> { let len = val_len as usize; let buffer = match util::read_memory(&self.caller, val_ptr, len) { - Err(_) => return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), + Err(_) => return Ok(sandbox_env::ERR_OUT_OF_BOUNDS), Ok(buffer) => buffer, }; if sandboxed_memory.write_from(Pointer::new(offset as u32), &buffer).is_err() { - return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS) + return Ok(sandbox_env::ERR_OUT_OF_BOUNDS) } - Ok(sandbox_primitives::ERR_OK) + Ok(sandbox_env::ERR_OK) } fn memory_teardown(&mut self, memory_id: MemoryId) -> sp_wasm_interface::Result<()> { @@ -236,7 +238,7 @@ impl<'a> Sandbox for HostContext<'a> { ); match result { - Ok(None) => Ok(sandbox_primitives::ERR_OK), + Ok(None) => Ok(sandbox_env::ERR_OK), Ok(Some(val)) => { // Serialize return value and write it back into the memory. sp_wasm_interface::ReturnValue::Value(val.into()).using_encoded(|val| { @@ -245,10 +247,10 @@ impl<'a> Sandbox for HostContext<'a> { } ::write_memory(self, return_val, val) .map_err(|_| "can't write return value")?; - Ok(sandbox_primitives::ERR_OK) + Ok(sandbox_env::ERR_OK) }) }, - Err(_) => Ok(sandbox_primitives::ERR_EXECUTION), + Err(_) => Ok(sandbox_env::ERR_EXECUTION), } } @@ -285,7 +287,7 @@ impl<'a> Sandbox for HostContext<'a> { let guest_env = match sandbox::GuestEnvironment::decode(&self.sandbox_store(), raw_env_def) { Ok(guest_env) => guest_env, - Err(_) => return Ok(sandbox_primitives::ERR_MODULE as u32), + Err(_) => return Ok(sandbox_env::ERR_MODULE as u32), }; let mut store = self @@ -315,8 +317,8 @@ impl<'a> Sandbox for HostContext<'a> { let instance_idx_or_err_code = match result { Ok(instance) => instance.register(&mut self.sandbox_store_mut(), dispatch_thunk), - Err(sandbox::InstantiationError::StartTrapped) => sandbox_primitives::ERR_EXECUTION, - Err(_) => sandbox_primitives::ERR_MODULE, + Err(sandbox::InstantiationError::StartTrapped) => sandbox_env::ERR_EXECUTION, + Err(_) => sandbox_env::ERR_MODULE, }; Ok(instance_idx_or_err_code as u32) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index b7c8b69e8a0ab..0709b615cf0d4 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -62,7 +62,6 @@ pub mod hash; #[cfg(feature = "std")] mod hasher; pub mod offchain; -pub mod sandbox; pub mod sr25519; pub mod testing; #[cfg(feature = "std")] diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index 22d295f313703..db9301a53029b 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -19,28 +19,29 @@ wasmi = { version = "0.9.1", default-features = false, features = ["core"] } wasmi = "0.9.0" [dependencies] +log = { version = "0.4", default-features = false } wasmi = { version = "0.9.0", optional = true } + +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-wasm-interface = { version = "6.0.0", default-features = false, path = "../wasm-interface" } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4", default-features = false } [dev-dependencies] -wat = "1.0" assert_matches = "1.3.0" +wat = "1.0" [features] default = ["std"] std = [ + "log/std", "wasmi", - "sp-core/std", - "sp-std/std", "codec/std", + "sp-core/std", "sp-io/std", + "sp-std/std", "sp-wasm-interface/std", - "log/std", ] strict = [] wasmer-sandbox = [] diff --git a/primitives/sandbox/src/embedded_executor.rs b/primitives/sandbox/src/embedded_executor.rs old mode 100755 new mode 100644 index 43967a0a38987..8a20cc1b39b54 --- a/primitives/sandbox/src/embedded_executor.rs +++ b/primitives/sandbox/src/embedded_executor.rs @@ -17,18 +17,20 @@ //! An embedded WASM executor utilizing `wasmi`. -use super::{Error, HostError, HostFuncType, ReturnValue, Value, TARGET}; use alloc::string::String; -use log::debug; -use sp_std::{ - borrow::ToOwned, collections::btree_map::BTreeMap, fmt, marker::PhantomData, prelude::*, -}; + use wasmi::{ memory_units::Pages, Externals, FuncInstance, FuncRef, GlobalDescriptor, GlobalRef, ImportResolver, MemoryDescriptor, MemoryInstance, MemoryRef, Module, ModuleInstance, ModuleRef, RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableRef, Trap, TrapKind, }; +use sp_std::{ + borrow::ToOwned, collections::btree_map::BTreeMap, fmt, marker::PhantomData, prelude::*, +}; + +use crate::{Error, HostError, HostFuncType, ReturnValue, Value, TARGET}; + /// The linear memory used by the sandbox. #[derive(Clone)] pub struct Memory { @@ -162,13 +164,18 @@ impl ImportResolver for EnvironmentDefinitionBuilder { ) -> Result { let key = (module_name.as_bytes().to_owned(), field_name.as_bytes().to_owned()); let externval = self.map.get(&key).ok_or_else(|| { - debug!(target: TARGET, "Export {}:{} not found", module_name, field_name); + log::debug!(target: TARGET, "Export {}:{} not found", module_name, field_name); wasmi::Error::Instantiation(String::new()) })?; let host_func_idx = match *externval { ExternVal::HostFunc(ref idx) => idx, _ => { - debug!(target: TARGET, "Export {}:{} is not a host func", module_name, field_name); + log::debug!( + target: TARGET, + "Export {}:{} is not a host func", + module_name, + field_name, + ); return Err(wasmi::Error::Instantiation(String::new())) }, }; @@ -181,7 +188,7 @@ impl ImportResolver for EnvironmentDefinitionBuilder { _field_name: &str, _global_type: &GlobalDescriptor, ) -> Result { - debug!(target: TARGET, "Importing globals is not supported yet"); + log::debug!(target: TARGET, "Importing globals is not supported yet"); Err(wasmi::Error::Instantiation(String::new())) } @@ -193,13 +200,18 @@ impl ImportResolver for EnvironmentDefinitionBuilder { ) -> Result { let key = (module_name.as_bytes().to_owned(), field_name.as_bytes().to_owned()); let externval = self.map.get(&key).ok_or_else(|| { - debug!(target: TARGET, "Export {}:{} not found", module_name, field_name); + log::debug!(target: TARGET, "Export {}:{} not found", module_name, field_name); wasmi::Error::Instantiation(String::new()) })?; let memory = match *externval { ExternVal::Memory(ref m) => m, _ => { - debug!(target: TARGET, "Export {}:{} is not a memory", module_name, field_name); + log::debug!( + target: TARGET, + "Export {}:{} is not a memory", + module_name, + field_name, + ); return Err(wasmi::Error::Instantiation(String::new())) }, }; @@ -212,7 +224,7 @@ impl ImportResolver for EnvironmentDefinitionBuilder { _field_name: &str, _table_type: &TableDescriptor, ) -> Result { - debug!("Importing tables is not supported yet"); + log::debug!("Importing tables is not supported yet"); Err(wasmi::Error::Instantiation(String::new())) } } diff --git a/primitives/core/src/sandbox.rs b/primitives/sandbox/src/env.rs similarity index 92% rename from primitives/core/src/sandbox.rs rename to primitives/sandbox/src/env.rs index 1f408a3b8cc05..94b1c5e467a9c 100644 --- a/primitives/core/src/sandbox.rs +++ b/primitives/sandbox/src/env.rs @@ -18,14 +18,16 @@ //! Definition of a sandbox environment. use codec::{Decode, Encode}; + +use sp_core::RuntimeDebug; use sp_std::vec::Vec; /// Error error that can be returned from host function. -#[derive(Encode, Decode, crate::RuntimeDebug)] +#[derive(Encode, Decode, RuntimeDebug)] pub struct HostError; /// Describes an entity to define or import into the environment. -#[derive(Clone, PartialEq, Eq, Encode, Decode, crate::RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] pub enum ExternEntity { /// Function that is specified by an index in a default table of /// a module that creates the sandbox. @@ -42,7 +44,7 @@ pub enum ExternEntity { /// /// Each entry has a two-level name and description of an entity /// being defined. -#[derive(Clone, PartialEq, Eq, Encode, Decode, crate::RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] pub struct Entry { /// Module name of which corresponding entity being defined. pub module_name: Vec, @@ -53,7 +55,7 @@ pub struct Entry { } /// Definition of runtime that could be used by sandboxed code. -#[derive(Clone, PartialEq, Eq, Encode, Decode, crate::RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] pub struct EnvironmentDefinition { /// Vector of all entries in the environment definition. pub entries: Vec, diff --git a/primitives/sandbox/src/host_executor.rs b/primitives/sandbox/src/host_executor.rs old mode 100755 new mode 100644 index 83721f40e3d93..e62c051262ca8 --- a/primitives/sandbox/src/host_executor.rs +++ b/primitives/sandbox/src/host_executor.rs @@ -17,12 +17,13 @@ //! A WASM executor utilizing the sandbox runtime interface of the host. -use super::{Error, HostFuncType, ReturnValue, Value}; use codec::{Decode, Encode}; -use sp_core::sandbox as sandbox_primitives; + use sp_io::sandbox; use sp_std::{marker, mem, prelude::*, rc::Rc, slice, vec}; +use crate::{env, Error, HostFuncType, ReturnValue, Value}; + mod ffi { use super::HostFuncType; use sp_std::mem; @@ -68,11 +69,10 @@ pub struct Memory { impl super::SandboxMemory for Memory { fn new(initial: u32, maximum: Option) -> Result { - let maximum = - if let Some(maximum) = maximum { maximum } else { sandbox_primitives::MEM_UNLIMITED }; + let maximum = if let Some(maximum) = maximum { maximum } else { env::MEM_UNLIMITED }; match sandbox::memory_new(initial, maximum) { - sandbox_primitives::ERR_MODULE => Err(Error::Module), + env::ERR_MODULE => Err(Error::Module), memory_idx => Ok(Memory { handle: Rc::new(MemoryHandle { memory_idx }) }), } } @@ -81,8 +81,8 @@ impl super::SandboxMemory for Memory { let result = sandbox::memory_get(self.handle.memory_idx, offset, buf.as_mut_ptr(), buf.len() as u32); match result { - sandbox_primitives::ERR_OK => Ok(()), - sandbox_primitives::ERR_OUT_OF_BOUNDS => Err(Error::OutOfBounds), + env::ERR_OK => Ok(()), + env::ERR_OUT_OF_BOUNDS => Err(Error::OutOfBounds), _ => unreachable!(), } } @@ -95,8 +95,8 @@ impl super::SandboxMemory for Memory { val.len() as u32, ); match result { - sandbox_primitives::ERR_OK => Ok(()), - sandbox_primitives::ERR_OUT_OF_BOUNDS => Err(Error::OutOfBounds), + env::ERR_OK => Ok(()), + env::ERR_OUT_OF_BOUNDS => Err(Error::OutOfBounds), _ => unreachable!(), } } @@ -104,22 +104,18 @@ impl super::SandboxMemory for Memory { /// A builder for the environment of the sandboxed WASM module. pub struct EnvironmentDefinitionBuilder { - env_def: sandbox_primitives::EnvironmentDefinition, + env_def: env::EnvironmentDefinition, retained_memories: Vec, _marker: marker::PhantomData, } impl EnvironmentDefinitionBuilder { - fn add_entry( - &mut self, - module: N1, - field: N2, - extern_entity: sandbox_primitives::ExternEntity, - ) where + fn add_entry(&mut self, module: N1, field: N2, extern_entity: env::ExternEntity) + where N1: Into>, N2: Into>, { - let entry = sandbox_primitives::Entry { + let entry = env::Entry { module_name: module.into(), field_name: field.into(), entity: extern_entity, @@ -131,7 +127,7 @@ impl EnvironmentDefinitionBuilder { impl super::SandboxEnvironmentBuilder for EnvironmentDefinitionBuilder { fn new() -> EnvironmentDefinitionBuilder { EnvironmentDefinitionBuilder { - env_def: sandbox_primitives::EnvironmentDefinition { entries: Vec::new() }, + env_def: env::EnvironmentDefinition { entries: Vec::new() }, retained_memories: Vec::new(), _marker: marker::PhantomData::, } @@ -142,7 +138,7 @@ impl super::SandboxEnvironmentBuilder for EnvironmentDefinitionBui N1: Into>, N2: Into>, { - let f = sandbox_primitives::ExternEntity::Function(f as u32); + let f = env::ExternEntity::Function(f as u32); self.add_entry(module, field, f); } @@ -154,7 +150,7 @@ impl super::SandboxEnvironmentBuilder for EnvironmentDefinitionBui // We need to retain memory to keep it alive while the EnvironmentDefinitionBuilder alive. self.retained_memories.push(mem.clone()); - let mem = sandbox_primitives::ExternEntity::Memory(mem.handle.memory_idx as u32); + let mem = env::ExternEntity::Memory(mem.handle.memory_idx as u32); self.add_entry(module, field, mem); } } @@ -228,8 +224,8 @@ impl super::SandboxInstance for Instance { ); let instance_idx = match result { - sandbox_primitives::ERR_MODULE => return Err(Error::Module), - sandbox_primitives::ERR_EXECUTION => return Err(Error::Execution), + env::ERR_MODULE => return Err(Error::Module), + env::ERR_EXECUTION => return Err(Error::Execution), instance_idx => instance_idx, }; @@ -256,12 +252,12 @@ impl super::SandboxInstance for Instance { ); match result { - sandbox_primitives::ERR_OK => { + env::ERR_OK => { let return_val = ReturnValue::decode(&mut &return_val[..]).map_err(|_| Error::Execution)?; Ok(return_val) }, - sandbox_primitives::ERR_EXECUTION => Err(Error::Execution), + env::ERR_EXECUTION => Err(Error::Execution), _ => unreachable!(), } } diff --git a/primitives/sandbox/src/lib.rs b/primitives/sandbox/src/lib.rs old mode 100755 new mode 100644 index 537c7cbb31b6d..b6b4a5a97da8c --- a/primitives/sandbox/src/lib.rs +++ b/primitives/sandbox/src/lib.rs @@ -40,26 +40,27 @@ extern crate alloc; -use sp_std::prelude::*; - -pub use sp_core::sandbox::HostError; -pub use sp_wasm_interface::{ReturnValue, Value}; - -/// The target used for logging. -const TARGET: &str = "runtime::sandbox"; - pub mod embedded_executor; +pub mod env; #[cfg(not(feature = "std"))] pub mod host_executor; -#[cfg(all(feature = "wasmer-sandbox", not(feature = "std")))] -pub use host_executor as default_executor; +use sp_core::RuntimeDebug; +use sp_std::prelude::*; + +pub use sp_wasm_interface::{ReturnValue, Value}; #[cfg(not(all(feature = "wasmer-sandbox", not(feature = "std"))))] -pub use embedded_executor as default_executor; +pub use self::embedded_executor as default_executor; +pub use self::env::HostError; +#[cfg(all(feature = "wasmer-sandbox", not(feature = "std")))] +pub use self::host_executor as default_executor; + +/// The target used for logging. +const TARGET: &str = "runtime::sandbox"; /// Error that can occur while using this crate. -#[derive(sp_core::RuntimeDebug)] +#[derive(RuntimeDebug)] pub enum Error { /// Module is not valid, couldn't be instantiated. Module, From cd21d1f223d42cdae50424719b989603231771df Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Tue, 26 Apr 2022 12:28:18 +0300 Subject: [PATCH 0728/1472] Change ci vars to use group one's (#11281) --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1c3e81ca71f3d..c05d528b2b091 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -599,7 +599,7 @@ build-rustdoc: - echo "${PRODUCT} version = ${VERSION}" - test -z "${VERSION}" && exit 1 script: - - test "$DOCKER_HUB_USER" -a "$DOCKER_HUB_PASS" || + - test "$Docker_Hub_User_Parity" -a "$Docker_Hub_Pass_Parity" || ( echo "no docker credentials provided"; exit 1 ) - buildah bud --format=docker @@ -608,8 +608,8 @@ build-rustdoc: --tag "$IMAGE_NAME:$VERSION" --tag "$IMAGE_NAME:latest" --file "$DOCKERFILE" . - - echo "$DOCKER_HUB_PASS" | - buildah login --username "$DOCKER_HUB_USER" --password-stdin docker.io + - 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:latest" From a7629eb19f749868d7d1a8d9606c75cc451d852f Mon Sep 17 00:00:00 2001 From: Ayevbeosa Iyamu Date: Tue, 26 Apr 2022 12:57:55 +0100 Subject: [PATCH 0729/1472] Recovery Pallet benchmarking (#11176) * Created benchmarks * Added recovery benchmarks * benchmark for `create_recovery` * benchmark for `initiate_recovery` * benchmark for `vouch_recovery` * benchmark for `claim_recovery` * benchmark for `close_recovery` * benchmark for `remove_recovery` * benchmark for `cancel_recovered` * benchmark for `as_recovered` * Some refactoring * Some refactoring * Fix create_recovery benchmark * fix close_recovery benchmark test * fixed issues with failing tests * Update frame/recovery/src/benchmarking.rs Co-authored-by: Oliver Tale-Yazdi * removed repetitive code * create weights file * Used weights to annotate extrinsics * Added WeightInfo implementation to mock * Beauty fixes Signed-off-by: Oliver Tale-Yazdi * Update frame/recovery/src/benchmarking.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/recovery/src/benchmarking.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Set vec to be mut * set delay_period to use non-zero amount * set delay default * Add weights Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 1 + bin/node/runtime/Cargo.toml | 1 + bin/node/runtime/src/lib.rs | 2 + frame/recovery/Cargo.toml | 8 + frame/recovery/src/benchmarking.rs | 371 +++++++++++++++++++++++++++++ frame/recovery/src/lib.rs | 114 ++------- frame/recovery/src/mock.rs | 5 +- frame/recovery/src/tests.rs | 21 +- frame/recovery/src/weights.rs | 203 ++++++++++++++++ 9 files changed, 626 insertions(+), 100 deletions(-) create mode 100644 frame/recovery/src/benchmarking.rs create mode 100644 frame/recovery/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index d58c66096848c..397f1f038c5d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6276,6 +6276,7 @@ dependencies = [ name = "pallet-recovery" version = "4.0.0-dev" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "pallet-balances", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 19d911a16552d..847530e5c61bc 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -215,6 +215,7 @@ runtime-benchmarks = [ "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-referenda/runtime-benchmarks", + "pallet-recovery/runtime-benchmarks", "pallet-remark/runtime-benchmarks", "pallet-session-benchmarking", "pallet-society/runtime-benchmarks", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index c88dc8d731d03..f073482d887bd 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1213,6 +1213,7 @@ parameter_types! { impl pallet_recovery::Config for Runtime { type Event = Event; + type WeightInfo = pallet_recovery::weights::SubstrateWeight; type Call = Call; type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; @@ -1557,6 +1558,7 @@ mod benches { [pallet_preimage, Preimage] [pallet_proxy, Proxy] [pallet_referenda, Referenda] + [pallet_recovery, Recovery] [pallet_remark, Remark] [pallet_scheduler, Scheduler] [pallet_session, SessionBench::] diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 0a173fe2c9dab..98dbfc0eb0d20 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -18,6 +18,7 @@ scale-info = { version = "2.0.1", default-features = false, features = ["derive" sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -27,6 +28,12 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] +runtime-benchmarks = [ + 'frame-benchmarking', + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] std = [ "codec/std", "scale-info/std", @@ -35,5 +42,6 @@ std = [ "sp-runtime/std", "frame-support/std", "frame-system/std", + "frame-benchmarking/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/recovery/src/benchmarking.rs b/frame/recovery/src/benchmarking.rs new file mode 100644 index 0000000000000..5354de6d10b51 --- /dev/null +++ b/frame/recovery/src/benchmarking.rs @@ -0,0 +1,371 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; + +use crate::Pallet; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_support::traits::{Currency, Get}; +use frame_system::RawOrigin; +use sp_runtime::traits::Bounded; + +const SEED: u32 = 0; +const DEFAULT_DELAY: u32 = 0; + +fn assert_last_event(generic_event: ::Event) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +fn get_total_deposit( + bounded_friends: &FriendsOf, +) -> Option<<::Currency as Currency<::AccountId>>::Balance> +{ + let friend_deposit = T::FriendDepositFactor::get() + .checked_mul(&bounded_friends.len().saturated_into()) + .unwrap(); + + T::ConfigDepositBase::get().checked_add(&friend_deposit) +} + +fn generate_friends(num: u32) -> Vec<::AccountId> { + // Create friends + let mut friends = (0..num).map(|x| account("friend", x, SEED)).collect::>(); + // Sort + friends.sort(); + + for friend in 0..friends.len() { + // Top up accounts of friends + T::Currency::make_free_balance_be( + &friends.get(friend).unwrap(), + BalanceOf::::max_value(), + ); + } + + friends +} + +fn add_caller_and_generate_friends( + caller: T::AccountId, + num: u32, +) -> Vec<::AccountId> { + // Create friends + let mut friends = generate_friends::(num - 1); + + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + + friends.push(caller); + + // Sort + friends.sort(); + + friends +} + +fn insert_recovery_account(caller: &T::AccountId, account: &T::AccountId) { + T::Currency::make_free_balance_be(&account, BalanceOf::::max_value()); + + let n = T::MaxFriends::get(); + + let friends = generate_friends::(n); + + let bounded_friends: FriendsOf = friends.try_into().unwrap(); + + // Get deposit for recovery + let total_deposit = get_total_deposit::(&bounded_friends).unwrap(); + + let recovery_config = RecoveryConfig { + delay_period: DEFAULT_DELAY.into(), + deposit: total_deposit, + friends: bounded_friends, + threshold: n as u16, + }; + + // Reserve deposit for recovery + T::Currency::reserve(&caller, total_deposit).unwrap(); + + >::insert(&account, recovery_config); +} + +benchmarks! { + as_recovered { + let caller: T::AccountId = whitelisted_caller(); + let recovered_account: T::AccountId = account("recovered_account", 0, SEED); + let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + + Proxy::::insert(&caller, &recovered_account); + }: _( + RawOrigin::Signed(caller), + recovered_account, + Box::new(call) + ) + + set_recovered { + let lost: T::AccountId = whitelisted_caller(); + let rescuer: T::AccountId = whitelisted_caller(); + }: _( + RawOrigin::Root, + lost.clone(), + rescuer.clone() + ) verify { + assert_last_event::( + Event::AccountRecovered { + lost_account: lost, + rescuer_account: rescuer, + }.into() + ); + } + + create_recovery { + let n in 1 .. T::MaxFriends::get(); + + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + + // Create friends + let friends = generate_friends::(n); + }: _( + RawOrigin::Signed(caller.clone()), + friends, + n as u16, + DEFAULT_DELAY.into() + ) verify { + assert_last_event::(Event::RecoveryCreated { account: caller }.into()); + } + + initiate_recovery { + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + + let lost_account: T::AccountId = account("lost_account", 0, SEED); + + insert_recovery_account::(&caller, &lost_account); + }: _( + RawOrigin::Signed(caller.clone()), + lost_account.clone() + ) verify { + assert_last_event::( + Event::RecoveryInitiated { + lost_account: lost_account, + rescuer_account: caller, + }.into() + ); + } + + vouch_recovery { + let n in 1 .. T::MaxFriends::get(); + + let caller: T::AccountId = whitelisted_caller(); + let lost_account: T::AccountId = account("lost_account", 0, SEED); + let rescuer_account: T::AccountId = account("rescuer_account", 0, SEED); + + // Create friends + let friends = add_caller_and_generate_friends::(caller.clone(), n); + let bounded_friends: FriendsOf = friends.try_into().unwrap(); + + // Get deposit for recovery + let total_deposit = get_total_deposit::(&bounded_friends).unwrap(); + + let recovery_config = RecoveryConfig { + delay_period: DEFAULT_DELAY.into(), + deposit: total_deposit.clone(), + friends: bounded_friends.clone(), + threshold: n as u16, + }; + + // Create the recovery config storage item + >::insert(&lost_account, recovery_config.clone()); + + // Reserve deposit for recovery + T::Currency::reserve(&caller, total_deposit).unwrap(); + + // Create an active recovery status + let recovery_status = ActiveRecovery { + created: DEFAULT_DELAY.into(), + deposit: total_deposit, + friends: generate_friends::(n - 1).try_into().unwrap(), + }; + + // Create the active recovery storage item + >::insert(&lost_account, &rescuer_account, recovery_status); + + }: _( + RawOrigin::Signed(caller.clone()), + lost_account.clone(), + rescuer_account.clone() + ) verify { + assert_last_event::( + Event::RecoveryVouched { + lost_account: lost_account, + rescuer_account: rescuer_account, + sender: caller, + }.into() + ); + } + + claim_recovery { + let n in 1 .. T::MaxFriends::get(); + + let caller: T::AccountId = whitelisted_caller(); + let lost_account: T::AccountId = account("lost_account", 0, SEED); + + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + + // Create friends + let friends = generate_friends::(n); + let bounded_friends: FriendsOf = friends.try_into().unwrap(); + + // Get deposit for recovery + let total_deposit = get_total_deposit::(&bounded_friends).unwrap(); + + let recovery_config = RecoveryConfig { + delay_period: 0u32.into(), + deposit: total_deposit.clone(), + friends: bounded_friends.clone(), + threshold: n as u16, + }; + + // Create the recovery config storage item + >::insert(&lost_account, recovery_config.clone()); + + // Reserve deposit for recovery + T::Currency::reserve(&caller, total_deposit).unwrap(); + + // Create an active recovery status + let recovery_status = ActiveRecovery { + created: 0u32.into(), + deposit: total_deposit, + friends: bounded_friends.clone(), + }; + + // Create the active recovery storage item + >::insert(&lost_account, &caller, recovery_status); + }: _( + RawOrigin::Signed(caller.clone()), + lost_account.clone() + ) verify { + assert_last_event::( + Event::AccountRecovered { + lost_account: lost_account, + rescuer_account: caller, + }.into() + ); + } + + close_recovery { + let caller: T::AccountId = whitelisted_caller(); + let rescuer_account: T::AccountId = account("rescuer_account", 0, SEED); + + let n in 1 .. T::MaxFriends::get(); + + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&rescuer_account, BalanceOf::::max_value()); + + // Create friends + let friends = generate_friends::(n); + let bounded_friends: FriendsOf = friends.try_into().unwrap(); + + // Get deposit for recovery + let total_deposit = get_total_deposit::(&bounded_friends).unwrap(); + + let recovery_config = RecoveryConfig { + delay_period: DEFAULT_DELAY.into(), + deposit: total_deposit.clone(), + friends: bounded_friends.clone(), + threshold: n as u16, + }; + + // Create the recovery config storage item + >::insert(&caller, recovery_config.clone()); + + // Reserve deposit for recovery + T::Currency::reserve(&caller, total_deposit).unwrap(); + + // Create an active recovery status + let recovery_status = ActiveRecovery { + created: DEFAULT_DELAY.into(), + deposit: total_deposit, + friends: bounded_friends.clone(), + }; + + // Create the active recovery storage item + >::insert(&caller, &rescuer_account, recovery_status); + }: _( + RawOrigin::Signed(caller.clone()), + rescuer_account.clone() + ) verify { + assert_last_event::( + Event::RecoveryClosed { + lost_account: caller, + rescuer_account: rescuer_account, + }.into() + ); + } + + remove_recovery { + let n in 1 .. T::MaxFriends::get(); + + let caller: T::AccountId = whitelisted_caller(); + + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + + // Create friends + let friends = generate_friends::(n); + let bounded_friends: FriendsOf = friends.try_into().unwrap(); + + // Get deposit for recovery + let total_deposit = get_total_deposit::(&bounded_friends).unwrap(); + + let recovery_config = RecoveryConfig { + delay_period: DEFAULT_DELAY.into(), + deposit: total_deposit.clone(), + friends: bounded_friends.clone(), + threshold: n as u16, + }; + + // Create the recovery config storage item + >::insert(&caller, recovery_config); + + // Reserve deposit for recovery + T::Currency::reserve(&caller, total_deposit).unwrap(); + }: _( + RawOrigin::Signed(caller.clone()) + ) verify { + assert_last_event::( + Event::RecoveryRemoved { + lost_account: caller + }.into() + ); + } + + cancel_recovered { + let caller: T::AccountId = whitelisted_caller(); + let account: T::AccountId = account("account", 0, SEED); + + frame_system::Pallet::::inc_providers(&caller); + + frame_system::Pallet::::inc_consumers(&caller)?; + + Proxy::::insert(&caller, &account); + }: _( + RawOrigin::Signed(caller), + account + ) + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index adc5c0b895c5f..e75c9025760b0 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -167,11 +167,16 @@ use frame_support::{ }; pub use pallet::*; +pub use weights::WeightInfo; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; #[cfg(test)] mod mock; #[cfg(test)] mod tests; +pub mod weights; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -222,10 +227,14 @@ pub mod pallet { /// The overarching event type. type Event: From> + IsType<::Event>; + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + /// The overarching call type. type Call: Parameter + Dispatchable - + GetDispatchInfo; + + GetDispatchInfo + + From>; /// The currency mechanism. type Currency: ReservableCurrency; @@ -365,21 +374,12 @@ pub mod pallet { /// Parameters: /// - `account`: The recovered account you want to make a call on-behalf-of. /// - `call`: The call you want to make with the recovered account. - /// - /// # - /// - The weight of the `call` + 10,000. - /// - One storage lookup to check account is recovered by `who`. O(1) - /// # #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( - dispatch_info.weight - .saturating_add(10_000) - // AccountData for inner call origin accountdata. - .saturating_add(T::DbWeight::get().reads_writes(1, 1)), + T::WeightInfo::as_recovered().saturating_add(dispatch_info.weight), dispatch_info.class, - ) - })] + )})] pub fn as_recovered( origin: OriginFor, account: T::AccountId, @@ -402,12 +402,7 @@ pub mod pallet { /// Parameters: /// - `lost`: The "lost account" to be recovered. /// - `rescuer`: The "rescuer account" which can call as the lost account. - /// - /// # - /// - One storage write O(1) - /// - One event - /// # - #[pallet::weight(30_000_000)] + #[pallet::weight(T::WeightInfo::set_recovered())] pub fn set_recovered( origin: OriginFor, lost: T::AccountId, @@ -439,18 +434,7 @@ pub mod pallet { /// friends. /// - `delay_period`: The number of blocks after a recovery attempt is initialized that /// needs to pass before the account can be recovered. - /// - /// # - /// - Key: F (len of friends) - /// - One storage read to check that account is not already recoverable. O(1). - /// - A check that the friends list is sorted and unique. O(F) - /// - One currency reserve operation. O(X) - /// - One storage write. O(1). Codec O(F). - /// - One event. - /// - /// Total Complexity: O(F + X) - /// # - #[pallet::weight(100_000_000)] + #[pallet::weight(T::WeightInfo::create_recovery(friends.len() as u32))] pub fn create_recovery( origin: OriginFor, friends: Vec, @@ -501,18 +485,7 @@ pub mod pallet { /// Parameters: /// - `account`: The lost account that you want to recover. This account needs to be /// recoverable (i.e. have a recovery configuration). - /// - /// # - /// - One storage read to check that account is recoverable. O(F) - /// - One storage read to check that this recovery process hasn't already started. O(1) - /// - One currency reserve operation. O(X) - /// - One storage read to get the current block number. O(1) - /// - One storage write. O(1). - /// - One event. - /// - /// Total Complexity: O(F + X) - /// # - #[pallet::weight(100_000_000)] + #[pallet::weight(T::WeightInfo::initiate_recovery())] pub fn initiate_recovery(origin: OriginFor, account: T::AccountId) -> DispatchResult { let who = ensure_signed(origin)?; // Check that the account is recoverable @@ -552,19 +525,7 @@ pub mod pallet { /// /// The combination of these two parameters must point to an active recovery /// process. - /// - /// # - /// Key: F (len of friends in config), V (len of vouching friends) - /// - One storage read to get the recovery configuration. O(1), Codec O(F) - /// - One storage read to get the active recovery process. O(1), Codec O(V) - /// - One binary search to confirm caller is a friend. O(logF) - /// - One binary search to confirm caller has not already vouched. O(logV) - /// - One storage write. O(1), Codec O(V). - /// - One event. - /// - /// Total Complexity: O(F + logF + V + logV) - /// # - #[pallet::weight(100_000_000)] + #[pallet::weight(T::WeightInfo::vouch_recovery(T::MaxFriends::get()))] pub fn vouch_recovery( origin: OriginFor, lost: T::AccountId, @@ -605,18 +566,7 @@ pub mod pallet { /// Parameters: /// - `account`: The lost account that you want to claim has been successfully recovered by /// you. - /// - /// # - /// Key: F (len of friends in config), V (len of vouching friends) - /// - One storage read to get the recovery configuration. O(1), Codec O(F) - /// - One storage read to get the active recovery process. O(1), Codec O(V) - /// - One storage read to get the current block number. O(1) - /// - One storage write. O(1), Codec O(V). - /// - One event. - /// - /// Total Complexity: O(F + V) - /// # - #[pallet::weight(100_000_000)] + #[pallet::weight(T::WeightInfo::claim_recovery(T::MaxFriends::get()))] pub fn claim_recovery(origin: OriginFor, account: T::AccountId) -> DispatchResult { let who = ensure_signed(origin)?; // Get the recovery configuration for the lost account @@ -659,16 +609,7 @@ pub mod pallet { /// /// Parameters: /// - `rescuer`: The account trying to rescue this recoverable account. - /// - /// # - /// Key: V (len of vouching friends) - /// - One storage read/remove to get the active recovery process. O(1), Codec O(V) - /// - One balance call to repatriate reserved. O(X) - /// - One event. - /// - /// Total Complexity: O(V + X) - /// # - #[pallet::weight(30_000_000)] + #[pallet::weight(T::WeightInfo::close_recovery(T::MaxFriends::get()))] pub fn close_recovery(origin: OriginFor, rescuer: T::AccountId) -> DispatchResult { let who = ensure_signed(origin)?; // Take the active recovery process started by the rescuer for this account. @@ -701,17 +642,7 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_ and must be a /// recoverable account (i.e. has a recovery configuration). - /// - /// # - /// Key: F (len of friends) - /// - One storage read to get the prefix iterator for active recoveries. O(1) - /// - One storage read/remove to get the recovery configuration. O(1), Codec O(F) - /// - One balance call to unreserved. O(X) - /// - One event. - /// - /// Total Complexity: O(F + X) - /// # - #[pallet::weight(30_000_000)] + #[pallet::weight(T::WeightInfo::remove_recovery(T::MaxFriends::get()))] pub fn remove_recovery(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; // Check there are no active recoveries @@ -733,16 +664,13 @@ pub mod pallet { /// /// Parameters: /// - `account`: The recovered account you are able to call on-behalf-of. - /// - /// # - /// - One storage mutation to check account is recovered by `who`. O(1) - /// # - #[pallet::weight(30_000_000)] + #[pallet::weight(T::WeightInfo::cancel_recovered())] pub fn cancel_recovered(origin: OriginFor, account: T::AccountId) -> DispatchResult { let who = ensure_signed(origin)?; // Check `who` is allowed to make a call on behalf of `account` ensure!(Self::proxy(&who) == Some(account), Error::::NotAllowed); Proxy::::remove(&who); + frame_system::Pallet::::dec_consumers(&who); Ok(()) } diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 2088f9eb0937e..44fc4d72a4a5f 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -97,15 +97,18 @@ parameter_types! { pub const ConfigDepositBase: u64 = 10; pub const FriendDepositFactor: u64 = 1; pub const RecoveryDeposit: u64 = 10; + // Large number of friends for benchmarking. + pub const MaxFriends: u32 = 128; } impl Config for Test { type Event = Event; + type WeightInfo = (); type Call = Call; type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; - type MaxFriends = ConstU32<3>; + type MaxFriends = MaxFriends; type RecoveryDeposit = RecoveryDeposit; } diff --git a/frame/recovery/src/tests.rs b/frame/recovery/src/tests.rs index 16fc678d357bb..a900a5b6bfa2a 100644 --- a/frame/recovery/src/tests.rs +++ b/frame/recovery/src/tests.rs @@ -20,7 +20,8 @@ use super::*; use frame_support::{assert_noop, assert_ok, bounded_vec, traits::Currency}; use mock::{ - new_test_ext, run_to_block, Balances, BalancesCall, Call, Origin, Recovery, RecoveryCall, Test, + new_test_ext, run_to_block, Balances, BalancesCall, Call, MaxFriends, Origin, Recovery, + RecoveryCall, Test, }; use sp_runtime::traits::BadOrigin; @@ -112,10 +113,13 @@ fn malicious_recovery_fails() { // Using account 1, the malicious user begins the recovery process on account 5 assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); // Off chain, the user **tricks** their friends and asks them to vouch for the recovery - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); // shame on you - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); // shame on you - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); // shame on you - // We met the threshold, lets try to recover the account...? + assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); + // shame on you + assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); + // shame on you + assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); + // shame on you + // We met the threshold, lets try to recover the account...? assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::DelayPeriod); // Account 1 needs to wait... run_to_block(19); @@ -162,7 +166,12 @@ fn create_recovery_handles_basic_errors() { ); // Too many friends assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![1, 2, 3, 4], 4, 0), + Recovery::create_recovery( + Origin::signed(5), + vec![1; (MaxFriends::get() + 1) as usize], + 1, + 0 + ), Error::::MaxFriends ); // Unsorted friends diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs new file mode 100644 index 0000000000000..4e5fb91ae69e1 --- /dev/null +++ b/frame/recovery/src/weights.rs @@ -0,0 +1,203 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_recovery +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-04-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/production/substrate +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet-recovery +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/recovery/src/weights.rs +// --template=.maintain/frame-weight-template.hbs +// --header=HEADER-APACHE2 + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_recovery. +pub trait WeightInfo { + fn as_recovered() -> Weight; + fn set_recovered() -> Weight; + fn create_recovery(n: u32, ) -> Weight; + fn initiate_recovery() -> Weight; + fn vouch_recovery(n: u32, ) -> Weight; + fn claim_recovery(n: u32, ) -> Weight; + fn close_recovery(n: u32, ) -> Weight; + fn remove_recovery(n: u32, ) -> Weight; + fn cancel_recovered() -> Weight; +} + +/// Weights for pallet_recovery using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Recovery Proxy (r:1 w:0) + fn as_recovered() -> Weight { + (3_667_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + } + // Storage: Recovery Proxy (r:0 w:1) + fn set_recovered() -> Weight { + (10_149_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery Recoverable (r:1 w:1) + fn create_recovery(n: u32, ) -> Weight { + (23_154_000 as Weight) + // Standard Error: 16_000 + .saturating_add((235_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery Recoverable (r:1 w:0) + // Storage: Recovery ActiveRecoveries (r:1 w:1) + fn initiate_recovery() -> Weight { + (28_857_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery Recoverable (r:1 w:0) + // Storage: Recovery ActiveRecoveries (r:1 w:1) + fn vouch_recovery(n: u32, ) -> Weight { + (17_841_000 as Weight) + // Standard Error: 10_000 + .saturating_add((349_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery Recoverable (r:1 w:0) + // Storage: Recovery ActiveRecoveries (r:1 w:0) + // Storage: Recovery Proxy (r:1 w:1) + fn claim_recovery(n: u32, ) -> Weight { + (24_927_000 as Weight) + // Standard Error: 14_000 + .saturating_add((222_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery ActiveRecoveries (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn close_recovery(n: u32, ) -> Weight { + (28_201_000 as Weight) + // Standard Error: 17_000 + .saturating_add((272_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Recovery ActiveRecoveries (r:1 w:0) + // Storage: Recovery Recoverable (r:1 w:1) + fn remove_recovery(n: u32, ) -> Weight { + (27_531_000 as Weight) + // Standard Error: 10_000 + .saturating_add((218_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery Proxy (r:1 w:1) + fn cancel_recovered() -> Weight { + (9_015_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Recovery Proxy (r:1 w:0) + fn as_recovered() -> Weight { + (3_667_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + } + // Storage: Recovery Proxy (r:0 w:1) + fn set_recovered() -> Weight { + (10_149_000 as Weight) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery Recoverable (r:1 w:1) + fn create_recovery(n: u32, ) -> Weight { + (23_154_000 as Weight) + // Standard Error: 16_000 + .saturating_add((235_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery Recoverable (r:1 w:0) + // Storage: Recovery ActiveRecoveries (r:1 w:1) + fn initiate_recovery() -> Weight { + (28_857_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery Recoverable (r:1 w:0) + // Storage: Recovery ActiveRecoveries (r:1 w:1) + fn vouch_recovery(n: u32, ) -> Weight { + (17_841_000 as Weight) + // Standard Error: 10_000 + .saturating_add((349_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery Recoverable (r:1 w:0) + // Storage: Recovery ActiveRecoveries (r:1 w:0) + // Storage: Recovery Proxy (r:1 w:1) + fn claim_recovery(n: u32, ) -> Weight { + (24_927_000 as Weight) + // Standard Error: 14_000 + .saturating_add((222_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery ActiveRecoveries (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn close_recovery(n: u32, ) -> Weight { + (28_201_000 as Weight) + // Standard Error: 17_000 + .saturating_add((272_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Recovery ActiveRecoveries (r:1 w:0) + // Storage: Recovery Recoverable (r:1 w:1) + fn remove_recovery(n: u32, ) -> Weight { + (27_531_000 as Weight) + // Standard Error: 10_000 + .saturating_add((218_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Recovery Proxy (r:1 w:1) + fn cancel_recovered() -> Weight { + (9_015_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } +} From f40dde2b092da06c73fb43a0e4a18255ec9fd908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Tue, 26 Apr 2022 09:14:21 -0300 Subject: [PATCH 0730/1472] Skip pr-custom-review if pull request is in Draft (#11248) * skip pr-custom-review if pull request is in Draft * ready_for_review * document steps[*].if * fix * converted_to_draft * fix Co-authored-by: Giles Cope --- .github/workflows/pr-custom-review.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/pr-custom-review.yml b/.github/workflows/pr-custom-review.yml index 322403da03b47..6cb16d931d6f4 100644 --- a/.github/workflows/pr-custom-review.yml +++ b/.github/workflows/pr-custom-review.yml @@ -11,12 +11,31 @@ on: - synchronize - review_requested - review_request_removed + - ready_for_review + - converted_to_draft pull_request_review: jobs: pr-custom-review: runs-on: ubuntu-latest steps: + - name: Skip if pull request is in Draft + # `if: github.event.pull_request.draft == true` should be kept here, at + # the step level, rather than at the job level. The latter is not + # recommended because when the PR is moved from "Draft" to "Ready to + # review" the workflow will immediately be passing (since it was skipped), + # even though it hasn't actually ran, since it takes a few seconds for + # the workflow to start. This is also disclosed in: + # https://github.community/t/dont-run-actions-on-draft-pull-requests/16817/17 + # That scenario would open an opportunity for the check to be bypassed: + # 1. Get your PR approved + # 2. Move it to Draft + # 3. Push whatever commits you want + # 4. Move it to "Ready for review"; now the workflow is passing (it was + # skipped) and "Check reviews" is also passing (it won't be updated + # until the workflow is finished) + if: github.event.pull_request.draft == true + run: exit 1 - name: pr-custom-review uses: paritytech/pr-custom-review@v2 with: From 0310d5591a556766a198dd94e09a474662f849f0 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 26 Apr 2022 16:31:26 +0200 Subject: [PATCH 0731/1472] Follow ups for `benchmark machine` (#11270) * Follow ups for the MachineCmd Signed-off-by: Oliver Tale-Yazdi * Fix CI Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Add to node-template Signed-off-by: Oliver Tale-Yazdi * Fix test with feature flag Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Lower disk requirements Signed-off-by: Oliver Tale-Yazdi * Add ExecutionLimit to the disk benchmarks Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Add doc Signed-off-by: Oliver Tale-Yazdi * Review fixes Signed-off-by: Oliver Tale-Yazdi * Rename DISK_WRITE_LIMIT -> DEFAULT_DISK_EXECUTION_LIMIT Signed-off-by: Oliver Tale-Yazdi * Rename POLKADOT_REFERENCE_HARDWARE -> SUBSTRATE_REFERENCE_HARDWARE Signed-off-by: Oliver Tale-Yazdi * Fix build profile + add license Signed-off-by: Oliver Tale-Yazdi * Remove deps Signed-off-by: Oliver Tale-Yazdi * Set tolerance to 10% Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * Ignore test I cannot reproduce the CI error, even with the full command: cargo test --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml I will put an 'ignore' on that test for now, since it works for me and is worth having. Signed-off-by: Oliver Tale-Yazdi * Remove test Still cannot reproduce the error and it fails in the CI. Removing it now. Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi --- Cargo.lock | 2 + bin/node-template/node/src/command.rs | 5 +- bin/node/cli/Cargo.toml | 1 + bin/node/cli/src/command.rs | 3 +- bin/node/cli/tests/benchmark_machine_works.rs | 23 ++- client/sysinfo/src/lib.rs | 5 + client/sysinfo/src/sysinfo.rs | 66 ++++-- utils/frame/benchmarking-cli/Cargo.toml | 2 + utils/frame/benchmarking-cli/build.rs | 31 +++ utils/frame/benchmarking-cli/src/lib.rs | 2 +- .../benchmarking-cli/src/machine/hardware.rs | 191 ++++++++++++++++++ .../frame/benchmarking-cli/src/machine/mod.rs | 173 ++++++++++++++-- .../src/machine/reference_hardware.json | 32 +++ .../frame/benchmarking-cli/src/shared/mod.rs | 16 ++ 14 files changed, 511 insertions(+), 41 deletions(-) create mode 100644 utils/frame/benchmarking-cli/build.rs create mode 100644 utils/frame/benchmarking-cli/src/machine/hardware.rs create mode 100644 utils/frame/benchmarking-cli/src/machine/reference_hardware.json diff --git a/Cargo.lock b/Cargo.lock index 397f1f038c5d3..26954cddbd5dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2181,6 +2181,7 @@ dependencies = [ "hex", "itertools", "kvdb", + "lazy_static", "linked-hash-map", "log 0.4.16", "memory-db", @@ -2210,6 +2211,7 @@ dependencies = [ "sp-storage", "sp-trie", "tempfile", + "thiserror", "thousands", ] diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index 809257f79007c..e3e10007929e6 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -4,7 +4,7 @@ use crate::{ command_helper::{inherent_benchmark_data, BenchmarkExtrinsicBuilder}, service, }; -use frame_benchmarking_cli::BenchmarkCmd; +use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; use node_template_runtime::Block; use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; @@ -141,7 +141,8 @@ pub fn run() -> sc_cli::Result<()> { cmd.run(config, client, inherent_benchmark_data()?, Arc::new(ext_builder)) }, - BenchmarkCmd::Machine(cmd) => cmd.run(&config), + BenchmarkCmd::Machine(cmd) => + cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), } }) }, diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 5562efa1846e1..6bb36b9f9ab94 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -96,6 +96,7 @@ sc-cli = { version = "0.10.0-dev", optional = true, path = "../../../client/cli" frame-benchmarking-cli = { version = "4.0.0-dev", optional = true, path = "../../../utils/frame/benchmarking-cli" } node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../utils/frame/try-runtime/cli" } +serde_json = "1.0.79" [target.'cfg(any(target_arch="x86_64", target_arch="aarch64"))'.dependencies] node-executor = { version = "3.0.0-dev", path = "../executor", features = ["wasmtime"] } diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index b98a38d2dbf5f..b17a26fa02935 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -130,7 +130,8 @@ pub fn run() -> Result<()> { cmd.run(config, client, inherent_benchmark_data()?, Arc::new(ext_builder)) }, - BenchmarkCmd::Machine(cmd) => cmd.run(&config), + BenchmarkCmd::Machine(cmd) => + cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), } }) }, diff --git a/bin/node/cli/tests/benchmark_machine_works.rs b/bin/node/cli/tests/benchmark_machine_works.rs index df407e988f636..bf4a2b7b85e65 100644 --- a/bin/node/cli/tests/benchmark_machine_works.rs +++ b/bin/node/cli/tests/benchmark_machine_works.rs @@ -24,9 +24,30 @@ use std::process::Command; fn benchmark_machine_works() { let status = Command::new(cargo_bin("substrate")) .args(["benchmark", "machine", "--dev"]) - .args(["--verify-duration", "0.1"]) + .args(["--verify-duration", "0.1", "--disk-duration", "0.1"]) + // Make it succeed. + .args(["--allow-fail"]) .status() .unwrap(); assert!(status.success()); } + +/// Test that the hardware does not meet the requirements. +/// +/// This is most likely to succeed since it uses a test profile. +#[test] +#[cfg(debug_assertions)] +fn benchmark_machine_fails_with_slow_hardware() { + let output = Command::new(cargo_bin("substrate")) + .args(["benchmark", "machine", "--dev"]) + .args(["--verify-duration", "0.1", "--disk-duration", "2", "--tolerance", "0"]) + .output() + .unwrap(); + + // Command should have failed. + assert!(!output.status.success()); + // An `UnmetRequirement` error should have been printed. + let log = String::from_utf8_lossy(&output.stderr).to_string(); + assert!(log.contains("UnmetRequirement")); +} diff --git a/client/sysinfo/src/lib.rs b/client/sysinfo/src/lib.rs index 911e725dcdd4e..be63fefe9ecd1 100644 --- a/client/sysinfo/src/lib.rs +++ b/client/sysinfo/src/lib.rs @@ -66,6 +66,11 @@ pub enum ExecutionLimit { } impl ExecutionLimit { + /// Creates a new execution limit with the passed seconds as duration limit. + pub fn from_secs_f32(secs: f32) -> Self { + Self::MaxDuration(Duration::from_secs_f32(secs)) + } + /// Returns the duration limit or `MAX` if none is present. pub fn max_duration(&self) -> Duration { match self { diff --git a/client/sysinfo/src/sysinfo.rs b/client/sysinfo/src/sysinfo.rs index 65d7a9e41b406..cd6adcf623e66 100644 --- a/client/sysinfo/src/sysinfo.rs +++ b/client/sysinfo/src/sysinfo.rs @@ -241,10 +241,16 @@ fn random_data(size: usize) -> Vec { buffer } -pub fn benchmark_disk_sequential_writes(directory: &Path) -> Result { +/// A default [`ExecutionLimit`] that can be used to call [`benchmark_disk_sequential_writes`] +/// and [`benchmark_disk_random_writes`]. +pub const DEFAULT_DISK_EXECUTION_LIMIT: ExecutionLimit = + ExecutionLimit::Both { max_iterations: 32, max_duration: Duration::from_millis(300) }; + +pub fn benchmark_disk_sequential_writes( + limit: ExecutionLimit, + directory: &Path, +) -> Result { const SIZE: usize = 64 * 1024 * 1024; - const MAX_ITERATIONS: usize = 32; - const MAX_DURATION: Duration = Duration::from_millis(300); let buffer = random_data(SIZE); let path = directory.join(".disk_bench_seq_wr.tmp"); @@ -273,14 +279,21 @@ pub fn benchmark_disk_sequential_writes(directory: &Path) -> Result Ok(()) }; - benchmark("disk sequential write score", SIZE, MAX_ITERATIONS, MAX_DURATION, run) - .map(|s| s as u64) + benchmark( + "disk sequential write score", + SIZE, + limit.max_iterations(), + limit.max_duration(), + run, + ) + .map(|s| s as u64) } -pub fn benchmark_disk_random_writes(directory: &Path) -> Result { +pub fn benchmark_disk_random_writes( + limit: ExecutionLimit, + directory: &Path, +) -> Result { const SIZE: usize = 64 * 1024 * 1024; - const MAX_ITERATIONS: usize = 32; - const MAX_DURATION: Duration = Duration::from_millis(300); let buffer = random_data(SIZE); let path = directory.join(".disk_bench_rand_wr.tmp"); @@ -333,8 +346,14 @@ pub fn benchmark_disk_random_writes(directory: &Path) -> Result { }; // We only wrote half of the bytes hence `SIZE / 2`. - benchmark("disk random write score", SIZE / 2, MAX_ITERATIONS, MAX_DURATION, run) - .map(|s| s as u64) + benchmark( + "disk random write score", + SIZE / 2, + limit.max_iterations(), + limit.max_duration(), + run, + ) + .map(|s| s as u64) } /// Benchmarks the verification speed of sr25519 signatures. @@ -389,7 +408,8 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { if let Some(scratch_directory) = scratch_directory { hwbench.disk_sequential_write_score = - match benchmark_disk_sequential_writes(scratch_directory) { + match benchmark_disk_sequential_writes(DEFAULT_DISK_EXECUTION_LIMIT, scratch_directory) + { Ok(score) => Some(score), Err(error) => { log::warn!("Failed to run the sequential write disk benchmark: {}", error); @@ -397,13 +417,14 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { }, }; - hwbench.disk_random_write_score = match benchmark_disk_random_writes(scratch_directory) { - Ok(score) => Some(score), - Err(error) => { - log::warn!("Failed to run the random write disk benchmark: {}", error); - None - }, - }; + hwbench.disk_random_write_score = + match benchmark_disk_random_writes(DEFAULT_DISK_EXECUTION_LIMIT, scratch_directory) { + Ok(score) => Some(score), + Err(error) => { + log::warn!("Failed to run the random write disk benchmark: {}", error); + None + }, + }; } hwbench @@ -437,12 +458,17 @@ mod tests { #[test] fn test_benchmark_disk_sequential_writes() { - assert!(benchmark_disk_sequential_writes("./".as_ref()).unwrap() > 0); + assert!( + benchmark_disk_sequential_writes(DEFAULT_DISK_EXECUTION_LIMIT, "./".as_ref()).unwrap() > + 0 + ); } #[test] fn test_benchmark_disk_random_writes() { - assert!(benchmark_disk_random_writes("./".as_ref()).unwrap() > 0); + assert!( + benchmark_disk_random_writes(DEFAULT_DISK_EXECUTION_LIMIT, "./".as_ref()).unwrap() > 0 + ); } #[test] diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 8a3773fb10022..208099162c52b 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -55,6 +55,8 @@ thousands = "0.2.0" prettytable-rs = "0.8.0" tempfile = "3.2.0" rand_pcg = "0.3.1" +lazy_static = "1.4.0" +thiserror = "1.0.30" [features] default = ["db", "sc-client-db/runtime-benchmarks"] diff --git a/utils/frame/benchmarking-cli/build.rs b/utils/frame/benchmarking-cli/build.rs new file mode 100644 index 0000000000000..4347804156815 --- /dev/null +++ b/utils/frame/benchmarking-cli/build.rs @@ -0,0 +1,31 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::env; + +/// Exposes build environment variables to the rust code. +/// +/// - The build profile as `build_profile` +/// - The optimization level as `build_opt_level` +pub fn main() { + if let Ok(opt_level) = env::var("OPT_LEVEL") { + println!("cargo:rustc-cfg=build_opt_level={:?}", opt_level); + } + if let Ok(profile) = env::var("PROFILE") { + println!("cargo:rustc-cfg=build_profile={:?}", profile); + } +} diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 75e2edc042a26..d0eee3d2939fc 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -25,7 +25,7 @@ mod shared; mod storage; pub use block::BlockCmd; -pub use machine::MachineCmd; +pub use machine::{MachineCmd, Requirements, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::{ExtrinsicBuilder, OverheadCmd}; pub use pallet::PalletCmd; pub use storage::StorageCmd; diff --git a/utils/frame/benchmarking-cli/src/machine/hardware.rs b/utils/frame/benchmarking-cli/src/machine/hardware.rs new file mode 100644 index 0000000000000..5c62660cc7cf4 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/machine/hardware.rs @@ -0,0 +1,191 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains types to define hardware requirements. + +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use std::fmt; + +lazy_static! { + /// The hardware requirements as measured on reference hardware. + /// + /// These values are provided by Parity, however it is possible + /// to use your own requirements if you are running a custom chain. + /// + /// The reference hardware is describe here: + /// + pub static ref SUBSTRATE_REFERENCE_HARDWARE: Requirements = { + let raw = include_bytes!("reference_hardware.json").as_slice(); + serde_json::from_slice(raw).expect("Hardcoded data is known good; qed") + }; +} + +/// Multiple requirements for the hardware. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Requirements(pub Vec); + +/// A single requirement for the hardware. +#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)] +pub struct Requirement { + /// The metric to measure. + pub metric: Metric, + /// The minimal throughput that needs to be archived for this requirement. + pub minimum: Throughput, +} + +/// A single hardware metric. +/// +/// The implementation of these is in `sc-sysinfo`. +#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)] +pub enum Metric { + /// SR25519 signature verification. + Sr25519Verify, + /// Blake2-256 hashing algorithm. + Blake2256, + /// Copying data in RAM. + MemCopy, + /// Disk sequential write. + DiskSeqWrite, + /// Disk random write. + DiskRndWrite, +} + +/// Throughput as measured in bytes per second. +#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)] +pub enum Throughput { + /// KiB/s + KiBs(f64), + /// MiB/s + MiBs(f64), + /// GiB/s + GiBs(f64), +} + +impl Metric { + /// The category of the metric. + pub fn category(&self) -> &'static str { + match self { + Self::Sr25519Verify | Self::Blake2256 => "CPU", + Self::MemCopy => "Memory", + Self::DiskSeqWrite | Self::DiskRndWrite => "Disk", + } + } + + /// The name of the metric. It is always prefixed by the [`self::category()`]. + pub fn name(&self) -> &'static str { + match self { + Self::Sr25519Verify => "SR25519-Verify", + Self::Blake2256 => "BLAKE2-256", + Self::MemCopy => "Copy", + Self::DiskSeqWrite => "Seq Write", + Self::DiskRndWrite => "Rnd Write", + } + } +} + +const KIBIBYTE: f64 = 1024.0; + +impl Throughput { + /// The unit of the metric. + pub fn unit(&self) -> &'static str { + match self { + Self::KiBs(_) => "KiB/s", + Self::MiBs(_) => "MiB/s", + Self::GiBs(_) => "GiB/s", + } + } + + /// [`Self`] as number of byte/s. + pub fn to_bs(&self) -> f64 { + self.to_kibs() * KIBIBYTE + } + + /// [`Self`] as number of kibibyte/s. + pub fn to_kibs(&self) -> f64 { + self.to_mibs() * KIBIBYTE + } + + /// [`Self`] as number of mebibyte/s. + pub fn to_mibs(&self) -> f64 { + self.to_gibs() * KIBIBYTE + } + + /// [`Self`] as number of gibibyte/s. + pub fn to_gibs(&self) -> f64 { + match self { + Self::KiBs(k) => *k / (KIBIBYTE * KIBIBYTE), + Self::MiBs(m) => *m / KIBIBYTE, + Self::GiBs(g) => *g, + } + } + + /// Normalizes [`Self`] to use the larges unit possible. + pub fn normalize(&self) -> Self { + let bs = self.to_bs(); + + if bs >= KIBIBYTE * KIBIBYTE * KIBIBYTE { + Self::GiBs(self.to_gibs()) + } else if bs >= KIBIBYTE * KIBIBYTE { + Self::MiBs(self.to_mibs()) + } else { + Self::KiBs(self.to_kibs()) + } + } +} + +impl fmt::Display for Throughput { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let normalized = self.normalize(); + match normalized { + Self::KiBs(s) | Self::MiBs(s) | Self::GiBs(s) => + write!(f, "{:.2?} {}", s, normalized.unit()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_runtime::assert_eq_error_rate; + + /// `SUBSTRATE_REFERENCE_HARDWARE` can be en- and decoded. + #[test] + fn json_static_data() { + let raw = serde_json::to_string(&*SUBSTRATE_REFERENCE_HARDWARE).unwrap(); + let decoded: Requirements = serde_json::from_str(&raw).unwrap(); + + assert_eq!(decoded, SUBSTRATE_REFERENCE_HARDWARE.clone()); + } + + /// Test the [`Throughput`]. + #[test] + fn throughput_works() { + /// Float precision. + const EPS: f64 = 0.1; + let gib = Throughput::GiBs(14.324); + + assert_eq_error_rate!(14.324, gib.to_gibs(), EPS); + assert_eq_error_rate!(14667.776, gib.to_mibs(), EPS); + assert_eq_error_rate!(14667.776 * 1024.0, gib.to_kibs(), EPS); + assert_eq!("14.32 GiB/s", gib.to_string()); + assert_eq!("14.32 GiB/s", gib.normalize().to_string()); + + let mib = Throughput::MiBs(1029.0); + assert_eq!("1.00 GiB/s", mib.to_string()); + } +} diff --git a/utils/frame/benchmarking-cli/src/machine/mod.rs b/utils/frame/benchmarking-cli/src/machine/mod.rs index ee6bf765d01c4..9e25e58921d71 100644 --- a/utils/frame/benchmarking-cli/src/machine/mod.rs +++ b/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -18,6 +18,8 @@ //! Contains the [`MachineCmd`] as entry point for the node //! and the core benchmarking logic. +pub mod hardware; + use sc_cli::{CliConfiguration, Result, SharedParams}; use sc_service::Configuration; use sc_sysinfo::{ @@ -26,9 +28,12 @@ use sc_sysinfo::{ }; use clap::Parser; -use log::info; +use log::{error, info, warn}; use prettytable::{cell, row, table}; -use std::{fmt::Debug, fs, time::Duration}; +use std::{boxed::Box, fmt::Debug, fs, path::Path}; + +use crate::shared::check_build_profile; +pub use hardware::{Metric, Requirement, Requirements, Throughput, SUBSTRATE_REFERENCE_HARDWARE}; /// Command to benchmark the hardware. /// @@ -44,40 +49,176 @@ pub struct MachineCmd { #[clap(flatten)] pub shared_params: SharedParams, + /// Do not return an error if any check fails. + /// + /// Should only be used for debugging. + #[clap(long)] + pub allow_fail: bool, + + /// Set a fault tolerance for passing a requirement. + /// + /// 10% means that the test would pass even when only 90% score was archived. + /// Can be used to mitigate outliers of the benchmarks. + #[clap(long, default_value = "10.0", value_name = "PERCENT")] + pub tolerance: f64, + /// Time limit for the verification benchmark. #[clap(long, default_value = "2.0", value_name = "SECONDS")] pub verify_duration: f32, + + /// Time limit for each disk benchmark. + #[clap(long, default_value = "5.0", value_name = "SECONDS")] + pub disk_duration: f32, +} + +/// Helper for the result of a concrete benchmark. +struct BenchResult { + /// Did the hardware pass the benchmark? + passed: bool, + + /// The absolute score that was archived. + score: Throughput, + + /// The score relative to the minimal required score. + /// + /// Is in range [0, 1]. + rel_score: f64, +} + +/// Errors that can be returned by the this command. +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum Error { + #[error("One of the benchmarks had a score that was lower than its requirement")] + UnmetRequirement, + + #[error("The build profile is unfit for benchmarking: {0}")] + BadBuildProfile(String), + + #[error("Benchmark results are off by at least factor 100")] + BadResults, } impl MachineCmd { /// Execute the benchmark and print the results. - pub fn run(&self, cfg: &Configuration) -> Result<()> { + pub fn run(&self, cfg: &Configuration, requirements: Requirements) -> Result<()> { + self.validate_args()?; // Ensure that the dir exists since the node is not started to take care of it. let dir = cfg.database.path().ok_or("No DB directory provided")?; fs::create_dir_all(dir)?; info!("Running machine benchmarks..."); - let write = benchmark_disk_sequential_writes(dir)?; - let read = benchmark_disk_random_writes(dir)?; - let verify_limit = - ExecutionLimit::MaxDuration(Duration::from_secs_f32(self.verify_duration)); - let verify = benchmark_sr25519_verify(verify_limit) * 1024.0; + let mut results = Vec::new(); + for requirement in &requirements.0 { + let result = self.run_benchmark(requirement, &dir)?; + results.push(result); + } + self.print_summary(requirements, results) + } + /// Benchmarks a specific metric of the hardware and judges the resulting score. + fn run_benchmark(&self, requirement: &Requirement, dir: &Path) -> Result { + // Dispatch the concrete function from `sc-sysinfo`. + let score = self.measure(&requirement.metric, dir)?; + let rel_score = score.to_bs() / requirement.minimum.to_bs(); + + // Sanity check if the result is off by factor >100x. + if rel_score >= 100.0 || rel_score <= 0.01 { + self.check_failed(Error::BadResults)?; + } + let passed = rel_score >= (1.0 - (self.tolerance / 100.0)); + Ok(BenchResult { passed, score, rel_score }) + } + + /// Measures a metric of the hardware. + fn measure(&self, metric: &Metric, dir: &Path) -> Result { + let verify_limit = ExecutionLimit::from_secs_f32(self.verify_duration); + let disk_limit = ExecutionLimit::from_secs_f32(self.disk_duration); + + let score = match metric { + Metric::Blake2256 => Throughput::MiBs(benchmark_cpu() as f64), + Metric::Sr25519Verify => Throughput::MiBs(benchmark_sr25519_verify(verify_limit)), + Metric::MemCopy => Throughput::MiBs(benchmark_memory() as f64), + Metric::DiskSeqWrite => + Throughput::MiBs(benchmark_disk_sequential_writes(disk_limit, dir)? as f64), + Metric::DiskRndWrite => + Throughput::MiBs(benchmark_disk_random_writes(disk_limit, dir)? as f64), + }; + Ok(score) + } + + /// Prints a human-readable summary. + fn print_summary(&self, requirements: Requirements, results: Vec) -> Result<()> { // Use a table for nicer console output. - let table = table!( - ["Category", "Function", "Score", "Unit"], - ["CPU", "BLAKE2-256", benchmark_cpu(), "MB/s"], - ["CPU", "SR25519 Verify", format!("{:.1}", verify), "KB/s"], - ["Memory", "Copy", benchmark_memory(), "MB/s"], - ["Disk", "Seq Write", write, "MB/s"], - ["Disk", "Rnd Write", read, "MB/s"] + let mut table = table!(["Category", "Function", "Score", "Minimum", "Result"]); + // Count how many passed and how many failed. + let (mut passed, mut failed) = (0, 0); + for (requirement, result) in requirements.0.iter().zip(results.iter()) { + if result.passed { + passed += 1 + } else { + failed += 1 + } + + table.add_row(result.to_row(requirement)); + } + // Print the table and a summary. + info!( + "\n{}\nFrom {} benchmarks in total, {} passed and {} failed ({:.0?}% fault tolerance).", + table, + passed + failed, + passed, + failed, + self.tolerance ); + // Print the final result. + if failed != 0 { + info!("The hardware fails to meet the requirements"); + self.check_failed(Error::UnmetRequirement)?; + } else { + info!("The hardware meets the requirements "); + } + // Check that the results were not created by a bad build profile. + if let Err(err) = check_build_profile() { + self.check_failed(Error::BadBuildProfile(err))?; + } + Ok(()) + } + + /// Returns `Ok` if [`self.allow_fail`] is set and otherwise the error argument. + fn check_failed(&self, e: Error) -> Result<()> { + if !self.allow_fail { + error!("Failing since --allow-fail is not set"); + Err(sc_cli::Error::Application(Box::new(e))) + } else { + warn!("Ignoring error since --allow-fail is set: {:?}", e); + Ok(()) + } + } - info!("\n{}", table); + /// Validates the CLI arguments. + fn validate_args(&self) -> Result<()> { + if self.tolerance > 100.0 || self.tolerance < 0.0 { + return Err("The --tolerance argument is out of range".into()) + } Ok(()) } } +impl BenchResult { + /// Format [`Self`] as row that can be printed in a table. + fn to_row(&self, req: &Requirement) -> prettytable::Row { + let passed = if self.passed { "✅ Pass" } else { "❌ Fail" }; + row![ + req.metric.category(), + req.metric.name(), + format!("{}", self.score), + format!("{}", req.minimum), + format!("{} ({: >5.1?} %)", passed, self.rel_score * 100.0) + ] + } +} + // Boilerplate impl CliConfiguration for MachineCmd { fn shared_params(&self) -> &SharedParams { diff --git a/utils/frame/benchmarking-cli/src/machine/reference_hardware.json b/utils/frame/benchmarking-cli/src/machine/reference_hardware.json new file mode 100644 index 0000000000000..12645df8391e7 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/machine/reference_hardware.json @@ -0,0 +1,32 @@ +[ + { + "metric": "Blake2256", + "minimum": { + "MiBs": 1029.0 + } + }, + { + "metric": "Sr25519Verify", + "minimum": { + "KiBs": 666.0 + } + }, + { + "metric": "MemCopy", + "minimum": { + "GiBs": 14.323 + } + }, + { + "metric": "DiskSeqWrite", + "minimum": { + "MiBs": 450.0 + } + }, + { + "metric": "DiskRndWrite", + "minimum": { + "MiBs": 200.0 + } + } +] diff --git a/utils/frame/benchmarking-cli/src/shared/mod.rs b/utils/frame/benchmarking-cli/src/shared/mod.rs index 853fbdef8e87f..f959c285a346e 100644 --- a/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -73,3 +73,19 @@ pub fn new_rng(seed: Option) -> (impl rand::Rng, u64) { let seed = seed.unwrap_or(rand::thread_rng().gen::()); (rand_pcg::Pcg64::seed_from_u64(seed), seed) } + +/// Returns an error if a debug profile is detected. +/// +/// The rust compiler only exposes the binary information whether +/// or not we are in a `debug` build. +/// This means that `release` and `production` cannot be told apart. +/// This function additionally checks for OPT-LEVEL = 3. +pub fn check_build_profile() -> Result<(), String> { + if cfg!(build_profile = "debug") { + Err("Detected a `debug` profile".into()) + } else if !cfg!(build_opt_level = "3") { + Err("The optimization level is not set to 3".into()) + } else { + Ok(()) + } +} From 4d3d480d8149fbca2834d05cc050a01f9a25afbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Tue, 26 Apr 2022 11:59:13 -0300 Subject: [PATCH 0732/1472] use options for check_dependent_project (#11284) Co-authored-by: TriplEight --- .gitlab-ci.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c05d528b2b091..0c06f3eb9c8e0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -468,13 +468,10 @@ cargo-check-macos: "--branch=$PIPELINE_SCRIPTS_TAG" https://github.com/paritytech/pipeline-scripts - ./pipeline-scripts/check_dependent_project.sh - paritytech - substrate - --substrate - "$DEPENDENT_REPO" - "$GITHUB_PR_TOKEN" - "$CARGO_UPDATE_CRATES" - "$EXTRA_DEPENDENCIES" + --org paritytech + --dependent-repo "$DEPENDENT_REPO" + --github-api-token "$GITHUB_PR_TOKEN" + --extra-dependencies "$EXTRA_DEPENDENCIES" # Individual jobs are set up for each dependent project so that they can be ran in parallel. # Arguably we could generate a job for each companion in the PR's description using Gitlab's @@ -484,13 +481,11 @@ check-dependent-polkadot: <<: *check-dependent-project variables: DEPENDENT_REPO: polkadot - CARGO_UPDATE_CRATES: "sp-io" check-dependent-cumulus: <<: *check-dependent-project variables: DEPENDENT_REPO: cumulus - CARGO_UPDATE_CRATES: "sp-io polkadot-runtime-common" EXTRA_DEPENDENCIES: polkadot From ba20231e277561cc447c5ca13eebb05f470a2927 Mon Sep 17 00:00:00 2001 From: yjh Date: Wed, 27 Apr 2022 02:21:30 +0800 Subject: [PATCH 0733/1472] chore: remove unused scoped-tls (#11286) * chore: remove unused scoped-tls * rm irrelevant files * rm sp-core --- Cargo.lock | 7 ------- client/executor/wasmi/Cargo.toml | 1 - 2 files changed, 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26954cddbd5dc..eeca5975a6f2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8639,7 +8639,6 @@ dependencies = [ "parity-scale-codec", "sc-allocator", "sc-executor-common", - "scoped-tls", "sp-runtime-interface", "sp-sandbox", "sp-wasm-interface", @@ -9347,12 +9346,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - [[package]] name = "scopeguard" version = "1.1.0" diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index ed653dca0aaab..9d913d1e9cc3e 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -15,7 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.16" -scoped-tls = "1.0" wasmi = "0.9.1" codec = { package = "parity-scale-codec", version = "3.0.0" } From 8bc45ed4be61b83dcfac77bfc8002858ff8042ec Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Tue, 26 Apr 2022 21:15:00 +0200 Subject: [PATCH 0734/1472] typo in `from_rational` rounding example (#11301) --- primitives/arithmetic/src/per_things.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index 1b9e6d91a2cd3..3851270b8d4db 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -273,7 +273,7 @@ pub trait PerThing: /// ```rust /// # use sp_arithmetic::{Percent, PerThing}; /// # fn main () { - /// // 989/100 is technically closer to 99%. + /// // 989/1000 is technically closer to 99%. /// assert_eq!( /// Percent::from_rational(989u64, 1000), /// Percent::from_parts(98), From 6e740bc89d097a38d922d5619b55e0c7e8664a6c Mon Sep 17 00:00:00 2001 From: Koute Date: Wed, 27 Apr 2022 14:35:52 +0900 Subject: [PATCH 0735/1472] Make wildcard storage change subscriptions RPC-unsafe (#11259) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * When an RPC is rejected because it's RPC-unsafe say why in the error message * Make wildcard storage change subscriptions RPC-unsafe * Apply suggestions from code review Co-authored-by: Bastian Köcher * Fix typo * Fix tests Co-authored-by: Bastian Köcher --- client/consensus/babe/rpc/src/lib.rs | 2 +- client/rpc-api/src/policy.rs | 4 ++-- client/rpc-api/src/state/mod.rs | 13 +++++++++- client/rpc/src/state/mod.rs | 10 +++++++- client/rpc/src/state/tests.rs | 36 ++++++++++++++++++++++++++++ utils/frame/rpc/system/src/lib.rs | 2 +- 6 files changed, 61 insertions(+), 6 deletions(-) diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 9dd6424a43a98..1fbe23e54f50d 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -290,6 +290,6 @@ mod tests { let mut response: serde_json::Value = serde_json::from_str(&response).unwrap(); let error: RpcError = serde_json::from_value(response["error"].take()).unwrap(); - assert_eq!(error, RpcError::method_not_found()) + assert_eq!(error, sc_rpc_api::UnsafeRpcError.into()) } } diff --git a/client/rpc-api/src/policy.rs b/client/rpc-api/src/policy.rs index 4d1e1d7c4ce7c..dc0753c1b9139 100644 --- a/client/rpc-api/src/policy.rs +++ b/client/rpc-api/src/policy.rs @@ -56,7 +56,7 @@ impl std::fmt::Display for UnsafeRpcError { impl std::error::Error for UnsafeRpcError {} impl From for rpc::Error { - fn from(_: UnsafeRpcError) -> rpc::Error { - rpc::Error::method_not_found() + fn from(error: UnsafeRpcError) -> rpc::Error { + rpc::Error { code: rpc::ErrorCode::MethodNotFound, message: error.to_string(), data: None } } } diff --git a/client/rpc-api/src/state/mod.rs b/client/rpc-api/src/state/mod.rs index 453e954ce5952..42e927580960c 100644 --- a/client/rpc-api/src/state/mod.rs +++ b/client/rpc-api/src/state/mod.rs @@ -144,7 +144,18 @@ pub trait StateApi { id: SubscriptionId, ) -> RpcResult; - /// New storage subscription + /// Subscribe to the changes in the storage. + /// + /// This RPC endpoint has two modes of operation: + /// 1) When `keys` is not `None` you'll only be informed about the changes + /// done to the specified keys; this is RPC-safe. + /// 2) When `keys` is `None` you'll be informed of *all* of the changes; + /// **this is RPC-unsafe**. + /// + /// When subscribed to all of the changes this API will emit every storage + /// change for every block that is imported. These changes will only be sent + /// after a block is imported. If you require a consistent view across all changes + /// of every block, you need to take this into account. #[pubsub(subscription = "state_storage", subscribe, name = "state_subscribeStorage")] fn subscribe_storage( &self, diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index 071db5324c836..c9806a30b4549 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -332,7 +332,15 @@ where subscriber: Subscriber>, keys: Option>, ) { - self.backend.subscribe_storage(meta, subscriber, keys); + if keys.is_none() { + if let Err(err) = self.deny_unsafe.check_if_safe() { + subscriber.reject(err.into()) + .expect("subscription rejection can only fail if it's been already rejected, and we're rejecting it for the first time; qed"); + return + } + } + + self.backend.subscribe_storage(meta, subscriber, keys) } fn unsubscribe_storage( diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 287dfac8c6ba0..19e474ee6459a 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -571,3 +571,39 @@ fn should_deserialize_storage_key() { assert_eq!(k.0.len(), 32); } + +#[test] +fn wildcard_storage_subscriptions_are_rpc_unsafe() { + let (subscriber, id, _) = Subscriber::new_test("test"); + + let client = Arc::new(substrate_test_runtime_client::new()); + let (api, _child) = new_full( + client.clone(), + SubscriptionManager::new(Arc::new(TaskExecutor)), + DenyUnsafe::Yes, + None, + ); + + api.subscribe_storage(Default::default(), subscriber, None.into()); + + let error = executor::block_on(id).unwrap().unwrap_err(); + assert_eq!(error.to_string(), "Method not found: RPC call is unsafe to be called externally"); +} + +#[test] +fn concrete_storage_subscriptions_are_rpc_safe() { + let (subscriber, id, _) = Subscriber::new_test("test"); + + let client = Arc::new(substrate_test_runtime_client::new()); + let (api, _child) = new_full( + client.clone(), + SubscriptionManager::new(Arc::new(TaskExecutor)), + DenyUnsafe::Yes, + None, + ); + + let key = StorageKey(STORAGE_KEY.to_vec()); + api.subscribe_storage(Default::default(), subscriber, Some(vec![key])); + + assert!(matches!(executor::block_on(id), Ok(Ok(SubscriptionId::String(_))))); +} diff --git a/utils/frame/rpc/system/src/lib.rs b/utils/frame/rpc/system/src/lib.rs index 0eae4d061afbb..b7da7730f0920 100644 --- a/utils/frame/rpc/system/src/lib.rs +++ b/utils/frame/rpc/system/src/lib.rs @@ -279,7 +279,7 @@ mod tests { let res = accounts.dry_run(vec![].into(), None); // then - assert_eq!(block_on(res), Err(RpcError::method_not_found())); + assert_eq!(block_on(res), Err(sc_rpc_api::UnsafeRpcError.into())); } #[test] From 3a02a69f31bfe4c750b2b9a16abf1e161a301849 Mon Sep 17 00:00:00 2001 From: Chigozie Joshua <36326251+guzzit@users.noreply.github.com> Date: Wed, 27 Apr 2022 10:23:46 +0100 Subject: [PATCH 0736/1472] Adds remove_approval feature to treasury pallet (#11243) * added remove_approval feature to treasury pallet * Update frame/treasury/src/lib.rs Co-authored-by: Xiliang Chen * treasury pallet refactoring: removed proposalId check in remove_approval call and trailing new line in tests file * fmt * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_treasury --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/treasury/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/treasury/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * remove_approval extrinsic in treasury pallet:added extra checks in test and extra documentation * refactored error logging on remove_approval extrinsic in treasury pallet Co-authored-by: Xiliang Chen Co-authored-by: Shawn Tabrizi Co-authored-by: Parity Bot Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- frame/treasury/src/benchmarking.rs | 11 ++++++ frame/treasury/src/lib.rs | 37 ++++++++++++++++++++ frame/treasury/src/tests.rs | 18 ++++++++++ frame/treasury/src/weights.rs | 54 ++++++++++++++++++------------ 4 files changed, 99 insertions(+), 21 deletions(-) diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index a0dd58ee3d42a..47bc1b9ea99de 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -87,6 +87,17 @@ benchmarks_instance_pallet! { let proposal_id = Treasury::::proposal_count() - 1; }: _(RawOrigin::Root, proposal_id) + remove_approval { + let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); + Treasury::::propose_spend( + RawOrigin::Signed(caller).into(), + value, + beneficiary_lookup + )?; + let proposal_id = Treasury::::proposal_count() - 1; + Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; + }: _(RawOrigin::Root, proposal_id) + on_initialize_proposals { let p in 0 .. T::MaxApprovals::get(); setup_pot_account::(); diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 81fca5243afa3..3f76ddb639c5b 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -50,6 +50,7 @@ //! - `propose_spend` - Make a spending proposal and stake the required deposit. //! - `reject_proposal` - Reject a proposal, slashing the deposit. //! - `approve_proposal` - Accept the proposal, returning the deposit. +//! - `remove_approval` - Remove an approval, the deposit will no longer be returned. //! //! ## GenesisConfig //! @@ -289,6 +290,8 @@ pub mod pallet { InvalidIndex, /// Too many approvals in the queue. TooManyApprovals, + /// Proposal has not been approved. + ProposalNotApproved, } #[pallet::hooks] @@ -393,6 +396,40 @@ pub mod pallet { .map_err(|_| Error::::TooManyApprovals)?; Ok(()) } + + /// Force a previously approved proposal to be removed from the approval queue. + /// The original deposit will no longer be returned. + /// + /// May only be called from `T::RejectOrigin`. + /// - `proposal_id`: The index of a proposal + /// + /// # + /// - Complexity: O(A) where `A` is the number of approvals + /// - Db reads and writes: `Approvals` + /// # + /// + /// Errors: + /// - `ProposalNotApproved`: The `proposal_id` supplied was not found in the approval queue, + /// i.e., the proposal has not been approved. This could also mean the proposal does not + /// exist altogether, thus there is no way it would have been approved in the first place. + #[pallet::weight((T::WeightInfo::remove_approval(), DispatchClass::Operational))] + pub fn remove_approval( + origin: OriginFor, + #[pallet::compact] proposal_id: ProposalIndex, + ) -> DispatchResult { + T::RejectOrigin::ensure_origin(origin)?; + + Approvals::::try_mutate(|v| -> DispatchResult { + if let Some(index) = v.iter().position(|x| x == &proposal_id) { + v.remove(index); + Ok(()) + } else { + Err(Error::::ProposalNotApproved.into()) + } + })?; + + Ok(()) + } } } diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index 26189f5201498..a67bbe9b1d1e9 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -388,3 +388,21 @@ fn max_approvals_limited() { ); }); } + +#[test] +fn remove_already_removed_approval_fails() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&Treasury::account_id(), 101); + + assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_eq!(Treasury::approvals(), vec![0]); + assert_ok!(Treasury::remove_approval(Origin::root(), 0)); + assert_eq!(Treasury::approvals(), vec![]); + + assert_noop!( + Treasury::remove_approval(Origin::root(), 0), + Error::::ProposalNotApproved + ); + }); +} diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index dcbf5983fa65c..c846a7f6885e9 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_treasury //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-04-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -33,9 +34,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/treasury/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,6 +48,7 @@ pub trait WeightInfo { fn propose_spend() -> Weight; fn reject_proposal() -> Weight; fn approve_proposal(p: u32, ) -> Weight; + fn remove_approval() -> Weight; fn on_initialize_proposals(p: u32, ) -> Weight; } @@ -58,34 +58,40 @@ impl WeightInfo for SubstrateWeight { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (21_673_000 as Weight) + (22_063_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (25_353_000 as Weight) + (25_965_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (8_164_000 as Weight) - // Standard Error: 1_000 - .saturating_add((57_000 as Weight).saturating_mul(p as Weight)) + (7_299_000 as Weight) + // Standard Error: 0 + .saturating_add((103_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Treasury Approvals (r:1 w:1) + fn remove_approval() -> Weight { + (3_867_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Treasury Approvals (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (20_762_000 as Weight) - // Standard Error: 21_000 - .saturating_add((26_835_000 as Weight).saturating_mul(p as Weight)) + (24_020_000 as Weight) + // Standard Error: 22_000 + .saturating_add((28_198_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -98,34 +104,40 @@ impl WeightInfo for () { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (21_673_000 as Weight) + (22_063_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (25_353_000 as Weight) + (25_965_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (8_164_000 as Weight) - // Standard Error: 1_000 - .saturating_add((57_000 as Weight).saturating_mul(p as Weight)) + (7_299_000 as Weight) + // Standard Error: 0 + .saturating_add((103_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Treasury Approvals (r:1 w:1) + fn remove_approval() -> Weight { + (3_867_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Treasury Approvals (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (20_762_000 as Weight) - // Standard Error: 21_000 - .saturating_add((26_835_000 as Weight).saturating_mul(p as Weight)) + (24_020_000 as Weight) + // Standard Error: 22_000 + .saturating_add((28_198_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) From 9e41e40c4016deff3a1babccbf7ce3419e966a79 Mon Sep 17 00:00:00 2001 From: Zeke Mostov Date: Wed, 27 Apr 2022 03:46:47 -0700 Subject: [PATCH 0737/1472] Nomination Pools (#10694) * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Add admin roles and make some calls permissionless * Destroy pool in withdraw unbonded * Add docs on pool admin * Fixup tests * Test unbond_other permissionless scenarios * Test withdraw unbonded permissionless * Test only can join open pools * Move unsafe set state to mock * Test: nominate_works * Add bounds: MinJoinBond, MinCreateBond, MaxPools * Test MinCreateBond, MinJoinBond, MaxPools * Add post checks to tests * Remove some TODOs * Setup weight infrastructure * Benchmark claim_payout * Benchmark create * Benchmark nominate * Benchmark join * Benchmark unbond_other * Refactor join benchmark to use scenario setup * Clean up and address warnings * Basic withdraw unbonded benchmarks * Refactor nominate benchmark * Refactor claim payout * Add feature sp-staking/runtime-benchmarks * Get node runtime to compile * Get node to run * Make claim_payout bench work with node * Make pool_withdraw_unbonded bench work with node * Make withdraw_unbonded_other work with node runtime' * Make create benchmark work with node * Make nominate benchmark work with node runtime * WiP new benchmark crate * Implement initial mock for benchmarks * Establish benchmark setup logic * Get claim payout and nominate benchmarks working * Remove pool bench utils; make struct fields pub insteaad * Get more benchmarks to work; trim interface trait * Some more top level docs * Finish tranistion benchmarks to crate * Hook up benchmark pallet to node runtime * Get benches to work with node runtime * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Benchmark withdraw_unbonded_other_kill * Delete old benchmarking files * Refunds for withdraw_unbonded * Remove some TODOs * 'Don't return an option for the current_era' * Streamline extrinsic docs * small docs tweaks * Refactor ledger::slash * Add on_slash impl for nomination pools * slash refactor wip * WIP slash working * DRY Ledger::stash * Fix slash saturation * Remove unused param from slash * Docs and warnings * Test ledger::slash * save progress * Introduce counter for delegators * Add tests for max delegator errors * Reproducible account ids * Adapt tests to new account id format * Simplify create_accounts api * Fix staking tests * Save PerBill slash impl before removing * Rever ledger slash test * Get node runtime to work * Organize sub pools by unbond era, not curren era * staking: Proportional ledger slashing * Some comment cleanup * Add more test post checks * Update frame/staking/src/pallet/mod.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Tests: account for storing unbond era * Improve docs for staking interface * Add events Created, Destroyed * withdraw_unbonded: Remove useless withdraw dust check * Test: withdraw_unbonded_other_handles_faulty_sub_pool_accounting * Add extrinsics: set_state_other, set_metadata * Test: set_state_other_works * Test: set_metadata_works * Add benchmarks for set_state_other, set_metadata * Fix benchmarks * Add weight info for new extrinsics * Some feedback * duo feedback * Incorporate some more feedback * integrate more kian feedback * integrate more kian feedback * More improvements * Add destroying_mul * Make do_reward_payout take refs * Remove some TODOs * Add test for saturating * feedback * Fix join test * use `inner` for nested types in nomination pools (#11030) * Use nested inner type for pool * make tests and benchmarks work * remove feat * all tests work now * fix node-runtime * nomination-pools: update benches for new account format (#11033) * Update benches to new account format * More sensible seeds * bring back rward account sanity check * Comment * Add extrinsic set_configs (#11038) * Better sanity checks for nomination pools (#11042) * new sanity checks, few other changes * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov * nomination-pools: Fix state event regression + benches (#11045) * new sanity checks, few other changes * Fix benches, improve sanity check * Remove useless clear storage in benchmarking * Set state * Save * Doc * Update frame/nomination-pools/src/lib.rs Co-authored-by: kianenigma * FMT * Try fill in all staking configs * Fix build * More changes to nomination pools (#11050) * new sanity checks, few other changes * some last touches as a whole * Apply suggestions from code review * Remove redundant event * Improve unbond_other error handling * Remove comment Co-authored-by: Zeke Mostov Co-authored-by: emostov <32168567+emostov@users.noreply.github.com> * Remove sanity module and some TODOs * round of feedback and imp from kian * Add TODO for ED QoL at reward pool creation * Make sure reward pool never gets dusted * Improve error type * demonstrate per_thing usage * Update sanity check & fix create_works * Improve test ext pool creation & fix some more tests * Try revert * Revert "Try revert" This reverts commit a6d1c9b920ad995fa8cdcbf6561b8db81c7a7783. * Revert "Improve test ext pool creation & fix some more tests" This reverts commit b410010ec4c9bc05410b62ebbba2a39d68d18c99. * Revert "Update sanity check & fix create_works" This reverts commit cdc2a32d22e6c00609bf496a5854b8f99f031156. Roll back reward account funding * Revert "Improve error type" This reverts commit f48cd379e608f98c70bd64a83fbc2e4530b115e1. * Revert "Make sure reward pool never gets dusted" This reverts commit 850cb3e80aa6462830bec7b545a434d0528ae774. revert * Update some tests * FMT * Test that era offset works correctly * Update mocks * Remove unnescary docs * Doc updates * Update calculate_delegator_payout_works_with_a_pool_of_1 * Fix test: claim_payout_works * do_reward_payout_correctly_sets_pool_state_to_destroying * Remove test do_reward_payout_errors_correctly * Fix test: do_reward_payout_works * Fix test: create_errors_correctly * Fix test: create works * Fix test: unbond_other_of_3_works * Ensure that ED is transferred into reward pool upon creation * WIP pool lifecycle test * Fix benchmarks * Add sanity check for ED + reward pools * `bond_extra` for nomination pools (#11100) * bond_extra for nomination pools * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov * add benchmarks * remove the min logic of bond_extra Co-authored-by: Zeke Mostov * FMT * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * make it compile end to end * Update some type viz * Update kick terminology * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/src/lib.rs * Cache bonded account when creating pool * Add bond extra weight stuff * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update docs for pool withdraw unbonded * Update docs for unbond * Improve Doc * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/Cargo.toml Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Improve Docs * Some docs improvements * fmt * Remove unlock_era * Fix accidental frame-support regression * Fix issue with transactions in tests * Fix doc links * Make sure result in test is used * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Fix can toggle state * Account for new_funds in ok to be open * Update docs: ok_to_withdraw_unbonded_other_with * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Remove some staking comments * Rename SubPoolsWithEra to UnbondingPoolsWithEra * Use validators length for benchmarks * Use metadata length for benchmarks * Remove debug assert eq * docs * Fix test: withdraw_unbonded_other_errors_correctly * Fix check for having enough balance to create the pool * Bond event for pool creation * Ok to be open * FMT * Remove _other postfix * Update frame/staking/src/lib.rs * Adjust tests to account for only remove when < ED * Remove stale TODOs * Remove dupe test * Fix build * Make sure to convert to u256 so we don't saturate * Refund depositor with reward pool fee * FMT * Remove reachable defensive * Use compact encoding for relevant extrinsics * Remove unnescary make_free_be for cleaning reward account * Add not to maintainers for reward account accounting * Remove note to maintainers from public doc * Make sure all configs have currency balance * Avoid saturation in balance_to_unbond * Partial Unbonding for Nomination Pools (#11212) * first draft of partial unbonding for pools * remove option * Add some more tests and fix issues * Fix all tests * simplify some tests * Update frame/nomination-pools/src/mock.rs * remove clone * rename to delegator_unbonding_eras * Update frame/nomination-pools/src/tests.rs Co-authored-by: Zeke Mostov * Update frame/nomination-pools/src/tests.rs Co-authored-by: Zeke Mostov * Update frame/nomination-pools/src/tests.rs Co-authored-by: Zeke Mostov * remove pub * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov * undo * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov * leftovers * fix invariant * Fix the depositor assumption * round of self-review * little bit more cleanup * Update frame/nomination-pools/src/mock.rs * Apply suggestions from code review * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov * Fix interpretation of MinCreateBond * controvesial refactor * rename * make everything build * add TODO about killing the reward account * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov * Update frame/nomination-pools/src/lib.rs * last self-review Co-authored-by: Zeke Mostov * Update Cargo.lock * Rename Delegator to PoolMember * fmt * Get runtime to build with runtime-benchmarks feature * Update Cargo.lock * Fix asserts to work in more scenarios * gte not gt * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/staking/src/mock.rs * Update frame/nomination-pools/src/lib.rs * Update frame/staking/src/slashing.rs * Apply suggestions from code review * fmt * Fix some tests Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Parity Bot Co-authored-by: kianenigma Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi --- Cargo.lock | 42 + Cargo.toml | 2 + bin/node/cli/src/chain_spec.rs | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 39 +- bin/node/testing/src/genesis.rs | 1 + frame/bags-list/src/benchmarks.rs | 12 +- frame/nomination-pools/Cargo.toml | 44 + .../nomination-pools/benchmarking/Cargo.toml | 55 + frame/nomination-pools/benchmarking/README.md | 0 .../nomination-pools/benchmarking/src/lib.rs | 639 ++++ .../nomination-pools/benchmarking/src/mock.rs | 200 ++ frame/nomination-pools/src/lib.rs | 2217 +++++++++++++ frame/nomination-pools/src/mock.rs | 309 ++ frame/nomination-pools/src/tests.rs | 2929 +++++++++++++++++ frame/nomination-pools/src/weights.rs | 482 +++ frame/staking/Cargo.toml | 1 + frame/staking/src/benchmarking.rs | 2 +- frame/staking/src/lib.rs | 12 + frame/staking/src/mock.rs | 2 +- frame/staking/src/pallet/impls.rs | 71 +- frame/staking/src/pallet/mod.rs | 2 +- frame/support/src/lib.rs | 21 + .../support/src/storage/bounded_btree_map.rs | 8 + frame/support/src/traits/misc.rs | 13 +- primitives/staking/Cargo.toml | 1 + primitives/staking/src/lib.rs | 80 +- 27 files changed, 7174 insertions(+), 15 deletions(-) create mode 100644 frame/nomination-pools/Cargo.toml create mode 100644 frame/nomination-pools/benchmarking/Cargo.toml create mode 100644 frame/nomination-pools/benchmarking/README.md create mode 100644 frame/nomination-pools/benchmarking/src/lib.rs create mode 100644 frame/nomination-pools/benchmarking/src/mock.rs create mode 100644 frame/nomination-pools/src/lib.rs create mode 100644 frame/nomination-pools/src/mock.rs create mode 100644 frame/nomination-pools/src/tests.rs create mode 100644 frame/nomination-pools/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index eeca5975a6f2d..596b737e22d09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5027,6 +5027,8 @@ dependencies = [ "pallet-membership", "pallet-mmr", "pallet-multisig", + "pallet-nomination-pools", + "pallet-nomination-pools-benchmarking", "pallet-offences", "pallet-offences-benchmarking", "pallet-preimage", @@ -6182,6 +6184,46 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-nomination-pools" +version = "1.0.0" +dependencies = [ + "frame-support", + "frame-system", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", + "sp-tracing", +] + +[[package]] +name = "pallet-nomination-pools-benchmarking" +version = "1.0.0" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "pallet-bags-list", + "pallet-balances", + "pallet-nomination-pools", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + [[package]] name = "pallet-offences" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 5cc90ec6f183b..f91e6226ccfd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,6 +109,8 @@ members = [ "frame/offences", "frame/preimage", "frame/proxy", + "frame/nomination-pools", + "frame/nomination-pools/benchmarking", "frame/randomness-collective-flip", "frame/recovery", "frame/referenda", diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 1212d3b3d07ed..221c229876275 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -363,6 +363,7 @@ pub fn testnet_genesis( gilt: Default::default(), transaction_storage: Default::default(), transaction_payment: Default::default(), + nomination_pools: Default::default(), } } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 847530e5c61bc..09f7534e7f521 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -76,6 +76,8 @@ pallet-lottery = { version = "4.0.0-dev", default-features = false, path = "../. pallet-membership = { version = "4.0.0-dev", default-features = false, path = "../../../frame/membership" } pallet-mmr = { version = "4.0.0-dev", default-features = false, path = "../../../frame/merkle-mountain-range" } pallet-multisig = { version = "4.0.0-dev", default-features = false, path = "../../../frame/multisig" } +pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../../../frame/nomination-pools"} +pallet-nomination-pools-benchmarking = { version = "1.0.0", default-features = false, optional = true, path = "../../../frame/nomination-pools/benchmarking" } pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../../frame/offences" } pallet-offences-benchmarking = { version = "4.0.0-dev", path = "../../../frame/offences/benchmarking", default-features = false, optional = true } pallet-preimage = { version = "4.0.0-dev", default-features = false, path = "../../../frame/preimage" } @@ -140,6 +142,7 @@ std = [ "pallet-membership/std", "pallet-mmr/std", "pallet-multisig/std", + "pallet-nomination-pools/std", "pallet-identity/std", "pallet-scheduler/std", "node-primitives/std", @@ -210,6 +213,7 @@ runtime-benchmarks = [ "pallet-membership/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-nomination-pools-benchmarking", "pallet-offences-benchmarking", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f073482d887bd..54101cc222f84 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -561,7 +561,7 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = onchain::UnboundedExecution; type VoterList = BagsList; type MaxUnlockingChunks = ConstU32<32>; - type OnStakerSlash = (); + type OnStakerSlash = NominationPools; type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; } @@ -705,6 +705,38 @@ impl pallet_bags_list::Config for Runtime { type Score = VoteWeight; } +parameter_types! { + pub const PostUnbondPoolsWindow: u32 = 4; + pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/npols"); +} + +use sp_runtime::traits::Convert; +pub struct BalanceToU256; +impl Convert for BalanceToU256 { + fn convert(balance: Balance) -> sp_core::U256 { + sp_core::U256::from(balance) + } +} +pub struct U256ToBalance; +impl Convert for U256ToBalance { + fn convert(n: sp_core::U256) -> Balance { + n.try_into().unwrap_or(Balance::max_value()) + } +} + +impl pallet_nomination_pools::Config for Runtime { + type WeightInfo = (); + type Event = Event; + type Currency = Balances; + type BalanceToU256 = BalanceToU256; + type U256ToBalance = U256ToBalance; + type StakingInterface = pallet_staking::Pallet; + type PostUnbondingPoolsWindow = PostUnbondPoolsWindow; + type MaxMetadataLen = ConstU32<256>; + type MaxUnbonding = ConstU32<8>; + type PalletId = NominationPoolsPalletId; +} + parameter_types! { pub const VoteLockingPeriod: BlockNumber = 30 * DAYS; } @@ -1470,6 +1502,7 @@ construct_runtime!( Remark: pallet_remark, ConvictionVoting: pallet_conviction_voting, Whitelist: pallet_whitelist, + NominationPools: pallet_nomination_pools, } ); @@ -1554,6 +1587,7 @@ mod benches { [pallet_membership, TechnicalMembership] [pallet_mmr, Mmr] [pallet_multisig, Multisig] + [pallet_nomination_pools, NominationPoolsBench::] [pallet_offences, OffencesBench::] [pallet_preimage, Preimage] [pallet_proxy, Proxy] @@ -1869,6 +1903,7 @@ impl_runtime_apis! { use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; use baseline::Pallet as BaselineBench; + use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -1891,12 +1926,14 @@ impl_runtime_apis! { use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; use baseline::Pallet as BaselineBench; + use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; impl pallet_session_benchmarking::Config for Runtime {} impl pallet_offences_benchmarking::Config for Runtime {} impl pallet_election_provider_support_benchmarking::Config for Runtime {} impl frame_system_benchmarking::Config for Runtime {} impl baseline::Config for Runtime {} + impl pallet_nomination_pools_benchmarking::Config for Runtime {} let whitelist: Vec = vec![ // Block Number diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index 8d2b53b0b7210..73e7ea50261d3 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -92,5 +92,6 @@ pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec) -> Gen gilt: Default::default(), transaction_storage: Default::default(), transaction_payment: Default::default(), + nomination_pools: Default::default(), } } diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index bcfd1e3392b0e..1a901c4d9d5a1 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -179,10 +179,10 @@ frame_benchmarking::benchmarks! { vec![heavier, lighter, heavier_prev, heavier_next] ) } -} -frame_benchmarking::impl_benchmark_test_suite!( - Pallet, - crate::mock::ExtBuilder::default().skip_genesis_ids().build(), - crate::mock::Runtime -); + impl_benchmark_test_suite!( + Pallet, + crate::mock::ExtBuilder::default().skip_genesis_ids().build(), + crate::mock::Runtime + ); +} diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml new file mode 100644 index 0000000000000..882a6f363a14f --- /dev/null +++ b/frame/nomination-pools/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "pallet-nomination-pools" +version = "1.0.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME nomination pools pallet" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +# parity +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } + +# FRAME +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } + +[dev-dependencies] +pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } + +[features] +runtime-benchmarks = [] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "sp-runtime/std", + "sp-std/std", + "sp-staking/std", + "sp-core/std", +] diff --git a/frame/nomination-pools/benchmarking/Cargo.toml b/frame/nomination-pools/benchmarking/Cargo.toml new file mode 100644 index 0000000000000..58158c20cf195 --- /dev/null +++ b/frame/nomination-pools/benchmarking/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "pallet-nomination-pools-benchmarking" +version = "1.0.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME nomination pools pallet benchmarking" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +# parity +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } + +# FRAME +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } +frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } +pallet-bags-list = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../bags-list" } +pallet-staking = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../staking" } +pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../", features = ["runtime-benchmarks"] } + +# Substrate Primitives +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } + +[dev-dependencies] +pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } +pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } +pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } + +[features] +default = ["std"] +std = [ + "frame-benchmarking/std", + "frame-election-provider-support/std", + "frame-support/std", + "frame-system/std", + "pallet-bags-list/std", + "pallet-staking/std", + "pallet-nomination-pools/std", + "sp-runtime/std", + "sp-staking/std", + "sp-std/std", + "pallet-balances/std", +] diff --git a/frame/nomination-pools/benchmarking/README.md b/frame/nomination-pools/benchmarking/README.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs new file mode 100644 index 0000000000000..7ae6338e6304a --- /dev/null +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -0,0 +1,639 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmarks for the nomination pools coupled with the staking and bags list pallets. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(test)] +mod mock; + +use frame_benchmarking::{account, frame_support::traits::Currency, vec, whitelist_account, Vec}; +use frame_election_provider_support::SortedListProvider; +use frame_support::{ensure, traits::Get}; +use frame_system::RawOrigin as Origin; +use pallet_nomination_pools::{ + BalanceOf, BondExtra, BondedPoolInner, BondedPools, ConfigOp, MaxPoolMembers, + MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, Pallet as Pools, + PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, +}; +use sp_runtime::traits::{Bounded, Zero}; +use sp_staking::{EraIndex, StakingInterface}; +// `frame_benchmarking::benchmarks!` macro needs this +use pallet_nomination_pools::Call; + +type CurrencyOf = ::Currency; + +const USER_SEED: u32 = 0; +const MAX_SPANS: u32 = 100; + +pub trait Config: + pallet_nomination_pools::Config + pallet_staking::Config + pallet_bags_list::Config +{ +} + +pub struct Pallet(Pools); + +fn create_funded_user_with_balance( + string: &'static str, + n: u32, + balance: BalanceOf, +) -> T::AccountId { + let user = account(string, n, USER_SEED); + T::Currency::make_free_balance_be(&user, balance); + user +} + +// Create a bonded pool account, bonding `balance` and giving the account `balance * 2` free +// balance. +fn create_pool_account( + n: u32, + balance: BalanceOf, +) -> (T::AccountId, T::AccountId) { + let ed = CurrencyOf::::minimum_balance(); + let pool_creator: T::AccountId = + create_funded_user_with_balance::("pool_creator", n, ed + balance * 2u32.into()); + + Pools::::create( + Origin::Signed(pool_creator.clone()).into(), + balance, + pool_creator.clone(), + pool_creator.clone(), + pool_creator.clone(), + ) + .unwrap(); + + let pool_account = pallet_nomination_pools::BondedPools::::iter() + .find(|(_, bonded_pool)| bonded_pool.roles.depositor == pool_creator) + .map(|(pool_id, _)| Pools::::create_bonded_account(pool_id)) + .expect("pool_creator created a pool above"); + + (pool_creator, pool_account) +} + +fn vote_to_balance( + vote: u64, +) -> Result, &'static str> { + vote.try_into().map_err(|_| "could not convert u64 to Balance") +} + +#[allow(unused)] +struct ListScenario { + /// Stash/Controller that is expected to be moved. + origin1: T::AccountId, + creator1: T::AccountId, + dest_weight: BalanceOf, + origin1_member: Option, +} + +impl ListScenario { + /// An expensive scenario for bags-list implementation: + /// + /// - the node to be updated (r) is the head of a bag that has at least one other node. The bag + /// itself will need to be read and written to update its head. The node pointed to by r.next + /// will need to be read and written as it will need to have its prev pointer updated. Note + /// that there are two other worst case scenarios for bag removal: 1) the node is a tail and + /// 2) the node is a middle node with prev and next; all scenarios end up with the same number + /// of storage reads and writes. + /// + /// - the destination bag has at least one node, which will need its next pointer updated. + pub(crate) fn new( + origin_weight: BalanceOf, + is_increase: bool, + ) -> Result { + ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0"); + + ensure!( + pallet_nomination_pools::MaxPools::::get().unwrap_or(0) >= 3, + "must allow at least three pools for benchmarks" + ); + + // Burn the entire issuance. + let i = CurrencyOf::::burn(CurrencyOf::::total_issuance()); + sp_std::mem::forget(i); + + // Create accounts with the origin weight + let (pool_creator1, pool_origin1) = create_pool_account::(USER_SEED + 1, origin_weight); + T::StakingInterface::nominate( + pool_origin1.clone(), + // NOTE: these don't really need to be validators. + vec![account("random_validator", 0, USER_SEED)], + )?; + + let (_, pool_origin2) = create_pool_account::(USER_SEED + 2, origin_weight); + T::StakingInterface::nominate( + pool_origin2.clone(), + vec![account("random_validator", 0, USER_SEED)].clone(), + )?; + + // Find a destination weight that will trigger the worst case scenario + let dest_weight_as_vote = ::VoterList::score_update_worst_case( + &pool_origin1, + is_increase, + ); + + let dest_weight: BalanceOf = + dest_weight_as_vote.try_into().map_err(|_| "could not convert u64 to Balance")?; + + // Create an account with the worst case destination weight + let (_, pool_dest1) = create_pool_account::(USER_SEED + 3, dest_weight); + T::StakingInterface::nominate( + pool_dest1.clone(), + vec![account("random_validator", 0, USER_SEED)], + )?; + + let weight_of = pallet_staking::Pallet::::weight_of_fn(); + assert_eq!(vote_to_balance::(weight_of(&pool_origin1)).unwrap(), origin_weight); + assert_eq!(vote_to_balance::(weight_of(&pool_origin2)).unwrap(), origin_weight); + assert_eq!(vote_to_balance::(weight_of(&pool_dest1)).unwrap(), dest_weight); + + Ok(ListScenario { + origin1: pool_origin1, + creator1: pool_creator1, + dest_weight, + origin1_member: None, + }) + } + + fn add_joiner(mut self, amount: BalanceOf) -> Self { + let amount = MinJoinBond::::get() + .max(CurrencyOf::::minimum_balance()) + // Max `amount` with minimum thresholds for account balance and joining a pool + // to ensure 1) the user can be created and 2) can join the pool + .max(amount); + + let joiner: T::AccountId = account("joiner", USER_SEED, 0); + self.origin1_member = Some(joiner.clone()); + CurrencyOf::::make_free_balance_be(&joiner, amount * 2u32.into()); + + let original_bonded = T::StakingInterface::active_stake(&self.origin1).unwrap(); + + // Unbond `amount` from the underlying pool account so when the member joins + // we will maintain `current_bonded`. + T::StakingInterface::unbond(self.origin1.clone(), amount) + .expect("the pool was created in `Self::new`."); + + // Account pool points for the unbonded balance. + BondedPools::::mutate(&1, |maybe_pool| { + maybe_pool.as_mut().map(|pool| pool.points -= amount) + }); + + Pools::::join(Origin::Signed(joiner.clone()).into(), amount, 1).unwrap(); + + // Sanity check that the vote weight is still the same as the original bonded + let weight_of = pallet_staking::Pallet::::weight_of_fn(); + assert_eq!(vote_to_balance::(weight_of(&self.origin1)).unwrap(), original_bonded); + + // Sanity check the member was added correctly + let member = PoolMembers::::get(&joiner).unwrap(); + assert_eq!(member.points, amount); + assert_eq!(member.pool_id, 1); + + self + } +} + +frame_benchmarking::benchmarks! { + join { + let origin_weight = pallet_nomination_pools::MinCreateBond::::get() + .max(CurrencyOf::::minimum_balance()) + * 2u32.into(); + + // setup the worst case list scenario. + let scenario = ListScenario::::new(origin_weight, true)?; + assert_eq!( + T::StakingInterface::active_stake(&scenario.origin1).unwrap(), + origin_weight + ); + + let max_additional = scenario.dest_weight.clone() - origin_weight; + let joiner_free = CurrencyOf::::minimum_balance() + max_additional; + + let joiner: T::AccountId + = create_funded_user_with_balance::("joiner", 0, joiner_free); + + whitelist_account!(joiner); + }: _(Origin::Signed(joiner.clone()), max_additional, 1) + verify { + assert_eq!(CurrencyOf::::free_balance(&joiner), joiner_free - max_additional); + assert_eq!( + T::StakingInterface::active_stake(&scenario.origin1).unwrap(), + scenario.dest_weight + ); + } + + bond_extra_transfer { + let origin_weight = pallet_nomination_pools::MinCreateBond::::get() + .max(CurrencyOf::::minimum_balance()) + * 2u32.into(); + let scenario = ListScenario::::new(origin_weight, true)?; + let extra = scenario.dest_weight.clone() - origin_weight; + + // creator of the src pool will bond-extra, bumping itself to dest bag. + + }: bond_extra(Origin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) + verify { + assert!( + T::StakingInterface::active_stake(&scenario.origin1).unwrap() >= + scenario.dest_weight + ); + } + + bond_extra_reward { + let origin_weight = pallet_nomination_pools::MinCreateBond::::get() + .max(CurrencyOf::::minimum_balance()) + * 2u32.into(); + let scenario = ListScenario::::new(origin_weight, true)?; + let extra = (scenario.dest_weight.clone() - origin_weight).max(CurrencyOf::::minimum_balance()); + + // transfer exactly `extra` to the depositor of the src pool (1), + let reward_account1 = Pools::::create_reward_account(1); + assert!(extra >= CurrencyOf::::minimum_balance()); + CurrencyOf::::deposit_creating(&reward_account1, extra); + + }: bond_extra(Origin::Signed(scenario.creator1.clone()), BondExtra::Rewards) + verify { + assert!( + T::StakingInterface::active_stake(&scenario.origin1).unwrap() >= + scenario.dest_weight + ); + } + + claim_payout { + let origin_weight = pallet_nomination_pools::MinCreateBond::::get().max(CurrencyOf::::minimum_balance()) * 2u32.into(); + let ed = CurrencyOf::::minimum_balance(); + let (depositor, pool_account) = create_pool_account::(0, origin_weight); + let reward_account = Pools::::create_reward_account(1); + + // Send funds to the reward account of the pool + CurrencyOf::::make_free_balance_be(&reward_account, ed + origin_weight); + + // Sanity check + assert_eq!( + CurrencyOf::::free_balance(&depositor), + origin_weight + ); + + whitelist_account!(depositor); + }:_(Origin::Signed(depositor.clone())) + verify { + assert_eq!( + CurrencyOf::::free_balance(&depositor), + origin_weight * 2u32.into() + ); + assert_eq!( + CurrencyOf::::free_balance(&reward_account), + ed + Zero::zero() + ); + } + + unbond { + // The weight the nominator will start at. The value used here is expected to be + // significantly higher than the first position in a list (e.g. the first bag threshold). + let origin_weight = BalanceOf::::try_from(952_994_955_240_703u128) + .map_err(|_| "balance expected to be a u128") + .unwrap(); + let scenario = ListScenario::::new(origin_weight, false)?; + let amount = origin_weight - scenario.dest_weight.clone(); + + let scenario = scenario.add_joiner(amount); + let member_id = scenario.origin1_member.unwrap().clone(); + let all_points = PoolMembers::::get(&member_id).unwrap().points; + whitelist_account!(member_id); + }: _(Origin::Signed(member_id.clone()), member_id.clone(), all_points) + verify { + let bonded_after = T::StakingInterface::active_stake(&scenario.origin1).unwrap(); + // We at least went down to the destination bag + assert!(bonded_after <= scenario.dest_weight.clone()); + let member = PoolMembers::::get( + &member_id + ) + .unwrap(); + assert_eq!( + member.unbonding_eras.keys().cloned().collect::>(), + vec![0 + T::StakingInterface::bonding_duration()] + ); + assert_eq!( + member.unbonding_eras.values().cloned().collect::>(), + vec![all_points] + ); + } + + pool_withdraw_unbonded { + let s in 0 .. MAX_SPANS; + + let min_create_bond = MinCreateBond::::get() + .max(T::StakingInterface::minimum_bond()) + .max(CurrencyOf::::minimum_balance()); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + + // Add a new member + let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); + let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); + Pools::::join(Origin::Signed(joiner.clone()).into(), min_join_bond, 1) + .unwrap(); + + // Sanity check join worked + assert_eq!( + T::StakingInterface::active_stake(&pool_account).unwrap(), + min_create_bond + min_join_bond + ); + assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); + + // Unbond the new member + Pools::::fully_unbond(Origin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); + + // Sanity check that unbond worked + assert_eq!( + T::StakingInterface::active_stake(&pool_account).unwrap(), + min_create_bond + ); + assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); + // Set the current era + pallet_staking::CurrentEra::::put(EraIndex::max_value()); + + // Add `s` count of slashing spans to storage. + pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); + whitelist_account!(pool_account); + }: _(Origin::Signed(pool_account.clone()), 1, s) + verify { + // The joiners funds didn't change + assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); + // The unlocking chunk was removed + assert_eq!(pallet_staking::Ledger::::get(pool_account).unwrap().unlocking.len(), 0); + } + + withdraw_unbonded_update { + let s in 0 .. MAX_SPANS; + + let min_create_bond = MinCreateBond::::get() + .max(T::StakingInterface::minimum_bond()) + .max(CurrencyOf::::minimum_balance()); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + + // Add a new member + let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); + let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); + Pools::::join(Origin::Signed(joiner.clone()).into(), min_join_bond, 1) + .unwrap(); + + // Sanity check join worked + assert_eq!( + T::StakingInterface::active_stake(&pool_account).unwrap(), + min_create_bond + min_join_bond + ); + assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); + + // Unbond the new member + pallet_staking::CurrentEra::::put(0); + Pools::::fully_unbond(Origin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); + + // Sanity check that unbond worked + assert_eq!( + T::StakingInterface::active_stake(&pool_account).unwrap(), + min_create_bond + ); + assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); + + // Set the current era to ensure we can withdraw unbonded funds + pallet_staking::CurrentEra::::put(EraIndex::max_value()); + + pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); + whitelist_account!(joiner); + }: withdraw_unbonded(Origin::Signed(joiner.clone()), joiner.clone(), s) + verify { + assert_eq!( + CurrencyOf::::free_balance(&joiner), + min_join_bond * 2u32.into() + ); + // The unlocking chunk was removed + assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 0); + } + + withdraw_unbonded_kill { + let s in 0 .. MAX_SPANS; + + let min_create_bond = MinCreateBond::::get() + .max(T::StakingInterface::minimum_bond()) + .max(CurrencyOf::::minimum_balance()); + + let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + + // We set the pool to the destroying state so the depositor can leave + BondedPools::::try_mutate(&1, |maybe_bonded_pool| { + maybe_bonded_pool.as_mut().ok_or(()).map(|bonded_pool| { + bonded_pool.state = PoolState::Destroying; + }) + }) + .unwrap(); + + // Unbond the creator + pallet_staking::CurrentEra::::put(0); + // Simulate some rewards so we can check if the rewards storage is cleaned up. We check this + // here to ensure the complete flow for destroying a pool works - the reward pool account + // should never exist by time the depositor withdraws so we test that it gets cleaned + // up when unbonding. + let reward_account = Pools::::create_reward_account(1); + assert!(frame_system::Account::::contains_key(&reward_account)); + Pools::::fully_unbond(Origin::Signed(depositor.clone()).into(), depositor.clone()).unwrap(); + + // Sanity check that unbond worked + assert_eq!( + T::StakingInterface::active_stake(&pool_account).unwrap(), + Zero::zero() + ); + assert_eq!( + CurrencyOf::::free_balance(&pool_account), + min_create_bond + ); + assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); + + // Set the current era to ensure we can withdraw unbonded funds + pallet_staking::CurrentEra::::put(EraIndex::max_value()); + + // Some last checks that storage items we expect to get cleaned up are present + assert!(pallet_staking::Ledger::::contains_key(&pool_account)); + assert!(BondedPools::::contains_key(&1)); + assert!(SubPoolsStorage::::contains_key(&1)); + assert!(RewardPools::::contains_key(&1)); + assert!(PoolMembers::::contains_key(&depositor)); + assert!(frame_system::Account::::contains_key(&reward_account)); + + whitelist_account!(depositor); + }: withdraw_unbonded(Origin::Signed(depositor.clone()), depositor.clone(), s) + verify { + // Pool removal worked + assert!(!pallet_staking::Ledger::::contains_key(&pool_account)); + assert!(!BondedPools::::contains_key(&1)); + assert!(!SubPoolsStorage::::contains_key(&1)); + assert!(!RewardPools::::contains_key(&1)); + assert!(!PoolMembers::::contains_key(&depositor)); + assert!(!frame_system::Account::::contains_key(&pool_account)); + assert!(!frame_system::Account::::contains_key(&reward_account)); + + // Funds where transferred back correctly + assert_eq!( + CurrencyOf::::free_balance(&depositor), + // gets bond back + rewards collecting when unbonding + min_create_bond * 2u32.into() + CurrencyOf::::minimum_balance() + ); + } + + create { + let min_create_bond = MinCreateBond::::get() + .max(T::StakingInterface::minimum_bond()) + .max(CurrencyOf::::minimum_balance()); + let depositor: T::AccountId = account("depositor", USER_SEED, 0); + + // Give the depositor some balance to bond + CurrencyOf::::make_free_balance_be(&depositor, min_create_bond * 2u32.into()); + + // Make sure no pools exist as a pre-condition for our verify checks + assert_eq!(RewardPools::::count(), 0); + assert_eq!(BondedPools::::count(), 0); + + whitelist_account!(depositor); + }: _( + Origin::Signed(depositor.clone()), + min_create_bond, + depositor.clone(), + depositor.clone(), + depositor.clone() + ) + verify { + assert_eq!(RewardPools::::count(), 1); + assert_eq!(BondedPools::::count(), 1); + let (_, new_pool) = BondedPools::::iter().next().unwrap(); + assert_eq!( + new_pool, + BondedPoolInner { + points: min_create_bond, + state: PoolState::Open, + member_counter: 1, + roles: PoolRoles { + depositor: depositor.clone(), + root: depositor.clone(), + nominator: depositor.clone(), + state_toggler: depositor.clone(), + }, + } + ); + assert_eq!( + T::StakingInterface::active_stake(&Pools::::create_bonded_account(1)), + Some(min_create_bond) + ); + } + + nominate { + let n in 1 .. T::MaxNominations::get(); + + // Create a pool + let min_create_bond = MinCreateBond::::get() + .max(T::StakingInterface::minimum_bond()) + .max(CurrencyOf::::minimum_balance()); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + + // Create some accounts to nominate. For the sake of benchmarking they don't need to be + // actual validators + let validators: Vec<_> = (0..n) + .map(|i| account("stash", USER_SEED, i)) + .collect(); + + whitelist_account!(depositor); + }:_(Origin::Signed(depositor.clone()), 1, validators) + verify { + assert_eq!(RewardPools::::count(), 1); + assert_eq!(BondedPools::::count(), 1); + let (_, new_pool) = BondedPools::::iter().next().unwrap(); + assert_eq!( + new_pool, + BondedPoolInner { + points: min_create_bond, + state: PoolState::Open, + member_counter: 1, + roles: PoolRoles { + depositor: depositor.clone(), + root: depositor.clone(), + nominator: depositor.clone(), + state_toggler: depositor.clone(), + } + } + ); + assert_eq!( + T::StakingInterface::active_stake(&Pools::::create_bonded_account(1)), + Some(min_create_bond) + ); + } + + set_state { + // Create a pool + let min_create_bond = MinCreateBond::::get() + .max(T::StakingInterface::minimum_bond()) + .max(CurrencyOf::::minimum_balance()); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + BondedPools::::mutate(&1, |maybe_pool| { + // Force the pool into an invalid state + maybe_pool.as_mut().map(|mut pool| pool.points = min_create_bond * 10u32.into()); + }); + + let caller = account("caller", 0, USER_SEED); + whitelist_account!(caller); + }:_(Origin::Signed(caller), 1, PoolState::Destroying) + verify { + assert_eq!(BondedPools::::get(1).unwrap().state, PoolState::Destroying); + } + + set_metadata { + let n in 1 .. ::MaxMetadataLen::get(); + + // Create a pool + let min_create_bond = MinCreateBond::::get() + .max(T::StakingInterface::minimum_bond()) + .max(CurrencyOf::::minimum_balance()); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + + // Create metadata of the max possible size + let metadata: Vec = (0..n).map(|_| 42).collect(); + + whitelist_account!(depositor); + }:_(Origin::Signed(depositor), 1, metadata.clone()) + verify { + assert_eq!(Metadata::::get(&1), metadata); + } + + set_configs { + }:_( + Origin::Root, + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(u32::MAX) + ) verify { + assert_eq!(MinJoinBond::::get(), BalanceOf::::max_value()); + assert_eq!(MinCreateBond::::get(), BalanceOf::::max_value()); + assert_eq!(MaxPools::::get(), Some(u32::MAX)); + assert_eq!(MaxPoolMembers::::get(), Some(u32::MAX)); + assert_eq!(MaxPoolMembersPerPool::::get(), Some(u32::MAX)); + } + + impl_benchmark_test_suite!( + Pallet, + crate::mock::new_test_ext(), + crate::mock::Runtime + ); +} diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs new file mode 100644 index 0000000000000..d98bcb542f514 --- /dev/null +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -0,0 +1,200 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_election_provider_support::VoteWeight; +use frame_support::{pallet_prelude::*, parameter_types, traits::ConstU64, PalletId}; +use sp_runtime::traits::{Convert, IdentityLookup}; + +type AccountId = u128; +type AccountIndex = u32; +type BlockNumber = u64; +type Balance = u128; + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = AccountIndex; + type BlockNumber = BlockNumber; + type Call = Call; + type Hash = sp_core::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = sp_runtime::testing::Header; + type Event = Event; + type BlockHashCount = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 10; +} +impl pallet_balances::Config for Runtime { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} + +pallet_staking_reward_curve::build! { + const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} +parameter_types! { + pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; +} +impl pallet_staking::Config for Runtime { + type MaxNominations = ConstU32<16>; + type Currency = Balances; + type CurrencyBalance = Balance; + type UnixTime = pallet_timestamp::Pallet; + type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; + type RewardRemainder = (); + type Event = Event; + type Slash = (); + type Reward = (); + type SessionsPerEra = (); + type SlashDeferDuration = (); + type SlashCancelOrigin = frame_system::EnsureRoot; + type BondingDuration = ConstU32<3>; + type SessionInterface = (); + type EraPayout = pallet_staking::ConvertCurve; + type NextNewSession = (); + type MaxNominatorRewardedPerValidator = ConstU32<64>; + type OffendingValidatorsThreshold = (); + type ElectionProvider = + frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking)>; + type GenesisElectionProvider = Self::ElectionProvider; + type VoterList = pallet_bags_list::Pallet; + type MaxUnlockingChunks = ConstU32<32>; + type OnStakerSlash = Pools; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type WeightInfo = (); +} + +parameter_types! { + pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; +} + +impl pallet_bags_list::Config for Runtime { + type Event = Event; + type WeightInfo = (); + type BagThresholds = BagThresholds; + type ScoreProvider = Staking; + type Score = VoteWeight; +} + +pub struct BalanceToU256; +impl Convert for BalanceToU256 { + fn convert(n: Balance) -> sp_core::U256 { + n.into() + } +} + +pub struct U256ToBalance; +impl Convert for U256ToBalance { + fn convert(n: sp_core::U256) -> Balance { + n.try_into().unwrap() + } +} + +parameter_types! { + pub static PostUnbondingPoolsWindow: u32 = 10; + pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); +} + +impl pallet_nomination_pools::Config for Runtime { + type Event = Event; + type WeightInfo = (); + type Currency = Balances; + type BalanceToU256 = BalanceToU256; + type U256ToBalance = U256ToBalance; + type StakingInterface = Staking; + type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; + type MaxMetadataLen = ConstU32<256>; + type MaxUnbonding = ConstU32<8>; + type PalletId = PoolsPalletId; +} + +impl crate::Config for Runtime {} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + Call: From, +{ + type OverarchingCall = Call; + type Extrinsic = UncheckedExtrinsic; +} + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system::{Pallet, Call, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, + BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, + Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event}, + } +); + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let _ = pallet_nomination_pools::GenesisConfig:: { + min_join_bond: 2, + min_create_bond: 2, + max_pools: Some(3), + max_members_per_pool: Some(3), + max_members: Some(3 * 3), + } + .assimilate_storage(&mut storage); + sp_io::TestExternalities::from(storage) +} diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs new file mode 100644 index 0000000000000..bafed9fc2f5b4 --- /dev/null +++ b/frame/nomination-pools/src/lib.rs @@ -0,0 +1,2217 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Nomination Pools for Staking Delegation +//! +//! A pallet that allows members to delegate their stake to nominating pools. A nomination pool +//! acts as nominator and nominates validators on the members behalf. +//! +//! # Index +//! +//! * [Key terms](#key-terms) +//! * [Usage](#usage) +//! * [Design](#design) +//! +//! ## Key terms +//! +//! * bonded pool: Tracks the distribution of actively staked funds. See [`BondedPool`] and +//! [`BondedPoolInner`]. Bonded pools are identified via the pools bonded account. +//! * reward pool: Tracks rewards earned by actively staked funds. See [`RewardPool`] and +//! [`RewardPools`]. Reward pools are identified via the pools bonded account. +//! * unbonding sub pools: Collection of pools at different phases of the unbonding lifecycle. See +//! [`SubPools`] and [`SubPoolsStorage`]. Sub pools are identified via the pools bonded account. +//! * members: Accounts that are members of pools. See [`PoolMember`] and [`PoolMembers`]. Pool +//! members are identified via their account. +//! * point: A unit of measure for a members portion of a pool's funds. +//! * kick: The act of a pool administrator forcibly ejecting a member. +//! +//! ## Usage +//! +//! ### Join +//! +//! A account can stake funds with a nomination pool by calling [`Call::join`]. +//! +//! ### Claim rewards +//! +//! After joining a pool, a member can claim rewards by calling [`Call::claim_payout`]. +//! +//! For design docs see the [reward pool](#reward-pool) section. +//! +//! ### Leave +//! +//! In order to leave, a member must take two steps. +//! +//! First, they must call [`Call::unbond`]. The unbond other extrinsic will start the +//! unbonding process by unbonding all of the members funds. +//! +//! Second, once [`sp_staking::StakingInterface::bonding_duration`] eras have passed, the member +//! can call [`Call::withdraw_unbonded`] to withdraw all their funds. +//! +//! For design docs see the [bonded pool](#bonded-pool) and [unbonding sub +//! pools](#unbonding-sub-pools) sections. +//! +//! ### Slashes +//! +//! Slashes are distributed evenly across the bonded pool and the unbonding pools from slash era+1 +//! through the slash apply era. Thus, any member who either a) unbonded or b) was actively +//! bonded in the aforementioned range of eras will be affected by the slash. A member is slashed +//! pro-rata based on its stake relative to the total slash amount. +//! +//! For design docs see the [slashing](#slashing) section. +//! +//! ### Administration +//! +//! A pool can be created with the [`Call::create`] call. Once created, the pools nominator or root +//! user must call [`Call::nominate`] to start nominating. [`Call::nominate`] can be called at +//! anytime to update validator selection. +//! +//! To help facilitate pool administration the pool has one of three states (see [`PoolState`]): +//! +//! * Open: Anyone can join the pool and no members can be permissionlessly removed. +//! * Blocked: No members can join and some admin roles can kick members. +//! * Destroying: No members can join and all members can be permissionlessly removed with +//! [`Call::unbond`] and [`Call::withdraw_unbonded`]. Once a pool is in destroying state, it +//! cannot be reverted to another state. +//! +//! A pool has 3 administrative roles (see [`PoolRoles`]): +//! +//! * Depositor: creates the pool and is the initial member. They can only leave the pool once all +//! other members have left. Once they fully leave the pool is destroyed. +//! * Nominator: can select which validators the pool nominates. +//! * State-Toggler: can change the pools state and kick members if the pool is blocked. +//! * Root: can change the nominator, state-toggler, or itself and can perform any of the actions +//! the nominator or state-toggler can. +//! +//! ## Design +//! +//! _Notes_: this section uses pseudo code to explain general design and does not necessarily +//! reflect the exact implementation. Additionally, a working knowledge of `pallet-staking`'s api is +//! assumed. +//! +//! ### Goals +//! +//! * Maintain network security by upholding integrity of slashing events, sufficiently penalizing +//! members that where in the pool while it was backing a validator that got slashed. +//! * Maximize scalability in terms of member count. +//! +//! In order to maintain scalability, all operations are independent of the number of members. To +//! do this, delegation specific information is stored local to the member while the pool data +//! structures have bounded datum. +//! +//! ### Bonded pool +//! +//! A bonded pool nominates with its total balance, excluding that which has been withdrawn for +//! unbonding. The total points of a bonded pool are always equal to the sum of points of the +//! delegation members. A bonded pool tracks its points and reads its bonded balance. +//! +//! When a member joins a pool, `amount_transferred` is transferred from the members account +//! to the bonded pools account. Then the pool calls `staking::bond_extra(amount_transferred)` and +//! issues new points which are tracked by the member and added to the bonded pool's points. +//! +//! When the pool already has some balance, we want the value of a point before the transfer to +//! equal the value of a point after the transfer. So, when a member joins a bonded pool with a +//! given `amount_transferred`, we maintain the ratio of bonded balance to points such that: +//! +//! ```text +//! balance_after_transfer / points_after_transfer == balance_before_transfer / points_before_transfer; +//! ``` +//! +//! To achieve this, we issue points based on the following: +//! +//! ```text +//! points_issued = (points_before_transfer / balance_before_transfer) * amount_transferred; +//! ``` +//! +//! For new bonded pools we can set the points issued per balance arbitrarily. In this +//! implementation we use a 1 points to 1 balance ratio for pool creation (see +//! [`POINTS_TO_BALANCE_INIT_RATIO`]). +//! +//! **Relevant extrinsics:** +//! +//! * [`Call::create`] +//! * [`Call::join`] +//! +//! ### Reward pool +//! +//! When a pool is first bonded it sets up an deterministic, inaccessible account as its reward +//! destination. To track staking rewards we track how the balance of this reward account changes. +//! +//! The reward pool needs to store: +//! +//! * The pool balance at the time of the last payout: `reward_pool.balance` +//! * The total earnings ever at the time of the last payout: `reward_pool.total_earnings` +//! * The total points in the pool at the time of the last payout: `reward_pool.points` +//! +//! And the member needs to store: +//! +//! * The total payouts at the time of the last payout by that member: +//! `member.reward_pool_total_earnings` +//! +//! Before the first reward claim is initiated for a pool, all the above variables are set to zero. +//! +//! When a member initiates a claim, the following happens: +//! +//! 1) Compute the reward pool's total points and the member's virtual points in the reward pool +//! * First `current_total_earnings` is computed (`current_balance` is the free balance of the +//! reward pool at the beginning of these operations.) +//! ```text +//! current_total_earnings = +//! current_balance - reward_pool.balance + pool.total_earnings; +//! ``` +//! * Then the `current_points` is computed. Every balance unit that was added to the reward +//! pool since last time recorded means that the `pool.points` is increased by +//! `bonding_pool.total_points`. In other words, for every unit of balance that has been +//! earned by the reward pool, the reward pool points are inflated by `bonded_pool.points`. In +//! effect this allows each, single unit of balance (e.g. planck) to be divvied up pro-rata +//! among members based on points. +//! ```text +//! new_earnings = current_total_earnings - reward_pool.total_earnings; +//! current_points = reward_pool.points + bonding_pool.points * new_earnings; +//! ``` +//! * Finally, the`member_virtual_points` are computed: the product of the member's points in +//! the bonding pool and the total inflow of balance units since the last time the member +//! claimed rewards +//! ```text +//! new_earnings_since_last_claim = current_total_earnings - member.reward_pool_total_earnings; +//! member_virtual_points = member.points * new_earnings_since_last_claim; +//! ``` +//! 2) Compute the `member_payout`: +//! ```text +//! member_pool_point_ratio = member_virtual_points / current_points; +//! member_payout = current_balance * member_pool_point_ratio; +//! ``` +//! 3) Transfer `member_payout` to the member +//! 4) For the member set: +//! ```text +//! member.reward_pool_total_earnings = current_total_earnings; +//! ``` +//! 5) For the pool set: +//! ```text +//! reward_pool.points = current_points - member_virtual_points; +//! reward_pool.balance = current_balance - member_payout; +//! reward_pool.total_earnings = current_total_earnings; +//! ``` +//! +//! _Note_: One short coming of this design is that new joiners can claim rewards for the era after +//! they join even though their funds did not contribute to the pools vote weight. When a +//! member joins, it's `reward_pool_total_earnings` field is set equal to the `total_earnings` +//! of the reward pool at that point in time. At best the reward pool has the rewards up through the +//! previous era. If a member joins prior to the election snapshot it will benefit from the +//! rewards for the active era despite not contributing to the pool's vote weight. If it joins +//! after the election snapshot is taken it will benefit from the rewards of the next _2_ eras +//! because it's vote weight will not be counted until the election snapshot in active era + 1. +//! Related: +// _Note to maintainers_: In order to ensure the reward account never falls below the existential +// deposit, at creation the reward account must be endowed with the existential deposit. All logic +// for calculating rewards then does not see that existential deposit as part of the free balance. +// See `RewardPool::current_balance`. +//! +//! **Relevant extrinsics:** +//! +//! * [`Call::claim_payout`] +//! +//! ### Unbonding sub pools +//! +//! When a member unbonds, it's balance is unbonded in the bonded pool's account and tracked in +//! an unbonding pool associated with the active era. If no such pool exists, one is created. To +//! track which unbonding sub pool a member belongs too, a member tracks it's +//! `unbonding_era`. +//! +//! When a member initiates unbonding it's claim on the bonded pool +//! (`balance_to_unbond`) is computed as: +//! +//! ```text +//! balance_to_unbond = (bonded_pool.balance / bonded_pool.points) * member.points; +//! ``` +//! +//! If this is the first transfer into an unbonding pool arbitrary amount of points can be issued +//! per balance. In this implementation unbonding pools are initialized with a 1 point to 1 balance +//! ratio (see [`POINTS_TO_BALANCE_INIT_RATIO`]). Otherwise, the unbonding pools hold the same +//! points to balance ratio properties as the bonded pool, so member points in the +//! unbonding pool are issued based on +//! +//! ```text +//! new_points_issued = (points_before_transfer / balance_before_transfer) * balance_to_unbond; +//! ``` +//! +//! For scalability, a bound is maintained on the number of unbonding sub pools (see +//! [`TotalUnbondingPools`]). An unbonding pool is removed once its older than `current_era - +//! TotalUnbondingPools`. An unbonding pool is merged into the unbonded pool with +//! +//! ```text +//! unbounded_pool.balance = unbounded_pool.balance + unbonding_pool.balance; +//! unbounded_pool.points = unbounded_pool.points + unbonding_pool.points; +//! ``` +//! +//! This scheme "averages" out the points value in the unbonded pool. +//! +//! Once a members `unbonding_era` is older than `current_era - +//! [sp_staking::StakingInterface::bonding_duration]`, it can can cash it's points out of the +//! corresponding unbonding pool. If it's `unbonding_era` is older than `current_era - +//! TotalUnbondingPools`, it can cash it's points from the unbonded pool. +//! +//! **Relevant extrinsics:** +//! +//! * [`Call::unbond`] +//! * [`Call::withdraw_unbonded`] +//! +//! ### Slashing +//! +//! This section assumes that the slash computation is executed by +//! `pallet_staking::StakingLedger::slash`, which passes the information to this pallet via +//! [`sp_staking::OnStakerSlash::on_slash`]. +//! +//! Unbonding pools need to be slashed to ensure all nominators whom where in the bonded pool +//! while it was backing a validator that equivocated are punished. Without these measures a +//! member could unbond right after a validator equivocated with no consequences. +//! +//! This strategy is unfair to members who joined after the slash, because they get slashed as +//! well, but spares members who unbond. The latter is much more important for security: if a +//! pool's validators are attacking the network, their members need to unbond fast! Avoiding +//! slashes gives them an incentive to do that if validators get repeatedly slashed. +//! +//! To be fair to joiners, this implementation also need joining pools, which are actively staking, +//! in addition to the unbonding pools. For maintenance simplicity these are not implemented. +//! Related: +//! +//! **Relevant methods:** +//! +//! * [`Pallet::on_slash`] +//! +//! ### Limitations +//! +//! * PoolMembers cannot vote with their staked funds because they are transferred into the pools +//! account. In the future this can be overcome by allowing the members to vote with their bonded +//! funds via vote splitting. +//! * PoolMembers cannot quickly transfer to another pool if they do no like nominations, instead +//! they must wait for the unbonding duration. +//! +//! # Runtime builder warnings +//! +//! * Watch out for overflow of [`RewardPoints`] and [`BalanceOf`] types. Consider things like the +//! chains total issuance, staking reward rate, and burn rate. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; +use frame_support::{ + defensive, ensure, + pallet_prelude::{MaxEncodedLen, *}, + storage::bounded_btree_map::BoundedBTreeMap, + traits::{ + Currency, Defensive, DefensiveOption, DefensiveResult, DefensiveSaturating, + ExistenceRequirement, Get, + }, + CloneNoBound, DefaultNoBound, PartialEqNoBound, RuntimeDebugNoBound, +}; +use scale_info::TypeInfo; +use sp_core::U256; +use sp_runtime::traits::{AccountIdConversion, Bounded, CheckedSub, Convert, Saturating, Zero}; +use sp_staking::{EraIndex, OnStakerSlash, StakingInterface}; +use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec}; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +pub mod weights; + +pub use pallet::*; +pub use weights::WeightInfo; + +/// The balance type used by the currency system. +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; +/// Type used to track the points of a reward pool. +pub type RewardPoints = U256; +/// Type used for unique identifier of each pool. +pub type PoolId = u32; + +type UnbondingPoolsWithEra = BoundedBTreeMap, TotalUnbondingPools>; + +pub const POINTS_TO_BALANCE_INIT_RATIO: u32 = 1; + +/// Possible operations on the configuration values of this pallet. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound, PartialEq, Clone)] +pub enum ConfigOp { + /// Don't change. + Noop, + /// Set the given value. + Set(T), + /// Remove from storage. + Remove, +} + +/// The type of bonding that can happen to a pool. +enum BondType { + /// Someone is bonding into the pool upon creation. + Create, + /// Someone is adding more funds later to this pool. + Later, +} + +/// How to increase the bond of a member. +#[derive(Encode, Decode, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] +pub enum BondExtra { + /// Take from the free balance. + FreeBalance(Balance), + /// Take the entire amount from the accumulated rewards. + Rewards, +} + +/// The type of account being created. +#[derive(Encode, Decode)] +enum AccountType { + Bonded, + Reward, +} + +/// A member in a pool. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound, CloneNoBound)] +#[cfg_attr(feature = "std", derive(PartialEqNoBound, DefaultNoBound))] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub struct PoolMember { + /// The identifier of the pool to which `who` belongs. + pub pool_id: PoolId, + /// The quantity of points this member has in the bonded pool or in a sub pool if + /// `Self::unbonding_era` is some. + pub points: BalanceOf, + /// The reward pools total earnings _ever_ the last time this member claimed a payout. + /// Assuming no massive burning events, we expect this value to always be below total issuance. + /// This value lines up with the [`RewardPool::total_earnings`] after a member claims a + /// payout. + pub reward_pool_total_earnings: BalanceOf, + /// The eras in which this member is unbonding, mapped from era index to the number of + /// points scheduled to unbond in the given era. + pub unbonding_eras: BoundedBTreeMap, T::MaxUnbonding>, +} + +impl PoolMember { + #[cfg(any(test, debug_assertions))] + fn total_points(&self) -> BalanceOf { + self.active_points().saturating_add(self.unbonding_points()) + } + + /// Active balance of the member. + /// + /// This is derived from the ratio of points in the pool to which the member belongs to. + /// Might return different values based on the pool state for the same member and points. + pub(crate) fn active_balance(&self) -> BalanceOf { + if let Some(pool) = BondedPool::::get(self.pool_id).defensive() { + pool.points_to_balance(self.points) + } else { + Zero::zero() + } + } + + /// Active points of the member. + pub(crate) fn active_points(&self) -> BalanceOf { + self.points + } + + /// Inactive points of the member, waiting to be withdrawn. + pub(crate) fn unbonding_points(&self) -> BalanceOf { + self.unbonding_eras + .as_ref() + .iter() + .fold(BalanceOf::::zero(), |acc, (_, v)| acc.saturating_add(*v)) + } + + /// Try and unbond `points` from self, with the given target unbonding era. + /// + /// Returns `Ok(())` and updates `unbonding_eras` and `points` if success, `Err(_)` otherwise. + fn try_unbond( + &mut self, + points: BalanceOf, + unbonding_era: EraIndex, + ) -> Result<(), Error> { + if let Some(new_points) = self.points.checked_sub(&points) { + match self.unbonding_eras.get_mut(&unbonding_era) { + Some(already_unbonding_points) => + *already_unbonding_points = already_unbonding_points.saturating_add(points), + None => self + .unbonding_eras + .try_insert(unbonding_era, points) + .map(|old| { + if old.is_some() { + defensive!("value checked to not exist in the map; qed"); + } + }) + .map_err(|_| Error::::MaxUnbondingLimit)?, + } + self.points = new_points; + Ok(()) + } else { + Err(Error::::NotEnoughPointsToUnbond) + } + } + + /// Withdraw any funds in [`Self::unbonding_eras`] who's deadline in reached and is fully + /// unlocked. + /// + /// Returns a a subset of [`Self::unbonding_eras`] that got withdrawn. + /// + /// Infallible, noop if no unbonding eras exist. + fn withdraw_unlocked( + &mut self, + current_era: EraIndex, + ) -> BoundedBTreeMap, T::MaxUnbonding> { + // NOTE: if only drain-filter was stable.. + let mut removed_points = + BoundedBTreeMap::, T::MaxUnbonding>::default(); + self.unbonding_eras.retain(|e, p| { + if *e > current_era { + true + } else { + removed_points + .try_insert(*e, p.clone()) + .expect("source map is bounded, this is a subset, will be bounded; qed"); + false + } + }); + removed_points + } +} + +/// A pool's possible states. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, RuntimeDebugNoBound, Clone, Copy)] +pub enum PoolState { + /// The pool is open to be joined, and is working normally. + Open, + /// The pool is blocked. No one else can join. + Blocked, + /// The pool is in the process of being destroyed. + /// + /// All members can now be permissionlessly unbonded, and the pool can never go back to any + /// other state other than being dissolved. + Destroying, +} + +/// Pool adminstration roles. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Debug, PartialEq, Clone)] +pub struct PoolRoles { + /// Creates the pool and is the initial member. They can only leave the pool once all + /// other members have left. Once they fully leave, the pool is destroyed. + pub depositor: AccountId, + /// Can change the nominator, state-toggler, or itself and can perform any of the actions + /// the nominator or state-toggler can. + pub root: AccountId, + /// Can select which validators the pool nominates. + pub nominator: AccountId, + /// Can change the pools state and kick members if the pool is blocked. + pub state_toggler: AccountId, +} + +/// Pool permissions and state +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, DebugNoBound, PartialEq, Clone)] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub struct BondedPoolInner { + /// Total points of all the members in the pool who are actively bonded. + pub points: BalanceOf, + /// The current state of the pool. + pub state: PoolState, + /// Count of members that belong to the pool. + pub member_counter: u32, + /// See [`PoolRoles`]. + pub roles: PoolRoles, +} + +/// A wrapper for bonded pools, with utility functions. +/// +/// The main purpose of this is to wrap a [`BondedPoolInner`], with the account + id of the pool, +/// for easier access. +#[derive(RuntimeDebugNoBound)] +#[cfg_attr(feature = "std", derive(Clone, PartialEq))] +pub struct BondedPool { + /// The identifier of the pool. + id: PoolId, + /// The inner fields. + inner: BondedPoolInner, +} + +impl sp_std::ops::Deref for BondedPool { + type Target = BondedPoolInner; + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl sp_std::ops::DerefMut for BondedPool { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl BondedPool { + /// Create a new bonded pool with the given roles and identifier. + fn new(id: PoolId, roles: PoolRoles) -> Self { + Self { + id, + inner: BondedPoolInner { + roles, + state: PoolState::Open, + points: Zero::zero(), + member_counter: Zero::zero(), + }, + } + } + + /// Get [`Self`] from storage. Returns `None` if no entry for `pool_account` exists. + fn get(id: PoolId) -> Option { + BondedPools::::try_get(id).ok().map(|inner| Self { id, inner }) + } + + /// Get the bonded account id of this pool. + fn bonded_account(&self) -> T::AccountId { + Pallet::::create_bonded_account(self.id) + } + + /// Get the reward account id of this pool. + fn reward_account(&self) -> T::AccountId { + Pallet::::create_reward_account(self.id) + } + + /// Consume self and put into storage. + fn put(self) { + BondedPools::::insert(self.id, BondedPoolInner { ..self.inner }); + } + + /// Consume self and remove from storage. + fn remove(self) { + BondedPools::::remove(self.id); + } + + /// Convert the given amount of balance to points given the current pool state. + /// + /// This is often used for bonding and issuing new funds into the pool. + fn balance_to_point(&self, new_funds: BalanceOf) -> BalanceOf { + let bonded_balance = + T::StakingInterface::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); + Pallet::::balance_to_point(bonded_balance, self.points, new_funds) + } + + /// Convert the given number of points to balance given the current pool state. + /// + /// This is often used for unbonding. + fn points_to_balance(&self, points: BalanceOf) -> BalanceOf { + let bonded_balance = + T::StakingInterface::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); + Pallet::::point_to_balance(bonded_balance, self.points, points) + } + + /// Issue points to [`Self`] for `new_funds`. + fn issue(&mut self, new_funds: BalanceOf) -> BalanceOf { + let points_to_issue = self.balance_to_point(new_funds); + self.points = self.points.saturating_add(points_to_issue); + points_to_issue + } + + /// Dissolve some points from the pool i.e. unbond the given amount of points from this pool. + /// This is the opposite of issuing some funds into the pool. + /// + /// Mutates self in place, but does not write anything to storage. + /// + /// Returns the equivalent balance amount that actually needs to get unbonded. + fn dissolve(&mut self, points: BalanceOf) -> BalanceOf { + // NOTE: do not optimize by removing `balance`. it must be computed before mutating + // `self.point`. + let balance = self.points_to_balance(points); + self.points = self.points.saturating_sub(points); + balance + } + + /// Increment the member counter. Ensures that the pool and system member limits are + /// respected. + fn try_inc_members(&mut self) -> Result<(), DispatchError> { + ensure!( + MaxPoolMembersPerPool::::get() + .map_or(true, |max_per_pool| self.member_counter < max_per_pool), + Error::::MaxPoolMembers + ); + ensure!( + MaxPoolMembers::::get().map_or(true, |max| PoolMembers::::count() < max), + Error::::MaxPoolMembers + ); + self.member_counter = self.member_counter.defensive_saturating_add(1); + Ok(()) + } + + /// Decrement the member counter. + fn dec_members(mut self) -> Self { + self.member_counter = self.member_counter.defensive_saturating_sub(1); + self + } + + /// The pools balance that is transferrable. + fn transferrable_balance(&self) -> BalanceOf { + let account = self.bonded_account(); + T::Currency::free_balance(&account) + .saturating_sub(T::StakingInterface::active_stake(&account).unwrap_or_default()) + } + + fn can_nominate(&self, who: &T::AccountId) -> bool { + *who == self.roles.root || *who == self.roles.nominator + } + + fn can_kick(&self, who: &T::AccountId) -> bool { + (*who == self.roles.root || *who == self.roles.state_toggler) && + self.state == PoolState::Blocked + } + + fn can_toggle_state(&self, who: &T::AccountId) -> bool { + (*who == self.roles.root || *who == self.roles.state_toggler) && !self.is_destroying() + } + + fn can_set_metadata(&self, who: &T::AccountId) -> bool { + *who == self.roles.root || *who == self.roles.state_toggler + } + + fn is_destroying(&self) -> bool { + matches!(self.state, PoolState::Destroying) + } + + fn is_destroying_and_only_depositor(&self, alleged_depositor_points: BalanceOf) -> bool { + // NOTE: if we add `&& self.member_counter == 1`, then this becomes even more strict and + // ensures that there are no unbonding members hanging around either. + self.is_destroying() && self.points == alleged_depositor_points + } + + /// Whether or not the pool is ok to be in `PoolSate::Open`. If this returns an `Err`, then the + /// pool is unrecoverable and should be in the destroying state. + fn ok_to_be_open(&self, new_funds: BalanceOf) -> Result<(), DispatchError> { + ensure!(!self.is_destroying(), Error::::CanNotChangeState); + + let bonded_balance = + T::StakingInterface::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); + ensure!(!bonded_balance.is_zero(), Error::::OverflowRisk); + + let points_to_balance_ratio_floor = self + .points + // We checked for zero above + .div(bonded_balance); + + // Pool points can inflate relative to balance, but only if the pool is slashed. + // If we cap the ratio of points:balance so one cannot join a pool that has been slashed + // 90%, + ensure!(points_to_balance_ratio_floor < 10u32.into(), Error::::OverflowRisk); + // while restricting the balance to 1/10th of max total issuance, + let next_bonded_balance = bonded_balance.saturating_add(new_funds); + ensure!( + next_bonded_balance < BalanceOf::::max_value().div(10u32.into()), + Error::::OverflowRisk + ); + // then we can be decently confident the bonding pool points will not overflow + // `BalanceOf`. Note that these are just heuristics. + + Ok(()) + } + + /// Check that the pool can accept a member with `new_funds`. + fn ok_to_join(&self, new_funds: BalanceOf) -> Result<(), DispatchError> { + ensure!(self.state == PoolState::Open, Error::::NotOpen); + self.ok_to_be_open(new_funds)?; + Ok(()) + } + + fn ok_to_unbond_with( + &self, + caller: &T::AccountId, + target_account: &T::AccountId, + target_member: &PoolMember, + unbonding_points: BalanceOf, + ) -> Result<(), DispatchError> { + let is_permissioned = caller == target_account; + let is_depositor = *target_account == self.roles.depositor; + match (is_permissioned, is_depositor) { + // If the pool is blocked, then an admin with kicking permissions can remove a + // member. If the pool is being destroyed, anyone can remove a member + (false, false) => { + ensure!( + self.can_kick(caller) || self.is_destroying(), + Error::::NotKickerOrDestroying + ) + }, + // Any member who is not the depositor can always unbond themselves + (true, false) => (), + (_, true) => { + if self.is_destroying_and_only_depositor(target_member.active_points()) { + // if the pool is about to be destroyed, anyone can unbond the depositor, and + // they can fully unbond. + } else { + // only the depositor can partially unbond, and they can only unbond up to the + // threshold. + ensure!(is_permissioned, Error::::DoesNotHavePermission); + let balance_after_unbond = { + let new_depositor_points = + target_member.active_points().saturating_sub(unbonding_points); + let mut depositor_after_unbond = (*target_member).clone(); + depositor_after_unbond.points = new_depositor_points; + depositor_after_unbond.active_balance() + }; + ensure!( + balance_after_unbond >= MinCreateBond::::get(), + Error::::NotOnlyPoolMember + ); + } + }, + }; + Ok(()) + } + + /// # Returns + /// + /// * Ok(()) if [`Call::withdraw_unbonded`] can be called, `Err(DispatchError)` otherwise. + fn ok_to_withdraw_unbonded_with( + &self, + caller: &T::AccountId, + target_account: &T::AccountId, + target_member: &PoolMember, + sub_pools: &SubPools, + ) -> Result<(), DispatchError> { + if *target_account == self.roles.depositor { + ensure!( + sub_pools.sum_unbonding_points() == target_member.unbonding_points(), + Error::::NotOnlyPoolMember + ); + debug_assert_eq!(self.member_counter, 1, "only member must exist at this point"); + Ok(()) + } else { + // This isn't a depositor + let is_permissioned = caller == target_account; + ensure!( + is_permissioned || self.can_kick(caller) || self.is_destroying(), + Error::::NotKickerOrDestroying + ); + Ok(()) + } + } + + /// Bond exactly `amount` from `who`'s funds into this pool. + /// + /// If the bond type is `Create`, `StakingInterface::bond` is called, and `who` + /// is allowed to be killed. Otherwise, `StakingInterface::bond_extra` is called and `who` + /// cannot be killed. + /// + /// Returns `Ok(points_issues)`, `Err` otherwise. + fn try_bond_funds( + &mut self, + who: &T::AccountId, + amount: BalanceOf, + ty: BondType, + ) -> Result, DispatchError> { + // Cache the value + let bonded_account = self.bonded_account(); + T::Currency::transfer( + &who, + &bonded_account, + amount, + match ty { + BondType::Create => ExistenceRequirement::AllowDeath, + BondType::Later => ExistenceRequirement::KeepAlive, + }, + )?; + // We must calculate the points issued *before* we bond who's funds, else points:balance + // ratio will be wrong. + let points_issued = self.issue(amount); + + match ty { + BondType::Create => T::StakingInterface::bond( + bonded_account.clone(), + bonded_account, + amount, + self.reward_account(), + )?, + // The pool should always be created in such a way its in a state to bond extra, but if + // the active balance is slashed below the minimum bonded or the account cannot be + // found, we exit early. + BondType::Later => T::StakingInterface::bond_extra(bonded_account, amount)?, + } + + Ok(points_issued) + } + + /// If `n` saturates at it's upper bound, mark the pool as destroying. This is useful when a + /// number saturating indicates the pool can no longer correctly keep track of state. + fn bound_check(&mut self, n: U256) -> U256 { + if n == U256::max_value() { + self.set_state(PoolState::Destroying) + } + + n + } + + // Set the state of `self`, and deposit an event if the state changed. State should never be set + // directly in in order to ensure a state change event is always correctly deposited. + fn set_state(&mut self, state: PoolState) { + if self.state != state { + self.state = state; + Pallet::::deposit_event(Event::::StateChanged { + pool_id: self.id, + new_state: state, + }); + }; + } +} + +/// A reward pool. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound)] +#[cfg_attr(feature = "std", derive(Clone, PartialEq))] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub struct RewardPool { + /// The balance of this reward pool after the last claimed payout. + pub balance: BalanceOf, + /// The total earnings _ever_ of this reward pool after the last claimed payout. I.E. the sum + /// of all incoming balance through the pools life. + /// + /// NOTE: We assume this will always be less than total issuance and thus can use the runtimes + /// `Balance` type. However in a chain with a burn rate higher than the rate this increases, + /// this type should be bigger than `Balance`. + pub total_earnings: BalanceOf, + /// The total points of this reward pool after the last claimed payout. + pub points: RewardPoints, +} + +impl RewardPool { + /// Mutate the reward pool by updating the total earnings and current free balance. + fn update_total_earnings_and_balance(&mut self, id: PoolId) { + let current_balance = Self::current_balance(id); + // The earnings since the last time it was updated + let new_earnings = current_balance.saturating_sub(self.balance); + // The lifetime earnings of the of the reward pool + self.total_earnings = new_earnings.saturating_add(self.total_earnings); + self.balance = current_balance; + } + + /// Get a reward pool and update its total earnings and balance + fn get_and_update(id: PoolId) -> Option { + RewardPools::::get(id).map(|mut r| { + r.update_total_earnings_and_balance(id); + r + }) + } + + /// The current balance of the reward pool. Never access the reward pools free balance directly. + /// The existential deposit was not received as a reward, so the reward pool can not use it. + fn current_balance(id: PoolId) -> BalanceOf { + T::Currency::free_balance(&Pallet::::create_reward_account(id)) + .saturating_sub(T::Currency::minimum_balance()) + } +} + +/// An unbonding pool. This is always mapped with an era. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, DefaultNoBound, RuntimeDebugNoBound)] +#[cfg_attr(feature = "std", derive(Clone, PartialEq, Eq))] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub struct UnbondPool { + /// The points in this pool. + points: BalanceOf, + /// The funds in the pool. + balance: BalanceOf, +} + +impl UnbondPool { + fn balance_to_point(&self, new_funds: BalanceOf) -> BalanceOf { + Pallet::::balance_to_point(self.balance, self.points, new_funds) + } + + fn point_to_balance(&self, points: BalanceOf) -> BalanceOf { + Pallet::::point_to_balance(self.balance, self.points, points) + } + + /// Issue points and update the balance given `new_balance`. + fn issue(&mut self, new_funds: BalanceOf) { + self.points = self.points.saturating_add(self.balance_to_point(new_funds)); + self.balance = self.balance.saturating_add(new_funds); + } + + /// Dissolve some points from the unbonding pool, reducing the balance of the pool + /// proportionally. + /// + /// This is the opposite of `issue`. + /// + /// Returns the actual amount of `Balance` that was removed from the pool. + fn dissolve(&mut self, points: BalanceOf) -> BalanceOf { + let balance_to_unbond = self.point_to_balance(points); + self.points = self.points.saturating_sub(points); + self.balance = self.balance.saturating_sub(balance_to_unbond); + + balance_to_unbond + } +} + +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, DefaultNoBound, RuntimeDebugNoBound)] +#[cfg_attr(feature = "std", derive(Clone, PartialEq))] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub struct SubPools { + /// A general, era agnostic pool of funds that have fully unbonded. The pools + /// of `Self::with_era` will lazily be merged into into this pool if they are + /// older then `current_era - TotalUnbondingPools`. + no_era: UnbondPool, + /// Map of era in which a pool becomes unbonded in => unbond pools. + with_era: UnbondingPoolsWithEra, +} + +impl SubPools { + /// Merge the oldest `with_era` unbond pools into the `no_era` unbond pool. + /// + /// This is often used whilst getting the sub-pool from storage, thus it consumes and returns + /// `Self` for ergonomic purposes. + fn maybe_merge_pools(mut self, unbond_era: EraIndex) -> Self { + // Ex: if `TotalUnbondingPools` is 5 and current era is 10, we only want to retain pools + // 6..=10. Note that in the first few eras where `checked_sub` is `None`, we don't remove + // anything. + if let Some(newest_era_to_remove) = unbond_era.checked_sub(TotalUnbondingPools::::get()) + { + self.with_era.retain(|k, v| { + if *k > newest_era_to_remove { + // keep + true + } else { + // merge into the no-era pool + self.no_era.points = self.no_era.points.saturating_add(v.points); + self.no_era.balance = self.no_era.balance.saturating_add(v.balance); + false + } + }); + } + + self + } + + /// The sum of all unbonding points, regardless of whether they are actually unlocked or not. + fn sum_unbonding_points(&self) -> BalanceOf { + self.no_era.points.saturating_add( + self.with_era + .values() + .fold(BalanceOf::::zero(), |acc, pool| acc.saturating_add(pool.points)), + ) + } + + /// The sum of all unbonding balance, regardless of whether they are actually unlocked or not. + #[cfg(any(test, debug_assertions))] + fn sum_unbonding_balance(&self) -> BalanceOf { + self.no_era.balance.saturating_add( + self.with_era + .values() + .fold(BalanceOf::::zero(), |acc, pool| acc.saturating_add(pool.balance)), + ) + } +} + +/// The maximum amount of eras an unbonding pool can exist prior to being merged with the +/// `no_era` pool. This is guaranteed to at least be equal to the staking `UnbondingDuration`. For +/// improved UX [`Config::PostUnbondingPoolsWindow`] should be configured to a non-zero value. +pub struct TotalUnbondingPools(PhantomData); +impl Get for TotalUnbondingPools { + fn get() -> u32 { + // NOTE: this may be dangerous in the scenario bonding_duration gets decreased because + // we would no longer be able to decode `UnbondingPoolsWithEra`, which uses + // `TotalUnbondingPools` as the bound + T::StakingInterface::bonding_duration() + T::PostUnbondingPoolsWindow::get() + } +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::transactional; + use frame_system::{ensure_signed, pallet_prelude::*}; + + #[pallet::pallet] + #[pallet::generate_store(pub(crate) trait Store)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: weights::WeightInfo; + + /// The nominating balance. + type Currency: Currency; + + /// The nomination pool's pallet id. + #[pallet::constant] + type PalletId: Get; + + /// Infallible method for converting `Currency::Balance` to `U256`. + type BalanceToU256: Convert, U256>; + + /// Infallible method for converting `U256` to `Currency::Balance`. + type U256ToBalance: Convert>; + + /// The interface for nominating. + type StakingInterface: StakingInterface< + Balance = BalanceOf, + AccountId = Self::AccountId, + >; + + /// The amount of eras a `SubPools::with_era` pool can exist before it gets merged into the + /// `SubPools::no_era` pool. In other words, this is the amount of eras a member will be + /// able to withdraw from an unbonding pool which is guaranteed to have the correct ratio of + /// points to balance; once the `with_era` pool is merged into the `no_era` pool, the ratio + /// can become skewed due to some slashed ratio getting merged in at some point. + type PostUnbondingPoolsWindow: Get; + + /// The maximum length, in bytes, that a pools metadata maybe. + type MaxMetadataLen: Get; + + /// The maximum number of simultaneous unbonding chunks that can exist per member. + type MaxUnbonding: Get; + } + + /// Minimum amount to bond to join a pool. + #[pallet::storage] + pub type MinJoinBond = StorageValue<_, BalanceOf, ValueQuery>; + + /// Minimum bond required to create a pool. + /// + /// This is the amount that the depositor must put as their initial stake in the pool, as an + /// indication of "skin in the game". + #[pallet::storage] + pub type MinCreateBond = StorageValue<_, BalanceOf, ValueQuery>; + + /// Maximum number of nomination pools that can exist. If `None`, then an unbounded number of + /// pools can exist. + #[pallet::storage] + pub type MaxPools = StorageValue<_, u32, OptionQuery>; + + /// Maximum number of members that can exist in the system. If `None`, then the count + /// members are not bound on a system wide basis. + #[pallet::storage] + pub type MaxPoolMembers = StorageValue<_, u32, OptionQuery>; + + /// Maximum number of members that may belong to pool. If `None`, then the count of + /// members is not bound on a per pool basis. + #[pallet::storage] + pub type MaxPoolMembersPerPool = StorageValue<_, u32, OptionQuery>; + + /// Active members. + #[pallet::storage] + pub type PoolMembers = + CountedStorageMap<_, Twox64Concat, T::AccountId, PoolMember>; + + /// Storage for bonded pools. + // To get or insert a pool see [`BondedPool::get`] and [`BondedPool::put`] + #[pallet::storage] + pub type BondedPools = + CountedStorageMap<_, Twox64Concat, PoolId, BondedPoolInner>; + + /// Reward pools. This is where there rewards for each pool accumulate. When a members payout + /// is claimed, the balance comes out fo the reward pool. Keyed by the bonded pools account. + #[pallet::storage] + pub type RewardPools = CountedStorageMap<_, Twox64Concat, PoolId, RewardPool>; + + /// Groups of unbonding pools. Each group of unbonding pools belongs to a bonded pool, + /// hence the name sub-pools. Keyed by the bonded pools account. + #[pallet::storage] + pub type SubPoolsStorage = CountedStorageMap<_, Twox64Concat, PoolId, SubPools>; + + /// Metadata for the pool. + #[pallet::storage] + pub type Metadata = + CountedStorageMap<_, Twox64Concat, PoolId, BoundedVec, ValueQuery>; + + #[pallet::storage] + pub type LastPoolId = StorageValue<_, u32, ValueQuery>; + + #[pallet::storage] + pub type ReversePoolIdLookup = + CountedStorageMap<_, Twox64Concat, T::AccountId, PoolId, OptionQuery>; + + #[pallet::genesis_config] + pub struct GenesisConfig { + pub min_join_bond: BalanceOf, + pub min_create_bond: BalanceOf, + pub max_pools: Option, + pub max_members_per_pool: Option, + pub max_members: Option, + } + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + Self { + min_join_bond: Zero::zero(), + min_create_bond: Zero::zero(), + max_pools: Some(16), + max_members_per_pool: Some(32), + max_members: Some(16 * 32), + } + } + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + MinJoinBond::::put(self.min_join_bond); + MinCreateBond::::put(self.min_create_bond); + if let Some(max_pools) = self.max_pools { + MaxPools::::put(max_pools); + } + if let Some(max_members_per_pool) = self.max_members_per_pool { + MaxPoolMembersPerPool::::put(max_members_per_pool); + } + if let Some(max_members) = self.max_members { + MaxPoolMembers::::put(max_members); + } + } + } + + /// Events of this pallet. + #[pallet::event] + #[pallet::generate_deposit(pub(crate) fn deposit_event)] + pub enum Event { + /// A pool has been created. + Created { depositor: T::AccountId, pool_id: PoolId }, + /// A member has became bonded in a pool. + Bonded { member: T::AccountId, pool_id: PoolId, bonded: BalanceOf, joined: bool }, + /// A payout has been made to a member. + PaidOut { member: T::AccountId, pool_id: PoolId, payout: BalanceOf }, + /// A member has unbonded from their pool. + Unbonded { member: T::AccountId, pool_id: PoolId, amount: BalanceOf }, + /// A member has withdrawn from their pool. + Withdrawn { member: T::AccountId, pool_id: PoolId, amount: BalanceOf }, + /// A pool has been destroyed. + Destroyed { pool_id: PoolId }, + /// The state of a pool has changed + StateChanged { pool_id: PoolId, new_state: PoolState }, + } + + #[pallet::error] + #[cfg_attr(test, derive(PartialEq))] + pub enum Error { + /// A (bonded) pool id does not exist. + PoolNotFound, + /// An account is not a member. + PoolMemberNotFound, + /// A reward pool does not exist. In all cases this is a system logic error. + RewardPoolNotFound, + /// A sub pool does not exist. + SubPoolsNotFound, + /// An account is already delegating in another pool. An account may only belong to one + /// pool at a time. + AccountBelongsToOtherPool, + /// The pool has insufficient balance to bond as a nominator. + InsufficientBond, + /// The member is already unbonding in this era. + AlreadyUnbonding, + /// The member is fully unbonded (and thus cannot access the bonded and reward pool + /// anymore to, for example, collect rewards). + FullyUnbonding, + /// The member cannot unbond further chunks due to reaching the limit. + MaxUnbondingLimit, + /// None of the funds can be withdrawn yet because the bonding duration has not passed. + CannotWithdrawAny, + /// The amount does not meet the minimum bond to either join or create a pool. + MinimumBondNotMet, + /// The transaction could not be executed due to overflow risk for the pool. + OverflowRisk, + /// A pool must be in [`PoolState::Destroying`] in order for the depositor to unbond or for + /// other members to be permissionlessly unbonded. + NotDestroying, + /// The depositor must be the only member in the bonded pool in order to unbond. And the + /// depositor must be the only member in the sub pools in order to withdraw unbonded. + NotOnlyPoolMember, + /// The caller does not have nominating permissions for the pool. + NotNominator, + /// Either a) the caller cannot make a valid kick or b) the pool is not destroying. + NotKickerOrDestroying, + /// The pool is not open to join + NotOpen, + /// The system is maxed out on pools. + MaxPools, + /// Too many members in the pool or system. + MaxPoolMembers, + /// The pools state cannot be changed. + CanNotChangeState, + /// The caller does not have adequate permissions. + DoesNotHavePermission, + /// Metadata exceeds [`Config::MaxMetadataLen`] + MetadataExceedsMaxLen, + /// Some error occurred that should never happen. This should be reported to the + /// maintainers. + DefensiveError, + /// Not enough points. Ty unbonding less. + NotEnoughPointsToUnbond, + } + + #[pallet::call] + impl Pallet { + /// Stake funds with a pool. The amount to bond is transferred from the member to the + /// pools account and immediately increases the pools bond. + /// + /// # Note + /// + /// * An account can only be a member of a single pool. + /// * An account cannot join the same pool multiple times. + /// * This call will *not* dust the member account, so the member must have at least + /// `existential deposit + amount` in their account. + /// * Only a pool with [`PoolState::Open`] can be joined + #[pallet::weight(T::WeightInfo::join())] + #[transactional] + pub fn join( + origin: OriginFor, + #[pallet::compact] amount: BalanceOf, + pool_id: PoolId, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + ensure!(amount >= MinJoinBond::::get(), Error::::MinimumBondNotMet); + // If a member already exists that means they already belong to a pool + ensure!(!PoolMembers::::contains_key(&who), Error::::AccountBelongsToOtherPool); + + let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + bonded_pool.ok_to_join(amount)?; + + // We just need its total earnings at this point in time, but we don't need to write it + // because we are not adjusting its points (all other values can calculated virtual). + let reward_pool = RewardPool::::get_and_update(pool_id) + .defensive_ok_or_else(|| Error::::RewardPoolNotFound)?; + + bonded_pool.try_inc_members()?; + let points_issued = bonded_pool.try_bond_funds(&who, amount, BondType::Later)?; + + PoolMembers::insert( + who.clone(), + PoolMember:: { + pool_id, + points: points_issued, + // At best the reward pool has the rewards up through the previous era. If the + // member joins prior to the snapshot they will benefit from the rewards of + // the active era despite not contributing to the pool's vote weight. If they + // join after the snapshot is taken they will benefit from the rewards of the + // next 2 eras because their vote weight will not be counted until the + // snapshot in active era + 1. + reward_pool_total_earnings: reward_pool.total_earnings, + unbonding_eras: Default::default(), + }, + ); + + Self::deposit_event(Event::::Bonded { + member: who, + pool_id, + bonded: amount, + joined: true, + }); + bonded_pool.put(); + + Ok(()) + } + + /// Bond `extra` more funds from `origin` into the pool to which they already belong. + /// + /// Additional funds can come from either the free balance of the account, of from the + /// accumulated rewards, see [`BondExtra`]. + // NOTE: this transaction is implemented with the sole purpose of readability and + // correctness, not optimization. We read/write several storage items multiple times instead + // of just once, in the spirit reusing code. + #[pallet::weight( + T::WeightInfo::bond_extra_transfer() + .max(T::WeightInfo::bond_extra_reward()) + )] + #[transactional] + pub fn bond_extra(origin: OriginFor, extra: BondExtra>) -> DispatchResult { + let who = ensure_signed(origin)?; + let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&who)?; + + let (points_issued, bonded) = match extra { + BondExtra::FreeBalance(amount) => + (bonded_pool.try_bond_funds(&who, amount, BondType::Later)?, amount), + BondExtra::Rewards => { + let claimed = Self::do_reward_payout( + &who, + &mut member, + &mut bonded_pool, + &mut reward_pool, + )?; + (bonded_pool.try_bond_funds(&who, claimed, BondType::Later)?, claimed) + }, + }; + bonded_pool.ok_to_be_open(bonded)?; + member.points = member.points.saturating_add(points_issued); + + Self::deposit_event(Event::::Bonded { + member: who.clone(), + pool_id: member.pool_id, + bonded, + joined: false, + }); + Self::put_member_with_pools(&who, member, bonded_pool, reward_pool); + + Ok(()) + } + + /// A bonded member can use this to claim their payout based on the rewards that the pool + /// has accumulated since their last claimed payout (OR since joining if this is there first + /// time claiming rewards). The payout will be transferred to the member's account. + /// + /// The member will earn rewards pro rata based on the members stake vs the sum of the + /// members in the pools stake. Rewards do not "expire". + #[pallet::weight(T::WeightInfo::claim_payout())] + #[transactional] + pub fn claim_payout(origin: OriginFor) -> DispatchResult { + let who = ensure_signed(origin)?; + let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&who)?; + + let _ = Self::do_reward_payout(&who, &mut member, &mut bonded_pool, &mut reward_pool)?; + + Self::put_member_with_pools(&who, member, bonded_pool, reward_pool); + Ok(()) + } + + /// Unbond up to `unbonding_points` of the `member_account`'s funds from the pool. It + /// implicitly collects the rewards one last time, since not doing so would mean some + /// rewards would go forfeited. + /// + /// Under certain conditions, this call can be dispatched permissionlessly (i.e. by any + /// account). + /// + /// # Conditions for a permissionless dispatch. + /// + /// * The pool is blocked and the caller is either the root or state-toggler. This is + /// refereed to as a kick. + /// * The pool is destroying and the member is not the depositor. + /// * The pool is destroying, the member is the depositor and no other members are in the + /// pool. + /// + /// ## Conditions for permissioned dispatch (i.e. the caller is also the + /// `member_account`): + /// + /// * The caller is not the depositor. + /// * The caller is the depositor, the pool is destroying and no other members are in the + /// pool. + /// + /// # Note + /// + /// If there are too many unlocking chunks to unbond with the pool account, + /// [`Call::pool_withdraw_unbonded`] can be called to try and minimize unlocking chunks. If + /// there are too many unlocking chunks, the result of this call will likely be the + /// `NoMoreChunks` error from the staking system. + #[pallet::weight(T::WeightInfo::unbond())] + #[transactional] + pub fn unbond( + origin: OriginFor, + member_account: T::AccountId, + #[pallet::compact] unbonding_points: BalanceOf, + ) -> DispatchResult { + let caller = ensure_signed(origin)?; + let (mut member, mut bonded_pool, mut reward_pool) = + Self::get_member_with_pools(&member_account)?; + + bonded_pool.ok_to_unbond_with(&caller, &member_account, &member, unbonding_points)?; + + // Claim the the payout prior to unbonding. Once the user is unbonding their points + // no longer exist in the bonded pool and thus they can no longer claim their payouts. + // It is not strictly necessary to claim the rewards, but we do it here for UX. + Self::do_reward_payout( + &member_account, + &mut member, + &mut bonded_pool, + &mut reward_pool, + )?; + + let current_era = T::StakingInterface::current_era(); + let unbond_era = T::StakingInterface::bonding_duration().saturating_add(current_era); + + // Try and unbond in the member map. + member.try_unbond(unbonding_points, unbond_era)?; + + // Unbond in the actual underlying nominator. + let unbonding_balance = bonded_pool.dissolve(unbonding_points); + T::StakingInterface::unbond(bonded_pool.bonded_account(), unbonding_balance)?; + + // Note that we lazily create the unbonding pools here if they don't already exist + let mut sub_pools = SubPoolsStorage::::get(member.pool_id) + .unwrap_or_default() + .maybe_merge_pools(unbond_era); + + // Update the unbond pool associated with the current era with the unbonded funds. Note + // that we lazily create the unbond pool if it does not yet exist. + if !sub_pools.with_era.contains_key(&unbond_era) { + sub_pools + .with_era + .try_insert(unbond_era, UnbondPool::default()) + // The above call to `maybe_merge_pools` should ensure there is + // always enough space to insert. + .defensive_map_err(|_| Error::::DefensiveError)?; + } + + sub_pools + .with_era + .get_mut(&unbond_era) + // The above check ensures the pool exists. + .defensive_ok_or_else(|| Error::::DefensiveError)? + .issue(unbonding_balance); + + Self::deposit_event(Event::::Unbonded { + member: member_account.clone(), + pool_id: member.pool_id, + amount: unbonding_balance, + }); + + // Now that we know everything has worked write the items to storage. + SubPoolsStorage::insert(&member.pool_id, sub_pools); + Self::put_member_with_pools(&member_account, member, bonded_pool, reward_pool); + + Ok(()) + } + + /// Call `withdraw_unbonded` for the pools account. This call can be made by any account. + /// + /// This is useful if their are too many unlocking chunks to call `unbond`, and some + /// can be cleared by withdrawing. In the case there are too many unlocking chunks, the user + /// would probably see an error like `NoMoreChunks` emitted from the staking system when + /// they attempt to unbond. + #[pallet::weight(T::WeightInfo::pool_withdraw_unbonded(*num_slashing_spans))] + #[transactional] + pub fn pool_withdraw_unbonded( + origin: OriginFor, + pool_id: PoolId, + num_slashing_spans: u32, + ) -> DispatchResult { + let _ = ensure_signed(origin)?; + let pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + // For now we only allow a pool to withdraw unbonded if its not destroying. If the pool + // is destroying then `withdraw_unbonded` can be used. + ensure!(pool.state != PoolState::Destroying, Error::::NotDestroying); + T::StakingInterface::withdraw_unbonded(pool.bonded_account(), num_slashing_spans)?; + Ok(()) + } + + /// Withdraw unbonded funds from `member_account`. If no bonded funds can be unbonded, an + /// error is returned. + /// + /// Under certain conditions, this call can be dispatched permissionlessly (i.e. by any + /// account). + /// + /// # Conditions for a permissionless dispatch + /// + /// * The pool is in destroy mode and the target is not the depositor. + /// * The target is the depositor and they are the only member in the sub pools. + /// * The pool is blocked and the caller is either the root or state-toggler. + /// + /// # Conditions for permissioned dispatch + /// + /// * The caller is the target and they are not the depositor. + /// + /// # Note + /// + /// If the target is the depositor, the pool will be destroyed. + #[pallet::weight( + T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans) + )] + #[transactional] + pub fn withdraw_unbonded( + origin: OriginFor, + member_account: T::AccountId, + num_slashing_spans: u32, + ) -> DispatchResultWithPostInfo { + let caller = ensure_signed(origin)?; + let mut member = + PoolMembers::::get(&member_account).ok_or(Error::::PoolMemberNotFound)?; + let current_era = T::StakingInterface::current_era(); + + let bonded_pool = BondedPool::::get(member.pool_id) + .defensive_ok_or_else(|| Error::::PoolNotFound)?; + let mut sub_pools = SubPoolsStorage::::get(member.pool_id) + .defensive_ok_or_else(|| Error::::SubPoolsNotFound)?; + + bonded_pool.ok_to_withdraw_unbonded_with( + &caller, + &member_account, + &member, + &sub_pools, + )?; + + // NOTE: must do this after we have done the `ok_to_withdraw_unbonded_other_with` check. + let withdrawn_points = member.withdraw_unlocked(current_era); + ensure!(!withdrawn_points.is_empty(), Error::::CannotWithdrawAny); + + // Before calculate the `balance_to_unbond`, with call withdraw unbonded to ensure the + // `transferrable_balance` is correct. + T::StakingInterface::withdraw_unbonded( + bonded_pool.bonded_account(), + num_slashing_spans, + )?; + + let balance_to_unbond = withdrawn_points + .iter() + .fold(BalanceOf::::zero(), |accumulator, (era, unlocked_points)| { + if let Some(era_pool) = sub_pools.with_era.get_mut(&era) { + let balance_to_unbond = era_pool.dissolve(*unlocked_points); + if era_pool.points.is_zero() { + sub_pools.with_era.remove(&era); + } + accumulator.saturating_add(balance_to_unbond) + } else { + // A pool does not belong to this era, so it must have been merged to the + // era-less pool. + accumulator.saturating_add(sub_pools.no_era.dissolve(*unlocked_points)) + } + }) + // A call to this function may cause the pool's stash to get dusted. If this happens + // before the last member has withdrawn, then all subsequent withdraws will be 0. + // However the unbond pools do no get updated to reflect this. In the aforementioned + // scenario, this check ensures we don't try to withdraw funds that don't exist. + // This check is also defensive in cases where the unbond pool does not update its + // balance (e.g. a bug in the slashing hook.) We gracefully proceed in order to + // ensure members can leave the pool and it can be destroyed. + .min(bonded_pool.transferrable_balance()); + + T::Currency::transfer( + &bonded_pool.bonded_account(), + &member_account, + balance_to_unbond, + ExistenceRequirement::AllowDeath, + ) + .defensive()?; + + Self::deposit_event(Event::::Withdrawn { + member: member_account.clone(), + pool_id: member.pool_id, + amount: balance_to_unbond, + }); + + let post_info_weight = if member.active_points().is_zero() { + // member being reaped. + PoolMembers::::remove(&member_account); + + if member_account == bonded_pool.roles.depositor { + Pallet::::dissolve_pool(bonded_pool); + None + } else { + bonded_pool.dec_members().put(); + SubPoolsStorage::::insert(&member.pool_id, sub_pools); + Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) + } + } else { + // we certainly don't need to delete any pools, because no one is being removed. + SubPoolsStorage::::insert(&member.pool_id, sub_pools); + PoolMembers::::insert(&member_account, member); + Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) + }; + + Ok(post_info_weight.into()) + } + + /// Create a new delegation pool. + /// + /// # Arguments + /// + /// * `amount` - The amount of funds to delegate to the pool. This also acts of a sort of + /// deposit since the pools creator cannot fully unbond funds until the pool is being + /// destroyed. + /// * `index` - A disambiguation index for creating the account. Likely only useful when + /// creating multiple pools in the same extrinsic. + /// * `root` - The account to set as [`PoolRoles::root`]. + /// * `nominator` - The account to set as the [`PoolRoles::nominator`]. + /// * `state_toggler` - The account to set as the [`PoolRoles::state_toggler`]. + /// + /// # Note + /// + /// In addition to `amount`, the caller will transfer the existential deposit; so the caller + /// needs at have at least `amount + existential_deposit` transferrable. + #[pallet::weight(T::WeightInfo::create())] + #[transactional] + pub fn create( + origin: OriginFor, + #[pallet::compact] amount: BalanceOf, + root: T::AccountId, + nominator: T::AccountId, + state_toggler: T::AccountId, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + ensure!( + amount >= + T::StakingInterface::minimum_bond() + .max(MinCreateBond::::get()) + .max(MinJoinBond::::get()), + Error::::MinimumBondNotMet + ); + ensure!( + MaxPools::::get() + .map_or(true, |max_pools| BondedPools::::count() < max_pools), + Error::::MaxPools + ); + ensure!(!PoolMembers::::contains_key(&who), Error::::AccountBelongsToOtherPool); + + let pool_id = LastPoolId::::mutate(|id| { + *id += 1; + *id + }); + let mut bonded_pool = BondedPool::::new( + pool_id, + PoolRoles { root, nominator, state_toggler, depositor: who.clone() }, + ); + + bonded_pool.try_inc_members()?; + let points = bonded_pool.try_bond_funds(&who, amount, BondType::Create)?; + + T::Currency::transfer( + &who, + &bonded_pool.reward_account(), + T::Currency::minimum_balance(), + ExistenceRequirement::AllowDeath, + )?; + + PoolMembers::::insert( + who.clone(), + PoolMember:: { + pool_id, + points, + reward_pool_total_earnings: Zero::zero(), + unbonding_eras: Default::default(), + }, + ); + RewardPools::::insert( + pool_id, + RewardPool:: { + balance: Zero::zero(), + points: U256::zero(), + total_earnings: Zero::zero(), + }, + ); + ReversePoolIdLookup::::insert(bonded_pool.bonded_account(), pool_id); + Self::deposit_event(Event::::Created { + depositor: who.clone(), + pool_id: pool_id.clone(), + }); + Self::deposit_event(Event::::Bonded { + member: who, + pool_id, + bonded: amount, + joined: true, + }); + bonded_pool.put(); + + Ok(()) + } + + #[pallet::weight(T::WeightInfo::nominate(validators.len() as u32))] + pub fn nominate( + origin: OriginFor, + pool_id: PoolId, + validators: Vec, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); + T::StakingInterface::nominate(bonded_pool.bonded_account(), validators)?; + Ok(()) + } + + #[pallet::weight(T::WeightInfo::set_state())] + pub fn set_state( + origin: OriginFor, + pool_id: PoolId, + state: PoolState, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + ensure!(bonded_pool.state != PoolState::Destroying, Error::::CanNotChangeState); + + if bonded_pool.can_toggle_state(&who) { + bonded_pool.set_state(state); + } else if bonded_pool.ok_to_be_open(Zero::zero()).is_err() && + state == PoolState::Destroying + { + // If the pool has bad properties, then anyone can set it as destroying + bonded_pool.set_state(PoolState::Destroying); + } else { + Err(Error::::CanNotChangeState)?; + } + + bonded_pool.put(); + + Ok(()) + } + + #[pallet::weight(T::WeightInfo::set_metadata(metadata.len() as u32))] + pub fn set_metadata( + origin: OriginFor, + pool_id: PoolId, + metadata: Vec, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let metadata: BoundedVec<_, _> = + metadata.try_into().map_err(|_| Error::::MetadataExceedsMaxLen)?; + ensure!( + BondedPool::::get(pool_id) + .ok_or(Error::::PoolNotFound)? + .can_set_metadata(&who), + Error::::DoesNotHavePermission + ); + + Metadata::::mutate(pool_id, |pool_meta| *pool_meta = metadata); + + Ok(()) + } + + /// Update configurations for the nomination pools. The origin must for this call must be + /// Root. + /// + /// # Arguments + /// + /// * `min_join_bond` - Set [`MinJoinBond`]. + /// * `min_create_bond` - Set [`MinCreateBond`]. + /// * `max_pools` - Set [`MaxPools`]. + /// * `max_members` - Set [`MaxPoolMembers`]. + /// * `max_members_per_pool` - Set [`MaxPoolMembersPerPool`]. + #[pallet::weight(T::WeightInfo::set_configs())] + pub fn set_configs( + origin: OriginFor, + min_join_bond: ConfigOp>, + min_create_bond: ConfigOp>, + max_pools: ConfigOp, + max_members: ConfigOp, + max_members_per_pool: ConfigOp, + ) -> DispatchResult { + ensure_root(origin)?; + + macro_rules! config_op_exp { + ($storage:ty, $op:ident) => { + match $op { + ConfigOp::Noop => (), + ConfigOp::Set(v) => <$storage>::put(v), + ConfigOp::Remove => <$storage>::kill(), + } + }; + } + + config_op_exp!(MinJoinBond::, min_join_bond); + config_op_exp!(MinCreateBond::, min_create_bond); + config_op_exp!(MaxPools::, max_pools); + config_op_exp!(MaxPoolMembers::, max_members); + config_op_exp!(MaxPoolMembersPerPool::, max_members_per_pool); + + Ok(()) + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + assert!( + sp_std::mem::size_of::() >= + 2 * sp_std::mem::size_of::>(), + "bit-length of the reward points must be at least twice as much as balance" + ); + + assert!( + T::StakingInterface::bonding_duration() < TotalUnbondingPools::::get(), + "There must be more unbonding pools then the bonding duration / + so a slash can be applied to relevant unboding pools. (We assume / + the bonding duration > slash deffer duration.", + ); + } + } +} + +impl Pallet { + /// Remove everything related to the given bonded pool. + /// + /// All sub-pools are also deleted. All accounts are dusted and the leftover of the reward + /// account is returned to the depositor. + pub fn dissolve_pool(bonded_pool: BondedPool) { + let reward_account = bonded_pool.reward_account(); + let bonded_account = bonded_pool.bonded_account(); + + ReversePoolIdLookup::::remove(&bonded_account); + RewardPools::::remove(bonded_pool.id); + SubPoolsStorage::::remove(bonded_pool.id); + + // Kill accounts from storage by making their balance go below ED. We assume that the + // accounts have no references that would prevent destruction once we get to this point. We + // don't work with the system pallet directly, but + // 1. we drain the reward account and kill it. This account should never have any extra + // consumers anyway. + // 2. the bonded account should become a 'killed stash' in the staking system, and all of + // its consumers removed. + debug_assert_eq!(frame_system::Pallet::::consumers(&reward_account), 0); + debug_assert_eq!(frame_system::Pallet::::consumers(&bonded_account), 0); + debug_assert_eq!( + T::StakingInterface::total_stake(&bonded_account).unwrap_or_default(), + Zero::zero() + ); + + // This shouldn't fail, but if it does we don't really care + let reward_pool_remaining = T::Currency::free_balance(&reward_account); + let _ = T::Currency::transfer( + &reward_account, + &bonded_pool.roles.depositor, + reward_pool_remaining, + ExistenceRequirement::AllowDeath, + ); + + // TODO: this is purely defensive. + T::Currency::make_free_balance_be(&reward_account, Zero::zero()); + T::Currency::make_free_balance_be(&bonded_pool.bonded_account(), Zero::zero()); + + Self::deposit_event(Event::::Destroyed { pool_id: bonded_pool.id }); + bonded_pool.remove(); + } + + /// Create the main, bonded account of a pool with the given id. + pub fn create_bonded_account(id: PoolId) -> T::AccountId { + T::PalletId::get().into_sub_account((AccountType::Bonded, id)) + } + + /// Create the reward account of a pool with the given id. + pub fn create_reward_account(id: PoolId) -> T::AccountId { + // NOTE: in order to have a distinction in the test account id type (u128), we put + // account_type first so it does not get truncated out. + T::PalletId::get().into_sub_account((AccountType::Reward, id)) + } + + /// Get the member with their associated bonded and reward pool. + fn get_member_with_pools( + who: &T::AccountId, + ) -> Result<(PoolMember, BondedPool, RewardPool), Error> { + let member = PoolMembers::::get(&who).ok_or(Error::::PoolMemberNotFound)?; + let bonded_pool = + BondedPool::::get(member.pool_id).defensive_ok_or(Error::::PoolNotFound)?; + let reward_pool = + RewardPools::::get(member.pool_id).defensive_ok_or(Error::::PoolNotFound)?; + Ok((member, bonded_pool, reward_pool)) + } + + /// Persist the member with their associated bonded and reward pool into storage, consuming + /// all of them. + fn put_member_with_pools( + member_account: &T::AccountId, + member: PoolMember, + bonded_pool: BondedPool, + reward_pool: RewardPool, + ) { + bonded_pool.put(); + RewardPools::insert(member.pool_id, reward_pool); + PoolMembers::::insert(member_account, member); + } + + /// Calculate the equivalent point of `new_funds` in a pool with `current_balance` and + /// `current_points`. + fn balance_to_point( + current_balance: BalanceOf, + current_points: BalanceOf, + new_funds: BalanceOf, + ) -> BalanceOf { + let u256 = |x| T::BalanceToU256::convert(x); + let balance = |x| T::U256ToBalance::convert(x); + match (current_balance.is_zero(), current_points.is_zero()) { + (_, true) => new_funds.saturating_mul(POINTS_TO_BALANCE_INIT_RATIO.into()), + (true, false) => { + // The pool was totally slashed. + // This is the equivalent of `(current_points / 1) * new_funds`. + new_funds.saturating_mul(current_points) + }, + (false, false) => { + // Equivalent to (current_points / current_balance) * new_funds + balance( + u256(current_points) + .saturating_mul(u256(new_funds)) + // We check for zero above + .div(u256(current_balance)), + ) + }, + } + } + + /// Calculate the equivalent balance of `points` in a pool with `current_balance` and + /// `current_points`. + fn point_to_balance( + current_balance: BalanceOf, + current_points: BalanceOf, + points: BalanceOf, + ) -> BalanceOf { + let u256 = |x| T::BalanceToU256::convert(x); + let balance = |x| T::U256ToBalance::convert(x); + if current_balance.is_zero() || current_points.is_zero() || points.is_zero() { + // There is nothing to unbond + return Zero::zero() + } + + // Equivalent of (current_balance / current_points) * points + balance(u256(current_balance).saturating_mul(u256(points))) + // We check for zero above + .div(current_points) + } + + /// Calculate the rewards for `member`. + /// + /// Returns the payout amount. + fn calculate_member_payout( + member: &mut PoolMember, + bonded_pool: &mut BondedPool, + reward_pool: &mut RewardPool, + ) -> Result, DispatchError> { + let u256 = |x| T::BalanceToU256::convert(x); + let balance = |x| T::U256ToBalance::convert(x); + + let last_total_earnings = reward_pool.total_earnings; + reward_pool.update_total_earnings_and_balance(bonded_pool.id); + + // Notice there is an edge case where total_earnings have not increased and this is zero + let new_earnings = u256(reward_pool.total_earnings.saturating_sub(last_total_earnings)); + + // The new points that will be added to the pool. For every unit of balance that has been + // earned by the reward pool, we inflate the reward pool points by `bonded_pool.points`. In + // effect this allows each, single unit of balance (e.g. plank) to be divvied up pro rata + // among members based on points. + let new_points = u256(bonded_pool.points).saturating_mul(new_earnings); + + // The points of the reward pool after taking into account the new earnings. Notice that + // this only stays even or increases over time except for when we subtract member virtual + // shares. + let current_points = bonded_pool.bound_check(reward_pool.points.saturating_add(new_points)); + + // The rewards pool's earnings since the last time this member claimed a payout. + let new_earnings_since_last_claim = + reward_pool.total_earnings.saturating_sub(member.reward_pool_total_earnings); + + // The points of the reward pool that belong to the member. + let member_virtual_points = + // The members portion of the reward pool + u256(member.active_points()) + // times the amount the pool has earned since the member last claimed. + .saturating_mul(u256(new_earnings_since_last_claim)); + + let member_payout = if member_virtual_points.is_zero() || + current_points.is_zero() || + reward_pool.balance.is_zero() + { + Zero::zero() + } else { + // Equivalent to `(member_virtual_points / current_points) * reward_pool.balance` + let numerator = { + let numerator = member_virtual_points.saturating_mul(u256(reward_pool.balance)); + bonded_pool.bound_check(numerator) + }; + balance( + numerator + // We check for zero above + .div(current_points), + ) + }; + + // Record updates + if reward_pool.total_earnings == BalanceOf::::max_value() { + bonded_pool.set_state(PoolState::Destroying); + }; + member.reward_pool_total_earnings = reward_pool.total_earnings; + reward_pool.points = current_points.saturating_sub(member_virtual_points); + reward_pool.balance = reward_pool.balance.saturating_sub(member_payout); + + Ok(member_payout) + } + + /// If the member has some rewards, transfer a payout from the reward pool to the member. + // Emits events and potentially modifies pool state if any arithmetic saturates, but does + // not persist any of the mutable inputs to storage. + fn do_reward_payout( + member_account: &T::AccountId, + member: &mut PoolMember, + bonded_pool: &mut BondedPool, + reward_pool: &mut RewardPool, + ) -> Result, DispatchError> { + debug_assert_eq!(member.pool_id, bonded_pool.id); + // a member who has no skin in the game anymore cannot claim any rewards. + ensure!(!member.active_points().is_zero(), Error::::FullyUnbonding); + let was_destroying = bonded_pool.is_destroying(); + + let member_payout = Self::calculate_member_payout(member, bonded_pool, reward_pool)?; + + // Transfer payout to the member. + T::Currency::transfer( + &bonded_pool.reward_account(), + &member_account, + member_payout, + ExistenceRequirement::AllowDeath, + )?; + + Self::deposit_event(Event::::PaidOut { + member: member_account.clone(), + pool_id: member.pool_id, + payout: member_payout, + }); + + if bonded_pool.is_destroying() && !was_destroying { + Self::deposit_event(Event::::StateChanged { + pool_id: member.pool_id, + new_state: PoolState::Destroying, + }); + } + + Ok(member_payout) + } + + /// Ensure the correctness of the state of this pallet. + /// + /// This should be valid before or after each state transition of this pallet. + /// + /// ## Invariants: + /// + /// First, let's consider pools: + /// + /// * `BondedPools` and `RewardPools` must all have the EXACT SAME key-set. + /// * `SubPoolsStorage` must be a subset of the above superset. + /// * `Metadata` keys must be a subset of the above superset. + /// * the count of the above set must be less than `MaxPools`. + /// + /// Then, considering members as well: + /// + /// * each `BondedPool.member_counter` must be: + /// - correct (compared to actual count of member who have `.pool_id` this pool) + /// - less than `MaxPoolMembersPerPool`. + /// * each `member.pool_id` must correspond to an existing `BondedPool.id` (which implies the + /// existence of the reward pool as well). + /// * count of all members must be less than `MaxPoolMembers`. + /// + /// Then, considering unbonding members: + /// + /// for each pool: + /// * sum of the balance that's tracked in all unbonding pools must be the same as the + /// unbonded balance of the main account, as reported by the staking interface. + /// * sum of the balance that's tracked in all unbonding pools, plus the bonded balance of the + /// main account should be less than or qual to the total balance of the main account. + /// + /// ## Sanity check level + /// + /// To cater for tests that want to escape parts of these checks, this function is split into + /// multiple `level`s, where the higher the level, the more checks we performs. So, + /// `sanity_check(255)` is the strongest sanity check, and `0` performs no checks. + #[cfg(any(test, debug_assertions))] + pub fn sanity_checks(level: u8) -> Result<(), &'static str> { + if level.is_zero() { + return Ok(()) + } + // note: while a bit wacky, since they have the same key, even collecting to vec should + // result in the same set of keys, in the same order. + let bonded_pools = BondedPools::::iter_keys().collect::>(); + let reward_pools = RewardPools::::iter_keys().collect::>(); + assert_eq!(bonded_pools, reward_pools); + + assert!(Metadata::::iter_keys().all(|k| bonded_pools.contains(&k))); + assert!(SubPoolsStorage::::iter_keys().all(|k| bonded_pools.contains(&k))); + + assert!(MaxPools::::get().map_or(true, |max| bonded_pools.len() <= (max as usize))); + + for id in reward_pools { + let account = Self::create_reward_account(id); + assert!(T::Currency::free_balance(&account) >= T::Currency::minimum_balance()); + } + + let mut pools_members = BTreeMap::::new(); + let mut all_members = 0u32; + PoolMembers::::iter().for_each(|(_, d)| { + assert!(BondedPools::::contains_key(d.pool_id)); + assert!(!d.total_points().is_zero(), "no member should have zero points: {:?}", d); + *pools_members.entry(d.pool_id).or_default() += 1; + all_members += 1; + }); + + BondedPools::::iter().for_each(|(id, inner)| { + let bonded_pool = BondedPool { id, inner }; + assert_eq!( + pools_members.get(&id).map(|x| *x).unwrap_or_default(), + bonded_pool.member_counter + ); + assert!(MaxPoolMembersPerPool::::get() + .map_or(true, |max| bonded_pool.member_counter <= max)); + + let depositor = PoolMembers::::get(&bonded_pool.roles.depositor).unwrap(); + assert!( + bonded_pool.is_destroying_and_only_depositor(depositor.active_points()) || + depositor.active_points() >= MinCreateBond::::get(), + "depositor must always have MinCreateBond stake in the pool, except for when the \ + pool is being destroyed and the depositor is the last member", + ); + }); + assert!(MaxPoolMembers::::get().map_or(true, |max| all_members <= max)); + + if level <= 1 { + return Ok(()) + } + + for (pool_id, _pool) in BondedPools::::iter() { + let pool_account = Pallet::::create_bonded_account(pool_id); + let subs = SubPoolsStorage::::get(pool_id).unwrap_or_default(); + + let sum_unbonding_balance = subs.sum_unbonding_balance(); + let bonded_balance = + T::StakingInterface::active_stake(&pool_account).unwrap_or_default(); + let total_balance = T::Currency::total_balance(&pool_account); + + assert!( + total_balance >= bonded_balance + sum_unbonding_balance, + "faulty pool: {:?} / {:?}, total_balance {:?} >= bonded_balance {:?} + sum_unbonding_balance {:?}", + pool_id, + _pool, + total_balance, + bonded_balance, + sum_unbonding_balance + ); + } + + Ok(()) + } + + /// Fully unbond the shares of `member`, when executed from `origin`. + /// + /// This is useful for backwards compatibility with the majority of tests that only deal with + /// full unbonding, not partial unbonding. + #[cfg(any(feature = "runtime-benchmarks", test))] + pub fn fully_unbond( + origin: frame_system::pallet_prelude::OriginFor, + member: T::AccountId, + ) -> DispatchResult { + let points = PoolMembers::::get(&member).map(|d| d.active_points()).unwrap_or_default(); + Self::unbond(origin, member, points) + } +} + +impl OnStakerSlash> for Pallet { + fn on_slash( + pool_account: &T::AccountId, + // Bonded balance is always read directly from staking, therefore we need not update + // anything here. + _slashed_bonded: BalanceOf, + slashed_unlocking: &BTreeMap>, + ) { + if let Some(pool_id) = ReversePoolIdLookup::::get(pool_account) { + let mut sub_pools = match SubPoolsStorage::::get(pool_id).defensive() { + Some(sub_pools) => sub_pools, + None => return, + }; + for (era, slashed_balance) in slashed_unlocking.iter() { + if let Some(pool) = sub_pools.with_era.get_mut(era) { + pool.balance = *slashed_balance + } + } + SubPoolsStorage::::insert(pool_id, sub_pools); + } + } +} diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs new file mode 100644 index 0000000000000..5498496965adb --- /dev/null +++ b/frame/nomination-pools/src/mock.rs @@ -0,0 +1,309 @@ +use super::*; +use crate::{self as pools}; +use frame_support::{assert_ok, parameter_types, PalletId}; +use frame_system::RawOrigin; +use std::collections::HashMap; + +pub type AccountId = u128; +pub type Balance = u128; + +// Ext builder creates a pool with id 1. +pub fn default_bonded_account() -> AccountId { + Pools::create_bonded_account(1) +} + +// Ext builder creates a pool with id 1. +pub fn default_reward_account() -> AccountId { + Pools::create_reward_account(1) +} + +parameter_types! { + pub static CurrentEra: EraIndex = 0; + pub static BondingDuration: EraIndex = 3; + static BondedBalanceMap: HashMap = Default::default(); + static UnbondingBalanceMap: HashMap = Default::default(); + #[derive(Clone, PartialEq)] + pub static MaxUnbonding: u32 = 8; + pub static Nominations: Vec = vec![]; +} + +pub struct StakingMock; +impl StakingMock { + pub(crate) fn set_bonded_balance(who: AccountId, bonded: Balance) { + BONDED_BALANCE_MAP.with(|m| m.borrow_mut().insert(who, bonded)); + } +} + +impl sp_staking::StakingInterface for StakingMock { + type Balance = Balance; + type AccountId = AccountId; + + fn minimum_bond() -> Self::Balance { + 10 + } + + fn current_era() -> EraIndex { + CurrentEra::get() + } + + fn bonding_duration() -> EraIndex { + BondingDuration::get() + } + + fn active_stake(who: &Self::AccountId) -> Option { + BondedBalanceMap::get().get(who).map(|v| *v) + } + + fn total_stake(who: &Self::AccountId) -> Option { + match ( + UnbondingBalanceMap::get().get(who).map(|v| *v), + BondedBalanceMap::get().get(who).map(|v| *v), + ) { + (None, None) => None, + (Some(v), None) | (None, Some(v)) => Some(v), + (Some(a), Some(b)) => Some(a + b), + } + } + + fn bond_extra(who: Self::AccountId, extra: Self::Balance) -> DispatchResult { + BONDED_BALANCE_MAP.with(|m| *m.borrow_mut().get_mut(&who).unwrap() += extra); + Ok(()) + } + + fn unbond(who: Self::AccountId, amount: Self::Balance) -> DispatchResult { + BONDED_BALANCE_MAP.with(|m| *m.borrow_mut().get_mut(&who).unwrap() -= amount); + UNBONDING_BALANCE_MAP + .with(|m| *m.borrow_mut().entry(who).or_insert(Self::Balance::zero()) += amount); + Ok(()) + } + + fn withdraw_unbonded(who: Self::AccountId, _: u32) -> Result { + // Simulates removing unlocking chunks and only having the bonded balance locked + let _maybe_new_free = UNBONDING_BALANCE_MAP.with(|m| m.borrow_mut().remove(&who)); + + Ok(100) + } + + fn bond( + stash: Self::AccountId, + _: Self::AccountId, + value: Self::Balance, + _: Self::AccountId, + ) -> DispatchResult { + StakingMock::set_bonded_balance(stash, value); + Ok(()) + } + + fn nominate(_: Self::AccountId, nominations: Vec) -> DispatchResult { + Nominations::set(nominations); + Ok(()) + } +} + +impl frame_system::Config for Runtime { + type SS58Prefix = (); + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = Call; + type Hash = sp_core::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = sp_runtime::testing::Header; + type Event = Event; + type BlockHashCount = (); + type DbWeight = (); + type BlockLength = (); + type BlockWeights = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +parameter_types! { + pub static ExistentialDeposit: Balance = 5; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = frame_support::traits::ConstU32<1024>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} + +pub struct BalanceToU256; +impl Convert for BalanceToU256 { + fn convert(n: Balance) -> U256 { + n.into() + } +} + +pub struct U256ToBalance; +impl Convert for U256ToBalance { + fn convert(n: U256) -> Balance { + n.try_into().unwrap() + } +} + +parameter_types! { + pub static PostUnbondingPoolsWindow: u32 = 2; + pub static MaxMetadataLen: u32 = 2; + pub static CheckLevel: u8 = 255; + pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); +} +impl pools::Config for Runtime { + type Event = Event; + type WeightInfo = (); + type Currency = Balances; + type BalanceToU256 = BalanceToU256; + type U256ToBalance = U256ToBalance; + type StakingInterface = StakingMock; + type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; + type PalletId = PoolsPalletId; + type MaxMetadataLen = MaxMetadataLen; + type MaxUnbonding = MaxUnbonding; +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Storage, Event, Config}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Pools: pools::{Pallet, Call, Storage, Event}, + } +); + +#[derive(Default)] +pub struct ExtBuilder { + members: Vec<(AccountId, Balance)>, +} + +impl ExtBuilder { + // Add members to pool 0. + pub(crate) fn add_members(mut self, members: Vec<(AccountId, Balance)>) -> Self { + self.members = members; + self + } + + pub(crate) fn ed(self, ed: Balance) -> Self { + ExistentialDeposit::set(ed); + self + } + + pub(crate) fn with_check(self, level: u8) -> Self { + CheckLevel::set(level); + self + } + + pub(crate) fn build(self) -> sp_io::TestExternalities { + let mut storage = + frame_system::GenesisConfig::default().build_storage::().unwrap(); + + let _ = crate::GenesisConfig:: { + min_join_bond: 2, + min_create_bond: 2, + max_pools: Some(2), + max_members_per_pool: Some(3), + max_members: Some(4), + } + .assimilate_storage(&mut storage); + + let mut ext = sp_io::TestExternalities::from(storage); + + ext.execute_with(|| { + // for events to be deposited. + frame_system::Pallet::::set_block_number(1); + + // make a pool + let amount_to_bond = ::StakingInterface::minimum_bond(); + Balances::make_free_balance_be(&10, amount_to_bond * 2); + assert_ok!(Pools::create(RawOrigin::Signed(10).into(), amount_to_bond, 900, 901, 902)); + + let last_pool = LastPoolId::::get(); + for (account_id, bonded) in self.members { + Balances::make_free_balance_be(&account_id, bonded * 2); + assert_ok!(Pools::join(RawOrigin::Signed(account_id).into(), bonded, last_pool)); + } + }); + + ext + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(|| { + test(); + Pools::sanity_checks(CheckLevel::get()).unwrap(); + }) + } +} + +pub(crate) fn unsafe_set_state(pool_id: PoolId, state: PoolState) -> Result<(), ()> { + BondedPools::::try_mutate(pool_id, |maybe_bonded_pool| { + maybe_bonded_pool.as_mut().ok_or(()).map(|bonded_pool| { + bonded_pool.state = state; + }) + }) +} + +parameter_types! { + static ObservedEvents: usize = 0; +} + +/// All events of this pallet. +pub(crate) fn pool_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let Event::Pools(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = ObservedEvents::get(); + ObservedEvents::set(events.len()); + events.into_iter().skip(already_seen).collect() +} + +/// Same as `fully_unbond`, in permissioned setting. +pub fn fully_unbond_permissioned(member: AccountId) -> DispatchResult { + let points = PoolMembers::::get(&member) + .map(|d| d.active_points()) + .unwrap_or_default(); + Pools::unbond(Origin::signed(member), member, points) +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn u256_to_balance_convert_works() { + assert_eq!(U256ToBalance::convert(0u32.into()), Zero::zero()); + assert_eq!(U256ToBalance::convert(Balance::max_value().into()), Balance::max_value()) + } + + #[test] + #[should_panic] + fn u256_to_balance_convert_panics_correctly() { + U256ToBalance::convert(U256::from(Balance::max_value()).saturating_add(1u32.into())); + } + + #[test] + fn balance_to_u256_convert_works() { + assert_eq!(BalanceToU256::convert(0u32.into()), U256::zero()); + assert_eq!(BalanceToU256::convert(Balance::max_value()), Balance::max_value().into()) + } +} diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs new file mode 100644 index 0000000000000..7df922280873b --- /dev/null +++ b/frame/nomination-pools/src/tests.rs @@ -0,0 +1,2929 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate::{mock::*, Event}; +use frame_support::{ + assert_noop, assert_ok, assert_storage_noop, bounded_btree_map, + storage::{with_transaction, TransactionOutcome}, +}; + +macro_rules! unbonding_pools_with_era { + ($($k:expr => $v:expr),* $(,)?) => {{ + use sp_std::iter::{Iterator, IntoIterator}; + let not_bounded: BTreeMap<_, _> = Iterator::collect(IntoIterator::into_iter([$(($k, $v),)*])); + UnbondingPoolsWithEra::try_from(not_bounded).unwrap() + }}; +} + +macro_rules! member_unbonding_eras { + ($( $any:tt )*) => {{ + let x: BoundedBTreeMap = bounded_btree_map!($( $any )*); + x + }}; +} + +pub const DEFAULT_ROLES: PoolRoles = + PoolRoles { depositor: 10, root: 900, nominator: 901, state_toggler: 902 }; + +#[test] +fn test_setup_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(BondedPools::::count(), 1); + assert_eq!(RewardPools::::count(), 1); + assert_eq!(SubPoolsStorage::::count(), 0); + assert_eq!(PoolMembers::::count(), 1); + assert_eq!(StakingMock::bonding_duration(), 3); + + let last_pool = LastPoolId::::get(); + assert_eq!( + BondedPool::::get(last_pool).unwrap(), + BondedPool:: { + id: last_pool, + inner: BondedPoolInner { + state: PoolState::Open, + points: 10, + member_counter: 1, + roles: DEFAULT_ROLES + }, + } + ); + assert_eq!( + RewardPools::::get(last_pool).unwrap(), + RewardPool:: { balance: 0, points: 0.into(), total_earnings: 0 } + ); + assert_eq!( + PoolMembers::::get(10).unwrap(), + PoolMember:: { pool_id: last_pool, points: 10, ..Default::default() } + ) + }) +} + +mod bonded_pool { + use super::*; + #[test] + fn points_to_issue_works() { + let mut bonded_pool = BondedPool:: { + id: 123123, + inner: BondedPoolInner { + state: PoolState::Open, + points: 100, + member_counter: 1, + roles: DEFAULT_ROLES, + }, + }; + + // 1 points : 1 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + assert_eq!(bonded_pool.balance_to_point(10), 10); + assert_eq!(bonded_pool.balance_to_point(0), 0); + + // 2 points : 1 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 50); + assert_eq!(bonded_pool.balance_to_point(10), 20); + + // 1 points : 2 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + bonded_pool.points = 50; + assert_eq!(bonded_pool.balance_to_point(10), 5); + + // 100 points : 0 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); + bonded_pool.points = 100; + assert_eq!(bonded_pool.balance_to_point(10), 100 * 10); + + // 0 points : 100 balance + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + bonded_pool.points = 100; + assert_eq!(bonded_pool.balance_to_point(10), 10); + + // 10 points : 3 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 30); + assert_eq!(bonded_pool.balance_to_point(10), 33); + + // 2 points : 3 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 300); + bonded_pool.points = 200; + assert_eq!(bonded_pool.balance_to_point(10), 6); + + // 4 points : 9 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 900); + bonded_pool.points = 400; + assert_eq!(bonded_pool.balance_to_point(90), 40); + } + + #[test] + fn balance_to_unbond_works() { + // 1 balance : 1 points ratio + let mut bonded_pool = BondedPool:: { + id: 123123, + inner: BondedPoolInner { + state: PoolState::Open, + points: 100, + member_counter: 1, + roles: DEFAULT_ROLES, + }, + }; + + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + assert_eq!(bonded_pool.points_to_balance(10), 10); + assert_eq!(bonded_pool.points_to_balance(0), 0); + + // 2 balance : 1 points ratio + bonded_pool.points = 50; + assert_eq!(bonded_pool.points_to_balance(10), 20); + + // 100 balance : 0 points ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); + bonded_pool.points = 0; + assert_eq!(bonded_pool.points_to_balance(10), 0); + + // 0 balance : 100 points ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); + bonded_pool.points = 100; + assert_eq!(bonded_pool.points_to_balance(10), 0); + + // 10 balance : 3 points ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + bonded_pool.points = 30; + assert_eq!(bonded_pool.points_to_balance(10), 33); + + // 2 balance : 3 points ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 200); + bonded_pool.points = 300; + assert_eq!(bonded_pool.points_to_balance(10), 6); + + // 4 balance : 9 points ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 400); + bonded_pool.points = 900; + assert_eq!(bonded_pool.points_to_balance(90), 40); + } + + #[test] + fn ok_to_join_with_works() { + ExtBuilder::default().build_and_execute(|| { + let pool = BondedPool:: { + id: 123, + inner: BondedPoolInner { + state: PoolState::Open, + points: 100, + member_counter: 1, + roles: DEFAULT_ROLES, + }, + }; + + // Simulate a 100% slashed pool + StakingMock::set_bonded_balance(pool.bonded_account(), 0); + assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); + + // Simulate a 89% + StakingMock::set_bonded_balance(pool.bonded_account(), 11); + assert_ok!(pool.ok_to_join(0)); + + // Simulate a 90% slashed pool + StakingMock::set_bonded_balance(pool.bonded_account(), 10); + assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); + + StakingMock::set_bonded_balance(pool.bonded_account(), Balance::MAX / 10); + // New bonded balance would be over 1/10th of Balance type + assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); + // and a sanity check + StakingMock::set_bonded_balance(pool.bonded_account(), Balance::MAX / 10 - 1); + assert_ok!(pool.ok_to_join(0)); + }); + } +} + +mod reward_pool { + #[test] + fn current_balance_only_counts_balance_over_existential_deposit() { + use super::*; + + ExtBuilder::default().build_and_execute(|| { + let reward_account = Pools::create_reward_account(2); + + // Given + assert_eq!(Balances::free_balance(&reward_account), 0); + + // Then + assert_eq!(RewardPool::::current_balance(2), 0); + + // Given + Balances::make_free_balance_be(&reward_account, Balances::minimum_balance()); + + // Then + assert_eq!(RewardPool::::current_balance(2), 0); + + // Given + Balances::make_free_balance_be(&reward_account, Balances::minimum_balance() + 1); + + // Then + assert_eq!(RewardPool::::current_balance(2), 1); + }); + } +} + +mod unbond_pool { + use super::*; + + #[test] + fn points_to_issue_works() { + // 1 points : 1 balance ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 100 }; + assert_eq!(unbond_pool.balance_to_point(10), 10); + assert_eq!(unbond_pool.balance_to_point(0), 0); + + // 2 points : 1 balance ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 50 }; + assert_eq!(unbond_pool.balance_to_point(10), 20); + + // 1 points : 2 balance ratio + let unbond_pool = UnbondPool:: { points: 50, balance: 100 }; + assert_eq!(unbond_pool.balance_to_point(10), 5); + + // 100 points : 0 balance ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 0 }; + assert_eq!(unbond_pool.balance_to_point(10), 100 * 10); + + // 0 points : 100 balance + let unbond_pool = UnbondPool:: { points: 0, balance: 100 }; + assert_eq!(unbond_pool.balance_to_point(10), 10); + + // 10 points : 3 balance ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 30 }; + assert_eq!(unbond_pool.balance_to_point(10), 33); + + // 2 points : 3 balance ratio + let unbond_pool = UnbondPool:: { points: 200, balance: 300 }; + assert_eq!(unbond_pool.balance_to_point(10), 6); + + // 4 points : 9 balance ratio + let unbond_pool = UnbondPool:: { points: 400, balance: 900 }; + assert_eq!(unbond_pool.balance_to_point(90), 40); + } + + #[test] + fn balance_to_unbond_works() { + // 1 balance : 1 points ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 100 }; + assert_eq!(unbond_pool.point_to_balance(10), 10); + assert_eq!(unbond_pool.point_to_balance(0), 0); + + // 1 balance : 2 points ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 50 }; + assert_eq!(unbond_pool.point_to_balance(10), 5); + + // 2 balance : 1 points ratio + let unbond_pool = UnbondPool:: { points: 50, balance: 100 }; + assert_eq!(unbond_pool.point_to_balance(10), 20); + + // 100 balance : 0 points ratio + let unbond_pool = UnbondPool:: { points: 0, balance: 100 }; + assert_eq!(unbond_pool.point_to_balance(10), 0); + + // 0 balance : 100 points ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 0 }; + assert_eq!(unbond_pool.point_to_balance(10), 0); + + // 10 balance : 3 points ratio + let unbond_pool = UnbondPool:: { points: 30, balance: 100 }; + assert_eq!(unbond_pool.point_to_balance(10), 33); + + // 2 balance : 3 points ratio + let unbond_pool = UnbondPool:: { points: 300, balance: 200 }; + assert_eq!(unbond_pool.point_to_balance(10), 6); + + // 4 balance : 9 points ratio + let unbond_pool = UnbondPool:: { points: 900, balance: 400 }; + assert_eq!(unbond_pool.point_to_balance(90), 40); + } +} + +mod sub_pools { + use super::*; + + #[test] + fn maybe_merge_pools_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(TotalUnbondingPools::::get(), 5); + + // Given + let mut sub_pool_0 = SubPools:: { + no_era: UnbondPool::::default(), + with_era: unbonding_pools_with_era! { + 0 => UnbondPool:: { points: 10, balance: 10 }, + 1 => UnbondPool:: { points: 10, balance: 10 }, + 2 => UnbondPool:: { points: 20, balance: 20 }, + 3 => UnbondPool:: { points: 30, balance: 30 }, + 4 => UnbondPool:: { points: 40, balance: 40 }, + }, + }; + + // When `current_era < TotalUnbondingPools`, + let sub_pool_1 = sub_pool_0.clone().maybe_merge_pools(3); + + // Then it exits early without modifications + assert_eq!(sub_pool_1, sub_pool_0); + + // When `current_era == TotalUnbondingPools`, + let sub_pool_1 = sub_pool_1.maybe_merge_pools(4); + + // Then it exits early without modifications + assert_eq!(sub_pool_1, sub_pool_0); + + // When `current_era - TotalUnbondingPools == 0`, + let mut sub_pool_1 = sub_pool_1.maybe_merge_pools(5); + + // Then era 0 is merged into the `no_era` pool + sub_pool_0.no_era = sub_pool_0.with_era.remove(&0).unwrap(); + assert_eq!(sub_pool_1, sub_pool_0); + + // Given we have entries for era 1..=5 + sub_pool_1 + .with_era + .try_insert(5, UnbondPool:: { points: 50, balance: 50 }) + .unwrap(); + sub_pool_0 + .with_era + .try_insert(5, UnbondPool:: { points: 50, balance: 50 }) + .unwrap(); + + // When `current_era - TotalUnbondingPools == 1` + let sub_pool_2 = sub_pool_1.maybe_merge_pools(6); + let era_1_pool = sub_pool_0.with_era.remove(&1).unwrap(); + + // Then era 1 is merged into the `no_era` pool + sub_pool_0.no_era.points += era_1_pool.points; + sub_pool_0.no_era.balance += era_1_pool.balance; + assert_eq!(sub_pool_2, sub_pool_0); + + // When `current_era - TotalUnbondingPools == 5`, so all pools with era <= 4 are removed + let sub_pool_3 = sub_pool_2.maybe_merge_pools(10); + + // Then all eras <= 5 are merged into the `no_era` pool + for era in 2..=5 { + let to_merge = sub_pool_0.with_era.remove(&era).unwrap(); + sub_pool_0.no_era.points += to_merge.points; + sub_pool_0.no_era.balance += to_merge.balance; + } + assert_eq!(sub_pool_3, sub_pool_0); + }); + } +} + +mod join { + use super::*; + + #[test] + fn join_works() { + let bonded = |points, member_counter| BondedPool:: { + id: 1, + inner: BondedPoolInner { + state: PoolState::Open, + points, + member_counter, + roles: DEFAULT_ROLES, + }, + }; + ExtBuilder::default().build_and_execute(|| { + // Given + Balances::make_free_balance_be(&11, ExistentialDeposit::get() + 2); + assert!(!PoolMembers::::contains_key(&11)); + + // When + assert_ok!(Pools::join(Origin::signed(11), 2, 1)); + + // then + assert_eq!( + PoolMembers::::get(&11).unwrap(), + PoolMember:: { pool_id: 1, points: 2, ..Default::default() } + ); + assert_eq!(BondedPool::::get(1).unwrap(), bonded(12, 2)); + + // Given + // The bonded balance is slashed in half + StakingMock::set_bonded_balance(Pools::create_bonded_account(1), 6); + + // And + Balances::make_free_balance_be(&12, ExistentialDeposit::get() + 12); + assert!(!PoolMembers::::contains_key(&12)); + + // When + assert_ok!(Pools::join(Origin::signed(12), 12, 1)); + + // Then + assert_eq!( + PoolMembers::::get(&12).unwrap(), + PoolMember:: { pool_id: 1, points: 24, ..Default::default() } + ); + assert_eq!(BondedPool::::get(1).unwrap(), bonded(12 + 24, 3)); + }); + } + + #[test] + fn join_errors_correctly() { + ExtBuilder::default().with_check(0).build_and_execute(|| { + // 10 is already part of the default pool created. + assert_eq!(PoolMembers::::get(&10).unwrap().pool_id, 1); + + assert_noop!( + Pools::join(Origin::signed(10), 420, 123), + Error::::AccountBelongsToOtherPool + ); + + assert_noop!(Pools::join(Origin::signed(11), 420, 123), Error::::PoolNotFound); + + // Force the pools bonded balance to 0, simulating a 100% slash + StakingMock::set_bonded_balance(Pools::create_bonded_account(1), 0); + assert_noop!(Pools::join(Origin::signed(11), 420, 1), Error::::OverflowRisk); + + // Given a mocked bonded pool + BondedPool:: { + id: 123, + inner: BondedPoolInner { + member_counter: 1, + state: PoolState::Open, + points: 100, + roles: DEFAULT_ROLES, + }, + } + .put(); + + // and reward pool + RewardPools::::insert( + 123, + RewardPool:: { + balance: Zero::zero(), + total_earnings: Zero::zero(), + points: U256::from(0u32), + }, + ); + + // Force the points:balance ratio to 100/10 + StakingMock::set_bonded_balance(Pools::create_bonded_account(123), 10); + assert_noop!(Pools::join(Origin::signed(11), 420, 123), Error::::OverflowRisk); + + StakingMock::set_bonded_balance(Pools::create_bonded_account(123), Balance::MAX / 10); + // Balance is gt 1/10 of Balance::MAX + assert_noop!(Pools::join(Origin::signed(11), 5, 123), Error::::OverflowRisk); + + StakingMock::set_bonded_balance(Pools::create_bonded_account(1), 10); + + // Cannot join a pool that isn't open + unsafe_set_state(123, PoolState::Blocked).unwrap(); + assert_noop!(Pools::join(Origin::signed(11), 10, 123), Error::::NotOpen); + + unsafe_set_state(123, PoolState::Destroying).unwrap(); + assert_noop!(Pools::join(Origin::signed(11), 10, 123), Error::::NotOpen); + + // Given + MinJoinBond::::put(100); + + // Then + assert_noop!( + Pools::join(Origin::signed(11), 99, 123), + Error::::MinimumBondNotMet + ); + }); + } + + #[test] + #[cfg_attr(debug_assertions, should_panic(expected = "Defensive failure has been triggered!"))] + #[cfg_attr(not(debug_assertions), should_panic)] + fn join_panics_when_reward_pool_not_found() { + ExtBuilder::default().build_and_execute(|| { + StakingMock::set_bonded_balance(Pools::create_bonded_account(123), 100); + BondedPool:: { + id: 123, + inner: BondedPoolInner { + state: PoolState::Open, + points: 100, + member_counter: 1, + roles: DEFAULT_ROLES, + }, + } + .put(); + let _ = Pools::join(Origin::signed(11), 420, 123); + }); + } + + #[test] + fn join_max_member_limits_are_respected() { + ExtBuilder::default().build_and_execute(|| { + // Given + assert_eq!(MaxPoolMembersPerPool::::get(), Some(3)); + for i in 1..3 { + let account = i + 100; + Balances::make_free_balance_be(&account, 100 + Balances::minimum_balance()); + + assert_ok!(Pools::join(Origin::signed(account), 100, 1)); + } + + Balances::make_free_balance_be(&103, 100 + Balances::minimum_balance()); + + // Then + assert_noop!( + Pools::join(Origin::signed(103), 100, 1), + Error::::MaxPoolMembers + ); + + // Given + assert_eq!(PoolMembers::::count(), 3); + assert_eq!(MaxPoolMembers::::get(), Some(4)); + + Balances::make_free_balance_be(&104, 100 + Balances::minimum_balance()); + assert_ok!(Pools::create(Origin::signed(104), 100, 104, 104, 104)); + + let pool_account = BondedPools::::iter() + .find(|(_, bonded_pool)| bonded_pool.roles.depositor == 104) + .map(|(pool_account, _)| pool_account) + .unwrap(); + + // Then + assert_noop!( + Pools::join(Origin::signed(103), 100, pool_account), + Error::::MaxPoolMembers + ); + }); + } +} + +mod claim_payout { + use super::*; + + fn del(points: Balance, reward_pool_total_earnings: Balance) -> PoolMember { + PoolMember { + pool_id: 1, + points, + reward_pool_total_earnings, + unbonding_eras: Default::default(), + } + } + + fn rew(balance: Balance, points: u32, total_earnings: Balance) -> RewardPool { + RewardPool { balance, points: points.into(), total_earnings } + } + + #[test] + fn claim_payout_works() { + ExtBuilder::default() + .add_members(vec![(40, 40), (50, 50)]) + .build_and_execute(|| { + // Given each member currently has a free balance of + Balances::make_free_balance_be(&10, 0); + Balances::make_free_balance_be(&40, 0); + Balances::make_free_balance_be(&50, 0); + let ed = Balances::minimum_balance(); + // and the reward pool has earned 100 in rewards + Balances::make_free_balance_be(&default_reward_account(), ed + 100); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(10))); + + // Then + // Expect a payout of 10: (10 del virtual points / 100 pool points) * 100 pool + // balance + assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 100)); + assert_eq!( + RewardPools::::get(&1).unwrap(), + rew(90, 100 * 100 - 100 * 10, 100) + ); + assert_eq!(Balances::free_balance(&10), 10); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 90); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(40))); + + // Then + // Expect payout 40: (400 del virtual points / 900 pool points) * 90 pool balance + assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 100)); + assert_eq!( + RewardPools::::get(&1).unwrap(), + rew(50, 9_000 - 100 * 40, 100) + ); + assert_eq!(Balances::free_balance(&40), 40); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 50); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(50))); + + // Then + // Expect payout 50: (50 del virtual points / 50 pool points) * 50 pool balance + assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 100)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 100)); + assert_eq!(Balances::free_balance(&50), 50); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 0); + + // Given the reward pool has some new rewards + Balances::make_free_balance_be(&default_reward_account(), ed + 50); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(10))); + + // Then + // Expect payout 5: (500 del virtual points / 5,000 pool points) * 50 pool balance + assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 150)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(45, 5_000 - 50 * 10, 150)); + assert_eq!(Balances::free_balance(&10), 10 + 5); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 45); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(40))); + + // Then + // Expect payout 20: (2,000 del virtual points / 4,500 pool points) * 45 pool + // balance + assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 150)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(25, 4_500 - 50 * 40, 150)); + assert_eq!(Balances::free_balance(&40), 40 + 20); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); + + // Given del 50 hasn't claimed and the reward pools has just earned 50 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 75); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(50))); + + // Then + // We expect a payout of 50: (5,000 del virtual points / 7,5000 pool points) * 75 + // pool balance + assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 200)); + assert_eq!( + RewardPools::::get(&1).unwrap(), + rew( + 25, + // old pool points + points from new earnings - del points. + // + // points from new earnings = new earnings(50) * bonded_pool.points(100) + // del points = member.points(50) * new_earnings_since_last_claim (100) + (2_500 + 50 * 100) - 50 * 100, + 200, + ) + ); + assert_eq!(Balances::free_balance(&50), 50 + 50); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(10))); + + // Then + // We expect a payout of 5 + assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 200)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(20, 2_500 - 10 * 50, 200)); + assert_eq!(Balances::free_balance(&10), 15 + 5); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 20); + + // Given del 40 hasn't claimed and the reward pool has just earned 400 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 400)); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 420); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(10))); + + // Then + // We expect a payout of 40 + assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 600)); + assert_eq!( + RewardPools::::get(&1).unwrap(), + rew( + 380, + // old pool points + points from new earnings - del points + // + // points from new earnings = new earnings(400) * bonded_pool.points(100) + // del points = member.points(10) * new_earnings_since_last_claim(400) + (2_000 + 400 * 100) - 10 * 400, + 600 + ) + ); + assert_eq!(Balances::free_balance(&10), 20 + 40); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 380); + + // Given del 40 + del 50 haven't claimed and the reward pool has earned 20 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 20)); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 400); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(10))); + + // Then + // Expect a payout of 2: (200 del virtual points / 38,000 pool points) * 400 pool + // balance + assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 620)); + assert_eq!( + RewardPools::::get(&1).unwrap(), + rew(398, (38_000 + 20 * 100) - 10 * 20, 620) + ); + assert_eq!(Balances::free_balance(&10), 60 + 2); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 398); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(40))); + + // Then + // Expect a payout of 188: (18,800 del virtual points / 39,800 pool points) * 399 + // pool balance + assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 620)); + assert_eq!( + RewardPools::::get(&1).unwrap(), + rew(210, 39_800 - 40 * 470, 620) + ); + assert_eq!(Balances::free_balance(&40), 60 + 188); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 210); + + // When + assert_ok!(Pools::claim_payout(Origin::signed(50))); + + // Then + // Expect payout of 210: (21,000 / 21,000) * 210 + assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 620)); + assert_eq!( + RewardPools::::get(&1).unwrap(), + rew(0, 21_000 - 50 * 420, 620) + ); + assert_eq!(Balances::free_balance(&50), 100 + 210); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 0); + }); + } + + #[test] + fn do_reward_payout_correctly_sets_pool_state_to_destroying() { + ExtBuilder::default().build_and_execute(|| { + let _ = with_transaction(|| -> TransactionOutcome { + let mut bonded_pool = BondedPool::::get(1).unwrap(); + let mut reward_pool = RewardPools::::get(1).unwrap(); + let mut member = PoolMembers::::get(10).unwrap(); + + // -- reward_pool.total_earnings saturates + + // Given + Balances::make_free_balance_be(&default_reward_account(), Balance::MAX); + + // When + assert_ok!(Pools::do_reward_payout( + &10, + &mut member, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + assert!(bonded_pool.is_destroying()); + + storage::TransactionOutcome::Rollback(Ok(())) + }); + + // -- current_points saturates (reward_pool.points + new_earnings * bonded_pool.points) + let _ = with_transaction(|| -> TransactionOutcome { + // Given + let mut bonded_pool = BondedPool::::get(1).unwrap(); + let mut reward_pool = RewardPools::::get(1).unwrap(); + let mut member = PoolMembers::::get(10).unwrap(); + // Force new_earnings * bonded_pool.points == 100 + Balances::make_free_balance_be(&default_reward_account(), 5 + 10); + assert_eq!(bonded_pool.points, 10); + // Force reward_pool.points == U256::MAX - new_earnings * bonded_pool.points + reward_pool.points = U256::MAX - U256::from(100u32); + RewardPools::::insert(1, reward_pool.clone()); + + // When + assert_ok!(Pools::do_reward_payout( + &10, + &mut member, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + assert!(bonded_pool.is_destroying()); + + storage::TransactionOutcome::Rollback(Ok(())) + }); + }); + } + + #[test] + fn reward_payout_errors_if_a_member_is_fully_unbonding() { + ExtBuilder::default().add_members(vec![(11, 11)]).build_and_execute(|| { + // fully unbond the member. + assert_ok!(Pools::fully_unbond(Origin::signed(11), 11)); + + let mut bonded_pool = BondedPool::::get(1).unwrap(); + let mut reward_pool = RewardPools::::get(1).unwrap(); + let mut member = PoolMembers::::get(11).unwrap(); + + assert_noop!( + Pools::do_reward_payout(&11, &mut member, &mut bonded_pool, &mut reward_pool,), + Error::::FullyUnbonding + ); + }); + } + + #[test] + fn calculate_member_payout_works_with_a_pool_of_1() { + let del = |reward_pool_total_earnings| del(10, reward_pool_total_earnings); + + ExtBuilder::default().build_and_execute(|| { + let mut bonded_pool = BondedPool::::get(1).unwrap(); + let mut reward_pool = RewardPools::::get(1).unwrap(); + let mut member = PoolMembers::::get(10).unwrap(); + let ed = Balances::minimum_balance(); + + // Given no rewards have been earned + // When + let payout = + Pools::calculate_member_payout(&mut member, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 0); + assert_eq!(member, del(0)); + assert_eq!(reward_pool, rew(0, 0, 0)); + + // Given the pool has earned some rewards for the first time + Balances::make_free_balance_be(&default_reward_account(), ed + 5); + + // When + let payout = + Pools::calculate_member_payout(&mut member, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 5); // (10 * 5 del virtual points / 10 * 5 pool points) * 5 pool balance + assert_eq!(reward_pool, rew(0, 0, 5)); + assert_eq!(member, del(5)); + + // Given the pool has earned rewards again + Balances::make_free_balance_be(&default_reward_account(), ed + 10); + + // When + let payout = + Pools::calculate_member_payout(&mut member, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 10); // (10 * 10 del virtual points / 10 pool points) * 5 pool balance + assert_eq!(reward_pool, rew(0, 0, 15)); + assert_eq!(member, del(15)); + + // Given the pool has earned no new rewards + Balances::make_free_balance_be(&default_reward_account(), ed + 0); + + // When + let payout = + Pools::calculate_member_payout(&mut member, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 0); + assert_eq!(reward_pool, rew(0, 0, 15)); + assert_eq!(member, del(15)); + }); + } + + #[test] + fn calculate_member_payout_works_with_a_pool_of_3() { + ExtBuilder::default() + .add_members(vec![(40, 40), (50, 50)]) + .build_and_execute(|| { + let mut bonded_pool = BondedPool::::get(1).unwrap(); + let mut reward_pool = RewardPools::::get(1).unwrap(); + let ed = Balances::minimum_balance(); + // PoolMember with 10 points + let mut del_10 = PoolMembers::::get(10).unwrap(); + // PoolMember with 40 points + let mut del_40 = PoolMembers::::get(40).unwrap(); + // PoolMember with 50 points + let mut del_50 = PoolMembers::::get(50).unwrap(); + + // Given we have a total of 100 points split among the members + assert_eq!(del_50.points + del_40.points + del_10.points, 100); + assert_eq!(bonded_pool.points, 100); + // and the reward pool has earned 100 in rewards + Balances::make_free_balance_be(&default_reward_account(), ed + 100); + + // When + let payout = + Pools::calculate_member_payout(&mut del_10, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 10); // (10 del virtual points / 100 pool points) * 100 pool balance + assert_eq!(del_10, del(10, 100)); + assert_eq!(reward_pool, rew(90, 100 * 100 - 100 * 10, 100)); + // Mock the reward pool transferring the payout to del_10 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 10)); + + // When + let payout = + Pools::calculate_member_payout(&mut del_40, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 40); // (400 del virtual points / 900 pool points) * 90 pool balance + assert_eq!(del_40, del(40, 100)); + assert_eq!( + reward_pool, + rew( + 50, + // old pool points - member virtual points + 9_000 - 100 * 40, + 100 + ) + ); + // Mock the reward pool transferring the payout to del_40 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 40)); + + // When + let payout = + Pools::calculate_member_payout(&mut del_50, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 50); // (50 del virtual points / 50 pool points) * 50 pool balance + assert_eq!(del_50, del(50, 100)); + assert_eq!(reward_pool, rew(0, 0, 100)); + // Mock the reward pool transferring the payout to del_50 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 50)); + + // Given the reward pool has some new rewards + Balances::make_free_balance_be(&default_reward_account(), ed + 50); + + // When + let payout = + Pools::calculate_member_payout(&mut del_10, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 5); // (500 del virtual points / 5,000 pool points) * 50 pool balance + assert_eq!(del_10, del(10, 150)); + assert_eq!(reward_pool, rew(45, 5_000 - 50 * 10, 150)); + // Mock the reward pool transferring the payout to del_10 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 5)); + + // When + let payout = + Pools::calculate_member_payout(&mut del_40, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 20); // (2,000 del virtual points / 4,500 pool points) * 45 pool balance + assert_eq!(del_40, del(40, 150)); + assert_eq!(reward_pool, rew(25, 4_500 - 50 * 40, 150)); + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 20)); + + // Given del_50 hasn't claimed and the reward pools has just earned 50 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 75); + + // When + let payout = + Pools::calculate_member_payout(&mut del_50, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 50); // (5,000 del virtual points / 7,5000 pool points) * 75 pool balance + assert_eq!(del_50, del(50, 200)); + assert_eq!( + reward_pool, + rew( + 25, + // old pool points + points from new earnings - del points. + // + // points from new earnings = new earnings(50) * bonded_pool.points(100) + // del points = member.points(50) * new_earnings_since_last_claim (100) + (2_500 + 50 * 100) - 50 * 100, + 200, + ) + ); + // Mock the reward pool transferring the payout to del_50 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 50)); + + // When + let payout = + Pools::calculate_member_payout(&mut del_10, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 5); + assert_eq!(del_10, del(10, 200)); + assert_eq!(reward_pool, rew(20, 2_500 - 10 * 50, 200)); + // Mock the reward pool transferring the payout to del_10 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 5)); + + // Given del_40 hasn't claimed and the reward pool has just earned 400 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 400)); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 420); + + // When + let payout = + Pools::calculate_member_payout(&mut del_10, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 40); + assert_eq!(del_10, del(10, 600)); + assert_eq!( + reward_pool, + rew( + 380, + // old pool points + points from new earnings - del points + // + // points from new earnings = new earnings(400) * bonded_pool.points(100) + // del points = member.points(10) * new_earnings_since_last_claim(400) + (2_000 + 400 * 100) - 10 * 400, + 600 + ) + ); + // Mock the reward pool transferring the payout to del_10 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 40)); + + // Given del_40 + del_50 haven't claimed and the reward pool has earned 20 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 20)); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 400); + + // When + let payout = + Pools::calculate_member_payout(&mut del_10, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 2); // (200 del virtual points / 38,000 pool points) * 400 pool balance + assert_eq!(del_10, del(10, 620)); + assert_eq!(reward_pool, rew(398, (38_000 + 20 * 100) - 10 * 20, 620)); + // Mock the reward pool transferring the payout to del_10 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 2)); + + // When + let payout = + Pools::calculate_member_payout(&mut del_40, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 188); // (18,800 del virtual points / 39,800 pool points) * 399 pool balance + assert_eq!(del_40, del(40, 620)); + assert_eq!(reward_pool, rew(210, 39_800 - 40 * 470, 620)); + // Mock the reward pool transferring the payout to del_10 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 188)); + + // When + let payout = + Pools::calculate_member_payout(&mut del_50, &mut bonded_pool, &mut reward_pool) + .unwrap(); + + // Then + assert_eq!(payout, 210); // (21,000 / 21,000) * 210 + assert_eq!(del_50, del(50, 620)); + assert_eq!(reward_pool, rew(0, 21_000 - 50 * 420, 620)); + }); + } + + #[test] + fn do_reward_payout_works() { + ExtBuilder::default() + .add_members(vec![(40, 40), (50, 50)]) + .build_and_execute(|| { + let mut bonded_pool = BondedPool::::get(1).unwrap(); + let mut reward_pool = RewardPools::::get(1).unwrap(); + let ed = Balances::minimum_balance(); + + // Given the bonded pool has 100 points + assert_eq!(bonded_pool.points, 100); + // Each member currently has a free balance of + Balances::make_free_balance_be(&10, 0); + Balances::make_free_balance_be(&40, 0); + Balances::make_free_balance_be(&50, 0); + // and the reward pool has earned 100 in rewards + Balances::make_free_balance_be(&default_reward_account(), ed + 100); + + let mut del_10 = PoolMembers::get(10).unwrap(); + let mut del_40 = PoolMembers::get(40).unwrap(); + let mut del_50 = PoolMembers::get(50).unwrap(); + + // When + assert_ok!(Pools::do_reward_payout( + &10, + &mut del_10, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // Expect a payout of 10: (10 del virtual points / 100 pool points) * 100 pool + // balance + assert_eq!(del_10, del(10, 100)); + assert_eq!(reward_pool, rew(90, 100 * 100 - 100 * 10, 100)); + assert_eq!(Balances::free_balance(&10), 10); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 90); + + // When + assert_ok!(Pools::do_reward_payout( + &40, + &mut del_40, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // Expect payout 40: (400 del virtual points / 900 pool points) * 90 pool balance + assert_eq!(del_40, del(40, 100)); + assert_eq!(reward_pool, rew(50, 9_000 - 100 * 40, 100)); + assert_eq!(Balances::free_balance(&40), 40); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 50); + + // When + assert_ok!(Pools::do_reward_payout( + &50, + &mut del_50, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // Expect payout 50: (50 del virtual points / 50 pool points) * 50 pool balance + assert_eq!(del_50, del(50, 100)); + assert_eq!(reward_pool, rew(0, 0, 100)); + assert_eq!(Balances::free_balance(&50), 50); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 0); + + // Given the reward pool has some new rewards + Balances::make_free_balance_be(&default_reward_account(), ed + 50); + + // When + assert_ok!(Pools::do_reward_payout( + &10, + &mut del_10, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // Expect payout 5: (500 del virtual points / 5,000 pool points) * 50 pool balance + assert_eq!(del_10, del(10, 150)); + assert_eq!(reward_pool, rew(45, 5_000 - 50 * 10, 150)); + assert_eq!(Balances::free_balance(&10), 10 + 5); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 45); + + // When + assert_ok!(Pools::do_reward_payout( + &40, + &mut del_40, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // Expect payout 20: (2,000 del virtual points / 4,500 pool points) * 45 pool + // balance + assert_eq!(del_40, del(40, 150)); + assert_eq!(reward_pool, rew(25, 4_500 - 50 * 40, 150)); + assert_eq!(Balances::free_balance(&40), 40 + 20); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); + + // Given del 50 hasn't claimed and the reward pools has just earned 50 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 75); + + // When + assert_ok!(Pools::do_reward_payout( + &50, + &mut del_50, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // We expect a payout of 50: (5,000 del virtual points / 7,5000 pool points) * 75 + // pool balance + assert_eq!(del_50, del(50, 200)); + assert_eq!( + reward_pool, + rew( + 25, + // old pool points + points from new earnings - del points. + // + // points from new earnings = new earnings(50) * bonded_pool.points(100) + // del points = member.points(50) * new_earnings_since_last_claim (100) + (2_500 + 50 * 100) - 50 * 100, + 200, + ) + ); + assert_eq!(Balances::free_balance(&50), 50 + 50); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); + + // When + assert_ok!(Pools::do_reward_payout( + &10, + &mut del_10, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // We expect a payout of 5 + assert_eq!(del_10, del(10, 200)); + assert_eq!(reward_pool, rew(20, 2_500 - 10 * 50, 200)); + assert_eq!(Balances::free_balance(&10), 15 + 5); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 20); + + // Given del 40 hasn't claimed and the reward pool has just earned 400 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 400)); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 420); + + // When + assert_ok!(Pools::do_reward_payout( + &10, + &mut del_10, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // We expect a payout of 40 + assert_eq!(del_10, del(10, 600)); + assert_eq!( + reward_pool, + rew( + 380, + // old pool points + points from new earnings - del points + // + // points from new earnings = new earnings(400) * bonded_pool.points(100) + // del points = member.points(10) * new_earnings_since_last_claim(400) + (2_000 + 400 * 100) - 10 * 400, + 600 + ) + ); + assert_eq!(Balances::free_balance(&10), 20 + 40); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 380); + + // Given del 40 + del 50 haven't claimed and the reward pool has earned 20 + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 20)); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 400); + + // When + assert_ok!(Pools::do_reward_payout( + &10, + &mut del_10, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // Expect a payout of 2: (200 del virtual points / 38,000 pool points) * 400 pool + // balance + assert_eq!(del_10, del(10, 620)); + assert_eq!(reward_pool, rew(398, (38_000 + 20 * 100) - 10 * 20, 620)); + assert_eq!(Balances::free_balance(&10), 60 + 2); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 398); + + // When + assert_ok!(Pools::do_reward_payout( + &40, + &mut del_40, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // Expect a payout of 188: (18,800 del virtual points / 39,800 pool points) * 399 + // pool balance + assert_eq!(del_40, del(40, 620)); + assert_eq!(reward_pool, rew(210, 39_800 - 40 * 470, 620)); + assert_eq!(Balances::free_balance(&40), 60 + 188); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 210); + + // When + assert_ok!(Pools::do_reward_payout( + &50, + &mut del_50, + &mut bonded_pool, + &mut reward_pool + )); + + // Then + // Expect payout of 210: (21,000 / 21,000) * 210 + assert_eq!(del_50, del(50, 620)); + assert_eq!(reward_pool, rew(0, 21_000 - 50 * 420, 620)); + assert_eq!(Balances::free_balance(&50), 100 + 210); + assert_eq!(Balances::free_balance(&default_reward_account()), ed + 0); + }); + } +} + +mod unbond { + use super::*; + + #[test] + fn unbond_of_1_works() { + ExtBuilder::default().build_and_execute(|| { + unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(fully_unbond_permissioned(10)); + + assert_eq!( + SubPoolsStorage::::get(1).unwrap().with_era, + unbonding_pools_with_era! { 0 + 3 => UnbondPool:: { points: 10, balance: 10 }} + ); + + assert_eq!( + BondedPool::::get(1).unwrap(), + BondedPool { + id: 1, + inner: BondedPoolInner { + state: PoolState::Destroying, + points: 0, + member_counter: 1, + roles: DEFAULT_ROLES, + } + } + ); + + assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 0); + }); + } + + #[test] + fn unbond_of_3_works() { + ExtBuilder::default() + .add_members(vec![(40, 40), (550, 550)]) + .build_and_execute(|| { + let ed = Balances::minimum_balance(); + // Given a slash from 600 -> 100 + StakingMock::set_bonded_balance(default_bonded_account(), 100); + // and unclaimed rewards of 600. + Balances::make_free_balance_be(&default_reward_account(), ed + 600); + + // When + assert_ok!(fully_unbond_permissioned(40)); + + // Then + assert_eq!( + SubPoolsStorage::::get(1).unwrap().with_era, + unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 6, balance: 6 }} + ); + assert_eq!( + BondedPool::::get(1).unwrap(), + BondedPool { + id: 1, + inner: BondedPoolInner { + state: PoolState::Open, + points: 560, + member_counter: 3, + roles: DEFAULT_ROLES, + } + } + ); + + assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 94); + assert_eq!( + PoolMembers::::get(40).unwrap().unbonding_eras, + member_unbonding_eras!(0 + 3 => 40) + ); + assert_eq!(Balances::free_balance(&40), 40 + 40); // We claim rewards when unbonding + + // When + unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(fully_unbond_permissioned(550)); + + // Then + assert_eq!( + SubPoolsStorage::::get(&1).unwrap().with_era, + unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 98, balance: 98 }} + ); + assert_eq!( + BondedPool::::get(1).unwrap(), + BondedPool { + id: 1, + inner: BondedPoolInner { + state: PoolState::Destroying, + points: 10, + member_counter: 3, + roles: DEFAULT_ROLES + } + } + ); + assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 2); + assert_eq!( + PoolMembers::::get(550).unwrap().unbonding_eras, + member_unbonding_eras!(0 + 3 => 550) + ); + assert_eq!(Balances::free_balance(&550), 550 + 550); + + // When + assert_ok!(fully_unbond_permissioned(10)); + + // Then + assert_eq!( + SubPoolsStorage::::get(1).unwrap().with_era, + unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 100, balance: 100 }} + ); + assert_eq!( + BondedPool::::get(1).unwrap(), + BondedPool { + id: 1, + inner: BondedPoolInner { + state: PoolState::Destroying, + points: 0, + member_counter: 3, + roles: DEFAULT_ROLES + } + } + ); + assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 0); + assert_eq!( + PoolMembers::::get(550).unwrap().unbonding_eras, + member_unbonding_eras!(0 + 3 => 550) + ); + assert_eq!(Balances::free_balance(&550), 550 + 550); + }); + } + + #[test] + fn unbond_merges_older_pools() { + ExtBuilder::default().with_check(1).build_and_execute(|| { + // Given + assert_eq!(StakingMock::bonding_duration(), 3); + SubPoolsStorage::::insert( + 1, + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 0 + 3 => UnbondPool { balance: 10, points: 100 }, + 1 + 3 => UnbondPool { balance: 20, points: 20 }, + 2 + 3 => UnbondPool { balance: 101, points: 101} + }, + }, + ); + unsafe_set_state(1, PoolState::Destroying).unwrap(); + + // When + let current_era = 1 + TotalUnbondingPools::::get(); + CurrentEra::set(current_era); + + assert_ok!(fully_unbond_permissioned(10)); + + // Then + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: UnbondPool { balance: 10 + 20, points: 100 + 20 }, + with_era: unbonding_pools_with_era! { + 2 + 3 => UnbondPool { balance: 101, points: 101}, + current_era + 3 => UnbondPool { balance: 10, points: 10 }, + }, + }, + ) + }); + } + + #[test] + fn unbond_kick_works() { + // Kick: the pool is blocked and the caller is either the root or state-toggler. + ExtBuilder::default() + .add_members(vec![(100, 100), (200, 200)]) + .build_and_execute(|| { + // Given + unsafe_set_state(1, PoolState::Blocked).unwrap(); + let bonded_pool = BondedPool::::get(1).unwrap(); + assert_eq!(bonded_pool.roles.root, 900); + assert_eq!(bonded_pool.roles.nominator, 901); + assert_eq!(bonded_pool.roles.state_toggler, 902); + + // When the nominator trys to kick, then its a noop + assert_noop!( + Pools::fully_unbond(Origin::signed(901), 100), + Error::::NotKickerOrDestroying + ); + + // When the root kicks then its ok + assert_ok!(Pools::fully_unbond(Origin::signed(900), 100)); + + // When the state toggler kicks then its ok + assert_ok!(Pools::fully_unbond(Origin::signed(902), 200)); + + assert_eq!( + BondedPool::::get(1).unwrap(), + BondedPool { + id: 1, + inner: BondedPoolInner { + roles: DEFAULT_ROLES, + state: PoolState::Blocked, + points: 10, // Only 10 points because 200 + 100 was unbonded + member_counter: 3, + } + } + ); + assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 10); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 0 + 3 => UnbondPool { points: 100 + 200, balance: 100 + 200 } + }, + } + ); + assert_eq!( + UNBONDING_BALANCE_MAP + .with(|m| *m.borrow_mut().get(&default_bonded_account()).unwrap()), + 100 + 200 + ); + }); + } + + #[test] + fn unbond_permissionless_works() { + // Scenarios where non-admin accounts can unbond others + ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { + // Given the pool is blocked + unsafe_set_state(1, PoolState::Blocked).unwrap(); + + // A permissionless unbond attempt errors + assert_noop!( + Pools::fully_unbond(Origin::signed(420), 100), + Error::::NotKickerOrDestroying + ); + + // Given the pool is destroying + unsafe_set_state(1, PoolState::Destroying).unwrap(); + + // The depositor cannot be fully unbonded until they are the last member + assert_noop!( + Pools::fully_unbond(Origin::signed(10), 10), + Error::::NotOnlyPoolMember + ); + + // Any account can unbond a member that is not the depositor + assert_ok!(Pools::fully_unbond(Origin::signed(420), 100)); + + // Given the pool is blocked + unsafe_set_state(1, PoolState::Blocked).unwrap(); + + // The depositor cannot be unbonded + assert_noop!( + Pools::fully_unbond(Origin::signed(420), 10), + Error::::DoesNotHavePermission + ); + + // Given the pools is destroying + unsafe_set_state(1, PoolState::Destroying).unwrap(); + + // The depositor can be unbonded by anyone. + assert_ok!(Pools::fully_unbond(Origin::signed(420), 10)); + + assert_eq!(BondedPools::::get(1).unwrap().points, 0); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 0 + 3 => UnbondPool { points: 110, balance: 110 } + } + } + ); + assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 0); + assert_eq!( + UNBONDING_BALANCE_MAP + .with(|m| *m.borrow_mut().get(&default_bonded_account()).unwrap()), + 110 + ); + }); + } + + #[test] + #[cfg_attr(debug_assertions, should_panic(expected = "Defensive failure has been triggered!"))] + #[cfg_attr(not(debug_assertions), should_panic)] + fn unbond_errors_correctly() { + ExtBuilder::default().build_and_execute(|| { + assert_noop!( + Pools::fully_unbond(Origin::signed(11), 11), + Error::::PoolMemberNotFound + ); + + // Add the member + let member = PoolMember { pool_id: 2, points: 10, ..Default::default() }; + PoolMembers::::insert(11, member); + + let _ = Pools::fully_unbond(Origin::signed(11), 11); + }); + } + + #[test] + #[cfg_attr(debug_assertions, should_panic(expected = "Defensive failure has been triggered!"))] + #[cfg_attr(not(debug_assertions), should_panic)] + fn unbond_panics_when_reward_pool_not_found() { + ExtBuilder::default().build_and_execute(|| { + let member = PoolMember { pool_id: 2, points: 10, ..Default::default() }; + PoolMembers::::insert(11, member); + BondedPool:: { + id: 1, + inner: BondedPoolInner { + state: PoolState::Open, + points: 10, + member_counter: 1, + roles: DEFAULT_ROLES, + }, + } + .put(); + + let _ = Pools::fully_unbond(Origin::signed(11), 11); + }); + } + + #[test] + fn partial_unbond_era_tracking() { + ExtBuilder::default().build_and_execute(|| { + // given + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 10); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 0); + assert_eq!(PoolMembers::::get(10).unwrap().pool_id, 1); + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!() + ); + assert_eq!(BondedPool::::get(1).unwrap().points, 10); + assert!(SubPoolsStorage::::get(1).is_none()); + assert_eq!(CurrentEra::get(), 0); + assert_eq!(BondingDuration::get(), 3); + + // so the depositor can leave, just keeps the test simpler. + unsafe_set_state(1, PoolState::Destroying).unwrap(); + + // when: casual unbond + assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + + // then + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 9); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 1); + assert_eq!(BondedPool::::get(1).unwrap().points, 9); + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 1) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 1, balance: 1 } + } + } + ); + + // when: casual further unbond, same era. + assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + + // then + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 4); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 6); + assert_eq!(BondedPool::::get(1).unwrap().points, 4); + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 6) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 6, balance: 6 } + } + } + ); + + // when: casual further unbond, next era. + CurrentEra::set(1); + assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + + // then + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 3); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 7); + assert_eq!(BondedPool::::get(1).unwrap().points, 3); + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 6, 4 => 1) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 6, balance: 6 }, + 4 => UnbondPool { points: 1, balance: 1 } + } + } + ); + + // when: unbonding more than our active: error + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 5), + Error::::NotEnoughPointsToUnbond + ); + // instead: + assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + + // then + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 0); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 10); + assert_eq!(BondedPool::::get(1).unwrap().points, 0); + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 6, 4 => 4) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 6, balance: 6 }, + 4 => UnbondPool { points: 4, balance: 4 } + } + } + ); + }); + } + + #[test] + fn partial_unbond_max_chunks() { + ExtBuilder::default().ed(1).build_and_execute(|| { + // so the depositor can leave, just keeps the test simpler. + unsafe_set_state(1, PoolState::Destroying).unwrap(); + MaxUnbonding::set(2); + + // given + assert_ok!(Pools::unbond(Origin::signed(10), 10, 2)); + CurrentEra::set(1); + assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 2, 4 => 3) + ); + + // when + CurrentEra::set(2); + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 4), + Error::::MaxUnbondingLimit + ); + + // when + MaxUnbonding::set(3); + assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 2, 4 => 3, 5 => 1) + ); + }) + } + + // depositor can unbond inly up to `MinCreateBond`. + #[test] + fn depositor_permissioned_partial_unbond() { + ExtBuilder::default().ed(1).add_members(vec![(100, 100)]).build_and_execute(|| { + // given + assert_eq!(MinCreateBond::::get(), 2); + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 10); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 0); + + // can unbond a bit.. + assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 7); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 3); + + // but not less than 2 + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 6), + Error::::NotOnlyPoolMember + ); + }); + } + + // same as above, but the pool is slashed and therefore the depositor cannot partially unbond. + #[test] + fn depositor_permissioned_partial_unbond_slashed() { + ExtBuilder::default().ed(1).add_members(vec![(100, 100)]).build_and_execute(|| { + // given + assert_eq!(MinCreateBond::::get(), 2); + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 10); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 0); + + // slash the default pool + StakingMock::set_bonded_balance(Pools::create_bonded_account(1), 5); + + // cannot unbond even 7, because the value of shares is now less. + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 7), + Error::::NotOnlyPoolMember + ); + }); + } +} + +mod pool_withdraw_unbonded { + use super::*; + + #[test] + fn pool_withdraw_unbonded_works() { + ExtBuilder::default().build_and_execute(|| { + // Given 10 unbond'ed directly against the pool account + assert_ok!(StakingMock::unbond(default_bonded_account(), 5)); + // and the pool account only has 10 balance + assert_eq!(StakingMock::active_stake(&default_bonded_account()), Some(5)); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Some(10)); + assert_eq!(Balances::free_balance(&default_bonded_account()), 10); + + // When + assert_ok!(Pools::pool_withdraw_unbonded(Origin::signed(10), 1, 0)); + + // Then there unbonding balance is no longer locked + assert_eq!(StakingMock::active_stake(&default_bonded_account()), Some(5)); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Some(5)); + assert_eq!(Balances::free_balance(&default_bonded_account()), 10); + }); + } +} + +mod withdraw_unbonded { + use super::*; + use frame_support::bounded_btree_map; + + #[test] + fn withdraw_unbonded_works_against_slashed_no_era_sub_pool() { + ExtBuilder::default() + .add_members(vec![(40, 40), (550, 550)]) + .build_and_execute(|| { + // Given + assert_eq!(StakingMock::bonding_duration(), 3); + assert_ok!(Pools::fully_unbond(Origin::signed(550), 550)); + assert_ok!(Pools::fully_unbond(Origin::signed(40), 40)); + assert_eq!(Balances::free_balance(&default_bonded_account()), 600); + + let mut current_era = 1; + CurrentEra::set(current_era); + // In a new era, unbond the depositor + unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + + let mut sub_pools = SubPoolsStorage::::get(1).unwrap(); + let unbond_pool = sub_pools.with_era.get_mut(&(current_era + 3)).unwrap(); + // Sanity check + assert_eq!(*unbond_pool, UnbondPool { points: 10, balance: 10 }); + + // Simulate a slash to the pool with_era(current_era), decreasing the balance by + // half + unbond_pool.balance = 5; + SubPoolsStorage::::insert(1, sub_pools); + // Update the equivalent of the unbonding chunks for the `StakingMock` + UNBONDING_BALANCE_MAP + .with(|m| *m.borrow_mut().get_mut(&default_bonded_account()).unwrap() -= 5); + Balances::make_free_balance_be(&default_bonded_account(), 595); + + // Advance the current_era to ensure all `with_era` pools will be merged into + // `no_era` pool + current_era += TotalUnbondingPools::::get(); + CurrentEra::set(current_era); + + // Simulate some other call to unbond that would merge `with_era` pools into + // `no_era` + let sub_pools = + SubPoolsStorage::::get(1).unwrap().maybe_merge_pools(current_era + 3); + SubPoolsStorage::::insert(1, sub_pools); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: UnbondPool { points: 550 + 40 + 10, balance: 550 + 40 + 5 }, + with_era: Default::default() + } + ); + + // When + assert_ok!(Pools::withdraw_unbonded(Origin::signed(550), 550, 0)); + + // Then + assert_eq!( + SubPoolsStorage::::get(1).unwrap().no_era, + UnbondPool { points: 40 + 10, balance: 40 + 5 + 5 } + ); + assert_eq!(Balances::free_balance(&550), 550 + 545); + assert_eq!(Balances::free_balance(&default_bonded_account()), 50); + assert!(!PoolMembers::::contains_key(550)); + + // When + assert_ok!(Pools::withdraw_unbonded(Origin::signed(40), 40, 0)); + + // Then + assert_eq!( + SubPoolsStorage::::get(1).unwrap().no_era, + UnbondPool { points: 10, balance: 10 } + ); + assert_eq!(Balances::free_balance(&40), 40 + 40); + assert_eq!(Balances::free_balance(&default_bonded_account()), 50 - 40); + assert!(!PoolMembers::::contains_key(40)); + + // When + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + + // Then + assert_eq!(Balances::free_balance(&10), 10 + 10); + assert_eq!(Balances::free_balance(&default_bonded_account()), 0); + assert!(!PoolMembers::::contains_key(10)); + // Pools are removed from storage because the depositor left + assert!(!SubPoolsStorage::::contains_key(1),); + assert!(!RewardPools::::contains_key(1),); + assert!(!BondedPools::::contains_key(1),); + }); + } + + // This test also documents the case when the pools free balance goes below ED before all + // members have unbonded. + #[test] + fn withdraw_unbonded_works_against_slashed_with_era_sub_pools() { + ExtBuilder::default() + .add_members(vec![(40, 40), (550, 550)]) + .build_and_execute(|| { + // Given + StakingMock::set_bonded_balance(default_bonded_account(), 100); // slash bonded balance + Balances::make_free_balance_be(&default_bonded_account(), 100); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Some(100)); + + assert_ok!(Pools::fully_unbond(Origin::signed(40), 40)); + assert_ok!(Pools::fully_unbond(Origin::signed(550), 550)); + unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + + SubPoolsStorage::::insert( + 1, + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 600, balance: 100 }}, + }, + ); + CurrentEra::set(StakingMock::bonding_duration()); + + // When + assert_ok!(Pools::withdraw_unbonded(Origin::signed(40), 40, 0)); + + // Then + assert_eq!( + SubPoolsStorage::::get(&1).unwrap().with_era, + unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 560, balance: 94 }} + ); + assert_eq!(Balances::free_balance(&40), 40 + 6); + assert_eq!(Balances::free_balance(&default_bonded_account()), 94); + assert!(!PoolMembers::::contains_key(40)); + + // When + assert_ok!(Pools::withdraw_unbonded(Origin::signed(550), 550, 0)); + + // Then + assert_eq!( + SubPoolsStorage::::get(&1).unwrap().with_era, + unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 10, balance: 2 }} + ); + assert_eq!(Balances::free_balance(&550), 550 + 92); + // The account was dusted because it went below ED(5) + assert_eq!(Balances::free_balance(&default_bonded_account()), 0); + assert!(!PoolMembers::::contains_key(550)); + + // When + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + + // Then + assert_eq!(Balances::free_balance(&10), 10 + 0); + assert_eq!(Balances::free_balance(&default_bonded_account()), 0); + assert!(!PoolMembers::::contains_key(10)); + // Pools are removed from storage because the depositor left + assert!(!SubPoolsStorage::::contains_key(1),); + assert!(!RewardPools::::contains_key(1),); + assert!(!BondedPools::::contains_key(1),); + }); + } + + #[test] + fn withdraw_unbonded_handles_faulty_sub_pool_accounting() { + ExtBuilder::default().build_and_execute(|| { + // Given + assert_eq!(Balances::minimum_balance(), 5); + assert_eq!(Balances::free_balance(&10), 5); + assert_eq!(Balances::free_balance(&default_bonded_account()), 10); + unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + + // Simulate a slash that is not accounted for in the sub pools. + Balances::make_free_balance_be(&default_bonded_account(), 5); + assert_eq!( + SubPoolsStorage::::get(1).unwrap().with_era, + //------------------------------balance decrease is not account for + unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 10, balance: 10 } } + ); + + CurrentEra::set(0 + 3); + + // When + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + + // Then + assert_eq!(Balances::free_balance(10), 10 + 5); + assert_eq!(Balances::free_balance(&default_bonded_account()), 0); + }); + } + + #[test] + fn withdraw_unbonded_errors_correctly() { + ExtBuilder::default().with_check(0).build_and_execute(|| { + // Insert the sub-pool + let sub_pools = SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 10, balance: 10 }}, + }; + SubPoolsStorage::::insert(1, sub_pools.clone()); + + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Error::::PoolMemberNotFound + ); + + let mut member = PoolMember { pool_id: 1, points: 10, ..Default::default() }; + PoolMembers::::insert(11, member.clone()); + + // Simulate calling `unbond` + member.unbonding_eras = member_unbonding_eras!(3 + 0 => 10); + PoolMembers::::insert(11, member.clone()); + + // We are still in the bonding duration + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Error::::CannotWithdrawAny + ); + + // If we error the member does not get removed + assert_eq!(PoolMembers::::get(&11), Some(member)); + // and the sub pools do not get updated. + assert_eq!(SubPoolsStorage::::get(1).unwrap(), sub_pools) + }); + } + + #[test] + fn withdraw_unbonded_kick() { + ExtBuilder::default() + .add_members(vec![(100, 100), (200, 200)]) + .build_and_execute(|| { + // Given + assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); + assert_ok!(Pools::fully_unbond(Origin::signed(200), 200)); + assert_eq!( + BondedPool::::get(1).unwrap(), + BondedPool { + id: 1, + inner: BondedPoolInner { + points: 10, + state: PoolState::Open, + member_counter: 3, + roles: DEFAULT_ROLES + } + } + ); + CurrentEra::set(StakingMock::bonding_duration()); + + // Cannot kick when pool is open + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(902), 100, 0), + Error::::NotKickerOrDestroying + ); + + // Given + unsafe_set_state(1, PoolState::Blocked).unwrap(); + + // Cannot kick as a nominator + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(901), 100, 0), + Error::::NotKickerOrDestroying + ); + + // Can kick as root + assert_ok!(Pools::withdraw_unbonded(Origin::signed(900), 100, 0)); + + // Can kick as state toggler + assert_ok!(Pools::withdraw_unbonded(Origin::signed(900), 200, 0)); + + assert_eq!(Balances::free_balance(100), 100 + 100); + assert_eq!(Balances::free_balance(200), 200 + 200); + assert!(!PoolMembers::::contains_key(100)); + assert!(!PoolMembers::::contains_key(200)); + assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default()); + }); + } + + #[test] + fn withdraw_unbonded_destroying_permissionless() { + ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { + // Given + assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); + assert_eq!( + BondedPool::::get(1).unwrap(), + BondedPool { + id: 1, + inner: BondedPoolInner { + points: 10, + state: PoolState::Open, + member_counter: 2, + roles: DEFAULT_ROLES, + } + } + ); + CurrentEra::set(StakingMock::bonding_duration()); + assert_eq!(Balances::free_balance(100), 100); + + // Cannot permissionlessly withdraw + assert_noop!( + Pools::fully_unbond(Origin::signed(420), 100), + Error::::NotKickerOrDestroying + ); + + // Given + unsafe_set_state(1, PoolState::Destroying).unwrap(); + + // Can permissionlesly withdraw a member that is not the depositor + assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 100, 0)); + + assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default(),); + assert_eq!(Balances::free_balance(100), 100 + 100); + assert!(!PoolMembers::::contains_key(100)); + }); + } + + #[test] + fn withdraw_unbonded_depositor_with_era_pool() { + ExtBuilder::default() + .add_members(vec![(100, 100), (200, 200)]) + .build_and_execute(|| { + // Given + assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); + + let mut current_era = 1; + CurrentEra::set(current_era); + + assert_ok!(Pools::fully_unbond(Origin::signed(200), 200)); + unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 0 + 3 => UnbondPool { points: 100, balance: 100}, + 1 + 3 => UnbondPool { points: 200 + 10, balance: 200 + 10 } + } + } + ); + + // Skip ahead eras to where its valid for the members to withdraw + current_era += StakingMock::bonding_duration(); + CurrentEra::set(current_era); + + // Cannot withdraw the depositor if their is a member in another `with_era` pool. + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(420), 10, 0), + Error::::NotOnlyPoolMember + ); + + // Given + assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 100, 0)); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + // Note that era 0+3 unbond pool is destroyed because points went to 0 + 1 + 3 => UnbondPool { points: 200 + 10, balance: 200 + 10 } + } + } + ); + + // Cannot withdraw the depositor if their is a member in another `with_era` pool. + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(420), 10, 0), + Error::::NotOnlyPoolMember + ); + + // Given + assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 200, 0)); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 1 + 3 => UnbondPool { points: 10, balance: 10 } + } + } + ); + + // The depositor can withdraw + assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 10, 0)); + assert!(!PoolMembers::::contains_key(10)); + assert_eq!(Balances::free_balance(10), 10 + 10); + // Pools are removed from storage because the depositor left + assert!(!SubPoolsStorage::::contains_key(1)); + assert!(!RewardPools::::contains_key(1)); + assert!(!BondedPools::::contains_key(1)); + }); + } + + #[test] + fn withdraw_unbonded_depositor_no_era_pool() { + ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { + // Given + assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); + unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + // Skip ahead to an era where the `with_era` pools can get merged into the `no_era` + // pool. + let current_era = TotalUnbondingPools::::get(); + CurrentEra::set(current_era); + + // Simulate some other withdraw that caused the pool to merge + let sub_pools = + SubPoolsStorage::::get(1).unwrap().maybe_merge_pools(current_era + 3); + SubPoolsStorage::::insert(1, sub_pools); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: UnbondPool { points: 100 + 10, balance: 100 + 10 }, + with_era: Default::default(), + } + ); + + // Cannot withdraw depositor with another member in the `no_era` pool + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(420), 10, 0), + Error::::NotOnlyPoolMember + ); + + // Given + assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 100, 0)); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: UnbondPool { points: 10, balance: 10 }, + with_era: Default::default(), + } + ); + + // The depositor can withdraw + assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 10, 0)); + assert!(!PoolMembers::::contains_key(10)); + assert_eq!(Balances::free_balance(10), 10 + 10); + // Pools are removed from storage because the depositor left + assert!(!SubPoolsStorage::::contains_key(1)); + assert!(!RewardPools::::contains_key(1)); + assert!(!BondedPools::::contains_key(1)); + }); + } + + #[test] + fn partial_withdraw_unbonded_depositor() { + ExtBuilder::default().ed(1).build_and_execute(|| { + // so the depositor can leave, just keeps the test simpler. + unsafe_set_state(1, PoolState::Destroying).unwrap(); + + // given + assert_ok!(Pools::unbond(Origin::signed(10), 10, 6)); + CurrentEra::set(1); + assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 6, 4 => 1) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 6, balance: 6 }, + 4 => UnbondPool { points: 1, balance: 1 } + } + } + ); + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 3); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 7); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 0 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 6 }, + Event::PaidOut { member: 10, pool_id: 1, payout: 0 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 1 } + ] + ); + + // when + CurrentEra::set(2); + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(10), 10, 0), + Error::::CannotWithdrawAny + ); + + // when + CurrentEra::set(3); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + + // then + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(4 => 1) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 4 => UnbondPool { points: 1, balance: 1 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Withdrawn { member: 10, pool_id: 1, amount: 6 }] + ); + + // when + CurrentEra::set(4); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + + // then + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!() + ); + assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default()); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Withdrawn { member: 10, pool_id: 1, amount: 1 },] + ); + + // when repeating: + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(10), 10, 0), + Error::::CannotWithdrawAny + ); + }); + } + + #[test] + fn partial_withdraw_unbonded_non_depositor() { + ExtBuilder::default().add_members(vec![(11, 10)]).build_and_execute(|| { + // given + assert_ok!(Pools::unbond(Origin::signed(11), 11, 6)); + CurrentEra::set(1); + assert_ok!(Pools::unbond(Origin::signed(11), 11, 1)); + assert_eq!( + PoolMembers::::get(11).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 6, 4 => 1) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 6, balance: 6 }, + 4 => UnbondPool { points: 1, balance: 1 } + } + } + ); + assert_eq!(PoolMembers::::get(11).unwrap().active_points(), 3); + assert_eq!(PoolMembers::::get(11).unwrap().unbonding_points(), 7); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 11, pool_id: 1, bonded: 10, joined: true }, + Event::PaidOut { member: 11, pool_id: 1, payout: 0 }, + Event::Unbonded { member: 11, pool_id: 1, amount: 6 }, + Event::PaidOut { member: 11, pool_id: 1, payout: 0 }, + Event::Unbonded { member: 11, pool_id: 1, amount: 1 } + ] + ); + + // when + CurrentEra::set(2); + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Error::::CannotWithdrawAny + ); + + // when + CurrentEra::set(3); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(11), 11, 0)); + + // then + assert_eq!( + PoolMembers::::get(11).unwrap().unbonding_eras, + member_unbonding_eras!(4 => 1) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 4 => UnbondPool { points: 1, balance: 1 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Withdrawn { member: 11, pool_id: 1, amount: 6 }] + ); + + // when + CurrentEra::set(4); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(11), 11, 0)); + + // then + assert_eq!( + PoolMembers::::get(11).unwrap().unbonding_eras, + member_unbonding_eras!() + ); + assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default()); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Withdrawn { member: 11, pool_id: 1, amount: 1 }] + ); + + // when repeating: + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Error::::CannotWithdrawAny + ); + }); + } +} + +mod create { + use super::*; + + #[test] + fn create_works() { + ExtBuilder::default().build_and_execute(|| { + // next pool id is 2. + let next_pool_stash = Pools::create_bonded_account(2); + let ed = Balances::minimum_balance(); + + assert!(!BondedPools::::contains_key(2)); + assert!(!RewardPools::::contains_key(2)); + assert!(!PoolMembers::::contains_key(11)); + assert_eq!(StakingMock::active_stake(&next_pool_stash), None); + + Balances::make_free_balance_be(&11, StakingMock::minimum_bond() + ed); + assert_ok!(Pools::create( + Origin::signed(11), + StakingMock::minimum_bond(), + 123, + 456, + 789 + )); + + assert_eq!(Balances::free_balance(&11), 0); + assert_eq!( + PoolMembers::::get(11).unwrap(), + PoolMember { + pool_id: 2, + points: StakingMock::minimum_bond(), + ..Default::default() + } + ); + assert_eq!( + BondedPool::::get(2).unwrap(), + BondedPool { + id: 2, + inner: BondedPoolInner { + points: StakingMock::minimum_bond(), + member_counter: 1, + state: PoolState::Open, + roles: PoolRoles { + depositor: 11, + root: 123, + nominator: 456, + state_toggler: 789 + } + } + } + ); + assert_eq!( + StakingMock::active_stake(&next_pool_stash).unwrap(), + StakingMock::minimum_bond() + ); + assert_eq!( + RewardPools::::get(2).unwrap(), + RewardPool { + balance: Zero::zero(), + points: U256::zero(), + total_earnings: Zero::zero(), + } + ); + }); + } + + #[test] + fn create_errors_correctly() { + ExtBuilder::default().with_check(0).build_and_execute(|| { + assert_noop!( + Pools::create(Origin::signed(10), 420, 123, 456, 789), + Error::::AccountBelongsToOtherPool + ); + + // Given + assert_eq!(MinCreateBond::::get(), 2); + assert_eq!(StakingMock::minimum_bond(), 10); + + // Then + assert_noop!( + Pools::create(Origin::signed(11), 9, 123, 456, 789), + Error::::MinimumBondNotMet + ); + + // Given + MinCreateBond::::put(20); + + // Then + assert_noop!( + Pools::create(Origin::signed(11), 19, 123, 456, 789), + Error::::MinimumBondNotMet + ); + + // Given + BondedPool:: { + id: 2, + inner: BondedPoolInner { + state: PoolState::Open, + points: 10, + member_counter: 1, + roles: DEFAULT_ROLES, + }, + } + .put(); + assert_eq!(MaxPools::::get(), Some(2)); + assert_eq!(BondedPools::::count(), 2); + + // Then + assert_noop!( + Pools::create(Origin::signed(11), 20, 123, 456, 789), + Error::::MaxPools + ); + + // Given + assert_eq!(PoolMembers::::count(), 1); + MaxPools::::put(3); + MaxPoolMembers::::put(1); + Balances::make_free_balance_be(&11, 5 + 20); + + // Then + assert_noop!( + Pools::create(Origin::signed(11), 20, 11, 11, 11), + Error::::MaxPoolMembers + ); + }); + } +} + +mod nominate { + use super::*; + + #[test] + fn nominate_works() { + ExtBuilder::default().build_and_execute(|| { + // Depositor can't nominate + assert_noop!( + Pools::nominate(Origin::signed(10), 1, vec![21]), + Error::::NotNominator + ); + + // State toggler can't nominate + assert_noop!( + Pools::nominate(Origin::signed(902), 1, vec![21]), + Error::::NotNominator + ); + + // Root can nominate + assert_ok!(Pools::nominate(Origin::signed(900), 1, vec![21])); + assert_eq!(Nominations::get(), vec![21]); + + // Nominator can nominate + assert_ok!(Pools::nominate(Origin::signed(901), 1, vec![31])); + assert_eq!(Nominations::get(), vec![31]); + + // Can't nominate for a pool that doesn't exist + assert_noop!( + Pools::nominate(Origin::signed(902), 123, vec![21]), + Error::::PoolNotFound + ); + }); + } +} + +mod set_state { + use super::*; + + #[test] + fn set_state_works() { + ExtBuilder::default().build_and_execute(|| { + // Given + assert_ok!(BondedPool::::get(1).unwrap().ok_to_be_open(0)); + + // Only the root and state toggler can change the state when the pool is ok to be open. + assert_noop!( + Pools::set_state(Origin::signed(10), 1, PoolState::Blocked), + Error::::CanNotChangeState + ); + assert_noop!( + Pools::set_state(Origin::signed(901), 1, PoolState::Blocked), + Error::::CanNotChangeState + ); + + // Root can change state + assert_ok!(Pools::set_state(Origin::signed(900), 1, PoolState::Blocked)); + assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Blocked); + + // State toggler can change state + assert_ok!(Pools::set_state(Origin::signed(902), 1, PoolState::Destroying)); + assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); + + // If the pool is destroying, then no one can set state + assert_noop!( + Pools::set_state(Origin::signed(900), 1, PoolState::Blocked), + Error::::CanNotChangeState + ); + assert_noop!( + Pools::set_state(Origin::signed(902), 1, PoolState::Blocked), + Error::::CanNotChangeState + ); + + // If the pool is not ok to be open, then anyone can set it to destroying + + // Given + unsafe_set_state(1, PoolState::Open).unwrap(); + let mut bonded_pool = BondedPool::::get(1).unwrap(); + bonded_pool.points = 100; + bonded_pool.put(); + // When + assert_ok!(Pools::set_state(Origin::signed(11), 1, PoolState::Destroying)); + // Then + assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); + + // Given + Balances::make_free_balance_be(&default_bonded_account(), Balance::max_value() / 10); + unsafe_set_state(1, PoolState::Open).unwrap(); + // When + assert_ok!(Pools::set_state(Origin::signed(11), 1, PoolState::Destroying)); + // Then + assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); + + // If the pool is not ok to be open, it cannot be permissionleslly set to a state that + // isn't destroying + unsafe_set_state(1, PoolState::Open).unwrap(); + assert_noop!( + Pools::set_state(Origin::signed(11), 1, PoolState::Blocked), + Error::::CanNotChangeState + ); + }); + } +} + +mod set_metadata { + use super::*; + + #[test] + fn set_metadata_works() { + ExtBuilder::default().build_and_execute(|| { + // Root can set metadata + assert_ok!(Pools::set_metadata(Origin::signed(900), 1, vec![1, 1])); + assert_eq!(Metadata::::get(1), vec![1, 1]); + + // State toggler can set metadata + assert_ok!(Pools::set_metadata(Origin::signed(902), 1, vec![2, 2])); + assert_eq!(Metadata::::get(1), vec![2, 2]); + + // Depositor can't set metadata + assert_noop!( + Pools::set_metadata(Origin::signed(10), 1, vec![3, 3]), + Error::::DoesNotHavePermission + ); + + // Nominator can't set metadata + assert_noop!( + Pools::set_metadata(Origin::signed(901), 1, vec![3, 3]), + Error::::DoesNotHavePermission + ); + + // Metadata cannot be longer than `MaxMetadataLen` + assert_noop!( + Pools::set_metadata(Origin::signed(900), 1, vec![1, 1, 1]), + Error::::MetadataExceedsMaxLen + ); + }); + } +} + +mod set_configs { + use super::*; + + #[test] + fn set_configs_works() { + ExtBuilder::default().build_and_execute(|| { + // Setting works + assert_ok!(Pools::set_configs( + Origin::root(), + ConfigOp::Set(1 as Balance), + ConfigOp::Set(2 as Balance), + ConfigOp::Set(3u32), + ConfigOp::Set(4u32), + ConfigOp::Set(5u32), + )); + assert_eq!(MinJoinBond::::get(), 1); + assert_eq!(MinCreateBond::::get(), 2); + assert_eq!(MaxPools::::get(), Some(3)); + assert_eq!(MaxPoolMembers::::get(), Some(4)); + assert_eq!(MaxPoolMembersPerPool::::get(), Some(5)); + + // Noop does nothing + assert_storage_noop!(assert_ok!(Pools::set_configs( + Origin::root(), + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop, + ))); + + // Removing works + assert_ok!(Pools::set_configs( + Origin::root(), + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove + )); + assert_eq!(MinJoinBond::::get(), 0); + assert_eq!(MinCreateBond::::get(), 0); + assert_eq!(MaxPools::::get(), None); + assert_eq!(MaxPoolMembers::::get(), None); + assert_eq!(MaxPoolMembersPerPool::::get(), None); + }); + } +} + +mod bond_extra { + use super::*; + use crate::Event; + + #[test] + fn bond_extra_from_free_balance_creator() { + ExtBuilder::default().build_and_execute(|| { + // 10 is the owner and a member in pool 1, give them some more funds. + Balances::make_free_balance_be(&10, 100); + + // given + assert_eq!(PoolMembers::::get(10).unwrap().points, 10); + assert_eq!(BondedPools::::get(1).unwrap().points, 10); + assert_eq!(Balances::free_balance(10), 100); + + // when + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + + // then + assert_eq!(Balances::free_balance(10), 90); + assert_eq!(PoolMembers::::get(10).unwrap().points, 20); + assert_eq!(BondedPools::::get(1).unwrap().points, 20); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: false } + ] + ); + + // when + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(20))); + + // then + assert_eq!(Balances::free_balance(10), 70); + assert_eq!(PoolMembers::::get(10).unwrap().points, 40); + assert_eq!(BondedPools::::get(1).unwrap().points, 40); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::Bonded { member: 10, pool_id: 1, bonded: 20, joined: false }] + ); + }) + } + + #[test] + fn bond_extra_from_rewards_creator() { + ExtBuilder::default().build_and_execute(|| { + // put some money in the reward account, all of which will belong to 10 as the only + // member of the pool. + Balances::make_free_balance_be(&default_reward_account(), 7); + // ... if which only 2 is claimable to make sure the reward account does not die. + let claimable_reward = 7 - ExistentialDeposit::get(); + + // given + assert_eq!(PoolMembers::::get(10).unwrap().points, 10); + assert_eq!(BondedPools::::get(1).unwrap().points, 10); + assert_eq!(Balances::free_balance(10), 5); + + // when + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::Rewards)); + + // then + assert_eq!(Balances::free_balance(10), 5); + assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + claimable_reward); + assert_eq!(BondedPools::::get(1).unwrap().points, 10 + claimable_reward); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: claimable_reward }, + Event::Bonded { + member: 10, + pool_id: 1, + bonded: claimable_reward, + joined: false + } + ] + ); + }) + } + + #[test] + fn bond_extra_from_rewards_joiner() { + ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { + // put some money in the reward account, all of which will belong to 10 as the only + // member of the pool. + Balances::make_free_balance_be(&default_reward_account(), 8); + // ... if which only 3 is claimable to make sure the reward account does not die. + let claimable_reward = 8 - ExistentialDeposit::get(); + // NOTE: easier to read of we use 3, so let's use the number instead of variable. + assert_eq!(claimable_reward, 3, "test is correct if rewards are divisible by 3"); + + // given + assert_eq!(PoolMembers::::get(10).unwrap().points, 10); + assert_eq!(PoolMembers::::get(20).unwrap().points, 20); + assert_eq!(BondedPools::::get(1).unwrap().points, 30); + assert_eq!(Balances::free_balance(10), 5); + assert_eq!(Balances::free_balance(20), 20); + + // when + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::Rewards)); + + // then + assert_eq!(Balances::free_balance(10), 5); + // 10's share of the reward is 1/3, since they gave 10/30 of the total shares. + assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + 1); + assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 1); + + // when + assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::Rewards)); + + // then + assert_eq!(Balances::free_balance(20), 20); + // 20's share of the rewards is the other 2/3 of the rewards, since they have 20/30 of + // the shares + assert_eq!(PoolMembers::::get(20).unwrap().points, 20 + 2); + assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 3); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 1, joined: false }, + Event::PaidOut { member: 20, pool_id: 1, payout: 2 }, + Event::Bonded { member: 20, pool_id: 1, bonded: 2, joined: false } + ] + ); + }) + } +} diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs new file mode 100644 index 0000000000000..4bd291f5276f8 --- /dev/null +++ b/frame/nomination-pools/src/weights.rs @@ -0,0 +1,482 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_nomination_pools +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-04-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/production/substrate +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_nomination_pools +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/nomination-pools/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_nomination_pools. +pub trait WeightInfo { + fn join() -> Weight; + fn bond_extra_transfer() -> Weight; + fn bond_extra_reward() -> Weight; + fn claim_payout() -> Weight; + fn unbond() -> Weight; + fn pool_withdraw_unbonded(s: u32, ) -> Weight; + fn withdraw_unbonded_update(s: u32, ) -> Weight; + fn withdraw_unbonded_kill(s: u32, ) -> Weight; + fn create() -> Weight; + fn nominate(n: u32, ) -> Weight; + fn set_state() -> Weight; + fn set_metadata(n: u32, ) -> Weight; + fn set_configs() -> Weight; +} + +/// Weights for pallet_nomination_pools using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools MinJoinBond (r:1 w:0) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:0) + // Storage: System Account (r:2 w:1) + // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + // Storage: NominationPools MaxPoolMembers (r:1 w:0) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: BagsList ListBags (r:2 w:2) + fn join() -> Weight { + (117_870_000 as Weight) + .saturating_add(T::DbWeight::get().reads(18 as Weight)) + .saturating_add(T::DbWeight::get().writes(12 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: System Account (r:2 w:2) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: BagsList ListBags (r:2 w:2) + fn bond_extra_transfer() -> Weight { + (110_176_000 as Weight) + .saturating_add(T::DbWeight::get().reads(14 as Weight)) + .saturating_add(T::DbWeight::get().writes(13 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: System Account (r:3 w:3) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:2 w:2) + fn bond_extra_reward() -> Weight { + (122_829_000 as Weight) + .saturating_add(T::DbWeight::get().reads(14 as Weight)) + .saturating_add(T::DbWeight::get().writes(13 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn claim_payout() -> Weight { + (50_094_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: System Account (r:2 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListBags (r:2 w:2) + // Storage: NominationPools SubPoolsStorage (r:1 w:1) + // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) + fn unbond() -> Weight { + (119_288_000 as Weight) + .saturating_add(T::DbWeight::get().reads(19 as Weight)) + .saturating_add(T::DbWeight::get().writes(14 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + fn pool_withdraw_unbonded(s: u32, ) -> Weight { + (39_986_000 as Weight) + // Standard Error: 0 + .saturating_add((50_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools SubPoolsStorage (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + fn withdraw_unbonded_update(s: u32, ) -> Weight { + (76_897_000 as Weight) + // Standard Error: 0 + .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(9 as Weight)) + .saturating_add(T::DbWeight::get().writes(8 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools SubPoolsStorage (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:0) + // Storage: System Account (r:2 w:2) + // Storage: Balances Locks (r:1 w:1) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + // Storage: NominationPools ReversePoolIdLookup (r:1 w:1) + // Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: NominationPools CounterForRewardPools (r:1 w:1) + // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) + // Storage: NominationPools CounterForBondedPools (r:1 w:1) + // Storage: Staking Payee (r:0 w:1) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + (135_837_000 as Weight) + .saturating_add(T::DbWeight::get().reads(20 as Weight)) + .saturating_add(T::DbWeight::get().writes(17 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: NominationPools MinCreateBond (r:1 w:0) + // Storage: NominationPools MinJoinBond (r:1 w:0) + // Storage: NominationPools MaxPools (r:1 w:0) + // Storage: NominationPools CounterForBondedPools (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools LastPoolId (r:1 w:1) + // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + // Storage: NominationPools MaxPoolMembers (r:1 w:0) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + // Storage: System Account (r:2 w:2) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking HistoryDepth (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: NominationPools CounterForRewardPools (r:1 w:1) + // Storage: NominationPools ReversePoolIdLookup (r:1 w:1) + // Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: Staking Payee (r:0 w:1) + fn create() -> Weight { + (129_265_000 as Weight) + .saturating_add(T::DbWeight::get().reads(23 as Weight)) + .saturating_add(T::DbWeight::get().writes(16 as Weight)) + } + // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking MaxNominatorsCount (r:1 w:0) + // Storage: Staking Validators (r:2 w:0) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListNodes (r:1 w:1) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + fn nominate(n: u32, ) -> Weight { + (45_546_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_075_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(12 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: Staking Ledger (r:1 w:0) + fn set_state() -> Weight { + (23_256_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: NominationPools Metadata (r:1 w:1) + // Storage: NominationPools CounterForMetadata (r:1 w:1) + fn set_metadata(n: u32, ) -> Weight { + (10_893_000 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: NominationPools MinJoinBond (r:0 w:1) + // Storage: NominationPools MaxPoolMembers (r:0 w:1) + // Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1) + // Storage: NominationPools MinCreateBond (r:0 w:1) + // Storage: NominationPools MaxPools (r:0 w:1) + fn set_configs() -> Weight { + (2_793_000 as Weight) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools MinJoinBond (r:1 w:0) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:0) + // Storage: System Account (r:2 w:1) + // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + // Storage: NominationPools MaxPoolMembers (r:1 w:0) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: BagsList ListBags (r:2 w:2) + fn join() -> Weight { + (117_870_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(18 as Weight)) + .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: System Account (r:2 w:2) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: BagsList ListBags (r:2 w:2) + fn bond_extra_transfer() -> Weight { + (110_176_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(14 as Weight)) + .saturating_add(RocksDbWeight::get().writes(13 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: System Account (r:3 w:3) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListBags (r:2 w:2) + fn bond_extra_reward() -> Weight { + (122_829_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(14 as Weight)) + .saturating_add(RocksDbWeight::get().writes(13 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn claim_payout() -> Weight { + (50_094_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: System Account (r:2 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: BagsList ListNodes (r:3 w:3) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListBags (r:2 w:2) + // Storage: NominationPools SubPoolsStorage (r:1 w:1) + // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) + fn unbond() -> Weight { + (119_288_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(19 as Weight)) + .saturating_add(RocksDbWeight::get().writes(14 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + fn pool_withdraw_unbonded(s: u32, ) -> Weight { + (39_986_000 as Weight) + // Standard Error: 0 + .saturating_add((50_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools SubPoolsStorage (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + fn withdraw_unbonded_update(s: u32, ) -> Weight { + (76_897_000 as Weight) + // Standard Error: 0 + .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(9 as Weight)) + .saturating_add(RocksDbWeight::get().writes(8 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools SubPoolsStorage (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:0) + // Storage: System Account (r:2 w:2) + // Storage: Balances Locks (r:1 w:1) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + // Storage: NominationPools ReversePoolIdLookup (r:1 w:1) + // Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: NominationPools CounterForRewardPools (r:1 w:1) + // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) + // Storage: NominationPools CounterForBondedPools (r:1 w:1) + // Storage: Staking Payee (r:0 w:1) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + (135_837_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(20 as Weight)) + .saturating_add(RocksDbWeight::get().writes(17 as Weight)) + } + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: NominationPools MinCreateBond (r:1 w:0) + // Storage: NominationPools MinJoinBond (r:1 w:0) + // Storage: NominationPools MaxPools (r:1 w:0) + // Storage: NominationPools CounterForBondedPools (r:1 w:1) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools LastPoolId (r:1 w:1) + // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + // Storage: NominationPools MaxPoolMembers (r:1 w:0) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + // Storage: System Account (r:2 w:2) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking HistoryDepth (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: NominationPools CounterForRewardPools (r:1 w:1) + // Storage: NominationPools ReversePoolIdLookup (r:1 w:1) + // Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: Staking Payee (r:0 w:1) + fn create() -> Weight { + (129_265_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(23 as Weight)) + .saturating_add(RocksDbWeight::get().writes(16 as Weight)) + } + // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking MaxNominatorsCount (r:1 w:0) + // Storage: Staking Validators (r:2 w:0) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListNodes (r:1 w:1) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + fn nominate(n: u32, ) -> Weight { + (45_546_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_075_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(12 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: Staking Ledger (r:1 w:0) + fn set_state() -> Weight { + (23_256_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: NominationPools Metadata (r:1 w:1) + // Storage: NominationPools CounterForMetadata (r:1 w:1) + fn set_metadata(n: u32, ) -> Weight { + (10_893_000 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: NominationPools MinJoinBond (r:0 w:1) + // Storage: NominationPools MaxPoolMembers (r:0 w:1) + // Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1) + // Storage: NominationPools MinCreateBond (r:0 w:1) + // Storage: NominationPools MaxPools (r:0 w:1) + fn set_configs() -> Weight { + (2_793_000 as Weight) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } +} diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 66ac5e0ff1b36..88080df0b5912 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -71,5 +71,6 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-election-provider-support/runtime-benchmarks", "rand_chacha", + "sp-staking/runtime-benchmarks" ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 6c1589417f15a..7321740cfa79f 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -49,7 +49,7 @@ type MaxNominators = <::BenchmarkingConfig as BenchmarkingConfig // Add slashing spans to a user account. Not relevant for actual use, only to benchmark // read and write operations. -fn add_slashing_spans(who: &T::AccountId, spans: u32) { +pub fn add_slashing_spans(who: &T::AccountId, spans: u32) { if spans == 0 { return } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 8003b9814c8e6..037dcc86ab2a8 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -737,6 +737,18 @@ where } } +impl SessionInterface for () { + fn disable_validator(_: u32) -> bool { + true + } + fn validators() -> Vec { + Vec::new() + } + fn prune_historical_up_to(_: SessionIndex) { + () + } +} + /// Handler for determining how much of a balance should be paid out on the current era. pub trait EraPayout { /// Determine the payout for this era. diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 24572855264c4..bd2d8cdc32ce9 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -323,7 +323,7 @@ pub struct ExtBuilder { invulnerables: Vec, has_stakers: bool, initialize_first_session: bool, - min_nominator_bond: Balance, + pub min_nominator_bond: Balance, min_validator_bond: Balance, balance_factor: Balance, status: BTreeMap>, diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index ea4235f274da3..4665d956fdddb 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -29,15 +29,15 @@ use frame_support::{ }, weights::{Weight, WithPostDispatchInfo}, }; -use frame_system::pallet_prelude::BlockNumberFor; +use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ - traits::{Bounded, Convert, SaturatedConversion, Saturating, Zero}, + traits::{Bounded, Convert, SaturatedConversion, Saturating, StaticLookup, Zero}, Perbill, }; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - EraIndex, SessionIndex, + EraIndex, SessionIndex, StakingInterface, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -1367,3 +1367,68 @@ impl SortedListProvider for UseNominatorsAndValidatorsM Validators::::remove_all(); } } + +impl StakingInterface for Pallet { + type AccountId = T::AccountId; + type Balance = BalanceOf; + + fn minimum_bond() -> Self::Balance { + MinNominatorBond::::get() + } + + fn bonding_duration() -> EraIndex { + T::BondingDuration::get() + } + + fn current_era() -> EraIndex { + Self::current_era().unwrap_or(Zero::zero()) + } + + fn active_stake(controller: &Self::AccountId) -> Option { + Self::ledger(controller).map(|l| l.active) + } + + fn total_stake(controller: &Self::AccountId) -> Option { + Self::ledger(controller).map(|l| l.total) + } + + fn bond_extra(stash: Self::AccountId, extra: Self::Balance) -> DispatchResult { + Self::bond_extra(RawOrigin::Signed(stash).into(), extra) + } + + fn unbond(controller: Self::AccountId, value: Self::Balance) -> DispatchResult { + Self::unbond(RawOrigin::Signed(controller).into(), value) + } + + fn withdraw_unbonded( + controller: Self::AccountId, + num_slashing_spans: u32, + ) -> Result { + Self::withdraw_unbonded(RawOrigin::Signed(controller).into(), num_slashing_spans) + .map(|post_info| { + post_info + .actual_weight + .unwrap_or(T::WeightInfo::withdraw_unbonded_kill(num_slashing_spans)) + }) + .map_err(|err_with_post_info| err_with_post_info.error) + } + + fn bond( + stash: Self::AccountId, + controller: Self::AccountId, + value: Self::Balance, + payee: Self::AccountId, + ) -> DispatchResult { + Self::bond( + RawOrigin::Signed(stash).into(), + T::Lookup::unlookup(controller), + value, + RewardDestination::Account(payee), + ) + } + + fn nominate(controller: Self::AccountId, targets: Vec) -> DispatchResult { + let targets = targets.into_iter().map(T::Lookup::unlookup).collect::>(); + Self::nominate(RawOrigin::Signed(controller).into(), targets) + } +} diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index f57d5bd7c7a0a..bf13786d64ee6 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -30,7 +30,7 @@ use frame_support::{ use frame_system::{ensure_root, ensure_signed, offchain::SendTransactionTypes, pallet_prelude::*}; use sp_runtime::{ traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero}, - DispatchError, Perbill, Percent, + Perbill, Percent, }; use sp_staking::{EraIndex, SessionIndex}; use sp_std::{cmp::max, prelude::*}; diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 4484ff6b6b295..2d2944cc9a44f 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -87,6 +87,8 @@ pub use self::{ StorageHasher, Twox128, Twox256, Twox64Concat, }, storage::{ + bounded_btree_map::BoundedBTreeMap, + bounded_btree_set::BoundedBTreeSet, bounded_vec::{BoundedSlice, BoundedVec}, migration, weak_bounded_vec::WeakBoundedVec, @@ -138,6 +140,25 @@ macro_rules! bounded_vec { } } +/// Build a bounded btree-map from the given literals. +/// +/// The type of the outcome must be known. +/// +/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding +/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. +#[macro_export] +#[cfg(feature = "std")] +macro_rules! bounded_btree_map { + ($ ( $key:expr => $value:expr ),* $(,)?) => { + { + $crate::traits::TryCollect::<$crate::BoundedBTreeMap<_, _, _>>::try_collect( + $crate::sp_std::vec![$(($key, $value)),*].into_iter() + ).unwrap() + } + }; + +} + /// Generate a new type alias for [`storage::types::StorageValue`], /// [`storage::types::StorageMap`], [`storage::types::StorageDoubleMap`] /// and [`storage::types::StorageNMap`]. diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index eca4b17821c77..0d589994bcc2c 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -74,6 +74,14 @@ where Self(t, Default::default()) } + /// Exactly the same semantics as `BTreeMap::retain`. + /// + /// The is a safe `&mut self` borrow because `retain` can only ever decrease the length of the + /// inner map. + pub fn retain bool>(&mut self, f: F) { + self.0.retain(f) + } + /// Create a new `BoundedBTreeMap`. /// /// Does not allocate. diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 2a0d6f0523e71..7575aa8c19dc6 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -129,9 +129,13 @@ pub trait DefensiveOption { /// if `None`, which should never happen. fn defensive_map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U; - /// Defensively transform this option to a result. + /// Defensively transform this option to a result, mapping `None` to the return value of an + /// error closure. fn defensive_ok_or_else E>(self, err: F) -> Result; + /// Defensively transform this option to a result, mapping `None` to a default value. + fn defensive_ok_or(self, err: E) -> Result; + /// Exactly the same as `map`, but it prints the appropriate warnings if the value being mapped /// is `None`. fn defensive_map U>(self, f: F) -> Option; @@ -284,6 +288,13 @@ impl DefensiveOption for Option { }) } + fn defensive_ok_or(self, err: E) -> Result { + self.ok_or_else(|| { + defensive!(); + err + }) + } + fn defensive_map U>(self, f: F) -> Option { match self { Some(inner) => Some(f(inner)), diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 7761519dabefb..ac6c9d0e6428c 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -26,3 +26,4 @@ std = [ "sp-runtime/std", "sp-std/std", ] +runtime-benchmarks = [] diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index 57d858be1e0ef..7ff0808af0a63 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -19,6 +19,7 @@ //! A crate which contains primitives that are useful for implementation that uses staking //! approaches in general. Definitions related to sessions, slashing, etc go here. +use sp_runtime::{DispatchError, DispatchResult}; use sp_std::collections::btree_map::BTreeMap; pub mod offence; @@ -38,7 +39,7 @@ pub trait OnStakerSlash { /// /// * `stash` - The stash of the staker whom the slash was applied to. /// * `slashed_active` - The new bonded balance of the staker after the slash was applied. - /// * `slashed_unlocking` - a map of slashed eras, and the balance of that unlocking chunk after + /// * `slashed_unlocking` - A map of slashed eras, and the balance of that unlocking chunk after /// the slash is applied. Any era not present in the map is not affected at all. fn on_slash( stash: &AccountId, @@ -52,3 +53,80 @@ impl OnStakerSlash for () { // Nothing to do here } } + +/// Trait for communication with the staking pallet. +pub trait StakingInterface { + /// Balance type used by the staking system. + type Balance; + + /// AccountId type used by the staking system + type AccountId; + + /// The minimum amount required to bond in order to be a nominator. This does not necessarily + /// mean the nomination will be counted in an election, but instead just enough to be stored as + /// a nominator. In other words, this is the minimum amount to register the intention to + /// nominate. + fn minimum_bond() -> Self::Balance; + + /// Number of eras that staked funds must remain bonded for. + /// + /// # Note + /// + /// This must be strictly greater than the staking systems slash deffer duration. + fn bonding_duration() -> EraIndex; + + /// The current era index. + /// + /// This should be the latest planned era that the staking system knows about. + fn current_era() -> EraIndex; + + /// The amount of active stake that `controller` has in the staking system. + fn active_stake(controller: &Self::AccountId) -> Option; + + /// The total stake that `controller` has in the staking system. This includes the + /// [`Self::active_stake`], and any funds currently in the process of unbonding via + /// [`Self::unbond`]. + /// + /// # Note + /// + /// This is only guaranteed to reflect the amount locked by the staking system. If there are + /// non-staking locks on the bonded pair's balance this may not be accurate. + fn total_stake(controller: &Self::AccountId) -> Option; + + /// Bond (lock) `value` of `stash`'s balance. `controller` will be set as the account + /// controlling `stash`. This creates what is referred to as "bonded pair". + fn bond( + stash: Self::AccountId, + controller: Self::AccountId, + value: Self::Balance, + payee: Self::AccountId, + ) -> DispatchResult; + + /// Have `controller` nominate `validators`. + fn nominate( + controller: Self::AccountId, + validators: sp_std::vec::Vec, + ) -> DispatchResult; + + /// Bond some extra amount in the _Stash_'s free balance against the active bonded balance of + /// the account. The amount extra actually bonded will never be more than the _Stash_'s free + /// balance. + fn bond_extra(controller: Self::AccountId, extra: Self::Balance) -> DispatchResult; + + /// Schedule a portion of the active bonded balance to be unlocked at era + /// [Self::current_era] + [`Self::bonding_duration`]. + /// + /// Once the unlock era has been reached, [`Self::withdraw_unbonded`] can be called to unlock + /// the funds. + /// + /// The amount of times this can be successfully called is limited based on how many distinct + /// eras funds are schedule to unlock in. Calling [`Self::withdraw_unbonded`] after some unlock + /// schedules have reached their unlocking era should allow more calls to this function. + fn unbond(controller: Self::AccountId, value: Self::Balance) -> DispatchResult; + + /// Unlock any funds schedule to unlock before or at the current era. + fn withdraw_unbonded( + controller: Self::AccountId, + num_slashing_spans: u32, + ) -> Result; +} From c4693ebfa67f4aafbf66daa7b70a8b88f17bddc7 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 27 Apr 2022 18:19:07 +0100 Subject: [PATCH 0738/1472] Updating shell.nix nightly (#11266) * The 2022-02-10 nightly can't build some deps There's a sig that returns `impl IntoIterator` and an Option is being retured but it's incorrectly not allowing a `?` in the method. * removing duplicate test * [ci] add job cargo-check-nixos * add dummy variables nix check * fix check-dependent jobs * fix check-dependent-project template Co-authored-by: alvicsam --- .gitlab-ci.yml | 14 ++++++++++++++ shell.nix | 2 +- utils/frame/remote-externalities/src/lib.rs | 19 +------------------ 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0c06f3eb9c8e0..bd75cb0bac63c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -263,6 +263,20 @@ cargo-clippy: script: - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo +nightly clippy --all-targets +cargo-check-nixos: + stage: test + <<: *docker-env + <<: *test-refs + before_script: [] + variables: + CI_IMAGE: "nixos/nix" + SNAP: "DUMMY" + WS_API: "DUMMY" + script: + - nix-channel --update + - nix-shell shell.nix + - nix-shell --run "cargo check --workspace --all-targets --all-features" + cargo-check-benches: stage: test <<: *docker-env diff --git a/shell.nix b/shell.nix index 023946ce16de4..c318995605a38 100644 --- a/shell.nix +++ b/shell.nix @@ -5,7 +5,7 @@ let rev = "15b7a05f20aab51c4ffbefddb1b448e862dccb7d"; }); nixpkgs = import { overlays = [ mozillaOverlay ]; }; - rust-nightly = with nixpkgs; ((rustChannelOf { date = "2022-02-10"; channel = "nightly"; }).rust.override { + rust-nightly = with nixpkgs; ((rustChannelOf { date = "2022-04-20"; channel = "nightly"; }).rust.override { extensions = [ "rust-src" ]; targets = [ "wasm32-unknown-unknown" ]; }); diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 018ad2f4e0ad8..a717a93f072bc 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -1098,21 +1098,6 @@ mod remote_tests { } } - #[tokio::test] - async fn can_build_child_tree() { - init_logger(); - Builder::::new() - .mode(Mode::Online(OnlineConfig { - transport: "wss://rpc.polkadot.io:443".to_owned().into(), - pallets: vec!["Crowdloan".to_owned()], - ..Default::default() - })) - .build() - .await - .expect(REMOTE_INACCESSIBLE) - .execute_with(|| {}); - } - #[tokio::test] async fn can_create_child_snapshot() { init_logger(); @@ -1196,9 +1181,7 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - // transport: "wss://kusama-rpc.polkadot.io".to_owned().into(), - transport: "ws://kianenigma-archive:9924".to_owned().into(), - // transport: "ws://localhost:9999".to_owned().into(), + transport: "wss://rpc.polkadot.io:443".to_owned().into(), pallets: vec!["Crowdloan".to_owned()], ..Default::default() })) From a79c69a49620e40966b4397cee03d39d85f11815 Mon Sep 17 00:00:00 2001 From: Joshua W <64296537+HashWarlock@users.noreply.github.com> Date: Thu, 28 Apr 2022 06:05:18 -0500 Subject: [PATCH 0739/1472] Dependency Injection Trait Locker for Uniques Pallet (#11025) * Create a dependency injection trait named Locker that can be implemented downstream to enable locking of an asset. Use case defined in RMRK substrate pallet PR76 * Formatting * Change impl Locker function name to is_locked * Remove unused import * Add docstring header * Remove impl_locker file and add Locker trait to frame_support::traits * Expose Locker from frame_support::traits::misc * Formatting * Move to tokens folder * Move to tokens folder * Format and remove Locker from misc traits * Punctuation * Update frame/support/src/traits/tokens/misc.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Shawn Tabrizi Co-authored-by: Giles Cope --- bin/node/runtime/src/lib.rs | 1 + frame/support/src/traits.rs | 2 +- frame/support/src/traits/tokens.rs | 2 +- frame/support/src/traits/tokens/misc.rs | 16 ++++++++++++++++ frame/uniques/src/functions.rs | 1 + frame/uniques/src/lib.rs | 7 ++++++- frame/uniques/src/mock.rs | 1 + 7 files changed, 27 insertions(+), 3 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 54101cc222f84..18ce64c29f8e8 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1407,6 +1407,7 @@ impl pallet_uniques::Config for Runtime { #[cfg(feature = "runtime-benchmarks")] type Helper = (); type CreateOrigin = AsEnsureOriginWithArg>; + type Locker = (); } impl pallet_transaction_storage::Config for Runtime { diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 40afc0d337f43..edeb7fead7c84 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -27,7 +27,7 @@ pub use tokens::{ }, fungible, fungibles, imbalance::{Imbalance, OnUnbalanced, SignedImbalance}, - BalanceStatus, ExistenceRequirement, WithdrawReasons, + BalanceStatus, ExistenceRequirement, Locker, WithdrawReasons, }; mod members; diff --git a/frame/support/src/traits/tokens.rs b/frame/support/src/traits/tokens.rs index 92f8ce12d9128..77eb83adfbfb0 100644 --- a/frame/support/src/traits/tokens.rs +++ b/frame/support/src/traits/tokens.rs @@ -27,5 +27,5 @@ pub mod nonfungibles; pub use imbalance::Imbalance; pub use misc::{ AssetId, Balance, BalanceConversion, BalanceStatus, DepositConsequence, ExistenceRequirement, - WithdrawConsequence, WithdrawReasons, + Locker, WithdrawConsequence, WithdrawReasons, }; diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index f30fd02bfe831..86304b14a33f6 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -179,3 +179,19 @@ pub trait BalanceConversion { type Error; fn to_asset_balance(balance: InBalance, asset_id: AssetId) -> Result; } + +/// Trait to handle asset locking mechanism to ensure interactions with the asset can be implemented +/// downstream to extend logic of Uniques current functionality. +pub trait Locker { + /// Check if the asset should be locked and prevent interactions with the asset from executing. + fn is_locked(class: ClassId, instance: InstanceId) -> bool; +} + +impl Locker for () { + // Default will be false if not implemented downstream. + // Note: The logic check in this function must be constant time and consistent for benchmarks + // to work. + fn is_locked(_class: ClassId, _instance: InstanceId) -> bool { + false + } +} diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 40c436bd56b47..8b874997f2ff0 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -33,6 +33,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult { let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; ensure!(!class_details.is_frozen, Error::::Frozen); + ensure!(!T::Locker::is_locked(class, instance), Error::::Locked); let mut details = Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 1e14825454193..d999acc4c9403 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -43,7 +43,7 @@ pub mod weights; use codec::{Decode, Encode}; use frame_support::traits::{ - BalanceStatus::Reserved, Currency, EnsureOriginWithArg, ReservableCurrency, + tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, ReservableCurrency, }; use frame_system::Config as SystemConfig; use sp_runtime::{ @@ -108,6 +108,9 @@ pub mod pallet { Self::ClassId, >; + /// Locker trait to enable Locking mechanism downstream. + type Locker: Locker; + /// The basic amount of funds that must be reserved for an asset class. #[pallet::constant] type ClassDeposit: Get>; @@ -352,6 +355,8 @@ pub mod pallet { Unapproved, /// The named owner has not signed ownership of the class is acceptable. Unaccepted, + /// The asset instance is locked. + Locked, } impl, I: 'static> Pallet { diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index 265142443ef48..f32540f6ef7ba 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -91,6 +91,7 @@ impl Config for Test { type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; + type Locker = (); type ClassDeposit = ConstU64<2>; type InstanceDeposit = ConstU64<1>; type MetadataDepositBase = ConstU64<1>; From 1b57cff6924e1de5958d40eacd9910896b4bf953 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 28 Apr 2022 14:19:32 +0300 Subject: [PATCH 0740/1472] pallet-beefy: ensure mandatory block once per session (#11269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * pallet-beefy: ensure mandatory block once per session Signed-off-by: acatangiu * pallet-beefy: fix tests with auth changes every session Signed-off-by: acatangiu * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * beefy: fix incorrect skip session metric on node restart Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- client/beefy/src/worker.rs | 5 ++++- frame/beefy-mmr/src/tests.rs | 26 +++++++++++++++++--------- frame/beefy/src/lib.rs | 16 ++++++---------- frame/beefy/src/mock.rs | 3 +-- frame/beefy/src/tests.rs | 30 ++++++++++++++++++------------ 5 files changed, 46 insertions(+), 34 deletions(-) diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 696bee9d7ee76..8ab18c58f9dd3 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -242,7 +242,10 @@ where debug!(target: "beefy", "🥩 New active validator set: {:?}", active); metric_set!(self, beefy_validator_set_id, active.id()); // BEEFY should produce a signed commitment for each session - if active.id() != self.last_signed_id + 1 && active.id() != GENESIS_AUTHORITY_SET_ID { + if active.id() != self.last_signed_id + 1 && + active.id() != GENESIS_AUTHORITY_SET_ID && + self.last_signed_id != 0 + { metric_inc!(self, beefy_skipped_sessions); } diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index 37f571cd842ee..fd3ecd5067155 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -70,9 +70,14 @@ fn should_contain_mmr_digest() { assert_eq!( System::digest().logs, - vec![beefy_log(ConsensusLog::MmrRoot( - hex!("fa0275b19b2565089f7e2377ee73b9050e8d53bce108ef722a3251fd9d371d4b").into() - ))] + vec![ + beefy_log(ConsensusLog::AuthoritiesChange( + ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap() + )), + beefy_log(ConsensusLog::MmrRoot( + hex!("95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc").into() + )) + ] ); // unique every time @@ -81,14 +86,17 @@ fn should_contain_mmr_digest() { assert_eq!( System::digest().logs, vec![ + beefy_log(ConsensusLog::AuthoritiesChange( + ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap() + )), beefy_log(ConsensusLog::MmrRoot( - hex!("fa0275b19b2565089f7e2377ee73b9050e8d53bce108ef722a3251fd9d371d4b").into() + hex!("95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc").into() )), beefy_log(ConsensusLog::AuthoritiesChange( - ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4),], 1,).unwrap() + ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4)], 2).unwrap() )), beefy_log(ConsensusLog::MmrRoot( - hex!("85554fa7d4e863cce3cdce668c1ae82c0174ad37f8d1399284018bec9f9971c3").into() + hex!("a73271a0974f1e67d6e9b8dd58e506177a2e556519a330796721e98279a753e2").into() )), ] ); @@ -109,9 +117,9 @@ fn should_contain_valid_leaf_data() { version: MmrLeafVersion::new(1, 5), parent_number_and_hash: (0_u64, H256::repeat_byte(0x45)), beefy_next_authority_set: BeefyNextAuthoritySet { - id: 1, + id: 2, len: 2, - root: hex!("176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96") + root: hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5") .into(), }, leaf_extra: hex!("55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648") @@ -131,7 +139,7 @@ fn should_contain_valid_leaf_data() { version: MmrLeafVersion::new(1, 5), parent_number_and_hash: (1_u64, H256::repeat_byte(0x45)), beefy_next_authority_set: BeefyNextAuthoritySet { - id: 2, + id: 3, len: 2, root: hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5") .into(), diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 744a06561e8c2..14e7ac26cdb6e 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -105,10 +105,6 @@ impl Pallet { } fn change_authorities(new: Vec, queued: Vec) { - // Always issue a change if `session` says that the validators have changed. - // Even if their session keys are the same as before, the underlying economic - // identities have changed. Furthermore, the digest below is used to signal - // BEEFY mandatory blocks. >::put(&new); let next_id = Self::validator_set_id() + 1u64; @@ -153,16 +149,16 @@ impl OneSessionHandler for Pallet { Self::initialize_authorities(&authorities); } - fn on_new_session<'a, I: 'a>(changed: bool, validators: I, queued_validators: I) + fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I) where I: Iterator, { - if changed { - let next_authorities = validators.map(|(_, k)| k).collect::>(); - let next_queued_authorities = queued_validators.map(|(_, k)| k).collect::>(); + let next_authorities = validators.map(|(_, k)| k).collect::>(); + let next_queued_authorities = queued_validators.map(|(_, k)| k).collect::>(); - Self::change_authorities(next_authorities, next_queued_authorities); - } + // Always issue a change on each `session`, even if validator set hasn't changed. + // We want to have at least one BEEFY mandatory block per session. + Self::change_authorities(next_authorities, next_queued_authorities); } fn on_disabled(i: u32) { diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 5fc04f7cbd1d2..7a8f15cd51d29 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -145,8 +145,7 @@ pub fn new_test_ext_raw_authorities(authorities: Vec<(u64, BeefyId)>) -> TestExt let session_keys: Vec<_> = authorities .iter() - .enumerate() - .map(|(_, id)| (id.0 as u64, id.0 as u64, MockSessionKeys { dummy: id.1.clone() })) + .map(|id| (id.0 as u64, id.0 as u64, MockSessionKeys { dummy: id.1.clone() })) .collect(); BasicExternalities::execute_with_storage(&mut t, || { diff --git a/frame/beefy/src/tests.rs b/frame/beefy/src/tests.rs index 7acb40f200dfd..4136b0c1f1ecf 100644 --- a/frame/beefy/src/tests.rs +++ b/frame/beefy/src/tests.rs @@ -59,23 +59,28 @@ fn genesis_session_initializes_authorities() { #[test] fn session_change_updates_authorities() { new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - init_block(1); - assert!(0 == Beefy::validator_set_id()); - // no change - no log - assert!(System::digest().logs.is_empty()); - - init_block(2); + init_block(1); assert!(1 == Beefy::validator_set_id()); let want = beefy_log(ConsensusLog::AuthoritiesChange( - ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4)], 1).unwrap(), + ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap(), )); let log = System::digest().logs[0].clone(); + assert_eq!(want, log); + + init_block(2); + + assert!(2 == Beefy::validator_set_id()); + + let want = beefy_log(ConsensusLog::AuthoritiesChange( + ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4)], 2).unwrap(), + )); + let log = System::digest().logs[1].clone(); assert_eq!(want, log); }); } @@ -85,15 +90,13 @@ fn session_change_updates_next_authorities() { let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)]; new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - init_block(1); - let next_authorities = Beefy::next_authorities(); assert!(next_authorities.len() == 2); assert_eq!(want[0], next_authorities[0]); assert_eq!(want[1], next_authorities[1]); - init_block(2); + init_block(1); let next_authorities = Beefy::next_authorities(); @@ -121,11 +124,14 @@ fn validator_set_updates_work() { let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)]; new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { + let vs = Beefy::validator_set().unwrap(); + assert_eq!(vs.id(), 0u64); + init_block(1); let vs = Beefy::validator_set().unwrap(); - assert_eq!(vs.id(), 0u64); + assert_eq!(vs.id(), 1u64); assert_eq!(want[0], vs.validators()[0]); assert_eq!(want[1], vs.validators()[1]); @@ -133,7 +139,7 @@ fn validator_set_updates_work() { let vs = Beefy::validator_set().unwrap(); - assert_eq!(vs.id(), 1u64); + assert_eq!(vs.id(), 2u64); assert_eq!(want[2], vs.validators()[0]); assert_eq!(want[3], vs.validators()[1]); }); From 804b4c99a2cf712a75f52b18b363e0bde1ad1515 Mon Sep 17 00:00:00 2001 From: yjh Date: Thu, 28 Apr 2022 22:12:56 +0800 Subject: [PATCH 0741/1472] make sp-wasm-interface some wasmi impls works in no_std (#11310) --- primitives/wasm-interface/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/wasm-interface/src/lib.rs b/primitives/wasm-interface/src/lib.rs index 6dfc3116ddc48..246c1abaeae3b 100644 --- a/primitives/wasm-interface/src/lib.rs +++ b/primitives/wasm-interface/src/lib.rs @@ -21,7 +21,7 @@ use sp_std::{borrow::Cow, iter::Iterator, marker::PhantomData, mem, result, vec, vec::Vec}; -#[cfg(feature = "std")] +#[cfg(feature = "wasmi")] mod wasmi_impl; #[cfg(not(all(feature = "std", feature = "wasmtime")))] From 88731ed619f6be1280f01cc8f02f10e2fb4cf199 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Apr 2022 17:57:02 +0200 Subject: [PATCH 0742/1472] Bump ss58-registry from 1.15.0 to 1.17.0 (#11265) Bumps [ss58-registry](https://github.com/paritytech/ss58-registry) from 1.15.0 to 1.17.0. - [Release notes](https://github.com/paritytech/ss58-registry/releases) - [Changelog](https://github.com/paritytech/ss58-registry/blob/main/CHANGELOG.md) - [Commits](https://github.com/paritytech/ss58-registry/compare/v1.15.0...v1.17.0) --- updated-dependencies: - dependency-name: ss58-registry 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: Giles Cope --- Cargo.lock | 9 +++++---- primitives/core/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 596b737e22d09..16e048f774230 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7466,9 +7466,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.10" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -10641,11 +10641,12 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "ss58-registry" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9799e6d412271cb2414597581128b03f3285f260ea49f5363d07df6a332b3e" +checksum = "7b84a70894df7a73666e0694f44b41a9571625e9546fb58a0818a565d2c7e084" dependencies = [ "Inflector", + "num-format", "proc-macro2", "quote", "serde", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 9c79cb4843401..d23579c8ca2c0 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -57,7 +57,7 @@ hex = { version = "0.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } secp256k1 = { version = "0.21.2", default-features = false, features = ["recovery", "alloc"], optional = true } -ss58-registry = { version = "1.15.0", default-features = false } +ss58-registry = { version = "1.17.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } From efe6d7759920145bc68f089cfa4137553f1e577a Mon Sep 17 00:00:00 2001 From: Bisola Olasehinde Date: Fri, 29 Apr 2022 03:25:50 +0100 Subject: [PATCH 0743/1472] Replace simple parameter_types (#11254) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update bin/node-template/runtime/src/lib.rs * update frame/contracts/src/tests.rs * update frame/executive/src/lib.rs * update frame/grandpa/src/mock.rs * update frame/im-online/src/mock.rs * update frame/offences/benchmarking/src/mock.rs * update frame/recovery/src/mock.rs * update frame/referenda/src/mock.rs * update frame/session/benchmarking/src/mock.rs * update frame/staking/src/mock.rs * update frame/state-trie-migration/src/lib.rs * update frame/support/test/compile_pass/src/lib.rs * frame/treasury/src/tests.rs * update frame/whitelist/src/mock.rs * update frame/vesting/src/mock.rs * update test-utils/runtime/src/lib.rs * update bin/node-template/runtime/src/lib.rs * Update frame/grandpa/src/mock.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * resolve failed checks 1518659 & 1518669 * resolve format check * backtrack to resolve compile error * check --all --tests ✅ * cargo +nightly fmt ✅ Co-authored-by: Shawn Tabrizi Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Keith Yeung --- bin/node-template/runtime/src/lib.rs | 12 +++++----- frame/contracts/src/tests.rs | 6 +---- frame/executive/src/lib.rs | 5 +---- frame/grandpa/src/mock.rs | 6 +---- frame/im-online/src/mock.rs | 6 +---- frame/offences/benchmarking/src/mock.rs | 6 ++--- frame/referenda/src/mock.rs | 26 ++++++---------------- frame/session/benchmarking/src/mock.rs | 6 ++--- frame/state-trie-migration/src/lib.rs | 14 ++++++------ frame/support/test/compile_pass/src/lib.rs | 5 ++--- frame/treasury/src/tests.rs | 5 +---- frame/whitelist/src/mock.rs | 13 ++++------- test-utils/runtime/src/lib.rs | 3 +-- 13 files changed, 35 insertions(+), 78 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 780a84572d582..a7a162bf74327 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -26,7 +26,9 @@ use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. pub use frame_support::{ construct_runtime, parameter_types, - traits::{ConstU128, ConstU32, ConstU8, KeyOwnerProofSystem, Randomness, StorageInfo}, + traits::{ + ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, Randomness, StorageInfo, + }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, IdentityFee, Weight, @@ -132,8 +134,8 @@ pub fn native_version() -> NativeVersion { const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); parameter_types! { - pub const Version: RuntimeVersion = VERSION; pub const BlockHashCount: BlockNumber = 2400; + pub const Version: RuntimeVersion = VERSION; /// We allow for 2 seconds of compute with a 6 second average block time. pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights ::with_sensible_defaults(2 * WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); @@ -224,15 +226,11 @@ impl pallet_grandpa::Config for Runtime { type MaxAuthorities = ConstU32<32>; } -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 = Aura; - type MinimumPeriod = MinimumPeriod; + type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = (); } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index ce59f5bb858ac..9d949eea9b948 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -234,9 +234,6 @@ impl pallet_utility::Config for Test { type WeightInfo = (); } parameter_types! { - pub const MaxValueSize: u32 = 16_384; - pub const DeletionWeightLimit: Weight = 500_000_000_000; - pub const MaxCodeSize: u32 = 2 * 1024; pub MySchedule: Schedule = { let mut schedule = >::default(); // We want stack height to be always enabled for tests so that this @@ -244,7 +241,6 @@ parameter_types! { schedule.limits.stack_height = Some(512); schedule }; - pub const TransactionByteFee: u64 = 0; pub static DepositPerByte: BalanceOf = 1; pub const DepositPerItem: BalanceOf = 2; } @@ -286,7 +282,7 @@ impl Config for Test { type WeightInfo = (); type ChainExtension = TestExtension; type DeletionQueueDepth = ConstU32<1024>; - type DeletionWeightLimit = DeletionWeightLimit; + type DeletionWeightLimit = ConstU64<500_000_000_000>; type Schedule = MySchedule; type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index de1cc3b916404..68b5e910ed1fc 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -769,14 +769,11 @@ mod tests { } type Balance = u64; - parameter_types! { - pub const ExistentialDeposit: Balance = 1; - } impl pallet_balances::Config for Runtime { type Balance = Balance; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type MaxLocks = (); type MaxReserves = (); diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 5700fbe3aa36e..5e6c955c441c5 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -172,11 +172,7 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const SessionsPerEra: SessionIndex = 3; pub const BondingDuration: EraIndex = 3; - pub const SlashDeferDuration: EraIndex = 0; - pub const AttestationPeriod: u64 = 100; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const ElectionLookahead: u64 = 0; - pub const StakingUnsignedPriority: u64 = u64::MAX / 2; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); } @@ -199,7 +195,7 @@ impl pallet_staking::Config for Test { type Reward = (); type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; - type SlashDeferDuration = SlashDeferDuration; + type SlashDeferDuration = (); type SlashCancelOrigin = frame_system::EnsureRoot; type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 86904b38d834b..2459f7e748941 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -218,17 +218,13 @@ impl frame_support::traits::EstimateNextSessionRotation for TestNextSession } } -parameter_types! { - pub const UnsignedPriority: u64 = 1 << 20; -} - impl Config for Runtime { type AuthorityId = UintAuthorityId; type Event = Event; type ValidatorSet = Historical; type NextSessionRotation = TestNextSessionRotation; type ReportUnresponsiveness = OffenceHandler; - type UnsignedPriority = UnsignedPriority; + type UnsignedPriority = ConstU64<{ 1 << 20 }>; type WeightInfo = (); type MaxKeys = ConstU32<10_000>; type MaxPeerInHeartbeats = ConstU32<10_000>; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index fba8c567059c2..d51a81b1212c0 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -69,9 +69,7 @@ impl frame_system::Config for Test { type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } -parameter_types! { - pub const ExistentialDeposit: Balance = 10; -} + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -79,7 +77,7 @@ impl pallet_balances::Config for Test { type Balance = Balance; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<10>; type AccountStore = System; type WeightInfo = (); } diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index fdd14fdadf04d..1b0bbba24bbe6 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -26,7 +26,6 @@ use frame_support::{ ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling, PreimageRecipient, SortedMembers, }, - weights::Weight, }; use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; @@ -62,7 +61,6 @@ impl Contains for BaseFilter { } parameter_types! { - pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1_000_000); } @@ -81,7 +79,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -101,15 +99,12 @@ impl pallet_preimage::Config for Test { type BaseDeposit = (); type ByteDeposit = (); } -parameter_types! { - pub MaximumSchedulerWeight: Weight = 2_000_000_000_000; -} impl pallet_scheduler::Config for Test { type Event = Event; type Origin = Origin; type PalletsOrigin = OriginCaller; type Call = Call; - type MaximumWeight = MaximumSchedulerWeight; + type MaximumWeight = ConstU64<2_000_000_000_000>; type ScheduleOrigin = EnsureRoot; type MaxScheduledPerBlock = ConstU32<100>; type WeightInfo = (); @@ -117,26 +112,19 @@ impl pallet_scheduler::Config for Test { type PreimageProvider = Preimage; type NoPreimagePostponement = ConstU64<10>; } -parameter_types! { - pub const ExistentialDeposit: u64 = 1; - pub const MaxLocks: u32 = 10; -} impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; - type MaxLocks = MaxLocks; + type MaxLocks = ConstU32<10>; type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } parameter_types! { pub static AlarmInterval: u64 = 1; - pub const SubmissionDeposit: u64 = 2; - pub const MaxQueued: u32 = 3; - pub const UndecidingTimeout: u64 = 20; } ord_parameter_types! { pub const One: u64 = 1; @@ -228,9 +216,9 @@ impl Config for Test { type Slash = (); type Votes = u32; type Tally = Tally; - type SubmissionDeposit = SubmissionDeposit; - type MaxQueued = MaxQueued; - type UndecidingTimeout = UndecidingTimeout; + type SubmissionDeposit = ConstU64<2>; + type MaxQueued = ConstU32<3>; + type UndecidingTimeout = ConstU64<20>; type AlarmInterval = AlarmInterval; type Tracks = TestTracksInfo; } diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 6835736aa8e00..c777f2c56de3a 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -73,9 +73,7 @@ impl frame_system::Config for Test { type OnSetCode = (); type MaxConsumers = ConstU32<16>; } -parameter_types! { - pub const ExistentialDeposit: Balance = 10; -} + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -83,7 +81,7 @@ impl pallet_balances::Config for Test { type Balance = Balance; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<10>; type AccountStore = System; type WeightInfo = (); } diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 87be4099c89c8..3d66c6a66b8cf 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -980,7 +980,10 @@ mod benchmarks { mod mock { use super::*; use crate as pallet_state_trie_migration; - use frame_support::{parameter_types, traits::Hooks}; + use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64, Hooks}, + }; use frame_system::{EnsureRoot, EnsureSigned}; use sp_core::{ storage::{ChildInfo, StateVersion}, @@ -1008,7 +1011,6 @@ mod mock { ); parameter_types! { - pub const BlockHashCount: u32 = 250; pub const SS58Prefix: u8 = 42; } @@ -1026,7 +1028,7 @@ mod mock { type Lookup = IdentityLookup; type Header = sp_runtime::generic::Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU32<250>; type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; @@ -1036,12 +1038,10 @@ mod mock { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } parameter_types! { - pub const ExistentialDeposit: u64 = 1; - pub const OffchainRepeat: u32 = 1; pub const SignedDepositPerItem: u64 = 1; pub const SignedDepositBase: u64 = 5; } @@ -1050,7 +1050,7 @@ mod mock { type Balance = u64; type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type MaxLocks = (); type MaxReserves = (); diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index 0c955c749613c..7850726048546 100644 --- a/frame/support/test/compile_pass/src/lib.rs +++ b/frame/support/test/compile_pass/src/lib.rs @@ -24,7 +24,7 @@ use frame_support::{ construct_runtime, parameter_types, - traits::{ConstU16, ConstU32}, + traits::{ConstU16, ConstU32, ConstU64}, }; use sp_core::{sr25519, H256}; use sp_runtime::{ @@ -50,7 +50,6 @@ pub type BlockNumber = u64; pub type Index = u64; parameter_types! { - pub const BlockHashCount: BlockNumber = 2400; pub const Version: RuntimeVersion = VERSION; } @@ -63,7 +62,7 @@ impl frame_system::Config for Runtime { type Hashing = BlakeTwo256; type Header = Header; type Lookup = IdentityLookup; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<2400>; type Version = Version; type AccountData = (); type Origin = Origin; diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index a67bbe9b1d1e9..b755db29682aa 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -101,9 +101,6 @@ parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - pub const BountyUpdatePeriod: u32 = 20; - pub const BountyCuratorDeposit: Permill = Permill::from_percent(50); - pub const BountyValueMinimum: u64 = 1; pub const MaxApprovals: u32 = 100; } impl Config for Test { @@ -121,7 +118,7 @@ impl Config for Test { type BurnDestination = (); // Just gets burned. type WeightInfo = (); type SpendFunds = (); - type MaxApprovals = MaxApprovals; + type MaxApprovals = ConstU32<100>; } pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs index 3009a6f6b5d58..634db53a09a4e 100644 --- a/frame/whitelist/src/mock.rs +++ b/frame/whitelist/src/mock.rs @@ -22,7 +22,7 @@ use crate as pallet_whitelist; use frame_support::{ - parameter_types, + construct_runtime, parameter_types, traits::{ConstU32, ConstU64, Nothing}, }; use frame_system::EnsureRoot; @@ -36,7 +36,7 @@ use sp_runtime::{ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; -frame_support::construct_runtime!( +construct_runtime!( pub enum Test where Block = Block, NodeBlock = Block, @@ -49,7 +49,7 @@ frame_support::construct_runtime!( } ); -frame_support::parameter_types! { +parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -92,16 +92,11 @@ impl pallet_balances::Config for Test { type WeightInfo = (); } -parameter_types! { - // Taken from Polkadot as reference. - pub const PreimageMaxSize: u32 = 4096 * 1024; -} - impl pallet_preimage::Config for Test { type Event = Event; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type MaxSize = PreimageMaxSize; + type MaxSize = ConstU32<{ 4096 * 1024 }>; // PreimageMaxSize Taken from Polkadot as reference. type BaseDeposit = ConstU64<1>; type ByteDeposit = ConstU64<1>; type WeightInfo = (); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 743652a0ee899..94325ae9c1ab1 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -553,7 +553,6 @@ impl frame_support::traits::PalletInfo for Runtime { } parameter_types! { - pub const BlockHashCount: BlockNumber = 2400; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 100, write: 1000, @@ -578,7 +577,7 @@ impl frame_system::Config for Runtime { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<2400>; type DbWeight = (); type Version = (); type PalletInfo = Self; From 39a634d249b54c598c7b1ba41634828ada7506da Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Fri, 29 Apr 2022 16:28:17 +0800 Subject: [PATCH 0744/1472] Remove deprecated RawEvent types from some pallets (#11316) Signed-off-by: koushiro --- frame/atomic-swap/src/lib.rs | 4 ---- frame/balances/src/lib.rs | 4 ---- frame/collective/src/lib.rs | 4 ---- frame/elections-phragmen/src/lib.rs | 3 --- frame/grandpa/src/lib.rs | 3 --- frame/indices/src/lib.rs | 4 ---- frame/membership/src/lib.rs | 4 ---- frame/proxy/src/lib.rs | 4 ---- frame/session/src/lib.rs | 4 ---- frame/society/src/lib.rs | 4 ---- frame/system/src/lib.rs | 4 ---- frame/tips/src/lib.rs | 4 ---- frame/treasury/src/lib.rs | 4 ---- 13 files changed, 50 deletions(-) diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index e57496954a574..40429c226e649 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -232,10 +232,6 @@ pub mod pallet { SwapCancelled { account: T::AccountId, proof: HashedProof }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - #[pallet::call] impl Pallet { /// Register a new atomic swap, declaring an intention to send funds from origin to target diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 0eab933f7757d..5ba6c4dfa1f69 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -466,10 +466,6 @@ pub mod pallet { Slashed { who: T::AccountId, amount: T::Balance }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - #[pallet::error] pub enum Error { /// Vesting balance too high to send value diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index e876343ec33da..817e4e176bd4c 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -306,10 +306,6 @@ pub mod pallet { Closed { proposal_hash: T::Hash, yes: MemberCount, no: MemberCount }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - #[pallet::error] pub enum Error { /// Account is not a member diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 4758c793cfefd..a59da9c20f809 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -569,9 +569,6 @@ pub mod pallet { }, } - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - #[pallet::error] pub enum Error { /// Cannot vote when no candidates or members exist. diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index e30d65acbc6a6..318f2f40ea4d9 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -262,9 +262,6 @@ pub mod pallet { Resumed, } - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - #[pallet::error] pub enum Error { /// Attempt to signal GRANDPA pause when the authority set isn't live diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index 9c9e3580f2c04..db983a802cadf 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -270,10 +270,6 @@ pub mod pallet { IndexFrozen { index: T::AccountIndex, who: T::AccountId }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - #[pallet::error] pub enum Error { /// The index was not already assigned. diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index e8256fab83af2..5a9c0a461cdac 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -147,10 +147,6 @@ pub mod pallet { Dummy { _phantom_data: PhantomData<(T::AccountId, >::Event)> }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - #[pallet::error] pub enum Error { /// Already a member. diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 891315c92aa39..1bab3626fb5a9 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -579,10 +579,6 @@ pub mod pallet { }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - #[pallet::error] pub enum Error { /// There are too many proxies registered or too many announcements pending. diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 4cf793a9b4739..d6ecd17a8f2ae 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -547,10 +547,6 @@ pub mod pallet { NewSession { session_index: SessionIndex }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - /// Error for the session pallet. #[pallet::error] pub enum Error { diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index a9f83094fd49c..6ad63d2102c53 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -513,10 +513,6 @@ pub mod pallet { Deposit { value: BalanceOf }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - /// The first member. #[pallet::storage] #[pallet::getter(fn founder)] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 0eefc23a6b5d6..14e67cfcd8156 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -509,10 +509,6 @@ pub mod pallet { Remarked { sender: T::AccountId, hash: T::Hash }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - /// Error for the System pallet #[pallet::error] pub enum Error { diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index ae320629dfc34..4b7d78b90be38 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -195,10 +195,6 @@ pub mod pallet { TipSlashed { tip_hash: T::Hash, finder: T::AccountId, deposit: BalanceOf }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - #[pallet::error] pub enum Error { /// The reason given is just too big. diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 3f76ddb639c5b..d080d346ba3de 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -277,10 +277,6 @@ pub mod pallet { Deposit { value: BalanceOf }, } - /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; - /// Error for the treasury pallet. #[pallet::error] pub enum Error { From 95067ccc3a7683768f8a10036785cde8d5f8a098 Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 29 Apr 2022 12:49:05 +0400 Subject: [PATCH 0745/1472] Upgrade to libp2p 0.44.0 (#11009) * Update libp2p to 0.43.0, lru to 0.7.3 * Fix websoket Incoming::Data * Rename ProtocolsHandler -> ConnectionHandler, remove inject_dis/connected, minor fixes * Fix args for inject_connection* callbacks * Fix DialPeer/DialAddress * Fix debug fmt * Add Endpoint to NetworkState * Fix Kad::get_record by key * Fix Sha2_256::digest * Fix IntoConnectionHandler * Fix borrowchk * Fix DialError::WrongPeerId * Remove NodeHandlerWrapperError * Fix KademliaEvent variants * Fix impl Add for String * Fix tabs in network_state * Apply cargo fmt * Fix a typo in req/resp * Fix tests * Fix peer_info:entry.info_expire * Fix PeerInfoBehaviour inject_address_change and inject_connection_closed * Patch libp2p to 0.44.0#6cc3b4e * Fix inject_connection_closed kad, req/resp * Apply cargo fmt * Use libp2p from crates.io * Fix review notes --- Cargo.lock | 711 ++++++++++++------ client/authority-discovery/Cargo.toml | 2 +- client/authority-discovery/src/worker.rs | 4 +- client/cli/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 6 +- client/network/src/behaviour.rs | 8 +- client/network/src/bitswap.rs | 10 +- client/network/src/discovery.rs | 81 +- client/network/src/network_state.rs | 29 +- client/network/src/peer_info.rs | 120 +-- client/network/src/protocol.rs | 49 +- .../src/protocol/notifications/behaviour.rs | 40 +- .../src/protocol/notifications/handler.rs | 42 +- .../src/protocol/notifications/tests.rs | 38 +- client/network/src/request_responses.rs | 86 +-- client/network/src/service.rs | 48 +- client/network/test/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/telemetry/src/transport.rs | 9 +- primitives/core/Cargo.toml | 2 +- .../benchmarking-cli/src/pallet/writer.rs | 2 +- 24 files changed, 758 insertions(+), 541 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16e048f774230..7a5ef8e09ae7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,20 +218,19 @@ dependencies = [ [[package]] name = "async-io" -version = "1.3.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9315f8f07556761c3e48fec2e6b276004acf426e6dc068b2c2251854d65ee0fd" +checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" dependencies = [ "concurrent-queue", - "fastrand", "futures-lite", "libc", "log 0.4.16", - "nb-connect", "once_cell", "parking", "polling", - "vec-arena", + "slab", + "socket2 0.4.4", "waker-fn", "winapi 0.3.9", ] @@ -254,6 +253,23 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-process" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83137067e3a2a6a06d67168e49e68a0957d215410473a740cea95a2425c0b7c6" +dependencies = [ + "async-io", + "blocking", + "cfg-if 1.0.0", + "event-listener", + "futures-lite", + "libc", + "once_cell", + "signal-hook", + "winapi 0.3.9", +] + [[package]] name = "async-std" version = "1.11.0" @@ -265,6 +281,7 @@ dependencies = [ "async-global-executor", "async-io", "async-lock", + "async-process", "crossbeam-utils 0.8.5", "futures-channel", "futures-core", @@ -284,15 +301,16 @@ dependencies = [ [[package]] name = "async-std-resolver" -version = "0.20.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665c56111e244fe38e7708ee10948a4356ad6a548997c21f5a63a0f4e0edc4d" +checksum = "0f2f8a4a203be3325981310ab243a28e6e4ea55b6519bffce05d41ab60e09ad8" dependencies = [ "async-std", "async-trait", "futures-io", "futures-util", "pin-utils", + "socket2 0.4.4", "trust-dns-resolver", ] @@ -612,17 +630,6 @@ dependencies = [ "wyz", ] -[[package]] -name = "blake2" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a5720225ef5daecf08657f23791354e1685a8c91a4c60c7f3d3b2892f978f4" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - [[package]] name = "blake2" version = "0.10.2" @@ -916,21 +923,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chacha20" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee7ad89dc1128635074c268ee661f90c3f7e83d9fd12910608c36b47d6c3412" +checksum = "01b72a433d0cf2aef113ba70f62634c56fddb0f244e6377185c56a7cadbd8f91" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures 0.1.5", + "cpufeatures 0.2.1", "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580317203210c517b6d44794abfbe600698276db18127e37ad3e69bf5e848e5" +checksum = "3b84ed6d1d5f7aa9bdde921a5090e0ca4d934d250ea3b402a5fab3a994e28a2a" dependencies = [ "aead", "chacha20", @@ -1094,9 +1101,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ "core-foundation-sys", "libc", @@ -1104,9 +1111,18 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" +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" @@ -1528,6 +1544,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "curve25519-dalek" +version = "4.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4033478fbf70d6acf2655ac70da91ee65852d69daf7a67bf7a2f518fb47aafcf" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.6.2", + "subtle", + "zeroize", +] + [[package]] name = "darling" version = "0.13.0" @@ -1734,9 +1763,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dtoa" -version = "0.4.8" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" +checksum = "5caaa75cbd2b960ff1e5392d2cfb1f44717fffe12fc1f32b7b5d1267f99732a6" [[package]] name = "dyn-clonable" @@ -1858,11 +1887,11 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "enum-as-inner" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" +checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" dependencies = [ - "heck 0.3.2", + "heck 0.4.0", "proc-macro2", "quote", "syn", @@ -2598,13 +2627,13 @@ dependencies = [ [[package]] name = "futures-rustls" -version = "0.21.1" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1387e07917c711fb4ee4f48ea0adb04a3c9739e53ef85bf43ae1edc2937a8b" +checksum = "e01fe9932a224b72b45336d96040aa86386d674a31d0af27d800ea7bc8ca97fe" dependencies = [ "futures-io", - "rustls 0.19.1", - "webpki 0.21.4", + "rustls 0.20.2", + "webpki 0.22.0", ] [[package]] @@ -3103,9 +3132,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" dependencies = [ "matches", "unicode-bidi", @@ -3114,39 +3143,30 @@ dependencies = [ [[package]] name = "if-addrs" -version = "0.6.5" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28538916eb3f3976311f5dfbe67b5362d0add1293d0a9cad17debf86f8e3aa48" +checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" dependencies = [ - "if-addrs-sys", "libc", "winapi 0.3.9", ] -[[package]] -name = "if-addrs-sys" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de74b9dd780476e837e5eb5ab7c88b49ed304126e412030a0adba99c8efe79ea" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "if-watch" -version = "0.2.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6d52908d4ea4ab2bc22474ba149bf1011c8e2c3ebc1ff593ae28ac44f494b6" +checksum = "ae8f4a3c3d4c89351ca83e120c1c00b27df945d38e05695668c9d4b4f7bc52f3" dependencies = [ "async-io", + "core-foundation", + "fnv", "futures 0.3.21", - "futures-lite", "if-addrs", "ipnet", - "libc", "log 0.4.16", - "winapi 0.3.9", + "rtnetlink", + "system-configuration", + "windows", ] [[package]] @@ -3191,9 +3211,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if 1.0.0", ] @@ -3230,11 +3250,11 @@ checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" [[package]] name = "ipconfig" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" +checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" dependencies = [ - "socket2 0.3.19", + "socket2 0.4.4", "widestring", "winapi 0.3.9", "winreg", @@ -3242,9 +3262,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "itertools" @@ -3451,7 +3471,7 @@ dependencies = [ "tokio-rustls 0.23.2", "tokio-util 0.7.1", "tracing", - "webpki-roots 0.22.2", + "webpki-roots", ] [[package]] @@ -3671,14 +3691,18 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libp2p" -version = "0.40.0" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bec54343492ba5940a6c555e512c6721139835d28c59bc22febece72dfd0d9d" +checksum = "475ce2ac4a9727e53a519f6ee05b38abfcba8f0d39c4d24f103d184e36fd5b0f" dependencies = [ "atomic", "bytes 1.1.0", "futures 0.3.21", + "futures-timer", + "getrandom 0.2.3", + "instant", "lazy_static", + "libp2p-autonat", "libp2p-core", "libp2p-deflate", "libp2p-dns", @@ -3704,17 +3728,36 @@ dependencies = [ "libp2p-websocket", "libp2p-yamux", "multiaddr", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "pin-project 1.0.10", + "rand 0.7.3", "smallvec 1.8.0", - "wasm-timer", +] + +[[package]] +name = "libp2p-autonat" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13b690e65046af6a09c0b27bd9508fa1cab0efce889de74b0b643b9d2a98f9a" +dependencies = [ + "async-trait", + "futures 0.3.21", + "futures-timer", + "instant", + "libp2p-core", + "libp2p-request-response", + "libp2p-swarm", + "log 0.4.16", + "prost", + "prost-build", + "rand 0.8.4", ] [[package]] name = "libp2p-core" -version = "0.30.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef22d9bba1e8bcb7ec300073e6802943fe8abb8190431842262b5f1c30abba1" +checksum = "db5b02602099fb75cb2d16f9ea860a320d6eb82ce41e95ab680912c454805cd5" dependencies = [ "asn1_der", "bs58", @@ -3723,32 +3766,33 @@ dependencies = [ "fnv", "futures 0.3.21", "futures-timer", + "instant", "lazy_static", "libsecp256k1", "log 0.4.16", "multiaddr", - "multihash 0.14.0", + "multihash 0.16.2", "multistream-select", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "pin-project 1.0.10", "prost", "prost-build", "rand 0.8.4", "ring", "rw-stream-sink", - "sha2 0.9.8", + "sha2 0.10.2", "smallvec 1.8.0", "thiserror", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "void", "zeroize", ] [[package]] name = "libp2p-deflate" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51a800adb195f33de63f4b17b63fe64cfc23bf2c6a0d3d0d5321328664e65197" +checksum = "6b1d37f042f748e224f04785d0e987ae09a2aa518d6401d82d412dad83e360ed" dependencies = [ "flate2", "futures 0.3.21", @@ -3757,9 +3801,9 @@ dependencies = [ [[package]] name = "libp2p-dns" -version = "0.30.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb8f89d15cb6e3c5bc22afff7513b11bab7856f2872d3cfba86f7f63a06bc498" +checksum = "066e33e854e10b5c93fc650458bf2179c7e0d143db260b0963e44a94859817f1" dependencies = [ "async-std-resolver", "futures 0.3.21", @@ -3771,9 +3815,9 @@ dependencies = [ [[package]] name = "libp2p-floodsub" -version = "0.31.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab3d7210901ea51b7bae2b581aa34521797af8c4ec738c980bda4a06434067f" +checksum = "733d3ea6ebe7a7a85df2bc86678b93f24b015fae5fe3b3acc4c400e795a55d2d" dependencies = [ "cuckoofilter", "fnv", @@ -3789,9 +3833,9 @@ dependencies = [ [[package]] name = "libp2p-gossipsub" -version = "0.33.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfeead619eb5dac46e65acc78c535a60aaec803d1428cca6407c3a4fc74d698d" +checksum = "a90c989a7c0969c2ab63e898da9bc735e3be53fb4f376e9c045ce516bcc9f928" dependencies = [ "asynchronous-codec 0.6.0", "base64 0.13.0", @@ -3800,41 +3844,43 @@ dependencies = [ "fnv", "futures 0.3.21", "hex_fmt", + "instant", "libp2p-core", "libp2p-swarm", "log 0.4.16", + "prometheus-client", "prost", "prost-build", "rand 0.7.3", "regex", - "sha2 0.9.8", + "sha2 0.10.2", "smallvec 1.8.0", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "wasm-timer", ] [[package]] name = "libp2p-identify" -version = "0.31.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca1275574183f288ff8b72d535d5ffa5ea9292ef7829af8b47dcb197c7b0dcd" +checksum = "c5ef5a5b57904c7c33d6713ef918d239dc6b7553458f3475d87f8a18e9c651c8" dependencies = [ "futures 0.3.21", + "futures-timer", "libp2p-core", "libp2p-swarm", "log 0.4.16", - "lru 0.6.6", + "lru", "prost", "prost-build", "smallvec 1.8.0", - "wasm-timer", ] [[package]] name = "libp2p-kad" -version = "0.32.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2297dc0ca285f3a09d1368bde02449e539b46f94d32d53233f53f6625bcd3ba" +checksum = "564e6bd64d177446399ed835b9451a8825b07929d6daa6a94e6405592974725e" dependencies = [ "arrayvec 0.5.2", "asynchronous-codec 0.6.0", @@ -3842,25 +3888,27 @@ dependencies = [ "either", "fnv", "futures 0.3.21", + "futures-timer", + "instant", "libp2p-core", "libp2p-swarm", "log 0.4.16", "prost", "prost-build", "rand 0.7.3", - "sha2 0.9.8", + "sha2 0.10.2", "smallvec 1.8.0", + "thiserror", "uint", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "void", - "wasm-timer", ] [[package]] name = "libp2p-mdns" -version = "0.32.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c864b64bdc8a84ff3910a0df88e6535f256191a450870f1e7e10cbf8e64d45" +checksum = "611ae873c8e280ccfab0d57c7a13cac5644f364529e233114ff07863946058b0" dependencies = [ "async-io", "data-encoding", @@ -3879,23 +3927,25 @@ dependencies = [ [[package]] name = "libp2p-metrics" -version = "0.1.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4af432fcdd2f8ba4579b846489f8f0812cfd738ced2c0af39df9b1c48bbb6ab2" +checksum = "985be799bb3796e0c136c768208c3c06604a38430571906a13dcfeda225a3b9d" dependencies = [ "libp2p-core", + "libp2p-gossipsub", "libp2p-identify", "libp2p-kad", "libp2p-ping", + "libp2p-relay", "libp2p-swarm", - "open-metrics-client", + "prometheus-client", ] [[package]] name = "libp2p-mplex" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2cd64ef597f40e14bfce0497f50ecb63dd6d201c61796daeb4227078834fbf" +checksum = "442eb0c9fff0bf22a34f015724b4143ce01877e079ed0963c722d94c07c72160" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", @@ -3903,17 +3953,17 @@ dependencies = [ "libp2p-core", "log 0.4.16", "nohash-hasher", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "rand 0.7.3", "smallvec 1.8.0", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", ] [[package]] name = "libp2p-noise" -version = "0.33.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8772c7a99088221bb7ca9c5c0574bf55046a7ab4c319f3619b275f28c8fb87a" +checksum = "9dd7e0c94051cda67123be68cf6b65211ba3dde7277be9068412de3e7ffd63ef" dependencies = [ "bytes 1.1.0", "curve25519-dalek 3.0.2", @@ -3924,7 +3974,7 @@ dependencies = [ "prost", "prost-build", "rand 0.8.4", - "sha2 0.9.8", + "sha2 0.10.2", "snow", "static_assertions", "x25519-dalek", @@ -3933,24 +3983,25 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.31.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80ef7b0ec5cf06530d9eb6cf59ae49d46a2c45663bde31c25a12f682664adbcf" +checksum = "bf57a3c2e821331dda9fe612d4654d676ab6e33d18d9434a18cced72630df6ad" dependencies = [ "futures 0.3.21", + "futures-timer", + "instant", "libp2p-core", "libp2p-swarm", "log 0.4.16", "rand 0.7.3", "void", - "wasm-timer", ] [[package]] name = "libp2p-plaintext" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fba1a6ff33e4a274c89a3b1d78b9f34f32af13265cc5c46c16938262d4e945a" +checksum = "962c0fb0e7212fb96a69b87f2d09bcefd317935239bdc79cda900e7a8897a3fe" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", @@ -3959,7 +4010,7 @@ dependencies = [ "log 0.4.16", "prost", "prost-build", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "void", ] @@ -3979,89 +4030,96 @@ dependencies = [ [[package]] name = "libp2p-relay" -version = "0.4.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2852b61c90fa8ce3c8fcc2aba76e6cefc20d648f9df29157d6b3a916278ef3e3" +checksum = "3aa754cb7bccef51ebc3c458c6bbcef89d83b578a9925438389be841527d408f" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", + "either", "futures 0.3.21", "futures-timer", + "instant", "libp2p-core", "libp2p-swarm", "log 0.4.16", "pin-project 1.0.10", "prost", "prost-build", - "rand 0.7.3", + "rand 0.8.4", "smallvec 1.8.0", - "unsigned-varint 0.7.0", + "static_assertions", + "thiserror", + "unsigned-varint 0.7.1", "void", - "wasm-timer", ] [[package]] name = "libp2p-rendezvous" -version = "0.1.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14a6d2b9e7677eff61dc3d2854876aaf3976d84a01ef6664b610c77a0c9407c5" +checksum = "bbd0baab894c5b84da510b915d53264d566c3c35889f09931fe9edbd2a773bee" dependencies = [ "asynchronous-codec 0.6.0", "bimap", "futures 0.3.21", + "futures-timer", + "instant", "libp2p-core", "libp2p-swarm", "log 0.4.16", "prost", "prost-build", "rand 0.8.4", - "sha2 0.9.8", + "sha2 0.10.2", "thiserror", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "void", - "wasm-timer", ] [[package]] name = "libp2p-request-response" -version = "0.13.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a877a4ced6d46bf84677e1974e8cf61fb434af73b2e96fb48d6cb6223a4634d8" +checksum = "b5e6a6fc6c9ad95661f46989473b34bd2993d14a4de497ff3b2668a910d4b869" dependencies = [ "async-trait", "bytes 1.1.0", "futures 0.3.21", + "instant", "libp2p-core", "libp2p-swarm", "log 0.4.16", - "lru 0.7.5", "rand 0.7.3", "smallvec 1.8.0", - "unsigned-varint 0.7.0", - "wasm-timer", + "unsigned-varint 0.7.1", ] [[package]] name = "libp2p-swarm" -version = "0.31.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f5184a508f223bc100a12665517773fb8730e9f36fc09eefb670bf01b107ae9" +checksum = "8f0c69ad9e8f7c5fc50ad5ad9c7c8b57f33716532a2b623197f69f93e374d14c" dependencies = [ "either", + "fnv", "futures 0.3.21", + "futures-timer", + "instant", "libp2p-core", "log 0.4.16", + "pin-project 1.0.10", "rand 0.7.3", "smallvec 1.8.0", + "thiserror", "void", - "wasm-timer", ] [[package]] name = "libp2p-swarm-derive" -version = "0.25.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "072c290f727d39bdc4e9d6d1c847978693d25a673bd757813681e33e5f6c00c2" +checksum = "daf2fe8c80b43561355f4d51875273b5b6dfbac37952e8f64b1270769305c9d7" dependencies = [ "quote", "syn", @@ -4069,9 +4127,9 @@ dependencies = [ [[package]] name = "libp2p-tcp" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7399c5b6361ef525d41c11fcf51635724f832baf5819b30d3d873eabb4fbae4b" +checksum = "193447aa729c85aac2376828df76d171c1a589c9e6b58fcc7f9d9a020734122c" dependencies = [ "async-io", "futures 0.3.21", @@ -4086,9 +4144,9 @@ dependencies = [ [[package]] name = "libp2p-uds" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b7563e46218165dfd60f64b96f7ce84590d75f53ecbdc74a7dd01450dc5973" +checksum = "24bdab114f7f2701757d6541266e1131b429bbae382008f207f2114ee4222dcb" dependencies = [ "async-std", "futures 0.3.21", @@ -4098,9 +4156,9 @@ dependencies = [ [[package]] name = "libp2p-wasm-ext" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1008a302b73c5020251f9708c653f5ed08368e530e247cc9cd2f109ff30042cf" +checksum = "4f6ea0f84a967ef59a16083f222c18115ae2e91db69809dce275df62e101b279" dependencies = [ "futures 0.3.21", "js-sys", @@ -4112,9 +4170,9 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.31.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e12df82d1ed64969371a9e65ea92b91064658604cc2576c2757f18ead9a1cf" +checksum = "c932834c3754501c368d1bf3d0fb458487a642b90fc25df082a3a2f3d3b32e37" dependencies = [ "either", "futures 0.3.21", @@ -4125,18 +4183,18 @@ dependencies = [ "rw-stream-sink", "soketto", "url 2.2.1", - "webpki-roots 0.21.0", + "webpki-roots", ] [[package]] name = "libp2p-yamux" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7362abb8867d7187e7e93df17f460d554c997fc5c8ac57dc1259057f6889af" +checksum = "be902ebd89193cd020e89e89107726a38cfc0d16d18f613f4a37d046e92c7517" dependencies = [ "futures 0.3.21", "libp2p-core", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "thiserror", "yamux", ] @@ -4323,15 +4381,6 @@ dependencies = [ "syn", ] -[[package]] -name = "lru" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea2d928b485416e8908cff2d97d621db22b27f7b3b6729e438bcf42c671ba91" -dependencies = [ - "hashbrown 0.11.2", -] - [[package]] name = "lru" version = "0.7.5" @@ -4592,19 +4641,19 @@ checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" [[package]] name = "multiaddr" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ee4ea82141951ac6379f964f71b20876d43712bea8faf6dd1a375e08a46499" +checksum = "3c580bfdd8803cce319b047d239559a22f809094aaea4ac13902a1fdcfcd4261" dependencies = [ "arrayref", "bs58", "byteorder", "data-encoding", - "multihash 0.14.0", + "multihash 0.16.2", "percent-encoding 2.1.0", "serde", "static_assertions", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "url 2.2.1", ] @@ -4630,7 +4679,7 @@ dependencies = [ "blake3", "digest 0.9.0", "generic-array 0.14.4", - "multihash-derive", + "multihash-derive 0.7.2", "sha2 0.9.8", "sha3 0.9.1", "unsigned-varint 0.5.1", @@ -4638,15 +4687,15 @@ dependencies = [ [[package]] name = "multihash" -version = "0.14.0" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "752a61cd890ff691b4411423d23816d5866dd5621e4d1c5687a53b94b5a979d8" +checksum = "e3db354f401db558759dfc1e568d010a5d4146f4d3f637be1275ec4a3cf09689" dependencies = [ - "digest 0.9.0", - "generic-array 0.14.4", - "multihash-derive", - "sha2 0.9.8", - "unsigned-varint 0.7.0", + "core2", + "digest 0.10.3", + "multihash-derive 0.8.0", + "sha2 0.10.2", + "unsigned-varint 0.7.1", ] [[package]] @@ -4663,6 +4712,20 @@ dependencies = [ "synstructure", ] +[[package]] +name = "multihash-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" +dependencies = [ + "proc-macro-crate 1.1.3", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "multimap" version = "0.8.2" @@ -4671,16 +4734,16 @@ checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" [[package]] name = "multistream-select" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d91ec0a2440aaff5f78ec35631a7027d50386c6163aa975f7caa0d5da4b6ff8" +checksum = "363a84be6453a70e63513660f4894ef815daf88e3356bffcda9ca27d810ce83b" dependencies = [ "bytes 1.1.0", "futures 0.3.21", "log 0.4.16", "pin-project 1.0.10", "smallvec 1.8.0", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", ] [[package]] @@ -4740,24 +4803,92 @@ dependencies = [ ] [[package]] -name = "nb-connect" -version = "1.0.3" +name = "net2" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" dependencies = [ + "cfg-if 0.1.10", "libc", - "socket2 0.3.19", + "winapi 0.3.9", ] [[package]] -name = "net2" -version = "0.2.37" +name = "netlink-packet-core" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" dependencies = [ - "cfg-if 0.1.10", + "anyhow", + "byteorder", "libc", - "winapi 0.3.9", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733ea73609acfd7fa7ddadfb7bf709b0471668c456ad9513685af543a06342b2" +dependencies = [ + "anyhow", + "bitflags", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e" +dependencies = [ + "anyhow", + "byteorder", + "paste 1.0.6", + "thiserror", +] + +[[package]] +name = "netlink-proto" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8785b8141e8432aa45fceb922a7e876d7da3fad37fa7e7ec702ace3aa0826b" +dependencies = [ + "bytes 1.1.0", + "futures 0.3.21", + "log 0.4.16", + "netlink-packet-core", + "netlink-sys", + "tokio", +] + +[[package]] +name = "netlink-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c9f9547a08241bee7b6558b9b98e1f290d187de8b7cfca2bbb4937bcaa8f8" +dependencies = [ + "async-io", + "bytes 1.1.0", + "futures 0.3.21", + "libc", + "log 0.4.16", +] + +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", ] [[package]] @@ -4825,7 +4956,7 @@ dependencies = [ "futures 0.3.21", "hex-literal", "log 0.4.16", - "nix", + "nix 0.23.1", "node-executor", "node-inspect", "node-primitives", @@ -5360,29 +5491,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "open-metrics-client" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7337d80c23c2d8b1349563981bc4fb531220733743ba8115454a67b181173f0d" -dependencies = [ - "dtoa", - "itoa 0.4.8", - "open-metrics-client-derive-text-encode", - "owning_ref", -] - -[[package]] -name = "open-metrics-client-derive-text-encode" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c83b586f00268c619c1cb3340ec1a6f59dd9ba1d9833a273a68e6d5cd8ffc" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "openssl" version = "0.10.35" @@ -7348,6 +7456,29 @@ dependencies = [ "thiserror", ] +[[package]] +name = "prometheus-client" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a896938cc6018c64f279888b8c7559d3725210d5db9a3a1ee6bc7188d51d34" +dependencies = [ + "dtoa", + "itoa 1.0.1", + "owning_ref", + "prometheus-client-derive-text-encode", +] + +[[package]] +name = "prometheus-client-derive-text-encode" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e12d01b9d66ad9eb4529c57666b6263fc1993cb30261d83ead658fdd932652" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "prost" version = "0.9.0" @@ -7988,6 +8119,21 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rtnetlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f54290e54521dac3de4149d83ddf9f62a359b3cc93bcb494a794a41e6f4744b" +dependencies = [ + "async-global-executor", + "futures 0.3.21", + "log 0.4.16", + "netlink-packet-route", + "netlink-proto", + "nix 0.22.3", + "thiserror", +] + [[package]] name = "rust-argon2" version = "0.8.3" @@ -8036,6 +8182,15 @@ dependencies = [ "semver 0.11.0", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.4", +] + [[package]] name = "rustix" version = "0.33.5" @@ -8625,7 +8780,7 @@ dependencies = [ "env_logger 0.9.0", "hex-literal", "lazy_static", - "lru 0.7.5", + "lru", "parity-scale-codec", "parking_lot 0.12.0", "paste 1.0.6", @@ -8834,7 +8989,7 @@ dependencies = [ "linked-hash-map", "linked_hash_set", "log 0.4.16", - "lru 0.7.5", + "lru", "parity-scale-codec", "parking_lot 0.12.0", "pin-project 1.0.10", @@ -8878,7 +9033,7 @@ dependencies = [ "futures-timer", "libp2p", "log 0.4.16", - "lru 0.7.5", + "lru", "quickcheck", "sc-network", "sp-runtime", @@ -9697,6 +9852,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" +[[package]] +name = "signal-hook" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac" +dependencies = [ + "libc", + "signal-hook-registry", +] + [[package]] name = "signal-hook-registry" version = "1.3.0" @@ -9757,20 +9922,19 @@ checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451" [[package]] name = "snow" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6142f7c25e94f6fd25a32c3348ec230df9109b463f59c8c7acc4bd34936babb7" +checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" dependencies = [ "aes-gcm", - "blake2 0.9.1", + "blake2", "chacha20poly1305", - "rand 0.8.4", + "curve25519-dalek 4.0.0-pre.1", "rand_core 0.6.2", "ring", - "rustc_version 0.3.3", - "sha2 0.9.8", + "rustc_version 0.4.0", + "sha2 0.10.2", "subtle", - "x25519-dalek", ] [[package]] @@ -9831,7 +9995,7 @@ dependencies = [ name = "sp-api-proc-macro" version = "4.0.0-dev" dependencies = [ - "blake2 0.10.2", + "blake2", "proc-macro-crate 1.1.3", "proc-macro2", "quote", @@ -9950,7 +10114,7 @@ version = "4.0.0-dev" dependencies = [ "futures 0.3.21", "log 0.4.16", - "lru 0.7.5", + "lru", "parity-scale-codec", "parking_lot 0.12.0", "sp-api", @@ -10108,7 +10272,7 @@ dependencies = [ name = "sp-core-hashing" version = "4.0.0" dependencies = [ - "blake2 0.10.2", + "blake2", "byteorder", "digest 0.10.3", "sha2 0.10.2", @@ -11001,6 +11165,27 @@ dependencies = [ "unicode-xid", ] +[[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" @@ -11450,7 +11635,7 @@ dependencies = [ "ahash", "lazy_static", "log 0.4.16", - "lru 0.7.5", + "lru", "tracing-core", ] @@ -11549,9 +11734,9 @@ dependencies = [ [[package]] name = "trust-dns-proto" -version = "0.20.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d57e219ba600dd96c2f6d82eb79645068e14edbc5c7e27514af40436b88150c" +checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" dependencies = [ "async-trait", "cfg-if 1.0.0", @@ -11560,7 +11745,7 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.2.2", + "idna 0.2.3", "ipnet", "lazy_static", "log 0.4.16", @@ -11573,9 +11758,9 @@ dependencies = [ [[package]] name = "trust-dns-resolver" -version = "0.20.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0437eea3a6da51acc1e946545ff53d5b8fb2611ff1c3bed58522dde100536ae" +checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" dependencies = [ "cfg-if 1.0.0", "futures-util", @@ -11583,7 +11768,7 @@ dependencies = [ "lazy_static", "log 0.4.16", "lru-cache", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "resolv-conf", "smallvec 1.8.0", "thiserror", @@ -11768,9 +11953,9 @@ dependencies = [ [[package]] name = "unsigned-varint" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f8d425fafb8cd76bc3f22aace4af471d3156301d7508f2107e98fbeae10bc7f" +checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.1.0", @@ -11802,7 +11987,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ "form_urlencoded", - "idna 0.2.2", + "idna 0.2.3", "matches", "percent-encoding 2.1.0", ] @@ -12468,15 +12653,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "webpki-roots" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" -dependencies = [ - "webpki 0.21.4", -] - [[package]] name = "webpki-roots" version = "0.22.2" @@ -12548,9 +12724,9 @@ dependencies = [ [[package]] name = "widestring" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" [[package]] name = "winapi" @@ -12595,43 +12771,86 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac7fef12f4b59cd0a29339406cc9203ab44e440ddff6b3f5a41455349fa9cf3" +dependencies = [ + "windows_aarch64_msvc 0.29.0", + "windows_i686_gnu 0.29.0", + "windows_i686_msvc 0.29.0", + "windows_x86_64_gnu 0.29.0", + "windows_x86_64_msvc 0.29.0", +] + [[package]] name = "windows-sys" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.32.0", + "windows_i686_gnu 0.32.0", + "windows_i686_msvc 0.32.0", + "windows_x86_64_gnu 0.32.0", + "windows_x86_64_msvc 0.32.0", ] +[[package]] +name = "windows_aarch64_msvc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" + [[package]] name = "windows_aarch64_msvc" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" +[[package]] +name = "windows_i686_gnu" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" + [[package]] name = "windows_i686_gnu" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" +[[package]] +name = "windows_i686_msvc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" + [[package]] name = "windows_i686_msvc" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" +[[package]] +name = "windows_x86_64_gnu" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" + [[package]] name = "windows_x86_64_gnu" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" +[[package]] +name = "windows_x86_64_msvc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" + [[package]] name = "windows_x86_64_msvc" version = "0.32.0" @@ -12640,9 +12859,9 @@ checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" [[package]] name = "winreg" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" dependencies = [ "winapi 0.3.9", ] @@ -12679,23 +12898,23 @@ dependencies = [ [[package]] name = "yamux" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d9028f208dd5e63c614be69f115c1b53cacc1111437d4c765185856666c107" +checksum = "0c0608f53c1dc0bad505d03a34bbd49fbf2ad7b51eb036123e896365532745a1" dependencies = [ "futures 0.3.21", "log 0.4.16", "nohash-hasher", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "rand 0.8.4", "static_assertions", ] [[package]] name = "zeroize" -version = "1.5.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317" +checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" dependencies = [ "zeroize_derive", ] diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index effc8cd715e1d..0e107b19ce6ab 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -23,7 +23,7 @@ thiserror = "1.0" futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" -libp2p = { version = "0.40.0", default-features = false, features = ["kad"] } +libp2p = { version = "0.44.0", default-features = false, features = ["kad"] } log = "0.4.16" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } prost = "0.9" diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index 726c032281cd8..0912359501385 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -37,7 +37,7 @@ use codec::Decode; use ip_network::IpNetwork; use libp2p::{ core::multiaddr, - multihash::{Hasher, Multihash}, + multihash::{Multihash, MultihashDigest}, }; use log::{debug, error, log_enabled}; use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64}; @@ -638,7 +638,7 @@ where } fn hash_authority_id(id: &[u8]) -> sc_network::KademliaKey { - sc_network::KademliaKey::new(&libp2p::multihash::Sha2_256::digest(id)) + sc_network::KademliaKey::new(&libp2p::multihash::Code::Sha2_256.digest(id).digest()) } // Makes sure all values are the same and returns it diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index adf88b8c88a2c..0495f522c1ade 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -18,7 +18,7 @@ clap = { version = "3.1.6", features = ["derive"] } fdlimit = "0.2.1" futures = "0.3.21" hex = "0.4.2" -libp2p = "0.40.0" +libp2p = "0.44.0" log = "0.4.16" names = { version = "0.13.0", default-features = false } rand = "0.7.3" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index f4f7626ab6b7e..2846a3e7898c5 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] thiserror = "1.0.30" -libp2p = { version = "0.40.0", default-features = false } +libp2p = { version = "0.44.0", default-features = false } log = "0.4.16" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 2989ff5b51412..79e07b597c65d 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" futures-timer = "3.0.1" -libp2p = { version = "0.40.0", default-features = false } +libp2p = { version = "0.44.0", default-features = false } log = "0.4.16" lru = "0.7.5" ahash = "0.7.6" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 6fe804ce52413..93b389d4361c1 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -61,12 +61,12 @@ unsigned-varint = { version = "0.6.0", features = [ "asynchronous_codec", ] } void = "1.0.2" -zeroize = "1.5.4" -libp2p = "0.40.0" +zeroize = "1.4.3" +libp2p = "0.44.0" [dev-dependencies] assert_matches = "1.3" -libp2p = { version = "0.40.0", default-features = false } +libp2p = { version = "0.44.0", default-features = false } quickcheck = "1.0.3" rand = "0.7.2" sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index d0de50ef61897..f6a7e9eb87018 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -33,8 +33,8 @@ use libp2p::{ identify::IdentifyInfo, kad::record, swarm::{ - toggle::Toggle, NetworkBehaviour, NetworkBehaviourAction, NetworkBehaviourEventProcess, - PollParameters, + behaviour::toggle::Toggle, NetworkBehaviour, NetworkBehaviourAction, + NetworkBehaviourEventProcess, PollParameters, }, NetworkBehaviour, }; @@ -304,7 +304,7 @@ impl Behaviour { /// Start querying a record from the DHT. Will later produce either a `ValueFound` or a /// `ValueNotFound` event. - pub fn get_value(&mut self, key: &record::Key) { + pub fn get_value(&mut self, key: record::Key) { self.discovery.get_value(key); } @@ -519,7 +519,7 @@ impl Behaviour { &mut self, _cx: &mut Context, _: &mut impl PollParameters, - ) -> Poll, ::ProtocolsHandler>> + ) -> Poll, ::ConnectionHandler>> { if let Some(event) = self.events.pop_front() { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event)) diff --git a/client/network/src/bitswap.rs b/client/network/src/bitswap.rs index e7c37968b5f99..da80ab8cb3d33 100644 --- a/client/network/src/bitswap.rs +++ b/client/network/src/bitswap.rs @@ -194,10 +194,10 @@ impl Bitswap { } impl NetworkBehaviour for Bitswap { - type ProtocolsHandler = OneShotHandler; + type ConnectionHandler = OneShotHandler; type OutEvent = void::Void; - fn new_handler(&mut self) -> Self::ProtocolsHandler { + fn new_handler(&mut self) -> Self::ConnectionHandler { Default::default() } @@ -205,10 +205,6 @@ impl NetworkBehaviour for Bitswap { Vec::new() } - fn inject_connected(&mut self, _peer: &PeerId) {} - - fn inject_disconnected(&mut self, _peer: &PeerId) {} - fn inject_event(&mut self, peer: PeerId, _connection: ConnectionId, message: HandlerEvent) { let request = match message { HandlerEvent::ResponseSent => return, @@ -300,7 +296,7 @@ impl NetworkBehaviour for Bitswap { &mut self, _ctx: &mut Context, _: &mut impl PollParameters, - ) -> Poll> { + ) -> Poll> { if let Some((peer_id, message)) = self.ready_blocks.pop_front() { return Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index cf75e2dcb4c65..a916ffda0794d 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -67,8 +67,8 @@ use libp2p::{ mdns::{Mdns, MdnsConfig, MdnsEvent}, multiaddr::Protocol, swarm::{ - protocols_handler::multi::IntoMultiHandler, DialError, IntoProtocolsHandler, - NetworkBehaviour, NetworkBehaviourAction, PollParameters, ProtocolsHandler, + handler::multi::IntoMultiHandler, ConnectionHandler, DialError, IntoConnectionHandler, + NetworkBehaviour, NetworkBehaviourAction, PollParameters, }, }; use log::{debug, error, info, trace, warn}; @@ -355,9 +355,9 @@ impl DiscoveryBehaviour { /// Start fetching a record from the DHT. /// /// A corresponding `ValueFound` or `ValueNotFound` event will later be generated. - pub fn get_value(&mut self, key: &record::Key) { + pub fn get_value(&mut self, key: record::Key) { for k in self.kademlias.values_mut() { - k.get_record(key, Quorum::One); + k.get_record(key.clone(), Quorum::One); } } @@ -433,7 +433,7 @@ impl DiscoveryBehaviour { &mut self, pid: ProtocolId, handler: KademliaHandlerProto, - ) -> ::ProtocolsHandler { + ) -> ::ConnectionHandler { let mut handlers: HashMap<_, _> = self .kademlias .iter_mut() @@ -498,10 +498,10 @@ pub enum DiscoveryOut { } impl NetworkBehaviour for DiscoveryBehaviour { - type ProtocolsHandler = IntoMultiHandler>; + type ConnectionHandler = IntoMultiHandler>; type OutEvent = DiscoveryOut; - fn new_handler(&mut self) -> Self::ProtocolsHandler { + fn new_handler(&mut self) -> Self::ConnectionHandler { let iter = self .kademlias .iter_mut() @@ -568,6 +568,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { conn: &ConnectionId, endpoint: &ConnectedPoint, failed_addresses: Option<&Vec>, + other_established: usize, ) { self.num_connections += 1; for k in self.kademlias.values_mut() { @@ -577,37 +578,37 @@ impl NetworkBehaviour for DiscoveryBehaviour { conn, endpoint, failed_addresses, + other_established, ) } } - fn inject_connected(&mut self, peer_id: &PeerId) { - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_connected(k, peer_id) - } - } - fn inject_connection_closed( &mut self, - _peer_id: &PeerId, - _conn: &ConnectionId, - _endpoint: &ConnectedPoint, - _handler: ::Handler, + peer_id: &PeerId, + conn: &ConnectionId, + endpoint: &ConnectedPoint, + handler: ::Handler, + remaining_established: usize, ) { self.num_connections -= 1; - // NetworkBehaviour::inject_connection_closed on Kademlia does nothing. - } - - fn inject_disconnected(&mut self, peer_id: &PeerId) { - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_disconnected(k, peer_id) + for (pid, event) in handler.into_iter() { + if let Some(kad) = self.kademlias.get_mut(&pid) { + kad.inject_connection_closed(peer_id, conn, endpoint, event, remaining_established) + } else { + error!( + target: "sub-libp2p", + "inject_connection_closed: no kademlia instance registered for protocol {:?}", + pid, + ) + } } } fn inject_dial_failure( &mut self, peer_id: Option, - _: Self::ProtocolsHandler, + _: Self::ConnectionHandler, error: &DialError, ) { if let Some(peer_id) = peer_id { @@ -630,7 +631,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { &mut self, peer_id: PeerId, connection: ConnectionId, - (pid, event): <::Handler as ProtocolsHandler>::OutEvent, + (pid, event): <::Handler as ConnectionHandler>::OutEvent, ) { if let Some(kad) = self.kademlias.get_mut(&pid) { return kad.inject_event(peer_id, connection, event) @@ -689,7 +690,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { } } - fn inject_listen_failure(&mut self, _: &Multiaddr, _: &Multiaddr, _: Self::ProtocolsHandler) { + fn inject_listen_failure(&mut self, _: &Multiaddr, _: &Multiaddr, _: Self::ConnectionHandler) { // NetworkBehaviour::inject_listen_failure on Kademlia does nothing. } @@ -709,7 +710,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { &mut self, cx: &mut Context, params: &mut impl PollParameters, - ) -> Poll> { + ) -> Poll> { // Immediately process the content of `discovered`. if let Some(ev) = self.pending_events.pop_front() { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) @@ -770,12 +771,8 @@ impl NetworkBehaviour for DiscoveryBehaviour { let ev = DiscoveryOut::Discovered(peer); return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) }, - KademliaEvent::InboundPutRecordRequest { .. } | - KademliaEvent::InboundAddProviderRequest { .. } => { - debug_assert!(false, "We don't use kad filtering at the moment"); - }, KademliaEvent::PendingRoutablePeer { .. } | - KademliaEvent::InboundRequestServed { .. } => { + KademliaEvent::InboundRequest { .. } => { // We are not interested in this event at the moment. }, KademliaEvent::OutboundQueryCompleted { @@ -890,19 +887,10 @@ impl NetworkBehaviour for DiscoveryBehaviour { warn!(target: "sub-libp2p", "Libp2p => Unhandled Kademlia event: {:?}", e) }, }, - NetworkBehaviourAction::DialAddress { address, handler } => { - let pid = pid.clone(); - let handler = self.new_handler_with_replacement(pid, handler); - return Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) - }, - NetworkBehaviourAction::DialPeer { peer_id, condition, handler } => { + NetworkBehaviourAction::Dial { opts, handler } => { let pid = pid.clone(); let handler = self.new_handler_with_replacement(pid, handler); - return Poll::Ready(NetworkBehaviourAction::DialPeer { - peer_id, - condition, - handler, - }) + return Poll::Ready(NetworkBehaviourAction::Dial { opts, handler }) }, NetworkBehaviourAction::NotifyHandler { peer_id, handler, event } => return Poll::Ready(NetworkBehaviourAction::NotifyHandler { @@ -941,10 +929,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { }, MdnsEvent::Expired(_) => {}, }, - NetworkBehaviourAction::DialAddress { .. } => { - unreachable!("mDNS never dials!"); - }, - NetworkBehaviourAction::DialPeer { .. } => { + NetworkBehaviourAction::Dial { .. } => { unreachable!("mDNS never dials!"); }, NetworkBehaviourAction::NotifyHandler { event, .. } => match event {}, /* `event` is an enum with no variant */ @@ -995,7 +980,7 @@ impl MdnsWrapper { &mut self, cx: &mut Context<'_>, params: &mut impl PollParameters, - ) -> Poll::ProtocolsHandler>> { + ) -> Poll::ConnectionHandler>> { loop { match self { Self::Instantiating(fut) => diff --git a/client/network/src/network_state.rs b/client/network/src/network_state.rs index a5e2fbef421db..57073c57afa69 100644 --- a/client/network/src/network_state.rs +++ b/client/network/src/network_state.rs @@ -20,7 +20,10 @@ //! //! **Warning**: These APIs are not stable. -use libp2p::{core::ConnectedPoint, Multiaddr}; +use libp2p::{ + core::{ConnectedPoint, Endpoint as CoreEndpoint}, + Multiaddr, +}; use serde::{Deserialize, Serialize}; use std::{ collections::{HashMap, HashSet}, @@ -80,7 +83,7 @@ pub struct NotConnectedPeer { #[serde(rename_all = "camelCase")] pub enum PeerEndpoint { /// We are dialing the given address. - Dialing(Multiaddr), + Dialing(Multiaddr, Endpoint), /// We are listening. Listening { /// Local address of the connection. @@ -90,12 +93,32 @@ pub enum PeerEndpoint { }, } +/// Part of the `NetworkState` struct. Unstable. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum Endpoint { + /// The socket comes from a dialer. + Dialer, + /// The socket comes from a listener. + Listener, +} + impl From for PeerEndpoint { fn from(endpoint: ConnectedPoint) -> Self { match endpoint { - ConnectedPoint::Dialer { address } => Self::Dialing(address), + ConnectedPoint::Dialer { address, role_override } => + Self::Dialing(address, role_override.into()), ConnectedPoint::Listener { local_addr, send_back_addr } => Self::Listening { local_addr, send_back_addr }, } } } + +impl From for Endpoint { + fn from(endpoint: CoreEndpoint) -> Self { + match endpoint { + CoreEndpoint::Dialer => Self::Dialer, + CoreEndpoint::Listener => Self::Listener, + } + } +} diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index 378c258820ffb..c3e79437bdd06 100644 --- a/client/network/src/peer_info.rs +++ b/client/network/src/peer_info.rs @@ -28,8 +28,8 @@ use libp2p::{ identify::{Identify, IdentifyConfig, IdentifyEvent, IdentifyInfo}, ping::{Ping, PingConfig, PingEvent, PingSuccess}, swarm::{ - IntoProtocolsHandler, IntoProtocolsHandlerSelect, NetworkBehaviour, NetworkBehaviourAction, - PollParameters, ProtocolsHandler, + ConnectionHandler, IntoConnectionHandler, IntoConnectionHandlerSelect, NetworkBehaviour, + NetworkBehaviourAction, PollParameters, }, Multiaddr, }; @@ -170,14 +170,14 @@ pub enum PeerInfoEvent { } impl NetworkBehaviour for PeerInfoBehaviour { - type ProtocolsHandler = IntoProtocolsHandlerSelect< - ::ProtocolsHandler, - ::ProtocolsHandler, + type ConnectionHandler = IntoConnectionHandlerSelect< + ::ConnectionHandler, + ::ConnectionHandler, >; type OutEvent = PeerInfoEvent; - fn new_handler(&mut self) -> Self::ProtocolsHandler { - IntoProtocolsHandler::select(self.ping.new_handler(), self.identify.new_handler()) + fn new_handler(&mut self) -> Self::ConnectionHandler { + IntoConnectionHandler::select(self.ping.new_handler(), self.identify.new_handler()) } fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { @@ -195,11 +195,18 @@ impl NetworkBehaviour for PeerInfoBehaviour { ) { self.ping.inject_address_change(peer_id, conn, old, new); self.identify.inject_address_change(peer_id, conn, old, new); - } - fn inject_connected(&mut self, peer_id: &PeerId) { - self.ping.inject_connected(peer_id); - self.identify.inject_connected(peer_id); + if let Some(entry) = self.nodes_info.get_mut(peer_id) { + if let Some(endpoint) = entry.endpoints.iter_mut().find(|e| e == &old) { + *endpoint = new.clone(); + } else { + error!(target: "sub-libp2p", + "Unknown address change for peer {:?} from {:?} to {:?}", peer_id, old, new); + } + } else { + error!(target: "sub-libp2p", + "Unknown peer {:?} to change address from {:?} to {:?}", peer_id, old, new); + } } fn inject_connection_established( @@ -208,11 +215,22 @@ impl NetworkBehaviour for PeerInfoBehaviour { conn: &ConnectionId, endpoint: &ConnectedPoint, failed_addresses: Option<&Vec>, + other_established: usize, ) { - self.ping - .inject_connection_established(peer_id, conn, endpoint, failed_addresses); - self.identify - .inject_connection_established(peer_id, conn, endpoint, failed_addresses); + self.ping.inject_connection_established( + peer_id, + conn, + endpoint, + failed_addresses, + other_established, + ); + self.identify.inject_connection_established( + peer_id, + conn, + endpoint, + failed_addresses, + other_established, + ); match self.nodes_info.entry(*peer_id) { Entry::Vacant(e) => { e.insert(NodeInfo::new(endpoint.clone())); @@ -234,14 +252,29 @@ impl NetworkBehaviour for PeerInfoBehaviour { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, - handler: ::Handler, + handler: ::Handler, + remaining_established: usize, ) { let (ping_handler, identity_handler) = handler.into_inner(); - self.identify - .inject_connection_closed(peer_id, conn, endpoint, identity_handler); - self.ping.inject_connection_closed(peer_id, conn, endpoint, ping_handler); + self.identify.inject_connection_closed( + peer_id, + conn, + endpoint, + identity_handler, + remaining_established, + ); + self.ping.inject_connection_closed( + peer_id, + conn, + endpoint, + ping_handler, + remaining_established, + ); if let Some(entry) = self.nodes_info.get_mut(peer_id) { + if remaining_established == 0 { + entry.info_expire = Some(Instant::now() + CACHE_EXPIRE); + } entry.endpoints.retain(|ep| ep != endpoint) } else { error!(target: "sub-libp2p", @@ -249,23 +282,11 @@ impl NetworkBehaviour for PeerInfoBehaviour { } } - fn inject_disconnected(&mut self, peer_id: &PeerId) { - self.ping.inject_disconnected(peer_id); - self.identify.inject_disconnected(peer_id); - - if let Some(entry) = self.nodes_info.get_mut(peer_id) { - entry.info_expire = Some(Instant::now() + CACHE_EXPIRE); - } else { - error!(target: "sub-libp2p", - "Disconnected from node we were not connected to {:?}", peer_id); - } - } - fn inject_event( &mut self, peer_id: PeerId, connection: ConnectionId, - event: <::Handler as ProtocolsHandler>::OutEvent, + event: <::Handler as ConnectionHandler>::OutEvent, ) { match event { EitherOutput::First(event) => self.ping.inject_event(peer_id, connection, event), @@ -276,7 +297,7 @@ impl NetworkBehaviour for PeerInfoBehaviour { fn inject_dial_failure( &mut self, peer_id: Option, - handler: Self::ProtocolsHandler, + handler: Self::ConnectionHandler, error: &libp2p::swarm::DialError, ) { let (ping_handler, identity_handler) = handler.into_inner(); @@ -313,7 +334,7 @@ impl NetworkBehaviour for PeerInfoBehaviour { &mut self, local_addr: &Multiaddr, send_back_addr: &Multiaddr, - handler: Self::ProtocolsHandler, + handler: Self::ConnectionHandler, ) { let (ping_handler, identity_handler) = handler.into_inner(); self.identify @@ -335,7 +356,7 @@ impl NetworkBehaviour for PeerInfoBehaviour { &mut self, cx: &mut Context, params: &mut impl PollParameters, - ) -> Poll> { + ) -> Poll> { loop { match self.ping.poll(cx, params) { Poll::Pending => break, @@ -344,19 +365,10 @@ impl NetworkBehaviour for PeerInfoBehaviour { self.handle_ping_report(&peer, rtt) } }, - Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) => { + Poll::Ready(NetworkBehaviourAction::Dial { opts, handler }) => { let handler = - IntoProtocolsHandler::select(handler, self.identify.new_handler()); - return Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) - }, - Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition, handler }) => { - let handler = - IntoProtocolsHandler::select(handler, self.identify.new_handler()); - return Poll::Ready(NetworkBehaviourAction::DialPeer { - peer_id, - condition, - handler, - }) + IntoConnectionHandler::select(handler, self.identify.new_handler()); + return Poll::Ready(NetworkBehaviourAction::Dial { opts, handler }) }, Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, handler, event }) => return Poll::Ready(NetworkBehaviourAction::NotifyHandler { @@ -392,17 +404,9 @@ impl NetworkBehaviour for PeerInfoBehaviour { IdentifyEvent::Pushed { .. } => {}, IdentifyEvent::Sent { .. } => {}, }, - Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) => { - let handler = IntoProtocolsHandler::select(self.ping.new_handler(), handler); - return Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) - }, - Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition, handler }) => { - let handler = IntoProtocolsHandler::select(self.ping.new_handler(), handler); - return Poll::Ready(NetworkBehaviourAction::DialPeer { - peer_id, - condition, - handler, - }) + Poll::Ready(NetworkBehaviourAction::Dial { opts, handler }) => { + let handler = IntoConnectionHandler::select(self.ping.new_handler(), handler); + return Poll::Ready(NetworkBehaviourAction::Dial { opts, handler }) }, Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, handler, event }) => return Poll::Ready(NetworkBehaviourAction::NotifyHandler { diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 80694210e77dc..8497dfd940de0 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -36,8 +36,8 @@ use libp2p::{ }, request_response::OutboundFailure, swarm::{ - IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters, - ProtocolsHandler, + ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, + PollParameters, }, Multiaddr, PeerId, }; @@ -1367,10 +1367,10 @@ pub enum CustomMessageOutcome { } impl NetworkBehaviour for Protocol { - type ProtocolsHandler = ::ProtocolsHandler; + type ConnectionHandler = ::ConnectionHandler; type OutEvent = CustomMessageOutcome; - fn new_handler(&mut self) -> Self::ProtocolsHandler { + fn new_handler(&mut self) -> Self::ConnectionHandler { self.behaviour.new_handler() } @@ -1384,9 +1384,15 @@ impl NetworkBehaviour for Protocol { conn: &ConnectionId, endpoint: &ConnectedPoint, failed_addresses: Option<&Vec>, + other_established: usize, ) { - self.behaviour - .inject_connection_established(peer_id, conn, endpoint, failed_addresses) + self.behaviour.inject_connection_established( + peer_id, + conn, + endpoint, + failed_addresses, + other_established, + ) } fn inject_connection_closed( @@ -1394,24 +1400,23 @@ impl NetworkBehaviour for Protocol { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, - handler: ::Handler, + handler: ::Handler, + remaining_established: usize, ) { - self.behaviour.inject_connection_closed(peer_id, conn, endpoint, handler) - } - - fn inject_connected(&mut self, peer_id: &PeerId) { - self.behaviour.inject_connected(peer_id) - } - - fn inject_disconnected(&mut self, peer_id: &PeerId) { - self.behaviour.inject_disconnected(peer_id) + self.behaviour.inject_connection_closed( + peer_id, + conn, + endpoint, + handler, + remaining_established, + ) } fn inject_event( &mut self, peer_id: PeerId, connection: ConnectionId, - event: <::Handler as ProtocolsHandler>::OutEvent, + event: <::Handler as ConnectionHandler>::OutEvent, ) { self.behaviour.inject_event(peer_id, connection, event) } @@ -1420,7 +1425,7 @@ impl NetworkBehaviour for Protocol { &mut self, cx: &mut std::task::Context, params: &mut impl PollParameters, - ) -> Poll> { + ) -> Poll> { if let Some(message) = self.pending_messages.pop_front() { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(message)) } @@ -1581,10 +1586,8 @@ impl NetworkBehaviour for Protocol { let event = match self.behaviour.poll(cx, params) { Poll::Pending => return Poll::Pending, Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) => ev, - Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) => - return Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }), - Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition, handler }) => - return Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition, handler }), + Poll::Ready(NetworkBehaviourAction::Dial { opts, handler }) => + return Poll::Ready(NetworkBehaviourAction::Dial { opts, handler }), Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, handler, event }) => return Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, @@ -1800,7 +1803,7 @@ impl NetworkBehaviour for Protocol { fn inject_dial_failure( &mut self, peer_id: Option, - handler: Self::ProtocolsHandler, + handler: Self::ConnectionHandler, error: &libp2p::swarm::DialError, ) { self.behaviour.inject_dial_failure(peer_id, handler, error); diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index b47216473970e..61f7db78c98b1 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -26,8 +26,8 @@ use futures::prelude::*; use libp2p::{ core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId}, swarm::{ - DialError, DialPeerCondition, IntoProtocolsHandler, NetworkBehaviour, - NetworkBehaviourAction, NotifyHandler, PollParameters, + DialError, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, + PollParameters, }, }; use log::{error, trace, warn}; @@ -620,10 +620,8 @@ impl Notifications { set_id, ); trace!(target: "sub-libp2p", "Libp2p <= Dial {}", entry.key().0); - // The `DialPeerCondition` ensures that dial attempts are de-duplicated - self.events.push_back(NetworkBehaviourAction::DialPeer { - peer_id: entry.key().0.clone(), - condition: DialPeerCondition::Disconnected, + self.events.push_back(NetworkBehaviourAction::Dial { + opts: entry.key().0.clone().into(), handler, }); entry.insert(PeerState::Requested); @@ -657,10 +655,8 @@ impl Notifications { set_id, ); trace!(target: "sub-libp2p", "Libp2p <= Dial {:?}", occ_entry.key()); - // The `DialPeerCondition` ensures that dial attempts are de-duplicated - self.events.push_back(NetworkBehaviourAction::DialPeer { - peer_id: occ_entry.key().0.clone(), - condition: DialPeerCondition::Disconnected, + self.events.push_back(NetworkBehaviourAction::Dial { + opts: occ_entry.key().0.clone().into(), handler, }); *occ_entry.into_mut() = PeerState::Requested; @@ -1059,10 +1055,10 @@ impl Notifications { } impl NetworkBehaviour for Notifications { - type ProtocolsHandler = NotifsHandlerProto; + type ConnectionHandler = NotifsHandlerProto; type OutEvent = NotificationsOut; - fn new_handler(&mut self) -> Self::ProtocolsHandler { + fn new_handler(&mut self) -> Self::ConnectionHandler { NotifsHandlerProto::new(self.notif_protocols.clone()) } @@ -1070,14 +1066,13 @@ impl NetworkBehaviour for Notifications { Vec::new() } - fn inject_connected(&mut self, _: &PeerId) {} - fn inject_connection_established( &mut self, peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, _failed_addresses: Option<&Vec>, + _other_established: usize, ) { for set_id in (0..self.notif_protocols.len()).map(sc_peerset::SetId::from) { match self.peers.entry((*peer_id, set_id)).or_insert(PeerState::Poisoned) { @@ -1136,7 +1131,8 @@ impl NetworkBehaviour for Notifications { peer_id: &PeerId, conn: &ConnectionId, _endpoint: &ConnectedPoint, - _handler: ::Handler, + _handler: ::Handler, + _remaining_established: usize, ) { for set_id in (0..self.notif_protocols.len()).map(sc_peerset::SetId::from) { let mut entry = if let Entry::Occupied(entry) = self.peers.entry((*peer_id, set_id)) { @@ -1394,12 +1390,10 @@ impl NetworkBehaviour for Notifications { } } - fn inject_disconnected(&mut self, _peer_id: &PeerId) {} - fn inject_dial_failure( &mut self, peer_id: Option, - _: Self::ProtocolsHandler, + _: Self::ConnectionHandler, error: &DialError, ) { if let DialError::Transport(errors) = error { @@ -1989,7 +1983,7 @@ impl NetworkBehaviour for Notifications { &mut self, cx: &mut Context, _params: &mut impl PollParameters, - ) -> Poll> { + ) -> Poll> { if let Some(event) = self.events.pop_front() { return Poll::Ready(event) } @@ -2038,12 +2032,8 @@ impl NetworkBehaviour for Notifications { PeerState::PendingRequest { timer, .. } if *timer == delay_id => { trace!(target: "sub-libp2p", "Libp2p <= Dial {:?} now that ban has expired", peer_id); - // The `DialPeerCondition` ensures that dial attempts are de-duplicated - self.events.push_back(NetworkBehaviourAction::DialPeer { - peer_id, - condition: DialPeerCondition::Disconnected, - handler, - }); + self.events + .push_back(NetworkBehaviourAction::Dial { opts: peer_id.into(), handler }); *peer_state = PeerState::Requested; }, diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index 91225f54203af..510f72d4b0123 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -16,10 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Implementations of the `IntoProtocolsHandler` and `ProtocolsHandler` traits for both incoming +//! Implementations of the `IntoConnectionHandler` and `ConnectionHandler` traits for both incoming //! and outgoing substreams for all gossiping protocols. //! -//! This is the main implementation of `ProtocolsHandler` in this crate, that handles all the +//! This is the main implementation of `ConnectionHandler` in this crate, that handles all the //! gossiping protocols that are Substrate-related and outside of the scope of libp2p. //! //! # Usage @@ -74,8 +74,8 @@ use libp2p::{ ConnectedPoint, PeerId, }, swarm::{ - IntoProtocolsHandler, KeepAlive, NegotiatedSubstream, ProtocolsHandler, - ProtocolsHandlerEvent, ProtocolsHandlerUpgrErr, SubstreamProtocol, + ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, IntoConnectionHandler, + KeepAlive, NegotiatedSubstream, SubstreamProtocol, }, }; use log::error; @@ -107,7 +107,7 @@ const OPEN_TIMEOUT: Duration = Duration::from_secs(10); /// open substreams. const INITIAL_KEEPALIVE_TIME: Duration = Duration::from_secs(5); -/// Implements the `IntoProtocolsHandler` trait of libp2p. +/// Implements the `IntoConnectionHandler` trait of libp2p. /// /// Every time a connection with a remote starts, an instance of this struct is created and /// sent to a background task dedicated to this connection. Once the connection is established, @@ -138,7 +138,7 @@ pub struct NotifsHandler { /// Events to return in priority from `poll`. events_queue: VecDeque< - ProtocolsHandlerEvent, + ConnectionHandlerEvent, >, } @@ -225,7 +225,7 @@ enum State { }, } -impl IntoProtocolsHandler for NotifsHandlerProto { +impl IntoConnectionHandler for NotifsHandlerProto { type Handler = NotifsHandler; fn inbound_protocol(&self) -> UpgradeCollec { @@ -475,7 +475,7 @@ impl NotifsHandlerProto { } } -impl ProtocolsHandler for NotifsHandler { +impl ConnectionHandler for NotifsHandler { type InEvent = NotifsHandlerIn; type OutEvent = NotifsHandlerOut; type Error = NotifsHandlerError; @@ -505,7 +505,7 @@ impl ProtocolsHandler for NotifsHandler { let mut protocol_info = &mut self.protocols[protocol_index]; match protocol_info.state { State::Closed { pending_opening } => { - self.events_queue.push_back(ProtocolsHandlerEvent::Custom( + self.events_queue.push_back(ConnectionHandlerEvent::Custom( NotifsHandlerOut::OpenDesiredByRemote { protocol_index }, )); @@ -573,7 +573,7 @@ impl ProtocolsHandler for NotifsHandler { in_substream: in_substream.take(), }; - self.events_queue.push_back(ProtocolsHandlerEvent::Custom( + self.events_queue.push_back(ConnectionHandlerEvent::Custom( NotifsHandlerOut::OpenResultOk { protocol_index, negotiated_fallback: new_open.negotiated_fallback, @@ -601,7 +601,7 @@ impl ProtocolsHandler for NotifsHandler { ); self.events_queue.push_back( - ProtocolsHandlerEvent::OutboundSubstreamRequest { + ConnectionHandlerEvent::OutboundSubstreamRequest { protocol: SubstreamProtocol::new(proto, protocol_index) .with_timeout(OPEN_TIMEOUT), }, @@ -622,7 +622,7 @@ impl ProtocolsHandler for NotifsHandler { ); self.events_queue.push_back( - ProtocolsHandlerEvent::OutboundSubstreamRequest { + ConnectionHandlerEvent::OutboundSubstreamRequest { protocol: SubstreamProtocol::new(proto, protocol_index) .with_timeout(OPEN_TIMEOUT), }, @@ -660,7 +660,7 @@ impl ProtocolsHandler for NotifsHandler { self.protocols[protocol_index].state = State::Closed { pending_opening: true }; - self.events_queue.push_back(ProtocolsHandlerEvent::Custom( + self.events_queue.push_back(ConnectionHandlerEvent::Custom( NotifsHandlerOut::OpenResultErr { protocol_index }, )); }, @@ -670,7 +670,7 @@ impl ProtocolsHandler for NotifsHandler { State::Closed { .. } => {}, } - self.events_queue.push_back(ProtocolsHandlerEvent::Custom( + self.events_queue.push_back(ConnectionHandlerEvent::Custom( NotifsHandlerOut::CloseResult { protocol_index }, )); }, @@ -680,7 +680,7 @@ impl ProtocolsHandler for NotifsHandler { fn inject_dial_upgrade_error( &mut self, num: usize, - _: ProtocolsHandlerUpgrErr, + _: ConnectionHandlerUpgrErr, ) { match self.protocols[num].state { State::Closed { ref mut pending_opening } | @@ -692,7 +692,7 @@ impl ProtocolsHandler for NotifsHandler { State::Opening { .. } => { self.protocols[num].state = State::Closed { pending_opening: false }; - self.events_queue.push_back(ProtocolsHandlerEvent::Custom( + self.events_queue.push_back(ConnectionHandlerEvent::Custom( NotifsHandlerOut::OpenResultErr { protocol_index: num }, )); }, @@ -717,7 +717,7 @@ impl ProtocolsHandler for NotifsHandler { &mut self, cx: &mut Context, ) -> Poll< - ProtocolsHandlerEvent< + ConnectionHandlerEvent< Self::OutboundProtocol, Self::OutboundOpenInfo, Self::OutEvent, @@ -741,7 +741,7 @@ impl ProtocolsHandler for NotifsHandler { // a substream is ready to send if there isn't actually something to send. match Pin::new(&mut *notifications_sink_rx).as_mut().poll_peek(cx) { Poll::Ready(Some(&NotificationsSinkMessage::ForceClose)) => - return Poll::Ready(ProtocolsHandlerEvent::Close( + return Poll::Ready(ConnectionHandlerEvent::Close( NotifsHandlerError::SyncNotificationsClogged, )), Poll::Ready(Some(&NotificationsSinkMessage::Notification { .. })) => {}, @@ -789,7 +789,7 @@ impl ProtocolsHandler for NotifsHandler { Poll::Ready(Err(_)) => { *out_substream = None; let event = NotifsHandlerOut::CloseDesired { protocol_index }; - return Poll::Ready(ProtocolsHandlerEvent::Custom(event)) + return Poll::Ready(ConnectionHandlerEvent::Custom(event)) }, }; }, @@ -815,7 +815,7 @@ impl ProtocolsHandler for NotifsHandler { Poll::Pending => {}, Poll::Ready(Some(Ok(message))) => { let event = NotifsHandlerOut::Notification { protocol_index, message }; - return Poll::Ready(ProtocolsHandlerEvent::Custom(event)) + return Poll::Ready(ConnectionHandlerEvent::Custom(event)) }, Poll::Ready(None) | Poll::Ready(Some(Err(_))) => *in_substream = None, }, @@ -827,7 +827,7 @@ impl ProtocolsHandler for NotifsHandler { Poll::Ready(Err(_)) => { self.protocols[protocol_index].state = State::Closed { pending_opening: *pending_opening }; - return Poll::Ready(ProtocolsHandlerEvent::Custom( + return Poll::Ready(ConnectionHandlerEvent::Custom( NotifsHandlerOut::CloseDesired { protocol_index }, )) }, diff --git a/client/network/src/protocol/notifications/tests.rs b/client/network/src/protocol/notifications/tests.rs index 73058598a1e3b..da12dbf216c4c 100644 --- a/client/network/src/protocol/notifications/tests.rs +++ b/client/network/src/protocol/notifications/tests.rs @@ -29,8 +29,8 @@ use libp2p::{ }, identity, noise, swarm::{ - DialError, IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters, - ProtocolsHandler, Swarm, SwarmEvent, + ConnectionHandler, DialError, IntoConnectionHandler, NetworkBehaviour, + NetworkBehaviourAction, PollParameters, Swarm, SwarmEvent, }, yamux, Multiaddr, PeerId, Transport, }; @@ -133,10 +133,10 @@ impl std::ops::DerefMut for CustomProtoWithAddr { } impl NetworkBehaviour for CustomProtoWithAddr { - type ProtocolsHandler = ::ProtocolsHandler; + type ConnectionHandler = ::ConnectionHandler; type OutEvent = ::OutEvent; - fn new_handler(&mut self) -> Self::ProtocolsHandler { + fn new_handler(&mut self) -> Self::ConnectionHandler { self.inner.new_handler() } @@ -150,23 +150,21 @@ impl NetworkBehaviour for CustomProtoWithAddr { list } - fn inject_connected(&mut self, peer_id: &PeerId) { - self.inner.inject_connected(peer_id) - } - - fn inject_disconnected(&mut self, peer_id: &PeerId) { - self.inner.inject_disconnected(peer_id) - } - fn inject_connection_established( &mut self, peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, failed_addresses: Option<&Vec>, + other_established: usize, ) { - self.inner - .inject_connection_established(peer_id, conn, endpoint, failed_addresses) + self.inner.inject_connection_established( + peer_id, + conn, + endpoint, + failed_addresses, + other_established, + ) } fn inject_connection_closed( @@ -174,16 +172,18 @@ impl NetworkBehaviour for CustomProtoWithAddr { peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, - handler: ::Handler, + handler: ::Handler, + remaining_established: usize, ) { - self.inner.inject_connection_closed(peer_id, conn, endpoint, handler) + self.inner + .inject_connection_closed(peer_id, conn, endpoint, handler, remaining_established) } fn inject_event( &mut self, peer_id: PeerId, connection: ConnectionId, - event: <::Handler as ProtocolsHandler>::OutEvent, + event: <::Handler as ConnectionHandler>::OutEvent, ) { self.inner.inject_event(peer_id, connection, event) } @@ -192,14 +192,14 @@ impl NetworkBehaviour for CustomProtoWithAddr { &mut self, cx: &mut Context, params: &mut impl PollParameters, - ) -> Poll> { + ) -> Poll> { self.inner.poll(cx, params) } fn inject_dial_failure( &mut self, peer_id: Option, - handler: Self::ProtocolsHandler, + handler: Self::ConnectionHandler, error: &DialError, ) { self.inner.inject_dial_failure(peer_id, handler, error) diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 4613a15af9366..87d070bc469a3 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -49,8 +49,8 @@ use libp2p::{ RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, ResponseChannel, }, swarm::{ - protocols_handler::multi::MultiHandler, IntoProtocolsHandler, NetworkBehaviour, - NetworkBehaviourAction, PollParameters, ProtocolsHandler, + handler::multi::MultiHandler, ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, + NetworkBehaviourAction, PollParameters, }, }; use std::{ @@ -381,7 +381,7 @@ impl RequestResponsesBehaviour { &mut self, protocol: String, handler: RequestResponseHandler, - ) -> ::ProtocolsHandler { + ) -> ::ConnectionHandler { let mut handlers: HashMap<_, _> = self .protocols .iter_mut() @@ -400,11 +400,13 @@ impl RequestResponsesBehaviour { } impl NetworkBehaviour for RequestResponsesBehaviour { - type ProtocolsHandler = - MultiHandler as NetworkBehaviour>::ProtocolsHandler>; + type ConnectionHandler = MultiHandler< + String, + as NetworkBehaviour>::ConnectionHandler, + >; type OutEvent = Event; - fn new_handler(&mut self) -> Self::ProtocolsHandler { + fn new_handler(&mut self) -> Self::ConnectionHandler { let iter = self .protocols .iter_mut() @@ -426,6 +428,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { conn: &ConnectionId, endpoint: &ConnectedPoint, failed_addresses: Option<&Vec>, + other_established: usize, ) { for (p, _) in self.protocols.values_mut() { NetworkBehaviour::inject_connection_established( @@ -434,32 +437,35 @@ impl NetworkBehaviour for RequestResponsesBehaviour { conn, endpoint, failed_addresses, + other_established, ) } } - fn inject_connected(&mut self, peer_id: &PeerId) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_connected(p, peer_id) - } - } - fn inject_connection_closed( &mut self, peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint, - _handler: ::Handler, + handler: ::Handler, + remaining_established: usize, ) { - for (p, _) in self.protocols.values_mut() { - let handler = p.new_handler(); - NetworkBehaviour::inject_connection_closed(p, peer_id, conn, endpoint, handler); - } - } - - fn inject_disconnected(&mut self, peer_id: &PeerId) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_disconnected(p, peer_id) + for (p_name, event) in handler.into_iter() { + if let Some((proto, _)) = self.protocols.get_mut(p_name.as_str()) { + proto.inject_connection_closed( + peer_id, + conn, + endpoint, + event, + remaining_established, + ) + } else { + log::error!( + target: "sub-libp2p", + "inject_connection_closed: no request-response instance registered for protocol {:?}", + p_name, + ) + } } } @@ -467,7 +473,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { &mut self, peer_id: PeerId, connection: ConnectionId, - (p_name, event): ::OutEvent, + (p_name, event): ::OutEvent, ) { if let Some((proto, _)) = self.protocols.get_mut(&*p_name) { return proto.inject_event(peer_id, connection, event) @@ -499,7 +505,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { fn inject_dial_failure( &mut self, peer_id: Option, - _: Self::ProtocolsHandler, + _: Self::ConnectionHandler, error: &libp2p::swarm::DialError, ) { for (p, _) in self.protocols.values_mut() { @@ -536,7 +542,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { &mut self, cx: &mut Context, params: &mut impl PollParameters, - ) -> Poll> { + ) -> Poll> { 'poll_all: loop { if let Some(message_request) = self.message_request.take() { // Now we can can poll `MessageRequest` until we get the reputation @@ -677,25 +683,15 @@ impl NetworkBehaviour for RequestResponsesBehaviour { // Other events generated by the underlying behaviour are transparently // passed through. - NetworkBehaviourAction::DialAddress { address, handler } => { - log::error!( - "The request-response isn't supposed to start dialing peers" - ); - let protocol = protocol.to_string(); - let handler = self.new_handler_with_replacement(protocol, handler); - return Poll::Ready(NetworkBehaviourAction::DialAddress { - address, - handler, - }) - }, - NetworkBehaviourAction::DialPeer { peer_id, condition, handler } => { + NetworkBehaviourAction::Dial { opts, handler } => { + if opts.get_peer_id().is_none() { + log::error!( + "The request-response isn't supposed to start dialing addresses" + ); + } let protocol = protocol.to_string(); let handler = self.new_handler_with_replacement(protocol, handler); - return Poll::Ready(NetworkBehaviourAction::DialPeer { - peer_id, - condition, - handler, - }) + return Poll::Ready(NetworkBehaviourAction::Dial { opts, handler }) }, NetworkBehaviourAction::NotifyHandler { peer_id, handler, event } => return Poll::Ready(NetworkBehaviourAction::NotifyHandler { @@ -1146,7 +1142,7 @@ mod tests { // this test, so they wouldn't connect to each other. { let dial_addr = swarms[1].1.clone(); - Swarm::dial_addr(&mut swarms[0].0, dial_addr).unwrap(); + Swarm::dial(&mut swarms[0].0, dial_addr).unwrap(); } let (mut swarm, _, peerset) = swarms.remove(0); @@ -1246,7 +1242,7 @@ mod tests { // this test, so they wouldn't connect to each other. { let dial_addr = swarms[1].1.clone(); - Swarm::dial_addr(&mut swarms[0].0, dial_addr).unwrap(); + Swarm::dial(&mut swarms[0].0, dial_addr).unwrap(); } // Running `swarm[0]` in the background until a `InboundRequest` event happens, @@ -1375,7 +1371,7 @@ mod tests { // Ask swarm 1 to dial swarm 2. There isn't any discovery mechanism in place in this test, // so they wouldn't connect to each other. - swarm_1.dial_addr(listen_add_2).unwrap(); + swarm_1.dial(listen_add_2).unwrap(); // Run swarm 2 in the background, receiving two requests. pool.spawner() diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 7239c9f6f9e6a..e88e7924954b3 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -49,16 +49,12 @@ use crate::{ use codec::Encode as _; use futures::{channel::oneshot, prelude::*}; use libp2p::{ - core::{ - connection::{ConnectionError, ConnectionLimits, PendingConnectionError}, - either::EitherError, - upgrade, ConnectedPoint, Executor, - }, + core::{either::EitherError, upgrade, ConnectedPoint, Executor}, multiaddr, ping::Failure as PingFailure, swarm::{ - protocols_handler::NodeHandlerWrapperError, AddressScore, DialError, NetworkBehaviour, - SwarmBuilder, SwarmEvent, + AddressScore, ConnectionError, ConnectionLimits, DialError, NetworkBehaviour, + PendingConnectionError, SwarmBuilder, SwarmEvent, }, Multiaddr, PeerId, }; @@ -1531,7 +1527,7 @@ impl Future for NetworkWorker { ServiceToWorkerMsg::PropagateTransactions => this.tx_handler_controller.propagate_transactions(), ServiceToWorkerMsg::GetValue(key) => - this.network_service.behaviour_mut().get_value(&key), + this.network_service.behaviour_mut().get_value(key), ServiceToWorkerMsg::PutValue(key, value) => this.network_service.behaviour_mut().put_value(key, value), ServiceToWorkerMsg::SetReservedOnly(reserved_only) => this @@ -1897,21 +1893,18 @@ impl Future for NetworkWorker { }; let reason = match cause { Some(ConnectionError::IO(_)) => "transport-error", - Some(ConnectionError::Handler(NodeHandlerWrapperError::Handler( - EitherError::A(EitherError::A(EitherError::A(EitherError::B( - EitherError::A(PingFailure::Timeout), - )))), - ))) => "ping-timeout", - Some(ConnectionError::Handler(NodeHandlerWrapperError::Handler( - EitherError::A(EitherError::A(EitherError::A(EitherError::A( + Some(ConnectionError::Handler(EitherError::A(EitherError::A( + EitherError::A(EitherError::B(EitherError::A( + PingFailure::Timeout, + ))), + )))) => "ping-timeout", + Some(ConnectionError::Handler(EitherError::A(EitherError::A( + EitherError::A(EitherError::A( NotifsHandlerError::SyncNotificationsClogged, - )))), - ))) => "sync-notifications-clogged", - Some(ConnectionError::Handler(NodeHandlerWrapperError::Handler(_))) => - "protocol-error", - Some(ConnectionError::Handler( - NodeHandlerWrapperError::KeepAliveTimeout, - )) => "keep-alive-timeout", + )), + )))) => "sync-notifications-clogged", + Some(ConnectionError::Handler(_)) => "protocol-error", + Some(ConnectionError::KeepAliveTimeout) => "keep-alive-timeout", None => "actively-closed", }; metrics @@ -1946,10 +1939,12 @@ impl Future for NetworkWorker { ); if this.boot_node_ids.contains(&peer_id) { - if let DialError::InvalidPeerId = error { + if let DialError::WrongPeerId { obtained, endpoint } = &error { error!( - "💔 The bootnode you want to connect provided a different peer ID than the one you expect: `{}`.", + "💔 The bootnode you want to connect provided a different peer ID than the one you expect: `{}` with `{}`:`{:?}`.", peer_id, + obtained, + endpoint, ); } } @@ -1958,13 +1953,14 @@ impl Future for NetworkWorker { if let Some(metrics) = this.metrics.as_ref() { let reason = match error { DialError::ConnectionLimit(_) => Some("limit-reached"), - DialError::InvalidPeerId => Some("invalid-peer-id"), + DialError::InvalidPeerId(_) => Some("invalid-peer-id"), DialError::Transport(_) | DialError::ConnectionIo(_) => Some("transport-error"), DialError::Banned | DialError::LocalPeerId | DialError::NoAddresses | DialError::DialPeerConditionFalse(_) | + DialError::WrongPeerId { .. } | DialError::Aborted => None, // ignore them }; if let Some(reason) = reason { @@ -1998,7 +1994,7 @@ impl Future for NetworkWorker { if let Some(metrics) = this.metrics.as_ref() { let reason = match error { PendingConnectionError::ConnectionLimit(_) => Some("limit-reached"), - PendingConnectionError::InvalidPeerId => Some("invalid-peer-id"), + PendingConnectionError::WrongPeerId { .. } => Some("invalid-peer-id"), PendingConnectionError::Transport(_) | PendingConnectionError::IO(_) => Some("transport-error"), PendingConnectionError::Aborted => None, // ignore it diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 642654bcb2de5..39297dd3ea295 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -20,7 +20,7 @@ parking_lot = "0.12.0" futures = "0.3.21" futures-timer = "3.0.1" rand = "0.7.2" -libp2p = { version = "0.40.0", default-features = false } +libp2p = { version = "0.44.0", default-features = false } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index 5cda0913da1a1..ee83d186b5417 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" -libp2p = { version = "0.40.0", default-features = false } +libp2p = { version = "0.44.0", default-features = false } sc-utils = { version = "4.0.0-dev", path = "../utils"} log = "0.4.16" serde_json = "1.0.79" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index bb517290cef51..4dfefd06ac737 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] parking_lot = "0.12.0" futures = "0.3.21" wasm-timer = "0.2.5" -libp2p = { version = "0.40.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } +libp2p = { version = "0.44.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.16" pin-project = "1.0.10" rand = "0.7.2" diff --git a/client/telemetry/src/transport.rs b/client/telemetry/src/transport.rs index 23725b44a64dd..e21a2380be255 100644 --- a/client/telemetry/src/transport.rs +++ b/client/telemetry/src/transport.rs @@ -38,8 +38,13 @@ pub(crate) fn initialize_transport() -> Result { let item = libp2p::websocket::framed::OutgoingData::Binary(item); future::ready(Ok::<_, io::Error>(item)) }) - .try_filter(|item| future::ready(item.is_data())) - .map_ok(|data| data.into_bytes()); + .try_filter_map(|item| async move { + if let libp2p::websocket::framed::Incoming::Data(data) = item { + Ok(Some(data.into_bytes())) + } else { + Ok(None) + } + }); future::ready(Ok::<_, io::Error>(connec)) }) }; diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index d23579c8ca2c0..9fbdeb15a0366 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -32,7 +32,7 @@ substrate-bip39 = { version = "0.4.4", optional = true } tiny-bip39 = { version = "0.8.2", optional = true } regex = { version = "1.5.4", optional = true } num-traits = { version = "0.2.8", default-features = false } -zeroize = { version = "1.5.4", default-features = false } +zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.12.0", optional = true } diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index cd97b3efbd9db..81b20ad445cd0 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -311,7 +311,7 @@ pub fn write_results( // Check if there might be multiple instances benchmarked. if all_results.keys().any(|(p, i)| p == pallet && i != instance) { // Create new file: "path/to/pallet_name_instance_name.rs". - file_path.push(pallet.clone() + "_" + &instance.to_snake_case()); + file_path.push(pallet.clone() + "_" + instance.to_snake_case().as_str()); } else { // Create new file: "path/to/pallet_name.rs". file_path.push(pallet.clone()); From 7aa0d43b299eb2a93a2556ecdb07eac1b3265e99 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 29 Apr 2022 17:02:03 +0300 Subject: [PATCH 0746/1472] Network sync refactoring (part 1) (#11303) * Remove unnecessary imports, move one internal re-export into where it is actually used, make one import explicit * Move a few data structures down into modules * Use generic parameters in `sc-network` instead of `chain::Client` trait * Remove unnecessary bound --- client/network/src/behaviour.rs | 112 ++++++++++++++--- client/network/src/bitswap.rs | 28 +++-- client/network/src/block_request_handler.rs | 15 ++- client/network/src/chain.rs | 48 ------- client/network/src/config.rs | 9 +- client/network/src/lib.rs | 1 - .../src/light_client_requests/handler.rs | 20 +-- client/network/src/protocol.rs | 37 ++++-- client/network/src/protocol/sync.rs | 68 ++++------ client/network/src/protocol/sync/state.rs | 32 +++-- client/network/src/protocol/sync/warp.rs | 56 ++++++--- client/network/src/service.rs | 117 ++++++++++++++---- client/network/src/state_request_handler.rs | 14 ++- client/network/test/src/lib.rs | 4 +- client/service/src/lib.rs | 21 +++- 15 files changed, 378 insertions(+), 204 deletions(-) delete mode 100644 client/network/src/chain.rs diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index f6a7e9eb87018..5ff3ba1ad44f4 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -40,8 +40,10 @@ use libp2p::{ }; use log::debug; use prost::Message; +use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::import_queue::{IncomingBlock, Origin}; use sc_peerset::PeersetHandle; +use sp_blockchain::{HeaderBackend, HeaderMetadata}; use sp_consensus::BlockOrigin; use sp_runtime::{ traits::{Block as BlockT, NumberFor}, @@ -62,17 +64,27 @@ pub use crate::request_responses::{ /// General behaviour of the network. Combines all protocols together. #[derive(NetworkBehaviour)] #[behaviour(out_event = "BehaviourOut", poll_method = "poll", event_process = true)] -pub struct Behaviour { +pub struct Behaviour +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ /// All the substrate-specific protocols. - substrate: Protocol, + substrate: Protocol, /// Periodically pings and identifies the nodes we are connected to, and store information in a /// cache. peer_info: peer_info::PeerInfoBehaviour, /// Discovers nodes of the network. discovery: DiscoveryBehaviour, /// Bitswap server for blockchain data. - bitswap: Toggle>, - /// Generic request-reponse protocols. + bitswap: Toggle>, + /// Generic request-response protocols. request_responses: request_responses::RequestResponsesBehaviour, /// Queue of events to produce for the outside. @@ -191,17 +203,27 @@ pub enum BehaviourOut { Dht(DhtEvent, Duration), } -impl Behaviour { +impl Behaviour +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ /// Builds a new `Behaviour`. pub fn new( - substrate: Protocol, + substrate: Protocol, user_agent: String, local_public_key: PublicKey, disco_config: DiscoveryConfig, block_request_protocol_config: request_responses::ProtocolConfig, state_request_protocol_config: request_responses::ProtocolConfig, warp_sync_protocol_config: Option, - bitswap: Option>, + bitswap: Option>, light_client_request_protocol_config: request_responses::ProtocolConfig, // All remaining request protocol configs. mut request_response_protocols: Vec, @@ -293,12 +315,12 @@ impl Behaviour { } /// Returns a shared reference to the user protocol. - pub fn user_protocol(&self) -> &Protocol { + pub fn user_protocol(&self) -> &Protocol { &self.substrate } /// Returns a mutable reference to the user protocol. - pub fn user_protocol_mut(&mut self) -> &mut Protocol { + pub fn user_protocol_mut(&mut self) -> &mut Protocol { &mut self.substrate } @@ -325,13 +347,33 @@ fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole { } } -impl NetworkBehaviourEventProcess for Behaviour { +impl NetworkBehaviourEventProcess for Behaviour +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ fn inject_event(&mut self, event: void::Void) { void::unreachable(event) } } -impl NetworkBehaviourEventProcess> for Behaviour { +impl NetworkBehaviourEventProcess> for Behaviour +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ fn inject_event(&mut self, event: CustomMessageOutcome) { match event { CustomMessageOutcome::BlockImport(origin, blocks) => @@ -435,7 +477,17 @@ impl NetworkBehaviourEventProcess> for Behavi } } -impl NetworkBehaviourEventProcess for Behaviour { +impl NetworkBehaviourEventProcess for Behaviour +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ fn inject_event(&mut self, event: request_responses::Event) { match event { request_responses::Event::InboundRequest { peer, protocol, result } => { @@ -457,7 +509,17 @@ impl NetworkBehaviourEventProcess for Behav } } -impl NetworkBehaviourEventProcess for Behaviour { +impl NetworkBehaviourEventProcess for Behaviour +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ fn inject_event(&mut self, event: peer_info::PeerInfoEvent) { let peer_info::PeerInfoEvent::Identified { peer_id, @@ -480,7 +542,17 @@ impl NetworkBehaviourEventProcess for Behav } } -impl NetworkBehaviourEventProcess for Behaviour { +impl NetworkBehaviourEventProcess for Behaviour +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ fn inject_event(&mut self, out: DiscoveryOut) { match out { DiscoveryOut::UnroutablePeer(_peer_id) => { @@ -514,7 +586,17 @@ impl NetworkBehaviourEventProcess for Behaviour { } } -impl Behaviour { +impl Behaviour +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ fn poll( &mut self, _cx: &mut Context, diff --git a/client/network/src/bitswap.rs b/client/network/src/bitswap.rs index da80ab8cb3d33..c46990997ca05 100644 --- a/client/network/src/bitswap.rs +++ b/client/network/src/bitswap.rs @@ -20,12 +20,9 @@ //! Only supports bitswap 1.2.0. //! CID is expected to reference 256-bit Blake2b transaction hash. -use crate::{ - chain::Client, - schema::bitswap::{ - message::{wantlist::WantType, Block as MessageBlock, BlockPresence, BlockPresenceType}, - Message as BitswapMessage, - }, +use crate::schema::bitswap::{ + message::{wantlist::WantType, Block as MessageBlock, BlockPresence, BlockPresenceType}, + Message as BitswapMessage, }; use cid::Version; use core::pin::Pin; @@ -44,10 +41,12 @@ use libp2p::{ }; use log::{debug, error, trace}; use prost::Message; +use sc_client_api::BlockBackend; use sp_runtime::traits::Block as BlockT; use std::{ collections::VecDeque, io, + marker::PhantomData, sync::Arc, task::{Context, Poll}, }; @@ -181,19 +180,24 @@ impl Prefix { } /// Network behaviour that handles sending and receiving IPFS blocks. -pub struct Bitswap { - client: Arc>, +pub struct Bitswap { + client: Arc, ready_blocks: VecDeque<(PeerId, BitswapMessage)>, + _block: PhantomData, } -impl Bitswap { +impl Bitswap { /// Create a new instance of the bitswap protocol handler. - pub fn new(client: Arc>) -> Self { - Self { client, ready_blocks: Default::default() } + pub fn new(client: Arc) -> Self { + Self { client, ready_blocks: Default::default(), _block: PhantomData::default() } } } -impl NetworkBehaviour for Bitswap { +impl NetworkBehaviour for Bitswap +where + B: BlockT, + Client: BlockBackend + Send + Sync + 'static, +{ type ConnectionHandler = OneShotHandler; type OutEvent = void::Void; diff --git a/client/network/src/block_request_handler.rs b/client/network/src/block_request_handler.rs index e1fe9ebf8d060..2e238c01636d5 100644 --- a/client/network/src/block_request_handler.rs +++ b/client/network/src/block_request_handler.rs @@ -18,7 +18,6 @@ //! `crate::request_responses::RequestResponsesBehaviour`. use crate::{ - chain::Client, config::ProtocolId, protocol::message::BlockAttributes, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, @@ -33,6 +32,8 @@ use futures::{ use log::debug; use lru::LruCache; use prost::Message; +use sc_client_api::BlockBackend; +use sp_blockchain::HeaderBackend; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header, One, Zero}, @@ -113,8 +114,8 @@ enum SeenRequestsValue { } /// Handler for incoming block requests from a remote peer. -pub struct BlockRequestHandler { - client: Arc>, +pub struct BlockRequestHandler { + client: Arc, request_receiver: mpsc::Receiver, /// Maps from request to number of times we have seen this request. /// @@ -122,11 +123,15 @@ pub struct BlockRequestHandler { seen_requests: LruCache, SeenRequestsValue>, } -impl BlockRequestHandler { +impl BlockRequestHandler +where + B: BlockT, + Client: HeaderBackend + BlockBackend + Send + Sync + 'static, +{ /// Create a new [`BlockRequestHandler`]. pub fn new( protocol_id: &ProtocolId, - client: Arc>, + client: Arc, num_peer_hint: usize, ) -> (Self, ProtocolConfig) { // Reserve enough request slots for one request per peer when we are at the maximum diff --git a/client/network/src/chain.rs b/client/network/src/chain.rs deleted file mode 100644 index c66cc2ce1daf5..0000000000000 --- a/client/network/src/chain.rs +++ /dev/null @@ -1,48 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Blockchain access trait - -use sc_client_api::{BlockBackend, ProofProvider}; -pub use sc_client_api::{StorageData, StorageKey}; -pub use sc_consensus::ImportedState; -use sp_blockchain::{Error, HeaderBackend, HeaderMetadata}; -use sp_runtime::traits::{Block as BlockT, BlockIdTo}; - -/// Local client abstraction for the network. -pub trait Client: - HeaderBackend - + ProofProvider - + BlockIdTo - + BlockBackend - + HeaderMetadata - + Send - + Sync -{ -} - -impl Client for T where - T: HeaderBackend - + ProofProvider - + BlockIdTo - + BlockBackend - + HeaderMetadata - + Send - + Sync -{ -} diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 40aefe9a3ec2d..2b448ed14eab0 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -22,7 +22,6 @@ //! See the documentation of [`Params`]. pub use crate::{ - chain::Client, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, @@ -64,7 +63,11 @@ use std::{ use zeroize::Zeroize; /// Network initialization parameters. -pub struct Params { +pub struct Params +where + B: BlockT + 'static, + H: ExHashT, +{ /// Assigned role for our node (full, light, ...). pub role: Role, @@ -79,7 +82,7 @@ pub struct Params { pub network_config: NetworkConfiguration, /// Client that contains the blockchain. - pub chain: Arc>, + pub chain: Arc, /// Pool of transactions. /// diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index d9f5b3de1bb10..973e0b15b7509 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -245,7 +245,6 @@ //! More precise usage details are still being worked on and will likely change in the future. mod behaviour; -mod chain; mod discovery; mod peer_info; mod protocol; diff --git a/client/network/src/light_client_requests/handler.rs b/client/network/src/light_client_requests/handler.rs index fb258304f2e8f..cb9bd960767ff 100644 --- a/client/network/src/light_client_requests/handler.rs +++ b/client/network/src/light_client_requests/handler.rs @@ -23,7 +23,6 @@ //! [`LightClientRequestHandler`](handler::LightClientRequestHandler). use crate::{ - chain::Client, config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, schema, PeerId, @@ -32,27 +31,32 @@ use codec::{self, Decode, Encode}; use futures::{channel::mpsc, prelude::*}; use log::{debug, trace}; use prost::Message; -use sc_client_api::StorageProof; +use sc_client_api::{ProofProvider, StorageProof}; use sc_peerset::ReputationChange; use sp_core::{ hexdisplay::HexDisplay, storage::{ChildInfo, ChildType, PrefixedStorageKey}, }; use sp_runtime::{generic::BlockId, traits::Block}; -use std::sync::Arc; +use std::{marker::PhantomData, sync::Arc}; const LOG_TARGET: &str = "light-client-request-handler"; /// Handler for incoming light client requests from a remote peer. -pub struct LightClientRequestHandler { +pub struct LightClientRequestHandler { request_receiver: mpsc::Receiver, /// Blockchain client. - client: Arc>, + client: Arc, + _block: PhantomData, } -impl LightClientRequestHandler { +impl LightClientRequestHandler +where + B: Block, + Client: ProofProvider + Send + Sync + 'static, +{ /// Create a new [`crate::block_request_handler::BlockRequestHandler`]. - pub fn new(protocol_id: &ProtocolId, client: Arc>) -> (Self, ProtocolConfig) { + pub fn new(protocol_id: &ProtocolId, client: Arc) -> (Self, ProtocolConfig) { // For now due to lack of data on light client request handling in production systems, this // value is chosen to match the block request limit. let (tx, request_receiver) = mpsc::channel(20); @@ -60,7 +64,7 @@ impl LightClientRequestHandler { let mut protocol_config = super::generate_protocol_config(protocol_id); protocol_config.inbound_queue = Some(tx); - (Self { client, request_receiver }, protocol_config) + (Self { client, request_receiver, _block: PhantomData::default() }, protocol_config) } /// Run [`LightClientRequestHandler`]. diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 8497dfd940de0..9999d278a249c 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -17,7 +17,6 @@ // along with this program. If not, see . use crate::{ - chain::Client, config::{self, ProtocolId, WarpSyncProvider}, error, request_responses::RequestFailure, @@ -49,6 +48,7 @@ use message::{ use notifications::{Notifications, NotificationsOut}; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; use prost::Message as _; +use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; use sc_consensus::import_queue::{BlockImportError, BlockImportStatus, IncomingBlock, Origin}; use sp_arithmetic::traits::SaturatedConversion; use sp_consensus::{block_validation::BlockAnnounceValidator, BlockOrigin}; @@ -76,6 +76,7 @@ pub mod message; pub mod sync; pub use notifications::{NotificationsSink, NotifsHandlerError, Ready}; +use sp_blockchain::HeaderMetadata; /// Interval at which we perform time based maintenance const TICK_TIMEOUT: time::Duration = time::Duration::from_millis(1100); @@ -158,7 +159,7 @@ impl Metrics { } // Lock must always be taken in order declared here. -pub struct Protocol { +pub struct Protocol { /// Interval at which we call `tick`. tick_timeout: Pin + Send>>, /// Pending list of messages to return from `poll` as a priority. @@ -167,10 +168,10 @@ pub struct Protocol { genesis_hash: B::Hash, /// State machine that handles the list of in-progress requests. Only full node peers are /// registered. - sync: ChainSync, + sync: ChainSync, // All connected peers. Contains both full and light node peers. peers: HashMap>, - chain: Arc>, + chain: Arc, /// List of nodes for which we perform additional logging because they are important for the /// user. important_peers: HashSet, @@ -283,18 +284,28 @@ impl BlockAnnouncesHandshake { } } -impl Protocol { +impl Protocol +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ /// Create a new instance. pub fn new( config: ProtocolConfig, - chain: Arc>, + chain: Arc, protocol_id: ProtocolId, network_config: &config::NetworkConfiguration, notifications_protocols_handshakes: Vec>, block_announce_validator: Box + Send>, metrics_registry: Option<&Registry>, warp_sync_provider: Option>>, - ) -> error::Result<(Protocol, sc_peerset::PeersetHandle, Vec<(PeerId, Multiaddr)>)> { + ) -> error::Result<(Protocol, sc_peerset::PeersetHandle, Vec<(PeerId, Multiaddr)>)> { let info = chain.info(); let sync = ChainSync::new( config.sync_mode(), @@ -1366,7 +1377,17 @@ pub enum CustomMessageOutcome { None, } -impl NetworkBehaviour for Protocol { +impl NetworkBehaviour for Protocol +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ type ConnectionHandler = ::ConnectionHandler; type OutEvent = CustomMessageOutcome; diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index 749366f6c1653..7e6a2a3c78508 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -39,9 +39,10 @@ use extra_requests::ExtraRequests; use futures::{stream::FuturesUnordered, task::Poll, Future, FutureExt, StreamExt}; use libp2p::PeerId; use log::{debug, error, info, trace, warn}; +use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; use sp_arithmetic::traits::Saturating; -use sp_blockchain::{Error as ClientError, HeaderMetadata}; +use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; use sp_consensus::{ block_validation::{BlockAnnounceValidator, Validation}, BlockOrigin, BlockStatus, @@ -54,6 +55,7 @@ use sp_runtime::{ }, EncodedJustification, Justifications, }; +pub use state::StateDownloadProgress; use state::StateSync; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, @@ -63,6 +65,7 @@ use std::{ sync::Arc, }; use warp::{WarpProofRequest, WarpSync, WarpSyncProvider}; +pub use warp::{WarpSyncPhase, WarpSyncProgress}; mod blocks; mod extra_requests; @@ -194,9 +197,9 @@ struct GapSync { /// The main data structure which contains all the state for a chains /// active syncing strategy. -pub struct ChainSync { +pub struct ChainSync { /// Chain client. - client: Arc>, + client: Arc, /// The active peers that we are using to sync and their PeerSync status peers: HashMap>, /// A `BlockCollection` of blocks that are being downloaded from peers @@ -228,9 +231,9 @@ pub struct ChainSync { /// Stats per peer about the number of concurrent block announce validations. block_announce_validation_per_peer_stats: HashMap, /// State sync in progress, if any. - state_sync: Option>, + state_sync: Option>, /// Warp sync in progress, if any. - warp_sync: Option>, + warp_sync: Option>, /// Warp sync provider. warp_sync_provider: Option>>, /// Enable importing existing blocks. This is used used after the state download to @@ -329,30 +332,6 @@ pub enum SyncState { Downloading, } -/// Reported state download progress. -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct StateDownloadProgress { - /// Estimated download percentage. - pub percentage: u32, - /// Total state size in bytes downloaded so far. - pub size: u64, -} - -/// Reported warp sync phase. -#[derive(Clone, Eq, PartialEq, Debug)] -pub enum WarpSyncPhase { - /// Waiting for peers to connect. - AwaitingPeers, - /// Downloading and verifying grandpa warp proofs. - DownloadingWarpProofs, - /// Downloading state data. - DownloadingState, - /// Importing state. - ImportingState, - /// Downloading block history. - DownloadingBlocks(NumberFor), -} - impl fmt::Display for WarpSyncPhase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -365,15 +344,6 @@ impl fmt::Display for WarpSyncPhase { } } -/// Reported warp sync progress. -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct WarpSyncProgress { - /// Estimated download percentage. - pub phase: WarpSyncPhase, - /// Total bytes downloaded so far. - pub total_bytes: u64, -} - /// Syncing status and statistics. #[derive(Clone)] pub struct Status { @@ -534,11 +504,21 @@ enum HasSlotForBlockAnnounceValidation { MaximumPeerSlotsReached, } -impl ChainSync { +impl ChainSync +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ /// Create a new instance. pub fn new( mode: SyncMode, - client: Arc>, + client: Arc, block_announce_validator: Box + Send>, max_parallel_downloads: u32, warp_sync_provider: Option>>, @@ -2741,7 +2721,11 @@ mod test { } /// Send a block annoucnement for the given `header`. - fn send_block_announce(header: Header, peer_id: &PeerId, sync: &mut ChainSync) { + fn send_block_announce( + header: Header, + peer_id: &PeerId, + sync: &mut ChainSync, + ) { let block_annnounce = BlockAnnounce { header: header.clone(), state: Some(BlockState::Best), @@ -2780,7 +2764,7 @@ mod test { /// Get a block request from `sync` and check that is matches the expected request. fn get_block_request( - sync: &mut ChainSync, + sync: &mut ChainSync, from: FromBlock, max: u32, peer: &PeerId, diff --git a/client/network/src/protocol/sync/state.rs b/client/network/src/protocol/sync/state.rs index 0df862a48333f..4eddc4c60867e 100644 --- a/client/network/src/protocol/sync/state.rs +++ b/client/network/src/protocol/sync/state.rs @@ -16,14 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::StateDownloadProgress; -use crate::{ - chain::{Client, ImportedState}, - schema::v1::{StateEntry, StateRequest, StateResponse}, -}; +use crate::schema::v1::{StateEntry, StateRequest, StateResponse}; use codec::{Decode, Encode}; use log::debug; -use sc_client_api::CompactProof; +use sc_client_api::{CompactProof, ProofProvider}; +use sc_consensus::ImportedState; use smallvec::SmallVec; use sp_core::storage::well_known_keys; use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; @@ -33,18 +30,27 @@ use std::{collections::HashMap, sync::Arc}; /// State sync state machine. Accumulates partial state data until it /// is ready to be imported. -pub struct StateSync { +pub struct StateSync { target_block: B::Hash, target_header: B::Header, target_root: B::Hash, last_key: SmallVec<[Vec; 2]>, state: HashMap, (Vec<(Vec, Vec)>, Vec>)>, complete: bool, - client: Arc>, + client: Arc, imported_bytes: u64, skip_proof: bool, } +/// Reported state download progress. +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct StateDownloadProgress { + /// Estimated download percentage. + pub percentage: u32, + /// Total state size in bytes downloaded so far. + pub size: u64, +} + /// Import state chunk result. pub enum ImportResult { /// State is complete and ready for import. @@ -55,9 +61,13 @@ pub enum ImportResult { BadResponse, } -impl StateSync { +impl StateSync +where + B: BlockT, + Client: ProofProvider + Send + Sync + 'static, +{ /// Create a new instance. - pub fn new(client: Arc>, target: B::Header, skip_proof: bool) -> Self { + pub fn new(client: Arc, target: B::Header, skip_proof: bool) -> Self { Self { client, target_block: target.hash(), @@ -71,7 +81,7 @@ impl StateSync { } } - /// Validate and import a state reponse. + /// Validate and import a state response. pub fn import(&mut self, response: StateResponse) -> ImportResult { if response.entries.is_empty() && response.proof.is_empty() { debug!(target: "sync", "Bad state response"); diff --git a/client/network/src/protocol/sync/warp.rs b/client/network/src/protocol/sync/warp.rs index f12deb2dbb432..fa2c23a0b33c1 100644 --- a/client/network/src/protocol/sync/warp.rs +++ b/client/network/src/protocol/sync/warp.rs @@ -17,23 +17,44 @@ // along with this program. If not, see . ///! Warp sync support. -pub use super::state::ImportResult; -use super::state::StateSync; +use super::state::{ImportResult, StateSync}; +use crate::schema::v1::{StateRequest, StateResponse}; pub use crate::warp_request_handler::{ EncodedProof, Request as WarpProofRequest, VerificationResult, WarpSyncProvider, }; -use crate::{ - chain::Client, - schema::v1::{StateRequest, StateResponse}, - WarpSyncPhase, WarpSyncProgress, -}; +use sc_client_api::ProofProvider; +use sp_blockchain::HeaderBackend; use sp_finality_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; use std::sync::Arc; -enum Phase { +enum Phase { WarpProof { set_id: SetId, authorities: AuthorityList, last_hash: B::Hash }, - State(StateSync), + State(StateSync), +} + +/// Reported warp sync phase. +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum WarpSyncPhase { + /// Waiting for peers to connect. + AwaitingPeers, + /// Downloading and verifying grandpa warp proofs. + DownloadingWarpProofs, + /// Downloading state data. + DownloadingState, + /// Importing state. + ImportingState, + /// Downloading block history. + DownloadingBlocks(NumberFor), +} + +/// Reported warp sync progress. +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct WarpSyncProgress { + /// Estimated download percentage. + pub phase: WarpSyncPhase, + /// Total bytes downloaded so far. + pub total_bytes: u64, } /// Import warp proof result. @@ -45,19 +66,20 @@ pub enum WarpProofImportResult { } /// Warp sync state machine. Accumulates warp proofs and state. -pub struct WarpSync { - phase: Phase, - client: Arc>, +pub struct WarpSync { + phase: Phase, + client: Arc, warp_sync_provider: Arc>, total_proof_bytes: u64, } -impl WarpSync { +impl WarpSync +where + B: BlockT, + Client: HeaderBackend + ProofProvider + 'static, +{ /// Create a new instance. - pub fn new( - client: Arc>, - warp_sync_provider: Arc>, - ) -> Self { + pub fn new(client: Arc, warp_sync_provider: Arc>) -> Self { let last_hash = client.hash(Zero::zero()).unwrap().expect("Genesis header always exists"); let phase = Phase::WarpProof { set_id: 0, diff --git a/client/network/src/service.rs b/client/network/src/service.rs index e88e7924954b3..6ffc0ec49bd67 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -54,16 +54,18 @@ use libp2p::{ ping::Failure as PingFailure, swarm::{ AddressScore, ConnectionError, ConnectionLimits, DialError, NetworkBehaviour, - PendingConnectionError, SwarmBuilder, SwarmEvent, + PendingConnectionError, Swarm, SwarmBuilder, SwarmEvent, }, Multiaddr, PeerId, }; use log::{debug, error, info, trace, warn}; use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; +use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; +use sp_blockchain::{HeaderBackend, HeaderMetadata}; use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::{ borrow::Cow, @@ -98,7 +100,7 @@ pub use libp2p::{ }, kad::record::Key as KademliaKey, }; -pub use signature::*; +pub use signature::Signature; /// Substrate network service. Handles network IO and manages connectivity. pub struct NetworkService { @@ -130,13 +132,24 @@ pub struct NetworkService { _marker: PhantomData, } -impl NetworkWorker { +impl NetworkWorker +where + B: BlockT + 'static, + H: ExHashT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ /// Creates the network service. /// /// Returns a `NetworkWorker` that implements `Future` and must be regularly polled in order /// for the network processing to advance. From it, you can extract a `NetworkService` using /// `worker.service()`. The `NetworkService` can be shared through the codebase. - pub fn new(mut params: Params) -> Result { + pub fn new(mut params: Params) -> Result { // Ensure the listen addresses are consistent with the transport. ensure_addresses_consistent_with_transport( params.network_config.listen_addresses.iter(), @@ -247,7 +260,7 @@ impl NetworkWorker { // Build the swarm. let client = params.chain.clone(); - let (mut swarm, bandwidth): (Swarm, _) = { + let (mut swarm, bandwidth): (Swarm>, _) = { let user_agent = format!( "{} ({})", params.network_config.client_version, params.network_config.node_name @@ -392,14 +405,18 @@ impl NetworkWorker { // Listen on multiaddresses. for addr in ¶ms.network_config.listen_addresses { - if let Err(err) = Swarm::::listen_on(&mut swarm, addr.clone()) { + if let Err(err) = Swarm::>::listen_on(&mut swarm, addr.clone()) { warn!(target: "sub-libp2p", "Can't listen on {} because: {:?}", addr, err) } } // Add external addresses. for addr in ¶ms.network_config.public_addresses { - Swarm::::add_external_address(&mut swarm, addr.clone(), AddressScore::Infinite); + Swarm::>::add_external_address( + &mut swarm, + addr.clone(), + AddressScore::Infinite, + ); } let external_addresses = Arc::new(Mutex::new(Vec::new())); @@ -540,14 +557,14 @@ impl NetworkWorker { /// Returns the local `PeerId`. pub fn local_peer_id(&self) -> &PeerId { - Swarm::::local_peer_id(&self.network_service) + Swarm::>::local_peer_id(&self.network_service) } /// Returns the list of addresses we are listening on. /// /// Does **NOT** include a trailing `/p2p/` with our `PeerId`. pub fn listen_addresses(&self) -> impl Iterator { - Swarm::::listeners(&self.network_service) + Swarm::>::listeners(&self.network_service) } /// Get network state. @@ -627,7 +644,7 @@ impl NetworkWorker { .collect() }; - let peer_id = Swarm::::local_peer_id(&swarm).to_base58(); + let peer_id = Swarm::>::local_peer_id(&swarm).to_base58(); let listened_addresses = swarm.listeners().cloned().collect(); let external_addresses = swarm.external_addresses().map(|r| &r.addr).cloned().collect(); @@ -1445,7 +1462,18 @@ enum ServiceToWorkerMsg { /// /// You are encouraged to poll this in a separate background thread or task. #[must_use = "The NetworkWorker must be polled in order for the network to advance"] -pub struct NetworkWorker { +pub struct NetworkWorker +where + B: BlockT + 'static, + H: ExHashT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. external_addresses: Arc>>, /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. @@ -1455,7 +1483,7 @@ pub struct NetworkWorker { /// The network service that can be extracted and shared through the codebase. service: Arc>, /// The *actual* network. - network_service: Swarm, + network_service: Swarm>, /// The import queue that was passed at initialization. import_queue: Box>, /// Messages from the [`NetworkService`] that must be processed. @@ -1473,7 +1501,18 @@ pub struct NetworkWorker { tx_handler_controller: transactions::TransactionsHandlerController, } -impl Future for NetworkWorker { +impl Future for NetworkWorker +where + B: BlockT + 'static, + H: ExHashT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context) -> Poll { @@ -2055,10 +2094,11 @@ impl Future for NetworkWorker { // Update the variables shared with the `NetworkService`. this.num_connected.store(num_connected_peers, Ordering::Relaxed); { - let external_addresses = Swarm::::external_addresses(&this.network_service) - .map(|r| &r.addr) - .cloned() - .collect(); + let external_addresses = + Swarm::>::external_addresses(&this.network_service) + .map(|r| &r.addr) + .cloned() + .collect(); *this.external_addresses.lock() = external_addresses; } @@ -2113,17 +2153,46 @@ impl Future for NetworkWorker { } } -impl Unpin for NetworkWorker {} - -/// The libp2p swarm, customized for our needs. -type Swarm = libp2p::swarm::Swarm>; +impl Unpin for NetworkWorker +where + B: BlockT + 'static, + H: ExHashT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ +} // Implementation of `import_queue::Link` trait using the available local variables. -struct NetworkLink<'a, B: BlockT> { - protocol: &'a mut Swarm, +struct NetworkLink<'a, B, Client> +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ + protocol: &'a mut Swarm>, } -impl<'a, B: BlockT> Link for NetworkLink<'a, B> { +impl<'a, B, Client> Link for NetworkLink<'a, B, Client> +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ fn blocks_processed( &mut self, imported: usize, diff --git a/client/network/src/state_request_handler.rs b/client/network/src/state_request_handler.rs index 10a77061a031d..3e208e22e3d93 100644 --- a/client/network/src/state_request_handler.rs +++ b/client/network/src/state_request_handler.rs @@ -18,7 +18,6 @@ //! `crate::request_responses::RequestResponsesBehaviour`. use crate::{ - chain::Client, config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, schema::v1::{KeyValueStateEntry, StateEntry, StateRequest, StateResponse}, @@ -32,6 +31,7 @@ use futures::{ use log::{debug, trace}; use lru::LruCache; use prost::Message; +use sc_client_api::ProofProvider; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use std::{ hash::{Hash, Hasher}, @@ -96,8 +96,8 @@ enum SeenRequestsValue { } /// Handler for incoming block requests from a remote peer. -pub struct StateRequestHandler { - client: Arc>, +pub struct StateRequestHandler { + client: Arc, request_receiver: mpsc::Receiver, /// Maps from request to number of times we have seen this request. /// @@ -105,11 +105,15 @@ pub struct StateRequestHandler { seen_requests: LruCache, SeenRequestsValue>, } -impl StateRequestHandler { +impl StateRequestHandler +where + B: BlockT, + Client: ProofProvider + Send + Sync + 'static, +{ /// Create a new [`StateRequestHandler`]. pub fn new( protocol_id: &ProtocolId, - client: Arc>, + client: Arc, num_peer_hint: usize, ) -> (Self, ProtocolConfig) { // Reserve enough request slots for one request per peer when we are at the maximum diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 552879f35d934..1760c08759761 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -223,7 +223,7 @@ pub struct Peer { block_import: BlockImportAdapter, select_chain: Option>, backend: Option>, - network: NetworkWorker::Hash>, + network: NetworkWorker::Hash, PeersFullClient>, imported_blocks_stream: Pin> + Send>>, finality_notification_stream: Pin> + Send>>, listen_addr: Multiaddr, @@ -498,7 +498,7 @@ where } /// Get a reference to the network worker. - pub fn network(&self) -> &NetworkWorker::Hash> { + pub fn network(&self) -> &NetworkWorker::Hash, PeersFullClient> { &self.network } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 6d9d99994288c..a48e6168c52cc 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -39,8 +39,10 @@ use std::{collections::HashMap, io, net::SocketAddr, pin::Pin}; use codec::{Decode, Encode}; use futures::{Future, FutureExt, StreamExt}; use log::{debug, error, warn}; +use sc_client_api::{BlockBackend, ProofProvider}; use sc_network::PeerId; use sc_utils::mpsc::TracingUnboundedReceiver; +use sp_blockchain::HeaderMetadata; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header as HeaderT}, @@ -135,11 +137,18 @@ pub struct PartialComponents + HeaderBackend, + C: BlockchainEvents + + HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, H: sc_network::ExHashT, >( role: Role, - mut network: sc_network::NetworkWorker, + mut network: sc_network::NetworkWorker, client: Arc, mut rpc_rx: TracingUnboundedReceiver>, should_have_peers: bool, @@ -461,7 +470,13 @@ where impl sc_network::config::TransactionPool for TransactionPoolAdapter where - C: sc_network::config::Client + Send + Sync, + C: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, Pool: 'static + TransactionPool, B: BlockT, H: std::hash::Hash + Eq + sp_runtime::traits::Member + sp_runtime::traits::MaybeSerialize, From c5a7fdd88e802987e9e2a786c9c2f81a2a824e07 Mon Sep 17 00:00:00 2001 From: yjh Date: Sat, 30 Apr 2022 14:11:15 +0800 Subject: [PATCH 0747/1472] import Vec when run on no_std for wasmi (#11319) * import Vec when run on no_std for wasmi * cargo fmt --- primitives/wasm-interface/src/wasmi_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/wasm-interface/src/wasmi_impl.rs b/primitives/wasm-interface/src/wasmi_impl.rs index 39afce4df4eb2..2239eb5f38658 100644 --- a/primitives/wasm-interface/src/wasmi_impl.rs +++ b/primitives/wasm-interface/src/wasmi_impl.rs @@ -16,8 +16,8 @@ // limitations under the License. //! Implementation of conversions between Substrate and wasmi types. - use crate::{Signature, Value, ValueType}; +use sp_std::vec::Vec; impl From for wasmi::RuntimeValue { fn from(value: Value) -> Self { From 0ba251c9388452c879bfcca425ada66f1f9bc802 Mon Sep 17 00:00:00 2001 From: Falco Hirschenberger Date: Sat, 30 Apr 2022 23:28:27 +0200 Subject: [PATCH 0748/1472] Apply some clippy lints (#11154) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Apply some clippy hints * Revert clippy ci changes * Update client/cli/src/commands/generate.rs Co-authored-by: Bastian Köcher * Update client/cli/src/commands/inspect_key.rs Co-authored-by: Bastian Köcher * Update client/db/src/bench.rs Co-authored-by: Bastian Köcher * Update client/db/src/bench.rs Co-authored-by: Bastian Köcher * Update client/service/src/client/block_rules.rs Co-authored-by: Bastian Köcher * Update client/service/src/client/block_rules.rs Co-authored-by: Bastian Köcher * Update client/network/src/transactions.rs Co-authored-by: Bastian Köcher * Update client/network/src/protocol.rs Co-authored-by: Bastian Köcher * Revert due to missing `or_default` function. * Fix compilation and simplify code * Undo change that corrupts benchmark. * fix clippy * Update client/service/test/src/lib.rs Co-authored-by: Bastian Köcher * Update client/state-db/src/noncanonical.rs Co-authored-by: Bastian Köcher * Update client/state-db/src/noncanonical.rs remove leftovers! * Update client/tracing/src/logging/directives.rs Co-authored-by: Bastian Köcher * Update utils/fork-tree/src/lib.rs Co-authored-by: Bastian Köcher * added needed ref * Update frame/referenda/src/benchmarking.rs * Simplify byte-vec creation * let's just not overlap the ranges * Correction * cargo fmt * Update utils/frame/benchmarking-cli/src/shared/stats.rs Co-authored-by: Bastian Köcher * Update utils/frame/benchmarking-cli/src/pallet/command.rs Co-authored-by: Bastian Köcher * Update utils/frame/benchmarking-cli/src/pallet/command.rs Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher Co-authored-by: Giles Cope --- bin/node-template/node/src/rpc.rs | 2 +- bin/node-template/node/src/service.rs | 4 +- bin/node-template/pallets/template/src/lib.rs | 2 +- bin/node-template/runtime/src/lib.rs | 2 +- bin/node/bench/src/core.rs | 2 +- bin/node/bench/src/main.rs | 29 +- bin/node/bench/src/state_sizes.rs | 2 +- bin/node/bench/src/trie.rs | 2 +- bin/node/cli/src/service.rs | 6 +- bin/node/runtime/src/lib.rs | 6 +- bin/node/testing/src/bench.rs | 19 +- bin/utils/chain-spec-builder/src/main.rs | 2 +- client/allocator/src/freeing_bump.rs | 2 +- client/api/src/backend.rs | 2 +- client/api/src/execution_extensions.rs | 2 +- client/api/src/in_mem.rs | 34 +-- client/api/src/lib.rs | 6 +- client/api/src/notifications.rs | 7 +- client/api/src/notifications/registry.rs | 14 +- client/authority-discovery/src/worker.rs | 6 +- .../src/worker/addr_cache.rs | 5 +- .../basic-authorship/src/basic_authorship.rs | 2 +- client/beefy/rpc/src/lib.rs | 2 +- client/beefy/src/lib.rs | 4 +- client/block-builder/src/lib.rs | 2 +- client/cli/src/commands/generate.rs | 9 +- client/cli/src/commands/inspect_key.rs | 10 +- client/cli/src/commands/purge_chain_cmd.rs | 2 +- client/cli/src/commands/utils.rs | 4 +- client/cli/src/commands/vanity.rs | 20 +- client/cli/src/config.rs | 4 +- client/cli/src/lib.rs | 4 +- client/cli/src/params/keystore_params.rs | 2 +- client/cli/src/params/node_key_params.rs | 2 +- client/cli/src/params/shared_params.rs | 2 +- client/consensus/aura/src/import_queue.rs | 8 +- client/consensus/aura/src/lib.rs | 8 +- client/consensus/babe/rpc/src/lib.rs | 4 +- client/consensus/babe/src/authorship.rs | 6 +- client/consensus/babe/src/lib.rs | 18 +- client/consensus/babe/src/verification.rs | 12 +- client/consensus/common/src/block_import.rs | 3 +- client/consensus/common/src/import_queue.rs | 12 +- .../common/src/import_queue/basic_queue.rs | 4 +- .../common/src/import_queue/buffered_link.rs | 4 +- client/consensus/common/src/longest_chain.rs | 8 +- client/consensus/epochs/src/lib.rs | 8 +- .../manual-seal/src/consensus/babe.rs | 18 +- client/consensus/pow/src/lib.rs | 34 +-- client/consensus/pow/src/worker.rs | 2 +- client/consensus/slots/src/aux_schema.rs | 2 +- client/consensus/slots/src/lib.rs | 2 +- client/db/src/bench.rs | 43 ++- client/db/src/lib.rs | 102 +++---- client/db/src/offchain.rs | 4 +- client/db/src/storage_cache.rs | 14 +- client/db/src/upgrade.rs | 2 +- client/db/src/utils.rs | 30 +- .../runtime_blob/data_segments_snapshot.rs | 2 +- .../common/src/runtime_blob/runtime_blob.rs | 4 +- client/executor/common/src/sandbox.rs | 14 +- .../common/src/sandbox/wasmer_backend.rs | 6 +- .../common/src/sandbox/wasmi_backend.rs | 4 +- client/executor/src/native_executor.rs | 5 +- client/executor/src/wasm_runtime.rs | 4 +- client/executor/wasmi/src/lib.rs | 26 +- client/executor/wasmtime/src/host.rs | 19 +- client/finality-grandpa/rpc/src/report.rs | 4 +- client/finality-grandpa/src/authorities.rs | 3 +- client/finality-grandpa/src/aux_schema.rs | 2 +- .../src/communication/gossip.rs | 37 +-- .../finality-grandpa/src/communication/mod.rs | 6 +- client/finality-grandpa/src/environment.rs | 10 +- client/finality-grandpa/src/import.rs | 7 +- client/finality-grandpa/src/observer.rs | 6 +- client/finality-grandpa/src/voting_rule.rs | 2 +- client/finality-grandpa/src/warp_proof.rs | 2 +- client/informant/src/lib.rs | 6 +- client/keystore/src/local.rs | 10 +- client/network-gossip/src/state_machine.rs | 45 ++- client/network/src/behaviour.rs | 3 +- client/network/src/bitswap.rs | 6 +- client/network/src/block_request_handler.rs | 2 +- client/network/src/discovery.rs | 16 +- client/network/src/light_client_requests.rs | 6 +- client/network/src/protocol.rs | 23 +- client/network/src/protocol/message.rs | 2 +- .../src/protocol/notifications/behaviour.rs | 37 +-- .../src/protocol/notifications/handler.rs | 4 +- client/network/src/protocol/sync.rs | 123 ++++---- .../src/protocol/sync/extra_requests.rs | 2 +- client/network/src/protocol/sync/state.rs | 26 +- client/network/src/protocol/sync/warp.rs | 6 +- client/network/src/request_responses.rs | 47 ++- client/network/src/service.rs | 48 ++- client/network/src/service/metrics.rs | 4 +- client/network/src/service/out_events.rs | 18 +- client/network/src/state_request_handler.rs | 9 +- client/network/src/transactions.rs | 10 +- client/network/src/transport.rs | 6 +- client/network/src/warp_request_handler.rs | 6 +- client/network/test/src/lib.rs | 20 +- client/offchain/src/api/http.rs | 2 +- client/peerset/src/lib.rs | 13 +- client/peerset/src/peersstate.rs | 33 +- client/peerset/tests/fuzz.rs | 18 +- client/rpc-api/src/author/error.rs | 4 +- client/rpc-servers/src/middleware.rs | 5 +- client/rpc/src/author/mod.rs | 6 +- client/rpc/src/chain/mod.rs | 4 +- client/rpc/src/state/state_full.rs | 6 +- client/service/src/builder.rs | 12 +- client/service/src/client/block_rules.rs | 6 +- client/service/src/client/call_executor.rs | 4 +- client/service/src/client/client.rs | 38 ++- client/service/src/client/wasm_override.rs | 48 ++- client/service/src/client/wasm_substitutes.rs | 4 +- client/service/src/lib.rs | 12 +- client/service/src/metrics.rs | 4 +- client/service/src/task_manager/mod.rs | 4 +- client/service/test/src/lib.rs | 18 +- client/state-db/src/lib.rs | 10 +- client/state-db/src/noncanonical.rs | 27 +- client/state-db/src/pruning.rs | 6 +- client/sync-state-rpc/src/lib.rs | 2 +- client/telemetry/src/lib.rs | 8 +- client/telemetry/src/node.rs | 2 +- client/tracing/src/block/mod.rs | 20 +- client/tracing/src/lib.rs | 5 +- client/tracing/src/logging/directives.rs | 2 +- client/tracing/src/logging/mod.rs | 46 ++- client/transaction-pool/api/src/lib.rs | 2 +- client/transaction-pool/src/api.rs | 12 +- client/transaction-pool/src/graph/pool.rs | 2 +- client/transaction-pool/src/graph/ready.rs | 6 +- .../src/graph/validated_pool.rs | 18 +- client/transaction-pool/src/lib.rs | 17 +- client/transaction-pool/src/revalidation.rs | 8 +- client/utils/src/pubsub.rs | 8 +- frame/assets/src/benchmarking.rs | 8 +- frame/assets/src/functions.rs | 31 +- frame/assets/src/impl_stored_map.rs | 2 +- frame/assets/src/lib.rs | 16 +- frame/assets/src/types.rs | 4 +- frame/atomic-swap/src/lib.rs | 6 +- frame/aura/src/lib.rs | 2 +- frame/authorship/src/lib.rs | 10 +- frame/babe/src/lib.rs | 6 +- frame/bags-list/fuzzer/src/main.rs | 2 +- frame/bags-list/remote-tests/src/lib.rs | 2 +- frame/bags-list/src/benchmarks.rs | 2 +- frame/bags-list/src/lib.rs | 4 +- frame/bags-list/src/list/mod.rs | 18 +- frame/bags-list/src/mock.rs | 2 +- frame/balances/src/lib.rs | 52 ++-- frame/benchmarking/src/analysis.rs | 6 +- frame/bounties/src/benchmarking.rs | 2 +- frame/bounties/src/lib.rs | 4 +- frame/child-bounties/src/benchmarking.rs | 8 +- frame/child-bounties/src/lib.rs | 6 +- frame/collective/src/benchmarking.rs | 32 +- frame/contracts/src/benchmarking/code.rs | 19 +- frame/contracts/src/benchmarking/mod.rs | 26 +- frame/contracts/src/exec.rs | 29 +- frame/contracts/src/gas.rs | 2 +- frame/contracts/src/schedule.rs | 2 +- frame/contracts/src/storage.rs | 8 +- frame/contracts/src/storage/meter.rs | 4 +- frame/contracts/src/wasm/code_cache.rs | 5 +- frame/contracts/src/wasm/prepare.rs | 34 +-- frame/contracts/src/wasm/runtime.rs | 38 +-- frame/conviction-voting/src/benchmarking.rs | 20 +- frame/conviction-voting/src/lib.rs | 3 +- frame/democracy/src/benchmarking.rs | 34 +-- frame/democracy/src/lib.rs | 27 +- .../src/benchmarking.rs | 2 +- .../election-provider-multi-phase/src/lib.rs | 47 ++- .../src/unsigned.rs | 19 +- .../solution-type/src/lib.rs | 4 +- .../solution-type/src/single_page.rs | 2 +- frame/election-provider-support/src/lib.rs | 2 +- frame/elections-phragmen/src/benchmarking.rs | 3 +- frame/elections-phragmen/src/lib.rs | 288 +++++++++--------- frame/elections-phragmen/src/migrations/v5.rs | 6 +- frame/examples/basic/src/benchmarking.rs | 2 +- frame/examples/basic/src/lib.rs | 4 +- frame/examples/offchain-worker/src/lib.rs | 4 +- frame/executive/src/lib.rs | 10 +- frame/gilt/src/lib.rs | 2 +- frame/grandpa/src/lib.rs | 23 +- frame/identity/src/benchmarking.rs | 24 +- frame/identity/src/lib.rs | 36 +-- frame/identity/src/types.rs | 10 +- frame/im-online/src/lib.rs | 6 +- frame/indices/src/lib.rs | 6 +- frame/lottery/src/lib.rs | 8 +- frame/membership/src/lib.rs | 2 +- frame/multisig/src/benchmarking.rs | 26 +- frame/multisig/src/lib.rs | 3 +- frame/nicks/src/lib.rs | 6 +- frame/offences/benchmarking/src/lib.rs | 32 +- frame/offences/src/lib.rs | 5 +- frame/offences/src/migration.rs | 4 +- frame/preimage/src/benchmarking.rs | 24 +- frame/preimage/src/lib.rs | 18 +- frame/proxy/src/benchmarking.rs | 24 +- frame/proxy/src/lib.rs | 40 +-- frame/recovery/src/lib.rs | 4 +- frame/referenda/src/benchmarking.rs | 11 +- frame/referenda/src/lib.rs | 14 +- frame/referenda/src/types.rs | 6 +- frame/scheduler/src/lib.rs | 6 +- frame/scored-pool/src/lib.rs | 4 +- frame/session/src/historical/shared.rs | 11 +- frame/session/src/lib.rs | 11 +- frame/society/src/lib.rs | 36 ++- frame/staking/reward-fn/src/lib.rs | 28 +- frame/staking/src/benchmarking.rs | 36 +-- frame/staking/src/lib.rs | 4 +- frame/staking/src/pallet/impls.rs | 14 +- frame/staking/src/pallet/mod.rs | 16 +- frame/staking/src/slashing.rs | 4 +- frame/staking/src/testing_utils.rs | 4 +- frame/state-trie-migration/src/lib.rs | 24 +- .../src/construct_runtime/expand/config.rs | 8 +- .../procedural/src/construct_runtime/mod.rs | 10 +- .../procedural/src/pallet/expand/call.rs | 2 +- .../src/pallet/expand/genesis_config.rs | 2 +- .../procedural/src/pallet/expand/storage.rs | 10 +- .../procedural/src/pallet/parse/call.rs | 7 +- .../procedural/src/pallet/parse/config.rs | 7 +- .../procedural/src/pallet/parse/error.rs | 4 +- .../src/pallet/parse/extra_constants.rs | 7 +- .../src/pallet/parse/genesis_build.rs | 3 +- .../src/pallet/parse/genesis_config.rs | 2 +- .../procedural/src/pallet/parse/hooks.rs | 7 +- .../procedural/src/pallet/parse/inherent.rs | 7 +- .../procedural/src/pallet/parse/origin.rs | 2 +- .../src/pallet/parse/pallet_struct.rs | 4 +- .../procedural/src/pallet/parse/storage.rs | 14 +- .../src/pallet/parse/validate_unsigned.rs | 7 +- .../src/storage/genesis_config/builder_def.rs | 4 +- .../procedural/src/storage/instance_trait.rs | 2 +- frame/support/procedural/src/storage/mod.rs | 2 +- frame/support/src/hash.rs | 4 +- frame/support/src/lib.rs | 2 +- frame/support/src/storage/child.rs | 4 +- .../src/storage/generator/double_map.rs | 2 +- frame/support/src/storage/hashed.rs | 26 +- frame/support/src/storage/mod.rs | 2 +- .../support/src/storage/types/counted_map.rs | 5 +- frame/support/src/storage/types/nmap.rs | 2 +- frame/support/src/storage/unhashed.rs | 4 +- frame/support/src/traits/dispatch.rs | 2 +- frame/support/src/traits/members.rs | 2 +- frame/support/src/traits/metadata.rs | 2 +- frame/support/src/traits/misc.rs | 4 +- frame/support/src/traits/stored_map.rs | 2 +- frame/support/src/traits/tokens/currency.rs | 2 +- frame/support/src/traits/tokens/fungible.rs | 2 +- .../src/traits/tokens/fungible/balanced.rs | 4 +- frame/support/src/traits/tokens/fungibles.rs | 2 +- .../src/traits/tokens/fungibles/balanced.rs | 4 +- frame/support/src/weights.rs | 10 +- .../src/extensions/check_non_zero_sender.rs | 2 +- frame/system/src/extensions/check_weight.rs | 6 +- frame/system/src/lib.rs | 15 +- frame/system/src/limits.rs | 4 +- frame/system/src/migrations/mod.rs | 6 +- frame/system/src/offchain.rs | 4 +- frame/timestamp/src/lib.rs | 4 +- frame/tips/src/benchmarking.rs | 4 +- frame/tips/src/lib.rs | 4 +- .../asset-tx-payment/src/payment.rs | 11 +- frame/transaction-payment/src/lib.rs | 6 +- frame/transaction-payment/src/payment.rs | 2 +- frame/transaction-storage/src/lib.rs | 9 +- frame/uniques/src/benchmarking.rs | 12 +- frame/uniques/src/functions.rs | 6 +- frame/uniques/src/impl_nonfungibles.rs | 12 +- frame/uniques/src/lib.rs | 12 +- frame/utility/src/benchmarking.rs | 2 +- frame/vesting/src/benchmarking.rs | 14 +- frame/vesting/src/lib.rs | 10 +- frame/whitelist/src/benchmarking.rs | 2 +- .../api/proc-macro/src/decl_runtime_apis.rs | 16 +- .../api/proc-macro/src/impl_runtime_apis.rs | 8 +- .../proc-macro/src/mock_impl_runtime_apis.rs | 4 +- primitives/api/proc-macro/src/utils.rs | 14 +- primitives/api/src/lib.rs | 7 +- primitives/application-crypto/src/ecdsa.rs | 2 +- primitives/application-crypto/src/ed25519.rs | 2 +- primitives/application-crypto/src/sr25519.rs | 2 +- primitives/arithmetic/benches/bench.rs | 6 +- primitives/arithmetic/fuzzer/src/normalize.rs | 18 +- primitives/arithmetic/src/lib.rs | 9 +- primitives/arithmetic/src/rational.rs | 9 +- primitives/blockchain/src/backend.rs | 4 +- primitives/blockchain/src/header_metadata.rs | 10 +- primitives/consensus/common/src/evaluation.rs | 2 +- primitives/consensus/common/src/lib.rs | 2 +- primitives/core/benches/bench.rs | 12 +- .../core/hashing/proc-macro/src/impls.rs | 2 +- primitives/core/src/crypto.rs | 2 +- primitives/core/src/ecdsa.rs | 6 +- primitives/core/src/ed25519.rs | 2 +- primitives/core/src/hexdisplay.rs | 4 +- primitives/debug-derive/src/impls.rs | 7 +- primitives/externalities/src/extensions.rs | 4 +- primitives/finality-grandpa/src/lib.rs | 2 +- primitives/io/src/lib.rs | 23 +- primitives/keyring/src/ed25519.rs | 2 +- primitives/keyring/src/sr25519.rs | 2 +- primitives/keystore/src/testing.rs | 2 +- primitives/merkle-mountain-range/src/lib.rs | 2 +- .../npos-elections/fuzzer/src/common.rs | 2 +- .../fuzzer/src/phragmen_balancing.rs | 16 +- .../fuzzer/src/phragmms_balancing.rs | 11 +- .../npos-elections/fuzzer/src/reduce.rs | 2 +- primitives/npos-elections/src/helpers.rs | 12 +- primitives/npos-elections/src/lib.rs | 4 +- primitives/npos-elections/src/phragmen.rs | 5 +- primitives/npos-elections/src/phragmms.rs | 13 +- primitives/npos-elections/src/pjr.rs | 4 +- primitives/npos-elections/src/reduce.rs | 18 +- primitives/panic-handler/src/lib.rs | 10 +- .../proc-macro/src/pass_by/enum_.rs | 2 +- .../runtime-interface/proc-macro/src/utils.rs | 38 ++- primitives/runtime/src/generic/digest.rs | 8 +- primitives/runtime/src/offchain/http.rs | 2 +- .../runtime/src/offchain/storage_lock.rs | 2 +- primitives/runtime/src/runtime_string.rs | 4 +- primitives/runtime/src/traits.rs | 4 +- primitives/sandbox/src/embedded_executor.rs | 2 +- primitives/state-machine/src/backend.rs | 4 +- primitives/state-machine/src/basic.rs | 2 +- primitives/state-machine/src/ext.rs | 16 +- .../state-machine/src/in_memory_backend.rs | 2 +- primitives/state-machine/src/lib.rs | 109 +++---- .../src/overlayed_changes/mod.rs | 4 +- .../src/overlayed_changes/offchain.rs | 2 +- .../state-machine/src/proving_backend.rs | 24 +- .../state-machine/src/trie_backend_essence.rs | 20 +- primitives/storage/src/lib.rs | 12 +- primitives/tracing/src/types.rs | 4 +- .../transaction-storage-proof/src/lib.rs | 6 +- primitives/trie/src/lib.rs | 8 +- primitives/trie/src/trie_codec.rs | 2 +- primitives/trie/src/trie_stream.rs | 2 +- .../proc-macro/src/decl_runtime_version.rs | 2 +- primitives/wasm-interface/src/wasmi_impl.rs | 2 +- test-utils/client/src/lib.rs | 2 +- test-utils/runtime/src/genesismap.rs | 5 +- test-utils/runtime/src/system.rs | 2 +- utils/fork-tree/src/lib.rs | 84 ++--- .../benchmarking-cli/src/overhead/template.rs | 6 +- .../benchmarking-cli/src/pallet/command.rs | 18 +- .../benchmarking-cli/src/pallet/writer.rs | 10 +- .../benchmarking-cli/src/shared/stats.rs | 10 +- .../benchmarking-cli/src/storage/template.rs | 2 +- .../frame-utilities-cli/src/pallet_id.rs | 4 +- utils/frame/remote-externalities/src/lib.rs | 19 +- .../rpc/state-trie-migration-rpc/src/lib.rs | 2 +- .../cli/src/commands/execute_block.rs | 6 +- .../cli/src/commands/follow_chain.rs | 10 +- .../cli/src/commands/offchain_worker.rs | 6 +- utils/frame/try-runtime/cli/src/lib.rs | 8 +- utils/wasm-builder/src/wasm_project.rs | 15 +- 368 files changed, 1938 insertions(+), 2247 deletions(-) diff --git a/bin/node-template/node/src/rpc.rs b/bin/node-template/node/src/rpc.rs index d23b23178ec2a..7f3701b5ab74f 100644 --- a/bin/node-template/node/src/rpc.rs +++ b/bin/node-template/node/src/rpc.rs @@ -43,7 +43,7 @@ where io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))); - io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))); + io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client))); // Extend this RPC with a custom API by using the following syntax. // `YourRpcStruct` should have a reference to a client, which is needed diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index e2a8cb4ed834b..5f46a16a9668f 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -82,7 +82,7 @@ pub fn new_partial( let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( - &config, + config, telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), executor, )?; @@ -263,7 +263,7 @@ pub fn new_full(mut config: Configuration) -> Result let aura = sc_consensus_aura::start_aura::( StartAuraParams { slot_duration, - client: client.clone(), + client, select_chain, block_import, proposer_factory, diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index f5ce8c5a0f7fd..067c7ce2575a0 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -88,7 +88,7 @@ pub mod pallet { // Read a value from storage. match >::get() { // Return an error if the value has not been set. - None => Err(Error::::NoneValue)?, + None => return Err(Error::::NoneValue.into()), Some(old) => { // Increment the value read from storage; will error in the event of overflow. let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index a7a162bf74327..0145cacef8f7d 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -478,7 +478,7 @@ impl_runtime_apis! { let storage_info = AllPalletsWithSystem::storage_info(); - return (list, storage_info) + (list, storage_info) } fn dispatch_benchmark( diff --git a/bin/node/bench/src/core.rs b/bin/node/bench/src/core.rs index b6ad3ecd80068..3b3060a888349 100644 --- a/bin/node/bench/src/core.rs +++ b/bin/node/bench/src/core.rs @@ -132,7 +132,7 @@ pub fn run_benchmark(benchmark: Box, mode: Mode) -> Be durations.push(duration.as_nanos()); } - durations.sort(); + durations.sort_unstable(); let raw_average = (durations.iter().sum::() / (durations.len() as u128)) as u64; let average = (durations.iter().skip(10).take(30).sum::() / 30) as u64; diff --git a/bin/node/bench/src/main.rs b/bin/node/bench/src/main.rs index 0e50447d464fb..d97c7af26535b 100644 --- a/bin/node/bench/src/main.rs +++ b/bin/node/bench/src/main.rs @@ -85,7 +85,7 @@ fn main() { let mut import_benchmarks = Vec::new(); - for profile in [Profile::Wasm, Profile::Native].iter() { + for profile in [Profile::Wasm, Profile::Native] { for size in [ SizeType::Empty, SizeType::Small, @@ -93,25 +93,14 @@ fn main() { SizeType::Large, SizeType::Full, SizeType::Custom(opt.transactions.unwrap_or(0)), - ] - .iter() - { + ] { for block_type in [ BlockType::RandomTransfersKeepAlive, BlockType::RandomTransfersReaping, BlockType::Noop, - ] - .iter() - { - for database_type in - [BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb].iter() - { - import_benchmarks.push(( - profile, - size.clone(), - block_type.clone(), - database_type, - )); + ] { + for database_type in [BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb] { + import_benchmarks.push((profile, size, block_type, database_type)); } } } @@ -120,11 +109,11 @@ fn main() { let benchmarks = matrix!( (profile, size, block_type, database_type) in import_benchmarks.into_iter() => ImportBenchmarkDescription { - profile: *profile, + profile, key_types: KeyTypes::Sr25519, - size: size, - block_type: block_type, - database_type: *database_type, + size, + block_type, + database_type, }, (size, db_type) in [ diff --git a/bin/node/bench/src/state_sizes.rs b/bin/node/bench/src/state_sizes.rs index f97645423edcd..5387850666b6e 100644 --- a/bin/node/bench/src/state_sizes.rs +++ b/bin/node/bench/src/state_sizes.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . /// Kusama value size distribution -pub const KUSAMA_STATE_DISTRIBUTION: &'static [(u32, u32)] = &[ +pub const KUSAMA_STATE_DISTRIBUTION: &[(u32, u32)] = &[ (32, 35), (33, 20035), (34, 5369), diff --git a/bin/node/bench/src/trie.rs b/bin/node/bench/src/trie.rs index 1b4534cbd0f79..0539c9ce11462 100644 --- a/bin/node/bench/src/trie.rs +++ b/bin/node/bench/src/trie.rs @@ -282,7 +282,7 @@ impl core::Benchmark for TrieWriteBenchmark { let mut db = self.database.clone(); let kvdb = db.open(self.database_type); - let mut new_root = self.root.clone(); + let mut new_root = self.root; let mut overlay = HashMap::new(); let mut trie = SimpleTrie { db: kvdb.clone(), overlay: &mut overlay }; diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 2742e7b113d6d..01c7eb9abe1b7 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -113,10 +113,10 @@ pub fn create_extrinsic( let signature = raw_payload.using_encoded(|e| sender.sign(e)); node_runtime::UncheckedExtrinsic::new_signed( - function.clone(), + function, sp_runtime::AccountId32::from(sender.public()).into(), - node_runtime::Signature::Sr25519(signature.clone()), - extra.clone(), + node_runtime::Signature::Sr25519(signature), + extra, ) } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 18ce64c29f8e8..8c999bb76fc14 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -631,7 +631,7 @@ impl Get> for OffchainRandomBalancing { use sp_runtime::traits::TrailingZeroInput; let iters = match MINER_MAX_ITERATIONS { 0 => 0, - max @ _ => { + max => { let seed = sp_io::offchain::random_seed(); let random = ::decode(&mut TrailingZeroInput::new(&seed)) .expect("input is padded with zeroes; qed") % @@ -1148,7 +1148,7 @@ where let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; let address = Indices::unlookup(account); let (call, extra, _) = raw_payload.deconstruct(); - Some((call, (address, signature.into(), extra))) + Some((call, (address, signature, extra))) } } @@ -1911,7 +1911,7 @@ impl_runtime_apis! { let storage_info = AllPalletsWithSystem::storage_info(); - return (list, storage_info) + (list, storage_info) } fn dispatch_benchmark( diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 8227582d88a4b..7e13c0a0ac5e0 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -280,8 +280,7 @@ impl<'a> BlockContentIterator<'a> { let genesis_hash = client .block_hash(Zero::zero()) .expect("Database error?") - .expect("Genesis block always exists; qed") - .into(); + .expect("Genesis block always exists; qed"); BlockContentIterator { iteration: 0, content, keyring, runtime_version, genesis_hash } } @@ -569,15 +568,13 @@ impl BenchKeyring { genesis_hash, ); let key = self.accounts.get(&signed).expect("Account id not found in keyring"); - let signature = payload - .using_encoded(|b| { - if b.len() > 256 { - key.sign(&sp_io::hashing::blake2_256(b)) - } else { - key.sign(b) - } - }) - .into(); + let signature = payload.using_encoded(|b| { + if b.len() > 256 { + key.sign(&sp_io::hashing::blake2_256(b)) + } else { + key.sign(b) + } + }); UncheckedExtrinsic { signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), function: payload.0, diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index 3e8b1f4ea7523..e972e130fcf78 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -163,7 +163,7 @@ fn generate_chain_spec( } fn generate_authority_keys_and_store(seeds: &[String], keystore_path: &Path) -> Result<(), String> { - for (n, seed) in seeds.into_iter().enumerate() { + for (n, seed) in seeds.iter().enumerate() { let keystore: SyncCryptoStorePtr = Arc::new( LocalKeystore::open(keystore_path.join(format!("auth-{}", n)), None) .map_err(|err| err.to_string())?, diff --git a/client/allocator/src/freeing_bump.rs b/client/allocator/src/freeing_bump.rs index 7eeda45370b87..f14c31c79c483 100644 --- a/client/allocator/src/freeing_bump.rs +++ b/client/allocator/src/freeing_bump.rs @@ -90,7 +90,7 @@ fn error(msg: &'static str) -> Error { Error::Other(msg) } -const LOG_TARGET: &'static str = "wasm-heap"; +const LOG_TARGET: &str = "wasm-heap"; // The minimum possible allocation size is chosen to be 8 bytes because in that case we would have // easier time to provide the guaranteed alignment of 8. diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index e96616d5416e6..394fcd420fda1 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -499,7 +499,7 @@ pub trait Backend: AuxStore + Send + Sync { /// Returns true if state for given block is available. fn have_state_at(&self, hash: &Block::Hash, _number: NumberFor) -> bool { - self.state_at(BlockId::Hash(hash.clone())).is_ok() + self.state_at(BlockId::Hash(*hash)).is_ok() } /// Returns state backend with post-state of given block. diff --git a/client/api/src/execution_extensions.rs b/client/api/src/execution_extensions.rs index 92efafe91a174..574687312c82b 100644 --- a/client/api/src/execution_extensions.rs +++ b/client/api/src/execution_extensions.rs @@ -151,7 +151,7 @@ impl ExecutionExtensions { where T: OffchainSubmitTransaction + 'static, { - *self.transaction_pool.write() = Some(Arc::downgrade(&pool) as _); + *self.transaction_pool.write() = Some(Arc::downgrade(pool) as _); } /// Based on the execution context and capabilities it produces diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 51370f47e7d14..8b8473287a7ca 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -166,23 +166,19 @@ impl Blockchain { body: Option::Extrinsic>>, new_state: NewBlockState, ) -> sp_blockchain::Result<()> { - let number = header.number().clone(); + let number = *header.number(); if new_state.is_best() { self.apply_head(&header)?; } { let mut storage = self.storage.write(); - storage - .leaves - .import(hash.clone(), number.clone(), header.parent_hash().clone()); - storage - .blocks - .insert(hash.clone(), StoredBlock::new(header, body, justifications)); + storage.leaves.import(hash, number, header.parent_hash().clone()); + storage.blocks.insert(hash, StoredBlock::new(header, body, justifications)); if let NewBlockState::Final = new_state { storage.finalized_hash = hash; - storage.finalized_number = number.clone(); + storage.finalized_number = number; } if number == Zero::zero() { @@ -266,9 +262,9 @@ impl Blockchain { } } - storage.best_hash = hash.clone(); - storage.best_number = number.clone(); - storage.hashes.insert(number.clone(), hash.clone()); + storage.best_hash = hash; + storage.best_number = *number; + storage.hashes.insert(*number, hash); Ok(()) } @@ -362,7 +358,7 @@ impl HeaderBackend for Blockchain { finalized_hash: storage.finalized_hash, finalized_number: storage.finalized_number, finalized_state: if storage.finalized_hash != Default::default() { - Some((storage.finalized_hash.clone(), storage.finalized_number)) + Some((storage.finalized_hash, storage.finalized_number)) } else { None }, @@ -428,16 +424,12 @@ impl blockchain::Backend for Blockchain { fn justifications(&self, id: BlockId) -> sp_blockchain::Result> { Ok(self.id(id).and_then(|hash| { - self.storage - .read() - .blocks - .get(&hash) - .and_then(|b| b.justifications().map(|x| x.clone())) + self.storage.read().blocks.get(&hash).and_then(|b| b.justifications().cloned()) })) } fn last_finalized(&self) -> sp_blockchain::Result { - Ok(self.storage.read().finalized_hash.clone()) + Ok(self.storage.read().finalized_hash) } fn leaves(&self) -> sp_blockchain::Result> { @@ -810,15 +802,15 @@ impl backend::LocalBackend for Backend where Block: /// Check that genesis storage is valid. pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> { if storage.top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) { - return Err(sp_blockchain::Error::InvalidState.into()) + return Err(sp_blockchain::Error::InvalidState) } if storage .children_default .keys() - .any(|child_key| !well_known_keys::is_child_storage_key(&child_key)) + .any(|child_key| !well_known_keys::is_child_storage_key(child_key)) { - return Err(sp_blockchain::Error::InvalidState.into()) + return Err(sp_blockchain::Error::InvalidState) } Ok(()) diff --git a/client/api/src/lib.rs b/client/api/src/lib.rs index aab2fabd5e25e..3d21f12f6940b 100644 --- a/client/api/src/lib.rs +++ b/client/api/src/lib.rs @@ -57,10 +57,10 @@ pub mod utils { /// represent the current block `hash` and its `parent hash`, if given the /// function that's returned will assume that `hash` isn't part of the local DB /// yet, and all searches in the DB will instead reference the parent. - pub fn is_descendent_of<'a, Block: BlockT, T>( - client: &'a T, + pub fn is_descendent_of( + client: &T, current: Option<(Block::Hash, Block::Hash)>, - ) -> impl Fn(&Block::Hash, &Block::Hash) -> Result + 'a + ) -> impl Fn(&Block::Hash, &Block::Hash) -> Result + '_ where T: HeaderBackend + HeaderMetadata, { diff --git a/client/api/src/notifications.rs b/client/api/src/notifications.rs index 36798abc5bde5..9fcc381f9697e 100644 --- a/client/api/src/notifications.rs +++ b/client/api/src/notifications.rs @@ -71,10 +71,9 @@ type ChildKeys = Option>>>; impl StorageChangeSet { /// Convert the change set into iterator over storage items. - pub fn iter<'a>( - &'a self, - ) -> impl Iterator, &'a StorageKey, Option<&'a StorageData>)> + 'a - { + pub fn iter( + &self, + ) -> impl Iterator, &StorageKey, Option<&StorageData>)> + '_ { let top = self .changes .iter() diff --git a/client/api/src/notifications/registry.rs b/client/api/src/notifications/registry.rs index b34d5a6b6711e..882d6ed40be67 100644 --- a/client/api/src/notifications/registry.rs +++ b/client/api/src/notifications/registry.rs @@ -134,7 +134,7 @@ impl<'a> Subscribe> for Registry { }); if let Some(m) = self.metrics.as_ref() { - m.with_label_values(&[&"added"]).inc(); + m.with_label_values(&["added"]).inc(); } if self @@ -195,7 +195,7 @@ impl Registry { let k = StorageKey(k); let listeners = self.listeners.get(&k); - if let Some(ref listeners) = listeners { + if let Some(listeners) = listeners { subscribers.extend(listeners.iter()); } @@ -211,7 +211,7 @@ impl Registry { let k = StorageKey(k); let listeners = cl.get(&k); - if let Some(ref listeners) = listeners { + if let Some(listeners) = listeners { subscribers.extend(listeners.iter()); } @@ -268,22 +268,22 @@ impl Registry { ); if let Some(child_filters) = &sink.child_keys { for (c_key, filters) in child_filters { - if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) { + if let Some((listeners, wildcards)) = self.child_listeners.get_mut(c_key) { Self::remove_subscriber_from( subscriber, - &filters, + filters, &mut *listeners, &mut *wildcards, ); if listeners.is_empty() && wildcards.is_empty() { - self.child_listeners.remove(&c_key); + self.child_listeners.remove(c_key); } } } } if let Some(m) = self.metrics.as_ref() { - m.with_label_values(&[&"removed"]).inc(); + m.with_label_values(&["removed"]).inc(); } Some((sink.keys.clone(), sink.child_keys.clone())) diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index 0912359501385..87cc72ba7a69c 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -64,7 +64,7 @@ mod schema { #[cfg(test)] pub mod tests; -const LOG_TARGET: &'static str = "sub-authority-discovery"; +const LOG_TARGET: &str = "sub-authority-discovery"; /// Maximum number of addresses cached per authority. Additional addresses are discarded. const MAX_ADDRESSES_PER_AUTHORITY: usize = 10; @@ -510,7 +510,7 @@ where // Ignore [`Multiaddr`]s without [`PeerId`] or with own addresses. let addresses: Vec = addresses .into_iter() - .filter(|a| get_peer_id(&a).filter(|p| *p != local_peer_id).is_some()) + .filter(|a| get_peer_id(a).filter(|p| *p != local_peer_id).is_some()) .collect(); let remote_peer_id = single(addresses.iter().map(get_peer_id)) @@ -525,7 +525,7 @@ where if let Some(peer_signature) = peer_signature { let public_key = sc_network::PublicKey::from_protobuf_encoding(&peer_signature.public_key) - .map_err(|e| Error::ParsingLibp2pIdentity(e))?; + .map_err(Error::ParsingLibp2pIdentity)?; let signature = sc_network::Signature { public_key, bytes: peer_signature.signature }; diff --git a/client/authority-discovery/src/worker/addr_cache.rs b/client/authority-discovery/src/worker/addr_cache.rs index 3cac5a6bf0348..f768b9c4e66a7 100644 --- a/client/authority-discovery/src/worker/addr_cache.rs +++ b/client/authority-discovery/src/worker/addr_cache.rs @@ -165,10 +165,7 @@ fn peer_id_from_multiaddr(addr: &Multiaddr) -> Option { } fn addresses_to_peer_ids(addresses: &HashSet) -> HashSet { - addresses - .iter() - .filter_map(|a| peer_id_from_multiaddr(a)) - .collect::>() + addresses.iter().filter_map(peer_id_from_multiaddr).collect::>() } #[cfg(test)] diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 23725e5138697..5a020ee81050e 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -371,7 +371,7 @@ where error!( "❌️ Mandatory inherent extrinsic returned error. Block cannot be produced." ); - Err(ApplyExtrinsicFailed(Validity(e)))? + return Err(ApplyExtrinsicFailed(Validity(e))) }, Err(e) => { warn!("❗️ Inherent extrinsic returned unexpected error: {}. Dropping.", e); diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 4c1bc03e222e7..e49af3352ae4e 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -192,7 +192,7 @@ where .read() .as_ref() .cloned() - .ok_or(Error::EndpointNotReady.into()); + .ok_or_else(|| Error::EndpointNotReady.into()); let future = async move { result }.boxed(); future.map_err(jsonrpc_core::Error::from).boxed() } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 5d8aa5c866c4a..c025ec5686ad2 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -51,9 +51,9 @@ pub use beefy_protocol_name::standard_name as protocol_standard_name; pub(crate) mod beefy_protocol_name { use sc_chain_spec::ChainSpec; - const NAME: &'static str = "/beefy/1"; + const NAME: &str = "/beefy/1"; /// Old names for the notifications protocol, used for backward compatibility. - pub(crate) const LEGACY_NAMES: [&'static str; 1] = ["/paritytech/beefy/1"]; + pub(crate) const LEGACY_NAMES: [&str; 1] = ["/paritytech/beefy/1"]; /// Name of the notifications protocol used by BEEFY. /// diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index 3f9fecbccbb9e..803e9c1e8bf26 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -264,7 +264,7 @@ where let storage_changes = self .api .into_storage_changes(&state, parent_hash) - .map_err(|e| sp_blockchain::Error::StorageChanges(e))?; + .map_err(sp_blockchain::Error::StorageChanges)?; Ok(BuiltBlock { block: ::new(header, self.extrinsics), diff --git a/client/cli/src/commands/generate.rs b/client/cli/src/commands/generate.rs index 9c1e5b689584b..5b1b708f8669c 100644 --- a/client/cli/src/commands/generate.rs +++ b/client/cli/src/commands/generate.rs @@ -61,16 +61,11 @@ impl GenerateCmd { }; let mnemonic = Mnemonic::new(words, Language::English); let password = self.keystore_params.read_password()?; - let output = self.output_scheme.output_type.clone(); + let output = self.output_scheme.output_type; with_crypto_scheme!( self.crypto_scheme.scheme, - print_from_uri( - mnemonic.phrase(), - password, - self.network_scheme.network.clone(), - output, - ) + print_from_uri(mnemonic.phrase(), password, self.network_scheme.network, output) ); Ok(()) } diff --git a/client/cli/src/commands/inspect_key.rs b/client/cli/src/commands/inspect_key.rs index 61fa8d2157e3b..14bb059503df9 100644 --- a/client/cli/src/commands/inspect_key.rs +++ b/client/cli/src/commands/inspect_key.rs @@ -87,15 +87,15 @@ impl InspectKeyCmd { self.crypto_scheme.scheme, print_from_public( &uri, - self.network_scheme.network.clone(), - self.output_scheme.output_type.clone(), + self.network_scheme.network, + self.output_scheme.output_type, ) )?; } else { if let Some(ref expect_public) = self.expect_public { with_crypto_scheme!( self.crypto_scheme.scheme, - expect_public_from_phrase(&&expect_public, &uri, password.as_ref(),) + expect_public_from_phrase(expect_public, &uri, password.as_ref()) )?; } @@ -104,8 +104,8 @@ impl InspectKeyCmd { print_from_uri( &uri, password, - self.network_scheme.network.clone(), - self.output_scheme.output_type.clone(), + self.network_scheme.network, + self.output_scheme.output_type, ) ); } diff --git a/client/cli/src/commands/purge_chain_cmd.rs b/client/cli/src/commands/purge_chain_cmd.rs index 7dd7c1f5a5a5a..b89487a18f779 100644 --- a/client/cli/src/commands/purge_chain_cmd.rs +++ b/client/cli/src/commands/purge_chain_cmd.rs @@ -60,7 +60,7 @@ impl PurgeChainCmd { io::stdin().read_line(&mut input)?; let input = input.trim(); - match input.chars().nth(0) { + match input.chars().next() { Some('y') | Some('Y') => {}, _ => { println!("Aborted"); diff --git a/client/cli/src/commands/utils.rs b/client/cli/src/commands/utils.rs index fa776c25a2eda..32556f0ea728d 100644 --- a/client/cli/src/commands/utils.rs +++ b/client/cli/src/commands/utils.rs @@ -74,7 +74,7 @@ pub fn print_from_uri( { let password = password.as_ref().map(|s| s.expose_secret().as_str()); let network_id = String::from(unwrap_or_default_ss58_version(network_override)); - if let Ok((pair, seed)) = Pair::from_phrase(uri, password.clone()) { + if let Ok((pair, seed)) = Pair::from_phrase(uri, password) { let public_key = pair.public(); let network_override = unwrap_or_default_ss58_version(network_override); @@ -113,7 +113,7 @@ pub fn print_from_uri( ); }, } - } else if let Ok((pair, seed)) = Pair::from_string_with_seed(uri, password.clone()) { + } else if let Ok((pair, seed)) = Pair::from_string_with_seed(uri, password) { let public_key = pair.public(); let network_override = unwrap_or_default_ss58_version(network_override); diff --git a/client/cli/src/commands/vanity.rs b/client/cli/src/commands/vanity.rs index 834b220df6388..6a1bf77f6c8b0 100644 --- a/client/cli/src/commands/vanity.rs +++ b/client/cli/src/commands/vanity.rs @@ -64,8 +64,8 @@ impl VanityCmd { print_from_uri( &formated_seed, None, - self.network_scheme.network.clone(), - self.output_scheme.output_type.clone(), + self.network_scheme.network, + self.output_scheme.output_type, ), ); Ok(()) @@ -98,7 +98,7 @@ where let p = Pair::from_seed(&seed); let ss58 = p.public().into_account().to_ss58check_with_version(network_override); - let score = calculate_score(&desired, &ss58); + let score = calculate_score(desired, &ss58); if score > best || desired.len() < 2 { best = score; if best >= top { @@ -117,20 +117,20 @@ where fn good_waypoint(done: u64) -> u64 { match done { 0..=1_000_000 => 100_000, - 0..=10_000_000 => 1_000_000, - 0..=100_000_000 => 10_000_000, - _ => 100_000_000, + 1_000_001..=10_000_000 => 1_000_000, + 10_000_001..=100_000_000 => 10_000_000, + 100_000_001.. => 100_000_000, } } fn next_seed(seed: &mut [u8]) { - for i in 0..seed.len() { - match seed[i] { + for s in seed { + match s { 255 => { - seed[i] = 0; + *s = 0; }, _ => { - seed[i] += 1; + *s += 1; break }, } diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index d0f10dc9f6f3a..5c44a05ab68dd 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -40,7 +40,7 @@ use std::{net::SocketAddr, path::PathBuf}; pub(crate) const NODE_NAME_MAX_LENGTH: usize = 64; /// Default sub directory to store network config. -pub(crate) const DEFAULT_NETWORK_CONFIG_PATH: &'static str = "network"; +pub(crate) const DEFAULT_NETWORK_CONFIG_PATH: &str = "network"; /// The recommended open file descriptor limit to be configured for the process. const RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT: u64 = 10_000; @@ -629,7 +629,7 @@ pub trait CliConfiguration: Sized { } // Call hook for custom profiling setup. - logger_hook(&mut logger, &config); + logger_hook(&mut logger, config); logger.init()?; diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index 244f6e167f9d5..e01befbef41a2 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -122,7 +122,7 @@ pub trait SubstrateCli: Sized { let app = ::command(); let mut full_version = Self::impl_version(); - full_version.push_str("\n"); + full_version.push('\n'); let name = Self::executable_name(); let author = Self::author(); @@ -164,7 +164,7 @@ pub trait SubstrateCli: Sized { let app = ::command(); let mut full_version = Self::impl_version(); - full_version.push_str("\n"); + full_version.push('\n'); let name = Self::executable_name(); let author = Self::author(); diff --git a/client/cli/src/params/keystore_params.rs b/client/cli/src/params/keystore_params.rs index 72b09134f57a4..46403f95fbc4b 100644 --- a/client/cli/src/params/keystore_params.rs +++ b/client/cli/src/params/keystore_params.rs @@ -26,7 +26,7 @@ use std::{ }; /// default sub directory for the key store -const DEFAULT_KEYSTORE_CONFIG_PATH: &'static str = "keystore"; +const DEFAULT_KEYSTORE_CONFIG_PATH: &str = "keystore"; /// Parameters of the keystore #[derive(Debug, Clone, Args)] diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index 699d0c4ece8dc..d51b6143ed393 100644 --- a/client/cli/src/params/node_key_params.rs +++ b/client/cli/src/params/node_key_params.rs @@ -112,7 +112,7 @@ fn invalid_node_key(e: impl std::fmt::Display) -> error::Error { /// Parse a Ed25519 secret key from a hex string into a `sc_network::Secret`. fn parse_ed25519_secret(hex: &str) -> error::Result { - H256::from_str(&hex).map_err(invalid_node_key).and_then(|bytes| { + H256::from_str(hex).map_err(invalid_node_key).and_then(|bytes| { ed25519::SecretKey::from_bytes(bytes) .map(sc_network::config::Secret::Input) .map_err(invalid_node_key) diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 01df2cf9abba4..67b18aa8b09e2 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -126,7 +126,7 @@ impl SharedParams { /// Receiver to process tracing messages. pub fn tracing_receiver(&self) -> sc_service::TracingReceiver { - self.tracing_receiver.clone().into() + self.tracing_receiver.into() } /// Comma separated list of targets for tracing. diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 56eb45c621a1b..30554006732c0 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -68,7 +68,7 @@ where C: sc_client_api::backend::AuxStore, P::Public: Encode + Decode + PartialEq + Clone, { - let seal = header.digest_mut().pop().ok_or_else(|| Error::HeaderUnsealed(hash))?; + let seal = header.digest_mut().pop().ok_or(Error::HeaderUnsealed(hash))?; let sig = seal.as_aura_seal().ok_or_else(|| aura_err(Error::HeaderBadSeal(hash)))?; @@ -81,7 +81,7 @@ where // check the signature is valid under the expected authority and // chain state. let expected_author = - slot_author::

(slot, &authorities).ok_or_else(|| Error::SlotAuthorNotFound)?; + slot_author::

(slot, authorities).ok_or(Error::SlotAuthorNotFound)?; let pre_hash = header.hash(); @@ -360,7 +360,7 @@ pub struct ImportQueueParams<'a, Block, I, C, S, CAW, CIDP> { } /// Start an import queue for the Aura consensus algorithm. -pub fn import_queue<'a, P, Block, I, C, S, CAW, CIDP>( +pub fn import_queue( ImportQueueParams { block_import, justification_import, @@ -371,7 +371,7 @@ pub fn import_queue<'a, P, Block, I, C, S, CAW, CIDP>( can_author_with, check_for_equivocation, telemetry, - }: ImportQueueParams<'a, Block, I, C, S, CAW, CIDP>, + }: ImportQueueParams, ) -> Result, sp_consensus::Error> where Block: BlockT, diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index d803aa4ae97f8..ac3b89f2ff9a2 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -186,7 +186,7 @@ where Error: std::error::Error + Send + From + 'static, { let worker = build_aura_worker::(BuildAuraWorkerParams { - client: client.clone(), + client, block_import, proposer_factory, keystore, @@ -459,7 +459,7 @@ where fn proposer(&mut self, block: &B::Header) -> Self::CreateProposer { self.env .init(block) - .map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e)).into()) + .map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e))) .boxed() } @@ -534,7 +534,7 @@ pub fn find_pre_digest(header: &B::Header) -> Resul for log in header.digest().logs() { trace!(target: "aura", "Checking log {:?}", log); match (CompatibleDigestItem::::as_aura_pre_digest(log), pre_digest.is_some()) { - (Some(_), true) => Err(aura_err(Error::MultipleHeaders))?, + (Some(_), true) => return Err(aura_err(Error::MultipleHeaders)), (None, _) => trace!(target: "aura", "Ignoring digest not meant for us"), (s, false) => pre_digest = s, } @@ -553,7 +553,7 @@ where .runtime_api() .authorities(at) .ok() - .ok_or_else(|| sp_consensus::Error::InvalidAuthoritiesSet.into()) + .ok_or(sp_consensus::Error::InvalidAuthoritiesSet) } #[cfg(test)] diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 1fbe23e54f50d..2d0c81afc7775 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -142,7 +142,7 @@ where claims.entry(key).or_default().secondary.push(slot); }, PreDigest::SecondaryVRF { .. } => { - claims.entry(key).or_default().secondary_vrf.push(slot.into()); + claims.entry(key).or_default().secondary_vrf.push(slot); }, }; } @@ -205,7 +205,7 @@ where .epoch_data_for_child_of( descendent_query(&**client), &parent.hash(), - parent.number().clone(), + *parent.number(), slot.into(), |slot| Epoch::genesis(babe_config.genesis_config(), slot), ) diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 1f74afb0e78b4..7a9b09495cd6f 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -202,15 +202,15 @@ pub fn claim_slot_using_keys( keystore: &SyncCryptoStorePtr, keys: &[(AuthorityId, usize)], ) -> Option<(PreDigest, AuthorityId)> { - claim_primary_slot(slot, epoch, epoch.config.c, keystore, &keys).or_else(|| { + claim_primary_slot(slot, epoch, epoch.config.c, keystore, keys).or_else(|| { if epoch.config.allowed_slots.is_secondary_plain_slots_allowed() || epoch.config.allowed_slots.is_secondary_vrf_slots_allowed() { claim_secondary_slot( slot, - &epoch, + epoch, keys, - &keystore, + keystore, epoch.config.allowed_slots.is_secondary_vrf_slots_allowed(), ) } else { diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index be5c2809bd796..490fdfb174311 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -528,7 +528,7 @@ where let (worker_tx, worker_rx) = channel(HANDLE_BUFFER_SIZE); let answer_requests = - answer_requests(worker_rx, babe_link.config, client, babe_link.epoch_changes.clone()); + answer_requests(worker_rx, babe_link.config, client, babe_link.epoch_changes); let inner = future::select(Box::pin(slot_worker), Box::pin(answer_requests)); Ok(BabeWorker { @@ -638,13 +638,13 @@ async fn answer_requests( slot_number, ) .map_err(|e| Error::::ForkTree(Box::new(e)))? - .ok_or_else(|| Error::::FetchEpoch(parent_hash))?; + .ok_or(Error::::FetchEpoch(parent_hash))?; let viable_epoch = epoch_changes .viable_epoch(&epoch_descriptor, |slot| { Epoch::genesis(&config.genesis_config, slot) }) - .ok_or_else(|| Error::::FetchEpoch(parent_hash))?; + .ok_or(Error::::FetchEpoch(parent_hash))?; Ok(sp_consensus_babe::Epoch { epoch_index: viable_epoch.as_ref().epoch_index, @@ -788,7 +788,7 @@ where .epoch_descriptor_for_child_of( descendent_query(&*self.client), &parent.hash(), - parent.number().clone(), + *parent.number(), slot, ) .map_err(|e| ConsensusError::ChainLookup(e.to_string()))? @@ -798,7 +798,7 @@ where fn authorities_len(&self, epoch_descriptor: &Self::EpochData) -> Option { self.epoch_changes .shared_data() - .viable_epoch(&epoch_descriptor, |slot| { + .viable_epoch(epoch_descriptor, |slot| { Epoch::genesis(&self.config.genesis_config, slot) }) .map(|epoch| epoch.as_ref().authorities.len()) @@ -815,7 +815,7 @@ where slot, self.epoch_changes .shared_data() - .viable_epoch(&epoch_descriptor, |slot| { + .viable_epoch(epoch_descriptor, |slot| { Epoch::genesis(&self.config.genesis_config, slot) })? .as_ref(), @@ -886,7 +886,7 @@ where .clone() .try_into() .map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?; - let digest_item = ::babe_seal(signature.into()); + let digest_item = ::babe_seal(signature); let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); import_block.post_digests.push(digest_item); @@ -1245,12 +1245,12 @@ where pre_digest.slot(), ) .map_err(|e| Error::::ForkTree(Box::new(e)))? - .ok_or_else(|| Error::::FetchEpoch(parent_hash))?; + .ok_or(Error::::FetchEpoch(parent_hash))?; let viable_epoch = epoch_changes .viable_epoch(&epoch_descriptor, |slot| { Epoch::genesis(&self.config.genesis_config, slot) }) - .ok_or_else(|| Error::::FetchEpoch(parent_hash))?; + .ok_or(Error::::FetchEpoch(parent_hash))?; // We add one to the current slot to allow for some small drift. // FIXME #1019 in the future, alter this queue to allow deferring of headers diff --git a/client/consensus/babe/src/verification.rs b/client/consensus/babe/src/verification.rs index 41d1e1bfa5d36..53ec3002e6a85 100644 --- a/client/consensus/babe/src/verification.rs +++ b/client/consensus/babe/src/verification.rs @@ -99,7 +99,7 @@ pub(super) fn check_header( primary.slot, ); - check_primary_header::(pre_hash, primary, sig, &epoch, epoch.config.c)?; + check_primary_header::(pre_hash, primary, sig, epoch, epoch.config.c)?; }, PreDigest::SecondaryPlain(secondary) if epoch.config.allowed_slots.is_secondary_plain_slots_allowed() => @@ -110,7 +110,7 @@ pub(super) fn check_header( secondary.slot, ); - check_secondary_plain_header::(pre_hash, secondary, sig, &epoch)?; + check_secondary_plain_header::(pre_hash, secondary, sig, epoch)?; }, PreDigest::SecondaryVRF(secondary) if epoch.config.allowed_slots.is_secondary_vrf_slots_allowed() => @@ -121,7 +121,7 @@ pub(super) fn check_header( secondary.slot, ); - check_secondary_vrf_header::(pre_hash, secondary, sig, &epoch)?; + check_secondary_vrf_header::(pre_hash, secondary, sig, epoch)?; }, _ => return Err(babe_err(Error::SecondarySlotAssignmentsDisabled)), } @@ -153,7 +153,7 @@ fn check_primary_header( ) -> Result<(), Error> { let author = &epoch.authorities[pre_digest.authority_index as usize].0; - if AuthorityPair::verify(&signature, pre_hash, &author) { + if AuthorityPair::verify(&signature, pre_hash, author) { let (inout, _) = { let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch.epoch_index); @@ -191,7 +191,7 @@ fn check_secondary_plain_header( // chain state. let expected_author = secondary_slot_author(pre_digest.slot, &epoch.authorities, epoch.randomness) - .ok_or_else(|| Error::NoSecondaryAuthorExpected)?; + .ok_or(Error::NoSecondaryAuthorExpected)?; let author = &epoch.authorities[pre_digest.authority_index as usize].0; @@ -217,7 +217,7 @@ fn check_secondary_vrf_header( // chain state. let expected_author = secondary_slot_author(pre_digest.slot, &epoch.authorities, epoch.randomness) - .ok_or_else(|| Error::NoSecondaryAuthorExpected)?; + .ok_or(Error::NoSecondaryAuthorExpected)?; let author = &epoch.authorities[pre_digest.authority_index as usize].0; diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index 24fec9b974a4c..f81c8eb7e8dee 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -62,8 +62,7 @@ impl ImportResult { /// `clear_justification_requests`, `needs_justification`, /// `bad_justification` set to false. pub fn imported(is_new_best: bool) -> ImportResult { - let mut aux = ImportedAux::default(); - aux.is_new_best = is_new_best; + let aux = ImportedAux { is_new_best, ..Default::default() }; ImportResult::Imported(aux) } diff --git a/client/consensus/common/src/import_queue.rs b/client/consensus/common/src/import_queue.rs index 8b560d0447411..a7b456191b000 100644 --- a/client/consensus/common/src/import_queue.rs +++ b/client/consensus/common/src/import_queue.rs @@ -232,17 +232,17 @@ pub(crate) async fn import_single_block_metered< trace!(target: "sync", "Header {} has {:?} logs", block.hash, header.digest().logs().len()); - let number = header.number().clone(); + let number = *header.number(); let hash = block.hash; - let parent_hash = header.parent_hash().clone(); + let parent_hash = *header.parent_hash(); let import_handler = |import| match import { Ok(ImportResult::AlreadyInChain) => { trace!(target: "sync", "Block already in chain {}: {:?}", number, hash); - Ok(BlockImportStatus::ImportedKnown(number, peer.clone())) + Ok(BlockImportStatus::ImportedKnown(number, peer)) }, Ok(ImportResult::Imported(aux)) => - Ok(BlockImportStatus::ImportedUnknown(number, aux, peer.clone())), + Ok(BlockImportStatus::ImportedUnknown(number, aux, peer)), Ok(ImportResult::MissingState) => { debug!(target: "sync", "Parent state is missing for {}: {:?}, parent: {:?}", number, hash, parent_hash); @@ -255,7 +255,7 @@ pub(crate) async fn import_single_block_metered< }, Ok(ImportResult::KnownBad) => { debug!(target: "sync", "Peer gave us a bad block {}: {:?}", number, hash); - Err(BlockImportError::BadBlock(peer.clone())) + Err(BlockImportError::BadBlock(peer)) }, Err(e) => { debug!(target: "sync", "Error importing block {}: {:?}: {}", number, hash, e); @@ -306,7 +306,7 @@ pub(crate) async fn import_single_block_metered< if let Some(metrics) = metrics.as_ref() { metrics.report_verification(false, started.elapsed()); } - BlockImportError::VerificationFailed(peer.clone(), msg) + BlockImportError::VerificationFailed(peer, msg) })?; if let Some(metrics) = metrics.as_ref() { diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index 5134dc041c26b..9fe293142050b 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -374,7 +374,7 @@ async fn import_many_blocks, Transaction: Send + 'stat }, }; - let block_number = block.header.as_ref().map(|h| h.number().clone()); + let block_number = block.header.as_ref().map(|h| *h.number()); let block_hash = block.hash; let import_result = if has_error { Err(BlockImportError::Cancelled) @@ -382,7 +382,7 @@ async fn import_many_blocks, Transaction: Send + 'stat // The actual import. import_single_block_metered( import_handle, - blocks_origin.clone(), + blocks_origin, block, verifier, metrics.clone(), diff --git a/client/consensus/common/src/import_queue/buffered_link.rs b/client/consensus/common/src/import_queue/buffered_link.rs index 8fb5689075ab2..d3d91f5bd31c5 100644 --- a/client/consensus/common/src/import_queue/buffered_link.rs +++ b/client/consensus/common/src/import_queue/buffered_link.rs @@ -105,14 +105,14 @@ impl Link for BufferedLinkSender { number: NumberFor, success: bool, ) { - let msg = BlockImportWorkerMsg::JustificationImported(who, hash.clone(), number, success); + let msg = BlockImportWorkerMsg::JustificationImported(who, *hash, number, success); let _ = self.tx.unbounded_send(msg); } fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { let _ = self .tx - .unbounded_send(BlockImportWorkerMsg::RequestJustification(hash.clone(), number)); + .unbounded_send(BlockImportWorkerMsg::RequestJustification(*hash, number)); } } diff --git a/client/consensus/common/src/longest_chain.rs b/client/consensus/common/src/longest_chain.rs index b38183b8ac11f..941cd4b944766 100644 --- a/client/consensus/common/src/longest_chain.rs +++ b/client/consensus/common/src/longest_chain.rs @@ -79,12 +79,12 @@ where Block: BlockT, { async fn leaves(&self) -> Result::Hash>, ConsensusError> { - LongestChain::leaves(self).map_err(|e| ConsensusError::ChainLookup(e.to_string()).into()) + LongestChain::leaves(self).map_err(|e| ConsensusError::ChainLookup(e.to_string())) } async fn best_chain(&self) -> Result<::Header, ConsensusError> { - LongestChain::best_block_header(&self) - .map_err(|e| ConsensusError::ChainLookup(e.to_string()).into()) + LongestChain::best_block_header(self) + .map_err(|e| ConsensusError::ChainLookup(e.to_string())) } async fn finality_target( @@ -97,6 +97,6 @@ where .blockchain() .best_containing(target_hash, maybe_max_number, import_lock) .map(|maybe_hash| maybe_hash.unwrap_or(target_hash)) - .map_err(|e| ConsensusError::ChainLookup(e.to_string()).into()) + .map_err(|e| ConsensusError::ChainLookup(e.to_string())) } } diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index 90081bf9af442..3a943e4851a4d 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -566,7 +566,7 @@ where ViableEpochDescriptor::UnimportedGenesis(slot) => Some(ViableEpoch::UnimportedGenesis(make_genesis(*slot))), ViableEpochDescriptor::Signaled(identifier, _) => - self.epoch(&identifier).map(ViableEpoch::Signaled), + self.epoch(identifier).map(ViableEpoch::Signaled), } } @@ -599,7 +599,7 @@ where ViableEpochDescriptor::UnimportedGenesis(slot) => Some(ViableEpoch::UnimportedGenesis(make_genesis(*slot))), ViableEpochDescriptor::Signaled(identifier, _) => - self.epoch_mut(&identifier).map(ViableEpoch::Signaled), + self.epoch_mut(identifier).map(ViableEpoch::Signaled), } } @@ -618,7 +618,7 @@ where { match descriptor { ViableEpochDescriptor::UnimportedGenesis(slot) => Some(make_genesis(*slot)), - ViableEpochDescriptor::Signaled(identifier, _) => self.epoch(&identifier).cloned(), + ViableEpochDescriptor::Signaled(identifier, _) => self.epoch(identifier).cloned(), } } @@ -750,7 +750,7 @@ where if let Some(gap) = &mut self.gap { if let PersistedEpoch::Regular(e) = epoch { - epoch = match gap.import(slot, hash.clone(), number.clone(), e) { + epoch = match gap.import(slot, hash, number, e) { Ok(()) => return Ok(()), Err(e) => PersistedEpoch::Regular(e), } diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 53cc58df30a36..3e7770cd982d2 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -114,7 +114,7 @@ where .epoch_descriptor_for_child_of( descendent_query(&*self.client), &parent.hash(), - parent.number().clone(), + *parent.number(), pre_digest.slot(), ) .map_err(|e| format!("failed to fetch epoch_descriptor: {}", e))? @@ -162,11 +162,11 @@ where .epoch_descriptor_for_child_of( descendent_query(&*self.client), &parent.hash(), - parent.number().clone(), + *parent.number(), slot, ) .map_err(|e| Error::StringError(format!("failed to fetch epoch_descriptor: {}", e)))? - .ok_or_else(|| sp_consensus::Error::InvalidAuthoritiesSet)?; + .ok_or(sp_consensus::Error::InvalidAuthoritiesSet)?; let epoch = epoch_changes .viable_epoch(&epoch_descriptor, |slot| { @@ -216,19 +216,19 @@ where .epoch_descriptor_for_child_of( descendent_query(&*self.client), &parent.hash(), - parent.number().clone(), + *parent.number(), slot, ) .map_err(|e| { Error::StringError(format!("failed to fetch epoch_descriptor: {}", e)) })? - .ok_or_else(|| sp_consensus::Error::InvalidAuthoritiesSet)?; + .ok_or(sp_consensus::Error::InvalidAuthoritiesSet)?; match epoch_descriptor { ViableEpochDescriptor::Signaled(identifier, _epoch_header) => { let epoch_mut = epoch_changes .epoch_mut(&identifier) - .ok_or_else(|| sp_consensus::Error::InvalidAuthoritiesSet)?; + .ok_or(sp_consensus::Error::InvalidAuthoritiesSet)?; // mutate the current epoch epoch_mut.authorities = self.authorities.clone(); @@ -236,7 +236,7 @@ where let next_epoch = ConsensusLog::NextEpochData(NextEpochDescriptor { authorities: self.authorities.clone(), // copy the old randomness - randomness: epoch_mut.randomness.clone(), + randomness: epoch_mut.randomness, }); vec![ @@ -268,11 +268,11 @@ where .epoch_descriptor_for_child_of( descendent_query(&*self.client), &parent.hash(), - parent.number().clone(), + *parent.number(), slot, ) .map_err(|e| Error::StringError(format!("failed to fetch epoch_descriptor: {}", e)))? - .ok_or_else(|| sp_consensus::Error::InvalidAuthoritiesSet)?; + .ok_or(sp_consensus::Error::InvalidAuthoritiesSet)?; // drop the lock drop(epoch_changes); // a quick check to see if we're in the authorities diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 8885099ceb514..6f9ee6f864ad8 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -234,7 +234,7 @@ impl Clone select_chain: self.select_chain.clone(), client: self.client.clone(), create_inherent_data_providers: self.create_inherent_data_providers.clone(), - check_inherents_after: self.check_inherents_after.clone(), + check_inherents_after: self.check_inherents_after, can_author_with: self.can_author_with.clone(), } } @@ -652,21 +652,19 @@ where }, }; - let proposal = match proposer - .propose(inherent_data, inherent_digest, build_time.clone(), None) - .await - { - Ok(x) => x, - Err(err) => { - warn!( - target: "pow", - "Unable to propose new block for authoring. \ - Creating proposal failed: {}", - err, - ); - continue - }, - }; + let proposal = + match proposer.propose(inherent_data, inherent_digest, build_time, None).await { + Ok(x) => x, + Err(err) => { + warn!( + target: "pow", + "Unable to propose new block for authoring. \ + Creating proposal failed: {}", + err, + ); + continue + }, + }; let build = MiningBuild:: { metadata: MiningMetadata { @@ -710,8 +708,8 @@ fn fetch_seal(digest: Option<&DigestItem>, hash: B::Hash) -> Result::WrongEngine(*id).into()) + Err(Error::::WrongEngine(*id)) }, - _ => return Err(Error::::HeaderUnsealed(hash).into()), + _ => Err(Error::::HeaderUnsealed(hash)), } } diff --git a/client/consensus/pow/src/worker.rs b/client/consensus/pow/src/worker.rs index 42f82fb43ef7b..750e78cd9a038 100644 --- a/client/consensus/pow/src/worker.rs +++ b/client/consensus/pow/src/worker.rs @@ -295,7 +295,7 @@ impl Stream for UntilImportedOrTimeout { } } - let timeout = self.timeout.clone(); + let timeout = self.timeout; let inner_delay = self.inner_delay.get_or_insert_with(|| Delay::new(timeout)); match Future::poll(Pin::new(inner_delay), cx) { diff --git a/client/consensus/slots/src/aux_schema.rs b/client/consensus/slots/src/aux_schema.rs index 275b12ff48f80..eeaec68d369d2 100644 --- a/client/consensus/slots/src/aux_schema.rs +++ b/client/consensus/slots/src/aux_schema.rs @@ -63,7 +63,7 @@ where P: Clone + Encode + Decode + PartialEq, { // We don't check equivocations for old headers out of our capacity. - if slot_now.saturating_sub(*slot) > Slot::from(MAX_SLOT_CAPACITY) { + if slot_now.saturating_sub(*slot) > MAX_SLOT_CAPACITY { return Ok(None) } diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index a97469fbcc300..a6fbc4bebc796 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -606,7 +606,7 @@ pub fn proposing_remaining_duration( // if we defined a maximum portion of the slot for proposal then we must make sure the // lenience doesn't go over it let lenient_proposing_duration = - if let Some(ref max_block_proposal_slot_portion) = max_block_proposal_slot_portion { + if let Some(max_block_proposal_slot_portion) = max_block_proposal_slot_portion { std::cmp::min( lenient_proposing_duration, slot_info.duration.mul_f32(max_block_proposal_slot_portion.get()), diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index fe31d31dfef9e..8bc4a0f4893c7 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -57,14 +57,14 @@ impl sp_state_machine::Storage> for StorageDb Result, String> { let prefixed_key = prefixed_key::>(key, prefix); if let Some(recorder) = &self.proof_recorder { - if let Some(v) = recorder.get(&key) { - return Ok(v.clone()) + if let Some(v) = recorder.get(key) { + return Ok(v) } let backend_value = self .db .get(0, &prefixed_key) .map_err(|e| format!("Database backend error: {:?}", e))?; - recorder.record(key.clone(), backend_value.clone()); + recorder.record(*key, backend_value.clone()); Ok(backend_value) } else { self.db @@ -114,7 +114,7 @@ impl BenchmarkingState { let mut state = BenchmarkingState { state: RefCell::new(None), db: Cell::new(None), - root: Cell::new(root.clone()), + root: Cell::new(root), genesis: Default::default(), genesis_root: Default::default(), record: Default::default(), @@ -123,7 +123,7 @@ impl BenchmarkingState { child_key_tracker: Default::default(), whitelist: Default::default(), proof_recorder: record_proof.then(Default::default), - proof_recorder_root: Cell::new(root.clone()), + proof_recorder_root: Cell::new(root), enable_tracking, }; @@ -143,7 +143,7 @@ impl BenchmarkingState { state_version, ); state.genesis = transaction.clone().drain(); - state.genesis_root = root.clone(); + state.genesis_root = root; state.commit(root, transaction, Vec::new(), Vec::new())?; state.record.take(); Ok(state) @@ -201,9 +201,7 @@ impl BenchmarkingState { let mut main_key_tracker = self.main_key_tracker.borrow_mut(); let key_tracker = if let Some(childtrie) = childtrie { - child_key_tracker - .entry(childtrie.to_vec()) - .or_insert_with(|| LinkedHashMap::new()) + child_key_tracker.entry(childtrie.to_vec()).or_insert_with(LinkedHashMap::new) } else { &mut main_key_tracker }; @@ -244,9 +242,7 @@ impl BenchmarkingState { let mut main_key_tracker = self.main_key_tracker.borrow_mut(); let key_tracker = if let Some(childtrie) = childtrie { - child_key_tracker - .entry(childtrie.to_vec()) - .or_insert_with(|| LinkedHashMap::new()) + child_key_tracker.entry(childtrie.to_vec()).or_insert_with(LinkedHashMap::new) } else { &mut main_key_tracker }; @@ -517,7 +513,7 @@ impl StateBackend> for BenchmarkingState { self.db.set(Some(db)); } - self.root.set(self.genesis_root.clone()); + self.root.set(self.genesis_root); self.reopen()?; self.wipe_tracker(); Ok(()) @@ -612,18 +608,17 @@ impl StateBackend> for BenchmarkingState { if proof_recorder_root == Default::default() || proof_size == 1 { // empty trie proof_size + } else if let Some(size) = proof.encoded_compact_size::>(proof_recorder_root) + { + size as u32 } else { - if let Some(size) = proof.encoded_compact_size::>(proof_recorder_root) { - size as u32 - } else { - panic!( - "proof rec root {:?}, root {:?}, genesis {:?}, rec_len {:?}", - self.proof_recorder_root.get(), - self.root.get(), - self.genesis_root, - proof_size, - ); - } + panic!( + "proof rec root {:?}, root {:?}, genesis {:?}, rec_len {:?}", + self.proof_recorder_root.get(), + self.root.get(), + self.genesis_root, + proof_size, + ); } }) } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 735058897340e..72422eb82d6dd 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -352,8 +352,8 @@ impl DatabaseSource { // // IIUC this is needed for polkadot to create its own dbs, so until it can use parity db // I would think rocksdb, but later parity-db. - DatabaseSource::Auto { paritydb_path, .. } => Some(&paritydb_path), - DatabaseSource::RocksDb { path, .. } | DatabaseSource::ParityDb { path } => Some(&path), + DatabaseSource::Auto { paritydb_path, .. } => Some(paritydb_path), + DatabaseSource::RocksDb { path, .. } | DatabaseSource::ParityDb { path } => Some(path), DatabaseSource::Custom(..) => None, } } @@ -478,7 +478,7 @@ impl BlockchainDb { if is_finalized { if with_state { - meta.finalized_state = Some((hash.clone(), number)); + meta.finalized_state = Some((hash, number)); } meta.finalized_number = number; meta.finalized_hash = hash; @@ -501,7 +501,7 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha } let header = utils::read_header(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id)?; - cache_header(&mut cache, h.clone(), header.clone()); + cache_header(&mut cache, *h, header.clone()); Ok(header) }, BlockId::Number(_) => @@ -517,7 +517,7 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha genesis_hash: meta.genesis_hash, finalized_hash: meta.finalized_hash, finalized_number: meta.finalized_number, - finalized_state: meta.finalized_state.clone(), + finalized_state: meta.finalized_state, number_leaves: self.leaves.read().count(), block_gap: meta.block_gap, } @@ -540,10 +540,7 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha fn hash(&self, number: NumberFor) -> ClientResult> { self.header(BlockId::Number(number)) - .and_then(|maybe_header| match maybe_header { - Some(header) => Ok(Some(header.hash().clone())), - None => Ok(None), - }) + .map(|maybe_header| maybe_header.map(|header| header.hash())) } } @@ -621,7 +618,7 @@ impl sc_client_api::blockchain::Backend for BlockchainDb ClientResult { - Ok(self.meta.read().finalized_hash.clone()) + Ok(self.meta.read().finalized_hash) } fn leaves(&self) -> ClientResult> { @@ -765,8 +762,8 @@ impl BlockImportOperation { storage: Storage, state_version: StateVersion, ) -> ClientResult { - if storage.top.keys().any(|k| well_known_keys::is_child_storage_key(&k)) { - return Err(sp_blockchain::Error::InvalidState.into()) + if storage.top.keys().any(|k| well_known_keys::is_child_storage_key(k)) { + return Err(sp_blockchain::Error::InvalidState) } let child_delta = storage.children_default.iter().map(|(_storage_key, child_content)| { @@ -1063,7 +1060,7 @@ impl Backend { ) -> ClientResult { let is_archive_pruning = config.state_pruning.is_archive(); let blockchain = BlockchainDb::new(db.clone())?; - let map_e = |e: sc_state_db::Error| sp_blockchain::Error::from_state_db(e); + let map_e = sp_blockchain::Error::from_state_db; let state_db: StateDb<_, _> = StateDb::new( config.state_pruning.clone(), !db.supports_ref_counting(), @@ -1087,7 +1084,7 @@ impl Backend { is_archive: is_archive_pruning, io_stats: FrozenForDuration::new(std::time::Duration::from_secs(1)), state_usage: Arc::new(StateUsageStats::new()), - keep_blocks: config.keep_blocks.clone(), + keep_blocks: config.keep_blocks, genesis_state: RwLock::new(None), }; @@ -1135,7 +1132,7 @@ impl Backend { (meta.best_number - best_number).saturated_into::() > self.canonicalization_delay { - return Err(sp_blockchain::Error::SetHeadTooOld.into()) + return Err(sp_blockchain::Error::SetHeadTooOld) } let parent_exists = @@ -1154,16 +1151,16 @@ impl Backend { (&r.number, &r.hash) ); - return Err(::sp_blockchain::Error::NotInFinalizedChain.into()) + return Err(::sp_blockchain::Error::NotInFinalizedChain) } - retracted.push(r.hash.clone()); + retracted.push(r.hash); utils::remove_number_to_key_mapping(transaction, columns::KEY_LOOKUP, r.number)?; } // canonicalize: set the number lookup to map to this block's hash. for e in tree_route.enacted() { - enacted.push(e.hash.clone()); + enacted.push(e.hash); utils::insert_number_to_key_mapping( transaction, columns::KEY_LOOKUP, @@ -1199,8 +1196,7 @@ impl Backend { "Last finalized {:?} not parent of {:?}", last_finalized, header.hash() - )) - .into()) + ))) } Ok(()) } @@ -1217,7 +1213,7 @@ impl Backend { // TODO: ensure best chain contains this block. let number = *header.number(); self.ensure_sequential_finalization(header, last_finalized)?; - let with_state = sc_client_api::Backend::have_state_at(self, &hash, number); + let with_state = sc_client_api::Backend::have_state_at(self, hash, number); self.note_finalized(transaction, header, *hash, finalization_displaced, with_state)?; @@ -1264,9 +1260,10 @@ impl Backend { } trace!(target: "db", "Canonicalize block #{} ({:?})", new_canonical, hash); - let commit = self.storage.state_db.canonicalize_block(&hash).map_err( - |e: sc_state_db::Error| sp_blockchain::Error::from_state_db(e), - )?; + let commit = + self.storage.state_db.canonicalize_block(&hash).map_err( + sp_blockchain::Error::from_state_db::>, + )?; apply_state_commit(transaction, commit); } Ok(()) @@ -1282,7 +1279,7 @@ impl Backend { let mut meta_updates = Vec::with_capacity(operation.finalized_blocks.len()); let (best_num, mut last_finalized_hash, mut last_finalized_num, mut block_gap) = { let meta = self.blockchain.meta.read(); - (meta.best_number, meta.finalized_hash, meta.finalized_number, meta.block_gap.clone()) + (meta.best_number, meta.finalized_hash, meta.finalized_number, meta.block_gap) }; for (block, justification) in operation.finalized_blocks { @@ -1297,14 +1294,14 @@ impl Backend { &mut finalization_displaced_leaves, )?); last_finalized_hash = block_hash; - last_finalized_num = block_header.number().clone(); + last_finalized_num = *block_header.number(); } let imported = if let Some(pending_block) = operation.pending_block { let hash = pending_block.header.hash(); let parent_hash = *pending_block.header.parent_hash(); - let number = pending_block.header.number().clone(); + let number = *pending_block.header.number(); let existing_header = number <= best_num && self.blockchain.header(BlockId::hash(hash))?.is_some(); @@ -1352,7 +1349,7 @@ impl Backend { // memory to bootstrap consensus. It is queried for an initial list of // authorities, etc. *self.genesis_state.write() = Some(Arc::new(DbGenesisStorage::new( - pending_block.header.state_root().clone(), + *pending_block.header.state_root(), operation.db_updates.clone(), ))); } @@ -1411,7 +1408,7 @@ impl Backend { let commit = self .storage .state_db - .insert_block(&hash, number_u64, &pending_block.header.parent_hash(), changeset) + .insert_block(&hash, number_u64, pending_block.header.parent_hash(), changeset) .map_err(|e: sc_state_db::Error| { sp_blockchain::Error::from_state_db(e) })?; @@ -1419,7 +1416,7 @@ impl Backend { if number <= last_finalized_num { // Canonicalize in the db when re-importing existing blocks with state. let commit = self.storage.state_db.canonicalize_block(&hash).map_err( - |e: sc_state_db::Error| sp_blockchain::Error::from_state_db(e), + sp_blockchain::Error::from_state_db::>, )?; apply_state_commit(&mut transaction, commit); meta_updates.push(MetaUpdate { @@ -1549,11 +1546,8 @@ impl Backend { let number = header.number(); let hash = header.hash(); - let (enacted, retracted) = self.set_head_with_transaction( - &mut transaction, - hash.clone(), - (number.clone(), hash.clone()), - )?; + let (enacted, retracted) = + self.set_head_with_transaction(&mut transaction, hash, (*number, hash))?; meta_updates.push(MetaUpdate { hash, number: *number, @@ -1616,9 +1610,9 @@ impl Backend { displaced: &mut Option>>, with_state: bool, ) -> ClientResult<()> { - let f_num = f_header.number().clone(); + let f_num = *f_header.number(); - let lookup_key = utils::number_and_hash_to_lookup_key(f_num, f_hash.clone())?; + let lookup_key = utils::number_and_hash_to_lookup_key(f_num, f_hash)?; if with_state { transaction.set_from_vec(columns::META, meta_keys::FINALIZED_STATE, lookup_key.clone()); } @@ -1631,9 +1625,10 @@ impl Backend { .map(|c| f_num.saturated_into::() > c) .unwrap_or(true) { - let commit = self.storage.state_db.canonicalize_block(&f_hash).map_err( - |e: sc_state_db::Error| sp_blockchain::Error::from_state_db(e), - )?; + let commit = + self.storage.state_db.canonicalize_block(&f_hash).map_err( + sp_blockchain::Error::from_state_db::>, + )?; apply_state_commit(transaction, commit); } @@ -1664,18 +1659,18 @@ impl Backend { // Also discard all blocks from displaced branches for h in displaced.leaves() { let mut number = finalized; - let mut hash = h.clone(); + let mut hash = *h; // Follow displaced chains back until we reach a finalized block. // Since leaves are discarded due to finality, they can't have parents // that are canonical, but not yet finalized. So we stop deleting as soon as // we reach canonical chain. - while self.blockchain.hash(number)? != Some(hash.clone()) { - let id = BlockId::::hash(hash.clone()); + while self.blockchain.hash(number)? != Some(hash) { + let id = BlockId::::hash(hash); match self.blockchain.header(id)? { Some(header) => { self.prune_block(transaction, id)?; number = header.number().saturating_sub(One::one()); - hash = header.parent_hash().clone(); + hash = *header.parent_hash(); }, None => break, } @@ -1780,7 +1775,7 @@ fn apply_index_ops( // Bump ref counter let extrinsic = extrinsic.encode(); transaction.reference(columns::TRANSACTION, DbHash::from_slice(hash.as_ref())); - DbExtrinsic::Indexed { hash: hash.clone(), header: extrinsic } + DbExtrinsic::Indexed { hash: *hash, header: extrinsic } } else { match index_map.get(&(index as u32)) { Some((hash, size)) => { @@ -2063,8 +2058,7 @@ impl sc_client_api::backend::Backend for Backend { let update_finalized = best_number < finalized; - let key = - utils::number_and_hash_to_lookup_key(best_number.clone(), &best_hash)?; + let key = utils::number_and_hash_to_lookup_key(best_number, &best_hash)?; if update_finalized { transaction.set_from_vec( columns::META, @@ -2143,8 +2137,8 @@ impl sc_client_api::backend::Backend for Backend { return Err(sp_blockchain::Error::Backend(format!("Can't remove best block {:?}", hash))) } - let hdr = self.blockchain.header_metadata(hash.clone())?; - if !self.have_state_at(&hash, hdr.number) { + let hdr = self.blockchain.header_metadata(*hash)?; + if !self.have_state_at(hash, hdr.number) { return Err(sp_blockchain::Error::UnknownBlock(format!( "State already discarded for {:?}", hash @@ -2164,7 +2158,7 @@ impl sc_client_api::backend::Backend for Backend { apply_state_commit(&mut transaction, commit); } transaction.remove(columns::KEY_LOOKUP, hash.as_ref()); - leaves.revert(hash.clone(), hdr.number); + leaves.revert(*hash, hdr.number); leaves.prepare_transaction(&mut transaction, columns::META, meta_keys::LEAF_PREFIX); self.storage.db.commit(transaction)?; self.blockchain().remove_header_metadata(*hash); @@ -2185,8 +2179,7 @@ impl sc_client_api::backend::Backend for Backend { }; if is_genesis { if let Some(genesis_state) = &*self.genesis_state.read() { - let root = genesis_state.root.clone(); - let db_state = DbState::::new(genesis_state.clone(), root); + let db_state = DbState::::new(genesis_state.clone(), genesis_state.root); let state = RefTrackingState::new(db_state, self.storage.clone(), None); let caching_state = CachingState::new(state, self.shared_cache.clone(), None); let mut state = SyncingCachingState::new( @@ -2218,8 +2211,7 @@ impl sc_client_api::backend::Backend for Backend { if let Ok(()) = self.storage.state_db.pin(&hash) { let root = hdr.state_root; let db_state = DbState::::new(self.storage.clone(), root); - let state = - RefTrackingState::new(db_state, self.storage.clone(), Some(hash.clone())); + let state = RefTrackingState::new(db_state, self.storage.clone(), Some(hash)); let caching_state = CachingState::new(state, self.shared_cache.clone(), Some(hash)); Ok(SyncingCachingState::new( @@ -2241,7 +2233,7 @@ impl sc_client_api::backend::Backend for Backend { fn have_state_at(&self, hash: &Block::Hash, number: NumberFor) -> bool { if self.is_archive { - match self.blockchain.header_metadata(hash.clone()) { + match self.blockchain.header_metadata(*hash) { Ok(header) => sp_state_machine::Storage::get( self.storage.as_ref(), &header.state_root, diff --git a/client/db/src/offchain.rs b/client/db/src/offchain.rs index 4f0a77ce57566..030a410981b26 100644 --- a/client/db/src/offchain.rs +++ b/client/db/src/offchain.rs @@ -104,7 +104,7 @@ impl sp_core::offchain::OffchainStorage for LocalStorage { { drop(key_lock); let key_lock = locks.get_mut(&key); - if let Some(_) = key_lock.and_then(Arc::get_mut) { + if key_lock.and_then(Arc::get_mut).is_some() { locks.remove(&key); } } @@ -114,7 +114,7 @@ impl sp_core::offchain::OffchainStorage for LocalStorage { /// Concatenate the prefix and key to create an offchain key in the db. pub(crate) fn concatenate_prefix_and_key(prefix: &[u8], key: &[u8]) -> Vec { - prefix.iter().chain(key.into_iter()).cloned().collect() + prefix.iter().chain(key.iter()).cloned().collect() } #[cfg(test)] diff --git a/client/db/src/storage_cache.rs b/client/db/src/storage_cache.rs index 5047087376375..9dada92b066ea 100644 --- a/client/db/src/storage_cache.rs +++ b/client/db/src/storage_cache.rs @@ -360,9 +360,9 @@ impl CacheChanges { // Same block comitted twice with different state changes. // Treat it as reenacted/retracted. if is_best { - enacted.push(commit_hash.clone()); + enacted.push(*commit_hash); } else { - retracted.to_mut().push(commit_hash.clone()); + retracted.to_mut().push(*commit_hash); } } } @@ -371,7 +371,7 @@ impl CacheChanges { // Propagate cache only if committing on top of the latest canonical state // blocks are ordered by number and only one block with a given number is marked as // canonical (contributed to canonical state cache) - if let Some(_) = self.parent_hash { + if self.parent_hash.is_some() { let mut local_cache = self.local_cache.write(); if is_best { trace!( @@ -423,9 +423,9 @@ impl CacheChanges { storage: modifications, child_storage: child_modifications, number: *number, - hash: hash.clone(), + hash: *hash, is_canon: is_best, - parent: parent.clone(), + parent: *parent, }; let insert_at = cache .modifications @@ -564,7 +564,7 @@ impl>, B: BlockT> StateBackend> for Cachin let cache = self.cache.shared_cache.upgradable_read(); if Self::is_allowed(Some(key), None, &self.cache.parent_hash, &cache.modifications) { let mut cache = RwLockUpgradableReadGuard::upgrade(cache); - if let Some(entry) = cache.lru_hashes.get(key).map(|a| a.0.clone()) { + if let Some(entry) = cache.lru_hashes.get(key).map(|a| a.0) { trace!("Found hash in shared cache: {:?}", HexDisplay::from(&key)); return Ok(entry) } @@ -934,7 +934,7 @@ impl Drop for SyncingCachingState { let _lock = self.lock.read(); self.state_usage.merge_sm(caching_state.usage.take()); - if let Some(hash) = caching_state.cache.parent_hash.clone() { + if let Some(hash) = caching_state.cache.parent_hash { let is_best = self.meta.read().best_hash == hash; caching_state.cache.sync_cache(&[], &[], vec![], vec![], None, None, is_best); } diff --git a/client/db/src/upgrade.rs b/client/db/src/upgrade.rs index ec91a753ed870..cd18554fb0d06 100644 --- a/client/db/src/upgrade.rs +++ b/client/db/src/upgrade.rs @@ -30,7 +30,7 @@ use kvdb_rocksdb::{Database, DatabaseConfig}; use sp_runtime::traits::Block as BlockT; /// Version file name. -const VERSION_FILE_NAME: &'static str = "db_version"; +const VERSION_FILE_NAME: &str = "db_version"; /// Current db version. const CURRENT_VERSION: u32 = 4; diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index 1798838ecc155..d3cb9a994fdd3 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -201,16 +201,16 @@ fn open_database_at( db_type: DatabaseType, ) -> sp_blockchain::Result>> { let db: Arc> = match &source { - DatabaseSource::ParityDb { path } => open_parity_db::(&path, db_type, true)?, + DatabaseSource::ParityDb { path } => open_parity_db::(path, db_type, true)?, DatabaseSource::RocksDb { path, cache_size } => - open_kvdb_rocksdb::(&path, db_type, true, *cache_size)?, + open_kvdb_rocksdb::(path, db_type, true, *cache_size)?, DatabaseSource::Custom(db) => db.clone(), DatabaseSource::Auto { paritydb_path, rocksdb_path, cache_size } => { // check if rocksdb exists first, if not, open paritydb - match open_kvdb_rocksdb::(&rocksdb_path, db_type, false, *cache_size) { + match open_kvdb_rocksdb::(rocksdb_path, db_type, false, *cache_size) { Ok(db) => db, Err(OpenDbError::NotEnabled(_)) | Err(OpenDbError::DoesNotExist) => - open_parity_db::(&paritydb_path, db_type, true)?, + open_parity_db::(paritydb_path, db_type, true)?, Err(_) => return Err(backend_err("cannot open rocksdb. corrupted database")), } }, @@ -234,7 +234,7 @@ type OpenDbResult = Result>, OpenDbError>; impl fmt::Display for OpenDbError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - OpenDbError::Internal(e) => write!(f, "{}", e.to_string()), + OpenDbError::Internal(e) => write!(f, "{}", e), OpenDbError::DoesNotExist => write!(f, "Database does not exist at given location"), OpenDbError::NotEnabled(feat) => { write!(f, "`{}` feature not enabled, database can not be opened", feat) @@ -300,7 +300,7 @@ fn open_kvdb_rocksdb( cache_size: usize, ) -> OpenDbResult { // first upgrade database to required version - match crate::upgrade::upgrade_db::(&path, db_type) { + match crate::upgrade::upgrade_db::(path, db_type) { // in case of missing version file, assume that database simply does not exist at given // location Ok(_) | Err(crate::upgrade::UpgradeError::MissingDatabaseVersionFile) => (), @@ -363,8 +363,7 @@ pub fn check_database_type( return Err(sp_blockchain::Error::Backend(format!( "Unexpected database type. Expected: {}", db_type.as_str() - )) - .into()) + ))) }, None => { let mut transaction = Transaction::new(); @@ -425,9 +424,9 @@ pub fn read_db( where Block: BlockT, { - block_id_to_lookup_key(db, col_index, id).and_then(|key| match key { - Some(key) => Ok(db.get(col, key.as_ref())), - None => Ok(None), + block_id_to_lookup_key(db, col_index, id).map(|key| match key { + Some(key) => db.get(col, key.as_ref()), + None => None, }) } @@ -442,9 +441,10 @@ pub fn remove_from_db( where Block: BlockT, { - block_id_to_lookup_key(db, col_index, id).and_then(|key| match key { - Some(key) => Ok(transaction.remove(col, key.as_ref())), - None => Ok(()), + block_id_to_lookup_key(db, col_index, id).map(|key| { + if let Some(key) = key { + transaction.remove(col, key.as_ref()); + } }) } @@ -458,7 +458,7 @@ pub fn read_header( match read_db(db, col_index, col, id)? { Some(header) => match Block::Header::decode(&mut &header[..]) { Ok(header) => Ok(Some(header)), - Err(_) => return Err(sp_blockchain::Error::Backend("Error decoding header".into())), + Err(_) => Err(sp_blockchain::Error::Backend("Error decoding header".into())), }, None => Ok(None), } diff --git a/client/executor/common/src/runtime_blob/data_segments_snapshot.rs b/client/executor/common/src/runtime_blob/data_segments_snapshot.rs index b44370e681b13..e65fc32f637a6 100644 --- a/client/executor/common/src/runtime_blob/data_segments_snapshot.rs +++ b/client/executor/common/src/runtime_blob/data_segments_snapshot.rs @@ -39,7 +39,7 @@ impl DataSegmentsSnapshot { .map(|mut segment| { // Just replace contents of the segment since the segments will be discarded later // anyway. - let contents = mem::replace(segment.value_mut(), vec![]); + let contents = mem::take(segment.value_mut()); let init_expr = match segment.offset() { Some(offset) => offset.code(), diff --git a/client/executor/common/src/runtime_blob/runtime_blob.rs b/client/executor/common/src/runtime_blob/runtime_blob.rs index 649ff51f287e1..08df4b32d59eb 100644 --- a/client/executor/common/src/runtime_blob/runtime_blob.rs +++ b/client/executor/common/src/runtime_blob/runtime_blob.rs @@ -187,9 +187,7 @@ impl RuntimeBlob { } /// Returns an iterator of all globals which were exported by [`expose_mutable_globals`]. - pub(super) fn exported_internal_global_names<'module>( - &'module self, - ) -> impl Iterator { + pub(super) fn exported_internal_global_names(&self) -> impl Iterator { let exports = self.raw_module.export_section().map(|es| es.entries()).unwrap_or(&[]); exports.iter().filter_map(|export| match export.internal() { Internal::Global(_) if export.field().starts_with("exported_internal_global") => diff --git a/client/executor/common/src/sandbox.rs b/client/executor/common/src/sandbox.rs index fe14c0865cfde..1e925bd5a7835 100644 --- a/client/executor/common/src/sandbox.rs +++ b/client/executor/common/src/sandbox.rs @@ -264,8 +264,8 @@ fn decode_environment_definition( let memory_ref = memories .get(memory_idx as usize) .cloned() - .ok_or_else(|| InstantiationError::EnvironmentDefinitionCorrupted)? - .ok_or_else(|| InstantiationError::EnvironmentDefinitionCorrupted)?; + .ok_or(InstantiationError::EnvironmentDefinitionCorrupted)? + .ok_or(InstantiationError::EnvironmentDefinitionCorrupted)?; memories_map.insert((module, field), memory_ref); }, } @@ -458,7 +458,7 @@ impl Store

{ }; let mem_idx = memories.len(); - memories.push(Some(memory.clone())); + memories.push(Some(memory)); Ok(mem_idx as u32) } @@ -472,7 +472,7 @@ impl Store
{ pub fn instance(&self, instance_idx: u32) -> Result> { self.instances .get(instance_idx as usize) - .ok_or_else(|| "Trying to access a non-existent instance")? + .ok_or("Trying to access a non-existent instance")? .as_ref() .map(|v| v.0.clone()) .ok_or_else(|| "Trying to access a torndown instance".into()) @@ -488,7 +488,7 @@ impl Store
{ self.instances .get(instance_idx as usize) .as_ref() - .ok_or_else(|| "Trying to access a non-existent instance")? + .ok_or("Trying to access a non-existent instance")? .as_ref() .map(|v| v.1.clone()) .ok_or_else(|| "Trying to access a torndown instance".into()) @@ -504,7 +504,7 @@ impl Store
{ self.memories .get(memory_idx as usize) .cloned() - .ok_or_else(|| "Trying to access a non-existent sandboxed memory")? + .ok_or("Trying to access a non-existent sandboxed memory")? .ok_or_else(|| "Trying to access a torndown sandboxed memory".into()) } @@ -564,7 +564,7 @@ impl Store
{ #[cfg(feature = "wasmer-sandbox")] BackendContext::Wasmer(ref context) => - wasmer_instantiate(&context, wasm, guest_env, state, sandbox_context)?, + wasmer_instantiate(context, wasm, guest_env, state, sandbox_context)?, }; Ok(UnregisteredInstance { sandbox_instance }) diff --git a/client/executor/common/src/sandbox/wasmer_backend.rs b/client/executor/common/src/sandbox/wasmer_backend.rs index ab585c7d15431..29926141ed8b8 100644 --- a/client/executor/common/src/sandbox/wasmer_backend.rs +++ b/client/executor/common/src/sandbox/wasmer_backend.rs @@ -113,7 +113,7 @@ pub fn instantiate( type Exports = HashMap; let mut exports_map = Exports::new(); - for import in module.imports().into_iter() { + for import in module.imports() { match import.ty() { // Nothing to do here wasmer::ExternType::Global(_) | wasmer::ExternType::Table(_) => (), @@ -121,7 +121,7 @@ pub fn instantiate( wasmer::ExternType::Memory(_) => { let exports = exports_map .entry(import.module().to_string()) - .or_insert(wasmer::Exports::new()); + .or_insert_with(wasmer::Exports::new); let memory = guest_env .imports @@ -173,7 +173,7 @@ pub fn instantiate( let exports = exports_map .entry(import.module().to_string()) - .or_insert(wasmer::Exports::new()); + .or_insert_with(wasmer::Exports::new); exports.insert(import.name(), wasmer::Extern::Function(function)); }, diff --git a/client/executor/common/src/sandbox/wasmi_backend.rs b/client/executor/common/src/sandbox/wasmi_backend.rs index 9c7c154b5b135..03fa5dc06dea8 100644 --- a/client/executor/common/src/sandbox/wasmi_backend.rs +++ b/client/executor/common/src/sandbox/wasmi_backend.rs @@ -78,7 +78,7 @@ impl ImportResolver for Imports { // Here we use inner memory reference only to resolve the imports // without accessing the memory contents. All subsequent memory accesses // should happen through the wrapper, that enforces the memory access protocol. - let mem = wrapper.0.clone(); + let mem = wrapper.0; Ok(mem) } @@ -247,7 +247,7 @@ impl<'a> wasmi::Externals for GuestExternals<'a> { serialized_result_val_ptr, "Can't deallocate memory for dispatch thunk's result", ) - .and_then(|_| serialized_result_val) + .and(serialized_result_val) .and_then(|serialized_result_val| { let result_val = std::result::Result::::decode(&mut serialized_result_val.as_slice()) .map_err(|_| trap("Decoding Result failed!"))?; diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 669780f2a4b6a..ea060a89c13df 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -253,7 +253,7 @@ where wasm_code: &[u8], ext: &mut dyn Externalities, ) -> std::result::Result, String> { - let runtime_blob = RuntimeBlob::uncompress_if_needed(&wasm_code) + let runtime_blob = RuntimeBlob::uncompress_if_needed(wasm_code) .map_err(|e| format!("Failed to create runtime blob: {:?}", e))?; if let Some(version) = crate::wasm_runtime::read_embedded_version(&runtime_blob) @@ -493,8 +493,7 @@ impl RuntimeSpawn for RuntimeInstanceSpawn { fn join(&self, handle: u64) -> Vec { let receiver = self.tasks.lock().remove(&handle).expect("No task for the handle"); - let output = receiver.recv().expect("Spawned task panicked for the handle"); - output + receiver.recv().expect("Spawned task panicked for the handle") } } diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 952130e980874..9c07dd7abf1f2 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -368,7 +368,7 @@ pub fn read_embedded_version(blob: &RuntimeBlob) -> Result sandbox::SandboxContext for SandboxContext<'a> { match result { Ok(Some(RuntimeValue::I64(val))) => Ok(val), - Ok(_) => return Err("Supervisor function returned unexpected result!".into()), + Ok(_) => Err("Supervisor function returned unexpected result!".into()), Err(err) => Err(Error::Sandbox(err.to_string())), } } @@ -161,7 +161,7 @@ impl Sandbox for FunctionExecutor { Ok(buffer) => buffer, }; - if let Err(_) = self.memory.set(buf_ptr.into(), &buffer) { + if self.memory.set(buf_ptr.into(), &buffer).is_err() { return Ok(sandbox_env::ERR_OUT_OF_BOUNDS) } @@ -185,7 +185,7 @@ impl Sandbox for FunctionExecutor { Ok(buffer) => buffer, }; - if let Err(_) = sandboxed_memory.write_from(Pointer::new(offset as u32), &buffer) { + if sandboxed_memory.write_from(Pointer::new(offset as u32), &buffer).is_err() { return Ok(sandbox_env::ERR_OUT_OF_BOUNDS) } @@ -241,9 +241,9 @@ impl Sandbox for FunctionExecutor { Ok(None) => Ok(sandbox_env::ERR_OK), Ok(Some(val)) => { // Serialize return value and write it back into the memory. - sp_wasm_interface::ReturnValue::Value(val.into()).using_encoded(|val| { + sp_wasm_interface::ReturnValue::Value(val).using_encoded(|val| { if val.len() > return_val_len as usize { - Err("Return value buffer is too small")?; + return Err("Return value buffer is too small".into()) } self.write_memory(return_val, val).map_err(|_| "Return value buffer is OOB")?; Ok(sandbox_env::ERR_OK) @@ -272,11 +272,11 @@ impl Sandbox for FunctionExecutor { let table = self .table .as_ref() - .ok_or_else(|| "Runtime doesn't have a table; sandbox is unavailable")?; + .ok_or("Runtime doesn't have a table; sandbox is unavailable")?; table .get(dispatch_thunk_id) .map_err(|_| "dispatch_thunk_idx is out of the table bounds")? - .ok_or_else(|| "dispatch_thunk_idx points on an empty table entry")? + .ok_or("dispatch_thunk_idx points on an empty table entry")? }; let guest_env = @@ -458,9 +458,9 @@ impl wasmi::Externals for FunctionExecutor { fn get_mem_instance(module: &ModuleRef) -> Result { Ok(module .export_by_name("memory") - .ok_or_else(|| Error::InvalidMemoryReference)? + .ok_or(Error::InvalidMemoryReference)? .as_memory() - .ok_or_else(|| Error::InvalidMemoryReference)? + .ok_or(Error::InvalidMemoryReference)? .clone()) } @@ -469,9 +469,9 @@ fn get_mem_instance(module: &ModuleRef) -> Result { fn get_heap_base(module: &ModuleRef) -> Result { let heap_base_val = module .export_by_name("__heap_base") - .ok_or_else(|| Error::HeapBaseNotFoundOrInvalid)? + .ok_or(Error::HeapBaseNotFoundOrInvalid)? .as_global() - .ok_or_else(|| Error::HeapBaseNotFoundOrInvalid)? + .ok_or(Error::HeapBaseNotFoundOrInvalid)? .get(); match heap_base_val { @@ -564,7 +564,7 @@ fn call_in_wasm_module( match result { Ok(Some(I64(r))) => { let (ptr, length) = unpack_ptr_and_len(r as u64); - memory.get(ptr.into(), length as usize).map_err(|_| Error::Runtime) + memory.get(ptr, length as usize).map_err(|_| Error::Runtime) }, Err(e) => { trace!( @@ -572,7 +572,7 @@ fn call_in_wasm_module( "Failed to execute code with {} pages", memory.current_size().0, ); - Err(e.into()) + Err(e) }, _ => Err(Error::InvalidReturn), } diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index 376eba86829a7..0cb64820fa8a3 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -243,7 +243,7 @@ impl<'a> Sandbox for HostContext<'a> { // Serialize return value and write it back into the memory. sp_wasm_interface::ReturnValue::Value(val.into()).using_encoded(|val| { if val.len() > return_val_len as usize { - Err("Return value buffer is too small")?; + return Err("Return value buffer is too small".into()) } ::write_memory(self, return_val, val) .map_err(|_| "can't write return value")?; @@ -273,19 +273,18 @@ impl<'a> Sandbox for HostContext<'a> { .caller .data() .table() - .ok_or_else(|| "Runtime doesn't have a table; sandbox is unavailable")?; + .ok_or("Runtime doesn't have a table; sandbox is unavailable")?; let table_item = table.get(&mut self.caller, dispatch_thunk_id); table_item - .ok_or_else(|| "dispatch_thunk_id is out of bounds")? + .ok_or("dispatch_thunk_id is out of bounds")? .funcref() - .ok_or_else(|| "dispatch_thunk_idx should be a funcref")? - .ok_or_else(|| "dispatch_thunk_idx should point to actual func")? + .ok_or("dispatch_thunk_idx should be a funcref")? + .ok_or("dispatch_thunk_idx should point to actual func")? .clone() }; - let guest_env = match sandbox::GuestEnvironment::decode(&self.sandbox_store(), raw_env_def) - { + let guest_env = match sandbox::GuestEnvironment::decode(self.sandbox_store(), raw_env_def) { Ok(guest_env) => guest_env, Err(_) => return Ok(sandbox_env::ERR_MODULE as u32), }; @@ -304,7 +303,7 @@ impl<'a> Sandbox for HostContext<'a> { wasm, guest_env, state, - &mut SandboxContext { host_context: self, dispatch_thunk: dispatch_thunk.clone() }, + &mut SandboxContext { host_context: self, dispatch_thunk }, ) })); @@ -316,7 +315,7 @@ impl<'a> Sandbox for HostContext<'a> { }; let instance_idx_or_err_code = match result { - Ok(instance) => instance.register(&mut self.sandbox_store_mut(), dispatch_thunk), + Ok(instance) => instance.register(self.sandbox_store_mut(), dispatch_thunk), Err(sandbox::InstantiationError::StartTrapped) => sandbox_env::ERR_EXECUTION, Err(_) => sandbox_env::ERR_MODULE, }; @@ -366,7 +365,7 @@ impl<'a, 'b> sandbox::SandboxContext for SandboxContext<'a, 'b> { if let Some(ret_val) = ret_vals[0].i64() { Ok(ret_val) } else { - return Err("Supervisor function returned unexpected result!".into()) + Err("Supervisor function returned unexpected result!".into()) }, Err(err) => Err(err.to_string().into()), } diff --git a/client/finality-grandpa/rpc/src/report.rs b/client/finality-grandpa/rpc/src/report.rs index 24d0b5ab0d1d6..8c04ca28ef870 100644 --- a/client/finality-grandpa/rpc/src/report.rs +++ b/client/finality-grandpa/rpc/src/report.rs @@ -88,10 +88,10 @@ impl RoundState { voters: &HashSet, ) -> Result { let prevotes = &round_state.prevote_ids; - let missing_prevotes = voters.difference(&prevotes).cloned().collect(); + let missing_prevotes = voters.difference(prevotes).cloned().collect(); let precommits = &round_state.precommit_ids; - let missing_precommits = voters.difference(&precommits).cloned().collect(); + let missing_precommits = voters.difference(precommits).cloned().collect(); Ok(Self { round: round.try_into()?, diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 668fe5f269051..c2d44371986ca 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -557,8 +557,7 @@ where fork_tree::FinalizationResult::Changed(change) => { status.changed = true; - let pending_forced_changes = - std::mem::replace(&mut self.pending_forced_changes, Vec::new()); + let pending_forced_changes = std::mem::take(&mut self.pending_forced_changes); // we will keep all forced changes for any later blocks and that are a // descendent of the finalized block (i.e. they are part of this branch). diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/finality-grandpa/src/aux_schema.rs index 0ac9ba9e64bd2..25ed4a3f490e0 100644 --- a/client/finality-grandpa/src/aux_schema.rs +++ b/client/finality-grandpa/src/aux_schema.rs @@ -430,7 +430,7 @@ where // reset. let set_state = VoterSetState::::live( new_set.set_id, - &set, + set, (new_set.canon_hash, new_set.canon_number), ); let encoded = set_state.encode(); diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index c39e2e82a621e..250e640cbf037 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -504,13 +504,13 @@ impl Peers { fn new_peer(&mut self, who: PeerId, role: ObservedRole) { match role { ObservedRole::Authority if self.first_stage_peers.len() < LUCKY_PEERS => { - self.first_stage_peers.insert(who.clone()); + self.first_stage_peers.insert(who); }, ObservedRole::Authority if self.second_stage_peers.len() < LUCKY_PEERS => { - self.second_stage_peers.insert(who.clone()); + self.second_stage_peers.insert(who); }, ObservedRole::Light if self.lucky_light_peers.len() < LUCKY_PEERS => { - self.lucky_light_peers.insert(who.clone()); + self.lucky_light_peers.insert(who); }, _ => {}, } @@ -590,11 +590,8 @@ impl Peers { // - third set: LUCKY_PEERS random light client peers let shuffled_peers = { - let mut peers = self - .inner - .iter() - .map(|(peer_id, info)| (*peer_id, info.clone())) - .collect::>(); + let mut peers = + self.inner.iter().map(|(peer_id, info)| (*peer_id, info)).collect::>(); peers.shuffle(&mut rand::thread_rng()); peers @@ -1103,7 +1100,7 @@ impl Inner { // won't be able to reply since they don't follow the full GRANDPA // protocol and therefore might not have the vote data available. if let (Some(peer), Some(local_view)) = (self.peers.peer(who), &self.local_view) { - if self.catch_up_config.request_allowed(&peer) && + if self.catch_up_config.request_allowed(peer) && peer.view.set_id == local_view.set_id && peer.view.round.0.saturating_sub(CATCH_UP_THRESHOLD) > local_view.round.0 { @@ -1195,7 +1192,7 @@ impl Inner { return (false, None) } else { // report peer for timeout - Some((peer.clone(), cost::CATCH_UP_REQUEST_TIMEOUT)) + Some((*peer, cost::CATCH_UP_REQUEST_TIMEOUT)) } }, PendingCatchUp::Processing { instant, .. } => { @@ -1209,7 +1206,7 @@ impl Inner { }; self.pending_catch_up = PendingCatchUp::Requesting { - who: who.clone(), + who: *who, request: catch_up_request.clone(), instant: Instant::now(), }; @@ -1488,7 +1485,7 @@ impl sc_network_gossip::Validator for GossipValidator sc_network_gossip::Validator for GossipValidator { - self.report(who.clone(), cb); + self.report(*who, cb); context.broadcast_message(topic, data.to_vec(), false); sc_network_gossip::ValidationResult::ProcessAndKeep(topic) }, Action::ProcessAndDiscard(topic, cb) => { - self.report(who.clone(), cb); + self.report(*who, cb); sc_network_gossip::ValidationResult::ProcessAndDiscard(topic) }, Action::Discard(cb) => { - self.report(who.clone(), cb); + self.report(*who, cb); sc_network_gossip::ValidationResult::Discard }, } @@ -1572,7 +1569,7 @@ impl sc_network_gossip::Validator for GossipValidator return false, Some(x) => x, }; @@ -1583,11 +1580,9 @@ impl sc_network_gossip::Validator for GossipValidator( let mut total_weight = 0; for id in votes { - if let Some(weight) = voters.get(&id).map(|info| info.weight()) { + if let Some(weight) = voters.get(id).map(|info| info.weight()) { total_weight += weight.get(); if total_weight > full_threshold { return Err(cost::MALFORMED_CATCH_UP) diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 6ffcdc719a166..63c8697053842 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -451,7 +451,7 @@ impl, SC, VR> Environment) -> Result>, Error>, { self.voter_set_state.with(|voter_set_state| { - if let Some(set_state) = f(&voter_set_state)? { + if let Some(set_state) = f(voter_set_state)? { *voter_set_state = set_state; if let Some(metrics) = self.metrics.as_ref() { @@ -987,11 +987,9 @@ where let mut current_rounds = current_rounds.clone(); current_rounds.remove(&round); - // NOTE: this condition should always hold as GRANDPA rounds are always + // NOTE: this entry should always exist as GRANDPA rounds are always // started in increasing order, still it's better to play it safe. - if !current_rounds.contains_key(&(round + 1)) { - current_rounds.insert(round + 1, HasVoted::No); - } + current_rounds.entry(round + 1).or_insert(HasVoted::No); let set_state = VoterSetState::::Live { completed_rounds, current_rounds }; @@ -1046,7 +1044,7 @@ where .votes .extend(historical_votes.seen().iter().skip(n_existing_votes).cloned()); already_completed.state = state; - crate::aux_schema::write_concluded_round(&*self.client, &already_completed)?; + crate::aux_schema::write_concluded_round(&*self.client, already_completed)?; } let set_state = VoterSetState::::Live { diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index ae5839d0c24e6..eefb3d3f0aee4 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -439,8 +439,7 @@ where // This code may be removed once warp sync to an old runtime is no longer needed. for prefix in ["GrandpaFinality", "Grandpa"] { let k = [twox_128(prefix.as_bytes()), twox_128(b"CurrentSetId")].concat(); - if let Ok(Some(id)) = - self.inner.storage(&id, &sc_client_api::StorageKey(k.to_vec())) + if let Ok(Some(id)) = self.inner.storage(id, &sc_client_api::StorageKey(k.to_vec())) { if let Ok(id) = SetId::decode(&mut id.0.as_ref()) { return Ok(id) @@ -451,7 +450,7 @@ where } else { self.inner .runtime_api() - .current_set_id(&id) + .current_set_id(id) .map_err(|e| ConsensusError::ClientImport(e.to_string())) } } @@ -732,7 +731,7 @@ impl GrandpaBlockImport Result, GrandpaError> { - environment::ancestry(&self.client, base, block) + environment::ancestry(self.client, base, block) } } @@ -193,13 +193,13 @@ where ); let observer_work = ObserverWork::new( - client.clone(), + client, network, persistent_data, config.keystore, voter_commands_rx, Some(justification_sender), - telemetry.clone(), + telemetry, ); let observer_work = observer_work.map_ok(|_| ()).map_err(|e| { diff --git a/client/finality-grandpa/src/voting_rule.rs b/client/finality-grandpa/src/voting_rule.rs index 749c504a051c1..209b0f1b33ced 100644 --- a/client/finality-grandpa/src/voting_rule.rs +++ b/client/finality-grandpa/src/voting_rule.rs @@ -125,7 +125,7 @@ where let current_target = current_target.clone(); // find the block at the given target height - Box::pin(std::future::ready(find_target(&*backend, target_number.clone(), ¤t_target))) + Box::pin(std::future::ready(find_target(&*backend, target_number, ¤t_target))) } } diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index bdb8e36373de3..90f6828a1105d 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -205,7 +205,7 @@ impl WarpSyncProof { let hash = proof.header.hash(); let number = *proof.header.number(); - if let Some((set_id, list)) = hard_forks.get(&(hash.clone(), number)) { + if let Some((set_id, list)) = hard_forks.get(&(hash, number)) { current_set_id = *set_id; current_authorities = list.clone(); } else { diff --git a/client/informant/src/lib.rs b/client/informant/src/lib.rs index 88a500a3a98fa..5dca77f1a7433 100644 --- a/client/informant/src/lib.rs +++ b/client/informant/src/lib.rs @@ -116,7 +116,7 @@ where if let Some((ref last_num, ref last_hash)) = last_best { if n.header.parent_hash() != last_hash && n.is_new_best { let maybe_ancestor = - sp_blockchain::lowest_common_ancestor(&*client, last_hash.clone(), n.hash); + sp_blockchain::lowest_common_ancestor(&*client, *last_hash, n.hash); match maybe_ancestor { Ok(ref ancestor) if ancestor.hash != *last_hash => info!( @@ -135,13 +135,13 @@ where } if n.is_new_best { - last_best = Some((n.header.number().clone(), n.hash.clone())); + last_best = Some((*n.header.number(), n.hash)); } // If we already printed a message for a given block recently, // we should not print it again. if !last_blocks.contains(&n.hash) { - last_blocks.push_back(n.hash.clone()); + last_blocks.push_back(n.hash); if last_blocks.len() > max_blocks_to_track { last_blocks.pop_front(); diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 9f6f18d0c2930..19be6715ffe3f 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -198,7 +198,7 @@ impl SyncCryptoStore for LocalKeystore { .0 .read() .key_pair_by_type::(&pub_key, id) - .map_err(|e| TraitError::from(e))?; + .map_err(TraitError::from)?; key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose() }, sr25519::CRYPTO_ID => { @@ -209,7 +209,7 @@ impl SyncCryptoStore for LocalKeystore { .0 .read() .key_pair_by_type::(&pub_key, id) - .map_err(|e| TraitError::from(e))?; + .map_err(TraitError::from)?; key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose() }, ecdsa::CRYPTO_ID => { @@ -220,7 +220,7 @@ impl SyncCryptoStore for LocalKeystore { .0 .read() .key_pair_by_type::(&pub_key, id) - .map_err(|e| TraitError::from(e))?; + .map_err(TraitError::from)?; key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose() }, _ => Err(TraitError::KeyNotSupported(id)), @@ -320,7 +320,7 @@ impl SyncCryptoStore for LocalKeystore { fn has_keys(&self, public_keys: &[(Vec, KeyTypeId)]) -> bool { public_keys .iter() - .all(|(p, t)| self.0.read().key_phrase_by_type(&p, *t).ok().flatten().is_some()) + .all(|(p, t)| self.0.read().key_phrase_by_type(p, *t).ok().flatten().is_some()) } fn sr25519_vrf_sign( @@ -536,7 +536,7 @@ impl KeystoreInner { if let Some(name) = path.file_name().and_then(|n| n.to_str()) { match hex::decode(name) { Ok(ref hex) if hex.len() > 4 => { - if &hex[0..4] != &id.0 { + if hex[0..4] != id.0 { continue } let public = hex[4..].to_vec(); diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 4f06819df64d1..8a016cbaab3da 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -88,8 +88,7 @@ impl<'g, 'p, B: BlockT> ValidatorContext for NetworkContext<'g, 'p, B> { /// Send addressed message to a peer. fn send_message(&mut self, who: &PeerId, message: Vec) { - self.network - .write_notification(who.clone(), self.gossip.protocol.clone(), message); + self.network.write_notification(*who, self.gossip.protocol.clone(), message); } /// Send all messages with given topic to a peer. @@ -116,13 +115,13 @@ where for (message_hash, topic, message) in messages.clone() { let intent = match intent { MessageIntent::Broadcast { .. } => - if peer.known_messages.contains(&message_hash) { + if peer.known_messages.contains(message_hash) { continue } else { MessageIntent::Broadcast }, MessageIntent::PeriodicRebroadcast => { - if peer.known_messages.contains(&message_hash) { + if peer.known_messages.contains(message_hash) { MessageIntent::PeriodicRebroadcast } else { // peer doesn't know message, so the logic should treat it as an @@ -133,11 +132,11 @@ where other => other, }; - if !message_allowed(id, intent, &topic, &message) { + if !message_allowed(id, intent, topic, message) { continue } - peer.known_messages.insert(message_hash.clone()); + peer.known_messages.insert(*message_hash); tracing::trace!( target: "gossip", @@ -146,7 +145,7 @@ where ?message, "Propagating message", ); - network.write_notification(id.clone(), protocol.clone(), message.clone()); + network.write_notification(*id, protocol.clone(), message.clone()); } } } @@ -198,8 +197,7 @@ impl ConsensusGossip { ?role, "Registering peer", ); - self.peers - .insert(who.clone(), PeerConsensus { known_messages: Default::default() }); + self.peers.insert(who, PeerConsensus { known_messages: Default::default() }); let validator = self.validator.clone(); let mut context = NetworkContext { gossip: self, network }; @@ -213,7 +211,7 @@ impl ConsensusGossip { message: Vec, sender: Option, ) { - if self.known_messages.put(message_hash.clone(), ()).is_none() { + if self.known_messages.put(message_hash, ()).is_none() { self.messages.push(MessageEntry { message_hash, topic, message, sender }); if let Some(ref metrics) = self.metrics { @@ -319,10 +317,7 @@ impl ConsensusGossip { self.messages .iter() .filter(move |e| e.topic == topic) - .map(|entry| TopicNotification { - message: entry.message.clone(), - sender: entry.sender.clone(), - }) + .map(|entry| TopicNotification { message: entry.message.clone(), sender: entry.sender }) } /// Register incoming messages and return the ones that are new and valid (according to a gossip @@ -355,7 +350,7 @@ impl ConsensusGossip { protocol = %self.protocol, "Ignored already known message", ); - network.report_peer(who.clone(), rep::DUPLICATE_GOSSIP); + network.report_peer(who, rep::DUPLICATE_GOSSIP); continue } @@ -393,15 +388,13 @@ impl ConsensusGossip { }, }; - network.report_peer(who.clone(), rep::GOSSIP_SUCCESS); + network.report_peer(who, rep::GOSSIP_SUCCESS); peer.known_messages.insert(message_hash); - to_forward.push(( - topic, - TopicNotification { message: message.clone(), sender: Some(who.clone()) }, - )); + to_forward + .push((topic, TopicNotification { message: message.clone(), sender: Some(who) })); if keep { - self.register_message_hashed(message_hash, topic, message, Some(who.clone())); + self.register_message_hashed(message_hash, topic, message, Some(who)); } } @@ -431,7 +424,7 @@ impl ConsensusGossip { continue } - peer.known_messages.insert(entry.message_hash.clone()); + peer.known_messages.insert(entry.message_hash); tracing::trace!( target: "gossip", @@ -440,11 +433,7 @@ impl ConsensusGossip { ?entry.message, "Sending topic message", ); - network.write_notification( - who.clone(), - self.protocol.clone(), - entry.message.clone(), - ); + network.write_notification(*who, self.protocol.clone(), entry.message.clone()); } } } @@ -489,7 +478,7 @@ impl ConsensusGossip { ); peer.known_messages.insert(message_hash); - network.write_notification(who.clone(), self.protocol.clone(), message); + network.write_notification(*who, self.protocol.clone(), message); } } diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 5ff3ba1ad44f4..b0bf3d6a1c135 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -434,7 +434,6 @@ where "Trying to send warp sync request when no protocol is configured {:?}", request, ); - return }, }, CustomMessageOutcome::NotificationStreamOpened { @@ -449,7 +448,7 @@ where protocol, negotiated_fallback, role: reported_roles_to_observed_role(roles), - notifications_sink: notifications_sink.clone(), + notifications_sink, }); }, CustomMessageOutcome::NotificationStreamReplaced { diff --git a/client/network/src/bitswap.rs b/client/network/src/bitswap.rs index c46990997ca05..d5039faaca113 100644 --- a/client/network/src/bitswap.rs +++ b/client/network/src/bitswap.rs @@ -65,7 +65,7 @@ const MAX_RESPONSE_QUEUE: usize = 20; // Max number of blocks per wantlist const MAX_WANTED_BLOCKS: usize = 16; -const PROTOCOL_NAME: &'static [u8] = b"/ipfs/bitswap/1.2.0"; +const PROTOCOL_NAME: &[u8] = b"/ipfs/bitswap/1.2.0"; type FutureResult = Pin> + Send>>; @@ -167,10 +167,10 @@ impl Prefix { let version = varint_encode::u64(self.version.into(), &mut buf); res.extend_from_slice(version); let mut buf = varint_encode::u64_buffer(); - let codec = varint_encode::u64(self.codec.into(), &mut buf); + let codec = varint_encode::u64(self.codec, &mut buf); res.extend_from_slice(codec); let mut buf = varint_encode::u64_buffer(); - let mh_type = varint_encode::u64(self.mh_type.into(), &mut buf); + let mh_type = varint_encode::u64(self.mh_type, &mut buf); res.extend_from_slice(mh_type); let mut buf = varint_encode::u64_buffer(); let mh_len = varint_encode::u64(self.mh_len as u64, &mut buf); diff --git a/client/network/src/block_request_handler.rs b/client/network/src/block_request_handler.rs index 2e238c01636d5..7458f421af397 100644 --- a/client/network/src/block_request_handler.rs +++ b/client/network/src/block_request_handler.rs @@ -197,7 +197,7 @@ where peer: *peer, max_blocks, direction, - from: from_block_id.clone(), + from: from_block_id, attributes, support_multiple_justifications, }; diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index a916ffda0794d..ae65d4f23cec7 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -287,7 +287,7 @@ impl DiscoveryBehaviour { for b in k.kbuckets() { for e in b.iter() { if !peers.contains(e.node.key.preimage()) { - peers.insert(e.node.key.preimage().clone()); + peers.insert(*e.node.key.preimage()); } } } @@ -307,7 +307,7 @@ impl DiscoveryBehaviour { k.add_address(&peer_id, addr.clone()); } - self.pending_events.push_back(DiscoveryOut::Discovered(peer_id.clone())); + self.pending_events.push_back(DiscoveryOut::Discovered(peer_id)); addrs_list.push(addr); } } @@ -718,7 +718,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { // Poll the stream that fires when we need to start a random Kademlia query. if let Some(next_kad_random_query) = self.next_kad_random_query.as_mut() { - while let Poll::Ready(_) = next_kad_random_query.poll_unpin(cx) { + while next_kad_random_query.poll_unpin(cx).is_ready() { let actually_started = if self.num_connections < self.discovery_only_if_under_num { let random_peer_id = PeerId::random(); debug!( @@ -815,7 +815,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { DiscoveryOut::ValueFound( results, - stats.duration().unwrap_or_else(Default::default), + stats.duration().unwrap_or_default(), ) }, Err(e @ libp2p::kad::GetRecordError::NotFound { .. }) => { @@ -826,7 +826,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { ); DiscoveryOut::ValueNotFound( e.into_key(), - stats.duration().unwrap_or_else(Default::default), + stats.duration().unwrap_or_default(), ) }, Err(e) => { @@ -837,7 +837,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { ); DiscoveryOut::ValueNotFound( e.into_key(), - stats.duration().unwrap_or_else(Default::default), + stats.duration().unwrap_or_default(), ) }, }; @@ -851,7 +851,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { let ev = match res { Ok(ok) => DiscoveryOut::ValuePut( ok.key, - stats.duration().unwrap_or_else(Default::default), + stats.duration().unwrap_or_default(), ), Err(e) => { debug!( @@ -861,7 +861,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { ); DiscoveryOut::ValuePutFailed( e.into_key(), - stats.duration().unwrap_or_else(Default::default), + stats.duration().unwrap_or_default(), ) }, }; diff --git a/client/network/src/light_client_requests.rs b/client/network/src/light_client_requests.rs index c77416003f821..d36158b2a373a 100644 --- a/client/network/src/light_client_requests.rs +++ b/client/network/src/light_client_requests.rs @@ -27,11 +27,7 @@ use std::time::Duration; /// Generate the light client protocol name from chain specific protocol identifier. fn generate_protocol_name(protocol_id: &ProtocolId) -> String { - let mut s = String::new(); - s.push_str("/"); - s.push_str(protocol_id.as_ref()); - s.push_str("/light/2"); - s + format!("/{}/light/2", protocol_id.as_ref()) } /// Generates a [`ProtocolConfig`] for the light client request protocol, refusing incoming diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 9999d278a249c..7214e60172aaa 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -391,13 +391,8 @@ where sc_peerset::Peerset::from_config(sc_peerset::PeersetConfig { sets }) }; - let block_announces_protocol: Cow<'static, str> = Cow::from({ - let mut proto = String::new(); - proto.push_str("/"); - proto.push_str(protocol_id.as_ref()); - proto.push_str("/block-announces/1"); - proto - }); + let block_announces_protocol: Cow<'static, str> = + format!("/{}/block-announces/1", protocol_id.as_ref()).into(); let behaviour = { let best_number = info.best_number; @@ -952,7 +947,7 @@ where }, }; - peer.known_blocks.insert(hash.clone()); + peer.known_blocks.insert(hash); let is_best = match announce.state.unwrap_or(message::BlockState::Best) { message::BlockState::Best => true, @@ -1062,7 +1057,7 @@ where /// Uses `protocol` to queue a new justification request and tries to dispatch all pending /// requests. pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { - self.sync.request_justification(&hash, number) + self.sync.request_justification(hash, number) } /// Clear all pending justification requests. @@ -1479,7 +1474,7 @@ where }, }; - finished_block_requests.push((id.clone(), req, protobuf_response)); + finished_block_requests.push((*id, req, protobuf_response)); }, PeerRequest::State => { let protobuf_response = @@ -1576,7 +1571,7 @@ where } for (id, request) in self.sync.block_requests() { - let event = prepare_block_request(&mut self.peers, id.clone(), request); + let event = prepare_block_request(&mut self.peers, *id, request); self.pending_messages.push_back(event); } if let Some((id, request)) = self.sync.state_request() { @@ -1727,9 +1722,9 @@ where } }, NotificationsOut::CustomProtocolReplaced { peer_id, notifications_sink, set_id } => - if set_id == HARDCODED_PEERSETS_SYNC { - CustomMessageOutcome::None - } else if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { + if set_id == HARDCODED_PEERSETS_SYNC || + self.bad_handshake_substreams.contains(&(peer_id, set_id)) + { CustomMessageOutcome::None } else { CustomMessageOutcome::NotificationStreamReplaced { diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index 3fb57b1c824a9..f173fff8503a5 100644 --- a/client/network/src/protocol/message.rs +++ b/client/network/src/protocol/message.rs @@ -154,7 +154,7 @@ impl generic::BlockAnnounce { AnnouncementSummary { block_hash: self.header.hash(), number: *self.header.number(), - parent_hash: self.header.parent_hash().clone(), + parent_hash: *self.header.parent_hash(), state: self.state, } } diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 61f7db78c98b1..1f872ec857e79 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -402,7 +402,7 @@ impl Notifications { } /// Returns the list of all the peers we have an open channel to. - pub fn open_peers<'a>(&'a self) -> impl Iterator + 'a { + pub fn open_peers(&self) -> impl Iterator { self.peers.iter().filter(|(_, state)| state.is_open()).map(|((id, _), _)| id) } @@ -551,10 +551,7 @@ impl Notifications { } /// Returns the list of reserved peers. - pub fn reserved_peers<'a>( - &'a self, - set_id: sc_peerset::SetId, - ) -> impl Iterator + 'a { + pub fn reserved_peers(&self, set_id: sc_peerset::SetId) -> impl Iterator { self.peerset.reserved_peers(set_id) } @@ -621,7 +618,7 @@ impl Notifications { ); trace!(target: "sub-libp2p", "Libp2p <= Dial {}", entry.key().0); self.events.push_back(NetworkBehaviourAction::Dial { - opts: entry.key().0.clone().into(), + opts: entry.key().0.into(), handler, }); entry.insert(PeerState::Requested); @@ -634,7 +631,7 @@ impl Notifications { match mem::replace(occ_entry.get_mut(), PeerState::Poisoned) { // Backoff (not expired) => PendingRequest PeerState::Backoff { ref timer, ref timer_deadline } if *timer_deadline > now => { - let peer_id = occ_entry.key().0.clone(); + let peer_id = occ_entry.key().0; trace!( target: "sub-libp2p", "PSM => Connect({}, {:?}): Will start to connect at until {:?}", @@ -656,7 +653,7 @@ impl Notifications { ); trace!(target: "sub-libp2p", "Libp2p <= Dial {:?}", occ_entry.key()); self.events.push_back(NetworkBehaviourAction::Dial { - opts: occ_entry.key().0.clone().into(), + opts: occ_entry.key().0.into(), handler, }); *occ_entry.into_mut() = PeerState::Requested; @@ -666,7 +663,7 @@ impl Notifications { PeerState::Disabled { connections, backoff_until: Some(ref backoff) } if *backoff > now => { - let peer_id = occ_entry.key().0.clone(); + let peer_id = occ_entry.key().0; trace!( target: "sub-libp2p", "PSM => Connect({}, {:?}): But peer is backed-off until {:?}", @@ -781,7 +778,7 @@ impl Notifications { trace!(target: "sub-libp2p", "Handler({:?}, {:?}) <= Open({:?})", occ_entry.key(), *connec_id, set_id); self.events.push_back(NetworkBehaviourAction::NotifyHandler { - peer_id: occ_entry.key().0.clone(), + peer_id: occ_entry.key().0, handler: NotifyHandler::One(*connec_id), event: NotifsHandlerIn::Open { protocol_index: set_id.into() }, }); @@ -861,10 +858,8 @@ impl Notifications { if connections.iter().any(|(_, s)| matches!(s, ConnectionState::Open(_))) { trace!(target: "sub-libp2p", "External API <= Closed({}, {:?})", entry.key().0, set_id); - let event = NotificationsOut::CustomProtocolClosed { - peer_id: entry.key().0.clone(), - set_id, - }; + let event = + NotificationsOut::CustomProtocolClosed { peer_id: entry.key().0, set_id }; self.events.push_back(NetworkBehaviourAction::GenerateEvent(event)); } @@ -874,7 +869,7 @@ impl Notifications { trace!(target: "sub-libp2p", "Handler({:?}, {:?}) <= Close({:?})", entry.key(), *connec_id, set_id); self.events.push_back(NetworkBehaviourAction::NotifyHandler { - peer_id: entry.key().0.clone(), + peer_id: entry.key().0, handler: NotifyHandler::One(*connec_id), event: NotifsHandlerIn::Close { protocol_index: set_id.into() }, }); @@ -887,7 +882,7 @@ impl Notifications { trace!(target: "sub-libp2p", "Handler({:?}, {:?}) <= Close({:?})", entry.key(), *connec_id, set_id); self.events.push_back(NetworkBehaviourAction::NotifyHandler { - peer_id: entry.key().0.clone(), + peer_id: entry.key().0, handler: NotifyHandler::One(*connec_id), event: NotifsHandlerIn::Close { protocol_index: set_id.into() }, }); @@ -1406,7 +1401,7 @@ impl NetworkBehaviour for Notifications { trace!(target: "sub-libp2p", "Libp2p => Dial failure for {:?}", peer_id); for set_id in (0..self.notif_protocols.len()).map(sc_peerset::SetId::from) { - if let Entry::Occupied(mut entry) = self.peers.entry((peer_id.clone(), set_id)) { + if let Entry::Occupied(mut entry) = self.peers.entry((peer_id, set_id)) { match mem::replace(entry.get_mut(), PeerState::Poisoned) { // The peer is not in our list. st @ PeerState::Backoff { .. } => { @@ -1646,7 +1641,6 @@ impl NetworkBehaviour for Notifications { "OpenDesiredByRemote: Unexpected state in the custom protos handler: {:?}", state); debug_assert!(false); - return }, }; }, @@ -1742,13 +1736,11 @@ impl NetworkBehaviour for Notifications { state @ PeerState::Disabled { .. } | state @ PeerState::DisabledPendingEnable { .. } => { *entry.into_mut() = state; - return }, state => { error!(target: "sub-libp2p", "Unexpected state in the custom protos handler: {:?}", state); - return }, } }, @@ -1853,7 +1845,6 @@ impl NetworkBehaviour for Notifications { "OpenResultOk: Unexpected state in the custom protos handler: {:?}", state); debug_assert!(false); - return }, } }, @@ -2052,9 +2043,7 @@ impl NetworkBehaviour for Notifications { event: NotifsHandlerIn::Open { protocol_index: set_id.into() }, }); *connec_state = ConnectionState::Opening; - *peer_state = PeerState::Enabled { - connections: mem::replace(connections, Default::default()), - }; + *peer_state = PeerState::Enabled { connections: mem::take(connections) }; } else { *timer_deadline = Instant::now() + Duration::from_secs(5); let delay = futures_timer::Delay::new(Duration::from_secs(5)); diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index 510f72d4b0123..c1602319d0ac4 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -400,7 +400,7 @@ impl NotificationsSink { /// error to send a notification using an unknown protocol. /// /// This method will be removed in a future version. - pub fn send_sync_notification<'a>(&'a self, message: impl Into>) { + pub fn send_sync_notification(&self, message: impl Into>) { let mut lock = self.inner.sync_channel.lock(); if let Some(tx) = lock.as_mut() { @@ -425,7 +425,7 @@ impl NotificationsSink { /// /// The protocol name is expected to be checked ahead of calling this method. It is a logic /// error to send a notification using an unknown protocol. - pub async fn reserve_notification<'a>(&'a self) -> Result, ()> { + pub async fn reserve_notification(&self) -> Result, ()> { let mut lock = self.inner.async_channel.lock().await; let poll_ready = future::poll_fn(|cx| lock.poll_ready(cx)).await; diff --git a/client/network/src/protocol/sync.rs b/client/network/src/protocol/sync.rs index 7e6a2a3c78508..fb89e12a44fe8 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/src/protocol/sync.rs @@ -672,7 +672,7 @@ where self.best_queued_number ); self.peers.insert( - who.clone(), + who, PeerSync { peer_id: who, common_number: self.best_queued_number, @@ -796,7 +796,7 @@ where .iter() // Only request blocks from peers who are ahead or on a par. .filter(|(_, peer)| peer.best_number >= number) - .map(|(id, _)| id.clone()) + .map(|(id, _)| *id) .collect(); debug!( @@ -809,7 +809,7 @@ where debug!(target: "sync", "Explicit sync request for block {:?} with {:?}", hash, peers); } - if self.is_known(&hash) { + if self.is_known(hash) { debug!(target: "sync", "Refusing to sync known hash {:?}", hash); return } @@ -843,7 +843,7 @@ where let peers = &mut self.peers; let mut matcher = self.extra_justifications.matcher(); std::iter::from_fn(move || { - if let Some((peer, request)) = matcher.next(&peers) { + if let Some((peer, request)) = matcher.next(peers) { peers .get_mut(&peer) .expect( @@ -1087,7 +1087,7 @@ where if let Some(start_block) = validate_blocks::(&blocks, who, Some(request))? { - self.blocks.insert(start_block, blocks, who.clone()); + self.blocks.insert(start_block, blocks, *who); } self.drain_blocks() }, @@ -1098,7 +1098,7 @@ where if let Some(start_block) = validate_blocks::(&blocks, who, Some(request))? { - gap_sync.blocks.insert(start_block, blocks, who.clone()); + gap_sync.blocks.insert(start_block, blocks, *who); } gap = true; let blocks: Vec<_> = gap_sync @@ -1106,11 +1106,12 @@ where .drain(gap_sync.best_queued_number + One::one()) .into_iter() .map(|block_data| { - let justifications = block_data.block.justifications.or( - legacy_justification_mapping( - block_data.block.justification, - ), - ); + let justifications = + block_data.block.justifications.or_else(|| { + legacy_justification_mapping( + block_data.block.justification, + ) + }); IncomingBlock { hash: block_data.block.hash, header: block_data.block.header, @@ -1129,7 +1130,7 @@ where blocks } else { debug!(target: "sync", "Unexpected gap block response from {}", who); - return Err(BadPeer(who.clone(), rep::NO_BLOCK)) + return Err(BadPeer(*who, rep::NO_BLOCK)) } }, PeerSyncState::DownloadingStale(_) => { @@ -1144,7 +1145,7 @@ where .map(|b| { let justifications = b .justifications - .or(legacy_justification_mapping(b.justification)); + .or_else(|| legacy_justification_mapping(b.justification)); IncomingBlock { hash: b.hash, header: b.header, @@ -1261,8 +1262,9 @@ where blocks .into_iter() .map(|b| { - let justifications = - b.justifications.or(legacy_justification_mapping(b.justification)); + let justifications = b + .justifications + .or_else(|| legacy_justification_mapping(b.justification)); IncomingBlock { hash: b.hash, header: b.header, @@ -1294,7 +1296,7 @@ where who: &PeerId, response: StateResponse, ) -> Result, BadPeer> { - if let Some(peer) = self.peers.get_mut(&who) { + if let Some(peer) = self.peers.get_mut(who) { if let PeerSyncState::DownloadingState = peer.state { peer.state = PeerSyncState::Available; self.allowed_requests.set_all(); @@ -1357,7 +1359,7 @@ where who: &PeerId, response: warp::EncodedProof, ) -> Result<(), BadPeer> { - if let Some(peer) = self.peers.get_mut(&who) { + if let Some(peer) = self.peers.get_mut(who) { if let PeerSyncState::DownloadingWarpProof = peer.state { peer.state = PeerSyncState::Available; self.allowed_requests.set_all(); @@ -1458,7 +1460,9 @@ where return Err(BadPeer(who, rep::BAD_JUSTIFICATION)) } - block.justifications.or(legacy_justification_mapping(block.justification)) + block + .justifications + .or_else(|| legacy_justification_mapping(block.justification)) } else { // we might have asked the peer for a justification on a block that we assumed it // had but didn't (regardless of whether it had a justification for it or not). @@ -1488,19 +1492,19 @@ where /// queue, with or without errors. /// /// `peer_info` is passed in case of a restart. - pub fn on_blocks_processed<'a>( - &'a mut self, + pub fn on_blocks_processed( + &mut self, imported: usize, count: usize, results: Vec<(Result>, BlockImportError>, B::Hash)>, - ) -> impl Iterator), BadPeer>> + 'a { + ) -> impl Iterator), BadPeer>> { trace!(target: "sync", "Imported {} of {}", imported, count); let mut output = Vec::new(); let mut has_error = false; for (_, hash) in &results { - self.queue_blocks.remove(&hash); + self.queue_blocks.remove(hash); } for (result, hash) in results { if has_error { @@ -1659,7 +1663,7 @@ where heads.sort(); let median = heads[heads.len() / 2]; if number + STATE_SYNC_FINALITY_THRESHOLD.saturated_into() >= median { - if let Ok(Some(header)) = self.client.header(BlockId::hash(hash.clone())) { + if let Ok(Some(header)) = self.client.header(BlockId::hash(*hash)) { log::debug!( target: "sync", "Starting state sync for #{} ({})", @@ -1688,7 +1692,7 @@ where /// Updates our internal state for best queued block and then goes /// through all peers to update our view of their state as well. fn on_block_queued(&mut self, hash: &B::Hash, number: NumberFor) { - if self.fork_targets.remove(&hash).is_some() { + if self.fork_targets.remove(hash).is_some() { trace!(target: "sync", "Completed fork sync {:?}", hash); } if let Some(gap_sync) = &mut self.gap_sync { @@ -1741,7 +1745,7 @@ where return HasSlotForBlockAnnounceValidation::TotalMaximumSlotsReached } - match self.block_announce_validation_per_peer_stats.entry(peer.clone()) { + match self.block_announce_validation_per_peer_stats.entry(*peer) { Entry::Vacant(entry) => { entry.insert(1); HasSlotForBlockAnnounceValidation::Yes @@ -1830,8 +1834,7 @@ where // Let external validator check the block announcement. let assoc_data = announce.data.as_ref().map_or(&[][..], |v| v.as_slice()); - let future = self.block_announce_validator.validate(&header, assoc_data); - let hash = hash.clone(); + let future = self.block_announce_validator.validate(header, assoc_data); self.block_announce_validation.push( async move { @@ -1900,7 +1903,7 @@ where PreValidateBlockAnnounce::Skip => return, }; - match self.block_announce_validation_per_peer_stats.entry(peer.clone()) { + match self.block_announce_validation_per_peer_stats.entry(*peer) { Entry::Vacant(_) => { error!( target: "sync", @@ -1994,7 +1997,7 @@ where if known || self.is_already_downloading(&hash) { trace!(target: "sync", "Known block announce from {}: {}", who, hash); if let Some(target) = self.fork_targets.get_mut(&hash) { - target.peers.insert(who.clone()); + target.peers.insert(who); } return PollBlockAnnounceValidation::Nothing { is_best, who, announce } } @@ -2070,9 +2073,7 @@ where /// Restart the sync process. This will reset all pending block requests and return an iterator /// of new block requests to make to peers. Peers that were downloading finality data (i.e. /// their state was `DownloadingJustification`) are unaffected and will stay in the same state. - fn restart<'a>( - &'a mut self, - ) -> impl Iterator), BadPeer>> + 'a { + fn restart(&mut self) -> impl Iterator), BadPeer>> + '_ { self.blocks.clear(); if let Err(e) = self.reset_sync_start_point() { warn!(target: "sync", "💔 Unable to restart sync: {}", e); @@ -2084,18 +2085,15 @@ where old_peers.into_iter().filter_map(move |(id, mut p)| { // peers that were downloading justifications // should be kept in that state. - match p.state { - PeerSyncState::DownloadingJustification(_) => { - // We make sure our commmon number is at least something we have. - p.common_number = self.best_queued_number; - self.peers.insert(id, p); - return None - }, - _ => {}, + if let PeerSyncState::DownloadingJustification(_) = p.state { + // We make sure our commmon number is at least something we have. + p.common_number = self.best_queued_number; + self.peers.insert(id, p); + return None } // handle peers that were in other states. - match self.new_peer(id.clone(), p.best_hash, p.best_number) { + match self.new_peer(id, p.best_hash, p.best_number) { Ok(None) => None, Ok(Some(x)) => Some(Ok((id, x))), Err(e) => Some(Err(e)), @@ -2124,23 +2122,24 @@ where self.import_existing = false; self.best_queued_hash = info.best_hash; self.best_queued_number = info.best_number; - if self.mode == SyncMode::Full { - if self.client.block_status(&BlockId::hash(info.best_hash))? != + + if self.mode == SyncMode::Full && + self.client.block_status(&BlockId::hash(info.best_hash))? != BlockStatus::InChainWithState - { - self.import_existing = true; - // Latest state is missing, start with the last finalized state or genesis instead. - if let Some((hash, number)) = info.finalized_state { - debug!(target: "sync", "Starting from finalized state #{}", number); - self.best_queued_hash = hash; - self.best_queued_number = number; - } else { - debug!(target: "sync", "Restarting from genesis"); - self.best_queued_hash = Default::default(); - self.best_queued_number = Zero::zero(); - } + { + self.import_existing = true; + // Latest state is missing, start with the last finalized state or genesis instead. + if let Some((hash, number)) = info.finalized_state { + debug!(target: "sync", "Starting from finalized state #{}", number); + self.best_queued_hash = hash; + self.best_queued_number = number; + } else { + debug!(target: "sync", "Restarting from genesis"); + self.best_queued_hash = Default::default(); + self.best_queued_number = Zero::zero(); } } + if let Some((start, end)) = info.block_gap { debug!(target: "sync", "Starting gap sync #{} - #{}", start, end); self.gap_sync = Some(GapSync { @@ -2192,7 +2191,7 @@ where let justifications = block_data .block .justifications - .or(legacy_justification_mapping(block_data.block.justification)); + .or_else(|| legacy_justification_mapping(block_data.block.justification)); IncomingBlock { hash: block_data.block.hash, header: block_data.block.header, @@ -2349,7 +2348,7 @@ fn peer_block_request( let request = message::generic::BlockRequest { id: 0, - fields: attrs.clone(), + fields: attrs, from, to: None, direction: message::Direction::Descending, @@ -2369,7 +2368,7 @@ fn peer_gap_block_request( common_number: NumberFor, ) -> Option<(Range>, BlockRequest)> { let range = blocks.needed_blocks( - id.clone(), + *id, MAX_BLOCKS_TO_REQUEST, std::cmp::min(peer.best_number, target), common_number, @@ -2383,7 +2382,7 @@ fn peer_gap_block_request( let request = message::generic::BlockRequest { id: 0, - fields: attrs.clone(), + fields: attrs, from, to: None, direction: message::Direction::Descending, @@ -2430,11 +2429,11 @@ fn fork_sync_request( }; trace!(target: "sync", "Downloading requested fork {:?} from {}, {} blocks", hash, id, count); return Some(( - hash.clone(), + *hash, message::generic::BlockRequest { id: 0, - fields: attributes.clone(), - from: message::FromBlock::Hash(hash.clone()), + fields: attributes, + from: message::FromBlock::Hash(*hash), to: None, direction: message::Direction::Descending, max: Some(count), diff --git a/client/network/src/protocol/sync/extra_requests.rs b/client/network/src/protocol/sync/extra_requests.rs index d0bfebab66010..43122631d3c22 100644 --- a/client/network/src/protocol/sync/extra_requests.rs +++ b/client/network/src/protocol/sync/extra_requests.rs @@ -327,7 +327,7 @@ impl<'a, B: BlockT> Matcher<'a, B> { { continue } - self.extras.active_requests.insert(peer.clone(), request); + self.extras.active_requests.insert(*peer, request); trace!(target: "sync", "Sending {} request to {:?} for {:?}", diff --git a/client/network/src/protocol/sync/state.rs b/client/network/src/protocol/sync/state.rs index 4eddc4c60867e..6208b2bcdd18a 100644 --- a/client/network/src/protocol/sync/state.rs +++ b/client/network/src/protocol/sync/state.rs @@ -71,7 +71,7 @@ where Self { client, target_block: target.hash(), - target_root: target.state_root().clone(), + target_root: *target.state_root(), target_header: target, last_key: SmallVec::default(), state: HashMap::default(), @@ -149,18 +149,16 @@ where if entry.0.len() > 0 && entry.1.len() > 1 { // Already imported child_trie with same root. // Warning this will not work with parallel download. - } else { - if entry.0.is_empty() { - for (key, _value) in key_values.iter() { - self.imported_bytes += key.len() as u64; - } + } else if entry.0.is_empty() { + for (key, _value) in key_values.iter() { + self.imported_bytes += key.len() as u64; + } - entry.0 = key_values; - } else { - for (key, value) in key_values { - self.imported_bytes += key.len() as u64; - entry.0.push((key, value)) - } + entry.0 = key_values; + } else { + for (key, value) in key_values { + self.imported_bytes += key.len() as u64; + entry.0.push((key, value)) } } } @@ -172,7 +170,7 @@ where // the parent cursor stays valid. // Empty parent trie content only happens when all the response content // is part of a single child trie. - if self.last_key.len() == 2 && response.entries[0].entries.len() == 0 { + if self.last_key.len() == 2 && response.entries[0].entries.is_empty() { // Do not remove the parent trie position. self.last_key.pop(); } else { @@ -220,7 +218,7 @@ where self.target_block, self.target_header.clone(), ImportedState { - block: self.target_block.clone(), + block: self.target_block, state: std::mem::take(&mut self.state).into(), }, ) diff --git a/client/network/src/protocol/sync/warp.rs b/client/network/src/protocol/sync/warp.rs index fa2c23a0b33c1..6845d6d1dc862 100644 --- a/client/network/src/protocol/sync/warp.rs +++ b/client/network/src/protocol/sync/warp.rs @@ -94,7 +94,7 @@ where match &mut self.phase { Phase::WarpProof { .. } => { log::debug!(target: "sync", "Unexpected state response"); - return ImportResult::BadResponse + ImportResult::BadResponse }, Phase::State(sync) => sync.import(response), } @@ -111,13 +111,13 @@ where match self.warp_sync_provider.verify(&response, *set_id, authorities.clone()) { Err(e) => { log::debug!(target: "sync", "Bad warp proof response: {}", e); - return WarpProofImportResult::BadResponse + WarpProofImportResult::BadResponse }, Ok(VerificationResult::Partial(new_set_id, new_authorities, new_last_hash)) => { log::debug!(target: "sync", "Verified partial proof, set_id={:?}", new_set_id); *set_id = new_set_id; *authorities = new_authorities; - *last_hash = new_last_hash.clone(); + *last_hash = new_last_hash; self.total_proof_bytes += response.0.len() as u64; WarpProofImportResult::Success }, diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 87d070bc469a3..04d6ccb54339f 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -355,25 +355,21 @@ impl RequestResponsesBehaviour { (Instant::now(), pending_response), ); debug_assert!(prev_req_id.is_none(), "Expect request id to be unique."); - } else { - if pending_response.send(Err(RequestFailure::NotConnected)).is_err() { - log::debug!( - target: "sub-libp2p", - "Not connected to peer {:?}. At the same time local \ - node is no longer interested in the result.", - target, - ); - }; - } - } else { - if pending_response.send(Err(RequestFailure::UnknownProtocol)).is_err() { + } else if pending_response.send(Err(RequestFailure::NotConnected)).is_err() { log::debug!( target: "sub-libp2p", - "Unknown protocol {:?}. At the same time local \ + "Not connected to peer {:?}. At the same time local \ node is no longer interested in the result.", - protocol_name, + target, ); - }; + } + } else if pending_response.send(Err(RequestFailure::UnknownProtocol)).is_err() { + log::debug!( + target: "sub-libp2p", + "Unknown protocol {:?}. At the same time local \ + node is no longer interested in the result.", + protocol_name, + ); } } @@ -599,7 +595,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { // will be reported by the corresponding `RequestResponse` through // an `InboundFailure::Omission` event. let _ = resp_builder.try_send(IncomingRequest { - peer: peer.clone(), + peer, payload: request, pending_response: tx, }); @@ -648,7 +644,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { if let Ok(payload) = result { if let Some((protocol, _)) = self.protocols.get_mut(&*protocol_name) { - if let Err(_) = protocol.send_response(inner_channel, Ok(payload)) { + if protocol.send_response(inner_channel, Ok(payload)).is_err() { // Note: Failure is handled further below when receiving // `InboundFailure` event from `RequestResponse` behaviour. log::debug!( @@ -658,11 +654,9 @@ impl NetworkBehaviour for RequestResponsesBehaviour { Dropping response", request_id, protocol_name, ); - } else { - if let Some(sent_feedback) = sent_feedback { - self.send_feedback - .insert((protocol_name, request_id).into(), sent_feedback); - } + } else if let Some(sent_feedback) = sent_feedback { + self.send_feedback + .insert((protocol_name, request_id).into(), sent_feedback); } } } @@ -718,13 +712,10 @@ impl NetworkBehaviour for RequestResponsesBehaviour { message: RequestResponseMessage::Request { request_id, request, channel, .. }, } => { - self.pending_responses_arrival_time.insert( - (protocol.clone(), request_id.clone()).into(), - Instant::now(), - ); + self.pending_responses_arrival_time + .insert((protocol.clone(), request_id).into(), Instant::now()); - let get_peer_reputation = - self.peerset.clone().peer_reputation(peer.clone()); + let get_peer_reputation = self.peerset.clone().peer_reputation(peer); let get_peer_reputation = Box::pin(get_peer_reputation); // Save the Future-like state with params to poll `get_peer_reputation` diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 6ffc0ec49bd67..91517e14915bc 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -195,7 +195,7 @@ where // Private and public keys configuration. let local_identity = params.network_config.node_key.clone().into_keypair()?; let local_public = local_identity.public(); - let local_peer_id = local_public.clone().to_peer_id(); + let local_peer_id = local_public.to_peer_id(); info!( target: "sub-libp2p", "🏷 Local node identity is: {}", @@ -248,7 +248,7 @@ where Err(Error::DuplicateBootnode { address: addr.clone(), first_id: *peer_id, - second_id: other.0.clone(), + second_id: other.0, }) } else { Ok(()) @@ -644,7 +644,7 @@ where .collect() }; - let peer_id = Swarm::>::local_peer_id(&swarm).to_base58(); + let peer_id = Swarm::>::local_peer_id(swarm).to_base58(); let listened_addresses = swarm.listeners().cloned().collect(); let external_addresses = swarm.external_addresses().map(|r| &r.addr).cloned().collect(); @@ -664,7 +664,7 @@ where .behaviour_mut() .user_protocol_mut() .peers_info() - .map(|(id, info)| (id.clone(), info.clone())) + .map(|(id, info)| (*id, info.clone())) .collect() } @@ -753,7 +753,7 @@ impl NetworkService { // `peers_notifications_sinks` mutex as soon as possible. let sink = { let peers_notifications_sinks = self.peers_notifications_sinks.lock(); - if let Some(sink) = peers_notifications_sinks.get(&(target.clone(), protocol.clone())) { + if let Some(sink) = peers_notifications_sinks.get(&(target, protocol.clone())) { sink.clone() } else { // Notification silently discarded, as documented. @@ -1093,7 +1093,7 @@ impl NetworkService { let _ = self .to_worker - .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id.clone(), addr)); + .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id, addr)); let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::AddReserved(peer_id)); Ok(()) } @@ -1173,7 +1173,7 @@ impl NetworkService { if !addr.is_empty() { let _ = self .to_worker - .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id.clone(), addr)); + .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id, addr)); } let _ = self .to_worker @@ -1227,7 +1227,7 @@ impl NetworkService { if !addr.is_empty() { let _ = self .to_worker - .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id.clone(), addr)); + .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id, addr)); } let _ = self .to_worker @@ -1351,9 +1351,7 @@ pub struct NotificationSender { impl NotificationSender { /// Returns a future that resolves when the `NotificationSender` is ready to send a /// notification. - pub async fn ready<'a>( - &'a self, - ) -> Result, NotificationSenderError> { + pub async fn ready(&self) -> Result, NotificationSenderError> { Ok(NotificationSenderReady { ready: match self.sink.reserve_notification().await { Ok(r) => r, @@ -1771,7 +1769,7 @@ where if let Some(metrics) = this.metrics.as_ref() { metrics .kademlia_random_queries_total - .with_label_values(&[&protocol.as_ref()]) + .with_label_values(&[protocol.as_ref()]) .inc(); }, Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::NotificationStreamOpened { @@ -1790,7 +1788,7 @@ where { let mut peers_notifications_sinks = this.peers_notifications_sinks.lock(); let _previous_value = peers_notifications_sinks - .insert((remote.clone(), protocol.clone()), notifications_sink); + .insert((remote, protocol.clone()), notifications_sink); debug_assert!(_previous_value.is_none()); } this.event_streams.send(Event::NotificationStreamOpened { @@ -1848,13 +1846,12 @@ where .inc(); } this.event_streams.send(Event::NotificationStreamClosed { - remote: remote.clone(), + remote, protocol: protocol.clone(), }); { let mut peers_notifications_sinks = this.peers_notifications_sinks.lock(); - let _previous_value = - peers_notifications_sinks.remove(&(remote.clone(), protocol)); + let _previous_value = peers_notifications_sinks.remove(&(remote, protocol)); debug_assert!(_previous_value.is_some()); } }, @@ -2117,10 +2114,7 @@ where for (lower_ilog2_bucket_bound, num_entries) in buckets { metrics .kbuckets_num_nodes - .with_label_values(&[ - &proto.as_ref(), - &lower_ilog2_bucket_bound.to_string(), - ]) + .with_label_values(&[proto.as_ref(), &lower_ilog2_bucket_bound.to_string()]) .set(num_entries as u64); } } @@ -2128,7 +2122,7 @@ where { metrics .kademlia_records_count - .with_label_values(&[&proto.as_ref()]) + .with_label_values(&[proto.as_ref()]) .set(num_entries as u64); } for (proto, num_entries) in @@ -2136,7 +2130,7 @@ where { metrics .kademlia_records_sizes_total - .with_label_values(&[&proto.as_ref()]) + .with_label_values(&[proto.as_ref()]) .set(num_entries as u64); } metrics @@ -2211,12 +2205,10 @@ where number: NumberFor, success: bool, ) { - self.protocol.behaviour_mut().user_protocol_mut().justification_import_result( - who, - hash.clone(), - number, - success, - ); + self.protocol + .behaviour_mut() + .user_protocol_mut() + .justification_import_result(who, *hash, number, success); } fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { self.protocol diff --git a/client/network/src/service/metrics.rs b/client/network/src/service/metrics.rs index ad30b1b093ff9..4b63df00b8d66 100644 --- a/client/network/src/service/metrics.rs +++ b/client/network/src/service/metrics.rs @@ -280,8 +280,8 @@ impl MetricSource for BandwidthCounters { type N = u64; fn collect(&self, mut set: impl FnMut(&[&str], Self::N)) { - set(&[&"in"], self.0.total_inbound()); - set(&[&"out"], self.0.total_outbound()); + set(&["in"], self.0.total_inbound()); + set(&["out"], self.0.total_outbound()); } } diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 3bff5a16fd0c2..c95b46af4cefa 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -197,9 +197,9 @@ fn format_label(prefix: &str, protocol: &str, callback: impl FnOnce(&str)) { label_buffer.clear(); label_buffer.reserve(prefix.len() + protocol.len() + 2); label_buffer.push_str(prefix); - label_buffer.push_str("\""); + label_buffer.push('"'); label_buffer.push_str(protocol); - label_buffer.push_str("\""); + label_buffer.push('"'); callback(&label_buffer); }); } @@ -249,14 +249,14 @@ impl Metrics { .inc_by(num); }, Event::NotificationStreamOpened { protocol, .. } => { - format_label("notif-open-", &protocol, |protocol_label| { + format_label("notif-open-", protocol, |protocol_label| { self.events_total .with_label_values(&[protocol_label, "sent", name]) .inc_by(num); }); }, Event::NotificationStreamClosed { protocol, .. } => { - format_label("notif-closed-", &protocol, |protocol_label| { + format_label("notif-closed-", protocol, |protocol_label| { self.events_total .with_label_values(&[protocol_label, "sent", name]) .inc_by(num); @@ -264,7 +264,7 @@ impl Metrics { }, Event::NotificationsReceived { messages, .. } => for (protocol, message) in messages { - format_label("notif-", &protocol, |protocol_label| { + format_label("notif-", protocol, |protocol_label| { self.events_total .with_label_values(&[protocol_label, "sent", name]) .inc_by(num); @@ -290,24 +290,24 @@ impl Metrics { .inc(); }, Event::NotificationStreamOpened { protocol, .. } => { - format_label("notif-open-", &protocol, |protocol_label| { + format_label("notif-open-", protocol, |protocol_label| { self.events_total.with_label_values(&[protocol_label, "received", name]).inc(); }); }, Event::NotificationStreamClosed { protocol, .. } => { - format_label("notif-closed-", &protocol, |protocol_label| { + format_label("notif-closed-", protocol, |protocol_label| { self.events_total.with_label_values(&[protocol_label, "received", name]).inc(); }); }, Event::NotificationsReceived { messages, .. } => for (protocol, message) in messages { - format_label("notif-", &protocol, |protocol_label| { + format_label("notif-", protocol, |protocol_label| { self.events_total .with_label_values(&[protocol_label, "received", name]) .inc(); }); self.notifications_sizes - .with_label_values(&[&protocol, "received", name]) + .with_label_values(&[protocol, "received", name]) .inc_by(u64::try_from(message.len()).unwrap_or(u64::MAX)); }, } diff --git a/client/network/src/state_request_handler.rs b/client/network/src/state_request_handler.rs index 3e208e22e3d93..7ac1a17e8e759 100644 --- a/client/network/src/state_request_handler.rs +++ b/client/network/src/state_request_handler.rs @@ -63,11 +63,7 @@ pub fn generate_protocol_config(protocol_id: &ProtocolId) -> ProtocolConfig { /// Generate the state protocol name from chain specific protocol identifier. fn generate_protocol_name(protocol_id: &ProtocolId) -> String { - let mut s = String::new(); - s.push_str("/"); - s.push_str(protocol_id.as_ref()); - s.push_str("/state/2"); - s + format!("/{}/state/2", protocol_id.as_ref()) } /// The key of [`BlockRequestHandler::seen_requests`]. @@ -152,8 +148,7 @@ where let request = StateRequest::decode(&payload[..])?; let block: B::Hash = Decode::decode(&mut request.block.as_ref())?; - let key = - SeenRequestsKey { peer: *peer, block: block.clone(), start: request.start.clone() }; + let key = SeenRequestsKey { peer: *peer, block, start: request.start.clone() }; let mut reputation_changes = Vec::new(); diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index c09c6b88dab8b..64e208d718889 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -133,15 +133,7 @@ pub struct TransactionsHandlerPrototype { impl TransactionsHandlerPrototype { /// Create a new instance. pub fn new(protocol_id: ProtocolId) -> Self { - Self { - protocol_name: Cow::from({ - let mut proto = String::new(); - proto.push_str("/"); - proto.push_str(protocol_id.as_ref()); - proto.push_str("/transactions/1"); - proto - }), - } + Self { protocol_name: format!("/{}/transactions/1", protocol_id.as_ref()).into() } } /// Returns the configuration of the set to put in the network configuration. diff --git a/client/network/src/transport.rs b/client/network/src/transport.rs index 9a8e080234f32..64b199e9d769e 100644 --- a/client/network/src/transport.rs +++ b/client/network/src/transport.rs @@ -82,11 +82,11 @@ pub fn build_transport( rare panic here is basically zero"); // Legacy noise configurations for backward compatibility. - let mut noise_legacy = noise::LegacyConfig::default(); - noise_legacy.recv_legacy_handshake = true; + let noise_legacy = + noise::LegacyConfig { recv_legacy_handshake: true, ..Default::default() }; let mut xx_config = noise::NoiseConfig::xx(noise_keypair); - xx_config.set_legacy_config(noise_legacy.clone()); + xx_config.set_legacy_config(noise_legacy); xx_config.into_authenticated() }; diff --git a/client/network/src/warp_request_handler.rs b/client/network/src/warp_request_handler.rs index 4c839825ff5ec..d5bee5833a12a 100644 --- a/client/network/src/warp_request_handler.rs +++ b/client/network/src/warp_request_handler.rs @@ -82,11 +82,7 @@ pub fn generate_request_response_config(protocol_id: ProtocolId) -> RequestRespo /// Generate the grandpa warp sync protocol name from chain specific protocol identifier. fn generate_protocol_name(protocol_id: ProtocolId) -> String { - let mut s = String::new(); - s.push_str("/"); - s.push_str(protocol_id.as_ref()); - s.push_str("/sync/warp"); - s + format!("/{}/sync/warp", protocol_id.as_ref()) } /// Handler for incoming grandpa warp sync requests from a remote peer. diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 1760c08759761..20f1a3014867b 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -236,7 +236,7 @@ where { /// Get this peer ID. pub fn id(&self) -> PeerId { - self.network.service().local_peer_id().clone() + *self.network.service().local_peer_id() } /// Returns true if we're major syncing. @@ -387,7 +387,7 @@ where if inform_sync_about_new_best_block { self.network.new_best_block_imported( at, - full_client.header(&BlockId::Hash(at)).ok().flatten().unwrap().number().clone(), + *full_client.header(&BlockId::Hash(at)).ok().flatten().unwrap().number(), ); } at @@ -458,7 +458,7 @@ where nonce, }; builder.push(transfer.into_signed_tx()).unwrap(); - nonce = nonce + 1; + nonce += 1; builder.build().unwrap().block }, headers_only, @@ -494,7 +494,7 @@ where /// Get a reference to the network service. pub fn network_service(&self) -> &Arc::Hash>> { - &self.network.service() + self.network.service() } /// Get a reference to the network worker. @@ -801,7 +801,7 @@ where let addrs = connect_to .iter() .map(|v| { - let peer_id = self.peer(*v).network_service().local_peer_id().clone(); + let peer_id = *self.peer(*v).network_service().local_peer_id(); let multiaddr = self.peer(*v).listen_addr.clone(); MultiaddrWithPeerId { peer_id, multiaddr } }) @@ -868,10 +868,8 @@ where self.mut_peers(move |peers| { for peer in peers.iter_mut() { - peer.network.add_known_address( - network.service().local_peer_id().clone(), - listen_addr.clone(), - ); + peer.network + .add_known_address(*network.service().local_peer_id(), listen_addr.clone()); } let imported_blocks_stream = Box::pin(client.import_notification_stream().fuse()); @@ -986,7 +984,7 @@ where /// Polls the testnet. Processes all the pending actions. fn poll(&mut self, cx: &mut FutureContext) { self.mut_peers(|peers| { - for (i, peer) in peers.into_iter().enumerate() { + for (i, peer) in peers.iter_mut().enumerate() { trace!(target: "sync", "-- Polling {}: {}", i, peer.id()); if let Poll::Ready(()) = peer.network.poll_unpin(cx) { panic!("NetworkWorker has terminated unexpectedly.") @@ -1076,7 +1074,7 @@ impl JustificationImport for ForceFinalized { ) -> Result<(), Self::Error> { self.0 .finalize_block(BlockId::Hash(hash), Some(justification), true) - .map_err(|_| ConsensusError::InvalidJustification.into()) + .map_err(|_| ConsensusError::InvalidJustification) } } diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index 012de78c5f645..f4fa7e0800b2d 100644 --- a/client/offchain/src/api/http.rs +++ b/client/offchain/src/api/http.rs @@ -199,7 +199,7 @@ impl HttpApi { ) -> Result<(), HttpError> { // Extract the request from the list. // Don't forget to add it back if necessary when returning. - let mut request = self.requests.remove(&request_id).ok_or_else(|| HttpError::Invalid)?; + let mut request = self.requests.remove(&request_id).ok_or(HttpError::Invalid)?; let mut deadline = timestamp::deadline_to_future(deadline); // Closure that writes data to a sender, taking the deadline into account. Can return `Ok` diff --git a/client/peerset/src/lib.rs b/client/peerset/src/lib.rs index 859319fab1320..ec09835c4898e 100644 --- a/client/peerset/src/lib.rs +++ b/client/peerset/src/lib.rs @@ -619,11 +619,9 @@ impl Peerset { self.update_time(); - if self.reserved_nodes[set_id.0].1 { - if !self.reserved_nodes[set_id.0].0.contains(&peer_id) { - self.message_queue.push_back(Message::Reject(index)); - return - } + if self.reserved_nodes[set_id.0].1 && !self.reserved_nodes[set_id.0].0.contains(&peer_id) { + self.message_queue.push_back(Message::Reject(index)); + return } let not_connected = match self.data.peer(set_id.0, &peer_id) { @@ -730,8 +728,7 @@ impl Stream for Peerset { return Poll::Ready(Some(message)) } - if let Poll::Ready(_) = Future::poll(Pin::new(&mut self.next_periodic_alloc_slots), cx) - { + if Future::poll(Pin::new(&mut self.next_periodic_alloc_slots), cx).is_ready() { self.next_periodic_alloc_slots = Delay::new(Duration::new(1, 0)); for set_index in 0..self.data.num_sets() { @@ -798,7 +795,7 @@ mod tests { fn next_message(mut peerset: Peerset) -> Result<(Message, Peerset), ()> { let next = futures::executor::block_on_stream(&mut peerset).next(); - let message = next.ok_or_else(|| ())?; + let message = next.ok_or(())?; Ok((message, peerset)) } diff --git a/client/peerset/src/peersstate.rs b/client/peerset/src/peersstate.rs index ca22cac324088..c9af5b8e2ccd0 100644 --- a/client/peerset/src/peersstate.rs +++ b/client/peerset/src/peersstate.rs @@ -169,9 +169,7 @@ impl PeersState { /// Returns an object that grants access to the reputation value of a peer. pub fn peer_reputation(&mut self, peer_id: PeerId) -> Reputation { - if !self.nodes.contains_key(&peer_id) { - self.nodes.insert(peer_id, Node::new(self.sets.len())); - } + self.nodes.entry(peer_id).or_insert_with(|| Node::new(self.sets.len())); let entry = match self.nodes.entry(peer_id) { Entry::Vacant(_) => unreachable!("guaranteed to be inserted above; qed"), @@ -652,7 +650,7 @@ mod tests { let id1 = PeerId::random(); let id2 = PeerId::random(); - peers_state.add_no_slot_node(0, id1.clone()); + peers_state.add_no_slot_node(0, id1); if let Peer::Unknown(p) = peers_state.peer(0, &id1) { assert!(p.discover().try_accept_incoming().is_ok()); } else { @@ -705,43 +703,28 @@ mod tests { assert!(peers_state.highest_not_connected_peer(0).is_none()); peers_state.peer(0, &id1).into_unknown().unwrap().discover().set_reputation(50); peers_state.peer(0, &id2).into_unknown().unwrap().discover().set_reputation(25); - assert_eq!( - peers_state.highest_not_connected_peer(0).map(|p| p.into_peer_id()), - Some(id1.clone()) - ); + assert_eq!(peers_state.highest_not_connected_peer(0).map(|p| p.into_peer_id()), Some(id1)); peers_state.peer(0, &id2).into_not_connected().unwrap().set_reputation(75); - assert_eq!( - peers_state.highest_not_connected_peer(0).map(|p| p.into_peer_id()), - Some(id2.clone()) - ); + assert_eq!(peers_state.highest_not_connected_peer(0).map(|p| p.into_peer_id()), Some(id2)); peers_state .peer(0, &id2) .into_not_connected() .unwrap() .try_accept_incoming() .unwrap(); - assert_eq!( - peers_state.highest_not_connected_peer(0).map(|p| p.into_peer_id()), - Some(id1.clone()) - ); + assert_eq!(peers_state.highest_not_connected_peer(0).map(|p| p.into_peer_id()), Some(id1)); peers_state.peer(0, &id1).into_not_connected().unwrap().set_reputation(100); peers_state.peer(0, &id2).into_connected().unwrap().disconnect(); - assert_eq!( - peers_state.highest_not_connected_peer(0).map(|p| p.into_peer_id()), - Some(id1.clone()) - ); + assert_eq!(peers_state.highest_not_connected_peer(0).map(|p| p.into_peer_id()), Some(id1)); peers_state.peer(0, &id1).into_not_connected().unwrap().set_reputation(-100); - assert_eq!( - peers_state.highest_not_connected_peer(0).map(|p| p.into_peer_id()), - Some(id2.clone()) - ); + assert_eq!(peers_state.highest_not_connected_peer(0).map(|p| p.into_peer_id()), Some(id2)); } #[test] fn disconnect_no_slot_doesnt_panic() { let mut peers_state = PeersState::new(iter::once(SetConfig { in_peers: 1, out_peers: 1 })); let id = PeerId::random(); - peers_state.add_no_slot_node(0, id.clone()); + peers_state.add_no_slot_node(0, id); let peer = peers_state .peer(0, &id) .into_unknown() diff --git a/client/peerset/tests/fuzz.rs b/client/peerset/tests/fuzz.rs index af4838d724cbf..48c5cb341c35a 100644 --- a/client/peerset/tests/fuzz.rs +++ b/client/peerset/tests/fuzz.rs @@ -52,7 +52,7 @@ fn test_once() { bootnodes: (0..Uniform::new_inclusive(0, 4).sample(&mut rng)) .map(|_| { let id = PeerId::random(); - known_nodes.insert(id.clone()); + known_nodes.insert(id); id }) .collect(), @@ -60,8 +60,8 @@ fn test_once() { (0..Uniform::new_inclusive(0, 2).sample(&mut rng)) .map(|_| { let id = PeerId::random(); - known_nodes.insert(id.clone()); - reserved_nodes.insert(id.clone()); + known_nodes.insert(id); + reserved_nodes.insert(id); id }) .collect() @@ -114,7 +114,7 @@ fn test_once() { // If we generate 1, discover a new node. 1 => { let new_id = PeerId::random(); - known_nodes.insert(new_id.clone()); + known_nodes.insert(new_id); peerset.add_to_peers_set(SetId::from(0), new_id); }, @@ -122,7 +122,7 @@ fn test_once() { 2 => if let Some(id) = known_nodes.iter().choose(&mut rng) { let val = Uniform::new_inclusive(i32::MIN, i32::MAX).sample(&mut rng); - peerset_handle.report_peer(id.clone(), ReputationChange::new(val, "")); + peerset_handle.report_peer(*id, ReputationChange::new(val, "")); }, // If we generate 3, disconnect from a random node. @@ -142,8 +142,8 @@ fn test_once() { }) .choose(&mut rng) { - peerset.incoming(SetId::from(0), id.clone(), next_incoming_id.clone()); - incoming_nodes.insert(next_incoming_id.clone(), id.clone()); + peerset.incoming(SetId::from(0), *id, next_incoming_id); + incoming_nodes.insert(next_incoming_id, *id); next_incoming_id.0 += 1; } }, @@ -157,8 +157,8 @@ fn test_once() { if let Some(id) = known_nodes.iter().filter(|n| !reserved_nodes.contains(*n)).choose(&mut rng) { - peerset_handle.add_reserved_peer(SetId::from(0), id.clone()); - reserved_nodes.insert(id.clone()); + peerset_handle.add_reserved_peer(SetId::from(0), *id); + reserved_nodes.insert(*id); } }, 8 => diff --git a/client/rpc-api/src/author/error.rs b/client/rpc-api/src/author/error.rs index fe12bd581f120..1f8c65c471398 100644 --- a/client/rpc-api/src/author/error.rs +++ b/client/rpc-api/src/author/error.rs @@ -89,12 +89,12 @@ impl From for rpc::Error { match e { Error::BadFormat(e) => rpc::Error { code: rpc::ErrorCode::ServerError(BAD_FORMAT), - message: format!("Extrinsic has invalid format: {}", e).into(), + message: format!("Extrinsic has invalid format: {}", e), data: None, }, Error::Verification(e) => rpc::Error { code: rpc::ErrorCode::ServerError(VERIFICATION_ERROR), - message: format!("Verification Error: {}", e).into(), + message: format!("Verification Error: {}", e), data: Some(e.to_string().into()), }, Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Custom(e))) => rpc::Error { diff --git a/client/rpc-servers/src/middleware.rs b/client/rpc-servers/src/middleware.rs index 4adc878660090..d4ac787ce9f0c 100644 --- a/client/rpc-servers/src/middleware.rs +++ b/client/rpc-servers/src/middleware.rs @@ -237,8 +237,5 @@ fn call_name<'a>(call: &'a jsonrpc_core::Call, known_methods: &HashSet) } fn is_success(output: &Option) -> bool { - match output { - Some(jsonrpc_core::Output::Success(..)) => true, - _ => false, - } + matches!(output, Some(jsonrpc_core::Output::Success(..))) } diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 5064e61342101..2821eea2cc09d 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -119,7 +119,7 @@ where .runtime_api() .decode_session_keys(&generic::BlockId::Hash(best_block_hash), session_keys.to_vec()) .map_err(|e| Error::Client(Box::new(e)))? - .ok_or_else(|| Error::InvalidSessionKeys)?; + .ok_or(Error::InvalidSessionKeys)?; Ok(SyncCryptoStore::has_keys(&*self.keystore, &keys)) } @@ -143,7 +143,7 @@ where .map_err(|e| { e.into_pool_error() .map(Into::into) - .unwrap_or_else(|e| error::Error::Verification(Box::new(e)).into()) + .unwrap_or_else(|e| error::Error::Verification(Box::new(e))) }) .boxed() } @@ -201,7 +201,7 @@ where .map_err(|e| { e.into_pool_error() .map(error::Error::from) - .unwrap_or_else(|e| error::Error::Verification(Box::new(e)).into()) + .unwrap_or_else(|e| error::Error::Verification(Box::new(e))) }); let subscriptions = self.subscriptions.clone(); diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index c20e5a188ad3d..64231dd78c83c 100644 --- a/client/rpc/src/chain/mod.rs +++ b/client/rpc/src/chain/mod.rs @@ -60,7 +60,7 @@ where /// Tries to unwrap passed block hash, or uses best block hash otherwise. fn unwrap_or_best(&self, hash: Option) -> Block::Hash { - match hash.into() { + match hash { None => self.client().info().best_hash, Some(hash) => hash, } @@ -311,7 +311,7 @@ fn subscribe_headers( // send further subscriptions let stream = stream() .inspect_err(|e| warn!("Block notification stream error: {:?}", e)) - .map(|res| Ok(res)); + .map(Ok); stream::iter(vec![Ok(header)]) .chain(stream) diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 1a35760bd67df..38f9b078d87a7 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -151,10 +151,8 @@ where changes: &mut Vec>, ) -> Result<()> { for block_hash in &range.hashes { - let block_hash = block_hash.clone(); - let mut block_changes = - StorageChangeSet { block: block_hash.clone(), changes: Vec::new() }; - let id = BlockId::hash(block_hash); + let mut block_changes = StorageChangeSet { block: *block_hash, changes: Vec::new() }; + let id = BlockId::hash(*block_hash); for key in keys { let (has_changed, data) = { let curr_data = self.client.storage(&id, key).map_err(client_err)?; diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 882d7666dbe63..35ea67d8fbf85 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -263,7 +263,7 @@ where state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), state_pruning: config.state_pruning.clone(), source: config.database.clone(), - keep_blocks: config.keep_blocks.clone(), + keep_blocks: config.keep_blocks, }; let backend = new_db_backend(db_config)?; @@ -421,10 +421,10 @@ where Some("offchain-worker"), sc_offchain::notification_future( config.role.is_authority(), - client.clone(), + client, offchain, Clone::clone(&spawn_handle), - network.clone(), + network, ), ); } @@ -517,7 +517,7 @@ where let metrics_service = if let Some(PrometheusConfig { port, registry }) = config.prometheus_config.clone() { // Set static metrics. - let metrics = MetricsService::with_prometheus(telemetry.clone(), ®istry, &config)?; + let metrics = MetricsService::with_prometheus(telemetry, ®istry, &config)?; spawn_handle.spawn( "prometheus-endpoint", None, @@ -526,7 +526,7 @@ where metrics } else { - MetricsService::new(telemetry.clone()) + MetricsService::new(telemetry) }; // Periodically updated metrics and telemetry updates. @@ -572,7 +572,7 @@ where None, sc_informant::build( client.clone(), - network.clone(), + network, transaction_pool.clone(), config.informant_output_format, ), diff --git a/client/service/src/client/block_rules.rs b/client/service/src/client/block_rules.rs index 519d5a13f5168..2ed27b8fe1b63 100644 --- a/client/service/src/client/block_rules.rs +++ b/client/service/src/client/block_rules.rs @@ -47,8 +47,8 @@ impl BlockRules { /// New block rules with provided black and white lists. pub fn new(fork_blocks: ForkBlocks, bad_blocks: BadBlocks) -> Self { Self { - bad: bad_blocks.unwrap_or_else(|| HashSet::new()), - forks: fork_blocks.unwrap_or_else(|| vec![]).into_iter().collect(), + bad: bad_blocks.unwrap_or_default(), + forks: fork_blocks.unwrap_or_default().into_iter().collect(), } } @@ -61,7 +61,7 @@ impl BlockRules { pub fn lookup(&self, number: NumberFor, hash: &B::Hash) -> LookupResult { if let Some(hash_for_height) = self.forks.get(&number) { if hash_for_height != hash { - return LookupResult::Expected(hash_for_height.clone()) + return LookupResult::Expected(*hash_for_height) } } diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 0f13b08d0ce8e..1e8114df13339 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -283,7 +283,7 @@ where state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; self.executor .runtime_version(&mut ext, &runtime_code) - .map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string()).into()) + .map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string())) } fn prove_execution( @@ -305,7 +305,7 @@ where let runtime_code = self.check_override(runtime_code, at)?; sp_state_machine::prove_execution_on_trie_backend( - &trie_backend, + trie_backend, &mut Default::default(), &self.executor, self.spawn_handle.clone(), diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index dfa392bc96bde..48e4d0141c4e7 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -367,7 +367,7 @@ where let mut op = backend.begin_operation()?; let state_root = op.set_genesis_state(genesis_storage, !config.no_genesis, genesis_state_version)?; - let genesis_block = genesis::construct_genesis_block::(state_root.into()); + let genesis_block = genesis::construct_genesis_block::(state_root); info!( "🔨 Initializing Genesis block/state (state: {}, header-hash: {})", genesis_block.header().state_root(), @@ -551,7 +551,7 @@ where >::Api: CoreApi + ApiExt, { - let parent_hash = import_headers.post().parent_hash().clone(); + let parent_hash = *import_headers.post().parent_hash(); let status = self.backend.blockchain().status(BlockId::Hash(hash))?; let parent_exists = self.backend.blockchain().status(BlockId::Hash(parent_hash))? == blockchain::BlockStatus::InChain; @@ -609,7 +609,7 @@ where sc_consensus::StorageChanges::Import(changes) => { let mut storage = sp_storage::Storage::default(); for state in changes.state.0.into_iter() { - if state.parent_storage_keys.len() == 0 && state.state_root.len() == 0 { + if state.parent_storage_keys.is_empty() && state.state_root.is_empty() { for (key, value) in state.key_values.into_iter() { storage.top.insert(key, value); } @@ -617,7 +617,7 @@ where for parent_storage in state.parent_storage_keys { let storage_key = PrefixedStorageKey::new_ref(&parent_storage); let storage_key = - match ChildType::from_prefixed_key(&storage_key) { + match ChildType::from_prefixed_key(storage_key) { Some((ChildType::ParentKeyId, storage_key)) => storage_key, None => @@ -1033,7 +1033,7 @@ where return Ok(BlockStatus::Queued) } } - let hash_and_number = match id.clone() { + let hash_and_number = match *id { BlockId::Hash(hash) => self.backend.blockchain().number(hash)?.map(|n| (hash, n)), BlockId::Number(n) => self.backend.blockchain().hash(n)?.map(|hash| (hash, n)), }; @@ -1212,8 +1212,8 @@ where } let state = self.state_at(id)?; let child_info = |storage_key: &Vec| -> sp_blockchain::Result { - let storage_key = PrefixedStorageKey::new_ref(&storage_key); - match ChildType::from_prefixed_key(&storage_key) { + let storage_key = PrefixedStorageKey::new_ref(storage_key); + match ChildType::from_prefixed_key(storage_key) { Some((ChildType::ParentKeyId, storage_key)) => Ok(ChildInfo::new_default(storage_key)), None => Err(Error::Backend("Invalid child storage key.".to_string())), @@ -1222,7 +1222,7 @@ where let mut current_child = if start_key.len() == 2 { let start_key = start_key.get(0).expect("checked len"); if let Some(child_root) = state - .storage(&start_key) + .storage(start_key) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? { Some((child_info(start_key)?, child_root)) @@ -1232,7 +1232,7 @@ where } else { None }; - let mut current_key = start_key.last().map(Clone::clone).unwrap_or(Vec::new()); + let mut current_key = start_key.last().map(Clone::clone).unwrap_or_default(); let mut total_size = 0; let mut result = vec![( KeyValueStorageLevel { @@ -1276,14 +1276,13 @@ where total_size += size; if current_child.is_none() && - sp_core::storage::well_known_keys::is_child_storage_key(next_key.as_slice()) + sp_core::storage::well_known_keys::is_child_storage_key(next_key.as_slice()) && + !child_roots.contains(value.as_slice()) { - if !child_roots.contains(value.as_slice()) { - child_roots.insert(value.clone()); - switch_child_key = Some((next_key.clone(), value.clone())); - entries.push((next_key.clone(), value)); - break - } + child_roots.insert(value.clone()); + switch_child_key = Some((next_key.clone(), value.clone())); + entries.push((next_key.clone(), value)); + break } entries.push((next_key.clone(), value)); current_key = next_key; @@ -1647,7 +1646,7 @@ where { type Api = >::RuntimeApi; - fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { + fn runtime_api(&self) -> ApiRef { RA::construct_runtime_api(self) } } @@ -1661,12 +1660,11 @@ where type StateBackend = B::State; fn call_api_at< - 'a, R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, >( &self, - params: CallApiAtParams<'a, Block, NC, B::State>, + params: CallApiAtParams, ) -> Result, sp_api::ApiError> { let at = params.at; @@ -1742,7 +1740,7 @@ where }) .map_err(|e| { warn!("Block import error: {}", e); - ConsensusError::ClientImport(e.to_string()).into() + ConsensusError::ClientImport(e.to_string()) }) } diff --git a/client/service/src/client/wasm_override.rs b/client/service/src/client/wasm_override.rs index fa35be9fcac87..5fc748f3e88b9 100644 --- a/client/service/src/client/wasm_override.rs +++ b/client/service/src/client/wasm_override.rs @@ -87,7 +87,7 @@ fn make_hash(val: &K) -> Vec { } impl FetchRuntimeCode for WasmBlob { - fn fetch_runtime_code<'a>(&'a self) -> Option> { + fn fetch_runtime_code(&self) -> Option> { Some(self.code.as_slice().into()) } } @@ -186,34 +186,30 @@ impl WasmOverride { for entry in fs::read_dir(dir).map_err(handle_err)? { let entry = entry.map_err(handle_err)?; let path = entry.path(); - match path.extension().and_then(|e| e.to_str()) { - Some("wasm") => { - let code = fs::read(&path).map_err(handle_err)?; - let code_hash = make_hash(&code); - let version = Self::runtime_version(executor, &code, &code_hash, Some(128))?; - + if let Some("wasm") = path.extension().and_then(|e| e.to_str()) { + let code = fs::read(&path).map_err(handle_err)?; + let code_hash = make_hash(&code); + let version = Self::runtime_version(executor, &code, &code_hash, Some(128))?; + tracing::info!( + target: "wasm_overrides", + version = %version, + file = %path.display(), + "Found wasm override.", + ); + + let wasm = + WasmBlob::new(code, code_hash, path.clone(), version.spec_name.to_string()); + + if let Some(other) = overrides.insert(version.spec_version, wasm) { tracing::info!( target: "wasm_overrides", - version = %version, - file = %path.display(), - "Found wasm override.", + first = %other.path.display(), + second = %path.display(), + %version, + "Found duplicate spec version for runtime.", ); - - let wasm = - WasmBlob::new(code, code_hash, path.clone(), version.spec_name.to_string()); - - if let Some(other) = overrides.insert(version.spec_version, wasm) { - tracing::info!( - target: "wasm_overrides", - first = %other.path.display(), - second = %path.display(), - %version, - "Found duplicate spec version for runtime.", - ); - duplicates.push(path.display().to_string()); - } - }, - _ => (), + duplicates.push(path.display().to_string()); + } } } diff --git a/client/service/src/client/wasm_substitutes.rs b/client/service/src/client/wasm_substitutes.rs index 3690672512675..f826fa3613c84 100644 --- a/client/service/src/client/wasm_substitutes.rs +++ b/client/service/src/client/wasm_substitutes.rs @@ -56,7 +56,7 @@ impl WasmSubstitute { /// Returns `true` when the substitute matches for the given `block_id`. fn matches(&self, block_id: &BlockId, backend: &impl backend::Backend) -> bool { let requested_block_number = - backend.blockchain().block_number_from_id(&block_id).ok().flatten(); + backend.blockchain().block_number_from_id(block_id).ok().flatten(); Some(self.block_number) <= requested_block_number } @@ -70,7 +70,7 @@ fn make_hash(val: &K) -> Vec { } impl FetchRuntimeCode for WasmSubstitute { - fn fetch_runtime_code<'a>(&'a self) -> Option> { + fn fetch_runtime_code(&self) -> Option> { Some(self.code.as_slice().into()) } } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index a48e6168c52cc..0d2461376d961 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -180,7 +180,7 @@ async fn build_network_future< if notification.is_new_best { network.service().new_best_block_imported( notification.hash, - notification.header.number().clone(), + *notification.header.number(), ); } } @@ -204,7 +204,7 @@ async fn build_network_future< let _ = sender.send(network.local_peer_id().to_base58()); }, sc_rpc::system::Request::LocalListenAddresses(sender) => { - let peer_id = network.local_peer_id().clone().into(); + let peer_id = (*network.local_peer_id()).into(); let p2p_proto_suffix = sc_network::multiaddr::Protocol::P2p(peer_id); let addresses = network.listen_addresses() .map(|addr| addr.clone().with(p2p_proto_suffix.clone()).to_string()) @@ -222,7 +222,7 @@ async fn build_network_future< ).collect()); } sc_rpc::system::Request::NetworkState(sender) => { - if let Some(network_state) = serde_json::to_value(&network.network_state()).ok() { + if let Ok(network_state) = serde_json::to_value(&network.network_state()) { let _ = sender.send(network_state); } } @@ -265,7 +265,7 @@ async fn build_network_future< use sc_rpc::system::SyncState; let _ = sender.send(SyncState { - starting_block: starting_block, + starting_block, current_block: client.info().best_number, highest_block: network.best_seen_block(), }); @@ -385,7 +385,7 @@ fn start_rpc_servers< address, config.rpc_cors.as_ref(), gen_handler( - deny_unsafe(&address, &config.rpc_methods), + deny_unsafe(address, &config.rpc_methods), sc_rpc_server::RpcMiddleware::new( rpc_metrics.clone(), rpc_method_names.clone(), @@ -404,7 +404,7 @@ fn start_rpc_servers< config.rpc_ws_max_connections, config.rpc_cors.as_ref(), gen_handler( - deny_unsafe(&address, &config.rpc_methods), + deny_unsafe(address, &config.rpc_methods), sc_rpc_server::RpcMiddleware::new( rpc_metrics.clone(), rpc_method_names.clone(), diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index 9fbf2c3ea3fca..555023f894488 100644 --- a/client/service/src/metrics.rs +++ b/client/service/src/metrics.rs @@ -61,13 +61,13 @@ impl PrometheusMetrics { .const_label("name", name) .const_label("version", version), )?, - ®istry, + registry, )? .set(1); register( Gauge::::new("substrate_node_roles", "The roles the node is running as")?, - ®istry, + registry, )? .set(roles); diff --git a/client/service/src/task_manager/mod.rs b/client/service/src/task_manager/mod.rs index 2f9cd257c360b..49189dc21ce8d 100644 --- a/client/service/src/task_manager/mod.rs +++ b/client/service/src/task_manager/mod.rs @@ -38,12 +38,12 @@ mod prometheus_future; mod tests; /// Default task group name. -pub const DEFAULT_GROUP_NAME: &'static str = "default"; +pub const DEFAULT_GROUP_NAME: &str = "default"; /// The name of a group a task belongs to. /// /// This name is passed belong-side the task name to the prometheus metrics and can be used -/// to group tasks. +/// to group tasks. pub enum GroupName { /// Sets the group name to `default`. Default, diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index c492ed30f7d91..ef04e16a65d26 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -308,15 +308,15 @@ where handle.clone(), Some(key), self.base_port, - &temp, + temp, ); - let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); + let addr = node_config.network.listen_addresses.first().unwrap().clone(); let (service, user_data) = authority(node_config).expect("Error creating test node service"); handle.spawn(service.clone().map_err(|_| ())); - let addr = addr - .with(multiaddr::Protocol::P2p(service.network().local_peer_id().clone().into())); + let addr = + addr.with(multiaddr::Protocol::P2p((*service.network().local_peer_id()).into())); self.authority_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; } @@ -329,14 +329,14 @@ where handle.clone(), None, self.base_port, - &temp, + temp, ); - let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); + let addr = node_config.network.listen_addresses.first().unwrap().clone(); let (service, user_data) = full(node_config).expect("Error creating test node service"); handle.spawn(service.clone().map_err(|_| ())); - let addr = addr - .with(multiaddr::Protocol::P2p(service.network().local_peer_id().clone().into())); + let addr = + addr.with(multiaddr::Protocol::P2p((*service.network().local_peer_id()).into())); self.full_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; } @@ -461,7 +461,7 @@ pub fn sync( info!("Generating #{}", i + 1); } - make_block_and_import(&first_service, first_user_data); + make_block_and_import(first_service, first_user_data); } let info = network.full_nodes[0].1.client().info(); network.full_nodes[0] diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 74f218e88f861..8fe2cdc9d9a85 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -268,7 +268,7 @@ impl StateDbSync Ok(()), @@ -314,7 +314,7 @@ impl StateDbSync if self.mode == PruningMode::ArchiveCanonical { commit.data.deleted.clear(); @@ -322,14 +322,14 @@ impl StateDbSync return Err(e), }; if let Some(ref mut pruning) = self.pruning { - pruning.note_canonical(&hash, &mut commit); + pruning.note_canonical(hash, &mut commit); } self.prune(&mut commit); Ok(commit) } fn best_canonical(&self) -> Option { - return self.non_canonical.last_canonicalized_block_number() + self.non_canonical.last_canonicalized_block_number() } fn is_pruned(&self, hash: &BlockHash, number: u64) -> bool { @@ -438,7 +438,7 @@ impl StateDbSync(values: &mut HashMap, inserted fn discard_descendants( levels: &mut (&mut [OverlayLevel], &mut [OverlayLevel]), - mut values: &mut HashMap, + values: &mut HashMap, parents: &mut HashMap, pinned: &HashMap, pinned_insertions: &mut HashMap, u32)>, @@ -135,12 +135,10 @@ fn discard_descendants( ) -> u32 { let (first, mut remainder) = if let Some((first, rest)) = levels.0.split_first_mut() { (Some(first), (rest, &mut *levels.1)) + } else if let Some((first, rest)) = levels.1.split_first_mut() { + (Some(first), (&mut *levels.0, rest)) } else { - if let Some((first, rest)) = levels.1.split_first_mut() { - (Some(first), (&mut *levels.0, rest)) - } else { - (None, (&mut *levels.0, &mut *levels.1)) - } + (None, (&mut *levels.0, &mut *levels.1)) }; let mut pinned_children = 0; if let Some(level) = first { @@ -169,7 +167,7 @@ fn discard_descendants( } else { // discard immediately. parents.remove(&overlay.hash); - discard_values(&mut values, overlay.inserted); + discard_values(values, overlay.inserted); } } } @@ -180,7 +178,7 @@ impl NonCanonicalOverlay { /// Creates a new instance. Does not expect any metadata to be present in the DB. pub fn new(db: &D) -> Result, Error> { let last_canonicalized = - db.get_meta(&to_meta_key(LAST_CANONICAL, &())).map_err(|e| Error::Db(e))?; + db.get_meta(&to_meta_key(LAST_CANONICAL, &())).map_err(Error::Db)?; let last_canonicalized = last_canonicalized .map(|buffer| <(BlockHash, u64)>::decode(&mut buffer.as_slice())) .transpose()?; @@ -196,7 +194,7 @@ impl NonCanonicalOverlay { let mut level = OverlayLevel::new(); for index in 0..MAX_BLOCKS_PER_LEVEL { let journal_key = to_journal_key(block, index); - if let Some(record) = db.get_meta(&journal_key).map_err(|e| Error::Db(e))? { + if let Some(record) = db.get_meta(&journal_key).map_err(Error::Db)? { let record: JournalRecord = Decode::decode(&mut record.as_slice())?; let inserted = record.inserted.iter().map(|(k, _)| k.clone()).collect(); @@ -280,7 +278,7 @@ impl NonCanonicalOverlay { { return Err(Error::InvalidParent) } - } else if !self.parents.contains_key(&parent_hash) { + } else if !self.parents.contains_key(parent_hash) { return Err(Error::InvalidParent) } } @@ -391,12 +389,12 @@ impl NonCanonicalOverlay { let level = self .levels .get(self.pending_canonicalizations.len()) - .ok_or_else(|| Error::InvalidBlock)?; + .ok_or(Error::InvalidBlock)?; let index = level .blocks .iter() .position(|overlay| overlay.hash == *hash) - .ok_or_else(|| Error::InvalidBlock)?; + .ok_or(Error::InvalidBlock)?; let mut discarded_journals = Vec::new(); let mut discarded_blocks = Vec::new(); @@ -493,10 +491,7 @@ impl NonCanonicalOverlay { Key: std::borrow::Borrow, Q: std::hash::Hash + Eq, { - if let Some((_, value)) = self.values.get(&key) { - return Some(value.clone()) - } - None + self.values.get(key).map(|v| v.1.clone()) } /// Check if the block is in the canonicalization queue. diff --git a/client/state-db/src/pruning.rs b/client/state-db/src/pruning.rs index 2631405cdffa7..0fdcb8e822b6f 100644 --- a/client/state-db/src/pruning.rs +++ b/client/state-db/src/pruning.rs @@ -76,7 +76,7 @@ impl RefWindow { db: &D, count_insertions: bool, ) -> Result, Error> { - let last_pruned = db.get_meta(&to_meta_key(LAST_PRUNED, &())).map_err(|e| Error::Db(e))?; + let last_pruned = db.get_meta(&to_meta_key(LAST_PRUNED, &())).map_err(Error::Db)?; let pending_number: u64 = match last_pruned { Some(buffer) => u64::decode(&mut buffer.as_slice())? + 1, None => 0, @@ -94,7 +94,7 @@ impl RefWindow { trace!(target: "state-db", "Reading pruning journal. Pending #{}", pending_number); loop { let journal_key = to_journal_key(block); - match db.get_meta(&journal_key).map_err(|e| Error::Db(e))? { + match db.get_meta(&journal_key).map_err(Error::Db)? { Some(record) => { let record: JournalRecord = Decode::decode(&mut record.as_slice())?; @@ -208,7 +208,7 @@ impl RefWindow { trace!(target: "state-db", "Applying pruning {:?} ({} deleted)", pruned.hash, pruned.deleted.len()); if self.count_insertions { for k in pruned.deleted.iter() { - self.death_index.remove(&k); + self.death_index.remove(k); } } self.pending_number += 1; diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index 6fc0d17800fed..d7696c662e856 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -166,7 +166,7 @@ where let finalized_block_weight = sc_consensus_babe::aux_schema::load_block_weight(&*self.client, finalized_hash)? - .ok_or_else(|| Error::LoadingBlockWeightFailed(finalized_hash))?; + .ok_or(Error::LoadingBlockWeightFailed(finalized_hash))?; Ok(LightSyncState { finalized_block_header: finalized_header, diff --git a/client/telemetry/src/lib.rs b/client/telemetry/src/lib.rs index d570701a3d9ec..fc40f999a6779 100644 --- a/client/telemetry/src/lib.rs +++ b/client/telemetry/src/lib.rs @@ -246,7 +246,7 @@ impl TelemetryWorker { "Initializing telemetry for: {:?}", addr, ); - node_map.entry(id.clone()).or_default().push((verbosity, addr.clone())); + node_map.entry(id).or_default().push((verbosity, addr.clone())); let node = node_pool.entry(addr.clone()).or_insert_with(|| { Node::new(transport.clone(), addr.clone(), Vec::new(), Vec::new()) @@ -288,7 +288,7 @@ impl TelemetryWorker { ) { let (id, verbosity, payload) = input.expect("the stream is never closed; qed"); - let ts = chrono::Local::now().to_rfc3339().to_string(); + let ts = chrono::Local::now().to_rfc3339(); let mut message = serde_json::Map::new(); message.insert("id".into(), id.into()); message.insert("ts".into(), ts.into()); @@ -318,7 +318,7 @@ impl TelemetryWorker { continue } - if let Some(node) = node_pool.get_mut(&addr) { + if let Some(node) = node_pool.get_mut(addr) { let _ = node.send(message.clone()).await; } else { log::debug!( @@ -386,7 +386,7 @@ impl Telemetry { /// The `connection_message` argument is a JSON object that is sent every time the connection /// (re-)establishes. pub fn start_telemetry(&mut self, connection_message: ConnectionMessage) -> Result<()> { - let endpoints = self.endpoints.take().ok_or_else(|| Error::TelemetryAlreadyInitialized)?; + let endpoints = self.endpoints.take().ok_or(Error::TelemetryAlreadyInitialized)?; self.register_sender .unbounded_send(Register::Telemetry { id: self.id, endpoints, connection_message }) diff --git a/client/telemetry/src/node.rs b/client/telemetry/src/node.rs index f3d746abb2b18..aa0f5a3843d33 100644 --- a/client/telemetry/src/node.rs +++ b/client/telemetry/src/node.rs @@ -239,7 +239,7 @@ where }, }, NodeSocket::WaitingReconnect(mut s) => { - if let Poll::Ready(_) = Future::poll(Pin::new(&mut s), cx) { + if Future::poll(Pin::new(&mut s), cx).is_ready() { socket = NodeSocket::ReconnectNow; } else { break NodeSocket::WaitingReconnect(s) diff --git a/client/tracing/src/block/mod.rs b/client/tracing/src/block/mod.rs index 259827e4b47d9..6de3a0220e15e 100644 --- a/client/tracing/src/block/mod.rs +++ b/client/tracing/src/block/mod.rs @@ -108,7 +108,7 @@ impl BlockSubscriber { impl Subscriber for BlockSubscriber { fn enabled(&self, metadata: &tracing::Metadata<'_>) -> bool { - if !metadata.is_span() && !metadata.fields().field(REQUIRED_EVENT_FIELD).is_some() { + if !metadata.is_span() && metadata.fields().field(REQUIRED_EVENT_FIELD).is_none() { return false } for (target, level) in &self.targets { @@ -221,12 +221,12 @@ where let mut header = self .client .header(id) - .map_err(|e| Error::InvalidBlockId(e))? + .map_err(Error::InvalidBlockId)? .ok_or_else(|| Error::MissingBlockComponent("Header not found".to_string()))?; let extrinsics = self .client .block_body(&id) - .map_err(|e| Error::InvalidBlockId(e))? + .map_err(Error::InvalidBlockId)? .ok_or_else(|| Error::MissingBlockComponent("Extrinsics not found".to_string()))?; tracing::debug!(target: "state_tracing", "Found {} extrinsics", extrinsics.len()); let parent_hash = *header.parent_hash(); @@ -252,16 +252,18 @@ where let _enter = span.enter(); self.client.runtime_api().execute_block(&parent_id, block) }) { - return Err(Error::Dispatch( - format!("Failed to collect traces and execute block: {}", e).to_string(), - )) + return Err(Error::Dispatch(format!( + "Failed to collect traces and execute block: {}", + e + ))) } } - let block_subscriber = - dispatch.downcast_ref::().ok_or(Error::Dispatch( + let block_subscriber = dispatch.downcast_ref::().ok_or_else(|| { + Error::Dispatch( "Cannot downcast Dispatch to BlockSubscriber after tracing block".to_string(), - ))?; + ) + })?; let spans: Vec<_> = block_subscriber .spans .lock() diff --git a/client/tracing/src/lib.rs b/client/tracing/src/lib.rs index ff3723e0d1a9a..1ae695a725f3f 100644 --- a/client/tracing/src/lib.rs +++ b/client/tracing/src/lib.rs @@ -166,8 +166,7 @@ impl Visit for Values { } fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) { - self.string_values - .insert(field.name().to_string(), format!("{:?}", value).to_owned()); + self.string_values.insert(field.name().to_string(), format!("{:?}", value)); } } @@ -239,7 +238,7 @@ impl ProfilingLayer { /// or without: "pallet" in which case the level defaults to `trace`. /// wasm_tracing indicates whether to enable wasm traces pub fn new_with_handler(trace_handler: Box, targets: &str) -> Self { - let targets: Vec<_> = targets.split(',').map(|s| parse_target(s)).collect(); + let targets: Vec<_> = targets.split(',').map(parse_target).collect(); Self { targets, trace_handlers: vec![trace_handler] } } diff --git a/client/tracing/src/logging/directives.rs b/client/tracing/src/logging/directives.rs index fe7d6a780dbf0..b5fb373674ace 100644 --- a/client/tracing/src/logging/directives.rs +++ b/client/tracing/src/logging/directives.rs @@ -84,7 +84,7 @@ pub fn reload_filter() -> Result<(), String> { log::debug!(target: "tracing", "Reloading log filter with: {}", env_filter); FILTER_RELOAD_HANDLE .get() - .ok_or("No reload handle present".to_string())? + .ok_or("No reload handle present")? .reload(env_filter) .map_err(|e| format!("{}", e)) } diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index f5cdda4d35442..33c83dd87189e 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -110,7 +110,7 @@ where // Accept all valid directives and print invalid ones fn parse_user_directives(mut env_filter: EnvFilter, dirs: &str) -> Result { for dir in dirs.split(',') { - env_filter = env_filter.add_directive(parse_default_directive(&dir)?); + env_filter = env_filter.add_directive(parse_default_directive(dir)?); } Ok(env_filter) } @@ -299,32 +299,30 @@ impl LoggerBuilder { Ok(()) } + } else if self.log_reloading { + let subscriber = prepare_subscriber( + &self.directives, + None, + self.force_colors, + self.detailed_output, + |builder| enable_log_reloading!(builder), + )?; + + tracing::subscriber::set_global_default(subscriber)?; + + Ok(()) } else { - if self.log_reloading { - let subscriber = prepare_subscriber( - &self.directives, - None, - self.force_colors, - self.detailed_output, - |builder| enable_log_reloading!(builder), - )?; + let subscriber = prepare_subscriber( + &self.directives, + None, + self.force_colors, + self.detailed_output, + |builder| builder, + )?; - tracing::subscriber::set_global_default(subscriber)?; + tracing::subscriber::set_global_default(subscriber)?; - Ok(()) - } else { - let subscriber = prepare_subscriber( - &self.directives, - None, - self.force_colors, - self.detailed_output, - |builder| builder, - )?; - - tracing::subscriber::set_global_default(subscriber)?; - - Ok(()) - } + Ok(()) } } } diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index d7b3ddc996362..448578b327b03 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -350,7 +350,7 @@ impl OffchainSubmitTransaction for TP extrinsic ); - let result = self.submit_local(&at, extrinsic); + let result = self.submit_local(at, extrinsic); result.map(|_| ()).map_err(|e| { log::warn!( diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index 12909f313d100..4710c96b003cd 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -123,7 +123,7 @@ where type BodyFuture = Ready::Extrinsic>>>>; fn block_body(&self, id: &BlockId) -> Self::BodyFuture { - ready(self.client.block_body(&id).map_err(|e| error::Error::from(e))) + ready(self.client.block_body(id).map_err(error::Error::from)) } fn validate_transaction( @@ -134,7 +134,7 @@ where ) -> Self::ValidationFuture { let (tx, rx) = oneshot::channel(); let client = self.client.clone(); - let at = at.clone(); + let at = *at; let validation_pool = self.validation_pool.clone(); let metrics = self.metrics.clone(); @@ -212,7 +212,7 @@ where let runtime_api = client.runtime_api(); let api_version = sp_tracing::within_span! { sp_tracing::Level::TRACE, "check_version"; runtime_api - .api_version::>(&at) + .api_version::>(at) .map_err(|e| Error::RuntimeApi(e.to_string()))? .ok_or_else(|| Error::RuntimeApi( format!("Could not find `TaggedTransactionQueue` api for block `{:?}`.", at) @@ -229,7 +229,7 @@ where sp_tracing::Level::TRACE, "runtime::validate_transaction"; { if api_version >= 3 { - runtime_api.validate_transaction(&at, source, uxt, block_hash) + runtime_api.validate_transaction(at, source, uxt, block_hash) .map_err(|e| Error::RuntimeApi(e.to_string())) } else { let block_number = client.to_number(at) @@ -249,11 +249,11 @@ where if api_version == 2 { #[allow(deprecated)] // old validate_transaction - runtime_api.validate_transaction_before_version_3(&at, source, uxt) + runtime_api.validate_transaction_before_version_3(at, source, uxt) .map_err(|e| Error::RuntimeApi(e.to_string())) } else { #[allow(deprecated)] // old validate_transaction - runtime_api.validate_transaction_before_version_2(&at, uxt) + runtime_api.validate_transaction_before_version_2(at, uxt) .map_err(|e| Error::RuntimeApi(e.to_string())) } } diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 39be43f82c8b9..618ba8ccf24d5 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -335,7 +335,7 @@ impl Pool { // And finally - submit reverified transactions back to the pool self.validated_pool.resubmit_pruned( - &at, + at, known_imported_hashes, pruned_hashes, reverified_transactions.into_iter().map(|(_, xt)| xt).collect(), diff --git a/client/transaction-pool/src/graph/ready.rs b/client/transaction-pool/src/graph/ready.rs index ebaa73f149240..220e69b13e7eb 100644 --- a/client/transaction-pool/src/graph/ready.rs +++ b/client/transaction-pool/src/graph/ready.rs @@ -300,7 +300,7 @@ impl ReadyTransactions { for tag in &tx.transaction.transaction.requires { if let Some(hash) = self.provided_tags.get(tag) { if let Some(tx) = ready.get_mut(hash) { - remove_item(&mut tx.unlocks, &hash); + remove_item(&mut tx.unlocks, hash); } } } @@ -351,7 +351,7 @@ impl ReadyTransactions { let mut ready = self.ready.write(); let mut find_previous = |tag| -> Option> { let prev_hash = self.provided_tags.get(tag)?; - let tx2 = ready.get_mut(&prev_hash)?; + let tx2 = ready.get_mut(prev_hash)?; remove_item(&mut tx2.unlocks, hash); // We eagerly prune previous transactions as well. // But it might not always be good. @@ -551,7 +551,7 @@ impl Iterator for BestIterator { continue } - let ready = match self.all.get(&hash).cloned() { + let ready = match self.all.get(hash).cloned() { Some(ready) => ready, // The transaction is not in all, maybe it was removed in the meantime? None => continue, diff --git a/client/transaction-pool/src/graph/validated_pool.rs b/client/transaction-pool/src/graph/validated_pool.rs index 4ddaf8de5c2bc..084b04842ee90 100644 --- a/client/transaction-pool/src/graph/validated_pool.rs +++ b/client/transaction-pool/src/graph/validated_pool.rs @@ -442,7 +442,7 @@ impl ValidatedPool { pub fn extrinsics_tags(&self, hashes: &[ExtrinsicHash]) -> Vec>> { self.pool .read() - .by_hashes(&hashes) + .by_hashes(hashes) .into_iter() .map(|existing_in_pool| { existing_in_pool.map(|transaction| transaction.provides.to_vec()) @@ -546,7 +546,7 @@ impl ValidatedPool { let now = Instant::now(); let to_remove = { self.ready() - .filter(|tx| self.rotator.ban_if_stale(&now, block_number, &tx)) + .filter(|tx| self.rotator.ban_if_stale(&now, block_number, tx)) .map(|tx| tx.hash) .collect::>() }; @@ -554,7 +554,7 @@ impl ValidatedPool { let p = self.pool.read(); let mut hashes = Vec::new(); for tx in p.futures() { - if self.rotator.ban_if_stale(&now, block_number, &tx) { + if self.rotator.ban_if_stale(&now, block_number, tx) { hashes.push(tx.hash); } } @@ -630,11 +630,7 @@ impl ValidatedPool { /// Returns a Vec of hashes and extrinsics in the future pool. pub fn futures(&self) -> Vec<(ExtrinsicHash, ExtrinsicFor)> { - self.pool - .read() - .futures() - .map(|tx| (tx.hash.clone(), tx.data.clone())) - .collect() + self.pool.read().futures().map(|tx| (tx.hash, tx.data.clone())).collect() } /// Returns pool status. @@ -663,9 +659,9 @@ where match *imported { base::Imported::Ready { ref promoted, ref failed, ref removed, ref hash } => { listener.ready(hash, None); - failed.into_iter().for_each(|f| listener.invalid(f)); - removed.into_iter().for_each(|r| listener.dropped(&r.hash, Some(hash))); - promoted.into_iter().for_each(|p| listener.ready(p, None)); + failed.iter().for_each(|f| listener.invalid(f)); + removed.iter().for_each(|r| listener.dropped(&r.hash, Some(hash))); + promoted.iter().for_each(|p| listener.ready(p, None)); }, base::Imported::Future { ref hash } => listener.future(hash), } diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 9fd2ef1deef43..eb36d46538c1a 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -430,7 +430,7 @@ where let validated = ValidatedTransaction::valid_at( block_number.saturated_into::(), - hash.clone(), + hash, TransactionSource::Local, xt, bytes, @@ -538,7 +538,7 @@ async fn prune_known_txs_for_block>(); + let hashes = extrinsics.iter().map(|tx| pool.hash_of(tx)).collect::>(); log::trace!(target: "txpool", "Pruning transactions: {:?}", hashes); @@ -609,11 +609,11 @@ where if let Some(ref tree_route) = tree_route { for retracted in tree_route.retracted() { // notify txs awaiting finality that it has been retracted - pool.validated_pool().on_block_retracted(retracted.hash.clone()); + pool.validated_pool().on_block_retracted(retracted.hash); } future::join_all(tree_route.enacted().iter().map(|h| { - prune_known_txs_for_block(BlockId::Hash(h.hash.clone()), &*api, &*pool) + prune_known_txs_for_block(BlockId::Hash(h.hash), &*api, &*pool) })) .await .into_iter() @@ -622,7 +622,7 @@ where }) } - pruned_log.extend(prune_known_txs_for_block(id.clone(), &*api, &*pool).await); + pruned_log.extend(prune_known_txs_for_block(id, &*api, &*pool).await); metrics.report(|metrics| { metrics.block_transactions_pruned.inc_by(pruned_log.len() as u64) @@ -632,7 +632,7 @@ where let mut resubmit_transactions = Vec::new(); for retracted in tree_route.retracted() { - let hash = retracted.hash.clone(); + let hash = retracted.hash; let block_transactions = api .block_body(&BlockId::hash(hash)) @@ -649,7 +649,7 @@ where resubmit_transactions.extend(block_transactions.into_iter().filter( |tx| { - let tx_hash = pool.hash_of(&tx); + let tx_hash = pool.hash_of(tx); let contains = pruned_log.contains(&tx_hash); // need to count all transactions, not just filtered, here @@ -699,8 +699,7 @@ where }); if next_action.revalidate { - let hashes = - pool.validated_pool().ready().map(|tx| tx.hash.clone()).collect(); + let hashes = pool.validated_pool().ready().map(|tx| tx.hash).collect(); revalidation_queue.revalidate_later(block_number, hashes).await; revalidation_strategy.lock().clear(); diff --git a/client/transaction-pool/src/revalidation.rs b/client/transaction-pool/src/revalidation.rs index e3641008a7061..b4b4299240a32 100644 --- a/client/transaction-pool/src/revalidation.rs +++ b/client/transaction-pool/src/revalidation.rs @@ -92,7 +92,7 @@ async fn batch_revalidate( }, Ok(Ok(validity)) => { revalidated.insert( - ext_hash.clone(), + ext_hash, ValidatedTransaction::valid_at( at.saturated_into::(), ext_hash, @@ -194,14 +194,14 @@ impl RevalidationWorker { self.block_ordered .entry(block_number) .and_modify(|value| { - value.insert(ext_hash.clone()); + value.insert(ext_hash); }) .or_insert_with(|| { let mut bt = HashSet::new(); - bt.insert(ext_hash.clone()); + bt.insert(ext_hash); bt }); - self.members.insert(ext_hash.clone(), block_number); + self.members.insert(ext_hash, block_number); } } diff --git a/client/utils/src/pubsub.rs b/client/utils/src/pubsub.rs index c8e51e3494b97..ba6e9ddc6ca2a 100644 --- a/client/utils/src/pubsub.rs +++ b/client/utils/src/pubsub.rs @@ -195,8 +195,8 @@ impl Hub { let mut shared_borrowed = shared_locked.borrow_mut(); let (registry, sinks) = shared_borrowed.get_mut(); - let dispatch_result = registry.dispatch(trigger, |subs_id, item| { - if let Some(tx) = sinks.get_mut(&subs_id) { + registry.dispatch(trigger, |subs_id, item| { + if let Some(tx) = sinks.get_mut(subs_id) { if let Err(send_err) = tx.unbounded_send(item) { log::warn!("Sink with SubsID = {} failed to perform unbounded_send: {} ({} as Dispatch<{}, Item = {}>::dispatch(...))", subs_id, send_err, std::any::type_name::(), std::any::type_name::(), @@ -211,9 +211,7 @@ impl Hub { std::any::type_name::(), ); } - }); - - dispatch_result + }) } } diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 33de190a8e36a..ca88899edf842 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -281,7 +281,7 @@ benchmarks_instance_pallet! { let target0 = T::Lookup::unlookup(account("target", 0, SEED)); let target1 = T::Lookup::unlookup(account("target", 1, SEED)); let target2 = T::Lookup::unlookup(account("target", 2, SEED)); - }: _(SystemOrigin::Signed(caller), Default::default(), target0.clone(), target1.clone(), target2.clone()) + }: _(SystemOrigin::Signed(caller), Default::default(), target0, target1, target2) verify { assert_last_event::(Event::TeamChanged { asset_id: Default::default(), @@ -346,7 +346,7 @@ benchmarks_instance_pallet! { let (caller, _) = create_default_asset::(true); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); let dummy = vec![0u8; T::StringLimit::get() as usize]; - let origin = SystemOrigin::Signed(caller.clone()).into(); + let origin = SystemOrigin::Signed(caller).into(); Assets::::set_metadata(origin, Default::default(), dummy.clone(), dummy, 12)?; let origin = T::ForceOrigin::successful_origin(); @@ -365,7 +365,7 @@ benchmarks_instance_pallet! { owner: caller_lookup.clone(), issuer: caller_lookup.clone(), admin: caller_lookup.clone(), - freezer: caller_lookup.clone(), + freezer: caller_lookup, min_balance: 100u32.into(), is_sufficient: true, is_frozen: false, @@ -398,7 +398,7 @@ benchmarks_instance_pallet! { let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let amount = 100u32.into(); let origin = SystemOrigin::Signed(owner.clone()).into(); - Assets::::approve_transfer(origin, id, delegate_lookup.clone(), amount)?; + Assets::::approve_transfer(origin, id, delegate_lookup, amount)?; let dest: T::AccountId = account("dest", 0, SEED); let dest_lookup = T::Lookup::unlookup(dest.clone()); diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index a6abfd9e0409c..0f8e7096e80c1 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -204,7 +204,7 @@ impl, I: 'static> Pallet { who: &T::AccountId, keep_alive: bool, ) -> Result { - let details = Asset::::get(id).ok_or_else(|| Error::::Unknown)?; + let details = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(!details.is_frozen, Error::::Frozen); let account = Account::::get(id, who).ok_or(Error::::NoAccount)?; @@ -258,7 +258,7 @@ impl, I: 'static> Pallet { Ok(dust) => actual.saturating_add(dust), //< guaranteed by reducible_balance Err(e) => { debug_assert!(false, "passed from reducible_balance; qed"); - return Err(e.into()) + return Err(e) }, }; @@ -291,7 +291,7 @@ impl, I: 'static> Pallet { (true, Some(dust)) => (amount, Some(dust)), _ => (debit, None), }; - Self::can_increase(id, &dest, credit, false).into_result()?; + Self::can_increase(id, dest, credit, false).into_result()?; Ok((credit, maybe_burn)) } @@ -352,7 +352,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult { Self::increase_balance(id, beneficiary, amount, |details| -> DispatchResult { if let Some(check_issuer) = maybe_check_issuer { - ensure!(&check_issuer == &details.issuer, Error::::NoPermission); + ensure!(check_issuer == details.issuer, Error::::NoPermission); } debug_assert!( T::Balance::max_value() - details.supply >= amount, @@ -433,7 +433,7 @@ impl, I: 'static> Pallet { let actual = Self::decrease_balance(id, target, amount, f, |actual, details| { // Check admin rights. if let Some(check_admin) = maybe_check_admin { - ensure!(&check_admin == &details.admin, Error::::NoPermission); + ensure!(check_admin == details.admin, Error::::NoPermission); } debug_assert!(details.supply >= actual, "checked in prep; qed"); @@ -471,7 +471,7 @@ impl, I: 'static> Pallet { let mut target_died: Option = None; Asset::::try_mutate(id, |maybe_details| -> DispatchResult { - let mut details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; check(actual, details)?; @@ -483,8 +483,7 @@ impl, I: 'static> Pallet { account.balance = account.balance.saturating_sub(actual); if account.balance < details.min_balance { debug_assert!(account.balance.is_zero(), "checked in prep; qed"); - target_died = - Some(Self::dead_account(target, &mut details, &account.reason, false)); + target_died = Some(Self::dead_account(target, details, &account.reason, false)); if let Some(Remove) = target_died { return Ok(()) } @@ -543,8 +542,8 @@ impl, I: 'static> Pallet { } // Figure out the debit and credit, together with side-effects. - let debit = Self::prep_debit(id, &source, amount, f.into())?; - let (credit, maybe_burn) = Self::prep_credit(id, &dest, amount, debit, f.burn_dust)?; + let debit = Self::prep_debit(id, source, amount, f.into())?; + let (credit, maybe_burn) = Self::prep_credit(id, dest, amount, debit, f.burn_dust)?; let mut source_account = Account::::get(id, &source).ok_or(Error::::NoAccount)?; @@ -555,7 +554,7 @@ impl, I: 'static> Pallet { // Check admin rights. if let Some(need_admin) = maybe_need_admin { - ensure!(&need_admin == &details.admin, Error::::NoPermission); + ensure!(need_admin == details.admin, Error::::NoPermission); } // Skip if source == dest @@ -590,7 +589,7 @@ impl, I: 'static> Pallet { *maybe_account = Some(AssetAccountOf:: { balance: credit, is_frozen: false, - reason: Self::new_account(&dest, details, None)?, + reason: Self::new_account(dest, details, None)?, extra: T::Extra::default(), }); }, @@ -602,7 +601,7 @@ impl, I: 'static> Pallet { if source_account.balance < details.min_balance { debug_assert!(source_account.balance.is_zero(), "checked in prep; qed"); source_died = - Some(Self::dead_account(&source, details, &source_account.reason, false)); + Some(Self::dead_account(source, details, &source_account.reason, false)); if let Some(Remove) = source_died { Account::::remove(id, &source); return Ok(()) @@ -746,7 +745,7 @@ impl, I: 'static> Pallet { }; let deposit_required = T::ApprovalDeposit::get(); if approved.deposit < deposit_required { - T::Currency::reserve(&owner, deposit_required - approved.deposit)?; + T::Currency::reserve(owner, deposit_required - approved.deposit)?; approved.deposit = deposit_required; } approved.amount = approved.amount.saturating_add(amount); @@ -789,10 +788,10 @@ impl, I: 'static> Pallet { approved.amount.checked_sub(&amount).ok_or(Error::::Unapproved)?; let f = TransferFlags { keep_alive: false, best_effort: false, burn_dust: false }; - owner_died = Self::transfer_and_die(id, &owner, &destination, amount, None, f)?.1; + owner_died = Self::transfer_and_die(id, owner, destination, amount, None, f)?.1; if remaining.is_zero() { - T::Currency::unreserve(&owner, approved.deposit); + T::Currency::unreserve(owner, approved.deposit); Asset::::mutate(id, |maybe_details| { if let Some(details) = maybe_details { details.approvals.saturating_dec(); diff --git a/frame/assets/src/impl_stored_map.rs b/frame/assets/src/impl_stored_map.rs index dfdcff37d1d69..a4669c776ed41 100644 --- a/frame/assets/src/impl_stored_map.rs +++ b/frame/assets/src/impl_stored_map.rs @@ -42,7 +42,7 @@ impl, I: 'static> StoredMap<(T::AssetId, T::AccountId), T::Extra> f if let Some(ref mut account) = maybe_account { account.extra = extra; } else { - Err(DispatchError::NoProviders)?; + return Err(DispatchError::NoProviders.into()) } } else { // They want to delete it. Let this pass if the item never existed anyway. diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 9b0f23a0a1783..eb412de58fda6 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -788,7 +788,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; let d = Asset::::get(id).ok_or(Error::::Unknown)?; - ensure!(&origin == &d.freezer, Error::::NoPermission); + ensure!(origin == d.freezer, Error::::NoPermission); let who = T::Lookup::lookup(who)?; Account::::try_mutate(id, &who, |maybe_account| -> DispatchResult { @@ -819,7 +819,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; let details = Asset::::get(id).ok_or(Error::::Unknown)?; - ensure!(&origin == &details.admin, Error::::NoPermission); + ensure!(origin == details.admin, Error::::NoPermission); let who = T::Lookup::lookup(who)?; Account::::try_mutate(id, &who, |maybe_account| -> DispatchResult { @@ -849,7 +849,7 @@ pub mod pallet { Asset::::try_mutate(id, |maybe_details| { let d = maybe_details.as_mut().ok_or(Error::::Unknown)?; - ensure!(&origin == &d.freezer, Error::::NoPermission); + ensure!(origin == d.freezer, Error::::NoPermission); d.is_frozen = true; @@ -876,7 +876,7 @@ pub mod pallet { Asset::::try_mutate(id, |maybe_details| { let d = maybe_details.as_mut().ok_or(Error::::Unknown)?; - ensure!(&origin == &d.admin, Error::::NoPermission); + ensure!(origin == d.admin, Error::::NoPermission); d.is_frozen = false; @@ -906,7 +906,7 @@ pub mod pallet { Asset::::try_mutate(id, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; - ensure!(&origin == &details.owner, Error::::NoPermission); + ensure!(origin == details.owner, Error::::NoPermission); if details.owner == owner { return Ok(()) } @@ -951,7 +951,7 @@ pub mod pallet { Asset::::try_mutate(id, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; - ensure!(&origin == &details.owner, Error::::NoPermission); + ensure!(origin == details.owner, Error::::NoPermission); details.issuer = issuer.clone(); details.admin = admin.clone(); @@ -1009,7 +1009,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; let d = Asset::::get(id).ok_or(Error::::Unknown)?; - ensure!(&origin == &d.owner, Error::::NoPermission); + ensure!(origin == d.owner, Error::::NoPermission); Metadata::::try_mutate_exists(id, |metadata| { let deposit = metadata.take().ok_or(Error::::Unknown)?.deposit; @@ -1241,7 +1241,7 @@ pub mod pallet { .map(|_| ()) .or_else(|origin| -> DispatchResult { let origin = ensure_signed(origin)?; - ensure!(&origin == &d.admin, Error::::NoPermission); + ensure!(origin == d.admin, Error::::NoPermission); Ok(()) })?; diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index 56034e59086b9..2e8a1f911fb0f 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -104,9 +104,9 @@ impl ExistenceReason { if let ExistenceReason::DepositHeld(deposit) = sp_std::mem::replace(self, ExistenceReason::DepositRefunded) { - return Some(deposit) + Some(deposit) } else { - return None + None } } } diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 40429c226e649..b999aefaaa907 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -138,7 +138,7 @@ where C: ReservableCurrency, { fn reserve(&self, source: &AccountId) -> DispatchResult { - C::reserve(&source, self.value) + C::reserve(source, self.value) } fn claim(&self, source: &AccountId, target: &AccountId) -> bool { @@ -267,7 +267,7 @@ pub mod pallet { action, end_block: frame_system::Pallet::::block_number() + duration, }; - PendingSwaps::::insert(target.clone(), hashed_proof.clone(), swap.clone()); + PendingSwaps::::insert(target.clone(), hashed_proof, swap.clone()); Self::deposit_event(Event::NewSwap { account: target, proof: hashed_proof, swap }); @@ -303,7 +303,7 @@ pub mod pallet { let succeeded = swap.action.claim(&swap.source, &target); - PendingSwaps::::remove(target.clone(), hashed_proof.clone()); + PendingSwaps::::remove(target.clone(), hashed_proof); Self::deposit_event(Event::SwapClaimed { account: target, diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 0f474770017d5..222360dc3a7d3 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -261,7 +261,7 @@ impl> FindAuthor let i = Inner::find_author(digests)?; let validators = >::authorities(); - validators.get(i as usize).map(|k| k.clone()) + validators.get(i as usize).cloned() } } diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 6b72d6ac5d28b..561db20849c2f 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -106,7 +106,7 @@ where let number = header.number(); if let Some(ref author) = author { - if !acc.insert((number.clone(), author.clone())) { + if !acc.insert((*number, author.clone())) { return Err("more than one uncle per number per author included") } } @@ -225,7 +225,7 @@ pub mod pallet { ensure!(new_uncles.len() <= MAX_UNCLES, Error::::TooManyUncles); if >::get() { - Err(Error::::UnclesAlreadySet)? + return Err(Error::::UnclesAlreadySet.into()) } >::put(true); @@ -334,7 +334,7 @@ impl Pallet { let hash = uncle.hash(); if let Some(author) = maybe_author.clone() { - T::EventHandler::note_uncle(author, now - uncle.number().clone()); + T::EventHandler::note_uncle(author, now - *uncle.number()); } uncles.push(UncleEntryItem::Uncle(hash, maybe_author)); } @@ -368,7 +368,7 @@ impl Pallet { } { - let parent_number = uncle.number().clone() - One::one(); + let parent_number = *uncle.number() - One::one(); let parent_hash = >::block_hash(&parent_number); if &parent_hash != uncle.parent_hash() { return Err(Error::::InvalidUncleParent.into()) @@ -387,7 +387,7 @@ impl Pallet { } // check uncle validity. - T::FilterUncle::filter_uncle(&uncle, accumulator).map_err(|e| Into::into(e)) + T::FilterUncle::filter_uncle(uncle, accumulator).map_err(Into::into) } fn prune_old_uncles(minimum_height: T::BlockNumber) { diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 87ae762707ccd..2709316d87150 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -438,7 +438,7 @@ impl FindAuthor for Pallet { } } - return None + None } } @@ -641,7 +641,7 @@ impl Pallet { let segment_idx = segment_idx + 1; let bounded_randomness = BoundedVec::<_, ConstU32>::try_from(vec![ - randomness.clone(), + *randomness, ]) .expect("UNDER_CONSTRUCTION_SEGMENT_LENGTH >= 1"); UnderConstruction::::insert(&segment_idx, bounded_randomness); @@ -726,7 +726,7 @@ impl Pallet { vrf_output.0.attach_input_hash(&pubkey, transcript).ok() }) - .map(|inout| inout.make_bytes(&sp_consensus_babe::BABE_VRF_INOUT_CONTEXT)) + .map(|inout| inout.make_bytes(sp_consensus_babe::BABE_VRF_INOUT_CONTEXT)) }) }); diff --git a/frame/bags-list/fuzzer/src/main.rs b/frame/bags-list/fuzzer/src/main.rs index 6f538eb28e7e4..387c266d32256 100644 --- a/frame/bags-list/fuzzer/src/main.rs +++ b/frame/bags-list/fuzzer/src/main.rs @@ -62,7 +62,7 @@ fn main() { match action { Action::Insert => { - if BagsList::on_insert(id.clone(), vote_weight).is_err() { + if BagsList::on_insert(id, vote_weight).is_err() { // this was a duplicate id, which is ok. We can just update it. BagsList::on_update(&id, vote_weight); } diff --git a/frame/bags-list/remote-tests/src/lib.rs b/frame/bags-list/remote-tests/src/lib.rs index caf7a2a547e09..458064cf79f57 100644 --- a/frame/bags-list/remote-tests/src/lib.rs +++ b/frame/bags-list/remote-tests/src/lib.rs @@ -21,7 +21,7 @@ use frame_election_provider_support::ScoreProvider; use sp_std::prelude::*; /// A common log target to use. -pub const LOG_TARGET: &'static str = "runtime::bags-list::remote-tests"; +pub const LOG_TARGET: &str = "runtime::bags-list::remote-tests"; pub mod migration; pub mod sanity_check; diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index 1a901c4d9d5a1..dba0c9ee1e623 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -133,7 +133,7 @@ frame_benchmarking::benchmarks! { List::::get_bags(), vec![ (origin_bag_thresh, vec![origin_head.clone()]), - (dest_bag_thresh, vec![dest_head.clone(), origin_tail.clone()]) + (dest_bag_thresh, vec![dest_head.clone(), origin_tail]) ] ); } diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 94553433e230d..53ccd5e4c19f1 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -74,7 +74,7 @@ pub use list::{notional_bag_for, Bag, List, ListError, Node}; pub use pallet::*; pub use weights::WeightInfo; -pub(crate) const LOG_TARGET: &'static str = "runtime::bags_list"; +pub(crate) const LOG_TARGET: &str = "runtime::bags_list"; // syntactic sugar for logging. #[macro_export] @@ -254,7 +254,7 @@ impl, I: 'static> Pallet { pub fn do_rebag(account: &T::AccountId, new_weight: T::Score) -> Option<(T::Score, T::Score)> { // if no voter at that node, don't do anything. // the caller just wasted the fee to call this. - let maybe_movement = list::Node::::get(&account) + let maybe_movement = list::Node::::get(account) .and_then(|node| List::update_position_for(node, new_weight)); if let Some((from, to)) = maybe_movement { Self::deposit_event(Event::::Rebagged { who: account.clone(), from, to }); diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index db8c06a38d674..4de70569253da 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -59,7 +59,7 @@ mod tests; pub fn notional_bag_for, I: 'static>(score: T::Score) -> T::Score { let thresholds = T::BagThresholds::get(); let idx = thresholds.partition_point(|&threshold| score > threshold); - thresholds.get(idx).copied().unwrap_or(T::Score::max_value()) + thresholds.get(idx).copied().unwrap_or_else(T::Score::max_value) } /// The **ONLY** entry point of this module. All operations to the bags-list should happen through @@ -163,7 +163,7 @@ impl, I: 'static> List { let affected_bag = { // this recreates `notional_bag_for` logic, but with the old thresholds. let idx = old_thresholds.partition_point(|&threshold| inserted_bag > threshold); - old_thresholds.get(idx).copied().unwrap_or(T::Score::max_value()) + old_thresholds.get(idx).copied().unwrap_or_else(T::Score::max_value) }; if !affected_old_bags.insert(affected_bag) { // If the previous threshold list was [10, 20], and we insert [3, 5], then there's @@ -420,24 +420,24 @@ impl, I: 'static> List { use crate::pallet; use frame_support::ensure; - let lighter_node = Node::::get(&lighter_id).ok_or(pallet::Error::IdNotFound)?; - let heavier_node = Node::::get(&heavier_id).ok_or(pallet::Error::IdNotFound)?; + let lighter_node = Node::::get(lighter_id).ok_or(pallet::Error::IdNotFound)?; + let heavier_node = Node::::get(heavier_id).ok_or(pallet::Error::IdNotFound)?; ensure!(lighter_node.bag_upper == heavier_node.bag_upper, pallet::Error::NotInSameBag); // this is the most expensive check, so we do it last. ensure!( - T::ScoreProvider::score(&heavier_id) > T::ScoreProvider::score(&lighter_id), + T::ScoreProvider::score(heavier_id) > T::ScoreProvider::score(lighter_id), pallet::Error::NotHeavier ); // remove the heavier node from this list. Note that this removes the node from storage and // decrements the node counter. - Self::remove(&heavier_id); + Self::remove(heavier_id); // re-fetch `lighter_node` from storage since it may have been updated when `heavier_node` // was removed. - let lighter_node = Node::::get(&lighter_id).ok_or_else(|| { + let lighter_node = Node::::get(lighter_id).ok_or_else(|| { debug_assert!(false, "id that should exist cannot be found"); crate::log!(warn, "id that should exist cannot be found"); pallet::Error::IdNotFound @@ -527,7 +527,7 @@ impl, I: 'static> List { thresholds.into_iter().filter_map(|t| Bag::::get(t)) }; - let _ = active_bags.clone().map(|b| b.sanity_check()).collect::>()?; + let _ = active_bags.clone().try_for_each(|b| b.sanity_check())?; let nodes_in_bags_count = active_bags.clone().fold(0u32, |acc, cur| acc + cur.iter().count() as u32); @@ -708,7 +708,7 @@ impl, I: 'static> Bag { // the first insertion into the bag. In this case, both head and tail should point to the // same node. if self.head.is_none() { - self.head = Some(id.clone()); + self.head = Some(id); debug_assert!(self.iter().count() == 1); } } diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index fce1431054174..961bf2b83552f 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -42,7 +42,7 @@ impl frame_election_provider_support::ScoreProvider for StakingMock { #[cfg(any(feature = "runtime-benchmarks", test))] fn set_score_of(id: &AccountId, weight: Self::Score) { - NEXT_VOTE_WEIGHT_MAP.with(|m| m.borrow_mut().insert(id.clone(), weight)); + NEXT_VOTE_WEIGHT_MAP.with(|m| m.borrow_mut().insert(*id, weight)); } } diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 5ba6c4dfa1f69..7060486f8584d 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -775,7 +775,7 @@ impl, I: 'static> Pallet { /// Get both the free and reserved balances of an account. fn account(who: &T::AccountId) -> AccountData { - T::AccountStore::get(&who) + T::AccountStore::get(who) } /// Handles any steps needed after mutating an account. @@ -988,17 +988,15 @@ impl, I: 'static> Pallet { } } else { Locks::::insert(who, bounded_locks); - if !existed { - if system::Pallet::::inc_consumers_without_limit(who).is_err() { - // No providers for the locks. This is impossible under normal circumstances - // since the funds that are under the lock will themselves be stored in the - // account and therefore will need a reference. - log::warn!( - target: "runtime::balances", - "Warning: Attempt to introduce lock consumer reference, yet no providers. \ - This is unexpected but should be safe." - ); - } + if !existed && system::Pallet::::inc_consumers_without_limit(who).is_err() { + // No providers for the locks. This is impossible under normal circumstances + // since the funds that are under the lock will themselves be stored in the + // account and therefore will need a reference. + log::warn!( + target: "runtime::balances", + "Warning: Attempt to introduce lock consumer reference, yet no providers. \ + This is unexpected but should be safe." + ); } } } @@ -1107,7 +1105,7 @@ impl, I: 'static> fungible::Mutate for Pallet { return Ok(()) } Self::try_mutate_account(who, |account, _is_new| -> DispatchResult { - Self::deposit_consequence(who, amount, &account, true).into_result()?; + Self::deposit_consequence(who, amount, account, true).into_result()?; account.free += amount; Ok(()) })?; @@ -1126,7 +1124,7 @@ impl, I: 'static> fungible::Mutate for Pallet { let actual = Self::try_mutate_account( who, |account, _is_new| -> Result { - let extra = Self::withdraw_consequence(who, amount, &account).into_result()?; + let extra = Self::withdraw_consequence(who, amount, account).into_result()?; let actual = amount + extra; account.free -= actual; Ok(actual) @@ -1214,7 +1212,7 @@ impl, I: 'static> fungible::MutateHold for Pallet::InsufficientBalance); // ^^^ Guaranteed to be <= amount and <= a.reserved a.free = new_free; - a.reserved = a.reserved.saturating_sub(actual.clone()); + a.reserved = a.reserved.saturating_sub(actual); Ok(actual) }) } @@ -1318,7 +1316,7 @@ mod imbalances { } } fn peek(&self) -> T::Balance { - self.0.clone() + self.0 } } @@ -1377,7 +1375,7 @@ mod imbalances { } } fn peek(&self) -> T::Balance { - self.0.clone() + self.0 } } @@ -1560,7 +1558,7 @@ where if value.is_zero() { return (NegativeImbalance::zero(), Zero::zero()) } - if Self::total_balance(&who).is_zero() { + if Self::total_balance(who).is_zero() { return (NegativeImbalance::zero(), value) } @@ -1656,7 +1654,7 @@ where return Self::PositiveImbalance::zero() } - let r = Self::try_mutate_account( + Self::try_mutate_account( who, |account, is_new| -> Result { let ed = T::ExistentialDeposit::get(); @@ -1673,9 +1671,7 @@ where Ok(PositiveImbalance::new(value)) }, ) - .unwrap_or_else(|_| Self::PositiveImbalance::zero()); - - r + .unwrap_or_else(|_| Self::PositiveImbalance::zero()) } /// Withdraw some free balance from an account, respecting existence requirements. @@ -1785,7 +1781,7 @@ where account.free.checked_sub(&value).ok_or(Error::::InsufficientBalance)?; account.reserved = account.reserved.checked_add(&value).ok_or(ArithmeticError::Overflow)?; - Self::ensure_can_withdraw(&who, value.clone(), WithdrawReasons::RESERVE, account.free) + Self::ensure_can_withdraw(&who, value, WithdrawReasons::RESERVE, account.free) })?; Self::deposit_event(Event::Reserved { who: who.clone(), amount: value }); @@ -1799,7 +1795,7 @@ where if value.is_zero() { return Zero::zero() } - if Self::total_balance(&who).is_zero() { + if Self::total_balance(who).is_zero() { return value } @@ -1820,7 +1816,7 @@ where }, }; - Self::deposit_event(Event::Unreserved { who: who.clone(), amount: actual.clone() }); + Self::deposit_event(Event::Unreserved { who: who.clone(), amount: actual }); value - actual } @@ -1835,7 +1831,7 @@ where if value.is_zero() { return (NegativeImbalance::zero(), Zero::zero()) } - if Self::total_balance(&who).is_zero() { + if Self::total_balance(who).is_zero() { return (NegativeImbalance::zero(), value) } @@ -1925,7 +1921,7 @@ where }, Err(index) => { reserves - .try_insert(index, ReserveData { id: id.clone(), amount: value }) + .try_insert(index, ReserveData { id: *id, amount: value }) .map_err(|_| Error::::TooManyReserves)?; }, }; @@ -2086,7 +2082,7 @@ where reserves .try_insert( index, - ReserveData { id: id.clone(), amount: actual }, + ReserveData { id: *id, amount: actual }, ) .map_err(|_| Error::::TooManyReserves)?; diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index 52baec80e62ed..c19af781234f8 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -91,7 +91,7 @@ impl Analysis { }) .collect(); - values.sort(); + values.sort_unstable(); let mid = values.len() / 2; Some(Self { @@ -216,7 +216,7 @@ impl Analysis { } for (_, rs) in results.iter_mut() { - rs.sort(); + rs.sort_unstable(); let ql = rs.len() / 4; *rs = rs[ql..rs.len() - ql].to_vec(); } @@ -255,7 +255,7 @@ impl Analysis { .iter() .map(|(p, vs)| { // Avoid divide by zero - if vs.len() == 0 { + if vs.is_empty() { return (p.clone(), 0, 0) } let total = vs.iter().fold(0u128, |acc, v| acc + *v); diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 04adacf6e4aec..912e461501be5 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -99,7 +99,7 @@ benchmarks! { propose_curator { setup_pot_account::(); let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); - let curator_lookup = T::Lookup::unlookup(curator.clone()); + let curator_lookup = T::Lookup::unlookup(curator); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 886c758bbe42e..dfeef36a1fae0 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -474,7 +474,7 @@ pub mod pallet { // Else this is the curator, willingly giving up their role. // Give back their deposit. let err_amount = - T::Currency::unreserve(&curator, bounty.curator_deposit); + T::Currency::unreserve(curator, bounty.curator_deposit); debug_assert!(err_amount.is_zero()); bounty.curator_deposit = Zero::zero(); // Continue to change bounty status below... @@ -706,7 +706,7 @@ pub mod pallet { BountyStatus::Active { curator, .. } => { // Cancelled by council, refund deposit of the working curator. let err_amount = - T::Currency::unreserve(&curator, bounty.curator_deposit); + T::Currency::unreserve(curator, bounty.curator_deposit); debug_assert!(err_amount.is_zero()); // Then execute removal of the bounty below. }, diff --git a/frame/child-bounties/src/benchmarking.rs b/frame/child-bounties/src/benchmarking.rs index d9edf14bbc9d7..dcb54361fac89 100644 --- a/frame/child-bounties/src/benchmarking.rs +++ b/frame/child-bounties/src/benchmarking.rs @@ -110,7 +110,7 @@ fn activate_bounty( Bounties::::propose_curator( RawOrigin::Root.into(), child_bounty_setup.bounty_id, - curator_lookup.clone(), + curator_lookup, child_bounty_setup.fee, )?; Bounties::::accept_curator( @@ -141,7 +141,7 @@ fn activate_child_bounty( RawOrigin::Signed(bounty_setup.curator.clone()).into(), bounty_setup.bounty_id, bounty_setup.child_bounty_id, - child_curator_lookup.clone(), + child_curator_lookup, bounty_setup.child_bounty_fee, )?; @@ -211,7 +211,7 @@ benchmarks! { RawOrigin::Signed(bounty_setup.curator.clone()).into(), bounty_setup.bounty_id, bounty_setup.child_bounty_id, - child_curator_lookup.clone(), + child_curator_lookup, bounty_setup.child_bounty_fee, )?; }: _(RawOrigin::Signed(bounty_setup.child_curator), bounty_setup.bounty_id, @@ -246,7 +246,7 @@ benchmarks! { setup_pot_account::(); let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; let beneficiary_account: T::AccountId = account("beneficiary", 0, SEED); - let beneficiary = T::Lookup::unlookup(beneficiary_account.clone()); + let beneficiary = T::Lookup::unlookup(beneficiary_account); ChildBounties::::award_child_bounty( RawOrigin::Signed(bounty_setup.child_curator.clone()).into(), diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 0bbd4512443d7..a8496d4e7af91 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -512,7 +512,7 @@ pub mod pallet { Some(sender) if sender == *curator => { // This is the child-bounty curator, willingly giving up their // role. Give back their deposit. - T::Currency::unreserve(&curator, child_bounty.curator_deposit); + T::Currency::unreserve(curator, child_bounty.curator_deposit); // Reset curator deposit. child_bounty.curator_deposit = Zero::zero(); // Continue to change bounty status below. @@ -673,13 +673,13 @@ pub mod pallet { // Unreserve the curator deposit. Should not fail // because the deposit is always reserved when curator is // assigned. - let _ = T::Currency::unreserve(&curator, child_bounty.curator_deposit); + let _ = T::Currency::unreserve(curator, child_bounty.curator_deposit); // Make payout to child-bounty curator. // Should not fail because curator fee is always less than bounty value. let fee_transfer_result = T::Currency::transfer( &child_bounty_account, - &curator, + curator, curator_fee, AllowDeath, ); diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index d5d0fc5f263e2..076afcd203030 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -250,7 +250,7 @@ benchmarks_instance_pallet! { let approve = true; Collective::::vote( SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), + last_hash, index, approve, )?; @@ -259,7 +259,7 @@ benchmarks_instance_pallet! { let approve = true; Collective::::vote( SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), + last_hash, index, approve, )?; @@ -272,7 +272,7 @@ benchmarks_instance_pallet! { // Whitelist voter account from further DB operations. let voter_key = frame_system::Account::::hashed_key_for(&voter); frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into()); - }: _(SystemOrigin::Signed(voter), last_hash.clone(), index, approve) + }: _(SystemOrigin::Signed(voter), last_hash, index, approve) verify { // All proposals exist and the last proposal has just been updated. assert_eq!(Collective::::proposals().len(), p as usize); @@ -327,7 +327,7 @@ benchmarks_instance_pallet! { let approve = true; Collective::::vote( SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), + last_hash, index, approve, )?; @@ -336,7 +336,7 @@ benchmarks_instance_pallet! { let approve = true; Collective::::vote( SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), + last_hash, index, approve, )?; @@ -347,7 +347,7 @@ benchmarks_instance_pallet! { let approve = false; Collective::::vote( SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), + last_hash, index, approve, )?; @@ -355,7 +355,7 @@ benchmarks_instance_pallet! { // Whitelist voter account from further DB operations. let voter_key = frame_system::Account::::hashed_key_for(&voter); frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into()); - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::max_value(), bytes_in_storage) + }: close(SystemOrigin::Signed(voter), last_hash, index, Weight::max_value(), bytes_in_storage) verify { // The last proposal is removed. assert_eq!(Collective::::proposals().len(), (p - 1) as usize); @@ -400,7 +400,7 @@ benchmarks_instance_pallet! { // Caller switches vote to nay on their own proposal, allowing them to be the deciding approval vote Collective::::vote( SystemOrigin::Signed(caller.clone()).into(), - last_hash.clone(), + last_hash, p - 1, false, )?; @@ -411,7 +411,7 @@ benchmarks_instance_pallet! { let approve = false; Collective::::vote( SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), + last_hash, p - 1, approve, )?; @@ -420,7 +420,7 @@ benchmarks_instance_pallet! { // Member zero is the first aye Collective::::vote( SystemOrigin::Signed(members[0].clone()).into(), - last_hash.clone(), + last_hash, p - 1, true, )?; @@ -432,11 +432,11 @@ benchmarks_instance_pallet! { let approve = true; Collective::::vote( SystemOrigin::Signed(caller.clone()).into(), - last_hash.clone(), + last_hash, index, approve, )?; - }: close(SystemOrigin::Signed(caller), last_hash.clone(), index, Weight::max_value(), bytes_in_storage) + }: close(SystemOrigin::Signed(caller), last_hash, index, Weight::max_value(), bytes_in_storage) verify { // The last proposal is removed. assert_eq!(Collective::::proposals().len(), (p - 1) as usize); @@ -493,7 +493,7 @@ benchmarks_instance_pallet! { let approve = true; Collective::::vote( SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), + last_hash, index, approve, )?; @@ -502,7 +502,7 @@ benchmarks_instance_pallet! { // caller is prime, prime votes nay Collective::::vote( SystemOrigin::Signed(caller.clone()).into(), - last_hash.clone(), + last_hash, index, false, )?; @@ -560,7 +560,7 @@ benchmarks_instance_pallet! { // The prime member votes aye, so abstentions default to aye. Collective::::vote( SystemOrigin::Signed(caller.clone()).into(), - last_hash.clone(), + last_hash, p - 1, true // Vote aye. )?; @@ -572,7 +572,7 @@ benchmarks_instance_pallet! { let approve = false; Collective::::vote( SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), + last_hash, p - 1, approve )?; diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 2544fd6b7f922..5f9b43d3e3b7a 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -277,15 +277,14 @@ where } module }; - let limits = module + let limits = *module .import_section() .unwrap() .entries() .iter() .find_map(|e| if let External::Memory(mem) = e.external() { Some(mem) } else { None }) .unwrap() - .limits() - .clone(); + .limits(); let code = module.to_bytes().unwrap(); let hash = T::Hashing::hash(&code); let memory = @@ -512,16 +511,10 @@ pub mod body { DynInstr::RandomI32(low, high) => { vec![Instruction::I32Const(rng.gen_range(*low..*high))] }, - DynInstr::RandomI32Repeated(num) => (&mut rng) - .sample_iter(Standard) - .take(*num) - .map(|val| Instruction::I32Const(val)) - .collect(), - DynInstr::RandomI64Repeated(num) => (&mut rng) - .sample_iter(Standard) - .take(*num) - .map(|val| Instruction::I64Const(val)) - .collect(), + DynInstr::RandomI32Repeated(num) => + (&mut rng).sample_iter(Standard).take(*num).map(Instruction::I32Const).collect(), + DynInstr::RandomI64Repeated(num) => + (&mut rng).sample_iter(Standard).take(*num).map(Instruction::I64Const).collect(), DynInstr::RandomGetLocal(low, high) => { vec![Instruction::GetLocal(rng.gen_range(*low..*high))] }, diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index e67436fbc9d37..84f4cb6083e5f 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -138,7 +138,7 @@ where Storage::::write(&info.trie_id, &item.0, Some(item.1.clone()), None, false) .map_err(|_| "Failed to write storage to restoration dest")?; } - >::insert(&self.account_id, info.clone()); + >::insert(&self.account_id, info); Ok(()) } @@ -253,7 +253,7 @@ benchmarks! { )?; let value = T::Currency::minimum_balance(); let origin = RawOrigin::Signed(instance.caller.clone()); - let callee = instance.addr.clone(); + let callee = instance.addr; }: call(origin, callee, value, Weight::MAX, None, vec![]) // This constructs a contract that is maximal expensive to instrument. @@ -1067,7 +1067,7 @@ benchmarks! { ) .map_err(|_| "Failed to write to storage during setup.")?; } - >::insert(&instance.account_id, info.clone()); + >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1164,7 +1164,7 @@ benchmarks! { ) .map_err(|_| "Failed to write to storage during setup.")?; } - >::insert(&instance.account_id, info.clone()); + >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1216,7 +1216,7 @@ benchmarks! { ) .map_err(|_| "Failed to write to storage during setup.")?; } - >::insert(&instance.account_id, info.clone()); + >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1263,7 +1263,7 @@ benchmarks! { ) .map_err(|_| "Failed to write to storage during setup.")?; } - >::insert(&instance.account_id, info.clone()); + >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1308,7 +1308,7 @@ benchmarks! { ) .map_err(|_| "Failed to write to storage during setup.")?; } - >::insert(&instance.account_id, info.clone()); + >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1360,7 +1360,7 @@ benchmarks! { ) .map_err(|_| "Failed to write to storage during setup.")?; } - >::insert(&instance.account_id, info.clone()); + >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1412,7 +1412,7 @@ benchmarks! { ) .map_err(|_| "Failed to write to storage during setup.")?; } - >::insert(&instance.account_id, info.clone()); + >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1577,7 +1577,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let callee = instance.addr.clone(); - let origin = RawOrigin::Signed(instance.caller.clone()); + let origin = RawOrigin::Signed(instance.caller); }: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]) seal_call_per_transfer_clone_kb { @@ -1739,7 +1739,7 @@ benchmarks! { .collect::>(); for addr in &addresses { - if let Some(_) = ContractInfoOf::::get(&addr) { + if ContractInfoOf::::get(&addr).is_some() { return Err("Expected that contract does not exist at this point.".into()); } } @@ -1747,7 +1747,7 @@ benchmarks! { verify { for addr in &addresses { ContractInfoOf::::get(&addr) - .ok_or_else(|| "Contract should have been instantiated")?; + .ok_or("Contract should have been instantiated")?; } } @@ -1755,7 +1755,7 @@ benchmarks! { let t in 0 .. 1; let s in 0 .. (code::max_pages::() - 1) * 64; let callee_code = WasmModule::::dummy(); - let hash = callee_code.hash.clone(); + let hash = callee_code.hash; let hash_bytes = callee_code.hash.encode(); let hash_len = hash_bytes.len(); Contracts::::store_code_raw(callee_code.code, whitelisted_caller())?; diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 54a5223b53d21..e3ff4788791a5 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -610,7 +610,7 @@ where debug_message: Option<&'a mut Vec>, ) -> Result<(Self, E), ExecError> { let (first_frame, executable, nonce) = - Self::new_frame(args, value, gas_meter, storage_meter, 0, &schedule)?; + Self::new_frame(args, value, gas_meter, storage_meter, 0, schedule)?; let stack = Self { origin, schedule, @@ -660,13 +660,10 @@ where }, FrameArgs::Instantiate { sender, nonce, executable, salt } => { let account_id = - >::contract_address(&sender, executable.code_hash(), &salt); + >::contract_address(&sender, executable.code_hash(), salt); let trie_id = Storage::::generate_trie_id(&account_id, nonce); - let contract = Storage::::new_contract( - &account_id, - trie_id, - executable.code_hash().clone(), - )?; + let contract = + Storage::::new_contract(&account_id, trie_id, *executable.code_hash())?; ( account_id, contract, @@ -742,7 +739,7 @@ where top_frame.nested_storage.charge_instantiate( &self.origin, &top_frame.account_id, - &mut top_frame.contract_info.get(&top_frame.account_id), + top_frame.contract_info.get(&top_frame.account_id), )?; } @@ -1020,11 +1017,11 @@ where code_hash: CodeHash, input_data: Vec, ) -> Result { - let executable = E::from_storage(code_hash, &self.schedule, self.gas_meter())?; + let executable = E::from_storage(code_hash, self.schedule, self.gas_meter())?; let top_frame = self.top_frame_mut(); let contract_info = top_frame.contract_info().clone(); let account_id = top_frame.account_id.clone(); - let value = top_frame.value_transferred.clone(); + let value = top_frame.value_transferred; let executable = self.push_frame( FrameArgs::Call { dest: account_id, @@ -1045,7 +1042,7 @@ where input_data: Vec, salt: &[u8], ) -> Result<(AccountIdOf, ExecReturnValue), ExecError> { - let executable = E::from_storage(code_hash, &self.schedule, self.gas_meter())?; + let executable = E::from_storage(code_hash, self.schedule, self.gas_meter())?; let nonce = self.next_nonce(); let executable = self.push_frame( FrameArgs::Instantiate { @@ -1118,7 +1115,7 @@ where fn caller(&self) -> &T::AccountId { if let Some(caller) = &self.top_frame().delegate_caller { - &caller + caller } else { self.frames().nth(1).map(|f| &f.account_id).unwrap_or(&self.origin) } @@ -1180,7 +1177,7 @@ where } fn schedule(&self) -> &Schedule { - &self.schedule + self.schedule } fn gas_meter(&mut self) -> &mut GasMeter { @@ -1205,7 +1202,7 @@ where } fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()> { - secp256k1_ecdsa_recover_compressed(&signature, &message_hash).map_err(|_| ()) + secp256k1_ecdsa_recover_compressed(signature, message_hash).map_err(|_| ()) } fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()> { @@ -1220,8 +1217,8 @@ where fn set_code_hash(&mut self, hash: CodeHash) -> Result<(), DispatchError> { E::add_user(hash)?; let top_frame = self.top_frame_mut(); - let prev_hash = top_frame.contract_info().code_hash.clone(); - E::remove_user(prev_hash.clone()); + let prev_hash = top_frame.contract_info().code_hash; + E::remove_user(prev_hash); top_frame.contract_info().code_hash = hash; Contracts::::deposit_event(Event::ContractCodeUpdated { contract: top_frame.account_id.clone(), diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index cdf0c1407c6bd..41df125da0170 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -114,7 +114,7 @@ where if self.gas_left < amount { Err(>::OutOfGas.into()) } else { - self.gas_left = self.gas_left - amount; + self.gas_left -= amount; Ok(GasMeter::new(amount)) } } diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index bbbeb72f2cdf6..9e9f213fabb76 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -670,7 +670,7 @@ struct ScheduleRules<'a, T: Config> { impl Schedule { pub(crate) fn rules(&self, module: &elements::Module) -> impl gas_metering::Rules + '_ { ScheduleRules { - schedule: &self, + schedule: self, params: module .type_section() .iter() diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 17022e9427664..2bdacc15cb11f 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -154,10 +154,10 @@ where let hashed_key = blake2_256(key); let child_trie_info = &child_trie_info(trie_id); let (old_len, old_value) = if take { - let val = child::get_raw(&child_trie_info, &hashed_key); + let val = child::get_raw(child_trie_info, &hashed_key); (val.as_ref().map(|v| v.len() as u32), val) } else { - (child::len(&child_trie_info, &hashed_key), None) + (child::len(child_trie_info, &hashed_key), None) }; if let Some(storage_meter) = storage_meter { @@ -183,8 +183,8 @@ where } match &new_value { - Some(new_value) => child::put_raw(&child_trie_info, &hashed_key, new_value), - None => child::kill(&child_trie_info, &hashed_key), + Some(new_value) => child::put_raw(child_trie_info, &hashed_key, new_value), + None => child::kill(child_trie_info, &hashed_key), } Ok(match (old_len, old_value) { diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index 28dc3356f7143..af51a5edc9472 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -230,7 +230,7 @@ where self.total_deposit = self.total_deposit.saturating_add(&absorbed.total_deposit); if !absorbed.own_deposit.is_zero() { - E::charge(origin, &contract, &absorbed.own_deposit, absorbed.terminated); + E::charge(origin, contract, &absorbed.own_deposit, absorbed.terminated); } } @@ -255,7 +255,7 @@ where limit: Option>, min_leftover: BalanceOf, ) -> Result { - let limit = E::check_limit(&origin, limit, min_leftover)?; + let limit = E::check_limit(origin, limit, min_leftover)?; Ok(Self { limit, ..Default::default() }) } diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index ee5cdd5307214..ca91fa3131474 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -165,8 +165,7 @@ where { let charged = gas_meter.charge(CodeToken::Load(schedule.limits.code_len))?; - let mut prefab_module = - >::get(code_hash).ok_or_else(|| Error::::CodeNotFound)?; + let mut prefab_module = >::get(code_hash).ok_or(Error::::CodeNotFound)?; gas_meter.adjust_gas(charged, CodeToken::Load(prefab_module.code.len() as u32)); prefab_module.code_hash = code_hash; @@ -189,7 +188,7 @@ pub fn reinstrument( schedule: &Schedule, ) -> Result { let original_code = - >::get(&prefab_module.code_hash).ok_or_else(|| Error::::CodeNotFound)?; + >::get(&prefab_module.code_hash).ok_or(Error::::CodeNotFound)?; let original_code_len = original_code.len(); prefab_module.code = prepare::reinstrument_contract::(original_code, schedule)?; prefab_module.instruction_weights_version = schedule.instruction_weights.version; diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 4571d752a80c6..6e9babe1264ed 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -225,10 +225,7 @@ impl<'a, T: Config> ContractModule<'a, T> { .map(|is| is.entries()) .unwrap_or(&[]) .iter() - .filter(|entry| match *entry.external() { - External::Function(_) => true, - _ => false, - }) + .filter(|entry| matches!(*entry.external(), External::Function(_))) .count(); for export in export_entries { @@ -259,11 +256,10 @@ impl<'a, T: Config> ContractModule<'a, T> { // We still support () -> (i32) for backwards compatibility. let func_ty_idx = func_entries .get(fn_idx as usize) - .ok_or_else(|| "export refers to non-existent function")? + .ok_or("export refers to non-existent function")? .type_ref(); - let Type::Function(ref func_ty) = types - .get(func_ty_idx as usize) - .ok_or_else(|| "function has a non-existent type")?; + let Type::Function(ref func_ty) = + types.get(func_ty_idx as usize).ok_or("function has a non-existent type")?; if !(func_ty.params().is_empty() && (func_ty.results().is_empty() || func_ty.results() == [ValueType::I32])) { @@ -300,11 +296,11 @@ impl<'a, T: Config> ContractModule<'a, T> { let mut imported_mem_type = None; for import in import_entries { - let type_idx = match import.external() { - &External::Table(_) => return Err("Cannot import tables"), - &External::Global(_) => return Err("Cannot import globals"), - &External::Function(ref type_idx) => type_idx, - &External::Memory(ref memory_type) => { + let type_idx = match *import.external() { + External::Table(_) => return Err("Cannot import tables"), + External::Global(_) => return Err("Cannot import globals"), + External::Function(ref type_idx) => type_idx, + External::Memory(ref memory_type) => { if import.module() != IMPORT_MODULE_MEMORY { return Err("Invalid module for imported memory") } @@ -321,7 +317,7 @@ impl<'a, T: Config> ContractModule<'a, T> { let Type::Function(ref func_ty) = types .get(*type_idx as usize) - .ok_or_else(|| "validation: import entry points to a non-existent type")?; + .ok_or("validation: import entry points to a non-existent type")?; if !T::ChainExtension::enabled() && import.field().as_bytes() == b"seal_call_chain_extension" @@ -352,17 +348,15 @@ fn get_memory_limits( let limits = memory_type.limits(); match (limits.initial(), limits.maximum()) { (initial, Some(maximum)) if initial > maximum => - return Err( - "Requested initial number of pages should not exceed the requested maximum", - ), + Err("Requested initial number of pages should not exceed the requested maximum"), (_, Some(maximum)) if maximum > schedule.limits.memory_pages => - return Err("Maximum number of pages should not exceed the configured maximum."), + Err("Maximum number of pages should not exceed the configured maximum."), (initial, Some(maximum)) => Ok((initial, maximum)), (_, None) => { // Maximum number of pages should be always declared. // This isn't a hard requirement and can be treated as a maximum set // to configured maximum. - return Err("Maximum number of pages should be always declared.") + Err("Maximum number of pages should be always declared.") }, } } else { @@ -377,7 +371,7 @@ fn check_and_instrument( schedule: &Schedule, ) -> Result<(Vec, (u32, u32)), &'static str> { let result = (|| { - let contract_module = ContractModule::new(&original_code, schedule)?; + let contract_module = ContractModule::new(original_code, schedule)?; contract_module.scan_exports()?; contract_module.ensure_no_internal_memory()?; contract_module.ensure_table_size_limit(schedule.limits.table_size)?; diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 876bd8848b0b1..7719d512b8aba 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -460,13 +460,13 @@ where return match trap_reason { // The trap was the result of the execution `return` host function. TrapReason::Return(ReturnData { flags, data }) => { - let flags = ReturnFlags::from_bits(flags) - .ok_or_else(|| Error::::InvalidCallFlags)?; + let flags = + ReturnFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?; Ok(ExecReturnValue { flags, data: Bytes(data) }) }, TrapReason::Termination => Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }), - TrapReason::SupervisorError(error) => Err(error)?, + TrapReason::SupervisorError(error) => return Err(error.into()), } } @@ -480,10 +480,10 @@ where // // Because panics are really undesirable in the runtime code, we treat this as // a trap for now. Eventually, we might want to revisit this. - Err(sp_sandbox::Error::Module) => Err("validation error")?, + Err(sp_sandbox::Error::Module) => return Err("validation error".into()), // Any other kind of a trap should result in a failure. Err(sp_sandbox::Error::Execution) | Err(sp_sandbox::Error::OutOfBounds) => - Err(Error::::ContractTrapped)?, + return Err(Error::::ContractTrapped.into()), } } @@ -620,7 +620,7 @@ where let len: u32 = self.read_sandbox_memory_as(out_len_ptr)?; if len < buf_len { - Err(Error::::OutputBufferTooSmall)? + return Err(Error::::OutputBufferTooSmall.into()) } if let Some(costs) = create_token(buf_len) { @@ -717,7 +717,7 @@ where let charged = self .charge_gas(RuntimeCosts::SetStorage { new_bytes: value_len, old_bytes: max_size })?; if value_len > max_size { - Err(Error::::ValueTooLarge)?; + return Err(Error::::ValueTooLarge.into()) } let mut key: StorageKey = [0; 32]; self.read_sandbox_memory_into_buf(key_ptr, &mut key)?; @@ -750,11 +750,11 @@ where ) -> Result { self.charge_gas(call_type.cost())?; let input_data = if flags.contains(CallFlags::CLONE_INPUT) { - let input = self.input_data.as_ref().ok_or_else(|| Error::::InputForwarded)?; + let input = self.input_data.as_ref().ok_or(Error::::InputForwarded)?; charge_gas!(self, RuntimeCosts::CallInputCloned(input.len() as u32))?; input.clone() } else if flags.contains(CallFlags::FORWARD_INPUT) { - self.input_data.take().ok_or_else(|| Error::::InputForwarded)? + self.input_data.take().ok_or(Error::::InputForwarded)? } else { self.charge_gas(RuntimeCosts::CopyFromContract(input_data_len))?; self.read_sandbox_memory(input_data_ptr, input_data_len)? @@ -1108,7 +1108,7 @@ define_env!(Env, , output_len_ptr: u32 ) -> ReturnCode => { ctx.call( - CallFlags::from_bits(flags).ok_or_else(|| Error::::InvalidCallFlags)?, + CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, CallType::Call{callee_ptr, value_ptr, gas}, input_data_ptr, input_data_len, @@ -1151,7 +1151,7 @@ define_env!(Env, , output_len_ptr: u32 ) -> ReturnCode => { ctx.call( - CallFlags::from_bits(flags).ok_or_else(|| Error::::InvalidCallFlags)?, + CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, CallType::DelegateCall{code_hash_ptr}, input_data_ptr, input_data_len, @@ -1486,7 +1486,7 @@ define_env!(Env, , ctx.charge_gas(RuntimeCosts::GasLeft)?; let gas_left = &ctx.ext.gas_meter().gas_left().encode(); Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &gas_left, false, already_charged, + out_ptr, out_len_ptr, gas_left, false, already_charged, )?) }, @@ -1535,7 +1535,7 @@ define_env!(Env, , [seal0] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeCosts::Random)?; if subject_len > ctx.ext.schedule().limits.subject_len { - Err(Error::::RandomSubjectTooLong)?; + return Err(Error::::RandomSubjectTooLong.into()); } let subject_buf = ctx.read_sandbox_memory(subject_ptr, subject_len)?; Ok(ctx.write_sandbox_output( @@ -1567,7 +1567,7 @@ define_env!(Env, , [seal1] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeCosts::Random)?; if subject_len > ctx.ext.schedule().limits.subject_len { - Err(Error::::RandomSubjectTooLong)?; + return Err(Error::::RandomSubjectTooLong.into()); } let subject_buf = ctx.read_sandbox_memory(subject_ptr, subject_len)?; Ok(ctx.write_sandbox_output( @@ -1685,13 +1685,13 @@ define_env!(Env, , let num_topic = topics_len .checked_div(sp_std::mem::size_of::>() as u32) - .ok_or_else(|| "Zero sized topics are not allowed")?; + .ok_or("Zero sized topics are not allowed")?; ctx.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len, })?; if data_len > ctx.ext.max_value_size() { - Err(Error::::ValueTooLarge)?; + return Err(Error::::ValueTooLarge.into()); } let mut topics: Vec::::T>> = match topics_len { @@ -1701,14 +1701,14 @@ define_env!(Env, , // If there are more than `event_topics`, then trap. if topics.len() > ctx.ext.schedule().limits.event_topics as usize { - Err(Error::::TooManyTopics)?; + return Err(Error::::TooManyTopics.into()); } // Check for duplicate topics. If there are any, then trap. // Complexity O(n * log(n)) and no additional allocations. // This also sorts the topics. if has_duplicates(&mut topics) { - Err(Error::::DuplicateTopics)?; + return Err(Error::::DuplicateTopics.into()); } let event_data = ctx.read_sandbox_memory(data_ptr, data_len)?; @@ -1888,7 +1888,7 @@ define_env!(Env, , ) -> u32 => { use crate::chain_extension::{ChainExtension, Environment, RetVal}; if !::ChainExtension::enabled() { - Err(Error::::NoChainExtension)?; + return Err(Error::::NoChainExtension.into()); } let env = Environment::new(ctx, input_ptr, input_len, output_ptr, output_len_ptr); match ::ChainExtension::call(func_id, env)? { diff --git a/frame/conviction-voting/src/benchmarking.rs b/frame/conviction-voting/src/benchmarking.rs index 2beee4f3b49d2..53ac7a07302f9 100644 --- a/frame/conviction-voting/src/benchmarking.rs +++ b/frame/conviction-voting/src/benchmarking.rs @@ -44,7 +44,7 @@ fn fill_voting() -> (ClassOf, BTreeMap, Vec> } } } - let c = r.iter().max_by_key(|(_, ref v)| v.len()).unwrap().0.clone(); + let c = r.iter().max_by_key(|(_, v)| v.len()).unwrap().0.clone(); (c, r) } @@ -73,7 +73,7 @@ benchmarks! { let r = polls.len() - 1; // We need to create existing votes for i in polls.iter().skip(1) { - ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, account_vote.clone())?; + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, account_vote)?; } let votes = match VotingFor::::get(&caller, &class) { Voting::Casting(Casting { votes, .. }) => votes, @@ -100,7 +100,7 @@ benchmarks! { let r = polls.len(); // We need to create existing votes for i in polls.iter() { - ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote.clone())?; + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote)?; } let votes = match VotingFor::::get(&caller, &class) { Voting::Casting(Casting { votes, .. }) => votes, @@ -128,7 +128,7 @@ benchmarks! { let r = polls.len(); // We need to create existing votes for i in polls.iter() { - ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote.clone())?; + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote)?; } let votes = match VotingFor::::get(&caller, &class) { Voting::Casting(Casting { votes, .. }) => votes, @@ -156,7 +156,7 @@ benchmarks! { let r = polls.len(); // We need to create existing votes for i in polls.iter() { - ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, old_account_vote.clone())?; + ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, old_account_vote)?; } let votes = match VotingFor::::get(&caller, &class) { Voting::Casting(Casting { votes, .. }) => votes, @@ -189,14 +189,14 @@ benchmarks! { // We need to create existing delegations for i in polls.iter().take(r as usize) { - ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote.clone())?; + ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote)?; } assert_matches!( VotingFor::::get(&voter, &class), Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize ); - }: _(RawOrigin::Signed(caller.clone()), class.clone(), voter.clone(), Conviction::Locked1x, delegated_balance) + }: _(RawOrigin::Signed(caller.clone()), class.clone(), voter, Conviction::Locked1x, delegated_balance) verify { assert_matches!(VotingFor::::get(&caller, &class), Voting::Delegating(_)); } @@ -224,7 +224,7 @@ benchmarks! { // We need to create delegations for i in polls.iter().take(r as usize) { - ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote.clone())?; + ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote)?; } assert_matches!( VotingFor::::get(&voter, &class), @@ -248,7 +248,7 @@ benchmarks! { for (class, polls) in all_polls.iter() { assert!(polls.len() > 0); for i in polls.iter() { - ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, normal_account_vote.clone())?; + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, normal_account_vote)?; } } @@ -257,7 +257,7 @@ benchmarks! { // Vote big on the class with the most ongoing votes of them to bump the lock and make it // hard to recompute when removed. - ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), polls[0], big_account_vote.clone())?; + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), polls[0], big_account_vote)?; let now_usable = >::reducible_balance(&caller, false); assert_eq!(orig_usable - now_usable, 100u32.into()); diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index af91e99fb3796..58ac76dac3a3e 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -553,7 +553,8 @@ impl, I: 'static> Pallet { }), ); match old { - Voting::Delegating(Delegating { .. }) => Err(Error::::AlreadyDelegating)?, + Voting::Delegating(Delegating { .. }) => + return Err(Error::::AlreadyDelegating.into()), Voting::Casting(Casting { votes, delegations, prior }) => { // here we just ensure that we're currently idling with no votes recorded. ensure!(votes.is_empty(), Error::::AlreadyVoting); diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index bce830b385a9f..c51fde8a3de8b 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -52,7 +52,7 @@ fn add_proposal(n: u32) -> Result { let value = T::MinimumDeposit::get(); let proposal_hash: T::Hash = T::Hashing::hash_of(&n); - Democracy::::propose(RawOrigin::Signed(other).into(), proposal_hash, value.into())?; + Democracy::::propose(RawOrigin::Signed(other).into(), proposal_hash, value)?; Ok(proposal_hash) } @@ -98,7 +98,7 @@ benchmarks! { let proposal_hash: T::Hash = T::Hashing::hash_of(&0); let value = T::MinimumDeposit::get(); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), proposal_hash, value.into()) + }: _(RawOrigin::Signed(caller), proposal_hash, value) verify { assert_eq!(Democracy::::public_props().len(), p as usize, "Proposals not created."); } @@ -133,7 +133,7 @@ benchmarks! { // We need to create existing direct votes for i in 0 .. r { let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote.clone())?; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; } let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, @@ -161,7 +161,7 @@ benchmarks! { // We need to create existing direct votes for i in 0 ..=r { let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote.clone())?; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; } let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, @@ -217,7 +217,7 @@ benchmarks! { // Place our proposal in the external queue, too. let hash = T::Hashing::hash_of(&0); assert_ok!( - Democracy::::external_propose(T::ExternalOrigin::successful_origin(), hash.clone()) + Democracy::::external_propose(T::ExternalOrigin::successful_origin(), hash) ); let origin = T::BlacklistOrigin::successful_origin(); // Add a referendum of our proposal. @@ -275,13 +275,13 @@ benchmarks! { fast_track { let origin_propose = T::ExternalDefaultOrigin::successful_origin(); let proposal_hash: T::Hash = T::Hashing::hash_of(&0); - Democracy::::external_propose_default(origin_propose, proposal_hash.clone())?; + Democracy::::external_propose_default(origin_propose, proposal_hash)?; // NOTE: Instant origin may invoke a little bit more logic, but may not always succeed. let origin_fast_track = T::FastTrackOrigin::successful_origin(); let voting_period = T::FastTrackVotingPeriod::get(); let delay = 0u32; - }: _(origin_fast_track, proposal_hash, voting_period.into(), delay.into()) + }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) verify { assert_eq!(Democracy::::referendum_count(), 1, "referendum not created") } @@ -293,7 +293,7 @@ benchmarks! { let proposal_hash: T::Hash = T::Hashing::hash_of(&v); let origin_propose = T::ExternalDefaultOrigin::successful_origin(); - Democracy::::external_propose_default(origin_propose, proposal_hash.clone())?; + Democracy::::external_propose_default(origin_propose, proposal_hash)?; let mut vetoers: Vec = Vec::new(); for i in 0 .. v { @@ -499,7 +499,7 @@ benchmarks! { // We need to create existing direct votes for the `new_delegate` for i in 0..r { let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_idx, account_vote.clone())?; + Democracy::::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_idx, account_vote)?; } let votes = match VotingOf::::get(&new_delegate) { Voting::Direct { votes, .. } => votes, @@ -550,7 +550,7 @@ benchmarks! { Democracy::::vote( RawOrigin::Signed(the_delegate.clone()).into(), ref_idx, - account_vote.clone() + account_vote )?; } let votes = match VotingOf::::get(&the_delegate) { @@ -619,17 +619,17 @@ benchmarks! { let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); let submitter = funded_account::("submitter", b); - Democracy::::note_preimage(RawOrigin::Signed(submitter.clone()).into(), encoded_proposal.clone())?; + Democracy::::note_preimage(RawOrigin::Signed(submitter).into(), encoded_proposal.clone())?; // We need to set this otherwise we get `Early` error. let block_number = T::VotingPeriod::get() + T::EnactmentPeriod::get() + T::BlockNumber::one(); - System::::set_block_number(block_number.into()); + System::::set_block_number(block_number); assert!(Preimages::::contains_key(proposal_hash)); let caller = funded_account::("caller", 0); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), proposal_hash.clone(), u32::MAX) + }: _(RawOrigin::Signed(caller), proposal_hash, u32::MAX) verify { let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); assert!(!Preimages::::contains_key(proposal_hash)); @@ -646,7 +646,7 @@ benchmarks! { // Vote and immediately unvote for i in 0 .. r { let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote.clone())?; + Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote)?; Democracy::::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_idx)?; } @@ -669,7 +669,7 @@ benchmarks! { let small_vote = account_vote::(base_balance); for i in 0 .. r { let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote.clone())?; + Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote)?; } // Create a big vote so lock increases @@ -711,7 +711,7 @@ benchmarks! { for i in 0 .. r { let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote.clone())?; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; } let votes = match VotingOf::::get(&caller) { @@ -740,7 +740,7 @@ benchmarks! { for i in 0 .. r { let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote.clone())?; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; } let votes = match VotingOf::::get(&caller) { diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 8588f1876d7e3..91362a0a3edf7 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -670,8 +670,7 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; - let seconds = - Self::len_of_deposit_of(proposal).ok_or_else(|| Error::::ProposalMissing)?; + let seconds = Self::len_of_deposit_of(proposal).ok_or(Error::::ProposalMissing)?; ensure!(seconds <= seconds_upper_bound, Error::::WrongUpperBound); let mut deposit = Self::deposit_of(proposal).ok_or(Error::::ProposalMissing)?; T::Currency::reserve(&who, deposit.1)?; @@ -820,12 +819,10 @@ pub mod pallet { // - `InstantAllowed` is `true` and `origin` is `InstantOrigin`. let maybe_ensure_instant = if voting_period < T::FastTrackVotingPeriod::get() { Some(origin) + } else if let Err(origin) = T::FastTrackOrigin::try_origin(origin) { + Some(origin) } else { - if let Err(origin) = T::FastTrackOrigin::try_origin(origin) { - Some(origin) - } else { - None - } + None }; if let Some(ensure_instant) = maybe_ensure_instant { T::InstantOrigin::ensure_origin(ensure_instant)?; @@ -867,7 +864,7 @@ pub mod pallet { if let Some((e_proposal_hash, _)) = >::get() { ensure!(proposal_hash == e_proposal_hash, Error::::ProposalMissing); } else { - Err(Error::::NoProposal)?; + return Err(Error::::NoProposal.into()) } let mut existing_vetoers = @@ -966,7 +963,7 @@ pub mod pallet { /// voted on. Weight is charged as if maximum votes. // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure // because a valid delegation cover decoding a direct voting with max votes. - #[pallet::weight(T::WeightInfo::undelegate(T::MaxVotes::get().into()))] + #[pallet::weight(T::WeightInfo::undelegate(T::MaxVotes::get()))] pub fn undelegate(origin: OriginFor) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let votes = Self::try_undelegate(who)?; @@ -1634,7 +1631,7 @@ impl Pallet { ); Ok(()) } else { - Err(Error::::NoneWaiting)? + return Err(Error::::NoneWaiting.into()) } } @@ -1667,7 +1664,7 @@ impl Pallet { } Ok(()) } else { - Err(Error::::NoneWaiting)? + return Err(Error::::NoneWaiting.into()) } } @@ -1822,8 +1819,7 @@ impl Pallet { // To decode the enum variant we only need the first byte. let mut buf = [0u8; 1]; let key = >::hashed_key_for(proposal_hash); - let bytes = - sp_io::storage::read(&key, &mut buf, 0).ok_or_else(|| Error::::NotImminent)?; + let bytes = sp_io::storage::read(&key, &mut buf, 0).ok_or(Error::::NotImminent)?; // The value may be smaller that 1 byte. let mut input = &buf[0..buf.len().min(bytes as usize)]; @@ -1851,8 +1847,7 @@ impl Pallet { // * at most 5 bytes to decode a `Compact` let mut buf = [0u8; 6]; let key = >::hashed_key_for(proposal_hash); - let bytes = - sp_io::storage::read(&key, &mut buf, 0).ok_or_else(|| Error::::PreimageMissing)?; + let bytes = sp_io::storage::read(&key, &mut buf, 0).ok_or(Error::::PreimageMissing)?; // The value may be smaller that 6 bytes. let mut input = &buf[0..buf.len().min(bytes as usize)]; @@ -1931,7 +1926,7 @@ impl Pallet { fn decode_compact_u32_at(key: &[u8]) -> Option { // `Compact` takes at most 5 bytes. let mut buf = [0u8; 5]; - let bytes = sp_io::storage::read(&key, &mut buf, 0)?; + let bytes = sp_io::storage::read(key, &mut buf, 0)?; // The value may be smaller than 5 bytes. let mut input = &buf[0..buf.len().min(bytes as usize)]; match codec::Compact::::decode(&mut input) { diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 6dfb2ac794810..a1c643754158b 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -491,7 +491,7 @@ frame_benchmarking::benchmarks! { // sort assignments by decreasing voter stake assignments.sort_by_key(|crate::unsigned::Assignment:: { who, .. }| { - let stake = cache.get(&who).map(|idx| { + let stake = cache.get(who).map(|idx| { let (_, stake, _) = voters[*idx]; stake }).unwrap_or_default(); diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index a9e341bad600f..4aea5b9da4794 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -264,7 +264,7 @@ mod mock; #[macro_use] pub mod helpers; -const LOG_TARGET: &'static str = "runtime::election-provider"; +const LOG_TARGET: &str = "runtime::election-provider"; pub mod signed; pub mod unsigned; @@ -1446,7 +1446,7 @@ impl Pallet { ensure!(winners.len() as u32 == desired_targets, FeasibilityError::WrongWinnerCount); // Ensure that the solution's score can pass absolute min-score. - let submitted_score = raw_solution.score.clone(); + let submitted_score = raw_solution.score; ensure!( Self::minimum_untrusted_score().map_or(true, |min_score| { submitted_score.strict_threshold_better(min_score, Perbill::zero()) @@ -1471,29 +1471,26 @@ impl Pallet { .map_err::(Into::into)?; // Ensure that assignments is correct. - let _ = assignments - .iter() - .map(|ref assignment| { - // Check that assignment.who is actually a voter (defensive-only). - // NOTE: while using the index map from `voter_index` is better than a blind linear - // search, this *still* has room for optimization. Note that we had the index when - // we did `solution -> assignment` and we lost it. Ideal is to keep the index - // around. - - // Defensive-only: must exist in the snapshot. - let snapshot_index = - voter_index(&assignment.who).ok_or(FeasibilityError::InvalidVoter)?; - // Defensive-only: index comes from the snapshot, must exist. - let (_voter, _stake, targets) = - snapshot_voters.get(snapshot_index).ok_or(FeasibilityError::InvalidVoter)?; - - // Check that all of the targets are valid based on the snapshot. - if assignment.distribution.iter().any(|(d, _)| !targets.contains(d)) { - return Err(FeasibilityError::InvalidVote) - } - Ok(()) - }) - .collect::>()?; + let _ = assignments.iter().try_for_each(|assignment| { + // Check that assignment.who is actually a voter (defensive-only). + // NOTE: while using the index map from `voter_index` is better than a blind linear + // search, this *still* has room for optimization. Note that we had the index when + // we did `solution -> assignment` and we lost it. Ideal is to keep the index + // around. + + // Defensive-only: must exist in the snapshot. + let snapshot_index = + voter_index(&assignment.who).ok_or(FeasibilityError::InvalidVoter)?; + // Defensive-only: index comes from the snapshot, must exist. + let (_voter, _stake, targets) = + snapshot_voters.get(snapshot_index).ok_or(FeasibilityError::InvalidVoter)?; + + // Check that all of the targets are valid based on the snapshot. + if assignment.distribution.iter().any(|(d, _)| !targets.contains(d)) { + return Err(FeasibilityError::InvalidVote) + } + Ok(()) + })?; // ----- Start building support. First, we need one more closure. let stake_of = helpers::stake_of_fn::(&snapshot_voters, &cache); diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index d184c3acfe91b..126dcb10416cc 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -99,7 +99,7 @@ impl From for MinerError { /// Save a given call into OCW storage. fn save_solution(call: &Call) -> Result<(), MinerError> { log!(debug, "saving a call to the offchain storage."); - let storage = StorageValueRef::persistent(&OFFCHAIN_CACHED_CALL); + let storage = StorageValueRef::persistent(OFFCHAIN_CACHED_CALL); match storage.mutate::<_, (), _>(|_| Ok(call.clone())) { Ok(_) => Ok(()), Err(MutateStorageError::ConcurrentModification(_)) => @@ -116,7 +116,7 @@ fn save_solution(call: &Call) -> Result<(), MinerError> { /// Get a saved solution from OCW storage if it exists. fn restore_solution() -> Result, MinerError> { - StorageValueRef::persistent(&OFFCHAIN_CACHED_CALL) + StorageValueRef::persistent(OFFCHAIN_CACHED_CALL) .get() .ok() .flatten() @@ -126,7 +126,7 @@ fn restore_solution() -> Result, MinerError> { /// Clear a saved solution from OCW storage. pub(super) fn kill_ocw_solution() { log!(debug, "clearing offchain call cache storage."); - let mut storage = StorageValueRef::persistent(&OFFCHAIN_CACHED_CALL); + let mut storage = StorageValueRef::persistent(OFFCHAIN_CACHED_CALL); storage.clear(); } @@ -135,14 +135,14 @@ pub(super) fn kill_ocw_solution() { /// After calling this, the next offchain worker is guaranteed to work, with respect to the /// frequency repeat. fn clear_offchain_repeat_frequency() { - let mut last_block = StorageValueRef::persistent(&OFFCHAIN_LAST_BLOCK); + let mut last_block = StorageValueRef::persistent(OFFCHAIN_LAST_BLOCK); last_block.clear(); } /// `true` when OCW storage contains a solution #[cfg(test)] fn ocw_solution_exists() -> bool { - matches!(StorageValueRef::persistent(&OFFCHAIN_CACHED_CALL).get::>(), Ok(Some(_))) + matches!(StorageValueRef::persistent(OFFCHAIN_CACHED_CALL).get::>(), Ok(Some(_))) } impl Pallet { @@ -206,9 +206,8 @@ impl Pallet { // get the solution, with a load of checks to ensure if submitted, IT IS ABSOLUTELY VALID. let (raw_solution, witness) = Self::mine_and_check()?; - let score = raw_solution.score.clone(); - let call: Call = - Call::submit_unsigned { raw_solution: Box::new(raw_solution), witness }.into(); + let score = raw_solution.score; + let call: Call = Call::submit_unsigned { raw_solution: Box::new(raw_solution), witness }; log!( debug, @@ -532,7 +531,7 @@ impl Pallet { // we found the right value - early exit the function. Ok(next) => return next, } - step = step / 2; + step /= 2; current_weight = weight_with(voters); } @@ -566,7 +565,7 @@ impl Pallet { /// is returned, `now` is written in storage and will be used in further calls as the baseline. pub fn ensure_offchain_repeat_frequency(now: T::BlockNumber) -> Result<(), MinerError> { let threshold = T::OffchainRepeat::get(); - let last_block = StorageValueRef::persistent(&OFFCHAIN_LAST_BLOCK); + let last_block = StorageValueRef::persistent(OFFCHAIN_LAST_BLOCK); let mutate_stat = last_block.mutate::<_, &'static str, _>( |maybe_head: Result, _>| { diff --git a/frame/election-provider-support/solution-type/src/lib.rs b/frame/election-provider-support/solution-type/src/lib.rs index 7c5cb960d2430..0a5c11e76dedb 100644 --- a/frame/election-provider-support/solution-type/src/lib.rs +++ b/frame/election-provider-support/solution-type/src/lib.rs @@ -153,7 +153,7 @@ fn check_attributes(input: ParseStream) -> syn::Result { if attrs.len() > 1 { let extra_attr = attrs.pop().expect("attributes vec with len > 1 can be popped"); return Err(syn::Error::new_spanned( - extra_attr.clone(), + extra_attr, "compact solution can accept only #[compact]", )) } @@ -164,7 +164,7 @@ fn check_attributes(input: ParseStream) -> syn::Result { if attr.path.is_ident("compact") { Ok(true) } else { - Err(syn::Error::new_spanned(attr.clone(), "compact solution can accept only #[compact]")) + Err(syn::Error::new_spanned(attr, "compact solution can accept only #[compact]")) } } diff --git a/frame/election-provider-support/solution-type/src/single_page.rs b/frame/election-provider-support/solution-type/src/single_page.rs index a20f0542984dc..a7ccf5085d2b1 100644 --- a/frame/election-provider-support/solution-type/src/single_page.rs +++ b/frame/election-provider-support/solution-type/src/single_page.rs @@ -33,7 +33,7 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { } = def; if count <= 2 { - Err(syn_err("cannot build solution struct with capacity less than 3."))? + return Err(syn_err("cannot build solution struct with capacity less than 3.")) } let single = { diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 37ea2fcc59091..69bd3025fa768 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -244,7 +244,7 @@ impl IndexAssignment>>() .or_invalid_index()?, }) diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 05e9df60c7fbe..493f20924203c 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -93,8 +93,7 @@ fn submit_candidates_with_self_vote( let stake = default_stake::(c); let _ = candidates .iter() - .map(|c| submit_voter::(c.clone(), vec![c.clone()], stake).map(|_| ())) - .collect::>()?; + .try_for_each(|c| submit_voter::(c.clone(), vec![c.clone()], stake).map(|_| ()))?; Ok(candidates) } diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index a59da9c20f809..270d3853e2ca5 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -503,7 +503,7 @@ pub mod pallet { let had_replacement = Self::remove_and_replace_member(&who, true)?; debug_assert_eq!(has_replacement, had_replacement); - Self::deposit_event(Event::MemberKicked { member: who.clone() }); + Self::deposit_event(Event::MemberKicked { member: who }); if !had_replacement { Self::do_phragmen(); @@ -782,7 +782,7 @@ impl Pallet { })?; let remaining_member_ids_sorted = - Self::members().into_iter().map(|x| x.who.clone()).collect::>(); + Self::members().into_iter().map(|x| x.who).collect::>(); let outgoing = &[who.clone()]; let maybe_current_prime = T::ChangeMembers::get_prime(); let return_value = match maybe_replacement { @@ -861,7 +861,7 @@ impl Pallet { /// Reads Members, RunnersUp, Candidates and Voting(who) from database. fn is_defunct_voter(votes: &[T::AccountId]) -> bool { votes.iter().all(|v| { - !Self::is_member(v) && !Self::is_runner_up(v) && !Self::is_candidate(v).is_ok() + !Self::is_member(v) && !Self::is_runner_up(v) && Self::is_candidate(v).is_err() }) } @@ -923,148 +923,156 @@ impl Pallet { let weight_candidates = candidates_and_deposit.len() as u32; let weight_voters = voters_and_votes.len() as u32; let weight_edges = num_edges; - let _ = sp_npos_elections::seq_phragmen( - num_to_elect, - candidate_ids, - voters_and_votes.clone(), - None, - ) - .map(|ElectionResult:: { winners, assignments: _ }| { - // this is already sorted by id. - let old_members_ids_sorted = - >::take().into_iter().map(|m| m.who).collect::>(); - // this one needs a sort by id. - let mut old_runners_up_ids_sorted = - >::take().into_iter().map(|r| r.who).collect::>(); - old_runners_up_ids_sorted.sort(); - - // filter out those who end up with no backing stake. - let mut new_set_with_stake = winners - .into_iter() - .filter_map(|(m, b)| if b.is_zero() { None } else { Some((m, to_balance(b))) }) - .collect::)>>(); - - // OPTIMIZATION NOTE: we could bail out here if `new_set.len() == 0`. There isn't - // much left to do. Yet, re-arranging the code would require duplicating the - // slashing of exposed candidates, cleaning any previous members, and so on. For - // now, in favor of readability and veracity, we keep it simple. - - // split new set into winners and runners up. - let split_point = desired_seats.min(new_set_with_stake.len()); - let mut new_members_sorted_by_id = - new_set_with_stake.drain(..split_point).collect::>(); - new_members_sorted_by_id.sort_by(|i, j| i.0.cmp(&j.0)); - - // all the rest will be runners-up - new_set_with_stake.reverse(); - let new_runners_up_sorted_by_rank = new_set_with_stake; - let mut new_runners_up_ids_sorted = - new_runners_up_sorted_by_rank.iter().map(|(r, _)| r.clone()).collect::>(); - new_runners_up_ids_sorted.sort(); - - // Now we select a prime member using a [Borda - // count](https://en.wikipedia.org/wiki/Borda_count). We weigh everyone's vote for - // that new member by a multiplier based on the order of the votes. i.e. the first - // person a voter votes for gets a 16x multiplier, the next person gets a 15x - // multiplier, an so on... (assuming `MAXIMUM_VOTE` = 16) - let mut prime_votes = new_members_sorted_by_id - .iter() - .map(|c| (&c.0, BalanceOf::::zero())) - .collect::>(); - for (_, stake, votes) in voters_and_stakes.into_iter() { - for (vote_multiplier, who) in votes - .iter() - .enumerate() - .map(|(vote_position, who)| ((MAXIMUM_VOTE - vote_position) as u32, who)) - { - if let Ok(i) = prime_votes.binary_search_by_key(&who, |k| k.0) { - prime_votes[i].1 = prime_votes[i] - .1 - .saturating_add(stake.saturating_mul(vote_multiplier.into())); + let _ = + sp_npos_elections::seq_phragmen(num_to_elect, candidate_ids, voters_and_votes, None) + .map(|ElectionResult:: { winners, assignments: _ }| { + // this is already sorted by id. + let old_members_ids_sorted = >::take() + .into_iter() + .map(|m| m.who) + .collect::>(); + // this one needs a sort by id. + let mut old_runners_up_ids_sorted = >::take() + .into_iter() + .map(|r| r.who) + .collect::>(); + old_runners_up_ids_sorted.sort(); + + // filter out those who end up with no backing stake. + let mut new_set_with_stake = winners + .into_iter() + .filter_map( + |(m, b)| if b.is_zero() { None } else { Some((m, to_balance(b))) }, + ) + .collect::)>>(); + + // OPTIMIZATION NOTE: we could bail out here if `new_set.len() == 0`. There + // isn't much left to do. Yet, re-arranging the code would require duplicating + // the slashing of exposed candidates, cleaning any previous members, and so on. + // For now, in favor of readability and veracity, we keep it simple. + + // split new set into winners and runners up. + let split_point = desired_seats.min(new_set_with_stake.len()); + let mut new_members_sorted_by_id = + new_set_with_stake.drain(..split_point).collect::>(); + new_members_sorted_by_id.sort_by(|i, j| i.0.cmp(&j.0)); + + // all the rest will be runners-up + new_set_with_stake.reverse(); + let new_runners_up_sorted_by_rank = new_set_with_stake; + let mut new_runners_up_ids_sorted = new_runners_up_sorted_by_rank + .iter() + .map(|(r, _)| r.clone()) + .collect::>(); + new_runners_up_ids_sorted.sort(); + + // Now we select a prime member using a [Borda + // count](https://en.wikipedia.org/wiki/Borda_count). We weigh everyone's vote for + // that new member by a multiplier based on the order of the votes. i.e. the + // first person a voter votes for gets a 16x multiplier, the next person gets a + // 15x multiplier, an so on... (assuming `MAXIMUM_VOTE` = 16) + let mut prime_votes = new_members_sorted_by_id + .iter() + .map(|c| (&c.0, BalanceOf::::zero())) + .collect::>(); + for (_, stake, votes) in voters_and_stakes.into_iter() { + for (vote_multiplier, who) in + votes.iter().enumerate().map(|(vote_position, who)| { + ((MAXIMUM_VOTE - vote_position) as u32, who) + }) { + if let Ok(i) = prime_votes.binary_search_by_key(&who, |k| k.0) { + prime_votes[i].1 = prime_votes[i] + .1 + .saturating_add(stake.saturating_mul(vote_multiplier.into())); + } + } } - } - } - // We then select the new member with the highest weighted stake. In the case of a tie, - // the last person in the list with the tied score is selected. This is the person with - // the "highest" account id based on the sort above. - let prime = prime_votes.into_iter().max_by_key(|x| x.1).map(|x| x.0.clone()); - - // new_members_sorted_by_id is sorted by account id. - let new_members_ids_sorted = new_members_sorted_by_id - .iter() - .map(|(m, _)| m.clone()) - .collect::>(); - - // report member changes. We compute diff because we need the outgoing list. - let (incoming, outgoing) = T::ChangeMembers::compute_members_diff_sorted( - &new_members_ids_sorted, - &old_members_ids_sorted, - ); - T::ChangeMembers::change_members_sorted(&incoming, &outgoing, &new_members_ids_sorted); - T::ChangeMembers::set_prime(prime); - - // All candidates/members/runners-up who are no longer retaining a position as a - // seat holder will lose their bond. - candidates_and_deposit.iter().for_each(|(c, d)| { - if new_members_ids_sorted.binary_search(c).is_err() && - new_runners_up_ids_sorted.binary_search(c).is_err() - { - let (imbalance, _) = T::Currency::slash_reserved(c, *d); - T::LoserCandidate::on_unbalanced(imbalance); - Self::deposit_event(Event::CandidateSlashed { - candidate: c.clone(), - amount: *d, + // We then select the new member with the highest weighted stake. In the case of + // a tie, the last person in the list with the tied score is selected. This is + // the person with the "highest" account id based on the sort above. + let prime = prime_votes.into_iter().max_by_key(|x| x.1).map(|x| x.0.clone()); + + // new_members_sorted_by_id is sorted by account id. + let new_members_ids_sorted = new_members_sorted_by_id + .iter() + .map(|(m, _)| m.clone()) + .collect::>(); + + // report member changes. We compute diff because we need the outgoing list. + let (incoming, outgoing) = T::ChangeMembers::compute_members_diff_sorted( + &new_members_ids_sorted, + &old_members_ids_sorted, + ); + T::ChangeMembers::change_members_sorted( + &incoming, + &outgoing, + &new_members_ids_sorted, + ); + T::ChangeMembers::set_prime(prime); + + // All candidates/members/runners-up who are no longer retaining a position as a + // seat holder will lose their bond. + candidates_and_deposit.iter().for_each(|(c, d)| { + if new_members_ids_sorted.binary_search(c).is_err() && + new_runners_up_ids_sorted.binary_search(c).is_err() + { + let (imbalance, _) = T::Currency::slash_reserved(c, *d); + T::LoserCandidate::on_unbalanced(imbalance); + Self::deposit_event(Event::CandidateSlashed { + candidate: c.clone(), + amount: *d, + }); + } }); - } - }); - // write final values to storage. - let deposit_of_candidate = |x: &T::AccountId| -> BalanceOf { - // defensive-only. This closure is used against the new members and new runners-up, - // both of which are phragmen winners and thus must have deposit. - candidates_and_deposit - .iter() - .find_map(|(c, d)| if c == x { Some(*d) } else { None }) - .defensive_unwrap_or_default() - }; - // fetch deposits from the one recorded one. This will make sure that a candidate who - // submitted candidacy before a change to candidacy deposit will have the correct amount - // recorded. - >::put( - new_members_sorted_by_id - .iter() - .map(|(who, stake)| SeatHolder { - deposit: deposit_of_candidate(&who), - who: who.clone(), - stake: stake.clone(), - }) - .collect::>(), - ); - >::put( - new_runners_up_sorted_by_rank - .into_iter() - .map(|(who, stake)| SeatHolder { - deposit: deposit_of_candidate(&who), - who, - stake, - }) - .collect::>(), - ); + // write final values to storage. + let deposit_of_candidate = |x: &T::AccountId| -> BalanceOf { + // defensive-only. This closure is used against the new members and new + // runners-up, both of which are phragmen winners and thus must have + // deposit. + candidates_and_deposit + .iter() + .find_map(|(c, d)| if c == x { Some(*d) } else { None }) + .defensive_unwrap_or_default() + }; + // fetch deposits from the one recorded one. This will make sure that a + // candidate who submitted candidacy before a change to candidacy deposit will + // have the correct amount recorded. + >::put( + new_members_sorted_by_id + .iter() + .map(|(who, stake)| SeatHolder { + deposit: deposit_of_candidate(who), + who: who.clone(), + stake: *stake, + }) + .collect::>(), + ); + >::put( + new_runners_up_sorted_by_rank + .into_iter() + .map(|(who, stake)| SeatHolder { + deposit: deposit_of_candidate(&who), + who, + stake, + }) + .collect::>(), + ); - // clean candidates. - >::kill(); + // clean candidates. + >::kill(); - Self::deposit_event(Event::NewTerm { new_members: new_members_sorted_by_id }); - >::mutate(|v| *v += 1); - }) - .map_err(|e| { - log::error!( - target: "runtime::elections-phragmen", - "Failed to run election [{:?}].", - e, - ); - Self::deposit_event(Event::ElectionError); - }); + Self::deposit_event(Event::NewTerm { new_members: new_members_sorted_by_id }); + >::mutate(|v| *v += 1); + }) + .map_err(|e| { + log::error!( + target: "runtime::elections-phragmen", + "Failed to run election [{:?}].", + e, + ); + Self::deposit_event(Event::ElectionError); + }); T::WeightInfo::election_phragmen(weight_candidates, weight_voters, weight_edges) } diff --git a/frame/elections-phragmen/src/migrations/v5.rs b/frame/elections-phragmen/src/migrations/v5.rs index 1898668cd07b3..a9fb018ba0219 100644 --- a/frame/elections-phragmen/src/migrations/v5.rs +++ b/frame/elections-phragmen/src/migrations/v5.rs @@ -12,7 +12,7 @@ pub fn migrate(to_migrate: Vec) -> Weight { for who in to_migrate.iter() { if let Ok(mut voter) = Voting::::try_get(who) { - let free_balance = T::Currency::free_balance(&who); + let free_balance = T::Currency::free_balance(who); weight = weight.saturating_add(T::DbWeight::get().reads(2)); @@ -21,7 +21,7 @@ pub fn migrate(to_migrate: Vec) -> Weight { Voting::::insert(&who, voter); let pallet_id = T::PalletId::get(); - T::Currency::set_lock(pallet_id, &who, free_balance, WithdrawReasons::all()); + T::Currency::set_lock(pallet_id, who, free_balance, WithdrawReasons::all()); weight = weight.saturating_add(T::DbWeight::get().writes(2)); } @@ -38,7 +38,7 @@ pub fn pre_migrate_fn(to_migrate: Vec) -> Box::try_get(who) { - let free_balance = T::Currency::free_balance(&who); + let free_balance = T::Currency::free_balance(who); if voter.stake > free_balance { // all good diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index b823ccd072969..d7b933577ead5 100644 --- a/frame/examples/basic/src/benchmarking.rs +++ b/frame/examples/basic/src/benchmarking.rs @@ -63,7 +63,7 @@ benchmarks! { } }: { // The benchmark execution phase could also be a closure with custom code - m.sort(); + m.sort_unstable(); } // This line generates test cases for benchmarking, and could be run by: diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 56e8db6936249..f8acc1962388f 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -758,8 +758,8 @@ where Some(Call::set_dummy { .. }) => { sp_runtime::print("set_dummy was received."); - let mut valid_tx = ValidTransaction::default(); - valid_tx.priority = Bounded::max_value(); + let valid_tx = + ValidTransaction { priority: Bounded::max_value(), ..Default::default() }; Ok(valid_tx) }, _ => Ok(Default::default()), diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index 3cf718217b062..b40311051594b 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -446,7 +446,7 @@ impl Pallet { if !signer.can_sign() { return Err( "No local accounts available. Consider adding one via `author_insertKey` RPC.", - )? + ) } // Make an external HTTP request to fetch the current price. // Note this call will block until response is received. @@ -640,7 +640,7 @@ impl Pallet { _ => return None, }; - let exp = price.fraction_length.checked_sub(2).unwrap_or(0); + let exp = price.fraction_length.saturating_sub(2); Some(price.integer as u32 * 100 + (price.fraction / 10_u64.pow(exp)) as u32) } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 68b5e910ed1fc..f1e7485d7440c 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -245,7 +245,7 @@ where let new_header = >::finalize(); let items_zip = header.digest().logs().iter().zip(new_header.digest().logs().iter()); for (header_item, computed_item) in items_zip { - header_item.check_equal(&computed_item); + header_item.check_equal(computed_item); assert!(header_item == computed_item, "Digest item must match that calculated."); } @@ -275,7 +275,7 @@ where pub fn initialize_block(header: &System::Header) { sp_io::init_tracing(); sp_tracing::enter_span!(sp_tracing::Level::TRACE, "init_block"); - let digests = Self::extract_pre_digest(&header); + let digests = Self::extract_pre_digest(header); Self::initialize_block_impl(header.number(), header.parent_hash(), &digests); } @@ -338,7 +338,7 @@ where let header = block.header(); // Check that `parent_hash` is correct. - let n = header.number().clone(); + let n = *header.number(); assert!( n > System::BlockNumber::zero() && >::block_hash(n - System::BlockNumber::one()) == @@ -478,13 +478,13 @@ where ); let items_zip = header.digest().logs().iter().zip(new_header.digest().logs().iter()); for (header_item, computed_item) in items_zip { - header_item.check_equal(&computed_item); + header_item.check_equal(computed_item); assert!(header_item == computed_item, "Digest item must match that calculated."); } // check storage root. let storage_root = new_header.state_root(); - header.state_root().check_equal(&storage_root); + header.state_root().check_equal(storage_root); assert!(header.state_root() == storage_root, "Storage root must match that calculated."); assert!( diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index 8956e04857f2c..59522f9a106f2 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -399,7 +399,7 @@ pub mod pallet { qs[queue_index].0 += net.0; qs[queue_index].1 = qs[queue_index].1.saturating_add(net.1); }); - Self::deposit_event(Event::BidPlaced { who: who.clone(), amount, duration }); + Self::deposit_event(Event::BidPlaced { who, amount, duration }); Ok(().into()) } diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 318f2f40ea4d9..75244c72cfd16 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -77,7 +77,7 @@ const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; #[pallet::pallet] @@ -244,10 +244,11 @@ pub mod pallet { origin: OriginFor, delay: T::BlockNumber, best_finalized_block_number: T::BlockNumber, - ) -> DispatchResultWithPostInfo { + ) -> DispatchResult { ensure_root(origin)?; - Ok(Self::on_stalled(delay, best_finalized_block_number).into()) + Self::on_stalled(delay, best_finalized_block_number); + Ok(()) } } @@ -423,7 +424,7 @@ impl Pallet { Ok(()) } else { - Err(Error::::PauseFailed)? + Err(Error::::PauseFailed.into()) } } @@ -435,7 +436,7 @@ impl Pallet { Ok(()) } else { - Err(Error::::ResumeFailed)? + Err(Error::::ResumeFailed.into()) } } @@ -461,9 +462,9 @@ impl Pallet { if !>::exists() { let scheduled_at = >::block_number(); - if let Some(_) = forced { + if forced.is_some() { if Self::next_forced().map_or(false, |next| next > scheduled_at) { - Err(Error::::TooSoon)? + return Err(Error::::TooSoon.into()) } // only allow the next forced change when twice the window has passed since @@ -488,7 +489,7 @@ impl Pallet { Ok(()) } else { - Err(Error::::ChangePending)? + Err(Error::::ChangePending.into()) } } @@ -544,14 +545,14 @@ impl Pallet { let previous_set_id_session_index = if set_id == 0 { None } else { - let session_index = Self::session_for_set(set_id - 1) - .ok_or_else(|| Error::::InvalidEquivocationProof)?; + let session_index = + Self::session_for_set(set_id - 1).ok_or(Error::::InvalidEquivocationProof)?; Some(session_index) }; let set_id_session_index = - Self::session_for_set(set_id).ok_or_else(|| Error::::InvalidEquivocationProof)?; + Self::session_for_set(set_id).ok_or(Error::::InvalidEquivocationProof)?; // check that the session id for the membership proof is within the // bounds of the set id reported in the equivocation. diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 2145779ecf541..b225db4edfa91 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -39,11 +39,7 @@ fn add_registrars(r: u32) -> Result<(), &'static str> { let registrar: T::AccountId = account("registrar", i, SEED); let _ = T::Currency::make_free_balance_be(®istrar, BalanceOf::::max_value()); Identity::::add_registrar(RawOrigin::Root.into(), registrar.clone())?; - Identity::::set_fee( - RawOrigin::Signed(registrar.clone()).into(), - i.into(), - 10u32.into(), - )?; + Identity::::set_fee(RawOrigin::Signed(registrar.clone()).into(), i, 10u32.into())?; let fields = IdentityFields( IdentityField::Display | @@ -52,7 +48,7 @@ fn add_registrars(r: u32) -> Result<(), &'static str> { IdentityField::PgpFingerprint | IdentityField::Image | IdentityField::Twitter, ); - Identity::::set_fields(RawOrigin::Signed(registrar.clone()).into(), i.into(), fields)?; + Identity::::set_fields(RawOrigin::Signed(registrar.clone()).into(), i, fields)?; } assert_eq!(Registrars::::get().len(), r as usize); @@ -75,9 +71,9 @@ fn create_sub_accounts( } // Set identity so `set_subs` does not fail. - let _ = T::Currency::make_free_balance_be(&who, BalanceOf::::max_value() / 2u32.into()); + let _ = T::Currency::make_free_balance_be(who, BalanceOf::::max_value() / 2u32.into()); let info = create_identity_info::(1); - Identity::::set_identity(who_origin.clone().into(), Box::new(info))?; + Identity::::set_identity(who_origin.into(), Box::new(info))?; Ok(subs) } @@ -101,7 +97,7 @@ fn add_sub_accounts( fn create_identity_info(num_fields: u32) -> IdentityInfo { let data = Data::Raw(vec![0; 32].try_into().unwrap()); - let info = IdentityInfo { + IdentityInfo { additional: vec![(data.clone(), data.clone()); num_fields as usize].try_into().unwrap(), display: data.clone(), legal: data.clone(), @@ -110,10 +106,8 @@ fn create_identity_info(num_fields: u32) -> IdentityInfo::add_registrar(RawOrigin::Root.into(), caller.clone())?; let registrars = Registrars::::get(); - ensure!(registrars[r as usize].as_ref().unwrap().account == caller.clone(), "id not set."); + ensure!(registrars[r as usize].as_ref().unwrap().account == caller, "id not set."); }: _(RawOrigin::Signed(caller), r, account("new", 0, SEED)) verify { let registrars = Registrars::::get(); @@ -325,7 +319,7 @@ benchmarks! { }; Identity::::add_registrar(RawOrigin::Root.into(), caller.clone())?; - Identity::::request_judgement(user_origin.clone(), r, 10u32.into())?; + Identity::::request_judgement(user_origin, r, 10u32.into())?; }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable) verify { assert_last_event::(Event::::JudgementGiven { target: user, registrar_index: r }.into()) diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 904b71654b416..46f847606903d 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -324,8 +324,8 @@ pub mod pallet { /// - One event. /// # #[pallet::weight( T::WeightInfo::set_identity( - T::MaxRegistrars::get().into(), // R - T::MaxAdditionalFields::get().into(), // X + T::MaxRegistrars::get(), // R + T::MaxAdditionalFields::get(), // X ))] pub fn set_identity( origin: OriginFor, @@ -416,7 +416,7 @@ pub mod pallet { let new_deposit = T::SubAccountDeposit::get() * >::from(subs.len() as u32); let not_other_sub = - subs.iter().filter_map(|i| SuperOf::::get(&i.0)).all(|i| &i.0 == &sender); + subs.iter().filter_map(|i| SuperOf::::get(&i.0)).all(|i| i.0 == sender); ensure!(not_other_sub, Error::::AlreadyClaimed); if old_deposit < new_deposit { @@ -470,9 +470,9 @@ pub mod pallet { /// - One event. /// # #[pallet::weight(T::WeightInfo::clear_identity( - T::MaxRegistrars::get().into(), // R - T::MaxSubAccounts::get().into(), // S - T::MaxAdditionalFields::get().into(), // X + T::MaxRegistrars::get(), // R + T::MaxSubAccounts::get(), // S + T::MaxAdditionalFields::get(), // X ))] pub fn clear_identity(origin: OriginFor) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; @@ -484,7 +484,7 @@ pub mod pallet { >::remove(sub); } - let err_amount = T::Currency::unreserve(&sender, deposit.clone()); + let err_amount = T::Currency::unreserve(&sender, deposit); debug_assert!(err_amount.is_zero()); Self::deposit_event(Event::IdentityCleared { who: sender, deposit }); @@ -521,8 +521,8 @@ pub mod pallet { /// - One event. /// # #[pallet::weight(T::WeightInfo::request_judgement( - T::MaxRegistrars::get().into(), // R - T::MaxAdditionalFields::get().into(), // X + T::MaxRegistrars::get(), // R + T::MaxAdditionalFields::get(), // X ))] pub fn request_judgement( origin: OriginFor, @@ -542,7 +542,7 @@ pub mod pallet { match id.judgements.binary_search_by_key(®_index, |x| x.0) { Ok(i) => if id.judgements[i].1.is_sticky() { - Err(Error::::StickyJudgement)? + return Err(Error::::StickyJudgement.into()) } else { id.judgements[i] = item }, @@ -583,8 +583,8 @@ pub mod pallet { /// - One event /// # #[pallet::weight(T::WeightInfo::cancel_request( - T::MaxRegistrars::get().into(), // R - T::MaxAdditionalFields::get().into(), // X + T::MaxRegistrars::get(), // R + T::MaxAdditionalFields::get(), // X ))] pub fn cancel_request( origin: OriginFor, @@ -600,7 +600,7 @@ pub mod pallet { let fee = if let Judgement::FeePaid(fee) = id.judgements.remove(pos).1 { fee } else { - Err(Error::::JudgementGiven)? + return Err(Error::::JudgementGiven.into()) }; let err_amount = T::Currency::unreserve(&sender, fee); @@ -754,8 +754,8 @@ pub mod pallet { /// - One event. /// # #[pallet::weight(T::WeightInfo::provide_judgement( - T::MaxRegistrars::get().into(), // R - T::MaxAdditionalFields::get().into(), // X + T::MaxRegistrars::get(), // R + T::MaxAdditionalFields::get(), // X ))] pub fn provide_judgement( origin: OriginFor, @@ -821,9 +821,9 @@ pub mod pallet { /// - One event. /// # #[pallet::weight(T::WeightInfo::kill_identity( - T::MaxRegistrars::get().into(), // R - T::MaxSubAccounts::get().into(), // S - T::MaxAdditionalFields::get().into(), // X + T::MaxRegistrars::get(), // R + T::MaxSubAccounts::get(), // S + T::MaxAdditionalFields::get(), // X ))] pub fn kill_identity( origin: OriginFor, diff --git a/frame/identity/src/types.rs b/frame/identity/src/types.rs index cb8091fe18747..b1f15da3b1117 100644 --- a/frame/identity/src/types.rs +++ b/frame/identity/src/types.rs @@ -217,20 +217,14 @@ impl bool { - match self { - Judgement::FeePaid(_) => true, - _ => false, - } + matches!(self, Judgement::FeePaid(_)) } /// Returns `true` if this judgement is one that should not be generally be replaced outside /// of specialized handlers. Examples include "malicious" judgements and deposit-holding /// judgements. pub(crate) fn is_sticky(&self) -> bool { - match self { - Judgement::FeePaid(_) | Judgement::Erroneous => true, - _ => false, - } + matches!(self, Judgement::FeePaid(_) | Judgement::Erroneous) } } diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 5ef515db0b236..05b7618b286a6 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -508,9 +508,9 @@ pub mod pallet { Ok(()) } else if exists { - Err(Error::::DuplicatedHeartbeat)? + Err(Error::::DuplicatedHeartbeat.into()) } else { - Err(Error::::InvalidKey)? + Err(Error::::InvalidKey.into()) } } } @@ -573,7 +573,7 @@ pub mod pallet { // check signature (this is expensive so we do it last). let signature_valid = heartbeat.using_encoded(|encoded_heartbeat| { - authority_id.verify(&encoded_heartbeat, &signature) + authority_id.verify(&encoded_heartbeat, signature) }); if !signature_valid { diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index db983a802cadf..ddc03c94b1233 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -142,7 +142,7 @@ pub mod pallet { Accounts::::try_mutate(index, |maybe_value| -> DispatchResult { let (account, amount, perm) = maybe_value.take().ok_or(Error::::NotAssigned)?; ensure!(!perm, Error::::Permanent); - ensure!(&account == &who, Error::::NotOwner); + ensure!(account == who, Error::::NotOwner); let lost = T::Currency::repatriate_reserved(&who, &new, amount, Reserved)?; *maybe_value = Some((new.clone(), amount.saturating_sub(lost), false)); Ok(()) @@ -176,7 +176,7 @@ pub mod pallet { Accounts::::try_mutate(index, |maybe_value| -> DispatchResult { let (account, amount, perm) = maybe_value.take().ok_or(Error::::NotAssigned)?; ensure!(!perm, Error::::Permanent); - ensure!(&account == &who, Error::::NotOwner); + ensure!(account == who, Error::::NotOwner); T::Currency::unreserve(&who, amount); Ok(()) })?; @@ -249,7 +249,7 @@ pub mod pallet { Accounts::::try_mutate(index, |maybe_value| -> DispatchResult { let (account, amount, perm) = maybe_value.take().ok_or(Error::::NotAssigned)?; ensure!(!perm, Error::::Permanent); - ensure!(&account == &who, Error::::NotOwner); + ensure!(account == who, Error::::NotOwner); T::Currency::slash_reserved(&who, amount); *maybe_value = Some((account, Zero::zero(), true)); Ok(()) diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index c9a508372ca85..bc96a029a4210 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -108,7 +108,7 @@ impl ValidateCall for () { impl ValidateCall for Pallet { fn validate_call(call: &::Call) -> bool { let valid_calls = CallIndices::::get(); - let call_index = match Self::call_to_index(&call) { + let call_index = match Self::call_to_index(call) { Ok(call_index) => call_index, Err(_) => return false, }; @@ -278,7 +278,7 @@ pub mod pallet { // but is not used if it is not relevant. } } - return T::DbWeight::get().reads(1) + T::DbWeight::get().reads(1) }) } } @@ -418,9 +418,9 @@ impl Pallet { fn call_to_index(call: &::Call) -> Result { let encoded_call = call.encode(); if encoded_call.len() < 2 { - Err(Error::::EncodingFailed)? + return Err(Error::::EncodingFailed.into()) } - return Ok((encoded_call[0], encoded_call[1])) + Ok((encoded_call[0], encoded_call[1])) } /// Logic for buying a ticket. diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 5a9c0a461cdac..ad6273e78f0f2 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -377,7 +377,7 @@ mod benchmark { let m in 1 .. T::MaxMembers::get(); let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); - set_members::(members.clone(), None); + set_members::(members, None); let new_member = account::("add", m, SEED); }: { assert_ok!(>::add_member(T::AddOrigin::successful_origin(), new_member.clone())); diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index 43abb349b7951..8201426f5330f 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -45,7 +45,7 @@ fn setup_multi( let call: ::Call = frame_system::Call::::remark { remark: vec![0; z as usize] }.into(); let call_data = OpaqueCall::::from_encoded(call.encode()); - return Ok((signatories, call_data)) + Ok((signatories, call_data)) } benchmarks! { @@ -74,7 +74,7 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(&call.encoded()); + let call_hash = blake2_256(call.encoded()); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; // Whitelist caller account from further DB operations. @@ -92,7 +92,7 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(&call.encoded()); + let call_hash = blake2_256(call.encoded()); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -111,7 +111,7 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(&call.encoded()); + let call_hash = blake2_256(call.encoded()); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; @@ -136,7 +136,7 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(&call.encoded()); + let call_hash = blake2_256(call.encoded()); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; @@ -162,7 +162,7 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(&call.encoded()); + let call_hash = blake2_256(call.encoded()); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; @@ -195,7 +195,7 @@ benchmarks! { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(&call.encoded()); + let call_hash = blake2_256(call.encoded()); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); @@ -214,16 +214,16 @@ benchmarks! { let mut signatories2 = signatories.clone(); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(&call.encoded()); + let call_hash = blake2_256(call.encoded()); // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi Multisig::::as_multi( - RawOrigin::Signed(caller.clone()).into(), + RawOrigin::Signed(caller).into(), s as u16, signatories, None, - call.clone(), + call, false, 0 )?; @@ -247,7 +247,7 @@ benchmarks! { let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let call_hash = blake2_256(&call.encoded()); + let call_hash = blake2_256(call.encoded()); // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi @@ -284,11 +284,11 @@ benchmarks! { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(&call.encoded()); + let call_hash = blake2_256(call.encoded()); let timepoint = Multisig::::timepoint(); // Create the multi let o = RawOrigin::Signed(caller.clone()).into(); - Multisig::::as_multi(o, s as u16, signatories.clone(), None, call.clone(), true, 0)?; + Multisig::::as_multi(o, s as u16, signatories.clone(), None, call, true, 0)?; assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); assert!(Calls::::contains_key(call_hash)); // Whitelist caller account from further DB operations. diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index cd59ea881739d..d4ea041e5820e 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -295,8 +295,7 @@ pub mod pallet { let weight_used = T::WeightInfo::as_multi_threshold_1(call_len as u32) .saturating_add(actual_weight); let post_info = Some(weight_used).into(); - let error = err.error.into(); - DispatchErrorWithPostInfo { post_info, error } + DispatchErrorWithPostInfo { post_info, error: err.error } }, None => err, }) diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 632ff7b0a8083..5da06a24df3e5 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -147,7 +147,7 @@ pub mod pallet { deposit } else { let deposit = T::ReservationFee::get(); - T::Currency::reserve(&sender, deposit.clone())?; + T::Currency::reserve(&sender, deposit)?; Self::deposit_event(Event::::NameSet { who: sender.clone() }); deposit }; @@ -172,7 +172,7 @@ pub mod pallet { let deposit = >::take(&sender).ok_or(Error::::Unnamed)?.1; - let err_amount = T::Currency::unreserve(&sender, deposit.clone()); + let err_amount = T::Currency::unreserve(&sender, deposit); debug_assert!(err_amount.is_zero()); Self::deposit_event(Event::::NameCleared { who: sender, deposit }); @@ -204,7 +204,7 @@ pub mod pallet { // Grab their deposit (and check that they have one). let deposit = >::take(&target).ok_or(Error::::Unnamed)?.1; // Slash their deposit from them. - T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit.clone()).0); + T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0); Self::deposit_event(Event::::NameKilled { target, deposit }); Ok(()) diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 8688090206c36..98c6390964d82 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -101,15 +101,14 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' let controller: T::AccountId = account("controller", n, SEED); let controller_lookup: LookupSourceOf = T::Lookup::unlookup(controller.clone()); let reward_destination = RewardDestination::Staked; - let raw_amount = bond_amount::(); + let amount = bond_amount::(); // add twice as much balance to prevent the account from being killed. - let free_amount = raw_amount.saturating_mul(2u32.into()); + let free_amount = amount.saturating_mul(2u32.into()); T::Currency::make_free_balance_be(&stash, free_amount); - let amount: BalanceOf = raw_amount.into(); Staking::::bond( RawOrigin::Signed(stash.clone()).into(), controller_lookup.clone(), - amount.clone(), + amount, reward_destination.clone(), )?; @@ -127,12 +126,12 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' account("nominator controller", n * MAX_NOMINATORS + i, SEED); let nominator_controller_lookup: LookupSourceOf = T::Lookup::unlookup(nominator_controller.clone()); - T::Currency::make_free_balance_be(&nominator_stash, free_amount.into()); + T::Currency::make_free_balance_be(&nominator_stash, free_amount); Staking::::bond( RawOrigin::Signed(nominator_stash.clone()).into(), nominator_controller_lookup.clone(), - amount.clone(), + amount, reward_destination.clone(), )?; @@ -143,14 +142,13 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' )?; individual_exposures - .push(IndividualExposure { who: nominator_stash.clone(), value: amount.clone() }); + .push(IndividualExposure { who: nominator_stash.clone(), value: amount }); nominator_stashes.push(nominator_stash.clone()); } - let exposure = - Exposure { total: amount.clone() * n.into(), own: amount, others: individual_exposures }; + let exposure = Exposure { total: amount * n.into(), own: amount, others: individual_exposures }; let current_era = 0u32; - Staking::::add_era_stakers(current_era.into(), stash.clone().into(), exposure); + Staking::::add_era_stakers(current_era, stash.clone(), exposure); Ok(Offender { controller, stash, nominator_stashes }) } @@ -327,13 +325,13 @@ benchmarks! { .flat_map(|offender| { let nom_slashes = offender.nominator_stashes.into_iter().flat_map(|nom| { balance_slash(nom.clone()).map(Into::into) - .chain(slash(nom.clone()).map(Into::into)) - }).collect::>(); + .chain(slash(nom).map(Into::into)) + }); let mut events = chill(offender.stash.clone()).map(Into::into) .chain(balance_slash(offender.stash.clone()).map(Into::into)) - .chain(slash(offender.stash.clone()).map(Into::into)) - .chain(nom_slashes.into_iter()) + .chain(slash(offender.stash).map(Into::into)) + .chain(nom_slashes) .collect::>(); // the first deposit creates endowed events, see `endowed_reward_events` @@ -341,10 +339,10 @@ benchmarks! { first = false; let mut reward_events = reporters.clone().into_iter() .flat_map(|reporter| vec![ - balance_deposit(reporter.clone(), reward.into()).into(), + balance_deposit(reporter.clone(), reward).into(), frame_system::Event::::NewAccount { account: reporter.clone() }.into(), ::Event::from( - pallet_balances::Event::::Endowed{account: reporter.clone(), free_balance: reward.into()} + pallet_balances::Event::::Endowed{account: reporter, free_balance: reward.into()} ).into(), ]) .collect::>(); @@ -352,7 +350,7 @@ benchmarks! { events.into_iter() } else { let mut reward_events = reporters.clone().into_iter() - .map(|reporter| balance_deposit(reporter, reward.into()).into()) + .map(|reporter| balance_deposit(reporter, reward).into()) .collect::>(); events.append(&mut reward_events); events.into_iter() diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index 6119fce7769e9..a6d69e2a5e268 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -136,8 +136,7 @@ where // The amount new offenders are slashed let new_fraction = O::slash_fraction(offenders_count, validator_set_count); - let slash_perbill: Vec<_> = - (0..concurrent_offenders.len()).map(|_| new_fraction.clone()).collect(); + let slash_perbill: Vec<_> = (0..concurrent_offenders.len()).map(|_| new_fraction).collect(); T::OnOffenceHandler::on_offence( &concurrent_offenders, @@ -202,7 +201,7 @@ impl Pallet { let concurrent_offenders = storage .concurrent_reports .iter() - .filter_map(|report_id| >::get(report_id)) + .filter_map(>::get) .collect::>(); storage.save(); diff --git a/frame/offences/src/migration.rs b/frame/offences/src/migration.rs index 72c24ef7c3e5b..0d6c98b564cb1 100644 --- a/frame/offences/src/migration.rs +++ b/frame/offences/src/migration.rs @@ -42,8 +42,8 @@ pub fn remove_deferred_storage() -> Weight { log::info!(target: "runtime::offences", "have {} deferred offences, applying.", deferred.len()); for (offences, perbill, session) in deferred.iter() { let consumed = T::OnOffenceHandler::on_offence( - &offences, - &perbill, + offences, + perbill, *session, DisableStrategy::WhenSlashed, ); diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index 64326108420e8..e0d7e9614abbc 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -62,7 +62,7 @@ benchmarks! { let caller = funded_account::("caller", 0); whitelist_account!(caller); let (preimage, hash) = sized_preimage_and_hash::(s); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); }: note_preimage(RawOrigin::Signed(caller), preimage) verify { assert!(Preimage::::have_preimage(&hash)); @@ -71,7 +71,7 @@ benchmarks! { note_no_deposit_preimage { let s in 0 .. T::MaxSize::get(); let (preimage, hash) = sized_preimage_and_hash::(s); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); }: note_preimage(T::ManagerOrigin::successful_origin(), preimage) verify { assert!(Preimage::::have_preimage(&hash)); @@ -83,7 +83,7 @@ benchmarks! { whitelist_account!(caller); let (preimage, hash) = preimage_and_hash::(); assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(caller.clone()).into(), preimage)); - }: _(RawOrigin::Signed(caller), hash.clone()) + }: _(RawOrigin::Signed(caller), hash) verify { assert!(!Preimage::::have_preimage(&hash)); } @@ -91,7 +91,7 @@ benchmarks! { unnote_no_deposit_preimage { let (preimage, hash) = preimage_and_hash::(); assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: unnote_preimage(T::ManagerOrigin::successful_origin(), hash.clone()) + }: unnote_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert!(!Preimage::::have_preimage(&hash)); } @@ -124,7 +124,7 @@ benchmarks! { // Cheap request - the preimage is already requested, so just a counter bump. request_requested_preimage { let (_, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(2))); @@ -133,26 +133,26 @@ benchmarks! { // Expensive unrequest - last reference and it's noted, so will destroy the preimage. unrequest_preimage { let (preimage, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: _(T::ManagerOrigin::successful_origin(), hash.clone()) + }: _(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), None); } // Cheap unrequest - last reference, but it's not noted. unrequest_unnoted_preimage { let (_, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); - }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash.clone()) + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); + }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), None); } // Cheap unrequest - not the last reference. unrequest_multi_referenced_preimage { let (_, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); - }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash.clone()) + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); + }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); } diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index a5d8ee28b5952..09f6ecd52f9ad 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -215,7 +215,8 @@ impl Pallet { // previously requested. This also allows the tx to pay no fee. let was_requested = match (StatusFor::::get(hash), maybe_depositor) { (Some(RequestStatus::Requested(..)), _) => true, - (Some(RequestStatus::Unrequested(..)), _) => Err(Error::::AlreadyNoted)?, + (Some(RequestStatus::Unrequested(..)), _) => + return Err(Error::::AlreadyNoted.into()), (None, None) => { StatusFor::::insert(hash, RequestStatus::Unrequested(None)); false @@ -256,7 +257,7 @@ impl Pallet { }); StatusFor::::insert(hash, RequestStatus::Requested(count)); if count == 1 { - Self::deposit_event(Event::Requested { hash: hash.clone() }); + Self::deposit_event(Event::Requested { hash: *hash }); } } @@ -270,20 +271,17 @@ impl Pallet { ) -> DispatchResult { match StatusFor::::get(hash).ok_or(Error::::NotNoted)? { RequestStatus::Unrequested(Some((owner, deposit))) => { - ensure!( - maybe_check_owner.map_or(true, |c| &c == &owner), - Error::::NotAuthorized - ); + ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::::NotAuthorized); T::Currency::unreserve(&owner, deposit); }, RequestStatus::Unrequested(None) => { ensure!(maybe_check_owner.is_none(), Error::::NotAuthorized); }, - RequestStatus::Requested(_) => Err(Error::::Requested)?, + RequestStatus::Requested(_) => return Err(Error::::Requested.into()), } StatusFor::::remove(hash); PreimageFor::::remove(hash); - Self::deposit_event(Event::Cleared { hash: hash.clone() }); + Self::deposit_event(Event::Cleared { hash: *hash }); Ok(()) } @@ -298,9 +296,9 @@ impl Pallet { debug_assert!(count == 1, "preimage request counter at zero?"); PreimageFor::::remove(hash); StatusFor::::remove(hash); - Self::deposit_event(Event::Cleared { hash: hash.clone() }); + Self::deposit_event(Event::Cleared { hash: *hash }); }, - RequestStatus::Unrequested(_) => Err(Error::::NotRequested)?, + RequestStatus::Unrequested(_) => return Err(Error::::NotRequested.into()), } Ok(()) } diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index f3098c6ad1274..87017290a3ab9 100644 --- a/frame/proxy/src/benchmarking.rs +++ b/frame/proxy/src/benchmarking.rs @@ -32,7 +32,7 @@ fn assert_last_event(generic_event: ::Event) { } fn add_proxies(n: u32, maybe_who: Option) -> Result<(), &'static str> { - let caller = maybe_who.unwrap_or_else(|| whitelisted_caller()); + let caller = maybe_who.unwrap_or_else(whitelisted_caller); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); for i in 0..n { Proxy::::add_proxy( @@ -77,7 +77,7 @@ fn add_announcements( benchmarks! { proxy { - let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; + let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); @@ -91,7 +91,7 @@ benchmarks! { proxy_announced { let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; + let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("anonymous", 0, SEED); let delegate: T::AccountId = account("target", p - 1, SEED); @@ -112,7 +112,7 @@ benchmarks! { remove_announcement { let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; + let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); @@ -133,7 +133,7 @@ benchmarks! { reject_announcement { let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; + let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); @@ -154,7 +154,7 @@ benchmarks! { announce { let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; + let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); @@ -169,11 +169,11 @@ benchmarks! { } add_proxy { - let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; + let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); }: _( RawOrigin::Signed(caller.clone()), - account("target", T::MaxProxies::get().into(), SEED), + account("target", T::MaxProxies::get(), SEED), T::ProxyType::default(), T::BlockNumber::zero() ) @@ -183,7 +183,7 @@ benchmarks! { } remove_proxy { - let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; + let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); }: _( RawOrigin::Signed(caller.clone()), @@ -197,7 +197,7 @@ benchmarks! { } remove_proxies { - let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; + let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); }: _(RawOrigin::Signed(caller.clone())) verify { @@ -206,7 +206,7 @@ benchmarks! { } anonymous { - let p in 1 .. (T::MaxProxies::get() - 1).into() => add_proxies::(p, None)?; + let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); }: _( RawOrigin::Signed(caller.clone()), @@ -225,7 +225,7 @@ benchmarks! { } kill_anonymous { - let p in 0 .. (T::MaxProxies::get() - 2).into(); + let p in 0 .. (T::MaxProxies::get() - 2); let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 1bab3626fb5a9..9945626efbeb1 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -196,7 +196,7 @@ pub mod pallet { /// # #[pallet::weight({ let di = call.get_dispatch_info(); - (T::WeightInfo::proxy(T::MaxProxies::get().into()) + (T::WeightInfo::proxy(T::MaxProxies::get()) .saturating_add(di.weight) // AccountData for inner call origin accountdata. .saturating_add(T::DbWeight::get().reads_writes(1, 1)), @@ -230,7 +230,7 @@ pub mod pallet { /// # /// Weight is a function of the number of proxies the user has (P). /// # - #[pallet::weight(T::WeightInfo::add_proxy(T::MaxProxies::get().into()))] + #[pallet::weight(T::WeightInfo::add_proxy(T::MaxProxies::get()))] pub fn add_proxy( origin: OriginFor, delegate: T::AccountId, @@ -252,7 +252,7 @@ pub mod pallet { /// # /// Weight is a function of the number of proxies the user has (P). /// # - #[pallet::weight(T::WeightInfo::remove_proxy(T::MaxProxies::get().into()))] + #[pallet::weight(T::WeightInfo::remove_proxy(T::MaxProxies::get()))] pub fn remove_proxy( origin: OriginFor, delegate: T::AccountId, @@ -273,7 +273,7 @@ pub mod pallet { /// # /// Weight is a function of the number of proxies the user has (P). /// # - #[pallet::weight(T::WeightInfo::remove_proxies(T::MaxProxies::get().into()))] + #[pallet::weight(T::WeightInfo::remove_proxies(T::MaxProxies::get()))] pub fn remove_proxies(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; let (_, old_deposit) = Proxies::::take(&who); @@ -305,7 +305,7 @@ pub mod pallet { /// Weight is a function of the number of proxies the user has (P). /// # /// TODO: Might be over counting 1 read - #[pallet::weight(T::WeightInfo::anonymous(T::MaxProxies::get().into()))] + #[pallet::weight(T::WeightInfo::anonymous(T::MaxProxies::get()))] pub fn anonymous( origin: OriginFor, proxy_type: T::ProxyType, @@ -356,7 +356,7 @@ pub mod pallet { /// # /// Weight is a function of the number of proxies the user has (P). /// # - #[pallet::weight(T::WeightInfo::kill_anonymous(T::MaxProxies::get().into()))] + #[pallet::weight(T::WeightInfo::kill_anonymous(T::MaxProxies::get()))] pub fn kill_anonymous( origin: OriginFor, spawner: T::AccountId, @@ -398,7 +398,7 @@ pub mod pallet { /// - A: the number of announcements made. /// - P: the number of proxies the user has. /// # - #[pallet::weight(T::WeightInfo::announce(T::MaxPending::get(), T::MaxProxies::get().into()))] + #[pallet::weight(T::WeightInfo::announce(T::MaxPending::get(), T::MaxProxies::get()))] pub fn announce( origin: OriginFor, real: T::AccountId, @@ -408,12 +408,12 @@ pub mod pallet { Proxies::::get(&real) .0 .into_iter() - .find(|x| &x.delegate == &who) + .find(|x| x.delegate == who) .ok_or(Error::::NotProxy)?; let announcement = Announcement { real: real.clone(), - call_hash: call_hash.clone(), + call_hash, height: system::Pallet::::block_number(), }; @@ -452,9 +452,10 @@ pub mod pallet { /// - A: the number of announcements made. /// - P: the number of proxies the user has. /// # - #[pallet::weight( - T::WeightInfo::remove_announcement(T::MaxPending::get(), T::MaxProxies::get().into()) - )] + #[pallet::weight(T::WeightInfo::remove_announcement( + T::MaxPending::get(), + T::MaxProxies::get() + ))] pub fn remove_announcement( origin: OriginFor, real: T::AccountId, @@ -482,9 +483,10 @@ pub mod pallet { /// - A: the number of announcements made. /// - P: the number of proxies the user has. /// # - #[pallet::weight( - T::WeightInfo::reject_announcement(T::MaxPending::get(), T::MaxProxies::get().into()) - )] + #[pallet::weight(T::WeightInfo::reject_announcement( + T::MaxPending::get(), + T::MaxProxies::get() + ))] pub fn reject_announcement( origin: OriginFor, delegate: T::AccountId, @@ -517,7 +519,7 @@ pub mod pallet { /// # #[pallet::weight({ let di = call.get_dispatch_info(); - (T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get().into()) + (T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get()) .saturating_add(di.weight) // AccountData for inner call origin accountdata. .saturating_add(T::DbWeight::get().reads_writes(1, 1)), @@ -759,9 +761,9 @@ impl Pallet { let new_deposit = if len == 0 { BalanceOf::::zero() } else { base + factor * (len as u32).into() }; if new_deposit > old_deposit { - T::Currency::reserve(&who, new_deposit - old_deposit)?; + T::Currency::reserve(who, new_deposit - old_deposit)?; } else if new_deposit < old_deposit { - T::Currency::unreserve(&who, old_deposit - new_deposit); + T::Currency::unreserve(who, old_deposit - new_deposit); } Ok(if len == 0 { None } else { Some(new_deposit) }) } @@ -816,7 +818,7 @@ impl Pallet { // has. Some(Call::add_proxy { ref proxy_type, .. }) | Some(Call::remove_proxy { ref proxy_type, .. }) - if !def.proxy_type.is_superset(&proxy_type) => + if !def.proxy_type.is_superset(proxy_type) => false, // Proxy call cannot remove all proxies or kill anonymous proxies unless it has full // permissions. diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index e75c9025760b0..b839d25e32b47 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -388,7 +388,7 @@ pub mod pallet { let who = ensure_signed(origin)?; // Check `who` is allowed to make a call on behalf of `account` let target = Self::proxy(&who).ok_or(Error::::NotAllowed)?; - ensure!(&target == &account, Error::::NotAllowed); + ensure!(target == account, Error::::NotAllowed); call.dispatch(frame_system::RawOrigin::Signed(account).into()) .map(|_| ()) .map_err(|e| e.error) @@ -541,7 +541,7 @@ pub mod pallet { ensure!(Self::is_friend(&recovery_config.friends, &who), Error::::NotFriend); // Either insert the vouch, or return an error that the user already vouched. match active_recovery.friends.binary_search(&who) { - Ok(_pos) => Err(Error::::AlreadyVouched)?, + Ok(_pos) => return Err(Error::::AlreadyVouched.into()), Err(pos) => active_recovery .friends .try_insert(pos, who.clone()) diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 08612e0614aeb..87b13868db9d9 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -57,10 +57,7 @@ fn create_referendum() -> (T::AccountId, ReferendumIndex) { fn place_deposit(index: ReferendumIndex) { let caller = funded_account::("caller", 0); whitelist_account!(caller); - assert_ok!(Referenda::::place_decision_deposit( - RawOrigin::Signed(caller.clone()).into(), - index, - )); + assert_ok!(Referenda::::place_decision_deposit(RawOrigin::Signed(caller).into(), index)); } fn nudge(index: ReferendumIndex) { @@ -265,7 +262,7 @@ benchmarks! { let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); assert_eq!(DecidingCount::::get(&track), 1); - }: one_fewer_deciding(RawOrigin::Root, track.clone()) + }: one_fewer_deciding(RawOrigin::Root, track) verify { assert_eq!(DecidingCount::::get(&track), 0); } @@ -278,7 +275,7 @@ benchmarks! { assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); let deciding_count = DecidingCount::::get(&track); - }: one_fewer_deciding(RawOrigin::Root, track.clone()) + }: one_fewer_deciding(RawOrigin::Root, track) verify { assert_eq!(DecidingCount::::get(&track), deciding_count); assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); @@ -297,7 +294,7 @@ benchmarks! { assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); let deciding_count = DecidingCount::::get(&track); - }: one_fewer_deciding(RawOrigin::Root, track.clone()) + }: one_fewer_deciding(RawOrigin::Root, track) verify { assert_eq!(DecidingCount::::get(&track), deciding_count); assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 067775fd336d0..b53be191d3525 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -363,7 +363,7 @@ pub mod pallet { let status = ReferendumStatus { track, origin: proposal_origin, - proposal_hash: proposal_hash.clone(), + proposal_hash, enactment: enactment_moment, submitted: now, submission_deposit, @@ -643,7 +643,7 @@ impl, I: 'static> Polling for Pallet { .iter() .max_by_key(|(_, info)| info.max_deciding) .expect("Always one class"); - (r.0.clone(), r.1.max_deciding) + (r.0, r.1.max_deciding) } } @@ -730,8 +730,8 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::::DecisionStarted { index, tally: status.tally.clone(), - proposal_hash: status.proposal_hash.clone(), - track: status.track.clone(), + proposal_hash: status.proposal_hash, + track: status.track, }); let confirming = if is_passing { Self::deposit_event(Event::::ConfirmStarted { index }); @@ -895,7 +895,7 @@ impl, I: 'static> Pallet { let prepare_end = status.submitted.saturating_add(track.prepare_period); if now >= prepare_end { let (maybe_alarm, branch) = - Self::ready_for_deciding(now, &track, index, &mut status); + Self::ready_for_deciding(now, track, index, &mut status); if let Some(set_alarm) = maybe_alarm { alarm = alarm.min(set_alarm); } @@ -934,7 +934,7 @@ impl, I: 'static> Pallet { &track.min_approval, ); branch = if is_passing { - match deciding.confirming.clone() { + match deciding.confirming { Some(t) if now >= t => { // Passed! Self::ensure_no_alarm(&mut status); @@ -996,7 +996,7 @@ impl, I: 'static> Pallet { ServiceBranch::ContinueNotConfirming } }; - alarm = Self::decision_time(&deciding, &status.tally, track); + alarm = Self::decision_time(deciding, &status.tally, track); }, } diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 622075100631b..5e0361c8fe160 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -182,7 +182,7 @@ pub trait TracksInfo { /// Return the track info for track `id`, by default this just looks it up in `Self::tracks()`. fn info(id: Self::Id) -> Option<&'static TrackInfo> { - Self::tracks().iter().find(|x| &x.0 == &id).map(|x| &x.1) + Self::tracks().iter().find(|x| x.0 == id).map(|x| &x.1) } } @@ -309,9 +309,9 @@ impl Curve { match self { Self::LinearDecreasing { begin, delta } => if delta.is_zero() { - return *delta + *delta } else { - return (*begin - y.min(*begin)).min(*delta) / *delta + (*begin - y.min(*begin)).min(*delta) / *delta }, } } diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index ec60cedc280b6..9b0fc87587e3a 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -727,7 +727,7 @@ impl Pallet { Self::deposit_event(Event::Canceled { when, index }); Ok(()) } else { - Err(Error::::NotFound)? + return Err(Error::::NotFound.into()) } } @@ -765,7 +765,7 @@ impl Pallet { ) -> Result, DispatchError> { // ensure id it is unique if Lookup::::contains_key(&id) { - return Err(Error::::FailedToSchedule)? + return Err(Error::::FailedToSchedule.into()) } let when = Self::resolve_time(when)?; @@ -817,7 +817,7 @@ impl Pallet { Self::deposit_event(Event::Canceled { when, index }); Ok(()) } else { - Err(Error::::NotFound)? + return Err(Error::::NotFound.into()) } }) } diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index 3f0674d720efd..abdb9b2acc9b5 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -256,7 +256,7 @@ pub mod pallet { // reserve balance for each candidate in the pool. // panicking here is ok, since this just happens one time, pre-genesis. pool.iter().for_each(|(who, _)| { - T::Currency::reserve(&who, T::CandidateDeposit::get()) + T::Currency::reserve(who, T::CandidateDeposit::get()) .expect("balance too low to create candidacy"); >::insert(who, true); }); @@ -387,7 +387,7 @@ pub mod pallet { // if there is already an element with `score`, we insert // right before that. if not, the search returns a location // where we can insert while maintaining order. - let item = (who, Some(score.clone())); + let item = (who, Some(score)); let location = pool .binary_search_by_key(&Reverse(score), |(_, maybe_score)| { Reverse(maybe_score.unwrap_or_default()) diff --git a/frame/session/src/historical/shared.rs b/frame/session/src/historical/shared.rs index 9e19b9df6d78d..faa91f7919860 100644 --- a/frame/session/src/historical/shared.rs +++ b/frame/session/src/historical/shared.rs @@ -27,13 +27,10 @@ pub(super) const LAST_PRUNE: &[u8] = b"session_historical_last_prune"; /// Derive the key used to store the list of validators pub(super) fn derive_key>(prefix: P, session_index: SessionIndex) -> Vec { - let prefix: &[u8] = prefix.as_ref(); session_index.using_encoded(|encoded_session_index| { - prefix - .into_iter() - .chain(b"/".into_iter()) - .chain(encoded_session_index.into_iter()) - .copied() - .collect::>() + let mut key = prefix.as_ref().to_owned(); + key.push(b'/'); + key.extend_from_slice(encoded_session_index); + key }) } diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index d6ecd17a8f2ae..a460c650ec602 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -184,7 +184,7 @@ impl< // (0% is never returned). let progress = if now >= offset { let current = (now - offset) % period.clone() + One::one(); - Some(Permill::from_rational(current.clone(), period.clone())) + Some(Permill::from_rational(current, period)) } else { Some(Permill::from_rational(now + One::one(), offset)) }; @@ -689,7 +689,6 @@ impl Pallet { if let Some(&(_, ref old_keys)) = now_session_keys.next() { if old_keys != keys { changed = true; - return } } }; @@ -803,10 +802,10 @@ impl Pallet { let who = T::ValidatorIdOf::convert(account.clone()) .ok_or(Error::::NoAssociatedValidatorId)?; - ensure!(frame_system::Pallet::::can_inc_consumer(&account), Error::::NoAccount); + ensure!(frame_system::Pallet::::can_inc_consumer(account), Error::::NoAccount); let old_keys = Self::inner_set_keys(&who, keys)?; if old_keys.is_none() { - let assertion = frame_system::Pallet::::inc_consumers(&account).is_ok(); + let assertion = frame_system::Pallet::::inc_consumers(account).is_ok(); debug_assert!(assertion, "can_inc_consumer() returned true; no change since; qed"); } @@ -866,7 +865,7 @@ impl Pallet { let key_data = old_keys.get_raw(*id); Self::clear_key_owner(*id, key_data); } - frame_system::Pallet::::dec_consumers(&account); + frame_system::Pallet::::dec_consumers(account); Ok(()) } @@ -949,6 +948,6 @@ impl> FindAuthor let i = Inner::find_author(digests)?; let validators = >::validators(); - validators.get(i as usize).map(|k| k.clone()) + validators.get(i as usize).cloned() } } diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 6ad63d2102c53..645a0b8ba1715 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -357,10 +357,10 @@ impl BidKind { if a == v { Ok(()) } else { - Err("incorrect identity")? + Err("incorrect identity".into()) } } else { - Err("not vouched")? + Err("not vouched".into()) } } } @@ -724,7 +724,7 @@ pub mod pallet { let deposit = T::CandidateDeposit::get(); T::Currency::reserve(&who, deposit)?; - Self::put_bid(bids, &who, value.clone(), BidKind::Deposit(deposit)); + Self::put_bid(bids, &who, value, BidKind::Deposit(deposit)); Self::deposit_event(Event::::Bid { candidate_id: who, offer: value }); Ok(()) } @@ -770,7 +770,7 @@ pub mod pallet { Self::deposit_event(Event::::Unbid { candidate: who }); Ok(()) } else { - Err(Error::::BadPosition)? + Err(Error::::BadPosition.into()) } }) } @@ -844,7 +844,7 @@ pub mod pallet { ensure!(!>::contains_key(&voucher), Error::::AlreadyVouching); >::insert(&voucher, VouchingStatus::Vouching); - Self::put_bid(bids, &who, value.clone(), BidKind::Vouch(voucher.clone(), tip)); + Self::put_bid(bids, &who, value, BidKind::Vouch(voucher.clone(), tip)); Self::deposit_event(Event::::Vouch { candidate_id: who, offer: value, @@ -887,7 +887,7 @@ pub mod pallet { Self::deposit_event(Event::::Unvouch { candidate: who }); Ok(()) } else { - Err(Error::::BadPosition)? + Err(Error::::BadPosition.into()) } }) } @@ -1001,7 +1001,7 @@ pub mod pallet { return Ok(()) } } - Err(Error::::NoPayout)? + Err(Error::::NoPayout.into()) } /// Found the society. @@ -1229,7 +1229,7 @@ pub mod pallet { // Remove suspended candidate >::remove(who); } else { - Err(Error::::NotSuspended)? + return Err(Error::::NotSuspended.into()) } Ok(()) } @@ -1392,8 +1392,8 @@ impl, I: 'static> Pallet { ensure!(Self::founder() != Some(m.clone()), Error::::Founder); let mut members = >::get(); - match members.binary_search(&m) { - Err(_) => Err(Error::::NotMember)?, + match members.binary_search(m) { + Err(_) => Err(Error::::NotMember.into()), Ok(i) => { members.remove(i); T::MembershipChanged::change_members_sorted(&[], &[m.clone()], &members[..]); @@ -1572,7 +1572,7 @@ impl, I: 'static> Pallet { >::put(&members[..]); >::put(&primary); - T::MembershipChanged::change_members_sorted(&accounts, &[], &members); + T::MembershipChanged::change_members_sorted(&accounts, &[], members); Self::deposit_event(Event::::Inducted { primary, candidates: accounts }); } @@ -1605,7 +1605,7 @@ impl, I: 'static> Pallet { if !payouts.is_empty() { let mut dropped = 0; for (_, amount) in payouts.iter_mut() { - if let Some(new_rest) = rest.checked_sub(&amount) { + if let Some(new_rest) = rest.checked_sub(amount) { // not yet totally slashed after this one; drop it completely. rest = new_rest; dropped += 1; @@ -1635,7 +1635,7 @@ impl, I: 'static> Pallet { /// Suspend a user, removing them from the member list. fn suspend_member(who: &T::AccountId) { - if Self::remove_member(&who).is_ok() { + if Self::remove_member(who).is_ok() { >::insert(who, true); >::remove(who); Self::deposit_event(Event::::MemberSuspended { member: who.clone() }); @@ -1683,12 +1683,10 @@ impl, I: 'static> Pallet { let mut approval_count = 0; let mut rejection_count = 0; // Tallies total number of approve and reject votes for the defender. - members.iter().filter_map(|m| >::take(m)).for_each( - |v| match v { - Vote::Approve => approval_count += 1, - _ => rejection_count += 1, - }, - ); + members.iter().filter_map(>::take).for_each(|v| match v { + Vote::Approve => approval_count += 1, + _ => rejection_count += 1, + }); if approval_count <= rejection_count { // User has failed the challenge diff --git a/frame/staking/reward-fn/src/lib.rs b/frame/staking/reward-fn/src/lib.rs index cb0b660bf544b..cc9919c28cce3 100644 --- a/frame/staking/reward-fn/src/lib.rs +++ b/frame/staking/reward-fn/src/lib.rs @@ -137,20 +137,18 @@ fn compute_taylor_serie_part(p: &INPoSParam) -> BigUint { if taylor_sum_positive == last_taylor_term_positive { taylor_sum = taylor_sum.add(&last_taylor_term); + } else if taylor_sum >= last_taylor_term { + taylor_sum = taylor_sum + .sub(&last_taylor_term) + // NOTE: Should never happen as checked above + .unwrap_or_else(|e| e); } else { - if taylor_sum >= last_taylor_term { - taylor_sum = taylor_sum - .sub(&last_taylor_term) - // NOTE: Should never happen as checked above - .unwrap_or_else(|e| e); - } else { - taylor_sum_positive = !taylor_sum_positive; - taylor_sum = last_taylor_term - .clone() - .sub(&taylor_sum) - // NOTE: Should never happen as checked above - .unwrap_or_else(|e| e); - } + taylor_sum_positive = !taylor_sum_positive; + taylor_sum = last_taylor_term + .clone() + .sub(&taylor_sum) + // NOTE: Should never happen as checked above + .unwrap_or_else(|e| e); } } @@ -217,10 +215,10 @@ fn div_by_stripped(mut a: BigUint, b: &BigUint) -> BigUint { return new_a .div(b, false) .map(|res| res.0) - .unwrap_or_else(|| BigUint::zero()) + .unwrap_or_else(BigUint::zero) .div_unit(100_000) .div_unit(100_000) } - a.div(b, false).map(|res| res.0).unwrap_or_else(|| BigUint::zero()) + a.div(b, false).map(|res| res.0).unwrap_or_else(BigUint::zero) } diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 7321740cfa79f..eb9129ac4b436 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -183,8 +183,8 @@ impl ListScenario { Default::default(), )?; Staking::::nominate( - RawOrigin::Signed(origin_controller2.clone()).into(), - vec![T::Lookup::unlookup(account("random_validator", 0, SEED))].clone(), + RawOrigin::Signed(origin_controller2).into(), + vec![T::Lookup::unlookup(account("random_validator", 0, SEED))], )?; // find a destination weight that will trigger the worst case scenario @@ -239,10 +239,10 @@ benchmarks! { // the weight the nominator will start at. let scenario = ListScenario::::new(origin_weight, true)?; - let max_additional = scenario.dest_weight.clone() - origin_weight; + let max_additional = scenario.dest_weight - origin_weight; let stash = scenario.origin_stash1.clone(); - let controller = scenario.origin_controller1.clone(); + let controller = scenario.origin_controller1; let original_bonded: BalanceOf = Ledger::::get(&controller).map(|l| l.active).ok_or("ledger not created after")?; @@ -271,7 +271,7 @@ benchmarks! { let stash = scenario.origin_stash1.clone(); let controller = scenario.origin_controller1.clone(); - let amount = origin_weight - scenario.dest_weight.clone(); + let amount = origin_weight - scenario.dest_weight; let ledger = Ledger::::get(&controller).ok_or("ledger not created before")?; let original_bonded: BalanceOf = ledger.active; @@ -315,7 +315,7 @@ benchmarks! { // destination position because we are doing a removal from the list but no insert. let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); - let stash = scenario.origin_stash1.clone(); + let stash = scenario.origin_stash1; assert!(T::VoterList::contains(&stash)); let ed = T::Currency::minimum_balance(); @@ -450,7 +450,7 @@ benchmarks! { // destination position because we are doing a removal from the list but no insert. let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); - let stash = scenario.origin_stash1.clone(); + let stash = scenario.origin_stash1; assert!(T::VoterList::contains(&stash)); whitelist_account!(controller); @@ -518,7 +518,7 @@ benchmarks! { // destination position because we are doing a removal from the list but no insert. let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); - let stash = scenario.origin_stash1.clone(); + let stash = scenario.origin_stash1; assert!(T::VoterList::contains(&stash)); add_slashing_spans::(&stash, s); @@ -561,10 +561,10 @@ benchmarks! { let validator_controller = >::get(&validator).unwrap(); let balance_before = T::Currency::free_balance(&validator_controller); for (_, controller) in &nominators { - let balance = T::Currency::free_balance(&controller); + let balance = T::Currency::free_balance(controller); ensure!(balance.is_zero(), "Controller has balance, but should be dead."); } - }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era) + }: payout_stakers(RawOrigin::Signed(caller), validator, current_era) verify { let balance_after = T::Currency::free_balance(&validator_controller); ensure!( @@ -572,7 +572,7 @@ benchmarks! { "Balance of validator controller should have increased after payout.", ); for (_, controller) in &nominators { - let balance = T::Currency::free_balance(&controller); + let balance = T::Currency::free_balance(controller); ensure!(!balance.is_zero(), "Payout not given to controller."); } } @@ -594,7 +594,7 @@ benchmarks! { let balance_before = T::Currency::free_balance(&validator); let mut nominator_balances_before = Vec::new(); for (stash, _) in &nominators { - let balance = T::Currency::free_balance(&stash); + let balance = T::Currency::free_balance(stash); nominator_balances_before.push(balance); } }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era) @@ -605,7 +605,7 @@ benchmarks! { "Balance of validator stash should have increased after payout.", ); for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) { - let balance_after = T::Currency::free_balance(&stash); + let balance_after = T::Currency::free_balance(stash); ensure!( balance_before < &balance_after, "Balance of nominator stash should have increased after payout.", @@ -626,7 +626,7 @@ benchmarks! { // setup a worst case list scenario. let scenario = ListScenario::::new(origin_weight, true)?; - let dest_weight = scenario.dest_weight.clone(); + let dest_weight = scenario.dest_weight; // rebond an amount that will give the user dest_weight let rebond_amount = dest_weight - origin_weight; @@ -644,7 +644,7 @@ benchmarks! { }; let stash = scenario.origin_stash1.clone(); - let controller = scenario.origin_controller1.clone(); + let controller = scenario.origin_controller1; let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); for _ in 0 .. l { @@ -691,7 +691,7 @@ benchmarks! { // destination position because we are doing a removal from the list but no insert. let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); - let stash = scenario.origin_stash1.clone(); + let stash = scenario.origin_stash1; add_slashing_spans::(&stash, s); let l = StakingLedger { @@ -895,7 +895,7 @@ benchmarks! { // destination position because we are doing a removal from the list but no insert. let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); - let stash = scenario.origin_stash1.clone(); + let stash = scenario.origin_stash1; assert!(T::VoterList::contains(&stash)); Staking::::set_staking_configs( @@ -909,7 +909,7 @@ benchmarks! { )?; let caller = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), controller.clone()) + }: _(RawOrigin::Signed(caller), controller) verify { assert!(!T::VoterList::contains(&stash)); } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 037dcc86ab2a8..2d4c1ea9a3488 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -321,7 +321,7 @@ pub use weights::WeightInfo; pub use pallet::{pallet::*, *}; -pub(crate) const LOG_TARGET: &'static str = "runtime::staking"; +pub(crate) const LOG_TARGET: &str = "runtime::staking"; // syntactic sugar for logging. #[macro_export] @@ -784,7 +784,7 @@ impl (Balance, Balance) { let (validator_payout, max_payout) = inflation::compute_total_payout( - &T::get(), + T::get(), total_staked, total_issuance, // Duration of era; more than u64::MAX is rewarded as u64::MAX. diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 4665d956fdddb..0ac61e21fb323 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -123,8 +123,9 @@ impl Pallet { .claimed_rewards .retain(|&x| x >= current_era.saturating_sub(history_depth)); match ledger.claimed_rewards.binary_search(&era) { - Ok(_) => Err(Error::::AlreadyClaimed - .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)))?, + Ok(_) => + return Err(Error::::AlreadyClaimed + .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))), Err(pos) => ledger.claimed_rewards.insert(pos, era), } @@ -146,8 +147,8 @@ impl Pallet { let validator_reward_points = era_reward_points .individual .get(&ledger.stash) - .map(|points| *points) - .unwrap_or_else(|| Zero::zero()); + .copied() + .unwrap_or_else(Zero::zero); // Nothing to do if they have no reward points. if validator_reward_points.is_zero() { @@ -260,8 +261,7 @@ impl Pallet { 0 }); - let era_length = - session_index.checked_sub(current_era_start_session_index).unwrap_or(0); // Must never happen. + let era_length = session_index.saturating_sub(current_era_start_session_index); // Must never happen. match ForceEra::::get() { // Will be set to `NotForcing` again if a new era has been triggered. @@ -1036,7 +1036,7 @@ impl ElectionDataProvider for Pallet { ); Self::do_add_nominator( &v, - Nominations { targets: t.try_into().unwrap(), submitted_in: 0, suppressed: false }, + Nominations { targets: t, submitted_in: 0, suppressed: false }, ); }); } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index bf13786d64ee6..117bc6e7c15bb 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -580,7 +580,7 @@ pub mod pallet { status ); assert!( - T::Currency::free_balance(&stash) >= balance, + T::Currency::free_balance(stash) >= balance, "Stash does not have enough balance to bond." ); frame_support::assert_ok!(>::bond( @@ -779,18 +779,18 @@ pub mod pallet { let stash = ensure_signed(origin)?; if >::contains_key(&stash) { - Err(Error::::AlreadyBonded)? + return Err(Error::::AlreadyBonded.into()) } let controller = T::Lookup::lookup(controller)?; if >::contains_key(&controller) { - Err(Error::::AlreadyPaired)? + return Err(Error::::AlreadyPaired.into()) } // Reject a bond which is considered to be _dust_. if value < T::Currency::minimum_balance() { - Err(Error::::InsufficientBond)? + return Err(Error::::InsufficientBond.into()) } frame_system::Pallet::::inc_consumers(&stash).map_err(|_| Error::::BadState)?; @@ -862,7 +862,7 @@ pub mod pallet { debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); } - Self::deposit_event(Event::::Bonded(stash.clone(), extra)); + Self::deposit_event(Event::::Bonded(stash, extra)); } Ok(()) } @@ -1183,7 +1183,7 @@ pub mod pallet { let old_controller = Self::bonded(&stash).ok_or(Error::::NotStash)?; let controller = T::Lookup::lookup(controller)?; if >::contains_key(&controller) { - Err(Error::::AlreadyPaired)? + return Err(Error::::AlreadyPaired.into()) } if controller != old_controller { >::insert(&stash, &controller); @@ -1466,8 +1466,8 @@ pub mod pallet { ensure_root(origin)?; if let Some(current_era) = Self::current_era() { HistoryDepth::::mutate(|history_depth| { - let last_kept = current_era.checked_sub(*history_depth).unwrap_or(0); - let new_last_kept = current_era.checked_sub(new_history_depth).unwrap_or(0); + let last_kept = current_era.saturating_sub(*history_depth); + let new_last_kept = current_era.saturating_sub(new_history_depth); for era_index in last_kept..new_last_kept { Self::clear_era_information(era_index); } diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 9fc50eaf538f6..0d55eb7fe0ddb 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -389,7 +389,7 @@ fn slash_nominators( let mut era_slash = as Store>::NominatorSlashInEra::get(¶ms.slash_era, stash) - .unwrap_or_else(|| Zero::zero()); + .unwrap_or_else(Zero::zero); era_slash += own_slash_difference; @@ -646,7 +646,7 @@ pub(crate) fn apply_slash( for &(ref nominator, nominator_slash) in &unapplied_slash.others { do_slash::( - &nominator, + nominator, nominator_slash, &mut reward_payout, &mut slashed_imbalance, diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 5f9f378b10619..f30020597db45 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -85,7 +85,7 @@ pub fn create_stash_controller( amount, destination, )?; - return Ok((stash, controller)) + Ok((stash, controller)) } /// Create a stash and controller pair with fixed balance. @@ -127,7 +127,7 @@ pub fn create_stash_and_dead_controller( amount, destination, )?; - return Ok((stash, controller)) + Ok((stash, controller)) } /// create `max` validators. diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 3d66c6a66b8cf..d78fd7d9ca932 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -57,7 +57,7 @@ pub use pallet::*; -const LOG_TARGET: &'static str = "runtime::state-trie-migration"; +const LOG_TARGET: &str = "runtime::state-trie-migration"; #[macro_export] macro_rules! log { @@ -319,12 +319,12 @@ pub mod pallet { let (maybe_current_child, child_root) = match (&self.progress_child, &self.progress_top) { (Progress::LastKey(last_child), Progress::LastKey(last_top)) => { - let child_root = Pallet::::transform_child_key_or_halt(&last_top); - let maybe_current_child = child_io::next_key(child_root, &last_child); + let child_root = Pallet::::transform_child_key_or_halt(last_top); + let maybe_current_child = child_io::next_key(child_root, last_child); (maybe_current_child, child_root) }, (Progress::ToStart, Progress::LastKey(last_top)) => { - let child_root = Pallet::::transform_child_key_or_halt(&last_top); + let child_root = Pallet::::transform_child_key_or_halt(last_top); // Start with the empty key as first key. (Some(Vec::new()), child_root) }, @@ -336,7 +336,7 @@ pub mod pallet { }; if let Some(current_child) = maybe_current_child.as_ref() { - let added_size = if let Some(data) = child_io::get(child_root, ¤t_child) { + let added_size = if let Some(data) = child_io::get(child_root, current_child) { child_io::set(child_root, current_child, &data); data.len() as u32 } else { @@ -369,8 +369,8 @@ pub mod pallet { }; if let Some(current_top) = maybe_current_top.as_ref() { - let added_size = if let Some(data) = sp_io::storage::get(¤t_top) { - sp_io::storage::set(¤t_top, &data); + let added_size = if let Some(data) = sp_io::storage::get(current_top) { + sp_io::storage::set(current_top, &data); data.len() as u32 } else { Zero::zero() @@ -503,7 +503,7 @@ pub mod pallet { ) -> DispatchResult { T::ControlOrigin::ensure_origin(origin)?; AutoLimits::::put(maybe_config); - Ok(().into()) + Ok(()) } /// Continue the migration for the given `limits`. @@ -616,7 +616,7 @@ pub mod pallet { let mut dyn_size = 0u32; for key in &keys { - if let Some(data) = sp_io::storage::get(&key) { + if let Some(data) = sp_io::storage::get(key) { dyn_size = dyn_size.saturating_add(data.len() as u32); sp_io::storage::set(key, &data); } @@ -678,9 +678,9 @@ pub mod pallet { let mut dyn_size = 0u32; let transformed_child_key = Self::transform_child_key(&root).ok_or("bad child key")?; for child_key in &child_keys { - if let Some(data) = child_io::get(transformed_child_key, &child_key) { + if let Some(data) = child_io::get(transformed_child_key, child_key) { dyn_size = dyn_size.saturating_add(data.len() as u32); - child_io::set(transformed_child_key, &child_key, &data); + child_io::set(transformed_child_key, child_key, &data); } } @@ -839,7 +839,7 @@ mod benchmarks { // The size of the key seemingly makes no difference in the read/write time, so we make it // constant. - const KEY: &'static [u8] = b"key"; + const KEY: &[u8] = b"key"; frame_benchmarking::benchmarks! { continue_migrate { diff --git a/frame/support/procedural/src/construct_runtime/expand/config.rs b/frame/support/procedural/src/construct_runtime/expand/config.rs index 79176fa7385ec..a3d70f18529c7 100644 --- a/frame/support/procedural/src/construct_runtime/expand/config.rs +++ b/frame/support/procedural/src/construct_runtime/expand/config.rs @@ -43,12 +43,8 @@ pub fn expand_outer_config( types.extend(expand_config_types(runtime, decl, &config, part_is_generic)); fields.extend(quote!(pub #field_name: #config,)); - build_storage_calls.extend(expand_config_build_storage_call( - scrate, - runtime, - decl, - &field_name, - )); + build_storage_calls + .extend(expand_config_build_storage_call(scrate, runtime, decl, field_name)); query_genesis_config_part_macros.push(quote! { #path::__substrate_genesis_config_check::is_genesis_config_defined!(#pallet_name); #[cfg(feature = "std")] diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 2a86869382c93..7b4156a94db58 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -201,7 +201,7 @@ fn construct_runtime_intermediary_expansion( ); } - Ok(expansion.into()) + Ok(expansion) } /// All pallets have explicit definition of parts, this will expand to the runtime declaration. @@ -225,16 +225,16 @@ fn construct_runtime_final_expansion( })?; let hidden_crate_name = "construct_runtime"; - let scrate = generate_crate_access(&hidden_crate_name, "frame-support"); - let scrate_decl = generate_hidden_includes(&hidden_crate_name, "frame-support"); + let scrate = generate_crate_access(hidden_crate_name, "frame-support"); + let scrate_decl = generate_hidden_includes(hidden_crate_name, "frame-support"); let outer_event = expand::expand_outer_event(&name, &pallets, &scrate)?; - let outer_origin = expand::expand_outer_origin(&name, &system_pallet, &pallets, &scrate)?; + let outer_origin = expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?; let all_pallets = decl_all_pallets(&name, pallets.iter()); let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate); - let dispatch = expand::expand_outer_dispatch(&name, &system_pallet, &pallets, &scrate); + let dispatch = expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate); let metadata = expand::expand_runtime_metadata(&name, &pallets, &scrate, &unchecked_extrinsic); let outer_config = expand::expand_outer_config(&name, &pallets, &scrate); let inherent = diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 2d7c550a44869..60546e1a96779 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -68,7 +68,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { .args .iter() .map(|(_, name, _)| { - syn::Ident::new(&name.to_string().trim_start_matches('_'), name.span()) + syn::Ident::new(name.to_string().trim_start_matches('_'), name.span()) }) .collect::>() }) diff --git a/frame/support/procedural/src/pallet/expand/genesis_config.rs b/frame/support/procedural/src/pallet/expand/genesis_config.rs index 18fa87a262533..739e85e0d1ced 100644 --- a/frame/support/procedural/src/pallet/expand/genesis_config.rs +++ b/frame/support/procedural/src/pallet/expand/genesis_config.rs @@ -85,7 +85,7 @@ pub fn expand_genesis_config(def: &mut Def) -> proc_macro2::TokenStream { syn::Item::Enum(syn::ItemEnum { attrs, .. }) | syn::Item::Struct(syn::ItemStruct { attrs, .. }) | syn::Item::Type(syn::ItemType { attrs, .. }) => { - if get_doc_literals(&attrs).is_empty() { + if get_doc_literals(attrs).is_empty() { attrs.push(syn::parse_quote!( #[doc = r" Can be used to configure the diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index d59dd46051392..657968e17a80c 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -74,9 +74,7 @@ fn check_prefix_duplicates( ), ); - if let Some(other_dup_err) = - used_prefixes.insert(counter_prefix.clone(), counter_dup_err.clone()) - { + if let Some(other_dup_err) = used_prefixes.insert(counter_prefix, counter_dup_err.clone()) { let mut err = counter_dup_err; err.combine(other_dup_err); return Err(err) @@ -113,7 +111,7 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> { _ => unreachable!("Checked by def"), }; - let prefix_ident = prefix_ident(&storage_def); + let prefix_ident = prefix_ident(storage_def); let type_use_gen = if def.config.has_instance { quote::quote_spanned!(storage_def.attr_span => T, I) } else { @@ -215,7 +213,7 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> { /// * generate metadatas pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { if let Err(e) = process_generics(def) { - return e.into_compile_error().into() + return e.into_compile_error() } // Check for duplicate prefixes @@ -393,7 +391,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { let prefix_structs = def.storages.iter().map(|storage_def| { let type_impl_gen = &def.type_impl_generics(storage_def.attr_span); let type_use_gen = &def.type_use_generics(storage_def.attr_span); - let prefix_struct_ident = prefix_ident(&storage_def); + let prefix_struct_ident = prefix_ident(storage_def); let prefix_struct_vis = &storage_def.vis; let prefix_struct_const = storage_def.prefix(); let config_where_clause = &def.config.where_clause; diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index 5468b1352197e..f532d339f1205 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -133,9 +133,10 @@ impl CallDef { return Err(syn::Error::new(item.span(), "Invalid pallet::call, expected item impl")) }; - let mut instances = vec![]; - instances.push(helper::check_impl_gen(&item.generics, item.impl_token.span())?); - instances.push(helper::check_pallet_struct_usage(&item.self_ty)?); + let instances = vec![ + helper::check_impl_gen(&item.generics, item.impl_token.span())?, + helper::check_pallet_struct_usage(&item.self_ty)?, + ]; if let Some((_, _, for_)) = item.trait_ { let msg = "Invalid pallet::call, expected no trait ident as in \ diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 526c7eda2fd57..60888fc5dd357 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -373,9 +373,10 @@ impl ConfigDef { let found = if item.supertraits.is_empty() { "none".to_string() } else { - let mut found = item.supertraits.iter().fold(String::new(), |acc, s| { - format!("{}`{}`, ", acc, quote::quote!(#s).to_string()) - }); + let mut found = item + .supertraits + .iter() + .fold(String::new(), |acc, s| format!("{}`{}`, ", acc, quote::quote!(#s))); found.pop(); found.pop(); found diff --git a/frame/support/procedural/src/pallet/parse/error.rs b/frame/support/procedural/src/pallet/parse/error.rs index 0ec49aa0adb49..c6ce9b37c75a2 100644 --- a/frame/support/procedural/src/pallet/parse/error.rs +++ b/frame/support/procedural/src/pallet/parse/error.rs @@ -62,8 +62,8 @@ impl ErrorDef { return Err(syn::Error::new(item.span(), msg)) } - let mut instances = vec![]; - instances.push(helper::check_type_def_gen_no_bounds(&item.generics, item.ident.span())?); + let instances = + vec![helper::check_type_def_gen_no_bounds(&item.generics, item.ident.span())?]; if item.generics.where_clause.is_some() { let msg = "Invalid pallet::error, where clause is not allowed on pallet error item"; diff --git a/frame/support/procedural/src/pallet/parse/extra_constants.rs b/frame/support/procedural/src/pallet/parse/extra_constants.rs index 7163b4b632089..d8622da08461b 100644 --- a/frame/support/procedural/src/pallet/parse/extra_constants.rs +++ b/frame/support/procedural/src/pallet/parse/extra_constants.rs @@ -87,9 +87,10 @@ impl ExtraConstantsDef { )) }; - let mut instances = vec![]; - instances.push(helper::check_impl_gen(&item.generics, item.impl_token.span())?); - instances.push(helper::check_pallet_struct_usage(&item.self_ty)?); + let instances = vec![ + helper::check_impl_gen(&item.generics, item.impl_token.span())?, + helper::check_pallet_struct_usage(&item.self_ty)?, + ]; if let Some((_, _, for_)) = item.trait_ { let msg = "Invalid pallet::call, expected no trait ident as in \ diff --git a/frame/support/procedural/src/pallet/parse/genesis_build.rs b/frame/support/procedural/src/pallet/parse/genesis_build.rs index 79ee083069821..9815b8d2203c4 100644 --- a/frame/support/procedural/src/pallet/parse/genesis_build.rs +++ b/frame/support/procedural/src/pallet/parse/genesis_build.rs @@ -53,8 +53,7 @@ impl GenesisBuildDef { })? .1; - let mut instances = vec![]; - instances.push(helper::check_genesis_builder_usage(&item_trait)?); + let instances = vec![helper::check_genesis_builder_usage(item_trait)?]; Ok(Self { attr_span, index, instances, where_clause: item.generics.where_clause.clone() }) } diff --git a/frame/support/procedural/src/pallet/parse/genesis_config.rs b/frame/support/procedural/src/pallet/parse/genesis_config.rs index 875d15bdc061d..45e765c018aae 100644 --- a/frame/support/procedural/src/pallet/parse/genesis_config.rs +++ b/frame/support/procedural/src/pallet/parse/genesis_config.rs @@ -49,7 +49,7 @@ impl GenesisConfigDef { let mut instances = vec![]; // NOTE: GenesisConfig is not allowed to be only generic on I because it is not supported // by construct_runtime. - if let Some(u) = helper::check_type_def_optional_gen(&generics, ident.span())? { + if let Some(u) = helper::check_type_def_optional_gen(generics, ident.span())? { instances.push(u); } diff --git a/frame/support/procedural/src/pallet/parse/hooks.rs b/frame/support/procedural/src/pallet/parse/hooks.rs index cacc149e48668..2dc8f4da47c5f 100644 --- a/frame/support/procedural/src/pallet/parse/hooks.rs +++ b/frame/support/procedural/src/pallet/parse/hooks.rs @@ -45,9 +45,10 @@ impl HooksDef { return Err(syn::Error::new(item.span(), msg)) }; - let mut instances = vec![]; - instances.push(helper::check_pallet_struct_usage(&item.self_ty)?); - instances.push(helper::check_impl_gen(&item.generics, item.impl_token.span())?); + let instances = vec![ + helper::check_pallet_struct_usage(&item.self_ty)?, + helper::check_impl_gen(&item.generics, item.impl_token.span())?, + ]; let item_trait = &item .trait_ diff --git a/frame/support/procedural/src/pallet/parse/inherent.rs b/frame/support/procedural/src/pallet/parse/inherent.rs index 2833b3ef5c724..a485eed4c40d9 100644 --- a/frame/support/procedural/src/pallet/parse/inherent.rs +++ b/frame/support/procedural/src/pallet/parse/inherent.rs @@ -50,9 +50,10 @@ impl InherentDef { return Err(syn::Error::new(item.span(), msg)) } - let mut instances = vec![]; - instances.push(helper::check_pallet_struct_usage(&item.self_ty)?); - instances.push(helper::check_impl_gen(&item.generics, item.impl_token.span())?); + let instances = vec![ + helper::check_pallet_struct_usage(&item.self_ty)?, + helper::check_impl_gen(&item.generics, item.impl_token.span())?, + ]; Ok(InherentDef { index, instances }) } diff --git a/frame/support/procedural/src/pallet/parse/origin.rs b/frame/support/procedural/src/pallet/parse/origin.rs index 2d729376f5de4..89929e3e8dbfc 100644 --- a/frame/support/procedural/src/pallet/parse/origin.rs +++ b/frame/support/procedural/src/pallet/parse/origin.rs @@ -50,7 +50,7 @@ impl OriginDef { let is_generic = !generics.params.is_empty(); let mut instances = vec![]; - if let Some(u) = helper::check_type_def_optional_gen(&generics, item.span())? { + if let Some(u) = helper::check_type_def_optional_gen(generics, item.span())? { instances.push(u); } else { // construct_runtime only allow generic event for instantiable pallet. diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index d98862be8f783..a96c310b6f1ca 100644 --- a/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -155,8 +155,8 @@ impl PalletStructDef { return Err(syn::Error::new(item.generics.where_clause.span(), msg)) } - let mut instances = vec![]; - instances.push(helper::check_type_def_gen_no_bounds(&item.generics, item.ident.span())?); + let instances = + vec![helper::check_type_def_gen_no_bounds(&item.generics, item.ident.span())?]; Ok(Self { index, diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index effe0ce6c55d8..1f1bb5b2f26ad 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -272,7 +272,7 @@ fn check_generics( ); e.pop(); e.pop(); - e.push_str("."); + e.push('.'); e }; @@ -550,7 +550,7 @@ fn process_generics( let args_span = segment.arguments.span(); let args = match &segment.arguments { - syn::PathArguments::AngleBracketed(args) if args.args.len() != 0 => args, + syn::PathArguments::AngleBracketed(args) if !args.args.is_empty() => args, _ => { let msg = "Invalid pallet::storage, invalid number of generic generic arguments, \ expect more that 0 generic arguments."; @@ -646,13 +646,16 @@ impl StorageDef { self.rename_as .as_ref() .map(syn::LitStr::value) - .unwrap_or(self.ident.to_string()) + .unwrap_or_else(|| self.ident.to_string()) } /// Return either the span of the ident or the span of the literal in the /// #[storage_prefix] attribute pub fn prefix_span(&self) -> proc_macro2::Span { - self.rename_as.as_ref().map(syn::LitStr::span).unwrap_or(self.ident.span()) + self.rename_as + .as_ref() + .map(syn::LitStr::span) + .unwrap_or_else(|| self.ident.span()) } pub fn try_from( @@ -672,8 +675,7 @@ impl StorageDef { let cfg_attrs = helper::get_item_cfg_attrs(&item.attrs); - let mut instances = vec![]; - instances.push(helper::check_type_def_gen(&item.generics, item.ident.span())?); + let instances = vec![helper::check_type_def_gen(&item.generics, item.ident.span())?]; let where_clause = item.generics.where_clause.clone(); let docs = get_doc_literals(&item.attrs); diff --git a/frame/support/procedural/src/pallet/parse/validate_unsigned.rs b/frame/support/procedural/src/pallet/parse/validate_unsigned.rs index a58671d9762de..18d5a2dc4443f 100644 --- a/frame/support/procedural/src/pallet/parse/validate_unsigned.rs +++ b/frame/support/procedural/src/pallet/parse/validate_unsigned.rs @@ -52,9 +52,10 @@ impl ValidateUnsignedDef { return Err(syn::Error::new(item.span(), msg)) } - let mut instances = vec![]; - instances.push(helper::check_pallet_struct_usage(&item.self_ty)?); - instances.push(helper::check_impl_gen(&item.generics, item.impl_token.span())?); + let instances = vec![ + helper::check_pallet_struct_usage(&item.self_ty)?, + helper::check_impl_gen(&item.generics, item.impl_token.span())?, + ]; Ok(ValidateUnsignedDef { index, instances }) } diff --git a/frame/support/procedural/src/storage/genesis_config/builder_def.rs b/frame/support/procedural/src/storage/genesis_config/builder_def.rs index 975791881da23..29e2560bc16e4 100644 --- a/frame/support/procedural/src/storage/genesis_config/builder_def.rs +++ b/frame/support/procedural/src/storage/genesis_config/builder_def.rs @@ -49,7 +49,7 @@ impl BuilderDef { let mut data = None; if let Some(builder) = &line.build { - is_generic |= ext::expr_contains_ident(&builder, &def.module_runtime_generic); + is_generic |= ext::expr_contains_ident(builder, &def.module_runtime_generic); is_generic |= line.is_generic; data = Some(match &line.storage_type { @@ -138,7 +138,7 @@ impl BuilderDef { } if let Some(builder) = def.extra_genesis_build.as_ref() { - is_generic |= ext::expr_contains_ident(&builder, &def.module_runtime_generic); + is_generic |= ext::expr_contains_ident(builder, &def.module_runtime_generic); blocks.push(quote_spanned! { builder.span() => let extra_genesis_builder: fn(&Self) = #builder; diff --git a/frame/support/procedural/src/storage/instance_trait.rs b/frame/support/procedural/src/storage/instance_trait.rs index 14e968112029e..e9df02e3dc132 100644 --- a/frame/support/procedural/src/storage/instance_trait.rs +++ b/frame/support/procedural/src/storage/instance_trait.rs @@ -116,7 +116,7 @@ fn create_and_impl_instance_struct( let instance_trait = quote!( #scrate::traits::Instance ); let instance_struct = &instance_def.instance_struct; - let prefix = format!("{}{}", instance_def.prefix, def.crate_name.to_string()); + let prefix = format!("{}{}", instance_def.prefix, def.crate_name); let doc = &instance_def.doc; let index = instance_def.index; diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index b89e756334986..756653f7ba85d 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -259,7 +259,7 @@ impl StorageLineDefExt { ) -> Self { let is_generic = match &storage_def.storage_type { StorageLineTypeDef::Simple(value) => - ext::type_contains_ident(&value, &def.module_runtime_generic), + ext::type_contains_ident(value, &def.module_runtime_generic), StorageLineTypeDef::Map(map) => ext::type_contains_ident(&map.key, &def.module_runtime_generic) || ext::type_contains_ident(&map.value, &def.module_runtime_generic), diff --git a/frame/support/src/hash.rs b/frame/support/src/hash.rs index 9ce0968351a42..9bdad6d9d59de 100644 --- a/frame/support/src/hash.rs +++ b/frame/support/src/hash.rs @@ -101,7 +101,7 @@ impl StorageHasher for Twox64Concat { const METADATA: metadata::StorageHasher = metadata::StorageHasher::Twox64Concat; type Output = Vec; fn hash(x: &[u8]) -> Vec { - twox_64(x).iter().chain(x.into_iter()).cloned().collect::>() + twox_64(x).iter().chain(x.iter()).cloned().collect::>() } fn max_len() -> usize { K::max_encoded_len().saturating_add(8) @@ -123,7 +123,7 @@ impl StorageHasher for Blake2_128Concat { const METADATA: metadata::StorageHasher = metadata::StorageHasher::Blake2_128Concat; type Output = Vec; fn hash(x: &[u8]) -> Vec { - blake2_128(x).iter().chain(x.into_iter()).cloned().collect::>() + blake2_128(x).iter().chain(x.iter()).cloned().collect::>() } fn max_len() -> usize { K::max_encoded_len().saturating_add(16) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 2d2944cc9a44f..3e84c009b5ca6 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -105,7 +105,7 @@ use scale_info::TypeInfo; use sp_runtime::TypeId; /// A unified log target for support operations. -pub const LOG_TARGET: &'static str = "runtime::frame-support"; +pub const LOG_TARGET: &str = "runtime::frame-support"; /// A type that cannot be instantiated. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] diff --git a/frame/support/src/storage/child.rs b/frame/support/src/storage/child.rs index 949df84e7e768..e20d4fe0cd4d3 100644 --- a/frame/support/src/storage/child.rs +++ b/frame/support/src/storage/child.rs @@ -50,7 +50,7 @@ pub fn get(child_info: &ChildInfo, key: &[u8]) -> Option { /// Return the value of the item in storage under `key`, or the type's default if there is no /// explicit entry. pub fn get_or_default(child_info: &ChildInfo, key: &[u8]) -> T { - get(child_info, key).unwrap_or_else(Default::default) + get(child_info, key).unwrap_or_default() } /// Return the value of the item in storage under `key`, or `default_value` if there is no @@ -90,7 +90,7 @@ pub fn take(child_info: &ChildInfo, key: &[u8]) -> Option /// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage, /// the default for its type. pub fn take_or_default(child_info: &ChildInfo, key: &[u8]) -> T { - take(child_info, key).unwrap_or_else(Default::default) + take(child_info, key).unwrap_or_default() } /// Return the value of the item in storage under `key`, or `default_value` if there is no diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index 12e1764bfb65d..16fcaf940c62a 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -461,7 +461,7 @@ where }, }; - let mut key2_material = G::Hasher2::reverse(&key_material); + let mut key2_material = G::Hasher2::reverse(key_material); let key2 = match K2::decode(&mut key2_material) { Ok(key2) => key2, Err(_) => { diff --git a/frame/support/src/storage/hashed.rs b/frame/support/src/storage/hashed.rs index a07db73c947d5..19c9d73be868d 100644 --- a/frame/support/src/storage/hashed.rs +++ b/frame/support/src/storage/hashed.rs @@ -28,7 +28,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::get(&hash(key).as_ref()) + unhashed::get(hash(key).as_ref()) } /// Return the value of the item in storage under `key`, or the type's default if there is no @@ -39,7 +39,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::get_or_default(&hash(key).as_ref()) + unhashed::get_or_default(hash(key).as_ref()) } /// Return the value of the item in storage under `key`, or `default_value` if there is no @@ -50,7 +50,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::get_or(&hash(key).as_ref(), default_value) + unhashed::get_or(hash(key).as_ref(), default_value) } /// Return the value of the item in storage under `key`, or `default_value()` if there is no @@ -62,7 +62,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::get_or_else(&hash(key).as_ref(), default_value) + unhashed::get_or_else(hash(key).as_ref(), default_value) } /// Put `value` in storage under `key`. @@ -72,7 +72,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::put(&hash(key).as_ref(), value) + unhashed::put(hash(key).as_ref(), value) } /// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise. @@ -82,7 +82,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::take(&hash(key).as_ref()) + unhashed::take(hash(key).as_ref()) } /// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage, @@ -93,7 +93,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::take_or_default(&hash(key).as_ref()) + unhashed::take_or_default(hash(key).as_ref()) } /// Return the value of the item in storage under `key`, or `default_value` if there is no @@ -104,7 +104,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::take_or(&hash(key).as_ref(), default_value) + unhashed::take_or(hash(key).as_ref(), default_value) } /// Return the value of the item in storage under `key`, or `default_value()` if there is no @@ -116,7 +116,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::take_or_else(&hash(key).as_ref(), default_value) + unhashed::take_or_else(hash(key).as_ref(), default_value) } /// Check to see if `key` has an explicit entry in storage. @@ -125,7 +125,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::exists(&hash(key).as_ref()) + unhashed::exists(hash(key).as_ref()) } /// Ensure `key` has no explicit entry in storage. @@ -134,7 +134,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::kill(&hash(key).as_ref()) + unhashed::kill(hash(key).as_ref()) } /// Get a Vec of bytes from storage. @@ -143,7 +143,7 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::get_raw(&hash(key).as_ref()) + unhashed::get_raw(hash(key).as_ref()) } /// Put a raw byte slice into storage. @@ -152,5 +152,5 @@ where HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>, { - unhashed::put_raw(&hash(key).as_ref(), value) + unhashed::put_raw(hash(key).as_ref(), value) } diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 066422ad456aa..115f179d803a7 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -1038,7 +1038,7 @@ impl Iterator for ChildTriePrefixIterator { Some(self.previous_key.clone()) } else { sp_io::default_child_storage::next_key( - &self.child_info.storage_key(), + self.child_info.storage_key(), &self.previous_key, ) .filter(|n| n.starts_with(&self.prefix)) diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 9c48267af86e0..a2160ede52fe9 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -217,8 +217,7 @@ where /// Take the value under a key. pub fn take + Clone>(key: KeyArg) -> QueryKind::Query { - let removed_value = - ::Map::mutate_exists(key, |value| core::mem::replace(value, None)); + let removed_value = ::Map::mutate_exists(key, |value| value.take()); if removed_value.is_some() { CounterFor::::mutate(|value| value.saturating_dec()); } @@ -429,7 +428,7 @@ where if cfg!(feature = "no-metadata-docs") { vec![] } else { - vec![&"Counter for the related counted storage map"] + vec!["Counter for the related counted storage map"] }, entries, ); diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index aff32f2110009..16dc30ea03903 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -481,7 +481,7 @@ where modifier: QueryKind::METADATA, ty: StorageEntryType::Map { key: scale_info::meta_type::(), - hashers: Key::HASHER_METADATA.iter().cloned().collect(), + hashers: Key::HASHER_METADATA.to_vec(), value: scale_info::meta_type::(), }, default: OnEmpty::get().encode(), diff --git a/frame/support/src/storage/unhashed.rs b/frame/support/src/storage/unhashed.rs index 96bccc6ae0feb..adabc9c14a3d5 100644 --- a/frame/support/src/storage/unhashed.rs +++ b/frame/support/src/storage/unhashed.rs @@ -38,7 +38,7 @@ pub fn get(key: &[u8]) -> Option { /// Return the value of the item in storage under `key`, or the type's default if there is no /// explicit entry. pub fn get_or_default(key: &[u8]) -> T { - get(key).unwrap_or_else(Default::default) + get(key).unwrap_or_default() } /// Return the value of the item in storage under `key`, or `default_value` if there is no @@ -70,7 +70,7 @@ pub fn take(key: &[u8]) -> Option { /// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage, /// the default for its type. pub fn take_or_default(key: &[u8]) -> T { - take(key).unwrap_or_else(Default::default) + take(key).unwrap_or_default() } /// Return the value of the item in storage under `key`, or `default_value` if there is no diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 250a31ebfb17a..443941bd8d771 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -157,7 +157,7 @@ impl, R: EnsureOrigin> type Success = Either; fn try_origin(o: OuterOrigin) -> Result { L::try_origin(o) - .map_or_else(|o| R::try_origin(o).map(|o| Either::Right(o)), |o| Ok(Either::Left(o))) + .map_or_else(|o| R::try_origin(o).map(Either::Right), |o| Ok(Either::Left(o))) } #[cfg(feature = "runtime-benchmarks")] diff --git a/frame/support/src/traits/members.rs b/frame/support/src/traits/members.rs index f3c586b64af04..8c69a2aaccb33 100644 --- a/frame/support/src/traits/members.rs +++ b/frame/support/src/traits/members.rs @@ -299,7 +299,7 @@ pub trait ChangeMembers { /// This resets any previous value of prime. fn set_members_sorted(new_members: &[AccountId], old_members: &[AccountId]) { let (incoming, outgoing) = Self::compute_members_diff_sorted(new_members, old_members); - Self::change_members_sorted(&incoming[..], &outgoing[..], &new_members); + Self::change_members_sorted(&incoming[..], &outgoing[..], new_members); } /// Compute diff between new and old members; they **must already be sorted**. diff --git a/frame/support/src/traits/metadata.rs b/frame/support/src/traits/metadata.rs index c76c53dbe8b2d..d3dc57e1ee52d 100644 --- a/frame/support/src/traits/metadata.rs +++ b/frame/support/src/traits/metadata.rs @@ -161,7 +161,7 @@ impl sp_std::cmp::Ord for CrateVersion { impl sp_std::cmp::PartialOrd for CrateVersion { fn partial_cmp(&self, other: &Self) -> Option { - Some(::cmp(&self, other)) + Some(::cmp(self, other)) } } diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 7575aa8c19dc6..b67eac2fbe7bc 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -25,9 +25,9 @@ use sp_runtime::{traits::Block as BlockT, DispatchError}; use sp_std::{cmp::Ordering, prelude::*}; #[doc(hidden)] -pub const DEFENSIVE_OP_PUBLIC_ERROR: &'static str = "a defensive failure has been triggered; please report the block number at https://github.com/paritytech/substrate/issues"; +pub const DEFENSIVE_OP_PUBLIC_ERROR: &str = "a defensive failure has been triggered; please report the block number at https://github.com/paritytech/substrate/issues"; #[doc(hidden)] -pub const DEFENSIVE_OP_INTERNAL_ERROR: &'static str = "Defensive failure has been triggered!"; +pub const DEFENSIVE_OP_INTERNAL_ERROR: &str = "Defensive failure has been triggered!"; /// Generic function to mark an execution path as ONLY defensive. /// diff --git a/frame/support/src/traits/stored_map.rs b/frame/support/src/traits/stored_map.rs index 3c3ff2eb0ed98..2aae88096ec74 100644 --- a/frame/support/src/traits/stored_map.rs +++ b/frame/support/src/traits/stored_map.rs @@ -101,7 +101,7 @@ impl< } fn remove(k: &K) -> Result<(), DispatchError> { if S::contains_key(&k) { - L::killed(&k)?; + L::killed(k)?; S::remove(k); } Ok(()) diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index d4b5c0c184f85..9a1634fd89313 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -83,7 +83,7 @@ pub trait Currency { /// This is just the same as burning and issuing the same amount and has no effect on the /// total issuance. fn pair(amount: Self::Balance) -> (Self::PositiveImbalance, Self::NegativeImbalance) { - (Self::burn(amount.clone()), Self::issue(amount)) + (Self::burn(amount), Self::issue(amount)) } /// The 'free' balance of a given account. diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs index 7422a9d651874..90aadb6d8daa6 100644 --- a/frame/support/src/traits/tokens/fungible.rs +++ b/frame/support/src/traits/tokens/fungible.rs @@ -92,7 +92,7 @@ pub trait Mutate: Inspect { let extra = Self::can_withdraw(&source, amount).into_result()?; // As we first burn and then mint, we don't need to check if `mint` fits into the supply. // If we can withdraw/burn it, we can also mint it again. - Self::can_deposit(&dest, amount.saturating_add(extra), false).into_result()?; + Self::can_deposit(dest, amount.saturating_add(extra), false).into_result()?; let actual = Self::burn_from(source, amount)?; debug_assert!( actual == amount.saturating_add(extra), diff --git a/frame/support/src/traits/tokens/fungible/balanced.rs b/frame/support/src/traits/tokens/fungible/balanced.rs index 196f3a35754af..ed9c3a1afa480 100644 --- a/frame/support/src/traits/tokens/fungible/balanced.rs +++ b/frame/support/src/traits/tokens/fungible/balanced.rs @@ -165,7 +165,7 @@ pub trait Unbalanced: Inspect { ) -> Result { let old_balance = Self::balance(who); let (mut new_balance, mut amount) = if old_balance < amount { - Err(TokenError::NoFunds)? + return Err(TokenError::NoFunds.into()) } else { (old_balance - amount, amount) }; @@ -225,7 +225,7 @@ pub trait Unbalanced: Inspect { let old_balance = Self::balance(who); let new_balance = old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; if new_balance < Self::minimum_balance() { - Err(TokenError::BelowMinimum)? + return Err(TokenError::BelowMinimum.into()) } if old_balance != new_balance { Self::set_balance(who, new_balance)?; diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 2abadf037687d..dab50d56962f6 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -145,7 +145,7 @@ pub trait Mutate: Inspect { let extra = Self::can_withdraw(asset, &source, amount).into_result()?; // As we first burn and then mint, we don't need to check if `mint` fits into the supply. // If we can withdraw/burn it, we can also mint it again. - Self::can_deposit(asset, &dest, amount.saturating_add(extra), false).into_result()?; + Self::can_deposit(asset, dest, amount.saturating_add(extra), false).into_result()?; let actual = Self::burn_from(asset, source, amount)?; debug_assert!( actual == amount.saturating_add(extra), diff --git a/frame/support/src/traits/tokens/fungibles/balanced.rs b/frame/support/src/traits/tokens/fungibles/balanced.rs index e07d45cc47170..a75832e4c440f 100644 --- a/frame/support/src/traits/tokens/fungibles/balanced.rs +++ b/frame/support/src/traits/tokens/fungibles/balanced.rs @@ -186,7 +186,7 @@ pub trait Unbalanced: Inspect { ) -> Result { let old_balance = Self::balance(asset, who); let (mut new_balance, mut amount) = if old_balance < amount { - Err(TokenError::NoFunds)? + return Err(TokenError::NoFunds.into()) } else { (old_balance - amount, amount) }; @@ -251,7 +251,7 @@ pub trait Unbalanced: Inspect { let old_balance = Self::balance(asset, who); let new_balance = old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; if new_balance < Self::minimum_balance(asset) { - Err(TokenError::BelowMinimum)? + return Err(TokenError::BelowMinimum.into()) } if old_balance != new_balance { Self::set_balance(asset, who, new_balance)?; diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index 5b4a13e7f9457..292c7d3e91d06 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -355,7 +355,7 @@ impl PostDispatchInfo { /// Extract the actual weight from a dispatch result if any or fall back to the default weight. pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Weight { match result { - Ok(post_info) => &post_info, + Ok(post_info) => post_info, Err(err) => &err.post_info, } .calc_actual_weight(info) @@ -432,7 +432,7 @@ where impl WeighData for Weight { fn weigh_data(&self, _: T) -> Weight { - return *self + *self } } @@ -450,7 +450,7 @@ impl PaysFee for Weight { impl WeighData for (Weight, DispatchClass, Pays) { fn weigh_data(&self, _: T) -> Weight { - return self.0 + self.0 } } @@ -468,7 +468,7 @@ impl PaysFee for (Weight, DispatchClass, Pays) { impl WeighData for (Weight, DispatchClass) { fn weigh_data(&self, _: T) -> Weight { - return self.0 + self.0 } } @@ -486,7 +486,7 @@ impl PaysFee for (Weight, DispatchClass) { impl WeighData for (Weight, Pays) { fn weigh_data(&self, _: T) -> Weight { - return self.0 + self.0 } } diff --git a/frame/system/src/extensions/check_non_zero_sender.rs b/frame/system/src/extensions/check_non_zero_sender.rs index f517201fbebc2..9a6c4007b3779 100644 --- a/frame/system/src/extensions/check_non_zero_sender.rs +++ b/frame/system/src/extensions/check_non_zero_sender.rs @@ -82,7 +82,7 @@ where _info: &DispatchInfoOf, _len: usize, ) -> TransactionValidity { - if who.using_encoded(|d| d.into_iter().all(|x| *x == 0)) { + if who.using_encoded(|d| d.iter().all(|x| *x == 0)) { return Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner)) } Ok(ValidTransaction::default()) diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index 774139054d08c..b59c36ecb53b5 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -188,7 +188,7 @@ where len: usize, ) -> Result<(), TransactionValidityError> { if info.class == DispatchClass::Mandatory { - Err(InvalidTransaction::MandatoryDispatch)? + return Err(InvalidTransaction::MandatoryDispatch.into()) } Self::do_pre_dispatch(info, len) } @@ -201,7 +201,7 @@ where len: usize, ) -> TransactionValidity { if info.class == DispatchClass::Mandatory { - Err(InvalidTransaction::MandatoryDispatch)? + return Err(InvalidTransaction::MandatoryDispatch.into()) } Self::do_validate(info, len) } @@ -234,7 +234,7 @@ where // extrinsics that result in error. if let (DispatchClass::Mandatory, Err(e)) = (info.class, result) { log::error!(target: "runtime::system", "Bad mandatory: {:?}", e); - Err(InvalidTransaction::BadMandatory)? + return Err(InvalidTransaction::BadMandatory.into()) } let unspent = post_info.calc_unspent(info); diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 14e67cfcd8156..ba494dfbd9f8c 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -456,7 +456,7 @@ pub mod pallet { pub fn kill_storage(origin: OriginFor, keys: Vec) -> DispatchResultWithPostInfo { ensure_root(origin)?; for key in &keys { - storage::unhashed::kill(&key); + storage::unhashed::kill(key); } Ok(().into()) } @@ -833,7 +833,7 @@ impl< Some(account) => account.clone(), None => zero_account_id, }; - O::from(RawOrigin::Signed(first_member.clone())) + O::from(RawOrigin::Signed(first_member)) } } @@ -1196,8 +1196,7 @@ impl Pallet { } let phase = ExecutionPhase::::get().unwrap_or_default(); - let event = - EventRecord { phase, event, topics: topics.iter().cloned().collect::>() }; + let event = EventRecord { phase, event, topics: topics.to_vec() }; // Index of the to be added event. let event_idx = { @@ -1522,16 +1521,16 @@ impl Pallet { /// of the old and new runtime has the same spec name and that the spec version is increasing. pub fn can_set_code(code: &[u8]) -> Result<(), sp_runtime::DispatchError> { let current_version = T::Version::get(); - let new_version = sp_io::misc::runtime_version(&code) + let new_version = sp_io::misc::runtime_version(code) .and_then(|v| RuntimeVersion::decode(&mut &v[..]).ok()) - .ok_or_else(|| Error::::FailedToExtractRuntimeVersion)?; + .ok_or(Error::::FailedToExtractRuntimeVersion)?; if new_version.spec_name != current_version.spec_name { - Err(Error::::InvalidSpecName)? + return Err(Error::::InvalidSpecName.into()) } if new_version.spec_version <= current_version.spec_version { - Err(Error::::SpecVersionNeedsToIncrease)? + return Err(Error::::SpecVersionNeedsToIncrease.into()) } Ok(()) diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index 4942a5dace7d4..d3c108afb6f32 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -217,7 +217,7 @@ impl BlockWeights { /// Verifies correctness of this `BlockWeights` object. pub fn validate(self) -> ValidationResult { fn or_max(w: Option) -> Weight { - w.unwrap_or_else(|| Weight::max_value()) + w.unwrap_or_else(Weight::max_value) } let mut error = ValidationErrors::default(); @@ -246,7 +246,7 @@ impl BlockWeights { ); // Max extrinsic should not be 0 error_assert!( - weights.max_extrinsic.unwrap_or_else(|| Weight::max_value()) > 0, + weights.max_extrinsic.unwrap_or_else(Weight::max_value) > 0, &mut error, "[{:?}] {:?} (max_extrinsic) must not be 0. Check base cost and average initialization cost.", class, weights.max_extrinsic, diff --git a/frame/system/src/migrations/mod.rs b/frame/system/src/migrations/mod.rs index 358ba55b7c819..872cf389d246c 100644 --- a/frame/system/src/migrations/mod.rs +++ b/frame/system/src/migrations/mod.rs @@ -89,7 +89,7 @@ frame_support::generate_storage_alias!( pub fn migrate_from_single_u8_to_triple_ref_count() -> Weight { let mut translated: usize = 0; >::translate::<(T::Index, u8, T::AccountData), _>(|_key, (nonce, rc, data)| { - translated = translated + 1; + translated += 1; Some(AccountInfo { nonce, consumers: rc as RefCount, providers: 1, sufficients: 0, data }) }); log::info!( @@ -107,7 +107,7 @@ pub fn migrate_from_single_to_triple_ref_count() -> Weight { let mut translated: usize = 0; >::translate::<(T::Index, RefCount, T::AccountData), _>( |_key, (nonce, consumers, data)| { - translated = translated + 1; + translated += 1; Some(AccountInfo { nonce, consumers, providers: 1, sufficients: 0, data }) }, ); @@ -125,7 +125,7 @@ pub fn migrate_from_dual_to_triple_ref_count() -> Weight { let mut translated: usize = 0; >::translate::<(T::Index, RefCount, RefCount, T::AccountData), _>( |_key, (nonce, consumers, providers, data)| { - translated = translated + 1; + translated += 1; Some(AccountInfo { nonce, consumers, providers, sufficients: 0, data }) }, ); diff --git a/frame/system/src/offchain.rs b/frame/system/src/offchain.rs index bf52ab8e3791d..86440188a765c 100644 --- a/frame/system/src/offchain.rs +++ b/frame/system/src/offchain.rs @@ -88,7 +88,7 @@ where call: >::OverarchingCall, signature: Option<::SignaturePayload>, ) -> Result<(), ()> { - let xt = T::Extrinsic::new(call.into(), signature).ok_or(())?; + let xt = T::Extrinsic::new(call, signature).ok_or(())?; sp_io::offchain::submit_transaction(xt.encode()) } @@ -163,7 +163,7 @@ impl, X> Signer keystore_accounts.map(|account| account.public).collect(); Box::new( - keys.into_iter() + keys.iter() .enumerate() .map(|(index, key)| { let account_id = key.clone().into_account(); diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index d8bfb405e5c7c..c75a0ac9765b9 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -229,7 +229,7 @@ pub mod pallet { let data = (*inherent_data).saturated_into::(); let next_time = cmp::max(data, Self::now() + T::MinimumPeriod::get()); - Some(Call::set { now: next_time.into() }) + Some(Call::set { now: next_time }) } fn check_inherent( @@ -240,7 +240,7 @@ pub mod pallet { sp_timestamp::Timestamp::new(30 * 1000); let t: u64 = match call { - Call::set { ref now } => now.clone().saturated_into::(), + Call::set { ref now } => (*now).saturated_into::(), _ => return Ok(()), }; diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 7abee6192f2e0..190ef60f3b810 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -131,7 +131,7 @@ benchmarks! { let reason_hash = T::Hashing::hash(&reason[..]); let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary)); ensure!(Tips::::contains_key(hash), "tip does not exist"); - create_tips::(t - 1, hash.clone(), value)?; + create_tips::(t - 1, hash, value)?; let caller = account("member", t - 1, SEED); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); @@ -159,7 +159,7 @@ benchmarks! { let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary)); ensure!(Tips::::contains_key(hash), "tip does not exist"); - create_tips::(t, hash.clone(), value)?; + create_tips::(t, hash, value)?; let caller = account("caller", t, SEED); // Whitelist caller account from further DB operations. diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index 4b7d78b90be38..b9868dac43011 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -340,7 +340,7 @@ pub mod pallet { let hash = T::Hashing::hash_of(&(&reason_hash, &who)); Reasons::::insert(&reason_hash, &reason); - Self::deposit_event(Event::NewTip { tip_hash: hash.clone() }); + Self::deposit_event(Event::NewTip { tip_hash: hash }); let tips = vec![(tipper.clone(), tip_value)]; let tip = OpenTip { reason: reason_hash, @@ -390,7 +390,7 @@ pub mod pallet { let mut tip = Tips::::get(hash).ok_or(Error::::UnknownTip)?; if Self::insert_tip_and_check_closing(&mut tip, tipper, tip_value) { - Self::deposit_event(Event::TipClosing { tip_hash: hash.clone() }); + Self::deposit_event(Event::TipClosing { tip_hash: hash }); } Tips::::insert(&hash, tip); Ok(()) diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs index 9eafc43fc2569..394696cc18929 100644 --- a/frame/transaction-payment/asset-tx-payment/src/payment.rs +++ b/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -127,15 +127,12 @@ where let converted_fee = CON::to_asset_balance(fee, asset_id) .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))? .max(min_converted_fee); - let can_withdraw = >::can_withdraw( - asset_id.into(), - who, - converted_fee, - ); + let can_withdraw = + >::can_withdraw(asset_id, who, converted_fee); if !matches!(can_withdraw, WithdrawConsequence::Success) { return Err(InvalidTransaction::Payment.into()) } - >::withdraw(asset_id.into(), who, converted_fee) + >::withdraw(asset_id, who, converted_fee) .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment)) } @@ -153,7 +150,7 @@ where ) -> Result<(), TransactionValidityError> { let min_converted_fee = if corrected_fee.is_zero() { Zero::zero() } else { One::one() }; // Convert the corrected fee into the asset used for payment. - let converted_fee = CON::to_asset_balance(corrected_fee, paid.asset().into()) + let converted_fee = CON::to_asset_balance(corrected_fee, paid.asset()) .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })? .max(min_converted_fee); // Calculate how much refund we should return. diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 1462faaa07062..45c8b8f479c9f 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -186,10 +186,8 @@ where let weights = T::BlockWeights::get(); // the computed ratio is only among the normal class. - let normal_max_weight = weights - .get(DispatchClass::Normal) - .max_total - .unwrap_or_else(|| weights.max_block); + let normal_max_weight = + weights.get(DispatchClass::Normal).max_total.unwrap_or(weights.max_block); let current_block_weight = >::block_weight(); let normal_block_weight = *current_block_weight.get(DispatchClass::Normal).min(&normal_max_weight); diff --git a/frame/transaction-payment/src/payment.rs b/frame/transaction-payment/src/payment.rs index 5b4a613102792..3a5fad0d66a52 100644 --- a/frame/transaction-payment/src/payment.rs +++ b/frame/transaction-payment/src/payment.rs @@ -132,7 +132,7 @@ where // refund to the the account that paid the fees. If this fails, the // account might have dropped below the existential balance. In // that case we don't refund anything. - let refund_imbalance = C::deposit_into_existing(&who, refund_amount) + let refund_imbalance = C::deposit_into_existing(who, refund_amount) .unwrap_or_else(|_| C::PositiveImbalance::zero()); // merge the imbalance caused by paying the fees and refunding parts of it again. let adjusted_paid = paid diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index e9aa786766dac..a63b31f2f1aac 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -192,8 +192,8 @@ pub mod pallet { let root = sp_io::trie::blake2_256_ordered_root(chunks, sp_runtime::StateVersion::V1); let content_hash = sp_io::hashing::blake2_256(&data); - let extrinsic_index = >::extrinsic_index() - .ok_or_else(|| Error::::BadContext)?; + let extrinsic_index = + >::extrinsic_index().ok_or(Error::::BadContext)?; sp_io::transaction_index::index(extrinsic_index, data.len() as u32, content_hash); let mut index = 0; @@ -287,13 +287,12 @@ pub mod pallet { Ok(index) => index, Err(index) => index, }; - let info = - infos.get(index).ok_or_else(|| Error::::MissingStateData)?.clone(); + let info = infos.get(index).ok_or(Error::::MissingStateData)?.clone(); let chunks = num_chunks(info.size); let prev_chunks = info.block_chunks - chunks; (info, selected_chunk_index - prev_chunks) }, - None => Err(Error::::MissingStateData)?, + None => return Err(Error::::MissingStateData.into()), }; ensure!( sp_io::trie::blake2_256_verify_proof( diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 19d3dfac6e5ac..b743ca12913a3 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -176,7 +176,7 @@ benchmarks_instance_pallet! { let witness = Class::::get(class).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), class, witness) verify { - assert_last_event::(Event::Destroyed { class: class }.into()); + assert_last_event::(Event::Destroyed { class }.into()); } mint { @@ -216,7 +216,7 @@ benchmarks_instance_pallet! { caller_lookup.clone(), caller_lookup.clone(), caller_lookup.clone(), - caller_lookup.clone(), + caller_lookup, true, false, )?; @@ -268,7 +268,7 @@ benchmarks_instance_pallet! { let target_lookup = T::Lookup::unlookup(target.clone()); T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); let origin = SystemOrigin::Signed(target.clone()).into(); - Uniques::::set_accept_ownership(origin, Some(class.clone()))?; + Uniques::::set_accept_ownership(origin, Some(class))?; }: _(SystemOrigin::Signed(caller), class, target_lookup) verify { assert_last_event::(Event::OwnerChanged { class, new_owner: target }.into()); @@ -279,7 +279,7 @@ benchmarks_instance_pallet! { let target0 = T::Lookup::unlookup(account("target", 0, SEED)); let target1 = T::Lookup::unlookup(account("target", 1, SEED)); let target2 = T::Lookup::unlookup(account("target", 2, SEED)); - }: _(SystemOrigin::Signed(caller), class, target0.clone(), target1.clone(), target2.clone()) + }: _(SystemOrigin::Signed(caller), class, target0, target1, target2) verify { assert_last_event::(Event::TeamChanged{ class, @@ -297,7 +297,7 @@ benchmarks_instance_pallet! { owner: caller_lookup.clone(), issuer: caller_lookup.clone(), admin: caller_lookup.clone(), - freezer: caller_lookup.clone(), + freezer: caller_lookup, free_holding: true, is_frozen: false, }; @@ -390,7 +390,7 @@ benchmarks_instance_pallet! { let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); let class = T::Helper::class(0); - }: _(SystemOrigin::Signed(caller.clone()), Some(class.clone())) + }: _(SystemOrigin::Signed(caller.clone()), Some(class)) verify { assert_last_event::(Event::OwnershipAcceptanceChanged { who: caller, diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 8b874997f2ff0..ea9eecd767dcf 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -73,7 +73,7 @@ impl, I: 'static> Pallet { owner: owner.clone(), issuer: admin.clone(), admin: admin.clone(), - freezer: admin.clone(), + freezer: admin, total_deposit: deposit, free_holding, instances: 0, @@ -135,7 +135,7 @@ impl, I: 'static> Pallet { Class::::try_mutate(&class, |maybe_class_details| -> DispatchResult { let class_details = maybe_class_details.as_mut().ok_or(Error::::UnknownClass)?; - with_details(&class_details)?; + with_details(class_details)?; let instances = class_details.instances.checked_add(1).ok_or(ArithmeticError::Overflow)?; @@ -171,7 +171,7 @@ impl, I: 'static> Pallet { maybe_class_details.as_mut().ok_or(Error::::UnknownClass)?; let details = Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; - with_details(&class_details, &details)?; + with_details(class_details, &details)?; // Return the deposit. T::Currency::unreserve(&class_details.owner, details.deposit); diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index 89b95fb770489..492befc46967c 100644 --- a/frame/uniques/src/impl_nonfungibles.rs +++ b/frame/uniques/src/impl_nonfungibles.rs @@ -93,12 +93,12 @@ impl, I: 'static> Create<::AccountId> for Pallet admin: &T::AccountId, ) -> DispatchResult { Self::do_create_class( - class.clone(), + *class, who.clone(), admin.clone(), T::ClassDeposit::get(), false, - Event::Created { class: class.clone(), creator: who.clone(), owner: admin.clone() }, + Event::Created { class: *class, creator: who.clone(), owner: admin.clone() }, ) } } @@ -125,7 +125,7 @@ impl, I: 'static> Mutate<::AccountId> for Pallet instance: &Self::InstanceId, who: &T::AccountId, ) -> DispatchResult { - Self::do_mint(class.clone(), instance.clone(), who.clone(), |_| Ok(())) + Self::do_mint(*class, *instance, who.clone(), |_| Ok(())) } fn burn( @@ -133,10 +133,10 @@ impl, I: 'static> Mutate<::AccountId> for Pallet instance: &Self::InstanceId, maybe_check_owner: Option<&T::AccountId>, ) -> DispatchResult { - Self::do_burn(class.clone(), instance.clone(), |_, d| { + Self::do_burn(*class, *instance, |_, d| { if let Some(check_owner) = maybe_check_owner { if &d.owner != check_owner { - Err(Error::::NoPermission)?; + return Err(Error::::NoPermission.into()) } } Ok(()) @@ -150,7 +150,7 @@ impl, I: 'static> Transfer for Pallet { instance: &Self::InstanceId, destination: &T::AccountId, ) -> DispatchResult { - Self::do_transfer(class.clone(), instance.clone(), destination.clone(), |_, _| Ok(())) + Self::do_transfer(*class, *instance, destination.clone(), |_, _| Ok(())) } } diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index d999acc4c9403..a360a02ebc702 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -720,7 +720,7 @@ pub mod pallet { Class::::try_mutate(class, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; - ensure!(&origin == &details.freezer, Error::::NoPermission); + ensure!(origin == details.freezer, Error::::NoPermission); details.is_frozen = true; @@ -744,7 +744,7 @@ pub mod pallet { Class::::try_mutate(class, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; - ensure!(&origin == &details.admin, Error::::NoPermission); + ensure!(origin == details.admin, Error::::NoPermission); details.is_frozen = false; @@ -778,7 +778,7 @@ pub mod pallet { Class::::try_mutate(class, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; - ensure!(&origin == &details.owner, Error::::NoPermission); + ensure!(origin == details.owner, Error::::NoPermission); if details.owner == owner { return Ok(()) } @@ -827,7 +827,7 @@ pub mod pallet { Class::::try_mutate(class, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; - ensure!(&origin == &details.owner, Error::::NoPermission); + ensure!(origin == details.owner, Error::::NoPermission); details.issuer = issuer.clone(); details.admin = admin.clone(); @@ -867,7 +867,7 @@ pub mod pallet { Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; if let Some(check) = maybe_check { - let permitted = &check == &class_details.admin || &check == &details.owner; + let permitted = check == class_details.admin || check == details.owner; ensure!(permitted, Error::::NoPermission); } @@ -916,7 +916,7 @@ pub mod pallet { let mut details = Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; if let Some(check) = maybe_check { - let permitted = &check == &class_details.admin || &check == &details.owner; + let permitted = check == class_details.admin || check == details.owner; ensure!(permitted, Error::::NoPermission); } let maybe_check_delegate = maybe_check_delegate.map(T::Lookup::lookup).transpose()?; diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index 402128d005808..27f346f13f52f 100644 --- a/frame/utility/src/benchmarking.rs +++ b/frame/utility/src/benchmarking.rs @@ -70,7 +70,7 @@ benchmarks! { let call = Box::new(frame_system::Call::remark { remark: vec![] }.into()); let origin: T::Origin = RawOrigin::Signed(caller).into(); let pallets_origin: ::PalletsOrigin = origin.caller().clone(); - let pallets_origin = Into::::into(pallets_origin.clone()); + let pallets_origin = Into::::into(pallets_origin); }: _(RawOrigin::Root, Box::new(pallets_origin), call) impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/frame/vesting/src/benchmarking.rs b/frame/vesting/src/benchmarking.rs index 1693fdd3f1cbe..2b8150e995240 100644 --- a/frame/vesting/src/benchmarking.rs +++ b/frame/vesting/src/benchmarking.rs @@ -72,7 +72,7 @@ fn add_vesting_schedules( T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); } - Ok(total_locked.into()) + Ok(total_locked) } benchmarks! { @@ -91,7 +91,7 @@ benchmarks! { assert_eq!(System::::block_number(), T::BlockNumber::zero()); assert_eq!( Vesting::::vesting_balance(&caller), - Some(expected_balance.into()), + Some(expected_balance), "Vesting schedule not added", ); }: vest(RawOrigin::Signed(caller.clone())) @@ -99,7 +99,7 @@ benchmarks! { // Nothing happened since everything is still vested. assert_eq!( Vesting::::vesting_balance(&caller), - Some(expected_balance.into()), + Some(expected_balance), "Vesting schedule was removed", ); } @@ -156,7 +156,7 @@ benchmarks! { // Nothing happened since everything is still vested. assert_eq!( Vesting::::vesting_balance(&other), - Some(expected_balance.into()), + Some(expected_balance), "Vesting schedule was removed", ); } @@ -260,7 +260,7 @@ benchmarks! { ); assert_eq!( Vesting::::vesting_balance(&target), - Some(expected_balance.into()), + Some(expected_balance), "Lock not correctly updated", ); } @@ -274,7 +274,7 @@ benchmarks! { // Give target existing locks. add_locks::(&caller, l as u8); // Add max vesting schedules. - let expected_balance = add_vesting_schedules::(caller_lookup.clone(), s)?; + let expected_balance = add_vesting_schedules::(caller_lookup, s)?; // Schedules are not vesting at block 0. assert_eq!(System::::block_number(), T::BlockNumber::zero()); @@ -324,7 +324,7 @@ benchmarks! { // Give target other locks. add_locks::(&caller, l as u8); // Add max vesting schedules. - let total_transferred = add_vesting_schedules::(caller_lookup.clone(), s)?; + let total_transferred = add_vesting_schedules::(caller_lookup, s)?; // Go to about half way through all the schedules duration. (They all start at 1, and have a duration of 20 or 21). System::::set_block_number(11u32.into()); diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 13841a0443ceb..23b7d231343b4 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -121,10 +121,10 @@ impl VestingAction { } /// Pick the schedules that this action dictates should continue vesting undisturbed. - fn pick_schedules<'a, T: Config>( - &'a self, + fn pick_schedules( + &self, schedules: Vec, T::BlockNumber>>, - ) -> impl Iterator, T::BlockNumber>> + 'a { + ) -> impl Iterator, T::BlockNumber>> + '_ { schedules.into_iter().enumerate().filter_map(move |(index, schedule)| { if self.should_remove(index) { None @@ -710,7 +710,7 @@ where let (schedules, locked_now) = Self::exec_action(schedules.to_vec(), VestingAction::Passive)?; - Self::write_vesting(&who, schedules)?; + Self::write_vesting(who, schedules)?; Self::write_lock(who, locked_now); Ok(()) @@ -744,7 +744,7 @@ where let (schedules, locked_now) = Self::exec_action(schedules.to_vec(), remove_action)?; - Self::write_vesting(&who, schedules)?; + Self::write_vesting(who, schedules)?; Self::write_lock(who, locked_now); Ok(()) } diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index 50809ddef7ec1..cafd1668819dd 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -69,7 +69,7 @@ benchmarks! { let origin = T::DispatchWhitelistedOrigin::successful_origin(); // NOTE: we remove `10` because we need some bytes to encode the variants and vec length let remark_len = >::MaxSize::get() - 10; - let remark = sp_std::vec![1_8; remark_len as usize]; + let remark = sp_std::vec![1u8; remark_len as usize]; let call: ::Call = frame_system::Call::remark { remark }.into(); let call_weight = call.get_dispatch_info().weight; diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index 2301f531590ee..b031c0f8bb1cc 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -188,7 +188,7 @@ fn generate_native_call_generators(decl: &ItemTrait) -> Result { // Generate a native call generator for each function of the given trait. for fn_ in fns { - let params = extract_parameter_names_types_and_borrows(&fn_, AllowSelfRefInParameters::No)?; + let params = extract_parameter_names_types_and_borrows(fn_, AllowSelfRefInParameters::No)?; let trait_fn_name = &fn_.ident; let function_name_str = fn_.ident.to_string(); let fn_name = generate_native_call_generator_fn_name(&fn_.ident); @@ -336,7 +336,7 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result { // Generate a native call generator for each function of the given trait. for (attrs, fn_) in fns { let trait_name = &decl.ident; - let trait_fn_name = prefix_function_with_trait(&trait_name, &fn_.ident); + let trait_fn_name = prefix_function_with_trait(trait_name, &fn_.ident); let fn_name = generate_call_api_at_fn_name(&fn_.ident); let attrs = remove_supported_attributes(&mut attrs.clone()); @@ -360,7 +360,7 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result { let mut renames = Vec::new(); if let Some((_, a)) = attrs.iter().find(|a| a.0 == &RENAMED_ATTRIBUTE) { let (old_name, version) = parse_renamed_attribute(a)?; - renames.push((version, prefix_function_with_trait(&trait_name, &old_name))); + renames.push((version, prefix_function_with_trait(trait_name, &old_name))); } renames.sort_by(|l, r| r.cmp(l)); @@ -582,7 +582,7 @@ impl<'a> ToClientSideDecl<'a> { Vec::new() }, }; - let name = generate_method_runtime_api_impl_name(&self.trait_, &method.sig.ident); + let name = generate_method_runtime_api_impl_name(self.trait_, &method.sig.ident); let block_id = self.block_id; let crate_ = self.crate_; @@ -619,9 +619,9 @@ impl<'a> ToClientSideDecl<'a> { let params2 = params.clone(); let ret_type = return_type_extract_type(&method.sig.output); - fold_fn_decl_for_client_side(&mut method.sig, &self.block_id, &self.crate_); + fold_fn_decl_for_client_side(&mut method.sig, self.block_id, self.crate_); - let name_impl = generate_method_runtime_api_impl_name(&self.trait_, &method.sig.ident); + let name_impl = generate_method_runtime_api_impl_name(self.trait_, &method.sig.ident); let crate_ = self.crate_; let found_attributes = remove_supported_attributes(&mut method.attrs); @@ -630,7 +630,7 @@ impl<'a> ToClientSideDecl<'a> { let (native_handling, param_tuple) = match get_changed_in(&found_attributes) { Ok(Some(version)) => { // Make sure that the `changed_in` version is at least the current `api_version`. - if get_api_version(&self.found_attributes).ok() < Some(version) { + if get_api_version(self.found_attributes).ok() < Some(version) { self.errors.push( Error::new( method.span(), @@ -972,7 +972,7 @@ pub fn decl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::Tok } fn decl_runtime_apis_impl_inner(api_decls: &[ItemTrait]) -> Result { - check_trait_decls(&api_decls)?; + check_trait_decls(api_decls)?; let hidden_includes = generate_hidden_includes(HIDDEN_INCLUDES_ID); let runtime_decls = generate_runtime_decls(api_decls)?; diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index f594a743fcf94..0ac3cfbe1244e 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -491,7 +491,7 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { }; input.sig.ident = - generate_method_runtime_api_impl_name(&self.impl_trait, &input.sig.ident); + generate_method_runtime_api_impl_name(self.impl_trait, &input.sig.ident); let ret_type = return_type_extract_type(&input.sig.output); // Generate the correct return type. @@ -593,7 +593,7 @@ fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result let mut result = Vec::with_capacity(impls.len()); for impl_ in impls { - let impl_trait_path = extract_impl_trait(&impl_, RequireQualifiedTraitPath::Yes)?; + let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?; let impl_trait = &impl_trait_path .segments .last() @@ -634,7 +634,7 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { for impl_ in impls { let mut path = extend_with_runtime_decl_path( - extract_impl_trait(&impl_, RequireQualifiedTraitPath::Yes)?.clone(), + extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?.clone(), ); // Remove the trait let trait_ = path @@ -723,7 +723,7 @@ fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result { // Filters all attributes except the cfg ones. fn filter_cfg_attrs(attrs: &[Attribute]) -> Vec { - attrs.into_iter().filter(|a| a.path.is_ident("cfg")).cloned().collect() + attrs.iter().filter(|a| a.path.is_ident("cfg")).cloned().collect() } #[cfg(test)] diff --git a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs index ffc158ac94d29..6098f8d6bd741 100644 --- a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs @@ -283,7 +283,7 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> { }; input.sig.ident = - generate_method_runtime_api_impl_name(&self.impl_trait, &input.sig.ident); + generate_method_runtime_api_impl_name(self.impl_trait, &input.sig.ident); // When using advanced, the user needs to declare the correct return type on its own, // otherwise do it for the user. @@ -350,7 +350,7 @@ fn generate_runtime_api_impls(impls: &[ItemImpl]) -> Result> = None; for impl_ in impls { - let impl_trait_path = extract_impl_trait(&impl_, RequireQualifiedTraitPath::No)?; + let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::No)?; let impl_trait = &impl_trait_path .segments .last() diff --git a/primitives/api/proc-macro/src/utils.rs b/primitives/api/proc-macro/src/utils.rs index 2aa6a657aa9c0..97b456b62dfa6 100644 --- a/primitives/api/proc-macro/src/utils.rs +++ b/primitives/api/proc-macro/src/utils.rs @@ -61,12 +61,11 @@ pub fn generate_crate_access(unique_id: &'static str) -> TokenStream { let mod_name = generate_hidden_includes_mod_name(unique_id); quote!( self::#mod_name::sp_api ) } - .into() } /// Generates the name of the module that contains the trait declaration for the runtime. pub fn generate_runtime_mod_name_for_trait(trait_: &Ident) -> Ident { - Ident::new(&format!("runtime_decl_for_{}", trait_.to_string()), Span::call_site()) + Ident::new(&format!("runtime_decl_for_{}", trait_), Span::call_site()) } /// Generates a name for a method that needs to be implemented in the runtime for the client side. @@ -169,17 +168,17 @@ pub fn extract_parameter_names_types_and_borrows( /// Generates the name for the native call generator function. pub fn generate_native_call_generator_fn_name(fn_name: &Ident) -> Ident { - Ident::new(&format!("{}_native_call_generator", fn_name.to_string()), Span::call_site()) + Ident::new(&format!("{}_native_call_generator", fn_name), Span::call_site()) } /// Generates the name for the call api at function. pub fn generate_call_api_at_fn_name(fn_name: &Ident) -> Ident { - Ident::new(&format!("{}_call_api_at", fn_name.to_string()), Span::call_site()) + Ident::new(&format!("{}_call_api_at", fn_name), Span::call_site()) } /// Prefix the given function with the trait name. pub fn prefix_function_with_trait(trait_: &Ident, function: &F) -> String { - format!("{}_{}", trait_.to_string(), function.to_string()) + format!("{}_{}", trait_, function.to_string()) } /// Extract all types that appear in signatures in the given `ImplItem`'s. @@ -250,10 +249,7 @@ pub enum RequireQualifiedTraitPath { } /// Extract the trait that is implemented by the given `ItemImpl`. -pub fn extract_impl_trait<'a>( - impl_: &'a ItemImpl, - require: RequireQualifiedTraitPath, -) -> Result<&'a Path> { +pub fn extract_impl_trait(impl_: &ItemImpl, require: RequireQualifiedTraitPath) -> Result<&Path> { impl_ .trait_ .as_ref() diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index 964ef15ce5f5a..2635c81948ff3 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -422,7 +422,7 @@ pub trait ConstructRuntimeApi> { type RuntimeApi: ApiExt; /// Construct an instance of the runtime api. - fn construct_runtime_api<'a>(call: &'a C) -> ApiRef<'a, Self::RuntimeApi>; + fn construct_runtime_api(call: &C) -> ApiRef; } /// Init the [`RuntimeLogger`](sp_runtime::runtime_logger::RuntimeLogger). @@ -554,12 +554,11 @@ pub trait CallApiAt { /// Calls the given api function with the given encoded arguments at the given block and returns /// the encoded result. fn call_api_at< - 'a, R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, >( &self, - params: CallApiAtParams<'a, Block, NC, Self::StateBackend>, + params: CallApiAtParams, ) -> Result, ApiError>; /// Returns the runtime version at the given block. @@ -604,7 +603,7 @@ pub trait ProvideRuntimeApi { /// call to an api function, will `commit` its changes to an internal buffer. Otherwise, /// the modifications will be `discarded`. The modifications will not be applied to the /// storage, even on a `commit`. - fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api>; + fn runtime_api(&self) -> ApiRef; } /// Something that provides information about a runtime api. diff --git a/primitives/application-crypto/src/ecdsa.rs b/primitives/application-crypto/src/ecdsa.rs index 6a0eb7ab2f84d..6356f54a0b085 100644 --- a/primitives/application-crypto/src/ecdsa.rs +++ b/primitives/application-crypto/src/ecdsa.rs @@ -53,7 +53,7 @@ impl RuntimePublic for Public { } fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { - sp_io::crypto::ecdsa_verify(&signature, msg.as_ref(), self) + sp_io::crypto::ecdsa_verify(signature, msg.as_ref(), self) } fn to_raw_vec(&self) -> Vec { diff --git a/primitives/application-crypto/src/ed25519.rs b/primitives/application-crypto/src/ed25519.rs index f5ec40233ca93..199e55383b881 100644 --- a/primitives/application-crypto/src/ed25519.rs +++ b/primitives/application-crypto/src/ed25519.rs @@ -53,7 +53,7 @@ impl RuntimePublic for Public { } fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { - sp_io::crypto::ed25519_verify(&signature, msg.as_ref(), self) + sp_io::crypto::ed25519_verify(signature, msg.as_ref(), self) } fn to_raw_vec(&self) -> Vec { diff --git a/primitives/application-crypto/src/sr25519.rs b/primitives/application-crypto/src/sr25519.rs index 81c5320efd71b..c96e7382eb191 100644 --- a/primitives/application-crypto/src/sr25519.rs +++ b/primitives/application-crypto/src/sr25519.rs @@ -53,7 +53,7 @@ impl RuntimePublic for Public { } fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { - sp_io::crypto::sr25519_verify(&signature, msg.as_ref(), self) + sp_io::crypto::sr25519_verify(signature, msg.as_ref(), self) } fn to_raw_vec(&self) -> Vec { diff --git a/primitives/arithmetic/benches/bench.rs b/primitives/arithmetic/benches/bench.rs index 3e4fafe2a4a9a..57556135f6431 100644 --- a/primitives/arithmetic/benches/bench.rs +++ b/primitives/arithmetic/benches/bench.rs @@ -41,19 +41,19 @@ fn bench_op(c: &mut Criterion, name: &str, op: F) { fn bench_addition(c: &mut Criterion) { bench_op(c, "addition", |a, b| { - let _ = a.clone().add(&b); + let _ = a.clone().add(b); }); } fn bench_subtraction(c: &mut Criterion) { bench_op(c, "subtraction", |a, b| { - let _ = a.clone().sub(&b); + let _ = a.clone().sub(b); }); } fn bench_multiplication(c: &mut Criterion) { bench_op(c, "multiplication", |a, b| { - let _ = a.clone().mul(&b); + let _ = a.clone().mul(b); }); } diff --git a/primitives/arithmetic/fuzzer/src/normalize.rs b/primitives/arithmetic/fuzzer/src/normalize.rs index dd717115a5c9c..3d2d6eb9acfcc 100644 --- a/primitives/arithmetic/fuzzer/src/normalize.rs +++ b/primitives/arithmetic/fuzzer/src/normalize.rs @@ -35,7 +35,7 @@ fn main() { loop { fuzz!(|data: (Vec, Ty)| { let (data, norm) = data; - if data.len() == 0 { + if data.is_empty() { return } let pre_sum: u128 = data.iter().map(|x| *x as u128).sum(); @@ -44,16 +44,14 @@ fn main() { // error cases. if pre_sum > sum_limit || data.len() > len_limit { assert!(normalized.is_err()) + } else if let Ok(normalized) = normalized { + // if sum goes beyond u128, panic. + let sum: u128 = normalized.iter().map(|x| *x as u128).sum(); + + // if this function returns Ok(), then it will ALWAYS be accurate. + assert_eq!(sum, norm as u128, "sums don't match {:?}, {}", normalized, norm); } else { - if let Ok(normalized) = normalized { - // if sum goes beyond u128, panic. - let sum: u128 = normalized.iter().map(|x| *x as u128).sum(); - - // if this function returns Ok(), then it will ALWAYS be accurate. - assert_eq!(sum, norm as u128, "sums don't match {:?}, {}", normalized, norm); - } else { - panic!("Should have returned Ok for input = {:?}, target = {:?}", data, norm); - } + panic!("Should have returned Ok for input = {:?}, target = {:?}", data, norm); } }) } diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index 729da123757c7..e43e42763575d 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -65,7 +65,7 @@ where fn tcmp(&self, other: &T, threshold: T) -> Ordering { // early exit. if threshold.is_zero() { - return self.cmp(&other) + return self.cmp(other) } let upper_bound = other.saturating_add(threshold); @@ -73,7 +73,7 @@ where if upper_bound <= lower_bound { // defensive only. Can never happen. - self.cmp(&other) + self.cmp(other) } else { // upper_bound is guaranteed now to be bigger than lower. match (self.cmp(&lower_bound), self.cmp(&upper_bound)) { @@ -113,10 +113,7 @@ impl_normalize_for_numeric!(u8, u16, u32, u64, u128); impl Normalizable

for Vec

{ fn normalize(&self, targeted_sum: P) -> Result, &'static str> { - let uppers = self - .iter() - .map(|p| >::from(p.clone().deconstruct())) - .collect::>(); + let uppers = self.iter().map(|p| >::from(p.deconstruct())).collect::>(); let normalized = normalize(uppers.as_ref(), >::from(targeted_sum.deconstruct()))?; diff --git a/primitives/arithmetic/src/rational.rs b/primitives/arithmetic/src/rational.rs index 63ae6e65bc9ee..1beafbe811614 100644 --- a/primitives/arithmetic/src/rational.rs +++ b/primitives/arithmetic/src/rational.rs @@ -63,14 +63,14 @@ impl Ord for RationalInfinite { fn cmp(&self, other: &Self) -> Ordering { // handle some edge cases. if self.d() == other.d() { - self.n().cmp(&other.n()) + self.n().cmp(other.n()) } else if self.d().is_zero() { Ordering::Greater } else if other.d().is_zero() { Ordering::Less } else { // (a/b) cmp (c/d) => (a*d) cmp (c*b) - self.n().clone().mul(&other.d()).cmp(&other.n().clone().mul(&self.d())) + self.n().clone().mul(other.d()).cmp(&other.n().clone().mul(self.d())) } } } @@ -272,6 +272,7 @@ impl PartialEq for Rational128 { #[cfg(test)] mod tests { use super::{helpers_128bit::*, *}; + use static_assertions::const_assert; const MAX128: u128 = u128::MAX; const MAX64: u128 = u64::MAX as u128; @@ -349,8 +350,8 @@ mod tests { r(1_000_000_000, MAX64).lcm(&r(7_000_000_000, MAX64 - 1)), Ok(340282366920938463408034375210639556610), ); - assert!(340282366920938463408034375210639556610 < MAX128); - assert!(340282366920938463408034375210639556610 == MAX64 * (MAX64 - 1)); + const_assert!(340282366920938463408034375210639556610 < MAX128); + const_assert!(340282366920938463408034375210639556610 == MAX64 * (MAX64 - 1)); } #[test] diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index 84b34105e59b8..f80c6d0269116 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -184,7 +184,7 @@ pub trait Backend: if let Some(max_number) = maybe_max_number { loop { let current_header = self - .header(BlockId::Hash(current_hash.clone()))? + .header(BlockId::Hash(current_hash))? .ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?; if current_header.number() <= &max_number { @@ -204,7 +204,7 @@ pub trait Backend: } let current_header = self - .header(BlockId::Hash(current_hash.clone()))? + .header(BlockId::Hash(current_hash))? .ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?; // stop search in this chain once we go below the target's block number diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index 858dcf6c92e80..46477a75b8a1f 100644 --- a/primitives/blockchain/src/header_metadata.rs +++ b/primitives/blockchain/src/header_metadata.rs @@ -275,11 +275,11 @@ pub struct CachedHeaderMetadata { impl From<&Block::Header> for CachedHeaderMetadata { fn from(header: &Block::Header) -> Self { CachedHeaderMetadata { - hash: header.hash().clone(), - number: header.number().clone(), - parent: header.parent_hash().clone(), - state_root: header.state_root().clone(), - ancestor: header.parent_hash().clone(), + hash: header.hash(), + number: *header.number(), + parent: *header.parent_hash(), + state_root: *header.state_root(), + ancestor: *header.parent_hash(), } } } diff --git a/primitives/consensus/common/src/evaluation.rs b/primitives/consensus/common/src/evaluation.rs index d0ddbb6fab813..6a6ca835f3153 100644 --- a/primitives/consensus/common/src/evaluation.rs +++ b/primitives/consensus/common/src/evaluation.rs @@ -49,7 +49,7 @@ pub fn evaluate_initial( parent_number: <::Header as HeaderT>::Number, ) -> Result<()> { let encoded = Encode::encode(proposal); - let proposal = Block::decode(&mut &encoded[..]).map_err(|e| Error::BadProposalFormat(e))?; + let proposal = Block::decode(&mut &encoded[..]).map_err(Error::BadProposalFormat)?; if *parent_hash != *proposal.header().parent_hash() { return Err(Error::WrongParentHash { diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index 59bbf7618dfc3..2743f434c209b 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -169,7 +169,7 @@ impl ProofRecording for EnableProofRecording { const ENABLED: bool = true; fn into_proof(proof: Option) -> Result { - proof.ok_or_else(|| NoProofRecorded) + proof.ok_or(NoProofRecorded) } } diff --git a/primitives/core/benches/bench.rs b/primitives/core/benches/bench.rs index 44bcd657ba3f0..53421278dca26 100644 --- a/primitives/core/benches/bench.rs +++ b/primitives/core/benches/bench.rs @@ -79,7 +79,7 @@ fn bench_hash_128_dyn_size(c: &mut Criterion) { fn bench_ed25519(c: &mut Criterion) { let mut group = c.benchmark_group("ed25519"); - for msg_size in vec![32, 1024, 1024 * 1024] { + for &msg_size in &[32, 1024, 1024 * 1024] { let msg = (0..msg_size).map(|_| rand::random::()).collect::>(); let key = sp_core::ed25519::Pair::generate().0; group.bench_function(BenchmarkId::new("signing", format!("{}", msg_size)), |b| { @@ -87,7 +87,7 @@ fn bench_ed25519(c: &mut Criterion) { }); } - for msg_size in vec![32, 1024, 1024 * 1024] { + for &msg_size in &[32, 1024, 1024 * 1024] { let msg = (0..msg_size).map(|_| rand::random::()).collect::>(); let key = sp_core::ed25519::Pair::generate().0; let sig = key.sign(&msg); @@ -103,7 +103,7 @@ fn bench_ed25519(c: &mut Criterion) { fn bench_sr25519(c: &mut Criterion) { let mut group = c.benchmark_group("sr25519"); - for msg_size in vec![32, 1024, 1024 * 1024] { + for &msg_size in &[32, 1024, 1024 * 1024] { let msg = (0..msg_size).map(|_| rand::random::()).collect::>(); let key = sp_core::sr25519::Pair::generate().0; group.bench_function(BenchmarkId::new("signing", format!("{}", msg_size)), |b| { @@ -111,7 +111,7 @@ fn bench_sr25519(c: &mut Criterion) { }); } - for msg_size in vec![32, 1024, 1024 * 1024] { + for &msg_size in &[32, 1024, 1024 * 1024] { let msg = (0..msg_size).map(|_| rand::random::()).collect::>(); let key = sp_core::sr25519::Pair::generate().0; let sig = key.sign(&msg); @@ -127,7 +127,7 @@ fn bench_sr25519(c: &mut Criterion) { fn bench_ecdsa(c: &mut Criterion) { let mut group = c.benchmark_group("ecdsa"); - for msg_size in vec![32, 1024, 1024 * 1024] { + for &msg_size in &[32, 1024, 1024 * 1024] { let msg = (0..msg_size).map(|_| rand::random::()).collect::>(); let key = sp_core::ecdsa::Pair::generate().0; group.bench_function(BenchmarkId::new("signing", format!("{}", msg_size)), |b| { @@ -135,7 +135,7 @@ fn bench_ecdsa(c: &mut Criterion) { }); } - for msg_size in vec![32, 1024, 1024 * 1024] { + for &msg_size in &[32, 1024, 1024 * 1024] { let msg = (0..msg_size).map(|_| rand::random::()).collect::>(); let key = sp_core::ecdsa::Pair::generate().0; let sig = key.sign(&msg); diff --git a/primitives/core/hashing/proc-macro/src/impls.rs b/primitives/core/hashing/proc-macro/src/impls.rs index ff9593ea18441..3058cf019b143 100644 --- a/primitives/core/hashing/proc-macro/src/impls.rs +++ b/primitives/core/hashing/proc-macro/src/impls.rs @@ -26,7 +26,7 @@ pub(super) struct MultipleInputBytes(pub Vec>); impl MultipleInputBytes { pub(super) fn concatenated(mut self) -> Vec { - if self.0.len() == 0 { + if self.0.is_empty() { Vec::new() } else { let mut result = core::mem::take(&mut self.0[0]); diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index f994da1515350..80b44449dbac1 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -1172,7 +1172,7 @@ mod tests { impl ByteArray for TestPublic { const LEN: usize = 0; fn from_slice(bytes: &[u8]) -> Result { - if bytes.len() == 0 { + if bytes.is_empty() { Ok(Self) } else { Err(()) diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 6343e3f4dfd0d..485e39d3a71db 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -364,7 +364,7 @@ impl From for Signature { /// Derive a single hard junction. #[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { - ("Secp256k1HDKD", secret_seed, cc).using_encoded(|data| sp_core_hashing::blake2_256(data)) + ("Secp256k1HDKD", secret_seed, cc).using_encoded(sp_core_hashing::blake2_256) } /// An error when deriving a key. @@ -763,12 +763,12 @@ mod test { set_default_ss58_version(Ss58AddressFormat::custom(200)); // custom addr encoded by version 200 let addr = "4pbsSkWcBaYoFHrKJZp5fDVUKbqSYD9dhZZGvpp3vQ5ysVs5ybV"; - Public::from_ss58check(&addr).unwrap(); + Public::from_ss58check(addr).unwrap(); set_default_ss58_version(default_format); // set current ss58 version to default version let addr = "KWAfgC2aRG5UVD6CpbPQXCx4YZZUhvWqqAJE6qcYc9Rtr6g5C"; - Public::from_ss58check(&addr).unwrap(); + Public::from_ss58check(addr).unwrap(); println!("CUSTOM_FORMAT_SUCCESSFUL"); } else { diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 0bde9e2e5303a..177af0651c0ef 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -397,7 +397,7 @@ impl From<&Public> for CryptoTypePublicPair { /// Derive a single hard junction. #[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { - ("Ed25519HDKD", secret_seed, cc).using_encoded(|data| sp_core_hashing::blake2_256(data)) + ("Ed25519HDKD", secret_seed, cc).using_encoded(sp_core_hashing::blake2_256) } /// An error when deriving a key. diff --git a/primitives/core/src/hexdisplay.rs b/primitives/core/src/hexdisplay.rs index e5262ba8f657b..26c04c433b49f 100644 --- a/primitives/core/src/hexdisplay.rs +++ b/primitives/core/src/hexdisplay.rs @@ -69,13 +69,13 @@ impl AsBytesRef for &[u8] { impl AsBytesRef for [u8] { fn as_bytes_ref(&self) -> &[u8] { - &self + self } } impl AsBytesRef for sp_std::vec::Vec { fn as_bytes_ref(&self) -> &[u8] { - &self + self } } diff --git a/primitives/debug-derive/src/impls.rs b/primitives/debug-derive/src/impls.rs index 060997fe97821..51a4d876c79b6 100644 --- a/primitives/debug-derive/src/impls.rs +++ b/primitives/debug-derive/src/impls.rs @@ -67,10 +67,9 @@ mod implementation { /// Derive the inner implementation of `Debug::fmt` function. pub fn derive(name_str: &str, data: &Data) -> TokenStream { match *data { - Data::Struct(ref s) => derive_struct(&name_str, &s.fields), - Data::Union(ref u) => - derive_fields(&name_str, Fields::new(u.fields.named.iter(), None)), - Data::Enum(ref e) => derive_enum(&name_str, &e), + Data::Struct(ref s) => derive_struct(name_str, &s.fields), + Data::Union(ref u) => derive_fields(name_str, Fields::new(u.fields.named.iter(), None)), + Data::Enum(ref e) => derive_enum(name_str, e), } } diff --git a/primitives/externalities/src/extensions.rs b/primitives/externalities/src/extensions.rs index d58edb749e9e6..5db40f12c21aa 100644 --- a/primitives/externalities/src/extensions.rs +++ b/primitives/externalities/src/extensions.rs @@ -174,9 +174,7 @@ impl Extensions { } /// Returns a mutable iterator over all extensions. - pub fn iter_mut<'a>( - &'a mut self, - ) -> impl Iterator)> { + pub fn iter_mut(&mut self) -> impl Iterator)> { self.extensions.iter_mut() } } diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index dd5cef85a2ba5..4be42c3d19b6c 100644 --- a/primitives/finality-grandpa/src/lib.rs +++ b/primitives/finality-grandpa/src/lib.rs @@ -59,7 +59,7 @@ pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK"; /// The storage key for the current set of weighted Grandpa authorities. /// The value stored is an encoded VersionedAuthorityList. -pub const GRANDPA_AUTHORITIES_KEY: &'static [u8] = b":grandpa_authorities"; +pub const GRANDPA_AUTHORITIES_KEY: &[u8] = b":grandpa_authorities"; /// The weight of an authority. pub type AuthorityWeight = u64; diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 2ff49b5048810..8f62b03b62ea9 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -220,7 +220,7 @@ pub trait Storage { /// Get the next key in storage after the given one in lexicographic order. fn next_key(&mut self, key: &[u8]) -> Option> { - self.next_storage_key(&key) + self.next_storage_key(key) } /// Start a new nested transaction. @@ -629,7 +629,7 @@ pub trait Crypto { /// /// Returns the public key. fn ed25519_generate(&mut self, id: KeyTypeId, seed: Option>) -> ed25519::Public { - let seed = seed.as_ref().map(|s| std::str::from_utf8(&s).expect("Seed is valid utf8!")); + let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); @@ -678,7 +678,7 @@ pub trait Crypto { pub_key: &ed25519::Public, ) -> bool { self.extension::() - .map(|extension| extension.push_ed25519(sig.clone(), pub_key.clone(), msg.to_vec())) + .map(|extension| extension.push_ed25519(sig.clone(), *pub_key, msg.to_vec())) .unwrap_or_else(|| ed25519_verify(sig, msg, pub_key)) } @@ -705,7 +705,7 @@ pub trait Crypto { pub_key: &sr25519::Public, ) -> bool { self.extension::() - .map(|extension| extension.push_sr25519(sig.clone(), pub_key.clone(), msg.to_vec())) + .map(|extension| extension.push_sr25519(sig.clone(), *pub_key, msg.to_vec())) .unwrap_or_else(|| sr25519_verify(sig, msg, pub_key)) } @@ -753,7 +753,7 @@ pub trait Crypto { /// /// Returns the public key. fn sr25519_generate(&mut self, id: KeyTypeId, seed: Option>) -> sr25519::Public { - let seed = seed.as_ref().map(|s| std::str::from_utf8(&s).expect("Seed is valid utf8!")); + let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); @@ -803,7 +803,7 @@ pub trait Crypto { /// /// Returns the public key. fn ecdsa_generate(&mut self, id: KeyTypeId, seed: Option>) -> ecdsa::Public { - let seed = seed.as_ref().map(|s| std::str::from_utf8(&s).expect("Seed is valid utf8!")); + let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); @@ -888,7 +888,7 @@ pub trait Crypto { pub_key: &ecdsa::Public, ) -> bool { self.extension::() - .map(|extension| extension.push_ecdsa(sig.clone(), pub_key.clone(), msg.to_vec())) + .map(|extension| extension.push_ecdsa(sig.clone(), *pub_key, msg.to_vec())) .unwrap_or_else(|| ecdsa_verify(sig, msg, pub_key)) } @@ -1504,14 +1504,7 @@ pub trait Sandbox { state_ptr: Pointer, ) -> u32 { self.sandbox() - .invoke( - instance_idx, - &function, - &args, - return_val_ptr, - return_val_len, - state_ptr.into(), - ) + .invoke(instance_idx, function, args, return_val_ptr, return_val_len, state_ptr.into()) .expect("Failed to invoke function with sandbox") } diff --git a/primitives/keyring/src/ed25519.rs b/primitives/keyring/src/ed25519.rs index 6d56062d3473c..404e4121e71a3 100644 --- a/primitives/keyring/src/ed25519.rs +++ b/primitives/keyring/src/ed25519.rs @@ -125,7 +125,7 @@ lazy_static! { impl From for Public { fn from(k: Keyring) -> Self { - (*PUBLIC_KEYS).get(&k).unwrap().clone() + *(*PUBLIC_KEYS).get(&k).unwrap() } } diff --git a/primitives/keyring/src/sr25519.rs b/primitives/keyring/src/sr25519.rs index 86bcac9d58cbb..115a7fce70122 100644 --- a/primitives/keyring/src/sr25519.rs +++ b/primitives/keyring/src/sr25519.rs @@ -168,7 +168,7 @@ impl From for AccountId32 { impl From for Public { fn from(k: Keyring) -> Self { - (*PUBLIC_KEYS).get(&k).unwrap().clone() + *(*PUBLIC_KEYS).get(&k).unwrap() } } diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index 2723b743c10db..a9ec6709d912a 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -316,7 +316,7 @@ impl SyncCryptoStore for KeyStore { fn has_keys(&self, public_keys: &[(Vec, KeyTypeId)]) -> bool { public_keys .iter() - .all(|(k, t)| self.keys.read().get(&t).and_then(|s| s.get(k)).is_some()) + .all(|(k, t)| self.keys.read().get(t).and_then(|s| s.get(k)).is_some()) } fn supported_keys( diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index a27536b8d35b7..60ef02c53001c 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -231,7 +231,7 @@ impl DataOrHash { pub fn hash(&self) -> H::Output { match *self { Self::Data(ref leaf) => leaf.using_encoded(::hash, true), - Self::Hash(ref hash) => hash.clone(), + Self::Hash(ref hash) => *hash, } } } diff --git a/primitives/npos-elections/fuzzer/src/common.rs b/primitives/npos-elections/fuzzer/src/common.rs index 1bef899d5e54c..6b89983c16abe 100644 --- a/primitives/npos-elections/fuzzer/src/common.rs +++ b/primitives/npos-elections/fuzzer/src/common.rs @@ -99,7 +99,7 @@ pub fn generate_random_npos_inputs( let mut chosen_candidates = Vec::with_capacity(n_candidates_chosen); chosen_candidates.extend(candidates.choose_multiple(&mut rng, n_candidates_chosen)); - chosen_candidates.sort(); + chosen_candidates.sort_unstable(); voters.push((id, vote_weight, chosen_candidates)); } diff --git a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs index 76641fc2c79fe..cacf64e81c8f7 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs @@ -53,11 +53,9 @@ fn main() { let stake_of = |who: &AccountId| -> VoteWeight { *stake_of_tree.get(who).unwrap() }; let unbalanced_score = { - let staked = assignment_ratio_to_staked_normalized( - unbalanced.assignments.clone(), - &stake_of, - ) - .unwrap(); + let staked = + assignment_ratio_to_staked_normalized(unbalanced.assignments, &stake_of) + .unwrap(); let score = to_supports(staked.as_ref()).evaluate(); if score.minimal_stake == 0 { @@ -72,11 +70,9 @@ fn main() { seq_phragmen(to_elect, candidates, voters, Some((iterations, 0))).unwrap(); let balanced_score = { - let staked = assignment_ratio_to_staked_normalized( - balanced.assignments.clone(), - &stake_of, - ) - .unwrap(); + let staked = + assignment_ratio_to_staked_normalized(balanced.assignments, &stake_of) + .unwrap(); to_supports(staked.as_ref()).evaluate() }; diff --git a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs index 09daf3f34d32e..988889428c9cf 100644 --- a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs @@ -53,11 +53,9 @@ fn main() { let stake_of = |who: &AccountId| -> VoteWeight { *stake_of_tree.get(who).unwrap() }; let unbalanced_score = { - let staked = assignment_ratio_to_staked_normalized( - unbalanced.assignments.clone(), - &stake_of, - ) - .unwrap(); + let staked = + assignment_ratio_to_staked_normalized(unbalanced.assignments, &stake_of) + .unwrap(); let score = to_supports(&staked).evaluate(); if score.minimal_stake == 0 { @@ -72,8 +70,7 @@ fn main() { let balanced_score = { let staked = - assignment_ratio_to_staked_normalized(balanced.assignments.clone(), &stake_of) - .unwrap(); + assignment_ratio_to_staked_normalized(balanced.assignments, &stake_of).unwrap(); to_supports(staked.as_ref()).evaluate() }; diff --git a/primitives/npos-elections/fuzzer/src/reduce.rs b/primitives/npos-elections/fuzzer/src/reduce.rs index a77b40ca56d54..605f2d6081a6f 100644 --- a/primitives/npos-elections/fuzzer/src/reduce.rs +++ b/primitives/npos-elections/fuzzer/src/reduce.rs @@ -118,7 +118,7 @@ fn reduce_and_compare(assignment: &Vec>, winners: &V let n = assignment.len() as u32; let m = winners.len() as u32; - let edges_before = assignment_len(&assignment); + let edges_before = assignment_len(assignment); let num_changed = reduce(&mut altered_assignment); let edges_after = edges_before - num_changed; diff --git a/primitives/npos-elections/src/helpers.rs b/primitives/npos-elections/src/helpers.rs index 76cfd59de6fb7..598eb3b2ecc2c 100644 --- a/primitives/npos-elections/src/helpers.rs +++ b/primitives/npos-elections/src/helpers.rs @@ -49,13 +49,9 @@ where for<'r> FS: Fn(&'r A) -> VoteWeight, { let mut staked = assignment_ratio_to_staked(ratio, &stake_of); - staked - .iter_mut() - .map(|a| { - a.try_normalize(stake_of(&a.who).into()) - .map_err(|err| Error::ArithmeticError(err)) - }) - .collect::>()?; + staked.iter_mut().try_for_each(|a| { + a.try_normalize(stake_of(&a.who).into()).map_err(Error::ArithmeticError) + })?; Ok(staked) } @@ -74,7 +70,7 @@ pub fn assignment_staked_to_ratio_normalized( ) -> Result>, Error> { let mut ratio = staked.into_iter().map(|a| a.into_assignment()).collect::>(); for assignment in ratio.iter_mut() { - assignment.try_normalize().map_err(|err| Error::ArithmeticError(err))?; + assignment.try_normalize().map_err(Error::ArithmeticError)?; } Ok(ratio) } diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 93fb24eb4a3ca..63b9740b74639 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -456,8 +456,8 @@ pub fn to_support_map( let mut supports = >>::new(); // build support struct. - for StakedAssignment { who, distribution } in assignments.into_iter() { - for (c, weight_extended) in distribution.into_iter() { + for StakedAssignment { who, distribution } in assignments.iter() { + for (c, weight_extended) in distribution.iter() { let mut support = supports.entry(c.clone()).or_default(); support.total = support.total.saturating_add(*weight_extended); support.voters.push((who.clone(), *weight_extended)); diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index e8e925935f774..9b0bfa42215c3 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -97,8 +97,7 @@ pub fn seq_phragmen( voters.into_iter().filter_map(|v| v.into_assignment()).collect::>(); let _ = assignments .iter_mut() - .map(|a| a.try_normalize().map_err(|e| crate::Error::ArithmeticError(e))) - .collect::>()?; + .try_for_each(|a| a.try_normalize().map_err(crate::Error::ArithmeticError))?; let winners = winners .into_iter() .map(|w_ptr| (w_ptr.borrow().who.clone(), w_ptr.borrow().backed_stake)) @@ -200,7 +199,7 @@ pub fn seq_phragmen_core( // edge of all candidates that eventually have a non-zero weight must be elected. debug_assert!(voter.edges.iter().all(|e| e.candidate.borrow().elected)); // inc budget to sum the budget. - voter.try_normalize_elected().map_err(|e| crate::Error::ArithmeticError(e))?; + voter.try_normalize_elected().map_err(crate::Error::ArithmeticError)?; } Ok((candidates, voters)) diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index aa4c558bea1da..5d63517c8e229 100644 --- a/primitives/npos-elections/src/phragmms.rs +++ b/primitives/npos-elections/src/phragmms.rs @@ -70,9 +70,8 @@ pub fn phragmms( voters.into_iter().filter_map(|v| v.into_assignment()).collect::>(); let _ = assignments .iter_mut() - .map(|a| a.try_normalize()) - .collect::>() - .map_err(|e| crate::Error::ArithmeticError(e))?; + .try_for_each(|a| a.try_normalize()) + .map_err(crate::Error::ArithmeticError)?; let winners = winners .into_iter() .map(|w_ptr| (w_ptr.borrow().who.clone(), w_ptr.borrow().backed_stake)) @@ -157,16 +156,14 @@ pub(crate) fn calculate_max_score( // `RationalInfinite` as the score type does not introduce significant overhead. Then we // can switch the score type to `RationalInfinite` and ensure compatibility with any // crazy token scale. - let score_n = candidate - .approval_stake - .checked_mul(one) - .unwrap_or_else(|| Bounded::max_value()); + let score_n = + candidate.approval_stake.checked_mul(one).unwrap_or_else(Bounded::max_value); candidate.score = Rational128::from(score_n, score_d); // check if we have a new winner. if !candidate.elected && candidate.score > best_score { best_score = candidate.score; - best_candidate = Some(Rc::clone(&c_ptr)); + best_candidate = Some(Rc::clone(c_ptr)); } } else { candidate.score = Rational128::zero(); diff --git a/primitives/npos-elections/src/pjr.rs b/primitives/npos-elections/src/pjr.rs index 2d58ca49c8a22..914834fbb2aef 100644 --- a/primitives/npos-elections/src/pjr.rs +++ b/primitives/npos-elections/src/pjr.rs @@ -212,7 +212,7 @@ fn validate_pjr_challenge_core( None => return false, Some(candidate) => candidate.clone(), }; - pre_score(candidate, &voters, threshold) >= threshold + pre_score(candidate, voters, threshold) >= threshold } /// Convert the data types that the user runtime has into ones that can be used by this module. @@ -351,7 +351,7 @@ fn pre_score( debug_assert!(!unelected.borrow().elected); voters .iter() - .filter(|ref v| v.votes_for(&unelected.borrow().who)) + .filter(|v| v.votes_for(&unelected.borrow().who)) .fold(Zero::zero(), |acc: ExtendedBalance, voter| acc.saturating_add(slack(voter, t))) } diff --git a/primitives/npos-elections/src/reduce.rs b/primitives/npos-elections/src/reduce.rs index f089a37e3fff3..c802a29504709 100644 --- a/primitives/npos-elections/src/reduce.rs +++ b/primitives/npos-elections/src/reduce.rs @@ -94,7 +94,7 @@ fn merge(voter_root_path: Vec>, target_root_path: Vec shorter_path .iter() .zip(shorter_path.iter().skip(1)) - .for_each(|(voter, next)| Node::set_parent_of(&next, &voter)); + .for_each(|(voter, next)| Node::set_parent_of(next, voter)); Node::set_parent_of(&shorter_path[0], &longer_path[0]); } @@ -524,12 +524,10 @@ fn reduce_all(assignments: &mut Vec>) -> u32 } else { ass.distribution[idx].1.saturating_sub(min_value) } + } else if start_operation_add { + ass.distribution[idx].1.saturating_sub(min_value) } else { - if start_operation_add { - ass.distribution[idx].1.saturating_sub(min_value) - } else { - ass.distribution[idx].1.saturating_add(min_value) - } + ass.distribution[idx].1.saturating_add(min_value) }; if next_value.is_zero() { @@ -569,12 +567,10 @@ fn reduce_all(assignments: &mut Vec>) -> u32 } else { ass.distribution[idx].1.saturating_add(min_value) } + } else if start_operation_add { + ass.distribution[idx].1.saturating_add(min_value) } else { - if start_operation_add { - ass.distribution[idx].1.saturating_add(min_value) - } else { - ass.distribution[idx].1.saturating_sub(min_value) - } + ass.distribution[idx].1.saturating_sub(min_value) }; if next_value.is_zero() { diff --git a/primitives/panic-handler/src/lib.rs b/primitives/panic-handler/src/lib.rs index df1f78da1cbef..e06fe90ad6f3b 100644 --- a/primitives/panic-handler/src/lib.rs +++ b/primitives/panic-handler/src/lib.rs @@ -158,7 +158,7 @@ fn panic_hook(info: &PanicInfo, report_url: &str, version: &str) { }, }; - let msg = strip_control_codes(&msg); + let msg = strip_control_codes(msg); let thread = thread::current(); let name = thread.name().unwrap_or(""); @@ -167,13 +167,13 @@ fn panic_hook(info: &PanicInfo, report_url: &str, version: &str) { let mut stderr = io::stderr(); - let _ = writeln!(stderr, ""); + let _ = writeln!(stderr); let _ = writeln!(stderr, "===================="); - let _ = writeln!(stderr, ""); + let _ = writeln!(stderr); let _ = writeln!(stderr, "Version: {}", version); - let _ = writeln!(stderr, ""); + let _ = writeln!(stderr); let _ = writeln!(stderr, "{:?}", backtrace); - let _ = writeln!(stderr, ""); + let _ = writeln!(stderr); let _ = writeln!(stderr, "Thread '{}' panicked at '{}', {}:{}", name, msg, file, line); let _ = writeln!(stderr, ABOUT_PANIC!(), report_url); diff --git a/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs b/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs index 7c3f066f6c83b..e25295fdca5cb 100644 --- a/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs +++ b/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs @@ -79,7 +79,7 @@ pub fn derive_impl(input: DeriveInput) -> Result { /// /// Returns an error if the number of variants is greater than `256`, the given `data` is not an /// enum or a variant is not an unit. -fn get_enum_field_idents<'a>(data: &'a Data) -> Result>> { +fn get_enum_field_idents(data: &Data) -> Result>> { match data { Data::Enum(d) => if d.variants.len() <= 256 { diff --git a/primitives/runtime-interface/proc-macro/src/utils.rs b/primitives/runtime-interface/proc-macro/src/utils.rs index 19f7fea023c30..386eef153f45c 100644 --- a/primitives/runtime-interface/proc-macro/src/utils.rs +++ b/primitives/runtime-interface/proc-macro/src/utils.rs @@ -65,13 +65,11 @@ impl RuntimeInterfaceFunction { } }); - if should_trap_on_return { - if !matches!(item.sig.output, syn::ReturnType::Default) { - return Err(Error::new( - item.sig.ident.span(), - "Methods marked as #[trap_on_return] cannot return anything", - )) - } + if should_trap_on_return && !matches!(item.sig.output, syn::ReturnType::Default) { + return Err(Error::new( + item.sig.ident.span(), + "Methods marked as #[trap_on_return] cannot return anything", + )) } Ok(Self { item, should_trap_on_return }) @@ -212,7 +210,7 @@ pub fn create_function_ident_with_version(name: &Ident, version: u32) -> Ident { } /// Returns the function arguments of the given `Signature`, minus any `self` arguments. -pub fn get_function_arguments<'a>(sig: &'a Signature) -> impl Iterator + 'a { +pub fn get_function_arguments(sig: &Signature) -> impl Iterator + '_ { sig.inputs .iter() .filter_map(|a| match a { @@ -234,20 +232,20 @@ pub fn get_function_arguments<'a>(sig: &'a Signature) -> impl Iterator(sig: &'a Signature) -> impl Iterator> + 'a { +pub fn get_function_argument_names(sig: &Signature) -> impl Iterator> + '_ { get_function_arguments(sig).map(|pt| pt.pat) } /// Returns the function argument types of the given `Signature`, minus any `Self` type. -pub fn get_function_argument_types<'a>(sig: &'a Signature) -> impl Iterator> + 'a { +pub fn get_function_argument_types(sig: &Signature) -> impl Iterator> + '_ { get_function_arguments(sig).map(|pt| pt.ty) } /// Returns the function argument types, minus any `Self` type. If any of the arguments /// is a reference, the underlying type without the ref is returned. -pub fn get_function_argument_types_without_ref<'a>( - sig: &'a Signature, -) -> impl Iterator> + 'a { +pub fn get_function_argument_types_without_ref( + sig: &Signature, +) -> impl Iterator> + '_ { get_function_arguments(sig).map(|pt| pt.ty).map(|ty| match *ty { Type::Reference(type_ref) => type_ref.elem, _ => ty, @@ -256,9 +254,9 @@ pub fn get_function_argument_types_without_ref<'a>( /// Returns the function argument names and types, minus any `self`. If any of the arguments /// is a reference, the underlying type without the ref is returned. -pub fn get_function_argument_names_and_types_without_ref<'a>( - sig: &'a Signature, -) -> impl Iterator, Box)> + 'a { +pub fn get_function_argument_names_and_types_without_ref( + sig: &Signature, +) -> impl Iterator, Box)> + '_ { get_function_arguments(sig).map(|pt| match *pt.ty { Type::Reference(type_ref) => (pt.pat, type_ref.elem), _ => (pt.pat, pt.ty), @@ -267,9 +265,9 @@ pub fn get_function_argument_names_and_types_without_ref<'a>( /// Returns the `&`/`&mut` for all function argument types, minus the `self` arg. If a function /// argument is not a reference, `None` is returned. -pub fn get_function_argument_types_ref_and_mut<'a>( - sig: &'a Signature, -) -> impl Iterator)>> + 'a { +pub fn get_function_argument_types_ref_and_mut( + sig: &Signature, +) -> impl Iterator)>> + '_ { get_function_arguments(sig).map(|pt| pt.ty).map(|ty| match *ty { Type::Reference(type_ref) => Some((type_ref.and_token, type_ref.mutability)), _ => None, @@ -277,7 +275,7 @@ pub fn get_function_argument_types_ref_and_mut<'a>( } /// Returns an iterator over all trait methods for the given trait definition. -fn get_trait_methods<'a>(trait_def: &'a ItemTrait) -> impl Iterator { +fn get_trait_methods(trait_def: &ItemTrait) -> impl Iterator { trait_def.items.iter().filter_map(|i| match i { TraitItem::Method(ref method) => Some(method), _ => None, diff --git a/primitives/runtime/src/generic/digest.rs b/primitives/runtime/src/generic/digest.rs index 55e0d69fad33d..ec74ebb0d4e15 100644 --- a/primitives/runtime/src/generic/digest.rs +++ b/primitives/runtime/src/generic/digest.rs @@ -321,7 +321,7 @@ impl<'a> DigestItemRef<'a> { /// Cast this digest item into `PreRuntime` pub fn as_pre_runtime(&self) -> Option<(ConsensusEngineId, &'a [u8])> { match *self { - Self::PreRuntime(consensus_engine_id, ref data) => Some((*consensus_engine_id, data)), + Self::PreRuntime(consensus_engine_id, data) => Some((*consensus_engine_id, data)), _ => None, } } @@ -329,7 +329,7 @@ impl<'a> DigestItemRef<'a> { /// Cast this digest item into `Consensus` pub fn as_consensus(&self) -> Option<(ConsensusEngineId, &'a [u8])> { match *self { - Self::Consensus(consensus_engine_id, ref data) => Some((*consensus_engine_id, data)), + Self::Consensus(consensus_engine_id, data) => Some((*consensus_engine_id, data)), _ => None, } } @@ -337,7 +337,7 @@ impl<'a> DigestItemRef<'a> { /// Cast this digest item into `Seal` pub fn as_seal(&self) -> Option<(ConsensusEngineId, &'a [u8])> { match *self { - Self::Seal(consensus_engine_id, ref data) => Some((*consensus_engine_id, data)), + Self::Seal(consensus_engine_id, data) => Some((*consensus_engine_id, data)), _ => None, } } @@ -345,7 +345,7 @@ impl<'a> DigestItemRef<'a> { /// Cast this digest item into `PreRuntime` pub fn as_other(&self) -> Option<&'a [u8]> { match *self { - Self::Other(ref data) => Some(data), + Self::Other(data) => Some(data), _ => None, } } diff --git a/primitives/runtime/src/offchain/http.rs b/primitives/runtime/src/offchain/http.rs index c479062de5f11..dede4db5dd3de 100644 --- a/primitives/runtime/src/offchain/http.rs +++ b/primitives/runtime/src/offchain/http.rs @@ -452,7 +452,7 @@ impl Headers { let raw = name.as_bytes(); for &(ref key, ref val) in &self.raw { if &**key == raw { - return str::from_utf8(&val).ok() + return str::from_utf8(val).ok() } } None diff --git a/primitives/runtime/src/offchain/storage_lock.rs b/primitives/runtime/src/offchain/storage_lock.rs index 90f8df7945578..4ea9030745296 100644 --- a/primitives/runtime/src/offchain/storage_lock.rs +++ b/primitives/runtime/src/offchain/storage_lock.rs @@ -134,7 +134,7 @@ impl Lockable for Time { fn snooze(deadline: &Self::Deadline) { let now = offchain::timestamp(); - let remainder: Duration = now.diff(&deadline); + let remainder: Duration = now.diff(deadline); // do not snooze the full duration, but instead snooze max 100ms // it might get unlocked in another thread use core::cmp::{max, min}; diff --git a/primitives/runtime/src/runtime_string.rs b/primitives/runtime/src/runtime_string.rs index fcbdd2e787ff3..762af0acd9250 100644 --- a/primitives/runtime/src/runtime_string.rs +++ b/primitives/runtime/src/runtime_string.rs @@ -98,8 +98,8 @@ impl std::ops::Deref for RuntimeString { fn deref(&self) -> &str { match self { - Self::Borrowed(val) => &val, - Self::Owned(val) => &val, + Self::Borrowed(val) => val, + Self::Owned(val) => val, } } } diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 9c71b2023d3f8..dc13567df58db 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -159,7 +159,7 @@ where use sp_application_crypto::IsWrappedBy; let inner: &S = self.as_ref(); let inner_pubkey = - <::Public as sp_application_crypto::AppPublic>::Generic::from_ref(&signer); + <::Public as sp_application_crypto::AppPublic>::Generic::from_ref(signer); Verify::verify(inner, msg, inner_pubkey) } } @@ -1284,7 +1284,7 @@ impl AccountIdConversion fo fn try_from_sub_account(x: &T) -> Option<(Self, S)> { x.using_encoded(|d| { - if &d[0..4] != Id::TYPE_ID { + if d[0..4] != Id::TYPE_ID { return None } let mut cursor = &d[4..]; diff --git a/primitives/sandbox/src/embedded_executor.rs b/primitives/sandbox/src/embedded_executor.rs index 8a20cc1b39b54..4410e26c8d122 100644 --- a/primitives/sandbox/src/embedded_executor.rs +++ b/primitives/sandbox/src/embedded_executor.rs @@ -266,7 +266,7 @@ impl super::SandboxInstance for Instance { let mut externals = GuestExternals { state, defined_host_functions: &self.defined_host_functions }; - let result = self.instance.invoke_export(&name, &args, &mut externals); + let result = self.instance.invoke_export(name, &args, &mut externals); match result { Ok(None) => Ok(ReturnValue::Unit), diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index 8d0ac2d1369c9..e9d4ac0fb8224 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -197,7 +197,7 @@ pub trait Backend: sp_std::fmt::Debug { // child first for (child_info, child_delta) in child_deltas { let (child_root, empty, child_txs) = - self.child_storage_root(&child_info, child_delta, state_version); + self.child_storage_root(child_info, child_delta, state_version); let prefixed_storage_key = child_info.prefixed_storage_key(); txs.consolidate(child_txs); if empty { @@ -311,7 +311,7 @@ pub struct BackendRuntimeCode<'a, B, H> { impl<'a, B: Backend, H: Hasher> sp_core::traits::FetchRuntimeCode for BackendRuntimeCode<'a, B, H> { - fn fetch_runtime_code<'b>(&'b self) -> Option> { + fn fetch_runtime_code(&self) -> Option> { self.backend .storage(sp_core::storage::well_known_keys::CODE) .ok() diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index 1f257550fbf7a..f1c09251faa5e 100644 --- a/primitives/state-machine/src/basic.rs +++ b/primitives/state-machine/src/basic.rs @@ -288,7 +288,7 @@ impl Externalities for BasicExternalities { let empty_hash = empty_child_trie_root::>(); for (prefixed_storage_key, child_info) in prefixed_keys { let child_root = self.child_storage_root(&child_info, state_version); - if &empty_hash[..] == &child_root[..] { + if empty_hash[..] == child_root[..] { top.remove(prefixed_storage_key.as_slice()); } else { top.insert(prefixed_storage_key.into_inner(), child_root); diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index 7b7e4b47f19ba..e33569e2a1f67 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -316,8 +316,8 @@ where match (&next_backend_key, overlay_changes.peek()) { (_, None) => next_backend_key, (Some(_), Some(_)) => { - while let Some(overlay_key) = overlay_changes.next() { - let cmp = next_backend_key.as_deref().map(|v| v.cmp(&overlay_key.0)); + for overlay_key in overlay_changes { + let cmp = next_backend_key.as_deref().map(|v| v.cmp(overlay_key.0)); // If `backend_key` is less than the `overlay_key`, we found out next key. if cmp == Some(Ordering::Less) { @@ -332,7 +332,7 @@ where // this key. next_backend_key = self .backend - .next_storage_key(&overlay_key.0) + .next_storage_key(overlay_key.0) .expect(EXT_NOT_ALLOWED_TO_FAIL); } } @@ -357,8 +357,8 @@ where match (&next_backend_key, overlay_changes.peek()) { (_, None) => next_backend_key, (Some(_), Some(_)) => { - while let Some(overlay_key) = overlay_changes.next() { - let cmp = next_backend_key.as_deref().map(|v| v.cmp(&overlay_key.0)); + for overlay_key in overlay_changes { + let cmp = next_backend_key.as_deref().map(|v| v.cmp(overlay_key.0)); // If `backend_key` is less than the `overlay_key`, we found out next key. if cmp == Some(Ordering::Less) { @@ -373,7 +373,7 @@ where // this key. next_backend_key = self .backend - .next_child_storage_key(child_info, &overlay_key.0) + .next_child_storage_key(child_info, overlay_key.0) .expect(EXT_NOT_ALLOWED_TO_FAIL); } } @@ -546,7 +546,7 @@ where .storage(prefixed_storage_key.as_slice()) .and_then(|k| Decode::decode(&mut &k[..]).ok()) // V1 is equivalent to V0 on empty root. - .unwrap_or_else(|| empty_child_trie_root::>()); + .unwrap_or_else(empty_child_trie_root::>); trace!( target: "state", method = "ChildStorageRoot", @@ -593,7 +593,7 @@ where .storage(prefixed_storage_key.as_slice()) .and_then(|k| Decode::decode(&mut &k[..]).ok()) // V1 is equivalent to V0 on empty root. - .unwrap_or_else(|| empty_child_trie_root::>()); + .unwrap_or_else(empty_child_trie_root::>); trace!( target: "state", diff --git a/primitives/state-machine/src/in_memory_backend.rs b/primitives/state-machine/src/in_memory_backend.rs index 2d8173452abfe..457d89b8c59aa 100644 --- a/primitives/state-machine/src/in_memory_backend.rs +++ b/primitives/state-machine/src/in_memory_backend.rs @@ -94,7 +94,7 @@ where H::Out: Codec + Ord, { fn clone(&self) -> Self { - TrieBackend::new(self.backend_storage().clone(), self.root().clone()) + TrieBackend::new(self.backend_storage().clone(), *self.root()) } } diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 1a69d51d58abf..97a9ae8d88cd2 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -644,7 +644,7 @@ mod execution { H::Out: Ord + 'static + codec::Codec, Spawn: SpawnNamed + Send + 'static, { - let trie_backend = create_proof_check_backend::(root.into(), proof)?; + let trie_backend = create_proof_check_backend::(root, proof)?; execution_proof_check_on_trie_backend::<_, _, _>( &trie_backend, overlay, @@ -791,7 +791,7 @@ mod execution { self.0.last().and_then(|s| s.key_values.last().map(|kv| kv.0.clone())); if let Some(child_last) = child_last { - if last.len() == 0 { + if last.is_empty() { if let Some(top_last) = top_last { last.push(top_last) } else { @@ -866,7 +866,7 @@ mod execution { .storage(&storage_key) .map_err(|e| Box::new(e) as Box)? { - child_roots.insert(state_root.clone()); + child_roots.insert(state_root); } else { return Err(Box::new("Invalid range start child trie key.")) } @@ -880,7 +880,7 @@ mod execution { let (child_info, depth) = if let Some(storage_key) = child_key.as_ref() { let storage_key = PrefixedStorageKey::new_ref(storage_key); ( - Some(match ChildType::from_prefixed_key(&storage_key) { + Some(match ChildType::from_prefixed_key(storage_key) { Some((ChildType::ParentKeyId, storage_key)) => ChildInfo::new_default(storage_key), None => return Err(Box::new("Invalid range start child trie key.")), @@ -900,15 +900,15 @@ mod execution { None, start_at_ref, |key, value| { - if first { - if start_at_ref + if first && + start_at_ref .as_ref() .map(|start| &key.as_slice() > start) .unwrap_or(true) - { - first = false; - } + { + first = false; } + if first { true } else if depth < MAX_NESTED_TRIE_DEPTH && @@ -938,12 +938,10 @@ mod execution { if switch_child_key.is_none() { if depth == 1 { break + } else if completed { + start_at = child_key.take(); } else { - if completed { - start_at = child_key.take(); - } else { - break - } + break } } else { child_key = switch_child_key; @@ -1269,7 +1267,7 @@ mod execution { let storage_key = PrefixedStorageKey::new_ref(storage_key); ( - Some(match ChildType::from_prefixed_key(&storage_key) { + Some(match ChildType::from_prefixed_key(storage_key) { Some((ChildType::ParentKeyId, storage_key)) => ChildInfo::new_default(storage_key), None => return Err(Box::new("Invalid range start child trie key.")), @@ -1294,15 +1292,15 @@ mod execution { None, start_at_ref, |key, value| { - if first { - if start_at_ref + if first && + start_at_ref .as_ref() .map(|start| &key.as_slice() > start) .unwrap_or(true) - { - first = false; - } + { + first = false; } + if !first { values.push((key.to_vec(), value.to_vec())); } @@ -1390,7 +1388,7 @@ mod tests { let using_native = use_native && self.native_available; match (using_native, self.native_succeeds, self.fallback_succeeds, native_call) { (true, true, _, Some(call)) => { - let res = sp_externalities::set_and_run_with_externalities(ext, || call()); + let res = sp_externalities::set_and_run_with_externalities(ext, call); (res.map(NativeOrEncoded::Native).map_err(|_| 0), true) }, (true, true, _, None) | (false, _, true, None) => ( @@ -1584,13 +1582,13 @@ mod tests { .map(|(k, v)| (k.clone(), v.value().cloned())) .collect::>(), map![ - b"abc".to_vec() => None.into(), - b"abb".to_vec() => None.into(), - b"aba".to_vec() => None.into(), - b"abd".to_vec() => None.into(), + b"abc".to_vec() => None, + b"abb".to_vec() => None, + b"aba".to_vec() => None, + b"abd".to_vec() => None, - b"bab".to_vec() => Some(b"228".to_vec()).into(), - b"bbd".to_vec() => Some(b"42".to_vec()).into() + b"bab".to_vec() => Some(b"228".to_vec()), + b"bbd".to_vec() => Some(b"42".to_vec()) ], ); @@ -1608,12 +1606,12 @@ mod tests { .map(|(k, v)| (k.clone(), v.value().cloned())) .collect::>(), map![ - b"abb".to_vec() => None.into(), - b"aba".to_vec() => None.into(), - b"abd".to_vec() => None.into(), + b"abb".to_vec() => None, + b"aba".to_vec() => None, + b"abd".to_vec() => None, - b"bab".to_vec() => Some(b"228".to_vec()).into(), - b"bbd".to_vec() => Some(b"42".to_vec()).into() + b"bab".to_vec() => Some(b"228".to_vec()), + b"bbd".to_vec() => Some(b"42".to_vec()) ], ); } @@ -1647,15 +1645,15 @@ mod tests { overlay .children() .flat_map(|(iter, _child_info)| iter) - .map(|(k, v)| (k.clone(), v.value().clone())) + .map(|(k, v)| (k.clone(), v.value())) .collect::>(), map![ - b"1".to_vec() => None.into(), - b"2".to_vec() => None.into(), - b"3".to_vec() => None.into(), - b"4".to_vec() => None.into(), - b"a".to_vec() => None.into(), - b"b".to_vec() => None.into(), + b"1".to_vec() => None, + b"2".to_vec() => None, + b"3".to_vec() => None, + b"4".to_vec() => None, + b"a".to_vec() => None, + b"b".to_vec() => None, ], ); } @@ -1796,7 +1794,7 @@ mod tests { fn test_compact(remote_proof: StorageProof, remote_root: &sp_core::H256) -> StorageProof { let compact_remote_proof = - remote_proof.into_compact_proof::(remote_root.clone()).unwrap(); + remote_proof.into_compact_proof::(*remote_root).unwrap(); compact_remote_proof .to_storage_proof::(Some(remote_root)) .unwrap() @@ -1823,8 +1821,7 @@ mod tests { read_proof_check::(remote_root, remote_proof.clone(), &[b"value2"]) .unwrap(); let local_result2 = - read_proof_check::(remote_root, remote_proof.clone(), &[&[0xff]]) - .is_ok(); + read_proof_check::(remote_root, remote_proof, &[&[0xff]]).is_ok(); // check that results are correct assert_eq!( local_result1.into_iter().collect::>(), @@ -1852,7 +1849,7 @@ mod tests { .unwrap(); let local_result3 = read_child_proof_check::( remote_root, - remote_proof.clone(), + remote_proof, missing_child_info, &[b"dummy"], ) @@ -1899,7 +1896,7 @@ mod tests { let trie: InMemoryBackend = (storage.clone(), StateVersion::default()).into(); - let trie_root = trie.root().clone(); + let trie_root = trie.root(); let backend = crate::ProvingBackend::new(&trie); let mut queries = Vec::new(); for c in 0..(5 + nb_child_trie / 2) { @@ -1948,7 +1945,7 @@ mod tests { let storage_proof = backend.extract_proof(); let remote_proof = test_compact(storage_proof, &trie_root); let proof_check = - create_proof_check_backend::(trie_root, remote_proof).unwrap(); + create_proof_check_backend::(*trie_root, remote_proof).unwrap(); for (child_info, key, expected) in queries { assert_eq!( @@ -1998,15 +1995,9 @@ mod tests { prove_range_read_with_size(remote_backend, None, None, 50000, Some(&[])).unwrap(); assert_eq!(proof.clone().into_memory_db::().drain().len(), 11); assert_eq!(count, 132); - let (results, completed) = read_range_proof_check::( - remote_root, - proof.clone(), - None, - None, - None, - None, - ) - .unwrap(); + let (results, completed) = + read_range_proof_check::(remote_root, proof, None, None, None, None) + .unwrap(); assert_eq!(results.len() as u32, count); assert_eq!(completed, true); } @@ -2041,11 +2032,11 @@ mod tests { remote_proof }; - let remote_proof = check_proof(mdb.clone(), root.clone(), state_version); + let remote_proof = check_proof(mdb.clone(), root, state_version); // check full values in proof assert!(remote_proof.encode().len() > 1_100); assert!(remote_proof.encoded_size() > 1_100); - let root1 = root.clone(); + let root1 = root; // do switch state_version = StateVersion::V1; @@ -2057,9 +2048,9 @@ mod tests { trie.insert(b"foo", vec![1u8; 1000].as_slice()) // inner hash .expect("insert failed"); } - let root3 = root.clone(); + let root3 = root; assert!(root1 != root3); - let remote_proof = check_proof(mdb.clone(), root.clone(), state_version); + let remote_proof = check_proof(mdb.clone(), root, state_version); // nodes foo is replaced by its hashed value form. assert!(remote_proof.encode().len() < 1000); assert!(remote_proof.encoded_size() < 1000); @@ -2159,7 +2150,7 @@ mod tests { let remote_proof = test_compact(remote_proof, &remote_root); let local_result1 = read_child_proof_check::( remote_root, - remote_proof.clone(), + remote_proof, &child_info1, &[b"key1"], ) diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index 59f3e1cffa5f6..2161b343711c9 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -513,7 +513,7 @@ impl OverlayedChanges { pub fn drain_storage_changes, H: Hasher>( &mut self, backend: &B, - mut cache: &mut StorageTransactionCache, + cache: &mut StorageTransactionCache, state_version: StateVersion, ) -> Result, DefaultError> where @@ -521,7 +521,7 @@ impl OverlayedChanges { { // If the transaction does not exist, we generate it. if cache.transaction.is_none() { - self.storage_root(backend, &mut cache, state_version); + self.storage_root(backend, cache, state_version); } let (transaction, transaction_storage_root) = cache diff --git a/primitives/state-machine/src/overlayed_changes/offchain.rs b/primitives/state-machine/src/overlayed_changes/offchain.rs index 98457700013aa..a9643c265e755 100644 --- a/primitives/state-machine/src/overlayed_changes/offchain.rs +++ b/primitives/state-machine/src/overlayed_changes/offchain.rs @@ -42,7 +42,7 @@ impl OffchainOverlayedChanges { } /// Iterate over all key value pairs by reference. - pub fn iter<'a>(&'a self) -> impl Iterator> { + pub fn iter(&self) -> impl Iterator { self.0.changes().map(|kv| (kv.0, kv.1.value_ref())) } diff --git a/primitives/state-machine/src/proving_backend.rs b/primitives/state-machine/src/proving_backend.rs index eeffcc8e47052..b47e6c693a3e8 100644 --- a/primitives/state-machine/src/proving_backend.rs +++ b/primitives/state-machine/src/proving_backend.rs @@ -77,7 +77,7 @@ where .storage(storage_key)? .and_then(|r| Decode::decode(&mut &r[..]).ok()) // V1 is equivalent to V0 on empty trie - .unwrap_or_else(|| empty_child_trie_root::>()); + .unwrap_or_else(empty_child_trie_root::>); let mut read_overlay = S::Overlay::default(); let eph = Ephemeral::new(self.backend.backend_storage(), &mut read_overlay); @@ -88,7 +88,7 @@ where read_child_trie_value_with::, _, _>( child_info.keyspace(), &eph, - &root.as_ref(), + root.as_ref(), key, &mut *self.proof_recorder, ) @@ -203,7 +203,7 @@ where proof_recorder: ProofRecorder, ) -> Self { let essence = backend.essence(); - let root = essence.root().clone(); + let root = *essence.root(); let recorder = ProofRecorderBackend { backend: essence.backend_storage(), proof_recorder }; ProvingBackend(TrieBackend::new(recorder, root)) } @@ -238,7 +238,7 @@ impl<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> TrieBackendStorage } let backend_value = self.backend.get(key, prefix)?; - self.proof_recorder.record(key.clone(), backend_value.clone()); + self.proof_recorder.record(*key, backend_value.clone()); Ok(backend_value) } } @@ -395,9 +395,9 @@ mod tests { use sp_runtime::traits::BlakeTwo256; use sp_trie::PrefixedMemoryDB; - fn test_proving<'a>( - trie_backend: &'a TrieBackend, BlakeTwo256>, - ) -> ProvingBackend<'a, PrefixedMemoryDB, BlakeTwo256> { + fn test_proving( + trie_backend: &TrieBackend, BlakeTwo256>, + ) -> ProvingBackend, BlakeTwo256> { ProvingBackend::new(trie_backend) } @@ -474,7 +474,6 @@ mod tests { let trie_root = trie.storage_root(std::iter::empty(), state_version).0; assert_eq!(in_memory_root, trie_root); value_range - .clone() .for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i; size_content])); let proving = ProvingBackend::new(trie); @@ -482,8 +481,7 @@ mod tests { let proof = proving.extract_proof(); - let proof_check = - create_proof_check_backend::(in_memory_root.into(), proof).unwrap(); + let proof_check = create_proof_check_backend::(in_memory_root, proof).unwrap(); assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42; size_content]); } @@ -530,8 +528,7 @@ mod tests { let proof = proving.extract_proof(); - let proof_check = - create_proof_check_backend::(in_memory_root.into(), proof).unwrap(); + let proof_check = create_proof_check_backend::(in_memory_root, proof).unwrap(); assert!(proof_check.storage(&[0]).is_err()); assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42]); // note that it is include in root because proof close @@ -542,8 +539,7 @@ mod tests { assert_eq!(proving.child_storage(child_info_1, &[64]), Ok(Some(vec![64]))); let proof = proving.extract_proof(); - let proof_check = - create_proof_check_backend::(in_memory_root.into(), proof).unwrap(); + let proof_check = create_proof_check_backend::(in_memory_root, proof).unwrap(); assert_eq!(proof_check.child_storage(child_info_1, &[64]).unwrap().unwrap(), vec![64]); } diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 418e6f3d2dce1..0bbea7004848a 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -521,7 +521,7 @@ where Ok(None) => default_root, Err(e) => { warn!(target: "trie", "Failed to read child storage root: {}", e); - default_root.clone() + default_root }, }; @@ -580,16 +580,12 @@ impl<'a, S: 'a + TrieBackendStorage, H: Hasher> hash_db::HashDB for Ephemeral<'a, S, H> { fn get(&self, key: &H::Out, prefix: Prefix) -> Option { - match HashDB::get(self.overlay, key, prefix) { - Some(val) => Some(val), - None => match self.storage.get(&key, prefix) { - Ok(x) => x, - Err(e) => { - warn!(target: "trie", "Failed to read from DB: {}", e); - None - }, - }, - } + HashDB::get(self.overlay, key, prefix).or_else(|| { + self.storage.get(key, prefix).unwrap_or_else(|e| { + warn!(target: "trie", "Failed to read from DB: {}", e); + None + }) + }) } fn contains(&self, key: &H::Out, prefix: Prefix) -> bool { @@ -664,7 +660,7 @@ impl, H: Hasher> HashDB for TrieBackendEsse if *key == self.empty { return Some([0u8].to_vec()) } - match self.storage.get(&key, prefix) { + match self.storage.get(key, prefix) { Ok(x) => x, Err(e) => { warn!(target: "trie", "Failed to read from DB: {}", e); diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index fecd2b24dbb00..0948cf431158d 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -189,21 +189,21 @@ pub mod well_known_keys { /// Wasm code of the runtime. /// /// Stored as a raw byte vector. Required by substrate. - pub const CODE: &'static [u8] = b":code"; + pub const CODE: &[u8] = b":code"; /// Number of wasm linear memory pages required for execution of the runtime. /// /// The type of this value is encoded `u64`. - pub const HEAP_PAGES: &'static [u8] = b":heappages"; + pub const HEAP_PAGES: &[u8] = b":heappages"; /// Current extrinsic index (u32) is stored under this key. - pub const EXTRINSIC_INDEX: &'static [u8] = b":extrinsic_index"; + pub const EXTRINSIC_INDEX: &[u8] = b":extrinsic_index"; /// Prefix of child storage keys. - pub const CHILD_STORAGE_KEY_PREFIX: &'static [u8] = b":child_storage:"; + pub const CHILD_STORAGE_KEY_PREFIX: &[u8] = b":child_storage:"; /// Prefix of the default child storage keys in the top trie. - pub const DEFAULT_CHILD_STORAGE_KEY_PREFIX: &'static [u8] = b":child_storage:default:"; + pub const DEFAULT_CHILD_STORAGE_KEY_PREFIX: &[u8] = b":child_storage:default:"; /// Whether a key is a default child storage key. /// @@ -359,7 +359,7 @@ impl ChildType { fn do_prefix_key(&self, key: &mut Vec) { let parent_prefix = self.parent_prefix(); let key_len = key.len(); - if parent_prefix.len() > 0 { + if !parent_prefix.is_empty() { key.resize(key_len + parent_prefix.len(), 0); key.copy_within(..key_len, parent_prefix.len()); key[..parent_prefix.len()].copy_from_slice(parent_prefix); diff --git a/primitives/tracing/src/types.rs b/primitives/tracing/src/types.rs index d175e1f8f17e8..e7d5abfb27d9a 100644 --- a/primitives/tracing/src/types.rs +++ b/primitives/tracing/src/types.rs @@ -639,7 +639,7 @@ mod std_features { tracing::span::Span::child_of( a.parent_id.map(tracing_core::span::Id::from_u64), - &metadata, + metadata, &tracing::valueset! { metadata.fields(), target, name, file, line, module_path, ?params }, ) } @@ -658,7 +658,7 @@ mod std_features { tracing_core::Event::child_of( self.parent_id.map(tracing_core::span::Id::from_u64), - &metadata, + metadata, &tracing::valueset! { metadata.fields(), target, name, file, line, module_path, ?params }, ) } diff --git a/primitives/transaction-storage-proof/src/lib.rs b/primitives/transaction-storage-proof/src/lib.rs index 2e5aa3b2b9c71..ee0c8e4ec8e29 100644 --- a/primitives/transaction-storage-proof/src/lib.rs +++ b/primitives/transaction-storage-proof/src/lib.rs @@ -154,7 +154,7 @@ pub mod registration { B: BlockT, C: IndexedBody, { - let parent_number = client.number(parent.clone())?.unwrap_or(Zero::zero()); + let parent_number = client.number(*parent)?.unwrap_or(Zero::zero()); let number = parent_number .saturating_add(One::one()) .saturating_sub(DEFAULT_STORAGE_PERIOD.into()); @@ -214,10 +214,10 @@ pub mod registration { trie.commit(); } if target_chunk.is_some() && target_root == Default::default() { - target_root = transaction_root.clone(); + target_root = transaction_root; chunk_proof = sp_trie::generate_trie_proof::( &db, - transaction_root.clone(), + transaction_root, &[target_chunk_key.clone()], ) .map_err(|e| Error::Application(Box::new(e)))?; diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index c4d4c7210bd46..358cb43ab4e92 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -555,7 +555,7 @@ mod tests { for (x, y) in input.iter().rev() { t.insert(x, y).unwrap(); } - t.root().clone() + *t.root() }; assert_eq!(closed_form, persistent); } @@ -571,7 +571,7 @@ mod tests { } } { - let t = TrieDB::::new(&mut memdb, &root).unwrap(); + let t = TrieDB::::new(&memdb, &root).unwrap(); assert_eq!( input.iter().map(|(i, j)| (i.to_vec(), j.to_vec())).collect::>(), t.iter() @@ -752,7 +752,7 @@ mod tests { memtrie.commit(); if *memtrie.root() != real { println!("TRIE MISMATCH"); - println!(""); + println!(); println!("{:?} vs {:?}", memtrie.root(), real); for i in &x { println!("{:#x?} -> {:#x?}", i.0, i.1); @@ -764,7 +764,7 @@ mod tests { let hashed_null_node = hashed_null_node::(); if *memtrie.root() != hashed_null_node { println!("- TRIE MISMATCH"); - println!(""); + println!(); println!("{:?} vs {:?}", memtrie.root(), hashed_null_node); for i in &x { println!("{:#x?} -> {:#x?}", i.0, i.1); diff --git a/primitives/trie/src/trie_codec.rs b/primitives/trie/src/trie_codec.rs index a7f292271565f..d29f5a98f31b9 100644 --- a/primitives/trie/src/trie_codec.rs +++ b/primitives/trie/src/trie_codec.rs @@ -71,7 +71,7 @@ where // Only check root if expected root is passed as argument. if let Some(expected_root) = expected_root { if expected_root != &top_root { - return Err(Error::RootMismatch(top_root.clone(), expected_root.clone())) + return Err(Error::RootMismatch(top_root, *expected_root)) } } diff --git a/primitives/trie/src/trie_stream.rs b/primitives/trie/src/trie_stream.rs index a17d7c25e1b8a..ca798db47b552 100644 --- a/primitives/trie/src/trie_stream.rs +++ b/primitives/trie/src/trie_stream.rs @@ -53,7 +53,7 @@ fn branch_node_bit_mask(has_children: impl Iterator) -> (u8, u8) { } /// Create a leaf/branch node, encoding a number of nibbles. -fn fuse_nibbles_node<'a>(nibbles: &'a [u8], kind: NodeKind) -> impl Iterator + 'a { +fn fuse_nibbles_node(nibbles: &[u8], kind: NodeKind) -> impl Iterator + '_ { let size = sp_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibbles.len()); let iter_start = match kind { diff --git a/primitives/version/proc-macro/src/decl_runtime_version.rs b/primitives/version/proc-macro/src/decl_runtime_version.rs index 9ca1a67cc7fd6..ee81940b53993 100644 --- a/primitives/version/proc-macro/src/decl_runtime_version.rs +++ b/primitives/version/proc-macro/src/decl_runtime_version.rs @@ -105,7 +105,7 @@ impl ParseRuntimeVersion { parser: impl FnOnce(&Expr) -> Result, ) -> Result<()> { if value.is_some() { - return Err(Error::new(field.span(), "field is already initialized before")) + Err(Error::new(field.span(), "field is already initialized before")) } else { *value = Some(parser(&field.expr)?); Ok(()) diff --git a/primitives/wasm-interface/src/wasmi_impl.rs b/primitives/wasm-interface/src/wasmi_impl.rs index 2239eb5f38658..977b4fc606fa7 100644 --- a/primitives/wasm-interface/src/wasmi_impl.rs +++ b/primitives/wasm-interface/src/wasmi_impl.rs @@ -73,7 +73,7 @@ impl From for wasmi::Signature { impl From<&wasmi::Signature> for Signature { fn from(sig: &wasmi::Signature) -> Self { Signature::new( - sig.params().into_iter().copied().map(Into::into).collect::>(), + sig.params().iter().copied().map(Into::into).collect::>(), sig.return_type().map(Into::into), ) } diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 94a350b5f5df3..cdadfb0f10f03 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -342,7 +342,7 @@ impl RpcHandlersExt for RpcHandlers { extrinsic: OpaqueExtrinsic, ) -> Pin> + Send>> { let (tx, rx) = futures::channel::mpsc::unbounded(); - let mem = RpcSession::new(tx.into()); + let mem = RpcSession::new(tx); Box::pin( self.rpc_query( &mem, diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index 71118b4183ef9..3ece5165e1757 100644 --- a/test-utils/runtime/src/genesismap.rs +++ b/test-utils/runtime/src/genesismap.rs @@ -67,7 +67,7 @@ impl GenesisConfig { (well_known_keys::CODE.into(), wasm_runtime), ( well_known_keys::HEAP_PAGES.into(), - vec![].and(&(self.heap_pages_override.unwrap_or(16 as u64))), + vec![].and(&(self.heap_pages_override.unwrap_or(16_u64))), ), ] .into_iter(), @@ -80,8 +80,7 @@ impl GenesisConfig { // Assimilate the system genesis config. let mut storage = Storage { top: map, children_default: self.extra_storage.children_default.clone() }; - let mut config = system::GenesisConfig::default(); - config.authorities = self.authorities.clone(); + let config = system::GenesisConfig { authorities: self.authorities.clone() }; config .assimilate_storage(&mut storage) .expect("Adding `system::GensisConfig` to the genesis"); diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 6df35421d3614..77cd18c028364 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -77,7 +77,7 @@ pub fn initialize_block(header: &Header) { // try to read something that depends on current header digest // so that it'll be included in execution proof if let Some(generic::DigestItem::Other(v)) = header.digest().logs().iter().next() { - let _: Option = storage::unhashed::get(&v); + let _: Option = storage::unhashed::get(v); } } diff --git a/utils/fork-tree/src/lib.rs b/utils/fork-tree/src/lib.rs index c23a4f55f44a1..b4985b77294b2 100644 --- a/utils/fork-tree/src/lib.rs +++ b/utils/fork-tree/src/lib.rs @@ -374,7 +374,7 @@ where let node = self.roots.swap_remove(position); self.roots = node.children; self.best_finalized_number = Some(node.number); - return node.data + node.data } /// Finalize a node in the tree. This method will make sure that the node @@ -539,18 +539,17 @@ where // tree, if we find a valid node that passes the predicate then we must // ensure that we're not finalizing past any of its child nodes. for node in self.node_iter() { - if predicate(&node.data) { - if node.hash == *hash || is_descendent_of(&node.hash, hash)? { - for child in node.children.iter() { - if child.number <= number && - (child.hash == *hash || is_descendent_of(&child.hash, hash)?) - { - return Err(Error::UnfinalizedAncestor) - } + if predicate(&node.data) && (node.hash == *hash || is_descendent_of(&node.hash, hash)?) + { + for child in node.children.iter() { + if child.number <= number && + (child.hash == *hash || is_descendent_of(&child.hash, hash)?) + { + return Err(Error::UnfinalizedAncestor) } - - return Ok(Some(self.roots.iter().any(|root| root.hash == node.hash))) } + + return Ok(Some(self.roots.iter().any(|root| root.hash == node.hash))) } } @@ -587,19 +586,18 @@ where // we're not finalizing past any children node. let mut position = None; for (i, root) in self.roots.iter().enumerate() { - if predicate(&root.data) { - if root.hash == *hash || is_descendent_of(&root.hash, hash)? { - for child in root.children.iter() { - if child.number <= number && - (child.hash == *hash || is_descendent_of(&child.hash, hash)?) - { - return Err(Error::UnfinalizedAncestor) - } + if predicate(&root.data) && (root.hash == *hash || is_descendent_of(&root.hash, hash)?) + { + for child in root.children.iter() { + if child.number <= number && + (child.hash == *hash || is_descendent_of(&child.hash, hash)?) + { + return Err(Error::UnfinalizedAncestor) } - - position = Some(i); - break } + + position = Some(i); + break } } @@ -1071,16 +1069,13 @@ mod test { let finalize_a = || { let (mut tree, ..) = test_fork_tree(); - assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), - vec![("A", 1)], - ); + assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("A", 1)]); // finalizing "A" opens up three possible forks tree.finalize_root(&"A"); assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), + tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("B", 2), ("F", 2), ("J", 2)], ); @@ -1093,10 +1088,7 @@ mod test { // finalizing "B" will progress on its fork and remove any other competing forks tree.finalize_root(&"B"); - assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), - vec![("C", 3)], - ); + assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("C", 3)],); // all the other forks have been pruned assert!(tree.roots.len() == 1); @@ -1108,10 +1100,7 @@ mod test { // finalizing "J" will progress on its fork and remove any other competing forks tree.finalize_root(&"J"); - assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), - vec![("K", 3)], - ); + assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("K", 3)],); // all the other forks have been pruned assert!(tree.roots.len() == 1); @@ -1136,7 +1125,7 @@ mod test { ); assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), + tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("B", 2), ("F", 2), ("J", 2)], ); @@ -1160,7 +1149,7 @@ mod test { ); assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), + tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("L", 4), ("I", 4)], ); @@ -1194,7 +1183,7 @@ mod test { ); assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), + tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("B", 2), ("F", 2), ("J", 2)], ); @@ -1208,7 +1197,7 @@ mod test { ); assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), + tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("L", 4), ("I", 4)], ); @@ -1224,10 +1213,7 @@ mod test { Ok(FinalizationResult::Changed(None)), ); - assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), - vec![], - ); + assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![],); assert_eq!(tree.best_finalized_number, Some(6)); } @@ -1306,10 +1292,7 @@ mod test { Ok(FinalizationResult::Changed(None)), ); - assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), - vec![("A0", 1)], - ); + assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("A0", 1)],); // finalizing "C" will finalize the node "A0" and prune it out of the tree assert_eq!( @@ -1327,10 +1310,7 @@ mod test { Ok(FinalizationResult::Changed(Some(Change { effective: 5 }))), ); - assert_eq!( - tree.roots().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), - vec![("D", 10)], - ); + assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("D", 10)],); // finalizing "F" will fail since it would finalize past "E" without finalizing "D" first assert_eq!( @@ -1359,7 +1339,7 @@ mod test { fn iter_iterates_in_preorder() { let (tree, ..) = test_fork_tree(); assert_eq!( - tree.iter().map(|(h, n, _)| (h.clone(), n.clone())).collect::>(), + tree.iter().map(|(h, n, _)| (*h, *n)).collect::>(), vec![ ("A", 1), ("B", 2), diff --git a/utils/frame/benchmarking-cli/src/overhead/template.rs b/utils/frame/benchmarking-cli/src/overhead/template.rs index d5f90d4873866..44e2c1f02e30f 100644 --- a/utils/frame/benchmarking-cli/src/overhead/template.rs +++ b/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -31,7 +31,7 @@ use crate::{ shared::{Stats, UnderscoreHelper}, }; -static VERSION: &'static str = env!("CARGO_PKG_VERSION"); +static VERSION: &str = env!("CARGO_PKG_VERSION"); static TEMPLATE: &str = include_str!("./weights.hbs"); /// Data consumed by Handlebar to fill out the `weights.hbs` template. @@ -93,13 +93,13 @@ impl TemplateData { let mut fd = fs::File::create(&out_path)?; info!("Writing weights to {:?}", fs::canonicalize(&out_path)?); handlebars - .render_template_to_write(&TEMPLATE, &self, &mut fd) + .render_template_to_write(TEMPLATE, &self, &mut fd) .map_err(|e| format!("HBS template write: {:?}", e).into()) } /// Build a path for the weight file. fn build_path(&self, weight_out: &Option) -> Result { - let mut path = weight_out.clone().unwrap_or(PathBuf::from(".")); + let mut path = weight_out.clone().unwrap_or_else(|| PathBuf::from(".")); if !path.is_dir() { return Err("Need directory as --weight-path".into()) diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 89b8d018bcb5c..660f31b8f1529 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -123,9 +123,9 @@ impl PalletCmd { let spec = config.chain_spec; let wasm_method = self.wasm_method.into(); let strategy = self.execution.unwrap_or(ExecutionStrategy::Native); - let pallet = self.pallet.clone().unwrap_or_else(|| String::new()); + let pallet = self.pallet.clone().unwrap_or_default(); let pallet = pallet.as_bytes(); - let extrinsic = self.extrinsic.clone().unwrap_or_else(|| String::new()); + let extrinsic = self.extrinsic.clone().unwrap_or_default(); let extrinsic_split: Vec<&str> = extrinsic.split(',').collect(); let extrinsics: Vec<_> = extrinsic_split.iter().map(|x| x.trim().as_bytes()).collect(); @@ -155,7 +155,7 @@ impl PalletCmd { extensions.register(OffchainWorkerExt::new(offchain.clone())); extensions.register(OffchainDbExt::new(offchain)); extensions.register(TransactionPoolExt::new(pool)); - return extensions + extensions }; // Get Benchmark List @@ -339,7 +339,7 @@ impl PalletCmd { batches.extend(batch); // Show progress information - if let Some(elapsed) = timer.elapsed().ok() { + if let Ok(elapsed) = timer.elapsed() { if elapsed >= time::Duration::from_secs(5) { timer = time::SystemTime::now(); log::info!( @@ -401,7 +401,7 @@ impl PalletCmd { batches: &Vec, storage_info: &Vec, ) { - for batch in batches.into_iter() { + for batch in batches.iter() { // Print benchmark metadata println!( "Pallet: {:?}, Extrinsic: {:?}, Lowest values: {:?}, Highest values: {:?}, Steps: {:?}, Repeat: {:?}", @@ -420,12 +420,12 @@ impl PalletCmd { if !self.no_storage_info { let mut comments: Vec = Default::default(); - writer::add_storage_comments(&mut comments, &batch.db_results, &storage_info); + writer::add_storage_comments(&mut comments, &batch.db_results, storage_info); println!("Raw Storage Info\n========"); for comment in comments { println!("{}", comment); } - println!(""); + println!(); } // Conduct analysis. @@ -446,7 +446,7 @@ impl PalletCmd { { println!("Writes = {:?}", analysis); } - println!(""); + println!(); } if !self.no_min_squares { println!("Min Squares Analysis\n========"); @@ -465,7 +465,7 @@ impl PalletCmd { { println!("Writes = {:?}", analysis); } - println!(""); + println!(); } } } diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index 81b20ad445cd0..515582d8c6db9 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -35,7 +35,7 @@ use frame_support::traits::StorageInfo; use sp_core::hexdisplay::HexDisplay; use sp_runtime::traits::Zero; -const VERSION: &'static str = env!("CARGO_PKG_VERSION"); +const VERSION: &str = env!("CARGO_PKG_VERSION"); const TEMPLATE: &str = include_str!("./template.hbs"); // This is the final structure we will pass to the Handlebars template. @@ -280,12 +280,12 @@ pub fn write_results( // Which analysis function should be used when outputting benchmarks let analysis_choice: AnalysisChoice = - cmd.output_analysis.clone().try_into().map_err(|e| io_error(e))?; + cmd.output_analysis.clone().try_into().map_err(io_error)?; // Capture individual args let cmd_data = CmdData { - steps: cmd.steps.clone(), - repeat: cmd.repeat.clone(), + steps: cmd.steps, + repeat: cmd.repeat, lowest_range_values: cmd.lowest_range_values.clone(), highest_range_values: cmd.highest_range_values.clone(), execution: format!("{:?}", cmd.execution), @@ -374,7 +374,7 @@ pub(crate) fn add_storage_comments( // This tracks the keys we already identified, so we only generate a single comment. let mut identified = HashSet::>::new(); - for result in results.clone() { + for result in results { for (key, reads, writes, whitelisted) in &result.keys { // skip keys which are whitelisted if *whitelisted { diff --git a/utils/frame/benchmarking-cli/src/shared/stats.rs b/utils/frame/benchmarking-cli/src/shared/stats.rs index 7785965fed4a7..3234d5f2f94f7 100644 --- a/utils/frame/benchmarking-cli/src/shared/stats.rs +++ b/utils/frame/benchmarking-cli/src/shared/stats.rs @@ -73,7 +73,7 @@ impl Stats { if xs.is_empty() { return Err("Empty input is invalid".into()) } - let (avg, stddev) = Self::avg_and_stddev(&xs); + let (avg, stddev) = Self::avg_and_stddev(xs); Ok(Self { sum: xs.iter().sum(), @@ -112,7 +112,7 @@ impl Stats { /// Returns the specified percentile for the given data. /// This is best effort since it ignores the interpolation case. fn percentile(mut xs: Vec, p: f64) -> u64 { - xs.sort(); + xs.sort_unstable(); let index = (xs.len() as f64 * p).ceil() as usize - 1; xs[index.clamp(0, xs.len() - 1)] } @@ -120,9 +120,9 @@ impl Stats { impl fmt::Debug for Stats { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Total: {}\n", self.sum)?; - write!(f, "Min: {}, Max: {}\n", self.min, self.max)?; - write!(f, "Average: {}, Median: {}, Stddev: {}\n", self.avg, self.median, self.stddev)?; + writeln!(f, "Total: {}", self.sum)?; + writeln!(f, "Min: {}, Max: {}", self.min, self.max)?; + writeln!(f, "Average: {}, Median: {}, Stddev: {}", self.avg, self.median, self.stddev)?; write!(f, "Percentiles 99th, 95th, 75th: {}, {}, {}", self.p99, self.p95, self.p75) } } diff --git a/utils/frame/benchmarking-cli/src/storage/template.rs b/utils/frame/benchmarking-cli/src/storage/template.rs index 26aa8a962301b..8365c3841d422 100644 --- a/utils/frame/benchmarking-cli/src/storage/template.rs +++ b/utils/frame/benchmarking-cli/src/storage/template.rs @@ -25,7 +25,7 @@ use std::{env, fs, path::PathBuf}; use super::cmd::StorageParams; use crate::shared::{Stats, UnderscoreHelper}; -static VERSION: &'static str = env!("CARGO_PKG_VERSION"); +static VERSION: &str = env!("CARGO_PKG_VERSION"); static TEMPLATE: &str = include_str!("./weights.hbs"); /// Data consumed by Handlebar to fill out the `weights.hbs` template. diff --git a/utils/frame/frame-utilities-cli/src/pallet_id.rs b/utils/frame/frame-utilities-cli/src/pallet_id.rs index c39bee8b87463..c0a221d4bcd11 100644 --- a/utils/frame/frame-utilities-cli/src/pallet_id.rs +++ b/utils/frame/frame-utilities-cli/src/pallet_id.rs @@ -64,7 +64,7 @@ impl PalletIdCmd { R::AccountId: Ss58Codec, { if self.id.len() != 8 { - Err("a module id must be a string of 8 characters")? + return Err("a module id must be a string of 8 characters".into()) } let password = self.keystore_params.read_password()?; @@ -80,7 +80,7 @@ impl PalletIdCmd { &account_id.to_ss58check_with_version(unwrap_or_default_ss58_version(self.network)), password, self.network, - self.output_scheme.output_type.clone() + self.output_scheme.output_type ) ); diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index a717a93f072bc..1d9dc5dcd11da 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -275,8 +275,8 @@ impl Default for Builder { impl Builder { fn as_online(&self) -> &OnlineConfig { match &self.mode { - Mode::Online(config) => &config, - Mode::OfflineOrElseOnline(_, config) => &config, + Mode::Online(config) => config, + Mode::OfflineOrElseOnline(_, config) => config, _ => panic!("Unexpected mode: Online"), } } @@ -380,7 +380,7 @@ impl Builder { log::error!( target: LOG_TARGET, "failed to execute batch: {:?}. Error: {:?}", - chunk_keys.iter().map(|k| HexDisplay::from(k)).collect::>(), + chunk_keys.iter().map(HexDisplay::from).collect::>(), e ); "batch failed." @@ -388,7 +388,7 @@ impl Builder { assert_eq!(chunk_keys.len(), values.len()); - for (idx, key) in chunk_keys.into_iter().enumerate() { + for (idx, key) in chunk_keys.iter().enumerate() { let maybe_value = values[idx].clone(); let value = maybe_value.unwrap_or_else(|| { log::warn!(target: LOG_TARGET, "key {:?} had none corresponding value.", &key); @@ -452,7 +452,7 @@ impl Builder { assert_eq!(batch_child_key.len(), batch_response.len()); - for (idx, key) in batch_child_key.into_iter().enumerate() { + for (idx, key) in batch_child_key.iter().enumerate() { let maybe_value = batch_response[idx].clone(); let value = maybe_value.unwrap_or_else(|| { log::warn!(target: LOG_TARGET, "key {:?} had none corresponding value.", &key); @@ -571,7 +571,7 @@ impl Builder { &self, top_kv: &[KeyValue], ) -> Result { - let child_kv = self.load_child_remote(&top_kv).await?; + let child_kv = self.load_child_remote(top_kv).await?; if let Some(c) = &self.as_online().state_snapshot { self.save_child_snapshot(&child_kv, &c.path)?; } @@ -612,7 +612,7 @@ impl Builder { }, }; - child_kv.push((ChildInfo::new_default(&un_prefixed), child_kv_inner)); + child_kv.push((ChildInfo::new_default(un_prefixed), child_kv_inner)); } Ok(child_kv) @@ -624,8 +624,7 @@ impl Builder { let at = self .as_online() .at - .expect("online config must be initialized by this point; qed.") - .clone(); + .expect("online config must be initialized by this point; qed."); log::info!(target: LOG_TARGET, "scraping key-pairs from remote @ {:?}", at); let mut keys_and_values = if config.pallets.len() > 0 { @@ -848,7 +847,7 @@ impl Builder { info!( target: LOG_TARGET, "injecting a total of {} child keys", - child_kv.iter().flat_map(|(_, kv)| kv).count(), + child_kv.iter().flat_map(|(_, kv)| kv).count() ); for (info, key_values) in child_kv { diff --git a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index 98a3cf964843c..2e3dd08a7db7e 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -73,7 +73,7 @@ where return Err("No access to trie from backend.".to_string()) }; let essence = trie_backend.essence(); - let (nb_to_migrate, trie) = count_migrate(essence, &essence.root())?; + let (nb_to_migrate, trie) = count_migrate(essence, essence.root())?; let mut nb_to_migrate_child = 0; let mut child_roots: Vec<(ChildInfo, Vec)> = Vec::new(); diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index b1a56f7e8f8eb..12c36955c26cd 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -76,12 +76,12 @@ impl ExecuteBlockCmd { ::Err: Debug, { match (&self.block_at, &self.state) { - (Some(block_at), State::Snap { .. }) => hash_of::(&block_at), + (Some(block_at), State::Snap { .. }) => hash_of::(block_at), (Some(block_at), State::Live { .. }) => { log::warn!(target: LOG_TARGET, "--block-at is provided while state type is live. the `Live::at` will be ignored"); - hash_of::(&block_at) + hash_of::(block_at) }, - (None, State::Live { at: Some(at), .. }) => hash_of::(&at), + (None, State::Live { at: Some(at), .. }) => hash_of::(at), _ => { panic!("either `--block-at` must be provided, or state must be `live with a proper `--at``"); }, diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index db305fa590760..e2e6bd7244945 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -31,8 +31,8 @@ use sp_core::H256; use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; use std::{fmt::Debug, str::FromStr}; -const SUB: &'static str = "chain_subscribeFinalizedHeads"; -const UN_SUB: &'static str = "chain_unsubscribeFinalizedHeads"; +const SUB: &str = "chain_subscribeFinalizedHeads"; +const UN_SUB: &str = "chain_unsubscribeFinalizedHeads"; /// Configurations of the [`Command::FollowChain`]. #[derive(Debug, Clone, clap::Parser)] @@ -68,7 +68,7 @@ where log::info!(target: LOG_TARGET, "subscribing to {:?} / {:?}", SUB, UN_SUB); let mut subscription: Subscription = - client.subscribe(&SUB, None, &UN_SUB).await.unwrap(); + client.subscribe(SUB, None, UN_SUB).await.unwrap(); let (code_key, code) = extract_code(&config.chain_spec)?; let executor = build_executor::(&shared, &config); @@ -104,7 +104,7 @@ where if maybe_state_ext.is_none() { let builder = Builder::::new().mode(Mode::Online(OnlineConfig { transport: command.uri.clone().into(), - at: Some(header.parent_hash().clone()), + at: Some(*header.parent_hash()), ..Default::default() })); @@ -136,7 +136,7 @@ where maybe_state_ext.as_mut().expect("state_ext either existed or was just created"); let (mut changes, encoded_result) = state_machine_call_with_proof::( - &state_ext, + state_ext, &executor, execution, "TryRuntime_execute_block_no_check", diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index 72136e9236de5..9aad901829772 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -68,12 +68,12 @@ impl OffchainWorkerCmd { ::Err: Debug, { match (&self.header_at, &self.state) { - (Some(header_at), State::Snap { .. }) => hash_of::(&header_at), + (Some(header_at), State::Snap { .. }) => hash_of::(header_at), (Some(header_at), State::Live { .. }) => { log::error!(target: LOG_TARGET, "--header-at is provided while state type is live, this will most likely lead to a nonsensical result."); - hash_of::(&header_at) + hash_of::(header_at) }, - (None, State::Live { at: Some(at), .. }) => hash_of::(&at), + (None, State::Live { at: Some(at), .. }) => hash_of::(at), _ => { panic!("either `--header-at` must be provided, or state must be `live` with a proper `--at`"); }, diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index a9047259838cf..c13bbb3626176 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -296,7 +296,7 @@ use std::{fmt::Debug, path::PathBuf, str::FromStr}; mod commands; pub(crate) mod parse; -pub(crate) const LOG_TARGET: &'static str = "try-runtime::cli"; +pub(crate) const LOG_TARGET: &str = "try-runtime::cli"; /// Possible commands of `try-runtime`. #[derive(Debug, Clone, clap::Subcommand)] @@ -738,7 +738,7 @@ pub(crate) fn state_machine_call_with_proof( executor: &NativeElseWasmExecutor, ) -> (String, u32, sp_core::storage::StateVersion) { let (_, encoded) = state_machine_call::( - &ext, - &executor, + ext, + executor, sc_cli::ExecutionStrategy::NativeElseWasm, "Core_version", &[], diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index e94703b610a48..005b428a3ccac 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -359,10 +359,11 @@ fn project_enabled_features( // this heuristic anymore. However, for the transition phase between now and namespaced // features already being present in nightly, we need this code to make // runtimes compile with all the possible rustc versions. - if v.len() == 1 && v.get(0).map_or(false, |v| *v == format!("dep:{}", f)) { - if std_enabled.as_ref().map(|e| e.iter().any(|ef| ef == *f)).unwrap_or(false) { - return false - } + if v.len() == 1 && + v.get(0).map_or(false, |v| *v == format!("dep:{}", f)) && + std_enabled.as_ref().map(|e| e.iter().any(|ef| ef == *f)).unwrap_or(false) + { + return false } // We don't want to enable the `std`/`default` feature for the wasm build and @@ -409,7 +410,7 @@ fn create_project( fs::create_dir_all(wasm_project_folder.join("src")) .expect("Wasm project dir create can not fail; qed"); - let mut enabled_features = project_enabled_features(&project_cargo_toml, &crate_metadata); + let mut enabled_features = project_enabled_features(project_cargo_toml, crate_metadata); if has_runtime_wasm_feature_declared(project_cargo_toml, crate_metadata) { enabled_features.push("runtime-wasm".into()); @@ -422,7 +423,7 @@ fn create_project( &wasm_project_folder, workspace_root_path, &crate_name, - &crate_path, + crate_path, &wasm_binary, enabled_features.into_iter(), ); @@ -788,7 +789,7 @@ fn package_rerun_if_changed(package: &DeduplicatePackage) { .filter(|p| { p.is_dir() || p.extension().map(|e| e == "rs" || e == "toml").unwrap_or_default() }) - .for_each(|p| rerun_if_changed(p)); + .for_each(rerun_if_changed); } /// Copy the WASM binary to the target directory set in `WASM_TARGET_DIRECTORY` environment From fa778cc1187e37bbab132293ddbbb20158139ea5 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sat, 30 Apr 2022 23:49:57 +0200 Subject: [PATCH 0749/1472] add missing features to node-template-runtime (#11326) --- bin/node-template/runtime/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index f4ff877290822..43dc98f254651 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -91,6 +91,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "hex-literal", "pallet-balances/runtime-benchmarks", + "pallet-grandpa/runtime-benchmarks", "pallet-template/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -99,10 +100,12 @@ try-runtime = [ "frame-executive/try-runtime", "frame-try-runtime", "frame-system/try-runtime", + "pallet-aura/try-runtime", "pallet-balances/try-runtime", "pallet-grandpa/try-runtime", "pallet-randomness-collective-flip/try-runtime", "pallet-sudo/try-runtime", + "pallet-template/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", ] From 75ae73b5ba0703f946bdd2cd1da7fa3b43474434 Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Mon, 2 May 2022 19:23:53 +0900 Subject: [PATCH 0750/1472] Uniques: fix typo in README.md (#11329) existance -> existence --- frame/uniques/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/uniques/README.md b/frame/uniques/README.md index 8d6859d55e23c..09f9d346895a6 100644 --- a/frame/uniques/README.md +++ b/frame/uniques/README.md @@ -20,7 +20,7 @@ The supported dispatchable functions are documented in the [`uniques::Call`](htt * **Asset transfer:** The action of transferring an asset instance from one account to another. * **Asset burning:** The destruction of an asset instance. * **Non-fungible asset:** An asset for which each unit has unique characteristics. There is exactly - one instance of such an asset in existance and there is exactly one owning account. + one instance of such an asset in existence and there is exactly one owning account. ### Goals From 3eac88e5d81781e6b837d704ce8b10a1d5245fcc Mon Sep 17 00:00:00 2001 From: Roy Yang Date: Tue, 3 May 2022 10:17:14 +1200 Subject: [PATCH 0751/1472] Added RuntimeDebug derive to enums in frame_support::tokens::misc (#11211) Co-authored-by: Roy Yang --- frame/support/src/traits/tokens/misc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index 86304b14a33f6..dd87fe36cd019 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -24,7 +24,7 @@ use sp_runtime::{ArithmeticError, DispatchError, TokenError}; use sp_std::fmt::Debug; /// One of a number of consequences of withdrawing a fungible from an account. -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)] pub enum WithdrawConsequence { /// Withdraw could not happen since the amount to be withdrawn is less than the total funds in /// the account. @@ -69,7 +69,7 @@ impl WithdrawConsequence { } /// One of a number of consequences of withdrawing a fungible from an account. -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)] pub enum DepositConsequence { /// Deposit couldn't happen due to the amount being too low. This is usually because the /// account doesn't yet exist and the deposit wouldn't bring it to at least the minimum needed @@ -104,7 +104,7 @@ impl DepositConsequence { } /// Simple boolean for whether an account needs to be kept in existence. -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)] pub enum ExistenceRequirement { /// Operation must not result in the account going out of existence. /// From cb85edb387505ee3de0628aec0d1e549304cdcd0 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Tue, 3 May 2022 18:23:37 +0800 Subject: [PATCH 0752/1472] sc-network: update cid v0.6.0 => v0.8.4 (#11325) Signed-off-by: koushiro --- Cargo.lock | 155 +++++++++++++------------------------- client/network/Cargo.toml | 13 +--- 2 files changed, 58 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a5ef8e09ae7b..ac1c66fdff68a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -352,19 +352,6 @@ dependencies = [ "syn", ] -[[package]] -name = "asynchronous-codec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4401f0a3622dad2e0763fa79e0eb328bc70fb7dccfdd645341f00d671247d6" -dependencies = [ - "bytes 1.1.0", - "futures-sink", - "futures-util", - "memchr", - "pin-project-lite 0.2.6", -] - [[package]] name = "asynchronous-codec" version = "0.6.0" @@ -660,30 +647,39 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "blake2b_simd" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" +dependencies = [ + "arrayref", + "arrayvec 0.7.1", + "constant_time_eq", +] + [[package]] name = "blake2s_simd" -version = "0.5.11" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" +checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" dependencies = [ "arrayref", - "arrayvec 0.5.2", + "arrayvec 0.7.1", "constant_time_eq", ] [[package]] name = "blake3" -version = "0.3.7" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9ff35b701f3914bdb8fad3368d822c766ef2858b2583198e41639b936f09d3f" +checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" dependencies = [ "arrayref", - "arrayvec 0.5.2", + "arrayvec 0.7.1", "cc", - "cfg-if 0.1.10", + "cfg-if 1.0.0", "constant_time_eq", - "crypto-mac 0.8.0", - "digest 0.9.0", ] [[package]] @@ -975,13 +971,15 @@ dependencies = [ [[package]] name = "cid" -version = "0.6.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff0e3bc0b6446b3f9663c1a6aba6ef06c5aeaa1bc92bd18077be337198ab9768" +checksum = "a52cffa791ce5cf490ac3b2d6df970dc04f931b04e727be3c3e220e17164dfc4" dependencies = [ + "core2", "multibase", - "multihash 0.13.2", - "unsigned-varint 0.5.1", + "multihash", + "serde", + "unsigned-varint", ] [[package]] @@ -3771,7 +3769,7 @@ dependencies = [ "libsecp256k1", "log 0.4.16", "multiaddr", - "multihash 0.16.2", + "multihash", "multistream-select", "parking_lot 0.12.0", "pin-project 1.0.10", @@ -3783,7 +3781,7 @@ dependencies = [ "sha2 0.10.2", "smallvec 1.8.0", "thiserror", - "unsigned-varint 0.7.1", + "unsigned-varint", "void", "zeroize", ] @@ -3837,7 +3835,7 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a90c989a7c0969c2ab63e898da9bc735e3be53fb4f376e9c045ce516bcc9f928" dependencies = [ - "asynchronous-codec 0.6.0", + "asynchronous-codec", "base64 0.13.0", "byteorder", "bytes 1.1.0", @@ -3855,7 +3853,7 @@ dependencies = [ "regex", "sha2 0.10.2", "smallvec 1.8.0", - "unsigned-varint 0.7.1", + "unsigned-varint", "wasm-timer", ] @@ -3883,7 +3881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "564e6bd64d177446399ed835b9451a8825b07929d6daa6a94e6405592974725e" dependencies = [ "arrayvec 0.5.2", - "asynchronous-codec 0.6.0", + "asynchronous-codec", "bytes 1.1.0", "either", "fnv", @@ -3900,7 +3898,7 @@ dependencies = [ "smallvec 1.8.0", "thiserror", "uint", - "unsigned-varint 0.7.1", + "unsigned-varint", "void", ] @@ -3947,7 +3945,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "442eb0c9fff0bf22a34f015724b4143ce01877e079ed0963c722d94c07c72160" dependencies = [ - "asynchronous-codec 0.6.0", + "asynchronous-codec", "bytes 1.1.0", "futures 0.3.21", "libp2p-core", @@ -3956,7 +3954,7 @@ dependencies = [ "parking_lot 0.12.0", "rand 0.7.3", "smallvec 1.8.0", - "unsigned-varint 0.7.1", + "unsigned-varint", ] [[package]] @@ -4003,14 +4001,14 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "962c0fb0e7212fb96a69b87f2d09bcefd317935239bdc79cda900e7a8897a3fe" dependencies = [ - "asynchronous-codec 0.6.0", + "asynchronous-codec", "bytes 1.1.0", "futures 0.3.21", "libp2p-core", "log 0.4.16", "prost", "prost-build", - "unsigned-varint 0.7.1", + "unsigned-varint", "void", ] @@ -4034,7 +4032,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3aa754cb7bccef51ebc3c458c6bbcef89d83b578a9925438389be841527d408f" dependencies = [ - "asynchronous-codec 0.6.0", + "asynchronous-codec", "bytes 1.1.0", "either", "futures 0.3.21", @@ -4050,7 +4048,7 @@ dependencies = [ "smallvec 1.8.0", "static_assertions", "thiserror", - "unsigned-varint 0.7.1", + "unsigned-varint", "void", ] @@ -4060,7 +4058,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd0baab894c5b84da510b915d53264d566c3c35889f09931fe9edbd2a773bee" dependencies = [ - "asynchronous-codec 0.6.0", + "asynchronous-codec", "bimap", "futures 0.3.21", "futures-timer", @@ -4073,7 +4071,7 @@ dependencies = [ "rand 0.8.4", "sha2 0.10.2", "thiserror", - "unsigned-varint 0.7.1", + "unsigned-varint", "void", ] @@ -4092,7 +4090,7 @@ dependencies = [ "log 0.4.16", "rand 0.7.3", "smallvec 1.8.0", - "unsigned-varint 0.7.1", + "unsigned-varint", ] [[package]] @@ -4649,67 +4647,40 @@ dependencies = [ "bs58", "byteorder", "data-encoding", - "multihash 0.16.2", + "multihash", "percent-encoding 2.1.0", "serde", "static_assertions", - "unsigned-varint 0.7.1", + "unsigned-varint", "url 2.2.1", ] [[package]] name = "multibase" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b78c60039650ff12e140ae867ef5299a58e19dded4d334c849dc7177083667e2" +checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" dependencies = [ "base-x", "data-encoding", "data-encoding-macro", ] -[[package]] -name = "multihash" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dac63698b887d2d929306ea48b63760431ff8a24fac40ddb22f9c7f49fb7cab" -dependencies = [ - "blake2b_simd", - "blake2s_simd", - "blake3", - "digest 0.9.0", - "generic-array 0.14.4", - "multihash-derive 0.7.2", - "sha2 0.9.8", - "sha3 0.9.1", - "unsigned-varint 0.5.1", -] - [[package]] name = "multihash" version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3db354f401db558759dfc1e568d010a5d4146f4d3f637be1275ec4a3cf09689" dependencies = [ + "blake2b_simd 1.0.0", + "blake2s_simd", + "blake3", "core2", "digest 0.10.3", - "multihash-derive 0.8.0", + "multihash-derive", "sha2 0.10.2", - "unsigned-varint 0.7.1", -] - -[[package]] -name = "multihash-derive" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99" -dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", - "synstructure", + "sha3 0.10.0", + "unsigned-varint", ] [[package]] @@ -4743,7 +4714,7 @@ dependencies = [ "log 0.4.16", "pin-project 1.0.10", "smallvec 1.8.0", - "unsigned-varint 0.7.1", + "unsigned-varint", ] [[package]] @@ -8141,7 +8112,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" dependencies = [ "base64 0.13.0", - "blake2b_simd", + "blake2b_simd 0.5.11", "constant_time_eq", "crossbeam-utils 0.8.5", ] @@ -8974,7 +8945,7 @@ dependencies = [ "assert_matches", "async-std", "async-trait", - "asynchronous-codec 0.5.0", + "asynchronous-codec", "bitflags", "bytes 1.1.0", "cid", @@ -9018,7 +8989,7 @@ dependencies = [ "substrate-test-runtime-client", "tempfile", "thiserror", - "unsigned-varint 0.6.0", + "unsigned-varint", "void", "zeroize", ] @@ -11933,31 +11904,13 @@ dependencies = [ "subtle", ] -[[package]] -name = "unsigned-varint" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fdeedbf205afadfe39ae559b75c3240f24e257d0ca27e85f85cb82aa19ac35" - -[[package]] -name = "unsigned-varint" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35581ff83d4101e58b582e607120c7f5ffb17e632a980b1f38334d76b36908b2" -dependencies = [ - "asynchronous-codec 0.5.0", - "bytes 1.1.0", - "futures-io", - "futures-util", -] - [[package]] name = "unsigned-varint" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836" dependencies = [ - "asynchronous-codec 0.6.0", + "asynchronous-codec", "bytes 1.1.0", "futures-io", "futures-util", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 93b389d4361c1..f3983173575ce 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -19,17 +19,15 @@ prost-build = "0.9" [dependencies] async-trait = "0.1" bitflags = "1.3.2" -cid = "0.6.0" +cid = "0.8.4" bytes = "1" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ - "derive", -] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } either = "1.5.3" fnv = "1.0.6" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } futures = "0.3.21" futures-timer = "3.0.2" -asynchronous-codec = "0.5" +asynchronous-codec = "0.6" hex = "0.4.0" ip_network = "0.4.1" linked-hash-map = "0.5.4" @@ -56,10 +54,7 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } thiserror = "1.0" -unsigned-varint = { version = "0.6.0", features = [ - "futures", - "asynchronous_codec", -] } +unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } void = "1.0.2" zeroize = "1.4.3" libp2p = "0.44.0" From 6f678f245753fcff08eb818208a3c88eedb88522 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 May 2022 13:05:45 +0200 Subject: [PATCH 0753/1472] Bump parity-db from 0.3.9 to 0.3.12 (#11340) Bumps [parity-db](https://github.com/paritytech/parity-db) from 0.3.9 to 0.3.12. - [Release notes](https://github.com/paritytech/parity-db/releases) - [Commits](https://github.com/paritytech/parity-db/commits/v0.3.12) --- updated-dependencies: - dependency-name: parity-db 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/db/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac1c66fdff68a..77d9463cbd9b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6832,9 +6832,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d121a9af17a43efd0a38c6afa508b927ba07785bd4709efb2ac03bf77efef8d" +checksum = "6e73cd0b0a78045276b19eaae8eaaa20e44a1da9a0217ff934a810d9492ae701" dependencies = [ "blake2-rfc", "crc32fast", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 071e7aa78ddac..9b6faaafbdb62 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -33,7 +33,7 @@ sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-trie = { version = "6.0.0", path = "../../primitives/trie" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -parity-db = { version = "0.3.9", optional = true } +parity-db = { version = "0.3.12", optional = true } [dev-dependencies] sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } From c2fc4b3ca0d7a15cc3f9cb1e5f441d99ec8d6e0b Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Tue, 3 May 2022 16:55:26 +0300 Subject: [PATCH 0754/1472] Network sync refactoring (part 2) (#11322) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move `api.v1.proto` schema into new crate `sc-network-sync` * Move `sc_network::protocol::sync::state` module into `sc_network_sync::state` * Move `sc_network::protocol::sync::blocks` module into `sc_network_sync::blocks` and some data structures from `sc_network::protocol::message` module into `sc_network_sync::message` * Move some data structures from `sc_network::config` and `sc_network::request_responses` into new `sc-network-common` crate * Move `sc_network::protocol::sync::warm` and `sc_network::warp_request_handler` modules into `sc_network_sync` * Move `client/network/sync/src/lib.rs` to `client/network/sync/src/lib_old.rs` to preserve history of changes of the file in the next commit * Move `client/network/src/protocol/sync.rs` on top of `client/network/sync/src/lib.rs` to preserve history of changes * Move `sc_network::protocol::sync` to `sc_network_sync` with submodules, move message data structures around accordingly * Move `sc_network::block_request_handler` to `sc_network_sync::block_request_handler` * Move `sc_network::state_request_handler` to `sc_network_sync::state_request_handler` * Add re-exports for compatibility reasons * Apply suggestions from code review Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- Cargo.lock | 49 ++++ Cargo.toml | 2 + client/network/Cargo.toml | 3 +- client/network/build.rs | 3 +- client/network/common/Cargo.toml | 26 ++ client/network/common/src/config.rs | 44 ++++ client/network/common/src/lib.rs | 23 ++ client/network/common/src/message.rs | 23 ++ .../network/common/src/request_responses.rs | 114 +++++++++ client/network/src/behaviour.rs | 12 +- client/network/src/config.rs | 41 +--- client/network/src/discovery.rs | 5 +- client/network/src/lib.rs | 15 +- client/network/src/light_client_requests.rs | 2 +- .../src/light_client_requests/handler.rs | 12 +- client/network/src/protocol.rs | 139 +++++------ client/network/src/protocol/message.rs | 222 ++---------------- client/network/src/request_responses.rs | 91 +------ client/network/src/schema.rs | 1 - client/network/src/service.rs | 8 +- client/network/src/service/tests.rs | 7 +- client/network/src/transactions.rs | 3 +- client/network/sync/Cargo.toml | 49 ++++ client/network/sync/build.rs | 5 + .../{ => sync}/src/block_request_handler.rs | 12 +- .../{src/protocol/sync => sync/src}/blocks.rs | 5 +- .../sync => sync/src}/extra_requests.rs | 16 +- .../{src/protocol/sync.rs => sync/src/lib.rs} | 56 ++--- client/network/sync/src/message.rs | 222 ++++++++++++++++++ client/network/sync/src/schema.rs | 23 ++ .../{ => sync}/src/schema/api.v1.proto | 0 .../{src/protocol/sync => sync/src}/state.rs | 4 +- .../{ => sync}/src/state_request_handler.rs | 14 +- .../{src/protocol/sync => sync/src}/warp.rs | 23 +- .../{ => sync}/src/warp_request_handler.rs | 7 +- client/network/test/Cargo.toml | 1 + client/network/test/src/lib.rs | 3 +- client/service/Cargo.toml | 1 + client/service/src/config.rs | 15 +- 39 files changed, 806 insertions(+), 495 deletions(-) create mode 100644 client/network/common/Cargo.toml create mode 100644 client/network/common/src/config.rs create mode 100644 client/network/common/src/lib.rs create mode 100644 client/network/common/src/message.rs create mode 100644 client/network/common/src/request_responses.rs create mode 100644 client/network/sync/Cargo.toml create mode 100644 client/network/sync/build.rs rename client/network/{ => sync}/src/block_request_handler.rs (99%) rename client/network/{src/protocol/sync => sync/src}/blocks.rs (99%) rename client/network/{src/protocol/sync => sync/src}/extra_requests.rs (98%) rename client/network/{src/protocol/sync.rs => sync/src/lib.rs} (98%) create mode 100644 client/network/sync/src/message.rs create mode 100644 client/network/sync/src/schema.rs rename client/network/{ => sync}/src/schema/api.v1.proto (100%) rename client/network/{src/protocol/sync => sync/src}/state.rs (99%) rename client/network/{ => sync}/src/state_request_handler.rs (97%) rename client/network/{src/protocol/sync => sync/src}/warp.rs (90%) rename client/network/{ => sync}/src/warp_request_handler.rs (97%) diff --git a/Cargo.lock b/Cargo.lock index 77d9463cbd9b8..00d45f10288a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8971,6 +8971,8 @@ dependencies = [ "sc-block-builder", "sc-client-api", "sc-consensus", + "sc-network-common", + "sc-network-sync", "sc-peerset", "sc-utils", "serde", @@ -8994,6 +8996,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "sc-network-common" +version = "0.10.0-dev" +dependencies = [ + "futures 0.3.21", + "libp2p", + "parity-scale-codec", + "prost-build", + "sc-peerset", + "smallvec 1.8.0", +] + [[package]] name = "sc-network-gossip" version = "0.10.0-dev" @@ -9013,6 +9027,39 @@ dependencies = [ "tracing", ] +[[package]] +name = "sc-network-sync" +version = "0.10.0-dev" +dependencies = [ + "bitflags", + "either", + "fork-tree", + "futures 0.3.21", + "libp2p", + "log 0.4.16", + "lru", + "parity-scale-codec", + "prost", + "prost-build", + "quickcheck", + "sc-block-builder", + "sc-client-api", + "sc-consensus", + "sc-network-common", + "sc-peerset", + "smallvec 1.8.0", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-finality-grandpa", + "sp-runtime", + "sp-test-primitives", + "sp-tracing", + "substrate-test-runtime-client", + "thiserror", +] + [[package]] name = "sc-network-test" version = "0.8.0" @@ -9029,6 +9076,7 @@ dependencies = [ "sc-client-api", "sc-consensus", "sc-network", + "sc-network-common", "sc-service", "sp-blockchain", "sp-consensus", @@ -9217,6 +9265,7 @@ dependencies = [ "sc-informant", "sc-keystore", "sc-network", + "sc-network-common", "sc-offchain", "sc-rpc", "sc-rpc-server", diff --git a/Cargo.toml b/Cargo.toml index f91e6226ccfd0..39ccceeb3a030 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,9 @@ members = [ "client/informant", "client/keystore", "client/network", + "client/network/common", "client/network-gossip", + "client/network/sync", "client/network/test", "client/offchain", "client/peerset", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index f3983173575ce..a8a1fc05bb365 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -51,6 +51,8 @@ sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/comm sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sc-network-common = { version = "0.10.0-dev", path = "./common" } +sc-network-sync = { version = "0.10.0-dev", path = "./sync" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } thiserror = "1.0" @@ -61,7 +63,6 @@ libp2p = "0.44.0" [dev-dependencies] assert_matches = "1.3" -libp2p = { version = "0.44.0", default-features = false } quickcheck = "1.0.3" rand = "0.7.2" sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } diff --git a/client/network/build.rs b/client/network/build.rs index 6e5b83d4e58ae..f551f61dab3d4 100644 --- a/client/network/build.rs +++ b/client/network/build.rs @@ -1,5 +1,4 @@ -const PROTOS: &[&str] = - &["src/schema/api.v1.proto", "src/schema/light.v1.proto", "src/schema/bitswap.v1.2.0.proto"]; +const PROTOS: &[&str] = &["src/schema/light.v1.proto", "src/schema/bitswap.v1.2.0.proto"]; fn main() { prost_build::compile_protos(PROTOS, &["src/schema"]).unwrap(); diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml new file mode 100644 index 0000000000000..5e3150ee9bc82 --- /dev/null +++ b/client/network/common/Cargo.toml @@ -0,0 +1,26 @@ +[package] +description = "Substrate network common" +name = "sc-network-common" +version = "0.10.0-dev" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +documentation = "https://docs.rs/sc-network-sync" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +prost-build = "0.9" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ + "derive", +] } +futures = "0.3.21" +libp2p = "0.44.0" +sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } +smallvec = "1.8.0" diff --git a/client/network/common/src/config.rs b/client/network/common/src/config.rs new file mode 100644 index 0000000000000..92f8df5cd380f --- /dev/null +++ b/client/network/common/src/config.rs @@ -0,0 +1,44 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Configuration of the networking layer. + +use std::{fmt, str}; + +/// Name of a protocol, transmitted on the wire. Should be unique for each chain. Always UTF-8. +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct ProtocolId(smallvec::SmallVec<[u8; 6]>); + +impl<'a> From<&'a str> for ProtocolId { + fn from(bytes: &'a str) -> ProtocolId { + Self(bytes.as_bytes().into()) + } +} + +impl AsRef for ProtocolId { + fn as_ref(&self) -> &str { + str::from_utf8(&self.0[..]) + .expect("the only way to build a ProtocolId is through a UTF-8 String; qed") + } +} + +impl fmt::Debug for ProtocolId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_ref(), f) + } +} diff --git a/client/network/common/src/lib.rs b/client/network/common/src/lib.rs new file mode 100644 index 0000000000000..81769e23debbb --- /dev/null +++ b/client/network/common/src/lib.rs @@ -0,0 +1,23 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Common data structures of the networking layer. + +pub mod config; +pub mod message; +pub mod request_responses; diff --git a/client/network/common/src/message.rs b/client/network/common/src/message.rs new file mode 100644 index 0000000000000..930fe5ca52847 --- /dev/null +++ b/client/network/common/src/message.rs @@ -0,0 +1,23 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Network packet message types. These get serialized and put into the lower level protocol +//! payload. + +/// A unique ID of a request. +pub type RequestId = u64; diff --git a/client/network/common/src/request_responses.rs b/client/network/common/src/request_responses.rs new file mode 100644 index 0000000000000..71570e6beb864 --- /dev/null +++ b/client/network/common/src/request_responses.rs @@ -0,0 +1,114 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Collection of generic data structures for request-response protocols. + +use futures::channel::{mpsc, oneshot}; +use libp2p::PeerId; +use sc_peerset::ReputationChange; +use std::{borrow::Cow, time::Duration}; + +/// Configuration for a single request-response protocol. +#[derive(Debug, Clone)] +pub struct ProtocolConfig { + /// Name of the protocol on the wire. Should be something like `/foo/bar`. + pub name: Cow<'static, str>, + + /// Maximum allowed size, in bytes, of a request. + /// + /// Any request larger than this value will be declined as a way to avoid allocating too + /// much memory for it. + pub max_request_size: u64, + + /// Maximum allowed size, in bytes, of a response. + /// + /// Any response larger than this value will be declined as a way to avoid allocating too + /// much memory for it. + pub max_response_size: u64, + + /// Duration after which emitted requests are considered timed out. + /// + /// If you expect the response to come back quickly, you should set this to a smaller duration. + pub request_timeout: Duration, + + /// Channel on which the networking service will send incoming requests. + /// + /// Every time a peer sends a request to the local node using this protocol, the networking + /// service will push an element on this channel. The receiving side of this channel then has + /// to pull this element, process the request, and send back the response to send back to the + /// peer. + /// + /// The size of the channel has to be carefully chosen. If the channel is full, the networking + /// service will discard the incoming request send back an error to the peer. Consequently, + /// the channel being full is an indicator that the node is overloaded. + /// + /// You can typically set the size of the channel to `T / d`, where `T` is the + /// `request_timeout` and `d` is the expected average duration of CPU and I/O it takes to + /// build a response. + /// + /// Can be `None` if the local node does not support answering incoming requests. + /// If this is `None`, then the local node will not advertise support for this protocol towards + /// other peers. If this is `Some` but the channel is closed, then the local node will + /// advertise support for this protocol, but any incoming request will lead to an error being + /// sent back. + pub inbound_queue: Option>, +} + +/// A single request received by a peer on a request-response protocol. +#[derive(Debug)] +pub struct IncomingRequest { + /// Who sent the request. + pub peer: PeerId, + + /// Request sent by the remote. Will always be smaller than + /// [`ProtocolConfig::max_request_size`]. + pub payload: Vec, + + /// Channel to send back the response. + /// + /// There are two ways to indicate that handling the request failed: + /// + /// 1. Drop `pending_response` and thus not changing the reputation of the peer. + /// + /// 2. Sending an `Err(())` via `pending_response`, optionally including reputation changes for + /// the given peer. + pub pending_response: oneshot::Sender, +} + +/// Response for an incoming request to be send by a request protocol handler. +#[derive(Debug)] +pub struct OutgoingResponse { + /// The payload of the response. + /// + /// `Err(())` if none is available e.g. due an error while handling the request. + pub result: Result, ()>, + + /// Reputation changes accrued while handling the request. To be applied to the reputation of + /// the peer sending the request. + pub reputation_changes: Vec, + + /// If provided, the `oneshot::Sender` will be notified when the request has been sent to the + /// peer. + /// + /// > **Note**: Operating systems typically maintain a buffer of a few dozen kilobytes of + /// > outgoing data for each TCP socket, and it is not possible for a user + /// > application to inspect this buffer. This channel here is not actually notified + /// > when the response has been fully sent out, but rather when it has fully been + /// > written to the buffer managed by the operating system. + pub sent_feedback: Option>, +} diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index b0bf3d6a1c135..091dd116e4c9c 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -18,7 +18,6 @@ use crate::{ bitswap::Bitswap, - config::ProtocolId, discovery::{DiscoveryBehaviour, DiscoveryConfig, DiscoveryOut}, peer_info, protocol::{message::Roles, CustomMessageOutcome, NotificationsSink, Protocol}, @@ -42,6 +41,7 @@ use log::debug; use prost::Message; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::import_queue::{IncomingBlock, Origin}; +use sc_network_common::{config::ProtocolId, request_responses::ProtocolConfig}; use sc_peerset::PeersetHandle; use sp_blockchain::{HeaderBackend, HeaderMetadata}; use sp_consensus::BlockOrigin; @@ -220,13 +220,13 @@ where user_agent: String, local_public_key: PublicKey, disco_config: DiscoveryConfig, - block_request_protocol_config: request_responses::ProtocolConfig, - state_request_protocol_config: request_responses::ProtocolConfig, - warp_sync_protocol_config: Option, + block_request_protocol_config: ProtocolConfig, + state_request_protocol_config: ProtocolConfig, + warp_sync_protocol_config: Option, bitswap: Option>, - light_client_request_protocol_config: request_responses::ProtocolConfig, + light_client_request_protocol_config: ProtocolConfig, // All remaining request protocol configs. - mut request_response_protocols: Vec, + mut request_response_protocols: Vec, peerset: PeersetHandle, ) -> Result { // Extract protocol name and add to `request_response_protocols`. diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 2b448ed14eab0..cfb06331b55a1 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -21,12 +21,14 @@ //! The [`Params`] struct is the struct that must be passed in order to initialize the networking. //! See the documentation of [`Params`]. -pub use crate::{ +pub use sc_network_common::{ + config::ProtocolId, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, - warp_request_handler::WarpSyncProvider, }; +pub use sc_network_sync::warp_request_handler::WarpSyncProvider; + pub use libp2p::{build_multiaddr, core::PublicKey, identity}; // Note: this re-export shouldn't be part of the public API of the crate and will be removed in @@ -111,10 +113,10 @@ where /// protocol name. In addition all of [`RequestResponseConfig`] is used to handle incoming /// block requests, if enabled. /// - /// Can be constructed either via [`crate::block_request_handler::generate_protocol_config`] - /// allowing outgoing but not incoming requests, or constructed via - /// [`crate::block_request_handler::BlockRequestHandler::new`] allowing both outgoing and - /// incoming requests. + /// Can be constructed either via + /// [`sc_network_sync::block_request_handler::generate_protocol_config`] allowing outgoing but + /// not incoming requests, or constructed via [`sc_network_sync::block_request_handler:: + /// BlockRequestHandler::new`] allowing both outgoing and incoming requests. pub block_request_protocol_config: RequestResponseConfig, /// Request response configuration for the light client request protocol. @@ -129,8 +131,8 @@ where /// Request response configuration for the state request protocol. /// /// Can be constructed either via - /// [`crate::block_request_handler::generate_protocol_config`] allowing outgoing but not - /// incoming requests, or constructed via + /// [`sc_network_sync::block_request_handler::generate_protocol_config`] allowing outgoing but + /// not incoming requests, or constructed via /// [`crate::state_request_handler::StateRequestHandler::new`] allowing /// both outgoing and incoming requests. pub state_request_protocol_config: RequestResponseConfig, @@ -232,29 +234,6 @@ impl TransactionPool for EmptyTransaction } } -/// Name of a protocol, transmitted on the wire. Should be unique for each chain. Always UTF-8. -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct ProtocolId(smallvec::SmallVec<[u8; 6]>); - -impl<'a> From<&'a str> for ProtocolId { - fn from(bytes: &'a str) -> ProtocolId { - Self(bytes.as_bytes().into()) - } -} - -impl AsRef for ProtocolId { - fn as_ref(&self) -> &str { - str::from_utf8(&self.0[..]) - .expect("the only way to build a ProtocolId is through a UTF-8 String; qed") - } -} - -impl fmt::Debug for ProtocolId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.as_ref(), f) - } -} - /// Parses a string address and splits it into Multiaddress and PeerId, if /// valid. /// diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index ae65d4f23cec7..2bae2fb807f7e 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -46,7 +46,7 @@ //! active mechanism that asks nodes for the addresses they are listening on. Whenever we learn //! of a node's address, you must call `add_self_reported_address`. -use crate::{config::ProtocolId, utils::LruHashSet}; +use crate::utils::LruHashSet; use futures::prelude::*; use futures_timer::Delay; use ip_network::IpNetwork; @@ -72,6 +72,7 @@ use libp2p::{ }, }; use log::{debug, error, info, trace, warn}; +use sc_network_common::config::ProtocolId; use sp_core::hexdisplay::HexDisplay; use std::{ cmp, @@ -1001,7 +1002,6 @@ impl MdnsWrapper { #[cfg(test)] mod tests { use super::{protocol_name_from_protocol_id, DiscoveryConfig, DiscoveryOut}; - use crate::config::ProtocolId; use futures::prelude::*; use libp2p::{ core::{ @@ -1013,6 +1013,7 @@ mod tests { swarm::{Swarm, SwarmEvent}, yamux, Multiaddr, PeerId, }; + use sc_network_common::config::ProtocolId; use std::{collections::HashSet, task::Poll}; #[test] diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 973e0b15b7509..3957aab22cca9 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -255,22 +255,25 @@ mod transport; mod utils; pub mod bitswap; -pub mod block_request_handler; pub mod config; pub mod error; pub mod light_client_requests; pub mod network_state; -pub mod state_request_handler; pub mod transactions; -pub mod warp_request_handler; #[doc(inline)] pub use libp2p::{multiaddr, Multiaddr, PeerId}; pub use protocol::{ event::{DhtEvent, Event, ObservedRole}, - sync::{StateDownloadProgress, SyncState, WarpSyncPhase, WarpSyncProgress}, PeerInfo, }; +pub use sc_network_sync::{ + block_request_handler, + state::StateDownloadProgress, + state_request_handler, + warp::{WarpSyncPhase, WarpSyncProgress}, + warp_request_handler, SyncState, +}; pub use service::{ DecodingError, IfDisconnected, KademliaKey, Keypair, NetworkService, NetworkWorker, NotificationSender, NotificationSenderReady, OutboundFailure, PublicKey, RequestFailure, @@ -325,7 +328,7 @@ pub struct NetworkStatus { /// The total number of bytes sent. pub total_bytes_outbound: u64, /// State sync in progress. - pub state_sync: Option, + pub state_sync: Option, /// Warp sync in progress. - pub warp_sync: Option>, + pub warp_sync: Option>, } diff --git a/client/network/src/light_client_requests.rs b/client/network/src/light_client_requests.rs index d36158b2a373a..9eccef41e833d 100644 --- a/client/network/src/light_client_requests.rs +++ b/client/network/src/light_client_requests.rs @@ -21,7 +21,7 @@ /// For incoming light client requests. pub mod handler; -use crate::{config::ProtocolId, request_responses::ProtocolConfig}; +use sc_network_common::{config::ProtocolId, request_responses::ProtocolConfig}; use std::time::Duration; diff --git a/client/network/src/light_client_requests/handler.rs b/client/network/src/light_client_requests/handler.rs index cb9bd960767ff..bf65cba5f82e5 100644 --- a/client/network/src/light_client_requests/handler.rs +++ b/client/network/src/light_client_requests/handler.rs @@ -22,16 +22,16 @@ //! `crate::request_responses::RequestResponsesBehaviour` with //! [`LightClientRequestHandler`](handler::LightClientRequestHandler). -use crate::{ - config::ProtocolId, - request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, - schema, PeerId, -}; +use crate::{schema, PeerId}; use codec::{self, Decode, Encode}; use futures::{channel::mpsc, prelude::*}; use log::{debug, trace}; use prost::Message; use sc_client_api::{ProofProvider, StorageProof}; +use sc_network_common::{ + config::ProtocolId, + request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, +}; use sc_peerset::ReputationChange; use sp_core::{ hexdisplay::HexDisplay, @@ -55,7 +55,7 @@ where B: Block, Client: ProofProvider + Send + Sync + 'static, { - /// Create a new [`crate::block_request_handler::BlockRequestHandler`]. + /// Create a new [`sc_network_sync::block_request_handler::BlockRequestHandler`]. pub fn new(protocol_id: &ProtocolId, client: Arc) -> (Self, ProtocolConfig) { // For now due to lack of data on light client request handling in production systems, this // value is chosen to match the block request limit. diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 7214e60172aaa..5db8f102d037b 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -17,12 +17,10 @@ // along with this program. If not, see . use crate::{ - config::{self, ProtocolId, WarpSyncProvider}, - error, + config, error, request_responses::RequestFailure, - schema::v1::StateResponse, utils::{interval, LruHashSet}, - warp_request_handler::EncodedProof, + warp_request_handler::{EncodedProof, WarpSyncProvider}, }; use bytes::Bytes; @@ -43,13 +41,23 @@ use libp2p::{ use log::{debug, error, info, log, trace, warn, Level}; use message::{ generic::{Message as GenericMessage, Roles}, - BlockAnnounce, Message, + Message, }; use notifications::{Notifications, NotificationsOut}; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; use prost::Message as _; use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; use sc_consensus::import_queue::{BlockImportError, BlockImportStatus, IncomingBlock, Origin}; +use sc_network_common::config::ProtocolId; +use sc_network_sync::{ + message::{ + BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, BlockState, + FromBlock, + }, + schema::v1::StateResponse, + BadPeer, ChainSync, OnBlockData, OnBlockJustification, OnStateData, + PollBlockAnnounceValidation, Status as SyncStatus, +}; use sp_arithmetic::traits::SaturatedConversion; use sp_consensus::{block_validation::BlockAnnounceValidator, BlockOrigin}; use sp_runtime::{ @@ -67,13 +75,11 @@ use std::{ task::Poll, time, }; -use sync::{ChainSync, Status as SyncStatus}; mod notifications; pub mod event; pub mod message; -pub mod sync; pub use notifications::{NotificationsSink, NotifsHandlerError, Ready}; use sp_blockchain::HeaderMetadata; @@ -202,7 +208,7 @@ pub struct Protocol { #[derive(Debug)] enum PeerRequest { - Block(message::BlockRequest), + Block(BlockRequest), State, WarpProof, } @@ -240,15 +246,15 @@ pub struct ProtocolConfig { } impl ProtocolConfig { - fn sync_mode(&self) -> sync::SyncMode { + fn sync_mode(&self) -> sc_network_sync::SyncMode { if self.roles.is_light() { - sync::SyncMode::Light + sc_network_sync::SyncMode::Light } else { match self.sync_mode { - config::SyncMode::Full => sync::SyncMode::Full, + config::SyncMode::Full => sc_network_sync::SyncMode::Full, config::SyncMode::Fast { skip_proofs, storage_chain_mode } => - sync::SyncMode::LightState { skip_proofs, storage_chain_mode }, - config::SyncMode::Warp => sync::SyncMode::Warp, + sc_network_sync::SyncMode::LightState { skip_proofs, storage_chain_mode }, + config::SyncMode::Warp => sc_network_sync::SyncMode::Warp, } } } @@ -563,7 +569,7 @@ where fn prepare_block_request( &mut self, who: PeerId, - request: message::BlockRequest, + request: BlockRequest, ) -> CustomMessageOutcome { prepare_block_request::(&mut self.peers, who, request) } @@ -579,9 +585,7 @@ where } if let Some(_peer_data) = self.peers.remove(&peer) { - if let Some(sync::OnBlockData::Import(origin, blocks)) = - self.sync.peer_disconnected(&peer) - { + if let Some(OnBlockData::Import(origin, blocks)) = self.sync.peer_disconnected(&peer) { self.pending_messages .push_back(CustomMessageOutcome::BlockImport(origin, blocks)); } @@ -601,21 +605,21 @@ where pub fn on_block_response( &mut self, peer_id: PeerId, - request: message::BlockRequest, - response: crate::schema::v1::BlockResponse, + request: BlockRequest, + response: sc_network_sync::schema::v1::BlockResponse, ) -> CustomMessageOutcome { let blocks = response .blocks .into_iter() .map(|block_data| { - Ok(message::BlockData:: { + Ok(BlockData:: { hash: Decode::decode(&mut block_data.hash.as_ref())?, header: if !block_data.header.is_empty() { Some(Decode::decode(&mut block_data.header.as_ref())?) } else { None }, - body: if request.fields.contains(message::BlockAttributes::BODY) { + body: if request.fields.contains(BlockAttributes::BODY) { Some( block_data .body @@ -626,8 +630,7 @@ where } else { None }, - indexed_body: if request.fields.contains(message::BlockAttributes::INDEXED_BODY) - { + indexed_body: if request.fields.contains(BlockAttributes::INDEXED_BODY) { Some(block_data.indexed_body) } else { None @@ -667,7 +670,7 @@ where }, }; - let block_response = message::BlockResponse:: { id: request.id, blocks }; + let block_response = BlockResponse:: { id: request.id, blocks }; let blocks_range = || match ( block_response @@ -687,12 +690,12 @@ where blocks_range(), ); - if request.fields == message::BlockAttributes::JUSTIFICATION { + if request.fields == BlockAttributes::JUSTIFICATION { match self.sync.on_block_justification(peer_id, block_response) { - Ok(sync::OnBlockJustification::Nothing) => CustomMessageOutcome::None, - Ok(sync::OnBlockJustification::Import { peer, hash, number, justifications }) => + Ok(OnBlockJustification::Nothing) => CustomMessageOutcome::None, + Ok(OnBlockJustification::Import { peer, hash, number, justifications }) => CustomMessageOutcome::JustificationImport(peer, hash, number, justifications), - Err(sync::BadPeer(id, repu)) => { + Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); CustomMessageOutcome::None @@ -700,10 +703,10 @@ where } } else { match self.sync.on_block_data(&peer_id, Some(request), block_response) { - Ok(sync::OnBlockData::Import(origin, blocks)) => + Ok(OnBlockData::Import(origin, blocks)) => CustomMessageOutcome::BlockImport(origin, blocks), - Ok(sync::OnBlockData::Request(peer, req)) => self.prepare_block_request(peer, req), - Err(sync::BadPeer(id, repu)) => { + Ok(OnBlockData::Request(peer, req)) => self.prepare_block_request(peer, req), + Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); CustomMessageOutcome::None @@ -720,10 +723,10 @@ where response: StateResponse, ) -> CustomMessageOutcome { match self.sync.on_state_data(&peer_id, response) { - Ok(sync::OnStateData::Import(origin, block)) => + Ok(OnStateData::Import(origin, block)) => CustomMessageOutcome::BlockImport(origin, vec![block]), - Ok(sync::OnStateData::Continue) => CustomMessageOutcome::None, - Err(sync::BadPeer(id, repu)) => { + Ok(OnStateData::Continue) => CustomMessageOutcome::None, + Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); CustomMessageOutcome::None @@ -740,7 +743,7 @@ where ) -> CustomMessageOutcome { match self.sync.on_warp_sync_data(&peer_id, response) { Ok(()) => CustomMessageOutcome::None, - Err(sync::BadPeer(id, repu)) => { + Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); CustomMessageOutcome::None @@ -849,7 +852,7 @@ where let req = if peer.info.roles.is_full() { match self.sync.new_peer(who, peer.info.best_hash, peer.info.best_number) { Ok(req) => req, - Err(sync::BadPeer(id, repu)) => { + Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); return Err(()) @@ -906,13 +909,9 @@ where let inserted = peer.known_blocks.insert(hash); if inserted { trace!(target: "sync", "Announcing block {:?} to {}", hash, who); - let message = message::BlockAnnounce { + let message = BlockAnnounce { header: header.clone(), - state: if is_best { - Some(message::BlockState::Best) - } else { - Some(message::BlockState::Normal) - }, + state: if is_best { Some(BlockState::Best) } else { Some(BlockState::Normal) }, data: Some(data.clone()), }; @@ -949,9 +948,9 @@ where peer.known_blocks.insert(hash); - let is_best = match announce.state.unwrap_or(message::BlockState::Best) { - message::BlockState::Best => true, - message::BlockState::Normal => false, + let is_best = match announce.state.unwrap_or(BlockState::Best) { + BlockState::Best => true, + BlockState::Normal => false, }; if peer.info.roles.is_full() { @@ -962,11 +961,11 @@ where /// Process the result of the block announce validation. fn process_block_announce_validation_result( &mut self, - validation_result: sync::PollBlockAnnounceValidation, + validation_result: PollBlockAnnounceValidation, ) -> CustomMessageOutcome { let (header, is_best, who) = match validation_result { - sync::PollBlockAnnounceValidation::Skip => return CustomMessageOutcome::None, - sync::PollBlockAnnounceValidation::Nothing { is_best, who, announce } => { + PollBlockAnnounceValidation::Skip => return CustomMessageOutcome::None, + PollBlockAnnounceValidation::Nothing { is_best, who, announce } => { self.update_peer_info(&who); if let Some(data) = announce.data { @@ -987,7 +986,7 @@ where return CustomMessageOutcome::None } }, - sync::PollBlockAnnounceValidation::ImportHeader { announce, is_best, who } => { + PollBlockAnnounceValidation::ImportHeader { announce, is_best, who } => { self.update_peer_info(&who); if let Some(data) = announce.data { @@ -998,7 +997,7 @@ where (announce.header, is_best, who) }, - sync::PollBlockAnnounceValidation::Failure { who, disconnect } => { + PollBlockAnnounceValidation::Failure { who, disconnect } => { if disconnect { self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); } @@ -1015,9 +1014,9 @@ where let blocks_to_import = self.sync.on_block_data( &who, None, - message::generic::BlockResponse { + BlockResponse:: { id: 0, - blocks: vec![message::generic::BlockData { + blocks: vec![BlockData:: { hash: header.hash(), header: Some(header), body: None, @@ -1035,10 +1034,10 @@ where } match blocks_to_import { - Ok(sync::OnBlockData::Import(origin, blocks)) => + Ok(OnBlockData::Import(origin, blocks)) => CustomMessageOutcome::BlockImport(origin, blocks), - Ok(sync::OnBlockData::Request(peer, req)) => self.prepare_block_request(peer, req), - Err(sync::BadPeer(id, repu)) => { + Ok(OnBlockData::Request(peer, req)) => self.prepare_block_request(peer, req), + Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); CustomMessageOutcome::None @@ -1096,7 +1095,7 @@ where req, )); }, - Err(sync::BadPeer(id, repu)) => { + Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu) }, @@ -1263,7 +1262,7 @@ where fn prepare_block_request( peers: &mut HashMap>, who: PeerId, - request: message::BlockRequest, + request: BlockRequest, ) -> CustomMessageOutcome { let (tx, rx) = oneshot::channel(); @@ -1271,13 +1270,13 @@ fn prepare_block_request( peer.request = Some((PeerRequest::Block(request.clone()), rx)); } - let request = crate::schema::v1::BlockRequest { + let request = sc_network_sync::schema::v1::BlockRequest { fields: request.fields.to_be_u32(), from_block: match request.from { - message::FromBlock::Hash(h) => - Some(crate::schema::v1::block_request::FromBlock::Hash(h.encode())), - message::FromBlock::Number(n) => - Some(crate::schema::v1::block_request::FromBlock::Number(n.encode())), + FromBlock::Hash(h) => + Some(sc_network_sync::schema::v1::block_request::FromBlock::Hash(h.encode())), + FromBlock::Number(n) => + Some(sc_network_sync::schema::v1::block_request::FromBlock::Number(n.encode())), }, to_block: request.to.map(|h| h.encode()).unwrap_or_default(), direction: request.direction as i32, @@ -1291,7 +1290,7 @@ fn prepare_block_request( fn prepare_state_request( peers: &mut HashMap>, who: PeerId, - request: crate::schema::v1::StateRequest, + request: sc_network_sync::schema::v1::StateRequest, ) -> CustomMessageOutcome { let (tx, rx) = oneshot::channel(); @@ -1348,13 +1347,13 @@ pub enum CustomMessageOutcome { /// A new block request must be emitted. BlockRequest { target: PeerId, - request: crate::schema::v1::BlockRequest, + request: sc_network_sync::schema::v1::BlockRequest, pending_response: oneshot::Sender, RequestFailure>>, }, /// A new storage request must be emitted. StateRequest { target: PeerId, - request: crate::schema::v1::StateRequest, + request: sc_network_sync::schema::v1::StateRequest, pending_response: oneshot::Sender, RequestFailure>>, }, /// A new warp sync request must be emitted. @@ -1458,7 +1457,9 @@ where match req { PeerRequest::Block(req) => { let protobuf_response = - match crate::schema::v1::BlockResponse::decode(&resp[..]) { + match sc_network_sync::schema::v1::BlockResponse::decode( + &resp[..], + ) { Ok(proto) => proto, Err(e) => { debug!( @@ -1478,7 +1479,9 @@ where }, PeerRequest::State => { let protobuf_response = - match crate::schema::v1::StateResponse::decode(&resp[..]) { + match sc_network_sync::schema::v1::StateResponse::decode( + &resp[..], + ) { Ok(proto) => proto, Err(e) => { debug!( @@ -1764,7 +1767,7 @@ where }, NotificationsOut::Notification { peer_id, set_id, message } => match set_id { HARDCODED_PEERSETS_SYNC if self.peers.contains_key(&peer_id) => { - if let Ok(announce) = message::BlockAnnounce::decode(&mut message.as_ref()) { + if let Ok(announce) = BlockAnnounce::decode(&mut message.as_ref()) { self.push_block_announce_validation(peer_id, announce); // Make sure that the newly added block announce validation future was diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index f173fff8503a5..a57740ec2746b 100644 --- a/client/network/src/protocol/message.rs +++ b/client/network/src/protocol/message.rs @@ -20,19 +20,13 @@ //! payload. pub use self::generic::{ - BlockAnnounce, FromBlock, RemoteCallRequest, RemoteChangesRequest, RemoteChangesResponse, - RemoteHeaderRequest, RemoteHeaderResponse, RemoteReadChildRequest, RemoteReadRequest, Roles, + RemoteCallRequest, RemoteChangesRequest, RemoteChangesResponse, RemoteHeaderRequest, + RemoteHeaderResponse, RemoteReadChildRequest, RemoteReadRequest, Roles, }; -use bitflags::bitflags; -use codec::{Decode, Encode, Error, Input, Output}; +use codec::{Decode, Encode}; use sc_client_api::StorageProof; -use sp_runtime::{ - traits::{Block as BlockT, Header as HeaderT}, - ConsensusEngineId, -}; - -/// A unique ID of a request. -pub type RequestId = u64; +use sc_network_common::message::RequestId; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; /// Type alias for using the message type using block type parameters. pub type Message = generic::Message< @@ -42,86 +36,9 @@ pub type Message = generic::Message< ::Extrinsic, >; -/// Type alias for using the block request type using block type parameters. -pub type BlockRequest = - generic::BlockRequest<::Hash, <::Header as HeaderT>::Number>; - -/// Type alias for using the BlockData type using block type parameters. -pub type BlockData = - generic::BlockData<::Header, ::Hash, ::Extrinsic>; - -/// Type alias for using the BlockResponse type using block type parameters. -pub type BlockResponse = - generic::BlockResponse<::Header, ::Hash, ::Extrinsic>; - /// A set of transactions. pub type Transactions = Vec; -// Bits of block data and associated artifacts to request. -bitflags! { - /// Node roles bitmask. - pub struct BlockAttributes: u8 { - /// Include block header. - const HEADER = 0b00000001; - /// Include block body. - const BODY = 0b00000010; - /// Include block receipt. - const RECEIPT = 0b00000100; - /// Include block message queue. - const MESSAGE_QUEUE = 0b00001000; - /// Include a justification for the block. - const JUSTIFICATION = 0b00010000; - /// Include indexed transactions for a block. - const INDEXED_BODY = 0b00100000; - } -} - -impl BlockAttributes { - /// Encodes attributes as big endian u32, compatible with SCALE-encoding (i.e the - /// significant byte has zero index). - pub fn to_be_u32(&self) -> u32 { - u32::from_be_bytes([self.bits(), 0, 0, 0]) - } - - /// Decodes attributes, encoded with the `encode_to_be_u32()` call. - pub fn from_be_u32(encoded: u32) -> Result { - Self::from_bits(encoded.to_be_bytes()[0]) - .ok_or_else(|| Error::from("Invalid BlockAttributes")) - } -} - -impl Encode for BlockAttributes { - fn encode_to(&self, dest: &mut T) { - dest.push_byte(self.bits()) - } -} - -impl codec::EncodeLike for BlockAttributes {} - -impl Decode for BlockAttributes { - fn decode(input: &mut I) -> Result { - Self::from_bits(input.read_byte()?).ok_or_else(|| Error::from("Invalid bytes")) - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Encode, Decode)] -/// Block enumeration direction. -pub enum Direction { - /// Enumerate in ascending order (from child to parent). - Ascending = 0, - /// Enumerate in descending order (from parent to canonical child). - Descending = 1, -} - -/// Block state in the chain. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Encode, Decode)] -pub enum BlockState { - /// Block is not part of the best chain. - Normal, - /// Latest best block. - Best, -} - /// Remote call response. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct RemoteCallResponse { @@ -140,35 +57,18 @@ pub struct RemoteReadResponse { pub proof: StorageProof, } -/// Announcement summary used for debug logging. -#[derive(Debug)] -pub struct AnnouncementSummary { - pub block_hash: H::Hash, - pub number: H::Number, - pub parent_hash: H::Hash, - pub state: Option, -} - -impl generic::BlockAnnounce { - pub fn summary(&self) -> AnnouncementSummary { - AnnouncementSummary { - block_hash: self.header.hash(), - number: *self.header.number(), - parent_hash: *self.header.parent_hash(), - state: self.state, - } - } -} - /// Generic types. pub mod generic { - use super::{ - BlockAttributes, BlockState, ConsensusEngineId, Direction, RemoteCallResponse, - RemoteReadResponse, RequestId, StorageProof, Transactions, - }; + use super::{RemoteCallResponse, RemoteReadResponse, Transactions}; use bitflags::bitflags; use codec::{Decode, Encode, Input, Output}; - use sp_runtime::{EncodedJustification, Justifications}; + use sc_client_api::StorageProof; + use sc_network_common::message::RequestId; + use sc_network_sync::message::{ + generic::{BlockRequest, BlockResponse}, + BlockAnnounce, + }; + use sp_runtime::ConsensusEngineId; bitflags! { /// Bitmask of the roles that a node fulfills. @@ -212,7 +112,7 @@ pub mod generic { } impl codec::Encode for Roles { - fn encode_to(&self, dest: &mut T) { + fn encode_to(&self, dest: &mut T) { dest.push_byte(self.bits()) } } @@ -220,7 +120,7 @@ pub mod generic { impl codec::EncodeLike for Roles {} impl codec::Decode for Roles { - fn decode(input: &mut I) -> Result { + fn decode(input: &mut I) -> Result { Self::from_bits(input.read_byte()?).ok_or_else(|| codec::Error::from("Invalid bytes")) } } @@ -234,36 +134,6 @@ pub mod generic { pub data: Vec, } - /// Block data sent in the response. - #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] - pub struct BlockData { - /// Block header hash. - pub hash: Hash, - /// Block header if requested. - pub header: Option

, - /// Block body if requested. - pub body: Option>, - /// Block body indexed transactions if requested. - pub indexed_body: Option>>, - /// Block receipt if requested. - pub receipt: Option>, - /// Block message queue if requested. - pub message_queue: Option>, - /// Justification if requested. - pub justification: Option, - /// Justifications if requested. - pub justifications: Option, - } - - /// Identifies starting point of a block sequence. - #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] - pub enum FromBlock { - /// Start with given hash. - Hash(Hash), - /// Start with given block number. - Number(Number), - } - /// A network message. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub enum Message { @@ -380,68 +250,6 @@ pub mod generic { } } - /// Request block data from a peer. - #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] - pub struct BlockRequest { - /// Unique request id. - pub id: RequestId, - /// Bits of block data to request. - pub fields: BlockAttributes, - /// Start from this block. - pub from: FromBlock, - /// End at this block. An implementation defined maximum is used when unspecified. - pub to: Option, - /// Sequence direction. - pub direction: Direction, - /// Maximum number of blocks to return. An implementation defined maximum is used when - /// unspecified. - pub max: Option, - } - - /// Response to `BlockRequest` - #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] - pub struct BlockResponse { - /// Id of a request this response was made for. - pub id: RequestId, - /// Block data for the requested sequence. - pub blocks: Vec>, - } - - /// Announce a new complete relay chain block on the network. - #[derive(Debug, PartialEq, Eq, Clone)] - pub struct BlockAnnounce { - /// New block header. - pub header: H, - /// Block state. TODO: Remove `Option` and custom encoding when v4 becomes common. - pub state: Option, - /// Data associated with this block announcement, e.g. a candidate message. - pub data: Option>, - } - - // Custom Encode/Decode impl to maintain backwards compatibility with v3. - // This assumes that the packet contains nothing but the announcement message. - // TODO: Get rid of it once protocol v4 is common. - impl Encode for BlockAnnounce { - fn encode_to(&self, dest: &mut T) { - self.header.encode_to(dest); - if let Some(state) = &self.state { - state.encode_to(dest); - } - if let Some(data) = &self.data { - data.encode_to(dest) - } - } - } - - impl Decode for BlockAnnounce { - fn decode(input: &mut I) -> Result { - let header = H::decode(input)?; - let state = BlockState::decode(input).ok(); - let data = Vec::decode(input).ok(); - Ok(Self { header, state, data }) - } - } - #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Remote call request. pub struct RemoteCallRequest { diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 04d6ccb54339f..6c7b0f3fcdfc8 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -53,6 +53,7 @@ use libp2p::{ NetworkBehaviourAction, PollParameters, }, }; +use sc_network_common::request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}; use std::{ borrow::Cow, collections::{hash_map::Entry, HashMap}, @@ -65,96 +66,6 @@ use std::{ pub use libp2p::request_response::{InboundFailure, OutboundFailure, RequestId}; use sc_peerset::{PeersetHandle, BANNED_THRESHOLD}; -/// Configuration for a single request-response protocol. -#[derive(Debug, Clone)] -pub struct ProtocolConfig { - /// Name of the protocol on the wire. Should be something like `/foo/bar`. - pub name: Cow<'static, str>, - - /// Maximum allowed size, in bytes, of a request. - /// - /// Any request larger than this value will be declined as a way to avoid allocating too - /// much memory for it. - pub max_request_size: u64, - - /// Maximum allowed size, in bytes, of a response. - /// - /// Any response larger than this value will be declined as a way to avoid allocating too - /// much memory for it. - pub max_response_size: u64, - - /// Duration after which emitted requests are considered timed out. - /// - /// If you expect the response to come back quickly, you should set this to a smaller duration. - pub request_timeout: Duration, - - /// Channel on which the networking service will send incoming requests. - /// - /// Every time a peer sends a request to the local node using this protocol, the networking - /// service will push an element on this channel. The receiving side of this channel then has - /// to pull this element, process the request, and send back the response to send back to the - /// peer. - /// - /// The size of the channel has to be carefully chosen. If the channel is full, the networking - /// service will discard the incoming request send back an error to the peer. Consequently, - /// the channel being full is an indicator that the node is overloaded. - /// - /// You can typically set the size of the channel to `T / d`, where `T` is the - /// `request_timeout` and `d` is the expected average duration of CPU and I/O it takes to - /// build a response. - /// - /// Can be `None` if the local node does not support answering incoming requests. - /// If this is `None`, then the local node will not advertise support for this protocol towards - /// other peers. If this is `Some` but the channel is closed, then the local node will - /// advertise support for this protocol, but any incoming request will lead to an error being - /// sent back. - pub inbound_queue: Option>, -} - -/// A single request received by a peer on a request-response protocol. -#[derive(Debug)] -pub struct IncomingRequest { - /// Who sent the request. - pub peer: PeerId, - - /// Request sent by the remote. Will always be smaller than - /// [`ProtocolConfig::max_request_size`]. - pub payload: Vec, - - /// Channel to send back the response. - /// - /// There are two ways to indicate that handling the request failed: - /// - /// 1. Drop `pending_response` and thus not changing the reputation of the peer. - /// - /// 2. Sending an `Err(())` via `pending_response`, optionally including reputation changes for - /// the given peer. - pub pending_response: oneshot::Sender, -} - -/// Response for an incoming request to be send by a request protocol handler. -#[derive(Debug)] -pub struct OutgoingResponse { - /// The payload of the response. - /// - /// `Err(())` if none is available e.g. due an error while handling the request. - pub result: Result, ()>, - - /// Reputation changes accrued while handling the request. To be applied to the reputation of - /// the peer sending the request. - pub reputation_changes: Vec, - - /// If provided, the `oneshot::Sender` will be notified when the request has been sent to the - /// peer. - /// - /// > **Note**: Operating systems typically maintain a buffer of a few dozen kilobytes of - /// > outgoing data for each TCP socket, and it is not possible for a user - /// > application to inspect this buffer. This channel here is not actually notified - /// > when the response has been fully sent out, but rather when it has fully been - /// > written to the buffer managed by the operating system. - pub sent_feedback: Option>, -} - /// Event generated by the [`RequestResponsesBehaviour`]. #[derive(Debug)] pub enum Event { diff --git a/client/network/src/schema.rs b/client/network/src/schema.rs index 032db5f1733c5..80301a59c29ef 100644 --- a/client/network/src/schema.rs +++ b/client/network/src/schema.rs @@ -19,7 +19,6 @@ //! Include sources generated from protobuf definitions. pub mod v1 { - include!(concat!(env!("OUT_DIR"), "/api.v1.rs")); pub mod light { include!(concat!(env!("OUT_DIR"), "/api.v1.light.rs")); } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 91517e14915bc..d2600e3295bf0 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -37,11 +37,8 @@ use crate::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, protocol::{ - self, - event::Event, - message::generic::Roles, - sync::{Status as SyncStatus, SyncState}, - NotificationsSink, NotifsHandlerError, PeerInfo, Protocol, Ready, + self, event::Event, message::generic::Roles, NotificationsSink, NotifsHandlerError, + PeerInfo, Protocol, Ready, }, transactions, transport, DhtEvent, ExHashT, NetworkStateInfo, NetworkStatus, ReputationChange, }; @@ -63,6 +60,7 @@ use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; +use sc_network_sync::{Status as SyncStatus, SyncState}; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::{HeaderBackend, HeaderMetadata}; diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 03d647eade173..36205f32d33c6 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -17,13 +17,14 @@ // along with this program. If not, see . use crate::{ - block_request_handler::BlockRequestHandler, config, - light_client_requests::handler::LightClientRequestHandler, + config, light_client_requests::handler::LightClientRequestHandler, state_request_handler::StateRequestHandler, Event, NetworkService, NetworkWorker, }; use futures::prelude::*; use libp2p::PeerId; +use sc_network_common::config::ProtocolId; +use sc_network_sync::block_request_handler::BlockRequestHandler; use sp_runtime::traits::{Block as BlockT, Header as _}; use std::{borrow::Cow, sync::Arc, time::Duration}; use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; @@ -87,7 +88,7 @@ fn build_test_full_node( None, )); - let protocol_id = config::ProtocolId::from("/test-protocol-name"); + let protocol_id = ProtocolId::from("/test-protocol-name"); let block_request_protocol_config = { let (handler, protocol_config) = BlockRequestHandler::new(&protocol_id, client.clone(), 50); diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 64e208d718889..1f54f05d7446f 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -27,7 +27,7 @@ //! `Future` that processes transactions. use crate::{ - config::{self, ProtocolId, TransactionImport, TransactionImportFuture, TransactionPool}, + config::{self, TransactionImport, TransactionImportFuture, TransactionPool}, error, protocol::message, service::NetworkService, @@ -40,6 +40,7 @@ use futures::{channel::mpsc, prelude::*, stream::FuturesUnordered}; use libp2p::{multiaddr, PeerId}; use log::{debug, trace, warn}; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; +use sc_network_common::config::ProtocolId; use sp_runtime::traits::Block as BlockT; use std::{ borrow::Cow, diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml new file mode 100644 index 0000000000000..c171194d5b24d --- /dev/null +++ b/client/network/sync/Cargo.toml @@ -0,0 +1,49 @@ +[package] +description = "Substrate sync network protocol" +name = "sc-network-sync" +version = "0.10.0-dev" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +documentation = "https://docs.rs/sc-network-sync" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +prost-build = "0.9" + +[dependencies] +bitflags = "1.3.2" +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ + "derive", +] } +either = "1.5.3" +fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } +futures = "0.3.21" +libp2p = "0.44.0" +log = "0.4.16" +lru = "0.7.5" +prost = "0.9" +sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } +sc-network-common = { version = "0.10.0-dev", path = "../common" } +sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } +smallvec = "1.8.0" +sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +thiserror = "1.0" + +[dev-dependencies] +quickcheck = "1.0.3" +sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } +sp-test-primitives = { version = "2.0.0", path = "../../../primitives/test-primitives" } +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/network/sync/build.rs b/client/network/sync/build.rs new file mode 100644 index 0000000000000..55794919cdb42 --- /dev/null +++ b/client/network/sync/build.rs @@ -0,0 +1,5 @@ +const PROTOS: &[&str] = &["src/schema/api.v1.proto"]; + +fn main() { + prost_build::compile_protos(PROTOS, &["src/schema"]).unwrap(); +} diff --git a/client/network/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs similarity index 99% rename from client/network/src/block_request_handler.rs rename to client/network/sync/src/block_request_handler.rs index 7458f421af397..b9ffd24cee4c7 100644 --- a/client/network/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -18,21 +18,23 @@ //! `crate::request_responses::RequestResponsesBehaviour`. use crate::{ - config::ProtocolId, - protocol::message::BlockAttributes, - request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, + message::BlockAttributes, schema::v1::{block_request::FromBlock, BlockResponse, Direction}, - PeerId, ReputationChange, }; use codec::{Decode, Encode}; use futures::{ channel::{mpsc, oneshot}, stream::StreamExt, }; +use libp2p::PeerId; use log::debug; use lru::LruCache; use prost::Message; use sc_client_api::BlockBackend; +use sc_network_common::{ + config::ProtocolId, + request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, +}; use sp_blockchain::HeaderBackend; use sp_runtime::{ generic::BlockId, @@ -51,7 +53,7 @@ const MAX_BODY_BYTES: usize = 8 * 1024 * 1024; const MAX_NUMBER_OF_SAME_REQUESTS_PER_PEER: usize = 2; mod rep { - use super::ReputationChange as Rep; + use sc_peerset::ReputationChange as Rep; /// Reputation change when a peer sent us the same request multiple times. pub const SAME_REQUEST: Rep = Rep::new_fatal("Same block request multiple times"); diff --git a/client/network/src/protocol/sync/blocks.rs b/client/network/sync/src/blocks.rs similarity index 99% rename from client/network/src/protocol/sync/blocks.rs rename to client/network/sync/src/blocks.rs index 43b70d17d8add..b897184e7a44c 100644 --- a/client/network/src/protocol/sync/blocks.rs +++ b/client/network/sync/src/blocks.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::protocol::message; +use crate::message; use libp2p::PeerId; use log::trace; use sp_runtime::traits::{Block as BlockT, NumberFor, One}; @@ -217,7 +217,8 @@ impl BlockCollection { #[cfg(test)] mod test { use super::{BlockCollection, BlockData, BlockRangeState}; - use crate::{protocol::message, PeerId}; + use crate::message; + use libp2p::PeerId; use sp_core::H256; use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; diff --git a/client/network/src/protocol/sync/extra_requests.rs b/client/network/sync/src/extra_requests.rs similarity index 98% rename from client/network/src/protocol/sync/extra_requests.rs rename to client/network/sync/src/extra_requests.rs index 43122631d3c22..c684d8e72783e 100644 --- a/client/network/src/protocol/sync/extra_requests.rs +++ b/client/network/sync/src/extra_requests.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::protocol::sync::{PeerSync, PeerSyncState}; +use crate::{PeerSync, PeerSyncState}; use fork_tree::ForkTree; use libp2p::PeerId; use log::{debug, trace, warn}; @@ -31,7 +31,7 @@ use std::{ const EXTRA_RETRY_WAIT: Duration = Duration::from_secs(10); /// Pending extra data request for the given block (hash and number). -pub(crate) type ExtraRequest = (::Hash, NumberFor); +type ExtraRequest = (::Hash, NumberFor); /// Manages pending block extra data (e.g. justification) requests. /// @@ -57,11 +57,11 @@ pub(crate) struct ExtraRequests { } #[derive(Debug)] -pub(crate) struct Metrics { - pub(crate) pending_requests: u32, - pub(crate) active_requests: u32, - pub(crate) importing_requests: u32, - pub(crate) failed_requests: u32, +pub struct Metrics { + pub pending_requests: u32, + pub active_requests: u32, + pub importing_requests: u32, + pub failed_requests: u32, _priv: (), } @@ -352,7 +352,7 @@ impl<'a, B: BlockT> Matcher<'a, B> { #[cfg(test)] mod tests { use super::*; - use crate::protocol::sync::PeerSync; + use crate::PeerSync; use quickcheck::{Arbitrary, Gen, QuickCheck}; use sp_blockchain::Error as ClientError; use sp_test_primitives::{Block, BlockNumber, Hash}; diff --git a/client/network/src/protocol/sync.rs b/client/network/sync/src/lib.rs similarity index 98% rename from client/network/src/protocol/sync.rs rename to client/network/sync/src/lib.rs index fb89e12a44fe8..bc0ed46c3f068 100644 --- a/client/network/src/protocol/sync.rs +++ b/client/network/sync/src/lib.rs @@ -28,11 +28,25 @@ //! the network, or whenever a block has been successfully verified, call the appropriate method in //! order to update it. +pub mod block_request_handler; +pub mod blocks; +pub mod message; +pub mod schema; +pub mod state; +pub mod state_request_handler; +pub mod warp; +pub mod warp_request_handler; + use crate::{ - protocol::message::{self, BlockAnnounce, BlockAttributes, BlockRequest, BlockResponse}, + blocks::BlockCollection, + message::{BlockAnnounce, BlockAttributes, BlockRequest, BlockResponse}, schema::v1::{StateRequest, StateResponse}, + state::{StateDownloadProgress, StateSync}, + warp::{ + EncodedProof, WarpProofImportResult, WarpProofRequest, WarpSync, WarpSyncPhase, + WarpSyncProgress, WarpSyncProvider, + }, }; -use blocks::BlockCollection; use codec::Encode; use either::Either; use extra_requests::ExtraRequests; @@ -55,8 +69,6 @@ use sp_runtime::{ }, EncodedJustification, Justifications, }; -pub use state::StateDownloadProgress; -use state::StateSync; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, fmt, @@ -64,13 +76,8 @@ use std::{ pin::Pin, sync::Arc, }; -use warp::{WarpProofRequest, WarpSync, WarpSyncProvider}; -pub use warp::{WarpSyncPhase, WarpSyncProgress}; -mod blocks; mod extra_requests; -mod state; -mod warp; /// Maximum blocks to request in a single packet. const MAX_BLOCKS_TO_REQUEST: usize = 64; @@ -332,18 +339,6 @@ pub enum SyncState { Downloading, } -impl fmt::Display for WarpSyncPhase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::AwaitingPeers => write!(f, "Waiting for peers"), - Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"), - Self::DownloadingState => write!(f, "Downloading state"), - Self::ImportingState => write!(f, "Importing state"), - Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n), - } - } -} - /// Syncing status and statistics. #[derive(Clone)] pub struct Status { @@ -1357,7 +1352,7 @@ where pub fn on_warp_sync_data( &mut self, who: &PeerId, - response: warp::EncodedProof, + response: EncodedProof, ) -> Result<(), BadPeer> { if let Some(peer) = self.peers.get_mut(who) { if let PeerSyncState::DownloadingWarpProof = peer.state { @@ -1379,8 +1374,8 @@ where }; match import_result { - warp::WarpProofImportResult::Success => Ok(()), - warp::WarpProofImportResult::BadResponse => { + WarpProofImportResult::Success => Ok(()), + WarpProofImportResult::BadResponse => { debug!(target: "sync", "Bad proof data received from {}", who); Err(BadPeer(*who, rep::BAD_BLOCK)) }, @@ -2173,7 +2168,7 @@ where } /// Return some key metrics. - pub(crate) fn metrics(&self) -> Metrics { + pub fn metrics(&self) -> Metrics { Metrics { queued_blocks: self.queue_blocks.len().try_into().unwrap_or(std::u32::MAX), fork_targets: self.fork_targets.len().try_into().unwrap_or(std::u32::MAX), @@ -2220,10 +2215,10 @@ fn legacy_justification_mapping( } #[derive(Debug)] -pub(crate) struct Metrics { - pub(crate) queued_blocks: u32, - pub(crate) fork_targets: u32, - pub(crate) justifications: extra_requests::Metrics, +pub struct Metrics { + pub queued_blocks: u32, + pub fork_targets: u32, + pub justifications: extra_requests::Metrics, _priv: (), } @@ -2575,9 +2570,10 @@ fn validate_blocks( #[cfg(test)] mod test { use super::{ - message::{BlockData, BlockState, FromBlock}, + message::{BlockState, FromBlock}, *, }; + use crate::message::BlockData; use futures::{executor::block_on, future::poll_fn}; use sc_block_builder::BlockBuilderProvider; use sp_blockchain::HeaderBackend; diff --git a/client/network/sync/src/message.rs b/client/network/sync/src/message.rs new file mode 100644 index 0000000000000..996ee5231cf2e --- /dev/null +++ b/client/network/sync/src/message.rs @@ -0,0 +1,222 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Network packet message types. These get serialized and put into the lower level protocol +//! payload. + +use bitflags::bitflags; +use codec::{Decode, Encode, Error, Input, Output}; +pub use generic::{BlockAnnounce, FromBlock}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; + +/// Type alias for using the block request type using block type parameters. +pub type BlockRequest = + generic::BlockRequest<::Hash, <::Header as HeaderT>::Number>; + +/// Type alias for using the BlockData type using block type parameters. +pub type BlockData = + generic::BlockData<::Header, ::Hash, ::Extrinsic>; + +/// Type alias for using the BlockResponse type using block type parameters. +pub type BlockResponse = + generic::BlockResponse<::Header, ::Hash, ::Extrinsic>; + +// Bits of block data and associated artifacts to request. +bitflags! { + /// Node roles bitmask. + pub struct BlockAttributes: u8 { + /// Include block header. + const HEADER = 0b00000001; + /// Include block body. + const BODY = 0b00000010; + /// Include block receipt. + const RECEIPT = 0b00000100; + /// Include block message queue. + const MESSAGE_QUEUE = 0b00001000; + /// Include a justification for the block. + const JUSTIFICATION = 0b00010000; + /// Include indexed transactions for a block. + const INDEXED_BODY = 0b00100000; + } +} + +impl BlockAttributes { + /// Encodes attributes as big endian u32, compatible with SCALE-encoding (i.e the + /// significant byte has zero index). + pub fn to_be_u32(&self) -> u32 { + u32::from_be_bytes([self.bits(), 0, 0, 0]) + } + + /// Decodes attributes, encoded with the `encode_to_be_u32()` call. + pub fn from_be_u32(encoded: u32) -> Result { + Self::from_bits(encoded.to_be_bytes()[0]) + .ok_or_else(|| Error::from("Invalid BlockAttributes")) + } +} + +impl Encode for BlockAttributes { + fn encode_to(&self, dest: &mut T) { + dest.push_byte(self.bits()) + } +} + +impl codec::EncodeLike for BlockAttributes {} + +impl Decode for BlockAttributes { + fn decode(input: &mut I) -> Result { + Self::from_bits(input.read_byte()?).ok_or_else(|| Error::from("Invalid bytes")) + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Encode, Decode)] +/// Block enumeration direction. +pub enum Direction { + /// Enumerate in ascending order (from child to parent). + Ascending = 0, + /// Enumerate in descending order (from parent to canonical child). + Descending = 1, +} + +/// Block state in the chain. +#[derive(Debug, PartialEq, Eq, Clone, Copy, Encode, Decode)] +pub enum BlockState { + /// Block is not part of the best chain. + Normal, + /// Latest best block. + Best, +} + +/// Announcement summary used for debug logging. +#[derive(Debug)] +pub struct AnnouncementSummary { + pub block_hash: H::Hash, + pub number: H::Number, + pub parent_hash: H::Hash, + pub state: Option, +} + +impl BlockAnnounce { + pub fn summary(&self) -> AnnouncementSummary { + AnnouncementSummary { + block_hash: self.header.hash(), + number: *self.header.number(), + parent_hash: *self.header.parent_hash(), + state: self.state, + } + } +} + +/// Generic types. +pub mod generic { + use super::{BlockAttributes, BlockState, Direction}; + use codec::{Decode, Encode, Input, Output}; + use sc_network_common::message::RequestId; + use sp_runtime::{EncodedJustification, Justifications}; + + /// Block data sent in the response. + #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] + pub struct BlockData { + /// Block header hash. + pub hash: Hash, + /// Block header if requested. + pub header: Option
, + /// Block body if requested. + pub body: Option>, + /// Block body indexed transactions if requested. + pub indexed_body: Option>>, + /// Block receipt if requested. + pub receipt: Option>, + /// Block message queue if requested. + pub message_queue: Option>, + /// Justification if requested. + pub justification: Option, + /// Justifications if requested. + pub justifications: Option, + } + + /// Request block data from a peer. + #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] + pub struct BlockRequest { + /// Unique request id. + pub id: RequestId, + /// Bits of block data to request. + pub fields: BlockAttributes, + /// Start from this block. + pub from: FromBlock, + /// End at this block. An implementation defined maximum is used when unspecified. + pub to: Option, + /// Sequence direction. + pub direction: Direction, + /// Maximum number of blocks to return. An implementation defined maximum is used when + /// unspecified. + pub max: Option, + } + + /// Identifies starting point of a block sequence. + #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] + pub enum FromBlock { + /// Start with given hash. + Hash(Hash), + /// Start with given block number. + Number(Number), + } + + /// Response to `BlockRequest` + #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] + pub struct BlockResponse { + /// Id of a request this response was made for. + pub id: RequestId, + /// Block data for the requested sequence. + pub blocks: Vec>, + } + + /// Announce a new complete relay chain block on the network. + #[derive(Debug, PartialEq, Eq, Clone)] + pub struct BlockAnnounce { + /// New block header. + pub header: H, + /// Block state. TODO: Remove `Option` and custom encoding when v4 becomes common. + pub state: Option, + /// Data associated with this block announcement, e.g. a candidate message. + pub data: Option>, + } + + // Custom Encode/Decode impl to maintain backwards compatibility with v3. + // This assumes that the packet contains nothing but the announcement message. + // TODO: Get rid of it once protocol v4 is common. + impl Encode for BlockAnnounce { + fn encode_to(&self, dest: &mut T) { + self.header.encode_to(dest); + if let Some(state) = &self.state { + state.encode_to(dest); + } + if let Some(data) = &self.data { + data.encode_to(dest) + } + } + } + + impl Decode for BlockAnnounce { + fn decode(input: &mut I) -> Result { + let header = H::decode(input)?; + let state = BlockState::decode(input).ok(); + let data = Vec::decode(input).ok(); + Ok(Self { header, state, data }) + } + } +} diff --git a/client/network/sync/src/schema.rs b/client/network/sync/src/schema.rs new file mode 100644 index 0000000000000..aa3eb84621d8f --- /dev/null +++ b/client/network/sync/src/schema.rs @@ -0,0 +1,23 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Include sources generated from protobuf definitions. + +pub mod v1 { + include!(concat!(env!("OUT_DIR"), "/api.v1.rs")); +} diff --git a/client/network/src/schema/api.v1.proto b/client/network/sync/src/schema/api.v1.proto similarity index 100% rename from client/network/src/schema/api.v1.proto rename to client/network/sync/src/schema/api.v1.proto diff --git a/client/network/src/protocol/sync/state.rs b/client/network/sync/src/state.rs similarity index 99% rename from client/network/src/protocol/sync/state.rs rename to client/network/sync/src/state.rs index 6208b2bcdd18a..4041c28af0eba 100644 --- a/client/network/src/protocol/sync/state.rs +++ b/client/network/sync/src/state.rs @@ -16,6 +16,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! State sync support. + use crate::schema::v1::{StateEntry, StateRequest, StateResponse}; use codec::{Decode, Encode}; use log::debug; @@ -26,8 +28,6 @@ use sp_core::storage::well_known_keys; use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; use std::{collections::HashMap, sync::Arc}; -/// State sync support. - /// State sync state machine. Accumulates partial state data until it /// is ready to be imported. pub struct StateSync { diff --git a/client/network/src/state_request_handler.rs b/client/network/sync/src/state_request_handler.rs similarity index 97% rename from client/network/src/state_request_handler.rs rename to client/network/sync/src/state_request_handler.rs index 7ac1a17e8e759..8e0bae14046da 100644 --- a/client/network/src/state_request_handler.rs +++ b/client/network/sync/src/state_request_handler.rs @@ -17,21 +17,21 @@ //! Helper for handling (i.e. answering) state requests from a remote peer via the //! `crate::request_responses::RequestResponsesBehaviour`. -use crate::{ - config::ProtocolId, - request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, - schema::v1::{KeyValueStateEntry, StateEntry, StateRequest, StateResponse}, - PeerId, ReputationChange, -}; +use crate::schema::v1::{KeyValueStateEntry, StateEntry, StateRequest, StateResponse}; use codec::{Decode, Encode}; use futures::{ channel::{mpsc, oneshot}, stream::StreamExt, }; +use libp2p::PeerId; use log::{debug, trace}; use lru::LruCache; use prost::Message; use sc_client_api::ProofProvider; +use sc_network_common::{ + config::ProtocolId, + request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, +}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use std::{ hash::{Hash, Hasher}, @@ -44,7 +44,7 @@ const MAX_RESPONSE_BYTES: usize = 2 * 1024 * 1024; // Actual reponse may be bigg const MAX_NUMBER_OF_SAME_REQUESTS_PER_PEER: usize = 2; mod rep { - use super::ReputationChange as Rep; + use sc_peerset::ReputationChange as Rep; /// Reputation change when a peer sent us the same request multiple times. pub const SAME_REQUEST: Rep = Rep::new(i32::MIN, "Same state request multiple times"); diff --git a/client/network/src/protocol/sync/warp.rs b/client/network/sync/src/warp.rs similarity index 90% rename from client/network/src/protocol/sync/warp.rs rename to client/network/sync/src/warp.rs index 6845d6d1dc862..d3d9d7d244153 100644 --- a/client/network/src/protocol/sync/warp.rs +++ b/client/network/sync/src/warp.rs @@ -16,17 +16,20 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -///! Warp sync support. -use super::state::{ImportResult, StateSync}; -use crate::schema::v1::{StateRequest, StateResponse}; +//! Warp sync support. + pub use crate::warp_request_handler::{ EncodedProof, Request as WarpProofRequest, VerificationResult, WarpSyncProvider, }; +use crate::{ + schema::v1::{StateRequest, StateResponse}, + state::{ImportResult, StateSync}, +}; use sc_client_api::ProofProvider; use sp_blockchain::HeaderBackend; use sp_finality_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; -use std::sync::Arc; +use std::{fmt, sync::Arc}; enum Phase { WarpProof { set_id: SetId, authorities: AuthorityList, last_hash: B::Hash }, @@ -48,6 +51,18 @@ pub enum WarpSyncPhase { DownloadingBlocks(NumberFor), } +impl fmt::Display for WarpSyncPhase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::AwaitingPeers => write!(f, "Waiting for peers"), + Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"), + Self::DownloadingState => write!(f, "Downloading state"), + Self::ImportingState => write!(f, "Importing state"), + Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n), + } + } +} + /// Reported warp sync progress. #[derive(Clone, Eq, PartialEq, Debug)] pub struct WarpSyncProgress { diff --git a/client/network/src/warp_request_handler.rs b/client/network/sync/src/warp_request_handler.rs similarity index 97% rename from client/network/src/warp_request_handler.rs rename to client/network/sync/src/warp_request_handler.rs index d5bee5833a12a..4f66e0a6daf17 100644 --- a/client/network/src/warp_request_handler.rs +++ b/client/network/sync/src/warp_request_handler.rs @@ -16,13 +16,18 @@ //! Helper for handling (i.e. answering) grandpa warp sync requests from a remote peer. -use crate::config::{IncomingRequest, OutgoingResponse, ProtocolId, RequestResponseConfig}; use codec::{Decode, Encode}; use futures::{ channel::{mpsc, oneshot}, stream::StreamExt, }; use log::debug; +use sc_network_common::{ + config::ProtocolId, + request_responses::{ + IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, + }, +}; use sp_runtime::traits::Block as BlockT; use std::{sync::Arc, time::Duration}; diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 39297dd3ea295..bf3317d0759ee 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-std = "1.11.0" +sc-network-common = { version = "0.10.0-dev", path = "../common" } sc-network = { version = "0.10.0-dev", path = "../" } log = "0.4.16" parking_lot = "0.12.0" diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 20f1a3014867b..9e23a4cc678e9 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -51,12 +51,13 @@ use sc_network::{ block_request_handler::BlockRequestHandler, config::{ MultiaddrWithPeerId, NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, - ProtocolConfig, ProtocolId, Role, SyncMode, TransportConfig, + ProtocolConfig, Role, SyncMode, TransportConfig, }, light_client_requests::handler::LightClientRequestHandler, state_request_handler::StateRequestHandler, warp_request_handler, Multiaddr, NetworkService, NetworkWorker, }; +pub use sc_network_common::config::ProtocolId; use sc_service::client::Client; use sp_blockchain::{ well_known_cache_keys::{self, Id as CacheKeyId}, diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 575305a597798..7138d9d384eeb 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -51,6 +51,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/comm sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sp-storage = { version = "6.0.0", path = "../../primitives/storage" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 7c7bb480aa5c3..56980ad14425f 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -23,12 +23,17 @@ pub use sc_client_db::{Database, DatabaseSource, KeepBlocks, PruningMode}; pub use sc_executor::WasmExecutionMethod; pub use sc_network::{ config::{ - IncomingRequest, MultiaddrWithPeerId, NetworkConfiguration, NodeKeyConfig, - NonDefaultSetConfig, OutgoingResponse, RequestResponseConfig, Role, SetConfig, - TransportConfig, + MultiaddrWithPeerId, NetworkConfiguration, NodeKeyConfig, NonDefaultSetConfig, Role, + SetConfig, TransportConfig, }, Multiaddr, }; +pub use sc_network_common::{ + config::ProtocolId, + request_responses::{ + IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, + }, +}; use prometheus_endpoint::Registry; use sc_chain_spec::ChainSpec; @@ -208,7 +213,7 @@ impl Configuration { } /// Returns the network protocol id from the chain spec, or the default. - pub fn protocol_id(&self) -> sc_network::config::ProtocolId { + pub fn protocol_id(&self) -> ProtocolId { let protocol_id_full = match self.chain_spec.protocol_id() { Some(pid) => pid, None => { @@ -220,7 +225,7 @@ impl Configuration { crate::DEFAULT_PROTOCOL_ID }, }; - sc_network::config::ProtocolId::from(protocol_id_full) + ProtocolId::from(protocol_id_full) } } From cfb5bc6f1a92207785a0bdd321039096685623c8 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 3 May 2022 23:13:58 +0100 Subject: [PATCH 0755/1472] Update Pallet Bags List to use `ListError` (#11342) * extract list error changes from kiz-revamp-sorted-list-providers-2-approval-stake * some fixes * weight -> score * Update tests.rs * Update tests.rs * more fixes * remove score updated event * Update frame/bags-list/src/lib.rs Co-authored-by: Keith Yeung Co-authored-by: Keith Yeung --- frame/bags-list/fuzzer/src/main.rs | 6 +-- frame/bags-list/src/lib.rs | 40 ++++++++++-------- frame/bags-list/src/list/mod.rs | 39 +++++++++++------- frame/bags-list/src/list/tests.rs | 16 ++++---- frame/bags-list/src/tests.rs | 48 +++++++++++----------- frame/election-provider-support/src/lib.rs | 16 ++++++-- frame/staking/src/pallet/impls.rs | 10 +++-- frame/staking/src/pallet/mod.rs | 13 +++--- 8 files changed, 109 insertions(+), 79 deletions(-) diff --git a/frame/bags-list/fuzzer/src/main.rs b/frame/bags-list/fuzzer/src/main.rs index 387c266d32256..d0586f0372ac4 100644 --- a/frame/bags-list/fuzzer/src/main.rs +++ b/frame/bags-list/fuzzer/src/main.rs @@ -64,19 +64,19 @@ fn main() { Action::Insert => { if BagsList::on_insert(id, vote_weight).is_err() { // this was a duplicate id, which is ok. We can just update it. - BagsList::on_update(&id, vote_weight); + BagsList::on_update(&id, vote_weight).unwrap(); } assert!(BagsList::contains(&id)); }, Action::Update => { let already_contains = BagsList::contains(&id); - BagsList::on_update(&id, vote_weight); + BagsList::on_update(&id, vote_weight).unwrap(); if already_contains { assert!(BagsList::contains(&id)); } }, Action::Remove => { - BagsList::on_remove(&id); + BagsList::on_remove(&id).unwrap(); assert!(!BagsList::contains(&id)); }, } diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 53ccd5e4c19f1..77fe609ad8123 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -194,12 +194,14 @@ pub mod pallet { #[pallet::error] #[cfg_attr(test, derive(PartialEq))] pub enum Error { - /// Attempted to place node in front of a node in another bag. - NotInSameBag, - /// Id not found in list. - IdNotFound, - /// An Id does not have a greater score than another Id. - NotHeavier, + /// A error in the list interface implementation. + List(ListError), + } + + impl From for Error { + fn from(t: ListError) -> Self { + Error::::List(t) + } } #[pallet::call] @@ -231,7 +233,9 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::put_in_front_of())] pub fn put_in_front_of(origin: OriginFor, lighter: T::AccountId) -> DispatchResult { let heavier = ensure_signed(origin)?; - List::::put_in_front_of(&lighter, &heavier).map_err(Into::into) + List::::put_in_front_of(&lighter, &heavier) + .map_err::, _>(Into::into) + .map_err::(Into::into) } } @@ -250,16 +254,18 @@ pub mod pallet { impl, I: 'static> Pallet { /// Move an account from one bag to another, depositing an event on success. /// - /// If the account changed bags, returns `Some((from, to))`. - pub fn do_rebag(account: &T::AccountId, new_weight: T::Score) -> Option<(T::Score, T::Score)> { - // if no voter at that node, don't do anything. - // the caller just wasted the fee to call this. - let maybe_movement = list::Node::::get(account) - .and_then(|node| List::update_position_for(node, new_weight)); + /// If the account changed bags, returns `Ok(Some((from, to)))`. + pub fn do_rebag( + account: &T::AccountId, + new_score: T::Score, + ) -> Result, ListError> { + // If no voter at that node, don't do anything. the caller just wasted the fee to call this. + let node = list::Node::::get(&account).ok_or(ListError::NodeNotFound)?; + let maybe_movement = List::update_position_for(node, new_score); if let Some((from, to)) = maybe_movement { Self::deposit_event(Event::::Rebagged { who: account.clone(), from, to }); }; - maybe_movement + Ok(maybe_movement) } /// Equivalent to `ListBags::get`, but public. Useful for tests in outside of this crate. @@ -296,11 +302,11 @@ impl, I: 'static> SortedListProvider for Pallet List::::insert(id, score) } - fn on_update(id: &T::AccountId, new_score: T::Score) { - Pallet::::do_rebag(id, new_score); + fn on_update(id: &T::AccountId, new_score: T::Score) -> Result<(), ListError> { + Pallet::::do_rebag(id, new_score).map(|_| ()) } - fn on_remove(id: &T::AccountId) { + fn on_remove(id: &T::AccountId) -> Result<(), ListError> { List::::remove(id) } diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 4de70569253da..f93bfca1081e9 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -27,7 +27,10 @@ use crate::Config; use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::ScoreProvider; -use frame_support::{traits::Get, DefaultNoBound}; +use frame_support::{ + traits::{Defensive, Get}, + DefaultNoBound, PalletError, +}; use scale_info::TypeInfo; use sp_runtime::traits::{Bounded, Zero}; use sp_std::{ @@ -38,10 +41,14 @@ use sp_std::{ vec::Vec, }; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, PalletError)] pub enum ListError { /// A duplicate id has been detected. Duplicate, + /// An Id does not have a greater score than another Id. + NotHeavier, + /// Attempted to place node in front of a node in another bag. + NotInSameBag, /// Given node id was not found. NodeNotFound, } @@ -321,9 +328,13 @@ impl, I: 'static> List { Ok(()) } - /// Remove an id from the list. - pub(crate) fn remove(id: &T::AccountId) { - Self::remove_many(sp_std::iter::once(id)); + /// Remove an id from the list, returning an error if `id` does not exists. + pub(crate) fn remove(id: &T::AccountId) -> Result<(), ListError> { + if !Self::contains(id) { + return Err(ListError::NodeNotFound) + } + let _ = Self::remove_many(sp_std::iter::once(id)); + Ok(()) } /// Remove many ids from the list. @@ -416,31 +427,31 @@ impl, I: 'static> List { pub(crate) fn put_in_front_of( lighter_id: &T::AccountId, heavier_id: &T::AccountId, - ) -> Result<(), crate::pallet::Error> { - use crate::pallet; + ) -> Result<(), ListError> { use frame_support::ensure; - let lighter_node = Node::::get(lighter_id).ok_or(pallet::Error::IdNotFound)?; - let heavier_node = Node::::get(heavier_id).ok_or(pallet::Error::IdNotFound)?; + let lighter_node = Node::::get(&lighter_id).ok_or(ListError::NodeNotFound)?; + let heavier_node = Node::::get(&heavier_id).ok_or(ListError::NodeNotFound)?; - ensure!(lighter_node.bag_upper == heavier_node.bag_upper, pallet::Error::NotInSameBag); + ensure!(lighter_node.bag_upper == heavier_node.bag_upper, ListError::NotInSameBag); // this is the most expensive check, so we do it last. ensure!( - T::ScoreProvider::score(heavier_id) > T::ScoreProvider::score(lighter_id), - pallet::Error::NotHeavier + T::ScoreProvider::score(&heavier_id) > T::ScoreProvider::score(&lighter_id), + ListError::NotHeavier ); // remove the heavier node from this list. Note that this removes the node from storage and // decrements the node counter. - Self::remove(heavier_id); + // defensive: both nodes have been checked to exist. + let _ = Self::remove(&heavier_id).defensive(); // re-fetch `lighter_node` from storage since it may have been updated when `heavier_node` // was removed. let lighter_node = Node::::get(lighter_id).ok_or_else(|| { debug_assert!(false, "id that should exist cannot be found"); crate::log!(warn, "id that should exist cannot be found"); - pallet::Error::IdNotFound + ListError::NodeNotFound })?; // insert `heavier_node` directly in front of `lighter_node`. This will update both nodes diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index c8e233f1e62cc..ff7dd2871c237 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -21,7 +21,7 @@ use crate::{ ListBags, ListNodes, }; use frame_election_provider_support::{SortedListProvider, VoteWeight}; -use frame_support::{assert_ok, assert_storage_noop}; +use frame_support::{assert_noop, assert_ok, assert_storage_noop}; #[test] fn basic_setup_works() { @@ -98,7 +98,7 @@ fn remove_last_node_in_bags_cleans_bag() { assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); // bump 1 to a bigger bag - List::::remove(&1); + List::::remove(&1).unwrap(); assert_ok!(List::::insert(1, 10_000)); // then the bag with bound 10 is wiped from storage. @@ -265,10 +265,10 @@ mod list { ExtBuilder::default().build_and_execute(|| { // removing a non-existent id is a noop assert!(!ListNodes::::contains_key(42)); - assert_storage_noop!(List::::remove(&42)); + assert_noop!(List::::remove(&42), ListError::NodeNotFound); // when removing a node from a bag with multiple nodes: - List::::remove(&2); + List::::remove(&2).unwrap(); // then assert_eq!(get_list_as_ids(), vec![3, 4, 1]); @@ -276,7 +276,7 @@ mod list { ensure_left(2, 3); // when removing a node from a bag with only one node: - List::::remove(&1); + List::::remove(&1).unwrap(); // then assert_eq!(get_list_as_ids(), vec![3, 4]); @@ -286,11 +286,11 @@ mod list { assert!(!ListBags::::contains_key(10)); // remove remaining ids to make sure storage cleans up as expected - List::::remove(&3); + List::::remove(&3).unwrap(); ensure_left(3, 1); assert_eq!(get_list_as_ids(), vec![4]); - List::::remove(&4); + List::::remove(&4).unwrap(); ensure_left(4, 0); assert_eq!(get_list_as_ids(), Vec::::new()); @@ -573,7 +573,7 @@ mod bags { }); // when we make a pre-existing bag empty - List::::remove(&1); + List::::remove(&1).unwrap(); // then assert_eq!(Bag::::get(10), None) diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs index 941623229dc27..c63ab26d59a67 100644 --- a/frame/bags-list/src/tests.rs +++ b/frame/bags-list/src/tests.rs @@ -34,7 +34,7 @@ mod pallet { vec![(10, vec![1]), (20, vec![42]), (1_000, vec![2, 3, 4])] ); - // when increasing vote weight to the level of non-existent bag + // when increasing score to the level of non-existent bag StakingMock::set_score_of(&42, 2_000); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); @@ -44,7 +44,7 @@ mod pallet { vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![42])] ); - // when decreasing weight within the range of the current bag + // when decreasing score within the range of the current bag StakingMock::set_score_of(&42, 1_001); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); @@ -54,7 +54,7 @@ mod pallet { vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![42])] ); - // when reducing weight to the level of a non-existent bag + // when reducing score to the level of a non-existent bag StakingMock::set_score_of(&42, 30); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); @@ -64,7 +64,7 @@ mod pallet { vec![(10, vec![1]), (30, vec![42]), (1_000, vec![2, 3, 4])] ); - // when increasing weight to the level of a pre-existing bag + // when increasing score to the level of a pre-existing bag StakingMock::set_score_of(&42, 500); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); @@ -380,7 +380,7 @@ mod pallet { // then assert_noop!( BagsList::put_in_front_of(Origin::signed(3), 2), - crate::pallet::Error::::NotHeavier + crate::pallet::Error::::List(ListError::NotHeavier) ); }); } @@ -394,7 +394,7 @@ mod pallet { // then assert_noop!( BagsList::put_in_front_of(Origin::signed(3), 4), - crate::pallet::Error::::NotHeavier + crate::pallet::Error::::List(ListError::NotHeavier) ); }); } @@ -411,7 +411,7 @@ mod pallet { // then assert_noop!( BagsList::put_in_front_of(Origin::signed(5), 4), - crate::pallet::Error::::IdNotFound + crate::pallet::Error::::List(ListError::NodeNotFound) ); }); @@ -425,7 +425,7 @@ mod pallet { // then assert_noop!( BagsList::put_in_front_of(Origin::signed(4), 5), - crate::pallet::Error::::IdNotFound + crate::pallet::Error::::List(ListError::NodeNotFound) ); }); } @@ -439,7 +439,7 @@ mod pallet { // then assert_noop!( BagsList::put_in_front_of(Origin::signed(4), 1), - crate::pallet::Error::::NotInSameBag + crate::pallet::Error::::List(ListError::NotInSameBag) ); }); } @@ -491,12 +491,12 @@ mod sorted_list_provider { assert_eq!(BagsList::count(), 5); // when removing - BagsList::on_remove(&201); + BagsList::on_remove(&201).unwrap(); // then the count goes down assert_eq!(BagsList::count(), 4); // when updating - BagsList::on_update(&201, VoteWeight::MAX); + assert_noop!(BagsList::on_update(&201, VoteWeight::MAX), ListError::NodeNotFound); // then the count stays the same assert_eq!(BagsList::count(), 4); }); @@ -554,8 +554,8 @@ mod sorted_list_provider { ); assert_eq!(BagsList::count(), 5); - // when increasing weight to the level of non-existent bag - BagsList::on_update(&42, 2_000); + // when increasing score to the level of non-existent bag + BagsList::on_update(&42, 2_000).unwrap(); // then the bag is created with the id in it, assert_eq!( @@ -565,8 +565,8 @@ mod sorted_list_provider { // and the id position is updated in the list. assert_eq!(BagsList::iter().collect::>(), vec![42, 2, 3, 4, 1]); - // when decreasing weight within the range of the current bag - BagsList::on_update(&42, 1_001); + // when decreasing score within the range of the current bag + BagsList::on_update(&42, 1_001).unwrap(); // then the id does not change bags, assert_eq!( @@ -576,8 +576,8 @@ mod sorted_list_provider { // or change position in the list. assert_eq!(BagsList::iter().collect::>(), vec![42, 2, 3, 4, 1]); - // when increasing weight to the level of a non-existent bag with the max threshold - BagsList::on_update(&42, VoteWeight::MAX); + // when increasing score to the level of a non-existent bag with the max threshold + BagsList::on_update(&42, VoteWeight::MAX).unwrap(); // the the new bag is created with the id in it, assert_eq!( @@ -587,8 +587,8 @@ mod sorted_list_provider { // and the id position is updated in the list. assert_eq!(BagsList::iter().collect::>(), vec![42, 2, 3, 4, 1]); - // when decreasing the weight to a pre-existing bag - BagsList::on_update(&42, 1_000); + // when decreasing the score to a pre-existing bag + BagsList::on_update(&42, 1_000).unwrap(); // then id is moved to the correct bag (as the last member), assert_eq!( @@ -615,10 +615,10 @@ mod sorted_list_provider { ExtBuilder::default().build_and_execute(|| { // it is a noop removing a non-existent id assert!(!ListNodes::::contains_key(42)); - assert_storage_noop!(BagsList::on_remove(&42)); + assert_noop!(BagsList::on_remove(&42), ListError::NodeNotFound); // when removing a node from a bag with multiple nodes - BagsList::on_remove(&2); + BagsList::on_remove(&2).unwrap(); // then assert_eq!(get_list_as_ids(), vec![3, 4, 1]); @@ -626,7 +626,7 @@ mod sorted_list_provider { ensure_left(2, 3); // when removing a node from a bag with only one node - BagsList::on_remove(&1); + BagsList::on_remove(&1).unwrap(); // then assert_eq!(get_list_as_ids(), vec![3, 4]); @@ -634,10 +634,10 @@ mod sorted_list_provider { ensure_left(1, 2); // when removing all remaining ids - BagsList::on_remove(&4); + BagsList::on_remove(&4).unwrap(); assert_eq!(get_list_as_ids(), vec![3]); ensure_left(4, 1); - BagsList::on_remove(&3); + BagsList::on_remove(&3).unwrap(); // then the storage is completely cleaned up assert_eq!(get_list_as_ids(), Vec::::new()); diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 69bd3025fa768..af366d5b8f919 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -171,7 +171,7 @@ pub mod traits; #[cfg(feature = "std")] use codec::{Decode, Encode}; use frame_support::{weights::Weight, BoundedVec, RuntimeDebug}; -use sp_runtime::traits::Bounded; +use sp_runtime::traits::{Bounded, Saturating, Zero}; use sp_std::{fmt::Debug, prelude::*}; /// Re-export the solution generation macro. @@ -439,7 +439,7 @@ pub trait SortedListProvider { type Error: sp_std::fmt::Debug; /// The type used by the list to compare nodes for ordering. - type Score: Bounded; + type Score: Bounded + Saturating + Zero; /// An iterator over the list, which can have `take` called on it. fn iter() -> Box>; @@ -456,13 +456,21 @@ pub trait SortedListProvider { fn contains(id: &AccountId) -> bool; /// Hook for inserting a new id. + /// + /// Implementation should return an error if duplicate item is being inserted. fn on_insert(id: AccountId, score: Self::Score) -> Result<(), Self::Error>; /// Hook for updating a single id. - fn on_update(id: &AccountId, score: Self::Score); + /// + /// The `new` score is given. + /// + /// Returns `Ok(())` iff it successfully updates an item, an `Err(_)` otherwise. + fn on_update(id: &AccountId, score: Self::Score) -> Result<(), Self::Error>; /// Hook for removing am id from the list. - fn on_remove(id: &AccountId); + /// + /// Returns `Ok(())` iff it successfully removes an item, an `Err(_)` otherwise. + fn on_remove(id: &AccountId) -> Result<(), Self::Error>; /// Regenerate this list from scratch. Returns the count of items inserted. /// diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 0ac61e21fb323..34d7a176670f2 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -803,7 +803,7 @@ impl Pallet { pub fn do_remove_nominator(who: &T::AccountId) -> bool { let outcome = if Nominators::::contains_key(who) { Nominators::::remove(who); - T::VoterList::on_remove(who); + let _ = T::VoterList::on_remove(who).defensive(); true } else { false @@ -850,7 +850,7 @@ impl Pallet { pub fn do_remove_validator(who: &T::AccountId) -> bool { let outcome = if Validators::::contains_key(who) { Validators::::remove(who); - T::VoterList::on_remove(who); + let _ = T::VoterList::on_remove(who).defensive(); true } else { false @@ -1343,11 +1343,13 @@ impl SortedListProvider for UseNominatorsAndValidatorsM // nothing to do on insert. Ok(()) } - fn on_update(_: &T::AccountId, _weight: Self::Score) { + fn on_update(_: &T::AccountId, _weight: VoteWeight) -> Result<(), Self::Error> { // nothing to do on update. + Ok(()) } - fn on_remove(_: &T::AccountId) { + fn on_remove(_: &T::AccountId) -> Result<(), Self::Error> { // nothing to do on remove. + Ok(()) } fn unsafe_regenerate( _: impl IntoIterator, diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 117bc6e7c15bb..e53464195de23 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -22,8 +22,8 @@ use frame_support::{ dispatch::Codec, pallet_prelude::*, traits::{ - Currency, CurrencyToVote, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, - LockIdentifier, LockableCurrency, OnUnbalanced, UnixTime, + Currency, CurrencyToVote, Defensive, DefensiveSaturating, EnsureOrigin, + EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, }; @@ -858,7 +858,8 @@ pub mod pallet { Self::update_ledger(&controller, &ledger); // update this staker in the sorted list, if they exist in it. if T::VoterList::contains(&stash) { - T::VoterList::on_update(&stash, Self::weight_of(&ledger.stash)); + let _ = + T::VoterList::on_update(&stash, Self::weight_of(&ledger.stash)).defensive(); debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); } @@ -941,7 +942,8 @@ pub mod pallet { // update this staker in the sorted list, if they exist in it. if T::VoterList::contains(&ledger.stash) { - T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash)); + let _ = T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash)) + .defensive(); } Self::deposit_event(Event::::Unbonded(ledger.stash, value)); @@ -1426,7 +1428,8 @@ pub mod pallet { // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); if T::VoterList::contains(&ledger.stash) { - T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash)); + let _ = T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash)) + .defensive(); } let removed_chunks = 1u32 // for the case where the last iterated chunk is not removed From 1a32a31ee8289b603c665766cd0dea0f6c96ea41 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 4 May 2022 01:54:08 +0100 Subject: [PATCH 0756/1472] Update docs (#11313) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update docs * Update primitives/runtime/src/traits.rs * Update primitives/runtime/src/traits.rs Co-authored-by: Bastian Köcher --- primitives/runtime/src/traits.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index dc13567df58db..9f706878bba49 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -874,12 +874,7 @@ pub trait SignedExtension: /// Do any pre-flight stuff for a signed transaction. /// - /// Note this function by default delegates to `validate`, so that - /// all checks performed for the transaction queue are also performed during - /// the dispatch phase (applying the extrinsic). - /// - /// If you ever override this function, you need to make sure to always - /// perform the same validation as in `validate`. + /// Make sure to perform the same checks as in [`Self::validate`]. fn pre_dispatch( self, who: &Self::AccountId, From 392f0b1786127b002998bd77911521b3f6fbc340 Mon Sep 17 00:00:00 2001 From: Alexander Gryaznov Date: Wed, 4 May 2022 10:35:30 +0300 Subject: [PATCH 0757/1472] [contracts] stabilize `seal_code_hash`, `seal_set_code_hash` and `seal_own_code_hash` (#11337) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * stabilize seal_code_hash, seal_set_code_hash, seal_own_code_hash * fix missed place found by CI * Fixed missed __unstable__ Co-authored-by: Alexander Theißen --- frame/contracts/fixtures/set_code_hash.wat | 2 +- frame/contracts/src/benchmarking/mod.rs | 6 +++--- frame/contracts/src/tests.rs | 1 - frame/contracts/src/wasm/mod.rs | 9 +++------ frame/contracts/src/wasm/runtime.rs | 12 +++--------- 5 files changed, 10 insertions(+), 20 deletions(-) diff --git a/frame/contracts/fixtures/set_code_hash.wat b/frame/contracts/fixtures/set_code_hash.wat index 0a7b2e7cbedfa..b4df1b133186b 100644 --- a/frame/contracts/fixtures/set_code_hash.wat +++ b/frame/contracts/fixtures/set_code_hash.wat @@ -1,7 +1,7 @@ (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "__unstable__" "seal_set_code_hash" (func $seal_set_code_hash (param i32) (result i32))) + (import "seal0" "seal_set_code_hash" (func $seal_set_code_hash (param i32) (result i32))) (import "env" "memory" (memory 1 1)) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 84f4cb6083e5f..6411bcb2b589a 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -448,7 +448,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "seal_code_hash", params: vec![ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -484,7 +484,7 @@ benchmarks! { seal_own_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "__unstable__", "seal_own_code_hash", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_own_code_hash", r * API_BENCHMARK_BATCH_SIZE ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -2017,7 +2017,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "seal_set_code_hash", params: vec![ ValueType::I32, diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 9d949eea9b948..eaec4df698e5a 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -3088,7 +3088,6 @@ fn code_rejected_error_works() { } #[test] -#[cfg(feature = "unstable-interface")] fn set_code_hash() { let (wasm, code_hash) = compile_module::("set_code_hash").unwrap(); let (new_wasm, new_code_hash) = compile_module::("new_set_code_hash_contract").unwrap(); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index f12df06b938c8..7257fbea6336a 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -2407,12 +2407,11 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn code_hash_works() { /// calls `seal_code_hash` and compares the result with the constant. const CODE_CODE_HASH: &str = r#" (module - (import "__unstable__" "seal_code_hash" (func $seal_code_hash (param i32 i32 i32) (result i32))) + (import "seal0" "seal_code_hash" (func $seal_code_hash (param i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; size of our buffer is 32 bytes @@ -2460,12 +2459,11 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn own_code_hash_works() { /// calls `seal_own_code_hash` and compares the result with the constant. const CODE_OWN_CODE_HASH: &str = r#" (module - (import "__unstable__" "seal_own_code_hash" (func $seal_own_code_hash (param i32 i32))) + (import "seal0" "seal_own_code_hash" (func $seal_own_code_hash (param i32 i32))) (import "env" "memory" (memory 1 1)) ;; size of our buffer is 32 bytes @@ -2546,11 +2544,10 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn set_code_hash() { const CODE: &str = r#" (module - (import "__unstable__" "seal_set_code_hash" (func $seal_set_code_hash (param i32) (result i32))) + (import "seal0" "seal_set_code_hash" (func $seal_set_code_hash (param i32) (result i32))) (import "env" "memory" (memory 1 1)) (func $assert (param i32) (block $ok diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 7719d512b8aba..a6f42ba64a49c 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -147,10 +147,8 @@ pub enum RuntimeCosts { /// Weight of calling `seal_is_contract`. IsContract, /// Weight of calling `seal_code_hash`. - #[cfg(feature = "unstable-interface")] CodeHash, /// Weight of calling `seal_own_code_hash`. - #[cfg(feature = "unstable-interface")] OwnCodeHash, /// Weight of calling `seal_caller_is_origin`. CallerIsOrigin, @@ -225,7 +223,6 @@ pub enum RuntimeCosts { #[cfg(feature = "unstable-interface")] CallRuntime(Weight), /// Weight of calling `seal_set_code_hash` - #[cfg(feature = "unstable-interface")] SetCodeHash, /// Weight of calling `ecdsa_to_eth_address` #[cfg(feature = "unstable-interface")] @@ -245,9 +242,7 @@ impl RuntimeCosts { CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()), Caller => s.caller, IsContract => s.is_contract, - #[cfg(feature = "unstable-interface")] CodeHash => s.code_hash, - #[cfg(feature = "unstable-interface")] OwnCodeHash => s.own_code_hash, CallerIsOrigin => s.caller_is_origin, Address => s.address, @@ -312,7 +307,6 @@ impl RuntimeCosts { #[cfg(feature = "unstable-interface")] CallRuntime(weight) => weight, - #[cfg(feature = "unstable-interface")] SetCodeHash => s.set_code_hash, #[cfg(feature = "unstable-interface")] EcdsaToEthAddress => s.ecdsa_to_eth_address, @@ -1401,7 +1395,7 @@ define_env!(Env, , // # Errors // // `ReturnCode::KeyNotFound` - [__unstable__] seal_code_hash(ctx, account_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { + [seal0] seal_code_hash(ctx, account_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { ctx.charge_gas(RuntimeCosts::CodeHash)?; let address: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(account_ptr)?; @@ -1420,7 +1414,7 @@ define_env!(Env, , // - `out_ptr`: pointer to the linear memory where the returning value is written to. // - `out_len_ptr`: in-out pointer into linear memory where the buffer length // is read from and the value length is written to. - [__unstable__] seal_own_code_hash(ctx, out_ptr: u32, out_len_ptr: u32) => { + [seal0] seal_own_code_hash(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeCosts::OwnCodeHash)?; let code_hash_encoded = &ctx.ext.own_code_hash().encode(); Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, code_hash_encoded, false, already_charged)?) @@ -2048,7 +2042,7 @@ define_env!(Env, , // # Errors // // `ReturnCode::CodeNotFound` - [__unstable__] seal_set_code_hash(ctx, code_hash_ptr: u32) -> ReturnCode => { + [seal0] seal_set_code_hash(ctx, code_hash_ptr: u32) -> ReturnCode => { ctx.charge_gas(RuntimeCosts::SetCodeHash)?; let code_hash: CodeHash<::T> = ctx.read_sandbox_memory_as(code_hash_ptr)?; match ctx.ext.set_code_hash(code_hash) { From ce4c065a1177de596b1b2941246348bab908791d Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 4 May 2022 12:36:52 +0300 Subject: [PATCH 0758/1472] BEEFY voter bugfixes (#11335) * beefy: gadget should always use current validator set The gadget/client-voter was using previous' session validator set to sign the 1st block in the new session (to have chained validator set handoffs). This is not necessary because: 1. BEEFY piggy-backs on GRANDPA and only works on canonical chain, so it need not concern itself with the validity of the block header (which contains digest with the new session's validator set). It can safely assume header is valid and simply use new validator set. 2. The BEEFY payload itself already contains a merkle root for the next validator set keys. So at the BEEFY-payload layer we already have a validated/trusted hand-off of authority. Signed-off-by: acatangiu * beefy: buffer votes for not yet finalized blocks Signed-off-by: acatangiu * beefy: add buffered votes regression test --- client/beefy/src/round.rs | 52 +++++-------------- client/beefy/src/tests.rs | 32 +++++++++--- client/beefy/src/worker.rs | 101 ++++++++++++++++++++++++++----------- 3 files changed, 112 insertions(+), 73 deletions(-) diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index a5a15bac5f8f9..fecb9557df6ea 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -73,7 +73,6 @@ pub(crate) struct Rounds { best_done: Option>, session_start: NumberFor, validator_set: ValidatorSet, - prev_validator_set: ValidatorSet, } impl Rounds @@ -81,18 +80,8 @@ where P: Ord + Hash + Clone, B: Block, { - pub(crate) fn new( - session_start: NumberFor, - validator_set: ValidatorSet, - prev_validator_set: ValidatorSet, - ) -> Self { - Rounds { - rounds: BTreeMap::new(), - best_done: None, - session_start, - validator_set, - prev_validator_set, - } + pub(crate) fn new(session_start: NumberFor, validator_set: ValidatorSet) -> Self { + Rounds { rounds: BTreeMap::new(), best_done: None, session_start, validator_set } } } @@ -101,24 +90,12 @@ where P: Ord + Hash + Clone, B: Block, { - pub(crate) fn validator_set_id_for(&self, block_number: NumberFor) -> ValidatorSetId { - if block_number > self.session_start { - self.validator_set.id() - } else { - self.prev_validator_set.id() - } - } - - pub(crate) fn validators_for(&self, block_number: NumberFor) -> &[Public] { - if block_number > self.session_start { - self.validator_set.validators() - } else { - self.prev_validator_set.validators() - } + pub(crate) fn validator_set_id(&self) -> ValidatorSetId { + self.validator_set.id() } - pub(crate) fn validator_set(&self) -> &ValidatorSet { - &self.validator_set + pub(crate) fn validators(&self) -> &[Public] { + self.validator_set.validators() } pub(crate) fn session_start(&self) -> &NumberFor { @@ -143,7 +120,7 @@ where round.1 ); false - } else if !self.validator_set.validators().iter().any(|id| vote.0 == *id) { + } else if !self.validators().iter().any(|id| vote.0 == *id) { debug!( target: "beefy", "🥩 received vote {:?} from validator that is not in the validator set, ignoring", @@ -170,12 +147,11 @@ where // remove this and older (now stale) rounds let signatures = self.rounds.remove(round)?.votes; self.rounds.retain(|&(_, number), _| number > round.1); - self.best_done = self.best_done.clone().max(Some(round.1.clone())); + self.best_done = self.best_done.max(Some(round.1)); debug!(target: "beefy", "🥩 Concluded round #{}", round.1); Some( - self.validator_set - .validators() + self.validators() .iter() .map(|authority_id| signatures.get(authority_id).cloned()) .collect(), @@ -247,13 +223,13 @@ mod tests { .unwrap(); let session_start = 1u64.into(); - let rounds = Rounds::::new(session_start, validators.clone(), validators); + let rounds = Rounds::::new(session_start, validators); - assert_eq!(42, rounds.validator_set_id_for(session_start)); + assert_eq!(42, rounds.validator_set_id()); assert_eq!(1, *rounds.session_start()); assert_eq!( &vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], - rounds.validators_for(session_start) + rounds.validators() ); } @@ -274,7 +250,7 @@ mod tests { let round = (H256::from_low_u64_le(1), 1); let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators.clone(), validators); + let mut rounds = Rounds::::new(session_start, validators); // no self vote yet, should self vote assert!(rounds.should_self_vote(&round)); @@ -347,7 +323,7 @@ mod tests { .unwrap(); let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators.clone(), validators); + let mut rounds = Rounds::::new(session_start, validators); // round 1 assert!(rounds.add_vote( diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index e568daba8e112..5f5fbd2f1ff1f 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -469,8 +469,8 @@ fn finalize_block_and_wait_for_beefy( } if expected_beefy.is_empty() { - // run for 1 second then verify no new best beefy block available - let timeout = Some(Duration::from_millis(500)); + // run for quarter second then verify no new best beefy block available + let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, runtime, timeout); streams_empty_after_timeout(signed_commitments, &net, runtime, None); } else { @@ -535,8 +535,8 @@ fn lagging_validators() { let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); - // push 42 blocks including `AuthorityChange` digests every 30 blocks. - net.generate_blocks(42, session_len, &validator_set, true); + // push 62 blocks including `AuthorityChange` digests every 30 blocks. + net.generate_blocks(62, session_len, &validator_set, true); net.block_until_sync(); let net = Arc::new(Mutex::new(net)); @@ -550,7 +550,7 @@ fn lagging_validators() { let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY - let timeout = Some(Duration::from_millis(500)); + let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); @@ -563,6 +563,26 @@ fn lagging_validators() { // Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32 finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[30, 32], &[30, 31, 32]); + + // Verify that session-boundary votes get buffered by client and only processed once + // session-boundary block is GRANDPA-finalized (this guarantees authenticity for the new session + // validator set). + + // Alice finalizes session-boundary mandatory block #60, Bob lags behind + let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); + let finalize = BlockId::number(60); + net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); + // verify nothing gets finalized by BEEFY + let timeout = Some(Duration::from_millis(250)); + streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); + streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); + + // Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60) + let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); + net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); + // verify beefy skips intermediary votes, and successfully finalizes mandatory block #40 + wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]); + wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[60]); } #[test] @@ -624,7 +644,7 @@ fn correct_beefy_payload() { .unwrap(); // verify consensus is _not_ reached - let timeout = Some(Duration::from_millis(500)); + let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 8ab18c58f9dd3..ae466a71abb57 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -16,7 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{collections::BTreeSet, fmt::Debug, marker::PhantomData, sync::Arc, time::Duration}; +use std::{ + collections::{BTreeMap, BTreeSet}, + fmt::Debug, + marker::PhantomData, + sync::Arc, + time::Duration, +}; use codec::{Codec, Decode, Encode}; use futures::{future, FutureExt, StreamExt}; @@ -27,7 +33,7 @@ use sc_client_api::{Backend, FinalityNotification, FinalityNotifications}; use sc_network_gossip::GossipEngine; use sp_api::{BlockId, ProvideRuntimeApi}; -use sp_arithmetic::traits::AtLeast32Bit; +use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_mmr_primitives::MmrApi; use sp_runtime::{ @@ -80,6 +86,8 @@ pub(crate) struct BeefyWorker { min_block_delta: u32, metrics: Option, rounds: Option>, + /// Buffer holding votes for blocks that the client hasn't seen finality for. + pending_votes: BTreeMap, Vec, AuthorityId, Signature>>>, finality_notifications: FinalityNotifications, /// Best block we received a GRANDPA notification for best_grandpa_block_header: ::Header, @@ -141,6 +149,7 @@ where min_block_delta: min_block_delta.max(1), metrics, rounds: None, + pending_votes: BTreeMap::new(), finality_notifications: client.finality_notification_stream(), best_grandpa_block_header: last_finalized_header, best_beefy_block: None, @@ -238,7 +247,11 @@ where } /// Handle session changes by starting new voting round for mandatory blocks. - fn init_session_at(&mut self, active: ValidatorSet, session_start: NumberFor) { + fn init_session_at( + &mut self, + active: ValidatorSet, + new_session_start: NumberFor, + ) { debug!(target: "beefy", "🥩 New active validator set: {:?}", active); metric_set!(self, beefy_validator_set_id, active.id()); // BEEFY should produce a signed commitment for each session @@ -246,23 +259,22 @@ where active.id() != GENESIS_AUTHORITY_SET_ID && self.last_signed_id != 0 { + debug!( + target: "beefy", "🥩 Detected skipped session: active-id {:?}, last-signed-id {:?}", + active.id(), + self.last_signed_id, + ); metric_inc!(self, beefy_skipped_sessions); } if log_enabled!(target: "beefy", log::Level::Debug) { // verify the new validator set - only do it if we're also logging the warning - let _ = self.verify_validator_set(&session_start, &active); + let _ = self.verify_validator_set(&new_session_start, &active); } - let prev_validator_set = if let Some(r) = &self.rounds { - r.validator_set().clone() - } else { - // no previous rounds present use new validator set instead (genesis case) - active.clone() - }; let id = active.id(); - self.rounds = Some(Rounds::new(session_start, active, prev_validator_set)); - info!(target: "beefy", "🥩 New Rounds for validator set id: {:?} with session_start {:?}", id, session_start); + self.rounds = Some(Rounds::new(new_session_start, active)); + info!(target: "beefy", "🥩 New Rounds for validator set id: {:?} with session_start {:?}", id, new_session_start); } fn handle_finality_notification(&mut self, notification: &FinalityNotification) { @@ -287,12 +299,36 @@ where self.init_session_at(new_validator_set, *header.number()); } + // Handle any pending votes for now finalized blocks. + self.check_pending_votes(); + // Vote if there's now a new vote target. if let Some(target_number) = self.current_vote_target() { self.do_vote(target_number); } } + // Handles all buffered votes for now finalized blocks. + fn check_pending_votes(&mut self) { + let not_finalized = self.best_grandpa_block_header.number().saturating_add(1u32.into()); + let still_pending = self.pending_votes.split_off(¬_finalized); + let votes_to_handle = std::mem::replace(&mut self.pending_votes, still_pending); + for (num, votes) in votes_to_handle.into_iter() { + if Some(num) > self.best_beefy_block { + debug!(target: "beefy", "🥩 Handling buffered votes for now GRANDPA finalized block: {:?}.", num); + for v in votes.into_iter() { + self.handle_vote( + (v.commitment.payload, v.commitment.block_number), + (v.id, v.signature), + false, + ); + } + } else { + debug!(target: "beefy", "🥩 Dropping outdated buffered votes for now BEEFY finalized block: {:?}.", num); + } + } + } + fn handle_vote( &mut self, round: (Payload, NumberFor), @@ -313,7 +349,7 @@ where self.gossip_validator.conclude_round(round.1); // id is stored for skipped session metric calculation - self.last_signed_id = rounds.validator_set_id_for(round.1); + self.last_signed_id = rounds.validator_set_id(); let block_num = round.1; let commitment = Commitment { @@ -390,7 +426,7 @@ where debug!(target: "beefy", "🥩 Don't double vote for block number: {:?}", target_number); return } - (rounds.validators_for(target_number), rounds.validator_set_id_for(target_number)) + (rounds.validators(), rounds.validator_set_id()) } else { debug!(target: "beefy", "🥩 Missing validator set - can't vote for: {:?}", target_hash); return @@ -506,11 +542,23 @@ where }, vote = votes.next().fuse() => { if let Some(vote) = vote { - self.handle_vote( - (vote.commitment.payload, vote.commitment.block_number), - (vote.id, vote.signature), - false - ); + let block_num = vote.commitment.block_number; + if block_num > *self.best_grandpa_block_header.number() { + // Only handle votes for blocks we _know_ have been finalized. + // Buffer vote to be handled later. + debug!( + target: "beefy", + "🥩 Buffering vote for not (yet) finalized block: {:?}.", + block_num + ); + self.pending_votes.entry(block_num).or_default().push(vote); + } else { + self.handle_vote( + (vote.commitment.payload, vote.commitment.block_number), + (vote.id, vote.signature), + false + ); + } } else { return; } @@ -854,8 +902,7 @@ pub(crate) mod tests { worker.best_grandpa_block_header = grandpa_header; worker.best_beefy_block = best_beefy; worker.min_block_delta = min_delta; - worker.rounds = - Some(Rounds::new(session_start, validator_set.clone(), validator_set.clone())); + worker.rounds = Some(Rounds::new(session_start, validator_set.clone())); }; // under min delta @@ -970,11 +1017,10 @@ pub(crate) mod tests { worker.init_session_at(validator_set.clone(), 1); let worker_rounds = worker.rounds.as_ref().unwrap(); - assert_eq!(worker_rounds.validator_set(), &validator_set); assert_eq!(worker_rounds.session_start(), &1); // in genesis case both current and prev validator sets are the same - assert_eq!(worker_rounds.validator_set_id_for(1), validator_set.id()); - assert_eq!(worker_rounds.validator_set_id_for(2), validator_set.id()); + assert_eq!(worker_rounds.validators(), validator_set.validators()); + assert_eq!(worker_rounds.validator_set_id(), validator_set.id()); // new validator set let keys = &[Keyring::Bob]; @@ -984,11 +1030,8 @@ pub(crate) mod tests { worker.init_session_at(new_validator_set.clone(), 11); let worker_rounds = worker.rounds.as_ref().unwrap(); - assert_eq!(worker_rounds.validator_set(), &new_validator_set); assert_eq!(worker_rounds.session_start(), &11); - // mandatory block gets prev set, further blocks get new set - assert_eq!(worker_rounds.validator_set_id_for(11), validator_set.id()); - assert_eq!(worker_rounds.validator_set_id_for(12), new_validator_set.id()); - assert_eq!(worker_rounds.validator_set_id_for(13), new_validator_set.id()); + assert_eq!(worker_rounds.validators(), new_validator_set.validators()); + assert_eq!(worker_rounds.validator_set_id(), new_validator_set.id()); } } From 58fd5b71021a36f835744fd14b08ae1631b9b856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 4 May 2022 12:15:11 +0200 Subject: [PATCH 0759/1472] sc-network: Do not return error on peer id only reserved nodes (#11346) When passing reserved nodes only with a peer id it was failing with the `DuplicateBootnode` error. Besides that there are some clean ups. We for example added the bootnodes twice to the `known_addresses`. --- client/network/src/protocol.rs | 6 ++++-- client/network/src/service.rs | 18 +++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 5db8f102d037b..387a7b3fdde90 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -356,13 +356,15 @@ where let mut default_sets_reserved = HashSet::new(); for reserved in network_config.default_peers_set.reserved_nodes.iter() { default_sets_reserved.insert(reserved.peer_id); - known_addresses.push((reserved.peer_id, reserved.multiaddr.clone())); + + if !reserved.multiaddr.is_empty() { + known_addresses.push((reserved.peer_id, reserved.multiaddr.clone())); + } } let mut bootnodes = Vec::with_capacity(network_config.boot_nodes.len()); for bootnode in network_config.boot_nodes.iter() { bootnodes.push(bootnode.peer_id); - known_addresses.push((bootnode.peer_id, bootnode.multiaddr.clone())); } // Set number 0 is used for block announces. diff --git a/client/network/src/service.rs b/client/network/src/service.rs index d2600e3295bf0..edd30e9c9dee4 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -228,12 +228,10 @@ where )?; // List of multiaddresses that we know in the network. - let mut bootnodes = Vec::new(); let mut boot_node_ids = HashSet::new(); // Process the bootnodes. for bootnode in params.network_config.boot_nodes.iter() { - bootnodes.push(bootnode.peer_id); boot_node_ids.insert(bootnode.peer_id); known_addresses.push((bootnode.peer_id, bootnode.multiaddr.clone())); } @@ -241,12 +239,18 @@ where let boot_node_ids = Arc::new(boot_node_ids); // Check for duplicate bootnodes. - known_addresses.iter().try_for_each(|(peer_id, addr)| { - if let Some(other) = known_addresses.iter().find(|o| o.1 == *addr && o.0 != *peer_id) { + params.network_config.boot_nodes.iter().try_for_each(|bootnode| { + if let Some(other) = params + .network_config + .boot_nodes + .iter() + .filter(|o| o.multiaddr == bootnode.multiaddr) + .find(|o| o.peer_id != bootnode.peer_id) + { Err(Error::DuplicateBootnode { - address: addr.clone(), - first_id: *peer_id, - second_id: other.0, + address: bootnode.multiaddr.clone(), + first_id: bootnode.peer_id, + second_id: other.peer_id, }) } else { Ok(()) From 636ffa4fcd65c0c42f341dd870647302eb50d557 Mon Sep 17 00:00:00 2001 From: Web3 Smith <31099392+Wizdave97@users.noreply.github.com> Date: Wed, 4 May 2022 11:40:11 +0100 Subject: [PATCH 0760/1472] Update MMR Runtime API with functionality to generate MMR proof for a series of leaf indices (#10635) * updated mmr rpc api with functions for batch generation of proof * update code comments * fix build errors * added tests to mmr-rpc * add tests to pallet-mmr * update comments * minor comment fix * remove unused variables * fix rust doc errors * refactor mmr runtime api * fix tests * minor fix * minor fix * fix node-runtime * revert to initial api * impl from proof fot batchproof * minor fix * minor fix * use explicit functions to convert btw batch proof and single proof * minor fix * add new variant to mmr error * fmt * update conversion to single leaf proof * fix style nit Co-authored-by: Adrian Catangiu --- bin/node/runtime/src/lib.rs | 38 +++++- client/beefy/src/tests.rs | 20 ++- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/src/lib.rs | 118 +++++++++++++++++- frame/merkle-mountain-range/src/lib.rs | 54 ++++---- frame/merkle-mountain-range/src/mmr/mmr.rs | 86 +++++++++---- frame/merkle-mountain-range/src/mmr/mod.rs | 2 +- frame/merkle-mountain-range/src/tests.rs | 131 +++++++++++++++++--- primitives/merkle-mountain-range/src/lib.rs | 59 ++++++++- 9 files changed, 429 insertions(+), 81 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8c999bb76fc14..660ba7ab86229 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1832,8 +1832,12 @@ impl_runtime_apis! { fn generate_proof(leaf_index: pallet_mmr::primitives::LeafIndex) -> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof), mmr::Error> { - Mmr::generate_proof(leaf_index) - .map(|(leaf, proof)| (mmr::EncodableOpaqueLeaf::from_leaf(&leaf), proof)) + Mmr::generate_batch_proof(vec![leaf_index]).and_then(|(leaves, proof)| + Ok(( + mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]), + mmr::BatchProof::into_single_leaf_proof(proof)? + )) + ) } fn verify_proof(leaf: mmr::EncodableOpaqueLeaf, proof: mmr::Proof) @@ -1843,7 +1847,7 @@ impl_runtime_apis! { .into_opaque_leaf() .try_decode() .ok_or(mmr::Error::Verify)?; - Mmr::verify_leaf(leaf, proof) + Mmr::verify_leaves(vec![leaf], mmr::Proof::into_batch_proof(proof)) } fn verify_proof_stateless( @@ -1852,12 +1856,38 @@ impl_runtime_apis! { proof: mmr::Proof ) -> Result<(), mmr::Error> { let node = mmr::DataOrHash::Data(leaf.into_opaque_leaf()); - pallet_mmr::verify_leaf_proof::(root, node, proof) + pallet_mmr::verify_leaves_proof::(root, vec![node], mmr::Proof::into_batch_proof(proof)) } fn mmr_root() -> Result { Ok(Mmr::mmr_root()) } + + fn generate_batch_proof(leaf_indices: Vec) + -> Result<(Vec, mmr::BatchProof), mmr::Error> + { + Mmr::generate_batch_proof(leaf_indices) + .map(|(leaves, proof)| (leaves.into_iter().map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)).collect(), proof)) + } + + fn verify_batch_proof(leaves: Vec, proof: mmr::BatchProof) + -> 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_batch_proof_stateless( + root: mmr::Hash, + leaves: Vec, + proof: mmr::BatchProof + ) -> 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 sp_session::SessionKeys for Runtime { diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 5f5fbd2f1ff1f..1d035a6a447c2 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -39,7 +39,9 @@ use beefy_primitives::{ crypto::AuthorityId, BeefyApi, ConsensusLog, MmrRootHash, ValidatorSet, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, }; -use sp_mmr_primitives::{EncodableOpaqueLeaf, Error as MmrError, LeafIndex, MmrApi, Proof}; +use sp_mmr_primitives::{ + BatchProof, EncodableOpaqueLeaf, Error as MmrError, LeafIndex, MmrApi, Proof, +}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; @@ -259,6 +261,22 @@ macro_rules! create_test_api { fn mmr_root() -> Result { Ok($mmr_root) } + + fn generate_batch_proof(_leaf_indices: Vec) -> Result<(Vec, BatchProof), MmrError> { + unimplemented!() + } + + fn verify_batch_proof(_leaves: Vec, _proof: BatchProof) -> Result<(), MmrError> { + unimplemented!() + } + + fn verify_batch_proof_stateless( + _root: MmrRootHash, + _leaves: Vec, + _proof: BatchProof + ) -> Result<(), MmrError> { + unimplemented!() + } } } } diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 94c895ea91517..359ee88a9c485 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1.0.136", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/merkle-mountain-range" } +sp-mmr-primitives = { version = "4.0.0-dev", path = "../../../primitives/merkle-mountain-range" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [dev-dependencies] diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 99359bfea8eb6..be1a74450d1f4 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -29,7 +29,7 @@ use serde::{Deserialize, Serialize}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::Bytes; -use sp_mmr_primitives::{Error as MmrError, LeafIndex, Proof}; +use sp_mmr_primitives::{BatchProof, Error as MmrError, LeafIndex, Proof}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; @@ -57,6 +57,34 @@ impl LeafProof { } } +/// Retrieved MMR leaves and their proof. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct LeafBatchProof { + /// Block hash the proof was generated for. + pub block_hash: BlockHash, + /// SCALE-encoded vector of `LeafData`. + pub leaves: Bytes, + /// SCALE-encoded proof data. See [sp_mmr_primitives::BatchProof]. + pub proof: Bytes, +} + +impl LeafBatchProof { + /// Create new `LeafBatchProof` from a given vector of `Leaf` and a + /// [sp_mmr_primitives::BatchProof]. + pub fn new( + block_hash: BlockHash, + leaves: Vec, + proof: BatchProof, + ) -> Self + where + Leaf: Encode, + MmrHash: Encode, + { + Self { block_hash, leaves: Bytes(leaves.encode()), proof: Bytes(proof.encode()) } + } +} + /// MMR RPC methods. #[rpc] pub trait MmrApi { @@ -74,6 +102,23 @@ pub trait MmrApi { leaf_index: LeafIndex, at: Option, ) -> Result>; + + /// Generate MMR proof for the given leaf indices. + /// + /// This method calls into a runtime with MMR pallet included and attempts to generate + /// MMR proof for a set of leaves at the given `leaf_indices`. + /// Optionally, a block hash at which the runtime should be queried can be specified. + /// + /// Returns the leaves and a proof for these leaves (compact encoding, i.e. hash of + /// the leaves). Both parameters are SCALE-encoded. + /// The order of entries in the `leaves` field of the returned struct + /// is the same as the order of the entries in `leaf_indices` supplied + #[rpc(name = "mmr_generateBatchProof")] + fn generate_batch_proof( + &self, + leaf_indices: Vec, + at: Option, + ) -> Result>; } /// An implementation of MMR specific RPC methods. @@ -117,6 +162,28 @@ where Ok(LeafProof::new(block_hash, leaf, proof)) } + + fn generate_batch_proof( + &self, + leaf_indices: Vec, + at: Option<::Hash>, + ) -> Result::Hash>> { + let api = self.client.runtime_api(); + let block_hash = at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash); + + let (leaves, proof) = api + .generate_batch_proof_with_context( + &BlockId::hash(block_hash), + sp_core::ExecutionContext::OffchainCall(None), + leaf_indices, + ) + .map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; + + Ok(LeafBatchProof::new(block_hash, leaves, proof)) + } } const RUNTIME_ERROR: i64 = 8000; @@ -179,6 +246,28 @@ mod tests { ); } + #[test] + fn should_serialize_leaf_batch_proof() { + // given + let leaf = vec![1_u8, 2, 3, 4]; + let proof = BatchProof { + leaf_indices: vec![1], + leaf_count: 9, + items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], + }; + + let leaf_proof = LeafBatchProof::new(H256::repeat_byte(0), vec![leaf], proof); + + // when + let actual = serde_json::to_string(&leaf_proof).unwrap(); + + // then + assert_eq!( + actual, + r#"{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","leaves":"0x041001020304","proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"}"# + ); + } + #[test] fn should_deserialize_leaf_proof() { // given @@ -205,4 +294,31 @@ mod tests { // then assert_eq!(actual, expected); } + + #[test] + fn should_deserialize_leaf_batch_proof() { + // given + let expected = LeafBatchProof { + block_hash: H256::repeat_byte(0), + leaves: Bytes(vec![vec![1_u8, 2, 3, 4]].encode()), + proof: Bytes( + BatchProof { + leaf_indices: vec![1], + leaf_count: 9, + items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], + } + .encode(), + ), + }; + + // when + let actual: LeafBatchProof = serde_json::from_str(r#"{ + "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "leaves":"0x041001020304", + "proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202" + }"#).unwrap(); + + // then + assert_eq!(actual, expected); + } } diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 855eb0a7436dc..d6cf3240692fc 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -71,6 +71,7 @@ mod tests; pub use pallet::*; pub use sp_mmr_primitives::{self as primitives, Error, LeafDataProvider, LeafIndex, NodeIndex}; +use sp_std::prelude::*; /// The most common use case for MMRs is to store historical block hashes, /// so that any point in time in the future we can receive a proof about some past @@ -228,22 +229,23 @@ type LeafOf = <>::LeafData as primitives::LeafDataProvider> /// Hashing used for the pallet. pub(crate) type HashingOf = >::Hashing; -/// Stateless MMR proof verification. +/// Stateless MMR proof verification for batch of leaves. /// -/// This function can be used to verify received MMR proof (`proof`) -/// for given leaf data (`leaf`) against a known MMR root hash (`root`). -/// -/// The verification does not require any storage access. -pub fn verify_leaf_proof( +/// This function can be used to verify received MMR [primitives::BatchProof] (`proof`) +/// for given leaves set (`leaves`) against a known MMR root hash (`root`). +/// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the +/// same position in both the `leaves` vector and the `leaf_indices` vector contained in the +/// [primitives::BatchProof]. +pub fn verify_leaves_proof( root: H::Output, - leaf: mmr::Node, - proof: primitives::Proof, + leaves: Vec>, + proof: primitives::BatchProof, ) -> Result<(), primitives::Error> where H: traits::Hash, L: primitives::FullLeaf, { - let is_valid = mmr::verify_leaf_proof::(root, leaf, proof)?; + let is_valid = mmr::verify_leaves_proof::(root, leaves, proof)?; if is_valid { Ok(()) } else { @@ -255,29 +257,36 @@ impl, I: 'static> Pallet { fn offchain_key(pos: NodeIndex) -> sp_std::prelude::Vec { (T::INDEXING_PREFIX, pos).encode() } - - /// Generate a MMR proof for the given `leaf_index`. + /// Generate a MMR proof for the given `leaf_indices`. /// /// Note this method can only be used from an off-chain context /// (Offchain Worker or Runtime API call), since it requires /// all the leaves to be present. /// It may return an error or panic if used incorrectly. - pub fn generate_proof( - leaf_index: LeafIndex, - ) -> Result<(LeafOf, primitives::Proof<>::Hash>), primitives::Error> { + pub fn generate_batch_proof( + leaf_indices: Vec, + ) -> Result< + (Vec>, primitives::BatchProof<>::Hash>), + primitives::Error, + > { let mmr: ModuleMmr = mmr::Mmr::new(Self::mmr_leaves()); - mmr.generate_proof(leaf_index) + mmr.generate_batch_proof(leaf_indices) + } + + /// Return the on-chain MMR root hash. + pub fn mmr_root() -> >::Hash { + Self::mmr_root_hash() } - /// Verify MMR proof for given `leaf`. + /// Verify MMR proof for given `leaves`. /// /// This method is safe to use within the runtime code. /// It will return `Ok(())` if the proof is valid /// and an `Err(..)` if MMR is inconsistent (some leaves are missing) /// or the proof is invalid. - pub fn verify_leaf( - leaf: LeafOf, - proof: primitives::Proof<>::Hash>, + pub fn verify_leaves( + leaves: Vec>, + proof: primitives::BatchProof<>::Hash>, ) -> Result<(), primitives::Error> { if proof.leaf_count > Self::mmr_leaves() || proof.leaf_count == 0 || @@ -288,16 +297,11 @@ impl, I: 'static> Pallet { } let mmr: ModuleMmr = mmr::Mmr::new(proof.leaf_count); - let is_valid = mmr.verify_leaf_proof(leaf, proof)?; + let is_valid = mmr.verify_leaves_proof(leaves, proof)?; if is_valid { Ok(()) } else { Err(primitives::Error::Verify.log_debug("The proof is incorrect.")) } } - - /// Return the on-chain MMR root hash. - pub fn mmr_root() -> >::Hash { - Self::mmr_root_hash() - } } diff --git a/frame/merkle-mountain-range/src/mmr/mmr.rs b/frame/merkle-mountain-range/src/mmr/mmr.rs index a1516ee8607f4..44e684c1bdcac 100644 --- a/frame/merkle-mountain-range/src/mmr/mmr.rs +++ b/frame/merkle-mountain-range/src/mmr/mmr.rs @@ -24,27 +24,39 @@ use crate::{ primitives::{self, Error, NodeIndex}, Config, HashingOf, }; -#[cfg(not(feature = "std"))] -use sp_std::vec; +use sp_std::prelude::*; -/// Stateless verification of the leaf proof. -pub fn verify_leaf_proof( +/// Stateless verification of the proof for a batch of leaves. +/// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the +/// same position in both the `leaves` vector and the `leaf_indices` vector contained in the +/// [primitives::BatchProof] +pub fn verify_leaves_proof( root: H::Output, - leaf: Node, - proof: primitives::Proof, + leaves: Vec>, + proof: primitives::BatchProof, ) -> Result where H: sp_runtime::traits::Hash, L: primitives::FullLeaf, { let size = NodesUtils::new(proof.leaf_count).size(); - let leaf_position = mmr_lib::leaf_index_to_pos(proof.leaf_index); + + if leaves.len() != proof.leaf_indices.len() { + return Err(Error::Verify.log_debug("Proof leaf_indices not same length with leaves")) + } + + let leaves_and_position_data = proof + .leaf_indices + .into_iter() + .map(|index| mmr_lib::leaf_index_to_pos(index)) + .zip(leaves.into_iter()) + .collect(); let p = mmr_lib::MerkleProof::, Hasher>::new( size, proof.items.into_iter().map(Node::Hash).collect(), ); - p.verify(Node::Hash(root), vec![(leaf_position, leaf)]) + p.verify(Node::Hash(root), leaves_and_position_data) .map_err(|e| Error::Verify.log_debug(e)) } @@ -76,19 +88,32 @@ where Self { mmr: mmr_lib::MMR::new(size, Default::default()), leaves } } - /// Verify proof of a single leaf. - pub fn verify_leaf_proof( + /// Verify proof for a set of leaves. + /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have + /// the same position in both the `leaves` vector and the `leaf_indices` vector contained in the + /// [primitives::BatchProof] + pub fn verify_leaves_proof( &self, - leaf: L, - proof: primitives::Proof<>::Hash>, + leaves: Vec, + proof: primitives::BatchProof<>::Hash>, ) -> Result { let p = mmr_lib::MerkleProof::, Hasher, L>>::new( self.mmr.mmr_size(), proof.items.into_iter().map(Node::Hash).collect(), ); - let position = mmr_lib::leaf_index_to_pos(proof.leaf_index); + + if leaves.len() != proof.leaf_indices.len() { + return Err(Error::Verify.log_debug("Proof leaf_indices not same length with leaves")) + } + + let leaves_positions_and_data = proof + .leaf_indices + .into_iter() + .map(|index| mmr_lib::leaf_index_to_pos(index)) + .zip(leaves.into_iter().map(|leaf| Node::Data(leaf))) + .collect(); let root = self.mmr.get_root().map_err(|e| Error::GetRoot.log_error(e))?; - p.verify(root, vec![(position, Node::Data(leaf))]) + p.verify(root, leaves_positions_and_data) .map_err(|e| Error::Verify.log_debug(e)) } @@ -134,29 +159,36 @@ where I: 'static, L: primitives::FullLeaf + codec::Decode, { - /// Generate a proof for given leaf index. + /// Generate a proof for given leaf indices. /// /// Proof generation requires all the nodes (or their hashes) to be available in the storage. /// (i.e. you can't run the function in the pruned storage). - pub fn generate_proof( + pub fn generate_batch_proof( &self, - leaf_index: NodeIndex, - ) -> Result<(L, primitives::Proof<>::Hash>), Error> { - let position = mmr_lib::leaf_index_to_pos(leaf_index); + leaf_indices: Vec, + ) -> Result<(Vec, primitives::BatchProof<>::Hash>), Error> { + let positions = leaf_indices + .iter() + .map(|index| mmr_lib::leaf_index_to_pos(*index)) + .collect::>(); let store = >::default(); - let leaf = match mmr_lib::MMRStore::get_elem(&store, position) { - Ok(Some(Node::Data(leaf))) => leaf, - e => return Err(Error::LeafNotFound.log_debug(e)), - }; + let leaves = positions + .iter() + .map(|pos| match mmr_lib::MMRStore::get_elem(&store, *pos) { + Ok(Some(Node::Data(leaf))) => Ok(leaf), + e => Err(Error::LeafNotFound.log_debug(e)), + }) + .collect::, Error>>()?; + let leaf_count = self.leaves; self.mmr - .gen_proof(vec![position]) + .gen_proof(positions) .map_err(|e| Error::GenerateProof.log_error(e)) - .map(|p| primitives::Proof { - leaf_index, + .map(|p| primitives::BatchProof { + leaf_indices, leaf_count, items: p.proof_items().iter().map(|x| x.hash()).collect(), }) - .map(|p| (leaf, p)) + .map(|p| (leaves, p)) } } diff --git a/frame/merkle-mountain-range/src/mmr/mod.rs b/frame/merkle-mountain-range/src/mmr/mod.rs index 1cb4e8535b991..04fdfa199e72b 100644 --- a/frame/merkle-mountain-range/src/mmr/mod.rs +++ b/frame/merkle-mountain-range/src/mmr/mod.rs @@ -22,7 +22,7 @@ pub mod utils; use sp_mmr_primitives::{DataOrHash, FullLeaf}; use sp_runtime::traits; -pub use self::mmr::{verify_leaf_proof, Mmr}; +pub use self::mmr::{verify_leaves_proof, Mmr}; /// Node type for runtime `T`. pub type NodeOf = Node<>::Hashing, L>; diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 70d1395aa94d5..d025910a9ee5c 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -23,7 +23,7 @@ use sp_core::{ offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt}, H256, }; -use sp_mmr_primitives::{Compact, Proof}; +use sp_mmr_primitives::{BatchProof, Compact}; pub(crate) fn new_test_ext() -> sp_io::TestExternalities { frame_system::GenesisConfig::default().build_storage::().unwrap().into() @@ -225,16 +225,18 @@ fn should_generate_proofs_correctly() { // when generate proofs for all leaves let proofs = (0_u64..crate::NumberOfLeaves::::get()) .into_iter() - .map(|leaf_index| crate::Pallet::::generate_proof(leaf_index).unwrap()) + .map(|leaf_index| { + crate::Pallet::::generate_batch_proof(vec![leaf_index]).unwrap() + }) .collect::>(); // then assert_eq!( proofs[0], ( - Compact::new(((0, H256::repeat_byte(1)).into(), LeafData::new(1).into(),)), - Proof { - leaf_index: 0, + vec![Compact::new(((0, H256::repeat_byte(1)).into(), LeafData::new(1).into(),))], + BatchProof { + leaf_indices: vec![0], leaf_count: 7, items: vec![ hex("ad4cbc033833612ccd4626d5f023b9dfc50a35e838514dd1f3c86f8506728705"), @@ -247,9 +249,9 @@ fn should_generate_proofs_correctly() { assert_eq!( proofs[4], ( - Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),)), - Proof { - leaf_index: 4, + vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], + BatchProof { + leaf_indices: vec![4], leaf_count: 7, items: vec![ hex("ae88a0825da50e953e7a359c55fe13c8015e48d03d301b8bdfc9193874da9252"), @@ -262,9 +264,9 @@ fn should_generate_proofs_correctly() { assert_eq!( proofs[6], ( - Compact::new(((6, H256::repeat_byte(7)).into(), LeafData::new(7).into(),)), - Proof { - leaf_index: 6, + vec![Compact::new(((6, H256::repeat_byte(7)).into(), LeafData::new(7).into(),))], + BatchProof { + leaf_indices: vec![6], leaf_count: 7, items: vec![ hex("ae88a0825da50e953e7a359c55fe13c8015e48d03d301b8bdfc9193874da9252"), @@ -276,6 +278,37 @@ fn should_generate_proofs_correctly() { }); } +#[test] +fn should_generate_batch_proof_correctly() { + let _ = env_logger::try_init(); + let mut ext = new_test_ext(); + // given + ext.execute_with(|| init_chain(7)); + ext.persist_offchain_overlay(); + + // Try to generate proofs now. This requires the offchain extensions to be present + // to retrieve full leaf data. + register_offchain_ext(&mut ext); + ext.execute_with(|| { + // when generate proofs for all leaves + let (.., proof) = crate::Pallet::::generate_batch_proof(vec![0, 4, 5]).unwrap(); + + // then + assert_eq!( + proof, + BatchProof { + leaf_indices: vec![0, 4, 5], + leaf_count: 7, + items: vec![ + hex("ad4cbc033833612ccd4626d5f023b9dfc50a35e838514dd1f3c86f8506728705"), + hex("cb24f4614ad5b2a5430344c99545b421d9af83c46fd632d70a332200884b4d46"), + hex("611c2174c6164952a66d985cfe1ec1a623794393e3acff96b136d198f37a648c"), + ], + } + ); + }); +} + #[test] fn should_verify() { let _ = env_logger::try_init(); @@ -289,15 +322,40 @@ fn should_verify() { // Try to generate proof now. This requires the offchain extensions to be present // to retrieve full leaf data. register_offchain_ext(&mut ext); - let (leaf, proof5) = ext.execute_with(|| { + let (leaves, proof5) = ext.execute_with(|| { + // when + crate::Pallet::::generate_batch_proof(vec![5]).unwrap() + }); + + ext.execute_with(|| { + init_chain(7); + // then + assert_eq!(crate::Pallet::::verify_leaves(leaves, proof5), Ok(())); + }); +} + +#[test] +fn should_verify_batch_proof() { + let _ = env_logger::try_init(); + + // Start off with chain initialisation and storing indexing data off-chain + // (MMR Leafs) + let mut ext = new_test_ext(); + ext.execute_with(|| init_chain(7)); + ext.persist_offchain_overlay(); + + // Try to generate proof now. This requires the offchain extensions to be present + // to retrieve full leaf data. + register_offchain_ext(&mut ext); + let (leaves, proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_proof(5).unwrap() + crate::Pallet::::generate_batch_proof(vec![0, 4, 5]).unwrap() }); ext.execute_with(|| { init_chain(7); // then - assert_eq!(crate::Pallet::::verify_leaf(leaf, proof5), Ok(())); + assert_eq!(crate::Pallet::::verify_leaves(leaves, proof), Ok(())); }); } @@ -314,16 +372,49 @@ fn verification_should_be_stateless() { // Try to generate proof now. This requires the offchain extensions to be present // to retrieve full leaf data. register_offchain_ext(&mut ext); - let (leaf, proof5) = ext.execute_with(|| { + let (leaves, proof5) = ext.execute_with(|| { + // when + crate::Pallet::::generate_batch_proof(vec![5]).unwrap() + }); + let root = ext.execute_with(|| crate::Pallet::::mmr_root_hash()); + + // Verify proof without relying on any on-chain data. + let leaf = crate::primitives::DataOrHash::Data(leaves[0].clone()); + assert_eq!( + crate::verify_leaves_proof::<::Hashing, _>(root, vec![leaf], proof5), + Ok(()) + ); +} + +#[test] +fn should_verify_batch_proof_statelessly() { + let _ = env_logger::try_init(); + + // Start off with chain initialisation and storing indexing data off-chain + // (MMR Leafs) + let mut ext = new_test_ext(); + ext.execute_with(|| init_chain(7)); + ext.persist_offchain_overlay(); + + // Try to generate proof now. This requires the offchain extensions to be present + // to retrieve full leaf data. + register_offchain_ext(&mut ext); + let (leaves, proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_proof(5).unwrap() + crate::Pallet::::generate_batch_proof(vec![0, 4, 5]).unwrap() }); let root = ext.execute_with(|| crate::Pallet::::mmr_root_hash()); // Verify proof without relying on any on-chain data. - let leaf = crate::primitives::DataOrHash::Data(leaf); assert_eq!( - crate::verify_leaf_proof::<::Hashing, _>(root, leaf, proof5), + crate::verify_leaves_proof::<::Hashing, _>( + root, + leaves + .into_iter() + .map(|leaf| crate::primitives::DataOrHash::Data(leaf)) + .collect(), + proof + ), Ok(()) ); } @@ -340,10 +431,10 @@ fn should_verify_on_the_next_block_since_there_is_no_pruning_yet() { ext.execute_with(|| { // when - let (leaf, proof5) = crate::Pallet::::generate_proof(5).unwrap(); + let (leaves, proof5) = crate::Pallet::::generate_batch_proof(vec![5]).unwrap(); new_block(); // then - assert_eq!(crate::Pallet::::verify_leaf(leaf, proof5), Ok(())); + assert_eq!(crate::Pallet::::verify_leaves(leaves, proof5), Ok(())); }); } diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 60ef02c53001c..5a339d069062c 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -22,9 +22,9 @@ use sp_debug_derive::RuntimeDebug; use sp_runtime::traits; -use sp_std::fmt; #[cfg(not(feature = "std"))] use sp_std::prelude::Vec; +use sp_std::{fmt, vec}; /// A type to describe node position in the MMR (node index). pub type NodeIndex = u64; @@ -351,6 +351,38 @@ impl_leaf_data_for_tuple!(A:0, B:1, C:2); impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3); impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3, E:4); +/// A MMR proof data for a group of leaves. +#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq)] +pub struct BatchProof { + /// The indices of the leaves the proof is for. + pub leaf_indices: Vec, + /// Number of leaves in MMR, when the proof was generated. + pub leaf_count: NodeIndex, + /// Proof elements (hashes of siblings of inner nodes on the path to the leaf). + pub items: Vec, +} + +impl BatchProof { + /// Converts batch proof to single leaf proof + pub fn into_single_leaf_proof(proof: BatchProof) -> Result, Error> { + Ok(Proof { + leaf_index: *proof.leaf_indices.get(0).ok_or(Error::InvalidLeafIndex)?, + leaf_count: proof.leaf_count, + items: proof.items, + }) + } +} + +impl Proof { + /// Converts a single leaf proof into a batch proof + pub fn into_batch_proof(proof: Proof) -> BatchProof { + BatchProof { + leaf_indices: vec![proof.leaf_index], + leaf_count: proof.leaf_count, + items: proof.items, + } + } +} /// Merkle Mountain Range operation error. #[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] pub enum Error { @@ -366,6 +398,10 @@ pub enum Error { Verify, /// Leaf not found in the storage. LeafNotFound, + /// Mmr Pallet not included in runtime + PalletNotIncluded, + /// Cannot find the requested leaf index + InvalidLeafIndex, } impl Error { @@ -417,6 +453,27 @@ sp_api::decl_runtime_apis! { /// Return the on-chain MMR root hash. fn mmr_root() -> Result; + + /// Generate MMR proof for a series of leaves under given indices. + fn generate_batch_proof(leaf_indices: Vec) -> Result<(Vec, BatchProof), Error>; + + /// Verify MMR proof against on-chain MMR for a batch of leaves. + /// + /// Note this function will use on-chain MMR root hash and check if the proof + /// matches the hash. + /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the + /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [BatchProof] + fn verify_batch_proof(leaves: Vec, proof: BatchProof) -> Result<(), Error>; + + /// Verify MMR proof against given root hash or a batch of leaves. + /// + /// Note this function does not require any on-chain storage - the + /// proof is verified against given MMR root hash. + /// + /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the + /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [BatchProof] + fn verify_batch_proof_stateless(root: Hash, leaves: Vec, proof: BatchProof) + -> Result<(), Error>; } } From 8fbed21e5a4785128cdd7fe28513f7230c17ec6d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 4 May 2022 14:17:24 +0100 Subject: [PATCH 0761/1472] fix a few things with nomination pools (#11343) * fix a few things with nomination pools * fix typo * fix build * add missing try-runtime feat --- frame/nomination-pools/Cargo.toml | 1 + frame/nomination-pools/src/lib.rs | 25 +- frame/nomination-pools/src/tests.rs | 341 +++++++++++++++++++++++++++- 3 files changed, 356 insertions(+), 11 deletions(-) diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index 882a6f363a14f..8c2f9daf2777b 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -31,6 +31,7 @@ sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } [features] runtime-benchmarks = [] +try-runtime = [] default = ["std"] std = [ "codec/std", diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index bafed9fc2f5b4..8b26bad6c7df8 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -403,7 +403,6 @@ pub struct PoolMember { } impl PoolMember { - #[cfg(any(test, debug_assertions))] fn total_points(&self) -> BalanceOf { self.active_points().saturating_add(self.unbonding_points()) } @@ -739,6 +738,14 @@ impl BondedPool { ) -> Result<(), DispatchError> { let is_permissioned = caller == target_account; let is_depositor = *target_account == self.roles.depositor; + let is_full_unbond = unbonding_points == target_member.active_points(); + + // any partial unbonding is only ever allowed if this unbond is permissioned. + ensure!( + is_permissioned || is_full_unbond, + Error::::PartialUnbondNotAllowedPermissionlessly + ); + match (is_permissioned, is_depositor) { // If the pool is blocked, then an admin with kicking permissions can remove a // member. If the pool is being destroyed, anyone can remove a member @@ -1198,6 +1205,10 @@ pub mod pallet { Destroyed { pool_id: PoolId }, /// The state of a pool has changed StateChanged { pool_id: PoolId, new_state: PoolState }, + /// A member has been removed from a pool. + /// + /// The removal can be voluntary (withdrawn all unbonded funds) or involuntary (kicked). + MemberRemoved { pool_id: PoolId, member: T::AccountId }, } #[pallet::error] @@ -1256,6 +1267,8 @@ pub mod pallet { DefensiveError, /// Not enough points. Ty unbonding less. NotEnoughPointsToUnbond, + /// Partial unbonding now allowed permissionlessly. + PartialUnbondNotAllowedPermissionlessly, } #[pallet::call] @@ -1595,9 +1608,13 @@ pub mod pallet { amount: balance_to_unbond, }); - let post_info_weight = if member.active_points().is_zero() { + let post_info_weight = if member.total_points().is_zero() { // member being reaped. PoolMembers::::remove(&member_account); + Self::deposit_event(Event::::MemberRemoved { + pool_id: member.pool_id, + member: member_account.clone(), + }); if member_account == bonded_pool.roles.depositor { Pallet::::dissolve_pool(bonded_pool); @@ -2044,6 +2061,10 @@ impl Pallet { let member_payout = Self::calculate_member_payout(member, bonded_pool, reward_pool)?; + if member_payout.is_zero() { + return Ok(member_payout) + } + // Transfer payout to the member. T::Currency::transfer( &bonded_pool.reward_account(), diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 7df922280873b..cd66c3d774960 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -1386,6 +1386,17 @@ mod unbond { } } ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, + Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, + Event::PaidOut { member: 40, pool_id: 1, payout: 40 }, + Event::Unbonded { member: 40, pool_id: 1, amount: 6 } + ] + ); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 94); assert_eq!( @@ -1421,6 +1432,13 @@ mod unbond { member_unbonding_eras!(0 + 3 => 550) ); assert_eq!(Balances::free_balance(&550), 550 + 550); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 550, pool_id: 1, payout: 550 }, + Event::Unbonded { member: 550, pool_id: 1, amount: 92 } + ] + ); // When assert_ok!(fully_unbond_permissioned(10)); @@ -1448,6 +1466,13 @@ mod unbond { member_unbonding_eras!(0 + 3 => 550) ); assert_eq!(Balances::free_balance(&550), 550 + 550); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 10 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 2 } + ] + ); }); } @@ -1485,7 +1510,15 @@ mod unbond { current_era + 3 => UnbondPool { balance: 10, points: 10 }, }, }, - ) + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Unbonded { member: 10, pool_id: 1, amount: 10 } + ] + ); }); } @@ -1502,7 +1535,7 @@ mod unbond { assert_eq!(bonded_pool.roles.nominator, 901); assert_eq!(bonded_pool.roles.state_toggler, 902); - // When the nominator trys to kick, then its a noop + // When the nominator tries to kick, then its a noop assert_noop!( Pools::fully_unbond(Origin::signed(901), 100), Error::::NotKickerOrDestroying @@ -1511,9 +1544,25 @@ mod unbond { // When the root kicks then its ok assert_ok!(Pools::fully_unbond(Origin::signed(900), 100)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, + Event::Bonded { member: 200, pool_id: 1, bonded: 200, joined: true }, + Event::Unbonded { member: 100, pool_id: 1, amount: 100 }, + ] + ); + // When the state toggler kicks then its ok assert_ok!(Pools::fully_unbond(Origin::signed(902), 200)); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 200, pool_id: 1, amount: 200 }] + ); + assert_eq!( BondedPool::::get(1).unwrap(), BondedPool { @@ -1557,6 +1606,12 @@ mod unbond { Error::::NotKickerOrDestroying ); + // permissionless unbond must be full + assert_noop!( + Pools::unbond(Origin::signed(420), 100, 80), + Error::::PartialUnbondNotAllowedPermissionlessly, + ); + // Given the pool is destroying unsafe_set_state(1, PoolState::Destroying).unwrap(); @@ -1568,6 +1623,21 @@ mod unbond { // Any account can unbond a member that is not the depositor assert_ok!(Pools::fully_unbond(Origin::signed(420), 100)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, + Event::Unbonded { member: 100, pool_id: 1, amount: 100 } + ] + ); + + // still permissionless unbond must be full + assert_noop!( + Pools::unbond(Origin::signed(420), 100, 80), + Error::::PartialUnbondNotAllowedPermissionlessly, + ); // Given the pool is blocked unsafe_set_state(1, PoolState::Blocked).unwrap(); @@ -1584,6 +1654,17 @@ mod unbond { // The depositor can be unbonded by anyone. assert_ok!(Pools::fully_unbond(Origin::signed(420), 10)); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 10, pool_id: 1, amount: 10 }] + ); + + // still permissionless unbond must be full. + assert_noop!( + Pools::unbond(Origin::signed(420), 10, 5), + Error::::PartialUnbondNotAllowedPermissionlessly, + ); + assert_eq!(BondedPools::::get(1).unwrap().points, 0); assert_eq!( SubPoolsStorage::::get(1).unwrap(), @@ -1682,6 +1763,14 @@ mod unbond { } } ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Unbonded { member: 10, pool_id: 1, amount: 1 } + ] + ); // when: casual further unbond, same era. assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); @@ -1703,6 +1792,10 @@ mod unbond { } } ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 10, pool_id: 1, amount: 5 }] + ); // when: casual further unbond, next era. CurrentEra::set(1); @@ -1726,6 +1819,10 @@ mod unbond { } } ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 10, pool_id: 1, amount: 1 }] + ); // when: unbonding more than our active: error assert_noop!( @@ -1753,6 +1850,10 @@ mod unbond { } } ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 10, pool_id: 1, amount: 3 }] + ); }); } @@ -1786,6 +1887,16 @@ mod unbond { PoolMembers::::get(10).unwrap().unbonding_eras, member_unbonding_eras!(3 => 2, 4 => 3, 5 => 1) ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Unbonded { member: 10, pool_id: 1, amount: 2 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 3 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 1 } + ] + ); }) } @@ -1808,6 +1919,15 @@ mod unbond { Pools::unbond(Origin::signed(10), 10, 6), Error::::NotOnlyPoolMember ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, + Event::Unbonded { member: 10, pool_id: 1, amount: 3 } + ] + ); }); } @@ -1828,6 +1948,14 @@ mod unbond { Pools::unbond(Origin::signed(10), 10, 7), Error::::NotOnlyPoolMember ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true } + ] + ); }); } } @@ -1944,6 +2072,26 @@ mod withdraw_unbonded { assert!(!SubPoolsStorage::::contains_key(1),); assert!(!RewardPools::::contains_key(1),); assert!(!BondedPools::::contains_key(1),); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, + Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, + Event::Unbonded { member: 550, pool_id: 1, amount: 550 }, + Event::Unbonded { member: 40, pool_id: 1, amount: 40 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 10 }, + Event::Withdrawn { member: 550, pool_id: 1, amount: 545 }, + Event::MemberRemoved { pool_id: 1, member: 550 }, + Event::Withdrawn { member: 40, pool_id: 1, amount: 40 }, + Event::MemberRemoved { pool_id: 1, member: 40 }, + Event::Withdrawn { member: 10, pool_id: 1, amount: 10 }, + Event::MemberRemoved { pool_id: 1, member: 10 }, + Event::Destroyed { pool_id: 1 } + ] + ); }); } @@ -2006,9 +2154,29 @@ mod withdraw_unbonded { assert_eq!(Balances::free_balance(&default_bonded_account()), 0); assert!(!PoolMembers::::contains_key(10)); // Pools are removed from storage because the depositor left - assert!(!SubPoolsStorage::::contains_key(1),); - assert!(!RewardPools::::contains_key(1),); - assert!(!BondedPools::::contains_key(1),); + assert!(!SubPoolsStorage::::contains_key(1)); + assert!(!RewardPools::::contains_key(1)); + assert!(!BondedPools::::contains_key(1)); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, + Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, + Event::Unbonded { member: 40, pool_id: 1, amount: 6 }, + Event::Unbonded { member: 550, pool_id: 1, amount: 92 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 2 }, + Event::Withdrawn { member: 40, pool_id: 1, amount: 6 }, + Event::MemberRemoved { pool_id: 1, member: 40 }, + Event::Withdrawn { member: 550, pool_id: 1, amount: 92 }, + Event::MemberRemoved { pool_id: 1, member: 550 }, + Event::Withdrawn { member: 10, pool_id: 1, amount: 0 }, + Event::MemberRemoved { pool_id: 1, member: 10 }, + Event::Destroyed { pool_id: 1 } + ] + ); }); } @@ -2103,6 +2271,17 @@ mod withdraw_unbonded { Pools::withdraw_unbonded(Origin::signed(902), 100, 0), Error::::NotKickerOrDestroying ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, + Event::Bonded { member: 200, pool_id: 1, bonded: 200, joined: true }, + Event::Unbonded { member: 100, pool_id: 1, amount: 100 }, + Event::Unbonded { member: 200, pool_id: 1, amount: 200 } + ] + ); // Given unsafe_set_state(1, PoolState::Blocked).unwrap(); @@ -2124,6 +2303,15 @@ mod withdraw_unbonded { assert!(!PoolMembers::::contains_key(100)); assert!(!PoolMembers::::contains_key(200)); assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default()); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Withdrawn { member: 100, pool_id: 1, amount: 100 }, + Event::MemberRemoved { pool_id: 1, member: 100 }, + Event::Withdrawn { member: 200, pool_id: 1, amount: 200 }, + Event::MemberRemoved { pool_id: 1, member: 200 } + ] + ); }); } @@ -2162,6 +2350,17 @@ mod withdraw_unbonded { assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default(),); assert_eq!(Balances::free_balance(100), 100 + 100); assert!(!PoolMembers::::contains_key(100)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, + Event::Unbonded { member: 100, pool_id: 1, amount: 100 }, + Event::Withdrawn { member: 100, pool_id: 1, amount: 100 }, + Event::MemberRemoved { pool_id: 1, member: 100 } + ] + ); }); } @@ -2240,6 +2439,26 @@ mod withdraw_unbonded { assert!(!SubPoolsStorage::::contains_key(1)); assert!(!RewardPools::::contains_key(1)); assert!(!BondedPools::::contains_key(1)); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, + Event::Bonded { member: 200, pool_id: 1, bonded: 200, joined: true }, + Event::Unbonded { member: 100, pool_id: 1, amount: 100 }, + Event::Unbonded { member: 200, pool_id: 1, amount: 200 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 10 }, + Event::Withdrawn { member: 100, pool_id: 1, amount: 100 }, + Event::MemberRemoved { pool_id: 1, member: 100 }, + Event::Withdrawn { member: 200, pool_id: 1, amount: 200 }, + Event::MemberRemoved { pool_id: 1, member: 200 }, + Event::Withdrawn { member: 10, pool_id: 1, amount: 10 }, + Event::MemberRemoved { pool_id: 1, member: 10 }, + Event::Destroyed { pool_id: 1 } + ] + ); }); } @@ -2325,9 +2544,7 @@ mod withdraw_unbonded { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::PaidOut { member: 10, pool_id: 1, payout: 0 }, Event::Unbonded { member: 10, pool_id: 1, amount: 6 }, - Event::PaidOut { member: 10, pool_id: 1, payout: 0 }, Event::Unbonded { member: 10, pool_id: 1, amount: 1 } ] ); @@ -2414,9 +2631,7 @@ mod withdraw_unbonded { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 11, pool_id: 1, bonded: 10, joined: true }, - Event::PaidOut { member: 11, pool_id: 1, payout: 0 }, Event::Unbonded { member: 11, pool_id: 1, amount: 6 }, - Event::PaidOut { member: 11, pool_id: 1, payout: 0 }, Event::Unbonded { member: 11, pool_id: 1, amount: 1 } ] ); @@ -2473,6 +2688,114 @@ mod withdraw_unbonded { ); }); } + + #[test] + fn full_multi_step_withdrawing_non_depositor() { + ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { + // given + assert_ok!(Pools::unbond(Origin::signed(100), 100, 75)); + assert_eq!( + PoolMembers::::get(100).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 75) + ); + + // progress one era and unbond the leftover. + CurrentEra::set(1); + assert_ok!(Pools::unbond(Origin::signed(100), 100, 25)); + assert_eq!( + PoolMembers::::get(100).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 75, 4 => 25) + ); + + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(100), 100, 0), + Error::::CannotWithdrawAny + ); + + // now the 75 should be free. + CurrentEra::set(3); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(100), 100, 0)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, + Event::Unbonded { member: 100, pool_id: 1, amount: 75 }, + Event::Unbonded { member: 100, pool_id: 1, amount: 25 }, + Event::Withdrawn { member: 100, pool_id: 1, amount: 75 }, + ] + ); + assert_eq!( + PoolMembers::::get(100).unwrap().unbonding_eras, + member_unbonding_eras!(4 => 25) + ); + + // the 25 should be free now, and the member removed. + CurrentEra::set(4); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(100), 100, 0)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Withdrawn { member: 100, pool_id: 1, amount: 25 }, + Event::MemberRemoved { pool_id: 1, member: 100 } + ] + ); + }) + } + + #[test] + fn full_multi_step_withdrawing_depositor() { + ExtBuilder::default().ed(1).build_and_execute(|| { + // given + assert_ok!(Pools::unbond(Origin::signed(10), 10, 7)); + + // progress one era and unbond the leftover. + CurrentEra::set(1); + unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 7, 4 => 3) + ); + + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(10), 10, 0), + Error::::CannotWithdrawAny + ); + + // now the 7 should be free. + CurrentEra::set(3); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Unbonded { member: 10, pool_id: 1, amount: 7 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 3 }, + Event::Withdrawn { member: 10, pool_id: 1, amount: 7 } + ] + ); + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(4 => 3) + ); + + // the 25 should be free now, and the member removed. + CurrentEra::set(4); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Withdrawn { member: 10, pool_id: 1, amount: 3 }, + Event::MemberRemoved { pool_id: 1, member: 10 }, + // the pool is also destroyed now. + Event::Destroyed { pool_id: 1 }, + ] + ); + }) + } } mod create { From f367d9062ad2566855bff2652df799b4c68859b9 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 4 May 2022 14:38:54 +0100 Subject: [PATCH 0762/1472] Basic TOML Lint (#11348) * basic lint * lint ordering --- bin/node-template/pallets/template/Cargo.toml | 19 +++--- bin/node/executor/Cargo.toml | 8 +-- bin/node/primitives/Cargo.toml | 2 +- bin/node/rpc/Cargo.toml | 8 +-- bin/node/testing/Cargo.toml | 56 ++++++++--------- bin/utils/chain-spec-builder/Cargo.toml | 5 +- client/allocator/Cargo.toml | 4 +- client/api/Cargo.toml | 24 ++++---- client/authority-discovery/Cargo.toml | 8 +-- client/basic-authorship/Cargo.toml | 18 +++--- client/beefy/Cargo.toml | 35 +++++------ client/beefy/rpc/Cargo.toml | 27 ++++----- client/block-builder/Cargo.toml | 15 +++-- client/chain-spec/Cargo.toml | 12 ++-- client/chain-spec/derive/Cargo.toml | 2 - client/cli/Cargo.toml | 3 +- client/consensus/aura/Cargo.toml | 42 ++++++------- client/consensus/babe/Cargo.toml | 56 ++++++++--------- client/consensus/babe/rpc/Cargo.toml | 22 +++---- client/consensus/common/Cargo.toml | 24 ++++---- client/consensus/epochs/Cargo.toml | 6 +- client/consensus/manual-seal/Cargo.toml | 53 ++++++++-------- client/consensus/pow/Cargo.toml | 26 ++++---- client/consensus/slots/Cargo.toml | 20 +++---- client/consensus/uncles/Cargo.toml | 4 +- client/db/Cargo.toml | 29 +++++---- client/executor/common/Cargo.toml | 5 +- client/executor/runtime-test/Cargo.toml | 3 +- client/executor/wasmi/Cargo.toml | 5 +- client/executor/wasmtime/Cargo.toml | 7 +-- client/finality-grandpa/Cargo.toml | 53 ++++++++-------- client/finality-grandpa/rpc/Cargo.toml | 23 +++---- client/informant/Cargo.toml | 2 +- client/keystore/Cargo.toml | 7 +-- client/network-gossip/Cargo.toml | 5 +- client/network/Cargo.toml | 42 ++++++------- client/network/common/Cargo.toml | 4 +- client/network/sync/Cargo.toml | 8 +-- client/network/test/Cargo.toml | 28 ++++----- client/offchain/Cargo.toml | 22 +++---- client/peerset/Cargo.toml | 4 +- client/proposer-metrics/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 11 ++-- client/rpc-servers/Cargo.toml | 8 +-- client/rpc/Cargo.toml | 36 +++++------ client/service/test/Cargo.toml | 40 ++++++------- client/state-db/Cargo.toml | 8 +-- client/sync-state-rpc/Cargo.toml | 8 +-- client/sysinfo/Cargo.toml | 4 +- client/telemetry/Cargo.toml | 7 +-- client/tracing/Cargo.toml | 14 ++--- client/transaction-pool/Cargo.toml | 24 ++++---- client/transaction-pool/api/Cargo.toml | 3 +- client/utils/Cargo.toml | 4 +- frame/atomic-swap/Cargo.toml | 10 ++-- frame/aura/Cargo.toml | 18 +++--- frame/authority-discovery/Cargo.toml | 26 ++++---- frame/authorship/Cargo.toml | 14 ++--- frame/babe/Cargo.toml | 10 ++-- frame/bags-list/fuzzer/Cargo.toml | 5 +- frame/balances/Cargo.toml | 18 +++--- frame/beefy-mmr/Cargo.toml | 60 +++++++++---------- frame/beefy-mmr/primitives/Cargo.toml | 7 ++- frame/beefy/Cargo.toml | 27 ++++----- frame/benchmarking/Cargo.toml | 30 +++++----- frame/bounties/Cargo.toml | 24 ++++---- frame/child-bounties/Cargo.toml | 28 ++++----- frame/collective/Cargo.toml | 16 +++-- frame/conviction-voting/Cargo.toml | 26 ++++---- frame/democracy/Cargo.toml | 24 ++++---- frame/election-provider-support/Cargo.toml | 16 ++--- .../benchmarking/Cargo.toml | 12 ++-- frame/elections-phragmen/Cargo.toml | 24 ++++---- frame/examples/basic/Cargo.toml | 7 +-- frame/examples/offchain-worker/Cargo.toml | 7 +-- frame/examples/parallel/Cargo.toml | 3 +- frame/executive/Cargo.toml | 16 ++--- frame/gilt/Cargo.toml | 20 +++---- frame/grandpa/Cargo.toml | 38 ++++++------ frame/identity/Cargo.toml | 20 +++---- frame/im-online/Cargo.toml | 27 ++++----- frame/indices/Cargo.toml | 21 ++++--- frame/lottery/Cargo.toml | 15 +++-- frame/membership/Cargo.toml | 20 +++---- frame/merkle-mountain-range/Cargo.toml | 18 +++--- frame/merkle-mountain-range/rpc/Cargo.toml | 1 - frame/multisig/Cargo.toml | 13 ++-- frame/nicks/Cargo.toml | 14 ++--- frame/node-authorization/Cargo.toml | 6 +- frame/offences/Cargo.toml | 22 +++---- frame/offences/benchmarking/Cargo.toml | 8 +-- frame/preimage/Cargo.toml | 23 ++++--- frame/proxy/Cargo.toml | 11 ++-- frame/randomness-collective-flip/Cargo.toml | 13 ++-- frame/recovery/Cargo.toml | 18 +++--- frame/referenda/Cargo.toml | 32 +++++----- frame/remark/Cargo.toml | 16 ++--- frame/scheduler/Cargo.toml | 25 ++++---- frame/scored-pool/Cargo.toml | 8 +-- frame/session/Cargo.toml | 29 ++++----- frame/session/benchmarking/Cargo.toml | 22 ++++--- frame/society/Cargo.toml | 18 +++--- frame/staking/reward-curve/Cargo.toml | 6 +- frame/staking/reward-fn/Cargo.toml | 4 +- frame/state-trie-migration/Cargo.toml | 36 +++++------ frame/sudo/Cargo.toml | 12 ++-- frame/support/procedural/Cargo.toml | 4 +- frame/support/procedural/tools/Cargo.toml | 4 +- .../procedural/tools/derive/Cargo.toml | 2 +- frame/support/test/compile_pass/Cargo.toml | 10 ++-- frame/support/test/pallet/Cargo.toml | 2 +- frame/system/Cargo.toml | 20 +++---- frame/system/benchmarking/Cargo.toml | 14 ++--- frame/system/rpc/runtime-api/Cargo.toml | 4 +- frame/timestamp/Cargo.toml | 25 ++++---- frame/tips/Cargo.toml | 20 +++---- frame/transaction-payment/Cargo.toml | 16 +++-- frame/transaction-payment/rpc/Cargo.toml | 3 +- .../rpc/runtime-api/Cargo.toml | 4 +- frame/transaction-storage/Cargo.toml | 20 +++---- frame/treasury/Cargo.toml | 21 +++---- frame/try-runtime/Cargo.toml | 13 ++-- frame/uniques/Cargo.toml | 22 +++---- frame/utility/Cargo.toml | 11 ++-- frame/vesting/Cargo.toml | 18 +++--- frame/whitelist/Cargo.toml | 17 +++--- primitives/application-crypto/test/Cargo.toml | 8 +-- primitives/arithmetic/Cargo.toml | 15 +++-- primitives/arithmetic/fuzzer/Cargo.toml | 4 +- primitives/authority-discovery/Cargo.toml | 12 ++-- primitives/authorship/Cargo.toml | 8 +-- primitives/beefy/Cargo.toml | 13 ++-- primitives/block-builder/Cargo.toml | 10 ++-- primitives/blockchain/Cargo.toml | 8 +-- primitives/consensus/aura/Cargo.toml | 24 ++++---- primitives/consensus/babe/Cargo.toml | 26 ++++---- primitives/consensus/common/Cargo.toml | 10 ++-- primitives/consensus/pow/Cargo.toml | 12 ++-- primitives/consensus/vrf/Cargo.toml | 10 ++-- primitives/core/hashing/Cargo.toml | 9 ++- primitives/core/hashing/proc-macro/Cargo.toml | 8 +-- primitives/database/Cargo.toml | 3 +- primitives/externalities/Cargo.toml | 6 +- primitives/finality-grandpa/Cargo.toml | 13 ++-- primitives/inherents/Cargo.toml | 17 +++--- primitives/keyring/Cargo.toml | 4 +- primitives/keystore/Cargo.toml | 11 ++-- primitives/merkle-mountain-range/Cargo.toml | 3 +- primitives/npos-elections/Cargo.toml | 10 ++-- primitives/npos-elections/fuzzer/Cargo.toml | 3 +- primitives/offchain/Cargo.toml | 4 +- primitives/panic-handler/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 6 +- .../test-wasm-deprecated/Cargo.toml | 6 +- .../runtime-interface/test-wasm/Cargo.toml | 6 +- primitives/runtime-interface/test/Cargo.toml | 10 ++-- primitives/runtime/Cargo.toml | 47 +++++++-------- primitives/sandbox/Cargo.toml | 7 +-- primitives/session/Cargo.toml | 8 +-- primitives/state-machine/Cargo.toml | 34 +++++------ primitives/std/Cargo.toml | 1 - primitives/storage/Cargo.toml | 8 +-- primitives/tasks/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 8 +-- primitives/timestamp/Cargo.toml | 26 ++++---- .../transaction-storage-proof/Cargo.toml | 18 +++--- primitives/trie/Cargo.toml | 20 +++---- primitives/version/Cargo.toml | 20 +++---- primitives/version/proc-macro/Cargo.toml | 4 +- primitives/wasm-interface/Cargo.toml | 12 ++-- scripts/ci/node-template-release/Cargo.toml | 17 +++--- test-utils/Cargo.toml | 4 +- test-utils/client/Cargo.toml | 8 +-- test-utils/derive/Cargo.toml | 4 +- test-utils/runtime/client/Cargo.toml | 18 +++--- .../runtime/transaction-pool/Cargo.toml | 12 ++-- test-utils/test-crate/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 57 +++++++++--------- utils/frame/frame-utilities-cli/Cargo.toml | 9 +-- utils/frame/remote-externalities/Cargo.toml | 16 +++-- utils/frame/rpc/support/Cargo.toml | 10 ++-- utils/frame/rpc/system/Cargo.toml | 16 ++--- utils/frame/try-runtime/cli/Cargo.toml | 16 +++-- utils/prometheus/Cargo.toml | 4 +- utils/wasm-builder/Cargo.toml | 4 +- 186 files changed, 1354 insertions(+), 1450 deletions(-) diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 686dd38b577b1..0647761a62f9c 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-template" version = "4.0.0-dev" description = "FRAME pallet template for defining custom runtime logic." authors = ["Substrate DevHub "] -homepage = "https://substrate.io/" +homepage = "https://substrate.io" edition = "2021" license = "Unlicense" publish = false @@ -17,24 +17,23 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", ] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -frame-support = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/support" } -frame-system = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/system" } -frame-benchmarking = { default-features = false, version = "4.0.0-dev", path = "../../../../frame/benchmarking", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../../../frame/benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../../../frame/support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../../frame/system" } [dev-dependencies] -sp-core = { default-features = false, version = "6.0.0", path = "../../../../primitives/core" } -sp-io = { default-features = false, version = "6.0.0", path = "../../../../primitives/io" } -sp-runtime = { default-features = false, version = "6.0.0", path = "../../../../primitives/runtime" } +sp-core = { version = "6.0.0", default-features = false, path = "../../../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", + "frame-benchmarking/std", "frame-support/std", "frame-system/std", - "frame-benchmarking/std", + "scale-info/std", ] - runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 3425a0df65d9b..909bd19103742 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } scale-info = { version = "2.0.1", features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } @@ -22,10 +23,11 @@ sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } -frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } [dev-dependencies] criterion = "0.3.0" +futures = "0.3.21" +wat = "1.0" frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } node-testing = { version = "3.0.0-dev", path = "../testing" } @@ -36,11 +38,9 @@ pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } pallet-treasury = { version = "4.0.0-dev", path = "../../../frame/treasury" } sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } -wat = "1.0" -futures = "0.3.21" +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [features] wasmtime = ["sc-executor/wasmtime"] diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 711b30d33933d..810b41003109d 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -24,8 +24,8 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../../pri default = ["std"] std = [ "codec/std", - "scale-info/std", "frame-system/std", + "scale-info/std", "sp-application-crypto/std", "sp-core/std", "sp-runtime/std", diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 6c18e70f0d634..f0ae8b42e6398 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -16,23 +16,23 @@ node-primitives = { version = "2.0.0", path = "../primitives" } pallet-contracts-rpc = { version = "4.0.0-dev", path = "../../../frame/contracts/rpc/" } pallet-mmr-rpc = { version = "3.0.0", path = "../../../frame/merkle-mountain-range/rpc/" } pallet-transaction-payment-rpc = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/rpc/" } +sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-consensus-babe = { version = "0.10.0-dev", path = "../../../client/consensus/babe" } sc-consensus-babe-rpc = { version = "0.10.0-dev", path = "../../../client/consensus/babe/rpc" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../../client/consensus/epochs" } -sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../../../client/finality-grandpa" } sc-finality-grandpa-rpc = { version = "0.10.0-dev", path = "../../../client/finality-grandpa/rpc" } -sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } +sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" } sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state-rpc" } +sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } substrate-frame-rpc-system = { version = "4.0.0-dev", path = "../../../utils/frame/rpc/system" } substrate-state-trie-migration-rpc = { version = "4.0.0-dev", path = "../../../utils/frame/rpc/state-trie-migration-rpc/" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index fc072312debaa..c4f97a3e47447 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -13,39 +13,39 @@ publish = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sc-service = { version = "0.10.0-dev", features = [ - "test-helpers", - "db", -], path = "../../../client/service" } -sc-client-db = { version = "0.10.0-dev", path = "../../../client/db/", features = [ - "kvdb-rocksdb", - "parity-db", -] } -sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } -sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } codec = { package = "parity-scale-codec", version = "3.0.0" } -sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +fs_extra = "1" +futures = "0.3.21" +log = "0.4.16" +tempfile = "3.1.0" +frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = [ - "wasmtime", -] } -sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } -substrate-test-client = { version = "2.0.0", path = "../../../test-utils/client" } -pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } pallet-asset-tx-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/asset-tx-payment/" } +pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } +sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } +sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } +sc-client-db = { version = "0.10.0-dev", features = [ + "kvdb-rocksdb", + "parity-db", +], path = "../../../client/db/" } +sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } +sc-executor = { version = "0.10.0-dev", features = [ + "wasmtime", +], path = "../../../client/executor" } +sc-service = { version = "0.10.0-dev", features = [ + "test-helpers", + "db", +], path = "../../../client/service" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/timestamp" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } -sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } -sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -log = "0.4.16" -tempfile = "3.1.0" -fs_extra = "1" -futures = "0.3.21" +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/timestamp" } +substrate-test-client = { version = "2.0.0", path = "../../../test-utils/client" } diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index 1ea1c402151dd..e179a3308dd62 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -17,9 +17,8 @@ targets = ["x86_64-unknown-linux-gnu"] ansi_term = "0.12.1" clap = { version = "3.1.6", features = ["derive"] } rand = "0.8" - -sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } -sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } node-cli = { version = "3.0.0-dev", path = "../../node/cli" } +sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } +sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index 190a150b57fff..ec5c19786b875 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } log = "0.4.16" thiserror = "1.0.30" +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index 8230f0baf3e72..f69549b60c53e 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -15,30 +15,30 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ - "derive", + "derive", ] } -sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sc-executor = { version = "0.10.0-dev", path = "../executor" } -sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } fnv = "1.0.6" futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } -sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } log = "0.4.16" parking_lot = "0.12.0" -sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } +sc-executor = { version = "0.10.0-dev", path = "../executor" } +sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } +sc-utils = { version = "4.0.0-dev", path = "../utils" } +sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } +sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } sp-keystore = { version = "0.12.0", default-features = false, path = "../../primitives/keystore" } -sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } -sp-trie = { version = "6.0.0", path = "../../primitives/trie" } sp-storage = { version = "6.0.0", path = "../../primitives/storage" } -sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } +sp-trie = { version = "6.0.0", path = "../../primitives/trie" } [dev-dependencies] +thiserror = "1.0.30" sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } -thiserror = "1.0.30" diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 0e107b19ce6ab..996e262ba2b44 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -18,24 +18,24 @@ prost-build = "0.9" [dependencies] async-trait = "0.1" -codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0" } -thiserror = "1.0" +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" libp2p = { version = "0.44.0", default-features = false, features = ["kad"] } log = "0.4.16" -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } prost = "0.9" rand = "0.7.2" +thiserror = "1.0" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } +sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-authority-discovery = { version = "4.0.0-dev", path = "../../primitives/authority-discovery" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } [dev-dependencies] quickcheck = "1.0.3" diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 6e0c15e1af2cc..6ef679d7995e6 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -17,20 +17,20 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.16" -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } +sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } +sc-client-api = { version = "4.0.0-dev", path = "../api" } +sc-proposer-metrics = { version = "0.10.0-dev", path = "../proposer-metrics" } +sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } +sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../client/transaction-pool/api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } -sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } -sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../client/transaction-pool/api" } -sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } -sc-proposer-metrics = { version = "0.10.0-dev", path = "../proposer-metrics" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] +parking_lot = "0.12.0" sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -parking_lot = "0.12.0" diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 96248249200af..4b6496e52c2f2 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -6,8 +6,10 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository = "https://github.com/paritytech/substrate" description = "BEEFY Client gadget for substrate" +homepage = "https://substrate.io" [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } fnv = "1.0.6" futures = "0.3" futures-timer = "3.0.1" @@ -16,10 +18,15 @@ log = "0.4" parking_lot = "0.12.0" thiserror = "1.0" wasm-timer = "0.2.5" - -codec = { version = "3.0.0", package = "parity-scale-codec", features = ["derive"] } -prometheus = { version = "0.10.0-dev", package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } - +beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } +prometheus = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } +sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } +sc-client-api = { version = "4.0.0-dev", path = "../api" } +sc-finality-grandpa = { version = "0.10.0-dev", path = "../../client/finality-grandpa" } +sc-keystore = { version = "4.0.0-dev", path = "../keystore" } +sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } +sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } @@ -30,26 +37,14 @@ sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-mmr-primitives = { version = "4.0.0-dev", path = "../../primitives/merkle-mountain-range" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } -sc-client-api = { version = "4.0.0-dev", path = "../api" } -sc-finality-grandpa = { version = "0.10.0-dev", path = "../../client/finality-grandpa" } -sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -sc-network = { version = "0.10.0-dev", path = "../network" } -sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } -sc-utils = { version = "4.0.0-dev", path = "../utils" } - -beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } - [dev-dependencies] +serde = "1.0.136" +strum = { version = "0.23", features = ["derive"] } +tempfile = "3.1.0" +tokio = "1.15" sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sc-network-test = { version = "0.8.0", path = "../network/test" } - sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } - -serde = "1.0.136" -strum = { version = "0.23", features = ["derive"] } -tokio = "1.15" -tempfile = "3.1.0" diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 47f2558c5ee71..adf29f1cef732 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -6,34 +6,29 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository = "https://github.com/paritytech/substrate" description = "RPC for the BEEFY Client gadget for substrate" +homepage = "https://substrate.io" [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" -log = "0.4" -parking_lot = "0.12.0" -thiserror = "1.0" -serde = { version = "1.0.136", features = ["derive"] } - jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" jsonrpc-pubsub = "18.0.0" - -codec = { version = "3.0.0", package = "parity-scale-codec", features = ["derive"] } - +log = "0.4" +parking_lot = "0.12.0" +serde = { version = "1.0.136", features = ["derive"] } +thiserror = "1.0" +beefy-gadget = { version = "4.0.0-dev", path = "../." } +beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } - sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -beefy-gadget = { version = "4.0.0-dev", path = "../." } -beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } - [dev-dependencies] serde_json = "1.0.79" - -sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ - "test-helpers", -] } +sc-rpc = { version = "4.0.0-dev", features = [ + "test-helpers", +], path = "../../rpc" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index fff7740ff8d04..69b84132fe90b 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -12,19 +12,18 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] -sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ + "derive", +] } +sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } +sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-builder" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } -sc-client-api = { version = "4.0.0-dev", path = "../api" } -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ - "derive", -] } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } [dev-dependencies] substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index bd19fd59d699e..6ab559dea46fd 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -13,13 +13,13 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } +codec = { package = "parity-scale-codec", version = "3.0.0" } impl-trait-for-tuples = "0.2.2" -sc-network = { version = "0.10.0-dev", path = "../network" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +memmap2 = "0.5.0" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } +sc-network = { version = "0.10.0-dev", path = "../network" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } -codec = { package = "parity-scale-codec", version = "3.0.0" } -memmap2 = "0.5.0" +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index 8cb5db5e42d91..06f397e1e7b10 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -19,5 +19,3 @@ proc-macro-crate = "1.1.3" proc-macro2 = "1.0.37" quote = "1.0.10" syn = "1.0.82" - -[dev-dependencies] diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 0495f522c1ade..1a504f354ee87 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -21,6 +21,7 @@ hex = "0.4.2" libp2p = "0.44.0" log = "0.4.16" names = { version = "0.13.0", default-features = false } +parity-scale-codec = "3.0.0" rand = "0.7.3" regex = "1.5.5" rpassword = "5.0.0" @@ -29,8 +30,6 @@ serde_json = "1.0.79" thiserror = "1.0.30" tiny-bip39 = "0.8.2" tokio = { version = "1.17.0", features = ["signal", "rt-multi-thread", "parking_lot"] } - -parity-scale-codec = "3.0.0" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-client-db = { version = "0.10.0-dev", path = "../db" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index beaa29d364672..448cf2549f2d9 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -13,36 +13,36 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } -sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consensus/aura" } -sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } -sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } -sc-client-api = { version = "4.0.0-dev", path = "../../api" } +async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0" } -sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } -thiserror = "1.0" futures = "0.3.21" -sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } log = "0.4.16" -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +thiserror = "1.0" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } +sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } +sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } +sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } +sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consensus/aura" } +sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } -sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } -async-trait = "0.1.50" +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [dev-dependencies] -sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +parking_lot = "0.12.0" +tempfile = "3.1.0" sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } +sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -tempfile = "3.1.0" -parking_lot = "0.12.0" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 48313cd0437e0..f421fdd36e37b 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -14,51 +14,51 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ - "derive", + "derive", ] } -sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } +futures = "0.3.21" +log = "0.4.16" +merlin = "2.0" num-bigint = "0.2.3" num-rational = "0.2.2" num-traits = "0.2.8" +parking_lot = "0.12.0" +rand = "0.7.2" +retain_mut = "0.1.4" +schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } serde = { version = "1.0.136", features = ["derive"] } -sp-version = { version = "5.0.0", path = "../../../primitives/version" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } -sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } -sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } +thiserror = "1.0" +fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../epochs" } +sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } +sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } +sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } +sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } sp-consensus-vrf = { version = "0.10.0-dev", path = "../../../primitives/consensus/vrf" } -sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } -futures = "0.3.21" -parking_lot = "0.12.0" -log = "0.4.16" -schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } -rand = "0.7.2" -merlin = "2.0" -thiserror = "1.0" -retain_mut = "0.1.4" -async-trait = "0.1.50" +sp-version = { version = "5.0.0", path = "../../../primitives/version" } [dev-dependencies] -sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +rand_chacha = "0.2.2" +tempfile = "3.1.0" +sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } +sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } -rand_chacha = "0.2.2" -tempfile = "3.1.0" diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index cce4544f09705..0e7141c77f8b2 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -13,28 +13,28 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sc-consensus-babe = { version = "0.10.0-dev", path = "../" } -sc-rpc-api = { version = "0.10.0-dev", path = "../../../rpc-api" } +futures = "0.3.21" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" -sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } serde = { version = "1.0.136", features = ["derive"] } -sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } -sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } -sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } -futures = "0.3.21" thiserror = "1.0" +sc-consensus-babe = { version = "0.10.0-dev", path = "../" } +sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } +sc-rpc-api = { version = "0.10.0-dev", path = "../../../rpc-api" } sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } +sp-application-crypto = { version = "6.0.0", path = "../../../../primitives/application-crypto" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } +sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } sp-core = { version = "6.0.0", path = "../../../../primitives/core" } -sp-application-crypto = { version = "6.0.0", path = "../../../../primitives/application-crypto" } sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] -sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } serde_json = "1.0.79" -sp-keyring = { version = "6.0.0", path = "../../../../primitives/keyring" } +tempfile = "3.1.0" +sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } +sp-keyring = { version = "6.0.0", path = "../../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } -tempfile = "3.1.0" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 2846a3e7898c5..4f8d7befb0d63 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -13,23 +13,23 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -thiserror = "1.0.30" -libp2p = { version = "0.44.0", default-features = false } -log = "0.4.16" +async-trait = "0.1.42" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" +libp2p = { version = "0.44.0", default-features = false } +log = "0.4.16" +parking_lot = "0.12.0" +serde = { version = "1.0", features = ["derive"] } +thiserror = "1.0.30" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { path = "../../../primitives/core", version = "6.0.0"} -sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } -sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -parking_lot = "0.12.0" -serde = { version = "1.0", features = ["derive"] } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } -async-trait = "0.1.42" +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } [dev-dependencies] sp-test-primitives = { version = "2.0.0", path = "../../../primitives/test-primitives" } diff --git a/client/consensus/epochs/Cargo.toml b/client/consensus/epochs/Cargo.toml index 2caf60547cceb..5c52b76185200 100644 --- a/client/consensus/epochs/Cargo.toml +++ b/client/consensus/epochs/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-consensus = { version = "0.10.0-dev", path = "../common" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sc-client-api = { path = "../../api" , version = "4.0.0-dev"} -sc-consensus = { path = "../common" , version = "0.10.0-dev"} +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index c1568ea488337..9452d2b1afd08 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -13,41 +13,38 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -thiserror = "1.0" +assert_matches = "1.3.0" +async-trait = "0.1.50" +codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" log = "0.4.16" -codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0", features = ["derive"] } -assert_matches = "1.3.0" -async-trait = "0.1.50" - -sc-client-api = { path = "../../api", version = "4.0.0-dev" } +thiserror = "1.0" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } +sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } -sc-consensus-babe = { path = "../../consensus/babe", version = "0.10.0-dev" } -sc-consensus-aura = { path = "../../consensus/aura", version = "0.10.0-dev" } -sc-consensus-epochs = { path = "../../consensus/epochs", version = "0.10.0-dev" } -sp-consensus-babe = { path = "../../../primitives/consensus/babe", version = "0.10.0-dev" } -sp-consensus-aura = { path = "../../../primitives/consensus/aura", version = "0.10.0-dev" } - -sc-transaction-pool = { path = "../../transaction-pool", version = "4.0.0-dev" } -sp-blockchain = { path = "../../../primitives/blockchain", version = "4.0.0-dev" } -sp-consensus = { path = "../../../primitives/consensus/common", version = "0.10.0-dev" } -sp-consensus-slots = { path = "../../../primitives/consensus/slots", version = "0.10.0-dev" } -sp-inherents = { path = "../../../primitives/inherents", version = "4.0.0-dev" } -sp-runtime = { path = "../../../primitives/runtime", version = "6.0.0"} -sp-core = { path = "../../../primitives/core", version = "6.0.0"} -sp-keystore = { path = "../../../primitives/keystore", version = "0.12.0"} -sp-api = { path = "../../../primitives/api", version = "4.0.0-dev" } -sc-transaction-pool-api = { path = "../../../client/transaction-pool/api", version = "4.0.0-dev" } -sp-timestamp = { path = "../../../primitives/timestamp", version = "4.0.0-dev" } - -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev" } +sc-consensus-aura = { version = "0.10.0-dev", path = "../../consensus/aura" } +sc-consensus-babe = { version = "0.10.0-dev", path = "../../consensus/babe" } +sc-consensus-epochs = { version = "0.10.0-dev", path = "../../consensus/epochs" } +sc-transaction-pool = { version = "4.0.0-dev", path = "../../transaction-pool" } +sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } +sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consensus/aura" } +sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } +sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } +sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } [dev-dependencies] tokio = { version = "1.17.0", features = ["rt-multi-thread", "macros"] } -sc-basic-authorship = { path = "../../basic-authorship", version = "0.10.0-dev" } -substrate-test-runtime-client = { path = "../../../test-utils/runtime/client", version = "2.0.0" } -substrate-test-runtime-transaction-pool = { path = "../../../test-utils/runtime/transaction-pool", version = "2.0.0" } +sc-basic-authorship = { version = "0.10.0-dev", path = "../../basic-authorship" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } +substrate-test-runtime-transaction-pool = { version = "2.0.0", path = "../../../test-utils/runtime/transaction-pool" } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index fc0151d293bbd..cc65687f80e13 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -13,21 +13,21 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } -sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-consensus-pow = { version = "0.10.0-dev", path = "../../../primitives/consensus/pow" } -sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -log = "0.4.16" futures = "0.3.21" futures-timer = "3.0.1" +log = "0.4.16" parking_lot = "0.12.0" thiserror = "1.0" -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.10.0-dev"} -async-trait = "0.1.50" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } +sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } +sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } +sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +sp-consensus-pow = { version = "0.10.0-dev", path = "../../../primitives/consensus/pow" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 8689818de8c17..27528b68e75ea 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -14,24 +14,24 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0" } +futures = "0.3.21" +futures-timer = "3.0.1" +log = "0.4.16" +thiserror = "1.0.30" sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } +sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } -sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } -sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -futures = "0.3.21" -futures-timer = "3.0.1" -log = "0.4.16" -thiserror = "1.0.30" -async-trait = "0.1.50" [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml index c512eb7e9f832..cf0aaf5cd30d7 100644 --- a/client/consensus/uncles/Cargo.toml +++ b/client/consensus/uncles/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +thiserror = "1.0.30" sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } -thiserror = "1.0.30" +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 9b6faaafbdb62..3c20cec72c695 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -13,34 +13,33 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -parking_lot = "0.12.0" -log = "0.4.16" +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ + "derive", +] } +hash-db = "0.15.2" kvdb = "0.11.0" -kvdb-rocksdb = { version = "0.15.2", optional = true } kvdb-memorydb = "0.11.0" +kvdb-rocksdb = { version = "0.15.2", optional = true } linked-hash-map = "0.5.4" -hash-db = "0.15.2" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ - "derive", -] } - +log = "0.4.16" +parity-db = { version = "0.3.12", optional = true } +parking_lot = "0.12.0" sc-client-api = { version = "4.0.0-dev", path = "../api" } +sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } -sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-trie = { version = "6.0.0", path = "../../primitives/trie" } -sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -parity-db = { version = "0.3.12", optional = true } [dev-dependencies] -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } -substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -quickcheck = "1.0.3" kvdb-rocksdb = "0.15.1" +quickcheck = "1.0.3" tempfile = "3" +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] default = [] diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 677148f709e6b..9ffdfb788474d 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -14,13 +14,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0" } environmental = "1.1.3" thiserror = "1.0.30" wasm-instrument = "0.1" -wasmi = "0.9.1" wasmer = { version = "2.2", features = ["singlepass"], optional = true } - -codec = { package = "parity-scale-codec", version = "3.0.0" } +wasmi = "0.9.1" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index 507b35114d630..7a7848700c4c1 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -14,9 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] paste = "1.0.6" - sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io", features = ["improved_panic_error_reporting"] } +sp-io = { version = "6.0.0", default-features = false, features = ["improved_panic_error_reporting"], path = "../../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 9d913d1e9cc3e..153deab49a305 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -14,12 +14,11 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0" } log = "0.4.16" wasmi = "0.9.1" - -codec = { package = "parity-scale-codec", version = "3.0.0" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } -sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } +sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface" } diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 5871629f47c0a..845fdfb72901c 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] cfg-if = "1.0" +codec = { package = "parity-scale-codec", version = "3.0.0" } libc = "0.2.121" log = "0.4.16" parity-wasm = "0.42.0" @@ -23,15 +24,13 @@ wasmtime = { version = "0.35.3", default-features = false, features = [ "jitdump", "parallel-compilation", ] } - -codec = { package = "parity-scale-codec", version = "3.0.0" } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } -sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface", features = ["wasmtime"] } +sp-wasm-interface = { version = "6.0.0", features = ["wasmtime"], path = "../../../primitives/wasm-interface" } [dev-dependencies] +wat = "1.0" sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } sp-io = { version = "6.0.0", path = "../../../primitives/io" } -wat = "1.0" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 2d011fb96be59..a0e53da23fc54 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -14,52 +14,51 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -thiserror = "1.0" +ahash = "0.7.6" +async-trait = "0.1.50" dyn-clone = "1.0" -fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } +finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } futures = "0.3.21" futures-timer = "3.0.1" hex = "0.4.2" log = "0.4.16" +parity-scale-codec = { version = "3.0.0", features = ["derive"] } parking_lot = "0.12.0" rand = "0.8.4" -ahash = "0.7.6" -parity-scale-codec = { version = "3.0.0", features = ["derive"] } -sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } -sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +serde_json = "1.0.79" +thiserror = "1.0" +fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } +sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } -sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } +sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } -sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -serde_json = "1.0.79" -sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } +sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } +sc-utils = { version = "4.0.0-dev", path = "../utils" } +sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } +sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } +sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } -sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } -finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } -async-trait = "0.1.50" +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3.0" finality-grandpa = { version = "0.15.0", features = [ - "derive-codec", - "test-helpers", + "derive-codec", + "test-helpers", ] } +serde = "1.0.136" +tempfile = "3.1.0" +tokio = "1.17.0" sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-test = { version = "0.8.0", path = "../network/test" } sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } -substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } - -serde = "1.0.136" -tokio = "1.17.0" -tempfile = "3.1.0" +substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 5e173e1a15fe4..40a4150f8dd98 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -7,31 +7,32 @@ repository = "https://github.com/paritytech/substrate/" edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" readme = "README.md" +homepage = "https://substrate.io" [dependencies] -sc-finality-grandpa = { version = "0.10.0-dev", path = "../" } -sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } -sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } +futures = "0.3.16" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" jsonrpc-pubsub = "18.0.0" -futures = "0.3.16" +log = "0.4.8" +parity-scale-codec = { version = "3.0.0", features = ["derive"] } serde = { version = "1.0.105", features = ["derive"] } serde_json = "1.0.50" -log = "0.4.8" thiserror = "1.0" -parity-scale-codec = { version = "3.0.0", features = ["derive"] } sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-finality-grandpa = { version = "0.10.0-dev", path = "../" } +sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [dev-dependencies] sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } -sc-rpc = { version = "4.0.0-dev", path = "../../rpc", features = [ - "test-helpers", -] } +sc-rpc = { version = "4.0.0-dev", features = [ + "test-helpers", +], path = "../../rpc" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index 9ba994b5a66c7..70af073e4bcfe 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -20,6 +20,6 @@ log = "0.4.16" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 844110f668869..be4adba2a52fe 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -13,16 +13,15 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] async-trait = "0.1.50" +hex = "0.4.0" +parking_lot = "0.12.0" +serde_json = "1.0.79" thiserror = "1.0" sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } -hex = "0.4.0" -parking_lot = "0.12.0" -serde_json = "1.0.79" [dev-dependencies] tempfile = "3.1.0" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 79e07b597c65d..4529957c7c38f 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -13,18 +13,17 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] +ahash = "0.7.6" futures = "0.3.21" futures-timer = "3.0.1" libp2p = { version = "0.44.0", default-features = false } log = "0.4.16" lru = "0.7.5" -ahash = "0.7.6" +tracing = "0.1.29" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -tracing = "0.1.29" [dev-dependencies] async-std = "1.11.0" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index a8a1fc05bb365..51e7e762f5292 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -18,59 +18,59 @@ prost-build = "0.9" [dependencies] async-trait = "0.1" +asynchronous-codec = "0.6" bitflags = "1.3.2" -cid = "0.8.4" bytes = "1" +cid = "0.8.4" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } either = "1.5.3" fnv = "1.0.6" -fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } futures = "0.3.21" futures-timer = "3.0.2" -asynchronous-codec = "0.6" hex = "0.4.0" ip_network = "0.4.1" -linked-hash-map = "0.5.4" +libp2p = "0.44.0" linked_hash_set = "0.1.3" -lru = "0.7.5" +linked-hash-map = "0.5.4" log = "0.4.16" +lru = "0.7.5" parking_lot = "0.12.0" pin-project = "1.0.10" -prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } prost = "0.9" rand = "0.7.2" -sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } -sc-client-api = { version = "4.0.0-dev", path = "../api" } -sc-peerset = { version = "4.0.0-dev", path = "../peerset" } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" smallvec = "1.8.0" -sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } -sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } +thiserror = "1.0" +unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } +void = "1.0.2" +zeroize = "1.4.3" +fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } +sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } +sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sc-network-common = { version = "0.10.0-dev", path = "./common" } sc-network-sync = { version = "0.10.0-dev", path = "./sync" } +sc-peerset = { version = "4.0.0-dev", path = "../peerset" } sc-utils = { version = "4.0.0-dev", path = "../utils" } +sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } -thiserror = "1.0" -unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } -void = "1.0.2" -zeroize = "1.4.3" -libp2p = "0.44.0" +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3" +async-std = "1.11.0" quickcheck = "1.0.3" rand = "0.7.2" +tempfile = "3.1.0" sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -tempfile = "3.1.0" -async-std = "1.11.0" [features] default = [] diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 5e3150ee9bc82..c41a7895888ae 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -18,9 +18,9 @@ prost-build = "0.9" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ - "derive", + "derive", ] } futures = "0.3.21" libp2p = "0.44.0" -sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } smallvec = "1.8.0" +sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index c171194d5b24d..9cf8afa58649c 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -19,27 +19,27 @@ prost-build = "0.9" [dependencies] bitflags = "1.3.2" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ - "derive", + "derive", ] } either = "1.5.3" -fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } futures = "0.3.21" libp2p = "0.44.0" log = "0.4.16" lru = "0.7.5" prost = "0.9" +smallvec = "1.8.0" +thiserror = "1.0" +fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-network-common = { version = "0.10.0-dev", path = "../common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } -smallvec = "1.8.0" sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -thiserror = "1.0" [dev-dependencies] quickcheck = "1.0.3" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index bf3317d0759ee..025658afcad22 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -14,24 +14,24 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-std = "1.11.0" -sc-network-common = { version = "0.10.0-dev", path = "../common" } -sc-network = { version = "0.10.0-dev", path = "../" } -log = "0.4.16" -parking_lot = "0.12.0" +async-trait = "0.1.50" futures = "0.3.21" futures-timer = "3.0.1" -rand = "0.7.2" libp2p = { version = "0.44.0", default-features = false } -sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } +log = "0.4.16" +parking_lot = "0.12.0" +rand = "0.7.2" +sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } +sc-network = { version = "0.10.0-dev", path = "../" } +sc-network-common = { version = "0.10.0-dev", path = "../common" } +sc-service = { version = "0.10.0-dev", default-features = false, features = ["test-helpers"], path = "../../service" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } -sc-service = { version = "0.10.0-dev", default-features = false, features = ["test-helpers"], path = "../../service" } -async-trait = "0.1.50" +substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 6cb1f83e360be..d4ae0a2558b7f 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -15,36 +15,36 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = "1.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } -hex = "0.4" fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" +hex = "0.4" +hyper = { version = "0.14.16", features = ["stream", "http2"] } +hyper-rustls = "0.22.1" num_cpus = "1.13" +once_cell = "1.8" parking_lot = "0.12.0" rand = "0.7.2" +threadpool = "1.7" +tracing = "0.1.29" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sc-utils = { version = "4.0.0-dev", path = "../utils" } -threadpool = "1.7" -hyper = { version = "0.14.16", features = ["stream", "http2"] } -hyper-rustls = "0.22.1" -once_cell = "1.8" -tracing = "0.1.29" [dev-dependencies] -sc-client-db = { version = "0.10.0-dev", default-features = true, path = "../db" } +lazy_static = "1.4.0" +tokio = "1.17.0" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } +sc-client-db = { version = "0.10.0-dev", default-features = true, path = "../db" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -tokio = "1.17.0" -lazy_static = "1.4.0" [features] default = [] diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index ee83d186b5417..7bf324b68cdc6 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -1,6 +1,6 @@ [package] description = "Connectivity manager based on reputation" -homepage = "http://parity.io" +homepage = "https://substrate.io" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" name = "sc-peerset" version = "4.0.0-dev" @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" libp2p = { version = "0.44.0", default-features = false } -sc-utils = { version = "4.0.0-dev", path = "../utils"} log = "0.4.16" serde_json = "1.0.79" wasm-timer = "0.2" +sc-utils = { version = "4.0.0-dev", path = "../utils" } [dev-dependencies] rand = "0.7.2" diff --git a/client/proposer-metrics/Cargo.toml b/client/proposer-metrics/Cargo.toml index fc80d5b14fd8f..9df6ff4e2e76d 100644 --- a/client/proposer-metrics/Cargo.toml +++ b/client/proposer-metrics/Cargo.toml @@ -14,4 +14,4 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.16" -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 21354737ce2cb..0287b0fd30799 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -21,15 +21,14 @@ jsonrpc-derive = "18.0.0" jsonrpc-pubsub = "18.0.0" log = "0.4.16" parking_lot = "0.12.0" -thiserror = "1.0" - scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-version = { version = "5.0.0", path = "../../primitives/version" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sc-chain-spec = { path = "../chain-spec", version = "4.0.0-dev" } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" +thiserror = "1.0" +sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index 12f5c23493ad8..4a13e9624a58e 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -14,12 +14,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" +http = { package = "jsonrpc-http-server", version = "18.0.0" } +ipc = { package = "jsonrpc-ipc-server", version = "18.0.0" } jsonrpc-core = "18.0.0" -pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } log = "0.4.16" -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} +pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } serde_json = "1.0.79" tokio = { version = "1.17.0", features = ["parking_lot"] } -http = { package = "jsonrpc-http-server", version = "18.0.0" } -ipc = { package = "jsonrpc-ipc-server", version = "18.0.0" } ws = { package = "jsonrpc-ws-server", version = "18.0.0" } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 0035ddaa94502..f76665d6c97a7 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -13,40 +13,40 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } -sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" +hash-db = { version = "0.15.2", default-features = false } jsonrpc-pubsub = "18.0.0" +lazy_static = { version = "1.4.0", optional = true } log = "0.4.16" -sp-core = { version = "6.0.0", path = "../../primitives/core" } +parking_lot = "0.12.0" rpc = { package = "jsonrpc-core", version = "18.0.0" } -sp-version = { version = "5.0.0", path = "../../primitives/version" } serde_json = "1.0.79" -sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } -sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } -sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } -sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } +sc-client-api = { version = "4.0.0-dev", path = "../api" } +sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } -hash-db = { version = "0.15.2", default-features = false } -parking_lot = "0.12.0" -lazy_static = { version = "1.4.0", optional = true } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } +sc-utils = { version = "4.0.0-dev", path = "../utils" } +sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } +sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } [dev-dependencies] assert_matches = "1.3.0" lazy_static = "1.4.0" sc-network = { version = "0.10.0-dev", path = "../network" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } -substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] test-helpers = ["lazy_static"] diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 854e8f5b74659..15105765c207c 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -12,33 +12,33 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +fdlimit = "0.2.1" +futures = "0.3.21" hex = "0.4" hex-literal = "0.3.4" -tempfile = "3.1.0" -tokio = { version = "1.17.0", features = ["time"] } log = "0.4.16" -fdlimit = "0.2.1" +parity-scale-codec = "3.0.0" parking_lot = "0.12.0" -sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } -sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } -sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } -sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } +tempfile = "3.1.0" +tokio = { version = "1.17.0", features = ["time"] } +sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } +sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../../db" } -futures = "0.3.21" -sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../../service" } +sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } +sc-executor = { version = "0.10.0-dev", path = "../../executor" } sc-network = { version = "0.10.0-dev", path = "../../network" } +sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../../service" } +sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } +sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } -substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } -substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } -sc-executor = { version = "0.10.0-dev", path = "../../executor" } +sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } sp-panic-handler = { version = "4.0.0", path = "../../../primitives/panic-handler" } -parity-scale-codec = "3.0.0" +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } +sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } +substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 3ca5a9065045f..5a143ffc9f1b8 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -parking_lot = "0.12.0" -log = "0.4.16" -sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +log = "0.4.16" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } parity-util-mem-derive = "0.1.0" +parking_lot = "0.12.0" +sc-client-api = { version = "4.0.0-dev", path = "../api" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index e13631f210bc0..a32849dc0e964 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -13,17 +13,17 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -thiserror = "1.0.30" +codec = { package = "parity-scale-codec", version = "3.0.0" } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" +serde = { version = "1.0.136", features = ["derive"] } +serde_json = "1.0.79" +thiserror = "1.0.30" sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-consensus-babe = { version = "0.10.0-dev", path = "../consensus/babe" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } -serde_json = "1.0.79" -serde = { version = "1.0.136", features = ["derive"] } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/client/sysinfo/Cargo.toml b/client/sysinfo/Cargo.toml index 15e9545094cbf..abfa090d85547 100644 --- a/client/sysinfo/Cargo.toml +++ b/client/sysinfo/Cargo.toml @@ -15,14 +15,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.19" +libc = "0.2" log = "0.4.16" rand = "0.7.3" rand_pcg = "0.2.1" regex = "1" -libc = "0.2" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" +sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-std = { version = "4.0.0", path = "../../primitives/std" } -sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 4dfefd06ac737..3c5942ad688fa 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -13,16 +13,15 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] -parking_lot = "0.12.0" +chrono = "0.4.19" futures = "0.3.21" -wasm-timer = "0.2.5" libp2p = { version = "0.44.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.16" +parking_lot = "0.12.0" pin-project = "1.0.10" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" -chrono = "0.4.19" thiserror = "1.0.30" +wasm-timer = "0.2.5" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 4178e26fe7bf6..058b718a783a4 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -28,15 +28,15 @@ thiserror = "1.0.30" tracing = "0.1.29" tracing-log = { version = "0.1.3", features = ["interest-cache"] } tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } -sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } sc-client-api = { version = "4.0.0-dev", path = "../api" } -sc-tracing-proc-macro = { version = "4.0.0-dev", path = "./proc-macro" } sc-rpc-server = { version = "4.0.0-dev", path = "../rpc-servers" } +sc-tracing-proc-macro = { version = "4.0.0-dev", path = "./proc-macro" } +sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } [dev-dependencies] criterion = "0.3" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index f651b2022032a..5d4996a424f86 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -14,35 +14,35 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -thiserror = "1.0.30" futures = "0.3.21" futures-timer = "3.0.2" +linked-hash-map = "0.5.4" log = "0.4.16" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } parking_lot = "0.12.0" -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev"} +retain_mut = "0.1.4" +serde = { version = "1.0.136", features = ["derive"] } +thiserror = "1.0.30" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-client-api = { version = "4.0.0-dev", path = "../api" } +sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } +sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } -sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } -sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sc-utils = { version = "4.0.0-dev", path = "../utils" } -serde = { version = "1.0.136", features = ["derive"] } -linked-hash-map = "0.5.4" -retain_mut = "0.1.4" [dev-dependencies] assert_matches = "1.3.0" +criterion = "0.3" hex = "0.4" -sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -substrate-test-runtime-transaction-pool = { version = "2.0.0", path = "../../test-utils/runtime/transaction-pool" } -substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } +sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } -criterion = "0.3" +substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } +substrate-test-runtime-transaction-pool = { version = "2.0.0", path = "../../test-utils/runtime/transaction-pool" } [[bench]] name = "basics" diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 84395aaf2eace..6ced3f6c7fc91 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -13,6 +13,5 @@ futures = "0.3.21" log = "0.4.16" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" - -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index 2f1338577e375..2df04be7fb4af 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -11,11 +11,11 @@ readme = "README.md" [dependencies] futures = "0.3.21" +futures-timer = "3.0.2" lazy_static = "1.4.0" +log = "0.4" parking_lot = "0.12.0" prometheus = { version = "0.13.0", default-features = false } -futures-timer = "3.0.2" -log = "0.4" [features] default = ["metered"] diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 361b7d5833e67..4fd793496572e 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -17,10 +17,10 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } @@ -29,12 +29,12 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } default = ["std"] std = [ "codec/std", - "scale-info/std", "frame-support/std", "frame-system/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", - "sp-io/std", - "sp-core/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index 96cfade56cc0f..2ce90ff0215ae 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -13,15 +13,15 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -sp-consensus-aura = { version = "0.10.0-dev", path = "../../primitives/consensus/aura", default-features = false } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } @@ -30,14 +30,14 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ - "sp-application-crypto/std", "codec/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", "frame-support/std", - "sp-consensus-aura/std", "frame-system/std", "pallet-timestamp/std", + "scale-info/std", + "sp-application-crypto/std", + "sp-consensus-aura/std", + "sp-runtime/std", + "sp-std/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index d379bdda6cf8a..bebe8e0f436a6 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -13,19 +13,19 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authority-discovery" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -pallet-session = { version = "4.0.0-dev", features = [ - "historical", -], path = "../session", default-features = false } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +pallet-session = { version = "4.0.0-dev", default-features = false, features = [ + "historical", +], path = "../session" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authority-discovery" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] sp-core = { version = "6.0.0", path = "../../primitives/core" } @@ -34,14 +34,14 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ - "sp-application-crypto/std", - "sp-authority-discovery/std", "codec/std", - "scale-info/std", - "sp-std/std", - "pallet-session/std", - "sp-runtime/std", "frame-support/std", "frame-system/std", + "pallet-session/std", + "scale-info/std", + "sp-application-crypto/std", + "sp-authority-discovery/std", + "sp-runtime/std", + "sp-std/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 4557ee65f1a6b..bc7fad9684e1f 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -16,13 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } +impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -impl-trait-for-tuples = "0.2.2" +sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] sp-core = { version = "6.0.0", path = "../../primitives/core" } @@ -32,11 +32,11 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-runtime/std", - "sp-std/std", "frame-support/std", "frame-system/std", + "scale-info/std", "sp-authorship/std", + "sp-runtime/std", + "sp-std/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 2c3af69b3b4a1..dfdc9d2163136 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -14,8 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } @@ -29,27 +30,27 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -log = { version = "0.4.16", default-features = false } [dev-dependencies] +frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } sp-core = { version = "6.0.0", path = "../../primitives/core" } -frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", + "log/std", "pallet-authorship/std", "pallet-session/std", "pallet-timestamp/std", + "scale-info/std", "sp-application-crypto/std", "sp-consensus-babe/std", "sp-consensus-vrf/std", @@ -58,7 +59,6 @@ std = [ "sp-session/std", "sp-staking/std", "sp-std/std", - "log/std", ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/bags-list/fuzzer/Cargo.toml b/frame/bags-list/fuzzer/Cargo.toml index 510000f631adc..ec7d98255b019 100644 --- a/frame/bags-list/fuzzer/Cargo.toml +++ b/frame/bags-list/fuzzer/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Fuzzer for FRAME pallet bags list" readme = "README.md" @@ -13,9 +13,8 @@ publish = false [dependencies] honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } - +frame-election-provider-support = { version = "4.0.0-dev", features = ["runtime-benchmarks"], path = "../../election-provider-support" } pallet-bags-list = { version = "4.0.0-dev", features = ["fuzz"], path = ".." } -frame-election-provider-support = { version = "4.0.0-dev", path = "../../election-provider-support", features = ["runtime-benchmarks"] } [[bin]] name = "bags-list" diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 46a15f9c6d7ef..6ec624130288b 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -14,30 +14,30 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -log = { version = "0.4.16", default-features = false } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-io = { version = "6.0.0", path = "../../primitives/io" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", "log/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 40e16ad780a61..bdec17b8589c2 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -6,48 +6,46 @@ edition = "2021" license = "Apache-2.0" description = "BEEFY + MMR runtime utilities" repository = "https://github.com/paritytech/substrate" +homepage = "https://substrate.io" [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex = { version = "0.4", optional = true } -codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } - -frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } -frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } -pallet-mmr = { version = "4.0.0-dev", path = "../merkle-mountain-range", default-features = false } -pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } - -sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } -sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime", default-features = false } -sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } - -beefy-merkle-tree = { version = "4.0.0-dev", path = "./primitives", default-features = false } -beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", default-features = false } -pallet-beefy = { version = "4.0.0-dev", path = "../beefy", default-features = false } +beefy-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "./primitives" } +beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +pallet-beefy = { version = "4.0.0-dev", default-features = false, path = "../beefy" } +pallet-mmr = { version = "4.0.0-dev", default-features = false, path = "../merkle-mountain-range" } +pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } hex-literal = "0.3" +sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } [features] default = ["std"] std = [ - "beefy-merkle-tree/std", - "beefy-primitives/std", - "codec/std", - "frame-support/std", - "frame-system/std", - "hex", - "log/std", - "pallet-beefy/std", - "pallet-mmr/std", - "pallet-session/std", - "serde", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", + "beefy-merkle-tree/std", + "beefy-primitives/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "hex", + "log/std", + "pallet-beefy/std", + "pallet-mmr/std", + "pallet-session/std", + "serde", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", ] diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/frame/beefy-mmr/primitives/Cargo.toml index b54ac225e7818..7878dc3d22837 100644 --- a/frame/beefy-mmr/primitives/Cargo.toml +++ b/frame/beefy-mmr/primitives/Cargo.toml @@ -6,10 +6,11 @@ edition = "2021" license = "Apache-2.0" repository = "https://github.com/paritytech/substrate" description = "A no-std/Substrate compatible library to construct binary merkle tree." +homepage = "https://substrate.io" [dependencies] -hex = { version = "0.4", optional = true, default-features = false } -log = { version = "0.4", optional = true, default-features = false } +hex = { version = "0.4", default-features = false, optional = true } +log = { version = "0.4", default-features = false, optional = true } tiny-keccak = { version = "2.0.2", features = ["keccak"], optional = true } [dev-dependencies] @@ -19,6 +20,6 @@ hex-literal = "0.3" [features] debug = ["hex", "hex/std", "log"] -default = ["std", "debug", "keccak"] +default = ["debug", "keccak", "std"] keccak = ["tiny-keccak"] std = [] diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 6ed9e7375bfe3..89a49831d9f62 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -6,21 +6,18 @@ edition = "2021" license = "Apache-2.0" repository = "https://github.com/paritytech/substrate" description = "BEEFY FRAME pallet" +homepage = "https://substrate.io" [dependencies] -codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } - -frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } -frame-system = { version = "4.0.0-dev", path = "../system", default-features = false } - -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime", default-features = false } -sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } - -pallet-session = { version = "4.0.0-dev", path = "../session", default-features = false } - -beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", default-features = false } +beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] sp-core = { version = "6.0.0", path = "../../primitives/core" } @@ -30,13 +27,13 @@ sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } [features] default = ["std"] std = [ - "codec/std", - "scale-info/std", - "serde", "beefy-primitives/std", + "codec/std", "frame-support/std", "frame-system/std", + "pallet-session/std", + "scale-info/std", + "serde", "sp-runtime/std", "sp-std/std", - "pallet-session/std", ] diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index aa551095d1d7e..d1d835e0d1d35 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -13,21 +13,21 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } linregress = { version = "0.4.4", optional = true } +log = { version = "0.4.16", default-features = false } paste = "1.0" -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } -sp-runtime-interface = { version = "6.0.0", path = "../../primitives/runtime-interface", default-features = false } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime", default-features = false } -sp-std = { version = "4.0.0", path = "../../primitives/std", default-features = false } -sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } -sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto", default-features = false } -sp-storage = { version = "6.0.0", path = "../../primitives/storage", default-features = false } +serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -log = { version = "0.4.16", default-features = false } -serde = { version = "1.0.136", optional = true } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../../primitives/runtime-interface" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-storage = { version = "6.0.0", default-features = false, path = "../../primitives/storage" } [dev-dependencies] hex-literal = "0.3.4" @@ -37,15 +37,15 @@ sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } default = ["std"] std = [ "codec/std", + "frame-support/std", + "frame-system/std", + "linregress", + "log/std", "scale-info/std", "serde", + "sp-api/std", "sp-runtime-interface/std", "sp-runtime/std", - "sp-api/std", "sp-std/std", - "frame-support/std", - "frame-system/std", - "linregress", - "log/std", ] runtime-benchmarks = [] diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 2eb8f486d3556..c090052e91277 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -16,16 +16,16 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } -sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } -sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -log = { version = "0.4.16", default-features = false } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } @@ -34,15 +34,15 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } default = ["std"] std = [ "codec/std", - "sp-core/std", - "sp-io/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", "frame-support/std", "frame-system/std", - "pallet-treasury/std", "log/std", + "pallet-treasury/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index b6a38fb22548d..eac338dc3c6aa 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -16,17 +16,17 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../bounties" } -sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } -sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -log = { version = "0.4.16", default-features = false } +pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } @@ -35,16 +35,16 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } default = ["std"] std = [ "codec/std", - "sp-core/std", - "sp-io/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", "frame-support/std", "frame-system/std", - "pallet-treasury/std", - "pallet-bounties/std", "log/std", + "pallet-bounties/std", + "pallet-treasury/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking", diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index 7e1186143270c..d1ef4d253a352 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -16,34 +16,32 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } - +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } - [features] default = ["std"] std = [ "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", "log/std", "scale-info/std", "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", - "frame-benchmarking/std", - "frame-support/std", - "frame-system/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index 5877bf0c5da2d..4ebc3c8f4bc43 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -13,41 +13,41 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.136", optional = true, features = ["derive"] } +assert_matches = "1.3.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +serde = { version = "1.0.136", features = ["derive"], optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -assert_matches = "1.3.0" +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ - "serde", "codec/std", - "scale-info/std", - "sp-std/std", - "sp-io/std", "frame-benchmarking/std", "frame-support/std", - "sp-runtime/std", "frame-system/std", + "scale-info/std", + "serde", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking", - "frame-system/runtime-benchmarks", "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 49b21d0eecdce..b36448bdf25ef 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -13,40 +13,40 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +serde = { version = "1.0.136", features = ["derive"], optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ - "serde", "codec/std", - "scale-info/std", - "sp-std/std", - "sp-io/std", "frame-benchmarking/std", "frame-support/std", - "sp-runtime/std", "frame-system/std", + "scale-info/std", + "serde", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index be0c05e46df32..8bc92f878c8ce 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -15,28 +15,28 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +frame-election-provider-solution-type = { version = "4.0.0-dev", path = "solution-type" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -frame-election-provider-solution-type = { version = "4.0.0-dev", path = "solution-type" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] rand = "0.7.3" -sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } [features] default = ["std"] std = [ "codec/std", - "sp-std/std", - "sp-npos-elections/std", - "sp-arithmetic/std", "frame-support/std", "frame-system/std", + "sp-arithmetic/std", + "sp-npos-elections/std", + "sp-std/std", ] runtime-benchmarks = [] diff --git a/frame/election-provider-support/benchmarking/Cargo.toml b/frame/election-provider-support/benchmarking/Cargo.toml index e9719be139a6d..14afff1aeb055 100644 --- a/frame/election-provider-support/benchmarking/Cargo.toml +++ b/frame/election-provider-support/benchmarking/Cargo.toml @@ -15,23 +15,21 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../benchmarking" } +frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = ".." } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = ".." } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true } - [features] default = ["std"] std = [ "codec/std", - "sp-npos-elections/std", - "sp-runtime/std", "frame-benchmarking/std", "frame-system/std", + "sp-npos-elections/std", + "sp-runtime/std", ] - runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-election-provider-support/runtime-benchmarks", diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index f772a82d73d87..0f195f12cce3c 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -16,16 +16,16 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } +log = { version = "0.4.14", default-features = false } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -log = { version = "0.4.14", default-features = false } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } @@ -36,15 +36,15 @@ substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } default = ["std"] std = [ "codec/std", - "scale-info/std", "frame-support/std", - "sp-runtime/std", - "sp-npos-elections/std", "frame-system/std", - "sp-std/std", - "sp-io/std", - "sp-core/std", "log/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-npos-elections/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index d9051dff8f2cb..a528cf89bbaf4 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -16,8 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } - -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } @@ -26,7 +25,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../../pri sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../../primitives/core", default-features = false } +sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } [features] default = ["std"] @@ -40,7 +39,7 @@ std = [ "scale-info/std", "sp-io/std", "sp-runtime/std", - "sp-std/std" + "sp-std/std", ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index ede25c2c939df..061f84bd40276 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -17,12 +17,11 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = lite-json = { version = "0.1", default-features = false } log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } - frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore", optional = true } +sp-keystore = { version = "0.12.0", optional = true, path = "../../../primitives/keystore" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } @@ -30,15 +29,15 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../../primiti default = ["std"] std = [ "codec/std", - "scale-info/std", "frame-support/std", "frame-system/std", "lite-json/std", + "log/std", + "scale-info/std", "sp-core/std", "sp-io/std", "sp-keystore", "sp-runtime/std", "sp-std/std", - "log/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/examples/parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml index 367b2e98aaa65..6834a9143ae97 100644 --- a/frame/examples/parallel/Cargo.toml +++ b/frame/examples/parallel/Cargo.toml @@ -14,7 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } - frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } @@ -27,9 +26,9 @@ sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../p default = ["std"] std = [ "codec/std", - "scale-info/std", "frame-support/std", "frame-system/std", + "scale-info/std", "sp-core/std", "sp-io/std", "sp-runtime/std", diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index f920affaab202..b60cffa478c7b 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -19,32 +19,32 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-tracing = { version = "5.0.0", default-features = false, path = "../../primitives/tracing" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-tracing = { version = "5.0.0", default-features = false, path = "../../primitives/tracing" } [dev-dependencies] hex-literal = "0.3.4" -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } -sp-version = { version = "5.0.0", path = "../../primitives/version" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } [features] default = ["std"] with-tracing = ["sp-tracing/with-tracing"] std = [ "codec/std", - "scale-info/std", "frame-support/std", "frame-system/std", + "scale-info/std", "sp-core/std", "sp-runtime/std", - "sp-tracing/std", "sp-std/std", + "sp-tracing/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index 837504e516cee..4916b950e47dd 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -15,29 +15,29 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-io = { version = "6.0.0", path = "../../primitives/io" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", - "sp-arithmetic/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", + "scale-info/std", + "sp-arithmetic/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 7312ae7da4cf8..b1c2da09b53ff 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -14,51 +14,51 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } +pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } -pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } -log = { version = "0.4.16", default-features = false } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } grandpa = { package = "finality-grandpa", version = "0.15.0", features = ["derive-codec"] } -sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } +frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } -frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } +sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-authorship/std", + "pallet-session/std", + "scale-info/std", "sp-application-crypto/std", "sp-core/std", "sp-finality-grandpa/std", - "sp-session/std", - "sp-std/std", - "frame-support/std", "sp-runtime/std", + "sp-session/std", "sp-staking/std", - "frame-system/std", - "pallet-authorship/std", - "pallet-session/std", - "log/std", + "sp-std/std", ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 5dff7acc73e26..d5057e302339b 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -14,30 +14,30 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } enumflags2 = { version = "0.7.4" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-std/std", - "sp-io/std", - "sp-runtime/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", + "scale-info/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index 8ac2da0fbb053..1f04c8b1bb3d8 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -13,20 +13,19 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } -pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -log = { version = "0.4.16", default-features = false } - -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-session = { version = "4.0.0-dev", path = "../session" } @@ -34,18 +33,18 @@ pallet-session = { version = "4.0.0-dev", path = "../session" } [features] default = ["std"] std = [ - "sp-application-crypto/std", - "pallet-authorship/std", "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-authorship/std", "scale-info/std", + "sp-application-crypto/std", "sp-core/std", - "sp-std/std", "sp-io/std", "sp-runtime/std", "sp-staking/std", - "frame-support/std", - "frame-system/std", - "log/std", + "sp-std/std", ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index 690fc9db14f95..99edf95fb332b 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -15,15 +15,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } - -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } @@ -31,15 +30,15 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] std = [ - "sp-keyring", "codec/std", + "frame-support/std", + "frame-system/std", "scale-info/std", "sp-core/std", - "sp-std/std", "sp-io/std", - "frame-support/std", + "sp-keyring", "sp-runtime/std", - "frame-system/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 7932abdc21a04..9e5992195441e 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -17,12 +17,11 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", ] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } - -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] frame-support-test = { version = "3.0.0", path = "../support/test" } @@ -34,15 +33,15 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-std/std", "frame-support/std", - "sp-runtime/std", "frame-system/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index a6ea127b79cba..1545b191c8719 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -14,36 +14,34 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } log = { version = "0.4.16", default-features = false } - +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } - [features] default = ["std"] std = [ "codec/std", - "scale-info/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", "log/std", + "scale-info/std", "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", - "frame-support/std", - "frame-system/std", - "frame-benchmarking/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 8b67174e8385d..0b5d404fe23aa 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -13,19 +13,17 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.3.2", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, version = "0.3.2" } - +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/merkle-mountain-range" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } - [dev-dependencies] env_logger = "0.9" hex-literal = "0.3" @@ -34,16 +32,16 @@ hex-literal = "0.3" default = ["std"] std = [ "codec/std", - "scale-info/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", "mmr-lib/std", + "scale-info/std", "sp-core/std", "sp-io/std", "sp-mmr-primitives/std", "sp-runtime/std", "sp-std/std", - "frame-benchmarking/std", - "frame-support/std", - "frame-system/std", ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 359ee88a9c485..9b3d3a43c6045 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -18,7 +18,6 @@ jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" serde = { version = "1.0.136", features = ["derive"] } - sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index a2188ca18b3b3..c151016c594c7 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -15,28 +15,27 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } - -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-runtime/std", "frame-support/std", "frame-system/std", + "scale-info/std", "sp-io/std", - "sp-std/std" + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 9e98864d24f99..5ee2e9193dd2a 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -15,25 +15,25 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ "codec/std", + "frame-support/std", + "frame-system/std", "scale-info/std", - "sp-std/std", "sp-io/std", "sp-runtime/std", - "frame-support/std", - "frame-system/std", + "sp-std/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index cfd1939d36ed7..317b5f392ebfa 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -13,6 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -20,19 +21,18 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -log = { version = "0.4.16", default-features = false } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", "frame-support/std", "frame-system/std", + "log/std", + "scale-info/std", "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", - "log/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index bb728bd05f2a1..f4aa01643315b 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -13,34 +13,34 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } serde = { version = "1.0.136", optional = true } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -log = { version = "0.4.16", default-features = false } +pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ - "pallet-balances/std", "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-balances/std", "scale-info/std", - "sp-std/std", "serde", "sp-runtime/std", "sp-staking/std", - "frame-support/std", - "frame-system/std", - "log/std", + "sp-std/std", ] runtime-benchmarks = [] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index 605e0c60a03c2..2b8e461b84192 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } +frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../babe" } @@ -32,7 +33,6 @@ pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } [dev-dependencies] pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } @@ -43,7 +43,9 @@ sp-io = { version = "6.0.0", path = "../../../primitives/io" } [features] default = ["std"] std = [ + "codec/std", "frame-benchmarking/std", + "frame-election-provider-support/std", "frame-support/std", "frame-system/std", "pallet-babe/std", @@ -53,10 +55,8 @@ std = [ "pallet-offences/std", "pallet-session/std", "pallet-staking/std", + "scale-info/std", "sp-runtime/std", "sp-staking/std", - "frame-election-provider-support/std", "sp-std/std", - "codec/std", - "scale-info/std", ] diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 58809f9e98964..9face65182f7e 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -12,18 +12,17 @@ readme = "README.md" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } - -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, optional = true, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } [features] default = ["std"] @@ -34,13 +33,13 @@ runtime-benchmarks = [ ] std = [ "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", "scale-info/std", - "sp-std/std", - "sp-io/std", "sp-core/std", + "sp-io/std", "sp-runtime/std", - "frame-system/std", - "frame-support/std", - "frame-benchmarking/std", + "sp-std/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index bdc39a81e34a6..62cbb16dddf29 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -15,29 +15,28 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["max-encoded-len"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } - [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-runtime/std", "frame-support/std", "frame-system/std", - "sp-std/std", + "scale-info/std", "sp-io/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index 17d4ff461aa0f..692f33575e127 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -13,14 +13,13 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -safe-mix = { version = "1.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +safe-mix = { version = "1.0", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } - frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] sp-core = { version = "6.0.0", path = "../../primitives/core" } @@ -29,12 +28,12 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ - "safe-mix/std", "codec/std", + "frame-support/std", + "frame-system/std", + "safe-mix/std", "scale-info/std", "sp-runtime/std", "sp-std/std", - "frame-system/std", - "frame-support/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 98dbfc0eb0d20..2a72963f6cf0d 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -15,16 +15,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] @@ -36,12 +36,12 @@ runtime-benchmarks = [ ] std = [ "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", "scale-info/std", - "sp-std/std", "sp-io/std", "sp-runtime/std", - "frame-support/std", - "frame-system/std", - "frame-benchmarking/std", + "sp-std/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index d85503a741f43..d13d08542f56e 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -13,44 +13,44 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.136", optional = true, features = ["derive"] } +assert_matches = { version = "1.5", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +serde = { version = "1.0.136", features = ["derive"], optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -assert_matches = { version = "1.5", optional = true } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } +assert_matches = { version = "1.5" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } -pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } -assert_matches = { version = "1.5" } +pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ - "serde", "codec/std", - "scale-info/std", - "sp-std/std", - "sp-io/std", "frame-benchmarking/std", "frame-support/std", - "sp-runtime/std", "frame-system/std", + "scale-info/std", + "serde", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ + "assert_matches", "frame-benchmarking", - "frame-system/runtime-benchmarks", "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", - "assert_matches", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/remark/Cargo.toml b/frame/remark/Cargo.toml index 82c76d679cc10..9759c37bfe92c 100644 --- a/frame/remark/Cargo.toml +++ b/frame/remark/Cargo.toml @@ -13,30 +13,30 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.136", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } [features] default = ["std"] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] std = [ - "serde", "codec/std", - "scale-info/std", - "sp-runtime/std", "frame-support/std", "frame-system/std", + "scale-info/std", + "serde", "sp-io/std", + "sp-runtime/std", "sp-std/std", ] diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 577deb84e559a..90c2bf10d19da 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -11,20 +11,19 @@ readme = "README.md" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } log = { version = "0.4.16", default-features = false } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } - sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } -substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] default = ["std"] @@ -35,13 +34,13 @@ runtime-benchmarks = [ ] std = [ "codec/std", - "scale-info/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", "log/std", - "sp-std/std", + "scale-info/std", "sp-io/std", "sp-runtime/std", - "frame-system/std", - "frame-support/std", - "frame-benchmarking/std", + "sp-std/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index 73fd25158ca88..c857dc9ab9ace 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } @@ -29,11 +29,11 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", + "frame-support/std", + "frame-system/std", "scale-info/std", "sp-io/std", "sp-runtime/std", "sp-std/std", - "frame-support/std", - "frame-system/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index d1407f1509307..01822ace9cf28 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -13,40 +13,37 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { version = "0.4.16", default-features = false } -impl-trait-for-tuples = "0.2.2" - codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +impl-trait-for-tuples = "0.2.2" +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } - -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-trie = { version = "6.0.0", default-features = false, path = "../../primitives/trie", optional = true } - -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-trie = { version = "6.0.0", default-features = false, optional = true, path = "../../primitives/trie" } [features] -default = ["std", "historical"] +default = ["historical", "std"] historical = ["sp-trie"] std = [ - "log/std", "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-timestamp/std", "scale-info/std", - "sp-std/std", "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-session/std", "sp-staking/std", + "sp-std/std", "sp-trie/std", - "frame-support/std", - "frame-system/std", - "pallet-timestamp/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index b00d1335d22a2..0449f3f674379 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -14,36 +14,34 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] rand = { version = "0.7.2", default-features = false } - -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } - frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../../session" } pallet-staking = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../staking" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } scale-info = "2.0.1" -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } +frame-election-provider-support = { version = "4.0.0-dev", path = "../../election-provider-support" } pallet-balances = { version = "4.0.0-dev", path = "../../balances" } -pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } -frame-election-provider-support = { version = "4.0.0-dev", path = "../../election-provider-support" } +pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } [features] default = ["std"] std = [ - "sp-std/std", - "sp-runtime/std", - "sp-session/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", "pallet-session/std", "pallet-staking/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", ] diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index 1fd9693d0d00f..b19820c66fb58 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -14,32 +14,32 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +rand_chacha = { version = "0.2", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -rand_chacha = { version = "0.2", default-features = false } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io ={ version = "6.0.0", path = "../../primitives/io" } frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ "codec/std", + "frame-support/std", + "frame-system/std", + "rand_chacha/std", "scale-info/std", "sp-runtime/std", - "rand_chacha/std", "sp-std/std", - "frame-support/std", - "frame-system/std", ] runtime-benchmarks = [ - "sp-runtime/runtime-benchmarks", "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index dd8361ece6386..0307f61b1dce6 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -15,10 +15,10 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.82", features = ["full", "visit"] } -quote = "1.0.10" -proc-macro2 = "1.0.37" proc-macro-crate = "1.1.3" +proc-macro2 = "1.0.37" +quote = "1.0.10" +syn = { version = "1.0.82", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/frame/staking/reward-fn/Cargo.toml b/frame/staking/reward-fn/Cargo.toml index f396030a1ae9a..4a41de806e13f 100644 --- a/frame/staking/reward-fn/Cargo.toml +++ b/frame/staking/reward-fn/Cargo.toml @@ -14,12 +14,12 @@ targets = ["x86_64-unknown-linux-gnu"] [lib] [dependencies] -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../../primitives/arithmetic" } log = { version = "0.4.16", default-features = false } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../../primitives/arithmetic" } [features] default = ["std"] std = [ - "sp-arithmetic/std", "log/std", + "sp-arithmetic/std", ] diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index 0c6ad240281e1..cae3bb1a9f975 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet migration of trie" readme = "README.md" @@ -13,40 +13,37 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4.16", default-features = false } - -sp-std = { default-features = false, path = "../../primitives/std" } -sp-io = { default-features = false, path = "../../primitives/io" } -sp-core = { default-features = false, path = "../../primitives/core" } -sp-runtime = { default-features = false, path = "../../primitives/runtime" } -substrate-state-trie-migration-rpc = { optional = true, path = "../../utils/frame/rpc/state-trie-migration-rpc" } - -frame-support = { default-features = false, path = "../support" } -frame-system = { default-features = false, path = "../system" } -frame-benchmarking = { default-features = false, path = "../benchmarking", optional = true } - +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.133", optional = true } thousands = { version = "0.2.0", optional = true } -remote-externalities = { path = "../../utils/frame/remote-externalities", optional = true } zstd = { version = "0.10.0", default-features = false, optional = true } +frame-benchmarking = { default-features = false, optional = true, path = "../benchmarking" } +frame-support = { default-features = false, path = "../support" } +frame-system = { default-features = false, path = "../system" } +remote-externalities = { optional = true, path = "../../utils/frame/remote-externalities" } +sp-core = { default-features = false, path = "../../primitives/core" } +sp-io = { default-features = false, path = "../../primitives/io" } +sp-runtime = { default-features = false, path = "../../primitives/runtime" } +sp-std = { default-features = false, path = "../../primitives/std" } +substrate-state-trie-migration-rpc = { optional = true, path = "../../utils/frame/rpc/state-trie-migration-rpc" } [dev-dependencies] -pallet-balances = { path = "../balances" } parking_lot = "0.12.0" -sp-tracing = { path = "../../primitives/tracing" } tokio = { version = "1.10", features = ["macros"] } +pallet-balances = { path = "../balances" } +sp-tracing = { path = "../../primitives/tracing" } [features] default = ["std"] std = [ - "log/std", - "scale-info/std", "codec/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", + "log/std", + "scale-info/std", "sp-core/std", "sp-io/std", "sp-runtime/std", @@ -54,5 +51,4 @@ std = [ ] runtime-benchmarks = ["frame-benchmarking"] try-runtime = ["frame-support/try-runtime"] - -remote-test = [ "std", "zstd", "serde", "thousands", "remote-externalities", "substrate-state-trie-migration-rpc" ] +remote-test = [ "remote-externalities", "serde", "std", "substrate-state-trie-migration-rpc", "thousands", "zstd" ] diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index b209351ddaf07..d2b3f98e65d0b 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] sp-core = { version = "6.0.0", path = "../../primitives/core" } @@ -28,11 +28,11 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", + "frame-support/std", + "frame-system/std", "scale-info/std", - "sp-std/std", "sp-io/std", "sp-runtime/std", - "frame-support/std", - "frame-system/std", + "sp-std/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 8f7438710dfdb..f8b325479c31d 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } +Inflector = "0.11.4" proc-macro2 = "1.0.37" quote = "1.0.10" -Inflector = "0.11.4" syn = { version = "1.0.82", features = ["full"] } +frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } [features] default = ["std"] diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index 00c453b1f1928..f76b2480f9838 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -12,8 +12,8 @@ description = "Proc macro helpers for procedural macros" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" } +proc-macro-crate = "1.1.3" proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "visit", "extra-traits"] } -proc-macro-crate = "1.1.3" +frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" } diff --git a/frame/support/procedural/tools/derive/Cargo.toml b/frame/support/procedural/tools/derive/Cargo.toml index 8d536be1cb725..6aface4ae0937 100644 --- a/frame/support/procedural/tools/derive/Cargo.toml +++ b/frame/support/procedural/tools/derive/Cargo.toml @@ -17,4 +17,4 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.37" quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.82", features = ["proc-macro" ,"full", "extra-traits", "parsing"] } +syn = { version = "1.0.82", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index 5850d2e5db148..c1619c6a56c97 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" publish = false -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" [package.metadata.docs.rs] @@ -14,20 +14,20 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../../../primitives/core" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "5.0.0", default-features = false, path = "../../../../primitives/version" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } [features] default = ["std"] std = [ "codec/std", + "frame-support/std", + "frame-system/std", "scale-info/std", "sp-core/std", "sp-runtime/std", "sp-version/std", - "frame-support/std", - "frame-system/std", ] diff --git a/frame/support/test/pallet/Cargo.toml b/frame/support/test/pallet/Cargo.toml index 51b74d5ec55fe..bf5febeb45441 100644 --- a/frame/support/test/pallet/Cargo.toml +++ b/frame/support/test/pallet/Cargo.toml @@ -21,7 +21,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../../ default = ["std"] std = [ "codec/std", - "scale-info/std", "frame-support/std", "frame-system/std", + "scale-info/std", ] diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 935038837d955..f1d2491ad0919 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -13,16 +13,16 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"], optional = true } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-version = { version = "5.0.0", default-features = false, path = "../../primitives/version" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -log = { version = "0.4.16", default-features = false } [dev-dependencies] criterion = "0.3.3" @@ -32,20 +32,20 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/ru [features] default = ["std"] std = [ - "serde", "codec/std", + "frame-support/std", + "log/std", "scale-info/std", + "serde", "sp-core/std", - "sp-std/std", "sp-io/std", - "frame-support/std", "sp-runtime/std", + "sp-std/std", "sp-version/std", - "log/std", ] runtime-benchmarks = [ - "sp-runtime/runtime-benchmarks", "frame-support/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index c543d5af0412e..b39b1a1c75b9d 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] sp-io = { version = "6.0.0", path = "../../../primitives/io" } @@ -29,11 +29,11 @@ sp-io = { version = "6.0.0", path = "../../../primitives/io" } default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-runtime/std", - "sp-std/std", "frame-benchmarking/std", - "frame-system/std", "frame-support/std", + "frame-system/std", + "scale-info/std", "sp-core/std", + "sp-runtime/std", + "sp-std/std", ] diff --git a/frame/system/rpc/runtime-api/Cargo.toml b/frame/system/rpc/runtime-api/Cargo.toml index e2f85000f5d05..63d76d731e26e 100644 --- a/frame/system/rpc/runtime-api/Cargo.toml +++ b/frame/system/rpc/runtime-api/Cargo.toml @@ -13,12 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } [features] default = ["std"] std = [ - "sp-api/std", "codec/std", + "sp-api/std", ] diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 83eb8a38eca77..971a0ace95d73 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -13,37 +13,36 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io", optional = true } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } +sp-io = { version = "6.0.0", default-features = false, optional = true, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../primitives/timestamp" } -log = { version = "0.4.16", default-features = false } [dev-dependencies] -sp-io ={ version = "6.0.0", path = "../../primitives/io" } sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ - "sp-inherents/std", "codec/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", - "sp-timestamp/std", "log/std", + "scale-info/std", + "sp-inherents/std", + "sp-runtime/std", + "sp-std/std", + "sp-timestamp/std", ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "sp-io"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 6cfdd2d1e7062..364135daa97f6 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -17,37 +17,33 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } - +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } - -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } - [dev-dependencies] -sp-storage = { version = "6.0.0", path = "../../primitives/storage" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-storage = { version = "6.0.0", path = "../../primitives/storage" } [features] default = ["std"] std = [ "codec/std", + "frame-support/std", + "frame-system/std", "log/std", + "pallet-treasury/std", "scale-info/std", "serde", - "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", - "frame-support/std", - "frame-system/std", - "pallet-treasury/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index d37a98deecb2a..6da8f4c699097 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -19,14 +19,12 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } smallvec = "1.8.0" - -sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } -sp-io = { version = "6.0.0", path = "../../primitives/io", default-features = false } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } - frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] serde_json = "1.0.79" @@ -35,14 +33,14 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] std = [ - "serde", "codec/std", + "frame-support/std", + "frame-system/std", "scale-info/std", + "serde", "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", - "frame-support/std", - "frame-system/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 64d7007dfe6c2..b7a353916efbc 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -17,10 +17,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" - +pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index d057361e1f5f7..5e1cb46753524 100644 --- a/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -14,15 +14,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } -pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment" } [features] default = ["std"] std = [ "codec/std", + "pallet-transaction-payment/std", "sp-api/std", "sp-runtime/std", - "pallet-transaction-payment/std", ] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index eec505708ed7d..47cf69cf73f8b 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -13,36 +13,36 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.136", optional = true } -hex-literal = { version = "0.3.4", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +hex-literal = { version = "0.3.4", optional = true } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } +sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-storage-proof" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = true, path = "../../primitives/transaction-storage-proof" } -sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false } [features] default = ["std"] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "hex-literal"] std = [ - "serde", "codec/std", - "scale-info/std", - "sp-runtime/std", "frame-support/std", "frame-system/std", "pallet-balances/std", + "scale-info/std", + "serde", + "sp-inherents/std", "sp-io/std", + "sp-runtime/std", "sp-std/std", - "sp-inherents/std", ] diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 85745c6c99fd4..4ae2c035e482a 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -17,34 +17,31 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", "max-encoded-len", ] } +impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -impl-trait-for-tuples = "0.2.2" - -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } - -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } - +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "serde", - "sp-std/std", - "sp-runtime/std", "frame-support/std", "frame-system/std", "pallet-balances/std", + "scale-info/std", + "serde", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index e40b92b8e98db..075de318c2a05 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -13,17 +13,16 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-api = { version = "4.0.0-dev", path = "../../primitives/api", default-features = false } -sp-std = { version = "4.0.0", path = "../../primitives/std" , default-features = false } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" , default-features = false } - -frame-support = { version = "4.0.0-dev", path = "../support", default-features = false } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [features] default = [ "std" ] std = [ + "frame-support/std", "sp-api/std", - "sp-std/std", "sp-runtime/std", - "frame-support/std", + "sp-std/std", ] diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index e8b95b8cb80c7..3f78df96b3517 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -14,34 +14,34 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -log = { version = "0.4.16", default-features = false } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-std = { version = "4.0.0", path = "../../primitives/std" } +pallet-balances = { version = "4.0.0-dev", path = "../balances" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-io = { version = "6.0.0", path = "../../primitives/io" } -pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-std = { version = "4.0.0", path = "../../primitives/std" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", + "frame-benchmarking/std", "frame-support/std", "frame-system/std", - "frame-benchmarking/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 6235d1ee15556..0c307020b521b 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -15,28 +15,27 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } - -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-runtime/std", "frame-support/std", "frame-system/std", + "scale-info/std", "sp-io/std", + "sp-runtime/std", "sp-std/std", ] runtime-benchmarks = [ diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 01ce92c6eaa4f..d8cb200caf062 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -16,28 +16,28 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } +log = { version = "0.4.16", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -log = { version = "0.4.16", default-features = false } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", "frame-support/std", "frame-system/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/whitelist/Cargo.toml b/frame/whitelist/Cargo.toml index 5f414e5d32033..c808cacb801af 100644 --- a/frame/whitelist/Cargo.toml +++ b/frame/whitelist/Cargo.toml @@ -15,30 +15,29 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.0", default-features = false, features = ["derive"] } -sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } - +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ "codec/std", + "frame-support/std", + "frame-system/std", "scale-info/std", "sp-api/std", "sp-runtime/std", "sp-std/std", - "frame-support/std", - "frame-system/std", ] runtime-benchmarks = [ "frame-benchmarking", diff --git a/primitives/application-crypto/test/Cargo.toml b/primitives/application-crypto/test/Cargo.toml index 9e93e78f69ffb..2962fb7477735 100644 --- a/primitives/application-crypto/test/Cargo.toml +++ b/primitives/application-crypto/test/Cargo.toml @@ -13,9 +13,9 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "6.0.0", default-features = false, path = "../../core" } -sp-keystore = { version = "0.12.0", path = "../../keystore", default-features = false } -substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -sp-runtime = { version = "6.0.0", path = "../../runtime" } sp-api = { version = "4.0.0-dev", path = "../../api" } sp-application-crypto = { version = "6.0.0", path = "../" } +sp-core = { version = "6.0.0", default-features = false, path = "../../core" } +sp-keystore = { version = "0.12.0", default-features = false, path = "../../keystore" } +sp-runtime = { version = "6.0.0", path = "../../runtime" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 26ee7677363c9..31b893531a8d5 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -13,34 +13,33 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", "max-encoded-len", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } integer-sqrt = "0.1.2" -static_assertions = "1.1.0" num-traits = { version = "0.2.8", default-features = false } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -serde = { version = "1.0.136", optional = true, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"], optional = true } +static_assertions = "1.1.0" sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] -rand = "0.7.2" criterion = "0.3" primitive-types = "0.11.1" +rand = "0.7.2" [features] default = ["std"] std = [ "codec/std", - "scale-info/std", "num-traits/std", - "sp-std/std", + "scale-info/std", "serde", "sp-debug-derive/std", + "sp-std/std", ] [[bench]] diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index e51dd4e415a6c..33bf313766545 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -14,10 +14,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-arithmetic = { version = "5.0.0", path = ".." } honggfuzz = "0.5.49" -primitive-types = "0.11.1" num-bigint = "0.2" +primitive-types = "0.11.1" +sp-arithmetic = { version = "5.0.0", path = ".." } [[bin]] name = "biguint" diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index c452aaa892020..6a822bf20b329 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -13,20 +13,20 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } -codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] default = ["std"] std = [ - "sp-application-crypto/std", "codec/std", "scale-info/std", - "sp-std/std", "sp-api/std", - "sp-runtime/std" + "sp-application-crypto/std", + "sp-runtime/std", + "sp-std/std", ] diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index 75e94b895f120..714d0a2610312 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -13,18 +13,18 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +async-trait = { version = "0.1.50", optional = true } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -async-trait = { version = "0.1.50", optional = true } [features] default = [ "std" ] std = [ + "async-trait", "codec/std", - "sp-std/std", "sp-inherents/std", "sp-runtime/std", - "async-trait", + "sp-std/std", ] diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index cf901f4a34fc6..83896674175bc 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -13,14 +13,13 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } - -sp-api = { version = "4.0.0-dev", path = "../api", default-features = false } -sp-application-crypto = { version = "6.0.0", path = "../application-crypto", default-features = false } -sp-core = { version = "6.0.0", path = "../core", default-features = false } -sp-runtime = { version = "6.0.0", path = "../runtime", default-features = false } -sp-std = { version = "4.0.0", path = "../std", default-features = false } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] hex = "0.4.3" diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index 6d7a0a2789c2a..a081b56b9d98a 100644 --- a/primitives/block-builder/Cargo.toml +++ b/primitives/block-builder/Cargo.toml @@ -13,18 +13,18 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] std = [ - "sp-runtime/std", "codec/std", - "sp-inherents/std", "sp-api/std", + "sp-inherents/std", + "sp-runtime/std", "sp-std/std", ] diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index f242132798efa..4389a867f7132 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -14,14 +14,14 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +futures = "0.3.21" log = "0.4.16" lru = "0.7.5" parking_lot = "0.12.0" thiserror = "1.0.30" -futures = "0.3.21" -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +sp-api = { version = "4.0.0-dev", path = "../api" } sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" } +sp-database = { version = "4.0.0-dev", path = "../database" } sp-runtime = { version = "6.0.0", path = "../runtime" } sp-state-machine = { version = "0.12.0", path = "../state-machine" } -sp-database = { version = "4.0.0-dev", path = "../database" } -sp-api = { version = "4.0.0-dev", path = "../api" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index 2c4a2f0a0de99..41d02ac0779a3 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -13,30 +13,30 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } +async-trait = { version = "0.1.50", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } +sp-consensus = { version = "0.10.0-dev", optional = true, path = "../common" } +sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../timestamp" } -sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } -sp-consensus = { version = "0.10.0-dev", path = "../common", optional = true } -async-trait = { version = "0.1.50", optional = true } [features] default = ["std"] std = [ - "sp-application-crypto/std", + "async-trait", "codec/std", "scale-info/std", - "sp-std/std", "sp-api/std", - "sp-runtime/std", + "sp-application-crypto/std", + "sp-consensus", + "sp-consensus-slots/std", "sp-inherents/std", + "sp-runtime/std", + "sp-std/std", "sp-timestamp/std", - "sp-consensus-slots/std", - "sp-consensus", - "async-trait", ] diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 189dc5b2e80f7..57775a1b718da 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -13,32 +13,33 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } +async-trait = { version = "0.1.50", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } merlin = { version = "2.0", default-features = false } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } sp-consensus = { version = "0.10.0-dev", optional = true, path = "../common" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } -sp-consensus-vrf = { version = "0.10.0-dev", path = "../vrf", default-features = false } +sp-consensus-vrf = { version = "0.10.0-dev", default-features = false, path = "../vrf" } sp-core = { version = "6.0.0", default-features = false, path = "../../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } -sp-keystore = { version = "0.12.0", default-features = false, path = "../../keystore", optional = true } +sp-keystore = { version = "0.12.0", default-features = false, optional = true, path = "../../keystore" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } -sp-timestamp = { version = "4.0.0-dev", path = "../../timestamp", optional = true } -serde = { version = "1.0.136", features = ["derive"], optional = true } -async-trait = { version = "0.1.50", optional = true } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +sp-timestamp = { version = "4.0.0-dev", optional = true, path = "../../timestamp" } [features] default = ["std"] std = [ - "sp-application-crypto/std", + "async-trait", "codec/std", - "scale-info/std", "merlin/std", - "sp-std/std", + "scale-info/std", + "serde", "sp-api/std", + "sp-application-crypto/std", "sp-consensus", "sp-consensus-slots/std", "sp-consensus-vrf/std", @@ -46,7 +47,6 @@ std = [ "sp-inherents/std", "sp-keystore", "sp-runtime/std", - "serde", + "sp-std/std", "sp-timestamp", - "async-trait", ] diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index afbe437a16fa4..5dc94872d6141 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -16,18 +16,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.42" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ - "derive", + "derive", ] } futures = { version = "0.3.21", features = ["thread-pool"] } +futures-timer = "3.0.1" log = "0.4.16" -sp-core = { path = "../../core", version = "6.0.0"} +thiserror = "1.0.30" +sp-core = { version = "6.0.0", path = "../../core" } sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } +sp-runtime = { version = "6.0.0", path = "../../runtime" } sp-state-machine = { version = "0.12.0", path = "../../state-machine" } -futures-timer = "3.0.1" sp-std = { version = "4.0.0", path = "../../std" } sp-version = { version = "5.0.0", path = "../../version" } -sp-runtime = { version = "6.0.0", path = "../../runtime" } -thiserror = "1.0.30" [dev-dependencies] futures = "0.3.21" diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index eb2db085c482b..f909b0b466a71 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -13,18 +13,18 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } sp-core = { version = "6.0.0", default-features = false, path = "../../core" } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } [features] default = ["std"] std = [ - "sp-std/std", + "codec/std", "sp-api/std", - "sp-runtime/std", "sp-core/std", - "codec/std", + "sp-runtime/std", + "sp-std/std", ] diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 80d2d1ddb09d1..9c8dca910b7e6 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -13,18 +13,18 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false } -schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } -sp-std = { version = "4.0.0", path = "../../std", default-features = false } -sp-core = { version = "6.0.0", path = "../../core", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +schnorrkel = { version = "0.9.1", default-features = false, features = ["preaudit_deprecated", "u64_backend"] } +sp-core = { version = "6.0.0", default-features = false, path = "../../core" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } [features] default = ["std"] std = [ "codec/std", "schnorrkel/std", - "sp-std/std", "sp-core/std", "sp-runtime/std", + "sp-std/std", ] diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index 0aee960f9e13d..b3ce080f7a704 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -4,7 +4,7 @@ version = "4.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Primitive core crate hashing implementation." documentation = "https://docs.rs/sp-core-hashing" @@ -13,21 +13,20 @@ documentation = "https://docs.rs/sp-core-hashing" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +blake2 = { version = "0.10.2", default-features = false } byteorder = { version = "1.3.2", default-features = false } - digest = { version = "0.10.3", default-features = false } -blake2 = { version = "0.10.2", default-features = false } sha2 = { version = "0.10.2", default-features = false } sha3 = { version = "0.10.0", default-features = false } twox-hash = { version = "1.6.2", default-features = false, features = ["digest_0_10"] } +sp-std = { version = "4.0.0", default-features = false, path = "../../std" } [features] default = ["std"] std = [ - "sp-std/std", "blake2/std", "sha2/std", "sha3/std", + "sp-std/std", "twox-hash/std", ] diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index 9a5f991d04362..0d8431facb874 100644 --- a/primitives/core/hashing/proc-macro/Cargo.toml +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -4,7 +4,7 @@ version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" -homepage = "https://substrate.dev" +homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "This crate provides procedural macros for calculating static hash." documentation = "https://docs.rs/sp-core-hashing-proc-macro" @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.82", features = ["full", "parsing"] } -quote = "1.0.6" proc-macro2 = "1.0.37" -sp-core-hashing = { version = "4.0.0", path = "../", default-features = false } +quote = "1.0.6" +syn = { version = "1.0.82", features = ["full", "parsing"] } +sp-core-hashing = { version = "4.0.0", default-features = false, path = "../" } diff --git a/primitives/database/Cargo.toml b/primitives/database/Cargo.toml index 198f44510209e..5aa3d9a239aa3 100644 --- a/primitives/database/Cargo.toml +++ b/primitives/database/Cargo.toml @@ -11,6 +11,5 @@ documentation = "https://docs.rs/sp-database" readme = "README.md" [dependencies] -parking_lot = "0.12.0" kvdb = "0.11.0" - +parking_lot = "0.12.0" diff --git a/primitives/externalities/Cargo.toml b/primitives/externalities/Cargo.toml index 4fc8619a9ba5c..e84047d5da5ed 100644 --- a/primitives/externalities/Cargo.toml +++ b/primitives/externalities/Cargo.toml @@ -14,10 +14,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-storage = { version = "6.0.0", path = "../storage", default-features = false } -sp-std = { version = "4.0.0", path = "../std", default-features = false } -environmental = { version = "1.1.3", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +environmental = { version = "1.1.3", default-features = false } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } [features] default = ["std"] diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index e6464207e67f2..277236abc0f8c 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -13,28 +13,27 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.15.0", default-features = false, features = ["derive-codec"] } log = { version = "0.4.16", optional = true } -serde = { version = "1.0.136", optional = true, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-keystore = { version = "0.12.0", default-features = false, path = "../keystore", optional = true } +sp-keystore = { version = "0.12.0", default-features = false, optional = true, path = "../keystore" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] default = ["std"] std = [ - "log", - "serde", "codec/std", - "scale-info/std", "grandpa/std", + "log", + "scale-info/std", + "serde", "sp-api/std", "sp-application-crypto/std", "sp-core/std", diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 0e701a397d7d9..c7e10be32fe28 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -13,15 +13,14 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "6.0.0", path = "../runtime", optional = true } +async-trait = { version = "0.1.50", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -thiserror = { version = "1.0.30", optional = true } impl-trait-for-tuples = "0.2.2" -async-trait = { version = "0.1.50", optional = true } +thiserror = { version = "1.0.30", optional = true } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "6.0.0", optional = true, path = "../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] futures = "0.3.21" @@ -29,10 +28,10 @@ futures = "0.3.21" [features] default = [ "std" ] std = [ - "sp-std/std", + "async-trait", "codec/std", "sp-core/std", - "thiserror", "sp-runtime", - "async-trait", + "sp-std/std", + "thiserror", ] diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 6186a51fef853..8f1adb6cf81f3 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "6.0.0", path = "../core" } -sp-runtime = { version = "6.0.0", path = "../runtime" } lazy_static = "1.4.0" strum = { version = "0.23.0", features = ["derive"] } +sp-core = { version = "6.0.0", path = "../core" } +sp-runtime = { version = "6.0.0", path = "../runtime" } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index f201cb8518bc6..551626adbc4e8 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -14,16 +14,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } futures = "0.3.21" +merlin = { version = "2.0", default-features = false } parking_lot = { version = "0.12.0", default-features = false } +schnorrkel = { version = "0.9.1", default-features = false, features = ["preaudit_deprecated", "u64_backend"] } serde = { version = "1.0", optional = true } thiserror = "1.0" - -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } -merlin = { version = "2.0", default-features = false } sp-core = { version = "6.0.0", path = "../core" } -sp-externalities = { version = "0.12.0", path = "../externalities", default-features = false } +sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } [dev-dependencies] rand = "0.7.2" @@ -32,6 +31,6 @@ rand_chacha = "0.2.2" [features] default = ["std"] std = [ - "serde", "schnorrkel/std", + "serde", ] diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index d6e244d50c495..831d07315f317 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -14,8 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4.16", default-features = false } -serde = { version = "1.0.136", optional = true, features = ["derive"] } - +serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 13edbfe90008b..7cd3ed1489798 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -15,15 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -serde = { version = "1.0.136", optional = true, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +serde = { version = "1.0.136", features = ["derive"], optional = true } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "6.0.0", path = "../runtime", default-features = false } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] -substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } rand = "0.7.3" +substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] default = ["std"] @@ -32,8 +32,8 @@ std = [ "codec/std", "scale-info/std", "serde", - "sp-std/std", "sp-arithmetic/std", "sp-core/std", "sp-runtime/std", + "sp-std/std", ] diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 71c0c07c3032a..f8cc21cb61077 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -15,10 +15,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "3.1.6", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } - -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } sp-runtime = { version = "6.0.0", path = "../../runtime" } diff --git a/primitives/offchain/Cargo.toml b/primitives/offchain/Cargo.toml index ff647f0e74205..f21c2fe837110 100644 --- a/primitives/offchain/Cargo.toml +++ b/primitives/offchain/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } [features] default = ["std"] -std = ["sp-core/std", "sp-api/std", "sp-runtime/std"] +std = ["sp-api/std", "sp-core/std", "sp-runtime/std"] diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml index 7b2023eff0bfc..bd429fd0e8af7 100644 --- a/primitives/panic-handler/Cargo.toml +++ b/primitives/panic-handler/Cargo.toml @@ -15,5 +15,5 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] backtrace = "0.3.64" -regex = "1.5.5" lazy_static = "1.4.0" +regex = "1.5.5" diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index dcfd48558de25..335eb6d6c9a0e 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -13,9 +13,9 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +rustc-hash = "1.1.0" serde = { version = "1.0.136", features = ["derive"] } sp-core = { version = "6.0.0", path = "../core" } -rustc-hash = "1.1.0" [dev-dependencies] serde_json = "1.0.79" diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 3c66f371b7a0c..a3ae1fd48651c 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.82", features = ["full", "visit", "fold", "extra-traits"] } -quote = "1.0.10" -proc-macro2 = "1.0.37" Inflector = "0.11.4" proc-macro-crate = "1.1.3" +proc-macro2 = "1.0.37" +quote = "1.0.10" +syn = { version = "1.0.82", features = ["full", "visit", "fold", "extra-traits"] } diff --git a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 1b0c9f57e5c44..2905cf2c9879e 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -13,14 +13,14 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] +sp-core = { version = "6.0.0", default-features = false, path = "../../core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../io" } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../io" } -sp-core = { version = "6.0.0", default-features = false, path = "../../core" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } [features] default = [ "std" ] -std = [ "sp-runtime-interface/std", "sp-std/std", "sp-core/std", "sp-io/std" ] +std = [ "sp-core/std", "sp-io/std", "sp-runtime-interface/std", "sp-std/std" ] diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index 4dfa0fd015d89..f0e78e0e536b9 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -13,14 +13,14 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] +sp-core = { version = "6.0.0", default-features = false, path = "../../core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../io" } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../" } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../io" } -sp-core = { version = "6.0.0", default-features = false, path = "../../core" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } [features] default = [ "std" ] -std = [ "sp-runtime-interface/std", "sp-std/std", "sp-core/std", "sp-io/std" ] +std = [ "sp-core/std", "sp-io/std", "sp-runtime-interface/std", "sp-std/std" ] diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 60962bb16caf5..e897fc0bab71c 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -12,13 +12,13 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-runtime-interface = { version = "6.0.0", path = "../" } +tracing = "0.1.29" +tracing-core = "0.1.26" sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-executor-common = { version = "0.10.0-dev", path = "../../../client/executor/common" } +sp-io = { version = "6.0.0", path = "../../io" } +sp-runtime = { version = "6.0.0", path = "../../runtime" } +sp-runtime-interface = { version = "6.0.0", path = "../" } sp-runtime-interface-test-wasm = { version = "2.0.0", path = "../test-wasm" } sp-runtime-interface-test-wasm-deprecated = { version = "2.0.0", path = "../test-wasm-deprecated" } sp-state-machine = { version = "0.12.0", path = "../../state-machine" } -sp-runtime = { version = "6.0.0", path = "../../runtime" } -sp-io = { version = "6.0.0", path = "../../io" } -tracing = "0.1.29" -tracing-core = "0.1.26" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 2d6080f7af849..04e5c2a9fe6ec 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -13,49 +13,48 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - [dependencies] -serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +either = { version = "1.5", default-features = false } +hash256-std-hasher = { version = "0.15.2", default-features = false } +impl-trait-for-tuples = "0.2.2" +log = { version = "0.4.16", default-features = false } +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +paste = "1.0" +rand = { version = "0.7.2", optional = true } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } +serde = { version = "1.0.136", features = ["derive"], optional = true } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } -log = { version = "0.4.16", default-features = false } -paste = "1.0" -rand = { version = "0.7.2", optional = true } -impl-trait-for-tuples = "0.2.2" -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } -hash256-std-hasher = { version = "0.15.2", default-features = false } -either = { version = "1.5", default-features = false } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] -serde_json = "1.0.79" rand = "0.7.2" -sp-state-machine = { version = "0.12.0", path = "../state-machine" } +serde_json = "1.0.79" +zstd = { version = "0.10.0", default-features = false } sp-api = { version = "4.0.0-dev", path = "../api" } -substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } +sp-state-machine = { version = "0.12.0", path = "../state-machine" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } -zstd = { version = "0.10.0", default-features = false } +substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] bench = [] runtime-benchmarks = [] default = ["std"] std = [ - "sp-application-crypto/std", - "sp-arithmetic/std", "codec/std", - "scale-info/std", + "either/use_std", + "hash256-std-hasher/std", "log/std", - "sp-core/std", + "parity-util-mem/std", "rand", - "sp-std/std", - "sp-io/std", + "scale-info/std", "serde", - "parity-util-mem/std", - "hash256-std-hasher/std", - "either/use_std", + "sp-application-crypto/std", + "sp-arithmetic/std", + "sp-core/std", + "sp-io/std", + "sp-std/std", ] diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index db9301a53029b..6a83e20a94618 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -19,10 +19,9 @@ wasmi = { version = "0.9.1", default-features = false, features = ["core"] } wasmi = "0.9.0" [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4", default-features = false } wasmi = { version = "0.9.0", optional = true } - -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } @@ -35,13 +34,13 @@ wat = "1.0" [features] default = ["std"] std = [ - "log/std", - "wasmi", "codec/std", + "log/std", "sp-core/std", "sp-io/std", "sp-std/std", "sp-wasm-interface/std", + "wasmi", ] strict = [] wasmer-sandbox = [] diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index 476bacc88ae34..b45e7131d5fee 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" } sp-runtime = { version = "6.0.0", optional = true, path = "../runtime" } +sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] @@ -28,7 +28,7 @@ std = [ "scale-info/std", "sp-api/std", "sp-core/std", - "sp-std/std", - "sp-staking/std", "sp-runtime/std", + "sp-staking/std", + "sp-std/std", ] diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 0080c72b1f0d0..7ee9fe98877a6 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -14,43 +14,43 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { version = "0.4.16", optional = true } -thiserror = { version = "1.0.30", optional = true } -parking_lot = { version = "0.12.0", optional = true } -hash-db = { version = "0.15.2", default-features = false } -trie-root = { version = "0.17.0", default-features = false } -sp-trie = { version = "6.0.0", path = "../trie", default-features = false } -sp-core = { version = "6.0.0", path = "../core", default-features = false } -sp-panic-handler = { version = "4.0.0", path = "../panic-handler", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +hash-db = { version = "0.15.2", default-features = false } +log = { version = "0.4.16", optional = true } num-traits = { version = "0.2.8", default-features = false } +parking_lot = { version = "0.12.0", optional = true } rand = { version = "0.7.2", optional = true } -sp-externalities = { version = "0.12.0", path = "../externalities", default-features = false } smallvec = "1.8.0" -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +thiserror = { version = "1.0.30", optional = true } tracing = { version = "0.1.29", optional = true } +trie-root = { version = "0.17.0", default-features = false } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } +sp-panic-handler = { version = "4.0.0", optional = true, path = "../panic-handler" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-trie = { version = "6.0.0", default-features = false, path = "../trie" } [dev-dependencies] hex-literal = "0.3.4" -sp-runtime = { version = "6.0.0", path = "../runtime" } pretty_assertions = "1.0.0" rand = "0.7.2" +sp-runtime = { version = "6.0.0", path = "../runtime" } [features] default = ["std"] std = [ "codec/std", "hash-db/std", + "log", "num-traits/std", + "parking_lot", + "rand", "sp-core/std", "sp-externalities/std", + "sp-panic-handler", "sp-std/std", "sp-trie/std", - "trie-root/std", - "log", "thiserror", - "parking_lot", - "rand", - "sp-panic-handler", - "tracing" + "tracing", + "trie-root/std", ] diff --git a/primitives/std/Cargo.toml b/primitives/std/Cargo.toml index 4c6aa8f40b498..e4a6a9f6a614f 100644 --- a/primitives/std/Cargo.toml +++ b/primitives/std/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" - description = "Lowest-abstraction level for the Substrate runtime: just exports useful primitives from std or client/alloc to be used with any code that depends on the runtime." documentation = "https://docs.rs/sp-std" readme = "README.md" diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index a304bd660cc1e..b37a4eb4b331d 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -14,13 +14,13 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -serde = { version = "1.0.136", optional = true, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } impl-serde = { version = "0.3.1", optional = true } ref-cast = "1.0.0" +serde = { version = "1.0.136", features = ["derive"], optional = true } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] -std = [ "sp-std/std", "serde", "impl-serde", "codec/std", "sp-debug-derive/std" ] +std = [ "codec/std", "impl-serde", "serde", "sp-debug-derive/std", "sp-std/std" ] diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index bf97212d08914..647a8ed63ff91 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -22,7 +22,7 @@ sp-runtime-interface = { version = "6.0.0", default-features = false, path = ".. sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] -codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } [features] default = ["std"] diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 0d491ea217c6c..1333c340a68a7 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -12,18 +12,18 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +serde = { version = "1.0.136", features = ["derive"], optional = true } +sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } -serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } [features] default = [ "std", ] std = [ - "sp-application-crypto/std", "serde", + "sp-application-crypto/std", ] diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index db753b0b708d9..8b40050b4aaa5 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -13,26 +13,26 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +async-trait = { version = "0.1.50", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -thiserror = { version = "1.0.30", optional = true } -log = { version = "0.4.16", optional = true } futures-timer = { version = "3.0.2", optional = true } -async-trait = { version = "0.1.50", optional = true } +log = { version = "0.4.16", optional = true } +thiserror = { version = "1.0.30", optional = true } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } +sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] std = [ - "sp-api/std", - "sp-std/std", - "sp-runtime/std", + "async-trait", "codec/std", + "futures-timer", + "log", + "sp-api/std", "sp-inherents/std", + "sp-runtime/std", + "sp-std/std", "thiserror", - "log", - "futures-timer", - "async-trait", ] diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index 7e8949d3da4b4..e017377ac63de 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -13,26 +13,26 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +async-trait = { version = "0.1.50", optional = true } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +log = { version = "0.4.16", optional = true } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +sp-core = { version = "6.0.0", optional = true, path = "../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-trie = { version = "6.0.0", optional = true, path = "../trie" } -sp-core = { version = "6.0.0", path = "../core", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -log = { version = "0.4.16", optional = true } -async-trait = { version = "0.1.50", optional = true } [features] default = [ "std" ] std = [ + "async-trait", "codec/std", + "log", "scale-info/std", - "sp-std/std", + "sp-core", "sp-inherents/std", "sp-runtime/std", + "sp-std/std", "sp-trie/std", - "sp-core", - "log", - "async-trait", ] diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index f434a15b8964a..60dd88b187bd2 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -19,33 +19,33 @@ harness = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } hash-db = { version = "0.15.2", default-features = false } +memory-db = { version = "0.29.0", default-features = false } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +thiserror = { version = "1.0.30", optional = true } trie-db = { version = "0.23.1", default-features = false } trie-root = { version = "0.17.0", default-features = false } -memory-db = { version = "0.29.0", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../core" } -thiserror = { version = "1.0.30", optional = true } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] -trie-bench = "0.30.0" -trie-standardmap = "0.15.2" criterion = "0.3.3" hex-literal = "0.3.4" +trie-bench = "0.30.0" +trie-standardmap = "0.15.2" sp-runtime = { version = "6.0.0", path = "../runtime" } [features] default = ["std"] std = [ - "sp-std/std", "codec/std", - "scale-info/std", "hash-db/std", "memory-db/std", - "trie-db/std", - "trie-root/std", + "scale-info/std", "sp-core/std", + "sp-std/std", "thiserror", + "trie-db/std", + "trie-root/std", ] memory-tracker = [] diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 7488d924070cb..8e48891a3c74e 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -14,26 +14,26 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -impl-serde = { version = "0.3.1", optional = true } -serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +impl-serde = { version = "0.3.1", optional = true } +parity-wasm = { version = "0.42.2", optional = true } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +serde = { version = "1.0.136", features = ["derive"], optional = true } +thiserror = { version = "1.0.30", optional = true } +sp-core-hashing-proc-macro = { version = "5.0.0", path = "../core/hashing/proc-macro" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" } -parity-wasm = { version = "0.42.2", optional = true } -sp-core-hashing-proc-macro = { version = "5.0.0", path = "../core/hashing/proc-macro" } -thiserror = { version = "1.0.30", optional = true } [features] default = ["std"] std = [ - "impl-serde", - "serde", "codec/std", + "impl-serde", + "parity-wasm", "scale-info/std", - "sp-std/std", + "serde", "sp-runtime/std", - "parity-wasm", + "sp-std/std", "thiserror", ] diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index b9ab7cee0ad2c..5b544c7ddd07d 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } +proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } -proc-macro2 = "1.0.37" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } [dev-dependencies] sp-version = { version = "5.0.0", path = ".." } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 3473370179b83..07e118d0ecc86 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -14,13 +14,13 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -wasmi = { version = "0.9.1", optional = true } -wasmtime = { version = "0.35.3", optional = true, default-features = false } -log = { version = "0.4.16", optional = true } -impl-trait-for-tuples = "0.2.2" -sp-std = { version = "4.0.0", path = "../std", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +impl-trait-for-tuples = "0.2.2" +log = { version = "0.4.16", optional = true } +wasmi = { version = "0.9.1", optional = true } +wasmtime = { version = "0.35.3", default-features = false, optional = true } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] -std = [ "wasmi", "sp-std/std", "codec/std", "log" ] +std = [ "codec/std", "log", "sp-std/std", "wasmi" ] diff --git a/scripts/ci/node-template-release/Cargo.toml b/scripts/ci/node-template-release/Cargo.toml index 667281f6dcad7..8871a04e19b16 100644 --- a/scripts/ci/node-template-release/Cargo.toml +++ b/scripts/ci/node-template-release/Cargo.toml @@ -4,18 +4,19 @@ version = "3.0.0" authors = ["Parity Technologies "] edition = "2021" license = "GPL-3.0" +homepage = "https://substrate.io" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] [dependencies] -toml = "0.4" -tar = "0.4" -glob = "0.2" clap = { version = "3.0", features = ["derive"] } -tempfile = "3" +flate2 = "1.0" fs_extra = "1" git2 = "0.8" -flate2 = "1.0" +glob = "0.2" +tar = "0.4" +tempfile = "3" +toml = "0.4" [workspace] - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index 9f66fa812bb4b..b60183c180b4a 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -13,9 +13,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.16" -substrate-test-utils-derive = { version = "0.10.0-dev", path = "./derive" } tokio = { version = "1.17.0", features = ["macros", "time"] } +substrate-test-utils-derive = { version = "0.10.0-dev", path = "./derive" } [dev-dependencies] -sc-service = { version = "0.10.0-dev", path = "../client/service" } trybuild = { version = "1.0.53", features = [ "diff" ] } +sc-service = { version = "0.10.0-dev", path = "../client/service" } diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index f99300f27eacb..1ff7d0de1d676 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -12,6 +12,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] +async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" hex = "0.4" @@ -19,19 +20,18 @@ serde = "1.0.136" serde_json = "1.0.79" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } sc-client-db = { version = "0.10.0-dev", features = [ - "test-helpers", + "test-helpers", ], path = "../../client/db" } sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } sc-executor = { version = "0.10.0-dev", path = "../../client/executor" } sc-offchain = { version = "4.0.0-dev", path = "../../client/offchain" } sc-service = { version = "0.10.0-dev", default-features = false, features = [ - "test-helpers", + "test-helpers", ], path = "../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } -async-trait = "0.1.50" diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index afa729c5163e9..aa4f9bb5eab85 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -9,10 +9,10 @@ repository = "https://github.com/paritytech/substrate/" description = "Substrate test utilities macros" [dependencies] -quote = "1.0.10" -syn = { version = "1.0.82", features = ["full"] } proc-macro-crate = "1.1.3" proc-macro2 = "1.0.37" +quote = "1.0.10" +syn = { version = "1.0.82", features = ["full"] } [lib] proc-macro = true diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index a22d9f302a9e9..3a3cfcbe33add 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -12,15 +12,15 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } +codec = { package = "parity-scale-codec", version = "3.0.0" } +futures = "0.3.21" sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } -substrate-test-client = { version = "2.0.0", path = "../../client" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -substrate-test-runtime = { version = "2.0.0", path = "../../runtime" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } +sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -codec = { package = "parity-scale-codec", version = "3.0.0" } -sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } -futures = "0.3.21" +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +substrate-test-client = { version = "2.0.0", path = "../../client" } +substrate-test-runtime = { version = "2.0.0", path = "../../runtime" } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index 59d576acdcb8f..98378309ad9c1 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -12,12 +12,12 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -substrate-test-runtime-client = { version = "2.0.0", path = "../client" } -parking_lot = "0.12.0" codec = { package = "parity-scale-codec", version = "3.0.0" } -sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } -sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } futures = "0.3.21" +parking_lot = "0.12.0" thiserror = "1.0" +sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } +sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +substrate-test-runtime-client = { version = "2.0.0", path = "../client" } diff --git a/test-utils/test-crate/Cargo.toml b/test-utils/test-crate/Cargo.toml index f6fea8407eaa7..2b66df6ae6513 100644 --- a/test-utils/test-crate/Cargo.toml +++ b/test-utils/test-crate/Cargo.toml @@ -13,5 +13,5 @@ targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] tokio = { version = "1.17.0", features = ["macros"] } -test-utils = { version = "4.0.0-dev", path = "..", package = "substrate-test-utils" } sc-service = { version = "0.10.0-dev", path = "../../client/service" } +test-utils = { package = "substrate-test-utils", version = "4.0.0-dev", path = ".." } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 208099162c52b..871f4e925648b 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -13,50 +13,49 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +chrono = "0.4" +clap = { version = "3.1.6", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0" } +handlebars = "4.2.2" +hash-db = "0.15.2" +hex = "0.4.3" +Inflector = "0.11.4" +itertools = "0.10.3" +kvdb = "0.11.0" +lazy_static = "1.4.0" +linked-hash-map = "0.5.4" +log = "0.4.16" +memory-db = "0.29.0" +prettytable-rs = "0.8.0" +rand = { version = "0.8.4", features = ["small_rng"] } +rand_pcg = "0.3.1" +serde = "1.0.136" +serde_json = "1.0.79" +serde_nanos = "0.1.2" +tempfile = "3.2.0" +thiserror = "1.0.30" +thousands = "0.2.0" frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } -sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } -sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } +sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } +sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sc-sysinfo = { version = "6.0.0-dev", path = "../../../client/sysinfo" } - sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } -sp-database = { version = "4.0.0-dev", path = "../../../primitives/database" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-database = { version = "4.0.0-dev", path = "../../../primitives/database" } +sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } -sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } +sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } -codec = { version = "3.0.0", package = "parity-scale-codec" } -clap = { version = "3.1.6", features = ["derive"] } -chrono = "0.4" -serde = "1.0.136" -serde_json = "1.0.79" -handlebars = "4.2.2" -Inflector = "0.11.4" -linked-hash-map = "0.5.4" -log = "0.4.16" -itertools = "0.10.3" -serde_nanos = "0.1.2" -kvdb = "0.11.0" -hash-db = "0.15.2" -hex = "0.4.3" -memory-db = "0.29.0" -rand = { version = "0.8.4", features = ["small_rng"] } -thousands = "0.2.0" -prettytable-rs = "0.8.0" -tempfile = "3.2.0" -rand_pcg = "0.3.1" -lazy_static = "1.4.0" -thiserror = "1.0.30" [features] default = ["db", "sc-client-db/runtime-benchmarks"] diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index 43c8b31898959..cd9fc4a8cf1e3 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -12,14 +12,11 @@ readme = "README.md" [dependencies] clap = { version = "3.1.6", features = ["derive"] } - -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } +frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } -frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } - -[dev-dependencies] [features] default = [] diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 7ca5b2f255e28..49c004c3c074d 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -13,24 +13,22 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.10.1", features = ["ws-client", "macros"] } - +codec = { package = "parity-scale-codec", version = "3.0.0" } env_logger = "0.9" -frame-support = { path = "../../../frame/support", optional = true, version = "4.0.0-dev" } +jsonrpsee = { version = "0.10.1", features = ["ws-client", "macros"] } log = "0.4.16" -codec = { package = "parity-scale-codec", version = "3.0.0" } -serde_json = "1.0" serde = "1.0.136" - -sp-io = { version = "6.0.0", path = "../../../primitives/io" } +serde_json = "1.0" +frame-support = { version = "4.0.0-dev", optional = true, path = "../../../frame/support" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-version = { version = "5.0.0", path = "../../../primitives/version" } [dev-dependencies] tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } -pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", version = "5.0.0-dev" } -frame-support = { path = "../../../frame/support", version = "4.0.0-dev" } +frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } +pallet-elections-phragmen = { version = "5.0.0-dev", path = "../../../frame/elections-phragmen" } [features] remote-test = ["frame-support"] diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index fe304370727f0..f9967758928e8 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -2,8 +2,8 @@ name = "substrate-frame-rpc-support" version = "3.0.0" authors = [ - "Parity Technologies ", - "Andrew Dirksen ", + "Parity Technologies ", + "Andrew Dirksen ", ] edition = "2021" license = "Apache-2.0" @@ -15,15 +15,15 @@ description = "Substrate RPC for FRAME's support" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" jsonrpc-client-transports = { version = "18.0.0", features = ["http"] } -codec = { package = "parity-scale-codec", version = "3.0.0" } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } -sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } +sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } [dev-dependencies] -frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } scale-info = "2.0.1" tokio = "1.17.0" +frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 9f3f2c6f266c5..5252d96af3f75 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -13,23 +13,23 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" jsonrpc-derive = "18.0.0" log = "0.4.16" -sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } -sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } -sp-core = { version = "6.0.0", path = "../../../../primitives/core" } -sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } +sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } +sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../../client/transaction-pool/api" } +sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../../primitives/block-builder" } -sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } +sp-core = { version = "6.0.0", path = "../../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] -substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } -sp-tracing = { version = "5.0.0", path = "../../../../primitives/tracing" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../../client/transaction-pool" } +sp-tracing = { version = "5.0.0", path = "../../../../primitives/tracing" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 70c890a220a3a..2c0a2787b1dac 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -14,22 +14,20 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "3.1.6", features = ["derive"] } +jsonrpsee = { version = "0.10.1", default-features = false, features = ["ws-client"] } log = "0.4.16" parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = { version = "0.10.0", default-features = false } - -sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../../client/service" } +remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } +sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } -sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } -sp-state-machine = { version = "0.12.0", path = "../../../../primitives/state-machine" } -sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../../client/service" } sp-core = { version = "6.0.0", path = "../../../../primitives/core" } +sp-externalities = { version = "0.12.0", path = "../../../../primitives/externalities" } sp-io = { version = "6.0.0", path = "../../../../primitives/io" } sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } -sp-externalities = { version = "0.12.0", path = "../../../../primitives/externalities" } +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +sp-state-machine = { version = "0.12.0", path = "../../../../primitives/state-machine" } sp-version = { version = "5.0.0", path = "../../../../primitives/version" } - -remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } -jsonrpsee = { version = "0.10.1", default-features = false, features = ["ws-client"] } diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index a9c3fd03e1688..9864cfd0823ce 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -13,12 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +futures-util = { version = "0.3.19", default-features = false, features = ["io"] } +hyper = { version = "0.14.16", default-features = false, features = ["http1", "server", "tcp"] } log = "0.4.16" prometheus = { version = "0.13.0", default-features = false } -futures-util = { version = "0.3.19", default-features = false, features = ["io"] } thiserror = "1.0" tokio = { version = "1.17.0", features = ["parking_lot"] } -hyper = { version = "0.14.16", default-features = false, features = ["http1", "server", "tcp"] } [dev-dependencies] hyper = { version = "0.14.16", features = ["client"] } diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index 66c04432c5dec..0cd1249628f22 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -13,12 +13,12 @@ homepage = "https://substrate.io" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +ansi_term = "0.12.1" build-helper = "0.1.1" cargo_metadata = "0.14.2" +strum = { version = "0.23.0", features = ["derive"] } tempfile = "3.1.0" toml = "0.5.4" walkdir = "2.3.2" wasm-gc-api = "0.1.11" -ansi_term = "0.12.1" sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } -strum = { version = "0.23.0", features = ["derive"] } From 65318e2737a309fd342e602dc819056191ed7244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Wed, 4 May 2022 11:45:23 -0300 Subject: [PATCH 0763/1472] customize check-dependent-* for release engineering (#11311) --- .gitlab-ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bd75cb0bac63c..c97cb03d9c8ad 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -486,6 +486,7 @@ cargo-check-macos: --dependent-repo "$DEPENDENT_REPO" --github-api-token "$GITHUB_PR_TOKEN" --extra-dependencies "$EXTRA_DEPENDENCIES" + --companion-overrides "$COMPANION_OVERRIDES" # Individual jobs are set up for each dependent project so that they can be ran in parallel. # Arguably we could generate a job for each companion in the PR's description using Gitlab's @@ -495,12 +496,18 @@ check-dependent-polkadot: <<: *check-dependent-project variables: DEPENDENT_REPO: polkadot + COMPANION_OVERRIDES: | + substrate: polkadot-v* + polkadot: release-v* check-dependent-cumulus: <<: *check-dependent-project variables: DEPENDENT_REPO: cumulus EXTRA_DEPENDENCIES: polkadot + COMPANION_OVERRIDES: | + substrate: polkadot-v* + cumulus: polkadot-v* build-linux-substrate: From 8300ce9cecc84df8dd1d76839c04368fff42f0d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Wed, 4 May 2022 17:14:58 +0100 Subject: [PATCH 0764/1472] babe: only process vrf on module finalization (#11113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * babe: only process vrf on block execution finalization * babe: rename CurrentBlockRandomness to PreviousBlockRandomness * babe: add test for initialization ordering * babe: rename PreviousBlockRandomness to ParentBlockRandomness * babe: re-add CurrentBlockRandomness with deprecation notice * babe: export CurrentBlockRandomness * babe: silence deprecation warning when exporting CurrentBlockRandomness * babe: suggestion from code review Co-authored-by: Bastian Köcher * babe: flatten nested option * babe: rustfmt Co-authored-by: Bastian Köcher --- Cargo.lock | 1 + frame/babe/src/lib.rs | 183 +++++++++++---------- frame/babe/src/randomness.rs | 50 ++++-- frame/babe/src/tests.rs | 54 ++++-- primitives/consensus/babe/src/digests.rs | 23 ++- primitives/consensus/vrf/Cargo.toml | 2 + primitives/consensus/vrf/src/schnorrkel.rs | 31 +++- 7 files changed, 220 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00d45f10288a5..e8e64d03de4c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10232,6 +10232,7 @@ name = "sp-consensus-vrf" version = "0.10.0-dev" dependencies = [ "parity-scale-codec", + "scale-info", "schnorrkel", "sp-core", "sp-runtime", diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 2709316d87150..e578f0695ac7c 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -61,8 +61,10 @@ mod mock; mod tests; pub use equivocation::{BabeEquivocationOffence, EquivocationHandler, HandleEquivocation}; +#[allow(deprecated)] +pub use randomness::CurrentBlockRandomness; pub use randomness::{ - CurrentBlockRandomness, RandomnessFromOneEpochAgo, RandomnessFromTwoEpochsAgo, + ParentBlockRandomness, RandomnessFromOneEpochAgo, RandomnessFromTwoEpochsAgo, }; pub use pallet::*; @@ -104,8 +106,6 @@ impl EpochChangeTrigger for SameAuthoritiesForever { const UNDER_CONSTRUCTION_SEGMENT_LENGTH: u32 = 256; -type MaybeRandomness = Option; - #[frame_support::pallet] pub mod pallet { use super::*; @@ -271,15 +271,16 @@ pub mod pallet { /// if per-block initialization has already been called for current block. #[pallet::storage] #[pallet::getter(fn initialized)] - pub(super) type Initialized = StorageValue<_, MaybeRandomness>; + pub(super) type Initialized = StorageValue<_, Option>; /// This field should always be populated during block processing unless /// secondary plain slots are enabled (which don't contain a VRF output). /// - /// It is set in `on_initialize`, before it will contain the value from the last block. + /// It is set in `on_finalize`, before it will contain the value from the last block. #[pallet::storage] #[pallet::getter(fn author_vrf_randomness)] - pub(super) type AuthorVrfRandomness = StorageValue<_, MaybeRandomness, ValueQuery>; + pub(super) type AuthorVrfRandomness = + StorageValue<_, Option, ValueQuery>; /// The block numbers when the last and current epoch have started, respectively `N-1` and /// `N`. @@ -320,7 +321,7 @@ pub mod pallet { impl GenesisBuild for GenesisConfig { fn build(&self) { SegmentIndex::::put(0); - Pallet::::initialize_authorities(&self.authorities); + Pallet::::initialize_genesis_authorities(&self.authorities); EpochConfig::::put( self.epoch_config.clone().expect("epoch_config must not be None"), ); @@ -331,19 +332,60 @@ pub mod pallet { impl Hooks> for Pallet { /// Initialization fn on_initialize(now: BlockNumberFor) -> Weight { - Self::do_initialize(now); + Self::initialize(now); 0 } /// Block finalization - fn on_finalize(_n: BlockNumberFor) { + fn on_finalize(_now: BlockNumberFor) { // at the end of the block, we can safely include the new VRF output // from this block into the under-construction randomness. If we've determined // that this block was the first in a new epoch, the changeover logic has // already occurred at this point, so the under-construction randomness // will only contain outputs from the right epoch. - if let Some(Some(randomness)) = Initialized::::take() { - Self::deposit_randomness(&randomness); + if let Some(pre_digest) = Initialized::::take().flatten() { + let authority_index = pre_digest.authority_index(); + + if T::DisabledValidators::is_disabled(authority_index) { + panic!( + "Validator with index {:?} is disabled and should not be attempting to author blocks.", + authority_index, + ); + } + + if let Some((vrf_output, vrf_proof)) = pre_digest.vrf() { + let randomness: Option = Authorities::::get() + .get(authority_index as usize) + .and_then(|(authority, _)| { + schnorrkel::PublicKey::from_bytes(authority.as_slice()).ok() + }) + .and_then(|pubkey| { + let current_slot = CurrentSlot::::get(); + + let transcript = sp_consensus_babe::make_transcript( + &Self::randomness(), + current_slot, + EpochIndex::::get(), + ); + + // NOTE: this is verified by the client when importing the block, before + // execution. we don't run the verification again here to avoid slowing + // down the runtime. + debug_assert!(pubkey + .vrf_verify(transcript.clone(), vrf_output, vrf_proof) + .is_ok()); + + vrf_output.0.attach_input_hash(&pubkey, transcript).ok() + }) + .map(|inout| inout.make_bytes(sp_consensus_babe::BABE_VRF_INOUT_CONTEXT)); + + if let Some(randomness) = pre_digest.is_primary().then(|| randomness).flatten() + { + Self::deposit_randomness(&randomness); + } + + AuthorVrfRandomness::::put(randomness); + } } // remove temporary "environment" entry from storage @@ -451,11 +493,10 @@ impl IsMember for Pallet { impl pallet_session::ShouldEndSession for Pallet { fn should_end_session(now: T::BlockNumber) -> bool { // it might be (and it is in current implementation) that session module is calling - // should_end_session() from it's own on_initialize() handler - // => because pallet_session on_initialize() is called earlier than ours, let's ensure - // that we have synced with digest before checking if session should be ended. - Self::do_initialize(now); - + // `should_end_session` from it's own `on_initialize` handler, in which case it's + // possible that babe's own `on_initialize` has not run yet, so let's ensure that we + // have initialized the pallet and updated the current slot. + Self::initialize(now); Self::should_epoch_change(now) } } @@ -573,7 +614,7 @@ impl Pallet { } /// Finds the start slot of the current epoch. only guaranteed to - /// give correct results after `do_initialize` of the first block + /// give correct results after `initialize` of the first block /// in the chain (as its result is based off of `GenesisSlot`). pub fn current_epoch_start() -> Slot { Self::epoch_start(EpochIndex::::get()) @@ -649,15 +690,41 @@ impl Pallet { } } - fn do_initialize(now: T::BlockNumber) { - // since do_initialize can be called twice (if session module is present) - // => let's ensure that we only modify the storage once per block + fn initialize_genesis_authorities(authorities: &[(AuthorityId, BabeAuthorityWeight)]) { + if !authorities.is_empty() { + assert!(Authorities::::get().is_empty(), "Authorities are already initialized!"); + let bounded_authorities = + WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.to_vec()) + .expect("Initial number of authorities should be lower than T::MaxAuthorities"); + Authorities::::put(&bounded_authorities); + NextAuthorities::::put(&bounded_authorities); + } + } + + fn initialize_genesis_epoch(genesis_slot: Slot) { + GenesisSlot::::put(genesis_slot); + debug_assert_ne!(*GenesisSlot::::get(), 0); + + // deposit a log because this is the first block in epoch #0 + // we use the same values as genesis because we haven't collected any + // randomness yet. + let next = NextEpochDescriptor { + authorities: Self::authorities().to_vec(), + randomness: Self::randomness(), + }; + + Self::deposit_consensus(ConsensusLog::NextEpochData(next)); + } + + fn initialize(now: T::BlockNumber) { + // since `initialize` can be called twice (e.g. if session module is present) + // let's ensure that we only do the initialization once per block let initialized = Self::initialized().is_some(); if initialized { return } - let maybe_pre_digest: Option = + let pre_digest = >::digest() .logs .iter() @@ -671,76 +738,29 @@ impl Pallet { }) .next(); - let is_primary = matches!(maybe_pre_digest, Some(PreDigest::Primary(..))); + if let Some(ref pre_digest) = pre_digest { + // the slot number of the current block being initialized + let current_slot = pre_digest.slot(); - let maybe_randomness: MaybeRandomness = maybe_pre_digest.and_then(|digest| { // on the first non-zero block (i.e. block #1) // this is where the first epoch (epoch #0) actually starts. // we need to adjust internal storage accordingly. if *GenesisSlot::::get() == 0 { - GenesisSlot::::put(digest.slot()); - debug_assert_ne!(*GenesisSlot::::get(), 0); - - // deposit a log because this is the first block in epoch #0 - // we use the same values as genesis because we haven't collected any - // randomness yet. - let next = NextEpochDescriptor { - authorities: Self::authorities().to_vec(), - randomness: Self::randomness(), - }; - - Self::deposit_consensus(ConsensusLog::NextEpochData(next)) + Self::initialize_genesis_epoch(current_slot) } - // the slot number of the current block being initialized - let current_slot = digest.slot(); - // how many slots were skipped between current and last block let lateness = current_slot.saturating_sub(CurrentSlot::::get() + 1); let lateness = T::BlockNumber::from(*lateness as u32); Lateness::::put(lateness); CurrentSlot::::put(current_slot); + } - let authority_index = digest.authority_index(); - - if T::DisabledValidators::is_disabled(authority_index) { - panic!( - "Validator with index {:?} is disabled and should not be attempting to author blocks.", - authority_index, - ); - } - - // Extract out the VRF output if we have it - digest.vrf_output().and_then(|vrf_output| { - // Reconstruct the bytes of VRFInOut using the authority id. - Authorities::::get() - .get(authority_index as usize) - .and_then(|author| schnorrkel::PublicKey::from_bytes(author.0.as_slice()).ok()) - .and_then(|pubkey| { - let transcript = sp_consensus_babe::make_transcript( - &Self::randomness(), - current_slot, - EpochIndex::::get(), - ); - - vrf_output.0.attach_input_hash(&pubkey, transcript).ok() - }) - .map(|inout| inout.make_bytes(sp_consensus_babe::BABE_VRF_INOUT_CONTEXT)) - }) - }); - - // For primary VRF output we place it in the `Initialized` storage - // item and it'll be put onto the under-construction randomness later, - // once we've decided which epoch this block is in. - Initialized::::put(if is_primary { maybe_randomness } else { None }); - - // Place either the primary or secondary VRF output into the - // `AuthorVrfRandomness` storage item. - AuthorVrfRandomness::::put(maybe_randomness); + Initialized::::put(pre_digest); // enact epoch change, if necessary. - T::EpochChangeTrigger::trigger::(now) + T::EpochChangeTrigger::trigger::(now); } /// Call this function exactly once when an epoch changes, to update the @@ -762,17 +782,6 @@ impl Pallet { this_randomness } - fn initialize_authorities(authorities: &[(AuthorityId, BabeAuthorityWeight)]) { - if !authorities.is_empty() { - assert!(Authorities::::get().is_empty(), "Authorities are already initialized!"); - let bounded_authorities = - WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.to_vec()) - .expect("Initial number of authorities should be lower than T::MaxAuthorities"); - Authorities::::put(&bounded_authorities); - NextAuthorities::::put(&bounded_authorities); - } - } - fn do_report_equivocation( reporter: Option, equivocation_proof: EquivocationProof, @@ -891,7 +900,7 @@ impl OneSessionHandler for Pallet { I: Iterator, { let authorities = validators.map(|(_, k)| (k, 1)).collect::>(); - Self::initialize_authorities(&authorities); + Self::initialize_genesis_authorities(&authorities); } fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I) diff --git a/frame/babe/src/randomness.rs b/frame/babe/src/randomness.rs index 7be27f568e9fb..28b2ea7cd665e 100644 --- a/frame/babe/src/randomness.rs +++ b/frame/babe/src/randomness.rs @@ -22,7 +22,7 @@ use super::{ AuthorVrfRandomness, Config, EpochStart, NextRandomness, Randomness, VRF_OUTPUT_LENGTH, }; use frame_support::traits::Randomness as RandomnessT; -use sp_runtime::traits::Hash; +use sp_runtime::traits::{Hash, One, Saturating}; /// Randomness usable by consensus protocols that **depend** upon finality and take action /// based upon on-chain commitments made during the epoch before the previous epoch. @@ -38,7 +38,7 @@ use sp_runtime::traits::Hash; /// /// All input commitments used with `RandomnessFromTwoEpochsAgo` should come from at least /// three epochs ago. We require BABE session keys be registered at least three epochs -/// before being used to derive `CurrentBlockRandomness` for example. +/// before being used to derive `ParentBlockRandomness` for example. /// /// All users learn `RandomnessFromTwoEpochsAgo` when epoch `current_epoch - 1` starts, /// although some learn it a few block earlier inside epoch `current_epoch - 2`. @@ -76,7 +76,7 @@ pub struct RandomnessFromTwoEpochsAgo(sp_std::marker::PhantomData); /// end of every epoch, but they possess some influence over when they possess more slots. /// /// As an example usage, we determine parachain auctions ending times in Polkadot using -/// `RandomnessFromOneEpochAgo` because it reduces bias from `CurrentBlockRandomness` and +/// `RandomnessFromOneEpochAgo` because it reduces bias from `ParentBlockRandomness` and /// does not require the extra finality delay of `RandomnessFromTwoEpochsAgo`. pub struct RandomnessFromOneEpochAgo(sp_std::marker::PhantomData); @@ -89,28 +89,44 @@ pub struct RandomnessFromOneEpochAgo(sp_std::marker::PhantomData); /// wins whatever game they play. /// /// As with `RandomnessFromTwoEpochsAgo`, all input commitments combined with -/// `CurrentBlockRandomness` should come from at least two epoch ago, except preferably +/// `ParentBlockRandomness` should come from at least two epoch ago, except preferably /// not near epoch ending, and thus ideally three epochs ago. /// -/// Almost all users learn this randomness for a block when the block producer announces -/// the block, which makes this randomness appear quite fresh. Yet, the block producer +/// Almost all users learn this randomness for a given block by the time they receive it's +/// parent block, which makes this randomness appear fresh enough. Yet, the block producer /// themselves learned this randomness at the beginning of epoch `current_epoch - 2`, at /// the same time as they learn `RandomnessFromTwoEpochsAgo`. /// /// Aside from just biasing `RandomnessFromTwoEpochsAgo`, adversaries could also bias -/// `CurrentBlockRandomness` by never announcing their block if doing so yields an -/// unfavorable randomness. As such, `CurrentBlockRandomness` should be considered weaker -/// than both other randomness sources provided by BABE, but `CurrentBlockRandomness` +/// `ParentBlockRandomness` by never announcing their block if doing so yields an +/// unfavorable randomness. As such, `ParentBlockRandomness` should be considered weaker +/// than both other randomness sources provided by BABE, but `ParentBlockRandomness` /// remains constrained by declared staking, while a randomness source like block hash is /// only constrained by adversaries' unknowable computational power. /// /// As an example use, parachains could assign block production slots based upon the -/// `CurrentBlockRandomness` of their relay parent or relay parent's parent, provided the +/// `ParentBlockRandomness` of their relay parent or relay parent's parent, provided the /// parachain registers collators but avoids censorship sensitive functionality like /// slashing. Any parachain with slashing could operate BABE itself or perhaps better yet -/// a BABE-like approach that derives its `CurrentBlockRandomness`, and authorizes block -/// production, based upon the relay parent's `CurrentBlockRandomness` or more likely the +/// a BABE-like approach that derives its `ParentBlockRandomness`, and authorizes block +/// production, based upon the relay parent's `ParentBlockRandomness` or more likely the /// relay parent's `RandomnessFromTwoEpochsAgo`. +/// +/// NOTE: there is some nuance here regarding what is current and parent randomness. If +/// you are using this trait from within the runtime (i.e. as part of block execution) +/// then the randomness provided here will always be generated from the parent block. If +/// instead you are using this randomness externally, i.e. after block execution, then +/// this randomness will be provided by the "current" block (this stems from the fact that +/// we process VRF outputs on block execution finalization, i.e. `on_finalize`). +pub struct ParentBlockRandomness(sp_std::marker::PhantomData); + +/// Randomness produced semi-freshly with each block, but inherits limitations of +/// `RandomnessFromTwoEpochsAgo` from which it derives. +/// +/// See [`ParentBlockRandomness`]. +#[deprecated(note = "Should not be relied upon for correctness, \ + will not provide fresh randomness for the current block. \ + Please use `ParentBlockRandomness` instead.")] pub struct CurrentBlockRandomness(sp_std::marker::PhantomData); impl RandomnessT for RandomnessFromTwoEpochsAgo { @@ -133,7 +149,7 @@ impl RandomnessT for RandomnessFromOneEpochA } } -impl RandomnessT, T::BlockNumber> for CurrentBlockRandomness { +impl RandomnessT, T::BlockNumber> for ParentBlockRandomness { fn random(subject: &[u8]) -> (Option, T::BlockNumber) { let random = AuthorVrfRandomness::::get().map(|random| { let mut subject = subject.to_vec(); @@ -143,6 +159,14 @@ impl RandomnessT, T::BlockNumber> for CurrentBlockRan T::Hashing::hash(&subject[..]) }); + (random, >::block_number().saturating_sub(One::one())) + } +} + +#[allow(deprecated)] +impl RandomnessT, T::BlockNumber> for CurrentBlockRandomness { + fn random(subject: &[u8]) -> (Option, T::BlockNumber) { + let (random, _) = ParentBlockRandomness::::random(subject); (random, >::block_number()) } } diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 65c9de85586e4..0859bb7a40849 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -26,6 +26,7 @@ use frame_support::{ use mock::*; use pallet_session::ShouldEndSession; use sp_consensus_babe::{AllowedSlots, BabeEpochConfiguration, Slot}; +use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; use sp_core::crypto::Pair; const EMPTY_RANDOMNESS: [u8; 32] = [ @@ -76,11 +77,11 @@ fn first_block_epoch_zero_start() { assert_eq!(Babe::genesis_slot(), genesis_slot); assert_eq!(Babe::current_slot(), genesis_slot); assert_eq!(Babe::epoch_index(), 0); - assert_eq!(Babe::author_vrf_randomness(), Some(vrf_randomness)); Babe::on_finalize(1); let header = System::finalize(); + assert_eq!(Babe::author_vrf_randomness(), Some(vrf_randomness)); assert_eq!(SegmentIndex::::get(), 0); assert_eq!(UnderConstruction::::get(0), vec![vrf_randomness]); assert_eq!(Babe::randomness(), [0; 32]); @@ -105,48 +106,71 @@ fn first_block_epoch_zero_start() { } #[test] -fn author_vrf_output_for_primary() { +fn current_slot_is_processed_on_initialization() { let (pairs, mut ext) = new_test_ext_with_pairs(1); ext.execute_with(|| { let genesis_slot = Slot::from(10); let (vrf_output, vrf_proof, vrf_randomness) = make_vrf_output(genesis_slot, &pairs[0]); - let primary_pre_digest = make_primary_pre_digest(0, genesis_slot, vrf_output, vrf_proof); + let pre_digest = make_primary_pre_digest(0, genesis_slot, vrf_output, vrf_proof); System::reset_events(); - System::initialize(&1, &Default::default(), &primary_pre_digest); + System::initialize(&1, &Default::default(), &pre_digest); + assert_eq!(Babe::current_slot(), Slot::from(0)); + assert!(Babe::initialized().is_none()); - Babe::do_initialize(1); - assert_eq!(Babe::author_vrf_randomness(), Some(vrf_randomness)); + // current slot is updated on initialization + Babe::initialize(1); + assert_eq!(Babe::current_slot(), genesis_slot); + assert!(Babe::initialized().is_some()); + // but author vrf randomness isn't + assert_eq!(Babe::author_vrf_randomness(), None); + // instead it is updated on block finalization Babe::on_finalize(1); - System::finalize(); assert_eq!(Babe::author_vrf_randomness(), Some(vrf_randomness)); }) } -#[test] -fn author_vrf_output_for_secondary_vrf() { +fn test_author_vrf_output(make_pre_digest: F) +where + F: Fn(sp_consensus_babe::AuthorityIndex, Slot, VRFOutput, VRFProof) -> sp_runtime::Digest, +{ let (pairs, mut ext) = new_test_ext_with_pairs(1); ext.execute_with(|| { let genesis_slot = Slot::from(10); let (vrf_output, vrf_proof, vrf_randomness) = make_vrf_output(genesis_slot, &pairs[0]); - let secondary_vrf_pre_digest = - make_secondary_vrf_pre_digest(0, genesis_slot, vrf_output, vrf_proof); + let pre_digest = make_pre_digest(0, genesis_slot, vrf_output, vrf_proof); System::reset_events(); - System::initialize(&1, &Default::default(), &secondary_vrf_pre_digest); + System::initialize(&1, &Default::default(), &pre_digest); - Babe::do_initialize(1); - assert_eq!(Babe::author_vrf_randomness(), Some(vrf_randomness)); + // author vrf randomness is not updated on initialization + Babe::initialize(1); + assert_eq!(Babe::author_vrf_randomness(), None); + // instead it is updated on block finalization to account for any + // epoch changes that might happen during the block Babe::on_finalize(1); + assert_eq!(Babe::author_vrf_randomness(), Some(vrf_randomness)); + + // and it is kept after finalizing the block System::finalize(); assert_eq!(Babe::author_vrf_randomness(), Some(vrf_randomness)); }) } +#[test] +fn author_vrf_output_for_primary() { + test_author_vrf_output(make_primary_pre_digest); +} + +#[test] +fn author_vrf_output_for_secondary_vrf() { + test_author_vrf_output(make_secondary_vrf_pre_digest); +} + #[test] fn no_author_vrf_output_for_secondary_plain() { new_test_ext(1).execute_with(|| { @@ -157,7 +181,7 @@ fn no_author_vrf_output_for_secondary_plain() { System::initialize(&1, &Default::default(), &secondary_plain_pre_digest); assert_eq!(Babe::author_vrf_randomness(), None); - Babe::do_initialize(1); + Babe::initialize(1); assert_eq!(Babe::author_vrf_randomness(), None); Babe::on_finalize(1); diff --git a/primitives/consensus/babe/src/digests.rs b/primitives/consensus/babe/src/digests.rs index 0f21c913ac57e..1e4c820379d7a 100644 --- a/primitives/consensus/babe/src/digests.rs +++ b/primitives/consensus/babe/src/digests.rs @@ -22,13 +22,14 @@ use super::{ BabeEpochConfiguration, Slot, BABE_ENGINE_ID, }; use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; use sp_runtime::{DigestItem, RuntimeDebug}; use sp_std::vec::Vec; use sp_consensus_vrf::schnorrkel::{Randomness, VRFOutput, VRFProof}; /// Raw BABE primary slot assignment pre-digest. -#[derive(Clone, RuntimeDebug, Encode, Decode)] +#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] pub struct PrimaryPreDigest { /// Authority index pub authority_index: super::AuthorityIndex, @@ -41,7 +42,7 @@ pub struct PrimaryPreDigest { } /// BABE secondary slot assignment pre-digest. -#[derive(Clone, RuntimeDebug, Encode, Decode)] +#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] pub struct SecondaryPlainPreDigest { /// Authority index /// @@ -55,7 +56,7 @@ pub struct SecondaryPlainPreDigest { } /// BABE secondary deterministic slot assignment with VRF outputs. -#[derive(Clone, RuntimeDebug, Encode, Decode)] +#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] pub struct SecondaryVRFPreDigest { /// Authority index pub authority_index: super::AuthorityIndex, @@ -70,7 +71,7 @@ pub struct SecondaryVRFPreDigest { /// A BABE pre-runtime digest. This contains all data required to validate a /// block and for the BABE runtime module. Slots can be assigned to a primary /// (VRF based) and to a secondary (slot number based). -#[derive(Clone, RuntimeDebug, Encode, Decode)] +#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] pub enum PreDigest { /// A primary VRF-based slot assignment. #[codec(index = 1)] @@ -102,6 +103,11 @@ impl PreDigest { } } + /// Returns true if this pre-digest is for a primary slot assignment. + pub fn is_primary(&self) -> bool { + matches!(self, PreDigest::Primary(..)) + } + /// Returns the weight _added_ by this digest, not the cumulative weight /// of the chain. pub fn added_weight(&self) -> crate::BabeBlockWeight { @@ -111,11 +117,12 @@ impl PreDigest { } } - /// Returns the VRF output, if it exists. - pub fn vrf_output(&self) -> Option<&VRFOutput> { + /// Returns the VRF output and proof, if they exist. + pub fn vrf(&self) -> Option<(&VRFOutput, &VRFProof)> { match self { - PreDigest::Primary(primary) => Some(&primary.vrf_output), - PreDigest::SecondaryVRF(secondary) => Some(&secondary.vrf_output), + PreDigest::Primary(primary) => Some((&primary.vrf_output, &primary.vrf_proof)), + PreDigest::SecondaryVRF(secondary) => + Some((&secondary.vrf_output, &secondary.vrf_proof)), PreDigest::SecondaryPlain(_) => None, } } diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 9c8dca910b7e6..44aabf074d137 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.0.1", default-features = false } schnorrkel = { version = "0.9.1", default-features = false, features = ["preaudit_deprecated", "u64_backend"] } sp-core = { version = "6.0.0", default-features = false, path = "../../core" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } @@ -23,6 +24,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../std" } default = ["std"] std = [ "codec/std", + "scale-info/std", "schnorrkel/std", "sp-core/std", "sp-runtime/std", diff --git a/primitives/consensus/vrf/src/schnorrkel.rs b/primitives/consensus/vrf/src/schnorrkel.rs index 094a398893ff6..8666de6c4bc0c 100644 --- a/primitives/consensus/vrf/src/schnorrkel.rs +++ b/primitives/consensus/vrf/src/schnorrkel.rs @@ -17,7 +17,8 @@ //! Schnorrkel-based VRF. -use codec::{Decode, Encode, EncodeLike}; +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use scale_info::TypeInfo; use schnorrkel::errors::MultiSignatureStage; use sp_core::U512; use sp_std::{ @@ -65,6 +66,20 @@ impl Decode for VRFOutput { } } +impl MaxEncodedLen for VRFOutput { + fn max_encoded_len() -> usize { + <[u8; VRF_OUTPUT_LENGTH]>::max_encoded_len() + } +} + +impl TypeInfo for VRFOutput { + type Identity = [u8; VRF_OUTPUT_LENGTH]; + + fn type_info() -> scale_info::Type { + Self::Identity::type_info() + } +} + impl TryFrom<[u8; VRF_OUTPUT_LENGTH]> for VRFOutput { type Error = SignatureError; @@ -117,6 +132,20 @@ impl Decode for VRFProof { } } +impl MaxEncodedLen for VRFProof { + fn max_encoded_len() -> usize { + <[u8; VRF_PROOF_LENGTH]>::max_encoded_len() + } +} + +impl TypeInfo for VRFProof { + type Identity = [u8; VRF_PROOF_LENGTH]; + + fn type_info() -> scale_info::Type { + Self::Identity::type_info() + } +} + impl TryFrom<[u8; VRF_PROOF_LENGTH]> for VRFProof { type Error = SignatureError; From 79222cb75ae9eb37d6897ae23922055bfb43cfe8 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 5 May 2022 11:50:14 +0200 Subject: [PATCH 0765/1472] [ci] fix cargo-check-nixos for nightly pipeline (#11358) --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c97cb03d9c8ad..224d5d5f0ef3f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -268,8 +268,9 @@ cargo-check-nixos: <<: *docker-env <<: *test-refs before_script: [] + # Don't use CI_IMAGE here because it breaks nightly checks of paritytech/ci-linux image + image: nixos/nix variables: - CI_IMAGE: "nixos/nix" SNAP: "DUMMY" WS_API: "DUMMY" script: From 528c35f87a20e78e08263e1a781f0a746a88d05e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 May 2022 12:38:53 +0200 Subject: [PATCH 0766/1472] Bump git2 from 0.13.25 to 0.14.2 (#11341) Bumps [git2](https://github.com/rust-lang/git2-rs) from 0.13.25 to 0.14.2. - [Release notes](https://github.com/rust-lang/git2-rs/releases) - [Commits](https://github.com/rust-lang/git2-rs/compare/0.13.25...0.14.2) --- updated-dependencies: - dependency-name: git2 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 ++++---- utils/frame/generate-bags/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e8e64d03de4c7..1aaf0523765de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2768,9 +2768,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.25" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29229cc1b24c0e6062f6e742aa3e256492a5323365e5ed3413599f8a5eff7d6" +checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c" dependencies = [ "bitflags", "libc", @@ -3651,9 +3651,9 @@ checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "libgit2-sys" -version = "0.12.26+1.3.0" +version = "0.13.2+1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494" +checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b" dependencies = [ "cc", "libc", diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 7c7fdea056b22..34d62ab0d8b5f 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -21,5 +21,5 @@ sp-io = { version = "6.0.0", path = "../../../primitives/io" } # third party chrono = { version = "0.4.19" } -git2 = { version = "0.13.25", default-features = false } +git2 = { version = "0.14.2", default-features = false } num-format = { version = "0.4.0" } From f996a3ad4c734a4439d884b5b952a87d6e69c70f Mon Sep 17 00:00:00 2001 From: Jun Jiang Date: Thu, 5 May 2022 18:44:13 +0800 Subject: [PATCH 0767/1472] Add force_batch to utility pallet (#11148) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add batch_try to utility pallet * lint * rename utility.batch_try -> utility.force_batch * Remove un-needed index field for utility.ItemFailed event * Remove indexes of utility,BatchCompletedWithErrors * Apply suggestions from code review Co-authored-by: Louis Merlin Co-authored-by: Louis Merlin Co-authored-by: Bastian Köcher --- frame/utility/src/benchmarking.rs | 13 ++++++ frame/utility/src/lib.rs | 74 +++++++++++++++++++++++++++++++ frame/utility/src/tests.rs | 32 +++++++++++++ frame/utility/src/weights.rs | 11 +++++ 4 files changed, 130 insertions(+) diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index 27f346f13f52f..018280f69baeb 100644 --- a/frame/utility/src/benchmarking.rs +++ b/frame/utility/src/benchmarking.rs @@ -73,5 +73,18 @@ benchmarks! { let pallets_origin = Into::::into(pallets_origin); }: _(RawOrigin::Root, Box::new(pallets_origin), call) + force_batch { + let c in 0 .. 1000; + let mut calls: Vec<::Call> = Vec::new(); + for i in 0 .. c { + let call = frame_system::Call::remark { remark: vec![] }.into(); + calls.push(call); + } + let caller = whitelisted_caller(); + }: _(RawOrigin::Signed(caller), calls) + verify { + assert_last_event::(Event::BatchCompleted.into()) + } + impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index ec48087e2ef48..9a8384f836f8b 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -113,8 +113,12 @@ pub mod pallet { BatchInterrupted { index: u32, error: DispatchError }, /// Batch of dispatches completed fully with no error. BatchCompleted, + /// Batch of dispatches completed but has errors. + BatchCompletedWithErrors, /// A single item within a Batch of dispatches has completed with no error. ItemCompleted, + /// A single item within a Batch of dispatches has completed with error. + ItemFailed { error: DispatchError }, /// A call was dispatched. DispatchedAs { result: DispatchResult }, } @@ -385,6 +389,76 @@ pub mod pallet { }); Ok(()) } + + /// Send a batch of dispatch calls. + /// Unlike `batch`, it allows errors and won't interrupt. + /// + /// May be called from any origin. + /// + /// - `calls`: The calls to be dispatched from the same origin. The number of call must not + /// exceed the constant: `batched_calls_limit` (available in constant metadata). + /// + /// If origin is root then call are dispatch without checking origin filter. (This includes + /// bypassing `frame_system::Config::BaseCallFilter`). + /// + /// # + /// - Complexity: O(C) where C is the number of calls to be batched. + /// # + #[pallet::weight({ + let dispatch_infos = calls.iter().map(|call| call.get_dispatch_info()).collect::>(); + let dispatch_weight = dispatch_infos.iter() + .map(|di| di.weight) + .fold(0, |total: Weight, weight: Weight| total.saturating_add(weight)) + .saturating_add(T::WeightInfo::force_batch(calls.len() as u32)); + let dispatch_class = { + let all_operational = dispatch_infos.iter() + .map(|di| di.class) + .all(|class| class == DispatchClass::Operational); + if all_operational { + DispatchClass::Operational + } else { + DispatchClass::Normal + } + }; + (dispatch_weight, dispatch_class) + })] + pub fn force_batch( + origin: OriginFor, + calls: Vec<::Call>, + ) -> DispatchResultWithPostInfo { + let is_root = ensure_root(origin.clone()).is_ok(); + let calls_len = calls.len(); + ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); + + // Track the actual weight of each of the batch calls. + let mut weight: Weight = 0; + // Track failed dispatch occur. + let mut has_error: bool = false; + for call in calls.into_iter() { + let info = call.get_dispatch_info(); + // If origin is root, don't apply any dispatch filters; root can call anything. + let result = if is_root { + call.dispatch_bypass_filter(origin.clone()) + } else { + call.dispatch(origin.clone()) + }; + // Add the weight of this call. + weight = weight.saturating_add(extract_actual_weight(&result, &info)); + if let Err(e) = result { + has_error = true; + Self::deposit_event(Event::ItemFailed { error: e.error }); + } else { + Self::deposit_event(Event::ItemCompleted); + } + } + if has_error { + Self::deposit_event(Event::BatchCompletedWithErrors); + } else { + Self::deposit_event(Event::BatchCompleted); + } + let base_weight = T::WeightInfo::batch(calls_len as u32); + Ok(Some(base_weight + weight).into()) + } } } diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 44b07f70db14c..f53459a707b54 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -606,3 +606,35 @@ fn batch_limit() { assert_noop!(Utility::batch_all(Origin::signed(1), calls), Error::::TooManyCalls); }); } + +#[test] +fn force_batch_works() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(1), 10); + assert_eq!(Balances::free_balance(2), 10); + assert_ok!(Utility::force_batch( + Origin::signed(1), + vec![ + call_transfer(2, 5), + call_foobar(true, 75, None), + call_transfer(2, 10), + call_transfer(2, 5), + ] + ),); + System::assert_last_event(utility::Event::BatchCompletedWithErrors.into()); + System::assert_has_event( + utility::Event::ItemFailed { error: DispatchError::Other("") }.into(), + ); + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::free_balance(2), 20); + + assert_ok!(Utility::force_batch( + Origin::signed(2), + vec![call_transfer(1, 5), call_transfer(1, 5),] + ),); + System::assert_last_event(utility::Event::BatchCompleted.into()); + + assert_ok!(Utility::force_batch(Origin::signed(1), vec![call_transfer(2, 50),]),); + System::assert_last_event(utility::Event::BatchCompletedWithErrors.into()); + }); +} diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index e5f3cb0f58fd4..34dad8d735a2e 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -50,6 +50,7 @@ pub trait WeightInfo { fn as_derivative() -> Weight; fn batch_all(c: u32, ) -> Weight; fn dispatch_as() -> Weight; + fn force_batch(c: u32, ) -> Weight; } /// Weights for pallet_utility using the Substrate node and recommended hardware. @@ -71,6 +72,11 @@ impl WeightInfo for SubstrateWeight { fn dispatch_as() -> Weight { (8_463_000 as Weight) } + fn force_batch(c: u32, ) -> Weight { + (13_988_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_481_000 as Weight).saturating_mul(c as Weight)) + } } // For backwards compatibility and tests @@ -91,4 +97,9 @@ impl WeightInfo for () { fn dispatch_as() -> Weight { (8_463_000 as Weight) } + fn force_batch(c: u32, ) -> Weight { + (13_988_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_481_000 as Weight).saturating_mul(c as Weight)) + } } From 06d43cba9c2498d058a600dfe200c75e36d1181f Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 5 May 2022 12:43:52 +0100 Subject: [PATCH 0768/1472] Backfill missing TOML features (#11351) * only check std * add default-features=false * Revert "add default-features=false" This reverts commit bc9453757a1df670f418a2d57ee4ce203425ab1b. * missing features only to non-optional --- frame/beefy-mmr/Cargo.toml | 1 + frame/benchmarking/Cargo.toml | 3 +++ frame/election-provider-support/Cargo.toml | 2 ++ frame/election-provider-support/benchmarking/Cargo.toml | 1 + frame/executive/Cargo.toml | 1 + frame/grandpa/Cargo.toml | 1 + frame/remark/Cargo.toml | 1 + frame/session/benchmarking/Cargo.toml | 1 + frame/transaction-storage/Cargo.toml | 1 + frame/uniques/Cargo.toml | 1 + frame/utility/Cargo.toml | 1 + frame/vesting/Cargo.toml | 1 + primitives/core/hashing/Cargo.toml | 1 + primitives/keystore/Cargo.toml | 6 +++++- primitives/test-primitives/Cargo.toml | 4 ++++ 15 files changed, 25 insertions(+), 1 deletion(-) diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index bdec17b8589c2..6affcd60ccb34 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -43,6 +43,7 @@ std = [ "pallet-beefy/std", "pallet-mmr/std", "pallet-session/std", + "scale-info/std", "serde", "sp-core/std", "sp-io/std", diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index d1d835e0d1d35..c070e64d37b45 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -44,8 +44,11 @@ std = [ "scale-info/std", "serde", "sp-api/std", + "sp-application-crypto/std", + "sp-io/std", "sp-runtime-interface/std", "sp-runtime/std", "sp-std/std", + "sp-storage/std", ] runtime-benchmarks = [] diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 8bc92f878c8ce..bfddd25a1fa3e 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -35,8 +35,10 @@ std = [ "codec/std", "frame-support/std", "frame-system/std", + "scale-info/std", "sp-arithmetic/std", "sp-npos-elections/std", + "sp-runtime/std", "sp-std/std", ] runtime-benchmarks = [] diff --git a/frame/election-provider-support/benchmarking/Cargo.toml b/frame/election-provider-support/benchmarking/Cargo.toml index 14afff1aeb055..00037d460db17 100644 --- a/frame/election-provider-support/benchmarking/Cargo.toml +++ b/frame/election-provider-support/benchmarking/Cargo.toml @@ -26,6 +26,7 @@ default = ["std"] std = [ "codec/std", "frame-benchmarking/std", + "frame-election-provider-support/std", "frame-system/std", "sp-npos-elections/std", "sp-runtime/std", diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index b60cffa478c7b..ed3c5282fc81d 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -43,6 +43,7 @@ std = [ "frame-system/std", "scale-info/std", "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", "sp-tracing/std", diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index b1c2da09b53ff..ea1ec173d8f44 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -55,6 +55,7 @@ std = [ "sp-application-crypto/std", "sp-core/std", "sp-finality-grandpa/std", + "sp-io/std", "sp-runtime/std", "sp-session/std", "sp-staking/std", diff --git a/frame/remark/Cargo.toml b/frame/remark/Cargo.toml index 9759c37bfe92c..573502779c586 100644 --- a/frame/remark/Cargo.toml +++ b/frame/remark/Cargo.toml @@ -36,6 +36,7 @@ std = [ "frame-system/std", "scale-info/std", "serde", + "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 0449f3f674379..1cce8fec023db 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -41,6 +41,7 @@ std = [ "frame-system/std", "pallet-session/std", "pallet-staking/std", + "rand/std", "sp-runtime/std", "sp-session/std", "sp-std/std", diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 47cf69cf73f8b..99bea1cd36882 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -45,4 +45,5 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "sp-transaction-storage-proof/std", ] diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 3f78df96b3517..1e6ca2ce687dc 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -35,6 +35,7 @@ std = [ "frame-benchmarking/std", "frame-support/std", "frame-system/std", + "log/std", "scale-info/std", "sp-runtime/std", "sp-std/std", diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 0c307020b521b..066682e0e349e 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -34,6 +34,7 @@ std = [ "frame-support/std", "frame-system/std", "scale-info/std", + "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index d8cb200caf062..f73a7af9e6ae4 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -35,6 +35,7 @@ std = [ "codec/std", "frame-support/std", "frame-system/std", + "log/std", "scale-info/std", "sp-runtime/std", "sp-std/std", diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index b3ce080f7a704..c83e48e563010 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -25,6 +25,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../std" } default = ["std"] std = [ "blake2/std", + "byteorder/std", "sha2/std", "sha3/std", "sp-std/std", diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 551626adbc4e8..3c3b7933c50da 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -21,7 +21,7 @@ parking_lot = { version = "0.12.0", default-features = false } schnorrkel = { version = "0.9.1", default-features = false, features = ["preaudit_deprecated", "u64_backend"] } serde = { version = "1.0", optional = true } thiserror = "1.0" -sp-core = { version = "6.0.0", path = "../core" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } [dev-dependencies] @@ -31,6 +31,10 @@ rand_chacha = "0.2.2" [features] default = ["std"] std = [ + "codec/std", + "merlin/std", "schnorrkel/std", "serde", + "sp-core/std", + "sp-externalities/std", ] diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 1333c340a68a7..2a20addf66b2b 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -24,6 +24,10 @@ default = [ "std", ] std = [ + "codec/std", + "parity-util-mem/std", "serde", "sp-application-crypto/std", + "sp-core/std", + "sp-runtime/std", ] From 6f3aafba3ed13dfc0b52dac1f201d4177988e67b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 May 2022 01:21:56 +0200 Subject: [PATCH 0769/1472] Bump k256 from 0.10.2 to 0.10.4 (#11249) Bumps [k256](https://github.com/RustCrypto/elliptic-curves) from 0.10.2 to 0.10.4. - [Release notes](https://github.com/RustCrypto/elliptic-curves/releases) - [Commits](https://github.com/RustCrypto/elliptic-curves/compare/k256/v0.10.2...k256/v0.10.4) --- updated-dependencies: - dependency-name: k256 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 ++-- frame/support/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1aaf0523765de..67a9372b367ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3534,9 +3534,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cc5937366afd3b38071f400d1ce5bd8b1d40b5083cc14e6f8dbcc4032a7f5bb" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" dependencies = [ "cfg-if 1.0.0", "ecdsa", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index f0d663f7a26fa..712570696b9eb 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -35,7 +35,7 @@ impl-trait-for-tuples = "0.2.2" smallvec = "1.8.0" log = { version = "0.4.16", default-features = false } sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } -k256 = { version = "0.10.2", default-features = false, features = ["ecdsa"] } +k256 = { version = "0.10.4", default-features = false, features = ["ecdsa"] } [dev-dependencies] assert_matches = "1.3.0" From dedfef293fdcf5b6a98b0de16f86278f9121c4eb Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Fri, 6 May 2022 10:44:21 +0100 Subject: [PATCH 0770/1472] Add event tests to Nomination Pools (#11349) * fix a few things with nomination pools * fix typo * fix build * eventify tests * Update frame/nomination-pools/src/tests.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fmt * comments * split Co-authored-by: kianenigma Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/nomination-pools/src/tests.rs | 290 ++++++++++++++++++++++++++-- 1 file changed, 272 insertions(+), 18 deletions(-) diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index cd66c3d774960..ecda162c6bdbc 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -407,7 +407,17 @@ mod join { // When assert_ok!(Pools::join(Origin::signed(11), 2, 1)); - // then + // Then + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 11, pool_id: 1, bonded: 2, joined: true }, + ] + ); + assert_eq!( PoolMembers::::get(&11).unwrap(), PoolMember:: { pool_id: 1, points: 2, ..Default::default() } @@ -426,6 +436,11 @@ mod join { assert_ok!(Pools::join(Origin::signed(12), 12, 1)); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::Bonded { member: 12, pool_id: 1, bonded: 12, joined: true }] + ); + assert_eq!( PoolMembers::::get(&12).unwrap(), PoolMember:: { pool_id: 1, points: 24, ..Default::default() } @@ -536,6 +551,16 @@ mod join { Balances::make_free_balance_be(&103, 100 + Balances::minimum_balance()); // Then + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 101, pool_id: 1, bonded: 100, joined: true }, + Event::Bonded { member: 102, pool_id: 1, bonded: 100, joined: true } + ] + ); + assert_noop!( Pools::join(Origin::signed(103), 100, 1), Error::::MaxPoolMembers @@ -554,6 +579,14 @@ mod join { .unwrap(); // Then + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 104, pool_id: 2 }, + Event::Bonded { member: 104, pool_id: 2, bonded: 100, joined: true } + ] + ); + assert_noop!( Pools::join(Origin::signed(103), 100, pool_account), Error::::MaxPoolMembers @@ -595,6 +628,17 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(10))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, + Event::Bonded { member: 50, pool_id: 1, bonded: 50, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 10 }, + ] + ); + // Expect a payout of 10: (10 del virtual points / 100 pool points) * 100 pool // balance assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 100)); @@ -609,6 +653,11 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(40))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 40, pool_id: 1, payout: 40 }] + ); + // Expect payout 40: (400 del virtual points / 900 pool points) * 90 pool balance assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 100)); assert_eq!( @@ -622,6 +671,11 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(50))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] + ); + // Expect payout 50: (50 del virtual points / 50 pool points) * 50 pool balance assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 100)); assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 100)); @@ -635,6 +689,11 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(10))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] + ); + // Expect payout 5: (500 del virtual points / 5,000 pool points) * 50 pool balance assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 150)); assert_eq!(RewardPools::::get(&1).unwrap(), rew(45, 5_000 - 50 * 10, 150)); @@ -645,6 +704,11 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(40))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 40, pool_id: 1, payout: 20 }] + ); + // Expect payout 20: (2,000 del virtual points / 4,500 pool points) * 45 pool // balance assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 150)); @@ -660,6 +724,11 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(50))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] + ); + // We expect a payout of 50: (5,000 del virtual points / 7,5000 pool points) * 75 // pool balance assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 200)); @@ -682,6 +751,11 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(10))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] + ); + // We expect a payout of 5 assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 200)); assert_eq!(RewardPools::::get(&1).unwrap(), rew(20, 2_500 - 10 * 50, 200)); @@ -696,6 +770,11 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(10))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 40 }] + ); + // We expect a payout of 40 assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 600)); assert_eq!( @@ -721,6 +800,11 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(10))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 2 }] + ); + // Expect a payout of 2: (200 del virtual points / 38,000 pool points) * 400 pool // balance assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 620)); @@ -735,6 +819,11 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(40))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 40, pool_id: 1, payout: 188 }] + ); + // Expect a payout of 188: (18,800 del virtual points / 39,800 pool points) * 399 // pool balance assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 620)); @@ -749,6 +838,11 @@ mod claim_payout { assert_ok!(Pools::claim_payout(Origin::signed(50))); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 50, pool_id: 1, payout: 210 }] + ); + // Expect payout of 210: (21,000 / 21,000) * 210 assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 620)); assert_eq!( @@ -830,6 +924,16 @@ mod claim_payout { Pools::do_reward_payout(&11, &mut member, &mut bonded_pool, &mut reward_pool,), Error::::FullyUnbonding ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 11, pool_id: 1, bonded: 11, joined: true }, + Event::Unbonded { member: 11, pool_id: 1, amount: 11 } + ] + ); }); } @@ -910,6 +1014,16 @@ mod claim_payout { // PoolMember with 50 points let mut del_50 = PoolMembers::::get(50).unwrap(); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, + Event::Bonded { member: 50, pool_id: 1, bonded: 50, joined: true } + ] + ); + // Given we have a total of 100 points split among the members assert_eq!(del_50.points + del_40.points + del_10.points, 100); assert_eq!(bonded_pool.points, 100); @@ -1101,6 +1215,16 @@ mod claim_payout { let mut reward_pool = RewardPools::::get(1).unwrap(); let ed = Balances::minimum_balance(); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, + Event::Bonded { member: 50, pool_id: 1, bonded: 50, joined: true } + ] + ); + // Given the bonded pool has 100 points assert_eq!(bonded_pool.points, 100); // Each member currently has a free balance of @@ -1123,6 +1247,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 10 }] + ); + // Expect a payout of 10: (10 del virtual points / 100 pool points) * 100 pool // balance assert_eq!(del_10, del(10, 100)); @@ -1139,6 +1268,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 40, pool_id: 1, payout: 40 }] + ); + // Expect payout 40: (400 del virtual points / 900 pool points) * 90 pool balance assert_eq!(del_40, del(40, 100)); assert_eq!(reward_pool, rew(50, 9_000 - 100 * 40, 100)); @@ -1154,6 +1288,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] + ); + // Expect payout 50: (50 del virtual points / 50 pool points) * 50 pool balance assert_eq!(del_50, del(50, 100)); assert_eq!(reward_pool, rew(0, 0, 100)); @@ -1172,6 +1311,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] + ); + // Expect payout 5: (500 del virtual points / 5,000 pool points) * 50 pool balance assert_eq!(del_10, del(10, 150)); assert_eq!(reward_pool, rew(45, 5_000 - 50 * 10, 150)); @@ -1187,6 +1331,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 40, pool_id: 1, payout: 20 }] + ); + // Expect payout 20: (2,000 del virtual points / 4,500 pool points) * 45 pool // balance assert_eq!(del_40, del(40, 150)); @@ -1207,6 +1356,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] + ); + // We expect a payout of 50: (5,000 del virtual points / 7,5000 pool points) * 75 // pool balance assert_eq!(del_50, del(50, 200)); @@ -1234,6 +1388,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] + ); + // We expect a payout of 5 assert_eq!(del_10, del(10, 200)); assert_eq!(reward_pool, rew(20, 2_500 - 10 * 50, 200)); @@ -1253,6 +1412,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 40 }] + ); + // We expect a payout of 40 assert_eq!(del_10, del(10, 600)); assert_eq!( @@ -1283,6 +1447,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 2 }] + ); + // Expect a payout of 2: (200 del virtual points / 38,000 pool points) * 400 pool // balance assert_eq!(del_10, del(10, 620)); @@ -1299,6 +1468,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 40, pool_id: 1, payout: 188 }] + ); + // Expect a payout of 188: (18,800 del virtual points / 39,800 pool points) * 399 // pool balance assert_eq!(del_40, del(40, 620)); @@ -1315,6 +1489,11 @@ mod claim_payout { )); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 50, pool_id: 1, payout: 210 }] + ); + // Expect payout of 210: (21,000 / 21,000) * 210 assert_eq!(del_50, del(50, 620)); assert_eq!(reward_pool, rew(0, 21_000 - 50 * 420, 620)); @@ -2372,13 +2551,35 @@ mod withdraw_unbonded { // Given assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, + Event::Bonded { member: 200, pool_id: 1, bonded: 200, joined: true }, + Event::Unbonded { member: 100, pool_id: 1, amount: 100 } + ] + ); + let mut current_era = 1; CurrentEra::set(current_era); assert_ok!(Pools::fully_unbond(Origin::signed(200), 200)); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 200, pool_id: 1, amount: 200 }] + ); + unsafe_set_state(1, PoolState::Destroying).unwrap(); assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 10, pool_id: 1, amount: 10 }] + ); + assert_eq!( SubPoolsStorage::::get(1).unwrap(), SubPools { @@ -2402,6 +2603,15 @@ mod withdraw_unbonded { // Given assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 100, 0)); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Withdrawn { member: 100, pool_id: 1, amount: 100 }, + Event::MemberRemoved { pool_id: 1, member: 100 } + ] + ); + assert_eq!( SubPoolsStorage::::get(1).unwrap(), SubPools { @@ -2421,6 +2631,15 @@ mod withdraw_unbonded { // Given assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 200, 0)); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Withdrawn { member: 200, pool_id: 1, amount: 200 }, + Event::MemberRemoved { pool_id: 1, member: 200 } + ] + ); + assert_eq!( SubPoolsStorage::::get(1).unwrap(), SubPools { @@ -2433,32 +2652,22 @@ mod withdraw_unbonded { // The depositor can withdraw assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 10, 0)); - assert!(!PoolMembers::::contains_key(10)); - assert_eq!(Balances::free_balance(10), 10 + 10); - // Pools are removed from storage because the depositor left - assert!(!SubPoolsStorage::::contains_key(1)); - assert!(!RewardPools::::contains_key(1)); - assert!(!BondedPools::::contains_key(1)); assert_eq!( pool_events_since_last_call(), vec![ - Event::Created { depositor: 10, pool_id: 1 }, - Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, - Event::Bonded { member: 200, pool_id: 1, bonded: 200, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, amount: 100 }, - Event::Unbonded { member: 200, pool_id: 1, amount: 200 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 10 }, - Event::Withdrawn { member: 100, pool_id: 1, amount: 100 }, - Event::MemberRemoved { pool_id: 1, member: 100 }, - Event::Withdrawn { member: 200, pool_id: 1, amount: 200 }, - Event::MemberRemoved { pool_id: 1, member: 200 }, Event::Withdrawn { member: 10, pool_id: 1, amount: 10 }, Event::MemberRemoved { pool_id: 1, member: 10 }, Event::Destroyed { pool_id: 1 } ] ); + + assert!(!PoolMembers::::contains_key(10)); + assert_eq!(Balances::free_balance(10), 10 + 10); + // Pools are removed from storage because the depositor left + assert!(!SubPoolsStorage::::contains_key(1)); + assert!(!RewardPools::::contains_key(1)); + assert!(!BondedPools::::contains_key(1)); }); } @@ -2510,6 +2719,22 @@ mod withdraw_unbonded { assert!(!SubPoolsStorage::::contains_key(1)); assert!(!RewardPools::::contains_key(1)); assert!(!BondedPools::::contains_key(1)); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, + Event::Unbonded { member: 100, pool_id: 1, amount: 100 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 10 }, + Event::Withdrawn { member: 100, pool_id: 1, amount: 100 }, + Event::MemberRemoved { pool_id: 1, member: 100 }, + Event::Withdrawn { member: 10, pool_id: 1, amount: 10 }, + Event::MemberRemoved { pool_id: 1, member: 10 }, + Event::Destroyed { pool_id: 1 } + ] + ); }); } @@ -2860,6 +3085,16 @@ mod create { total_earnings: Zero::zero(), } ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Created { depositor: 11, pool_id: 2 }, + Event::Bonded { member: 11, pool_id: 2, bonded: 10, joined: true } + ] + ); }); } @@ -2981,6 +3216,16 @@ mod set_state { // Root can change state assert_ok!(Pools::set_state(Origin::signed(900), 1, PoolState::Blocked)); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::StateChanged { pool_id: 1, new_state: PoolState::Blocked } + ] + ); + assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Blocked); // State toggler can change state @@ -3024,6 +3269,15 @@ mod set_state { Pools::set_state(Origin::signed(11), 1, PoolState::Blocked), Error::::CanNotChangeState ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, + Event::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, + Event::StateChanged { pool_id: 1, new_state: PoolState::Destroying } + ] + ); }); } } From 43d8c8787ded25dab5db55af5ab65f5d5882a51b Mon Sep 17 00:00:00 2001 From: Roman Gafiyatullin Date: Fri, 6 May 2022 13:07:44 +0300 Subject: [PATCH 0771/1472] Remove the `--unsafe-pruning` CLI-argument (step 1) (#10995) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * sc-client-db: utils::open_database(...) — return OpenDbError so that the caller could tell the `OpenDbError::DoesNotExist` clearly * sc-client-db: utils::open_database(..) — accept the `create: bool` argument * sc-client-db: pruning — optional argument in the DatabaseSettings * sc-state-db: Split `Error` into separate `Error` and `StateDbError` * StateDb::open: choose the pruning-mode depending on the requested and stored values * sc-state-db: test for different combinations of stored and requested pruning-modes * CLI-argument: mark the unsafe-pruning as deprecated * Fix tests * tests: do not specify --pruning when running the substrate over the existing storage * fix types for benches * cargo fmt * Check whether the pruning-mode and sync-mode are compatible * cargo fmt * parity-db: 0.3.11 -> 0.3.12 * sc-state-db: MetaDb::set_meta — a better doc-test * cargo fmt * make MetaDb read-only again! * Remove the stray newline (and run the CI once again please) * Last nitpicks * A more comprehensive error message --- Cargo.lock | 6 +- bin/node/cli/benches/block_production.rs | 2 +- bin/node/cli/benches/transaction_pool.rs | 2 +- bin/node/cli/tests/benchmark_block_works.rs | 1 - bin/node/cli/tests/check_block_works.rs | 2 +- bin/node/cli/tests/export_import_flow.rs | 6 +- bin/node/cli/tests/inspect_works.rs | 2 +- bin/node/testing/src/bench.rs | 2 +- client/api/src/backend.rs | 3 + client/api/src/client.rs | 3 + client/api/src/in_mem.rs | 4 + client/cli/src/config.rs | 19 +- client/cli/src/params/import_params.rs | 12 +- client/cli/src/params/pruning_params.rs | 36 +-- client/db/src/lib.rs | 81 ++++-- client/db/src/upgrade.rs | 13 +- client/db/src/utils.rs | 168 ++++++------ client/service/src/builder.rs | 6 +- client/service/src/client/client.rs | 4 + client/service/src/config.rs | 2 +- client/service/test/src/client/mod.rs | 4 +- client/state-db/src/lib.rs | 280 ++++++++++++++++---- client/state-db/src/noncanonical.rs | 226 +++++++--------- 23 files changed, 546 insertions(+), 338 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67a9372b367ea..14d1a547a8073 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11680,7 +11680,7 @@ dependencies = [ "chrono", "lazy_static", "matchers", - "parking_lot 0.11.2", + "parking_lot 0.9.0", "regex", "serde", "serde_json", @@ -11854,9 +11854,9 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "digest 0.10.3", - "rand 0.8.4", + "rand 0.6.5", "static_assertions", ] diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index ebb89c07da221..6eab08c39e5a2 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -74,7 +74,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, state_cache_size: 67108864, state_cache_child_ratio: None, - state_pruning: PruningMode::ArchiveAll, + state_pruning: Some(PruningMode::ArchiveAll), keep_blocks: KeepBlocks::All, chain_spec: spec, wasm_method: WasmExecutionMethod::Compiled, diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index a889399eda83a..eb0e24d2fdd37 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -65,7 +65,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, state_cache_size: 67108864, state_cache_child_ratio: None, - state_pruning: PruningMode::ArchiveAll, + state_pruning: Some(PruningMode::ArchiveAll), keep_blocks: KeepBlocks::All, chain_spec: spec, wasm_method: WasmExecutionMethod::Interpreted, diff --git a/bin/node/cli/tests/benchmark_block_works.rs b/bin/node/cli/tests/benchmark_block_works.rs index 359abf3e4265f..65cb474ea88d6 100644 --- a/bin/node/cli/tests/benchmark_block_works.rs +++ b/bin/node/cli/tests/benchmark_block_works.rs @@ -37,7 +37,6 @@ async fn benchmark_block_works() { .args(["benchmark", "block", "--dev"]) .arg("-d") .arg(base_dir.path()) - .args(["--pruning", "archive"]) .args(["--from", "1", "--to", "1"]) .args(["--repeat", "1"]) .args(["--execution", "wasm", "--wasm-execution", "compiled"]) diff --git a/bin/node/cli/tests/check_block_works.rs b/bin/node/cli/tests/check_block_works.rs index c5447fd2311c6..d4afc530bbcb3 100644 --- a/bin/node/cli/tests/check_block_works.rs +++ b/bin/node/cli/tests/check_block_works.rs @@ -31,7 +31,7 @@ async fn check_block_works() { common::run_node_for_a_while(base_path.path(), &["--dev", "--no-hardware-benchmarks"]).await; let status = Command::new(cargo_bin("substrate")) - .args(&["check-block", "--dev", "--pruning", "archive", "-d"]) + .args(&["check-block", "--dev", "-d"]) .arg(base_path.path()) .arg("1") .status() diff --git a/bin/node/cli/tests/export_import_flow.rs b/bin/node/cli/tests/export_import_flow.rs index 48fccc8ca0293..750b4f7acc121 100644 --- a/bin/node/cli/tests/export_import_flow.rs +++ b/bin/node/cli/tests/export_import_flow.rs @@ -79,9 +79,9 @@ impl<'a> ExportImportRevertExecutor<'a> { // Adding "--binary" if need be. let arguments: Vec<&str> = match format_opt { FormatOpt::Binary => { - vec![&sub_command_str, "--dev", "--pruning", "archive", "--binary", "-d"] + vec![&sub_command_str, "--dev", "--binary", "-d"] }, - FormatOpt::Json => vec![&sub_command_str, "--dev", "--pruning", "archive", "-d"], + FormatOpt::Json => vec![&sub_command_str, "--dev", "-d"], }; let tmp: TempDir; @@ -161,7 +161,7 @@ impl<'a> ExportImportRevertExecutor<'a> { /// Runs the `revert` command. fn run_revert(&self) { let output = Command::new(cargo_bin("substrate")) - .args(&["revert", "--dev", "--pruning", "archive", "-d"]) + .args(&["revert", "--dev", "-d"]) .arg(&self.base_path.path()) .output() .unwrap(); diff --git a/bin/node/cli/tests/inspect_works.rs b/bin/node/cli/tests/inspect_works.rs index 6f73cc69582a9..849fb913a18d0 100644 --- a/bin/node/cli/tests/inspect_works.rs +++ b/bin/node/cli/tests/inspect_works.rs @@ -31,7 +31,7 @@ async fn inspect_works() { common::run_node_for_a_while(base_path.path(), &["--dev", "--no-hardware-benchmarks"]).await; let status = Command::new(cargo_bin("substrate")) - .args(&["inspect", "--dev", "--pruning", "archive", "-d"]) + .args(&["inspect", "--dev", "-d"]) .arg(base_path.path()) .args(&["block", "1"]) .status() diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 7e13c0a0ac5e0..e5287dc3c4af2 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -389,7 +389,7 @@ impl BenchDb { let db_config = sc_client_db::DatabaseSettings { state_cache_size: 16 * 1024 * 1024, state_cache_child_ratio: Some((0, 100)), - state_pruning: PruningMode::ArchiveAll, + state_pruning: Some(PruningMode::ArchiveAll), source: database_type.into_settings(dir.into()), keep_blocks: sc_client_db::KeepBlocks::All, }; diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 394fcd420fda1..af8552886b72e 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -546,6 +546,9 @@ pub trait Backend: AuxStore + Send + Sync { /// something that the import of a block would interfere with, e.g. importing /// a new block or calculating the best head. fn get_import_lock(&self) -> &RwLock<()>; + + /// Tells whether the backend requires full-sync mode. + fn requires_full_sync(&self) -> bool; } /// Mark for all Backend implementations, that are making use of state data, stored locally. diff --git a/client/api/src/client.rs b/client/api/src/client.rs index c4b01fbd0abbd..b809e0ee61032 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -146,6 +146,9 @@ pub trait BlockBackend { fn has_indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result { Ok(self.indexed_transaction(hash)?.is_some()) } + + /// Tells whether the current client configuration requires full-sync mode. + fn requires_full_sync(&self) -> bool; } /// Provide a list of potential uncle headers for a given block. diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 8b8473287a7ca..a8a7442a8ef9f 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -795,6 +795,10 @@ where fn get_import_lock(&self) -> &RwLock<()> { &self.import_lock } + + fn requires_full_sync(&self) -> bool { + false + } } impl backend::LocalBackend for Backend where Block::Hash: Ord {} diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 5c44a05ab68dd..aef1da8193757 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -251,9 +251,9 @@ pub trait CliConfiguration: Sized { /// /// By default this is retrieved from `PruningMode` if it is available. Otherwise its /// `PruningMode::default()`. - fn state_pruning(&self, unsafe_pruning: bool, role: &Role) -> Result { + fn state_pruning(&self) -> Result> { self.pruning_params() - .map(|x| x.state_pruning(unsafe_pruning, role)) + .map(|x| x.state_pruning()) .unwrap_or_else(|| Ok(Default::default())) } @@ -494,8 +494,6 @@ pub trait CliConfiguration: Sized { let telemetry_endpoints = self.telemetry_endpoints(&chain_spec)?; let runtime_cache_size = self.runtime_cache_size()?; - let unsafe_pruning = self.import_params().map(|p| p.unsafe_pruning).unwrap_or(false); - Ok(Configuration { impl_name: C::impl_name(), impl_version: C::impl_version(), @@ -516,7 +514,7 @@ pub trait CliConfiguration: Sized { database: self.database_config(&config_dir, database_cache_size, database, &role)?, state_cache_size: self.state_cache_size()?, state_cache_child_ratio: self.state_cache_child_ratio()?, - state_pruning: self.state_pruning(unsafe_pruning, &role)?, + state_pruning: self.state_pruning()?, keep_blocks: self.keep_blocks()?, wasm_method: self.wasm_method()?, wasm_runtime_overrides: self.wasm_runtime_overrides(), @@ -643,6 +641,17 @@ pub trait CliConfiguration: Sized { } } + if self.import_params().map_or(false, |p| { + #[allow(deprecated)] + p.unsafe_pruning + }) { + // according to https://github.com/substrate/issues/8103; + warn!( + "WARNING: \"--unsafe-pruning\" CLI-flag is deprecated and has no effect. \ + In future builds it will be removed, and providing this flag will lead to an error." + ); + } + Ok(()) } } diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index 1df11cff8d79f..4c9b334150557 100644 --- a/client/cli/src/params/import_params.rs +++ b/client/cli/src/params/import_params.rs @@ -40,12 +40,16 @@ pub struct ImportParams { #[clap(flatten)] pub database_params: DatabaseParams, - /// Force start with unsafe pruning settings. + /// THIS IS A DEPRECATED CLI-ARGUMENT. /// - /// When running as a validator it is highly recommended to disable state - /// pruning (i.e. 'archive') which is the default. The node will refuse to - /// start as a validator if pruning is enabled unless this option is set. + /// It has been preserved in order to not break the compatibility with the existing scripts. + /// Enabling this option will lead to a runtime warning. + /// In future this option will be removed completely, thus specifying it will lead to a start + /// up error. + /// + /// Details: #[clap(long)] + #[deprecated = "According to https://github.com/paritytech/substrate/issues/8103"] pub unsafe_pruning: bool, /// Method for executing Wasm runtime code. diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index de9628ecf7ad9..0f3d1013381e6 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -18,7 +18,7 @@ use crate::error; use clap::Args; -use sc_service::{KeepBlocks, PruningMode, Role}; +use sc_service::{KeepBlocks, PruningMode}; /// Parameters to define the pruning mode #[derive(Debug, Clone, PartialEq, Args)] @@ -39,29 +39,17 @@ pub struct PruningParams { impl PruningParams { /// Get the pruning value from the parameters - pub fn state_pruning(&self, unsafe_pruning: bool, role: &Role) -> error::Result { - // by default we disable pruning if the node is an authority (i.e. - // `ArchiveAll`), otherwise we keep state for the last 256 blocks. if the - // node is an authority and pruning is enabled explicitly, then we error - // unless `unsafe_pruning` is set. - Ok(match &self.pruning { - Some(ref s) if s == "archive" => PruningMode::ArchiveAll, - None if role.is_authority() => PruningMode::ArchiveAll, - None => PruningMode::default(), - Some(s) => { - if role.is_authority() && !unsafe_pruning { - return Err(error::Error::Input( - "Validators should run with state pruning disabled (i.e. archive). \ - You can ignore this check with `--unsafe-pruning`." - .to_string(), - )) - } - - PruningMode::keep_blocks(s.parse().map_err(|_| { - error::Error::Input("Invalid pruning mode specified".to_string()) - })?) - }, - }) + pub fn state_pruning(&self) -> error::Result> { + self.pruning + .as_ref() + .map(|s| match s.as_str() { + "archive" => Ok(PruningMode::ArchiveAll), + bc => bc + .parse() + .map_err(|_| error::Error::Input("Invalid pruning mode specified".to_string())) + .map(PruningMode::keep_blocks), + }) + .transpose() } /// Get the block pruning value from the parameters diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 72422eb82d6dd..a32a666c3c980 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -296,8 +296,8 @@ pub struct DatabaseSettings { pub state_cache_size: usize, /// Ratio of cache size dedicated to child tries. pub state_cache_child_ratio: Option<(usize, usize)>, - /// State pruning mode. - pub state_pruning: PruningMode, + /// Requested state pruning mode. + pub state_pruning: Option, /// Where to find the database. pub source: DatabaseSource, /// Block pruning mode. @@ -341,7 +341,13 @@ pub enum DatabaseSource { }, /// Use a custom already-open database. - Custom(Arc>), + Custom { + /// the handle to the custom storage + db: Arc>, + + /// if set, the `create` flag will be required to open such datasource + require_create_flag: bool, + }, } impl DatabaseSource { @@ -354,7 +360,7 @@ impl DatabaseSource { // I would think rocksdb, but later parity-db. DatabaseSource::Auto { paritydb_path, .. } => Some(paritydb_path), DatabaseSource::RocksDb { path, .. } | DatabaseSource::ParityDb { path } => Some(path), - DatabaseSource::Custom(..) => None, + DatabaseSource::Custom { .. } => None, } } @@ -370,7 +376,7 @@ impl DatabaseSource { *path = p.into(); true }, - DatabaseSource::Custom(..) => false, + DatabaseSource::Custom { .. } => false, } } } @@ -381,7 +387,7 @@ impl std::fmt::Display for DatabaseSource { DatabaseSource::Auto { .. } => "Auto", DatabaseSource::RocksDb { .. } => "RocksDb", DatabaseSource::ParityDb { .. } => "ParityDb", - DatabaseSource::Custom(_) => "Custom", + DatabaseSource::Custom { .. } => "Custom", }; write!(f, "{}", name) } @@ -416,7 +422,7 @@ struct PendingBlock { struct StateMetaDb<'a>(&'a dyn Database); impl<'a> sc_state_db::MetaDb for StateMetaDb<'a> { - type Error = io::Error; + type Error = sp_database::error::DatabaseError; fn get_meta(&self, key: &[u8]) -> Result>, Self::Error> { Ok(self.0.get(columns::STATE_META, key)) @@ -1009,9 +1015,23 @@ impl Backend { /// Create a new instance of database backend. /// /// The pruning window is how old a block must be before the state is pruned. - pub fn new(config: DatabaseSettings, canonicalization_delay: u64) -> ClientResult { - let db = crate::utils::open_database::(&config, DatabaseType::Full)?; - Self::from_database(db as Arc<_>, canonicalization_delay, &config) + pub fn new(db_config: DatabaseSettings, canonicalization_delay: u64) -> ClientResult { + use utils::OpenDbError; + + let db_source = &db_config.source; + + let (needs_init, db) = + match crate::utils::open_database::(db_source, DatabaseType::Full, false) { + Ok(db) => (false, db), + Err(OpenDbError::DoesNotExist) => { + let db = + crate::utils::open_database::(db_source, DatabaseType::Full, true)?; + (true, db) + }, + Err(as_is) => return Err(as_is.into()), + }; + + Self::from_database(db as Arc<_>, canonicalization_delay, &db_config, needs_init) } /// Create new memory-backed client backend for tests. @@ -1028,8 +1048,8 @@ impl Backend { let db_setting = DatabaseSettings { state_cache_size: 16777216, state_cache_child_ratio: Some((50, 100)), - state_pruning: PruningMode::keep_blocks(keep_blocks), - source: DatabaseSource::Custom(db), + state_pruning: Some(PruningMode::keep_blocks(keep_blocks)), + source: DatabaseSource::Custom { db, require_create_flag: true }, keep_blocks: KeepBlocks::Some(keep_blocks), }; @@ -1057,18 +1077,31 @@ impl Backend { db: Arc>, canonicalization_delay: u64, config: &DatabaseSettings, + should_init: bool, ) -> ClientResult { - let is_archive_pruning = config.state_pruning.is_archive(); - let blockchain = BlockchainDb::new(db.clone())?; + let mut db_init_transaction = Transaction::new(); + + let requested_state_pruning = config.state_pruning.clone(); + let state_meta_db = StateMetaDb(db.as_ref()); let map_e = sp_blockchain::Error::from_state_db; - let state_db: StateDb<_, _> = StateDb::new( - config.state_pruning.clone(), + + let (state_db_init_commit_set, state_db) = StateDb::open( + &state_meta_db, + requested_state_pruning, !db.supports_ref_counting(), - &StateMetaDb(&*db), + should_init, ) .map_err(map_e)?; + + apply_state_commit(&mut db_init_transaction, state_db_init_commit_set); + + let state_pruning_used = state_db.pruning_mode(); + let is_archive_pruning = state_pruning_used.is_archive(); + let blockchain = BlockchainDb::new(db.clone())?; + let storage_db = StorageDb { db: db.clone(), state_db, prefix_keys: !db.supports_ref_counting() }; + let offchain_storage = offchain::LocalStorage::new(db.clone()); let backend = Backend { @@ -1105,6 +1138,9 @@ impl Backend { with_state: true, }); } + + db.commit(db_init_transaction)?; + Ok(backend) } @@ -2251,6 +2287,13 @@ impl sc_client_api::backend::Backend for Backend { fn get_import_lock(&self) -> &RwLock<()> { &*self.import_lock } + + fn requires_full_sync(&self) -> bool { + matches!( + self.storage.state_db.pruning_mode(), + PruningMode::ArchiveAll | PruningMode::ArchiveCanonical + ) + } } impl sc_client_api::backend::LocalBackend for Backend {} @@ -2390,8 +2433,8 @@ pub(crate) mod tests { DatabaseSettings { state_cache_size: 16777216, state_cache_child_ratio: Some((50, 100)), - state_pruning: PruningMode::keep_blocks(1), - source: DatabaseSource::Custom(backing), + state_pruning: Some(PruningMode::keep_blocks(1)), + source: DatabaseSource::Custom { db: backing, require_create_flag: false }, keep_blocks: KeepBlocks::All, }, 0, diff --git a/client/db/src/upgrade.rs b/client/db/src/upgrade.rs index cd18554fb0d06..292905663a20b 100644 --- a/client/db/src/upgrade.rs +++ b/client/db/src/upgrade.rs @@ -190,8 +190,7 @@ fn version_file_path(path: &Path) -> PathBuf { #[cfg(test)] mod tests { use super::*; - use crate::{tests::Block, DatabaseSettings, DatabaseSource, KeepBlocks}; - use sc_state_db::PruningMode; + use crate::{tests::Block, DatabaseSource}; fn create_db(db_path: &Path, version: Option) { if let Some(version) = version { @@ -203,16 +202,12 @@ mod tests { fn open_database(db_path: &Path, db_type: DatabaseType) -> sp_blockchain::Result<()> { crate::utils::open_database::( - &DatabaseSettings { - state_cache_size: 0, - state_cache_child_ratio: None, - state_pruning: PruningMode::ArchiveAll, - source: DatabaseSource::RocksDb { path: db_path.to_owned(), cache_size: 128 }, - keep_blocks: KeepBlocks::All, - }, + &DatabaseSource::RocksDb { path: db_path.to_owned(), cache_size: 128 }, db_type, + true, ) .map(|_| ()) + .map_err(|e| sp_blockchain::Error::Backend(e.to_string())) } #[test] diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index d3cb9a994fdd3..0227e4db8bcd0 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -23,7 +23,7 @@ use std::{fmt, fs, io, path::Path, sync::Arc}; use log::{debug, info}; -use crate::{Database, DatabaseSettings, DatabaseSource, DbHash}; +use crate::{Database, DatabaseSource, DbHash}; use codec::Decode; use sp_database::Transaction; use sp_runtime::{ @@ -177,41 +177,42 @@ where }) } -fn backend_err(feat: &'static str) -> sp_blockchain::Error { - sp_blockchain::Error::Backend(feat.to_string()) -} - /// Opens the configured database. pub fn open_database( - config: &DatabaseSettings, + db_source: &DatabaseSource, db_type: DatabaseType, -) -> sp_blockchain::Result>> { + create: bool, +) -> OpenDbResult { // Maybe migrate (copy) the database to a type specific subdirectory to make it // possible that light and full databases coexist // NOTE: This function can be removed in a few releases - maybe_migrate_to_type_subdir::(&config.source, db_type).map_err(|e| { - sp_blockchain::Error::Backend(format!("Error in migration to role subdirectory: {}", e)) - })?; + maybe_migrate_to_type_subdir::(db_source, db_type)?; - open_database_at::(&config.source, db_type) + open_database_at::(db_source, db_type, create) } fn open_database_at( - source: &DatabaseSource, + db_source: &DatabaseSource, db_type: DatabaseType, -) -> sp_blockchain::Result>> { - let db: Arc> = match &source { - DatabaseSource::ParityDb { path } => open_parity_db::(path, db_type, true)?, + create: bool, +) -> OpenDbResult { + let db: Arc> = match &db_source { + DatabaseSource::ParityDb { path } => open_parity_db::(path, db_type, create)?, DatabaseSource::RocksDb { path, cache_size } => - open_kvdb_rocksdb::(path, db_type, true, *cache_size)?, - DatabaseSource::Custom(db) => db.clone(), + open_kvdb_rocksdb::(path, db_type, create, *cache_size)?, + DatabaseSource::Custom { db, require_create_flag } => { + if *require_create_flag && !create { + return Err(OpenDbError::DoesNotExist) + } + db.clone() + }, DatabaseSource::Auto { paritydb_path, rocksdb_path, cache_size } => { // check if rocksdb exists first, if not, open paritydb match open_kvdb_rocksdb::(rocksdb_path, db_type, false, *cache_size) { Ok(db) => db, Err(OpenDbError::NotEnabled(_)) | Err(OpenDbError::DoesNotExist) => - open_parity_db::(paritydb_path, db_type, true)?, - Err(_) => return Err(backend_err("cannot open rocksdb. corrupted database")), + open_parity_db::(paritydb_path, db_type, create)?, + Err(as_is) => return Err(as_is), } }, }; @@ -221,12 +222,17 @@ fn open_database_at( } #[derive(Debug)] -enum OpenDbError { +pub enum OpenDbError { // constructed only when rocksdb and paritydb are disabled #[allow(dead_code)] NotEnabled(&'static str), DoesNotExist, Internal(String), + DatabaseError(sp_database::error::DatabaseError), + UnexpectedDbType { + expected: DatabaseType, + found: Vec, + }, } type OpenDbResult = Result>, OpenDbError>; @@ -239,6 +245,17 @@ impl fmt::Display for OpenDbError { OpenDbError::NotEnabled(feat) => { write!(f, "`{}` feature not enabled, database can not be opened", feat) }, + OpenDbError::DatabaseError(db_error) => { + write!(f, "Database Error: {}", db_error) + }, + OpenDbError::UnexpectedDbType { expected, found } => { + write!( + f, + "Unexpected DB-Type. Expected: {:?}, Found: {:?}", + expected.as_str().as_bytes(), + found + ) + }, } } } @@ -356,19 +373,19 @@ fn open_kvdb_rocksdb( pub fn check_database_type( db: &dyn Database, db_type: DatabaseType, -) -> sp_blockchain::Result<()> { +) -> Result<(), OpenDbError> { match db.get(COLUMN_META, meta_keys::TYPE) { Some(stored_type) => if db_type.as_str().as_bytes() != &*stored_type { - return Err(sp_blockchain::Error::Backend(format!( - "Unexpected database type. Expected: {}", - db_type.as_str() - ))) + return Err(OpenDbError::UnexpectedDbType { + expected: db_type, + found: stored_type.to_owned(), + }) }, None => { let mut transaction = Transaction::new(); transaction.set(COLUMN_META, meta_keys::TYPE, db_type.as_str().as_bytes()); - db.commit(transaction)?; + db.commit(transaction).map_err(OpenDbError::DatabaseError)?; }, } @@ -378,7 +395,7 @@ pub fn check_database_type( fn maybe_migrate_to_type_subdir( source: &DatabaseSource, db_type: DatabaseType, -) -> io::Result<()> { +) -> Result<(), OpenDbError> { if let Some(p) = source.path() { let mut basedir = p.to_path_buf(); basedir.pop(); @@ -393,14 +410,14 @@ fn maybe_migrate_to_type_subdir( // database stored in the target directory and close the database on success. let mut old_source = source.clone(); old_source.set_path(&basedir); - open_database_at::(&old_source, db_type) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + open_database_at::(&old_source, db_type, false)?; info!( "Migrating database to a database-type-based subdirectory: '{:?}' -> '{:?}'", basedir, basedir.join(db_type.as_str()) ); + let mut tmp_dir = basedir.clone(); tmp_dir.pop(); tmp_dir.push("tmp"); @@ -580,9 +597,7 @@ impl<'a, 'b> codec::Input for JoinInput<'a, 'b> { #[cfg(test)] mod tests { use super::*; - use crate::KeepBlocks; use codec::Input; - use sc_state_db::PruningMode; use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; use std::path::PathBuf; type Block = RawBlock>; @@ -601,18 +616,17 @@ mod tests { let old_db_path = base_path.path().join("chains/dev/db"); source.set_path(&old_db_path); - let settings = db_settings(source.clone()); { - let db_res = open_database::(&settings, db_type); + let db_res = open_database::(&source, db_type, true); assert!(db_res.is_ok(), "New database should be created."); assert!(old_db_path.join(db_check_file).exists()); assert!(!old_db_path.join(db_type.as_str()).join("db_version").exists()); } source.set_path(&old_db_path.join(db_type.as_str())); - let settings = db_settings(source); - let db_res = open_database::(&settings, db_type); + + let db_res = open_database::(&source, db_type, true); assert!(db_res.is_ok(), "Reopening the db with the same role should work"); // check if the database dir had been migrated assert!(!old_db_path.join(db_check_file).exists()); @@ -638,9 +652,8 @@ mod tests { let old_db_path = base_path.path().join("chains/dev/db"); let source = DatabaseSource::RocksDb { path: old_db_path.clone(), cache_size: 128 }; - let settings = db_settings(source); { - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::(&source, DatabaseType::Full, true); assert!(db_res.is_ok(), "New database should be created."); // check if the database dir had been migrated @@ -689,16 +702,6 @@ mod tests { assert_eq!(joined.remaining_len().unwrap(), Some(0)); } - fn db_settings(source: DatabaseSource) -> DatabaseSettings { - DatabaseSettings { - state_cache_size: 0, - state_cache_child_ratio: None, - state_pruning: PruningMode::ArchiveAll, - source, - keep_blocks: KeepBlocks::All, - } - } - #[cfg(feature = "with-parity-db")] #[cfg(any(feature = "with-kvdb-rocksdb", test))] #[test] @@ -712,31 +715,36 @@ mod tests { rocksdb_path: rocksdb_path.clone(), cache_size: 128, }; - let mut settings = db_settings(source); // it should create new auto (paritydb) database { - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::(&source, DatabaseType::Full, true); assert!(db_res.is_ok(), "New database should be created."); } // it should reopen existing auto (pairtydb) database { - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::(&source, DatabaseType::Full, true); assert!(db_res.is_ok(), "Existing parity database should be reopened"); } // it should fail to open existing auto (pairtydb) database { - settings.source = DatabaseSource::RocksDb { path: rocksdb_path, cache_size: 128 }; - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::( + &DatabaseSource::RocksDb { path: rocksdb_path, cache_size: 128 }, + DatabaseType::Full, + true, + ); assert!(db_res.is_ok(), "New database should be opened."); } // it should reopen existing auto (pairtydb) database { - settings.source = DatabaseSource::ParityDb { path: paritydb_path }; - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::( + &DatabaseSource::ParityDb { path: paritydb_path }, + DatabaseType::Full, + true, + ); assert!(db_res.is_ok(), "Existing parity database should be reopened"); } } @@ -751,36 +759,44 @@ mod tests { let rocksdb_path = db_path.join("rocksdb_path"); let source = DatabaseSource::RocksDb { path: rocksdb_path.clone(), cache_size: 128 }; - let mut settings = db_settings(source); // it should create new rocksdb database { - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::(&source, DatabaseType::Full, true); assert!(db_res.is_ok(), "New rocksdb database should be created"); } // it should reopen existing auto (rocksdb) database { - settings.source = DatabaseSource::Auto { - paritydb_path: paritydb_path.clone(), - rocksdb_path: rocksdb_path.clone(), - cache_size: 128, - }; - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::( + &DatabaseSource::Auto { + paritydb_path: paritydb_path.clone(), + rocksdb_path: rocksdb_path.clone(), + cache_size: 128, + }, + DatabaseType::Full, + true, + ); assert!(db_res.is_ok(), "Existing rocksdb database should be reopened"); } // it should fail to open existing auto (rocksdb) database { - settings.source = DatabaseSource::ParityDb { path: paritydb_path }; - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::( + &DatabaseSource::ParityDb { path: paritydb_path }, + DatabaseType::Full, + true, + ); assert!(db_res.is_ok(), "New paritydb database should be created"); } // it should reopen existing auto (pairtydb) database { - settings.source = DatabaseSource::RocksDb { path: rocksdb_path, cache_size: 128 }; - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::( + &DatabaseSource::RocksDb { path: rocksdb_path, cache_size: 128 }, + DatabaseType::Full, + true, + ); assert!(db_res.is_ok(), "Existing rocksdb database should be reopened"); } } @@ -795,32 +811,36 @@ mod tests { let rocksdb_path = db_path.join("rocksdb_path"); let source = DatabaseSource::ParityDb { path: paritydb_path.clone() }; - let mut settings = db_settings(source); // it should create new paritydb database { - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::(&source, DatabaseType::Full, true); assert!(db_res.is_ok(), "New database should be created."); } // it should reopen existing pairtydb database { - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::(&source, DatabaseType::Full, true); assert!(db_res.is_ok(), "Existing parity database should be reopened"); } // it should fail to open existing pairtydb database { - settings.source = - DatabaseSource::RocksDb { path: rocksdb_path.clone(), cache_size: 128 }; - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::( + &DatabaseSource::RocksDb { path: rocksdb_path.clone(), cache_size: 128 }, + DatabaseType::Full, + true, + ); assert!(db_res.is_ok(), "New rocksdb database should be created"); } // it should reopen existing auto (pairtydb) database { - settings.source = DatabaseSource::Auto { paritydb_path, rocksdb_path, cache_size: 128 }; - let db_res = open_database::(&settings, DatabaseType::Full); + let db_res = open_database::( + &DatabaseSource::Auto { paritydb_path, rocksdb_path, cache_size: 128 }, + DatabaseType::Full, + true, + ); assert!(db_res.is_ok(), "Existing parity database should be reopened"); } } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 35ea67d8fbf85..cabf004b2f707 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -307,7 +307,7 @@ where wasm_runtime_overrides: config.wasm_runtime_overrides.clone(), no_genesis: matches!( config.network.sync_mode, - sc_network::config::SyncMode::Fast { .. } | sc_network::config::SyncMode::Warp + SyncMode::Fast { .. } | SyncMode::Warp { .. } ), wasm_runtime_substitutes, }, @@ -781,12 +781,12 @@ where return Err("Warp sync enabled, but no warp sync provider configured.".into()) } - if config.state_pruning.is_archive() { + if client.requires_full_sync() { match config.network.sync_mode { SyncMode::Fast { .. } => return Err("Fast sync doesn't work for archive nodes".into()), SyncMode::Warp => return Err("Warp sync doesn't work for archive nodes".into()), SyncMode::Full => {}, - }; + } } let transaction_pool_adapter = Arc::new(TransactionPoolAdapter { diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 48e4d0141c4e7..fb73b4c34c040 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1989,6 +1989,10 @@ where ) -> sp_blockchain::Result>>> { self.backend.blockchain().block_indexed_body(*id) } + + fn requires_full_sync(&self) -> bool { + self.backend.requires_full_sync() + } } impl backend::AuxStore for Client diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 56980ad14425f..e49e8b40a7b1a 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -73,7 +73,7 @@ pub struct Configuration { /// Size in percent of cache size dedicated to child tries pub state_cache_child_ratio: Option, /// State pruning settings. - pub state_pruning: PruningMode, + pub state_pruning: Option, /// Number of blocks to keep in the db. pub keep_blocks: KeepBlocks, /// Chain configuration. diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 6aa047c6393da..136efad088fae 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1199,7 +1199,7 @@ fn doesnt_import_blocks_that_revert_finality() { DatabaseSettings { state_cache_size: 1 << 20, state_cache_child_ratio: None, - state_pruning: PruningMode::ArchiveAll, + state_pruning: Some(PruningMode::ArchiveAll), keep_blocks: KeepBlocks::All, source: DatabaseSource::RocksDb { path: tmp.path().into(), cache_size: 1024 }, }, @@ -1426,7 +1426,7 @@ fn returns_status_for_pruned_blocks() { DatabaseSettings { state_cache_size: 1 << 20, state_cache_child_ratio: None, - state_pruning: PruningMode::keep_blocks(1), + state_pruning: Some(PruningMode::keep_blocks(1)), keep_blocks: KeepBlocks::All, source: DatabaseSource::RocksDb { path: tmp.path().into(), cache_size: 1024 }, }, diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 8fe2cdc9d9a85..794dec3b954b7 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -115,9 +115,13 @@ pub trait NodeDb { } /// Error type. -pub enum Error { +pub enum Error { /// Database backend error. Db(E), + StateDb(StateDbError), +} + +pub enum StateDbError { /// `Codec` decoding error. Decoding(codec::Error), /// Trying to canonicalize invalid block. @@ -127,11 +131,19 @@ pub enum Error { /// Trying to insert block with unknown parent. InvalidParent, /// Invalid pruning mode specified. Contains expected mode. - InvalidPruningMode(String), + IncompatiblePruningModes { stored: PruningMode, requested: PruningMode }, /// Too many unfinalized sibling blocks inserted. TooManySiblingBlocks, /// Trying to insert existing block. BlockAlreadyExists, + /// Invalid metadata + Metadata(String), +} + +impl From for Error { + fn from(inner: StateDbError) -> Self { + Self::StateDb(inner) + } } /// Pinning error type. @@ -142,21 +154,34 @@ pub enum PinError { impl From for Error { fn from(x: codec::Error) -> Self { - Error::Decoding(x) + StateDbError::Decoding(x).into() } } impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Error::Db(e) => e.fmt(f), - Error::Decoding(e) => write!(f, "Error decoding sliceable value: {}", e), - Error::InvalidBlock => write!(f, "Trying to canonicalize invalid block"), - Error::InvalidBlockNumber => write!(f, "Trying to insert block with invalid number"), - Error::InvalidParent => write!(f, "Trying to insert block with unknown parent"), - Error::InvalidPruningMode(e) => write!(f, "Expected pruning mode: {}", e), - Error::TooManySiblingBlocks => write!(f, "Too many sibling blocks inserted"), - Error::BlockAlreadyExists => write!(f, "Block already exists"), + Self::Db(e) => e.fmt(f), + Self::StateDb(e) => e.fmt(f), + } + } +} + +impl fmt::Debug for StateDbError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Decoding(e) => write!(f, "Error decoding sliceable value: {}", e), + Self::InvalidBlock => write!(f, "Trying to canonicalize invalid block"), + Self::InvalidBlockNumber => write!(f, "Trying to insert block with invalid number"), + Self::InvalidParent => write!(f, "Trying to insert block with unknown parent"), + Self::IncompatiblePruningModes { stored, requested } => write!( + f, + "Incompatible pruning modes [stored: {:?}; requested: {:?}]", + stored, requested + ), + Self::TooManySiblingBlocks => write!(f, "Too many sibling blocks inserted"), + Self::BlockAlreadyExists => write!(f, "Block already exists"), + Self::Metadata(message) => write!(f, "Invalid metadata: {}", message), } } } @@ -180,7 +205,7 @@ pub struct CommitSet { } /// Pruning constraints. If none are specified pruning is -#[derive(Default, Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Constraints { /// Maximum blocks. Defaults to 0 when unspecified, effectively keeping only non-canonical /// states. @@ -222,11 +247,25 @@ impl PruningMode { PruningMode::Constrained(_) => PRUNING_MODE_CONSTRAINED, } } + pub fn from_id(id: &[u8]) -> Option { + match id { + PRUNING_MODE_ARCHIVE => Some(Self::ArchiveAll), + PRUNING_MODE_ARCHIVE_CANON => Some(Self::ArchiveCanonical), + PRUNING_MODE_CONSTRAINED => Some(Self::Constrained(Default::default())), + _ => None, + } + } } impl Default for PruningMode { fn default() -> Self { - PruningMode::keep_blocks(256) + PruningMode::Constrained(Default::default()) + } +} + +impl Default for Constraints { + fn default() -> Self { + Self { max_blocks: Some(256), max_mem: None } } } @@ -251,9 +290,6 @@ impl StateDbSync Result, Error> { trace!(target: "state-db", "StateDb settings: {:?}. Ref-counting: {}", mode, ref_counting); - // Check that settings match - Self::check_meta(&mode, db)?; - let non_canonical: NonCanonicalOverlay = NonCanonicalOverlay::new(db)?; let pruning: Option> = match mode { PruningMode::Constrained(Constraints { max_mem: Some(_), .. }) => unimplemented!(), @@ -264,19 +300,6 @@ impl StateDbSync(mode: &PruningMode, db: &D) -> Result<(), Error> { - let db_mode = db.get_meta(&to_meta_key(PRUNING_MODE, &())).map_err(Error::Db)?; - trace!(target: "state-db", - "DB pruning mode: {:?}", - db_mode.as_ref().map(|v| std::str::from_utf8(v)) - ); - match &db_mode { - Some(v) if v.as_slice() == mode.id() => Ok(()), - Some(v) => Err(Error::InvalidPruningMode(String::from_utf8_lossy(v).into())), - None => Ok(()), - } - } - fn insert_block( &mut self, hash: &BlockHash, @@ -284,25 +307,16 @@ impl StateDbSync, ) -> Result, Error> { - let mut meta = ChangeSet::default(); - if number == 0 { - // Save pruning mode when writing first block. - meta.inserted.push((to_meta_key(PRUNING_MODE, &()), self.mode.id().into())); - } - match self.mode { PruningMode::ArchiveAll => { changeset.deleted.clear(); // write changes immediately - Ok(CommitSet { data: changeset, meta }) - }, - PruningMode::Constrained(_) | PruningMode::ArchiveCanonical => { - let commit = self.non_canonical.insert(hash, number, parent_hash, changeset); - commit.map(|mut c| { - c.meta.inserted.extend(meta.inserted); - c - }) + Ok(CommitSet { data: changeset, meta: Default::default() }) }, + PruningMode::Constrained(_) | PruningMode::ArchiveCanonical => self + .non_canonical + .insert(hash, number, parent_hash, changeset) + .map_err(Into::into), } } @@ -319,7 +333,7 @@ impl StateDbSync return Err(e), + Err(e) => return Err(e.into()), }; if let Some(ref mut pruning) = self.pruning { pruning.note_canonical(hash, &mut commit); @@ -480,13 +494,56 @@ pub struct StateDb { } impl StateDb { - /// Creates a new instance. Does not expect any metadata in the database. - pub fn new( - mode: PruningMode, - ref_counting: bool, + /// Create an instance of [`StateDb`]. + pub fn open( db: &D, - ) -> Result, Error> { - Ok(StateDb { db: RwLock::new(StateDbSync::new(mode, ref_counting, db)?) }) + requested_mode: Option, + ref_counting: bool, + should_init: bool, + ) -> Result<(CommitSet, StateDb), Error> + where + D: MetaDb, + { + let stored_mode = fetch_stored_pruning_mode(db)?; + + let selected_mode = match (should_init, stored_mode, requested_mode) { + (true, stored_mode, requested_mode) => { + assert!(stored_mode.is_none(), "The storage has just been initialized. No meta-data is expected to be found in it."); + requested_mode.unwrap_or_default() + }, + + (false, None, _) => + return Err(StateDbError::Metadata( + "An existing StateDb does not have PRUNING_MODE stored in its meta-data".into(), + ) + .into()), + + (false, Some(stored), None) => stored, + + (false, Some(stored), Some(requested)) => choose_pruning_mode(stored, requested)?, + }; + + let db_init_commit_set = if should_init { + let mut cs: CommitSet = Default::default(); + + let key = to_meta_key(PRUNING_MODE, &()); + let value = selected_mode.id().to_owned(); + + cs.meta.inserted.push((key, value)); + + cs + } else { + Default::default() + }; + + let state_db = + StateDb { db: RwLock::new(StateDbSync::new(selected_mode, ref_counting, db)?) }; + + Ok((db_init_commit_set, state_db)) + } + + pub fn pruning_mode(&self) -> PruningMode { + self.db.read().mode.clone() } /// Add a new non-canonical block. @@ -571,18 +628,51 @@ impl StateDb(db: &D) -> Result, Error> { + let meta_key_mode = to_meta_key(PRUNING_MODE, &()); + if let Some(stored_mode) = db.get_meta(&meta_key_mode).map_err(Error::Db)? { + if let Some(mode) = PruningMode::from_id(&stored_mode) { + Ok(Some(mode)) + } else { + Err(StateDbError::Metadata(format!( + "Invalid value stored for PRUNING_MODE: {:02x?}", + stored_mode + )) + .into()) + } + } else { + Ok(None) + } +} + +fn choose_pruning_mode( + stored: PruningMode, + requested: PruningMode, +) -> Result { + match (stored, requested) { + (PruningMode::ArchiveAll, PruningMode::ArchiveAll) => Ok(PruningMode::ArchiveAll), + (PruningMode::ArchiveCanonical, PruningMode::ArchiveCanonical) => + Ok(PruningMode::ArchiveCanonical), + (PruningMode::Constrained(_), PruningMode::Constrained(requested)) => + Ok(PruningMode::Constrained(requested)), + (stored, requested) => Err(StateDbError::IncompatiblePruningModes { requested, stored }), + } +} + #[cfg(test)] mod tests { use crate::{ test::{make_changeset, make_db, TestDb}, - Constraints, PruningMode, StateDb, + Constraints, Error, PruningMode, StateDb, StateDbError, }; use sp_core::H256; use std::io; fn make_test_db(settings: PruningMode) -> (TestDb, StateDb) { let mut db = make_db(&[91, 921, 922, 93, 94]); - let state_db = StateDb::new(settings, false, &db).unwrap(); + let (state_db_init, state_db) = + StateDb::open(&mut db, Some(settings), false, true).unwrap(); + db.commit(&state_db_init); db.commit( &state_db @@ -697,7 +787,9 @@ mod tests { #[test] fn detects_incompatible_mode() { let mut db = make_db(&[]); - let state_db = StateDb::new(PruningMode::ArchiveAll, false, &db).unwrap(); + let (state_db_init, state_db) = + StateDb::open(&mut db, Some(PruningMode::ArchiveAll), false, true).unwrap(); + db.commit(&state_db_init); db.commit( &state_db .insert_block::( @@ -709,7 +801,85 @@ mod tests { .unwrap(), ); let new_mode = PruningMode::Constrained(Constraints { max_blocks: Some(2), max_mem: None }); - let state_db: Result, _> = StateDb::new(new_mode, false, &db); - assert!(state_db.is_err()); + let state_db_open_result: Result<(_, StateDb), _> = + StateDb::open(&mut db, Some(new_mode), false, false); + assert!(state_db_open_result.is_err()); + } + + fn check_stored_and_requested_mode_compatibility( + mode_when_created: Option, + mode_when_reopened: Option, + expected_effective_mode_when_reopenned: Result, + ) { + let mut db = make_db(&[]); + let (state_db_init, state_db) = + StateDb::::open(&mut db, mode_when_created, false, true).unwrap(); + db.commit(&state_db_init); + std::mem::drop(state_db); + + let state_db_reopen_result = + StateDb::::open(&mut db, mode_when_reopened, false, false); + if let Ok(expected_mode) = expected_effective_mode_when_reopenned { + let (state_db_init, state_db_reopened) = state_db_reopen_result.unwrap(); + db.commit(&state_db_init); + assert_eq!(state_db_reopened.pruning_mode(), expected_mode,) + } else { + assert!(matches!( + state_db_reopen_result, + Err(Error::StateDb(StateDbError::IncompatiblePruningModes { .. })) + )); + } + } + + #[test] + fn pruning_mode_compatibility() { + for (created, reopened, expected) in [ + (None, None, Ok(PruningMode::keep_blocks(256))), + (None, Some(PruningMode::keep_blocks(256)), Ok(PruningMode::keep_blocks(256))), + (None, Some(PruningMode::keep_blocks(128)), Ok(PruningMode::keep_blocks(128))), + (None, Some(PruningMode::keep_blocks(512)), Ok(PruningMode::keep_blocks(512))), + (None, Some(PruningMode::ArchiveAll), Err(())), + (None, Some(PruningMode::ArchiveCanonical), Err(())), + (Some(PruningMode::keep_blocks(256)), None, Ok(PruningMode::keep_blocks(256))), + ( + Some(PruningMode::keep_blocks(256)), + Some(PruningMode::keep_blocks(256)), + Ok(PruningMode::keep_blocks(256)), + ), + ( + Some(PruningMode::keep_blocks(256)), + Some(PruningMode::keep_blocks(128)), + Ok(PruningMode::keep_blocks(128)), + ), + ( + Some(PruningMode::keep_blocks(256)), + Some(PruningMode::keep_blocks(512)), + Ok(PruningMode::keep_blocks(512)), + ), + (Some(PruningMode::keep_blocks(256)), Some(PruningMode::ArchiveAll), Err(())), + (Some(PruningMode::keep_blocks(256)), Some(PruningMode::ArchiveCanonical), Err(())), + (Some(PruningMode::ArchiveAll), None, Ok(PruningMode::ArchiveAll)), + (Some(PruningMode::ArchiveAll), Some(PruningMode::keep_blocks(256)), Err(())), + (Some(PruningMode::ArchiveAll), Some(PruningMode::keep_blocks(128)), Err(())), + (Some(PruningMode::ArchiveAll), Some(PruningMode::keep_blocks(512)), Err(())), + ( + Some(PruningMode::ArchiveAll), + Some(PruningMode::ArchiveAll), + Ok(PruningMode::ArchiveAll), + ), + (Some(PruningMode::ArchiveAll), Some(PruningMode::ArchiveCanonical), Err(())), + (Some(PruningMode::ArchiveCanonical), None, Ok(PruningMode::ArchiveCanonical)), + (Some(PruningMode::ArchiveCanonical), Some(PruningMode::keep_blocks(256)), Err(())), + (Some(PruningMode::ArchiveCanonical), Some(PruningMode::keep_blocks(128)), Err(())), + (Some(PruningMode::ArchiveCanonical), Some(PruningMode::keep_blocks(512)), Err(())), + (Some(PruningMode::ArchiveCanonical), Some(PruningMode::ArchiveAll), Err(())), + ( + Some(PruningMode::ArchiveCanonical), + Some(PruningMode::ArchiveCanonical), + Ok(PruningMode::ArchiveCanonical), + ), + ] { + check_stored_and_requested_mode_compatibility(created, reopened, expected); + } } } diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index 30f2042863010..13cf5825b1b24 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -22,13 +22,10 @@ //! All pending changes are kept in memory until next call to `apply_pending` or //! `revert_pending` -use super::{to_meta_key, ChangeSet, CommitSet, DBValue, Error, Hash, MetaDb}; +use super::{to_meta_key, ChangeSet, CommitSet, DBValue, Error, Hash, MetaDb, StateDbError}; use codec::{Decode, Encode}; use log::trace; -use std::{ - collections::{hash_map::Entry, HashMap, VecDeque}, - fmt, -}; +use std::collections::{hash_map::Entry, HashMap, VecDeque}; const NON_CANONICAL_JOURNAL: &[u8] = b"noncanonical_journal"; const LAST_CANONICAL: &[u8] = b"last_canonical"; @@ -242,13 +239,13 @@ impl NonCanonicalOverlay { /// Insert a new block into the overlay. If inserted on the second level or lover expects parent /// to be present in the window. - pub fn insert( + pub fn insert( &mut self, hash: &BlockHash, number: u64, parent_hash: &BlockHash, changeset: ChangeSet, - ) -> Result, Error> { + ) -> Result, StateDbError> { let mut commit = CommitSet::default(); let front_block_number = self.front_block_number(); if self.levels.is_empty() && self.last_canonicalized.is_none() && number > 0 { @@ -267,7 +264,7 @@ impl NonCanonicalOverlay { front_block_number, front_block_number + self.levels.len() as u64, ); - return Err(Error::InvalidBlockNumber) + return Err(StateDbError::InvalidBlockNumber) } // check for valid parent if inserting on second level or higher if number == front_block_number { @@ -276,10 +273,10 @@ impl NonCanonicalOverlay { .as_ref() .map_or(false, |&(ref h, n)| h == parent_hash && n == number - 1) { - return Err(Error::InvalidParent) + return Err(StateDbError::InvalidParent) } } else if !self.parents.contains_key(parent_hash) { - return Err(Error::InvalidParent) + return Err(StateDbError::InvalidParent) } } let level = if self.levels.is_empty() || @@ -293,10 +290,10 @@ impl NonCanonicalOverlay { }; if level.blocks.len() >= MAX_BLOCKS_PER_LEVEL as usize { - return Err(Error::TooManySiblingBlocks) + return Err(StateDbError::TooManySiblingBlocks) } if level.blocks.iter().any(|b| b.hash == *hash) { - return Err(Error::BlockAlreadyExists) + return Err(StateDbError::BlockAlreadyExists) } let index = level.available_index(); @@ -380,21 +377,21 @@ impl NonCanonicalOverlay { /// Select a top-level root and canonicalized it. Discards all sibling subtrees and the root. /// Returns a set of changes that need to be added to the DB. - pub fn canonicalize( + pub fn canonicalize( &mut self, hash: &BlockHash, commit: &mut CommitSet, - ) -> Result<(), Error> { + ) -> Result<(), StateDbError> { trace!(target: "state-db", "Canonicalizing {:?}", hash); let level = self .levels .get(self.pending_canonicalizations.len()) - .ok_or(Error::InvalidBlock)?; + .ok_or(StateDbError::InvalidBlock)?; let index = level .blocks .iter() .position(|overlay| overlay.hash == *hash) - .ok_or(Error::InvalidBlock)?; + .ok_or(StateDbError::InvalidBlock)?; let mut discarded_journals = Vec::new(); let mut discarded_blocks = Vec::new(); @@ -640,10 +637,9 @@ mod tests { use super::{to_journal_key, NonCanonicalOverlay}; use crate::{ test::{make_changeset, make_db}, - ChangeSet, CommitSet, Error, MetaDb, + ChangeSet, CommitSet, MetaDb, StateDbError, }; use sp_core::H256; - use std::io; fn contains(overlay: &NonCanonicalOverlay, key: u64) -> bool { overlay.get(&H256::from_low_u64_be(key)) == @@ -665,7 +661,7 @@ mod tests { let db = make_db(&[]); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); let mut commit = CommitSet::default(); - overlay.canonicalize::(&H256::default(), &mut commit).unwrap(); + overlay.canonicalize(&H256::default(), &mut commit).unwrap(); } #[test] @@ -675,10 +671,8 @@ mod tests { let h1 = H256::random(); let h2 = H256::random(); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - overlay - .insert::(&h1, 2, &H256::default(), ChangeSet::default()) - .unwrap(); - overlay.insert::(&h2, 1, &h1, ChangeSet::default()).unwrap(); + overlay.insert(&h1, 2, &H256::default(), ChangeSet::default()).unwrap(); + overlay.insert(&h2, 1, &h1, ChangeSet::default()).unwrap(); } #[test] @@ -688,10 +682,8 @@ mod tests { let h2 = H256::random(); let db = make_db(&[]); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - overlay - .insert::(&h1, 1, &H256::default(), ChangeSet::default()) - .unwrap(); - overlay.insert::(&h2, 3, &h1, ChangeSet::default()).unwrap(); + overlay.insert(&h1, 1, &H256::default(), ChangeSet::default()).unwrap(); + overlay.insert(&h2, 3, &h1, ChangeSet::default()).unwrap(); } #[test] @@ -701,12 +693,8 @@ mod tests { let h1 = H256::random(); let h2 = H256::random(); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - overlay - .insert::(&h1, 1, &H256::default(), ChangeSet::default()) - .unwrap(); - overlay - .insert::(&h2, 2, &H256::default(), ChangeSet::default()) - .unwrap(); + overlay.insert(&h1, 1, &H256::default(), ChangeSet::default()).unwrap(); + overlay.insert(&h2, 2, &H256::default(), ChangeSet::default()).unwrap(); } #[test] @@ -714,12 +702,10 @@ mod tests { let db = make_db(&[]); let h1 = H256::random(); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - overlay - .insert::(&h1, 2, &H256::default(), ChangeSet::default()) - .unwrap(); + overlay.insert(&h1, 2, &H256::default(), ChangeSet::default()).unwrap(); assert!(matches!( - overlay.insert::(&h1, 2, &H256::default(), ChangeSet::default()), - Err(Error::BlockAlreadyExists) + overlay.insert(&h1, 2, &H256::default(), ChangeSet::default()), + Err(StateDbError::BlockAlreadyExists) )); } @@ -730,11 +716,9 @@ mod tests { let h2 = H256::random(); let db = make_db(&[]); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - overlay - .insert::(&h1, 1, &H256::default(), ChangeSet::default()) - .unwrap(); + overlay.insert(&h1, 1, &H256::default(), ChangeSet::default()).unwrap(); let mut commit = CommitSet::default(); - overlay.canonicalize::(&h2, &mut commit).unwrap(); + overlay.canonicalize(&h2, &mut commit).unwrap(); } #[test] @@ -743,16 +727,14 @@ mod tests { let mut db = make_db(&[1, 2]); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); let changeset = make_changeset(&[3, 4], &[2]); - let insertion = overlay - .insert::(&h1, 1, &H256::default(), changeset.clone()) - .unwrap(); + let insertion = overlay.insert(&h1, 1, &H256::default(), changeset.clone()).unwrap(); assert_eq!(insertion.data.inserted.len(), 0); assert_eq!(insertion.data.deleted.len(), 0); assert_eq!(insertion.meta.inserted.len(), 2); assert_eq!(insertion.meta.deleted.len(), 0); db.commit(&insertion); let mut finalization = CommitSet::default(); - overlay.canonicalize::(&h1, &mut finalization).unwrap(); + overlay.canonicalize(&h1, &mut finalization).unwrap(); assert_eq!(finalization.data.inserted.len(), changeset.inserted.len()); assert_eq!(finalization.data.deleted.len(), changeset.deleted.len()); assert_eq!(finalization.meta.inserted.len(), 1); @@ -769,10 +751,10 @@ mod tests { let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); db.commit( &overlay - .insert::(&h1, 10, &H256::default(), make_changeset(&[3, 4], &[2])) + .insert(&h1, 10, &H256::default(), make_changeset(&[3, 4], &[2])) .unwrap(), ); - db.commit(&overlay.insert::(&h2, 11, &h1, make_changeset(&[5], &[3])).unwrap()); + db.commit(&overlay.insert(&h2, 11, &h1, make_changeset(&[5], &[3])).unwrap()); assert_eq!(db.meta.len(), 3); let overlay2 = NonCanonicalOverlay::::new(&db).unwrap(); @@ -789,12 +771,12 @@ mod tests { let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); db.commit( &overlay - .insert::(&h1, 10, &H256::default(), make_changeset(&[3, 4], &[2])) + .insert(&h1, 10, &H256::default(), make_changeset(&[3, 4], &[2])) .unwrap(), ); - db.commit(&overlay.insert::(&h2, 11, &h1, make_changeset(&[5], &[3])).unwrap()); + db.commit(&overlay.insert(&h2, 11, &h1, make_changeset(&[5], &[3])).unwrap()); let mut commit = CommitSet::default(); - overlay.canonicalize::(&h1, &mut commit).unwrap(); + overlay.canonicalize(&h1, &mut commit).unwrap(); db.commit(&commit); overlay.apply_pending(); assert_eq!(overlay.levels.len(), 1); @@ -813,15 +795,15 @@ mod tests { let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); let changeset1 = make_changeset(&[5, 6], &[2]); let changeset2 = make_changeset(&[7, 8], &[5, 3]); - db.commit(&overlay.insert::(&h1, 1, &H256::default(), changeset1).unwrap()); + db.commit(&overlay.insert(&h1, 1, &H256::default(), changeset1).unwrap()); assert!(contains(&overlay, 5)); - db.commit(&overlay.insert::(&h2, 2, &h1, changeset2).unwrap()); + db.commit(&overlay.insert(&h2, 2, &h1, changeset2).unwrap()); assert!(contains(&overlay, 7)); assert!(contains(&overlay, 5)); assert_eq!(overlay.levels.len(), 2); assert_eq!(overlay.parents.len(), 2); let mut commit = CommitSet::default(); - overlay.canonicalize::(&h1, &mut commit).unwrap(); + overlay.canonicalize(&h1, &mut commit).unwrap(); db.commit(&commit); assert!(contains(&overlay, 5)); assert_eq!(overlay.levels.len(), 2); @@ -832,7 +814,7 @@ mod tests { assert!(!contains(&overlay, 5)); assert!(contains(&overlay, 7)); let mut commit = CommitSet::default(); - overlay.canonicalize::(&h2, &mut commit).unwrap(); + overlay.canonicalize(&h2, &mut commit).unwrap(); db.commit(&commit); overlay.apply_pending(); assert_eq!(overlay.levels.len(), 0); @@ -847,11 +829,11 @@ mod tests { let (h_2, c_2) = (H256::random(), make_changeset(&[1], &[])); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - db.commit(&overlay.insert::(&h_1, 1, &H256::default(), c_1).unwrap()); - db.commit(&overlay.insert::(&h_2, 1, &H256::default(), c_2).unwrap()); + db.commit(&overlay.insert(&h_1, 1, &H256::default(), c_1).unwrap()); + db.commit(&overlay.insert(&h_2, 1, &H256::default(), c_2).unwrap()); assert!(contains(&overlay, 1)); let mut commit = CommitSet::default(); - overlay.canonicalize::(&h_1, &mut commit).unwrap(); + overlay.canonicalize(&h_1, &mut commit).unwrap(); db.commit(&commit); assert!(contains(&overlay, 1)); overlay.apply_pending(); @@ -866,18 +848,14 @@ mod tests { let mut db = make_db(&[]); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); let changeset = make_changeset(&[], &[]); - db.commit( - &overlay - .insert::(&h1, 1, &H256::default(), changeset.clone()) - .unwrap(), - ); - db.commit(&overlay.insert::(&h2, 2, &h1, changeset.clone()).unwrap()); + db.commit(&overlay.insert(&h1, 1, &H256::default(), changeset.clone()).unwrap()); + db.commit(&overlay.insert(&h2, 2, &h1, changeset.clone()).unwrap()); overlay.apply_pending(); let mut commit = CommitSet::default(); - overlay.canonicalize::(&h1, &mut commit).unwrap(); - overlay.canonicalize::(&h2, &mut commit).unwrap(); + overlay.canonicalize(&h1, &mut commit).unwrap(); + overlay.canonicalize(&h2, &mut commit).unwrap(); db.commit(&commit); - db.commit(&overlay.insert::(&h3, 3, &h2, changeset.clone()).unwrap()); + db.commit(&overlay.insert(&h3, 3, &h2, changeset.clone()).unwrap()); overlay.apply_pending(); assert_eq!(overlay.levels.len(), 1); } @@ -912,21 +890,21 @@ mod tests { let (h_2_1_1, c_2_1_1) = (H256::random(), make_changeset(&[211], &[])); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - db.commit(&overlay.insert::(&h_1, 1, &H256::default(), c_1).unwrap()); + db.commit(&overlay.insert(&h_1, 1, &H256::default(), c_1).unwrap()); - db.commit(&overlay.insert::(&h_1_1, 2, &h_1, c_1_1).unwrap()); - db.commit(&overlay.insert::(&h_1_2, 2, &h_1, c_1_2).unwrap()); + db.commit(&overlay.insert(&h_1_1, 2, &h_1, c_1_1).unwrap()); + db.commit(&overlay.insert(&h_1_2, 2, &h_1, c_1_2).unwrap()); - db.commit(&overlay.insert::(&h_2, 1, &H256::default(), c_2).unwrap()); + db.commit(&overlay.insert(&h_2, 1, &H256::default(), c_2).unwrap()); - db.commit(&overlay.insert::(&h_2_1, 2, &h_2, c_2_1).unwrap()); - db.commit(&overlay.insert::(&h_2_2, 2, &h_2, c_2_2).unwrap()); + db.commit(&overlay.insert(&h_2_1, 2, &h_2, c_2_1).unwrap()); + db.commit(&overlay.insert(&h_2_2, 2, &h_2, c_2_2).unwrap()); - db.commit(&overlay.insert::(&h_1_1_1, 3, &h_1_1, c_1_1_1).unwrap()); - db.commit(&overlay.insert::(&h_1_2_1, 3, &h_1_2, c_1_2_1).unwrap()); - db.commit(&overlay.insert::(&h_1_2_2, 3, &h_1_2, c_1_2_2).unwrap()); - db.commit(&overlay.insert::(&h_1_2_3, 3, &h_1_2, c_1_2_3).unwrap()); - db.commit(&overlay.insert::(&h_2_1_1, 3, &h_2_1, c_2_1_1).unwrap()); + db.commit(&overlay.insert(&h_1_1_1, 3, &h_1_1, c_1_1_1).unwrap()); + db.commit(&overlay.insert(&h_1_2_1, 3, &h_1_2, c_1_2_1).unwrap()); + db.commit(&overlay.insert(&h_1_2_2, 3, &h_1_2, c_1_2_2).unwrap()); + db.commit(&overlay.insert(&h_1_2_3, 3, &h_1_2, c_1_2_3).unwrap()); + db.commit(&overlay.insert(&h_2_1_1, 3, &h_2_1, c_2_1_1).unwrap()); assert!(contains(&overlay, 2)); assert!(contains(&overlay, 11)); @@ -946,7 +924,7 @@ mod tests { // canonicalize 1. 2 and all its children should be discarded let mut commit = CommitSet::default(); - overlay.canonicalize::(&h_1, &mut commit).unwrap(); + overlay.canonicalize(&h_1, &mut commit).unwrap(); db.commit(&commit); overlay.apply_pending(); assert_eq!(overlay.levels.len(), 2); @@ -967,7 +945,7 @@ mod tests { // canonicalize 1_2. 1_1 and all its children should be discarded let mut commit = CommitSet::default(); - overlay.canonicalize::(&h_1_2, &mut commit).unwrap(); + overlay.canonicalize(&h_1_2, &mut commit).unwrap(); db.commit(&commit); overlay.apply_pending(); assert_eq!(overlay.levels.len(), 1); @@ -984,7 +962,7 @@ mod tests { // canonicalize 1_2_2 let mut commit = CommitSet::default(); - overlay.canonicalize::(&h_1_2_2, &mut commit).unwrap(); + overlay.canonicalize(&h_1_2_2, &mut commit).unwrap(); db.commit(&commit); overlay.apply_pending(); assert_eq!(overlay.levels.len(), 0); @@ -1002,8 +980,8 @@ mod tests { assert!(overlay.revert_one().is_none()); let changeset1 = make_changeset(&[5, 6], &[2]); let changeset2 = make_changeset(&[7, 8], &[5, 3]); - db.commit(&overlay.insert::(&h1, 1, &H256::default(), changeset1).unwrap()); - db.commit(&overlay.insert::(&h2, 2, &h1, changeset2).unwrap()); + db.commit(&overlay.insert(&h1, 1, &H256::default(), changeset1).unwrap()); + db.commit(&overlay.insert(&h2, 2, &h1, changeset2).unwrap()); assert!(contains(&overlay, 7)); db.commit(&overlay.revert_one().unwrap()); assert_eq!(overlay.parents.len(), 1); @@ -1025,10 +1003,10 @@ mod tests { let changeset1 = make_changeset(&[5, 6], &[2]); let changeset2 = make_changeset(&[7, 8], &[5, 3]); let changeset3 = make_changeset(&[9], &[]); - overlay.insert::(&h1, 1, &H256::default(), changeset1).unwrap(); + overlay.insert(&h1, 1, &H256::default(), changeset1).unwrap(); assert!(contains(&overlay, 5)); - overlay.insert::(&h2_1, 2, &h1, changeset2).unwrap(); - overlay.insert::(&h2_2, 2, &h1, changeset3).unwrap(); + overlay.insert(&h2_1, 2, &h1, changeset2).unwrap(); + overlay.insert(&h2_2, 2, &h1, changeset3).unwrap(); assert!(contains(&overlay, 7)); assert!(contains(&overlay, 5)); assert!(contains(&overlay, 9)); @@ -1052,14 +1030,14 @@ mod tests { let (h_2, c_2) = (H256::random(), make_changeset(&[2], &[])); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - db.commit(&overlay.insert::(&h_1, 1, &H256::default(), c_1).unwrap()); - db.commit(&overlay.insert::(&h_2, 1, &H256::default(), c_2).unwrap()); + db.commit(&overlay.insert(&h_1, 1, &H256::default(), c_1).unwrap()); + db.commit(&overlay.insert(&h_2, 1, &H256::default(), c_2).unwrap()); overlay.apply_pending(); overlay.pin(&h_1); let mut commit = CommitSet::default(); - overlay.canonicalize::(&h_2, &mut commit).unwrap(); + overlay.canonicalize(&h_2, &mut commit).unwrap(); db.commit(&commit); overlay.apply_pending(); assert!(contains(&overlay, 1)); @@ -1082,15 +1060,15 @@ mod tests { let (h_3, c_3) = (H256::random(), make_changeset(&[], &[])); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - db.commit(&overlay.insert::(&h_1, 1, &H256::default(), c_1).unwrap()); - db.commit(&overlay.insert::(&h_2, 1, &H256::default(), c_2).unwrap()); - db.commit(&overlay.insert::(&h_3, 1, &H256::default(), c_3).unwrap()); + db.commit(&overlay.insert(&h_1, 1, &H256::default(), c_1).unwrap()); + db.commit(&overlay.insert(&h_2, 1, &H256::default(), c_2).unwrap()); + db.commit(&overlay.insert(&h_3, 1, &H256::default(), c_3).unwrap()); overlay.apply_pending(); overlay.pin(&h_1); let mut commit = CommitSet::default(); - overlay.canonicalize::(&h_3, &mut commit).unwrap(); + overlay.canonicalize(&h_3, &mut commit).unwrap(); db.commit(&commit); overlay.apply_pending(); // 1_2 should be discarded, 1_1 is pinned @@ -1112,15 +1090,15 @@ mod tests { let (h_21, c_21) = (H256::random(), make_changeset(&[], &[])); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - db.commit(&overlay.insert::(&h_11, 1, &H256::default(), c_11).unwrap()); - db.commit(&overlay.insert::(&h_12, 1, &H256::default(), c_12).unwrap()); - db.commit(&overlay.insert::(&h_21, 2, &h_11, c_21).unwrap()); + db.commit(&overlay.insert(&h_11, 1, &H256::default(), c_11).unwrap()); + db.commit(&overlay.insert(&h_12, 1, &H256::default(), c_12).unwrap()); + db.commit(&overlay.insert(&h_21, 2, &h_11, c_21).unwrap()); overlay.apply_pending(); overlay.pin(&h_21); let mut commit = CommitSet::default(); - overlay.canonicalize::(&h_12, &mut commit).unwrap(); + overlay.canonicalize(&h_12, &mut commit).unwrap(); db.commit(&commit); overlay.apply_pending(); // 1_1 and 2_1 should be both pinned @@ -1141,18 +1119,14 @@ mod tests { let h21 = H256::random(); let mut db = make_db(&[]); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - db.commit( - &overlay - .insert::(&root, 10, &H256::default(), make_changeset(&[], &[])) - .unwrap(), - ); - db.commit(&overlay.insert::(&h1, 11, &root, make_changeset(&[1], &[])).unwrap()); - db.commit(&overlay.insert::(&h2, 11, &root, make_changeset(&[2], &[])).unwrap()); - db.commit(&overlay.insert::(&h11, 12, &h1, make_changeset(&[11], &[])).unwrap()); - db.commit(&overlay.insert::(&h21, 12, &h2, make_changeset(&[21], &[])).unwrap()); + db.commit(&overlay.insert(&root, 10, &H256::default(), make_changeset(&[], &[])).unwrap()); + db.commit(&overlay.insert(&h1, 11, &root, make_changeset(&[1], &[])).unwrap()); + db.commit(&overlay.insert(&h2, 11, &root, make_changeset(&[2], &[])).unwrap()); + db.commit(&overlay.insert(&h11, 12, &h1, make_changeset(&[11], &[])).unwrap()); + db.commit(&overlay.insert(&h21, 12, &h2, make_changeset(&[21], &[])).unwrap()); let mut commit = CommitSet::default(); - overlay.canonicalize::(&root, &mut commit).unwrap(); - overlay.canonicalize::(&h2, &mut commit).unwrap(); // h11 should stay in the DB + overlay.canonicalize(&root, &mut commit).unwrap(); + overlay.canonicalize(&h2, &mut commit).unwrap(); // h11 should stay in the DB db.commit(&commit); overlay.apply_pending(); assert_eq!(overlay.levels.len(), 1); @@ -1166,7 +1140,7 @@ mod tests { assert!(contains(&overlay, 21)); let mut commit = CommitSet::default(); - overlay.canonicalize::(&h21, &mut commit).unwrap(); // h11 should stay in the DB + overlay.canonicalize(&h21, &mut commit).unwrap(); // h11 should stay in the DB db.commit(&commit); overlay.apply_pending(); assert!(!contains(&overlay, 21)); @@ -1183,25 +1157,21 @@ mod tests { let h21 = H256::random(); let mut db = make_db(&[]); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - db.commit( - &overlay - .insert::(&root, 10, &H256::default(), make_changeset(&[], &[])) - .unwrap(), - ); - db.commit(&overlay.insert::(&h1, 11, &root, make_changeset(&[1], &[])).unwrap()); - db.commit(&overlay.insert::(&h2, 11, &root, make_changeset(&[2], &[])).unwrap()); - db.commit(&overlay.insert::(&h11, 12, &h1, make_changeset(&[11], &[])).unwrap()); - db.commit(&overlay.insert::(&h21, 12, &h2, make_changeset(&[21], &[])).unwrap()); + db.commit(&overlay.insert(&root, 10, &H256::default(), make_changeset(&[], &[])).unwrap()); + db.commit(&overlay.insert(&h1, 11, &root, make_changeset(&[1], &[])).unwrap()); + db.commit(&overlay.insert(&h2, 11, &root, make_changeset(&[2], &[])).unwrap()); + db.commit(&overlay.insert(&h11, 12, &h1, make_changeset(&[11], &[])).unwrap()); + db.commit(&overlay.insert(&h21, 12, &h2, make_changeset(&[21], &[])).unwrap()); let mut commit = CommitSet::default(); - overlay.canonicalize::(&root, &mut commit).unwrap(); - overlay.canonicalize::(&h2, &mut commit).unwrap(); // h11 should stay in the DB + overlay.canonicalize(&root, &mut commit).unwrap(); + overlay.canonicalize(&h2, &mut commit).unwrap(); // h11 should stay in the DB db.commit(&commit); overlay.apply_pending(); // add another block at top level. It should reuse journal index 0 of previously discarded // block let h22 = H256::random(); - db.commit(&overlay.insert::(&h22, 12, &h2, make_changeset(&[22], &[])).unwrap()); + db.commit(&overlay.insert(&h22, 12, &h2, make_changeset(&[22], &[])).unwrap()); assert_eq!(overlay.levels[0].blocks[0].journal_index, 1); assert_eq!(overlay.levels[0].blocks[1].journal_index, 0); @@ -1221,15 +1191,11 @@ mod tests { let h21 = H256::random(); let mut db = make_db(&[]); let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - db.commit( - &overlay - .insert::(&root, 10, &H256::default(), make_changeset(&[], &[])) - .unwrap(), - ); - db.commit(&overlay.insert::(&h1, 11, &root, make_changeset(&[1], &[])).unwrap()); - db.commit(&overlay.insert::(&h2, 11, &root, make_changeset(&[2], &[])).unwrap()); - db.commit(&overlay.insert::(&h11, 12, &h1, make_changeset(&[11], &[])).unwrap()); - db.commit(&overlay.insert::(&h21, 12, &h2, make_changeset(&[21], &[])).unwrap()); + db.commit(&overlay.insert(&root, 10, &H256::default(), make_changeset(&[], &[])).unwrap()); + db.commit(&overlay.insert(&h1, 11, &root, make_changeset(&[1], &[])).unwrap()); + db.commit(&overlay.insert(&h2, 11, &root, make_changeset(&[2], &[])).unwrap()); + db.commit(&overlay.insert(&h11, 12, &h1, make_changeset(&[11], &[])).unwrap()); + db.commit(&overlay.insert(&h21, 12, &h2, make_changeset(&[21], &[])).unwrap()); assert!(overlay.remove(&h1).is_none()); assert!(overlay.remove(&h2).is_none()); assert_eq!(overlay.levels.len(), 3); From 99bc7b5ae6b6e0b44b9af53fc0b9852e4e1e28be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 May 2022 12:47:50 +0200 Subject: [PATCH 0772/1472] Bump pretty_assertions from 1.0.0 to 1.2.1 (#11360) Bumps [pretty_assertions](https://github.com/colin-kiegel/rust-pretty-assertions) from 1.0.0 to 1.2.1. - [Release notes](https://github.com/colin-kiegel/rust-pretty-assertions/releases) - [Changelog](https://github.com/colin-kiegel/rust-pretty-assertions/blob/main/CHANGELOG.md) - [Commits](https://github.com/colin-kiegel/rust-pretty-assertions/compare/v1.0.0...v1.2.1) --- updated-dependencies: - dependency-name: pretty_assertions 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 | 4 ++-- frame/support/Cargo.toml | 2 +- frame/support/test/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14d1a547a8073..1e75fc0af75e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7318,9 +7318,9 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.0.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0cfe1b2403f172ba0f234e500906ee0a3e493fb81092dac23ebefe129301cc" +checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" dependencies = [ "ansi_term", "ctor", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 712570696b9eb..4132b9f98ebca 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -39,7 +39,7 @@ k256 = { version = "0.10.4", default-features = false, features = ["ecdsa"] } [dev-dependencies] assert_matches = "1.3.0" -pretty_assertions = "1.0.0" +pretty_assertions = "1.2.1" frame-system = { version = "4.0.0-dev", path = "../system" } parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index f5f690a0468af..4aa0ff7d5a347 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -24,7 +24,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../../primit sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } trybuild = { version = "1.0.60", features = [ "diff" ] } -pretty_assertions = "1.0.0" +pretty_assertions = "1.2.1" rustversion = "1.0.6" frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } # The "std" feature for this pallet is never activated on purpose, in order to test construct_runtime error message diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 7ee9fe98877a6..58fa3be514e4c 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -32,7 +32,7 @@ sp-trie = { version = "6.0.0", default-features = false, path = "../trie" } [dev-dependencies] hex-literal = "0.3.4" -pretty_assertions = "1.0.0" +pretty_assertions = "1.2.1" rand = "0.7.2" sp-runtime = { version = "6.0.0", path = "../runtime" } From 98518a635beb13f006d66e8575eaed9c2a5a3398 Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Fri, 6 May 2022 15:39:03 +0300 Subject: [PATCH 0773/1472] update approval rules (#11368) --- .github/pr-custom-review.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml index 518faf15a6113..769ac1e110d33 100644 --- a/.github/pr-custom-review.yml +++ b/.github/pr-custom-review.yml @@ -6,11 +6,22 @@ action-review-team: ci rules: - name: Core developers check_type: changed_files - condition: .* + condition: + include: .* + # excluding files from 'CI team' rules + exclude: ^\.gitlab-ci\.yml|^scripts/ci/.*|^\.github/.* min_approvals: 2 teams: - core-devs + - name: CI team + check_type: changed_files + condition: + include: ^\.gitlab-ci\.yml|^scripts/ci/.*|^\.github/.* + min_approvals: 2 + teams: + - ci + prevent-review-request: teams: - core-devs From 015a46e08ecacbb7a2b62fb3081ae66f22da06e1 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 6 May 2022 14:55:15 +0200 Subject: [PATCH 0774/1472] Break the ref cycle (#11371) --- bin/node/cli/tests/running_the_node_and_interrupt.rs | 7 +++++++ client/consensus/babe/src/lib.rs | 8 ++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/bin/node/cli/tests/running_the_node_and_interrupt.rs b/bin/node/cli/tests/running_the_node_and_interrupt.rs index ecdb4d7671b01..35f0fc106613c 100644 --- a/bin/node/cli/tests/running_the_node_and_interrupt.rs +++ b/bin/node/cli/tests/running_the_node_and_interrupt.rs @@ -38,6 +38,7 @@ async fn running_the_node_works_and_can_be_interrupted() { Command::new(cargo_bin("substrate")) .args(&["--dev", "-d"]) .arg(base_path.path()) + .arg("--db=paritydb") .arg("--no-hardware-benchmarks") .spawn() .unwrap(), @@ -52,6 +53,12 @@ async fn running_the_node_works_and_can_be_interrupted() { "the process must exit gracefully after signal {}", signal, ); + // Check if the database was closed gracefully. If it was not, + // there may exist a ref cycle that prevents the Client from being dropped properly. + // + // parity-db only writes the stats file on clean shutdown. + let stats_file = base_path.path().join("chains/dev/paritydb/full/stats.txt"); + assert!(std::path::Path::exists(&stats_file)); } run_command_and_kill(SIGINT).await; diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 490fdfb174311..683df9ddacd62 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1783,9 +1783,13 @@ where // startup rather than waiting until importing the next epoch change block. prune_finalized(client.clone(), &mut epoch_changes.shared_data())?; - let client_clone = client.clone(); + let client_weak = Arc::downgrade(&client); let on_finality = move |summary: &FinalityNotification| { - aux_storage_cleanup(client_clone.as_ref(), summary) + if let Some(client) = client_weak.upgrade() { + aux_storage_cleanup(client.as_ref(), summary) + } else { + Default::default() + } }; client.register_finality_action(Box::new(on_finality)); From a0567535f94558aef8d7e8190f7534afd0d87d1e Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 6 May 2022 14:21:54 +0100 Subject: [PATCH 0775/1472] Rename nomination pools pallet id (#11361) --- bin/node/runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 660ba7ab86229..db4539b82f31e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -707,7 +707,7 @@ impl pallet_bags_list::Config for Runtime { parameter_types! { pub const PostUnbondPoolsWindow: u32 = 4; - pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/npols"); + pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/nopls"); } use sp_runtime::traits::Convert; From f7df8fba26794b48ef5057bca577da0f72a1b8c7 Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 6 May 2022 15:22:39 +0200 Subject: [PATCH 0776/1472] Parity-db `Change` missing implementation. (#11049) * support for release as in kvdb (only if no rc). * Start impl * minimal implementation for paritydb rc * Update client/db/src/parity_db.rs Co-authored-by: Arkadiy Paronyan * Update client/db/src/parity_db.rs Co-authored-by: Arkadiy Paronyan * Update client/db/src/parity_db.rs Co-authored-by: Arkadiy Paronyan * Commit not panicking in DbAdapter * errors from string * update parity db version Co-authored-by: Arkadiy Paronyan --- Cargo.lock | 4 +-- client/db/Cargo.toml | 2 +- client/db/src/parity_db.rs | 54 +++++++++++++++++++++++++++++++++----- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e75fc0af75e5..907c917d723a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6832,9 +6832,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e73cd0b0a78045276b19eaae8eaaa20e44a1da9a0217ff934a810d9492ae701" +checksum = "55a7901b85874402471e131de3332dde0e51f38432c69a3853627c8e25433048" dependencies = [ "blake2-rfc", "crc32fast", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 3c20cec72c695..e548887e56fe2 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -22,7 +22,7 @@ kvdb-memorydb = "0.11.0" kvdb-rocksdb = { version = "0.15.2", optional = true } linked-hash-map = "0.5.4" log = "0.4.16" -parity-db = { version = "0.3.12", optional = true } +parity-db = { version = "0.3.13", optional = true } parking_lot = "0.12.0" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } diff --git a/client/db/src/parity_db.rs b/client/db/src/parity_db.rs index f88e6f2e91678..7ce1d6a683401 100644 --- a/client/db/src/parity_db.rs +++ b/client/db/src/parity_db.rs @@ -86,15 +86,57 @@ pub fn open>( Ok(std::sync::Arc::new(DbAdapter(db))) } +fn ref_counted_column(col: u32) -> bool { + col == columns::TRANSACTION || col == columns::STATE +} + impl> Database for DbAdapter { fn commit(&self, transaction: Transaction) -> Result<(), DatabaseError> { - handle_err(self.0.commit(transaction.0.into_iter().map(|change| match change { - Change::Set(col, key, value) => (col as u8, key, Some(value)), - Change::Remove(col, key) => (col as u8, key, None), - _ => unimplemented!(), - }))); + let mut not_ref_counted_column = Vec::new(); + let result = self.0.commit(transaction.0.into_iter().filter_map(|change| { + Some(match change { + Change::Set(col, key, value) => (col as u8, key, Some(value)), + Change::Remove(col, key) => (col as u8, key, None), + Change::Store(col, key, value) => + if ref_counted_column(col) { + (col as u8, key.as_ref().to_vec(), Some(value)) + } else { + if !not_ref_counted_column.contains(&col) { + not_ref_counted_column.push(col); + } + return None + }, + Change::Reference(col, key) => + if ref_counted_column(col) { + // FIXME accessing value is not strictly needed, optimize this in parity-db. + let value = >::get(self, col, key.as_ref()); + (col as u8, key.as_ref().to_vec(), value) + } else { + if !not_ref_counted_column.contains(&col) { + not_ref_counted_column.push(col); + } + return None + }, + Change::Release(col, key) => + if ref_counted_column(col) { + (col as u8, key.as_ref().to_vec(), None) + } else { + if !not_ref_counted_column.contains(&col) { + not_ref_counted_column.push(col); + } + return None + }, + }) + })); + + if not_ref_counted_column.len() > 0 { + return Err(DatabaseError(Box::new(parity_db::Error::InvalidInput(format!( + "Ref counted operation on non ref counted columns {:?}", + not_ref_counted_column + ))))) + } - Ok(()) + result.map_err(|e| DatabaseError(Box::new(e))) } fn get(&self, col: ColumnId, key: &[u8]) -> Option> { From f9f0b08273c41beabf5ad5f3d6262d96c947b8d9 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 6 May 2022 14:25:07 +0100 Subject: [PATCH 0777/1472] allow defensive operations to take a proof (#11353) * allow defensive operations to take a proof * Update frame/support/src/traits/misc.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/bags-list/src/list/mod.rs Co-authored-by: Keith Yeung * Update frame/support/src/traits/misc.rs Co-authored-by: Keith Yeung * Update frame/support/src/traits/misc.rs Co-authored-by: Keith Yeung * Fix build * fix build again * fmt Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Keith Yeung --- frame/bags-list/src/list/mod.rs | 4 ++-- frame/staking/src/slashing.rs | 6 +++--- frame/support/src/traits/misc.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index f93bfca1081e9..2e65c3be25b24 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -443,8 +443,8 @@ impl, I: 'static> List { // remove the heavier node from this list. Note that this removes the node from storage and // decrements the node counter. - // defensive: both nodes have been checked to exist. - let _ = Self::remove(&heavier_id).defensive(); + let _ = + Self::remove(&heavier_id).defensive_proof("both nodes have been checked to exist; qed"); // re-fetch `lighter_node` from storage since it may have been updated when `heavier_node` // was removed. diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 0d55eb7fe0ddb..25954a3699b31 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -56,7 +56,7 @@ use crate::{ use codec::{Decode, Encode}; use frame_support::{ ensure, - traits::{Currency, Get, Imbalance, OnUnbalanced}, + traits::{Currency, Defensive, Get, Imbalance, OnUnbalanced}, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -600,8 +600,8 @@ pub fn do_slash( slashed_imbalance: &mut NegativeImbalanceOf, slash_era: EraIndex, ) { - let controller = match >::bonded(stash) { - None => return, // defensive: should always exist. + let controller = match >::bonded(stash).defensive() { + None => return, Some(c) => c, }; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index b67eac2fbe7bc..03420f64dd55b 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -50,6 +50,16 @@ macro_rules! defensive { $error ); debug_assert!(false, "{}: {:?}", $crate::traits::DEFENSIVE_OP_INTERNAL_ERROR, $error); + }; + ($error:tt, $proof:tt) => { + frame_support::log::error!( + target: "runtime", + "{}: {:?}: {:?}", + $crate::traits::DEFENSIVE_OP_PUBLIC_ERROR, + $error, + $proof, + ); + debug_assert!(false, "{}: {:?}: {:?}", $crate::traits::DEFENSIVE_OP_INTERNAL_ERROR, $error, $proof); } } @@ -102,6 +112,10 @@ pub trait Defensive { /// } /// ``` fn defensive(self) -> Self; + + /// Same as [`Defensive::defensive`], but it takes a proof as input, and displays it if the + /// defensive operation has been triggered. + fn defensive_proof(self, proof: &'static str) -> Self; } /// Subset of methods similar to [`Defensive`] that can only work for a `Result`. @@ -184,6 +198,13 @@ impl Defensive for Option { }, } } + + fn defensive_proof(self, proof: &'static str) -> Self { + if self.is_none() { + defensive!(proof); + } + self + } } impl Defensive for Result { @@ -229,6 +250,16 @@ impl Defensive for Result { }, } } + + fn defensive_proof(self, proof: &'static str) -> Self { + match self { + Ok(inner) => Ok(inner), + Err(e) => { + defensive!(e, proof); + Err(e) + }, + } + } } impl DefensiveResult for Result { From 6e5ee5155aaf8f9c25a1a2292f73a041ab501ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 9 May 2022 11:25:14 +0200 Subject: [PATCH 0778/1472] contracts: Prevent PoV attack vector with minimal viable solution (#11372) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add ContractAccessWeight * Apply suggestions from code review Co-authored-by: Michael Müller Co-authored-by: Michael Müller --- bin/node/runtime/src/lib.rs | 8 +++-- frame/contracts/src/lib.rs | 50 ++++++++++++++++++++++++-- frame/contracts/src/tests.rs | 5 +-- frame/contracts/src/wasm/code_cache.rs | 10 ++++-- 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index db4539b82f31e..fee288cb2b7f8 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1059,8 +1059,11 @@ parameter_types! { pub const DepositPerByte: Balance = deposit(0, 1); pub const MaxValueSize: u32 = 16 * 1024; // The lazy deletion runs inside on_initialize. - pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO * - RuntimeBlockWeights::get().max_block; + pub DeletionWeightLimit: Weight = RuntimeBlockWeights::get() + .per_class + .get(DispatchClass::Normal) + .max_total + .unwrap_or(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() / ( @@ -1093,6 +1096,7 @@ impl pallet_contracts::Config for Runtime { type DeletionWeightLimit = DeletionWeightLimit; type Schedule = Schedule; type AddressGenerator = pallet_contracts::DefaultAddressGenerator; + type ContractAccessWeight = pallet_contracts::DefaultContractAccessWeight; } impl pallet_sudo::Config for Runtime { diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 4edf43a672152..0ae326f6c1e8f 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -115,9 +115,9 @@ use frame_support::{ dispatch::Dispatchable, ensure, traits::{Contains, Currency, Get, Randomness, ReservableCurrency, StorageVersion, Time}, - weights::{GetDispatchInfo, Pays, PostDispatchInfo, Weight}, + weights::{DispatchClass, GetDispatchInfo, Pays, PostDispatchInfo, Weight}, }; -use frame_system::Pallet as System; +use frame_system::{limits::BlockWeights, Pallet as System}; use pallet_contracts_primitives::{ Code, CodeUploadResult, CodeUploadReturnValue, ContractAccessError, ContractExecResult, ContractInstantiateResult, ExecReturnValue, GetStorageResult, InstantiateReturnValue, @@ -126,7 +126,7 @@ use pallet_contracts_primitives::{ use scale_info::TypeInfo; use sp_core::{crypto::UncheckedFrom, Bytes}; use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup}; -use sp_std::{fmt::Debug, prelude::*}; +use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; type CodeHash = ::Hash; type TrieId = Vec; @@ -193,6 +193,29 @@ where } } +/// A conservative implementation to be used for [`pallet::Config::ContractAccessWeight`]. +/// +/// This derives the weight from the [`BlockWeights`] passed as `B` and the `maxPovSize` passed +/// as `P`. The default value for `P` is the `maxPovSize` used by Polkadot and Kusama. +/// +/// It simply charges from the weight meter pro rata: If loading the contract code would consume +/// 50% of the max storage proof then this charges 50% of the max block weight. +pub struct DefaultContractAccessWeight, const P: u32 = 5_242_880>( + PhantomData, +); + +impl, const P: u32> Get for DefaultContractAccessWeight { + fn get() -> Weight { + let block_weights = B::get(); + block_weights + .per_class + .get(DispatchClass::Normal) + .max_total + .unwrap_or(block_weights.max_block) / + Weight::from(P) + } +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -297,6 +320,27 @@ pub mod pallet { #[pallet::constant] type DepositPerByte: Get>; + /// The weight per byte of code that is charged when loading a contract from storage. + /// + /// Currently, FRAME only charges fees for computation incurred but not for PoV + /// consumption caused for storage access. This is usually not exploitable because + /// accessing storage carries some substantial weight costs, too. However in case + /// of contract code very much PoV consumption can be caused while consuming very little + /// computation. This could be used to keep the chain busy without paying the + /// proper fee for it. Until this is resolved we charge from the weight meter for + /// contract access. + /// + /// For more information check out: + /// + /// [`DefaultContractAccessWeight`] is a safe default to be used for polkadot or kusama + /// parachains. + /// + /// # Note + /// + /// This is only relevant for parachains. Set to zero in case of a standalone chain. + #[pallet::constant] + type ContractAccessWeight: Get; + /// The amount of balance a caller has to pay for each storage item. /// /// # Note diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index eaec4df698e5a..407e1e999dde1 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -24,8 +24,8 @@ use crate::{ storage::Storage, wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, - BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, Error, Pallet, - Schedule, + BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, + DefaultContractAccessWeight, Error, Pallet, Schedule, }; use assert_matches::assert_matches; use codec::Encode; @@ -287,6 +287,7 @@ impl Config for Test { type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; type AddressGenerator = DefaultAddressGenerator; + type ContractAccessWeight = DefaultContractAccessWeight; } pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index ca91fa3131474..b194c283e90cd 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -38,7 +38,7 @@ use crate::{ use frame_support::{ dispatch::{DispatchError, DispatchResult}, ensure, - traits::ReservableCurrency, + traits::{Get, ReservableCurrency}, }; use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::BadOrigin; @@ -216,8 +216,12 @@ impl Token for CodeToken { // size of the contract. match *self { Reinstrument(len) => T::WeightInfo::reinstrument(len), - Load(len) => T::WeightInfo::call_with_code_per_byte(len) - .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)), + Load(len) => { + let computation = T::WeightInfo::call_with_code_per_byte(len) + .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)); + let bandwith = T::ContractAccessWeight::get().saturating_mul(len.into()); + computation.max(bandwith) + }, } } } From 8a0dcafadcccdd6230931d3f0fec4cf95cbe4af3 Mon Sep 17 00:00:00 2001 From: Alexander Gryaznov Date: Tue, 10 May 2022 11:07:13 +0300 Subject: [PATCH 0779/1472] stabilize `seal_contains_storage` (`seal0`) and `seal_set_storage` (`seal1`) (#11378) --- frame/contracts/src/benchmarking/mod.rs | 10 +++++----- frame/contracts/src/wasm/mod.rs | 6 ++---- frame/contracts/src/wasm/runtime.rs | 6 ++---- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 6411bcb2b589a..194f97f8c878d 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -896,7 +896,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal1", name: "seal_set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -942,7 +942,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal1", name: "seal_set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -988,7 +988,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal1", name: "seal_set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -1233,7 +1233,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "seal_contains_storage", params: vec![ValueType::I32], return_type: Some(ValueType::I32), @@ -1278,7 +1278,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "seal_contains_storage", params: vec![ValueType::I32], return_type: Some(ValueType::I32), diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 7257fbea6336a..d710cad199f93 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -819,13 +819,12 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn contains_storage_works() { const CODE: &str = r#" (module (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "__unstable__" "seal_contains_storage" (func $seal_contains_storage (param i32) (result i32))) + (import "seal0" "seal_contains_storage" (func $seal_contains_storage (param i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 4) size of input buffer (32 byte as we copy the key here) @@ -2163,13 +2162,12 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn set_storage_works() { const CODE: &str = r#" (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "__unstable__" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32) (result i32))) + (import "seal1" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; 0x1000 = 4k in little endian diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index a6f42ba64a49c..11dfc77616e69 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -185,7 +185,6 @@ pub enum RuntimeCosts { /// Weight of calling `seal_clear_storage` per cleared byte. ClearStorage(u32), /// Weight of calling `seal_contains_storage` per byte of the checked item. - #[cfg(feature = "unstable-interface")] ContainsStorage(u32), /// Weight of calling `seal_get_storage` with the specified size in storage. GetStorage(u32), @@ -269,7 +268,6 @@ impl RuntimeCosts { ClearStorage(len) => s .clear_storage .saturating_add(s.clear_storage_per_byte.saturating_mul(len.into())), - #[cfg(feature = "unstable-interface")] ContainsStorage(len) => s .contains_storage .saturating_add(s.contains_storage_per_byte.saturating_mul(len.into())), @@ -889,7 +887,7 @@ define_env!(Env, , // // Returns the size of the pre-existing value at the specified key if any. Otherwise // `SENTINEL` is returned as a sentinel value. - [__unstable__] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) -> u32 => { + [seal1] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) -> u32 => { ctx.set_storage(key_ptr, value_ptr, value_len) }, @@ -951,7 +949,7 @@ define_env!(Env, , // // Returns the size of the pre-existing value at the specified key if any. Otherwise // `SENTINEL` is returned as a sentinel value. - [__unstable__] seal_contains_storage(ctx, key_ptr: u32) -> u32 => { + [seal0] seal_contains_storage(ctx, key_ptr: u32) -> u32 => { let charged = ctx.charge_gas(RuntimeCosts::ContainsStorage(ctx.ext.max_value_size()))?; let mut key: StorageKey = [0; 32]; ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; From e0ccd008fe8bfaf29357ea87561e60f3baaae08c Mon Sep 17 00:00:00 2001 From: David Date: Tue, 10 May 2022 10:52:19 +0200 Subject: [PATCH 0780/1472] jsonrpsee integration (#8783) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add tokio * No need to map CallError to CallError * jsonrpsee proc macros (#9673) * port error types to `JsonRpseeError` * migrate chain module to proc macro api * make it compile with proc macros * update branch * update branch * update to jsonrpsee master * port system rpc * port state rpc * port childstate & offchain * frame system rpc * frame transaction payment * bring back CORS hack to work with polkadot UI * port babe rpc * port manual seal rpc * port frame mmr rpc * port frame contracts rpc * port finality grandpa rpc * port sync state rpc * resolve a few TODO + no jsonrpc deps * Update bin/node/rpc-client/src/main.rs * Update bin/node/rpc-client/src/main.rs * Update bin/node/rpc-client/src/main.rs * Update bin/node/rpc-client/src/main.rs * Port over system_ rpc tests * Make it compile * Use prost 0.8 * Use prost 0.8 * Make it compile * Ignore more failing tests * Comment out WIP tests * fix nit in frame system api * Update lockfile * No more juggling tokio versions * No more wait_for_stop ? * Remove browser-testing * Arguments must be arrays * Use same argument names * Resolve todo: no wait_for_stop for WS server Add todo: is parse_rpc_result used? Cleanup imports * fmt * log * One test passes * update jsonrpsee * update jsonrpsee * cleanup rpc-servers crate * jsonrpsee: add host and origin filtering (#9787) * add access control in the jsonrpsee servers * use master * fix nits * rpc runtime_version safe * fix nits * fix grumbles * remove unused files * resolve some todos * jsonrpsee more cleanup (#9803) * more cleanup * resolve TODOs * fix some unwraps * remove type hints * update jsonrpsee * downgrade zeroize * pin jsonrpsee rev * remove unwrap nit * Comment out more tests that aren't ported * Comment out more tests * Fix tests after merge * Subscription test * Invalid nonce test * Pending exts * WIP removeExtrinsic test * Test remove_extrinsic * Make state test: should_return_storage work * Uncomment/fix the other non-subscription related state tests * test: author_insertKey * test: author_rotateKeys * Get rest of state tests passing * asyncify a little more * Add todo to note #msg change * Crashing test for has_session_keys * Fix error conversion to avoid stack overflows Port author_hasSessionKeys test fmt * test author_hasKey * Add two missing tests Add a check on the return type Add todos for James's concerns * RPC tests for state, author and system (#9859) * Fix test runner * Impl Default for SubscriptionTaskExecutor * Keep the minimul amount of code needed to compile tests * Re-instate `RpcSession` (for now) * cleanup * Port over RPC tests * Add tokio * No need to map CallError to CallError * Port over system_ rpc tests * Make it compile * Use prost 0.8 * Use prost 0.8 * Make it compile * Ignore more failing tests * Comment out WIP tests * Update lockfile * No more juggling tokio versions * No more wait_for_stop ? * Remove browser-testing * Arguments must be arrays * Use same argument names * Resolve todo: no wait_for_stop for WS server Add todo: is parse_rpc_result used? Cleanup imports * fmt * log * One test passes * Comment out more tests that aren't ported * Comment out more tests * Fix tests after merge * Subscription test * Invalid nonce test * Pending exts * WIP removeExtrinsic test * Test remove_extrinsic * Make state test: should_return_storage work * Uncomment/fix the other non-subscription related state tests * test: author_insertKey * test: author_rotateKeys * Get rest of state tests passing * asyncify a little more * Add todo to note #msg change * Crashing test for has_session_keys * Fix error conversion to avoid stack overflows Port author_hasSessionKeys test fmt * test author_hasKey * Add two missing tests Add a check on the return type Add todos for James's concerns * offchain rpc tests * Address todos * fmt Co-authored-by: James Wilson * fix drop in state test * update jsonrpsee * fix ignored system test * fix chain tests * remove some boiler plate * Port BEEFY RPC (#9883) * Merge master * Port beefy RPC (ty @niklas!) * trivial changes left over from merge * Remove unused code * Update jsonrpsee * fix build * make tests compile again * beefy update jsonrpsee * fix: respect rpc methods policy * update cargo.lock * update jsonrpsee * update jsonrpsee * downgrade error logs * update jsonrpsee * Fix typo * remove unused file * Better name * Port Babe RPC tests * Put docs back * Resolve todo * Port tests for System RPCs * Resolve todo * fix build * Updated jsonrpsee to current master * fix: port finality grandpa rpc tests * Move .into() outside of the match * more review grumbles * jsonrpsee: add `rpc handlers` back (#10245) * add back RpcHandlers * cargo fmt * fix docs * fix grumble: remove needless alloc * resolve TODO * fmt * Fix typo * grumble: Use constants based on BASE_ERROR * grumble: DRY whitelisted listening addresses grumble: s/JSONRPC/JSON-RPC/ * cleanup * grumbles: Making readers aware of the possibility of gaps * review grumbles * grumbles * remove notes from niklasad1 * Update `jsonrpsee` * fix: jsonrpsee features * jsonrpsee: fallback to random port in case the specified port failed (#10304) * jsonrpsee: fallback to random port * better comment * Update client/rpc-servers/src/lib.rs Co-authored-by: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com> * Update client/rpc-servers/src/lib.rs Co-authored-by: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com> * address grumbles * cargo fmt * addrs already slice Co-authored-by: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com> * Update jsonrpsee to 092081a0a2b8904c6ebd2cd99e16c7bc13ffc3ae * lockfile * update jsonrpsee * fix warning * Don't fetch jsonrpsee from crates * make tests compile again * fix rpc tests * remove unused deps * update tokio * fix rpc tests again * fix: test runner `HttpServerBuilder::builder` fails unless it's called within tokio runtime * cargo fmt * grumbles: fix subscription aliases * make clippy happy * update remaining subscriptions alias * cleanup * cleanup * fix chain subscription: less boiler plate (#10285) * fix chain subscription: less boiler plate * fix bad merge * cargo fmt * Switch to jsonrpsee 0.5 * fix build * add missing features * fix nit: remove needless Box::pin * Integrate jsonrpsee metrics (#10395) * draft metrics impl * Use latest api * Add missing file * Http server metrics * cleanup * bump jsonrpsee * Remove `ServerMetrics` and use a single middleware for both connection counting (aka sessions) and call metrics. * fix build * remove needless Arc::clone * Update to jsonrpsee 0.6 * lolz * fix metrics * Revert "lolz" This reverts commit eed6c6a56e78d8e307b4950f4c52a1c3a2322ba1. * fix: in-memory rpc support subscriptions * commit Cargo.lock * Update tests to 0.7 * fix TODOs * ws server: generate subscriptionIDs as Strings Some libraries seems to expect the subscription IDs to be Strings, let's not break this in this PR. * Increase timeout * Port over tests * cleanup * Using error codes from the spec * fix clippy * cargo fmt * update jsonrpsee * fix nits * fix: rpc_query * enable custom subid gen through spawn_tasks * remove unsed deps * unify tokio deps * Revert "enable custom subid gen through spawn_tasks" This reverts commit 5c5eb70328fe39d154fdb55c56e637b4548cf470. * fix bad merge of `test-utils` * fix more nits * downgrade wasm-instrument to 0.1.0 * [jsonrpsee]: enable custom RPC subscription ID generatation (#10731) * enable custom subid gen through spawn_tasks * fix nits * Update client/service/src/builder.rs Co-authored-by: David * add Poc; needs jsonrpsee pr * update jsonrpsee * add re-exports * add docs Co-authored-by: David * cargo fmt * fmt * port RPC-API dev * Remove unused file * fix nit: remove async trait * fix doc links * fix merge nit: remove jsonrpc deps * kill namespace on rpc apis * companion for jsonrpsee v0.10 (#11158) * companion for jsonrpsee v0.10 * update versions v0.10.0 * add some fixes * spelling * fix spaces Co-authored-by: Niklas Adolfsson * send error before subs are closed * fix unsubscribe method names: chain * fix tests * jsonrpc server: print binded local address * grumbles: kill SubscriptionTaskExecutor * Update client/sync-state-rpc/src/lib.rs Co-authored-by: Bastian Köcher * Update client/rpc/src/chain/chain_full.rs Co-authored-by: Bastian Köcher * Update client/rpc/src/chain/chain_full.rs Co-authored-by: Bastian Köcher * sync-state-rpc: kill anyhow * no more anyhow * remove todo * jsonrpsee: fix bad params in subscriptions. (#11251) * update jsonrpsee * fix error responses * revert error codes * dont do weird stuff in drop impl * rpc servers: remove needless clone * Remove silly constants * chore: update jsonrpsee v0.12 * commit Cargo.lock * deps: downgrade git2 * feat: CLI flag max subscriptions per connection * metrics: use old logging format * fix: read WS address from substrate output (#11379) Co-authored-by: Niklas Adolfsson Co-authored-by: James Wilson Co-authored-by: Maciej Hirsz Co-authored-by: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com> Co-authored-by: Bastian Köcher --- Cargo.lock | 1701 +++++------------ bin/node-template/node/Cargo.toml | 2 +- bin/node-template/node/src/rpc.rs | 23 +- bin/node-template/node/src/service.rs | 5 +- bin/node/cli/Cargo.toml | 1 + bin/node/cli/benches/block_production.rs | 4 + bin/node/cli/benches/transaction_pool.rs | 4 + bin/node/cli/src/service.rs | 10 +- bin/node/cli/tests/common.rs | 52 +- .../tests/running_the_node_and_interrupt.rs | 19 +- bin/node/cli/tests/temp_base_path_works.rs | 10 +- bin/node/rpc/Cargo.toml | 2 +- bin/node/rpc/src/lib.rs | 92 +- client/beefy/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 6 +- client/beefy/rpc/src/lib.rs | 308 ++- client/cli/src/commands/run_cmd.rs | 18 +- client/cli/src/config.rs | 14 + client/consensus/babe/rpc/Cargo.toml | 5 +- client/consensus/babe/rpc/src/lib.rs | 204 +- client/consensus/manual-seal/Cargo.toml | 4 +- client/consensus/manual-seal/src/error.rs | 34 +- client/consensus/manual-seal/src/rpc.rs | 83 +- client/finality-grandpa/rpc/Cargo.toml | 6 +- client/finality-grandpa/rpc/src/error.rs | 17 +- client/finality-grandpa/rpc/src/lib.rs | 345 ++-- client/rpc-api/Cargo.toml | 5 +- client/rpc-api/src/author/error.rs | 180 +- client/rpc-api/src/author/mod.rs | 70 +- client/rpc-api/src/chain/error.rs | 25 +- client/rpc-api/src/chain/mod.rs | 111 +- client/rpc-api/src/child_state/mod.rs | 59 +- client/rpc-api/src/dev/error.rs | 42 +- client/rpc-api/src/dev/mod.rs | 9 +- client/rpc-api/src/errors.rs | 28 - client/rpc-api/src/helpers.rs | 41 - client/rpc-api/src/lib.rs | 8 +- client/rpc-api/src/metadata.rs | 60 - client/rpc-api/src/offchain/error.rs | 20 +- client/rpc-api/src/offchain/mod.rs | 17 +- client/rpc-api/src/policy.rs | 24 +- client/rpc-api/src/state/error.rs | 34 +- client/rpc-api/src/state/mod.rs | 155 +- client/rpc-api/src/system/error.rs | 33 +- client/rpc-api/src/system/mod.rs | 95 +- client/rpc-servers/Cargo.toml | 6 +- client/rpc-servers/src/lib.rs | 340 ++-- client/rpc-servers/src/middleware.rs | 227 +-- client/rpc/Cargo.toml | 10 +- client/rpc/src/author/mod.rs | 133 +- client/rpc/src/author/tests.rs | 380 ++-- client/rpc/src/chain/chain_full.rs | 114 +- client/rpc/src/chain/mod.rs | 221 +-- client/rpc/src/chain/tests.rs | 261 ++- client/rpc/src/dev/mod.rs | 16 +- client/rpc/src/dev/tests.rs | 35 +- client/rpc/src/lib.rs | 37 +- client/rpc/src/offchain/mod.rs | 17 +- client/rpc/src/offchain/tests.rs | 9 +- client/rpc/src/state/mod.rs | 385 ++-- client/rpc/src/state/state_full.rs | 417 ++-- client/rpc/src/state/tests.rs | 450 ++--- client/rpc/src/system/mod.rs | 141 +- client/rpc/src/system/tests.rs | 250 ++- client/rpc/src/testing.rs | 33 +- client/service/Cargo.toml | 3 +- client/service/src/builder.rs | 190 +- client/service/src/config.rs | 12 + client/service/src/lib.rs | 274 ++- client/service/test/src/lib.rs | 4 + client/sync-state-rpc/Cargo.toml | 4 +- client/sync-state-rpc/src/lib.rs | 60 +- client/tracing/src/block/mod.rs | 2 +- client/transaction-pool/api/src/error.rs | 4 +- client/transaction-pool/api/src/lib.rs | 11 +- frame/bags-list/remote-tests/Cargo.toml | 1 - frame/contracts/rpc/Cargo.toml | 4 +- frame/contracts/rpc/src/lib.rs | 126 +- frame/merkle-mountain-range/rpc/Cargo.toml | 4 +- frame/merkle-mountain-range/rpc/src/lib.rs | 99 +- frame/state-trie-migration/Cargo.toml | 2 +- frame/transaction-payment/rpc/Cargo.toml | 4 +- frame/transaction-payment/rpc/src/lib.rs | 115 +- test-utils/client/src/lib.rs | 106 +- test-utils/runtime/src/lib.rs | 13 + utils/frame/remote-externalities/Cargo.toml | 2 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 4 +- .../rpc/state-trie-migration-rpc/src/lib.rs | 33 +- utils/frame/rpc/support/Cargo.toml | 3 +- utils/frame/rpc/support/src/lib.rs | 56 +- utils/frame/rpc/system/Cargo.toml | 7 +- utils/frame/rpc/system/src/lib.rs | 229 ++- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 93 files changed, 3781 insertions(+), 5062 deletions(-) delete mode 100644 client/rpc-api/src/errors.rs delete mode 100644 client/rpc-api/src/helpers.rs delete mode 100644 client/rpc-api/src/metadata.rs diff --git a/Cargo.lock b/Cargo.lock index 907c917d723a7..928be6b18fc15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,7 +70,7 @@ checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ "getrandom 0.2.3", "once_cell", - "version_check 0.9.2", + "version_check", ] [[package]] @@ -88,7 +88,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -225,21 +225,21 @@ dependencies = [ "concurrent-queue", "futures-lite", "libc", - "log 0.4.16", + "log", "once_cell", "parking", "polling", "slab", "socket2 0.4.4", "waker-fn", - "winapi 0.3.9", + "winapi", ] [[package]] name = "async-lock" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb" +checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" dependencies = [ "event-listener", ] @@ -255,9 +255,9 @@ dependencies = [ [[package]] name = "async-process" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83137067e3a2a6a06d67168e49e68a0957d215410473a740cea95a2425c0b7c6" +checksum = "cf2c06e30a24e8c78a3987d07f0930edf76ef35e027e7bdb063fccafdad1f60c" dependencies = [ "async-io", "blocking", @@ -267,7 +267,7 @@ dependencies = [ "libc", "once_cell", "signal-hook", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -282,14 +282,14 @@ dependencies = [ "async-io", "async-lock", "async-process", - "crossbeam-utils 0.8.5", + "crossbeam-utils", "futures-channel", "futures-core", "futures-io", "futures-lite", "gloo-timers", "kv-log-macro", - "log 0.4.16", + "log", "memchr", "num_cpus", "once_cell", @@ -358,7 +358,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0de5164e5edbf51c45fb8c2d9664ae1c095cce1b265ecf7569093c0d66ef690" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-sink", "futures-util", "memchr", @@ -388,7 +388,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -436,25 +436,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" -[[package]] -name = "base64" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -dependencies = [ - "byteorder", - "safemem", -] - -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -dependencies = [ - "byteorder", -] - [[package]] name = "base64" version = "0.13.0" @@ -476,10 +457,10 @@ version = "4.0.0-dev" dependencies = [ "beefy-primitives", "fnv", - "futures 0.3.21", + "futures", "futures-timer", "hex", - "log 0.4.16", + "log", "parity-scale-codec", "parking_lot 0.12.0", "sc-chain-spec", @@ -519,12 +500,9 @@ version = "4.0.0-dev" dependencies = [ "beefy-gadget", "beefy-primitives", - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "jsonrpc-pubsub", - "log 0.4.16", + "futures", + "jsonrpsee", + "log", "parity-scale-codec", "parking_lot 0.12.0", "sc-rpc", @@ -535,6 +513,7 @@ dependencies = [ "sp-runtime", "substrate-test-runtime-client", "thiserror", + "tokio", ] [[package]] @@ -544,7 +523,7 @@ dependencies = [ "env_logger 0.9.0", "hex", "hex-literal", - "log 0.4.16", + "log", "tiny-keccak", ] @@ -814,16 +793,6 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "iovec", -] - [[package]] name = "bytes" version = "1.1.0" @@ -966,7 +935,7 @@ dependencies = [ "num-integer", "num-traits", "time", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1185,9 +1154,9 @@ dependencies = [ "cranelift-codegen-shared 0.76.0", "cranelift-entity 0.76.0", "gimli 0.25.0", - "log 0.4.16", + "log", "regalloc 0.0.31", - "smallvec 1.8.0", + "smallvec", "target-lexicon", ] @@ -1202,9 +1171,9 @@ dependencies = [ "cranelift-codegen-shared 0.82.3", "cranelift-entity 0.82.3", "gimli 0.26.1", - "log 0.4.16", + "log", "regalloc 0.0.34", - "smallvec 1.8.0", + "smallvec", "target-lexicon", ] @@ -1261,8 +1230,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279afcc0d3e651b773f94837c3d581177b348c8d69e928104b2e9fccb226f921" dependencies = [ "cranelift-codegen 0.76.0", - "log 0.4.16", - "smallvec 1.8.0", + "log", + "smallvec", "target-lexicon", ] @@ -1273,8 +1242,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" dependencies = [ "cranelift-codegen 0.82.3", - "log 0.4.16", - "smallvec 1.8.0", + "log", + "smallvec", "target-lexicon", ] @@ -1299,8 +1268,8 @@ dependencies = [ "cranelift-entity 0.82.3", "cranelift-frontend 0.82.3", "itertools", - "log 0.4.16", - "smallvec 1.8.0", + "log", + "smallvec", "wasmparser 0.83.0", "wasmtime-types", ] @@ -1325,7 +1294,7 @@ dependencies = [ "clap 2.34.0", "criterion-plot", "csv", - "futures 0.3.21", + "futures", "itertools", "lazy_static", "num-traits", @@ -1359,7 +1328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.5", + "crossbeam-utils", ] [[package]] @@ -1370,7 +1339,7 @@ checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", - "crossbeam-utils 0.8.5", + "crossbeam-utils", ] [[package]] @@ -1380,23 +1349,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.5", + "crossbeam-utils", "lazy_static", "memoffset", "scopeguard", ] -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -dependencies = [ - "autocfg 1.0.1", - "cfg-if 0.1.10", - "lazy_static", -] - [[package]] name = "crossbeam-utils" version = "0.8.5" @@ -1706,7 +1664,7 @@ checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" dependencies = [ "libc", "redox_users 0.3.5", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1717,7 +1675,7 @@ checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" dependencies = [ "libc", "redox_users 0.4.0", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1728,7 +1686,7 @@ checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users 0.4.0", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1964,7 +1922,7 @@ checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ "atty", "humantime 1.3.0", - "log 0.4.16", + "log", "regex", "termcolor", ] @@ -1975,7 +1933,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ - "log 0.4.16", + "log", "regex", ] @@ -1987,7 +1945,7 @@ checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime 2.1.0", - "log 0.4.16", + "log", "regex", "termcolor", ] @@ -2006,7 +1964,7 @@ checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ "errno-dragonfly", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2031,7 +1989,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" dependencies = [ - "futures 0.3.21", + "futures", ] [[package]] @@ -2081,7 +2039,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fdbe0d94371f9ce939b555dd342d0686cc4c0cadbcd4b61d70af5ff97eb4126" dependencies = [ "env_logger 0.7.1", - "log 0.4.16", + "log", ] [[package]] @@ -2091,9 +2049,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9def033d8505edf199f6a5d07aa7e6d2d6185b164293b77f0efd108f4f3e11d" dependencies = [ "either", - "futures 0.3.21", + "futures", "futures-timer", - "log 0.4.16", + "log", "num-traits", "parity-scale-codec", "parking_lot 0.11.2", @@ -2138,21 +2096,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "fork-tree" version = "3.0.0" @@ -2167,7 +2110,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] @@ -2178,7 +2121,7 @@ dependencies = [ "frame-system", "hex-literal", "linregress", - "log 0.4.16", + "log", "parity-scale-codec", "paste 1.0.6", "scale-info", @@ -2210,7 +2153,7 @@ dependencies = [ "kvdb", "lazy_static", "linked-hash-map", - "log 0.4.16", + "log", "memory-db", "parity-scale-codec", "prettytable-rs", @@ -2249,7 +2192,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "parity-scale-codec", - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "scale-info", @@ -2336,7 +2279,7 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "k256", - "log 0.4.16", + "log", "once_cell", "parity-scale-codec", "parity-util-mem", @@ -2344,7 +2287,7 @@ dependencies = [ "pretty_assertions", "scale-info", "serde", - "smallvec 1.8.0", + "smallvec", "sp-arithmetic", "sp-core", "sp-core-hashing-proc-macro", @@ -2374,7 +2317,7 @@ name = "frame-support-procedural-tools" version = "4.0.0-dev" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -2440,7 +2383,7 @@ version = "4.0.0-dev" dependencies = [ "criterion", "frame-support", - "log 0.4.16", + "log", "parity-scale-codec", "scale-info", "serde", @@ -2495,7 +2438,7 @@ dependencies = [ "lazy_static", "libc", "libloading 0.5.2", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2505,7 +2448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2520,34 +2463,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futures" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - [[package]] name = "futures" version = "0.3.21" @@ -2658,7 +2579,6 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ - "futures 0.1.31", "futures-channel", "futures-core", "futures-io", @@ -2707,7 +2627,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", - "version_check 0.9.2", + "version_check", ] [[package]] @@ -2775,8 +2695,8 @@ dependencies = [ "bitflags", "libc", "libgit2-sys", - "log 0.4.16", - "url 2.2.1", + "log", + "url", ] [[package]] @@ -2794,7 +2714,7 @@ dependencies = [ "aho-corasick", "bstr", "fnv", - "log 0.4.16", + "log", "regex", ] @@ -2828,7 +2748,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", "futures-core", "futures-sink", @@ -2853,7 +2773,7 @@ version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d6a30320f094710245150395bc763ad23128d6a1ebbad7594dc4164b62c56b" dependencies = [ - "log 0.4.16", + "log", "pest", "pest_derive", "quick-error 2.0.0", @@ -2986,7 +2906,7 @@ checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" dependencies = [ "libc", "match_cfg", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2995,7 +2915,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", "itoa 0.4.8", ] @@ -3006,7 +2926,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9" dependencies = [ - "bytes 1.1.0", + "bytes", "http", "pin-project-lite 0.2.6", ] @@ -3038,32 +2958,13 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "hyper" -version = "0.10.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" -dependencies = [ - "base64 0.9.3", - "httparse", - "language-tags", - "log 0.3.9", - "mime", - "num_cpus", - "time", - "traitobject", - "typeable", - "unicase 1.4.2", - "url 1.7.2", -] - [[package]] name = "hyper" version = "0.14.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-channel", "futures-core", "futures-util", @@ -3089,8 +2990,8 @@ checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" dependencies = [ "ct-logs", "futures-util", - "hyper 0.14.16", - "log 0.4.16", + "hyper", + "log", "rustls 0.19.1", "rustls-native-certs 0.5.0", "tokio", @@ -3098,36 +2999,12 @@ dependencies = [ "webpki 0.21.4", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes 1.1.0", - "hyper 0.14.16", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[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.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.2.3" @@ -3146,7 +3023,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3158,10 +3035,10 @@ dependencies = [ "async-io", "core-foundation", "fnv", - "futures 0.3.21", + "futures", "if-addrs", "ipnet", - "log 0.4.16", + "log", "rtnetlink", "system-configuration", "windows", @@ -3231,15 +3108,6 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6" -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - [[package]] name = "ip_network" version = "0.4.1" @@ -3254,7 +3122,7 @@ checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" dependencies = [ "socket2 0.4.4", "widestring", - "winapi 0.3.9", + "winapi", "winreg", ] @@ -3303,161 +3171,28 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "jsonrpc-client-transports" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" -dependencies = [ - "derive_more", - "futures 0.3.21", - "hyper 0.14.16", - "hyper-tls", - "jsonrpc-core", - "jsonrpc-pubsub", - "log 0.4.16", - "serde", - "serde_json", - "tokio", - "url 1.7.2", - "websocket", -] - -[[package]] -name = "jsonrpc-core" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" -dependencies = [ - "futures 0.3.21", - "futures-executor", - "futures-util", - "log 0.4.16", - "serde", - "serde_derive", - "serde_json", -] - -[[package]] -name = "jsonrpc-core-client" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" -dependencies = [ - "futures 0.3.21", - "jsonrpc-client-transports", -] - -[[package]] -name = "jsonrpc-derive" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b939a78fa820cdfcb7ee7484466746a7377760970f6f9c6fe19f9edcc8a38d2" -dependencies = [ - "proc-macro-crate 0.1.5", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "jsonrpc-http-server" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" -dependencies = [ - "futures 0.3.21", - "hyper 0.14.16", - "jsonrpc-core", - "jsonrpc-server-utils", - "log 0.4.16", - "net2", - "parking_lot 0.11.2", - "unicase 2.6.0", -] - -[[package]] -name = "jsonrpc-ipc-server" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382bb0206323ca7cda3dcd7e245cea86d37d02457a02a975e3378fb149a48845" -dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-server-utils", - "log 0.4.16", - "parity-tokio-ipc", - "parking_lot 0.11.2", - "tower-service", -] - -[[package]] -name = "jsonrpc-pubsub" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" -dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "lazy_static", - "log 0.4.16", - "parking_lot 0.11.2", - "rand 0.7.3", - "serde", -] - -[[package]] -name = "jsonrpc-server-utils" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" -dependencies = [ - "bytes 1.1.0", - "futures 0.3.21", - "globset", - "jsonrpc-core", - "lazy_static", - "log 0.4.16", - "tokio", - "tokio-stream", - "tokio-util 0.6.7", - "unicase 2.6.0", -] - -[[package]] -name = "jsonrpc-ws-server" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f892c7d766369475ab7b0669f417906302d7c0fb521285c0a0c92e52e7c8e946" -dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-server-utils", - "log 0.4.16", - "parity-ws", - "parking_lot 0.11.2", - "slab", -] - [[package]] name = "jsonrpsee" -version = "0.10.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91dc760c341fa81173f9a434931aaf32baad5552b0230cc6c93e8fb7eaad4c19" +checksum = "ad6f9ff3481f3069c92474b697c104502f7e9191d29b34bfa38ae9a19415f1cd" dependencies = [ "jsonrpsee-core", + "jsonrpsee-http-server", "jsonrpsee-proc-macros", "jsonrpsee-types", "jsonrpsee-ws-client", + "jsonrpsee-ws-server", + "tracing", ] [[package]] name = "jsonrpsee-client-transport" -version = "0.10.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765f7a36d5087f74e3b3b47805c2188fef8eb54afcb587b078d9f8ebfe9c7220" +checksum = "4358e100faf43b2f3b7b0ecf0ad4ce3e6275fe12fda8428dedda2979751dd184" dependencies = [ - "futures 0.3.21", + "futures-util", "http", "jsonrpsee-core", "jsonrpsee-types", @@ -3474,18 +3209,22 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.10.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ef77ecd20c2254d54f5da8c0738eacca61e6b6511268a8f2753e3148c6c706" +checksum = "8e1d26ab3868749d6f716345a5fbd3334a100c0709fe464bd9189ee9d78adcde" dependencies = [ "anyhow", "arrayvec 0.7.1", + "async-lock", "async-trait", "beef", "futures-channel", + "futures-timer", "futures-util", - "hyper 0.14.16", + "hyper", "jsonrpsee-types", + "parking_lot 0.12.0", + "rand 0.8.4", "rustc-hash", "serde", "serde_json", @@ -3495,13 +3234,32 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-http-server" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee87f19a7a01a55248fc4b4861d822331c4fd60151d99e7ac9c6771999132671" +dependencies = [ + "futures-channel", + "futures-util", + "globset", + "hyper", + "jsonrpsee-core", + "jsonrpsee-types", + "lazy_static", + "serde_json", + "tokio", + "tracing", + "unicase", +] + [[package]] name = "jsonrpsee-proc-macros" -version = "0.10.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7291c72805bc7d413b457e50d8ef3e87aa554da65ecbbc278abb7dfc283e7f0" +checksum = "b75da57d54817577801c2f7a1b638610819dfd86f0470c21a2af81b06eb41ba6" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -3509,9 +3267,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.10.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b6aa52f322cbf20c762407629b8300f39bcc0cf0619840d9252a2f65fd2dd9" +checksum = "f5fe5a629443d17a30ff564881ba68881a710fd7eb02a538087b0bc51cb4962c" dependencies = [ "anyhow", "beef", @@ -3523,15 +3281,32 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.10.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd66d18bab78d956df24dd0d2e41e4c00afbb818fda94a98264bdd12ce8506ac" +checksum = "ba31eb2b9a4b73d8833f53fe55e579516289f8b31adb6104b3dbc629755acf7d" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", ] +[[package]] +name = "jsonrpsee-ws-server" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "179fe584af5c0145f922c581770d073c661a514ae6cdfa5b1a0bce41fdfdf646" +dependencies = [ + "futures-channel", + "futures-util", + "jsonrpsee-core", + "jsonrpsee-types", + "serde_json", + "soketto", + "tokio", + "tokio-util 0.7.1", + "tracing", +] + [[package]] name = "k256" version = "0.10.4" @@ -3561,23 +3336,13 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "kv-log-macro" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" dependencies = [ - "log 0.4.16", + "log", ] [[package]] @@ -3587,7 +3352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a301d8ecb7989d4a6e2c57a49baca77d353bdbf879909debe3f375fe25d61f86" dependencies = [ "parity-util-mem", - "smallvec 1.8.0", + "smallvec", ] [[package]] @@ -3609,22 +3374,16 @@ checksum = "ca7fbdfd71cd663dceb0faf3367a99f8cf724514933e9867cec4995b6027cbc1" dependencies = [ "fs-swap", "kvdb", - "log 0.4.16", + "log", "num_cpus", "owning_ref", "parity-util-mem", "parking_lot 0.12.0", "regex", "rocksdb", - "smallvec 1.8.0", + "smallvec", ] -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" - [[package]] name = "lazy_static" version = "1.4.0" @@ -3651,9 +3410,9 @@ checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "libgit2-sys" -version = "0.13.2+1.4.2" +version = "0.13.3+1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b" +checksum = "c24d36c3ac9b9996a2418d6bf428cc0bc5d1a814a84303fc60986088c5ed60de" dependencies = [ "cc", "libc", @@ -3668,7 +3427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" dependencies = [ "cc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3678,7 +3437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" dependencies = [ "cfg-if 1.0.0", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3694,8 +3453,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "475ce2ac4a9727e53a519f6ee05b38abfcba8f0d39c4d24f103d184e36fd5b0f" dependencies = [ "atomic", - "bytes 1.1.0", - "futures 0.3.21", + "bytes", + "futures", "futures-timer", "getrandom 0.2.3", "instant", @@ -3729,7 +3488,7 @@ dependencies = [ "parking_lot 0.12.0", "pin-project 1.0.10", "rand 0.7.3", - "smallvec 1.8.0", + "smallvec", ] [[package]] @@ -3739,13 +3498,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13b690e65046af6a09c0b27bd9508fa1cab0efce889de74b0b643b9d2a98f9a" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "futures-timer", "instant", "libp2p-core", "libp2p-request-response", "libp2p-swarm", - "log 0.4.16", + "log", "prost", "prost-build", "rand 0.8.4", @@ -3762,12 +3521,12 @@ dependencies = [ "ed25519-dalek", "either", "fnv", - "futures 0.3.21", + "futures", "futures-timer", "instant", "lazy_static", "libsecp256k1", - "log 0.4.16", + "log", "multiaddr", "multihash", "multistream-select", @@ -3779,7 +3538,7 @@ dependencies = [ "ring", "rw-stream-sink", "sha2 0.10.2", - "smallvec 1.8.0", + "smallvec", "thiserror", "unsigned-varint", "void", @@ -3793,7 +3552,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1d37f042f748e224f04785d0e987ae09a2aa518d6401d82d412dad83e360ed" dependencies = [ "flate2", - "futures 0.3.21", + "futures", "libp2p-core", ] @@ -3804,10 +3563,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "066e33e854e10b5c93fc650458bf2179c7e0d143db260b0963e44a94859817f1" dependencies = [ "async-std-resolver", - "futures 0.3.21", + "futures", "libp2p-core", - "log 0.4.16", - "smallvec 1.8.0", + "log", + "smallvec", "trust-dns-resolver", ] @@ -3819,14 +3578,14 @@ checksum = "733d3ea6ebe7a7a85df2bc86678b93f24b015fae5fe3b3acc4c400e795a55d2d" dependencies = [ "cuckoofilter", "fnv", - "futures 0.3.21", + "futures", "libp2p-core", "libp2p-swarm", - "log 0.4.16", + "log", "prost", "prost-build", "rand 0.7.3", - "smallvec 1.8.0", + "smallvec", ] [[package]] @@ -3836,23 +3595,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a90c989a7c0969c2ab63e898da9bc735e3be53fb4f376e9c045ce516bcc9f928" dependencies = [ "asynchronous-codec", - "base64 0.13.0", + "base64", "byteorder", - "bytes 1.1.0", + "bytes", "fnv", - "futures 0.3.21", + "futures", "hex_fmt", "instant", "libp2p-core", "libp2p-swarm", - "log 0.4.16", + "log", "prometheus-client", "prost", "prost-build", "rand 0.7.3", "regex", "sha2 0.10.2", - "smallvec 1.8.0", + "smallvec", "unsigned-varint", "wasm-timer", ] @@ -3863,15 +3622,15 @@ version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5ef5a5b57904c7c33d6713ef918d239dc6b7553458f3475d87f8a18e9c651c8" dependencies = [ - "futures 0.3.21", + "futures", "futures-timer", "libp2p-core", "libp2p-swarm", - "log 0.4.16", + "log", "lru", "prost", "prost-build", - "smallvec 1.8.0", + "smallvec", ] [[package]] @@ -3882,20 +3641,20 @@ checksum = "564e6bd64d177446399ed835b9451a8825b07929d6daa6a94e6405592974725e" dependencies = [ "arrayvec 0.5.2", "asynchronous-codec", - "bytes 1.1.0", + "bytes", "either", "fnv", - "futures 0.3.21", + "futures", "futures-timer", "instant", "libp2p-core", "libp2p-swarm", - "log 0.4.16", + "log", "prost", "prost-build", "rand 0.7.3", "sha2 0.10.2", - "smallvec 1.8.0", + "smallvec", "thiserror", "uint", "unsigned-varint", @@ -3911,14 +3670,14 @@ dependencies = [ "async-io", "data-encoding", "dns-parser", - "futures 0.3.21", + "futures", "if-watch", "lazy_static", "libp2p-core", "libp2p-swarm", - "log 0.4.16", + "log", "rand 0.8.4", - "smallvec 1.8.0", + "smallvec", "socket2 0.4.4", "void", ] @@ -3946,14 +3705,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "442eb0c9fff0bf22a34f015724b4143ce01877e079ed0963c722d94c07c72160" dependencies = [ "asynchronous-codec", - "bytes 1.1.0", - "futures 0.3.21", + "bytes", + "futures", "libp2p-core", - "log 0.4.16", + "log", "nohash-hasher", "parking_lot 0.12.0", "rand 0.7.3", - "smallvec 1.8.0", + "smallvec", "unsigned-varint", ] @@ -3963,12 +3722,12 @@ version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dd7e0c94051cda67123be68cf6b65211ba3dde7277be9068412de3e7ffd63ef" dependencies = [ - "bytes 1.1.0", + "bytes", "curve25519-dalek 3.0.2", - "futures 0.3.21", + "futures", "lazy_static", "libp2p-core", - "log 0.4.16", + "log", "prost", "prost-build", "rand 0.8.4", @@ -3985,12 +3744,12 @@ version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf57a3c2e821331dda9fe612d4654d676ab6e33d18d9434a18cced72630df6ad" dependencies = [ - "futures 0.3.21", + "futures", "futures-timer", "instant", "libp2p-core", "libp2p-swarm", - "log 0.4.16", + "log", "rand 0.7.3", "void", ] @@ -4002,10 +3761,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "962c0fb0e7212fb96a69b87f2d09bcefd317935239bdc79cda900e7a8897a3fe" dependencies = [ "asynchronous-codec", - "bytes 1.1.0", - "futures 0.3.21", + "bytes", + "futures", "libp2p-core", - "log 0.4.16", + "log", "prost", "prost-build", "unsigned-varint", @@ -4018,8 +3777,8 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" dependencies = [ - "futures 0.3.21", - "log 0.4.16", + "futures", + "log", "pin-project 1.0.10", "rand 0.7.3", "salsa20", @@ -4033,19 +3792,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3aa754cb7bccef51ebc3c458c6bbcef89d83b578a9925438389be841527d408f" dependencies = [ "asynchronous-codec", - "bytes 1.1.0", + "bytes", "either", - "futures 0.3.21", + "futures", "futures-timer", "instant", "libp2p-core", "libp2p-swarm", - "log 0.4.16", + "log", "pin-project 1.0.10", "prost", "prost-build", "rand 0.8.4", - "smallvec 1.8.0", + "smallvec", "static_assertions", "thiserror", "unsigned-varint", @@ -4060,12 +3819,12 @@ checksum = "bbd0baab894c5b84da510b915d53264d566c3c35889f09931fe9edbd2a773bee" dependencies = [ "asynchronous-codec", "bimap", - "futures 0.3.21", + "futures", "futures-timer", "instant", "libp2p-core", "libp2p-swarm", - "log 0.4.16", + "log", "prost", "prost-build", "rand 0.8.4", @@ -4082,14 +3841,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6a6fc6c9ad95661f46989473b34bd2993d14a4de497ff3b2668a910d4b869" dependencies = [ "async-trait", - "bytes 1.1.0", - "futures 0.3.21", + "bytes", + "futures", "instant", "libp2p-core", "libp2p-swarm", - "log 0.4.16", + "log", "rand 0.7.3", - "smallvec 1.8.0", + "smallvec", "unsigned-varint", ] @@ -4101,14 +3860,14 @@ checksum = "8f0c69ad9e8f7c5fc50ad5ad9c7c8b57f33716532a2b623197f69f93e374d14c" dependencies = [ "either", "fnv", - "futures 0.3.21", + "futures", "futures-timer", "instant", "libp2p-core", - "log 0.4.16", + "log", "pin-project 1.0.10", "rand 0.7.3", - "smallvec 1.8.0", + "smallvec", "thiserror", "void", ] @@ -4130,13 +3889,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "193447aa729c85aac2376828df76d171c1a589c9e6b58fcc7f9d9a020734122c" dependencies = [ "async-io", - "futures 0.3.21", + "futures", "futures-timer", "if-watch", "ipnet", "libc", "libp2p-core", - "log 0.4.16", + "log", "socket2 0.4.4", ] @@ -4147,9 +3906,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24bdab114f7f2701757d6541266e1131b429bbae382008f207f2114ee4222dcb" dependencies = [ "async-std", - "futures 0.3.21", + "futures", "libp2p-core", - "log 0.4.16", + "log", ] [[package]] @@ -4158,7 +3917,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f6ea0f84a967ef59a16083f222c18115ae2e91db69809dce275df62e101b279" dependencies = [ - "futures 0.3.21", + "futures", "js-sys", "libp2p-core", "parity-send-wrapper", @@ -4173,14 +3932,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c932834c3754501c368d1bf3d0fb458487a642b90fc25df082a3a2f3d3b32e37" dependencies = [ "either", - "futures 0.3.21", + "futures", "futures-rustls", "libp2p-core", - "log 0.4.16", + "log", "quicksink", "rw-stream-sink", "soketto", - "url 2.2.1", + "url", "webpki-roots", ] @@ -4190,7 +3949,7 @@ version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be902ebd89193cd020e89e89107726a38cfc0d16d18f613f4a37d046e92c7517" dependencies = [ - "futures 0.3.21", + "futures", "libp2p-core", "parking_lot 0.12.0", "thiserror", @@ -4219,7 +3978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0452aac8bab02242429380e9b2f94ea20cea2b37e2c1777a1358799bbe97f37" dependencies = [ "arrayref", - "base64 0.13.0", + "base64", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -4321,15 +4080,6 @@ dependencies = [ "paste 0.1.18", ] -[[package]] -name = "lock_api" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -dependencies = [ - "scopeguard", -] - [[package]] name = "lock_api" version = "0.4.6" @@ -4339,15 +4089,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -dependencies = [ - "log 0.4.16", -] - [[package]] name = "log" version = "0.4.16" @@ -4462,12 +4203,6 @@ dependencies = [ "rawpointer", ] -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - [[package]] name = "memchr" version = "2.4.1" @@ -4481,7 +4216,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -4540,15 +4275,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "mime" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -dependencies = [ - "log 0.3.9", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -4565,25 +4291,6 @@ dependencies = [ "autocfg 1.0.1", ] -[[package]] -name = "mio" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" -dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log 0.4.16", - "miow 0.2.2", - "net2", - "slab", - "winapi 0.2.8", -] - [[package]] name = "mio" version = "0.8.0" @@ -4591,34 +4298,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" dependencies = [ "libc", - "log 0.4.16", - "miow 0.3.6", + "log", + "miow", "ntapi", - "winapi 0.3.9", -] - -[[package]] -name = "mio-extras" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" -dependencies = [ - "lazycell", - "log 0.4.16", - "mio 0.6.23", - "slab", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", + "winapi", ] [[package]] @@ -4628,7 +4311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" dependencies = [ "socket2 0.3.19", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -4648,11 +4331,11 @@ dependencies = [ "byteorder", "data-encoding", "multihash", - "percent-encoding 2.1.0", + "percent-encoding", "serde", "static_assertions", "unsigned-varint", - "url 2.2.1", + "url", ] [[package]] @@ -4689,7 +4372,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro-error", "proc-macro2", "quote", @@ -4709,11 +4392,11 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "363a84be6453a70e63513660f4894ef815daf88e3356bffcda9ca27d810ce83b" dependencies = [ - "bytes 1.1.0", - "futures 0.3.21", - "log 0.4.16", + "bytes", + "futures", + "log", "pin-project 1.0.10", - "smallvec 1.8.0", + "smallvec", "unsigned-varint", ] @@ -4755,35 +4438,6 @@ dependencies = [ "rand 0.8.4", ] -[[package]] -name = "native-tls" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" -dependencies = [ - "lazy_static", - "libc", - "log 0.4.16", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - [[package]] name = "netlink-packet-core" version = "0.4.2" @@ -4828,9 +4482,9 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef8785b8141e8432aa45fceb922a7e876d7da3fad37fa7e7ec702ace3aa0826b" dependencies = [ - "bytes 1.1.0", - "futures 0.3.21", - "log 0.4.16", + "bytes", + "futures", + "log", "netlink-packet-core", "netlink-sys", "tokio", @@ -4843,10 +4497,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e4c9f9547a08241bee7b6558b9b98e1f290d187de8b7cfca2bbb4937bcaa8f8" dependencies = [ "async-io", - "bytes 1.1.0", - "futures 0.3.21", + "bytes", + "futures", "libc", - "log 0.4.16", + "log", ] [[package]] @@ -4882,13 +4536,13 @@ dependencies = [ "clap 3.1.6", "derive_more", "fs_extra", - "futures 0.3.21", + "futures", "hash-db", "hex", "kvdb", "kvdb-rocksdb", "lazy_static", - "log 0.4.16", + "log", "node-primitives", "node-runtime", "node-testing", @@ -4924,9 +4578,10 @@ dependencies = [ "frame-benchmarking-cli", "frame-system", "frame-system-rpc-runtime-api", - "futures 0.3.21", + "futures", "hex-literal", - "log 0.4.16", + "jsonrpsee", + "log", "nix 0.23.1", "node-executor", "node-inspect", @@ -5003,7 +4658,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "futures 0.3.21", + "futures", "node-primitives", "node-runtime", "node-testing", @@ -5060,7 +4715,7 @@ dependencies = [ name = "node-rpc" version = "3.0.0-dev" dependencies = [ - "jsonrpc-core", + "jsonrpsee", "node-primitives", "pallet-contracts-rpc", "pallet-mmr-rpc", @@ -5100,7 +4755,7 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "hex-literal", - "log 0.4.16", + "log", "node-primitives", "pallet-asset-tx-payment", "pallet-assets", @@ -5195,7 +4850,7 @@ dependencies = [ "frame-benchmarking", "frame-benchmarking-cli", "frame-system", - "jsonrpc-core", + "jsonrpsee", "node-template-runtime", "pallet-transaction-payment", "pallet-transaction-payment-rpc", @@ -5272,8 +4927,8 @@ version = "3.0.0-dev" dependencies = [ "frame-system", "fs_extra", - "futures 0.3.21", - "log 0.4.16", + "futures", + "log", "node-executor", "node-primitives", "node-runtime", @@ -5320,7 +4975,7 @@ checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" dependencies = [ "memchr", "minimal-lexical", - "version_check 0.9.2", + "version_check", ] [[package]] @@ -5329,7 +4984,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -5462,39 +5117,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "openssl" -version = "0.10.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885" -dependencies = [ - "bitflags", - "cfg-if 1.0.0", - "foreign-types", - "libc", - "once_cell", - "openssl-sys", -] - [[package]] name = "openssl-probe" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -[[package]] -name = "openssl-sys" -version = "0.9.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a7907e3bfa08bb85105209cdfcb6c63d109f8f6c1ed6ca318fff5c1853fbc1d" -dependencies = [ - "autocfg 1.0.1", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "os_str_bytes" version = "6.0.0" @@ -5510,7 +5138,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -5536,7 +5164,7 @@ dependencies = [ "scale-info", "serde", "serde_json", - "smallvec 1.8.0", + "smallvec", "sp-core", "sp-io", "sp-runtime", @@ -5633,7 +5261,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-authorship", "pallet-balances", "pallet-offences", @@ -5662,7 +5290,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "parity-scale-codec", "scale-info", @@ -5690,7 +5318,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-bags-list", "pallet-staking", "remote-externalities", @@ -5699,7 +5327,6 @@ dependencies = [ "sp-std", "sp-storage", "sp-tracing", - "tokio", ] [[package]] @@ -5709,7 +5336,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-transaction-payment", "parity-scale-codec", "scale-info", @@ -5747,7 +5374,7 @@ dependencies = [ "frame-system", "hex", "hex-literal", - "log 0.4.16", + "log", "pallet-beefy", "pallet-mmr", "pallet-session", @@ -5768,7 +5395,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "pallet-treasury", "parity-scale-codec", @@ -5786,7 +5413,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "pallet-bounties", "pallet-treasury", @@ -5805,7 +5432,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "parity-scale-codec", "scale-info", "sp-core", @@ -5825,7 +5452,7 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", - "log 0.4.16", + "log", "pallet-balances", "pallet-contracts-primitives", "pallet-contracts-proc-macro", @@ -5838,7 +5465,7 @@ dependencies = [ "rand_pcg 0.3.1", "scale-info", "serde", - "smallvec 1.8.0", + "smallvec", "sp-core", "sp-io", "sp-keystore", @@ -5877,9 +5504,7 @@ dependencies = [ name = "pallet-contracts-rpc" version = "4.0.0-dev" dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", + "jsonrpsee", "pallet-contracts-primitives", "pallet-contracts-rpc-runtime-api", "parity-scale-codec", @@ -5949,7 +5574,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "pallet-election-provider-support-benchmarking", "parity-scale-codec", @@ -5986,7 +5611,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "parity-scale-codec", "scale-info", @@ -6005,7 +5630,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "parity-scale-codec", "scale-info", @@ -6022,7 +5647,7 @@ dependencies = [ "frame-support", "frame-system", "lite-json", - "log 0.4.16", + "log", "parity-scale-codec", "scale-info", "sp-core", @@ -6073,7 +5698,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-authorship", "pallet-balances", "pallet-offences", @@ -6118,7 +5743,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-authorship", "pallet-session", "parity-scale-codec", @@ -6172,7 +5797,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "parity-scale-codec", "scale-info", "sp-core", @@ -6204,9 +5829,7 @@ dependencies = [ name = "pallet-mmr-rpc" version = "3.0.0" dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", + "jsonrpsee", "parity-scale-codec", "serde", "serde_json", @@ -6254,7 +5877,7 @@ version = "4.0.0-dev" dependencies = [ "frame-support", "frame-system", - "log 0.4.16", + "log", "parity-scale-codec", "scale-info", "sp-core", @@ -6309,7 +5932,7 @@ version = "4.0.0-dev" dependencies = [ "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "parity-scale-codec", "scale-info", @@ -6454,7 +6077,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-preimage", "parity-scale-codec", "scale-info", @@ -6487,7 +6110,7 @@ dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "log 0.4.16", + "log", "pallet-timestamp", "parity-scale-codec", "scale-info", @@ -6548,7 +6171,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-authorship", "pallet-bags-list", "pallet-balances", @@ -6574,7 +6197,7 @@ dependencies = [ name = "pallet-staking-reward-curve" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "sp-runtime", @@ -6585,7 +6208,7 @@ dependencies = [ name = "pallet-staking-reward-fn" version = "4.0.0-dev" dependencies = [ - "log 0.4.16", + "log", "sp-arithmetic", ] @@ -6596,7 +6219,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "parity-scale-codec", "parking_lot 0.12.0", @@ -6649,7 +6272,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "parity-scale-codec", "scale-info", "sp-core", @@ -6667,7 +6290,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "pallet-treasury", "parity-scale-codec", @@ -6691,7 +6314,7 @@ dependencies = [ "scale-info", "serde", "serde_json", - "smallvec 1.8.0", + "smallvec", "sp-core", "sp-io", "sp-runtime", @@ -6702,9 +6325,7 @@ dependencies = [ name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", + "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", "sp-api", @@ -6769,7 +6390,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "parity-scale-codec", "scale-info", @@ -6802,7 +6423,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log 0.4.16", + "log", "pallet-balances", "parity-scale-codec", "scale-info", @@ -6841,7 +6462,7 @@ dependencies = [ "fs2", "hex", "libc", - "log 0.4.16", + "log", "lz4", "memmap2 0.2.1", "parking_lot 0.11.2", @@ -6869,7 +6490,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6e626dc84025ff56bf1476ed0e30d10c84d7f89a475ef46ebabee1095a8fba" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -6881,20 +6502,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" -[[package]] -name = "parity-tokio-ipc" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6" -dependencies = [ - "futures 0.3.21", - "libc", - "log 0.4.16", - "rand 0.7.3", - "tokio", - "winapi 0.3.9", -] - [[package]] name = "parity-util-mem" version = "0.11.0" @@ -6907,8 +6514,8 @@ dependencies = [ "parity-util-mem-derive", "parking_lot 0.12.0", "primitive-types", - "smallvec 1.8.0", - "winapi 0.3.9", + "smallvec", + "winapi", ] [[package]] @@ -6937,41 +6544,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" -[[package]] -name = "parity-ws" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab8a461779bd022964cae2b4989fa9c99deb270bec162da2125ec03c09fcaa" -dependencies = [ - "byteorder", - "bytes 0.4.12", - "httparse", - "log 0.4.16", - "mio 0.6.23", - "mio-extras", - "rand 0.7.3", - "sha-1 0.8.2", - "slab", - "url 2.2.1", -] - [[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.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -dependencies = [ - "lock_api 0.3.4", - "parking_lot_core 0.6.2", - "rustc_version 0.2.3", -] - [[package]] name = "parking_lot" version = "0.11.2" @@ -6979,7 +6557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", - "lock_api 0.4.6", + "lock_api", "parking_lot_core 0.8.5", ] @@ -6989,25 +6567,10 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ - "lock_api 0.4.6", + "lock_api", "parking_lot_core 0.9.1", ] -[[package]] -name = "parking_lot_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -dependencies = [ - "cfg-if 0.1.10", - "cloudabi", - "libc", - "redox_syscall 0.1.57", - "rustc_version 0.2.3", - "smallvec 0.6.14", - "winapi 0.3.9", -] - [[package]] name = "parking_lot_core" version = "0.8.5" @@ -7018,8 +6581,8 @@ dependencies = [ "instant", "libc", "redox_syscall 0.2.10", - "smallvec 1.8.0", - "winapi 0.3.9", + "smallvec", + "winapi", ] [[package]] @@ -7031,7 +6594,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall 0.2.10", - "smallvec 1.8.0", + "smallvec", "windows-sys", ] @@ -7084,12 +6647,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.1.0" @@ -7255,9 +6812,9 @@ checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" dependencies = [ "cfg-if 0.1.10", "libc", - "log 0.4.16", + "log", "wepoll-sys", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -7355,15 +6912,6 @@ dependencies = [ "uint", ] -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - [[package]] name = "proc-macro-crate" version = "1.1.3" @@ -7384,7 +6932,7 @@ dependencies = [ "proc-macro2", "quote", "syn", - "version_check 0.9.2", + "version_check", ] [[package]] @@ -7395,7 +6943,7 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", - "version_check 0.9.2", + "version_check", ] [[package]] @@ -7406,9 +6954,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" dependencies = [ "unicode-xid", ] @@ -7456,7 +7004,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ - "bytes 1.1.0", + "bytes", "prost-derive", ] @@ -7466,11 +7014,11 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" dependencies = [ - "bytes 1.1.0", + "bytes", "heck 0.3.2", "itertools", "lazy_static", - "log 0.4.16", + "log", "multimap", "petgraph", "prost", @@ -7499,7 +7047,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" dependencies = [ - "bytes 1.1.0", + "bytes", "prost", ] @@ -7551,7 +7099,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ "env_logger 0.8.4", - "log 0.4.16", + "log", "rand 0.8.4", ] @@ -7597,7 +7145,7 @@ dependencies = [ "rand_os", "rand_pcg 0.1.2", "rand_xorshift", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -7743,7 +7291,7 @@ checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" dependencies = [ "libc", "rand_core 0.4.2", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -7757,7 +7305,7 @@ dependencies = [ "libc", "rand_core 0.4.2", "rdrand", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -7823,7 +7371,7 @@ checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ "crossbeam-channel", "crossbeam-deque", - "crossbeam-utils 0.8.5", + "crossbeam-utils", "lazy_static", "num_cpus", ] @@ -7899,9 +7447,9 @@ version = "0.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" dependencies = [ - "log 0.4.16", + "log", "rustc-hash", - "smallvec 1.8.0", + "smallvec", ] [[package]] @@ -7910,9 +7458,9 @@ version = "0.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" dependencies = [ - "log 0.4.16", + "log", "rustc-hash", - "smallvec 1.8.0", + "smallvec", ] [[package]] @@ -7951,7 +7499,7 @@ dependencies = [ "bitflags", "libc", "mach", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -7963,7 +7511,7 @@ dependencies = [ "bitflags", "libc", "mach", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -7973,7 +7521,7 @@ dependencies = [ "env_logger 0.9.0", "frame-support", "jsonrpsee", - "log 0.4.16", + "log", "pallet-elections-phragmen", "parity-scale-codec", "serde", @@ -7991,7 +7539,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -8042,7 +7590,7 @@ dependencies = [ "spin", "untrusted", "web-sys", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -8087,7 +7635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -8097,8 +7645,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f54290e54521dac3de4149d83ddf9f62a359b3cc93bcb494a794a41e6f4744b" dependencies = [ "async-global-executor", - "futures 0.3.21", - "log 0.4.16", + "futures", + "log", "netlink-packet-route", "netlink-proto", "nix 0.22.3", @@ -8111,10 +7659,10 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" dependencies = [ - "base64 0.13.0", + "base64", "blake2b_simd 0.5.11", "constant_time_eq", - "crossbeam-utils 0.8.5", + "crossbeam-utils", ] [[package]] @@ -8173,7 +7721,7 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -8182,8 +7730,8 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64 0.13.0", - "log 0.4.16", + "base64", + "log", "ring", "sct 0.6.0", "webpki 0.21.4", @@ -8195,7 +7743,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" dependencies = [ - "log 0.4.16", + "log", "ring", "sct 0.7.0", "webpki 0.22.0", @@ -8231,7 +7779,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" dependencies = [ - "base64 0.13.0", + "base64", ] [[package]] @@ -8246,7 +7794,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" dependencies = [ - "futures 0.3.21", + "futures", "pin-project 0.4.27", "static_assertions", ] @@ -8266,12 +7814,6 @@ dependencies = [ "rustc_version 0.2.3", ] -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - [[package]] name = "salsa20" version = "0.9.0" @@ -8294,7 +7836,7 @@ dependencies = [ name = "sc-allocator" version = "4.1.0-dev" dependencies = [ - "log 0.4.16", + "log", "sp-core", "sp-wasm-interface", "thiserror", @@ -8305,11 +7847,11 @@ name = "sc-authority-discovery" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "futures-timer", "ip_network", "libp2p", - "log 0.4.16", + "log", "parity-scale-codec", "prost", "prost-build", @@ -8333,9 +7875,9 @@ dependencies = [ name = "sc-basic-authorship" version = "0.10.0-dev" dependencies = [ - "futures 0.3.21", + "futures", "futures-timer", - "log 0.4.16", + "log", "parity-scale-codec", "parking_lot 0.12.0", "sc-block-builder", @@ -8390,7 +7932,7 @@ dependencies = [ name = "sc-chain-spec-derive" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -8403,10 +7945,10 @@ dependencies = [ "chrono", "clap 3.1.6", "fdlimit", - "futures 0.3.21", + "futures", "hex", "libp2p", - "log 0.4.16", + "log", "names", "parity-scale-codec", "rand 0.7.3", @@ -8440,9 +7982,9 @@ name = "sc-client-api" version = "4.0.0-dev" dependencies = [ "fnv", - "futures 0.3.21", + "futures", "hash-db", - "log 0.4.16", + "log", "parity-scale-codec", "parking_lot 0.12.0", "sc-executor", @@ -8474,7 +8016,7 @@ dependencies = [ "kvdb-memorydb", "kvdb-rocksdb", "linked-hash-map", - "log 0.4.16", + "log", "parity-db", "parity-scale-codec", "parking_lot 0.12.0", @@ -8498,10 +8040,10 @@ name = "sc-consensus" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "futures-timer", "libp2p", - "log 0.4.16", + "log", "parking_lot 0.12.0", "sc-client-api", "sc-utils", @@ -8522,8 +8064,8 @@ name = "sc-consensus-aura" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.21", - "log 0.4.16", + "futures", + "log", "parity-scale-codec", "parking_lot 0.12.0", "sc-block-builder", @@ -8560,8 +8102,8 @@ version = "0.10.0-dev" dependencies = [ "async-trait", "fork-tree", - "futures 0.3.21", - "log 0.4.16", + "futures", + "log", "merlin", "num-bigint", "num-rational 0.2.4", @@ -8608,10 +8150,8 @@ dependencies = [ name = "sc-consensus-babe-rpc" version = "0.10.0-dev" dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", + "futures", + "jsonrpsee", "sc-consensus", "sc-consensus-babe", "sc-consensus-epochs", @@ -8631,6 +8171,7 @@ dependencies = [ "substrate-test-runtime-client", "tempfile", "thiserror", + "tokio", ] [[package]] @@ -8651,11 +8192,9 @@ version = "0.10.0-dev" dependencies = [ "assert_matches", "async-trait", - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "log 0.4.16", + "futures", + "jsonrpsee", + "log", "parity-scale-codec", "sc-basic-authorship", "sc-client-api", @@ -8689,9 +8228,9 @@ name = "sc-consensus-pow" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "futures-timer", - "log 0.4.16", + "log", "parity-scale-codec", "parking_lot 0.12.0", "sc-client-api", @@ -8713,9 +8252,9 @@ name = "sc-consensus-slots" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "futures-timer", - "log 0.4.16", + "log", "parity-scale-codec", "sc-client-api", "sc-consensus", @@ -8803,7 +8342,7 @@ dependencies = [ name = "sc-executor-wasmi" version = "0.10.0-dev" dependencies = [ - "log 0.4.16", + "log", "parity-scale-codec", "sc-allocator", "sc-executor-common", @@ -8819,7 +8358,7 @@ version = "0.10.0-dev" dependencies = [ "cfg-if 1.0.0", "libc", - "log 0.4.16", + "log", "parity-scale-codec", "parity-wasm 0.42.2", "sc-allocator", @@ -8843,10 +8382,10 @@ dependencies = [ "dyn-clone", "finality-grandpa", "fork-tree", - "futures 0.3.21", + "futures", "futures-timer", "hex", - "log 0.4.16", + "log", "parity-scale-codec", "parking_lot 0.12.0", "rand 0.8.4", @@ -8885,12 +8424,9 @@ name = "sc-finality-grandpa-rpc" version = "0.10.0-dev" dependencies = [ "finality-grandpa", - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "jsonrpc-pubsub", - "log 0.4.16", + "futures", + "jsonrpsee", + "log", "parity-scale-codec", "sc-block-builder", "sc-client-api", @@ -8905,6 +8441,7 @@ dependencies = [ "sp-runtime", "substrate-test-runtime-client", "thiserror", + "tokio", ] [[package]] @@ -8912,9 +8449,9 @@ name = "sc-informant" version = "0.10.0-dev" dependencies = [ "ansi_term", - "futures 0.3.21", + "futures", "futures-timer", - "log 0.4.16", + "log", "parity-util-mem", "sc-client-api", "sc-network", @@ -8947,19 +8484,19 @@ dependencies = [ "async-trait", "asynchronous-codec", "bitflags", - "bytes 1.1.0", + "bytes", "cid", "either", "fnv", "fork-tree", - "futures 0.3.21", + "futures", "futures-timer", "hex", "ip_network", "libp2p", "linked-hash-map", "linked_hash_set", - "log 0.4.16", + "log", "lru", "parity-scale-codec", "parking_lot 0.12.0", @@ -8977,7 +8514,7 @@ dependencies = [ "sc-utils", "serde", "serde_json", - "smallvec 1.8.0", + "smallvec", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -9000,12 +8537,12 @@ dependencies = [ name = "sc-network-common" version = "0.10.0-dev" dependencies = [ - "futures 0.3.21", + "futures", "libp2p", "parity-scale-codec", "prost-build", "sc-peerset", - "smallvec 1.8.0", + "smallvec", ] [[package]] @@ -9014,10 +8551,10 @@ version = "0.10.0-dev" dependencies = [ "ahash", "async-std", - "futures 0.3.21", + "futures", "futures-timer", "libp2p", - "log 0.4.16", + "log", "lru", "quickcheck", "sc-network", @@ -9034,9 +8571,9 @@ dependencies = [ "bitflags", "either", "fork-tree", - "futures 0.3.21", + "futures", "libp2p", - "log 0.4.16", + "log", "lru", "parity-scale-codec", "prost", @@ -9047,7 +8584,7 @@ dependencies = [ "sc-consensus", "sc-network-common", "sc-peerset", - "smallvec 1.8.0", + "smallvec", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -9066,10 +8603,10 @@ version = "0.8.0" dependencies = [ "async-std", "async-trait", - "futures 0.3.21", + "futures", "futures-timer", "libp2p", - "log 0.4.16", + "log", "parking_lot 0.12.0", "rand 0.7.3", "sc-block-builder", @@ -9092,12 +8629,12 @@ dependencies = [ name = "sc-offchain" version = "4.0.0-dev" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", - "futures 0.3.21", + "futures", "futures-timer", "hex", - "hyper 0.14.16", + "hyper", "hyper-rustls", "lazy_static", "num_cpus", @@ -9128,9 +8665,9 @@ dependencies = [ name = "sc-peerset" version = "4.0.0-dev" dependencies = [ - "futures 0.3.21", + "futures", "libp2p", - "log 0.4.16", + "log", "rand 0.7.3", "sc-utils", "serde_json", @@ -9141,7 +8678,7 @@ dependencies = [ name = "sc-proposer-metrics" version = "0.10.0-dev" dependencies = [ - "log 0.4.16", + "log", "substrate-prometheus-endpoint", ] @@ -9150,12 +8687,12 @@ name = "sc-rpc" version = "4.0.0-dev" dependencies = [ "assert_matches", - "futures 0.3.21", + "env_logger 0.9.0", + "futures", "hash-db", - "jsonrpc-core", - "jsonrpc-pubsub", + "jsonrpsee", "lazy_static", - "log 0.4.16", + "log", "parity-scale-codec", "parking_lot 0.12.0", "sc-block-builder", @@ -9180,18 +8717,16 @@ dependencies = [ "sp-session", "sp-version", "substrate-test-runtime-client", + "tokio", ] [[package]] name = "sc-rpc-api" version = "0.10.0-dev" dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "jsonrpc-pubsub", - "log 0.4.16", + "futures", + "jsonrpsee", + "log", "parity-scale-codec", "parking_lot 0.12.0", "sc-chain-spec", @@ -9211,13 +8746,9 @@ dependencies = [ name = "sc-rpc-server" version = "4.0.0-dev" dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-http-server", - "jsonrpc-ipc-server", - "jsonrpc-pubsub", - "jsonrpc-ws-server", - "log 0.4.16", + "futures", + "jsonrpsee", + "log", "serde_json", "substrate-prometheus-endpoint", "tokio", @@ -9245,12 +8776,11 @@ dependencies = [ "async-trait", "directories", "exit-future", - "futures 0.3.21", + "futures", "futures-timer", "hash-db", - "jsonrpc-core", - "jsonrpc-pubsub", - "log 0.4.16", + "jsonrpsee", + "log", "parity-scale-codec", "parity-util-mem", "parking_lot 0.12.0", @@ -9310,10 +8840,10 @@ name = "sc-service-test" version = "2.0.0" dependencies = [ "fdlimit", - "futures 0.3.21", + "futures", "hex", "hex-literal", - "log 0.4.16", + "log", "parity-scale-codec", "parking_lot 0.12.0", "sc-block-builder", @@ -9345,7 +8875,7 @@ dependencies = [ name = "sc-state-db" version = "0.10.0-dev" dependencies = [ - "log 0.4.16", + "log", "parity-scale-codec", "parity-util-mem", "parity-util-mem-derive", @@ -9358,9 +8888,7 @@ dependencies = [ name = "sc-sync-state-rpc" version = "0.10.0-dev" dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", + "jsonrpsee", "parity-scale-codec", "sc-chain-spec", "sc-client-api", @@ -9378,9 +8906,9 @@ dependencies = [ name = "sc-sysinfo" version = "6.0.0-dev" dependencies = [ - "futures 0.3.21", + "futures", "libc", - "log 0.4.16", + "log", "rand 0.7.3", "rand_pcg 0.2.1", "regex", @@ -9397,9 +8925,9 @@ name = "sc-telemetry" version = "4.0.0-dev" dependencies = [ "chrono", - "futures 0.3.21", + "futures", "libp2p", - "log 0.4.16", + "log", "parking_lot 0.12.0", "pin-project 1.0.10", "rand 0.7.3", @@ -9419,7 +8947,7 @@ dependencies = [ "criterion", "lazy_static", "libc", - "log 0.4.16", + "log", "once_cell", "parking_lot 0.12.0", "regex", @@ -9444,7 +8972,7 @@ dependencies = [ name = "sc-tracing-proc-macro" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -9456,11 +8984,11 @@ version = "4.0.0-dev" dependencies = [ "assert_matches", "criterion", - "futures 0.3.21", + "futures", "futures-timer", "hex", "linked-hash-map", - "log 0.4.16", + "log", "parity-scale-codec", "parity-util-mem", "parking_lot 0.12.0", @@ -9488,8 +9016,8 @@ dependencies = [ name = "sc-transaction-pool-api" version = "4.0.0-dev" dependencies = [ - "futures 0.3.21", - "log 0.4.16", + "futures", + "log", "serde", "sp-blockchain", "sp-runtime", @@ -9500,10 +9028,10 @@ dependencies = [ name = "sc-utils" version = "4.0.0-dev" dependencies = [ - "futures 0.3.21", + "futures", "futures-timer", "lazy_static", - "log 0.4.16", + "log", "parking_lot 0.12.0", "prometheus", "tokio-test", @@ -9529,7 +9057,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7805950c36512db9e3251c970bb7ac425f326716941862205d612ab3b5e46e2" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -9542,7 +9070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" dependencies = [ "lazy_static", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -9793,12 +9321,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" - [[package]] name = "sha2" version = "0.8.2" @@ -9919,15 +9441,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -[[package]] -name = "smallvec" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" -dependencies = [ - "maybe-uninit", -] - [[package]] name = "smallvec" version = "1.8.0" @@ -9965,7 +9478,7 @@ checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" dependencies = [ "cfg-if 1.0.0", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -9975,7 +9488,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -9984,12 +9497,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ - "base64 0.13.0", - "bytes 1.1.0", + "base64", + "bytes", "flate2", - "futures 0.3.21", + "futures", "httparse", - "log 0.4.16", + "log", "rand 0.8.4", "sha-1 0.9.4", ] @@ -9999,7 +9512,7 @@ name = "sp-api" version = "4.0.0-dev" dependencies = [ "hash-db", - "log 0.4.16", + "log", "parity-scale-codec", "sp-api-proc-macro", "sp-core", @@ -10016,7 +9529,7 @@ name = "sp-api-proc-macro" version = "4.0.0-dev" dependencies = [ "blake2", - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -10027,8 +9540,8 @@ name = "sp-api-test" version = "2.0.1" dependencies = [ "criterion", - "futures 0.3.21", - "log 0.4.16", + "futures", + "log", "parity-scale-codec", "rustversion", "sc-block-builder", @@ -10132,8 +9645,8 @@ dependencies = [ name = "sp-blockchain" version = "4.0.0-dev" dependencies = [ - "futures 0.3.21", - "log 0.4.16", + "futures", + "log", "lru", "parity-scale-codec", "parking_lot 0.12.0", @@ -10150,9 +9663,9 @@ name = "sp-consensus" version = "0.10.0-dev" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "futures-timer", - "log 0.4.16", + "log", "parity-scale-codec", "sp-core", "sp-inherents", @@ -10250,7 +9763,7 @@ dependencies = [ "criterion", "dyn-clonable", "ed25519-dalek", - "futures 0.3.21", + "futures", "hash-db", "hash256-std-hasher", "hex", @@ -10258,7 +9771,7 @@ dependencies = [ "impl-serde", "lazy_static", "libsecp256k1", - "log 0.4.16", + "log", "merlin", "num-traits", "parity-scale-codec", @@ -10344,7 +9857,7 @@ name = "sp-finality-grandpa" version = "4.0.0-dev" dependencies = [ "finality-grandpa", - "log 0.4.16", + "log", "parity-scale-codec", "scale-info", "serde", @@ -10361,7 +9874,7 @@ name = "sp-inherents" version = "4.0.0-dev" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "impl-trait-for-tuples", "parity-scale-codec", "sp-core", @@ -10374,10 +9887,10 @@ dependencies = [ name = "sp-io" version = "6.0.0" dependencies = [ - "futures 0.3.21", + "futures", "hash-db", "libsecp256k1", - "log 0.4.16", + "log", "parity-scale-codec", "parking_lot 0.12.0", "secp256k1", @@ -10409,7 +9922,7 @@ name = "sp-keystore" version = "0.12.0" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "merlin", "parity-scale-codec", "parking_lot 0.12.0", @@ -10435,7 +9948,7 @@ name = "sp-mmr-primitives" version = "4.0.0-dev" dependencies = [ "hex-literal", - "log 0.4.16", + "log", "parity-scale-codec", "serde", "sp-api", @@ -10508,7 +10021,7 @@ dependencies = [ "either", "hash256-std-hasher", "impl-trait-for-tuples", - "log 0.4.16", + "log", "parity-scale-codec", "parity-util-mem", "paste 1.0.6", @@ -10555,7 +10068,7 @@ name = "sp-runtime-interface-proc-macro" version = "5.0.0" dependencies = [ "Inflector", - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -10604,7 +10117,7 @@ name = "sp-sandbox" version = "0.10.0-dev" dependencies = [ "assert_matches", - "log 0.4.16", + "log", "parity-scale-codec", "sp-core", "sp-io", @@ -10651,13 +10164,13 @@ version = "0.12.0" dependencies = [ "hash-db", "hex-literal", - "log 0.4.16", + "log", "num-traits", "parity-scale-codec", "parking_lot 0.12.0", "pretty_assertions", "rand 0.7.3", - "smallvec 1.8.0", + "smallvec", "sp-core", "sp-externalities", "sp-panic-handler", @@ -10689,7 +10202,7 @@ dependencies = [ name = "sp-tasks" version = "4.0.0-dev" dependencies = [ - "log 0.4.16", + "log", "parity-scale-codec", "sp-core", "sp-externalities", @@ -10716,7 +10229,7 @@ version = "4.0.0-dev" dependencies = [ "async-trait", "futures-timer", - "log 0.4.16", + "log", "parity-scale-codec", "sp-api", "sp-inherents", @@ -10749,7 +10262,7 @@ name = "sp-transaction-storage-proof" version = "4.0.0-dev" dependencies = [ "async-trait", - "log 0.4.16", + "log", "parity-scale-codec", "scale-info", "sp-core", @@ -10811,7 +10324,7 @@ name = "sp-wasm-interface" version = "6.0.0" dependencies = [ "impl-trait-for-tuples", - "log 0.4.16", + "log", "parity-scale-codec", "sp-std", "wasmi", @@ -10938,8 +10451,8 @@ version = "3.0.0" dependencies = [ "frame-support", "frame-system", - "futures 0.3.21", - "jsonrpc-client-transports", + "futures", + "jsonrpsee", "parity-scale-codec", "sc-rpc-api", "scale-info", @@ -10952,17 +10465,17 @@ dependencies = [ name = "substrate-frame-rpc-system" version = "4.0.0-dev" dependencies = [ + "assert_matches", "frame-system-rpc-runtime-api", - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "log 0.4.16", + "futures", + "jsonrpsee", + "log", "parity-scale-codec", "sc-client-api", "sc-rpc-api", "sc-transaction-pool", "sc-transaction-pool-api", + "serde_json", "sp-api", "sp-block-builder", "sp-blockchain", @@ -10970,6 +10483,7 @@ dependencies = [ "sp-runtime", "sp-tracing", "substrate-test-runtime-client", + "tokio", ] [[package]] @@ -10977,8 +10491,8 @@ name = "substrate-prometheus-endpoint" version = "0.10.0-dev" dependencies = [ "futures-util", - "hyper 0.14.16", - "log 0.4.16", + "hyper", + "log", "prometheus", "thiserror", "tokio", @@ -10988,10 +10502,8 @@ dependencies = [ name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "log 0.4.16", + "jsonrpsee", + "log", "parity-scale-codec", "sc-client-api", "sc-rpc-api", @@ -11012,7 +10524,7 @@ name = "substrate-test-client" version = "2.0.1" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "hex", "parity-scale-codec", "sc-client-api", @@ -11041,8 +10553,8 @@ dependencies = [ "frame-support", "frame-system", "frame-system-rpc-runtime-api", - "futures 0.3.21", - "log 0.4.16", + "futures", + "log", "memory-db", "pallet-babe", "pallet-timestamp", @@ -11083,7 +10595,7 @@ dependencies = [ name = "substrate-test-runtime-client" version = "2.0.0" dependencies = [ - "futures 0.3.21", + "futures", "parity-scale-codec", "sc-block-builder", "sc-client-api", @@ -11101,7 +10613,7 @@ dependencies = [ name = "substrate-test-runtime-transaction-pool" version = "2.0.0" dependencies = [ - "futures 0.3.21", + "futures", "parity-scale-codec", "parking_lot 0.12.0", "sc-transaction-pool", @@ -11116,7 +10628,7 @@ dependencies = [ name = "substrate-test-utils" version = "4.0.0-dev" dependencies = [ - "futures 0.3.21", + "futures", "sc-service", "substrate-test-utils-derive", "tokio", @@ -11127,7 +10639,7 @@ dependencies = [ name = "substrate-test-utils-derive" version = "0.10.0-dev" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -11230,7 +10742,7 @@ dependencies = [ "libc", "redox_syscall 0.2.10", "remove_dir_all", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -11241,7 +10753,7 @@ checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" dependencies = [ "byteorder", "dirs", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -11331,7 +10843,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -11393,10 +10905,10 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" dependencies = [ - "bytes 1.1.0", + "bytes", "libc", "memchr", - "mio 0.8.0", + "mio", "num_cpus", "once_cell", "parking_lot 0.12.0", @@ -11404,39 +10916,7 @@ dependencies = [ "signal-hook-registry", "socket2 0.4.4", "tokio-macros", - "winapi 0.3.9", -] - -[[package]] -name = "tokio-codec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "tokio-io", -] - -[[package]] -name = "tokio-executor" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" -dependencies = [ - "crossbeam-utils 0.7.2", - "futures 0.1.31", -] - -[[package]] -name = "tokio-io" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "log 0.4.16", + "winapi", ] [[package]] @@ -11450,35 +10930,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" -dependencies = [ - "crossbeam-utils 0.7.2", - "futures 0.1.31", - "lazy_static", - "log 0.4.16", - "mio 0.6.23", - "num_cpus", - "parking_lot 0.9.0", - "slab", - "tokio-executor", - "tokio-io", - "tokio-sync", -] - [[package]] name = "tokio-rustls" version = "0.22.0" @@ -11512,30 +10963,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-sync" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" -dependencies = [ - "fnv", - "futures 0.1.31", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "iovec", - "mio 0.6.23", - "tokio-io", - "tokio-reactor", -] - [[package]] name = "tokio-test" version = "0.4.2" @@ -11543,33 +10970,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53474327ae5e166530d17f2d956afcb4f8a004de581b3cae10f12006bc8163e3" dependencies = [ "async-stream", - "bytes 1.1.0", + "bytes", "futures-core", "tokio", "tokio-stream", ] -[[package]] -name = "tokio-tls" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c" -dependencies = [ - "futures 0.1.31", - "native-tls", - "tokio-io", -] - [[package]] name = "tokio-util" version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-core", "futures-sink", - "log 0.4.16", + "log", "pin-project-lite 0.2.6", "tokio", ] @@ -11580,7 +10996,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-core", "futures-io", "futures-sink", @@ -11610,7 +11026,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ "cfg-if 1.0.0", - "log 0.4.16", + "log", "pin-project-lite 0.2.6", "tracing-attributes", "tracing-core", @@ -11655,7 +11071,7 @@ checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ "ahash", "lazy_static", - "log 0.4.16", + "log", "lru", "tracing-core", ] @@ -11685,7 +11101,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec 1.8.0", + "smallvec", "thread_local", "tracing", "tracing-core", @@ -11693,12 +11109,6 @@ dependencies = [ "tracing-serde", ] -[[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" - [[package]] name = "treeline" version = "0.1.0" @@ -11729,9 +11139,9 @@ checksum = "d32d034c0d3db64b43c31de38e945f15b40cd4ca6d2dcfc26d4798ce8de4ab83" dependencies = [ "hash-db", "hashbrown 0.12.0", - "log 0.4.16", + "log", "rustc-hex", - "smallvec 1.8.0", + "smallvec", ] [[package]] @@ -11766,15 +11176,15 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.2.3", + "idna", "ipnet", "lazy_static", - "log 0.4.16", + "log", "rand 0.8.4", - "smallvec 1.8.0", + "smallvec", "thiserror", "tinyvec", - "url 2.2.1", + "url", ] [[package]] @@ -11787,11 +11197,11 @@ dependencies = [ "futures-util", "ipconfig", "lazy_static", - "log 0.4.16", + "log", "lru-cache", "parking_lot 0.12.0", "resolv-conf", - "smallvec 1.8.0", + "smallvec", "thiserror", "trust-dns-proto", ] @@ -11808,7 +11218,7 @@ version = "0.10.0-dev" dependencies = [ "clap 3.1.6", "jsonrpsee", - "log 0.4.16", + "log", "parity-scale-codec", "remote-externalities", "sc-chain-spec", @@ -11860,12 +11270,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "typeable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" - [[package]] name = "typenum" version = "1.15.0" @@ -11890,22 +11294,13 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "unicase" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -dependencies = [ - "version_check 0.1.5", -] - [[package]] name = "unicase" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" dependencies = [ - "version_check 0.9.2", + "version_check", ] [[package]] @@ -11940,9 +11335,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "universal-hash" @@ -11961,7 +11356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836" dependencies = [ "asynchronous-codec", - "bytes 1.1.0", + "bytes", "futures-io", "futures-util", ] @@ -11972,17 +11367,6 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna 0.1.5", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "url" version = "2.2.1" @@ -11990,9 +11374,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ "form_urlencoded", - "idna 0.2.3", + "idna", "matches", - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] @@ -12008,7 +11392,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" dependencies = [ "ctor", - "version_check 0.9.2", + "version_check", ] [[package]] @@ -12023,12 +11407,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" - [[package]] name = "version_check" version = "0.9.2" @@ -12063,7 +11441,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", - "winapi 0.3.9", + "winapi", "winapi-util", ] @@ -12073,7 +11451,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ - "log 0.4.16", + "log", "try-lock", ] @@ -12107,7 +11485,7 @@ checksum = "f34c405b4f0658583dba0c1c7c9b694f3cac32655db463b56c254a1c75269523" dependencies = [ "bumpalo", "lazy_static", - "log 0.4.16", + "log", "proc-macro2", "quote", "syn", @@ -12161,7 +11539,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0c32691b6c7e6c14e7f8fd55361a9088b507aa49620fcd06c09b3a1082186b9" dependencies = [ - "log 0.4.16", + "log", "parity-wasm 0.32.0", "rustc-demangle", ] @@ -12181,7 +11559,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" dependencies = [ - "futures 0.3.21", + "futures", "js-sys", "parking_lot 0.11.2", "pin-utils", @@ -12214,7 +11592,7 @@ dependencies = [ "wasmer-types", "wasmer-vm", "wat", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -12228,7 +11606,7 @@ dependencies = [ "rkyv", "serde", "serde_bytes", - "smallvec 1.8.0", + "smallvec", "target-lexicon", "thiserror", "wasmer-types", @@ -12249,7 +11627,7 @@ dependencies = [ "loupe", "more-asserts", "rayon", - "smallvec 1.8.0", + "smallvec", "target-lexicon", "tracing", "wasmer-compiler", @@ -12270,7 +11648,7 @@ dependencies = [ "loupe", "more-asserts", "rayon", - "smallvec 1.8.0", + "smallvec", "wasmer-compiler", "wasmer-types", "wasmer-vm", @@ -12352,7 +11730,7 @@ dependencies = [ "wasmer-engine", "wasmer-types", "wasmer-vm", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -12400,7 +11778,7 @@ dependencies = [ "serde", "thiserror", "wasmer-types", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -12454,7 +11832,7 @@ dependencies = [ "indexmap", "lazy_static", "libc", - "log 0.4.16", + "log", "object 0.27.1", "once_cell", "paste 1.0.6", @@ -12469,7 +11847,7 @@ dependencies = [ "wasmtime-environ", "wasmtime-jit", "wasmtime-runtime", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -12479,16 +11857,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c6ab24291fa7cb3a181f5669f6c72599b7ef781669759b45c7828c5999d0c0" dependencies = [ "anyhow", - "base64 0.13.0", + "base64", "bincode", "directories-next", "file-per-thread-logger", - "log 0.4.16", + "log", "rustix", "serde", "sha2 0.9.8", "toml", - "winapi 0.3.9", + "winapi", "zstd", ] @@ -12505,7 +11883,7 @@ dependencies = [ "cranelift-native", "cranelift-wasm", "gimli 0.26.1", - "log 0.4.16", + "log", "more-asserts", "object 0.27.1", "target-lexicon", @@ -12524,7 +11902,7 @@ dependencies = [ "cranelift-entity 0.82.3", "gimli 0.26.1", "indexmap", - "log 0.4.16", + "log", "more-asserts", "object 0.27.1", "serde", @@ -12546,7 +11924,7 @@ dependencies = [ "cfg-if 1.0.0", "cpp_demangle", "gimli 0.26.1", - "log 0.4.16", + "log", "object 0.27.1", "region 2.2.0", "rustc-demangle", @@ -12557,7 +11935,7 @@ dependencies = [ "wasmtime-environ", "wasmtime-jit-debug", "wasmtime-runtime", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -12583,7 +11961,7 @@ dependencies = [ "cfg-if 1.0.0", "indexmap", "libc", - "log 0.4.16", + "log", "mach", "memoffset", "more-asserts", @@ -12593,7 +11971,7 @@ dependencies = [ "thiserror", "wasmtime-environ", "wasmtime-jit-debug", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -12665,47 +12043,6 @@ dependencies = [ "webpki 0.22.0", ] -[[package]] -name = "websocket" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413b37840b9e27b340ce91b319ede10731de8c72f5bc4cb0206ec1ca4ce581d0" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "hyper 0.10.16", - "native-tls", - "rand 0.6.5", - "tokio-codec", - "tokio-io", - "tokio-reactor", - "tokio-tcp", - "tokio-tls", - "unicase 1.4.2", - "url 1.7.2", - "websocket-base", -] - -[[package]] -name = "websocket-base" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3810f0d00c4dccb54c30a4eee815e703232819dec7b007db115791c42aa374" -dependencies = [ - "base64 0.10.1", - "bitflags", - "byteorder", - "bytes 0.4.12", - "futures 0.1.31", - "native-tls", - "rand 0.6.5", - "sha1", - "tokio-codec", - "tokio-io", - "tokio-tcp", - "tokio-tls", -] - [[package]] name = "wepoll-sys" version = "3.0.1" @@ -12731,12 +12068,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - [[package]] name = "winapi" version = "0.3.9" @@ -12747,12 +12078,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -12765,7 +12090,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -12866,17 +12191,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", + "winapi", ] [[package]] @@ -12905,8 +12220,8 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c0608f53c1dc0bad505d03a34bbd49fbf2ad7b51eb036123e896365532745a1" dependencies = [ - "futures 0.3.21", - "log 0.4.16", + "futures", + "log", "nohash-hasher", "parking_lot 0.12.0", "rand 0.8.4", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index e642ce3c0411e..ab91dc7990380 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -42,7 +42,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" } # These dependencies are used for the node template's RPCs -jsonrpc-core = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server"] } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" } diff --git a/bin/node-template/node/src/rpc.rs b/bin/node-template/node/src/rpc.rs index 7f3701b5ab74f..7edae4d81474f 100644 --- a/bin/node-template/node/src/rpc.rs +++ b/bin/node-template/node/src/rpc.rs @@ -7,13 +7,15 @@ use std::sync::Arc; +use jsonrpsee::RpcModule; use node_template_runtime::{opaque::Block, AccountId, Balance, Index}; -pub use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +pub use sc_rpc_api::DenyUnsafe; + /// Full client dependencies. pub struct FullDeps { /// The client instance to use. @@ -25,7 +27,9 @@ pub struct FullDeps { } /// Instantiate all full RPC extensions. -pub fn create_full(deps: FullDeps) -> jsonrpc_core::IoHandler +pub fn create_full( + deps: FullDeps, +) -> Result, Box> where C: ProvideRuntimeApi, C: HeaderBackend + HeaderMetadata + 'static, @@ -35,20 +39,19 @@ where C::Api: BlockBuilder, P: TransactionPool + 'static, { - use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; - use substrate_frame_rpc_system::{FullSystem, SystemApi}; + use pallet_transaction_payment_rpc::{TransactionPaymentApiServer, TransactionPaymentRpc}; + use substrate_frame_rpc_system::{SystemApiServer, SystemRpc}; - let mut io = jsonrpc_core::IoHandler::default(); + let mut module = RpcModule::new(()); let FullDeps { client, pool, deny_unsafe } = deps; - io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))); - - io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client))); + module.merge(SystemRpc::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; + module.merge(TransactionPaymentRpc::new(client).into_rpc())?; // Extend this RPC with a custom API by using the following syntax. // `YourRpcStruct` should have a reference to a client, which is needed // to call into the runtime. - // `io.extend_with(YourRpcTrait::to_delegate(YourRpcStruct::new(ReferenceToClient, ...)));` + // `module.merge(YourRpcTrait::into_rpc(YourRpcStruct::new(ReferenceToClient, ...)))?;` - io + Ok(module) } diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 5f46a16a9668f..f45f914d94f44 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -228,8 +228,7 @@ pub fn new_full(mut config: Configuration) -> Result Box::new(move |deny_unsafe, _| { let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe }; - - Ok(crate::rpc::create_full(deps)) + crate::rpc::create_full(deps).map_err(Into::into) }) }; @@ -239,7 +238,7 @@ pub fn new_full(mut config: Configuration) -> Result keystore: keystore_container.sync_keystore(), task_manager: &mut task_manager, transaction_pool: transaction_pool.clone(), - rpc_extensions_builder, + rpc_builder: rpc_extensions_builder, backend, system_rpc_tx, config, diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 6bb36b9f9ab94..c18f2f5d1a108 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -37,6 +37,7 @@ crate-type = ["cdylib", "rlib"] clap = { version = "3.1.6", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } +jsonrpsee = { version = "0.12.0", features = ["server"] } futures = "0.3.21" hex-literal = "0.3.4" log = "0.4.16" diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 6eab08c39e5a2..376241d8157bf 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -92,6 +92,10 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { rpc_cors: None, rpc_methods: Default::default(), rpc_max_payload: None, + rpc_max_request_size: None, + rpc_max_response_size: None, + rpc_id_provider: None, + rpc_max_subs_per_conn: None, ws_max_out_buffer_capacity: None, prometheus_config: None, telemetry_endpoints: None, diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index eb0e24d2fdd37..f1fce16d8c1b3 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -84,6 +84,10 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { rpc_cors: None, rpc_methods: Default::default(), rpc_max_payload: None, + rpc_max_request_size: None, + rpc_max_response_size: None, + rpc_id_provider: None, + rpc_max_subs_per_conn: None, ws_max_out_buffer_capacity: None, prometheus_config: None, telemetry_endpoints: None, diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 01c7eb9abe1b7..bff4be88002fb 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -134,7 +134,7 @@ pub fn new_partial( impl Fn( node_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor, - ) -> Result, + ) -> Result, sc_service::Error>, ( sc_consensus_babe::BabeBlockImport, grandpa::LinkHalf, @@ -236,7 +236,7 @@ pub fn new_partial( let justification_stream = grandpa_link.justification_stream(); let shared_authority_set = grandpa_link.shared_authority_set().clone(); let shared_voter_state = grandpa::SharedVoterState::empty(); - let rpc_setup = shared_voter_state.clone(); + let shared_voter_state2 = shared_voter_state.clone(); let finality_proof_provider = grandpa::FinalityProofProvider::new_for_service( backend.clone(), @@ -277,7 +277,7 @@ pub fn new_partial( node_rpc::create_full(deps, rpc_backend.clone()).map_err(Into::into) }; - (rpc_extensions_builder, rpc_setup) + (rpc_extensions_builder, shared_voter_state2) }; Ok(sc_service::PartialComponents { @@ -332,7 +332,7 @@ pub fn new_full_base( keystore_container, select_chain, transaction_pool, - other: (rpc_extensions_builder, import_setup, rpc_setup, mut telemetry), + other: (rpc_builder, import_setup, rpc_setup, mut telemetry), } = new_partial(&config)?; let shared_voter_state = rpc_setup; @@ -386,7 +386,7 @@ pub fn new_full_base( client: client.clone(), keystore: keystore_container.sync_keystore(), network: network.clone(), - rpc_extensions_builder: Box::new(rpc_extensions_builder), + rpc_builder: Box::new(rpc_builder), transaction_pool: transaction_pool.clone(), task_manager: &mut task_manager, system_rpc_tx, diff --git a/bin/node/cli/tests/common.rs b/bin/node/cli/tests/common.rs index c17cabfa1d38a..9c739c2cf2d28 100644 --- a/bin/node/cli/tests/common.rs +++ b/bin/node/cli/tests/common.rs @@ -26,15 +26,14 @@ use nix::{ use node_primitives::Block; use remote_externalities::rpc_api; use std::{ + io::{BufRead, BufReader, Read}, ops::{Deref, DerefMut}, path::Path, - process::{Child, Command, ExitStatus}, + process::{self, Child, Command, ExitStatus}, time::Duration, }; use tokio::time::timeout; -static LOCALHOST_WS: &str = "ws://127.0.0.1:9944/"; - /// Wait for the given `child` the given number of `secs`. /// /// Returns the `Some(exit status)` or `None` if the process did not finish in the given time. @@ -63,8 +62,9 @@ pub fn wait_for(child: &mut Child, secs: u64) -> Result { pub async fn wait_n_finalized_blocks( n: usize, timeout_secs: u64, + url: &str, ) -> Result<(), tokio::time::error::Elapsed> { - timeout(Duration::from_secs(timeout_secs), wait_n_finalized_blocks_from(n, LOCALHOST_WS)).await + timeout(Duration::from_secs(timeout_secs), wait_n_finalized_blocks_from(n, url)).await } /// Wait for at least n blocks to be finalized from a specified node @@ -85,12 +85,23 @@ pub async fn wait_n_finalized_blocks_from(n: usize, url: &str) { /// Run the node for a while (3 blocks) pub async fn run_node_for_a_while(base_path: &Path, args: &[&str]) { - let mut cmd = Command::new(cargo_bin("substrate")); + let mut cmd = Command::new(cargo_bin("substrate")) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::piped()) + .args(args) + .arg("-d") + .arg(base_path) + .spawn() + .unwrap(); - let mut child = KillChildOnDrop(cmd.args(args).arg("-d").arg(base_path).spawn().unwrap()); + let stderr = cmd.stderr.take().unwrap(); + + let mut child = KillChildOnDrop(cmd); + + let (ws_url, _) = find_ws_url_from_output(stderr); // Let it produce some blocks. - let _ = wait_n_finalized_blocks(3, 30).await; + let _ = wait_n_finalized_blocks(3, 30, &ws_url).await; assert!(child.try_wait().unwrap().is_none(), "the process should still be running"); @@ -134,3 +145,30 @@ impl DerefMut for KillChildOnDrop { &mut self.0 } } + +/// Read the WS address from the output. +/// +/// This is hack to get the actual binded sockaddr because +/// substrate assigns a random port if the specified port was already binded. +pub fn find_ws_url_from_output(read: impl Read + Send) -> (String, String) { + let mut data = String::new(); + + let ws_url = BufReader::new(read) + .lines() + .find_map(|line| { + let line = + line.expect("failed to obtain next line from stdout for WS address discovery"); + data.push_str(&line); + + // does the line contain our port (we expect this specific output from substrate). + let sock_addr = match line.split_once("Running JSON-RPC WS server: addr=") { + None => return None, + Some((_, after)) => after.split_once(",").unwrap().0, + }; + + Some(format!("ws://{}", sock_addr)) + }) + .expect("We should get a WebSocket address"); + + (ws_url, data) +} diff --git a/bin/node/cli/tests/running_the_node_and_interrupt.rs b/bin/node/cli/tests/running_the_node_and_interrupt.rs index 35f0fc106613c..6d4a4b40425c4 100644 --- a/bin/node/cli/tests/running_the_node_and_interrupt.rs +++ b/bin/node/cli/tests/running_the_node_and_interrupt.rs @@ -25,7 +25,7 @@ use nix::{ }, unistd::Pid, }; -use std::process::{Child, Command}; +use std::process::{self, Child, Command}; use tempfile::tempdir; pub mod common; @@ -36,6 +36,8 @@ async fn running_the_node_works_and_can_be_interrupted() { let base_path = tempdir().expect("could not create a temp dir"); let mut cmd = common::KillChildOnDrop( Command::new(cargo_bin("substrate")) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::piped()) .args(&["--dev", "-d"]) .arg(base_path.path()) .arg("--db=paritydb") @@ -44,7 +46,13 @@ async fn running_the_node_works_and_can_be_interrupted() { .unwrap(), ); - common::wait_n_finalized_blocks(3, 30).await.unwrap(); + let stderr = cmd.stderr.take().unwrap(); + + let (ws_url, _) = common::find_ws_url_from_output(stderr); + + common::wait_n_finalized_blocks(3, 30, &ws_url) + .await + .expect("Blocks are produced in time"); assert!(cmd.try_wait().unwrap().is_none(), "the process should still be running"); kill(Pid::from_raw(cmd.id().try_into().unwrap()), signal).unwrap(); assert_eq!( @@ -69,6 +77,8 @@ async fn running_the_node_works_and_can_be_interrupted() { async fn running_two_nodes_with_the_same_ws_port_should_work() { fn start_node() -> Child { Command::new(cargo_bin("substrate")) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::piped()) .args(&["--dev", "--tmp", "--ws-port=45789", "--no-hardware-benchmarks"]) .spawn() .unwrap() @@ -77,7 +87,10 @@ async fn running_two_nodes_with_the_same_ws_port_should_work() { let mut first_node = common::KillChildOnDrop(start_node()); let mut second_node = common::KillChildOnDrop(start_node()); - let _ = common::wait_n_finalized_blocks(3, 30).await; + let stderr = first_node.stderr.take().unwrap(); + let (ws_url, _) = common::find_ws_url_from_output(stderr); + + common::wait_n_finalized_blocks(3, 30, &ws_url).await.unwrap(); assert!(first_node.try_wait().unwrap().is_none(), "The first node should still be running"); assert!(second_node.try_wait().unwrap().is_none(), "The second node should still be running"); diff --git a/bin/node/cli/tests/temp_base_path_works.rs b/bin/node/cli/tests/temp_base_path_works.rs index df293161e3234..98422a21f5308 100644 --- a/bin/node/cli/tests/temp_base_path_works.rs +++ b/bin/node/cli/tests/temp_base_path_works.rs @@ -43,8 +43,11 @@ async fn temp_base_path_works() { .unwrap(), ); + let mut stderr = child.stderr.take().unwrap(); + let (ws_url, mut data) = common::find_ws_url_from_output(&mut stderr); + // Let it produce some blocks. - common::wait_n_finalized_blocks(3, 30).await.unwrap(); + common::wait_n_finalized_blocks(3, 30, &ws_url).await.unwrap(); assert!(child.try_wait().unwrap().is_none(), "the process should still be running"); // Stop the process @@ -52,10 +55,9 @@ async fn temp_base_path_works() { assert!(common::wait_for(&mut child, 40).map(|x| x.success()).unwrap_or_default()); // Ensure the database has been deleted - let mut stderr = String::new(); - child.stderr.as_mut().unwrap().read_to_string(&mut stderr).unwrap(); + stderr.read_to_string(&mut data).unwrap(); let re = Regex::new(r"Database: .+ at (\S+)").unwrap(); - let db_path = PathBuf::from(re.captures(stderr.as_str()).unwrap().get(1).unwrap().as_str()); + let db_path = PathBuf::from(re.captures(data.as_str()).unwrap().get(1).unwrap().as_str()); assert!(!db_path.exists()); } diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index f0ae8b42e6398..9520c621d3165 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpc-core = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server"] } node-primitives = { version = "2.0.0", path = "../primitives" } pallet-contracts-rpc = { version = "4.0.0-dev", path = "../../../frame/contracts/rpc/" } pallet-mmr-rpc = { version = "3.0.0", path = "../../../frame/merkle-mountain-range/rpc/" } diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index b8349e26cd1da..05aa973e102b1 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -29,18 +29,20 @@ //! be placed here or imported from corresponding FRAME RPC definitions. #![warn(missing_docs)] +#![warn(unused_crate_dependencies)] use std::sync::Arc; +use jsonrpsee::RpcModule; use node_primitives::{AccountId, Balance, Block, BlockNumber, Hash, Index}; use sc_client_api::AuxStore; use sc_consensus_babe::{Config, Epoch}; -use sc_consensus_babe_rpc::BabeRpcHandler; +use sc_consensus_babe_rpc::BabeRpc; use sc_consensus_epochs::SharedEpochChanges; use sc_finality_grandpa::{ FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState, }; -use sc_finality_grandpa_rpc::GrandpaRpcHandler; +use sc_finality_grandpa_rpc::GrandpaRpc; use sc_rpc::SubscriptionTaskExecutor; pub use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::TransactionPool; @@ -93,14 +95,11 @@ pub struct FullDeps { pub grandpa: GrandpaDeps, } -/// A IO handler that uses all Full RPC extensions. -pub type IoHandler = jsonrpc_core::IoHandler; - /// Instantiate all Full RPC extensions. pub fn create_full( deps: FullDeps, backend: Arc, -) -> Result, Box> +) -> Result, Box> where C: ProvideRuntimeApi + sc_client_api::BlockBackend @@ -121,13 +120,17 @@ where B: sc_client_api::Backend + Send + Sync + 'static, B::State: sc_client_api::backend::StateBackend>, { - use pallet_contracts_rpc::{Contracts, ContractsApi}; - use pallet_mmr_rpc::{Mmr, MmrApi}; - use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; - use sc_rpc::dev::{Dev, DevApi}; - use substrate_frame_rpc_system::{FullSystem, SystemApi}; + use pallet_contracts_rpc::{ContractsApiServer, ContractsRpc}; + use pallet_mmr_rpc::{MmrApiServer, MmrRpc}; + use pallet_transaction_payment_rpc::{TransactionPaymentApiServer, TransactionPaymentRpc}; + use sc_consensus_babe_rpc::BabeApiServer; + use sc_finality_grandpa_rpc::GrandpaApiServer; + use sc_rpc::dev::{Dev, DevApiServer}; + use sc_sync_state_rpc::{SyncStateRpc, SyncStateRpcApiServer}; + use substrate_frame_rpc_system::{SystemApiServer, SystemRpc}; + use substrate_state_trie_migration_rpc::StateMigrationApiServer; - let mut io = jsonrpc_core::IoHandler::default(); + let mut io = RpcModule::new(()); let FullDeps { client, pool, select_chain, chain_spec, deny_unsafe, babe, grandpa } = deps; let BabeDeps { keystore, babe_config, shared_epoch_changes } = babe; @@ -139,40 +142,45 @@ where finality_provider, } = grandpa; - io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))); + io.merge(SystemRpc::new(client.clone(), pool, deny_unsafe).into_rpc())?; // Making synchronous calls in light client freezes the browser currently, // more context: https://github.com/paritytech/substrate/pull/3480 // These RPCs should use an asynchronous caller instead. - io.extend_with(ContractsApi::to_delegate(Contracts::new(client.clone()))); - io.extend_with(MmrApi::to_delegate(Mmr::new(client.clone()))); - io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))); - io.extend_with(sc_consensus_babe_rpc::BabeApi::to_delegate(BabeRpcHandler::new( - client.clone(), - shared_epoch_changes.clone(), - keystore, - babe_config, - select_chain, - deny_unsafe, - ))); - io.extend_with(sc_finality_grandpa_rpc::GrandpaApi::to_delegate(GrandpaRpcHandler::new( - shared_authority_set.clone(), - shared_voter_state, - justification_stream, - subscription_executor, - finality_provider, - ))); - io.extend_with(substrate_state_trie_migration_rpc::StateMigrationApi::to_delegate( - substrate_state_trie_migration_rpc::MigrationRpc::new(client.clone(), backend, deny_unsafe), - )); - io.extend_with(sc_sync_state_rpc::SyncStateRpcApi::to_delegate( - sc_sync_state_rpc::SyncStateRpcHandler::new( - chain_spec, + io.merge(ContractsRpc::new(client.clone()).into_rpc())?; + io.merge(MmrRpc::new(client.clone()).into_rpc())?; + io.merge(TransactionPaymentRpc::new(client.clone()).into_rpc())?; + io.merge( + BabeRpc::new( client.clone(), - shared_authority_set, - shared_epoch_changes, - )?, - )); - io.extend_with(DevApi::to_delegate(Dev::new(client, deny_unsafe))); + shared_epoch_changes.clone(), + keystore, + babe_config, + select_chain, + deny_unsafe, + ) + .into_rpc(), + )?; + io.merge( + GrandpaRpc::new( + subscription_executor, + shared_authority_set.clone(), + shared_voter_state, + justification_stream, + finality_provider, + ) + .into_rpc(), + )?; + + io.merge( + SyncStateRpc::new(chain_spec, client.clone(), shared_authority_set, shared_epoch_changes)? + .into_rpc(), + )?; + + io.merge( + substrate_state_trie_migration_rpc::MigrationRpc::new(client.clone(), backend, deny_unsafe) + .into_rpc(), + )?; + io.merge(Dev::new(client, deny_unsafe).into_rpc())?; Ok(io) } diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 4b6496e52c2f2..bd25496f2dfea 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -41,7 +41,7 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } serde = "1.0.136" strum = { version = "0.23", features = ["derive"] } tempfile = "3.1.0" -tokio = "1.15" +tokio = "1.17.0" sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sc-network-test = { version = "0.8.0", path = "../network/test" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index adf29f1cef732..f8ca6470f267a 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -11,10 +11,7 @@ homepage = "https://substrate.io" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" -jsonrpc-pubsub = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } log = "0.4" parking_lot = "0.12.0" serde = { version = "1.0.136", features = ["derive"] } @@ -32,3 +29,4 @@ sc-rpc = { version = "4.0.0-dev", features = [ "test-helpers", ], path = "../../rpc" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } +tokio = { version = "1.17.0", features = ["macros"] } diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index e49af3352ae4e..e4c8c76419ccb 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -23,19 +23,22 @@ use parking_lot::RwLock; use std::sync::Arc; +use sc_rpc::SubscriptionTaskExecutor; use sp_runtime::traits::Block as BlockT; -use futures::{task::SpawnError, FutureExt, SinkExt, StreamExt, TryFutureExt}; -use jsonrpc_derive::rpc; -use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; +use futures::{task::SpawnError, FutureExt, StreamExt}; +use jsonrpsee::{ + core::{async_trait, Error as JsonRpseeError, RpcResult}, + proc_macros::rpc, + types::{error::CallError, ErrorObject}, + PendingSubscription, +}; use log::warn; use beefy_gadget::notification::{BeefyBestBlockStream, BeefySignedCommitmentStream}; mod notification; -type FutureResult = jsonrpc_core::BoxFuture>; - #[derive(Debug, thiserror::Error)] /// Top-level error type for the RPC handler pub enum Error { @@ -64,195 +67,149 @@ impl From for ErrorCode { } } -impl From for jsonrpc_core::Error { +impl From for JsonRpseeError { fn from(error: Error) -> Self { - let message = format!("{}", error); + let message = error.to_string(); let code = ErrorCode::from(error); - jsonrpc_core::Error { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + code as i32, message, - code: jsonrpc_core::ErrorCode::ServerError(code as i64), - data: None, - } + None::<()>, + ))) } } -/// Provides RPC methods for interacting with BEEFY. -#[rpc] +// Provides RPC methods for interacting with BEEFY. +#[rpc(client, server)] pub trait BeefyApi { - /// RPC Metadata - type Metadata; - /// Returns the block most recently finalized by BEEFY, alongside side its justification. - #[pubsub( - subscription = "beefy_justifications", - subscribe, - name = "beefy_subscribeJustifications" - )] - fn subscribe_justifications( - &self, - metadata: Self::Metadata, - subscriber: Subscriber, - ); - - /// Unsubscribe from receiving notifications about recently finalized blocks. - #[pubsub( - subscription = "beefy_justifications", - unsubscribe, - name = "beefy_unsubscribeJustifications" + #[subscription( + name = "beefy_subscribeJustifications" => "beefy_justifications", + unsubscribe = "beefy_unsubscribeJustifications", + item = Notification, )] - fn unsubscribe_justifications( - &self, - metadata: Option, - id: SubscriptionId, - ) -> jsonrpc_core::Result; + fn subscribe_justifications(&self); /// Returns hash of the latest BEEFY finalized block as seen by this client. /// /// The latest BEEFY block might not be available if the BEEFY gadget is not running /// in the network or if the client is still initializing or syncing with the network. /// In such case an error would be returned. - #[rpc(name = "beefy_getFinalizedHead")] - fn latest_finalized(&self) -> FutureResult; + #[method(name = "beefy_getFinalizedHead")] + async fn latest_finalized(&self) -> RpcResult; } /// Implements the BeefyApi RPC trait for interacting with BEEFY. pub struct BeefyRpcHandler { signed_commitment_stream: BeefySignedCommitmentStream, beefy_best_block: Arc>>, - manager: SubscriptionManager, + executor: SubscriptionTaskExecutor, } -impl BeefyRpcHandler { +impl BeefyRpcHandler +where + Block: BlockT, +{ /// Creates a new BeefyRpcHandler instance. - pub fn new( + pub fn new( signed_commitment_stream: BeefySignedCommitmentStream, best_block_stream: BeefyBestBlockStream, - executor: E, - ) -> Result - where - E: futures::task::Spawn + Send + Sync + 'static, - { + executor: SubscriptionTaskExecutor, + ) -> Result { let beefy_best_block = Arc::new(RwLock::new(None)); let stream = best_block_stream.subscribe(); let closure_clone = beefy_best_block.clone(); let future = stream.for_each(move |best_beefy| { let async_clone = closure_clone.clone(); - async move { - *async_clone.write() = Some(best_beefy); - } + async move { *async_clone.write() = Some(best_beefy) } }); - executor - .spawn_obj(futures::task::FutureObj::new(Box::pin(future))) - .map_err(|e| { - log::error!("Failed to spawn BEEFY RPC background task; err: {}", e); - e - })?; - - let manager = SubscriptionManager::new(Arc::new(executor)); - Ok(Self { signed_commitment_stream, beefy_best_block, manager }) + executor.spawn("substrate-rpc-subscription", Some("rpc"), future.map(drop).boxed()); + Ok(Self { signed_commitment_stream, beefy_best_block, executor }) } } -impl BeefyApi for BeefyRpcHandler +#[async_trait] +impl BeefyApiServer + for BeefyRpcHandler where Block: BlockT, { - type Metadata = sc_rpc::Metadata; - - fn subscribe_justifications( - &self, - _metadata: Self::Metadata, - subscriber: Subscriber, - ) { + fn subscribe_justifications(&self, pending: PendingSubscription) { let stream = self .signed_commitment_stream .subscribe() - .map(|x| Ok::<_, ()>(Ok(notification::EncodedSignedCommitment::new::(x)))); + .map(|sc| notification::EncodedSignedCommitment::new::(sc)); - self.manager.add(subscriber, |sink| { - stream - .forward(sink.sink_map_err(|e| warn!("Error sending notifications: {:?}", e))) - .map(|_| ()) - }); - } + let fut = async move { + if let Some(mut sink) = pending.accept() { + sink.pipe_from_stream(stream).await; + } + } + .boxed(); - fn unsubscribe_justifications( - &self, - _metadata: Option, - id: SubscriptionId, - ) -> jsonrpc_core::Result { - Ok(self.manager.cancel(id)) + self.executor + .spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); } - fn latest_finalized(&self) -> FutureResult { - let result: Result = self - .beefy_best_block + async fn latest_finalized(&self) -> RpcResult { + self.beefy_best_block .read() .as_ref() .cloned() - .ok_or_else(|| Error::EndpointNotReady.into()); - let future = async move { result }.boxed(); - future.map_err(jsonrpc_core::Error::from).boxed() + .ok_or(Error::EndpointNotReady) + .map_err(Into::into) } } #[cfg(test)] mod tests { use super::*; - use jsonrpc_core::{types::Params, Notification, Output}; - use beefy_gadget::notification::{BeefySignedCommitment, BeefySignedCommitmentSender}; + use beefy_gadget::notification::{ + BeefyBestBlockStream, BeefySignedCommitment, BeefySignedCommitmentSender, + }; use beefy_primitives::{known_payload_ids, Payload}; use codec::{Decode, Encode}; + use jsonrpsee::{types::EmptyParams, RpcModule}; use sp_runtime::traits::{BlakeTwo256, Hash}; use substrate_test_runtime_client::runtime::Block; - fn setup_io_handler( - ) -> (jsonrpc_core::MetaIoHandler, BeefySignedCommitmentSender) { + fn setup_io_handler() -> (RpcModule>, BeefySignedCommitmentSender) + { let (_, stream) = BeefyBestBlockStream::::channel(); setup_io_handler_with_best_block_stream(stream) } fn setup_io_handler_with_best_block_stream( best_block_stream: BeefyBestBlockStream, - ) -> (jsonrpc_core::MetaIoHandler, BeefySignedCommitmentSender) { + ) -> (RpcModule>, BeefySignedCommitmentSender) { let (commitment_sender, commitment_stream) = BeefySignedCommitmentStream::::channel(); - let handler: BeefyRpcHandler = BeefyRpcHandler::new( + let handler = BeefyRpcHandler::new( commitment_stream, best_block_stream, - sc_rpc::testing::TaskExecutor, + sc_rpc::testing::test_executor(), ) - .unwrap(); + .expect("Setting up the BEEFY RPC handler works"); - let mut io = jsonrpc_core::MetaIoHandler::default(); - io.extend_with(BeefyApi::to_delegate(handler)); - - (io, commitment_sender) - } - - fn setup_session() -> (sc_rpc::Metadata, futures::channel::mpsc::UnboundedReceiver) { - let (tx, rx) = futures::channel::mpsc::unbounded(); - let meta = sc_rpc::Metadata::new(tx); - (meta, rx) + (handler.into_rpc(), commitment_sender) } - #[test] - fn uninitialized_rpc_handler() { - let (io, _) = setup_io_handler(); - + #[tokio::test] + async fn uninitialized_rpc_handler() { + let (rpc, _) = setup_io_handler(); let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; - let response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"BEEFY RPC endpoint not ready"},"id":1}"#; + let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"BEEFY RPC endpoint not ready"},"id":1}"#.to_string(); + let (result, _) = rpc.raw_json_request(&request).await.unwrap(); - let meta = sc_rpc::Metadata::default(); - assert_eq!(Some(response.into()), io.handle_request_sync(request, meta)); + assert_eq!(expected_response, result,); } - #[test] - fn latest_finalized_rpc() { + #[tokio::test] + async fn latest_finalized_rpc() { let (sender, stream) = BeefyBestBlockStream::::channel(); let (io, _) = setup_io_handler_with_best_block_stream(stream); @@ -266,83 +223,78 @@ mod tests { \"jsonrpc\":\"2.0\",\ \"result\":\"0x2f0039e93a27221fcf657fb877a1d4f60307106113e885096cb44a461cd0afbf\",\ \"id\":1\ - }"; + }" + .to_string(); let not_ready = "{\ \"jsonrpc\":\"2.0\",\ \"error\":{\"code\":1,\"message\":\"BEEFY RPC endpoint not ready\"},\ \"id\":1\ - }"; + }" + .to_string(); let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2); while std::time::Instant::now() < deadline { - let meta = sc_rpc::Metadata::default(); - let response = io.handle_request_sync(request, meta); - // Retry "not ready" responses. - if response != Some(not_ready.into()) { - assert_eq!(response, Some(expected.into())); + let (response, _) = io.raw_json_request(request).await.expect("RPC requests work"); + if response != not_ready { + assert_eq!(response, expected); // Success return } - std::thread::sleep(std::time::Duration::from_millis(50)); + std::thread::sleep(std::time::Duration::from_millis(50)) } + panic!( "Deadline reached while waiting for best BEEFY block to update. Perhaps the background task is broken?" ); } - #[test] - fn subscribe_and_unsubscribe_to_justifications() { - let (io, _) = setup_io_handler(); - let (meta, _) = setup_session(); + #[tokio::test] + async fn subscribe_and_unsubscribe_to_justifications() { + let (rpc, _) = setup_io_handler(); - // Subscribe - let sub_request = - r#"{"jsonrpc":"2.0","method":"beefy_subscribeJustifications","params":[],"id":1}"#; - let resp = io.handle_request_sync(sub_request, meta.clone()); - let resp: Output = serde_json::from_str(&resp.unwrap()).unwrap(); + // Subscribe call. + let sub = rpc + .subscribe("beefy_subscribeJustifications", EmptyParams::new()) + .await + .unwrap(); - let sub_id = match resp { - Output::Success(success) => success.result, - _ => panic!(), - }; + let ser_id = serde_json::to_string(sub.subscription_id()).unwrap(); // Unsubscribe let unsub_req = format!( - r#"{{"jsonrpc":"2.0","method":"beefy_unsubscribeJustifications","params":[{}],"id":1}}"#, - sub_id - ); - assert_eq!( - io.handle_request_sync(&unsub_req, meta.clone()), - Some(r#"{"jsonrpc":"2.0","result":true,"id":1}"#.into()), + "{{\"jsonrpc\":\"2.0\",\"method\":\"beefy_unsubscribeJustifications\",\"params\":[{}],\"id\":1}}", + ser_id ); + let (response, _) = rpc.raw_json_request(&unsub_req).await.unwrap(); + + assert_eq!(response, r#"{"jsonrpc":"2.0","result":true,"id":1}"#); // Unsubscribe again and fail - assert_eq!( - io.handle_request_sync(&unsub_req, meta), - Some(r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid subscription id."},"id":1}"#.into()), - ); - } + let (response, _) = rpc.raw_json_request(&unsub_req).await.unwrap(); + let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; - #[test] - fn subscribe_and_unsubscribe_with_wrong_id() { - let (io, _) = setup_io_handler(); - let (meta, _) = setup_session(); + assert_eq!(response, expected); + } - // Subscribe - let sub_request = - r#"{"jsonrpc":"2.0","method":"beefy_subscribeJustifications","params":[],"id":1}"#; - let resp = io.handle_request_sync(sub_request, meta.clone()); - let resp: Output = serde_json::from_str(&resp.unwrap()).unwrap(); - assert!(matches!(resp, Output::Success(_))); + #[tokio::test] + async fn subscribe_and_unsubscribe_with_wrong_id() { + let (rpc, _) = setup_io_handler(); + // Subscribe call. + let _sub = rpc + .subscribe("beefy_subscribeJustifications", EmptyParams::new()) + .await + .unwrap(); // Unsubscribe with wrong ID - assert_eq!( - io.handle_request_sync( + let (response, _) = rpc + .raw_json_request( r#"{"jsonrpc":"2.0","method":"beefy_unsubscribeJustifications","params":["FOO"],"id":1}"#, - meta.clone() - ), - Some(r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid subscription id."},"id":1}"#.into()) - ); + ) + .await + .unwrap(); + let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; + + assert_eq!(response, expected); } fn create_commitment() -> BeefySignedCommitment { @@ -357,18 +309,15 @@ mod tests { } } - #[test] - fn subscribe_and_listen_to_one_justification() { - let (io, commitment_sender) = setup_io_handler(); - let (meta, receiver) = setup_session(); + #[tokio::test] + async fn subscribe_and_listen_to_one_justification() { + let (rpc, commitment_sender) = setup_io_handler(); // Subscribe - let sub_request = - r#"{"jsonrpc":"2.0","method":"beefy_subscribeJustifications","params":[],"id":1}"#; - - let resp = io.handle_request_sync(sub_request, meta.clone()); - let mut resp: serde_json::Value = serde_json::from_str(&resp.unwrap()).unwrap(); - let sub_id: String = serde_json::from_value(resp["result"].take()).unwrap(); + let mut sub = rpc + .subscribe("beefy_subscribeJustifications", EmptyParams::new()) + .await + .unwrap(); // Notify with commitment let commitment = create_commitment(); @@ -376,21 +325,10 @@ mod tests { r.unwrap(); // Inspect what we received - let recv = futures::executor::block_on(receiver.take(1).collect::>()); - let recv: Notification = serde_json::from_str(&recv[0]).unwrap(); - let mut json_map = match recv.params { - Params::Map(json_map) => json_map, - _ => panic!(), - }; - - let recv_sub_id: String = serde_json::from_value(json_map["subscription"].take()).unwrap(); - let recv_commitment: sp_core::Bytes = - serde_json::from_value(json_map["result"].take()).unwrap(); + let (bytes, recv_sub_id) = sub.next::().await.unwrap().unwrap(); let recv_commitment: BeefySignedCommitment = - Decode::decode(&mut &recv_commitment[..]).unwrap(); - - assert_eq!(recv.method, "beefy_justifications"); - assert_eq!(recv_sub_id, sub_id); + Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(&recv_sub_id, sub.subscription_id()); assert_eq!(recv_commitment, commitment); } } diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index dea1e2a6dae5b..6cb0de0ebd04c 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -100,18 +100,28 @@ pub struct RunCmd { #[clap(long)] pub unsafe_ws_external: bool, - /// Set the the maximum RPC payload size for both requests and responses (both http and ws), in - /// megabytes. Default is 15MiB. + /// DEPRECATED, this has no affect anymore. Use `rpc_max_request_size` or + /// `rpc_max_response_size` instead. #[clap(long)] pub rpc_max_payload: Option, + /// Set the the maximum RPC request payload size for both HTTP and WS in megabytes. + /// Default is 15MiB. + #[clap(long)] + pub rpc_max_request_size: Option, + + /// Set the the maximum RPC response payload size for both HTTP and WS in megabytes. + /// Default is 15MiB. + #[clap(long)] + pub rpc_max_response_size: Option, + /// Expose Prometheus exporter on all interfaces. /// /// Default is local. #[clap(long)] pub prometheus_external: bool, - /// Specify IPC RPC server path + /// DEPRECATED, IPC support has been removed. #[clap(long, value_name = "PATH")] pub ipc_path: Option, @@ -127,7 +137,7 @@ pub struct RunCmd { #[clap(long, value_name = "COUNT")] pub ws_max_connections: Option, - /// Set the the maximum WebSocket output buffer size in MiB. Default is 16. + /// DEPRECATED, this has no affect anymore. Use `rpc_max_response_size` instead. #[clap(long)] pub ws_max_out_buffer_capacity: Option, diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index aef1da8193757..e38d34b92c74d 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -359,6 +359,16 @@ pub trait CliConfiguration: Sized { Ok(None) } + /// Get maximum RPC request payload size. + fn rpc_max_request_size(&self) -> Result> { + Ok(None) + } + + /// Get maximum RPC response payload size. + fn rpc_max_response_size(&self) -> Result> { + Ok(None) + } + /// Get maximum WS output buffer capacity. fn ws_max_out_buffer_capacity(&self) -> Result> { Ok(None) @@ -526,6 +536,10 @@ pub trait CliConfiguration: Sized { rpc_ws_max_connections: self.rpc_ws_max_connections()?, rpc_cors: self.rpc_cors(is_dev)?, rpc_max_payload: self.rpc_max_payload()?, + rpc_max_request_size: self.rpc_max_request_size()?, + rpc_max_response_size: self.rpc_max_response_size()?, + rpc_id_provider: None, + rpc_max_subs_per_conn: None, ws_max_out_buffer_capacity: self.ws_max_out_buffer_capacity()?, prometheus_config: self .prometheus_config(DCV::prometheus_listen_port(), &chain_spec)?, diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 0e7141c77f8b2..4be5d1f8bba90 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -13,10 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } futures = "0.3.21" -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0" sc-consensus-babe = { version = "0.10.0-dev", path = "../" } @@ -34,6 +32,7 @@ sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] serde_json = "1.0.79" tempfile = "3.1.0" +tokio = "1.17.0" sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } sp-keyring = { version = "6.0.0", path = "../../../../primitives/keyring" } diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 2d0c81afc7775..d5f21606c62ed 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -18,9 +18,13 @@ //! RPC api for babe. -use futures::{FutureExt, TryFutureExt}; -use jsonrpc_core::Error as RpcError; -use jsonrpc_derive::rpc; +use futures::TryFutureExt; +use jsonrpsee::{ + core::{async_trait, Error as JsonRpseeError, RpcResult}, + proc_macros::rpc, + types::{error::CallError, ErrorObject}, +}; + use sc_consensus_babe::{authorship, Config, Epoch}; use sc_consensus_epochs::{descendent_query, Epoch as EpochT, SharedEpochChanges}; use sc_rpc_api::DenyUnsafe; @@ -35,19 +39,17 @@ use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::traits::{Block as BlockT, Header as _}; use std::{collections::HashMap, sync::Arc}; -type FutureResult = jsonrpc_core::BoxFuture>; - /// Provides rpc methods for interacting with Babe. -#[rpc] +#[rpc(client, server)] pub trait BabeApi { /// Returns data about which slots (primary or secondary) can be claimed in the current epoch /// with the keys in the keystore. - #[rpc(name = "babe_epochAuthorship")] - fn epoch_authorship(&self) -> FutureResult>; + #[method(name = "babe_epochAuthorship")] + async fn epoch_authorship(&self) -> RpcResult>; } -/// Implements the BabeRpc trait for interacting with Babe. -pub struct BabeRpcHandler { +/// Provides RPC methods for interacting with Babe. +pub struct BabeRpc { /// shared reference to the client. client: Arc, /// shared reference to EpochChanges @@ -62,7 +64,7 @@ pub struct BabeRpcHandler { deny_unsafe: DenyUnsafe, } -impl BabeRpcHandler { +impl BabeRpc { /// Creates a new instance of the BabeRpc handler. pub fn new( client: Arc, @@ -76,7 +78,8 @@ impl BabeRpcHandler { } } -impl BabeApi for BabeRpcHandler +#[async_trait] +impl BabeApiServer for BabeRpc where B: BlockT, C: ProvideRuntimeApi @@ -86,71 +89,63 @@ where C::Api: BabeRuntimeApi, SC: SelectChain + Clone + 'static, { - fn epoch_authorship(&self) -> FutureResult> { - if let Err(err) = self.deny_unsafe.check_if_safe() { - return async move { Err(err.into()) }.boxed() - } - - let (babe_config, keystore, shared_epoch, client, select_chain) = ( - self.babe_config.clone(), - self.keystore.clone(), - self.shared_epoch_changes.clone(), - self.client.clone(), - self.select_chain.clone(), - ); - - async move { - let header = select_chain.best_chain().map_err(Error::Consensus).await?; - let epoch_start = client - .runtime_api() - .current_epoch_start(&BlockId::Hash(header.hash())) - .map_err(|err| Error::StringError(err.to_string()))?; - let epoch = - epoch_data(&shared_epoch, &client, &babe_config, *epoch_start, &select_chain) - .await?; - let (epoch_start, epoch_end) = (epoch.start_slot(), epoch.end_slot()); - - let mut claims: HashMap = HashMap::new(); - - let keys = { - epoch - .authorities - .iter() - .enumerate() - .filter_map(|(i, a)| { - if SyncCryptoStore::has_keys( - &*keystore, - &[(a.0.to_raw_vec(), AuthorityId::ID)], - ) { - Some((a.0.clone(), i)) - } else { - None - } - }) - .collect::>() - }; - - for slot in *epoch_start..*epoch_end { - if let Some((claim, key)) = - authorship::claim_slot_using_keys(slot.into(), &epoch, &keystore, &keys) - { - match claim { - PreDigest::Primary { .. } => { - claims.entry(key).or_default().primary.push(slot); - }, - PreDigest::SecondaryPlain { .. } => { - claims.entry(key).or_default().secondary.push(slot); - }, - PreDigest::SecondaryVRF { .. } => { - claims.entry(key).or_default().secondary_vrf.push(slot); - }, - }; - } + async fn epoch_authorship(&self) -> RpcResult> { + self.deny_unsafe.check_if_safe()?; + let header = self.select_chain.best_chain().map_err(Error::Consensus).await?; + let epoch_start = self + .client + .runtime_api() + .current_epoch_start(&BlockId::Hash(header.hash())) + .map_err(|err| Error::StringError(format!("{:?}", err)))?; + + let epoch = epoch_data( + &self.shared_epoch_changes, + &self.client, + &self.babe_config, + *epoch_start, + &self.select_chain, + ) + .await?; + let (epoch_start, epoch_end) = (epoch.start_slot(), epoch.end_slot()); + let mut claims: HashMap = HashMap::new(); + + let keys = { + epoch + .authorities + .iter() + .enumerate() + .filter_map(|(i, a)| { + if SyncCryptoStore::has_keys( + &*self.keystore, + &[(a.0.to_raw_vec(), AuthorityId::ID)], + ) { + Some((a.0.clone(), i)) + } else { + None + } + }) + .collect::>() + }; + + for slot in *epoch_start..*epoch_end { + if let Some((claim, key)) = + authorship::claim_slot_using_keys(slot.into(), &epoch, &self.keystore, &keys) + { + match claim { + PreDigest::Primary { .. } => { + claims.entry(key).or_default().primary.push(slot); + }, + PreDigest::SecondaryPlain { .. } => { + claims.entry(key).or_default().secondary.push(slot); + }, + PreDigest::SecondaryVRF { .. } => { + claims.entry(key).or_default().secondary_vrf.push(slot.into()); + }, + }; } - - Ok(claims) } - .boxed() + + Ok(claims) } } @@ -176,13 +171,13 @@ pub enum Error { StringError(String), } -impl From for jsonrpc_core::Error { +impl From for JsonRpseeError { fn from(error: Error) -> Self { - jsonrpc_core::Error { - message: format!("{}", error), - code: jsonrpc_core::ErrorCode::ServerError(1234), - data: None, - } + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + 1234, + error.to_string(), + None::<()>, + ))) } } @@ -226,7 +221,6 @@ mod tests { TestClientBuilderExt, }; - use jsonrpc_core::IoHandler; use sc_consensus_babe::{block_import, AuthorityPair, Config}; use std::sync::Arc; @@ -243,9 +237,9 @@ mod tests { (keystore, keystore_path) } - fn test_babe_rpc_handler( + fn test_babe_rpc_module( deny_unsafe: DenyUnsafe, - ) -> BabeRpcHandler> { + ) -> BabeRpc> { let builder = TestClientBuilder::new(); let (client, longest_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); @@ -256,40 +250,30 @@ mod tests { let epoch_changes = link.epoch_changes().clone(); let keystore = create_temp_keystore::(Sr25519Keyring::Alice).0; - BabeRpcHandler::new( - client.clone(), - epoch_changes, - keystore, - config, - longest_chain, - deny_unsafe, - ) + BabeRpc::new(client.clone(), epoch_changes, keystore, config, longest_chain, deny_unsafe) } - #[test] - fn epoch_authorship_works() { - let handler = test_babe_rpc_handler(DenyUnsafe::No); - let mut io = IoHandler::new(); + #[tokio::test] + async fn epoch_authorship_works() { + let babe_rpc = test_babe_rpc_module(DenyUnsafe::No); + let api = babe_rpc.into_rpc(); - io.extend_with(BabeApi::to_delegate(handler)); let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params": [],"id":1}"#; - let response = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[1,2,4],"secondary_vrf":[]}},"id":1}"#; + let (response, _) = api.raw_json_request(request).await.unwrap(); + let expected = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[1,2,4],"secondary_vrf":[]}},"id":1}"#; - assert_eq!(Some(response.into()), io.handle_request_sync(request)); + assert_eq!(&response, expected); } - #[test] - fn epoch_authorship_is_unsafe() { - let handler = test_babe_rpc_handler(DenyUnsafe::Yes); - let mut io = IoHandler::new(); - - io.extend_with(BabeApi::to_delegate(handler)); - let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params": [],"id":1}"#; + #[tokio::test] + async fn epoch_authorship_is_unsafe() { + let babe_rpc = test_babe_rpc_module(DenyUnsafe::Yes); + let api = babe_rpc.into_rpc(); - let response = io.handle_request_sync(request).unwrap(); - let mut response: serde_json::Value = serde_json::from_str(&response).unwrap(); - let error: RpcError = serde_json::from_value(response["error"].take()).unwrap(); + let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params":[],"id":1}"#; + let (response, _) = api.raw_json_request(request).await.unwrap(); + let expected = r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"RPC call is unsafe to be called externally"},"id":1}"#; - assert_eq!(error, sc_rpc_api::UnsafeRpcError.into()) + assert_eq!(&response, expected); } } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 9452d2b1afd08..e8f4e20ab0e55 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -13,13 +13,11 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } assert_matches = "1.3.0" async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" log = "0.4.16" serde = { version = "1.0", features = ["derive"] } thiserror = "1.0" diff --git a/client/consensus/manual-seal/src/error.rs b/client/consensus/manual-seal/src/error.rs index 7c3211203bf54..a056c541c3cef 100644 --- a/client/consensus/manual-seal/src/error.rs +++ b/client/consensus/manual-seal/src/error.rs @@ -20,6 +20,10 @@ //! This is suitable for a testing environment. use futures::channel::{mpsc::SendError, oneshot}; +use jsonrpsee::{ + core::Error as JsonRpseeError, + types::error::{CallError, ErrorObject}, +}; use sc_consensus::ImportResult; use sp_blockchain::Error as BlockchainError; use sp_consensus::Error as ConsensusError; @@ -27,14 +31,14 @@ use sp_inherents::Error as InherentsError; /// Error code for rpc mod codes { - pub const SERVER_SHUTTING_DOWN: i64 = 10_000; - pub const BLOCK_IMPORT_FAILED: i64 = 11_000; - pub const EMPTY_TRANSACTION_POOL: i64 = 12_000; - pub const BLOCK_NOT_FOUND: i64 = 13_000; - pub const CONSENSUS_ERROR: i64 = 14_000; - pub const INHERENTS_ERROR: i64 = 15_000; - pub const BLOCKCHAIN_ERROR: i64 = 16_000; - pub const UNKNOWN_ERROR: i64 = 20_000; + pub const SERVER_SHUTTING_DOWN: i32 = 10_000; + pub const BLOCK_IMPORT_FAILED: i32 = 11_000; + pub const EMPTY_TRANSACTION_POOL: i32 = 12_000; + pub const BLOCK_NOT_FOUND: i32 = 13_000; + pub const CONSENSUS_ERROR: i32 = 14_000; + pub const INHERENTS_ERROR: i32 = 15_000; + pub const BLOCKCHAIN_ERROR: i32 = 16_000; + pub const UNKNOWN_ERROR: i32 = 20_000; } /// errors encountered by background block authorship task @@ -71,7 +75,7 @@ pub enum Error { SendError(#[from] SendError), /// Some other error. #[error("Other error: {0}")] - Other(#[from] Box), + Other(Box), } impl From for Error { @@ -87,7 +91,7 @@ impl From for Error { } impl Error { - fn to_code(&self) -> i64 { + fn to_code(&self) -> i32 { use Error::*; match self { BlockImportError(_) => codes::BLOCK_IMPORT_FAILED, @@ -102,12 +106,8 @@ impl Error { } } -impl From for jsonrpc_core::Error { - fn from(error: Error) -> Self { - jsonrpc_core::Error { - code: jsonrpc_core::ErrorCode::ServerError(error.to_code()), - message: format!("{}", error), - data: None, - } +impl From for JsonRpseeError { + fn from(err: Error) -> Self { + CallError::Custom(ErrorObject::owned(err.to_code(), err.to_string(), None::<()>)).into() } } diff --git a/client/consensus/manual-seal/src/rpc.rs b/client/consensus/manual-seal/src/rpc.rs index 4a8dcbc0cb765..b9bb06551f818 100644 --- a/client/consensus/manual-seal/src/rpc.rs +++ b/client/consensus/manual-seal/src/rpc.rs @@ -18,21 +18,21 @@ //! RPC interface for the `ManualSeal` Engine. -pub use self::gen_client::Client as ManualSealClient; +use crate::error::Error; use futures::{ channel::{mpsc, oneshot}, - FutureExt, SinkExt, TryFutureExt, + SinkExt, +}; +use jsonrpsee::{ + core::{async_trait, Error as JsonRpseeError, RpcResult}, + proc_macros::rpc, }; -use jsonrpc_core::Error; -use jsonrpc_derive::rpc; use sc_consensus::ImportedAux; use serde::{Deserialize, Serialize}; use sp_runtime::EncodedJustification; -/// Future's type for jsonrpc -type FutureResult = jsonrpc_core::BoxFuture>; -/// sender passed to the authorship task to report errors or successes. -pub type Sender = Option>>; +/// Sender passed to the authorship task to report errors or successes. +pub type Sender = Option>>; /// Message sent to the background authorship task, usually by RPC. pub enum EngineCommand { @@ -65,27 +65,27 @@ pub enum EngineCommand { } /// RPC trait that provides methods for interacting with the manual-seal authorship task over rpc. -#[rpc] +#[rpc(client, server)] pub trait ManualSealApi { /// Instructs the manual-seal authorship task to create a new block - #[rpc(name = "engine_createBlock")] - fn create_block( + #[method(name = "engine_createBlock")] + async fn create_block( &self, create_empty: bool, finalize: bool, parent_hash: Option, - ) -> FutureResult>; + ) -> RpcResult>; /// Instructs the manual-seal authorship task to finalize a block - #[rpc(name = "engine_finalizeBlock")] - fn finalize_block( + #[method(name = "engine_finalizeBlock")] + async fn finalize_block( &self, hash: Hash, justification: Option, - ) -> FutureResult; + ) -> RpcResult; } -/// A struct that implements the [`ManualSealApi`]. +/// A struct that implements the [`ManualSealApiServer`]. pub struct ManualSeal { import_block_channel: mpsc::Sender>, } @@ -106,44 +106,43 @@ impl ManualSeal { } } -impl ManualSealApi for ManualSeal { - fn create_block( +#[async_trait] +impl ManualSealApiServer for ManualSeal { + async fn create_block( &self, create_empty: bool, finalize: bool, parent_hash: Option, - ) -> FutureResult> { + ) -> RpcResult> { let mut sink = self.import_block_channel.clone(); - async move { - let (sender, receiver) = oneshot::channel(); - let command = EngineCommand::SealNewBlock { - create_empty, - finalize, - parent_hash, - sender: Some(sender), - }; - sink.send(command).await?; - receiver.await? + let (sender, receiver) = oneshot::channel(); + // NOTE: this sends a Result over the channel. + let command = EngineCommand::SealNewBlock { + create_empty, + finalize, + parent_hash, + sender: Some(sender), + }; + + sink.send(command).await?; + + match receiver.await { + Ok(Ok(rx)) => Ok(rx), + Ok(Err(e)) => Err(e.into()), + Err(e) => Err(JsonRpseeError::to_call_error(e)), } - .map_err(Error::from) - .boxed() } - fn finalize_block( + async fn finalize_block( &self, hash: Hash, justification: Option, - ) -> FutureResult { + ) -> RpcResult { let mut sink = self.import_block_channel.clone(); - async move { - let (sender, receiver) = oneshot::channel(); - sink.send(EngineCommand::FinalizeBlock { hash, sender: Some(sender), justification }) - .await?; - - receiver.await?.map(|_| true) - } - .map_err(Error::from) - .boxed() + let (sender, receiver) = oneshot::channel(); + let command = EngineCommand::FinalizeBlock { hash, sender: Some(sender), justification }; + sink.send(command).await?; + receiver.await.map(|_| true).map_err(|e| JsonRpseeError::to_call_error(e)) } } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 40a4150f8dd98..c124712e3fa84 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -12,10 +12,7 @@ homepage = "https://substrate.io" [dependencies] finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } futures = "0.3.16" -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" -jsonrpc-pubsub = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } log = "0.4.8" parity-scale-codec = { version = "3.0.0", features = ["derive"] } serde = { version = "1.0.105", features = ["derive"] } @@ -37,3 +34,4 @@ sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } +tokio = { version = "1.17.0", features = ["macros"] } diff --git a/client/finality-grandpa/rpc/src/error.rs b/client/finality-grandpa/rpc/src/error.rs index 845b4d99dcc1a..197c0b8a72102 100644 --- a/client/finality-grandpa/rpc/src/error.rs +++ b/client/finality-grandpa/rpc/src/error.rs @@ -16,6 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use jsonrpsee::{ + core::Error as JsonRpseeError, + types::error::{CallError, ErrorObject}, +}; + #[derive(Debug, thiserror::Error)] /// Top-level error type for the RPC handler pub enum Error { @@ -56,15 +61,15 @@ impl From for ErrorCode { } } -impl From for jsonrpc_core::Error { +impl From for JsonRpseeError { fn from(error: Error) -> Self { - let message = format!("{}", error); + let message = error.to_string(); let code = ErrorCode::from(error); - jsonrpc_core::Error { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + code as i32, message, - code: jsonrpc_core::ErrorCode::ServerError(code as i64), - data: None, - } + None::<()>, + ))) } } diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index 9c51bc3d226a7..82962d716d589 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -19,167 +19,137 @@ //! RPC API for GRANDPA. #![warn(missing_docs)] -use futures::{task::Spawn, FutureExt, SinkExt, StreamExt, TryFutureExt}; -use jsonrpc_derive::rpc; -use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; +use futures::{FutureExt, StreamExt}; use log::warn; use std::sync::Arc; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + proc_macros::rpc, + PendingSubscription, +}; + mod error; mod finality; mod notification; mod report; use sc_finality_grandpa::GrandpaJustificationStream; +use sc_rpc::SubscriptionTaskExecutor; use sp_runtime::traits::{Block as BlockT, NumberFor}; use finality::{EncodedFinalityProof, RpcFinalityProofProvider}; use notification::JustificationNotification; use report::{ReportAuthoritySet, ReportVoterState, ReportedRoundStates}; -type FutureResult = jsonrpc_core::BoxFuture>; - /// Provides RPC methods for interacting with GRANDPA. -#[rpc] +#[rpc(client, server)] pub trait GrandpaApi { - /// RPC Metadata - type Metadata; - /// Returns the state of the current best round state as well as the /// ongoing background rounds. - #[rpc(name = "grandpa_roundState")] - fn round_state(&self) -> FutureResult; + #[method(name = "grandpa_roundState")] + async fn round_state(&self) -> RpcResult; /// Returns the block most recently finalized by Grandpa, alongside /// side its justification. - #[pubsub( - subscription = "grandpa_justifications", - subscribe, - name = "grandpa_subscribeJustifications" - )] - fn subscribe_justifications( - &self, - metadata: Self::Metadata, - subscriber: Subscriber, - ); - - /// Unsubscribe from receiving notifications about recently finalized blocks. - #[pubsub( - subscription = "grandpa_justifications", - unsubscribe, - name = "grandpa_unsubscribeJustifications" + #[subscription( + name = "grandpa_subscribeJustifications" => "grandpa_justifications", + unsubscribe = "grandpa_unsubscribeJustifications", + item = Notification )] - fn unsubscribe_justifications( - &self, - metadata: Option, - id: SubscriptionId, - ) -> jsonrpc_core::Result; + fn subscribe_justifications(&self); /// Prove finality for the given block number by returning the Justification for the last block /// in the set and all the intermediary headers to link them together. - #[rpc(name = "grandpa_proveFinality")] - fn prove_finality(&self, block: Number) -> FutureResult>; + #[method(name = "grandpa_proveFinality")] + async fn prove_finality(&self, block: Number) -> RpcResult>; } -/// Implements the GrandpaApi RPC trait for interacting with GRANDPA. -pub struct GrandpaRpcHandler { +/// Provides RPC methods for interacting with GRANDPA. +pub struct GrandpaRpc { + executor: SubscriptionTaskExecutor, authority_set: AuthoritySet, voter_state: VoterState, justification_stream: GrandpaJustificationStream, - manager: SubscriptionManager, finality_proof_provider: Arc, } - impl - GrandpaRpcHandler + GrandpaRpc { - /// Creates a new GrandpaRpcHandler instance. - pub fn new( + /// Prepare a new [`GrandpaRpc`] + pub fn new( + executor: SubscriptionTaskExecutor, authority_set: AuthoritySet, voter_state: VoterState, justification_stream: GrandpaJustificationStream, - executor: E, finality_proof_provider: Arc, - ) -> Self - where - E: Spawn + Sync + Send + 'static, - { - let manager = SubscriptionManager::new(Arc::new(executor)); - Self { authority_set, voter_state, justification_stream, manager, finality_proof_provider } + ) -> Self { + Self { executor, authority_set, voter_state, justification_stream, finality_proof_provider } } } +#[async_trait] impl - GrandpaApi> - for GrandpaRpcHandler + GrandpaApiServer> + for GrandpaRpc where VoterState: ReportVoterState + Send + Sync + 'static, AuthoritySet: ReportAuthoritySet + Send + Sync + 'static, Block: BlockT, ProofProvider: RpcFinalityProofProvider + Send + Sync + 'static, { - type Metadata = sc_rpc::Metadata; - - fn round_state(&self) -> FutureResult { - let round_states = ReportedRoundStates::from(&self.authority_set, &self.voter_state); - let future = async move { round_states }.boxed(); - future.map_err(jsonrpc_core::Error::from).boxed() + async fn round_state(&self) -> RpcResult { + ReportedRoundStates::from(&self.authority_set, &self.voter_state).map_err(Into::into) } - fn subscribe_justifications( - &self, - _metadata: Self::Metadata, - subscriber: Subscriber, - ) { - let stream = self - .justification_stream - .subscribe() - .map(|x| Ok(Ok::<_, jsonrpc_core::Error>(JustificationNotification::from(x)))); - - self.manager.add(subscriber, |sink| { - stream - .forward(sink.sink_map_err(|e| warn!("Error sending notifications: {:?}", e))) - .map(|_| ()) - }); - } + fn subscribe_justifications(&self, pending: PendingSubscription) { + let stream = self.justification_stream.subscribe().map( + |x: sc_finality_grandpa::GrandpaJustification| { + JustificationNotification::from(x) + }, + ); - fn unsubscribe_justifications( - &self, - _metadata: Option, - id: SubscriptionId, - ) -> jsonrpc_core::Result { - Ok(self.manager.cancel(id)) + let fut = async move { + if let Some(mut sink) = pending.accept() { + sink.pipe_from_stream(stream).await; + } + } + .boxed(); + + self.executor + .spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); } - fn prove_finality( + async fn prove_finality( &self, block: NumberFor, - ) -> FutureResult> { - let result = self.finality_proof_provider.rpc_prove_finality(block); - let future = async move { result }.boxed(); - future + ) -> RpcResult> { + self.finality_proof_provider + .rpc_prove_finality(block) .map_err(|e| { warn!("Error proving finality: {}", e); error::Error::ProveFinalityFailed(e) }) - .map_err(jsonrpc_core::Error::from) - .boxed() + .map_err(Into::into) } } #[cfg(test)] mod tests { use super::*; - use jsonrpc_core::{types::Params, Notification, Output}; - use std::{collections::HashSet, sync::Arc}; + use std::{collections::HashSet, convert::TryInto, sync::Arc}; + use jsonrpsee::{ + types::{EmptyParams, SubscriptionId}, + RpcModule, + }; use parity_scale_codec::{Decode, Encode}; use sc_block_builder::{BlockBuilder, RecordProof}; use sc_finality_grandpa::{ report, AuthorityId, FinalityProof, GrandpaJustification, GrandpaJustificationSender, }; use sp_blockchain::HeaderBackend; - use sp_core::crypto::ByteArray; + use sp_core::{crypto::ByteArray, testing::TaskExecutor}; use sp_keyring::Ed25519Keyring; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use substrate_test_runtime_client::{ @@ -274,7 +244,10 @@ mod tests { fn setup_io_handler( voter_state: VoterState, - ) -> (jsonrpc_core::MetaIoHandler, GrandpaJustificationSender) + ) -> ( + RpcModule>, + GrandpaJustificationSender, + ) where VoterState: ReportVoterState + Send + Sync + 'static, { @@ -284,120 +257,107 @@ mod tests { fn setup_io_handler_with_finality_proofs( voter_state: VoterState, finality_proof: Option>, - ) -> (jsonrpc_core::MetaIoHandler, GrandpaJustificationSender) + ) -> ( + RpcModule>, + GrandpaJustificationSender, + ) where VoterState: ReportVoterState + Send + Sync + 'static, { let (justification_sender, justification_stream) = GrandpaJustificationStream::channel(); let finality_proof_provider = Arc::new(TestFinalityProofProvider { finality_proof }); + let executor = Arc::new(TaskExecutor::default()); - let handler = GrandpaRpcHandler::new( + let rpc = GrandpaRpc::new( + executor, TestAuthoritySet, voter_state, justification_stream, - sc_rpc::testing::TaskExecutor, finality_proof_provider, - ); - - let mut io = jsonrpc_core::MetaIoHandler::default(); - io.extend_with(GrandpaApi::to_delegate(handler)); + ) + .into_rpc(); - (io, justification_sender) + (rpc, justification_sender) } - #[test] - fn uninitialized_rpc_handler() { - let (io, _) = setup_io_handler(EmptyVoterState); - - let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":1}"#; - let response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"GRANDPA RPC endpoint not ready"},"id":1}"#; + #[tokio::test] + async fn uninitialized_rpc_handler() { + let (rpc, _) = setup_io_handler(EmptyVoterState); + let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"GRANDPA RPC endpoint not ready"},"id":0}"#.to_string(); + let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; + let (result, _) = rpc.raw_json_request(&request).await.unwrap(); - let meta = sc_rpc::Metadata::default(); - assert_eq!(Some(response.into()), io.handle_request_sync(request, meta)); + assert_eq!(expected_response, result,); } - #[test] - fn working_rpc_handler() { - let (io, _) = setup_io_handler(TestVoterState); - - let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":1}"#; - let response = "{\"jsonrpc\":\"2.0\",\"result\":{\ - \"background\":[{\ - \"precommits\":{\"currentWeight\":100,\"missing\":[]},\ - \"prevotes\":{\"currentWeight\":100,\"missing\":[]},\ - \"round\":1,\"thresholdWeight\":67,\"totalWeight\":100\ - }],\ + #[tokio::test] + async fn working_rpc_handler() { + let (rpc, _) = setup_io_handler(TestVoterState); + let expected_response = "{\"jsonrpc\":\"2.0\",\"result\":{\ + \"setId\":1,\ \"best\":{\ - \"precommits\":{\"currentWeight\":0,\"missing\":[\"5C62Ck4UrFPiBtoCmeSrgF7x9yv9mn38446dhCpsi2mLHiFT\",\"5C7LYpP2ZH3tpKbvVvwiVe54AapxErdPBbvkYhe6y9ZBkqWt\"]},\ + \"round\":2,\"totalWeight\":100,\"thresholdWeight\":67,\ \"prevotes\":{\"currentWeight\":50,\"missing\":[\"5C7LYpP2ZH3tpKbvVvwiVe54AapxErdPBbvkYhe6y9ZBkqWt\"]},\ - \"round\":2,\"thresholdWeight\":67,\"totalWeight\":100\ + \"precommits\":{\"currentWeight\":0,\"missing\":[\"5C62Ck4UrFPiBtoCmeSrgF7x9yv9mn38446dhCpsi2mLHiFT\",\"5C7LYpP2ZH3tpKbvVvwiVe54AapxErdPBbvkYhe6y9ZBkqWt\"]}\ },\ - \"setId\":1\ - },\"id\":1}"; - - let meta = sc_rpc::Metadata::default(); - assert_eq!(io.handle_request_sync(request, meta), Some(response.into())); - } + \"background\":[{\ + \"round\":1,\"totalWeight\":100,\"thresholdWeight\":67,\ + \"prevotes\":{\"currentWeight\":100,\"missing\":[]},\ + \"precommits\":{\"currentWeight\":100,\"missing\":[]}\ + }]\ + },\"id\":0}".to_string(); - fn setup_session() -> (sc_rpc::Metadata, futures::channel::mpsc::UnboundedReceiver) { - let (tx, rx) = futures::channel::mpsc::unbounded(); - let meta = sc_rpc::Metadata::new(tx); - (meta, rx) + let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; + let (result, _) = rpc.raw_json_request(&request).await.unwrap(); + assert_eq!(expected_response, result); } - #[test] - fn subscribe_and_unsubscribe_to_justifications() { - let (io, _) = setup_io_handler(TestVoterState); - let (meta, _) = setup_session(); + #[tokio::test] + async fn subscribe_and_unsubscribe_to_justifications() { + let (rpc, _) = setup_io_handler(TestVoterState); + // Subscribe call. + let sub = rpc + .subscribe("grandpa_subscribeJustifications", EmptyParams::new()) + .await + .unwrap(); - // Subscribe - let sub_request = - r#"{"jsonrpc":"2.0","method":"grandpa_subscribeJustifications","params":[],"id":1}"#; - let resp = io.handle_request_sync(sub_request, meta.clone()); - let resp: Output = serde_json::from_str(&resp.unwrap()).unwrap(); - - let sub_id = match resp { - Output::Success(success) => success.result, - _ => panic!(), - }; + let ser_id = serde_json::to_string(sub.subscription_id()).unwrap(); // Unsubscribe let unsub_req = format!( "{{\"jsonrpc\":\"2.0\",\"method\":\"grandpa_unsubscribeJustifications\",\"params\":[{}],\"id\":1}}", - sub_id - ); - assert_eq!( - io.handle_request_sync(&unsub_req, meta.clone()), - Some(r#"{"jsonrpc":"2.0","result":true,"id":1}"#.into()), + ser_id ); + let (response, _) = rpc.raw_json_request(&unsub_req).await.unwrap(); + + assert_eq!(response, r#"{"jsonrpc":"2.0","result":true,"id":1}"#); // Unsubscribe again and fail - assert_eq!( - io.handle_request_sync(&unsub_req, meta), - Some("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32602,\"message\":\"Invalid subscription id.\"},\"id\":1}".into()), - ); - } + let (response, _) = rpc.raw_json_request(&unsub_req).await.unwrap(); + let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; - #[test] - fn subscribe_and_unsubscribe_with_wrong_id() { - let (io, _) = setup_io_handler(TestVoterState); - let (meta, _) = setup_session(); + assert_eq!(response, expected); + } - // Subscribe - let sub_request = - r#"{"jsonrpc":"2.0","method":"grandpa_subscribeJustifications","params":[],"id":1}"#; - let resp = io.handle_request_sync(sub_request, meta.clone()); - let resp: Output = serde_json::from_str(&resp.unwrap()).unwrap(); - assert!(matches!(resp, Output::Success(_))); + #[tokio::test] + async fn subscribe_and_unsubscribe_with_wrong_id() { + let (rpc, _) = setup_io_handler(TestVoterState); + // Subscribe call. + let _sub = rpc + .subscribe("grandpa_subscribeJustifications", EmptyParams::new()) + .await + .unwrap(); // Unsubscribe with wrong ID - assert_eq!( - io.handle_request_sync( + let (response, _) = rpc + .raw_json_request( r#"{"jsonrpc":"2.0","method":"grandpa_unsubscribeJustifications","params":["FOO"],"id":1}"#, - meta.clone() - ), - Some("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32602,\"message\":\"Invalid subscription id.\"},\"id\":1}".into()) - ); + ) + .await + .unwrap(); + let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; + + assert_eq!(response, expected); } fn create_justification() -> GrandpaJustification { @@ -454,60 +414,41 @@ mod tests { justification } - #[test] - fn subscribe_and_listen_to_one_justification() { - let (io, justification_sender) = setup_io_handler(TestVoterState); - let (meta, receiver) = setup_session(); - - // Subscribe - let sub_request = - r#"{"jsonrpc":"2.0","method":"grandpa_subscribeJustifications","params":[],"id":1}"#; + #[tokio::test] + async fn subscribe_and_listen_to_one_justification() { + let (rpc, justification_sender) = setup_io_handler(TestVoterState); - let resp = io.handle_request_sync(sub_request, meta.clone()); - let mut resp: serde_json::Value = serde_json::from_str(&resp.unwrap()).unwrap(); - let sub_id: String = serde_json::from_value(resp["result"].take()).unwrap(); + let mut sub = rpc + .subscribe("grandpa_subscribeJustifications", EmptyParams::new()) + .await + .unwrap(); // Notify with a header and justification let justification = create_justification(); justification_sender.notify(|| Ok::<_, ()>(justification.clone())).unwrap(); // Inspect what we received - let recv = futures::executor::block_on(receiver.take(1).collect::>()); - let recv: Notification = serde_json::from_str(&recv[0]).unwrap(); - let mut json_map = match recv.params { - Params::Map(json_map) => json_map, - _ => panic!(), - }; - - let recv_sub_id: String = serde_json::from_value(json_map["subscription"].take()).unwrap(); - let recv_justification: sp_core::Bytes = - serde_json::from_value(json_map["result"].take()).unwrap(); + let (recv_justification, recv_sub_id): (sp_core::Bytes, SubscriptionId) = + sub.next().await.unwrap().unwrap(); let recv_justification: GrandpaJustification = Decode::decode(&mut &recv_justification[..]).unwrap(); - assert_eq!(recv.method, "grandpa_justifications"); - assert_eq!(recv_sub_id, sub_id); + assert_eq!(&recv_sub_id, sub.subscription_id()); assert_eq!(recv_justification, justification); } - #[test] - fn prove_finality_with_test_finality_proof_provider() { + #[tokio::test] + async fn prove_finality_with_test_finality_proof_provider() { let finality_proof = FinalityProof { block: header(42).hash(), justification: create_justification().encode(), unknown_headers: vec![header(2)], }; - let (io, _) = + let (rpc, _) = setup_io_handler_with_finality_proofs(TestVoterState, Some(finality_proof.clone())); - let request = - "{\"jsonrpc\":\"2.0\",\"method\":\"grandpa_proveFinality\",\"params\":[42],\"id\":1}"; - - let meta = sc_rpc::Metadata::default(); - let resp = io.handle_request_sync(request, meta); - let mut resp: serde_json::Value = serde_json::from_str(&resp.unwrap()).unwrap(); - let result: sp_core::Bytes = serde_json::from_value(resp["result"].take()).unwrap(); - let finality_proof_rpc: FinalityProof
= Decode::decode(&mut &result[..]).unwrap(); + let bytes: sp_core::Bytes = rpc.call("grandpa_proveFinality", [42]).await.unwrap(); + let finality_proof_rpc: FinalityProof
= Decode::decode(&mut &bytes[..]).unwrap(); assert_eq!(finality_proof_rpc, finality_proof); } } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 0287b0fd30799..f8dfaab2a58a3 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -15,10 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" -jsonrpc-pubsub = "18.0.0" log = "0.4.16" parking_lot = "0.12.0" scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } @@ -32,3 +28,4 @@ sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-version = { version = "5.0.0", path = "../../primitives/version" } +jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } diff --git a/client/rpc-api/src/author/error.rs b/client/rpc-api/src/author/error.rs index 1f8c65c471398..57a27d48de3ad 100644 --- a/client/rpc-api/src/author/error.rs +++ b/client/rpc-api/src/author/error.rs @@ -18,28 +18,27 @@ //! Authoring RPC module errors. -use crate::errors; -use jsonrpc_core as rpc; +use jsonrpsee::{ + core::Error as JsonRpseeError, + types::error::{CallError, ErrorObject}, +}; use sp_runtime::transaction_validity::InvalidTransaction; /// Author RPC Result type. pub type Result = std::result::Result; -/// Author RPC future Result type. -pub type FutureResult = jsonrpc_core::BoxFuture>; - /// Author RPC errors. #[derive(Debug, thiserror::Error)] pub enum Error { /// Client error. #[error("Client error: {}", .0)] - Client(Box), + Client(Box), /// Transaction pool error, #[error("Transaction pool error: {}", .0)] Pool(#[from] sc_transaction_pool_api::error::Error), /// Verification error #[error("Extrinsic verification error: {}", .0)] - Verification(Box), + Verification(Box), /// Incorrect extrinsic format. #[error("Invalid extrinsic format: {}", .0)] BadFormat(#[from] codec::Error), @@ -58,98 +57,127 @@ pub enum Error { } /// Base code for all authorship errors. -const BASE_ERROR: i64 = 1000; +const BASE_ERROR: i32 = 1000; /// Extrinsic has an invalid format. -const BAD_FORMAT: i64 = BASE_ERROR + 1; +const BAD_FORMAT: i32 = BASE_ERROR + 1; /// Error during transaction verification in runtime. -const VERIFICATION_ERROR: i64 = BASE_ERROR + 2; +const VERIFICATION_ERROR: i32 = BASE_ERROR + 2; /// Pool rejected the transaction as invalid -const POOL_INVALID_TX: i64 = BASE_ERROR + 10; +const POOL_INVALID_TX: i32 = BASE_ERROR + 10; /// Cannot determine transaction validity. -const POOL_UNKNOWN_VALIDITY: i64 = POOL_INVALID_TX + 1; +const POOL_UNKNOWN_VALIDITY: i32 = POOL_INVALID_TX + 1; /// The transaction is temporarily banned. -const POOL_TEMPORARILY_BANNED: i64 = POOL_INVALID_TX + 2; +const POOL_TEMPORARILY_BANNED: i32 = POOL_INVALID_TX + 2; /// The transaction is already in the pool -const POOL_ALREADY_IMPORTED: i64 = POOL_INVALID_TX + 3; +const POOL_ALREADY_IMPORTED: i32 = POOL_INVALID_TX + 3; /// Transaction has too low priority to replace existing one in the pool. -const POOL_TOO_LOW_PRIORITY: i64 = POOL_INVALID_TX + 4; +const POOL_TOO_LOW_PRIORITY: i32 = POOL_INVALID_TX + 4; /// Including this transaction would cause a dependency cycle. -const POOL_CYCLE_DETECTED: i64 = POOL_INVALID_TX + 5; +const POOL_CYCLE_DETECTED: i32 = POOL_INVALID_TX + 5; /// The transaction was not included to the pool because of the limits. -const POOL_IMMEDIATELY_DROPPED: i64 = POOL_INVALID_TX + 6; +const POOL_IMMEDIATELY_DROPPED: i32 = POOL_INVALID_TX + 6; /// The transaction was not included to the pool since it is unactionable, /// it is not propagable and the local node does not author blocks. -const POOL_UNACTIONABLE: i64 = POOL_INVALID_TX + 8; +const POOL_UNACTIONABLE: i32 = POOL_INVALID_TX + 8; +/// Transaction does not provide any tags, so the pool can't identify it. +const POOL_NO_TAGS: i32 = POOL_INVALID_TX + 9; +/// Invalid block ID. +const POOL_INVALID_BLOCK_ID: i32 = POOL_INVALID_TX + 10; +/// The pool is not accepting future transactions. +const POOL_FUTURE_TX: i32 = POOL_INVALID_TX + 11; -impl From for rpc::Error { +impl From for JsonRpseeError { fn from(e: Error) -> Self { use sc_transaction_pool_api::error::Error as PoolError; match e { - Error::BadFormat(e) => rpc::Error { - code: rpc::ErrorCode::ServerError(BAD_FORMAT), - message: format!("Extrinsic has invalid format: {}", e), - data: None, - }, - Error::Verification(e) => rpc::Error { - code: rpc::ErrorCode::ServerError(VERIFICATION_ERROR), - message: format!("Verification Error: {}", e), - data: Some(e.to_string().into()), - }, - Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Custom(e))) => rpc::Error { - code: rpc::ErrorCode::ServerError(POOL_INVALID_TX), - message: "Invalid Transaction".into(), - data: Some(format!("Custom error: {}", e).into()), + Error::BadFormat(e) => CallError::Custom(ErrorObject::owned( + BAD_FORMAT, + format!("Extrinsic has invalid format: {}", e), + None::<()>, + )), + Error::Verification(e) => CallError::Custom(ErrorObject::owned( + VERIFICATION_ERROR, + format!("Verification Error: {}", e), + Some(format!("{:?}", e)), + )), + Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Custom(e))) => { + CallError::Custom(ErrorObject::owned( + POOL_INVALID_TX, + "Invalid Transaction", + Some(format!("Custom error: {}", e)), + )) }, Error::Pool(PoolError::InvalidTransaction(e)) => { let msg: &str = e.into(); - rpc::Error { - code: rpc::ErrorCode::ServerError(POOL_INVALID_TX), - message: "Invalid Transaction".into(), - data: Some(msg.into()), - } - }, - Error::Pool(PoolError::UnknownTransaction(e)) => rpc::Error { - code: rpc::ErrorCode::ServerError(POOL_UNKNOWN_VALIDITY), - message: "Unknown Transaction Validity".into(), - data: serde_json::to_value(e).ok(), - }, - Error::Pool(PoolError::TemporarilyBanned) => rpc::Error { - code: rpc::ErrorCode::ServerError(POOL_TEMPORARILY_BANNED), - message: "Transaction is temporarily banned".into(), - data: None, - }, - Error::Pool(PoolError::AlreadyImported(hash)) => rpc::Error { - code: rpc::ErrorCode::ServerError(POOL_ALREADY_IMPORTED), - message: "Transaction Already Imported".into(), - data: Some(format!("{:?}", hash).into()), - }, - Error::Pool(PoolError::TooLowPriority { old, new }) => rpc::Error { - code: rpc::ErrorCode::ServerError(POOL_TOO_LOW_PRIORITY), - message: format!("Priority is too low: ({} vs {})", old, new), - data: Some("The transaction has too low priority to replace another transaction already in the pool.".into()), - }, - Error::Pool(PoolError::CycleDetected) => rpc::Error { - code: rpc::ErrorCode::ServerError(POOL_CYCLE_DETECTED), - message: "Cycle Detected".into(), - data: None, + CallError::Custom(ErrorObject::owned( + POOL_INVALID_TX, + "Invalid Transaction", + Some(msg), + )) }, - Error::Pool(PoolError::ImmediatelyDropped) => rpc::Error { - code: rpc::ErrorCode::ServerError(POOL_IMMEDIATELY_DROPPED), - message: "Immediately Dropped".into(), - data: Some("The transaction couldn't enter the pool because of the limit".into()), + Error::Pool(PoolError::UnknownTransaction(e)) => { + CallError::Custom(ErrorObject::owned( + POOL_UNKNOWN_VALIDITY, + "Unknown Transaction Validity", + Some(format!("{:?}", e)), + )) }, - Error::Pool(PoolError::Unactionable) => rpc::Error { - code: rpc::ErrorCode::ServerError(POOL_UNACTIONABLE), - message: "Unactionable".into(), - data: Some( - "The transaction is unactionable since it is not propagable and \ - the local node does not author blocks".into(), - ), + Error::Pool(PoolError::TemporarilyBanned) => + CallError::Custom(ErrorObject::owned( + POOL_TEMPORARILY_BANNED, + "Transaction is temporarily banned", + None::<()>, + )), + Error::Pool(PoolError::AlreadyImported(hash)) => + CallError::Custom(ErrorObject::owned( + POOL_ALREADY_IMPORTED, + "Transaction Already Imported", + Some(format!("{:?}", hash)), + )), + Error::Pool(PoolError::TooLowPriority { old, new }) => CallError::Custom(ErrorObject::owned( + POOL_TOO_LOW_PRIORITY, + format!("Priority is too low: ({} vs {})", old, new), + Some("The transaction has too low priority to replace another transaction already in the pool.") + )), + Error::Pool(PoolError::CycleDetected) => + CallError::Custom(ErrorObject::owned( + POOL_CYCLE_DETECTED, + "Cycle Detected", + None::<()> + )), + Error::Pool(PoolError::ImmediatelyDropped) => CallError::Custom(ErrorObject::owned( + POOL_IMMEDIATELY_DROPPED, + "Immediately Dropped", + Some("The transaction couldn't enter the pool because of the limit"), + )), + Error::Pool(PoolError::Unactionable) => CallError::Custom(ErrorObject::owned( + POOL_UNACTIONABLE, + "Unactionable", + Some("The transaction is unactionable since it is not propagable and \ + the local node does not author blocks") + )), + Error::Pool(PoolError::NoTagsProvided) => CallError::Custom(ErrorObject::owned( + POOL_NO_TAGS, + "No tags provided", + Some("Transaction does not provide any tags, so the pool can't identify it") + )), + Error::Pool(PoolError::InvalidBlockId(_)) => + CallError::Custom(ErrorObject::owned( + POOL_INVALID_BLOCK_ID, + "The provided block ID is not valid", + None::<()> + )), + Error::Pool(PoolError::RejectedFutureTransaction) => { + CallError::Custom(ErrorObject::owned( + POOL_FUTURE_TX, + "The pool is not accepting future transactions", + None::<()>, + )) }, Error::UnsafeRpcCalled(e) => e.into(), - e => errors::internal(e), - } + e => CallError::Failed(e.into()), + }.into() } } diff --git a/client/rpc-api/src/author/mod.rs b/client/rpc-api/src/author/mod.rs index 84167ee95d108..feba7640e3b9f 100644 --- a/client/rpc-api/src/author/mod.rs +++ b/client/rpc-api/src/author/mod.rs @@ -18,85 +18,61 @@ //! Substrate block-author/full-node API. -pub mod error; -pub mod hash; - -use self::error::{FutureResult, Result}; -use jsonrpc_derive::rpc; -use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use sc_transaction_pool_api::TransactionStatus; use sp_core::Bytes; -pub use self::gen_client::Client as AuthorClient; +pub mod error; +pub mod hash; /// Substrate authoring RPC API -#[rpc] +#[rpc(client, server)] pub trait AuthorApi { - /// RPC metadata - type Metadata; - /// Submit hex-encoded extrinsic for inclusion in block. - #[rpc(name = "author_submitExtrinsic")] - fn submit_extrinsic(&self, extrinsic: Bytes) -> FutureResult; + #[method(name = "author_submitExtrinsic")] + async fn submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult; /// Insert a key into the keystore. - #[rpc(name = "author_insertKey")] - fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> Result<()>; + #[method(name = "author_insertKey")] + fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> RpcResult<()>; /// Generate new session keys and returns the corresponding public keys. - #[rpc(name = "author_rotateKeys")] - fn rotate_keys(&self) -> Result; + #[method(name = "author_rotateKeys")] + fn rotate_keys(&self) -> RpcResult; /// Checks if the keystore has private keys for the given session public keys. /// /// `session_keys` is the SCALE encoded session keys object from the runtime. /// /// Returns `true` iff all private keys could be found. - #[rpc(name = "author_hasSessionKeys")] - fn has_session_keys(&self, session_keys: Bytes) -> Result; + #[method(name = "author_hasSessionKeys")] + fn has_session_keys(&self, session_keys: Bytes) -> RpcResult; /// Checks if the keystore has private keys for the given public key and key type. /// /// Returns `true` if a private key could be found. - #[rpc(name = "author_hasKey")] - fn has_key(&self, public_key: Bytes, key_type: String) -> Result; + #[method(name = "author_hasKey")] + fn has_key(&self, public_key: Bytes, key_type: String) -> RpcResult; /// Returns all pending extrinsics, potentially grouped by sender. - #[rpc(name = "author_pendingExtrinsics")] - fn pending_extrinsics(&self) -> Result>; + #[method(name = "author_pendingExtrinsics")] + fn pending_extrinsics(&self) -> RpcResult>; /// Remove given extrinsic from the pool and temporarily ban it to prevent reimporting. - #[rpc(name = "author_removeExtrinsic")] + #[method(name = "author_removeExtrinsic")] fn remove_extrinsic( &self, bytes_or_hash: Vec>, - ) -> Result>; + ) -> RpcResult>; /// Submit an extrinsic to watch. /// /// See [`TransactionStatus`](sc_transaction_pool_api::TransactionStatus) for details on /// transaction life cycle. - #[pubsub( - subscription = "author_extrinsicUpdate", - subscribe, - name = "author_submitAndWatchExtrinsic" + #[subscription( + name = "author_submitAndWatchExtrinsic" => "author_extrinsicUpdate", + unsubscribe = "author_unwatchExtrinsic", + item = TransactionStatus, )] - fn watch_extrinsic( - &self, - metadata: Self::Metadata, - subscriber: Subscriber>, - bytes: Bytes, - ); - - /// Unsubscribe from extrinsic watching. - #[pubsub( - subscription = "author_extrinsicUpdate", - unsubscribe, - name = "author_unwatchExtrinsic" - )] - fn unwatch_extrinsic( - &self, - metadata: Option, - id: SubscriptionId, - ) -> Result; + fn watch_extrinsic(&self, bytes: Bytes); } diff --git a/client/rpc-api/src/chain/error.rs b/client/rpc-api/src/chain/error.rs index a0cacb6739155..670e221cf1cde 100644 --- a/client/rpc-api/src/chain/error.rs +++ b/client/rpc-api/src/chain/error.rs @@ -18,38 +18,33 @@ //! Error helpers for Chain RPC module. -use crate::errors; -use jsonrpc_core as rpc; - +use jsonrpsee::{ + core::Error as JsonRpseeError, + types::error::{CallError, ErrorObject}, +}; /// Chain RPC Result type. pub type Result = std::result::Result; -/// Chain RPC future Result type. -pub type FutureResult = jsonrpc_core::BoxFuture>; - /// Chain RPC errors. #[derive(Debug, thiserror::Error)] pub enum Error { /// Client error. #[error("Client error: {}", .0)] - Client(#[from] Box), + Client(#[from] Box), /// Other error type. #[error("{0}")] Other(String), } /// Base error code for all chain errors. -const BASE_ERROR: i64 = 3000; +const BASE_ERROR: i32 = 3000; -impl From for rpc::Error { +impl From for JsonRpseeError { fn from(e: Error) -> Self { match e { - Error::Other(message) => rpc::Error { - code: rpc::ErrorCode::ServerError(BASE_ERROR + 1), - message, - data: None, - }, - e => errors::internal(e), + Error::Other(message) => + CallError::Custom(ErrorObject::owned(BASE_ERROR + 1, message, None::<()>)).into(), + e => e.into(), } } } diff --git a/client/rpc-api/src/chain/mod.rs b/client/rpc-api/src/chain/mod.rs index d7d598942f1ea..f5f9524264e34 100644 --- a/client/rpc-api/src/chain/mod.rs +++ b/client/rpc-api/src/chain/mod.rs @@ -18,96 +18,59 @@ //! Substrate blockchain API. -pub mod error; - -use self::error::{FutureResult, Result}; -use jsonrpc_core::Result as RpcResult; -use jsonrpc_derive::rpc; -use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use sp_rpc::{list::ListOrValue, number::NumberOrHex}; -pub use self::gen_client::Client as ChainClient; +pub mod error; -/// Substrate blockchain API -#[rpc] +#[rpc(client, server)] pub trait ChainApi { - /// RPC metadata - type Metadata; - - /// Get header of a relay chain block. - #[rpc(name = "chain_getHeader")] - fn header(&self, hash: Option) -> FutureResult>; + /// Get header. + #[method(name = "chain_getHeader")] + async fn header(&self, hash: Option) -> RpcResult>; /// Get header and body of a relay chain block. - #[rpc(name = "chain_getBlock")] - fn block(&self, hash: Option) -> FutureResult>; + #[method(name = "chain_getBlock")] + async fn block(&self, hash: Option) -> RpcResult>; /// Get hash of the n-th block in the canon chain. /// /// By default returns latest block hash. - #[rpc(name = "chain_getBlockHash", alias("chain_getHead"))] + #[method(name = "chain_getBlockHash", aliases = ["chain_getHead"])] fn block_hash( &self, hash: Option>, - ) -> Result>>; + ) -> RpcResult>>; /// Get hash of the last finalized block in the canon chain. - #[rpc(name = "chain_getFinalizedHead", alias("chain_getFinalisedHead"))] - fn finalized_head(&self) -> Result; - - /// All head subscription - #[pubsub(subscription = "chain_allHead", subscribe, name = "chain_subscribeAllHeads")] - fn subscribe_all_heads(&self, metadata: Self::Metadata, subscriber: Subscriber
); - - /// Unsubscribe from all head subscription. - #[pubsub(subscription = "chain_allHead", unsubscribe, name = "chain_unsubscribeAllHeads")] - fn unsubscribe_all_heads( - &self, - metadata: Option, - id: SubscriptionId, - ) -> RpcResult; - - /// New head subscription - #[pubsub( - subscription = "chain_newHead", - subscribe, - name = "chain_subscribeNewHeads", - alias("subscribe_newHead", "chain_subscribeNewHead") + #[method(name = "chain_getFinalizedHead", aliases = ["chain_getFinalisedHead"])] + fn finalized_head(&self) -> RpcResult; + + /// All head subscription. + #[subscription( + name = "chain_subscribeAllHeads" => "chain_allHead", + unsubscribe = "chain_unsubscribeAllHeads", + item = Header )] - fn subscribe_new_heads(&self, metadata: Self::Metadata, subscriber: Subscriber
); - - /// Unsubscribe from new head subscription. - #[pubsub( - subscription = "chain_newHead", - unsubscribe, - name = "chain_unsubscribeNewHeads", - alias("unsubscribe_newHead", "chain_unsubscribeNewHead") + fn subscribe_all_heads(&self); + + /// New head subscription. + #[subscription( + name = "chain_subscribeNewHeads" => "chain_newHead", + aliases = ["subscribe_newHead", "chain_subscribeNewHead"], + unsubscribe = "chain_unsubscribeNewHeads", + unsubscribe_aliases = ["unsubscribe_newHead", "chain_unsubscribeNewHead"], + item = Header )] - fn unsubscribe_new_heads( - &self, - metadata: Option, - id: SubscriptionId, - ) -> RpcResult; - - /// Finalized head subscription - #[pubsub( - subscription = "chain_finalizedHead", - subscribe, - name = "chain_subscribeFinalizedHeads", - alias("chain_subscribeFinalisedHeads") + fn subscribe_new_heads(&self); + + /// Finalized head subscription. + #[subscription( + name = "chain_subscribeFinalizedHeads" => "chain_finalizedHead", + aliases = ["chain_subscribeFinalisedHeads"], + unsubscribe = "chain_unsubscribeFinalizedHeads", + unsubscribe_aliases = ["chain_unsubscribeFinalisedHeads"], + item = Header )] - fn subscribe_finalized_heads(&self, metadata: Self::Metadata, subscriber: Subscriber
); - - /// Unsubscribe from finalized head subscription. - #[pubsub( - subscription = "chain_finalizedHead", - unsubscribe, - name = "chain_unsubscribeFinalizedHeads", - alias("chain_unsubscribeFinalisedHeads") - )] - fn unsubscribe_finalized_heads( - &self, - metadata: Option, - id: SubscriptionId, - ) -> RpcResult; + fn subscribe_finalized_heads(&self); } diff --git a/client/rpc-api/src/child_state/mod.rs b/client/rpc-api/src/child_state/mod.rs index 6b4cd20f22605..a15b1a0e7ee05 100644 --- a/client/rpc-api/src/child_state/mod.rs +++ b/client/rpc-api/src/child_state/mod.rs @@ -16,89 +16,82 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Substrate state API. - -use crate::state::error::FutureResult; -use jsonrpc_derive::rpc; -use sp_core::storage::{PrefixedStorageKey, StorageData, StorageKey}; - -pub use self::gen_client::Client as ChildStateClient; +//! Substrate child state API use crate::state::ReadProof; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use sp_core::storage::{PrefixedStorageKey, StorageData, StorageKey}; /// Substrate child state API /// /// Note that all `PrefixedStorageKey` are deserialized /// from json and not guaranteed valid. -#[rpc] +#[rpc(client, server)] pub trait ChildStateApi { - /// RPC Metadata - type Metadata; - - /// DEPRECATED: Please use `childstate_getKeysPaged` with proper paging support. /// Returns the keys with prefix from a child storage, leave empty to get all the keys - #[rpc(name = "childstate_getKeys")] - fn storage_keys( + #[method(name = "childstate_getKeys")] + #[deprecated(since = "2.0.0", note = "Please use `getKeysPaged` with proper paging support")] + async fn storage_keys( &self, child_storage_key: PrefixedStorageKey, prefix: StorageKey, hash: Option, - ) -> FutureResult>; + ) -> RpcResult>; /// Returns the keys with prefix from a child storage with pagination support. /// Up to `count` keys will be returned. /// If `start_key` is passed, return next keys in storage in lexicographic order. - #[rpc(name = "childstate_getKeysPaged", alias("childstate_getKeysPagedAt"))] - fn storage_keys_paged( + #[method(name = "childstate_getKeysPaged", aliases = ["childstate_getKeysPagedAt"])] + async fn storage_keys_paged( &self, child_storage_key: PrefixedStorageKey, prefix: Option, count: u32, start_key: Option, hash: Option, - ) -> FutureResult>; + ) -> RpcResult>; /// Returns a child storage entry at a specific block's state. - #[rpc(name = "childstate_getStorage")] - fn storage( + #[method(name = "childstate_getStorage")] + async fn storage( &self, child_storage_key: PrefixedStorageKey, key: StorageKey, hash: Option, - ) -> FutureResult>; + ) -> RpcResult>; /// Returns child storage entries for multiple keys at a specific block's state. - #[rpc(name = "childstate_getStorageEntries")] - fn storage_entries( + #[method(name = "childstate_getStorageEntries")] + async fn storage_entries( &self, child_storage_key: PrefixedStorageKey, keys: Vec, hash: Option, - ) -> FutureResult>>; + ) -> RpcResult>>; /// Returns the hash of a child storage entry at a block's state. - #[rpc(name = "childstate_getStorageHash")] - fn storage_hash( + #[method(name = "childstate_getStorageHash")] + async fn storage_hash( &self, child_storage_key: PrefixedStorageKey, key: StorageKey, hash: Option, - ) -> FutureResult>; + ) -> RpcResult>; /// Returns the size of a child storage entry at a block's state. - #[rpc(name = "childstate_getStorageSize")] - fn storage_size( + #[method(name = "childstate_getStorageSize")] + async fn storage_size( &self, child_storage_key: PrefixedStorageKey, key: StorageKey, hash: Option, - ) -> FutureResult>; + ) -> RpcResult>; /// Returns proof of storage for child key entries at a specific block's state. - #[rpc(name = "state_getChildReadProof")] - fn read_child_proof( + #[method(name = "state_getChildReadProof")] + async fn read_child_proof( &self, child_storage_key: PrefixedStorageKey, keys: Vec, hash: Option, - ) -> FutureResult>; + ) -> RpcResult>; } diff --git a/client/rpc-api/src/dev/error.rs b/client/rpc-api/src/dev/error.rs index 1a14b0d78994e..fe74dea256376 100644 --- a/client/rpc-api/src/dev/error.rs +++ b/client/rpc-api/src/dev/error.rs @@ -18,14 +18,10 @@ //! Error helpers for Dev RPC module. -use crate::errors; -use jsonrpc_core as rpc; - -/// Dev RPC Result type. -pub type Result = std::result::Result; - -/// Dev RPC future Result type. -pub type FutureResult = jsonrpc_core::BoxFuture>; +use jsonrpsee::{ + core::Error as JsonRpseeError, + types::error::{CallError, ErrorObject}, +}; /// Dev RPC errors. #[derive(Debug, thiserror::Error)] @@ -45,27 +41,21 @@ pub enum Error { } /// Base error code for all dev errors. -const BASE_ERROR: i64 = 6000; +const BASE_ERROR: i32 = 6000; -impl From for rpc::Error { +impl From for JsonRpseeError { fn from(e: Error) -> Self { + let msg = e.to_string(); + match e { - Error::BlockQueryError(_) => rpc::Error { - code: rpc::ErrorCode::ServerError(BASE_ERROR + 1), - message: e.to_string(), - data: None, - }, - Error::BlockExecutionFailed => rpc::Error { - code: rpc::ErrorCode::ServerError(BASE_ERROR + 3), - message: e.to_string(), - data: None, - }, - Error::WitnessCompactionFailed => rpc::Error { - code: rpc::ErrorCode::ServerError(BASE_ERROR + 4), - message: e.to_string(), - data: None, - }, - e => errors::internal(e), + Error::BlockQueryError(_) => + CallError::Custom(ErrorObject::owned(BASE_ERROR + 1, msg, None::<()>)), + Error::BlockExecutionFailed => + CallError::Custom(ErrorObject::owned(BASE_ERROR + 3, msg, None::<()>)), + Error::WitnessCompactionFailed => + CallError::Custom(ErrorObject::owned(BASE_ERROR + 4, msg, None::<()>)), + Error::UnsafeRpcCalled(e) => e.into(), } + .into() } } diff --git a/client/rpc-api/src/dev/mod.rs b/client/rpc-api/src/dev/mod.rs index b1ae8934af8a1..afd83272a0127 100644 --- a/client/rpc-api/src/dev/mod.rs +++ b/client/rpc-api/src/dev/mod.rs @@ -22,9 +22,8 @@ pub mod error; -use self::error::Result; use codec::{Decode, Encode}; -use jsonrpc_derive::rpc; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; @@ -52,13 +51,13 @@ pub struct BlockStats { /// /// This API contains unstable and unsafe methods only meant for development nodes. They /// are all flagged as unsafe for this reason. -#[rpc] +#[rpc(client, server)] pub trait DevApi { /// Reexecute the specified `block_hash` and gather statistics while doing so. /// /// This function requires the specified block and its parent to be available /// at the queried node. If either the specified block or the parent is pruned, /// this function will return `None`. - #[rpc(name = "dev_getBlockStats")] - fn block_stats(&self, block_hash: Hash) -> Result>; + #[method(name = "dev_getBlockStats")] + fn block_stats(&self, block_hash: Hash) -> RpcResult>; } diff --git a/client/rpc-api/src/errors.rs b/client/rpc-api/src/errors.rs deleted file mode 100644 index e59b1b0eda5ce..0000000000000 --- a/client/rpc-api/src/errors.rs +++ /dev/null @@ -1,28 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use log::warn; - -pub fn internal(e: E) -> jsonrpc_core::Error { - warn!("Unknown error: {}", e); - jsonrpc_core::Error { - code: jsonrpc_core::ErrorCode::InternalError, - message: "Unknown error occurred".into(), - data: Some(e.to_string().into()), - } -} diff --git a/client/rpc-api/src/helpers.rs b/client/rpc-api/src/helpers.rs deleted file mode 100644 index 2fbd2f5040463..0000000000000 --- a/client/rpc-api/src/helpers.rs +++ /dev/null @@ -1,41 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use futures::{channel::oneshot, Future}; -use std::pin::Pin; - -/// Wraps around `oneshot::Receiver` and adjusts the error type to produce an internal error if the -/// sender gets dropped. -pub struct Receiver(pub oneshot::Receiver); - -impl Future for Receiver { - type Output = Result; - - fn poll( - mut self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll { - Future::poll(Pin::new(&mut self.0), cx).map_err(|_| jsonrpc_core::Error::internal_error()) - } -} - -impl jsonrpc_core::WrapFuture for Receiver { - fn into_future(self) -> jsonrpc_core::BoxFuture> { - Box::pin(async { self.await }) - } -} diff --git a/client/rpc-api/src/lib.rs b/client/rpc-api/src/lib.rs index e06f30bf9cd87..a0cbbcee80e3e 100644 --- a/client/rpc-api/src/lib.rs +++ b/client/rpc-api/src/lib.rs @@ -22,15 +22,9 @@ #![warn(missing_docs)] -mod errors; -mod helpers; -mod metadata; mod policy; -pub use helpers::Receiver; -pub use jsonrpc_core::IoHandlerExtension as RpcExtension; -pub use metadata::Metadata; -pub use policy::{DenyUnsafe, UnsafeRpcError}; +pub use policy::DenyUnsafe; pub mod author; pub mod chain; diff --git a/client/rpc-api/src/metadata.rs b/client/rpc-api/src/metadata.rs deleted file mode 100644 index 3c798782062e9..0000000000000 --- a/client/rpc-api/src/metadata.rs +++ /dev/null @@ -1,60 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! RPC Metadata -use std::sync::Arc; - -use futures::channel::mpsc; -use jsonrpc_pubsub::{PubSubMetadata, Session}; - -/// RPC Metadata. -/// -/// Manages persistent session for transports that support it -/// and may contain some additional info extracted from specific transports -/// (like remote client IP address, request headers, etc) -#[derive(Default, Clone)] -pub struct Metadata { - session: Option>, -} - -impl jsonrpc_core::Metadata for Metadata {} -impl PubSubMetadata for Metadata { - fn session(&self) -> Option> { - self.session.clone() - } -} - -impl Metadata { - /// Create new `Metadata` with session (Pub/Sub) support. - pub fn new(transport: mpsc::UnboundedSender) -> Self { - Metadata { session: Some(Arc::new(Session::new(transport))) } - } - - /// Create new `Metadata` for tests. - #[cfg(test)] - pub fn new_test() -> (mpsc::UnboundedReceiver, Self) { - let (tx, rx) = mpsc::unbounded(); - (rx, Self::new(tx)) - } -} - -impl From> for Metadata { - fn from(sender: mpsc::UnboundedSender) -> Self { - Self::new(sender) - } -} diff --git a/client/rpc-api/src/offchain/error.rs b/client/rpc-api/src/offchain/error.rs index 41f1416bfb367..be72e05fc4460 100644 --- a/client/rpc-api/src/offchain/error.rs +++ b/client/rpc-api/src/offchain/error.rs @@ -18,7 +18,10 @@ //! Offchain RPC errors. -use jsonrpc_core as rpc; +use jsonrpsee::{ + core::Error as JsonRpseeError, + types::error::{CallError, ErrorObject}, +}; /// Offchain RPC Result type. pub type Result = std::result::Result; @@ -35,16 +38,17 @@ pub enum Error { } /// Base error code for all offchain errors. -const BASE_ERROR: i64 = 5000; +const BASE_ERROR: i32 = 5000; -impl From for rpc::Error { +impl From for JsonRpseeError { fn from(e: Error) -> Self { match e { - Error::UnavailableStorageKind => rpc::Error { - code: rpc::ErrorCode::ServerError(BASE_ERROR + 1), - message: "This storage kind is not available yet".into(), - data: None, - }, + Error::UnavailableStorageKind => CallError::Custom(ErrorObject::owned( + BASE_ERROR + 1, + "This storage kind is not available yet", + None::<()>, + )) + .into(), Error::UnsafeRpcCalled(e) => e.into(), } } diff --git a/client/rpc-api/src/offchain/mod.rs b/client/rpc-api/src/offchain/mod.rs index c76e83011072d..d9435d9a875fe 100644 --- a/client/rpc-api/src/offchain/mod.rs +++ b/client/rpc-api/src/offchain/mod.rs @@ -18,22 +18,19 @@ //! Substrate offchain API. -pub mod error; - -use self::error::Result; -use jsonrpc_derive::rpc; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use sp_core::{offchain::StorageKind, Bytes}; -pub use self::gen_client::Client as OffchainClient; +pub mod error; /// Substrate offchain RPC API -#[rpc] +#[rpc(client, server)] pub trait OffchainApi { /// Set offchain local storage under given key and prefix. - #[rpc(name = "offchain_localStorageSet")] - fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> Result<()>; + #[method(name = "offchain_localStorageSet")] + fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> RpcResult<()>; /// Get offchain local storage under given key and prefix. - #[rpc(name = "offchain_localStorageGet")] - fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> Result>; + #[method(name = "offchain_localStorageGet")] + fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> RpcResult>; } diff --git a/client/rpc-api/src/policy.rs b/client/rpc-api/src/policy.rs index dc0753c1b9139..69ca8958520a6 100644 --- a/client/rpc-api/src/policy.rs +++ b/client/rpc-api/src/policy.rs @@ -21,7 +21,13 @@ //! Contains a `DenyUnsafe` type that can be used to deny potentially unsafe //! RPC when accessed externally. -use jsonrpc_core as rpc; +use jsonrpsee::{ + core::Error as JsonRpseeError, + types::{ + error::{CallError, ErrorCode}, + ErrorObject, + }, +}; /// Signifies whether a potentially unsafe RPC should be denied. #[derive(Clone, Copy, Debug)] @@ -55,8 +61,18 @@ impl std::fmt::Display for UnsafeRpcError { impl std::error::Error for UnsafeRpcError {} -impl From for rpc::Error { - fn from(error: UnsafeRpcError) -> rpc::Error { - rpc::Error { code: rpc::ErrorCode::MethodNotFound, message: error.to_string(), data: None } +impl From for CallError { + fn from(e: UnsafeRpcError) -> CallError { + CallError::Custom(ErrorObject::owned( + ErrorCode::MethodNotFound.code(), + e.to_string(), + None::<()>, + )) + } +} + +impl From for JsonRpseeError { + fn from(e: UnsafeRpcError) -> JsonRpseeError { + JsonRpseeError::Call(e.into()) } } diff --git a/client/rpc-api/src/state/error.rs b/client/rpc-api/src/state/error.rs index 4414629e2e294..b1df64b4789ab 100644 --- a/client/rpc-api/src/state/error.rs +++ b/client/rpc-api/src/state/error.rs @@ -18,21 +18,19 @@ //! State RPC errors. -use crate::errors; -use jsonrpc_core as rpc; - +use jsonrpsee::{ + core::Error as JsonRpseeError, + types::error::{CallError, ErrorObject}, +}; /// State RPC Result type. pub type Result = std::result::Result; -/// State RPC future Result type. -pub type FutureResult = jsonrpc_core::BoxFuture>; - /// State RPC errors. #[derive(Debug, thiserror::Error)] pub enum Error { /// Client error. #[error("Client error: {}", .0)] - Client(#[from] Box), + Client(#[from] Box), /// Provided block range couldn't be resolved to a list of blocks. #[error("Cannot resolve a block range ['{:?}' ... '{:?}]. {}", .from, .to, .details)] InvalidBlockRange { @@ -57,22 +55,18 @@ pub enum Error { } /// Base code for all state errors. -const BASE_ERROR: i64 = 4000; +const BASE_ERROR: i32 = 4000; -impl From for rpc::Error { +impl From for JsonRpseeError { fn from(e: Error) -> Self { match e { - Error::InvalidBlockRange { .. } => rpc::Error { - code: rpc::ErrorCode::ServerError(BASE_ERROR + 1), - message: format!("{}", e), - data: None, - }, - Error::InvalidCount { .. } => rpc::Error { - code: rpc::ErrorCode::ServerError(BASE_ERROR + 2), - message: format!("{}", e), - data: None, - }, - e => errors::internal(e), + Error::InvalidBlockRange { .. } => + CallError::Custom(ErrorObject::owned(BASE_ERROR + 1, e.to_string(), None::<()>)) + .into(), + Error::InvalidCount { .. } => + CallError::Custom(ErrorObject::owned(BASE_ERROR + 2, e.to_string(), None::<()>)) + .into(), + e => Self::to_call_error(e), } } } diff --git a/client/rpc-api/src/state/mod.rs b/client/rpc-api/src/state/mod.rs index 42e927580960c..fba023e830262 100644 --- a/client/rpc-api/src/state/mod.rs +++ b/client/rpc-api/src/state/mod.rs @@ -18,161 +18,122 @@ //! Substrate state API. -pub mod error; -pub mod helpers; - -use self::error::FutureResult; -use jsonrpc_core::Result as RpcResult; -use jsonrpc_derive::rpc; -use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use sp_core::{ storage::{StorageChangeSet, StorageData, StorageKey}, Bytes, }; use sp_version::RuntimeVersion; -pub use self::{gen_client::Client as StateClient, helpers::ReadProof}; +pub mod error; +pub mod helpers; + +pub use self::helpers::ReadProof; /// Substrate state API -#[rpc] +#[rpc(client, server)] pub trait StateApi { - /// RPC Metadata - type Metadata; - /// Call a contract at a block's state. - #[rpc(name = "state_call", alias("state_callAt"))] - fn call(&self, name: String, bytes: Bytes, hash: Option) -> FutureResult; + #[method(name = "state_call", aliases = ["state_callAt"])] + async fn call(&self, name: String, bytes: Bytes, hash: Option) -> RpcResult; - /// DEPRECATED: Please use `state_getKeysPaged` with proper paging support. /// Returns the keys with prefix, leave empty to get all the keys. - #[rpc(name = "state_getKeys")] - fn storage_keys(&self, prefix: StorageKey, hash: Option) - -> FutureResult>; + #[method(name = "state_getKeys")] + #[deprecated(since = "2.0.0", note = "Please use `getKeysPaged` with proper paging support")] + async fn storage_keys( + &self, + prefix: StorageKey, + hash: Option, + ) -> RpcResult>; /// Returns the keys with prefix, leave empty to get all the keys - #[rpc(name = "state_getPairs")] - fn storage_pairs( + #[method(name = "state_getPairs")] + async fn storage_pairs( &self, prefix: StorageKey, hash: Option, - ) -> FutureResult>; + ) -> RpcResult>; /// Returns the keys with prefix with pagination support. /// Up to `count` keys will be returned. /// If `start_key` is passed, return next keys in storage in lexicographic order. - #[rpc(name = "state_getKeysPaged", alias("state_getKeysPagedAt"))] - fn storage_keys_paged( + #[method(name = "state_getKeysPaged", aliases = ["state_getKeysPagedAt"])] + async fn storage_keys_paged( &self, prefix: Option, count: u32, start_key: Option, hash: Option, - ) -> FutureResult>; + ) -> RpcResult>; /// Returns a storage entry at a specific block's state. - #[rpc(name = "state_getStorage", alias("state_getStorageAt"))] - fn storage(&self, key: StorageKey, hash: Option) -> FutureResult>; + #[method(name = "state_getStorage", aliases = ["state_getStorageAt"])] + async fn storage(&self, key: StorageKey, hash: Option) -> RpcResult>; /// Returns the hash of a storage entry at a block's state. - #[rpc(name = "state_getStorageHash", alias("state_getStorageHashAt"))] - fn storage_hash(&self, key: StorageKey, hash: Option) -> FutureResult>; + #[method(name = "state_getStorageHash", aliases = ["state_getStorageHashAt"])] + async fn storage_hash(&self, key: StorageKey, hash: Option) -> RpcResult>; /// Returns the size of a storage entry at a block's state. - #[rpc(name = "state_getStorageSize", alias("state_getStorageSizeAt"))] - fn storage_size(&self, key: StorageKey, hash: Option) -> FutureResult>; + #[method(name = "state_getStorageSize", aliases = ["state_getStorageSizeAt"])] + async fn storage_size(&self, key: StorageKey, hash: Option) -> RpcResult>; /// Returns the runtime metadata as an opaque blob. - #[rpc(name = "state_getMetadata")] - fn metadata(&self, hash: Option) -> FutureResult; + #[method(name = "state_getMetadata")] + async fn metadata(&self, hash: Option) -> RpcResult; /// Get the runtime version. - #[rpc(name = "state_getRuntimeVersion", alias("chain_getRuntimeVersion"))] - fn runtime_version(&self, hash: Option) -> FutureResult; + #[method(name = "state_getRuntimeVersion", aliases = ["chain_getRuntimeVersion"])] + async fn runtime_version(&self, hash: Option) -> RpcResult; /// Query historical storage entries (by key) starting from a block given as the second /// parameter. /// /// NOTE This first returned result contains the initial state of storage for all keys. /// Subsequent values in the vector represent changes to the previous state (diffs). - #[rpc(name = "state_queryStorage")] - fn query_storage( + #[method(name = "state_queryStorage")] + async fn query_storage( &self, keys: Vec, block: Hash, hash: Option, - ) -> FutureResult>>; + ) -> RpcResult>>; /// Query storage entries (by key) starting at block hash given as the second parameter. - #[rpc(name = "state_queryStorageAt")] - fn query_storage_at( + #[method(name = "state_queryStorageAt")] + async fn query_storage_at( &self, keys: Vec, at: Option, - ) -> FutureResult>>; + ) -> RpcResult>>; /// Returns proof of storage entries at a specific block's state. - #[rpc(name = "state_getReadProof")] - fn read_proof( + #[method(name = "state_getReadProof")] + async fn read_proof( &self, keys: Vec, hash: Option, - ) -> FutureResult>; + ) -> RpcResult>; /// New runtime version subscription - #[pubsub( - subscription = "state_runtimeVersion", - subscribe, - name = "state_subscribeRuntimeVersion", - alias("chain_subscribeRuntimeVersion") + #[subscription( + name = "state_subscribeRuntimeVersion" => "state_runtimeVersion", + unsubscribe = "state_unsubscribeRuntimeVersion", + aliases = ["chain_subscribeRuntimeVersion"], + unsubscribe_aliases = ["chain_unsubscribeRuntimeVersion"], + item = RuntimeVersion, )] - fn subscribe_runtime_version( - &self, - metadata: Self::Metadata, - subscriber: Subscriber, - ); + fn subscribe_runtime_version(&self); - /// Unsubscribe from runtime version subscription - #[pubsub( - subscription = "state_runtimeVersion", - unsubscribe, - name = "state_unsubscribeRuntimeVersion", - alias("chain_unsubscribeRuntimeVersion") + /// New storage subscription + #[subscription( + name = "state_subscribeStorage" => "state_storage", + unsubscribe = "state_unsubscribeStorage", + item = StorageChangeSet, )] - fn unsubscribe_runtime_version( - &self, - metadata: Option, - id: SubscriptionId, - ) -> RpcResult; - - /// Subscribe to the changes in the storage. - /// - /// This RPC endpoint has two modes of operation: - /// 1) When `keys` is not `None` you'll only be informed about the changes - /// done to the specified keys; this is RPC-safe. - /// 2) When `keys` is `None` you'll be informed of *all* of the changes; - /// **this is RPC-unsafe**. - /// - /// When subscribed to all of the changes this API will emit every storage - /// change for every block that is imported. These changes will only be sent - /// after a block is imported. If you require a consistent view across all changes - /// of every block, you need to take this into account. - #[pubsub(subscription = "state_storage", subscribe, name = "state_subscribeStorage")] - fn subscribe_storage( - &self, - metadata: Self::Metadata, - subscriber: Subscriber>, - keys: Option>, - ); - - /// Unsubscribe from storage subscription - #[pubsub(subscription = "state_storage", unsubscribe, name = "state_unsubscribeStorage")] - fn unsubscribe_storage( - &self, - metadata: Option, - id: SubscriptionId, - ) -> RpcResult; + fn subscribe_storage(&self, keys: Option>); - /// The `state_traceBlock` RPC provides a way to trace the re-execution of a single + /// The `traceBlock` RPC provides a way to trace the re-execution of a single /// block, collecting Spans and Events from both the client and the relevant WASM runtime. /// The Spans and Events are conceptually equivalent to those from the [Tracing][1] crate. /// @@ -323,13 +284,13 @@ pub trait StateApi { /// narrow down the traces using a smaller set of targets and/or storage keys. /// /// If you are having issues with maximum payload size you can use the flag - /// `-lstate_tracing=trace` to get some logging during tracing. - #[rpc(name = "state_traceBlock")] - fn trace_block( + /// `-ltracing=trace` to get some logging during tracing. + #[method(name = "state_traceBlock")] + async fn trace_block( &self, block: Hash, targets: Option, storage_keys: Option, methods: Option, - ) -> FutureResult; + ) -> RpcResult; } diff --git a/client/rpc-api/src/system/error.rs b/client/rpc-api/src/system/error.rs index 050d79b6ad636..777f8c6c6df0b 100644 --- a/client/rpc-api/src/system/error.rs +++ b/client/rpc-api/src/system/error.rs @@ -19,7 +19,10 @@ //! System RPC module errors. use crate::system::helpers::Health; -use jsonrpc_core as rpc; +use jsonrpsee::{ + core::Error as JsonRpseeError, + types::error::{CallError, ErrorObject}, +}; /// System RPC Result type. pub type Result = std::result::Result; @@ -35,22 +38,24 @@ pub enum Error { MalformattedPeerArg(String), } -/// Base code for all system errors. -const BASE_ERROR: i64 = 2000; +// Base code for all system errors. +const BASE_ERROR: i32 = 2000; +// Provided block range couldn't be resolved to a list of blocks. +const NOT_HEALTHY_ERROR: i32 = BASE_ERROR + 1; +// Peer argument is malformatted. +const MALFORMATTED_PEER_ARG_ERROR: i32 = BASE_ERROR + 2; -impl From for rpc::Error { +impl From for JsonRpseeError { fn from(e: Error) -> Self { match e { - Error::NotHealthy(ref h) => rpc::Error { - code: rpc::ErrorCode::ServerError(BASE_ERROR + 1), - message: format!("{}", e), - data: serde_json::to_value(h).ok(), - }, - Error::MalformattedPeerArg(ref e) => rpc::Error { - code: rpc::ErrorCode::ServerError(BASE_ERROR + 2), - message: e.clone(), - data: None, - }, + Error::NotHealthy(ref h) => + CallError::Custom(ErrorObject::owned(NOT_HEALTHY_ERROR, e.to_string(), Some(h))), + Error::MalformattedPeerArg(e) => CallError::Custom(ErrorObject::owned( + MALFORMATTED_PEER_ARG_ERROR + 2, + e, + None::<()>, + )), } + .into() } } diff --git a/client/rpc-api/src/system/mod.rs b/client/rpc-api/src/system/mod.rs index b610094f5b58d..1e12d5be87ee8 100644 --- a/client/rpc-api/src/system/mod.rs +++ b/client/rpc-api/src/system/mod.rs @@ -18,65 +18,61 @@ //! Substrate system API. -pub mod error; -pub mod helpers; - -use crate::helpers::Receiver; -use jsonrpc_core::BoxFuture; -use jsonrpc_derive::rpc; +use jsonrpsee::{ + core::{JsonValue, RpcResult}, + proc_macros::rpc, +}; -use self::error::Result as SystemResult; +pub use self::helpers::{Health, NodeRole, PeerInfo, SyncState, SystemInfo}; -pub use self::{ - gen_client::Client as SystemClient, - helpers::{Health, NodeRole, PeerInfo, SyncState, SystemInfo}, -}; +pub mod error; +pub mod helpers; /// Substrate system RPC API -#[rpc] +#[rpc(client, server)] pub trait SystemApi { /// Get the node's implementation name. Plain old string. - #[rpc(name = "system_name")] - fn system_name(&self) -> SystemResult; + #[method(name = "system_name")] + fn system_name(&self) -> RpcResult; /// Get the node implementation's version. Should be a semver string. - #[rpc(name = "system_version")] - fn system_version(&self) -> SystemResult; + #[method(name = "system_version")] + fn system_version(&self) -> RpcResult; /// Get the chain's name. Given as a string identifier. - #[rpc(name = "system_chain")] - fn system_chain(&self) -> SystemResult; + #[method(name = "system_chain")] + fn system_chain(&self) -> RpcResult; /// Get the chain's type. - #[rpc(name = "system_chainType")] - fn system_type(&self) -> SystemResult; + #[method(name = "system_chainType")] + fn system_type(&self) -> RpcResult; /// Get a custom set of properties as a JSON object, defined in the chain spec. - #[rpc(name = "system_properties")] - fn system_properties(&self) -> SystemResult; + #[method(name = "system_properties")] + fn system_properties(&self) -> RpcResult; /// Return health status of the node. /// /// Node is considered healthy if it is: /// - connected to some peers (unless running in dev mode) /// - not performing a major sync - #[rpc(name = "system_health", returns = "Health")] - fn system_health(&self) -> Receiver; + #[method(name = "system_health")] + async fn system_health(&self) -> RpcResult; /// Returns the base58-encoded PeerId of the node. - #[rpc(name = "system_localPeerId", returns = "String")] - fn system_local_peer_id(&self) -> Receiver; + #[method(name = "system_localPeerId")] + async fn system_local_peer_id(&self) -> RpcResult; - /// Returns the multiaddresses that the local node is listening on + /// Returns the multi-addresses that the local node is listening on /// /// The addresses include a trailing `/p2p/` with the local PeerId, and are thus suitable to - /// be passed to `system_addReservedPeer` or as a bootnode address for example. - #[rpc(name = "system_localListenAddresses", returns = "Vec")] - fn system_local_listen_addresses(&self) -> Receiver>; + /// be passed to `addReservedPeer` or as a bootnode address for example. + #[method(name = "system_localListenAddresses")] + async fn system_local_listen_addresses(&self) -> RpcResult>; /// Returns currently connected peers - #[rpc(name = "system_peers", returns = "Vec>")] - fn system_peers(&self) -> BoxFuture>>>; + #[method(name = "system_peers")] + async fn system_peers(&self) -> RpcResult>>; /// Returns current state of the network. /// @@ -84,47 +80,44 @@ pub trait SystemApi { /// as its format might change at any time. // TODO: the future of this call is uncertain: https://github.com/paritytech/substrate/issues/1890 // https://github.com/paritytech/substrate/issues/5541 - #[rpc(name = "system_unstable_networkState", returns = "jsonrpc_core::Value")] - fn system_network_state(&self) -> BoxFuture>; + #[method(name = "system_unstable_networkState")] + async fn system_network_state(&self) -> RpcResult; /// Adds a reserved peer. Returns the empty string or an error. The string /// parameter should encode a `p2p` multiaddr. /// /// `/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV` /// is an example of a valid, passing multiaddr with PeerId attached. - #[rpc(name = "system_addReservedPeer", returns = "()")] - fn system_add_reserved_peer(&self, peer: String) -> BoxFuture>; + #[method(name = "system_addReservedPeer")] + async fn system_add_reserved_peer(&self, peer: String) -> RpcResult<()>; /// Remove a reserved peer. Returns the empty string or an error. The string /// should encode only the PeerId e.g. `QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV`. - #[rpc(name = "system_removeReservedPeer", returns = "()")] - fn system_remove_reserved_peer( - &self, - peer_id: String, - ) -> BoxFuture>; + #[method(name = "system_removeReservedPeer")] + async fn system_remove_reserved_peer(&self, peer_id: String) -> RpcResult<()>; /// Returns the list of reserved peers - #[rpc(name = "system_reservedPeers", returns = "Vec")] - fn system_reserved_peers(&self) -> Receiver>; + #[method(name = "system_reservedPeers")] + async fn system_reserved_peers(&self) -> RpcResult>; /// Returns the roles the node is running as. - #[rpc(name = "system_nodeRoles", returns = "Vec")] - fn system_node_roles(&self) -> Receiver>; + #[method(name = "system_nodeRoles")] + async fn system_node_roles(&self) -> RpcResult>; /// Returns the state of the syncing of the node: starting block, current best block, highest /// known block. - #[rpc(name = "system_syncState", returns = "SyncState")] - fn system_sync_state(&self) -> Receiver>; + #[method(name = "system_syncState")] + async fn system_sync_state(&self) -> RpcResult>; /// Adds the supplied directives to the current log filter /// /// The syntax is identical to the CLI `=`: /// /// `sync=debug,state=trace` - #[rpc(name = "system_addLogFilter", returns = "()")] - fn system_add_log_filter(&self, directives: String) -> Result<(), jsonrpc_core::Error>; + #[method(name = "system_addLogFilter")] + fn system_add_log_filter(&self, directives: String) -> RpcResult<()>; /// Resets the log filter to Substrate defaults - #[rpc(name = "system_resetLogFilter", returns = "()")] - fn system_reset_log_filter(&self) -> Result<(), jsonrpc_core::Error>; + #[method(name = "system_resetLogFilter")] + fn system_reset_log_filter(&self) -> RpcResult<()>; } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index 4a13e9624a58e..ad01f3bdd6199 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -14,12 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" -http = { package = "jsonrpc-http-server", version = "18.0.0" } -ipc = { package = "jsonrpc-ipc-server", version = "18.0.0" } -jsonrpc-core = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server"] } log = "0.4.16" -pubsub = { package = "jsonrpc-pubsub", version = "18.0.0" } serde_json = "1.0.79" tokio = { version = "1.17.0", features = ["parking_lot"] } -ws = { package = "jsonrpc-ws-server", version = "18.0.0" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 963d9aec072f5..4f69413895a9b 100644 --- a/client/rpc-servers/src/lib.rs +++ b/client/rpc-servers/src/lib.rs @@ -20,213 +20,193 @@ #![warn(missing_docs)] -mod middleware; - -use jsonrpc_core::{IoHandlerExtension, MetaIoHandler}; -use log::error; -use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; -use pubsub::PubSubMetadata; -use std::io; +use jsonrpsee::{ + http_server::{AccessControlBuilder, HttpServerBuilder, HttpServerHandle}, + ws_server::{WsServerBuilder, WsServerHandle}, + RpcModule, +}; +use std::{error::Error as StdError, net::SocketAddr}; + +pub use crate::middleware::{RpcMetrics, RpcMiddleware}; +pub use jsonrpsee::core::{ + id_providers::{RandomIntegerIdProvider, RandomStringIdProvider}, + traits::IdProvider, +}; const MEGABYTE: usize = 1024 * 1024; /// Maximal payload accepted by RPC servers. pub const RPC_MAX_PAYLOAD_DEFAULT: usize = 15 * MEGABYTE; -/// Maximal buffer size in WS server. -pub const WS_MAX_BUFFER_CAPACITY_DEFAULT: usize = 16 * MEGABYTE; - /// Default maximum number of connections for WS RPC servers. const WS_MAX_CONNECTIONS: usize = 100; -/// The RPC IoHandler containing all requested APIs. -pub type RpcHandler = pubsub::PubSubHandler; - -pub use middleware::{method_names, RpcMetrics, RpcMiddleware}; - -/// Construct rpc `IoHandler` -pub fn rpc_handler( - extension: impl IoHandlerExtension, - rpc_middleware: RpcMiddleware, -) -> RpcHandler { - let io_handler = MetaIoHandler::with_middleware(rpc_middleware); - let mut io = pubsub::PubSubHandler::new(io_handler); - extension.augment(&mut io); - - // add an endpoint to list all available methods. - let mut methods = io.iter().map(|x| x.0.clone()).collect::>(); - io.add_method("rpc_methods", { - methods.sort(); - let methods = serde_json::to_value(&methods) - .expect("Serialization of Vec is infallible; qed"); - - move |_| { - let methods = methods.clone(); - async move { - Ok(serde_json::json!({ - "version": 1, - "methods": methods, - })) - } - } - }); - io -} +/// Default maximum number subscriptions per connection for WS RPC servers. +const WS_MAX_SUBS_PER_CONN: usize = 1024; -/// RPC server-specific prometheus metrics. -#[derive(Debug, Clone, Default)] -pub struct ServerMetrics { - /// Number of sessions opened. - session_opened: Option>, - /// Number of sessions closed. - session_closed: Option>, -} +pub mod middleware; -impl ServerMetrics { - /// Create new WebSocket RPC server metrics. - pub fn new(registry: Option<&Registry>) -> Result { - registry - .map(|r| { - Ok(Self { - session_opened: register( - Counter::new( - "substrate_rpc_sessions_opened", - "Number of persistent RPC sessions opened", - )?, - r, - )? - .into(), - session_closed: register( - Counter::new( - "substrate_rpc_sessions_closed", - "Number of persistent RPC sessions closed", - )?, - r, - )? - .into(), - }) - }) - .unwrap_or_else(|| Ok(Default::default())) - } -} - -/// Type alias for ipc server -pub type IpcServer = ipc::Server; /// Type alias for http server -pub type HttpServer = http::Server; +pub type HttpServer = HttpServerHandle; /// Type alias for ws server -pub type WsServer = ws::Server; - -impl ws::SessionStats for ServerMetrics { - fn open_session(&self, _id: ws::SessionId) { - self.session_opened.as_ref().map(|m| m.inc()); - } +pub type WsServer = WsServerHandle; + +/// WebSocket specific settings on the server. +pub struct WsConfig { + /// Maximum connections. + pub max_connections: Option, + /// Maximum subscriptions per connection. + pub max_subs_per_conn: Option, + /// Maximum rpc request payload size. + pub max_payload_in_mb: Option, + /// Maximum rpc response payload size. + pub max_payload_out_mb: Option, +} - fn close_session(&self, _id: ws::SessionId) { - self.session_closed.as_ref().map(|m| m.inc()); +impl WsConfig { + // Deconstructs the config to get the finalized inner values. + // + // `Payload size` or `max subs per connection` bigger than u32::MAX will be truncated. + fn deconstruct(self) -> (u32, u32, u64, u32) { + let max_conns = self.max_connections.unwrap_or(WS_MAX_CONNECTIONS) as u64; + let max_payload_in_mb = payload_size_or_default(self.max_payload_in_mb) as u32; + let max_payload_out_mb = payload_size_or_default(self.max_payload_out_mb) as u32; + let max_subs_per_conn = self.max_subs_per_conn.unwrap_or(WS_MAX_SUBS_PER_CONN) as u32; + + (max_payload_in_mb, max_payload_out_mb, max_conns, max_subs_per_conn) } } /// Start HTTP server listening on given address. -pub fn start_http( - addr: &std::net::SocketAddr, +pub async fn start_http( + addrs: [SocketAddr; 2], cors: Option<&Vec>, - io: RpcHandler, - maybe_max_payload_mb: Option, - tokio_handle: tokio::runtime::Handle, -) -> io::Result { - let max_request_body_size = maybe_max_payload_mb - .map(|mb| mb.saturating_mul(MEGABYTE)) - .unwrap_or(RPC_MAX_PAYLOAD_DEFAULT); - - http::ServerBuilder::new(io) - .threads(1) - .event_loop_executor(tokio_handle) - .health_api(("/health", "system_health")) - .allowed_hosts(hosts_filtering(cors.is_some())) - .rest_api(if cors.is_some() { http::RestApi::Secure } else { http::RestApi::Unsecure }) - .cors(map_cors::(cors)) - .max_request_body_size(max_request_body_size) - .start_http(addr) -} - -/// Start IPC server listening on given path. -pub fn start_ipc( - addr: &str, - io: RpcHandler, - server_metrics: ServerMetrics, -) -> io::Result { - let builder = ipc::ServerBuilder::new(io); - #[cfg(target_os = "unix")] - builder.set_security_attributes({ - let security_attributes = ipc::SecurityAttributes::empty(); - security_attributes.set_mode(0o600)?; - security_attributes - }); - builder.session_stats(server_metrics).start(addr) + max_payload_in_mb: Option, + max_payload_out_mb: Option, + metrics: Option, + rpc_api: RpcModule, + rt: tokio::runtime::Handle, +) -> Result> { + let max_payload_in = payload_size_or_default(max_payload_in_mb); + let max_payload_out = payload_size_or_default(max_payload_out_mb); + + let mut acl = AccessControlBuilder::new(); + + if let Some(cors) = cors { + // Whitelist listening address. + // NOTE: set_allowed_hosts will whitelist both ports but only one will used. + acl = acl.set_allowed_hosts(format_allowed_hosts(&addrs[..]))?; + acl = acl.set_allowed_origins(cors)?; + }; + + let builder = HttpServerBuilder::new() + .max_request_body_size(max_payload_in as u32) + .max_response_body_size(max_payload_out as u32) + .set_access_control(acl.build()) + .custom_tokio_runtime(rt); + + let rpc_api = build_rpc_api(rpc_api); + let (handle, addr) = if let Some(metrics) = metrics { + let middleware = RpcMiddleware::new(metrics, "http".into()); + let builder = builder.set_middleware(middleware); + let server = builder.build(&addrs[..]).await?; + let addr = server.local_addr(); + (server.start(rpc_api)?, addr) + } else { + let server = builder.build(&addrs[..]).await?; + let addr = server.local_addr(); + (server.start(rpc_api)?, addr) + }; + + log::info!( + "Running JSON-RPC HTTP server: addr={}, allowed origins={:?}", + addr.map_or_else(|_| "unknown".to_string(), |a| a.to_string()), + cors + ); + + Ok(handle) } /// Start WS server listening on given address. -pub fn start_ws< - M: pubsub::PubSubMetadata + From>, ->( - addr: &std::net::SocketAddr, - max_connections: Option, +pub async fn start_ws( + addrs: [SocketAddr; 2], cors: Option<&Vec>, - io: RpcHandler, - maybe_max_payload_mb: Option, - maybe_max_out_buffer_capacity_mb: Option, - server_metrics: ServerMetrics, - tokio_handle: tokio::runtime::Handle, -) -> io::Result { - let max_payload = maybe_max_payload_mb - .map(|mb| mb.saturating_mul(MEGABYTE)) - .unwrap_or(RPC_MAX_PAYLOAD_DEFAULT); - let max_out_buffer_capacity = maybe_max_out_buffer_capacity_mb - .map(|mb| mb.saturating_mul(MEGABYTE)) - .unwrap_or(WS_MAX_BUFFER_CAPACITY_DEFAULT); - - if max_payload > max_out_buffer_capacity { - log::warn!( - "maximum payload ({}) is more than maximum output buffer ({}) size in ws server, the payload will actually be limited by the buffer size", - max_payload, - max_out_buffer_capacity, - ) + ws_config: WsConfig, + metrics: Option, + rpc_api: RpcModule, + rt: tokio::runtime::Handle, + id_provider: Option>, +) -> Result> { + let (max_payload_in, max_payload_out, max_connections, max_subs_per_conn) = + ws_config.deconstruct(); + + let mut builder = WsServerBuilder::new() + .max_request_body_size(max_payload_in) + .max_response_body_size(max_payload_out) + .max_connections(max_connections) + .max_subscriptions_per_connection(max_subs_per_conn) + .custom_tokio_runtime(rt); + + if let Some(provider) = id_provider { + builder = builder.set_id_provider(provider); + } else { + builder = builder.set_id_provider(RandomStringIdProvider::new(16)); + }; + + if let Some(cors) = cors { + // Whitelist listening address. + // NOTE: set_allowed_hosts will whitelist both ports but only one will used. + builder = builder.set_allowed_hosts(format_allowed_hosts(&addrs[..]))?; + builder = builder.set_allowed_origins(cors)?; } - ws::ServerBuilder::with_meta_extractor(io, |context: &ws::RequestContext| { - context.sender().into() - }) - .event_loop_executor(tokio_handle) - .max_payload(max_payload) - .max_connections(max_connections.unwrap_or(WS_MAX_CONNECTIONS)) - .max_out_buffer_capacity(max_out_buffer_capacity) - .allowed_origins(map_cors(cors)) - .allowed_hosts(hosts_filtering(cors.is_some())) - .session_stats(server_metrics) - .start(addr) - .map_err(|err| match err { - ws::Error::Io(io) => io, - ws::Error::ConnectionClosed => io::ErrorKind::BrokenPipe.into(), - e => { - error!("{}", e); - io::ErrorKind::Other.into() - }, - }) + let rpc_api = build_rpc_api(rpc_api); + let (handle, addr) = if let Some(metrics) = metrics { + let middleware = RpcMiddleware::new(metrics, "ws".into()); + let builder = builder.set_middleware(middleware); + let server = builder.build(&addrs[..]).await?; + let addr = server.local_addr(); + (server.start(rpc_api)?, addr) + } else { + let server = builder.build(&addrs[..]).await?; + let addr = server.local_addr(); + (server.start(rpc_api)?, addr) + }; + + log::info!( + "Running JSON-RPC WS server: addr={}, allowed origins={:?}", + addr.map_or_else(|_| "unknown".to_string(), |a| a.to_string()), + cors + ); + + Ok(handle) } -fn map_cors From<&'a str>>(cors: Option<&Vec>) -> http::DomainsValidation { - cors.map(|x| x.iter().map(AsRef::as_ref).map(Into::into).collect::>()) - .into() +fn format_allowed_hosts(addrs: &[SocketAddr]) -> Vec { + let mut hosts = Vec::with_capacity(addrs.len() * 2); + for addr in addrs { + hosts.push(format!("localhost:{}", addr.port())); + hosts.push(format!("127.0.0.1:{}", addr.port())); + } + hosts } -fn hosts_filtering(enable: bool) -> http::DomainsValidation { - if enable { - // NOTE The listening address is whitelisted by default. - // Setting an empty vector here enables the validation - // and allows only the listening address. - http::DomainsValidation::AllowOnly(vec![]) - } else { - http::DomainsValidation::Disabled - } +fn build_rpc_api(mut rpc_api: RpcModule) -> RpcModule { + let mut available_methods = rpc_api.method_names().collect::>(); + available_methods.sort_unstable(); + + rpc_api + .register_method("rpc_methods", move |_, _| { + Ok(serde_json::json!({ + "version": 1, + "methods": available_methods, + })) + }) + .expect("infallible all other methods have their own address space; qed"); + + rpc_api +} + +fn payload_size_or_default(size_mb: Option) -> usize { + size_mb.map_or(RPC_MAX_PAYLOAD_DEFAULT, |mb| mb.saturating_mul(MEGABYTE)) } diff --git a/client/rpc-servers/src/middleware.rs b/client/rpc-servers/src/middleware.rs index d4ac787ce9f0c..5b2ee4bedb7dd 100644 --- a/client/rpc-servers/src/middleware.rs +++ b/client/rpc-servers/src/middleware.rs @@ -16,34 +16,38 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Middleware for RPC requests. +//! RPC middlware to collect prometheus metrics on RPC calls. -use std::collections::HashSet; - -use jsonrpc_core::{FutureOutput, FutureResponse, Metadata, Middleware as RequestMiddleware}; +use jsonrpsee::core::middleware::Middleware; use prometheus_endpoint::{ - register, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry, U64, + register, Counter, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry, + U64, }; -use futures::{future::Either, Future, FutureExt}; -use pubsub::PubSubMetadata; - -use crate::RpcHandler; - -/// Metrics for RPC middleware +/// Metrics for RPC middleware storing information about the number of requests started/completed, +/// calls started/completed and their timings. #[derive(Debug, Clone)] pub struct RpcMetrics { + /// Number of RPC requests received since the server started. requests_started: CounterVec, + /// Number of RPC requests completed since the server started. requests_finished: CounterVec, + /// Histogram over RPC execution times. calls_time: HistogramVec, + /// Number of calls started. calls_started: CounterVec, + /// Number of calls completed. calls_finished: CounterVec, + /// Number of Websocket sessions opened (Websocket only). + ws_sessions_opened: Option>, + /// Number of Websocket sessions closed (Websocket only). + ws_sessions_closed: Option>, } impl RpcMetrics { /// Create an instance of metrics pub fn new(metrics_registry: Option<&Registry>) -> Result, PrometheusError> { - if let Some(r) = metrics_registry { + if let Some(metrics_registry) = metrics_registry { Ok(Some(Self { requests_started: register( CounterVec::new( @@ -53,7 +57,7 @@ impl RpcMetrics { ), &["protocol"], )?, - r, + metrics_registry, )?, requests_finished: register( CounterVec::new( @@ -63,7 +67,7 @@ impl RpcMetrics { ), &["protocol"], )?, - r, + metrics_registry, )?, calls_time: register( HistogramVec::new( @@ -73,7 +77,7 @@ impl RpcMetrics { ), &["protocol", "method"], )?, - r, + metrics_registry, )?, calls_started: register( CounterVec::new( @@ -83,7 +87,7 @@ impl RpcMetrics { ), &["protocol", "method"], )?, - r, + metrics_registry, )?, calls_finished: register( CounterVec::new( @@ -93,8 +97,24 @@ impl RpcMetrics { ), &["protocol", "method", "is_error"], )?, - r, + metrics_registry, )?, + ws_sessions_opened: register( + Counter::new( + "substrate_rpc_sessions_opened", + "Number of persistent RPC sessions opened", + )?, + metrics_registry, + )? + .into(), + ws_sessions_closed: register( + Counter::new( + "substrate_rpc_sessions_closed", + "Number of persistent RPC sessions closed", + )?, + metrics_registry, + )? + .into(), })) } else { Ok(None) @@ -102,140 +122,71 @@ impl RpcMetrics { } } -/// Instantiates a dummy `IoHandler` given a builder function to extract supported method names. -pub fn method_names(gen_handler: F) -> Result, E> -where - F: FnOnce(RpcMiddleware) -> Result, E>, - M: PubSubMetadata, -{ - let io = gen_handler(RpcMiddleware::new(None, HashSet::new(), "dummy"))?; - Ok(io.iter().map(|x| x.0.clone()).collect()) -} - +#[derive(Clone)] /// Middleware for RPC calls pub struct RpcMiddleware { - metrics: Option, - known_rpc_method_names: HashSet, - transport_label: String, + metrics: RpcMetrics, + transport_label: &'static str, } impl RpcMiddleware { - /// Create an instance of middleware. - /// - /// - `metrics`: Will be used to report statistics. - /// - `transport_label`: The label that is used when reporting the statistics. - pub fn new( - metrics: Option, - known_rpc_method_names: HashSet, - transport_label: &str, - ) -> Self { - RpcMiddleware { metrics, known_rpc_method_names, transport_label: transport_label.into() } + /// Create a new [`RpcMiddleware`] with the provided [`RpcMetrics`]. + pub fn new(metrics: RpcMetrics, transport_label: &'static str) -> Self { + Self { metrics, transport_label } } } -impl RequestMiddleware for RpcMiddleware { - type Future = FutureResponse; - type CallFuture = FutureOutput; - - fn on_request( - &self, - request: jsonrpc_core::Request, - meta: M, - next: F, - ) -> Either - where - F: Fn(jsonrpc_core::Request, M) -> X + Send + Sync, - X: Future> + Send + 'static, - { - let metrics = self.metrics.clone(); - let transport_label = self.transport_label.clone(); - if let Some(ref metrics) = metrics { - metrics.requests_started.with_label_values(&[transport_label.as_str()]).inc(); - } - let r = next(request, meta); - Either::Left( - async move { - let r = r.await; - if let Some(ref metrics) = metrics { - metrics.requests_finished.with_label_values(&[transport_label.as_str()]).inc(); - } - r - } - .boxed(), - ) +impl Middleware for RpcMiddleware { + type Instant = std::time::Instant; + + fn on_connect(&self) { + self.metrics.ws_sessions_opened.as_ref().map(|counter| counter.inc()); } - fn on_call( - &self, - call: jsonrpc_core::Call, - meta: M, - next: F, - ) -> Either - where - F: Fn(jsonrpc_core::Call, M) -> X + Send + Sync, - X: Future> + Send + 'static, - { - let start = std::time::Instant::now(); - let name = call_name(&call, &self.known_rpc_method_names).to_owned(); - let metrics = self.metrics.clone(); - let transport_label = self.transport_label.clone(); - log::trace!(target: "rpc_metrics", "[{}] {} call: {:?}", transport_label, name, &call); - if let Some(ref metrics) = metrics { - metrics - .calls_started - .with_label_values(&[transport_label.as_str(), name.as_str()]) - .inc(); - } - let r = next(call, meta); - Either::Left( - async move { - let r = r.await; - let micros = start.elapsed().as_micros(); - if let Some(ref metrics) = metrics { - metrics - .calls_time - .with_label_values(&[transport_label.as_str(), name.as_str()]) - .observe(micros as _); - metrics - .calls_finished - .with_label_values(&[ - transport_label.as_str(), - name.as_str(), - if is_success(&r) { "true" } else { "false" }, - ]) - .inc(); - } - log::debug!( - target: "rpc_metrics", - "[{}] {} call took {} μs", - transport_label, - name, - micros, - ); - r - } - .boxed(), - ) + fn on_request(&self) -> Self::Instant { + let now = std::time::Instant::now(); + self.metrics.requests_started.with_label_values(&[self.transport_label]).inc(); + now } -} -fn call_name<'a>(call: &'a jsonrpc_core::Call, known_methods: &HashSet) -> &'a str { - // To prevent bloating metric with all invalid method names we filter them out here. - let only_known = |method: &'a String| { - if known_methods.contains(method) { - method.as_str() - } else { - "invalid method" - } - }; + fn on_call(&self, name: &str) { + log::trace!(target: "rpc_metrics", "[{}] on_call name={}", self.transport_label, name); + self.metrics + .calls_started + .with_label_values(&[self.transport_label, name]) + .inc(); + } - match call { - jsonrpc_core::Call::Invalid { .. } => "invalid call", - jsonrpc_core::Call::MethodCall(ref call) => only_known(&call.method), - jsonrpc_core::Call::Notification(ref notification) => only_known(¬ification.method), + fn on_result(&self, name: &str, success: bool, started_at: Self::Instant) { + let micros = started_at.elapsed().as_micros(); + log::debug!( + target: "rpc_metrics", + "[{}] {} call took {} μs", + self.transport_label, + name, + micros, + ); + self.metrics + .calls_time + .with_label_values(&[self.transport_label, name]) + .observe(micros as _); + + self.metrics + .calls_finished + .with_label_values(&[ + self.transport_label, + name, + if success { "true" } else { "false" }, + ]) + .inc(); + } + + fn on_response(&self, started_at: Self::Instant) { + log::trace!(target: "rpc_metrics", "[{}] on_response started_at={:?}", self.transport_label, started_at); + self.metrics.requests_finished.with_label_values(&[self.transport_label]).inc(); } -} -fn is_success(output: &Option) -> bool { - matches!(output, Some(jsonrpc_core::Output::Success(..))) + fn on_disconnect(&self) { + self.metrics.ws_sessions_closed.as_ref().map(|counter| counter.inc()); + } } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index f76665d6c97a7..515de401119d4 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -16,11 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } -jsonrpc-pubsub = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server"] } lazy_static = { version = "1.4.0", optional = true } log = "0.4.16" parking_lot = "0.12.0" -rpc = { package = "jsonrpc-core", version = "18.0.0" } serde_json = "1.0.79" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } @@ -39,14 +38,19 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-version = { version = "5.0.0", path = "../../primitives/version" } +tokio = { version = "1.17.0", optional = true } + [dev-dependencies] +env_logger = "0.9" assert_matches = "1.3.0" lazy_static = "1.4.0" +sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } +tokio = "1.17.0" sp-io = { version = "6.0.0", path = "../../primitives/io" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] -test-helpers = ["lazy_static"] +test-helpers = ["lazy_static", "tokio"] diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 2821eea2cc09d..d10398afc813b 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -23,26 +23,27 @@ mod tests; use std::sync::Arc; -use sp_blockchain::HeaderBackend; +use crate::SubscriptionTaskExecutor; use codec::{Decode, Encode}; -use futures::{ - future::{FutureExt, TryFutureExt}, - SinkExt, StreamExt as _, +use futures::{FutureExt, TryFutureExt}; +use jsonrpsee::{ + core::{async_trait, Error as JsonRpseeError, RpcResult}, + PendingSubscription, }; -use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::{ error::IntoPoolError, BlockHash, InPoolTransaction, TransactionFor, TransactionPool, - TransactionSource, TransactionStatus, TxHash, + TransactionSource, TxHash, }; use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; use sp_core::Bytes; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{generic, traits::Block as BlockT}; use sp_session::SessionKeys; -use self::error::{Error, FutureResult, Result}; +use self::error::{Error, Result}; /// Re-export the API for backward compatibility. pub use sc_rpc_api::author::*; @@ -52,12 +53,12 @@ pub struct Author { client: Arc, /// Transactions pool pool: Arc

, - /// Subscriptions manager - subscriptions: SubscriptionManager, /// The key store. keystore: SyncCryptoStorePtr, /// Whether to deny unsafe calls deny_unsafe: DenyUnsafe, + /// Executor to spawn subscriptions. + executor: SubscriptionTaskExecutor, } impl Author { @@ -65,11 +66,11 @@ impl Author { pub fn new( client: Arc, pool: Arc

, - subscriptions: SubscriptionManager, keystore: SyncCryptoStorePtr, deny_unsafe: DenyUnsafe, + executor: SubscriptionTaskExecutor, ) -> Self { - Author { client, pool, subscriptions, keystore, deny_unsafe } + Author { client, pool, keystore, deny_unsafe, executor } } } @@ -80,7 +81,8 @@ impl Author { /// some unique transactions via RPC and have them included in the pool. const TX_SOURCE: TransactionSource = TransactionSource::External; -impl AuthorApi, BlockHash

> for Author +#[async_trait] +impl AuthorApiServer, BlockHash

> for Author where P: TransactionPool + Sync + Send + 'static, Client: HeaderBackend + ProvideRuntimeApi + Send + Sync + 'static, @@ -88,9 +90,24 @@ where P::Hash: Unpin, ::Hash: Unpin, { - type Metadata = crate::Metadata; + async fn submit_extrinsic(&self, ext: Bytes) -> RpcResult> { + let xt = match Decode::decode(&mut &ext[..]) { + Ok(xt) => xt, + Err(err) => return Err(Error::Client(Box::new(err)).into()), + }; + let best_block_hash = self.client.info().best_hash; + self.pool + .submit_one(&generic::BlockId::hash(best_block_hash), TX_SOURCE, xt) + .await + .map_err(|e| { + e.into_pool_error() + .map(|e| Error::Pool(e)) + .unwrap_or_else(|e| Error::Verification(Box::new(e))) + .into() + }) + } - fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> Result<()> { + fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> RpcResult<()> { self.deny_unsafe.check_if_safe()?; let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?; @@ -99,7 +116,7 @@ where Ok(()) } - fn rotate_keys(&self) -> Result { + fn rotate_keys(&self) -> RpcResult { self.deny_unsafe.check_if_safe()?; let best_block_hash = self.client.info().best_hash; @@ -107,10 +124,10 @@ where .runtime_api() .generate_session_keys(&generic::BlockId::Hash(best_block_hash), None) .map(Into::into) - .map_err(|e| Error::Client(Box::new(e))) + .map_err(|api_err| Error::Client(Box::new(api_err)).into()) } - fn has_session_keys(&self, session_keys: Bytes) -> Result { + fn has_session_keys(&self, session_keys: Bytes) -> RpcResult { self.deny_unsafe.check_if_safe()?; let best_block_hash = self.client.info().best_hash; @@ -124,40 +141,22 @@ where Ok(SyncCryptoStore::has_keys(&*self.keystore, &keys)) } - fn has_key(&self, public_key: Bytes, key_type: String) -> Result { + fn has_key(&self, public_key: Bytes, key_type: String) -> RpcResult { self.deny_unsafe.check_if_safe()?; let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?; Ok(SyncCryptoStore::has_keys(&*self.keystore, &[(public_key.to_vec(), key_type)])) } - fn submit_extrinsic(&self, ext: Bytes) -> FutureResult> { - let xt = match Decode::decode(&mut &ext[..]) { - Ok(xt) => xt, - Err(err) => return async move { Err(err.into()) }.boxed(), - }; - let best_block_hash = self.client.info().best_hash; - - self.pool - .submit_one(&generic::BlockId::hash(best_block_hash), TX_SOURCE, xt) - .map_err(|e| { - e.into_pool_error() - .map(Into::into) - .unwrap_or_else(|e| error::Error::Verification(Box::new(e))) - }) - .boxed() - } - - fn pending_extrinsics(&self) -> Result> { + fn pending_extrinsics(&self) -> RpcResult> { Ok(self.pool.ready().map(|tx| tx.data().encode().into()).collect()) } fn remove_extrinsic( &self, bytes_or_hash: Vec>>, - ) -> Result>> { + ) -> RpcResult>> { self.deny_unsafe.check_if_safe()?; - let hashes = bytes_or_hash .into_iter() .map(|x| match x { @@ -177,20 +176,12 @@ where .collect()) } - fn watch_extrinsic( - &self, - _metadata: Self::Metadata, - subscriber: Subscriber, BlockHash

>>, - xt: Bytes, - ) { + fn watch_extrinsic(&self, pending: PendingSubscription, xt: Bytes) { let best_block_hash = self.client.info().best_hash; - let dxt = match TransactionFor::

::decode(&mut &xt[..]).map_err(error::Error::from) { - Ok(tx) => tx, - Err(err) => { - log::debug!("Failed to submit extrinsic: {}", err); - // reject the subscriber (ignore errors - we don't care if subscriber is no longer - // there). - let _ = subscriber.reject(err.into()); + let dxt = match TransactionFor::

::decode(&mut &xt[..]).map_err(|e| Error::from(e)) { + Ok(dxt) => dxt, + Err(e) => { + pending.reject(JsonRpseeError::from(e)); return }, }; @@ -204,41 +195,25 @@ where .unwrap_or_else(|e| error::Error::Verification(Box::new(e))) }); - let subscriptions = self.subscriptions.clone(); - - let future = async move { - let tx_stream = match submit.await { - Ok(s) => s, + let fut = async move { + let stream = match submit.await { + Ok(stream) => stream, Err(err) => { - log::debug!("Failed to submit extrinsic: {}", err); - // reject the subscriber (ignore errors - we don't care if subscriber is no - // longer there). - let _ = subscriber.reject(err.into()); + pending.reject(JsonRpseeError::from(err)); return }, }; - subscriptions.add(subscriber, move |sink| { - tx_stream - .map(|v| Ok(Ok(v))) - .forward( - sink.sink_map_err(|e| log::debug!("Error sending notifications: {:?}", e)), - ) - .map(drop) - }); - }; + let mut sink = match pending.accept() { + Some(sink) => sink, + _ => return, + }; - let res = self.subscriptions.executor().spawn_obj(future.boxed().into()); - if res.is_err() { - log::warn!("Error spawning subscription RPC task."); + sink.pipe_from_stream(stream).await; } - } + .boxed(); - fn unwatch_extrinsic( - &self, - _metadata: Option, - id: SubscriptionId, - ) -> Result { - Ok(self.subscriptions.cancel(id)) + self.executor + .spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); } } diff --git a/client/rpc/src/author/tests.rs b/client/rpc/src/author/tests.rs index c555465645a74..f969812e5b14c 100644 --- a/client/rpc/src/author/tests.rs +++ b/client/rpc/src/author/tests.rs @@ -18,21 +18,26 @@ use super::*; +use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; use codec::Encode; -use futures::executor; +use jsonrpsee::{ + core::Error as RpcError, + types::{error::CallError, EmptyParams}, + RpcModule, +}; use sc_transaction_pool::{BasicPool, FullChainApi}; +use sc_transaction_pool_api::TransactionStatus; use sp_core::{ blake2_256, + bytes::to_hex, crypto::{ByteArray, CryptoTypePublicPair, Pair}, - ed25519, - hexdisplay::HexDisplay, - sr25519, + ed25519, sr25519, testing::{ED25519, SR25519}, H256, }; use sp_keystore::testing::KeyStore; -use std::{mem, sync::Arc}; +use std::sync::Arc; use substrate_test_runtime_client::{ self, runtime::{Block, Extrinsic, SessionKeys, Transfer}, @@ -75,240 +80,253 @@ impl TestSetup { Author { client: self.client.clone(), pool: self.pool.clone(), - subscriptions: SubscriptionManager::new(Arc::new(crate::testing::TaskExecutor)), keystore: self.keystore.clone(), deny_unsafe: DenyUnsafe::No, + executor: test_executor(), } } -} -#[test] -fn submit_transaction_should_not_cause_error() { - let p = TestSetup::default().author(); - let xt = uxt(AccountKeyring::Alice, 1).encode(); - let h: H256 = blake2_256(&xt).into(); - - assert_matches!( - executor::block_on(AuthorApi::submit_extrinsic(&p, xt.clone().into())), - Ok(h2) if h == h2 - ); - assert!(executor::block_on(AuthorApi::submit_extrinsic(&p, xt.into())).is_err()); + fn into_rpc() -> RpcModule>> { + Self::default().author().into_rpc() + } } -#[test] -fn submit_rich_transaction_should_not_cause_error() { - let p = TestSetup::default().author(); - let xt = uxt(AccountKeyring::Alice, 0).encode(); - let h: H256 = blake2_256(&xt).into(); +#[tokio::test] +async fn author_submit_transaction_should_not_cause_error() { + let _ = env_logger::try_init(); + let author = TestSetup::default().author(); + let api = author.into_rpc(); + let xt: Bytes = uxt(AccountKeyring::Alice, 1).encode().into(); + let extrinsic_hash: H256 = blake2_256(&xt).into(); + let response: H256 = api.call("author_submitExtrinsic", [xt.clone()]).await.unwrap(); + + assert_eq!(response, extrinsic_hash); assert_matches!( - executor::block_on(AuthorApi::submit_extrinsic(&p, xt.clone().into())), - Ok(h2) if h == h2 + api.call::<_, H256>("author_submitExtrinsic", [xt]).await, + Err(RpcError::Call(CallError::Custom(err))) if err.message().contains("Already Imported") && err.code() == 1013 ); - assert!(executor::block_on(AuthorApi::submit_extrinsic(&p, xt.into())).is_err()); } -#[test] -fn should_watch_extrinsic() { - // given - let setup = TestSetup::default(); - let p = setup.author(); +#[tokio::test] +async fn author_should_watch_extrinsic() { + let api = TestSetup::into_rpc(); + let xt = to_hex(&uxt(AccountKeyring::Alice, 0).encode(), true); - let (subscriber, id_rx, data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); - - // when - p.watch_extrinsic( - Default::default(), - subscriber, - uxt(AccountKeyring::Alice, 0).encode().into(), - ); + let mut sub = api.subscribe("author_submitAndWatchExtrinsic", [xt]).await.unwrap(); + let (tx, sub_id) = timeout_secs(10, sub.next::>()) + .await + .unwrap() + .unwrap() + .unwrap(); - let id = executor::block_on(id_rx).unwrap().unwrap(); - assert_matches!(id, SubscriptionId::String(_)); + assert_matches!(tx, TransactionStatus::Ready); + assert_eq!(&sub_id, sub.subscription_id()); - let id = match id { - SubscriptionId::String(id) => id, - _ => unreachable!(), - }; - - // check notifications - let replacement = { + // Replace the extrinsic and observe the subscription is notified. + let (xt_replacement, xt_hash) = { let tx = Transfer { amount: 5, nonce: 0, from: AccountKeyring::Alice.into(), to: AccountKeyring::Bob.into(), }; - tx.into_signed_tx() + let tx = tx.into_signed_tx().encode(); + let hash = blake2_256(&tx); + + (to_hex(&tx, true), hash) }; - executor::block_on(AuthorApi::submit_extrinsic(&p, replacement.encode().into())).unwrap(); - let (res, data) = executor::block_on(data.into_future()); - - let expected = Some(format!( - r#"{{"jsonrpc":"2.0","method":"test","params":{{"result":"ready","subscription":"{}"}}}}"#, - id, - )); - assert_eq!(res, expected); - - let h = blake2_256(&replacement.encode()); - let expected = Some(format!( - r#"{{"jsonrpc":"2.0","method":"test","params":{{"result":{{"usurped":"0x{}"}},"subscription":"{}"}}}}"#, - HexDisplay::from(&h), - id, - )); - - let res = executor::block_on(data.into_future()).0; - assert_eq!(res, expected); + + let _ = api.call::<_, H256>("author_submitExtrinsic", [xt_replacement]).await.unwrap(); + + let (tx, sub_id) = timeout_secs(10, sub.next::>()) + .await + .unwrap() + .unwrap() + .unwrap(); + assert_eq!(tx, TransactionStatus::Usurped(xt_hash.into())); + assert_eq!(&sub_id, sub.subscription_id()); } -#[test] -fn should_return_watch_validation_error() { - // given - let setup = TestSetup::default(); - let p = setup.author(); +#[tokio::test] +async fn author_should_return_watch_validation_error() { + const METHOD: &'static str = "author_submitAndWatchExtrinsic"; - let (subscriber, id_rx, _data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); + let api = TestSetup::into_rpc(); + let failed_sub = api + .subscribe(METHOD, [to_hex(&uxt(AccountKeyring::Alice, 179).encode(), true)]) + .await; - // when - p.watch_extrinsic( - Default::default(), - subscriber, - uxt(AccountKeyring::Alice, 179).encode().into(), + assert_matches!( + failed_sub, + Err(RpcError::Call(CallError::Custom(err))) if err.message().contains("Invalid Transaction") && err.code() == 1010 ); - - // then - let res = executor::block_on(id_rx).unwrap(); - assert!(res.is_err(), "Expected the transaction to be rejected as invalid."); } -#[test] -fn should_return_pending_extrinsics() { - let p = TestSetup::default().author(); +#[tokio::test] +async fn author_should_return_pending_extrinsics() { + let api = TestSetup::into_rpc(); - let ex = uxt(AccountKeyring::Alice, 0); - executor::block_on(AuthorApi::submit_extrinsic(&p, ex.encode().into())).unwrap(); - assert_matches!( - p.pending_extrinsics(), - Ok(ref expected) if *expected == vec![Bytes(ex.encode())] - ); + let xt_bytes: Bytes = uxt(AccountKeyring::Alice, 0).encode().into(); + api.call::<_, H256>("author_submitExtrinsic", [to_hex(&xt_bytes, true)]) + .await + .unwrap(); + + let pending: Vec = + api.call("author_pendingExtrinsics", EmptyParams::new()).await.unwrap(); + assert_eq!(pending, vec![xt_bytes]); } -#[test] -fn should_remove_extrinsics() { +#[tokio::test] +async fn author_should_remove_extrinsics() { + const METHOD: &'static str = "author_removeExtrinsic"; let setup = TestSetup::default(); - let p = setup.author(); - - let ex1 = uxt(AccountKeyring::Alice, 0); - executor::block_on(p.submit_extrinsic(ex1.encode().into())).unwrap(); - let ex2 = uxt(AccountKeyring::Alice, 1); - executor::block_on(p.submit_extrinsic(ex2.encode().into())).unwrap(); - let ex3 = uxt(AccountKeyring::Bob, 0); - let hash3 = executor::block_on(p.submit_extrinsic(ex3.encode().into())).unwrap(); + let api = setup.author().into_rpc(); + + // Submit three extrinsics, then remove two of them (will cause the third to be removed as well, + // having a higher nonce) + let xt1_bytes = uxt(AccountKeyring::Alice, 0).encode(); + let xt1 = to_hex(&xt1_bytes, true); + let xt1_hash: H256 = api.call("author_submitExtrinsic", [xt1]).await.unwrap(); + + let xt2 = to_hex(&uxt(AccountKeyring::Alice, 1).encode(), true); + let xt2_hash: H256 = api.call("author_submitExtrinsic", [xt2]).await.unwrap(); + + let xt3 = to_hex(&uxt(AccountKeyring::Bob, 0).encode(), true); + let xt3_hash: H256 = api.call("author_submitExtrinsic", [xt3]).await.unwrap(); assert_eq!(setup.pool.status().ready, 3); - // now remove all 3 - let removed = p - .remove_extrinsic(vec![ - hash::ExtrinsicOrHash::Hash(hash3), - // Removing this one will also remove ex2 - hash::ExtrinsicOrHash::Extrinsic(ex1.encode().into()), - ]) + // Now remove all three. + // Notice how we need an extra `Vec` wrapping the `Vec` we want to submit as params. + let removed: Vec = api + .call( + METHOD, + vec![vec![ + hash::ExtrinsicOrHash::Hash(xt3_hash), + // Removing this one will also remove xt2 + hash::ExtrinsicOrHash::Extrinsic(xt1_bytes.into()), + ]], + ) + .await .unwrap(); - assert_eq!(removed.len(), 3); + assert_eq!(removed, vec![xt1_hash, xt2_hash, xt3_hash]); } -#[test] -fn should_insert_key() { +#[tokio::test] +async fn author_should_insert_key() { let setup = TestSetup::default(); - let p = setup.author(); - + let api = setup.author().into_rpc(); let suri = "//Alice"; - let key_pair = ed25519::Pair::from_string(suri, None).expect("Generates keypair"); - p.insert_key( + let keypair = ed25519::Pair::from_string(suri, None).expect("generates keypair"); + let params: (String, String, Bytes) = ( String::from_utf8(ED25519.0.to_vec()).expect("Keytype is a valid string"), suri.to_string(), - key_pair.public().0.to_vec().into(), - ) - .expect("Insert key"); - - let public_keys = SyncCryptoStore::keys(&*setup.keystore, ED25519).unwrap(); + keypair.public().0.to_vec().into(), + ); + api.call::<_, ()>("author_insertKey", params).await.unwrap(); + let pubkeys = SyncCryptoStore::keys(&*setup.keystore, ED25519).unwrap(); - assert!(public_keys - .contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, key_pair.public().to_raw_vec()))); + assert!( + pubkeys.contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, keypair.public().to_raw_vec())) + ); } -#[test] -fn should_rotate_keys() { +#[tokio::test] +async fn author_should_rotate_keys() { let setup = TestSetup::default(); - let p = setup.author(); - - let new_public_keys = p.rotate_keys().expect("Rotates the keys"); + let api = setup.author().into_rpc(); + let new_pubkeys: Bytes = api.call("author_rotateKeys", EmptyParams::new()).await.unwrap(); let session_keys = - SessionKeys::decode(&mut &new_public_keys[..]).expect("SessionKeys decode successfully"); - - let ed25519_public_keys = SyncCryptoStore::keys(&*setup.keystore, ED25519).unwrap(); - let sr25519_public_keys = SyncCryptoStore::keys(&*setup.keystore, SR25519).unwrap(); - - assert!(ed25519_public_keys + SessionKeys::decode(&mut &new_pubkeys[..]).expect("SessionKeys decode successfully"); + let ed25519_pubkeys = SyncCryptoStore::keys(&*setup.keystore, ED25519).unwrap(); + let sr25519_pubkeys = SyncCryptoStore::keys(&*setup.keystore, SR25519).unwrap(); + assert!(ed25519_pubkeys .contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, session_keys.ed25519.to_raw_vec()))); - assert!(sr25519_public_keys + assert!(sr25519_pubkeys .contains(&CryptoTypePublicPair(sr25519::CRYPTO_ID, session_keys.sr25519.to_raw_vec()))); } -#[test] -fn test_has_session_keys() { - let setup = TestSetup::default(); - let p = setup.author(); - - let non_existent_public_keys = - TestSetup::default().author().rotate_keys().expect("Rotates the keys"); - - let public_keys = p.rotate_keys().expect("Rotates the keys"); - let test_vectors = vec![ - (public_keys, Ok(true)), - (vec![1, 2, 3].into(), Err(Error::InvalidSessionKeys)), - (non_existent_public_keys, Ok(false)), - ]; - - for (keys, result) in test_vectors { - assert_eq!( - result.map_err(|e| mem::discriminant(&e)), - p.has_session_keys(keys).map_err(|e| mem::discriminant(&e)), - ); - } +#[tokio::test] +async fn author_has_session_keys() { + // Setup + let api = TestSetup::into_rpc(); + + // Add a valid session key + let pubkeys: Bytes = api + .call("author_rotateKeys", EmptyParams::new()) + .await + .expect("Rotates the keys"); + + // Add a session key in a different keystore + let non_existent_pubkeys: Bytes = { + let api2 = TestSetup::default().author().into_rpc(); + api2.call("author_rotateKeys", EmptyParams::new()) + .await + .expect("Rotates the keys") + }; + + // Then… + let existing = api.call::<_, bool>("author_hasSessionKeys", vec![pubkeys]).await.unwrap(); + assert!(existing, "Existing key is in the session keys"); + + let inexistent = api + .call::<_, bool>("author_hasSessionKeys", vec![non_existent_pubkeys]) + .await + .unwrap(); + assert_eq!(inexistent, false, "Inexistent key is not in the session keys"); + + assert_matches!( + api.call::<_, bool>("author_hasSessionKeys", vec![Bytes::from(vec![1, 2, 3])]).await, + Err(RpcError::Call(CallError::Custom(err))) if err.message().contains("Session keys are not encoded correctly") + ); } -#[test] -fn test_has_key() { - let setup = TestSetup::default(); - let p = setup.author(); +#[tokio::test] +async fn author_has_key() { + let _ = env_logger::try_init(); + let api = TestSetup::into_rpc(); let suri = "//Alice"; - let alice_key_pair = ed25519::Pair::from_string(suri, None).expect("Generates keypair"); - p.insert_key( + let alice_keypair = ed25519::Pair::from_string(suri, None).expect("Generates keypair"); + let params = ( String::from_utf8(ED25519.0.to_vec()).expect("Keytype is a valid string"), suri.to_string(), - alice_key_pair.public().0.to_vec().into(), - ) - .expect("Insert key"); - let bob_key_pair = ed25519::Pair::from_string("//Bob", None).expect("Generates keypair"); - - let test_vectors = vec![ - (alice_key_pair.public().to_raw_vec().into(), ED25519, Ok(true)), - (alice_key_pair.public().to_raw_vec().into(), SR25519, Ok(false)), - (bob_key_pair.public().to_raw_vec().into(), ED25519, Ok(false)), - ]; - - for (key, key_type, result) in test_vectors { - assert_eq!( - result.map_err(|e| mem::discriminant(&e)), - p.has_key( - key, - String::from_utf8(key_type.0.to_vec()).expect("Keytype is a valid string"), - ) - .map_err(|e| mem::discriminant(&e)), + Bytes::from(alice_keypair.public().0.to_vec()), + ); + + api.call::<_, ()>("author_insertKey", params).await.expect("insertKey works"); + + let bob_keypair = ed25519::Pair::from_string("//Bob", None).expect("Generates keypair"); + + // Alice's ED25519 key is there + let has_alice_ed: bool = { + let params = ( + Bytes::from(alice_keypair.public().to_raw_vec()), + String::from_utf8(ED25519.0.to_vec()).expect("Keytype is a valid string"), ); - } + api.call("author_hasKey", params).await.unwrap() + }; + assert!(has_alice_ed); + + // Alice's SR25519 key is not there + let has_alice_sr: bool = { + let params = ( + Bytes::from(alice_keypair.public().to_raw_vec()), + String::from_utf8(SR25519.0.to_vec()).expect("Keytype is a valid string"), + ); + api.call("author_hasKey", params).await.unwrap() + }; + assert!(!has_alice_sr); + + // Bob's ED25519 key is not there + let has_bob_ed: bool = { + let params = ( + Bytes::from(bob_keypair.public().to_raw_vec()), + String::from_utf8(ED25519.0.to_vec()).expect("Keytype is a valid string"), + ); + api.call("author_hasKey", params).await.unwrap() + }; + assert!(!has_bob_ed); } diff --git a/client/rpc/src/chain/chain_full.rs b/client/rpc/src/chain/chain_full.rs index 288a825eb5bed..9ca6b3edcfe60 100644 --- a/client/rpc/src/chain/chain_full.rs +++ b/client/rpc/src/chain/chain_full.rs @@ -18,34 +18,40 @@ //! Blockchain API backend for full nodes. -use super::{client_err, error::FutureResult, ChainBackend}; -use futures::FutureExt; -use jsonrpc_pubsub::manager::SubscriptionManager; +use super::{client_err, ChainBackend, Error}; +use crate::SubscriptionTaskExecutor; +use std::{marker::PhantomData, sync::Arc}; + +use futures::{ + future::{self, FutureExt}, + stream::{self, Stream, StreamExt}, +}; +use jsonrpsee::{core::async_trait, PendingSubscription}; use sc_client_api::{BlockBackend, BlockchainEvents}; use sp_blockchain::HeaderBackend; use sp_runtime::{ generic::{BlockId, SignedBlock}, traits::Block as BlockT, }; -use std::{marker::PhantomData, sync::Arc}; /// Blockchain API backend for full nodes. Reads all the data from local database. pub struct FullChain { /// Substrate client. client: Arc, - /// Current subscriptions. - subscriptions: SubscriptionManager, /// phantom member to pin the block type _phantom: PhantomData, + /// Subscription executor. + executor: SubscriptionTaskExecutor, } impl FullChain { /// Create new Chain API RPC handler. - pub fn new(client: Arc, subscriptions: SubscriptionManager) -> Self { - Self { client, subscriptions, _phantom: PhantomData } + pub fn new(client: Arc, executor: SubscriptionTaskExecutor) -> Self { + Self { client, executor, _phantom: PhantomData } } } +#[async_trait] impl ChainBackend for FullChain where Block: BlockT + 'static, @@ -56,17 +62,93 @@ where &self.client } - fn subscriptions(&self) -> &SubscriptionManager { - &self.subscriptions + async fn header(&self, hash: Option) -> Result, Error> { + self.client.header(BlockId::Hash(self.unwrap_or_best(hash))).map_err(client_err) } - fn header(&self, hash: Option) -> FutureResult> { - let res = self.client.header(BlockId::Hash(self.unwrap_or_best(hash))).map_err(client_err); - async move { res }.boxed() + async fn block(&self, hash: Option) -> Result>, Error> { + self.client.block(&BlockId::Hash(self.unwrap_or_best(hash))).map_err(client_err) } - fn block(&self, hash: Option) -> FutureResult>> { - let res = self.client.block(&BlockId::Hash(self.unwrap_or_best(hash))).map_err(client_err); - async move { res }.boxed() + fn subscribe_all_heads(&self, sink: PendingSubscription) { + subscribe_headers( + &self.client, + &self.executor, + sink, + || self.client().info().best_hash, + || { + self.client() + .import_notification_stream() + .map(|notification| notification.header) + }, + ) } + + fn subscribe_new_heads(&self, sink: PendingSubscription) { + subscribe_headers( + &self.client, + &self.executor, + sink, + || self.client().info().best_hash, + || { + self.client() + .import_notification_stream() + .filter(|notification| future::ready(notification.is_new_best)) + .map(|notification| notification.header) + }, + ) + } + + fn subscribe_finalized_heads(&self, sink: PendingSubscription) { + subscribe_headers( + &self.client, + &self.executor, + sink, + || self.client().info().finalized_hash, + || { + self.client() + .finality_notification_stream() + .map(|notification| notification.header) + }, + ) + } +} + +/// Subscribe to new headers. +fn subscribe_headers( + client: &Arc, + executor: &SubscriptionTaskExecutor, + pending: PendingSubscription, + best_block_hash: G, + stream: F, +) where + Block: BlockT + 'static, + Block::Header: Unpin, + Client: HeaderBackend + 'static, + F: FnOnce() -> S, + G: FnOnce() -> Block::Hash, + S: Stream + Send + Unpin + 'static, +{ + // send current head right at the start. + let maybe_header = client + .header(BlockId::Hash(best_block_hash())) + .map_err(client_err) + .and_then(|header| header.ok_or_else(|| Error::Other("Best header missing.".into()))) + .map_err(|e| log::warn!("Best header error {:?}", e)) + .ok(); + + // NOTE: by the time we set up the stream there might be a new best block and so there is a risk + // that the stream has a hole in it. The alternative would be to look up the best block *after* + // we set up the stream and chain it to the stream. Consuming code would need to handle + // duplicates at the beginning of the stream though. + let stream = stream::iter(maybe_header).chain(stream()); + + let fut = async move { + if let Some(mut sink) = pending.accept() { + sink.pipe_from_stream(stream).await; + } + } + .boxed(); + + executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); } diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index 64231dd78c83c..a79c66e0a18f6 100644 --- a/client/rpc/src/chain/mod.rs +++ b/client/rpc/src/chain/mod.rs @@ -23,15 +23,14 @@ mod chain_full; #[cfg(test)] mod tests; -use futures::{future, StreamExt, TryStreamExt}; -use log::warn; -use rpc::{ - futures::{stream, FutureExt, SinkExt, Stream}, - Result as RpcResult, -}; use std::sync::Arc; -use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; +use crate::SubscriptionTaskExecutor; + +use jsonrpsee::{ + core::{async_trait, RpcResult}, + PendingSubscription, +}; use sc_client_api::BlockchainEvents; use sp_rpc::{list::ListOrValue, number::NumberOrHex}; use sp_runtime::{ @@ -39,13 +38,14 @@ use sp_runtime::{ traits::{Block as BlockT, Header, NumberFor}, }; -use self::error::{Error, FutureResult, Result}; +use self::error::Error; use sc_client_api::BlockBackend; pub use sc_rpc_api::chain::*; use sp_blockchain::HeaderBackend; /// Blockchain backend API +#[async_trait] trait ChainBackend: Send + Sync + 'static where Block: BlockT + 'static, @@ -55,9 +55,6 @@ where /// Get client reference. fn client(&self) -> &Arc; - /// Get subscriptions reference. - fn subscriptions(&self) -> &SubscriptionManager; - /// Tries to unwrap passed block hash, or uses best block hash otherwise. fn unwrap_or_best(&self, hash: Option) -> Block::Hash { match hash { @@ -67,15 +64,15 @@ where } /// Get header of a relay chain block. - fn header(&self, hash: Option) -> FutureResult>; + async fn header(&self, hash: Option) -> Result, Error>; /// Get header and body of a relay chain block. - fn block(&self, hash: Option) -> FutureResult>>; + async fn block(&self, hash: Option) -> Result>, Error>; /// Get hash of the n-th block in the canon chain. /// /// By default returns latest block hash. - fn block_hash(&self, number: Option) -> Result> { + fn block_hash(&self, number: Option) -> Result, Error> { match number { None => Ok(Some(self.client().info().best_hash)), Some(num_or_hex) => { @@ -97,107 +94,31 @@ where } /// Get hash of the last finalized block in the canon chain. - fn finalized_head(&self) -> Result { + fn finalized_head(&self) -> Result { Ok(self.client().info().finalized_hash) } /// All new head subscription - fn subscribe_all_heads( - &self, - _metadata: crate::Metadata, - subscriber: Subscriber, - ) { - subscribe_headers( - self.client(), - self.subscriptions(), - subscriber, - || self.client().info().best_hash, - || { - self.client() - .import_notification_stream() - .map(|notification| Ok::<_, rpc::Error>(notification.header)) - }, - ) - } - - /// Unsubscribe from all head subscription. - fn unsubscribe_all_heads( - &self, - _metadata: Option, - id: SubscriptionId, - ) -> RpcResult { - Ok(self.subscriptions().cancel(id)) - } + fn subscribe_all_heads(&self, sink: PendingSubscription); /// New best head subscription - fn subscribe_new_heads( - &self, - _metadata: crate::Metadata, - subscriber: Subscriber, - ) { - subscribe_headers( - self.client(), - self.subscriptions(), - subscriber, - || self.client().info().best_hash, - || { - self.client() - .import_notification_stream() - .filter(|notification| future::ready(notification.is_new_best)) - .map(|notification| Ok::<_, rpc::Error>(notification.header)) - }, - ) - } - - /// Unsubscribe from new best head subscription. - fn unsubscribe_new_heads( - &self, - _metadata: Option, - id: SubscriptionId, - ) -> RpcResult { - Ok(self.subscriptions().cancel(id)) - } + fn subscribe_new_heads(&self, sink: PendingSubscription); /// Finalized head subscription - fn subscribe_finalized_heads( - &self, - _metadata: crate::Metadata, - subscriber: Subscriber, - ) { - subscribe_headers( - self.client(), - self.subscriptions(), - subscriber, - || self.client().info().finalized_hash, - || { - self.client() - .finality_notification_stream() - .map(|notification| Ok::<_, rpc::Error>(notification.header)) - }, - ) - } - - /// Unsubscribe from finalized head subscription. - fn unsubscribe_finalized_heads( - &self, - _metadata: Option, - id: SubscriptionId, - ) -> RpcResult { - Ok(self.subscriptions().cancel(id)) - } + fn subscribe_finalized_heads(&self, sink: PendingSubscription); } /// Create new state API that works on full node. pub fn new_full( client: Arc, - subscriptions: SubscriptionManager, + executor: SubscriptionTaskExecutor, ) -> Chain where Block: BlockT + 'static, Block::Header: Unpin, Client: BlockBackend + HeaderBackend + BlockchainEvents + 'static, { - Chain { backend: Box::new(self::chain_full::FullChain::new(client, subscriptions)) } + Chain { backend: Box::new(self::chain_full::FullChain::new(client, executor)) } } /// Chain API with subscriptions support. @@ -205,122 +126,58 @@ pub struct Chain { backend: Box>, } -impl ChainApi, Block::Hash, Block::Header, SignedBlock> +#[async_trait] +impl ChainApiServer, Block::Hash, Block::Header, SignedBlock> for Chain where Block: BlockT + 'static, Block::Header: Unpin, Client: HeaderBackend + BlockchainEvents + 'static, { - type Metadata = crate::Metadata; - - fn header(&self, hash: Option) -> FutureResult> { - self.backend.header(hash) + async fn header(&self, hash: Option) -> RpcResult> { + self.backend.header(hash).await.map_err(Into::into) } - fn block(&self, hash: Option) -> FutureResult>> { - self.backend.block(hash) + async fn block(&self, hash: Option) -> RpcResult>> { + self.backend.block(hash).await.map_err(Into::into) } fn block_hash( &self, number: Option>, - ) -> Result>> { + ) -> RpcResult>> { match number { - None => self.backend.block_hash(None).map(ListOrValue::Value), - Some(ListOrValue::Value(number)) => - self.backend.block_hash(Some(number)).map(ListOrValue::Value), + None => self.backend.block_hash(None).map(ListOrValue::Value).map_err(Into::into), + Some(ListOrValue::Value(number)) => self + .backend + .block_hash(Some(number)) + .map(ListOrValue::Value) + .map_err(Into::into), Some(ListOrValue::List(list)) => Ok(ListOrValue::List( list.into_iter() .map(|number| self.backend.block_hash(Some(number))) - .collect::>()?, + .collect::>()?, )), } } - fn finalized_head(&self) -> Result { - self.backend.finalized_head() - } - - fn subscribe_all_heads(&self, metadata: Self::Metadata, subscriber: Subscriber) { - self.backend.subscribe_all_heads(metadata, subscriber) - } - - fn unsubscribe_all_heads( - &self, - metadata: Option, - id: SubscriptionId, - ) -> RpcResult { - self.backend.unsubscribe_all_heads(metadata, id) - } - - fn subscribe_new_heads(&self, metadata: Self::Metadata, subscriber: Subscriber) { - self.backend.subscribe_new_heads(metadata, subscriber) + fn finalized_head(&self) -> RpcResult { + self.backend.finalized_head().map_err(Into::into) } - fn unsubscribe_new_heads( - &self, - metadata: Option, - id: SubscriptionId, - ) -> RpcResult { - self.backend.unsubscribe_new_heads(metadata, id) + fn subscribe_all_heads(&self, sink: PendingSubscription) { + self.backend.subscribe_all_heads(sink) } - fn subscribe_finalized_heads( - &self, - metadata: Self::Metadata, - subscriber: Subscriber, - ) { - self.backend.subscribe_finalized_heads(metadata, subscriber) + fn subscribe_new_heads(&self, sink: PendingSubscription) { + self.backend.subscribe_new_heads(sink) } - fn unsubscribe_finalized_heads( - &self, - metadata: Option, - id: SubscriptionId, - ) -> RpcResult { - self.backend.unsubscribe_finalized_heads(metadata, id) + fn subscribe_finalized_heads(&self, sink: PendingSubscription) { + self.backend.subscribe_finalized_heads(sink) } } -/// Subscribe to new headers. -fn subscribe_headers( - client: &Arc, - subscriptions: &SubscriptionManager, - subscriber: Subscriber, - best_block_hash: G, - stream: F, -) where - Block: BlockT + 'static, - Block::Header: Unpin, - Client: HeaderBackend + 'static, - F: FnOnce() -> S, - G: FnOnce() -> Block::Hash, - S: Stream> + Send + 'static, -{ - subscriptions.add(subscriber, |sink| { - // send current head right at the start. - let header = client - .header(BlockId::Hash(best_block_hash())) - .map_err(client_err) - .and_then(|header| { - header.ok_or_else(|| Error::Other("Best header missing.".to_string())) - }) - .map_err(Into::into); - - // send further subscriptions - let stream = stream() - .inspect_err(|e| warn!("Block notification stream error: {:?}", e)) - .map(Ok); - - stream::iter(vec![Ok(header)]) - .chain(stream) - .forward(sink.sink_map_err(|e| warn!("Error sending notifications: {:?}", e))) - // we ignore the resulting Stream (if the first stream is over we are unsubscribed) - .map(|_| ()) - }); -} - fn client_err(err: sp_blockchain::Error) -> Error { Error::Client(Box::new(err)) } diff --git a/client/rpc/src/chain/tests.rs b/client/rpc/src/chain/tests.rs index fa4473d35f300..f09da200ff587 100644 --- a/client/rpc/src/chain/tests.rs +++ b/client/rpc/src/chain/tests.rs @@ -17,9 +17,9 @@ // along with this program. If not, see . use super::*; -use crate::testing::TaskExecutor; +use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; -use futures::executor; +use jsonrpsee::types::EmptyParams; use sc_block_builder::BlockBuilderProvider; use sp_consensus::BlockOrigin; use sp_rpc::list::ListOrValue; @@ -28,221 +28,218 @@ use substrate_test_runtime_client::{ runtime::{Block, Header, H256}, }; -#[test] -fn should_return_header() { +#[tokio::test] +async fn should_return_header() { let client = Arc::new(substrate_test_runtime_client::new()); - let api = new_full(client.clone(), SubscriptionManager::new(Arc::new(TaskExecutor))); + let api = new_full(client.clone(), test_executor()).into_rpc(); - assert_matches!( - executor::block_on(api.header(Some(client.genesis_hash()).into())), - Ok(Some(ref x)) if x == &Header { + let res: Header = + api.call("chain_getHeader", [H256::from(client.genesis_hash())]).await.unwrap(); + assert_eq!( + res, + Header { parent_hash: H256::from_low_u64_be(0), number: 0, - state_root: x.state_root.clone(), - extrinsics_root: - "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314".parse().unwrap(), + state_root: res.state_root.clone(), + extrinsics_root: "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" + .parse() + .unwrap(), digest: Default::default(), } ); - assert_matches!( - executor::block_on(api.header(None.into())), - Ok(Some(ref x)) if x == &Header { + let res: Header = api.call("chain_getHeader", EmptyParams::new()).await.unwrap(); + assert_eq!( + res, + Header { parent_hash: H256::from_low_u64_be(0), number: 0, - state_root: x.state_root.clone(), - extrinsics_root: - "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314".parse().unwrap(), + state_root: res.state_root.clone(), + extrinsics_root: "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" + .parse() + .unwrap(), digest: Default::default(), } ); assert_matches!( - executor::block_on(api.header(Some(H256::from_low_u64_be(5)).into())), - Ok(None) + api.call::<_, Option

>("chain_getHeader", [H256::from_low_u64_be(5)]) + .await + .unwrap(), + None ); } -#[test] -fn should_return_a_block() { +#[tokio::test] +async fn should_return_a_block() { let mut client = Arc::new(substrate_test_runtime_client::new()); - let api = new_full(client.clone(), SubscriptionManager::new(Arc::new(TaskExecutor))); + let api = new_full(client.clone(), test_executor()).into_rpc(); let block = client.new_block(Default::default()).unwrap().build().unwrap().block; let block_hash = block.hash(); - executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); + client.import(BlockOrigin::Own, block).await.unwrap(); + + let res: SignedBlock = + api.call("chain_getBlock", [H256::from(client.genesis_hash())]).await.unwrap(); // Genesis block is not justified - assert_matches!( - executor::block_on(api.block(Some(client.genesis_hash()).into())), - Ok(Some(SignedBlock { justifications: None, .. })) - ); + assert!(res.justifications.is_none()); - assert_matches!( - executor::block_on(api.block(Some(block_hash).into())), - Ok(Some(ref x)) if x.block == Block { + let res: SignedBlock = + api.call("chain_getBlock", [H256::from(block_hash)]).await.unwrap(); + assert_eq!( + res.block, + Block { header: Header { parent_hash: client.genesis_hash(), number: 1, - state_root: x.block.header.state_root.clone(), - extrinsics_root: - "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314".parse().unwrap(), + state_root: res.block.header.state_root.clone(), + extrinsics_root: "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" + .parse() + .unwrap(), digest: Default::default(), }, extrinsics: vec![], } ); - assert_matches!( - executor::block_on(api.block(None.into())), - Ok(Some(ref x)) if x.block == Block { + let res: SignedBlock = api.call("chain_getBlock", Vec::::new()).await.unwrap(); + assert_eq!( + res.block, + Block { header: Header { parent_hash: client.genesis_hash(), number: 1, - state_root: x.block.header.state_root.clone(), - extrinsics_root: - "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314".parse().unwrap(), + state_root: res.block.header.state_root.clone(), + extrinsics_root: "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" + .parse() + .unwrap(), digest: Default::default(), }, extrinsics: vec![], } ); - assert_matches!(executor::block_on(api.block(Some(H256::from_low_u64_be(5)).into())), Ok(None)); + assert_matches!( + api.call::<_, Option
>("chain_getBlock", [H256::from_low_u64_be(5)]) + .await + .unwrap(), + None + ); } -#[test] -fn should_return_block_hash() { +#[tokio::test] +async fn should_return_block_hash() { let mut client = Arc::new(substrate_test_runtime_client::new()); - let api = new_full(client.clone(), SubscriptionManager::new(Arc::new(TaskExecutor))); + let api = new_full(client.clone(), test_executor()).into_rpc(); - assert_matches!( - api.block_hash(None.into()), - Ok(ListOrValue::Value(Some(ref x))) if x == &client.genesis_hash() - ); + let res: ListOrValue> = + api.call("chain_getBlockHash", EmptyParams::new()).await.unwrap(); assert_matches!( - api.block_hash(Some(ListOrValue::Value(0u64.into())).into()), - Ok(ListOrValue::Value(Some(ref x))) if x == &client.genesis_hash() + res, + ListOrValue::Value(Some(ref x)) if x == &client.genesis_hash() ); + let res: ListOrValue> = + api.call("chain_getBlockHash", [ListOrValue::from(0_u64)]).await.unwrap(); assert_matches!( - api.block_hash(Some(ListOrValue::Value(1u64.into())).into()), - Ok(ListOrValue::Value(None)) + res, + ListOrValue::Value(Some(ref x)) if x == &client.genesis_hash() ); + let res: Option>> = + api.call("chain_getBlockHash", [ListOrValue::from(1_u64)]).await.unwrap(); + assert_matches!(res, None); + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + let res: ListOrValue> = + api.call("chain_getBlockHash", [ListOrValue::from(0_u64)]).await.unwrap(); assert_matches!( - api.block_hash(Some(ListOrValue::Value(0u64.into())).into()), - Ok(ListOrValue::Value(Some(ref x))) if x == &client.genesis_hash() + res, + ListOrValue::Value(Some(ref x)) if x == &client.genesis_hash() ); + + let res: ListOrValue> = + api.call("chain_getBlockHash", [ListOrValue::from(1_u64)]).await.unwrap(); assert_matches!( - api.block_hash(Some(ListOrValue::Value(1u64.into())).into()), - Ok(ListOrValue::Value(Some(ref x))) if x == &block.hash() + res, + ListOrValue::Value(Some(ref x)) if x == &block.hash() ); + + let res: ListOrValue> = api + .call("chain_getBlockHash", [ListOrValue::Value(sp_core::U256::from(1_u64))]) + .await + .unwrap(); assert_matches!( - api.block_hash(Some(ListOrValue::Value(sp_core::U256::from(1u64).into())).into()), - Ok(ListOrValue::Value(Some(ref x))) if x == &block.hash() + res, + ListOrValue::Value(Some(ref x)) if x == &block.hash() ); + let res: ListOrValue> = api + .call("chain_getBlockHash", [ListOrValue::List(vec![0_u64, 1_u64, 2_u64])]) + .await + .unwrap(); assert_matches!( - api.block_hash(Some(vec![0u64.into(), 1u64.into(), 2u64.into()].into())), - Ok(ListOrValue::List(list)) if list == &[client.genesis_hash().into(), block.hash().into(), None] + res, + ListOrValue::List(list) if list == &[client.genesis_hash().into(), block.hash().into(), None] ); } -#[test] -fn should_return_finalized_hash() { +#[tokio::test] +async fn should_return_finalized_hash() { let mut client = Arc::new(substrate_test_runtime_client::new()); - let api = new_full(client.clone(), SubscriptionManager::new(Arc::new(TaskExecutor))); + let api = new_full(client.clone(), test_executor()).into_rpc(); - assert_matches!( - api.finalized_head(), - Ok(ref x) if x == &client.genesis_hash() - ); + let res: H256 = api.call("chain_getFinalizedHead", EmptyParams::new()).await.unwrap(); + assert_eq!(res, client.genesis_hash()); // import new block let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); + client.import(BlockOrigin::Own, block).await.unwrap(); + // no finalization yet - assert_matches!( - api.finalized_head(), - Ok(ref x) if x == &client.genesis_hash() - ); + let res: H256 = api.call("chain_getFinalizedHead", EmptyParams::new()).await.unwrap(); + assert_eq!(res, client.genesis_hash()); // finalize client.finalize_block(BlockId::number(1), None).unwrap(); - assert_matches!( - api.finalized_head(), - Ok(ref x) if x == &client.block_hash(1).unwrap().unwrap() - ); + let res: H256 = api.call("chain_getFinalizedHead", EmptyParams::new()).await.unwrap(); + assert_eq!(res, client.block_hash(1).unwrap().unwrap()); } -#[test] -fn should_notify_about_latest_block() { - let (subscriber, id, mut transport) = Subscriber::new_test("test"); - - { - let mut client = Arc::new(substrate_test_runtime_client::new()); - let api = new_full(client.clone(), SubscriptionManager::new(Arc::new(TaskExecutor))); - - api.subscribe_all_heads(Default::default(), subscriber); - - // assert id assigned - assert!(matches!(executor::block_on(id), Ok(Ok(SubscriptionId::String(_))))); - - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); - } - - // Check for the correct number of notifications - executor::block_on((&mut transport).take(2).collect::>()); - assert!(executor::block_on(transport.next()).is_none()); +#[tokio::test] +async fn should_notify_about_latest_block() { + test_head_subscription("chain_subscribeAllHeads").await; } -#[test] -fn should_notify_about_best_block() { - let (subscriber, id, mut transport) = Subscriber::new_test("test"); - - { - let mut client = Arc::new(substrate_test_runtime_client::new()); - let api = new_full(client.clone(), SubscriptionManager::new(Arc::new(TaskExecutor))); - - api.subscribe_new_heads(Default::default(), subscriber); - - // assert id assigned - assert!(matches!(executor::block_on(id), Ok(Ok(SubscriptionId::String(_))))); - - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); - } - - // Assert that the correct number of notifications have been sent. - executor::block_on((&mut transport).take(2).collect::>()); - assert!(executor::block_on(transport.next()).is_none()); +#[tokio::test] +async fn should_notify_about_best_block() { + test_head_subscription("chain_subscribeNewHeads").await; } -#[test] -fn should_notify_about_finalized_block() { - let (subscriber, id, mut transport) = Subscriber::new_test("test"); - - { - let mut client = Arc::new(substrate_test_runtime_client::new()); - let api = new_full(client.clone(), SubscriptionManager::new(Arc::new(TaskExecutor))); - - api.subscribe_finalized_heads(Default::default(), subscriber); +#[tokio::test] +async fn should_notify_about_finalized_block() { + test_head_subscription("chain_subscribeFinalizedHeads").await; +} - // assert id assigned - assert!(matches!(executor::block_on(id), Ok(Ok(SubscriptionId::String(_))))); +async fn test_head_subscription(method: &str) { + let mut client = Arc::new(substrate_test_runtime_client::new()); + let mut sub = { + let api = new_full(client.clone(), test_executor()).into_rpc(); + let sub = api.subscribe(method, EmptyParams::new()).await.unwrap(); let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); + client.import(BlockOrigin::Own, block).await.unwrap(); client.finalize_block(BlockId::number(1), None).unwrap(); - } + sub + }; + + assert_matches!(timeout_secs(10, sub.next::
()).await, Ok(Some(_))); + assert_matches!(timeout_secs(10, sub.next::
()).await, Ok(Some(_))); - // Assert that the correct number of notifications have been sent. - executor::block_on((&mut transport).take(2).collect::>()); - assert!(executor::block_on(transport.next()).is_none()); + sub.close(); + assert_matches!(timeout_secs(10, sub.next::
()).await, Ok(None)); } diff --git a/client/rpc/src/dev/mod.rs b/client/rpc/src/dev/mod.rs index d782a03feae43..7f4b68f56f6f6 100644 --- a/client/rpc/src/dev/mod.rs +++ b/client/rpc/src/dev/mod.rs @@ -16,19 +16,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Implementation of the [`DevApi`] trait providing debug utilities for Substrate based +//! Implementation of the [`DevApiServer`] trait providing debug utilities for Substrate based //! blockchains. #[cfg(test)] mod tests; -pub use sc_rpc_api::dev::{BlockStats, DevApi}; - +use jsonrpsee::core::RpcResult; use sc_client_api::{BlockBackend, HeaderBackend}; -use sc_rpc_api::{ - dev::error::{Error, Result}, - DenyUnsafe, -}; +use sc_rpc_api::{dev::error::Error, DenyUnsafe}; use sp_api::{ApiExt, Core, ProvideRuntimeApi}; use sp_core::Encode; use sp_runtime::{ @@ -40,6 +36,8 @@ use std::{ sync::Arc, }; +pub use sc_rpc_api::dev::{BlockStats, DevApiServer}; + type HasherOf = <::Header as Header>::Hashing; /// The Dev API. All methods are unsafe. @@ -56,7 +54,7 @@ impl Dev { } } -impl DevApi for Dev +impl DevApiServer for Dev where Block: BlockT + 'static, Client: BlockBackend @@ -67,7 +65,7 @@ where + 'static, Client::Api: Core, { - fn block_stats(&self, hash: Block::Hash) -> Result> { + fn block_stats(&self, hash: Block::Hash) -> RpcResult> { self.deny_unsafe.check_if_safe()?; let block = { diff --git a/client/rpc/src/dev/tests.rs b/client/rpc/src/dev/tests.rs index 1d31abe38b640..b7a0de8f5ae0b 100644 --- a/client/rpc/src/dev/tests.rs +++ b/client/rpc/src/dev/tests.rs @@ -18,25 +18,32 @@ use super::*; use assert_matches::assert_matches; -use futures::executor; +use jsonrpsee::{core::Error as JsonRpseeError, types::error::CallError}; use sc_block_builder::BlockBuilderProvider; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use substrate_test_runtime_client::{prelude::*, runtime::Block}; -#[test] -fn block_stats_work() { +#[tokio::test] +async fn block_stats_work() { let mut client = Arc::new(substrate_test_runtime_client::new()); - let api = >::new(client.clone(), DenyUnsafe::No); + let api = >::new(client.clone(), DenyUnsafe::No).into_rpc(); let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); + client.import(BlockOrigin::Own, block).await.unwrap(); // Can't gather stats for a block without a parent. - assert_eq!(api.block_stats(client.genesis_hash()).unwrap(), None); + assert_eq!( + api.call::<_, Option>("dev_getBlockStats", [client.genesis_hash()]) + .await + .unwrap(), + None + ); assert_eq!( - api.block_stats(client.info().best_hash).unwrap(), + api.call::<_, Option>("dev_getBlockStats", [client.info().best_hash]) + .await + .unwrap(), Some(BlockStats { witness_len: 597, witness_compact_len: 500, @@ -46,13 +53,17 @@ fn block_stats_work() { ); } -#[test] -fn deny_unsafe_works() { +#[tokio::test] +async fn deny_unsafe_works() { let mut client = Arc::new(substrate_test_runtime_client::new()); - let api = >::new(client.clone(), DenyUnsafe::Yes); + let api = >::new(client.clone(), DenyUnsafe::Yes).into_rpc(); let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); + client.import(BlockOrigin::Own, block).await.unwrap(); - assert_matches!(api.block_stats(client.info().best_hash), Err(Error::UnsafeRpcCalled(_))); + assert_matches!( + api.call::<_, Option>("dev_getBlockStats", [client.info().best_hash]) + .await, + Err(JsonRpseeError::Call(CallError::Custom(err))) if err.message().contains("RPC call is unsafe to be called externally") + ); } diff --git a/client/rpc/src/lib.rs b/client/rpc/src/lib.rs index 59a1d542d365a..a0e810eafbb62 100644 --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -22,15 +22,14 @@ #![warn(missing_docs)] -use futures::{ - task::{FutureObj, Spawn, SpawnError}, - FutureExt, +pub use jsonrpsee::core::{ + id_providers::{ + RandomIntegerIdProvider as RandomIntegerSubscriptionId, + RandomStringIdProvider as RandomStringSubscriptionId, + }, + traits::IdProvider as RpcSubscriptionIdProvider, }; -use sp_core::traits::SpawnNamed; -use std::sync::Arc; - -pub use rpc::IoHandlerExtension as RpcExtension; -pub use sc_rpc_api::{DenyUnsafe, Metadata}; +pub use sc_rpc_api::DenyUnsafe; pub mod author; pub mod chain; @@ -43,24 +42,4 @@ pub mod system; pub mod testing; /// Task executor that is being used by RPC subscriptions. -#[derive(Clone)] -pub struct SubscriptionTaskExecutor(Arc); - -impl SubscriptionTaskExecutor { - /// Create a new `Self` with the given spawner. - pub fn new(spawn: impl SpawnNamed + 'static) -> Self { - Self(Arc::new(spawn)) - } -} - -impl Spawn for SubscriptionTaskExecutor { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - self.0 - .spawn("substrate-rpc-subscription", Some("rpc"), future.map(drop).boxed()); - Ok(()) - } - - fn status(&self) -> Result<(), SpawnError> { - Ok(()) - } -} +pub type SubscriptionTaskExecutor = std::sync::Arc; diff --git a/client/rpc/src/offchain/mod.rs b/client/rpc/src/offchain/mod.rs index 67b97d31ab949..b66b78274a64e 100644 --- a/client/rpc/src/offchain/mod.rs +++ b/client/rpc/src/offchain/mod.rs @@ -21,7 +21,8 @@ #[cfg(test)] mod tests; -use self::error::{Error, Result}; +use self::error::Error; +use jsonrpsee::core::{async_trait, Error as JsonRpseeError, RpcResult}; use parking_lot::RwLock; /// Re-export the API for backward compatibility. pub use sc_rpc_api::offchain::*; @@ -47,27 +48,27 @@ impl Offchain { } } -impl OffchainApi for Offchain { - /// Set offchain local storage under given key and prefix. - fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> Result<()> { +#[async_trait] +impl OffchainApiServer for Offchain { + fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> RpcResult<()> { self.deny_unsafe.check_if_safe()?; let prefix = match kind { StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX, - StorageKind::LOCAL => return Err(Error::UnavailableStorageKind), + StorageKind::LOCAL => return Err(JsonRpseeError::from(Error::UnavailableStorageKind)), }; self.storage.write().set(prefix, &*key, &*value); Ok(()) } - /// Get offchain local storage under given key and prefix. - fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> Result> { + fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> RpcResult> { self.deny_unsafe.check_if_safe()?; let prefix = match kind { StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX, - StorageKind::LOCAL => return Err(Error::UnavailableStorageKind), + StorageKind::LOCAL => return Err(JsonRpseeError::from(Error::UnavailableStorageKind)), }; + Ok(self.storage.read().get(prefix, &*key).map(Into::into)) } } diff --git a/client/rpc/src/offchain/tests.rs b/client/rpc/src/offchain/tests.rs index 219eeb192dfdd..28a7b6115b657 100644 --- a/client/rpc/src/offchain/tests.rs +++ b/client/rpc/src/offchain/tests.rs @@ -39,6 +39,7 @@ fn local_storage_should_work() { #[test] fn offchain_calls_considered_unsafe() { + use jsonrpsee::types::error::CallError; let storage = InMemOffchainStorage::default(); let offchain = Offchain::new(storage, DenyUnsafe::Yes); let key = Bytes(b"offchain_storage".to_vec()); @@ -46,10 +47,14 @@ fn offchain_calls_considered_unsafe() { assert_matches!( offchain.set_local_storage(StorageKind::PERSISTENT, key.clone(), value.clone()), - Err(Error::UnsafeRpcCalled(_)) + Err(JsonRpseeError::Call(CallError::Custom(err))) => { + assert_eq!(err.message(), "RPC call is unsafe to be called externally") + } ); assert_matches!( offchain.get_local_storage(StorageKind::PERSISTENT, key), - Err(Error::UnsafeRpcCalled(_)) + Err(JsonRpseeError::Call(CallError::Custom(err))) => { + assert_eq!(err.message(), "RPC call is unsafe to be called externally") + } ); } diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index c9806a30b4549..a45651c5e7990 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -23,11 +23,15 @@ mod state_full; #[cfg(test)] mod tests; -use futures::FutureExt; -use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; -use rpc::Result as RpcResult; use std::sync::Arc; +use crate::SubscriptionTaskExecutor; + +use jsonrpsee::{ + core::{async_trait, Error as JsonRpseeError, RpcResult}, + ws_server::PendingSubscription, +}; + use sc_rpc_api::{state::ReadProof, DenyUnsafe}; use sp_core::{ storage::{PrefixedStorageKey, StorageChangeSet, StorageData, StorageKey}, @@ -38,7 +42,7 @@ use sp_version::RuntimeVersion; use sp_api::{CallApiAt, Metadata, ProvideRuntimeApi}; -use self::error::{Error, FutureResult}; +use self::error::Error; use sc_client_api::{ Backend, BlockBackend, BlockchainEvents, ExecutorProvider, ProofProvider, StorageProvider, @@ -49,144 +53,122 @@ use sp_blockchain::{HeaderBackend, HeaderMetadata}; const STORAGE_KEYS_PAGED_MAX_COUNT: u32 = 1000; /// State backend API. +#[async_trait] pub trait StateBackend: Send + Sync + 'static where Block: BlockT + 'static, Client: Send + Sync + 'static, { /// Call runtime method at given block. - fn call( + async fn call( &self, block: Option, method: String, call_data: Bytes, - ) -> FutureResult; + ) -> Result; /// Returns the keys with prefix, leave empty to get all the keys. - fn storage_keys( + async fn storage_keys( &self, block: Option, prefix: StorageKey, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns the keys with prefix along with their values, leave empty to get all the pairs. - fn storage_pairs( + async fn storage_pairs( &self, block: Option, prefix: StorageKey, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns the keys with prefix with pagination support. - fn storage_keys_paged( + async fn storage_keys_paged( &self, block: Option, prefix: Option, count: u32, start_key: Option, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns a storage entry at a specific block's state. - fn storage( + async fn storage( &self, block: Option, key: StorageKey, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns the hash of a storage entry at a block's state. - fn storage_hash( + async fn storage_hash( &self, block: Option, key: StorageKey, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns the size of a storage entry at a block's state. /// /// If data is available at `key`, it is returned. Else, the sum of values who's key has `key` /// prefix is returned, i.e. all the storage (double) maps that have this prefix. - fn storage_size( + async fn storage_size( &self, block: Option, key: StorageKey, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns the runtime metadata as an opaque blob. - fn metadata(&self, block: Option) -> FutureResult; + async fn metadata(&self, block: Option) -> Result; /// Get the runtime version. - fn runtime_version(&self, block: Option) -> FutureResult; + async fn runtime_version(&self, block: Option) -> Result; /// Query historical storage entries (by key) starting from a block given as the second /// parameter. /// /// NOTE This first returned result contains the initial state of storage for all keys. /// Subsequent values in the vector represent changes to the previous state (diffs). - fn query_storage( + async fn query_storage( &self, from: Block::Hash, to: Option, keys: Vec, - ) -> FutureResult>>; + ) -> Result>, Error>; /// Query storage entries (by key) starting at block hash given as the second parameter. - fn query_storage_at( + async fn query_storage_at( &self, keys: Vec, at: Option, - ) -> FutureResult>>; + ) -> Result>, Error>; /// Returns proof of storage entries at a specific block's state. - fn read_proof( + async fn read_proof( &self, block: Option, keys: Vec, - ) -> FutureResult>; - - /// New runtime version subscription - fn subscribe_runtime_version( - &self, - _meta: crate::Metadata, - subscriber: Subscriber, - ); - - /// Unsubscribe from runtime version subscription - fn unsubscribe_runtime_version( - &self, - _meta: Option, - id: SubscriptionId, - ) -> RpcResult; - - /// New storage subscription - fn subscribe_storage( - &self, - _meta: crate::Metadata, - subscriber: Subscriber>, - keys: Option>, - ); - - /// Unsubscribe from storage subscription - fn unsubscribe_storage( - &self, - _meta: Option, - id: SubscriptionId, - ) -> RpcResult; + ) -> Result, Error>; /// Trace storage changes for block - fn trace_block( + async fn trace_block( &self, block: Block::Hash, targets: Option, storage_keys: Option, methods: Option, - ) -> FutureResult; + ) -> Result; + + /// New runtime version subscription + fn subscribe_runtime_version(&self, sink: PendingSubscription); + + /// New storage subscription + fn subscribe_storage(&self, sink: PendingSubscription, keys: Option>); } /// Create new state API that works on full node. pub fn new_full( client: Arc, - subscriptions: SubscriptionManager, + executor: SubscriptionTaskExecutor, deny_unsafe: DenyUnsafe, rpc_max_payload: Option, -) -> (State, ChildState) +) -> (StateApi, ChildState) where Block: BlockT + 'static, Block::Hash: Unpin, @@ -207,168 +189,127 @@ where { let child_backend = Box::new(self::state_full::FullState::new( client.clone(), - subscriptions.clone(), + executor.clone(), rpc_max_payload, )); - let backend = - Box::new(self::state_full::FullState::new(client, subscriptions, rpc_max_payload)); - (State { backend, deny_unsafe }, ChildState { backend: child_backend }) + let backend = Box::new(self::state_full::FullState::new(client, executor, rpc_max_payload)); + (StateApi { backend, deny_unsafe }, ChildState { backend: child_backend }) } /// State API with subscriptions support. -pub struct State { +pub struct StateApi { backend: Box>, /// Whether to deny unsafe calls deny_unsafe: DenyUnsafe, } -impl StateApi for State +#[async_trait] +impl StateApiServer for StateApi where Block: BlockT + 'static, Client: Send + Sync + 'static, { - type Metadata = crate::Metadata; - - fn call(&self, method: String, data: Bytes, block: Option) -> FutureResult { - self.backend.call(block, method, data) + async fn call( + &self, + method: String, + data: Bytes, + block: Option, + ) -> RpcResult { + self.backend.call(block, method, data).await.map_err(Into::into) } - fn storage_keys( + async fn storage_keys( &self, key_prefix: StorageKey, block: Option, - ) -> FutureResult> { - self.backend.storage_keys(block, key_prefix) + ) -> RpcResult> { + self.backend.storage_keys(block, key_prefix).await.map_err(Into::into) } - fn storage_pairs( + async fn storage_pairs( &self, key_prefix: StorageKey, block: Option, - ) -> FutureResult> { - if let Err(err) = self.deny_unsafe.check_if_safe() { - return async move { Err(err.into()) }.boxed() - } - - self.backend.storage_pairs(block, key_prefix) + ) -> RpcResult> { + self.deny_unsafe.check_if_safe()?; + self.backend.storage_pairs(block, key_prefix).await.map_err(Into::into) } - fn storage_keys_paged( + async fn storage_keys_paged( &self, prefix: Option, count: u32, start_key: Option, block: Option, - ) -> FutureResult> { + ) -> RpcResult> { if count > STORAGE_KEYS_PAGED_MAX_COUNT { - return async move { - Err(Error::InvalidCount { value: count, max: STORAGE_KEYS_PAGED_MAX_COUNT }) - } - .boxed() + return Err(JsonRpseeError::from(Error::InvalidCount { + value: count, + max: STORAGE_KEYS_PAGED_MAX_COUNT, + })) } - self.backend.storage_keys_paged(block, prefix, count, start_key) + self.backend + .storage_keys_paged(block, prefix, count, start_key) + .await + .map_err(Into::into) } - fn storage( + async fn storage( &self, key: StorageKey, block: Option, - ) -> FutureResult> { - self.backend.storage(block, key) + ) -> RpcResult> { + self.backend.storage(block, key).await.map_err(Into::into) } - fn storage_hash( + async fn storage_hash( &self, key: StorageKey, block: Option, - ) -> FutureResult> { - self.backend.storage_hash(block, key) + ) -> RpcResult> { + self.backend.storage_hash(block, key).await.map_err(Into::into) } - fn storage_size( + async fn storage_size( &self, key: StorageKey, block: Option, - ) -> FutureResult> { - self.backend.storage_size(block, key) + ) -> RpcResult> { + self.backend.storage_size(block, key).await.map_err(Into::into) + } + + async fn metadata(&self, block: Option) -> RpcResult { + self.backend.metadata(block).await.map_err(Into::into) } - fn metadata(&self, block: Option) -> FutureResult { - self.backend.metadata(block) + async fn runtime_version(&self, at: Option) -> RpcResult { + self.backend.runtime_version(at).await.map_err(Into::into) } - fn query_storage( + async fn query_storage( &self, keys: Vec, from: Block::Hash, to: Option, - ) -> FutureResult>> { - if let Err(err) = self.deny_unsafe.check_if_safe() { - return async move { Err(err.into()) }.boxed() - } - - self.backend.query_storage(from, to, keys) + ) -> RpcResult>> { + self.deny_unsafe.check_if_safe()?; + self.backend.query_storage(from, to, keys).await.map_err(Into::into) } - fn query_storage_at( + async fn query_storage_at( &self, keys: Vec, at: Option, - ) -> FutureResult>> { - self.backend.query_storage_at(keys, at) + ) -> RpcResult>> { + self.backend.query_storage_at(keys, at).await.map_err(Into::into) } - fn read_proof( + async fn read_proof( &self, keys: Vec, block: Option, - ) -> FutureResult> { - self.backend.read_proof(block, keys) - } - - fn subscribe_storage( - &self, - meta: Self::Metadata, - subscriber: Subscriber>, - keys: Option>, - ) { - if keys.is_none() { - if let Err(err) = self.deny_unsafe.check_if_safe() { - subscriber.reject(err.into()) - .expect("subscription rejection can only fail if it's been already rejected, and we're rejecting it for the first time; qed"); - return - } - } - - self.backend.subscribe_storage(meta, subscriber, keys) - } - - fn unsubscribe_storage( - &self, - meta: Option, - id: SubscriptionId, - ) -> RpcResult { - self.backend.unsubscribe_storage(meta, id) - } - - fn runtime_version(&self, at: Option) -> FutureResult { - self.backend.runtime_version(at) - } - - fn subscribe_runtime_version( - &self, - meta: Self::Metadata, - subscriber: Subscriber, - ) { - self.backend.subscribe_runtime_version(meta, subscriber); - } - - fn unsubscribe_runtime_version( - &self, - meta: Option, - id: SubscriptionId, - ) -> RpcResult { - self.backend.unsubscribe_runtime_version(meta, id) + ) -> RpcResult> { + self.backend.read_proof(block, keys).await.map_err(Into::into) } /// Re-execute the given block with the tracing targets given in `targets` @@ -376,88 +317,102 @@ where /// /// Note: requires the node to run with `--rpc-methods=Unsafe`. /// Note: requires runtimes compiled with wasm tracing support, `--features with-tracing`. - fn trace_block( + async fn trace_block( &self, block: Block::Hash, targets: Option, storage_keys: Option, methods: Option, - ) -> FutureResult { - if let Err(err) = self.deny_unsafe.check_if_safe() { - return async move { Err(err.into()) }.boxed() + ) -> RpcResult { + self.deny_unsafe.check_if_safe()?; + self.backend + .trace_block(block, targets, storage_keys, methods) + .await + .map_err(Into::into) + } + + fn subscribe_runtime_version(&self, sink: PendingSubscription) { + self.backend.subscribe_runtime_version(sink) + } + + fn subscribe_storage(&self, sink: PendingSubscription, keys: Option>) { + if keys.is_none() { + if let Err(err) = self.deny_unsafe.check_if_safe() { + let _ = sink.reject(JsonRpseeError::from(err)); + return + } } - self.backend.trace_block(block, targets, storage_keys, methods) + self.backend.subscribe_storage(sink, keys) } } /// Child state backend API. +#[async_trait] pub trait ChildStateBackend: Send + Sync + 'static where Block: BlockT + 'static, Client: Send + Sync + 'static, { /// Returns proof of storage for a child key entries at a specific block's state. - fn read_child_proof( + async fn read_child_proof( &self, block: Option, storage_key: PrefixedStorageKey, keys: Vec, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns the keys with prefix from a child storage, /// leave prefix empty to get all the keys. - fn storage_keys( + async fn storage_keys( &self, block: Option, storage_key: PrefixedStorageKey, prefix: StorageKey, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns the keys with prefix from a child storage with pagination support. - fn storage_keys_paged( + async fn storage_keys_paged( &self, block: Option, storage_key: PrefixedStorageKey, prefix: Option, count: u32, start_key: Option, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns a child storage entry at a specific block's state. - fn storage( + async fn storage( &self, block: Option, storage_key: PrefixedStorageKey, key: StorageKey, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns child storage entries at a specific block's state. - fn storage_entries( + async fn storage_entries( &self, block: Option, storage_key: PrefixedStorageKey, keys: Vec, - ) -> FutureResult>>; + ) -> Result>, Error>; /// Returns the hash of a child storage entry at a block's state. - fn storage_hash( + async fn storage_hash( &self, block: Option, storage_key: PrefixedStorageKey, key: StorageKey, - ) -> FutureResult>; + ) -> Result, Error>; /// Returns the size of a child storage entry at a block's state. - fn storage_size( + async fn storage_size( &self, block: Option, storage_key: PrefixedStorageKey, key: StorageKey, - ) -> FutureResult> { - self.storage(block, storage_key, key) - .map(|x| x.map(|r| r.map(|v| v.0.len() as u64))) - .boxed() + ) -> Result, Error> { + self.storage(block, storage_key, key).await.map(|x| x.map(|x| x.0.len() as u64)) } } @@ -466,76 +421,84 @@ pub struct ChildState { backend: Box>, } -impl ChildStateApi for ChildState +#[async_trait] +impl ChildStateApiServer for ChildState where Block: BlockT + 'static, Client: Send + Sync + 'static, { - type Metadata = crate::Metadata; - - fn read_child_proof( + async fn storage_keys( &self, - child_storage_key: PrefixedStorageKey, - keys: Vec, + storage_key: PrefixedStorageKey, + key_prefix: StorageKey, block: Option, - ) -> FutureResult> { - self.backend.read_child_proof(block, child_storage_key, keys) + ) -> RpcResult> { + self.backend + .storage_keys(block, storage_key, key_prefix) + .await + .map_err(Into::into) } - fn storage( + async fn storage_keys_paged( &self, storage_key: PrefixedStorageKey, - key: StorageKey, + prefix: Option, + count: u32, + start_key: Option, block: Option, - ) -> FutureResult> { - self.backend.storage(block, storage_key, key) + ) -> RpcResult> { + self.backend + .storage_keys_paged(block, storage_key, prefix, count, start_key) + .await + .map_err(Into::into) } - fn storage_entries( + async fn storage( &self, storage_key: PrefixedStorageKey, - keys: Vec, + key: StorageKey, block: Option, - ) -> FutureResult>> { - self.backend.storage_entries(block, storage_key, keys) + ) -> RpcResult> { + self.backend.storage(block, storage_key, key).await.map_err(Into::into) } - fn storage_keys( + async fn storage_entries( &self, storage_key: PrefixedStorageKey, - key_prefix: StorageKey, + keys: Vec, block: Option, - ) -> FutureResult> { - self.backend.storage_keys(block, storage_key, key_prefix) + ) -> RpcResult>> { + self.backend.storage_entries(block, storage_key, keys).await.map_err(Into::into) } - fn storage_keys_paged( + async fn storage_hash( &self, storage_key: PrefixedStorageKey, - prefix: Option, - count: u32, - start_key: Option, + key: StorageKey, block: Option, - ) -> FutureResult> { - self.backend.storage_keys_paged(block, storage_key, prefix, count, start_key) + ) -> RpcResult> { + self.backend.storage_hash(block, storage_key, key).await.map_err(Into::into) } - fn storage_hash( + async fn storage_size( &self, storage_key: PrefixedStorageKey, key: StorageKey, block: Option, - ) -> FutureResult> { - self.backend.storage_hash(block, storage_key, key) + ) -> RpcResult> { + self.backend.storage_size(block, storage_key, key).await.map_err(Into::into) } - fn storage_size( + async fn read_child_proof( &self, - storage_key: PrefixedStorageKey, - key: StorageKey, + child_storage_key: PrefixedStorageKey, + keys: Vec, block: Option, - ) -> FutureResult> { - self.backend.storage_size(block, storage_key, key) + ) -> RpcResult> { + self.backend + .read_child_proof(block, child_storage_key, keys) + .await + .map_err(Into::into) } } diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 38f9b078d87a7..48165e912b03a 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -18,17 +18,26 @@ //! State API backend for full nodes. -use futures::{ - future, - future::{err, try_join_all}, - stream, FutureExt, SinkExt, StreamExt, +use std::{collections::HashMap, marker::PhantomData, sync::Arc}; + +use super::{ + client_err, + error::{Error, Result}, + ChildStateBackend, StateBackend, }; -use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId}; -use log::warn; -use rpc::Result as RpcResult; -use std::{collections::HashMap, sync::Arc}; +use crate::SubscriptionTaskExecutor; +use futures::{future, stream, FutureExt, StreamExt}; +use jsonrpsee::{ + core::{async_trait, Error as JsonRpseeError}, + PendingSubscription, +}; +use sc_client_api::{ + Backend, BlockBackend, BlockchainEvents, CallExecutor, ExecutorProvider, ProofProvider, + StorageProvider, +}; use sc_rpc_api::state::ReadProof; +use sp_api::{CallApiAt, Metadata, ProvideRuntimeApi}; use sp_blockchain::{ CachedHeaderMetadata, Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult, @@ -42,19 +51,6 @@ use sp_core::{ use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_version::RuntimeVersion; -use sp_api::{CallApiAt, Metadata, ProvideRuntimeApi}; - -use super::{ - client_err, - error::{Error, FutureResult, Result}, - ChildStateBackend, StateBackend, -}; -use sc_client_api::{ - Backend, BlockBackend, BlockchainEvents, CallExecutor, ExecutorProvider, ProofProvider, - StorageNotification, StorageProvider, -}; -use std::marker::PhantomData; - /// Ranges to query in state_queryStorage. struct QueryStorageRange { /// Hashes of all the blocks in the range. @@ -64,7 +60,7 @@ struct QueryStorageRange { /// State API backend for full nodes. pub struct FullState { client: Arc, - subscriptions: SubscriptionManager, + executor: SubscriptionTaskExecutor, _phantom: PhantomData<(BE, Block)>, rpc_max_payload: Option, } @@ -81,10 +77,10 @@ where /// Create new state API backend for full nodes. pub fn new( client: Arc, - subscriptions: SubscriptionManager, + executor: SubscriptionTaskExecutor, rpc_max_payload: Option, ) -> Self { - Self { client, subscriptions, _phantom: PhantomData, rpc_max_payload } + Self { client, executor, _phantom: PhantomData, rpc_max_payload } } /// Returns given block hash or best block hash if None is passed. @@ -174,6 +170,7 @@ where } } +#[async_trait] impl StateBackend for FullState where Block: BlockT + 'static, @@ -193,14 +190,13 @@ where + 'static, Client::Api: Metadata, { - fn call( + async fn call( &self, block: Option, method: String, call_data: Bytes, - ) -> FutureResult { - let r = self - .block_or_best(block) + ) -> std::result::Result { + self.block_or_best(block) .and_then(|block| { self.client .executor() @@ -213,43 +209,37 @@ where ) .map(Into::into) }) - .map_err(client_err); - async move { r }.boxed() + .map_err(client_err) } - fn storage_keys( + async fn storage_keys( &self, block: Option, prefix: StorageKey, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| self.client.storage_keys(&BlockId::Hash(block), &prefix)) - .map_err(client_err); - async move { r }.boxed() + .map_err(client_err) } - fn storage_pairs( + async fn storage_pairs( &self, block: Option, prefix: StorageKey, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| self.client.storage_pairs(&BlockId::Hash(block), &prefix)) - .map_err(client_err); - async move { r }.boxed() + .map_err(client_err) } - fn storage_keys_paged( + async fn storage_keys_paged( &self, block: Option, prefix: Option, count: u32, start_key: Option, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| { self.client.storage_keys_iter( &BlockId::Hash(block), @@ -258,40 +248,36 @@ where ) }) .map(|iter| iter.take(count as usize).collect()) - .map_err(client_err); - async move { r }.boxed() + .map_err(client_err) } - fn storage( + async fn storage( &self, block: Option, key: StorageKey, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| self.client.storage(&BlockId::Hash(block), &key)) - .map_err(client_err); - async move { r }.boxed() + .map_err(client_err) } - fn storage_size( + async fn storage_size( &self, block: Option, key: StorageKey, - ) -> FutureResult> { + ) -> std::result::Result, Error> { let block = match self.block_or_best(block) { Ok(b) => b, - Err(e) => return async move { Err(client_err(e)) }.boxed(), + Err(e) => return Err(client_err(e)), }; match self.client.storage(&BlockId::Hash(block), &key) { - Ok(Some(d)) => return async move { Ok(Some(d.0.len() as u64)) }.boxed(), - Err(e) => return async move { Err(client_err(e)) }.boxed(), + Ok(Some(d)) => return Ok(Some(d.0.len() as u64)), + Err(e) => return Err(client_err(e)), Ok(None) => {}, } - let r = self - .client + self.client .storage_pairs(&BlockId::Hash(block), &key) .map(|kv| { let item_sum = kv.iter().map(|(_, v)| v.0.len() as u64).sum::(); @@ -301,48 +287,46 @@ where None } }) - .map_err(client_err); - async move { r }.boxed() + .map_err(client_err) } - fn storage_hash( + async fn storage_hash( &self, block: Option, key: StorageKey, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| self.client.storage_hash(&BlockId::Hash(block), &key)) - .map_err(client_err); - async move { r }.boxed() + .map_err(client_err) } - fn metadata(&self, block: Option) -> FutureResult { - let r = self.block_or_best(block).map_err(client_err).and_then(|block| { + async fn metadata(&self, block: Option) -> std::result::Result { + self.block_or_best(block).map_err(client_err).and_then(|block| { self.client .runtime_api() .metadata(&BlockId::Hash(block)) .map(Into::into) .map_err(|e| Error::Client(Box::new(e))) - }); - async move { r }.boxed() + }) } - fn runtime_version(&self, block: Option) -> FutureResult { - let r = self.block_or_best(block).map_err(client_err).and_then(|block| { + async fn runtime_version( + &self, + block: Option, + ) -> std::result::Result { + self.block_or_best(block).map_err(client_err).and_then(|block| { self.client .runtime_version_at(&BlockId::Hash(block)) .map_err(|e| Error::Client(Box::new(e))) - }); - async move { r }.boxed() + }) } - fn query_storage( + async fn query_storage( &self, from: Block::Hash, to: Option, keys: Vec, - ) -> FutureResult>> { + ) -> std::result::Result>, Error> { let call_fn = move || { let range = self.query_storage_range(from, to)?; let mut changes = Vec::new(); @@ -350,168 +334,151 @@ where self.query_storage_unfiltered(&range, &keys, &mut last_values, &mut changes)?; Ok(changes) }; - - let r = call_fn(); - async move { r }.boxed() + call_fn() } - fn query_storage_at( + async fn query_storage_at( &self, keys: Vec, at: Option, - ) -> FutureResult>> { + ) -> std::result::Result>, Error> { let at = at.unwrap_or_else(|| self.client.info().best_hash); - self.query_storage(at, Some(at), keys) + self.query_storage(at, Some(at), keys).await } - fn read_proof( + async fn read_proof( &self, block: Option, keys: Vec, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| { self.client .read_proof(&BlockId::Hash(block), &mut keys.iter().map(|key| key.0.as_ref())) .map(|proof| proof.iter_nodes().map(|node| node.into()).collect()) .map(|proof| ReadProof { at: block, proof }) }) - .map_err(client_err); - async move { r }.boxed() + .map_err(client_err) } - fn subscribe_runtime_version( - &self, - _meta: crate::Metadata, - subscriber: Subscriber, - ) { - self.subscriptions.add(subscriber, |sink| { - let version = self - .block_or_best(None) - .and_then(|block| { - self.client.runtime_version_at(&BlockId::Hash(block)).map_err(Into::into) - }) - .map_err(client_err) - .map_err(Into::into); + fn subscribe_runtime_version(&self, pending: PendingSubscription) { + let client = self.client.clone(); - let client = self.client.clone(); - let mut previous_version = version.clone(); + let initial = match self + .block_or_best(None) + .and_then(|block| { + self.client.runtime_version_at(&BlockId::Hash(block)).map_err(Into::into) + }) + .map_err(|e| Error::Client(Box::new(e))) + { + Ok(initial) => initial, + Err(e) => { + pending.reject(JsonRpseeError::from(e)); + return + }, + }; - // A stream of all best blocks. - let stream = - client.import_notification_stream().filter(|n| future::ready(n.is_new_best)); + let mut previous_version = initial.clone(); - let stream = stream.filter_map(move |n| { + // A stream of new versions + let version_stream = client + .import_notification_stream() + .filter(|n| future::ready(n.is_new_best)) + .filter_map(move |n| { let version = client .runtime_version_at(&BlockId::hash(n.hash)) - .map_err(|e| Error::Client(Box::new(e))) - .map_err(Into::into); - - if previous_version != version { - previous_version = version.clone(); - future::ready(Some(Ok::<_, ()>(version))) - } else { - future::ready(None) + .map_err(|e| Error::Client(Box::new(e))); + + match version { + Ok(version) if version != previous_version => { + previous_version = version.clone(); + future::ready(Some(version)) + }, + _ => future::ready(None), } }); - stream::iter(vec![Ok(version)]) - .chain(stream) - .forward(sink.sink_map_err(|e| warn!("Error sending notifications: {:?}", e))) - // we ignore the resulting Stream (if the first stream is over we are unsubscribed) - .map(|_| ()) - }); - } + let stream = futures::stream::once(future::ready(initial)).chain(version_stream); - fn unsubscribe_runtime_version( - &self, - _meta: Option, - id: SubscriptionId, - ) -> RpcResult { - Ok(self.subscriptions.cancel(id)) + let fut = async move { + if let Some(mut sink) = pending.accept() { + sink.pipe_from_stream(stream).await; + } + } + .boxed(); + + self.executor + .spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); } - fn subscribe_storage( - &self, - _meta: crate::Metadata, - subscriber: Subscriber>, - keys: Option>, - ) { - let keys = Into::>>::into(keys); + fn subscribe_storage(&self, pending: PendingSubscription, keys: Option>) { let stream = match self.client.storage_changes_notification_stream(keys.as_deref(), None) { Ok(stream) => stream, - Err(err) => { - let _ = subscriber.reject(client_err(err).into()); + Err(blockchain_err) => { + pending.reject(JsonRpseeError::from(Error::Client(Box::new(blockchain_err)))); return }, }; // initial values - let initial = stream::iter( - keys.map(|keys| { - let block = self.client.info().best_hash; - let changes = keys - .into_iter() - .map(|key| { - let v = self.client.storage(&BlockId::Hash(block), &key).ok().flatten(); - (key, v) - }) - .collect(); - vec![Ok(Ok(StorageChangeSet { block, changes }))] - }) - .unwrap_or_default(), - ); - - self.subscriptions.add(subscriber, |sink| { - let stream = stream.map(|StorageNotification { block, changes }| { - Ok(Ok::<_, rpc::Error>(StorageChangeSet { - block, - changes: changes - .iter() - .filter_map(|(o_sk, k, v)| o_sk.is_none().then(|| (k.clone(), v.cloned()))) - .collect(), - })) - }); - - initial - .chain(stream) - .forward(sink.sink_map_err(|e| warn!("Error sending notifications: {:?}", e))) - // we ignore the resulting Stream (if the first stream is over we are unsubscribed) - .map(|_| ()) + let initial = stream::iter(keys.map(|keys| { + let block = self.client.info().best_hash; + let changes = keys + .into_iter() + .map(|key| { + let v = self.client.storage(&BlockId::Hash(block), &key).ok().flatten(); + (key, v) + }) + .collect(); + StorageChangeSet { block, changes } + })); + + // let storage_stream = stream.map(|(block, changes)| StorageChangeSet { + let storage_stream = stream.map(|storage_notif| StorageChangeSet { + block: storage_notif.block, + changes: storage_notif + .changes + .iter() + .filter_map(|(o_sk, k, v)| o_sk.is_none().then(|| (k.clone(), v.cloned()))) + .collect(), }); - } - fn unsubscribe_storage( - &self, - _meta: Option, - id: SubscriptionId, - ) -> RpcResult { - Ok(self.subscriptions.cancel(id)) + let stream = initial + .chain(storage_stream) + .filter(|storage| future::ready(!storage.changes.is_empty())); + + let fut = async move { + if let Some(mut sink) = pending.accept() { + sink.pipe_from_stream(stream).await; + } + } + .boxed(); + + self.executor + .spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); } - fn trace_block( + async fn trace_block( &self, block: Block::Hash, targets: Option, storage_keys: Option, methods: Option, - ) -> FutureResult { - let block_executor = sc_tracing::block::BlockExecutor::new( + ) -> std::result::Result { + sc_tracing::block::BlockExecutor::new( self.client.clone(), block, targets, storage_keys, methods, self.rpc_max_payload, - ); - let r = block_executor - .trace_block() - .map_err(|e| invalid_block::(block, None, e.to_string())); - async move { r }.boxed() + ) + .trace_block() + .map_err(|e| invalid_block::(block, None, e.to_string())) } } +#[async_trait] impl ChildStateBackend for FullState where Block: BlockT + 'static, @@ -530,14 +497,13 @@ where + 'static, Client::Api: Metadata, { - fn read_child_proof( + async fn read_child_proof( &self, block: Option, storage_key: PrefixedStorageKey, keys: Vec, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| { let child_info = match ChildType::from_prefixed_key(&storage_key) { Some((ChildType::ParentKeyId, storage_key)) => @@ -553,19 +519,16 @@ where .map(|proof| proof.iter_nodes().map(|node| node.into()).collect()) .map(|proof| ReadProof { at: block, proof }) }) - .map_err(client_err); - - async move { r }.boxed() + .map_err(client_err) } - fn storage_keys( + async fn storage_keys( &self, block: Option, storage_key: PrefixedStorageKey, prefix: StorageKey, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| { let child_info = match ChildType::from_prefixed_key(&storage_key) { Some((ChildType::ParentKeyId, storage_key)) => @@ -574,21 +537,18 @@ where }; self.client.child_storage_keys(&BlockId::Hash(block), &child_info, &prefix) }) - .map_err(client_err); - - async move { r }.boxed() + .map_err(client_err) } - fn storage_keys_paged( + async fn storage_keys_paged( &self, block: Option, storage_key: PrefixedStorageKey, prefix: Option, count: u32, start_key: Option, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| { let child_info = match ChildType::from_prefixed_key(&storage_key) { Some((ChildType::ParentKeyId, storage_key)) => @@ -603,19 +563,16 @@ where ) }) .map(|iter| iter.take(count as usize).collect()) - .map_err(client_err); - - async move { r }.boxed() + .map_err(client_err) } - fn storage( + async fn storage( &self, block: Option, storage_key: PrefixedStorageKey, key: StorageKey, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| { let child_info = match ChildType::from_prefixed_key(&storage_key) { Some((ChildType::ParentKeyId, storage_key)) => @@ -624,28 +581,25 @@ where }; self.client.child_storage(&BlockId::Hash(block), &child_info, &key) }) - .map_err(client_err); - - async move { r }.boxed() + .map_err(client_err) } - fn storage_entries( + async fn storage_entries( &self, block: Option, storage_key: PrefixedStorageKey, keys: Vec, - ) -> FutureResult>> { - let child_info = match ChildType::from_prefixed_key(&storage_key) { - Some((ChildType::ParentKeyId, storage_key)) => - Arc::new(ChildInfo::new_default(storage_key)), - None => return err(client_err(sp_blockchain::Error::InvalidChildStorageKey)).boxed(), - }; - let block = match self.block_or_best(block) { - Ok(b) => b, - Err(e) => return err(client_err(e)).boxed(), + ) -> std::result::Result>, Error> { + let child_info = if let Some((ChildType::ParentKeyId, storage_key)) = + ChildType::from_prefixed_key(&storage_key) + { + Arc::new(ChildInfo::new_default(storage_key)) + } else { + return Err(client_err(sp_blockchain::Error::InvalidChildStorageKey)) }; + let block = self.block_or_best(block).map_err(client_err)?; let client = self.client.clone(); - try_join_all(keys.into_iter().map(move |key| { + future::try_join_all(keys.into_iter().map(move |key| { let res = client .clone() .child_storage(&BlockId::Hash(block), &child_info, &key) @@ -653,17 +607,16 @@ where async move { res } })) - .boxed() + .await } - fn storage_hash( + async fn storage_hash( &self, block: Option, storage_key: PrefixedStorageKey, key: StorageKey, - ) -> FutureResult> { - let r = self - .block_or_best(block) + ) -> std::result::Result, Error> { + self.block_or_best(block) .and_then(|block| { let child_info = match ChildType::from_prefixed_key(&storage_key) { Some((ChildType::ParentKeyId, storage_key)) => @@ -672,9 +625,7 @@ where }; self.client.child_storage_hash(&BlockId::Hash(block), &child_info, &key) }) - .map_err(client_err); - - async move { r }.boxed() + .map_err(client_err) } } diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 19e474ee6459a..a375a30d2c1a2 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -18,9 +18,13 @@ use self::error::Error; use super::*; -use crate::testing::TaskExecutor; +use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; -use futures::{executor, StreamExt}; +use futures::executor; +use jsonrpsee::{ + core::Error as RpcError, + types::{error::CallError as RpcCallError, EmptyParams, ErrorObject}, +}; use sc_block_builder::BlockBuilderProvider; use sc_rpc_api::DenyUnsafe; use sp_consensus::BlockOrigin; @@ -36,8 +40,8 @@ fn prefixed_storage_key() -> PrefixedStorageKey { child_info.prefixed_storage_key() } -#[test] -fn should_return_storage() { +#[tokio::test] +async fn should_return_storage() { const KEY: &[u8] = b":mock"; const VALUE: &[u8] = b"hello world"; const CHILD_VALUE: &[u8] = b"hello world !"; @@ -51,49 +55,46 @@ fn should_return_storage() { .add_extra_storage(b":map:acc2".to_vec(), vec![1, 2, 3]) .build(); let genesis_hash = client.genesis_hash(); - let (client, child) = new_full( - Arc::new(client), - SubscriptionManager::new(Arc::new(TaskExecutor)), - DenyUnsafe::No, - None, - ); + let (client, child) = new_full(Arc::new(client), test_executor(), DenyUnsafe::No, None); let key = StorageKey(KEY.to_vec()); assert_eq!( - executor::block_on(client.storage(key.clone(), Some(genesis_hash).into())) + client + .storage(key.clone(), Some(genesis_hash).into()) + .await .map(|x| x.map(|x| x.0.len())) .unwrap() .unwrap() as usize, VALUE.len(), ); assert_matches!( - executor::block_on(client.storage_hash(key.clone(), Some(genesis_hash).into())) + client + .storage_hash(key.clone(), Some(genesis_hash).into()) + .await .map(|x| x.is_some()), Ok(true) ); assert_eq!( - executor::block_on(client.storage_size(key.clone(), None)).unwrap().unwrap() as usize, + client.storage_size(key.clone(), None).await.unwrap().unwrap() as usize, VALUE.len(), ); assert_eq!( - executor::block_on(client.storage_size(StorageKey(b":map".to_vec()), None)) - .unwrap() - .unwrap() as usize, + client.storage_size(StorageKey(b":map".to_vec()), None).await.unwrap().unwrap() as usize, 2 + 3, ); assert_eq!( - executor::block_on( - child - .storage(prefixed_storage_key(), key, Some(genesis_hash).into()) - .map(|x| x.map(|x| x.unwrap().0.len())) - ) - .unwrap() as usize, + child + .storage(prefixed_storage_key(), key, Some(genesis_hash).into()) + .await + .map(|x| x.map(|x| x.0.len())) + .unwrap() + .unwrap() as usize, CHILD_VALUE.len(), ); } -#[test] -fn should_return_storage_entries() { +#[tokio::test] +async fn should_return_storage_entries() { const KEY1: &[u8] = b":mock"; const KEY2: &[u8] = b":turtle"; const VALUE: &[u8] = b"hello world"; @@ -107,22 +108,15 @@ fn should_return_storage_entries() { .add_extra_child_storage(&child_info, KEY2.to_vec(), CHILD_VALUE2.to_vec()) .build(); let genesis_hash = client.genesis_hash(); - let (_client, child) = new_full( - Arc::new(client), - SubscriptionManager::new(Arc::new(TaskExecutor)), - DenyUnsafe::No, - None, - ); + let (_client, child) = new_full(Arc::new(client), test_executor(), DenyUnsafe::No, None); let keys = &[StorageKey(KEY1.to_vec()), StorageKey(KEY2.to_vec())]; assert_eq!( - executor::block_on(child.storage_entries( - prefixed_storage_key(), - keys.to_vec(), - Some(genesis_hash).into() - )) - .map(|x| x.into_iter().map(|x| x.map(|x| x.0.len()).unwrap()).sum::()) - .unwrap(), + child + .storage_entries(prefixed_storage_key(), keys.to_vec(), Some(genesis_hash).into()) + .await + .map(|x| x.into_iter().map(|x| x.map(|x| x.0.len()).unwrap()).sum::()) + .unwrap(), CHILD_VALUE1.len() + CHILD_VALUE2.len() ); @@ -130,18 +124,16 @@ fn should_return_storage_entries() { let mut failing_keys = vec![StorageKey(b":soup".to_vec())]; failing_keys.extend_from_slice(keys); assert_matches!( - executor::block_on(child.storage_entries( - prefixed_storage_key(), - failing_keys, - Some(genesis_hash).into() - )) - .map(|x| x.iter().all(|x| x.is_some())), + child + .storage_entries(prefixed_storage_key(), failing_keys, Some(genesis_hash).into()) + .await + .map(|x| x.iter().all(|x| x.is_some())), Ok(false) ); } -#[test] -fn should_return_child_storage() { +#[tokio::test] +async fn should_return_child_storage() { let child_info = ChildInfo::new_default(STORAGE_KEY); let client = Arc::new( substrate_test_runtime_client::TestClientBuilder::new() @@ -149,49 +141,30 @@ fn should_return_child_storage() { .build(), ); let genesis_hash = client.genesis_hash(); - let (_client, child) = - new_full(client, SubscriptionManager::new(Arc::new(TaskExecutor)), DenyUnsafe::No, None); + let (_client, child) = new_full(client, test_executor(), DenyUnsafe::No, None); let child_key = prefixed_storage_key(); let key = StorageKey(b"key".to_vec()); assert_matches!( - executor::block_on(child.storage( + child.storage( child_key.clone(), key.clone(), Some(genesis_hash).into(), - )), + ).await, Ok(Some(StorageData(ref d))) if d[0] == 42 && d.len() == 1 ); - - // should fail if key does not exist. - let failing_key = StorageKey(b":soup".to_vec()); assert_matches!( - executor::block_on(child.storage( - prefixed_storage_key(), - failing_key, - Some(genesis_hash).into() - )) - .map(|x| x.is_some()), - Ok(false) - ); - - assert_matches!( - executor::block_on(child.storage_hash( - child_key.clone(), - key.clone(), - Some(genesis_hash).into(), - )) - .map(|x| x.is_some()), + child + .storage_hash(child_key.clone(), key.clone(), Some(genesis_hash).into(),) + .await + .map(|x| x.is_some()), Ok(true) ); - assert_matches!( - executor::block_on(child.storage_size(child_key.clone(), key.clone(), None)), - Ok(Some(1)) - ); + assert_matches!(child.storage_size(child_key.clone(), key.clone(), None).await, Ok(Some(1))); } -#[test] -fn should_return_child_storage_entries() { +#[tokio::test] +async fn should_return_child_storage_entries() { let child_info = ChildInfo::new_default(STORAGE_KEY); let client = Arc::new( substrate_test_runtime_client::TestClientBuilder::new() @@ -200,17 +173,14 @@ fn should_return_child_storage_entries() { .build(), ); let genesis_hash = client.genesis_hash(); - let (_client, child) = - new_full(client, SubscriptionManager::new(Arc::new(TaskExecutor)), DenyUnsafe::No, None); + let (_client, child) = new_full(client, test_executor(), DenyUnsafe::No, None); let child_key = prefixed_storage_key(); let keys = vec![StorageKey(b"key1".to_vec()), StorageKey(b"key2".to_vec())]; - let res = executor::block_on(child.storage_entries( - child_key.clone(), - keys.clone(), - Some(genesis_hash).into(), - )) - .unwrap(); + let res = child + .storage_entries(child_key.clone(), keys.clone(), Some(genesis_hash).into()) + .await + .unwrap(); assert_matches!( res[0], @@ -232,46 +202,37 @@ fn should_return_child_storage_entries() { Ok(true) ); assert_matches!( - executor::block_on(child.storage_size(child_key.clone(), keys[0].clone(), None)), + child.storage_size(child_key.clone(), keys[0].clone(), None).await, Ok(Some(1)) ); } -#[test] -fn should_call_contract() { +#[tokio::test] +async fn should_call_contract() { let client = Arc::new(substrate_test_runtime_client::new()); let genesis_hash = client.genesis_hash(); - let (client, _child) = - new_full(client, SubscriptionManager::new(Arc::new(TaskExecutor)), DenyUnsafe::No, None); + let (client, _child) = new_full(client, test_executor(), DenyUnsafe::No, None); + + use jsonrpsee::{core::Error, types::error::CallError}; assert_matches!( - executor::block_on(client.call( - "balanceOf".into(), - Bytes(vec![1, 2, 3]), - Some(genesis_hash).into() - )), - Err(Error::Client(_)) + client + .call("balanceOf".into(), Bytes(vec![1, 2, 3]), Some(genesis_hash).into()) + .await, + Err(Error::Call(CallError::Failed(_))) ) } -#[test] -fn should_notify_about_storage_changes() { - let (subscriber, id, mut transport) = Subscriber::new_test("test"); - - { +#[tokio::test] +async fn should_notify_about_storage_changes() { + let mut sub = { let mut client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full( - client.clone(), - SubscriptionManager::new(Arc::new(TaskExecutor)), - DenyUnsafe::No, - None, - ); - - api.subscribe_storage(Default::default(), subscriber, None.into()); + let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No, None); - // assert id assigned - assert!(matches!(executor::block_on(id), Ok(Ok(SubscriptionId::String(_))))); + let api_rpc = api.into_rpc(); + let sub = api_rpc.subscribe("state_subscribeStorage", EmptyParams::new()).await.unwrap(); + // Cause a change: let mut builder = client.new_block(Default::default()).unwrap(); builder .push_transfer(runtime::Transfer { @@ -282,38 +243,32 @@ fn should_notify_about_storage_changes() { }) .unwrap(); let block = builder.build().unwrap().block; - executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); - } + client.import(BlockOrigin::Own, block).await.unwrap(); - // Check notification sent to transport - executor::block_on((&mut transport).take(2).collect::>()); - assert!(executor::block_on(transport.next()).is_none()); -} + sub + }; -#[test] -fn should_send_initial_storage_changes_and_notifications() { - let (subscriber, id, mut transport) = Subscriber::new_test("test"); + // We should get a message back on our subscription about the storage change: + // NOTE: previous versions of the subscription code used to return an empty value for the + // "initial" storage change here + assert_matches!(timeout_secs(1, sub.next::>()).await, Ok(Some(_))); + assert_matches!(timeout_secs(1, sub.next::>()).await, Ok(None)); +} - { +#[tokio::test] +async fn should_send_initial_storage_changes_and_notifications() { + let mut sub = { let mut client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full( - client.clone(), - SubscriptionManager::new(Arc::new(TaskExecutor)), - DenyUnsafe::No, - None, - ); + let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No, None); let alice_balance_key = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Alice.into())); - api.subscribe_storage( - Default::default(), - subscriber, - Some(vec![StorageKey(alice_balance_key.to_vec())]).into(), - ); - - // assert id assigned - assert!(matches!(executor::block_on(id), Ok(Ok(SubscriptionId::String(_))))); + let api_rpc = api.into_rpc(); + let sub = api_rpc + .subscribe("state_subscribeStorage", [[StorageKey(alice_balance_key.to_vec())]]) + .await + .unwrap(); let mut builder = client.new_block(Default::default()).unwrap(); builder @@ -325,23 +280,22 @@ fn should_send_initial_storage_changes_and_notifications() { }) .unwrap(); let block = builder.build().unwrap().block; - executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); - } + client.import(BlockOrigin::Own, block).await.unwrap(); + + sub + }; + + assert_matches!(timeout_secs(1, sub.next::>()).await, Ok(Some(_))); + assert_matches!(timeout_secs(1, sub.next::>()).await, Ok(Some(_))); - // Check for the correct number of notifications - executor::block_on((&mut transport).take(2).collect::>()); - assert!(executor::block_on(transport.next()).is_none()); + // No more messages to follow + assert_matches!(timeout_secs(1, sub.next::>()).await, Ok(None)); } -#[test] -fn should_query_storage() { - fn run_tests(mut client: Arc) { - let (api, _child) = new_full( - client.clone(), - SubscriptionManager::new(Arc::new(TaskExecutor)), - DenyUnsafe::No, - None, - ); +#[tokio::test] +async fn should_query_storage() { + async fn run_tests(mut client: Arc) { + let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No, None); let mut add_block = |nonce| { let mut builder = client.new_block(Default::default()).unwrap(); @@ -393,7 +347,7 @@ fn should_query_storage() { let keys = (1..6).map(|k| StorageKey(vec![k])).collect::>(); let result = api.query_storage(keys.clone(), genesis_hash, Some(block1_hash).into()); - assert_eq!(executor::block_on(result).unwrap(), expected); + assert_eq!(result.await.unwrap(), expected); // Query all changes let result = api.query_storage(keys.clone(), genesis_hash, None.into()); @@ -406,23 +360,28 @@ fn should_query_storage() { (StorageKey(vec![5]), Some(StorageData(vec![1]))), ], }); - assert_eq!(executor::block_on(result).unwrap(), expected); + assert_eq!(result.await.unwrap(), expected); // Query changes up to block2. let result = api.query_storage(keys.clone(), genesis_hash, Some(block2_hash)); - assert_eq!(executor::block_on(result).unwrap(), expected); + assert_eq!(result.await.unwrap(), expected); // Inverted range. let result = api.query_storage(keys.clone(), block1_hash, Some(genesis_hash)); assert_eq!( - executor::block_on(result).map_err(|e| e.to_string()), - Err(Error::InvalidBlockRange { - from: format!("1 ({:?})", block1_hash), - to: format!("0 ({:?})", genesis_hash), - details: "from number > to number".to_owned(), - }) + result.await.map_err(|e| e.to_string()), + Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( + 4001, + Error::InvalidBlockRange { + from: format!("1 ({:?})", block1_hash), + to: format!("0 ({:?})", genesis_hash), + details: "from number > to number".to_owned(), + } + .to_string(), + None::<()>, + )))) .map_err(|e| e.to_string()) ); @@ -433,15 +392,20 @@ fn should_query_storage() { let result = api.query_storage(keys.clone(), genesis_hash, Some(random_hash1)); assert_eq!( - executor::block_on(result).map_err(|e| e.to_string()), - Err(Error::InvalidBlockRange { - from: format!("{:?}", genesis_hash), - to: format!("{:?}", Some(random_hash1)), - details: format!( - "UnknownBlock: Header was not found in the database: {:?}", - random_hash1 - ), - }) + result.await.map_err(|e| e.to_string()), + Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( + 4001, + Error::InvalidBlockRange { + from: format!("{:?}", genesis_hash), + to: format!("{:?}", Some(random_hash1)), + details: format!( + "UnknownBlock: Header was not found in the database: {:?}", + random_hash1 + ), + } + .to_string(), + None::<()>, + )))) .map_err(|e| e.to_string()) ); @@ -449,15 +413,20 @@ fn should_query_storage() { let result = api.query_storage(keys.clone(), random_hash1, Some(genesis_hash)); assert_eq!( - executor::block_on(result).map_err(|e| e.to_string()), - Err(Error::InvalidBlockRange { - from: format!("{:?}", random_hash1), - to: format!("{:?}", Some(genesis_hash)), - details: format!( - "UnknownBlock: Header was not found in the database: {:?}", - random_hash1 - ), - }) + result.await.map_err(|e| e.to_string()), + Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( + 4001, + Error::InvalidBlockRange { + from: format!("{:?}", random_hash1), + to: format!("{:?}", Some(genesis_hash)), + details: format!( + "UnknownBlock: Header was not found in the database: {:?}", + random_hash1 + ), + } + .to_string(), + None::<()>, + )))) .map_err(|e| e.to_string()), ); @@ -465,15 +434,20 @@ fn should_query_storage() { let result = api.query_storage(keys.clone(), random_hash1, None); assert_eq!( - executor::block_on(result).map_err(|e| e.to_string()), - Err(Error::InvalidBlockRange { - from: format!("{:?}", random_hash1), - to: format!("{:?}", Some(block2_hash)), // Best block hash. - details: format!( - "UnknownBlock: Header was not found in the database: {:?}", - random_hash1 - ), - }) + result.await.map_err(|e| e.to_string()), + Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( + 4001, + Error::InvalidBlockRange { + from: format!("{:?}", random_hash1), + to: format!("{:?}", Some(block2_hash)), // Best block hash. + details: format!( + "UnknownBlock: Header was not found in the database: {:?}", + random_hash1 + ), + } + .to_string(), + None::<()>, + )))) .map_err(|e| e.to_string()), ); @@ -481,15 +455,20 @@ fn should_query_storage() { let result = api.query_storage(keys.clone(), random_hash1, Some(random_hash2)); assert_eq!( - executor::block_on(result).map_err(|e| e.to_string()), - Err(Error::InvalidBlockRange { - from: format!("{:?}", random_hash1), // First hash not found. - to: format!("{:?}", Some(random_hash2)), - details: format!( - "UnknownBlock: Header was not found in the database: {:?}", - random_hash1 - ), - }) + result.await.map_err(|e| e.to_string()), + Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( + 4001, + Error::InvalidBlockRange { + from: format!("{:?}", random_hash1), // First hash not found. + to: format!("{:?}", Some(random_hash2)), + details: format!( + "UnknownBlock: Header was not found in the database: {:?}", + random_hash1 + ), + } + .to_string(), + None::<()> + )))) .map_err(|e| e.to_string()), ); @@ -497,7 +476,7 @@ fn should_query_storage() { let result = api.query_storage_at(keys.clone(), Some(block1_hash)); assert_eq!( - executor::block_on(result).unwrap(), + result.await.unwrap(), vec![StorageChangeSet { block: block1_hash, changes: vec![ @@ -511,19 +490,14 @@ fn should_query_storage() { ); } - run_tests(Arc::new(substrate_test_runtime_client::new())); - run_tests(Arc::new(TestClientBuilder::new().build())); + run_tests(Arc::new(substrate_test_runtime_client::new())).await; + run_tests(Arc::new(TestClientBuilder::new().build())).await; } -#[test] -fn should_return_runtime_version() { +#[tokio::test] +async fn should_return_runtime_version() { let client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full( - client.clone(), - SubscriptionManager::new(Arc::new(TaskExecutor)), - DenyUnsafe::No, - None, - ); + let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No, None); let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\ @@ -532,7 +506,7 @@ fn should_return_runtime_version() { [\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\ \"transactionVersion\":1,\"stateVersion\":1}"; - let runtime_version = executor::block_on(api.runtime_version(None.into())).unwrap(); + let runtime_version = api.runtime_version(None.into()).await.unwrap(); let serialized = serde_json::to_string(&runtime_version).unwrap(); assert_eq!(serialized, result); @@ -540,28 +514,26 @@ fn should_return_runtime_version() { assert_eq!(deserialized, runtime_version); } -#[test] -fn should_notify_on_runtime_version_initially() { - let (subscriber, id, mut transport) = Subscriber::new_test("test"); - - { +#[tokio::test] +async fn should_notify_on_runtime_version_initially() { + let mut sub = { let client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full( - client.clone(), - SubscriptionManager::new(Arc::new(TaskExecutor)), - DenyUnsafe::No, - None, - ); + let (api, _child) = new_full(client, test_executor(), DenyUnsafe::No, None); - api.subscribe_runtime_version(Default::default(), subscriber); + let api_rpc = api.into_rpc(); + let sub = api_rpc + .subscribe("state_subscribeRuntimeVersion", EmptyParams::new()) + .await + .unwrap(); - // assert id assigned - assert!(matches!(executor::block_on(id), Ok(Ok(SubscriptionId::String(_))))); - } + sub + }; // assert initial version sent. - executor::block_on((&mut transport).take(1).collect::>()); - assert!(executor::block_on(transport.next()).is_none()); + assert_matches!(timeout_secs(10, sub.next::()).await, Ok(Some(_))); + + sub.close(); + assert_matches!(timeout_secs(10, sub.next::()).await, Ok(None)); } #[test] @@ -572,38 +544,24 @@ fn should_deserialize_storage_key() { assert_eq!(k.0.len(), 32); } -#[test] -fn wildcard_storage_subscriptions_are_rpc_unsafe() { - let (subscriber, id, _) = Subscriber::new_test("test"); - +#[tokio::test] +async fn wildcard_storage_subscriptions_are_rpc_unsafe() { let client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full( - client.clone(), - SubscriptionManager::new(Arc::new(TaskExecutor)), - DenyUnsafe::Yes, - None, - ); + let (api, _child) = new_full(client, test_executor(), DenyUnsafe::Yes, None); - api.subscribe_storage(Default::default(), subscriber, None.into()); - - let error = executor::block_on(id).unwrap().unwrap_err(); - assert_eq!(error.to_string(), "Method not found: RPC call is unsafe to be called externally"); + let api_rpc = api.into_rpc(); + let err = api_rpc.subscribe("state_subscribeStorage", EmptyParams::new()).await; + assert_matches!(err, Err(RpcError::Call(RpcCallError::Custom(e))) if e.message() == "RPC call is unsafe to be called externally"); } -#[test] -fn concrete_storage_subscriptions_are_rpc_safe() { - let (subscriber, id, _) = Subscriber::new_test("test"); - +#[tokio::test] +async fn concrete_storage_subscriptions_are_rpc_safe() { let client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full( - client.clone(), - SubscriptionManager::new(Arc::new(TaskExecutor)), - DenyUnsafe::Yes, - None, - ); + let (api, _child) = new_full(client, test_executor(), DenyUnsafe::Yes, None); + let api_rpc = api.into_rpc(); let key = StorageKey(STORAGE_KEY.to_vec()); - api.subscribe_storage(Default::default(), subscriber, Some(vec![key])); + let sub = api_rpc.subscribe("state_subscribeStorage", [[key]]).await; - assert!(matches!(executor::block_on(id), Ok(Ok(SubscriptionId::String(_))))); + assert!(sub.is_ok()); } diff --git a/client/rpc/src/system/mod.rs b/client/rpc/src/system/mod.rs index 534e446e140ad..ea24524cd2ea9 100644 --- a/client/rpc/src/system/mod.rs +++ b/client/rpc/src/system/mod.rs @@ -18,30 +18,23 @@ //! Substrate system API. -use self::error::Result; -use futures::{channel::oneshot, FutureExt}; -use sc_rpc_api::{DenyUnsafe, Receiver}; +#[cfg(test)] +mod tests; + +use futures::channel::oneshot; +use jsonrpsee::{ + core::{async_trait, error::Error as JsonRpseeError, JsonValue, RpcResult}, + types::error::{CallError, ErrorCode, ErrorObject}, +}; +use sc_rpc_api::DenyUnsafe; use sc_tracing::logging; use sc_utils::mpsc::TracingUnboundedSender; use sp_runtime::traits::{self, Header as HeaderT}; -pub use self::{ - gen_client::Client as SystemClient, - helpers::{Health, NodeRole, PeerInfo, SyncState, SystemInfo}, -}; -pub use sc_rpc_api::system::*; - -#[cfg(test)] -mod tests; +use self::error::Result; -/// Early exit for RPCs that require `--rpc-methods=Unsafe` to be enabled -macro_rules! bail_if_unsafe { - ($value: expr) => { - if let Err(err) = $value.check_if_safe() { - return async move { Err(err.into()) }.boxed() - } - }; -} +pub use self::helpers::{Health, NodeRole, PeerInfo, SyncState, SystemInfo}; +pub use sc_rpc_api::system::*; /// System API implementation pub struct System { @@ -62,7 +55,7 @@ pub enum Request { /// Must return information about the peers we are connected to. Peers(oneshot::Sender::Number>>>), /// Must return the state of the network. - NetworkState(oneshot::Sender), + NetworkState(oneshot::Sender), /// Must return any potential parse error. NetworkAddReservedPeer(String, oneshot::Sender>), /// Must return any potential parse error. @@ -89,121 +82,123 @@ impl System { } } -impl SystemApi::Number> for System { - fn system_name(&self) -> Result { +#[async_trait] +impl SystemApiServer::Number> for System { + fn system_name(&self) -> RpcResult { Ok(self.info.impl_name.clone()) } - fn system_version(&self) -> Result { + fn system_version(&self) -> RpcResult { Ok(self.info.impl_version.clone()) } - fn system_chain(&self) -> Result { + fn system_chain(&self) -> RpcResult { Ok(self.info.chain_name.clone()) } - fn system_type(&self) -> Result { + fn system_type(&self) -> RpcResult { Ok(self.info.chain_type.clone()) } - fn system_properties(&self) -> Result { + fn system_properties(&self) -> RpcResult { Ok(self.info.properties.clone()) } - fn system_health(&self) -> Receiver { + async fn system_health(&self) -> RpcResult { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::Health(tx)); - Receiver(rx) + rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) } - fn system_local_peer_id(&self) -> Receiver { + async fn system_local_peer_id(&self) -> RpcResult { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::LocalPeerId(tx)); - Receiver(rx) + rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) } - fn system_local_listen_addresses(&self) -> Receiver> { + async fn system_local_listen_addresses(&self) -> RpcResult> { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::LocalListenAddresses(tx)); - Receiver(rx) + rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) } - fn system_peers( + async fn system_peers( &self, - ) -> rpc::BoxFuture::Number>>>> { - bail_if_unsafe!(self.deny_unsafe); - + ) -> RpcResult::Number>>> { + self.deny_unsafe.check_if_safe()?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::Peers(tx)); - - async move { rx.await.map_err(|_| rpc::Error::internal_error()) }.boxed() + rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) } - fn system_network_state(&self) -> rpc::BoxFuture> { - bail_if_unsafe!(self.deny_unsafe); - + async fn system_network_state(&self) -> RpcResult { + self.deny_unsafe.check_if_safe()?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkState(tx)); - - async move { rx.await.map_err(|_| rpc::Error::internal_error()) }.boxed() + rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) } - fn system_add_reserved_peer(&self, peer: String) -> rpc::BoxFuture> { - bail_if_unsafe!(self.deny_unsafe); - + async fn system_add_reserved_peer(&self, peer: String) -> RpcResult<()> { + self.deny_unsafe.check_if_safe()?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkAddReservedPeer(peer, tx)); - async move { - match rx.await { - Ok(Ok(())) => Ok(()), - Ok(Err(e)) => Err(rpc::Error::from(e)), - Err(_) => Err(rpc::Error::internal_error()), - } + match rx.await { + Ok(Ok(())) => Ok(()), + Ok(Err(e)) => Err(JsonRpseeError::from(e)), + Err(e) => Err(JsonRpseeError::to_call_error(e)), } - .boxed() } - fn system_remove_reserved_peer(&self, peer: String) -> rpc::BoxFuture> { - bail_if_unsafe!(self.deny_unsafe); - + async fn system_remove_reserved_peer(&self, peer: String) -> RpcResult<()> { + self.deny_unsafe.check_if_safe()?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkRemoveReservedPeer(peer, tx)); - async move { - match rx.await { - Ok(Ok(())) => Ok(()), - Ok(Err(e)) => Err(rpc::Error::from(e)), - Err(_) => Err(rpc::Error::internal_error()), - } + match rx.await { + Ok(Ok(())) => Ok(()), + Ok(Err(e)) => Err(JsonRpseeError::from(e)), + Err(e) => Err(JsonRpseeError::to_call_error(e)), } - .boxed() } - fn system_reserved_peers(&self) -> Receiver> { + async fn system_reserved_peers(&self) -> RpcResult> { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkReservedPeers(tx)); - Receiver(rx) + rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) } - fn system_node_roles(&self) -> Receiver> { + async fn system_node_roles(&self) -> RpcResult> { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NodeRoles(tx)); - Receiver(rx) + rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) } - fn system_sync_state(&self) -> Receiver::Number>> { + async fn system_sync_state(&self) -> RpcResult::Number>> { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::SyncState(tx)); - Receiver(rx) + rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) } - fn system_add_log_filter(&self, directives: String) -> rpc::Result<()> { + fn system_add_log_filter(&self, directives: String) -> RpcResult<()> { self.deny_unsafe.check_if_safe()?; + logging::add_directives(&directives); - logging::reload_filter().map_err(|_e| rpc::Error::internal_error()) + logging::reload_filter().map_err(|e| { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + ErrorCode::InternalError.code(), + e, + None::<()>, + ))) + }) } - fn system_reset_log_filter(&self) -> rpc::Result<()> { + fn system_reset_log_filter(&self) -> RpcResult<()> { self.deny_unsafe.check_if_safe()?; - logging::reset_log_filter().map_err(|_e| rpc::Error::internal_error()) + logging::reset_log_filter().map_err(|e| { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + ErrorCode::InternalError.code(), + e, + None::<()>, + ))) + }) } } diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index 5d6945b714200..77acdf8418ccc 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -16,12 +16,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::*; - +use super::{helpers::SyncState, *}; use assert_matches::assert_matches; -use futures::{executor, prelude::*}; +use futures::prelude::*; +use jsonrpsee::{ + core::Error as RpcError, + types::{error::CallError, EmptyParams}, + RpcModule, +}; use sc_network::{self, config::Role, PeerId}; +use sc_rpc_api::system::helpers::PeerInfo; use sc_utils::mpsc::tracing_unbounded; +use sp_core::H256; use std::{ env, io::{BufRead, BufReader, Write}, @@ -43,7 +49,7 @@ impl Default for Status { } } -fn api>>(sync: T) -> System { +fn api>>(sync: T) -> RpcModule> { let status = sync.into().unwrap_or_default(); let should_have_peers = !status.is_dev; let (tx, rx) = tracing_unbounded("rpc_system_tests"); @@ -136,98 +142,122 @@ fn api>>(sync: T) -> System { tx, sc_rpc_api::DenyUnsafe::No, ) + .into_rpc() } -fn wait_receiver(rx: Receiver) -> T { - futures::executor::block_on(rx).unwrap() +#[tokio::test] +async fn system_name_works() { + assert_eq!( + api(None).call::<_, String>("system_name", EmptyParams::new()).await.unwrap(), + "testclient".to_string(), + ); } -#[test] -fn system_name_works() { - assert_eq!(api(None).system_name().unwrap(), "testclient".to_owned()); +#[tokio::test] +async fn system_version_works() { + assert_eq!( + api(None).call::<_, String>("system_version", EmptyParams::new()).await.unwrap(), + "0.2.0".to_string(), + ); } -#[test] -fn system_version_works() { - assert_eq!(api(None).system_version().unwrap(), "0.2.0".to_owned()); +#[tokio::test] +async fn system_chain_works() { + assert_eq!( + api(None).call::<_, String>("system_chain", EmptyParams::new()).await.unwrap(), + "testchain".to_string(), + ); } -#[test] -fn system_chain_works() { - assert_eq!(api(None).system_chain().unwrap(), "testchain".to_owned()); -} +#[tokio::test] +async fn system_properties_works() { + type Map = serde_json::map::Map; -#[test] -fn system_properties_works() { - assert_eq!(api(None).system_properties().unwrap(), serde_json::map::Map::new()); + assert_eq!( + api(None).call::<_, Map>("system_properties", EmptyParams::new()).await.unwrap(), + Map::new() + ); } -#[test] -fn system_type_works() { - assert_eq!(api(None).system_type().unwrap(), Default::default()); +#[tokio::test] +async fn system_type_works() { + assert_eq!( + api(None) + .call::<_, String>("system_chainType", EmptyParams::new()) + .await + .unwrap(), + "Live".to_owned(), + ); } -#[test] -fn system_health() { - assert_matches!( - wait_receiver(api(None).system_health()), - Health { peers: 0, is_syncing: false, should_have_peers: true } +#[tokio::test] +async fn system_health() { + assert_eq!( + api(None).call::<_, Health>("system_health", EmptyParams::new()).await.unwrap(), + Health { peers: 0, is_syncing: false, should_have_peers: true }, ); - assert_matches!( - wait_receiver( - api(Status { peer_id: PeerId::random(), peers: 5, is_syncing: true, is_dev: true }) - .system_health() - ), - Health { peers: 5, is_syncing: true, should_have_peers: false } + assert_eq!( + api(Status { peer_id: PeerId::random(), peers: 5, is_syncing: true, is_dev: true }) + .call::<_, Health>("system_health", EmptyParams::new()) + .await + .unwrap(), + Health { peers: 5, is_syncing: true, should_have_peers: false }, ); assert_eq!( - wait_receiver( - api(Status { peer_id: PeerId::random(), peers: 5, is_syncing: false, is_dev: false }) - .system_health() - ), - Health { peers: 5, is_syncing: false, should_have_peers: true } + api(Status { peer_id: PeerId::random(), peers: 5, is_syncing: false, is_dev: false }) + .call::<_, Health>("system_health", EmptyParams::new()) + .await + .unwrap(), + Health { peers: 5, is_syncing: false, should_have_peers: true }, ); assert_eq!( - wait_receiver( - api(Status { peer_id: PeerId::random(), peers: 0, is_syncing: false, is_dev: true }) - .system_health() - ), - Health { peers: 0, is_syncing: false, should_have_peers: false } + api(Status { peer_id: PeerId::random(), peers: 0, is_syncing: false, is_dev: true }) + .call::<_, Health>("system_health", EmptyParams::new()) + .await + .unwrap(), + Health { peers: 0, is_syncing: false, should_have_peers: false }, ); } -#[test] -fn system_local_peer_id_works() { +#[tokio::test] +async fn system_local_peer_id_works() { assert_eq!( - wait_receiver(api(None).system_local_peer_id()), - "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".to_owned(), + api(None) + .call::<_, String>("system_localPeerId", EmptyParams::new()) + .await + .unwrap(), + "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".to_owned() ); } -#[test] -fn system_local_listen_addresses_works() { +#[tokio::test] +async fn system_local_listen_addresses_works() { assert_eq!( - wait_receiver(api(None).system_local_listen_addresses()), + api(None) + .call::<_, Vec>("system_localListenAddresses", EmptyParams::new()) + .await + .unwrap(), vec![ - "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV" - .to_string(), + "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV", "/ip4/127.0.0.1/tcp/30334/ws/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV" - .to_string(), ] ); } -#[test] -fn system_peers() { +#[tokio::test] +async fn system_peers() { let peer_id = PeerId::random(); - let req = api(Status { peer_id, peers: 1, is_syncing: false, is_dev: true }).system_peers(); - let res = executor::block_on(req).unwrap(); + let peer_info: Vec> = + api(Status { peer_id, peers: 1, is_syncing: false, is_dev: true }) + .call("system_peers", EmptyParams::new()) + .await + .unwrap(); assert_eq!( - res, + peer_info, vec![PeerInfo { peer_id: peer_id.to_base58(), roles: "FULL".into(), @@ -237,14 +267,16 @@ fn system_peers() { ); } -#[test] -fn system_network_state() { - let req = api(None).system_network_state(); - let res = executor::block_on(req).unwrap(); - +#[tokio::test] +async fn system_network_state() { + use sc_network::network_state::NetworkState; + let network_state: NetworkState = api(None) + .call("system_unstable_networkState", EmptyParams::new()) + .await + .unwrap(); assert_eq!( - serde_json::from_value::(res).unwrap(), - sc_network::network_state::NetworkState { + network_state, + NetworkState { peer_id: String::new(), listened_addresses: Default::default(), external_addresses: Default::default(), @@ -255,50 +287,59 @@ fn system_network_state() { ); } -#[test] -fn system_node_roles() { - assert_eq!(wait_receiver(api(None).system_node_roles()), vec![NodeRole::Authority]); +#[tokio::test] +async fn system_node_roles() { + let node_roles: Vec = + api(None).call("system_nodeRoles", EmptyParams::new()).await.unwrap(); + assert_eq!(node_roles, vec![NodeRole::Authority]); } - -#[test] -fn system_sync_state() { +#[tokio::test] +async fn system_sync_state() { + let sync_state: SyncState = + api(None).call("system_syncState", EmptyParams::new()).await.unwrap(); assert_eq!( - wait_receiver(api(None).system_sync_state()), + sync_state, SyncState { starting_block: 1, current_block: 2, highest_block: Some(3) } ); } -#[test] -fn system_network_add_reserved() { +#[tokio::test] +async fn system_network_add_reserved() { let good_peer_id = - "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"; - let bad_peer_id = "/ip4/198.51.100.19/tcp/30333"; + ["/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"]; + let _good: () = api(None) + .call("system_addReservedPeer", good_peer_id) + .await + .expect("good peer id works"); - let good_fut = api(None).system_add_reserved_peer(good_peer_id.into()); - let bad_fut = api(None).system_add_reserved_peer(bad_peer_id.into()); - assert_eq!(executor::block_on(good_fut), Ok(())); - assert!(executor::block_on(bad_fut).is_err()); + let bad_peer_id = ["/ip4/198.51.100.19/tcp/30333"]; + assert_matches!( + api(None).call::<_, ()>("system_addReservedPeer", bad_peer_id).await, + Err(RpcError::Call(CallError::Custom(err))) if err.message().contains("Peer id is missing from the address") + ); } -#[test] -fn system_network_remove_reserved() { - let good_peer_id = "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"; - let bad_peer_id = - "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"; +#[tokio::test] +async fn system_network_remove_reserved() { + let _good_peer: () = api(None) + .call("system_removeReservedPeer", ["QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"]) + .await + .expect("call with good peer id works"); - let good_fut = api(None).system_remove_reserved_peer(good_peer_id.into()); - let bad_fut = api(None).system_remove_reserved_peer(bad_peer_id.into()); - assert_eq!(executor::block_on(good_fut), Ok(())); - assert!(executor::block_on(bad_fut).is_err()); -} + let bad_peer_id = + ["/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"]; -#[test] -fn system_network_reserved_peers() { - assert_eq!( - wait_receiver(api(None).system_reserved_peers()), - vec!["QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".to_string()] + assert_matches!( + api(None).call::<_, String>("system_removeReservedPeer", bad_peer_id).await, + Err(RpcError::Call(CallError::Custom(err))) if err.message().contains("base-58 decode error: provided string contained invalid character '/' at byte 0") ); } +#[tokio::test] +async fn system_network_reserved_peers() { + let reserved_peers: Vec = + api(None).call("system_reservedPeers", EmptyParams::new()).await.unwrap(); + assert_eq!(reserved_peers, vec!["QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".to_string()],); +} #[test] fn test_add_reset_log_filter() { @@ -315,15 +356,20 @@ fn test_add_reset_log_filter() { for line in std::io::stdin().lock().lines() { let line = line.expect("Failed to read bytes"); if line.contains("add_reload") { - api(None) - .system_add_log_filter("test_after_add".into()) - .expect("`system_add_log_filter` failed"); + let filter = "test_after_add"; + let fut = + async move { api(None).call::<_, ()>("system_addLogFilter", [filter]).await }; + futures::executor::block_on(fut).expect("`system_addLogFilter` failed"); } else if line.contains("add_trace") { - api(None) - .system_add_log_filter("test_before_add=trace".into()) - .expect("`system_add_log_filter` failed"); + let filter = "test_before_add=trace"; + let fut = + async move { api(None).call::<_, ()>("system_addLogFilter", [filter]).await }; + futures::executor::block_on(fut).expect("`system_addLogFilter (trace)` failed"); } else if line.contains("reset") { - api(None).system_reset_log_filter().expect("`system_reset_log_filter` failed"); + let fut = async move { + api(None).call::<_, ()>("system_resetLogFilter", EmptyParams::new()).await + }; + futures::executor::block_on(fut).expect("`system_resetLogFilter` failed"); } else if line.contains("exit") { return } diff --git a/client/rpc/src/testing.rs b/client/rpc/src/testing.rs index bfb91adb81d31..584e4a9901eab 100644 --- a/client/rpc/src/testing.rs +++ b/client/rpc/src/testing.rs @@ -18,29 +18,16 @@ //! Testing utils used by the RPC tests. -use futures::{ - executor, - task::{FutureObj, Spawn, SpawnError}, -}; - -// Executor shared by all tests. -// -// This shared executor is used to prevent `Too many open files` errors -// on systems with a lot of cores. -lazy_static::lazy_static! { - static ref EXECUTOR: executor::ThreadPool = executor::ThreadPool::new() - .expect("Failed to create thread pool executor for tests"); +use std::{future::Future, sync::Arc}; + +use sp_core::testing::TaskExecutor; + +/// Executor for testing. +pub fn test_executor() -> Arc { + Arc::new(TaskExecutor::default()) } -/// Executor for use in testing -pub struct TaskExecutor; -impl Spawn for TaskExecutor { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - EXECUTOR.spawn_ok(future); - Ok(()) - } - - fn status(&self) -> Result<(), SpawnError> { - Ok(()) - } +/// Wrap a future in a timeout a little more concisely +pub fn timeout_secs>(s: u64, f: F) -> tokio::time::Timeout { + tokio::time::timeout(std::time::Duration::from_secs(s), f) } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 7138d9d384eeb..a62298a260aa4 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -22,10 +22,9 @@ wasmtime = ["sc-executor/wasmtime"] test-helpers = [] [dependencies] +jsonrpsee = { version = "0.12.0", features = ["server"] } thiserror = "1.0.30" futures = "0.3.21" -jsonrpc-pubsub = "18.0" -jsonrpc-core = "18.0" rand = "0.7.3" parking_lot = "0.12.0" log = "0.4.16" diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index cabf004b2f707..5319bf24d5e72 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -25,7 +25,7 @@ use crate::{ start_rpc_servers, RpcHandlers, SpawnTaskHandle, TaskManager, TransactionPoolAdapter, }; use futures::{channel::oneshot, future::ready, FutureExt, StreamExt}; -use jsonrpc_pubsub::manager::SubscriptionManager; +use jsonrpsee::RpcModule; use log::info; use prometheus_endpoint::Registry; use sc_chain_spec::get_extension; @@ -45,6 +45,14 @@ use sc_network::{ warp_request_handler::{self, RequestHandler as WarpSyncRequestHandler, WarpSyncProvider}, NetworkService, }; +use sc_rpc::{ + author::AuthorApiServer, + chain::ChainApiServer, + offchain::OffchainApiServer, + state::{ChildStateApiServer, StateApiServer}, + system::SystemApiServer, + DenyUnsafe, SubscriptionTaskExecutor, +}; use sc_telemetry::{telemetry, ConnectionMessage, Telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sc_transaction_pool_api::MaintainedTransactionPool; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; @@ -62,69 +70,6 @@ use sp_runtime::{ }; use std::{str::FromStr, sync::Arc, time::SystemTime}; -/// A utility trait for building an RPC extension given a `DenyUnsafe` instance. -/// This is useful since at service definition time we don't know whether the -/// specific interface where the RPC extension will be exposed is safe or not. -/// This trait allows us to lazily build the RPC extension whenever we bind the -/// service to an interface. -pub trait RpcExtensionBuilder { - /// The type of the RPC extension that will be built. - type Output: sc_rpc::RpcExtension; - - /// Returns an instance of the RPC extension for a particular `DenyUnsafe` - /// value, e.g. the RPC extension might not expose some unsafe methods. - fn build( - &self, - deny: sc_rpc::DenyUnsafe, - subscription_executor: sc_rpc::SubscriptionTaskExecutor, - ) -> Result; -} - -impl RpcExtensionBuilder for F -where - F: Fn(sc_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor) -> Result, - R: sc_rpc::RpcExtension, -{ - type Output = R; - - fn build( - &self, - deny: sc_rpc::DenyUnsafe, - subscription_executor: sc_rpc::SubscriptionTaskExecutor, - ) -> Result { - (*self)(deny, subscription_executor) - } -} - -/// A utility struct for implementing an `RpcExtensionBuilder` given a cloneable -/// `RpcExtension`, the resulting builder will simply ignore the provided -/// `DenyUnsafe` instance and return a static `RpcExtension` instance. -pub struct NoopRpcExtensionBuilder(pub R); - -impl RpcExtensionBuilder for NoopRpcExtensionBuilder -where - R: Clone + sc_rpc::RpcExtension, -{ - type Output = R; - - fn build( - &self, - _deny: sc_rpc::DenyUnsafe, - _subscription_executor: sc_rpc::SubscriptionTaskExecutor, - ) -> Result { - Ok(self.0.clone()) - } -} - -impl From for NoopRpcExtensionBuilder -where - R: sc_rpc::RpcExtension, -{ - fn from(e: R) -> NoopRpcExtensionBuilder { - NoopRpcExtensionBuilder(e) - } -} - /// Full client type. pub type TFullClient = Client, TFullCallExecutor, TBl, TRtApi>; @@ -389,9 +334,9 @@ pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> { pub keystore: SyncCryptoStorePtr, /// A shared transaction pool. pub transaction_pool: Arc, - /// A RPC extension builder. Use `NoopRpcExtensionBuilder` if you just want to pass in the - /// extensions directly. - pub rpc_extensions_builder: Box + Send>, + /// Builds additional [`RpcModule`]s that should be added to the server + pub rpc_builder: + Box Result, Error>>, /// A shared network instance. pub network: Arc::Hash>>, /// A Sender for RPC requests. @@ -463,7 +408,6 @@ where TExPool: MaintainedTransactionPool::Hash> + parity_util_mem::MallocSizeOf + 'static, - TRpc: sc_rpc::RpcExtension, { let SpawnTasksParams { mut config, @@ -472,7 +416,7 @@ where backend, keystore, transaction_pool, - rpc_extensions_builder, + rpc_builder, network, system_rpc_tx, telemetry, @@ -536,35 +480,25 @@ where metrics_service.run(client.clone(), transaction_pool.clone(), network.clone()), ); - // RPC - let gen_handler = |deny_unsafe: sc_rpc::DenyUnsafe, - rpc_middleware: sc_rpc_server::RpcMiddleware| { - gen_handler( + let rpc_id_provider = config.rpc_id_provider.take(); + + // jsonrpsee RPC + let gen_rpc_module = |deny_unsafe: DenyUnsafe| { + gen_rpc_module( deny_unsafe, - rpc_middleware, - &config, task_manager.spawn_handle(), client.clone(), transaction_pool.clone(), keystore.clone(), - &*rpc_extensions_builder, - backend.offchain_storage(), system_rpc_tx.clone(), + &config, + backend.offchain_storage(), + &*rpc_builder, ) }; - let rpc_metrics = sc_rpc_server::RpcMetrics::new(config.prometheus_registry())?; - let server_metrics = sc_rpc_server::ServerMetrics::new(config.prometheus_registry())?; - let rpc = start_rpc_servers(&config, gen_handler, rpc_metrics.clone(), server_metrics)?; - // This is used internally, so don't restrict access to unsafe RPC - let known_rpc_method_names = - sc_rpc_server::method_names(|m| gen_handler(sc_rpc::DenyUnsafe::No, m))?; - let rpc_handlers = RpcHandlers(Arc::new( - gen_handler( - sc_rpc::DenyUnsafe::No, - sc_rpc_server::RpcMiddleware::new(rpc_metrics, known_rpc_method_names, "inbrowser"), - )? - .into(), - )); + + let rpc = start_rpc_servers(&config, gen_rpc_module, rpc_id_provider)?; + let rpc_handlers = RpcHandlers(Arc::new(gen_rpc_module(sc_rpc::DenyUnsafe::No)?.into())); // Spawn informant task spawn_handle.spawn( @@ -578,7 +512,7 @@ where ), ); - task_manager.keep_alive((config.base_path, rpc, rpc_handlers.clone())); + task_manager.keep_alive((config.base_path, rpc)); Ok(rpc_handlers) } @@ -642,18 +576,17 @@ fn init_telemetry>( Ok(telemetry.handle()) } -fn gen_handler( - deny_unsafe: sc_rpc::DenyUnsafe, - rpc_middleware: sc_rpc_server::RpcMiddleware, - config: &Configuration, +fn gen_rpc_module( + deny_unsafe: DenyUnsafe, spawn_handle: SpawnTaskHandle, client: Arc, transaction_pool: Arc, keystore: SyncCryptoStorePtr, - rpc_extensions_builder: &(dyn RpcExtensionBuilder + Send), - offchain_storage: Option<>::OffchainStorage>, system_rpc_tx: TracingUnboundedSender>, -) -> Result, Error> + config: &Configuration, + offchain_storage: Option<>::OffchainStorage>, + rpc_builder: &(dyn Fn(DenyUnsafe, SubscriptionTaskExecutor) -> Result, Error>), +) -> Result, Error> where TBl: BlockT, TCl: ProvideRuntimeApi @@ -668,15 +601,12 @@ where + Send + Sync + 'static, - TExPool: MaintainedTransactionPool::Hash> + 'static, TBackend: sc_client_api::backend::Backend + 'static, - TRpc: sc_rpc::RpcExtension, >::Api: sp_session::SessionKeys + sp_api::Metadata, + TExPool: MaintainedTransactionPool::Hash> + 'static, TBl::Hash: Unpin, TBl::Header: Unpin, { - use sc_rpc::{author, chain, offchain, state, system}; - let system_info = sc_rpc::system::SystemInfo { chain_name: config.chain_spec.name().into(), impl_name: config.impl_name.clone(), @@ -685,42 +615,50 @@ where chain_type: config.chain_spec.chain_type(), }; - let task_executor = sc_rpc::SubscriptionTaskExecutor::new(spawn_handle); - let subscriptions = SubscriptionManager::new(Arc::new(task_executor.clone())); + let mut rpc_api = RpcModule::new(()); + let task_executor = Arc::new(spawn_handle); let (chain, state, child_state) = { - // Full nodes - let chain = sc_rpc::chain::new_full(client.clone(), subscriptions.clone()); + let chain = sc_rpc::chain::new_full(client.clone(), task_executor.clone()).into_rpc(); let (state, child_state) = sc_rpc::state::new_full( client.clone(), - subscriptions.clone(), + task_executor.clone(), deny_unsafe, config.rpc_max_payload, ); + let state = state.into_rpc(); + let child_state = child_state.into_rpc(); + (chain, state, child_state) }; - let author = - sc_rpc::author::Author::new(client, transaction_pool, subscriptions, keystore, deny_unsafe); - let system = system::System::new(system_info, system_rpc_tx, deny_unsafe); + let author = sc_rpc::author::Author::new( + client.clone(), + transaction_pool, + keystore, + deny_unsafe, + task_executor.clone(), + ) + .into_rpc(); - let maybe_offchain_rpc = offchain_storage.map(|storage| { - let offchain = sc_rpc::offchain::Offchain::new(storage, deny_unsafe); - offchain::OffchainApi::to_delegate(offchain) - }); + let system = sc_rpc::system::System::new(system_info, system_rpc_tx, deny_unsafe).into_rpc(); - Ok(sc_rpc_server::rpc_handler( - ( - state::StateApi::to_delegate(state), - state::ChildStateApi::to_delegate(child_state), - chain::ChainApi::to_delegate(chain), - maybe_offchain_rpc, - author::AuthorApi::to_delegate(author), - system::SystemApi::to_delegate(system), - rpc_extensions_builder.build(deny_unsafe, task_executor)?, - ), - rpc_middleware, - )) + if let Some(storage) = offchain_storage { + let offchain = sc_rpc::offchain::Offchain::new(storage, deny_unsafe).into_rpc(); + + rpc_api.merge(offchain).map_err(|e| Error::Application(e.into()))?; + } + + rpc_api.merge(chain).map_err(|e| Error::Application(e.into()))?; + rpc_api.merge(author).map_err(|e| Error::Application(e.into()))?; + rpc_api.merge(system).map_err(|e| Error::Application(e.into()))?; + rpc_api.merge(state).map_err(|e| Error::Application(e.into()))?; + rpc_api.merge(child_state).map_err(|e| Error::Application(e.into()))?; + // Additional [`RpcModule`]s defined in the node to fit the specific blockchain + let extra_rpcs = rpc_builder(deny_unsafe, task_executor.clone())?; + rpc_api.merge(extra_rpcs).map_err(|e| Error::Application(e.into()))?; + + Ok(rpc_api) } /// Parameters to pass into `build_network`. diff --git a/client/service/src/config.rs b/client/service/src/config.rs index e49e8b40a7b1a..35380da11fc71 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -100,6 +100,18 @@ pub struct Configuration { pub rpc_methods: RpcMethods, /// Maximum payload of rpc request/responses. pub rpc_max_payload: Option, + /// Maximum payload of a rpc request + pub rpc_max_request_size: Option, + /// Maximum payload of a rpc request + pub rpc_max_response_size: Option, + /// Custom JSON-RPC subscription ID provider. + /// + /// Default: [`crate::RandomStringSubscriptionId`]. + pub rpc_id_provider: Option>, + /// Maximum allowed subscriptions per rpc connection + /// + /// Default: 1024. + pub rpc_max_subs_per_conn: Option, /// Maximum size of the output buffer capacity for websocket connections. pub ws_max_out_buffer_capacity: Option, /// Prometheus endpoint configuration. `None` if disabled. diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 0d2461376d961..027b704789635 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -34,13 +34,15 @@ mod client; mod metrics; mod task_manager; -use std::{collections::HashMap, io, net::SocketAddr, pin::Pin}; +use std::{collections::HashMap, net::SocketAddr}; use codec::{Decode, Encode}; -use futures::{Future, FutureExt, StreamExt}; +use futures::{channel::mpsc, FutureExt, StreamExt}; +use jsonrpsee::{core::Error as JsonRpseeError, RpcModule}; use log::{debug, error, warn}; -use sc_client_api::{BlockBackend, ProofProvider}; +use sc_client_api::{blockchain::HeaderBackend, BlockBackend, BlockchainEvents, ProofProvider}; use sc_network::PeerId; +use sc_rpc_server::WsConfig; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; use sp_runtime::{ @@ -52,8 +54,7 @@ pub use self::{ builder::{ build_network, build_offchain_workers, new_client, new_db_backend, new_full_client, new_full_parts, spawn_tasks, BuildNetworkParams, KeystoreContainer, NetworkStarter, - NoopRpcExtensionBuilder, RpcExtensionBuilder, SpawnTasksParams, TFullBackend, - TFullCallExecutor, TFullClient, + SpawnTasksParams, TFullBackend, TFullCallExecutor, TFullClient, }, client::{ClientConfig, LocalCallExecutor}, error::Error, @@ -65,12 +66,14 @@ pub use sc_chain_spec::{ ChainSpec, ChainType, Extension as ChainSpecExtension, GenericChainSpec, NoExtension, Properties, RuntimeGenesis, }; -use sc_client_api::{blockchain::HeaderBackend, BlockchainEvents}; + pub use sc_consensus::ImportQueue; pub use sc_executor::NativeExecutionDispatch; #[doc(hidden)] pub use sc_network::config::{TransactionImport, TransactionImportFuture}; -pub use sc_rpc::Metadata as RpcMetadata; +pub use sc_rpc::{ + RandomIntegerSubscriptionId, RandomStringSubscriptionId, RpcSubscriptionIdProvider, +}; pub use sc_tracing::TracingReceiver; pub use sc_transaction_pool::Options as TransactionPoolOptions; pub use sc_transaction_pool_api::{error::IntoPoolError, InPoolTransaction, TransactionPool}; @@ -82,32 +85,27 @@ const DEFAULT_PROTOCOL_ID: &str = "sup"; /// RPC handlers that can perform RPC queries. #[derive(Clone)] -pub struct RpcHandlers( - Arc>, -); +pub struct RpcHandlers(Arc>); impl RpcHandlers { /// Starts an RPC query. /// - /// The query is passed as a string and must be a JSON text similar to what an HTTP client - /// would for example send. + /// The query is passed as a string and must be valid JSON-RPC request object. /// - /// Returns a `Future` that contains the optional response. + /// Returns a response and a stream if the call successful, fails if the + /// query could not be decoded as a JSON-RPC request object. /// - /// If the request subscribes you to events, the `Sender` in the `RpcSession` object is used to - /// send back spontaneous events. - pub fn rpc_query( + /// If the request subscribes you to events, the `stream` can be used to + /// retrieve the events. + pub async fn rpc_query( &self, - mem: &RpcSession, - request: &str, - ) -> Pin> + Send>> { - self.0.handle_request(request, mem.metadata.clone()).boxed() + json_query: &str, + ) -> Result<(String, mpsc::UnboundedReceiver), JsonRpseeError> { + self.0.raw_json_request(json_query).await } - /// Provides access to the underlying `MetaIoHandler` - pub fn io_handler( - &self, - ) -> Arc> { + /// Provides access to the underlying `RpcModule` + pub fn handle(&self) -> Arc> { self.0.clone() } } @@ -284,74 +282,41 @@ async fn build_network_future< // Wrapper for HTTP and WS servers that makes sure they are properly shut down. mod waiting { pub struct HttpServer(pub Option); - impl Drop for HttpServer { - fn drop(&mut self) { - if let Some(server) = self.0.take() { - server.close_handle().close(); - server.wait(); - } - } - } - pub struct IpcServer(pub Option); - impl Drop for IpcServer { + impl Drop for HttpServer { fn drop(&mut self) { if let Some(server) = self.0.take() { - server.close_handle().close(); - let _ = server.wait(); + // This doesn't not wait for the server to be stopped but fires the signal. + let _ = server.stop(); } } } pub struct WsServer(pub Option); + impl Drop for WsServer { fn drop(&mut self) { if let Some(server) = self.0.take() { - server.close_handle().close(); - let _ = server.wait(); + // This doesn't not wait for the server to be stopped but fires the signal. + let _ = server.stop(); } } } } -/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them -/// alive. -fn start_rpc_servers< - H: FnMut( - sc_rpc::DenyUnsafe, - sc_rpc_server::RpcMiddleware, - ) -> Result, Error>, ->( +/// Starts RPC servers. +fn start_rpc_servers( config: &Configuration, - mut gen_handler: H, - rpc_metrics: Option, - server_metrics: sc_rpc_server::ServerMetrics, -) -> Result, Error> { - fn maybe_start_server( - address: Option, - mut start: F, - ) -> Result, Error> - where - F: FnMut(&SocketAddr) -> Result, - { - address - .map(|mut address| { - start(&address).or_else(|e| match e { - Error::Io(e) => match e.kind() { - io::ErrorKind::AddrInUse | io::ErrorKind::PermissionDenied => { - warn!("Unable to bind RPC server to {}. Trying random port.", address); - address.set_port(0); - start(&address) - }, - _ => Err(e.into()), - }, - e => Err(e), - }) - }) - .transpose() - } + gen_rpc_module: R, + rpc_id_provider: Option>, +) -> Result, error::Error> +where + R: Fn(sc_rpc::DenyUnsafe) -> Result, Error>, +{ + let (max_request_size, ws_max_response_size, http_max_response_size) = + legacy_cli_parsing(config); - fn deny_unsafe(addr: &SocketAddr, methods: &RpcMethods) -> sc_rpc::DenyUnsafe { + fn deny_unsafe(addr: SocketAddr, methods: &RpcMethods) -> sc_rpc::DenyUnsafe { let is_exposed_addr = !addr.ip().is_loopback(); match (is_exposed_addr, methods) { | (_, RpcMethods::Unsafe) | (false, RpcMethods::Auto) => sc_rpc::DenyUnsafe::No, @@ -359,85 +324,54 @@ fn start_rpc_servers< } } - let rpc_method_names = sc_rpc_server::method_names(|m| gen_handler(sc_rpc::DenyUnsafe::No, m))?; - Ok(Box::new(( - config - .rpc_ipc - .as_ref() - .map(|path| { - sc_rpc_server::start_ipc( - &*path, - gen_handler( - sc_rpc::DenyUnsafe::No, - sc_rpc_server::RpcMiddleware::new( - rpc_metrics.clone(), - rpc_method_names.clone(), - "ipc", - ), - )?, - server_metrics.clone(), - ) - .map_err(Error::from) - }) - .transpose()?, - maybe_start_server(config.rpc_http, |address| { - sc_rpc_server::start_http( - address, - config.rpc_cors.as_ref(), - gen_handler( - deny_unsafe(address, &config.rpc_methods), - sc_rpc_server::RpcMiddleware::new( - rpc_metrics.clone(), - rpc_method_names.clone(), - "http", - ), - )?, - config.rpc_max_payload, - config.tokio_handle.clone(), - ) - .map_err(Error::from) - })? - .map(|s| waiting::HttpServer(Some(s))), - maybe_start_server(config.rpc_ws, |address| { - sc_rpc_server::start_ws( - address, - config.rpc_ws_max_connections, - config.rpc_cors.as_ref(), - gen_handler( - deny_unsafe(address, &config.rpc_methods), - sc_rpc_server::RpcMiddleware::new( - rpc_metrics.clone(), - rpc_method_names.clone(), - "ws", - ), - )?, - config.rpc_max_payload, - config.ws_max_out_buffer_capacity, - server_metrics.clone(), - config.tokio_handle.clone(), - ) - .map_err(Error::from) - })? - .map(|s| waiting::WsServer(Some(s))), - ))) -} + let random_port = |mut addr: SocketAddr| { + addr.set_port(0); + addr + }; -/// An RPC session. Used to perform in-memory RPC queries (ie. RPC queries that don't go through -/// the HTTP or WebSockets server). -#[derive(Clone)] -pub struct RpcSession { - metadata: sc_rpc::Metadata, -} + let ws_addr = config + .rpc_ws + .unwrap_or_else(|| "127.0.0.1:9944".parse().expect("valid sockaddr; qed")); + let ws_addr2 = random_port(ws_addr); + let http_addr = config + .rpc_http + .unwrap_or_else(|| "127.0.0.1:9933".parse().expect("valid sockaddr; qed")); + let http_addr2 = random_port(http_addr); + + let metrics = sc_rpc_server::RpcMetrics::new(config.prometheus_registry())?; + + let http_fut = sc_rpc_server::start_http( + [http_addr, http_addr2], + config.rpc_cors.as_ref(), + max_request_size, + http_max_response_size, + metrics.clone(), + gen_rpc_module(deny_unsafe(ws_addr, &config.rpc_methods))?, + config.tokio_handle.clone(), + ); + + let ws_config = WsConfig { + max_connections: config.rpc_ws_max_connections, + max_payload_in_mb: max_request_size, + max_payload_out_mb: ws_max_response_size, + max_subs_per_conn: config.rpc_max_subs_per_conn, + }; -impl RpcSession { - /// Creates an RPC session. - /// - /// The `sender` is stored inside the `RpcSession` and is used to communicate spontaneous JSON - /// messages. - /// - /// The `RpcSession` must be kept alive in order to receive messages on the sender. - pub fn new(sender: futures::channel::mpsc::UnboundedSender) -> RpcSession { - RpcSession { metadata: sender.into() } + let ws_fut = sc_rpc_server::start_ws( + [ws_addr, ws_addr2], + config.rpc_cors.as_ref(), + ws_config, + metrics, + gen_rpc_module(deny_unsafe(http_addr, &config.rpc_methods))?, + config.tokio_handle.clone(), + rpc_id_provider, + ); + + match tokio::task::block_in_place(|| { + config.tokio_handle.block_on(futures::future::try_join(http_fut, ws_fut)) + }) { + Ok((http, ws)) => Ok(Box::new((http, ws))), + Err(e) => Err(Error::Application(e)), } } @@ -545,6 +479,44 @@ where } } +fn legacy_cli_parsing(config: &Configuration) -> (Option, Option, Option) { + let ws_max_response_size = config.ws_max_out_buffer_capacity.map(|max| { + eprintln!("DEPRECATED: `--ws_max_out_buffer_capacity` has been removed use `rpc-max-response-size or rpc-max-request-size` instead"); + eprintln!("Setting WS `rpc-max-response-size` to `max(ws_max_out_buffer_capacity, rpc_max_response_size)`"); + std::cmp::max(max, config.rpc_max_response_size.unwrap_or(0)) + }); + + let max_request_size = match (config.rpc_max_payload, config.rpc_max_request_size) { + (Some(legacy_max), max) => { + eprintln!("DEPRECATED: `--rpc_max_payload` has been removed use `rpc-max-response-size or rpc-max-request-size` instead"); + eprintln!( + "Setting `rpc-max-response-size` to `max(rpc_max_payload, rpc_max_request_size)`" + ); + Some(std::cmp::max(legacy_max, max.unwrap_or(0))) + }, + (None, Some(max)) => Some(max), + (None, None) => None, + }; + + let http_max_response_size = match (config.rpc_max_payload, config.rpc_max_request_size) { + (Some(legacy_max), max) => { + eprintln!("DEPRECATED: `--rpc_max_payload` has been removed use `rpc-max-response-size or rpc-max-request-size` instead"); + eprintln!( + "Setting HTTP `rpc-max-response-size` to `max(rpc_max_payload, rpc_max_response_size)`" + ); + Some(std::cmp::max(legacy_max, max.unwrap_or(0))) + }, + (None, Some(max)) => Some(max), + (None, None) => None, + }; + + if config.rpc_ipc.is_some() { + eprintln!("DEPRECATED: `--ipc-path` has no effect anymore IPC support has been removed"); + } + + (max_request_size, ws_max_response_size, http_max_response_size) +} + #[cfg(test)] mod tests { use super::*; diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index ef04e16a65d26..749c83c6eeac7 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -246,6 +246,10 @@ fn node_config< rpc_cors: None, rpc_methods: Default::default(), rpc_max_payload: None, + rpc_max_request_size: None, + rpc_max_response_size: None, + rpc_id_provider: None, + rpc_max_subs_per_conn: None, ws_max_out_buffer_capacity: None, prometheus_config: None, telemetry_endpoints: None, diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index a32849dc0e964..f42c307ffa84c 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -14,9 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" thiserror = "1.0.30" diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index d7696c662e856..a0a5b66cb86fc 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -37,10 +37,15 @@ //! ``` //! //! If the [`LightSyncStateExtension`] is not added as an extension to the chain spec, -//! the [`SyncStateRpcHandler`] will fail at instantiation. +//! the [`SyncStateRpc`] will fail at instantiation. #![deny(unused_crate_dependencies)] +use jsonrpsee::{ + core::{Error as JsonRpseeError, RpcResult}, + proc_macros::rpc, + types::{error::CallError, ErrorObject}, +}; use sc_client_api::StorageData; use sp_blockchain::HeaderBackend; use sp_runtime::{ @@ -49,8 +54,6 @@ use sp_runtime::{ }; use std::sync::Arc; -use jsonrpc_derive::rpc; - type SharedAuthoritySet = sc_finality_grandpa::SharedAuthoritySet<::Hash, NumberFor>; type SharedEpochChanges = @@ -76,13 +79,13 @@ pub enum Error { LightSyncStateExtensionNotFound, } -impl From> for jsonrpc_core::Error { +impl From> for JsonRpseeError { fn from(error: Error) -> Self { let message = match error { Error::JsonRpc(s) => s, _ => error.to_string(), }; - jsonrpc_core::Error { message, code: jsonrpc_core::ErrorCode::ServerError(1), data: None } + CallError::Custom(ErrorObject::owned(1, message, None::<()>)).into() } } @@ -101,7 +104,7 @@ fn serialize_encoded( /// chain-spec as an extension. pub type LightSyncStateExtension = Option; -/// Hardcoded infomation that allows light clients to sync quickly. +/// Hardcoded information that allows light clients to sync quickly. #[derive(serde::Serialize, Clone)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] @@ -121,30 +124,30 @@ pub struct LightSyncState { } /// An api for sync state RPC calls. -#[rpc] +#[rpc(client, server)] pub trait SyncStateRpcApi { - /// Returns the json-serialized chainspec running the node, with a sync state. - #[rpc(name = "sync_state_genSyncSpec", returns = "jsonrpc_core::Value")] - fn system_gen_sync_spec(&self, raw: bool) -> jsonrpc_core::Result; + /// Returns the JSON serialized chainspec running the node, with a sync state. + #[method(name = "sync_state_genSyncSpec")] + fn system_gen_sync_spec(&self, raw: bool) -> RpcResult; } -/// The handler for sync state RPC calls. -pub struct SyncStateRpcHandler { +/// An api for sync state RPC calls. +pub struct SyncStateRpc { chain_spec: Box, - client: Arc, + client: Arc, shared_authority_set: SharedAuthoritySet, shared_epoch_changes: SharedEpochChanges, } -impl SyncStateRpcHandler +impl SyncStateRpc where Block: BlockT, - Backend: HeaderBackend + sc_client_api::AuxStore + 'static, + Client: HeaderBackend + sc_client_api::AuxStore + 'static, { - /// Create a new handler. + /// Create a new sync state RPC helper. pub fn new( chain_spec: Box, - client: Arc, + client: Arc, shared_authority_set: SharedAuthoritySet, shared_epoch_changes: SharedEpochChanges, ) -> Result> { @@ -177,32 +180,23 @@ where } } -impl SyncStateRpcApi for SyncStateRpcHandler +impl SyncStateRpcApiServer for SyncStateRpc where Block: BlockT, Backend: HeaderBackend + sc_client_api::AuxStore + 'static, { - fn system_gen_sync_spec(&self, raw: bool) -> jsonrpc_core::Result { + fn system_gen_sync_spec(&self, raw: bool) -> RpcResult { + let current_sync_state = self.build_sync_state()?; let mut chain_spec = self.chain_spec.cloned_box(); - let sync_state = self.build_sync_state().map_err(map_error::>)?; - let extension = sc_chain_spec::get_extension_mut::( chain_spec.extensions_mut(), ) - .ok_or_else(|| { - Error::::JsonRpc("Could not find `LightSyncState` chain-spec extension!".into()) - })?; - - *extension = - Some(serde_json::to_value(&sync_state).map_err(|err| map_error::(err))?); + .ok_or(Error::::LightSyncStateExtensionNotFound)?; - let json_string = chain_spec.as_json(raw).map_err(map_error::)?; + let val = serde_json::to_value(¤t_sync_state)?; + *extension = Some(val); - serde_json::from_str(&json_string).map_err(|err| map_error::(err)) + chain_spec.as_json(raw).map_err(|e| Error::::JsonRpc(e).into()) } } - -fn map_error(error: S) -> jsonrpc_core::Error { - Error::::JsonRpc(error.to_string()).into() -} diff --git a/client/tracing/src/block/mod.rs b/client/tracing/src/block/mod.rs index 6de3a0220e15e..2a034f06ce8a8 100644 --- a/client/tracing/src/block/mod.rs +++ b/client/tracing/src/block/mod.rs @@ -53,7 +53,7 @@ const AVG_SPAN: usize = 100 * 8; // are used for the RPC Id this may need to be adjusted. Note: The base payload // does not include the RPC result. // -// The estimate is based on the JSONRPC response message which has the following format: +// The estimate is based on the JSON-RPC response message which has the following format: // `{"jsonrpc":"2.0","result":[],"id":18446744073709551615}`. // // We care about the total size of the payload because jsonrpc-server will simply ignore diff --git a/client/transaction-pool/api/src/error.rs b/client/transaction-pool/api/src/error.rs index b093657f739b1..aada44734d053 100644 --- a/client/transaction-pool/api/src/error.rs +++ b/client/transaction-pool/api/src/error.rs @@ -46,7 +46,7 @@ pub enum Error { TemporarilyBanned, #[error("[{0:?}] Already imported")] - AlreadyImported(Box), + AlreadyImported(Box), #[error("Too low priority ({} > {})", old, new)] TooLowPriority { @@ -72,7 +72,7 @@ pub enum Error { } /// Transaction pool error conversion. -pub trait IntoPoolError: std::error::Error + Send + Sized { +pub trait IntoPoolError: std::error::Error + Send + Sized + Sync { /// Try to extract original `Error` /// /// This implementation is optional and used only to diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index 448578b327b03..0ebb8f9d4cd9c 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -22,16 +22,17 @@ pub mod error; use futures::{Future, Stream}; -use serde::{Deserialize, Serialize}; -pub use sp_runtime::transaction_validity::{ - TransactionLongevity, TransactionPriority, TransactionSource, TransactionTag, -}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Member, NumberFor}, }; use std::{collections::HashMap, hash::Hash, pin::Pin, sync::Arc}; +pub use sp_runtime::transaction_validity::{ + TransactionLongevity, TransactionPriority, TransactionSource, TransactionTag, +}; + /// Transaction pool status. #[derive(Debug)] pub struct PoolStatus { @@ -177,7 +178,7 @@ pub trait TransactionPool: Send + Sync { /// Block type. type Block: BlockT; /// Transaction hash type. - type Hash: Hash + Eq + Member + Serialize; + type Hash: Hash + Eq + Member + Serialize + DeserializeOwned; /// In-pool transaction type. type InPoolTransaction: InPoolTransaction< Transaction = TransactionFor, diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 05675741ae51b..760115917c6d4 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -32,4 +32,3 @@ remote-externalities = { path = "../../../utils/frame/remote-externalities", ver # others log = "0.4.16" -tokio = { version = "1", features = ["macros"] } diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index e506e78a2fbdc..36f6c06328501 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -14,9 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } serde = { version = "1", features = ["derive"] } # Substrate Dependencies diff --git a/frame/contracts/rpc/src/lib.rs b/frame/contracts/rpc/src/lib.rs index e83e4e6249b92..599e80676cb19 100644 --- a/frame/contracts/rpc/src/lib.rs +++ b/frame/contracts/rpc/src/lib.rs @@ -17,11 +17,16 @@ //! Node-specific RPC methods for interaction with contracts. -use std::sync::Arc; +#![warn(unused_crate_dependencies)] + +use std::{marker::PhantomData, sync::Arc}; use codec::Codec; -use jsonrpc_core::{Error, ErrorCode, Result}; -use jsonrpc_derive::rpc; +use jsonrpsee::{ + core::{async_trait, Error as JsonRpseeError, RpcResult}, + proc_macros::rpc, + types::error::{CallError, ErrorCode, ErrorObject}, +}; use pallet_contracts_primitives::{ Code, CodeUploadResult, ContractExecResult, ContractInstantiateResult, }; @@ -37,8 +42,8 @@ use sp_runtime::{ pub use pallet_contracts_rpc_runtime_api::ContractsApi as ContractsRuntimeApi; -const RUNTIME_ERROR: i64 = 1; -const CONTRACT_DOESNT_EXIST: i64 = 2; +const RUNTIME_ERROR: i32 = 1; +const CONTRACT_DOESNT_EXIST: i32 = 2; pub type Weight = u64; @@ -58,15 +63,17 @@ const GAS_LIMIT: Weight = 5 * GAS_PER_SECOND; /// A private newtype for converting `ContractAccessError` into an RPC error. struct ContractAccessError(pallet_contracts_primitives::ContractAccessError); -impl From for Error { - fn from(e: ContractAccessError) -> Error { + +impl From for JsonRpseeError { + fn from(e: ContractAccessError) -> Self { use pallet_contracts_primitives::ContractAccessError::*; match e.0 { - DoesntExist => Error { - code: ErrorCode::ServerError(CONTRACT_DOESNT_EXIST), - message: "The specified contract doesn't exist.".into(), - data: None, - }, + DoesntExist => CallError::Custom(ErrorObject::owned( + CONTRACT_DOESNT_EXIST, + "The specified contract doesn't exist.", + None::<()>, + )) + .into(), } } } @@ -109,7 +116,7 @@ pub struct CodeUploadRequest { } /// Contracts RPC methods. -#[rpc] +#[rpc(client, server)] pub trait ContractsApi where Balance: Copy + TryFrom + Into, @@ -121,12 +128,12 @@ where /// /// This method is useful for calling getter-like methods on contracts or to dry-run a /// a contract call in order to determine the `gas_limit`. - #[rpc(name = "contracts_call")] + #[method(name = "contracts_call")] fn call( &self, call_request: CallRequest, at: Option, - ) -> Result>; + ) -> RpcResult>; /// Instantiate a new contract. /// @@ -134,12 +141,12 @@ where /// is not actually created. /// /// This method is useful for UIs to dry-run contract instantiations. - #[rpc(name = "contracts_instantiate")] + #[method(name = "contracts_instantiate")] fn instantiate( &self, instantiate_request: InstantiateRequest, at: Option, - ) -> Result>; + ) -> RpcResult>; /// Upload new code without instantiating a contract from it. /// @@ -147,48 +154,50 @@ where /// won't change any state. /// /// This method is useful for UIs to dry-run code upload. - #[rpc(name = "contracts_upload_code")] + #[method(name = "contracts_upload_code")] fn upload_code( &self, upload_request: CodeUploadRequest, at: Option, - ) -> Result>; + ) -> RpcResult>; /// Returns the value under a specified storage `key` in a contract given by `address` param, /// or `None` if it is not set. - #[rpc(name = "contracts_getStorage")] + #[method(name = "contracts_getStorage")] fn get_storage( &self, address: AccountId, key: H256, at: Option, - ) -> Result>; + ) -> RpcResult>; } -/// An implementation of contract specific RPC methods. -pub struct Contracts { - client: Arc, - _marker: std::marker::PhantomData, +/// Contracts RPC methods. +pub struct ContractsRpc { + client: Arc, + _marker: PhantomData, } -impl Contracts { +impl ContractsRpc { /// Create new `Contracts` with the given reference to the client. - pub fn new(client: Arc) -> Self { - Contracts { client, _marker: Default::default() } + pub fn new(client: Arc) -> Self { + Self { client, _marker: Default::default() } } } -impl - ContractsApi< + +#[async_trait] +impl + ContractsApiServer< ::Hash, <::Header as HeaderT>::Number, AccountId, Balance, Hash, - > for Contracts + > for ContractsRpc where Block: BlockT, - C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - C::Api: ContractsRuntimeApi< + Client: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, + Client::Api: ContractsRuntimeApi< Block, AccountId, Balance, @@ -203,7 +212,7 @@ where &self, call_request: CallRequest, at: Option<::Hash>, - ) -> Result> { + ) -> RpcResult> { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. @@ -226,7 +235,7 @@ where &self, instantiate_request: InstantiateRequest, at: Option<::Hash>, - ) -> Result> { + ) -> RpcResult> { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. @@ -265,7 +274,7 @@ where &self, upload_request: CodeUploadRequest, at: Option<::Hash>, - ) -> Result> { + ) -> RpcResult> { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. @@ -285,12 +294,9 @@ where address: AccountId, key: H256, at: Option<::Hash>, - ) -> Result> { + ) -> RpcResult> { let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); - + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); let result = api .get_storage(&at, address, key.into()) .map_err(runtime_error_into_rpc_err)? @@ -302,32 +308,35 @@ where } /// Converts a runtime trap into an RPC error. -fn runtime_error_into_rpc_err(err: impl std::fmt::Display) -> Error { - Error { - code: ErrorCode::ServerError(RUNTIME_ERROR), - message: "Runtime error".into(), - data: Some(err.to_string().into()), - } +fn runtime_error_into_rpc_err(err: impl std::fmt::Debug) -> JsonRpseeError { + CallError::Custom(ErrorObject::owned( + RUNTIME_ERROR, + "Runtime error", + Some(format!("{:?}", err)), + )) + .into() } -fn decode_hex>(from: H, name: &str) -> Result { - from.try_into().map_err(|_| Error { - code: ErrorCode::InvalidParams, - message: format!("{:?} does not fit into the {} type", from, name), - data: None, +fn decode_hex>(from: H, name: &str) -> RpcResult { + from.try_into().map_err(|_| { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + ErrorCode::InvalidParams.code(), + format!("{:?} does not fit into the {} type", from, name), + None::<()>, + ))) }) } -fn limit_gas(gas_limit: Weight) -> Result<()> { +fn limit_gas(gas_limit: Weight) -> RpcResult<()> { if gas_limit > GAS_LIMIT { - Err(Error { - code: ErrorCode::InvalidParams, - message: format!( + Err(JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + ErrorCode::InvalidParams.code(), + format!( "Requested gas limit is greater than maximum allowed: {} > {}", gas_limit, GAS_LIMIT ), - data: None, - }) + None::<()>, + )))) } else { Ok(()) } @@ -336,6 +345,7 @@ fn limit_gas(gas_limit: Weight) -> Result<()> { #[cfg(test)] mod tests { use super::*; + use pallet_contracts_primitives::{ContractExecResult, ContractInstantiateResult}; use sp_core::U256; fn trim(json: &str) -> String { diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 9b3d3a43c6045..2d3bfebc6633f 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -14,9 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index be1a74450d1f4..12e4e11f88256 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -16,14 +16,18 @@ // limitations under the License. #![warn(missing_docs)] +#![warn(unused_crate_dependencies)] //! Node-specific RPC methods for interaction with Merkle Mountain Range pallet. -use std::sync::Arc; +use std::{marker::PhantomData, sync::Arc}; use codec::{Codec, Encode}; -use jsonrpc_core::{Error, ErrorCode, Result}; -use jsonrpc_derive::rpc; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + proc_macros::rpc, + types::error::{CallError, ErrorObject}, +}; use serde::{Deserialize, Serialize}; use sp_api::ProvideRuntimeApi; @@ -34,6 +38,11 @@ use sp_runtime::{generic::BlockId, traits::Block as BlockT}; pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; +const RUNTIME_ERROR: i32 = 8000; +const MMR_ERROR: i32 = 8010; +const LEAF_NOT_FOUND_ERROR: i32 = MMR_ERROR + 1; +const GENERATE_PROOF_ERROR: i32 = MMR_ERROR + 2; + /// Retrieved MMR leaf and its proof. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] @@ -86,7 +95,7 @@ impl LeafBatchProof { } /// MMR RPC methods. -#[rpc] +#[rpc(client, server)] pub trait MmrApi { /// Generate MMR proof for given leaf index. /// @@ -96,12 +105,12 @@ pub trait MmrApi { /// /// Returns the (full) leaf itself and a proof for this leaf (compact encoding, i.e. hash of /// the leaf). Both parameters are SCALE-encoded. - #[rpc(name = "mmr_generateProof")] + #[method(name = "mmr_generateProof")] fn generate_proof( &self, leaf_index: LeafIndex, at: Option, - ) -> Result>; + ) -> RpcResult>; /// Generate MMR proof for the given leaf indices. /// @@ -113,43 +122,43 @@ pub trait MmrApi { /// the leaves). Both parameters are SCALE-encoded. /// The order of entries in the `leaves` field of the returned struct /// is the same as the order of the entries in `leaf_indices` supplied - #[rpc(name = "mmr_generateBatchProof")] + #[method(name = "mmr_generateBatchProof")] fn generate_batch_proof( &self, leaf_indices: Vec, at: Option, - ) -> Result>; + ) -> RpcResult>; } -/// An implementation of MMR specific RPC methods. -pub struct Mmr { - client: Arc, - _marker: std::marker::PhantomData, +/// MMR RPC methods. +pub struct MmrRpc { + client: Arc, + _marker: PhantomData, } -impl Mmr { +impl MmrRpc { /// Create new `Mmr` with the given reference to the client. pub fn new(client: Arc) -> Self { Self { client, _marker: Default::default() } } } -impl MmrApi<::Hash> for Mmr +#[async_trait] +impl MmrApiServer<::Hash> + for MmrRpc where Block: BlockT, - C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - C::Api: MmrRuntimeApi, + Client: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, + Client::Api: MmrRuntimeApi, MmrHash: Codec + Send + Sync + 'static, { fn generate_proof( &self, leaf_index: LeafIndex, at: Option<::Hash>, - ) -> Result::Hash>> { + ) -> RpcResult> { let api = self.client.runtime_api(); - let block_hash = at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash); + let block_hash = at.unwrap_or_else(|| self.client.info().best_hash); let (leaf, proof) = api .generate_proof_with_context( @@ -167,7 +176,7 @@ where &self, leaf_indices: Vec, at: Option<::Hash>, - ) -> Result::Hash>> { + ) -> RpcResult::Hash>> { let api = self.client.runtime_api(); let block_hash = at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. @@ -186,37 +195,31 @@ where } } -const RUNTIME_ERROR: i64 = 8000; -const MMR_ERROR: i64 = 8010; - -/// Converts a mmr-specific error into an RPC error. -fn mmr_error_into_rpc_error(err: MmrError) -> Error { +/// Converts a mmr-specific error into a [`CallError`]. +fn mmr_error_into_rpc_error(err: MmrError) -> CallError { + let data = format!("{:?}", err); match err { - MmrError::LeafNotFound => Error { - code: ErrorCode::ServerError(MMR_ERROR + 1), - message: "Leaf was not found".into(), - data: Some(format!("{:?}", err).into()), - }, - MmrError::GenerateProof => Error { - code: ErrorCode::ServerError(MMR_ERROR + 2), - message: "Error while generating the proof".into(), - data: Some(format!("{:?}", err).into()), - }, - _ => Error { - code: ErrorCode::ServerError(MMR_ERROR), - message: "Unexpected MMR error".into(), - data: Some(format!("{:?}", err).into()), - }, + MmrError::LeafNotFound => CallError::Custom(ErrorObject::owned( + LEAF_NOT_FOUND_ERROR, + "Leaf was not found", + Some(data), + )), + MmrError::GenerateProof => CallError::Custom(ErrorObject::owned( + GENERATE_PROOF_ERROR, + "Error while generating the proof", + Some(data), + )), + _ => CallError::Custom(ErrorObject::owned(MMR_ERROR, "Unexpected MMR error", Some(data))), } } -/// Converts a runtime trap into an RPC error. -fn runtime_error_into_rpc_error(err: impl std::fmt::Display) -> Error { - Error { - code: ErrorCode::ServerError(RUNTIME_ERROR), - message: "Runtime trapped".into(), - data: Some(err.to_string().into()), - } +/// Converts a runtime trap into a [`CallError`]. +fn runtime_error_into_rpc_error(err: impl std::fmt::Debug) -> CallError { + CallError::Custom(ErrorObject::owned( + RUNTIME_ERROR, + "Runtime trapped", + Some(format!("{:?}", err)), + )) } #[cfg(test)] diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index cae3bb1a9f975..958ab50315427 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -31,7 +31,7 @@ substrate-state-trie-migration-rpc = { optional = true, path = "../../utils/fram [dev-dependencies] parking_lot = "0.12.0" -tokio = { version = "1.10", features = ["macros"] } +tokio = { version = "1.17.0", features = ["macros"] } pallet-balances = { path = "../balances" } sp-tracing = { path = "../../primitives/tracing" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index b7a353916efbc..6133d3a4b6da1 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -14,9 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index 29d94fa260105..b0be19fdb22a9 100644 --- a/frame/transaction-payment/rpc/src/lib.rs +++ b/frame/transaction-payment/rpc/src/lib.rs @@ -17,11 +17,14 @@ //! RPC interface for the transaction payment pallet. -pub use self::gen_client::Client as TransactionPaymentClient; +use std::{convert::TryInto, sync::Arc}; + use codec::{Codec, Decode}; -use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; -use jsonrpc_derive::rpc; -pub use pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi as TransactionPaymentRuntimeApi; +use jsonrpsee::{ + core::{async_trait, Error as JsonRpseeError, RpcResult}, + proc_macros::rpc, + types::error::{CallError, ErrorCode, ErrorObject}, +}; use pallet_transaction_payment_rpc_runtime_api::{FeeDetails, InclusionFee, RuntimeDispatchInfo}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; @@ -31,28 +34,31 @@ use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, MaybeDisplay}, }; -use std::sync::Arc; -#[rpc] +pub use pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi as TransactionPaymentRuntimeApi; + +#[rpc(client, server)] pub trait TransactionPaymentApi { - #[rpc(name = "payment_queryInfo")] - fn query_info(&self, encoded_xt: Bytes, at: Option) -> Result; - #[rpc(name = "payment_queryFeeDetails")] + #[method(name = "payment_queryInfo")] + fn query_info(&self, encoded_xt: Bytes, at: Option) -> RpcResult; + + #[method(name = "payment_queryFeeDetails")] fn query_fee_details( &self, encoded_xt: Bytes, at: Option, - ) -> Result>; + ) -> RpcResult>; } -/// A struct that implements the [`TransactionPaymentApi`]. -pub struct TransactionPayment { +/// Provides RPC methods to query a dispatchable's class, weight and fee. +pub struct TransactionPaymentRpc { + /// Shared reference to the client. client: Arc, _marker: std::marker::PhantomData

, } -impl TransactionPayment { - /// Create new `TransactionPayment` with the given reference to the client. +impl TransactionPaymentRpc { + /// Creates a new instance of the TransactionPaymentRpc helper. pub fn new(client: Arc) -> Self { Self { client, _marker: Default::default() } } @@ -66,8 +72,8 @@ pub enum Error { RuntimeError, } -impl From for i64 { - fn from(e: Error) -> i64 { +impl From for i32 { + fn from(e: Error) -> i32 { match e { Error::RuntimeError => 1, Error::DecodeError => 2, @@ -75,66 +81,75 @@ impl From for i64 { } } -impl TransactionPaymentApi<::Hash, RuntimeDispatchInfo> - for TransactionPayment +#[async_trait] +impl + TransactionPaymentApiServer<::Hash, RuntimeDispatchInfo> + for TransactionPaymentRpc where Block: BlockT, - C: 'static + ProvideRuntimeApi + HeaderBackend, + C: ProvideRuntimeApi + HeaderBackend + Send + Sync + 'static, C::Api: TransactionPaymentRuntimeApi, - Balance: Codec + MaybeDisplay + Copy + TryInto, + Balance: Codec + MaybeDisplay + Copy + TryInto + Send + Sync + 'static, { fn query_info( &self, encoded_xt: Bytes, - at: Option<::Hash>, - ) -> Result> { + at: Option, + ) -> RpcResult> { let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); let encoded_len = encoded_xt.len() as u32; - let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::DecodeError.into()), - message: "Unable to query dispatch info.".into(), - data: Some(format!("{:?}", e).into()), + let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::DecodeError.into(), + "Unable to query dispatch info.", + Some(format!("{:?}", e)), + )) })?; - api.query_info(&at, uxt, encoded_len).map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to query dispatch info.".into(), - data: Some(e.to_string().into()), + api.query_info(&at, uxt, encoded_len).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to query dispatch info.", + Some(e.to_string()), + )) + .into() }) } fn query_fee_details( &self, encoded_xt: Bytes, - at: Option<::Hash>, - ) -> Result> { + at: Option, + ) -> RpcResult> { let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); let encoded_len = encoded_xt.len() as u32; - let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::DecodeError.into()), - message: "Unable to query fee details.".into(), - data: Some(format!("{:?}", e).into()), + let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::DecodeError.into(), + "Unable to query fee details.", + Some(format!("{:?}", e)), + )) })?; - let fee_details = api.query_fee_details(&at, uxt, encoded_len).map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to query fee details.".into(), - data: Some(e.to_string().into()), + let fee_details = api.query_fee_details(&at, uxt, encoded_len).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to query fee details.", + Some(e.to_string()), + )) })?; let try_into_rpc_balance = |value: Balance| { - value.try_into().map_err(|_| RpcError { - code: ErrorCode::InvalidParams, - message: format!("{} doesn't fit in NumberOrHex representation", value), - data: None, + value.try_into().map_err(|_| { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + ErrorCode::InvalidParams.code(), + format!("{} doesn't fit in NumberOrHex representation", value), + None::<()>, + ))) }) }; diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index cdadfb0f10f03..148f34246044d 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -28,7 +28,7 @@ pub use sc_client_api::{ }; pub use sc_client_db::{self, Backend}; pub use sc_executor::{self, NativeElseWasmExecutor, WasmExecutionMethod}; -pub use sc_service::{client, RpcHandlers, RpcSession}; +pub use sc_service::{client, RpcHandlers}; pub use sp_consensus; pub use sp_keyring::{ ed25519::Keyring as Ed25519Keyring, sr25519::Keyring as Sr25519Keyring, AccountKeyring, @@ -37,10 +37,7 @@ pub use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; pub use sp_runtime::{Storage, StorageChild}; pub use sp_state_machine::ExecutionStrategy; -use futures::{ - future::{Future, FutureExt}, - stream::StreamExt, -}; +use futures::{future::Future, stream::StreamExt}; use sc_client_api::BlockchainEvents; use sc_service::client::{ClientConfig, LocalCallExecutor}; use serde::Deserialize; @@ -297,16 +294,14 @@ impl /// The output of an RPC transaction. pub struct RpcTransactionOutput { /// The output string of the transaction if any. - pub result: Option, - /// The session object. - pub session: RpcSession, + pub result: String, /// An async receiver if data will be returned via a callback. pub receiver: futures::channel::mpsc::UnboundedReceiver, } impl std::fmt::Debug for RpcTransactionOutput { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "RpcTransactionOutput {{ result: {:?}, session, receiver }}", self.result) + write!(f, "RpcTransactionOutput {{ result: {:?}, receiver }}", self.result) } } @@ -328,56 +323,51 @@ impl std::fmt::Display for RpcTransactionError { } /// An extension trait for `RpcHandlers`. +#[async_trait::async_trait] pub trait RpcHandlersExt { /// Send a transaction through the RpcHandlers. - fn send_transaction( + async fn send_transaction( &self, extrinsic: OpaqueExtrinsic, - ) -> Pin> + Send>>; + ) -> Result; } +#[async_trait::async_trait] impl RpcHandlersExt for RpcHandlers { - fn send_transaction( + async fn send_transaction( &self, extrinsic: OpaqueExtrinsic, - ) -> Pin> + Send>> { - let (tx, rx) = futures::channel::mpsc::unbounded(); - let mem = RpcSession::new(tx); - Box::pin( - self.rpc_query( - &mem, - &format!( - r#"{{ + ) -> Result { + let (result, rx) = self + .rpc_query(&format!( + r#"{{ "jsonrpc": "2.0", "method": "author_submitExtrinsic", "params": ["0x{}"], "id": 0 }}"#, - hex::encode(extrinsic.encode()) - ), - ) - .map(move |result| parse_rpc_result(result, mem, rx)), - ) + hex::encode(extrinsic.encode()) + )) + .await + .expect("valid JSON-RPC request object; qed"); + parse_rpc_result(result, rx) } } pub(crate) fn parse_rpc_result( - result: Option, - session: RpcSession, + result: String, receiver: futures::channel::mpsc::UnboundedReceiver, ) -> Result { - if let Some(ref result) = result { - let json: serde_json::Value = - serde_json::from_str(result).expect("the result can only be a JSONRPC string; qed"); - let error = json.as_object().expect("JSON result is always an object; qed").get("error"); - - if let Some(error) = error { - return Err(serde_json::from_value(error.clone()) - .expect("the JSONRPC result's error is always valid; qed")) - } + let json: serde_json::Value = + serde_json::from_str(&result).expect("the result can only be a JSONRPC string; qed"); + let error = json.as_object().expect("JSON result is always an object; qed").get("error"); + + if let Some(error) = error { + return Err(serde_json::from_value(error.clone()) + .expect("the JSONRPC result's error is always valid; qed")) } - Ok(RpcTransactionOutput { result, session, receiver }) + Ok(RpcTransactionOutput { result, receiver }) } /// An extension trait for `BlockchainEvents`. @@ -418,40 +408,23 @@ where #[cfg(test)] mod tests { - use sc_service::RpcSession; - - fn create_session_and_receiver( - ) -> (RpcSession, futures::channel::mpsc::UnboundedReceiver) { - let (tx, rx) = futures::channel::mpsc::unbounded(); - let mem = RpcSession::new(tx.into()); - - (mem, rx) - } - #[test] fn parses_error_properly() { - let (mem, rx) = create_session_and_receiver(); - assert!(super::parse_rpc_result(None, mem, rx).is_ok()); - - let (mem, rx) = create_session_and_receiver(); + let (_, rx) = futures::channel::mpsc::unbounded(); assert!(super::parse_rpc_result( - Some( - r#"{ + r#"{ "jsonrpc": "2.0", "result": 19, "id": 1 }"# - .to_string() - ), - mem, + .to_string(), rx ) - .is_ok(),); + .is_ok()); - let (mem, rx) = create_session_and_receiver(); + let (_, rx) = futures::channel::mpsc::unbounded(); let error = super::parse_rpc_result( - Some( - r#"{ + r#"{ "jsonrpc": "2.0", "error": { "code": -32601, @@ -459,9 +432,7 @@ mod tests { }, "id": 1 }"# - .to_string(), - ), - mem, + .to_string(), rx, ) .unwrap_err(); @@ -469,10 +440,9 @@ mod tests { assert_eq!(error.message, "Method not found"); assert!(error.data.is_none()); - let (mem, rx) = create_session_and_receiver(); + let (_, rx) = futures::channel::mpsc::unbounded(); let error = super::parse_rpc_result( - Some( - r#"{ + r#"{ "jsonrpc": "2.0", "error": { "code": -32601, @@ -481,9 +451,7 @@ mod tests { }, "id": 1 }"# - .to_string(), - ), - mem, + .to_string(), rx, ) .unwrap_err(); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 94325ae9c1ab1..aef061d952a96 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -176,6 +176,19 @@ impl serde::Serialize for Extrinsic { } } +// rustc can't deduce this trait bound https://github.com/rust-lang/rust/issues/48214 +#[cfg(feature = "std")] +impl<'a> serde::Deserialize<'a> for Extrinsic { + fn deserialize(de: D) -> Result + where + D: serde::Deserializer<'a>, + { + let r = sp_core::bytes::deserialize(de)?; + Decode::decode(&mut &r[..]) + .map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e))) + } +} + impl BlindCheckable for Extrinsic { type Checked = Self; diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 49c004c3c074d..4a931470eafac 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } env_logger = "0.9" -jsonrpsee = { version = "0.10.1", features = ["ws-client", "macros"] } +jsonrpsee = { version = "0.12.0", features = ["ws-client", "macros"] } log = "0.4.16" serde = "1.0.136" serde_json = "1.0" diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 3913bae425757..726cc9f989ced 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -25,9 +25,7 @@ sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } trie-db = { version = "0.23.1" } -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" +jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } # Substrate Dependencies sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } diff --git a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index 2e3dd08a7db7e..531bf463f6523 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -17,8 +17,11 @@ //! Rpc for state migration. -use jsonrpc_core::{Error, ErrorCode, Result}; -use jsonrpc_derive::rpc; +use jsonrpsee::{ + core::{Error as JsonRpseeError, RpcResult}, + proc_macros::rpc, + types::error::{CallError, ErrorCode, ErrorObject}, +}; use sc_rpc_api::DenyUnsafe; use serde::{Deserialize, Serialize}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; @@ -107,15 +110,15 @@ pub struct MigrationStatusResult { } /// Migration RPC methods. -#[rpc] +#[rpc(server)] pub trait StateMigrationApi { /// Check current migration state. /// /// This call is performed locally without submitting any transactions. Thus executing this /// won't change any state. Nonetheless it is a VERY costy call that should be /// only exposed to trusted peers. - #[rpc(name = "state_trieMigrationStatus")] - fn call(&self, at: Option) -> Result; + #[method(name = "state_trieMigrationStatus")] + fn call(&self, at: Option) -> RpcResult; } /// An implementation of state migration specific RPC methods. @@ -133,16 +136,14 @@ impl MigrationRpc { } } -impl StateMigrationApi<::Hash> for MigrationRpc +impl StateMigrationApiServer<::Hash> for MigrationRpc where B: BlockT, C: Send + Sync + 'static + sc_client_api::HeaderBackend, BA: 'static + sc_client_api::backend::Backend, { - fn call(&self, at: Option<::Hash>) -> Result { - if let Err(err) = self.deny_unsafe.check_if_safe() { - return Err(err.into()) - } + fn call(&self, at: Option<::Hash>) -> RpcResult { + self.deny_unsafe.check_if_safe()?; let block_id = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); let state = self.backend.state_at(block_id).map_err(error_into_rpc_err)?; @@ -155,10 +156,10 @@ where } } -fn error_into_rpc_err(err: impl std::fmt::Display) -> Error { - Error { - code: ErrorCode::InternalError, - message: "Error while checking migration state".into(), - data: Some(err.to_string().into()), - } +fn error_into_rpc_err(err: impl std::fmt::Display) -> JsonRpseeError { + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + ErrorCode::InternalError.code(), + "Error while checking migration state", + Some(err.to_string()), + ))) } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index f9967758928e8..0c6d082406421 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -jsonrpc-client-transports = { version = "18.0.0", features = ["http"] } +jsonrpsee = { version = "0.12.0", features = ["jsonrpsee-types"] } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } @@ -25,5 +25,6 @@ sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } [dev-dependencies] scale-info = "2.0.1" +jsonrpsee = { version = "0.12.0", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.17.0" frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } diff --git a/utils/frame/rpc/support/src/lib.rs b/utils/frame/rpc/support/src/lib.rs index 5d7cba19f643c..2ee007c84f0aa 100644 --- a/utils/frame/rpc/support/src/lib.rs +++ b/utils/frame/rpc/support/src/lib.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Combines [sc_rpc_api::state::StateClient] with [frame_support::storage::generator] traits +//! Combines [sc_rpc_api::state::StateApiClient] with [frame_support::storage::generator] traits //! to provide strongly typed chain state queries over rpc. #![warn(missing_docs)] @@ -23,29 +23,26 @@ use codec::{DecodeAll, FullCodec, FullEncode}; use core::marker::PhantomData; use frame_support::storage::generator::{StorageDoubleMap, StorageMap, StorageValue}; -use jsonrpc_client_transports::RpcError; -use sc_rpc_api::state::StateClient; +use jsonrpsee::core::Error as RpcError; +use sc_rpc_api::state::StateApiClient; use serde::{de::DeserializeOwned, Serialize}; use sp_storage::{StorageData, StorageKey}; /// A typed query on chain state usable from an RPC client. /// /// ```no_run -/// # use jsonrpc_client_transports::RpcError; -/// # use jsonrpc_client_transports::transports::http; +/// # use jsonrpsee::core::Error as RpcError; +/// # use jsonrpsee::ws_client::WsClientBuilder; /// # use codec::Encode; /// # use frame_support::{decl_storage, decl_module}; /// # use substrate_frame_rpc_support::StorageQuery; /// # use frame_system::Config; -/// # use sc_rpc_api::state::StateClient; +/// # use sc_rpc_api::state::StateApiClient; /// # /// # // Hash would normally be ::Hash, but we don't have /// # // frame_system::Config implemented for TestRuntime. Here we just pretend. /// # type Hash = (); /// # -/// # fn main() -> Result<(), RpcError> { -/// # tokio::runtime::Runtime::new().unwrap().block_on(test()) -/// # } /// # /// # struct TestRuntime; /// # @@ -66,24 +63,25 @@ use sp_storage::{StorageData, StorageKey}; /// } /// } /// -/// # async fn test() -> Result<(), RpcError> { -/// let conn = http::connect("http://[::1]:9933").await?; -/// let cl = StateClient::::new(conn); +/// #[tokio::main] +/// async fn main() -> Result<(), RpcError> { +/// let cl = WsClientBuilder::default().build("ws://[::1]:9944").await?; /// -/// let q = StorageQuery::value::(); -/// let _: Option = q.get(&cl, None).await?; +/// let q = StorageQuery::value::(); +/// let hash = None::; +/// let _: Option = q.get(&cl, hash).await?; /// -/// let q = StorageQuery::map::((0, 0, 0)); -/// let _: Option = q.get(&cl, None).await?; +/// let q = StorageQuery::map::((0, 0, 0)); +/// let _: Option = q.get(&cl, hash).await?; /// -/// let q = StorageQuery::map::(12); -/// let _: Option = q.get(&cl, None).await?; +/// let q = StorageQuery::map::(12); +/// let _: Option = q.get(&cl, hash).await?; /// -/// let q = StorageQuery::double_map::(3, (0, 0, 0)); -/// let _: Option = q.get(&cl, None).await?; -/// # -/// # Ok(()) -/// # } +/// let q = StorageQuery::double_map::(3, (0, 0, 0)); +/// let _: Option = q.get(&cl, hash).await?; +/// +/// Ok(()) +/// } /// ``` #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct StorageQuery { @@ -120,14 +118,18 @@ impl StorageQuery { /// /// block_index indicates the block for which state will be queried. A value of None indicates /// the latest block. - pub async fn get( + pub async fn get( self, - state_client: &StateClient, + state_client: &StateClient, block_index: Option, - ) -> Result, RpcError> { + ) -> Result, RpcError> + where + Hash: Send + Sync + 'static + DeserializeOwned + Serialize, + StateClient: StateApiClient + Sync, + { let opt: Option = state_client.storage(self.key, block_index).await?; opt.map(|encoded| V::decode_all(&mut &encoded.0[..])) .transpose() - .map_err(|decode_err| RpcError::Other(Box::new(decode_err))) + .map_err(|decode_err| RpcError::Custom(decode_err.to_string())) } } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 5252d96af3f75..c95ae4793ca6a 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -13,11 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +serde_json = "1" codec = { package = "parity-scale-codec", version = "3.0.0" } +jsonrpsee = { version = "0.12.0", features = ["server"] } futures = "0.3.21" -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" log = "0.4.16" frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } @@ -31,5 +30,7 @@ sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] sc-transaction-pool = { version = "4.0.0-dev", path = "../../../../client/transaction-pool" } +tokio = "1.17.0" +assert_matches = "1.3.0" sp-tracing = { version = "5.0.0", path = "../../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } diff --git a/utils/frame/rpc/system/src/lib.rs b/utils/frame/rpc/system/src/lib.rs index b7da7730f0920..b044035c8120e 100644 --- a/utils/frame/rpc/system/src/lib.rs +++ b/utils/frame/rpc/system/src/lib.rs @@ -17,12 +17,15 @@ //! System FRAME specific RPC methods. -use std::sync::Arc; +use std::{fmt::Display, sync::Arc}; + +use codec::{self, Codec, Decode, Encode}; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + proc_macros::rpc, + types::error::{CallError, ErrorObject}, +}; -use codec::{Codec, Decode, Encode}; -use futures::FutureExt; -use jsonrpc_core::{Error as RpcError, ErrorCode}; -use jsonrpc_derive::rpc; use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_api::ApiExt; @@ -31,26 +34,22 @@ use sp_blockchain::HeaderBackend; use sp_core::{hexdisplay::HexDisplay, Bytes}; use sp_runtime::{generic::BlockId, legacy, traits}; -pub use self::gen_client::Client as SystemClient; pub use frame_system_rpc_runtime_api::AccountNonceApi; -/// Future that resolves to account nonce. -type FutureResult = jsonrpc_core::BoxFuture>; - /// System RPC methods. -#[rpc] +#[rpc(client, server)] pub trait SystemApi { /// Returns the next valid index (aka nonce) for given account. /// /// This method takes into consideration all pending transactions /// currently in the pool and if no transactions are found in the pool /// it fallbacks to query the index from the runtime (aka. state nonce). - #[rpc(name = "system_accountNextIndex", alias("account_nextIndex"))] - fn nonce(&self, account: AccountId) -> FutureResult; + #[method(name = "system_accountNextIndex", aliases = ["account_nextIndex"])] + async fn nonce(&self, account: AccountId) -> RpcResult; /// Dry run an extrinsic at a given block. Return SCALE encoded ApplyExtrinsicResult. - #[rpc(name = "system_dryRun", alias("system_dryRunAt"))] - fn dry_run(&self, extrinsic: Bytes, at: Option) -> FutureResult; + #[method(name = "system_dryRun", aliases = ["system_dryRunAt"])] + async fn dry_run(&self, extrinsic: Bytes, at: Option) -> RpcResult; } /// Error type of this RPC api. @@ -61,8 +60,8 @@ pub enum Error { RuntimeError, } -impl From for i64 { - fn from(e: Error) -> i64 { +impl From for i32 { + fn from(e: Error) -> i32 { match e { Error::RuntimeError => 1, Error::DecodeError => 2, @@ -71,22 +70,23 @@ impl From for i64 { } /// An implementation of System-specific RPC methods on full client. -pub struct FullSystem { +pub struct SystemRpc { client: Arc, pool: Arc

, deny_unsafe: DenyUnsafe, _marker: std::marker::PhantomData, } -impl FullSystem { +impl SystemRpc { /// Create new `FullSystem` given client and transaction pool. pub fn new(client: Arc, pool: Arc

, deny_unsafe: DenyUnsafe) -> Self { - FullSystem { client, pool, deny_unsafe, _marker: Default::default() } + Self { client, pool, deny_unsafe, _marker: Default::default() } } } -impl SystemApi<::Hash, AccountId, Index> - for FullSystem +#[async_trait] +impl + SystemApiServer<::Hash, AccountId, Index> for SystemRpc where C: sp_api::ProvideRuntimeApi, C: HeaderBackend, @@ -95,88 +95,83 @@ where C::Api: BlockBuilder, P: TransactionPool + 'static, Block: traits::Block, - AccountId: Clone + std::fmt::Display + Codec, - Index: Clone + std::fmt::Display + Codec + Send + traits::AtLeast32Bit + 'static, + AccountId: Clone + Display + Codec + Send + 'static, + Index: Clone + Display + Codec + Send + traits::AtLeast32Bit + 'static, { - fn nonce(&self, account: AccountId) -> FutureResult { - let get_nonce = || { - let api = self.client.runtime_api(); - let best = self.client.info().best_hash; - let at = BlockId::hash(best); - - let nonce = api.account_nonce(&at, account.clone()).map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to query nonce.".into(), - data: Some(e.to_string().into()), - })?; - - Ok(adjust_nonce(&*self.pool, account, nonce)) - }; - - let res = get_nonce(); - async move { res }.boxed() + async fn nonce(&self, account: AccountId) -> RpcResult { + let api = self.client.runtime_api(); + let best = self.client.info().best_hash; + let at = BlockId::hash(best); + + let nonce = api.account_nonce(&at, account.clone()).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to query nonce.", + Some(e.to_string()), + )) + })?; + Ok(adjust_nonce(&*self.pool, account, nonce)) } - fn dry_run( + async fn dry_run( &self, extrinsic: Bytes, at: Option<::Hash>, - ) -> FutureResult { - if let Err(err) = self.deny_unsafe.check_if_safe() { - return async move { Err(err.into()) }.boxed() - } + ) -> RpcResult { + self.deny_unsafe.check_if_safe()?; + let api = self.client.runtime_api(); + let at = BlockId::::hash(at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash)); + + let uxt: ::Extrinsic = + Decode::decode(&mut &*extrinsic).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::DecodeError.into(), + "Unable to dry run extrinsic", + Some(e.to_string()), + )) + })?; - let dry_run = || { - let api = self.client.runtime_api(); - let at = BlockId::::hash(at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); - - let uxt: ::Extrinsic = Decode::decode(&mut &*extrinsic) - .map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::DecodeError.into()), - message: "Unable to dry run extrinsic.".into(), - data: Some(e.to_string().into()), - })?; - - let api_version = api - .api_version::>(&at) - .map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to dry run extrinsic.".into(), - data: Some(e.to_string().into()), - })? - .ok_or_else(|| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to dry run extrinsic.".into(), - data: Some( - format!("Could not find `BlockBuilder` api for block `{:?}`.", at).into(), - ), - })?; - - let result = if api_version < 6 { - #[allow(deprecated)] - api.apply_extrinsic_before_version_6(&at, uxt) - .map(legacy::byte_sized_error::convert_to_latest) - .map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to dry run extrinsic.".into(), - data: Some(e.to_string().into()), - })? - } else { - api.apply_extrinsic(&at, uxt).map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to dry run extrinsic.".into(), - data: Some(e.to_string().into()), - })? - }; + let api_version = api + .api_version::>(&at) + .map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to dry run extrinsic.", + Some(e.to_string()), + )) + })? + .ok_or_else(|| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to dry run extrinsic.", + Some(format!("Could not find `BlockBuilder` api for block `{:?}`.", at)), + )) + })?; - Ok(Encode::encode(&result).into()) + let result = if api_version < 6 { + #[allow(deprecated)] + api.apply_extrinsic_before_version_6(&at, uxt) + .map(legacy::byte_sized_error::convert_to_latest) + .map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to dry run extrinsic.", + Some(e.to_string()), + )) + })? + } else { + api.apply_extrinsic(&at, uxt).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to dry run extrinsic.", + Some(e.to_string()), + )) + })? }; - let res = dry_run(); - - async move { res }.boxed() + Ok(Encode::encode(&result).into()) } } @@ -220,7 +215,9 @@ where mod tests { use super::*; + use assert_matches::assert_matches; use futures::executor::block_on; + use jsonrpsee::{core::Error as JsonRpseeError, types::error::CallError}; use sc_transaction_pool::BasicPool; use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidityError}, @@ -228,8 +225,8 @@ mod tests { }; use substrate_test_runtime_client::{runtime::Transfer, AccountKeyring}; - #[test] - fn should_return_next_nonce_for_some_account() { + #[tokio::test] + async fn should_return_next_nonce_for_some_account() { sp_tracing::try_init_simple(); // given @@ -254,17 +251,17 @@ mod tests { let ext1 = new_transaction(1); block_on(pool.submit_one(&BlockId::number(0), source, ext1)).unwrap(); - let accounts = FullSystem::new(client, pool, DenyUnsafe::Yes); + let accounts = SystemRpc::new(client, pool, DenyUnsafe::Yes); // when - let nonce = accounts.nonce(AccountKeyring::Alice.into()); + let nonce = accounts.nonce(AccountKeyring::Alice.into()).await; // then - assert_eq!(block_on(nonce).unwrap(), 2); + assert_eq!(nonce.unwrap(), 2); } - #[test] - fn dry_run_should_deny_unsafe() { + #[tokio::test] + async fn dry_run_should_deny_unsafe() { sp_tracing::try_init_simple(); // given @@ -273,17 +270,17 @@ mod tests { let pool = BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); - let accounts = FullSystem::new(client, pool, DenyUnsafe::Yes); + let accounts = SystemRpc::new(client, pool, DenyUnsafe::Yes); // when - let res = accounts.dry_run(vec![].into(), None); - - // then - assert_eq!(block_on(res), Err(sc_rpc_api::UnsafeRpcError.into())); + let res = accounts.dry_run(vec![].into(), None).await; + assert_matches!(res, Err(JsonRpseeError::Call(CallError::Custom(e))) => { + assert!(e.message().contains("RPC call is unsafe to be called externally")); + }); } - #[test] - fn dry_run_should_work() { + #[tokio::test] + async fn dry_run_should_work() { sp_tracing::try_init_simple(); // given @@ -292,7 +289,7 @@ mod tests { let pool = BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); - let accounts = FullSystem::new(client, pool, DenyUnsafe::No); + let accounts = SystemRpc::new(client, pool, DenyUnsafe::No); let tx = Transfer { from: AccountKeyring::Alice.into(), @@ -303,16 +300,15 @@ mod tests { .into_signed_tx(); // when - let res = accounts.dry_run(tx.encode().into(), None); + let bytes = accounts.dry_run(tx.encode().into(), None).await.expect("Call is successful"); // then - let bytes = block_on(res).unwrap().0; - let apply_res: ApplyExtrinsicResult = Decode::decode(&mut bytes.as_slice()).unwrap(); + let apply_res: ApplyExtrinsicResult = Decode::decode(&mut bytes.as_ref()).unwrap(); assert_eq!(apply_res, Ok(Ok(()))); } - #[test] - fn dry_run_should_indicate_error() { + #[tokio::test] + async fn dry_run_should_indicate_error() { sp_tracing::try_init_simple(); // given @@ -321,7 +317,7 @@ mod tests { let pool = BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); - let accounts = FullSystem::new(client, pool, DenyUnsafe::No); + let accounts = SystemRpc::new(client, pool, DenyUnsafe::No); let tx = Transfer { from: AccountKeyring::Alice.into(), @@ -332,11 +328,10 @@ mod tests { .into_signed_tx(); // when - let res = accounts.dry_run(tx.encode().into(), None); + let bytes = accounts.dry_run(tx.encode().into(), None).await.expect("Call is successful"); // then - let bytes = block_on(res).unwrap().0; - let apply_res: ApplyExtrinsicResult = Decode::decode(&mut bytes.as_slice()).unwrap(); + let apply_res: ApplyExtrinsicResult = Decode::decode(&mut bytes.as_ref()).unwrap(); assert_eq!(apply_res, Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))); } } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 2c0a2787b1dac..a5e658fc68476 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -14,12 +14,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "3.1.6", features = ["derive"] } -jsonrpsee = { version = "0.10.1", default-features = false, features = ["ws-client"] } log = "0.4.16" parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = { version = "0.10.0", default-features = false } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } +jsonrpsee = { version = "0.12.0", default-features = false, features = ["ws-client"] } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } From bbe4fd43b9a27b7c709e61f0044915dbc46ed5cd Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 10 May 2022 15:37:51 +0200 Subject: [PATCH 0781/1472] Sanity check for Babe's configuration (#11385) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Prevent div by zero in native babe code * Additional sanity check for babe config * Further sanity checks and postpone threshold computation * Apply suggestions from code review Co-authored-by: Bastian Köcher --- client/consensus/babe/src/authorship.rs | 16 ++++++++++------ frame/babe/src/lib.rs | 15 +++++++++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 7a9b09495cd6f..43df26a9a29ae 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -41,6 +41,14 @@ pub(super) fn calculate_primary_threshold( use num_rational::BigRational; use num_traits::{cast::ToPrimitive, identities::One}; + // Prevent div by zero and out of bounds access. + // While Babe's pallet implementation that ships with FRAME performs a sanity check over + // configuration parameters, this is not sufficient to guarantee that `c.1` is non-zero + // (i.e. third party implementations are possible). + if c.1 == 0 || authority_index >= authorities.len() { + return 0 + } + let c = c.0 as f64 / c.1 as f64; let theta = authorities[authority_index].1 as f64 / @@ -235,12 +243,6 @@ fn claim_primary_slot( for (authority_id, authority_index) in keys { let transcript = make_transcript(randomness, slot, *epoch_index); let transcript_data = make_transcript_data(randomness, slot, *epoch_index); - // Compute the threshold we will use. - // - // We already checked that authorities contains `key.public()`, so it can't - // be empty. Therefore, this division in `calculate_threshold` is safe. - let threshold = calculate_primary_threshold(c, authorities, *authority_index); - let result = SyncCryptoStore::sr25519_vrf_sign( &**keystore, AuthorityId::ID, @@ -253,6 +255,8 @@ fn claim_primary_slot( Ok(inout) => inout, Err(_) => continue, }; + + let threshold = calculate_primary_threshold(c, authorities, *authority_index); if check_primary_threshold(&inout, threshold) { let pre_digest = PreDigest::Primary(PrimaryPreDigest { slot, diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index e578f0695ac7c..1effc2c1989fa 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -24,6 +24,7 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::DispatchResultWithPostInfo, + ensure, traits::{ ConstU32, DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem, OnTimestampSet, OneSessionHandler, @@ -42,8 +43,8 @@ use sp_std::prelude::*; use sp_consensus_babe::{ digests::{NextConfigDescriptor, NextEpochDescriptor, PreDigest}, - BabeAuthorityWeight, BabeEpochConfiguration, ConsensusLog, Epoch, EquivocationProof, Slot, - BABE_ENGINE_ID, + AllowedSlots, BabeAuthorityWeight, BabeEpochConfiguration, ConsensusLog, Epoch, + EquivocationProof, Slot, BABE_ENGINE_ID, }; use sp_consensus_vrf::schnorrkel; @@ -185,6 +186,8 @@ pub mod pallet { InvalidKeyOwnershipProof, /// A given equivocation report is valid but already previously reported. DuplicateOffenceReport, + /// Submitted configuration is invalid. + InvalidConfiguration, } /// Current epoch index. @@ -447,6 +450,14 @@ pub mod pallet { config: NextConfigDescriptor, ) -> DispatchResult { ensure_root(origin)?; + match config { + NextConfigDescriptor::V1 { c, allowed_slots } => { + ensure!( + (c.0 != 0 || allowed_slots != AllowedSlots::PrimarySlots) && c.1 != 0, + Error::::InvalidConfiguration + ); + }, + } PendingEpochConfigChange::::put(config); Ok(()) } From b9df2488c964c4a3fdeb53ae0241e0f72efe1b36 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 10 May 2022 16:06:23 +0200 Subject: [PATCH 0782/1472] Refactory of Fork-Tree data structure (#11228) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Iterative version of some fork-tree methods * Prune doesn't require its generic args to be 'clone' * Fork-tree import and drain-filter iterative implementations * Fork-tree map iterative implementation * Optimization of some operations, e.g. rebalance only when required * Destructuring assignments not supported yet by stable rustc 1.57 * Safe implementation of 'map' and 'drain_filter' methods * Remove dummy comment * Trigger CI pipeline * Test map for multi-root fork-tree and refactory of `find_node_index_where` * Fix find node index with predicate * Nits * Tree traversal algorithm is not specified * Move unspecified tree traversal warning to 'map' * Immutable 'drain_filter' predicate * Apply suggestions from code review * Remove double mapping Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- client/finality-grandpa/src/authorities.rs | 4 +- utils/fork-tree/src/lib.rs | 779 ++++++++++----------- 2 files changed, 359 insertions(+), 424 deletions(-) diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index c2d44371986ca..0803e6b3c2931 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -229,7 +229,7 @@ where where F: Fn(&H, &H) -> Result, { - let mut filter = |node_hash: &H, node_num: &N, _: &PendingChange| { + let filter = |node_hash: &H, node_num: &N, _: &PendingChange| { if number >= *node_num && (is_descendent_of(node_hash, &hash).unwrap_or_default() || *node_hash == hash) { @@ -245,7 +245,7 @@ where }; // Remove standard changes. - let _ = self.pending_standard_changes.drain_filter(&mut filter); + let _ = self.pending_standard_changes.drain_filter(&filter); // Remove forced changes. self.pending_forced_changes diff --git a/utils/fork-tree/src/lib.rs b/utils/fork-tree/src/lib.rs index b4985b77294b2..45957f4390532 100644 --- a/utils/fork-tree/src/lib.rs +++ b/utils/fork-tree/src/lib.rs @@ -81,6 +81,7 @@ pub enum FilterAction { } /// A tree data structure that stores several nodes across multiple branches. +/// /// Top-level branches are called roots. The tree has functionality for /// finalizing nodes, which means that that node is traversed, and all competing /// branches are pruned. It also guarantees that nodes in the tree are finalized @@ -93,90 +94,6 @@ pub struct ForkTree { best_finalized_number: Option, } -impl ForkTree -where - H: PartialEq + Clone, - N: Ord + Clone, - V: Clone, -{ - /// Prune the tree, removing all non-canonical nodes. We find the node in the - /// tree that is the deepest ancestor of the given hash and that passes the - /// given predicate. If such a node exists, we re-root the tree to this - /// node. Otherwise the tree remains unchanged. The given function - /// `is_descendent_of` should return `true` if the second hash (target) is a - /// descendent of the first hash (base). - /// - /// Returns all pruned node data. - pub fn prune( - &mut self, - hash: &H, - number: &N, - is_descendent_of: &F, - predicate: &P, - ) -> Result, Error> - where - E: std::error::Error, - F: Fn(&H, &H) -> Result, - P: Fn(&V) -> bool, - { - let new_root_index = - self.find_node_index_where(hash, number, is_descendent_of, predicate)?; - - let removed = if let Some(mut root_index) = new_root_index { - let mut old_roots = std::mem::take(&mut self.roots); - - let mut root = None; - let mut cur_children = Some(&mut old_roots); - - while let Some(cur_index) = root_index.pop() { - if let Some(children) = cur_children.take() { - if root_index.is_empty() { - root = Some(children.remove(cur_index)); - } else { - cur_children = Some(&mut children[cur_index].children); - } - } - } - - let mut root = root.expect( - "find_node_index_where will return array with at least one index; \ - this results in at least one item in removed; qed", - ); - - let mut removed = old_roots; - - // we found the deepest ancestor of the finalized block, so we prune - // out any children that don't include the finalized block. - let root_children = std::mem::take(&mut root.children); - let mut is_first = true; - - for child in root_children { - if is_first && - (child.number == *number && child.hash == *hash || - child.number < *number && is_descendent_of(&child.hash, hash)?) - { - root.children.push(child); - // assuming that the tree is well formed only one child should pass this - // requirement due to ancestry restrictions (i.e. they must be different forks). - is_first = false; - } else { - removed.push(child); - } - } - - self.roots = vec![root]; - - removed - } else { - Vec::new() - }; - - self.rebalance(); - - Ok(RemovedIterator { stack: removed }) - } -} - impl ForkTree where H: PartialEq, @@ -187,19 +104,19 @@ where ForkTree { roots: Vec::new(), best_finalized_number: None } } - /// Rebalance the tree, i.e. sort child nodes by max branch depth - /// (decreasing). + /// Rebalance the tree, i.e. sort child nodes by max branch depth (decreasing). /// /// Most operations in the tree are performed with depth-first search /// starting from the leftmost node at every level, since this tree is meant /// to be used in a blockchain context, a good heuristic is that the node - /// we'll be looking - /// for at any point will likely be in one of the deepest chains (i.e. the - /// longest ones). + /// we'll be looking for at any point will likely be in one of the deepest chains + /// (i.e. the longest ones). pub fn rebalance(&mut self) { self.roots.sort_by_key(|n| Reverse(n.max_depth())); - for root in &mut self.roots { - root.rebalance(); + let mut stack: Vec<_> = self.roots.iter_mut().collect(); + while let Some(node) = stack.pop() { + node.children.sort_by_key(|n| Reverse(n.max_depth())); + stack.extend(node.children.iter_mut()); } } @@ -211,9 +128,9 @@ where /// Returns `true` if the imported node is a root. pub fn import( &mut self, - mut hash: H, - mut number: N, - mut data: V, + hash: H, + number: N, + data: V, is_descendent_of: &F, ) -> Result> where @@ -226,29 +143,33 @@ where } } - for root in self.roots.iter_mut() { - if root.hash == hash { + let mut children = &mut self.roots; + let mut i = 0; + while i < children.len() { + let child = &children[i]; + if child.hash == hash { return Err(Error::Duplicate) } - - match root.import(hash, number, data, is_descendent_of)? { - Some((h, n, d)) => { - hash = h; - number = n; - data = d; - }, - None => { - self.rebalance(); - return Ok(false) - }, + if child.number < number && is_descendent_of(&child.hash, &hash)? { + children = &mut children[i].children; + i = 0; + } else { + i += 1; } } - self.roots.push(Node { data, hash, number, children: Vec::new() }); + let is_first = children.is_empty(); + children.push(Node { data, hash, number, children: Default::default() }); - self.rebalance(); + // Quick way to check if the pushed node is a root + let is_root = children.as_ptr() == self.roots.as_ptr(); + + if is_first { + // Rebalance is required only if we've extended the branch depth. + self.rebalance(); + } - Ok(true) + Ok(is_root) } /// Iterates over the existing roots in the tree. @@ -267,6 +188,53 @@ where self.node_iter().map(|node| (&node.hash, &node.number, &node.data)) } + /// Map fork tree into values of new types. + /// + /// Tree traversal technique (e.g. BFS vs DFS) is left as not specified and + /// may be subject to change in the future. In other words, your predicates + /// should not rely on the observed traversal technique currently in use. + pub fn map(self, f: &mut F) -> ForkTree + where + F: FnMut(&H, &N, V) -> VT, + { + let mut queue: Vec<_> = + self.roots.into_iter().rev().map(|node| (usize::MAX, node)).collect(); + let mut next_queue = Vec::new(); + let mut output = Vec::new(); + + while !queue.is_empty() { + for (parent_index, node) in queue.drain(..) { + let new_data = f(&node.hash, &node.number, node.data); + let new_node = Node { + hash: node.hash, + number: node.number, + data: new_data, + children: Vec::with_capacity(node.children.len()), + }; + + let node_id = output.len(); + output.push((parent_index, new_node)); + + for child in node.children.into_iter().rev() { + next_queue.push((node_id, child)); + } + } + + std::mem::swap(&mut queue, &mut next_queue); + } + + let mut roots = Vec::new(); + while let Some((parent_index, new_node)) = output.pop() { + if parent_index == usize::MAX { + roots.push(new_node); + } else { + output[parent_index].1.children.push(new_node); + } + } + + ForkTree { roots, best_finalized_number: self.best_finalized_number } + } + /// Find a node in the tree that is the deepest ancestor of the given /// block hash and which passes the given predicate. The given function /// `is_descendent_of` should return `true` if the second hash (target) @@ -283,27 +251,12 @@ where F: Fn(&H, &H) -> Result, P: Fn(&V) -> bool, { - // search for node starting from all roots - for root in self.roots.iter() { - let node = root.find_node_where(hash, number, is_descendent_of, predicate)?; - - // found the node, early exit - if let FindOutcome::Found(node) = node { - return Ok(Some(node)) - } - } - - Ok(None) - } - - /// Map fork tree into values of new types. - pub fn map(self, f: &mut F) -> ForkTree - where - F: FnMut(&H, &N, V) -> VT, - { - let roots = self.roots.into_iter().map(|root| root.map(f)).collect(); - - ForkTree { roots, best_finalized_number: self.best_finalized_number } + let maybe_path = self.find_node_index_where(hash, number, is_descendent_of, predicate)?; + Ok(maybe_path.map(|path| { + let children = + path.iter().take(path.len() - 1).fold(&self.roots, |curr, &i| &curr[i].children); + &children[path[path.len() - 1]] + })) } /// Same as [`find_node_where`](ForkTree::find_node_where), but returns mutable reference. @@ -319,44 +272,121 @@ where F: Fn(&H, &H) -> Result, P: Fn(&V) -> bool, { - // search for node starting from all roots - for root in self.roots.iter_mut() { - let node = root.find_node_where_mut(hash, number, is_descendent_of, predicate)?; + let maybe_path = self.find_node_index_where(hash, number, is_descendent_of, predicate)?; + Ok(maybe_path.map(|path| { + let children = path + .iter() + .take(path.len() - 1) + .fold(&mut self.roots, |curr, &i| &mut curr[i].children); + &mut children[path[path.len() - 1]] + })) + } - // found the node, early exit - if let FindOutcome::Found(node) = node { - return Ok(Some(node)) + /// Same as [`find_node_where`](ForkTree::find_node_where), but returns indices. + /// + /// The returned indices represent the full path to reach the matching node starting + /// from first to last, i.e. the earliest index in the traverse path goes first, and the final + /// index in the traverse path goes last. If a node is found that matches the predicate + /// the returned path should always contain at least one index, otherwise `None` is + /// returned. + pub fn find_node_index_where( + &self, + hash: &H, + number: &N, + is_descendent_of: &F, + predicate: &P, + ) -> Result>, Error> + where + E: std::error::Error, + F: Fn(&H, &H) -> Result, + P: Fn(&V) -> bool, + { + let mut path = vec![]; + let mut children = &self.roots; + let mut i = 0; + let mut best_depth = 0; + + while i < children.len() { + let node = &children[i]; + if node.number < *number && is_descendent_of(&node.hash, hash)? { + path.push(i); + if predicate(&node.data) { + best_depth = path.len(); + } + i = 0; + children = &node.children; + } else { + i += 1; } } - Ok(None) + Ok(if best_depth == 0 { + None + } else { + path.truncate(best_depth); + Some(path) + }) } - /// Same as [`find_node_where`](ForkTree::find_node_where), but returns indexes. - pub fn find_node_index_where( - &self, + /// Prune the tree, removing all non-canonical nodes. We find the node in the + /// tree that is the deepest ancestor of the given hash and that passes the + /// given predicate. If such a node exists, we re-root the tree to this + /// node. Otherwise the tree remains unchanged. The given function + /// `is_descendent_of` should return `true` if the second hash (target) is a + /// descendent of the first hash (base). + /// + /// Returns all pruned node data. + pub fn prune( + &mut self, hash: &H, number: &N, is_descendent_of: &F, predicate: &P, - ) -> Result>, Error> + ) -> Result, Error> where E: std::error::Error, F: Fn(&H, &H) -> Result, P: Fn(&V) -> bool, { - // search for node starting from all roots - for (index, root) in self.roots.iter().enumerate() { - let node = root.find_node_index_where(hash, number, is_descendent_of, predicate)?; - - // found the node, early exit - if let FindOutcome::Found(mut node) = node { - node.push(index); - return Ok(Some(node)) + let root_index = + match self.find_node_index_where(hash, number, is_descendent_of, predicate)? { + Some(idx) => idx, + None => return Ok(RemovedIterator { stack: Vec::new() }), + }; + + let mut old_roots = std::mem::take(&mut self.roots); + + let curr_children = root_index + .iter() + .take(root_index.len() - 1) + .fold(&mut old_roots, |curr, idx| &mut curr[*idx].children); + let mut root = curr_children.remove(root_index[root_index.len() - 1]); + + let mut removed = old_roots; + + // we found the deepest ancestor of the finalized block, so we prune + // out any children that don't include the finalized block. + let root_children = std::mem::take(&mut root.children); + let mut is_first = true; + + for child in root_children { + if is_first && + (child.number == *number && child.hash == *hash || + child.number < *number && is_descendent_of(&child.hash, hash)?) + { + root.children.push(child); + // assuming that the tree is well formed only one child should pass this + // requirement due to ancestry restrictions (i.e. they must be different forks). + is_first = false; + } else { + removed.push(child); } } - Ok(None) + self.roots = vec![root]; + self.rebalance(); + + Ok(RemovedIterator { stack: removed }) } /// Finalize a root in the tree and return it, return `None` in case no root @@ -638,44 +668,71 @@ where } /// Remove from the tree some nodes (and their subtrees) using a `filter` predicate. + /// /// The `filter` is called over tree nodes and returns a filter action: /// - `Remove` if the node and its subtree should be removed; /// - `KeepNode` if we should maintain the node and keep processing the tree. /// - `KeepTree` if we should maintain the node and its entire subtree. + /// /// An iterator over all the pruned nodes is returned. - pub fn drain_filter(&mut self, mut filter: F) -> impl Iterator + pub fn drain_filter(&mut self, filter: F) -> impl Iterator where - F: FnMut(&H, &N, &V) -> FilterAction, + F: Fn(&H, &N, &V) -> FilterAction, { - let mut removed = Vec::new(); - let mut i = 0; - while i < self.roots.len() { - if self.roots[i].drain_filter(&mut filter, &mut removed) { - removed.push(self.roots.remove(i)); + let mut removed = vec![]; + let mut retained = Vec::new(); + + let mut queue: Vec<_> = std::mem::take(&mut self.roots) + .into_iter() + .rev() + .map(|node| (usize::MAX, node)) + .collect(); + let mut next_queue = Vec::new(); + + while !queue.is_empty() { + for (parent_idx, mut node) in queue.drain(..) { + match filter(&node.hash, &node.number, &node.data) { + FilterAction::KeepNode => { + let node_idx = retained.len(); + let children = std::mem::take(&mut node.children); + retained.push((parent_idx, node)); + for child in children.into_iter().rev() { + next_queue.push((node_idx, child)); + } + }, + FilterAction::KeepTree => { + retained.push((parent_idx, node)); + }, + FilterAction::Remove => { + removed.push(node); + }, + } + } + + std::mem::swap(&mut queue, &mut next_queue); + } + + while let Some((parent_idx, node)) = retained.pop() { + if parent_idx == usize::MAX { + self.roots.push(node); } else { - i += 1; + retained[parent_idx].1.children.push(node); } } - self.rebalance(); + + if !removed.is_empty() { + self.rebalance(); + } RemovedIterator { stack: removed } } } // Workaround for: https://github.com/rust-lang/rust/issues/34537 +use node_implementation::Node; + mod node_implementation { use super::*; - /// The outcome of a search within a node. - pub enum FindOutcome { - // this is the node we were looking for. - Found(T), - // not the node we're looking for. contains a flag indicating - // whether the node was a descendent. true implies the predicate failed. - Failure(bool), - // Abort search. - Abort, - } - #[derive(Clone, Debug, Decode, Encode, PartialEq)] pub struct Node { pub hash: H, @@ -685,239 +742,21 @@ mod node_implementation { } impl Node { - /// Rebalance the tree, i.e. sort child nodes by max branch depth (decreasing). - pub fn rebalance(&mut self) { - self.children.sort_by_key(|n| Reverse(n.max_depth())); - for child in &mut self.children { - child.rebalance(); - } - } - /// Finds the max depth among all branches descendent from this node. pub fn max_depth(&self) -> usize { - let mut max = 0; - - for node in &self.children { - max = node.max_depth().max(max) - } - - max + 1 - } - - /// Map node data into values of new types. - pub fn map(self, f: &mut F) -> Node - where - F: FnMut(&H, &N, V) -> VT, - { - let children = self.children.into_iter().map(|node| node.map(f)).collect(); - - let vt = f(&self.hash, &self.number, self.data); - Node { hash: self.hash, number: self.number, data: vt, children } - } - - pub fn import( - &mut self, - mut hash: H, - mut number: N, - mut data: V, - is_descendent_of: &F, - ) -> Result, Error> - where - E: fmt::Debug, - F: Fn(&H, &H) -> Result, - { - if self.hash == hash { - return Err(Error::Duplicate) - }; - - if number <= self.number { - return Ok(Some((hash, number, data))) - } - - for node in self.children.iter_mut() { - match node.import(hash, number, data, is_descendent_of)? { - Some((h, n, d)) => { - hash = h; - number = n; - data = d; - }, - None => return Ok(None), + let mut max: usize = 0; + let mut stack = vec![(self, 0)]; + while let Some((node, height)) = stack.pop() { + if height > max { + max = height; } + node.children.iter().for_each(|n| stack.push((n, height + 1))); } - - if is_descendent_of(&self.hash, &hash)? { - self.children.push(Node { data, hash, number, children: Vec::new() }); - - Ok(None) - } else { - Ok(Some((hash, number, data))) - } - } - - /// Find a node in the tree that is the deepest ancestor of the given - /// block hash which also passes the given predicate, backtracking - /// when the predicate fails. - /// The given function `is_descendent_of` should return `true` if the second hash (target) - /// is a descendent of the first hash (base). - /// - /// The returned indices are from last to first. The earliest index in the traverse path - /// goes last, and the final index in the traverse path goes first. An empty list means - /// that the current node is the result. - pub fn find_node_index_where( - &self, - hash: &H, - number: &N, - is_descendent_of: &F, - predicate: &P, - ) -> Result>, Error> - where - E: std::error::Error, - F: Fn(&H, &H) -> Result, - P: Fn(&V) -> bool, - { - // stop searching this branch - if *number < self.number { - return Ok(FindOutcome::Failure(false)) - } - - let mut known_descendent_of = false; - - // continue depth-first search through all children - for (i, node) in self.children.iter().enumerate() { - // found node, early exit - match node.find_node_index_where(hash, number, is_descendent_of, predicate)? { - FindOutcome::Abort => return Ok(FindOutcome::Abort), - FindOutcome::Found(mut x) => { - x.push(i); - return Ok(FindOutcome::Found(x)) - }, - FindOutcome::Failure(true) => { - // if the block was a descendent of this child, - // then it cannot be a descendent of any others, - // so we don't search them. - known_descendent_of = true; - break - }, - FindOutcome::Failure(false) => {}, - } - } - - // node not found in any of the descendents, if the node we're - // searching for is a descendent of this node then we will stop the - // search here, since there aren't any more children and we found - // the correct node so we don't want to backtrack. - let is_descendent_of = known_descendent_of || is_descendent_of(&self.hash, hash)?; - if is_descendent_of { - // if the predicate passes we return the node - if predicate(&self.data) { - return Ok(FindOutcome::Found(Vec::new())) - } - } - - // otherwise, tell our ancestor that we failed, and whether - // the block was a descendent. - Ok(FindOutcome::Failure(is_descendent_of)) - } - - /// Find a node in the tree that is the deepest ancestor of the given - /// block hash which also passes the given predicate, backtracking - /// when the predicate fails. - /// The given function `is_descendent_of` should return `true` if the second hash (target) - /// is a descendent of the first hash (base). - pub fn find_node_where( - &self, - hash: &H, - number: &N, - is_descendent_of: &F, - predicate: &P, - ) -> Result>, Error> - where - E: std::error::Error, - F: Fn(&H, &H) -> Result, - P: Fn(&V) -> bool, - { - let outcome = self.find_node_index_where(hash, number, is_descendent_of, predicate)?; - - match outcome { - FindOutcome::Abort => Ok(FindOutcome::Abort), - FindOutcome::Failure(f) => Ok(FindOutcome::Failure(f)), - FindOutcome::Found(mut indexes) => { - let mut cur = self; - - while let Some(i) = indexes.pop() { - cur = &cur.children[i]; - } - Ok(FindOutcome::Found(cur)) - }, - } - } - - /// Find a node in the tree that is the deepest ancestor of the given - /// block hash which also passes the given predicate, backtracking - /// when the predicate fails. - /// The given function `is_descendent_of` should return `true` if the second hash (target) - /// is a descendent of the first hash (base). - pub fn find_node_where_mut( - &mut self, - hash: &H, - number: &N, - is_descendent_of: &F, - predicate: &P, - ) -> Result>, Error> - where - E: std::error::Error, - F: Fn(&H, &H) -> Result, - P: Fn(&V) -> bool, - { - let outcome = self.find_node_index_where(hash, number, is_descendent_of, predicate)?; - - match outcome { - FindOutcome::Abort => Ok(FindOutcome::Abort), - FindOutcome::Failure(f) => Ok(FindOutcome::Failure(f)), - FindOutcome::Found(mut indexes) => { - let mut cur = self; - - while let Some(i) = indexes.pop() { - cur = &mut cur.children[i]; - } - Ok(FindOutcome::Found(cur)) - }, - } - } - - /// Calls a `filter` predicate for the given node. - /// The `filter` is called over tree nodes and returns a filter action: - /// - `Remove` if the node and its subtree should be removed; - /// - `KeepNode` if we should maintain the node and keep processing the tree; - /// - `KeepTree` if we should maintain the node and its entire subtree. - /// Pruned subtrees are added to the `removed` list. - /// Returns a booleans indicateing if this node (and its subtree) should be removed. - pub fn drain_filter(&mut self, filter: &mut F, removed: &mut Vec>) -> bool - where - F: FnMut(&H, &N, &V) -> FilterAction, - { - match filter(&self.hash, &self.number, &self.data) { - FilterAction::KeepNode => { - let mut i = 0; - while i < self.children.len() { - if self.children[i].drain_filter(filter, removed) { - removed.push(self.children.remove(i)); - } else { - i += 1; - } - } - false - }, - FilterAction::KeepTree => false, - FilterAction::Remove => true, - } + max } } } -// Workaround for: https://github.com/rust-lang/rust/issues/34537 -use node_implementation::{FindOutcome, Node}; - struct ForkTreeIterator<'a, H, N, V> { stack: Vec<&'a Node>, } @@ -985,7 +824,7 @@ mod test { // / / // A - F - H - I // \ \ - // \ - L - M + // \ - L - M - N // \ \ // \ - O // - J - K @@ -996,7 +835,7 @@ mod test { // diagram above. the children will be ordered by subtree depth and the longest branches // will be on the leftmost side of the tree. let is_descendent_of = |base: &&str, block: &&str| -> Result { - let letters = vec!["B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "O"]; + let letters = vec!["B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"]; match (*base, *block) { ("A", b) => Ok(letters.into_iter().any(|n| n == b)), ("B", b) => Ok(b == "C" || b == "D" || b == "E"), @@ -1004,14 +843,14 @@ mod test { ("D", b) => Ok(b == "E"), ("E", _) => Ok(false), ("F", b) => - Ok(b == "G" || b == "H" || b == "I" || b == "L" || b == "M" || b == "O"), + Ok(b == "G" || b == "H" || b == "I" || b == "L" || b == "M" || b == "N" || b == "O"), ("G", _) => Ok(false), - ("H", b) => Ok(b == "I" || b == "L" || b == "M" || b == "O"), + ("H", b) => Ok(b == "I" || b == "L" || b == "M" || b == "N" || b == "O"), ("I", _) => Ok(false), ("J", b) => Ok(b == "K"), ("K", _) => Ok(false), - ("L", b) => Ok(b == "M" || b == "O"), - ("M", _) => Ok(false), + ("L", b) => Ok(b == "M" || b == "O" || b == "N"), + ("M", b) => Ok(b == "N"), ("O", _) => Ok(false), ("0", _) => Ok(true), _ => Ok(false), @@ -1237,7 +1076,7 @@ mod test { // // Nodes B, C, F and G are not part of the tree. match (*base, *block) { - ("A0", b) => Ok(b == "B" || b == "C" || b == "D" || b == "G"), + ("A0", b) => Ok(b == "B" || b == "C" || b == "D" || b == "E" || b == "G"), ("A1", _) => Ok(false), ("C", b) => Ok(b == "D"), ("D", b) => Ok(b == "E" || b == "F" || b == "G"), @@ -1246,10 +1085,16 @@ mod test { } }; - tree.import("A0", 1, Change { effective: 5 }, &is_descendent_of).unwrap(); - tree.import("A1", 1, Change { effective: 5 }, &is_descendent_of).unwrap(); - tree.import("D", 10, Change { effective: 10 }, &is_descendent_of).unwrap(); - tree.import("E", 15, Change { effective: 50 }, &is_descendent_of).unwrap(); + let is_root = tree.import("A0", 1, Change { effective: 5 }, &is_descendent_of).unwrap(); + assert!(is_root); + let is_root = tree.import("A1", 1, Change { effective: 5 }, &is_descendent_of).unwrap(); + assert!(is_root); + let is_root = + tree.import("D", 10, Change { effective: 10 }, &is_descendent_of).unwrap(); + assert!(!is_root); + let is_root = + tree.import("E", 15, Change { effective: 50 }, &is_descendent_of).unwrap(); + assert!(!is_root); (tree, is_descendent_of) }; @@ -1416,20 +1261,25 @@ mod test { } #[test] - fn find_node_works() { - let (tree, is_descendent_of) = test_fork_tree(); - - let node = tree.find_node_where(&"D", &4, &is_descendent_of, &|_| true).unwrap().unwrap(); + fn map_works() { + let (mut tree, _) = test_fork_tree(); - assert_eq!(node.hash, "C"); - assert_eq!(node.number, 3); - } + // Extend the single root fork-tree to also excercise the roots order during map. + let is_descendent_of = |_: &&str, _: &&str| -> Result { Ok(false) }; + let is_root = tree.import("A1", 1, (), &is_descendent_of).unwrap(); + assert!(is_root); + let is_root = tree.import("A2", 1, (), &is_descendent_of).unwrap(); + assert!(is_root); - #[test] - fn map_works() { - let (tree, _is_descendent_of) = test_fork_tree(); + let old_tree = tree.clone(); + let new_tree = tree.map(&mut |hash, _, _| hash.to_owned()); - let _tree = tree.map(&mut |_, _, _| ()); + // Check content and order + assert!(new_tree.iter().all(|(hash, _, data)| hash == data)); + assert_eq!( + old_tree.iter().map(|(hash, _, _)| *hash).collect::>(), + new_tree.iter().map(|(hash, _, _)| *hash).collect::>(), + ); } #[test] @@ -1489,7 +1339,7 @@ mod test { } #[test] - fn tree_rebalance() { + fn rebalance_works() { let (mut tree, _) = test_fork_tree(); // the tree is automatically rebalanced on import, therefore we should iterate in preorder @@ -1503,7 +1353,7 @@ mod test { // let's add a block "P" which is a descendent of block "O" let is_descendent_of = |base: &&str, block: &&str| -> Result { match (*base, *block) { - (b, "P") => Ok(vec!["A", "F", "L", "O"].into_iter().any(|n| n == b)), + (b, "P") => Ok(vec!["A", "F", "H", "L", "O"].into_iter().any(|n| n == b)), _ => Ok(false), } }; @@ -1520,7 +1370,7 @@ mod test { } #[test] - fn tree_drain_filter() { + fn drain_filter_works() { let (mut tree, _) = test_fork_tree(); let filter = |h: &&str, _: &u64, _: &()| match *h { @@ -1539,7 +1389,92 @@ mod test { assert_eq!( removed.map(|(h, _, _)| h).collect::>(), - ["J", "K", "H", "L", "M", "O", "I"] + ["H", "L", "M", "O", "I", "J", "K"] ); } + + #[test] + fn find_node_index_works() { + let (tree, is_descendent_of) = test_fork_tree(); + + let path = tree + .find_node_index_where(&"D", &4, &is_descendent_of, &|_| true) + .unwrap() + .unwrap(); + assert_eq!(path, [0, 0, 0]); + + let path = tree + .find_node_index_where(&"O", &5, &is_descendent_of, &|_| true) + .unwrap() + .unwrap(); + assert_eq!(path, [0, 1, 0, 0]); + + let path = tree + .find_node_index_where(&"N", &6, &is_descendent_of, &|_| true) + .unwrap() + .unwrap(); + assert_eq!(path, [0, 1, 0, 0, 0]); + } + + #[test] + fn find_node_index_with_predicate_works() { + fn is_descendent_of(parent: &char, child: &char) -> Result { + match *parent { + 'A' => Ok(['B', 'C', 'D', 'E', 'F'].contains(child)), + 'B' => Ok(['C', 'D'].contains(child)), + 'C' => Ok(['D'].contains(child)), + 'E' => Ok(['F'].contains(child)), + 'D' | 'F' => Ok(false), + _ => unreachable!(), + } + } + + // A(t) --- B(f) --- C(t) --- D(f) + // \-- E(t) --- F(f) + let mut tree: ForkTree = ForkTree::new(); + tree.import('A', 1, true, &is_descendent_of).unwrap(); + tree.import('B', 2, false, &is_descendent_of).unwrap(); + tree.import('C', 3, true, &is_descendent_of).unwrap(); + tree.import('D', 4, false, &is_descendent_of).unwrap(); + + tree.import('E', 2, true, &is_descendent_of).unwrap(); + tree.import('F', 3, false, &is_descendent_of).unwrap(); + + let path = tree + .find_node_index_where(&'D', &4, &is_descendent_of, &|&value| !value) + .unwrap() + .unwrap(); + assert_eq!(path, [0, 0]); + + let path = tree + .find_node_index_where(&'D', &4, &is_descendent_of, &|&value| value) + .unwrap() + .unwrap(); + assert_eq!(path, [0, 0, 0]); + + let path = tree + .find_node_index_where(&'F', &3, &is_descendent_of, &|&value| !value) + .unwrap(); + assert_eq!(path, None); + + let path = tree + .find_node_index_where(&'F', &3, &is_descendent_of, &|&value| value) + .unwrap() + .unwrap(); + assert_eq!(path, [0, 1]); + } + + #[test] + fn find_node_works() { + let (tree, is_descendent_of) = test_fork_tree(); + + let node = tree.find_node_where(&"D", &4, &is_descendent_of, &|_| true).unwrap().unwrap(); + assert_eq!((node.hash, node.number), ("C", 3)); + + let node = tree.find_node_where(&"O", &5, &is_descendent_of, &|_| true).unwrap().unwrap(); + assert_eq!((node.hash, node.number), ("L", 4)); + + let node = tree.find_node_where(&"N", &6, &is_descendent_of, &|_| true).unwrap().unwrap(); + assert_eq!((node.hash, node.number), ("M", 5)); + } } From 6f2e1390303efa8ea73e969c8db8a77ac7a02e72 Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Tue, 10 May 2022 12:18:56 -0400 Subject: [PATCH 0783/1472] sc-consensus-slots: rename `client` -> `select_chain` (#11375) * rename `client` -> `select_chain` * missed one * `cargo fmt` (only the file I touched) * Missed another one * Revert "`cargo fmt` (only the file I touched)" This reverts commit 96a0c6cd131cdc08013f7ddb9e7bf2af34ae3ee3. * `cargo fmt` (again) (only the LINES I touched) --- client/consensus/slots/src/slots.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/client/consensus/slots/src/slots.rs b/client/consensus/slots/src/slots.rs index a7b9f3e3ff611..accf24b6b4e78 100644 --- a/client/consensus/slots/src/slots.rs +++ b/client/consensus/slots/src/slots.rs @@ -91,33 +91,37 @@ impl SlotInfo { } /// A stream that returns every time there is a new slot. -pub(crate) struct Slots { +pub(crate) struct Slots { last_slot: Slot, slot_duration: Duration, inner_delay: Option, create_inherent_data_providers: IDP, - client: C, + select_chain: SC, _phantom: std::marker::PhantomData, } -impl Slots { +impl Slots { /// Create a new `Slots` stream. - pub fn new(slot_duration: Duration, create_inherent_data_providers: IDP, client: C) -> Self { + pub fn new( + slot_duration: Duration, + create_inherent_data_providers: IDP, + select_chain: SC, + ) -> Self { Slots { last_slot: 0.into(), slot_duration, inner_delay: None, create_inherent_data_providers, - client, + select_chain, _phantom: Default::default(), } } } -impl Slots +impl Slots where Block: BlockT, - C: SelectChain, + SC: SelectChain, IDP: CreateInherentDataProviders, IDP::InherentDataProviders: crate::InherentDataProviderExt, { @@ -145,7 +149,7 @@ where let ends_at = Instant::now() + ends_in; - let chain_head = match self.client.best_chain().await { + let chain_head = match self.select_chain.best_chain().await { Ok(x) => x, Err(e) => { log::warn!( From 7143e6511730c7d3cbb98c04155628366f6d0ae6 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 10 May 2022 18:20:42 +0200 Subject: [PATCH 0784/1472] update Cargo.lock (#11384) --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 928be6b18fc15..1c73e59ff10d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11096,7 +11096,7 @@ dependencies = [ "chrono", "lazy_static", "matchers", - "parking_lot 0.9.0", + "parking_lot 0.11.2", "regex", "serde", "serde_json", From 1a5ad4c988c47484fd582e6159ed52a47919247a Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 10 May 2022 17:34:59 +0100 Subject: [PATCH 0785/1472] fix a few more things with nomination pools (#11373) * fix a few more things with nomination pools * add bench * use weight fn * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * allow real root to also set roles * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * move out of the closure * fix a few more things Co-authored-by: Parity Bot Co-authored-by: Oliver Tale-Yazdi --- .../nomination-pools/benchmarking/src/lib.rs | 22 +++ frame/nomination-pools/src/lib.rs | 81 ++++++++- frame/nomination-pools/src/tests.rs | 165 +++++++++++++++++- frame/nomination-pools/src/weights.rs | 83 +++++---- primitives/staking/src/lib.rs | 14 +- 5 files changed, 310 insertions(+), 55 deletions(-) diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 7ae6338e6304a..aa4c093dcf0d4 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -631,6 +631,28 @@ frame_benchmarking::benchmarks! { assert_eq!(MaxPoolMembersPerPool::::get(), Some(u32::MAX)); } + update_roles { + let first_id = pallet_nomination_pools::LastPoolId::::get() + 1; + let (root, _) = create_pool_account::(0, CurrencyOf::::minimum_balance() * 2u32.into()); + let random: T::AccountId = account("but is anything really random in computers..?", 0, USER_SEED); + }:_( + Origin::Signed(root.clone()), + first_id, + Some(random.clone()), + Some(random.clone()), + Some(random.clone()) + ) verify { + assert_eq!( + pallet_nomination_pools::BondedPools::::get(first_id).unwrap().roles, + pallet_nomination_pools::PoolRoles { + depositor: root, + nominator: random.clone(), + state_toggler: random.clone(), + root: random, + }, + ) + } + impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext(), diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 8b26bad6c7df8..017eac8ee2aeb 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -348,7 +348,7 @@ pub const POINTS_TO_BALANCE_INIT_RATIO: u32 = 1; /// Possible operations on the configuration values of this pallet. #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound, PartialEq, Clone)] -pub enum ConfigOp { +pub enum ConfigOp { /// Don't change. Noop, /// Set the given value. @@ -505,11 +505,11 @@ pub enum PoolState { /// Pool adminstration roles. #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Debug, PartialEq, Clone)] pub struct PoolRoles { - /// Creates the pool and is the initial member. They can only leave the pool once all - /// other members have left. Once they fully leave, the pool is destroyed. + /// Creates the pool and is the initial member. They can only leave the pool once all other + /// members have left. Once they fully leave, the pool is destroyed. pub depositor: AccountId, - /// Can change the nominator, state-toggler, or itself and can perform any of the actions - /// the nominator or state-toggler can. + /// Can change the nominator, state-toggler, or itself and can perform any of the actions the + /// nominator or state-toggler can. pub root: AccountId, /// Can select which validators the pool nominates. pub nominator: AccountId, @@ -665,6 +665,10 @@ impl BondedPool { .saturating_sub(T::StakingInterface::active_stake(&account).unwrap_or_default()) } + fn can_update_roles(&self, who: &T::AccountId) -> bool { + *who == self.roles.root + } + fn can_nominate(&self, who: &T::AccountId) -> bool { *who == self.roles.root || *who == self.roles.nominator } @@ -1141,9 +1145,14 @@ pub mod pallet { pub type Metadata = CountedStorageMap<_, Twox64Concat, PoolId, BoundedVec, ValueQuery>; + /// Ever increasing number of all pools created so far. #[pallet::storage] pub type LastPoolId = StorageValue<_, u32, ValueQuery>; + /// A reverse lookup from the pool's account id to its id. + /// + /// This is only used for slashing. In all other instances, the pool id is used, and the + /// accounts are deterministically derived from it. #[pallet::storage] pub type ReversePoolIdLookup = CountedStorageMap<_, Twox64Concat, T::AccountId, PoolId, OptionQuery>; @@ -1209,6 +1218,8 @@ pub mod pallet { /// /// The removal can be voluntary (withdrawn all unbonded funds) or involuntary (kicked). MemberRemoved { pool_id: PoolId, member: T::AccountId }, + /// The roles of a pool have been updated to the given new roles. + RolesUpdated { root: T::AccountId, state_toggler: T::AccountId, nominator: T::AccountId }, } #[pallet::error] @@ -1436,9 +1447,9 @@ pub mod pallet { bonded_pool.ok_to_unbond_with(&caller, &member_account, &member, unbonding_points)?; - // Claim the the payout prior to unbonding. Once the user is unbonding their points - // no longer exist in the bonded pool and thus they can no longer claim their payouts. - // It is not strictly necessary to claim the rewards, but we do it here for UX. + // Claim the the payout prior to unbonding. Once the user is unbonding their points no + // longer exist in the bonded pool and thus they can no longer claim their payouts. It + // is not strictly necessary to claim the rewards, but we do it here for UX. Self::do_reward_payout( &member_account, &mut member, @@ -1827,6 +1838,60 @@ pub mod pallet { Ok(()) } + + /// Update the roles of the pool. + /// + /// The root is the only entity that can change any of the roles, including itself, + /// excluding the depositor, who can never change. + /// + /// It emits an event, notifying UIs of the role change. This event is quite relevant to + /// most pool members and they should be informed of changes to pool roles. + #[pallet::weight(T::WeightInfo::update_roles())] + pub fn update_roles( + origin: OriginFor, + pool_id: PoolId, + root: Option, + nominator: Option, + state_toggler: Option, + ) -> DispatchResult { + let o1 = origin; + let o2 = o1.clone(); + + let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + let is_pool_root = || -> Result<(), sp_runtime::DispatchError> { + let who = ensure_signed(o1)?; + ensure!(bonded_pool.can_update_roles(&who), Error::::DoesNotHavePermission); + Ok(()) + }; + let is_root = || -> Result<(), sp_runtime::DispatchError> { + ensure_root(o2)?; + Ok(()) + }; + + let _ = is_root().or_else(|_| is_pool_root())?; + + match root { + None => (), + Some(v) => bonded_pool.roles.root = v, + }; + match nominator { + None => (), + Some(v) => bonded_pool.roles.nominator = v, + }; + match state_toggler { + None => (), + Some(v) => bonded_pool.roles.state_toggler = v, + }; + + Self::deposit_event(Event::::RolesUpdated { + root: bonded_pool.roles.root.clone(), + nominator: bonded_pool.roles.nominator.clone(), + state_toggler: bonded_pool.roles.state_toggler.clone(), + }); + + bonded_pool.put(); + Ok(()) + } } #[pallet::hooks] diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index ecda162c6bdbc..f39b5c92375c4 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -69,7 +69,20 @@ fn test_setup_works() { assert_eq!( PoolMembers::::get(10).unwrap(), PoolMember:: { pool_id: last_pool, points: 10, ..Default::default() } - ) + ); + + let bonded_account = Pools::create_bonded_account(last_pool); + let reward_account = Pools::create_reward_account(last_pool); + + // the bonded_account should be bonded by the depositor's funds. + assert_eq!(StakingMock::active_stake(&bonded_account).unwrap(), 10); + assert_eq!(StakingMock::total_stake(&bonded_account).unwrap(), 10); + + // but not nominating yet. + assert!(Nominations::get().is_empty()); + + // reward account should have an initial ED in it. + assert_eq!(Balances::free_balance(&reward_account), Balances::minimum_balance()); }) } @@ -2082,7 +2095,7 @@ mod unbond { // depositor can unbond inly up to `MinCreateBond`. #[test] fn depositor_permissioned_partial_unbond() { - ExtBuilder::default().ed(1).add_members(vec![(100, 100)]).build_and_execute(|| { + ExtBuilder::default().ed(1).build_and_execute(|| { // given assert_eq!(MinCreateBond::::get(), 2); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 10); @@ -2098,12 +2111,12 @@ mod unbond { Pools::unbond(Origin::signed(10), 10, 6), Error::::NotOnlyPoolMember ); + assert_eq!( pool_events_since_last_call(), vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, Event::Unbonded { member: 10, pool_id: 1, amount: 3 } ] ); @@ -2113,7 +2126,7 @@ mod unbond { // same as above, but the pool is slashed and therefore the depositor cannot partially unbond. #[test] fn depositor_permissioned_partial_unbond_slashed() { - ExtBuilder::default().ed(1).add_members(vec![(100, 100)]).build_and_execute(|| { + ExtBuilder::default().ed(1).build_and_execute(|| { // given assert_eq!(MinCreateBond::::get(), 2); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 10); @@ -2132,11 +2145,75 @@ mod unbond { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true } ] ); }); } + + #[test] + fn every_unbonding_triggers_payout() { + ExtBuilder::default().build_and_execute(|| { + let initial_reward_account = Balances::free_balance(Pools::create_reward_account(1)); + assert_eq!(initial_reward_account, Balances::minimum_balance()); + assert_eq!(initial_reward_account, 5); + + // set the pool to destroying so that depositor can leave. + unsafe_set_state(1, PoolState::Destroying).unwrap(); + + Balances::make_free_balance_be( + &Pools::create_reward_account(1), + 2 * Balances::minimum_balance(), + ); + + assert_ok!(Pools::unbond(Origin::signed(10), 10, 2)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + // exactly equal to ed, all that can be claimed. + Event::PaidOut { member: 10, pool_id: 1, payout: 5 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 2 } + ] + ); + + CurrentEra::set(1); + Balances::make_free_balance_be( + &Pools::create_reward_account(1), + 2 * Balances::minimum_balance(), + ); + + assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_eq!( + pool_events_since_last_call(), + vec![ + // exactly equal to ed, all that can be claimed. + Event::PaidOut { member: 10, pool_id: 1, payout: 5 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 3 } + ] + ); + + CurrentEra::set(2); + Balances::make_free_balance_be( + &Pools::create_reward_account(1), + 2 * Balances::minimum_balance(), + ); + + assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 5 }, + Event::Unbonded { member: 10, pool_id: 1, amount: 5 } + ] + ); + + assert_eq!( + PoolMembers::::get(10).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 2, 4 => 3, 5 => 5) + ); + }); + } } mod pool_withdraw_unbonded { @@ -3504,3 +3581,81 @@ mod bond_extra { }) } } + +mod update_roles { + use super::*; + + #[test] + fn update_roles_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!( + BondedPools::::get(1).unwrap().roles, + PoolRoles { depositor: 10, root: 900, nominator: 901, state_toggler: 902 }, + ); + + // non-existent pools + assert_noop!( + Pools::update_roles(Origin::signed(1), 2, Some(5), Some(6), Some(7)), + Error::::PoolNotFound, + ); + + // depositor cannot change roles. + assert_noop!( + Pools::update_roles(Origin::signed(1), 1, Some(5), Some(6), Some(7)), + Error::::DoesNotHavePermission, + ); + + // nominator cannot change roles. + assert_noop!( + Pools::update_roles(Origin::signed(901), 1, Some(5), Some(6), Some(7)), + Error::::DoesNotHavePermission, + ); + // state-toggler + assert_noop!( + Pools::update_roles(Origin::signed(902), 1, Some(5), Some(6), Some(7)), + Error::::DoesNotHavePermission, + ); + + // but root can + assert_ok!(Pools::update_roles(Origin::signed(900), 1, Some(5), Some(6), Some(7))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::RolesUpdated { root: 5, state_toggler: 7, nominator: 6 } + ] + ); + assert_eq!( + BondedPools::::get(1).unwrap().roles, + PoolRoles { depositor: 10, root: 5, nominator: 6, state_toggler: 7 }, + ); + + // also root origin can + assert_ok!(Pools::update_roles(Origin::root(), 1, Some(1), Some(2), Some(3))); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::RolesUpdated { root: 1, state_toggler: 3, nominator: 2 }] + ); + assert_eq!( + BondedPools::::get(1).unwrap().roles, + PoolRoles { depositor: 10, root: 1, nominator: 2, state_toggler: 3 }, + ); + + // None is a noop + assert_ok!(Pools::update_roles(Origin::root(), 1, Some(11), None, None)); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::RolesUpdated { root: 11, state_toggler: 3, nominator: 2 }] + ); + + assert_eq!( + BondedPools::::get(1).unwrap().roles, + PoolRoles { depositor: 10, root: 11, nominator: 2, state_toggler: 3 }, + ); + }) + } +} diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index 4bd291f5276f8..0b2a84ddd2ac3 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-04-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -58,6 +58,7 @@ pub trait WeightInfo { fn set_state() -> Weight; fn set_metadata(n: u32, ) -> Weight; fn set_configs() -> Weight; + fn update_roles() -> Weight; } /// Weights for pallet_nomination_pools using the Substrate node and recommended hardware. @@ -78,7 +79,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (117_870_000 as Weight) + (119_253_000 as Weight) .saturating_add(T::DbWeight::get().reads(18 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) } @@ -93,7 +94,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (110_176_000 as Weight) + (110_157_000 as Weight) .saturating_add(T::DbWeight::get().reads(14 as Weight)) .saturating_add(T::DbWeight::get().writes(13 as Weight)) } @@ -108,7 +109,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:2 w:2) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (122_829_000 as Weight) + (124_003_000 as Weight) .saturating_add(T::DbWeight::get().reads(14 as Weight)) .saturating_add(T::DbWeight::get().writes(13 as Weight)) } @@ -118,7 +119,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (50_094_000 as Weight) + (51_767_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -138,7 +139,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (119_288_000 as Weight) + (116_959_000 as Weight) .saturating_add(T::DbWeight::get().reads(19 as Weight)) .saturating_add(T::DbWeight::get().writes(14 as Weight)) } @@ -148,9 +149,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (39_986_000 as Weight) + (41_124_000 as Weight) // Standard Error: 0 - .saturating_add((50_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -164,9 +165,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (76_897_000 as Weight) + (80_654_000 as Weight) // Standard Error: 0 - .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((50_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(9 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -191,7 +192,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (135_837_000 as Weight) + (140_296_000 as Weight) .saturating_add(T::DbWeight::get().reads(20 as Weight)) .saturating_add(T::DbWeight::get().writes(17 as Weight)) } @@ -219,7 +220,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (129_265_000 as Weight) + (130_543_000 as Weight) .saturating_add(T::DbWeight::get().reads(23 as Weight)) .saturating_add(T::DbWeight::get().writes(16 as Weight)) } @@ -236,9 +237,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (45_546_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_075_000 as Weight).saturating_mul(n as Weight)) + (46_152_000 as Weight) + // Standard Error: 15_000 + .saturating_add((2_114_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(5 as Weight)) @@ -246,7 +247,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (23_256_000 as Weight) + (23_544_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -254,7 +255,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) fn set_metadata(n: u32, ) -> Weight { - (10_893_000 as Weight) + (11_032_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -266,9 +267,15 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (2_793_000 as Weight) + (2_910_000 as Weight) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } + // Storage: NominationPools BondedPools (r:1 w:1) + fn update_roles() -> Weight { + (18_608_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } } // For backwards compatibility and tests @@ -288,7 +295,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (117_870_000 as Weight) + (119_253_000 as Weight) .saturating_add(RocksDbWeight::get().reads(18 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) } @@ -303,7 +310,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (110_176_000 as Weight) + (110_157_000 as Weight) .saturating_add(RocksDbWeight::get().reads(14 as Weight)) .saturating_add(RocksDbWeight::get().writes(13 as Weight)) } @@ -318,7 +325,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:2 w:2) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (122_829_000 as Weight) + (124_003_000 as Weight) .saturating_add(RocksDbWeight::get().reads(14 as Weight)) .saturating_add(RocksDbWeight::get().writes(13 as Weight)) } @@ -328,7 +335,7 @@ impl WeightInfo for () { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (50_094_000 as Weight) + (51_767_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -348,7 +355,7 @@ impl WeightInfo for () { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (119_288_000 as Weight) + (116_959_000 as Weight) .saturating_add(RocksDbWeight::get().reads(19 as Weight)) .saturating_add(RocksDbWeight::get().writes(14 as Weight)) } @@ -358,9 +365,9 @@ impl WeightInfo for () { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (39_986_000 as Weight) + (41_124_000 as Weight) // Standard Error: 0 - .saturating_add((50_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -374,9 +381,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (76_897_000 as Weight) + (80_654_000 as Weight) // Standard Error: 0 - .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((50_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(9 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -401,7 +408,7 @@ impl WeightInfo for () { // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (135_837_000 as Weight) + (140_296_000 as Weight) .saturating_add(RocksDbWeight::get().reads(20 as Weight)) .saturating_add(RocksDbWeight::get().writes(17 as Weight)) } @@ -429,7 +436,7 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (129_265_000 as Weight) + (130_543_000 as Weight) .saturating_add(RocksDbWeight::get().reads(23 as Weight)) .saturating_add(RocksDbWeight::get().writes(16 as Weight)) } @@ -446,9 +453,9 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (45_546_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_075_000 as Weight).saturating_mul(n as Weight)) + (46_152_000 as Weight) + // Standard Error: 15_000 + .saturating_add((2_114_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) @@ -456,7 +463,7 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (23_256_000 as Weight) + (23_544_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -464,7 +471,7 @@ impl WeightInfo for () { // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) fn set_metadata(n: u32, ) -> Weight { - (10_893_000 as Weight) + (11_032_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -476,7 +483,13 @@ impl WeightInfo for () { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (2_793_000 as Weight) + (2_910_000 as Weight) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } + // Storage: NominationPools BondedPools (r:1 w:1) + fn update_roles() -> Weight { + (18_608_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } } diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index 7ff0808af0a63..a2a6432485be8 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -80,10 +80,10 @@ pub trait StakingInterface { /// This should be the latest planned era that the staking system knows about. fn current_era() -> EraIndex; - /// The amount of active stake that `controller` has in the staking system. - fn active_stake(controller: &Self::AccountId) -> Option; + /// The amount of active stake that `stash` has in the staking system. + fn active_stake(stash: &Self::AccountId) -> Option; - /// The total stake that `controller` has in the staking system. This includes the + /// The total stake that `stash` has in the staking system. This includes the /// [`Self::active_stake`], and any funds currently in the process of unbonding via /// [`Self::unbond`]. /// @@ -91,7 +91,7 @@ pub trait StakingInterface { /// /// This is only guaranteed to reflect the amount locked by the staking system. If there are /// non-staking locks on the bonded pair's balance this may not be accurate. - fn total_stake(controller: &Self::AccountId) -> Option; + fn total_stake(stash: &Self::AccountId) -> Option; /// Bond (lock) `value` of `stash`'s balance. `controller` will be set as the account /// controlling `stash`. This creates what is referred to as "bonded pair". @@ -111,7 +111,7 @@ pub trait StakingInterface { /// Bond some extra amount in the _Stash_'s free balance against the active bonded balance of /// the account. The amount extra actually bonded will never be more than the _Stash_'s free /// balance. - fn bond_extra(controller: Self::AccountId, extra: Self::Balance) -> DispatchResult; + fn bond_extra(stash: Self::AccountId, extra: Self::Balance) -> DispatchResult; /// Schedule a portion of the active bonded balance to be unlocked at era /// [Self::current_era] + [`Self::bonding_duration`]. @@ -122,11 +122,11 @@ pub trait StakingInterface { /// The amount of times this can be successfully called is limited based on how many distinct /// eras funds are schedule to unlock in. Calling [`Self::withdraw_unbonded`] after some unlock /// schedules have reached their unlocking era should allow more calls to this function. - fn unbond(controller: Self::AccountId, value: Self::Balance) -> DispatchResult; + fn unbond(stash: Self::AccountId, value: Self::Balance) -> DispatchResult; /// Unlock any funds schedule to unlock before or at the current era. fn withdraw_unbonded( - controller: Self::AccountId, + stash: Self::AccountId, num_slashing_spans: u32, ) -> Result; } From 34737a23d2a918693185df5ba8612f6f18e5b219 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 11 May 2022 11:01:02 +0200 Subject: [PATCH 0786/1472] [ci] Divide .gitlab-ci.yml into several files (#11333) * rebase * update Cargo.lock * revert Cargo.lock * fix Cargo.lock from 11384 --- .gitlab-ci.yml | 645 ++----------------------- scripts/ci/gitlab/pipeline/build.yml | 121 +++++ scripts/ci/gitlab/pipeline/check.yml | 54 +++ scripts/ci/gitlab/pipeline/publish.yml | 149 ++++++ scripts/ci/gitlab/pipeline/test.yml | 271 +++++++++++ 5 files changed, 633 insertions(+), 607 deletions(-) create mode 100644 scripts/ci/gitlab/pipeline/build.yml create mode 100644 scripts/ci/gitlab/pipeline/check.yml create mode 100644 scripts/ci/gitlab/pipeline/publish.yml create mode 100644 scripts/ci/gitlab/pipeline/test.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 224d5d5f0ef3f..b0af4cda995ad 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,15 @@ # substrate # # pipelines can be triggered manually in the web - +# +# Currently the file is divided into subfiles. Each stage has a different file which +# can be found here: scripts/ci/gitlab/pipeline/.yml +# +# Instead of YAML anchors "extends" is used. +# Useful links: +# https://docs.gitlab.com/ee/ci/yaml/index.html#extends +# https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html#reference-tags +# # SAMPLE JOB TEMPLATE - This is not a complete example but is enough to build a # simple CI job. For full documentation, visit https://docs.gitlab.com/ee/ci/yaml/ # @@ -50,7 +58,7 @@ default: interruptible: true cache: {} -.collect-artifacts: &collect-artifacts +.collect-artifacts: artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" when: on_success @@ -58,7 +66,7 @@ default: paths: - artifacts/ -.collect-artifacts-short: &collect-artifacts-short +.collect-artifacts-short: artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" when: on_success @@ -66,25 +74,26 @@ default: paths: - artifacts/ -.kubernetes-env: &kubernetes-env +.kubernetes-env: + image: "${CI_IMAGE}" tags: - kubernetes-parity-build .rust-info-script: &rust-info-script - - rustup show - - cargo --version - - rustup +nightly show - - cargo +nightly --version - - sccache -s + script: + - rustup show + - cargo --version + - rustup +nightly show + - cargo +nightly --version -.docker-env: &docker-env +.docker-env: image: "${CI_IMAGE}" before_script: - - *rust-info-script + - !reference [.rust-info-script, script] tags: - linux-docker -.test-refs: &test-refs +.test-refs: rules: - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" @@ -92,7 +101,7 @@ default: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 -.test-refs-no-trigger: &test-refs-no-trigger +.test-refs-no-trigger: rules: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never @@ -103,7 +112,7 @@ default: - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ -.test-refs-no-trigger-prs-only: &test-refs-no-trigger-prs-only +.test-refs-no-trigger-prs-only: rules: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never @@ -111,7 +120,7 @@ default: - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs -.test-refs-wasmer-sandbox: &test-refs-wasmer-sandbox +.test-refs-wasmer-sandbox: rules: - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" @@ -131,7 +140,7 @@ default: - frame/contracts/**/* - primitives/sandbox/**/* -.build-refs: &build-refs +.build-refs: rules: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never @@ -140,35 +149,17 @@ default: - if: $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 -.nightly-pipeline: &nightly-pipeline +.nightly-pipeline: rules: # this job runs only on nightly pipeline with the mentioned variable, against `master` branch - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "schedule" && $PIPELINE == "nightly" -.merge-ref-into-master-script: &merge-ref-into-master-script - - if [ $CI_COMMIT_REF_NAME != "master" ]; then - git fetch origin +master:master; - git fetch origin +$CI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME; - git checkout master; - git config user.email "ci@gitlab.parity.io"; - git merge $CI_COMMIT_REF_NAME --verbose --no-edit; - fi - -.cargo-check-benches-script: &cargo-check-benches-script - - mkdir -p ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA - - SKIP_WASM_BUILD=1 time cargo +nightly check --benches --all - - 'cargo run --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json - | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::native::sr25519::transfer_keep_alive::paritydb::small.json' - - 'cargo run --release -p node-bench -- ::trie::read::small --json - | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json' - - sccache -s - - #### stage: .pre skip-if-draft: - image: paritytech/tools:latest - <<: *kubernetes-env + extends: .kubernetes-env + variables: + CI_IMAGE: "paritytech/tools:latest" stage: .pre rules: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs @@ -178,576 +169,16 @@ skip-if-draft: - echo "pipeline source is ${CI_PIPELINE_SOURCE}" - ./scripts/ci/gitlab/skip_if_draft.sh -#### stage: check +include: + # check jobs + - scripts/ci/gitlab/pipeline/check.yml + # tests jobs + - scripts/ci/gitlab/pipeline/test.yml + # build jobs + - scripts/ci/gitlab/pipeline/build.yml + # publish jobs + - scripts/ci/gitlab/pipeline/publish.yml -check-runtime: - stage: check - image: paritytech/tools:latest - <<: *kubernetes-env - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - variables: - <<: *default-vars - GITLAB_API: "https://gitlab.parity.io/api/v4" - GITHUB_API_PROJECT: "parity%2Finfrastructure%2Fgithub-api" - script: - - ./scripts/ci/gitlab/check_runtime.sh - allow_failure: true - -check-signed-tag: - stage: check - image: paritytech/tools:latest - <<: *kubernetes-env - rules: - - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - script: - - ./scripts/ci/gitlab/check_signed.sh - -test-dependency-rules: - stage: check - image: paritytech/tools:latest - <<: *kubernetes-env - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - script: - - ./scripts/ci/gitlab/ensure-deps.sh - -test-prometheus-alerting-rules: - stage: check - image: paritytech/tools:latest - <<: *kubernetes-env - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_COMMIT_BRANCH - changes: - - .gitlab-ci.yml - - ./scripts/ci/monitoring/**/* - script: - - promtool check rules ./scripts/ci/monitoring/alerting-rules/alerting-rules.yaml - - cat ./scripts/ci/monitoring/alerting-rules/alerting-rules.yaml | - promtool test rules ./scripts/ci/monitoring/alerting-rules/alerting-rule-tests.yaml - -#### stage: test - -cargo-deny: - stage: test - <<: *docker-env - <<: *nightly-pipeline - script: - - cargo deny check --hide-inclusion-graph -c ./scripts/ci/deny.toml - after_script: - - echo "___The complete log is in the artifacts___" - - cargo deny check -c ./scripts/ci/deny.toml 2> deny.log - artifacts: - name: $CI_COMMIT_SHORT_SHA - expire_in: 3 days - when: always - paths: - - deny.log - # FIXME: Temporarily allow to fail. - allow_failure: true - -cargo-fmt: - stage: test - <<: *docker-env - <<: *test-refs - script: - - cargo +nightly fmt --all -- --check - -cargo-clippy: - stage: test - <<: *docker-env - <<: *test-refs - script: - - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo +nightly clippy --all-targets - -cargo-check-nixos: - stage: test - <<: *docker-env - <<: *test-refs - before_script: [] - # Don't use CI_IMAGE here because it breaks nightly checks of paritytech/ci-linux image - image: nixos/nix - variables: - SNAP: "DUMMY" - WS_API: "DUMMY" - script: - - nix-channel --update - - nix-shell shell.nix - - nix-shell --run "cargo check --workspace --all-targets --all-features" - -cargo-check-benches: - stage: test - <<: *docker-env - <<: *test-refs - <<: *collect-artifacts - before_script: - # merges in the master branch on PRs - - *merge-ref-into-master-script - - *rust-info-script - script: - - *cargo-check-benches-script - tags: - - linux-docker-benches - -node-bench-regression-guard: - # it's not belong to `build` semantically, but dag jobs can't depend on each other - # within the single stage - https://gitlab.com/gitlab-org/gitlab/-/issues/30632 - # more: https://github.com/paritytech/substrate/pull/8519#discussion_r608012402 - stage: build - <<: *docker-env - <<: *test-refs-no-trigger-prs-only - needs: - # this is a DAG - - job: cargo-check-benches - artifacts: true - # this does not like a DAG, just polls the artifact - - project: $CI_PROJECT_PATH - job: cargo-check-benches - ref: master - artifacts: true - variables: - CI_IMAGE: "paritytech/node-bench-regression-guard:latest" - before_script: [""] - script: - - echo "------- IMPORTANT -------" - - echo "node-bench-regression-guard depends on the results of a cargo-check-benches job" - - echo "In case of this job failure, check your pipeline's cargo-check-benches" - - 'node-bench-regression-guard --reference artifacts/benches/master-* - --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA' - -cargo-check-subkey: - stage: test - <<: *docker-env - <<: *test-refs - script: - - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo check --release - - sccache -s - -cargo-check-try-runtime: - stage: test - <<: *docker-env - <<: *test-refs - script: - - time cargo check --features try-runtime - - sccache -s - -cargo-check-wasmer-sandbox: - stage: test - <<: *docker-env - <<: *test-refs - script: - - time cargo check --features wasmer-sandbox - - sccache -s - -test-deterministic-wasm: - stage: test - <<: *docker-env - <<: *test-refs - variables: - <<: *default-vars - WASM_BUILD_NO_COLOR: 1 - script: - # build runtime - - cargo build --verbose --release -p node-runtime - # make checksum - - sha256sum ./target/release/wbuild/node-runtime/target/wasm32-unknown-unknown/release/node_runtime.wasm > checksum.sha256 - # clean up – FIXME: can we reuse some of the artifacts? - - cargo clean - # build again - - cargo build --verbose --release -p node-runtime - # confirm checksum - - sha256sum -c ./checksum.sha256 - - sccache -s - -test-linux-stable: &test-linux - stage: test - <<: *docker-env - <<: *test-refs - variables: - <<: *default-vars - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - RUST_BACKTRACE: 1 - WASM_BUILD_NO_COLOR: 1 - # Ensure we run the UI tests. - RUN_UI_TESTS: 1 - script: - # this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests - - time cargo test --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml - - time cargo test -p frame-support-test --features=conditional-storage,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec - - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout - - sccache -s - -test-frame-examples-compile-to-wasm: - # into one job - stage: test - <<: *docker-env - <<: *test-refs - variables: - <<: *default-vars - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y" - RUST_BACKTRACE: 1 - script: - - cd ./frame/examples/offchain-worker/ - - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features - - cd ../basic - - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features - - sccache -s - -test-linux-stable-int: - <<: *test-linux - stage: test - script: - - echo "___Logs will be partly shown at the end in case of failure.___" - - echo "___Full log will be saved to the job artifacts only in case of failure.___" - - WASM_BUILD_NO_COLOR=1 - RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace - time cargo test -p node-cli --release --verbose --locked -- --ignored - &> ${CI_COMMIT_SHORT_SHA}_int_failure.log - - sccache -s - after_script: - - awk '/FAILED|^error\[/,0' ${CI_COMMIT_SHORT_SHA}_int_failure.log - artifacts: - name: $CI_COMMIT_SHORT_SHA - when: on_failure - expire_in: 3 days - paths: - - ${CI_COMMIT_SHORT_SHA}_int_failure.log - -check-tracing: - stage: test - <<: *docker-env - <<: *test-refs - script: - # with-tracing must be explicitly activated, we run a test to ensure this works as expected in both cases - - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features - - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing - - sccache -s - -test-full-crypto-feature: - stage: test - <<: *docker-env - <<: *test-refs - variables: - <<: *default-vars - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y" - RUST_BACKTRACE: 1 - script: - - cd primitives/core/ - - time cargo +nightly build --verbose --no-default-features --features full_crypto - - cd ../application-crypto - - time cargo +nightly build --verbose --no-default-features --features full_crypto - - sccache -s - -test-wasmer-sandbox: - stage: test - <<: *docker-env - <<: *test-refs-wasmer-sandbox - variables: - <<: *default-vars - script: - - time cargo test --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests - - sccache -s - -cargo-check-macos: - stage: test - # shell runner on mac ignores the image set in *docker-env - <<: *docker-env - <<: *test-refs-no-trigger - script: - - SKIP_WASM_BUILD=1 time cargo check --release - - sccache -s - tags: - - osx - -#### stage: build - -# PIPELINE_SCRIPTS_TAG can be found in the project variables - -.check-dependent-project: &check-dependent-project - stage: build - <<: *docker-env - <<: *test-refs-no-trigger-prs-only - script: - - git clone - --depth=1 - "--branch=$PIPELINE_SCRIPTS_TAG" - https://github.com/paritytech/pipeline-scripts - - ./pipeline-scripts/check_dependent_project.sh - --org paritytech - --dependent-repo "$DEPENDENT_REPO" - --github-api-token "$GITHUB_PR_TOKEN" - --extra-dependencies "$EXTRA_DEPENDENCIES" - --companion-overrides "$COMPANION_OVERRIDES" - -# Individual jobs are set up for each dependent project so that they can be ran in parallel. -# Arguably we could generate a job for each companion in the PR's description using Gitlab's -# parent-child pipelines but that's more complicated. - -check-dependent-polkadot: - <<: *check-dependent-project - variables: - DEPENDENT_REPO: polkadot - COMPANION_OVERRIDES: | - substrate: polkadot-v* - polkadot: release-v* - -check-dependent-cumulus: - <<: *check-dependent-project - variables: - DEPENDENT_REPO: cumulus - EXTRA_DEPENDENCIES: polkadot - COMPANION_OVERRIDES: | - substrate: polkadot-v* - cumulus: polkadot-v* - - -build-linux-substrate: - stage: build - <<: *collect-artifacts - <<: *docker-env - <<: *build-refs - needs: - - job: test-linux-stable - artifacts: false - before_script: - - mkdir -p ./artifacts/substrate/ - script: - - WASM_BUILD_NO_COLOR=1 time cargo build --release --verbose - - mv ./target/release/substrate ./artifacts/substrate/. - - echo -n "Substrate version = " - - if [ "${CI_COMMIT_TAG}" ]; then - echo "${CI_COMMIT_TAG}" | tee ./artifacts/substrate/VERSION; - else - ./artifacts/substrate/substrate --version | - cut -d ' ' -f 2 | tee ./artifacts/substrate/VERSION; - fi - - sha256sum ./artifacts/substrate/substrate | tee ./artifacts/substrate/substrate.sha256 - - cp -r ./scripts/ci/docker/substrate.Dockerfile ./artifacts/substrate/ - - printf '\n# building node-template\n\n' - - ./scripts/ci/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz - -build-linux-subkey: &build-subkey - stage: build - <<: *collect-artifacts - <<: *docker-env - <<: *build-refs - needs: - - job: cargo-check-subkey - artifacts: false - before_script: - - mkdir -p ./artifacts/subkey - script: - - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo build --release --verbose - - cd - - - mv ./target/release/subkey ./artifacts/subkey/. - - echo -n "Subkey version = " - - ./artifacts/subkey/subkey --version | - sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | - tee ./artifacts/subkey/VERSION; - - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 - - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ - - sccache -s - -build-macos-subkey: - <<: *build-subkey - tags: - - osx - -check-rustdoc: - stage: test - <<: *docker-env - <<: *test-refs - variables: - <<: *default-vars - SKIP_WASM_BUILD: 1 - RUSTDOCFLAGS: "-Dwarnings" - script: - - time cargo +nightly doc --workspace --all-features --verbose --no-deps - - sccache -s - -build-rustdoc: - stage: build - <<: *docker-env - <<: *test-refs - variables: - <<: *default-vars - SKIP_WASM_BUILD: 1 - DOC_INDEX_PAGE: "sc_service/index.html" # default redirected page - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" - when: on_success - expire_in: 7 days - paths: - - ./crate-docs/ - script: - - time cargo +nightly doc --workspace --all-features --verbose - - rm -f ./target/doc/.lock - - mv ./target/doc ./crate-docs - # FIXME: remove me after CI image gets nonroot - - chown -R nonroot:nonroot ./crate-docs - - echo "" > ./crate-docs/index.html - - sccache -s - -#### stage: publish - -.build-push-docker-image: &build-push-docker-image - <<: *build-refs - <<: *kubernetes-env - image: quay.io/buildah/stable - variables: &docker-build-vars - <<: *default-vars - GIT_STRATEGY: none - DOCKERFILE: $PRODUCT.Dockerfile - IMAGE_NAME: docker.io/parity/$PRODUCT - before_script: - - cd ./artifacts/$PRODUCT/ - - VERSION="$(cat ./VERSION)" - - echo "${PRODUCT} version = ${VERSION}" - - test -z "${VERSION}" && exit 1 - script: - - test "$Docker_Hub_User_Parity" -a "$Docker_Hub_Pass_Parity" || - ( echo "no docker credentials provided"; exit 1 ) - - buildah bud - --format=docker - --build-arg VCS_REF="${CI_COMMIT_SHA}" - --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" - --tag "$IMAGE_NAME:$VERSION" - --tag "$IMAGE_NAME:latest" - --file "$DOCKERFILE" . - - 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:latest" - after_script: - - buildah logout --all - - echo "SUBSTRATE_IMAGE_NAME=${IMAGE_NAME}" | tee -a ./artifacts/$PRODUCT/build.env - - IMAGE_TAG="$(cat ./artifacts/$PRODUCT/VERSION)" - - echo "SUBSTRATE_IMAGE_TAG=${IMAGE_TAG}" | tee -a ./artifacts/$PRODUCT/build.env - - cat ./artifacts/$PRODUCT/build.env - -publish-docker-substrate: - stage: publish - <<: *build-push-docker-image - <<: *build-refs - needs: - - job: build-linux-substrate - artifacts: true - variables: - <<: *docker-build-vars - PRODUCT: substrate - -publish-docker-subkey: - stage: publish - <<: *build-push-docker-image - needs: - - job: build-linux-subkey - artifacts: true - variables: - <<: *docker-build-vars - PRODUCT: subkey - -publish-s3-release: - stage: publish - <<: *build-refs - <<: *kubernetes-env - needs: - - job: build-linux-substrate - artifacts: true - - job: build-linux-subkey - artifacts: true - image: paritytech/awscli:latest - variables: - GIT_STRATEGY: none - BUCKET: "releases.parity.io" - PREFIX: "substrate/${ARCH}-${DOCKER_OS}" - script: - - aws s3 sync ./artifacts/ s3://${BUCKET}/${PREFIX}/$(cat ./artifacts/substrate/VERSION)/ - - echo "update objects in latest path" - - aws s3 sync s3://${BUCKET}/${PREFIX}/$(cat ./artifacts/substrate/VERSION)/ s3://${BUCKET}/${PREFIX}/latest/ - after_script: - - aws s3 ls s3://${BUCKET}/${PREFIX}/latest/ - --recursive --human-readable --summarize - -publish-rustdoc: - stage: publish - <<: *kubernetes-env - image: node:16 - variables: - GIT_DEPTH: 100 - RUSTDOCS_DEPLOY_REFS: "master" - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^monthly-20[0-9]{2}-[0-9]{2}.*$/ # to support: monthly-2021-09+1 - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - # `needs:` can be removed after CI image gets nonroot. In this case `needs:` stops other - # artifacts from being dowloaded by this job. - needs: - - job: build-rustdoc - artifacts: true - script: - # If $CI_COMMIT_REF_NAME doesn't match one of $RUSTDOCS_DEPLOY_REFS space-separated values, we - # exit immediately. - # Putting spaces at the front and back to ensure we are not matching just any substring, but the - # whole space-separated value. - - '[[ " ${RUSTDOCS_DEPLOY_REFS} " =~ " ${CI_COMMIT_REF_NAME} " ]] || exit 0' - # setup ssh - - eval $(ssh-agent) - - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} - - mkdir ~/.ssh && touch ~/.ssh/known_hosts - - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts - # Set git config - - git config user.email "devops-team@parity.io" - - git config user.name "${GITHUB_USER}" - - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" - - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - - git fetch origin gh-pages - # Save README and docs - - cp -r ./crate-docs/ /tmp/doc/ - - cp README.md /tmp/doc/ - # we don't need to commit changes because we copy docs to /tmp - - git checkout gh-pages --force - # Install `index-tpl-crud` and generate index.html based on RUSTDOCS_DEPLOY_REFS - - which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud - - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} - # Ensure the destination dir doesn't exist. - - rm -rf ${CI_COMMIT_REF_NAME} - - mv -f /tmp/doc ${CI_COMMIT_REF_NAME} - # Upload files - - git add --all - # `git commit` has an exit code of > 0 if there is nothing to commit. - # This causes GitLab to exit immediately and marks this job failed. - # We don't want to mark the entire job failed if there's nothing to - # publish though, hence the `|| true`. - - git commit -m "___Updated docs for ${CI_COMMIT_REF_NAME}___" || - echo "___Nothing to commit___" - - git push origin gh-pages --force - after_script: - - rm -rf .git/ ./* - -publish-draft-release: - stage: publish - image: paritytech/tools:latest - rules: - - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - script: - - ./scripts/ci/gitlab/publish_draft_release.sh - allow_failure: true #### stage: deploy diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml new file mode 100644 index 0000000000000..4ab83f53e7bdf --- /dev/null +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -0,0 +1,121 @@ +# This file is part of .gitlab-ci.yml +# Here are all jobs that are executed during "build" stage + +# PIPELINE_SCRIPTS_TAG can be found in the project variables + +.check-dependent-project: + stage: build + extends: + - .docker-env + - .test-refs-no-trigger-prs-only + script: + - git clone + --depth=1 + "--branch=$PIPELINE_SCRIPTS_TAG" + https://github.com/paritytech/pipeline-scripts + - ./pipeline-scripts/check_dependent_project.sh + --org paritytech + --dependent-repo "$DEPENDENT_REPO" + --github-api-token "$GITHUB_PR_TOKEN" + --extra-dependencies "$EXTRA_DEPENDENCIES" + --companion-overrides "$COMPANION_OVERRIDES" + +# Individual jobs are set up for each dependent project so that they can be ran in parallel. +# Arguably we could generate a job for each companion in the PR's description using Gitlab's +# parent-child pipelines but that's more complicated. + +check-dependent-polkadot: + extends: .check-dependent-project + variables: + DEPENDENT_REPO: polkadot + COMPANION_OVERRIDES: | + substrate: polkadot-v* + polkadot: release-v* + +check-dependent-cumulus: + extends: .check-dependent-project + variables: + DEPENDENT_REPO: cumulus + EXTRA_DEPENDENCIES: polkadot + COMPANION_OVERRIDES: | + substrate: polkadot-v* + polkadot: release-v* + +build-linux-substrate: + stage: build + extends: + - .collect-artifacts + - .docker-env + - .build-refs + needs: + - job: test-linux-stable + artifacts: false + before_script: + - mkdir -p ./artifacts/substrate/ + script: + - WASM_BUILD_NO_COLOR=1 time cargo build --release --verbose + - mv ./target/release/substrate ./artifacts/substrate/. + - echo -n "Substrate version = " + - if [ "${CI_COMMIT_TAG}" ]; then + echo "${CI_COMMIT_TAG}" | tee ./artifacts/substrate/VERSION; + else + ./artifacts/substrate/substrate --version | + cut -d ' ' -f 2 | tee ./artifacts/substrate/VERSION; + fi + - sha256sum ./artifacts/substrate/substrate | tee ./artifacts/substrate/substrate.sha256 + - cp -r ./scripts/ci/docker/substrate.Dockerfile ./artifacts/substrate/ + - printf '\n# building node-template\n\n' + - ./scripts/ci/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz + +.build-subkey: + stage: build + extends: + - .collect-artifacts + - .docker-env + - .build-refs + needs: + - job: cargo-check-subkey + artifacts: false + before_script: + - mkdir -p ./artifacts/subkey + script: + - cd ./bin/utils/subkey + - SKIP_WASM_BUILD=1 time cargo build --release --verbose + - cd - + - mv ./target/release/subkey ./artifacts/subkey/. + - echo -n "Subkey version = " + - ./artifacts/subkey/subkey --version | + sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | + tee ./artifacts/subkey/VERSION; + - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 + - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ + +build-subkey-linux: + extends: .build-subkey + +build-subkey-macos: + extends: .build-subkey + tags: + - osx + +build-rustdoc: + stage: build + extends: + - .docker-env + - .test-refs + variables: + SKIP_WASM_BUILD: 1 + DOC_INDEX_PAGE: "sc_service/index.html" # default redirected page + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" + when: on_success + expire_in: 7 days + paths: + - ./crate-docs/ + script: + - time cargo +nightly doc --workspace --all-features --verbose + - rm -f ./target/doc/.lock + - mv ./target/doc ./crate-docs + # FIXME: remove me after CI image gets nonroot + - chown -R nonroot:nonroot ./crate-docs + - echo "" > ./crate-docs/index.html diff --git a/scripts/ci/gitlab/pipeline/check.yml b/scripts/ci/gitlab/pipeline/check.yml new file mode 100644 index 0000000000000..3166e13313f2a --- /dev/null +++ b/scripts/ci/gitlab/pipeline/check.yml @@ -0,0 +1,54 @@ +# This file is part of .gitlab-ci.yml +# Here are all jobs that are executed during "check" stage + +check-runtime: + stage: check + extends: + - .kubernetes-env + - .test-refs-no-trigger-prs-only + variables: + CI_IMAGE: "paritytech/tools:latest" + GITLAB_API: "https://gitlab.parity.io/api/v4" + GITHUB_API_PROJECT: "parity%2Finfrastructure%2Fgithub-api" + script: + - ./scripts/ci/gitlab/check_runtime.sh + allow_failure: true + +check-signed-tag: + stage: check + extends: .kubernetes-env + variables: + CI_IMAGE: "paritytech/tools:latest" + rules: + - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + script: + - ./scripts/ci/gitlab/check_signed.sh + +test-dependency-rules: + stage: check + extends: + - .kubernetes-env + - .test-refs-no-trigger-prs-only + variables: + CI_IMAGE: "paritytech/tools:latest" + script: + - ./scripts/ci/gitlab/ensure-deps.sh + +test-prometheus-alerting-rules: + stage: check + extends: .kubernetes-env + variables: + CI_IMAGE: "paritytech/tools:latest" + rules: + - if: $CI_PIPELINE_SOURCE == "pipeline" + when: never + - if: $CI_COMMIT_BRANCH + changes: + - .gitlab-ci.yml + - ./scripts/ci/monitoring/**/* + script: + - promtool check rules ./scripts/ci/monitoring/alerting-rules/alerting-rules.yaml + - cat ./scripts/ci/monitoring/alerting-rules/alerting-rules.yaml | + promtool test rules ./scripts/ci/monitoring/alerting-rules/alerting-rule-tests.yaml + diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml new file mode 100644 index 0000000000000..c02b50e0cbc1d --- /dev/null +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -0,0 +1,149 @@ + +# This file is part of .gitlab-ci.yml +# Here are all jobs that are executed during "publish" stage + +.build-push-docker-image: + extends: + - .build-refs + - .kubernetes-env + variables: + CI_IMAGE: quay.io/buildah/stable + GIT_STRATEGY: none + DOCKERFILE: $PRODUCT.Dockerfile + IMAGE_NAME: docker.io/parity/$PRODUCT + before_script: + - cd ./artifacts/$PRODUCT/ + - VERSION="$(cat ./VERSION)" + - echo "${PRODUCT} version = ${VERSION}" + - test -z "${VERSION}" && exit 1 + script: + - test "$Docker_Hub_User_Parity" -a "$Docker_Hub_Pass_Parity" || + ( echo "no docker credentials provided"; exit 1 ) + - buildah bud + --format=docker + --build-arg VCS_REF="${CI_COMMIT_SHA}" + --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" + --tag "$IMAGE_NAME:$VERSION" + --tag "$IMAGE_NAME:latest" + --file "$DOCKERFILE" . + - 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:latest" + after_script: + - buildah logout --all + - echo "SUBSTRATE_IMAGE_NAME=${IMAGE_NAME}" | tee -a ./artifacts/$PRODUCT/build.env + - IMAGE_TAG="$(cat ./artifacts/$PRODUCT/VERSION)" + - echo "SUBSTRATE_IMAGE_TAG=${IMAGE_TAG}" | tee -a ./artifacts/$PRODUCT/build.env + - cat ./artifacts/$PRODUCT/build.env + +publish-docker-substrate: + stage: publish + extends: .build-push-docker-image + needs: + - job: build-linux-substrate + artifacts: true + variables: + PRODUCT: substrate + +publish-docker-subkey: + stage: publish + extends: .build-push-docker-image + needs: + - job: build-subkey-linux + artifacts: true + variables: + PRODUCT: subkey + +publish-s3-release: + stage: publish + extends: + - .build-refs + - .kubernetes-env + needs: + - job: build-linux-substrate + artifacts: true + - job: build-subkey-linux + artifacts: true + image: paritytech/awscli:latest + variables: + GIT_STRATEGY: none + BUCKET: "releases.parity.io" + PREFIX: "substrate/${ARCH}-${DOCKER_OS}" + script: + - aws s3 sync ./artifacts/ s3://${BUCKET}/${PREFIX}/$(cat ./artifacts/substrate/VERSION)/ + - echo "update objects in latest path" + - aws s3 sync s3://${BUCKET}/${PREFIX}/$(cat ./artifacts/substrate/VERSION)/ s3://${BUCKET}/${PREFIX}/latest/ + after_script: + - aws s3 ls s3://${BUCKET}/${PREFIX}/latest/ + --recursive --human-readable --summarize + +publish-rustdoc: + stage: publish + extends: .kubernetes-env + variables: + CI_IMAGE: node:16 + GIT_DEPTH: 100 + RUSTDOCS_DEPLOY_REFS: "master" + rules: + - if: $CI_PIPELINE_SOURCE == "pipeline" + when: never + - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master" + - if: $CI_COMMIT_REF_NAME == "master" + - if: $CI_COMMIT_REF_NAME =~ /^monthly-20[0-9]{2}-[0-9]{2}.*$/ # to support: monthly-2021-09+1 + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + # `needs:` can be removed after CI image gets nonroot. In this case `needs:` stops other + # artifacts from being dowloaded by this job. + needs: + - job: build-rustdoc + artifacts: true + script: + # If $CI_COMMIT_REF_NAME doesn't match one of $RUSTDOCS_DEPLOY_REFS space-separated values, we + # exit immediately. + # Putting spaces at the front and back to ensure we are not matching just any substring, but the + # whole space-separated value. + - '[[ " ${RUSTDOCS_DEPLOY_REFS} " =~ " ${CI_COMMIT_REF_NAME} " ]] || exit 0' + # setup ssh + - eval $(ssh-agent) + - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} + - mkdir ~/.ssh && touch ~/.ssh/known_hosts + - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts + # Set git config + - git config user.email "devops-team@parity.io" + - git config user.name "${GITHUB_USER}" + - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" + - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" + - git fetch origin gh-pages + # Save README and docs + - cp -r ./crate-docs/ /tmp/doc/ + - cp README.md /tmp/doc/ + # we don't need to commit changes because we copy docs to /tmp + - git checkout gh-pages --force + # Install `index-tpl-crud` and generate index.html based on RUSTDOCS_DEPLOY_REFS + - which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud + - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} + # Ensure the destination dir doesn't exist. + - rm -rf ${CI_COMMIT_REF_NAME} + - mv -f /tmp/doc ${CI_COMMIT_REF_NAME} + # Upload files + - git add --all + # `git commit` has an exit code of > 0 if there is nothing to commit. + # This causes GitLab to exit immediately and marks this job failed. + # We don't want to mark the entire job failed if there's nothing to + # publish though, hence the `|| true`. + - git commit -m "___Updated docs for ${CI_COMMIT_REF_NAME}___" || + echo "___Nothing to commit___" + - git push origin gh-pages --force + after_script: + - rm -rf .git/ ./* + +publish-draft-release: + stage: publish + image: paritytech/tools:latest + rules: + - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + script: + - ./scripts/ci/gitlab/publish_draft_release.sh + allow_failure: true diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml new file mode 100644 index 0000000000000..bd2c059c3ed68 --- /dev/null +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -0,0 +1,271 @@ +# This file is part of .gitlab-ci.yml +# Here are all jobs that are executed during "test" stage + +cargo-deny: + stage: test + extends: + - .docker-env + - .nightly-pipeline + script: + - cargo deny check --hide-inclusion-graph -c ./scripts/ci/deny.toml + after_script: + - echo "___The complete log is in the artifacts___" + - cargo deny check -c ./scripts/ci/deny.toml 2> deny.log + artifacts: + name: $CI_COMMIT_SHORT_SHA + expire_in: 3 days + when: always + paths: + - deny.log + # FIXME: Temporarily allow to fail. + allow_failure: true + +cargo-fmt: + stage: test + extends: + - .docker-env + - .test-refs + script: + - cargo +nightly fmt --all -- --check + +cargo-clippy: + stage: test + extends: + - .docker-env + - .test-refs + script: + - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo +nightly clippy --all-targets + +cargo-check-nixos: + stage: test + extends: + - .docker-env + - .test-refs + before_script: [] + # Don't use CI_IMAGE here because it breaks nightly checks of paritytech/ci-linux image + image: nixos/nix + variables: + SNAP: "DUMMY" + WS_API: "DUMMY" + script: + - nix-channel --update + - nix-shell shell.nix + - nix-shell --run "cargo check --workspace --all-targets --all-features" + +cargo-check-benches: + stage: test + extends: + - .docker-env + - .test-refs + - .collect-artifacts + before_script: + # merges in the master branch on PRs + - if [ $CI_COMMIT_REF_NAME != "master" ]; then + git fetch origin +master:master; + git fetch origin +$CI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME; + git checkout master; + git config user.email "ci@gitlab.parity.io"; + git merge $CI_COMMIT_REF_NAME --verbose --no-edit; + fi + - !reference [.rust-info-script, script] + script: + - mkdir -p ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA + - SKIP_WASM_BUILD=1 time cargo +nightly check --benches --all + - 'cargo run --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json + | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::native::sr25519::transfer_keep_alive::paritydb::small.json' + - 'cargo run --release -p node-bench -- ::trie::read::small --json + | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json' + - sccache -s + tags: + - linux-docker-benches + +node-bench-regression-guard: + # it's not belong to `build` semantically, but dag jobs can't depend on each other + # within the single stage - https://gitlab.com/gitlab-org/gitlab/-/issues/30632 + # more: https://github.com/paritytech/substrate/pull/8519#discussion_r608012402 + stage: build + extends: + - .docker-env + - .test-refs-no-trigger-prs-only + needs: + # this is a DAG + - job: cargo-check-benches + artifacts: true + # this does not like a DAG, just polls the artifact + - project: $CI_PROJECT_PATH + job: cargo-check-benches + ref: master + artifacts: true + variables: + CI_IMAGE: "paritytech/node-bench-regression-guard:latest" + before_script: [""] + script: + - echo "------- IMPORTANT -------" + - echo "node-bench-regression-guard depends on the results of a cargo-check-benches job" + - echo "In case of this job failure, check your pipeline's cargo-check-benches" + - 'node-bench-regression-guard --reference artifacts/benches/master-* + --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA' + +cargo-check-subkey: + stage: test + extends: + - .docker-env + - .test-refs + script: + - cd ./bin/utils/subkey + - SKIP_WASM_BUILD=1 time cargo check --release + +cargo-check-try-runtime: + stage: test + extends: + - .docker-env + - .test-refs + script: + - time cargo check --features try-runtime + +cargo-check-wasmer-sandbox: + stage: test + extends: + - .docker-env + - .test-refs + script: + - time cargo check --features wasmer-sandbox + +test-deterministic-wasm: + stage: test + extends: + - .docker-env + - .test-refs + variables: + WASM_BUILD_NO_COLOR: 1 + script: + # build runtime + - cargo build --verbose --release -p node-runtime + # make checksum + - sha256sum ./target/release/wbuild/node-runtime/target/wasm32-unknown-unknown/release/node_runtime.wasm > checksum.sha256 + # clean up – FIXME: can we reuse some of the artifacts? + - cargo clean + # build again + - cargo build --verbose --release -p node-runtime + # confirm checksum + - sha256sum -c ./checksum.sha256 + +test-linux-stable: + stage: test + extends: + - .docker-env + - .test-refs + variables: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUST_BACKTRACE: 1 + WASM_BUILD_NO_COLOR: 1 + # Ensure we run the UI tests. + RUN_UI_TESTS: 1 + script: + # this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests + - time cargo test --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml + - time cargo test -p frame-support-test --features=conditional-storage,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec + - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout + +test-frame-examples-compile-to-wasm: + # into one job + stage: test + extends: + - .docker-env + - .test-refs + variables: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y" + RUST_BACKTRACE: 1 + script: + - cd ./frame/examples/offchain-worker/ + - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features + - cd ../basic + - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features + +test-linux-stable-int: + stage: test + extends: + - .docker-env + - .test-refs + variables: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUST_BACKTRACE: 1 + WASM_BUILD_NO_COLOR: 1 + # Ensure we run the UI tests. + RUN_UI_TESTS: 1 + script: + - echo "___Logs will be partly shown at the end in case of failure.___" + - echo "___Full log will be saved to the job artifacts only in case of failure.___" + - WASM_BUILD_NO_COLOR=1 + RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace + time cargo test -p node-cli --release --verbose --locked -- --ignored + &> ${CI_COMMIT_SHORT_SHA}_int_failure.log + after_script: + - awk '/FAILED|^error\[/,0' ${CI_COMMIT_SHORT_SHA}_int_failure.log + artifacts: + name: $CI_COMMIT_SHORT_SHA + when: on_failure + expire_in: 3 days + paths: + - ${CI_COMMIT_SHORT_SHA}_int_failure.log + +check-tracing: + stage: test + extends: + - .docker-env + - .test-refs + script: + # with-tracing must be explicitly activated, we run a test to ensure this works as expected in both cases + - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features + - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing + +test-full-crypto-feature: + stage: test + extends: + - .docker-env + - .test-refs + variables: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y" + RUST_BACKTRACE: 1 + script: + - cd primitives/core/ + - time cargo +nightly build --verbose --no-default-features --features full_crypto + - cd ../application-crypto + - time cargo +nightly build --verbose --no-default-features --features full_crypto + +test-wasmer-sandbox: + stage: test + extends: + - .docker-env + - .test-refs-wasmer-sandbox + script: + - time cargo test --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests + +cargo-check-macos: + stage: test + extends: .test-refs-no-trigger + before_script: + - !reference [.rust-info-script, script] + script: + - SKIP_WASM_BUILD=1 time cargo check --release + tags: + - osx + +check-rustdoc: + stage: test + extends: + - .docker-env + - .test-refs + variables: + SKIP_WASM_BUILD: 1 + RUSTDOCFLAGS: "-Dwarnings" + script: + - time cargo +nightly doc --workspace --all-features --verbose --no-deps From 6c14be4dd82fc5079f3e33fc37160ac2200747d1 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 11 May 2022 12:39:39 +0200 Subject: [PATCH 0787/1472] jsonrpc http server: expose health endpoint (#11395) --- Cargo.lock | 36 +++++++++---------- bin/node-template/node/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/rpc/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc-servers/src/lib.rs | 1 + client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- frame/contracts/rpc/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/transaction-payment/rpc/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 4 +-- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 22 files changed, 40 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c73e59ff10d2..68272e1df9c8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3173,9 +3173,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad6f9ff3481f3069c92474b697c104502f7e9191d29b34bfa38ae9a19415f1cd" +checksum = "eae63f7fdeb51700b35e9b28bf92e8d233951590968c186ed79510b6c12fa3d9" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-server", @@ -3188,9 +3188,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4358e100faf43b2f3b7b0ecf0ad4ce3e6275fe12fda8428dedda2979751dd184" +checksum = "32feb1f2f0b5ce37a03b96a988a6dadccc3f529a2f930356bac93f13c09cf385" dependencies = [ "futures-util", "http", @@ -3209,9 +3209,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d26ab3868749d6f716345a5fbd3334a100c0709fe464bd9189ee9d78adcde" +checksum = "31e6b13067b615dd050ced7c19517a52cde490eee2c754d5447ce513f2275f7d" dependencies = [ "anyhow", "arrayvec 0.7.1", @@ -3236,9 +3236,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-server" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee87f19a7a01a55248fc4b4861d822331c4fd60151d99e7ac9c6771999132671" +checksum = "b34f1090bdc8f7f14ad8811fc84501867c23a9046ce79d49c0cd929a256c501e" dependencies = [ "futures-channel", "futures-util", @@ -3255,9 +3255,9 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75da57d54817577801c2f7a1b638610819dfd86f0470c21a2af81b06eb41ba6" +checksum = "5d8dc7a8b629e371cd5ca9d128883763ae00c5b63158ace4a6a61345726a21b7" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3267,9 +3267,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fe5a629443d17a30ff564881ba68881a710fd7eb02a538087b0bc51cb4962c" +checksum = "44f1835f131e77cd766b4dcb025873944cb1e479cd5debb639e2dc11f90df24a" dependencies = [ "anyhow", "beef", @@ -3281,9 +3281,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba31eb2b9a4b73d8833f53fe55e579516289f8b31adb6104b3dbc629755acf7d" +checksum = "9d75df866743c9733b3e2f5421e56df2f5b4630f7de39f82c44eaab350604926" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -3292,9 +3292,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-server" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "179fe584af5c0145f922c581770d073c661a514ae6cdfa5b1a0bce41fdfdf646" +checksum = "099971913436e7f6b1bc80180d4e5f014ec944660636da45d2f372c23d6308c3" dependencies = [ "futures-channel", "futures-util", @@ -11264,9 +11264,9 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "digest 0.10.3", - "rand 0.6.5", + "rand 0.8.4", "static_assertions", ] diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index ab91dc7990380..7ae343fd56dbe 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -42,7 +42,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" } # These dependencies are used for the node template's RPCs -jsonrpsee = { version = "0.12.0", features = ["server"] } +jsonrpsee = { version = "0.13.0", features = ["server"] } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index c18f2f5d1a108..b574fa948b857 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -37,7 +37,7 @@ crate-type = ["cdylib", "rlib"] clap = { version = "3.1.6", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } -jsonrpsee = { version = "0.12.0", features = ["server"] } +jsonrpsee = { version = "0.13.0", features = ["server"] } futures = "0.3.21" hex-literal = "0.3.4" log = "0.4.16" diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 9520c621d3165..ea6e8a5eb9c90 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.12.0", features = ["server"] } +jsonrpsee = { version = "0.13.0", features = ["server"] } node-primitives = { version = "2.0.0", path = "../primitives" } pallet-contracts-rpc = { version = "4.0.0-dev", path = "../../../frame/contracts/rpc/" } pallet-mmr-rpc = { version = "3.0.0", path = "../../../frame/merkle-mountain-range/rpc/" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index f8ca6470f267a..98596c36f84d2 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://substrate.io" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" -jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } log = "0.4" parking_lot = "0.12.0" serde = { version = "1.0.136", features = ["derive"] } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 4be5d1f8bba90..4fb45d3817036 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } futures = "0.3.21" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0" diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index e8f4e20ab0e55..9806fbdcaac3c 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } assert_matches = "1.3.0" async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index c124712e3fa84..0648c874f7dff 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" [dependencies] finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } futures = "0.3.16" -jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } log = "0.4.8" parity-scale-codec = { version = "3.0.0", features = ["derive"] } serde = { version = "1.0.105", features = ["derive"] } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index f8dfaab2a58a3..a9d5101733342 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -28,4 +28,4 @@ sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-version = { version = "5.0.0", path = "../../primitives/version" } -jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index ad01f3bdd6199..7d6ca821adc3c 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" -jsonrpsee = { version = "0.12.0", features = ["server"] } +jsonrpsee = { version = "0.13.0", features = ["server"] } log = "0.4.16" serde_json = "1.0.79" tokio = { version = "1.17.0", features = ["parking_lot"] } diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 4f69413895a9b..78b8e16f8f13d 100644 --- a/client/rpc-servers/src/lib.rs +++ b/client/rpc-servers/src/lib.rs @@ -103,6 +103,7 @@ pub async fn start_http( .max_request_body_size(max_payload_in as u32) .max_response_body_size(max_payload_out as u32) .set_access_control(acl.build()) + .health_api("/health", "system_health") .custom_tokio_runtime(rt); let rpc_api = build_rpc_api(rpc_api); diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 515de401119d4..50b0dff20cfcd 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } -jsonrpsee = { version = "0.12.0", features = ["server"] } +jsonrpsee = { version = "0.13.0", features = ["server"] } lazy_static = { version = "1.4.0", optional = true } log = "0.4.16" parking_lot = "0.12.0" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index a62298a260aa4..d59e8e8d19c4c 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -22,7 +22,7 @@ wasmtime = ["sc-executor/wasmtime"] test-helpers = [] [dependencies] -jsonrpsee = { version = "0.12.0", features = ["server"] } +jsonrpsee = { version = "0.13.0", features = ["server"] } thiserror = "1.0.30" futures = "0.3.21" rand = "0.7.3" diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index f42c307ffa84c..3a2da48907a36 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" thiserror = "1.0.30" diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index 36f6c06328501..c8777d50b90a1 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } serde = { version = "1", features = ["derive"] } # Substrate Dependencies diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 2d3bfebc6633f..75238e5e329eb 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 6133d3a4b6da1..f58049a0062ab 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 4a931470eafac..f3876e41f4d02 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } env_logger = "0.9" -jsonrpsee = { version = "0.12.0", features = ["ws-client", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["ws-client", "macros"] } log = "0.4.16" serde = "1.0.136" serde_json = "1.0" diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 726cc9f989ced..71fadfdbc041c 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -25,7 +25,7 @@ sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } trie-db = { version = "0.23.1" } -jsonrpsee = { version = "0.12.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } # Substrate Dependencies sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 0c6d082406421..262da29b01d9a 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -jsonrpsee = { version = "0.12.0", features = ["jsonrpsee-types"] } +jsonrpsee = { version = "0.13.0", features = ["jsonrpsee-types"] } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } @@ -25,6 +25,6 @@ sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } [dev-dependencies] scale-info = "2.0.1" -jsonrpsee = { version = "0.12.0", features = ["ws-client", "jsonrpsee-types"] } +jsonrpsee = { version = "0.13.0", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.17.0" frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index c95ae4793ca6a..10163aacd1969 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde_json = "1" codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.12.0", features = ["server"] } +jsonrpsee = { version = "0.13.0", features = ["server"] } futures = "0.3.21" log = "0.4.16" frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index a5e658fc68476..4bbcaf1c216a5 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -19,7 +19,7 @@ parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = { version = "0.10.0", default-features = false } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } -jsonrpsee = { version = "0.12.0", default-features = false, features = ["ws-client"] } +jsonrpsee = { version = "0.13.0", default-features = false, features = ["ws-client"] } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } From cd1853bad31e29ee18db86e21825965ce3e30f20 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 11 May 2022 07:27:26 -0400 Subject: [PATCH 0788/1472] Only read storage after origin check (#11391) * only read storage after origin check * fmt --- frame/nomination-pools/src/lib.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 017eac8ee2aeb..0fff470eec43b 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1854,22 +1854,17 @@ pub mod pallet { nominator: Option, state_toggler: Option, ) -> DispatchResult { - let o1 = origin; - let o2 = o1.clone(); - - let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; - let is_pool_root = || -> Result<(), sp_runtime::DispatchError> { - let who = ensure_signed(o1)?; - ensure!(bonded_pool.can_update_roles(&who), Error::::DoesNotHavePermission); - Ok(()) - }; - let is_root = || -> Result<(), sp_runtime::DispatchError> { - ensure_root(o2)?; - Ok(()) + let mut bonded_pool = match ensure_root(origin.clone()) { + Ok(()) => BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?, + Err(frame_support::error::BadOrigin) => { + let who = ensure_signed(origin)?; + let bonded_pool = + BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + ensure!(bonded_pool.can_update_roles(&who), Error::::DoesNotHavePermission); + bonded_pool + }, }; - let _ = is_root().or_else(|_| is_pool_root())?; - match root { None => (), Some(v) => bonded_pool.roles.root = v, From 76a6cc3ca66926fa88569c2b5bfe2b311ef335ae Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 11 May 2022 18:45:59 +0100 Subject: [PATCH 0789/1472] New sub-trait to mock staking miner (#11350) * new separate config trait for staking miner * fix some docs and stuff * relax trait bounds * some cleanup * Update frame/election-provider-multi-phase/src/unsigned.rs * add comment * self review and fix build * fix docs Co-authored-by: Niklas Adolfsson --- bin/node/runtime/src/lib.rs | 29 +- .../src/benchmarking.rs | 47 +- .../src/helpers.rs | 48 +- .../election-provider-multi-phase/src/lib.rs | 86 ++- .../election-provider-multi-phase/src/mock.rs | 116 +--- .../src/signed.rs | 36 +- .../src/unsigned.rs | 580 ++++++++++-------- 7 files changed, 478 insertions(+), 464 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index fee288cb2b7f8..019c14b2c7dfd 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -23,7 +23,9 @@ #![recursion_limit = "256"] use codec::{Decode, Encode, MaxEncodedLen}; -use frame_election_provider_support::{onchain, ExtendedBalance, SequentialPhragmen, VoteWeight}; +use frame_election_provider_support::{ + onchain, ElectionDataProvider, ExtendedBalance, SequentialPhragmen, VoteWeight, +}; use frame_support::{ construct_runtime, pallet_prelude::Get, @@ -660,6 +662,25 @@ impl onchain::BoundedConfig for OnChainSeqPhragmen { type TargetsBound = ConstU32<2_000>; } +impl pallet_election_provider_multi_phase::MinerConfig for Runtime { + type AccountId = AccountId; + type MaxLength = MinerMaxLength; + type MaxWeight = MinerMaxWeight; + type Solution = NposSolution16; + type MaxVotesPerVoter = + <::DataProvider as ElectionDataProvider>::MaxVotesPerVoter; + + // The unsigned submissions have to respect the weight of the submit_unsigned call, thus their + // weight estimate function is wired to this call's weight. + fn solution_weight(v: u32, t: u32, a: u32, d: u32) -> Weight { + < + ::WeightInfo + as + pallet_election_provider_multi_phase::WeightInfo + >::submit_unsigned(v, t, a, d) + } +} + impl pallet_election_provider_multi_phase::Config for Runtime { type Event = Event; type Currency = Balances; @@ -669,9 +690,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type BetterUnsignedThreshold = BetterUnsignedThreshold; type BetterSignedThreshold = (); type OffchainRepeat = OffchainRepeat; - type MinerMaxWeight = MinerMaxWeight; - type MinerMaxLength = MinerMaxLength; type MinerTxPriority = MultiPhaseUnsignedPriority; + type MinerConfig = Self; type SignedMaxSubmissions = ConstU32<10>; type SignedRewardBase = SignedRewardBase; type SignedDepositBase = SignedDepositBase; @@ -682,7 +702,6 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type SlashHandler = (); // burn slashes type RewardHandler = (); // nothing to do upon rewards type DataProvider = Staking; - type Solution = NposSolution16; type Fallback = onchain::BoundedExecution; type GovernanceFallback = onchain::BoundedExecution; type Solver = SequentialPhragmen, OffchainRandomBalancing>; @@ -2017,7 +2036,7 @@ mod tests { #[test] fn perbill_as_onchain_accuracy() { type OnChainAccuracy = - <::Solution as NposSolution>::Accuracy; + <::Solution as NposSolution>::Accuracy; let maximum_chain_accuracy: Vec> = (0..MaxNominations::get()) .map(|_| >::from(OnChainAccuracy::one().deconstruct())) .collect(); diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index a1c643754158b..a8195df7305ff 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -39,15 +39,15 @@ fn solution_with_size( size: SolutionOrSnapshotSize, active_voters_count: u32, desired_targets: u32, -) -> Result>, &'static str> { +) -> Result>, &'static str> { ensure!(size.targets >= desired_targets, "must have enough targets"); ensure!( - size.targets >= (>::LIMIT * 2) as u32, + size.targets >= (>::LIMIT * 2) as u32, "must have enough targets for unique votes." ); ensure!(size.voters >= active_voters_count, "must have enough voters"); ensure!( - (>::LIMIT as u32) < desired_targets, + (>::LIMIT as u32) < desired_targets, "must have enough winners to give them votes." ); @@ -74,10 +74,10 @@ fn solution_with_size( // chose a random subset of winners. let winner_votes: BoundedVec<_, _> = winners .as_slice() - .choose_multiple(&mut rng, >::LIMIT) + .choose_multiple(&mut rng, >::LIMIT) .cloned() .try_collect() - .expect(">::LIMIT is the correct bound; qed."); + .expect(">::LIMIT is the correct bound; qed."); let voter = frame_benchmarking::account::("Voter", i, SEED); (voter, stake, winner_votes) }) @@ -92,10 +92,10 @@ fn solution_with_size( let rest_voters = (active_voters_count..size.voters) .map(|i| { let votes: BoundedVec<_, _> = (&non_winners) - .choose_multiple(&mut rng, >::LIMIT) + .choose_multiple(&mut rng, >::LIMIT) .cloned() .try_collect() - .expect(">::LIMIT is the correct bound; qed."); + .expect(">::LIMIT is the correct bound; qed."); let voter = frame_benchmarking::account::("Voter", i, SEED); (voter, stake, votes) }) @@ -120,12 +120,12 @@ fn solution_with_size( // down the road. T::DataProvider::put_snapshot(all_voters.clone(), targets.clone(), Some(stake)); - let cache = helpers::generate_voter_cache::(&all_voters); - let stake_of = helpers::stake_of_fn::(&all_voters, &cache); - let voter_index = helpers::voter_index_fn::(&cache); - let target_index = helpers::target_index_fn::(&targets); - let voter_at = helpers::voter_at_fn::(&all_voters); - let target_at = helpers::target_at_fn::(&targets); + let cache = helpers::generate_voter_cache::(&all_voters); + let stake_of = helpers::stake_of_fn::(&all_voters, &cache); + let voter_index = helpers::voter_index_fn::(&cache); + let target_index = helpers::target_index_fn::(&targets); + let voter_at = helpers::voter_at_fn::(&all_voters); + let target_at = helpers::target_at_fn::(&targets); let assignments = active_voters .iter() @@ -143,7 +143,8 @@ fn solution_with_size( .collect::>(); let solution = - >::from_assignment(&assignments, &voter_index, &target_index).unwrap(); + >::from_assignment(&assignments, &voter_index, &target_index) + .unwrap(); let score = solution.clone().score(stake_of, voter_at, target_at).unwrap(); let round = >::round(); @@ -480,14 +481,14 @@ frame_benchmarking::benchmarks! { let witness = SolutionOrSnapshotSize { voters: v, targets: t }; let RawSolution { solution, .. } = solution_with_size::(witness, a, d)?; let RoundSnapshot { voters, targets } = MultiPhase::::snapshot().ok_or("snapshot missing")?; - let voter_at = helpers::voter_at_fn::(&voters); - let target_at = helpers::target_at_fn::(&targets); + let voter_at = helpers::voter_at_fn::(&voters); + let target_at = helpers::target_at_fn::(&targets); let mut assignments = solution.into_assignment(voter_at, target_at).expect("solution generated by `solution_with_size` must be valid."); // make a voter cache and some helper functions for access - let cache = helpers::generate_voter_cache::(&voters); - let voter_index = helpers::voter_index_fn::(&cache); - let target_index = helpers::target_index_fn::(&targets); + let cache = helpers::generate_voter_cache::(&voters); + let voter_index = helpers::voter_index_fn::(&cache); + let target_index = helpers::target_index_fn::(&targets); // sort assignments by decreasing voter stake assignments.sort_by_key(|crate::unsigned::Assignment:: { who, .. }| { @@ -504,21 +505,21 @@ frame_benchmarking::benchmarks! { .collect::, _>>() .unwrap(); - let encoded_size_of = |assignments: &[IndexAssignmentOf]| { - SolutionOf::::try_from(assignments).map(|solution| solution.encoded_size()) + let encoded_size_of = |assignments: &[IndexAssignmentOf]| { + SolutionOf::::try_from(assignments).map(|solution| solution.encoded_size()) }; let desired_size = Percent::from_percent(100 - f.saturated_into::()) .mul_ceil(encoded_size_of(index_assignments.as_slice()).unwrap()); log!(trace, "desired_size = {}", desired_size); }: { - MultiPhase::::trim_assignments_length( + crate::Miner::::trim_assignments_length( desired_size.saturated_into(), &mut index_assignments, &encoded_size_of, ).unwrap(); } verify { - let solution = SolutionOf::::try_from(index_assignments.as_slice()).unwrap(); + let solution = SolutionOf::::try_from(index_assignments.as_slice()).unwrap(); let encoding = solution.encode(); log!( trace, diff --git a/frame/election-provider-multi-phase/src/helpers.rs b/frame/election-provider-multi-phase/src/helpers.rs index 48da194cc65d9..0a7240c5d27af 100644 --- a/frame/election-provider-multi-phase/src/helpers.rs +++ b/frame/election-provider-multi-phase/src/helpers.rs @@ -17,7 +17,10 @@ //! Some helper functions/macros for this crate. -use crate::{unsigned::VoterOf, Config, SolutionTargetIndexOf, SolutionVoterIndexOf, VoteWeight}; +use crate::{ + unsigned::{MinerConfig, MinerVoterOf}, + SolutionTargetIndexOf, SolutionVoterIndexOf, VoteWeight, +}; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; #[macro_export] @@ -30,11 +33,22 @@ macro_rules! log { }; } +// This is only useful for a context where a `` is not in scope. +#[macro_export] +macro_rules! log_no_system { + ($level:tt, $pattern:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: $crate::LOG_TARGET, + concat!("🗳 ", $pattern) $(, $values)* + ) + }; +} + /// Generate a btree-map cache of the voters and their indices. /// /// This can be used to efficiently build index getter closures. -pub fn generate_voter_cache( - snapshot: &Vec>, +pub fn generate_voter_cache( + snapshot: &Vec>, ) -> BTreeMap { let mut cache: BTreeMap = BTreeMap::new(); snapshot.iter().enumerate().for_each(|(i, (x, _, _))| { @@ -54,7 +68,7 @@ pub fn generate_voter_cache( /// ## Warning /// /// Note that this will represent the snapshot data from which the `cache` is generated. -pub fn voter_index_fn( +pub fn voter_index_fn( cache: &BTreeMap, ) -> impl Fn(&T::AccountId) -> Option> + '_ { move |who| { @@ -68,7 +82,7 @@ pub fn voter_index_fn( /// /// Same as [`voter_index_fn`] but the returned function owns all its necessary data; nothing is /// borrowed. -pub fn voter_index_fn_owned( +pub fn voter_index_fn_owned( cache: BTreeMap, ) -> impl Fn(&T::AccountId) -> Option> { move |who| { @@ -83,7 +97,7 @@ pub fn voter_index_fn_owned( /// ## Warning /// /// Note that this will represent the snapshot data from which the `cache` is generated. -pub fn voter_index_fn_usize( +pub fn voter_index_fn_usize( cache: &BTreeMap, ) -> impl Fn(&T::AccountId) -> Option + '_ { move |who| cache.get(who).cloned() @@ -96,8 +110,8 @@ pub fn voter_index_fn_usize( /// /// Not meant to be used in production. #[cfg(test)] -pub fn voter_index_fn_linear( - snapshot: &Vec>, +pub fn voter_index_fn_linear( + snapshot: &Vec>, ) -> impl Fn(&T::AccountId) -> Option> + '_ { move |who| { snapshot @@ -114,7 +128,7 @@ pub fn voter_index_fn_linear( /// Note: to the extent possible, the returned function should be cached and reused. Producing that /// function requires a `O(n log n)` data transform. Each invocation of that function completes /// in `O(log n)`. -pub fn target_index_fn( +pub fn target_index_fn( snapshot: &Vec, ) -> impl Fn(&T::AccountId) -> Option> + '_ { let cache: BTreeMap<_, _> = @@ -134,7 +148,7 @@ pub fn target_index_fn( /// /// Not meant to be used in production. #[cfg(test)] -pub fn target_index_fn_linear( +pub fn target_index_fn_linear( snapshot: &Vec, ) -> impl Fn(&T::AccountId) -> Option> + '_ { move |who| { @@ -147,8 +161,8 @@ pub fn target_index_fn_linear( /// Create a function that can map a voter index ([`SolutionVoterIndexOf`]) to the actual voter /// account using a linearly indexible snapshot. -pub fn voter_at_fn( - snapshot: &Vec>, +pub fn voter_at_fn( + snapshot: &Vec>, ) -> impl Fn(SolutionVoterIndexOf) -> Option + '_ { move |i| { as TryInto>::try_into(i) @@ -159,7 +173,7 @@ pub fn voter_at_fn( /// Create a function that can map a target index ([`SolutionTargetIndexOf`]) to the actual target /// account using a linearly indexible snapshot. -pub fn target_at_fn( +pub fn target_at_fn( snapshot: &Vec, ) -> impl Fn(SolutionTargetIndexOf) -> Option + '_ { move |i| { @@ -173,8 +187,8 @@ pub fn target_at_fn( /// /// This is not optimized and uses a linear search. #[cfg(test)] -pub fn stake_of_fn_linear( - snapshot: &Vec>, +pub fn stake_of_fn_linear( + snapshot: &Vec>, ) -> impl Fn(&T::AccountId) -> VoteWeight + '_ { move |who| { snapshot @@ -191,8 +205,8 @@ pub fn stake_of_fn_linear( /// /// The cache need must be derived from the same snapshot. Zero is returned if a voter is /// non-existent. -pub fn stake_of_fn<'a, T: Config>( - snapshot: &'a Vec>, +pub fn stake_of_fn<'a, T: MinerConfig>( + snapshot: &'a Vec>, cache: &'a BTreeMap, ) -> impl Fn(&T::AccountId) -> VoteWeight + 'a { move |who| { diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 4aea5b9da4794..36d2373c9f623 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -103,7 +103,7 @@ //! //! Validators will only submit solutions if the one that they have computed is sufficiently better //! than the best queued one (see [`pallet::Config::BetterUnsignedThreshold`]) and will limit the -//! weight of the solution to [`pallet::Config::MinerMaxWeight`]. +//! weight of the solution to [`MinerConfig::MaxWeight`]. //! //! The unsigned phase can be made passive depending on how the previous signed phase went, by //! setting the first inner value of [`Phase`] to `false`. For now, the signed phase is always @@ -276,16 +276,18 @@ pub use signed::{ BalanceOf, NegativeImbalanceOf, PositiveImbalanceOf, SignedSubmission, SignedSubmissionOf, SignedSubmissions, SubmissionIndicesOf, }; +pub use unsigned::{Miner, MinerConfig}; /// The solution type used by this crate. -pub type SolutionOf = ::Solution; +pub type SolutionOf = ::Solution; /// The voter index. Derived from [`SolutionOf`]. pub type SolutionVoterIndexOf = as NposSolution>::VoterIndex; /// The target index. Derived from [`SolutionOf`]. pub type SolutionTargetIndexOf = as NposSolution>::TargetIndex; /// The accuracy of the election, when submitted from offchain. Derived from [`SolutionOf`]. -pub type SolutionAccuracyOf = as NposSolution>::Accuracy; +pub type SolutionAccuracyOf = + ::MinerConfig> as NposSolution>::Accuracy; /// The fallback election type. pub type FallbackErrorOf = <::Fallback as ElectionProvider>::Error; @@ -488,7 +490,7 @@ pub enum ElectionError { /// An error happened in the feasibility check sub-system. Feasibility(FeasibilityError), /// An error in the miner (offchain) sub-system. - Miner(unsigned::MinerError), + Miner(unsigned::MinerError), /// An error happened in the data provider. DataProvider(&'static str), /// An error nested in the fallback. @@ -520,8 +522,8 @@ impl From for ElectionError { } } -impl From> for ElectionError { - fn from(e: unsigned::MinerError) -> Self { +impl From for ElectionError { + fn from(e: unsigned::MinerError) -> Self { ElectionError::Miner(e) } } @@ -605,12 +607,14 @@ pub mod pallet { #[pallet::constant] type MinerTxPriority: Get; - /// Maximum weight that the miner should consume. + /// Configurations of the embedded miner. /// - /// The miner will ensure that the total weight of the unsigned solution will not exceed - /// this value, based on [`WeightInfo::submit_unsigned`]. - #[pallet::constant] - type MinerMaxWeight: Get; + /// Any external software implementing this can use the [`unsigned::Miner`] type provided, + /// which can mine new solutions and trim them accordingly. + type MinerConfig: crate::unsigned::MinerConfig< + AccountId = Self::AccountId, + MaxVotesPerVoter = ::MaxVotesPerVoter, + >; /// Maximum number of signed submissions that can be queued. /// @@ -624,7 +628,9 @@ pub mod pallet { /// Maximum weight of a signed solution. /// - /// This should probably be similar to [`Config::MinerMaxWeight`]. + /// If [`Config::MinerConfig`] is being implemented to submit signed solutions (outside of + /// this pallet), then [`MinerConfig::solution_weight`] is used to compare against + /// this value. #[pallet::constant] type SignedMaxWeight: Get; @@ -652,11 +658,11 @@ pub mod pallet { /// are only over a single block, but once multi-block elections are introduced they will /// take place over multiple blocks. #[pallet::constant] - type MaxElectingVoters: Get>; + type MaxElectingVoters: Get>; /// The maximum number of electable targets to put in the snapshot. #[pallet::constant] - type MaxElectableTargets: Get>; + type MaxElectableTargets: Get>; /// Handler for the slashed deposits. type SlashHandler: OnUnbalanced>; @@ -664,30 +670,12 @@ pub mod pallet { /// Handler for the rewards. type RewardHandler: OnUnbalanced>; - /// Maximum length (bytes) that the mined solution should consume. - /// - /// The miner will ensure that the total length of the unsigned solution will not exceed - /// this value. - #[pallet::constant] - type MinerMaxLength: Get; - /// Something that will provide the election data. type DataProvider: ElectionDataProvider< AccountId = Self::AccountId, BlockNumber = Self::BlockNumber, >; - /// The solution type. - type Solution: codec::Codec - + Default - + PartialEq - + Eq - + Clone - + sp_std::fmt::Debug - + Ord - + NposSolution - + TypeInfo; - /// Configuration for the fallback. type Fallback: InstantElectionProvider< AccountId = Self::AccountId, @@ -824,12 +812,12 @@ pub mod pallet { use sp_std::mem::size_of; // The index type of both voters and targets need to be smaller than that of usize (very // unlikely to be the case, but anyhow).. - assert!(size_of::>() <= size_of::()); - assert!(size_of::>() <= size_of::()); + assert!(size_of::>() <= size_of::()); + assert!(size_of::>() <= size_of::()); // ---------------------------- // Based on the requirements of [`sp_npos_elections::Assignment::try_normalize`]. - let max_vote: usize = as NposSolution>::LIMIT; + let max_vote: usize = as NposSolution>::LIMIT; // 2. Maximum sum of [SolutionAccuracy; 16] must fit into `UpperOf`. let maximum_chain_accuracy: Vec>> = (0..max_vote) @@ -850,7 +838,7 @@ pub mod pallet { // solution cannot represent any voters more than `LIMIT` anyhow. assert_eq!( ::MaxVotesPerVoter::get(), - as NposSolution>::LIMIT as u32, + as NposSolution>::LIMIT as u32, ); // While it won't cause any failures, setting `SignedMaxRefunds` gt @@ -887,7 +875,7 @@ pub mod pallet { ))] pub fn submit_unsigned( origin: OriginFor, - raw_solution: Box>>, + raw_solution: Box>>, witness: SolutionOrSnapshotSize, ) -> DispatchResultWithPostInfo { ensure_none(origin)?; @@ -976,7 +964,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::submit())] pub fn submit( origin: OriginFor, - raw_solution: Box>>, + raw_solution: Box>>, ) -> DispatchResult { let who = ensure_signed(origin)?; @@ -991,7 +979,7 @@ pub mod pallet { let size = Self::snapshot_metadata().ok_or(Error::::MissingSnapshotMetadata)?; ensure!( - Self::feasibility_weight_of(&raw_solution, size) < T::SignedMaxWeight::get(), + Self::solution_weight_of(&raw_solution, size) < T::SignedMaxWeight::get(), Error::::SignedTooMuchWeight, ); @@ -1429,7 +1417,7 @@ impl Pallet { /// Checks the feasibility of a solution. pub fn feasibility_check( - raw_solution: RawSolution>, + raw_solution: RawSolution>, compute: ElectionCompute, ) -> Result, FeasibilityError> { let RawSolution { solution, score, round } = raw_solution; @@ -1459,10 +1447,10 @@ impl Pallet { Self::snapshot().ok_or(FeasibilityError::SnapshotUnavailable)?; // ----- Start building. First, we need some closures. - let cache = helpers::generate_voter_cache::(&snapshot_voters); - let voter_at = helpers::voter_at_fn::(&snapshot_voters); - let target_at = helpers::target_at_fn::(&snapshot_targets); - let voter_index = helpers::voter_index_fn_usize::(&cache); + let cache = helpers::generate_voter_cache::(&snapshot_voters); + let voter_at = helpers::voter_at_fn::(&snapshot_voters); + let target_at = helpers::target_at_fn::(&snapshot_targets); + let voter_index = helpers::voter_index_fn_usize::(&cache); // Then convert solution -> assignment. This will fail if any of the indices are gibberish, // namely any of the voters or targets. @@ -1493,7 +1481,7 @@ impl Pallet { })?; // ----- Start building support. First, we need one more closure. - let stake_of = helpers::stake_of_fn::(&snapshot_voters, &cache); + let stake_of = helpers::stake_of_fn::(&snapshot_voters, &cache); // This might fail if the normalization fails. Very unlikely. See `integrity_test`. let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) @@ -1803,8 +1791,8 @@ mod tests { use super::*; use crate::{ mock::{ - multi_phase_events, roll_to, AccountId, ExtBuilder, MockWeightInfo, MultiPhase, - Runtime, SignedMaxSubmissions, System, TargetIndex, Targets, + multi_phase_events, roll_to, AccountId, ExtBuilder, MockWeightInfo, MockedWeightInfo, + MultiPhase, Runtime, SignedMaxSubmissions, System, TargetIndex, Targets, }, Phase, }; @@ -2123,7 +2111,7 @@ mod tests { // set the solution balancing to get the desired score. crate::mock::Balancing::set(Some((2, 0))); - let (solution, _) = MultiPhase::mine_solution::<::Solver>().unwrap(); + let (solution, _) = MultiPhase::mine_solution().unwrap(); // Default solution's score. assert!(matches!(solution.score, ElectionScore { minimal_stake: 50, .. })); @@ -2147,7 +2135,7 @@ mod tests { #[test] fn number_of_voters_allowed_2sec_block() { // Just a rough estimate with the substrate weights. - assert!(!MockWeightInfo::get()); + assert_eq!(MockWeightInfo::get(), MockedWeightInfo::Real); let all_voters: u32 = 10_000; let all_targets: u32 = 5_000; diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 38d9c8dfc1b7e..afce24ff6e3f0 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -16,7 +16,7 @@ // limitations under the License. use super::*; -use crate as multi_phase; +use crate::{self as multi_phase, unsigned::MinerConfig}; use frame_election_provider_support::{ data_provider, onchain, ElectionDataProvider, NposSolution, SequentialPhragmen, }; @@ -239,6 +239,13 @@ impl pallet_balances::Config for Runtime { type WeightInfo = (); } +#[derive(Eq, PartialEq, Debug, Clone, Copy)] +pub enum MockedWeightInfo { + Basic, + Complex, + Real, +} + parameter_types! { pub static Targets: Vec = vec![10, 20, 30, 40]; pub static Voters: Vec> = vec![ @@ -269,7 +276,7 @@ parameter_types! { pub static OffchainRepeat: BlockNumber = 5; pub static MinerMaxWeight: Weight = BlockWeights::get().max_block; pub static MinerMaxLength: u32 = 256; - pub static MockWeightInfo: bool = false; + pub static MockWeightInfo: MockedWeightInfo = MockedWeightInfo::Real; pub static MaxElectingVoters: VoterIndex = u32::max_value(); pub static MaxElectableTargets: TargetIndex = TargetIndex::max_value(); @@ -314,85 +321,6 @@ impl InstantElectionProvider for MockFallback { } } -// Hopefully this won't be too much of a hassle to maintain. -pub struct DualMockWeightInfo; -impl multi_phase::weights::WeightInfo for DualMockWeightInfo { - fn on_initialize_nothing() -> Weight { - if MockWeightInfo::get() { - Zero::zero() - } else { - <() as multi_phase::weights::WeightInfo>::on_initialize_nothing() - } - } - fn create_snapshot_internal(v: u32, t: u32) -> Weight { - if MockWeightInfo::get() { - Zero::zero() - } else { - <() as multi_phase::weights::WeightInfo>::create_snapshot_internal(v, t) - } - } - fn on_initialize_open_signed() -> Weight { - if MockWeightInfo::get() { - Zero::zero() - } else { - <() as multi_phase::weights::WeightInfo>::on_initialize_open_signed() - } - } - fn on_initialize_open_unsigned() -> Weight { - if MockWeightInfo::get() { - Zero::zero() - } else { - <() as multi_phase::weights::WeightInfo>::on_initialize_open_unsigned() - } - } - fn elect_queued(a: u32, d: u32) -> Weight { - if MockWeightInfo::get() { - Zero::zero() - } else { - <() as multi_phase::weights::WeightInfo>::elect_queued(a, d) - } - } - fn finalize_signed_phase_accept_solution() -> Weight { - if MockWeightInfo::get() { - Zero::zero() - } else { - <() as multi_phase::weights::WeightInfo>::finalize_signed_phase_accept_solution() - } - } - fn finalize_signed_phase_reject_solution() -> Weight { - if MockWeightInfo::get() { - Zero::zero() - } else { - <() as multi_phase::weights::WeightInfo>::finalize_signed_phase_reject_solution() - } - } - fn submit() -> Weight { - if MockWeightInfo::get() { - Zero::zero() - } else { - <() as multi_phase::weights::WeightInfo>::submit() - } - } - fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight { - if MockWeightInfo::get() { - // 10 base - // 5 per edge. - (10 as Weight).saturating_add((5 as Weight).saturating_mul(a as Weight)) - } else { - <() as multi_phase::weights::WeightInfo>::submit_unsigned(v, t, a, d) - } - } - fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight { - if MockWeightInfo::get() { - // 10 base - // 5 per edge. - (10 as Weight).saturating_add((5 as Weight).saturating_mul(a as Weight)) - } else { - <() as multi_phase::weights::WeightInfo>::feasibility_check(v, t, a, d) - } - } -} - parameter_types! { pub static Balancing: Option<(usize, ExtendedBalance)> = Some((0, 0)); } @@ -410,6 +338,24 @@ impl BenchmarkingConfig for TestBenchmarkingConfig { const MAXIMUM_TARGETS: u32 = 200; } +impl MinerConfig for Runtime { + type AccountId = AccountId; + type MaxLength = MinerMaxLength; + type MaxWeight = MinerMaxWeight; + type MaxVotesPerVoter = ::MaxVotesPerVoter; + type Solution = TestNposSolution; + + fn solution_weight(v: u32, t: u32, a: u32, d: u32) -> Weight { + match MockWeightInfo::get() { + MockedWeightInfo::Basic => + (10 as Weight).saturating_add((5 as Weight).saturating_mul(a as Weight)), + MockedWeightInfo::Complex => (0 * v + 0 * t + 1000 * a + 0 * d) as Weight, + MockedWeightInfo::Real => + <() as multi_phase::weights::WeightInfo>::feasibility_check(v, t, a, d), + } + } +} + impl crate::Config for Runtime { type Event = Event; type Currency = Balances; @@ -419,8 +365,6 @@ impl crate::Config for Runtime { type BetterUnsignedThreshold = BetterUnsignedThreshold; type BetterSignedThreshold = BetterSignedThreshold; type OffchainRepeat = OffchainRepeat; - type MinerMaxWeight = MinerMaxWeight; - type MinerMaxLength = MinerMaxLength; type MinerTxPriority = MinerTxPriority; type SignedRewardBase = SignedRewardBase; type SignedDepositBase = SignedDepositBase; @@ -432,14 +376,14 @@ impl crate::Config for Runtime { type SlashHandler = (); type RewardHandler = (); type DataProvider = StakingMock; - type WeightInfo = DualMockWeightInfo; + type WeightInfo = (); type BenchmarkingConfig = TestBenchmarkingConfig; type Fallback = MockFallback; type GovernanceFallback = NoFallback; type ForceOrigin = frame_system::EnsureRoot; - type Solution = TestNposSolution; type MaxElectingVoters = MaxElectingVoters; type MaxElectableTargets = MaxElectableTargets; + type MinerConfig = Self; type Solver = SequentialPhragmen, Balancing>; } @@ -562,7 +506,7 @@ impl ExtBuilder { ::set(weight); self } - pub fn mock_weight_info(self, mock: bool) -> Self { + pub fn mock_weight_info(self, mock: MockedWeightInfo) -> Self { ::set(mock); self } diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 5f61eb7575da4..eca75139f925a 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -18,9 +18,9 @@ //! The signed phase implementation. use crate::{ - Config, ElectionCompute, Pallet, QueuedSolution, RawSolution, ReadySolution, - SignedSubmissionIndices, SignedSubmissionNextIndex, SignedSubmissionsMap, SolutionOf, - SolutionOrSnapshotSize, Weight, WeightInfo, + unsigned::MinerConfig, Config, ElectionCompute, Pallet, QueuedSolution, RawSolution, + ReadySolution, SignedSubmissionIndices, SignedSubmissionNextIndex, SignedSubmissionsMap, + SolutionOf, SolutionOrSnapshotSize, Weight, WeightInfo, }; use codec::{Decode, Encode, HasCompact}; use frame_election_provider_support::NposSolution; @@ -93,8 +93,11 @@ pub type PositiveImbalanceOf = <::Currency as Currency< pub type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; -pub type SignedSubmissionOf = - SignedSubmission<::AccountId, BalanceOf, SolutionOf>; +pub type SignedSubmissionOf = SignedSubmission< + ::AccountId, + BalanceOf, + <::MinerConfig as MinerConfig>::Solution, +>; pub type SubmissionIndicesOf = BoundedBTreeMap::SignedMaxSubmissions>; @@ -482,12 +485,12 @@ impl Pallet { T::SlashHandler::on_unbalanced(negative_imbalance); } - /// The feasibility weight of the given raw solution. - pub fn feasibility_weight_of( - raw_solution: &RawSolution>, + /// The weight of the given raw solution. + pub fn solution_weight_of( + raw_solution: &RawSolution>, size: SolutionOrSnapshotSize, ) -> Weight { - T::WeightInfo::feasibility_check( + T::MinerConfig::solution_weight( size.voters, size.targets, raw_solution.solution.voter_count() as u32, @@ -503,12 +506,12 @@ impl Pallet { /// 2. a per-byte deposit, for renting the state usage. /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize pub fn deposit_for( - raw_solution: &RawSolution>, + raw_solution: &RawSolution>, size: SolutionOrSnapshotSize, ) -> BalanceOf { let encoded_len: u32 = raw_solution.encoded_size().saturated_into(); let encoded_len: BalanceOf = encoded_len.into(); - let feasibility_weight = Self::feasibility_weight_of(raw_solution, size); + let feasibility_weight = Self::solution_weight_of(raw_solution, size); let len_deposit = T::SignedDepositByte::get().saturating_mul(encoded_len); let weight_deposit = @@ -525,8 +528,8 @@ mod tests { use super::*; use crate::{ mock::{ - balances, raw_solution, roll_to, Balances, ExtBuilder, MultiPhase, Origin, Runtime, - SignedMaxRefunds, SignedMaxSubmissions, SignedMaxWeight, + balances, raw_solution, roll_to, Balances, ExtBuilder, MockedWeightInfo, MultiPhase, + Origin, Runtime, SignedMaxRefunds, SignedMaxSubmissions, SignedMaxWeight, }, Error, Perbill, Phase, }; @@ -955,14 +958,13 @@ mod tests { fn cannot_consume_too_much_future_weight() { ExtBuilder::default() .signed_weight(40) - .mock_weight_info(true) + .mock_weight_info(MockedWeightInfo::Basic) .build_and_execute(|| { roll_to(15); assert!(MultiPhase::current_phase().is_signed()); - let (raw, witness) = - MultiPhase::mine_solution::<::Solver>().unwrap(); - let solution_weight = ::WeightInfo::feasibility_check( + let (raw, witness) = MultiPhase::mine_solution().unwrap(); + let solution_weight = ::solution_weight( witness.voters, witness.targets, raw.solution.voter_count() as u32, diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 126dcb10416cc..9a1b52d354569 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -20,14 +20,15 @@ use crate::{ helpers, Call, Config, ElectionCompute, Error, FeasibilityError, Pallet, RawSolution, ReadySolution, RoundSnapshot, SolutionAccuracyOf, SolutionOf, SolutionOrSnapshotSize, Weight, - WeightInfo, }; use codec::Encode; -use frame_election_provider_support::{NposSolution, NposSolver, PerThing128}; -use frame_support::{dispatch::DispatchResult, ensure, traits::Get}; +use frame_election_provider_support::{NposSolution, NposSolver, PerThing128, VoteWeight}; +use frame_support::{dispatch::DispatchResult, ensure, traits::Get, BoundedVec}; use frame_system::offchain::SubmitTransaction; +use scale_info::TypeInfo; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, ElectionResult, + ElectionScore, }; use sp_runtime::{ offchain::storage::{MutateStorageError, StorageValueRef}, @@ -47,6 +48,12 @@ pub(crate) const OFFCHAIN_CACHED_CALL: &[u8] = b"parity/multi-phase-unsigned-ele /// voted. pub type VoterOf = frame_election_provider_support::VoterOf<::DataProvider>; +/// Same as [`VoterOf`], but parameterized by the `MinerConfig`. +pub type MinerVoterOf = frame_election_provider_support::Voter< + ::AccountId, + ::MaxVotesPerVoter, +>; + /// The relative distribution of a voter's stake among the winning targets. pub type Assignment = sp_npos_elections::Assignment<::AccountId, SolutionAccuracyOf>; @@ -59,7 +66,7 @@ pub type IndexAssignmentOf = frame_election_provider_support::IndexAssignment pub type SolverErrorOf = <::Solver as NposSolver>::Error; /// Error type for operations related to the OCW npos solution miner. #[derive(frame_support::DebugNoBound, frame_support::PartialEqNoBound)] -pub enum MinerError { +pub enum MinerError { /// An internal error in the NPoS elections crate. NposElections(sp_npos_elections::Error), /// Snapshot data was unavailable unexpectedly. @@ -81,23 +88,23 @@ pub enum MinerError { /// There are no more voters to remove to trim the solution. NoMoreVoters, /// An error from the solver. - Solver(SolverErrorOf), + Solver, } -impl From for MinerError { +impl From for MinerError { fn from(e: sp_npos_elections::Error) -> Self { MinerError::NposElections(e) } } -impl From for MinerError { +impl From for MinerError { fn from(e: FeasibilityError) -> Self { MinerError::Feasibility(e) } } /// Save a given call into OCW storage. -fn save_solution(call: &Call) -> Result<(), MinerError> { +fn save_solution(call: &Call) -> Result<(), MinerError> { log!(debug, "saving a call to the offchain storage."); let storage = StorageValueRef::persistent(OFFCHAIN_CACHED_CALL); match storage.mutate::<_, (), _>(|_| Ok(call.clone())) { @@ -115,7 +122,7 @@ fn save_solution(call: &Call) -> Result<(), MinerError> { } /// Get a saved solution from OCW storage if it exists. -fn restore_solution() -> Result, MinerError> { +fn restore_solution() -> Result, MinerError> { StorageValueRef::persistent(OFFCHAIN_CACHED_CALL) .get() .ok() @@ -146,9 +153,46 @@ fn ocw_solution_exists() -> bool { } impl Pallet { + /// Mine a new npos solution. + /// + /// The Npos Solver type, `S`, must have the same AccountId and Error type as the + /// [`crate::Config::Solver`] in order to create a unified return type. + pub fn mine_solution( + ) -> Result<(RawSolution>, SolutionOrSnapshotSize), MinerError> { + let RoundSnapshot { voters, targets } = + Self::snapshot().ok_or(MinerError::SnapshotUnAvailable)?; + let desired_targets = Self::desired_targets().ok_or(MinerError::SnapshotUnAvailable)?; + let (solution, score, size) = Miner::::mine_solution_with_snapshot::< + T::Solver, + >(voters, targets, desired_targets)?; + let round = Self::round(); + Ok((RawSolution { solution, score, round }, size)) + } + + /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which + /// is ready to be submitted to the chain. + /// + /// Will always reduce the solution as well. + pub fn prepare_election_result( + election_result: ElectionResult, + ) -> Result<(RawSolution>, SolutionOrSnapshotSize), MinerError> { + let RoundSnapshot { voters, targets } = + Self::snapshot().ok_or(MinerError::SnapshotUnAvailable)?; + let desired_targets = Self::desired_targets().ok_or(MinerError::SnapshotUnAvailable)?; + let (solution, score, size) = + Miner::::prepare_election_result_with_snapshot( + election_result, + voters, + targets, + desired_targets, + )?; + let round = Self::round(); + Ok((RawSolution { solution, score, round }, size)) + } + /// Attempt to restore a solution from cache. Otherwise, compute it fresh. Either way, submit /// if our call's score is greater than that of the cached solution. - pub fn restore_or_compute_then_maybe_submit() -> Result<(), MinerError> { + pub fn restore_or_compute_then_maybe_submit() -> Result<(), MinerError> { log!(debug, "miner attempting to restore or compute an unsigned solution."); let call = restore_solution::() @@ -162,7 +206,7 @@ impl Pallet { Err(MinerError::SolutionCallInvalid) } }) - .or_else::, _>(|error| { + .or_else::(|error| { log!(debug, "restoring solution failed due to {:?}", error); match error { MinerError::NoStoredSolution => { @@ -193,7 +237,7 @@ impl Pallet { } /// Mine a new solution, cache it, and submit it back to the chain as an unsigned transaction. - pub fn mine_check_save_submit() -> Result<(), MinerError> { + pub fn mine_check_save_submit() -> Result<(), MinerError> { log!(debug, "miner attempting to compute an unsigned solution."); let call = Self::mine_checked_call()?; @@ -202,7 +246,7 @@ impl Pallet { } /// Mine a new solution as a call. Performs all checks. - pub fn mine_checked_call() -> Result, MinerError> { + pub fn mine_checked_call() -> Result, MinerError> { // get the solution, with a load of checks to ensure if submitted, IT IS ABSOLUTELY VALID. let (raw_solution, witness) = Self::mine_and_check()?; @@ -219,7 +263,7 @@ impl Pallet { Ok(call) } - fn submit_call(call: Call) -> Result<(), MinerError> { + fn submit_call(call: Call) -> Result<(), MinerError> { log!(debug, "miner submitting a solution as an unsigned transaction"); SubmitTransaction::>::submit_unsigned_transaction(call.into()) @@ -230,9 +274,9 @@ impl Pallet { // // Performance: note that it internally clones the provided solution. pub fn basic_checks( - raw_solution: &RawSolution>, + raw_solution: &RawSolution>, solution_type: &str, - ) -> Result<(), MinerError> { + ) -> Result<(), MinerError> { Self::unsigned_pre_dispatch_checks(raw_solution).map_err(|err| { log!(debug, "pre-dispatch checks failed for {} solution: {:?}", solution_type, err); MinerError::PreDispatchChecksFailed(err) @@ -255,45 +299,155 @@ impl Pallet { /// If you want a checked solution and submit it at the same time, use /// [`Pallet::mine_check_save_submit`]. pub fn mine_and_check( - ) -> Result<(RawSolution>, SolutionOrSnapshotSize), MinerError> { - let (raw_solution, witness) = Self::mine_solution::()?; + ) -> Result<(RawSolution>, SolutionOrSnapshotSize), MinerError> { + let (raw_solution, witness) = Self::mine_solution()?; Self::basic_checks(&raw_solution, "mined")?; Ok((raw_solution, witness)) } - /// Mine a new npos solution. + /// Checks if an execution of the offchain worker is permitted at the given block number, or + /// not. /// - /// The Npos Solver type, `S`, must have the same AccountId and Error type as the - /// [`crate::Config::Solver`] in order to create a unified return type. - pub fn mine_solution( - ) -> Result<(RawSolution>, SolutionOrSnapshotSize), MinerError> - where - S: NposSolver>, - { - let RoundSnapshot { voters, targets } = - Self::snapshot().ok_or(MinerError::SnapshotUnAvailable)?; - let desired_targets = Self::desired_targets().ok_or(MinerError::SnapshotUnAvailable)?; + /// This makes sure that + /// 1. we don't run on previous blocks in case of a re-org + /// 2. we don't run twice within a window of length `T::OffchainRepeat`. + /// + /// Returns `Ok(())` if offchain worker limit is respected, `Err(reason)` otherwise. If `Ok()` + /// is returned, `now` is written in storage and will be used in further calls as the baseline. + pub fn ensure_offchain_repeat_frequency(now: T::BlockNumber) -> Result<(), MinerError> { + let threshold = T::OffchainRepeat::get(); + let last_block = StorageValueRef::persistent(OFFCHAIN_LAST_BLOCK); - S::solve(desired_targets as usize, targets, voters) - .map_err(|e| MinerError::Solver::(e)) - .and_then(|e| Self::prepare_election_result::(e)) + let mutate_stat = last_block.mutate::<_, &'static str, _>( + |maybe_head: Result, _>| { + match maybe_head { + Ok(Some(head)) if now < head => Err("fork."), + Ok(Some(head)) if now >= head && now <= head + threshold => + Err("recently executed."), + Ok(Some(head)) if now > head + threshold => { + // we can run again now. Write the new head. + Ok(now) + }, + _ => { + // value doesn't exists. Probably this node just booted up. Write, and run + Ok(now) + }, + } + }, + ); + + match mutate_stat { + // all good + Ok(_) => Ok(()), + // failed to write. + Err(MutateStorageError::ConcurrentModification(_)) => + Err(MinerError::Lock("failed to write to offchain db (concurrent modification).")), + // fork etc. + Err(MutateStorageError::ValueFunctionFailed(why)) => Err(MinerError::Lock(why)), + } } - /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which - /// is ready to be submitted to the chain. + /// Do the basics checks that MUST happen during the validation and pre-dispatch of an unsigned + /// transaction. /// - /// Will always reduce the solution as well. - pub fn prepare_election_result( - election_result: ElectionResult, - ) -> Result<(RawSolution>, SolutionOrSnapshotSize), MinerError> { - // NOTE: This code path is generally not optimized as it is run offchain. Could use some at - // some point though. + /// Can optionally also be called during dispatch, if needed. + /// + /// NOTE: Ideally, these tests should move more and more outside of this and more to the miner's + /// code, so that we do less and less storage reads here. + pub fn unsigned_pre_dispatch_checks( + raw_solution: &RawSolution>, + ) -> DispatchResult { + // ensure solution is timely. Don't panic yet. This is a cheap check. + ensure!(Self::current_phase().is_unsigned_open(), Error::::PreDispatchEarlySubmission); - // storage items. Note: we have already read this from storage, they must be in cache. - let RoundSnapshot { voters, targets } = - Self::snapshot().ok_or(MinerError::SnapshotUnAvailable)?; - let desired_targets = Self::desired_targets().ok_or(MinerError::SnapshotUnAvailable)?; + // ensure round is current + ensure!(Self::round() == raw_solution.round, Error::::OcwCallWrongEra); + // ensure correct number of winners. + ensure!( + Self::desired_targets().unwrap_or_default() == + raw_solution.solution.unique_targets().len() as u32, + Error::::PreDispatchWrongWinnerCount, + ); + + // ensure score is being improved. Panic henceforth. + ensure!( + Self::queued_solution().map_or(true, |q: ReadySolution<_>| raw_solution + .score + .strict_threshold_better(q.score, T::BetterUnsignedThreshold::get())), + Error::::PreDispatchWeakSubmission, + ); + + Ok(()) + } +} + +/// Configurations for a miner that comes with this pallet. +pub trait MinerConfig { + /// The account id type. + type AccountId: Ord + Clone + codec::Codec + sp_std::fmt::Debug; + /// The solution that the miner is mining. + type Solution: codec::Codec + + Default + + PartialEq + + Eq + + Clone + + sp_std::fmt::Debug + + Ord + + NposSolution + + TypeInfo; + /// Maximum number of votes per voter in the snapshots. + type MaxVotesPerVoter; + /// Maximum length of the solution that the miner is allowed to generate. + /// + /// Solutions are trimmed to respect this. + type MaxLength: Get; + /// Maximum weight of the solution that the miner is allowed to generate. + /// + /// Solutions are trimmed to respect this. + /// + /// The weight is computed using `solution_weight`. + type MaxWeight: Get; + /// Something that can compute the weight of a solution. + /// + /// This weight estimate is then used to trim the solution, based on [`MinerConfig::MaxWeight`]. + fn solution_weight(voters: u32, targets: u32, active_voters: u32, degree: u32) -> Weight; +} + +/// A base miner, suitable to be used for both signed and unsigned submissions. +pub struct Miner(sp_std::marker::PhantomData); +impl Miner { + /// Same as [`Pallet::mine_solution`], but the input snapshot data must be given. + pub fn mine_solution_with_snapshot( + voters: Vec<(T::AccountId, VoteWeight, BoundedVec)>, + targets: Vec, + desired_targets: u32, + ) -> Result<(SolutionOf, ElectionScore, SolutionOrSnapshotSize), MinerError> + where + S: NposSolver, + { + S::solve(desired_targets as usize, targets.clone(), voters.clone()) + .map_err(|e| { + log_no_system!(error, "solver error: {:?}", e); + MinerError::Solver + }) + .and_then(|e| { + Self::prepare_election_result_with_snapshot::( + e, + voters, + targets, + desired_targets, + ) + }) + } + + /// Same as [`Pallet::prepare_election_result`], but the input snapshot mut be given as inputs. + pub fn prepare_election_result_with_snapshot( + election_result: ElectionResult, + voters: Vec<(T::AccountId, VoteWeight, BoundedVec)>, + targets: Vec, + desired_targets: u32, + ) -> Result<(SolutionOf, ElectionScore, SolutionOrSnapshotSize), MinerError> { // now make some helper closures. let cache = helpers::generate_voter_cache::(&voters); let voter_index = helpers::voter_index_fn::(&cache); @@ -355,11 +509,11 @@ impl Pallet { Self::trim_assignments_weight( desired_targets, size, - T::MinerMaxWeight::get(), + T::MaxWeight::get(), &mut index_assignments, ); Self::trim_assignments_length( - T::MinerMaxLength::get(), + T::MaxLength::get(), &mut index_assignments, &encoded_size_of, )?; @@ -370,43 +524,7 @@ impl Pallet { // re-calc score. let score = solution.clone().score(stake_of, voter_at, target_at)?; - let round = Self::round(); - Ok((RawSolution { solution, score, round }, size)) - } - - /// Greedily reduce the size of the solution to fit into the block w.r.t. weight. - /// - /// The weight of the solution is foremost a function of the number of voters (i.e. - /// `assignments.len()`). Aside from this, the other components of the weight are invariant. The - /// number of winners shall not be changed (otherwise the solution is invalid) and the - /// `ElectionSize` is merely a representation of the total number of stakers. - /// - /// Thus, we reside to stripping away some voters from the `assignments`. - /// - /// Note that the solution is already computed, and the winners are elected based on the merit - /// of the entire stake in the system. Nonetheless, some of the voters will be removed further - /// down the line. - /// - /// Indeed, the score must be computed **after** this step. If this step reduces the score too - /// much or remove a winner, then the solution must be discarded **after** this step. - pub fn trim_assignments_weight( - desired_targets: u32, - size: SolutionOrSnapshotSize, - max_weight: Weight, - assignments: &mut Vec>, - ) { - let maximum_allowed_voters = - Self::maximum_voter_for_weight::(desired_targets, size, max_weight); - let removing: usize = - assignments.len().saturating_sub(maximum_allowed_voters.saturated_into()); - log!( - debug, - "from {} assignments, truncating to {} for weight, removing {}", - assignments.len(), - maximum_allowed_voters, - removing, - ); - assignments.truncate(maximum_allowed_voters as usize); + Ok((solution, score, size)) } /// Greedily reduce the size of the solution to fit into the block w.r.t length. @@ -427,7 +545,7 @@ impl Pallet { max_allowed_length: u32, assignments: &mut Vec>, encoded_size_of: impl Fn(&[IndexAssignmentOf]) -> Result, - ) -> Result<(), MinerError> { + ) -> Result<(), MinerError> { // Perform a binary search for the max subset of which can fit into the allowed // length. Having discovered that, we can truncate efficiently. let max_allowed_length: usize = max_allowed_length.saturated_into(); @@ -470,7 +588,7 @@ impl Pallet { // after this point, we never error. // check before edit. - log!( + log_no_system!( debug, "from {} assignments, truncating to {} for length, removing {}", assignments.len(), @@ -482,10 +600,45 @@ impl Pallet { Ok(()) } + /// Greedily reduce the size of the solution to fit into the block w.r.t. weight. + /// + /// The weight of the solution is foremost a function of the number of voters (i.e. + /// `assignments.len()`). Aside from this, the other components of the weight are invariant. The + /// number of winners shall not be changed (otherwise the solution is invalid) and the + /// `ElectionSize` is merely a representation of the total number of stakers. + /// + /// Thus, we reside to stripping away some voters from the `assignments`. + /// + /// Note that the solution is already computed, and the winners are elected based on the merit + /// of the entire stake in the system. Nonetheless, some of the voters will be removed further + /// down the line. + /// + /// Indeed, the score must be computed **after** this step. If this step reduces the score too + /// much or remove a winner, then the solution must be discarded **after** this step. + pub fn trim_assignments_weight( + desired_targets: u32, + size: SolutionOrSnapshotSize, + max_weight: Weight, + assignments: &mut Vec>, + ) { + let maximum_allowed_voters = + Self::maximum_voter_for_weight(desired_targets, size, max_weight); + let removing: usize = + assignments.len().saturating_sub(maximum_allowed_voters.saturated_into()); + log_no_system!( + debug, + "from {} assignments, truncating to {} for weight, removing {}", + assignments.len(), + maximum_allowed_voters, + removing, + ); + assignments.truncate(maximum_allowed_voters as usize); + } + /// Find the maximum `len` that a solution can have in order to fit into the block weight. /// /// This only returns a value between zero and `size.nominators`. - pub fn maximum_voter_for_weight( + pub fn maximum_voter_for_weight( desired_winners: u32, size: SolutionOrSnapshotSize, max_weight: Weight, @@ -499,7 +652,7 @@ impl Pallet { // helper closures. let weight_with = |active_voters: u32| -> Weight { - W::submit_unsigned(size.voters, size.targets, active_voters, desired_winners) + T::solution_weight(size.voters, size.targets, active_voters, desired_winners) }; let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result { @@ -553,176 +706,65 @@ impl Pallet { ); final_decision } - - /// Checks if an execution of the offchain worker is permitted at the given block number, or - /// not. - /// - /// This makes sure that - /// 1. we don't run on previous blocks in case of a re-org - /// 2. we don't run twice within a window of length `T::OffchainRepeat`. - /// - /// Returns `Ok(())` if offchain worker limit is respected, `Err(reason)` otherwise. If `Ok()` - /// is returned, `now` is written in storage and will be used in further calls as the baseline. - pub fn ensure_offchain_repeat_frequency(now: T::BlockNumber) -> Result<(), MinerError> { - let threshold = T::OffchainRepeat::get(); - let last_block = StorageValueRef::persistent(OFFCHAIN_LAST_BLOCK); - - let mutate_stat = last_block.mutate::<_, &'static str, _>( - |maybe_head: Result, _>| { - match maybe_head { - Ok(Some(head)) if now < head => Err("fork."), - Ok(Some(head)) if now >= head && now <= head + threshold => - Err("recently executed."), - Ok(Some(head)) if now > head + threshold => { - // we can run again now. Write the new head. - Ok(now) - }, - _ => { - // value doesn't exists. Probably this node just booted up. Write, and run - Ok(now) - }, - } - }, - ); - - match mutate_stat { - // all good - Ok(_) => Ok(()), - // failed to write. - Err(MutateStorageError::ConcurrentModification(_)) => - Err(MinerError::Lock("failed to write to offchain db (concurrent modification).")), - // fork etc. - Err(MutateStorageError::ValueFunctionFailed(why)) => Err(MinerError::Lock(why)), - } - } - - /// Do the basics checks that MUST happen during the validation and pre-dispatch of an unsigned - /// transaction. - /// - /// Can optionally also be called during dispatch, if needed. - /// - /// NOTE: Ideally, these tests should move more and more outside of this and more to the miner's - /// code, so that we do less and less storage reads here. - pub fn unsigned_pre_dispatch_checks( - raw_solution: &RawSolution>, - ) -> DispatchResult { - // ensure solution is timely. Don't panic yet. This is a cheap check. - ensure!(Self::current_phase().is_unsigned_open(), Error::::PreDispatchEarlySubmission); - - // ensure round is current - ensure!(Self::round() == raw_solution.round, Error::::OcwCallWrongEra); - - // ensure correct number of winners. - ensure!( - Self::desired_targets().unwrap_or_default() == - raw_solution.solution.unique_targets().len() as u32, - Error::::PreDispatchWrongWinnerCount, - ); - - // ensure score is being improved. Panic henceforth. - ensure!( - Self::queued_solution().map_or(true, |q: ReadySolution<_>| raw_solution - .score - .strict_threshold_better(q.score, T::BetterUnsignedThreshold::get())), - Error::::PreDispatchWeakSubmission, - ); - - Ok(()) - } } #[cfg(test)] mod max_weight { #![allow(unused_variables)] use super::*; - use crate::mock::MultiPhase; - - struct TestWeight; - impl crate::weights::WeightInfo for TestWeight { - fn elect_queued(a: u32, d: u32) -> Weight { - unreachable!() - } - fn create_snapshot_internal(v: u32, t: u32) -> Weight { - unreachable!() - } - fn on_initialize_nothing() -> Weight { - unreachable!() - } - fn on_initialize_open_signed() -> Weight { - unreachable!() - } - fn on_initialize_open_unsigned() -> Weight { - unreachable!() - } - fn finalize_signed_phase_accept_solution() -> Weight { - unreachable!() - } - fn finalize_signed_phase_reject_solution() -> Weight { - unreachable!() - } - fn submit() -> Weight { - unreachable!() - } - fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight { - (0 * v + 0 * t + 1000 * a + 0 * d) as Weight - } - fn feasibility_check(v: u32, _t: u32, a: u32, d: u32) -> Weight { - unreachable!() - } - } - + use crate::mock::{MockWeightInfo, Runtime}; #[test] fn find_max_voter_binary_search_works() { let w = SolutionOrSnapshotSize { voters: 10, targets: 0 }; - - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 0), 0); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1), 0); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 999), 0); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1000), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1001), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1990), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1999), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2000), 2); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2001), 2); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2010), 2); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2990), 2); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2999), 2); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 3000), 3); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 3333), 3); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 5500), 5); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 7777), 7); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 9999), 9); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 10_000), 10); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 10_999), 10); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 11_000), 10); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 22_000), 10); + MockWeightInfo::set(crate::mock::MockedWeightInfo::Complex); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 0), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 999), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1000), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1001), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1990), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1999), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2000), 2); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2001), 2); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2010), 2); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2990), 2); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2999), 2); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 3000), 3); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 3333), 3); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 5500), 5); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 7777), 7); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 9999), 9); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 10_000), 10); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 10_999), 10); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 11_000), 10); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 22_000), 10); let w = SolutionOrSnapshotSize { voters: 1, targets: 0 }; - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 0), 0); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1), 0); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 999), 0); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1000), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1001), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1990), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1999), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2000), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2001), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2010), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 3333), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 0), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 999), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1000), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1001), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1990), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1999), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2000), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2001), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2010), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 3333), 1); let w = SolutionOrSnapshotSize { voters: 2, targets: 0 }; - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 0), 0); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1), 0); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 999), 0); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1000), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1001), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 1999), 1); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2000), 2); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2001), 2); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 2010), 2); - assert_eq!(MultiPhase::maximum_voter_for_weight::(0, w, 3333), 2); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 0), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 999), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1000), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1001), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1999), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2000), 2); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2001), 2); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2010), 2); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, 3333), 2); } } @@ -988,8 +1030,7 @@ mod tests { assert_eq!(MultiPhase::desired_targets().unwrap(), 2); // mine seq_phragmen solution with 2 iters. - let (solution, witness) = - MultiPhase::mine_solution::<::Solver>().unwrap(); + let (solution, witness) = MultiPhase::mine_solution().unwrap(); // ensure this solution is valid. assert!(MultiPhase::queued_solution().is_none()); @@ -1002,14 +1043,13 @@ mod tests { fn miner_trims_weight() { ExtBuilder::default() .miner_weight(100) - .mock_weight_info(true) + .mock_weight_info(crate::mock::MockedWeightInfo::Basic) .build_and_execute(|| { roll_to(25); assert!(MultiPhase::current_phase().is_unsigned()); - let (raw, witness) = - MultiPhase::mine_solution::<::Solver>().unwrap(); - let solution_weight = ::WeightInfo::submit_unsigned( + let (raw, witness) = MultiPhase::mine_solution().unwrap(); + let solution_weight = ::solution_weight( witness.voters, witness.targets, raw.solution.voter_count() as u32, @@ -1022,9 +1062,8 @@ mod tests { // now reduce the max weight ::set(25); - let (raw, witness) = - MultiPhase::mine_solution::<::Solver>().unwrap(); - let solution_weight = ::WeightInfo::submit_unsigned( + let (raw, witness) = MultiPhase::mine_solution().unwrap(); + let solution_weight = ::solution_weight( witness.voters, witness.targets, raw.solution.voter_count() as u32, @@ -1044,8 +1083,7 @@ mod tests { assert!(MultiPhase::current_phase().is_unsigned()); // Force the number of winners to be bigger to fail - let (mut solution, _) = - MultiPhase::mine_solution::<::Solver>().unwrap(); + let (mut solution, _) = MultiPhase::mine_solution().unwrap(); solution.solution.votes1[0].1 = 4; assert_eq!( @@ -1460,8 +1498,12 @@ mod tests { let solution_clone = solution.clone(); // when - MultiPhase::trim_assignments_length(encoded_len, &mut assignments, encoded_size_of) - .unwrap(); + Miner::::trim_assignments_length( + encoded_len, + &mut assignments, + encoded_size_of, + ) + .unwrap(); // then let solution = SolutionOf::::try_from(assignments.as_slice()).unwrap(); @@ -1481,7 +1523,7 @@ mod tests { let solution_clone = solution.clone(); // when - MultiPhase::trim_assignments_length( + Miner::::trim_assignments_length( encoded_len as u32 - 1, &mut assignments, encoded_size_of, @@ -1514,8 +1556,12 @@ mod tests { .unwrap(); // when - MultiPhase::trim_assignments_length(encoded_len - 1, &mut assignments, encoded_size_of) - .unwrap(); + Miner::::trim_assignments_length( + encoded_len - 1, + &mut assignments, + encoded_size_of, + ) + .unwrap(); // then assert_eq!(assignments.len(), count - 1, "we must have removed exactly one assignment"); @@ -1542,11 +1588,11 @@ mod tests { assert_eq!(min_solution_size, SolutionOf::::LIMIT); // all of this should not panic. - MultiPhase::trim_assignments_length(0, &mut assignments, encoded_size_of.clone()) + Miner::::trim_assignments_length(0, &mut assignments, encoded_size_of.clone()) .unwrap(); - MultiPhase::trim_assignments_length(1, &mut assignments, encoded_size_of.clone()) + Miner::::trim_assignments_length(1, &mut assignments, encoded_size_of.clone()) .unwrap(); - MultiPhase::trim_assignments_length( + Miner::::trim_assignments_length( min_solution_size as u32, &mut assignments, encoded_size_of, @@ -1563,7 +1609,7 @@ mod tests { // trim to min solution size. let min_solution_size = SolutionOf::::LIMIT as u32; - MultiPhase::trim_assignments_length( + Miner::::trim_assignments_length( min_solution_size, &mut assignments, encoded_size_of, @@ -1582,15 +1628,15 @@ mod tests { roll_to(25); // how long would the default solution be? - let solution = MultiPhase::mine_solution::<::Solver>().unwrap(); - let max_length = ::MinerMaxLength::get(); + let solution = MultiPhase::mine_solution().unwrap(); + let max_length = ::MaxLength::get(); let solution_size = solution.0.solution.encoded_size(); assert!(solution_size <= max_length as usize); // now set the max size to less than the actual size and regenerate - ::MinerMaxLength::set(solution_size as u32 - 1); - let solution = MultiPhase::mine_solution::<::Solver>().unwrap(); - let max_length = ::MinerMaxLength::get(); + ::MaxLength::set(solution_size as u32 - 1); + let solution = MultiPhase::mine_solution().unwrap(); + let max_length = ::MaxLength::get(); let solution_size = solution.0.solution.encoded_size(); assert!(solution_size <= max_length as usize); }); From d602397a0bbb24b5d627795b797259a44a5e29e9 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 12 May 2022 03:34:38 +0200 Subject: [PATCH 0790/1472] Whitelist Transactional key (#11394) * Make constants public Signed-off-by: Oliver Tale-Yazdi * Whitelist the transactional layer Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- frame/benchmarking/src/lib.rs | 6 + frame/nomination-pools/src/weights.rs | 160 +++++++++------------ frame/support/src/storage/transactional.rs | 6 +- 3 files changed, 80 insertions(+), 92 deletions(-) diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index ca836e431e5ee..afd53915cc397 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -1021,6 +1021,12 @@ macro_rules! impl_benchmark { $crate::whitelisted_caller::() ); whitelist.push(whitelisted_caller_key.into()); + // Whitelist the transactional layer. + let transactional_layer_key = $crate::TrackedStorageKey::new( + $crate::frame_support::storage::transactional::TRANSACTION_LEVEL_KEY.into() + ); + whitelist.push(transactional_layer_key); + $crate::benchmarking::set_whitelist(whitelist); let mut results: $crate::Vec<$crate::BenchmarkResult> = $crate::Vec::new(); diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index 0b2a84ddd2ac3..6a5a38ac0abf7 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-11, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -64,7 +64,6 @@ pub trait WeightInfo { /// Weights for pallet_nomination_pools using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools MinJoinBond (r:1 w:0) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -79,11 +78,10 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (119_253_000 as Weight) - .saturating_add(T::DbWeight::get().reads(18 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) + (122_806_000 as Weight) + .saturating_add(T::DbWeight::get().reads(17 as Weight)) + .saturating_add(T::DbWeight::get().writes(11 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) @@ -94,11 +92,10 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (110_157_000 as Weight) - .saturating_add(T::DbWeight::get().reads(14 as Weight)) - .saturating_add(T::DbWeight::get().writes(13 as Weight)) + (114_398_000 as Weight) + .saturating_add(T::DbWeight::get().reads(13 as Weight)) + .saturating_add(T::DbWeight::get().writes(12 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) @@ -109,21 +106,19 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:2 w:2) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (124_003_000 as Weight) - .saturating_add(T::DbWeight::get().reads(14 as Weight)) - .saturating_add(T::DbWeight::get().writes(13 as Weight)) + (128_370_000 as Weight) + .saturating_add(T::DbWeight::get().reads(13 as Weight)) + .saturating_add(T::DbWeight::get().writes(12 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (51_767_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + (52_338_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) @@ -139,23 +134,21 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (116_959_000 as Weight) - .saturating_add(T::DbWeight::get().reads(19 as Weight)) - .saturating_add(T::DbWeight::get().writes(14 as Weight)) + (120_866_000 as Weight) + .saturating_add(T::DbWeight::get().reads(18 as Weight)) + .saturating_add(T::DbWeight::get().writes(13 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (41_124_000 as Weight) + (42_038_000 as Weight) // Standard Error: 0 .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: NominationPools BondedPools (r:1 w:1) @@ -165,13 +158,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (80_654_000 as Weight) + (83_220_000 as Weight) // Standard Error: 0 - .saturating_add((50_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(9 as Weight)) - .saturating_add(T::DbWeight::get().writes(8 as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(8 as Weight)) + .saturating_add(T::DbWeight::get().writes(7 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: NominationPools BondedPools (r:1 w:1) @@ -192,11 +184,10 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (140_296_000 as Weight) - .saturating_add(T::DbWeight::get().reads(20 as Weight)) - .saturating_add(T::DbWeight::get().writes(17 as Weight)) + (143_981_000 as Weight) + .saturating_add(T::DbWeight::get().reads(19 as Weight)) + .saturating_add(T::DbWeight::get().writes(16 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: NominationPools MinCreateBond (r:1 w:0) // Storage: NominationPools MinJoinBond (r:1 w:0) @@ -220,9 +211,9 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (130_543_000 as Weight) - .saturating_add(T::DbWeight::get().reads(23 as Weight)) - .saturating_add(T::DbWeight::get().writes(16 as Weight)) + (134_974_000 as Weight) + .saturating_add(T::DbWeight::get().reads(22 as Weight)) + .saturating_add(T::DbWeight::get().writes(15 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -237,9 +228,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (46_152_000 as Weight) - // Standard Error: 15_000 - .saturating_add((2_114_000 as Weight).saturating_mul(n as Weight)) + (47_085_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_222_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(5 as Weight)) @@ -247,7 +238,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (23_544_000 as Weight) + (24_192_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -255,7 +246,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) fn set_metadata(n: u32, ) -> Weight { - (11_032_000 as Weight) + (11_448_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -267,12 +258,12 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (2_910_000 as Weight) + (2_829_000 as Weight) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (18_608_000 as Weight) + (19_017_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -280,7 +271,6 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools MinJoinBond (r:1 w:0) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -295,11 +285,10 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (119_253_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(18 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + (122_806_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(17 as Weight)) + .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) @@ -310,11 +299,10 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (110_157_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(14 as Weight)) - .saturating_add(RocksDbWeight::get().writes(13 as Weight)) + (114_398_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(13 as Weight)) + .saturating_add(RocksDbWeight::get().writes(12 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) @@ -325,21 +313,19 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:2 w:2) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (124_003_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(14 as Weight)) - .saturating_add(RocksDbWeight::get().writes(13 as Weight)) + (128_370_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(13 as Weight)) + .saturating_add(RocksDbWeight::get().writes(12 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (51_767_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + (52_338_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) @@ -355,23 +341,21 @@ impl WeightInfo for () { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (116_959_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(19 as Weight)) - .saturating_add(RocksDbWeight::get().writes(14 as Weight)) + (120_866_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(18 as Weight)) + .saturating_add(RocksDbWeight::get().writes(13 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (41_124_000 as Weight) + (42_038_000 as Weight) // Standard Error: 0 .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: NominationPools BondedPools (r:1 w:1) @@ -381,13 +365,12 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (80_654_000 as Weight) + (83_220_000 as Weight) // Standard Error: 0 - .saturating_add((50_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(9 as Weight)) - .saturating_add(RocksDbWeight::get().writes(8 as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(8 as Weight)) + .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: NominationPools BondedPools (r:1 w:1) @@ -408,11 +391,10 @@ impl WeightInfo for () { // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (140_296_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(20 as Weight)) - .saturating_add(RocksDbWeight::get().writes(17 as Weight)) + (143_981_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(19 as Weight)) + .saturating_add(RocksDbWeight::get().writes(16 as Weight)) } - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: NominationPools MinCreateBond (r:1 w:0) // Storage: NominationPools MinJoinBond (r:1 w:0) @@ -436,9 +418,9 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (130_543_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(23 as Weight)) - .saturating_add(RocksDbWeight::get().writes(16 as Weight)) + (134_974_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(22 as Weight)) + .saturating_add(RocksDbWeight::get().writes(15 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -453,9 +435,9 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (46_152_000 as Weight) - // Standard Error: 15_000 - .saturating_add((2_114_000 as Weight).saturating_mul(n as Weight)) + (47_085_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_222_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) @@ -463,7 +445,7 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (23_544_000 as Weight) + (24_192_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -471,7 +453,7 @@ impl WeightInfo for () { // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) fn set_metadata(n: u32, ) -> Weight { - (11_032_000 as Weight) + (11_448_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -483,12 +465,12 @@ impl WeightInfo for () { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (2_910_000 as Weight) + (2_829_000 as Weight) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (18_608_000 as Weight) + (19_017_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/support/src/storage/transactional.rs b/frame/support/src/storage/transactional.rs index d1c59d44e2581..c46eb9258e0ca 100644 --- a/frame/support/src/storage/transactional.rs +++ b/frame/support/src/storage/transactional.rs @@ -30,11 +30,11 @@ use sp_io::storage::{commit_transaction, rollback_transaction, start_transaction use sp_runtime::{DispatchError, TransactionOutcome, TransactionalError}; /// The type that is being used to store the current number of active layers. -type Layer = u32; +pub type Layer = u32; /// The key that is holds the current number of active layers. -const TRANSACTION_LEVEL_KEY: &[u8] = b":transaction_level:"; +pub const TRANSACTION_LEVEL_KEY: &[u8] = b":transaction_level:"; /// The maximum number of nested layers. -const TRANSACTIONAL_LIMIT: Layer = 255; +pub const TRANSACTIONAL_LIMIT: Layer = 255; /// Returns the current number of nested transactional layers. fn get_transaction_level() -> Layer { From 7d233c2446b5a60662400a0a4bcfb78bb3b79ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 12 May 2022 13:02:29 +0200 Subject: [PATCH 0791/1472] Make clippy happy on latest nightly (#11403) Co-authored-by: Vladimir Istyufeev --- bin/utils/chain-spec-builder/src/main.rs | 2 +- client/service/src/error.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index e972e130fcf78..641416154115b 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -159,7 +159,7 @@ fn generate_chain_spec( Default::default(), ); - chain_spec.as_json(false).map_err(|err| err) + chain_spec.as_json(false) } fn generate_authority_keys_and_store(seeds: &[String], keystore_path: &Path) -> Result<(), String> { diff --git a/client/service/src/error.rs b/client/service/src/error.rs index be2199de2643d..0d702c7f37b98 100644 --- a/client/service/src/error.rs +++ b/client/service/src/error.rs @@ -71,7 +71,7 @@ impl<'a> From<&'a str> for Error { } } -impl<'a> From for Error { +impl From for Error { fn from(s: String) -> Self { Error::Other(s) } From c6c2179b5b69a4ff7fa653afa8f2ca16d7721754 Mon Sep 17 00:00:00 2001 From: Tarek Mohamed Abdalla Date: Fri, 13 May 2022 19:21:21 +0200 Subject: [PATCH 0792/1472] [Tests] [pallet-timestamp] Add tests for OnTimestampSet. (#11323) * NF: move tests mod to another file * NF: separate test setup to mock mod * test: check if OnTimestampSet ran correctly. * docs: add license header. * fixup! NF: separate test setup to mock mod * NF: formatting changes --- frame/timestamp/src/benchmarking.rs | 2 +- frame/timestamp/src/lib.rs | 108 +-------------------------- frame/timestamp/src/mock.rs | 111 ++++++++++++++++++++++++++++ frame/timestamp/src/tests.rs | 52 +++++++++++++ 4 files changed, 168 insertions(+), 105 deletions(-) create mode 100644 frame/timestamp/src/mock.rs create mode 100644 frame/timestamp/src/tests.rs diff --git a/frame/timestamp/src/benchmarking.rs b/frame/timestamp/src/benchmarking.rs index 0da71dbdd1a59..8974eb95692af 100644 --- a/frame/timestamp/src/benchmarking.rs +++ b/frame/timestamp/src/benchmarking.rs @@ -56,5 +56,5 @@ benchmarks! { ensure!(!DidUpdate::::exists(), "Time was not removed."); } - impl_benchmark_test_suite!(Timestamp, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Timestamp, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index c75a0ac9765b9..81ed67913c2e6 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -103,6 +103,10 @@ #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; pub mod weights; use frame_support::traits::{OnTimestampSet, Time, UnixTime}; @@ -309,107 +313,3 @@ impl UnixTime for Pallet { core::time::Duration::from_millis(now.saturated_into::()) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate as pallet_timestamp; - - use frame_support::{ - assert_ok, parameter_types, - traits::{ConstU32, ConstU64}, - }; - use sp_core::H256; - use sp_io::TestExternalities; - use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - }; - - pub fn new_test_ext() -> TestExternalities { - let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - TestExternalities::new(t) - } - - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; - type Block = frame_system::mocking::MockBlock; - - frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - } - ); - - parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); - } - impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Call = Call; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; - } - - impl Config for Test { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = ConstU64<5>; - type WeightInfo = (); - } - - #[test] - fn timestamp_works() { - new_test_ext().execute_with(|| { - Timestamp::set_timestamp(42); - assert_ok!(Timestamp::set(Origin::none(), 69)); - assert_eq!(Timestamp::now(), 69); - }); - } - - #[test] - #[should_panic(expected = "Timestamp must be updated only once in the block")] - fn double_timestamp_should_fail() { - new_test_ext().execute_with(|| { - Timestamp::set_timestamp(42); - assert_ok!(Timestamp::set(Origin::none(), 69)); - let _ = Timestamp::set(Origin::none(), 70); - }); - } - - #[test] - #[should_panic( - expected = "Timestamp must increment by at least between sequential blocks" - )] - fn block_period_minimum_enforced() { - new_test_ext().execute_with(|| { - Timestamp::set_timestamp(42); - let _ = Timestamp::set(Origin::none(), 46); - }); - } -} diff --git a/frame/timestamp/src/mock.rs b/frame/timestamp/src/mock.rs new file mode 100644 index 0000000000000..9536414c54db6 --- /dev/null +++ b/frame/timestamp/src/mock.rs @@ -0,0 +1,111 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests Utilities. + +use super::*; +use crate as pallet_timestamp; +use sp_std::cell::RefCell; + +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, +}; +use sp_core::H256; +use sp_io::TestExternalities; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; +type Moment = u64; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + } +); + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(1024); +} +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = Call; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +thread_local! { + pub static CAPTURED_MOMENT: RefCell> = RefCell::new(None); +} + +pub struct MockOnTimestampSet; +impl OnTimestampSet for MockOnTimestampSet { + fn on_timestamp_set(moment: Moment) { + CAPTURED_MOMENT.with(|x| *x.borrow_mut() = Some(moment)); + } +} + +impl Config for Test { + type Moment = Moment; + type OnTimestampSet = MockOnTimestampSet; + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +pub(crate) fn clear_captured_moment() { + CAPTURED_MOMENT.with(|x| *x.borrow_mut() = None); +} + +pub(crate) fn get_captured_moment() -> Option { + CAPTURED_MOMENT.with(|x| x.borrow().clone()) +} + +pub(crate) fn new_test_ext() -> TestExternalities { + let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + clear_captured_moment(); + TestExternalities::new(t) +} diff --git a/frame/timestamp/src/tests.rs b/frame/timestamp/src/tests.rs new file mode 100644 index 0000000000000..f52ba7849c951 --- /dev/null +++ b/frame/timestamp/src/tests.rs @@ -0,0 +1,52 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for the Timestamp module. + +use crate::mock::*; +use frame_support::assert_ok; + +#[test] +fn timestamp_works() { + new_test_ext().execute_with(|| { + Timestamp::set_timestamp(42); + assert_ok!(Timestamp::set(Origin::none(), 69)); + assert_eq!(Timestamp::now(), 69); + assert_eq!(Some(69), get_captured_moment()); + }); +} + +#[test] +#[should_panic(expected = "Timestamp must be updated only once in the block")] +fn double_timestamp_should_fail() { + new_test_ext().execute_with(|| { + Timestamp::set_timestamp(42); + assert_ok!(Timestamp::set(Origin::none(), 69)); + let _ = Timestamp::set(Origin::none(), 70); + }); +} + +#[test] +#[should_panic( + expected = "Timestamp must increment by at least between sequential blocks" +)] +fn block_period_minimum_enforced() { + new_test_ext().execute_with(|| { + Timestamp::set_timestamp(42); + let _ = Timestamp::set(Origin::none(), 46); + }); +} From 97a2bf9b26357cbefa56cabbd1c4579240e170ff Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sat, 14 May 2022 10:17:53 +0300 Subject: [PATCH 0793/1472] Network sync refactoring (part 3) (#11347) * Move `light.v1.proto` schema into new crate `sc-network-light` * Move `sc_network::light_client_requests` and submodule to `sc_network_light::light_client_requests` * Fix apparently outdated reference in documentation and visibility modifier * Fix rustdoc check * Update lock file --- Cargo.lock | 20 +++++++++++ Cargo.toml | 3 +- client/network/Cargo.toml | 1 + client/network/build.rs | 2 +- client/network/light/Cargo.toml | 33 +++++++++++++++++++ client/network/light/build.rs | 5 +++ client/network/light/src/lib.rs | 22 +++++++++++++ .../{ => light}/src/light_client_requests.rs | 0 .../src/light_client_requests/handler.rs | 5 +-- client/network/light/src/schema.rs | 25 ++++++++++++++ .../{ => light}/src/schema/light.v1.proto | 0 client/network/src/config.rs | 8 ++--- client/network/src/lib.rs | 2 +- client/network/src/schema.rs | 6 ---- client/network/src/service/tests.rs | 4 +-- .../network/sync/src/block_request_handler.rs | 4 +-- 16 files changed, 120 insertions(+), 20 deletions(-) create mode 100644 client/network/light/Cargo.toml create mode 100644 client/network/light/build.rs create mode 100644 client/network/light/src/lib.rs rename client/network/{ => light}/src/light_client_requests.rs (100%) rename client/network/{ => light}/src/light_client_requests/handler.rs (98%) create mode 100644 client/network/light/src/schema.rs rename client/network/{ => light}/src/schema/light.v1.proto (100%) diff --git a/Cargo.lock b/Cargo.lock index 68272e1df9c8c..1683cc2b06b69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8509,6 +8509,7 @@ dependencies = [ "sc-client-api", "sc-consensus", "sc-network-common", + "sc-network-light", "sc-network-sync", "sc-peerset", "sc-utils", @@ -8564,6 +8565,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "sc-network-light" +version = "0.10.0-dev" +dependencies = [ + "futures", + "libp2p", + "log", + "parity-scale-codec", + "prost", + "prost-build", + "sc-client-api", + "sc-network-common", + "sc-peerset", + "sp-blockchain", + "sp-core", + "sp-runtime", + "thiserror", +] + [[package]] name = "sc-network-sync" version = "0.10.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 39ccceeb3a030..41739fe6f1ebc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,8 +42,9 @@ members = [ "client/informant", "client/keystore", "client/network", - "client/network/common", "client/network-gossip", + "client/network/common", + "client/network/light", "client/network/sync", "client/network/test", "client/offchain", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 51e7e762f5292..7e12d9862f8ef 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -51,6 +51,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sc-network-common = { version = "0.10.0-dev", path = "./common" } +sc-network-light = { version = "0.10.0-dev", path = "./light" } sc-network-sync = { version = "0.10.0-dev", path = "./sync" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } sc-utils = { version = "4.0.0-dev", path = "../utils" } diff --git a/client/network/build.rs b/client/network/build.rs index f551f61dab3d4..671277230a774 100644 --- a/client/network/build.rs +++ b/client/network/build.rs @@ -1,4 +1,4 @@ -const PROTOS: &[&str] = &["src/schema/light.v1.proto", "src/schema/bitswap.v1.2.0.proto"]; +const PROTOS: &[&str] = &["src/schema/bitswap.v1.2.0.proto"]; fn main() { prost_build::compile_protos(PROTOS, &["src/schema"]).unwrap(); diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml new file mode 100644 index 0000000000000..8bbbce9274c0c --- /dev/null +++ b/client/network/light/Cargo.toml @@ -0,0 +1,33 @@ +[package] +description = "Substrate light network protocol" +name = "sc-network-light" +version = "0.10.0-dev" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +documentation = "https://docs.rs/sc-network-light" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +prost-build = "0.9" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ + "derive", +] } +futures = "0.3.21" +libp2p = "0.44.0" +log = "0.4.16" +prost = "0.9" +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-network-common = { version = "0.10.0-dev", path = "../common" } +sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +thiserror = "1.0" diff --git a/client/network/light/build.rs b/client/network/light/build.rs new file mode 100644 index 0000000000000..9c44bcd293181 --- /dev/null +++ b/client/network/light/build.rs @@ -0,0 +1,5 @@ +const PROTOS: &[&str] = &["src/schema/light.v1.proto"]; + +fn main() { + prost_build::compile_protos(PROTOS, &["src/schema"]).unwrap(); +} diff --git a/client/network/light/src/lib.rs b/client/network/light/src/lib.rs new file mode 100644 index 0000000000000..2b7cf226f90dd --- /dev/null +++ b/client/network/light/src/lib.rs @@ -0,0 +1,22 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Light client data structures of the networking layer. + +pub mod light_client_requests; +mod schema; diff --git a/client/network/src/light_client_requests.rs b/client/network/light/src/light_client_requests.rs similarity index 100% rename from client/network/src/light_client_requests.rs rename to client/network/light/src/light_client_requests.rs diff --git a/client/network/src/light_client_requests/handler.rs b/client/network/light/src/light_client_requests/handler.rs similarity index 98% rename from client/network/src/light_client_requests/handler.rs rename to client/network/light/src/light_client_requests/handler.rs index bf65cba5f82e5..3c87ccfd6ed9f 100644 --- a/client/network/src/light_client_requests/handler.rs +++ b/client/network/light/src/light_client_requests/handler.rs @@ -22,9 +22,10 @@ //! `crate::request_responses::RequestResponsesBehaviour` with //! [`LightClientRequestHandler`](handler::LightClientRequestHandler). -use crate::{schema, PeerId}; +use crate::schema; use codec::{self, Decode, Encode}; use futures::{channel::mpsc, prelude::*}; +use libp2p::PeerId; use log::{debug, trace}; use prost::Message; use sc_client_api::{ProofProvider, StorageProof}; @@ -55,7 +56,7 @@ where B: Block, Client: ProofProvider + Send + Sync + 'static, { - /// Create a new [`sc_network_sync::block_request_handler::BlockRequestHandler`]. + /// Create a new [`LightClientRequestHandler`]. pub fn new(protocol_id: &ProtocolId, client: Arc) -> (Self, ProtocolConfig) { // For now due to lack of data on light client request handling in production systems, this // value is chosen to match the block request limit. diff --git a/client/network/light/src/schema.rs b/client/network/light/src/schema.rs new file mode 100644 index 0000000000000..09cc82cc2811a --- /dev/null +++ b/client/network/light/src/schema.rs @@ -0,0 +1,25 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Include sources generated from protobuf definitions. + +pub(crate) mod v1 { + pub(crate) mod light { + include!(concat!(env!("OUT_DIR"), "/api.v1.light.rs")); + } +} diff --git a/client/network/src/schema/light.v1.proto b/client/network/light/src/schema/light.v1.proto similarity index 100% rename from client/network/src/schema/light.v1.proto rename to client/network/light/src/schema/light.v1.proto diff --git a/client/network/src/config.rs b/client/network/src/config.rs index cfb06331b55a1..e44977e5be6b3 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -122,10 +122,10 @@ where /// Request response configuration for the light client request protocol. /// /// Can be constructed either via - /// [`crate::light_client_requests::generate_protocol_config`] allowing outgoing but not - /// incoming requests, or constructed via - /// [`crate::light_client_requests::handler::LightClientRequestHandler::new`] allowing - /// both outgoing and incoming requests. + /// [`sc_network_light::light_client_requests::generate_protocol_config`] allowing outgoing but + /// not incoming requests, or constructed via + /// [`sc_network_light::light_client_requests::handler::LightClientRequestHandler::new`] + /// allowing both outgoing and incoming requests. pub light_client_request_protocol_config: RequestResponseConfig, /// Request response configuration for the state request protocol. diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 3957aab22cca9..fff30550eb8c9 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -257,7 +257,6 @@ mod utils; pub mod bitswap; pub mod config; pub mod error; -pub mod light_client_requests; pub mod network_state; pub mod transactions; @@ -267,6 +266,7 @@ pub use protocol::{ event::{DhtEvent, Event, ObservedRole}, PeerInfo, }; +pub use sc_network_light::light_client_requests; pub use sc_network_sync::{ block_request_handler, state::StateDownloadProgress, diff --git a/client/network/src/schema.rs b/client/network/src/schema.rs index 80301a59c29ef..4893bc28a7355 100644 --- a/client/network/src/schema.rs +++ b/client/network/src/schema.rs @@ -18,12 +18,6 @@ //! Include sources generated from protobuf definitions. -pub mod v1 { - pub mod light { - include!(concat!(env!("OUT_DIR"), "/api.v1.light.rs")); - } -} - pub mod bitswap { include!(concat!(env!("OUT_DIR"), "/bitswap.message.rs")); } diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 36205f32d33c6..808546d67fc7c 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -17,13 +17,13 @@ // along with this program. If not, see . use crate::{ - config, light_client_requests::handler::LightClientRequestHandler, - state_request_handler::StateRequestHandler, Event, NetworkService, NetworkWorker, + config, state_request_handler::StateRequestHandler, Event, NetworkService, NetworkWorker, }; use futures::prelude::*; use libp2p::PeerId; use sc_network_common::config::ProtocolId; +use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::block_request_handler::BlockRequestHandler; use sp_runtime::traits::{Block as BlockT, Header as _}; use std::{borrow::Cow, sync::Arc, time::Duration}; diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index b9ffd24cee4c7..78d6a1a7d1680 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -75,9 +75,7 @@ pub fn generate_protocol_config(protocol_id: &ProtocolId) -> ProtocolConfig { } /// Generate the block protocol name from chain specific protocol identifier. -// Visibility `pub(crate)` to allow `crate::light_client_requests::sender` to generate block request -// protocol name and send block requests. -pub(crate) fn generate_protocol_name(protocol_id: &ProtocolId) -> String { +fn generate_protocol_name(protocol_id: &ProtocolId) -> String { format!("/{}/sync/2", protocol_id.as_ref()) } From 51eac35742c423b12682c5f6e06455adf70e18dd Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sun, 15 May 2022 08:25:48 +0100 Subject: [PATCH 0794/1472] make pool roles optional (#11411) * make pool roles optional * undo lock file changes? * add migration * Fix * fix review comments --- Cargo.lock | 1 + frame/nomination-pools/Cargo.toml | 2 + .../nomination-pools/benchmarking/src/lib.rs | 24 +-- frame/nomination-pools/src/lib.rs | 108 +++++++++---- frame/nomination-pools/src/migration.rs | 105 ++++++++++++ frame/nomination-pools/src/tests.rs | 149 ++++++++++++++---- frame/staking/src/lib.rs | 7 +- frame/staking/src/tests.rs | 76 ++++++++- 8 files changed, 400 insertions(+), 72 deletions(-) create mode 100644 frame/nomination-pools/src/migration.rs diff --git a/Cargo.lock b/Cargo.lock index 1683cc2b06b69..1995ebb46023e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5892,6 +5892,7 @@ version = "1.0.0" dependencies = [ "frame-support", "frame-system", + "log", "pallet-balances", "parity-scale-codec", "scale-info", diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index 8c2f9daf2777b..1ac8caa5f64b4 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -23,6 +23,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +log = { version = "0.4.0", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } @@ -42,4 +43,5 @@ std = [ "sp-std/std", "sp-staking/std", "sp-core/std", + "log/std", ] diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index aa4c093dcf0d4..275b914cda297 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -526,9 +526,9 @@ frame_benchmarking::benchmarks! { member_counter: 1, roles: PoolRoles { depositor: depositor.clone(), - root: depositor.clone(), - nominator: depositor.clone(), - state_toggler: depositor.clone(), + root: Some(depositor.clone()), + nominator: Some(depositor.clone()), + state_toggler: Some(depositor.clone()), }, } ); @@ -567,9 +567,9 @@ frame_benchmarking::benchmarks! { member_counter: 1, roles: PoolRoles { depositor: depositor.clone(), - root: depositor.clone(), - nominator: depositor.clone(), - state_toggler: depositor.clone(), + root: Some(depositor.clone()), + nominator: Some(depositor.clone()), + state_toggler: Some(depositor.clone()), } } ); @@ -638,17 +638,17 @@ frame_benchmarking::benchmarks! { }:_( Origin::Signed(root.clone()), first_id, - Some(random.clone()), - Some(random.clone()), - Some(random.clone()) + ConfigOp::Set(random.clone()), + ConfigOp::Set(random.clone()), + ConfigOp::Set(random.clone()) ) verify { assert_eq!( pallet_nomination_pools::BondedPools::::get(first_id).unwrap().roles, pallet_nomination_pools::PoolRoles { depositor: root, - nominator: random.clone(), - state_toggler: random.clone(), - root: random, + nominator: Some(random.clone()), + state_toggler: Some(random.clone()), + root: Some(random), }, ) } diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 0fff470eec43b..d68a6f09c31d1 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -324,11 +324,26 @@ use sp_runtime::traits::{AccountIdConversion, Bounded, CheckedSub, Convert, Satu use sp_staking::{EraIndex, OnStakerSlash, StakingInterface}; use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec}; +/// The log target of this pallet. +pub const LOG_TARGET: &'static str = "runtime::nomination-pools"; + +// syntactic sugar for logging. +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: crate::LOG_TARGET, + concat!("[{:?}] 🏊‍♂️ ", $patter), >::block_number() $(, $values)* + ) + }; +} + #[cfg(test)] mod mock; #[cfg(test)] mod tests; +pub mod migration; pub mod weights; pub use pallet::*; @@ -502,7 +517,11 @@ pub enum PoolState { Destroying, } -/// Pool adminstration roles. +/// Pool administration roles. +/// +/// Any pool has a depositor, which can never change. But, all the other roles are optional, and +/// cannot exist. Note that if `root` is set to `None`, it basically means that the roles of this +/// pool can never change again (except via governance). #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Debug, PartialEq, Clone)] pub struct PoolRoles { /// Creates the pool and is the initial member. They can only leave the pool once all other @@ -510,11 +529,11 @@ pub struct PoolRoles { pub depositor: AccountId, /// Can change the nominator, state-toggler, or itself and can perform any of the actions the /// nominator or state-toggler can. - pub root: AccountId, + pub root: Option, /// Can select which validators the pool nominates. - pub nominator: AccountId, + pub nominator: Option, /// Can change the pools state and kick members if the pool is blocked. - pub state_toggler: AccountId, + pub state_toggler: Option, } /// Pool permissions and state @@ -665,25 +684,36 @@ impl BondedPool { .saturating_sub(T::StakingInterface::active_stake(&account).unwrap_or_default()) } + fn is_root(&self, who: &T::AccountId) -> bool { + self.roles.root.as_ref().map_or(false, |root| root == who) + } + + fn is_state_toggler(&self, who: &T::AccountId) -> bool { + self.roles + .state_toggler + .as_ref() + .map_or(false, |state_toggler| state_toggler == who) + } + fn can_update_roles(&self, who: &T::AccountId) -> bool { - *who == self.roles.root + self.is_root(who) } fn can_nominate(&self, who: &T::AccountId) -> bool { - *who == self.roles.root || *who == self.roles.nominator + self.is_root(who) || + self.roles.nominator.as_ref().map_or(false, |nominator| nominator == who) } fn can_kick(&self, who: &T::AccountId) -> bool { - (*who == self.roles.root || *who == self.roles.state_toggler) && - self.state == PoolState::Blocked + self.state == PoolState::Blocked && (self.is_root(who) || self.is_state_toggler(who)) } fn can_toggle_state(&self, who: &T::AccountId) -> bool { - (*who == self.roles.root || *who == self.roles.state_toggler) && !self.is_destroying() + (self.is_root(who) || self.is_state_toggler(who)) && !self.is_destroying() } fn can_set_metadata(&self, who: &T::AccountId) -> bool { - *who == self.roles.root || *who == self.roles.state_toggler + self.is_root(who) || self.is_state_toggler(who) } fn is_destroying(&self) -> bool { @@ -987,11 +1017,12 @@ impl SubPools { /// /// This is often used whilst getting the sub-pool from storage, thus it consumes and returns /// `Self` for ergonomic purposes. - fn maybe_merge_pools(mut self, unbond_era: EraIndex) -> Self { + fn maybe_merge_pools(mut self, current_era: EraIndex) -> Self { // Ex: if `TotalUnbondingPools` is 5 and current era is 10, we only want to retain pools // 6..=10. Note that in the first few eras where `checked_sub` is `None`, we don't remove // anything. - if let Some(newest_era_to_remove) = unbond_era.checked_sub(TotalUnbondingPools::::get()) + if let Some(newest_era_to_remove) = + current_era.checked_sub(T::PostUnbondingPoolsWindow::get()) { self.with_era.retain(|k, v| { if *k > newest_era_to_remove { @@ -1045,11 +1076,15 @@ impl Get for TotalUnbondingPools { #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::transactional; + use frame_support::{traits::StorageVersion, transactional}; use frame_system::{ensure_signed, pallet_prelude::*}; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -1218,8 +1253,13 @@ pub mod pallet { /// /// The removal can be voluntary (withdrawn all unbonded funds) or involuntary (kicked). MemberRemoved { pool_id: PoolId, member: T::AccountId }, - /// The roles of a pool have been updated to the given new roles. - RolesUpdated { root: T::AccountId, state_toggler: T::AccountId, nominator: T::AccountId }, + /// The roles of a pool have been updated to the given new roles. Note that the depositor + /// can never change. + RolesUpdated { + root: Option, + state_toggler: Option, + nominator: Option, + }, } #[pallet::error] @@ -1470,7 +1510,7 @@ pub mod pallet { // Note that we lazily create the unbonding pools here if they don't already exist let mut sub_pools = SubPoolsStorage::::get(member.pool_id) .unwrap_or_default() - .maybe_merge_pools(unbond_era); + .maybe_merge_pools(current_era); // Update the unbond pool associated with the current era with the unbonded funds. Note // that we lazily create the unbond pool if it does not yet exist. @@ -1693,7 +1733,12 @@ pub mod pallet { }); let mut bonded_pool = BondedPool::::new( pool_id, - PoolRoles { root, nominator, state_toggler, depositor: who.clone() }, + PoolRoles { + root: Some(root), + nominator: Some(nominator), + state_toggler: Some(state_toggler), + depositor: who.clone(), + }, ); bonded_pool.try_inc_members()?; @@ -1850,9 +1895,9 @@ pub mod pallet { pub fn update_roles( origin: OriginFor, pool_id: PoolId, - root: Option, - nominator: Option, - state_toggler: Option, + new_root: ConfigOp, + new_nominator: ConfigOp, + new_state_toggler: ConfigOp, ) -> DispatchResult { let mut bonded_pool = match ensure_root(origin.clone()) { Ok(()) => BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?, @@ -1865,17 +1910,20 @@ pub mod pallet { }, }; - match root { - None => (), - Some(v) => bonded_pool.roles.root = v, + match new_root { + ConfigOp::Noop => (), + ConfigOp::Remove => bonded_pool.roles.root = None, + ConfigOp::Set(v) => bonded_pool.roles.root = Some(v), }; - match nominator { - None => (), - Some(v) => bonded_pool.roles.nominator = v, + match new_nominator { + ConfigOp::Noop => (), + ConfigOp::Remove => bonded_pool.roles.nominator = None, + ConfigOp::Set(v) => bonded_pool.roles.nominator = Some(v), }; - match state_toggler { - None => (), - Some(v) => bonded_pool.roles.state_toggler = v, + match new_state_toggler { + ConfigOp::Noop => (), + ConfigOp::Remove => bonded_pool.roles.state_toggler = None, + ConfigOp::Set(v) => bonded_pool.roles.state_toggler = Some(v), }; Self::deposit_event(Event::::RolesUpdated { @@ -2282,7 +2330,7 @@ impl OnStakerSlash> for Pallet { _slashed_bonded: BalanceOf, slashed_unlocking: &BTreeMap>, ) { - if let Some(pool_id) = ReversePoolIdLookup::::get(pool_account) { + if let Some(pool_id) = ReversePoolIdLookup::::get(pool_account).defensive() { let mut sub_pools = match SubPoolsStorage::::get(pool_id).defensive() { Some(sub_pools) => sub_pools, None => return, diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs new file mode 100644 index 0000000000000..e23a35fe85602 --- /dev/null +++ b/frame/nomination-pools/src/migration.rs @@ -0,0 +1,105 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; + +pub mod v1 { + use super::*; + use crate::log; + use frame_support::traits::OnRuntimeUpgrade; + + #[derive(Decode)] + pub struct OldPoolRoles { + pub depositor: AccountId, + pub root: AccountId, + pub nominator: AccountId, + pub state_toggler: AccountId, + } + + impl OldPoolRoles { + fn migrate_to_v1(self) -> PoolRoles { + PoolRoles { + depositor: self.depositor, + root: Some(self.root), + nominator: Some(self.nominator), + state_toggler: Some(self.state_toggler), + } + } + } + + #[derive(Decode)] + pub struct OldBondedPoolInner { + pub points: BalanceOf, + pub state: PoolState, + pub member_counter: u32, + pub roles: OldPoolRoles, + } + + impl OldBondedPoolInner { + fn migrate_to_v1(self) -> BondedPoolInner { + BondedPoolInner { + member_counter: self.member_counter, + points: self.points, + state: self.state, + roles: self.roles.migrate_to_v1(), + } + } + } + + /// Trivial migration which makes the roles of each pool optional. + /// + /// Note: The depositor is not optional since he can never change. + pub struct MigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); + + log!( + info, + "Running migration with current storage version {:?} / onchain {:?}", + current, + onchain + ); + + if current == 1 && onchain == 0 { + // this is safe to execute on any runtime that has a bounded number of pools. + let mut translated = 0u64; + BondedPools::::translate::, _>(|_key, old_value| { + translated.saturating_inc(); + Some(old_value.migrate_to_v1()) + }); + + current.put::>(); + + log!(info, "Upgraded {} pools, storage to version {:?}", translated, current); + + T::DbWeight::get().reads_writes(translated + 1, translated + 1) + } else { + log!(info, "Migration did not executed. This probably should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + // new version must be set. + assert_eq!(Pallet::::on_chain_storage_version(), 1); + Ok(()) + } + } +} diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index f39b5c92375c4..fe78da3bb14af 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -38,7 +38,7 @@ macro_rules! member_unbonding_eras { } pub const DEFAULT_ROLES: PoolRoles = - PoolRoles { depositor: 10, root: 900, nominator: 901, state_toggler: 902 }; + PoolRoles { depositor: 10, root: Some(900), nominator: Some(901), state_toggler: Some(902) }; #[test] fn test_setup_works() { @@ -333,6 +333,8 @@ mod sub_pools { fn maybe_merge_pools_works() { ExtBuilder::default().build_and_execute(|| { assert_eq!(TotalUnbondingPools::::get(), 5); + assert_eq!(BondingDuration::get(), 3); + assert_eq!(PostUnbondingPoolsWindow::get(), 2); // Given let mut sub_pool_0 = SubPools:: { @@ -347,19 +349,19 @@ mod sub_pools { }; // When `current_era < TotalUnbondingPools`, - let sub_pool_1 = sub_pool_0.clone().maybe_merge_pools(3); + let sub_pool_1 = sub_pool_0.clone().maybe_merge_pools(0); // Then it exits early without modifications assert_eq!(sub_pool_1, sub_pool_0); // When `current_era == TotalUnbondingPools`, - let sub_pool_1 = sub_pool_1.maybe_merge_pools(4); + let sub_pool_1 = sub_pool_1.maybe_merge_pools(1); // Then it exits early without modifications assert_eq!(sub_pool_1, sub_pool_0); // When `current_era - TotalUnbondingPools == 0`, - let mut sub_pool_1 = sub_pool_1.maybe_merge_pools(5); + let mut sub_pool_1 = sub_pool_1.maybe_merge_pools(2); // Then era 0 is merged into the `no_era` pool sub_pool_0.no_era = sub_pool_0.with_era.remove(&0).unwrap(); @@ -376,7 +378,7 @@ mod sub_pools { .unwrap(); // When `current_era - TotalUnbondingPools == 1` - let sub_pool_2 = sub_pool_1.maybe_merge_pools(6); + let sub_pool_2 = sub_pool_1.maybe_merge_pools(3); let era_1_pool = sub_pool_0.with_era.remove(&1).unwrap(); // Then era 1 is merged into the `no_era` pool @@ -385,7 +387,7 @@ mod sub_pools { assert_eq!(sub_pool_2, sub_pool_0); // When `current_era - TotalUnbondingPools == 5`, so all pools with era <= 4 are removed - let sub_pool_3 = sub_pool_2.maybe_merge_pools(10); + let sub_pool_3 = sub_pool_2.maybe_merge_pools(7); // Then all eras <= 5 are merged into the `no_era` pool for era in 2..=5 { @@ -1723,9 +1725,9 @@ mod unbond { // Given unsafe_set_state(1, PoolState::Blocked).unwrap(); let bonded_pool = BondedPool::::get(1).unwrap(); - assert_eq!(bonded_pool.roles.root, 900); - assert_eq!(bonded_pool.roles.nominator, 901); - assert_eq!(bonded_pool.roles.state_toggler, 902); + assert_eq!(bonded_pool.roles.root.unwrap(), 900); + assert_eq!(bonded_pool.roles.nominator.unwrap(), 901); + assert_eq!(bonded_pool.roles.state_toggler.unwrap(), 902); // When the nominator tries to kick, then its a noop assert_noop!( @@ -3143,9 +3145,9 @@ mod create { state: PoolState::Open, roles: PoolRoles { depositor: 11, - root: 123, - nominator: 456, - state_toggler: 789 + root: Some(123), + nominator: Some(456), + state_toggler: Some(789) } } } @@ -3590,71 +3592,164 @@ mod update_roles { ExtBuilder::default().build_and_execute(|| { assert_eq!( BondedPools::::get(1).unwrap().roles, - PoolRoles { depositor: 10, root: 900, nominator: 901, state_toggler: 902 }, + PoolRoles { + depositor: 10, + root: Some(900), + nominator: Some(901), + state_toggler: Some(902) + }, ); // non-existent pools assert_noop!( - Pools::update_roles(Origin::signed(1), 2, Some(5), Some(6), Some(7)), + Pools::update_roles( + Origin::signed(1), + 2, + ConfigOp::Set(5), + ConfigOp::Set(6), + ConfigOp::Set(7) + ), Error::::PoolNotFound, ); // depositor cannot change roles. assert_noop!( - Pools::update_roles(Origin::signed(1), 1, Some(5), Some(6), Some(7)), + Pools::update_roles( + Origin::signed(1), + 1, + ConfigOp::Set(5), + ConfigOp::Set(6), + ConfigOp::Set(7) + ), Error::::DoesNotHavePermission, ); // nominator cannot change roles. assert_noop!( - Pools::update_roles(Origin::signed(901), 1, Some(5), Some(6), Some(7)), + Pools::update_roles( + Origin::signed(901), + 1, + ConfigOp::Set(5), + ConfigOp::Set(6), + ConfigOp::Set(7) + ), Error::::DoesNotHavePermission, ); // state-toggler assert_noop!( - Pools::update_roles(Origin::signed(902), 1, Some(5), Some(6), Some(7)), + Pools::update_roles( + Origin::signed(902), + 1, + ConfigOp::Set(5), + ConfigOp::Set(6), + ConfigOp::Set(7) + ), Error::::DoesNotHavePermission, ); // but root can - assert_ok!(Pools::update_roles(Origin::signed(900), 1, Some(5), Some(6), Some(7))); + assert_ok!(Pools::update_roles( + Origin::signed(900), + 1, + ConfigOp::Set(5), + ConfigOp::Set(6), + ConfigOp::Set(7) + )); assert_eq!( pool_events_since_last_call(), vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::RolesUpdated { root: 5, state_toggler: 7, nominator: 6 } + Event::RolesUpdated { + root: Some(5), + state_toggler: Some(7), + nominator: Some(6) + } ] ); assert_eq!( BondedPools::::get(1).unwrap().roles, - PoolRoles { depositor: 10, root: 5, nominator: 6, state_toggler: 7 }, + PoolRoles { + depositor: 10, + root: Some(5), + nominator: Some(6), + state_toggler: Some(7) + }, ); // also root origin can - assert_ok!(Pools::update_roles(Origin::root(), 1, Some(1), Some(2), Some(3))); + assert_ok!(Pools::update_roles( + Origin::root(), + 1, + ConfigOp::Set(1), + ConfigOp::Set(2), + ConfigOp::Set(3) + )); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::RolesUpdated { + root: Some(1), + state_toggler: Some(3), + nominator: Some(2) + }] + ); + assert_eq!( + BondedPools::::get(1).unwrap().roles, + PoolRoles { + depositor: 10, + root: Some(1), + nominator: Some(2), + state_toggler: Some(3) + }, + ); + + // Noop works + assert_ok!(Pools::update_roles( + Origin::root(), + 1, + ConfigOp::Set(11), + ConfigOp::Noop, + ConfigOp::Noop + )); assert_eq!( pool_events_since_last_call(), - vec![Event::RolesUpdated { root: 1, state_toggler: 3, nominator: 2 }] + vec![Event::RolesUpdated { + root: Some(11), + state_toggler: Some(3), + nominator: Some(2) + }] ); + assert_eq!( BondedPools::::get(1).unwrap().roles, - PoolRoles { depositor: 10, root: 1, nominator: 2, state_toggler: 3 }, + PoolRoles { + depositor: 10, + root: Some(11), + nominator: Some(2), + state_toggler: Some(3) + }, ); - // None is a noop - assert_ok!(Pools::update_roles(Origin::root(), 1, Some(11), None, None)); + // Remove works + assert_ok!(Pools::update_roles( + Origin::root(), + 1, + ConfigOp::Set(69), + ConfigOp::Remove, + ConfigOp::Remove + )); assert_eq!( pool_events_since_last_call(), - vec![Event::RolesUpdated { root: 11, state_toggler: 3, nominator: 2 }] + vec![Event::RolesUpdated { root: Some(69), state_toggler: None, nominator: None }] ); assert_eq!( BondedPools::::get(1).unwrap().roles, - PoolRoles { depositor: 10, root: 11, nominator: 2, state_toggler: 3 }, + PoolRoles { depositor: 10, root: Some(69), nominator: None, state_toggler: None }, ); }) } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 2d4c1ea9a3488..f17d09b413606 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -533,10 +533,12 @@ impl StakingLedger { /// case that either the active bonded or some unlocking chunks become dust after slashing. /// Returns the amount of funds actually slashed. /// + /// `slash_era` is the era in which the slash (which is being enacted now) actually happened. + /// /// # Note /// - /// This calls `Config::OnStakerSlash::on_slash` with information as to how the slash - /// was applied. + /// This calls `Config::OnStakerSlash::on_slash` with information as to how the slash was + /// applied. fn slash( &mut self, slash_amount: BalanceOf, @@ -615,6 +617,7 @@ impl StakingLedger { break } } + self.unlocking.retain(|c| !c.value.is_zero()); T::OnStakerSlash::on_slash(&self.stash, self.active, &slashed_unlocking); pre_slash_total.saturating_sub(self.total) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 21d4714985c6b..ccd9558c5c21d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2787,6 +2787,80 @@ fn deferred_slashes_are_deferred() { }) } +#[test] +fn staker_cannot_bail_deferred_slash() { + // as long as SlashDeferDuration is less than BondingDuration, this should not be possible. + ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { + mock::start_active_era(1); + + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); + + let exposure = Staking::eras_stakers(active_era(), 11); + let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; + + on_offence_now( + &[OffenceDetails { + offender: (11, Staking::eras_stakers(active_era(), 11)), + reporters: vec![], + }], + &[Perbill::from_percent(10)], + ); + + // now we chill + assert_ok!(Staking::chill(Origin::signed(100))); + assert_ok!(Staking::unbond(Origin::signed(100), 500)); + + assert_eq!(Staking::current_era().unwrap(), 1); + assert_eq!(active_era(), 1); + + assert_eq!( + Ledger::::get(100).unwrap(), + StakingLedger { + active: 0, + total: 500, + stash: 101, + claimed_rewards: Default::default(), + unlocking: bounded_vec![UnlockChunk { era: 4u32, value: 500 }], + } + ); + + // no slash yet. + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); + + // no slash yet. + mock::start_active_era(2); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(Staking::current_era().unwrap(), 2); + assert_eq!(active_era(), 2); + + // no slash yet. + mock::start_active_era(3); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(Staking::current_era().unwrap(), 3); + assert_eq!(active_era(), 3); + + // and cannot yet unbond: + assert_storage_noop!(assert!(Staking::withdraw_unbonded(Origin::signed(100), 0).is_ok())); + assert_eq!( + Ledger::::get(100).unwrap().unlocking.into_inner(), + vec![UnlockChunk { era: 4u32, value: 500 as Balance }], + ); + + // at the start of era 4, slashes from era 1 are processed, + // after being deferred for at least 2 full eras. + mock::start_active_era(4); + + assert_eq!(Balances::free_balance(11), 900); + assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); + + // and the leftover of the funds can now be unbonded. + }) +} + #[test] fn remove_deferred() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { @@ -4856,7 +4930,7 @@ fn force_apply_min_commission_works() { } #[test] -fn ledger_slash_works() { +fn proportional_ledger_slash_works() { let c = |era, value| UnlockChunk:: { era, value }; // Given let mut ledger = StakingLedger:: { From 9ab620058f9968ce9ecbd2ed93ccbb89aadee932 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 15 May 2022 21:37:23 -0400 Subject: [PATCH 0795/1472] Bump clap from 3.1.6 to 3.1.18 (#11376) * Bump clap from 3.1.6 to 3.1.17 Bumps [clap](https://github.com/clap-rs/clap) from 3.1.6 to 3.1.17. - [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/v3.1.6...v3.1.17) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update utils/frame/try-runtime/cli/Cargo.toml * Update frame/election-provider-support/solution-type/fuzzer/Cargo.toml * use 3.1.18 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn Tabrizi --- Cargo.lock | 54 ++++++++++--------- bin/node-template/node/Cargo.toml | 2 +- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 4 +- bin/utils/chain-spec-builder/Cargo.toml | 2 +- bin/utils/subkey/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/frame-utilities-cli/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 13 files changed, 43 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1995ebb46023e..4dad89fbd97f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -916,7 +916,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 3.1.6", + "clap 3.1.18", "node-cli", "rand 0.8.4", "sc-chain-spec", @@ -993,16 +993,16 @@ dependencies = [ [[package]] name = "clap" -version = "3.1.6" +version = "3.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" +checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" dependencies = [ "atty", "bitflags", "clap_derive", + "clap_lex", "indexmap", "lazy_static", - "os_str_bytes", "strsim", "termcolor", "textwrap 0.15.0", @@ -1014,14 +1014,14 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a394f7ec0715b42a4e52b294984c27c9a61f77c8d82f7774c5198350be143f19" dependencies = [ - "clap 3.1.6", + "clap 3.1.18", ] [[package]] name = "clap_derive" -version = "3.1.4" +version = "3.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16" +checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" dependencies = [ "heck 0.4.0", "proc-macro-error", @@ -1030,6 +1030,15 @@ dependencies = [ "syn", ] +[[package]] +name = "clap_lex" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -2142,7 +2151,7 @@ version = "4.0.0-dev" dependencies = [ "Inflector", "chrono", - "clap 3.1.6", + "clap 3.1.18", "frame-benchmarking", "frame-support", "frame-system", @@ -2223,7 +2232,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 3.1.6", + "clap 3.1.18", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -3410,9 +3419,9 @@ checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "libgit2-sys" -version = "0.13.3+1.4.2" +version = "0.13.2+1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c24d36c3ac9b9996a2418d6bf428cc0bc5d1a814a84303fc60986088c5ed60de" +checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b" dependencies = [ "cc", "libc", @@ -4533,7 +4542,7 @@ dependencies = [ name = "node-bench" version = "0.9.0-dev" dependencies = [ - "clap 3.1.6", + "clap 3.1.18", "derive_more", "fs_extra", "futures", @@ -4572,7 +4581,7 @@ version = "3.0.0-dev" dependencies = [ "assert_cmd", "async-std", - "clap 3.1.6", + "clap 3.1.18", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4687,7 +4696,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 3.1.6", + "clap 3.1.18", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4837,7 +4846,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 3.1.6", + "clap 3.1.18", "generate-bags", "node-runtime", ] @@ -4846,7 +4855,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 3.1.6", + "clap 3.1.18", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -5128,9 +5137,6 @@ name = "os_str_bytes" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] [[package]] name = "output_vt100" @@ -7944,7 +7950,7 @@ name = "sc-cli" version = "0.10.0-dev" dependencies = [ "chrono", - "clap 3.1.6", + "clap 3.1.18", "fdlimit", "futures", "hex", @@ -9998,7 +10004,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 3.1.6", + "clap 3.1.18", "honggfuzz", "parity-scale-codec", "rand 0.8.4", @@ -10430,7 +10436,7 @@ dependencies = [ name = "subkey" version = "2.0.1" dependencies = [ - "clap 3.1.6", + "clap 3.1.18", "sc-cli", ] @@ -10458,7 +10464,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 3.1.6", + "clap 3.1.18", "frame-support", "frame-system", "sc-cli", @@ -11237,7 +11243,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ - "clap 3.1.6", + "clap 3.1.18", "jsonrpsee", "log", "parity-scale-codec", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 7ae343fd56dbe..8a6b041bbd518 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] name = "node-template" [dependencies] -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } sp-core = { version = "6.0.0", path = "../../../primitives/core" } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 2675c12d0d3b4..d9fb495ffc65c 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -9,7 +9,7 @@ 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] -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } log = "0.4.16" node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index b574fa948b857..50852cfb393ae 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -34,7 +34,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies -clap = { version = "3.1.6", features = ["derive"], optional = true } +clap = { version = "3.1.18", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } jsonrpsee = { version = "0.13.0", features = ["server"] } @@ -135,7 +135,7 @@ remote-externalities = { path = "../../../utils/frame/remote-externalities" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } [build-dependencies] -clap = { version = "3.1.6", optional = true } +clap = { version = "3.1.18", optional = true } clap_complete = { version = "3.0", optional = true } node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } frame-benchmarking-cli = { version = "4.0.0-dev", optional = true, path = "../../../utils/frame/benchmarking-cli" } diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index e179a3308dd62..e3deb54ea8ac9 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } rand = "0.8" node-cli = { version = "3.0.0-dev", path = "../../node/cli" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } diff --git a/bin/utils/subkey/Cargo.toml b/bin/utils/subkey/Cargo.toml index c8132fe7b5b4b..26bc949b74ae7 100644 --- a/bin/utils/subkey/Cargo.toml +++ b/bin/utils/subkey/Cargo.toml @@ -17,5 +17,5 @@ path = "src/main.rs" name = "subkey" [dependencies] -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 1a504f354ee87..ecc58e0b23450 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = "0.4.10" -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } fdlimit = "0.2.1" futures = "0.3.21" hex = "0.4.2" diff --git a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index e2bae3f72a4f7..6520f6e632230 100644 --- a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.0", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index f8cc21cb61077..a0c420329b3d0 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -14,7 +14,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 871f4e925648b..6266f4eb8bb2a 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = "0.4" -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } handlebars = "4.2.2" hash-db = "0.15.2" diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index cd9fc4a8cf1e3..f01e2f1a5d51f 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" [dependencies] -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml index d5c8cab7ba0d8..c5f3b1998fa97 100644 --- a/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -14,4 +14,4 @@ node-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runtime" } generate-bags = { version = "4.0.0-dev", path = "../" } # third-party -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 4bbcaf1c216a5..48e9c1d6b36a1 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "3.1.18", features = ["derive"] } log = "0.4.16" parity-scale-codec = "3.0.0" serde = "1.0.136" From 5673e591babcc5097a11b2a3e1e95a32ce0bb62d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 15 May 2022 22:21:04 -0400 Subject: [PATCH 0796/1472] Bump log from 0.4.16 to 0.4.17 (#11369) * Bump log from 0.4.16 to 0.4.17 Bumps [log](https://github.com/rust-lang/log) from 0.4.16 to 0.4.17. - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/commits/0.4.17) --- updated-dependencies: - dependency-name: log dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update Cargo.lock Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn Tabrizi --- Cargo.lock | 8 ++++---- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- client/allocator/Cargo.toml | 2 +- client/api/Cargo.toml | 2 +- client/authority-discovery/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/executor/wasmi/Cargo.toml | 2 +- client/executor/wasmtime/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/informant/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/sync/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/proposer-metrics/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- client/state-db/Cargo.toml | 2 +- client/sysinfo/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/api/Cargo.toml | 2 +- frame/babe/Cargo.toml | 2 +- frame/bags-list/Cargo.toml | 2 +- frame/bags-list/remote-tests/Cargo.toml | 2 +- frame/balances/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 2 +- frame/bounties/Cargo.toml | 2 +- frame/child-bounties/Cargo.toml | 2 +- frame/collective/Cargo.toml | 2 +- frame/election-provider-multi-phase/Cargo.toml | 2 +- frame/examples/basic/Cargo.toml | 2 +- frame/examples/offchain-worker/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/im-online/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/node-authorization/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/scheduler/Cargo.toml | 2 +- frame/session/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/staking/reward-fn/Cargo.toml | 2 +- frame/state-trie-migration/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- frame/timestamp/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 2 +- frame/vesting/Cargo.toml | 2 +- primitives/api/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/consensus/common/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/merkle-mountain-range/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/tasks/Cargo.toml | 2 +- primitives/timestamp/Cargo.toml | 2 +- primitives/transaction-storage-proof/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/state-trie-migration-rpc/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 2 +- 87 files changed, 90 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4dad89fbd97f7..abd9cd7b46e02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4100,9 +4100,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", "value-bag", @@ -11414,9 +11414,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.0.0-alpha.8" +version = "1.0.0-alpha.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" dependencies = [ "ctor", "version_check", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index d9fb495ffc65c..5013383af1cea 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] clap = { version = "3.1.18", features = ["derive"] } -log = "0.4.16" +log = "0.4.17" node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 50852cfb393ae..ab6644a379bb5 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -40,7 +40,7 @@ serde = { version = "1.0.136", features = ["derive"] } jsonrpsee = { version = "0.13.0", features = ["server"] } futures = "0.3.21" hex-literal = "0.3.4" -log = "0.4.16" +log = "0.4.17" rand = "0.8" # primitives diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 09f7534e7f521..46d9ff03ed36e 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } static_assertions = "1.1.0" hex-literal = { version = "0.3.4", optional = true } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } # primitives sp-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/authority-discovery" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index c4f97a3e47447..f7a78d10910b3 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } fs_extra = "1" futures = "0.3.21" -log = "0.4.16" +log = "0.4.17" tempfile = "3.1.0" frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } node-executor = { version = "3.0.0-dev", path = "../executor" } diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index ec5c19786b875..aded67ad80cde 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.16" +log = "0.4.17" thiserror = "1.0.30" sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index f69549b60c53e..c8e9dc7482823 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = fnv = "1.0.6" futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } -log = "0.4.16" +log = "0.4.17" parking_lot = "0.12.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-executor = { version = "0.10.0-dev", path = "../executor" } diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 996e262ba2b44..2545447001511 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -23,7 +23,7 @@ futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" libp2p = { version = "0.44.0", default-features = false, features = ["kad"] } -log = "0.4.16" +log = "0.4.17" prost = "0.9" rand = "0.7.2" thiserror = "1.0" diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 6ef679d7995e6..a2ccba486ae29 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.16" +log = "0.4.17" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index ecc58e0b23450..456489e5f6639 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -19,7 +19,7 @@ fdlimit = "0.2.1" futures = "0.3.21" hex = "0.4.2" libp2p = "0.44.0" -log = "0.4.16" +log = "0.4.17" names = { version = "0.13.0", default-features = false } parity-scale-codec = "3.0.0" rand = "0.7.3" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 448cf2549f2d9..69499fa346e31 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -log = "0.4.16" +log = "0.4.17" thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index f421fdd36e37b..765fc367f424f 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -log = "0.4.16" +log = "0.4.17" merlin = "2.0" num-bigint = "0.2.3" num-rational = "0.2.2" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 4f8d7befb0d63..1508dfa82a363 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -17,7 +17,7 @@ async-trait = "0.1.42" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" libp2p = { version = "0.44.0", default-features = false } -log = "0.4.16" +log = "0.4.17" parking_lot = "0.12.0" serde = { version = "1.0", features = ["derive"] } thiserror = "1.0.30" diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 9806fbdcaac3c..dbc7c29c7f300 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -18,7 +18,7 @@ assert_matches = "1.3.0" async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -log = "0.4.16" +log = "0.4.17" serde = { version = "1.0", features = ["derive"] } thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index cc65687f80e13..7e9b43fac8a57 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -17,7 +17,7 @@ async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.16" +log = "0.4.17" parking_lot = "0.12.0" thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 27528b68e75ea..41a6c1ad5e641 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -18,7 +18,7 @@ async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.16" +log = "0.4.17" thiserror = "1.0.30" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index e548887e56fe2..babbb0b91c8fb 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -21,7 +21,7 @@ kvdb = "0.11.0" kvdb-memorydb = "0.11.0" kvdb-rocksdb = { version = "0.15.2", optional = true } linked-hash-map = "0.5.4" -log = "0.4.16" +log = "0.4.17" parity-db = { version = "0.3.13", optional = true } parking_lot = "0.12.0" sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 153deab49a305..46bacf54a42c6 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -log = "0.4.16" +log = "0.4.17" wasmi = "0.9.1" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 845fdfb72901c..c514a93be1d88 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] cfg-if = "1.0" codec = { package = "parity-scale-codec", version = "3.0.0" } libc = "0.2.121" -log = "0.4.16" +log = "0.4.17" parity-wasm = "0.42.0" wasmtime = { version = "0.35.3", default-features = false, features = [ "cache", diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index a0e53da23fc54..2f7fcd4d052b1 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -21,7 +21,7 @@ finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } futures = "0.3.21" futures-timer = "3.0.1" hex = "0.4.2" -log = "0.4.16" +log = "0.4.17" parity-scale-codec = { version = "3.0.0", features = ["derive"] } parking_lot = "0.12.0" rand = "0.8.4" diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index 70af073e4bcfe..528365d62c18b 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] ansi_term = "0.12.1" futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.16" +log = "0.4.17" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 4529957c7c38f..7ba45f6ee9b87 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -18,7 +18,7 @@ ahash = "0.7.6" futures = "0.3.21" futures-timer = "3.0.1" libp2p = { version = "0.44.0", default-features = false } -log = "0.4.16" +log = "0.4.17" lru = "0.7.5" tracing = "0.1.29" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 7e12d9862f8ef..4d6af584d8610 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -32,7 +32,7 @@ ip_network = "0.4.1" libp2p = "0.44.0" linked_hash_set = "0.1.3" linked-hash-map = "0.5.4" -log = "0.4.16" +log = "0.4.17" lru = "0.7.5" parking_lot = "0.12.0" pin-project = "1.0.10" diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 9cf8afa58649c..e570310ceb955 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -24,7 +24,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ either = "1.5.3" futures = "0.3.21" libp2p = "0.44.0" -log = "0.4.16" +log = "0.4.17" lru = "0.7.5" prost = "0.9" smallvec = "1.8.0" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 025658afcad22..fa34feb22df1d 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -18,7 +18,7 @@ async-trait = "0.1.50" futures = "0.3.21" futures-timer = "3.0.1" libp2p = { version = "0.44.0", default-features = false } -log = "0.4.16" +log = "0.4.17" parking_lot = "0.12.0" rand = "0.7.2" sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index 7bf324b68cdc6..29e67c73c18da 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" libp2p = { version = "0.44.0", default-features = false } -log = "0.4.16" +log = "0.4.17" serde_json = "1.0.79" wasm-timer = "0.2" sc-utils = { version = "4.0.0-dev", path = "../utils" } diff --git a/client/proposer-metrics/Cargo.toml b/client/proposer-metrics/Cargo.toml index 9df6ff4e2e76d..97a7c076bd9e7 100644 --- a/client/proposer-metrics/Cargo.toml +++ b/client/proposer-metrics/Cargo.toml @@ -13,5 +13,5 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.16" +log = "0.4.17" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index a9d5101733342..0ad0b7cc5bfdc 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -log = "0.4.16" +log = "0.4.17" parking_lot = "0.12.0" scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"] } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index 7d6ca821adc3c..f5cd943b24e09 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" jsonrpsee = { version = "0.13.0", features = ["server"] } -log = "0.4.16" +log = "0.4.17" serde_json = "1.0.79" tokio = { version = "1.17.0", features = ["parking_lot"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 50b0dff20cfcd..f783ce8a94fb7 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } jsonrpsee = { version = "0.13.0", features = ["server"] } lazy_static = { version = "1.4.0", optional = true } -log = "0.4.16" +log = "0.4.17" parking_lot = "0.12.0" serde_json = "1.0.79" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index d59e8e8d19c4c..22bac652c30c4 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -27,7 +27,7 @@ thiserror = "1.0.30" futures = "0.3.21" rand = "0.7.3" parking_lot = "0.12.0" -log = "0.4.16" +log = "0.4.17" futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.10" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 15105765c207c..d003db57eb7ac 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -16,7 +16,7 @@ fdlimit = "0.2.1" futures = "0.3.21" hex = "0.4" hex-literal = "0.3.4" -log = "0.4.16" +log = "0.4.17" parity-scale-codec = "3.0.0" parking_lot = "0.12.0" tempfile = "3.1.0" diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 5a143ffc9f1b8..08856ce3f48a9 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } -log = "0.4.16" +log = "0.4.17" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } parity-util-mem-derive = "0.1.0" parking_lot = "0.12.0" diff --git a/client/sysinfo/Cargo.toml b/client/sysinfo/Cargo.toml index abfa090d85547..0973631a3cc24 100644 --- a/client/sysinfo/Cargo.toml +++ b/client/sysinfo/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.19" libc = "0.2" -log = "0.4.16" +log = "0.4.17" rand = "0.7.3" rand_pcg = "0.2.1" regex = "1" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 3c5942ad688fa..e8abdfee44a2e 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] chrono = "0.4.19" futures = "0.3.21" libp2p = { version = "0.44.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } -log = "0.4.16" +log = "0.4.17" parking_lot = "0.12.0" pin-project = "1.0.10" rand = "0.7.2" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 058b718a783a4..3f0bbbe922d3f 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -18,7 +18,7 @@ atty = "0.2.13" chrono = "0.4.19" lazy_static = "1.4.0" libc = "0.2.121" -log = { version = "0.4.16" } +log = { version = "0.4.17" } once_cell = "1.8.0" parking_lot = "0.12.0" regex = "1.5.5" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 5d4996a424f86..cabde4b6307ae 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" futures-timer = "3.0.2" linked-hash-map = "0.5.4" -log = "0.4.16" +log = "0.4.17" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } parking_lot = "0.12.0" retain_mut = "0.1.4" diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 6ced3f6c7fc91..d34ffe512b023 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -10,7 +10,7 @@ description = "Transaction pool client facing API." [dependencies] futures = "0.3.21" -log = "0.4.16" +log = "0.4.17" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index dfdc9d2163136..23f8f1517cb63 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 8a47fd7d9e7d2..4efa1fbe287fa 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -27,7 +27,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } # third party -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking", optional = true, default-features = false } diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 760115917c6d4..3e2de430f6424 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -31,4 +31,4 @@ sp-std = { path = "../../../primitives/std", version = "4.0.0" } remote-externalities = { path = "../../../utils/frame/remote-externalities", version = "0.10.0-dev" } # others -log = "0.4.16" +log = "0.4.17" diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 6ec624130288b..b2840eb3e1787 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 6affcd60ccb34..85986c2a41529 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://substrate.io" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex = { version = "0.4", optional = true } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } beefy-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "./primitives" } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index c070e64d37b45..6dddcf7e247ae 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } linregress = { version = "0.4.4", optional = true } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } paste = "1.0" scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index c090052e91277..d37c06a96e88e 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index eac338dc3c6aa..722ee0af01f95 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index d1ef4d253a352..b810c3f3bd11d 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 50afd274c3f7d..6f3e500577af6 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index a528cf89bbaf4..d6bea8b3c290f 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index 061f84bd40276..bcc845823e137 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } lite-json = { version = "0.1", default-features = false } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index ea1ec173d8f44..fb2ffe42f526b 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index 1f04c8b1bb3d8..0279e29169006 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 1545b191c8719..356fc12b09507 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 317b5f392ebfa..a22af2d87578e 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index f4aa01643315b..91553ea414f7e 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 90c2bf10d19da..0908fc110802a 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 01822ace9cf28..56c72eeaf6d4b 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 88080df0b5912..cc8e19b1de892 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -30,7 +30,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, features = [ pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } diff --git a/frame/staking/reward-fn/Cargo.toml b/frame/staking/reward-fn/Cargo.toml index 4a41de806e13f..f16131f481494 100644 --- a/frame/staking/reward-fn/Cargo.toml +++ b/frame/staking/reward-fn/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [lib] [dependencies] -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../../primitives/arithmetic" } [features] diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index 958ab50315427..be3e4392ac918 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.133", optional = true } thousands = { version = "0.2.0", optional = true } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 4132b9f98ebca..2d510fd4690ca 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -33,7 +33,7 @@ sp-state-machine = { version = "0.12.0", optional = true, path = "../../primitiv bitflags = "1.3" impl-trait-for-tuples = "0.2.2" smallvec = "1.8.0" -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } k256 = { version = "0.10.4", default-features = false, features = ["ecdsa"] } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index f1d2491ad0919..38a2b934cef17 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 971a0ace95d73..6ce1592cae3f9 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 364135daa97f6..23f61dc4f96cd 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 1e6ca2ce687dc..0441289b3a351 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index f73a7af9e6ae4..1690e9eb19f72 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index 3a94cd8e0bd88..f3d091266d5d4 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -23,7 +23,7 @@ sp-state-machine = { version = "0.12.0", optional = true, path = "../state-machi hash-db = { version = "0.15.2", optional = true } thiserror = { version = "1.0.30", optional = true } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } [dev-dependencies] sp-test-primitives = { version = "2.0.0", path = "../test-primitives" } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index a36e68ecf9fe0..25000072c88a9 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -27,7 +27,7 @@ rustversion = "1.0.6" [dev-dependencies] criterion = "0.3.0" futures = "0.3.21" -log = "0.4.16" +log = "0.4.17" sp-core = { version = "6.0.0", path = "../../core" } [[bench]] diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 4389a867f7132..a5137606e16a2 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } futures = "0.3.21" -log = "0.4.16" +log = "0.4.17" lru = "0.7.5" parking_lot = "0.12.0" thiserror = "1.0.30" diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 5dc94872d6141..973cb3e410e0d 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ ] } futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" -log = "0.4.16" +log = "0.4.17" thiserror = "1.0.30" sp-core = { version = "6.0.0", path = "../../core" } sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 9fbdeb15a0366..852812c1c5659 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "max-encoded-len", ] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } primitive-types = { version = "0.11.1", default-features = false, features = ["codec", "scale-info"] } diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index 277236abc0f8c..c8b24c97bbafd 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.15.0", default-features = false, features = ["derive-codec"] } -log = { version = "0.4.16", optional = true } +log = { version = "0.4.17", optional = true } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 6d0ac398e473d..bd288dd896d1b 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -27,7 +27,7 @@ sp-runtime-interface = { version = "6.0.0", default-features = false, path = ".. sp-trie = { version = "6.0.0", optional = true, path = "../trie" } sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } -log = { version = "0.4.16", optional = true } +log = { version = "0.4.17", optional = true } futures = { version = "0.3.21", features = ["thread-pool"], optional = true } parking_lot = { version = "0.12.0", optional = true } secp256k1 = { version = "0.21.2", features = ["recovery", "global-context"], optional = true } diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index 831d07315f317..2be3f592b2b20 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 04e5c2a9fe6ec..ca4ba82e1aee8 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = either = { version = "1.5", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } impl-trait-for-tuples = "0.2.2" -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } paste = "1.0" rand = { version = "0.7.2", optional = true } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 58fa3be514e4c..e472b66c5d9ee 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } hash-db = { version = "0.15.2", default-features = false } -log = { version = "0.4.16", optional = true } +log = { version = "0.4.17", optional = true } num-traits = { version = "0.2.8", default-features = false } parking_lot = { version = "0.12.0", optional = true } rand = { version = "0.7.2", optional = true } diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml index 647a8ed63ff91..c37a8a66f94df 100644 --- a/primitives/tasks/Cargo.toml +++ b/primitives/tasks/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { version = "0.4.16", optional = true } +log = { version = "0.4.17", optional = true } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 8b40050b4aaa5..42701f5ad3bf1 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.50", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } futures-timer = { version = "3.0.2", optional = true } -log = { version = "0.4.16", optional = true } +log = { version = "0.4.17", optional = true } thiserror = { version = "1.0.30", optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index e017377ac63de..9501f86cca055 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.50", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.16", optional = true } +log = { version = "0.4.17", optional = true } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-core = { version = "6.0.0", optional = true, path = "../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 07e118d0ecc86..2314bfb7be5eb 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" -log = { version = "0.4.16", optional = true } +log = { version = "0.4.17", optional = true } wasmi = { version = "0.9.1", optional = true } wasmtime = { version = "0.35.3", default-features = false, optional = true } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 64767877548a9..8c529bb6a00a9 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -48,7 +48,7 @@ sp-externalities = { version = "0.12.0", default-features = false, path = "../.. # 3rd party cfg-if = "1.0" -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } [dev-dependencies] diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 6266f4eb8bb2a..68be768012d51 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -24,7 +24,7 @@ itertools = "0.10.3" kvdb = "0.11.0" lazy_static = "1.4.0" linked-hash-map = "0.5.4" -log = "0.4.16" +log = "0.4.17" memory-db = "0.29.0" prettytable-rs = "0.8.0" rand = { version = "0.8.4", features = ["small_rng"] } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index f3876e41f4d02..a0adb8edb2d67 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } env_logger = "0.9" jsonrpsee = { version = "0.13.0", features = ["ws-client", "macros"] } -log = "0.4.16" +log = "0.4.17" serde = "1.0.136" serde_json = "1.0" frame-support = { version = "4.0.0-dev", optional = true, path = "../../../frame/support" } diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 71fadfdbc041c..8fe0ad8d61d6e 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } serde = { version = "1", features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } sp-std = { path = "../../../../primitives/std" } sp-io = { path = "../../../../primitives/io" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 10163aacd1969..5f28c4e16231b 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -17,7 +17,7 @@ serde_json = "1" codec = { package = "parity-scale-codec", version = "3.0.0" } jsonrpsee = { version = "0.13.0", features = ["server"] } futures = "0.3.21" -log = "0.4.16" +log = "0.4.17" frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 48e9c1d6b36a1..a357378dc1903 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "3.1.18", features = ["derive"] } -log = "0.4.16" +log = "0.4.17" parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = { version = "0.10.0", default-features = false } diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 9864cfd0823ce..3c2f8321befbe 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures-util = { version = "0.3.19", default-features = false, features = ["io"] } hyper = { version = "0.14.16", default-features = false, features = ["http1", "server", "tcp"] } -log = "0.4.16" +log = "0.4.17" prometheus = { version = "0.13.0", default-features = false } thiserror = "1.0" tokio = { version = "1.17.0", features = ["parking_lot"] } From e8e6833213ef358db0e1e34bc2dfc39fcf60cff7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 10:07:00 +0200 Subject: [PATCH 0797/1472] Bump scale-info from 2.0.1 to 2.1.1 (#11420) Bumps [scale-info](https://github.com/paritytech/scale-info) from 2.0.1 to 2.1.1. - [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/commits/v2.1.1) --- 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 ++++---- bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- bin/node/primitives/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- frame/assets/Cargo.toml | 2 +- frame/atomic-swap/Cargo.toml | 2 +- frame/aura/Cargo.toml | 2 +- frame/authority-discovery/Cargo.toml | 2 +- frame/authorship/Cargo.toml | 2 +- frame/babe/Cargo.toml | 2 +- frame/bags-list/Cargo.toml | 2 +- frame/balances/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 2 +- frame/bounties/Cargo.toml | 2 +- frame/child-bounties/Cargo.toml | 2 +- frame/collective/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/rpc/runtime-api/Cargo.toml | 2 +- frame/conviction-voting/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- frame/election-provider-multi-phase/Cargo.toml | 2 +- frame/election-provider-support/Cargo.toml | 2 +- frame/election-provider-support/solution-type/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- frame/examples/basic/Cargo.toml | 2 +- frame/examples/offchain-worker/Cargo.toml | 2 +- frame/examples/parallel/Cargo.toml | 2 +- frame/executive/Cargo.toml | 2 +- frame/gilt/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/identity/Cargo.toml | 2 +- frame/im-online/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- frame/lottery/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 2 +- frame/nicks/Cargo.toml | 2 +- frame/node-authorization/Cargo.toml | 2 +- frame/nomination-pools/Cargo.toml | 2 +- frame/nomination-pools/benchmarking/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/preimage/Cargo.toml | 2 +- frame/proxy/Cargo.toml | 2 +- frame/randomness-collective-flip/Cargo.toml | 2 +- frame/recovery/Cargo.toml | 2 +- frame/referenda/Cargo.toml | 2 +- frame/remark/Cargo.toml | 2 +- frame/scheduler/Cargo.toml | 2 +- frame/scored-pool/Cargo.toml | 2 +- frame/session/Cargo.toml | 2 +- frame/session/benchmarking/Cargo.toml | 2 +- frame/society/Cargo.toml | 2 +- frame/staking/Cargo.toml | 2 +- frame/state-trie-migration/Cargo.toml | 2 +- frame/sudo/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/test/Cargo.toml | 2 +- frame/support/test/compile_pass/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- frame/system/benchmarking/Cargo.toml | 2 +- frame/timestamp/Cargo.toml | 2 +- frame/tips/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- frame/transaction-payment/asset-tx-payment/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 2 +- frame/treasury/Cargo.toml | 2 +- frame/uniques/Cargo.toml | 2 +- frame/utility/Cargo.toml | 2 +- frame/vesting/Cargo.toml | 2 +- frame/whitelist/Cargo.toml | 2 +- primitives/application-crypto/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/authority-discovery/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 2 +- primitives/consensus/aura/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/consensus/vrf/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/session/Cargo.toml | 2 +- primitives/staking/Cargo.toml | 2 +- primitives/transaction-storage-proof/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 2 +- primitives/version/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- utils/frame/rpc/state-trie-migration-rpc/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- 96 files changed, 99 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index abd9cd7b46e02..5d86af6c74262 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9066,9 +9066,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0563970d79bcbf3c537ce3ad36d859b30d36fc5b190efd227f1f7a84d7cf0d42" +checksum = "8980cafbe98a7ee7a9cc16b32ebce542c77883f512d83fbf2ddc8f6a85ea74c9" dependencies = [ "bitvec", "cfg-if 1.0.0", @@ -9080,9 +9080,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7805950c36512db9e3251c970bb7ac425f326716941862205d612ab3b5e46e2" +checksum = "4260c630e8a8a33429d1688eff2f163f24c65a4e1b1578ef6b565061336e4b6f" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 0647761a62f9c..6f7a4b1d25841 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../../../frame/benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../../../frame/support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../../frame/system" } diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 43dc98f254651..734ed089aa4bd 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } pallet-aura = { version = "4.0.0-dev", default-features = false, path = "../../../frame/aura" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../../frame/balances" } diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 909bd19103742..6b6a1709d5aa0 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -scale-info = { version = "2.0.1", features = ["derive"] } +scale-info = { version = "2.1.1", features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 810b41003109d..bc6fa669ca4ea 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../../primitives/application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 46d9ff03ed36e..1b3e9083d1a1d 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } static_assertions = "1.1.0" hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 0ad0b7cc5bfdc..f63f8ee65fbec 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" log = "0.4.17" parking_lot = "0.12.0" -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" thiserror = "1.0" diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index d3685e6582324..9e98d4e15aed4 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 4fd793496572e..e70041f21ca96 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index 2ce90ff0215ae..7dad0b6b1b098 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index bebe8e0f436a6..514fd7e244ef9 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-session = { version = "4.0.0-dev", default-features = false, features = [ diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index bc7fad9684e1f..3078b9dfa295a 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", ] } impl-trait-for-tuples = "0.2.2" -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 23f8f1517cb63..dd76726df3017 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 4efa1fbe287fa..9590d3d3ec4a4 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # primitives sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index b2840eb3e1787..10150f0895906 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 85986c2a41529..8da182f1c29fc 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex = { version = "0.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } beefy-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "./primitives" } beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy" } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 89a49831d9f62..eecce963d19f0 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -10,7 +10,7 @@ homepage = "https://substrate.io" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 6dddcf7e247ae..4205274b5dbc3 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = linregress = { version = "0.4.4", optional = true } log = { version = "0.4.17", default-features = false } paste = "1.0" -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index d37c06a96e88e..645772fb27669 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", ] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 722ee0af01f95..575f3e38c8183 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", ] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index b810c3f3bd11d..0cb2a8b136044 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 2e906b69f32fc..d27801df33bda 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } log = { version = "0.4", default-features = false } wasm-instrument = { version = "0.1", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml index e50a41624e7e9..bd07d577ec272 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/rpc/runtime-api/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # Substrate Dependencies pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../common" } diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index 4ebc3c8f4bc43..ff6cfcc3efdee 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -17,7 +17,7 @@ assert_matches = "1.3.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index b36448bdf25ef..e0b85ed7d18df 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 6f3e500577af6..6c8e537a72c64 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -17,7 +17,7 @@ static_assertions = "1.1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = [ +scale-info = { version = "2.1.1", default-features = false, features = [ "derive", ] } log = { version = "0.4.17", default-features = false } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index bfddd25a1fa3e..67e1ea63cb655 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { version = "4.0.0-dev", path = "solution-type" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index a4e7256127115..8fd7ddbff434d 100644 --- a/frame/election-provider-support/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -22,7 +22,7 @@ proc-macro-crate = "1.1.3" [dev-dependencies] parity-scale-codec = "3.0.0" -scale-info = "2.0.1" +scale-info = "2.1.1" sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } # used by generate_solution_type: frame-election-provider-support = { version = "4.0.0-dev", path = ".." } diff --git a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 6520f6e632230..10f82cd316851 100644 --- a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -18,7 +18,7 @@ honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { version = "4.0.0-dev", path = ".." } frame-election-provider-support = { version = "4.0.0-dev", path = "../.." } sp-arithmetic = { version = "5.0.0", path = "../../../../primitives/arithmetic" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index d6bea8b3c290f..a5f0c7c89321a 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index bcc845823e137..e63b82757c030 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } lite-json = { version = "0.1", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/frame/examples/parallel/Cargo.toml b/frame/examples/parallel/Cargo.toml index 6834a9143ae97..f4d2c72a23a49 100644 --- a/frame/examples/parallel/Cargo.toml +++ b/frame/examples/parallel/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index ed3c5282fc81d..b67f3313e612b 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index 4916b950e47dd..d6f61c6d250ba 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index fb2ffe42f526b..cb4233a26fb33 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index d5057e302339b..8e821537fd9b2 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } enumflags2 = { version = "0.7.4" } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index 0279e29169006..a90b95b21cd88 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index 99edf95fb332b..90eb18a106000 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 9e5992195441e..8f7c8eefe800d 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 356fc12b09507..0473fd46956af 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 0b5d404fe23aa..f5f8bdee0855d 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.3.2", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index c151016c594c7..a370215032714 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 5ee2e9193dd2a..1d378b257f5a2 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index a22af2d87578e..0b27028228c10 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index 1ac8caa5f64b4..0820125d77f44 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # FRAME frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/nomination-pools/benchmarking/Cargo.toml b/frame/nomination-pools/benchmarking/Cargo.toml index 58158c20cf195..2e045c95ec9b3 100644 --- a/frame/nomination-pools/benchmarking/Cargo.toml +++ b/frame/nomination-pools/benchmarking/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # FRAME frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 91553ea414f7e..ddbed3d3297fa 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 9face65182f7e..325e906c61a3c 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index 62cbb16dddf29..aaacaa23021e7 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["max-encoded-len"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index 692f33575e127..03f0022a42e29 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } safe-mix = { version = "1.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 2a72963f6cf0d..396555b3e2758 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index d13d08542f56e..75888c6d14f3d 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -17,7 +17,7 @@ assert_matches = { version = "1.5", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/remark/Cargo.toml b/frame/remark/Cargo.toml index 573502779c586..71a65ce554975 100644 --- a/frame/remark/Cargo.toml +++ b/frame/remark/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 0908fc110802a..d92d0df0c8037 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index c857dc9ab9ace..2ec765498be9e 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 56c72eeaf6d4b..14996782eae87 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 1cce8fec023db..930ddb0ce7057 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -25,7 +25,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../../primiti [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } -scale-info = "2.0.1" +scale-info = "2.1.1" frame-election-provider-support = { version = "4.0.0-dev", path = "../../election-provider-support" } pallet-balances = { version = "4.0.0-dev", path = "../../balances" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index b19820c66fb58..5e13c95d74eb3 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } rand_chacha = { version = "0.2", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index cc8e19b1de892..0950478fba089 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -17,7 +17,7 @@ serde = { version = "1.0.136", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index be3e4392ac918..9c8c05a4fada4 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.133", optional = true } thousands = { version = "0.2.0", optional = true } zstd = { version = "0.10.0", default-features = false, optional = true } diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index d2b3f98e65d0b..efa75813af543 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 2d510fd4690ca..7d88f7fe8eb6f 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-metadata = { version = "15.0.0", default-features = false, features = ["v14"] } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 4aa0ff7d5a347..dd23d7e6b0d96 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { version = "1.0.136", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../../primitives/arithmetic" } sp-io = { version = "6.0.0", path = "../../../primitives/io", default-features = false } sp-state-machine = { version = "0.12.0", optional = true, path = "../../../primitives/state-machine" } diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index c1619c6a56c97..34bd980e0187b 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../../../primitives/core" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 38a2b934cef17..3429c6546c7fd 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index b39b1a1c75b9d..437d06a17c781 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 6ce1592cae3f9..8967733f7c5c8 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 23f61dc4f96cd..e2ca152148db6 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 6da8f4c699097..519433a8ce0a8 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } smallvec = "1.8.0" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 0c2bcb730aa75..fb000dbfdb103 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -25,7 +25,7 @@ pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, # Other dependencies codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } [dev-dependencies] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 99bea1cd36882..a5195c4f75974 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } hex-literal = { version = "0.3.4", optional = true } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 4ae2c035e482a..56c2fcdab58f7 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "max-encoded-len", ] } impl-trait-for-tuples = "0.2.2" -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 0441289b3a351..19b0790947f84 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 066682e0e349e..7b56d7974e4b5 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 1690e9eb19f72..eb902c0633331 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", ] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/frame/whitelist/Cargo.toml b/frame/whitelist/Cargo.toml index c808cacb801af..daee560904a08 100644 --- a/frame/whitelist/Cargo.toml +++ b/frame/whitelist/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index a8181ca5380c2..117e84e959392 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { version = "6.0.0", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 31b893531a8d5..4fdf983943c41 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } integer-sqrt = "0.1.2" num-traits = { version = "0.2.8", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } static_assertions = "1.1.0" sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index 6a822bf20b329..b5491931d19ba 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 83896674175bc..320a30770ab42 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index 41d02ac0779a3..dbb67a27c5144 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.50", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } sp-consensus = { version = "0.10.0-dev", optional = true, path = "../common" } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 57775a1b718da..736a78ab67b1a 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.50", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } merlin = { version = "2.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 44aabf074d137..3209fb230b5aa 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false } +scale-info = { version = "2.1.1", default-features = false } schnorrkel = { version = "0.9.1", default-features = false, features = ["preaudit_deprecated", "u64_backend"] } sp-core = { version = "6.0.0", default-features = false, path = "../../core" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 852812c1c5659..34727f8fb6b78 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index c8b24c97bbafd..f86e2ab07e673 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.15.0", default-features = false, features = ["derive-codec"] } log = { version = "0.4.17", optional = true } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 7cd3ed1489798..db42199a52984 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index a0c420329b3d0..42a80296a4530 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -18,7 +18,7 @@ clap = { version = "3.1.18", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } sp-runtime = { version = "6.0.0", path = "../../runtime" } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index ca4ba82e1aee8..8655a9808d5bf 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -22,7 +22,7 @@ log = { version = "0.4.17", default-features = false } parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } paste = "1.0" rand = { version = "0.7.2", optional = true } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index b45e7131d5fee..fb04b06e75327 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-runtime = { version = "6.0.0", optional = true, path = "../runtime" } diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index ac6c9d0e6428c..7afc13d7c5723 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index 9501f86cca055..a5a80528c6734 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.50", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", optional = true } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-core = { version = "6.0.0", optional = true, path = "../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 60dd88b187bd2..a3754461f890e 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -21,7 +21,7 @@ harness = false codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } hash-db = { version = "0.15.2", default-features = false } memory-db = { version = "0.29.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } trie-db = { version = "0.23.1", default-features = false } trie-root = { version = "0.17.0", default-features = false } diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 8e48891a3c74e..0ca78940fbbbc 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } impl-serde = { version = "0.3.1", optional = true } parity-wasm = { version = "0.42.2", optional = true } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } thiserror = { version = "1.0.30", optional = true } sp-core-hashing-proc-macro = { version = "5.0.0", path = "../core/hashing/proc-macro" } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 8c529bb6a00a9..739be9ec8bdd8 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -19,7 +19,7 @@ sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = " sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } memory-db = { version = "0.29.0", default-features = false } diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 8fe0ad8d61d6e..f4fbb1acbc0b1 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } serde = { version = "1", features = ["derive"] } log = { version = "0.4.17", default-features = false } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 262da29b01d9a..b19c3f235c7c7 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -24,7 +24,7 @@ sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } [dev-dependencies] -scale-info = "2.0.1" +scale-info = "2.1.1" jsonrpsee = { version = "0.13.0", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.17.0" frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } From 73ca2dacd2bcfd300d270b4e0211621200c0c596 Mon Sep 17 00:00:00 2001 From: yjh Date: Mon, 16 May 2022 16:25:34 +0800 Subject: [PATCH 0798/1472] remove unused error InvalidCode and improve docs (#11383) --- client/executor/common/src/error.rs | 3 --- client/executor/src/wasm_runtime.rs | 6 +----- frame/executive/src/lib.rs | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/client/executor/common/src/error.rs b/client/executor/common/src/error.rs index 5ffcafd7e92c4..09e070bb3bae5 100644 --- a/client/executor/common/src/error.rs +++ b/client/executor/common/src/error.rs @@ -43,9 +43,6 @@ pub enum Error { #[error("Method not found: '{0}'")] MethodNotFound(String), - #[error("Invalid Code (expected single byte): '{0}'")] - InvalidCode(String), - #[error("On-chain runtime does not specify version")] VersionInvalid, diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 9c07dd7abf1f2..85c33ecacf8ff 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -191,8 +191,6 @@ impl RuntimeCache { /// This uses internal cache to find available instance or create a new one. /// # Parameters /// - /// `code` - Provides external code or tells the executor to fetch it from storage. - /// /// `runtime_code` - The runtime wasm code used setup the runtime. /// /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. @@ -201,8 +199,6 @@ impl RuntimeCache { /// /// `allow_missing_func_imports` - Ignore missing function imports. /// - /// `max_runtime_instances` - The size of the instances cache. - /// /// `f` - Function to execute. /// /// `H` - A compile-time list of host functions to expose to the runtime. @@ -210,7 +206,7 @@ impl RuntimeCache { /// # Returns result of `f` wrapped in an additional result. /// In case of failure one of two errors can be returned: /// - /// `Err::InvalidCode` is returned for runtime code issues. + /// `Err::RuntimeConstruction` is returned for runtime construction issues. /// /// `Error::InvalidMemoryReference` is returned if no memory export with the /// identifier `memory` can be found in the runtime. diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index f1e7485d7440c..4affc26f831fd 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -1299,7 +1299,7 @@ mod tests { sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); - // set block number to non zero so events are not exlcuded + // set block number to non zero so events are not excluded System::set_block_number(1); Executive::initialize_block(&Header::new( From fe9ea15ab2733009a788e9b61dbead6944f4972e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 10:01:12 +0000 Subject: [PATCH 0799/1472] Bump ss58-registry from 1.17.0 to 1.18.0 (#11419) Bumps [ss58-registry](https://github.com/paritytech/ss58-registry) from 1.17.0 to 1.18.0. - [Release notes](https://github.com/paritytech/ss58-registry/releases) - [Changelog](https://github.com/paritytech/ss58-registry/blob/main/CHANGELOG.md) - [Commits](https://github.com/paritytech/ss58-registry/compare/v1.17.0...v1.18.0) --- updated-dependencies: - dependency-name: ss58-registry 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 | 4 ++-- primitives/core/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d86af6c74262..4733f33fd87d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10366,9 +10366,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "ss58-registry" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b84a70894df7a73666e0694f44b41a9571625e9546fb58a0818a565d2c7e084" +checksum = "ceb8b72a924ccfe7882d0e26144c114503760a4d1248bb5cd06c8ab2d55404cc" dependencies = [ "Inflector", "num-format", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 34727f8fb6b78..cdc12c677e4f3 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -57,7 +57,7 @@ hex = { version = "0.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } secp256k1 = { version = "0.21.2", default-features = false, features = ["recovery", "alloc"], optional = true } -ss58-registry = { version = "1.17.0", default-features = false } +ss58-registry = { version = "1.18.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } From 4fd77a94e1aa516c7eb9f6a0428f81637fe87f07 Mon Sep 17 00:00:00 2001 From: Dmitriy Shabanov Date: Mon, 16 May 2022 16:03:22 +0500 Subject: [PATCH 0800/1472] serde::{Serialize, Deserialize} for BoundedVec (#11314) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * serde::{Serialize, Deserialize} for BoundedVec * Apply suggestions from code review * FMT * :facepalm: Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- Cargo.lock | 1 + frame/support/Cargo.toml | 1 + frame/support/src/storage/bounded_vec.rs | 92 +++++++++++++++++++++++- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 4733f33fd87d2..e77daaafd0778 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2296,6 +2296,7 @@ dependencies = [ "pretty_assertions", "scale-info", "serde", + "serde_json", "smallvec", "sp-arithmetic", "sp-core", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 7d88f7fe8eb6f..ca26d3a5e32f2 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -38,6 +38,7 @@ sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/ k256 = { version = "0.10.4", default-features = false, features = ["ecdsa"] } [dev-dependencies] +serde_json = "1.0.79" assert_matches = "1.3.0" pretty_assertions = "1.2.1" frame-system = { version = "4.0.0-dev", path = "../system" } diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 92ca167f98436..e99ec6850b9f4 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -28,6 +28,11 @@ use core::{ ops::{Deref, Index, IndexMut, RangeBounds}, slice::SliceIndex, }; +#[cfg(feature = "std")] +use serde::{ + de::{Error, SeqAccess, Visitor}, + Deserialize, Deserializer, Serialize, +}; use sp_std::{marker::PhantomData, prelude::*}; /// A bounded vector. @@ -37,9 +42,67 @@ use sp_std::{marker::PhantomData, prelude::*}; /// /// As the name suggests, the length of the queue is always bounded. All internal operations ensure /// this bound is respected. +#[cfg_attr(feature = "std", derive(Serialize), serde(transparent))] #[derive(Encode, scale_info::TypeInfo)] #[scale_info(skip_type_params(S))] -pub struct BoundedVec(Vec, PhantomData); +pub struct BoundedVec( + Vec, + #[cfg_attr(feature = "std", serde(skip_serializing))] PhantomData, +); + +#[cfg(feature = "std")] +impl<'de, T, S: Get> Deserialize<'de> for BoundedVec +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VecVisitor>(PhantomData<(T, S)>); + + impl<'de, T, S: Get> Visitor<'de> for VecVisitor + where + T: Deserialize<'de>, + { + type Value = Vec; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let size = seq.size_hint().unwrap_or(0); + let max = match usize::try_from(S::get()) { + Ok(n) => n, + Err(_) => return Err(A::Error::custom("can't convert to usize")), + }; + if size > max { + Err(A::Error::custom("out of bounds")) + } else { + let mut values = Vec::with_capacity(size); + + while let Some(value) = seq.next_element()? { + values.push(value); + if values.len() > max { + return Err(A::Error::custom("out of bounds")) + } + } + + Ok(values) + } + } + } + + let visitor: VecVisitor = VecVisitor(PhantomData); + deserializer + .deserialize_seq(visitor) + .map(|v| BoundedVec::::try_from(v).map_err(|_| Error::custom("out of bounds")))? + } +} /// A bounded slice. /// @@ -908,4 +971,31 @@ pub mod test { assert!(b.try_extend(vec![4, 5, 6].into_iter()).is_err()); assert_eq!(*b, vec![1, 2, 3]); } + + #[test] + fn test_serializer() { + let c: BoundedVec> = bounded_vec![0, 1, 2]; + assert_eq!(serde_json::json!(&c).to_string(), r#"[0,1,2]"#); + } + + #[test] + fn test_deserializer() { + let c: BoundedVec> = serde_json::from_str(r#"[0,1,2]"#).unwrap(); + + assert_eq!(c.len(), 3); + assert_eq!(c[0], 0); + assert_eq!(c[1], 1); + assert_eq!(c[2], 2); + } + + #[test] + fn test_deserializer_failed() { + let c: Result>, serde_json::error::Error> = + serde_json::from_str(r#"[0,1,2,3,4,5]"#); + + match c { + Err(msg) => assert_eq!(msg.to_string(), "out of bounds at line 1 column 11"), + _ => unreachable!("deserializer must raise error"), + } + } } From 7879b22b7f81c562b268fd3f2ae8b56ac67799ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 13:09:12 +0200 Subject: [PATCH 0801/1472] Bump prost from 0.9.0 to 0.10.3 (#11425) Bumps [prost](https://github.com/tokio-rs/prost) from 0.9.0 to 0.10.3. - [Release notes](https://github.com/tokio-rs/prost/releases) - [Commits](https://github.com/tokio-rs/prost/compare/v0.9.0...v0.10.3) --- updated-dependencies: - dependency-name: prost 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 | 57 +++++++++++++++++++-------- client/authority-discovery/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/light/Cargo.toml | 2 +- client/network/sync/Cargo.toml | 2 +- 5 files changed, 44 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e77daaafd0778..201feb7e06d7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3515,7 +3515,7 @@ dependencies = [ "libp2p-request-response", "libp2p-swarm", "log", - "prost", + "prost 0.9.0", "prost-build", "rand 0.8.4", ] @@ -3542,7 +3542,7 @@ dependencies = [ "multistream-select", "parking_lot 0.12.0", "pin-project 1.0.10", - "prost", + "prost 0.9.0", "prost-build", "rand 0.8.4", "ring", @@ -3592,7 +3592,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost", + "prost 0.9.0", "prost-build", "rand 0.7.3", "smallvec", @@ -3616,7 +3616,7 @@ dependencies = [ "libp2p-swarm", "log", "prometheus-client", - "prost", + "prost 0.9.0", "prost-build", "rand 0.7.3", "regex", @@ -3638,7 +3638,7 @@ dependencies = [ "libp2p-swarm", "log", "lru", - "prost", + "prost 0.9.0", "prost-build", "smallvec", ] @@ -3660,7 +3660,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost", + "prost 0.9.0", "prost-build", "rand 0.7.3", "sha2 0.10.2", @@ -3738,7 +3738,7 @@ dependencies = [ "lazy_static", "libp2p-core", "log", - "prost", + "prost 0.9.0", "prost-build", "rand 0.8.4", "sha2 0.10.2", @@ -3775,7 +3775,7 @@ dependencies = [ "futures", "libp2p-core", "log", - "prost", + "prost 0.9.0", "prost-build", "unsigned-varint", "void", @@ -3811,7 +3811,7 @@ dependencies = [ "libp2p-swarm", "log", "pin-project 1.0.10", - "prost", + "prost 0.9.0", "prost-build", "rand 0.8.4", "smallvec", @@ -3835,7 +3835,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost", + "prost 0.9.0", "prost-build", "rand 0.8.4", "sha2 0.10.2", @@ -7013,7 +7013,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.9.0", +] + +[[package]] +name = "prost" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc03e116981ff7d8da8e5c220e374587b98d294af7ba7dd7fda761158f00086f" +dependencies = [ + "bytes", + "prost-derive 0.10.1", ] [[package]] @@ -7029,7 +7039,7 @@ dependencies = [ "log", "multimap", "petgraph", - "prost", + "prost 0.9.0", "prost-types", "regex", "tempfile", @@ -7049,6 +7059,19 @@ dependencies = [ "syn", ] +[[package]] +name = "prost-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "prost-types" version = "0.9.0" @@ -7056,7 +7079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" dependencies = [ "bytes", - "prost", + "prost 0.9.0", ] [[package]] @@ -7861,7 +7884,7 @@ dependencies = [ "libp2p", "log", "parity-scale-codec", - "prost", + "prost 0.10.3", "prost-build", "quickcheck", "rand 0.7.3", @@ -8509,7 +8532,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.0", "pin-project 1.0.10", - "prost", + "prost 0.10.3", "prost-build", "quickcheck", "rand 0.7.3", @@ -8581,7 +8604,7 @@ dependencies = [ "libp2p", "log", "parity-scale-codec", - "prost", + "prost 0.10.3", "prost-build", "sc-client-api", "sc-network-common", @@ -8604,7 +8627,7 @@ dependencies = [ "log", "lru", "parity-scale-codec", - "prost", + "prost 0.10.3", "prost-build", "quickcheck", "sc-block-builder", diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 2545447001511..96c07b5dae278 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -24,7 +24,7 @@ futures-timer = "3.0.1" ip_network = "0.4.1" libp2p = { version = "0.44.0", default-features = false, features = ["kad"] } log = "0.4.17" -prost = "0.9" +prost = "0.10" rand = "0.7.2" thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 4d6af584d8610..f222c39673516 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -36,7 +36,7 @@ log = "0.4.17" lru = "0.7.5" parking_lot = "0.12.0" pin-project = "1.0.10" -prost = "0.9" +prost = "0.10" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index 8bbbce9274c0c..aa0b003e00763 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ futures = "0.3.21" libp2p = "0.44.0" log = "0.4.16" -prost = "0.9" +prost = "0.10" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-network-common = { version = "0.10.0-dev", path = "../common" } diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index e570310ceb955..c557c9bf42b92 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -26,7 +26,7 @@ futures = "0.3.21" libp2p = "0.44.0" log = "0.4.17" lru = "0.7.5" -prost = "0.9" +prost = "0.10" smallvec = "1.8.0" thiserror = "1.0" fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } From 98aa88c4bf6345a0e961e13f78e1b829524d1f2b Mon Sep 17 00:00:00 2001 From: Koute Date: Mon, 16 May 2022 21:25:15 +0900 Subject: [PATCH 0802/1472] Make sure the commit hash is always of the same length in `impl_version` (#11404) * Make sure the commit hash is always of the same length in `impl_version` * Add a comment regarding the length of the commit hash --- utils/build-script-utils/src/version.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/utils/build-script-utils/src/version.rs b/utils/build-script-utils/src/version.rs index 9432f23e9b8ee..19b507ba261e0 100644 --- a/utils/build-script-utils/src/version.rs +++ b/utils/build-script-utils/src/version.rs @@ -22,7 +22,10 @@ pub fn generate_cargo_keys() { let commit = if let Ok(hash) = std::env::var("SUBSTRATE_CLI_GIT_COMMIT_HASH") { Cow::from(hash.trim().to_owned()) } else { - match Command::new("git").args(&["rev-parse", "--short", "HEAD"]).output() { + // We deliberately set the length here to `11` to ensure that + // the emitted hash is always of the same length; otherwise + // it can (and will!) vary between different build environments. + match Command::new("git").args(&["rev-parse", "--short=11", "HEAD"]).output() { Ok(o) if o.status.success() => { let sha = String::from_utf8_lossy(&o.stdout).trim().to_owned(); Cow::from(sha) From 5d3e7c4ee9f5c8e370022d5f3fa9723185710831 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Mon, 16 May 2022 15:38:12 +0200 Subject: [PATCH 0803/1472] Use 'Items' and 'Collections' in uniques pallet (#11389) * Rename class to collection * Use "assets collection" instead of "asset collection" * Rename 'instance' to 'asset' * Change "asset `collection`" to "`collection`" * A bit more clean up * Rename Asset to Item * Add a storage hack * Typos * fix compile * fmt * Fix * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/uniques/src/lib.rs * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Change 'items collection' to 'collection' * Apply suggestions Co-authored-by: Shawn Tabrizi Co-authored-by: Parity Bot --- bin/node/runtime/src/lib.rs | 8 +- frame/support/src/traits/tokens/misc.rs | 8 +- .../support/src/traits/tokens/nonfungible.rs | 125 ++- .../support/src/traits/tokens/nonfungibles.rs | 172 ++-- frame/uniques/src/benchmarking.rs | 264 ++--- frame/uniques/src/functions.rs | 180 ++-- frame/uniques/src/impl_nonfungibles.rs | 114 +-- frame/uniques/src/lib.rs | 898 +++++++++--------- frame/uniques/src/migration.rs | 4 +- frame/uniques/src/mock.rs | 10 +- frame/uniques/src/tests.rs | 182 ++-- frame/uniques/src/types.rs | 72 +- frame/uniques/src/weights.rs | 165 ++-- 13 files changed, 1120 insertions(+), 1082 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 019c14b2c7dfd..1257aabb9d5cc 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1414,12 +1414,12 @@ parameter_types! { impl pallet_uniques::Config for Runtime { type Event = Event; - type ClassId = u32; - type InstanceId = u32; + type CollectionId = u32; + type ItemId = u32; type Currency = Balances; type ForceOrigin = frame_system::EnsureRoot; - type ClassDeposit = ClassDeposit; - type InstanceDeposit = InstanceDeposit; + type CollectionDeposit = ClassDeposit; + type ItemDeposit = InstanceDeposit; type MetadataDepositBase = MetadataDepositBase; type AttributeDepositBase = MetadataDepositBase; type DepositPerByte = MetadataDepositPerByte; diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index dd87fe36cd019..fbbef6c31822f 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -182,16 +182,16 @@ pub trait BalanceConversion { /// Trait to handle asset locking mechanism to ensure interactions with the asset can be implemented /// downstream to extend logic of Uniques current functionality. -pub trait Locker { +pub trait Locker { /// Check if the asset should be locked and prevent interactions with the asset from executing. - fn is_locked(class: ClassId, instance: InstanceId) -> bool; + fn is_locked(collection: CollectionId, item: ItemId) -> bool; } -impl Locker for () { +impl Locker for () { // Default will be false if not implemented downstream. // Note: The logic check in this function must be constant time and consistent for benchmarks // to work. - fn is_locked(_class: ClassId, _instance: InstanceId) -> bool { + fn is_locked(_collection: CollectionId, _item: ItemId) -> bool { false } } diff --git a/frame/support/src/traits/tokens/nonfungible.rs b/frame/support/src/traits/tokens/nonfungible.rs index 5cf9638131b28..fe0d2e729930e 100644 --- a/frame/support/src/traits/tokens/nonfungible.rs +++ b/frame/support/src/traits/tokens/nonfungible.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Traits for dealing with a single non-fungible asset class. +//! Traits for dealing with a single non-fungible collection of items. //! -//! This assumes a single level namespace identified by `Inspect::InstanceId`, and could +//! This assumes a single level namespace identified by `Inspect::ItemId`, and could //! reasonably be implemented by pallets which wants to expose a single collection of NFT-like //! objects. //! @@ -30,167 +30,164 @@ use codec::{Decode, Encode}; use sp_runtime::TokenError; use sp_std::prelude::*; -/// Trait for providing an interface to a read-only NFT-like set of asset instances. +/// Trait for providing an interface to a read-only NFT-like set of items. pub trait Inspect { - /// Type for identifying an asset instance. - type InstanceId; + /// Type for identifying an item. + type ItemId; - /// Returns the owner of asset `instance`, or `None` if the asset doesn't exist or has no + /// Returns the owner of `item`, or `None` if the item doesn't exist or has no /// owner. - fn owner(instance: &Self::InstanceId) -> Option; + fn owner(item: &Self::ItemId) -> Option; - /// Returns the attribute value of `instance` corresponding to `key`. + /// Returns the attribute value of `item` corresponding to `key`. /// /// By default this is `None`; no attributes are defined. - fn attribute(_instance: &Self::InstanceId, _key: &[u8]) -> Option> { + fn attribute(_item: &Self::ItemId, _key: &[u8]) -> Option> { None } - /// Returns the strongly-typed attribute value of `instance` corresponding to `key`. + /// Returns the strongly-typed attribute value of `item` corresponding to `key`. /// /// By default this just attempts to use `attribute`. - fn typed_attribute(instance: &Self::InstanceId, key: &K) -> Option { - key.using_encoded(|d| Self::attribute(instance, d)) + fn typed_attribute(item: &Self::ItemId, key: &K) -> Option { + key.using_encoded(|d| Self::attribute(item, d)) .and_then(|v| V::decode(&mut &v[..]).ok()) } - /// Returns `true` if the asset `instance` may be transferred. + /// Returns `true` if the `item` may be transferred. /// - /// Default implementation is that all assets are transferable. - fn can_transfer(_instance: &Self::InstanceId) -> bool { + /// Default implementation is that all items are transferable. + fn can_transfer(_item: &Self::ItemId) -> bool { true } } -/// Interface for enumerating assets in existence or owned by a given account over a collection +/// Interface for enumerating items in existence or owned by a given account over a collection /// of NFTs. pub trait InspectEnumerable: Inspect { - /// Returns an iterator of the instances of an asset `class` in existence. - fn instances() -> Box>; + /// Returns an iterator of the items within a `collection` in existence. + fn items() -> Box>; - /// Returns an iterator of the asset instances of all classes owned by `who`. - fn owned(who: &AccountId) -> Box>; + /// Returns an iterator of the items of all collections owned by `who`. + fn owned(who: &AccountId) -> Box>; } -/// Trait for providing an interface for NFT-like assets which may be minted, burned and/or have +/// Trait for providing an interface for NFT-like items which may be minted, burned and/or have /// attributes set on them. pub trait Mutate: Inspect { - /// Mint some asset `instance` to be owned by `who`. + /// Mint some `item` to be owned by `who`. /// /// By default, this is not a supported operation. - fn mint_into(_instance: &Self::InstanceId, _who: &AccountId) -> DispatchResult { + fn mint_into(_item: &Self::ItemId, _who: &AccountId) -> DispatchResult { Err(TokenError::Unsupported.into()) } - /// Burn some asset `instance`. + /// Burn some `item`. /// /// By default, this is not a supported operation. - fn burn( - _instance: &Self::InstanceId, - _maybe_check_owner: Option<&AccountId>, - ) -> DispatchResult { + fn burn(_item: &Self::ItemId, _maybe_check_owner: Option<&AccountId>) -> DispatchResult { Err(TokenError::Unsupported.into()) } - /// Set attribute `value` of asset `instance`'s `key`. + /// Set attribute `value` of `item`'s `key`. /// /// By default, this is not a supported operation. - fn set_attribute(_instance: &Self::InstanceId, _key: &[u8], _value: &[u8]) -> DispatchResult { + fn set_attribute(_item: &Self::ItemId, _key: &[u8], _value: &[u8]) -> DispatchResult { Err(TokenError::Unsupported.into()) } - /// Attempt to set the strongly-typed attribute `value` of `instance`'s `key`. + /// Attempt to set the strongly-typed attribute `value` of `item`'s `key`. /// /// By default this just attempts to use `set_attribute`. fn set_typed_attribute( - instance: &Self::InstanceId, + item: &Self::ItemId, key: &K, value: &V, ) -> DispatchResult { - key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(instance, k, v))) + key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(item, k, v))) } } -/// Trait for providing a non-fungible set of assets which can only be transferred. +/// Trait for providing a non-fungible set of items which can only be transferred. pub trait Transfer: Inspect { - /// Transfer asset `instance` into `destination` account. - fn transfer(instance: &Self::InstanceId, destination: &AccountId) -> DispatchResult; + /// Transfer `item` into `destination` account. + fn transfer(item: &Self::ItemId, destination: &AccountId) -> DispatchResult; } /// Convert a `fungibles` trait implementation into a `fungible` trait implementation by identifying /// a single item. pub struct ItemOf< F: nonfungibles::Inspect, - A: Get<>::ClassId>, + A: Get<>::CollectionId>, AccountId, >(sp_std::marker::PhantomData<(F, A, AccountId)>); impl< F: nonfungibles::Inspect, - A: Get<>::ClassId>, + A: Get<>::CollectionId>, AccountId, > Inspect for ItemOf { - type InstanceId = >::InstanceId; - fn owner(instance: &Self::InstanceId) -> Option { - >::owner(&A::get(), instance) + type ItemId = >::ItemId; + fn owner(item: &Self::ItemId) -> Option { + >::owner(&A::get(), item) } - fn attribute(instance: &Self::InstanceId, key: &[u8]) -> Option> { - >::attribute(&A::get(), instance, key) + fn attribute(item: &Self::ItemId, key: &[u8]) -> Option> { + >::attribute(&A::get(), item, key) } - fn typed_attribute(instance: &Self::InstanceId, key: &K) -> Option { - >::typed_attribute(&A::get(), instance, key) + fn typed_attribute(item: &Self::ItemId, key: &K) -> Option { + >::typed_attribute(&A::get(), item, key) } - fn can_transfer(instance: &Self::InstanceId) -> bool { - >::can_transfer(&A::get(), instance) + fn can_transfer(item: &Self::ItemId) -> bool { + >::can_transfer(&A::get(), item) } } impl< F: nonfungibles::InspectEnumerable, - A: Get<>::ClassId>, + A: Get<>::CollectionId>, AccountId, > InspectEnumerable for ItemOf { - fn instances() -> Box> { - >::instances(&A::get()) + fn items() -> Box> { + >::items(&A::get()) } - fn owned(who: &AccountId) -> Box> { - >::owned_in_class(&A::get(), who) + fn owned(who: &AccountId) -> Box> { + >::owned_in_collection(&A::get(), who) } } impl< F: nonfungibles::Mutate, - A: Get<>::ClassId>, + A: Get<>::CollectionId>, AccountId, > Mutate for ItemOf { - fn mint_into(instance: &Self::InstanceId, who: &AccountId) -> DispatchResult { - >::mint_into(&A::get(), instance, who) + fn mint_into(item: &Self::ItemId, who: &AccountId) -> DispatchResult { + >::mint_into(&A::get(), item, who) } - fn burn(instance: &Self::InstanceId, maybe_check_owner: Option<&AccountId>) -> DispatchResult { - >::burn(&A::get(), instance, maybe_check_owner) + fn burn(item: &Self::ItemId, maybe_check_owner: Option<&AccountId>) -> DispatchResult { + >::burn(&A::get(), item, maybe_check_owner) } - fn set_attribute(instance: &Self::InstanceId, key: &[u8], value: &[u8]) -> DispatchResult { - >::set_attribute(&A::get(), instance, key, value) + fn set_attribute(item: &Self::ItemId, key: &[u8], value: &[u8]) -> DispatchResult { + >::set_attribute(&A::get(), item, key, value) } fn set_typed_attribute( - instance: &Self::InstanceId, + item: &Self::ItemId, key: &K, value: &V, ) -> DispatchResult { - >::set_typed_attribute(&A::get(), instance, key, value) + >::set_typed_attribute(&A::get(), item, key, value) } } impl< F: nonfungibles::Transfer, - A: Get<>::ClassId>, + A: Get<>::CollectionId>, AccountId, > Transfer for ItemOf { - fn transfer(instance: &Self::InstanceId, destination: &AccountId) -> DispatchResult { - >::transfer(&A::get(), instance, destination) + fn transfer(item: &Self::ItemId, destination: &AccountId) -> DispatchResult { + >::transfer(&A::get(), item, destination) } } diff --git a/frame/support/src/traits/tokens/nonfungibles.rs b/frame/support/src/traits/tokens/nonfungibles.rs index 8bd731b20342c..d043a87ce7c10 100644 --- a/frame/support/src/traits/tokens/nonfungibles.rs +++ b/frame/support/src/traits/tokens/nonfungibles.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Traits for dealing with multiple collections of non-fungible assets. +//! Traits for dealing with multiple collections of non-fungible items. //! -//! This assumes a dual-level namespace identified by `Inspect::InstanceId`, and could +//! This assumes a dual-level namespace identified by `Inspect::ItemId`, and could //! reasonably be implemented by pallets which want to expose multiple independent collections of //! NFT-like objects. //! @@ -32,196 +32,210 @@ use codec::{Decode, Encode}; use sp_runtime::TokenError; use sp_std::prelude::*; -/// Trait for providing an interface to many read-only NFT-like sets of asset instances. +/// Trait for providing an interface to many read-only NFT-like sets of items. pub trait Inspect { - /// Type for identifying an asset instance. - type InstanceId; + /// Type for identifying an item. + type ItemId; - /// Type for identifying an asset class (an identifier for an independent collection of asset - /// instances). - type ClassId; + /// Type for identifying a collection (an identifier for an independent collection of + /// items). + type CollectionId; - /// Returns the owner of asset `instance` of `class`, or `None` if the asset doesn't exist (or - /// somehow has no owner). - fn owner(class: &Self::ClassId, instance: &Self::InstanceId) -> Option; + /// Returns the owner of `item` of `collection`, or `None` if the item doesn't exist + /// (or somehow has no owner). + fn owner(collection: &Self::CollectionId, item: &Self::ItemId) -> Option; - /// Returns the owner of the asset `class`, if there is one. For many NFTs this may not make - /// any sense, so users of this API should not be surprised to find an asset class results in - /// `None` here. - fn class_owner(_class: &Self::ClassId) -> Option { + /// Returns the owner of the `collection`, if there is one. For many NFTs this may not + /// make any sense, so users of this API should not be surprised to find a collection + /// results in `None` here. + fn collection_owner(_collection: &Self::CollectionId) -> Option { None } - /// Returns the attribute value of `instance` of `class` corresponding to `key`. + /// Returns the attribute value of `item` of `collection` corresponding to `key`. /// /// By default this is `None`; no attributes are defined. fn attribute( - _class: &Self::ClassId, - _instance: &Self::InstanceId, + _collection: &Self::CollectionId, + _item: &Self::ItemId, _key: &[u8], ) -> Option> { None } - /// Returns the strongly-typed attribute value of `instance` of `class` corresponding to `key`. + /// Returns the strongly-typed attribute value of `item` of `collection` corresponding to + /// `key`. /// /// By default this just attempts to use `attribute`. fn typed_attribute( - class: &Self::ClassId, - instance: &Self::InstanceId, + collection: &Self::CollectionId, + item: &Self::ItemId, key: &K, ) -> Option { - key.using_encoded(|d| Self::attribute(class, instance, d)) + key.using_encoded(|d| Self::attribute(collection, item, d)) .and_then(|v| V::decode(&mut &v[..]).ok()) } - /// Returns the attribute value of `class` corresponding to `key`. + /// Returns the attribute value of `collection` corresponding to `key`. /// /// By default this is `None`; no attributes are defined. - fn class_attribute(_class: &Self::ClassId, _key: &[u8]) -> Option> { + fn collection_attribute(_collection: &Self::CollectionId, _key: &[u8]) -> Option> { None } - /// Returns the strongly-typed attribute value of `class` corresponding to `key`. + /// Returns the strongly-typed attribute value of `collection` corresponding to `key`. /// - /// By default this just attempts to use `class_attribute`. - fn typed_class_attribute(class: &Self::ClassId, key: &K) -> Option { - key.using_encoded(|d| Self::class_attribute(class, d)) + /// By default this just attempts to use `collection_attribute`. + fn typed_collection_attribute( + collection: &Self::CollectionId, + key: &K, + ) -> Option { + key.using_encoded(|d| Self::collection_attribute(collection, d)) .and_then(|v| V::decode(&mut &v[..]).ok()) } - /// Returns `true` if the asset `instance` of `class` may be transferred. + /// Returns `true` if the `item` of `collection` may be transferred. /// - /// Default implementation is that all assets are transferable. - fn can_transfer(_class: &Self::ClassId, _instance: &Self::InstanceId) -> bool { + /// Default implementation is that all items are transferable. + fn can_transfer(_collection: &Self::CollectionId, _item: &Self::ItemId) -> bool { true } } -/// Interface for enumerating assets in existence or owned by a given account over many collections +/// Interface for enumerating items in existence or owned by a given account over many collections /// of NFTs. pub trait InspectEnumerable: Inspect { - /// Returns an iterator of the asset classes in existence. - fn classes() -> Box>; + /// Returns an iterator of the collections in existence. + fn collections() -> Box>; - /// Returns an iterator of the instances of an asset `class` in existence. - fn instances(class: &Self::ClassId) -> Box>; + /// Returns an iterator of the items of a `collection` in existence. + fn items(collection: &Self::CollectionId) -> Box>; - /// Returns an iterator of the asset instances of all classes owned by `who`. - fn owned(who: &AccountId) -> Box>; + /// Returns an iterator of the items of all collections owned by `who`. + fn owned(who: &AccountId) -> Box>; - /// Returns an iterator of the asset instances of `class` owned by `who`. - fn owned_in_class( - class: &Self::ClassId, + /// Returns an iterator of the items of `collection` owned by `who`. + fn owned_in_collection( + collection: &Self::CollectionId, who: &AccountId, - ) -> Box>; + ) -> Box>; } -/// Trait for providing the ability to create classes of nonfungible assets. +/// Trait for providing the ability to create collections of nonfungible items. pub trait Create: Inspect { - /// Create a `class` of nonfungible assets to be owned by `who` and managed by `admin`. - fn create_class(class: &Self::ClassId, who: &AccountId, admin: &AccountId) -> DispatchResult; + /// Create a `collection` of nonfungible items to be owned by `who` and managed by `admin`. + fn create_collection( + collection: &Self::CollectionId, + who: &AccountId, + admin: &AccountId, + ) -> DispatchResult; } -/// Trait for providing the ability to destroy classes of nonfungible assets. +/// Trait for providing the ability to destroy collections of nonfungible items. pub trait Destroy: Inspect { - /// The witness data needed to destroy an asset. + /// The witness data needed to destroy an item. type DestroyWitness; - /// Provide the appropriate witness data needed to destroy an asset. - fn get_destroy_witness(class: &Self::ClassId) -> Option; + /// Provide the appropriate witness data needed to destroy an item. + fn get_destroy_witness(collection: &Self::CollectionId) -> Option; - /// Destroy an existing fungible asset. - /// * `class`: The `ClassId` to be destroyed. + /// Destroy an existing fungible item. + /// * `collection`: The `CollectionId` to be destroyed. /// * `witness`: Any witness data that needs to be provided to complete the operation /// successfully. /// * `maybe_check_owner`: An optional account id that can be used to authorize the destroy /// command. If not provided, we will not do any authorization checks before destroying the - /// asset. + /// item. /// - /// If successful, this function will return the actual witness data from the destroyed asset. + /// If successful, this function will return the actual witness data from the destroyed item. /// This may be different than the witness data provided, and can be used to refund weight. fn destroy( - class: Self::ClassId, + collection: Self::CollectionId, witness: Self::DestroyWitness, maybe_check_owner: Option, ) -> Result; } -/// Trait for providing an interface for multiple classes of NFT-like assets which may be minted, -/// burned and/or have attributes set on them. +/// Trait for providing an interface for multiple collections of NFT-like items which may be +/// minted, burned and/or have attributes set on them. pub trait Mutate: Inspect { - /// Mint some asset `instance` of `class` to be owned by `who`. + /// Mint some `item` of `collection` to be owned by `who`. /// /// By default, this is not a supported operation. fn mint_into( - _class: &Self::ClassId, - _instance: &Self::InstanceId, + _collection: &Self::CollectionId, + _item: &Self::ItemId, _who: &AccountId, ) -> DispatchResult { Err(TokenError::Unsupported.into()) } - /// Burn some asset `instance` of `class`. + /// Burn some `item` of `collection`. /// /// By default, this is not a supported operation. fn burn( - _class: &Self::ClassId, - _instance: &Self::InstanceId, + _collection: &Self::CollectionId, + _item: &Self::ItemId, _maybe_check_owner: Option<&AccountId>, ) -> DispatchResult { Err(TokenError::Unsupported.into()) } - /// Set attribute `value` of asset `instance` of `class`'s `key`. + /// Set attribute `value` of `item` of `collection`'s `key`. /// /// By default, this is not a supported operation. fn set_attribute( - _class: &Self::ClassId, - _instance: &Self::InstanceId, + _collection: &Self::CollectionId, + _item: &Self::ItemId, _key: &[u8], _value: &[u8], ) -> DispatchResult { Err(TokenError::Unsupported.into()) } - /// Attempt to set the strongly-typed attribute `value` of `instance` of `class`'s `key`. + /// Attempt to set the strongly-typed attribute `value` of `item` of `collection`'s `key`. /// /// By default this just attempts to use `set_attribute`. fn set_typed_attribute( - class: &Self::ClassId, - instance: &Self::InstanceId, + collection: &Self::CollectionId, + item: &Self::ItemId, key: &K, value: &V, ) -> DispatchResult { - key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(class, instance, k, v))) + key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(collection, item, k, v))) } - /// Set attribute `value` of asset `class`'s `key`. + /// Set attribute `value` of `collection`'s `key`. /// /// By default, this is not a supported operation. - fn set_class_attribute(_class: &Self::ClassId, _key: &[u8], _value: &[u8]) -> DispatchResult { + fn set_collection_attribute( + _collection: &Self::CollectionId, + _key: &[u8], + _value: &[u8], + ) -> DispatchResult { Err(TokenError::Unsupported.into()) } - /// Attempt to set the strongly-typed attribute `value` of `class`'s `key`. + /// Attempt to set the strongly-typed attribute `value` of `collection`'s `key`. /// /// By default this just attempts to use `set_attribute`. - fn set_typed_class_attribute( - class: &Self::ClassId, + fn set_typed_collection_attribute( + collection: &Self::CollectionId, key: &K, value: &V, ) -> DispatchResult { - key.using_encoded(|k| value.using_encoded(|v| Self::set_class_attribute(class, k, v))) + key.using_encoded(|k| { + value.using_encoded(|v| Self::set_collection_attribute(collection, k, v)) + }) } } -/// Trait for providing a non-fungible sets of assets which can only be transferred. +/// Trait for providing a non-fungible sets of items which can only be transferred. pub trait Transfer: Inspect { - /// Transfer asset `instance` of `class` into `destination` account. + /// Transfer `item` of `collection` into `destination` account. fn transfer( - class: &Self::ClassId, - instance: &Self::InstanceId, + collection: &Self::CollectionId, + item: &Self::ItemId, destination: &AccountId, ) -> DispatchResult; } diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index b743ca12913a3..cd66d03922141 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Assets pallet benchmarking. +//! Uniques pallet benchmarking. #![cfg(feature = "runtime-benchmarks")] @@ -36,32 +36,32 @@ use crate::Pallet as Uniques; const SEED: u32 = 0; -fn create_class, I: 'static>( -) -> (T::ClassId, T::AccountId, ::Source) { +fn create_collection, I: 'static>( +) -> (T::CollectionId, T::AccountId, ::Source) { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - let class = T::Helper::class(0); + let collection = T::Helper::collection(0); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); assert!(Uniques::::force_create( SystemOrigin::Root.into(), - class, + collection, caller_lookup.clone(), false, ) .is_ok()); - (class, caller, caller_lookup) + (collection, caller, caller_lookup) } -fn add_class_metadata, I: 'static>( +fn add_collection_metadata, I: 'static>( ) -> (T::AccountId, ::Source) { - let caller = Class::::get(T::Helper::class(0)).unwrap().owner; + let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; if caller != whitelisted_caller() { whitelist_account!(caller); } let caller_lookup = T::Lookup::unlookup(caller.clone()); - assert!(Uniques::::set_class_metadata( + assert!(Uniques::::set_collection_metadata( SystemOrigin::Signed(caller.clone()).into(), - T::Helper::class(0), + T::Helper::collection(0), vec![0; T::StringLimit::get() as usize].try_into().unwrap(), false, ) @@ -69,37 +69,37 @@ fn add_class_metadata, I: 'static>( (caller, caller_lookup) } -fn mint_instance, I: 'static>( +fn mint_item, I: 'static>( index: u16, -) -> (T::InstanceId, T::AccountId, ::Source) { - let caller = Class::::get(T::Helper::class(0)).unwrap().admin; +) -> (T::ItemId, T::AccountId, ::Source) { + let caller = Collection::::get(T::Helper::collection(0)).unwrap().admin; if caller != whitelisted_caller() { whitelist_account!(caller); } let caller_lookup = T::Lookup::unlookup(caller.clone()); - let instance = T::Helper::instance(index); + let item = T::Helper::item(index); assert!(Uniques::::mint( SystemOrigin::Signed(caller.clone()).into(), - T::Helper::class(0), - instance, + T::Helper::collection(0), + item, caller_lookup.clone(), ) .is_ok()); - (instance, caller, caller_lookup) + (item, caller, caller_lookup) } -fn add_instance_metadata, I: 'static>( - instance: T::InstanceId, +fn add_item_metadata, I: 'static>( + item: T::ItemId, ) -> (T::AccountId, ::Source) { - let caller = Class::::get(T::Helper::class(0)).unwrap().owner; + let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; if caller != whitelisted_caller() { whitelist_account!(caller); } let caller_lookup = T::Lookup::unlookup(caller.clone()); assert!(Uniques::::set_metadata( SystemOrigin::Signed(caller.clone()).into(), - T::Helper::class(0), - instance, + T::Helper::collection(0), + item, vec![0; T::StringLimit::get() as usize].try_into().unwrap(), false, ) @@ -107,10 +107,10 @@ fn add_instance_metadata, I: 'static>( (caller, caller_lookup) } -fn add_instance_attribute, I: 'static>( - instance: T::InstanceId, +fn add_item_attribute, I: 'static>( + item: T::ItemId, ) -> (BoundedVec, T::AccountId, ::Source) { - let caller = Class::::get(T::Helper::class(0)).unwrap().owner; + let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; if caller != whitelisted_caller() { whitelist_account!(caller); } @@ -118,8 +118,8 @@ fn add_instance_attribute, I: 'static>( let key: BoundedVec<_, _> = vec![0; T::KeyLimit::get() as usize].try_into().unwrap(); assert!(Uniques::::set_attribute( SystemOrigin::Signed(caller.clone()).into(), - T::Helper::class(0), - Some(instance), + T::Helper::collection(0), + Some(item), key.clone(), vec![0; T::ValueLimit::get() as usize].try_into().unwrap(), ) @@ -137,24 +137,24 @@ fn assert_last_event, I: 'static>(generic_event: >:: benchmarks_instance_pallet! { create { - let class = T::Helper::class(0); - let origin = T::CreateOrigin::successful_origin(&class); - let caller = T::CreateOrigin::ensure_origin(origin.clone(), &class).unwrap(); + let collection = T::Helper::collection(0); + let origin = T::CreateOrigin::successful_origin(&collection); + let caller = T::CreateOrigin::ensure_origin(origin.clone(), &collection).unwrap(); whitelist_account!(caller); let admin = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - let call = Call::::create { class, admin }; + let call = Call::::create { collection, admin }; }: { call.dispatch_bypass_filter(origin)? } verify { - assert_last_event::(Event::Created { class: T::Helper::class(0), creator: caller.clone(), owner: caller }.into()); + assert_last_event::(Event::Created { collection: T::Helper::collection(0), creator: caller.clone(), owner: caller }.into()); } force_create { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - }: _(SystemOrigin::Root, T::Helper::class(0), caller_lookup, true) + }: _(SystemOrigin::Root, T::Helper::collection(0), caller_lookup, true) verify { - assert_last_event::(Event::ForceCreated { class: T::Helper::class(0), owner: caller }.into()); + assert_last_event::(Event::ForceCreated { collection: T::Helper::collection(0), owner: caller }.into()); } destroy { @@ -162,57 +162,57 @@ benchmarks_instance_pallet! { let m in 0 .. 1_000; let a in 0 .. 1_000; - let (class, caller, caller_lookup) = create_class::(); - add_class_metadata::(); + let (collection, caller, caller_lookup) = create_collection::(); + add_collection_metadata::(); for i in 0..n { - mint_instance::(i as u16); + mint_item::(i as u16); } for i in 0..m { - add_instance_metadata::(T::Helper::instance(i as u16)); + add_item_metadata::(T::Helper::item(i as u16)); } for i in 0..a { - add_instance_attribute::(T::Helper::instance(i as u16)); + add_item_attribute::(T::Helper::item(i as u16)); } - let witness = Class::::get(class).unwrap().destroy_witness(); - }: _(SystemOrigin::Signed(caller), class, witness) + let witness = Collection::::get(collection).unwrap().destroy_witness(); + }: _(SystemOrigin::Signed(caller), collection, witness) verify { - assert_last_event::(Event::Destroyed { class }.into()); + assert_last_event::(Event::Destroyed { collection }.into()); } mint { - let (class, caller, caller_lookup) = create_class::(); - let instance = T::Helper::instance(0); - }: _(SystemOrigin::Signed(caller.clone()), class, instance, caller_lookup) + let (collection, caller, caller_lookup) = create_collection::(); + let item = T::Helper::item(0); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, caller_lookup) verify { - assert_last_event::(Event::Issued { class, instance, owner: caller }.into()); + assert_last_event::(Event::Issued { collection, item, owner: caller }.into()); } burn { - let (class, caller, caller_lookup) = create_class::(); - let (instance, ..) = mint_instance::(0); - }: _(SystemOrigin::Signed(caller.clone()), class, instance, Some(caller_lookup)) + let (collection, caller, caller_lookup) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, Some(caller_lookup)) verify { - assert_last_event::(Event::Burned { class, instance, owner: caller }.into()); + assert_last_event::(Event::Burned { collection, item, owner: caller }.into()); } transfer { - let (class, caller, caller_lookup) = create_class::(); - let (instance, ..) = mint_instance::(0); + let (collection, caller, caller_lookup) = create_collection::(); + let (item, ..) = mint_item::(0); let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - }: _(SystemOrigin::Signed(caller.clone()), class, instance, target_lookup) + }: _(SystemOrigin::Signed(caller.clone()), collection, item, target_lookup) verify { - assert_last_event::(Event::Transferred { class, instance, from: caller, to: target }.into()); + assert_last_event::(Event::Transferred { collection, item, from: caller, to: target }.into()); } redeposit { let i in 0 .. 5_000; - let (class, caller, caller_lookup) = create_class::(); - let instances = (0..i).map(|x| mint_instance::(x as u16).0).collect::>(); - Uniques::::force_asset_status( + let (collection, caller, caller_lookup) = create_collection::(); + let items = (0..i).map(|x| mint_item::(x as u16).0).collect::>(); + Uniques::::force_item_status( SystemOrigin::Root.into(), - class, + collection, caller_lookup.clone(), caller_lookup.clone(), caller_lookup.clone(), @@ -220,80 +220,80 @@ benchmarks_instance_pallet! { true, false, )?; - }: _(SystemOrigin::Signed(caller.clone()), class, instances.clone()) + }: _(SystemOrigin::Signed(caller.clone()), collection, items.clone()) verify { - assert_last_event::(Event::Redeposited { class, successful_instances: instances }.into()); + assert_last_event::(Event::Redeposited { collection, successful_items: items }.into()); } freeze { - let (class, caller, caller_lookup) = create_class::(); - let (instance, ..) = mint_instance::(0); - }: _(SystemOrigin::Signed(caller.clone()), T::Helper::class(0), T::Helper::instance(0)) + let (collection, caller, caller_lookup) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Signed(caller.clone()), T::Helper::collection(0), T::Helper::item(0)) verify { - assert_last_event::(Event::Frozen { class: T::Helper::class(0), instance: T::Helper::instance(0) }.into()); + assert_last_event::(Event::Frozen { collection: T::Helper::collection(0), item: T::Helper::item(0) }.into()); } thaw { - let (class, caller, caller_lookup) = create_class::(); - let (instance, ..) = mint_instance::(0); + let (collection, caller, caller_lookup) = create_collection::(); + let (item, ..) = mint_item::(0); Uniques::::freeze( SystemOrigin::Signed(caller.clone()).into(), - class, - instance, + collection, + item, )?; - }: _(SystemOrigin::Signed(caller.clone()), class, instance) + }: _(SystemOrigin::Signed(caller.clone()), collection, item) verify { - assert_last_event::(Event::Thawed { class, instance }.into()); + assert_last_event::(Event::Thawed { collection, item }.into()); } - freeze_class { - let (class, caller, caller_lookup) = create_class::(); - }: _(SystemOrigin::Signed(caller.clone()), class) + freeze_collection { + let (collection, caller, caller_lookup) = create_collection::(); + }: _(SystemOrigin::Signed(caller.clone()), collection) verify { - assert_last_event::(Event::ClassFrozen { class }.into()); + assert_last_event::(Event::CollectionFrozen { collection }.into()); } - thaw_class { - let (class, caller, caller_lookup) = create_class::(); + thaw_collection { + let (collection, caller, caller_lookup) = create_collection::(); let origin = SystemOrigin::Signed(caller.clone()).into(); - Uniques::::freeze_class(origin, class)?; - }: _(SystemOrigin::Signed(caller.clone()), class) + Uniques::::freeze_collection(origin, collection)?; + }: _(SystemOrigin::Signed(caller.clone()), collection) verify { - assert_last_event::(Event::ClassThawed { class }.into()); + assert_last_event::(Event::CollectionThawed { collection }.into()); } transfer_ownership { - let (class, caller, _) = create_class::(); + let (collection, caller, _) = create_collection::(); let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); let origin = SystemOrigin::Signed(target.clone()).into(); - Uniques::::set_accept_ownership(origin, Some(class))?; - }: _(SystemOrigin::Signed(caller), class, target_lookup) + Uniques::::set_accept_ownership(origin, Some(collection))?; + }: _(SystemOrigin::Signed(caller), collection, target_lookup) verify { - assert_last_event::(Event::OwnerChanged { class, new_owner: target }.into()); + assert_last_event::(Event::OwnerChanged { collection, new_owner: target }.into()); } set_team { - let (class, caller, _) = create_class::(); + let (collection, caller, _) = create_collection::(); let target0 = T::Lookup::unlookup(account("target", 0, SEED)); let target1 = T::Lookup::unlookup(account("target", 1, SEED)); let target2 = T::Lookup::unlookup(account("target", 2, SEED)); - }: _(SystemOrigin::Signed(caller), class, target0, target1, target2) + }: _(SystemOrigin::Signed(caller), collection, target0, target1, target2) verify { assert_last_event::(Event::TeamChanged{ - class, + collection, issuer: account("target", 0, SEED), admin: account("target", 1, SEED), freezer: account("target", 2, SEED), }.into()); } - force_asset_status { - let (class, caller, caller_lookup) = create_class::(); + force_item_status { + let (collection, caller, caller_lookup) = create_collection::(); let origin = T::ForceOrigin::successful_origin(); - let call = Call::::force_asset_status { - class, + let call = Call::::force_item_status { + collection, owner: caller_lookup.clone(), issuer: caller_lookup.clone(), admin: caller_lookup.clone(), @@ -303,98 +303,98 @@ benchmarks_instance_pallet! { }; }: { call.dispatch_bypass_filter(origin)? } verify { - assert_last_event::(Event::AssetStatusChanged { class }.into()); + assert_last_event::(Event::ItemStatusChanged { collection }.into()); } set_attribute { let key: BoundedVec<_, _> = vec![0u8; T::KeyLimit::get() as usize].try_into().unwrap(); let value: BoundedVec<_, _> = vec![0u8; T::ValueLimit::get() as usize].try_into().unwrap(); - let (class, caller, _) = create_class::(); - let (instance, ..) = mint_instance::(0); - add_instance_metadata::(instance); - }: _(SystemOrigin::Signed(caller), class, Some(instance), key.clone(), value.clone()) + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + add_item_metadata::(item); + }: _(SystemOrigin::Signed(caller), collection, Some(item), key.clone(), value.clone()) verify { - assert_last_event::(Event::AttributeSet { class, maybe_instance: Some(instance), key, value }.into()); + assert_last_event::(Event::AttributeSet { collection, maybe_item: Some(item), key, value }.into()); } clear_attribute { - let (class, caller, _) = create_class::(); - let (instance, ..) = mint_instance::(0); - add_instance_metadata::(instance); - let (key, ..) = add_instance_attribute::(instance); - }: _(SystemOrigin::Signed(caller), class, Some(instance), key.clone()) + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + add_item_metadata::(item); + let (key, ..) = add_item_attribute::(item); + }: _(SystemOrigin::Signed(caller), collection, Some(item), key.clone()) verify { - assert_last_event::(Event::AttributeCleared { class, maybe_instance: Some(instance), key }.into()); + assert_last_event::(Event::AttributeCleared { collection, maybe_item: Some(item), key }.into()); } set_metadata { let data: BoundedVec<_, _> = vec![0u8; T::StringLimit::get() as usize].try_into().unwrap(); - let (class, caller, _) = create_class::(); - let (instance, ..) = mint_instance::(0); - }: _(SystemOrigin::Signed(caller), class, instance, data.clone(), false) + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Signed(caller), collection, item, data.clone(), false) verify { - assert_last_event::(Event::MetadataSet { class, instance, data, is_frozen: false }.into()); + assert_last_event::(Event::MetadataSet { collection, item, data, is_frozen: false }.into()); } clear_metadata { - let (class, caller, _) = create_class::(); - let (instance, ..) = mint_instance::(0); - add_instance_metadata::(instance); - }: _(SystemOrigin::Signed(caller), class, instance) + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + add_item_metadata::(item); + }: _(SystemOrigin::Signed(caller), collection, item) verify { - assert_last_event::(Event::MetadataCleared { class, instance }.into()); + assert_last_event::(Event::MetadataCleared { collection, item }.into()); } - set_class_metadata { + set_collection_metadata { let data: BoundedVec<_, _> = vec![0u8; T::StringLimit::get() as usize].try_into().unwrap(); - let (class, caller, _) = create_class::(); - }: _(SystemOrigin::Signed(caller), class, data.clone(), false) + let (collection, caller, _) = create_collection::(); + }: _(SystemOrigin::Signed(caller), collection, data.clone(), false) verify { - assert_last_event::(Event::ClassMetadataSet { class, data, is_frozen: false }.into()); + assert_last_event::(Event::CollectionMetadataSet { collection, data, is_frozen: false }.into()); } - clear_class_metadata { - let (class, caller, _) = create_class::(); - add_class_metadata::(); - }: _(SystemOrigin::Signed(caller), class) + clear_collection_metadata { + let (collection, caller, _) = create_collection::(); + add_collection_metadata::(); + }: _(SystemOrigin::Signed(caller), collection) verify { - assert_last_event::(Event::ClassMetadataCleared { class }.into()); + assert_last_event::(Event::CollectionMetadataCleared { collection }.into()); } approve_transfer { - let (class, caller, _) = create_class::(); - let (instance, ..) = mint_instance::(0); + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - }: _(SystemOrigin::Signed(caller.clone()), class, instance, delegate_lookup) + }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup) verify { - assert_last_event::(Event::ApprovedTransfer { class, instance, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovedTransfer { collection, item, owner: caller, delegate }.into()); } cancel_approval { - let (class, caller, _) = create_class::(); - let (instance, ..) = mint_instance::(0); + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let origin = SystemOrigin::Signed(caller.clone()).into(); - Uniques::::approve_transfer(origin, class, instance, delegate_lookup.clone())?; - }: _(SystemOrigin::Signed(caller.clone()), class, instance, Some(delegate_lookup)) + Uniques::::approve_transfer(origin, collection, item, delegate_lookup.clone())?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item, Some(delegate_lookup)) verify { - assert_last_event::(Event::ApprovalCancelled { class, instance, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item, owner: caller, delegate }.into()); } set_accept_ownership { let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - let class = T::Helper::class(0); - }: _(SystemOrigin::Signed(caller.clone()), Some(class)) + let collection = T::Helper::collection(0); + }: _(SystemOrigin::Signed(caller.clone()), Some(collection)) verify { assert_last_event::(Event::OwnershipAcceptanceChanged { who: caller, - maybe_class: Some(class), + maybe_collection: Some(collection), }.into()); } diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index ea9eecd767dcf..20e1410a8a849 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -23,168 +23,174 @@ use sp_runtime::{DispatchError, DispatchResult}; impl, I: 'static> Pallet { pub fn do_transfer( - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, dest: T::AccountId, with_details: impl FnOnce( - &ClassDetailsFor, - &mut InstanceDetailsFor, + &CollectionDetailsFor, + &mut ItemDetailsFor, ) -> DispatchResult, ) -> DispatchResult { - let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; - ensure!(!class_details.is_frozen, Error::::Frozen); - ensure!(!T::Locker::is_locked(class, instance), Error::::Locked); + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + ensure!(!collection_details.is_frozen, Error::::Frozen); + ensure!(!T::Locker::is_locked(collection, item), Error::::Locked); let mut details = - Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; + Item::::get(&collection, &item).ok_or(Error::::UnknownCollection)?; ensure!(!details.is_frozen, Error::::Frozen); - with_details(&class_details, &mut details)?; + with_details(&collection_details, &mut details)?; - Account::::remove((&details.owner, &class, &instance)); - Account::::insert((&dest, &class, &instance), ()); + Account::::remove((&details.owner, &collection, &item)); + Account::::insert((&dest, &collection, &item), ()); let origin = details.owner; details.owner = dest; - Asset::::insert(&class, &instance, &details); + Item::::insert(&collection, &item, &details); Self::deposit_event(Event::Transferred { - class, - instance, + collection, + item, from: origin, to: details.owner, }); Ok(()) } - pub fn do_create_class( - class: T::ClassId, + pub fn do_create_collection( + collection: T::CollectionId, owner: T::AccountId, admin: T::AccountId, deposit: DepositBalanceOf, free_holding: bool, event: Event, ) -> DispatchResult { - ensure!(!Class::::contains_key(class), Error::::InUse); + ensure!(!Collection::::contains_key(collection), Error::::InUse); T::Currency::reserve(&owner, deposit)?; - Class::::insert( - class, - ClassDetails { + Collection::::insert( + collection, + CollectionDetails { owner: owner.clone(), issuer: admin.clone(), admin: admin.clone(), freezer: admin, total_deposit: deposit, free_holding, - instances: 0, - instance_metadatas: 0, + items: 0, + item_metadatas: 0, attributes: 0, is_frozen: false, }, ); - ClassAccount::::insert(&owner, &class, ()); + CollectionAccount::::insert(&owner, &collection, ()); Self::deposit_event(event); Ok(()) } - pub fn do_destroy_class( - class: T::ClassId, + pub fn do_destroy_collection( + collection: T::CollectionId, witness: DestroyWitness, maybe_check_owner: Option, ) -> Result { - Class::::try_mutate_exists(class, |maybe_details| { - let class_details = maybe_details.take().ok_or(Error::::UnknownClass)?; + Collection::::try_mutate_exists(collection, |maybe_details| { + let collection_details = + maybe_details.take().ok_or(Error::::UnknownCollection)?; if let Some(check_owner) = maybe_check_owner { - ensure!(class_details.owner == check_owner, Error::::NoPermission); + ensure!(collection_details.owner == check_owner, Error::::NoPermission); } - ensure!(class_details.instances == witness.instances, Error::::BadWitness); + ensure!(collection_details.items == witness.items, Error::::BadWitness); ensure!( - class_details.instance_metadatas == witness.instance_metadatas, + collection_details.item_metadatas == witness.item_metadatas, Error::::BadWitness ); - ensure!(class_details.attributes == witness.attributes, Error::::BadWitness); + ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); - for (instance, details) in Asset::::drain_prefix(&class) { - Account::::remove((&details.owner, &class, &instance)); + for (item, details) in Item::::drain_prefix(&collection) { + Account::::remove((&details.owner, &collection, &item)); } - InstanceMetadataOf::::remove_prefix(&class, None); - ClassMetadataOf::::remove(&class); - Attribute::::remove_prefix((&class,), None); - ClassAccount::::remove(&class_details.owner, &class); - T::Currency::unreserve(&class_details.owner, class_details.total_deposit); + ItemMetadataOf::::remove_prefix(&collection, None); + CollectionMetadataOf::::remove(&collection); + Attribute::::remove_prefix((&collection,), None); + CollectionAccount::::remove(&collection_details.owner, &collection); + T::Currency::unreserve(&collection_details.owner, collection_details.total_deposit); - Self::deposit_event(Event::Destroyed { class }); + Self::deposit_event(Event::Destroyed { collection }); Ok(DestroyWitness { - instances: class_details.instances, - instance_metadatas: class_details.instance_metadatas, - attributes: class_details.attributes, + items: collection_details.items, + item_metadatas: collection_details.item_metadatas, + attributes: collection_details.attributes, }) }) } pub fn do_mint( - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, owner: T::AccountId, - with_details: impl FnOnce(&ClassDetailsFor) -> DispatchResult, + with_details: impl FnOnce(&CollectionDetailsFor) -> DispatchResult, ) -> DispatchResult { - ensure!(!Asset::::contains_key(class, instance), Error::::AlreadyExists); - - Class::::try_mutate(&class, |maybe_class_details| -> DispatchResult { - let class_details = maybe_class_details.as_mut().ok_or(Error::::UnknownClass)?; - - with_details(class_details)?; - - let instances = - class_details.instances.checked_add(1).ok_or(ArithmeticError::Overflow)?; - class_details.instances = instances; - - let deposit = match class_details.free_holding { - true => Zero::zero(), - false => T::InstanceDeposit::get(), - }; - T::Currency::reserve(&class_details.owner, deposit)?; - class_details.total_deposit += deposit; - - let owner = owner.clone(); - Account::::insert((&owner, &class, &instance), ()); - let details = InstanceDetails { owner, approved: None, is_frozen: false, deposit }; - Asset::::insert(&class, &instance, details); - Ok(()) - })?; + ensure!(!Item::::contains_key(collection, item), Error::::AlreadyExists); + + Collection::::try_mutate( + &collection, + |maybe_collection_details| -> DispatchResult { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + + with_details(collection_details)?; + + let items = + collection_details.items.checked_add(1).ok_or(ArithmeticError::Overflow)?; + collection_details.items = items; + + let deposit = match collection_details.free_holding { + true => Zero::zero(), + false => T::ItemDeposit::get(), + }; + T::Currency::reserve(&collection_details.owner, deposit)?; + collection_details.total_deposit += deposit; + + let owner = owner.clone(); + Account::::insert((&owner, &collection, &item), ()); + let details = ItemDetails { owner, approved: None, is_frozen: false, deposit }; + Item::::insert(&collection, &item, details); + Ok(()) + }, + )?; - Self::deposit_event(Event::Issued { class, instance, owner }); + Self::deposit_event(Event::Issued { collection, item, owner }); Ok(()) } pub fn do_burn( - class: T::ClassId, - instance: T::InstanceId, - with_details: impl FnOnce(&ClassDetailsFor, &InstanceDetailsFor) -> DispatchResult, + collection: T::CollectionId, + item: T::ItemId, + with_details: impl FnOnce(&CollectionDetailsFor, &ItemDetailsFor) -> DispatchResult, ) -> DispatchResult { - let owner = Class::::try_mutate( - &class, - |maybe_class_details| -> Result { - let class_details = - maybe_class_details.as_mut().ok_or(Error::::UnknownClass)?; - let details = - Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; - with_details(class_details, &details)?; + let owner = Collection::::try_mutate( + &collection, + |maybe_collection_details| -> Result { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + let details = Item::::get(&collection, &item) + .ok_or(Error::::UnknownCollection)?; + with_details(collection_details, &details)?; // Return the deposit. - T::Currency::unreserve(&class_details.owner, details.deposit); - class_details.total_deposit.saturating_reduce(details.deposit); - class_details.instances.saturating_dec(); + T::Currency::unreserve(&collection_details.owner, details.deposit); + collection_details.total_deposit.saturating_reduce(details.deposit); + collection_details.items.saturating_dec(); Ok(details.owner) }, )?; - Asset::::remove(&class, &instance); - Account::::remove((&owner, &class, &instance)); + Item::::remove(&collection, &item); + Account::::remove((&owner, &collection, &item)); - Self::deposit_event(Event::Burned { class, instance, owner }); + Self::deposit_event(Event::Burned { collection, item, owner }); Ok(()) } } diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index 492befc46967c..cead6f562ab58 100644 --- a/frame/uniques/src/impl_nonfungibles.rs +++ b/frame/uniques/src/impl_nonfungibles.rs @@ -26,59 +26,59 @@ use sp_runtime::{DispatchError, DispatchResult}; use sp_std::prelude::*; impl, I: 'static> Inspect<::AccountId> for Pallet { - type InstanceId = T::InstanceId; - type ClassId = T::ClassId; + type ItemId = T::ItemId; + type CollectionId = T::CollectionId; fn owner( - class: &Self::ClassId, - instance: &Self::InstanceId, + collection: &Self::CollectionId, + item: &Self::ItemId, ) -> Option<::AccountId> { - Asset::::get(class, instance).map(|a| a.owner) + Item::::get(collection, item).map(|a| a.owner) } - fn class_owner(class: &Self::ClassId) -> Option<::AccountId> { - Class::::get(class).map(|a| a.owner) + fn collection_owner(collection: &Self::CollectionId) -> Option<::AccountId> { + Collection::::get(collection).map(|a| a.owner) } - /// Returns the attribute value of `instance` of `class` corresponding to `key`. + /// Returns the attribute value of `item` of `collection` corresponding to `key`. /// - /// When `key` is empty, we return the instance metadata value. + /// When `key` is empty, we return the item metadata value. /// /// By default this is `None`; no attributes are defined. fn attribute( - class: &Self::ClassId, - instance: &Self::InstanceId, + collection: &Self::CollectionId, + item: &Self::ItemId, key: &[u8], ) -> Option> { if key.is_empty() { - // We make the empty key map to the instance metadata value. - InstanceMetadataOf::::get(class, instance).map(|m| m.data.into()) + // We make the empty key map to the item metadata value. + ItemMetadataOf::::get(collection, item).map(|m| m.data.into()) } else { let key = BoundedSlice::<_, _>::try_from(key).ok()?; - Attribute::::get((class, Some(instance), key)).map(|a| a.0.into()) + Attribute::::get((collection, Some(item), key)).map(|a| a.0.into()) } } - /// Returns the attribute value of `instance` of `class` corresponding to `key`. + /// Returns the attribute value of `item` of `collection` corresponding to `key`. /// - /// When `key` is empty, we return the instance metadata value. + /// When `key` is empty, we return the item metadata value. /// /// By default this is `None`; no attributes are defined. - fn class_attribute(class: &Self::ClassId, key: &[u8]) -> Option> { + fn collection_attribute(collection: &Self::CollectionId, key: &[u8]) -> Option> { if key.is_empty() { - // We make the empty key map to the instance metadata value. - ClassMetadataOf::::get(class).map(|m| m.data.into()) + // We make the empty key map to the item metadata value. + CollectionMetadataOf::::get(collection).map(|m| m.data.into()) } else { let key = BoundedSlice::<_, _>::try_from(key).ok()?; - Attribute::::get((class, Option::::None, key)).map(|a| a.0.into()) + Attribute::::get((collection, Option::::None, key)).map(|a| a.0.into()) } } - /// Returns `true` if the asset `instance` of `class` may be transferred. + /// Returns `true` if the `item` of `collection` may be transferred. /// - /// Default implementation is that all assets are transferable. - fn can_transfer(class: &Self::ClassId, instance: &Self::InstanceId) -> bool { - match (Class::::get(class), Asset::::get(class, instance)) { + /// Default implementation is that all items are transferable. + fn can_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> bool { + match (Collection::::get(collection), Item::::get(collection, item)) { (Some(cd), Some(id)) if !cd.is_frozen && !id.is_frozen => true, _ => false, } @@ -86,19 +86,19 @@ impl, I: 'static> Inspect<::AccountId> for Palle } impl, I: 'static> Create<::AccountId> for Pallet { - /// Create a `class` of nonfungible assets to be owned by `who` and managed by `admin`. - fn create_class( - class: &Self::ClassId, + /// Create a `collection` of nonfungible items to be owned by `who` and managed by `admin`. + fn create_collection( + collection: &Self::CollectionId, who: &T::AccountId, admin: &T::AccountId, ) -> DispatchResult { - Self::do_create_class( - *class, + Self::do_create_collection( + *collection, who.clone(), admin.clone(), - T::ClassDeposit::get(), + T::CollectionDeposit::get(), false, - Event::Created { class: *class, creator: who.clone(), owner: admin.clone() }, + Event::Created { collection: *collection, creator: who.clone(), owner: admin.clone() }, ) } } @@ -106,34 +106,34 @@ impl, I: 'static> Create<::AccountId> for Pallet impl, I: 'static> Destroy<::AccountId> for Pallet { type DestroyWitness = DestroyWitness; - fn get_destroy_witness(class: &Self::ClassId) -> Option { - Class::::get(class).map(|a| a.destroy_witness()) + fn get_destroy_witness(collection: &Self::CollectionId) -> Option { + Collection::::get(collection).map(|a| a.destroy_witness()) } fn destroy( - class: Self::ClassId, + collection: Self::CollectionId, witness: Self::DestroyWitness, maybe_check_owner: Option, ) -> Result { - Self::do_destroy_class(class, witness, maybe_check_owner) + Self::do_destroy_collection(collection, witness, maybe_check_owner) } } impl, I: 'static> Mutate<::AccountId> for Pallet { fn mint_into( - class: &Self::ClassId, - instance: &Self::InstanceId, + collection: &Self::CollectionId, + item: &Self::ItemId, who: &T::AccountId, ) -> DispatchResult { - Self::do_mint(*class, *instance, who.clone(), |_| Ok(())) + Self::do_mint(*collection, *item, who.clone(), |_| Ok(())) } fn burn( - class: &Self::ClassId, - instance: &Self::InstanceId, + collection: &Self::CollectionId, + item: &Self::ItemId, maybe_check_owner: Option<&T::AccountId>, ) -> DispatchResult { - Self::do_burn(*class, *instance, |_, d| { + Self::do_burn(*collection, *item, |_, d| { if let Some(check_owner) = maybe_check_owner { if &d.owner != check_owner { return Err(Error::::NoPermission.into()) @@ -146,43 +146,43 @@ impl, I: 'static> Mutate<::AccountId> for Pallet impl, I: 'static> Transfer for Pallet { fn transfer( - class: &Self::ClassId, - instance: &Self::InstanceId, + collection: &Self::CollectionId, + item: &Self::ItemId, destination: &T::AccountId, ) -> DispatchResult { - Self::do_transfer(*class, *instance, destination.clone(), |_, _| Ok(())) + Self::do_transfer(*collection, *item, destination.clone(), |_, _| Ok(())) } } impl, I: 'static> InspectEnumerable for Pallet { - /// Returns an iterator of the asset classes in existence. + /// Returns an iterator of the collections in existence. /// /// NOTE: iterating this list invokes a storage read per item. - fn classes() -> Box> { - Box::new(ClassMetadataOf::::iter_keys()) + fn collections() -> Box> { + Box::new(CollectionMetadataOf::::iter_keys()) } - /// Returns an iterator of the instances of an asset `class` in existence. + /// Returns an iterator of the items of a `collection` in existence. /// /// NOTE: iterating this list invokes a storage read per item. - fn instances(class: &Self::ClassId) -> Box> { - Box::new(InstanceMetadataOf::::iter_key_prefix(class)) + fn items(collection: &Self::CollectionId) -> Box> { + Box::new(ItemMetadataOf::::iter_key_prefix(collection)) } - /// Returns an iterator of the asset instances of all classes owned by `who`. + /// Returns an iterator of the items of all collections owned by `who`. /// /// NOTE: iterating this list invokes a storage read per item. - fn owned(who: &T::AccountId) -> Box> { + fn owned(who: &T::AccountId) -> Box> { Box::new(Account::::iter_key_prefix((who,))) } - /// Returns an iterator of the asset instances of `class` owned by `who`. + /// Returns an iterator of the items of `collection` owned by `who`. /// /// NOTE: iterating this list invokes a storage read per item. - fn owned_in_class( - class: &Self::ClassId, + fn owned_in_collection( + collection: &Self::CollectionId, who: &T::AccountId, - ) -> Box> { - Box::new(Account::::iter_key_prefix((who, class))) + ) -> Box> { + Box::new(Account::::iter_key_prefix((who, collection))) } } diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index a360a02ebc702..0a8cf201415a1 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Unique (Assets) Module +//! # Unique (Items) Module //! -//! A simple, secure module for dealing with non-fungible assets. +//! A simple, secure module for dealing with non-fungible items. //! //! ## Related Modules //! @@ -67,16 +67,16 @@ pub mod pallet { pub struct Pallet(_); #[cfg(feature = "runtime-benchmarks")] - pub trait BenchmarkHelper { - fn class(i: u16) -> ClassId; - fn instance(i: u16) -> InstanceId; + pub trait BenchmarkHelper { + fn collection(i: u16) -> CollectionId; + fn item(i: u16) -> ItemId; } #[cfg(feature = "runtime-benchmarks")] - impl, InstanceId: From> BenchmarkHelper for () { - fn class(i: u16) -> ClassId { + impl, ItemId: From> BenchmarkHelper for () { + fn collection(i: u16) -> CollectionId { i.into() } - fn instance(i: u16) -> InstanceId { + fn item(i: u16) -> ItemId { i.into() } } @@ -87,43 +87,43 @@ pub mod pallet { /// The overarching event type. type Event: From> + IsType<::Event>; - /// Identifier for the class of asset. - type ClassId: Member + Parameter + MaxEncodedLen + Copy; + /// Identifier for the collection of item. + type CollectionId: Member + Parameter + MaxEncodedLen + Copy; - /// The type used to identify a unique asset within an asset class. - type InstanceId: Member + Parameter + MaxEncodedLen + Copy; + /// The type used to identify a unique item within a collection. + type ItemId: Member + Parameter + MaxEncodedLen + Copy; /// The currency mechanism, used for paying for reserves. type Currency: ReservableCurrency; - /// The origin which may forcibly create or destroy an asset or otherwise alter privileged + /// The origin which may forcibly create or destroy an item or otherwise alter privileged /// attributes. type ForceOrigin: EnsureOrigin; - /// Standard class creation is only allowed if the origin attempting it and the class are - /// in this set. + /// Standard collection creation is only allowed if the origin attempting it and the + /// collection are in this set. type CreateOrigin: EnsureOriginWithArg< Success = Self::AccountId, Self::Origin, - Self::ClassId, + Self::CollectionId, >; /// Locker trait to enable Locking mechanism downstream. - type Locker: Locker; + type Locker: Locker; - /// The basic amount of funds that must be reserved for an asset class. + /// The basic amount of funds that must be reserved for collection. #[pallet::constant] - type ClassDeposit: Get>; + type CollectionDeposit: Get>; - /// The basic amount of funds that must be reserved for an asset instance. + /// The basic amount of funds that must be reserved for an item. #[pallet::constant] - type InstanceDeposit: Get>; + type ItemDeposit: Get>; - /// The basic amount of funds that must be reserved when adding metadata to your asset. + /// The basic amount of funds that must be reserved when adding metadata to your item. #[pallet::constant] type MetadataDepositBase: Get>; - /// The basic amount of funds that must be reserved when adding an attribute to an asset. + /// The basic amount of funds that must be reserved when adding an attribute to an item. #[pallet::constant] type AttributeDepositBase: Get>; @@ -146,94 +146,99 @@ pub mod pallet { #[cfg(feature = "runtime-benchmarks")] /// A set of helper functions for benchmarking. - type Helper: BenchmarkHelper; + type Helper: BenchmarkHelper; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } #[pallet::storage] - /// Details of an asset class. - pub(super) type Class, I: 'static = ()> = StorageMap< + #[pallet::storage_prefix = "Class"] + /// Details of a collection. + pub(super) type Collection, I: 'static = ()> = StorageMap< _, Blake2_128Concat, - T::ClassId, - ClassDetails>, + T::CollectionId, + CollectionDetails>, >; #[pallet::storage] - /// The class, if any, of which an account is willing to take ownership. + /// The collection, if any, of which an account is willing to take ownership. pub(super) type OwnershipAcceptance, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, T::AccountId, T::ClassId>; + StorageMap<_, Blake2_128Concat, T::AccountId, T::CollectionId>; #[pallet::storage] - /// The assets held by any given account; set out this way so that assets owned by a single + /// The items held by any given account; set out this way so that items owned by a single /// account can be enumerated. pub(super) type Account, I: 'static = ()> = StorageNMap< _, ( NMapKey, // owner - NMapKey, - NMapKey, + NMapKey, + NMapKey, ), (), OptionQuery, >; #[pallet::storage] - /// The classes owned by any given account; set out this way so that classes owned by a single - /// account can be enumerated. - pub(super) type ClassAccount, I: 'static = ()> = StorageDoubleMap< + #[pallet::storage_prefix = "ClassAccount"] + /// The collections owned by any given account; set out this way so that collections owned by + /// a single account can be enumerated. + pub(super) type CollectionAccount, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, Blake2_128Concat, - T::ClassId, + T::CollectionId, (), OptionQuery, >; #[pallet::storage] - /// The assets in existence and their ownership details. - pub(super) type Asset, I: 'static = ()> = StorageDoubleMap< + #[pallet::storage_prefix = "Asset"] + /// The items in existence and their ownership details. + pub(super) type Item, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, - T::ClassId, + T::CollectionId, Blake2_128Concat, - T::InstanceId, - InstanceDetails>, + T::ItemId, + ItemDetails>, OptionQuery, >; #[pallet::storage] - /// Metadata of an asset class. - pub(super) type ClassMetadataOf, I: 'static = ()> = StorageMap< + #[pallet::storage_prefix = "ClassMetadataOf"] + /// Metadata of a collection. + pub(super) type CollectionMetadataOf, I: 'static = ()> = StorageMap< _, Blake2_128Concat, - T::ClassId, - ClassMetadata, T::StringLimit>, + T::CollectionId, + CollectionMetadata, T::StringLimit>, OptionQuery, >; #[pallet::storage] - /// Metadata of an asset instance. - pub(super) type InstanceMetadataOf, I: 'static = ()> = StorageDoubleMap< + #[pallet::storage_prefix = "InstanceMetadataOf"] + /// Metadata of an item. + pub(super) type ItemMetadataOf, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, - T::ClassId, + T::CollectionId, Blake2_128Concat, - T::InstanceId, - InstanceMetadata, T::StringLimit>, + T::ItemId, + ItemMetadata, T::StringLimit>, OptionQuery, >; #[pallet::storage] - /// Metadata of an asset class. + /// Attributes of a collection. pub(super) type Attribute, I: 'static = ()> = StorageNMap< _, ( - NMapKey, - NMapKey>, + NMapKey, + NMapKey>, NMapKey>, ), (BoundedVec, DepositBalanceOf), @@ -243,109 +248,109 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { - /// An asset class was created. - Created { class: T::ClassId, creator: T::AccountId, owner: T::AccountId }, - /// An asset class was force-created. - ForceCreated { class: T::ClassId, owner: T::AccountId }, - /// An asset `class` was destroyed. - Destroyed { class: T::ClassId }, - /// An asset `instance` was issued. - Issued { class: T::ClassId, instance: T::InstanceId, owner: T::AccountId }, - /// An asset `instance` was transferred. + /// A `collection` was created. + Created { collection: T::CollectionId, creator: T::AccountId, owner: T::AccountId }, + /// A `collection` was force-created. + ForceCreated { collection: T::CollectionId, owner: T::AccountId }, + /// A `collection` was destroyed. + Destroyed { collection: T::CollectionId }, + /// An `item` was issued. + Issued { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId }, + /// An `item` was transferred. Transferred { - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, from: T::AccountId, to: T::AccountId, }, - /// An asset `instance` was destroyed. - Burned { class: T::ClassId, instance: T::InstanceId, owner: T::AccountId }, - /// Some asset `instance` was frozen. - Frozen { class: T::ClassId, instance: T::InstanceId }, - /// Some asset `instance` was thawed. - Thawed { class: T::ClassId, instance: T::InstanceId }, - /// Some asset `class` was frozen. - ClassFrozen { class: T::ClassId }, - /// Some asset `class` was thawed. - ClassThawed { class: T::ClassId }, + /// An `item` was destroyed. + Burned { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId }, + /// Some `item` was frozen. + Frozen { collection: T::CollectionId, item: T::ItemId }, + /// Some `item` was thawed. + Thawed { collection: T::CollectionId, item: T::ItemId }, + /// Some `collection` was frozen. + CollectionFrozen { collection: T::CollectionId }, + /// Some `collection` was thawed. + CollectionThawed { collection: T::CollectionId }, /// The owner changed. - OwnerChanged { class: T::ClassId, new_owner: T::AccountId }, + OwnerChanged { collection: T::CollectionId, new_owner: T::AccountId }, /// The management team changed. TeamChanged { - class: T::ClassId, + collection: T::CollectionId, issuer: T::AccountId, admin: T::AccountId, freezer: T::AccountId, }, - /// An `instance` of an asset `class` has been approved by the `owner` for transfer by a - /// `delegate`. + /// An `item` of a `collection` has been approved by the `owner` for transfer by + /// a `delegate`. ApprovedTransfer { - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, owner: T::AccountId, delegate: T::AccountId, }, - /// An approval for a `delegate` account to transfer the `instance` of an asset `class` was - /// cancelled by its `owner`. + /// An approval for a `delegate` account to transfer the `item` of an item + /// `collection` was cancelled by its `owner`. ApprovalCancelled { - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, owner: T::AccountId, delegate: T::AccountId, }, - /// An asset `class` has had its attributes changed by the `Force` origin. - AssetStatusChanged { class: T::ClassId }, - /// New metadata has been set for an asset class. - ClassMetadataSet { - class: T::ClassId, + /// A `collection` has had its attributes changed by the `Force` origin. + ItemStatusChanged { collection: T::CollectionId }, + /// New metadata has been set for a `collection`. + CollectionMetadataSet { + collection: T::CollectionId, data: BoundedVec, is_frozen: bool, }, - /// Metadata has been cleared for an asset class. - ClassMetadataCleared { class: T::ClassId }, - /// New metadata has been set for an asset instance. + /// Metadata has been cleared for a `collection`. + CollectionMetadataCleared { collection: T::CollectionId }, + /// New metadata has been set for an item. MetadataSet { - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, data: BoundedVec, is_frozen: bool, }, - /// Metadata has been cleared for an asset instance. - MetadataCleared { class: T::ClassId, instance: T::InstanceId }, - /// Metadata has been cleared for an asset instance. - Redeposited { class: T::ClassId, successful_instances: Vec }, - /// New attribute metadata has been set for an asset class or instance. + /// Metadata has been cleared for an item. + MetadataCleared { collection: T::CollectionId, item: T::ItemId }, + /// Metadata has been cleared for an item. + Redeposited { collection: T::CollectionId, successful_items: Vec }, + /// New attribute metadata has been set for a `collection` or `item`. AttributeSet { - class: T::ClassId, - maybe_instance: Option, + collection: T::CollectionId, + maybe_item: Option, key: BoundedVec, value: BoundedVec, }, - /// Attribute metadata has been cleared for an asset class or instance. + /// Attribute metadata has been cleared for a `collection` or `item`. AttributeCleared { - class: T::ClassId, - maybe_instance: Option, + collection: T::CollectionId, + maybe_item: Option, key: BoundedVec, }, /// Ownership acceptance has changed for an account. - OwnershipAcceptanceChanged { who: T::AccountId, maybe_class: Option }, + OwnershipAcceptanceChanged { who: T::AccountId, maybe_collection: Option }, } #[pallet::error] pub enum Error { /// The signing account has no permission to do the operation. NoPermission, - /// The given asset ID is unknown. - UnknownClass, - /// The asset instance ID has already been used for an asset. + /// The given item ID is unknown. + UnknownCollection, + /// The item ID has already been used for an item. AlreadyExists, /// The owner turned out to be different to what was expected. WrongOwner, /// Invalid witness data given. BadWitness, - /// The asset ID is already taken. + /// The item ID is already taken. InUse, - /// The asset instance or class is frozen. + /// The item or collection is frozen. Frozen, /// The delegate turned out to be different to what was expected. WrongDelegate, @@ -353,38 +358,38 @@ pub mod pallet { NoDelegate, /// No approval exists that would allow the transfer. Unapproved, - /// The named owner has not signed ownership of the class is acceptable. + /// The named owner has not signed ownership of the collection is acceptable. Unaccepted, - /// The asset instance is locked. + /// The item is locked. Locked, } impl, I: 'static> Pallet { - /// Get the owner of the asset instance, if the asset exists. - pub fn owner(class: T::ClassId, instance: T::InstanceId) -> Option { - Asset::::get(class, instance).map(|i| i.owner) + /// Get the owner of the item, if the item exists. + pub fn owner(collection: T::CollectionId, item: T::ItemId) -> Option { + Item::::get(collection, item).map(|i| i.owner) } - /// Get the owner of the asset instance, if the asset exists. - pub fn class_owner(class: T::ClassId) -> Option { - Class::::get(class).map(|i| i.owner) + /// Get the owner of the item, if the item exists. + pub fn collection_owner(collection: T::CollectionId) -> Option { + Collection::::get(collection).map(|i| i.owner) } } #[pallet::call] impl, I: 'static> Pallet { - /// Issue a new class of non-fungible assets from a public origin. + /// Issue a new collection of non-fungible items from a public origin. /// - /// This new asset class has no assets initially and its owner is the origin. + /// This new collection has no items initially and its owner is the origin. /// /// The origin must be Signed and the sender must have sufficient funds free. /// - /// `AssetDeposit` funds of sender are reserved. + /// `ItemDeposit` funds of sender are reserved. /// /// Parameters: - /// - `class`: The identifier of the new asset class. This must not be currently in use. - /// - `admin`: The admin of this class of assets. The admin is the initial address of each - /// member of the asset class's admin team. + /// - `collection`: The identifier of the new collection. This must not be currently in use. + /// - `admin`: The admin of this collection. The admin is the initial address of each + /// member of the collection's admin team. /// /// Emits `Created` event when successful. /// @@ -392,33 +397,34 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::create())] pub fn create( origin: OriginFor, - class: T::ClassId, + collection: T::CollectionId, admin: ::Source, ) -> DispatchResult { - let owner = T::CreateOrigin::ensure_origin(origin, &class)?; + let owner = T::CreateOrigin::ensure_origin(origin, &collection)?; let admin = T::Lookup::lookup(admin)?; - Self::do_create_class( - class, + Self::do_create_collection( + collection, owner.clone(), admin.clone(), - T::ClassDeposit::get(), + T::CollectionDeposit::get(), false, - Event::Created { class, creator: owner, owner: admin }, + Event::Created { collection, creator: owner, owner: admin }, ) } - /// Issue a new class of non-fungible assets from a privileged origin. + /// Issue a new collection of non-fungible items from a privileged origin. /// - /// This new asset class has no assets initially. + /// This new collection has no items initially. /// /// The origin must conform to `ForceOrigin`. /// /// Unlike `create`, no funds are reserved. /// - /// - `class`: The identifier of the new asset. This must not be currently in use. - /// - `owner`: The owner of this class of assets. The owner has full superuser permissions - /// over this asset, but may later change and configure the permissions using + /// - `collection`: The identifier of the new item. This must not be currently in use. + /// - `owner`: The owner of this collection of items. The owner has full superuser + /// permissions + /// over this item, but may later change and configure the permissions using /// `transfer_ownership` and `set_team`. /// /// Emits `ForceCreated` event when successful. @@ -427,69 +433,69 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_create())] pub fn force_create( origin: OriginFor, - class: T::ClassId, + collection: T::CollectionId, owner: ::Source, free_holding: bool, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; - Self::do_create_class( - class, + Self::do_create_collection( + collection, owner.clone(), owner.clone(), Zero::zero(), free_holding, - Event::ForceCreated { class, owner }, + Event::ForceCreated { collection, owner }, ) } - /// Destroy a class of fungible assets. + /// Destroy a collection of fungible items. /// /// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the - /// owner of the asset `class`. + /// owner of the `collection`. /// - /// - `class`: The identifier of the asset class to be destroyed. - /// - `witness`: Information on the instances minted in the asset class. This must be + /// - `collection`: The identifier of the collection to be destroyed. + /// - `witness`: Information on the items minted in the collection. This must be /// correct. /// /// Emits `Destroyed` event when successful. /// /// Weight: `O(n + m)` where: - /// - `n = witness.instances` - /// - `m = witness.instance_metadatas` + /// - `n = witness.items` + /// - `m = witness.item_metadatas` /// - `a = witness.attributes` #[pallet::weight(T::WeightInfo::destroy( - witness.instances, - witness.instance_metadatas, + witness.items, + witness.item_metadatas, witness.attributes, ))] pub fn destroy( origin: OriginFor, - class: T::ClassId, + collection: T::CollectionId, witness: DestroyWitness, ) -> DispatchResultWithPostInfo { let maybe_check_owner = match T::ForceOrigin::try_origin(origin) { Ok(_) => None, Err(origin) => Some(ensure_signed(origin)?), }; - let details = Self::do_destroy_class(class, witness, maybe_check_owner)?; + let details = Self::do_destroy_collection(collection, witness, maybe_check_owner)?; Ok(Some(T::WeightInfo::destroy( - details.instances, - details.instance_metadatas, + details.items, + details.item_metadatas, details.attributes, )) .into()) } - /// Mint an asset instance of a particular class. + /// Mint an item of a particular collection. /// - /// The origin must be Signed and the sender must be the Issuer of the asset `class`. + /// The origin must be Signed and the sender must be the Issuer of the `collection`. /// - /// - `class`: The class of the asset to be minted. - /// - `instance`: The instance value of the asset to be minted. - /// - `beneficiary`: The initial owner of the minted asset. + /// - `collection`: The collection of the item to be minted. + /// - `item`: The item value of the item to be minted. + /// - `beneficiary`: The initial owner of the minted item. /// /// Emits `Issued` event when successful. /// @@ -497,27 +503,27 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::mint())] pub fn mint( origin: OriginFor, - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, owner: ::Source, ) -> DispatchResult { let origin = ensure_signed(origin)?; let owner = T::Lookup::lookup(owner)?; - Self::do_mint(class, instance, owner, |class_details| { - ensure!(class_details.issuer == origin, Error::::NoPermission); + Self::do_mint(collection, item, owner, |collection_details| { + ensure!(collection_details.issuer == origin, Error::::NoPermission); Ok(()) }) } - /// Destroy a single asset instance. + /// Destroy a single item. /// - /// Origin must be Signed and the sender should be the Admin of the asset `class`. + /// Origin must be Signed and the sender should be the Admin of the `collection`. /// - /// - `class`: The class of the asset to be burned. - /// - `instance`: The instance of the asset to be burned. + /// - `collection`: The collection of the item to be burned. + /// - `item`: The item of the item to be burned. /// - `check_owner`: If `Some` then the operation will fail with `WrongOwner` unless the - /// asset is owned by this value. + /// item is owned by this value. /// /// Emits `Burned` with the actual amount burned. /// @@ -526,15 +532,15 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::burn())] pub fn burn( origin: OriginFor, - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, check_owner: Option<::Source>, ) -> DispatchResult { let origin = ensure_signed(origin)?; let check_owner = check_owner.map(T::Lookup::lookup).transpose()?; - Self::do_burn(class, instance, |class_details, details| { - let is_permitted = class_details.admin == origin || details.owner == origin; + Self::do_burn(collection, item, |collection_details, details| { + let is_permitted = collection_details.admin == origin || details.owner == origin; ensure!(is_permitted, Error::::NoPermission); ensure!( check_owner.map_or(true, |o| o == details.owner), @@ -544,17 +550,17 @@ pub mod pallet { }) } - /// Move an asset from the sender account to another. + /// Move an item from the sender account to another. /// /// Origin must be Signed and the signing account must be either: - /// - the Admin of the asset `class`; - /// - the Owner of the asset `instance`; - /// - the approved delegate for the asset `instance` (in this case, the approval is reset). + /// - the Admin of the `collection`; + /// - the Owner of the `item`; + /// - the approved delegate for the `item` (in this case, the approval is reset). /// /// Arguments: - /// - `class`: The class of the asset to be transferred. - /// - `instance`: The instance of the asset to be transferred. - /// - `dest`: The account to receive ownership of the asset. + /// - `collection`: The collection of the item to be transferred. + /// - `item`: The item of the item to be transferred. + /// - `dest`: The account to receive ownership of the item. /// /// Emits `Transferred`. /// @@ -562,15 +568,15 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( origin: OriginFor, - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, dest: ::Source, ) -> DispatchResult { let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; - Self::do_transfer(class, instance, dest, |class_details, details| { - if details.owner != origin && class_details.admin != origin { + Self::do_transfer(collection, item, dest, |collection_details, details| { + if details.owner != origin && collection_details.admin != origin { let approved = details.approved.take().map_or(false, |i| i == origin); ensure!(approved, Error::::NoPermission); } @@ -578,79 +584,79 @@ pub mod pallet { }) } - /// Reevaluate the deposits on some assets. + /// Reevaluate the deposits on some items. /// - /// Origin must be Signed and the sender should be the Owner of the asset `class`. + /// Origin must be Signed and the sender should be the Owner of the `collection`. /// - /// - `class`: The class of the asset to be frozen. - /// - `instances`: The instances of the asset class whose deposits will be reevaluated. + /// - `collection`: The collection to be frozen. + /// - `items`: The items of the collection whose deposits will be reevaluated. /// - /// NOTE: This exists as a best-effort function. Any asset instances which are unknown or + /// NOTE: This exists as a best-effort function. Any items which are unknown or /// in the case that the owner account does not have reservable funds to pay for a - /// deposit increase are ignored. Generally the owner isn't going to call this on instances + /// deposit increase are ignored. Generally the owner isn't going to call this on items /// whose existing deposit is less than the refreshed deposit as it would only cost them, /// so it's of little consequence. /// - /// It will still return an error in the case that the class is unknown of the signer is - /// not permitted to call it. + /// It will still return an error in the case that the collection is unknown of the signer + /// is not permitted to call it. /// - /// Weight: `O(instances.len())` - #[pallet::weight(T::WeightInfo::redeposit(instances.len() as u32))] + /// Weight: `O(items.len())` + #[pallet::weight(T::WeightInfo::redeposit(items.len() as u32))] pub fn redeposit( origin: OriginFor, - class: T::ClassId, - instances: Vec, + collection: T::CollectionId, + items: Vec, ) -> DispatchResult { let origin = ensure_signed(origin)?; - let mut class_details = - Class::::get(&class).ok_or(Error::::UnknownClass)?; - ensure!(class_details.owner == origin, Error::::NoPermission); - let deposit = match class_details.free_holding { + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + ensure!(collection_details.owner == origin, Error::::NoPermission); + let deposit = match collection_details.free_holding { true => Zero::zero(), - false => T::InstanceDeposit::get(), + false => T::ItemDeposit::get(), }; - let mut successful = Vec::with_capacity(instances.len()); - for instance in instances.into_iter() { - let mut details = match Asset::::get(&class, &instance) { + let mut successful = Vec::with_capacity(items.len()); + for item in items.into_iter() { + let mut details = match Item::::get(&collection, &item) { Some(x) => x, None => continue, }; let old = details.deposit; if old > deposit { - T::Currency::unreserve(&class_details.owner, old - deposit); + T::Currency::unreserve(&collection_details.owner, old - deposit); } else if deposit > old { - if T::Currency::reserve(&class_details.owner, deposit - old).is_err() { - // NOTE: No alterations made to class_details in this iteration so far, so - // this is OK to do. + if T::Currency::reserve(&collection_details.owner, deposit - old).is_err() { + // NOTE: No alterations made to collection_details in this iteration so far, + // so this is OK to do. continue } } else { continue } - class_details.total_deposit.saturating_accrue(deposit); - class_details.total_deposit.saturating_reduce(old); + collection_details.total_deposit.saturating_accrue(deposit); + collection_details.total_deposit.saturating_reduce(old); details.deposit = deposit; - Asset::::insert(&class, &instance, &details); - successful.push(instance); + Item::::insert(&collection, &item, &details); + successful.push(item); } - Class::::insert(&class, &class_details); + Collection::::insert(&collection, &collection_details); Self::deposit_event(Event::::Redeposited { - class, - successful_instances: successful, + collection, + successful_items: successful, }); Ok(()) } - /// Disallow further unprivileged transfer of an asset instance. + /// Disallow further unprivileged transfer of an item. /// - /// Origin must be Signed and the sender should be the Freezer of the asset `class`. + /// Origin must be Signed and the sender should be the Freezer of the `collection`. /// - /// - `class`: The class of the asset to be frozen. - /// - `instance`: The instance of the asset to be frozen. + /// - `collection`: The collection of the item to be frozen. + /// - `item`: The item of the item to be frozen. /// /// Emits `Frozen`. /// @@ -658,29 +664,30 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::freeze())] pub fn freeze( origin: OriginFor, - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, ) -> DispatchResult { let origin = ensure_signed(origin)?; let mut details = - Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; - let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; - ensure!(class_details.freezer == origin, Error::::NoPermission); + Item::::get(&collection, &item).ok_or(Error::::UnknownCollection)?; + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + ensure!(collection_details.freezer == origin, Error::::NoPermission); details.is_frozen = true; - Asset::::insert(&class, &instance, &details); + Item::::insert(&collection, &item, &details); - Self::deposit_event(Event::::Frozen { class, instance }); + Self::deposit_event(Event::::Frozen { collection, item }); Ok(()) } - /// Re-allow unprivileged transfer of an asset instance. + /// Re-allow unprivileged transfer of an item. /// - /// Origin must be Signed and the sender should be the Freezer of the asset `class`. + /// Origin must be Signed and the sender should be the Freezer of the `collection`. /// - /// - `class`: The class of the asset to be thawed. - /// - `instance`: The instance of the asset to be thawed. + /// - `collection`: The collection of the item to be thawed. + /// - `item`: The item of the item to be thawed. /// /// Emits `Thawed`. /// @@ -688,78 +695,85 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::thaw())] pub fn thaw( origin: OriginFor, - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, ) -> DispatchResult { let origin = ensure_signed(origin)?; let mut details = - Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; - let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; - ensure!(class_details.admin == origin, Error::::NoPermission); + Item::::get(&collection, &item).ok_or(Error::::UnknownCollection)?; + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + ensure!(collection_details.admin == origin, Error::::NoPermission); details.is_frozen = false; - Asset::::insert(&class, &instance, &details); + Item::::insert(&collection, &item, &details); - Self::deposit_event(Event::::Thawed { class, instance }); + Self::deposit_event(Event::::Thawed { collection, item }); Ok(()) } - /// Disallow further unprivileged transfers for a whole asset class. + /// Disallow further unprivileged transfers for a whole collection. /// - /// Origin must be Signed and the sender should be the Freezer of the asset `class`. + /// Origin must be Signed and the sender should be the Freezer of the `collection`. /// - /// - `class`: The asset class to be frozen. + /// - `collection`: The collection to be frozen. /// - /// Emits `ClassFrozen`. + /// Emits `CollectionFrozen`. /// /// Weight: `O(1)` - #[pallet::weight(T::WeightInfo::freeze_class())] - pub fn freeze_class(origin: OriginFor, class: T::ClassId) -> DispatchResult { + #[pallet::weight(T::WeightInfo::freeze_collection())] + pub fn freeze_collection( + origin: OriginFor, + collection: T::CollectionId, + ) -> DispatchResult { let origin = ensure_signed(origin)?; - Class::::try_mutate(class, |maybe_details| { - let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; + Collection::::try_mutate(collection, |maybe_details| { + let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; ensure!(origin == details.freezer, Error::::NoPermission); details.is_frozen = true; - Self::deposit_event(Event::::ClassFrozen { class }); + Self::deposit_event(Event::::CollectionFrozen { collection }); Ok(()) }) } - /// Re-allow unprivileged transfers for a whole asset class. + /// Re-allow unprivileged transfers for a whole collection. /// - /// Origin must be Signed and the sender should be the Admin of the asset `class`. + /// Origin must be Signed and the sender should be the Admin of the `collection`. /// - /// - `class`: The class to be thawed. + /// - `collection`: The collection to be thawed. /// - /// Emits `ClassThawed`. + /// Emits `CollectionThawed`. /// /// Weight: `O(1)` - #[pallet::weight(T::WeightInfo::thaw_class())] - pub fn thaw_class(origin: OriginFor, class: T::ClassId) -> DispatchResult { + #[pallet::weight(T::WeightInfo::thaw_collection())] + pub fn thaw_collection( + origin: OriginFor, + collection: T::CollectionId, + ) -> DispatchResult { let origin = ensure_signed(origin)?; - Class::::try_mutate(class, |maybe_details| { - let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; + Collection::::try_mutate(collection, |maybe_details| { + let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; ensure!(origin == details.admin, Error::::NoPermission); details.is_frozen = false; - Self::deposit_event(Event::::ClassThawed { class }); + Self::deposit_event(Event::::CollectionThawed { collection }); Ok(()) }) } - /// Change the Owner of an asset class. + /// Change the Owner of a collection. /// - /// Origin must be Signed and the sender should be the Owner of the asset `class`. + /// Origin must be Signed and the sender should be the Owner of the `collection`. /// - /// - `class`: The asset class whose owner should be changed. - /// - `owner`: The new Owner of this asset class. They must have called - /// `set_accept_ownership` with `class` in order for this operation to succeed. + /// - `collection`: The collection whose owner should be changed. + /// - `owner`: The new Owner of this collection. They must have called + /// `set_accept_ownership` with `collection` in order for this operation to succeed. /// /// Emits `OwnerChanged`. /// @@ -767,17 +781,17 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer_ownership())] pub fn transfer_ownership( origin: OriginFor, - class: T::ClassId, + collection: T::CollectionId, owner: ::Source, ) -> DispatchResult { let origin = ensure_signed(origin)?; let owner = T::Lookup::lookup(owner)?; - let acceptable_class = OwnershipAcceptance::::get(&owner); - ensure!(acceptable_class.as_ref() == Some(&class), Error::::Unaccepted); + let acceptable_collection = OwnershipAcceptance::::get(&owner); + ensure!(acceptable_collection.as_ref() == Some(&collection), Error::::Unaccepted); - Class::::try_mutate(class, |maybe_details| { - let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; + Collection::::try_mutate(collection, |maybe_details| { + let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; ensure!(origin == details.owner, Error::::NoPermission); if details.owner == owner { return Ok(()) @@ -790,24 +804,24 @@ pub mod pallet { details.total_deposit, Reserved, )?; - ClassAccount::::remove(&details.owner, &class); - ClassAccount::::insert(&owner, &class, ()); + CollectionAccount::::remove(&details.owner, &collection); + CollectionAccount::::insert(&owner, &collection, ()); details.owner = owner.clone(); OwnershipAcceptance::::remove(&owner); - Self::deposit_event(Event::OwnerChanged { class, new_owner: owner }); + Self::deposit_event(Event::OwnerChanged { collection, new_owner: owner }); Ok(()) }) } - /// Change the Issuer, Admin and Freezer of an asset class. + /// Change the Issuer, Admin and Freezer of a collection. /// - /// Origin must be Signed and the sender should be the Owner of the asset `class`. + /// Origin must be Signed and the sender should be the Owner of the `collection`. /// - /// - `class`: The asset class whose team should be changed. - /// - `issuer`: The new Issuer of this asset class. - /// - `admin`: The new Admin of this asset class. - /// - `freezer`: The new Freezer of this asset class. + /// - `collection`: The collection whose team should be changed. + /// - `issuer`: The new Issuer of this collection. + /// - `admin`: The new Admin of this collection. + /// - `freezer`: The new Freezer of this collection. /// /// Emits `TeamChanged`. /// @@ -815,7 +829,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_team())] pub fn set_team( origin: OriginFor, - class: T::ClassId, + collection: T::CollectionId, issuer: ::Source, admin: ::Source, freezer: ::Source, @@ -825,26 +839,26 @@ pub mod pallet { let admin = T::Lookup::lookup(admin)?; let freezer = T::Lookup::lookup(freezer)?; - Class::::try_mutate(class, |maybe_details| { - let details = maybe_details.as_mut().ok_or(Error::::UnknownClass)?; + Collection::::try_mutate(collection, |maybe_details| { + let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; ensure!(origin == details.owner, Error::::NoPermission); details.issuer = issuer.clone(); details.admin = admin.clone(); details.freezer = freezer.clone(); - Self::deposit_event(Event::TeamChanged { class, issuer, admin, freezer }); + Self::deposit_event(Event::TeamChanged { collection, issuer, admin, freezer }); Ok(()) }) } - /// Approve an instance to be transferred by a delegated third-party account. + /// Approve an item to be transferred by a delegated third-party account. /// - /// Origin must be Signed and must be the owner of the asset `instance`. + /// Origin must be Signed and must be the owner of the `item`. /// - /// - `class`: The class of the asset to be approved for delegated transfer. - /// - `instance`: The instance of the asset to be approved for delegated transfer. - /// - `delegate`: The account to delegate permission to transfer the asset. + /// - `collection`: The collection of the item to be approved for delegated transfer. + /// - `item`: The item of the item to be approved for delegated transfer. + /// - `delegate`: The account to delegate permission to transfer the item. /// /// Emits `ApprovedTransfer` on success. /// @@ -852,8 +866,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::approve_transfer())] pub fn approve_transfer( origin: OriginFor, - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, delegate: ::Source, ) -> DispatchResult { let maybe_check: Option = T::ForceOrigin::try_origin(origin) @@ -862,22 +876,23 @@ pub mod pallet { let delegate = T::Lookup::lookup(delegate)?; - let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; let mut details = - Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; + Item::::get(&collection, &item).ok_or(Error::::UnknownCollection)?; if let Some(check) = maybe_check { - let permitted = check == class_details.admin || check == details.owner; + let permitted = check == collection_details.admin || check == details.owner; ensure!(permitted, Error::::NoPermission); } details.approved = Some(delegate); - Asset::::insert(&class, &instance, &details); + Item::::insert(&collection, &item, &details); let delegate = details.approved.expect("set as Some above; qed"); Self::deposit_event(Event::ApprovedTransfer { - class, - instance, + collection, + item, owner: details.owner, delegate, }); @@ -885,16 +900,16 @@ pub mod pallet { Ok(()) } - /// Cancel the prior approval for the transfer of an asset by a delegate. + /// Cancel the prior approval for the transfer of an item by a delegate. /// /// Origin must be either: /// - the `Force` origin; - /// - `Signed` with the signer being the Admin of the asset `class`; - /// - `Signed` with the signer being the Owner of the asset `instance`; + /// - `Signed` with the signer being the Admin of the `collection`; + /// - `Signed` with the signer being the Owner of the `item`; /// /// Arguments: - /// - `class`: The class of the asset of whose approval will be cancelled. - /// - `instance`: The instance of the asset of whose approval will be cancelled. + /// - `collection`: The collection of the item of whose approval will be cancelled. + /// - `item`: The item of the item of whose approval will be cancelled. /// - `maybe_check_delegate`: If `Some` will ensure that the given account is the one to /// which permission of transfer is delegated. /// @@ -904,19 +919,20 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::cancel_approval())] pub fn cancel_approval( origin: OriginFor, - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, maybe_check_delegate: Option<::Source>, ) -> DispatchResult { let maybe_check: Option = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - let class_details = Class::::get(&class).ok_or(Error::::UnknownClass)?; + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; let mut details = - Asset::::get(&class, &instance).ok_or(Error::::UnknownClass)?; + Item::::get(&collection, &item).ok_or(Error::::UnknownCollection)?; if let Some(check) = maybe_check { - let permitted = check == class_details.admin || check == details.owner; + let permitted = check == collection_details.admin || check == details.owner; ensure!(permitted, Error::::NoPermission); } let maybe_check_delegate = maybe_check_delegate.map(T::Lookup::lookup).transpose()?; @@ -925,10 +941,10 @@ pub mod pallet { ensure!(check_delegate == old, Error::::WrongDelegate); } - Asset::::insert(&class, &instance, &details); + Item::::insert(&collection, &item, &details); Self::deposit_event(Event::ApprovalCancelled { - class, - instance, + collection, + item, owner: details.owner, delegate: old, }); @@ -936,27 +952,26 @@ pub mod pallet { Ok(()) } - /// Alter the attributes of a given asset. + /// Alter the attributes of a given item. /// /// Origin must be `ForceOrigin`. /// - /// - `class`: The identifier of the asset. - /// - `owner`: The new Owner of this asset. - /// - `issuer`: The new Issuer of this asset. - /// - `admin`: The new Admin of this asset. - /// - `freezer`: The new Freezer of this asset. - /// - `free_holding`: Whether a deposit is taken for holding an instance of this asset - /// class. - /// - `is_frozen`: Whether this asset class is frozen except for permissioned/admin + /// - `collection`: The identifier of the item. + /// - `owner`: The new Owner of this item. + /// - `issuer`: The new Issuer of this item. + /// - `admin`: The new Admin of this item. + /// - `freezer`: The new Freezer of this item. + /// - `free_holding`: Whether a deposit is taken for holding an item of this collection. + /// - `is_frozen`: Whether this collection is frozen except for permissioned/admin /// instructions. /// - /// Emits `AssetStatusChanged` with the identity of the asset. + /// Emits `ItemStatusChanged` with the identity of the item. /// /// Weight: `O(1)` - #[pallet::weight(T::WeightInfo::force_asset_status())] - pub fn force_asset_status( + #[pallet::weight(T::WeightInfo::force_item_status())] + pub fn force_item_status( origin: OriginFor, - class: T::ClassId, + collection: T::CollectionId, owner: ::Source, issuer: ::Source, admin: ::Source, @@ -966,36 +981,36 @@ pub mod pallet { ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; - Class::::try_mutate(class, |maybe_asset| { - let mut asset = maybe_asset.take().ok_or(Error::::UnknownClass)?; - let old_owner = asset.owner; + Collection::::try_mutate(collection, |maybe_item| { + let mut item = maybe_item.take().ok_or(Error::::UnknownCollection)?; + let old_owner = item.owner; let new_owner = T::Lookup::lookup(owner)?; - asset.owner = new_owner.clone(); - asset.issuer = T::Lookup::lookup(issuer)?; - asset.admin = T::Lookup::lookup(admin)?; - asset.freezer = T::Lookup::lookup(freezer)?; - asset.free_holding = free_holding; - asset.is_frozen = is_frozen; - *maybe_asset = Some(asset); - ClassAccount::::remove(&old_owner, &class); - ClassAccount::::insert(&new_owner, &class, ()); - - Self::deposit_event(Event::AssetStatusChanged { class }); + item.owner = new_owner.clone(); + item.issuer = T::Lookup::lookup(issuer)?; + item.admin = T::Lookup::lookup(admin)?; + item.freezer = T::Lookup::lookup(freezer)?; + item.free_holding = free_holding; + item.is_frozen = is_frozen; + *maybe_item = Some(item); + CollectionAccount::::remove(&old_owner, &collection); + CollectionAccount::::insert(&new_owner, &collection, ()); + + Self::deposit_event(Event::ItemStatusChanged { collection }); Ok(()) }) } - /// Set an attribute for an asset class or instance. + /// Set an attribute for a collection or item. /// /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the - /// asset `class`. + /// `collection`. /// /// If the origin is Signed, then funds of signer are reserved according to the formula: /// `MetadataDepositBase + DepositPerByte * (key.len + value.len)` taking into /// account any already reserved funds. /// - /// - `class`: The identifier of the asset class whose instance's metadata to set. - /// - `maybe_instance`: The identifier of the asset instance whose metadata to set. + /// - `collection`: The identifier of the collection whose item's metadata to set. + /// - `maybe_item`: The identifier of the item whose metadata to set. /// - `key`: The key of the attribute. /// - `value`: The value to which to set the attribute. /// @@ -1005,8 +1020,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_attribute())] pub fn set_attribute( origin: OriginFor, - class: T::ClassId, - maybe_instance: Option, + collection: T::CollectionId, + maybe_item: Option, key: BoundedVec, value: BoundedVec, ) -> DispatchResult { @@ -1014,52 +1029,51 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let mut class_details = - Class::::get(&class).ok_or(Error::::UnknownClass)?; + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; if let Some(check_owner) = &maybe_check_owner { - ensure!(check_owner == &class_details.owner, Error::::NoPermission); + ensure!(check_owner == &collection_details.owner, Error::::NoPermission); } - let maybe_is_frozen = match maybe_instance { - None => ClassMetadataOf::::get(class).map(|v| v.is_frozen), - Some(instance) => - InstanceMetadataOf::::get(class, instance).map(|v| v.is_frozen), + let maybe_is_frozen = match maybe_item { + None => CollectionMetadataOf::::get(collection).map(|v| v.is_frozen), + Some(item) => ItemMetadataOf::::get(collection, item).map(|v| v.is_frozen), }; ensure!(!maybe_is_frozen.unwrap_or(false), Error::::Frozen); - let attribute = Attribute::::get((class, maybe_instance, &key)); + let attribute = Attribute::::get((collection, maybe_item, &key)); if attribute.is_none() { - class_details.attributes.saturating_inc(); + collection_details.attributes.saturating_inc(); } let old_deposit = attribute.map_or(Zero::zero(), |m| m.1); - class_details.total_deposit.saturating_reduce(old_deposit); + collection_details.total_deposit.saturating_reduce(old_deposit); let mut deposit = Zero::zero(); - if !class_details.free_holding && maybe_check_owner.is_some() { + if !collection_details.free_holding && maybe_check_owner.is_some() { deposit = T::DepositPerByte::get() .saturating_mul(((key.len() + value.len()) as u32).into()) .saturating_add(T::AttributeDepositBase::get()); } - class_details.total_deposit.saturating_accrue(deposit); + collection_details.total_deposit.saturating_accrue(deposit); if deposit > old_deposit { - T::Currency::reserve(&class_details.owner, deposit - old_deposit)?; + T::Currency::reserve(&collection_details.owner, deposit - old_deposit)?; } else if deposit < old_deposit { - T::Currency::unreserve(&class_details.owner, old_deposit - deposit); + T::Currency::unreserve(&collection_details.owner, old_deposit - deposit); } - Attribute::::insert((&class, maybe_instance, &key), (&value, deposit)); - Class::::insert(class, &class_details); - Self::deposit_event(Event::AttributeSet { class, maybe_instance, key, value }); + Attribute::::insert((&collection, maybe_item, &key), (&value, deposit)); + Collection::::insert(collection, &collection_details); + Self::deposit_event(Event::AttributeSet { collection, maybe_item, key, value }); Ok(()) } - /// Clear an attribute for an asset class or instance. + /// Clear an attribute for a collection or item. /// /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the - /// asset `class`. + /// `collection`. /// - /// Any deposit is freed for the asset class owner. + /// Any deposit is freed for the collection's owner. /// - /// - `class`: The identifier of the asset class whose instance's metadata to clear. - /// - `maybe_instance`: The identifier of the asset instance whose metadata to clear. + /// - `collection`: The identifier of the collection whose item's metadata to clear. + /// - `maybe_item`: The identifier of the item whose metadata to clear. /// - `key`: The key of the attribute. /// /// Emits `AttributeCleared`. @@ -1068,48 +1082,47 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::clear_attribute())] pub fn clear_attribute( origin: OriginFor, - class: T::ClassId, - maybe_instance: Option, + collection: T::CollectionId, + maybe_item: Option, key: BoundedVec, ) -> DispatchResult { let maybe_check_owner = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let mut class_details = - Class::::get(&class).ok_or(Error::::UnknownClass)?; + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; if let Some(check_owner) = &maybe_check_owner { - ensure!(check_owner == &class_details.owner, Error::::NoPermission); + ensure!(check_owner == &collection_details.owner, Error::::NoPermission); } - let maybe_is_frozen = match maybe_instance { - None => ClassMetadataOf::::get(class).map(|v| v.is_frozen), - Some(instance) => - InstanceMetadataOf::::get(class, instance).map(|v| v.is_frozen), + let maybe_is_frozen = match maybe_item { + None => CollectionMetadataOf::::get(collection).map(|v| v.is_frozen), + Some(item) => ItemMetadataOf::::get(collection, item).map(|v| v.is_frozen), }; ensure!(!maybe_is_frozen.unwrap_or(false), Error::::Frozen); - if let Some((_, deposit)) = Attribute::::take((class, maybe_instance, &key)) { - class_details.attributes.saturating_dec(); - class_details.total_deposit.saturating_reduce(deposit); - T::Currency::unreserve(&class_details.owner, deposit); - Class::::insert(class, &class_details); - Self::deposit_event(Event::AttributeCleared { class, maybe_instance, key }); + if let Some((_, deposit)) = Attribute::::take((collection, maybe_item, &key)) { + collection_details.attributes.saturating_dec(); + collection_details.total_deposit.saturating_reduce(deposit); + T::Currency::unreserve(&collection_details.owner, deposit); + Collection::::insert(collection, &collection_details); + Self::deposit_event(Event::AttributeCleared { collection, maybe_item, key }); } Ok(()) } - /// Set the metadata for an asset instance. + /// Set the metadata for an item. /// /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the - /// asset `class`. + /// `collection`. /// /// If the origin is Signed, then funds of signer are reserved according to the formula: /// `MetadataDepositBase + DepositPerByte * data.len` taking into /// account any already reserved funds. /// - /// - `class`: The identifier of the asset class whose instance's metadata to set. - /// - `instance`: The identifier of the asset instance whose metadata to set. - /// - `data`: The general information of this asset. Limited in length by `StringLimit`. + /// - `collection`: The identifier of the collection whose item's metadata to set. + /// - `item`: The identifier of the item whose metadata to set. + /// - `data`: The general information of this item. Limited in length by `StringLimit`. /// - `is_frozen`: Whether the metadata should be frozen against further changes. /// /// Emits `MetadataSet`. @@ -1118,8 +1131,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_metadata())] pub fn set_metadata( origin: OriginFor, - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, data: BoundedVec, is_frozen: bool, ) -> DispatchResult { @@ -1127,52 +1140,52 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let mut class_details = - Class::::get(&class).ok_or(Error::::UnknownClass)?; + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; if let Some(check_owner) = &maybe_check_owner { - ensure!(check_owner == &class_details.owner, Error::::NoPermission); + ensure!(check_owner == &collection_details.owner, Error::::NoPermission); } - InstanceMetadataOf::::try_mutate_exists(class, instance, |metadata| { + ItemMetadataOf::::try_mutate_exists(collection, item, |metadata| { let was_frozen = metadata.as_ref().map_or(false, |m| m.is_frozen); ensure!(maybe_check_owner.is_none() || !was_frozen, Error::::Frozen); if metadata.is_none() { - class_details.instance_metadatas.saturating_inc(); + collection_details.item_metadatas.saturating_inc(); } let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit); - class_details.total_deposit.saturating_reduce(old_deposit); + collection_details.total_deposit.saturating_reduce(old_deposit); let mut deposit = Zero::zero(); - if !class_details.free_holding && maybe_check_owner.is_some() { + if !collection_details.free_holding && maybe_check_owner.is_some() { deposit = T::DepositPerByte::get() .saturating_mul(((data.len()) as u32).into()) .saturating_add(T::MetadataDepositBase::get()); } if deposit > old_deposit { - T::Currency::reserve(&class_details.owner, deposit - old_deposit)?; + T::Currency::reserve(&collection_details.owner, deposit - old_deposit)?; } else if deposit < old_deposit { - T::Currency::unreserve(&class_details.owner, old_deposit - deposit); + T::Currency::unreserve(&collection_details.owner, old_deposit - deposit); } - class_details.total_deposit.saturating_accrue(deposit); + collection_details.total_deposit.saturating_accrue(deposit); - *metadata = Some(InstanceMetadata { deposit, data: data.clone(), is_frozen }); + *metadata = Some(ItemMetadata { deposit, data: data.clone(), is_frozen }); - Class::::insert(&class, &class_details); - Self::deposit_event(Event::MetadataSet { class, instance, data, is_frozen }); + Collection::::insert(&collection, &collection_details); + Self::deposit_event(Event::MetadataSet { collection, item, data, is_frozen }); Ok(()) }) } - /// Clear the metadata for an asset instance. + /// Clear the metadata for an item. /// /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the - /// asset `instance`. + /// `item`. /// - /// Any deposit is freed for the asset class owner. + /// Any deposit is freed for the collection's owner. /// - /// - `class`: The identifier of the asset class whose instance's metadata to clear. - /// - `instance`: The identifier of the asset instance whose metadata to clear. + /// - `collection`: The identifier of the collection whose item's metadata to clear. + /// - `item`: The identifier of the item whose metadata to clear. /// /// Emits `MetadataCleared`. /// @@ -1180,56 +1193,56 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::clear_metadata())] pub fn clear_metadata( origin: OriginFor, - class: T::ClassId, - instance: T::InstanceId, + collection: T::CollectionId, + item: T::ItemId, ) -> DispatchResult { let maybe_check_owner = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let mut class_details = - Class::::get(&class).ok_or(Error::::UnknownClass)?; + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; if let Some(check_owner) = &maybe_check_owner { - ensure!(check_owner == &class_details.owner, Error::::NoPermission); + ensure!(check_owner == &collection_details.owner, Error::::NoPermission); } - InstanceMetadataOf::::try_mutate_exists(class, instance, |metadata| { + ItemMetadataOf::::try_mutate_exists(collection, item, |metadata| { let was_frozen = metadata.as_ref().map_or(false, |m| m.is_frozen); ensure!(maybe_check_owner.is_none() || !was_frozen, Error::::Frozen); if metadata.is_some() { - class_details.instance_metadatas.saturating_dec(); + collection_details.item_metadatas.saturating_dec(); } - let deposit = metadata.take().ok_or(Error::::UnknownClass)?.deposit; - T::Currency::unreserve(&class_details.owner, deposit); - class_details.total_deposit.saturating_reduce(deposit); + let deposit = metadata.take().ok_or(Error::::UnknownCollection)?.deposit; + T::Currency::unreserve(&collection_details.owner, deposit); + collection_details.total_deposit.saturating_reduce(deposit); - Class::::insert(&class, &class_details); - Self::deposit_event(Event::MetadataCleared { class, instance }); + Collection::::insert(&collection, &collection_details); + Self::deposit_event(Event::MetadataCleared { collection, item }); Ok(()) }) } - /// Set the metadata for an asset class. + /// Set the metadata for a collection. /// /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of - /// the asset `class`. + /// the `collection`. /// /// If the origin is `Signed`, then funds of signer are reserved according to the formula: /// `MetadataDepositBase + DepositPerByte * data.len` taking into /// account any already reserved funds. /// - /// - `class`: The identifier of the asset whose metadata to update. - /// - `data`: The general information of this asset. Limited in length by `StringLimit`. + /// - `collection`: The identifier of the item whose metadata to update. + /// - `data`: The general information of this item. Limited in length by `StringLimit`. /// - `is_frozen`: Whether the metadata should be frozen against further changes. /// - /// Emits `ClassMetadataSet`. + /// Emits `CollectionMetadataSet`. /// /// Weight: `O(1)` - #[pallet::weight(T::WeightInfo::set_class_metadata())] - pub fn set_class_metadata( + #[pallet::weight(T::WeightInfo::set_collection_metadata())] + pub fn set_collection_metadata( origin: OriginFor, - class: T::ClassId, + collection: T::CollectionId, data: BoundedVec, is_frozen: bool, ) -> DispatchResult { @@ -1237,12 +1250,13 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let mut details = Class::::get(&class).ok_or(Error::::UnknownClass)?; + let mut details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; if let Some(check_owner) = &maybe_check_owner { ensure!(check_owner == &details.owner, Error::::NoPermission); } - ClassMetadataOf::::try_mutate_exists(class, |metadata| { + CollectionMetadataOf::::try_mutate_exists(collection, |metadata| { let was_frozen = metadata.as_ref().map_or(false, |m| m.is_frozen); ensure!(maybe_check_owner.is_none() || !was_frozen, Error::::Frozen); @@ -1261,67 +1275,71 @@ pub mod pallet { } details.total_deposit.saturating_accrue(deposit); - Class::::insert(&class, details); + Collection::::insert(&collection, details); - *metadata = Some(ClassMetadata { deposit, data: data.clone(), is_frozen }); + *metadata = Some(CollectionMetadata { deposit, data: data.clone(), is_frozen }); - Self::deposit_event(Event::ClassMetadataSet { class, data, is_frozen }); + Self::deposit_event(Event::CollectionMetadataSet { collection, data, is_frozen }); Ok(()) }) } - /// Clear the metadata for an asset class. + /// Clear the metadata for a collection. /// /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of - /// the asset `class`. + /// the `collection`. /// - /// Any deposit is freed for the asset class owner. + /// Any deposit is freed for the collection's owner. /// - /// - `class`: The identifier of the asset class whose metadata to clear. + /// - `collection`: The identifier of the collection whose metadata to clear. /// - /// Emits `ClassMetadataCleared`. + /// Emits `CollectionMetadataCleared`. /// /// Weight: `O(1)` - #[pallet::weight(T::WeightInfo::clear_class_metadata())] - pub fn clear_class_metadata(origin: OriginFor, class: T::ClassId) -> DispatchResult { + #[pallet::weight(T::WeightInfo::clear_collection_metadata())] + pub fn clear_collection_metadata( + origin: OriginFor, + collection: T::CollectionId, + ) -> DispatchResult { let maybe_check_owner = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some))?; - let details = Class::::get(&class).ok_or(Error::::UnknownClass)?; + let details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; if let Some(check_owner) = &maybe_check_owner { ensure!(check_owner == &details.owner, Error::::NoPermission); } - ClassMetadataOf::::try_mutate_exists(class, |metadata| { + CollectionMetadataOf::::try_mutate_exists(collection, |metadata| { let was_frozen = metadata.as_ref().map_or(false, |m| m.is_frozen); ensure!(maybe_check_owner.is_none() || !was_frozen, Error::::Frozen); - let deposit = metadata.take().ok_or(Error::::UnknownClass)?.deposit; + let deposit = metadata.take().ok_or(Error::::UnknownCollection)?.deposit; T::Currency::unreserve(&details.owner, deposit); - Self::deposit_event(Event::ClassMetadataCleared { class }); + Self::deposit_event(Event::CollectionMetadataCleared { collection }); Ok(()) }) } /// Set (or reset) the acceptance of ownership for a particular account. /// - /// Origin must be `Signed` and if `maybe_class` is `Some`, then the signer must have a + /// Origin must be `Signed` and if `maybe_collection` is `Some`, then the signer must have a /// provider reference. /// - /// - `maybe_class`: The identifier of the asset class whose ownership the signer is willing - /// to accept, or if `None`, an indication that the signer is willing to accept no + /// - `maybe_collection`: The identifier of the collection whose ownership the signer is + /// willing to accept, or if `None`, an indication that the signer is willing to accept no /// ownership transferal. /// /// Emits `OwnershipAcceptanceChanged`. #[pallet::weight(T::WeightInfo::set_accept_ownership())] pub fn set_accept_ownership( origin: OriginFor, - maybe_class: Option, + maybe_collection: Option, ) -> DispatchResult { let who = ensure_signed(origin)?; let old = OwnershipAcceptance::::get(&who); - match (old.is_some(), maybe_class.is_some()) { + match (old.is_some(), maybe_collection.is_some()) { (false, true) => { frame_system::Pallet::::inc_consumers(&who)?; }, @@ -1330,12 +1348,12 @@ pub mod pallet { }, _ => {}, } - if let Some(class) = maybe_class.as_ref() { - OwnershipAcceptance::::insert(&who, class); + if let Some(collection) = maybe_collection.as_ref() { + OwnershipAcceptance::::insert(&who, collection); } else { OwnershipAcceptance::::remove(&who); } - Self::deposit_event(Event::OwnershipAcceptanceChanged { who, maybe_class }); + Self::deposit_event(Event::OwnershipAcceptanceChanged { who, maybe_collection }); Ok(()) } } diff --git a/frame/uniques/src/migration.rs b/frame/uniques/src/migration.rs index 2bacfc8f43b61..d301f0a3d1eb1 100644 --- a/frame/uniques/src/migration.rs +++ b/frame/uniques/src/migration.rs @@ -34,8 +34,8 @@ pub fn migrate_to_v1, I: 'static, P: GetStorageVersion + PalletInfo if on_chain_storage_version < 1 { let mut count = 0; - for (class, detail) in Class::::iter() { - ClassAccount::::insert(&detail.owner, &class, ()); + for (collection, detail) in Collection::::iter() { + CollectionAccount::::insert(&detail.owner, &collection, ()); count += 1; } StorageVersion::new(1).put::

(); diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index f32540f6ef7ba..ff7b791de4950 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Test environment for Assets pallet. +//! Test environment for Uniques pallet. use super::*; use crate as pallet_uniques; @@ -86,14 +86,14 @@ impl pallet_balances::Config for Test { impl Config for Test { type Event = Event; - type ClassId = u32; - type InstanceId = u32; + type CollectionId = u32; + type ItemId = u32; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; type Locker = (); - type ClassDeposit = ConstU64<2>; - type InstanceDeposit = ConstU64<1>; + type CollectionDeposit = ConstU64<2>; + type ItemDeposit = ConstU64<1>; type MetadataDepositBase = ConstU64<1>; type AttributeDepositBase = ConstU64<1>; type DepositPerByte = ConstU64<1>; diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 364073ad37cde..6bd397eefa7ef 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -23,13 +23,13 @@ use frame_support::{assert_noop, assert_ok, traits::Currency}; use pallet_balances::Error as BalancesError; use sp_std::prelude::*; -fn assets() -> Vec<(u64, u32, u32)> { +fn items() -> Vec<(u64, u32, u32)> { let mut r: Vec<_> = Account::::iter().map(|x| x.0).collect(); r.sort(); - let mut s: Vec<_> = Asset::::iter().map(|x| (x.2.owner, x.0, x.1)).collect(); + let mut s: Vec<_> = Item::::iter().map(|x| (x.2.owner, x.0, x.1)).collect(); s.sort(); assert_eq!(r, s); - for class in Asset::::iter() + for collection in Item::::iter() .map(|x| x.0) .scan(None, |s, item| { if s.map_or(false, |last| last == item) { @@ -41,17 +41,17 @@ fn assets() -> Vec<(u64, u32, u32)> { }) .flatten() { - let details = Class::::get(class).unwrap(); - let instances = Asset::::iter_prefix(class).count() as u32; - assert_eq!(details.instances, instances); + let details = Collection::::get(collection).unwrap(); + let items = Item::::iter_prefix(collection).count() as u32; + assert_eq!(details.items, items); } r } -fn classes() -> Vec<(u64, u32)> { - let mut r: Vec<_> = ClassAccount::::iter().map(|x| (x.0, x.1)).collect(); +fn collections() -> Vec<(u64, u32)> { + let mut r: Vec<_> = CollectionAccount::::iter().map(|x| (x.0, x.1)).collect(); r.sort(); - let mut s: Vec<_> = Class::::iter().map(|x| (x.1.owner, x.0)).collect(); + let mut s: Vec<_> = Collection::::iter().map(|x| (x.1.owner, x.0)).collect(); s.sort(); assert_eq!(r, s); r @@ -63,8 +63,8 @@ macro_rules! bvec { } } -fn attributes(class: u32) -> Vec<(Option, Vec, Vec)> { - let mut s: Vec<_> = Attribute::::iter_prefix((class,)) +fn attributes(collection: u32) -> Vec<(Option, Vec, Vec)> { + let mut s: Vec<_> = Attribute::::iter_prefix((collection,)) .map(|(k, v)| (k.0, k.1.into(), v.0.into())) .collect(); s.sort(); @@ -74,7 +74,7 @@ fn attributes(class: u32) -> Vec<(Option, Vec, Vec)> { #[test] fn basic_setup_works() { new_test_ext().execute_with(|| { - assert_eq!(assets(), vec![]); + assert_eq!(items(), vec![]); }); } @@ -82,14 +82,14 @@ fn basic_setup_works() { fn basic_minting_should_work() { new_test_ext().execute_with(|| { assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_eq!(classes(), vec![(1, 0)]); + assert_eq!(collections(), vec![(1, 0)]); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); - assert_eq!(assets(), vec![(1, 0, 42)]); + assert_eq!(items(), vec![(1, 0, 42)]); assert_ok!(Uniques::force_create(Origin::root(), 1, 2, true)); - assert_eq!(classes(), vec![(1, 0), (2, 1)]); + assert_eq!(collections(), vec![(1, 0), (2, 1)]); assert_ok!(Uniques::mint(Origin::signed(2), 1, 69, 1)); - assert_eq!(assets(), vec![(1, 0, 42), (1, 1, 69)]); + assert_eq!(items(), vec![(1, 0, 42), (1, 1, 69)]); }); } @@ -99,40 +99,40 @@ fn lifecycle_should_work() { Balances::make_free_balance_be(&1, 100); assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); assert_eq!(Balances::reserved_balance(&1), 2); - assert_eq!(classes(), vec![(1, 0)]); - assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0, 0], false)); + assert_eq!(collections(), vec![(1, 0)]); + assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0, 0], false)); assert_eq!(Balances::reserved_balance(&1), 5); - assert!(ClassMetadataOf::::contains_key(0)); + assert!(CollectionMetadataOf::::contains_key(0)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 10)); assert_eq!(Balances::reserved_balance(&1), 6); assert_ok!(Uniques::mint(Origin::signed(1), 0, 69, 20)); assert_eq!(Balances::reserved_balance(&1), 7); - assert_eq!(assets(), vec![(10, 0, 42), (20, 0, 69)]); - assert_eq!(Class::::get(0).unwrap().instances, 2); - assert_eq!(Class::::get(0).unwrap().instance_metadatas, 0); + assert_eq!(items(), vec![(10, 0, 42), (20, 0, 69)]); + assert_eq!(Collection::::get(0).unwrap().items, 2); + assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![42, 42], false)); assert_eq!(Balances::reserved_balance(&1), 10); - assert!(InstanceMetadataOf::::contains_key(0, 42)); + assert!(ItemMetadataOf::::contains_key(0, 42)); assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![69, 69], false)); assert_eq!(Balances::reserved_balance(&1), 13); - assert!(InstanceMetadataOf::::contains_key(0, 69)); + assert!(ItemMetadataOf::::contains_key(0, 69)); - let w = Class::::get(0).unwrap().destroy_witness(); - assert_eq!(w.instances, 2); - assert_eq!(w.instance_metadatas, 2); + let w = Collection::::get(0).unwrap().destroy_witness(); + assert_eq!(w.items, 2); + assert_eq!(w.item_metadatas, 2); assert_ok!(Uniques::destroy(Origin::signed(1), 0, w)); assert_eq!(Balances::reserved_balance(&1), 0); - assert!(!Class::::contains_key(0)); - assert!(!Asset::::contains_key(0, 42)); - assert!(!Asset::::contains_key(0, 69)); - assert!(!ClassMetadataOf::::contains_key(0)); - assert!(!InstanceMetadataOf::::contains_key(0, 42)); - assert!(!InstanceMetadataOf::::contains_key(0, 69)); - assert_eq!(classes(), vec![]); - assert_eq!(assets(), vec![]); + assert!(!Collection::::contains_key(0)); + assert!(!Item::::contains_key(0, 42)); + assert!(!Item::::contains_key(0, 69)); + assert!(!CollectionMetadataOf::::contains_key(0)); + assert!(!ItemMetadataOf::::contains_key(0, 42)); + assert!(!ItemMetadataOf::::contains_key(0, 69)); + assert_eq!(collections(), vec![]); + assert_eq!(items(), vec![]); }); } @@ -142,7 +142,7 @@ fn destroy_with_bad_witness_should_not_work() { Balances::make_free_balance_be(&1, 100); assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); - let w = Class::::get(0).unwrap().destroy_witness(); + let w = Collection::::get(0).unwrap().destroy_witness(); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_noop!(Uniques::destroy(Origin::signed(1), 0, w), Error::::BadWitness); }); @@ -154,8 +154,8 @@ fn mint_should_work() { assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_eq!(Uniques::owner(0, 42).unwrap(), 1); - assert_eq!(classes(), vec![(1, 0)]); - assert_eq!(assets(), vec![(1, 0, 42)]); + assert_eq!(collections(), vec![(1, 0)]); + assert_eq!(items(), vec![(1, 0, 42)]); }); } @@ -166,7 +166,7 @@ fn transfer_should_work() { assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 3)); - assert_eq!(assets(), vec![(3, 0, 42)]); + assert_eq!(items(), vec![(3, 0, 42)]); assert_noop!(Uniques::transfer(Origin::signed(2), 0, 42, 4), Error::::NoPermission); assert_ok!(Uniques::approve_transfer(Origin::signed(3), 0, 42, 2)); @@ -183,10 +183,10 @@ fn freezing_should_work() { assert_noop!(Uniques::transfer(Origin::signed(1), 0, 42, 2), Error::::Frozen); assert_ok!(Uniques::thaw(Origin::signed(1), 0, 42)); - assert_ok!(Uniques::freeze_class(Origin::signed(1), 0)); + assert_ok!(Uniques::freeze_collection(Origin::signed(1), 0)); assert_noop!(Uniques::transfer(Origin::signed(1), 0, 42, 2), Error::::Frozen); - assert_ok!(Uniques::thaw_class(Origin::signed(1), 0)); + assert_ok!(Uniques::thaw_collection(Origin::signed(1), 0)); assert_ok!(Uniques::transfer(Origin::signed(1), 0, 42, 2)); }); } @@ -208,7 +208,7 @@ fn origin_guards_should_work() { assert_noop!(Uniques::thaw(Origin::signed(2), 0, 42), Error::::NoPermission); assert_noop!(Uniques::mint(Origin::signed(2), 0, 69, 2), Error::::NoPermission); assert_noop!(Uniques::burn(Origin::signed(2), 0, 42, None), Error::::NoPermission); - let w = Class::::get(0).unwrap().destroy_witness(); + let w = Collection::::get(0).unwrap().destroy_witness(); assert_noop!(Uniques::destroy(Origin::signed(2), 0, w), Error::::NoPermission); }); } @@ -220,7 +220,7 @@ fn transfer_owner_should_work() { Balances::make_free_balance_be(&2, 100); Balances::make_free_balance_be(&3, 100); assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); - assert_eq!(classes(), vec![(1, 0)]); + assert_eq!(collections(), vec![(1, 0)]); assert_noop!( Uniques::transfer_ownership(Origin::signed(1), 0, 2), Error::::Unaccepted @@ -228,7 +228,7 @@ fn transfer_owner_should_work() { assert_ok!(Uniques::set_accept_ownership(Origin::signed(2), Some(0))); assert_ok!(Uniques::transfer_ownership(Origin::signed(1), 0, 2)); - assert_eq!(classes(), vec![(2, 0)]); + assert_eq!(collections(), vec![(2, 0)]); assert_eq!(Balances::total_balance(&1), 98); assert_eq!(Balances::total_balance(&2), 102); assert_eq!(Balances::reserved_balance(&1), 0); @@ -241,12 +241,12 @@ fn transfer_owner_should_work() { ); // Mint and set metadata now and make sure that deposit gets transferred back. - assert_ok!(Uniques::set_class_metadata(Origin::signed(2), 0, bvec![0u8; 20], false)); + assert_ok!(Uniques::set_collection_metadata(Origin::signed(2), 0, bvec![0u8; 20], false)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_ok!(Uniques::set_metadata(Origin::signed(2), 0, 42, bvec![0u8; 20], false)); assert_ok!(Uniques::set_accept_ownership(Origin::signed(3), Some(0))); assert_ok!(Uniques::transfer_ownership(Origin::signed(2), 0, 3)); - assert_eq!(classes(), vec![(3, 0)]); + assert_eq!(collections(), vec![(3, 0)]); assert_eq!(Balances::total_balance(&2), 57); assert_eq!(Balances::total_balance(&3), 145); assert_eq!(Balances::reserved_balance(&2), 0); @@ -276,73 +276,76 @@ fn set_team_should_work() { } #[test] -fn set_class_metadata_should_work() { +fn set_collection_metadata_should_work() { new_test_ext().execute_with(|| { - // Cannot add metadata to unknown asset + // Cannot add metadata to unknown item assert_noop!( - Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 20], false), - Error::::UnknownClass, + Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 20], false), + Error::::UnknownCollection, ); assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); - // Cannot add metadata to unowned asset + // Cannot add metadata to unowned item assert_noop!( - Uniques::set_class_metadata(Origin::signed(2), 0, bvec![0u8; 20], false), + Uniques::set_collection_metadata(Origin::signed(2), 0, bvec![0u8; 20], false), Error::::NoPermission, ); // Successfully add metadata and take deposit Balances::make_free_balance_be(&1, 30); - assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 20], false)); + assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 20], false)); assert_eq!(Balances::free_balance(&1), 9); - assert!(ClassMetadataOf::::contains_key(0)); + assert!(CollectionMetadataOf::::contains_key(0)); // Force origin works, too. - assert_ok!(Uniques::set_class_metadata(Origin::root(), 0, bvec![0u8; 18], false)); + assert_ok!(Uniques::set_collection_metadata(Origin::root(), 0, bvec![0u8; 18], false)); // Update deposit - assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 15], false)); + assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 15], false)); assert_eq!(Balances::free_balance(&1), 14); - assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 25], false)); + assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 25], false)); assert_eq!(Balances::free_balance(&1), 4); // Cannot over-reserve assert_noop!( - Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 40], false), + Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 40], false), BalancesError::::InsufficientBalance, ); // Can't set or clear metadata once frozen - assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 15], true)); + assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 15], true)); assert_noop!( - Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 15], false), + Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 15], false), Error::::Frozen, ); - assert_noop!(Uniques::clear_class_metadata(Origin::signed(1), 0), Error::::Frozen); + assert_noop!( + Uniques::clear_collection_metadata(Origin::signed(1), 0), + Error::::Frozen + ); // Clear Metadata - assert_ok!(Uniques::set_class_metadata(Origin::root(), 0, bvec![0u8; 15], false)); + assert_ok!(Uniques::set_collection_metadata(Origin::root(), 0, bvec![0u8; 15], false)); assert_noop!( - Uniques::clear_class_metadata(Origin::signed(2), 0), + Uniques::clear_collection_metadata(Origin::signed(2), 0), Error::::NoPermission ); assert_noop!( - Uniques::clear_class_metadata(Origin::signed(1), 1), - Error::::UnknownClass + Uniques::clear_collection_metadata(Origin::signed(1), 1), + Error::::UnknownCollection ); - assert_ok!(Uniques::clear_class_metadata(Origin::signed(1), 0)); - assert!(!ClassMetadataOf::::contains_key(0)); + assert_ok!(Uniques::clear_collection_metadata(Origin::signed(1), 0)); + assert!(!CollectionMetadataOf::::contains_key(0)); }); } #[test] -fn set_instance_metadata_should_work() { +fn set_item_metadata_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 30); - // Cannot add metadata to unknown asset + // Cannot add metadata to unknown item assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); - // Cannot add metadata to unowned asset + // Cannot add metadata to unowned item assert_noop!( Uniques::set_metadata(Origin::signed(2), 0, 42, bvec![0u8; 20], false), Error::::NoPermission, @@ -351,7 +354,7 @@ fn set_instance_metadata_should_work() { // Successfully add metadata and take deposit assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 20], false)); assert_eq!(Balances::free_balance(&1), 8); - assert!(InstanceMetadataOf::::contains_key(0, 42)); + assert!(ItemMetadataOf::::contains_key(0, 42)); // Force origin works, too. assert_ok!(Uniques::set_metadata(Origin::root(), 0, 42, bvec![0u8; 18], false)); @@ -384,10 +387,10 @@ fn set_instance_metadata_should_work() { ); assert_noop!( Uniques::clear_metadata(Origin::signed(1), 1, 42), - Error::::UnknownClass + Error::::UnknownCollection ); assert_ok!(Uniques::clear_metadata(Origin::signed(1), 0, 42)); - assert!(!InstanceMetadataOf::::contains_key(0, 42)); + assert!(!ItemMetadataOf::::contains_key(0, 42)); }); } @@ -429,7 +432,7 @@ fn set_attribute_should_work() { ); assert_eq!(Balances::reserved_balance(1), 15); - let w = Class::::get(0).unwrap().destroy_witness(); + let w = Collection::::get(0).unwrap().destroy_witness(); assert_ok!(Uniques::destroy(Origin::signed(1), 0, w)); assert_eq!(attributes(0), vec![]); assert_eq!(Balances::reserved_balance(1), 0); @@ -456,7 +459,7 @@ fn set_attribute_should_respect_freeze() { ); assert_eq!(Balances::reserved_balance(1), 9); - assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![], true)); + assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![], true)); let e = Error::::Frozen; assert_noop!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0]), e); assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![1])); @@ -469,20 +472,20 @@ fn set_attribute_should_respect_freeze() { } #[test] -fn force_asset_status_should_work() { +fn force_item_status_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 69, 2)); - assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0; 20], false)); + assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0; 20], false)); assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0; 20], false)); assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 65); - // force asset status to be free holding - assert_ok!(Uniques::force_asset_status(Origin::root(), 0, 1, 1, 1, 1, true, false)); + // force item status to be free holding + assert_ok!(Uniques::force_item_status(Origin::root(), 0, 1, 1, 1, 1, true, false)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 142, 1)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 169, 2)); assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 142, bvec![0; 20], false)); @@ -498,7 +501,7 @@ fn force_asset_status_should_work() { assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 21); - assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0; 20], false)); + assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 0); }); } @@ -510,7 +513,10 @@ fn burn_works() { assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4)); - assert_noop!(Uniques::burn(Origin::signed(5), 0, 42, Some(5)), Error::::UnknownClass); + assert_noop!( + Uniques::burn(Origin::signed(5), 0, 42, Some(5)), + Error::::UnknownCollection + ); assert_ok!(Uniques::mint(Origin::signed(2), 0, 42, 5)); assert_ok!(Uniques::mint(Origin::signed(2), 0, 69, 5)); @@ -533,7 +539,7 @@ fn approval_lifecycle_works() { assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); assert_ok!(Uniques::transfer(Origin::signed(3), 0, 42, 4)); assert_noop!(Uniques::transfer(Origin::signed(3), 0, 42, 3), Error::::NoPermission); - assert!(Asset::::get(0, 42).unwrap().approved.is_none()); + assert!(Item::::get(0, 42).unwrap().approved.is_none()); assert_ok!(Uniques::approve_transfer(Origin::signed(4), 0, 42, 2)); assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 2)); @@ -549,11 +555,11 @@ fn cancel_approval_works() { assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); assert_noop!( Uniques::cancel_approval(Origin::signed(2), 1, 42, None), - Error::::UnknownClass + Error::::UnknownCollection ); assert_noop!( Uniques::cancel_approval(Origin::signed(2), 0, 43, None), - Error::::UnknownClass + Error::::UnknownCollection ); assert_noop!( Uniques::cancel_approval(Origin::signed(3), 0, 42, None), @@ -581,11 +587,11 @@ fn cancel_approval_works_with_admin() { assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); assert_noop!( Uniques::cancel_approval(Origin::signed(1), 1, 42, None), - Error::::UnknownClass + Error::::UnknownCollection ); assert_noop!( Uniques::cancel_approval(Origin::signed(1), 0, 43, None), - Error::::UnknownClass + Error::::UnknownCollection ); assert_noop!( Uniques::cancel_approval(Origin::signed(1), 0, 42, Some(4)), @@ -609,11 +615,11 @@ fn cancel_approval_works_with_force() { assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); assert_noop!( Uniques::cancel_approval(Origin::root(), 1, 42, None), - Error::::UnknownClass + Error::::UnknownCollection ); assert_noop!( Uniques::cancel_approval(Origin::root(), 0, 43, None), - Error::::UnknownClass + Error::::UnknownCollection ); assert_noop!( Uniques::cancel_approval(Origin::root(), 0, 42, Some(4)), diff --git a/frame/uniques/src/types.rs b/frame/uniques/src/types.rs index b5aee6912fec2..d7706fd7e3a58 100644 --- a/frame/uniques/src/types.rs +++ b/frame/uniques/src/types.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Various basic types for use in the assets pallet. +//! Various basic types for use in the Uniques pallet. use super::*; use frame_support::{ @@ -26,13 +26,13 @@ use scale_info::TypeInfo; pub(super) type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; -pub(super) type ClassDetailsFor = - ClassDetails<::AccountId, DepositBalanceOf>; -pub(super) type InstanceDetailsFor = - InstanceDetails<::AccountId, DepositBalanceOf>; +pub(super) type CollectionDetailsFor = + CollectionDetails<::AccountId, DepositBalanceOf>; +pub(super) type ItemDetailsFor = + ItemDetails<::AccountId, DepositBalanceOf>; #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct ClassDetails { +pub struct CollectionDetails { /// Can change `owner`, `issuer`, `freezer` and `admin` accounts. pub(super) owner: AccountId, /// Can mint tokens. @@ -41,55 +41,55 @@ pub struct ClassDetails { pub(super) admin: AccountId, /// Can freeze tokens. pub(super) freezer: AccountId, - /// The total balance deposited for the all storage associated with this asset class. Used by - /// `destroy`. + /// The total balance deposited for the all storage associated with this collection. + /// Used by `destroy`. pub(super) total_deposit: DepositBalance, - /// If `true`, then no deposit is needed to hold instances of this class. + /// If `true`, then no deposit is needed to hold items of this collection. pub(super) free_holding: bool, - /// The total number of outstanding instances of this asset class. - pub(super) instances: u32, - /// The total number of outstanding instance metadata of this asset class. - pub(super) instance_metadatas: u32, - /// The total number of attributes for this asset class. + /// The total number of outstanding items of this collection. + pub(super) items: u32, + /// The total number of outstanding item metadata of this collection. + pub(super) item_metadatas: u32, + /// The total number of attributes for this collection. pub(super) attributes: u32, - /// Whether the asset is frozen for non-admin transfers. + /// Whether the collection is frozen for non-admin transfers. pub(super) is_frozen: bool, } /// Witness data for the destroy transactions. #[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct DestroyWitness { - /// The total number of outstanding instances of this asset class. + /// The total number of outstanding items of this collection. #[codec(compact)] - pub instances: u32, - /// The total number of outstanding instance metadata of this asset class. + pub items: u32, + /// The total number of items in this collection that have outstanding item metadata. #[codec(compact)] - pub instance_metadatas: u32, + pub item_metadatas: u32, #[codec(compact)] - /// The total number of attributes for this asset class. + /// The total number of attributes for this collection. pub attributes: u32, } -impl ClassDetails { +impl CollectionDetails { pub fn destroy_witness(&self) -> DestroyWitness { DestroyWitness { - instances: self.instances, - instance_metadatas: self.instance_metadatas, + items: self.items, + item_metadatas: self.item_metadatas, attributes: self.attributes, } } } -/// Information concerning the ownership of a single unique asset. +/// Information concerning the ownership of a single unique item. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] -pub struct InstanceDetails { - /// The owner of this asset. +pub struct ItemDetails { + /// The owner of this item. pub(super) owner: AccountId, - /// The approved transferrer of this asset, if one is set. + /// The approved transferrer of this item, if one is set. pub(super) approved: Option, - /// Whether the asset can be transferred or not. + /// Whether the item can be transferred or not. pub(super) is_frozen: bool, - /// The amount held in the pallet's default account for this asset. Free-hold assets will have + /// The amount held in the pallet's default account for this item. Free-hold items will have /// this as zero. pub(super) deposit: DepositBalance, } @@ -97,31 +97,31 @@ pub struct InstanceDetails { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(StringLimit))] #[codec(mel_bound(DepositBalance: MaxEncodedLen))] -pub struct ClassMetadata> { +pub struct CollectionMetadata> { /// The balance deposited for this metadata. /// /// This pays for the data stored in this struct. pub(super) deposit: DepositBalance, - /// General information concerning this asset. Limited in length by `StringLimit`. This will - /// generally be either a JSON dump or the hash of some JSON which can be found on a + /// General information concerning this collection. Limited in length by `StringLimit`. This + /// will generally be either a JSON dump or the hash of some JSON which can be found on a /// hash-addressable global publication system such as IPFS. pub(super) data: BoundedVec, - /// Whether the asset metadata may be changed by a non Force origin. + /// Whether the collection's metadata may be changed by a non Force origin. pub(super) is_frozen: bool, } #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(StringLimit))] #[codec(mel_bound(DepositBalance: MaxEncodedLen))] -pub struct InstanceMetadata> { +pub struct ItemMetadata> { /// The balance deposited for this metadata. /// /// This pays for the data stored in this struct. pub(super) deposit: DepositBalance, - /// General information concerning this asset. Limited in length by `StringLimit`. This will + /// General information concerning this item. Limited in length by `StringLimit`. This will /// generally be either a JSON dump or the hash of some JSON which can be found on a /// hash-addressable global publication system such as IPFS. pub(super) data: BoundedVec, - /// Whether the asset metadata may be changed by a non Force origin. + /// Whether the item metadata may be changed by a non Force origin. pub(super) is_frozen: bool, } diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index eb9067b7133a0..9b0cbda423ace 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-12, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -33,9 +34,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/uniques/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,17 +54,17 @@ pub trait WeightInfo { fn redeposit(i: u32, ) -> Weight; fn freeze() -> Weight; fn thaw() -> Weight; - fn freeze_class() -> Weight; - fn thaw_class() -> Weight; + fn freeze_collection() -> Weight; + fn thaw_collection() -> Weight; fn transfer_ownership() -> Weight; fn set_team() -> Weight; - fn force_asset_status() -> Weight; + fn force_item_status() -> Weight; fn set_attribute() -> Weight; fn clear_attribute() -> Weight; fn set_metadata() -> Weight; fn clear_metadata() -> Weight; - fn set_class_metadata() -> Weight; - fn clear_class_metadata() -> Weight; + fn set_collection_metadata() -> Weight; + fn clear_collection_metadata() -> Weight; fn approve_transfer() -> Weight; fn cancel_approval() -> Weight; fn set_accept_ownership() -> Weight; @@ -77,14 +76,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (24_063_000 as Weight) + (24_319_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (13_017_000 as Weight) + (13_572_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -97,12 +96,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 14_000 - .saturating_add((9_248_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 14_000 - .saturating_add((854_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 14_000 - .saturating_add((758_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 15_000 + .saturating_add((9_433_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 15_000 + .saturating_add((980_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 15_000 + .saturating_add((852_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -114,7 +113,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (29_865_000 as Weight) + (29_884_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -122,7 +121,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (31_603_000 as Weight) + (31_384_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -130,7 +129,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (23_331_000 as Weight) + (23_254_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -138,8 +137,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 12_000 - .saturating_add((11_527_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 13_000 + .saturating_add((11_718_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -148,47 +147,47 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (18_617_000 as Weight) + (17_807_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (18_618_000 as Weight) + (17_904_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) - fn freeze_class() -> Weight { - (13_570_000 as Weight) + fn freeze_collection() -> Weight { + (13_828_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) - fn thaw_class() -> Weight { - (13_937_000 as Weight) + fn thaw_collection() -> Weight { + (13_636_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques OwnershipAcceptance (r:1 w:1) // Storage: Uniques Class (r:1 w:1) - // Storage: System Account (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (31_021_000 as Weight) + (20_897_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (14_739_000 as Weight) + (14_340_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) - fn force_asset_status() -> Weight { - (16_826_000 as Weight) + fn force_item_status() -> Weight { + (16_355_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -196,7 +195,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (37_010_000 as Weight) + (37_035_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -204,56 +203,55 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (34_432_000 as Weight) + (34_957_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (28_575_000 as Weight) + (28_337_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (28_730_000 as Weight) + (29_166_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) - fn set_class_metadata() -> Weight { - (28_225_000 as Weight) + fn set_collection_metadata() -> Weight { + (28_246_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) - fn clear_class_metadata() -> Weight { - (26_455_000 as Weight) + fn clear_collection_metadata() -> Weight { + (26_637_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (19_587_000 as Weight) + (18_938_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (19_417_000 as Weight) + (18_465_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (19_417_000 as Weight) + (16_675_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -264,14 +262,14 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (24_063_000 as Weight) + (24_319_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (13_017_000 as Weight) + (13_572_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -284,12 +282,12 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 14_000 - .saturating_add((9_248_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 14_000 - .saturating_add((854_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 14_000 - .saturating_add((758_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 15_000 + .saturating_add((9_433_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 15_000 + .saturating_add((980_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 15_000 + .saturating_add((852_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -301,7 +299,7 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (29_865_000 as Weight) + (29_884_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -309,7 +307,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (31_603_000 as Weight) + (31_384_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -317,7 +315,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (23_331_000 as Weight) + (23_254_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -325,8 +323,8 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 12_000 - .saturating_add((11_527_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 13_000 + .saturating_add((11_718_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -335,47 +333,47 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (18_617_000 as Weight) + (17_807_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (18_618_000 as Weight) + (17_904_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) - fn freeze_class() -> Weight { - (13_570_000 as Weight) + fn freeze_collection() -> Weight { + (13_828_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) - fn thaw_class() -> Weight { - (13_937_000 as Weight) + fn thaw_collection() -> Weight { + (13_636_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: Uniques OwnershipAcceptance (r:1 w:1) // Storage: Uniques Class (r:1 w:1) - // Storage: System Account (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (31_021_000 as Weight) + (20_897_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (14_739_000 as Weight) + (14_340_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) - fn force_asset_status() -> Weight { - (16_826_000 as Weight) + fn force_item_status() -> Weight { + (16_355_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -383,7 +381,7 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (37_010_000 as Weight) + (37_035_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -391,56 +389,55 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (34_432_000 as Weight) + (34_957_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (28_575_000 as Weight) + (28_337_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (28_730_000 as Weight) + (29_166_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) - fn set_class_metadata() -> Weight { - (28_225_000 as Weight) + fn set_collection_metadata() -> Weight { + (28_246_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) - fn clear_class_metadata() -> Weight { - (26_455_000 as Weight) + fn clear_collection_metadata() -> Weight { + (26_637_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (19_587_000 as Weight) + (18_938_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (19_417_000 as Weight) + (18_465_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (19_417_000 as Weight) + (16_675_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } From 25f791812ae870906844c66ed5f4b4473cababd0 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 17 May 2022 05:50:03 -0400 Subject: [PATCH 0804/1472] remove deprecated (#11432) --- client/consensus/babe/src/tests.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index db19deda06fd8..9875ff00673f5 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -18,9 +18,6 @@ //! BABE testsuite -// FIXME #2532: need to allow deprecated until refactor is done -// https://github.com/paritytech/substrate/issues/2532 -#![allow(deprecated)] use super::*; use authorship::claim_slot; use futures::executor::block_on; From 17e062bd31b2af1b1ab3217c9c93c8e59cf9f646 Mon Sep 17 00:00:00 2001 From: mikolaichuk <45576473+mikolaichuk@users.noreply.github.com> Date: Tue, 17 May 2022 16:03:03 +0600 Subject: [PATCH 0805/1472] Small typo (#11392) Small typo --- primitives/runtime/src/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 9f706878bba49..393de086f3c58 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -821,7 +821,7 @@ impl Dispatchable for () { type Info = (); type PostInfo = (); fn dispatch(self, _origin: Self::Origin) -> crate::DispatchResultWithInfo { - panic!("This implemention should not be used for actual dispatch."); + panic!("This implementation should not be used for actual dispatch."); } } From c44cd637c45799b451813dc7b4558a2781e8b775 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 17 May 2022 15:57:08 +0200 Subject: [PATCH 0806/1472] More `benchmark machine` args (#11428) * Add ExecutionLimits to sc-sysinfo and return float Signed-off-by: Oliver Tale-Yazdi * Increase benchmarking duration and add options Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi --- bin/node/cli/tests/benchmark_machine_works.rs | 24 ++++++++- client/sysinfo/src/sysinfo.rs | 51 ++++++++++--------- .../frame/benchmarking-cli/src/machine/mod.rs | 16 ++++-- 3 files changed, 62 insertions(+), 29 deletions(-) diff --git a/bin/node/cli/tests/benchmark_machine_works.rs b/bin/node/cli/tests/benchmark_machine_works.rs index bf4a2b7b85e65..193e6b701ec94 100644 --- a/bin/node/cli/tests/benchmark_machine_works.rs +++ b/bin/node/cli/tests/benchmark_machine_works.rs @@ -24,7 +24,16 @@ use std::process::Command; fn benchmark_machine_works() { let status = Command::new(cargo_bin("substrate")) .args(["benchmark", "machine", "--dev"]) - .args(["--verify-duration", "0.1", "--disk-duration", "0.1"]) + .args([ + "--verify-duration", + "0.1", + "--disk-duration", + "0.1", + "--memory-duration", + "0.1", + "--hash-duration", + "0.1", + ]) // Make it succeed. .args(["--allow-fail"]) .status() @@ -41,7 +50,18 @@ fn benchmark_machine_works() { fn benchmark_machine_fails_with_slow_hardware() { let output = Command::new(cargo_bin("substrate")) .args(["benchmark", "machine", "--dev"]) - .args(["--verify-duration", "0.1", "--disk-duration", "2", "--tolerance", "0"]) + .args([ + "--verify-duration", + "1.0", + "--disk-duration", + "2", + "--hash-duration", + "1.0", + "--memory-duration", + "1.0", + "--tolerance", + "0", + ]) .output() .unwrap(); diff --git a/client/sysinfo/src/sysinfo.rs b/client/sysinfo/src/sysinfo.rs index cd6adcf623e66..fc347c1cc2eb3 100644 --- a/client/sysinfo/src/sysinfo.rs +++ b/client/sysinfo/src/sysinfo.rs @@ -60,9 +60,9 @@ pub(crate) fn benchmark( let score = ((size * count) as f64 / elapsed.as_secs_f64()) / (1024.0 * 1024.0); log::trace!( - "Calculated {} of {}MB/s in {} iterations in {}ms", + "Calculated {} of {:.2}MB/s in {} iterations in {}ms", name, - score as u64, + score, count, elapsed.as_millis() ); @@ -116,8 +116,12 @@ fn clobber_value(input: &mut T) { } } +/// A default [`ExecutionLimit`] that can be used to call [`benchmark_cpu`]. +pub const DEFAULT_CPU_EXECUTION_LIMIT: ExecutionLimit = + ExecutionLimit::Both { max_iterations: 4 * 1024, max_duration: Duration::from_millis(100) }; + // This benchmarks the CPU speed as measured by calculating BLAKE2b-256 hashes, in MB/s. -pub fn benchmark_cpu() -> u64 { +pub fn benchmark_cpu(limit: ExecutionLimit) -> f64 { // In general the results of this benchmark are somewhat sensitive to how much // data we hash at the time. The smaller this is the *less* MB/s we can hash, // the bigger this is the *more* MB/s we can hash, up until a certain point @@ -131,8 +135,6 @@ pub fn benchmark_cpu() -> u64 { // picked in such a way as to still measure how fast the hasher is at hashing, // but without hitting its theoretical maximum speed. const SIZE: usize = 32 * 1024; - const MAX_ITERATIONS: usize = 4 * 1024; - const MAX_DURATION: Duration = Duration::from_millis(100); let mut buffer = Vec::new(); buffer.resize(SIZE, 0x66); @@ -146,16 +148,20 @@ pub fn benchmark_cpu() -> u64 { Ok(()) }; - benchmark("CPU score", SIZE, MAX_ITERATIONS, MAX_DURATION, run) - .expect("benchmark cannot fail; qed") as u64 + benchmark("CPU score", SIZE, limit.max_iterations(), limit.max_duration(), run) + .expect("benchmark cannot fail; qed") } +/// A default [`ExecutionLimit`] that can be used to call [`benchmark_memory`]. +pub const DEFAULT_MEMORY_EXECUTION_LIMIT: ExecutionLimit = + ExecutionLimit::Both { max_iterations: 32, max_duration: Duration::from_millis(100) }; + // This benchmarks the effective `memcpy` memory bandwidth available in MB/s. // // It doesn't technically measure the absolute maximum memory bandwidth available, // but that's fine, because real code most of the time isn't optimized to take // advantage of the full memory bandwidth either. -pub fn benchmark_memory() -> u64 { +pub fn benchmark_memory(limit: ExecutionLimit) -> f64 { // Ideally this should be at least as big as the CPU's L3 cache, // and it should be big enough so that the `memcpy` takes enough // time to be actually measurable. @@ -163,8 +169,6 @@ pub fn benchmark_memory() -> u64 { // As long as it's big enough increasing it further won't change // the benchmark's results. const SIZE: usize = 64 * 1024 * 1024; - const MAX_ITERATIONS: usize = 32; - const MAX_DURATION: Duration = Duration::from_millis(100); let mut src = Vec::new(); let mut dst = Vec::new(); @@ -192,8 +196,8 @@ pub fn benchmark_memory() -> u64 { Ok(()) }; - benchmark("memory score", SIZE, MAX_ITERATIONS, MAX_DURATION, run) - .expect("benchmark cannot fail; qed") as u64 + benchmark("memory score", SIZE, limit.max_iterations(), limit.max_duration(), run) + .expect("benchmark cannot fail; qed") } struct TemporaryFile { @@ -249,7 +253,7 @@ pub const DEFAULT_DISK_EXECUTION_LIMIT: ExecutionLimit = pub fn benchmark_disk_sequential_writes( limit: ExecutionLimit, directory: &Path, -) -> Result { +) -> Result { const SIZE: usize = 64 * 1024 * 1024; let buffer = random_data(SIZE); @@ -286,13 +290,12 @@ pub fn benchmark_disk_sequential_writes( limit.max_duration(), run, ) - .map(|s| s as u64) } pub fn benchmark_disk_random_writes( limit: ExecutionLimit, directory: &Path, -) -> Result { +) -> Result { const SIZE: usize = 64 * 1024 * 1024; let buffer = random_data(SIZE); @@ -353,7 +356,6 @@ pub fn benchmark_disk_random_writes( limit.max_duration(), run, ) - .map(|s| s as u64) } /// Benchmarks the verification speed of sr25519 signatures. @@ -400,8 +402,8 @@ pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> f64 { pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { #[allow(unused_mut)] let mut hwbench = HwBench { - cpu_hashrate_score: benchmark_cpu(), - memory_memcpy_score: benchmark_memory(), + cpu_hashrate_score: benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT) as u64, + memory_memcpy_score: benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT) as u64, disk_sequential_write_score: None, disk_random_write_score: None, }; @@ -410,7 +412,7 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { hwbench.disk_sequential_write_score = match benchmark_disk_sequential_writes(DEFAULT_DISK_EXECUTION_LIMIT, scratch_directory) { - Ok(score) => Some(score), + Ok(score) => Some(score as u64), Err(error) => { log::warn!("Failed to run the sequential write disk benchmark: {}", error); None @@ -419,7 +421,7 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { hwbench.disk_random_write_score = match benchmark_disk_random_writes(DEFAULT_DISK_EXECUTION_LIMIT, scratch_directory) { - Ok(score) => Some(score), + Ok(score) => Some(score as u64), Err(error) => { log::warn!("Failed to run the random write disk benchmark: {}", error); None @@ -448,26 +450,27 @@ mod tests { #[test] fn test_benchmark_cpu() { - assert_ne!(benchmark_cpu(), 0); + assert!(benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT) > 0.0); } #[test] fn test_benchmark_memory() { - assert_ne!(benchmark_memory(), 0); + assert!(benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT) > 0.0); } #[test] fn test_benchmark_disk_sequential_writes() { assert!( benchmark_disk_sequential_writes(DEFAULT_DISK_EXECUTION_LIMIT, "./".as_ref()).unwrap() > - 0 + 0.0 ); } #[test] fn test_benchmark_disk_random_writes() { assert!( - benchmark_disk_random_writes(DEFAULT_DISK_EXECUTION_LIMIT, "./".as_ref()).unwrap() > 0 + benchmark_disk_random_writes(DEFAULT_DISK_EXECUTION_LIMIT, "./".as_ref()).unwrap() > + 0.0 ); } diff --git a/utils/frame/benchmarking-cli/src/machine/mod.rs b/utils/frame/benchmarking-cli/src/machine/mod.rs index 9e25e58921d71..d5cd2420a3833 100644 --- a/utils/frame/benchmarking-cli/src/machine/mod.rs +++ b/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -63,9 +63,17 @@ pub struct MachineCmd { pub tolerance: f64, /// Time limit for the verification benchmark. - #[clap(long, default_value = "2.0", value_name = "SECONDS")] + #[clap(long, default_value = "5.0", value_name = "SECONDS")] pub verify_duration: f32, + /// Time limit for the hash function benchmark. + #[clap(long, default_value = "5.0", value_name = "SECONDS")] + pub hash_duration: f32, + + /// Time limit for the memory benchmark. + #[clap(long, default_value = "5.0", value_name = "SECONDS")] + pub memory_duration: f32, + /// Time limit for each disk benchmark. #[clap(long, default_value = "5.0", value_name = "SECONDS")] pub disk_duration: f32, @@ -134,11 +142,13 @@ impl MachineCmd { fn measure(&self, metric: &Metric, dir: &Path) -> Result { let verify_limit = ExecutionLimit::from_secs_f32(self.verify_duration); let disk_limit = ExecutionLimit::from_secs_f32(self.disk_duration); + let hash_limit = ExecutionLimit::from_secs_f32(self.hash_duration); + let memory_limit = ExecutionLimit::from_secs_f32(self.memory_duration); let score = match metric { - Metric::Blake2256 => Throughput::MiBs(benchmark_cpu() as f64), + Metric::Blake2256 => Throughput::MiBs(benchmark_cpu(hash_limit) as f64), Metric::Sr25519Verify => Throughput::MiBs(benchmark_sr25519_verify(verify_limit)), - Metric::MemCopy => Throughput::MiBs(benchmark_memory() as f64), + Metric::MemCopy => Throughput::MiBs(benchmark_memory(memory_limit) as f64), Metric::DiskSeqWrite => Throughput::MiBs(benchmark_disk_sequential_writes(disk_limit, dir)? as f64), Metric::DiskRndWrite => From d6e615741e6bdbe72c6d2fa78e3bf6eaaa42b5fe Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 17 May 2022 18:29:21 +0200 Subject: [PATCH 0807/1472] fix: regression of `sync_state_genSyncSpec` #11435 (#11437) * fix: #11435 * address grumbles: better safe than sorry --- client/sync-state-rpc/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index a0a5b66cb86fc..02a22a838b8b2 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -128,7 +128,7 @@ pub struct LightSyncState { pub trait SyncStateRpcApi { /// Returns the JSON serialized chainspec running the node, with a sync state. #[method(name = "sync_state_genSyncSpec")] - fn system_gen_sync_spec(&self, raw: bool) -> RpcResult; + fn system_gen_sync_spec(&self, raw: bool) -> RpcResult; } /// An api for sync state RPC calls. @@ -185,7 +185,7 @@ where Block: BlockT, Backend: HeaderBackend + sc_client_api::AuxStore + 'static, { - fn system_gen_sync_spec(&self, raw: bool) -> RpcResult { + fn system_gen_sync_spec(&self, raw: bool) -> RpcResult { let current_sync_state = self.build_sync_state()?; let mut chain_spec = self.chain_spec.cloned_box(); @@ -197,6 +197,7 @@ where let val = serde_json::to_value(¤t_sync_state)?; *extension = Some(val); - chain_spec.as_json(raw).map_err(|e| Error::::JsonRpc(e).into()) + let json_str = chain_spec.as_json(raw).map_err(|e| Error::::JsonRpc(e))?; + serde_json::from_str(&json_str).map_err(Into::into) } } From 127536132f52b0a1ef0693a4adb5399a175a4aa1 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Wed, 18 May 2022 00:38:51 +0800 Subject: [PATCH 0808/1472] Migrate abandoned `prettytable-rs` to `comfy-table` (#11430) * Migrate to comfy-table Signed-off-by: koushiro * disable the default features Signed-off-by: koushiro --- Cargo.lock | 109 +++--------------- utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../frame/benchmarking-cli/src/machine/mod.rs | 25 ++-- 3 files changed, 34 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 201feb7e06d7d..14196e4f85364 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -615,17 +615,6 @@ dependencies = [ "constant_time_eq", ] -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "constant_time_eq", -] - [[package]] name = "blake2b_simd" version = "1.0.0" @@ -1048,6 +1037,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "comfy-table" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b103d85ca6e209388771bfb7aa6b68a7aeec4afbf6f0a0264bfbf50360e5212e" +dependencies = [ + "strum", + "strum_macros", + "unicode-width", +] + [[package]] name = "concurrent-queue" version = "1.2.2" @@ -1665,17 +1665,6 @@ dependencies = [ "dirs-sys-next", ] -[[package]] -name = "dirs" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" -dependencies = [ - "libc", - "redox_users 0.3.5", - "winapi", -] - [[package]] name = "dirs-sys" version = "0.3.6" @@ -1683,7 +1672,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" dependencies = [ "libc", - "redox_users 0.4.0", + "redox_users", "winapi", ] @@ -1694,7 +1683,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users 0.4.0", + "redox_users", "winapi", ] @@ -1844,12 +1833,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - [[package]] name = "enum-as-inner" version = "0.4.0" @@ -2152,6 +2135,7 @@ dependencies = [ "Inflector", "chrono", "clap 3.1.18", + "comfy-table", "frame-benchmarking", "frame-support", "frame-system", @@ -2165,7 +2149,6 @@ dependencies = [ "log", "memory-db", "parity-scale-codec", - "prettytable-rs", "rand 0.8.4", "rand_pcg 0.3.1", "sc-block-builder", @@ -4365,7 +4348,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3db354f401db558759dfc1e568d010a5d4146f4d3f637be1275ec4a3cf09689" dependencies = [ - "blake2b_simd 1.0.0", + "blake2b_simd", "blake2s_simd", "blake3", "core2", @@ -6588,7 +6571,7 @@ dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall 0.2.10", + "redox_syscall", "smallvec", "winapi", ] @@ -6601,7 +6584,7 @@ checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.2.10", + "redox_syscall", "smallvec", "windows-sys", ] @@ -6893,20 +6876,6 @@ dependencies = [ "output_vt100", ] -[[package]] -name = "prettytable-rs" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e" -dependencies = [ - "atty", - "csv", - "encode_unicode", - "lazy_static", - "term", - "unicode-width", -] - [[package]] name = "primitive-types" version = "0.11.1" @@ -7416,12 +7385,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "redox_syscall" version = "0.2.10" @@ -7431,17 +7394,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_users" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" -dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", -] - [[package]] name = "redox_users" version = "0.4.0" @@ -7449,7 +7401,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom 0.2.3", - "redox_syscall 0.2.10", + "redox_syscall", ] [[package]] @@ -7684,18 +7636,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64", - "blake2b_simd 0.5.11", - "constant_time_eq", - "crossbeam-utils", -] - [[package]] name = "rustc-demangle" version = "0.1.18" @@ -10791,22 +10731,11 @@ dependencies = [ "cfg-if 1.0.0", "fastrand", "libc", - "redox_syscall 0.2.10", + "redox_syscall", "remove_dir_all", "winapi", ] -[[package]] -name = "term" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" -dependencies = [ - "byteorder", - "dirs", - "winapi", -] - [[package]] name = "termcolor" version = "1.1.2" diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 68be768012d51..5f30e21b2986a 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] chrono = "0.4" clap = { version = "3.1.18", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } +comfy-table = { version = "5.0.1", default-features = false } handlebars = "4.2.2" hash-db = "0.15.2" hex = "0.4.3" @@ -26,7 +27,6 @@ lazy_static = "1.4.0" linked-hash-map = "0.5.4" log = "0.4.17" memory-db = "0.29.0" -prettytable-rs = "0.8.0" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.136" diff --git a/utils/frame/benchmarking-cli/src/machine/mod.rs b/utils/frame/benchmarking-cli/src/machine/mod.rs index d5cd2420a3833..5f27c71983905 100644 --- a/utils/frame/benchmarking-cli/src/machine/mod.rs +++ b/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -20,6 +20,12 @@ pub mod hardware; +use std::{boxed::Box, fs, path::Path}; + +use clap::Parser; +use comfy_table::{Row, Table}; +use log::{error, info, warn}; + use sc_cli::{CliConfiguration, Result, SharedParams}; use sc_service::Configuration; use sc_sysinfo::{ @@ -27,11 +33,6 @@ use sc_sysinfo::{ benchmark_memory, benchmark_sr25519_verify, ExecutionLimit, }; -use clap::Parser; -use log::{error, info, warn}; -use prettytable::{cell, row, table}; -use std::{boxed::Box, fmt::Debug, fs, path::Path}; - use crate::shared::check_build_profile; pub use hardware::{Metric, Requirement, Requirements, Throughput, SUBSTRATE_REFERENCE_HARDWARE}; @@ -160,7 +161,8 @@ impl MachineCmd { /// Prints a human-readable summary. fn print_summary(&self, requirements: Requirements, results: Vec) -> Result<()> { // Use a table for nicer console output. - let mut table = table!(["Category", "Function", "Score", "Minimum", "Result"]); + let mut table = Table::new(); + table.set_header(["Category", "Function", "Score", "Minimum", "Result"]); // Count how many passed and how many failed. let (mut passed, mut failed) = (0, 0); for (requirement, result) in requirements.0.iter().zip(results.iter()) { @@ -217,15 +219,16 @@ impl MachineCmd { impl BenchResult { /// Format [`Self`] as row that can be printed in a table. - fn to_row(&self, req: &Requirement) -> prettytable::Row { + fn to_row(&self, req: &Requirement) -> Row { let passed = if self.passed { "✅ Pass" } else { "❌ Fail" }; - row![ - req.metric.category(), - req.metric.name(), + vec![ + req.metric.category().into(), + req.metric.name().into(), format!("{}", self.score), format!("{}", req.minimum), - format!("{} ({: >5.1?} %)", passed, self.rel_score * 100.0) + format!("{} ({: >5.1?} %)", passed, self.rel_score * 100.0), ] + .into() } } From 6a7af64fea375bd8599dbf1389a38c53e169808f Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Tue, 17 May 2022 19:16:04 +0100 Subject: [PATCH 0809/1472] Add MinPointsToBalance to nomination pools (#11377) * add MinPointsToBalance to pools * add min_points_to_balance to benchmark mock * fmt * comments Co-authored-by: Oliver Tale-Yazdi * check min_points_to_balance.is_zero * comment * comment * storage to constant * fix * comment Co-authored-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- bin/node/runtime/src/lib.rs | 2 + .../nomination-pools/benchmarking/src/mock.rs | 2 + frame/nomination-pools/src/lib.rs | 31 ++++++++--- frame/nomination-pools/src/mock.rs | 2 + frame/nomination-pools/src/tests.rs | 55 ++++++++++++++----- 5 files changed, 69 insertions(+), 23 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1257aabb9d5cc..40316cee9b2b7 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -727,6 +727,7 @@ impl pallet_bags_list::Config for Runtime { parameter_types! { pub const PostUnbondPoolsWindow: u32 = 4; pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/nopls"); + pub const MinPointsToBalance: u32 = 10; } use sp_runtime::traits::Convert; @@ -754,6 +755,7 @@ impl pallet_nomination_pools::Config for Runtime { type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; type PalletId = NominationPoolsPalletId; + type MinPointsToBalance = MinPointsToBalance; } parameter_types! { diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index d98bcb542f514..eb884869f6d32 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -144,6 +144,7 @@ impl Convert for U256ToBalance { parameter_types! { pub static PostUnbondingPoolsWindow: u32 = 10; pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); + pub const MinPointsToBalance: u32 = 10; } impl pallet_nomination_pools::Config for Runtime { @@ -157,6 +158,7 @@ impl pallet_nomination_pools::Config for Runtime { type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; type PalletId = PoolsPalletId; + type MinPointsToBalance = MinPointsToBalance; } impl crate::Config for Runtime {} diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index d68a6f09c31d1..cdc3bdaf34389 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -740,16 +740,22 @@ impl BondedPool { // We checked for zero above .div(bonded_balance); + let min_points_to_balance = T::MinPointsToBalance::get(); + // Pool points can inflate relative to balance, but only if the pool is slashed. // If we cap the ratio of points:balance so one cannot join a pool that has been slashed - // 90%, - ensure!(points_to_balance_ratio_floor < 10u32.into(), Error::::OverflowRisk); - // while restricting the balance to 1/10th of max total issuance, + // by `min_points_to_balance`%, if not zero. + ensure!( + points_to_balance_ratio_floor < min_points_to_balance.into(), + Error::::OverflowRisk + ); + // while restricting the balance to `min_points_to_balance` of max total issuance, let next_bonded_balance = bonded_balance.saturating_add(new_funds); ensure!( - next_bonded_balance < BalanceOf::::max_value().div(10u32.into()), + next_bonded_balance < BalanceOf::::max_value().div(min_points_to_balance.into()), Error::::OverflowRisk ); + // then we can be decently confident the bonding pool points will not overflow // `BalanceOf`. Note that these are just heuristics. @@ -1102,6 +1108,14 @@ pub mod pallet { #[pallet::constant] type PalletId: Get; + /// The minimum pool points-to-balance ratio that must be maintained for it to be `open`. + /// This is important in the event slashing takes place and the pool's points-to-balance + /// ratio becomes disproportional. + /// For a value of 10, the threshold would be a pool points-to-balance ratio of 10:1. + /// Such a scenario would also be the equivalent of the pool being 90% slashed. + #[pallet::constant] + type MinPointsToBalance: Get; + /// Infallible method for converting `Currency::Balance` to `U256`. type BalanceToU256: Convert, U256>; @@ -1844,7 +1858,7 @@ pub mod pallet { Ok(()) } - /// Update configurations for the nomination pools. The origin must for this call must be + /// Update configurations for the nomination pools. The origin for this call must be /// Root. /// /// # Arguments @@ -1880,7 +1894,6 @@ pub mod pallet { config_op_exp!(MaxPools::, max_pools); config_op_exp!(MaxPoolMembers::, max_members); config_op_exp!(MaxPoolMembersPerPool::, max_members_per_pool); - Ok(()) } @@ -1940,12 +1953,15 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn integrity_test() { + assert!( + T::MinPointsToBalance::get() > 0, + "Minimum points to balance ratio must be greater than 0" + ); assert!( sp_std::mem::size_of::() >= 2 * sp_std::mem::size_of::>(), "bit-length of the reward points must be at least twice as much as balance" ); - assert!( T::StakingInterface::bonding_duration() < TotalUnbondingPools::::get(), "There must be more unbonding pools then the bonding duration / @@ -2304,7 +2320,6 @@ impl Pallet { sum_unbonding_balance ); } - Ok(()) } diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 5498496965adb..1dadd7e00c528 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -162,6 +162,7 @@ parameter_types! { pub static MaxMetadataLen: u32 = 2; pub static CheckLevel: u8 = 255; pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); + pub const MinPointsToBalance: u32 = 10; } impl pools::Config for Runtime { type Event = Event; @@ -174,6 +175,7 @@ impl pools::Config for Runtime { type PalletId = PoolsPalletId; type MaxMetadataLen = MaxMetadataLen; type MaxUnbonding = MaxUnbonding; + type MinPointsToBalance = MinPointsToBalance; } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index fe78da3bb14af..c16c1c9da9e90 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -199,23 +199,34 @@ mod bonded_pool { }, }; + let min_points_to_balance: u128 = MinPointsToBalance::get().into(); + // Simulate a 100% slashed pool StakingMock::set_bonded_balance(pool.bonded_account(), 0); assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); - // Simulate a 89% - StakingMock::set_bonded_balance(pool.bonded_account(), 11); + // Simulate a slashed pool at `MinPointsToBalance` + 1 slashed pool + StakingMock::set_bonded_balance( + pool.bonded_account(), + min_points_to_balance.saturating_add(1).into(), + ); assert_ok!(pool.ok_to_join(0)); - // Simulate a 90% slashed pool - StakingMock::set_bonded_balance(pool.bonded_account(), 10); + // Simulate a slashed pool at `MinPointsToBalance` + StakingMock::set_bonded_balance(pool.bonded_account(), min_points_to_balance); assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); - StakingMock::set_bonded_balance(pool.bonded_account(), Balance::MAX / 10); - // New bonded balance would be over 1/10th of Balance type + StakingMock::set_bonded_balance( + pool.bonded_account(), + Balance::MAX / min_points_to_balance, + ); + // New bonded balance would be over threshold of Balance type assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); // and a sanity check - StakingMock::set_bonded_balance(pool.bonded_account(), Balance::MAX / 10 - 1); + StakingMock::set_bonded_balance( + pool.bonded_account(), + Balance::MAX / min_points_to_balance - 1, + ); assert_ok!(pool.ok_to_join(0)); }); } @@ -503,22 +514,36 @@ mod join { }, ); - // Force the points:balance ratio to 100/10 - StakingMock::set_bonded_balance(Pools::create_bonded_account(123), 10); + // Force the points:balance ratio to `MinPointsToBalance` (100/10) + let min_points_to_balance: u128 = MinPointsToBalance::get().into(); + + StakingMock::set_bonded_balance( + Pools::create_bonded_account(123), + min_points_to_balance, + ); assert_noop!(Pools::join(Origin::signed(11), 420, 123), Error::::OverflowRisk); - StakingMock::set_bonded_balance(Pools::create_bonded_account(123), Balance::MAX / 10); - // Balance is gt 1/10 of Balance::MAX + StakingMock::set_bonded_balance( + Pools::create_bonded_account(123), + Balance::MAX / min_points_to_balance, + ); + // Balance needs to be gt Balance::MAX / `MinPointsToBalance` assert_noop!(Pools::join(Origin::signed(11), 5, 123), Error::::OverflowRisk); - StakingMock::set_bonded_balance(Pools::create_bonded_account(1), 10); + StakingMock::set_bonded_balance(Pools::create_bonded_account(1), min_points_to_balance); // Cannot join a pool that isn't open unsafe_set_state(123, PoolState::Blocked).unwrap(); - assert_noop!(Pools::join(Origin::signed(11), 10, 123), Error::::NotOpen); + assert_noop!( + Pools::join(Origin::signed(11), min_points_to_balance, 123), + Error::::NotOpen + ); unsafe_set_state(123, PoolState::Destroying).unwrap(); - assert_noop!(Pools::join(Origin::signed(11), 10, 123), Error::::NotOpen); + assert_noop!( + Pools::join(Origin::signed(11), min_points_to_balance, 123), + Error::::NotOpen + ); // Given MinJoinBond::::put(100); @@ -3434,7 +3459,7 @@ mod set_configs { ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, - ConfigOp::Remove + ConfigOp::Remove, )); assert_eq!(MinJoinBond::::get(), 0); assert_eq!(MinCreateBond::::get(), 0); From 88abf20f01c73cd98515d95e257a7c6b885b8373 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Wed, 18 May 2022 02:28:34 +0800 Subject: [PATCH 0810/1472] frame_support::pallet_prelude: reexport StorageVersion (#11408) * frame_support::pallet_prelude: reexport StorageVersion Signed-off-by: koushiro * cargo fmt Signed-off-by: koushiro --- frame/collective/src/lib.rs | 4 +--- frame/collective/src/tests.rs | 2 +- frame/contracts/src/lib.rs | 18 +++++++++--------- frame/contracts/src/migration.rs | 2 -- frame/elections-phragmen/src/lib.rs | 20 ++++++++++---------- frame/grandpa/src/lib.rs | 11 +++++------ frame/membership/src/lib.rs | 6 ++---- frame/session/src/historical/mod.rs | 2 +- frame/session/src/lib.rs | 2 +- frame/session/src/tests.rs | 2 +- frame/support/src/lib.rs | 2 +- frame/support/test/tests/pallet.rs | 6 +----- frame/tips/src/lib.rs | 2 +- frame/tips/src/tests.rs | 2 +- frame/vesting/src/lib.rs | 12 ++++++++---- frame/vesting/src/mock.rs | 2 +- 16 files changed, 44 insertions(+), 51 deletions(-) diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 817e4e176bd4c..9fce1762c6ea7 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -51,9 +51,7 @@ use frame_support::{ codec::{Decode, Encode}, dispatch::{DispatchError, DispatchResultWithPostInfo, Dispatchable, PostDispatchInfo}, ensure, - traits::{ - Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers, StorageVersion, - }, + traits::{Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers}, weights::{GetDispatchInfo, Weight}, }; diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index a8abfb0c52358..063479e42fe77 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -19,7 +19,7 @@ use super::{Event as CollectiveEvent, *}; use crate as pallet_collective; use frame_support::{ assert_noop, assert_ok, parameter_types, - traits::{ConstU32, ConstU64, GenesisBuild}, + traits::{ConstU32, ConstU64, GenesisBuild, StorageVersion}, weights::Pays, Hashable, }; diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 0ae326f6c1e8f..ca639d7781ac2 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -114,7 +114,7 @@ use codec::{Encode, HasCompact}; use frame_support::{ dispatch::Dispatchable, ensure, - traits::{Contains, Currency, Get, Randomness, ReservableCurrency, StorageVersion, Time}, + traits::{Contains, Currency, Get, Randomness, ReservableCurrency, Time}, weights::{DispatchClass, GetDispatchInfo, Pays, PostDispatchInfo, Weight}, }; use frame_system::{limits::BlockWeights, Pallet as System}; @@ -133,9 +133,6 @@ type TrieId = Vec; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -/// The current storage version. -const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); - /// Used as a sentinel value when reading and writing contract memory. /// /// It is usually used to signal `None` to a contract when only a primitive is allowed @@ -222,6 +219,14 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData); + #[pallet::config] pub trait Config: frame_system::Config { /// The time implementation used to supply timestamps to conntracts through `seal_now`. @@ -353,11 +358,6 @@ pub mod pallet { type AddressGenerator: AddressGenerator; } - #[pallet::pallet] - #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::without_storage_info] - pub struct Pallet(PhantomData); - #[pallet::hooks] impl Hooks> for Pallet where diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 035e3b4409cf9..fb99078451ef9 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -28,8 +28,6 @@ use sp_std::{marker::PhantomData, prelude::*}; /// Wrapper for all migrations of this pallet, based on `StorageVersion`. pub fn migrate() -> Weight { - use frame_support::traits::StorageVersion; - let version = StorageVersion::get::>(); let mut weight: Weight = 0; diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 270d3853e2ca5..ec2234cde5a6e 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -104,7 +104,7 @@ use frame_support::{ traits::{ defensive_prelude::*, ChangeMembers, Contains, ContainsLengthBound, Currency, CurrencyToVote, Get, InitializeMembers, LockIdentifier, LockableCurrency, OnUnbalanced, - ReservableCurrency, SortedMembers, StorageVersion, WithdrawReasons, + ReservableCurrency, SortedMembers, WithdrawReasons, }, weights::Weight, }; @@ -123,9 +123,6 @@ pub use weights::WeightInfo; /// All migrations. pub mod migrations; -/// The current storage version. -const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); - /// The maximum votes allowed per voter. pub const MAXIMUM_VOTE: usize = 16; @@ -186,6 +183,15 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData); + #[pallet::config] pub trait Config: frame_system::Config { type Event: From> + IsType<::Event>; @@ -247,12 +253,6 @@ pub mod pallet { type WeightInfo: WeightInfo; } - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::without_storage_info] - pub struct Pallet(PhantomData); - #[pallet::hooks] impl Hooks> for Pallet { /// What to do at the end of each block. diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 75244c72cfd16..be613e302b21e 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -43,10 +43,11 @@ use frame_support::{ dispatch::DispatchResultWithPostInfo, pallet_prelude::Get, storage, - traits::{KeyOwnerProofSystem, OneSessionHandler, StorageVersion}, + traits::{KeyOwnerProofSystem, OneSessionHandler}, weights::{Pays, Weight}, WeakBoundedVec, }; +use scale_info::TypeInfo; use sp_runtime::{generic::DigestItem, traits::Zero, DispatchResult, KeyTypeId}; use sp_session::{GetSessionNumber, GetValidatorCount}; use sp_staking::SessionIndex; @@ -69,17 +70,15 @@ pub use equivocation::{ pub use pallet::*; -use scale_info::TypeInfo; - -/// The current storage version. -const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); - #[frame_support::pallet] pub mod pallet { use super::*; use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); + #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index ad6273e78f0f2..8e7ea9eeec313 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -23,9 +23,7 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::traits::{ - ChangeMembers, Contains, Get, InitializeMembers, SortedMembers, StorageVersion, -}; +use frame_support::traits::{ChangeMembers, Contains, Get, InitializeMembers, SortedMembers}; use sp_std::prelude::*; pub mod migrations; @@ -507,7 +505,7 @@ mod tests { use frame_support::{ assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{ConstU32, ConstU64, GenesisBuild}, + traits::{ConstU32, ConstU64, GenesisBuild, StorageVersion}, }; use frame_system::EnsureSignedBy; diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index 76cefeb7b0532..2a749f2aae9dd 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -45,7 +45,7 @@ use sp_trie::{ use frame_support::{ print, - traits::{KeyOwnerProofSystem, StorageVersion, ValidatorSet, ValidatorSetWithIdentification}, + traits::{KeyOwnerProofSystem, ValidatorSet, ValidatorSetWithIdentification}, Parameter, }; diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index a460c650ec602..71ee9d1e0758a 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -121,7 +121,7 @@ use frame_support::{ ensure, traits::{ EstimateNextNewSession, EstimateNextSessionRotation, FindAuthor, Get, OneSessionHandler, - StorageVersion, ValidatorRegistration, ValidatorSet, + ValidatorRegistration, ValidatorSet, }, weights::Weight, Parameter, diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index 4f2108a9a4380..c9d2dbb53d9ba 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -459,7 +459,7 @@ fn test_migration_v1() { historical::{HistoricalSessions, StoredRange}, mock::Historical, }; - use frame_support::traits::PalletInfoAccess; + use frame_support::traits::{PalletInfoAccess, StorageVersion}; new_test_ext().execute_with(|| { assert!(>::iter_values().count() > 0); diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 3e84c009b5ca6..33830257cdd82 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1409,7 +1409,7 @@ pub mod pallet_prelude { }, traits::{ ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, IsType, - PalletInfoAccess, StorageInfoTrait, + PalletInfoAccess, StorageInfoTrait, StorageVersion, }, weights::{DispatchClass, Pays, Weight}, Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity, diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 83f6a722f93aa..ec97c1794c27b 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -96,13 +96,9 @@ impl SomeAssociation2 for u64 { #[frame_support::pallet] pub mod pallet { - use super::{ - SomeAssociation1, SomeAssociation2, SomeType1, SomeType2, SomeType3, SomeType4, SomeType5, - SomeType6, SomeType7, StorageVersion, - }; + use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - use scale_info::TypeInfo; type BalanceOf = ::Balance; diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index b9868dac43011..f43545e2b4fe8 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -70,7 +70,7 @@ use codec::{Decode, Encode}; use frame_support::{ traits::{ ContainsLengthBound, Currency, EnsureOrigin, ExistenceRequirement::KeepAlive, Get, - OnUnbalanced, ReservableCurrency, SortedMembers, StorageVersion, + OnUnbalanced, ReservableCurrency, SortedMembers, }, Parameter, }; diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index 0c58a949958fe..27cce5576a3b9 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -34,7 +34,7 @@ use frame_support::{ pallet_prelude::GenesisBuild, parameter_types, storage::StoragePrefixedMap, - traits::{ConstU32, ConstU64, SortedMembers}, + traits::{ConstU32, ConstU64, SortedMembers, StorageVersion}, PalletId, }; diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 23b7d231343b4..9fb7eb8037916 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -57,15 +57,15 @@ pub mod weights; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ + dispatch::{DispatchError, DispatchResult}, ensure, - pallet_prelude::*, + storage::bounded_vec::BoundedVec, traits::{ Currency, ExistenceRequirement, Get, LockIdentifier, LockableCurrency, VestingSchedule, WithdrawReasons, }, + weights::Weight, }; -use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; -pub use pallet::*; use scale_info::TypeInfo; use sp_runtime::{ traits::{ @@ -74,7 +74,9 @@ use sp_runtime::{ }, RuntimeDebug, }; -use sp_std::{fmt::Debug, prelude::*}; +use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; + +pub use pallet::*; pub use vesting_info::*; pub use weights::WeightInfo; @@ -146,6 +148,8 @@ impl Get for MaxVestingSchedulesGet { #[frame_support::pallet] pub mod pallet { use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; #[pallet::config] pub trait Config: frame_system::Config { diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index 8a830d72b26b8..9ad8e57500e89 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -17,7 +17,7 @@ use frame_support::{ parameter_types, - traits::{ConstU32, ConstU64}, + traits::{ConstU32, ConstU64, GenesisBuild}, }; use sp_core::H256; use sp_runtime::{ From f2c9c5173d22cef009e7f67a82a0c31ac44f5426 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Tue, 17 May 2022 23:12:59 +0300 Subject: [PATCH 0811/1472] Remove unnecessary RPC boxing (#11434) --- client/beefy/rpc/src/lib.rs | 6 ++---- client/finality-grandpa/rpc/src/lib.rs | 6 ++---- client/rpc/src/author/mod.rs | 6 ++---- client/rpc/src/chain/chain_full.rs | 5 ++--- client/rpc/src/state/state_full.rs | 12 ++++-------- 5 files changed, 12 insertions(+), 23 deletions(-) diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index e4c8c76419ccb..ea35678a48b8f 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -146,11 +146,9 @@ where if let Some(mut sink) = pending.accept() { sink.pipe_from_stream(stream).await; } - } - .boxed(); + }; - self.executor - .spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } async fn latest_finalized(&self) -> RpcResult { diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index 82962d716d589..cb51d71b20bf4 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -113,11 +113,9 @@ where if let Some(mut sink) = pending.accept() { sink.pipe_from_stream(stream).await; } - } - .boxed(); + }; - self.executor - .spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } async fn prove_finality( diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index d10398afc813b..b8c4f5d582808 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -210,10 +210,8 @@ where }; sink.pipe_from_stream(stream).await; - } - .boxed(); + }; - self.executor - .spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } } diff --git a/client/rpc/src/chain/chain_full.rs b/client/rpc/src/chain/chain_full.rs index 9ca6b3edcfe60..2d507f7b9b684 100644 --- a/client/rpc/src/chain/chain_full.rs +++ b/client/rpc/src/chain/chain_full.rs @@ -147,8 +147,7 @@ fn subscribe_headers( if let Some(mut sink) = pending.accept() { sink.pipe_from_stream(stream).await; } - } - .boxed(); + }; - executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); + executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 48165e912b03a..0e20832b30508 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -404,11 +404,9 @@ where if let Some(mut sink) = pending.accept() { sink.pipe_from_stream(stream).await; } - } - .boxed(); + }; - self.executor - .spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } fn subscribe_storage(&self, pending: PendingSubscription, keys: Option>) { @@ -451,11 +449,9 @@ where if let Some(mut sink) = pending.accept() { sink.pipe_from_stream(stream).await; } - } - .boxed(); + }; - self.executor - .spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed()); + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } async fn trace_block( From 2823dc4de5030aada6032e2ac58f4781f8dbfaf3 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 17 May 2022 17:12:02 -0400 Subject: [PATCH 0812/1472] Explicitly note that existing `AccountIdConversion` is truncating and add fallible `try_into...` (#10719) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * note truncating, add fallible try_into * fmt * migrate all to `truncating` * typo * uno mas * Update primitives/runtime/src/traits.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * check the bytes before and after are sensible * fmt * Update lib.rs * Update primitives/runtime/src/traits.rs Co-authored-by: Bastian Köcher Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Bastian Köcher --- frame/bounties/src/lib.rs | 4 +- frame/child-bounties/src/lib.rs | 2 +- frame/lottery/src/lib.rs | 2 +- frame/nomination-pools/src/lib.rs | 4 +- frame/society/src/lib.rs | 4 +- frame/tips/src/lib.rs | 2 +- frame/treasury/src/lib.rs | 2 +- primitives/runtime/src/traits.rs | 89 ++++++++++++++++--- .../frame-utilities-cli/src/pallet_id.rs | 2 +- 9 files changed, 87 insertions(+), 24 deletions(-) diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index dfeef36a1fae0..b01a36b430a4e 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -799,14 +799,14 @@ impl Pallet { /// This actually does computation. If you need to keep using it, then make sure you cache the /// value and only call this once. pub fn account_id() -> T::AccountId { - T::PalletId::get().into_account() + T::PalletId::get().into_account_truncating() } /// The account ID of a bounty account pub fn bounty_account_id(id: BountyIndex) -> T::AccountId { // only use two byte prefix to support 16 byte account id (used by test) // "modl" ++ "py/trsry" ++ "bt" is 14 bytes, and two bytes remaining for bounty index - T::PalletId::get().into_sub_account(("bt", id)) + T::PalletId::get().into_sub_account_truncating(("bt", id)) } fn create_bounty( diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index a8496d4e7af91..4f25fdcf8903a 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -786,7 +786,7 @@ impl Pallet { // This function is taken from the parent (bounties) pallet, but the // prefix is changed to have different AccountId when the index of // parent and child is same. - T::PalletId::get().into_sub_account(("cb", id)) + T::PalletId::get().into_sub_account_truncating(("cb", id)) } fn create_child_bounty( diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index bc96a029a4210..02df65a3336bf 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -389,7 +389,7 @@ impl Pallet { /// This actually does computation. If you need to keep using it, then make sure you cache the /// value and only call this once. pub fn account_id() -> T::AccountId { - T::PalletId::get().into_account() + T::PalletId::get().into_account_truncating() } /// Return the pot account and amount of money in the pot. diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index cdc3bdaf34389..ff77949cf6952 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2018,14 +2018,14 @@ impl Pallet { /// Create the main, bonded account of a pool with the given id. pub fn create_bonded_account(id: PoolId) -> T::AccountId { - T::PalletId::get().into_sub_account((AccountType::Bonded, id)) + T::PalletId::get().into_sub_account_truncating((AccountType::Bonded, id)) } /// Create the reward account of a pool with the given id. pub fn create_reward_account(id: PoolId) -> T::AccountId { // NOTE: in order to have a distinction in the test account id type (u128), we put // account_type first so it does not get truncated out. - T::PalletId::get().into_sub_account((AccountType::Reward, id)) + T::PalletId::get().into_sub_account_truncating((AccountType::Reward, id)) } /// Get the member with their associated bonded and reward pool. diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 645a0b8ba1715..2973ecd68092e 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -1726,7 +1726,7 @@ impl, I: 'static> Pallet { /// This actually does computation. If you need to keep using it, then make sure you cache the /// value and only call this once. pub fn account_id() -> T::AccountId { - T::PalletId::get().into_account() + T::PalletId::get().into_account_truncating() } /// The account ID of the payouts pot. This is where payouts are made from. @@ -1734,7 +1734,7 @@ impl, I: 'static> Pallet { /// This actually does computation. If you need to keep using it, then make sure you cache the /// value and only call this once. pub fn payouts() -> T::AccountId { - T::PalletId::get().into_sub_account(b"payouts") + T::PalletId::get().into_sub_account_truncating(b"payouts") } /// Return the duration of the lock, in blocks, with the given number of members. diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index f43545e2b4fe8..e1c7b5e77c062 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -467,7 +467,7 @@ impl Pallet { /// This actually does computation. If you need to keep using it, then make sure you cache the /// value and only call this once. pub fn account_id() -> T::AccountId { - T::PalletId::get().into_account() + T::PalletId::get().into_account_truncating() } /// Given a mutable reference to an `OpenTip`, insert the tip into it and check whether it diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index d080d346ba3de..419970ed18afa 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -437,7 +437,7 @@ impl, I: 'static> Pallet { /// This actually does computation. If you need to keep using it, then make sure you cache the /// value and only call this once. pub fn account_id() -> T::AccountId { - T::PalletId::get().into_account() + T::PalletId::get().into_account_truncating() } /// The needed bond for a proposal whose spend is `value`. diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 393de086f3c58..1b21e7c65ddf7 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1243,9 +1243,16 @@ impl<'a> codec::Input for TrailingZeroInput<'a> { /// This type can be converted into and possibly from an AccountId (which itself is generic). pub trait AccountIdConversion: Sized { - /// Convert into an account ID. This is infallible. - fn into_account(&self) -> AccountId { - self.into_sub_account(&()) + /// Convert into an account ID. This is infallible, and may truncate bytes to provide a result. + /// This may lead to duplicate accounts if the size of `AccountId` is less than the seed. + fn into_account_truncating(&self) -> AccountId { + self.into_sub_account_truncating(&()) + } + + /// Convert into an account ID, checking that all bytes of the seed are being used in the final + /// `AccountId` generated. If any bytes are dropped, this returns `None`. + fn try_into_account(&self) -> Option { + self.try_into_sub_account(&()) } /// Try to convert an account ID into this type. Might not succeed. @@ -1253,8 +1260,8 @@ pub trait AccountIdConversion: Sized { Self::try_from_sub_account::<()>(a).map(|x| x.0) } - /// Convert this value amalgamated with the a secondary "sub" value into an account ID. This is - /// infallible. + /// Convert this value amalgamated with the a secondary "sub" value into an account ID, + /// truncating any unused bytes. This is infallible. /// /// NOTE: The account IDs from this and from `into_account` are *not* guaranteed to be distinct /// for any given value of `self`, nor are different invocations to this with different types @@ -1262,19 +1269,45 @@ pub trait AccountIdConversion: Sized { /// - `self.into_sub_account(0u32)` /// - `self.into_sub_account(vec![0u8; 0])` /// - `self.into_account()` - fn into_sub_account(&self, sub: S) -> AccountId; + /// + /// Also, if the seed provided to this function is greater than the number of bytes which fit + /// into this `AccountId` type, then it will lead to truncation of the seed, and potentially + /// non-unique accounts. + fn into_sub_account_truncating(&self, sub: S) -> AccountId; + + /// Same as `into_sub_account_truncating`, but ensuring that all bytes of the account's seed are + /// used when generating an account. This can help guarantee that different accounts are unique, + /// besides types which encode the same as noted above. + fn try_into_sub_account(&self, sub: S) -> Option; /// Try to convert an account ID into this type. Might not succeed. fn try_from_sub_account(x: &AccountId) -> Option<(Self, S)>; } -/// Format is TYPE_ID ++ encode(parachain ID) ++ 00.... where 00... is indefinite trailing zeroes to +/// Format is TYPE_ID ++ encode(sub-seed) ++ 00.... where 00... is indefinite trailing zeroes to /// fill AccountId. impl AccountIdConversion for Id { - fn into_sub_account(&self, sub: S) -> T { + // Take the `sub` seed, and put as much of it as possible into the generated account, but + // allowing truncation of the seed if it would not fit into the account id in full. This can + // lead to two different `sub` seeds with the same account generated. + fn into_sub_account_truncating(&self, sub: S) -> T { (Id::TYPE_ID, self, sub) .using_encoded(|b| T::decode(&mut TrailingZeroInput(b))) - .expect("`AccountId` type is never greater than 32 bytes; qed") + .expect("All byte sequences are valid `AccountIds`; qed") + } + + // Same as `into_sub_account_truncating`, but returns `None` if any bytes would be truncated. + fn try_into_sub_account(&self, sub: S) -> Option { + let encoded_seed = (Id::TYPE_ID, self, sub).encode(); + let account = T::decode(&mut TrailingZeroInput(&encoded_seed)) + .expect("All byte sequences are valid `AccountIds`; qed"); + // If the `account` generated has less bytes than the `encoded_seed`, then we know that + // bytes were truncated, and we return `None`. + if encoded_seed.len() <= account.encoded_size() { + Some(account) + } else { + None + } } fn try_from_sub_account(x: &T) -> Option<(Self, S)> { @@ -1652,6 +1685,13 @@ mod tests { let _ = s.verify(&[0u8; 100][..], &Public::unchecked_from([0; 32])); } + #[derive(Encode, Decode, Default, PartialEq, Debug)] + struct U128Value(u128); + impl super::TypeId for U128Value { + const TYPE_ID: [u8; 4] = [0x0d, 0xf0, 0x0d, 0xf0]; + } + // f00df00d + #[derive(Encode, Decode, Default, PartialEq, Debug)] struct U32Value(u32); impl super::TypeId for U32Value { @@ -1669,9 +1709,19 @@ mod tests { type AccountId = u64; #[test] - fn into_account_should_work() { - let r: AccountId = U32Value::into_account(&U32Value(0xdeadbeef)); + fn into_account_truncating_should_work() { + let r: AccountId = U32Value::into_account_truncating(&U32Value(0xdeadbeef)); + assert_eq!(r, 0x_deadbeef_cafef00d); + } + + #[test] + fn try_into_account_should_work() { + let r: AccountId = U32Value::try_into_account(&U32Value(0xdeadbeef)).unwrap(); assert_eq!(r, 0x_deadbeef_cafef00d); + + // u128 is bigger than u64 would fit + let maybe: Option = U128Value::try_into_account(&U128Value(u128::MAX)); + assert!(maybe.is_none()); } #[test] @@ -1681,9 +1731,22 @@ mod tests { } #[test] - fn into_account_with_fill_should_work() { - let r: AccountId = U16Value::into_account(&U16Value(0xc0da)); + fn into_account_truncating_with_fill_should_work() { + let r: AccountId = U16Value::into_account_truncating(&U16Value(0xc0da)); + assert_eq!(r, 0x_0000_c0da_f00dcafe); + } + + #[test] + fn try_into_sub_account_should_work() { + let r: AccountId = U16Value::try_into_account(&U16Value(0xc0da)).unwrap(); assert_eq!(r, 0x_0000_c0da_f00dcafe); + + let maybe: Option = U16Value::try_into_sub_account( + &U16Value(0xc0da), + "a really large amount of additional encoded information which will certainly overflow the account id type ;)" + ); + + assert!(maybe.is_none()) } #[test] diff --git a/utils/frame/frame-utilities-cli/src/pallet_id.rs b/utils/frame/frame-utilities-cli/src/pallet_id.rs index c0a221d4bcd11..4ad82a01c2433 100644 --- a/utils/frame/frame-utilities-cli/src/pallet_id.rs +++ b/utils/frame/frame-utilities-cli/src/pallet_id.rs @@ -72,7 +72,7 @@ impl PalletIdCmd { "Cannot convert argument to palletid: argument should be 8-character string" })?; - let account_id: R::AccountId = PalletId(id_fixed_array).into_account(); + let account_id: R::AccountId = PalletId(id_fixed_array).into_account_truncating(); with_crypto_scheme!( self.crypto_scheme.scheme, From 19b44f087b30e7730cf037518ec921c336fcbb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 18 May 2022 00:45:56 +0200 Subject: [PATCH 0813/1472] generate_storage_alias: Rewrite as proc macro attribute (#11387) * generate_storage_alias: Rewrite as proc macro attribute This rewrites the `generate_storage_alias!` declarative macro as proc-macro attribute. While doing this the name is changed to `storage_alias`. The prefix can now also be the name of a pallet. This makes storage aliases work in migrations for all kind of chains and not just for the ones that use predefined prefixes. * Fix compilation and FMT * Moare fixes * :facepalm: * ...... * Rework the syntax and support instancing * FMT * Prefix variants with `Storage` * Make it compile * Fix where clause on rust stable --- frame/bags-list/src/list/tests.rs | 10 +- frame/bags-list/src/migrations.rs | 5 +- frame/contracts/src/migration.rs | 64 +- frame/elections-phragmen/src/migrations/v3.rs | 98 +-- frame/offences/src/migration.rs | 11 +- frame/staking/src/migrations.rs | 63 +- frame/support/procedural/src/lib.rs | 8 + frame/support/procedural/src/storage_alias.rs | 566 ++++++++++++++++++ frame/support/src/lib.rs | 232 +++---- .../support/src/storage/bounded_btree_map.rs | 15 +- .../support/src/storage/bounded_btree_set.rs | 15 +- frame/support/src/storage/bounded_vec.rs | 15 +- .../src/storage/generator/double_map.rs | 6 +- frame/support/src/storage/generator/map.rs | 3 +- frame/support/src/storage/generator/nmap.rs | 22 +- frame/support/src/storage/mod.rs | 19 +- frame/support/src/storage/types/nmap.rs | 8 +- frame/support/src/storage/weak_bounded_vec.rs | 13 +- frame/support/test/tests/pallet.rs | 15 + frame/support/test/tests/pallet_instance.rs | 13 + frame/system/src/migrations/mod.rs | 66 +- 21 files changed, 886 insertions(+), 381 deletions(-) create mode 100644 frame/support/procedural/src/storage_alias.rs diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index ff7dd2871c237..40a174b35a5d3 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -368,12 +368,10 @@ mod list { assert_eq!(crate::ListNodes::::count(), 4); // we do some wacky stuff here to get access to the counter, since it is (reasonably) // not exposed as mutable in any sense. - frame_support::generate_storage_alias!( - BagsList, - CounterForListNodes - => Value - ); - CounterForListNodes::mutate(|counter| *counter += 1); + #[frame_support::storage_alias] + type CounterForListNodes = + StorageValue, u32, frame_support::pallet_prelude::ValueQuery>; + CounterForListNodes::::mutate(|counter| *counter += 1); assert_eq!(crate::ListNodes::::count(), 5); assert_eq!(List::::sanity_check(), Err("iter_count != stored_count")); diff --git a/frame/bags-list/src/migrations.rs b/frame/bags-list/src/migrations.rs index 696733e8c7ba5..f8041327f10be 100644 --- a/frame/bags-list/src/migrations.rs +++ b/frame/bags-list/src/migrations.rs @@ -30,11 +30,12 @@ impl OnRuntimeUpgrade for CheckCounterPrefix { fn pre_upgrade() -> Result<(), &'static str> { use frame_support::ensure; // The old explicit storage item. - frame_support::generate_storage_alias!(BagsList, CounterForListNodes => Value); + #[frame_support::storage_alias] + type CounterForListNodes = StorageValue, u32>; // ensure that a value exists in the counter struct. ensure!( - crate::ListNodes::::count() == CounterForListNodes::get().unwrap(), + crate::ListNodes::::count() == CounterForListNodes::::get().unwrap(), "wrong list node counter" ); diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index fb99078451ef9..0832ebadac9c6 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -18,11 +18,8 @@ use crate::{BalanceOf, CodeHash, Config, Pallet, TrieId, Weight}; use codec::{Decode, Encode}; use frame_support::{ - codec, generate_storage_alias, - pallet_prelude::*, - storage::migration, - traits::{Get, PalletInfoAccess}, - Identity, Twox64Concat, + codec, pallet_prelude::*, storage::migration, storage_alias, traits::Get, Identity, + Twox64Concat, }; use sp_std::{marker::PhantomData, prelude::*}; @@ -117,15 +114,16 @@ mod v5 { trie_id: TrieId, } - generate_storage_alias!( - Contracts, - ContractInfoOf => Map<(Twox64Concat, T::AccountId), ContractInfo> - ); + #[storage_alias] + type ContractInfoOf = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + ContractInfo, + >; - generate_storage_alias!( - Contracts, - DeletionQueue => Value> - ); + #[storage_alias] + type DeletionQueue = StorageValue, Vec>; pub fn migrate() -> Weight { let mut weight: Weight = 0; @@ -142,7 +140,7 @@ mod v5 { } }); - DeletionQueue::translate(|old: Option>| { + DeletionQueue::::translate(|old: Option>| { weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); old.map(|old| old.into_iter().map(|o| DeletedContract { trie_id: o.trie_id }).collect()) }) @@ -202,20 +200,19 @@ mod v6 { type ContractInfo = RawContractInfo, BalanceOf>; - generate_storage_alias!( - Contracts, - ContractInfoOf => Map<(Twox64Concat, T::AccountId), ContractInfo> - ); + #[storage_alias] + type ContractInfoOf = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + ContractInfo, + >; - generate_storage_alias!( - Contracts, - CodeStorage => Map<(Identity, CodeHash), PrefabWasmModule> - ); + #[storage_alias] + type CodeStorage = StorageMap, Identity, CodeHash, PrefabWasmModule>; - generate_storage_alias!( - Contracts, - OwnerInfoOf => Map<(Identity, CodeHash), OwnerInfo> - ); + #[storage_alias] + type OwnerInfoOf = StorageMap, Identity, CodeHash, OwnerInfo>; pub fn migrate() -> Weight { let mut weight: Weight = 0; @@ -259,15 +256,12 @@ mod v7 { use super::*; pub fn migrate() -> Weight { - generate_storage_alias!( - Contracts, - AccountCounter => Value - ); - generate_storage_alias!( - Contracts, - Nonce => Value - ); - Nonce::set(AccountCounter::take()); + #[storage_alias] + type AccountCounter = StorageValue, u64, ValueQuery>; + #[storage_alias] + type Nonce = StorageValue, u64, ValueQuery>; + + Nonce::::set(AccountCounter::::take()); T::DbWeight::get().reads_writes(1, 2) } } diff --git a/frame/elections-phragmen/src/migrations/v3.rs b/frame/elections-phragmen/src/migrations/v3.rs index c6a7ce7e7ca1b..b1cdd4be98541 100644 --- a/frame/elections-phragmen/src/migrations/v3.rs +++ b/frame/elections-phragmen/src/migrations/v3.rs @@ -17,12 +17,10 @@ //! Migrations to version [`3.0.0`], as denoted by the changelog. +use crate::{Config, Pallet}; use codec::{Decode, Encode, FullCodec}; use frame_support::{ - pallet_prelude::ValueQuery, - traits::{PalletInfoAccess, StorageVersion}, - weights::Weight, - RuntimeDebug, Twox64Concat, + pallet_prelude::ValueQuery, traits::StorageVersion, weights::Weight, RuntimeDebug, Twox64Concat, }; use sp_std::prelude::*; @@ -42,9 +40,6 @@ struct Voter { /// Trait to implement to give information about types used for migration pub trait V2ToV3 { - /// The elections-phragmen pallet. - type Pallet: 'static + PalletInfoAccess; - /// System config account id type AccountId: 'static + FullCodec; @@ -52,30 +47,31 @@ pub trait V2ToV3 { type Balance: 'static + FullCodec + Copy; } -frame_support::generate_storage_alias!( - PhragmenElection, Candidates => Value< - Vec<(T::AccountId, T::Balance)>, - ValueQuery - > -); -frame_support::generate_storage_alias!( - PhragmenElection, Members => Value< - Vec>, - ValueQuery - > -); -frame_support::generate_storage_alias!( - PhragmenElection, RunnersUp => Value< - Vec>, - ValueQuery - > -); -frame_support::generate_storage_alias!( - PhragmenElection, Voting => Map< - (Twox64Concat, T::AccountId), - Voter - > -); +#[frame_support::storage_alias] +type Candidates = + StorageValue, Vec<(::AccountId, ::Balance)>, ValueQuery>; + +#[frame_support::storage_alias] +type Members = StorageValue< + Pallet, + Vec::AccountId, ::Balance>>, + ValueQuery, +>; + +#[frame_support::storage_alias] +type RunnersUp = StorageValue< + Pallet, + Vec::AccountId, ::Balance>>, + ValueQuery, +>; + +#[frame_support::storage_alias] +type Voting = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + Voter<::AccountId, ::Balance>, +>; /// Apply all of the migrations from 2 to 3. /// @@ -86,8 +82,11 @@ frame_support::generate_storage_alias!( /// /// Be aware that this migration is intended to be used only for the mentioned versions. Use /// with care and run at your own risk. -pub fn apply(old_voter_bond: T::Balance, old_candidacy_bond: T::Balance) -> Weight { - let storage_version = StorageVersion::get::(); +pub fn apply( + old_voter_bond: V::Balance, + old_candidacy_bond: V::Balance, +) -> Weight { + let storage_version = StorageVersion::get::>(); log::info!( target: "runtime::elections-phragmen", "Running migration for elections-phragmen with storage version {:?}", @@ -95,12 +94,12 @@ pub fn apply(old_voter_bond: T::Balance, old_candidacy_bond: T::Balan ); if storage_version <= 2 { - migrate_voters_to_recorded_deposit::(old_voter_bond); - migrate_candidates_to_recorded_deposit::(old_candidacy_bond); - migrate_runners_up_to_recorded_deposit::(old_candidacy_bond); - migrate_members_to_recorded_deposit::(old_candidacy_bond); + migrate_voters_to_recorded_deposit::(old_voter_bond); + migrate_candidates_to_recorded_deposit::(old_candidacy_bond); + migrate_runners_up_to_recorded_deposit::(old_candidacy_bond); + migrate_members_to_recorded_deposit::(old_candidacy_bond); - StorageVersion::new(3).put::(); + StorageVersion::new(3).put::>(); Weight::max_value() } else { @@ -114,21 +113,21 @@ pub fn apply(old_voter_bond: T::Balance, old_candidacy_bond: T::Balan } /// Migrate from the old legacy voting bond (fixed) to the new one (per-vote dynamic). -pub fn migrate_voters_to_recorded_deposit(old_deposit: T::Balance) { - >::translate::<(T::Balance, Vec), _>(|_who, (stake, votes)| { +pub fn migrate_voters_to_recorded_deposit(old_deposit: V::Balance) { + >::translate::<(V::Balance, Vec), _>(|_who, (stake, votes)| { Some(Voter { votes, stake, deposit: old_deposit }) }); log::info!( target: "runtime::elections-phragmen", "migrated {} voter accounts.", - >::iter().count(), + >::iter().count(), ); } /// Migrate all candidates to recorded deposit. -pub fn migrate_candidates_to_recorded_deposit(old_deposit: T::Balance) { - let _ = >::translate::, _>(|maybe_old_candidates| { +pub fn migrate_candidates_to_recorded_deposit(old_deposit: V::Balance) { + let _ = >::translate::, _>(|maybe_old_candidates| { maybe_old_candidates.map(|old_candidates| { log::info!( target: "runtime::elections-phragmen", @@ -141,8 +140,8 @@ pub fn migrate_candidates_to_recorded_deposit(old_deposit: T::Balance } /// Migrate all members to recorded deposit. -pub fn migrate_members_to_recorded_deposit(old_deposit: T::Balance) { - let _ = >::translate::, _>(|maybe_old_members| { +pub fn migrate_members_to_recorded_deposit(old_deposit: V::Balance) { + let _ = >::translate::, _>(|maybe_old_members| { maybe_old_members.map(|old_members| { log::info!( target: "runtime::elections-phragmen", @@ -158,9 +157,9 @@ pub fn migrate_members_to_recorded_deposit(old_deposit: T::Balance) { } /// Migrate all runners-up to recorded deposit. -pub fn migrate_runners_up_to_recorded_deposit(old_deposit: T::Balance) { - let _ = - >::translate::, _>(|maybe_old_runners_up| { +pub fn migrate_runners_up_to_recorded_deposit(old_deposit: V::Balance) { + let _ = >::translate::, _>( + |maybe_old_runners_up| { maybe_old_runners_up.map(|old_runners_up| { log::info!( target: "runtime::elections-phragmen", @@ -172,5 +171,6 @@ pub fn migrate_runners_up_to_recorded_deposit(old_deposit: T::Balance .map(|(who, stake)| SeatHolder { who, stake, deposit: old_deposit }) .collect::>() }) - }); + }, + ); } diff --git a/frame/offences/src/migration.rs b/frame/offences/src/migration.rs index 0d6c98b564cb1..e8fab1c0babc7 100644 --- a/frame/offences/src/migration.rs +++ b/frame/offences/src/migration.rs @@ -16,9 +16,7 @@ // limitations under the License. use super::{Config, OffenceDetails, Perbill, SessionIndex}; -use frame_support::{ - generate_storage_alias, pallet_prelude::ValueQuery, traits::Get, weights::Weight, -}; +use frame_support::{pallet_prelude::ValueQuery, storage_alias, traits::Get, weights::Weight}; use sp_staking::offence::{DisableStrategy, OnOffenceHandler}; use sp_std::vec::Vec; @@ -31,10 +29,9 @@ type DeferredOffenceOf = ( // Deferred reports that have been rejected by the offence handler and need to be submitted // at a later time. -generate_storage_alias!( - Offences, - DeferredOffences => Value>, ValueQuery> -); +#[storage_alias] +type DeferredOffences = + StorageValue, Vec>, ValueQuery>; pub fn remove_deferred_storage() -> Weight { let mut weight = T::DbWeight::get().reads_writes(1, 1); diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 96c905f4e5942..14846da8a5d54 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -139,18 +139,20 @@ pub mod v8 { pub mod v7 { use super::*; - use frame_support::generate_storage_alias; + use frame_support::storage_alias; - generate_storage_alias!(Staking, CounterForValidators => Value); - generate_storage_alias!(Staking, CounterForNominators => Value); + #[storage_alias] + type CounterForValidators = StorageValue, u32>; + #[storage_alias] + type CounterForNominators = StorageValue, u32>; pub fn pre_migrate() -> Result<(), &'static str> { assert!( - CounterForValidators::get().unwrap().is_zero(), + CounterForValidators::::get().unwrap().is_zero(), "CounterForValidators already set." ); assert!( - CounterForNominators::get().unwrap().is_zero(), + CounterForNominators::::get().unwrap().is_zero(), "CounterForNominators already set." ); assert!(Validators::::count().is_zero(), "Validators already set."); @@ -164,8 +166,8 @@ pub mod v7 { let validator_count = Validators::::iter().count() as u32; let nominator_count = Nominators::::iter().count() as u32; - CounterForValidators::put(validator_count); - CounterForNominators::put(nominator_count); + CounterForValidators::::put(validator_count); + CounterForNominators::::put(nominator_count); StorageVersion::::put(Releases::V7_0_0); log!(info, "Completed staking migration to Releases::V7_0_0"); @@ -176,26 +178,35 @@ pub mod v7 { pub mod v6 { use super::*; - use frame_support::{generate_storage_alias, traits::Get, weights::Weight}; + use frame_support::{storage_alias, traits::Get, weights::Weight}; // NOTE: value type doesn't matter, we just set it to () here. - generate_storage_alias!(Staking, SnapshotValidators => Value<()>); - generate_storage_alias!(Staking, SnapshotNominators => Value<()>); - generate_storage_alias!(Staking, QueuedElected => Value<()>); - generate_storage_alias!(Staking, QueuedScore => Value<()>); - generate_storage_alias!(Staking, EraElectionStatus => Value<()>); - generate_storage_alias!(Staking, IsCurrentSessionFinal => Value<()>); + #[storage_alias] + type SnapshotValidators = StorageValue, ()>; + #[storage_alias] + type SnapshotNominators = StorageValue, ()>; + #[storage_alias] + type QueuedElected = StorageValue, ()>; + #[storage_alias] + type QueuedScore = StorageValue, ()>; + #[storage_alias] + type EraElectionStatus = StorageValue, ()>; + #[storage_alias] + type IsCurrentSessionFinal = StorageValue, ()>; /// check to execute prior to migration. pub fn pre_migrate() -> Result<(), &'static str> { // these may or may not exist. - log!(info, "SnapshotValidators.exits()? {:?}", SnapshotValidators::exists()); - log!(info, "SnapshotNominators.exits()? {:?}", SnapshotNominators::exists()); - log!(info, "QueuedElected.exits()? {:?}", QueuedElected::exists()); - log!(info, "QueuedScore.exits()? {:?}", QueuedScore::exists()); + log!(info, "SnapshotValidators.exits()? {:?}", SnapshotValidators::::exists()); + log!(info, "SnapshotNominators.exits()? {:?}", SnapshotNominators::::exists()); + log!(info, "QueuedElected.exits()? {:?}", QueuedElected::::exists()); + log!(info, "QueuedScore.exits()? {:?}", QueuedScore::::exists()); // these must exist. - assert!(IsCurrentSessionFinal::exists(), "IsCurrentSessionFinal storage item not found!"); - assert!(EraElectionStatus::exists(), "EraElectionStatus storage item not found!"); + assert!( + IsCurrentSessionFinal::::exists(), + "IsCurrentSessionFinal storage item not found!" + ); + assert!(EraElectionStatus::::exists(), "EraElectionStatus storage item not found!"); Ok(()) } @@ -203,12 +214,12 @@ pub mod v6 { pub fn migrate() -> Weight { log!(info, "Migrating staking to Releases::V6_0_0"); - SnapshotValidators::kill(); - SnapshotNominators::kill(); - QueuedElected::kill(); - QueuedScore::kill(); - EraElectionStatus::kill(); - IsCurrentSessionFinal::kill(); + SnapshotValidators::::kill(); + SnapshotNominators::::kill(); + QueuedElected::::kill(); + QueuedScore::::kill(); + EraElectionStatus::::kill(); + IsCurrentSessionFinal::::kill(); StorageVersion::::put(Releases::V6_0_0); log!(info, "Done."); diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 92564e94493c1..f8aaa5fe37749 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -31,6 +31,7 @@ mod pallet; mod pallet_error; mod partial_eq_no_bound; mod storage; +mod storage_alias; mod transactional; mod tt_macro; @@ -575,3 +576,10 @@ pub fn derive_pallet_error(input: TokenStream) -> TokenStream { pub fn __create_tt_macro(input: TokenStream) -> TokenStream { tt_macro::create_tt_return_macro(input) } + +#[proc_macro_attribute] +pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { + storage_alias::storage_alias(input.into()) + .unwrap_or_else(|r| r.into_compile_error()) + .into() +} diff --git a/frame/support/procedural/src/storage_alias.rs b/frame/support/procedural/src/storage_alias.rs new file mode 100644 index 0000000000000..adec995016653 --- /dev/null +++ b/frame/support/procedural/src/storage_alias.rs @@ -0,0 +1,566 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of the `storage_alias` attribute macro. + +use frame_support_procedural_tools::generate_crate_access_2018; +use proc_macro2::{Span, TokenStream}; +use quote::{quote, ToTokens}; +use syn::{ + ext::IdentExt, + parenthesized, + parse::{Parse, ParseStream}, + punctuated::Punctuated, + token, Attribute, Error, Ident, Result, Token, Type, TypeParam, Visibility, WhereClause, +}; + +/// Represents a path that only consists of [`Ident`] separated by `::`. +struct SimplePath { + leading_colon: Option, + segments: Punctuated, +} + +impl SimplePath { + /// Returns the [`Ident`] of this path. + /// + /// It only returns `Some(_)` if there is exactly one element and no leading colon. + fn get_ident(&self) -> Option<&Ident> { + if self.segments.len() != 1 || self.leading_colon.is_some() { + None + } else { + self.segments.first() + } + } +} + +impl Parse for SimplePath { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + leading_colon: if input.peek(Token![::]) { Some(input.parse()?) } else { None }, + segments: Punctuated::parse_separated_nonempty_with(input, |p| Ident::parse_any(p))?, + }) + } +} + +impl ToTokens for SimplePath { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.leading_colon.to_tokens(tokens); + self.segments.to_tokens(tokens); + } +} + +/// Represents generics which only support [`Ident`] separated by commas as you would pass it to a +/// type. +struct TypeGenerics { + lt_token: Token![<], + params: Punctuated, + gt_token: Token![>], +} + +impl TypeGenerics { + /// Returns the generics for types declarations etc. + fn iter(&self) -> impl Iterator { + self.params.iter() + } +} + +impl Parse for TypeGenerics { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + lt_token: input.parse()?, + params: Punctuated::parse_separated_nonempty(input)?, + gt_token: input.parse()?, + }) + } +} + +impl ToTokens for TypeGenerics { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.lt_token.to_tokens(tokens); + self.params.to_tokens(tokens); + self.gt_token.to_tokens(tokens); + } +} + +/// Represents generics which only support [`TypeParam`] separated by commas. +struct SimpleGenerics { + lt_token: Token![<], + params: Punctuated, + gt_token: Token![>], +} + +impl SimpleGenerics { + /// Returns the generics for types declarations etc. + fn type_generics(&self) -> impl Iterator { + self.params.iter().map(|p| &p.ident) + } + + /// Returns the generics for the `impl` block. + fn impl_generics(&self) -> impl Iterator { + self.params.iter() + } +} + +impl Parse for SimpleGenerics { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + lt_token: input.parse()?, + params: Punctuated::parse_separated_nonempty(input)?, + gt_token: input.parse()?, + }) + } +} + +impl ToTokens for SimpleGenerics { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.lt_token.to_tokens(tokens); + self.params.to_tokens(tokens); + self.gt_token.to_tokens(tokens); + } +} + +mod storage_types { + syn::custom_keyword!(StorageValue); + syn::custom_keyword!(StorageMap); + syn::custom_keyword!(StorageDoubleMap); + syn::custom_keyword!(StorageNMap); +} + +/// The supported storage types +enum StorageType { + Value { + _kw: storage_types::StorageValue, + _lt_token: Token![<], + prefix: SimplePath, + prefix_generics: Option, + _value_comma: Token![,], + value_ty: Type, + query_type: Option<(Token![,], Type)>, + _trailing_comma: Option, + _gt_token: Token![>], + }, + Map { + _kw: storage_types::StorageMap, + _lt_token: Token![<], + prefix: SimplePath, + prefix_generics: Option, + _hasher_comma: Token![,], + hasher_ty: Type, + _key_comma: Token![,], + key_ty: Type, + _value_comma: Token![,], + value_ty: Type, + query_type: Option<(Token![,], Type)>, + _trailing_comma: Option, + _gt_token: Token![>], + }, + DoubleMap { + _kw: storage_types::StorageDoubleMap, + _lt_token: Token![<], + prefix: SimplePath, + prefix_generics: Option, + _hasher1_comma: Token![,], + hasher1_ty: Type, + _key1_comma: Token![,], + key1_ty: Type, + _hasher2_comma: Token![,], + hasher2_ty: Type, + _key2_comma: Token![,], + key2_ty: Type, + _value_comma: Token![,], + value_ty: Type, + query_type: Option<(Token![,], Type)>, + _trailing_comma: Option, + _gt_token: Token![>], + }, + NMap { + _kw: storage_types::StorageNMap, + _lt_token: Token![<], + prefix: SimplePath, + prefix_generics: Option, + _paren_comma: Token![,], + _paren_token: token::Paren, + key_types: Punctuated, + _value_comma: Token![,], + value_ty: Type, + query_type: Option<(Token![,], Type)>, + _trailing_comma: Option, + _gt_token: Token![>], + }, +} + +impl StorageType { + /// Generate the actual type declaration. + fn generate_type_declaration( + &self, + crate_: &Ident, + storage_instance: &StorageInstance, + storage_name: &Ident, + storage_generics: Option<&SimpleGenerics>, + visibility: &Visibility, + attributes: &[Attribute], + ) -> TokenStream { + let storage_instance = &storage_instance.name; + let attributes = attributes.iter(); + let storage_generics = storage_generics.map(|g| { + let generics = g.type_generics(); + + quote!( < #( #generics ),* > ) + }); + + match self { + Self::Value { value_ty, query_type, prefix_generics, .. } => { + let query_type = query_type.as_ref().map(|(c, t)| quote!(#c #t)); + + quote! { + #( #attributes )* + #visibility type #storage_name #storage_generics = #crate_::storage::types::StorageValue< + #storage_instance #prefix_generics, + #value_ty + #query_type + >; + } + }, + Self::Map { value_ty, query_type, hasher_ty, key_ty, prefix_generics, .. } => { + let query_type = query_type.as_ref().map(|(c, t)| quote!(#c #t)); + + quote! { + #( #attributes )* + #visibility type #storage_name #storage_generics = #crate_::storage::types::StorageMap< + #storage_instance #prefix_generics, + #hasher_ty, + #key_ty, + #value_ty + #query_type + >; + } + }, + Self::DoubleMap { + value_ty, + query_type, + hasher1_ty, + key1_ty, + hasher2_ty, + key2_ty, + prefix_generics, + .. + } => { + let query_type = query_type.as_ref().map(|(c, t)| quote!(#c #t)); + + quote! { + #( #attributes )* + #visibility type #storage_name #storage_generics = #crate_::storage::types::StorageDoubleMap< + #storage_instance #prefix_generics, + #hasher1_ty, + #key1_ty, + #hasher2_ty, + #key2_ty, + #value_ty + #query_type + >; + } + }, + Self::NMap { value_ty, query_type, key_types, prefix_generics, .. } => { + let query_type = query_type.as_ref().map(|(c, t)| quote!(#c #t)); + let key_types = key_types.iter(); + + quote! { + #( #attributes )* + #visibility type #storage_name #storage_generics = #crate_::storage::types::StorageNMap< + #storage_instance #prefix_generics, + ( #( #key_types ),* ), + #value_ty + #query_type + >; + } + }, + } + } + + /// The prefix for this storage type. + fn prefix(&self) -> &SimplePath { + match self { + Self::Value { prefix, .. } | + Self::Map { prefix, .. } | + Self::NMap { prefix, .. } | + Self::DoubleMap { prefix, .. } => prefix, + } + } + + /// The prefix generics for this storage type. + fn prefix_generics(&self) -> Option<&TypeGenerics> { + match self { + Self::Value { prefix_generics, .. } | + Self::Map { prefix_generics, .. } | + Self::NMap { prefix_generics, .. } | + Self::DoubleMap { prefix_generics, .. } => prefix_generics.as_ref(), + } + } +} + +impl Parse for StorageType { + fn parse(input: ParseStream<'_>) -> Result { + let lookahead = input.lookahead1(); + + let parse_query_type = |input: ParseStream<'_>| -> Result> { + if input.peek(Token![,]) && !input.peek2(Token![>]) { + Ok(Some((input.parse()?, input.parse()?))) + } else { + Ok(None) + } + }; + + let parse_pallet_generics = |input: ParseStream<'_>| -> Result> { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![<]) { + Ok(Some(input.parse()?)) + } else if lookahead.peek(Token![,]) { + Ok(None) + } else { + Err(lookahead.error()) + } + }; + + if lookahead.peek(storage_types::StorageValue) { + Ok(Self::Value { + _kw: input.parse()?, + _lt_token: input.parse()?, + prefix: input.parse()?, + prefix_generics: parse_pallet_generics(input)?, + _value_comma: input.parse()?, + value_ty: input.parse()?, + query_type: parse_query_type(input)?, + _trailing_comma: input.peek(Token![,]).then(|| input.parse()).transpose()?, + _gt_token: input.parse()?, + }) + } else if lookahead.peek(storage_types::StorageMap) { + Ok(Self::Map { + _kw: input.parse()?, + _lt_token: input.parse()?, + prefix: input.parse()?, + prefix_generics: parse_pallet_generics(input)?, + _hasher_comma: input.parse()?, + hasher_ty: input.parse()?, + _key_comma: input.parse()?, + key_ty: input.parse()?, + _value_comma: input.parse()?, + value_ty: input.parse()?, + query_type: parse_query_type(input)?, + _trailing_comma: input.peek(Token![,]).then(|| input.parse()).transpose()?, + _gt_token: input.parse()?, + }) + } else if lookahead.peek(storage_types::StorageDoubleMap) { + Ok(Self::DoubleMap { + _kw: input.parse()?, + _lt_token: input.parse()?, + prefix: input.parse()?, + prefix_generics: parse_pallet_generics(input)?, + _hasher1_comma: input.parse()?, + hasher1_ty: input.parse()?, + _key1_comma: input.parse()?, + key1_ty: input.parse()?, + _hasher2_comma: input.parse()?, + hasher2_ty: input.parse()?, + _key2_comma: input.parse()?, + key2_ty: input.parse()?, + _value_comma: input.parse()?, + value_ty: input.parse()?, + query_type: parse_query_type(input)?, + _trailing_comma: input.peek(Token![,]).then(|| input.parse()).transpose()?, + _gt_token: input.parse()?, + }) + } else if lookahead.peek(storage_types::StorageNMap) { + let content; + Ok(Self::NMap { + _kw: input.parse()?, + _lt_token: input.parse()?, + prefix: input.parse()?, + prefix_generics: parse_pallet_generics(input)?, + _paren_comma: input.parse()?, + _paren_token: parenthesized!(content in input), + key_types: Punctuated::parse_terminated(&content)?, + _value_comma: input.parse()?, + value_ty: input.parse()?, + query_type: parse_query_type(input)?, + _trailing_comma: input.peek(Token![,]).then(|| input.parse()).transpose()?, + _gt_token: input.parse()?, + }) + } else { + Err(lookahead.error()) + } + } +} + +/// The input expected by this macro. +struct Input { + attributes: Vec, + visibility: Visibility, + _type: Token![type], + storage_name: Ident, + storage_generics: Option, + where_clause: Option, + _equal: Token![=], + storage_type: StorageType, + _semicolon: Token![;], +} + +impl Parse for Input { + fn parse(input: ParseStream<'_>) -> Result { + let attributes = input.call(Attribute::parse_outer)?; + let visibility = input.parse()?; + let _type = input.parse()?; + let storage_name = input.parse()?; + + let lookahead = input.lookahead1(); + let storage_generics = if lookahead.peek(Token![<]) { + Some(input.parse()?) + } else if lookahead.peek(Token![=]) { + None + } else { + return Err(lookahead.error()) + }; + + let lookahead = input.lookahead1(); + let where_clause = if lookahead.peek(Token![where]) { + Some(input.parse()?) + } else if lookahead.peek(Token![=]) { + None + } else { + return Err(lookahead.error()) + }; + + let _equal = input.parse()?; + + let storage_type = input.parse()?; + + let _semicolon = input.parse()?; + + Ok(Self { + attributes, + visibility, + _type, + storage_name, + storage_generics, + _equal, + storage_type, + where_clause, + _semicolon, + }) + } +} + +/// Implementation of the `storage_alias` attribute macro. +pub fn storage_alias(input: TokenStream) -> Result { + let input = syn::parse2::(input)?; + let crate_ = generate_crate_access_2018("frame-support")?; + + let storage_instance = generate_storage_instance( + &crate_, + &input.storage_name, + input.storage_generics.as_ref(), + input.where_clause.as_ref(), + input.storage_type.prefix(), + input.storage_type.prefix_generics(), + &input.visibility, + )?; + + let definition = input.storage_type.generate_type_declaration( + &crate_, + &storage_instance, + &input.storage_name, + input.storage_generics.as_ref(), + &input.visibility, + &input.attributes, + ); + + let storage_instance_code = storage_instance.code; + + Ok(quote! { + #storage_instance_code + + #definition + }) +} + +/// The storage instance to use for the storage alias. +struct StorageInstance { + name: Ident, + code: TokenStream, +} + +/// Generate the [`StorageInstance`] for the storage alias. +fn generate_storage_instance( + crate_: &Ident, + storage_name: &Ident, + storage_generics: Option<&SimpleGenerics>, + storage_where_clause: Option<&WhereClause>, + prefix: &SimplePath, + prefix_generics: Option<&TypeGenerics>, + visibility: &Visibility, +) -> Result { + let (pallet_prefix, impl_generics, type_generics) = + if let Some((prefix_generics, storage_generics)) = + prefix_generics.and_then(|p| storage_generics.map(|s| (p, s))) + { + let type_generics = prefix_generics.iter(); + let type_generics2 = prefix_generics.iter(); + let impl_generics = storage_generics + .impl_generics() + .filter(|g| prefix_generics.params.iter().any(|pg| *pg == g.ident)); + + ( + quote! { + <#prefix < #( #type_generics2 ),* > as #crate_::traits::PalletInfoAccess>::name() + }, + quote!( #( #impl_generics ),* ), + quote!( #( #type_generics ),* ), + ) + } else if let Some(prefix) = prefix.get_ident() { + let prefix_str = prefix.to_string(); + + (quote!(#prefix_str), quote!(), quote!()) + } else { + return Err(Error::new_spanned( + prefix, + "If there are no generics, the prefix is only allowed to be an identifier.", + )) + }; + + let where_clause = storage_where_clause.map(|w| quote!(#w)).unwrap_or_default(); + + let name = Ident::new(&format!("{}_Storage_Instance", storage_name), Span::call_site()); + let storage_name_str = storage_name.to_string(); + + // Implement `StorageInstance` trait. + let code = quote! { + #visibility struct #name< #impl_generics >( + #crate_::sp_std::marker::PhantomData<(#type_generics)> + ) #where_clause; + + impl<#impl_generics> #crate_::traits::StorageInstance + for #name< #type_generics > #where_clause + { + fn pallet_prefix() -> &'static str { + #pallet_prefix + } + + const STORAGE_PREFIX: &'static str = #storage_name_str; + } + }; + + Ok(StorageInstance { name, code }) +} diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 33830257cdd82..d73a01187bfcc 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -166,178 +166,74 @@ macro_rules! bounded_btree_map { /// Useful for creating a *storage-like* struct for test and migrations. /// /// ``` -/// # use frame_support::generate_storage_alias; +/// # use frame_support::storage_alias; /// use frame_support::codec; /// use frame_support::Twox64Concat; /// // generate a storage value with type u32. -/// generate_storage_alias!(Prefix, StorageName => Value); +/// #[storage_alias] +/// type StorageName = StorageValue; /// /// // generate a double map from `(u32, u32)` (with hashers `Twox64Concat` for each key) /// // to `Vec` -/// generate_storage_alias!( -/// OtherPrefix, OtherStorageName => DoubleMap< -/// (Twox64Concat, u32), -/// (Twox64Concat, u32), -/// Vec -/// > -/// ); +/// #[storage_alias] +/// type OtherStorageName = StorageDoubleMap< +/// OtherPrefix, +/// Twox64Concat, +/// u32, +/// Twox64Concat, +/// u32, +/// Vec, +/// >; /// /// // optionally specify the query type /// use frame_support::pallet_prelude::{ValueQuery, OptionQuery}; -/// generate_storage_alias!(Prefix, ValueName => Value); -/// generate_storage_alias!( -/// Prefix, SomeStorageName => DoubleMap< -/// (Twox64Concat, u32), -/// (Twox64Concat, u32), -/// Vec, -/// ValueQuery -/// > -/// ); +/// #[storage_alias] +/// type ValueName = StorageValue; +/// #[storage_alias] +/// type SomeStorageName = StorageMap< +/// Prefix, +/// Twox64Concat, +/// u32, +/// Vec, +/// ValueQuery, +/// >; /// /// // generate a map from `Config::AccountId` (with hasher `Twox64Concat`) to `Vec` /// trait Config { type AccountId: codec::FullCodec; } -/// generate_storage_alias!( -/// Prefix, GenericStorage => Map<(Twox64Concat, T::AccountId), Vec> -/// ); +/// #[storage_alias] +/// type GenericStorage = StorageMap::AccountId, Vec>; +/// +/// // It also supports NMap +/// use frame_support::storage::types::Key as NMapKey; +/// +/// #[storage_alias] +/// type SomeNMap = StorageNMap, NMapKey), Vec>; +/// +/// // Using pallet name as prefix. +/// // +/// // When the first generic argument is taking generic arguments it is expected to be a pallet. +/// // The prefix will then be the pallet name as configured in the runtime through +/// // `construct_runtime!`. +/// +/// # struct Pallet(std::marker::PhantomData<(T, I)>); +/// # impl frame_support::traits::PalletInfoAccess for Pallet { +/// # fn index() -> usize { 0 } +/// # fn name() -> &'static str { "pallet" } +/// # fn module_name() -> &'static str { "module" } +/// # fn crate_version() -> frame_support::traits::CrateVersion { unimplemented!() } +/// # } +/// +/// #[storage_alias] +/// type SomeValue = StorageValue, u64>; +/// +/// // Pallet with instance +/// +/// #[storage_alias] +/// type SomeValue2 = StorageValue, u64>; +/// /// # fn main() {} /// ``` -#[macro_export] -macro_rules! generate_storage_alias { - // without generic for $name. - ($pallet:ident, $name:ident => Map<($hasher:ty, $key:ty), $value:ty $(, $querytype:ty)?>) => { - $crate::paste::paste! { - $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); - type $name = $crate::storage::types::StorageMap< - [<$name Instance>], - $hasher, - $key, - $value, - $( $querytype )? - >; - } - }; - ( - $pallet:ident, - $name:ident - => DoubleMap<($hasher1:ty, $key1:ty), ($hasher2:ty, $key2:ty), $value:ty $(, $querytype:ty)?> - ) => { - $crate::paste::paste! { - $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); - type $name = $crate::storage::types::StorageDoubleMap< - [<$name Instance>], - $hasher1, - $key1, - $hasher2, - $key2, - $value, - $( $querytype )? - >; - } - }; - ( - $pallet:ident, - $name:ident - => NMap, $value:ty $(, $querytype:ty)?> - ) => { - $crate::paste::paste! { - $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); - type $name = $crate::storage::types::StorageNMap< - [<$name Instance>], - ( - $( $crate::storage::types::Key<$hasher, $key>, )+ - ), - $value, - $( $querytype )? - >; - } - }; - ($pallet:ident, $name:ident => Value<$value:ty $(, $querytype:ty)?>) => { - $crate::paste::paste! { - $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); - type $name = $crate::storage::types::StorageValue< - [<$name Instance>], - $value, - $( $querytype )? - >; - } - }; - // with generic for $name. - ( - $pallet:ident, - $name:ident<$t:ident : $bounds:tt> - => Map<($hasher:ty, $key:ty), $value:ty $(, $querytype:ty)?> - ) => { - $crate::paste::paste! { - $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); - #[allow(type_alias_bounds)] - type $name<$t : $bounds> = $crate::storage::types::StorageMap< - [<$name Instance>], - $hasher, - $key, - $value, - $( $querytype )? - >; - } - }; - ( - $pallet:ident, - $name:ident<$t:ident : $bounds:tt> - => DoubleMap<($hasher1:ty, $key1:ty), ($hasher2:ty, $key2:ty), $value:ty $(, $querytype:ty)?> - ) => { - $crate::paste::paste! { - $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); - #[allow(type_alias_bounds)] - type $name<$t : $bounds> = $crate::storage::types::StorageDoubleMap< - [<$name Instance>], - $hasher1, - $key1, - $hasher2, - $key2, - $value, - $( $querytype )? - >; - } - }; - ( - $pallet:ident, - $name:ident<$t:ident : $bounds:tt> - => NMap<$(($hasher:ty, $key:ty),)+ $value:ty $(, $querytype:ty)?> - ) => { - $crate::paste::paste! { - $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); - #[allow(type_alias_bounds)] - type $name<$t : $bounds> = $crate::storage::types::StorageNMap< - [<$name Instance>], - ( - $( $crate::storage::types::Key<$hasher, $key>, )+ - ), - $value, - $( $querytype )? - >; - } - }; - ($pallet:ident, $name:ident<$t:ident : $bounds:tt> => Value<$value:ty $(, $querytype:ty)?>) => { - $crate::paste::paste! { - $crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name); - #[allow(type_alias_bounds)] - type $name<$t : $bounds> = $crate::storage::types::StorageValue< - [<$name Instance>], - $value, - $( $querytype )? - >; - } - }; - // helper used in all arms. - (@GENERATE_INSTANCE_STRUCT $pallet:ident, $name:ident) => { - $crate::paste::paste! { - struct [<$name Instance>]; - impl $crate::traits::StorageInstance for [<$name Instance>] { - fn pallet_prefix() -> &'static str { stringify!($pallet) } - const STORAGE_PREFIX: &'static str = stringify!($name); - } - } - }; -} +pub use frame_support_procedural::storage_alias; /// Create new implementations of the [`Get`](crate::traits::Get) trait. /// @@ -995,16 +891,28 @@ pub mod tests { } #[test] - fn generate_storage_alias_works() { + fn storage_alias_works() { new_test_ext().execute_with(|| { - generate_storage_alias!( + #[crate::storage_alias] + type GenericData2 = StorageMap< Test, - GenericData2 => Map<(Blake2_128Concat, T::BlockNumber), T::BlockNumber> - ); + Blake2_128Concat, + ::BlockNumber, + ::BlockNumber, + >; assert_eq!(Module::::generic_data2(5), None); GenericData2::::insert(5, 5); assert_eq!(Module::::generic_data2(5), Some(5)); + + /// Some random docs that ensure that docs are accepted + #[crate::storage_alias] + pub type GenericData = StorageMap< + Test2, + Blake2_128Concat, + ::BlockNumber, + ::BlockNumber, + >; }); } diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index 0d589994bcc2c..390330457b9b9 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -348,12 +348,15 @@ pub mod test { use frame_support::traits::ConstU32; use sp_io::TestExternalities; - crate::generate_storage_alias! { Prefix, Foo => Value>> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), BoundedBTreeMap>> } - crate::generate_storage_alias! { - Prefix, - FooDoubleMap => DoubleMap<(Twox128, u32), (Twox128, u32), BoundedBTreeMap>> - } + #[crate::storage_alias] + type Foo = StorageValue>>; + + #[crate::storage_alias] + type FooMap = StorageMap>>; + + #[crate::storage_alias] + type FooDoubleMap = + StorageDoubleMap>>; fn map_from_keys(keys: &[K]) -> BTreeMap where diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index f38952bf545d9..275bb07c6275c 100644 --- a/frame/support/src/storage/bounded_btree_set.rs +++ b/frame/support/src/storage/bounded_btree_set.rs @@ -322,12 +322,15 @@ pub mod test { use frame_support::traits::ConstU32; use sp_io::TestExternalities; - crate::generate_storage_alias! { Prefix, Foo => Value>> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), BoundedBTreeSet>> } - crate::generate_storage_alias! { - Prefix, - FooDoubleMap => DoubleMap<(Twox128, u32), (Twox128, u32), BoundedBTreeSet>> - } + #[crate::storage_alias] + type Foo = StorageValue>>; + + #[crate::storage_alias] + type FooMap = StorageMap>>; + + #[crate::storage_alias] + type FooDoubleMap = + StorageDoubleMap>>; fn set_from_keys(keys: &[T]) -> BTreeSet where diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index e99ec6850b9f4..d3f9bfdd21d3b 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -672,12 +672,15 @@ pub mod test { use crate::{bounded_vec, traits::ConstU32, Twox128}; use sp_io::TestExternalities; - crate::generate_storage_alias! { Prefix, Foo => Value>> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), BoundedVec>> } - crate::generate_storage_alias! { - Prefix, - FooDoubleMap => DoubleMap<(Twox128, u32), (Twox128, u32), BoundedVec>> - } + #[crate::storage_alias] + type Foo = StorageValue>>; + + #[crate::storage_alias] + type FooMap = StorageMap>>; + + #[crate::storage_alias] + type FooDoubleMap = + StorageDoubleMap>>; #[test] fn slide_works() { diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index 16fcaf940c62a..1c308bc351902 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -525,10 +525,8 @@ mod test_iterators { fn double_map_iter_from() { sp_io::TestExternalities::default().execute_with(|| { use crate::hash::Identity; - crate::generate_storage_alias!( - MyModule, - MyDoubleMap => DoubleMap<(Identity, u64), (Identity, u64), u64> - ); + #[crate::storage_alias] + type MyDoubleMap = StorageDoubleMap; MyDoubleMap::insert(1, 10, 100); MyDoubleMap::insert(1, 21, 201); diff --git a/frame/support/src/storage/generator/map.rs b/frame/support/src/storage/generator/map.rs index da48952bcba87..bd24e14e9e0d8 100644 --- a/frame/support/src/storage/generator/map.rs +++ b/frame/support/src/storage/generator/map.rs @@ -384,7 +384,8 @@ mod test_iterators { fn map_iter_from() { sp_io::TestExternalities::default().execute_with(|| { use crate::hash::Identity; - crate::generate_storage_alias!(MyModule, MyMap => Map<(Identity, u64), u64>); + #[crate::storage_alias] + type MyMap = StorageMap; MyMap::insert(1, 10); MyMap::insert(2, 20); diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index be085ca2d9db6..18c912cf294ef 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -475,10 +475,12 @@ mod test_iterators { fn n_map_iter_from() { sp_io::TestExternalities::default().execute_with(|| { use crate::{hash::Identity, storage::Key as NMapKey}; - crate::generate_storage_alias!( + #[crate::storage_alias] + type MyNMap = StorageNMap< MyModule, - MyNMap => NMap, u64> - ); + (NMapKey, NMapKey, NMapKey), + u64, + >; MyNMap::insert((1, 1, 1), 11); MyNMap::insert((1, 1, 2), 21); @@ -518,11 +520,15 @@ mod test_iterators { let key_hash = NMap::hashed_key_for((1, 2)); { - crate::generate_storage_alias!(Test, NMap => DoubleMap< - (crate::Blake2_128Concat, u16), - (crate::Twox64Concat, u32), - u64 - >); + #[crate::storage_alias] + type NMap = StorageDoubleMap< + Test, + crate::Blake2_128Concat, + u16, + crate::Twox64Concat, + u32, + u64, + >; let value = NMap::get(1, 2).unwrap(); assert_eq!(value, 50); diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 115f179d803a7..7135ead850b6d 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -1545,10 +1545,8 @@ mod test { fn prefix_iterator_pagination_works() { TestExternalities::default().execute_with(|| { use crate::{hash::Identity, storage::generator::map::StorageMap}; - crate::generate_storage_alias! { - MyModule, - MyStorageMap => Map<(Identity, u64), u64> - } + #[crate::storage_alias] + type MyStorageMap = StorageMap; MyStorageMap::insert(1, 10); MyStorageMap::insert(2, 20); @@ -1663,12 +1661,13 @@ mod test { }); } - crate::generate_storage_alias! { Prefix, Foo => Value>> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), BoundedVec>> } - crate::generate_storage_alias! { - Prefix, - FooDoubleMap => DoubleMap<(Twox128, u32), (Twox128, u32), BoundedVec>> - } + #[crate::storage_alias] + type Foo = StorageValue>>; + #[crate::storage_alias] + type FooMap = StorageMap>>; + #[crate::storage_alias] + type FooDoubleMap = + StorageDoubleMap>>; #[test] fn try_append_works() { diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 16dc30ea03903..5faeb5d8cac28 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -544,7 +544,7 @@ mod test { use crate::{ hash::{StorageHasher as _, *}, metadata::{StorageEntryModifier, StorageHasher}, - storage::types::{Key, ValueQuery}, + storage::types::{Key, Key as NMapKey, ValueQuery}, }; use sp_io::{hashing::twox_128, TestExternalities}; @@ -589,10 +589,8 @@ mod test { assert_eq!(AValueQueryWithAnOnEmpty::get((3,)), 10); { - crate::generate_storage_alias!(test, Foo => NMap< - Key<(Blake2_128Concat, u16)>, - u32 - >); + #[crate::storage_alias] + type Foo = StorageNMap), u32>; assert_eq!(Foo::contains_key((3,)), true); assert_eq!(Foo::get((3,)), Some(10)); diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 21cc487b49082..8d1d38374d8a7 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -321,12 +321,13 @@ pub mod test { use frame_support::traits::ConstU32; use sp_io::TestExternalities; - crate::generate_storage_alias! { Prefix, Foo => Value>> } - crate::generate_storage_alias! { Prefix, FooMap => Map<(Twox128, u32), WeakBoundedVec>> } - crate::generate_storage_alias! { - Prefix, - FooDoubleMap => DoubleMap<(Twox128, u32), (Twox128, u32), WeakBoundedVec>> - } + #[crate::storage_alias] + type Foo = StorageValue>>; + #[crate::storage_alias] + type FooMap = StorageMap>>; + #[crate::storage_alias] + type FooDoubleMap = + StorageDoubleMap>>; #[test] fn bound_returns_correct_value() { diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index ec97c1794c27b..792fd93299705 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -17,6 +17,7 @@ use frame_support::{ dispatch::{Parameter, UnfilteredDispatchable}, + pallet_prelude::ValueQuery, storage::unhashed, traits::{ ConstU32, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, @@ -1631,3 +1632,17 @@ fn assert_type_all_pallets_without_system_reversed_is_correct() { _a(t) } } + +#[test] +fn test_storage_alias() { + #[frame_support::storage_alias] + type Value + where + ::AccountId: From + SomeAssociation1, + = StorageValue, u32, ValueQuery>; + + TestExternalities::default().execute_with(|| { + pallet::Value::::put(10); + assert_eq!(10, Value::::get()); + }) +} diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 118794e2fa20a..29074843f4bbb 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -17,6 +17,7 @@ use frame_support::{ dispatch::UnfilteredDispatchable, + pallet_prelude::ValueQuery, storage::unhashed, traits::{ConstU32, GetCallName, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade}, weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, @@ -821,3 +822,15 @@ fn test_pallet_info_access() { assert_eq!(::index(), 3); assert_eq!(::index(), 4); } + +#[test] +fn test_storage_alias() { + #[frame_support::storage_alias] + type Value, I: 'static> = + StorageValue, u32, ValueQuery>; + + TestExternalities::default().execute_with(|| { + pallet::Value::::put(10); + assert_eq!(10, Value::::get()); + }) +} diff --git a/frame/system/src/migrations/mod.rs b/frame/system/src/migrations/mod.rs index 872cf389d246c..f02af7a316fe1 100644 --- a/frame/system/src/migrations/mod.rs +++ b/frame/system/src/migrations/mod.rs @@ -17,6 +17,7 @@ //! Migrate the reference counting state. +use crate::{Config, Pallet}; use codec::{Decode, Encode, FullCodec}; use frame_support::{ pallet_prelude::ValueQuery, traits::PalletInfoAccess, weights::Weight, Blake2_128Concat, @@ -52,43 +53,24 @@ pub trait V2ToV3 { type AccountData: 'static + FullCodec; } -// ### Warning -// -// The call below is only valid because the name System is enforced -// at runtime construction level for the system pallet. -frame_support::generate_storage_alias!( - System, UpgradedToU32RefCount => Value< - bool, - ValueQuery - > -); - -// ### Warning -// -// The call below is only valid because the name System is enforced -// at runtime construction level for the system pallet. -frame_support::generate_storage_alias!( - System, UpgradedToTripleRefCount => Value< - bool, - ValueQuery - > -); - -// ### Warning -// -// The call below is only valid because the name System is enforced -// at runtime construction level for the system pallet. -frame_support::generate_storage_alias!( - System, Account => Map< - (Blake2_128Concat, T::AccountId), - AccountInfo - > -); +#[frame_support::storage_alias] +type UpgradedToU32RefCount = StorageValue, bool, ValueQuery>; + +#[frame_support::storage_alias] +type UpgradedToTripleRefCount = StorageValue, bool, ValueQuery>; + +#[frame_support::storage_alias] +type Account = StorageMap< + Pallet, + Blake2_128Concat, + ::AccountId, + AccountInfo<::Index, ::AccountData>, +>; /// Migrate from unique `u8` reference counting to triple `u32` reference counting. -pub fn migrate_from_single_u8_to_triple_ref_count() -> Weight { +pub fn migrate_from_single_u8_to_triple_ref_count() -> Weight { let mut translated: usize = 0; - >::translate::<(T::Index, u8, T::AccountData), _>(|_key, (nonce, rc, data)| { + >::translate::<(V::Index, u8, V::AccountData), _>(|_key, (nonce, rc, data)| { translated += 1; Some(AccountInfo { nonce, consumers: rc as RefCount, providers: 1, sufficients: 0, data }) }); @@ -97,15 +79,15 @@ pub fn migrate_from_single_u8_to_triple_ref_count() -> Weight { "Applied migration from single u8 to triple reference counting to {:?} elements.", translated ); - ::put(true); - ::put(true); + >::put(true); + >::put(true); Weight::max_value() } /// Migrate from unique `u32` reference counting to triple `u32` reference counting. -pub fn migrate_from_single_to_triple_ref_count() -> Weight { +pub fn migrate_from_single_to_triple_ref_count() -> Weight { let mut translated: usize = 0; - >::translate::<(T::Index, RefCount, T::AccountData), _>( + >::translate::<(V::Index, RefCount, V::AccountData), _>( |_key, (nonce, consumers, data)| { translated += 1; Some(AccountInfo { nonce, consumers, providers: 1, sufficients: 0, data }) @@ -116,14 +98,14 @@ pub fn migrate_from_single_to_triple_ref_count() -> Weight { "Applied migration from single to triple reference counting to {:?} elements.", translated ); - ::put(true); + >::put(true); Weight::max_value() } /// Migrate from dual `u32` reference counting to triple `u32` reference counting. -pub fn migrate_from_dual_to_triple_ref_count() -> Weight { +pub fn migrate_from_dual_to_triple_ref_count() -> Weight { let mut translated: usize = 0; - >::translate::<(T::Index, RefCount, RefCount, T::AccountData), _>( + >::translate::<(V::Index, RefCount, RefCount, V::AccountData), _>( |_key, (nonce, consumers, providers, data)| { translated += 1; Some(AccountInfo { nonce, consumers, providers, sufficients: 0, data }) @@ -134,6 +116,6 @@ pub fn migrate_from_dual_to_triple_ref_count() -> Weight { "Applied migration from dual to triple reference counting to {:?} elements.", translated ); - ::put(true); + >::put(true); Weight::max_value() } From 1caa0e574154323a50980f05873e816984d4c701 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Wed, 18 May 2022 15:23:15 +0800 Subject: [PATCH 0814/1472] Prune some duplicated dependencies in the dep graph (#11433) Signed-off-by: koushiro --- Cargo.lock | 153 ++++---------------------- bin/node/bench/Cargo.toml | 2 +- bin/node/bench/src/tempdb.rs | 2 +- bin/node/bench/src/trie.rs | 4 +- client/authority-discovery/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 1 - client/network/sync/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/offchain/src/api/http.rs | 10 +- 11 files changed, 36 insertions(+), 146 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14196e4f85364..ff14da370db9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1069,12 +1069,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -[[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" @@ -1444,15 +1438,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ct-logs" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" -dependencies = [ - "sct 0.6.0", -] - [[package]] name = "ctor" version = "0.1.19" @@ -1594,14 +1579,12 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.16" +version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "convert_case", "proc-macro2", "quote", - "rustc_version 0.3.3", "syn", ] @@ -1919,16 +1902,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "env_logger" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" -dependencies = [ - "log", - "regex", -] - [[package]] name = "env_logger" version = "0.9.0" @@ -2544,8 +2517,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01fe9932a224b72b45336d96040aa86386d674a31d0af27d800ea7bc8ca97fe" dependencies = [ "futures-io", - "rustls 0.20.2", - "webpki 0.22.0", + "rustls", + "webpki", ] [[package]] @@ -2977,19 +2950,17 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.22.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" dependencies = [ - "ct-logs", - "futures-util", + "http", "hyper", "log", - "rustls 0.19.1", - "rustls-native-certs 0.5.0", + "rustls", + "rustls-native-certs", "tokio", - "tokio-rustls 0.22.0", - "webpki 0.21.4", + "tokio-rustls", ] [[package]] @@ -3190,11 +3161,11 @@ dependencies = [ "jsonrpsee-core", "jsonrpsee-types", "pin-project 1.0.10", - "rustls-native-certs 0.6.1", + "rustls-native-certs", "soketto", "thiserror", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls", "tokio-util 0.7.1", "tracing", "webpki-roots", @@ -7098,8 +7069,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ - "env_logger 0.8.4", - "log", "rand 0.8.4", ] @@ -7663,15 +7632,6 @@ dependencies = [ "semver 0.9.0", ] -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - [[package]] name = "rustc_version" version = "0.4.0" @@ -7695,19 +7655,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "rustls" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" -dependencies = [ - "base64", - "log", - "ring", - "sct 0.6.0", - "webpki 0.21.4", -] - [[package]] name = "rustls" version = "0.20.2" @@ -7716,20 +7663,8 @@ checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" dependencies = [ "log", "ring", - "sct 0.7.0", - "webpki 0.22.0", -] - -[[package]] -name = "rustls-native-certs" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" -dependencies = [ - "openssl-probe", - "rustls 0.19.1", - "schannel", - "security-framework", + "sct", + "webpki", ] [[package]] @@ -8474,7 +8409,6 @@ dependencies = [ "pin-project 1.0.10", "prost 0.10.3", "prost-build", - "quickcheck", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -9088,16 +9022,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "sct" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sct" version = "0.7.0" @@ -9183,7 +9107,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" dependencies = [ - "semver-parser 0.7.0", + "semver-parser", ] [[package]] @@ -9192,16 +9116,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0", -] - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser 0.10.2", + "semver-parser", ] [[package]] @@ -9219,15 +9134,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - [[package]] name = "serde" version = "1.0.136" @@ -10910,26 +10816,15 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-rustls" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" -dependencies = [ - "rustls 0.19.1", - "tokio", - "webpki 0.21.4", -] - [[package]] name = "tokio-rustls" version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" dependencies = [ - "rustls 0.20.2", + "rustls", "tokio", - "webpki 0.22.0", + "webpki", ] [[package]] @@ -11994,16 +11889,6 @@ dependencies = [ "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" @@ -12020,7 +11905,7 @@ version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" dependencies = [ - "webpki 0.22.0", + "webpki", ] [[package]] diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 5013383af1cea..90c325b8e5b32 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -19,7 +19,7 @@ sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } serde = "1.0.136" serde_json = "1.0.79" -derive_more = "0.99.16" +derive_more = { version = "0.99.17", default-features = false, features = ["display"] } kvdb = "0.11.0" kvdb-rocksdb = "0.15.1" sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } diff --git a/bin/node/bench/src/tempdb.rs b/bin/node/bench/src/tempdb.rs index 1e5f3dfbce148..22c5980fd6524 100644 --- a/bin/node/bench/src/tempdb.rs +++ b/bin/node/bench/src/tempdb.rs @@ -20,7 +20,7 @@ use kvdb::{DBTransaction, KeyValueDB}; use kvdb_rocksdb::{Database, DatabaseConfig}; use std::{io, path::PathBuf, sync::Arc}; -#[derive(Debug, Clone, Copy, derive_more::Display)] +#[derive(Clone, Copy, Debug)] pub enum DatabaseType { RocksDb, ParityDb, diff --git a/bin/node/bench/src/trie.rs b/bin/node/bench/src/trie.rs index 0539c9ce11462..d508dc712e1c3 100644 --- a/bin/node/bench/src/trie.rs +++ b/bin/node/bench/src/trie.rs @@ -155,7 +155,7 @@ impl core::BenchmarkDescription for TrieReadBenchmarkDescription { fn name(&self) -> Cow<'static, str> { format!( - "Trie read benchmark({} database ({} keys), db_type: {})", + "Trie read benchmark({:?} database ({} keys), db_type: {:?})", self.database_size, pretty_print(self.database_size.keys()), self.database_type, @@ -260,7 +260,7 @@ impl core::BenchmarkDescription for TrieWriteBenchmarkDescription { fn name(&self) -> Cow<'static, str> { format!( - "Trie write benchmark({} database ({} keys), db_type = {})", + "Trie write benchmark({:?} database ({} keys), db_type = {:?})", self.database_size, pretty_print(self.database_size.keys()), self.database_type, diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 96c07b5dae278..136c2606a384e 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -38,6 +38,6 @@ sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] -quickcheck = "1.0.3" +quickcheck = { version = "1.0.3", default-features = false } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index babbb0b91c8fb..e1472bcbda01a 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -36,7 +36,7 @@ sp-trie = { version = "6.0.0", path = "../../primitives/trie" } [dev-dependencies] kvdb-rocksdb = "0.15.1" -quickcheck = "1.0.3" +quickcheck = { version = "1.0.3", default-features = false } tempfile = "3" sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 7ba45f6ee9b87..641574db288d7 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -27,5 +27,5 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] async-std = "1.11.0" -quickcheck = "1.0.3" +quickcheck = { version = "1.0.3", default-features = false } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index f222c39673516..89a36bc483e6c 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -65,7 +65,6 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3" async-std = "1.11.0" -quickcheck = "1.0.3" rand = "0.7.2" tempfile = "3.1.0" sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index c557c9bf42b92..f11cc753203ef 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -42,7 +42,7 @@ sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/final sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [dev-dependencies] -quickcheck = "1.0.3" +quickcheck = { version = "1.0.3", default-features = false } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-test-primitives = { version = "2.0.0", path = "../../../primitives/test-primitives" } sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index d4ae0a2558b7f..8da2d4be3adde 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3.21" futures-timer = "3.0.2" hex = "0.4" hyper = { version = "0.14.16", features = ["stream", "http2"] } -hyper-rustls = "0.22.1" +hyper-rustls = { version = "0.23.0", features = ["http2"] } num_cpus = "1.13" once_cell = "1.8" parking_lot = "0.12.0" diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index f4fa7e0800b2d..4c97e5a47058d 100644 --- a/client/offchain/src/api/http.rs +++ b/client/offchain/src/api/http.rs @@ -32,7 +32,7 @@ use bytes::buf::{Buf, Reader}; use fnv::FnvHashMap; use futures::{channel::mpsc, future, prelude::*}; use hyper::{client, Body, Client as HyperClient}; -use hyper_rustls::HttpsConnector; +use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder}; use once_cell::sync::Lazy; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_core::offchain::{HttpError, HttpRequestId, HttpRequestStatus, Timestamp}; @@ -53,7 +53,13 @@ pub struct SharedClient(Arc Self { Self(Arc::new(Lazy::new(|| { - HyperClient::builder().build(HttpsConnector::with_native_roots()) + let connector = HttpsConnectorBuilder::new() + .with_native_roots() + .https_or_http() + .enable_http1() + .enable_http2() + .build(); + HyperClient::builder().build(connector) }))) } } From c00ed052e7cd72cfc4bc0e00e38722081b789ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 18 May 2022 09:40:53 +0200 Subject: [PATCH 0815/1472] contracts: Get rid of `#[pallet::without_storage_info]` (#11414) * Implement `MaxEncodeLen` for pallet-contracts storage * Remove redundant debug println * Move code len check to PrefabWasmModule::from_code --- bin/node/runtime/src/lib.rs | 2 ++ frame/contracts/src/benchmarking/mod.rs | 8 ++--- frame/contracts/src/lib.rs | 43 +++++++++++++++---------- frame/contracts/src/schedule.rs | 8 +---- frame/contracts/src/storage.rs | 29 +++++++++-------- frame/contracts/src/tests.rs | 2 ++ frame/contracts/src/wasm/code_cache.rs | 10 ++++-- frame/contracts/src/wasm/mod.rs | 31 ++++++++++++++---- frame/contracts/src/wasm/prepare.rs | 33 ++++++++++--------- 9 files changed, 99 insertions(+), 67 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 40316cee9b2b7..de6f8eeb9f1c0 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1118,6 +1118,8 @@ impl pallet_contracts::Config for Runtime { type Schedule = Schedule; type AddressGenerator = pallet_contracts::DefaultAddressGenerator; type ContractAccessWeight = pallet_contracts::DefaultContractAccessWeight; + type MaxCodeLen = ConstU32<{ 128 * 1024 }>; + type RelaxedMaxCodeLen = ConstU32<{ 256 * 1024 }>; } impl pallet_sudo::Config for Runtime { diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 194f97f8c878d..01e62e07e1ce0 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -231,7 +231,7 @@ benchmarks! { // first time after a new schedule was deployed: For every new schedule a contract needs // to re-run the instrumentation once. reinstrument { - let c in 0 .. T::Schedule::get().limits.code_len; + let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); Contracts::::store_code_raw(code, whitelisted_caller())?; let schedule = T::Schedule::get(); @@ -247,7 +247,7 @@ benchmarks! { // which is in the wasm module but not executed on `call`. // The results are supposed to be used as `call_with_code_kb(c) - call_with_code_kb(0)`. call_with_code_per_byte { - let c in 0 .. T::Schedule::get().limits.code_len; + let c in 0 .. T::MaxCodeLen::get(); let instance = Contract::::with_caller( whitelisted_caller(), WasmModule::sized(c, Location::Deploy), vec![], )?; @@ -271,7 +271,7 @@ benchmarks! { // We cannot let `c` grow to the maximum code size because the code is not allowed // to be larger than the maximum size **after instrumentation**. instantiate_with_code { - let c in 0 .. Perbill::from_percent(49).mul_ceil(T::Schedule::get().limits.code_len); + let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let s in 0 .. code::max_pages::() * 64 * 1024; let salt = vec![42u8; s as usize]; let value = T::Currency::minimum_balance(); @@ -360,7 +360,7 @@ benchmarks! { // We cannot let `c` grow to the maximum code size because the code is not allowed // to be larger than the maximum size **after instrumentation**. upload_code { - let c in 0 .. Perbill::from_percent(50).mul_ceil(T::Schedule::get().limits.code_len); + let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index ca639d7781ac2..ffac3e222bbce 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -114,8 +114,9 @@ use codec::{Encode, HasCompact}; use frame_support::{ dispatch::Dispatchable, ensure, - traits::{Contains, Currency, Get, Randomness, ReservableCurrency, Time}, + traits::{ConstU32, Contains, Currency, Get, Randomness, ReservableCurrency, Time}, weights::{DispatchClass, GetDispatchInfo, Pays, PostDispatchInfo, Weight}, + BoundedVec, }; use frame_system::{limits::BlockWeights, Pallet as System}; use pallet_contracts_primitives::{ @@ -129,9 +130,11 @@ use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup}; use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; type CodeHash = ::Hash; -type TrieId = Vec; +type TrieId = BoundedVec>; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type CodeVec = BoundedVec::MaxCodeLen>; +type RelaxedCodeVec = BoundedVec::RelaxedMaxCodeLen>; /// Used as a sentinel value when reading and writing contract memory. /// @@ -224,7 +227,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::config] @@ -356,6 +358,20 @@ pub mod pallet { /// The address generator used to generate the addresses of contracts. type AddressGenerator: AddressGenerator; + + /// The maximum length of a contract code in bytes. This limit applies to the instrumented + /// version of the code. Therefore `instantiate_with_code` can fail even when supplying + /// a wasm binary below this maximum size. + type MaxCodeLen: Get; + + /// The maximum length of a contract code after reinstrumentation. + /// + /// When uploading a new contract the size defined by [`Self::MaxCodeLen`] is used for both + /// the pristine **and** the instrumented version. When a existing contract needs to be + /// reinstrumented after a runtime upgrade we apply this bound. The reason is that if the + /// new instrumentation increases the size beyond the limit it would make that contract + /// inaccessible until rectified by another runtime upgrade. + type RelaxedMaxCodeLen: Get; } #[pallet::hooks] @@ -698,7 +714,7 @@ pub mod pallet { /// A mapping from an original code hash to the original code, untouched by instrumentation. #[pallet::storage] - pub(crate) type PristineCode = StorageMap<_, Identity, CodeHash, Vec>; + pub(crate) type PristineCode = StorageMap<_, Identity, CodeHash, CodeVec>; /// A mapping between an original code hash and instrumented wasm code, ready for execution. #[pallet::storage] @@ -746,7 +762,8 @@ pub mod pallet { /// Child trie deletion is a heavy operation depending on the amount of storage items /// stored in said trie. Therefore this operation is performed lazily in `on_initialize`. #[pallet::storage] - pub(crate) type DeletionQueue = StorageValue<_, Vec, ValueQuery>; + pub(crate) type DeletionQueue = + StorageValue<_, BoundedVec, ValueQuery>; } /// Return type of the private [`Pallet::internal_call`] function. @@ -864,8 +881,8 @@ where storage_deposit_limit: Option>, ) -> CodeUploadResult, BalanceOf> { let schedule = T::Schedule::get(); - let module = PrefabWasmModule::from_code(code, &schedule, origin) - .map_err(|_| >::CodeRejected)?; + let module = + PrefabWasmModule::from_code(code, &schedule, origin).map_err(|(err, _)| err)?; let deposit = module.open_deposit(); if let Some(storage_deposit_limit) = storage_deposit_limit { ensure!(storage_deposit_limit >= deposit, >::StorageDepositLimitExhausted); @@ -971,19 +988,11 @@ where let schedule = T::Schedule::get(); let (extra_deposit, executable) = match code { Code::Upload(Bytes(binary)) => { - ensure!( - binary.len() as u32 <= schedule.limits.code_len, - >::CodeTooLarge - ); let executable = PrefabWasmModule::from_code(binary, &schedule, origin.clone()) - .map_err(|msg| { + .map_err(|(err, msg)| { debug_message.as_mut().map(|buffer| buffer.extend(msg.as_bytes())); - >::CodeRejected + err })?; - ensure!( - executable.code_len() <= schedule.limits.code_len, - >::CodeTooLarge - ); // The open deposit will be charged during execution when the // uploaded module does not already exist. This deposit is not part of the // storage meter because it is not transfered to the contract but diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 9e9f213fabb76..907ce9e088648 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -33,7 +33,7 @@ use wasm_instrument::{gas_metering, parity_wasm::elements}; /// How many API calls are executed in a single batch. The reason for increasing the amount /// of API calls in batches (per benchmark component increase) is so that the linear regression /// has an easier time determining the contribution of that component. -pub const API_BENCHMARK_BATCH_SIZE: u32 = 100; +pub const API_BENCHMARK_BATCH_SIZE: u32 = 80; /// How many instructions are executed in a single batch. The reasoning is the same /// as for `API_BENCHMARK_BATCH_SIZE`. @@ -147,11 +147,6 @@ pub struct Limits { /// The maximum size of a storage value and event payload in bytes. pub payload_len: u32, - - /// The maximum length of a contract code in bytes. This limit applies to the instrumented - /// version of the code. Therefore `instantiate_with_code` can fail even when supplying - /// a wasm binary below this maximum size. - pub code_len: u32, } impl Limits { @@ -522,7 +517,6 @@ impl Default for Limits { subject_len: 32, call_depth: 32, payload_len: 16 * 1024, - code_len: 128 * 1024, } } } diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 2bdacc15cb11f..a9a78f12581d8 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -24,11 +24,10 @@ use crate::{ weights::WeightInfo, BalanceOf, CodeHash, Config, ContractInfoOf, DeletionQueue, Error, TrieId, SENTINEL, }; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::{DispatchError, DispatchResult}, storage::child::{self, ChildInfo, KillStorageResult}, - traits::Get, weights::Weight, }; use scale_info::TypeInfo; @@ -44,7 +43,7 @@ pub type ContractInfo = RawContractInfo, BalanceOf>; /// Information for managing an account and its sub trie abstraction. /// This is the required info to cache for an account. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct RawContractInfo { /// Unique ID for the subtree encoded as a bytes vector. pub trie_id: TrieId, @@ -67,7 +66,7 @@ fn child_trie_info(trie_id: &[u8]) -> ChildInfo { ChildInfo::new_default(trie_id) } -#[derive(Encode, Decode, TypeInfo)] +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct DeletedContract { pub(crate) trie_id: TrieId, } @@ -217,12 +216,8 @@ where /// /// You must make sure that the contract is also removed when queuing the trie for deletion. pub fn queue_trie_for_deletion(contract: &ContractInfo) -> DispatchResult { - if >::decode_len().unwrap_or(0) >= T::DeletionQueueDepth::get() as usize { - Err(Error::::DeletionQueueFull.into()) - } else { - >::append(DeletedContract { trie_id: contract.trie_id.clone() }); - Ok(()) - } + >::try_append(DeletedContract { trie_id: contract.trie_id.clone() }) + .map_err(|_| >::DeletionQueueFull.into()) } /// Calculates the weight that is necessary to remove one key from the trie and how many @@ -293,7 +288,11 @@ where /// Generates a unique trie id by returning `hash(account_id ++ nonce)`. pub fn generate_trie_id(account_id: &AccountIdOf, nonce: u64) -> TrieId { let buf: Vec<_> = account_id.as_ref().iter().chain(&nonce.to_le_bytes()).cloned().collect(); - T::Hashing::hash(&buf).as_ref().into() + T::Hashing::hash(&buf) + .as_ref() + .to_vec() + .try_into() + .expect("Runtime uses a reasonable hash size. Hence sizeof(T::Hash) <= 128; qed") } /// Returns the code hash of the contract specified by `account` ID. @@ -305,9 +304,11 @@ where /// Fill up the queue in order to exercise the limits during testing. #[cfg(test)] pub fn fill_queue_with_dummies() { - let queue: Vec<_> = (0..T::DeletionQueueDepth::get()) - .map(|_| DeletedContract { trie_id: vec![] }) + use frame_support::{traits::Get, BoundedVec}; + let queue: Vec = (0..T::DeletionQueueDepth::get()) + .map(|_| DeletedContract { trie_id: TrieId::default() }) .collect(); - >::put(queue); + let bounded: BoundedVec<_, _> = queue.try_into().unwrap(); + >::put(bounded); } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 407e1e999dde1..e52ce5ca0e156 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -288,6 +288,8 @@ impl Config for Test { type DepositPerItem = DepositPerItem; type AddressGenerator = DefaultAddressGenerator; type ContractAccessWeight = DefaultContractAccessWeight; + type MaxCodeLen = ConstU32<{ 128 * 1024 }>; + type RelaxedMaxCodeLen = ConstU32<{ 256 * 1024 }>; } pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index b194c283e90cd..10de436bfb155 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -163,7 +163,8 @@ pub fn load( where T::AccountId: UncheckedFrom + AsRef<[u8]>, { - let charged = gas_meter.charge(CodeToken::Load(schedule.limits.code_len))?; + let max_code_len = T::MaxCodeLen::get(); + let charged = gas_meter.charge(CodeToken::Load(max_code_len))?; let mut prefab_module = >::get(code_hash).ok_or(Error::::CodeNotFound)?; gas_meter.adjust_gas(charged, CodeToken::Load(prefab_module.code.len() as u32)); @@ -172,7 +173,7 @@ where if prefab_module.instruction_weights_version < schedule.instruction_weights.version { // The instruction weights have changed. // We need to re-instrument the code with the new instruction weights. - let charged = gas_meter.charge(CodeToken::Reinstrument(schedule.limits.code_len))?; + let charged = gas_meter.charge(CodeToken::Reinstrument(max_code_len))?; let code_size = reinstrument(&mut prefab_module, schedule)?; gas_meter.adjust_gas(charged, CodeToken::Reinstrument(code_size)); } @@ -190,7 +191,10 @@ pub fn reinstrument( let original_code = >::get(&prefab_module.code_hash).ok_or(Error::::CodeNotFound)?; let original_code_len = original_code.len(); - prefab_module.code = prepare::reinstrument_contract::(original_code, schedule)?; + prefab_module.code = prepare::reinstrument_contract::(&original_code, schedule) + .map_err(|_| >::CodeRejected)? + .try_into() + .map_err(|_| >::CodeTooLarge)?; prefab_module.instruction_weights_version = schedule.instruction_weights.version; >::insert(&prefab_module.code_hash, &*prefab_module); Ok(original_code_len as u32) diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index d710cad199f93..8764bf3690b82 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -31,10 +31,15 @@ use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, gas::GasMeter, wasm::env_def::FunctionImplProvider, - AccountIdOf, BalanceOf, CodeHash, CodeStorage, Config, Schedule, + AccountIdOf, BalanceOf, CodeHash, CodeStorage, CodeVec, Config, Error, RelaxedCodeVec, + Schedule, }; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::dispatch::{DispatchError, DispatchResult}; +use frame_support::{ + dispatch::{DispatchError, DispatchResult}, + ensure, + traits::Get, +}; use sp_core::crypto::UncheckedFrom; use sp_sandbox::{SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory}; use sp_std::prelude::*; @@ -50,7 +55,8 @@ pub use tests::MockExt; /// `instruction_weights_version` and `code` change when a contract with an outdated instrumentation /// is called. Therefore one must be careful when holding any in-memory representation of this /// type while calling into a contract as those fields can get out of date. -#[derive(Clone, Encode, Decode, scale_info::TypeInfo)] +#[derive(Clone, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen)] +#[codec(mel_bound())] #[scale_info(skip_type_params(T))] pub struct PrefabWasmModule { /// Version of the instruction weights with which the code was instrumented. @@ -63,14 +69,14 @@ pub struct PrefabWasmModule { #[codec(compact)] maximum: u32, /// Code instrumented with the latest schedule. - code: Vec, + code: RelaxedCodeVec, /// The uninstrumented, pristine version of the code. /// /// It is not stored because the pristine code has its own storage item. The value /// is only `Some` when this module was created from an `original_code` and `None` if /// it was loaded from storage. #[codec(skip)] - original_code: Option>, + original_code: Option>, /// The code hash of the stored code which is defined as the hash over the `original_code`. /// /// As the map key there is no need to store the hash in the value, too. It is set manually @@ -122,8 +128,19 @@ where original_code: Vec, schedule: &Schedule, owner: AccountIdOf, - ) -> Result { - prepare::prepare_contract(original_code, schedule, owner) + ) -> Result { + let module = prepare::prepare_contract( + original_code.try_into().map_err(|_| (>::CodeTooLarge.into(), ""))?, + schedule, + owner, + )?; + // When instrumenting a new code we apply a stricter limit than enforced by the + // `RelaxedCodeVec` in order to leave some headroom for reinstrumentation. + ensure!( + module.code.len() as u32 <= T::MaxCodeLen::get(), + (>::CodeTooLarge.into(), ""), + ); + Ok(module) } /// Store the code without instantiating it. diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 6e9babe1264ed..f6fff20de6b1a 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -23,10 +23,10 @@ use crate::{ chain_extension::ChainExtension, storage::meter::Diff, wasm::{env_def::ImportSatisfyCheck, OwnerInfo, PrefabWasmModule}, - AccountIdOf, Config, Schedule, + AccountIdOf, CodeVec, Config, Error, Schedule, }; use codec::{Encode, MaxEncodedLen}; -use sp_runtime::traits::Hash; +use sp_runtime::{traits::Hash, DispatchError}; use sp_std::prelude::*; use wasm_instrument::parity_wasm::elements::{ self, External, Internal, MemoryType, Type, ValueType, @@ -401,19 +401,19 @@ fn check_and_instrument( } fn do_preparation( - original_code: Vec, + original_code: CodeVec, schedule: &Schedule, owner: AccountIdOf, -) -> Result, &'static str> { - let (code, (initial, maximum)) = - check_and_instrument::(original_code.as_ref(), schedule)?; +) -> Result, (DispatchError, &'static str)> { + let (code, (initial, maximum)) = check_and_instrument::(original_code.as_ref(), schedule) + .map_err(|msg| (>::CodeRejected.into(), msg))?; let original_code_len = original_code.len(); let mut module = PrefabWasmModule { instruction_weights_version: schedule.instruction_weights.version, initial, maximum, - code, + code: code.try_into().map_err(|_| (>::CodeTooLarge.into(), ""))?, code_hash: T::Hashing::hash(&original_code), original_code: Some(original_code), owner_info: None, @@ -446,10 +446,10 @@ fn do_preparation( /// /// The preprocessing includes injecting code for gas metering and metering the height of stack. pub fn prepare_contract( - original_code: Vec, + original_code: CodeVec, schedule: &Schedule, owner: AccountIdOf, -) -> Result, &'static str> { +) -> Result, (DispatchError, &'static str)> { do_preparation::(original_code, schedule, owner) } @@ -459,10 +459,10 @@ pub fn prepare_contract( /// /// Use this when an existing contract should be re-instrumented with a newer schedule version. pub fn reinstrument_contract( - original_code: Vec, + original_code: &[u8], schedule: &Schedule, ) -> Result, &'static str> { - Ok(check_and_instrument::(&original_code, schedule)?.0) + Ok(check_and_instrument::(original_code, schedule)?.0) } /// Alternate (possibly unsafe) preparation functions used only for benchmarking. @@ -493,9 +493,12 @@ pub mod benchmarking { instruction_weights_version: schedule.instruction_weights.version, initial: memory_limits.0, maximum: memory_limits.1, - code: contract_module.into_wasm_code()?, code_hash: T::Hashing::hash(&original_code), - original_code: Some(original_code), + original_code: Some(original_code.try_into().map_err(|_| "Original code too large")?), + code: contract_module + .into_wasm_code()? + .try_into() + .map_err(|_| "Instrumented code too large")?, owner_info: Some(OwnerInfo { owner, // this is a helper function for benchmarking which skips deposit collection @@ -546,7 +549,7 @@ mod tests { ($name:ident, $wat:expr, $($expected:tt)*) => { #[test] fn $name() { - let wasm = wat::parse_str($wat).unwrap(); + let wasm = wat::parse_str($wat).unwrap().try_into().unwrap(); let schedule = Schedule { limits: Limits { globals: 3, @@ -559,7 +562,7 @@ mod tests { .. Default::default() }; let r = do_preparation::(wasm, &schedule, ALICE); - assert_matches::assert_matches!(r, $($expected)*); + assert_matches::assert_matches!(r.map_err(|(_, msg)| msg), $($expected)*); } }; } From d45e3837bc89338c6eae1ff5dc250d01e1cae0e6 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Wed, 18 May 2022 03:42:53 -0400 Subject: [PATCH 0816/1472] Return a successful response on repeated small block request (#11429) --- client/network/sync/src/block_request_handler.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index 78d6a1a7d1680..4cd69d1fac4f5 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -204,15 +204,15 @@ where let mut reputation_change = None; + let small_request = attributes + .difference(BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION) + .is_empty(); + match self.seen_requests.get_mut(&key) { Some(SeenRequestsValue::First) => {}, Some(SeenRequestsValue::Fulfilled(ref mut requests)) => { *requests = requests.saturating_add(1); - let small_request = attributes - .difference(BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION) - .is_empty(); - if *requests > MAX_NUMBER_OF_SAME_REQUESTS_PER_PEER { reputation_change = Some(if small_request { rep::SAME_SMALL_REQUEST @@ -237,7 +237,7 @@ where attributes, ); - let result = if reputation_change.is_none() { + let result = if reputation_change.is_none() || small_request { let block_response = self.get_block_response( attributes, from_block_id, From e63e26959b6f6912ffb6bcc7367a6b059d306ff0 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 18 May 2022 13:14:25 +0200 Subject: [PATCH 0817/1472] [ci] Adjust job order in pipeline test stage with Gitlab DAG (#11442) * [Do Not Merge] Test gitlab DAG in pipeline * add jobs for pipeline cancel * add check-tracing to cancel-pipeline --- .gitlab-ci.yml | 26 ++++++++++++++++++++++++++ scripts/ci/gitlab/pipeline/test.yml | 28 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b0af4cda995ad..87e7fa6fc61b0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -201,3 +201,29 @@ deploy-prometheus-alerting-rules: changes: - .gitlab-ci.yml - ./scripts/ci/monitoring/**/* + +#### stage: .post + +# This job cancels the whole pipeline if any of provided jobs fail. +# In a DAG, every jobs chain is executed independently of others. The `fail_fast` principle suggests +# to fail the pipeline as soon as possible to shorten the feedback loop. +cancel-pipeline: + stage: .post + needs: + - job: test-linux-stable + artifacts: false + - job: test-linux-stable-int + artifacts: false + - job: cargo-check-subkey + artifacts: false + - job: cargo-check-benches + artifacts: false + - job: check-tracing + artifacts: false + rules: + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + when: on_failure + variables: + PROJECT_ID: "${CI_PROJECT_ID}" + PIPELINE_ID: "${CI_PIPELINE_ID}" + trigger: "parity/infrastructure/ci_cd/pipeline-stopper" diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index bd2c059c3ed68..769d1cd30d0d5 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -30,6 +30,10 @@ cargo-fmt: cargo-clippy: stage: test + # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs + needs: + - job: cargo-fmt + artifacts: false extends: - .docker-env - .test-refs @@ -38,6 +42,10 @@ cargo-clippy: cargo-check-nixos: stage: test + # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs + needs: + - job: cargo-clippy + artifacts: false extends: - .docker-env - .test-refs @@ -117,6 +125,10 @@ cargo-check-subkey: cargo-check-try-runtime: stage: test + # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs + needs: + - job: cargo-check-subkey + artifacts: false extends: - .docker-env - .test-refs @@ -125,6 +137,10 @@ cargo-check-try-runtime: cargo-check-wasmer-sandbox: stage: test + # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs + needs: + - job: cargo-check-try-runtime + artifacts: false extends: - .docker-env - .test-refs @@ -133,6 +149,10 @@ cargo-check-wasmer-sandbox: test-deterministic-wasm: stage: test + # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs + needs: + - job: cargo-check-wasmer-sandbox + artifacts: false extends: - .docker-env - .test-refs @@ -217,6 +237,10 @@ test-linux-stable-int: check-tracing: stage: test + # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs + needs: + - job: test-linux-stable-int + artifacts: false extends: - .docker-env - .test-refs @@ -227,6 +251,10 @@ check-tracing: test-full-crypto-feature: stage: test + # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs + needs: + - job: check-tracing + artifacts: false extends: - .docker-env - .test-refs From 8c80d3691bcc36d2bcbe105848e3639105e265a7 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Wed, 18 May 2022 13:23:44 +0200 Subject: [PATCH 0818/1472] Allow to set the max supply for collection (#11441) * Allow to set the max supply for collection * Update error * Add weights info * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/uniques/src/lib.rs Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Parity Bot Co-authored-by: Oliver Tale-Yazdi --- frame/uniques/src/benchmarking.rs | 10 +++ frame/uniques/src/functions.rs | 4 + frame/uniques/src/lib.rs | 52 +++++++++++ frame/uniques/src/tests.rs | 57 +++++++++++- frame/uniques/src/weights.rs | 139 +++++++++++++++++------------- 5 files changed, 199 insertions(+), 63 deletions(-) diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index cd66d03922141..14a3e2c61809a 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -398,5 +398,15 @@ benchmarks_instance_pallet! { }.into()); } + set_collection_max_supply { + let (collection, caller, _) = create_collection::(); + }: _(SystemOrigin::Signed(caller.clone()), collection, u32::MAX) + verify { + assert_last_event::(Event::CollectionMaxSupplySet { + collection, + max_supply: u32::MAX, + }.into()); + } + impl_benchmark_test_suite!(Uniques, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 20e1410a8a849..cdaa31d4e1c8a 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -142,6 +142,10 @@ impl, I: 'static> Pallet { with_details(collection_details)?; + if let Ok(max_supply) = CollectionMaxSupply::::try_get(&collection) { + ensure!(collection_details.items < max_supply, Error::::MaxSupplyReached); + } + let items = collection_details.items.checked_add(1).ok_or(ArithmeticError::Overflow)?; collection_details.items = items; diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 0a8cf201415a1..5c7adeac0eff2 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -245,6 +245,11 @@ pub mod pallet { OptionQuery, >; + #[pallet::storage] + /// Keeps track of the number of items a collection might have. + pub(super) type CollectionMaxSupply, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, T::CollectionId, u32, OptionQuery>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { @@ -334,6 +339,8 @@ pub mod pallet { }, /// Ownership acceptance has changed for an account. OwnershipAcceptanceChanged { who: T::AccountId, maybe_collection: Option }, + /// Max supply has been set for a collection. + CollectionMaxSupplySet { collection: T::CollectionId, max_supply: u32 }, } #[pallet::error] @@ -362,6 +369,12 @@ pub mod pallet { Unaccepted, /// The item is locked. Locked, + /// All items have been minted. + MaxSupplyReached, + /// The max supply has already been set. + MaxSupplyAlreadySet, + /// The provided max supply is less to the amount of items a collection already has. + MaxSupplyTooSmall, } impl, I: 'static> Pallet { @@ -1356,5 +1369,44 @@ pub mod pallet { Self::deposit_event(Event::OwnershipAcceptanceChanged { who, maybe_collection }); Ok(()) } + + /// Set the maximum amount of items a collection could have. + /// + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of + /// the `collection`. + /// + /// Note: This function can only succeed once per collection. + /// + /// - `collection`: The identifier of the collection to change. + /// - `max_supply`: The maximum amount of items a collection could have. + /// + /// Emits `CollectionMaxSupplySet` event when successful. + #[pallet::weight(T::WeightInfo::set_collection_max_supply())] + pub fn set_collection_max_supply( + origin: OriginFor, + collection: T::CollectionId, + max_supply: u32, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some))?; + + ensure!( + !CollectionMaxSupply::::contains_key(&collection), + Error::::MaxSupplyAlreadySet + ); + + let details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + if let Some(check_owner) = &maybe_check_owner { + ensure!(check_owner == &details.owner, Error::::NoPermission); + } + + ensure!(details.items <= max_supply, Error::::MaxSupplyTooSmall); + + CollectionMaxSupply::::insert(&collection, max_supply); + Self::deposit_event(Event::CollectionMaxSupplySet { collection, max_supply }); + Ok(()) + } } } diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 6bd397eefa7ef..98e81863114e2 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -17,8 +17,7 @@ //! Tests for Uniques pallet. -use super::*; -use crate::mock::*; +use crate::{mock::*, Event, *}; use frame_support::{assert_noop, assert_ok, traits::Currency}; use pallet_balances::Error as BalancesError; use sp_std::prelude::*; @@ -71,6 +70,18 @@ fn attributes(collection: u32) -> Vec<(Option, Vec, Vec)> { s } +fn events() -> Vec> { + let result = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let mock::Event::Uniques(inner) = e { Some(inner) } else { None }) + .collect::>(); + + System::reset_events(); + + result +} + #[test] fn basic_setup_works() { new_test_ext().execute_with(|| { @@ -633,3 +644,45 @@ fn cancel_approval_works_with_force() { ); }); } + +#[test] +fn max_supply_should_work() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let user_id = 1; + let max_supply = 2; + + // validate set_collection_max_supply + assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true)); + assert!(!CollectionMaxSupply::::contains_key(collection_id)); + + assert_ok!(Uniques::set_collection_max_supply( + Origin::signed(user_id), + collection_id, + max_supply + )); + assert_eq!(CollectionMaxSupply::::get(collection_id).unwrap(), max_supply); + + assert!(events().contains(&Event::::CollectionMaxSupplySet { + collection: collection_id, + max_supply, + })); + + assert_noop!( + Uniques::set_collection_max_supply( + Origin::signed(user_id), + collection_id, + max_supply + 1 + ), + Error::::MaxSupplyAlreadySet + ); + + // validate we can't mint more to max supply + assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, 0, user_id)); + assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, 1, user_id)); + assert_noop!( + Uniques::mint(Origin::signed(user_id), collection_id, 2, user_id), + Error::::MaxSupplyReached + ); + }); +} diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 9b0cbda423ace..98cc823f0ccbd 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-12, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -68,6 +68,7 @@ pub trait WeightInfo { fn approve_transfer() -> Weight; fn cancel_approval() -> Weight; fn set_accept_ownership() -> Weight; + fn set_collection_max_supply() -> Weight; } /// Weights for pallet_uniques using the Substrate node and recommended hardware. @@ -76,14 +77,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (24_319_000 as Weight) + (23_770_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (13_572_000 as Weight) + (13_759_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -96,12 +97,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 15_000 - .saturating_add((9_433_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 15_000 - .saturating_add((980_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 15_000 - .saturating_add((852_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 16_000 + .saturating_add((9_387_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 16_000 + .saturating_add((967_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 16_000 + .saturating_add((799_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -111,17 +112,18 @@ impl WeightInfo for SubstrateWeight { } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (29_884_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) + (31_588_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (31_384_000 as Weight) + (31_125_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -129,7 +131,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (23_254_000 as Weight) + (22_955_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -137,8 +139,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 13_000 - .saturating_add((11_718_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 12_000 + .saturating_add((11_761_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -147,26 +149,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (17_807_000 as Weight) + (17_808_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (17_904_000 as Weight) + (18_342_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (13_828_000 as Weight) + (13_423_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (13_636_000 as Weight) + (13_453_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -174,20 +176,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (20_897_000 as Weight) + (20_745_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (14_340_000 as Weight) + (14_192_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (16_355_000 as Weight) + (16_488_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -195,7 +197,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (37_035_000 as Weight) + (37_207_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -203,58 +205,65 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (34_957_000 as Weight) + (35_432_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (28_337_000 as Weight) + (28_655_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (29_166_000 as Weight) + (28_898_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (28_246_000 as Weight) + (27_890_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (26_637_000 as Weight) + (26_538_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (18_938_000 as Weight) + (18_961_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (18_465_000 as Weight) + (19_116_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (16_675_000 as Weight) + (17_154_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques CollectionMaxSupply (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) + fn set_collection_max_supply() -> Weight { + (16_060_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } } // For backwards compatibility and tests @@ -262,14 +271,14 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (24_319_000 as Weight) + (23_770_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (13_572_000 as Weight) + (13_759_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -282,12 +291,12 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 15_000 - .saturating_add((9_433_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 15_000 - .saturating_add((980_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 15_000 - .saturating_add((852_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 16_000 + .saturating_add((9_387_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 16_000 + .saturating_add((967_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 16_000 + .saturating_add((799_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -297,17 +306,18 @@ impl WeightInfo for () { } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (29_884_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + (31_588_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (31_384_000 as Weight) + (31_125_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -315,7 +325,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (23_254_000 as Weight) + (22_955_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -323,8 +333,8 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 13_000 - .saturating_add((11_718_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 12_000 + .saturating_add((11_761_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -333,26 +343,26 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (17_807_000 as Weight) + (17_808_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (17_904_000 as Weight) + (18_342_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (13_828_000 as Weight) + (13_423_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (13_636_000 as Weight) + (13_453_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -360,20 +370,20 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (20_897_000 as Weight) + (20_745_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (14_340_000 as Weight) + (14_192_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (16_355_000 as Weight) + (16_488_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -381,7 +391,7 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (37_035_000 as Weight) + (37_207_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -389,56 +399,63 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (34_957_000 as Weight) + (35_432_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (28_337_000 as Weight) + (28_655_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (29_166_000 as Weight) + (28_898_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (28_246_000 as Weight) + (27_890_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (26_637_000 as Weight) + (26_538_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (18_938_000 as Weight) + (18_961_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (18_465_000 as Weight) + (19_116_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (16_675_000 as Weight) + (17_154_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: Uniques CollectionMaxSupply (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) + fn set_collection_max_supply() -> Weight { + (16_060_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } } From b75a253f148aa36fa17cf795b9f2fc2f22d0fcc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Wed, 18 May 2022 08:35:15 -0300 Subject: [PATCH 0819/1472] disable check-dependent-cumulus (#11450) --- scripts/ci/gitlab/pipeline/build.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 4ab83f53e7bdf..f7ce974924d60 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -32,14 +32,15 @@ check-dependent-polkadot: substrate: polkadot-v* polkadot: release-v* -check-dependent-cumulus: - extends: .check-dependent-project - variables: - DEPENDENT_REPO: cumulus - EXTRA_DEPENDENCIES: polkadot - COMPANION_OVERRIDES: | - substrate: polkadot-v* - polkadot: release-v* +# TODO: Re-enable after https://github.com/paritytech/pipeline-scripts/issues/44 +#check-dependent-cumulus: +# extends: .check-dependent-project +# variables: +# DEPENDENT_REPO: cumulus +# EXTRA_DEPENDENCIES: polkadot +# COMPANION_OVERRIDES: | +# substrate: polkadot-v* +# polkadot: release-v* build-linux-substrate: stage: build From 2c7de9be40b0fffee922efe7c0a1de78bcac9d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 18 May 2022 21:20:47 +0200 Subject: [PATCH 0820/1472] trie: Optimize `keys` function (#11457) * trie: Optimize `keys` function Instead of iterating the entire state and collecting all keys that match the given prefix, we can directly use the optimized prefix iterator. * Add a test --- primitives/state-machine/src/trie_backend.rs | 24 +++++++++++++++++-- .../state-machine/src/trie_backend_essence.rs | 19 +++------------ 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index 3b985ec2b99f6..c0a620120bff2 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -190,8 +190,8 @@ pub mod tests { use sp_core::H256; use sp_runtime::traits::BlakeTwo256; use sp_trie::{ - trie_types::{TrieDBMutV0, TrieDBMutV1}, - KeySpacedDBMut, PrefixedMemoryDB, TrieMut, + trie_types::{TrieDB, TrieDBMutV0, TrieDBMutV1}, + KeySpacedDBMut, PrefixedMemoryDB, Trie, TrieMut, }; use std::{collections::HashSet, iter}; @@ -369,4 +369,24 @@ pub mod tests { expected.insert(b"value2".to_vec()); assert_eq!(seen, expected); } + + #[test] + fn keys_with_empty_prefix_returns_all_keys() { + keys_with_empty_prefix_returns_all_keys_inner(StateVersion::V0); + keys_with_empty_prefix_returns_all_keys_inner(StateVersion::V1); + } + fn keys_with_empty_prefix_returns_all_keys_inner(state_version: StateVersion) { + let (test_db, test_root) = test_db(state_version); + let expected = TrieDB::new(&test_db, &test_root) + .unwrap() + .iter() + .unwrap() + .map(|d| d.unwrap().0.to_vec()) + .collect::>(); + + let trie = test_trie(state_version); + let keys = trie.keys(&[]); + + assert_eq!(expected, keys); + } } diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 0bbea7004848a..11cac92efd2f4 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -453,22 +453,9 @@ where /// Returns all keys that start with the given `prefix`. pub fn keys(&self, prefix: &[u8]) -> Vec { - let collect_all = || -> sp_std::result::Result<_, Box>> { - let trie = TrieDB::::new(self, &self.root)?; - let mut v = Vec::new(); - for x in trie.iter()? { - let (key, _) = x?; - if key.starts_with(prefix) { - v.push(key.to_vec()); - } - } - - Ok(v) - }; - - collect_all() - .map_err(|e| debug!(target: "trie", "Error extracting trie keys: {}", e)) - .unwrap_or_default() + let mut keys = Vec::new(); + self.for_keys_with_prefix(prefix, |k| keys.push(k.to_vec())); + keys } /// Return the storage root after applying the given `delta`. From 19a8a9ba9fec2383c75cc5a1dd51d45d28c1f24b Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Thu, 19 May 2022 00:26:44 +0300 Subject: [PATCH 0821/1472] add GHA support to dependabot (#11448) * add GHA support to dependabot * fix formatting * add labels * add label --- .github/dependabot.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a321729dcbc81..cca9219e6c5e1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,3 +5,8 @@ updates: labels: ["A2-insubstantial", "B0-silent", "C1-low 📌"] schedule: interval: "daily" + - package-ecosystem: github-actions + directory: '/' + labels: ["A2-insubstantial", "B0-silent", "C1-low 📌", "E3-dependencies"] + schedule: + interval: daily From 2b1326a4da39c6a46f6c0e72d07bee38e31a5421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 19 May 2022 01:50:22 +0200 Subject: [PATCH 0822/1472] contracts: Add `set_code` root dispatchable (#11451) * Add `set_code` dispatchable * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- frame/contracts/src/benchmarking/mod.rs | 14 + frame/contracts/src/lib.rs | 36 + frame/contracts/src/tests.rs | 82 +- frame/contracts/src/weights.rs | 1390 ++++++++++++----------- 4 files changed, 836 insertions(+), 686 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 01e62e07e1ce0..57a330ae275f2 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -391,6 +391,20 @@ benchmarks! { assert!(>::code_removed(&hash)); } + set_code { + let instance = >::with_caller( + whitelisted_caller(), WasmModule::dummy(), vec![], + )?; + // we just add some bytes so that the code hash is different + let WasmModule { code, hash, .. } = >::dummy_with_bytes(128); + >::store_code_raw(code, instance.caller.clone())?; + let callee = instance.addr.clone(); + assert_ne!(instance.info()?.code_hash, hash); + }: _(RawOrigin::Root, callee, hash) + verify { + assert_eq!(instance.info()?.code_hash, hash); + } + seal_caller { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index ffac3e222bbce..a8d1e18efd2cc 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -586,6 +586,42 @@ pub mod pallet { // we waive the fee because removing unused code is beneficial Ok(Pays::No.into()) } + + /// Privileged function that changes the code of an existing contract. + /// + /// This takes care of updating refcounts and all other necessary operations. Returns + /// an error if either the `code_hash` or `dest` do not exist. + /// + /// # Note + /// + /// This does **not** change the address of the contract in question. This means + /// that the contract address is no longer derived from its code hash after calling + /// this dispatchable. + #[pallet::weight(T::WeightInfo::set_code())] + pub fn set_code( + origin: OriginFor, + dest: ::Source, + code_hash: CodeHash, + ) -> DispatchResult { + ensure_root(origin)?; + let dest = T::Lookup::lookup(dest)?; + >::try_mutate(&dest, |contract| { + let contract = if let Some(contract) = contract { + contract + } else { + return Err(>::ContractNotFound.into()) + }; + >::add_user(code_hash)?; + >::remove_user(contract.code_hash); + Self::deposit_event(Event::ContractCodeUpdated { + contract: dest.clone(), + new_code_hash: code_hash, + old_code_hash: contract.code_hash, + }); + contract.code_hash = code_hash; + Ok(()) + }) + } } #[pallet::event] diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index e52ce5ca0e156..2125fe24d1a07 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -40,7 +40,7 @@ use frame_support::{ weights::{constants::WEIGHT_PER_SECOND, DispatchClass, PostDispatchInfo, Weight}, }; use frame_system::{self as system, EventRecord, Phase}; -use pretty_assertions::assert_eq; +use pretty_assertions::{assert_eq, assert_ne}; use sp_core::Bytes; use sp_io::hashing::blake2_256; use sp_keystore::{testing::KeyStore, KeystoreExt}; @@ -2862,6 +2862,86 @@ fn storage_deposit_works() { }); } +#[test] +fn set_code_extrinsic() { + let (wasm, code_hash) = compile_module::("dummy").unwrap(); + let (new_wasm, new_code_hash) = compile_module::("crypto_hashes").unwrap(); + + assert_ne!(code_hash, new_code_hash); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + assert_ok!(Contracts::upload_code(Origin::signed(ALICE), new_wasm, None,)); + + // Drop previous events + initialize_block(2); + + assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + + // only root can execute this extrinsic + assert_noop!( + Contracts::set_code(Origin::signed(ALICE), addr.clone(), new_code_hash), + sp_runtime::traits::BadOrigin, + ); + assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + assert_eq!(System::events(), vec![],); + + // contract must exist + assert_noop!( + Contracts::set_code(Origin::root(), BOB, new_code_hash), + >::ContractNotFound, + ); + assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + assert_eq!(System::events(), vec![],); + + // new code hash must exist + assert_noop!( + Contracts::set_code(Origin::root(), addr.clone(), Default::default()), + >::CodeNotFound, + ); + assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + assert_eq!(System::events(), vec![],); + + // successful call + assert_ok!(Contracts::set_code(Origin::root(), addr.clone(), new_code_hash)); + assert_eq!(>::get(&addr).unwrap().code_hash, new_code_hash); + assert_refcount!(&code_hash, 0); + assert_refcount!(&new_code_hash, 1); + assert_eq!( + System::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(pallet_contracts::Event::ContractCodeUpdated { + contract: addr, + new_code_hash, + old_code_hash: code_hash, + }), + topics: vec![], + },] + ); + }); +} + #[test] fn call_after_killed_account_needs_funding() { let (wasm, code_hash) = compile_module::("dummy").unwrap(); diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 85ff2548ca698..256e0ffc9d808 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-03-21, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -54,6 +55,7 @@ pub trait WeightInfo { fn call() -> Weight; fn upload_code(c: u32, ) -> Weight; fn remove_code() -> Weight; + fn set_code() -> Weight; fn seal_caller(r: u32, ) -> Weight; fn seal_is_contract(r: u32, ) -> Weight; fn seal_code_hash(r: u32, ) -> Weight; @@ -163,14 +165,14 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_569_000 as Weight) + (1_641_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (9_620_000 as Weight) + (11_282_000 as Weight) // Standard Error: 0 - .saturating_add((748_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((758_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -178,17 +180,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_000 - .saturating_add((1_795_000 as Weight).saturating_mul(q as Weight)) + // Standard Error: 5_000 + .saturating_add((1_892_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (12_256_000 as Weight) + (19_908_000 as Weight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -197,9 +199,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_per_byte(c: u32, ) -> Weight { - (213_494_000 as Weight) + (200_315_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -211,9 +213,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (231_180_000 as Weight) + (252_036_000 as Weight) // Standard Error: 0 - .saturating_add((125_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((121_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) @@ -226,7 +228,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (172_238_000 as Weight) + (177_274_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) @@ -237,7 +239,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (140_912_000 as Weight) + (146_086_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -245,7 +247,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (42_493_000 as Weight) + (43_995_000 as Weight) // Standard Error: 0 .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -255,18 +257,25 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_533_000 as Weight) + (25_007_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts OwnerInfoOf (r:2 w:2) + fn set_code() -> Weight { + (22_940_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (220_009_000 as Weight) - // Standard Error: 80_000 - .saturating_add((47_887_000 as Weight).saturating_mul(r as Weight)) + (207_387_000 as Weight) + // Standard Error: 88_000 + .saturating_add((40_577_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -275,11 +284,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (71_779_000 as Weight) - // Standard Error: 900_000 - .saturating_add((371_278_000 as Weight).saturating_mul(r as Weight)) + (96_692_000 as Weight) + // Standard Error: 688_000 + .saturating_add((313_348_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:0) @@ -287,11 +296,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_code_hash(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 2_329_000 - .saturating_add((451_731_000 as Weight).saturating_mul(r as Weight)) + (107_076_000 as Weight) + // Standard Error: 721_000 + .saturating_add((370_976_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:0) @@ -299,9 +308,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_own_code_hash(r: u32, ) -> Weight { - (227_824_000 as Weight) - // Standard Error: 128_000 - .saturating_add((52_843_000 as Weight).saturating_mul(r as Weight)) + (207_147_000 as Weight) + // Standard Error: 112_000 + .saturating_add((43_974_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -310,9 +319,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (213_057_000 as Weight) - // Standard Error: 43_000 - .saturating_add((21_023_000 as Weight).saturating_mul(r as Weight)) + (203_029_000 as Weight) + // Standard Error: 31_000 + .saturating_add((16_811_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -321,9 +330,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (219_066_000 as Weight) - // Standard Error: 117_000 - .saturating_add((48_056_000 as Weight).saturating_mul(r as Weight)) + (206_641_000 as Weight) + // Standard Error: 86_000 + .saturating_add((40_239_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -332,9 +341,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (218_844_000 as Weight) - // Standard Error: 101_000 - .saturating_add((47_325_000 as Weight).saturating_mul(r as Weight)) + (205_195_000 as Weight) + // Standard Error: 85_000 + .saturating_add((39_915_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -343,9 +352,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (219_234_000 as Weight) - // Standard Error: 171_000 - .saturating_add((142_534_000 as Weight).saturating_mul(r as Weight)) + (213_345_000 as Weight) + // Standard Error: 126_000 + .saturating_add((116_249_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -354,9 +363,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (215_128_000 as Weight) - // Standard Error: 119_000 - .saturating_add((48_392_000 as Weight).saturating_mul(r as Weight)) + (206_141_000 as Weight) + // Standard Error: 96_000 + .saturating_add((39_999_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -365,9 +374,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (214_603_000 as Weight) - // Standard Error: 115_000 - .saturating_add((48_041_000 as Weight).saturating_mul(r as Weight)) + (205_569_000 as Weight) + // Standard Error: 104_000 + .saturating_add((40_046_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -376,9 +385,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (214_091_000 as Weight) - // Standard Error: 126_000 - .saturating_add((48_067_000 as Weight).saturating_mul(r as Weight)) + (205_782_000 as Weight) + // Standard Error: 89_000 + .saturating_add((39_757_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -387,9 +396,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (214_418_000 as Weight) - // Standard Error: 100_000 - .saturating_add((47_791_000 as Weight).saturating_mul(r as Weight)) + (205_465_000 as Weight) + // Standard Error: 87_000 + .saturating_add((39_605_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -399,9 +408,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (229_261_000 as Weight) - // Standard Error: 150_000 - .saturating_add((121_988_000 as Weight).saturating_mul(r as Weight)) + (208_900_000 as Weight) + // Standard Error: 108_000 + .saturating_add((101_341_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -410,9 +419,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (127_983_000 as Weight) - // Standard Error: 56_000 - .saturating_add((24_016_000 as Weight).saturating_mul(r as Weight)) + (132_788_000 as Weight) + // Standard Error: 22_000 + .saturating_add((19_129_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -421,9 +430,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (216_634_000 as Weight) - // Standard Error: 114_000 - .saturating_add((46_864_000 as Weight).saturating_mul(r as Weight)) + (205_111_000 as Weight) + // Standard Error: 96_000 + .saturating_add((39_317_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -432,9 +441,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (285_180_000 as Weight) - // Standard Error: 4_000 - .saturating_add((11_899_000 as Weight).saturating_mul(n as Weight)) + (263_644_000 as Weight) + // Standard Error: 3_000 + .saturating_add((9_593_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -442,8 +451,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(_r: u32, ) -> Weight { - (215_379_000 as Weight) + fn seal_return(r: u32, ) -> Weight { + (201_299_000 as Weight) + // Standard Error: 903_000 + .saturating_add((947_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -452,9 +463,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (213_957_000 as Weight) + (202_730_000 as Weight) // Standard Error: 0 - .saturating_add((201_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((183_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -465,9 +476,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (215_782_000 as Weight) - // Standard Error: 149_000 - .saturating_add((52_421_000 as Weight).saturating_mul(r as Weight)) + (203_795_000 as Weight) + // Standard Error: 759_000 + .saturating_add((52_720_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -479,9 +490,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (217_910_000 as Weight) - // Standard Error: 149_000 - .saturating_add((157_525_000 as Weight).saturating_mul(r as Weight)) + (215_805_000 as Weight) + // Standard Error: 158_000 + .saturating_add((127_687_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -490,9 +501,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (230_787_000 as Weight) - // Standard Error: 210_000 - .saturating_add((296_973_000 as Weight).saturating_mul(r as Weight)) + (215_300_000 as Weight) + // Standard Error: 143_000 + .saturating_add((229_183_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -500,137 +511,137 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:100 w:100) + // Storage: System EventTopics (r:80 w:80) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (539_238_000 as Weight) - // Standard Error: 1_701_000 - .saturating_add((294_348_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 335_000 - .saturating_add((82_116_000 as Weight).saturating_mul(n as Weight)) + (459_865_000 as Weight) + // Standard Error: 1_733_000 + .saturating_add((235_448_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 341_000 + .saturating_add((66_363_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) + .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(t as Weight))) + .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(t as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (135_081_000 as Weight) - // Standard Error: 94_000 - .saturating_add((39_247_000 as Weight).saturating_mul(r as Weight)) + (137_820_000 as Weight) + // Standard Error: 77_000 + .saturating_add((31_956_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (41_752_000 as Weight) - // Standard Error: 1_107_000 - .saturating_add((403_473_000 as Weight).saturating_mul(r as Weight)) + (94_007_000 as Weight) + // Standard Error: 589_000 + .saturating_add((328_631_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (602_028_000 as Weight) - // Standard Error: 255_000 - .saturating_add((28_303_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(105 as Weight)) - .saturating_add(T::DbWeight::get().writes(103 as Weight)) + (528_794_000 as Weight) + // Standard Error: 233_000 + .saturating_add((21_533_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(85 as Weight)) + .saturating_add(T::DbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (620_964_000 as Weight) - // Standard Error: 308_000 - .saturating_add((11_338_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(105 as Weight)) - .saturating_add(T::DbWeight::get().writes(103 as Weight)) + (543_507_000 as Weight) + // Standard Error: 270_000 + .saturating_add((9_142_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(85 as Weight)) + .saturating_add(T::DbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (88_113_000 as Weight) - // Standard Error: 851_000 - .saturating_add((381_671_000 as Weight).saturating_mul(r as Weight)) + (129_893_000 as Weight) + // Standard Error: 471_000 + .saturating_add((313_807_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) - .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (603_193_000 as Weight) - // Standard Error: 262_000 - .saturating_add((10_286_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(105 as Weight)) - .saturating_add(T::DbWeight::get().writes(103 as Weight)) + (532_323_000 as Weight) + // Standard Error: 204_000 + .saturating_add((8_729_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(85 as Weight)) + .saturating_add(T::DbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (112_477_000 as Weight) - // Standard Error: 666_000 - .saturating_add((324_824_000 as Weight).saturating_mul(r as Weight)) + (131_771_000 as Weight) + // Standard Error: 415_000 + .saturating_add((269_174_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (564_781_000 as Weight) - // Standard Error: 403_000 - .saturating_add((63_824_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(104 as Weight)) + (494_409_000 as Weight) + // Standard Error: 280_000 + .saturating_add((50_499_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(84 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (115_207_000 as Weight) - // Standard Error: 672_000 - .saturating_add((290_919_000 as Weight).saturating_mul(r as Weight)) + (133_366_000 as Weight) + // Standard Error: 400_000 + .saturating_add((235_761_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (511_026_000 as Weight) - // Standard Error: 224_000 - .saturating_add((10_138_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(104 as Weight)) + (447_828_000 as Weight) + // Standard Error: 197_000 + .saturating_add((8_190_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(84 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (79_113_000 as Weight) - // Standard Error: 904_000 - .saturating_add((417_022_000 as Weight).saturating_mul(r as Weight)) + (121_933_000 as Weight) + // Standard Error: 509_000 + .saturating_add((342_550_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) - .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (651_769_000 as Weight) - // Standard Error: 338_000 - .saturating_add((65_576_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(105 as Weight)) - .saturating_add(T::DbWeight::get().writes(103 as Weight)) + (578_648_000 as Weight) + // Standard Error: 320_000 + .saturating_add((51_767_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(85 as Weight)) + .saturating_add(T::DbWeight::get().writes(83 as Weight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (93_588_000 as Weight) - // Standard Error: 1_444_000 - .saturating_add((1_803_217_000 as Weight).saturating_mul(r as Weight)) + (146_890_000 as Weight) + // Standard Error: 789_000 + .saturating_add((1_427_230_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -638,12 +649,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_050_000 - .saturating_add((19_925_209_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 2_542_000 + .saturating_add((15_063_367_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -651,56 +662,56 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 7_377_000 - .saturating_add((19_978_301_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) + // Standard Error: 3_267_000 + .saturating_add((15_037_276_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:0) - // Storage: Contracts ContractInfoOf (r:101 w:101) + // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (11_124_804_000 as Weight) - // Standard Error: 21_475_000 - .saturating_add((1_635_442_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 9_000 - .saturating_add((11_981_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(105 as Weight)) - .saturating_add(T::DbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) - .saturating_add(T::DbWeight::get().writes(101 as Weight)) - .saturating_add(T::DbWeight::get().writes((101 as Weight).saturating_mul(t as Weight))) + (9_081_513_000 as Weight) + // Standard Error: 18_081_000 + .saturating_add((1_388_391_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 7_000 + .saturating_add((9_653_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(T::DbWeight::get().reads(85 as Weight)) + .saturating_add(T::DbWeight::get().reads((81 as Weight).saturating_mul(t as Weight))) + .saturating_add(T::DbWeight::get().writes(81 as Weight)) + .saturating_add(T::DbWeight::get().writes((81 as Weight).saturating_mul(t as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts Nonce (r:1 w:1) - // Storage: Contracts OwnerInfoOf (r:100 w:100) + // Storage: Contracts OwnerInfoOf (r:80 w:80) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 47_682_000 - .saturating_add((27_883_754_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 34_560_000 + .saturating_add((20_828_575_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().reads((320 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) - .saturating_add(T::DbWeight::get().writes((400 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((320 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:101 w:101) - // Storage: Contracts ContractInfoOf (r:101 w:101) + // Storage: System Account (r:81 w:81) + // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (14_824_308_000 as Weight) - // Standard Error: 39_823_000 - .saturating_add((880_630_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 18_000 - .saturating_add((156_232_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(207 as Weight)) + (12_124_898_000 as Weight) + // Standard Error: 34_430_000 + .saturating_add((573_971_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 16_000 + .saturating_add((123_415_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(167 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) - .saturating_add(T::DbWeight::get().writes(205 as Weight)) + .saturating_add(T::DbWeight::get().writes(165 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(t as Weight))) } // Storage: System Account (r:1 w:0) @@ -708,9 +719,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (218_378_000 as Weight) - // Standard Error: 131_000 - .saturating_add((78_260_000 as Weight).saturating_mul(r as Weight)) + (203_422_000 as Weight) + // Standard Error: 126_000 + .saturating_add((65_317_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -719,9 +730,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (202_849_000 as Weight) - // Standard Error: 61_000 - .saturating_add((466_532_000 as Weight).saturating_mul(n as Weight)) + (411_079_000 as Weight) + // Standard Error: 20_000 + .saturating_add((354_947_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -730,9 +741,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (220_258_000 as Weight) - // Standard Error: 147_000 - .saturating_add((90_363_000 as Weight).saturating_mul(r as Weight)) + (203_192_000 as Weight) + // Standard Error: 116_000 + .saturating_add((73_562_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -741,9 +752,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (232_371_000 as Weight) - // Standard Error: 23_000 - .saturating_add((307_036_000 as Weight).saturating_mul(n as Weight)) + (227_572_000 as Weight) + // Standard Error: 13_000 + .saturating_add((244_646_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -752,9 +763,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (217_991_000 as Weight) - // Standard Error: 124_000 - .saturating_add((62_273_000 as Weight).saturating_mul(r as Weight)) + (204_922_000 as Weight) + // Standard Error: 112_000 + .saturating_add((51_349_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -763,9 +774,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (396_282_000 as Weight) - // Standard Error: 13_000 - .saturating_add((119_575_000 as Weight).saturating_mul(n as Weight)) + (247_293_000 as Weight) + // Standard Error: 17_000 + .saturating_add((94_654_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -774,9 +785,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (217_578_000 as Weight) - // Standard Error: 104_000 - .saturating_add((62_189_000 as Weight).saturating_mul(r as Weight)) + (203_511_000 as Weight) + // Standard Error: 108_000 + .saturating_add((50_585_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -785,9 +796,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (358_167_000 as Weight) - // Standard Error: 15_000 - .saturating_add((119_692_000 as Weight).saturating_mul(n as Weight)) + (253_133_000 as Weight) + // Standard Error: 10_000 + .saturating_add((94_606_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -796,9 +807,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (292_884_000 as Weight) - // Standard Error: 683_000 - .saturating_add((3_824_902_000 as Weight).saturating_mul(r as Weight)) + (280_685_000 as Weight) + // Standard Error: 627_000 + .saturating_add((3_062_997_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -807,9 +818,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - (272_893_000 as Weight) - // Standard Error: 1_438_000 - .saturating_add((15_412_877_000 as Weight).saturating_mul(r as Weight)) + (212_204_000 as Weight) + // Standard Error: 469_000 + .saturating_add((2_034_397_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -817,268 +828,268 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: Contracts OwnerInfoOf (r:36 w:36) + // Storage: Contracts OwnerInfoOf (r:16 w:16) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_302_000 - .saturating_add((922_467_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) + // Standard Error: 1_507_000 + .saturating_add((747_481_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((79 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (74_516_000 as Weight) + (74_627_000 as Weight) // Standard Error: 1_000 - .saturating_add((592_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((593_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_430_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_320_000 as Weight).saturating_mul(r as Weight)) + (74_587_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_294_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_440_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_428_000 as Weight).saturating_mul(r as Weight)) + (74_392_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_381_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (74_151_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_782_000 as Weight).saturating_mul(r as Weight)) + (73_823_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_780_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (74_225_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_887_000 as Weight).saturating_mul(r as Weight)) + (74_072_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_946_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_987_000 as Weight) + (73_981_000 as Weight) // Standard Error: 1_000 - .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((930_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_305_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_465_000 as Weight).saturating_mul(r as Weight)) + (73_690_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_433_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_037_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_605_000 as Weight).saturating_mul(r as Weight)) + (74_317_000 as Weight) + // Standard Error: 8_000 + .saturating_add((1_571_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_434_000 as Weight) + (76_373_000 as Weight) // Standard Error: 0 .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (75_461_000 as Weight) + (76_013_000 as Weight) // Standard Error: 10_000 - .saturating_add((7_446_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((6_848_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (87_222_000 as Weight) - // Standard Error: 15_000 - .saturating_add((9_406_000 as Weight).saturating_mul(r as Weight)) + (88_704_000 as Weight) + // Standard Error: 16_000 + .saturating_add((8_824_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (97_204_000 as Weight) + (97_846_000 as Weight) // Standard Error: 1_000 - .saturating_add((472_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((471_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (75_299_000 as Weight) + (75_010_000 as Weight) // Standard Error: 1_000 - .saturating_add((601_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((612_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_827_000 as Weight) - // Standard Error: 3_000 - .saturating_add((686_000 as Weight).saturating_mul(r as Weight)) + (74_636_000 as Weight) + // Standard Error: 1_000 + .saturating_add((681_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_624_000 as Weight) - // Standard Error: 2_000 - .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) + (74_196_000 as Weight) + // Standard Error: 0 + .saturating_add((916_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_435_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_201_000 as Weight).saturating_mul(r as Weight)) + (77_349_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_176_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (76_693_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_410_000 as Weight).saturating_mul(r as Weight)) + (76_861_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_383_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_244_000 as Weight) - // Standard Error: 1_000 - .saturating_add((660_000 as Weight).saturating_mul(r as Weight)) + (74_696_000 as Weight) + // Standard Error: 2_000 + .saturating_add((655_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_527_000 as Weight) - // Standard Error: 931_000 - .saturating_add((184_946_000 as Weight).saturating_mul(r as Weight)) + (73_522_000 as Weight) + // Standard Error: 50_000 + .saturating_add((179_720_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_181_000 as Weight) - // Standard Error: 6_000 - .saturating_add((906_000 as Weight).saturating_mul(r as Weight)) + (74_292_000 as Weight) + // Standard Error: 1_000 + .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_339_000 as Weight) + (74_299_000 as Weight) // Standard Error: 1_000 - .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_444_000 as Weight) - // Standard Error: 3_000 - .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) + (74_289_000 as Weight) + // Standard Error: 1_000 + .saturating_add((883_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_572_000 as Weight) - // Standard Error: 1_000 - .saturating_add((908_000 as Weight).saturating_mul(r as Weight)) + (74_120_000 as Weight) + // Standard Error: 2_000 + .saturating_add((899_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_349_000 as Weight) - // Standard Error: 2_000 - .saturating_add((881_000 as Weight).saturating_mul(r as Weight)) + (74_599_000 as Weight) + // Standard Error: 1_000 + .saturating_add((851_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_426_000 as Weight) - // Standard Error: 1_000 - .saturating_add((875_000 as Weight).saturating_mul(r as Weight)) + (74_622_000 as Weight) + // Standard Error: 2_000 + .saturating_add((854_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_172_000 as Weight) + (74_504_000 as Weight) // Standard Error: 2_000 - .saturating_add((906_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((874_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (74_169_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (74_532_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (74_205_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (74_130_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (74_237_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + (74_172_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_181_000 as Weight) + (74_356_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (74_038_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (74_181_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (73_881_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) + (74_045_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (73_969_000 as Weight) - // Standard Error: 0 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + (74_246_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_497_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) + (73_998_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (74_275_000 as Weight) + (74_035_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_349_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (74_511_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (74_192_000 as Weight) + (74_305_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_319_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_271_000 as Weight) + (74_214_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_321_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (73_971_000 as Weight) + (74_073_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_323_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (74_546_000 as Weight) + (74_295_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_995_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_986_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (74_194_000 as Weight) + (74_109_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_050_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_023_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (74_106_000 as Weight) + (73_990_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_997_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_993_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (74_219_000 as Weight) - // Standard Error: 5_000 - .saturating_add((2_061_000 as Weight).saturating_mul(r as Weight)) + (73_940_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_056_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_157_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (74_261_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_326_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (74_135_000 as Weight) + (74_014_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_336_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (74_038_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) + (74_220_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_323_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (74_011_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (74_139_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (74_054_000 as Weight) + (73_923_000 as Weight) // Standard Error: 2_000 .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (73_900_000 as Weight) + (73_999_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (73_948_000 as Weight) - // Standard Error: 0 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (74_312_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (73_972_000 as Weight) + (73_988_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) } } @@ -1086,14 +1097,14 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_569_000 as Weight) + (1_641_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (9_620_000 as Weight) + (11_282_000 as Weight) // Standard Error: 0 - .saturating_add((748_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((758_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -1101,17 +1112,17 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_000 - .saturating_add((1_795_000 as Weight).saturating_mul(q as Weight)) + // Standard Error: 5_000 + .saturating_add((1_892_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (12_256_000 as Weight) + (19_908_000 as Weight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1120,9 +1131,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_per_byte(c: u32, ) -> Weight { - (213_494_000 as Weight) + (200_315_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1134,9 +1145,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (231_180_000 as Weight) + (252_036_000 as Weight) // Standard Error: 0 - .saturating_add((125_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((121_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) @@ -1149,7 +1160,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (172_238_000 as Weight) + (177_274_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) @@ -1160,7 +1171,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (140_912_000 as Weight) + (146_086_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1168,7 +1179,7 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (42_493_000 as Weight) + (43_995_000 as Weight) // Standard Error: 0 .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -1178,18 +1189,25 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (24_533_000 as Weight) + (25_007_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts OwnerInfoOf (r:2 w:2) + fn set_code() -> Weight { + (22_940_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (220_009_000 as Weight) - // Standard Error: 80_000 - .saturating_add((47_887_000 as Weight).saturating_mul(r as Weight)) + (207_387_000 as Weight) + // Standard Error: 88_000 + .saturating_add((40_577_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1198,11 +1216,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (71_779_000 as Weight) - // Standard Error: 900_000 - .saturating_add((371_278_000 as Weight).saturating_mul(r as Weight)) + (96_692_000 as Weight) + // Standard Error: 688_000 + .saturating_add((313_348_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:0) @@ -1210,11 +1228,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_code_hash(r: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 2_329_000 - .saturating_add((451_731_000 as Weight).saturating_mul(r as Weight)) + (107_076_000 as Weight) + // Standard Error: 721_000 + .saturating_add((370_976_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:0) @@ -1222,9 +1240,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_own_code_hash(r: u32, ) -> Weight { - (227_824_000 as Weight) - // Standard Error: 128_000 - .saturating_add((52_843_000 as Weight).saturating_mul(r as Weight)) + (207_147_000 as Weight) + // Standard Error: 112_000 + .saturating_add((43_974_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1233,9 +1251,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (213_057_000 as Weight) - // Standard Error: 43_000 - .saturating_add((21_023_000 as Weight).saturating_mul(r as Weight)) + (203_029_000 as Weight) + // Standard Error: 31_000 + .saturating_add((16_811_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1244,9 +1262,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (219_066_000 as Weight) - // Standard Error: 117_000 - .saturating_add((48_056_000 as Weight).saturating_mul(r as Weight)) + (206_641_000 as Weight) + // Standard Error: 86_000 + .saturating_add((40_239_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1255,9 +1273,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (218_844_000 as Weight) - // Standard Error: 101_000 - .saturating_add((47_325_000 as Weight).saturating_mul(r as Weight)) + (205_195_000 as Weight) + // Standard Error: 85_000 + .saturating_add((39_915_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1266,9 +1284,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (219_234_000 as Weight) - // Standard Error: 171_000 - .saturating_add((142_534_000 as Weight).saturating_mul(r as Weight)) + (213_345_000 as Weight) + // Standard Error: 126_000 + .saturating_add((116_249_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1277,9 +1295,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (215_128_000 as Weight) - // Standard Error: 119_000 - .saturating_add((48_392_000 as Weight).saturating_mul(r as Weight)) + (206_141_000 as Weight) + // Standard Error: 96_000 + .saturating_add((39_999_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1288,9 +1306,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (214_603_000 as Weight) - // Standard Error: 115_000 - .saturating_add((48_041_000 as Weight).saturating_mul(r as Weight)) + (205_569_000 as Weight) + // Standard Error: 104_000 + .saturating_add((40_046_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1299,9 +1317,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (214_091_000 as Weight) - // Standard Error: 126_000 - .saturating_add((48_067_000 as Weight).saturating_mul(r as Weight)) + (205_782_000 as Weight) + // Standard Error: 89_000 + .saturating_add((39_757_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1310,9 +1328,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (214_418_000 as Weight) - // Standard Error: 100_000 - .saturating_add((47_791_000 as Weight).saturating_mul(r as Weight)) + (205_465_000 as Weight) + // Standard Error: 87_000 + .saturating_add((39_605_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1322,9 +1340,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (229_261_000 as Weight) - // Standard Error: 150_000 - .saturating_add((121_988_000 as Weight).saturating_mul(r as Weight)) + (208_900_000 as Weight) + // Standard Error: 108_000 + .saturating_add((101_341_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1333,9 +1351,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (127_983_000 as Weight) - // Standard Error: 56_000 - .saturating_add((24_016_000 as Weight).saturating_mul(r as Weight)) + (132_788_000 as Weight) + // Standard Error: 22_000 + .saturating_add((19_129_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1344,9 +1362,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (216_634_000 as Weight) - // Standard Error: 114_000 - .saturating_add((46_864_000 as Weight).saturating_mul(r as Weight)) + (205_111_000 as Weight) + // Standard Error: 96_000 + .saturating_add((39_317_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1355,9 +1373,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (285_180_000 as Weight) - // Standard Error: 4_000 - .saturating_add((11_899_000 as Weight).saturating_mul(n as Weight)) + (263_644_000 as Weight) + // Standard Error: 3_000 + .saturating_add((9_593_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1365,8 +1383,10 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(_r: u32, ) -> Weight { - (215_379_000 as Weight) + fn seal_return(r: u32, ) -> Weight { + (201_299_000 as Weight) + // Standard Error: 903_000 + .saturating_add((947_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1375,9 +1395,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (213_957_000 as Weight) + (202_730_000 as Weight) // Standard Error: 0 - .saturating_add((201_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((183_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1388,9 +1408,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (215_782_000 as Weight) - // Standard Error: 149_000 - .saturating_add((52_421_000 as Weight).saturating_mul(r as Weight)) + (203_795_000 as Weight) + // Standard Error: 759_000 + .saturating_add((52_720_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1402,9 +1422,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (217_910_000 as Weight) - // Standard Error: 149_000 - .saturating_add((157_525_000 as Weight).saturating_mul(r as Weight)) + (215_805_000 as Weight) + // Standard Error: 158_000 + .saturating_add((127_687_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1413,9 +1433,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (230_787_000 as Weight) - // Standard Error: 210_000 - .saturating_add((296_973_000 as Weight).saturating_mul(r as Weight)) + (215_300_000 as Weight) + // Standard Error: 143_000 + .saturating_add((229_183_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1423,137 +1443,137 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:100 w:100) + // Storage: System EventTopics (r:80 w:80) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (539_238_000 as Weight) - // Standard Error: 1_701_000 - .saturating_add((294_348_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 335_000 - .saturating_add((82_116_000 as Weight).saturating_mul(n as Weight)) + (459_865_000 as Weight) + // Standard Error: 1_733_000 + .saturating_add((235_448_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 341_000 + .saturating_add((66_363_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) + .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(t as Weight))) + .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(t as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (135_081_000 as Weight) - // Standard Error: 94_000 - .saturating_add((39_247_000 as Weight).saturating_mul(r as Weight)) + (137_820_000 as Weight) + // Standard Error: 77_000 + .saturating_add((31_956_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (41_752_000 as Weight) - // Standard Error: 1_107_000 - .saturating_add((403_473_000 as Weight).saturating_mul(r as Weight)) + (94_007_000 as Weight) + // Standard Error: 589_000 + .saturating_add((328_631_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (602_028_000 as Weight) - // Standard Error: 255_000 - .saturating_add((28_303_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(105 as Weight)) - .saturating_add(RocksDbWeight::get().writes(103 as Weight)) + (528_794_000 as Weight) + // Standard Error: 233_000 + .saturating_add((21_533_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(85 as Weight)) + .saturating_add(RocksDbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (620_964_000 as Weight) - // Standard Error: 308_000 - .saturating_add((11_338_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(105 as Weight)) - .saturating_add(RocksDbWeight::get().writes(103 as Weight)) + (543_507_000 as Weight) + // Standard Error: 270_000 + .saturating_add((9_142_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(85 as Weight)) + .saturating_add(RocksDbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (88_113_000 as Weight) - // Standard Error: 851_000 - .saturating_add((381_671_000 as Weight).saturating_mul(r as Weight)) + (129_893_000 as Weight) + // Standard Error: 471_000 + .saturating_add((313_807_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (603_193_000 as Weight) - // Standard Error: 262_000 - .saturating_add((10_286_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(105 as Weight)) - .saturating_add(RocksDbWeight::get().writes(103 as Weight)) + (532_323_000 as Weight) + // Standard Error: 204_000 + .saturating_add((8_729_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(85 as Weight)) + .saturating_add(RocksDbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (112_477_000 as Weight) - // Standard Error: 666_000 - .saturating_add((324_824_000 as Weight).saturating_mul(r as Weight)) + (131_771_000 as Weight) + // Standard Error: 415_000 + .saturating_add((269_174_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (564_781_000 as Weight) - // Standard Error: 403_000 - .saturating_add((63_824_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(104 as Weight)) + (494_409_000 as Weight) + // Standard Error: 280_000 + .saturating_add((50_499_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(84 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (115_207_000 as Weight) - // Standard Error: 672_000 - .saturating_add((290_919_000 as Weight).saturating_mul(r as Weight)) + (133_366_000 as Weight) + // Standard Error: 400_000 + .saturating_add((235_761_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (511_026_000 as Weight) - // Standard Error: 224_000 - .saturating_add((10_138_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(104 as Weight)) + (447_828_000 as Weight) + // Standard Error: 197_000 + .saturating_add((8_190_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(84 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (79_113_000 as Weight) - // Standard Error: 904_000 - .saturating_add((417_022_000 as Weight).saturating_mul(r as Weight)) + (121_933_000 as Weight) + // Standard Error: 509_000 + .saturating_add((342_550_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (651_769_000 as Weight) - // Standard Error: 338_000 - .saturating_add((65_576_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(105 as Weight)) - .saturating_add(RocksDbWeight::get().writes(103 as Weight)) + (578_648_000 as Weight) + // Standard Error: 320_000 + .saturating_add((51_767_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(85 as Weight)) + .saturating_add(RocksDbWeight::get().writes(83 as Weight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (93_588_000 as Weight) - // Standard Error: 1_444_000 - .saturating_add((1_803_217_000 as Weight).saturating_mul(r as Weight)) + (146_890_000 as Weight) + // Standard Error: 789_000 + .saturating_add((1_427_230_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1561,12 +1581,12 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_050_000 - .saturating_add((19_925_209_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 2_542_000 + .saturating_add((15_063_367_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1574,56 +1594,56 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 7_377_000 - .saturating_add((19_978_301_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) + // Standard Error: 3_267_000 + .saturating_add((15_037_276_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:0) - // Storage: Contracts ContractInfoOf (r:101 w:101) + // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (11_124_804_000 as Weight) - // Standard Error: 21_475_000 - .saturating_add((1_635_442_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 9_000 - .saturating_add((11_981_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(RocksDbWeight::get().reads(105 as Weight)) - .saturating_add(RocksDbWeight::get().reads((101 as Weight).saturating_mul(t as Weight))) - .saturating_add(RocksDbWeight::get().writes(101 as Weight)) - .saturating_add(RocksDbWeight::get().writes((101 as Weight).saturating_mul(t as Weight))) + (9_081_513_000 as Weight) + // Standard Error: 18_081_000 + .saturating_add((1_388_391_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 7_000 + .saturating_add((9_653_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(RocksDbWeight::get().reads(85 as Weight)) + .saturating_add(RocksDbWeight::get().reads((81 as Weight).saturating_mul(t as Weight))) + .saturating_add(RocksDbWeight::get().writes(81 as Weight)) + .saturating_add(RocksDbWeight::get().writes((81 as Weight).saturating_mul(t as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts Nonce (r:1 w:1) - // Storage: Contracts OwnerInfoOf (r:100 w:100) + // Storage: Contracts OwnerInfoOf (r:80 w:80) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 47_682_000 - .saturating_add((27_883_754_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 34_560_000 + .saturating_add((20_828_575_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().reads((400 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().reads((320 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes((400 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes((320 as Weight).saturating_mul(r as Weight))) } - // Storage: System Account (r:101 w:101) - // Storage: Contracts ContractInfoOf (r:101 w:101) + // Storage: System Account (r:81 w:81) + // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (14_824_308_000 as Weight) - // Standard Error: 39_823_000 - .saturating_add((880_630_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 18_000 - .saturating_add((156_232_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(207 as Weight)) + (12_124_898_000 as Weight) + // Standard Error: 34_430_000 + .saturating_add((573_971_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 16_000 + .saturating_add((123_415_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(167 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) - .saturating_add(RocksDbWeight::get().writes(205 as Weight)) + .saturating_add(RocksDbWeight::get().writes(165 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(t as Weight))) } // Storage: System Account (r:1 w:0) @@ -1631,9 +1651,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (218_378_000 as Weight) - // Standard Error: 131_000 - .saturating_add((78_260_000 as Weight).saturating_mul(r as Weight)) + (203_422_000 as Weight) + // Standard Error: 126_000 + .saturating_add((65_317_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1642,9 +1662,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (202_849_000 as Weight) - // Standard Error: 61_000 - .saturating_add((466_532_000 as Weight).saturating_mul(n as Weight)) + (411_079_000 as Weight) + // Standard Error: 20_000 + .saturating_add((354_947_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1653,9 +1673,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (220_258_000 as Weight) - // Standard Error: 147_000 - .saturating_add((90_363_000 as Weight).saturating_mul(r as Weight)) + (203_192_000 as Weight) + // Standard Error: 116_000 + .saturating_add((73_562_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1664,9 +1684,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (232_371_000 as Weight) - // Standard Error: 23_000 - .saturating_add((307_036_000 as Weight).saturating_mul(n as Weight)) + (227_572_000 as Weight) + // Standard Error: 13_000 + .saturating_add((244_646_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1675,9 +1695,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (217_991_000 as Weight) - // Standard Error: 124_000 - .saturating_add((62_273_000 as Weight).saturating_mul(r as Weight)) + (204_922_000 as Weight) + // Standard Error: 112_000 + .saturating_add((51_349_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1686,9 +1706,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (396_282_000 as Weight) - // Standard Error: 13_000 - .saturating_add((119_575_000 as Weight).saturating_mul(n as Weight)) + (247_293_000 as Weight) + // Standard Error: 17_000 + .saturating_add((94_654_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1697,9 +1717,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (217_578_000 as Weight) - // Standard Error: 104_000 - .saturating_add((62_189_000 as Weight).saturating_mul(r as Weight)) + (203_511_000 as Weight) + // Standard Error: 108_000 + .saturating_add((50_585_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1708,9 +1728,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (358_167_000 as Weight) - // Standard Error: 15_000 - .saturating_add((119_692_000 as Weight).saturating_mul(n as Weight)) + (253_133_000 as Weight) + // Standard Error: 10_000 + .saturating_add((94_606_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1719,9 +1739,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (292_884_000 as Weight) - // Standard Error: 683_000 - .saturating_add((3_824_902_000 as Weight).saturating_mul(r as Weight)) + (280_685_000 as Weight) + // Standard Error: 627_000 + .saturating_add((3_062_997_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1730,9 +1750,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - (272_893_000 as Weight) - // Standard Error: 1_438_000 - .saturating_add((15_412_877_000 as Weight).saturating_mul(r as Weight)) + (212_204_000 as Weight) + // Standard Error: 469_000 + .saturating_add((2_034_397_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1740,267 +1760,267 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: Contracts OwnerInfoOf (r:36 w:36) + // Storage: Contracts OwnerInfoOf (r:16 w:16) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_302_000 - .saturating_add((922_467_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads((99 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes((99 as Weight).saturating_mul(r as Weight))) + // Standard Error: 1_507_000 + .saturating_add((747_481_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes((79 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (74_516_000 as Weight) + (74_627_000 as Weight) // Standard Error: 1_000 - .saturating_add((592_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((593_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_430_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_320_000 as Weight).saturating_mul(r as Weight)) + (74_587_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_294_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_440_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_428_000 as Weight).saturating_mul(r as Weight)) + (74_392_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_381_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (74_151_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_782_000 as Weight).saturating_mul(r as Weight)) + (73_823_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_780_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (74_225_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_887_000 as Weight).saturating_mul(r as Weight)) + (74_072_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_946_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_987_000 as Weight) + (73_981_000 as Weight) // Standard Error: 1_000 - .saturating_add((898_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((930_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_305_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_465_000 as Weight).saturating_mul(r as Weight)) + (73_690_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_433_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (73_037_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_605_000 as Weight).saturating_mul(r as Weight)) + (74_317_000 as Weight) + // Standard Error: 8_000 + .saturating_add((1_571_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_434_000 as Weight) + (76_373_000 as Weight) // Standard Error: 0 .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (75_461_000 as Weight) + (76_013_000 as Weight) // Standard Error: 10_000 - .saturating_add((7_446_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((6_848_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (87_222_000 as Weight) - // Standard Error: 15_000 - .saturating_add((9_406_000 as Weight).saturating_mul(r as Weight)) + (88_704_000 as Weight) + // Standard Error: 16_000 + .saturating_add((8_824_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (97_204_000 as Weight) + (97_846_000 as Weight) // Standard Error: 1_000 - .saturating_add((472_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((471_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (75_299_000 as Weight) + (75_010_000 as Weight) // Standard Error: 1_000 - .saturating_add((601_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((612_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_827_000 as Weight) - // Standard Error: 3_000 - .saturating_add((686_000 as Weight).saturating_mul(r as Weight)) + (74_636_000 as Weight) + // Standard Error: 1_000 + .saturating_add((681_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_624_000 as Weight) - // Standard Error: 2_000 - .saturating_add((895_000 as Weight).saturating_mul(r as Weight)) + (74_196_000 as Weight) + // Standard Error: 0 + .saturating_add((916_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_435_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_201_000 as Weight).saturating_mul(r as Weight)) + (77_349_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_176_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (76_693_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_410_000 as Weight).saturating_mul(r as Weight)) + (76_861_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_383_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_244_000 as Weight) - // Standard Error: 1_000 - .saturating_add((660_000 as Weight).saturating_mul(r as Weight)) + (74_696_000 as Weight) + // Standard Error: 2_000 + .saturating_add((655_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_527_000 as Weight) - // Standard Error: 931_000 - .saturating_add((184_946_000 as Weight).saturating_mul(r as Weight)) + (73_522_000 as Weight) + // Standard Error: 50_000 + .saturating_add((179_720_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_181_000 as Weight) - // Standard Error: 6_000 - .saturating_add((906_000 as Weight).saturating_mul(r as Weight)) + (74_292_000 as Weight) + // Standard Error: 1_000 + .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_339_000 as Weight) + (74_299_000 as Weight) // Standard Error: 1_000 - .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((882_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_444_000 as Weight) - // Standard Error: 3_000 - .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) + (74_289_000 as Weight) + // Standard Error: 1_000 + .saturating_add((883_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_572_000 as Weight) - // Standard Error: 1_000 - .saturating_add((908_000 as Weight).saturating_mul(r as Weight)) + (74_120_000 as Weight) + // Standard Error: 2_000 + .saturating_add((899_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_349_000 as Weight) - // Standard Error: 2_000 - .saturating_add((881_000 as Weight).saturating_mul(r as Weight)) + (74_599_000 as Weight) + // Standard Error: 1_000 + .saturating_add((851_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_426_000 as Weight) - // Standard Error: 1_000 - .saturating_add((875_000 as Weight).saturating_mul(r as Weight)) + (74_622_000 as Weight) + // Standard Error: 2_000 + .saturating_add((854_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_172_000 as Weight) + (74_504_000 as Weight) // Standard Error: 2_000 - .saturating_add((906_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((874_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (74_169_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (74_532_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (74_205_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (74_130_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (74_237_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + (74_172_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_181_000 as Weight) + (74_356_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (74_038_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + (74_181_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (73_881_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_372_000 as Weight).saturating_mul(r as Weight)) + (74_045_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (73_969_000 as Weight) - // Standard Error: 0 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + (74_246_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (74_497_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) + (73_998_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (74_275_000 as Weight) + (74_035_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_349_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (74_511_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (74_192_000 as Weight) + (74_305_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_319_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_271_000 as Weight) + (74_214_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_321_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (73_971_000 as Weight) + (74_073_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_323_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (74_546_000 as Weight) + (74_295_000 as Weight) // Standard Error: 2_000 - .saturating_add((1_995_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_986_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (74_194_000 as Weight) + (74_109_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_050_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_023_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (74_106_000 as Weight) + (73_990_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_997_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_993_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (74_219_000 as Weight) - // Standard Error: 5_000 - .saturating_add((2_061_000 as Weight).saturating_mul(r as Weight)) + (73_940_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_056_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_157_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (74_261_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_326_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (74_135_000 as Weight) + (74_014_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_336_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (74_038_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_345_000 as Weight).saturating_mul(r as Weight)) + (74_220_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_323_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (74_011_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_362_000 as Weight).saturating_mul(r as Weight)) + (74_139_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (74_054_000 as Weight) + (73_923_000 as Weight) // Standard Error: 2_000 .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (73_900_000 as Weight) + (73_999_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (73_948_000 as Weight) - // Standard Error: 0 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (74_312_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (73_972_000 as Weight) + (73_988_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) } } From 2916ebbc0cad448874dc4b446ee7709d7b33776b Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 19 May 2022 16:32:53 +0900 Subject: [PATCH 0823/1472] Switch to pooling copy-on-write instantiation strategy for WASM (#11232) * Switch to pooling copy-on-write instantiation strategy for WASM * Fix benchmark compilation * Fix `cargo fmt` * Fix compilation of another benchmark I've missed * Cleanups according to review comments * Move `max_memory_size` to `Semantics` * Set `memory_guaranteed_dense_image_size` to `max_memory_size` * Rename `wasm_instantiation_strategy` to `wasmtime_instantiation_strategy` * Update the doc-comments regarding the instantiation strategy * Extend the integration tests to test every instantiation strategy * Don't drop the temporary directory until the runtime is dropped in benchmarks * Don't drop the temporary directory until the runtime is dropped in tests --- Cargo.lock | 13 + bin/node/cli/benches/block_production.rs | 6 +- bin/node/executor/benches/bench.rs | 6 +- bin/node/testing/src/bench.rs | 11 +- client/cli/src/arg_enums.rs | 69 ++++- client/cli/src/params/import_params.rs | 32 +- client/executor/Cargo.toml | 2 + client/executor/benches/bench.rs | 265 +++++++++++++---- client/executor/benches/kusama_runtime.wasm | Bin 5554150 -> 7365767 bytes .../executor/src/integration_tests/linux.rs | 8 +- client/executor/src/integration_tests/mod.rs | 124 +++++++- client/executor/src/lib.rs | 3 + client/executor/src/wasm_runtime.rs | 39 ++- client/executor/wasmtime/Cargo.toml | 3 + client/executor/wasmtime/src/lib.rs | 2 +- client/executor/wasmtime/src/runtime.rs | 279 ++++++++++++------ client/executor/wasmtime/src/tests.rs | 61 ++-- client/service/src/config.rs | 2 + .../benchmarking-cli/src/pallet/command.rs | 7 +- .../frame/benchmarking-cli/src/pallet/mod.rs | 16 +- utils/frame/try-runtime/cli/src/lib.rs | 18 +- 21 files changed, 728 insertions(+), 238 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ff14da370db9c..03bc44a0a848a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4173,6 +4173,15 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "memfd" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6627dc657574b49d6ad27105ed671822be56e0d2547d413bfbf3e8d8fa92e7a" +dependencies = [ + "libc", +] + [[package]] name = "memmap" version = "0.7.0" @@ -8197,6 +8206,7 @@ dependencies = [ "hex-literal", "lazy_static", "lru", + "num_cpus", "parity-scale-codec", "parking_lot 0.12.0", "paste 1.0.6", @@ -8221,6 +8231,7 @@ dependencies = [ "sp-version", "sp-wasm-interface", "substrate-test-runtime", + "tempfile", "tracing", "tracing-subscriber", "wasmi", @@ -8274,6 +8285,7 @@ dependencies = [ "sp-runtime-interface", "sp-sandbox", "sp-wasm-interface", + "tempfile", "wasmtime", "wat", ] @@ -11838,6 +11850,7 @@ dependencies = [ "libc", "log", "mach", + "memfd", "memoffset", "more-asserts", "rand 0.8.4", diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 376241d8157bf..ad16ba8e4072b 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -29,7 +29,7 @@ use sc_consensus::{ use sc_service::{ config::{ DatabaseSource, KeepBlocks, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, - PruningMode, WasmExecutionMethod, + PruningMode, WasmExecutionMethod, WasmtimeInstantiationStrategy, }, BasePath, Configuration, Role, }; @@ -77,7 +77,9 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { state_pruning: Some(PruningMode::ArchiveAll), keep_blocks: KeepBlocks::All, chain_spec: spec, - wasm_method: WasmExecutionMethod::Compiled, + wasm_method: WasmExecutionMethod::Compiled { + instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + }, execution_strategies: ExecutionStrategies { syncing: execution_strategy, importing: execution_strategy, diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index 3d7c264a89d1c..61e2d1b053012 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -25,6 +25,8 @@ use node_runtime::{ UncheckedExtrinsic, }; use node_testing::keyring::*; +#[cfg(feature = "wasmtime")] +use sc_executor::WasmtimeInstantiationStrategy; use sc_executor::{Externalities, NativeElseWasmExecutor, RuntimeVersionOf, WasmExecutionMethod}; use sp_core::{ storage::well_known_keys, @@ -183,7 +185,9 @@ fn bench_execute_block(c: &mut Criterion) { ExecutionMethod::Native, ExecutionMethod::Wasm(WasmExecutionMethod::Interpreted), #[cfg(feature = "wasmtime")] - ExecutionMethod::Wasm(WasmExecutionMethod::Compiled), + ExecutionMethod::Wasm(WasmExecutionMethod::Compiled { + instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + }), ]; for strategy in execution_methods { diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index e5287dc3c4af2..00ce7f64bc3f0 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -46,7 +46,7 @@ use sc_client_api::{ }; use sc_client_db::PruningMode; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, ImportedAux}; -use sc_executor::{NativeElseWasmExecutor, WasmExecutionMethod}; +use sc_executor::{NativeElseWasmExecutor, WasmExecutionMethod, WasmtimeInstantiationStrategy}; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; use sp_consensus::BlockOrigin; @@ -398,7 +398,14 @@ impl BenchDb { let backend = sc_service::new_db_backend(db_config).expect("Should not fail"); let client = sc_service::new_client( backend.clone(), - NativeElseWasmExecutor::new(WasmExecutionMethod::Compiled, None, 8, 2), + NativeElseWasmExecutor::new( + WasmExecutionMethod::Compiled { + instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + }, + None, + 8, + 2, + ), &keyring.generate_genesis(), None, None, diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index ac50413803278..bc0989cf34659 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -20,6 +20,36 @@ use clap::ArgEnum; +/// The instantiation strategy to use in compiled mode. +#[derive(Debug, Clone, Copy, ArgEnum)] +#[clap(rename_all = "kebab-case")] +pub enum WasmtimeInstantiationStrategy { + /// Pool the instances to avoid initializing everything from scratch + /// on each instantiation. Use copy-on-write memory when possible. + PoolingCopyOnWrite, + + /// Recreate the instance from scratch on every instantiation. + /// Use copy-on-write memory when possible. + RecreateInstanceCopyOnWrite, + + /// Pool the instances to avoid initializing everything from scratch + /// on each instantiation. + Pooling, + + /// Recreate the instance from scratch on every instantiation. Very slow. + RecreateInstance, + + /// Legacy instance reuse mechanism. DEPRECATED. Will be removed in the future. + /// + /// Should only be used in case of encountering any issues with the new default + /// instantiation strategy. + LegacyInstanceReuse, +} + +/// The default [`WasmtimeInstantiationStrategy`]. +pub const DEFAULT_WASMTIME_INSTANTIATION_STRATEGY: WasmtimeInstantiationStrategy = + WasmtimeInstantiationStrategy::PoolingCopyOnWrite; + /// How to execute Wasm runtime code. #[derive(Debug, Clone, Copy)] pub enum WasmExecutionMethod { @@ -71,18 +101,33 @@ impl WasmExecutionMethod { } } -impl Into for WasmExecutionMethod { - fn into(self) -> sc_service::config::WasmExecutionMethod { - match self { - WasmExecutionMethod::Interpreted => - sc_service::config::WasmExecutionMethod::Interpreted, - #[cfg(feature = "wasmtime")] - WasmExecutionMethod::Compiled => sc_service::config::WasmExecutionMethod::Compiled, - #[cfg(not(feature = "wasmtime"))] - WasmExecutionMethod::Compiled => panic!( - "Substrate must be compiled with \"wasmtime\" feature for compiled Wasm execution" - ), - } +/// Converts the execution method and instantiation strategy command line arguments +/// into an execution method which can be used internally. +pub fn execution_method_from_cli( + execution_method: WasmExecutionMethod, + _instantiation_strategy: WasmtimeInstantiationStrategy, +) -> sc_service::config::WasmExecutionMethod { + match execution_method { + WasmExecutionMethod::Interpreted => sc_service::config::WasmExecutionMethod::Interpreted, + #[cfg(feature = "wasmtime")] + WasmExecutionMethod::Compiled => sc_service::config::WasmExecutionMethod::Compiled { + instantiation_strategy: match _instantiation_strategy { + WasmtimeInstantiationStrategy::PoolingCopyOnWrite => + sc_service::config::WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + WasmtimeInstantiationStrategy::RecreateInstanceCopyOnWrite => + sc_service::config::WasmtimeInstantiationStrategy::RecreateInstanceCopyOnWrite, + WasmtimeInstantiationStrategy::Pooling => + sc_service::config::WasmtimeInstantiationStrategy::Pooling, + WasmtimeInstantiationStrategy::RecreateInstance => + sc_service::config::WasmtimeInstantiationStrategy::RecreateInstance, + WasmtimeInstantiationStrategy::LegacyInstanceReuse => + sc_service::config::WasmtimeInstantiationStrategy::LegacyInstanceReuse, + }, + }, + #[cfg(not(feature = "wasmtime"))] + WasmExecutionMethod::Compiled => panic!( + "Substrate must be compiled with \"wasmtime\" feature for compiled Wasm execution" + ), } } diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index 4c9b334150557..aef7511ffc371 100644 --- a/client/cli/src/params/import_params.rs +++ b/client/cli/src/params/import_params.rs @@ -18,10 +18,11 @@ use crate::{ arg_enums::{ - ExecutionStrategy, WasmExecutionMethod, DEFAULT_EXECUTION_BLOCK_CONSTRUCTION, - DEFAULT_EXECUTION_IMPORT_BLOCK, DEFAULT_EXECUTION_IMPORT_BLOCK_VALIDATOR, - DEFAULT_EXECUTION_OFFCHAIN_WORKER, DEFAULT_EXECUTION_OTHER, DEFAULT_EXECUTION_SYNCING, - DEFAULT_WASM_EXECUTION_METHOD, + ExecutionStrategy, WasmExecutionMethod, WasmtimeInstantiationStrategy, + DEFAULT_EXECUTION_BLOCK_CONSTRUCTION, DEFAULT_EXECUTION_IMPORT_BLOCK, + DEFAULT_EXECUTION_IMPORT_BLOCK_VALIDATOR, DEFAULT_EXECUTION_OFFCHAIN_WORKER, + DEFAULT_EXECUTION_OTHER, DEFAULT_EXECUTION_SYNCING, + DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD, }, params::{DatabaseParams, PruningParams}, }; @@ -62,6 +63,27 @@ pub struct ImportParams { )] pub wasm_method: WasmExecutionMethod, + /// The WASM instantiation method to use. + /// + /// Only has an effect when `wasm-execution` is set to `compiled`. + /// + /// The copy-on-write strategies are only supported on Linux. + /// If the copy-on-write variant of a strategy is unsupported + /// the executor will fall back to the non-CoW equivalent. + /// + /// The fastest (and the default) strategy available is `pooling-copy-on-write`. + /// + /// The `legacy-instance-reuse` strategy is deprecated and will + /// be removed in the future. It should only be used in case of + /// issues with the default instantiation strategy. + #[clap( + long, + value_name = "STRATEGY", + default_value_t = DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, + arg_enum, + )] + pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, + /// Specify the path where local WASM runtimes are stored. /// /// These runtimes will override on-chain runtimes when the version matches. @@ -85,7 +107,7 @@ impl ImportParams { /// Get the WASM execution method from the parameters pub fn wasm_method(&self) -> sc_service::config::WasmExecutionMethod { - self.wasm_method.into() + crate::execution_method_from_cli(self.wasm_method, self.wasmtime_instantiation_strategy) } /// Enable overriding on-chain WASM with locally-stored WASM diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index ad2288b9272d3..566ed0a50fc0f 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -50,6 +50,8 @@ paste = "1.0" regex = "1.5.5" criterion = "0.3" env_logger = "0.9" +num_cpus = "1.13.1" +tempfile = "3.3.0" [[bench]] name = "bench" diff --git a/client/executor/benches/bench.rs b/client/executor/benches/bench.rs index 49ea8be50624e..fcefe408603d7 100644 --- a/client/executor/benches/bench.rs +++ b/client/executor/benches/bench.rs @@ -17,26 +17,43 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use sc_executor_common::{runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; +use codec::Encode; + +use sc_executor_common::{ + runtime_blob::RuntimeBlob, + wasm_runtime::{WasmInstance, WasmModule}, +}; +#[cfg(feature = "wasmtime")] +use sc_executor_wasmtime::InstantiationStrategy; use sc_runtime_test::wasm_binary_unwrap as test_runtime; use sp_wasm_interface::HostFunctions as _; -use std::sync::Arc; +use std::sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, +}; +#[derive(Clone)] enum Method { Interpreted, #[cfg(feature = "wasmtime")] Compiled { - fast_instance_reuse: bool, + instantiation_strategy: InstantiationStrategy, + precompile: bool, }, } -// This is just a bog-standard Kusama runtime with the extra `test_empty_return` -// function copy-pasted from the test runtime. +// This is just a bog-standard Kusama runtime with an extra +// `test_empty_return` and `test_dirty_plenty_memory` functions +// copy-pasted from the test runtime. fn kusama_runtime() -> &'static [u8] { include_bytes!("kusama_runtime.wasm") } -fn initialize(runtime: &[u8], method: Method) -> Arc { +fn initialize( + _tmpdir: &mut Option, + runtime: &[u8], + method: Method, +) -> Arc { let blob = RuntimeBlob::uncompress_if_needed(runtime).unwrap(); let host_functions = sp_io::SubstrateHostFunctions::host_functions(); let heap_pages = 2048; @@ -51,80 +68,200 @@ fn initialize(runtime: &[u8], method: Method) -> Arc { ) .map(|runtime| -> Arc { Arc::new(runtime) }), #[cfg(feature = "wasmtime")] - Method::Compiled { fast_instance_reuse } => - sc_executor_wasmtime::create_runtime::( - blob, - sc_executor_wasmtime::Config { + Method::Compiled { instantiation_strategy, precompile } => { + let config = sc_executor_wasmtime::Config { + allow_missing_func_imports, + cache_path: None, + semantics: sc_executor_wasmtime::Semantics { + extra_heap_pages: heap_pages, + instantiation_strategy, + deterministic_stack_limit: None, + canonicalize_nans: false, + parallel_compilation: true, max_memory_size: None, - allow_missing_func_imports, - cache_path: None, - semantics: sc_executor_wasmtime::Semantics { - extra_heap_pages: heap_pages, - fast_instance_reuse, - deterministic_stack_limit: None, - canonicalize_nans: false, - parallel_compilation: true, - }, }, - ) - .map(|runtime| -> Arc { Arc::new(runtime) }), + }; + + if precompile { + let precompiled_blob = + sc_executor_wasmtime::prepare_runtime_artifact(blob, &config.semantics) + .unwrap(); + + // Create a fresh temporary directory to make absolutely sure + // we'll use the right module. + *_tmpdir = Some(tempfile::tempdir().unwrap()); + let tmpdir = _tmpdir.as_ref().unwrap(); + + let path = tmpdir.path().join("module.bin"); + std::fs::write(&path, &precompiled_blob).unwrap(); + unsafe { + sc_executor_wasmtime::create_runtime_from_artifact::< + sp_io::SubstrateHostFunctions, + >(&path, config) + } + } else { + sc_executor_wasmtime::create_runtime::(blob, config) + } + .map(|runtime| -> Arc { Arc::new(runtime) }) + }, } .unwrap() } +fn run_benchmark( + c: &mut Criterion, + benchmark_name: &str, + thread_count: usize, + runtime: &dyn WasmModule, + testcase: impl Fn(&mut Box) + Copy + Send + 'static, +) { + c.bench_function(benchmark_name, |b| { + // Here we deliberately start a bunch of extra threads which will just + // keep on independently instantiating the runtime over and over again. + // + // We don't really have to measure how much time those take since the + // work done is essentially the same on each thread, and what we're + // interested in here is only how those extra threads affect the execution + // on the current thread. + // + // In an ideal case assuming we have enough CPU cores those extra threads + // shouldn't affect the main thread's runtime at all, however in practice + // they're not completely independent. There might be per-process + // locks in the kernel which are briefly held during instantiation, etc., + // and how much those affect the execution here is what we want to measure. + let is_benchmark_running = Arc::new(AtomicBool::new(true)); + let threads_running = Arc::new(AtomicUsize::new(0)); + let aux_threads: Vec<_> = (0..thread_count - 1) + .map(|_| { + let mut instance = runtime.new_instance().unwrap(); + let is_benchmark_running = is_benchmark_running.clone(); + let threads_running = threads_running.clone(); + std::thread::spawn(move || { + threads_running.fetch_add(1, Ordering::SeqCst); + while is_benchmark_running.load(Ordering::Relaxed) { + testcase(&mut instance); + } + }) + }) + .collect(); + + while threads_running.load(Ordering::SeqCst) != (thread_count - 1) { + std::thread::yield_now(); + } + + let mut instance = runtime.new_instance().unwrap(); + b.iter(|| testcase(&mut instance)); + + is_benchmark_running.store(false, Ordering::SeqCst); + for thread in aux_threads { + thread.join().unwrap(); + } + }); +} + fn bench_call_instance(c: &mut Criterion) { let _ = env_logger::try_init(); - #[cfg(feature = "wasmtime")] - { - let runtime = initialize(test_runtime(), Method::Compiled { fast_instance_reuse: true }); - c.bench_function("call_instance_test_runtime_with_fast_instance_reuse", |b| { - let mut instance = runtime.new_instance().unwrap(); - b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()) - }); - } + let strategies = [ + #[cfg(feature = "wasmtime")] + ( + "legacy_instance_reuse", + Method::Compiled { + instantiation_strategy: InstantiationStrategy::LegacyInstanceReuse, + precompile: false, + }, + ), + #[cfg(feature = "wasmtime")] + ( + "recreate_instance_vanilla", + Method::Compiled { + instantiation_strategy: InstantiationStrategy::RecreateInstance, + precompile: false, + }, + ), + #[cfg(feature = "wasmtime")] + ( + "recreate_instance_cow_fresh", + Method::Compiled { + instantiation_strategy: InstantiationStrategy::RecreateInstanceCopyOnWrite, + precompile: false, + }, + ), + #[cfg(feature = "wasmtime")] + ( + "recreate_instance_cow_precompiled", + Method::Compiled { + instantiation_strategy: InstantiationStrategy::RecreateInstanceCopyOnWrite, + precompile: true, + }, + ), + #[cfg(feature = "wasmtime")] + ( + "pooling_vanilla", + Method::Compiled { + instantiation_strategy: InstantiationStrategy::Pooling, + precompile: false, + }, + ), + #[cfg(feature = "wasmtime")] + ( + "pooling_cow_fresh", + Method::Compiled { + instantiation_strategy: InstantiationStrategy::PoolingCopyOnWrite, + precompile: false, + }, + ), + #[cfg(feature = "wasmtime")] + ( + "pooling_cow_precompiled", + Method::Compiled { + instantiation_strategy: InstantiationStrategy::PoolingCopyOnWrite, + precompile: true, + }, + ), + ("interpreted", Method::Interpreted), + ]; - #[cfg(feature = "wasmtime")] - { - let runtime = initialize(test_runtime(), Method::Compiled { fast_instance_reuse: false }); - c.bench_function("call_instance_test_runtime_without_fast_instance_reuse", |b| { - let mut instance = runtime.new_instance().unwrap(); - b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()); - }); - } + let runtimes = [("kusama_runtime", kusama_runtime()), ("test_runtime", test_runtime())]; - #[cfg(feature = "wasmtime")] - { - let runtime = initialize(kusama_runtime(), Method::Compiled { fast_instance_reuse: true }); - c.bench_function("call_instance_kusama_runtime_with_fast_instance_reuse", |b| { - let mut instance = runtime.new_instance().unwrap(); - b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()) - }); - } + let thread_counts = [1, 2, 4, 8, 16]; - #[cfg(feature = "wasmtime")] - { - let runtime = initialize(kusama_runtime(), Method::Compiled { fast_instance_reuse: false }); - c.bench_function("call_instance_kusama_runtime_without_fast_instance_reuse", |b| { - let mut instance = runtime.new_instance().unwrap(); - b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()); - }); + fn test_call_empty_function(instance: &mut Box) { + instance.call_export("test_empty_return", &[0]).unwrap(); } - { - let runtime = initialize(test_runtime(), Method::Interpreted); - c.bench_function("call_instance_test_runtime_interpreted", |b| { - let mut instance = runtime.new_instance().unwrap(); - b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()) - }); + fn test_dirty_1mb_of_memory(instance: &mut Box) { + instance.call_export("test_dirty_plenty_memory", &(0, 16).encode()).unwrap(); } - { - let runtime = initialize(kusama_runtime(), Method::Interpreted); - c.bench_function("call_instance_kusama_runtime_interpreted", |b| { - let mut instance = runtime.new_instance().unwrap(); - b.iter(|| instance.call_export("test_empty_return", &[0]).unwrap()) - }); + let testcases = [ + ("call_empty_function", test_call_empty_function as fn(&mut Box)), + ("dirty_1mb_of_memory", test_dirty_1mb_of_memory), + ]; + + let num_cpus = num_cpus::get_physical(); + let mut tmpdir = None; + + for (strategy_name, strategy) in strategies { + for (runtime_name, runtime) in runtimes { + let runtime = initialize(&mut tmpdir, runtime, strategy.clone()); + + for (testcase_name, testcase) in testcases { + for thread_count in thread_counts { + if thread_count > num_cpus { + // If there are not enough cores available the benchmark is pointless. + continue + } + + let benchmark_name = format!( + "{}_from_{}_with_{}_on_{}_threads", + testcase_name, runtime_name, strategy_name, thread_count + ); + + run_benchmark(c, &benchmark_name, thread_count, &*runtime, testcase); + } + } + } } } diff --git a/client/executor/benches/kusama_runtime.wasm b/client/executor/benches/kusama_runtime.wasm index 3470237fb5aeea2fc21c9efc5a214b0754f3afd6..28adce962340037a0dca62724add224218c50b66 100755 GIT binary patch literal 7365767 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 zμ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

rNzWC8asVxJqeG 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[)KHDA zU@L*7^Dzd?*dj7HD7`FZ`-iSPs6INBl)*fDFi?kH`9A5;pEa^g@`e{Wv~YJHy>Glw zHV;)5llZ?-aTDppfKYv1@#eA4n%XMbuPeT7=GEWb$nL8S=$=KxO>|p?o~!7%tu-B& z`yT4*O;U9#S8RADU3~O>kZYEkS86r{lT;KzlXfflm96HHiYN?p<8F2) zfw*k}!mv8i%iV{|oFueWe6>qwT;?j{m357=$TbGS9Kl}I8rtiFX>6f2Pym)UIeB=E zF)4)`Yo?2u@w~~2;CsOh%Di=~ouDx$(k0Rui={CVPqp+puV-OH_7#n>)MB9R6G-yn zt-cx~D2P&HkRgQPkjAjxF38;6$j1|Dj3j7`9`V)!bONAhjDF$`(FDo|xYh#Ftch-o zabccxvpH7}g~Cus(;OG3FkUI|Q=TM#f5SXM3`FwnJH;>Z4-C!slqJ#^FInGwB`=re zPeXJp3M=Tichce{%ItKo#9mvHR3Wf8Xl6Q`nv`7Yl5tAa*5=|)B2>_~qC)(d{4|$> z$xqViC25Jp_7lUcdtDZN6l)kN4&}m_fmRESTIe^60NLkX6dV7t;RW| z`y)=0pR19!uXCkZy8$mY;Y0k28?)a6xV720g|Q{CVuC&Pk`;Ij6|!!^FNiG4|AdTY z)?EHg8~q6X@I=heU_F@fE-;9)M>o&S5bXCRd6@C~rOE#AVJ)~F@Zt53=XdeiHRx*g zkb0MVN4=rX9ZH_ni z-aWN=LV3WS&PuMFfsa~?5cee2c&|qgwJ>UJw3L>M#N6M z3edawH`7Rr zA}v|9aH(-hCxbwS)bU4J?*3tITO}PLmdO_^>es|Z5jP~GDS)-=xeJV5=bALb^1d32&{x)FsIRl3 zuaE->8N~r1incisZC83eN+z40>66}Vh^Oqf<`^_9VvV&~Y2zvuU%i8Kdw9GGNY?_0a{rr%%V<$R= z3`VmoSg9t28!7lfHWhY909DvMouA#StUu_!uSnRwDk{!Bs-5`erdrPGM{+f)3)2*F zFVhN9ye8-}+O^9CwAY6t!+si%mb7>hXzo+dmLw{4)@V3Q(YEla-SV8ThGB(GHwJ;9 zw1T8Wh1}Dc%~nxFm5u6vK3C#@0txX4Y<@9mR+oGqLuVZ64T~x zOb|nWSR+5;;oBmN+DI9T*}gWGdps>XjOA@N-E{x8@7emJZ`)J=S-iSAwZ18U&6%k` zCHaU*z$wW|G-tnOv#yNV|IR93gnzN?%Hu`mRm_}}A#H{DfK6;%s zb|JT4q6mV@zJIM1ZQ%A!ik{1L){6u-6`jrXe|*?#iQX9E8ZIC3k|}Q0)GDs`c~?_z zDOt%SIizz@*!UvhMc86_A(Y|3}fe{0@rl zVYaZ=7$qhFUST%ZJ5nyjY&;dS0d~QL>?AQ;%V(-0K{TjKa53B8f!JANua>xNmY*{% zaa#*{>fEL{auzn*S2=yF?zb;nOv2!B+~$3AcKeZIPjZ7Ti_fhv*gLL-l#WuqSoE;U zVB(tP&NY}1rR>qL?7&20yl>PP@2kJPW#_Mdan0ZUsrw6@+t|vc!fiDHHP667vr<^T z^pQaOL)j^SpbtGDkH!?tkQdObmvEQUgTcIq9*$V}LJ07RM1z>Z($T6A>k=V#au^oe zEaGo)E6Blw?~#%NI~?U!+rAt)kE8Ils7h_5jKx-i{-+6Fe3E^nuLQ@z900=^a}LR} zn|Bnl?8|VfWZ6%yw<4kKd>3W6cu7#55@kUGNtFGrOR~3n9Z9meAj-b_QENz|3<)Sv z_D(P9FUmN4v&F==yXz1(0dvGimpO2Z63X@g>5))xMIvo2CDbN<&Y2Ns63V>pCZRsY zgCN+DP}Kt)=9N(Bs>OgpY67X5eZ~>MYll%*H-AKWuUDzU%S#~dyJ%~I>*qdZ0G9w1 z4rD|Bx@cbe@k#;a7RI}dK>*rT9aSPfoB%8>kAJQSz?*k{?SFmk=b!)fkKOVJ_C~J+ z4CX)=V0#rEfE8iA@#6*rnK$;A-Gjy#qy{IIfy zdSFPZ?#$l6zcur|%iy>-Crkt4SFU{Xom=)EeA{Pi!Pfjh6hVFN69v_+aTxyl%>@ka z2r&GN7YT+UF}?S&zt>+Pt{W&3PkJ0AqU}C39|)^diDI)O43119_LX8MBdR{SGk~y_ z;e3%i`;C_r23>!aJf$B?F5F(J8EpAv(P9!+0cZ9~A&G3VSa777E2WhCW=>3IuH3Qh z<_Es=hTpv7ZV$Cot=GPg(5Y>I`^f?l=Q$+4;U$8^SB$ax3a3*a2S`{>*%3jaG?NkBws=iO0IiG%H6K26(b?VnpwHIlnJ`U5O{#2!WbU=Bv{c4-lb_SIH zqBZ0T%Cxsv$i(UnHGJ~(fHzz0%eAtpL7@gBINgd8yF`-<+`ntM{7~&^B5#wy)E{(3 zAim{H1A$L}=Qj`Cc*SqN`|$s#iIIX5YwJM?2txjQW)>-Qk^Ap|@li}9<1UtOGDTeG ze&yw)q??0^SJX{&=K7lu9ENi8P4nQ17!^4n6ktB$U*$exzM;5$e&9T5K^nmKeu~pm z9vd5y+?n4l2e9eGU%O}X?g#FAfd)`LU2!Fw$Qm_I5v?)bZc4D4e&yY8jo8xua;z-2 z95-$y#usXEoEnuRx3R`Xova^ZE zmX2*^Z~v4PCEU8P*UawnT3U#}9H*b1;%>X?gU`~}dTl3WC0dI0fH$q2;3>g*DEqfh z+s9IFHKAI`b%z%%=T?57Wn6!FYv|Gtab=14q3l{O(mD~<>Ngd_V3V6`_U*$=hWbE= zSlck3>ke;oxmJ-vBe&^XYimnI=;1ZxWMebtjp9$6xN6FM8J9c##aD70<~e`K3)M-^ zCH&59tCu@*T})B#K7A=gu;+y|uvF8`D7(U&+`w&crQ(aJ`BCKxeG}%|+Vw`YkTz6X zv?xD3e7~IciPB6two~Bd5h8`2%`oeHR!F#3j&0tz+HZX0=J?Ku2|C4 ziA;qc-QT>l6T7ym(z+x`gSa+lF-0-4V1D91XXR@TEgSJEH&HpB%FOm`tW=qd9Ts9} zacEIQ_=-&vY`MQLhky+TnBiAOLQu={S!hFE)F#4oHEVo$6sujt9c5GXGG>TP9@Ofc zt1^64wL*SVikGTZ%5O^1*R|4pR=U5dl;6}n&{fKBO3A9oTi} z;(6M(pL_X1*o=^n53coU9!`*!yFo z0ta_`tyT!7Y0ZPt9aZ>Jer`ldbXyz`(F%J`9Ejj>-w&jzRZ2qQ`wWRFR7p3iL`gO? z9ld{^>0@OeOl}UCO?7|{t8HWIs=uq72Nlw{y+@vAKPR`R*-z3??C~`F8Ivx6{cKit z^z5f3=nTFT3kP<6rthT`W`jjOwXv;)fr}6A0=vIiP6bh(r8=+vxch{7xLjnim18yf zXyh1!1Sy~;Ru~8fMv^p5z94@PA8g|rcAlVfY%bo4?eqqTl?e{4)0rHIn&gKHB}&n2 z=bdeF$7VmV#2np5U0XdDXD*PCLYrCa$X2fsyfmVq*P*bJTALN_y%s@}6xizUfLq>; zrbO!@SND>RTC$0#(}4#1TvJmdEv<7I&AdY&P`^K+J>BRvE4#K}TniVxM`Ls@$Bfmb zh0vH`$ID8AD*>B}WWmL|CdIQ%M;Vw3n&_}=6W=0F?=qcv$jJ-J7G$5~`iX!nJ}fsG z9@2)tb|RqG`T2=};SK`wy9JyGh}jH`__R(09BP6n|7UwrEp9a$<%xi{Jq~9?Y;0Su zUa@;IGcZQgH4Q7<>Dp&l+J}@!OQ>a^;RQ5>!eT)*vovxXIO<~@NEsE0CSO<3Bn$7D z3InxgHkjfo9Rek+r7^1ZHI|O#xN1o%3o2+%oO0B zn1AX7c8`g*wJydq&;I}}eq?8C4E?xx5OSmBm6bTz5Oqh%_h=d8@8b;4mV4a~)|dCd8d=gMFOi25YyDn-8dZIcls#$%Vk~h?sFJ+injbMV ze*K9HHlz}YpT`Pnu^R6qe@5Sgmf#?8Y^s6swY<;Kai;v z%q(1RdT_L6R)5FKU^9!wz`2=aX-*1IRm?2g07H(MU}oWj_5lSD1e@#TU~>Vcip@pK z6`M;vlSv4tNZXsuUA_&YAgyS*k2pZ zDDV+Xv}ZP!J{BfepvNaCgP}v8oD9}usO2mM&Yo}!L`VrvgO86!LwP`3ypNB6`Rw5qvAq1yvyd9Gb5XI!c@E!Wxtixm zk-!lmfz8&?FfJm(U_?Ul(_0n0)2<2>`0=e)KwyZ1V*7n9>2KipW9KLf38ry&AU{z- z-Sg7q=kI1@zE!!lPgg80`5Yl(Zu1>WSd@$Ul`XA!Nx##9-2i>$0n+R;+x54$1C`A- zya86AzwtU6clfBWnW!_Q?~-$_9bN590N;;P#9+FFGS)x%v5K6{yD1`R15XW4xQy@; zn^4$Z#@cV@dL3()*Cy7d+m!Wi%?)@h7G=@jr0nUpNar8YAL48D=LYQ=-QkoZoocHy zj2ahq#yF}?)iq%5<4du=2tP5|;D9mFzCpvC)0j+h>4lh_Kd`(Lywo12^D?Fb=BW;4 z!VV!X+`KgWlF2a;LdLJ$cA%CpnU*p6F^>T05)O=H0Df>|L;wvE=Cw;1Nb)iDpEHHS z45T66wWy@#KE8pCmC>iXbMls38GXt-7s@m*(}>troE}Bl_Zzk=VAvSiEN{*v*_bK6 z%{|D9oo}F-P_jwn_8^aDx#4zJOtjhW=NjD4MAGQK!@Ax22FI~VeS>2W81okjW9IBcoDomXwQK4;AA5DHBALs_m#mcl9b2#?0V{ddDZ4(_0 zeK;gwnnWRm3xzE$)GaEajZ0yC8ZC<>Mh&5sw#$O%Z8nwqYDP-b$9#yzu z-_NKWpf`x2Y4|Gzd?L?zlou{_A)B1k_<-Ws@wT#V%Xw$ZjT z0a8@Ey40jNQdCQIYGrctVA$kkq%XK+FL}rq6jEU$as9a{=Ouo(p#VzS5_(`Wd5d@8 znT@@;tbd0>F^$RdABD6H@t_J#px@tBXcGN9Wg#5XxChSO8G%jryqQdhUQH-bcx<)f zrZ#&;>>D0iK{@IR6+CJaEL+oUc;vo{N1@p9n0!gypZJ}?o|hPRUczUNjyX@y3B$s` z75)^ln3AoqsLD*q_HgMXKumOLt^84eC@Zs8{;*zVt*kD}prbZHNyBP?hNpd)xYw4V zOX1T2low2%MgdEB3n^f`I@P4Wn#V#4h^VR(;5rGaQUuKEC-k0k+{9@>x+()yK|PK@>~mApY){C1xdoyF0OPZ6$%XJGkJiWGo#`9wxgHCgd)c9J3%lmmDy$ z5t@;UcvS^7Y;BryQ335*lPU-TBRACb_9TCb2Bh6-V3I$zGTNA|%AHAjYPwmU5Q_CG z*D15crs5q@DS2ii7d<;T|Hyk;mp!LYxRclEO*1==WX~x<_FO2MR&tn4SGn_)F(TPM z#YHFu)mzSsyrjy!&>+f2gD4~IV@Wz3WZ3Xw zWSHP`#4>ED$uL&Bl^{4}s!+KGuo6-&8 z@V{U;w94M41g8LvX7*No z+1CI7vsixRkg{nJUugV_mYui$nB}?7BAh!J#Oteb`mkqkM=~3XNHxY(7HiBw?;mSs zTPr2%jHeanb#Qb^hC3Sl;{rnRJA}t?_oab_TKtQYGm$pY7z8n*0j-0}K7yNkh zdG8G0TjJi~S4ah(>q9E_&My=bU1Pqm@0h>RHD;k`=c0|P5FZ4Qei}!ud{J$3X{Y7I zrsE=fFIt6z#JdpJmkGY^eX?Lk`KVb7s~8BocxcTY=?3CPWgT%iPAlIa4CNEi4k7YU z;LSyvfFbBRxbnPQ={LHig>Z}%cT$|6ptqq8`4_y*N-`XML!5S5nH?*nSNz6;Q$kYl z8&gp_BmA~@&F?l!aZ2hB^Y2UWte6K-l7$Z#OW&*moU~xD(FmQhG#L8O&GFj6Ckdck zGF}{EL2iD&SbBG5hgzLiT4eh3tp^+brE=`0z7Ye!Je0vNK^3b!FOmOJv5jRsiOG}_ z9(0#*XI<+FYoLK35HDXOMEv6A`y{;{_h_evR zSe3>_G~;6WMOQE65@H!Exn(@dAxA$hHjiXzF(J_C7s%k{d~N;s)~4+tTI}~*fuhR6b_+p(h# zb%Jx1PfEIjhb!(rq()j(`!C-gqeA&)PI+6BK}0?7 zGV7khVdQBof`&Z`E%Ju*dUoEB7C)MQsiliQD~davW-C4Ycb>6w#c8K5Kjq|;mYsOQ z(qzfv$%*l?MIHS&I%1dMPG_hw-uo%ko%!pP2eru3p#ETZWEAzMT}hJfvsoxJ3M_!) zcGu4k*uCIn1krsvM{^*-`3Pawq00%DRt`d${HLSJ%FC_Rb1DCIepeJ{oQ^TVt9Qo?NmCvAI;IA9VvgaieCQgYXe>}Mo zdTekU@^BuRgSO{SmjE( z-7B^tPuT{HH^n}uh6*iZV=z*%ce)2)n3NwzyDL@R#<9vTwnvl5XJaAz!8d!}=kcsk ze^X`rk2^*S%2Pk+qQ2aZ^1QZ7&!Dr7-r5mt_elJTcHG>6hv;V?H6w`<0LGIouSEkD zA2V{x)ekR)kJ(O`HK-Y}t+GLyvdZ;NGbn3E4~{`Ub80O-YvM&vF@O)VYf`Qnd$XIY{*;K*Wv>?S+Un zn43&%{G0tvrcxRkxw%Ac#!-Vbb6HYtTNu@pM7D)d;ZCG%WeZ)weq2duDNa!cBy}p( zF8hbz%v5aocvWcEgeGrD?Y9~$qL`?t6dpG+52T*A(o3vWy>QoLpeH#=P?YN@E6>O;n8a)|FU@o~auHq0KXscX_A{Dd`{Y{-U7I z3Y#A}g&3$7{^FGA(}!cyue)*6|Fuq^IJnb1F<2qkUPofhOD0dCHz9qjq1@2ClT;*O zwdiq<=KOs(dQWB|s(C!60q6ojU!V&Ft2o4_U=rXFejMHV;e#g(`k;ZO`jIZ)c%5&$ zNV=Xn9|&KNGinXSL@3rrtT>oFMSTs|6qw2A{??X0P#EV+`EhogtT}+HuS^J>To^&k z#?pu!w<=!vVPMD!a0vx{pHmpHZWnjNzU}{MtuCU+Y!}K#J4@0Gk zF5o-ah?d!Z=C25lW~`kk`BX7=HTja8#=BiX_XCK?3|oJ~m)Ikzoh@XdI4^Yx)lh$J zUfeiZ}?2wKfx?}@Hei8;oQi(&L-df3TD{g zSLTXWc2{1x<8ZG$SiJI3cKD^CE7cL-T03~=Wd{RH+A z(VLZc!K7{tbKSr+b}h(H=cxq*>$Wd~MbkVh-Z?T}1OcM)Koz>}OBKibk;UalbUWZ9 zJSoO8$&WC0-3}akAqIH?^Ka+2 zr3sdHgaN-d%1!$>UGJtnS$FniCp(jwX>V;=7j(9X&bNnF007_a{%n}PJ`NwA$Ui(W z;KKz7U1Ys><6@@4S#CjlsWEX~K0y7uM^HryPyYS=|okY!}>QJuySKkFGWG zQu*kbe)1-KG{?DpDgV*Gab-if37i8({X62udB<`6s*PFmPuM#6x_EQ=o{1=Uk#JY|&M@Cw@4k*}0wY0%|&KdpsWBU7+ZvD+(RGf|~s_*9&t;+;RAeRZc9Uv2mCxQ1x5rYMeK~$Xl z+a}XufogEG{YMam5k!MVP)uDh`T7v%lJW76j7H;mQr=8lB#EKnl)+SHHaU*;SKnHW z4e5Jh+oxA1hw||B*04KGtfj?#k|kEu-xhKFgz}d1CRLbB^0Jl$q}Ir?)fIAbaIFUR37WHwR zqsy%^8j{m*qPc-aF`GgILEIO6ebH z{&;Zpv242T9+GC^9ES!6ILN6=w7(toajZ7Xu}TIW(F1clkE*)fV<(N?7VF+_Fk?=` zfnIJZK+&C1&0C7FD^_Ig*G_zHTv_z=X|TW;qzAndk88 z?d`XayqdL0ECo6{I7fzqUG|9^MenQ;p``Lt705WPlzhkQ-Z<(R_B-sF?H?iGaL(`d z>3)~r@74Xz1!O_8#)v~aTec=EyNxZSfBM-X-SOa1*ivIB-K<43(vRxw^wewy! z%T)_QH{;GuG~1>&wol?ZyUL!P%&p#~q88z*6qmfxcK58<*gjQHf&4+f zqQ&HI<7I6|vK>03y_I^5yYv}cXK6uO2+Z*Nbd~d(I+t?49hu8e+M$>?JK>g>&Iq?u zSjDY~lnn!Zm)m`(*jIj!TaAU+em~q&VTxOIoZHnZ^&b5JxA&d7v3+KE$~$YgwPC%w z{mf9R;XI4`?@;qBu7{Rb>uV8j(nrv_HeV;38LNi``IRq5G1?-Ki#mVEigd$$_8k^6 z#Qe&>K9Xy#W;%3U113`Ed0ak`2s-+Ivicg?X)XhSE3FGkd-LzsTUN|_bFz5l=%TUl ziOI&vIGC5ThAcg5>1ijNcl!5G$2gRVD(oR4V0^ei_?q# z4C%s@es{C2Ghl!@I{e+fjfKX$7g*EQRQox)Zk}qNO)c=1o|4VwdqAaUPcQoONi8Q# zpTkKZ5byLbJHRZNAhz1HEpL|iJ`N-xQ))>8m5;j%0VbJVS|h4hJoeV;5J)B21H>R*p(-(63dsb?3sN7R8CH7+-Rw zwsivE)_PdfO@mYIb5yi#s=ZEEPz(W}bf((togHSUGV9XSbcti-A3`*!{}1ZAeqFrZ zeqWG9mvzov7vC42-W#6o)s^x+x~`+4A)45&ABfXAUC&t;-)6t92^!uNp6(1!Z`76Y z9V=YRGX#)fe4-@$gJ;Qt%YnFK#m3~*<)*jWQ$?cazH072(?`E!MeTLo#d6%S!dEn^ zfwylpEO@cMdk_h-nii(xKbwriiVjAaPMmJ769S)%BH*_LsC5}e-oix^GtX=sIMcRB z8-9s?vUAg!B0_E+IBR8f?_@m{aO=@QcDZ@-(!k=0h zQfrCWvRV(;Tp~6IW$6;TJ9s+7%Hg=j5i%XO&n^dhYO<@uqp^c9S=K?_q-(NAD?Kei zR4r9ssd}dRkGQDz|4jA2T1NlR3}U6INB_?ZY^<{MOnc*?w4Z?GI4J-&9U-6M_8&1e zL%~@F;C!Il*8uFrHG-L46A0$&o~STXEhK5rA_(TtSvkS*lV#0o!+VdO)lD$tbmBP( zUg?18d3SV+`b zArx!(q;!4wqPAB`&nbRDxcT8w!=j90V*qI_@lMGv+#3|GDUMTD?w*cbo50XuNmfXx?CKje?ZMtK4YtL8ZM%uG;CNy`pm-M7}P*j>THIK+NpqESuKG4rf5lt^{C1$Z`or ziD7t^-#l#(DFcl`Lz=2k2yC-&jn{^*8u%`Mov#mPXdDm$Zy=b1o0T+m7&Xd$=N4tb=X?fTMHlJF-%&UD~sD`EBj; z+uDuO=eF0=wk#rRQx=}uJPAFZX|!+M?u`7PzMCk(W3|)?Gjb={ibq9OD=wK?vQ;2@U~M~?%OD(N|f13?7FTG=t;F)0=JXnSu8AVBb` zhc>|KD;C%Hh(t{Ya50Fr?$edu`|N5Yfx868dGM5Uy-QT5VQPs?beI9}qP6!mT_QrN z$3MKG`bJLm4My5U_2OuU@~OI&;9Xx4x^8iq)L-9E>JL%7kJLYh;=WRUeNE~E>;3GB zYa%~b&rB9eonsc2i+r=Fa*=}IKJ%toQx&e z=V%Fb7%viKU3_bbknlCz=U~j5nva*h#Vi`1{M6+8`oK5H7DL_PWXloD_s3SYNWPz% zQ~IfNw~NvzjKI-{r9A&nG@i|ncX>|6tBW({8D{03uPavGd2ZwR-_kFJ(3F6BMaNlL zs#$2jGZZC1kvvzZ)6JR)Kg%7ZNz*w;a|Mh5$v3C~3k{V%WZLk&blpbmob}i|H0L&- zp&^$M$Ac^CK8&-T@LlqxCG?+SmgyP zZL3~nV7u939CHK#TlCIz*$W+~aIWY5@Fz28OwZeB566p7yq-T_dgpx6t!~ci=EhR* zoGe$sdaL9lB}3-C`3#vSTG%kWQ}W@R(mT9~Q#7i|WNmeGS5k2y8$oEUaz@pM1(9en za|VBk36sj0?VQ1%yevJ#?y&14CX&wi&q=P414Z!@SLY|0l({aKvr?f*X>CA z^*jNhV^sWt_Iku^FpiAl#m#S>1>Oe3HO16%=Ng|n-nho5j_WE@$8&)(0H0mcIZu%0 z_PRBi1%i_`2+?MG9$`DNDYYM=NCNLspIhs0M|g_N1K|i6?F2zU@hSdSSc<7}NE}YcyN(+F&E^Y0+%`(G#ImOeBy3M}3NtQ4hP=Qn0&|Z@#N@^Zrk7zS`NFM;EQ3FkOibfB9(P4-;9O6# z-KBLVUo`qf2>^0(SDx4uQQ2DNKo_IXCC@B< z-Z~ao#K@wi0;}>8=xSa9u6PMDB~)N^?H&26Hl77fr11oSI9;DyabuA8`%ck>YKkW0 zk&%;0i5Tg0I+PoH7RHw^feF|CQ)mk5(txk1r<>_+=@R6I555L60Uzz}y{I_Z!QZ}9 zpaD%)-B}tyj@QV7xQ=BM{2GOEMGU8z-HvTpMbG{c|{>)6YKDK~%@MG+d55P%Bp}Eh$3B=PDUqC$2qJk+?>FVt3dBO&5l8zyJV2Up& zz14b~?9iK{t)+pl3p7ngX`Iz~FaArl`~H#`&A!Lf6rU1JVfqhqnD*auXg93eaqxZjkN;9XkMB;iUXt~7^kBUl_nb@PM4)8 zWe=8oQrJV@fTBoW+!Vm(QZ;?{%Z%eR=XK8ATZ}V@wlG|rUPdjTAE072k~uX=F3RgQ ziP$^RIeWU1TKI_c1g@MAv|`0;JI_v^oj&JfD=sIpM8s7QB}83db)k`X{xigaMh1PP zjtEIeR?ZfpCV8iYp=_J~6NE=61!RaNC7$SfH=Zs@?z@8SIkRh&Ne!}v)Sy*!DTpov zCvW}){nT5lO1;8|Dw8Fn$jVdI$1xc+OY-;94%un#Slz>4Z)%4@R@6>aVSy*_c*fB% zd|L>_Y}20l`9!Fqg}irsZE1F29qH&p3;Ke&%9C!f>FxUP3Ku}==(0dqE{lz8!OZp) z47Gz2lzhf+N(0uePWxbun8FzsvBXPJ`7`pUJU@xbuhJ<1+&p?l_j?m0z5}e;WtxQ= zI9DNtg2qx;_@#IH=~b&=)Ry)$HzwIcWpYfayf?{^pMF}D+msu#63asz)aYHzGvOV{ zSlrW{9poxYNUwxs3xFM28iND>D8n#pObV@>C|ZGnrHfC}Oq_IKWHG}`PtyIf*Q1UB zuhN-bm@ZDAt+cSks(rTZn&}JC)tWv-Yb1aU-#GPj*K~hTfFct3-RR!K{77Hmx_IPn$T>X)<$MU z;$5+ESP~=cveT)jvZTxH4iH%=TT%_nFityMh&x#lZQ8LqHhy~OL;pw_BTue3VxKbycrsTMR^bC@k29V|=HZ zb#($5U)_wgrPO=iZ-^{G99il}A^9gPZEs#&n068wR&bF%=D1jrTI7x4A?AY2?MaWNs$fjUsteq50{L*U>mlSJ+K z7SRZPKAWOta^snJKq6Xm$;agG(;hfMpLsKdWenZVrcPU8fwWUZ>K70texjYLVr1+5 zVu;5)$Rwz16g|YFY+oB5Hl>aDT-EOk$>(IPkV3QG3N+Ov-eC;tkn(Dc2~-zH3d^zYD&LK z?h9GAs$}!Y31d|=Si`$sY|_+2V^+h{#~0Nc{Pw}9`Z1c#6rp>MzAsu-4ymqNEi<=z z%m*)1zQs~^<8Bg{`0%MaYmkG%3T%p7l?pgp6L(BzCz-{H6zm7Y}#poZOvy zohIc?%UH=LcV2c-mE?Nk9`7AC(BRQwPS%7d z9h8!@U#qFz#Wx8fFMOF^{j(LFAtrb`@MZD(v&m$aIl#1UlO=P?C1`_Yz;s6LEm;8N z>IlF=wzk=aXF+d`*;VTrjr6RnDUBlYyqOLGEOCl zX35@oDEFNSE~vWy%);h02`8d;QdSzAEe(++%(tuBj}pN>txgx10-qvC+O#p3npXuo zRz6Wiq%V4$!VDX=>L6$&?+!I(>=;jr-?pcPjxfHQO+DT6x>Ozq)wnUujB|IOJy|wz zpGX`sx>r{ci}u>@eC5HO@br%GbWT^oG`H!hl?Ph9uuDIfep)~V=dcB2Vrzni^Jt5O zXLx$GYRl`))m*eTp5y}`bNX@v&mV!Nnt{49z=Ao8L!p?K@fIb*cVTb9)%};H&}rcb zPophMfp)Yk1^K6CDImPEEXA_3eTI~GB%dSJR-9;JY{Sss9%p6R$64te76tY?D}_*Z zR=NyTLWkdNL)wNp^cFl>bQ`-sR>8a}a!&%|hrk7$m)&8;4{1>S7Id(#IG+)3ozgB9 zBUpo{1YL$RT{MnP!B42=HQjoJwaCJHIq?G@;O6v_EbP6+nFN(fD8#Z<$W}4;!5LKs zHI|+5Cs|a^=X11F*ZY{MmIq|a!)84d_vsU}Qyq?8(;X{*#CH$M^9dW=rz?ql`|P(d z&GX>K@N`djx?5Mu@6h$!z;|={0pIP?71q7ge&3{TC)%G2xgnM`UFT-h~wha;{us~Je{x@jYvs$UszEs3+WsBs<`_Ifm8aSGGLMgI7o{GyQ>z4(; zshR~3sGb`HSuVoB(RC7CNIw&00Nz9ypfyp3z}9*`32dp&0K)=0St+mut5RT_E7;=Y zF0e!VoH%+Qof|PcL^wNeA3!*Jq?75CtO*g$oc%Ve(`A_xdU|VkDhtAfqH9h#JM@G8 zTeOh=TU4(Q*m;Jv^sdNChK8E7QMm%r2y%hVy{l76-@3q7lB2!l0$XpH9}UqwDBOkT z-b6D>e1$h#ir+><3G2uYtYH`8`198{B1%Fy%-?wDRDP6^jZ%)JY3#X~)Yb`FV9P>b zo=RYDDB@jZD2yDfJ@e6+zZD?(~!8Wvl|`m`JSQQaIt(6b`n6rvi_4^A;zf z<;IZ4=e%VL&JpVZl5C%n#kyEa>HMUW2F}7lsd3ghHO}H`U(N#KW(pmKvv{>HXHovx zan=C7iqgaL6&wU;kDjO8lS%G=OvH{ondA2Q5JrKjVW7Ue#mWvM(Bhem>3Q&97jF&a zyk$O)b93J6n{yW^{z=4JPSyO~ig+xPXg06n>E=nFmV5jpEK`dSmRR~G|zLrgh3p4;Al(o8piZkZo12*Q)A2}_Cj-i$zN6O*WxrNr-$rS!b^^VR0_ zLz@647sy4MmI(+qJXigEu4E1d$N39L@mPQX0N;jbj4ws3hXMPFhT6(Zx{mptXFJ-o zy4xlNj*pQ|>W*ebsSpgaW{X;GXYNEej7^HkSg}dvEC>dqX-=M+O-lKVD$kt=hGucI z3K0~Cu}OLQB(h1-ot~40&2}{Qs8Lx+&>E;g`&*|~4SIf8q896Vo^;l!t+Whcbsp<9 z>b6d`GYi6Z`JYSz@07EJetYoqas zU@g>=>@+0~(ZXsHWM#QF(m&L3k#_vAcD)^yg|8iP%t=ZO&M1I`S}DhT_(XJ${kq?) z^^a7XUAu9Wl9w9eziKvPwyKJYt?i;>Yda|#|L41KHS^OF(pQm_$ogw_J4$}8cG?ZC za#2~kmCZzL>^UwQ!!b$?ot5ELn%V<$ZT4+8?z$ezTk!a;SdBKiCw$?j=V*Rf}g&9l3M0d zd9RE#tXJ#%cdDmbhN93dTaSGNy^7SQ>;5^Ps? zI@|~p)5fLA{s3h9dekp#oiI3Y#HWq%N7h79j`q1`AGGJ_XZ+d}aq*%?WSevQDQlV; zH73}T2&Wn@Z|#GZY<(M}fGF)mRBf2-4_V0{T;1AyGL$h>cK5e7DGz1EmLv_2@X>I& zoTK4kK$R74a@$GJI#3XP3hfcwXBp(^1VI}T7dZ30(!0F7;)l>*?;@qL|dWj@0ifm|?MHZcR1CJ2^%@TMyI1hD$lQ(<7sj|wq4eu(ebTU{ zg@09688#skuU7}>_BuEP-4dL2=m&6ip~=Ci!b%4moGPsJ)WNC3%8(qKDy)DLT2v=? zu#u+Yw0x$m218+`6?XFsg_ZAV15kgx(zDG)VFfmDd8kCEn;u+o{iqOj7LT}5G~GmuF^ zbEt)u#0qvoY^+ctJ@vCLR)A_3=`m7DO47@T@jy2*f`KYRj2Kl`8Lbhc$|{33VpLgW ztVWC~s|?kMQDx;wHOd`zViawb#K`z6)dMlAu+pv*qY5h>aAH(prKe7eDy$62iBW|W zRMSns-9@3ZMPcQ2Cq~t*e8`DWg_SOCE?%#6ex@iap_0p-oGr9u0 zaVDR~rp@gaEBXUtfM16tKal%`;*ncwc-*d7tkX zbIvu_{?UE9^8+HsV4uC_T5GN`#~i=r7-NnJ1-DNJR#9Wtt+R?6v+th-b%w7TP-hiA znT-g5!jl;x@(hj8XpWD=sWE%qSw&A~7;#onV+PWl>GcfwjntS8Gsx{IHRuOm#CREm z&MIomfN@q)V+PFe^m+!&W@^lUaaPgm88CrWBHwZsV8l)tFwQD!%z$xLQDX*-vx*us zV4PLdm;vLgqQ(rEQv#cWm7v_Y3ozob44C7oF#~2ZHDX_C8aD@=FUR>P(IaAMoY$PcHMz{uBh5Mq2xQ-%&> zW12E#7#Gu&p~9G$rVJ6r!!)&M5DKp8urLhWa&VX50|%=y>(n_|joHUf8egh01JXHI zjoDzh1nFwbs6ZHY0gyEwPL0{?&cQsNf5f`D444BQ-m;vJ)tk*MO0tZKN;vCGsIl2xRfvYjYjB~IWGhm#9)tCX} z9IVC+80TO$X26^h*kr(UI2gjtfpHF2V+M?Kuo^R9jv3f$%z!zX8Z%&=gY{$vOyJ-s zP7owa(}XzLNR1gVkJ%^mWCqOX)R+NtDm7-noJ@@wFb}J-H3JqUPVg>~=L*P4b(?J2 z%q##=e^-=1wX`tn=_Lq)7EqsBm=#(We`*0Wv;ahE5juL!p(?fn;j*`N)|h0;&|+dG z!-&b03>hX+GCY_xX;Glz<4MX^aR`=Hlyt;SkR)B{toPN&8U7?&Y>G6UvhdNKp%VFxA(w9O>D_O?uWEH!4p98HZGFh^2j2F&5q zm;rNlYRrH^a^wPS2rtVz0;mvh_~yUsRd=+WiP_B@F9hs|Tj|V6BW^z>E)cgLF80hKZa>hC0bCFV&k33{&x!jt zz|1y;#Lf~A#?A<)8Ply`UOZ~^-vn!)^XTi4mtrqYpZvGhLwYL{rmXf6YW6}W91zN( zJG!GnCuIDav;;N159avVv7S)N2`E1`kl!m^?H#o7{-i`vIa0^6@-DEn8~t0fyI!=6Rv{331{w2 z!(OPkV+1sGX=pasF3Vx7HF_!0EyHGSw6LvrU|Uyru959*m07S+rqW?EocURgw#g(M zhIkIsZ>I+edL7ne)6a@x<^i%fVhszsax5fawPh^W8!Z+hMQa(SD0aev$?+*H*vJ#` z1+P4#?H9JlC@%^70v@47iY(^1nhsLJ2R!L}f|Eo)#-#uJh81$>MR}6h!IF#=W!{n_> z!)p7q+#-)fOx{t{$sLK4cjWwWhvMWNd1BnLIC)2I5qB_VcgXw`mCH-vu134}13S(Bck(Gxviuo52bkeAF|Prl0-BpCP^6|N~0 zb>(vlyM${%qmYO_m9sC!=rEnH7ldL`F)V;wwZ9lYK;xVpNDTaOng%lHUem-r@E_`9zv zZ;S6g&DA#*JgIW|o8BV_g04 zLGtI*7Z_6fbow5XlYh`rbb}C7PU>DW68(W|G_dvZx^Z6~Qx9zvavz%`__LRc z-*N{@vulflVMh-bR^)I5lbynAoQbU5Sv!9kI#9TQZGRk}EOg1}9xrQKDwD^{|Ne(f z;TKIky2px?avrq3qd(-7F4neXkfi(3)rAH?j6>6`5JXXU6O(RDI80*`glA2-OTB5S zR>w9l|MW7K6sM_sFBSj_0|fx$f=FYqXE-&Rn_=IYjfH$+-RVIK-dR{m)V*8lzW3Lw z`=LMEp(xA9U#SP&37v(0Y+k_zNWNCHWG8W)c)y4jg4rNf*>7H{o70CzGt!NiYYgZ8 z(wiQHz+cduJj&nEAEjyPjXvPNzuq78$U`6Gx#*mm+zTAm14+&MKPWEQ+5Eo!T_1hv zeInG}<>ekS-BFpfYf5s(CuiRd^X;q9!t*%h_iyz6Rpq+Qj=rj_`NNG}{Q1-0wi_dU ze!;7-49O?|;-9_oS6}yz!>_ZL3@C(k)DOSZM^8m>_xM%K74t4&M_>PS0}c-alnQXW zpj7_sUSo+w>a<=Fn2)~mGlE5L4i8YcuNZwMjH((!r8aKz>_`9fp3ognu9xdjE{Bkh z`!x=B4d4r3{kXc>%}@Sl0AFke@DKmxi;utIp|>4YvI2M5705IC#STfz@PNW~P}tX> zdTm*7MKG9R8vD&R`M=)FHPc*jcfIUTLS2~{)q(BnFcZ6rN^J(~K~{^+?w1C1u|o)S z>9lvDi>sPvuk4`9j)Pya!+OP)FpQrF4}ZpU~ch(6>)l+C|!9a-3u! zIyR$4@@hVG1Ozn~Hb;JgzmWj{@!O2(?r!Jok^lQOpZV)kfAHY%-JwZ)#!%f~v?F-n zlmFkZ-h1eck3Xn=0^4NwZA^A2+e!P{7dF0n>VuDe=*u=~&ls}%Qaggb{N-Of`M~3+ zUjOJe*?pT!yQ9+lSCvw+U-`@jzw+?sKlh%mJ+sK}%Prac^oQ?y&ENjYXCM8qCa<@Z zY^!8{rz~aFeK)g>1|Hq2;*r=DX0u{k7URC{4jh9=28~Yfh&Y*lh@G73FgWW(E$GiZAnR+_KH!Hr~a6 zuNQSvYe`EFJ7tyEhZbBScEAQiOk^IGWj(yrUcr_N+tvm$Ph_>FYcu^)g2X_pf}WNH zzRj&hA~QzD@)E;bozALDuzBTfcSC0lOD z(oSo!3TPS(by-Ho-X~L?T8SG)p+PfjVOusFfBUTFu=zQt@6s{Gu>?IEE^TJw!&ekT z9;#kG?lpGSbZ=+H_P>B+Zv60$D&V^>pC$$HmUvXN-2b7b_kXPQwSlbPls~a1gVGwb z>xc!uy~g&}B^8zLzk;uP^PAPnn~hSZ2KJlBb&U8Q?ieEU}^kcC7Xq0TnHli{^jM1)|N#M%v8Bg(_>{f?H# zQ(rkr`-7XQ{X|98O|_HI7+>Awk&#hd^J)AiQY(ISuim?=ycXT5)%c12)wp_W?RN`* z?)SSd;wKb!4a;+{!MW6Mg5}bsG=rx>IM#AWCt8LBD^;;f2q`tl&JxebaR>X&&3Cfv zK(+{b=wCl6U`E_q)Jz(mX;bw6D<=oNg(&1s6loK(%90;s z0-bQpvoQ{k$%~=}b4PW&W%9$!b)`XXSCv=7nWZM%UhaC*bmZYfAldI5p7k(OAUykf zSC!YuzR6&+*JqxxvKzneXVa8tk8AHGGWOiM8`)3LsLVrkV~rp zpZXM%N8d);NPzd6nVPbiqIE3H_GVSMX@WNkxYO^u7F(zBX(+tfBOM7$ zpnCM~gDsJxmeIIEiBuD~qhVE;=@7Z@>3{$4A0h!7^v>jc(@7#vIe{fWX3#n=Wr-#H zN8u48_vmJpsJl77epPvk{bc-Cl{fMHUU@N3M#phe3xduBcnXQ>BN3iVAn=!{&Rk?A zLqK2o{XlZz+Faedlo;yH(=mj1eSxt09{H*0>vDy1X#uY}0Q5hA`zeAX z1?(X#@vj(CV-R=aQJ;(;Vdm=2%m~tyw9uonxudAS@QB+GAda=VHmR|}Ssu`eVRv_@a17PcAYDK`3^1hw!h|LR8H=U@A=*$nd+TX8U; zrC5#@TX8YCp*K$jJPlq3L7Mv)Y+=1s|3bO#UqElNo|ls(`WFm?EcO~pwXDruIK8^V zuVD5cDo8%$Gx!xA*@8o%Q030c=J*x5(m(SnWNwdS-~7^`?Bl!+j_cFQ9Bt)BlevsA z#N{%Qo?YwlxtHPPcPD6B?vvOzCn#R2&HFYtFzCWP-Ek+U8D{R}BpAcN7v|&~#^-S( zQclxemhc}m^#QN`H!xBCDfQ}p&!a2m_Z;9rz;{^bSrib*LF!lNU>85p9d;Go(pf}$ z;+T56s=TZon8))pXJ!5f%{1-f50gS9C%8F>a&rzZrCILy;N~3WZcayyTrG+h-ElxJ z{8fG{WQ1=hs0nTS*;y7n^N1h8ou!b^=*w^0*x)@oZD>h{$*D>|+1>ohaYOC-K>Lfe zWhhD*RW(W_!<3Y&j31J9JXHE`kL0C6le+(qouZX>&xS{Mn)q(*? zS{S${2femK3kLXNs}a~@L1u9jRuwp_g$dcU$_NoAf1QiTSXO^hK`DkiK%Qs-~3m;}a0Q@6QZhtrSx@8*x9n z=OFUiv><*QBEnLI=7hpY8@6WW4ovQ?A87t%&SDWKlh$syeSCQ)GoiauypCJ=CF29A zK0e2lx$AF;Z))+T*06XB(OjPCgx7#?pNH4b{t6D!a1HK_!L$?4JWi8NJTrk6gv4~v z_lT_t0-W~OOTT%D%|OdSY<%Mer5BJ6PpF+gH?C3nc(Im$pU`r#Tb|G*IdO$W{uf+! zOEN*MDYWNER zV)2*rm%0&M9|UUK{Ilwr^>xTwIApmap0}XqRxusZrFnP+ryAi?UOHP|8!f>ZVOsT+$Sh#AD<^^pL~+N$6_LQm%5Qp#OtVI?mHjbAf?fWX|`$`%*&uTf0Av(5i(;#IAYtP{kLn;&P+MkvPFAdi?9dH zHn@0}pxw4;x7T4|Z|;`XVGsQM`N-PyT8C|#d9ZVvYPY=y=WEo)b=X6%$s@hlI_!+z zgY&Ww-eIzKI>&a~LfH0swRI5AC~KpIa6C^+eQGU)KQURmZ6R!XYM-zJ;n8^(!qJ7Y zx}%Co2PfGrH*hyEq)o~dp5)Q{6(Z)6MNvJlZCLuVZ@e)2^LK{eg9RW4R}{B5{U6k} zxcwWrq^ zY_UB`MBkSblpZL7l5HKMFQbn+Lyte=+)Xz0Q4n_C(vMsA13Ioad48a(L*y z;US!#OZD>p!yo=1c(ZNvr}h4j_lNqi`<3INo_m#gc#VF&q#o|?-TAHq@4X!umTutB z(tb8X?LYX?y>I#tH#EczuD^6#U7EMnTn_ht@^%08E4`Q0JpG@;GsNpdGfyZ20k%lf zCk|0BjozoKU*H0S9`B8-W|@7Zc=WA8NZF7BKxAClP;|d8nq_St)qWr40Sx(N5emMr zsD@>p{bOcM+lE3cqijA(!;-uiW%K<9=-7UJk2ZM~e*Py2DE_c_b4gi^$v!h*cbZ>!i5qGnt@-el>4kAxDAcpPC6PUWkqCL z-f4l0*J*!^?Xesv7v;DzCU*Fl>%x*{EYOPdXdF#U`P`5jXRwdEjt z2C=*mPjS}fcFLy50BxVncSMf!lbEvkz`T^r&s=9<)f~Mt?GDsq@K4S@hge7ybWnpNdo3=2>nX(F|@H;L%%jm z<4EgF{#W;}DDLk`m$A)Ly3Bw}x~y_tR-wyw_Iu@kz4V#TTh4_Z!Cm?~SW4$vxOt;g z^tm}oa#p|j<w>Ayw(1r>P8nvbBF!mcAa)BHx zMn5Y7Ov5pCvR)o3#}@QHT8`eTJIE+n?<*~HZb}#m=Eo{_mM{DuyT^&+ga6&ygW7L? zw%>xR=FtIkVZV99M6-v}n^(8Z0{)*kKlM0Ujv5ZiX!@@J6AK_&8FdOB{~B=VP)Q#J z;B6?C_lb?fXEq;?kOJ;zjYrKh#-rx>@J$X*j5*Z(;U?(QHoF$E_u&>rHE!LD$Db zYkZu4A=^mU+KTD<6C!sVoL)ot>tFzIMi1FR)xdK-53%81ZGYvNm-`LaN`LBAF=8OQ zXr8FWvBnQ@CY^1`z~0P&BZkK$TrxVx+IYqAW_FQ1uH1Ut9$y#r3cKWWlr}bytRYLV zb7Y;%glqK7NWaOZ%uvFtbf;HOW`Jg3UR@bFAzog|(OIf;vQX(sATFJBD81_8L7y#x zMF1^=sh+@!pvCV(2fqU>sK{(4uPN&QwZ}=6oH4%ExEAl$BmQlp7&Y+y zR$i$=CsyQS8l!<_kv2OEZ`;=K+vHK4qpM4Qpl4lpuSc>#?q{SHYF)HSTGuErxg&)L9H6@t@DIw z^?U_H>jPGL!ycMa`sF^ocbho1H+7Q_o$eplV+mj@ukBL^Ds5CaoK@Ii-P1>_Yx$$y zxOFcx??kH-v7Ui8Ud+7*QXtGX#WTnNG&mL5CXJa?a7dyGD!5yJO#~dumceFb>Jhet z_(V<+!Ckft=JuiKd3GW&X*qq9uN_Xy;A0DA**cDnF13y$&9X{c=@0cf1Yt`DzPUlM zeOsvSj#hru9sqzd;0DpcLi8imEiEj#>Ahg4cS&6>b1_8JYJUeb!R#@~HNV!49ZjgB z^JpMr_B}=n)##x89qd2-4OsRNd(x#S zwchAc?HvXqQeKo@#M7KPM-eR$LD{x|3Wx+(A+73EK_#S9OS2&Py;g= z%*TU}uxPT((+SU{*!J2Prl5?DB&LBU{gJk_Omo_z+)Hb|Ke1bPUqNRt4 zz?^ev^}*Rgc02bG`S5qm5uZ@eQWT$mvxxW{M3?In=PWqq$bpK4$~kA+OiG`$>X8h*aKf~Hp;yH3;8`krv!0kbLIwH@XmUfT)oFbHrIOAN?Y3ZsnNwsJ=+ z`?N&(^$O&^D$*}69k0|o`ETVV^$r}w;N#Nqvi<(iOLcc=z03`M?8unI$E&WyH+1mI z@oK%QK6v<*YPjLOucTu-;verweN#S>WAZw8VHfwNuyO5jMox>nF=dNd^xih-iIQjQ2P#{C8!|3808&~ucqm`a0qhGcK zM*rhMZ!wlcQ)H#xxB+ptjBVRBP?|#+n?KYQOpdR+?c`PLip=q)HUvY*@ufD@tQjP6 z<*zorQ;8ZvTX1~cjR4SpvbugmG9!7pcDFJkb8Fc&~ULw1UJ#6k;`IYz31e zhHq?3!lpqXyMMjBr#Bu3+Jw^kQlmhvc#Bh|F9_Ajl3TXGw3a|`|l1G-(me_z%~z=-U7LL zWW7A>R$H#O4Dp&DduU2_YF618GKZX5Y$uEFV+->t{B0 zuN~M^?Z8T9#|#yOPOA1eiuCz*cWKy?{2U>Y{rWX$f?@VuCw!i@b|5xAIL>MZR<=E? zm)8!oN$6k^E7bP*^O=5adzcgWNZn|o{(BfK^gW&`WHWsOU8EiaotL;70 z2KcH`eb=Env5p8<>>4ktUhGP&7rPSc#V$8gUF}PNEqCh0s>lD0UcA3&t3Q4H607q& zQ7=}{9!SrAmp^+&af#~1E_W&e%Yzr|#rCDJL%mq_a7*f8xA*Y;;u41Pth`>V^|rBL z^M#yvX!$z*4elzafWbf=A{jvQ=uQep#b`M7y5BQI>~Xpx`)N>+SN)#WyR#I zJ`^=9q8_&5P@Q6Ol!Tm?&ezF_6eP1n#J&8GU~kI>aW%7;oa@5O0&Ni<%4|I;RfFIg zr~utT6^9`Ngx{!p91-%Hxn>+&FBQ2Rf}USy>tt3;F78C_WI#hmN!aE>_@U+29zTRV zUhOe|CQ2bCl`>88TSaz+vgY%ni15tyTXl|)O2CokF(ZFtojYtTvD&SA0wPAb)5s2O z5%-J2yRtjHStXz)2l(fju$THN;6%PJo)a@Ze1@v65h!pFVO{5!AhhL4gpj^wn@AuU z5iNYz)f@mKmAIo>inLW$nSIPjDm|*MygCxxb??@CAREm3!nkS2v{x08 z)Mt%n0?%PIdO|+~rYZDd%UGV=Jvm46uhDMn0{&X+bXQZVf8owx8>16BH&1&6c~rRc z>_H>@Beop*DVVK54tmGe=(Gr_O}crJB9UsAT@Ck{`NOKDC@9iSRUICqPbPh>6qu>n zdll=uUnVGwXBbCb*xjD@nn&g}3N?>-*qPTW9NEEp%?JPaziosHN2k5AyB(|7oOnF7 zZ}hE(ksZkwU!|&nS9Y(ON01gGe&gfjnBKE0t^2i?W3#%tJP5i(o$HDH#+YyXqiz#p#M2v&zW>3E zB9@_nz*^%!s~-K%UauFO@tjARY=4>X*sF1=S`|*ntZ8C)&QEx z-Wh$!HcD`dp?VqT;pou4MtW+qC4M<23V1gjb-D8QnZsb}h>72A8Q4*H4u?$qj%Asf z4b)*_xAJX?Y-=G~`E*&h>t(fsgUri1i^Z+eE{jLSOxGCtiOFv5jOAu{kuaQGM@SW{a3JVR>QpHUK>n~FaD z+K*pX;9~`Lle7nt4}l)sgH>}9aoBND-0Uujo7_clOV>qVEE-%Crpf|81`ma)vebmQ z>#}I;pSVRJWc~@D=sGCU=jS;nZV3(w^#o>a&Kwl#tmC1$C3q-qn&qLmrIv>xbYt8p zi8wh&!9!sTs)?AoUz;Qa!|UZOqpvI5D*z^|o5q`_-*^Is_wfnmV(DfI36O7S^|slh zF*YjaB1ACz0JPv-oL6q4w55y!GKx(S8JMvcUgwVdi+sbLFtw}4lYi0QwYa7=%X=qv z$v@G1H$%yC^kfg*#yD)D7qU34Wfx}_f~Ci2ivU3PPP-Pu5L|F00Ev@?;2>}?H1~x@ zSOp;qfEGgDn$5jnmLw@5cyBlyfG1NZ*3MUxo3WUVCt8o4g$?mU^Dinr3fM>$HCGpZ zxKegf;m&;nxMg0xy}IU$5O|oYk!tP|K2^#yp%U{iD$jv#HRDOaDkCDaCI6ywCqi3N zu_YNj7!E@~5)kz;#btRGl(u2nVFUmNXRqci;w$IY2;H%V_=sNl; zZ4?DgN>)}iBuw0Hq91v(Loa5?^W?N6%D-a%NA6GiAFY4k&R|o#m?G=Kwz>Gg!!-g5 zcN&|UCjE4o96vbH zsKaZjo8oZ)qIpQ&zbGQf{flMuICDGgUo0E8z|HV4md&Xm6koTHv-=lI^Dm0{Wj>d! zf3eK{i>3P)8EW(|mhNAq(EEGjNnC8GslIrrg9zWce{nG@sxCaR<-nxmBx_0Nf>Cn| z^VbHQ+vMQ8NghRUX5G6K$KuSAA5CT-@n~AL{dC!`)Hd^TezZRYE*gE<)>*;vY~K58 zM*rRAJK!PNYwba&jJa(GkbH{2ILkA%4b!hZ`UOU9S|9k_N944vEuc#Tz;_gYZk^Lw zG<%TPmzR6|ak$o!u);IqSSi=|j<}}cpLG2^T|Z9_ZYD6-UQ_0WQXV$rLU-k~ zJY}goPX#;9tMszXj*|yJohh2Uoz(Gd5b$_1+41i`HQSp45hQEjb6LP+BTwp(&L$*1 zc{m`M0x}zAUdvQ4^_IIt?H;$Ad1sT@f*pS*56W>lLqFccEiAsV+`{&VS!{X%yY4E^ z_YUt`Aeh#ZYJC|$uy1SynvMwMZCX|jjDGevS-$$Cg8F)QFW)GS;Y5}O1`_LV_ppKi zLe2gfLyDhH-^0epKj_BO4MI>k!|*Hj`2)#m*+0;*_TbTJr)4=^!{55>EUGw&)3WQ% zlsm-`3O-wIEq9734ae--GFH>vuBqhDXSlgX#FjSJlvY%&(=vQ|SsJZO2XV6S3yUf( zY^C)y275+YuRWZayUY?svh<-6H#ClT%r3bbmIuPUd|}m5p_2W~dfrV%%!g!~(gW?6wYDh_i@a}g+w_*R+otVDz(@Li z`^^*fh4f9AjW?goJiX3yif;@NyE2)l*TZ+fw~vUOo2Q*UL_CKjoeNBS{$-X^Y|vsU z2pyWngFOHWc4^fBWjAPdki=DeZlkxx3v89|DQ+jvyQdb{S!yv8o47E%`Jst>Z2Ax$vSx+P-2r14H^9^ z)h!F*VZGclk1BCwc8n_USj}_$-7DRUo?ek^tv7PTCLNYZRn)jA7EH=iGdUb)={7 z$QYh^N5(KL?lGzhB1%iOCE6}4JO#4>^cY#>%h?$lqhwU*9sNOUQWe+K*5!p6FSfZ% z9MpTSP9A-*wQ^wIWX-%W%Sn8)HZjgSWXky5$yNc>88%E@Z*0e&Tq$nH zo*;YiR>r8$$kee}dT~c-(Q0(j6Z)ALRwY0jIRl?ueZfDzdSN!w4bibIo z2`DLV`l*P?%{#jh83nyX?Yb?dAQqq4Z04kem^@i#+hXcI@zV@@;u$HXIww)i6H}*p zy(*f?)V4?qh+0zVW6}N}u9I$4c`QQJ%+KKlSHMRno3m{sf|Jdo#2@t? zdqkF{y@26o^8V)dI%&4?h9x6=2=ZiHB{0E&*IAYUe-F^{nup4m%s`g?sU!zah+N9678K6bX+%)#NrG{vPdU^t7H_HVScB`v1 zw0PUuEx`kHlN>-L-f6$m7$UCWvpF;m(@l;#^2Lo#SLqkN zclM!3rDREfHgt2-)Mt1cpJH0@#JWB6w^No)TKs%HlVqb-l0j|y-x{PPS{SN&3o>beS9h|;-O5Qd0ib_|WnvCt)epv%Zmg+Tx85CKo?TVYhdpnL zer8wEu4=ULU!-EhmiDOLGc0sXEt*ZD>6uwb8bzV@cMI*Nl%pL7knwuv*6BL2i?RFJ zn$r{=H&UM^-M9%l&X8UKLhk{Apq4_^v(|v1ySa~OLUL*W#4!RjVVC4<)X$Z9)iAlbE z?nj1vmB!2d+A`TOY;c7vdA2r=;l%F9>`rlt1OX0Y3SxA8Ax4nYzBX%LY2Sdln(h6N{7-HW z8wPrrzeBATCSAuP^Bjj>?v3Pn*yt#i??HCl6`wdX{R9(RA6VSv*2@amgSZMDkr+tm@(i_$k>$ z3j8H{Vo!YH5-u!L`3H7f!V`P-1f{LAK6bTz?23I{EI{hm$HiQ%`&TaJ;mg#=MS8+y z;ScP%$hxEP!T^8aw`Y#z;)@x{#TWN4?v6x#gpphnp`g2LBo}fKMsguf*hog5k&N0t zDCgzaxS%tV3uq1_xqydlBs;T_?4+@;;q3?`F{10t#ApQkqfvj8_yfZvX;nTh`$6b-I+?4V{#=iBNo z!0%d)PUtyebMmGXEOMg+dh^f{1P)QB`vk^FY&P9U!pKl5|YI6&)%9joUptM z{L9Pz6A2EVrOwA_S0Jod2|``{Rb4E_Z!0{%%5bNEr~ z3I2g~2kPV>p3TXNi@?9Q*cY>B-&S`4etpE?r{@fQ^&Q|J@Pxt7XR zXz^ch5#UE>IsC-`68s9h8U1U)H37f4AV{Ny1;((j&|m0|K@f&92tpf!L71eGAPi#= zgf<2s%*G(FLLUOw`Y;HSG$L9Q#~^Txh78;wje6FdmW=Z5OqoYr(M(^Pn998?iel%| z)`o?j$R{|Pn~8CqvPaH1Fz>}i##uK(oNH(&?FvJqGd3PKDSxhmBOTzJ21kJSY=b*& zkDPIE-ir;6EkxPis5xxI=njs@&uef;<(E8%nLBp&!99HT!Few>xZ|C{otQZ|9zU|gc>KHucep&anWJF(*~s$v*$3yn*x;zr zo(*nu=HPgID}#e)ALiS|Dyn*0;^-KHb7IPEiE~z_+?F`4lHa1lfhmzOFr_S1aXL%+ ziB)HA2yB}Ht=T2hZJQ~-MNA3qQT))Y)-Kz0`)^5^FttZ*YFSc#=S?l6XEGsdEeK~3 zHV?28;{oimnGfXhS}W1*gdd$F10#AJy^9Q*PFJvMVy%Huqv(7n6r=15E4Kg73HouvIw?mP2yRb_8sp;!oB zO6yNT1lOMlXcbxsfXGc}t~ZWh;U|W8;YVtu7=+w(na574t4@c>>!-m4ub(^bc)~n( zsgGXUhkmLLCQ=|w+U+ZUUbT7p-I_AC-HF&eLH5#W!&G#{|7apm7MjSY)h`7eNq}cE1*4SMhq}BN@+QFRy@4FfPnCR_p#stMw1zY;a zwjQo6Fk&H`s#&%Vn5j?}W;1GI`MX7)Ji}hE8g~afTCXmKl=)xKP9S$%d)I8n5xv-; zr$YE!N?MwxEZ~VrOC)_~HFE#C*QS(q>L)l49B)%ZDv^q{JsoV0~!BE>@qYMuNJvQ#ZZOqf1P(qJ@%vl&$)lVKneCFAZAN7`BI zJcTq&i5{Ikh_Hu54~9IL*%9IhdSmaX{w!+1^v6kjiQ>BC77k)g9gm4$DRlsHV><=M z78Ss)SB#*C^k-e!88vF>7(XvMA@GrWN=5-j>xG1$%Zokg!44_yH!q6&sqG}De!Kr# z`?o<7C|Ce$z#ld@QGQSI z3qs}G4nULgnPS_Rs4%UYAhDErGr#m%rl#VCvP?~drm%-BQ&T@5C10zi$}?}a(zYY= zQuYECGpB7~qt1RSZm^Si_8{k{a`_C+QEYr=GfU9Q_FFwInMm_D)NW@YS?)3uzMYBW zV(9R6o{^LGQ0xA*XDVUapHaegh1dGv zq~^@vfaFdbPb*sv6{Bw}5X@E)E%SzJ=Q_K-1Dc$@%!#49;+eu1arvM60h3@$u`gW`&j<5o9fD$mB%_Lf- z>VI25|0A5T98F~3xu2Q9l8h3M(Il2+%uHxf(3=^O@p^_3x1{(c4<6Je3Kdpvccp|Y zE&fV5Q%bEb(}r~!))}V#JDpT(fT!QIImLjF%hiH)gn-Y)dNnE5ZE+d~&^iA@@6LqV zH>Y&qhE2~5xOf%XWWrQRk3Vs9N|ox9>--OH==={q@3@m=&U4c_=KU2!L8wnIyh6ud zQCPlNj1cRSgU~F=oNwGLs$VZ}T7%ElOWT}6mFQ5Q+)ft=1Bne5DoOTvR5Y(>N08K(8i(c!wVKZ%pQXr8&9vN%Oj2blsCyk2R`vbv0 z!ypSMRFihoW3|Ptsj|s|rX9LJ-D@4Nxqr?$k}?#&SJ@bnY+i=D6eSCT@p(;XRI^rVkPwRB(;e5WR=mMAtCea92Tyu!Lb@E_5y>kb)~WKL zN+Qmxe7N^OEPTkGgo`zrLF`}`KPk0lu)KG_&T%?g+Ci0r=Gc9k8wi5SLfu1E{reG~ zrU`eCwCafcW8H%%&4aTr$NOSr$E5aL^oC zgaM_zzWg>#BsKMpERL7xfU_*Ur2D(4mR$h2mM=_vpS*n(v@q(&B0WN%*5J3|yZCGTT==P+1`DM`5Ep$FTF~ zC%y0^zbFAYQcc4O2}rRL{!o+%;w)rOXntVCxLImUQGe}<(!?RL_({L|`7l3$#G)Ve z24M{NZ+}UfuxVl>Y+51QQ;uxYiqPZF2+OCJBU%4azv^+Wd@9?iSVzxEz6K_tu{ZkV zgCI+Ni?7Y+-4hlHH5f~EObFf6NZ$VUAK54xus301SmhOas2;uMUQI)f6W0}9P=BK_ ze7Igd^sk@fMscYm_&Rs^Q}d_XZ;j=DpvC}=T+2R<8j2_%`@;3@#Pw=u4%e;rgmIs_{ZpI&*Qa#TNR}rUt~W=j6kaEE&Z*a}Z|3H^(#Ywkfr$#v_Lt9ddE4jhB>fFr$!u%JaI>DbkhRVzrM-jgUu)YZbPjBg4F{&NCZ(IKfF92Ycq|;b;jNU z%^!SVQ(}~7O>VbW>j#?O{(}$4d-wX!Jv`SDX&Xf$Vw$I+^3J3?rZx02`U+APbEWa9)1ly2|3H{nYU$?AFvzRj%@leN(5cn0}3?t)K{359|kUeg2Wv1I<@Iz?8Tq zJUuw5(>eyt!?b_7ZQtw#4SAw{^%##l#|LqgpKPtQ@p;Q5KDQ5`hy1*irK`(Fxe!B~ z)ZgRk{HpSP{e~@$t|Dc+N3Nji2yVC&gM$`&aw9AiIs%iQ*G-#36SPU0#8sL z1t?|{hrIuawdD$& zY6|oeXE5=cO>GG7GhsG-{!IfO{j4jPDY8H1 zPt|&PT!(5cgJX3CWmwo!Jh-eEj_%e^W`&=t_ES&x2x6r z1v%m4>D8;viA8jEuil}F%+)(Km~-jjRktb}q8@zDE3z4|wSM7Uu%u+@A{i9iIr@{B z%^}^vM&f(s^?+Ff*2mn!w>loI2Fr=7>6vRXsG(j&<0GSO&}B5 zzn!^6WBL@rMfHlxyO%Y1#}nW-Ymd{kN+oFsHrD`^Yk>Q^@_x2LXf=Rs>JQRi!VQHW zao>DpN+BF=6++MrQV7x>Jbp}ib?eGu;rx}uz+XM1a`?t1H&b7Ju5uuJe2&Ti%LZFU z8C1@lCZU?c!&tooX1dd@Uw&=u8t)W)-MMSrzfsD7sqXJD>Ya7}mE#NQ3+kOOxpchq zcKc~_ey4=k&a0~vyYkr$`u+1AL3cv(A{TT$k%O;uCsi`1ZXxXWe)9-Y;HMw|XjI9E z7NSa~{h$9iwWmeviT2fFJOVYUmxoNHnZ(lNqxXGG>h=MaaHfw>jzPKBbCQ+%ds;oC zkM&#nc=s%QOrNv#vG8|d*BV=~P5Yj>7;Nq2zY9R!2;HPUqktQ|`7W_I7RJS>6%Z|9 z=2L)~`^xc!^@X6E`zLi@_b#-zT`-O>dZlLOhWEabS1x=Bzc2jJOUDaHQ#!I)^WOs| zZuCkf>0+eqMF+2sTAp6S()vDwHNYfvO^kx8&Z72iESih_*+cvc2Ga)STcHw4SOsSC z{4E(Ph2^pgn!{=lF8sA4_5f7iz&e3Uk1wf)nx{Y10bXE0|OKnAlbHY+{=;?m@@roeD1*eKBw306H!sCp) zm0ZpLld%To{%N-bHsle0EVBj7|Klu@*#ewf&}>5In03OuSY%T38%@zZsr1z@7LkX5 zpJI_aq+OkMA1ctH{hGq@GB8#)UL3}z;nt9aAK!s|He#Oux zhX8kv?slcqfFgf+bdM$|SrBUoxP>1O>ZMnk)9}jzMq2Y6mTP!B>;p_Dd6-53(&wk} zgq@QA%W0CNx`m81{iFt{H=oR)whms>nM}>?-};0aezUn92w>`dUm|kWhcv(T`_!a3 z%-nu6<~puW&SS0vnK*LiO!xi2>n0_$X%g}DWoMXfDWToT?(0tXOy^(im}eeLs#}CS zNd_&w{fvytPBxU~g`17DCMo4su7Q>{vz3~Ajnl>y2L{U+bY_S)$9WsmONf7vpJsO$ zVTV?=+^=&#v05=~cCC?ZHIS8ZLUMweo8fPif1|gEu#Ae1`WMaZGidI!t2M26^wIDo zebhX2{!wpLi+$8g&ii+%YS*CVtRnj;H|?YRO&@)uK5FBXaVsaMMua)-K0C=QD9JAj zw#^*2_43#*0Nb+h*gW8Go0Xf}kH<{-71Cz()S_tOjor(c% z-F#dOQku2nOeszKOexKZHdvl#G#~GrG#^Q=h^ymc3`>FEi-236~68!Y?lZbU;``KVSy6GW5j@0&oQ}8~n#-W=V zayp&^+lT!7iB+RI(L{Ebo=Fx{aU&B*UNpLo(&qUOV z(Psi?s@<(4W2{jN*M-V!p=91Oapq7NcQs&Ci_vggVr~-sC?uqDLK7 z8qq@!ec{hu{ei#z=KrYy^^s<>`1K0|{=57aMht^vxC}>D7@;(;PR}@5dh8qXt-VT8 zwukg(0Yz{pgJ0gEWeeSy&Nfh~leAu5D>KZ7P%q`{%p zZ$556HKH(|8c{Z%-4X2p^fWdd56F9r&3-8&q_F|R)Y$3_#S?=hTe>qyc}D9Q&2Kj64v;_*+Aae?z8l|mmZ3f|zFiQJ%ZZp^! zS>LD6O|B;}eQ*5OAI9nX&30se*AnEr@45dM-~9169DDI3L3XBZXLn$hUnFW`(I=t- zSS(Ac6HaWUF69Qq;$qFQ`=xS0uXe7RNJ3w;bWNjiqJe>w zEOaOS)ou9q@plCNgrZ zlL^j5?2ht{S2FpgH@mE(-A!wZz+~Bi;lQ6C7nT;m6s`vBzZ_0nCnQTMweGo)m3&y$(`vVf`yE<+ePW z4s$^Gf$Je__&|B=APe;~})X`)r)?eOAs= z8!`K1+{VqKswpxLcR-z_<>*E+hB}Q^dsh_XAT)~rz4$|yuIx+i(t17}9Pal9vGlmM zvz37#Eras+4#LppT`>F0g7{=$6qv)Z$Y!Naa#Q;8J&$|@5nzF+PI83Os0cghse1I+ z@3ijg@`_@l1+HZ_^6%xAELo}H8gtE+&05>E$>+=F*{OkWRB_?e)inmEr+)~7-Yb-@ zi_5>aMl9VB+WQIe+rT9G65cgiw&YloVM%t3sDfZV&P2963Ezy8-_@;alCP>Z%rd$h z8B#3vt#ncl(IUi>04BzJilNTOh9N@YBTo{Ox29~q#5i@@L`WAbo3B_y$|NnDuUSJ1 z;+G8p$Qy}6u-A-Q1ix2aF)%B=#?4!`j69x7!*vpxxfwC ztbeMHxD4bE;*>T8!7tM<$raotdeW|_P|7u)gRe)^RNGDw6Dmc_pCOJG%gpOQf{&%g z_OybOtKZ>crdOr^RJoN2dc^J5*mrZE4R?9;=3fTA_BsA}yEX0@{rN9iqct~oS>wv+ zHNTWS`TFqW$L`6V{Fk2-3YSNpczgEbH>`1K^!L9)Bhmy|I&d#Ryh#Be09DPHQIs1; z|HMb3QpRd{?0u<$tJC4C+$WUm#;)eiE*I^nSBzF+@8>f2sATEe3%aPm+X!M>_^RK)O+vF z=-=6z!T9b>R*=X7(XPEf2zrqPSE^QPRuGi&sPz*Lw;d|cNdTMm6Jx7x0O|B&Le1Qh zZw)yjCewV!%t)ANZzkc{$(rmSHb1A|-w^p=6Mg<({ziuTD`%~AMA{^4eNBXj6x{-A zmCqFBI(6&}%r%28Mc&XfY|`&tS#MVcqyGht;`@xRz+VZ`{SVGstbPE%(G9 z&RWn{3$~oLf)+*-YaKi*v=VZGwT6MU*eQHYtRSROGFlYDxgiZ{Grtd*Mv|kk2&c#wbHuv{{M=$*4qQDbB)g;iG}vmEPy!Wcn=9E@@EP3 zJe%NAn{SFHB!Z=S2t}jQ5$qRf-9?WEDOgqJD~t|S7oVojDt(=g#m_GA*~#&aF?8aH z?GQ_>YF9f1Vwri_-L`C@kunj=XmoQuHgd}Cj)Vs_8iKS4U)Fvj?EWxlRj&iZzwc{6 z;rI{ajg^+L&wykdTjxlYy>CeVUfFGFJy10NQ$q6P5y{Mz@GN_VIxK8g62_T=719BG zKA4%+biuUkNEbS+ZWV!}wIQimU)RBRph#;&TfLdku!Z619pW1O+~*6sOSR(SzO%#h4suPHWM$NG3ah*_kBR2|;f4&maIy zR#+eC2Z;g&IBzmh5PFf`aCzsXs>QUEDyuJ%>LSw#VZ{wsntRCutLtOLNTDCm17bnc zIZGZq{ZPyn4=o&lDuvSyHfT3&L`flQZc0)t(Ksb3mT7cmHc4TtdL%{rNjnFpBQwr# zE)W}?xj<}$xj=0ATu5vLDcunp!z3J-z@>D->@KH^39<2yXAm17dJ4rxj<=_WaA!%8 zryq)Q6)OLIrS%9>-)XKrVP)=+A3GO|U@AyTsz#bbjLaRDV-zjIvha0}ELSg)q+8qw z#w(^3{t2l7dqp{Ltl=<5WQ5VB^~QN$R%uD9FjiWc?#8#k^dvsQ78myu+BIGc$r&l> z@GY*F!gW(qE>AlDyhk80^(`O4AdNtoU=Gff=fF1bP0WED?jXf_tI`})Q*&VH5^D$C z&xTTf2(%l?rXuW#Pg7AL>+-3nAcu*maL5kF&l+y&1twj%vaXtGt@M7utJEeJ%-aSVq*prm3S&dfdPtye19|yxzGWY?)sHNWyn!| z6uLH_UK+AT{L+wFF&Wc=X>){0X#sboVqG}f2CH6g@O+uu?7IoVdfJ)0jI(+^;z^=B zOwYGYJlXz<$O0{0YIk1UV~QumE7qbh17^3BK+{wC4%|p$kV5n+YckbRn+!uOY#|J_ zz*iRtLv3nzc=f7gQTx5S|JnZLTuty*z%|hzpv@3WqQMNoUMr=|9PA}2twAyphwQw& zkeqvhU0@FNu!({IDF|6{?QtvPHcY4<%dd3bOswy1uO%ujfFSiBPr7iZ8Y{(ESDMfY zk&rf*;#(@nBQ5*vDM=d?10@g|x42WskwP3yeg~o_5-x~0Dgge3Db$LUjC@sE!~q@= z5z&BtQ42$V2(CzYs4i&$U*@}8egr&A#4P2#dPv3;>D$&_H!^WfDJJP=zSV;5{(p7xclsoJGR4gPCz~%=ahmF>5p zUq3tK=ZACc#{}}D9cnpOoFne0AzyaLf9vd!yI*lRGSLjI!~PcadO)2ugVC>hBsz-# z;n5KtC=i6YZ>5K5cZT#x!PP}XBtm-~p*PRUDs|u~uG6=Npp%@ZzIThE^LXs!t*^>^;pY8W16hEB=CfJDf*Kyn8f?k*i+8krEbEB}vIZ781BR7A-N|*j z(22M4S*x{SstVX9**~E~BZy5=yE!MJRG*4JE zqJ5e9=H3)q$%m*w7oBU-Wv|@Ehga5?gi6^#d^P|Tu-Kz~4v#E3Y|EOMWg${CM%N26 z(!RM!trTsMrnQ?z?zua`z2N|v*$!yC!kcovaygoORfY+C73?;RtIaVGs$$gVzH_0~ zex%j%+-X(u=xJKr^U~(WM5}wYN~>U9BES~3n)5wprq#y-t=^N->cLlO?qVJpKwHz{2gC0*?WToyc}-16asJXLFRJ-Y^)y+6*b0pw}*a%EQ5 zi(qO%Z3C03y;~`Y5LyrhD{vbwYYHSF9@s1(_jScusNSKFo)j%Flk0N;;kqh8yR%+> z@fzEl>E(hTXqTvDiJ(1eZ!3!7gpX;hwW1V4`=Ecxzq!(E^wLx7dg@NQc6e$cbNaQS z^R8lF*XSt@GE9B#4NqC>w+&zu(5Xrf%E)FEawKT`HJde%v(@OHqfx-hP2d7n0Shiz z8Pe8YyFgMw>y40=7NH-OWB=E|awizc^L0ykwOdW$l{> z108r!LBZ*`43>t|_JP}3dtWL8VLx6${(r$CV>F8pqDW>4A+9YM^)5mxly;1dqTEIG zjSA#Hj(#a#e(TyWzgg|ue~14^rN>35&)eaEMJL3I<21R&9#L9BRZQ>d(h`1I3cJ& zj2Vh$>51)BFM%E#``V%~V>mJDGMqqVTmJ+ks4qBMyjW%vT`$?kaAima5T#d$9tqXw zQB@DpZpc0Qr6ko-n_N|>m@79{bQ}l9Ga8)gK%cdWCIxB_!rEg;I^qM*bl7oIi-wb~!u1z$*appk)=vKJuJ`lS)L=abI{NSZ)eLD9D86q82ohiyz&vL}GPALL_e7mO5+wmMf304Yo@GdE@`is zuA$GJHnp)YeTjR)W2DJtQD5+kAZY1Md0`SVO+96i z`C3bO+$H9c&u)wZ0ndSig|(0i1)?SVVvEfv!q2XOFGe*M(wr@%Ig22M6Fut%P?G{( zN-Cq0g7>R*E0m&F#jTI0{Wz*)s|YBtDHSN%m+nG1ioonE!tFg>8ZMDPG9N;p8S{6X*{_I$tPO z(?U_i+5QIzOl2n`(voREpH>;h7aL~N)?@z|Mk3gR4uK%F5l+@B(WmO$ZUsLqa{5{ELVNKH0yuCL68 z&2{2mpBoDsLJO{fX5u%H_O%hebn^L(icPA2I%_Z?kVrqHhVw&h7Vb9e#+0gv;Fx#C z^%ij4%p4+aJ>l`@Y>1C%BeEfWBWtiBQpn#)ARl6&^{pheOpwsiF-}y9#(B{4Hv+-j z!@4puh7FVoy{W+l`sUaW2I`S^=^nB5w|uBT<(5)lo3qkTdvsY~N z>8xR04G(1vX6QVaH5lhTkTn=0@6Q?xk@uyB*4VKenAuc`p4MzVl4i@~*yE`a6KxV? z-^iMfZ9|$KjZGPG&a#}uGT<#Yo+jurY87L?D9x>^a1w(Gc(L4)K8qysIY- z@&2qS4Dr6$^zAZ48B!0HA@k`WJ4;uIMcvdVfF=0}Bb6;BFI_8GRuZim{i7Arwdy0h zUo?1W$Az!Pw_tC8+nILAR@#r0vl1Tx0ryrFFlz~oL4AmPX4$K@Sn3$7%&Xa3W~|Br zOV`H!zUVH3$tpW6+)q}3kjFX~|J*OV7yq2r!%!$NX}QROmbP9VFZe=%ekLqIQf_Rm zz*-uoP+Th*6S$3sP0a`BkB-eyvanWe8f$SI&ApY^E|d#*ET($c#jU=?6++}B8QVtj zIa^HZJF?VNO1aos+QA2WlUNVFhF7IMDT)o*c9dw<>G|Gxac93G-xTy>?flRVa?5#( z5Dm*6s0XuZ?8$#^U?z6_eccxP7zO$g<kiv1q$7OWrKiR?_pgIA2gWSM(WNN^3e#(`Z^jOQ-e_hl8&1 z@K$nP@@th}d+pZ_Teaa!E}Abuq!s)A0}B+*XK2_VxnDGY%+FQ-`B8qZ_|NYr+1!79 zPu$yrvmtITdhP*gwd(Df{Sycjh1hfjlHf@#t9A&3<~;OXF447PSnuJO;Mym_vyU3m zkoqhCI+()*+w||mdTz|NP5&y#`V6A~w=T=U85||5&l3&AB(UY9B!#h0kiJBvzmbVikF4OLF9^wCkK;!&C)ItWkG zA<=dlE1u74F@YPi* zfMKR-%h04j6|$++9IXj@Gk-L%hb4H`h8mI>2?QN?k~~++S%v|;fsGI-Tm}RU*a)d% zT@6?Ysi9T__Cji~MR*EVh#h$#g)0IxX5k7}Sr}0oz@`~Gl>C^p%y@rUDqI}Vr9qoq zG)G7}!$;Orbk^DwOuFfkhZ49t{zbZ&LYX0uc{gbp2cEnqhvcu77i^8X2~( zf3yDz8ES;}u$PGSSx6yDC1&vgk1Bx4u<)=bR!an+k8OlXrm%g5p>Gw5E>?cGs``0! zz4a1DENWPeMRhxK#Xb==lXT^9F;R>;U4@k}`{ta;mSEr5+R+YV%-QcvXe5atF7ox#F# zFS^ngSB~&@nKuTGFko}|XPckA5VhOqZttQA+Raa_!Sz{@k*zrg`~qm-2{f?`U-@LO zJs^vD>w7dns#-wbrsJ_#NM6Uf!Pb)@o^@)z4mgPIRQ5FrN316PD~l`HbN`f-;O zw9_9Qq?nL|3EoK|f`6>m#EJKDIPZn&Bq*BQ*{^X-C^0Q`;xhJvb}NN~rlES_eO2oP z*qbsvlKBzD(-?sVqxsooey!;Rsi&?|EfIRa{X#e6-mP^d zPl0ZO)+&&YeS%;%f8kV6&z&PGkMPaZ^(jT!zndCO8<1=|p-q5^ zk}9vg&Q)R*@iFEYe}?0M#d`vuShz6ry;v+U6AY8S8_Ic$Ng!Nb?!whvu zUI9jg-{lJdqu2GoG+$JJ@BF*+XBi9R;+O%om@EGY>c2Y+E1iC7p7B(he?y-{i3Bpk(Tu2t1OCnGQ#BqW`riT7uWyg`9X z@+ct%Lq`J2AdsF2fLiz?lc3hCtx9w#g^9-nZIrZQit66;d#g70e9$22Nn_}pvSl=& zO_0=s?<@3x5kBU-#6fL*5N7)1QHi&o5{(yOgn?0JOrxxPpTGoXJR$aq^Rn_UT|aZCHKk<| ziz(rFtb&w~&w^=~#azR1XClIFsj+An?W78d6zPOMSAJSy%;&ivu4s5DX&I?g{Et$o zYgFDL9}X)9S6_;=D+4car$QArQ@M%;aw%TxLn_9I!d$X}D6DgMR^O6-;cSXX6#f>b zlh2f%Sd(!8OE8et8iuVgAsH732lPk3i>lW|>U-h@JwGkbaz&3PGpUTDgHk2jgVH!j z$)t%H&@4QaGXdm-txZ8x^p2kyQ&58v6n(Igo}4Mb__9P_nJRr1Oq5{4j&olDbJr(z zAjwC&#{Wx$hc(pTn}?JFNHSvukS=S>=RuvCMJDw|8u`)<{DDZXrxBs+gHdAY=+s-& z9FLkF3s)c9uCWT>?(CD6JCMF3rwGHVT8Vd&!ITT)Gd;D?r@-b2sU;nh%OLv6i47$V zSiJ(z(!1oRF@Ea!J6M%vWFw1~Z|N;_I+-G#MR+#G-V{BC$(c{DFoh>1!&*Y}$&^aC z*`Jw2Q#zNIZsdqoC?SBsrRj3hQZhR!PtBvT6q9+YCzYw_ZP(BYS_%1=C6&2u3Q1+A zp)(B^lcUh}Nt}pclu;)BRYut$S*w=G%K$NFntDotIX9E}nx&FaGpJ2P(To!3)wCz& zY%x&Fq_rR$c(#GYgad6yj;kbtizzg?kT#4lbW_O&h+*nVv={@}mKPX9zSfxuLNoAl zauMD~<|(ny>r;q9_m9Xq+QGA%*(L^C|A^tnxG!jbBck)x{@^#syiZohyfVtXsihj* zCCMrE*^bve-ME(e}O zf$*GGApG{|98^kXC^BSlz_^*iu24tgAk_2!5I~bAsu3cjcX?qhPK%AOENq>eA`~%s z>*f?GnaGch&WKACk7ble@pJ@yt9TGBkt~N2@KL4@MUzpc4>4TQTF^Q(0dKyIT)@Zg zYV^sKd!~=uIQNLgH3r6%GAcDnu2aUP>6l)dk?BxKi4SKZ5%-Fac&&F1{JkvGGW6bN zT87VOnU--Z;Lu8;8712(fs+Fo=ZgFZu{lGTjo8^kl-Oj5H)lg^GcCgq+f2(a#5~iI zF$HsHm?#Ap@b1TEp+T6-8v^=-++hAysfegmAAQ+N+O}*p_sl1lkHW* zr?ZA@j4@J!gU4LY6kL`mV}7=6WypH5UogPQW7=ofn<6 z(K*lB4APwKKQ_z3f-ub*Z39C&LLdc61AV6;D#?AVwfX$s9y86%+MH#V$vbai3~w!> z0crA-*=85D^Yd>ps`kg_yhx$17n_o3AuGEOEi`wh5-+ob&m?^*fXK9*-?CJ}1B$2I zCU=zd6pK-LqdnHEb(vPAmfN6(U0l1z^`9~s*6?h|c918t<0kdhB_2M8lNNyfsCeYO z*MKZ;6AS-QckNd>8%ma#NC`&{Ydq3ue08=LpO_@0pyO4R#|+`J*6<-UJ87gy26zDNedvqS;}Cjp4pSqRvI+STYT?LXG= z_TVRAoLJa=)tz5+0~XQwh4Vi-zb2jkcpai|IsmO`uW-x9*wu^@%5 zYY;;~bbf_ELe|TbPrR3&R-;0*JEP7m+Lyu+e>;~oq5PA*C)G8ik~>V8cO1)`LUiun zPN^Lt$!Mr^*Wxn9LHO)?$@ybCH;dR>8N4iF8!7-N=aBVkI=7H9*&iJbv~*JOomhKF z>kj*tKKz6jHj`b6alh6@b~TrAMQHHu=p(NWBu*3rb3(J7HF7XhBt?;(5NJY6fvpZb zW`Qm9b+q&-XRJPUS=-gQ_Y(T35vO9q^)|g_f(^rlkJXp16^I)#^r1IufQTTanH0@! zOod6!MBEzKjCr8>jM3~w-(L{QrDebr<1DPE3BTpfAEVtxjVu7gNG6SHe3nRB-)gPa zY;W{LhMYu#$)7&jz`8;puwA?K#J%(Sg5~kq^Z=;|o$v*1L5bf8S$D0_332%hRQJ!= z(2TpJvl6^R;1zTly@M=$m`Y{ zq2URqppc~4NI>zhBmPtfj-J`8pm-8VE-t1BG0_S~$ce))LV-t0uNKaGo<@+cPzg{3APV*Llpck3mY@!V5OT zM)$!SnNC5_^oNnG^<~cWWzGc@_bbnp>*!eX7D`h`)nc=Ord|Yk5t(s=+>bFc#BzdS zL9fL~Lxf4dXyc*4 zu{Z-YDa{q8XTv8XB6-9n^8A#4cbea}NJJsBZS!39+gZ`su~-N?6MACiYX5UptEOx| z{PQ39UDGR4$0VRjPU(Sg?h!?N&}Fo>wG{EJM?p+{L7sK>6UDB&(c|PMOJvt2=Xp}H z7yZz7?;iG|sb|5dI7f_acosZ-C3c|`rN|f-(=|*T`O7{Mb`{(z=V*^rNXdk42}sL$ zf4YH$t|5P@FA;V`AInxlpQSsMVYrsgWE+|s9ik`0NxBa@B%H#v4JW7&xh#Z0dd*$q z60du-_0J}lSqhqkhB2EKOk3%-C^uzaWpnGQs?|~iPUcLj#kWK7Ktq5-vfzOxwi`Uq zFeZZs5xSTpc5aA^qQS5hLkJ?C6kITTx$H6*&kTH#K>plzF$V=F`*7ax*M0BoU|;0c zbNOpDv9n?q&2vQAW~GQZ-44>+OrO|cGlmhVIZnrQgc*Yo5!yClGEl`U_E4C2?a7Su z9<7SDBah#iRS`D3A~j@H&0uRgIZx8oipg{`x|#Je$+ZzELw=S`kCF^Pn9Y(a zAn|ghpehk&23G>f_EgQrF}=$MDVmdM%R~sPtA?D*40UNZR}Hz)#2cKd=T{k)XALM~ zIUCaima{P#r)6U@W{Zg50-|S+Qj0+wR`jFz=iM>LCqc~T;=0DJUPz0vxYF6huS6(p~8PQw^2yg?gPj8Q$(t9 zS`(d0u1t*-*p6UQ$O~g2naBd~7K0KuZx+EokAyY{_gLYBcB`=!^cWCD3Ul38glWJ( z=^C#Aj*0df0y^8=Wz1)o%j$W|7jsykQOs?mXoXn7sPVBlFFXZ%7tQJapS^bvvg@ku z{O`Gse%;&MwTOyo$QAoQ6*Jx4|8t|`~A_=7*F8brjX5y3+oFjxeG1=#ra`L4D1dE9%u z)vX5@A%y#$v(J95wbx#It+m%)yGY>ef%sOMgrkV^D7XQ(6UFMXbVx*lmtz==KoU|n z;5Y|zcPYt$Bt&$~1CTr7TNy|Zypf2xwdU?=ee3KKHKD6-sJ#}*PL7TiNObmos)Dl#4A7cUi+=qqPVIeF!3Phb}LmgH%vC^D3M zwOK|gQj~g=7fxxZXevT^ic3YZZrNy_mWreZRh69cB-NakPY$`&JRzi_jt!bAf2Xcg zG+h9Bic3Wb9RF)06%j;Svih&ARJ6Xc;h3c&Gm8G=rJ@pjotBDfvU0NGY03pPs&N8r zMYC2R^8YC<6?G$&r?^x!7vVfD75(Z+MQd!(PI0MdZ2{ydE)}gSAU*YMMIpY!$&!i+ z9~bOIn0C(StZ!#4*lash^WeF%>|Wdw9zKY!xii(f&MLVGR5u-qZACkd9e1_N>MehO z{!kn=rIzAJyK_}=9tgYpY69_MV!QkWF~XY{-$2n}+S9HYkOM-2Y%X1Qjlkxz|dT4((ZR zpaCRGXKm7py^XRUtux8lo>EfSQQKW4kzrSStJv~SbXdo@iDvW@@acPoIEoE8ZV>;y zK%Q-;`Bcp}@0TT0!`lcl9gRF(fFknptwoa91`+ZK+1fU(%lohmKIdDoB?fS!5vPWO za|Pn!O*Om z2jW(sp&2ahFC{>s!n-bM^BsJlS@*M*_k0D_D1hP|F2RK3bg0N2u1YXz{jeV7-+?K* zFsuO6*~qzwho?iCZ+J#14@DqI2vFWzBmw2Y_*Nn&>xXTtjUp@CrYiW~V2st30-NtN z72xHdjDfEFl}ocO zQu2ud-op-leRv0d3EZD2!pd#cb=j&zOmX-0ThM#HgI{O!p7-1wv?4++O+KTMu#oPr zxqIX2LBkJ~L9>P8fw+N7Qs8xmN=ZzGT6S-dz#E&XLz8e6QN~HQ1a2Uj!Ua-(LFMT; z2-WiAH5y2d?ruQth$~wGlyB)Yx;`ES#B>K z(KkzxTSI8j)jr=`JuKVs!#*~6bpjVE<_^x=itlDV+!bGIg$qq_e$cqvNE4sRpHT&f z)TU>=VROIuTJCRQUfQakg9dg>UA-Z4ap5jRLV)Au-i4kgcnTALkOPl_QJANl@S49f zN;+kgzr$j5$|}6$3c|FCPTzJZa7%#^{TQUUpJQNjWWul2mveE|q}A=F+N)e`)YS?e z@g~dh$QeXEo8z)w>?(BXqWH8xr>##4SB-0t$4zCpIJe~IgY-d%ZbV}2qjK6Y51Q(p zUYr^>uL4HEYGR(ORX|ADX-Q7|eui7;E1U5{_-w<0Gn|L4wX0T4 zy5JmztPG6$gbscuhTQ&SV7HuQ2;{^$mO6<7W-?GzOoFH;15qg{ofLUBQr!ZKJHA!_ zJfKzOli6m2dvc+c63EHc^U@Wv^V}*USptL!o=x2cU$VGJl?(N)ee))+%VkxlXMb*? ze!iTU486rIv|V(*QWfjE?}@k2ZtYJ=Aa9X!!v!X+|s_-EXMhB6!Ul~z&E5vf z!wJ98mou1Y)jSiudCPM}DUXE-r>n7^PVY?1!^Q7;Jx={ao^EfQ<#{3Xi%!mfp41ZE zAQ}^W$CcTy$*GCG9@3kr5mpzk4aTV8X|TJPh7#&&u)LT?m>r$FQZ+b3r*uh=#M(*E z^hYQxo%ct@N!;L%BFgptNHoPce?poiT!P9Ic9CefdfLMMHU30c0}}@?IH}bEj1SC5sa1tJ?2()@S>A( zQT8hi$LX+)>{4QQIw5Cv!tny{`EhnRlt$~M=jM!~tfd&_C~OOzPE!{5-P$@@#5@Rf zy1uzW`vG)!cI{HBZFbJ0Wbz?_WdhIUT9hgtBTAV{t2SFXp#dThErJ9F!Eo_yvP}F4%gDatI+$h_muTe6xp||J)GIG>p zOh%4}L&1vVC&NULwi;Sygos@FQeAK{hn_PnI(1hPz<`BA-UiF&QvjBQ0E^$H@T)y8 zPnQ4!g+J5Ag~>ETV|Lb^uoTWMZ6aI54&4K6+<=D>+yJ2orfg@W#p>*gY)}hME(b^_ z(+TIbkloh&!jRGpGG?8JHw>L+H?~w57CpR5v3+5zhDy&j^N|Gbk$fv>fB8wSktgC! zv8J{Q2fD~yJu15>;=b6nL9FUIwi96;8&yl}STX5Khv0JNle4gkPh7_?IT0O`#2_Kr zRk`*X$65);{}lqD5f`g1m-Q3>44ooXz5lbHSgd7dW(N=GcSHA^?~xRqoQ+yx;fhl~ z7M#s%F|BC99v(GAzFG(E{;SICG<`GsltgGnooH@*|0}+8-y`pO$@d;XNuX9fO4fUt zo}N)(pa+!R>~AS=Fi~}?`@^?eC&b_3+T5&w@Xyb@6qs$bb5%s$dGKvtQ9~+eK?Z8w zuY}%nk{jV#@YPVXe)6tRopPEa*`L&UF{O~V{icrWr*!R$AN+!z~_`?hX$Eb(0uLo9GbiQQP6z9fadeB z|LR-6bNA0)zT?_Ka1dM#2m{Q7W&_NGS=Lh^F|E^@rL!iIF2ErXg6leSj*`i_{rSto zP-7=ys3qfSsCi4tix6EJYF(8ixF}KMqZUtpLT$IM)H39A4ZS`y^pF0H4gFTV>F_zx ziv!hTE}G{8plBBQ`@Nr8#CVnMeFwkY&)G!{?ToGL8~AoWEi$4$P}Kb8TF;uoOGbDY$Al)IZ@yd1GG3W^$I;5+oASr6soH?;u@b zOL#YEszMu=k=DVt1&|36etsDLsQg&|3m$o8S(IjpvmI#4!wNv$!mH67%uNK+{?eM9 zujLoaEGA{fhBBBPF^;x&n6q8&OWjJ0p9$^FziP#1KAKFofGb z`44ye>1*zJ`xlH^5AZjmL1P1cVTB-~r9lRFg&5rPD-2HE+Fu1h0)la^t-TJD!+R@s zad$l*e%=5JFF{w~;nxHne#IaUzuw15E7Hzl$Q~+&Z0EkW{mX-&{mw_< zy*v*$7HZI$$-&4`(23)E+#y??!r&EDR9dDqidzQ2e7X0?gG9 zqOBPQ=5J{ASmhvUIWMonPxC=sINm`lL3hXMp$kKYgi%0uT!WYnfVtTRF+G8U_|n^Q z_HsOfcq}uK7)_Ny+~k8ef4qbEgJLEg`sP1~TE#pM7c=oCcYXCs```PjH%%=oOqngw zDAcTb$2t*_Eh|v2^D*q6z%hK;>Pgk)L*u3esRl4t#Z9ZSybMJq5KkQM7{0F6_S81$eOOdz(mg_9kR4Z6rtnw{Jzz-H zhvWIJe6!Uojz!bvffa9hrjr=#OBY4kR$nd4uZa#PxZ^d^+2~#I_6;Wu%>ZZPH3~9~ zp$4G}T!_^aAj`ur2gvd;%>lAJjI$9$2$g|B(-k!-gk}7WvK__!SY`<{0yae}p(2l0 zxHvH^*lSBP$t@NVBwuYNixGnT`7YRRJqd#Sb5b)|TnGUnDxU9eA}6+hOuQ}RdP2~O z5j@@H`tzb(PnnWjucFnp>g>k6iS;fjmt|99&~FzR9z`V0tw&}5TIT^>aCSpqoBCnaH5 zz^!l1kt3(J+Hj;Ux!Ev z7Es7Dwu2p+jpk}uIlNdr0BSBx6LpIzRV!;vOQ;ijRsJT}stj5?bS8)nDibBxDlFjA zzyh!rR9V3O0=8QU*nV8V_J&)&eBDo9`OeS1bckhFSU_QO4#4>`F{svukt;}OUC(FJ8UE?$CdWkY!V zD{_;?8;U8nBoi61I~7X3?MoSO8=XFnZ3rtCGL3fQC2GPUDhV}u2w4XUEVH^D^f2YSi~j27>`^(?l3JueH zB1EllBi2+)N3Ur*(om!FL5%kRq3IU+7E9qO<4UL*kqhM`-(sP!RX5}JH%9sQ9A$XA z`S9ov+QQKAKAMldO1riVc@|N;mhHYaUO!N5aaRZJJ&j~K?sJ!%vUL9Qhwr4a;2w)NDMY79 zRo6JU+Ar_SCi2=qX7FIyxxX8-p&$a9dj<{B&nMG5mSDqsDdBVyLo~f>a9Tfg{B5B6~ zTdbE|pP}TW`y*W;z@uuRetm*Cu2y4} zO6&qlJMvPz5gLDo|pZCwL9*|W#2d3A}6tL?II!s`50QkNcZyY|68@GQvWxJ9a2 zF`-hw-@+RkY=e2Iyl7AdYq;@_3AsYA^QWe3WJN^*=_)fkPO+raP<11e#=)95>qjEL zZF?D2p26FLI*APD2sh@?Qpc>1L->I@IYH@4fBO~Hi+Sq77681EIJ1zEc*$!tlX&Tb zrDmOXQ#?*wo-E&bqj3|%yJ3aF!3&dt)N1o~4-k;uS6AM*-lXbSdn|M+4-fi7JlEdP zkjo#`p`qRR&~6&r9a`dozton?^ETfa+GNsblrCm1GHSHxnRNfzxkJG&A6qj@C=t}S z88WibxNU3jicR)*S8&y2uhEYGvQ&dp5l9^p38Z$0xrA(+5~J~ptx5PjztjjZ7D6qdmEscN&`jwP z;hYv$yd6+MZOOISu&WkB`G`NwSdp6)WHlQ)&d=?2s2Psa4uci z>!2#aXq~S^#V#gRO$1E({NU|spAW20CZo1`crw>kT~KnN8aill1{#}y3*Ij_UEOI| z=|%)*9p+myw7h_meLXuoZabHvQqBK{08|>>LG!heCL>TVEGeHe zmd0UR=WWcrht{ry&LtY$h2dPfW4S@44K}E>(GBimnysS2eIpuF+F*l98{Oc()iro< zM1x8jY*1;V8$7tW1`m&DP-%k=Ds6OwheLyi_Bw9Azh=aPcCyu|#%Gg#FgnAMFlnRM zsEi_MG%1^LPBzL%lhHlg$V+LgxvW~%d@Rh3VB5^|ZBg2mYQFQ7c3z(5R?5aMJIes; zSs57~Gyt?ZmO)UeEm9TQS1QZ3Sge~>OVod`+U%2mKg`c1sQ;i(w>a-~p4ebjI=G8- zuaXY_Je|h#{H@_xbda>cAy?Yqkk`*<&Ys&isMrT48#E5einWg}SW~-6*14}*r_!xXrI+edy49)lYMuM2bC>EoJQn(S zuv(|mtxlzv>QuVbsq|`{2dVS0PX8Z_bsnzPsdTGT>7_cAZgncXTIXTvJg7Q%k>@EFz={|0xSNpze z5*(}Vhn;LD@mf?&?BUr$E8 z9?+}t5;LRu^144yM7gbp`Ei>i-b!egn6fX=hJRU1+?yw2ABc&2@! z8_5X_Tilh7;nUN7#Pf8Fq@L~*QRxQu___6m6>{R{hBE9kny*xd>x-ukRH$Q3mfwdV zR=AG}uNU3iX%%Wx6fI_V3MxcH&_dr%Vp!b$Mc`szf4h~psr>C` z-XNSRG&kmnr7ql%Csv`^MHjBu41CZsIKk)j-=8Ozs=6;vtX6fn1!7dyP9wB~Hh1!> zuFDfkRXu7|DQC5+gH-h}RmrA)Ju^vrD2GK_KBMl55nF6GVKQz>@R52X-cp1Og-MD1 zp~%D9p7QLz^?<@<+$ol^NvA>4}4{D(pk1CrD4pZo4bXK0*@jiDkCNu(IY+CTwU#0MHG3N_72-Z`M_N?S%nMRVnI=L3YP}71Z6ApJ zA3d^F!v^pb3bJCGHM)Yj#}U8_j6cuLm=O zL(JG~zfA$gw3Fk*pgw8p4P)50K$xTkaor$3Dwd>P8J4Acg&`D%M>deq3s{{QiVT3g zZXI%GAevR*43MGDS@vK|@@v6^ovBZyd<3|wF-AbQ@JInIPi{3=(5+a(P`#;D2LC5A zcYrvj+W`D9Mzo=7+q=$6o*FGads_J-pF=LsWPQf**vMG%9KiFXOdd#*_2iLfSB6> zGJq1?j>?rOmCDW{wN#l>sca*urOMh?*#T9ygA8cUZN!B0iV;%kmhJsbq;9FEE^O~V ziPVK^Dq8bzkXkY}sRlavWKv5IE0s>Bq?S6VR65xswbaRub#jL~iJ+^>Iyh35DpM+z z^+_#Nrc^3>3aO>arX76}^B+Jj;K*83oF8aL#Tkcj)7fumi4|!&LQ+rW=RD*@4T zPGWbSfW)#UCQ#^l&YejIo`*b<&kr=uZR`y#2jO%LxzJ>2rnlL<1n%_qo4ldT=<%uH zgE8J70SGfR8hw}!A8Z-w{T6Qz`v;>mBSmEcaRga0uefXny{40EV<#;EFxFKPfc}h_ zppNgQ<2$V5_%u8Hd5gTH=m<3dU= zSmAE`q<6~BmftBl6WABcL>jz-^n1DzKzb*4l;2x1HM zoec~9X{Fo=Q>i20=_$O=QZI;5E4r@;Y|<{ zt2OPVrt1=_VlSQyxM=0|uo+JZE|7T&yYZypotUSv9Z$-RQVRR=q-esFAZAZKB$m3w zzI;fmcIk!Z)^Ajg*mCE)6Mo(xo9-d8R1@3oA+cK1h3D4qS553~^W7#vUJ;wyo>r=d z-EB{+RQuwtB%h7N2XeJ&@EVYLk4q$TOYqN>xh1He_wg9~GLboB5YYoXZWhhs z)WG9!`Xf?n`c!|^Hg5<$iYy;viXsrFzvUVB@o3VPDL1Y}qj5f?&Prjb^^N)szM&70 znT}3)M`h@dRz^i-Lr+w7vH4)Vsk!+_%Dh}U&E_MY#sQm;lwwm#T0zXOXproxJs3ydd7kpH5>|*99TY(#||It!UVCXX{0MtN#5&nNSvoD7SRV^mu2If0lQjRkC&EtWCOUyIH8||D z`p!vN)rkRY$XZI>XiT532|C>z6Tq1f%P6@6J3=%HMmtvAQDKpnGT#M`iKH{-)w0KP zbm#V?ndrt#Gk29Hy73qzwrm@5UN(rZV=~c=yCcxAvx)BZuAQS32dFa*179>_lwT4y zDwKrGkP7XunT$Qk?_|qQbD0q$vLOG>QjJ%|i`gw{@`W=m=KNS)9tcBbIy+XEdoeel zck>4v^kN>je&nux7)XL+*s%Lk|70Ai199F3`l0i5D{(n&2z2ve7U(SZxfinl=RNmg z7TCO3y_j>yJj3>A{9*u7Bj&{%8Y#S(Lo0vKw1rI)ugocnha}zq!#mc zKvIL@UE{>au#DHxqs4rN%!Z>uB$}Z>G%w}=V&TOcKrFnN1Bj!%nAP;k9nc#&91Ptr z0#1foaJmrH$cf(++JXUwO6{;= zJp4U;g;zeV%QDXs=Y!dsJT!$qr~2K>TSyGGY>y@6B85!_?e*s+Sc>D$lhqHik9$t`4$savmMnnOtN>Dk9gk0F4RDWEj6!ua^fbEWmj|^oxROFg!Rn#knA(@0MYYG6&&I7R2jm< zmQbnyLmvKIE<%9-Du_EqRwLFy5^|vmBw9kL0&IiW&0__Jc#FG4R>8fNu%+nnK}%RD z60nm}#J7d4$bL&GL2;WUlsd7`5=x!GLW=1;c4CoXjJrTq;}Jf`4IoQ6Yzd_b9#BH8 zKpH8=m7d(9bje$-{efm(G4_X?nW73ZVy>1ndgibToYJ7IjitcR_}R@%@Z@=%AF9ogjfIuhAisd_{;vU3G4 zjSK8>^NIH5Miym-a7{kg73qkX4~H8mIj4Mf=HzR>td^(sUKVLg+h!}!jenA=PV2qS z4qYf*R&*OpLZ|g!nH5g!y@rI-dT&&gnRu|9Ok5nEr>Xl^>Hap>@FsFBbiu|f|WqI2^UZYgw# zSBFREc0c#p{;TGwJA36bYGS4yMqEmU=p++-=`OG_!8x8E73O~9U>nni9`}yg!a9x_ zk}rEdgy4BrxO}iUDy+CHV^l2_ccnLi*$rOh^(nYg*0*NELQN5pWL=CWVaBZ7X05qs zK}t49-NGhh5ws)#t`3gn*5^^ZLZGZa%Ux@KAe_F)+JRptABW)jg>Fsy_)f->-{hdQ$TM4uKWDSQ! z`m`vRcAE;cF%V_<7aVE31k#QV8+3BCT@gr|gRhHS_)q|6(S#G%Cr1L8Rze7i+u#LO zD~AwX;=YIT(Xhz9A3A66zPKA`$w=F!_@#eY07p=zI9^LfMh7_CfgZRU2;QtNcmP^C z5V*T@l5(|M7`YfenbV=R8=mNnH$hneafuMEs|N8Oix92fFG%u8L6S#)a>rMXJoe5n z-9AK;6%d1OIg!$BYaXo|m=?IDiN$N7{;L{H{F^Ica`zrDlfx}SHz3|$1QY*BF#v~O z_T`6fc>LkF9WZBK`3&g>#3wG3+v_t$akt-6Oq!n-0KNJ4@4a`=4R^nDy_}cJagE_| zn{ys#1Qln>FPF!Cy@2S>0-~Q45Pjw&U-|hbe)8VO=LaELg2kCv-V=kxoutbI;=nx- zSlp{VlCQdt7Q?sX3@cM)g~gfklC8gXhUFAtaW~G@f8*LlG(GR)jMA8k|5?%-m;ITQ z=Rvo3HeN(*)@cjnX(xj{^q$F-W7%PI`bR+KL|Z(5@2QB*oLAzseK?fwsq82dQbQ5{ z{HXp|cF=2>A{C*#oJtLdsB$MMr`lyj*Yl9;^9`#49kTrkSXRI-L-xoVV?X>u*ea_I=k z>f8AQ&IsLn0kIf(%nmoKf9uFBw}@DWlBxO(lI0vxPNskBNtTO5scIZ78i#eR=>bfY z8~85&f>`VjY4fDrT}r!`v@=PQmqE;TkhHT%!#_Ju+vgqJNV41wVpb*7!A&H~>7blU z2cJZ;Tn|FBV8{8Pu}>Y`#v{ODdTPpG>lx3(Cn#eJ67`|9v8+umQRpNZZYS==W$l4T~R*?gmLlIj!$mhD9%`=*@>6yX<( z%l6(>I*rdSPWan<>l_owRYd(JAOB6DVa&31T)&zl<@K$+jnk>elPjg7w5StBMIwDm z9c-~EjN|NV-F{J)=mhWt8GAaYsJM7(i*3jz08A;qEv3S1OVN@Qjl4|_)9E_tW8Gd` z+kJEC#P1U*V2#H^Xy|z@^|!9Z=EA-yN7NdiPfx$elkL^^o|DM0eI2r8YeUub^}>E>gSU{BNy}Y%pp{nEeTs)9jM|R=G-_HpFg_-Og2w4CLcL=Ool`5@bO@V378zT#DK}4 zS1|dNzrXF~pFZ}AL+=czJ^`p)2~nPGR6c&}s4R%`sHl9rg325I?%j{S>WA<6QMl#w z1Yq(9rJaW2K+wq99{f3Mwqu-z@;TznB;e2d_U@zCGmV+%I7`lJ#R|`xM*C7IBf5r+ z;~{VvWaHa1V`e{Zu^{UF41rp-$Z_0DyCq|OenWM_Hd$(`OqKQ4KCxKpEZSHDw#9VM z&#!649xfxZj;*ZPXCR07c!}5^E$!LFNceRYAA#UI7~w=32-rN-2>mz){+GS(bDxmG zQ;ZK*SYmv39{Q1_qpz7$HSsESD-z{7R$P@Y~P*fOXe;m!&yP zW-5gHKi#^*A879Jg65u{)lraboq{OrUItu!jTr5!TAm<9LH#Q#IcO(->h;}3(otJ%BX(v$Oo@`<^6Yj^uOk#x*EoN%%e&{AF=ANesSbY56h0K z@ALn>=j*SzY1zpFU-0QSAS)odNK{FxGbQf)R#Cc=W$t9lULPy4x?0)G zwp>j1x~@PV+~}e2zUJVk?zr)NkC|Ov?DwS0UQYx}-f`@hv^ydVlXps%&-waaz3TJd ze%D*S`8M{cB#nW{mlv3ZRKI@jyMFYYTMs>U{YX+Bpv*E!R_PGgK9^!|D{=31Wz0KH zbMv>@hRMh#{qNM)Y3}P@E5(!OB0O*67Xwbc`NzmIP*l{%rNhG?Kqz% zpV*T3$cK5cZZdrpes&{Z4*!=XC?3Z()cV5zyVsg~`NYQYUWq?Ir7 zt-*DdZjIn3=|~3snJ0k$@oy2WtJmb#In{&pS4OOxCik&_e%-%)`qTgNo&PtV11DQ% z{$K-@_$f?8maLTuFkucXY~NDYQmh0f~w$i&dv_>r%E(uF{uCf(2O z^fgk_Y!p5H_A97<%ZU;_A1g*`Nc1!^T~hS?cp+K>? z0n}Bjrb|dDD^b8t_Hz2V&*u{TYM0Xxzl{m7qcQ=$bHh7cd+6W3b;Dt!CtC$pBi$d< zD)4JD1#T$DYDH5Z#OPyyp0HD3C34WoHk{m4pmnuVpfH@gr6LF2^RtKUfBDzm_wqLf zIfs?^WG@0w1WbPD*fANrhM?6~RhY?Lx4rDWAG`OC$G7C{`cI4Rh%mSB|LNl|edo<@ zy79zGl%HFHTw-h)Bg23JI$D@HyE!Q5Dc~$x)(S1m`;U%E6SU02d>yp6-o$4IwGj@oOIK9UhIsD601*v(E{9dJmZuhg= zz9Vys+9^73wQsw2+qE>lpv^xTvHNHmwHGS`5ueK$c zpZm+-@lV9K6D;vF{vxqTqC}ReTr55uspr}82HCc_?;DSN`9FAV1h$Jcsp6;yjfaX3 z*3)rSe?Y(c-tehUqC)KFIXg%kO8~pnYr%;oza(Wm!_6iSH99Uw9C!aP%pK+}1_B+o zeZs|qe|sk_9BELij#!Upbfo(ki*m+3`yzG^wn`x#`^-#)0{R>pN%`-RjiEa_sqF=K zif{5v3PVO-_T}m5g+28evg_`<&NASZt8EWU#eJcr06^z!aXW0=$1j&`qk4oD4Rv<# zTd07U#eEydvJl$lu*1K+&0D9GTHUg3adFp&Z@=f3!_%sNq2Jm_l`QxM1(T6?04Z{9 zt97s6M-`$zmDpeRoqPGy;2Hr~`0DUD%@p5uZEu?YI_$V;ekZpuyq>BQ(z? z5W|D4afM(9$9XJbTHn)R+{;6KpkNux4D+@`Q%c?zk#p?j@x-wxQO1@kmr@dD8#7z_ zlssXKsyf*C$AqERVCO@>^1*HnFe({V`7dWwEaV12H}a{8$fn>#TCx=}fb*aoG1eMD zr_=s~Y+`GJg$Xc2j)e|jVIg1IWxZpWOo?}V9zSM_u8G~HP3O>y&DZY z<<|G@hpQcmoNoVn^?LpL`P=%RKQ@~6YwLfK zj24Vs98zrEezW^Av2&Y8T*qV6W?Nl?5yFhg04Co2PHkSu0l$t+lqe0en5eE3vM^Gd z$TlIW5Rz)YXNCLYxpahNpj;!QqX{ZGPg68VN2)YPM>vGJbcC43Ix}&J{JL6vy4kP4ho8v&a!hAE>hjsy^67+dxvt->*hw%ie_7M zqhvGGL>5)&3o{5#GQkQ?6NUpYw>H!f(2G}dMO#}}_p6{ekP_aWOE^()(W__Moyw&$;3`sm;KmVXQP;6_^PJ_r;?vsYxw zZ%gzdd>}jMgw**4EZLB>%6d4g~cmBOJz_X>l%8)ZUx z&zEiB_vravPy`JqF9{R0pg$U)0=1&?=7@N$0N?@2G@@r-BGU%=0sJ>~g4lIMB+gt{-~ z@hQ)!U&7DN?y`#HA%_X=IsAOrQ!eC@D6jIMyU$bPFhf1h-vp2qLreZlHp;PL-?2C>?k*`xnpDQU>GiQjj4(man8vm;lIfG#Q6O*{O&+4D^B zcn_K6?Q%dA;q-#L$9v={=93J$Rf&x7V(K>_H2>@H-5{u z`9JAT=(4G4nuk+O+|-}SY8UdB^x9V86n?uCy$%&v2EGo^5g~t@=~OoVzi`9k2Tk8H zPOCgVyHn|;6a~4k!ab2ua8K$YDQQhdQX11vW;g9{Zxp>g1NYH$YG-KHw{#U^H>>@g zy`;9b!lA|fG-p$ry^0(~uXR!xINQWR?zim#I-!s*?@iJXJ4U>iz!G2`t*m9&)$q}H zBxn#gRR)PzczM>ms*f`*c%be;gh5`E2{ni_8 zT-^Ce6|<~yW*oF|8bld>`U*0{{f{eArBcpF5Bi6&YFs_3cs)&`jz3uKm`E^rFg~kFj!bAzQ z`ZZ}?ljnSXc6)xzGudmL&!3mpx843vZ+q>le)`Q$%MQ==I z@fC5&?hoH?oe-yDsv~f~T_kddcWRjr63&Bf`-(kj?sPapiwYr__U zBqR;B9q5KQ^~7ms+YS{l^ok*sKyCz~xsmp1tXny)u1=Nut`Lz^f)?fp&$N!(Mbn#I z#6*&-oK#=vO&XKs2z&sCi6?MM$GCSD;2h5}ZretTXB;N=<@VK)B*e6LYx6 zfJ&*KzZ}mQjWzR!vDP%ySo4;Wm-9}gu{P7NPKF9o7DUl-MpOz==xJP6<{}=*TBtwz zH#YWL$?Q^US#B%OjlbXfnMGNs_P&GPsHlCbo=im9t?(6MW^3i>mM#e>%;2I;H-qQ# z_PgA6pQExa&lO;XG4MxGW9hQT2ys` zfIU^Ac~C zt;F{ogPit5I4JOqJ8}L(qB5i~$yFz-<`<4l$(y+$QI;^8;MA1YCv9 zUK-f!#e;12){lNJt{NXJfLoFTZ96us8kM8uHej}XAnhsJm~~1m4~9~2^+^z*UHy6>rvQ+Thqu64J zW;K;hu=%T){n-fGu9FKlb0IPWDTaM-JHKd>4a16zqd|^qFExRXjzlN3ZmXpZLC|U@ zUve5VJZZ(T6C^#In2n#~X1X0T^&%Jx;#m`v;tRN9-45hR>mDCm*Wua3aNzPPWm$Sz zk7lvZ4^I+Wp+{a^pdl+(?Ck=Ay^b94HOW6=T<=}b0_aTa?X{V20? zv9HA`Sz^3X0Y8|7u>GdkKN^zi)hRptrKMCHCFy?OloTOOab-C)s}}lbe1z*($;)`} zzQZHoq1zY@i9jhUDwpK7zcj7C_Uey=u-``PN@Qem(Oo#ZCZGN^ z9m_^7%b_w6nbcAFduk`3(&6@%~CuG(1Fx) zQI=e-$2yBzRQ1|daWWyR+a(jiaNlBFB)>2A=a|Dyji?u%qH$3Cixknfo;CirMlegL zaQw=vuk`uQ44;$Yb7G&b!e*^7`t|mG=*1Pmr5So-XI4RdKES#`h%Sjr3QlC+h{`6THo&LqBottY`^34_3iJsI=j1ycwE|Wmkmpz1S2yHZ_{IJ16 z0y`BvNm5zhS0V!ycXy#c(1t8viAeOE+AO`(6J`Rtkg;*4x(gE+FrX_uev`#bYO4fL z)9$t2AcNqACw$Au!IA-`CLT;*-p-l~wlwN2tMZde`IU~S;VX_}!#Wb%|F_?4u^U}4 zFnoB;kRaeVUh1zgf|>Tz+m&8NS7XW0`?l6y_cG9_wann9oP7T)Uob&1d0!aFCLm^L*q=Ey8~em zJEsN(W@9~eMOc{O@K!ZBn196psDP#(Yd8#9PbdR{Cu_WSGqi!UBsyt6Ha)--qvqsb zsO*0419VUvV9&VZQ}hPHQ;iE9Vf2Bk)NUji4U-WKE`bsxkr9MyaOm{&2atdxfpIiW zBWH*mO`-uv)&uFiq_I^qg`Vw3*AaKM3BKpW+q;W0h--Ex8LxctxqpK_53vC1;AUYP z#*3|rYm9-8Nl+Dk^1`Fb(!vf~cDdIE*(SdQHdy=Vuu6|SqaN<`-QB#L^>9q!pyR#f zCZQ9MLZuJ<5unAzyu-px_Ge9ZMwlCM;d7LmDZLo!)s7|D$VZcbwb3kwoN*g5nmG#y z130m5@(hVxyn4b8qs|;KbK2Htf=Q{z!urrScEEZ*gGJL{dX*@T zvKocJ7gjl$@&Pa!vH`#kINbqj;YwQsfga2R|7-*^Z@Od4fX`=b)cSlDqi`8Z`r_*5 zbKV8hZwne=bzYo>8EBswLSzxX0n(7xzFWU2hS!I8aS5l#XVmxbTrl76<3{4p*xqrL ze12gUaCC7H#V5Bp4d-4AE4T^R*zd+Khd;z=^13ih4stoH#D;y>AlKWNnH8y_>`PkZ z#}q!|)Syk#nb9UY41;`4RM@y>Tl$K0?3U|9Jb}?Bx4@mDq$cv^SVtazwgfTe;o=hA zOGT+7Y5=Xabd=nMMRL~ewn^EhZ0teBDzv1?>5a)Z>9+KHt-!9CxIR`E6H%B{SQmh` z$0Dsc;b%}?(-Va)o@A#Ny35qSC5&$C`KD;KHSw6Y3 zHDyl!C2!+>YjZ=3?}eG!iFR&Z}p zdI;QOt)`%f|E{znxwG@OV=bx7>?4}l;PzJX%09JEzf9$u^~*Ty)o(pJqA7hF&)IIP zZ*O~h_q$PM-?LU)`a=DNwLNky)OWAd)INv0pEW&K$KEC?F~q{0rg}|8NL=`>v{DuO zk5fNPX17qcpEbP(M_8N8YoM+{@?ImOGYte~s-q@5w2b-ff@w67jLyN-4~|DWOC#Ge ztHGg5d)tgKqZ6`qACxJ@s%vIbzo+D*A)|zV1Ge2{04r3>Oj`fX;6TE4lQ}k>c1*Y? zIoq>#`+vrqGMjd8>Tx#Kwg4tNPg)KTz*-3)A=@AzBp*8<4C2ZFsRuwdi7*yN6PgIj z0IAEnr(i}31|<`dR+!xPi|MU2RR?Xp5*kIVG*W>4ZnRfc7X7jnd_#EOt>1d~%C+R# z%X7BFdIF&qB)Th*=uRWeh5C-Q+RZ+PCZ08oepw~a$)l1ed=E-?5*=q*93)X&xBWnA zK?L(g1JiUcH7h`%hB5WTDVPpT_NF=;1-~ooA|6-RyVz}G#?G1S%NK9+qw`M|IW{PV z_h&XIO1BP9r?aBTHvD3}a>c%BRAj4Af8A=4Pc)c1mR}psLcWM_8inI4&^beE?%K$d z$S$5?#!Q~!C*2S2W$uA{fPZvN-z;h}n3-{mv?FT<(Q5Adnyi{PZ5cpiR^|WdXPD9S zn$#^yGACxWO8-f-!{$Yrt&f!Eq-rx}_WBIka~tA(e)8&KjK0oV)z`hW{(IK8s%~E8 zaFBOjTf{3s1hfG{6$`M^K|s*LvDTpTpH~r_U8{o|buXn$EQ)q8Z2Dy;hZOgQ<{!vQqTR zxJCo6k?Z)HA?kyPGS)Bs5zfcku_wi^c=^Q4xc0yr^~4+oaFems9lTFCuP{amzc+R} zh+3&}$iFzyh^NG9E%xLLczAe*kF}7Ofc3`Xte~xC9>py#a+*L$Hnzglx_@RuP>mFy zT7}6nU|p@YAQ}^f%(=(TyOfXn0NJCS~Vc_ONYAV)@F^ldk*SY$ot$VHSMYAGhW>+?@y)U8P=M}D58js^bf?VVc32=zU z;INDJ>{}a^xc#NzMnh7*(lU#*3j>RJk4|6IaXH@6mO%}FIKnJbG1%Ka$##h<|m4dIA}pto=x ztWt~nFSbj!(LgFWAe9Q6+VEnOJy1RaDK3C9BngKOVJ``v;ZD68>;*dL{@a_xV6+9U z9q?Lq#5aZ^C8HoZR=O@&f@5EM(R8hmcTK7CPSfPU>q`-5S)%Ov8@guBo`Sa7tJOJt zYMJu;ZX5Z1x6%Ees3@%wwk_bq0W~TWMRwzqzGDMkunNWyykHM@Dp(e#SN2c6Um@X6 zV?r?l%H&kLGh>pvOt;cjZ2p!`9f^v&M#X!HJ)G!uT{kD=y{!@(xEU{>ooHv8+B^8o zc2I)9lOWh7-%c7tM7L7Q|APPCDy^Sa(&I7nlZA@TFD6Za#^KRR|+LOQweB zL0$>5n@$R1Z5Azu*c_e0&ytAM4Rm-0zr-xVN4&ob zqdbVOi-Sm`x=6q#&E0W#t2#BpB*D!!A7dt^tGM!|M3v+K2!s14xsb~oj`D57nGx<^ zm7~DKMfkHQp(O4_7(sgQq;$d* zwM=_qa>xyRrgu1y7UU&dzfcB~h5F?Z5wkAEJFZyC@H7K*o^&Q=J1f!AHu|`Qe+bJgZf&{pv z`+&yHy$}Ph5cAIS6p-?SVr_1GBS;F13A;Q7o-G=_8lT`FLbf$kens9G?KVd5gC?TBW2g)LHs%hrIx#}Atb~V|oj@T87@)g7miSj28u?u2LIbw%I`ICXz;}+!|u`3kij|_|QT6454 zB;9*|!J<5Iy_XQ>E8{;T%ID*M+@gGyW0~a?v8|~vDj2S?%DO!7h9KgIx#@50oSJsG z;xc>3YUO#C&LuJa!sK};l9kHyIr@Fc7?S7n0a$*?Sb;px09569?9;0l0GGw{0a#9` zAFBxU48aJY{;s16^*a0cL>KCfjHC2`yYF(+1GKt;Z$}mQ3x~Qvfj`iGMc|iFxe)kc ziD7|1Z-1n~pMNb0{OY?4{Q1|T3j70oFA4nlMA(-cP2m5I3H;{sxwOD9NCACi0>3RS zqXd2}FfQ=ttIui$ep@L{vcT^wa^(X5E9Os|?N@BJzwfl!{uuW|OxCvzMX{tIS^s1p z_PAwz-w#=#te=O-6MRFm{>j^DGFd-I?2xQ~G7x**vc4mBg|dEbUO8>HuMcfBo;KT` zHrt;z+egj+qlFZIYrcsmi~UsGm@x0+a}$iXX2xxuo4gM*c-eN3pjapO*$JEI2kfJi$od=CLP^;s0bH_PCV+N9+offeK=Wlz|o69gktF>L`Z)lY!XdRt6lgD^vz@ z(@UWYoHqPN^Tlbye{kfRTK9mnteMdvsGc z(s^q2Z`z!hRTkc*_oBv@ALap4;6}qn&i`k38Hl zO@lfaSPS)iUev}GrUyvKPmkffc#NQ$K>LIMwX;G{r;im>6EU9Czs-6DNZhd zh5&zGf``v!9XskP{9;-@RHfANp(-Qq;;u^P_;}y-U?3K{I&J1BmpC03j%LM^OA5cN z2JvexPA(;u25W*Za47cJM#h|8DkEd(sZK11!KVh_1oN7gkIoPg(c}meDz${d5S1sK zZgVeZ7~5aV&4)w0#|FMRbDwnZ?UKlv!X*fN7LsF_L+S7wB1EBsFPyA^hffU5_RlTB z!#SuMy0~gGx5!C@WUlzWEo!tmGc;31(726?FO%l4ud{yc3$Cl870X^LvUiSa6ULuy zlaIS)!?YP#M)BvWF?YNwcbBQ*^lrgi(6+(K1NJh^9P&;ZfnJu@6h>YyXtkv$D1;u} z=?w&*rfJQlsd++od^T`1`WS7yXi=qz6-|iXGGCq$ra9+a^)dG<^c%s#Y0a2c78@+h zU9;(oMyhgZbY-1!N1SSBh8r=j?-K>TyWLlt#5d*`;WsyQjS2AU>?=r^;P{0`-tR$P zMoyC}P9(74j98wVoKNj2I%qDi`cA{0v%v`G+*8by?nPqx%d3lK_AT;7KzLv!1X>l3*ShVa(d@3ok z!Ee1JRSn2&E|Z@YmrpTqdDaDKl!N;}h~1+7$;qUCEz`zytb~g|C1pR({}R9a3D?`f z&>Fs+5;#edtgeHosCE{XGRdB4<*BS3_zY@pWOhz&l>c4xL z68Be1%!d*j2Vb%cj&hgU*c3`UxJ-#h{TulCF98NlX)IYk$GuDSZw~ceXQ`v1zP?go zA(Y^h#FA}rs=Cz1(?W?GmML*_rNov{V(&5~ZmX1ddMH73f+c%(N2SDhp#%z65VW2MNwvB;ifitMWtxi1#Ed6^;~sT4UBi`=$M zkpqvXe_73r}vmkcAb*8V-%Uu1q5Me5o| zOA}(#Y^(i&I9mwLu8lnpkAV?o6b(P9XlT9(7pf!Iv~26)N-!rQxtCk4ha-*4dv&(5 z8r_{1{=N?$pqtXlK3M@Jj=N5gD z$nPV%rig?_Wq#kB5g0W0T^*KQf=G_H+iwh{qCL;!?)LZ8QAM{fAilp$xBEVaO4Dg* znC^BlA`VIXwSDTDskjq8F=0{o!IE8hV7BKzxUKn}eZHMEFu7+no^h|)##0t+%JdQj zE>5E)Oryl6k-p^9$ckHpH;-eYEXMq4XqetCw{Js-#yq~bs?;SN6t5;wsgA=sfeq^?^%tW51ULs@6w1b1q z#Kgq-M43s2psdEE`nm%tRn9L>4x3;2$c$VWK)OvMkNIp%?l37@ zChr@M`0bd=VT#&Fm80GM=95M){DlZmesXc(%peY|<$vQ73ZFeaGrP7sw|33iQ$aY0 zh?ZhgI$AVJG&m)wzYOnOtL=uoVt>}jrQq&H{O~dVApb8Oe!{ikwmzwP6R|VM_(i6>P&nmL%&W%<{ z9fP5e;PfE#VL*v1(l+%6=Zx|k=AP4BHYyNlecM#-TN*jZiu-0IioPvW`nI6zylXDlKCa= z*j;a1r`q0esqB>5v0D*fzlu9{D+28Fj@{y7O^d`YaKh2lFKNe)!%K;Q>RwyUwf!93 z@Vb|^WhejX~{pablQLhkAP zypxFBs;)4?We478wwTlVc>xip&7M*O-5u{#a_{g({+F?zcT9^s+MX}+W(UQ=(0XpO z)pz^Mzj36x(r#au1mE2hAHFQQxy4SNw5e=>$%}}I)30Z(tGN&^OS|v- z5Mo7t91)}5YmvK&PpHbL++~)IXSECa;~V?B*Nkh;S}D)1%X-8eNn6AV&}nQPl4k!r zRWOeBkLt;|yqFW3p^cy8*FJt_-|v}D6VCnHx9O|Xuwzw{^9CxsZl(*KYqG zFX~f+_?S0W^};ulD2QJ#OwJfq=dwC{Bpt`n1vserN;7G~K7&Fle~# zgBHg|w3sg0P@`ywJ4Qw{WYweFV}87jO_r7%4DPoh&>VE&=$-LwrMsKby`*#4Djif-Z#w@%)?^#IK+s zQRDF-UQHwpiz8kMwEzo&pMhm%i2q)z)eaZq*$Jd1`)$9+9R{F~7%vo46;U(9+U2(y z##Ku?O6XCr^b6h)Hz~;Uo6ww1Kyr=A*SNYrxxGIHMfBV06wYxxss2_vxxF`GL8Qhn zz^{Is$;pL+6UsQ1wx8RZOefUZL^{=Lr;|)nYoNzvf;4nNzoQ!ovjiB&=^J$$1y9&z zpJ|(BxA!N6p6N92#|+s>>d$Jp+v&6q_jpz}c&Ue5HoI0*-A!k2>QDYYJ*5YZR)ex@ zAa>2_N0C1UHWg6;%iTz4=(MB8AV}2>wK%1Ho+%-6iVt|Y3sx1XD<%YZvr4Cg2kvgI zrPh^nb{h=n@h88G8rn=yK8}IwBpttuhOOsq_BB%eSWFTD2+Zx22ho7Wf&BDQK$5GQ zPT$m@gB4|sUf0+oy;mNF!g@7RbU5wyCoiDWlh&tn2K%gcdXCCqoRb2E0clf`TGHui zUllE*o$Ag|Ik#74yT-7}5uBiGlZL?*2eDD1$=*a(kHjXx)uRDwxoD7D45egFE(iqD zBjAeYrhUs;(slN3WS%gBM&^*3tgm)*Lo$`l8yeZe)Zx!PmJvFV^d^01^;iE=u3e?0 ze4KKspQ6|#CHn2{{SHv{r_+vme+r&f+GhAc^;imK>yFvU)TT!#oqjH)KBdN|(vC(^ z_)`NtuH5AJg8ocS^};=M8`VQu%+z$+7`_^%nojJ;Y?yu1T3wh~zPivw^@nXw`T*Ux zt!!5v7I9E~&N9}wsuyXu*8x0UyZ}@`mp9gLt0vEpc4Gr`q}8kxWu~$#G(-ArRozTy zxA!`ZMsUM@q3TmQCxGTOM& zEkr66KJp1%kl96pWah{X)5T^rmpO^x+F#n(Sa)rmYg3=X!o66_7VC&Io9)@iKgrGj zFU*U4MKD}wiM6?6GFubOPEcRH`y)H-Vs6?@;VV78`vavS7-@|WSE;{9O!ac>WpZ_| z!|a;&$(H>mL^kHejE2Bir5A0EaF^kh8Lh+3mJ*IScL_0~eGQ|U}^&L`|N zk84QcB6h76vqc?q7xlRVa3-BgyBpIr7xmX^G&?NYy*1XG30|D__s^hYM-9%z6tPGe zTu)~=q-R)TkQ8J(&D(m~+#oR8>1;}WHo}V6q#LMYO)S4QrTN*7bZr_EBhy?uyD?pV zQGczfVCCE1!{rAOfcM8T>P1_=uxP$d3$G|M5^AQOh=^C=9sDHMCl35Ti z)#KK44M7giteTvnZmXKNbZTST6=K_TV@lneewHy_TAt2~y9mdg24T#R&f@hV3nfU+ zlfnzUh&jT?bfVXW72A?|CRJ*__NT*YJ)NGZMY|o-dS}wNAP9gi`zW>s&e~d}#EjsH zurRH9VwKRborj$uoo4$gOf4+_Oa-{zA8xl~HE%6hotkzt`qrCaQduy+v2-fbGui!j z&6H`IKMl~p6!U|KGwGzz!cX>KS#7Q$+RO05sf1@Sq;4eH#SNl0gEoI)o8U?zFZ zQke@YeC(fjlg-09o6rn|YGFiFt7DOx)6TPD-$EJafXy-#j*fJyH%Dtu4n2?q+O3XU zAd>uIbd6jzV`N2LH4&jB&j#r%25BY^h;TNYo~0i(WaOka&Mbrw4TAS#O4y0*3;$D> z^(V!;#$W>K>tyz*;q9xgpBTY`O+hK4nsJlv7LZs)mSG7VEG(UMlabbXla%{`zJwX@ zRgajNPS*=F>rFhG?yVOu)5ujdr1e0@e-~|J1+4K^lzWX3JK5VH1lG5v8#LFM!Ojym zXhaQ8)idh{IxK>rM0DtP8=>0ESGKY=Y!z&3N&@ewwmA2`^?-de%R zKk3%%E`#Tik-}hthjmoj>QDD(m1$kpxU$DlVWw%TKMQGqOyvP&U$)m}FTS$3#xwY5 zh-x~WQGeF_w(l7v&)>+?&6`K*Mw^6h6yurGg6`AYpe)*T zLM%0J#cVoAgX$-NHGn7wd96SO;mC?E{;!Q-qcmH(1R&NbKwq1KK9fBkdM6=ZAmr_J z=t(EF$Z%ptq4O6}xiD@(DLnui(j5s(56B7Wjs(&TV;3QBk;U3wLv0dijDF|Xgwo`; z;hq!O!6ITWY?(67Sgu5QT(pk(=%fT$7W1FI3^IazpS`i)7L~F7oKr(piOTMoX#yp7 zNkag=_7CmD8lR3}h~~78gk-$^PU@ljOzsS=habZ1IY#wyP4^haPZ?yR!i4j#vkbMf{m)46?K9+Ce}V3QYKQ( zcjg`lCe`>pjcPWMq9JoZZkj=zvBj7wrbX>@5g#4!1P6tXrS?|W8ZiSV>}3*D!+JW0 zLSk!*M1f*7=DZeoT6GDqrI@U-wIW{_p6Y7NC|^WZ+tx^mnxciD1zh?Y0Evf*@EnqE z0jX#-h^(yn9T#8n1$4&6KLa_8NEJ?W6v^feZU=C+Yy~)T$pEpdN@0S& zky|i_<^}{8hY4^7p_OUjtguG*g*$*|Jxn)V21ifV!=z;N&_5@*Dj1eIVX`9h|Kw}f z@3N<451JkCi@tKg-4p&XgF!N@){9_)rU;qFr!OK6QyJk(s8LgCv-_~A1x!%QH9{!F zq;v|Uyxl`3>@iGpQjo{(hm~=|bFU<9D*6YOOWe5B?BEj0a+lrwbr~7I7dl6=kn;VI zGD+=7L*fl?2NDZoVwkc&-GIWG7Yw*48i-tk2Ma9euHf?&$NNVJH{EpaIPWM-*+!YGxL+l-#DOY1I?5tl{zukE*bVNfM7! zjt0n7!(vk3?s{AMp+>!FrdIU~Py*z#yDD5oYPN3d&iSWVrW z%>YQSX<^T(VV#15h|z0J^GBqYG0axVB^$J5mZm3$u869!l$pORk0$vzSqro5xF*0D zW^low5#MP;TDBzLP)R{D&WDqL!vN3{%~_YRlXwexFZ%@-S4*I_89{DDkTIoi?>Ewx zhL>%F=i+$C1>CXo4o9O5a$Oc4%MK*ZB?Q4ppe35CO0!7|=th|C4I&i>pe3GydPKZ- z8-6})NvEA5jI^=}MqaWhS%0hwd=NDY75)*Ms}^Uwq{1IQ4i#RrZQ3YN5<12<(9(D9 zkzwn`l%PTuD!i+ZSptWdEvxV|v4rW5sHf5#msa6JgSiSn8;c)Bg`YJQo-vtm6@D#? zt*h{%#;(-Y8CT(Fw!?~9AWenGLL5~1ZUEcNZvwld!iQQ`uEMW%6@Hd}(5h7UuBq@j z22F*>iXau9pF)Mlz))4;D}zw&$O={XyoM95!c((&bVY>+bwVlRgJ3$#n=Fb*EBY~E zRkpVt31$vd>Qp*wKUNiaOh}iA%S<1s!qcoVVR(31g;%mfWL1V#!Ou}t_#c`IulZwR zZ=r)s(@Y9gJ+>u-X`N*Q{ZEmTW}J`8+Q%v)4rZj@m$IYw>6w0Pv&M~rxi$(~s@f=) zXmABEL)s`NxFI`&?aQzfA!exsH=!cZP=oTinZQu2rKxNqkQ56zCeI;yk>?^?+pO); zHUi7OoQ(jxaEG2VoQP`btuW86XUds>mH<&n_YQCbUTh?4pCzJH_`KYJQ8}2$%$)%^y z@}F@_ekYaadOA(^&kTBc$My8N5tWiJvt` zt1VOlq8#KxPoH($v+3yqJLujRt!AYZP^i$;CFg;cAw7MTo-h|=l#qQZbRNB%#Gt1u zz0k*%?nqF2Ku*Z-NFbf5l}@3jD~q)|pr?ZsghnBP43M4l^w0}w9X6pVl_(D?V+kL# z>5S{??6M5#>621LM2Ol$Vr4{+N@qwj#TUhyPkivnX9BJmvn}uF>1P=$EcEnlSx*;J zM#rgNoh@EtdirEpPmfJ%qFb8-db+;H%i+p;`e3=To?h;5RZnM8HIAnrwn)wrGV}gP zPX`Ug0!lpD@E|?CQZ43P=bijeQwPgGT}n3yj=^tPP}3ntlyb6Ri*YrbIT=#QYC5SB zE8)w3D2jw8r`fHFYP#suwy=VlZWb1yV@4y#@($~S!xoE*m?+v8y>K->7#C-yzKV!s z{BSj0wd5D1Vp)_3i+L*MMtq_ZNrX?4PAYI}b&G!Ip&d0W$9{Q`H^)b!~Hr!Znt zhDO{04s|Rmage*zoVsG|L}*R$U8Scu!b5K$(VkxJoPmFB(qyU`8Agr?ve9=E3#B zkYx@wb-zj^=I>xI_?Pxwn1=SRYzYX>sF4{pf*?W^_}DQLaT^HE z^}vaglI~b&5snC0dzyu?SP>(a>>m@Q?p$IXR7>*fKi1 zqh%O*fuNcp&|#}1iFXKC#!83G=(IezH{#ZzSpQFlH5yQ#54=Zx-erAe6a}0Vx;kKw4JB8FKw(aUj?&fh z{X0UTPHg<3U%xzO^=eopvFQcF%-^-8uG%eASc?rTo9mZtZ*2jgh*W`_(aQpu16D`| zFvH?Ze)>aJys{22bUCND2-K>}0LOial3XZLLecO(AvzE-qz#gaEM)`RzeBZ*Bw=3- zhFWG=D!N{x(X){b!ncdC^GGXkIy+Y{k8A7(?>!|cxDjoPq zNY=$AeF5CGwmI7nZZ>CwfgoTz)1QKFC`yg6!jD4W7$1wQ*i?=Mh%Lw9&Ww#kVGJr3 za5|?8fuOgiTXLAtiJ!u<(;9fAM94{f&FzN1YG`<$ZGpA9vIF} zj=bk@%yV)mS8IMoG0FH8m`5Wr!&zthX)ltUuD;d*raij(1f<()W z+7dRiIvP&?|BOJA0Ko?ECeBMXEs7$k6Sc}SRytJ`j@C3tUoe}Qu=+_QKSv5M7uDjD1EX}$&HPNCTF8iX^#k%_J~k1IouE`$Zx1`T&QpsUnNx9 zC4ZSv@s@SCEt=)1LPfFeX+ni(a3%6V+UZmamHEGIr87~E97$dRj$HKsE1G}(^ZdW2AyXsJHz?u({w!YFNYZr7@}j9@FANw zcyxi(R1dqm%ykN9t*HNt zJzx4buWTv~>bHF5&G)KwP#mt8KG><~>j1N<>2cH7p{exse23YkX^q6_#~6vJY$}Pp zh>AGr0*c#ibI&P1`Sp;Ues_!fpp%<#yk{Alu5e2MP){G-GNWIJqB&eod1`f<<3T50dzuvM} z=qR+(8ghiT_}ULVu?c5*Rvc3@&LiXYGmHbnhy?F~^u!}y)>aA-b_fiJ739hO>?mM#RCpo;3?E4ON#)G^tzYT>=me$ zbkb0NG+3-a9~yhPkW!hOJNae2&J%0dYh%OQyZm_8rR*YcOZ6`ZEAb5+*IV@Xi&mo} z?M<{pqv9KpBRk~$)E{V6Z3IEjo(C822PTSl;F5S>85QrT(`Zw?vrwWg-uXu2y(0pJ zT4fhuNV$0L6pJqm;ypu)&nX+QU{ZmOq5)5QwcB)ofeCbXaSn2QKAa;BY|?uex!0S#$+;nsSEE z#YO#Bt6akO&L4b!S#b?YFP0qIm_2t{0lTLvt z1~c0MZvB?*xm>FrObSCl|F*~+o1)K}xOroSepiB4UZ$YbCrc$Wm;puvjrYJ+@nAO1 zyuoa^13r*A{*e6&a0Wy|nq5B^ru*2PrrTirn}I`QC>S^&%7)!&;b>cuEF9Itx9i}6 zE{q6VxD#jbnd9vcG7!U-EOafDezR!yLn`I_? z@2!UVj;bsfB8r$S zUJo}tGi6MSuS2{CDczD7?^Kx4)M3L9<+Q$rZJqLt~I*AOI%4O4^tl!3eZ57Qv{KMj64FL>VE1Q4+>@1cP%oAB~9{ z^nGQ}9wma2HVNm*aS+bQ1}SdHs~`mv8flbKXr?I00*jg07>KB$4U-=IKQ>tak+1W! z{K~K0al*Ms*#^tkS9)U7dKjMsSFxY#5-@3u;96oEi~x z6gQOZ@N$s*L{?;(+@6>Gyw@*FhCXu6v@vEB_MhW}{2}|@ob5UX0yJrFk(GVtxUjY2 z%5NpI0us(oKXi^qR>aj7SwTLlCT?&fi)+qd#6{gIxITZOx^WM9t?-o;`+3LK7sSv9 zRnV%1KCIPB#LEOc(%ErL8Bd2#O3QyY&r=-F()gaN>1#?{i{Q89X!?zs-vhe+F32Zq zdY+^GqME-|lo9z^zsD!QU8^fhVOg+EzxU+w(7uEM`?9Xfrj0ja@c^SM<^C%B9aZkT zYRX++n4V(;hS7f2sB$MtrF!6M?7iX|G<7bUS_Q7{nclX*MNPrC6mp2#KPkw47$RRG z(oCH|aV!l#RS?kmlM)24Ygb}=r4ija6qWN`o zR$NJtNK+qUnsGGrrJAq_H_2cGG@Skznr#W!GyDm7ZGmF$OFSzG%e^~X;Lc`2Ymrx* z1+7J9-DcQPTvu5QcX2ry2BQx~kh_`aOq-^|%5en3K;KEpqeo>r-0~CC;juLx{<_0j zu;3FOX-Eu$qfLI6xs6Szj=o6?A?SMWUDTLq?UT?f;!evvl%!EtL$xwwR zTwsoRBPLwN{0z<06bJZ(YT|+z$sQ}Cnz$&YETbA}xmdL?sj*;*3n_5mUG+NpH%CEr z#kd`WR5*s)LLlBvScxh(YcXbB-5s15;0XT8o*5TTm=iwZS{F@0GReOkS9YDcT=IVV96}X0xgeK%=Jk>V{3WZR zWC2yd8k+q1m}Z=z%?I`tJk>LPbjBO&9$&hr)WXiwjzRYES zbKms8gOs^~RSQWxqFo0UYQc)DH4a9)We;8#_lIz)H4Oc?TLF00#Iyp-_A*F;C(Uz} zyTYWxI-64B3*8*b{SIkkRh6&zSW0$YG~2!amiju^J_IGmfk zpCvuE_>A^AEe_^3LnPCn9M;!|<)V$jv&zhEb}z2|^kffG$OcuP5@?BW9N+-J9$6X9 z=~4#+?Xdi8v^^HwdVBQ3sthpJ$jh3>iW#FTWtRj5SkLiR2Z74;%&5%P`j#~5WGI^K zb?1Xh3bDPoDm{!zeZ0gS=^~0_A!X<~Y=o$-z#bJl=rDTEvhzXPkwQ%dOPJPyhLMrr zuEshZ)uWRkzNf*oHTp@x3|i7-5-%yb-YYN?ATHTVAWP`dE7mol<^4@637z519xhl? z%pOl2&{-G=GAP>sac-TTtH9$yPkX2M*?DLp~8LRBD_s_re1r)0eG@sy0QvByO+ z#>Rdk8KYYJahHsTZHl}SjfZ^7T)GT@NxJM5$VM88a!*msAPi|L%0Oi0`7SFEBTX^- zqa+?*^F$Sof02=qCwp0l$<+2+FwW(kkSuPu@?2{PB!G7h0Z7rK9El&3wK$hqBfrd| z48u;?YsE^CBJL`(@Pn46=q>hQU?`VflDVO!3)GQ?VNqW9^A!y@T@v0;tr2X1p&8yu za2I8o;JHGbT9szN0Eg|z5FBwo#yA|d2?O(8F^W)k-$MCXgNawWV#nUdq1;aZA@OaF zIY7Dsn*Vl|md3Xh-{oG8DF7OmaM7@gH*l9}#}VpDP9iqYzsNZX#t1I6c82oP1GVNm zY*4I$3N`=}#H@iXGum!d}EU|vDf{FsvAq!-iBYPPi@$D z^{hvMw>{Fi1Ldk>G( z=~3_G_RI#iXKtQqlW3MTt*7~U$3|iENWWxr6q&;f*0Wl7MXs=5x+MWeqCB4pWW7PWT4E;1QMI8Il4r`=J2QsBlHxSo zpH|(^>V7ud_vT`M%yMh=#{!1lAGzFSd6RYjB>NL=1sI!^b?YolBCZZyLVt!Um?3m2 z*uMBI0p-3st&VaZ1VcFrh|nUWbMhd%OI1TTNDWZoUWBW&OZezYu+0OCmlE5qhjraR zFa0ayrJH|62Zf=E5kopci5~*`1xIIy-72)lt3kGEw%cj9Xl^EPAN$!0T~*+;VaG5T zm4s>nl$oH+(j=RwCvr!PspDXf?a!Eva_4;wlU+q%CVYfCv~zFd?1mG~`88JM*Eo_| zY|4ROFAqb~zgC72xM6^wy`ZJE0?8KGSO@Hi2NYUg_}+g*lh3qIeE~E*fg*Uret(xw z2-{nM{r>LGOYCL#PNHRCLgPdY5~RoMyrItJi#lyrCF*!bJK5}=4Prfm&aRq>iM{pT zh!}IYF=B}su$#%T<)E{OI6LZ~)muJ^A+bP_#hR>7;Ny8tQC@F)lpgV@*6U4WukEVY zYg2SI;J>lgCOu-W!`VpIYb=A2@qCu{-sJOdgm+@dl7(JDdE2y!f-t@@!HhM6X2oDE z5Mil*k!{f^WE5$sG$KXH+?TUCA{FkT7dI+lRED00w_UOSm9e^>AkAyx2gt2MPBatCMd71a^5pYsjt= z`xakCPi8bhW|LrSCuv*Snc4Hx|8uAeJeE40wK}#Z~{8pNybMOSlU?PC061)t|3P4Y^vp5GV;{X=#zwTqpN%7?3&M)%Y|5V7D z(E$@Ptk_xQD|oFNeo1m8j1ehcmhcE4obeRvxV=$Fcm8kA>1xqiZac1Ovo1&0lrqc* z|JZ-s4Vj;tok6*qVHG9~klYf1iayKF-aYT^TO3Mbyq)cT@GyT(X}WaML`!c=erN_1 zv2A7dyq|w--}mo+Jsd5Twa-?%1n}cJHoWf-dI0Sj!NKJjp3Y+L{coM1$L3-;YdWyw}sM9-_CIF z*`ydRFa+qj3XQ=kg2m#(XpNd#B}SCj8&THCPeW=`z~H`ykp4sO17niEE8U@WoQ;Dw zch$2nhBRJlHx506;6p#Clc&%D73AAze{}%?X&q!Vn3MpM%mdhIoSdmA{4J(A!jY#e zI3}~4q$zKu#mW^s`pbU=Q0~Wb%M(?Q7B|@SC{iVJ5+M=3yu{wSTr+4zM~S**q4>v> zzoph)lD^cyulDbGl1IV-T2BJN2K%HogPgm*^+F_9OWhfy{nvyunEfdGq|j0J^owES z=mO>U<#k<{XIQs4#CDEy4Pyi2CpMN~qZ~~J)<%=15P=66w?^I0I`BsrO&`Fn2C!QV z;H*T@(3HN^v<)K>xhL!};=l;yvj($r+SxdghIDish4qpTMbn>`X(c{1gUkedR-EJj z7{0U>5QZ9(yL;zqH&T~Z54s>!Qe$Jjyc(hD0^Wo}Zs(iK5DE%_Nd!c0S6F3y8^lQi z2*1}Ugy1Eh5sZa8AyXoiH$amL09~(N0sz;Ad&v-|Ri?0ZT#QDiT=M>nQ7$yvzHR&9m4nu8J0Yb=MConFZlk0OHNy&nQVNHFr^_qs2$NUW zO_f)mdQSTsB(LViRhbC%CuI5Wk}NgwCQx;-#E69>X?1k6Od(5)PRaU#Lr1qJ_&HE3?d z4{8dY7{4iaQXQLu=RPR-Z>+%xFaKWBgF*4;&BRB9%8<Q>&jqGR=n2&3ZKk&6mN{Bd=!K5*0^QrlUZDYi|`Hj6?`n&bkNRe zg7zk>nCh#F84xOghfVwtRtboFeV3d>*~`ieKiV3a`?En_q!*^FhY&K)c5W^nvG}6$ z2I4O)WiJ9RU>YTBu&bZg@=l z-wC6_ih~*4pp4j&OAu?9H4#5eizN2W#P?d3;1UL7H+`N?8&d@QY(Gz0$#2721P7hy z4kmKG{o&8Q@6Dfh_x1Z&B-B<5rZ6~U>#n?Ayu$u&Wy~UH(=P=Sjrkmo2DCb z@B-m|g@MD0olIvd{O=Nl)UY5(?Tj%%;WdSNS&Ib`Sf59Fw-xvh-J2ZDa~(|9w{Woz z61cz%E(RrRkJ!fDepZ->_RD0;6tXvD2T|jB^4n#;=7R4j1jHee#TNq=w-*hv7ZhDz z@~=8G5AU2sij2Xn02Dahl4k^-Z8P#chBBhbNMOU12+6cQc+)Y6XPu%%VJ zK}G$)_ULfop;m?DsKOv3jfRp%8D6a~{a4ybE=K3+iPrPXJ|p>QQOd94DKd8DqIc*| z7=aEUU|*dpA}AO4JJkYfAbtYx#W{*28U=F-*P!#P1xrz2SM;f?6nkJzo-WscGazOY ziPKxAD_Q~+m=Yip(HnuYL8<^&{@bLF{PSh24v{mzt8GWLg#}?s+mQsGm3-~5>@*Q3 zA+ff2l784zPhPFFRbO%FE1+|r`*qniQT+AqB`vd`nwk{%DZ{d+&jf?0WuRBS_ikQM zJc1<7cA4q&I(=w@bL$Szn#}i*(v5#l3%6~TsNOrj(`WqYU9tOXW%-dT2zvGk#!p#{ z^kgwtQYfisLYUL1cz zhWUDmVK*`~zS9cVgObyjN?aECNb&UdR>R{u>}L56TjYN=0K$D+hPsF3?Zp~UZ26xTrR!K(a3 zkUK(&d&$jy3Muiu6|yE!;$zRYJ0%#L;`Z0s_NK3v<;(f;Q{o7+R+^M}@@(6`{$wce zJr#0)D3rMGA4(*y)RFrUi7!X`p_7-12WC$xC0<=2YXT*%JoNF$Sb_Zg*Jxn^CEkCe zEI$!SyjuWQ3gp1gG>~&4>o-0FJ-%I7SitoDC9t>LBcfR3ouKJ&cR{r5I zsWsN|h$N9~`T0A4xzFVrUQT;>FJ}AS_m{OYiFE>kjH7q- zGgEBPWQO{O=SlyRBNkwFSA(+ukc|lILDB(+gx*ZFx;K+418VSj$(vcnlcq#ekKrlt zwB_LGL954CPh(60hg&pS(P>Mo6Dr2osky7)dz;~G8xL&Sxylm7N}WyBmZ{=lA(x#0 z_ub5ITsyJSYirR%oBzu-TUzO!Zjdns@Uk+C&;K5_WU;E)<-ZjHUg`vR$*~9!tcd_W zqVJsm?^g9fVr%=Gum1Fx-*w~tH_e)n9y4mq+C&<#ln7vBjE8@gji{Chq*IJP$y}ROvhkQ5S@9$&l8VvGTRe zP$!H10SgMR^?vrFBkI#DZ!i1w zz@25E!iaLRNqs~Ge$}N7JN#5M>zr+Zx6aw}YZ0zI{7HS=G}bq~utwj`)_Mj>6nro5 z8;hA5eVc9eP0@b!Z8r3c5T^R}nNO5`d$8);8(v}5s=j^n4gdV^<@;{^z)dCrM>;p> zI^fkD*8N;A)FcMThE8k5BxOpG+j|6Pr@A)<6WlHR%{4S zLN6T7f>sfi2C+tJ1i??nz`=-y_{bh` zg@)K8nH4p}ot;uclxHE08Ytg4y)ZwnA4Uw6b<+$KFfE%S=m(MFw84_ep(sPmjHmW6!^j92m*fqTAK8z9MTf_CPZswr#C5^BJOLH_ksKGisJr_mH7DZ zH~-}a_uu&Po#&4772H(O8{@8lg8Rn>;y}W_-w=p`sUap>&Pquo4ULsHxTMF1YH-q0 z;3Tom2qzt?D(x(V&ePJ) z+K&zKorh$Pt}g!8etVUjb&=ay+k%~S7lS?7(nkPZ#3+1S6>LTmwu*PSp|w@2>oX6& z^>1%@e|F3tP5FXyS{EO%Pn}54=jYR{m*Xt^k?4xm)CvuHN1QhZUMq+bM{;? zkCk#U}BCO6A2a4y{%xs-2eW|=;1Dtwt-l%d-63YX(YjR>Mz=NgiT>{6!F zMYto9=yhNHi)cvSP<1a*w;5(N>K^M}C5b{uFX?*L5^al;sG?j+qDho{oT5k- z(GV;kQKX8vle1#B#oeR4sHA026QeMQ?RE{)tHoa{$E&eG@)@4|+3zxTCO zm%@mOUF#z{#;%n#vM$v<470tSNYd!)s(X({8buf5-=8$PcjkC(qiPl6yqV zxm`EkAPd^1d-c7CxBsAWq`v*yTfg@Dn{V3ntL{ey$?|!BSD}vZu9RZ! z-9+A!1(=?=lI8Vxd?qUSYy9$P{h2CROvXGhoTztHJ^F*HM}J<$Men%tGoL?j%Y(nq zny{l-Emd4}wMTMJt<_=y$eIt;2yI`y=%H=G;K4ye^P%I44^(|SbpKyQJ@Do#mh-C5 zUiZ$MZ+y+(-<;65%7I!l67vmWg;iUc+pEQ)6zX1_#o0mfw2FV@KkY+?u8CU8sju&0 z!|Mx?f~LPUXn8M8zgA&`C$95#Op$ba*3Qd6ERi%jm=KDfMP~PijF{B*oN$mW*0C>^#}DRuOqFH|8GG{FAYa^0hP$KzB0m({(J~$2}FD2@_2HUIFCLhB5P8aj{ zwbF7HeFD8C;h2O5(P*2;l?IP(Ur5+tWCxN(V$tuQH9{~lvb{3G8tN5kXNu?7Yf-qP zK|g7oerj2yLh8vT{b(XC4BgS`CnQ4^nT*oU53~sJv7w(6>3)?ivSObT=>Al4s>5J} zr6JHVz>o(vA<{zDrrQ5v6?WdXvK09x@c*2#A-_KB1*wA(`>0S zrVW+M#6(Qo;-g1ASY%tFx;1Ds-Rg@;_{7dFVfK|PlVjRs!z&?Guq0KPDtN4#A@XXY zQlqMQOY~NzJhf?m5nqs7f&r$ADNl<58L><_hMYsk2Y-<+(p2b!$vP7_CyNCWYlgTI z3&vDhOG*wT;PpI+#D&qC?6zYKh!wNNv{!4jAmch zqZm4)_$JVg|IjHJ=}8lx@ypSBaJn{`iTFs>XdBGN5!xU=RuGHWoWqQk>cqBok^MiM zEhECw(gyA_RB90GfA))+c150Ji)M@cv*n)1itmp1$~SP4-g8dczt!$^XJ%=pRZWOl552t*xE0Zp+@?z!1er;A& zdH=e18nFs|rJCN)u2Ai0%Zuy1ZF@K5DYmv$PWxV7gF)rM;N{N521mXz`6z&}Rn`Hq z9(etOcK=XW5uR2pp;~B%MueJM4Ysiz&%JeI@)NMKc`olgS$p+%8a_Gn-Zu^k z{hPDP`N@mjq40{{lk_GVW{Ylr*NRjl_`aO&*=r{aKL?V8;Ya>XAb=qYn}h5$Gnz4|q#*bJ%K^+CyrU7}LP)SvNJg!88wUE7#!!#(4}EqSOB zFXo)Vpc&Gxk%W=lrB^J@A@a8?QKNRk8fEdjltCYeDfSw$p$Ex?lwjkmUC~2jYu=tJ z9-OeoJ)apQN`Wj5yKv?{Hxzw2EZ+r{rDc_pWr9_CKs=&aRT}!0Z0-TR3(3Tm$XKOmow3;o zZTt4#u;gv7f14z~aijTp1X5)O9-Y-pif21?@*VDb$hL_Rm%_&m)zJ>eFlY~|H_Tj=Y5m~@cSZp(?D)v08L)Jy(~1URd@2@HWhl;b^AVUBm8;s zVeU*k*{dJtF5)3CKEoX+lPh~i-Vb6 z(atYcI!zX_)$$*jWme0^vdn1E6d}}X1b@;Rm4Q4}o|4l9osM$Zg_~(tl!~;g>sALD z)Zn>FwwwG;*R!F3OPnfGcCKo>PB5+}+v6l6-N2V{Dg?>}@B2Rxvh>2C34NCct(TzV zx}LHNuEt$0W=OsrVA0@XfCEq|mZe@Tq?iSRLz2n{2O(B3v%x`@hBCZZT_M~gA!;o0 zOx#25;ap4s?lLmaSV|Rm2{Oq8A%~QpVhegS+F$Gq@L`F;+JSY(-VuRnP}lkCNTNY5 zE6Y;PP)`!9PP4m01XIhZ?ji6FT6r40;rQoCzE0reY7qz$mO~8riKreLH%nGFny|7fJ!mwoE6s3n& zic0VDp!5EbO04Hr<^SZ)&|`OBPsE|#LQRJkcj z5LJdRU0MFOEu^jCWYMQ5+n}ZMl5N74rX{vR)$-T!rDW^oJ?11f<#4_F(6S}jaU;OV8g{CAf=18_B9#)3Vpk&pa z6pOML?dlw8-OI*82uJs3`f6AM{v)TGA0NUn0+>J;Mlky!64%#4A=e^|xBPezhMgS2 z4rH{u`MDoW%4oI7bCg_EHfqYLY_c2?KY%f>rDn>hY}Axf*;G?bHlaB47*X%02ys@X zUOqm^-!eLF9Ei=6inh$W4l#1+c(EOS;NhVK-=bopw6bH&bQ!gGWX_D*MJl64uPInR z3Y|+_n~R4{MNCpw1>pAIqSc*Tn|mS11fM(ZhwQMN-!;eG;dZy(J21gNAW_`zomQRY zhtpv)jzpSQ;y6AzQmfM+GAzY|5B>Qvhbl~Xf$^~_aBLpD$*NXWoLPnluI3 zB$}<69oPBwR*EeE8-%Ybc2P*fFV|Q(I^HNA3xkTH#ZW#kxg(XX3}ze`d=1uRcE}X7 za#QLmcgv$JH}F;7oIWtqjZZ}{Cq8>XDq&iU#9Jc~l?4)srgI>GZCbhE+Mg4j_D-3W z=*$yzsd5#%iP)~3y2B~iGI{Asul^{*^|a!FxAGg)00fxA%ml4rtAMwutwG$EM2 zHmsRl*+g^Z)mgA-EG)j1Jz4`MXfIEb58th4K8L2x`ZTQTMCs8agh@l zwE5Q@CU-7pkTH~9pvd3^-;y_@Z%Nc=z1EHEAM2E2OqQ+1h*CzKJ078VU_<~eh{cOeejH@aDNWv7%vGc_rs)Y+^H zC#70GV}bz-VCN+W6NFsG|CUwPNC08=c?BTgu3ZE(kvZF3T3y`#LMY#Z{3l4D(`r`y zvdbl=l}g!%#Zgqun(B8K+JS+fl8dGYt~nncj#1eOLS}aE+@9zhGbn6x_6%x;C*pF&sc1$reH1box_67 z;V;n@*)RM(Xa%xpTE#v}$V{P25CmYpl&e)-%Y$|xcyfX0E)Y+mm)~XuC6BOw)(T1< zAS;Usxz*e<$cFR2i7vox z?yPswGOK&v=DZU1W?qEpT`?N6U68K%>r0?<4M!EH~(i{8P1 zR8~>V#*e((c#MB;9j7~v?b5QeV!H0drC}M-a>9s#n#glJ)C8VmqbBes;zZRONQ2Hx1<=fJZjfDi+e=C5%*9JR*}9AY zkuY?t97+miIfTd)#k2r_CNlgD8HX{SgA0Pl({k9Z%WtC^R=G;MlN&4g9bNLf4NV<% zrPIlqMGklAgNECoXMix(>*(^3T6rlt9aN))l>GFO30?K_k>C3$AoYV+g1s{6DDcfI za!&Y}!Nwtd_aMJ8y+9gQ+0#kttzB14-e?mjA#&v&>K4~}ew_h$P_zAAuab1?R_cnJ z9TRQthdbm2%{h@WU}$ecAX0k|+GFq~7eVbhq0Rp>QI2%1i6OB544k565p;`Hh?}!3 z?5fYz;&qzX17KDgW^pig$3@Oso*I$+LNunyqCkfO;4f$kREJ`KKRyRcv zf_Tt&>UB3NilVC;)O)q=M0u`^197{|s5pF-detxW$Mj5;L^`R^mfo1uEp@&zkU%gi z&_$Zc#6k$A%Z-(Eym3o}LjYZ3&fkw5st0II)P_CaaxOj+C*Twg1~X>#2@ip1g@C}x z>T<5$kO0wHSl#B!fp<|1J*ygd#YI|-OB=5?dJEt*V53d#muJ|~gRGQZLW)Z-b*S;C z10SA>b&EM*(K#_vfrKl~E0JTTg5Dx%@Ut*DiAB(Y8kZ10sOnyj%t987WeYdSg~@|T zI-P>?jgSHu_Mq9K1(p>w@jG@S`uUv;la%*ZBG7g_R7Mw98r8j}OuFjnX_o_kPsKl9 zYyAspHXP=y!Bd~|Q)jO~>&$g$Jo!m$PhWFdfAy+`9%sZ3_1{d_emcWpJ26siHV@Q3 zfycVgSz8wRbF2#maP_AD)oaACmdQU}uHDi9no5brjlS|vQ_7Fy(`m0fSgUfVwblLi zS`0#$qxO0OqUkr&x-%UwGe4XDtSy)|w3tKs%!Qw^?oR_Fy!6w@^U{XndFh;^zSP6o z?!SLe94w&H%=}P9$`s^KJ0T{Z3+7E&?4q}AhBdAz&&@^1INGD&5Y$%DdNJ}ohaOJxgqs8c4;rOj>NMh~I#!BKG;*`Y{(dEu$?P2>|e&il6u#}%NCx2#wj z*FQ`^NLqX^(ePBCVw4A%)lL6)(g@ML2|ckC~qh=YXHEK@{qXwo!q_?r6 z=cx^m#c0gflt03%ZNe%DDxwAj2iu5A`cP?a=)x%!4`VT*2+?>bhEV+N0gcojB-|KI zMX`axM(Ig4ZHhICpe|6mPi-_H>M?Mh(kOmPEdHt3uBah!pm7Q|07pzEFi_hW2qyH+ z9`+Xck?nsCChbHfT?-g4$rMOUR<+VJO;EDpTaM^PiRIvMkx+2A;!3Q}3509M4YSw^ z3JshbDrQ+B6(>oOQn9QjH_yf9GRm{6;)zu4wHOnv6$VQfT?`0Dt;{=~s(5k97D%`> zFw4>KBCoi_YUEGhZG0Sw14UWl-$0c=MaAG>7m(%HM>NGO18yXfsk! zUHKSt`7^@HJN()T=GVMiMVuF;*1Xi0g30}yR+Cs3Y`ze~>`F^t|8 zQ`qj|?1hV2zKt-|H~vVbKuQS+9+vSbsuK8IcXvNqbuhM6Aa_ zS^Mx{n)~ovE| zWWyHP%MXoP#y`ZntnfdmIw@!Z`Yi-d*GDz>ivs)HfDxoFh#oPSDrsy);}SW~(!}DV zh|7++DHrE-eEWr6iIlBOXBw8aQwOw;ccZkoeq^My6sITzk~)*&ll{Xgq^0cK(auHb zWTHi#M=rIJ^=Y==B~bs%4ey|TTipOwTA-(r6^JG#;4Qibp@zVNLH6azx`b$0fb*FP zXK-o5JPp8#g#}_eNzXbfJ4+Rq_BSbMnoc&#I*PG&CCj-gi`9mTYa;u}Qy>>9`9Hof zUQw$vDQ%vWpLJGnQpN>!Kbk9QOO)v#l*LaD#WfI~GzA3SbWOpjklKQ8#>q47(g9*P z>wFVOas#fIy6Eq;k}2PLag26|8Pn4>D@8u zH(I$-PXp-FrvuFs!xe(9Vms+`C@72Vt&ald@Qi zSaC3U$_MK1@z_hHaef*f$T+W&b$<$33trwX(VZu!rEFHHj|(@3hDd;`DVT`;Nb>ev zef@tCUg>G4B~~G-GO%CSG1a6V*WhG&bfWC4h$BGkHYNC7NYb_TpT#Qzrm16?_Wz`G zT}`7z*Yz$}(32VxnPKbq{AgP3i!rv4)!@7|!sX%pP4RtG$8Kdz*1=x?rSW|ZY%Cja z18S7THKNNYjqs%G#{xHoqGvAXa%$g8dDhY< zB5B>+RG4AKq`*+VaUsLfm?T6i;S)P5IUOAW10u?QtHs)mwxw0Mm||BRNTX^0ig-*p zDG>E!@5_Q|Z*@T!q7?*(KGB8R9&Oe}o&!h6wBw_0SSviN;og*nOBA}udg+c;xWVk( zN{R>N+__02m$D`XxtvDuE_$J?IqQC)W!;4F)a8`%B#T}}aZ1aBfeRH-$($%I&~(Q_wBwa{oBb89Ky zOs-rjyxdfeND+J|TshzPSihLnH^0ov$k0a}Gar@d7=nVFVL;r*n>Z9MjecxGp-c%{ z0J|mDu|=;<6B=xp=7#1Jo6Zff6BxsAXTm?SvkR4G#PA6o);ErjD9Zy@=q|J96D673 zGrX$+l2MB9(V9S2PU-qa0e zZSbV0aQ}Np^|zLRZ9pWqr>pN$AwdFBCg^gCOemiO-WNqo7dVDdaq_?AI8H*<^lB&f zAPqf8r}dzWHlqC|5a#On`OmJ(Gfsr8mS*H-GAWswcjb%uc2@US!&F^am8)iF6_`}= z8s#Epv=`Iueh&MtoN#%MArNqSAzHoQsJ$vSFmtQiu z%$K=+Ns<-5By=;@!uXe2!Q0fu_hntoV^del>N>=A+mqoP6N>S=vV!laof^y9F*B*X zZM8EyPVI!2P72cT+OvWhX^%F__Sh3ldmU@<2v}+>fc2QQr}+>;K&vGL2MvO*L9kT- zU^G0A0A!f5Km-&eM7yEEbo-1TQbIFW-X9@H1}!aIATarKsGMIm0`9U^OIn}As*R2L z0b98tw)9>=++mrAZ23@DF6T;E6%xwIm0z}8)-b@s^4m@Ey``!Q$o;)dRT-fO3Sp0W z!^F5lVXbAHvrt%T`cPR|Yn$ae;mum(8cA=c*18DH2pyB71RV!06xKdxHDxHQHMF}d ztbw$vEUW>)To%^w3!7>Pt`9>X?lLZ@19Pw}tO0YNEUW=@S6NsCW`9{&1I8BFiJ9v- zhpPq5Ar|F9F(yci0qek!+X)Ck8Zo01UB2%~g*9N7%QtJlJYvA;%^EOA%EB6E4m&V= z0x*yV?J|OOVD2glYryO;3v0maD+_DD>@5px!0agtYrw$$!pw^tF%q0&!a69+v8)Ek zBUTmf)c`pX%W7~Oj%7744#lz>6mYzt*y>R1w-z^5qp;5kYVGf}f?DHytf1ENiWStF zz1|9HZ6aCJrfnU{3flDbjPo~~&pO9SNgn%3W>m6j=1D<|TKrX7wE9wOi)L2MoWUDs zoY6XiH{#?AewL!M7MCLl5cZ6D8WcZ?VvA{6E*dveDOPOQ-ewQ61eS~ficjZLo6jT< zgX+fbv#8iaIMxBjx^=B}O*j<8rsjH{Db+0SfFn`Hvl`R_&)&9(SP92khr_lw8yraw zh-5=fz{lypar)`4)0=RVaY{N+!-s+{z>)UY&02%QBP$e}H&(*2+TjRUOAH?iQ{m_X zN59|dH{poUL*+oJ!Jz<%!9jgBI6TS$9KFW4$a}YOv3(o{hk2M2@v#6L3kzgbYSi3w zOs74oqNEQsV{lMk4G#Ctfx~>w5+Ab>jv0TO7t9o&2*(_7%+0mtnsCT}XT;N%J8iCc{H(;?(f}}Ym z&|(}M6I!f_iO{ZC`8a0%eS;R$9pRF*_zgi-|K4xBk9Cd)KLj7W3km&|;TN zgcciUBDDU#L5uNoDshYbaZG42TqZ(`ku(unf8U_RIyxoL!X?-!0n#O=%jc6b8~z*ie+CqG}u_{o?Oiuom+vK&ntPvMK2W4Z{^mC46bqEP8PyO!5eM@I>8199M0-h#Qc4Olt_IL zYync+;q9_k@~x%ElC+Adk9oQCAD!!VZMr*sS&QE+?zi9Fs!e+rp9Btt_z1#DN^WE- zlbf0lFjGAkgsgH|@o64(J&~k8{u>H9^@4w*pj|7_ zj_Zrrr_(>*^)E=-=oRmZOW8&_?+`oFpAZO&c@Fq&;71xw!F z^8tEr7A4nMN*qSk6WU~h)npf8%9i~@D!IC4C|jdpW$Ty{Uk+2Qz{csqxIxYmh~(_e z3Hcdxb*7Hq;!5wFwnGr4YyHkvT`-XL$Yy*PCc7Ef=uv?_vYDR6zTem?PAI|=?;D;) zYHF#w8GHj5`)M{ODHI6SJwXz6fF(Tzgh6(Gy4DkMp3Wq7fLc>9gRbDW8D-01qJ<`8 zm#{K*4FV|AMb@Zi+Xhew>(sT(o|_(fFW5^+*jF3;KuU8Y4Nr}+^x;W`7#p6HHBF0a z1`A+gZZRFq)7@E+F%u48a7;HVWzRqDGzg?;MGX=$G7!Q;JD}0YAl1QG5N~t*2RZxq zZKT)pqK$dBZm^218}w3~0D8|)Nnv8=K=GjU(jh0X4bop*Z`%&TJ68-- zJ-c-Me2drSBbZj_WH9ZKz}y$XynQm5_F@I5z5eLIj1XFNlOeQ6f^dI?@Q%q4+KUy0 z_WG%V(5jmZp*<3WcSQ*AoD8A8SV3s7pE?Mwy2%jQBSCl|LU{LN2<^oRLVNwxL1@)Y zhR_}f!h;dQdnQ9@FIEuR>yIA7hgNku!6stmLYb1SU1rh~iyNEU8p5#BSzakR&kQ76 z+iEsa)UIJeidjmw0@5rcTMD|UoE3N{^rLG_do?b0vk^!&ifu&Djn5C4Z9= z_nPKI%Eg}gcl|pofeKmwwqXUb?G%Nc7l-JSXZF@tvPewvu^4kpelZf)cJs1_L6>2Z zD`HgJerM1F;CQAog=Z$2!UNl_Jj2(@3)0CMVT_B?e72z;og^|7S2S!EZZNcukr$+6 zdwPo$Bcm$=u4_xG1?E`oV;hpegQX!ek`Wr1=U3|_+(gvJ)i3V%=IcY@ z$-~@gVJi&})Uec=7nlY`kY*;2NIz&-q-ZCT8qJa7g(mFP{u{3YYr<&!Hz32ykxYpk zRofnv=>>J zPh2dQPoBJExH>#>@mxMxwPQ$rMfEC(X+4o7-kWVn-z@|^;>T{CrhYw~;ip&8Ou9{GixbfLfvJ>Ac>Et7=mh6yp{kSMg3;Q z3*+`nu&8>!tnf^c4Q2-O|8+389>YG937g?0TQVA4^dXrapEX=4+P}T1=uQtIPKkD@ z&a2+WVTnDkN2w(WhA)2$q~q8>pP%`n{X4_?&Dn48`TSr($BH{aCWD3kgYOb{0sOZR zNUGnMaET8yniY9sT0@c&9!Wy;F#5a*Ki-3pd08;=9@Ni+|8P%lFvc`SB6q%3ns4sJ zVAW^LVI`sJJA$lxQ-FhMWf!7mRfq(M?#8} zP_FjTk;xhgv+!uwuShfB;Yu?GZGvAI{NV?d`XJ>_hMC zU0PtMT(W*4>A(H8C@9O3H`vjCP>~JZ!p$1UR^oR<@j&t`3uHGlFolJPj$prdxxwQo zX_Om0j+R)i(><2iX1Y&xRtPxgC&HPQrQLhF+G%ef9Oy1~{A|!c=Q#_gTdc!w%>O_P zXxt2SR2v4R68+q3A$Q+ADX(-?lT6Va{Wr?T4L$QT=dyxOqZl`Wj;Q4w{5qVQGeOKX zc;1{H&@`(L-4Qd)^Wq+cw~idRg_9`DLU*;S@XmRK)cjq{O?*Hre!$-KVJr(DEDLKD zJX{vKaj4G&UIWCO+exz-eRA07*{)oN z_AF&PEg`DGE8Y#hoxLC*jEiNhPLNy2`y2UQE}bIMC2W3Fv6a^7&<`oLQUgcu5<9oh zI;9b(@T(=e)Ul_GR46a|$#5F-%MLQ}U++>7c!4(i_nOGaiZysXeECta^TwQh+wCWf zyDPj{;pfUiZ^H`jEejnIE0h>Pa;f4e%uBqgI4kfFo&lG-PFYK_zMd3>y+>z)A=gzj`CmqpwjPCc7Ku1TRIc!4x< zB!%0R4h2C*e{BUpIPCz3+Hg<{P)5hoVk^HS(P48vIAIVc{bE+bmo>$Kvr=X@$|X*w z9jp{>;me&G??N|oR9g}Of(u%*S60H%A4@D%CVUl^9cO{cF}Gtkj79YcbTb;TgN?TR5mq)UlkwVp?)Y&|b&%9oP`U6B16 z-{Hxx=k;_w(`->g)7r58Ym~O1x1OA`W~N9y-G_8?kTzo|*)`qX3?A&7)6~s;aV=@! z@izLgf1k8@wyka`CEFkP)cgMR{deED_a6d10t}++k(31}{O-!G03txRbSNToeWVIn z`r~dSnNfn!T1j1_?MeIJbFPsnyVsfb$qCwEv{BJB&Zs@KO(1LCr}#XazOz(EU@~8J7n&t67r3 z5cFoJRC?IZ4bL4#X1a7`llDmY7mxT&Z0nA!sE&;j+|wBA5dTXsZv{ z#SV18bUy|B&fHGU(&ci#I2)YL+2DNc;y~7z>UqK%j+*5cNO=^#w9>*2Xb@`$1(k^S zb#l~t|Ir2&%e>}lRn2c2UqaH`6u%IHnzY~+zS%f6f>0^=k&QD(6^ErqfM$xkGrBN$ z#0RG`d1J>*tXl!fwzM|Xak&>Z3{aJId~1!Qwu+=A>={~#dJce`KvK~6(Wxomp40C% z6Ty78R$ZEm2Qk!R*tMWdst@s^lunw1u?juolJKRk?4K|5|h{po!5NS_y|& zV+DzgWtD}OxjipgF@ID0gZdwl)OB&cnDuW_Y?R?AQg~a4oBdmN2Xe#U`*wBtjq36% z)#cxnm-^(drD1XO@f%%Tx#?k5xx*iHSm8jrAtxHVC-6sfmbg(XSE|bi`v#fORuTPaZ$1>|evxB}#9d+d3yyQ$!@!k;)en~d6 z-c(Q{E_KLUcBhg^iK0{je%N(<0+!3R-lhFj3;5B7Tzl4EmRax8PJ!29DqPAKxQF>Hlkppw6o6h3J?=j%=!8$*y2Z^wK5cCu?7GFmkvfP8t3|>S ztoOh1sxW*@nU3+6HFIf<5O~jhEIsUK9Opgv?`1VdYu9lii#9xy@m5DfX;q1O0uK9o zl%hQdHkFC*q8LK?##o6gW1B!gPLQJZ^&AyHJAgHxvtGC`Tg}l6bp4N*f7G=@Q>iQj zF=^gJkYt*{Wp@&0m1vg~s{*VhzHCm&Uj3?p=DebQS>ZR!LZ=2R{7zZuG-HK3C2Cx* zjk#$q-+Sko7SObVJ84=<{&Vz~aj)m7=>44Dlhnv`dDIvHFA61b0i`2&91Kae;6v*5 zcqlyARh+c%OY`?99+GU;)@uTGgvQ@dy7L36=A{yD2#~DUYm(S$rpe&&L0mdx|GgxFAlJsp5TLLGXB1P^FJz>M zO%hM#4}nqii@&@%yH$1Pg#|$O_%(HJ#tg9X0}7t5a9uUPHP&MPQ;OgfsjNzIpPUL^ z?PJxLQza0IwGlX?(Gf`)4} zWt}b_RapCcOeWHG81-SK32N@ACGix#G6GVsYRcDR+`QnuRXfsD{&{c1JnOzwe*A^0 zmP|SQDje1)V7;GwEr^Yy;vA);B|I^%3UicZ>6ksBZ`|eZolnpNHjN0sMxTnfJ101% z@L+tdGf*eI9KPneG9qRG_5a3$xTC|b6^&+Ah$$R16~;nAu$Y&@6vuK$mqkcaDB7Y? zHi#-YbGn+Wjhtu=Z%9q+BittAJPOj=w(q_3mjCp!?T23R<{u>LByozLmbJDg!H_IRMZsmiY=c-RC|EJs)q#npFMI;#JY4Nzrg>P&!yDyEpO?JCow7lGJ`VVWsjYapCa^B{H{&HRPo`X#c7GL0hp3zigtug*u1 z1!RvIKR;DR_D@Yh_Suf?vmYI@OQGFF_BdshqIx26mQvakN6qh?N}mWQkX6y=Cn9~W zWJ6q!XW6X7C(Iy_EUT?6s-_NWCKpY<&1Q@6=%CZC?;;(eQHcmi#MNQExG1A7E-8H+ z8T(QV1|M{p>B+@Z#zODRM~C!NPT{_1c%p(lDH`8{JtP{xS-;S@34}V0Ga~(Rz@YJw z0dp-J+!3?g@CxH}Tp*5p^N+_!ouQGkL_8Lm6eW$%pE!M)!9Q-=Pn#TPeUs#aG%zw7@c4HHOINb38C;-=%90Nf zuC(N3vG@Wls;T($HDS%0^6X$59}dg5j!5jO=}wVI5$rQ(_UhowO6~eTee+x9`swP0 z1d}v*)$zDPu+OPR_Idcg=F1^Fmh_euyc$Yh;zs;=$*y!&ma;av`086V-MCThFTYpQ zitbDY{4yiHDy%cHwNS!gt;`(DL+X{e0^gF4Dy6fOJs)_FQnwIS)e{;kt;9-j*dW`e z>WjMdC}UI0HY~=yl>J8ZJ07&XE!n7Ig@y;S|J7#tWvVw8cr`l}*49m}$0n+QnAtUn zHwBNmW9r!M*eJ=Zmgs5^rB8o|$jzGU@AUAR2-;TL+ENG~tb!;qHJDNQh&gJDtOY5K z%-j6W9G5J1UCOlg1=8|M5$Sz?sRaS*2adGjYIs>uSOgT>j0Emgqc|)uz`=^eQtzxR z#lqJ(7Kf~M(cXl~TqALDNW~CA#Z@e$0>(9N#s@b(!+ba|da{H(?1u2WvWlv)n$V+a z#qv%fjDP_T^H+5RUw6GGaP2M4T+Oltu2{eW?GENRXiW-=L5}knJ_s81K*~Ii>kfp$ zv2_QL(!ELks(BpdBI)1d8dk1B{{xyK;%V?`;{rwZR$U&7Boe*j-l~hvvM~6*F(~MM zs$;Nx$Nf|lPWDqlZee+PqVKFWYR<2F#6AjTrF#ei1{-ZJm%(^@6PK>pYfW8S7S??4 ztINV#OIN9|ic~`M?pReJH2C7UCnapEo{-g}U(EOmX0PBTG^QZrB{ZT?jv~rxD#Dk4 zn3F6XK1K{m3{&^nmB`G9wtt(?B?>(+vh`m&kH=6qZ122eVPqW{kZ92uA-+$F+RPu2 zpl!qoYaTf7_iwt{Y0*Uuf}sCq^oS@=wIPpWdMjw!|CH(!s1l&nS`B+;OlVdv-i93~ zv?PEi@=;=aNwM4PR z8@cexMVOQm;6j1wjZy^p+x?F!=HVdY4caWJ(EZO^AU5U=YHGI_^9D0_KdOKOP$++z zN0~AOQ-`ns)#B)+N77;E!jy5WJNbkLIvyH02l~{z6IT3gKkDj@b1U;skz1Kdi1Y@t zs0=0C;1`u4*eCGIvh<-4dQ5&99dYp>ZI79DDxYN9soabPX}%iY)_tei$VKH*B+n)m zF2cY*x1kX=hIP6|7$}Ql5XOO$Fd!mFoA<_*!_bB8*#!!l2k& z$Oqhode}ZjqDsPm9-)vXVXQnxgz@uD!Vr$lUTBbpO2LTPV{%tQf=$a%Sd%|xG3VyFM(^9bc4tmRZQ>!(pHwzS4~T1z9#A&-A~TUg5@!R+(uYSa2>;x5>fZ1}S! zE*8x-cgx=C#`XL9yt3MZW;F^t_S${$63l$D2A)q`y>A|r6RI-}kWE~2ucZJh7VMPd zjUY>WXu8_-DAiYlz!u}Psok&=*TUOPNHiqDk|nsE2ty-5^}Ywy-M)2|P+F93->R@? zJNjgf3TtK}Xb)4nwdq$8=gfdMmzYoXxVcTp-o)VqjR{#;DXv0c^FE;CZ!=%g^ikM zDkq9nRd)i>Sm%RPBm}wJT^oi}LoZ*n|BnhI)1Z0w&QYaw6`}MDXY&j{OR($XK{PsU( zp%c9()VIQGXH0o*^2aAqN<-#ug@#C#;RSKE9Y-&@EeFG&=`UIAbFNk%I%DOtO7?=N zBRonrS)nS8aF`#$bS&L90zfiicA*d5W7P?B z6ug!KUq~0`ht802JX)&+3rhw)WvxD0_<}{1Dbi@k;>Wl;tP;Crh6N-?>r^ZIpYOHKEU&l#H*9GfZTxGBJL zJ60CJs2yuy9ouT13KsII4pvmjWgmRC)R=PSe3|-Z$GiTN<7ep2uF_MwuC}rDny|68 zUhg;&8J0dhI-kzrD{#;*IOrrtha*7i?XHXwuiGf2?XpwCh{jLa)Dm|kRcO|Aydy0x zX1|Xp%$>t(Nv=7Kr6>!ecMO7~w&KW|9UIV-%gOvV^0X6AI5?ENVA%F@LY<;fiJd{N z@D!0xdNDLpr#)bXuMX9WQJmU~PRP0LbUt)U;&;n+tHX zNC#ypYRsZQr&%*?#*6Kb>w*`nPF)a%fTHpRZ%=a%3t98_rgFOD^}R(`>-Y z8wwC5;$MIqY)@{T=2W~dl>!L+U3Vl$S{E9fu~t8WIbA-c~q zb6pskkR8M)gp=p;^dL_`p9WDhUQV~z1H%Ompz)X;*uStwc>s;agu>|fjrr1+{4(mg z3Zk2nJyE3r%!{ij)cJ-~wh(N?yttM^`8G7Yx-8tEhI2%)ptzjz_yb!BEd3hw@1a!l zJDsrA0uzn2ze)cW>D3>F8lF}>@K%1K^YSmVX)g-pCVvhp{v=JF zh-`#433vZ@Z`NsHP?K_z8F)@{DdW7@=z!uKaSVTSuL(uBz~D zPhk8KXIIr;a<^A6Nj*~ie3VAnHtFw6kbdZG4LslTcd#RhJY#k0;T1u9S^w45R`pBO z$ML#VE~exZ3Nx$Eg&8z8MVS2;$9Ii@Yr@QXYhxk# zQ%yVTK}E#PEgz8aC43@brX}Xm=Ov>`n8{axat+OKbh!rdHzwQaa_ti}xkiVmb40GiR*`G*vM$$H7_c!Ps74Oy z2{LSOgRb`-f*p+s`6!iD5og@h?`4eFXK%PLhWTW6Ht=wK-g=fAelPOoggtc!V) zM)9|Q_65Vv2D4Q$dZ6Q`_lPE^-%yJ3E=yEQ+ZpO^wyk1{gY{P^z+tXh)YiU2zN*zfEjT*Kh zwNS!>C0zoC)ENR_ch~YjX;C%wo#IWplPHe`Z?ggmCHfohumX!XdI9kgp~Sjp3JX~{ zn7?G$Gf32!Of&wd&JqC3ijbhSDuW4Q+j`Hz%6B1tIyz=jJhk8rskYcNJ%I&Rg(szU z@^9eS)!_-3(Sqsd)G~2%U(aB^gRoDmP>-naG#(wUVNk_Du!iCzRk0R$?ZT_M*eF3& z!F^WMZ}B4b1lNnFhgP=Q9pfwOLJu_X9*)s4TDo;g*Z%+Py$`fqRekTf*4lfYv(Mh= zBr6ag8d}%c#`dI=5?dN_m3wd28P?*k9i|<;KE}Jgdl~n2jO&QL`>>Dkp5tB6qeKjf zZB*2tRDxoO^2e0g3K}&C+9=pYMU9rLK@mfX8Wn3$)c5)ReslfXd!PK{udOh0_F8kT zHRo^s=I`J9&ENb@E-|b?+X*F5+=H@Z^?T5j7WV?<#b>tW_);(cXNrMQ^hib4qa}?Z z`mfyI;Vo5hw(|L86KkSh$Ls8r0%q!jBiUlcSjQI#Ci2fh5Hlq$N%)n-12uvD;B$6r zfu2BNa88#LH8{ycX8GY?QD?C|c_P0>cXgt?)e34v`6(+n98qS|gl~C|)(0EUnW889 z!{?+P&}T-|oH|R9Tp)(R6CCSYo#goDiepiRsh;sCiL>!ORl*UyY-;m-^hc;{Yc~C+ zQa~c@k_}l$tbvR{>ZCWA=iKt8I6=_tYfej@y;Lq7y$trQlz?vE?zco%jAD-+m zkKR0$iWoWRh4ep0Tic5V+;?f1&n~m|g?L1u@-_44i-4(n&J7pIa?ZLJ4VW|iF%y%v z{jnTMvy;5ZK><{#^Jj;9UF&NRk{4|C|$r1d(xpo0W!h z$)bsn+TRK!i>TZg&Pv7&3k}<_(CQYMPRp~t4UC3SGT8?P18G7qRN(&BW-0ZQ#N?$N3NL81@gn3t!V{W9k8Dv(R3G9 z5fe&Ykq-^as&OO$p1L@Tu|hgJ0iZoQ#abgyB+Wg#62ge5o=n6Pl_g7&6AW-pp_-+z zx@)2pE=g@y<4lGu>}E64UB>^D%!FvQtDkN*MTqfW%2oxF{I{R4iH*S7rcmNMv9u!j z-LC>zow(V`Pg<9(;%C?E@Pn*NG9;8HR#?#b=;0grXx3)7hwKvPz+7^4z-ms=P!_6)kHa>GxnuN9*#9+ga@YaU3G^Jbl_pG3_T3Y!-R!~|kwsuYTL<}MN z)!2G^qr8OXXf(`2C|*ek0^HSw`+|Xu;$9tLqn&HO%xb+y)}P#;f|qaI;%fmq=9-ss zS-6kQe{-%n=$=&}z^o)&Ko2{zth3Y7)l;s(y~9i*&1mx8ngz-$p{wOHv~;7N3@Htq z#}7i{T*jlH^@56aY`BV!=}G-X2i^6zIw>ZK(w}UH4$QS8BZkcc;*xsOGavD}pTgTN>m}<%3%j9cq)8$hKAlFJc{XQ5k}Szi;f6?3VAg zl1pnPOfhg8RRwa_JcQR_EybMHCD8(H<~RGLIP=Pm?az=`ZM$D;tHw2c*@Gehb+heG z8TEyTVtHdCZ@p~LR^}Ip!S<3?6ua9PK*~v()hTf*I>se)NQxDdNQ^C!=C-cYCun%m z^?i^p_6A+0peEX=pmbJ;eG(3iCA`9%Skg-31RL7DwMdI6 z5A`yUnG7>9?&+1eNEl--ZI>>=1?!8X%u5gHvco4E|MDhEZ~7JA z1_+#xY)C7N`dW+ip4SQrSv0z>Kv8ZEkOprxNnvD2kBK%)-b#I$qpwX%ECooZ)ODBO z<_X6B@Dq(DyLH?j+CMmrzf```b|o_RGO1_>e<`#hvz-Y9R)A55E#^}*Q`-*zl(-<_ zUrQ~vO#l{t3Qp_8UTDv;#Dm{}C7$4=Xcvx5>Mb0ZI%sf*d%}9+sqOJB)va!ABLXNv zgxO-wI2|o8c!8V?5SQQq4*if(slOSf?rjdC2bhn`=?8Y>S^Tu~v#=YtvotG}&hfb_ zT22us=!RbK3;gM4WlVC7?SrJ|EK+`TP9TDX*+g3w!0ZykjC$(krdAXnH9rMXC@oCErSBWsdoI;mifJ~gW>zXirqu|_QOFSU`*OyWpBHN|Z3K09-mH{17sWuL zKYlrg$2y26qi4w>=O}ieBW5>pM9?`?n5uS;zz3^R5h5I6YQs5#p;#dW?i>+_NVH>R zTDWTCbT13U6verL_QnWPKykEd!h}Y*#eg)Gb;Gp9APAmCiOA-w4q!2HQ6NuAR4x(% z_?C&rJ3~U7!msW0&E^K{K*Gc?W1Z`-;EC=+>j@lR*TMVM7ne~hoXYk%NE9Q6Kc_SyA;^nFT zZ^vEf_^8Q=$j^`J&+mKaj;nYPFZleZew>v-g@cZIda64_cyWjZg z>*7~jIKOcJr@lxus=}YM_;-@_{Pu0zf0Ddne&OA>{T&H=ETO5DZ+ZV`-bVTEn?Ca# z6*E3XRX6`x>lO2RANuw#)k6ohslV&}jQT%5rIX-<>zXs}>G*kYQb}vZL2D|RS^ECM zpsIIq_*z|_8`vB(Hg%b(6%&d9aMOy*iC*%Z(Hck1E?cOcdFvd(NDkK{yV8FV<^hqdXzKsu(z`h%)wy*fivYuOqv&Q#W8 zB}%xcous~0s>hvhc6c59%~qt{-MzV&y=kF^j?|EU++j zL3qM;>Da6aSK@L0$!l);N_$=ODyy1wzWhpHyzI>AHKCRC@0EAS2X7k*9HI`JF&w`3 zpQ6+Wz#Ti7y~bend<4m2tbVnFLqNbjh5ybZN%}=#qs|}+Kn-8N#&xQ?y@-Z5= z`f#DQG=d_Ikzt#}VyX?>WVONLfyO=-mJ|y=ai+-EZA!eFeqLe=uSx<@FLkkcR4?*{ zxEz@kGg@;m)o+iI;faQ%Y4Ild!QLclZp@qX0$HFx8#hU=V5Li63%gulU=SNI=}or5tB`khm@)2`_5Wf z`n5uvZX6KP`@9)c*J@N(OS&Ao#$IW~QxQVbR35qkb+=S>%!@fgW^|0N!bYd8xD@iw zQA^U#O&O1m>9@lJ6Y*yj)3j2;|Do7pb+q=(=zrlw7-pltKO!euY>n{Fbfv*ck){PpRok94B zC|GbrKw{pf`?YJAZj=)h0;|X3=q=Bhl*g=v$E@i!Bg(Ml_W!VvU)*Q$nkbUI2-6#s zuS{&I6LFo*Ii5E0WX}U(I~a$}(Q)Y&tz+wxZ=xn+fXe z^SErQGMrGNUg%sVIP)f5Y1v^L4c0a^Q?do!V&$G&CCABOA`kbu$0W*`dkCGZ*`9n& zt39mG3xUfb?;C|Ot`+596ympyF2z%Gh&i*>J)z}+2+P4%enyw%03s%Efm*Hu-j=2u z^ac#NM_wnFwDND`MssVJm4VaabDt9vo@t8&=bah7TbJE+(N+2-fA>4=QT~<4QT=vq z^W8{)>ji&>7rZ*`#o4R)ESQe|Z$J|$svAoqfb%v(7Gk{gI)gq9m~FYJ_cvE$o%JKO z&AHUbG82_8+Gi%ceZ!8W(P#Z9+6FD}$AM1m?+8x!Zv;<$7BVWT`C3LriVYZtN(f_e zV>ltojn!75Q0=viYBVss%TgQF=Av)Z_f{fCi*KL^difq$CV~!oLX{)h_nKl4yyB zz|vvZ$BCr-Ei zyPthlvoe6RCQnxt|9G~w1b>pB)hTteWy5iHV+_$we!XAi;?N**_=aonn10TD?_9eZ zU81q1Uqq(XY~dsYM5H6pGl7t9i9>(6QS`cRVcwQm%m3nuCsYLn|nq?k#h= z3md{f&FP+M3#H3e(*ss#k?KKW*eDpUM^vVI2*NqI{|4+e)OZTG!7>S5Z$z-0d(^ub z0$Q{_xYRz#)uUxDVAY*)n2&cO!oG)RrxHPlqM4Hd$qV@Vm)p-z4? z#KR818gSr`(Fxvp(>6kRxjf+Irf^hljvt3y2r#jyau8M%d)u@+sY+Kv-2=`H{bTAs zU<1s`GoDcX{2@M2X16>%N4HE-SK29$?D**8JN5G?)XyABJj!?})CF{AJ(>jmg$#fAGJ3R9&u#OticB7#UP z#mcVeN3_=DrEoNnD31zJ+j>pJH=^=IhPLjl!7ZuL1Y=n;LX_z3L~brP{W8*CDb+zd zZL=gyFFrGS3}voMNgYI2PCJjxATu#oYLfG)ZP+4HIDDl^P^Z@BGbU>Q=+YPSMcFraaMhChMhr5|MmN`0MX#@~rtt+lJ=^b|&^n}KLiGy33K7f7bS z1~a}vCc|87#WL4Sah)(s+frN>=58DiWy>|kI&s`vaW*4Ak{LoA-Kgu4+T>7j1#sdR zI*?*8(SZ8MXG(c118{TvoOp}rAS0zW>k^gt=lVTiUG#c;6vi0bJUerkx-OO^enq>Hytx&6ToE3WRcq8;b)$)75$cx&bd|sKL{!u<` zfo_o82o|UdR4*_S^dI0VpG*WB)WpOuXKhciS(|2JkSB!4Us#O45@q6wXxz-rCz1bF zXKm2%q8#(+&)V1mgXbfjoeXm_gu)|MrkUwAOg(A5^H5=n&&os>Lu!o@^o5sKnPWAx zfAl>YWm`~X*umxS*z`qdwyPanOr!dmUh!{QQ!4%~;onmJDcGuwOvW7AmK4*HeYUG> zwnrP7Q?gd1A~C0QX_Fqmv`LR&YNmsmL@#Lmv%@dVe%nscP>Eo(ilnNO5mn6>j=1ri zIicPe8ID-S{8L1M#THE2#<4;Fq5&4OS*!{@SXtPZ18h^h%b8MgqbpKS?kUaV@AXSe z6!m|$0p^IM01l~zjcFhd2)O8(BJYDY6!@QJT>K%%M*M=8{i!crlZq~W8Jb;R@)7^P z5(9eah4f*`g+xYl&KV>(T!_`3NTh^wuh?6Mt4 zVYtguv>9~Gld7^sJwTc$Q$-LqSdydCrt+nZkv5_|qd!Aaae$$f;QMLEGN5fQ=2(BH zf}9)^(PD35ysX-ULne_KgLQ+48)LRubIZBJUwV1-ArzNE-<>C{(GHn@AJR(VG#ppoVnhOYOP|`z;Yt`T=J3^Oc znUj?1sqNKcPEVcmB{C9oXkmt)yDrhpsFnX?@Yt@TnbLm=DhYZ8FDxcjX+-Cul{KSN z1~o5?uj%RL-56hyFuAwf40>6= z6%&p$S?qflNqX=!0%a_g*ODHDYzI!2p79`yk@v%y4%olNfMcL+IP3|61ZUYz=vuuJ+i!V?$wuRgKMj4KY zvLP|D^_g-lC_4b9-^=P?B18GsL`j!wud}a$U7Cj7Fx4q43ON;oclUgF6M{t<6;$rd z5ijR!%cr37{pKktL0aqC6!awM9cx4P?yy$|3*Aw-23Vv)Pk7hmh22r72VzYqV)9(b zkR2Iww(lMSQmz7hCr-`K*kO1179`91uwlcI!W_i{gS2(Za;)FRmi=Ao{ z=58vs{^OV!v&|pCj00$aZT@U#HMi#QHhE9Lx&aL++cCb-!=R&Dr4 z8rQex-+N+58S|qCelu%h>;RgZmx> z_{`Q$nIYR-Qu|iNHZFI*b;qyy9qHfa7q))-bDuPCeyo(dzS);ZGCkV8)+RO)vT{ydpW`LkAn&I~~ zFB*y%+JU4^@>?FbZDD+PF0#%cLC1P(KC0e892q~)HGlK^TAS+!%I@VKU|jLeStD&G z`G>xx)|QSukv%-znCdu#^*w&pGNT~(B{zhW@wdg~h2RD3ndAj4LtIm&lgZE5B(QbE z{K36f&yeHy;MeyMJv}K2AUAS_p*caT5C#zK(2k2>21EIq4dRoAA@(sTLEd}~sJCRH zmg-D&CSuC;Sv~43>nI_rHyfp&3+wZY>$b#`u8|BDvE7ri$7zAEN4@1;5VWBH;XCFt zt6U@$Dwm9QsRz{)T*;(YFyHs^IAR)=XXKPFQrDU(wSJCP!_`CMGT~g@~8ttxdCO)}2jo&nkdZG-~-(mC=$o zy<&HvL7PoeUs;m1O-nANdA7jM`DVbByL-z!3r5^t@K&ZwapE|Q1r#(c7;#DdWuuyL zLGLz?GulYM?qPb;DP{?29F&`4nQE0r@}A=Ic7f}Q=q@`&Tt&GVot0=r4r^IPLtHL6 z3RNm7EiSK`C}Az8=t;TO$e_AZ)5<60Q;_Sjc{ZS|%#=c>y)u30YZ&4|n~`MtXoo!# z#-sH0RLAZ`re)TGF9#d(mal>F@vn(i=aPHlfvvi5hF``4j5>2d7IEg^iDt-)E-ptp zzD}tJbBkJQMBbn9yE9XK&{`LDvlHqkM@4`-e;ILTyW=yH2Z+UBB_%nam<)*fkp0>; zZl+8rHUmdy(7VZmsvEUy=E``m2&PX5eb3biP6Ic%+b&q_f#T7QO0(vO;VF6 zN;{2xgY2RX+f_Ox>EeP%aMYWj3rru78RsuT(ynk$3NIygN-K*e%}16}`Aq%(wTm z{U`B$Anpp~SlAjM0ZBSH2!~2)&W5rbx6vmN_8`6dwu92`qj98(Ce$>c*Rr%Yk|tRb z?TH7i+>%yDg)&m^u<)h^yrDW1Yy{0&t-eaMSuvh4FD?a~6~n(?jG!wFuta9s4v2Rx z&j>SjtBI~hp^dvXnXo29 z=({%gR4}cOwgF;;iCBJ;zNoT>CD&Qhs?wIC0+wLHQ9}wB^RpZktGz2#V_juBXOyim z(ngYqd89FWsL@``lEdAMaBE|r<+2Qhae?(Vf{UL=vbiISJ0;XDF27q{eyh3^K9?5n z=+*y~ue1ZwQC-Sv4BN8M#iG@JYgveD^hMGn|5RCsCM^m-YlVlH?-wQe;-cOBUKA!r zbZT=0Vuzbo!q=Fea)O|so^N@b6N!HYSp*jm9RFU?7N(8pkK7OX^q@5YS(n;3v8BL3 z(_zYxlSJ#!+TLCy6a^w1b>Zv^Jxmg?r*zHHm!Q&adP(G4ejTiM$!9%V~uR z@wT3kY-WU5lMO1r(xkAxW+PY^p#H{U$@ysU19a1Ng7{DcsGS9zpfG_#DY7DPLYT~w z{J02fZX9+~mX4Q!}dza1gw5`_DeNVEhDQu1@~MtS_e4 zY*l2L;`ZpJgEm}tWh|gF%VCTN@&V5{AxlAvHt2%S1|8-^^UHb*jbdT3^*gdWO%yTf zbEzSKnBsT!%r@-!GZU$LhDhx}jD8%G3DuipoyP>ZNPzG>H0ZlT#44hEZF7eyNT4R} z>4h`^M7P)re19`^C{^y&@R!EY2RA#wl#}!TkZiGUF43u?6E8HO6<}fw5wQwl=oY>Y zTWu}6N_UhHVR^F@d$~vHsbwj1^#qp>fCw?nU|4I!S;F>7!}um@Pv5H?{Z9ot;R~fC zR5(uu1Qt1(ORNUDH7cj31&|9i~Z0fZ6Ymte;$zj)2fVg^Io{`wM#L zT6%!td3oNtVkcdx^oX1dy zM106%kIM@T71B(g9C#4q^_^S>f(A;w2;|06&u^!^>z9ZoBSWVtcf>j&dRqH2N;+WQ z2X0hJw-#5J6}uIF7SNN@Gk%s!SC1-baA{PssFD`ohgH&ypS&n7Q_|;ob$Q0GIBcAf z{_{%vy|%g>uew!7LrMQPDt6VYM>Qqws#k?ICGDzLg*7GpWk$!Lt10PwtZ)moRw(HM z6>JZJgHlPOX)7g7zKyJ|q&3#ars%vgqgy0>4yjtALY<*q`R;bW3oe)Tb=Iy~oUC1h z!gAt`%*EWd9Wf?;%lQ<8yPaim4KgWXG|KK{F+DA-!3NkwY0%S1I=!uDnu8fDH|JB7 zUtj3y9sa_oo_0;{LtKAKi{b!F3u*Rgoda6WiNzw2RS59TDpzx9ydR~!Iaui2+J>dO z8{2>BY5LKjSyAJSQujCX`S{Xaltt+~G>_{)G?ggV`qQZzUA&z{Yn@egjRi!%Nt)&v znl$H!B3eRm>trInlb-YRq{r^yhiPGlynPspI`6R z^$x#Q+W758IG(T+lATLDVX2|Y6P7Bs6a9yw=WQXVqx^9B`@hVj){}BBkek$i-%9!R zs{EiQ>+Iwt%_=@UsEQnF<7RJbmA5YWtrzW1avlWPP$h1>MIRW+|m9^eJ- zX+3}v52;JzoYbZ9O3F1(Nl0B9*HV|tKfkxFxPaPN?k&f%lkWpAXoQoJ>;f~vpwf4{ z8K`|~v>aisd0$a9>3$tfE~*jTkTj~zl1ZYx_YD7zc7Dq9W|Da=6Y^|Fn=I9MdF*n~ zwbPW0`~n($20XB&G3u{I)nw6tEiH2tXb_6!s!skr(VKE>Mxuy^jQV(5%Hoc4{_%ve zQWSS`<^Hm=QWDb;WtO#uefeD4;#eo&!KG!|?BqMSbg=S_vxJ2UU@5G6EvCSd_)S^lAVL zF;Oae(=L0XzN$m8vvsHqFs#mbb;_n>ZI<^mr(Tu!(goqhum;6a8(k91o8YUv6EnI8 z?f}Z+;cgJUByTy2qr4qZTmZ#7tN|ql+d8^$O+e>rLb5kPOJ+3>UJ|#8akTOC4-or! zM$$T78%aBctu~T&Mq6zp6+2|zwvo)DHPI^Trf4N=Yd5I;S@BT!DxABs zqK-is-@>6`4B9A(6Os)0YL)o1saQplndO!VLt%L8bI6+#jdu$N=i2(}b+#$L;vp0Q zw(a{4=y!Q~&-+E{WJXxUIyqyI`9h*(bG~APN^NdU|133I{uioiU6N`Zv@T(di;ESE z)@i!ZaVt2{mGRr|GVUNMTSxlAUs|Iw@NJQFImQ5OuOQUe@_#otgDu4|D`nB@)&aFA zt*NzW)hqb!efJjxM6LS#6ZfcZo%D6@ux21qYdha%qgzJGAPuzOLD!t&rrVQDtq56|9dN3 znts7wp2IZMq7z7hQ}xpoD(WPoSt&y+0;)lue%t62DT$1fnL3wQEMa1Zz+fZ)VNnk` zRv@SX~hPR5uTbV)AAA-PiD2EK%IEw8^7coktnVgT|wsQ663HJj%4#t*7C? z$IY>)I>J{lXvW)y{**$|R$8*FcGWRvGVe8XM_||eKd!Uua_XwsH66p~2p0=%z#_a6 z?s5_b9U#AAB7h3yJ|%J&AF-$=KI(~NmS@}rMwN&rlW2~|10Ku2^_{>_Ju#G4*KCA) zHGYDbtkxzIk&0+UB3Np(DG8K)e zbY!qAi8U&(7D08#!QOjA9qeO5wMp7xRQDa#cODt$<3Kg3Y=!D=j|kO735=o|dJ%=( zc4V-R1J#ob_QB()Y62ieVV-uFKX_!Aj|0^@hXhpb4^qQ9@mQ&v;QLXq1BG0FWU!9| z)l&}k!tqlzDX|xY`RXIWEJ2R6GO>k3GTFpJO1=txTqy*%PMQj#RK`6N*mMedaR27$Ap>Y)6G=K8zwkQ&2Qd} zf#j;&aPP5TXohKvD52XySME~6KQNZ3Bl-tj$&e86xGqsv>sK8#-6r$#vlPjG-1*(0 z?&5j;S__#O%!O4IEaLR7^5Bh8Z$TA5)2sTF*N)LxsLh&zR#f%lYh?DBry^)*#Jde= zu&ugID{X!Vppyk!Gp35g&FzA^u#@O_Wl7bB?t}e!hUwp8|L5D25q!xZJO+(K;l&xw zrZb6?O6GU|CF$H5WN@+kdrsiXag>C;j-26dr zKH~DM@zpSsvy-F7SA%&XLH?m1hJH;sDUZPv(Ng4tbxidRJ8EQ?WpOos%fEy=`!cUi zrR1-F6cE$TKWB*P=lA$aDNiY317wAmetsuK;|6W|cggR=o=*|b^!$N4e{g`yar8r; zglS^up04I+^8a}#G(VGn(VCyhU+YDj`smHiRL#%izeDRh_?$y6Mnr}z>_${5M2!qV zI=(cXCpc?ifhiH2dg2U~%kG9ae+rp=^t<4*^#xtu$$PYW2;o2fj!W;j@49#0^KQJE z2X$Z6e1Mw_1$eIti<<9NA@kLJ{N|^uOYYL|haIfFx(+q(;ksV)Zrul)nT>VLN{b zFzyFN2~{nIFfHBAvQ;@3O__j%s5fLR=EWdBFB`OcBW$A7 z7zs*iE;6?pc-DP+riv||&f@CEflo3&t({61aI;+REiJxdpMmZ@*vX#bez3To$d*Wz zF)Uz!lfT+|_I$aH9Z!)?LX~kL}ixZ?>h?N!&LR{3-8o>`pM@E$-Q#=5J1_ zVwr!f{9_90C~Ce{(K4#YolBP6zNnibb86M9r-&Bhqbgfy+f}9z2Cx64_4+^V^@H)8 z*p%)Id52wE1t_~-S&oo}?XW;`dNe;9XFz25042Pa*im61De;LFS z)Mn`UECo|OP@m$`7Tz3xJu9t^>ah-Fg9?s&R26zUjbrAq8b7Qd_>4Ubk13yd{fFl> zZP#Qe++Y1rHLjlw3_15C;WPN&7xo)`CIP9`Ux7T?a%&?-2tJ5?3?!qA+{aEbdi{qV zG1i1NV*ctc+=xj)PTMicrp?KB5yno(BD;oH$^pO9s<&UEg2PoQj4XaG3N!uwKQ1GD zzp41O4i^-D+iGuf)#pUejZqJc?rK{dwPeI(S6$eFJ%n%V} z+Dz=)ScQ1&(c`U*!ddN2pPgXaz=#vtk|M_}6-kg!reD+Ud?ezku)hE$itNGwq|8hV z&n;ihrJ1DLPDFcwi67ye?kmxJkcoZlroO2#gr8X!F?BJSFS=x(QcuyLqN<`Vb`LxO zNK@{DDs)T6snRL>j;qJ64Kskv6fOUkW8F>pf(1f4epy*F{9iL+kGTh33Zmbj0w7u8<+R^T;lv$)jbZEIRAIy z-hyDYI}~UiLBAgv3})ln0gg``3`~J!P7iZ37ReANFUH0&v>bULloVdVjm zL7c*9x^U3fkdtjCv#+70ZXrPEBSuro+$)e=4!#VRW#vG61#N z2pN3U+gqitI$u58nkSr;e|C~`A&DQKU!UrpUdsCZ^vsf_>9P|}Tz=BYr>uC&Q&*n) zE5G`*Y<3VuPha(n=+}OI-Rj?X=4orbH?GMLmhO5Az2Ne9f~ z&to$!b3^k`&-Sv(YiC&!8xsk46XXE&K}j| zlCwwoUA5_1Q8b@jvY9OgxEhpjonJe%Cr>Z(3D1<Htbhl=EH8=CK&#GHvGQ! zVB01r+h3J&N7^YdWJ@Hr$B88^x~45(JG^XJQP!a>5Y-8k)rjiElBjmuH;fD0vHViI z0Y6Y=n@yA}Q^R!L#SE5|_n&9y3Au>G^u=j&Cd zjgH|>?ns4TcPw?|g3|HscDqA2yY0r9cfE>@-^mfCOAkX5i7e+$KS<#uuIB9NGOjYa zBJ0i=es{p>GEa9@@K_&#h|=vtr8G>{Gp^j(qztLMgg%+B z5>V|wrHC-Hw>yJ!bE=r$vT`}tw)I_XzZ&M9C9ak3uX(I0M;^c{6_oWpASGI}OC*BL zW|)4a-b)3okI*x?H53HxBf^}ijapx*OpQQ!nI9~^INF(3VGrZ$RtNPfsf z38QFb`KI*G3}1B>l9{la;qfXdNo`Yaip|xem_*N+ZijblnYqdHF8iA-pQ%A;+y({e z=C0t^E-EOygqRit{L5~T7J{~oH3uaD5!Jx{CLI`_xy~EI&}mQ!itrcG>fDTEKRJW+ z`uP-M>^B+``XfP&?QrEYJx2Moo64tX=_oYLA_5j`XKB`!rV&ukLR$d{{7z5*dIPvG z|GBG=Cm6VX0PfeGjKC2rX_yoJi&mi(4BNeS3TJ6k$jmVVu4YqcsB1PwHLQz_8n)0< z8LB>N`3$7=t9?Y+VXV-};EOS%`)Y&jSBj}_l3!s3CshS+w1V<*8L>&npI(|EvbvrR z>Jiq1bt*GBv23|fek|}wg)tl)R5H*U3pe_s|f`Xr;cFqmA5 zGj#8iRFZWs%k|j7#0tZ}tT*G<$sjb*-v_>~R>_~V*risS@_=%Z5nZ z@EM^WA$J3d>cl$I9X8$4quh*!o%T+Sv%#SVM9>IpF&h;9HJZ z@c#>@Y>JeMcijiwZx8k}yhYJS>%a%9f{RSMZ)K5e?u+@vE=aJk9wMNG67C z)VICKEnIQk(JeZWjAS~k#veue4tMnhUlzWzH5JCe?+QHlH2~HA^)Uo^dhzbjaj{2AS*&X0FXB z?>4x6^ldtMZ>=B`MjogYm>K(^Sx#EBmg5va4bwuecd~K-kjkaBY*y*D=FBP>jJ4UN z49049IUe`NWvvabWKAn!d*M{hpHX8=SgMpFTsadrmRx_m_V!HQ#hd;X6%Lk2$W2D= zIBBJH2G{eD@M~PkwM5VMlhHOJ-pI!btVyugn&`v^X}Rx8`H9u;fc& z)lSpWJdDj!;8Kl-4+BrlLbRu?(We?Xk!Gf(%3?7YLC)jZvdvN@?(2Ztn9;^~^u_7< zGeOamzE$8wams4XNfU6*R3G%K6(q`>mb9E-P$0^-{u$tLwPJgplPooFs+C-jGm#o#rXXC$E^t*{+c}r@I&vMgP>EGxjDjw3=34XK}`fB{4r12TcllG%+c- zBVw7b0PGmLSox!ti&*W9rjz^%Wnvi~mG8jQJ}Q(iBY~IRV~|%Un%|D4BFopwH*EGw z(J-BCX>o@Fnn0+{|NQ5zi^B_O$Lp zk!)m~ApGlqGBM?25=spxeLL<1Qm27F;_T<>?GaPHwY6zP2QTomg7DJO=`_)$?BiBW zmwi70a?1oY&(A8VC+dAn%D4S`FP}+&9FmfORm(#0Z7WaHuU;u~w1JA@=lrKuK9znt zlo#(`^04aZrQ6CRX1u)B3a8WSJwuxErVu!1TVE6`*GOWls(asEl*sgIJ{zCJbFSAcv9bCD^V@= z#$tKQ#^yEo;7Q3;wS#-_;ybvNTvXy!yJy(4N(UHrN7+&A;0|Kl_HkE%%{})2wY8m+ zgPf?AU4Nn4PClzW5iGcCWo4~p#S8mX-Rz?X7H#Z{rU?EmHmkzz9Dr(Jj%&4D+*|n1 zwSCb8wO}?7P~l06Bg`naI4?C={&$|LgPr{8wmXA&1_QDgzHmlI;H2Mq3*&g%LZYzaS=@-E%!z}veA;CJvC#_UF7Fl4Eb(IDkRGJ#TaanSP%}LqHIEWn zy!H{aX#f1|z;<)%lv4IA`iuWtiIrb-tjtA&*|>p%;SP>qU<5}E6og&awu=`t(NNHP zOi|#q9}WdQM}fcixS_x{$XeVUS5u=jt{o|`4bvb2_L0p;0n#>8|Af0UXN@8Xt7Bixj&A1 zA0-O)+7CB8%49>n0e|sDWp9-A%6c=f`5ZbpPJi%LX${QKF0b=5EgQF99(j3th^R+s zc7&>j$sU^^@HOO(&=(p9L`ZwS0YaYxp=&Qdm?=21qtqOmWm14DHG~O5V!TI1A!=(> z7!E|ZnEfH!Ln#ic%m60TmBo-I*&1DlJfgYffsyK_OW>%oi24h5 zGSkI#u8?FXeU)UE9m3kmr=Eu$U9&!7SG{R{Lj|UYgpG+T1H9xZ6I#~2vdF|1MdmUp z**Cylz6Ebvk@>OxE!f|R%&Xu3J(TE7%MI)H>EeI0Hm;Q= zy$}XA*_Gw0o${d#w_#QJdCkggYcFQ3Tq$df)*cBhR1M1T^uBnapU|7hsyErBAWkZ) zR%MHa#xUZC_{J<-yOi#ta{@#+zurN88_A@ z1~rA)Fnon|Nl}5CiA(;nTpjWlRrd4gkv4!rE11>3d2ZO4t|~Tzhr@dw zFUIhu79VVz2%38*2t4G63~u455GmH>Qm)Y3%If~%h}F%k9yL~$KQ>l(*rIqOt9uCT z+NeKXj2H6APTNCa2D4gn-7-pys&w{fj#uiX2#m`lU8bQh#YIL9B_j8h$VeF@WPIbP z3f4HTDi!n~D%7zYM}n!a#zU4atnrYf3sGF<=n4)C1eYD@XCEQ8%6;3iAF6Gab!+^| zgfF!4lM-KbEB(oYFHH9*CBDX6@5h2Uvti-38edX`A>ZIiipCq-WaTV*(xfjloFj;V zW@9D zc@^b(OW5mSyo-@y%4x{J7_;23Dj&pF=C-~0SdI_7mgMA@*wr8|irvY67;TNUAs^Bv z7w|BDs#N@0P_EC9G8Ow&cUqpF;~OXQz&6Lp!slk&)ablE3{F8l6-4gGwH}NTBU{f4 z;1;FG5xQ2cs8E%TbTj@SJw$`9L)y7^nRc!KtWMXyR$bAx%|=*YFF-n4*;wG-=J8E@ zm56$Lh2pVG4Ml(0Zt+zLrYTt8sA+iEPLBtV0M`gJ(WcM*Y#*`$S2 zI_@;JGPdy@@0eIBp(oFn{k`mN8I?Ha`g}v7E02m1t`Wn!f~<=(b!W zfnFrnJnD3O9Jm>#LTF#LSKgz28z*lvHfk?CH%<kFz_3Jl0ljW9n zani#=|0RQ#e}1^R+2NnLwQXU?Y}X>wAuBv_i0mZvhF+QRr`L2qVJqL$lAHZNd0@36 z!iv*>c#jszl3Awh96~zt6lU*SEFX}#cS{WBi3QS8<}F1u?BSW}O22WnKKgn5vRPiy z|9PZj(o4E=WdFqqcgp_;eoNV2u(&>>wx-#p)XMjBa{OCu7X)e!7w}widy;jY z&$&0mYE0?=E>1wySqRqh1^fWf`Jpc@?Jr1Q`!1@>T5F;Mt(^4Es#YEKhaVS+dibzC z)X75(c1uCK>CM~inW7l1=`NOyKed|$e@?LU;82%6MA)XOiWeJM#hi}VRP6LSSBvl59M&AgX2oQ(vKO zqF1-YJ|tj+Z+`z_LBhj(%H!twp04X zYc(=4C7bNY&X?2pOhf<=Z|`j>jtzgjKCnZvRKtkT!-DK&`b`a;NMSO)PnUsMohCJI z# z>9ioLjq%8d>QxCu-Ae!FdO^j0O(&K(aOesXri+OV0z@62hUmy5BgrLq2PmFbw|Zs84yPIvpCB!OQN#}TFz;2 zw%gSV*I@e0_@nCRHY!2uSwyto!JcrFAks4gQQz(qT+NoISZmTXk!Yyf!wgve^Q0+o zUkRel?Lz4amXgkS)_r#gomvZ->(s+X_IdfgpTweyM#XM25@+j$a4|l zg(qCqZAK885;jk0h&vX5k4QqHC2i15LUl|+by}kms*_7Xb&g#^wJQnLe#8>$l$wM( z1ymkELT&rfu!P#KlA45K=dh_1!qMG^VE1QX=9uqUVTU$kLuSrgF_I>$oSo*9ImhK` zoFQFW7mV8Z_B_rcRY-0`bYzBEVN4`3>~_U%ZdVkdYd=vS8ubHldb^&u=(-oZpvm~K z=ps`MZ@W#RMwaTtPn|o=eU*v;}_0f(!gU=bNZt<$}RYdTQ*zgAnpOi9Gc%s8VRGRHef2 z5eW7AFANjvy(*~)Rb;vkVPnz1W}SE}E35Wyub@5*=d;g_3Wc2RQU+RWd^T|j4voa! z$df?TF`BpAW>_|3wN@v);@O_b_#A)v&2C-Z9K!&14E&TQwk9^F=U3X#p~kh3&6j5) zHjqFd5hg+_A{~T86Eg)YxG_v*JmE-tvv$NAjfxJxB{ODTyQ~2rB3querKlOUiO7*Z zAJ4MLT(srNu!Lb66Jvy5$2PT=tfQNa`sb3hvbS`UsD{*p?HL-tgFCT>mc2&%e~f`p z3s>ByahV?Tl+pJJm_J@6jp(h;C3oW!me<<3Y`d~2IF{9z!J1!QrGA9O>U!`%6B$Q^ z0uyQir#3Sii-Pr=(i;jCtS?ZY4-Expjp-ybn7`@)p#WV!f}pBHS^BzbYAD!`FheTw z#qB@)+=A~A3#3MKd8Q{@-Y;ZBvWD!{oQcV)=odTykGbSkw}|F(nfR% zNI&Pl_~MPM3y;WRr`n?$D6ElUc8!O_Ep=b=Tukj~x4ZL9sdv0L=Ze7Qk{3zyC?qqz z{|$zJ6`mtGGM8*znQ12Jn(0cgCidMHi!zKlV%JY8GO*H5q6QO#J}J(ZNkW>D3{^|h zoIrsBI!zB?7?~)+W+ev3zq{kz!k}Nj!ICZ_M-h%RUP`JhK4`A{By`ilKqO+1Zv{m! zn@VrcXjIHolW6;)Fr6M{N_Cv1H24Z>N!#P4rHLKfpoM|S1yoR<``*m0S(++u&VBD; z?t6>y%CgMOvG$>QH77O&FF;x|_Iyavx)h#5*qx?+yL2uEZxF#j@E%?cn%I{i+X|Kq z`+;4bwL<}WtGpnfQIVitFcIEhw~rT0h5~bisM2mIU<-`DF%=5>B!6d5R=Hc$t*d@` z%J~dlFdYgy&DR^>=I?m@?FgFR$}ii^Z+T#Kag6omU5KHgv{DC{<2Sd~MNa{RrCK6k z1?_$~%&Sl((o+%Zlp^KxneL$sB}Kj?Vp|ja-!iZv($k}tJtuxC5VPxG{`;gS4^k(+L>C*-8Jm#T824BptOTdWUtxaB>Cv zjxUJ}?~r7S7~gjGxQP_3C1ER= zN%$*{30nmzjU^y;c%dJBw*9-N;$-N|JQJ%#QV^!@?$pU{w~L3yHl}~avg0cFRFTb* zPm|mMJEW5A)Tyw+-Vd_ZS9~*z$j%S7UOJng599Q*;8Qx(l23_^;ui*`m29vk`J&LH zd?f8hLv|8*Ljl^`w&S&E%(vvL%5CkUu{VUqws8)io*eiep)s0TF5uJ@Qz(6+3!1X? z*y~OG;&x2x+B(+xSJp8(7_4I~v^*9gRwqOZ5K-^%&a}o7;^RymKt`@3_VG8lMv%M&;Iue?waWdu4}4}#J?{hXRnOeMfpDJUla z$6ObaiwxE;kt-uSsJvrDuC$OL_b9ZG4f`)C*X)U-qFiZ0L+)al5HdGoWu|R3Y@=8R z2xqllAOTUAa8i{f9!ynshow_PiTv9jE3ktKy-Abwf1ABWja%=H(ibtIk5PElR)NPG zWFXzx$TlgASL00VZOUP=aal|`Y{7W!l%wC@InilzLR-SWxHzFrr)9>gaFZ=aU$fX4 zrI(uL24&loo(~pd-IWI_D4v!QO@>*-eQnh8+DBT;TEX(S+e^S`a_s>7axPgvXr~XU z`UImx1pr!iMJD)SI_6ShQ2`9sVV8%Id=xSZ`0xz%p*5}#*7_|&ts@@P`h>Thb>zm( zaUV=pfVAp>v;f3nI+UYmEFgq=BpJ&e`xR8yi$hX6m8B%c`O^r@DZ`Ib1;d5=Z)3{*%Vn)nL&+~pk>IN#D-fIH@c!ESWXrR?>0PR1fJlV|Vp$l{m|3`Y;?!r(dce(xj4gF3FZkc>#!nuaUnTBz>V}_0)9?aja z9$T-meY1i2p|w{TY*VmGtu$61EPqjc$v@%m$}L7?=qbJyDqoKu-M#Lr1z(Gis`=Zq z)=Jj5lqwX@BR2yhMl~#NF$1DN5U}3f1kTM&zc&(@C6EA#P6=YN>Oqvw&%nDp+w)AK`xerC>uBy0HcrQk96`kqc75i=bIUm7fMexZ%;8EgAg{An)+D97L#hC%+Eu_?%U9hRzx>jyT98wN|$2UNXi!9iPL z>^7I2I!HsD-gLHfSfokhf&i$`0$+H;F_613v&En-4vg1&mTDbGA7RMqkh(rmK;_{f zO#`IM9~VdoVgvn%r)ikY(%qW)g7Iy{Ja)-23u@*>sYB|hW9v>!FJ{SQTFDD_e3{-f z)Np?2@JiN9*4eDBI?5;oTTiHM{yc9cnMOY5g(v;N4>v|$k}!xVRo)#IP@{{VhZj&R zkxPddAt9o^Zt2gxD_TM$8gm$OD0LCws?VejMmn72+v81cp!C0zB<(6Zb}NE7E=?Dh zB1)ahECD5&V$SUstcEh)B3=`{l!Ox&3noE1G#s*CkcE;)ngpQ;bjf6Mb?a<|CqL_F zy9^MOpJsG60xu6k^#(;0R=u=soC=`}@=E!dm*2{AE8js+d-6;c_HA8E@bFEP?kTJ( z^sibUAtVRNs3sW!Dnr|*J4|}0J#Kc|O)PmHaQm@1iEAketAl$@1kj}XHrO*QxLiMK zkVKQ1IDa@}>vuG(Km|R^u)vU+{-uI2apAz}Qpo1lk(_X=+C+w5@)%E&@U2lffz?(EQY2D3; z(<&TTa#scGYal|Ngh2p`LL+snn9xc=YH$q*YFtr4ZL3e-LB>`ft7j8_slHei1@FkD z_eou_EDH|2rCt~VHtkU(>seUcXSTKo$=EZS=Of3i2JxF(NmrKbp;sNe@EF}{eWW{% zYl{|j0KMy8T!t0e+n}i!83x_E-{!<jy7Y{;(O0)>u95j72-2Tn*rbrSeY<4f#oSctU%&pf@xw|FoHR# zigu0sXw>+S<4Xe{8U%sSeC}6&)jQ~q<>&wt&McBb791T}7`yCWM2BJ*!%LW7n*J35 zZLonUCx6{uGSy@+*%btr?=D&Ij>%Sn5~-iM3_)y6$*Ce5^a_3=QZ`bnc+(4%i$} zjVK#FsBSId=*9f*gt)Bo^!sL7w(`|D1QMtk&j-jKpi=bH_aHo$^80M4diXl2W&)8` zDTM*Qry`1{Uut3At6MwSvk4LppN#vC^cq5plF_)yj`UG}?{~poJ|o=M9XNSQzPtoctSa(M&$rw3_hOs= zTIB?*ZdLoLf2~?1$gFB{G+5PJeBj$^(Y%TE7Wov)49)rEUG<)pTlI77NCPwR?-8`o zfhWD=dLdK87(rFTqrNI{`0uQ%z2UC%Df}|hF#ZBIlVkGI#;MsPq^hBuNZ)gfdK~td zt8LjMbF9Z=s=$q^z3wVfJeRhSR{*CYm|8vtB#q6Y0JE_!$>R&)c63vKoL^D>h@%27 zET^px{1iejyeautUVkeC@mu-5SMghx7W3~1l>7ehrO1&an#FEY&%3CLtKXniZuQ0) z+?=bO{O(tQvUSOG0r5V5G2A-&C9i@C9DavSP#1L9ZqXL5V#^j$!Obph_#5+Y?_qWNqxX%_MT2t|i)g$S`#aUAIc&m-V&rq;~TWj;Xlf zA+QSRe)NETPfqW7Kb48PR$+BRTbU;7`u|CHOvM2~E}bJgNI91@6l0F5c+WS~vlG)F z4;?#ksg<9a?yes@@zbyC<>~ZC{xXKqtoDeSz3^}B*oj-0*a0WqLIGxVhZ*#J&?u)f zN;%7&ayVkzDX01OxammCOmOfD1{&5~?swV>Cm%xk0|g4%ILY~@aWkdB=@etmI^jgo zn0?fob+TWlw3I|dr8Oc-a|=*xq)M6663Gz?AqfWBPdrVR~C1IC&%VU51L5{ zFhHp?_6+uCNwU!4=I0pTdomMx0r>qN3c#b4S10?zU7=9SM6P9XD7(_F5`2Yz zU|XplJ?n?MBk(cr1pZf!48Gw7{Fp&)W;DYX%;a>;*wG0Z)7b6!u=l`WUg2i_a-Ucs z-$@%?jlhZkc1p3MpBd*U*fS3HXBuEj8QJ+RbgPc_Fs2&OVcc8rM}u$xyW?Q*4|H-I zs3sZGD9k7-q56|YhWR*9J>f8K|LeaqNgKxlMeQw2H0Jv zkfWn&d}NEl{MIAGd>p9mI?Q`+dL*bO+0-c5m|LQdg(HHkBcjl9lAkMJ6aA)x_9mvy zzRK_7*F}~I<5K*7+spK~|crJJ`(GZiY@-;@qbVykc{_m~Up9>}PBgMtRxbEeKHQrx4yps4 zCSQ?dl2&ar4;Xr&|01R^82jTwUkh+3~0tB zlRt+qpB-(a04mXZ17DSGz0edazmmDDzmK4wf8$SH|CtZ{{FeL9lAFY400y1w0IOBD zyv+hk@CJ&Mlx0k%D;u(verwTWN73PS{wz>H{)yoiZJx{o2jkf#*)eyYPpdA9hShJg z^o8OACr#)(xX-J;7-G;f>Ntq8JfVIEVm^1>2ma-szJBMMKVtsABX?VD{pG6Lr!U%V z9l-NwciZO3$JA|XgwSmQgKG3}>)$_c)mN{)^w`Lp<9_ms zUt`e9?)nnVx)16?!B-1%1y6%=O_(iBi&(LXbS%MO{t|$e$6EY#R})Y<@^MfWyA9(UM)Ybdy?y@p+Ettf7>h+=X|r?d>v{B6C$_flfoU2JOwY)1Q#l#bm0huE1r zpRn$)n}ad)G-8XipdjoX3>)8P*-4j-40{{DAjQ>g(#VvMyxk0_FVmZ++;YFMv$WVo zUw|08q}BlG{neJ}2SY$Mwk9t4gGR3I%ny)Z;I&Q)nKv@|NX=3v^+zKSNt&ebCIhbSD^-q(V2x|7%LRuMOpzeVl8I-{fm>@ZhNEEicr~+K0>IB5~6;1 zd{wIOs$zUKWy)+w3qoa4Bz?DbaN35Z2JIhRl}42HDv!4!9GFem`u*Dy0#M>tbVdgn zEY}Cg#+~sP9;mC!feJyst4Yw>wuCz@)v^$qwH0#w9|_Zi{)ct8q!m!5qM)|zNU7*+ zvXERlvTK0LMk2^aYbxklobqg`K;PPm%OnEMUz!TyZE8)_9>hzMBxdBjAttqghRqlu z9Cyfq$YW(DgjWEHA6lK}2SF#Boyj{CXggsf_DV|n=Sf@ln5rQ$c5@yc#6#9K$0sxUC=IX;iAS^ijj4X6mu#iZL=hqogO{V*F>^;zdnqytq2;TN4h-NCZ^P3I} zqTIh>wexW9U#oc$_iyYR^_aVVec~kn^zhZJnjMV?c&vx^o^B^Li5XXWv~*BuTyi{< z`TTEfRJx-q|6E_{+~7-{`C0)q?3xsR;37JWpN~5F=eWGnoga|%{5vka!*MnQgkpTI-$6X?#GnV&^5|M$9zA2$mPglXUxF4A`9`qY5~Pr+ zEeEV&M(GzqJV0xONFx_EBsU%^mNxaO3WMMn^zyY@-BdUQeakQT0IL~t__y5@AGcx5i7DoJ-YYU zdZbK=E-o8=bHhAGT+%mS80lM9L-9~2wGLekk`@cBlijM5CS7Zt)T(GXcxQ)I(G6gJ z?Mnx2vSdS&ck}z+Hx1kaRX5*R4csMnyzZla|MRcxe9G{^HM;ps?=VA%(qMEH;thz5 zmT;@Jr6&CfL*wZ8`?kE#`ciyY0V760AHWDw@2ZHq4Ok1dzQiC0MhFW`>np>PjV-98 zwdT*swZJr1!k9g1yL?giI%vw$uYO=@Jb(}k2VhCIim44qKD6$75DENO7UMv7f-;vOH8GRG)4VLw<{U1~@f z_yG1BFF~zuO$n;LH8lXCm@ZsaRKmr$xYoCZ1U)xM(2a+Ypg*a`>u7XBL$uhkiw&HM zmY{})MQ9kfih_nla8ys&h@_8n1h4b1Nr1kq>g83H0DbEZcm3J6FTVdnTg}q1Q)Oca z&nW5BDD~Ke@F?{|Z3r9s;oP7fHqwb9{qUWtdta-%x4r7#I}X17nr*w^`Lj#Lb+6Kc zwi0Ti$QEc*5a(11Vq>8oD(NEyF;@Bef@NqX4uY(R zLD+C~Dq??a4d{p};$ty!0(nPX3d9ETAW{lIoH7;zz(jkD^H_(Jboc^`#)zZ#$~W{SKwIWI_Vtjz-q0c&3D4K;L~8?2*|&&e z%Dyeph@&>3Q4eZ_HIVPE#-Q4BM9U?^+9FO?-GfHkh9rik6>A5}MREYYSq)b2rFK%$ zop!#F`G6%(kuTQ`-u|`@F2+u^EoPxgXyUwM{NvKA5 zx9*;l4-*Q@$_3-BTn^33#m`KxRJojgVBPCpJKKX;Bs|Q+UP8nv1|>w&8A&lG7b~7NDYyA}HI}X2uEmPHY#P zh$^F;G4qXUT3(a~mVNhKe!?C$G7?coP^g-r(Jx?BpB*AudPkh{d`R#aL2ua?kIb^0t8(~LqpC51vA5JPeJq!FVL3`Nd>MG;*s z&VMuVw3FfJGm!|-ha9w^vN140$L73X!FiTh5-(>%gr`C78YQnSsqUY&nMV&uN}-vs z62eF_K;p`51c{fFVk9E+F1~K3rEh=j09U)oz%vx>DOB_XB@)c%2dY!59m{AHKQ@># z!*ITJpcwnK9Q(o-!*@goN5}|N6JMHvSLp|AEoQiD8 z8p}hT2b0=~ZK`f{oT zBbx&+8+T&l&{8N4t>TPEtx}Xc3cMC0RIst#*EpT~&=qiH^v#IqpqXxd9?Msz6(!$F z?4^di!o~x#fIwOqLLl@fAwzPlaR?0B*%6p9pn;a&UOB2uFVd)^`upZZ>W_Mnh8)!^ zMC9Wf)wZ*yo&SaQ_W0TqKRABDme!$aj%MC`uFBn8EHRTq`IQssadtGn_miJ0oIvmL zOUd51R10e#UHI_>cm3IC-g3dPzY;e|<)t*I!Xk6*qjofpbs*GyuniZ`*}(V!*al-8`4f z1{0@0l-(%9$Bag-C=Os%5+>aerGmy^xcr~*_BnutzN_cF?PicngNY(R6Ewpf621Kb z(pH+`f%62{fCp8&;2IDsBmGbCJtq1Z91|2gk0gakIjCrkjA^8n-4)b9>!p1ANF0}P zt#oeWVen;^bprUYcXx*SQylo zO_8v=r88|!s4(c2XIpR5=S5uhZ~41YTG!m$MvR9`kyOlc6H?r{qev2^t-SAo4@(m zgG^c_j+viouESNsshxQlT`Q#7s>&Uj74Fb#RDHr_YPdeCN9hbzJs5&ehn%6J4(>86 zMq4f`sU!G8YhhY#sK;WsWNaU4wQOy$VOT6Xq9}XK#Dr%Uj+w}nA+`vFmfJxZoh*1z zWP8bpVo6;@w!wy#_yWJOF%{p`wu9qLesq~hGS_+WrU9V*_dK>NuG-=4?=ToEHt7zs zRbA|@(9aANVuhzH7$;c8^VrAP^hG3sm^tT$iw4uWxM(nwP5yDlMg#lvhbsqDD`z{r zIg@e0t_?rDuC2_TK%{93=85JrYK=x&Yz8EGYuVgt=~S^a3n;n)3gGC%xat@J{HQ_c z7oc!4DPcI}U=S1|Fs2-gsQ^Y7w)M_~ExV%s*0Q7Yv21xQrgg@lU4HTcw#ZBJ75^va zUeAIUKw$e8e(T^37>O9~=WjCs`x$hMgw(Em61TfASIKE- zCZ|!8v6;<=#P;&(1#ADZiK!O3Dq~o{|Fx@GWMl1^byZ>?B&l2C;xHw#2nfyT2rZ&T zIcqe*>SzP|`CV8DQQBr(JZzt4BA?s@FTdC3yQ1mUx1dS<#;uU@ZSy?V9nI%IBO z{!BS5GdxAigq$e&T~v?yE1=w5hM8Q3nde&O%|O72R4wgxXhulr!Kt+G4}0U5N-@p} zWAjhcrbnIhKG zsPV1j2~L&BghauUWC@;H=+ZxPG`HZ@IsVOFnRoLU`$JpVw%#~wO(NlKWbXdDGTG-F zfXURLA+t9xQ9#`jy^UA&Hr;k@KA(?Wn{NbOuE+C@SMvJ2{rSz_X4NQq;_&Z$qrG)4 zRm+b_O1FHIUcDmUyzREV>5J9mymAG1sSoisry3UsSu=K=zd1xgPIn(vsI>TcI_5kZ z%e&W-{FpDUrIQ*w@LA4W_dZ`j=34MNDFHT~cdya)wG7PMHN82o-D}-;4R@sE6V~|y zCX_OoFR2c3qL6ufjt3&~cwQ}Au7VWIHzFeHccn}lrR|giiw+lv(lQM-eJ&cgQ>7o} z#tSAgvWqIMVdRM5;X5%|Ps&8{rab9>_mBpuQyk17pT+DLhm7g>c-sB)n;l;6K4klS z*b~{;E&#Heb}&=ABUOS4&?)ZV2x>W-RUn!yZmAVuNOg)gRR!`lyp}XM+G!?$qwaHdee$93HqbP86i&-J%fh3heh-k(!fp=(`13S2nr()E_W-y3F)4aP)CxeHwEWP zaa@t}hY=myhVtSv=VJCc+k{ObRgDR=?O5w*}?M>@u8h|!!gH41vE;c*nCKtBk(+e}| z`xt1NyH>o5w&JzT!s48;D1C1&%$Jy(G0e^L^&HsSY}nhIaI4Ll5Rv_WT48VAu{Uqn z<0TGT9EJqL5@?h(+i)df4Ll+41OVf6CBV#jA2u#*;N3~}Vt!#(%(*3>DN`(Bl?Y!X z)1M+OH#Sq3JX~V@jlzB>r++(jJ0<$Oytk=1^21M}YQLy$w-i&DXpQ=Es@J62eTX>?&c1vTf4jFdX`95=qHWHfltS3V4D)hQq z$oYa_Mpc{378ttXK7LK_s1L_dPhBh~f$uuSe(&;RF8KoB9ZLhrdUaW!NP@m_G+|#R(*Mm+xHi9_Mb0UrGRC;aN1E3EvRSpzo2* z&ah#%Q_`D)a=Elq++_urcJU3?#|11glPknp#Wm_Wf{(f z7*e4!2MV!>?;u}a8)0Ek@fNI)tUKiK)P{miGYf&xyG4rFuDj%Sk z&4MQj;egn{YmIFUmM~#vuEDyRLGfUI%AwE`3sE$CO+JQoJ&Rq1YMv?UpW@S5uN&my zY5;lKB;TSFb4kje3C?#IQls>a@#lbuv&8hcZHwha)1OUElU<$yyOc28q<%ccv z5%D5sZr@yi7f(#?+rGsAlIidNTw8H5Gqvc0D%C;`=k99Vm-_FC@cU5sJ;iTv2(04U z;&2US?W|gcyuo|T;a;2J9^gHKCJvEA!M}1|>5Y|d-WKM0g)M#(DG+Z{?WgPMK_l(8@&lW~}Tqj*c-5tf~RLU4rmHdhPQfR7;-LJ=>#y zdiZPzllh7+kLbN|zPFw(0jXU)@7ldf_x#m2Q!Kcf*;ahpwJ!n?8Vdl+TarADQZs?5 zW+}A*3Oem?XsNl_-;$eShVRYG+x_56W$4f$Xp9Ar{Vl9Seh;*|FS&^)f^9K-xlLn- zo$VwW);>6%G3TMtV<>bOc#0eY3f@UCN}jO54|}#`yvdo4*Fk$uto<1|AD}Dbn$g2i zVlYG(N5bzT;rBGZ2Kt8XZ9Y46z^-p04mcG^a!Z^85aiwGWkqOQr;oT_vR}-!droS3 z?d5u$$)YoR(7V2&d%NnT{E#E!SjJ?5t{>03FB328`a^JX>c{ld!FNQ0Wh0j-{c=-=7R_g$0e&~?NVd6r zo*~<`K&(MNr=*EEE9z3L;M(ZvU>yBbToJuZ~1xnDEHZRq}~a-wS#jTCjrQb0X9AmHS7Kl`h~Q7&=w@lh-`KmjC|6YbYh&mdSNp!MBb1z z7@*3zNR<%OVsxqtPTEji$-TU(;c34}*oL{ee-ZNYV*( zTF~g3=JW`D6B)uXc8{Ivb}Z|DT`Z#a$e#|e8~-e3-^<`J`+|3k>NtiDKIW|tWj&>C z#Uw;mOiKE2#bS(pI(&n=(5y@=Au=0H#HtKQ2gM5x-67us8?a!oUtzy=_ORN7lKq|T z`(3^+B92{S?5C4`hj(eI+1A>D>^ke`5S@d&m44xNG4PQqna+q?5@7&K-YUu7+BTKO zJEqb~N$v^_ec5Nf2z6nU?NCEEb)rxlcpU+3N-Z%cr0Whh8V&jgp`8Q7IwA1-Hhx!!^tCVFs$={Rl(*>tI3vdhsR zxpA29^n1vr9hk1Yt_FT{pdCyCWO7)V))Q9SG8rP1=5Db-v#fYIP7hW97PB0|F{w}- zDG?KnEG1YrHq)tiM5b1w$4u{RRL!LP}9WosHWqcSt8w6pGns- zokBy@pf!??ymKrwz$buvuKm#Y)M z8mk>p=#Y$JJ7Z6xZ1gMFV1R6>auj7PiNQGasg<_?wCoYloJsB>7mkY&__#^aPul)3>g zx(p*bFxIq-#X|XTU5^TpdBz*}BD71rxX~X!kU9SDvy*#R9_iPH8>9_4P+n=n4f)2V zHk3Dgq=i=3hCL>+51Y}*d9xm-;Nv<(_Z>lz1l@OM%R6wC!9HhNkFj+sskGkdp!FVM zSeMay-y5a%u&sw^y>ebuX+3Lu?OKo6*Q~DcWX|++0qZte)ZT0sju{PZ0vN~R&B5+5 z1EMP3x(~O{T+MjM=gf={`D*&%;#NY8S#K6oL`gGp_)glJv_X{99q|<-sqB%WL%2X` znqJZvYwoF**`~9rmFHTQcdMi&=88`9mbg!TCwo=4&4zHJB=(}kM^eapb3U)t7@D}w zqXTKK2rC)Lcf1YR!nlGbxI7`pgG)zk=%D13op5WH%A1(uW!t$A!39?<5MOw`*K-zA zK*boejtL955a7rMD?>GlUo2ihrXao$ch=cX5=4Le(uFZv;~I4=F@39!m#=G|fjVCn zND)?hptQfnrjGk1Tc`c3tzW$)S<*;JO_(j`HVpWw8KTG?9*PEr8={AhB7qriazm6a zcvrodJ7+ApG{}-a&W0!$^(pYmJef!XYU#B&R;FWoLyI(ZAt0a@DF)po3+5+M1bfTR zpRq!D*VxV*;___*#UJ>_vang)Kgm}u?tjA5xhZyqSJ*xgvae}-T&)5-6~Sj>INdHz z#F(nGUdx0dupOB7Hy{UH*J3A$hfm*;V6SjWXqW-uXZj*A$=nP3a zvRt1oOkn{`@cz}kX(X);zzns>Eu#WmLp^fKmxaY=^8@5=M+@-hgr}uCJp-7reR{wl-;DAqHV?Uv!VzjF7W`5C_y~k5ns@1k3+~ zxy*sMsX`kL`C2XC3N&7z@`F~Uby9_59AKj3|8Tvuw2siWKfkFc3`$<45?rHxEZ9+i zVEoIeg-=2JNF*9Pn#%asshF|3@=c$Fum(U4#4gH}yx5y7CmpQ)ru+6{n`=dhr3qTr z^G zx_N`)RE-qWfQr`mX<4B$5N|P0y`LsEY=CxKcPH<8m~bMs}Q)*hj+xlb{HQ&qM93rb#CD(h}_xsp}yV8HkDQqc<{D zS0(_ny$~tdHxZJ}V@_`Og{Kd$V&}mp6a-sL6`!-;tyRjx)$Tl?RV4xp`OCDk>RzpS zNk=sDm(g#YX{T5fqW)vG@t~HE?D*f@qaG~RnR=LhBb!dxCibJ>cTnrkv9qqd(RYK8L zH|^X~>2VJ9b1^HfVM+TB3)DTEE4G=*p;xtACe-SSa4PGWnPoo4{bppnSlpGk(K+L8 zOc`Je3kwy9@q<^E^%$8tN(~@yWbwS`EC51CCc~BHc9>a$b=;0G%g29}{oiC{-N)%@ zExw;pf|;oW&dU^NvQI4Z-F@Izgux?Wtof8gm);U)_!Em{^DH8aQ!7v>cWTN-;D9^B z=_d!33I)3h`cm(w3V%_(9Ecm3k(uVGMl`ZV+t%YHWBSmc&XGE#d-x_0S9=vpq5oBN z5|3*TpAWPe`_AIPQ@xf3m?zXG51KW^ZP|cqrtd_rgRxA|hwsU@BYHWQzTARs2L`ll zZ$ND>+m;(sh)SpgaFq}PlxcTDY0$q>-o6LGW(7~i~IuO~JKO2C-Nxzn6_ zP*;8GLG-v`ucOF;vpe;8O_pUO_M|VS*dcZ8gYX@WHaF8Kii&$3u6kqTwrwK%0?2wG z&OjzYphVqpn0P{5F4i4`huKcK%oNC9Qo&4mZ^sTm6zceHNX2S)*}4rbj<^jC_>O%W z_iPV9xAnEQ>W6gTopM5|FKQ_R7<3>F6?r=F*QHrXM17bvpRV#`AU;lErKVjEfVHgA z_=TR?V=B0qJ*)evLn2D0>^3~g|I^hrQf&j&B$=0fPn?_%avjvV7kG)7=%qv_P2_M5 z1-e#^r%RUnih%2!0dR{EIQU9nYK_7Hwk3nEFBxz&2k!2C;4l;f(bs*hF0GIt@ zU3v$!3eviwm)fj_OdqUg=noci=%}K?hII79X{OC?VHBiy(x7)Fe!GXR1J{5E>)Ti@AaneJSUJBy?fFH^;Y7G+ z=xTO+K8MvF^9izZc|$8pQrv|)hHcuyvE@G?;*J?97xu>n8aOFrl(o&7(YK8Q_J>({ zie%7{y`I>|u1sNN-M8JuAfuRT^#8zETg;hN`yY=@T-|F2(tw!7JW!nFucq@6zmV9) z*;7Pm#Qo3_I`I@V#{s{b;F17$(@l(fTXXmB$1pUcB4IwElBueWYSyKK7Nw)OWS$k# z4#jJK{e&>4%RR(`_c#-kc?tb*`Bn?IS%-L4K4eaAgT&=2zcg*~l!cTUS|0QbOmZ-2 ze$2ZP2W`0{+@WoNLMtBa-7a3q1G6y_z4lt&@igdCl5kr=>G^FJw^#w}@7k7w<5{zg z{jWuPPlsr4+a2$XHtirUYZ^ikxDp1z9!#M9gtUtmG#}#s{K_L?a>%<#F}1~N%bweg zwNPwY%idO4>3%%zTNN3>!gW9PETxj8Eu4Vl{tu7*b+l2%Rw*qGR31YW!CV$;t(yFN*P3*HP4Z*RAXz=|@R-MV1m-(U45N7GWS?p-k zjV9~r7#|F5SWbp}N8QksB{{;zwv0KLRZ69p6ReA&k1RGjX`I!S-nfh>eb0wQYHA2* zx5BXY7>nTvSeVa;&@s_luoU>icgQYAzTJ_qzM?G=+JB^_nkSeRgBt;1tDEz@Yf34E*pv+nNKvZEOd1lFUdSr z;!a!CQa&wS@BV`X7`R3FNY9zp0?~G3-IrAYq!^q8?`bB~ih2VJE@&8BPeH?AgUiXD zX&_uSwIs}V?tB4RwItF!9>_od%PyK)#V2@>1v%3y?$@2hAei~Z=dGX=O|9aqR#1wj zmP8XhwT{&!(?pO=Mt|NW!)GQ9RU1gcoR~uhsFy(o5d^*G(6uf@Fj+n zbyF3UA}V3@LYX1f-=po=@jza-VCRY6H0cW)sA*e5NfT6?oe8x>hXp=v`}&~0q@!G* za~aT}yX4f+y|2n8BC`VBd zNCOjaW=UJnQJ}3!u6EkvsUfs=pr5u7+L5-rACb09XtAEJgz48XK;C~9eLj_4t(tcNS*UX`BAey#mJK& z5Oq2U;;z5=pq!73T=J9i!vnckhh^T{3B^{vH|1a74(VDZgQ1CBus{@h-m#ejddjTg zMz$~fKr*nI3_qkUi5KhHUhJe8fmK#tyiTXpkm~*$Hz05+XL$9nIAG<|-G6z#my4@- zSiI26H+28J@BME*qq7p;7zd%)lK%1>G$5nEn}e*y1V>T?ovO-|^b8b=Nh zv&w*gr6A;RSA)J=9#5SiXox6U%oUp8#sru|?cpM+BiVBw1|(PcP#VWmFP9JH1vv2R z=wkEO@1Z%{fu+o1uJ!s(4yYgYIrN~CAIuqPmR?Fsmo(^48;8?InyfGOlV zzsH_bb;viw$syk&)y;lKJh+W%m2gPY4d}Fuy~Gc*@ga0dqDqETbb9IsbvmU|85@C4 zN1TPNGoktNzL))dpm5PE1F`I(M^h5Gc|N5cY{oH4E0+66NdR?1JNpeto=}|lQ{!Jt zPFg$Mc?#{a*V#!rD4cmDy+rRV9S1z5Ivd=`1WG#y1nYi>75hUt=}j4i6i}l4n>EPs z_6C>Kl%3VYLkAne2W&wvXty}D?_C*MPy@ihCl!o9gBc5B7=D47$Z5g6^wK)aTOH== zK&1xQTLakI>#ZZEh?W}$Hqnkk^5K=iHkb`|^nV>}EvgSkHK{HH_CqhJgS{qH6Pzas zX`-4?Kf(N(m0?~7s!1szm=89{W38yRgQ5DtrV|4DPge$e9jI26JzyVeP{^84-5G}J z^Bv}YdHISwxDHg4fkH5!Zos@&RF4eh9|{bhEkEC3oYo4Iv&;xyov~8Ec`Yo8w${8Qomh(`Vy)sP6yNbmg*Wn4~PO z9l8#?tEtglby#dIqaeqn*>*u^h8-BgWIEwoXzt>4lm+eL=NSIN)+HMXi-je^9#C{F zgxC)ds8yPfuUcLMQ}%Kvbg#SBEJJfzn9fqdkNXm&KTj`7F2{#~wtA{OM;B+id1lV) zi?f|v+LUfg6Rc{~#_($HCG*hIlKFzhAb`S75m6R~BE%)I-hn==AFU=8D(Fl}Y{la^ zpoZBROvWR;o|Z;qtoY+UH~Df@Zk>B5yi*rArtAj&hI8o;>Y7epuiu*v*vEL$#&k$8p4+kFOnC1J zI+(HITYqMs{t=g8;JN&K!AqXaC2jsbKcUHIaS8MN9zXZ_JJ0lYey4ipDlR|FXQX^8 z4tr~ijw<@~>ZQxL^zn+2;{X%jPvIxPtx%&& z)H#=2fcUX%nKEP+P;$P!kW32Zc6os^Q*=zuTkwcJS&eFZ( zEl}hTvW5Uu$=y_@`d@IpL9Y6L-mCwVQ-rD~vG7tpwDynPq}m6qJZhJ7Z--ZPk5{g$ zf;`f+r4P`z8lYPTC>2JPe|}MNuwA_B)dr^mSqyT#z~9DLmIc@@en!o;i|>}r=^Z9Y z3Ws%^m`NOt>tJ!V-z z_QCJ|&DS4X)Eu8_0o#d`I%=%Y#NVcsrCg7)!(;=MEZNa*L6q2xh(+D7=7}p7#7Y;) zYhYJyje{YZ4&sw?_funj_RVi;e z`sN^z6t3Ok$t)EQX%2y}7}0OVYC6R(@kpn*^))uUsDa{t4zD+fbEv(@x(lk^5Du_>bagxE?8=3th=O1#JaQ0&l|>AIOY5#Jk6Oc z=cV17ecgZ;vWpVpj$1{?Hl7st*olS|o-0L*7Sj^>#e?T^k-$6m zVG_7MuFwn^SLsOYig4un;LGC8}aOrTO9);KnB4u&})~(rebu4;h@)v#gW)B<3wy=fm}SIPf=f>wVn=~ zZcv+6v;zwScxFWY`s9WIc%1lI^lg$o)D;RM449QH5LzjtV2#>xB_uA+VU;4{U)aCg z&pe{Ej{d7^M1HVA26J*o-;qbvhE>pP!o2~a$!eloe-W~BZPA-?Q}ZZOv&#v z6~ay0;RO)F2c_LGglBsOIbMw198;9rSWF}ISyV;W zPwQt;*Eh7gG(n~KA4^@2zfh+{Msg?#!*xCJA~NF#M?u?Iwbf5REbhp1-jm3&d zDznw&^JS9BY}K^J8PRq(;+1qpl$dD#Gu9kpwjN%=Y(>!yn60u;2dyb>Z(PQn!bBKh zwnm*^nyrsolr{stezTQC*Ol2?S*nb?#Sz(nk1$(pqwM<3R)pgUW@|wAa3L~?>Y<2U z7R@8f);f;OY&9H9m#l2ImcudBY#rU_QvL(58;B*bso^!5t)*>fmR4!Dx^aln9ZklX z**ZSlY^`IW233G(WwW({L^1_P24FC=)muLl%vQK4q>qheYl+meV73Nh6|*(ChJM`5 z)@4|3^=2!69Qhz|{xs%{H7lwlzkcEiI{X~VIyYNOLO27n_3TKymCRO~Ck&{z`aGdT z__;S*D>gTy$Sfu(g!Lk(HVxag6Kq!@@!Z?4?TgoEyMp{x+pgs>{5a5kH5}_OV6jU_ zD04(y#Rbcmh-=sSD;cm1#eX^jb{UD=XTZ|C6%E)s#)V&OG%#zn!sW3 zUa&$tHVxI%VyQaKjMIvO{3ZliHlcFM+aA2l1tP8kHqrbf7N3=d}v zkwz~c0a3dK+aMe^F+1boa0l<|hl6QeWAuC4;KxwJZHr2lh0Jc1<8ONwfmL!OZ|y6j zrSh;Rt@*TYI?Kd0H=j@9nsQ?s z`}1sLfT_tA822q*b8%s$?*#F%=-6cM{yUS$8>Vcbq%$@?F%>dXwu@Y6!D&o?*YXfS zmgwXKb6RAY@-z0@t>Gcytd?4#Wy{dID$WcoF<2qHc$Ff@w;8C=_N!?1x2;2p&FiEc zX`v&(K^xxMldQE)vBO*>Q}~{fg#}1a^PzlKl7awo@Ky$ z|Bn6q%xk>%_a}9-0fv5}p{So^D5?<*yW63soTi5m%sZl`*wF?Uc{n?SP*gNiM4DkG zEOnYuKTG0(Y{YZrJ(Lr+>-svuf_dE_IB}eoADsNl_n#DsYE}GlDDs^w_F-)efM}vf zgwh0YSf=u2*^SN*;H@ztiO*-re z$rQUi@?!e#3tKuZn!`c&4F8vFT3xfVC#SJIZ8F=#=^W+(tR1m9syyFFq4 z!jxM!5oPnC%)|)ylkwi#4|BSlQ+GZ1!jwHbs%(NZ9{MP-vvPVw#Q`RpCNjCSei42} z{Hf+f1lM6~5eIPwC^Dh+xJS`Mi6WuWXOpX@BJ)D@p-7_$)~z;1EKpH4Kt<*eSdeEX zj@?LNS{)&=I3z-bkhCxo2VRL(m0>8r(JA53%QXiRL3%btNM!p%%5m~w_mFX%U)Vh% z2yqI+ebsOXB*IWf)jA1ZW+{3M3V4dShx1gVUm;I`RIJ$~Vet_$CE1>Jb9&|FI3rHS zffhJjn5l8PVW!UI!ps1dhqhPXa!X+~l+Pujblh%5E5_%96=+fwYR7jFWC*i@as+nU z2t;}eBTz|@I0CiG8$!fJVC+mrz+6{-Tp~(gP#;IKwsR&ZGMCxo9!2dEMeC5YGLBt5 zSA6_mvNk4oGIL?=vX;FvG8c#ulNd1q4ALA~;?n%0q*#dBM7m_ax-vyl$?sgIRY9s8 z!ph)qtv0O3K-27?f4CoiLL)m96lqHF_(zeQkGozfva@C%?{Zb~aWYw%*PvCWr$5lk zCaYyi3>T)% zAZ7lK;qEHJkWAT69N*%mv+oy@54B@5|<@T6h%Cn*z!mJq0 z5N5R*hnQ-B;w*AhJMQFKGbgmgU`<7k6UILhgI=*uNLy|6VM7eX&Pd{HjGnuY&Yw(c(a+M1f@V(}HyTH;f8`I%869NTVaEFrv$(+)C&ouN1~q{HK#C7whul=QK?JBg!Q$sc|m?io3H! zvD%4T6Sg~CH*L33W6e#kN;g^lY~?(n7GPt~LCWSSU9}iBJJu$=M1BNxliu{_<2Gtz zrkhOcTOem6F$3Fu=cUmJ4XAVzHzZ~?*>SEq(xM|aVvPn1<*7I6ZKL*-WzbdXre)A2 zxj{u{$wujr579xSxCzoBXd~A_6RuE@JT_hMwdG$(w|fnyidfR^7YW9+O>JaMYXGYm z+rqZJ_F<~TcXFs;bg%<&VTPC3suuJiq%`I55sDn-nAWPpvaEKog@B2mYaz8tfl8DG zbE$+$%iB#AIr*PJMOG%->Qp3T-e-b6-c_V|!umAjW3L?7V}jW#>5sVyhNnC#$C~mR zZQ}pr(O0mt&YYyyK|*;VotxT$(kU+cXwoxi(U>1kJ7ec$vRJoHS>(`G)W&2HP$MPf z?b#Gi$55`__bHec00&JeCX5`R@e?Mk%;WmwD6KSGMs04l;A@L}DKlpTDjzmHj75BYWS!(IpvFE2NQqkMgt>@3{A=HaPsVh1-3&I zY_zb{v^{bOc4BIVOoKGywso#j7gg|pp{y1Z(zydk*8@_0j;_^SiZ zhVrFo_=7;HGE=A6K+OLZ^Ll3LGW+Ed`I6bI>Y?kZhr672nMq2D*0Wz~S?ytAsLucU!468SZDOe9;S4MWDnEb<=kOTc#o^()_b((prdk3IIyixt8W2X|sSLVS^}ChiHksuOYCFuF7@MBMm=?&v?oo2zpmbU`g~;Jcv$UG|LRL-zjV6nmd$Oqdt7qb=Y4`Qx!qqs|?zcWFC56Bm_@ zLp#m;Be&bAzU>_78)xw}`t}65>m(+%^lE)G{a)+aWV3H16B415oY(sXTpF)h-;Pw{ zwaUJkzo^aPh$udxHU`c-N9Di)L|B2Z4_rk-eItnQYxHunk6`yP9Km<3xtGI6kZi;v z&$Wyo&bdb4W_$!E9>Wp5Y0Z5bHiF2K8tbib1RGtnM9lDA)kV`tH6oS9tudhM{L7)F zoxk6klr0j-^tks-V&wx>C*SNjJ7q&X`u*>{;?M7T`#XM1CR85_R-N2llBqd8B@8qQ ze!A@C$`UQhs}iqL@BRQD%5UGN zG54&XF+%|GscIT29ad#&{M*Bb<6^!zEU_FjhyHUrWdraY$%D3z^8+4_*$2LiEx$c@ zn1RxB&ruUXF{L8ozy1t0j5`an79%Y!ZWq3%iH2IfA1o<6ijhWs7c{GhcGyWsxTbb? zB`L75Q=x-kw0ptEPKFLvN_o#t2gP>!y){(ZaS)nPN7%0zIucuH>4ZvF1Iqs5w%2m9 z-u~?pqMzl8c54tJ#@ma@f)$?uco7c)II|ob1p+h?YT4Trb|7Zjaus)ww2QEHj{L^W z9;mMO#=RqLk|qxT&n}TxiMuu77Cf;_q*Wgawz#$GW5NEmRyh{DuM~Nps&G_=4Ly$T z>APlHtq>cJ=o}JHRfhL6iwJ??3J9r3)wUJC%IR|qS_ohzuS@8iVtWCBgnwlLrb9y7 z(pcaDCfErfC`>(LIi#Z?bpm}se~jc@O@yz`k+Y~Xg3lx{v4}!UA5mwf2IC>D)&Pfn z(m>VmRvAYOMniWkKDOE}&AFb|1j)dg@v))y#R~kq0)JS=(NS2ddo|$O4n4=u&Juiv zBp=qsT7Va=*Z*l-#GaUHpbV6@mV6sT3q{e~22pjzL{Fhuy)t@rg)jB8i8t*@m%Jk7 zSs0uZzAV3zaI-f1;sXb^zz?E6h(QrdpvYBh+Ze(L5(*`$TQoN(y_E&V3~W3r3yc|j z?-|roaBnrR4-12K>E+A=WrQGoMDa+nPHM1AfWW2|?2<4PRIp0~QBcCpB;0np zz{qNv)m-EP2d^$5Lyf}%i6SeLT)XSqBWWksk;JSJN7hum`D*Y`#X47G7y@~%j$xZ7 zYz$fcPKwWyK_XCKMqnu=)mVl-I2As^2Am2X+Q`?yMrxvHgMlp*VJJxW9fqQho^2d7kXqw_ zF;Zu=5DWN*7AeYy&hBj$TnN0)d}li636G~NDXXXZ?$^ptOQo3Tqdidd8X~1RrWqYO zm^>vsno*i(o4t@oR|bi`{m4yseU=m~Pq(*|U*45GgF>XnW&Tn3<9|jQQJM+vi49qz zoSN!M(f)%Ff}p9l3TF0c3xqUHFH^dftXTYg{R&l@lh+essSdJl(pmB zxD9lLSeX*`54`ZDZ*$lK#B?}z0VGA(4Qeq9tS7({0mPz-0Y;Bzh5=Suozw3>&$hj_ z$}u8`cgH<25iiUA4oMf!Qk5m%mmz`Y0wkSE@iQ>Ike+~PM4OPek-cJ;V9{QK2nhza zC7`Wi*b6yX;}^5vQMIR!d}b+`e~~Sr@$fKN$)A`j?H*f2HtwS%i4xvkU(O*!HeQTJ(@OwgwrKCoH zTPOUfsGJ>?J6eCVt3^^o!<4@WN|-x#zo`sK-g6P%YQL7pA@BIt4i-DgpIJ;P*L|nJ zSzFR*E_^{t#tsJS_7V6RO`&M*0Rr6$iGcj>Hp2DN>F%Qvl?(WyG{dW?bwaHN)c9x( z;{Y+^NQy0+F3DAEUo?&PA#`i9L8uV15vrEMktq4J5$aej;$D$Z2Qn9OWbp#)^8@8W zgq3v_ndYKxv_#`%dAY};Aj=Vi#SJ3(eB6J#KY)Xn?Q5VK;*b`mBsEuRLFX*@w{SGH zV87jub9l{&7C4w@iGV_JKLTp-ml*Zq`{!o#N$xLp>6;$_7s_ zFV6f7mq%~s!v(A35xdM(-Sw&t3)Dp5UOVr+qb$M2k-z=GQgYi~1liK*+3Vze>J-N) z|GU2_%a=OW$=2#9O{@;@(IvC+;ygoXaVG+ohyu^<#S>L%2T^tGjFJNzc4a38IEBac z`|?-W3*=$#$a+&w*y7mRPlAqik^O3~y^V6lCQpi!Z?n>EEE>)SQA=+@>mj~XihUEE z8pqe$I65h$MIVZv8BzSKUb+H?IRdLwoCZ=u^*=j`IUh?nwjSC}9S=Hs-=ok(bXOK->A%-Y-|!zFh9jN~Gkj#&yX&rD6l`a?{M9qrY?b2ebT+Wv zNiLEdJzUNStnlA`dV^u|c5VE@{AC=>jRijvz1>EL;4*nyufyvcf{}@TKH$y(7&a>o zSji>k9k7C>%*+ZfT9#Qmnn|>lvI38ZPiWX-gh;z2VFlQdU~%qh=JO<+gIVGACG^n?iH`%8FZ4Zo1G8O{1$d@b9zm?FXU>sui%$3siSy}1gP;8%wQ^>kEicnkC@gfy5sv$o9_73E6Vx!6b7wII^AUoML=t4^dx|+)drZ7x*Un zv4ywdvsU0WSivW)z?-pxdsHCi;BG@cTVb5ZKzecdHC0R3`3osIamn#Ri#wbZ%LeI5 zQe4vKSbwtas(D<#J%gESIb} zO!>#F@>7{vE=~`5FkZ4^KW}j|n#TPGMpXpmcemJc!4}yb>k)3M!5?eH(rv4V$F)v*}m^=v{)GG4lh%kOh5m$NI{f??$@B=+G6Ow9Zwf2By{N6ugZo0Gh zM^WG0bJ%`5_4IA*z14b{PFJ%8w{yQH&uY>B!v(CdSz?M?#S(HRDPEBN2JPURDjwZ` z45;b9s^nq8=T~=6g@$p0FuZZD^c1fO0-+19f zMkJ9UirV})R_#ANGFB>NhV&RYs}olZ+H&h7!C0Us9>R(>CBbRa9kAywr`5}imr!*k z9qlb~X;g74Hx)-ybseX2Q-`NI)ysIBBx1ATRb%^hq(Mol&}#V0zC!!_##-UMrjKtQ z+gAy(9j)V?U9D#uH@+;qdb!=bZOrw_Wmp6_A0?QNb^e!W#bY?V4n^UyN2W>|x=*kj zAxJ}nhkAz=?D$c;#q5w*7S%Dmmv_G)CrnPIJ6b#Unm}6YwZvkJss-Fp*xJ_pleh62 z@lF}Kt^z0*K;l#C!cz!9!#o^zw_D*yhko^g4nDA8&-F6QH>Y z1f|_uUoQ9^f#I!M4#?8r8-#lo!;9!8UgA0^``c>b zuK|Xt(icmvQRRIiWYb|G&9K#=0+?wges6EUa+OV|H=r9!MyyZN+50e>mQ*hmuS^^J zigkADec5RnqoasaBRg@utyO#PRBo)T@|w_4xpBA3YliV74u+j(Qm;qlR*%byvL7n9 zdQ@K3Bj}%v#b@M16yC1ZBZ40trrnR37G1cggverc*~QuE44pHc?Lqi59g%ljxMZMJ zvE~-I4?+Pw@q(#P;O169T=Gf~cZ}5X3wE^PLGNote=49e715~x>PBFN*~T;IU&klu8J8R4v&ahK z*W!qw^sAkHy}5>+|3GVBugi19b#K1HbrI$AefrorSZiD27$a6^UAOaXAE&?)W~`raL|jvjaXpgippmP(8{L?2=-(9FYw*#()_f zGLhx2A-?8lIXTjHL;u@4Btke5`MPDB72hulopKVfwUFwjzTPhF;7qpiOQjRgeEh9A z#N-J&G88&HSs~gq6gux&A==RSfV=s;Ta5rd*w)4A+tdW8;4hFwyFV*R7L-V+v24kL zE=(dR*!#wUhq5Ss8CdZjy=)25-Uo-w%8ZlMFR$Lp`lNv{q+0efnKa%7DTgyTan2@$ zJ%!ge+%*_ob@W5oGif{=PRFU>U&?x8-G4A^0G2&&CYLzT3B;K4J8;faX$P)$d7QNW-VCCS1(mv?K_!w6-? zC%B9K&WiiFGf}0U6`$v>?57CxxJVyHh3vC@{*vUYog5zD(SrPGcFK8&t1w6AYSz^b zS9AFWfkVY2JrUhMX*o_qO0W4V%Bp)*f+TQk<&nBdap2|Pq|}R1D)4FIk3VGujU{m^`< zL(gz`xCG3B)9}lehHp08OXO$>h3kW@x~OsG5$HCG8Wonzl@%{A`Jh7Akv6tXG2@z4 z)i6?7;bO*lzASVx;{u{A3}WVy%s)ih^ZEC(hIT!j1$pD+tf4m?Ym%qAJ%*l9!C07M z<}GHK(V6+t7`d-WSj51Y>2MtS2 zglfchComm!{y8;bY55y93zKPDDsya4R{Q76Gywg7iXW!Ts;337D%-lyDNfiLQU9V_ zO4Sdi`z+8yKy>%91eq3JAlOF-U*MDbxQ@!ed2oE376||qp17STp1&~F+CvM|8J3b} z0VK-6;X0P{ZI-i7Vc)_OCe*|}=J3xKxh5F1o&P1hdgZnr+6{|EgDp_m(xSlS2LMNH zV7yu*Cz-CZ7CI4Adu-j;z5V4f`dicLPZ>1qUq2MSelUD}O83kO?=w#`Vc91XaiM?~ z`AQ6>{H4wpXsKG5(v3BsF5$bz{=@o{BMZx@#dOYG*VfmJSHSchf5pd#p^s5WMh%Wo z${2Gu6XQrz#&Cx+k7HuQ>8!i}Ie~gR5TQ;53DT689bSFqifKwB#H%a$d#a!K%!7dE zE%t->^b!5|KYjg}q^by?Q75fU4(Z2ay&seIMWY`Rk6Axj-6MyLS@H7u7N{8w8D2Qs z1XHlIr0zqS8c5E;7D4G!55S*4P$5fXvX2>9{C9_SlU!P)&+YNXLAx{8bEFSG@4ov_ zX;}jvP=Wr0fX!)=7C(T{SynCX=U3|uFU+8Lem^e;Xz8OP1_6w&fh@7AQZ!SW(i(lJ z6iqfxX>A0M0!WHUW2d0+O*EK+K+fyvL$N|WpXE(HcgKnq{P z=l~F(W%7-V{%}LuZg|Zm8+P;4``kF-hC#X{kth%o!@FrdcS-Vnev4zwr90hI7Q++9 zX)!yN5mW~~9M8J%kdV;zhX_}*v2L!8`x+qZS=GV|segYTqNf=iqnb`yv=3C%tVsi| zdW_7RPK38p)MdUAk{9@+*B&sCiWAX&I{mTvmJT&bqp$Q(>*`+1H4?J4T^wg5^k=NK z2cgO=@(=NKVkmZs)^m$ve{*b!wK2p@c13S|ThCqq_c_AlZin1FEG z#Ya;`mbM$;lDKIvp)EW|=2O>i@`lAu*4MMJewh6e3xLl^byffJ){FThBszADf59zePcd^$hjskQm#_xjFR&m5i zLIAIo;F_mAM7^qnJ3CN@iDRbLSp^cB4%ye5C8VQLUkM?KXD?H9zAjGE`rt}P zt2j>i;7Ukwn)k>W5Fv{XPfc4pMXQW3Q7vmpEPsW7c(;u9cCSw?1W39V2-UnKeQ?5j;MN#sB77Cf) zgRP)MxW3+&1t9gN=$8`l@5)*TtIhoT!f$@xV1^Vjf=P1y~WfsT|JRX`*_>;rNW$~d2g&VIh+!#T~R`LfQOf}&CZ9r zJm|yAZT(p9$3sE9U0-Kb`GQ$tNu;zN6=i}hqfFw!j548AqfDvE$$rY*Z}@>i(~2@* zj!~lRczyI#QD#}odMOi=5nGM%#afn@p4iKfX^sNShQ8K5H(91nPi5y-(LhTWGpRpe zc$rHry1Yw67|)Ivrh>6_6vIsxLV~1(W^5hD-qWQ5KYVV@BP?6(bvOVCav1|y>?)qU zuxHXc-%+n3taOXG*;*Ar8M5zt7gR;T%I{rhMXHvVnk9AmxYrSC)E%FP%5=w**yEa9je2;SHME=?nGd)g)|Gr5H&B^LFfnz-ubbKxq@ zH(iq4uaCZi)Y`04R8XoYq!P=nhz~W}+Ke@CYW1X8DCs@1%DtFt@0;GLJ>Q!93P@CB>8Kv}*^W5+5egRiXzY zJ7}z8Y7rgaRIIE5sH9}z2zNH)fAY~MJMG_cm-NI?) zR%uI*kiN|d?B$ReV}kejmMx88ryiPL^R3%8#Z{#WyyO>C2Wr%q)z0G5#(3^a)oh0z zB}J){J3NefzQ{GHqV}9648s2Dm9hmfd2_nMK?l%WlfP7+I>AxvVI7XROMaMEWnW9!8{-_Ry7f(4G$jAYWL7t8S$zD?l6@R{z(EN@RbS?32Pa?yAFGhH>CQT zTa$z$Gus(}e#?M5Xf|lrn( z_h_oB>zl}IO3jly%~3L7lS~WEHUVO0M`W)4bXqoY@@%j~3^_II+dRFZH?~d4gY4)# z*R88DOPS;c&qhj}t>D>cHNIVdauJ`(8tvUkYlbfCZ%4INAsD*!OT_V8qV`PrQ7|{{ zqdqg&>f1@Rq=eYb8z+PvghNos{)vrY>CW>q8|TvTXN}>-vR|y_jKv4MYSf!pO-J=; zX8<9X%1E`H3-p%$0{m{px!`i?bxJ!q!fT(F?86;H7*DdTABU%6tYqtM$%+2{@WEe!A|*Rv1_J zmg^*hDI~JXeV=><&rmYVIrOHl;UOtD4MNo4TyYbPvx!Ik6m?UYiY!WRjgF$MxSo>Q zEz#YT8wuhL@!U802iIv}feAUGA32b2wW8uyId2a6^&*!C{W9nBfL|Wg8%rjD+{I*m zC3i8I+;JDv7%C9Qv4DLLSO#589#A#tVhV`f7r#~rdI+}F2-xWcbl>r?|BWE<;_Q8Z zW-g}FKesD;m>VhKQ~C`qraN_w3WJhKy=NO)#<2H17|@0&xR_eCc-xUKrqc0r=Z)`Q zD%UyV@+s4A7x8&(`unYx;zP42=vN<+i_KD`eG$2oA-b2+g+Kxd&4tVp6YLhWt3X_j z(QV(1?k7xl%))fX6sF6o?Y(nX!Y4ZAhP71l%sx+~Z(+UcTuPrq>~8%VUVWYxRN8x& zNPUDqZSTZ>v;Z3h75m3jbP%R&PXj9Rb{JH<@}WQtfMuSY0M;(tE^C1*6--1MYu{S} zs`{dL@m1FXkTJ@a(mbi6kG1}{-jAiepvy4y$@Jfkm5Bz+W$&Hkv>a11-&Y(F`4%mA zv=-;BJ*OyMQzZ_(OF3UXrzk(UbhfADeEs)XwD**H{3t8HW1A~9qyx<94sKxVlqwzI zge_&$N$9vr*`+rrV*=#)^_s~5U-t050#{kP-r$!?=XtXWEoJR`?OPsv!^3}f%bV{v z)4raz3u(AnGQo1n!RZMNFho`)9rqz z&Y{1A_U?DyD)nRzResi=vh%xEPe?+xwLb^hN?AK?j-y<7&MU;2?5u(bilG_E{$i?R zrgGACqLH=p7|i@GW2g2YJ3ZBxtoMYhojav)8?hK>vK!Z|i=BSmQGFR$W>d#g{caC; zSdx|;q)M;3a{&i|QX`D%heJv|{)KM@RNyCl%A#|PCKW{j`xfeEgQ4`Q3P*6%8$SBc z$Wccgz9-6pk-3EXIEs9hfurbFLQB}^gB-O-9M#M~DX8GSS_d$f7H~8ud|(ENUuD;P zs-}+C2XSg8DJ~1yHTO{5$gWxAsdufNr>f+P1LDHuQop#c&gBhpq0Tj>9oC&ojQ-?| zwa!g8JLl;&K}6_W$Xi(J+`HG_xzPe6j2uANR33~=7KV|lD5xeB)yu~CjSz~pE^7K; zO2x~9RNONt72obXlbFA;>LmGyMV}J$pZT|MJ@}%}zVk(Iumsn2qHIV-%lT>o-}1mh zTu-f};+`lKE9R6`9LAih6pN~ebc}GhqNG$2cbH$E$rvVVCTHB;FBf<2f`=^S-SBM2 zK`s(Qzk0#=!)eP}J`oMfehcHZG60Hp@n$6wFSd@dFtR=RSJ)Q15rT0uqczN&(B8L7 z@yPJl4rWk8xybve<2bFI&KrgQiU zGRfgaxVYd>UZu|oC|4xpe`oP==~${Ut&+e;OD&j&@|^hu&kZ)rwPJBtSIqH=mf4Y= z_#nOTN~Je7gCjv8q6_dq;M(D&X!&xbyCB?O|M@v0ODVs?tnl_qPVk)TLP6 zpDJe6{V5UsX045=`%_A9q3E&?$L>#|()YfI?w>G7r^+1oq1#TfL66rFz#2}Cmx`ld z@ZZrl_;0lG3%Ymr9sKZ8D?hLM!#-mC%7Y@VUiV-7-v6wX&vyT&6I9Qa_GYjDUktDnJa z^^n~V3G@w1Q;zA26ZcF^--oRpGks;lh^~>Z$eTvCdbw)c3|8`d=?L>+H;mq`HKVtl zE8-OO#WP!=`|5gVKKr9T-&6p3eToU`pEd>18B_q9-6rlvadKl@^;_~#pKV$KSjn7^coI`3moi;(&leprU1 z$xCNj*o)GO0alk*6E3aVCaq|x2DwM)Qa!~ks-Q!Gjf|40LSji&k)2$k>dPxb3q=92 z?B70^nUD{|FEFDI1oQrnJAT(EVOeD!3HCp(47R~+u=jzDY#o7WHlqpbgX>2%D;0w< z&pWC=vNFu;K=qizeCQKrf@YO-`Bxj6IHV~F$i-&^^GgT zybe@PILxOSFt62aAmnHeY-WOD#=lq@>~)}e(!oCV$#tWeT~LECo2fTd{OQUtuLIRc zD{*y}(w2N?K-J%R(~6p99jKmh zn2$7s-da&TH4N-P)eo)=_Bv2K8z|)7b)$NE7|fV%;=~75hIt*R-rz8wIwM(a^R9kv z9>6}iGT7@t^_+u!xS`G0MAc!kG}Hq5@X9c+1J!u@#fis0RVRWx;qT)AVB_dWw6(Q>P-&zq4f(8HenB< zI&k8vR)%>UsNNi4Zm9CLQuW4RVB_|e+$h|cQ5F$ng zQ5`t(1!o1-=Q+&x{ll3Ekj=}0efrRf+I$^UeZGTzx}=y}!|q7vj0etr%t24yu`%x5%xyl@$?Z(JGdb)fpE9PIt;r|NCPVD7rYdDV(A*ZjY7 z{02YpzGC}6Wrs8mBK}0J^WplFcdPU#mj2(L&X@E5suEW9R0(T*s)V~P{#!e(6u)H6 z{~Nqubr-O?9({?gWJ*HN8!q6yTHYJw0oKma}?(@L|Pnpb5Q>6;(x*jtk(9+W@1UT z|4=8;xc;MV#kP)>3sgGi{kmIi)l!FivLlrjNI1`)BvzZb&Q^C5`x+_^G3!|I*Ecz`xukMV z94L-{+l*Ke{S^z|+^hW^pxjGf*%GVrLz=tqCN(!`p#VC&`-@-p%0KiLYfhEl7drEB zReLZchSdHkt9=kL5CmgX{JU4HCDMCU?Qn`96Y^tD5%2lRxuA$aw9;{{7~lO?YhE4S zB@DNVSKS;i%)`;B&^aWJHFMnc@Gw-A=HW2rz%X7ba||VD&f*~Vx>NMOI0D4Vl=M;b zMNZLo`#Z~1^g~8-`7j33KBG&dK*x$N-(tPq>dlFz0s{$ve+&@3!e0{Et4REJ^l%ut zw3HY_=>C?s4Cg9_UxR(2S6J{Fog%W5tC&Feh&<2WE#; z#@oF_1M}%HFrV?yG%(AcYi=02eDzR~qKe|GsS;)JmnvzyDnU72l5pUzhd{9(NUEe= zeDJh^x06fjIXjF{C6)4MOP7@RYD<-b;6jY&!*Lsf@*3=Y)w|z$<2Ua6>-Rocy9XNR z8k8G|WAz{66=!_lHUmQ4KPhVA_nVF+vBqd|d~$?1ruKR2xF^*0s8_GLLQjT}_#2JH z2iY1D-w1NPdwm$#cJXr>#&+?M+pR!0&h7VMSZHl(n*%-?w^EmrJ8*GW45K1PC|L`LDvhFvOOcrnPB3p`(w3@6?GFfaF0E5zPN++yM5iFVz zq_OwT54`8EX0#i15H}p%H$}#;&%Y}`GF^O(W})H%Z8>x4>~ub3(MUs#=~?OF+2Vb7 zhI(d;MGfd|@zuYwk}j7rboJ6Jy@-SQO#KWSi4B*|&gL76{Tqgl=-j2V8}hm0jei|l zn=5{0_&{_oot?|Oqe)|4T428TR;*~=t??lk-6)B^(J{Jl@11x3y;2kmLFgt)>rKVU zcL&fmxe^${Nt-X7-IQ-G9+df64ARJ!OJ_IdTZ%i5hKjau;p)fSUfEes6q_!FyWQ9Fisj=OL~eGrvk*S+-bzx?(aKmTSnE-dLjR7{HFG{?pIJ$}o6Jgh=IR1fi6 zVB$Zh-;X+FoYHjw`97{2*dWJMS@UtOb0*IpQdz_hCxfIpDpZ*W3NUr2en0C}d_>ow zX42F&Yd)lcpqCGFodeeODhvJK0FpFk;P&%d&;ZAcq{S<};w4=N3-uAqtG#vm^t1{> zB@c0(v+DMs$|9C6M=0*K`zTb+q#{d;+g)Cq&~?D_aeY+7@-f}VezUKbtxNQ`UdRU2 zRGzZK{1%MCP5M3I677(#12Wi=+C&EXQcIZkbDfXVVU@+^uAvNX!XHrwIC(BV|Ln5= z*;TF2>Z|mbRh?JyIacl!wHm7}1*-9>RP$c1aZgp_?!Fp#av!6A7pao%SD23_ka9d? z{@{3&k43(t@4Bj0@L}jW8-N-FM(F8YlBX__6%zJ_tFgw|O@$dy=4M4=Ri?>e&3vhs z*UgdDl-Et1Zms@$JvCDXMYFQGHmcoG_1E98!&5J>!Sjx7qDW zrcuo#m5qQQVw?Bu_U$pu` z9MA5MgE8Bq+zwY2mJiG7vaTAuKntX*oBH~~a?mdDuSb$kpc#fU&~_u9jTI#Yf4TjB!>xL^89;td^RDb0NwC@uw3W+wUa)7=Gd@ zlbJ2&2>S#=sxg{1xwKgfy}M*+2oGM~?IPnT>Ty8`V&D@2KEns$(@hTXYI%#Wz+{Hp zZsF^VVc1DQw~Syuvq4Y0555#hq>R43Rx$poOnpo_k-6#Vx<(H?I}CKtNnIap*9Gu( zN8H>L(<8^-l}0(z14BPda4#TN9lwMhCNuLw4?%s&OjlRL$t5#$8leNEK1sVD)=9-a zLl!qjrch zTecl)5A85%K7;-c8@6ma)E?TIIiq$6=32HLY7gy9!v@*1@;a(3^7=dmRtB46>*{w; zU5Asg1NMFDLYmhl)hZ1O1X2)9M1>_YQ|Cw^5zD24N@kSD)5Y1ukii(G zP}u4-Y&f)nGidb5CqBgJL#_N;&B~i_Q}?$^?cw^x6iahVkRq1;PgEvjFD7<0yTMMg zvM1G;5O$T!jQ?o6H-7fIM}$@~Gd84qXVYM3T?JNJa*Lf4({#x2(`v)X(m(9<>(~VA zU?((v(C^hC63~^*kO(kPE9*gaE?ng2Y>(Qz+_mo&;^KmEDp5$=c~i%dgl~1ar_;P; z+KDqQFH^mTVgjA%dw$9$Y*l{#!3kT^Q?k8Yo2Emp${d7Y_Ix8{OOehlQQui7dAGiQ zd3#keHdDq9kk8!&$upafD2*1QQcd7uBJa`^v;?9tn|E2NJfqZB75eGh<4(5uVs37?x7eq+dKDA z3{L(k7{WAgMP`S62YfY@4Jhs5Y+i5A=7egmK}`4yeEj97GBIRi#|krqrF8P6s4vy? z77}#i9AUY+VQp@S?vT5Mn$R71&2&}G6006Ssq$=`bqXFiX$*o&vZ$Oi3IWxm(cDIT zlg4@nZ2CA7qka55IESpNGU}N#rPbhO%55~GsyIXH>3*r4Qnt$}Wl1JBuT*b*UK#YJ z#7Cb%krh}lo*Heec3#QeW0B2j=9Q<;(Y$gU?W}8FxsG<$HLqMpJ8Pa- z_7S+4{hZiBKFutRgw;(mS7ZKE)^Ih=tU7tFB-*f9XB~<)iKXF_(5gBUO{*C>rHCF- zZDy|yC^u%WL#^1V)pTHPI#SHm6<4+FfNZJ;6tPoISZmUV(F~fZK0&R3__63Z^VYN4 z_4?#>9bFek501KMVQ|z(&Ru*iyMM*Gti^`a*PN;$9zA8j9tl=R#l55FvNfZioXg56 zsOGX}6s&75`;wo}#yM;5zbR6I2)HuW`}*di{a@*j0VVVuy{Nd=)`T?Oz&NxSf-FR) z#-1@oOQz-N0oaNb@R^V`-=^wNpoRZpsL8QBqMG=o2$o2r9gBedZ&<=@sxGaHb@@%S~y^eZdJ#7!|sY>fTwIu@bzfmmOae=G-TM0E8{?6j8ki39VIX z5*>NvEM_M&M&^@2Q!<}yo+k4J2{(fIBxtvru5d_9a;{G7b+jz%?CJ^_8SM59;V~ve zBdOBAAV+Zm4cFu@M1$0G`8mJNL6l49oDSj|h7iC?DTy%MZKn4eN$XjxRO})hz%}7*+qzMAhGK+*PWd zwdcAu*{^>4m2XY;HW)|e7@9lsqGX}8+j?V0S1VY+ItjR++G%E|Vq@e{-_csMl(}Bn z)y1553YpPo&s0WrPp3B$&`*X5sq?x9H;3EIY()4P2~AEjY86%blGn`4I%`reN3$ly z3jk`v3|yTRp>U8&T-Y$k2;>+m@HnFhiB8liZQU=*)}}3|5jK|Akw0qi72mKv;xPy3j~aZ%FBteG zKdz4Q&1+f$zs%%$7Eajyc%3}^UN>ZN1ouHkCx3)$S|+n}z?s>%t%#5{vaMXgmBLzvZKrsvZk}*fV!yL%RsMk= zlSxVoj8~JCq?}XW?dsFIoP}xbECP{Qoy=}*1%*#fmZPtQnm}_wH-WX`TAQ6?GBFcHal^GGhBx_W!ud$F2A;i zI{Q8xTWLFM`*3K>cH(Rr+=;VE{tcctwqR)6kB8s;CX6xJ`Zihy=TA=~F_Sbz;$Mx` z=`U|F4>J?d4iPyv5A77Qad(bwFbVr&+Bg}^y!7}uw%%Ct8*_O_|8Fh&KQ_;*JvjiD zY17;Bc<>JE_L=Xqxu;q;Uu1JQK;hCL_cj8+?4caoeIQYsBG=d^4q zG3(wXV-<&8GOOJOP;GXxuft}S)qY(?G1=E_BeAjF5XN>WQo?9`;w4}PT4Yz!Vlk~V zqWi{+A+ho5R^x@gDh#3G`fXGL()hTFWinXg-#1dP?HB5?HPfkgAfLALTQv#?i> zVtZ1#Noj{DH4%;$_T{s7<)odYl&vy+xr$k0;VJIH>feMnayyd%WZ5|eUK=p1Q4WOJ z0iD4lp0S-RHXOtpS)((#Z!j4)6l}}ghAM>j4beQ>e z`nMM0--a+^%bJk6+?JQcAfGv%r<5qjovHE$iBs)=*(-?R(OM=~!)+lEmGZGMBId(BW0(QWek)N68PT)gjM9U-- z6PH@jfW??JU=fQ#( zOU<%EPKC%vxz<@~ib%Dsp@!aJTSEs?jIamu~Yy~}AvP<50-?3@EwB46>#rDTQ zSVUZgEB4TZE8F*G?^)!ZU9svEp4u)pD=X(TVRxLnG^X!mYw`F01^Oyzp6hxn1bM+>GT_K|E1b^BUr z8HuvyUdwG!^Ln3^UgzR^@AcL-_nM3?>UDdt*BYG(VlB0TYSaF~71TUYqBD|oJeRFK zB`qvyc!*?}XzgJL%-M^dH!Q>x4Ou6U%E{XU=bBc6FAK5k1OvzPA!~)qVk^!fWMv@5nuUW!^qob>%D@a?`zaZ8G_{Je#L6NcWVS`pjRMdZd(DGd z$!xKJXhUJ;Q?O!wdi1r9IRr4T|$|nRTz2% zp{5ptSjN;1Vp)MbO|=-svi9^MT+5BU+PYU4%R(aerC2VTWuQG}#=0b@MYc7GFk%tv z3-BZJ`<4$Yi$N=K zwEE0dk7Ny1dn9WaU!)Opfx*?_?v_3+TUdNzDO*;;eT`6i6AVRzRGA6&5i9PgidWPbLer{Qb)AG4 zM#N_XLDGR5oVcZNeA$|f<7K7}Uw)81!yZIqq{aksKw&D&?`q zT{$E{HiVr8%TD}9%nZt4xi#Y6LWchf_p5WdjKF;v4!B0#TfB3H`xWewI^F-5PF%e) z=8~wikHY52!gFrA!{}M1PApBf;3z}&*Bv$Hjb!B@&PrO^-D<9*#9c?B8CJ~XghAYl zbo@w4KraiGr-iDbq*<%)$3#xULT^n6S+_=-v>^71CeK6`4@hEBZJ#6-bgPuZeb|X| zIK+81-C|KL58!3cG@dErCu=j?)j4x5Vm^#`%BEc(@#yARZcb(!xS3q5`yIYKv#D7a zuF~FHO-yf}eeRZisK}EW0bbaboJLw&GlncIe_a^*aYoJAkLf(pZMUDFJ}>3Ju$YlI zLN~SIz5aiBIy#8~Y0k5x}{? z`>8L%Y68@f@Cs3pQ>@Y&YSbZfteP)AU(NtCGZfkvb>D5b$dDkKX&}qmMrNV80R&KrC(P#cx%DOYP;mcNgosU!lha0>*_#aE+Em=IAhQ zv9-yqIB2>FBX$J35Q67%Ok`;>cha9I%QeuT0T z_VEk~oGqiES!B4z#UeBNV}bp4A5)H@X`H%3{y^gppo;-*PB6rP_R*l(yXWc+sTM@z z49?`9r<|2SV<+J44hafg3+)l4Nc6FL_fjiK_ z1jc|CR)qy-F^vS9F6*^tD_-$aqC;*4bS5sz33FcP2Ribk!xw24{p+e>&f+ea#XLXM zilr^IMqaX+P!Nb<~A9`~Iu%77(TCvpqX*qi?O`^Y6E2G{36t z>_*+Dl{J#9K1lkAmbhCkQk4&?%FZMXaWuN)TVJw9qm2S_8v8sy>uj@J6>E5oT<^Ox z?YD|jlGkwsbWNM)yy)H~5T+~Ab-^T8IH3z?pKzCZ38AYi_jFEe;<7Y#(4=@ZE%9!+`vgFgM8+VCsY zf1jndl5Y&u|A5c`fY4gX|B$7(lN)wc;rX?tHiy^(;>=8i40IOK&Hi^65E#K56Oosj_0OKc^d zbcu4=kxv{n!91&TnXS(2VL=Hm z>8O(G;VmWa$)1-Uw0dlEmJQL(#hR6+UfL9mYkhvb7&Er6``So(ztcOjX`LMe<4hX2 zh8GuVmTqx^QTjJYjl9(TTTvKqb}}Okmj%7qM-S{epN;cK_i0$5^xnZwU%vwdzPIm^ zo&T*!7zJ_OaBGXs`WKXm#>>d2dox7E5 z_Ktu2$MeZ$CXR@94}R#Tt0O)fy64w7@F9nT487UwF1(BY2)#pp|A|ZO(<4{jvKj41 zfE>PbXUwNZuDRzb`}CP#9?>VQ6NVdq7(TdA z15Qt=Vrg_I5H4M0l+|cuCQvY!$DGz<{%%q0%XEi41^wZn1|qUJymBZo570?1UYG@A z!J#zRc#=PrG*(2DT6dN6!FH3#vPv4W=%f~9<$Nysyff5Eq)`3j|43G{o-5-XfIOcSW=EtzbFtREsK?WOa)SD>QXhz zoAag;T74S91I4WjcgJBZSLcXh89RYZo2GQdJ<=}?|IZEdVFs9okb_p@MiT1NwtWs!gie^{@#x6Re(x_o5nQo=%b^1E( z)}N&;d8`@JBo(=oS*}xyHRBL~*7sZjDcHb-=iX6vp=TvSCybvdDe z6QJ(Y8Sx_yzI<^0D@df&Ms&udM`YntX4CBOUcFS zRQDgA#mNpgOk&PB(5W{4On8`xRti+M%cAo6E{m{Obie@zWPn%GsZM$563zxH-PsCT9!dW4&zOS#U)m4J+D^Xbk!pLl;v1P`sZO7ml(L_#yQfk zgjwU9to9}@xx_>xj%2tGn!}E1WkHvVwY97=R)aYG#&6azeM;zEo=` zgsE6tB)4CzNx=BNBlUbEQqx8RBDOeT`eU~kAE;6?$wtZA1R17eVaRo4Mc>9Dhj)K3 z{OwT`L*CX$5X=;!#&M7rV{}LD_2@&{*N*96eUNIHMP&5AP4M<^g3BoZ_HL5RDGIz7 zo;c>>M@dI|5`_>*Big7LjcOMcI}Eftl4FC<_o2VN=TCMx(z6BA|8-Kk*Y_x#MV1Mx3@tQ*M^`FPrl?-5cbZD=K|>&o(z4sH}3ccF?P1Keqc47J#& zBB2&v*48Ob082d;G!zy*X`>KljjA}KU4cQFh#EW*SP4i-`FvFZQU`u%eVxTln082Ela z0StUGe;Y=D@ldlg2F;gy5@_`WY`N=hN8Aq~0>EUM#HyhtI2OtJsW_~cBSl)eBUQsjssLRKN6^plSfTc0Gkqs zxdO;jSz?ma^k|Y58a`J5Taul9Z)Vn_RRyr631g%Js406;0kqYbG(VZ9Fs}l-z;g%Y zP_F$%DbR9FO`3-kM&QtsfD}l%&Ih`L7BomHa2DXRo(K4J6SB3HSX*?fXrZqQ=2av0 z)dKR`WPPst*24WwJoUdhNfWwVdAo5C>4(N=Y5kVC>g4yhT1^uqsJPbUSfEM#(p zTyphs-SS!xhJo#%*r_e#T;ZF*R(xFe7Cite19o-dVpqqO-0FFl9fGgYVH`H?8 za0yPsWamc=;pFfzorRDP%jJV?SbJTHMhSntjw)GbiMdC#{5rXSh!xb51`YW<9qrnq zW&b;D*{{uQgGqHL(_l3cT$mI@E+t|K=xO+736+|RO^&9j!QrmQw4U?I@Es<`%4VN6 z8+g9vFg^jqMFh(B?4!(XXUUnemr#>;5-QbX{JHcP-lJ~K=u4U~F0{Z;o}4S%oZi`)3izNg(*w^RDQw^?4Mquz}_z3Abu zzUSZ-SDY^ko;ZC5`hSIOT(A|EsH(t%G>afAEC%?@1FO^j&g7qgvKG@l{iz)9X`j)-p^IuRe z)UO{tyg%>IPx>9YZs#Z7fAO6c?fq-@rzRsX+4Zz`lQuo|v}#j^n4-6IM{;3Oi#obX zilqL=E^W=E6T*O!coR^tO@J8n@JqPjdm&LfMfV)2dOt&pFzbTq?f2`<4%bHWeIv=P zM^iRh*@d6Dv*^)%U&(vqhf_mT8qR8u))9%u^@zSf5!Jq>WBZm4_03NaMc<~dv;%9a z)6V;brKi$2DeT3Vo#{;`8$s^O8@dx3FCa^KE%ok4cUniaRlmsIO^)cD^;572L^>jr zVq+d4TN%wqk?lja>(7p7m@;9H-SHItLn6?>>|Cmdw~Yu;+wttvzioMj7=@rz!D@s2US_nzQ=?cc!%S`PtoIDmyOQ{b7ESFPeOBzr7X~9u=r8 zu@@+8abl2@H2?rX2KORs2H?qQ~A^uu~@aY43DwILJZi+tadl$iJx$Iho6=L z15zKAsx7(HBeGintn>N_Pb95kmY>L`kXsXyV>0ydaaGC<0L5Mq4JcjxnUKI#pCOX{ zzxkR(0H}$xz6Xv5u-E{@Kml1gk zqe>=N^Mvq`MO;74b#pj#3>2^sjNjJ$U|MT~)~wy(><-P2el&zok1fZ-W;d302X3urmO&?nEbuG_Oe>`iwE_)zOVlddH_Bl{(q+1 zXsrywS9jQ=(CAdOZoE~9LX=^4J}k&JyD#AXcc1m_S;;>RIGBCG(pM)Jc*izovJgR^ zeag~TCYKL5uw85EN%FA)2ea*#{_Nz(0}f-4{Hrj!I@#~?yUGvw#H|h(?V~W~sk=Db z7@74Q#+U=A`G!x36L| znhu0u99ZSvG$orb`njpG8b3$1+NYMZSipJpkQ{Fd;-yj%x_4epMvy(4r0Iq@?|kim zFX`4nC5KbFe}Xu_UNfK5Nh!D~svg6>3LTGDY$51204B3%O4XRm9=;V>sDYOsR^L5v zl6g)V5j-X}OiL?Mu6Wn-Ob1p*z>4E63Y=JU_S+6t$VE6o?c~RYhS8F&aFuQOC7A$_ zt1KTK*ib!S3;GtHPH@oPy)d+f27`J4W?a!m;TM=q?OPuoI9P^xwS#$;TS_7#Dqyen zU?&CG=HZL4a0P7CIwAQp3xf@k{SXd-Js#B`#^BmZ}yk#-;e6*-;InzMMrFna;AV_}$=fNEICgx)bxHRs-j z!S<+rbnfw>>b3*>k);a|&ee^D`Ov~JF9Fq44(2@-@;F*q%~8H#use>bKesU0OQ7my z4(wguS~67=FliWOFZ8Zl80ICQdbuZ$ua;pxT2ylaau{q+)ms+^dkLss;lMtybX0SK zau{YmmH+s23v%KTP@OoK_a2h~A#}?y*k114wJ_LAK=pAB?0w%XQ^--tY7UDI!|XZn zx`kn00;*R!n0Fi#Rdd>O80_ab0kVBzu$O@9XE?C8e|^cQ=B(;4%$_`c_SwgSs#iIf z=PEECtpMSm>oC}C+eokemj%Jr77=R?tv*(>zR+)?or-msIQz>x?Nkgd?}}yiGe<46 zi*s43g!MIRMD0?j65f)0nT^e=bS_IvDYX0YGTW9|fo!Dxwb$U$tda?OF-Nn?$FzQ* zo=2Jz-gR8xA){j8YHdnx$jy|a%mZ#&YGzt!VoKIat#|!;{N`^PKP00!f3;`x6^2o} zzZc$aIko%CZreJ3es!CrXyc7MYx&vxGnV{rzjQ`4Qp@ggdHji4IdA(s>@{XD5OLSC zoh}b6?w-uwhk&lI;>cWO>&4`4|A3tmE8d{BOlAWm-mad=K+&sJ${YBhP8zDN+>K0F z0R=FNkKky#JgnEZm>-2c_-#gkjw78+x)=V~Iy^%PwaPet@}`XGQcnoz>n;F7_tx6f zyJ`F1|Ko=~^S7USu5As=mcZ%N)5wW=*g)y?2-}-~9=wuIY&$qxggL&Sk+ZWldsdG& z?#P+(78(_`eYYD&VHhLW- zdS}t%cYKRix+JxDuW#`V2iN>9zTa9rZB&bL84?wq%&(_H4FOary7W{ix+Kp!emsSV zE}=rvrKdverIGu^ zNimWBCtRkKN0GH?|H1uMZZz%NhITFck;@}&=A{2lmn2NF6+3$XXWbEU;!+I_Sv+G< zU23w;iR^D1B9l>g#NKHVNo4VF4v}j8Puwuw?ow1UzBaSz$hQB(Y9HyeB=0rMzCzOb zzhT`Mk|d&pq|bfbl7yr`cR1SWQiP*FcJkpnU$Z=t4}a!}_bQhnDDR=78o&F#YMBJ) zJQLUV1SfiuZNBukADnd=o3HI{Xcr9E3aVm5ZykM}4cG+x=})!4@}lfw&5*?=*i3(S zp82pif5Ze)?AlkJPb;M_CO?$luP7-!ml{4$n}5$OkGk>H+jCoN%#DwVu(DOjhX?k= zZnN}fBs&K7(7x%@?{#}|#v$1QmbfhWtV{eu-YfflgG0a3M(Jd=ZsdF{UDPU0Yc(_OpU)TyM5dsNvkr!MZf^>x)UcSWpygtMoEu!9Ck zp8rwGGlBXQ0GZ_ql&fy8CQouZtKp9k9=!7goPC#FLgvaJV+t)SlJcm@O3({^2!`g))FODP@-X;f+PFm%6mxvM**qz#sR0EIQR@7967Hxds<_wh(m-{wKu_=2o&%LR+^a`@1Ik0m0eg~uBoa+WA{s}EgHR%27zKkD;X z(0!WGJoi7%XimsH&1h9=eGH7YXVNCKXyf32<}k@@mQPKM{)HlP&_pZ1wZRTFc^?8P zY}eaa8Kss^i#xYoJF6&<1%L2c8br*zVwG|J%Li7+jnCKOO>?D+n4^NcVLPFU`(9BS zKAzO3(-B<-&ef5!p(+OeLyx6C4_K+HsSfj?uYcD64CX~1`qICrG>D6p6ICiV1a2z^$N9AZ1^{YVhWdtvrl>;hiB*CW&a_x1U|nzu zo=1SyJw^+!G(C3lQUdRomo7&Sl-%;QqRJKS`BossLZ?th%I&$e+0gp!2}44$J{p7$ zu|6zA`|l7q1LJqF%qy948lV zEz=40;*^2ms$6IXQwK)Xl4~iYiu(7y_G=T;g}!8H7Cn}!WUO}a*oom`TrOF$LXrsO z72WDsrnx6T^HJ{y)t+OSH=kN+&+vd9!@T*)WpPB%sp9Oz_HxKfoix+wFeVfN|Ks+| zA0{CkdQYy?u@7m>Df1OSt2+|X9AH&0&b7FMT$aLFE*Y-eXJ#wSPt+P`@E*ILXX+%3 zjO{d(ALlyFwK~m@n$*TeBy*VROFrh#b|Fe=s6`CXxreX$SC%$9B}EGBgx=i8zVu=X zl1B_C)iE8t0wULziuLA|RK(k>-Op?IImD(aAp|+Xb*IkML>v46sr2i*VfI`87o43c zw1Q+9$Ie^`vVh3tESk{Uipb@B890;SPD)v;=K=!~k#Ge}A3K0VY0)vtNDDc&KC0fMxBH_XH$1dV^T|}+@akmA)kG5jT^-nkaLA? zJiYA*CFg!Q^rK^xwQKF*kNRJZM<4(Rn1DnFdl*vzn&NaN4}M0y7(E#Yd6>Lf(^#Cg zI0Z*-8VRz#k-!64!tqPIK059=qk7Mq(@E_E%HMF)6yqGEN1i#BD6hxkaQ1+0{!VCZ z+HQ->yh=zP&Kyb*xn2qArl%5>X$02x^#Rx#G9%>^#4}b54kZ%-+0+Tfe{aL+l>;f@~Ot|NCTS96KQu!uFZ}p{*Oli_X zT}Z8>P)BFu*bU6%h*6{40;QqR=O9R)>(A*p@`Y`N5v%h<733!GBo2i~&RCQ}W?;%# zJ*u}Jt4TFy>@{rK{>>NV@QP4%)QxvdH*kh^EiJed7Fz^p^USg z`U%9fWV`mE4~1j{)ylQQPDJu~RR{c%!XF&Dev=dPj1y_ULT6M&@xGD(iCk3Zx97heo1s1}5cLsTch^-Uo2`M{;EH1uk?!?vw%eu=+tf`r9 z>*czkL@k}B$VB{ZP#TbOlvxHnOPf}j=2~brrpMp~4pD4max^83C5E+r#CFne({1Z$ zk;&0I$x2`|I5gGdVEgswa3)S|7MYxiJ)$Pbe}`J6S)~z0V`YAFL)!l6%6fxCwk`fW zGe1baD=IE^awNBXOEGDST$8SociBE9tWBxIr&}X^1TE|ZKKK)D#hSdX9L4o2hw`O~ zopTj&5mrn;EhHxsr8~=3vwQGjbddn`vPRaN3?NgPu}^CaQ=_I3{T%@{d zZ|Y3(NXQYM?7*)b(CsWI@$zU>X9d5%CVxW3xJq(R7 z2dwf>FqLODmF%$jhI7e|daZRqxg+eZ)bFmaAYk5hn)q5dBu8jFIw^RRGMP?QyT&zN z9%pkuR5m#GyXkRuZu<%ypyojNT*R{~o2^C}7O=h{5M2j4agEiaFUjdjo! zF2A)l`8WNXE1DFU#Od>sx62e@Xzjsx6SYO9KX%X2D}EO`x2sC+g*9 zkkB3_Oso~*{`tPjwyTo1c_`9s$)PlhPN&kQC+-WWU|O|6KgqA&EjU-D&+tU_tn`^4 z6|2){`=?rZynkAgKF2??rcsn~Dt)d)9#1DYyzDCdbeaeaK|sf;xZvbcYg-?V!Q z1I_P=r!dgzAEoR3$il2I2-m$>#TLVFKNIZHM$yYSexs4&PK^(!F(mGO{h}%xFoqtX zV2{O}Fm$BLlI{M@_S1A zXgyGwETQGS%5t1#HCpYgl*UUv`%O?-B!lu)r%!VsmGQfmi?hg0{*{^*S0Xu4i=*+n0O&ga>dosimHYdCc({qx`? zu=G5KPSXuzTR%N-q-O7`N{KSFHr7bRL*iTl!Wmg+r3Nrv z%NW?TV1TMQg#PW!m)h2~;l^6IwkoY&QG^LW3Ask??4Ebt!aV+>?EWkGE!^F-o!~=k z(*QBvIYdv@k@^_s=u%s;yX(+&CDwGV`}ScpzWU3`@~UYZjzZxmwl<4prQ+O-L=K=p zQ`R{#S$SDmAI3J$qIKhsV~F^@;9dgPWir%)y8w$qEspbRgv5mKRIn-FJ&8MQlcZFiD*7)Uit3v^~u z3cmr18tlW6G^EHe4)i`&#H0q;=h1X@^J&835Yd}SahQ<|G@>wZySTbVHFpCvD*6f)D>w;G4 z5oyH%IxOM}=u^ZMeiU&fg)vIY6p%@W4ILBLf)6p!lCU9MP?I6`2}cL&IUTdHb?cr| z7t5H^*bb<(3LRFUL~A1IkwU|h*|c(O_1837UCE<3cg$`7-LgiA(N!Ee*}u?Y7pB+P zGiktJqouGQ&o60!9?d*?!xpD7uw;Funa4;+sS`-k(W?Y(WeF2!+gRu|+|iS4&4}*@ zDQs1+#(Bpz(xl?`(Q9SpcgkQ4A}- z6_h`W63%K(W^qEz9hXjZ+VMs(&}Q-F?zeGxC10}5)G;?q01HY5^I6@AY*6jEAxKx4dPBp@N)(1sV1UBX=!Whydb@sm z^?%xITNme9H!OrQJ8qN>2Rw7~A!kVwLHSt0DrQnyY2#sQ&{W7P^M(^w zE7O1t3=qB2meIzq;#QD@85i`i0x;G@XnCq(Jd=kU)res1@}F50g=+OwNiS`LN9Y<7 z{T*;B;z%Aa1Wjb;5=l{5GiXe(Fz1f6$i~^O+^ETTJ)^hnqhGo#+H8-zcI^69wAqH| z>f7!Nis9)pVA|a(5=zHBwkSYvq4(y8KOWWvjPs}7SYsDZaez;>lOx$2Ce_GKMP|8` zeQHMQZS=+eWt10*)6mvuy0&~d&Bvl+#kj5)=tJ5K*K|w?a#~v*bdY?qvEMKUNaLbF zgJAG1M{8uZJtb4sQQ8UZi{!O!F$NR$Du6&)Ua=t5@g@Uu2KdY_G2?gf3}~C2N#~bR zny+nDMzkR1rxVCS%a}a+cVa2Fzt~fAz@}Y-9tG}sx=YYcB!MkcxJ2Tdu5AhsT3?#r zgw|R_Aaku)#!)Ju0*9J3VJTn=;G$O!LZ6R5rYgp+954}rN!w<#HS9VQJi(Z$4gJd* zfvLS_`eAIeI)cUK2o(T%!QV?RQ3Dd8y$^$GBMey82@=RDpY~P5PA0 z_l!4ea`xXSd-UxVa~3O_?smXtkv+Q2QgmpXaYOPYpNB#jdkKU{K$v}*r+j$X!eCLA zy;a$4u=7VYG>f*O07lt%wWYYBke7gwCI!I5%syDyz3$gxaMj6m5#4po&1N}MszT4blc7{ z6;hixbsd!w56vY|SN_y0o&eIH61SFVVtt%id96g#R0+`;c})&{XYNxQROynORnU_1 zPC7fIC2>64kh8%vxzYZsgwJ?b*4TExBW0xLN8b5$kolr)%SZUl<>aN!xrcbnI;?>f8rY(!m@9kw(k zDXmqn?XaINk;%m*+zSw8-;Ot7CFbEf@g~fRS#r*s(3aWVwb#xRcUM|&N;DQM!60|1 ztYJj~1sH1Vw6fT$XlNBQzCm)Ucpq*csMbeEUPyh~<+$Iz(HE|d)iy{hg2pgxEz0=K zgpnPwjw|H*_*RD+Sri8Aw8|1KhXbIwC{9hf>inHtxQ&48DY1gB@G1c`r!W~R-Hp;z z%3XKv76gaBj9{i{6_chK6O0^klv2iTcbPXWvvyh^uRb+q9&wE0#h-5aM1Q(TngXL1 zIaYN0dhGn1$%@dE+#kM7~`}F3l*9;L?#K2vKN{}$6@Yip0LY1LN z&1E{$)f)$eUj|scCIG#P%wo8eKI#!-q@GUR&`U35Hg8!?H*8VXShSEcBVUU1sD(Gp zvVIypxorYj3R*O$V2n9ggjiCpk>qxyx3U-_yM@(N5wBId0Kj2(x|OH0;R5^ZPTpy^+{o;xfTj9ZS%Be?1KHynxW7_jwJ&jKo)T<}mfBeBOFTGFiAUWx)XgZlyQYkU*OR!fzwhdI?QX3n5iJkM5_(-M1j4!c!o)UX2B~JDw zJ~2;;+bbnb^CjlyDZzcSrGA|5OYEPg#J%ntV{w8Xi-YszK3u8)_P{rA|2#z=t`ymq z7dbLdky(pcpL50jyvU>T6uG!kDcd6AFIQ^W=B&%1vpFS2)@BKs<>+@BY@eRL6%Q$t8O6@9soVNAqGc&!AIJ+_3D zXzMUDg+t};ielXnnipn`1y)oM@o6X|6a~n9qf6>zizOt^w(Pq6B8q$GZ|%*#^=(_W zZQnIFd;SITd5KMRLHiH>E2Z(5WKOd6G8Y6%tk3>WjKUJ^3XT(Nl4G|;zCitIy5%=& zF;}7D^H$1HM2Y90m)2>NTG>SS8|;K{dA(gP(#XvIF7O)|lt&EklsT%%+Z4R`E`pzM z(+$0u&DXwu2vLR;n;Q%#qb7y+e`X@drx9=!*<4MW9rRi$%Te;vi23XgnW9l2~+Le|SR76O8q2{%!jDBqw+_uLA7v3C4GDpRL@*{1mUW^nQALM;j8 zz4J)?2BM-zGAZPB+G0U$-D zG%1+Ium2*l5QW&=59cA0V+H%N#}e#+%L&`SKBBiVwB1FZfZdW{8XBet{*wu_d`SAg zR&sd@eT^khqp2n&lfr%uH-ubRw|t_}AX}qRYmm*mHpv49qmbjFzvR)}okQp5WI|3k zv_;|>U5_&~pjAhy4orV;pH-d!z7B2Tur4vuQ7y6{Op6C>$YlaD6N7SFVrUhbQ09FI z2ZLRbt)v^mD~s(ITO71#4qTO)w-r%nbl;qw>N@A@vEHGNR=Vf(%EA6oU`ZWB zi#)0h&T0-C(ZOp>(Qq9^GaNa1PXBZrboE#VQ8FtX#NB1Y08(H{9o(bZk75K-IY)NT zDSfVksCy$jc(aF5LB{%QFRb4a%2ac66ZR&9e2f1?B^6y zH-fGn>mbT!WdxlHIoLr8EUAO2ibvJK-3I(H5AHY3&UFywZ)69Zj_Eq+>ah-@M^-vG z=c{5`DajZLEUAMBkFtY@#&mFtS!`SfXVD)>ve>u7fnP zoqOIL|1Dd_)Ua%s?%^qmbs2O`z52^#Q{>+P;K7us7=;9tkiXe?PS1NSkFK@@`#>bg zKS}ydpGVKGo(W~&Ef9RR3EubkY!hzuoSU`^Sm&@JYfQ~odvKyl1DoWqH%0N(R1Iym z41!*KPt+_s3Bi;BS#(5z`AJTXOme{#AeOoz_*OYU^k{X+i@ZF^v45XWa#djcBu987 z*8}1m4ff#oaH^({{b{=0W@y^&TDv+lll`F);x)Z`%ok%Lbm!Bwo;6JyX_Q7sn9rwa zJ-d2zwXk*$3nFXso=?-&!N{j+?SvVT`Kz6u)~1Y!2h>ENca*Y`57U!Jn_|HGn$+YZ zG&ng~o2=5H#ElmZqAzJcp1uki6iwxtl%AzYnIJ0BpolBir1b3SF;?GRQZyQT+Tmy1 zDz)XBl#p#S$W-|UASRsTD~XE5EmfX6H0V3nr^Cf{Q1mm3$#OarlZg&TX%jgeN}F)? zm^M+SL#@biI;^ToIUO!~O-4<73T1af>(Pmc+C-JfG$DE>69Y*L_Y71pnV2Tm=JkBg z^1whPCKLDM+Pt1!JtnNn+Pv1X2RxHi*@*(CP2i^Mn2fdT(@a*&wKXBj50h~CG?RgZ zCkK;xDbi=O#Yqt{$S5h2Gn%A`7;Tgk$rJX=^p?krbA>XXPUnU zny#M5bB}^Xma;!#aY#bv!;)|B4(?9`BQ|&k_a}682@n?8pYRg@P<4NT$!esdNBbe? zd#JH1|0nByuw2GF?Q^$US`=s+aSkLr60=wP2#M{x%cEdu2ib!8E2<~ooHvq6@gm0^ zxqo!zF%o)@5uEt6O(WNe++zgK2Q{hUb{t<>%w>w647*lXZaYSrH)dM^R^^Ub-qi@khl!l&TqXQogPPJ@P7yuOlwHPtN*^V;rwLj#%DwBvWV2s0VvMHmihp>t4^ zGngFILhp14^nC}lu@uZS~qom-@XT3B{albCgd$2h17C@)3jtezj$91x@Cq6W@J zP;Yy_q0Bwb!sLB^DCKb`G1~VyD~VBAj?Ci>yU{{S`80Bm61keA47rP#qn<|YQ6g9K zq#<|QJc+z9Rc2Yu_{B60r=;Yp_7oBjbjB%Z(1|8e6Aw0#4n>NnOfi2LWCeDZV9iSqU)$`%SrGj!b{y}d5c9UlBqyy{BOp5(en~?7TrGbr78dcyI!%*F zO_NDpd?1sWl1bw@p{diulq7_(6GMnp#UhZ^ibLO$OjLl7Bakw}%(ZCE)T|lZ8^(Fv z+Q>FY%}?KSn;hj`9|Q_@hD_5F2gwncdYVj|`jPN+A$Zd^VKsn+aJ`cX`=X>pG zEpdJob{GJg$mM1gZk;kNVplyOm>nl5A4|**webgm*>QsJvBd098-Ea(9jBo@mY5xC z;|~I}Jpf`4o_GuIv&4AaVM4>!vaC2ce2;F49)5Rz$nSk~!lD9)7IcX`G^ZYtgu&tCl z>yjr)-aU{^CED8DGmuP^I)a5SXHmB*NePHU^4vi3^rr4|lJ^ZH&ur?hAo;*R@@bp8 z3CZ|?=5_Nn>)+-uj_|t6zs{P8-g%n9tAE&Lph$4x4 zTj@leq)O(f8heJmYC)^+dUVS1$K9XY;SP6 z8(+N%y0cD=AP8bS@WDpevcZCGSnUlybwg@zbG+Gb+8Z42hSJ^;3vL+g4cXy_P;Y81 zJvG{;#vb8AK9WQN3)L(G}kG2Of;=$ujKA+7kqlqv@Kf|-wWC%gpl+D;A@eb;s6YnoQ2)rD3wl3b#jtSfyC~KRhj&rSO;wZ3G@#G zS;%q)aMkUTt+aMhkVr{4!cOf%5ot!HE5L~j?5jYO_Altx6^E`0y;PzT-S&2gF25bAAe4w!dfv35;ZHa8 zXwwE#jy5g_3lzmfL4i_aZ9{0Q>&`G$+*Le#DzZ8#{t}5V6`u>d{2D0V4FRAS<4|G2 z?NF8{f)Is(ggLi1pruf^_5@O&9F<6o;C-h5UX^gV*oyCk1XR2l-U}-7kkf!{rV^%v zHSKDoEjVMb(Q{9$G5}G&)QdLG|DQR;ET8aRE|WSO4k0L1qR=J0%HvM9-F90wk+RNw z@L~&h>sB-~mVy)BndU5KQ%R?uaU~A_G;V$h8C-KV{&LweS&S8Y+XZw~>vp>^m|P!l zo08BEik*d5iim##%eH~0NLjj&K=2+fc#qF99c0Jp{kZ=7gx)9oJMjm6f2@bya(~3If@iQMi703)E@WPM0>@0Re2GS%xs*SfIF z_SIOb=0eiiNV6|NQDtQ}H_CK7p;#-jiwlLZR>6{ra_2TRbnP&A$ha5i2$j)rY0SWA zd9t7`)s%}0_QGrZc%zGX-V%iq=VyWL_VFyU;_PlMQ|Nz**%oM(v}FsNAMVr1-W6$A ziMXP%;_m?mlMUP7+|Pv%WW0JE#Zd6?5&%Lbp0DH z+Yym-=!W6s&PuC=opAf!X$n(R?<#C-UYwxCYDK@nDX*EfaV-xKoXvF7Vg~BKp~xG# zY7`A_1gu5DVz$2I2*J6NubcMR{&k%lx8`OCY!(hto6Tw@Gf>e+eck>sluNl2XTzlF zqu$NV&RG!eY&b+O_Bfmg9iK(n?r-0wj8xRG***Es zLxRF4V?<=nPSo2GL7%=UJ8%)5a+o}{M~e7XYk`j^m#!ZR#F{fCPH)OXZ*$||?t2U& zlBM7!W&CvQ$t3^c8@Bdt_|4t-e`D*fcOMKkZ|$`%D!+FpxAs?#ZcW?N5wO~X=<~%U#9G`Y23Z!*H%-L4(x>ba6FMcMSMNkUlMYhgT1W=? zxUT0~w}E~ojzM#QKN+o5`ml1FvPZU>F=}&}?){7;8pv5?JjZd=(aaie$)YzeuMr3_ zmSiU7PQY&ZDs=0*0i2D&S%0SmtWFhkY0SL${jDjUWU+; zIBcp^F1B1}UF{~ngde1lh<90j7R1Xj!u@9wc%D+hr3nObQ zt2AU*$=A@D2DOHkcVCLV*xzoeWaOOmv>LaP^U3L^-6;DDW<7Y_{e9UQrSR7liKP9- z%eyhx#sFbJP~Vhix5Vh6Dt3YxSqZ|3_l_`gmt}ETHwHM=FJuE6FFogq6^My!bm&=CC|mxR^ih;Es)y=Qsh7N2Ps#1q2VQkqS|?vp>g4l=I{7^7Bx|B5d){Nx zNp$KbzLTXcmd8*e`xj7!$Q6qe#ObLu0!Ua#8g6zz;BI97=dRJha04Yl`plcC_MUv> zKKVjpXG58q@a<-xrlU}4w^SN=0*;J;p(qHL;dNK@IwIzc(vfC+8UDQ5;KmjcgSXnC zY>3(&0oOeNyUdkA83wGTtB%4&McjHoL)v|XM-jNoM{ySQ_J<&(4owrGi>M~@=1oyT9p{3GZv0EHTZ8Sgou#ZPE!F6w8DDjo-rlfp*juFJLn*VRr@ez}Jk1hi_FDS(z+ z+=f9528C9ep{)cp{}o06G7Pi=*fu{>y;gaC5l-PsE4E4}U({EG=~kf>gR*p!({|e* zsMVwMW4kyf)T-E+qa2++HDsXRV(nouCT$dSZZ+2g6yDHYlx_pEl^)CAqO6+tcHQ;4 zOaK0pS6(rBUbnVYC6cO&FOQ6&6$=`uY5Dvut$)(`6PatQl*)Ou6X@GK%VUU zH>1qYyrJMD*;{EP@Ku`rVHs?x40Rwbqc!cTYkf290q()7JEF1K+8MDbyxL!qS2&{q z7nN)@un^w5EW2|nY0hzJjnf6r>9+XD^4s&HBGLmV_AeNcvL+Ag-bHJ6#0_Yy!axJ$ zcDgp}oXJx6yGR;X0&*kFy<;rFEOy>A#u?7+8soAx0d+*6i!m#!{JM~aV5;+{+k^uo znkZE>Kej)s~*F+eNG*2P0*O~Gi+?Z4v22UXrB_D!4F2vjbNp~*mK;c zGob-B&s#m4hL%jtjol2_H4kQ7pHHUcAE#%N@Nep{?z1+kucTP zvXcz6kS9dVrRl*RRSA4bYn58|Le4BW7lS{O|G%Z(5`ZE}340@yqEWiN>C&(b)CauN z{Io^-d!* zg0I;8mMn;KSwO{RC@tx7G0m5G-8^?JvBc|m^+9gl`&X^dlBlxc6Ho~B@%nXB*p4&ms z)^1bW&eii{)D+YjSd3f5b>j|G%aD>HJAcUacX0bMoR>VeH~$8ugsQo}_yYJ|gNY!n z<=oyno6EFEa66aR2k9i-zTCK7_Zyo+&brNP6%cFeI4|yVUM$X=p7ZQ_^Mdo@l>2NqF#8(kaih9OG0x5xm&F+P zqgU~U@Y(;HuW85QmAuh)cQw2*oO*Dm;Grw(n59enGY9`fj(JAKxfq2hg7Q!2{4|4x0;l$E42N=q5onxhmGTzGp(bmB7-a|PzvU7Hfh zI%}5>LIxR58O#}BsvzDpX^UuPkhD3n3~H?Do~TiFqm;ZF$Qf+fzziN{=fA=c7M(4( zWm(B|QV`g7me%2+0c_jzl(7vfZPg&5oxVATqf}7s6b@qaht4!4h06_8I|I*Pa_V=c zArMEDvChB;zAKG>SA0iCbwleh5&ab3fx#Bg?t7HY6$JYJ zuzz!KT9WOcIi%tKO5HSAyOYOVfDXAz?>0%^m+kJI=KQkK-W_wr8amj}uh&Ccs#t|g z_gb}!4q|%c*&}SPQr92$TZk=){}k0Ei1n}U$LA$+Z}+FJyAx5&1X}B_aLP~S zhQu7Td@?AajKTD>Wtpc-^0_UDChmu=i27_U%P1i2DqdwI z0xH(Li26aWwq5n@uY@JA$jh}ToPveV*f?Mjp*v+;;!>MP5Fu{N+o$WQzEE0r4HtFo zu}eqCzwIr&lJN31?5oD-AlpPqxywQty-Y0o=1Av#hKqM=?ueL7+>OqvmrYqT z*ocYDj>P8L?7752Q&YBG-|S(45VxQS2zF_b?UzQ{4%QeNqz-Z&{iSxZ--b|er5YV5 zGIl_T$WhS#6Nw z@d4XI7UynavOTqI`HJMYmCso9%x69Oc!`_Vraz5>-mdNS&AokB9sYc99=&}w^mO2t zchdgUv)D}M=+y2XJ@jkg;aTn8_S`?3?UCWvw25iYt6*F%%`1EVjvaW#7*x++ zr%|Zca2hk6Ed)~ME`L6h3-e$Ld@oS%7?%p}b;#}hK|JSFv-CunF zpSw>um!$4r&Qk8r9ABZTKXWzx+?4Ixb;_H9nYTMEOq>A(F;v-+tEL&-+ z{tDO-8>Mv|ttOSiv{M~dbH@XutLiwLGkEEZ^FC=K&)Jjz z`s{&!*iXUTu(UKfJ9UuU$rrMp6wJt3Q!4O`@J&I6CGwQ|q1P;^7jP}$z%v_hE!4*heH zzCGTep)vp8yeJ5LmXwD;GXj58^V3DE62PZKC#Qi8&n~?5Udv~aUd_*=?&}5~asQhJ zX>-?qgAT@7^isBmNk$>%YVGSRaSbRr?m~w}J`u;}oqc3YIb^Xn@-(u9!7{Rvx9JEA zYd=n=<_dXQYkxB;Q=%*`K~9Ou`}&xzIn1)g0<%-lR+$W2(O5EEMOKZ{DK1v%LS#5y zkRfNLvg_|H$n8K*hAbws_w>^XGVBv@T2LXUv&2r0Bs~$r7e<70E3~>cB0Q5HPlPa- zh>$~JLqupc-aJg)aw2Hp=L)*^p6-Jko~kC-rmK zj*wh0&{ipEzS}9PitgG=Lo0#%D`iO#aN3Zv{^dDsy-v46Nn(L$T2pzcBJwiV(Drwu zC_)b#Qn~41+}r!{YYq*l+=ZIc2tqb8QRDz|#-{S!H~zeV63N0@lm70{)Ha{jJ9N<_ zKRD$)Q;PXwx{pjLJe#$+(0^;az0cm<+kWAl&tb>Xv__`|*HF%D^bXBkCnIugV%IOO znT?cFZ8IH}GczyI&@G87=)=mqh|jCRh?ZWJV?f zknP)Y+lCR4m1a3y;H8wBflE5dI?V*Z{P^AR-A^6`erNynXC?e@+ffIX27zSvn?6w4ZDogqgRth!pr03q z?+BrA7D{U=&x9?>XxfGSoF?jLqF(g|gzU+Bk#{m1+_Gxgo8U8h5p#IN@-_MV`vic2 zuv&r{@YW)j_*rM?)1r-fp31{oud=At>Vx!^@+M3!56o>sj)pZUh@&c*}Lz!%z zj4s6^C9+1Ij_yayF@NEw%g#K@pIX*LB_xY|)Aw=zDCgFvRt~B-CF1P6`j@1kv^!hm zpi0-1@7VZJ)5(I#fDweJWm9ipnM~KfrIDQzibJEO%&iVXg?X|IJ|b>MZD;%6di!jU z{YiG<0)CUPdi9PxpuiBIc_hrhv>_4{1RhVqh7FfZJcf)#V~Da##1Z2RK=4=CcK8iC zL9~&Zo}f2eAB2E-xa$#HgbbBw+#b`YGhVp zOgxhJ8Hk+s*Dap+Z$CQTU$+$AFLW@>1$43C{lg_^l;1<%za$>d`ye` zVI{an#iC#yBULG9rBTm9aM)I%fF<|ZP04M2o=*IHzRJz#YfJNaEuYU%%XvB&5|0dp z^!pL>d9hxFr|EDJ3*v#_Z=T*)8_(1G*xnoeuR`L?oAb=)-+t2Y^gwq9czS$ig@{Ur zhj@B>t)tob5wXh>nfizIa56Ww6O*CfY4j~qdAjIIQ*Z<)Ps99dztiWWP@3Ln+PJBj z&_4c_(gTY?q;;t?H5R#{Ifysuy{S=B=Q`*-w1dhw;Z#0LWO-)NtY!zKx)Y{Qv~rct zzRfH4We8$R!c;}z(ZL9sA<@!WZduT9Xrtwax_V$rv>Wtxm1iDTEF~+b;-b$S}b& zlfSMADyKpz$g5HSQwN{59#x#u=$uW6RB4B%CF5HoMb%t10!~(SXdYjUzFIq}j^pIv z`&d$I+eg#KN%e8ka5DjPb)Yy|@ash&;jAz0YE9jp1UU2e>Q4Az7$LaLW4Xwip);XP zV*oRylv)%LDUXRUp@oi2uIrtL=!BLCvOg8?2!D}_e{VS7G8`pf&me7C{lbF4&~Deu z!C**S?jX0BZyDr?u-k%M>4O6NZOeSUMD z`y(}uHxC(5m;$uE8BOH+G@8U?=ztCl&~}5QK5ZMNYusCdv<+87T%wYeb*Whz_XVWE zNZJ-GG>xh21s?NU6I}1oOK>kiN zM8MIMN2Ht5^+osd7u2o z?Z()~h9LnvnNIIZUH}3@1KKx8(KP%DY2Ma;K3{8}d>f#sVYX2g+uGF)jy8liCWo7& zoFmE$2gJ8Tewh7}HbshsX|!?l`E_-l0$@5XKnKkdot(;M4QSEHZ8Ix`(geT%QGu)# zuuR3FeUa=iFD{Z-K}R#vp(-ml9q^z9Fo*pm`@DlpHW>6u0hy*z@0Kq=c*S>jUU=Qd z&ez#(%Pht44wqTV;roOxSyZCljX%BU;jg~u;1ySp8F2VG1HEi;@M7Z7l6(a8KmSk; zy(T(AYo7P3;U?{Gs)%5J@M>ZTxPC);$=$Bc>SK!xsLOC-^2_UeU7!b}0VLc-?n2IT zmW!m@c%zg+zx#p$^atO*^W&F)?z

;|yl9p^?{cx{jFz*{=H1E&=|keM%=s_UR$( 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

2MOCCHC-*zzSy<{Xp0v~3!JVSERg)>Xro4wT zYSq+Z-_JJ<^_iX0Y3!HTDWM`u;Vk+nvo0YrCdly5>=dmwY%laykd;B9sn-j2wkx|+ zS$P3|lMiAn%?3QaBwv`G_#I?y+%!D*$A6~dwD#wd?5Mw&C3k)6AkU_~fF z)R+WLnFn!ELN?w1X$@>J6j^ZP0xb|T)qgl7^JqhlXc02Ua$wGd9CJow@_0JUjZqG= z&M!u@aov!RwH2R=#xFX4 zi@oWot_9fdSy@f=EGFK6`eB-?>J*FdfxrFHFLDO^%FXB(d1igpW%P^Oq>0w%#%hz# z($_7bGTP*TpIM$nUqP^McP?l_Pp-a1f4wS4!3)`q0PILdZ2RD751ubz14tuSmqVbX zC88MNmlvea@CYGDh}p_44VN^qnTA94BNQl6WedJkPsIP zbnH`wrLj-d_>6t3XlCqFMLF>&2^#>Zc-20Ru&SkvjCfqh^VydG@JMfTXm_*|&nLhE zsuA>$aO`t~#?bT#QH=2HvuHZhKSGZqOnb5VLnRg0T7eO!4V8qv1=D)YI?sljjCn1W z^X$iTbh%bS%Z8;S(>QI9!Gd^TH(g*$w z%^x?3%rMuHL=ts+~KwZ`<16vbZomH#;-b|9aE*Gc_D` zi+NGptRWH@W%13h`qJsXa%#EwgLZ+8*B-6f)WV(LcO!F*W^?%70;6xNaHRQ^mA*{EXdEn64cpOgaWpr{* zq@|+mLBgjroEYx-iQzUM2ZW*a?YWwyT0Gy8&NJ_^Pn6b);dc8FHHFQu`XCY=1w{MY zI5F%(BOp#vW5S8y6e!p=?atq*w*wWSw*$?mxcjxf>JpDiwk|Gt2wPXmzb7yXe&s)`|NCQqaxPihN#)fSXU`!Fgx^Qh#tGND^O*ZWYD^lA^|zq~rRzUkfyh;SNs{PFJMry6H?Q-= zrczcpbTt_btB<-~d%S~oC6k;8kL5V0hZ6((_1%%S; z5}WQJ1U2+cv=##mLe>7Jp+ ztx`xdjR3Z*{2Eqt0x`?i2{m`bR-n?IZbRF$Rca~ggOP$rxIH?QHj*k?xJ^T8_gULU z9$a4LzHKf~$>Ut)ga^{-&PKGPJZS_#RLLgF^YM4-86<|$+aQ7Mo=(4Qkm4v#`hTT0 zS!#M(JBa!6p6^Bjg%BHszOXw5m8EE`-_TP=$`>sxcZ*8}qRylCJFUG* zy4R(WO%N=P)MQ(RIl(aLe>}F175?%%qF>T}15(RE`gW1(jUY;+q}|%x+AZKr zEZ@1Xi$^1nNnH!YL+84!WY3;-k18;`!6yBtBW2y}Cb_tmR!kg>54EA>NZ4OBp<5zC z|Bo`pWwxM@(B_`@o;_iDGcMx$aa*Ek>1e?iK)8w*B}X8zoIeS(u47p1+d(nY19#e^ z12n>?1r3bg8RcZqy82@@zlqTl7!$E=@Cu}m8Tsmsj}DD`w)=4Z^FB4Uc1^@?sNj;M zfp^E`=4jF)XAEw=^Dve@RGYkce}MUVQXnTF1#2T3Od?CLL>GI zlDF^Tuz!o#OSW!pS%oOsz^6XZOoO#;f+NW2C&+RUeYpKYk2Z3n$P5ZHl;C>iVu1D7 zIKZN5zLg|3cBa2lddYsS*U&?+g@Dhkyj}!Y|%CpYln-Vi* zxPA>4W&oQM7;09XYf8Xq;n#H!C?nl-#vb7q1EP@sR*SV=Sfy6wAi*L%lN6JJci8R` zrWZO$$(NIF50e6`3qljEAUIS+4{CcH#bjoEbWA%w>xSoxhUX_VT%yoL)^{IXWCG2B znpXalriE^jXfhg!K^_|z$jH}4FO)TF-4C>^moT1soG_kzaY@f`=}2--uKO9~#%9$8 zvX|y!w>3LEo6M>Y-cqnlsyatTz0P<#TN!}W;{;$w@P-X7RcehMF!2&KdP9@E35^zG zZY>or&6RU>x$sPc$_3vgS56s6)ps1uSuE>X%OKXbK{(RK5EMj!Ws{U?RI$!?FBvB) z`}@uH%_fZoC#sE~X>P22d9~Y<&|DsO zt6=WIo025j&`=TMq$k7EVs9r_1`C(dHd$6Mi7LOAs(XvQUF6uctFwz7g^vyFYAS7$ zsGUmosVvDmNwx_H^Mfe2Ci0ehyU5;rX&R#K_9J_&I_wLT_IvjFt zP;+bksu~;u4>(%$2A<2d0G{Qx=}QR**NO{{);!<|YMy{d=x@NscHr2)y|cXzM>(ma z0}(!CAp=J;-}jmWZMqpuvWeajjx7Z~uv!cbJNh*Njy`bo`<;Frj$*3Enc^4@S*r#I z2VbIbag!7{=4<03Q_IGMV@ClFGY1;+u>c$k3mu%tan18I2&V1iQiKmRV{lMk1c#ea zY+nHvTN^+j-K_o?M(8&5>1 z?2d6bIA0R*VXGaD_+U4nN%=Y)lJHiuRZ+qrlf~emz6cJN%ybv$Zv=-FmW>O3zW|5% z+3IkJg9GnQ0n5}>NBa_@+TBi~c5AeRMU5IPwrE%Kj6}adZqCMXY$QkxmS9fT%<5(# zjZqc&S)Hj zSm<{08l*%LFa-#irc=={97+wr!nlby*+41O4W3tLTznNu~GzfNCOQ)2TpOTdwb%n>q&6z7&x3;CB zvc90OioX`o42z4M#kyt?6-t8!IbLc8S@zPnB^3q*AWPNr+gxF#)C{wQX0U*TMzz77 zr{oo?eL<;~F*{jWUh~kw{CsD=P6rxS*?mFQlysmuo9x7vCT)@Q(u~XVGs>(&msTzD zK;1$Jb1q8iv;=bOrAP;Ky_zpfo|{VBx8}zur;=PP&2}TqYIf@RZF+jN#B7+KwiN#$ z=!I%Nxd9HN-fAY+g9>`Rj*b$Hw5^#{7_*WJG_Tc6tZX|-1I;l#KafBut-?-}E86VD zVEIrIoA;$k1wI##C}HwES0mdr&lM$@BOn@$D>KL7Nf7mw@@q0~rI(s;du8T0!9ECd zTg@IP<5si5CfsWF*hIIU-{!g1?D5(8XP^R3i(hm`PE1Lp&A7fjW$EKHG0$(160kA| zwg9P}Wpi08`Bv&MTYVUv<<33PNeEI|dcWNFo?4ib;N+JhMO>}*XlwpitOsT?Jw`^4chQ#3daqVWA<_O2wr|Txv%P7iqk3q4f|ckd&(dg@DnX`GSS* z>ea%9Z&;=qw*I3f{{Z$viYqf(kg+YeRHobg+7`fq^8;f6EZX@I0$8*yfJMNQ>Qn#+ zi(jFYCi4o*3rb}R2?_2DjbU(a?Vn3a*T9e^Gh>eW?}NWr0aF_p_TI( zDRH+0Dvz3UvSzuS-nAA(TkZ-Q?3$MGqa+(=+n&!7BW~EoC^9prF=h0(rZZqnNLf4tXxeY#U zQHnyF^t$K2%r-luT-ocr$&O~(>rIYkUv>(jJ6K`j8P8AW@Q-8u7VM-AO$8IVtEP;S z6m4^KKEE;rcHCT<0>60JDQKvQrPkqpu}G6yzcCN^<+JRo=`XwDCvBAU%@4-sr8>0* zC0lk5$}#Z2nB4Q5s?_wi;D7m3jsFp2f&b+w9NE@;h5v14lw9F|{OM4~75*3BxV$j^ zFO_C01uvb^5nNariHE8N4?XC8$%OK)to2ot54>v=LD0?we#@07*_y6@<)Bmkw_>)o~_ zu08AdO(+}%o#s?ZboUi^1KI^`q*r%ec_LAGiu+gWQU*1oE7aE7y8kMn1yyEwtDKpZ zm{ghFL8b!sR>b$`^)iEH{iok0U;%(j0n7qtva00>%&&c0e(nF0x9(!O3^aeoV#)$v z`PC!YhrFz+^+ITSbu4HyT?5a}90XweWjo-N`Y~(WA+AevEMz%(8V>N;Wv;rtiP5wS ze(!k47S@Pjsc=SFCq#!=s$Zz9#WfZUafAjaR7_Xy*y383&@yP!c!5}sG1{NEi1i#n zF5vXFN($?;B!iQX_6TMGJfM0f1XSm1Cj?Z7W!A~a*CHb%t1I-@%T1Od zH|pQQ4y{u+Swe1suu@!mPMqhD%_LI=qn&BJb=VHU+uIyyV(HSaH)9=kNo$%*={~L0 zE~Qy3fZWR(HoPPWW0p6z8}32y%rq zQh0u&G|pm@G8WKFr@a+$$}ebXbJQ~6kw7RyB?!u<45JyheSuM3`gK><)@@XWas8dA{jo)+wd`Jj zSZgi1s?F*Dhz)HAr=R&*vJBwGrSyV5rh0rp1ySZLm`;qPBHY7~|J?^^;p5A)Syp=Y>7qYd z^2vYsp)&pC)P0`+wz4F{bd?xaN2U4Gx46`;{IMex5+}Eo6|r$`{?_zvJ{vm|`r)1S zRUsI;&2cyMy!tbb)4euQa@gKWGWRwn`Qsn8#Jwojt?#53;y(6Ie}rG8CI?b z>!U9)UcV$%I9^ZAMR@&8m3}_mEMB{p3$I^Q)TlAM9_hyPdOoIChPwaW3bi|&Wcx<4 z3~Y^Lcc+I$c}*k>h1hT-?v>?YBwG<4!GrRr?;A%g?3SN>f05*>%9^UzvA3*Uw3QYCC3#QYI|MjOmNwkFH53QS${|z-PbS7`g?w~BV%#cSvC#B z^*OvtoyG5Hy{Y(}C3|imlbl6+?r)#kerx-v_Gho|I9y~q#pB5zIq`LtDL={E%F*BY zz298)_Y=IETqi<;KCPbktslSLKM7*wX7Tw5p95qoJXTd+*j|1(&ts_V9FHp}zwnjM zeZAMVR((>%yNfcRqSHhYQ1z?&J^Al`<5OF1r8o5CGc}4Zf&1aV1bj&EzxzMKD|+2s6%hm5z0~Gq(BEYFW3LRV}bAh z-UwwmPy358JH9f z1<2YobhTl7Ne-EYbd@1B(KtR(>^{za;@yuSVsFmZevaSr)>M#uV{34G>(uuA6OXKt zVGYEayj}fyy*}^@{O$jN+l1h8*6Ci}atI#2N&D{?ISR%3aSJA;SsCCw*hDTFx4a&Q zxw6@VWDo~=O)dvMG+7QjCsgE80jdm?805eu5)<-u*TB%h7I4R1$+iA2R9!aypX;Ap zm;V(FX+(5A_x%5SkKD85|Cij575s0UH_rbf%*y25wt1Qof{FV_q~KgimMZA@F0Mg< zmQHU!Jdgqvi*mR?YRLIy&`A$TnCg|kv9c04N4SSkT($@70ZcaPf7 zlx|hKtJPJfJ1GSvkl8)Eg;SQ&g+CO9i??;J%uly~O3bMsc>5OoNw(ObTjZVPOX%`5 zcG>n>yIR4F=+@9Yw_ORJ16gR*@J;s#jX@*D6 zyz?3+VWY@`;||s$g9b2`Q8-*zB$WZ>f+_`o^V6lp!Cenj_#Z3b zOhbTEp+27cnxKlJ!v1f0RoMEvN*(wv7;=vMoc8&+|H0vYdRoe4%)6;p zL@py>lx<7cu0o$s=_!9tCK)V;@K zd`gM({E(^D{@>WLNRk7#z?CU`YP;jeMH z`ZGb-=aL`jnmI_?+J( ze86|^wh~R*G{L6=N;eZz={8BI(oIAuJsLJf_53t*KGo?=R&un^su`i#<1Xfw(ua0Q zqAjJzcR}uaKDNsxTTuTnl~+__E$2(VRjHAnN|;CJriD@pLK<};=yZ;U_18ZE>59XY zy^w+WIw}KIef6IJJ-0<`kBpSqmcMoK?wXW@pjZ(2jQ9Wo(~MHmzz7ZU#yphZ_u^ut zKM)HyPeJas$dafH8GC9}w2Zx{NBlVz?Rte_$&0R;IGbYzsPF`nfN`UDZp71Ns+(NEDQiD;X^6mvd0!3em77CmJW&eAFyM!eU+ z-!U=l=Q}rmd_P=I`EtpzCIgyVAk|UGAY4SiN~%eaH49nEf;trzzTV<`js$Qg!DmbSTC)VM zaoe;s8YH{No5b_E`6dk&<4uY#pf{@B5^HIYI!d6K1X zMGb3f%D3qpwN_K@E4wayVQ@I-{;4i#2`2NLZ;|m{cWdT*(V0qfndQ^1EGsZ5!`b%5 zM3SYlydtx<|FgEP3^Fig_h8o3jg>$7@vpS*8O*cMChNR)IGz7V>y51Kh7BJTkn(vt zgLnJyR+M+)uIuN-vG28+$2v}@ZJ{{pfige54KDOBz8A!{Xc(5LfI|%YA?U77)k%+v zQnKlfFK6#$1QZ!~%R5*IcvRX|-+w4%1LbJ7%b|LYVC6hPgi=v|A zW`b)f(rVdBe7-!nD48;TJ(Xy~|I3nvR{wMA6A~uX)+Ga=f~!fj`Yr~!t^3@g*431U zfz^~JHHR}3oX5D3LHia~`4#kK-K*OQ^%;5~4XUm+cJbVzMps=OBveRKD;g$|IvZSa zH<_*DN37%UT-ohJScx|QX^0dEt$bQf+>#v65WI6XlEz zT=%m7>}=avv+diUpe5Uj+jhGoV_Sx7UeU8{htu6H@#@6wxG=`R;|4TM4AYQZD z+r|W?ov#h7p>1k0UoC+&P`2`Y#b#WdG5T(RtiXyC^UWQ$JmdntogckcqULm2UC|Ed zm4x@iNFw<#1KZj_UKs=h?XK=AFfmm?Y7YQj%8c=cJ(LvUwLz~!yufly{ErU@#G@jv zbp)NZ2_N6dMXylOnuf3s34`t0Tid6n`E&|qcAUh0^J)RK9E}yGTI>PE6Y^6w5vNj1 zp?ot|${y^|s3~`T_TN2*VE=%|*Tb3{`wQ{v?Bf@mprwE`mv#gTsg79tkWE&_a34TjX`KI4@The*XFHf`wuC zRa5gfbm+;t81G+jnd5jixzj7;j(BR4;K8I_8-%JyxXMUd;_UClRoXarbc<}R{3M)I zQQ8UKgm#QEhU3_^WT3%7U(7c&pYSqvZ+$x-Eg+B~4z8YMJ7|*HjXz_T`9dQI{psSO zo*xw#$n2T+{e36DE9~!shP8j!h*kWhIW@)f&~&%0oVCi`e?%j!!UES)exXb;4ib;E zyFmRH8;?j5t+uP15>D3tiu09fGDs$PEPhTgt2it1bHGU6N=k=J!82>-TY*V@JeSe~ zESR^nuMW9&8^jOiN()J-1+ous{liR(r07dARyF+GJc z^5ylZTQzq1UlpnDHM6uY7isP>Q<~a8aBJ&}f}75QhcNj0AE^WTVQ{bS&v;Guw_5)8 z*G2E-lq(Ydu1o}yB5?&zQ2+^NtcgF-p!rmt#Ex=T^q46MIEXyJkuV9e-mYNnYBH=% z?hvOa#`ZaC_j8%TsLEt5y@IwOuGk}?U3TRb3Cde3WR7UvZ%c^kUeX@Ql&yYc-Rv(> z-C32w4iuSok)Ks!pI-Tq@Xr$AJ!Z4-SW-M0<+X7=DfhBx^n zj(q&;wkx@xFv~O@w@lmllfZ^mDNk&rlF3K^7d2lhAlYDhx<+Gy22Kx!J{O~ykMP)OTE@n@R9m`^UGvRPj8H=ekB->^TIA_t?SedL5t=TMJeUWW2Of}Qj zsL$TsI-p?BW=AjNVwvgJ?{$Mm0a(q3IbdY%cQ32Q=F;P2g2q^x(qI%RjK;IXqRhi4 zERwz+7S*u=kLs2NV{>>E050`nJc<(q!l%WF8hZav*o1-eX}^db5PE}ZqM!mc<VxIPrG3~8$2eRDvs8+`|Gb-}=FWf4yY;+J7zi?7 z8|}`BtD~KN0^8!RwA0Zw&{Jq2h#z8JPH#nPQT!7>`k20&Hu`hV`7x%ed_mvg&++FI zdw4!ae$pS+^GQ!XrRNj=%xv#q`Y6w4V0H7yRkP-Q{a^f;#F*_b7$I2Z*qU7(u*p?5 zF={WhPR$)`U0qF%c)CXH_G@#8ms+iZE#^&b%824IGi5&QPj7*0!&K}w>rBJqYQtR2 zwy*la(g=u>LlumL*1P03*Vo3zr!r#S>%ye-Zn@y|03vNtz zMcT#|>4%o)DU}O?xe5{%--3zfFBy*AEkhSXf;Ou-&BWoqMAHgCUN$>i&^$nR-hlNm=_p3nu{BTB_R7i>nxb$lW+ z9gdV4yACOLp=GHPq1h~i9bO+rb1FQvO(LS0iysC}D|P#VXRFE3ok zU)|eI?7YME5bp{nv0nMsVK1z&^ztLuYsPb~bU60%(@>SA$6gn=vqt}Bz5VUeR}E+6 z`DEiP#eCJ#DnSfIe#4%YJ~Mc+^u21<>PCAnKZ~6h`(Atb8up*1SLUWCM$x1lfD_63}_=99)2^F^EvxTaHiRHGFg_K$Yi0kjq+nCh@{E-qP#%jfO@2Ad*zGdax0&F#U`gV z+Hxnn+44nKY@%;N;R%tdTL42?DFX@@g4QaLX{~Ht+YaXa>}UtzM-;cO0R@L21+0)P z6I#wG1$Q{PpJ&DCFKo*wym0bbtzaiK zt;M(|x`Wkd&DR&kANEitkQlA7o*I#vSd9Y+MrY@Ss-2wu|E8wt(vUn&pB?R)u`kPHP#kbo2_e!u-dfkG{yEm^GS*d9=7 z4%u$L{r1-JExe)%&&X}x!;81)))tr+9~naPQsH*<58xQ~_I@ZJ$?9VN=q^eyz89{d z5`LfNSB{$V{A#>e5%1a>C%^fcK@BEKX#=Rs_aT2*@%leAqz`PGy1=hIaJ~EjJ^rxv zD64DzhoM-0cWd*4cyi_X;er^4#|uL|PYY&BEwtI}+jn0vdk*jw>x+EF3*i_H`JWkT z7p}IL2Bm6sj4}b69OQL9zGaQ3|>zuaW0UIzT%iqg@Ww+w>6=NQ30cVnLH8|n0{jJkiiH;LI+&FOU+FM({8&C>3j>BI5ULn|V zqbh}gt>~-Z0`KJ?umMmPN@sa5|45lwI?H?cNfHBKn87A?s4dvGEitqjkoa?pb=>M} zj}p38&$zR>@_XPj3NJV{2q)$*&UR~id@=yboZW*aF~f9_z;>;`b{u5&nPsuV=c@dLR8`!0Pwv9ZE(K7Bmm(1F#s+M#{d9-61EoT#XJ2} zS_n9w=bSWxo(*QAy5WWWsGW~tVdvhISdbwMRQqSlIFrXw;aWG56YXkXi4wqYtIi;MQmbdrTf$28;7zB6+B{SaXc3FVg|Y_t|7`ZtcqCFSf!;HCjGgnfzUu{FN%= z%H;2*GWj$A>XpggOL6kou!wsJlRvy_Zr4Q`Ajvr)i6vD`&j&jBT`HH$q z@q#a6L*YoRxOpdwRdtIz+{&1-j?KKivE6ZFzRO*W9qSZ(qaO%c2aaiVj4$W@ZP*(P zq#mc(jDbW&KTu6+Jm#!YE08>e2B_kLg_yeCuHMlzW&lGb6{KGe#ev^(zQq9ibv-*-Ra z&0>`qL6+a7)$gSLA-U1!=HAy&+7o5oT+4-Cuh*OI#UjkS%0YzLiD7eS>fq?tY7FGI zR>Nf&prMur$)Y+^hGl@+K_oBwew<|8f~a!FUG0ShB|g-Y6LIW zB)9GEe@=Z7h_4rDYGlTTPl(Jw8Fk9c&3$FdmC27LjF;*|xi-UPj@yk;zX`Bb`4BEQeyGTu1EkjP^C?>}u#G9}b0aNUQ3 zFw(KMDUU)|Ym-oJL{iGRN$tGaQw${C^1@YLc4Ym@4}D%hMAhdPyodd@2dx=ew6^nS zEPYG=iT8VY04IOi#eP zWWD~+S^Bm8|2L!;_5Zb{XZ@eDcvU5O^7sC@;JL29pR~kX{XcOawf$BY7Yz_P zg`Zx&@7n_MXAJpSPxqlE8E+AG`hRKT-PY}Yt;{Z#vQy5S;ifOd8JNm<7xnlcYLiPj zh<5Fo4dPQ)k93nA(I#&g2K~7lm6Q@ z?O!7t>WVp|eQgoqO3_@{p2v54?>^$?61 z2*2;wMb%gaHYH%BownGYt{(Zc7lupsr>BZH!ILu-{qsL#)Cw~ijFcMAKvbfp;jE5p zWEuO?#qqo?rB7)@hP?N9=RjMBpCj)EK8^k?givgc(%bxDajJNP!!K5A0*Q*wj6~Y_ z+{U^+qouc*0Q^Hg7=WJ<@DGMJh)4uKoHZQkBrP|o#9isx#SZj>WbX$gr+&Z-^h4c= z!2h4`x+wVIsya@|iKVg=9O)uXb5kcebb_%v`UBnrhk3Wdyu)CYJgkAeJAmCU!RB<@ zIN0#Du>Q9-utQ9eF|6A-o1Tfm?h^p18SJiuz4opc>`Ov5_ce^eyv_rFr)WyNx1gbgJCa_mFkLu|rm=_%8pSd{9n?N-LIG2M?0>-ae~xSxyX zjkMKh=s&oaOch3cZ5m6k(siy~l~L~oqAdY1n)AA?N~UPAoge&@$86@>U;=qO_I#}{ zX*>B4GHS@kfq7y%QfaH@%~3b>Gn^`IyD3c4`xLIqJ}6qR2#X2U*%r1nUvF={nMkJ? zqp#x!`nZj6KX~p_0_^~gW>Qb(x*NA-wyFFzhnE$feI=1$J(b@=EH}~0lni@E6$tmy zEk#6VfZ;zH4C6wbVN?vABLKh*wAReQiu!}$LPt9|#_ z5HkKcO?|!St&>0U!&bXIRjPfS-`{_4Ne2Jf8tml%(_sKLqDtIX3e+Kj=MA5h!g7oF z`(M(9(VHX;yY!^S-V8HL7l!#M?wp`Cy}`i0`_n)F7Z3mBFTC$xiho%Q+277?ZA(b3 zwj2~PG28I`E=^2YP|3;x6Avz2f@agCq>1&xl}>tp-jO6;dBsG&Akxfb=L@^_x`vZ+ zkyq!7eu=QZtRd{&sXzPtvG;xSGy8=w#?kyxz0BeOkJ(bDuvr372v3c9mWS`6YFK z+PG6oqMu2rcE_gB44p0RMd9>~!V8e%d&6)N-G$qU{Dc_DlR=w*Q_wmzBElGT2*bq0 zgR?qOW7IAkfoRAOzQyGPsa%BmN=7*xg=@QNMl56(U)c3;@>dbkX)tY3o(H-WcZMtZ z>Yd3tH*#KKI_%w5jiSa2ZHsHmjy83TFb&ir3P`15FR*o&R5tHg>Pkm}no`C6u`iva zR&ucQcWuRMOm)|!=fA1-N9{XER#|*)fc=cu^QHD-K)Aj2)v{W9rCNnPRkVeChVJqw z#4_Q2_M)l%t>jiUMGz6si36yE-Y#=Cl~(wsMAsEqJL(j(eg{3&XZ@q7_3vC;p(TpQ z5Xi2(Y~cJv23F7l6g21%Frfda=mr#$XWY$C9rT=dMg;TL;L&?R(6VRh#4l574^S|P zcT^or?^EvlEM14TY@f7`rHz4NgP-G)#0E}|(|0aOon1}_1SeMiii__E zD#oZ~g!&02qsyoCD3r|Fqr$~ev3BayvWUrZfG#S6%1TP$Mm^^a)>P2>1v65#eEu$k zIy4D3JTzHx*NXTf?Dw=S7n8OWsCkb_M#GF&KJ`X$-%=;2G8BEXEp*4{Oy=eu?3hEl z+16#r=KPN$hVr>_hjx9*X0p?oNvG7{S5=QM*aUk5D`6&=yqj47W%k%Bdz3JQA#Y|{*u_oz-gU+yRl%}h4 zO_~z|wD9ZnZ*+K%8H|`+Fr*qvZp|CNw^_X_Po4N%X*ZZm!)t@p+GoGdH ze{X?MqPlgbKvUhsBSnQtpehs?!oWPyU zBBJQM>73yV_j0trlHOoaj+$CQ6UK_vw8QI78}tL%hcVv^F&y!W>69N_quyzAxd zHz}4(%da_>Cbj*r7LKimD5{xbh&-gA+7!AcppQPZhHci|ghL`7w+0DSnG`Oh=pGWJ z7nP$0q}l8pEuJ#GY|4u&(+yVzUAUs(2qoCfZyJ(_5-!X-CFl;aQ$&JG?dq#Zl#tMs zbtu8>E-9g?JDE^-of6JTJ)=3+L{rii22hO{bU&MjAuv$E0r%EX>z;gKwsI(JF-;S? z?PG<$X9yWORH3SeDN4-+&NEC8;g_F)_cSkWL6eFuN8FATr9|m7QVc<4$xsY=)uLhm zk^F@Z!+1u*+;B!UZq})NuG&z4%d0jVDz4iQYnIn-ci2qw&jZ z-g)Cfk|o(}ph2fL2?1BgMv>$)iZsKUFm+~)joc}M7ol5zSz;*47pQd>QVs+w`mCYA z5$6P}OW@Ypeq|0|yQb9@ghInp#Ow0FU`7IB70xoqTCk%JWMMgTOdYE+K0MjhDzVoR zN;0N85jcR;EWTUPe^1y2kM&`UcZA5M*bZEOSiqtd88emB!+2{NQ?&+CtxO3q(1&)D z0%EdoL*aNGrTkF4tBb+VnY;i0OcqL|(VnC8D|+EyfVUjG0%QKg3=@qiBUg0RznI$A7sjo?E2HIu zacped>ReM0Vkt)p>MMuO69Bn_RJ04E6@W?rzzQxU0M{5eqhwU^L;^=$V7wzDIzfn6 z$411($IHZsjgOUy5g#8d6C*}GQYJ>6yiz9GBvTqGh!7v)f@ok^0P?Xd(`=ZP7By`H zthA_Q8(O7B4cnk9t!h^YIOc>|FqP<35Q!apG^*^zF`gLJE2i?q2mtY2F_Oc%Z}g>^Z}cS-SSq8t!Af4! zmu9}vmu9}vmv#AOE%Bxbc~^BnA2ejp!Wh4gv3UihQ$xfvP6`pvI30}h%qR<2poq7{ zX+mMZ438BM`iAh46(_9mSZCR<0X&fiX^~UB)wD=KfF%NS&>fGwPDFwGu0~&Lw0EIwp=jZw1W~ai6zB zrsFE+t5QI5>danmy_)oR*3R*a784}Kwyd2l6{Ysi4mtBDH9`}UMUkJ@pC~^v=M+89OoqLz(ClomA%&b(~Zt`KmdF8Cw|E5RqquCfPvMu}0q zF8Guf0pNnq8KXp}3qB=A=ybuS#HjCp4zMHA@OYUR6_*(FoDoVS4Lvae=}4Iv0l!iv zM%@git}H#F0@$ccR2D&awoHtGk>2y15iqCA#0Z$xGBE7r7o*C;d@Aff{Z{NMTadAl=xdPO`eMWwY?n$H>Pxfi)|Y14 ztuIENW3pRc;BAMXX%6-6^}bZ_OQwqhfWH#mN&xH%S|!xPjS_0&MhU=HiEbqT(wOKz zF;R<1bVEcFP^mA?sMMEcRO(AJD)prqmHM(SDktk68L&b3RJaT(r^2NYYPeKF4VOx& z;Zg}rxSVWOYtg`2@g-nZcabi~r8z3In!c6fiRsK+VMSn@@>Y;tD?i0sWmcc$tum`m z@HS#ri<2Vx1zR|ON8-z?Ef;(H6Uc%^f+pjV>WP|cRF~a0N&fPoS^V-wMSkBlr$*UZIRt%u$0Hi{kloODN`cz5`&JiRH_JF=L zV^Lq4(Wo!Yc+{6>MC!}Bm^?923rmTKYip=fLJgHlsG(8`HB>60hDs$gp>nc5l@b#t zHsexXnsKQw&A8N;W?bq^GcNUIU0hDq!tz?dhIL#jp@vH()NrYU8ZMPk!=)0Ma5;G{ zH-!#8i!_RKC=6TDXsJn7%EU;fUQof{wJdXo7Sdvt=sIK2u)3a#ZO3jM(tIS~z=klQJva4AoMvbqv z)DtB}K)RY$V$>O4L(ZtvuqugS*eLOMnHUv!HLILaL#}3(7=d)8EFNKGrA&;v8Rl?> z#Q~23j5sv{#?`D6BVb(3Dlr1)bXhzCX0=R=fN?de;t?=G%@#Tz#se6!Uj)q2GBE;1 zO4oBnz)1IcVg!s-uqQ^qNE3Tv1k5=lRvu0`jy&SK2$<7lVg!uLPtO?vbE-^?fH_$v zM!=jX6C+@bE3vW;v@fvH8`)q9%=ZhMV1BWD;>z;|JAuXfU`H@FUdLh>wHb_WrT%N{ zAjY~%t@+uEd&f+LW|?d}th_ZpC34SYQPVtE({V}^bN0H0fH(lu%0S>9AS?TTcfhO6 z1Kw+5n0G*`j04^QX3RF2Xr;(DkVt68mkW!~w;Im$r5SJf(u_NOX~v(vtc$~mwv9{! zNtzlGl~BW?5^88vLJf~fs3B4bO_)3}(MpkNAnDPJN__z)CzBc~^`#k=`qGR_eQ8Fe zzO0MN$+nG50~c)(K`Nn!OC{8Bse~FXl~BW_5}I&1*-DuL6c=nS0bc=;n6;rLwsTf_ zEtnjC0B@DA;3RJa1Gn-Myj8w}>P_$+OS+ITg3!VX_cI5iPZmp_TD|%j;p@&-QB&<`=Qpu*3-~?qa;TYdr&e& z)&O^|`V=9~4Jk}Y<>HT2UH`$YOC38Y!*v+yUOx^*7!d?0V2l_XEc}RN8-s!k2yl`^ z5TF6ii~wg)5)TnU5J3zG5Fmnp`}zKUt6zKXqlYbHI~d`!yH~GXz1Hu&e(Se>%Y;)| z=9UU&wQn9S>ec$?b_(@seMdled$sYwp_EB<)CzZ(g|)ZcN>R<)XWU9rVXZ&g%hzjw zm@f+}XcW$XV6VY-^hGkG))zNYR9Nea8!0NR_2oeMdaW-DWnrx^Zlvh-T3>>ZQdmr| z8=av`_0H@p3u~QmBSkf9opB>Yg|*JOk)py{XWU3pVXZSq)oovu6?MSHbVd@O1{pU} zR9Neb8!0NRb!K1rdaW~Vq^M@CGj61)u-2Jiq!eBfso_G`;tAod(5yts@TEeJ5^2R< zauJ0SA&r7 z>=}fGQ}>gb@Lgl3-hLmZ-y`&UWTZXf{XSy-R!5M6MZdSj1tqB?h}^Q@UR`#hSGRs6 zX#e{<;{oM3; z2r3>K6($v<-bskVAGD`!obYQT$k429X@oN+m}hPCp+pP+&xX=Ze~@s|*;Z%Rr9@Hu zSrvmE-(?~I@}$^eq3i<6;-xU}K_9MmSBP@8=f*ZehHu(t%mrcgRp;454!;!dZhBMz0M|h(;P=&&er)q|<{RA0Ul5 zkQT$vJi5des;ug>f$&ZWnG7h;0@`_0x&&JYQKjbK~ zjZ7-ILj|Gbs$JItV1Yx~q7+%0Jlp$fC}QIfW!k8w=n~9cP@+A}LZ-H- zo)SY-j~k#)gQ4li?Zc{!Ti3YkX&rZ>gRWnNBZ%=?@68C?a7-0 zzuUI#K#u^vJ(s>I@Vk_R7#e=>XLb=3Y$D@{H zpxQ=0(%2DLsI1;!J6LaeqO!8bW%8KKBAxUW=_KwC;n~n$`*gPzv}|87Y((l0Rjz3W z-jbyh5(LZTXK5SENHT{YO_kN(D^~F(8Z04q4+Ar^rw1hW4{*HK2RWqz#*a8v$Tl8dlg1o#W2x z&kS8~t9iasn|YcYDcm0oxbH-K*rqXzxsE21S{B`;gJPJ4kucM5W>(SXOA$9e_Hz+F zcmF(vPw}yzi|{Ev_O$RRsP_pKK6uZV2z4!6mZT4!GVV?M*jm6j5kGvy@@Bz_oPb+g z@+mnS#DuWsvz;9^eZx%6=!>VFcq&OCn+reQ66n~lNuWiK#aK{|{d~Zo0nHps@s`E2 zEMZwb5yxWey_ufN$#j}yG4`omK9+v5=U9x7TX{SE^PXcaK56C4(sza9DQvm~$$inv zr_%TL99wb3%16`PJ?%eYU5dfI=Fm8a>~ zJrfi&HyDrp{DqaTOmFS!{{btXO5fH~|8GP2fu8#RWaa0jZ|Uj(4@3KVd;0(8cdMT( z(tEtzJ9DcQu1@c%(p52s(!B8(?wF2$jpGErf5=aGus;DwtBZTA-EAx9hv#mrD~|A~J5;?5<<42`ReQ;dY&pi#{Y7r6(eBXf*h}m2p<|`w8fc_D9Gk;eC)LMvudq%b%P&^-BZt zMgEt?z}Gt?Jo|gc+Q9rT$DUgGU#z=TJl#_}|H~lQ7kk?O4d;IufJ0U;2^N8a6ld9p z-_(&q8G1tQo+8l7R(4&~=t(1|m?bC)}mDRp%s8w0*!=^t}R()4~t$!2wUrKV5;BS%~bCE^(Mo$c&qUQ$R=*eKd z(UZY^qbCO9KEBZt=+mid5Z@e*{2_|Jk5CJ;sPT+&NWUwdQ9*-eRM6lV6*PE81@x(p zXL?zYpLsM0=CaDODf=X0a6KN8%Rixo=?g}~oq{{!&kS4wIgfT24PxNH4JkgWE z@L0t)A?UKd#mi3r}Mu!_f%G1Vd@s~-tcNkx}{`4R2J5RIN_wBW=-55C<|)_=R#Rn zvpDyag|*HQj4Cu0`MS<+{+Axf-7C8lsf*|h$3Mn@c&Ji z)mo4an@fs$HDfDhDo^Ksu?)n{$2H-3xFwn7tXm4?r}Mv*pja?H;>=bSx^i)bD+_~i zDKs5VOJVsG%m31+$$E7eduRsBU)v)HJ@t7tcraM{@?fy=<-uUt%Y##j-fCy{04*jR z*pR#`Xh>caG$gMI8j@E94auv5L6Ub-eJUj;mKzL2J)uhjpy+HGo-}-_dNLS}dNLT0 zdU8rg?pag|ONmJbHbAL@1}Ig~0Hq2Vpj1Hvlqwhm%Ek4ml$bbiFf8?CFf8?CFiGmk zU|8zOU|8zODPg&|7M9n_wQwmfo~XIp)A?UCJ$O3*i%W)5vxVh~VmC89TC#sx$LDZj z-@ZAV3j5}8Dy*3y3uT*qb2!!PpTj+!|HXww4Kl&{EoQer&-^a~EQVg2VX%B2ESm?* z<-sy}uslAcELK1^7Ruly56la?T1|7gr<2uM1NRM`#(hJjaZi`36+-UmOy6S1qE?D* z0~r*9;iV^oVWua8;ie~pVW%g9;io63gyEvLjZ6c{j|LD`(14-}8emjG1CAd9bG>d9bG>d9bG>d9bG>d7fVxwvg3(?FI*1C}aiz)}SbSgN1_ zOBFO=se(bUT--`|YUh9HnF&0d|Hbme_%fRbuu_j7Zb`XQR@2x|=YO%-;e5f26cHIGt zhs)FXU#6bU|I$cpGj4&h+6z=acG$Pp!MRmN9yED%1ILG(cuVz9F)L5!e~F*Y|I(x- z+kMucr7Hi+SC+Sjhy#zRSn%DWjjgBkIBtu^R)zsZHlK@#WRE=_FZZvGk6AVr=0;zA zJDVcAWB_63gu0+Wb3ZbfgNaG!!nwStsy#Y8H~s1z+CWJvsy*#4M;5=(9+}zAa}tK+ z$BR9ai==>Ix4ZA!(WZBr-8fgh!om)=s&6N>L@gB9F6GcI3x~JdTe(3-InV8ilntM< zV0PQ+*I;h4a@9sS<_ugGk#B%Or{6RPaPF*qh|^IOjz6puUfJ%M4L462rrgeS9iC~C zrY0lY-m{mKUDsaUa${0?-mp-qv|-+Lx)rXL7gx%;V}ls#lTajbe^LxWiCZk=nGZtw z<^4)oWgQcX4}x8h0gsTEU?yBZ+D>Acsym5&twv&;7ww1oo-v7Wer#jsdeK9`3>Rs; zm{N%Fu?FFVj`@BI%PDdpeWPcA7TWo!j<9DFZT@Q8lVLAt-`l9sf)nnBR)`P@6rs;e zR``wc3+K`ULh+;!TC&;zSlE}(bVG+`zYe-`M+e+F;#)d2P=8KWt8E=@k?7kKE6~-q z;}@W#vx%Q3&PLV%x@vz2PR}vXa ze#atAzO>u~W1JgA*-wL@vfw zAk?sWZdljVBxfqL3Qo}AgG}YjW9^z@IC_UHM=i_0>@}BIrw7(lS|nxM3vH6WuxOE? z8Q)m{i^4uBR=|H)a%@yXYq6)hI4ylRqr9bZ8{eqluUS91jnWUj&ICMJbD*I3_oi&~ zwjDveIA`1DY?H{!8EvEEg!>?pZI5|FBrCfBc@H{cfF^Ltn1d7NhBo2Q23`%hHMzo_ z5rAEZ)gWpo$+Z_iL<;Ky8i0rctNmYDc#c3sw`w3-^=Lq(bd#qAkrEATNU}PJ#vdJs zN{m>>OQ$>#5WrS;hP(+)u_;#XL`G(Ek%hxey`Ym4bTKyZ`8Z0h4`j-eq&3xoZIvj*w2ny* z*tZi7O}B&A<8aVADI+;(T~Bn-dSnN!>zjHr*7549aOISeE!EoO2@EBX5K)1n-{-VD zoAd-Ul^DZNyh{yQZ#1lH=F<5;m%=i;mRp{vl{mlIu6uEBB2Bq7826=C@6~e%*?d?M z2&*x?JosJfR2UX2I{B^MafNPUra{1rqwnhzAB;+vYT$y027{0%MFS;8whRM>bcOAP zJUDWtAb^5-hn-`e^~i0Nq52k4C#_Te&4#1`$D5M^DD-R9 zl%TLJ{#j<3TB}?CqJ+}EIGyz$4K~eAVZ3ADM{Y_h6^MPScedcBLZL@=H(A-%9Dq<8 zOJ)4~@UZtK(*D`Tih?j8p5E?vm4woCfs9tF5}>%*U-TwcZ^}u^q>f{7>{T`m3Ej-5 z>7!+t6i;N|QOtEnRt8RKmLN?R>pKQZK{iJoGubR=(VJOn03T%0*Nu2hRfGLL)U@9z zHyg+-xuJpfdxfi-{VszOPH?LNKD>@rm@H>Qd2H>$R-Q%E?ef1e9HY_Csa+0EPHC5u zNaz5TklE!xAXwo;&DkvFH3$?`T~M%D;3e))VS%TTt~GFUF=1-}!Q^fm!~~drll%WI z!8h#Sn`y;na?AP@dkrwT%PA*@vIZGs)&P^cq*#tTS+u5^+|X^{P%O)$#U7J;5!s=J zrCQBvfLJ-D*PyhvKfI{5y*P7K*0yq(2UBt=Slj)+15CU}Yi&2>+N6$&aruQ&S%Xg9 z+CEp%F+;nAPM@KDCeR@{>FJ?^t@>yU?H=fq$WUhC0H?ZnU6f(kKL+dgG27OQ63S!h z7Bu;|G~BeUA6jAww4)+{cG~csO1?DznE{B6R5NhK#!Unu^f2bkFjMXg961=9FfFdn z^q%)&=vc~)4&q1VV}@(f(w%uG4mYyQ0)-8}A_b=#(wn45bpruN8t{$o&{=-PQfQs_ zE9ECA`Q$$p-%llCGy9?qsdYu3{Em%^jBH_4!HVr*h}ytd18#3>1wfenqwH-`{iBb1 z43?SeNil|zM?D5hcQR-UUw3HZ9_bACLVKiu_UPi!9=^B-+Gc-{SdhkgC`L)QyP5<+ zmq|&ND(!e0Ux*Z!yArdsaiS?hxA|4W9It&5+P^bWcCxpjf)uK@GRx7YayDO!gaV*N`O}+3C!Ra$(a34bMEP$O^75__6?9G^ud`X0DMzV6UTQs^3n`l3 zktIXdw^iAfoN=G$Y-q)uk=a&fROD_Iwcxl|MWBY?4}pjzaWhzH@7@$d@n{*D{0mg`HAhGWuJ z=8PZrE1dBoegzwiay9uZ5sTra%LwfFAo@RWJ}ift_rIJEpGa__lX^^<_g97JNvgo4 z)l!vm{6DvKn76egu&Qk2L8&A`-1}cFcO4p$qezVuY5UiduYB}%CEVohkuWe{sDBb| z0sZh917W%PU_GnaYULyw=2gDa_`=5~z>JyzWY$FM;?{ivj;BSX(bnFHi(3&Tz%I@| zJTWJKLj#1J0+`;uJBoFr)#(9i6Q&ZbnlJ^hs-N~jgKsZbcS9ip>meBmHi2bw;>&eO z(^aBLi@=l6>yC~A`q=<5wDORb)xy&R)-M+E0F3((Zmip?PT-9)<_Zk5ke1D)`JUeqE(yOT-i z17U%IiZJ)|$g)vCBXnhrHS?cKS8%N>Yfjr0YN#umC1qWyI_sUWv09yRh*Nd`p!S{R z*5RVghSmh~M|J+Ma!6~fhKUe>vbkRoWFQi&OdEesPWjkB3p8DEnWFdd8h#OqLNl}FiJ~_aA?Fuf;2)Q zXfMqo(u_L~C2 zzkYhK43v`s%FkI&hFs>S9_5;1l-|Ff4_0d)Voc{#!(K^QIJ1=(6DTQB`6Nd;2Y9U# z9cRDIX>=l=|Fh)Oj&UkWUK6G-h7tF{AMRyZhsS7ZlmX0PsHrF;f1V;>_6Bf5ex{=X zC7_R-_yVvioEz||{bfzAU8Wxz$zzZFVR@3Sn3{GJVdiLHrehBwAde;tZM9_h0aPjv zTN?FJ6)e;W##G>gD=MjDu9G?K&9qsA6ysbfJyf>O9ZfE7>1!^j@(xXE#P-1rYTsdI z_qHsyWKJG+yMKC4B5id7lhe zWR6K?;@^OiOPlLzwu3E{NyRWgn=Zwzs1Oi%HI)um{244+%^zW2>vKiY%$&wF$te+W zZ7I$Yqg@(~Z6SYAL=0#&>L@}6ownc&wa3-PY{v%GSy3%GSZ`%GSB;s=|}4?pT?H z4B3^fY1oymY1oxb5$%cv7K2J)a>XoFV$9roR!wVoP89f&!j-LI*;AXM7Q#<09Gfm3 z15p$gPJsbgvx$eW1$?xa$8AP7|LWo^b-8sBa!Yegq+u|Gzz`%g>QhCDDCU{PnI2p? z8qM?M2LjVM-%O&8RY|3P)WKs>JIM2N>kv-m#ow$&$EJH-3rldxOL2EhE+bY;-=+CO z`+R}s5A9u_fLD2~7(b(ay&MH$f%I(rT%c)Aa{_gO#gFE)gysm63QXq=#A0Bp*t>=z zFB}iFjAEqQ;Zz!L(esI$m#*|(t5H5#xSI1lBi6j!?1lgDj9lWHK-65~YL@R7%_`=H zfLS`^fmTfUOW)L2-XWnwjM6lZ6%^DWC`kU_2h4BKwy+>AMJp_bcr5^1xP;GmrN?kw zLAJSAQa~0`J7dV6IYf25lr0D}z=`+1Z{flg86Ze&n>8Zy`2oy(8jWLprA9xQ9<^$wo-a|&q*IkAez@) zqJTJ&qJIj@wXnBLrg^av*|Xx4*~&-BHDx<-M+#_g69psI9Qn4MX<&;C%`P-1&z_(Q zU|F}GI>2h54X}(5n$jx3U2)9jIxD3s3n_u0@R$X%?L}depUS3IRm4B2l>u0^hU!>! z?kpF%&zj_$OJKhcB>(7F>zfOEzYxGW`>=o>h1XoO3^0>zb;b(s>`jStsQAp3c&n`* zo_%yd4=9?8h>r#oPmJy#6s&M&3)XgK-nrEgL3_E}8!A-26sgN=u1+6BVg8(^O3kwz zTe|nmz#+`R7S4USeA-NQ$V4ySQ*Z)tusVlaP_nct!F4rC$yg{URQ;H#`YZBh{!WPR z$a*Xsn=7rK>x}dA<~jM^?G1%yw8Q5TIv|g;IiM2FP0jyC*R)ncCK`WYa0o!pY-ZHf z(CS-q_y&uC;y|fI@0$SEa*LiBMNjW)wqd0k8?z5O987Me{vM=M#bunaTI%5#xtOW| zjmMW`G*PI}#cb{|DAc9bSWe{c3&iB1E@j}zqaC;0P*1^epM7LY55CR))GIHZV#?wJ zuh%3*o&?SAo3{R0h$!<4l_IK`)P~p|a(?*C&dmRUQv0TL`W$RskINctK+4@w#Ahs- z$TRr=Bl8TSHE~iKY(k(0ZjZ=gIN~kT=@pmko1wHk`IIKV^~bcaDP{?O_Rbym{mU2c zd*A2oy8hxM<#%YhCFZS3lHA>x2iXTbm#8o zTe*|@OdzB})(OE>fU>Qtx{m^{dz3!%ej4Zf{jGXax9jCi@fIG8&dt7-4rKlr?KJVX zgKR56F>%l6kaq7koIeL!B^dbn0_n7V@E7~%StH0lYrjj0_Uyaf@Y%23bL*FH8x?dEvAPPG{vus%iZ7uDY=L=! z-^p*nDui_^{hqdQ>FXQa3-cUz?`+mGwcyJ;g6Jc+1)%8o;2e;re;azAtm+878ld#S zkM0TW=_@Kk(MfT1$McO>;^rkfB+2OAkw-qGL9F6(uU~3B-*!qE&DygcddnT3`-i`J z{f@TA(wyuy`e+L;9B-c`Zl1*YRP1hrd@>yi%MPhpEI3yadt_FY~Df# zHeT5s6Taw~M)#u%U*E0pb*#eINAG*nkN+k_NqYt+AOSwxD#iK|ApH?|8@?0 zgh2(Rs;|C&wISK)oZl1>C*M;Fh~OJhfrKqiMIT&_CON((tOWd{HC8d2cmKT zd1P!8&;I?_4t!+c@ZWyqO+i$KN5nEV9%(R7B2oG6;ZjtV3S(nkQbO(viwVl+QM38R zKHb8CkC+GAx{#kBC}+3~f)Yxu3rb0!r7l$eUf*<~x|k4>P!)Av2pJ(%XP_X&&w9Vh zOtSEYW0${I$kfzj>I#>sxN#as&<2^RH=BGbcc)}3plFCx)ih}^P@;aI;?T2~s6au0 zt0XE?vR|TRlBj7z>Znf*k<)gO)9Mj9>s_1@XVs86GeP1=#Pmp<$0Sb?8ye35c{&rX zuOv=ZNSq3%k~jl!dWHf=?I2>H4GA2z!(CPgoRT(zyjj&NZ_+c9HybN)v+;D|=Cea~ zuJdqVo%J%?eTVlWqmukX_B&EpB|XfxYB6Sm6=apXXBX`_1Mvg-QYI6mf~-uC0g$b6 zOIuoCg)_}6F^wz`UeTwIxCK(OW}Z%hJ!42PebzU$Vl9^iAG*O+yt)2*60$p`X!wy;Ppy&89_BAYxGP=B@^{ z^qXe5Ev7o#irgvMaVaMfF7XyrCzM=R&kEm`QDt)ov0b4&Pe;rlBELq=b=`Sf_(pd= zd^^8|?)-Y3=*Z+UCcH7#=vN1}oj=ZRa-}(gW_;hb-f;YLZ#{I&Ehx>5`NbzIeR|&w z-+1_k_q^ttKO~Iklv9rwAuLnf+m*&)@fb-md&>>q`Sd$(d+nEhNoOY4Kbv91>T4T$ zPZPe=>SG{23Fi0#wZ+thI|291rY>NGHSR0&_8<9MXc+Cs;Qd9XF&Hm3Y4QsoH@?$z z@OdFOJ|D_^<;HD~v)s6|M-H4*x$y=UV!xPj<6j?(dm`A5a!=GI*%A>ye2rP-GPyr^ z;(?F8{$rn%-$G1wS`PpDIVXPnSjPUH$~AM}pP$_Kr5nHgg*g|GL2_#Bb;nE#EHBee#`@sHryzu#(?Dzc2`dQ&Vne^QIWVAy7#Y*V945Af&m+~VmTFo6u zMkcM^_PGP`4{i-nzqE$r>)=KAXmEUQ;d%*WT4KODkXg_*C&-FyOz+yfql=k4$~`th zo1brM{L&9&7;WxX8zT~?xYA5SzGibwPGr`sM^n*l*1FB-J{($Fj%OQGV3XpPZ_rWzV{nIIQd&-LM{n zXsO2MN5khebc0k*2ulCwX;7bk{e7o^Q!s;Mj$sXTCj@*vQdM7MSrmOaV`$)PT(mno zPt~1s0}bLg`ad6#@y=6yK0w1@ac&?%5JG=f0%C4EWmhz-&=wRCBUm1I()Xx-5<*b_boz_(TlXf&( zNWHy7<<`kex!t=7jE$a>MT*@Tu4h=bEUr0QYPh&&Ig`DJUY~``(c)U3-Ei$cQU0-a z??;>}Dt4ije&oHHX88#WtVmWTV(35wq(FHjMy>+94P*5Xem;0O;_Wi`dHS#NpHZ?W zR1(8axh6ytu~j>>Lj`=HIZDonsGHejsAcY=R^#WGJHz(v(ve!WI1s zSCD168Y-`b%PWG7!&CW;Tqci|SL50cq19Qf)a)G!fre=ZKwjFbK@Si^g$k<@p1D-v@@^$e};|++go%1L? z6!Lp*r@L^NlJ=E5W_XQKcujfu%DpvS3fB!$TJFNZXQBoDWc#qb#r9Tt0<1O(P zF~Ro9*+_XB+xZE0f3@?!1PF|!ogW?#7raQ5CE500tfBT^?Ue~U${@HaPRVKKySXd4 zi{(hZIec-l3$sI5#1X%W8=zFS~iEt2AerKdr-Whq7cSd4%w=XGQ zBFlF1{(GQIVFaq`ciSLBg4Lm6!N z3jzy(7T{Yj;Hyv76Rm6dJNbNV4}r`-&#s_sdE&h1w%WcxT`OQyMZR~c;FZ@UQM(W< znAWk&6_K6)vzYd7GCgD)=1nTCo1^KpaD2vGsyph_OtH^eOpg-HTb+dD8Zg%B-pL~c z^sCEyPlGu9J5~LhtsuT79vu?mzXbs`Xz}*yOCryWC68m`NAsxkpWX)+EPLf5$x4Q< z(9_Xw@?wyLMSx88BtjVBnD-%eX9#5QB&Z7j&qFe}&;!VU_rsb7#r4n}4Y4o>CT>Wo z)%V>Kb&<6IlZm`;dV~5(1i-=w;)CAWC5BM*c5M2)gG&>J5S%$P{q2s;~aL?+NG=hyJ%PKvAVkJ^j!^AtgAPkgRX*-R^EDEG%DN> zjhH7_=SLp_Teht?X-#~$wj->uzD0iBzuIQA|c(+J`lDNezpMAxysl7g=@ zj^i25j=e`dF^@_b@DO#CrC+&?HZ3u%)K{iz+f9<*;BBTZ2KF%`FZ=s#N8G5@vH|1`) zW8+tJ6aQc#bLzhua7%gb64bFmHR&GaobpXzvgk^drR{%`*U43~98VXu+AK&XIffN# z=V&Q9F@~9oS$TTn-36SJi&_U`w@i>1R^jV$u^Bwck7A4f{v`i$Pa$SNlK)**sFWg~ zL#`iq{fX3{r`ovbN)cU<_?9#Q}cr6{-{k5Au z_nI%a_z)E^6&d^6?i=p?34_z&J|ZcYAoSJ?cbK9I?R% z_uBS|tpBkz=^~&6`!X+SjsZg5G{8XP9m-xS?>67KF`C;D2ge05K105Atu;(hv!;Pz zq9ywp)|GkPBBLGaQqUo;%WXnd4@n8rUYdUQZS>xHVLSf4YLai`*rmH}<&i3GNcJT@ zwXretrl<>(+9=a6_yVv-_(+3^O8Yr#*Hb^vl2^2`0=9p`i3yN@7NfgpVV$)N;w-0I}b zxWe64LV~KDMBK$7Sufe{iv4T&iPdn1DZkS}5X zgF(&M}7rM|W=VS>Z&LL%AMup&p*$V~izZNiQ9xXGh&CpILHB8ai7Wt@KNO*D%* z)#xQqYNJPxFnodXVFW`l{D)%3kGTUhoX-KnK`}fZ6OEr15Exp4Djhu~wSoe*y7+Sw zE9^`D(`^A1t30!Qpk#GnU7y-;vS2a}qyV2uI|5a1%hzWnr0aDX|<;!-|Jb@*nej#4rDq%LqpfN07wYbsz^&lK(Nz zI4SI|`8llUjaI~$i#-l<*hTqNS&)sJZ;wel(*nRGEQ{B~+eeW@Oz)Fy^w}+piW6K0 zste?8Fa@FqW2|L<55?(+6s#R@(cMGAg6Jh|S}9rFp;h>tl73FF(N{9lx@uEvbzNX; zzMJIVYn4etM62j)fH~f8Ps}TFt*|FbE2B|*C}tH*w!*W(CPMY_NI6%R8KhZSobinr z<4jDEZGNstj9HL=RorRw9GJ9)n?GAH?>dK<6`ty?R$lC7kTG16f%i30n z3Y2IaR+DLPvo#x8d+%&?1La*Ng6fjF6Eu~zp(J-s$CwOQ4C#?#7{fjyO`v5SNGn;# z)l&P_iyG_dcv0^rf-wrtoM zu)*`pV1g`ou`PfmFZG{G!GDzhj~0HC-CS{v0^bzh?AM#QEI;$@Hv`3cXAds?@UNrm zWZ0hRi$CxecO84f0xymTq8GKymm@j{&YR6`yV>juVS)9Nx}_Z2}_VExN$cw_5PfoWj%>}QT=cb#5e?`dMxICz z7bEu)$-Q{*A@d*53mkr$nw&egA!277d^lieHwRNyKED3xm#19rx24i+nTLBMmFlXy#>sjT6mHTxWO zvH?J7wNAT65%l&2E=$u&E54!BSE8&g%nJ7lFv7f%ixGmDgJ$m@FJri3}Mzt z`c@YPGn_~(Yy$Nhgz&M>c(O%s+>5T%?;bL9ig${CD!U(UoyHIEE(e9iZsvHWw*1NC z0Ialfy-gq`8?7{Ry%eZopEKb{3^;%2`>d}|Q99EsW!-3+(v4-Q>{UeAtMw}#FI#mp zK+^$FV{|6HOU?==2|nbJ^zQ%$mOb*(hSVizs)m>zy^-?R2K-(#36_W;8YTfxW1mYq zUg^wOHeL4G2zZVLry51zbFxtYPA3`#;B~wxkO+MB#fh<=D8c)k9<@pI5^71ID!EsB zZFi|Om_h=&%czDo!BnAiSSsrz&X!@0WXoQ%*4Uh{I1G3#y;owH@E2azh)`w%16(x| zU)mj&+k;hk*m4vn$+zwi#Pmd2j`_Vru92%XDTyh!CpJsE6x~Hb!bAb48QJN4nX;Jz zZ^g%(7@^%gk=RSv5a=8JLP{Mg{XQ)@Xdr7NJewf*qAd)2Ahi!owk9Uv{c@XT3*&t3c$(+UUR@0;&*CVpuj?Wkb?PZ2)8HF_p~d8qobzN%(tw%2x+ zq4SuZt?i6E(1F3F=~rK8WGWssz}wMg%Vx9f-T2PVgeDRy zo+ux74666(SEQ}n1Lr)WQ4gm_H5tyw04wG&ui&5&Vr;-k`q4WKCX<~BjIk-+W1R8q z!GHe2f4VM>*Q4pg@ zTU;<*=#;Rr^zTiy;(Q}uz-X%*t?k${=|e{OnsHHag$Cjdl)sQ=r8Ul$Xhv##EkrbQ zXJ=H{rTP$*eJ5+0o3HFjC|jArq-L+j_?eAfI)#_Y4CQf`JwupvEqU%og6E$2Gei%d zR=-WRO3|Q16Ca93!&bB)vs? z>Fv#Pa>$Kn;@WY^lwU$pxMT}`HRl;sqx_}PVHyXaCzokx*`zuzH--hTpw7%7=AE+h zQGPjdfO>b`f1vysMUT0Z#8t3EQN)x%!&z()n%CMOAVm4=$FhmbbYXvN5`hS!(8fvU z$f}`XT|xw$5igF)7?rTu&&?D<7|f`lX55{SDe`Ytg&kx5a-{0&wjXVB>$29PE--fFOwZU6JH)8ln=MWISmsptTf|l|9t><n5RaJ$ubfq1}oBP+_ec;oArgo6-@=Fcrldpwy z6tCO_tONqnf1c=yO^FOcS8TUL>N4Oku|%e6ZXFDd4aw!&Z+R)i8H%`5w>CCLFcUuq z9%ASldv>tD%!M|CP`lO0ULJO^Urupj2m2SaP1(n^uiC-BD4ObHV!5H(!fpZ2Ho7qJ zS}-^c9Nm__(Fsr$erDne-9kXh!FPrVGj406Q#^Nxx0i=_?#qeR_R)nM?6uLowZhn$ zj&8ifT{XHU?&!q;+*L%>gT$<7nCl&h*<(dwZQJZWf7apVRxQ|F&_pNGhCn~Nx@uU5Jcj6~^fBvJk52uGhD;zFg zg#XSGhv=flFc(QBQ6tqeW5oYn4f8YAFmLjiuY}9TZ~E^0<{y6Vhi@A+%!(0Lm&0@c za&}0>``8%WBFQ9bqibyKetFp1eL2YL+1h>A*FRMVn%7sXcmh)?(CBSH{ObF5-}&vY zzJAd7Dl}GN)W(bqe3=Lhks`%d?Cq|!i1v~U)FR*gb3UCdwkNiX@>fg5^`npEXi!Vs zU7m$Ku?X5`ItiQ@Xb$0^*b;lGFUc+%=Wk11k(PknMj&hiyjNG_i_>oT17Pvm&g? zp~_stXXl0(2v07clJjk5$O;u8ao64>Yi!wN0O zvm2KP{cj5?Qrtcici7UQ+E`S^mugleNt`L;Q#Iq00A3r-rRvge69%Et?5uwTEa@Xm z&{;gmkFq@9Vsa)RTprFlc}uBVG9t*Ku&gP9H=EI@4BNOx_(k(iJ<-Al5M9ZV3yN!N#gpP1` zsoy_mZUttX_MyyRt!9LMRu#ewg0En+HUs14zqx-NQZ#4d#E!JB zh2JIBTz8(WKw+|5(2jmRuC5*$wpndJt3{9)3_#ouqQcfjX6#D-yY+UZiOqI_AY?tX z`6nHvz>^+Y0n|o;=R8z_yw9w^Ud79-2QsuWw9NWsr9E*#bXDIHl`H8YKAH5J@*bL- z!j5|)>IQ_z>Br=VP*~I@MFY2kffvb2(da1mv_@fDdK8cFDxxeaVu-aewAYx z&umxGKo0$7^lS9l(TAe$@_gv(j&=bcnL07QQM^SiuZ+k@O>LHUVvqh2G2jB9(^5?7 zzQAopR5(Jc!)7n~WMoU?2GU~W*Z&_jvtK6H>N3P04kH#<<%P?4S;RkQ8x=QqkdEkAe9=O?l$z%Z3fns*L>njdn)e9Qy=YLFY=amSBhg}hr%u`lXcykC;P zR~#%M>CeG8;=%55kF+4kP4PZ}qB^Y7!~4IPM_21*Rs*=R1^Yyr+Z#x?<9INdxV*DM zpMII#X1aK}Im>|9#w)??3ZrBvKj}pm_1zGFCwc{4wu=f{w`Iv16`QW;o@eed=Z5no zjtYuj$rb)IDknF;@_~3OB`U z;*tIH922DJ&TTLzU?-_)+QqEF1eR%!M5Dxrxe-u5Y-ZIX-~0qhx^HQkS78}@AIa@; zkL+7fIHOkbksDkSsL0nh8x>+hT|r<#TWdAesps=E42#LLsVjy4Y_%(8pTc^lEaU1$ zcD0VHOYG`7T)n`qp3l{mEQ}&OsTBlS69!yDrUCA-#8LoOn>ksrMt04|FD0)m3~gu-vWD6|L5^su7v)Oeh;D>vQw2FI1P+ik1a*<*k6U*Gtl9slLS8!t|d z8A5g`1SF4{vWZttzK^?(U7oPZM5Q;X4wHvCe=nV}ZNif6alX4fXOZ1p?&rymZe=j{ z8rRN`Zqsx(&i7Hi{R?IJ-l1(0nsL6DS8b`nhMJ=wRC?pX)I>+1y={Zou}@++Jt$pH z>4JW5zTIlvsB5&zPTA87_dEpnhVuA@-66I-Iehbn?zYmk&}9g5k^BQh&yH?t6Z&Mh?|u`Z_blVHn`B%Iq+sO|g!(;+nm0+GID7Cen%~ zma>e6{1EESjsT|owZsvxnGGZGp&aU=frU?7{|BMg#g30;>>Y zk}LWr=G)@7g>@y1RPq9iv?0(OH_T<`;e=s-mkV%VCR?0u!BiP^-|J;uB6VJ}`eOg?_^De?l{k zg3#c52&k)xsd2CFnbDOwKy;5&5Cg-W%K+O6B}r=JyM{`7-O1(NoA&&&H?p0(`JJEn z{HLb<9_yn}4<``!^9y@E^Ix9pkEGSmtHtBPl{PrUW!2=t>cIgnL%{X|m-BnS^usUw zs<(!cDITfeB2z#d8rm&&!a#QEckkOi`H3YLGa5#+oBh{}>=@|^pn`l4x0;jr9Vs-h z{EEAM+!Z+vkRaR@kxs6u<`3TSATJ(}mMl@1e%ifoY>LBwr~OnWXAuqVeoD5}3rH!E zreJ#k8_o60kzCZAi62fnFz!rzI3YlU-y=zfF!!1GXwo6liG|Iivz*Uq$a_D(AHvVl zKT$+eY?R^x$6_nu{9aU6t7X-ZBf6x8{0_fV>^y=*rF?`Id9Ei+*gaA^s489$e)>o{e8nDWcpxwI7w z$dOBPHDcy)X}(5G1!l)$y9LI!b2uB%ur8E^CSRqCJqOAOhJo2ML(mdF&R&fR0Qnng4;b)Dt zsOA!6HBXsR$4Dg^w%J^^+OKe-tnw=~)*8RU?q6wF*)shM$yGDt)6-YW%qnE>(N++? z7NsR}YKq-3zn&&=iUrsS`7{8}5GHiIMYWwkb(XE}PG#MS+8=>2Yt}70JqoF^jrFiW z)~)iG46<&I@oEqwho};)+Y|rG2=rmpm|3^;p8;4qq)b8WyncgqDRO@>fu2PY8vQ%e?4hXOonMpo9JHCt zC7LOP^p@S$c7DRLc9@MTsdmzC^@StEP|6D16dw@X9zl7s?O;>t5im+_<=;3eNeRl+;j>L1n5w~Xdz4OTV*UcXLZ{PduB)e4d z2Vy~c?KRz%*~)C$R+*6H8;6Dly@6TLc!Tdn`OzV{35jC`HRhg{SN06P&tBWO`gmuV zvVg?D5g#3%J^Yh{cZ^>L(S+#7)%0y;w(6y3yF+j`&l}3d3%W+{7)|dsvlGrs-)=tG zRoUum_2Ol?)zD`Clx##d?{O)>MA0dp7rCerbF!OLi5Esp2SJPbNIoM&+Jv1xB~=$# ziblLgCZ?RF-fW-OilA$)R{9N#*0%S3mTJi-)fAhN?e76`B|MzIM`zr6c^B@tls6V< zYxw1U?}(dR`$w3$k6I3(96LwkZ`(0C(=YnC^LPLBla&2>e*61ARW*{o_l;k$ z(!H<2aaJ^4*1f+`xA21Azq{rIwQdtc&X*-&h6Pw-c?LLa@=baR8fN`q5vme8gOou> zrtgxJffH9^F(LNhM4zG*Y}&;(SWuxH@4yiu<6l$>VdT@aztVU#n^L^>6g|N>p%_@O zTzydEHYlG{IV^%uh=r161xgC#je%vTa43hh zejk0d8bv*!4IC55z63g*wvO6fGI|E+#pHq$ENy5})P&H*7>2ZUMC-muQv&f~U4~B& z)DWc%kAP+&!=qA$+elqYAiHhk$Zk^y@4XdHc5%LUq&wb;_#QIvYRw2o^Yj&xc3Ppa z2N(l_v=)XbW#S)uUJgoa$mKsj?^Hdo2b$MV0_(P*$ZH7Cf?omMOcZJ8XZJ322nYJR)KwZ%IkS(@*<+!zL$%JDuevdANhO7gtW2G{w7zql^AC@Tq zXIan}ll5w)3(3*GLV%J3o|-2~7W1>8{qOF=g!Be+y%52ioF#ZXPVOAHlX5;%~Y(xe3#iD9N6Du^!$X5bs4uM7~ zHEk5vC6JtnU+$XkWv&P>cZc~_+#fu zYM@pjv^8EX1*ibTmi~WxO@69I4TF$I7hL@<0i09EnG_$6u~@N=#Zx9|P4eeo)nWlI zCy+oFPRNaQI8vQH7mUwSZB<@mBuZlqF)WUpY9aQ+x9=}j==ToSR^r2}EQc4qO58fM z3^N!f=Qrxbns0r6-6>q_AerSAV!mx%9vke1-SNV;UI^gvh5+uv2LKw=&}}l_CD?@m z6c}iaWZHDlyqfy8(T9@(->3;Xj@laK0~TUR!DzNCx$3_2}DI$w}+HB=f`n1GO~Ph_P=xG`rt zrDjA8u%xL#3pCj3gMGf^lVebiu@6w$K>$X+@23}wi z=Llg9zL*QjXd#Ks>8FDBvNL({t;$T=Dik!#8C6FRcvY@02Px7d*r29o#|xzBC@yg0 zYSO^mDzqK=7@%iOBSLznXU)t#7kbv*VcI+p);Jc`vzl2*&(6dz)8G{Oqfm0B1cU4a z15R9n+au$p07Q+yqzj8SK>HV7Vd2nH%&QP}54;=Tb=-OROdqqpfm zZ>*O249n*E9I%|6LO-?_ExnqQ7MOl}ZNv1i?`V^EV~@JS;!S%d=^ZcH`C zoS8FxstGt<+_yuMA^J7&ao@~Hw5z-^`c@%dvBXsxpvpcZL6uV*!n~D45{#qk0iXrJ zK%JEO{Isv%+K)jCH2I_xt=STFZHYQ&eeCZ$pg~{BTH#2B^*Hp%Lh+UVXK0$_NXiG? zDf0X&6J6rZq3spIwHAX=eY!%J5od{A#E+dX1s&pHHot{7HXOx-j`H<&+f3omdR5-0 zb#`Tbj#b*Us&4v}(IV7HSsu%yMk}cW8*xpHhIT)f5o%sik76TB|daW5q4-oSw^?kr|;vA5nbWml9ELF<=8iUwk232mx)IO8!ea4h|N<2zI33!gu z2aG9#UF2rCd1%nWFPp(A?_c=!x3lu?W3**!zy82dI|2vU8*G_T=;x;RIK8#i;Dukg zIKEv%lEPj34U55#P(h2qN81QmH>p_he_?leE#>qUba<%abi<^waQfabw?bf=q(`J) z?#j~fg;qwx2$hYHH+u+377cmxUU;>7$Qx14M?*X-mUcAfE8TJ~+-D`%5khkJ33V&1vxG_W~kxBlYszkBcUk7)G5CBELN-9K(6lLl|NOl3g(RvXQ zC>XrdwQPW{N`8M3R6y=xkhMmwc7 z+G)d-uhYsAzAR(*%w#1;)fS7EQ$_h%FIq0omY?OKWq6~uXo`Rv@qk=4y{LuhnAh z(f{^C7HhAEL)Z=2EO>s;{bY5YExl%T-}i2L?Zh=*^>HaHr;n;JqpWE)AK3Hbu1Ud*w*V5KyCQ=cpWv== z8PEalRunZoI>;jmce6vIP^YYHdqg3k^+c?QLi;BE2y-%YRu-Iu%_g#wV-SXdP$nfw zk}X#ve05FJ{b?DjQT^10b;Uvppuh( zp@}?DiDdP|X02$_3Cyk6qT!Q-OJOvykLQHE#e^xTZ>Ct$$|_=_l})3+kBxXRNH%hB z5m&LwWrHFx;7R-3^K(z5<8YW)agVsex#;4T#gt$-K#?;6YKP;#Y= zp;S~YEYmxmnKCtP8c&MX6twcR;gK=})2A&{*_cgRM#8j(t+AT6jFr;?tHDK97cKWwmz|5(1l5uBF;?TmL$h^;!xjc!a{+i+F_k z-{(#D20 zwWv~kwe`)meHD|jv(BulVj81}+KNLj(50_@Jwum1TX-go!9-QaDBN^AlR>WNS0RmVYaK z$J@~(fDJkEfJtf?o?~DvTf>xAZrlu=(Y9@UWJ(|LGTX}SWpu>LJX?s>qqAP-t2I`} zfV|8XgRBg*3WsN5&B&6G37%aLf^y94;#Nz(c<=t8vmzi_1{RkqnyzST$H6EOzFIDy z)ulstpli^WBBCKJ`MN85x?J)#CuFr|?6{P`YU&YR@>PG7_(5N`#FZ<`FE8dAoVFkr z%sC87&NG5L@p3SfWkPbC#&c?FQIly*jwFx*pt6w zWCD>z3S0rtK5N7_rfXM3d~%HwN(xZ6U|`MMez!xxFfZ=H_={h?$P0N zrJN6xA;dE~eXA|=CsO>H*kk@F&YE8o2k1A&A$k)T^@!_4=7Gw4M0Q!;Beu(OI$KVh zt$`l7t%^ZSI4R;V_D^LIG`Xf!Eb8ZjI^hQdbIBGG{_Yy>u9juZ+>v%y6KHtjdquwX zsI%H^UAStsvx&ZQfWVR#;IMA+E$K*CM*nW<7)+Pn)!q_!42D3I8fYMFDQ!Lj0(P8#j{0!5v`B7xS`yOM@qUv+aGDCL$TsSk~)Tc-kWc z=>{Eu)&&wBop_u+pj9AbWj`KK>}KroU428wxx_Iw<5zhX*c%ad)(O{O0V?6-tF`X( z;pgg%C7WyHN?O}tzDXx-x{$3%zpq?I@bn6G5(DkUcpO*j2d4>OW5iLm4*DdhxVt*Q zk=l+xYjF*A*5r{1dHb$S#jH1oLE;gY>Kp)>vuoM6x-L_9<~nO!LW)zVzfK~Len;6F zaKXjeTEHW8-fQ`Y8<^_(Xnnj3?MFG@*vIPu8D}@%iE=n*T|b~%Xf+g()fo*%n4AHx zEL-E(M5^F!$*RC$o}GwY{GJ5GUKfH{qS$32sk`EL!J6|YUh+wh35W-23eI+wqp}7R)7M$*px-wdRwAXQx+_dS0gZax4wk4Z5RcojENN?tDa(q*CrdI{ zp2*3P5AgmlK=nli9njc2+9#l>+c5W56h>Va^A9ns=hzeC-R4{`gy8fwDEyh0;?0oh z&A)Fht>(0FjUwvIcAJ-qz(78UV3C1*LIS49#!)DW8N(P{wzSw|Xe(tIuJL6E3!8eN zE$9Jby-+>tT~@~Pv{=FpXFgXqMZyj;H=c~q490(&GiYAavD_Jc{s@i^+35i?A#aB! z;{y_Qki;fivKF~Zl7j4fv>O9i#<^P9(aZ02*W`(aSqUGTkHJ}Yis^Q|1s&K}LID$y zwrrcO9Gr+yK^tgEPqO@_+0o^!ifLAaHEl+#9atvw)6oDQqu~PPH2>opq%@1gmCEVLjR^Q%af;VH;nbR+My# ziXoVppb}A;E|;H}0cxKPpZG0Q{2GSLunPYU16W6$ax}6;YJ*U+01ZOG@!3p3i5(ZNK^j|(l#VKo0pTTZq9 ze;QQ?jDTQ6c-eZB3IjHACQJs>ySG{MGjS%S1CaJ<`-+i84`(@r*JheQRhOb4;DvmF`@AwTukC*bT&fiGe>S|jdhfYnCDAj4%v2|qEEz;^3PD8e&cNpU3#o<;Y0XW zty>C^0y5-lAQg!qW!lor9$2H#YmHVP*J7CNZJieVMoYAp?!VL9R;xGISyZ&aRLNMM zsndBHE~YtRVs-jO+k$+a)?v=eldFAR^*|d&81en|$*ZL4?$`H}pQgvpwVTCH3QxFfH)`jsK0 zBM$h4U?h)?5)GcDv#bPgIm=Yk)&LK@0jnwuJp@=8*PkE!K!C+uLk3(Vfk0)NJm~vi zA4u1mWP9(Q$V&TsFg?bN-Mg}y1T3HPno%manYyy>6ti%qMu1RK$IMpi*K{UQ6G_U5 zJ&)aO$8CqQml?LeSx;ko*_vtS6e4#RZt!W@l-nd%`BmoR$@Uo1&F5e9$$2~CYA3(N zCfBmlTrAdQjVv@>3=vN6`GW8b-)PDf*(z24${Dy_Cj(#|LQTJxO|7Yj6Ggs}?T%xL zH{s~!mne4&lz>P9fq~ZhQt!fc23cSTi?cSN@;h+>oQ&} zxtrm@U>%CYko+x$A3CA_?Gt=kn2=!BVwJJhn>9ydyiAjVws7TO8|HCy#J$8>GgY(6`dWt5K&%?wRWqnet6IgkdA%!>6f6@uZ>DvPfs10Ko zD)g|-u7Icjws(X#MnkH#f;w1)4hFeZGyvH=qM>QV^Z)rTp8yQDRip8wAQ<%|OW(bl z-ibGSJ}Nto2r{3un)^%Pc<%l(TWAm6HdmR--BnhW+qhKjZZ(xlt{g&>?9m}%*essN z?aoe@C}C|gz#K6vu=6aw`N*(l5lK!;7ZcSx_!V(HLJE#?mGdj+c`v_mRqo(7tf5Mz z7mL%k2f_u$%0Sj8FWxWlvkd~D{RXs`=Vmn|0Rk&A+4LL zE^@oSOfk9m%i23l5_f-vVgl@y5CC zzo)p`#^%K{bKPfCTU z4RZ2xeq&ED4gN=pcT~k{a2sM{??|?uCs2O+U*9K&h8K#}*L9LNY;Ut=*LAc_+VtWE z4o|}kj8r(t*XoV)igLYietE+i7la#Fa05glm--sL@ykWI-uR{RhBuxWZj$U7CLUKa z@N7dUT&?Oe{CauA8^2cGph7m5H#2kDv&)-}bJ@QyZ#K_m7loTijpRAy4Nd<>dBaCH6*ubs zLF>M)wqG2|m6bo+T;A};e=Kecxb}vTC$uYN@&;L6=xu3NXgR$}x)t@EC#XT&U4utI zW+yzUU?f}-veLRT4kfumTs1FnoF#8)YG+#HS=qC)ZvLDr=hA6b-CuAgJ~6K&+2uDpu@}A-QoFKmJ{!Wz>I{1 zl^|VHI8t8#k8$-B0>nfSP(@7vau-ZzHW0!3YhETyR=Ud*U2jTDrSYgbL-3JJ8zUci1SY%*CGHW^x0 zvzq_Z4r&L|=}j^P(z}K0HFYox0GgbYvo%fOL>~1_AW<)q9pGC@LQ_Rx5 z0r#5}4e&8Rs;_&ze3&gp-X9N>X!_h1-9cqe5?|J0fF~m#V9oP)q90r$1hz`IUzy$? zoD0W%*CZ4@LRYl?40XmP?cR?1L|W5o#}J6poZJ#C+GN}(-kOYuX*m)|rl;)D3emDw z$Az*epo~6J(1$j$Goc7Z5HO4dbc*{x+iB)C)EXCAJSwC&w`o3!k*?u6$|Z<=pC(29 zC@&@y`OvB3V+Ar>s_h{&er+axgj|!nuf##x+Dep_i;bSGtvMfR~)tJ>OXad(n7XR>Ej zZFoCO8LX)&ips66p((bup2_yxu(ee&z7r0>O189uY(Z-bkS(e$am&xyMMnD;OG_^& z*qINqDWOHuH0zPm#b(dPDQcPs>nCH>bg>yWZ1%KSbQ4JU-HM~EC%zviI?pR9Hh9*K z`or|X_L$)ZHINzEfY)uat=|Lou^h->mBA&#wwmM=RZZo6=GiCp3{;Rp&NMb@A6iQO z@E?mnF3;kD84%~c)-1yeit`O+88d)Z=i-DsDHI=|5qgpSi)=gYrQT>G;?kz>-Q-%H zYtGPZZ|x4ds!w=U0L+AWXdu!**bJqTPD2dry zJ5qrC;0TeAVP9>K4%ou-49QeWOrh$EanPc!hPbk57`EFg&4lc@5s8z-NoQ1Di??Jg zSiC!y+rsl`HY!m=T!q|=dI%ONvU2UZ3FnIQgi^_Pv6w3KO3Vqei?K&5$ga?!H`iB{ z)?)4aQ9yD>XM9IjXTwBw$iCkuzq=+mOiNiFws>2telG2JG!Cug(voLz!WN!(aHf4V zN9{KseO0&hyw=xs14v%=+}6M7lBB1}T>1|>*VJTXXUr^%Jdw1+@Mt}|MJ8*3iL~d6 zN1TD2_>=ETLe3V-uw?A`35%k_>7gD%V|G51MPLozJDc5*joiDLQLckwoV=h9K2PYWI9h$ZPE@d07 z!Cc9Vg(~VX7>qQ-Sq+I^U`SMjKFly|kXTWLWk?J2h90YTe{}PF5kky?z zY=tPlK)D2Ugeq1-l%F?;iJ`H45tL#ea3pRzYZRDwyDd+g4T`lKo)UFgK)wV0v9!%@9+F(Ws+lpP^wYnB0AZuFc(9Vc^p53$joA{F{W>n9PcDB8ILh~zU ztCFLZsLYXFl?A!YaB`1sdy(>fE9}9_dCzU_4!96@-lJ>Kb9)Uxci43uLAQB{ zbG?oBPD=8MFSwlP`{^BKiA(VQEN_izE+6Ho;A z1U`ad1A^9<@PKydU4aGTgdQX~Cloj^PUt~F$J!_`@GK#_2LZoiH46CtifZ(rfXVf= z!}nM9)YV{#pbhr^iGUv#7pA=KvsKsCV_Ekit9v}u-KZJ|V6v8h;5bsGS5ar__PA&$3DQ3Q>evHmMKy5Ta5_Z8Z{;#agp*sR8~p)qoe68c>CP zxi0Gm@rI5tHJ}E)xxT6xU$zJmD32fsx9KLZ_0B){wjLIP+j+A1+|HB5=XRbfKDYBc zx&%C+i{u5-l`;^yohOUW?L1k0Zs%d~nVo0$-r=Nker4yaBzFLyEHnkLm|w=x{d&OOs)!joSU65 zCMRGleAE(#CuZwKJnOUd+|J{C*&aKObV?vndGnoR%+{+CCz%*46wm-$ukC#Fm~Fk4 zkIvQ$nh9MPG!xn?XeP8((A3y^9NJh}5l^tKXWFUX);qs2?=Y#)z}5>k!2nw?pyW~8 zdMgIldZ6b~+j;>)7EQDl4`bI zz+RuN7ohmK+j@O7rDApxqq+;r>Pckl1^excY`w|HZ0ns@*?Kbj9oqPAs zE3W^Y_Pa9u^80O_c0;^^#cpN|sWP3%Tk=(6n8v0=Grrn6J62ZUM%{KR?QDuuE^qQ3 zN~2kO_I=-a!|~6(_0TQ1T<^=WZKg1rVzv+})w9kw#RtdaM0d<(xMykpdwvWdhMWB4 zEPBgNj*a*Kv-kc{b{*B7@A+|W_w8TOl_lA2OETwP6w)H*(P0=#%Xnt`^fF+NnH49? z!}6P#wH|-ukF2&IF?n8Dyf-@a;w$wi)St5mKpL6S+Q?;vV*RK7$q$kHCQSS?u$L{{(e9*;2 z>VzPoiLwYogW9S>4(clRo<$WlWD6FgeEWobJGvdt5|LA;;YNBu10eb(7}bvM#)~`B z8=9iqjLlZ5J23;G?Q}|{QEAt31h;`4YJd568Aym1pig$u`%guR7 zIhY#`&=iY$lH~9zjZ6j1kDLfhH6lBLRZC@7Z5N?@Yi-osNYqFDA8p<_xgkvO5ZWG1 zp>IR}cPUPiCQA0n>$6Jmc4g}12B4|qSDSZVsJ=6MPgp&6+=hmV(bt&Du&sfzVGYuQ zq;Jh`nT@C4!%S{xsF*@+L6Uu)oV|7oyldr=^668Wwsc*3^d7ExNY|55NILYH{GT~k ztcim#YQVHpm$`Lu1s6~y1l{a3Y@y5j=G>lvY4&tpNbp|KOsB|kxQbXA=}SA8@kHb=`)W zF8V=w?IfBF_4jhZ5`$kz;;T1xo0|xf;a9>vX^(#2JS+f^^@?;72TFRimVRz*=u>wy5@n`$}j4H*K~ zd%mIf{#K(SkE$d8pr7ue?08R}tmq@Ki2mS3HgI&oA)ZcBxp_Kic=Bo57Pr_H8qE1z zHsjIQe-ERZwTT6tC|fIrDq3$U?Z(%ovBPqFXfiCf*X3}eS5XW`+XL2})xvrelKq0! zD$Uj+wHhr=;$r>vRVhl6Rq62dt8o==57*FE7i?vzrRtO^TcO^$# zz4C#)F}{4I+S}v2HN%|2Y8RIOXh#2FT7U%d10-A@3+7Qv;l;?^O|NwXD&`ITcq5+g zHfHCe|6#j=HA<>!3PUSoqqtXQMxC!M<6b)-f$-k+vEX_#qsFgFny)17Pb9)H&Lx|O zRyh%-cz49)fK6UL4=ebl7%x{-M$6u)9XZ<_`bVRj7v|@&;FWGP1izaTmb8{Na}vL@ z+eqg*x84SVG1ClC$b{-Jd(cc{LA*eHEXtt>p7Ei0>++CeVb_1kv4h*i&_hde5QeyN zAxS@i%&I}eE-*SO_!`u=Oqr#RaZ91uov zqd7F(8W|lMpIEcDz3#mA8#bPQ!Q_P(ZQ8u$;%6nD?z6Z4)N_7%YTI*v<`Q$WbV)FT znA-oVb}JUR3fsSZAB>DR1$-aadZgfDnYVxat>SNpBo9*3to(00wP;~{AV_kh+Q=xE?FrM&s`M|Z>RzB zGb;sR+p2)Lr3S=vR|>?`s(|>78W7u73dB#Z3W(h`Af{Fd#B){!#2afs{PaqJ_^DL^ z@tZXup0iRQwyp|@H`Rdnsg(lp>{S7AYYm94D+QvvDj?om147v(Rz$W5YhV+Aa9iet zNvb*F_MzQ_cQ``$Eoxs|OSW-nTd6~UYGM{wx^ZUQ?Kn%^Ns^U<^jk{?iTPg^NY7f; zRPCuvRnj+5OB|PrR|UjdYe49{i27_T5r{3T0^)5oAd~}SML=v`6%fB&17gccf!MSv zAa1Jxp-e6-8VQn`u7d0Oof;5GE-M3q%+sp?;_Wpcl;&ndBf(KGs{rC1H6WC8XGK6< zuqq&KuK^)iydogZUlkDVtO0SsN`W9%-72QzcWXfCe76;i#D-M?aYqdZrG#4%5bFhm zsi!1Top^igmChRNJ8M8F3(AUsIB!)W@q0BO)~^%@(!s9+C*D;9LMgjeG!kuX{k=Sn zxR@#D*%_l%&mB7ve0P&j(Uic7fmJ3$Se{7g9{GInpSsVND>#{Br?XY$6}syBjQxn) zNoLTKxShV^FAmNJsP_2ZLc9yxpK@nc5R3aPI~fcHVmj*a{(ja}0VOZ@ZVl~{cscNB zS&S2@=uZ)hdzTC&XtpdE?GT+6YcAeXLrZ0ITM=54jc*leO> zCDmII5FFpQ3Ly5?fKVd76#;=Jv_i}J_K+HF?cd1XR|7&vajpmmS>4eNqmDfZb?=2B zY~NRdK!=;I2m;H(uwrs~e+>vRL@NSN}ii2XGnq|jIq5Gc?WoeP^Dr*ap!V4-)M z8utfpVW%~%2*YSQyj1aHv!Qw7>jA||YSv1ylFB2gOzBDz`5din#*{FiXZ*a7v?dxZ;y7GZ|%0|o(T6T zOwW{XA$`YXNmIv*F$jV;X{Z9$S#~ThwN7>6tpGJuyMR6@nZG@R7fRpxH9_5qX25CFT&TT-#)r5JbfTbYg9#jj)a2TAeZ9{U(~f=D?x zH88p*D`$R7-p>4%%%0gTm-yAZ2k&`%Xyd7zHhOrce*U@`!V7nB#wkB;5py_Bo^AaI zcSMissvO&7)_;V1`Lc120<%Hx5nXpjYDT@(Wgfl?^b;=utLkM=HySq*(4$a$ZbC{q&5S0C^^ThHTBCKK5iemqm2orCs+9&eraBY=O`t} zq&(W#dZ^PH7{v5Zo_zeSgSlvYU|6Ct<%;us%i*GYZ_~0a;o8>7DPFpdSF+I0Cna2O zkM=XBMlTQi9@O)w_C`t%>w4V1p%@yG;=STr7VdwPi3}MyPJp4@W+gk?IIJ9PtkXlH z^t-QTsJBO!?7#*Pf^I!NS?3A2UQKVafvWUYAv+dLY0E5qO2bs?{KC6Vb?2FRPWL(+ zCi>9l>wTTydrJFCp8fnZ_x%gBlzRXdrL{BOi_$%xsJzS6U|##+F0jQdRrAgkJD*{g zNQRv!S6$gW1W(eheN*e+&LQe~3emOiS@chcQA=-DJ)G>WOM8Pu{T?xyULO3s%SS**<#)Y1*jfE|c?Q#Ma5#CSm)HcFd)qV6zcqItgV9kKDHG z(!Jp(pLg+SNk8p%xizyb%veV_+0JS1r@XQyfr)N^>?b|Y^bQ0HAg`V{l>g7m@ne|iAw)DS8GwSJ!ltS8zP zM7gszG*11^;8r-~r3WuPc zF5!~sO%LAm;7t#V0K3^~_fYe~gBKpW@Ze1k-t^#258m{k(`3Bq;hZ%+XbF4i!AlQb zdhpUi9wLDZ<-;C)*h7vEMQqF|414gV2QNK%>A_16UV1pEgQj2Og@>~tl-9>g`F@iEhiRXS0GxrNeaZs$JZQkGMOR5@7|qb%i2{>x`v@)?&bThS=i z0-te7#6>xo6vO`SHRIAjZ+h@i4?gO_M?D;zFS0Xv(*xF6Z+bYLrU&o1A_16UV8A-gO?tBzE+>FmHf6YsjffmAycg;g(bq<9=z?r+aACHf7*l6 zbnCPS9l_$m9(>q?4}0)o54p10+aA2_!Jqcv&x-S&OLN(AW93;3hl&iV+!bdn$b)5} zc*0%n31^x?QsqwQPB$xS^Z8nR(Db={R-6vA^U{Nt9=!D6r3WuPaE=_RXMa|lKP%4L z9=z>A{Qlt{Nx(}F{-kMdd&q4MItt!P4_Cy!7Cu2Y=GE_gpG`m84QnieKJy z$$Kt&&n54<^yoY1bLruTmmYlFgO7XgaSuN3!N)zExwwZv@n^;Pv*KVq{8@3CPZK^& zHE$<>R-8X8?(9A*F1I-(;kGE)5glbUr+Xv$=t=2tBy79=l;6o*`<=T?;+Tq(ZsWxh zkwbb%0k5~V(G#{*c!#r>0iSq9L_9y3q^!(nZ5rJv?=c*vJ;I4c4DE)Exs%|5V zUNRAo5G;JvL^#F^$76FDjON;z#4{BgkJE{lObqdGH93LJlo~6;16JCJu0)!VJ4*Il9AA%Bj=cOQhL3-Mq zm%ISs(=Pe6OFr$APrG!^rd{e0ARhAq#0gz^9!6ey@K(4i6H}B+d^U73P>=HD<9G4o zfmsBo`2)kdc1V&*4^jS>!$tYt<}UaC0-t6Hw)gSM`L05L>VrS^!Jqmt*Nu}nXHx0pQ2Z?v`}lO>>=C`iFQXL6Z@p64*1jYuoKXC^aVNHhlEMX%`@T-c~O_cmcu-5MF>d zX9WmlUU~wlAr~aP`N3=!$KNlTMJyA=nbS&p>A_16UV8A-gG3@^9i*CAgn7Kze9OZV zor1PSqK`i_uE!Mqt*^=yzGlE!I)l69NPlLWKQk`4h{YrC3nHeoW#nV0)14ObFoLFL zA@I=;KKh{&{qUrh9=!9CcV0SkV&b9Cn*nP-`t;e?$yl{F#C4EgDQ2z1x*q=vd*dG6 zN86*l(yTAs|LA;>gt+&0!%c2ugPK2jpOtQ!iZ-mfg{p#J+@Cn@Z4X|0@Y2Jcu&{9N zE^p_{+rvTeg81cj@ynk$?WG6ymT40dTHJZ*VX7XP;xjM7i`c0TPkHIVOAlUp@X`Yk zi_g5|LmzzRC0y5JjgS1P5B}5#pSRUZ4~&499-KMc40CxLvOJfLd+EVT4_C zeCDMymwCy@J@~i>ANSzn9(>%xIUV=#w3i;d^x&ljFFkna!AlQbdI+K!Z+j@5nEa^^ z{>(Vl z4}IK&yk$?uK>M?%SAMd#k9(+ueE9PoIGF2+yK!qzZx-p$` zk9*L$=dE*(b-=o ziYD0+@8Mpj>KqNnBROLb;lO_t^m1F+_Hhrx$P6tz<-x~2biDMi6zO4?mma+B;bfwd zkDAto{3zSZ$L~T%|G=z*Iu8u*+7YSz5an-C+_x*=+uY>@t%XM6K341|xG_R<5iw!I^IMC*bS^GXsa5#TXhcSkvi zo#mu#Wq_HT-}841pXJ95dd*7@F(SdubLp}0`Z+|)JHxrDDCns09(Oy$?U8Wqc|p+e z(nIHBMq|L_lCJ1hP&d)F_mtM zA8Oi*NyBU`1iX6rA?RF$RM0l5U=w$V-EHQM@sl*Qh1-2LlwN*7Xc)3^2Z`s&Ng^M1 z#8-In;bg8$LuY`ieDW{QURSb~9{4?o=TRjjr1Y?^$K4zE=swyW?QJl(3->=dA28j~ zOS(gwD3?vUkv@8#m2Sc>WZf;=k%RH3Ots&AJ@?zAJE?(RyOl8YcFWUxBIAQPe>NK* zme%=38veJ5_-vTy)rb#E=xaQd-ti_-DSbh@e}QYBNU12jbzte9PgLGz#wX|6AKV4D zL^IKh2*hN!L5fTs7>222^CIanzxGWzT&y4PbXmrSVYM;S-6FM_l=M^4&Tf+KyJ@Zy z3#ND`0iaMj07Y5~XwW)CT-imt8&R(fu`eXUS55?D$wtAApU07~{k{*;sf)(*G!m($ z4$htxfe%~M+-1%MWanJ6B@Nqe+|PFgMJF-HI*0%XkDOL78CLG$MphlhsH3GXguR{u z)t2pUEO&O2(%^7?j8Bk`UJ8u>b>8(O zpLEGhl0R%3Jn{!V_yZsOfe-$`2QiP@_>Ce|Q?~9##PG%kZ+w{d2R?Y?!)G&g@+^=Z z5LzWYY^+KTTTUiDgqid(jPwvndKfb40ZC+8(gV^)ReIQ1mmW;EnCWaBgHbo|@CitU zmLNTBETji-eDH@&`@^RFVblJwX@A)CIepmltzLTYfe$CLJ%Ar)we2C4;U(-fyo5c5 zm!;Vr)K~AiBu&FJZhP?3!%uYJ!xtx8y{=2%ami%&Ow#pX)828(6uy~Hjdxta#b_fY z)C11N=zMM;a<><7yWnmoxjp1=FXWbUJMirCj!QBTB%?$I={m9_el?et#Rerfy5W74 z45z_MU6jz09hVB5gDjNz6@)J4-Z{>N=23UGBWCfHW^nC{KvVdAAg4s&_cL^wV? zCaCOL8eKUtSgZ*3j!W^$27lVQ&6T(`g_%oJEY3Ra<*ef#&U!g6O+B4I8(o@~*ZC8O z6+L}D8^wxc^z~eKX$lkkl&;)_chX`;iBROD*QF^mmnKXR=F&7wY)gDj8YRLqo;uVB z42q^b(YealNg!4t!Hc;xZ4q62#$B4e;Kho>9Q7{g-5@o6J{waK`FMzIAv;%nFIIT5 zB3@umNY?F$AJVnGBR-((+8yyeUDxc0_v$*aBfeeNang_JItDYW>uD7$IBsu%Sn&!+ z%=qu>#R~0uUZ!9WmY%xD%M_Iuk%f1iJVs<0d^Ry6UZ%){C(iOPiO|awj+bB@eu8BR z@95+moxG!ycXaZOPUp0v(|+5e_BL=VHdTn19-`y#ml-22EfNgTS!t2TgRGb4>$4n- zL{I0>MvKJqI)4J`p{K8BqeWsFeLdGL60vfMoX{e1f*@-jCULGAd^Vp@Pr}NOAlUp=o6j1^gwzZe?Ei;p>Sn9%_*7|_h<6b14hkneO2C~Yx-jK%}oXGnt*Oxi}ucJEhFq-ixn&x!af)=|^(d1J!`4mk)Mbn}wnjZAh z!{BI$Gpv$ciRaQXRMIO?@CttTAZy!8{poUEdWd$COk8mqK1CC`gMS}(TcdHAOaEIW zk)>#7f6zt5$q#c|;p*puF>ibDwg+!}@U{nUdpM_U4+_ihwg;c!RUzlv@CUkWdE0}x zJ)Gg=A-wJ3Cptxwmma+I;H3vIJ$UKioR%IQ_R@p5J@^E#F6EZ&EI#hRCwMh|dU3d% zKOSPxX@!ZmJ=_y@nxr_1w?{jTM6+_TX&~i~wuFOAnk??2m`=hs(|PpK4w^>)cBZk(VBz6c2_9li(mnNN0I_u((wW z1?lM1XnUmelKM$LdVS(;58n3RZ4c+P?Li4-z4YLv2QNK%>7nh9rVcJbXY7xre(?RD z_R>Qv(}CFB%V2(S>U{J^UziWNvNVkAkfLo~dXUKAr3VH<;pLof#+?H2-AQL<;5mn& zWl!93Xyp@5O3R+OGtl6st9(2rvmma+I;H3vIJ$UJ1 z-b)Xpa(Y2}+NFn&O^);)O s52sc{xma?4iX3c-_g(VxgB>ls!TT;9Iy>bDJKoxh z4<{BMbmH~t_J?0h(xo9CK|R!a1ohA=j-ak&oKok{=CJ9db$)3FKAee(KJ@v6^PHBx zAGhb(*U9U5@5ztG%d=}Op|3wF2R;l-t1;8v!jaO~bA~)Wc6O6=-%WF!6Qpb%N@6>L zdLzfz4Cx5!;VUQb#IjSFIo9_`*nZ!KV9+iy<+14r8>ZrO&-U3fj1QJp>9Qj5VM`je z-?*Re42n)-kaf0&jk4M9{s}8M^I+BKS-7VXxTOH{n=&o^& zQoqtx#V@|qjmsmbR}?l4NEy$u*b&r8e>S8b9lbON#zCET{peF?MttyL(>`q4yDoXx zCGWa)4!bU08r*KXn?Ek@WRb&Xv-IGPiwk>2r?5wKTAK8Lgn!z_#MMX-OPJ`N6zRby zU0RX!;17K82R>M^_8yBouvF8#%iH<#_Ha-;*P&hfI#z#>6c6qxf*I2N<*j#JV$<-h zOF?HG?a7hAtOXO?f=1ioptFYC$KCB(Zl83wZElad+jZQ6mU{O*Zb4SvuICmM)~z=^ z#Am7L0oNrjJ@}+cClj5{X4}IOIBHJ2@Y2H_S>~Ku7qETgPD*KBy5|#>Qntg%x%LNl zp>B_6oW6Y0rSvz)-o#7+{GT{ zL@CN;yfdLo3uP#mMrW-qL8pzcn`0s$k27Dh2!T2O=bpCTb{~+zl*jTj`?#d)B&M!z z^x_FJwz>*bGA^&M+F{qR)UoM-$8`z67GoG^1-V-%07zv-Xn)>vgXATfk4=Q*Q4`6Cra9#P^D?(#`K1{ z?pWG>6&bX00)pXes6kT=^*ESLJL7H`x|$va;&BJxI7r%8T@qSlR5YEBZxVI0aTGSf zv*s0KBR!xFnFS1C=5{Y4S^n=HTY0+*U}wQUUmoOxw|n2DZ@s_YcQnNJSxKt z4AUBihK5j~H5LRxND~^jPNWs2vFeyWSyYU6r+)|vpha@5sxS-#t7@{SYV(q+qRlCx zr&b019V_&BPyflmQoEPLj@*Deke9$safRR*iu4m42K!_r=Mx`ZfF!vt8tK_>YZzjJ zO(*(BTjG{wUT6PdvtvgC*#|rS8$ow z9$mv_&GzVOE^D_(FXPhQ9$i6GPxGxX59G{!enkR#A`%(2|7nj_VZ1GF&xSv5h%tD? z(hv&Y6k0Z!eO-t8(bHAR?1$73ofRG!eyrjBkc=2kU!d)zyM`sz&h-RBnXVKMt-K^a z(VDEuJ_rQySpFjk?XES8Rn4%hQZaL{il_2ww69skNm(*E*KPC8WLW|@a;~p~GhPR0 zx(d!z1su&;JBLkB4;4RvdOZJ8Kpl3@8%qL3>kAbyAh->BY@Wq>b9~cq9;Y~cT{kNB zZd*V2jjKP@XuG&|faK;HPL*jF9~X(~XcxCVpu;Xc6&;H^BgHc9j;5h@jFDtSOYvqF z3pm9>2vx`)r2jxA^WBFhuE0(v(+mCcKEgU@&1pNzD|FTMy=q{@>5oIvtX3Ld56um4 z{5kD^QM#1{;?fLmW_`H34UDI|V=&E+J<_sZa+3JcpruRN`n7KOqF}_fwf3)F%7!U= z4NLJi?E8UeU63~ALvAD~7KQ0RoSq+qj)!?HhKUJ48ioyS;Gvvjq3p4EPRlFc_87Oe z3Iok}L(^wS+H`k-H{|YG0Q$gea!b;BV3#Yw@t&+Oyq}CG@B=sgYTCLn8U0m?)a~hi z&lu1Y2E^BU4A3@l25CU_?}Y{&J-2AU595D-yFhqjGVBR}5rBU?W7B`u5P;J+_kQUI zXFCI^rGJ&@{0H{h;~ukSXw>keI)uD!~{s-d*q zzW@CaHOGZSidz#|iQx+CDJJx5sRnoow9S2bYmw5=U$Vo=4oII(EmCcq6@ zSgRT^;Z_`V(LmDEk!AsYvjAT~u^qG(k|UBPwIq?iZ#wY%YTsGbK3#%8sNx*_O5I2Z zsv8kZLu25FPJn68i7&r3isGB2o1$#+rM7TynZBTLT?*P#f-a<$4Za?5sFZ^qj-T0U zt8R3TJYiD1CjIBr+jP@AL}r7eg69R3 z-5`yCFoR#vH^lJ?;4lNYzxKowq1C|%Z7{~(JlYIVD>wOT10iL&ExH^eV^U`{OVLa^DY5W~X*k*R=7YewP&HEIJ9)&u`7Y|& z9?6mR5k23IP}-QitPB|?e97@ z<5V;)QF$tQq2y$RIU^)1cPHNnoG0%7q8ietljudzjC?VJKAsd2Rb3Q^?eE`jouW5c zArp&K93WStJY;@=F9Et+9{h|doaFY;p7`v^`qPl$$?FQ!-aMy)(A|c))Nn@K0fEqn zqIz{DQYXxGX=@ruJ}csvfI{(7fqyF6AYpeZYInwg*@3Fxmm5B)U#hq4*A<;ndw+&v z*CW(SJv}eM|cK*6Qioc*krKt&TL&);FvbwZ4ti`!Fc{A!pQzUe)5#`(fTb|1R_(#?MxS+q3PPfOn7b3!u*acOiL*Mk=!0lvGZMm z+mW{EcWoyTvPp$TcjWCU+AK%9^PS>UT-p4g}4&DFU@Zy3DhNYek zD%ZYkAM_z*-{!9&a<|yOBz#^lzGkQygi+kk&II8R9l>qliV6L6Hn*WP>@dTfVLF}Z zUwf%1rVuvfVfOiEuH$WXTH}qeG_oWPTj$b9W3yJ8FLhVSPkwKm+ZJUGT+j>@Sh5V} zukd4H?)gFRqHwDz);7DB+msuerg(G)LXk%Y?66D>QTm)S)LI&M8qQ(ujJ4RHMN?Lu zu@;-zNtHPs32&xrcypQI4f=S8H)dw)Ky$#surmtY3>EtN+OCV0ZFnphW#ta#cr(-) zb9h69UV2%EH~*nP3b(CdIVcckr=}WPVg+q})}akav3bPyV((6IZ*ZEL+E%HyC1(@s zj5@se&#LSUvHJlK9)W69cNO)`>W&`784FlYh{!mR8_&tH`oVrKm?eWHRy;13gz zRjh(VUkn@?U1Mm3HO$Zm=w)VwPIly$fMra#B1#$1YaJ$i$!a`vt%6Y#4x`R^%MDsK z%sS&OH#-wBCFMV1)~jonwabnK?c#>uNE6mb&DT1xYMj6Gz^u$X--}u2y?6pv?Yv}N zvL?r@HJ$Yivt*eAeH>=}pu`$s2AH7Ox_n=I+)D5~tzg#oGt9c)FiSysdiz?wbl}RB zB_(W6kgn%81NuCNS>LuA&s?iu*0{s0Gv0E8mJPGcc+1VsxM$LruTTN~IyWqtWNIDlJ=O^oO6kFGsbSS2zTwsGk zv3Hl~V^;i7XBreJ2Bv@{9E?^$vEK_F@!Ay{juBF9uiwCn4&Kf>ZV5UTsFU1gP+#D1 z>=vu?3^ogrZFER>=9_NNv|-tqZ@SspD5(mvwL5ZF@yNW?!}Oie+*DxlcqDql481j) z+ZH%(nO|?re(gr@(Agkdy^z0)dU183j;oJ2Ts=R>)q@TJHc`h#{A~u7^M$Lt(4!#P z{NjnRv1D_yDLFsK)$==B9Ijpju7Z#bS3gG_k5q8=fR!98-{JWuGF*Mo;i|$q zL=X3dJaYhd&gb@!gLMnH8Q7a0vi`Bvc_!NhTQ73h`V6$)plw6fXQ1t7=c2w1_pv&P zJ?T(vQ;uSfyJ-`eUdZ3Ypx7p%7%%jo*u^iNKpR8sqFQKgklch&L(c3aIij$+YIcB9g6+A)p;h{ z1;s9ODE17r-Joqlv1g#|X6Hh4pFweN+LEMkX)un`WCG31^TVw#3Zy|ndyr}PanCU= zo_T1Q)-phUDTl1KQ?{VllPeDUoKwoI)o)WsWZPvRw;%al@mAib>48*aS_S)1-agYb zeOcx%7oh2JN=4HInJNlT(MyACcP?g_T0|%nh*J(k#97`z|5^b+ z5{Z?S5Tr;Xs`eUJEwTk~I02`qSPW?9BZO!oA3O~gqKUlnbSuxl$aKk-is5Cm!U_cP z{{zMuHw)vJ2CwFG*iPPbyl>Gc{H)-*-oXXeB2PdyCeCENyM>2M&U3d4!-~v(x&p$U zqObzOZWV5euXP}7yfh#uVvxd?@IB2y4GI`wcm%^P{IJyWK7Ouq&E3Q8q`QU5NiJ}= zuuD{e^J8U-wTWeg6(IJja9ezX17gFaY}GWt{>-ZYn0;@pvPEZw?t3d_r`GqoL)lA$ zje}qIp4v1h+B(YLzBquW>?BaN+oow+6(sEtgzAx zc2z;4Y`TKt!b^k41O+6GcO7LdpnzHmibpaiAdtx>*B%5id6v62pJ%#I{DaGTM7W|HUOT^UKkW3T>@P*x zKb_ZaJeo&q8oI`{2Y?5!`@@6t=y20F+x7g?cyyyP9^G&<;}Il4#-qFSy)zzhK{ZL4 zEJd%;-S+6!G>4_=M)yk$xf2=zp)?h}!kLPG$(f3NIX4yYQN>iGZ_S6cYAd?JY(?r% zzyK6ldA+N`MQlZ%IPkgLR`lV!3tQ1s@?3JZufyMb_xB$C;a7fVi)>##wxX@V0<#qv z5ws4`P_MD*1{sT9Q8TCrDo7!q7S=8)^PPpH$69owvlh{by0z%lnYHMKUTe|4WuNxC zTiNp#e!b|^m%n!C!wbj0_~AF-+}o*|xyWo=);-%^Oxd_t_pa{i-p-!hUDg?unPO*Y zO);}YrFS)Z(W^VoUUUP|3(gjn*-|RKyMOt;vxzc;QQ14&P>adyu^45OS0YixVx(D| z?&;1Gya zm7Ky!e0ce|YKF|gxO&(q+CW0nzY^^XuPv=SRQu zTOWBpQR8*m37IM9&{#DiGsdZ{bPnNJYpA-2?Y%;8YPR>KP}2itFIPiNGkUYEIXt=b zy&>va>0Qk>{p!p%eFGaok8Qd_Pd~W){*}{M(o?rv0F3a=8K-Z^jngGBAPgAD3w&p3 z)@jwmNWxXfI<1=cbpxE8S*O`8>(*)1(S;=B%+s$hhVZ23X;}H3RXe$P`cJVa6GvoV*(*ldGKJT}|p5{=CcaS6v}hvn%M|kOYCZi`)W~$oob2a($M)q&~WCkhRcd* zM2c%5_?(9r;nmhMUj*|NT%xlbi$hLpA#+U>PBRB{`CU~2u64Ds@;Xo?xH{sM*MU;R z)e)_{4n-tcU&58wF_hJT(}nXQjI}7o#{Rn1FLL$!>pfti)-KQ(GSTL6U z_UIBQz^=OvN>G{N_U(?pPw>}!|F_@x)aT!JDx-Y`;5P+crMoXixc?1z18ve!oxR}tp2~0T;jnG9)8Cc{{E3Y z|Mi4iqAAv_cjiJ3?fgmeeVaa+@7s^gBS0y`>D4hlNUw0%gMOzqrBYaVKiFSb$C0}>c9x2M1VHYzo#t;$g%9uZa zQ;#cWrW~velr;i{8A>04r-)D#masVbR6@aTyaoH(e;Mt&mZuYIknmhSgk{o1^r@-tJzuKVr0IPbpvIb8SG*&|Ym<=sC|-Di_DXx6*(p6+iD zH1c}8l@Y6VA2wcyUBaOP;OK+kR)#Nejo*-1n`^T+v#IE5bDi4MFH-OT4kW~yi=XoeHOHlQQw3e<*sHBCx+%xTQ$8QjeDrInPu z<}w3_-IkFuxu|%>%vrW}Av7>!YUuglB`*plT$5PACiy5)MXcS5E`BO2Dy!C)FMCn& zv%GIME4L2Idd-*lGM?hgOm(&>3qW|;m6i3S&P3%_S6Pi&ivBy*fW>^`)>Kgs5^7dh z!m6>mdPnpMzHtU9w?wK{-ioo}|Ka&3%Bx zJ-vW!g9@}HD!l_;v%-3C-YSKMcB0P7WxcS-!Chu@&C0T_o zsDkhqAbdiV9p%Y|MUNik*JS=n!*hs6AK^V&YQWDx7NUc?Vl`XP7314Ix?)e-tLr*v zO_N=4Ucb>ly@m_+E$n^;ru(SnliNR@nVanO95w@do$UQV6yCcUN>{l3XqQ(fa!!_7w4e<6(Tx5jO_JwGEY1IkgeTp2&2yTKll{;1 z843abhT$~P-<6xXC>UVT_!(ccHX)5?>g-%QbKVu3k2jl7P>(;D#v#V(KrLMa|XI2uX^ax89}x)&>dX%ZP~Fv z(9|}SCMWH1NGvp1njX3;g;BXi`86a@AG!5KJ}C|ipAH+7hlr+Ilvf6l;?+9M+nbN!t3&Nm=L4l;3$m#3HwgL4{d%? z5Yh(%w3^!k^#*pb;qK6a54k(7SCorxrzY1#RP#8J8&PH7c03hD?d&a~!9tLe z$t8%X-#v+#`VZ1&iM9NR6jK+@Au-j#dIrVRYJ<SQzR=)FR?7%GXNiLg!NR_U*#cs0L!_}*N^O@^MY_CQ}LZiAg2n26-hG{<^k7p7RL=VjWIV9!?@C=Pf3?!!9G8{2?g2f?0&oF#C zXGkJ>hOOMSaMQ?Lu3f2cuddw^o|?MPwua}2rG(WgB&^Xw!Wubs5>~Pd0qc7w5wM>4 zi59T_^c)hf9IR(hz^XR*%nMjmXwH;?Rc-Sb6tHeNr2|vx30bE+GbIlI;tq+BHCY8QG$xH|5?pi*TB!IGU|`Hlix*{i zaIqjddp_SAXlA>tdxZ#!>9Ya~!u!vL!QkkivjL1d!xMv{kdOj3;v6;N3^nw$lAIdU zC_Fw~24h@36rCibT@*PC2UU?GSDfds%d)AY$4cUZH?5F9SxU%D7C0l*^^(6S!(_6w z%cv(apfh;zT}jtpm8tnQR68%2wJy|8P&~^a6i^^%6-#QMq(fGKg*?b}4h2EF!9wS3 z{aHF`w~TDPE-XGPXK1bB=vhTiO+Y>tCCO;kNrni6i)gaE*~)*ap~0;H-|1YT>LQW) zNJh}B4U_4=J-3zA1LRSEAR0&}Au3fM<6a;Qd2=9#9P;8KRh>W6TyCA~K=LwJ<1%w* zhQmWW zl;pv-U{Y2pWm*7jr*n@>GMVf5RQcP`I>~=$k!BpxWpSIQGc~$JqbMc2LLCeAWT|F( z+~XpTd+z{~Z=IgG9P7qmjvZT4bk#>Jx@tf|i=ODJLpDD(dqcKoXgg4I zDxF+F8!6tNio5!>d!V>09wc0r7h^@RLoI_kV|009Su!+2(|GvEp{7iWafUOf|9Kg+ zbFhrr`PVXL=bs+>#~*%V|BwFYdA%_^I0XI|8C5J&XH<82CT=`RGh_>&*$nDm|IBCd zu(4IdSXs1Hh)IZ@p*IfS;>XTpjMd%ce7(DzujA!>eeni5~42P~v z{&g}YR?EN|?VNd;bHIxqS1bucJBIz|4sy<&{B+%k8#0AK7gUIQuC>Qc3Kcvx(teK; zpl9Xe=pyS({tJpiuy_7zDmyR_#mkO(H*!e!&Ef2zO6-?NH3k|PGLbeqZ1YpmFS;}P zNNTLY2FY4u@Sp!o&b2>qo5?(o%F(HaRP^$z=Cn;aVAh=&ymPL*mW5&+aiEZ#iyn5{ zlv+p2(y6)bI!bLI%2GC~^C)Ex%Lh_5aHiyXN-M*wQbJlbP+AVKrQJe^+DNGjL9pRq z;KbUUPbqO6@D^GEF|kx?;##|lF5eOBJWsNBDf8LdqIDH8u=xp;?hVFvUF{7<=)771 z8}<5H0qC)zRse3~AwTTXN&^<(uCP2-?pc}PJc8~-u*L2(M$quu$R0=-v@d&4E>Uc8htd&-X z=o{Oe!xRo={~xhUYOfa0se%Xd0&Dk4`H$vcXc)IgyLey$L)KLL`wAuocWB@VJM)*D z$D@A!&E9rjwx8Z>9n^~&41uN(s;5rtRNk`A{=e27J7G>k_$m|53jQTy9& zx$DE-QvlOfr|XNByq19iEGx@i z)K@3*WKSwfUr$)%YqKZi@)!0io=)o^CuMpmnrlC#9zqp*y2aDoZZt0Gj*`GXc4_oM ziMjUM-shH_nlrkX=$b7|0nG0LUV+K)0!jhL?>cNr2ATkR&;Vlmc1IoB-4@-dL?5`| zYYxJ`Q9jZ?BmKQ`$OZr{}>qk|YJ7^#WW{TKdz!113{_6Wk z)vqZl9uz3V8>4R7p(&uIHfM{6`nzfq-thCced}oaN@iR#lKr^;IznxbWD9O;ob|<=-u%yv1(+1v>z><8m#R=gnNhqTALGX?MF4DeS6s9J!oRsX(Qz) zIpuJqjujD_I8Dp8>sc&pLA|vPmc(5lba8sOP~SE}JBY;TOYSHN9Wn>{@V6a|aML)JJa=Xk|Jw3l0}x8RQNyox9ZE z7yv5(Bu@8^&NE3T~ZGYZnk$k9!4c@a1Hkb`W z^A^?kH_AZ22pU(gI(m;StjZdT>%^Pxh}ht1<8#FZ@3cFy!3&Q06(0=eMok^@!K#QS z6cSQf;e%Dav*3gEYr5cr^=qoi2Op1&4_0};ON!;m7;~D*IAR7@9Py~u?=Qg^3jrKs z+|X)MFXQ%sf*o#%9iA`>n?43RET&mZr?JBg*EPrDs?^wFQgoGrq|zy|!^-4umfWxk7~zr|RzZy$Rso1oa>FWM{7PXWg@IP!?I8{LBXCI*A~8F~ z4NvI(k{gC9AA>~9vdM!~yd+M`VN8uw>Y+HBjH5D2drW+5mu6Ihk}pYr#ala5;;v50B~O5ZNU$|7 zSreA=y>znd9$1DB>j3j3Y}>CZT=G7y=^@*(n4Elw-S<<`p-9-s7}mJtM~q7z#Nz1P zJ7Y&8CbIp8qTBnqUpGzr>s;~xZrb&Q!4M$AAB{`C?nU3A1|max!eCaPfbU{N^`xW< zLjEJ!0@CtS_o=4+$HtNNiB&v3E=(cOB&?bE+^x1JR#{|0VJtGzYQZ84T7DP63Pyex zAPO=`w*|-o%u%>aWTk zk0;`otL$;fL&FHy+2e7s$DG2GtbskAsItfWST1|q235$C0KGK!STxqA&`~*UgZvaG zIrg~0T4(64aO;O0GH}Uhg+YdvlU~JWxi$dNa?aPaov233^>B(;GdY|D>2ZAucxraJS&Cz4^+oj>~)rxqlb=9{zg$~q|p^>g&FhwTXp8yO~SU| zI92|&?Jsra`DMbkjCmeNuEw<##$ji#hwEt!;G8R%eJVNUapRoFrPpBU`Z(vlgAipsbjrM-0rxk*O)0P{GG@Xu< z9MT2XAzfO=-HPJMHRKO->J|_z4(f6|sZ&xpOhzu$%n(P;{zdXGZE0dSSyP6wq^@Dx zYq2fEgSN5_du`HsDMIxK=Yo-{C`L7fSPc_xha@eyVO#%VQbiR^>jvsKe!RxCZlrX& zpv%VKPKl2U2QaM{P}L{jy^1Ig9rY@wkp#QFvm3I-P){4~|%#)?5DGFdjEnSfc zM09e-731O|Y5yoHS=LR43xS)_)Udf`VsQD;H1FdQyV(i0#fOc7gw~8R94a`H7noL0 zOMP}1c(}lUA|k>L&{NJ=t`}6tBJE8zzA|)(>3G%tBr-g8+E?QiYzTY#O0<|_NUzYv zG_4%Z#6DMQTOGSv8z_!(g7hMatK0Md4Sbnww!7qFT{3O!Mrm6&nznVV)3!o+8EDbyqB{&dDPD|^ zWD7Drl59l#G$AMABcb?%`A9g1K0ZM2!bfI#^9pV2so*04^9bFkEKlt&Mwe7xS)eLs zoZS265*4b~I7lU=a9jU}MAcI1(DAIG3-D=lLFbpM3m`2VbzgVE0G3Fh!T<}(`*o(N zhZE|o6GOyFt0BS&BvCg5qq)YCb=QFzhlBsi3~jr@9nH-!70(1_+?pvs#}Cq z9#Uy*4{?}KVbs~}H6X`BTI4#9woZ7Lv+4tOFXJI>pRnC4PSLdFTa&g&sc_33%}Snh zC2mVoi9j_`0u``<1+l5BeV-01tSjeN_RU3-&8k>emc#(owP!t@Dy8pwV_ny0OK@|q z(syGYtSEigh|86SfY!MI&KS448)|fEqoYe3GP<-OrzqJ`hHewsuqa(J@+F4unWsw; zJ3`S@14x7l<>>%&3Nzr;+f^ogpccEjN&F~^LuG@{9Xpi4Eq2;*Hv+H>%7TO_F4qTB z6J9bWIT0Qrl<*)b$dZ_HB51;|1f;FXi57kbYP^xNvcbj&qT^r}D&>ZG8`2CJgvT1#R zu|d_BJ}LRboc?A>G(ArWRuEnmQgB)ll!UqV-`^vSZ(v=RVA9WKb^YmsOQ`Fkzp1)x zsB1z1Mly^Q>6fWX?wX(fW2;NNQ81C+P6L6(3NRMf7+n=S4AQ)r(8ifU~dOuy3KORL*R@}4sf(o?WB3G%H5>qpD zV{jD;OPk`AMc`zebonvBgn&$V@FvQ*&KF7pBIGVUpbVQ*o>wD3pQM?cPa+E*3x#!v zAb>a()462G?xrCXJPF%bA~^96E>}4u12FhG-u_^oqhLmjYAfU$mWx>dxy{Bff-|Me z+LD0I@F}TeJk!PFjpWa|pWeX?XQ}L{rW}9Ght=$47`_EFfgr1hJP*_-4RX=v>`s2~ z#abIX5S0t9j1STv>qroYfuHm)s1bPSL;N+l&~1`4pRbD45Z z=u@OWc34HP>qMF}dD!6T?QHn--DndzQycu^CZ7G`!gtnQ^T2DdYQ(em|H+$gcny9c z@ynU2=F2I0l&3G>#3y#D4&Pv~=3WpZm}UL`e8YCZ;eliscH%v^ADjo)oi~=|J=&gwh!K6<$S?7ecTG$?Qh*_h0=!VlpCX2s6avGbnEq5r%2mOr=)>V zr}$NAwf&EOpbCi2jS{25Q>>OtAPNRBQ#+JS=Jh}qRS)a27@X|1DF){WtH&~JRtY>y zM`*`RDAIz!pKpx(Okh-ID9r+!DkQ&p6hxJ{Kc!Ji*QH1A;hJv+_q7bAsyUxRhix{v z>1TfTARjgRQEG!jDNY&EhLHa|^@z1OF~pLF7sP_85J%AFV(h?o<@;$9=g_HvQAhLF z86JRDB%EdQP9V zFbG#NOYGbb-e~oJyH98qy0}k@4ItaNIG?vZ1URB`a=j?$xB(>+KIXSiuvG36zIR!)+i^fEADQNX_5+c#nE{V7C}5-j)rbf>S$Qdfo3v*4vtlwgEph^=KyB|m^-Z2yo4cvN=2;RDjRghDG z9O0aE?@DBXg%ZcMF?|D+LL`AFeHz?nK(m@EhLd^g4i&hfy?bRz4k29TswdXv5HqK!F5Q9i_-VRz zEUtC-6Mz21yZ`piTkiWqJ193pE3Jje0ThPB&%_F*oD!{F;~RPR!<-su(*S1@7F8|^ zz3%sEZ9r9sFT(f#?9hJqhYvcK*g0(rk~fp8;TM~>wkuUx@@p#?$-nqU@1QX(ki2YI zzW@5_u>8@xzWJ%WfAWbp{ff97sP(ouk!@`#T@d%K?YThwe2#kNz)e|BZ1J{rM8+fy z787JbG6yTs?VU@Kj}BmJSduU9_{c%w4LJ$ZFLH%VO+THZQWF{^ zkv5wxu4=rPHX6{uBXKgIcJLfIj$Ms&1&3z$9C+IU@+BCA#_)hKg!5Yt4)`6XD1d=s z7p+0;5Po*=*WUj5*L{VWq0Nph(jk{>YEbns15KEL!ymP7k|Hvz-Ztr4^=zm^Y)R;l6W;K|$|9w3{{c9*SHlR0*R$z-_k`PO7&^Jg;G z_RZyB(8gap(Za^-G!EnG-??6^Ky@_f90lpukN!g>UQpH8`K^ZWHs;RUINc9m63B~eh&i8 zYbXQKS5pV3lpDF+<*L1b+aI`Y{xa`B@i!lO+m|2tr&~V4uJ?+v&TIJ`iRBtf_E6(I zHA)`}p~lHVHD1o;V{S3daGM3!q9&caFuXFk~>MYup%GN9YFk~y3RB{rU!It z9_7y=J}3tGVg1O)>2~g=ayzIi3*sTJ!hr{M-Qy(a1G>)!eINI=LElS(nCsj0(lJv^ z*qY3{Ataf`_gKBq8AxW{E$OVOCT4JGj*?*ZHvslYFhFWR3!1l}0k;v!fgh?>Y-8=p z_SRlxd#gJ6SGKxz3EN?9o2;wwlDK7}vx> z7(*kKO6LbIMAGqNK79Rceyb{AP$a8ZJ{fDw2wy3~v4}Y4l9d(*vi7xiK$GV6rLN zclxI&n;4oKI>{7e*>N>D#T22l%%@12_>)XgrG{dPR6{mJR>MiB=zGy%t+5+w>0<*X zL(3sDG-=GC$`lToBXO>kHI1&`?N=<*HSSK0{r0-C7ziAG?soD$m_(b6cg)coyG zBgQNe-Q2uM{n8?cY!PsTTR?Dg$jewkG>6<9q3T-&`D&m7TMxsUqegSsGJL}iIGae6 z{!d#=;%1v#M%Ggl`+=wjKa>WE7K79^O>J>*PZ@CD`?dggc3w6mik!aM^1;icRCc2E%0|;ulS}jch0cdl{m@F3PH&K+iyAh5$wYvmk zM#v*fJx(yxfqM0!v%#wjd_I9?ch_DuVaS%vvvnL~w~o8XZqRMbjPYIh)~QT=kL zW#({`sKb`lj;(s`bg=oU#04F4Ua614J4HyQwC#f`&RQ7z%vjWrqs2_`KP3ta)?`a% z$PNcE`xs=HeG$xY8SX0TO_zQ^k3`7|4JT4EFt|_9lQ?pgB{GsFAYd}A(#Ca}G{yof z#Ol7<5)&mF9HeE-*I<%KYnd=*YJ8db3YfI%r!tpl)rxf)!ZL@C$uJOF6VY`kXh~CG zVLLOY<^5#?5%odZ>Y_Q4xQ#`H@bPn!!nt&8`LcvN$+fHJujt>Uie6;cTrz0yH?aYLmjrL+F zCa4XA24I;PZ7btlN3pm-u@$TYk+R;^d3shtv>Gr)AxR z0;b$S&C9?Ng^rDVxk)Od=%&JjD5*J+IO=Z8HRn<}xm}%L@x zoPtX7nurO$UCyge%t}V}u~2bvqp(~5@>jbUsug6Aza$a#*k zHw|b04mfTOCBvPT9MofO&s@L6M-OaGh9{`rB16VFi6cMpkYSRANlidRsU|opn=?AP~^q>1M?{e=Jy+h-VI^Gan- zGI9HiFi=8_6C@l@mX~QrN^=^VY+(oZK=Z_Y7z=kCoF8a3KX?5w4%|tXG~_4o!#E_h z7pkVWzZ>xk%*g#P4rk>DGye=*i`aUOSov`Kqdk5bf0w;~yK~WSYnS)GZspDP)9xaos8|n3!1yJ^fPu{ z)O~1x-W&@Ia?di;SWY4>VS$tqVG2xv9>~bauf!;dAy1jak_4cdu?^5gE|a3qn0EAu zD64r@xG!1!0p_zWnoA7|RK-D>p$d}I{(kPPp*H9;{I+5_yQ74`i1kLCOz6lh4}M1K zVR>_Y?Wsp}D<6ZUBzz==rI9X6VTp-OYruI!^rWy%y0k^`q&mz?u4VdCf-ZC&RcDcY z*=-C?wnY5Eor#;JCFN?-rKwEDQ3s~4?~bTHD3^Qs^X=~~t3MFWQ2~grO0{R!M}Z;; zwTVqdiCiV>u3-9fz?^=^oOZBwhHMDX+$qR==`~e&O9(d@L2yH2yXxUr!n@`zQMi;X z!E4G07b80rJ^dcMZ?-d<{BoR8#c>L|e4!%$_&zWITjRd>an0?*|KR-Z20KB3O@C_( zXU$0$(Bi3M8Q04h>o?zZ(1BSX9qD81h7e>@=c;#`dsptspK?|WW_8 z|M;&kH9}($K@Lbic!yOiY|e}lIQGto-H&S5IKRBBr4o&1 zn8-fHvn1AM532nllL$WJ=pZe)EX(}5nqLd%6he>7onXf81ed#=;EH@F;G@b;pl_#o zc7iF}2{d}Otw67;aFM;>ZQuBGz8AdjUkci}=;~3XC9~?ViXfS+I}y(fb56UTTkvoa z$YpsD9B&Ej2GID*ZXmFrDa>EKmx4^f0F`4IeNpV$zxKG8edyR3KS1SP>ujQXI?P4{&UKbKnP zHoM(!vfS-#U#WC%q~5uataBq-=d#Uizw42x-UEAz3H#^V5>Mye`}9M9d)qhua!wlX zp1zfvo%P82W^zX{a{!TPVX8A%qEOEiLN;o>+~B6Lz1k_Ppyi#fJEYk>AyMz?W;ul= zf@a*xa;C7(Yst~i@R5|iIes=ow<}Xv<5;fEIF_rKg&vOO%Srs!S9br! z_rCwJhdL*m#5Kk8bG-wWl4H3#=U7VWBaUSt^;sg%qMB$)4qNans)=7$vtJm`Qj)QZ zX{j2P-HtLN8O!;458P2QuH{%BsfB63wxtZ@Tkc;{;`=v!;^4fb);{*XC-Hs1+f2Em zh{wp7mlJW!Vll-2zl;HbhFk%ugZ;nU{hHwyS^-;dCDlK}N$e{Uz+ad6w`>W(2;?GU z(GtDa$)dWxM1pa-qxsq&Yc&6gjOLU3v`+IYJ^EkE>rsv5m(oqvH}AC*VXu}7HBe+t!W zBm-EbrI%M;e6Fj*S;eu~KF8EQQTmd~JD1kpNnc>rX85pe!E+k<5 zo+U_#s6w%X}G)GXpLRT0`AN_?~K;AsN8#( zk%d&wo&jz~;ECO_0VFcXQV6Y7WNL1O3XEswU~#ii1rp`(-E~ov_P*G}CS;~~gOv9a zn4O&l%{p5c$lZ-ZiE=J(stjMG;jqWdN7!wyiNXN&HNFNI1Y|!&vy5*HkgDDUt4YXj zCl@hP|1Y1zBG3UlfQLsQHZvvd?ARAtgrMfOV6*?`=R~d4pqA~PH7l!;F%7L0Ei1RF zWj4m#rj`s6yWF-%P+*|!&e`}Yu_~c}76xAwK~Zhy@&bNA4csrLqGFm`iU|`(ovb2v z7Jcypf!She!3%S%$@0lN<0hk&<>p8X=gl*^8tw>Cpdq#a7Z%CXb>)h0M#+BTluVTs zE4)yFSMBA3qYhjOaJkK!SAViZ8+@ciVTQ5#GytKqoDVz8d5d~WOWM*5$r#OLNN#CR zvf494GPNgWo}zXw9}HD$U^%Awh78mQTvojqVyzcNjBVWC9|yA^Ta!z+C=T*eaBBzxP+366pRlm=KxMTu2nDJgMzS(fFYXj_%5u&a6=Zjz z4&Z9;kI`d?PUMV%EhkNAHVfLQ+a*6X)R0*+#DDAAc+Ae%Lfau*rZq8ohK&(IC4W%y zWSU$EmFOsUsG`-`A-!1r#|x1b1b!+*=F?@?$prF>Og%aqwBP$7ngo7hnp6|Xs0o0< z<~O92gE9UBY0M=aOB-CEq)je#XsCl1pZrRxi2d$??g+I#kktlhAmW&eOnKSt&Adyg z0~cF|!q{Ka9o2Q`Z14-5Juq_3uXe*tongI7ynDiZOG)xWt(1gMny>9*o_x8XT$dDF zD9Mw?Yhme{iehdiqc5jdqd&h1*V=%6EKV3`^UE4ae;mF_x?S{Ryw`fIDpNhSL{Lf( zzm_jsu9k*sX}DS#=8jqCWRSIi=JRauyRF*zLAYd>6jU-B+cNA9m#>r^A#mljg4}gP zAB+GJD=zB>J!~c;01z=KV}jK>28{f4@!9~->-LH~0W%!XbU19VVQs@(Fp$CxCPKsE zc6;-(Q?mxhumi+(j;00!qRauPCfF`58ho*F92+!_5$)PIYU5SA)fsT@E;0l9K#=DR zvl=L>xCJNS*h44LfbThQa2^ksbnhp0UAI^S`U=8?QNl>L+;tZfJ6*@yowi%*s`r2U zjZc04ZAaey?kvG%@}Of{BQiscnhqf*JJP=SF;#_zt@sK!(@b7oB( zfA{rAa&y4DoaKATx@3$1rJ@|=g(lZA9s{iaGc}da=`?Z7fA7!oK2@v$OETNk^j)QX zJTn6Hjb9Ttz$ikL8AV-<=Qs?yaAB<3m5UMD2K{%gbi&EHQCZdRfs} zF0q%Tg`>0qWW8L@3@%Y)xdIDE#elP1yCMiWs--s2!uXSD;;3>L11%hHX%G!nN@6Zp zK(SA&^1ohOT_hfECAuP{IwwWKmP>Y(&O{Qgq}^60h-M(4h1d1cq}|gZ%mYa7THbe# zbiW|q4G}d~?jvu?;=JFc4lrdz;4}yb;XR=Z@)VZh1Nl~p#gy|pdcBYTAr43Lj0}r; z9yhv$+BoLqEqT^U6{)JpTxV{~tT2Lt(8^DtluA_-$0Hj)q_^J}aZ7R_pe($d@6250`Yna{1%gSMr+L1DP8 z%Tjyc>m4A61?VjhIJs*TL60qxC2$Iaj$(|JZmFIlO_{p056U|t39>RI&Pr0`X7ATk zpWLxqnk;&)9Luv|E2l4AUJ=8?j1JD2M+A4k$hfE*mZLE-rhIBdD7~pYA#q-|7Ry@l zRZvDqGP+b`_**V+jksnsP1KcIUJ3Aks*bcqU=m z&Vi+}Uk*)>xezU6IHpVafQE^SN1vGm-nD3r1=`l%m7BUl=G?;1q3ckb4H1pD$w7tb z45LFbl!2f?$zfi~j6I1Nd#HQZ#jlN~D4vS$#D#)QTF1`#Y-sAy*@#PHY&PZ+kImxB zje2yJSW*E!gz{2UZ(KgLBy%ynnTVgJ8bn7w>4Jr4(X6QxAiR@6$37W_%^oVEHE&pN z`_Ld8gdS9l8Ad}~0F1VDx9Y)>-ZgLbOqTSvz;ZMzy4BV^fhrC$W373XjRI2g5)3gz zl#CBp7R8Ea^sR_8;IRw+FYvyy>TN}oYlXF!8-uL#wdD}2D^=r9eK{PANexyf#plEz zc83M#l8I+NjQzwjA4VgdwPCDL&c0#PA}|p6Pd6^6Gwz#CHcJtYB(^PKTd-ARO!xz4 zTvp-=bX?v872M(XCHZfgSC#}7IWkwD#s57FbEXLj7P~n(}Xeon{}-=T$4p_F*abwE$or4O6OyRWTo(uu>y-aN{j#v|y6;l>(|= z#}H#O!|DlorAE~!S_MD@Rh-n=*qcUUWs~6m1qN4Wrk-&p@VFx@bU*KE?N_!ihI?CZ zg=0^R<{c~eNMl~>9u>w$;^&gDe>Vu6d20fY@k?gt)tdd~G-gBr4TN(NXF0TjQ3Fu| zl821|dq&t9TGa{{Lf;<;k)tKoHNcdf@rv!Qn_)>Sz~&V=GTWjq*qz-#YLv8lWmy0i zi5|AN1RQWVO%}SP$oOpZvmU^4*tnRW;VhV#9Icg8)&K&iA;q)}k70rBdu(}`XcZT@ zXT2`>yIuj!Rh2nHz$(dpt`W)W%LW5l*fSVql_wvJ8btt^Uuc6(R%_oyu#uyd(OMi`s)K z%E2m8ERidU>uSbGyTJHw>s*DZpjhxiZYRxHB2Z37=@^<~iXy2cbQmK$YFzB7ra@p` zb1Wlg&9JB1$`NLO02vFC>n?E4C>9t`Nq`2sAT(|&*cwnXE<{j@yMctp?T_02jPMB4 zW6X?%tc(`5wDN+^NUgP;7K!J{m!Gx9v|DRpGUS9rUQw5w$KJFyO&b-rKWS}-ITNI> zSHTC3J>9U)r#QK%%6;~Zc%l)PbluAzWfa>*%y1wZ?h_sB*?&dYK8w=J_quz)ux7=$+?E~ksbn`{VKBepN9mA1743JXRc4TCm-GiJ~tnFvnJMMYlLmNtvz0`rxvn3x)s< zV$U8}R>`1R$BDNs7=qI8u*MKr18!VP{w*J0Iko1km^)sL=ddQs%MrMo$)jX9rpj4M zNOLX(()^TLxY)cGI^I3V_hBP_ZU-+9Q^}htN6GlTG{i5hX9w>)h-JXH zSz@^&2_pu z_GX-^j(wy}Gf4BX&lw4}&I|yX16%xqpvVyjKupsE0POACO2r4{p{DlWcTMTR??UCF z%J^K^q`g~MCnEG}<75nkrBIzLx0wuXs?RYpNnm2#XXBbmr{Uynx9E7id1Ko6)k2{# zPvaF^R?vpfpl!A*J!eb!n86e9%A<#>)n+ z)g8+4MA728?ue(H{Voy!+8&IQBrHp-23epxcA#F!{*Y7ZPZd*6S$|Bzz zZ73R|8JP44Yk)R-idiA6+3W9XVn}$lxwWMy;xduwt%DUN(ZRkbm+5>BfDqhVHh*Zt zWXzOF6YfmVMWqSJ5*Vd5NS$Up!&F%{aDM=ozEiDk10ahsq95RqQQE0QYF@r=Q;A}drC}2w!b9VLv0i!aa zruaCKTsBDPC~(y&pzB&u&DB!0!(+dGGKKJlGo}yTP^yFfhScy{gd3bTn2bE9QyKhE z3UnMOi7&${VP=@ZDp43>Oo)JOE=@674rY}oj4>iom9^w(z^S%MWa!2orRCZk$#ylJ z5LIa#0^^oEDHV7xz}{%-gV;_lcRE+&Y#u4tO!bf6Jz6O+&h%(eU@e$p5yK9wKZMJ8 zUCC|zEz1$c=m`uy>IU1Xw*|kXw$1($q)!($n{_5gpQ;oXbWaoo)`n{vAf4)zjb0++ zSPsk}xpM#%_!A3L=gm_M#Fic!W~M6O-2 zy5>KntvH%VlRnliGXcgq^CZ>|bS<}!Y_Xy6&E=$QvBl*U6jc_RsZIHhnE;v8tYW=g zm;hB-VFENWYtD%i3dj~EEN~RK%DkCrMUzkMBt};gVTSkkb`*H82OTykuF`E_LFj>^ zvUeIFmA%tosqCFrZ;tC)XBxj_2gFgnAvYQd8f^<|Pmim1{HiZR9bFEG;gYmw)1atD z&w@H{QR;U?qQAN?TMn0@+S=>*lLg#5E^J9YSab- z2^gi(1OfzY1tn@E^ZEXM`<%1Sx%XCARd=w2(4_7;`|PvNZ~yl1-~R32{%wc71Xw3$ z8$K6&SO%DacLbPCM>FJTcA6tcGrb%+ma{qI@Pc(mk>lK9SUEcm(&}M$URW~z`YmON z*mQ{~IvhiVZqPXuA|}RDA(a$5mQ8~Bf9%qM z^czNv`DY{Vx>;M}44mA~%N*+{u~i-GntIIurnMO6E2ZU)TI8x%Vk_bC!Dq5tU@#9%*biRHQ~nWs_rqxyG>x&hEy%$#9VIRK&;EHiC-Z{9G7KQ z07Db>3atp#Os~lMXc9HoD{?=U^-4ohu+S8srqExaTrj)E_ zf|7;H+8kaj2E}4?_)O*a1U@{m{!FV~lmi{D>K))P5VSr&%p9Mpm&qDEh+<8Ktc?Uc zqNXDaL4OeK^>x*9a4)eD4NSgrk12^l3H3*hC z%mmPPV6M^cEEL~y*TVSLMF#$XY{)C$KzHjKL_6slHlXDW?JYjEXdN2=p>goDX+mwI zo(lM(lkV%9_59T7!d)hw0$+{bKgK9iK-#EnW~WrLq~uHnLxuBNjp7*-m9r}&Uo@}f zi{{3jYJbpaj+<`qT;^UqP`5E2i3p47hB4kOCAlgUn+)AY?r+fpi$)RMYk4oQUOOjw zJ+Q--AlE_N*$)>Q9}b_@3?S*|H<0~oe#1;Vb1QRh?IgBint}_hV=gpVUv6YhLHSmC>xWLPC^PO`?DvB8Z}Dft$&^??wd)6M)g_KNCAV)MwVtFOF!XQjzs?h$yI`c1Ke6(u{{5a% z-7DW`gf_F)R!@+%MZG)C-B$CQ#VHkUC)9)=VGjf4dv90cL$E$ zLH?&}+Cly~LsEB?uq!*rC#TefvY*AMhArg#xD5M^mAyIMLcYi&HfV_rLbk*OE<<*~ zgv!yGmmAn_ZrPio{pJkRrrK}*Ki+DFb%-Xp+y`P2F$B-R5UbsC%@2$N5Asnm0HTQr}~h` z*pNy8(KpeiTGT{V&NeObsnuHl(}(Sm(#i3lj~kYs9sSR!IMrlUp@=JgKmSwQv~~`K z(>mKd>uenYrp6EL^z}kQ8u3pzuCR1gwd)2J&2ry2KE6^LgwAZ2FT`LhuQ^OF@fEVq z@hQ7#Y5et%Ij{DrByCaW^ip!*jzO)d@_JHxo@RomjlD0_Y;>vqqgxbioiv`uAAX*z z0Hwwcy@*eCJ(Jz^9Ybbw+HAk~gQXToQG z?t@_FKco-c&Tn=cNJwdwFDX=KN^d-Lf|pw9poLq-ZlOQds5XP@Pyvz@jevp_oiF>i7VUV}A$-aPz^e;VEt3QDtW zO?)Y1wyoKs&$gvBnJVd2xOmb%#1g}tNw@j5`yW08IBv5r?al|Xn0njNk+mAlwfopW z<6%`;1F)V9uu3qQ$TkcW8-j8_fyJ;>1<4h_Mza@S%kmer7|C)HJbFfGH4ZR~eU%3F z%LcmTbRN}LjHe@|Jf8W~9k1pn*W{-zsS(%(qR?JW#!q+bsaI6L2BFL~=0J9R=d<^4 zXaO5K3uLocSK^xDP(1`+apY3WHIuH#a?{I|{3it7m1HoA^@uChY@E#b2hMtO&dLiD z2=umxPndvBSBzduV$s*u(mhu;Zf1yn?hmZyOa}XE?3( zn9LIz$8@g$SnQ?!xD`(IfB7i`>6NXJ`rq_wm|`oSoEepvwU`~c0wly7vUJw>zllw; zo3(n=;>k(lg~aF0|86U;Ev{QBD=x5?IGV{Ya%|O;DAKJzLLD{nLs1joV^hwi@^48H zUar|9(;6a9o?+H)BfUDR{k^5y3$^b-4FzM;4tMah&zhEz!3I|2WB-X)9NPbAFUPZ6 z4ow8+?{)pVz+BF+a44E{W}P$M;DDef64Jf{$PktR&~^Y=Of*#SF`M6pVL{&7_%!x` z&(Mf(#@Rq40HD^o_q7_VvuD%h;dC1!eJi zb|1yM>)zuHxguSXQ&dwF6~IP87?uq(DGH}3w#$m5Wcf8kQF(2rsI0aq$`mN`<2^Ny zK<$ix+H6d6`oL`@sI88M8n=<4&hIbMy)9vD#g^WG@1Rb#y@4u~4JPCX*Rh?_2Rw!R z07_SopB?xzM{-pZHvT)_DRajCD@Y}?@xv;f#lO)1Ku1^{^R~BL>*M(r4oRSF4~S+VJc|-d zz|0_Dqb0$+uk}8sW5HKyTNAB75i98|f;yMeMeElSno)Jv*7K^wZm@N3xkW$EEO;R%e zvm<}PZtg}|7DpR;@mTKiM7d!*aW0F^Zjdexve@j3v9j1^$EcJA3&hGk9kS>Y8Jx0# zD!z__uEDVpQZ(L1c?%8C9$_S4(Rx`@C~;S&rA)I#?HO9i7%>*Wl7Qz-NhsVrYcD7X zdRj?JP&A3IBO3v(1?33AQ-C#N@D`~99A2GjmVag6KwlB)lJ)>T@*&Gh5PbzVx5uRE zD|q`&cM!b_F1ojzA^zzBo2B*BN9=bv$*Vuvr*9MQJW524m3-n|juMe{UB92-oVDBC zS-V4`Pj0Sx&;!Yw+mNQ8{i73+ZiXF^Z!T!BtmB2Gm6S_;MeP{^J_~7fe0+@sJIIY4Lf;tp|Q{QY$_VkR|#*l8JK#( zQcTpfn+AR!`1KTfrxXje()2vh9c)wjr=6<7yeA)ksKmW+D{pFj!*p#^z_X#6x z*84>7&d+;i##(mZw}1$94p?Sa(|UJJgl3->*X7YsH}_V0dDXyXYI`f^fk(Y89q)Tn zINtaARgU-l!bfcs)yuPpKQlvgonyFI>D(1MLRG1cWXhe*5c;V!qRY<}L%7Dy6+>uU zG6FUK*hYtNq0-CUK7V;Cn6?|yZ_H~Y7Qt92ik705S$M7%C$ry&t zoiuT_UN#&Jl{7ZoakgXlLGPL<^=Q${CkkQnn!~Su_bWbl@~vO3jgdCR7+#u78y2!r z`O*$+m!-CTo@)bb;xaz$pY0fawdma!ir!5$Unk1afa`K96(eZIZ=@!)*7lF@kV_JYdsFZvUJu-hFC1Dj z2Vjsod}pB!-@N|L6~eU8_EyG6ZxoE^buO>Zj!G}A9jVf>*3RF()%>Vhg~g3GaZiC- z!oPx-eis^#ztL={eLQe~ zR=QGOc3ZW&$T{}lp)Yir?Uzomoh-y39LCmd`1>-%tN(->ojYT}mvY*&MF%U8vD6dx z3Z==iVAkwk?4D)x!Z5KSmd>*X&#Z{$g)GQZMebK>GKCgG^@;zQ`?T5~LyFzr5@1>i zNpxU0&f-S;n9R@q=WUwRxV&}~*{_?=w%|FLT8;D#b)9T0pI1X^j`{nVdghaAnDN?3 zUmca`RPjdoGewE^HvNBln%G7nXZt3aG*KHQcVB7*q1A^Vld^! zzN%q(;4s!}_B0nj01iA&eVXa@`RYwTcHfXqP^VUb0eGV z%vj_n4nb=7jq;o6kLMp~TSSf)d1zbS3w8(-KLrp!%r`aOZ3tIG-S!Re*bp={KjHsH3BuKMer4I>te&RI{sx<`!xc;ru5eC;D}4NZC8j)_38U_jo`nof zjG4%SO&@>fi4`JcCb^{=|8|2-KVm(*tp6qtkC5cBsKB>d`6c~Vc(AF57h%P|#>y}1 zf1+|m?~0Xg>;GX0T1BRqr|I-v!d$<9UuY+5|1(y8VgFacceDB*vGVQx*H!8t4fTJm zQvX&fzoh?$uwyT4|Lb?^yO;L=yi)(uR{r$&Q(CzNOKzbushd<8$Be23t*B-HZBvR;mA| zR(@&!E0y+t+sZHLAFRNC$jW#2AFk9teMIdq^j}}8f4`Mq)c;1MzsIfoY5l(q?PT=u zRx7`_e|rV~S6lg|{nu3J|4Vo1yO;G3RqB7(%D=1snhHLD)yfz8AFI^=r?;w|LI0B# z_&;vt3;o{=c+2qlHY?xNKU``57F)6rwL{p3g zmrq{Auz>N&8xs^~h+V5VL#t_bGDIwd_^W2|%Le-Nftu=&-Yr<0!2KT=O+rG#*?8C>c8-Iqi>(MTnMu?VlLN1r!1CJ$}CAB?QFTu;BF=d6$!^$ed#H`NlqdCZNO*T@gy; zD~V9zS>-i8h7z6%aOQXxa4#m?%d-;ij?(fot?gGKeJxv^pK$3#7OSbQ9T zy|;*vhqQ{!Wc{cd8J$JZ&+@tcUE+`KvDsS8py&454%t$$-Q_w^tJR*G?##?~dt2tV z_P3pP{`LzleA`rBA;s84SN;{u$r-T?@Ou`A^*l z9$cI~2xB0h2r{#l?#v!kk$B0Z2bWHI@bv6~+2pxTObMK9-1BcB0P@2hW)F;5#Qh_^wG07P1FbOza8|B!N&JSASov&X|06R=wKoXHI&sdu%(G zQ`)_2N4(d&Uvdab9mR3$%2h6};F$y0&#eGPG2;ELtxx`5zPrnNAr4zmXOW)@na>4G zh~f^Cx%WSHxsumiXqK?Co`aTQa`4JAeC`>-)A8LGPLQ+uyyux1}w5-<`j` zYkhA^rSx{?Z!fIxZRwrfLjLx5t?z9qr`~tvZ-3|d-j)XIeP{mmGuHRE)Licw`P=jB zdt17&H=n=#9qW5r3bXee`P)N$uXy2CbcPiaZ+`fC+8|6;*DPK@l+v60AYU-gbS2Tj zRgaeg!Q<1nFwRm-q=e2}(maQ4V3S(n{m@dfzV1jJ_mceW%hva{bawBu{OzZ&?`Xy)BER zcTxWKj`h7Qv!%BqfBR|cdt0_m?`iql7q0JZ89==Y^S3Wp-`ld1dKctxZ}+!5+Jhzq z^Z$nRs5YBYoXg-h*2(PHXg8&L+w-^2U*ET7Z}ra4-#%}BZ_6m_otMA8ZGCUca_eo& z-|qX{tQC5{|DU|y+pOQ}GV6ynK@=`npmbvrbWHh`OuSw{Z!zqeQ(P??b%6}X12_(?`;{ezC37e&#dol zS-QTYXm5Ac_qNR8o-IS#+tcfNTQ+mgmM-n>DSvydyePxEXUm=Tw(X$9Ip_5JlAN9! zqG#E%vOnv?y5bK!F%QF);CQJ+F*3({wqR;)wbs`U+3Y=AWVN@O>w8;xy0wK_ zYo~7QY_La~82Ay?8HS?9ZYo|Ja*l=Ux<`Wxk zY~1u>!;OubZEU!)ag&b?H#TlAvf;+YO-(l3*tnU>h8r6yP8*XgelxV|^jhi8DxUq2)rVTeXZvM34#>P#jHr&{_+0}*{8#me7aAV`_CA%a4V*L<2HpLcbl7B{vot6H=EpWW8)^58*XgeTr+NLUD9RT)H7;KQ#LVOX}-jww`LqR z6J;rg`AI$#)#NY1z@Ib|jhbHHbY|Sdbi<9UK2MFBJ)7>YGHre1l}uY3FFDtf%(%Tg zCC|F%oV#tENi)hbCbOvKdC}ZFWCMUa@=P)tOJV`VvCY=vz+^Te3L5->SOHYH$kv}{Vi z9m`H9&4j1c^%i?0$0SBmX_TZcl}9PzAH^YB5kt$*#SS5P8*SMgPZL^h>;uRR=y&r$ zjm_gmi(2JhYjVEvY1THb-{re{Qb&2C7?U4tQvxQR+NK0d{<%#Fn0$Sk5-|A5 zL2gRGrcfXO$yDFKt8byET+pY5guO#a^yz}Nv^N}f3VL$<)ru7*lVKi^V;K9%c| zhT^%fd5AZzE9FZb0ZdVOICK70mAL%Un-VbjxHlzW@|TYQMr4FiJK_ZwwM|8X8uB`l zU3((64cRKB)Q&a6qG&rNJ9Dycoa_`|^=}1MdGSYJ-3%D(rfK*Z0dy?34L#(1~ zNowONN@0^DP;CaWuZ6Eo378hqMgTiU*98U$WBFfUYzZOKi$grgAoME*6oq4 z@V){jOEwvD_Ee2(hnhrPsbpT8ol9qd+Cxkx-^QKJjj8aMB}k$T(vm;;CbqPwrN`>* zJ!$M}JYFZqwvv%MAbP~+apewcErFVy19m$vH2hG{DJrV5wrX86{!0So4WDPHbUJ!& zsdvQM0F>Jg14>FNVOxWx#XDQW>9irfX;_k44(ziicfaeG?$|{go*k@fyL5b4)YP-0 z72PFyO*X7Y@9D01Pj|(8x+~rz_f__>#i#|9U7s}cbFl8e`}}8dY31N&kN;t9K=OjY zOgc4~O&=nUUwTh{&`axsEudhI|F-g!eei>Al%2(ENR@Wt>s;fFm#Ss9^FzYw5Io03auxP^S$_W>&DlLLXq^N zd>GuP_nJGKL}_FP^GlMer6>GyE0@RpQmB2OU(RxQ%r7tG@@~KEi{2k;4ldB|(bnK; z`aRMbY}4PCPzak%o(GWTySOM8o=8QJ_zziNbP(;zvo@qxJAFD zT!o13u-9ApO%H*or&;)`GQ!=aA`-JDmfoSJyq0fPZSrd#(JzT&?$j>{L5}K|>~VMN z7i8?)!(o24^g)A3)bG%~G%s}Mt?+AkVPdppg^yby!bv?>Ny1v& zNqv_r7We9xlpgo+n?BlDPQxh*$LU2N)eK<*b8%1em_f`T6Ia$grkCzh&4t=Cb%I3e zj$!Qwx6DuqP3fX3RS+NW%nlY69r~?Ltx&U}>&M^8^t)bd+D|H1)k}yzsdTRvyQ5=F$*s(CS z;L})Xn15C!G@J}dB|wlQr4qnPE-RIYn4exMq36k^r4l-tT#}U}JB4PTysmDq><$H)Y;5G-Gi2DlQ;|#C>xaIsAV=P{rAobOC?6W)Hz-Jo! z64NcFKLpFgqi_J=QSR-LleL!& zyRwR)*6tlctnTON++QUHhnhL5oV>3Bw{)yX58gp%VJvdKw{ok^NPqYBJrdjgloEMy z4wA%l+WhIHc{QD%!Kg`@BK7aLtlKl`y{KSig(HSr8fwP!%4SDFS^+6#v!fz)FV(!r z566e`#uds9QX9@CvwZP|%S!O8x%<{+j-%#H9atXpw4c(@_JX8N8E1yyTMJ4h!=fRGV;X*(J`VXDDcLj|n~@6f zFZMqZ`g*hhNo02m7#P4vedaV7m?(+!c!`SW0AP{*G?UEiY94LuX+D76nDB-=)IUvf zFrFd(IE2Q_nft0>zW+94VQnzWz_pU*vy-|_3MTpn$xakq8sJ8tWkBz9Y8Hknyse)0%yr4N4cgxY_IYqLoXe*-eORbT$c zU+0P2J1ZURom*5$)dTuH@QM84Q5ij${MP1UY7?DyO24@E-1nF?3K170>$hi|e zhG3xZsA;qjsUk%d%M0N#mKXac;FLKfvn~z?%6Y(K#aS^yE8zP;MQ)saeB<~=7CmYB zW(MP`C7HRrwp9q1tl_V8*U3!#=-xQPpDmKn0$J6*ak>9Tw;+EtHV@RdNS1T8U4M3j z;ll){X1)Ipu9TGB(#Nt-v2=vL{2($bM~Klxb3q?sO%RWxG4RJ1!BdK!;j zriME~ardI}FgB32%8YfOOea8~B%$j0tq*xq6z#tdOIVVj;?4}|W9%{f4KLq06Py^dMf$=ZLj18dc_9M@Q&PLd=QG$d`A zK$7)IBBYuGl2F>QagmsJM^a)IY#q|CfB5dmoNT%86 z?j(57mS^#lLMN2}5K~-c@;^Pm2Q78bOjqFd8ix#VG&%%WPai*Ue5ICZ34|tjn1YDw z`lrH&Q5`V(*bnb{GQVp%gjVY5qk^vgX+Z<@H2|y>H3YNcI;nL(bwN{0$K4F$r@;7( zKNTTV|79aOoDD9D8YnT!8Ft+((lf6Jvxhr|4D@rhz_Nom$if)LhQ8zznRC-vMh2wj z$KuSGq{knkc{2x>m;4>`x@Yww^M712>h6$7#oZm2l)EG}YR&>S5)m3r8PqQ&sboJ>msEO}Wp(&`O+=XWtAUP1s*5eH-`PE8 zXbWeM7AEaE3tKw+F27H7zgXNa=zec;kICE8%1{2nUKOx%6$%XZhnP+1%nDYdX0+CH zP`}LVS&o{aF~<*o0cMKi=q3AkZ)QH53D+5RO=N)i$ad}wNO^|zz-eX!lAOm+w(7ta z&34ujHaX~7;WT6qTS=d$x=A0jTkfx)Iq&=HwX&EpBjqYjNI#=)@(mYNa*){#E}c=q z6AdRUK0Bse6K0mxU7nvzjEN9n^RiSm1>Iy|x#%dq0m0zsrw7H;&19Bns71vsb||=8 z0UV#4L(QIH)6QmDmOld3(ky*3Tc|7Qw1$jAEg^rPMT0ibsNNavefFkE8WcJ9T4`hp zDOvrh*pn^PN;K3AY^I$t*RYQSpe~wKM8P|mMGc*|vb69%+KjQh8nCA`AoflZ_7ZsX zoPd!tG97*-G2Ip@G-JAYU^*L{g6W7K7gh8B;rY}JywH?kP3a=%tWg?RCM#W79*QoV zv9iKMZpe)Lvcet9!wV>M7R?G-?7EOb=i{spFXq!I#HkB&tB@NcoNo3qw(twb1UNV8 zoP~TQN|=1$CZ~oW-dr7Eutj2&>5MqJ#g82f35V=z?%jjCc?(}ko~8vV6C?z5^f%9PNqGlo|((P#ALa3ewn{A>hRu6}WRwOFL-BcAaERbUpB~IG1x*RkNgsdWi6?3|TsN4_9yIqYy_CuX zUob&gdgPD4e&I{3fS8+d!Bv&}UU8rFZeBX})!Sdzy%`2%qWk=v!wr>a^-K{NM1##D zJ%+Qvfgw5s`YvEop~rKFItOqR0BdT|TLLkxian3RJ-ak8XO;jH;~$f;G|eQPqk-p^ zSz$EG+v6}h5I$JrzgbP*rxg5z^cwJjmzvU_adAHEOYe(7u-m1viDz;nxXUH?t|}W6 zN7$t^L66!!if$$-Tf0Zs%@juSREV^iQZN>#@06W6YS3tMhpK(O0@oPssfC7->8!Ng zPfBmj(u}{L_FN3l@~KdUg3ro;!5S7^S()r-eN3=tW%R|%=wDU_ia7)n`V*?>M2o^N zrjaNvlyjTRTsQ2di~r50A}&@;mvZ*1IXwEVHLV@TpqMJCnn!XD9MK7gbCXegdJ$Jp z-=;!c_#w>rTnA(g_;8JIF<_oTSxdLeuF{uHdCY+T=Y5VbqIC2{KJSL*Y%<3e-b1a9Wmv9;RfE_W6-mRm{VbRtDkiDS1{A6dh=tiDGjf z;)AuVpH5~WdlBH!gaEIayfEH|_dHAaHmbsOegi{@+x&(Pad`5crWhP!(_Zes=hZMa z(qvAojkWXa;ml6N*c@U$nN7H!y$&dlYwSH`Eg+eF?iN!K2}0B6ITDUJLRjPo2*H&* zpkgv(d?S)BA!Ay|Nb1NhB&eoK0SUCJ#s3=6C6a`uhpfBq=Lc~-vy+B}W#EC~qY*K8 zi;V~l3w<7v!R<1BMBqLWaLa9@uu@Dp@H{L0B0v{k=(BO8xsB68K2GyoF|A0trrM^K zn4B!~4H!}(5rSOu3@=J2T;fFmf3!H5vsV!9k{_o2R@ZKLLVk=EyPBs&;yQ?TpF06} z5dS`H(mj=PT@dsIJ|(c+f9(+sx5@dRbPA}7Z>C*NRuvJRmsiAiUXCd5N?zv$6*;bQ z*BVBFNI?HktYJiiSAj%u$rT)-<;Sg>@o}{GGP8hs|5iI(PY(tpJ>j=cv3LT$v3VU4 z#TwBmO!WS1w|FsETiYBz6y@4&N^odtlm2W`z%>hHnGS++ zf^HJ4H~CNE9w-;&s;3+Hkj2?)<31h5DoS5DG zCh;E3FUzEoV_ZE+wz(=4R^&uOn1)5TAxF*bO~jCmt3W*OC|ufvt%*FOE$%yL5X!i+ zakymW^nc-PCI|6;GcFjfPc&~xX3W(Ph6)*vG%+VGOWL{LW^@pdDo7^#tiB;xVV`Fi z_@^C$g~r~&R#z(`h98G#JWoWR2%BfKiv zrXLoU!4_SGDj@sDjf`?YAGLkltTlGM;IU>40YY4##Kq4KU?9a*wZ4;kL{Gh z*8o`_G+e;Jk<`Z0GNXqL6kr9KZU!ugs<)1sEVTZUStp$XuHQg6p;qth`nxG>PzW`J ziq%@`gJ@_?ebC6U|Drw=A>9KXvbiFe`M<8~|HIFkASJe~&R|jJHiZ*eUDOSd35mc+ z4Cj8t0=UGC2>d=n2uR~56dZSJGaCF<$b3hc$ko1XtCqnYM+W}2g<$x{Snl8gI2&r& z2OS#MYbK?jL838xa!ZPQz{!zUeTapTPlSaL5S$(>m5A96D}X<*Bh_IhwRH(0!Hh4N z3q3NjJ7bSf#{w$vk@1%I2-Bw2BMbxY5gbF0n35njM|!01OReiiog34SaowdWxu10{ z*Rx5d|G|K&s6M^vL<}&x$PGu%^&ftP5s5}qO^m#I^WHsylIhwJc&TYt+O&0_>A!U!dr7{$ zY485Dqp~tPn;zSJLufD?C9!G0m>1fYW{c^at!s>c1ny2%=7rT4C(aA!Tp4By4#C>? z{!fp7X-a!mf@A1Ft668kGe5b!bZRul_Ztr(0yxI@-HL5Z|L6YaenZ5J$v%$}fe$0` zJ#meF8$P#ucVeeSb3D8P_vZaB;SRf@jtSQPYIbyapS5T{xt-Mzes&CC2X(GGrC{!m z)^;^d3v&4;>aqoBS9KqH(;E^Kg1_(pv5i=J+v4UEz^l)p&wVcY6;U<{b|6cA4TP7)oI82w>|p@pqWKnEEICA1opa6P1@yAn3*UE)kn?BKU3Za zcYW$!;mGPgYVFuEX9zcvbg(s01cZr>ngTrvnL#sD(_aRoDMp@hXu>?swg` zg(GvjxO5#KT|cSLr1Gyx<)+)x2j9$Zwnz6Drt0}xR7ugWz4HD0(Zz)dahcVSEr;0B z@vWxN!L4NAZ4aN24DA!hRy74!Qj>f;QHZIJQ*$>(2R>~tEpSQ6JU<~S8LCMCod%$l ze)<8cvxCdeP)Sh^Pk2ibGn6RWF}x}h!-MdBwQHF9Ku6Ew2TH)Zksf{M!|L`Tm;7ixLDa#LHb$Sa z;h##cibj75%1I#r)k9AF6Pqc*Tb<>l{jdA8pZW7shyUskbJ`hM?=VpfVT^Q#jj7CU z)6X~p)!xTwX+p;d(-`fz>m3<)lHpOuJ$<2&YaIv2>Uc{m@GO3;-{&&V?m>=BOkKJ54z+J^F8DF#l?Ejn@|JnQ*fcty`x@lWD$~M zpv@0k58u{4I6nx)sEhCvHw6HrIT6rBb^s&H6nRb@us|D8{;dl1Jf_mSp2X$IOJeoHP*(q z%j*!fwovQXgrjMD1F|}PHj#Y`!e6NMH1XkEQV!nAc58)4edJ+7-syV(6*^QdXhiA`|c>lweGS%P0lhrGzW-B7-^;(L+%#H|ReY%jX!Tt(V%z93F9M72|nRZ{=k zf*VbjBWjlB=pX~fY+CM2nWQW|4OslpPcNY{>8RQj_WHGFtE0Kfx z`VyP_@b>a#hreI<_sKc1RR7Ogxbr0qy$uT04&12>R7BG)8Ie<*G?!{@@?NU-?@~$( zlaKm*xoi3_mKfDcPck%Uk_pCvl7y71>mcdFv-ixGyD z>+$sS?|LzvVcYSGGuMP7*9)w*O)fghpaY?-8=-2c0b?7wIzo4bE-UVoQO4T=W!)}r zUAAD{%y)@P5s1UqT{jOA(Ubrxe*m?$bI_n7<^rjN6b>@mfB2x`Ght8QHAx*)u=#?< zKE{?8_Ja&yt&3dx5C1&%B#*7mbNI20OaAcp^^lk9m)EW_J4tcdy!gdhM*Q{kF$=Gt z@N<c4~X`!B>VeiiKhckD*ScCFn zjfD{KV!EG?)UYiCmHF;~BQPU}S2kp|#VgJLY(&ZcK=UX~^U;6*9(9Et<}2;dk;{ zd>_YcVAnsNG9SrIru<5#D;CDFzc{giJ1PA=`<*YmWn~}9WUmP3g)Gg_>3!M!t&|lh zT|zTUAN-R?Z~u$iUitRldZ}YkZi9HrA^%x*%JJ3Ad8Qa*$!@7FoB+~Haxw%n+WcZe zq+jr6Fi{xi;gILwr`VE|f)soAQ5pEdS@#VfPBn}AEAN05rX_VV)tUJP6!2??p;6J$ z*GMo4{O~76+?^bZ4r&FE%~YnP2&9Rg3I|IL3mN4Ia6xnTQA6i=XjmSt%<|=&NJMyy z=;v)DJN-}G7FcYZ4wNvfFN0+Yvz7k!YDluN3ckqBD$`7BdBQZao|t|^qdmFP%rN7G z79M{iw6K<$=Ga-`uXhS77}jdUDp1_&|7=6iT&q@ZNV7?A$u{drC^3ObPkr_TJa{p~ zcgZpX%an1Od{Z)jP zq)*gu$hN_lPC-*%%>!!Ua_5)N4P|<#tsAy5t>bMX^>?KAY7bJXxo8C-T;8Q{1{Ygc#g?6kFD z)#kreriL}KtLGIl0Mc7d!N_TMR1rVRm#qkWkT997h)tEY($}jUSH!Q}k5q6){P=6% z`kR07rZ2rZiS_UgCnkk4&7_B)<#+qIlUZz5Nv?|*T^C>Bx_EDsRUtcPY;E4c*M=>ngiMe+AHU^ef?TewKlDo(7L)p; zJv#1GlDtx1q&K$*2U4)tnOK$d^}ZqBvb;*FUe}ie6bdwgUrTrH-BMyGkBpd=(0-OX z!{~zA?dSb^j>3I;&T6d|mgy1B9QEi}(WBokdh}}Kd>Elme)hAE{LB4ce)BGkP~0Q- zOWOV)>lV!%A-OTU+e2Ak6&Mi*kdz-+HV;VIB;d z@HneieAn+k0@m;|A9)+UnICR#(&CUwi!Em@E#6W{i`Nyj_|Ct6_18Z3+6QjGy=1l* zXy0t&;?D}^`b0r~uPVgfZHHg|fnRy|XYTz!s>}t=1?GB6TzvDy#aD{)`g}272a54} z*=IiZo?GvF^M|%p#|vRtNDFf425DiT*AmO$Zqnj6r*hjO&$&Y3Xir|&ViqM;7O(lny ztO#_SX8E~7Qccr;V{M4X3nF{$?mx*Oe|14*x4!k=|8V=)e(vpeo0N-n5>la{Ei?l< zREEK*qD^E(ShfPIpyj8iz;u6g~%D85};F=`UvBjW@;l>Q=8da>?LB&EG zQn6}>yChSw_^iHasyb-c9h(0Nm6?VODNeL9yqbnx3`X}_6zqX!W9p?-ndAC+>7<3j z4J_aOAHN){Ovbj>oDSPMu2!6Q$bVsbMbn-ma+p7BzHRFZNF!fga4(MUdY^`L)Fl=& zwYs1ny zOPgd{XF4Qvc#*85cfFRb$X7fqr#atax8tr_qJ7=a&dt_P-5XHW0kzgzpjw?Km<2TR z4qr^c!g96*!McRTP|FpfHMVZ}LIvE=;cmtXiO~m}G?_2TEoy>9KK*&z6)Uyw{hc~X z2>WQr0}K_uuGAVdNRK2EN|_U^W?vLCv~|FG+Ov2`>W!v(vdZRzuyEH}*6fb)%`U{v zZqJ&XA79y`8Z#JnWR-0>e-vP>$Oz&~vf4!YkLw;QMd~_;_<;=K=ZvrEc^xt+=CgL6 zKfX43<0B{*vf9^s#DP2+1H@HFOO1h2^2-ft>k6n(dr zs_)IJADmE~4QLT8S7p_2n^2vQ=78?YGISrAQ1w`;XW)IYX82x{f8#hC-YrYp8$uzm!~JxC+}TU|G~We z;}hzWKQF3(DzAT_F`jM?mFho~*S~eNe)k_5jrQsy{@(S7c*#|h-IAHC9;3lf;Vv~5 zo+7Ck8_b>OWUXN+AiPQ6Q%l8km~F_ zkW}wk13w(3x?*Sq+SEdAaZsNi&=K5{-z+UBF3??eORo1RpLT(cT&LC<1^UYx^>*gr z>gV2Y^G7Z&_kUG5w{!qM4!#zU3uojt~)@srT=HyFifSWzDn-1H~xw>x6859(@=-uLnh(DO)10 ztO;i-4mwl*_@LCj(P~T=v{$SNp!u|J+5f6y9x~%X`{?y9p9At<|BH%q(xn|R;Lmu? zzOP~e$uqm7MW9t6$|(^g##~O6oj{bB9x^$UPf^s!u3Y_y%%((?;gwDx%DlD{CA(Bb zl%lCA5oKQ6iISbLYT2y{GS!Iw=B)1X0{wN;e{b~HxxBVGtScq7Stf)sUIprXmI_jf&H)G$KyO?bzyEnZZfw5yTYU$x2lBA*zMf?%Vwj6r#ZxBFc)k% zVUEyWW1lF>DUex6puoeLPUu0RB_yu+eolV#c!61uavD~p+7@1eeEjWJ|BdTSw0X_o&I3{ z-l*^<_7*u6?Oh%y3Td~EcWzV>nYK_J9BgKF7wSp(W=S(4gUXwA$HwT(b)6^_NXKoh z!iMAg10$xY=iNDh#6k4F#=%A~2=CKL=54giI3(T%|1>>Bb4RV5w25_bbh{Z`A4l135GZ5JQN? zz=Q1Bg08PiFUy2#GG3_SOKu{ZbR4g|3P9vxP`oVYFl4KhXHfHHji}9!|P6+m$Qe&>e>HOJWGuXA1w5?+TE$?&g{$#E52G50Yspx zJ2n*^2T&?=%;`$&wWbo~7Xi^K6BFS@K156kaVhomKuZyIU(>-~$m7%cW#af~xPL^y z#7$09=P|C+m9Dt&k-6pm;ok{-z0&1FgxnoMfOC4;LSuh-&}o<~IMB_e6OT1tC=+H- zhf3=GU$u7$tzjp#wkjPU)NtA`%ii#(p#-R|3nF{VBDwdp&D(c7hV3l-zCG)^a$r>Z zzJ2rd-Hxg|%f4^R`mVem)xK|2-+fYFfA$v40vG>A*zh$Wd#vaL5*OJ!D?GWxZked) zbZeu;j-r`EI2o~%U1OxvbJD}&ICB=BY-T2E*7;TV`=li8n)#c97XyF8=~ezdH0}I- z67@YR{=RKG>+<30_3}4e#^vN)W{xq^Wh|bo%c%Ic%T<9VG3TQ!Pp+G^-+Y81`OX?4 z(-}e#kRu4OyeuxdCE~rG8dw+XQ|a`e-n%I04s8gfV227;duxVD$Wr11h>7;<-XQjv z#Jhbey(cF*QyND(aWc{X_rJ?+0AiU}*y_79qexsk#S<{SCKnu-m(eXr8aNvO%Cs-E z)6>P1sM+6^hfyqbd5vc4sb!6IK)v<;9SRr~(59Kfm+CJ{zmT<;GP_D2F?+eRGZw3# zL_l{)6DiO`E>waAc6nWa3%u>tMB#Q^1VoMQ@mtHUA!dl+$HhHvSA8-0#@ z;KVD84OilFyzuDzN_2 z&;UCgh9v@9LThaDn8s}aHGTFx<`Cc{cnS}-UWl!fA@Sz}5)WZ$;weZU`R{m5%p?Kl zntM@Q7b7V2NkkYQn>v_yV|+4e=a$g4TRSzgcCzuYN$<4FLy=>JqBMl-8*`2L1;B43 ze!&=UFJKzJ1$8>gQG9EC@FzfjKIWS#u=7Wu@0~CDMT_O%LYW0x1A?h7Nc$jxl)-2V z8MOVj+Uxe2C|!UnTekI@46#)__Ru<0TWq7kI8Itq`_fz1z9!|Baq7{NDW$YO3;0>M z@%EK4x7t1l(~xKRE=BPvmWL!@X3TShnO@I$2c9wBVbW&2!~H78e9k)uy3RW?Ys5P% zU3U;MBEiI$7>YP(I?0e%=AdcgAUEn69C^QtgT!0a&f&#rm&9DxP8SYe(bQoL%%ns2 zctgg3(W8=%RX?N@?RPCDuT0u^?MKMjXEbxV3sK)if}uC+I)}aGCT~s z6HJxWv0DebiY9%Ec3n|x+G~m+U{~g=VOOcSsT2qwd^+}_IA)i||9 zpO71&A`_U%SZx}QcZ|oy+nl^WRosE3uI9%qzi6$QX+*Zbj5Eqzhx$JL5cQgrjCe$J zg;i)TeCgurr6L#=I3V70(nS^8>c<68t<7j5vImalt+^a-mlQ(EkE@=|tLAo%QFC(@cI=9K!_BUzE*VuJmBd*4oE}_T9 zV3C8qgC)gb=NcLfNw1$%*fBc_T2GHh3rz3hNCGVT5|JYF;x=0SpUDRDnB|7F{pZM@ zV;y(bg<4 zQ-qs^GH!OS5jR=}%9b}pY)Kh6^XDEn>`ty})_oSZIX}Y;1bk7YN>O8=Xe_VaVJb2PS~@O|YG8?Ww)D1HkOEgBxh62HVu? z&KQmK1I4O_XpJSZnxAsd^To^m+z6SJUOPxnbrbH#M+HoJQF^#ek3kQEbC3&n;BMRdI*%!&k*n52|hRUAYjfS`lI#CI|V*HTz zRq0AG-U^z~@L#)yeU%H1pJ1_#VJ|;>fj|3kAOG^RYy8>s2jWFw)fctc>H5pGR%Tzy zBI%j8pN!cBJ?gVRDRd}nt6Jd@dbJ`M5#9)+Wh_gqLH4d*S*ersm*4%$$J)^5_xR~e z{_tjloTcXY+4cVHM*HT>nIYFfpzcUE_q`bhO@?#J?U8D^zfx(vI@y-=D9hc~q0&@q_%kg&T!#rkzKZ0NdKi|`ehC+a@j z%cdspxF8Pf7-MFZZ1~L9)S|v;vT6EJWkj2cttC9y{?F3$Ot3Z0;uqzP*qXV)4|#wY zQ(kUsnxi+jHKRGhh^=XvpVa!gY|UU-8rNn#*oth;d@Y4B3l3WhBp8o*YID@qY?>3e zY5rv#wijk&rjx)bVKL&#&pB?)){O1&_0vschmYdM>~OO+A6w1VeAkm}Yv#tZ ztc=Xo%m-`4)*Lffg{>Jed9XE4t;g0}g@?`7%+2Br(dl^^o$B1bDi52T?Y3s%KZ#1w z*@&%~V*p#zqNbjy+blGnV^c?y2(t?ps=zeWo^Q}B0Ka08?{3ro;vFL?CsDT4?X&x*`YbF zT+0d<1QXk#`Lh@Jvme)VOu3R`fq0ESn{0;$k0&OM*`a0wyB!*6Ri9nW4wZMztrw42 zF*`Je4LfvJEtKrg{OL{p@MeSD?a=($_5N(K9a@2$!47a>v@y z4P*73nxwY_o?M`7UnBv;*+_2{wwE^6DE)Bjk1&2X7y%M3p_O< zDp{DAWqvk(Z9Hks%@zTdvs&^GTl@IU)0kLhHnEmr^la>OITI6EB3=7JGoM>DN9Gm<%n8$m$#VHE`#8stH9R$@$Xe8xWjN3bSIGo?vwE~uU7@f%tFi%a zH*ufNwZ#Z++be~nuIVu12BeE8BV<07&%NW@w>56tOCoq}d&xp$-Wm__ zyy_DjOlq3twsaa|Ew#pt^6g3~GRUl&0ji$wW!ES_SJ`K5yGQhyMMujO_L(BHMf@2< ztTk?%(Co^*=yqijT3zYGY!vpP?fyfvIHhvTke4=&W$jFg-XAmWt<}dp3QNz&9l4T? zyJ64v;Mu2(anA$GcWkMSd(`9x$31U+!5fdpJ!<@{$36ed=(tCpd9ud+&2x=Tk?r;% zXLL_scH1SHGyD28Q+O_lVrgX7c2`X2?}|mFZsqq+b68sUjJQL{LHmOGFXUL*gzpA zYCCYXWkZ6{4o)TS&0rdtp0WoTaY%9=)61Y?ZC(Jlh$Lx>Z5V}zj|o%J2S93Uu!(D#wOUVJ@5NJjbvN@ij@12(6$93>1!DRV{% zCA(vkKxt!8Qc&6qn3;CW%s6J;-NI2#8L25&ACaM`SfShOBHU6g-M0#IGg7O5g|h)8koX=CGa^ z2BwFgXn2Z^e-3L!3_3|R7<`JwJ0uHcLy|IX=%ui23kLU8_@V^Sgc=IFz0KnA-FuO4 z^__dR>0ZS9!^P07SmwG$`ekBF8!0v5T@WnPSq6iZ`kvbVN#nu6P0EgIql_KUe>xp_ z+07RdU#Kzc5B1dy11rNY07VFwQ4}%u5@-?cWnAb4H{J31g-JKxF=l;JSFSPM%=z&7 zMbECywp|B4#Co`T2iZF_(-dHWf+YdtlFC9)8*qO3rST_Cv$TpV~@u5~5)D={-GC?m{l){)`btRuTJ z>&UK9aNdG?eXyQcM_-?dbHb0&k|p~nYiaHFQ8tqL^^NqaDayz!$Q7koOW*+Tvu%H< z)j;lyzR3e-Zng!LtgKlqJL62A$&_tL(4B$0O1g8}Wnv)$E4mYmneHULWF?zD%y-T(ZK^cK^oT0mFs7kwxT@Z_P2|uU z3|OdAg?sqaSE@9e(l&t!1Dc>WF=3=i9X~ozu8JST!TRvinM{eMS9AOJ3RZj~|Ti9G8nem!75?dph zHYet9rlu`XA~KL+GmOPDaoSxO$i#>eGn!1MHLV?^cyp>8QM`FatBQAoDkH_4H}?YH zKkbUQgT9k-?25PJir2_^N*1#;m@D4n8&te!HlLw^isE%5J!gvd3#~KxSIvjzE+x)W z5$~b^VTJYh`bIsgW+mX7Y;CMTpRz{oHOxeuHByI|G4;N?Cd~k0)m~vP=iCii{?^#< zo7r>L-yd<5@-5snYxuqyTW9_K5%=m^zb^*K0w}t7oaOS7w@I|FmsKtm8xzEqZP;A!XFO0OC1yDszn;$55 zun!fEm8|7GV>Dm)FdMd5%vew&5EyGw!a#HOoFKEKsr(~)+P*GnWd{moC;C-ZObE1V zg_R8CZ6p=e0;QRcC0G4g-V$SV(M8CjsE0&9T9jG@!nm`u41B#QO!5kL$F3T)RLMmw z40)J>fviJUxZhUXW8x#%v-_}0WQI4h!RWgN)#{|9&|)SS1_eu4CM)tF!?6_9IyV&L zD^=AcwK0@8nSwfjg6vG1(cowh;U6*jx^6Vot}+BrP_`EK&88rH{V@euWM4%}S{QDz zpeU+Y!|-O~YBG5Baourl#`PRXhD*Y@&VO4-hV!#i^|ps)A^(BnxO zrT}>@ogTGT*7ts9w}3~dbTFwtN7nXj^sN1KMEDL-(l%!_rJ`a@>K0UNv%I{v{IpivCSSJiO0{LFUZUE@QA_}e zZwLtzURAG8x4YFJz#)Her#Pgz|J~mx-~ZO#y1%XHm$j%)1r8Aj?MUx^-KSRY>Y({A zQSVp>-NrKLN=<=OR^feCp+C98Z(9YO+&H0yqgFxAsY-?J?=?ARA)KmFi9paS!yq0C z5p!C@1wX=B3(CT6(Km}eL-Sx!&O2kjIWF1Kgj8$cCQn&-70cGcsG{?PkDod;Jf zdtgXoskx`In}VZnJfXH0tg_B=-<#AEk=DX;|0BXpIEm$(0n2@d&kPInli@|!Sf&5v zURwZ3W2xc2K6vIYiDiyw;Uh^sBEAQW7+(&zyfm=RkmY@djU}HHQesNejOUGhoiyfV zrl;DiW~1Jzc|_3FTc*{3vzprQtI$mL8a}(Z29({!N9WuHjZoJ_F$w)}Mp`Rw#;X;( z%77X3Qqt(Zt_U zwZj#yPb~fZs8f`;TVJI|Jc@d~Xx6_lV^`%~FX$nU{5R{hiR`S`98#V4S`s>pV@9L$ zn>4$(w^%o9WM>6w-LRR3(n;oIt6jvO3<)t%fcoSG#+nvxOugMFD`_f0N7^Q+Yb* zsy?Fo|F`Hp-!E#Fk%dF+UfuB1Tke0%tY}f^ux`Xvse(c+9Ut07vtEtlc6BRQ2JkaT zuhYk+nvM-?guMGwHGcLZ_7J2p0_3}7G+ zNhJlQ(Kt%M~1R|?s$>Q2+5KEkoib_}%&+61O+R)uJ zjRIW9mbp4CcipV1n<6e}(kJRS@In3p5^G0d4Hs3(6ax1Be+AK|J1EAae#CAbeOPpS zzti!!3XjJX?re_5m{6s;dShQ|LsvT7*9g10#F=GE-7AYOO*9nMN_D!W)qh{^N8GjP zS`+}#UzQvduV;0Llh+x|h#fC!rZgS-M)ZE6kAP#gJ{-IyrLZV+^e+|&1) zL_Wz?+Cc^ZYRp>_<%u~aB*6R=wd-`aie7_73jjK@|20cZYDif{BiKx;BQ^#P3VDR? z?YVvBH?Z5c9k8Kjz&SK;Qzt4^frv+zan-Ko-wi{U6xYAmF3qo-ff9VQAOeG-xm1_P zmVz1pASjG_KmjORX4FQ3=MDDj1VEFupumm;%TXW%&<02XEwg#`i3Yq*z+ceHNpWK*0?cUm~Ph|v{TsN${+?0Bw-E0=vK>c!S=JgQ453zum8?Fm8GS#*> zFm*5(+TwkD7Sd{s=Q1zU^iNtCRMe8X*&J6kaB!GrH)jT-qH!aCWJ)w|NZQZVtzPSY z(GqBAj*-@t>s}U<&?vDPY^t>J(;;<*(l9U)=d)@3#;d8#7(9>IR7^3jJ)C;3d9BRG zX7<=lrZ9x~5)qvUW&KX^H}gWne!wedSZ2GS-7#gP32V6u`qV=wR%+=p)BR>Te9RRS z;Q2>1-%-2b+NfnPDQ$?-MQPR%wvP3!-TwQ$fv@e3JWFM7V}|VP*G%NO85~T_R+|$u zX%VXzHRqd@4&XyHYw|DLtac4p(*~YK%0p&tnjfGQEiT{7e9mBH%pttY=M`4QJj2V3 zsQq1(iI>?--^)-qUY1XmYMOW)XzpotJWBUuqXeDR2HfMd<$i$I0j1supem~Zss4VJ@jl0UK=u}x5 zorlWk6m|=Ama!kuSs5lrrwStg9GxnRAa!)AFzS+{Q-u*ap+y04#7@Gf@WbJ}Flyyc zUKo9kxa%-d5oCV6huVyAqgZ_((*ikmE?!^^3kfF-j%pFxW`lh^A4z7NHrmD5W}|(S zW9CZCLt9agxdZ@}MV+$IR$0_18*P< zC2zC9N;b?H;e)e43K4`4XH+q3ZuRQCg`qE=;6FD zdfkb!LiJ9JDvUrnkiQ-QzmgXgSjmVn<4a%z7*TNqp%bGDBVe2uRT%a9p8WL)nB#e2 z1dJ1-UXOqY#F%jgof_qggLz>D%z?Zx0%j#IjDUH}fT>91(|KV8%p)pvGX)}9;?Q=p z0$G|uAD1{oBUt7Pp)ppt8L!a6Ae1w~%~$dgpyI8=jjSY?XM8Un4dWG+Mg2EkQCZY| z;}w-fy*FM_Su_&HD=I7cu6|!%lH1~(f>r2nR6DSW3ZrJ7Ra6*#-&sY45una0DvWvr zKrV#hu2Y9XkQ)~s&I_a0omEsb`q06=W(3lKyf6ZOB`++HlCerAHE0}QDtzm#qQVH6 zlX=Yun0xZV2$Z)tRlk12}KVQfrMgbd?i ziXv1P6H^o+!g!dX0u4gJ-VzJL&;doxiE}WI;=VWs zt1#;IJ^AYqFvs)42pH#Jy&eG*I5-n0&cXbRF>}xeT!j&4oP$*u0plF3!U!1WU=>Ed zI0vgR0_G8cU5FFsVE)FyI0vgR0>(L5g%L2v3~Uufz#PpBBVe3^RWkx6aBwD0q!xXy zv{(?*N?sTN^O$`?$~^++bY2(%^GIG80dp!ZjDUGSg@qX~Ei=FzTO|`w&83LR!W{&4IBg`Dj3nO5T=7kY3E<@C21PnYB3pAG@fE3e_%McYtn0d@T zp~485(|KV8jLQ(!jDR_n*NlL9z=6pG+VNa=EfxapSY8+bb2KlEfH{&EM!+1-3nO3- z<%JP2NRC*bb>L-LM*!vS=k7`!ud{pi;c~g$LvRL*0T!OYs)WjWJlaOY;!3TiWdbX( z4-rUGaZ}$({Qw`2D(6U&)IM?7b3B8&QBd&a+MfPeD?8?R! za_kfS)MeySa;_lf!!4qUQ~m(gD$0 z6`A6I=plg*c`B3+-w?zsa5!(*)nqa#ui1SPf7#1^;J3Im1r;fQSVx%L|n`Df0PU&3${Cef9k(2DUr6Wx+0| z4CCL!qI-{3thRz9SZoyJwv5ATeGh252i?$f6?1}1R&!K^uY{yzS`3)=s-SqrueOJn zEvrjH4vXlr8+NUC1+}l@wC~W``bfBq=u?3j((Qf)O;4;lr6sB#xIrz|N5~h9pm72- zeW6ndNN9L*wraE5uc9Jr#b(Ve$*cvL0>Lf!k8jo08d3<|6ZGA#nxw>IBb!<+^Hg_G zqZojWKZhvJ5Ft3=Addl+EdRFg?r1Q})DLbU4aZc%B4k(-6CAdslHS|iygCJpL>SB6 z`4xso7(B*6%V^Xi$wj@`!)Hkc>ct*DZQtX0wug^oI-x&d(J|_e$6#82w6BJ35FyIU?BwVI#x2FY0HILg36-d zte=pCFAxvNAGXC}y@(OZ7BrpjN?}lt7YPHP$c(&r(d0pa@NgwccN$W*B8xopEJWI% zTK<;-k*6*-6=(cyYi2}`n)!ajqDLE+u1`sLSfPBvalA4jV6R#MiEYHx&F)s1&xcD zY~gsen@bsB7sh=w)#-1VYzavS3PS%kE?ZnyZfe=$;x7{C=TNp}a?8`Cxoq)-uviul zSY)tn0@)&|=d#75%%+hozK8K&N4EU$ObAj-u7$;>3;=F1xXeXPu#u%zWB&^ahlp|Q z+GDr!)QKNue@j_q z=x%*md1xkJK!H(VD-Y%rK%4T&l*sB^c?8Uum$H2|8`;Y9x$;&XZ#@g*I`dW@_AG$d zM!Lq$JjB*p_40NeZ$jI7LhmXYdcp(Y+``8|np;cKy>{h05!b$rCj(m>dBQi{XjF@K z6&}RjbR$wV>{Oc=7gXi( zcT$B70bD+2mu+3%su!6!Hq!&GWe-$qrgw67+O4lTu~NHh36I0d$@YF(RL%4-$JvRGw4*vR7BA@(c_ZYTt@QqrEVG_vT-sy(=60>HCuW7^i=^zNc}wh1Oo#IHKP> zy~g93Q)BKurs(M7@3;@t5hD2P;nYsbK`Enf-`lNpCjrviUTHoNA#MKuXYXBu?7FIZ z-}TtLd-qG)dRT5teyqJMlGZKzqNF&MFHq-db%j@vb0DW&DQ?yIz^%%Ml%Q_KTrQQW zW9$ZmBOjcgfQbbd5MW~2SV4dxHgOJZkU46G3I#BF~`&<7&QpU-)lQ#EQptS(wuJDBlhnWv4&Pz`_aGfxgqTF z`t4yh+Fk5)<<_*;RP|bc>gYbj&%ZgeCwS#2j(!%fuNd+a;pzyGRkJ+lvy9iGXVS_CxIS{(6wsDAU}E1rlr=grex*3~hNB%1l0yu%*zu6amtrk;(sV1(jN8}!Pa%Iq zFSH9G&2M}?UGZI1|4CaSvRJ+(`7){W*cRi4D1&5|_= zm3f(d9$+rjwf*|V(440VdFk|zH}H?P-~8wFs5^3#b{nzd$x^|N=C9w@Y58lsIJ%||_Aln`m+%?7 z6_4_3kL+h2!zMg+kWxP1mdCF%XWR_^?>1hF!;Li5+q#pPU8mWk23YixW+w92E1-Qc zOI`|JiL;4q&yJ$b6lrl+X#3WS=-J#a(>Ed9U-JUC>9)XVbK;?~J1qX);^rAidy2e{ zd}V{8LGdPY7^*8Tol@H8Y$BV?Z?K;K&@oUAhms$731eAdVN z%xgBecYDX?mTB6qy`~~PO&`BU!tdemdvEwX5Pt6rzx%@Pjp27!_`Np#&V}D&fwUhD zzYm1pLm&(L(b&7kxwOq}3Qu5qd8d_b1*k1RxAOAWF`L5X6n?=UA&vpd5h=Kcg#iw% z$?lYP!~(Yc>3@N01O)jalxE%iJM2oqAu7J3_Ocf_2ZERm0NN&WL_e4_pq96_364hR zSaGl}=JRnOT~-PY@x89RiFqaiyk~=12;V?c;oFJt58|8J>cKZV7BbBy9LF44G=6Cp z)%Z2UX=ffn7@KTInkhXxSJ-M$03)FiAw)JoS4kvh?@r`wOq$F_1ti!)@DgB2#$vK* zj^AI0*FR0H?647FhKm@+?YVu1PY51@K>79o(7{)t&1?^MB_5; zsK;XltHg4GTZ*a5)^N8NI|*Q#A$Jbl)IfZH1Xt!rr9rm>n#OCbaZtzF)z$~x`6ISx zfNS~ui)$?mglqq4f`mAc@$K^s3ldVfw0#>(-fy&RyIfac@g)>%{|4KgZSw{eB08{o zFFN6Y`U@G@UhmC31nhLm-qIJ7VVhva9<)r_kRHvLPdjn=@qlekS>o!y*iM4?jhY?6 z5-+CYpCXKv<$MsvaOH(yoS`9)L66A7x`s>|htmB?Px}NV-$3i2YB`xqt1wq6H)JyH zDLR0}UVlR)6Zz(W2EZ03prDq3Gv-GHx^hHDv?Q;)?JCv102NXJ+jHF)sj2O`xD%F5 zAz$;1LGO7~eBwueyVsto?efjd>^KX%HffI)9jBCuPu1)eQBZR+3QD$`4)x^IkUKz~ zhyx|b=m})p@ue>CTL)ki)T6Ts3hEI@?~Vl$@}Ch=5=dKWO33O4TtQOlthN6Ogqs>d1RENzKe)PMQ|;hY-jodYLO@mG&1gO zDohV)>4noFEgg|CNLrxuFpM``rI%CKT>Thtrvvnp6ug0Kq}ufrD5!&arh&J*S~d-? zfJkc&pyqW-`eILItMOJuv65D>uv*tzrLG$BX=xx_v3Xhqp|nDXIy)D|2`CoK?R1pl z9+70{qWC?$lkWH~d9f+euPf*-!Y>${F@K;En7?H- z?q-W$>imOwS))V&vNa?beD1rpdi$%<%fWLFrg$xzI87q4sxJ974y2C6+d7i*gy%4` z=uByTjG`$w-d0ePiLCC*P8(Hb75}dmTNw5)-O9)8dW0pcaTF*b3n+v)taUu86~ZLW zqOhcToDN3yt!!nsdRuoLs#i#D!R6&*K-tJk5eQ81bE89s_m?CG^@}odz?36<1NzNI zY#*d%*Iu+2ggV6sSz;E)(fIP`Mqf6q3d9veOin9WX{=%(P!;;xO!sV4b{$q-*8P3B zA`SEc2Og}VC(9ZD^L0wSjXN7{PSKJ*G3DAGn8}cGgYk zt%zcAk9FC4QRupCl}K@2$vxHyl17xkL&Jo7tP}S*E6Cb)VjXMC8^FIN+)P_93Z`M; zvtEA7wsfW!M*xiF{;_No?{qc@@$eAEopbejB<`H0-$&!lTKzr}ch1xA;ka|YejkWC z7wGr?xWjzRB=^Q0I*29{ch>0lAnGU+NOz|48%jRSgB#OMrWbanosNEQNIPB0p6k-i zg}UFFb^zeQ|M0mtBm5DHLeh>^bk%9O=cj-=5Poeo{VMD#d=#s-?tuD8`D)B7T{1+H zp>6AKge1D_vvn_n3fd}omI}JU_R(xjwq7{hU5{y&tPcGk(t;o9dXO#2h z(h6H|N zgc_DO8tmLAA<-ltBVH%GyL>}FsmxU}A1=tXrcj_~)?JaF!@mjUzpE#hS&p~on8?7x z4wZxe8`I^L!BJE#tstbbqGie;dy6Ye3QkE`u_RhAgJnqTD85xd0bd+o0`hAyQGd%@ zk#C=`f7|cmv7D(MP(@~US%)dp)OF2mX+lFj5II_|(=Re%C%^gaI5VxA{FP%9i@T z{3gGxKej$lH=`y*n%m$l_Os4T?((Kx6Ox(;p{k0rRK;0?RZO161PS*a4Y>bE!2QDk z_l+jNeWM9*-)Lew(8Rhx6KjknG}U#QD3DILPsml)F44@8VknyN&H$Rl0hzM(E7EEH zO~A4egR)`FlZ;u8GMav27MLS>F3bXXB&aWR7r5Aft!bcuoIWmr0HBa#6P2D0Hig$~ z7;yFiC?yJ1A z8G@&;1pePwGWgZ0yaV6Lulw%)T3dr9>rfIqtLX%3yxPF_0*%!<-TB#h?H+9bK?fnh z$$0O)JQL#Do6=U7Qjr5y&da0r_brPDGu&{cLY(v@{6X5|qcevF_bbgQW%uCl`T5z^J^c6l{DSa4AUH>$ zI=g?8C$bHlRk-40s97uviqIysQ}di4GNX%-GaNaCRL<6163y@$?v&}EwV7?SuDrpK z(hfJc_(Vm{B6admQdv8yG2ecyj#Vl-_7jx^kGZ{boxM|))OvorL3U|(}t z+Sgic0=-N%z)B_Y-%rrruW?$=pITP$buYKL#k{%jvU*jgMv0TvqIkE&bMOZi7 zURsF|YCr>Qxxu+gb3hPi@ueG_ z7s73VF+7o7C~lZBTS|m>-U^sfTB1W zp=<~g1^dSUm1VZM*Wm1INq2~&qj+wI5X}ux0Ar&AV?(wf+qfVwMzcO($lzQWU{sg} zNH)qKq$ASVH_G6omo;z*{YS(U#f1@E`}r87PhnU){b5ngOiR$4D%NIHv39Tu83KmoM+25030Q8XCRlFR50)GD_q$&(DQoT*O==zc z3-lUpS`J63KGV_=DlSY*%lE-Nyk0XRaUMxzn%G??y+Ue(^a@EdGs3(!Zm1NU)HGmr^RH34w=HZu5&pd3GF&#bTpqYoIIcS(9ALelL5G0NUkyxT> z0rT)nWFA!-bshWJ&CdyiOdG_5CW4I7N*1yBH}OY4KHE5Qh~y% z^zux%^?L5~t-t?z%3GK1ef@SC+j zQ@zu)J2%(3ELXp#L)|amAb=|bh(^$?vgk6}j_uDMXlS})U}~xu6sworq^gSLY#WxU zinCFIWC@JyHi^cX|K|QVHvZ;EzQ=F7NRHdcSsML)+B~7+OOhAoH_Ee_e?$FX3wVD2 z!@Bj4LbiUMoY6;zifDl>v3|WeYyLkIf0MF1D4g5G`eNcv4+m87H;Zs4=2t2PTGl9W zzj@;&8}!?I0M*0aP+x(OZ}Qa|xgS8qDNBl$(jis1?bADoIwQ)c|giCA6l;0mHN zl5+`i?1*h@7mHrE^At3JHt@#f9`TbQ%s6Fh$2wE8uCX3 z7@eLaem@N}k%Rk)LF+3Xw)V=N20|1kC|5Ml@CF)H1C9KFqJc)$fFcvUfkuAo5n64B z27bJ@If@HSC+n0ahUsjb=1|llo{?bla%&mXn~0|T?@Kli?Hj+2c!Vx!&=oqqwr-m&LdkZrT(~mgB`UcY@j_dH^@&d zoWaRp-qAz`87F{9a*VP9-<-e^Vl5IHPPE)hH}KS2CRQzbm z9x!>8wQv2m;OfpO2^fTtWkeEnFX4p9%gam@^K$wV0%AOg6ViB6Cqzhp@(DSe=>SPj zi9X(toGF38PM^g2NS@UBU~CJ`hw&Q=o0#atkcfCecT{vf;p9(XzmvZUAGmzr0upMX zaeZ7c0xGa?b>h^ zK)8Iqaa(t_`ik_>&Y6`IWkoU)giA;UqooXP{4{rN6jbYJV7Q^0O%W+*|CmB$Q(!_z zb32NDDrcM0<#~%G8%6wEU?`?I16?^2S-ul5vhd6Cux8>#f+Ph2Sc)hWFlAhK*J@>j zi0Mt~A9v4ErYAcCmk2;JT%?Dc<#FDQXtr7e7`+bnYgDVSQvEbEnn|AD zLE4rt0Yi4+gc`VMbK}(;bgf~V($32`9)vl*gfZCMpoz^Om--$kH)VHfvXETu(R( z1KAk|{TGWBvdIq~*^fF|EcdJIPAe(4)xl^&NqA>j5uA+Y^|2`g`O)V|(!+hcx{sDOtFhJ%!5b6%!3 z^PsS~&FZnmrRJ+Fg9gHuNW@^Rn+Fp=yjeX>)?$jyUF#7=dPq$eQ(j;On=3;EQGJZei?)el*RZDmLnK)F54}Y=mfV!sHBa2u~br zR(S~IR*t-!K28^@giwabw2+^rpXqMQ^5{kY73W`i^Zq%0xz99F$yPPw8JtpOaMJo% z$VSA2kd4UCz>8JaU^b#CC+#~s?{E0~&&);nS*oumTakT?S$aqbr_6u+{B8OF+|G^A zAtF0N?JmO$_j?ouZ~H}DM$e01NY|tMa}glB)Go;utYhF+8uApeI%|og61DF+rogTu zM-dB)cH$N9pFpq-=9h}>{EET+QlazPX2ZF0tS{wQ^=kMLdD2<4^Sgsr@7I7XW1UeM zrsl|cyd8ka9sj5N9P!7$&n4@lF9!MMExQz}oiAi|C_X@SNysi0*RvCOB{TeRq>1N= zVq9!-w#6I!j)qudS^)AyWgPqQXXlvMAur5m3^dLB9Q#WnUR5=d`)()pTDtYBtiKS? z0@iC(S+BEmpZV&u2`9em&j3gMwJ5(~2Ny*;qB2R*;g8fxfAy?}l7Bb(KP=MiYn7{X zR^hM|evZAv{~D#si88(}iW}?rFG&gY2^sOoGGd_U*=|avg)xkDmNVEXj7x@0Oyt;V zyrzSDE7>Z?AFfLAGp&n$;FEw#o*VHI6?{kqtQp9uPu>~$(WZ1Cr-IA&g3EYi`1p!k z)k^f@hl-n@!fW>PzG+AprIlfM`lv0@O1#(6{=p|`NUd6->JARb`Zv2_JOkM&1d|3S z*zPy7=pXyIal#G@Uq#XkykoQR9~f5>B-B#-^J;yTjEdfaviu)ZuHi!^K751T{UP5O z%t7Je21t@F*XyO92gXZ~(X*ayj-<3WWk%$*RXLKXaan%SEb zWwBl)5)c$xu_2cb5>m9fj;uE0B=1UZ>b9nuh6H0m041q#1RxE=Nf1Ef7C6V#908Qh z?dgmFNreC?ssRC5ZYU670ntJBlmY>saiRl%`V)u}Phru4S`dT>dXa7l*%9TtR}RPt z)HQZ(mK=Z!?)0`E{X2d?J5$0=+~OPsa*3(W)-!RZAq>Ru|_-j^|QBkqGo<* z7c5lW+A5jIRv;-Wy4cm~T3$*ncPiirhCBM|PLqYRxPARi`lv`{*|b!aO-tjLnihA3 zR0~ydohh&W>Z{H0QEmM~ePZ@1?7_wcw2ieB`Y^xU)BM_cipI2~@oH^G8_ge0kryd? z8n4Cqt}8f+9@wJ0aKzRX+uCz~O~<55*ey?7kGpj)X_vsQn=*Ht%^Ujpc4+0 zr@r#z;on-Pv}n{+O4Lm2uM>>Jfp{CI)hI69I<5=SDfa3y1c>))AzJ!!A+%cH&@|Gm zZh&WZj8K~NGC^pSAY^hYVn$SNkCMWiDVL2SpG!qXQX(I!s*o?q4{ABB)Q;9O49nl% z)D~&wuPKp>m?|l`0ULvoTcKBzm@ujn7T;T`cV-!J^o!vfS#}NQX7pkY&TV#Z&HQ?C zE*``=k!QfU)^8Nfi4f?x(0-82h?wX@!y$;NXx+u}i@IE~Rs7w%JW@L!%=Ug0^g^6C~k&v^a zRpymj!UyPgRlUgD1#arE;b+5>*~;*GE9MB}w6$%cJcZH3+naG(_|Z3)o-b)L{r^k> z>9T{Q5e}Hc?zjpMq&(-8mK!dz1|e80#^NZ7lC%-EaL$mSp9qyn+dLG9W9-nyA_8&} zoTynW&8*S>rNW$bX$d2nd?uXUlx$SwkbK}IFtsZkB%>oFMBmF$jG0)zkjrFqfs_w7s>Pj?BW0r-Hu9w4V;5(Zw(=Ni z5P5F1Pt4n*82J-RGd=_(KY^tZFp_B)hLMgBmOVoli775T)IPHRVR$HY+?QLLGm#GP z2q;)K*^h#~O`bXmTFZ=kv6ciMU2CtJ#5L5iiTb194S_y7BTp6Y%&*(yoUvy2s1 zkhJQhWii&f^vb|NB#BD>AQH{aVh>=u>^?>deh$gL2}>Q0bw&B#{H!cL>gSNy zB1-Wod%D9KkxsSrB`WpepgOE$Ov4({`Yp*HQB2V*__^1gUc@C!L^B|%FA=3$B1$(< zJOhsiD@1AE3K2H@M=M}WIu=f0Fz5v$lIeA?L?e2 z!NlF`dVu?QG4bscu!dmb;qS0c{DhM27ayVp$GEvVux@#@ET2COOuSZ~RhYPQvIkh# z`O`DO#1lg?@t>1APdr@biS18TkZm}P6J89BPr~Ku43S04g&5*mUX@bEwzyMah%+Ta z#5a_`<7kP7C5_Kh{yp)oJ{qrBX;$(>PGS&a4@>6G@HPf^xSJ(&me0iwU(8QHLRh`n zA=zIC*rBA^Fm~8}_ge}IKU{7HZA^S@v<}w+S@RbaXn!pf{^nnmAlx}plQj?ivMitD zEG$fiGokRKtsbO(ycGVn3RpuZ{D~LL-&g=xpRCFs53tTzGGMj$R*>qUSXW`5cwV^s z2PMzjT}P{*9VyFqo(5X=@xu9Ydm!~Vc;SBx<%K7a%70w}_t!(SZ@jx;d%H(#G<)wG z%5u^28Pe<_0!aSI8RAmthqqL~`nAyP7w1Z#9Ij*Hd#Z9B_IHNBI{dp!1g!SwZZ4!p zdANJlm{?3If1rYF4~;)rQhCpbQbZh@3}`5+e05d6yAdFJx>9*=bg88Bo3Ah6T9?Wv zq3};tp#8N__$@y!LEB>i&Q*H%Z(EvQoJoq_?)T&`PyPrOwA?7s~M z*7ZvQthuoz0#ekbWk+VP|dASC#GXsSXiCM9g+@ zO8bI1o)|*@$j#6)->edHke@-DK6zqG*|s1)dT~Tb1ceqRsK(@#d35_vzc)=vnUDJ- zJcZQ5vM*b4S&?sdXPIl zmW;KGauLCe(*F;ALDJP6xKe}QZsZm1MUBB*%UxUUHH~y2 zl_H((IjF1*%Yvid=Ny@*&uvw@=B(U3lIrBgGG(ofmWnr;cO4sHgx%5nJSa58>`Auz zzueYBd)CPljXlu^isK3&U|JO`*B51gQqCDW2PnoP)Bfg1fQ4qB+?twNJuxt7#_)pL z0lWFM;Mw046QuBswfsCB`o^VM&qA7H_U%7^S9<%XCGO_sP{w?Y<5$l& z>WBm#vZv1S?Gb%zoy^VIo8*u92n4?AZE8hVljRjQpzZokElEf43CHXONN2XB(~QXA z_NXdh{bufcVFa9$r)P5QTb7cRdLmog<^d4sJhdSp_<_v|VGlU7pJcTlEmRt9rQ8yBMlAyGN`Z^TM(#*CKYP!PY_O`n0Nxa=d&#;7Fi3@qPo% zRvu_+f_jj}j*A3Fx2n}Co)8Jo6!H$qs%%=Wd#`;g=3R zWA<-;c+IgdzwQ3_z3(bVeI2r?G;3tglLO5H1b@%(wsN;w42==AOX0AY1n%_sIW8kE zm5dM<WC3kN1^1;oNNkg|0}@1;2;V84nF*;|LP1Hc}!{vb9TNo6&GW5qIhp z3RF}LfVCu4C`R7yOeO?1SzmSkdrCcHV^F>Aa$qm+aEzhmmSUaw)zA^W8qy699Vmvh z%P%#gcNE;IF?-~fU%2M(fBdt*`$J7peMB3>xwSSn{I_9j-t8P&xxm=6fw2+T-ZQpI zv_$&a>PTU;v6&818yh(p>tkbW*v1C_yt+H4(Q%@#Mt8N(k|ykLtI-8)6$aL@bzpSk zJ|<=kgb$-b3SVlfD0I52%go-6L!-Wbe^tD%R4f z#dyReS7EZh^kp%XW`3{z)|d(>ehEqhtQk`oR3ZaY0dLkaO((7~rXnOXCZS}STKSY- z!z)rM&^9*uU1o&ApRC3c+RhW!I!~A`cmkhP3L^%MzNOzi3S%e>)NcwSwC^3OD~zmD zOQ~t(-_&RwISPeQ8B<)7YFPcQKAHW~CEE;?T2~yiEva$`DRM+4{%wQaWcz#XHql6t z_wwJYd`M=Ff&|dX$mlbHw6xS44DfEJS zp~VuBtDBQ)u|;GEO6*Cs&8L$+_E!ZzPiEixPxtM5%XhB5_me^9K4a{$H@tUQ-CSCA zb6FnefHRx$#Vr2~Q^vgl)rj55&XQKlICeZ~x&B%>nuh@<1G2770u2qWgJV zg@Kc%Ja!Wy*_vlkzI&a=(A*6l;7+;xC($MOfm6w-KzG%h^hFs|rCQmmJl?2}-Rx>@D|Q+N zh0_wdpn4X%y^nI@=4R=BDRZ^6{t|%Tn*6@)ch5!nc>XE-y|8k=^w~+92jCU#By*QH z@(1<3J74&bt;+)$P^B0C6g(}J=B}-nLp1lF6khnnjjG^Dm-*Cd%ae8A94*1nD%}yh zsa2k_UiZp_Km5GLBx{`?nSej2d_}k1aNE1C{rokzo0qiihrm9^N{&?HMt2-!TC=FR z6vnW)I%8PSywV^A-mh52(jp1Bk-*%uMg(%Wohc)}0ts1othZ)~7Isn zV9!tY+w&(gZh}2uGj2|5&Oa_X4a6uqt@%$xrWWk%GUeFqpZe(E-Ez-?`)u9kDMhEZ zJjLkrorQJQm_0hb>x0*S^&Qtd8dl5PBl?u5(|1)P`0nTaW%rvu^6x+Wu8m-sQ0r@H zXF#a`@wf!4Pm2h(=EnVvk*E6_=5s7p#QSCGPFuhj9bCvbRayE3FJzn!*&?yz)VJk~ zX}K&3y0lL?tGbF*ogKUnCd|Kyj8j;2rU0f(@F#KIJcr+oc`%VU|A{>VFDTl&j- z6j|x7uHr_0YhxRI-48#1&(awACv0g<_Cep$*pZKw3xA)h1{CH}OJnu9ROc04C~o$``TDmtc}%JMUPtjo3BYfE&;u;CjFj@;~c#9+jk%M>WR;urxn<7PrvJ5ZvM#Ef3d7cgY}r{ zwV<>!P^2H1#k+`Vu)CPCWcKKLe}2uU@A=}}p7WF=)Kk$6_LxR6x~v)4vVA?kL_&C3 zGjJ_$Su-$YngD{jF)}n{<`Z$xk)4GaehLyCXY3?a89z0bb#OYLn#-Daw~bQAv{N;I zzq2Ua;mZEeJ0H9LCpYc>5w?xJpd=`!k#4k+O+1~}xNKLG`y=o9+>h_u`SAxI*zBQ( z&zP`>tcI6-U%ZIf>?w8+sYkB#uHbku*erDw}OeuVHIq+#&gs@R~`0m{sD*}1bV|QG0$KT(& z|Fgl3`iwD~{$g3lT4D-$I*E{l!V&S=*lwk2Z?~2}wfKeihV^zH@`oMwKPdw1Y^`7W z>wnX>x8Jf%AWKXjPbVwnOO>7e{=eS)o`3x1k3W0-nI=NsRqc^jwnCP~3VAwF$XhE4 z`Odq)blufIeCN+jJku!Twq+TzEJGGFLq1fQA;%8v+H>>AuD$-DXBvgPY1vR;rjP|G zq)erf45U(d#@HcuE&FaAZ z4|eYS=6im&@0ms+pI>%lEmO$C6jE$ZO!`t6JcEL=9(WhN3T1j(4tyt}&QfgldOB%Y z*H(7=!|!|OuRi{f4;=c=Gi@>C-o(i7m|?yCf$A^yI5lk_k&?*=cyP$jRPhk#^SBkYtfnavNpHDf3_{%a3Ia zc*>@UtmnWVx`lndQD&4{Fr(?uY<{QnJNMqr{H}j$&2KG>+8HJ(E%PRYGhlAKt3OHU z^~C}~WA^WV{L^1P^no{SzewJlddeh{lycz8(=R>JNipbHBQDPj*&V;Cn{2c!1H{Rb z|4J$8^v6{ek>74RuCF-C4=Us^KMsH-S!-n3r*u{!MU(97)7}-b&9*$P+zn`XlJ~o$ z?cE=3xwH^A#t8R z*sS9T72d<4Gn~&SO!Egb+qzAEFw^@W+twZN2U+if>22Lnf572|^{U#O`RETg#jyTB z+0p!g9p`9`>qN)tE$J&5l0g{Ex6~6Vf5jHkEn8mOG1X%UC)RGuTIJ2T+p^K}hQwkc zL0b;P?nvIy8ImLU6&wxpU$|<{L=ia~o13DBj?SD(4j3A8#2(`&SJ+i0a4>J_}PF8GLHr z=2d=rIYaATwUbbcBx`S_J4iWTxzlas(zv-p5H4zB|E{wQgGRqRJdn&uBgB4e^)+cU4MGp27YBc)%@2LbWo{Hkp$ z8c`Z20BF4ZskaMx#s{F6h?js)JnJO7%tv0^ZRK0xAE40XDiV|DQ7M9y%*fv=g^vVi{QvHCwotJmVAjfe_$tP)+_l2y zDoH$Wwp{!@-`bmuUr24>it|aMrU)$4_k1<@!9mA&)g4&^`be6`g0G{+)aqXw>c4l9 zFHkgUUrdKD4lnYBlVCB1bHf)XF$?wz6-dt*!~Yq^aD0)scbJw{)W0#*k6yK4{jQf4 zU(AFr!21QiKP&IhA>&mv#k-t)zCLL0X&^2Pq1FD?yV%rElA zp`I_EAHF!a$QKXzGv-1}QZo4dMc#h2r~ds>XyB1WJ~`I&$${dNqllj|1wcMcAEN`M%1Bt#F=DWv!i3!;rKe*Jsglh6F~u`9i*t~oRi9O zFsO6tTlI;==)7K?fTxcY~QjSn0S`$t8e+`7k>1SZ+-o<$a6uLm*pVa=PxTSb-6KQ zp)+=CE-R*JV`hh*WC&9vtdd<;8`PKnywT;p*zKq!M|smwiZRh}cg)>E^ZulE$MF2UQkym> zmsqZsmx?!jwM~psRsD&aY@3qX;_mpC^p)IDwpAs6gyo9m5V|{lQxFmGW~yZXf_Q>>p?{3+9aFqcvbg>4@dMY`YC=UkWvly^bmgA9G}x^}RsrZo>3Z57Ckbep&x;$& z{N;Nj%;jBk_oaFAT7R^yi{DZ2AV2f{_Hs%e;`XOy=XV-%b66dKv>}&Y>aV|W1HcxB zOD3;+i<@qZiP@`=q|vM%G+vKi1JA}EZZPp3-npV1>)B-+CK|jpQFPO~Fua@gNZmYC zbo1cwZrY1gH|_Pu-_4?jR^9L(+9UPw{-THX4)3A8SoP3eU%DPzb;EmTkJQ7%MGqes z-a~t_>Y=^9bUn1{hWF4OsfUjiJ$z(%5ADUOhxYo?_0Xyt-a~t&9v&@vcw~4F?Zv8x z_WIKG(5f5WLwlqi9xr-$Yr2-| zt8RD??U8!8qv+vwT{yF=Gevu`>Y=^9bUn1{hWF4OsfRm@9$q`VhxTICLwo)4_wZ}0 zl15GcX_Y>0iI`#kviRaCk`K8V;X-a;#l%Pw*>6&h@XXM~N7MG6zeV1xr{u8t^C)j$ zcMC;cWtLtXy)utqh&qyLT@BB9nm@*Zmg`RDMnv4C`HyR5c(qt@O7rhlWzwDgZ)p$S zvU-4wZy(xiEvc0qF`ymyhPo(T7e{Z2m6{yM_w4AJ_<3>0H+Y9|(xNZnF1;3Cr^I!d zo0=r;A^ro=7Lef=RXk-EP^#n4@l<7gJHh!z@w9qr5|V&$Fuw(c`@AB9=p3`$5CU z?u}+y?T{ghX4%ScRJ#7c@}3U4m>k!vZM0bvoNZ(A>cc`kErfZm z^jkb_f1?L8;(T0w2A^tMUi7I>(d)_?)oi1sRRx;xG`Oc1n)9rG&L>-%YCH%wJfOt| z-i}MG0*c2}r;2@aDi(5I6K{#eCYwt_WHiu6VwBVgtc3E(DeQASa6D5A(|CnaPGq2R zopc0^rwY9=c?G?o0z-jNDdw2tV?XH}b|jAL2&}T<#Pdofnj?R=QW*oTGf%NfFKxeF ztP@NXOQb6PGFR=ZKS(LpVpQ@taVbW{+J#o>+!8hX5(>+2A@*toLSdy1EDQSC7KF{K zL)aGHy9myq2pI7q2u@sSac%=6dg{rD2bTnc&qzi9u{xqZMPJLqNZB!6$9&p$6!fIYPw@j=5AATgW=#{?)94{)dM5HtbIJ=%$n}#_4N8Jcd_USq zp$FYhp-GH)_7$2m{L88^2#fT7+|rVLP2z)IHU+;BXLuA@A}97E`UQZ8C4=dR%V4!p zdPTh4n)J3M2XSY3ISy8_AU!GlBa%}zyCvOINL+Z7eD*fff3WxhQ?aBYvYc#Eu7DUT z0VrH?vQ4p8jVrn= zJYPXr)o9kbYy)vDD5<8RrmoP@$R7G_T3(9&m+q#AqKsXs6YzDeqHFSe-n-*m?!*N& z!L&HE^?(qqNgnKIn7UJ&cM9jKLhcxNfi-&?Hk_6XL|?mDPxCkMMS;mGG_<;=R`@G%O9}dTCs}j0DWu&YlyP}@GLDS#{O zN)<{oQmt*r1B;I!Yv0m7162nJlZi7!5CsOoNln)DL8qW@3+BM5RvX7bOY@g z?Sn@014Eizp@yi^GzKo246{axPbVj(Cz$34@Pgy{=&n&vlqsri%bUE})i_tGhwe-X_)(=Nd? z(^TiPR3NqPnDg+t?)W}@#s|AV&}`);$((+f@e?p-9l?4WA3WbVyN(gWx{`3SI7JZB zc?ip#D=Nl8&2B)6jKr+7$>&Bli)jP4nq&~vHE^--B%@ZZEo-&!36es9H@r7G5>L_m zIlHlr3AY3Ct8`)Pe-xKCon9RM!AeE68G9Dibq(u;P#4+2$GMuZE0%o%3d##{+6c9W zaRuHp44W$cU~z*zaXvKXI5Sqq8BM5J?EPq?2WC9`!cB!adSLctcWICZWHIDn<_&p3 zB14|dCGuF@lW9v9Zwwka@|+`<XJRHROUv1S%z6$I2^1DK`dl)$AjY+_(G+^ zD@ixUD-IL)h8D#uMNK|ocr_)w^5KhjIY?A?stEQdCS$*8sWQX&nr}p9P+tKi35DR7 z`QreCUWc5+3xL=8UZHxqZb!2&#cK|s`wLA}^jT|O<;Ip&-s_sdd13k}sGVM(CodsP zcU-#Zc&VF$KoBWHBj~0e&|&U_j>3g%KXu(ylkWYIm^MhjL{6%ks^=~}deu`9tx!+h zB&aK?tg#yR%bKU5q*e^yXSe7kW7NE+xleGt*kJ2(Tog;g_+w}Ipf6t?H(hvoTl?>? zF^zL3InKJESgXjwr*cFWA~U-X+8>BqKOVeTpHIkHt>NxTEo_!=Z%swj*`!t$$4t#e zQ!t0DKwi1s#G-6Pw*BE7UH`q!zAPA=MU?JCF7yU7y3dslg-t;f(H&yO2Vh!{ybgvg zmkG-+NnS2jrU%2eygfzLgfK#}^Zr(X8&3RTlSx36nP$wi_p3R- zk3l|t0!^ZhX2zHPzAW@^TH)Pgp`)-B-lM`zsmutqb)UV%1Tt*RuN6L67S?L}R#{l9 zjbk>=GFlh-qN97XSAutE6H)6D`Z_Lcr%;-|nM=pBS~b70x+~tpMl5PmqkNyPH8x6ok{By>QCB=|t=QkKP%pIMHj~~6wbgp79U6T|h0dpeUmU&M{K>N5dK@8p z8bduHA1+)W)*Mm(Qmu&B*4OR>A-ccr1d(5#M+-SY+$bdA0M6%N6P0h4XfUO^t~AZ4 zG!w=Z%7flj&CYHM%|WF#o5R%x6Ph)(3tf^~M(9x6sx8>JbdqL+)j?BX^?~Y57d55K zsxq6zK94fK6xig)nQUm%e`9;k#)<{4ppzJaSQ;tDfrbx;56&HhgHuQ0;LK4tIB^s% zJa5_Koi>}aiNgK%i8M`cy)}ycGVRju#^B)b!A|Q2vmpl4y9CkT{<*0$;_?=%Y9MX2 zTn0!QdGoa$;$%8wD#=FVHcCZ#V~SE96GHpiPkz^!$C@8R!ty@Mj4nq_L@Xq9(@(}?VEi8mCj=rirZRXDW6-!89)(d zx1)cwYcITGk(P=MEAIicg20M8#Jh3b8-2CIOsxb2And2-=v6fFiRZ?nR~6uYe7{-5 zGRcbnJx;paw2@tK{(0waSbxs++3U_)yJq#O_R1AglM~}(UH#V@wV#o0w;35X?QNK` zn@z7}=P|81H~+Vh(H8Dl!K8iPI|NR#lJauxw)Q`(l%e&%^3?^(i&_@>bfH)7uT|OA z4zTuDO;^xmzpUu#(ZV+i4QFAvw0=AOZ9!(lz+&e63#NX{hQClZ!b{IOm6tZ2%1ak6 z`qCs(4((6wDJF|vX?I0eNX({zu7#crf(!c5)<3;%JH#}fx=GDzoG9|`3gQRyhW4bT zJnTsCHFu}&(Hb&%ScyG?GA3WWt&uqows>i;*#A6&RJu*w-K;(T3N_t}~}l+%1ancnZfuF^J-CXA)(#2N5?0 zQ(>&$89q1Y5TPa^)N|DC1w9Q2d#pR>_Y|LB6rWeLOZ~-M8g+HSaDs&)pr#WLMChbx zbjsEW0;hY3l#L)xq-*Jhb24eo(TYYK#}SfPbnCJ{1%{HzqZK8O4jte~LCI?iN)8n( zOo@H2Q4~|LbPZol5Sc6NM&YkisIP}&wbx=qv{n!-`{-;y@?Fm7Q>ls<*+dUla&FL2 zgtfs%J6B4m7W65&^&-oQ|B_D0bO)C6kS#Z zJmz_c!ATUK?-+0@$Ob^PVr-cDoC3Zw28Pa^wlzxEEm`k|p{%#)R+w06V?t?kfsqLM zLSu5wrD^mUkqB2zdbnb;!xc?wWIau;U$9C0O4B1@p&7aL1NY8FI6l+?l{<1Hd0w0U z367Aw?Z}PU=vXhU50%#Rz5?6m0;RTNd2s0<3&^Y;=U{U~WCbX3$6Ir%s05XP%}~Jz zU;tx^FXf7$p`06v0y$Euf>K2Uw3E8xN{=EOFwdj&Q;{HtC;n4Q5oVnywQ z{+J`Yh}$neG-?_AFsZ}eR=o<4g#D%LV;lIYBEN!RUsOZb0hOuZ#)dS`k<%oO%=H4h z91%68qMQ+TmDrU~*~&0s3iQS~0mZXhWQAaK7UPfu~s*rdS3Wpc}XM)>UKqFtz=b#)m+({D@~Eg~RaI z3>8Xdo<`Hrw7O*s`2|yFb7`ot(4fNS>VZf6u3w+5R|Tdq7-u!@LFz6p?QH_`s{)Ny&8MbXK#^uX;MYX5mir#9)QlaV75SmrSh|L3;>~ZGBHZsQ3+7YK#|T_D)Ft^JkK>;@j;=FGki4X$3OK?6&@5g$VN`jy*O zq^Kfm)v;1@7vw53DT~#J6$dq`e4yc;ijGw(^sD&bIlXAzUI48FO_ktIqg63+AN6_R z#_=s+>q-iSLcfRMiNgK|3@=`_DzXX@uYvr^fvF~qxJG`&a17;Y1!~mbs}_LoR1~kZ z|IEh`AWa?Jxc%|c+;zPy$m9b-CJ$*y3JQ{E(qlbBh=X*8U@`ZTMRrt7e+qP^OJ|mSz!XmNtVG$i=8r#62kxxqR4v(tsZVz4vjU+@vbscx^A@hQF(U=$&-$AY;*h2aiy zYgACtyK*`irs#5j*%lhvAhw?!jq+bSI-2NrG#wpn=(mYyRR|xr$_O{lamzrLPIi3^ zJy03)`(yp`Td|VL!A01<_{{JRLsOtY!4q`308c2N1o9L{EI?01ePVA!nK`HyuGTb= zff2-E1o1*6DBW&IzoBECxcZ{z7@JID@`;o=jptUrsynukW!1UJr>6cF30H*0Y2C_Z zw@Y|joOyU0X)*HS%@A8>PqpAnYDYzcq{o{)J}{~^ewGpBlhz6^i|1ZyVf<2NdrH~8 zF~z&S8mxB}C&*U^M)_zl0NJWbc!w`{_{NQ0x~A7&SJ=2QhT=rE*;LtA?uk;EtltyLFj3rR zW1FG_gp^#Gje=F(m1>(+^NXXnqvVdNKP($`S8&B}F%wpkIkdaxCSm8{dP3BRJbF=Q zZMJ6i(8?=2XAw4&$M^?J*lM}{!wO>~$SKWO_pdalv#w1moe6Hth6;>>Ubp?;*f?W}UFno`NwBC@) z#Lz^R-zoPd3_*}lTv4q@MX;3@0hoA^-t+rmT;P&cilCbTz>{~mjKgNmhQUh8HC`^M67ytwmk#qX{f7&$dDBy{8N5b zZ%M9T?ZaxG%&d~BEWFQ~HL|`m)Y|@E7SISm5;Sdu3-{o6chcS|EJwl`S<8xqGJ1Vo z6WQvUI+JxCHtgD}i#;1GFjG6WA*hHpU9S)r_6q8~!?vs?a`SY7*~p8KZ(~LkGs&ZI z_Z)7Hnw3e009FiarxzbSr$aTWfmCNNqC#=fz)-u%OD^wDZ3{&&gDZ{Y&wg&SD z3?}EB^QtlN7`9mP>6>Pw*}1(x{N358y;o5;d||PX0(!fAg4yo}mrZ0AlMi)G`y&=xI(9Lft83e(#Z7KXw8CPjHshNj$MW5j zF|_>4u#v#h#qho`s_;D+sFSggeBM!zT_nWbROKKrrV@wx7C?CcLXootiVl+?lnuy_ zg`|g2@feU6W*!y9U79$nha4z5N+hxX@xkj1!WT0m4u}yR{@I8Fg3oBQgoVpL1IPQ5 z9&o%f5jc>7O9zfIp~sY1uIkLkOJ=J^hB6L1?(PsNAIe+G$c483m>_OdK${B)Wnsl<)P-b?)rRXMPIHTWa~BTg4e9Ks{>dF ztP+caR zUD7M_Gz9mk=m)&(@Dj9t%ALfcL-`lnRWN@uGPHvAhqyD8vM#)bJ3}M8dk1%hICl5v z+|j}-yw2OX8x@-!%Wvb-c0`Wl`?$1yqJWjl^(8Fs;_jTXLw9gTRmYoNm!{9cY^FSzoG*9({DxZ)H8<+eVACzBp`2g3N`t@=xh%js{?H^m5oio62aY;Jf zLv{rDdDlbHlgDfgys5yO4gqh9g4JP{m@`h(7Xt^h+(O0yT^{mE;DDBcsC*(MEBN0E z;hvs23QJQMgRI*ha&Da;Gg5<5vR~9x<+1#P6&YVGinddwjLB}Jc*{vJIRXjlfE2nb zmoHjio(byr+mRGz;O>$Yp1H#kuzt=)p=RXP8l*NV z6kaEqk=X_^>k5sQpD}GGFrL6E35UfS*w1pmeo=o9i9r~%FZGW0eSzf<@{Pc|OJWuG zurfCz)L1SaVr8ZXIu(nb8T9N8F|#5x+c{Y=3c}MDW@BPUMeeAvTasj9oalu z1HJ61WFd8BMBp0V+ilGr`bG1~*+)PB>3@o@Km_c$ZREM$|=1ERao2r9_@_n{X+*lUy~R0|xk{I8am0=60dM zvJI!7nd&9Z&XA$iynL!r_W(GrzziP51Lrfws)CjwRlxa*u_+VnZlkh}m<9Esy~kF8 zd|K-~vE*-I!WmxRiKXUePmFH$gvKmQM2#mFPBXrhu2)&4fq7KA))T`#Dh46uQLz%K zK?cM~tY?VsgT82LQBC`(=_Fz)726O?sdO5#lppBBz%_Z-^( z*{IW+z5UH2oz;;1?4JL%|4k?!v$wx-w6hxZqs~YAnbB(4(Un>2iokP%Kq+@>qt<1yMqV^l#j~>q*fthk9 zZ|&mIpGjU!-2N~01Zw2=@ z*NdSfFD_k=_BMPl&W~GwsO=^SF9nz3G`IMPsK++&6Oy1yy!|>{DD{5+p1=f*`&=J9 zwEoB1IZHKu2o9uZfsp+5<8Q1$++K+l%&*NGXa>o-I#NaqgFk{3UYlZft{RL68sxp5 zWwPY&OeZ5(jg$$W#>$Onl5-3Fvrt5>dNv}D-qL0YdAhZFW%#0@J3@4{#bl2%SoEa2 zb=|(T-PR{`?6Oy5PTy8;srR4bb=#vI7T z%WEUNg$P-c$h{Nz`xG7)U;DL{$12 z*~xDO?h;6$^ExPpf-v9C7eJSDO^S4yzc5ID)IElgV`6kO8}5H9f+5-BF$+=a#|tS! zb|N1$*vHRk05-`SB*(NrncJgshsiyV<}gP7auiMAU|^D!&@uRj7^@+{D@B1;PmuYfqUh4$v&i}O~HH!5n>3#cdlZ652XOdS4&u5ZX zwm%mnAvgbhK?!3-UNP6qc!c9!Dg9Epa;=+ST8a9U8AX6>MVZ5ZSFIq+lBtGEitxZ_ z4abciS?J6n4gADXP(TuVs!*1y*oWN;0$uOER7s4vl?0xow z@Ud`xN4Wl&QR6Ppo)+urr>umCM0L_iK4T?&Y9-f`*wl_1f;yGFf{y`WU9#7t*L!ba#3ss_ z*!Gtt38f(1Nb{d5f$pk(TwaE(9e z_g6fV$;DA7V_Kj#bxgRsi6dZ?m~1A=Ix(Hq6047i<5wduT4VRJCc(%Ucs@1Z<#rw1UNZJj}A{l`V$O^o-Cxc!9~Pl z#Hs&OLC_~5Q%I0RF_{!B>)^E zAFHAy9c!v28|#wYon283&Gb=>PqfCMgaQDZqf%bu(#kkacy0`$NcCYH3R!`g;qqK~ zJ7a)$0k3eKfW!f%^&@qP>W)WBr(*gQcYTu0u}{mo&R;f*7u4FFDIUz&gP=~(p#o*O z&=*1F@SYaTRSzazDD$8cNj|nR&sqA)?g}3cy$F;@v(}V3gsg5+XJ(bzU_D1k#)r_a z;g?2oc&sq?{yMD=O*=GNKZaVXopJl0-3&;!%4Ry8b|I^X1PUx+M}> zV}y8vWeT=P28frH1_*hcin7x9p#Q3nIY&9;N@K&a?vD(%$W}%iYvc+h?b_LADSkx? zNX&#YnFp(|S?0VFE3kd}dSOrllj+q(KnzsZ|0>K*Rx+W*qs2UZvBxMs%1p(jQO<-% zK@W-LL#Fjs$~AaQLWK2c##HosI_Jr z>r!SVraK*p@kudAE;qS?T-fxI!u29>z|{Zn7Q9ARGT03}sH(J>0Y`q7I{184C2$WA zX30x7XybCMJX_D_Blyv!)`=mYfLkF9+TW7o^N|`T(tfZ{7^;T72%kZ$DPmFGf?LJ; z7p=etVFh2Y0w1UqTu;mxoya2l=DB=xX;?IqPJFbS%ZJjq46y5^xp~}ZahOV{shMPc zlmQc#cwn@gOz!skA+AG)kZjd3K)^7Y+@(w-*<^xzvt+KkFv$zVss`$f+dnl;*1uE* zwokS0xAA%{RAdl#V5=ss=)ARmMzyRK5|waI^7Xne!Jgz@-Iq{Law%SRT(3cW-1-re zE)WES(UG^(5UwKa%p?U102x#=ARC(KS|E;TtIv{hO{oATY6&aaaFJeeJ-)T6%t0gk zU!ApnI%&H#i>LC>SrTnjx_M}bx%4MPts2dUFbS!TIPoo1{I0eDy)wG|A{ z1+EFU3d&sI*hiG8b(?;V-tbA5iDMBP{>Udywmfb4BCdVnldSU6Y3t>t)tQCY^LmED zN{#bwR>?-^PM@=rr<7km^|?XIX*hXqpo8iRXe*%HKr^(^@P7C7J;7ZJepaJH}lw zFj&d7uax38@fHr*^1u#Lr3T4WvqPx1sa6A1Cs2J#$V*5Ob~n?VL&U@oxZqB6s29I$ zarZIqtdsWUXY`@5C)05J^DmZ#jxqM;SIR=iaVvaV>v^$|(g_I$;81t*GmBp2!eW?N zO%!s8XO=Ur#06#55#&%4$)gyDB;v|m?cRJPn{;o!G%#D<5!&@nw~s4ysL-o>*z+DE z?T4T?fMXspr!~I$T3?}Y@3XHCznIJ&j9pB$>8yDYkC7Lop@0-aso34IPGpO zI9QsmcI>u(pq4d_JTx{rxP~A*i0jZY;jUK8um&$T5v%gj7=t&H{T;#ikmM1_fv$HPSj6Ng+TzQcTRIoBZFJ+|G zvdV3IDzCNfu;oLQ*LpBWDfF|4QXt-wQ_29QPbfVkL=l#GfvN-FyWZYy!9!FGZk=fZ zE%-`eNa?jRL`P|G-lD<9n59Ocg$R4w2U*~a3T6cK%)64=+JR8lKX&vL;U4_uSLRq< zuw477>4v=k$49_lT5TWjaTpF74*M)iA21dy?p`2WS?GwZH*1I;goJQcbmpwzXRZ9u zS-($lS?H`^g|*t=hOuX42ss>1`^jOF)G4k&4kLwmI<^QYm=37`+jR1rPz{FFUegr; z_k2op069>WO0}2PZRAx`HB@HgRns<9X5=+Y;gD`FBw3We99=5=KyVmFVk#d-Vk$RD zG@QidMddtl$P^@I-GUA<5R48m5Z)!esLm7y!XR-;@c0|IHasfOIJ0Cjh)g=@2C^9k zzF{BQJ=egepgQNlL_GxB+u3OUsxnHhbstf`=we1^k{dBtB+L&NL#+_hB(%y=v&MO) zLdf!o0joK#=$*}|7jAp{Mw1UL4Q$oUOKf#-<@0ID{dw@D2m-_hJT=q<#X34xFmo%Xg1&` zsAF)`GcJpuD}&HHhxUk?^JDUQ@+;Qkfn2gk4qH>9GL&O02Tjq5CBRa(1S|8UqUK>`&_43=|B#Fc#Zh<$;;~8~rojT3z4c&cJDR-{j5!Xm?-NNQmNx4T`f0cAiqbRRra&Lm%tc)Yb_n zWbRJdmBW|`ugO}K85^p}S%)<5)nx4HNcnyy`aKB zE(H^ER#Y-0^Jri@Tb_#!xM$1=EG1yXEVsY{X`Rl~+mb0UFM10`XeX+U2Fs}~Eh^Umo^HUA~im@YANpMbu zDy$KXQ=tlLg!6c{h{AvzszuOwJRI{{LMbUp=Fb4Mv=Q63Z^?h&_taH|dAeONXJf`H zD7Z75WSsG@4D8wt)Y^fDg9_3v9!`XZ?4$R$r$T`RD5<`7D6kMMD4VbCWrx|5LE29q zaaXt%G;K%4x+AjNBlRI7cSiaI)*b8Sjx2PMq<;eS)QP^J^nMB#^EK%ud^TZ{N9_aQ zC=eGj&b9gwT!jM&uEH9E2a1u3TWQUj(3;S4Iitc_Z7yeg>dSWDhS6HcnL#5G?J?l7 zHu?ACv0>GGg|;$1=An=m5-XVM_&cq_!xJ_o`_s;(y9EsijR#3<&deznd~h4JOp13f z!W-a6#FZYH(lg@=^5+TR#b{2V-1Z~i9%Das{|dG>Rn?sO++g4JRo~8T;Hf`KmSMkvS#Zawz(bUy~jVdv)VD=yK9Pi)!=B5+oXQ* zf+Q4}VxTt)_vdOmQJJ?~y04g+g*Pnh$ySoX5NHGbMSn8%5TTzCz2CEzLaS%+6&pKF zQArxc4Ju(GHMd`w81+0338Exwrw<1cc$Z>!`E1w;vW0*&hHxw$#O4|d223tv7q-X+ zJF0i+cZN<336*;0MMpO--5S>-$8Mh@o+uEH_y{pI7y3m3g=W2Ka(N1Yoa z&y!LFT0{p$liTtgYN-8y`nX>4W9Gaj9lG+AYZ;9b-aAnqO9FCFd`Hv~|0UdKRIjrg zGbaB9hqqrGQS;?fEFkG!_3q$~d3wi9fA4r-Y%pbbL#9nW|W52%U-2B9FU`XD@6 zSuqG8QVxQ=WML4v>rP=1wj(kO;#M1k^zSns#GQ)_f>wG4!D?J>CgR#40CyM!Qv4JK zp`)^jnb>KA&=#UI9>fiUgFuguZ5X^_D8+p_8&NrsfPRajlmZ(J>F!ww z>7+{<5S8~Uwrnq|@l@Z}0TZY5K2SZK_Z0_K9Ltr(6aSnioW)gaWZTz0rHyREcvTtb zWG7}cIAjYTSSCUXM0CFtB%&N@^8Fmg{Z+TuiWPOOp8Gnwn1ZjP%YAj6I5YdoLtZ6W z?jP;KoR~CaU?AL;+KXd7&C$*$s82;!66oE)^lDgKP)fS3m@6Qx5|TC(ZXrpPWCd< zx$7)E@HRx2$8}(-FdT!9B7k#d@vTnKT5q=#P_4RtNh-nEfVgQ&2grC3yE~_S_oMR1o(`<}cV$pi-_`Y+%e)xT1MxpCi7_7WpBBus;91*}lKn zdO4GT9*U*&X*|BZ1jL3OK%D<;0t91%HPjCiU?oVDbKTi6Y{Pl?2+2(?3UH@UCn!eM zctlB@eOF=T{paJY5K9#zDO(K?Xv)(O zNP*YlW+LN9-g=$Fjtkv6zfer3{W{`5Q4TuXJkPFBLdQ#0uD0jI->YK2v=dLO9|a?l zh<8q=wJ4ZOor4wV2B0h|Uw}TE_Od7cA+^nnR<*`w>ZazVkn^%*kp zB%I)B`<~q8j?(}a%*iAbaUP3JVkHDS;r8CdVsYRRE04wE~*>=~N2q=(h( z{dPQ$k*+vaQr5!}Q`#9Y$~z^Ssy$5eIY~DHA;P{FUQ*4TCMHE{3ByjTb2f%FvKV{o zfY*qF#J6-A&_U~U?ko2`+G^X;b&|p+uVoCdF0HuA^teDKR(qFxC>q4}4RmD&xY}#^ z9Jd}orEMQ4^!nQ8M&)OblDY14W` zzZB=s-)lGML+>e;-ih^qcvNdCkB5UbGLBX=mS`ht(8ZzMigCE|qA5lmM~K!V#YiCw zLd`l`DbyibYq!rTE+n}`R#CtX0+=f8Ba-H20~X8-H?7_RuLo5p5TM{o%c|250cBf* zDvq)ws*`O5A9m8WRKnjhr79b{B$)$!#WGKTbjoITT*wEHHU8jeTBAAWZA;qb4d+R4KwJ>Zi;HwfH!A2Bm8mi!ivV{$9<^g4oJQ>`~pM4%q}3 zJVg9w8a6}?Yn>}qtcI8Kx?jLGI+J@al=gc)V}xvf#m&ADZ)BSPhqQ)^qqm@WP|02EcVKez-?Qx$(OQ}!m z;fa$>>%$X$)9RVG4zunjvq>vVE6i$o*iJbxtLdT9=fw&KKEl~EctFi)dStX*aawpO zvDYZf8ru1^lygCK19M@SSg_`9Uxjv0>@LRPLHU`OA*{nS#md9(HO10Hvh^wHy8}_G zH7%U-t&HK!L?LmRktnNLJ+Wk|p&?5ZhJ}Rh^dsSJAS%M zMP#$DyUpXNCXS3G4U)TDNVw5lgtcF0&Pujc|14%UK*oy4NQyC_ zBQTga1c&iru`+M1#~-ua%W5-O!C_@s6M@=TCQ2|wBqos)0?I(J02>4`K_m`t2Ae40 z5CJ9;JO`AC$tWO*LY$z?IPgB-z3cqAw_9q-HbEARaNkpP>QwF8wQKKPReSFuLBu(^ z?6=ZNugZ+(@Clv*&aaLt^xp$Y2(v`M2(jUDot0gNY^WohRpQRAhVnF9R|3S-3I!j_ z##{er&aPs$OHCoo?7YB4ik}zIvzkoX;MVzLcyq#GR|-_jdD9g+ohitzl$HtfQhoA-f+|uUr`DCsRK{YF@>Tx`AsJl z3C(a}*=)54(g37rH-l8&w;~LQ0q+=#6@KiT#zCv*P?TL@Pv9t zFvhd#-Hhz~Pv1LyN*3y!*J8cHM1P=n_^4Pv28WIho>1=&sP;1-yMqh&4o8)RdgrxR z?{H2S=-uIYd&dV)sCUQCu6HLE?%kev!QOc-*1H+*A1u#0;+oDgc6{)JdbdxtpZVDB zH_%Tz?+z{8JFmrhN0{(|-p$V2J3e?qy(94R+4Sz{!o8cRE;x2xi}mirQ14F8+dDou zyWYVs_vp4A8@Dm!z}Q$#(SAxiT-L&Yhj%Ex7qBA*E-wiJC4wLj<34CbSn!l;87*pI z860X+FyVB++6QXMixJWXEChlA9hopN{~!CndM5n`E*jaQX-K36an_+5oldPY*bPAw zy5YiwIt;}1LYW#Dh@lq(5pkwm!otU;W~&el4>qV4>b z$#k)h$883t-LAC<2WE&eBuN9_^N|rLgpm>6C65j9CHl(sVmUQL3bslSEvyw5JEt$a z7}8804-P~okF~3A!y~_vA^MW4v8XaRau-l4G(-z1gBl|9O&A;^se{=N4JsAc5S_6? zNKJ*hGz#&Jj@Cv8iBFUjxPmB4icX-cocKgpf%rsOQkRUfO2n7j&YPc1sKw^@o{~b* z;Oo6XxDJw8rY^aG8Py{e7l|)0-Jx}elg(-MhI4}WoLQ6z@QhYjBESWvmI!cxspYkp z-cTk$O|6Uo2d7p>fM+wc4&>UbR+%FswUNQ8HN=snWrul_Pc6-xFtx;)k601rO=)Ur zqJ#;m`Qx=1Z!YWVbzU6~Q)_S%@qy_LTB{mg*M`s{Uw4gXacUI=h;LwePE4)9IEv|Y zMvOxfV*$pY>9qjk@LG&f3%8Amp~&W3Rm%itD_qt&Xl1{ueYG(Aypg`9DS zD+I5HT5Six=uE9t^R$FN6DE?CbNI93SkoezxZhn^vqbi6$0D7Jkc!;{6> z**A7mf5eZelMze_x_fqUz|96KSAceba; zzxAmZ;^ocr7UK{5o&aLUEo2zAEXPZYpYGb;C=Dq#WV(|ZvPKg`D|Sr8MkQ3U!dB3c z#Ba(n3gZozw(&`ea}e>dh>%&tBC}f{WuL;iIaV(AqR!n=^6!7~YkFABCrb_(JvG8~2`YG~QGsjg1HmDWL1{UvKR$B)W&z&_p_ANA*>_37?E{bm55 zCOjDk(Y3uMIs-Uuwm~Wt9XCVc(K*yaeUCvNI721PwSDit2u84)A1KgY9UT|+I4&R4 zFK@<-{-TFS~NTP39}Pt@@#f;0EmsE%}yp6(a9mED)-o-mXiC@ zu?C$otl9+B1twu;%I%wA=nxYcOjcR(Z!V(6n-A226pN|b+gUf;Yez@9}i3ExUJ;p>|4Et~L01Q z0Gz`BnBK+!2!4m@QLA7AOt8%{OrWKC&=eauEfb&?V*)MJ*XcK40{j=40GayOn1G%O zCO~0h0tN<5putqsppoyyI!{nOIt$4VQlD#I;4ruYTE&%6@%N3{wTw&H#W1b(1PsG$ z+~}0?hF0JWhLMan=(hQz#J!?8-Arm1OhYExNnbqM2#MGkRmfJk>or9NWVpQq+Vo@p zC^2pqCk_?R-3O{7V-$#Ms)FI@XL2pkIfCql#Cmms!DtcfZM<5EBIJl5#`uwtx-qY~ z8k1`msF7^~$hlvWVXM+7VJqB7}h_Dy}^~Nh-hUIGvFQ&Pr~FGG=BD|NcXKxLcmx?49rzNV!-A(l<;W zw9CF_Xen=CfnjqFKB%DJTt}_nJ#kM)@oHS~mcdN$*ho6tD?iQs9$P3VQACasqK#xE zB#u_Hxseej*2__Q`_2S(=n9-2CeNZ9*V>)hp0D7yeGNeQWhH!+LTke>OOjgyhlmC; zD4pjiyM9(y*mSaotSnEG7+~}Yk~fyi<54}fZNU3zLxP}vBLl`o0+53=q_eGwK8bv? z+EgD{VwG^V6=}3OOk+Ctayo}>g$0rM3WEQ^ZCdfR?K^4A1`e?KJyz+D?x0~ha^u=Q z*DrwaO256MKc0*yV>hl<#*ykPj9E1agy^*dw1Ggd4W!||+X-uYB@7q*h>hWk~4%P`83BhqgX3J^LuGEDqMmPFRnuy?> zS+x{=No-GT!voNNPR*<;rxtoLz86DLJ!!(Pdg1Za%GW(ssu!En0vIpPaX0 zXMdPmP(CtC6-Olo)wS6VD|yEs@VEO{t|jGq)C2pTf=UJ;nZN4atX8p*FLa)x(M|oj zcdeimtl-mFE4G@HEG|ibI_mIuU7Xs-P9N%ceZPrv+<3)WvUPtd?00P+Tm8wTaRbrK zz?+d53J9Th;TIKA#@>&xp`i<6>ghp(1fyp!M@6Z#0l(RAk$(Jx6zIh&d(s|l`0mhW zESKwuB$xK}^dasgy7T`$FcaOg-DL3CE;(e>(^>NWNfCZM|7dNO=2D$Irm`1%j%iGu@lpcQz}vY_U6wmr%{$&ecP~ zsPx^id*oxLrCztsEnJF|IfD+;P|jScT*i3TW0V^L!i`=*tJSBQq7iq;sWObx|JaYJ<`7Dd(4-Kcrt zWA^iMEwPqj_FGasYv~Enrqk8ZV|tYEEH0YfNi7g|l=P!T+y_0#nO=_p!i5{%PfZmx;_Aq*;q)`smOZagFLoEd@9*LYf z5EmL$0UHE^W)83>6?7%7)tH(BoT*+XwSHQ2_`qksG=sya?GORu}_W z7iZpD-RbQ+sYvDv?A~^s6IJ+yduoTycO-^0QDd^@=l};q0)UA0>S!h|Sg|2wURLa} z(|yYUgyl{}cV8Mec2+YNzS)U+UHCG5p8D6E{L){T9&c*XzSdM^V)okTRf=~W|J4*J zFf3quas%DX28b?8E=3rM(}Q@W!7|vDIh?yfg(FNbp9P%K;iyOS!&^?M`>hE!MPUo+ z;pVI1c=uY8trYzte(w(H{rZj5-1!VRU5W++LCn6EpfG9(T}*vyc~;&A|p9;-`8 zwBupm%n)l%xj7P%=1&@lAdN~LX*o8DIP`yyGj`%ScLDcg+(~cRnk3ngV7DpZbi#ccpEEa;Mv_4xf_ky zw<&vCyRt9U!h0Tm5cQ;*HhW08-YEaIEHZ)3ZI_U$g^J^J4`G`vda?8ZOG3?>FEn(! zt>eoBCytA9b#z=%5n*mzzNo1#xh8dDTzk6V+vDTIebs6W?FqkMW>qD-pGo%Jp>v}= zI-Qp%Q|66H^yFe%J(5i;GEopJ>3-PH-csfPV@kqcY&;&0VL9yF9M=^YQ!Dna}2Q;Rnc)MhNgeWh&WwHpxr8Ke>tQb0YfWc8 zh5TsAJhYAe_70LG$pA=(lsUcdL2w#|x^!vC0Mx+B+}=N93y<5bKh4zpVdr8Ap2owfOHIpUfJn_J?2C?--l#LP!|JmQav zSO_1(bG$i?zg@N!Tf1j_@}{JD&#oTJI$+@Vi{R0yIW4Xjwp&!@lLfiXL46LIH&_PE zS&`?656%nhUI7~*6tDmngpdPE2x*oG0a&}l#DP1Nkow^Ome#?Xm#FVNYX_s?>u9V zWw2_=O6;}_Q!Slp>h@|zo1C`#Aea$+)mH>|22L?ey)K={O!b8^A@?6^?TT4J9%Nq+|L! zdvdwX+BnyB))Fbk4z@)CnGgNiRzjZ*)6!;>k>a}Yw6uA2R@2hH$TY_aBBaa^r;2I0 zUXQ~xp=rt9OKDmfyU3=c?;xD{wDdWxUS_0N5h>0Ic%A9KWlr8HqrssF6@_)c>A91A zQJ?{Xr+i%+SeJ7ryE6KQI*6Vtw7-Ts>kD%E*I@Ms)||H*qi8eh%kqr&nm z@ zr?CvS^_BPR)ax|Vuza0XDX-HQn=tcEu}%|EoS^}e)@fB=r%7QD%yfYJLR_jXl~kL< zawg8V{w~S-yW~fszq$w0reF6I{e_xs=E-<=!id|%zh7e$`9*b4Gvap52;$b|o!0pY zb>5Dj%JTHQAZ{D7d^$^UwjM|G4!73fncn-O+51fCHMBXQ#NxhT78s{Q1?$CVu$7>} zR!oBx50wTRn+BWB45&<3j+)jsCY+lM-5`}wxebtRV-MnDSblLbph7OcEKwe&VvG$^ z1Z^Ca0Re2y)=DhP-&v`Phu5;{0sjo{1$tw^Xqq``(RRKVuC z(AmH?pbO~?uMFE%0oy5bAZhOu+RYfJp(Eedi8zYItte-k zzDc8X8dW)cQTaT4GpDa&Tc=_3Fz1497?5r2Xg_2AZJoR(8`L0k%KXj7&V`Xp-#Igz zsF==szD@X}eslO;&4cWfwFH7~Sqc(QGYaavofN*8JiY4fyXc}A}J zbU!OSu8leKD4p*9?H+b%+wZE?Dwu~tChn1bN;c(NEagFQCY zvD)d&D0uW0xB}V+q@9RhC9Gf6qz%=ry)jyxV$qu5lY(s@Thb%g5XnfP%kRy~Xm$VW zSLriH+-)6ogG3C1%-}jQOJv#EQDc9UstAI?;|`VBMB`?frwmMy+c);3dt{~@38owM z2kXHIuQrMipH9WFYaUO?(wB!l>oi~XMnm~tTLG9OK_*HdJ5bM$oja9&%J1 z;Hw%WITY2k_Ca;6A)%3sC7tf4_R{ITSxT8*q%eqc$oIbAe2s2Ppb>WGsq#e0s1GaA zNQQAYxA%7H6>~GGz9IJp-BY`%-v|bP*m+>0gGoB-ePcmI5v}A8wlL1i2Y4PY;DUZP8e00BQZE;lhAYe9kAc8fq+qLrA8SS z{b49-!h1tzU-}S)V0y06X~^JCS*Q6D((v*)f*L9t7E*Ie(2Vb(0l?T@?N99JceB>z zG}ck;{IS-19lq?+X0I!X&i*A6$>=V~qP=UEj?f)(F$FtmC0)XRjqJK%Z5nltznSq$ z*#9~l%L=YS$^AII)EonvTkMWkFs}<(vYdo@w1=WH>)Xd~(!t7@yL!7{e~YF$g&E$= zg9a30Xxc^Z#Hh{cQ+jf`za&fVrop8l;iI#q`my{$N!KJEtxV}w`D+@z23*`0L5M&vnt23%-uyzjA+S>(S|dt1tO#a;hRv&QEbMPb40(H z{|wKPi|W+RhQ5;$^?C})D2@|SXlKciJjHq;S(>G`m)&O=oOF+k34jDMMtr>XR5XHW zl9wQyZ+mz-&GF6>i6oUFFDNE{b2~TCY_GgR)C+C%+q^+$k@t|U-@{A!FRwNC2$*9Z zOB(?K?}7kvD&1bu+-Tj{uQN#|n4}XpR!~vvXK=-m?K3URFjs2H_+3AD57QP8GaN5) zb?DynF(X3pGwPx>70+Lg1uZ}`KFcAm4b|(^7QZ)ak6tcdZ@ig_Xq=7AS86tBrh^cf zW;ev%I@_b|7#-zpZJkcKLs<-|n%bJR)KLp9dAaaQ;g{3Rjmux-xDVvN+ zJ9B$dEXwt=uowl>U|G5zI`p@}ij;Do$@tLroi9(hH|B=5^2PDB-3-^TS11xLtqDe^ zn(CM`Id^7rpdnwww^0Uel3VoqB%IHp|L_MNoQcxa>3#a`em>awXSv7Ax%WP!8DorJ z+gU?>s1(v+-_g7*Y+Qj7jSXCyZkBlpctE_%G7=JjV59=4J zifwQ5ye`&vMx|?Xp%*desWcOWVAeoNy0!b(~fQ$^tQTsxBqz322JaEcj z6`?gQd)oAYs(=BcVY7(?`3rb!;H8&(ULO?4FIK$#n0tcMgKzP@|oTZHU^;G|Et3f70 z=^lSH!{~>{gZxRXdDTM-Ekj_kx;=3Zxmkds<4ras9`Aaq3_vfIN8qzHXCS#kez&5cRGPX%Nu+4X^$=IeN0#tRspRvuuE8U+}YqEE( z35@gMmAxg7>mw^Op2X@MuAT8Dx4qYzUgR=j+v+36la^>7dr7v~pUXH|=QPGFDt)kt zgbu>QBKN$dB&;a^ohS)@n@_HctK@`#-cb?;S&molbf6?N)3QByXf|U%l0LRUhZ2%w z=xo@JOVTr7KANslV8qXzu$l{#9Ha7g$2V+)6ss!Wh`x^dEK5EZ%YAf?qG%duCIAYN> zr)oNUS|*}x5HmnA%5Zv+N$HajN7V(zkthJp{3OLuZc5Hbc!ZcBjxx469K_Ka z#vITV#F1e!pkxjck@OjsMv8Ys)tNMc+KuX=ev?L|&qNv>St&hrDn_z5Q*-B zbm9?xBtjpNJZdIOf*c-{M@^GQuE=*KkGh#WS~7=Tpx`C$Za7CC#lneXrmcEPO63zF zmcTqJ3z7;5Q0Oru6-K~8$Qd}eFR849`tVq$59i9ME1TLwagEiK(@Y(e!sTOYO6ZoV z>8GyGn&RnNtUU7AOB9-~>cU3(z`O~oRLips^}(T9SR5AvqOoB(G)z7=@;=I46L1WvVyACoA&K2R zC&r@2Se)GoNb4UtOq#$^+_vF`qdX_i^|7ck7J;tMow10Y&{&{=_*k%XoHG`PI+QT? zO$oPZA}cK98@xDoGhwS8NglzU%{K)$Uz$EUas zeQTzDN4EVxuRO&ipPGg9{nIHn*I%x1D`SNb7n;hKfBG#}Bdb4E*YYTf2V$G7P>JR6uDu}pxN36|s)K+4YR@>ZOouI0&yoOt09V~@PBheudMnX$1gWncGVI;gdhR4@y z^HI{+8QmRd@KbXMekB6@g2^a}W=il&l?w2WX7HQ7ljDD+fL{x0gWvSD0KZmMhJSb2 zoe%!eQSiUu^!!`zT_~p+M@ULwEgWvq|0{l9( zF!+6mH6Q%VGrBXt+NS0b{Hi;^U(evDnG*auJqh@i@sZVGfl_n$s|EbpMK$=vvngvc z*|$!iA7^$0@S7$P=^EmZ#u)|ow)PFeoEr(k&<8=di3a4$TIz$q3Vjf;R);~D_d(7% zVGIPW^})ameW+M{w&_Ycc5M0^4_Bn+QfI=hpKsn#!glQPI%Fvs>d>R=05p9*yqIo(HjV}*flC9* zj<;Lse!fnXhx7PgIJU{v#X7C$hwXW|A%*$Nal^LnyxxXI39xtS5)Oo& zMBv$PhMFN^K!B5ZzvXx?hk!$^dCK_CEqj-Wyeh;6r+q!n8y#l|hW3w|ng91Pd(|go z=KuC!rOTmY@0>OB9|UsI%%550CfSQ-{(h3ZXy)(MYJ~h;H1l6H^T*c1Pd(2ihY>py z4=!D2XD$W1J1d8gMKk|Mp{>e~=M zu!?(NS@rShdn_bFb$BaVs~av0J-jL*rqJg2Q23qIZ{vAXpnRez5jiA1QkU=LLu3(` z$HDD>LEE0*!Zt3ly7HwCo?V%m#$5TO2K|0iZY9m`M>R0~epFfgKC)^$J@F3@=ps|0 z;qa;uBdU@<#+wKKnKynf>TKKYOXb21<$pKNpQ+k?soeU(rxwA9d$cIB)GIuG*Mq8C zkX!JkeV1;DA6GZXJfYvmynuR}a_=L(uZEjaYxq(U5r}*ZPCfOjQfsBFQia@Yx_E`( ztpq}oDK=%he|?(-YnJg#n!UCkd0+uxPSO;X zxj)3A(+>Fte0jxmPhJGdlKqLi8SY%IF!H!Zwx@gYf6%)__356xC5{lHsdjU3S<3z8 z=_pr>0anD-r}F3c>s8ae6Zt)hy=p+E57l+{(I*()i*XAR=+gkl`BR=e$>cyrhAP7_7(B`K(weTJXCl2Xxc3nk^S!u7L;g=e zk@n&Js-Pxbc)WW|1@+?alJp9HvA3gsg9%KQ^L|e;AU(C=c%n@A{$2Lz2HNhe1=W=o zCGBKQ_x{_-?yU<&yWPL^7Sdy58OQjFm|tEM`2=Rl8!C0;j`yqFIs$R6+dlh|KYz}S z{sqYe$vQ5BH+a|f)|Gp9qK(OiZW!d=9uMl+NC@4fPZ~rvftzxb-NC#JB_mcBc)IL$BALVgj z=>&hKqG)pjdXfpF6AkR;(UBFsRRFx9dT2%O0{zae=v@eCG{+~w2u8g|2x!6{G(q(%Ca8=bQb}S>sJiw2$+VvE-%Hlw+YfK^ zj}cSib4(E<(C$C|rcu&Vyw0JRytcO*MoM>92e41c2bLrq>W`AuYrD6+n_3iVZC%n{ z3pdV)+*m};ti+c!t{?vI)~2YU`;cfmxHLPOj<)+3rO|be;YFaeVrcE&XT5AEyaD4M z=2Gw_(da^rkt3rDihOvV2@h(n2Ul%oKqquCT~GZ8=aV@&W4!UgTzFY zppUGog$7Igglb8Z$i;MTK_M0 z4J)^fDF7EL9?>PDUe)v{^l{zlI_t`mBoehgU@1M%iOa5ep}4;oYgkc&llv%J{?UrX z(PgMr4aQkM+=T43hPjoVH*M81s@g{dj2`CPNzEMWe&=0GX_L=07fr7>K1AOeC6?3v z@UyFR!aG)WUTm*170SapW)k-Y`zzXx#;*v*I^3)@KG9vWblLJ1D_2dfUbA-H1s7hF z^!gXCkD^O1y)2sA@Qi0}y!=^LRN4#?8_X5a7N#_RC+3Cr8-j8oHSDD{G}o`>Kp66J z`6!zjGYKG?Zq#|!K!vv=u2f+NyNOuy3Q_K|3ZFeE+5(Q_(&y6N` z+Wo{)8UPZ=S}Z~r-Ur1j2z}^mD86K_eA0AnCw|Q!R(VBB4Yf1{e~Gt&SToD(*R-&= zxD~Xa4@@bW$`(JK$Mll+7ZyYY3mN%Z$P0l=Z71Y~R2f1ZR!yLDUrKqwt;%GfIgm-3 zT-KxmxddJ(_vlcrR<1~$B9~NHu0hBm>rGzG2~R0}y8zf@A&da)q*bt+;VZ*Mcx^t# z#Cjl?X2|7>fn2^NckfWyJ(jy~D3?-{-9MB|n%sj!xd$wFb|{xpls#1Bk^)+T=m4D} zNz;}*>`CgeYs~F{N#T!B+0JlGAX)F6<#aBUtT1Qze$`hhVM-g5>))fu=aGg z)Y4M5w0fZYABUE5$PSgtFH`x+qCAj&_6~<^-l1W?ChD*|XnlnF0MG7U9_snYQvEAb zeq~Xf`o9+HU&$*FuwDo|QPLYtYdwZ)kg2g2n5(SDo)%feoXUWsv9H=CC&sOPSjwGe z(<)K~s;oSn`CtHUUSv(Gyl&gg{(*peaa7adC|eV98sf;=ALNcMMzD|&ar*ZrlP)mT z2MomN-&n?qBIC=JF;---UJE)S2OMaF(dSJ;ctUlt@R(B<;{FNM#j0SqE-4PHePl}{ z{8Wsy0(q52>a&5Y*LY*-@BY>=SJLitq;o?b^&g_hB63&>>IVbEU3-p0O*FF-)VBtf zv+f*+8lR#P)PME+&X_JZ$Dtk{UYps!S6kEgw{nPYQGX-_EU5c|}Yr<_zwK64j zZXxz(v@H@Me)hOvhg%f1S5jI5z{}XCVAfpd_(Csi`ZPjaZ28l`T1q;$?n;Q#i~I}Q z{Nd^=aVSkc+k+uuYnJAUlS;}38(Dgd(rb!zoL00Mr+~uDkBXw$l!o)Se%*&N$-%Ri zT2yDMrxqioO=O!|03lB9ntY_o53&l84Zjn3vo8`@t-T{;9L{za)=hWcRxBK*1g@6p zy3Rq2+cLCAkY%vC0BgRPP|AZ1`TjsDPyEWa2TGZ~zo12PDbqI+wBj#ivfIGty9YCU z7eI^bP?93-bto}u>u;*E)K*JryFl+=NipBR3Y&N)yf#jE-|l_aVoLGlA44qJdZ|!t zN^9;rvNbn2H`M`Tl=CiT*c1Y#Gyq3}=8$U|MaAd^DsLhCF7W}UR9HNU?#wOWGJnIc z2g-ITWyqzOI9cF5nThLoTUGOQlwj4Byn7HRjh zwCrc<)O{}5Vt3#b<_?-8Q#q`*Hnn|;u&$TnD+$Px+^E{*Rsr*|$8u9JghqN#c zLGz4e46im0=m}c78fKt<@{CnMo;+!dy~%czwXwS~-&R{+PG@(ot4sC`x67O{h-e20}@ zXJ~TD;=_DhTVg_Rg$zwO7}8j|rCBxedx#AlJ{AiI92O1{IINcV4!|=tkZw+Cgllr4 zKT;aTjA(^4r_m}zJK}_BD{{lEjh)HvnTt(coX}8e{mhJ@5=xhKN zR20^9fpo!WAZI!oNF3}FF5i5x4J9-O`F?hI!BF1*ykW;T5ki$5X#zw<_8UdkMhO4?CRG~~DU9%&*1k`5F--#>r?6_*vP5r8uFL42==N-m{sfw8 zrpya=q$pWq`-*<)SdL=N?$@;xO|P1>gT^hiVp+C5&(CuzSF(W$v32MhnL6L&XE{F@ zrA_fpZElX&>uGbG@WY_5^OTH_7+u*K@rMnz2hBQy!$}TfRTodb-K4>cwzDx-Gh-Rf z6xrDuG?S__0Ud|noc?5ZrVsh^zPM7&aDJ4lV*}D143O6So`jW;fq>}t?I4t=R$up1 z{)>>J7o8rrn#OaG!*#%H`3Wn!I>T^;G_?LIrT+2*E_8Ud6(k7r_1A)*tCZLrZ*s(J z^c3iG)G&RjtZ}>d7x-D9<7bjBx)Oc_UHbj+fB*Tf(SfQ!pAT1v{tQ{_NRFXT#FbhZ zL$Q~lH&eFX9JZ5<2VvA9$v?$QMo}fY_r0&cA3UntH{U&RE$~+j_#@eYBgbT}NIXW+``dNE!S}+N?y{W$=b_#1KkBw7 zaUAQA6qM!NZ_C(B%R$R?6A&?1y`3D3{9(QGShCh(@>|p0C8%X|kNEh#T9x9ItEGFn zcuxksCf4@tK!1HNm5cAyQj)w;X zWDBf{pOq-SvPkWxqjuXuJtei*7NqvSKP|OKr=fP!I+@ao)Sgj$?JTH0;bJ4#S2Ipt z*9={NlXnVE-U^&tD(^f_91Z0PLZ_XRaGjiJOa=a=T&Uv%XwgUNEe&fYVsaU45uT zdnzRY*P_IteUh2e_JnNqRr$aykviaeGNtcBkTSkz-@>MhbfRke(Ry6R-7c7{oJTVQQOQM(Qs4dqj&cYue|%v@AHC^d7F}Js(0s+)h=86PV4M(iCY^IYK*w4zm zKW$e@yGK}L*_L6vP1NF)!jL1=Y#SFxF%dx3H$Av+f}JMzkcczb6G^ibf}z(voFNyUK&AhbK$=(fchyn|(#JSdlA=db?zKgQ9W zIWo7R2C+=G#V8C)RBd}TQhMNS0OJ&({hKT=Bb9PqMpNayKzwx5_h)KWGXnzUuyCuf z_1R}J2zHXcV6G-PhV#I?r!miX23Qb190oj+N{mInZJ5p@{=0IiFr z%XxIDE|MyVQKc0B&+*kCVZJzGctO<}()y$27r@~! zU`*}u3xM_)$#lO{enAhjuJ*^We(DTin|M#Gi{Gx|rvae-@h#P@8e~y`jV;U0fYQs+LLC}w#OxXUbFK$VQUP&)Gk?MErQK{(nR z&vqZRnmEDEs*{}Gp2Y{+Gs-_g`^J5s()|M&)iI7NJ&rWfy3QTKtJK_)DV2YeKdi|= zFc%^8e_}8Fm9~o@Ib1E<63vhx%aT6(=c+$e#Y_eL>F{a^n|U*lwQL!-Q?CMZnXgWK zSq8D!l2_=}%_+*kpn99SFiU6K0gp-L-vN^!Uc_WhAWx1aKk_4j$;ZbkOS0KLGg8tW zFo>~3@}=6gtYAZf#$Um&%4BX&Tc386o7j^M&R5&h2v3vtG|JNwdy)+3+LQc=N9@V{ zAyo^39&og;D$v7Je6*?{57^%Hmbm1iM1QGmZ*s+|Tw|qm`6)j zlTlDK0)9HZ(L~pHw+VMK*5lsu-k7+0obHGQ z+_ye8gHOyn@BfUEwNgp<@7`?{r~AP>4jA>sEXujvmNcuqvBYfjruNwZaDrOt8rr-o|`cZ4ghwq9?Bnyr>{kWIe6UzLFmGR-s$|P7re@J6Q zUHd5aK6?(dVTJBd4kp<9`88Nk`_RiAia(`FbJL5{2d#D|jI8$blMcadL10w5B>jHn zH6AiQzC8M~nv#C3EHqSZHus9p@R+G8I&t2Bt|i6CjpE|8r!-nmmR_wis&Gi7nCWSW z#$Q%3G4nq|Hfo#fzsbY0&hb}KN>zHkbUA*Cz9)&Fo$}_A4y|WS*k_wza z2(Y|Ml~-M_k(sX!wMOWJNe{TPQ0(UL7uCBZ&g zz2KA8*{I?M5VDpOSu$8ssgaOnBW}!1Oi^csxyW4;Z%d%Ky|6a)KHlxG=Qs2?%#Y!Vh>}Q^@^{?v9cf0q?M+w^1y* zUkbgdwu1d2xs~p}n$@W~samG6MBMahIZk37s1E$~xBpbtO!62yaCgyx2fpyRTfcbg zk>7mW_GYw)p+XU5*Rl7jC#qbJGN2l$N@4V|<@BikW2OEo|dLDAs4;4J= z)8G2LKiPHbAKrKD=|!psiXI&J*uVb9H;?`CLpLvy>Ul`2A1(&^-~MplKYi}gzkbK> z?R;7(s~;(P@U35-{g*pG_wkcAEt2YaNUDEO4D{O{|I8o0_x|_Z_Qy{zQoXn6!3Vy6 zbl0zc^s)QXMN)kVNcH{a*bcy76uRo~z4xBq{oMEd@lz+CUJAfR3sU{YT}Sr(&;R|G zpE+ogZE;=oB-d5@&oNs4!(yc0dhAmle(cV--(qHGPn#Wpj};xb_tsB*`(wAQ}z`8-H{7E3@DIf5nuZHeB`B ziY<))^*euY$D6)==XV!v0G<*XfO{(h#4+ZYHLinqMVNVL3rVHHA?ke$4%Dd-t}A`#j6mq%VIf3`pYZflls*hi-ci8;4mh z3A`A5$ZSkNVnY+zb(may6`4QF7&j-H2lT7vVn{(PU4XCS}q zQ3XU;0b#lAuQ|$90H&Q7SmS`98V!ItwW#9_83n8MO2q#vaKdUbBPncz`;q$M4Js-LU98S@yjk){m-0qsSbVV3AKR6T?b;r_+zT-n zz=9n;FAr4uousp42Y<(Iyjfw(xT3GZ9iH_xehrufj9=`J(@A+pVCK(^B?XWw@G^Mq z82KH)gfBcAe0zYUGXP7R?wbQ&N6qaWfR93D`1TCKSJ4OifX@Li+dYfIm4Kd7$IbW6 z002ojf@bC*jjvv=VlRJZq~!={2}Fo0E}VsReJaHAgi5>X2_ah~8Yo*Q;>?vDEOHAe@sOhc5HlS@3)C2Lo}boD2q$6X=! z<*LU~HJPCbFLrR&O*%K;+^?+dbydlRYLf7*eryWWDRUEeo1p7FZhQS3M0eh`8K5#` zyy5lRXFl`MZ&zNCbncqIM>N^K@tz&w+F7Q`a^}NM8fYe?JCG-x9sN;m8thlBXa$rs zZ`7ZkUJE3A+}%N0sCF&I#(dDMtgdtefj8=pmF+bth$!L`HJfK3g(hCFCT_gv^=c&P zydK~iub{f7{mI*SJ%#nD+E8IgBN=-=V>tQ>@;mk?YXl0lMxYnCWIbs~0%|VdW2yKy zFgCmX%oxgCb5y+2C13&0+=SEFczV6@-}d`DP2JioljF+H>KpRVeemTFOTxKI@i&Q? z%itkStFP^IX`C^vq|$3Kdz(p1gO2k`^F}yA3xa@ujbQ3qCtjA=m2S(yXg{gm*dJZ1 z-(+;{>-!@&jKS|IYF4`#@5;m#Lu4^zjF8DDF7hYjT&mCy5q<>xwD9k-7vH%}FH~!M zPrnUKB<(l6o;JA|PP##RMw4FuDAB&r6e)bAdkp{vlP@)o_f}d%R~c0lgR00w5c2gX zJ+Qz9_VE}W)2Rxx?dN-h{%xQV^&1+Aq42 zRxeUHm{{p!jFN zQlr;WpZLkJj7Al(A*A-k!DxnV2q3AxQX-4tV!jxGykafhbWO%0sWO-d4-X(gybP)V z@1snY*7c&HF^Vcyfn0rw*V17;(#M5@^!e$1yZOxwmJP)ZSx!K)#;qa^+DD8>z{=o+ z+qC*4LNPS^3OW^Q)T)|EITVOJgQ6Os(1^JF4q%1?A{W{+;C!S9z=(rIx#Fi*d}`r@ zcbzSt%o}gOir)~AF})S^i>HteX8A2&XB#V!RQ*Luc;E{kb6r!%tjz4XsUpmwM{Ew& zGce@1tvOcfac6I@1yYbxukBkv4U4Wa01vtsUQVdc219?eATJ2L`iqKvA)xRe99M*b z$fpSdS(hF#o<>Q%`xa9zN15HKMlD+u8oG)uq|vRu7G7fGgMZO$)1RO2gwzN}i6xvtHK$_Om1EmZW5cPCh@de_up59QTr<8tGkw#3{=^(7s zXiWidGKa5LItv)W2XjcFPHpW~m%afB&>a&D1uZag6E>)kdn?Q%8*H@DIPzPsU`{!K zDC)y{7Zrcrs*IG>_IboZAsS*A4bTK$9+_xhY~|P3e2Iw$0wQLjL6I3tqTwZlXt>F) z3$|)bCmP;Thz9&7OQPZLjI4DNZ~Sw_4T@iV6O9JB5dWO(2cU@8jJ7qy9Rnvx3u zE4u6BEL)QlX9pl@3;YhmEa3zxLnEUi6@@~UT!2++9j#?2a)GHaC>N+#vdZgaSzYT_ zMS-kD*erp{LcOZ>WiA&aJkLZflmIXW$@Q(LkqWByOr*lynN-kfFFmzX@F*B!6jBdN zDzN6zJnlGxHPuI9jYtK4G91S_E)-*-CzXbc1dzfk7E-_#GdiS5U%$2odsdL0DnqG( zHR*(~2c^O~Wt&I^bUKPEFwDYIL8us%3JU5Hqypo`V-BU3jeV;W?yI2;?TXFQE-mt{ zMTe2&_7HHPP!60AQxI9mI>xyy6^z-rWT>*r5KAU*@oW1yK`W%U`9cr#VIc>|C>G>G ztKbDZ!K<2S9OMG5SZjRg0*p#N{kdQ{pZ+76d^lliTCJ^56{Bq~G|L2l!oiDkryiTgsj0 zr*v~0@@Av2!jD!|1FmZj(R$^(0~!om`*mg4HB?c#u9*khBq7n~3gxC8xEK@S`Tr`A zoA*}9zwOb&zb#as?m3~J)w_TAPN7IG@`qiH-Im|#{`zlwepY^$<=46ges{3^zx;#h z8SmcX^;k{m3CnDB-}yUMSQAk_rx!#Q(@!g1pShJWWK+C@9)tu^i2-62b-!h9c(|t_ zmgl;sp{W<{Y3>IoeIrL^;huKf>Nx}VG=*hxZ#9wBwj}bXTm!yolZA+4C~|sD9}|}G zQ+wn+{AOz3-nLO%E2A{lHWim?j_)HHFZPz^P}*`NEST!fjd=NlX>J_|22GQ+49#&n zw^GEsFh~l5BW$!|Rj)Y@!HG$s%s_C5-drX)UHQ#~2n5%i=gScd=7_%B{e?q; zR7H4Tx_ct?uT-os^4NfuQYKe zw&AR?o$JdD?Up81t8LG#_i|9I!k^|$WrQ_rM8P`yMTZrV5c#sPEDVV&YC@MFZ&}H)zrEgytT0;Zqux(GIwfbf-qo2)(Utp#&!F=TNWtb-&=H&)6 z$Q=ZGGJq|wTL+tnjB~-ZFm|L9z!KP}Ms?l6J`~8}380$53Ugr&gmK%# zFh2oQONSRJ50J;%qMFDMbHRqJMbD2*D4&*|B^qF=BFIU`PQTpzFrBV937O4!an|7( zpL5sdeB3p6{uSF`;9(oSGh!);S#$nnb7X+K8l4JY6T^0BWeGX|mbfbuU>ij&EP|wu z^F%yB3A$mC2eacN z;&NDYLQ4y(qDL0BM2($ckNA?_Xy@e=y?JSP`JYN%b?{B#3uuLb;`5)$yLYL&7jFYD zFn>wEG9Fi=S|0JtLaeZ$FZUfRs-r#lk-W?!f{C0J3iu)$p#m3nq0-sl!YgV2Q@v8s z1bQ+3F!JIL%Z@=Bw1pf3I;TMnH7t~;^De$ zG*}f4hW6{=Pk7YIpD?y|jtYs`zJ^7zwUg8=hd4$fQq7FaREASne^;AB!?sf|LS=oG zlW{!_WURqzYAeD<4r0|7uP2~X3*BgMpmDkrXk4*`jdXKF1kycYL@-$c>7EJ+!zdul z0epdgQ+D5pUR^D4>zyS$hD8JGDfk1($cVn47DUfb4-B@#sOSh!MM%2u~M8qk*XpfTWP>7v7x3(mN&#l@0 zaZebgAlB%{AWS7-F3Nx*5|#z>oeK;fM;oGw=v~?@oG1^Mq~$H?JXVrU&`4*2k{lm( zCI!kD0ll;{OHg3yQ;ZSeMA#Nu;v6k;juw3-lLWD*B&OcYTu7!pmM4r43-A5Zk5T+& zU~;A)Qu|?!QD{4ik&jP3!!%oT^N*0|ygWj6Mu;_rk-wsa8u?!y^=zoU7N1EmYn4HA zD~~fXDfRfm83Zq`N5fa_x=V$sm15sF7xc|Kz;_h%!gDi9qWE)XqWj*mOtA4Ev&nvqyi0L!1FcB zYHUxk_AIuyPoKziPH|JQYE-@YPM)WLuZ5JH%&2q`GE7M9Ipl z>ihbgJk4fjM8r<+#uMRdnZf?e@9tt0G7hX?N!o7T4%4dXQ4GAWjb@uk`=bN#aqT5F zr2qTxKgBqA<|)7=@lr|m_`7|usfv=Sv9(rLK6n#x_mAwB6|!HY0J4JZC zq>B*xW=Q1O^s|~i=Gk^7uV?4Y(PcicYkO&7L;Rn0t;tbUx~n3^*ZR&4B~%}3B|)X3 zE)rA~KIcm=Gk{D%T332h9PS!6BTBR66sX-@Z!tU~Qai79?6FnG(YVm^_{U~vu!Ll@ zFn-J)Ihh3*jG@%fsDvp8ja#a-vNjdUtv_DERVy(Z0Pp^aT49hoI=Gds1Sh?vPx#nR z-`0?Ogk#~VUD)o&`8->WZfwtT4q47@kpsG_TY;pK0F%KYT7$Nd?%q4RhYZq8#kweB zNpCll>g+W`Z(qlK;JBV(5oqQC?2=*zciZ-vTi&>9_nv*TGdpkXHREm7ZANg-?a@#3 zdDBeUzzko$4AO|wnb*sX+^kSJj-b;1DAhK~)%43LYT>NB^!hg0S@hU9YhWFdG-#As zvD5f(cVQiJlLc@bO4+Kt&((r3cl z!kS<-?&KLe=_=qh`+>BnUv*;mJ1_y_jzy4mn)sYxDgP?TRT|$M|7U);+T7rlwv*x) zfK$CZ+Ugg{IJ#uOteJ{BTb1Dqe?Jd(XB?61CCK@+JV!j?lX*(aBKq+yRoc{?)?b?X z+uIAekNcybsA#I1?v6E^AS@_kS4_vN8B0|Tt0rN}Dq@XBj&*y8kpflvu7400g-6U` zv#<%TfI0Za_W+An+5_=+ey8HuxL;e#BuIAOWi|{A-Td)PcG+&45c28rcAobUv$G*dQ^xwV&#&G*X$23j;CSGi(>eMWQ78wkk&dDyo1jhWp)RJn_N=e&EwH47W_lrL1g%fU%JoMks`rhuc104z~@W z&zJcNbFldv%{zZJdk^RKy`OHxvhNMv7JIl5zP{efxs2skG_$aas-)LQwAjrx#+4Kr z7s4uSAnRf!QB`S^)v_R|(pEGkXg0~GKsWM(Z@RlBEBjbSAX-f8_=#|WqG5$iAewb7 z#+Nz>$0+G759+k7Lk_j#v2z?!fseXIUAFdU6+pijjP|s){raL7i z2KMBsjeTyGh{kI*4xJEC6;5Rkb=rG@>-q&?d_yTXV``37)og8?iYjdVE0$Mh4K{e1e+Het#-w^gg zt!99H)*lxz)l+;?*1PfJ=SFG@$*upwT$-(x-G9m|yh*;kUtFK=m)KCwT-7~J55{b= zpHg#|$cAZA19Q_gck02qLDh8-t+C5EB~i@953Mw2pybRa;Z7ypVojv1B^Pe-hIk|5 z)O3U?fCR-Z#Hz@-&G7-*vhllLzi5sL+0Ez0cUv|YOcr_nZI16HM?`70cfV%VU^pRF zZBEWp|Bs@RA!iNgcTQnD^TqZBpD7_KZgwq4F zB43rtM>AiKI!frLmM?*~pb^@dRHGUCLn~nrAim!j7=WA`n4P0$wNx85P9M0AqOye@ zPE!FO5He}UtEF>}3e%>i;_FP6*081z+x?;95)AQA_9as21#1Lby6_7!hLBP)+V?1%PCvBlrwH)4)6)a`&zm*Z^bnU z`}d?-TDnw5^HluGVeXc*O*XsYbha8;6m}cg zJtG4Pm^^nt9eOWZWRRboz~DA^ZUE1Hs@w=SgJrrNTud1f_N*>i9q`3+OVUqt=3u-4rhz@RIxAsEh{WZ{IMazD!fI*01 zO~+=4w(Gjmc`N+M(`dsoZp_n6y$Y-#Ps2jAIhUtRRX}^l>N7n7)gepU+=f|s+Iky0 z@j%X?;#5eYq$9&i+ZZdK8a>}@&GU_q3#HzAo)3ge=ybt+nP_WqJSbHwmIhBf$StabiNq)1cl+Q*$%MM$Jok_nz7UTQ3TFrX%BA9q$fe?PE?5KyQ~>5u8HlVHI~j+vK=HRKajLOxiFImMv-*-lH{U+ zEP8xtl7uYC)#XN%tkg)a&GNxhvMx_BrWa(D=!-*O{s1aQ(%(`&sb5Sw9@Fod&9U7w zl%Q#%VWj_j->ek%ljtE1_U8C;p40t?J0=Rx$I*U_CvK0 zIlZm|*8Un+cKlqN=h4}<9{RvVl;bA}c>t&3a^Tb%0PgfIa}XGw zp6(93U_YzF4HjZqtD(UrK+7=Rw$8|LFU8brcnz>NtOg8{A+=nGeOAws92L^ z2w2O2IeIRD3jFCJM%tgww2PdzmisnlcSzIKv+5yt&)G2l+j-l=Wub?+{7FvW=h+x8 z4?Vo?yzSwN(8FIj-+Cxcah%!BDAT`ey5AFb zKTwk?Q%~~XQgMAtAP+9d6Uc-0ArZs*64r3EA>D`CyWe}WvGFh;T-kesRuK?IYu!IG zm5-c98^&Y`W_!7IV5-$fjHo9itt)ohlaAI!ODY&G*HF&GXnVuF7fre~og$jF&bZIF zjZRsn^WdSbjeG-E<& z#C2Zbh8D^~sD;i5R`?P8K?p5)HbBwGYTCV$;;HRX6SpVkZ1A^})jAGZ%|6bg6x9Bt zP6(0)jnc!Xb_fEdfeY0~baz^~d|l8>CU27aEU^8T9#HV}MT zrDgYou}Zp+p7r?kgP;B?wYn;_TG4*aykuoZF;)7`x`dY0G)s-DjSMQi>xzS2$Q1oK zw3Pt?;5iswfze$UjHIWb5Yl|VRPgB2>fBabtNPt=7|7TseYL`;v0uKf?_%Z^9qwzs zLrmSIXUl1Rnc>6B>8X4|>ksa_wXvYh5iEvI|7oCdpm-0RajG&GL&lK#MQx}37* zbUEWTzT=ZN->{tS-`bm^)+p(hmeXf=5~v=FWrQw*-P5h8uM!$;gKR3cTk!@?0fC1- z@S8wWPIAItMT)8>L{4tXG}-_O8C49C*sQJH=Z=?=7>Lx6{xE2(7hJ>7lD5Dvt6%;e zEiE0n*OMHM^&}^J5okFlN;!Ki=O`NntiM7r37}VPsqU#8*Y>K}FvwOq@O!wnt$`ZT zVc+#YllXFB$93k6PcJrURmnz8zD%quoD5=a;Piql#Na%q7n?wm_R=?<_VgkW$65IF zf6s)PARS%eR&fHm-stBih;8x5oJceA;X8-c}rKBy6YK3AC9O zb1JeiE6k;V#TR>Tm7u2V&)Xf#^oZxzDnN$Vg0tbuTr#E5I>i;x?5gHq>$*lAG&s=U z2D=wIk6uF_l6I@ZE$~TgO0*>i?%uc`5WL~ULq|~UWIwV)b9VJ@T45cpL-U9aXhPCF zbPr6;Bf1QJwgc6EFRE^%dhwy~O^}guyJZJmij_y{twm{L3v){&3SkHqWsVUBBSIm2 zSB5sQqJxy7BL|62r(aP;pyczW?_zsSGV}Favj9zS{o+YUym(TQ>bNSf{26TwEuNGh z0Txe6bW88k@}%TswMv9rqN62I_v5y%m8|Mlx*rPSO-{JTpG>sgUNMz@e)}!6Z=tZ< z4s9_LrLHjcCHt*zMA7=7ek-R`C@D!jtPi9+6F5oXXruHJ z`AkTAo2SoaET~TF=q~gUrA14G!_j=Ug28EJ*O3Ro^S2z&clH{qcaFTF!8uufXY&o| z*H3)%%>b8v`_L_SR(sX-BVXD5*=DbnKK7YgzTCjXbQCj3+U)e3oLuoh@G#D+cp!FA zucHUTD{?B;`yYB&@%Gug-OO7e+4;9y zdRz7O$9q@v_Bp)0CZOZF0bS1v=z4xY*S7FJ4e9OS{R=|*7l!xOhW9TD?_V6=UkAMr zBo4a?>rb4F<7;)#u4JPnpLNf!+Z?jA`(OJTlM956>Hf3q<;8a?^Cigz6RLJR#rKs$#_Zf6Xm+A2F_h+Qxy|yFoT-t z5V%GF!X?(yWksa`SWnhE)c%r+$-FFC3)I*1Ny|PN)hAX?K(+)mRXR>at;AXbe>9O3 z2A|c7mi#lI{mJAK&XBUwWYm-EPtgcHAZ7-QksRBEt<6yFNapz2>vlRb8p)BYx=Sd&#G&Uf%Q6jm z2ovZ#$qSMt!mzsf!epuFa947rC9e{=KV?=mKzC(wp;O3J_VTBULSB$u2!*_mPnKBj zQhj3OL?KIrV6XZ@BaEfOQPIE)iqc^G%H*o)zE@6ZGG36pa8BJc3tpEb&rK$#`%A6O z?Fk2T&jo}lEV-$u6sWIA);ZLh>?IYGxjk72)L<-`u-vXbv2ucXLRg?muf1y})*1NS zGA2NhaNR8i(P_c(AI9+oR@D^+ zBEaraO+p_FY9QmP3=xh?Ya_?DRqxd}l5HM|q8$GQy_W{utCA}mddiZ#f|`MTUE(#5 z3J#+Xgxrgh6&dkem#lQM+iKumtztK1blpu7rx0)N1_OC(l0YF8Ojg(@EA@$$6NRiO zP?8v7tjy@z;n-S~2FR}H$t$Nc881$*p6*koTsO^v*A>aN$+GGGN^A2)$#Mtb*_PZ~ zR0>X?om}KlZ?>0IOy;%8ML_)`YF=i!%k_zs6V%Iu1*-Jgms^R84E*H+NS*bTt}Q+T z+Gi)5r~B7srODWwyvXT#P9yYSnX01Q#No1;<#+?WK}?XbIoVpq^0K0f8NAnK-7~ZU zy?W!$lo z4%9%#%0ap|-j`$B=-R7sBpY2{2lS44qbM&8^jAZyB@{o~>H4BFT^ogXS(mLP@0TulINYG5qhvn zRncy8ja6lI?U(?*K}?V_HHe8-MHe%8Q>(_Yyjlp^M%_-=pe7p=gDTLq<5)FA*ZqKr z)hhcRjjmULq#?R?S}4=C)1DEEBLZNT3lYu~sDX@0A%dC%JVw_!wvDczUqZ6cwZ_Kl zE{%;L8E~aqIEtSG?E-zTOxH#sEIM9lgo{cto@DwH3z?T?xl5Bw`ml)k=`43;lFeO~ zGXF8lU6W)zXF-$4%eG~Rua?&LUXnztC~7;lR1;RVmm~_B^>~HH%MwLhIjP5u$uoI; zOpnh>F6Z%t9$QJ1$4B%ynvC#xM30@M&Evy*98bo0JgmpMuPaDCq-4#P7bFiUS@l&0 z$p@5-eX&7uR>><2ru+1`$zVFD$19T`qrkm-yejz*JRZ>Fgu(O2@Wz=P>P7@&!3eyOexk4%3X1&o-EL@U+=LdL2(&lP!SpTAr>>ew?SD z=V_V2^MCQQ+`xGyPb&^ftvxwUqA5}(6DkPTZdLES$ygA$H!A26-khn&PDH2;r zOu^|l$5-*R0kdPBW2kP}okzzU6~DI7m@KK6+qOw7tS>jmk9vcymT!*V<4MsG8FE_wq)3FVz30$k0wOkt91Rkr z6_BV1_wyZN&bj8=d;gxD7m(`Yx7V6$t@#*Z%rV9sW6UuzYv~Y;;DOST++Mo8-s9O2 z@PY*(>FX@5%oy|8#T^2n+43jkSnUdfwA#&j=+-t2Lzh_f>((6nWO?OS)>JuWG*xaS z1l`dCT97ODL&a2v7tibkUN_6n=lNZVPGL9&fSwS|QbpNL!QLVAD&aj=RsT25Y3}y` zvA|}#2YLa%rDwwmEq5$E${q*>Qh~xfQ`+pDF+kV6ap_Yd7GWK9bVjlDpGd8Xqtkkp zzV0xu)`wyU@itS}E&Xtp1A~|zvH^BUWnC)$3V_y`UxX>?fvm3~Hz$*5%sY&}eA0oX zBk5a8cT&M8%A#nFD>~D;d_3nqI-Hx3&-ut>0=J9duULpPHq}ab<+N>%=1#u*6RVxQ zIFVO7X06tPgEBLd;<&vr+c06+D1t#2v;<~Ue?NydJ^O~EoujKa{NoQE?SvC#tYNUN zZ5@N>u!rpI7hmwZ|7yo$VE^S~{)4Qa1J~?vjtl9g2mFkC!*^Tw+1!O4x>}R#UK!Kj zR2BIYWDBm$qc1KfG|qW;Osayj+5O`cN$*kOc28gr1s)}!0v$2&WPVBo)|M4lUHkR| z>N;Pc0wjgL?Ja-=6fKhK$i2S1hwr?GGIRWD|KrG$K3cc|Jz}GFN9nuxhU{3G+`UjmDcFTxyAo~X=t`o zVEynW#UT{T)C)Umw||1d9qsgaqUsJcZb)hnx*YWZh$e(>lizYTBF@|>l#sPeR)>v+AoTv6CPuiWuR9|2Ot2y z_niIqN^j~Fx(Bk64uYcXJe`Dgcqocs7fL|*-*y{>uQ83gUT&m2JaL5s7`DA%IaKRU zU-<{Co%#psJKn@^%z@3jn(Jcj=Zm^pTi^8zG}d>0>BD?!=X*>%hnDT7xDSzPn&j9# zV#eP6t7>)_Q;hgVMTUy|rVN|I_)1wvv{wvfU#}&KKD|kno|p@M_3Jm&#`k^)=7N9i zKWSw9hNmZTyZ@S%4~Cx!K9WSKPMhsiedO;9aw_z;l)dj#Rw(_zR!-^X4XxQSY--$V*OXIyhYoCl+Pv40>8*^PzA%ex~UUF#4Gh)S6=6JQj?Rhp3_*=*VWg0 zUlA#=lL0G1enL*f#k}VOovz0-b-=rg@~3WF7H;dkdb`Jad-LYK1vJRdphf3>Mpc-V z1)e^08ix9O{Hnaq`@PRi7Wh`T_lIs{+zH)ASWI`DeMSQEdp7U3_1XHqWl;CM+o!J1 zyS*(?lVEV&KEGx2KJNh3=xze_t*^}cyj@UR7WhdDInP0TV)JhA0Mzr|?X_3u-QE_c zNeMg+YPP?KJpTO^o6f-f2lLWxJqeQ8-N@yPc{(vU#_6K-IefRlg>ukZpl_X;z=ZOuTXP zKJS34Im%I>UTyVxyP#g4)$Jh7-?n+TcK~Xlw$$yrcg{d|&Fb?mCy%Q)?K64~ZWz=g z^d58rQ*LIQGO{SO4CBgU3)$T@b(=GsI5K4V45#m)Q%1IXD#^LLKl4PBulKw26N&cO zbtWCTbyAyl>D9xjVoWgIsz5!)C|d-h7?#=Ewk)+Ou;V#Md-tj!;7jd5zW}Sjm9Mdq z6)tZ>{XWR=hhA+(6_;xiaU^>EE&pymmz3<|=j@knmbyOVa^yyo&-y!Bm|n7wmzm??i)^J>2SoVURG;^?nn&8#ja9haS=gU2kMhI5>G zqQl0n(0qYiKZ~C?TxC7`1ukFAhjax`($TBl|KZQR=H18t6>FA4j za)$NM3ZLV~IGEKaCmVL#{d|ukWRBPGbbvC?V~vA$jh(6!yC`$B>`&y0fgsZfpJ25c zkNbnpnxoY6^8HzPk-eWypR4v3yEs5Pm?hVm-L&m9ZBPPgdcNy4Nx{Mu`Qrdb0aGcsskjO*&QH~gS5r^~Zlg+J@* z-JW}v_+<9Wa!M?(Y6VHVb{Yts#Wn?pm18E9AC<_1YUbU9S=1wKf}^e6eEBde zfm8IzESaNHS$Y{Rozu51+aOjQ*fq#fsw7LJZ61<2w;HqmuJkMSb$Nfyg|NI^=1B9Y z%;}idA7w}EE+#B9rnSQnjVwb!&1t7((xWraGe1OvePIjn-eWpSAtjq?4%`8w$bh@t z0xnb1wweRcevUYA7N1nlQvfFT!!Vef9M0*7Y}vU9m=+BCb!X)6okct%I$j7<>4Gxv z$z?E43jX-fVmM4EJX}-)eU7*1onN$pX)&R=fDWh4b^4=Sb$3J(*@)G*Sr%U>4tR!< z4E;yMidwDDwuVoA-c8jDfnNQjhw*~ zG~=|97wZ)f8YBl3(bc|V)v{mV35Hdv3}*-IP*+%u7yXI@eqfC%gCLdJYgyfECbpwCs>*OARa?+!_k;AMujKqr(N z)|_MD9n%}`nZk4BrFeB0Db2DNiMtSxq~n6qR#wvO$tP7R0!F|$a+()8nO{9}){b!n zZOsd8VHt@z$rg;h=G*k8ZVAn5#ptVb$`j{5E#jF&%tHsbv*gvb8}0fyi|<_Y1}O%5 zV@qnFx5J6vII=F#8=GGPy+K=|D89uh;2B{%^*GXTt@A3DnYliwW-3*^uXgl2&UhC!WEBwTW?q<;1SMNq2Kj6_Fwd6ee)}CU|hKfmk>YH>Dg{&Z#5XdM3j(H^+XK=Y-o4ocT;Bu|x zE9+_{Z(dg`u{0`@p$x%zV)9_R@-eq<<%5-mR2wG2V?xyA_k#PNN}1`FmgDtgop}8FNeJl)brit zX-;ZdSgfJh<^m3bq(-+`)b}Q_gKmKuE8RjLp<9HH7J_aO9xh0?5OK@}-9m!dbqgN# zN6Scfre#FiZ)LiLl86N8R5JdRMB13YDa;ap@@Ent?vnn#U3dZ!wnS+^o-qY zbpo|zU3Nc6{ofP%zvmD`6I)n-lK+fWjOhz|eIx9khYnm1by|s44}iASNZH>Vj=&A=rqT0xfwq@HCNGIlvy!1=@VabphiefNcdCtPt2abb&F`$YF{` zXo}KOTMI~tS%i5`h&ic2)Yc1JX%asJrx#E(2nxV?0GP%f0xkgQU_t>nFDU>>e(+U2 zBq;z)j&%^I2&=#fKzU#f4PNd=1t392s?r2x+6utmKeW&m-e8#+rYyIO6!GxY=O5cG z@m=;bD_dc;7%o`cc{nQz_&icGEb7=A>8tP%plRxYqWgN1a{zqV!hNBCrK&~Fc88z8 z3Y!8gVI7cJp#Lm{zMRXpxmiJ}EVD-Qw8~m% zpE`j%!k`|@Sg!5uq7qj4h6Y1$Iuf<1*D%F$AX0$rWZY@W_^e|F7^6}OBNS+6oo6?g zHS3IcZC=^rp1Zv2DeVGmxr*b^0}grc_Q+{V2zSg>mD&rZ++K(RRnmQ*sFRFBT~uAo zM6D#S@~%tcaN&5UTp0~ANHFbL+N)t&>G^S2D zh91)$w{U)L6ZBxm-$!gQf_>8a3n9lH-bKt8s`|syD1`gzk@!2J_ zM^Hf?kkd`t$6@2JjnV<~wsI(`880#+A*IDh!PE8_RYz)=s&Il3S+>9(15JgB0x<`A znmXNdnx1yP&B!H2AVRYzOVb@53t{4)e@HoprK=zJ1}I-*;m=H=FiS}Z(vih*`3-Dc zb{b2gA5UMktz9UjPr{&~rTb4G8?zYHbsr~}LmF$GrGaG0lPzIYhEAGgWc2q~m1T(= z+4p42*CRH9U|m;3A7as-TH@@uaDa@qNzjVvxAvio>nfwEU?)WADdcylW*G5$UfIGO(TqFG>D_X$gA#-76I|6Sg6KDLbrP_~EtmCncv z-evuN7-4xg4mswHJgldz2Uj`|w?%PTzaJ`LRqC$-^+=EolCchR$-3=yLaLY+QK}Rt z%$|fzqZKF1%c|uzt;o^JD6VQ~2;{U9De?ZKm0bz>5J_Wzfjai2 zC!7o!m;85d8B9O&Ov@i=C~!=|3Z{s~c6POaPSGSAplCK15bz)dw-T;HDRaXA29)Am zoZkwStT``f(TK_>`>V3q9XTrIqm(c-czP)E`#gLG&ZrsOE zm5Pi>QRE+rY}FLXQkSNj3&GCRu5lp;X8PK=kOMQ785eS3rZVxzhM$RXMxdov#8|yB z<7i^PUYN18*|Zxi&_OJkpV1gU1~#K-`4ddEP0_Ots!h;7s5TGrLCxYIs9_>$r;v3> znpmg}N&11p{D9YNI{yx5erA3)Kc|t+Kn_j2VxwfZGAE~%nUmA5Sm1=G=H#?8b8^}h zD!D(Ej<=f9>;BP0y8RSjXogF-T6WTkpLmIATi|NDc1x3x#S!_dY=N|qLaS-cTHXvY z(uQ}uN;CaDEQnaDX>U7SFkPR7!|;`4`z(^}(=3YyE?C5f5!;J=oNSsJ+@iR(wnxS&mvTbseRZOq402s_0 z6kBzMm{~PN#MsoziIc#|2Ijb}m zTVj=4t;Qp0VZP(gGxyZ7Vi|tnP3X_5Ld&J&Ol@ntcZN~#!8x(DIq_X6_l zS43mo>9(9 zMbC9ECy$cmqZ2u+Wvu~q3TL%sSJf{43}6YguW0J=f*j1V0_O>nk{=HiFdW|bDrP4v zf*N%!?CFp%#22wR)PpNgrav!(7b|dyaSxQHMW-Dz?r{byc8;`Q#Tty*>Bn>ld))!l zushuMP@~80<76zCY7yy~$uK}Ft&Q-!Ti`n%W0RohvH8`&$YEaOFmv||%NF(}R|9u< z@~wr2S$v8Ggoi6a!$Oc4Xb+*`goZ6T{6SO`biOWj3W%Vii1j@dv2KZ|6#+;a(LDB``vH3%?o8T)BOV-g7(33P z^040!ITgT$c_$Dxky9ZWk02Wd8KdiZl!qiJMwu>un3QgM!EV!S(w14^PnYPQ^!yS% zH}{_AO37S-D7t<^Kt5LpvTZ>c6Wk6VEv9pya~B|UAH$Y#2iXBCHeYL{c{(oONdQJP zaoTa!3W&}gFfr3h`3J+Bv~vvJpS`E_=?}%jmh~3Q@|CgU}q> zPD(16m^hK;W~2}16JQ4;hGO&Q^2)yChc^RF6Xv4N6*OaYAQ?W0eWjEi{19kzg*=YHu6!8xabka#hp&q<{}(AXNj*fn z(OVu{VUi5qTiZS{ee2`m1@>>>^b%1*tn4u4NDY?^zw}m$H6=c#k%YK*o>b!{s>Zpm za6_p~mT*U$os-oMqO^77!SP4vXXGTS8MffiCqE8OmID?*LQMt`bjtR2Lh&_h@ZnhqLb^=*LuAY+RMT=+w>=|L){tP ze9FP%@xD#0FdizjcVMoQACq%xM#wVcscC6b2M&PG)R3Ho!XLI1 zfT+w#4hULwAU_Bjn`k0C8=;}?J|Vk#QQJIZ$E4gL*){5DAix=9*WU`+y?-OJD~{BL z$ku9!J;jO#k&KYt2R`X0WKzSrqH3W?WmNm7DJY7KN%0i5QFGqV##N6&3|nrdSlr z0Uqf<8p?|)92$$-3aubf6$$>ku8sX#52s8BFt1X6MxU$nQp}Os#{~+6;*UV>rDD(~ z->Q;xzS!}_5+^BlhWi$wv5qmtoGwZ!VL)&xXR}=;1yBkAX+tTjJY@4c`1Da(;$!5= z7hWN5*<-0z&!*E{ZX zu@}ikIU(8XMbFJ00`m{rac;uZ)XS!(MGcDyo9N-2<$Cmx(ZUL}@XSeCP#aT-r=9KM zedXz+BH;bAzwUUqRM!Rjc$6g+CpXaTIl@uJbeHg+3pwVTqhmXGH{zQ{lv9-pm!pQ1q?*8CpIuxAY?;OVt@?1 zrq_}Zov*n-CF8~aPRZg^4~&<1rc91jm5NdBpL(ELIzY_&c;UcUa)g>N;vE=wFQ;+} z*lDmN?=!rYyy|uljw+CgMgu{Bbcg@?PLY&gqrE*a2y1?z6_4^TbT8+A`1ben(!(g| zUtA9OnUh%y+pXE2hIF0Ew2m5EK7)?igiV=XAa1`J$Q~#+{#ZNL+@i%gLrGLzRL7GT zy7bN1yLZ!8%-!K#v77s(*3(_~-C-H$@XpW+VSrx5%1wmEwuKu{wLsTwu=}jpeRfo2 zZ}_1g`pfQIhT_0Sg~;MaV)kZ*?2~JTeV^cOF5r(WML?_M9>W6s_etZy0g$S_fuMzJ z(4uz|TA&k0OP{JuN+q<&9&|R2H=#v|Pv?>NRKmBH(@sPSElUAnVPKF|ZUUfY_^{AM z20gFTAX+LV=+7%Lh~XpR%+`IheUIWJR&MxckOMwq*QW5%kN9|HX^DS(Eu3g_A&$0( zla;4yZa(E4aq{cePfiu;1t$=8z{yIE6U~u`6OOl$PB(!Qn>8(*$mF3p62bO>!^vg_ z%9!5!s&6|3<>{B+vLyrM`~Lan)lR)@cvCP$f-=*AueI_$!%w|lRATfl(_ej+l@EuX z^KyUrMOJv;aMg2xe>WQ_KfS!Q^xjhxwNZNS8Hww{8UULgR?7PGqED^0;3d8eQ#`Jp zeq>fK7IK!DO}v#AnW1g?mESVlO20N8x~H6DT5OSNXG-12DA<)#j!ec^=A@-;ZwRnp z`(7vAbb++z%M)+DEf6K_W4(0Vi&`d0JTMkzr6jYJ50X|qoj3Q2x5m0c#8iEoOc;_F z8ggTC?jbeIx=8=v&sM94R51E=(|MEbs>D&OQHH)EECmx{2(>Knco1nCF47EKX+K!# zHa2c`d(pbB-mAA3?BA=`Ht(&i`K{N2MAm0ws%OEMJ}YexeLnLRhp+c}zxTOG=iTbI z8L;WTXvU#U?9_C(NxLB+zi0Dq17zbIX0OP*y-wzIx{cnaZeRD-yxZFXHL)$zeGY{2 z&dvM015l&F8mLd^ecmppiKCtFHiRNjzh(1o?*P;oGS%&qEehEds4boMI#m7IP5UgF zfUnBt67;5DB7l#f0p?uFr@Hx@5|{dtIh!!p45}GUtMAYhu```tHy6!mD~FRY&p5^K zrB}eqwTz4W$}Al~d08eDF~Y#8ulbm<%UO&BnF8qRgHDHcM4YB%qzAzt@}r`~pe77I zcMZ+XkQP*>BOD&?RUQA0z@j&*>Mv9ks|Ohi;pEVVm^!+L`EvsDiR6}1Q5s3+LR@_T z^>eVy$JFI`unfIwoQc`>-}bs?G>K-;n+Q1qaiG<0X9Jzc{V9QjhD>_9qbFP<#b5pa$%L>L?#C9pLFbxZ)%EB~Kgm?(kNG)45vu(#KEi_z} zZ?R>IO5AzNtnNFO*hB$1;mY$#Y@-j_&QR^V4_dm1WQMtq@V7IY`wRlxVpg|_ov!VD zty+0OU*_Tk<1^^%z0qZI&(oLfJOXOim4Di(%D2?oY>fov%i%y!ahsZeO~?;Mgf>An zn^9Zo^%&TOO$7?tX;bS`(1wi$lG$ma>yXSF7qHa?H_fa(K!LG$F6=a6mMI&MW*q2% zB<%3Uao?3x*^L$&U)1}MOf2P49Jr}6<=GZu2( zyS(anQWE&_L~@m+3@a}Q(GPBGv)-BXhXx>;EK|=mJ8!%&bzY~tVO5w~tssAJ+qSm- zXd_G$V5U8cL|9}eXKE`LHZHM1=c~}4Hu@OQ(l(!d9a9`>NIV-gfE@#B|CCy=hLq_B znU)Mhn!3>-l7S_#s^1O3wt64v(S`~c4Y2T2>^nm(Fj>s%7WmUhfKsufY5QK#V2#Ht=%OV%zA|L@FEQM zC;T)*yHX5oU3fVe4B=CmWSL_ppGlT5XM#w<;*LZNyM$v}V($AoR~F?7 zS--Sa;Qq9|iD~m!A{Nt(vIV~LPL<~Qk!)6l&18&|!81{P#4Jc#h1m=>`VWPd6~2$c?5MP^qEh zF6uUkd|;CU5o1W_lzr=&oHh5dTef5|y+Mnax<9=0b&{=8rTK#)!Pf2d!tg{2-Nan_JNEMY z@NExdny3^6-veRgbju zt5&{i_yO(oGIBD)s_*`a-rqC4EtJRi|K7^?4$p+J;z0WKr>uPU@INN3`F|41|7PO- z-w);QmEpd=&MdhtHl}sF7=jsIl^CS{#(OY)@oLzDu~?W$*scN04lJ8ACfONDz4~41 zlz6@wbYFuv^Rz`M=N4V)MJpi9JDBDS<8B3)(A=zl(}p-4e$YXl*`csMi9KY&)6Q08 zgqp!tk{t>?ayocA*`dUqP$6JXigHyw+*Q@g;A!>Sgd1vRuyaU$O+-#(&OAct)+49E zV`KT4X-WFG1CwFYO>me)^>+D>2+g0GjT`wXqQuXCcg*K?s0;|vp)&WM?;_Z-5D%-L zbc3&h2Xr(Z01t5!A#V97(nVQg7V9s*4k(KPv^TBsU7YJtq_=)5H%@Qs%r)~}EV>gVMcDj zcR{zqQKTnY-QE_c&37@`=Rg=YZ{Ft}fI1vSdi>Mp0&4SJOm^FR7mM}pZQku2fI1vS zdi7uD-QE_cXC6grN$nTw8#eFr4nQ4_B0YUOeI75dA0f)gMN>)5M1%BVa%GHU`iR|` zhmnSJUthm@$9Dkia2V-{zu7UcXC6ixfc^5#`@92SLygklZ*LLEc3H^G!$`w)eBtKZ z-T|n?VWc1U#EwBd^Dxpd7ym6fUDlT^I{8k-?muD%)>|nRex^tKJNh3;V{yx#X@$>KxQ6B8YtxU&AYt=P=~`vuim*1GV?If zKpua(d7pOxY7V9#3BXR7^zK>8hsAp=)_<^he|G@mz0UCN+&MY#nbl_toLH=Xchf#= z6@?&+%P0NL^5(-m@j6Q#oA&0Px8W*E%0KHSlz*+FR0(&(xQb%qVQUL&+#vs+4_VnLpyl}M!y;!R@Bi!H zCJRJ0Wk(GQutzIOq*uTF4OZ2DE^ncBg}&Y4wTI9*&RA^DY3Y>=U4uNb z1%8ZWc;8Fah5fU-pnbVN;_cn-U6|e8L2vJ4{tlL$c*g0B=Dv3B@eX%OEtwhbP-PZ? z?2ObC3*Cj3qpw+|*K5<3pDi5(e8p|oT=^r|w`U*@12~%w>-W7eAiu01HJ)hr`UbLS}>svbYSLXm@pVB$Nukd%2F5*vki7c5@O@?!T7ub3^ zG8bE=a>bh5RA(4Y>RAdV(fUNZF}t6eQ;kiZx5^QO01j}CKrn#L~R z_s_2h{a&a)O3^`zUgSj;mnu4+-`{(yy|tgqKc#3NzyIh1*11rWNViP=UZ_7pk&ZRJ z)?dEmj ze1@8jbEECzSEw*Di{@PB8jH*>no?8eXB~63kCq&bdlnzLIep1(`;7;(DhxU(&q) znO%jlO@-Kp)6=Ij?<`!V;cdF|;F$$HkY%qwH@`5jokSiSl{*{z!PzMPsO-xzaHYh3 zs3O+uF?J;u;bn{AD=Kow8p$V$dX?NkT|XsJ2Q;r1<1(I+XeowyzUcwYFkz`#=Ap(6 zs;IC3(mtTsG9s@uxzX{37MQ)+A0oG-#dBGtSh!bE83$^1dBWZs;hQU2mX#vA;{jDm zKnIxNn^o|b!>7q;-{j8M0I+!~$GkgZ4JInZvq`>re&ljYrFcLWX8~)KgJV;!atkKY z9#A+xne@d0m^(F@RMpp*u2<=gt#(pISg!J2be<&5F$=W~9VlChFH7@mDZV=3*Ryxl3zi>^Pc`nB*=-WlXMaB<4*cO z2&1Kle9$9LGilh&D<5Zyp$AG0=pp9N(IecbdkV5@9nX4y6C??f9)JXiRkO1^e;?sQ z=d{uo*s&=(cONyYv+0*74&qhjs%=CH-cwYGu}xuX5ds9Qv~pxQV8k9yrz3t}zsJ(W zlx(?OU&8G$;#hN{`RDP+Z4u|(CRXq4Tq~JYEHG@|ctezVfyFx8cA3}8_fHWrFEUz~ zyYb%;{e$qglev_Wfz7oj^kQWL9TOG>;_tr@btwqMUj3N=+Hf|BAjvm>byL|0XI-Fv z3&<>I$;M39!C`VKs36oLmy&HM+BGIkY?HW~3Ch42O;85$Xe^rOAVS4Ag=~yHhe#+nrmul>=OiTv0w^!(b_hO}1jFV3FY=HWhC# zQEhw~1cbw24uxbxCN`U+U^1~emxLn_oliG_vk|BhV)JY9@acgBV=gv77(7zPSnuW!Ba8jr^g~j@yHVIvoaPa_5R0#rV)7T{c^07%u=3|pAof=!% z7|>*O*JuRVP690>&-X<%ncT-LnSvCw?E%bOZ+>XAzZ&+57%n0_3>O(Z z3>O(Z3>O(ZCQjRcnuX&zJ4fD9JlV<0efr)|8*~y*Z{>*e4K|ge99&}enZ0BAd2Hr-P*V-rE_%6&hp*%3HBj;#@)sndxF}`%Q#-KTw13&D@EslGgFS8AlPRS`2*~j8$4om1tTlI&Br& zw)D2F*$))V<~wyhW*c@`fp==5(~?A`jXRaCbvqa&AyXLw8;gQp zx#@h)Oy_gPR>C5|?ZUI|fAh)yhjADYX^Hw-r%c-a?EGT0QP11jQwx_a{gj1?e#Q=) z3f5|Nyx25sJj#~y5_d8^X4Yr|z%fQ+g$%OWjL{Tgi`EgF*$Ufs#FPY)re$>ot@SO@ zY4uJ@ZnK0e&~28~arF-6b!5{BLuE z7(`?(wi5tnKtwCh92n>@EjY~fT^I=fhGhNMfwrl34Ds1VVh(cCaBdyv~$m#CsZ5Rov|cneLe0g^2@iSH(M+5sdq9(R%&=A^f^(8TUcM*S&-!VI{N+c&+pwu;kgdu#)0bjoHxxCb#) zP7X+=N@6Knibi6~L(BV)$2RGdR?8+jr61T<(6#2^!M<%iJ>=3{|O{1 zxt7df2NXZCg1g@--aOYk=L)uzYIB8r88D03v^3Drf>$ocz!wIep+{M3Rh3^X0|@ps>xVq`!9g zlV&mcP#2{r-J=Y3QGC<=59$7g!advlOEb1OWJ1!BUN|jIoA5)T08Wb|_pox(&sj41 z`8*kYU^pXob>ocTy$MJXXQ$v4&UEUJbYdL&h;?EdL4_z=j$uL-7M<4+s<23B301)F zv#k^3N?Er`0@dP)aX=H7j~qQ*K}}lzbA|IK90LKx!PVKGrecK&J*Ha_WRGMRarxnnhbHi(&4oC>^v;*}V6Q}nsX zh1T&{ZFfIuE@GV9YTtIY&qsbRxwAdyM3~x3`+(1haO>M{StWiEU@C(gjsnfG8OL0m z)_d$z|GkNQ=YMPEdxx(Jj#_@PB$eR6-cS z8?A89@DH1v-2+rY^F4i+9gFoFyRiLqpO+}`WRVWVa#`e10W^eD)`J+=_e-|WOaW&y z;QQj<7N+hF!3{1o`)LIF#pT9ITA!ZjOvg#847{~04Jw;$ZMe)Nz@S+Oe*i9uAxfR< z*SB_#iAh?RfH-N(*x-?dlx5ZimC;bNzLb3HIhhFdqf5Ow@*8Od2JNlf*4Q-8bVE#I zY*Nd1)l%z;#Wng9U*o4I7Tf4ge5r3OdyHXuhAl9}x~uK}O6O8!jv)F~!u@QMkOulP zG!6M#NnUeB(}9~wcOzMV+=dt_xf%Nzr>Qxz%a3-GjKd! z+#JiNX)9s*6d<-xN5^H}(}3J;EN3Q08^T2+Du2SFmUPUVMTCLX>p7>&(0alnQH0d9 zKDthQbr-lMP3WZV0(Lvn0IstFr(!FhtGwaHNh|n(6*y9@09f;eW7G<6wE{<{6>zR& z!lf0QpumUj6l%)H@l@ypZH23;5E6v`t?+IvXwWkVwOhuf+H77Y)7G7-&}*}H0cCj8 zYqP@JRd}epOlDupoychMzeX}^h|HJ?soVUCSL@Wq6S1rC#Osb^w+3d8@Z=J$a(zlc z)p05xR?xDS09Q+% zB~BK{4zl@SwX<~9T(65$qWir5^N)5jhs0K;5ImEa(@3E-pTU>KFlRN>`JoliKw^bfAZ|ftjg4EuniW9RafvH#(F@Gq-Z*Uq%#rv8M2S7RA_ZxbNrr`ednl#Wu=V&M7qGRSPeR-kK#30_Kq_{YOQadA>=yE?7QsN|@U@AjbmUWWjTNzVu zNy2P)>TEu3HqKxQ1UCWBA*2Z0qyj`|rv^8nz&)`ssK{ttN?lz|Ey(?}8Gy+52jl0V zf%BVttAAg*=jG*a(}L0_@d#!&J*OxZ8(1FN0}@#O&gf&nS+t;1!;i)q)+Q6IHnkwzI-K8|@PhW%sUhuDfQr|tA?;MK zq5?=e6;vvKv{QlM2GULiFan8{bZ^MHDBkC|Uqg+CDPrrMg?K^3Du-{R%B*tuMk=t{ z;Ty4lw$H}92PE>Je!n6grW_#!djnXvW(9`*wXDFfk8ntz81_$P1%{yOvI0ZU$*jN- zbag5){39ixd!(C``F6TUXd#(N?po~Y>}D-gQ;@=GPH*nIrU3t=hWew|-LlGruitII z95iF;|GS5ZC%9MVh$oO_X*fk?1dU6avv=tU{QS)oRHW2tz54Z6pou)TxTNYGz2Sw| zyyxFP_s2KghW2vUU%r5!+tr$~w)N_h{&L03XMgkGU-F?p{pc$%y13Mqa}v*M$N4Ax zUF`rTy|O-I*>d#5cYp4S*Pi;#_Z^l}rv;zsA3v_k#}=0|I1KSm@H?@3kYnR*vQ-}T zD9DRE-4zLG?BRyL7}ZHydCa5`EB+zUAZ4kiOmwX+0d}BSMu3Djs9A^95{dreB)DYMrsM zy?J76901)K+cJAB=<8s#6vt+!scdWu?XfL{v7w&m3>@`KWBaFOY%jPgq3eTAtD?X6 ze(=VtuR8uOC;riv{S$*TRn8D+D_|R(S*0W5=tR&`bHp_SG%?E75G@smbdog0-URxz zCpgjNr6F$k2%|du^zp*%L4L78;JFOahAUbU8bFrFM#qjEhE+9lQ>yN)x%tn(#ca@7 zvE7Ovu?NXp6fTi`l~O*cBB046*Ir6h#N83zy{J9O%`MP{Q3EW^8gmISO%D6|4ymgN zuW}~*H{Sel%|unBa44qD>CUl(wx)u`!u^^p+8?}*sa)@^uX{VcF&)Ggzdg9^8yarA z_V@p|_WHFe{^uKDI1jSh2ifg3N4me+?S~q6`{@%OdEw_j|DxAEb5b}WO1`bR?KzC` zyO-H+<^hbkt#7g1*83Z!_5tq!+-hd)-~Zap$e_XST_M9XOAAx<-f!h|!(W^5=)K*_ zcMq?f@EE?)%9n>XgzV}pKuiJq_3-|e{fJ4g{NF8Y_P*gQ-l%rVe7AZ4|7xL~U46ZL z&Qlb)UOwm9iLj*fv%dN^I&<>)Km6&cX;op}k)>O0@-{D`k!|VBNlPi*tAFL~w@5h? zH1fR7d4_VW7*wnKfK01i{~*M0=H!_#cwf=_v}Qp2=SR^nsFc#7w|nNKd2D<2nOAJu zTioe%SgZMoKC_ybbyQq)=Hyy{ulISodEg0ZWOXBn2}voV6HA%;d*ztz)nD{=_9j3! zv`%$cp9;3je5B zKULw&rHjeV94E`p6BR1?n+WcjIIA~GRQTez(e8|cL_(s%wNTgBw^G*&RTm396LLE{ z^6=GaC$9O{OGf$Wc=Wi#OMh|QPT9|t@^AQI<>wd?06F#8*1>pUaW~A!CKty4{&yr^ zb4Z(2N&omxE78RM3jt?Fx;*>>CFbEDeC*7cNv7AsQFO7Yo2y@ReW-3OB#4`mF?z(mJumEa4isXjbzB7=28jHf$250k)at zZ`ngi$Cz9OYie;&-Rs185wpJ_L)?&{;J6Z8cy^PJFoU`=h}cIBiOjn4G&6H?JD9jw zY(aijA}p!8l`;b#h^o%tRNg^CCOTL;y(gYsEc8WN(fELv&Vdc0uN?+Ow}WA9UTqM* zNgMxf$dx6!>01NgAr*IFuzKegDc6~oeM0ip1s?TBm=Z@y=hSpuQKH@te_fs&lDfFy z?$Np|&g_x@#r5Vh?EHh~w_f?0UXs|-eQM|#;lB&%Qb@Mm(hycb`& z=TRDBG;8`He{6nngUP62akL?B+_WjD>sAU}IOi)6-qPpECj8Qu7>& zU$^VA$nz@4sZJ#WYMk(M(SE`lWZ5-4vR8YS4H*VH7ZOSkoAv6Lq+26ShXN zB~9bEGlmI}WXvWzT_D5>?}8GnQQl#91Ye6I1@=1!gWFwny4pBapP4&Wb%vgCjqN9A z=9GYxy>a!4KBTF~X+O!sxL+$(%ClA}ksp-)Zh5T!WH|KeVf3`Hu`8?-?o79S8uqGA z&DA4gwAAk5pz)+ee288q4jRH{QW-NPp4g}|KkJcLL#8*t*A|xWanps{yXz{ba+j3A z#Xf9$4OcdBn_y6_rv|~HQkA$=s4yvE@9%O(IQ-Y-Y+<^Syn--o$s$mI-X}S09J8f7 zxq?)53pO8h%$4Yz-oByz$G~8*@&; z5LHt6`a$8dI%U!;>t|m6usy)o&?VNHbax#AXDU^QgO9tcAq zuffmu6}O=BBGu<-C~l>dRV4W60?{2RZrO?KQ;J&x`8}?<8KQh*-S<;(5u|M}^@57F z)2Vl_=wxYDOzLC_MGwx3z*gF`;sK$CmFucuQ%~Az*h@=Je-5USObv4(XS#u(cA`~P zl<}rBxH%w1Y3lVL6T{Y2_^RCxjrQ=)1U=3!x`nk_CWrMovW=2R}|8B;Lce3JMe-?vdIl>X?eO+^D-x z+|}Va#UQ)e32WR$F1{xI*en?}8=t`SHor8xS>Bx(>_JzS-QI>$GoI53x01@Q)bN^- zxujP@K;;-*x0VPe7Jbs>$v;WtRtI&;Lev^ySz=1lv@Yzhbv_$w=A85M;w{TWR-g2U z*fG~+7$LUe;Z-ML7g>H2L#9DQ@%`gX6Al^#?=8xR@EeSBlGq9&rgJJb8BdxaT856z zVCNZ6Qfdx^zet}gUnpqHGAjBqqmcgF9e(~QAPR1LS{M*7uX;bh>P@kFF%m!GydmR? zyxe}8wHCo?hBQbQ9kr02rW}e_m>pAipC(8X9K!zORGR`s>|;YmGp3rSuG`AD8%?(T zS^WAIhNXQAnjVp)nWL;>O-P<^b1kxuGF8T+c7lU6No{PpX(>Jf>i5i4tI||!GR16{ z4rk6`0imHo?8MqqXqNMtbl8b>xc+ty9N?W69d?~7Sy(+%HL#s+rz|uR@V&(;B#|Ov zKPW@)7a5X-Z$=qgW3aZk+LXagW*mNy!J0oSW6lpUSR}7IuMV2`dFj+bImbSqlp={_ zq?4ZMXp0nkk}+9Ugl7M)SyqE9xKXVA$}NvQoX|Znb@<{I4QtjE-hrJM*34Hozy0QL zH|(T2k(AE8v60CxHrr%~fsT__cP`49fc)0TuQ4$4bo!JUCh%zt+?l zh2#X=D(1pqI7GS!-!J;61v_Km4|ocmRsaG&)t@PskY#rAqpe^a=ZaTB&mc&PEHJi% zUxT%2Dhb5{d2teoGwZOSm}k={*0z{(T?AJ`?6|wTDCCK9;6TnS7MbbLMPp>;A@29> zLf(&ma?QpFTz{rP-n7l2Lod_;LxV_eE$*pVx?$JGr$N}7ez%wod$)@twoc9j?$#D< z_v&)~o?NueQkJ(iM3aU0mbQ6M4squSwOPLI{UOdpDw{XkL|RZyFFM8c$YK_47`C~5 z!Wg1DJW5B_o@F!jz@(bkVmDu`zw!)8)3^4`423AH5|_jBeV;AgXDyrJ3er{B%d4<* z(&A{giG^_3uxx6tB-xIx@ExEiW>haS)&Nn#b1EHe9D0*A(iYvmIPDs6U3fK1v8~qA zfWubGGMWk;U~KpWiMz&rwr!4LYtwt57Nhy&+$?f3#GMln220~TON20$sU=Q}2+L$f zLdN7om>Dt}8&aDHF_1XZk~t%%zp1G=X+bhskuT0#3icazbr+K_qkU?wD+aUv$~)1? z?9w82Xpus34>zePeh}@)FlDr_E0jxYY`U74Q6CP{N?D5Q7G`CW%jdPVBZD#`mN*cr zCuA}$>OE4t6de+CnJS*7t0h2T{$n(^sM%QvRYvcDvM|1&xT)pdu|tJ6laRl(D-|TbY)r89rMrmg z4?rR!#0-YOr9)RH!G-38W)Ce@17}>?`5*8gNLwVh)OBJJ1#>FaCizAE3`gcxnN=l? zx+2eO)p+|T(B#@V3T!~qyrtq#gPy3$5LBmF9|NxRzD2(Rt)2o)iBm(M9U5x5GPAr` zw#dWHjTN3qQYwH2&B0&{HY`8{0SjFt$pN`!!G^{*6BDe@q{c=}D5_wp4_G|Al+zEj zuAEm9UEev=<{q6gb>Am+3o{K9*?fN38G!ff{1B7)E}I{7X|*NZc`6=DI}z+A%%>d( zc@*5b4~92siviMOy)RGqww4ihYB%Boen0G%GvZ!<%PL0!3_monzx7jAJ{bPP#QxUL zS^47d)_i~K7p-tOe3uu>zyf=d80e6zke`7zEk3rmfI_(I3O}&SgML@Rq)c2^$A(|B zTrtQUJQmZ5EVR33f2;>>MfG6(P(9pLaK4Kq{HW(Ht0&~KXf`Z~Gm^(**yOQz0R-Z= zV)jR_P!v^{$}l&3mp>Vk`QFt+M{#L6O4v`t^mT_ZRh@ zo|i`^3r}}v%8g3NAt~FDr`1cPd=a;wB5S@&K-s!aTAGU)y6#pR`t6O`?0 zo019*z`A`81P+y#rreoLD$IiuxieEjOMNg%xijsICDSyN-Or9+vO6XJvy++ZPPqX$ z%AMI$*X>Ou9t>$Z&0^)WX~vZ;QyL3jORH)0{67*Y?J`m_K==Yfc``Y3dtmw3y&)OB z;&fmVZn;UfB|k{qBF+Z{aTl5#4`kwo-8!X-L!9mgCcpHaq9}0#L3>ilwUeR46asN91K<&Au02oDG^RO5oXXh==>OLYdDxn)CF65F#D~xrhh~( zgeuEarKQ}=R{M6W_GDETc7_&~WgVM3ekPiivRcf1ZN2K6OlRRlpO&s-f${v}c_C0S zOXV)Nj3kNTU50o3nlXHU3HSf4cW@&)*!;7gZ^d?7Ip5fte#}|1=)rx-N1YO@(={d* z^LQ^5vIEY5JTIN@kcVs@;~A^;0pHmpE3QxBuUp`SpC`E->-q8-<2gAaMsvJYb7aTm zBb;BOxzdi_(3-wOq1N&m%X*2lAwRnFcK{MHIdS|O6% zQ^J>a&Pn=lpzAgsy@0VVI2v%1$PnCHaDXB|sY(qrq zvgDEkg*fZDS>y&`sY|ICROe5r0T9Gkm!f6>{#bQKxvznSQt}c<{Q!7S2#1L!8p5rp z2Y0IXjN&+5pYDCo!?CNdYP<5%5ZJ z{%Eeg>*cqwg1cC6uKvy^Ry%uNY>Qr^1r3jRnN%)75f{+_rhCKD!_T|+^2uhFss(jo zak`w~Q`_(rz0T441<9pU>i^KQHBcGXKu!3ud^$GwbV1&j8PRAa;ACTV0W4Gecs?1n zSzQF_X*PO{Vp?QY^DvVpIC3sT(ngauE4~q1w(vgl>J}xj9XdE6iG%%>)eS_T3WEg? z0TM+q=Ou*xnJC75YW-t>qg9whvB~thGM0m&WT9Z2&*cc3wDHr9QA7tZ2-el6PKl~3 zA*W^D<~6OGo1E;nK#9w-4w{)1#YJRgl49DQ1&4{tyH1DJl-bmQFK67C!F|80E^~Di z24`M6i~2z5v1HU2Y>&gkl^8s1#=`b#R>{-t&?=X!kW9?BK3}OO;Nb9JK>4;+2>3Gi zmk9#t1qUr=hZT9%(C{nEUV-K|*C-;VnlokKI5gHBe)YA+;cS94Ymmh}p-)}Sq2=LC zi_rW;{1-9Ux&;l_p^++|MpQ{f;Y#h#_w_nrt=vtrs~cd`XUp>S@8upJ(1s~MYI z;#muEgvJSr#I*oH&b3&M+l)p9v9pL1*V6WHXh=k+s@AO~c5JdD>sZ$+2k6w*p3Cpo zDl9E1kQ$}WcyKoVLhfx7e7|0K`lyd= z=hfjSuhiUE8e+ce>-ea?@f(FI2xMYu40oR4vg+dtlUtYjG}N+V7$BzyS`%t*D5}7z zU(H?I8B{thr32^CyC#uj8YLKxd-1z>OJplmPp1>wkmOY@_V~B;SXN4zv9~*eAmpv#7fkc+pi7TLdzYeVIm_0V8HfH1W{j0$pSUx}Drm*ACOf`Z zMaVhy^0MHVUzY3)Qb$u9?V@qnfXxBylR(U8ywwPb+TCxVj_g=dt7W5wvZSbdqZ%yv z2bwU7#wMUuJT)6USh)w*Qckg!X4yRk8-ZttwLzSbjn!=PFlwT#VPy1y`^d{$OrV0Q zZGz}1kx0}lM%0lj!|qJ7h#g0gR%f%lS!2>hi=f$#4nZSq#HTc1s$Tk+jY#m$&b>l| zRGWzKO@Rnmdm0s9&C2J#Aj1vEeS80288_9Yao-ijeS6=>eH|GK?u&81qafuSMCQ>J z7<`~Sk&7ffZ0+WLT_D}LA<2=8dHn5xRi<}?oMFmX5J@f`%*3RF);Fo3Q{T+Ug9TQo_Z`r`~R#;s06;6>`IN-ejCNF9OLKIYe|rdr!1Cx$tE zQE1?HThspW6*RZ>uSIJs=B82&OFFYuLW3*KXx&)uFSS=5Js~}q$iBIi=_Du51lr^;*Q6GVR&&VNPm37CDx-E*U#Bq=h=SeaZNiY%6u6P#{Q6-j(jK z;4UAk0g1(_ygP9{BgX2uaO+?=3@CBmaAr*8&?fDr-68%NBYMU+P0s*dPexD(2AJQr zjxZT2`Gy4`hyHFCVW=?jrZvK(Ehr>t+k&JeY^<{g5Ca&hums(_5H_C>Mg!-7u%*8c zD`~WsGHNgNsP6g>{fe>$v8)=rzDAAWC>+Q6`{5A9fs-CIC=a$d?}6?``e@ zs$%`ate{qULtT}@^`0PmaF~>%SGaOC1=Iwr*@Vx4G{|v3EamUEBfHEJ-l@(KKTNf~keJFoEO>yHFr>hB?x1$;>4QKj%p0uk1IuwbtcC z5V(yWh7|2w>Yf1vE~>?ysgwh)>rm+cW?fB93)iYeo45IyYX}F8u)ZUi+ifiZtm@BX zMXZg5u8+l{I2qzn*sz*Ik9Dwh4|?HznLye)TP~bw*Rg}=($ZJQ(xpYQlZXgpdj0Dm zY{OG8HPm9HmVxa0LJSj(fB08J@r^3}z*O;CVV*L2)-2a7^?;P-46JFn#$pZT(Sog6 zCc(zdSzU1nzJqFREk^Jp0gKgD2$0{X8rwhAU^>yDLHk^oZF|A}%5uGRqcPBKeF6F_ zgcjD0cC!5(UcYQT28^bbld>mTm$$K=yuegiYgUsWYL8kY+WOHG4Nzgy%y@)Ll(s|_ zf{$E8QgXUIPchski zD)@tWaYCdy8H+FWGx9UHvB)o4ee`X#UD#xBgN2Hj%x)gtF}GZmz5 zt0UP+S{-rWZR}4H`ktEyOJ7(=LKf@Vnk4MEq?J1nGf)q3D$P>kTS9;x12#7D zb1BAW$!HMKvg}N~KY>|i{?1W0;?HK5u@*E*aHE@~&h!uy<)cQlo1Stg-9z_DiIGgt zlonI^P2?(&Xp{u|rot9TO1Cy)+mB+sEo^y3V(lKWj-6glzg#_Uw&*O6uAbMJ6>%>1 zv^-)0!4Bv+gN?=}n+w9HvnR>440Xny4CRqM1(qJ!6R%@9nu}9&YZbK#K?0OT-0(kM zVq8jx1T$gl)$^EIzMQfSsOobAD8NeU<$H^b_8^)aOl}(tY8I;>*86qwEb>RvIV_Rr z-zN53vIFaE7Z?Xq6^sY%-52kGofT(P?B(P|CWSo|(&YiWba{9D8Sn03Hwf*H&5T*d zjM+(MO!=M6O^9Wk7mH_&yUKi_C3nQ26j$C7W0Xh|W5oTIws7h3m@o9mtQF=~m@-+4 zxdoHu9~YdY+b3UV-K}46o(0^Ei=)L)9vHKRnUJHV!_lUXpOzSKf&~aSSX6xd-|01= z)bR67IHcO7<;l{FmNEL`F3D(F4plShkIi5MpGvfBE-fsRHr8mZ$y*Z+O40Isam1ak z`egHpraFkzt23LH8IU>@K)IG>szsYF;+j#@H2xDETC8nDhn9>d5g}p>idzCG!5H77 zMoZ@pjU)`rXBa?hRe1@)`Vx~iy4r97Yw(atP?kPmCIp5q&2}^}uP2QPo?7S3Nq;d| z1cxZH&gz#%+4zGwf}-XqghxGg29esfN~2EGWz?klDrjIg*0k`PM6;%aUKSllslxMH zg-Jo6Wf*`SsLMtQxV7^c;ho>&WOz|w_WMT9NjRM0>`{0abJIiNq>}dJ_^~lza@3fN z2PfxwGtb)|AC}v}<5SAxBYvGcKHASDImTF{$H!DlgQSylSVd}T#8qUR8W?r3qZq9S zex+QIW-TZDMA}rr)5sfg*UjJkoY+OuB%z#=N%>y%Y|-cz7is_XmvC5RUvgudr_15%0%65nK3JydS={J|DthM z7!#p3T~sVdFlm*VaWQ~He7><_(YIt-H>_(p>v0`GZz7&at|qYVb}fhjyB2@1$BY$> zTHX3aH)nODU8{LQTlI06R%WMURt|G^{^yotD;m^D&K^dhb+Gau%Z8Q>1gZuYuM z>b7dPfs!6HZs@7?Gj*|?>SCi^hR>%8+X^pKp>0Nh(E%~R6@t=lx+k- zNIFuVh&4;|V6{vo0|-kjO&f;Igvz5Ig8CViSvuGo!8(m-6O&NzNrb|5ZMa8_%EVed z+`yJvOaI&}SV&1#=+=A1K!;;Rxb1i)MXv%q#I=+`b7NHjt{{aGrlTL(KcdoL&IYlU zDA{xNB4%RtcVFnz5UfUX(JdnG=r9Qb$0cZwdL!pDX@j6kVjn(4r{XTCTHL^*OFEXWXSfgDrOf#To}m)0>pz;avTR~=@uizJYgxF z5SG%-!%~ED<9O3n6r3-hPJ#fQW=*4K32VMvg(B%`+VtK9FLk79lO510*3LSCX|yJtnhFgNr(07Z9}upT*=h{$x$CRMo(OxYn&Djy$UO7nqpP(R3bBWl(>>s3@6}3!+H@(v7Puj=oWNY|~~vkoMM6QQlWt6#Ue* zn#pM<)zoa2sa3N=SzJ*KG{apZHgZcWeUSdCU87-kBwH8=Fv~f#YC9jPWAt>i7h|4t z%qy8DOOdl#8wr7_wATO=Xgvzk$6pP6mH-&0au67{L^5fd2^eWP={W)@4+BHIa9=45 z&#lz7!kW&7`bZkXJf}#+D5FV95O>_DbJ2?#7(;HIl*9ow;+5hgE?+%jm3a{-cbggB zTyDX+!GyC4-80@Z&v-xgjL$T*NJ3@qjkZbO4a!0eQd1m^gN>$@2w1@})Kb&>AqL(`M1`@rb66yPRJ`T~eU7Gv^?TZ*`v$ zeYfk%_Iv^+31vLAuC(xPsfSE&vV2JMwP-PID~1>|-B6cA%r=H?z#CJ@p&d9SG1tLP-4+XN0vO}GM!gnVh3W`REIqG|r^uLG|= zO|%eGCQi@Kuft?#7%C@4Bfg);1nWyHx;oQBBO1u(X~L)_RR9S_7jZj=L~LADP4H1o z)-ajG_YHaJ9#*9pmF}5O=1U5Z!m8C+RhM6&;*r4U`e`FNuZL*hDVJOow%ZW-3)~Hx zVxmA-(t6&cwYjoc6$Pe1GeKI5vu8#n1`#=e4I<+R64dmwJ%~K{0bOJ{XiIJl#~enN zF*nU$w4NmW$8|gsac1b(XUB|Sffy-(%ud8UEmSvh((cejD{#*A%^LXA65WVgud>Jn zI<`KV8EFvNwrK6%b*cV_Vw%iLmG_}d0+VNQss+4#zL`ZK}mENlvwM}%) zt7>Wq#-x%w?xABE-jo+cBp{qiw%7}ZPB@QCnlXK&&=;ypZDIMKI&xpCBX4yXTrbqV z6vZ~&JvZAh+J{TbIyl4D^&S&r0R?SGsZNd*V=#dxH8TQ>VQHDsB+@Eq>WwGGh&$8z z*L9=7hit`c2mVdh z;+tKXQML*4AQ z^B^?aS*FCA%TG^%X~7m$ns#Xtb(XosMw$g>^px6%4u-yI;i2A1)ifHT)mT?xU~>rv zlXY1@O&X+Eq>UoW;6Z_{X25;CE$td5f=*6V9HE%?a|RRxaxd&0X_N?ab*lT3_e^3| zXUxXIPR4&Ot?ub}@fG!+zu25Dbe8nzWthPwPO-XsbnS}&?I`wn&w8pN_q0e+FE3#Z zm&(9J;dt(-C04SOUgPFdK(cVygRCt3ah8zb{ikw32&)ALmAy1euPIR!$hzbc7DOcQN5?W z*x&Lk^iP(A0K@2t2IHbOK^icB+@4U_5 zQDaV@d-QrW(gzyfVzqRX#4;ADw^Wg|?WqUGmisEU^E}dO6~~{WuhjajZ+znyUwil5 zQ~BKL8!r>3S1mvJzzxqCFZ2EKQ^#`$$jhp0E_Oec+ILmEpK`-<^KLQ9uKs`O0lN6= zQw+lt4?umYFq|1BjD#6cpZ8o@y^cPAL<+9aqHF`|{w@Z<|9Rch^}%)cW-tGr=T-%9 z$7n|9Q3+enbh$THIIQ+m{J)h7cT?d*S`|K|sc?6!aCh~PyfUs&{>xXd|LZepx6f?pNKX5OD0YCh{lknDuzPPd92!Fi@Ab2!kPA-lHyCZF?%Khcm5+ zY6e@h>@_~5+Fk9f&dd9~9#n;m-7O%5KB|Yiq*WlG4uDDG{&Z0oqM?)j6Dek`K_J6w z*K?t|rE2(8#CYd1Jt-Bbf=*j_|zLHKcagmqF=1`JeS&r zYH5!y)L@|=EZQGyb+j1T9Vtr`gAI5+`h0a#G`~y@XwUTfIn^Aqfc`$E>9k(kdZ!IH zvpT#))9UbZ=;zXN)Lq)7F?0q2q1nZFmvhBi1he3SO#Xi8o-vY)4o zWc;_Y+R-8j0|lrO7nphB`O|xxe##Bxde#bGwRR-%HFz5XBpHM$ngAXI+R+2-c=-eL z2Q|n8V}kaDcrh8NpJpB5kM$iZf7_ULh_A*A*N)Aex}e-{w&dkwvWw24x>}%#t&+<6 zWnKY^ZdeeHI@X1Ga%t8jD;L$uH1^7Q<2lc`T!vVtg1Yr{THaZ|?5dD|)2>RtBA!s5 zZzzHlNOW(KxUZAdVDBhQz0x5#$P<_dBJ`AbaOdAipR#r8#8aE$XxY{971vn322QFP*3W&0O*)-< z-XZ6oKnR^56f$+RfDF9e8MQo6R{&?~%JPh^&<-<_46o~Uhe@R>=+4hpgaC5fAhCr%0hG` zxambpv8>u@DR2r#gGzUC8QS<`x0o!~dJ>Di@k?H9`p z_dVO3stOHd{t*~Qu#mXx!S35kmoCe*q9=|Kvg&p`mn<&1-!pDiu$f1ug(pM4{5);= z6)_gbhMT7tUZ)6`>C0r&3r}!9$JOJphwyV)>uA=`tiSkKfu)2dQR0cKqwJFLAn>Sx zc+`TC5#>*I7RA+5n2LM`L-jeiDD|eO@4#`W-!ty}fow({{@IPt)%+8yfxT%~O8EZ-w*vAksUm+_`lCk`D-Dq< zfq6eX>$CEN6Tmv@#>Z}1WvUIig9q3OPwUAx)CjpcP_ao2~F=!LypU1V41nUrDCK;s8Tf{&$ch8P&x zL&IdWuJQs2oDCKvaE{ZFQcvML1Bqa(8nApYTIR*avobaXgzF=tffdht0%~?L17=xM zU|@4UcHl|k*L?{>FvNwi!ob(O7{+hKNj(AB#_q00Br>0g!$WFvb&*CZ768b_0&E18 z@E}F>PAC((Eut`C*@H5HgpnKK5JR-oraW$5oJGI2Z z!g_`D25K9ANqe}gYozps&5k()PlLWo+F9zRo>BXOYCi-c!O~Y6d8w-BSKpT~p(6VI zpQ`U^7181UTzzjWs^%ZpxkJ6cdiXK@f~Y&`*{LpM<{MYh(o6y9fgVDy0J$;&DrEUH zrnrs2UtGE3{wA2zD0Ifp3LLBRw|7TBpx>Liql5ZA)g3)tzc+SAj}RitFuRT1$AfCG z^d+7T$DEW`Km%Owhx+*0hhcyQAg~fk;f-d6(VI>{`-L#AzKdsJU4<$0?YMdb6aZ^| zB;2s>J#oCET?^&2tHFPxs?ght!b8Av{3t%2e+IhW_|bLw|45otkEY<+bypm*@{i`~ zhaVeZ?;Sn5;(a^q>Yt<}(ApztkGdWe8?cuiULB;cdQ_-+CDy#s)cgb0_c!$blSfCw zLwY|{YQM|mNQ{&v3GQXg#D_wQ@xAJyb_IPsgnIkW(u6eT!62(gRu>Gf6X=9k4ci9M z8OA|8nxT4!LYd9gbH_%)spj?0aB6lBqj;+TsrcApzmkg~^&n3;7GWA#k(G~M9R6(0&z{3w3cd|5IUiK;co*vJ<$hHQ+CFVL^Z*hx4MFzXhE7)dV> zUU^^)>I31a0VZfw9uV0*x)Lpj>>e43H>(lJdi4a#+`me z&_=%nWC#T_Zw%3a1shs-iV#1t5vF0M6$lqnytuPk1p__V?$n*Gb$tw@E%^jEED{&X zI~-TzUXH5zu)ys0R|mq?_f_YItM94)Q@Hxx>OY4oV}hpwdzL0(H4VRP`)hq3F|0~s zJ2);~HFf<&MR$gkGnaSS%DJ!8I-r4P{2a$cNbc3&fJ#^Rz1t}ay95WQc1B~t>kwa! zFTB=OoC{4cowJWe~{Bfpq>g3X_2Iht8;GKb#N;`Cg>caCy+y`Z%QLGtBAjGsyiNwd+J}cx8^8-Z)hK?G%8T-sH5 z&Bp@C$^1aKctrKc(TaFJHh0ZQP1wPYVJ159C%3R>KUCkO-?(N+5DcV}j2{Z=%by)a zcOlk#&O>~mCrw~6{3O$MSa&S@^jBl`FJT9Re=9_vCn#a!7ED6(un(Td2&42<3_pep zKg*}S&ARf5PJPX7SziD~skurdYE}Li3xFgBL?n)a{pesoqS3V^GcsMv@VehDc|Ndd zhF$qkWqB8WSgIcCnO#<-FRxUO0G*P}VlgpB)d|U$6y_HLSV7X`ER(J*ur;dzUn|&X zJwR7|US~~U#AF{_;2%69FdbWH%_i|g1xABi3|3vE5A`576hljZ?NRBiPW8yiSAvWp zUc@KK7_yhO4-Ms@~3dUMc0vH=Vs8Qu#JEgAzJ2mk_wCg)wn%Qj`cpGr}q8O^kpisa1vuk658!g#VDpfRhn7PALVi~Ym4X_EB2I-(%CZk9Nmswn%r*#BE@jz6d9oA16lz67CfeeULygJl>B43SJ@6 zP9RZDtx3#_9)^+Y}U4_+`KCZ7z54g%7NW1hexXK@(%!LPB50sSXdK+7GO*stAIVI={NCw_@APAeq@bu=7{vklNW#&N(G=RBH$Vz1mlex!kjHm=rHwJakDrQt|7JD?#@R|0W zq+MwxJ*6!-Fi~eIl|qrW;bpv3wzxV9DX?S8k+~*%vtt&!g48#FZxIoUJ3>lDNVD`OEH^DPX(ay-4jGNP{Xp1IxnRL9blc+pm(WZ zH>DFbV4)@GgE@@Ek|GNXtOY{sfRSCE&?SAp4(NPF<2&QE4gFYYIE)w3>|Ty^^C$x^ zqJQUsvQQ*<;s*#nJflho78E}1m}{#-1#qc7u_N{dNVapW(;HyfjN`PwtC%;B zuATkb(sM#+0G)jUI=v8NN6izrSalR&Y?)~LqpbeyP;opVm3FV0exKO zdZIk!Y`spukZta6J*hJM!EfMq1^8$M6llL1#*teAP3&zIFqZRTfyQ!%vCu@QfNB8A z@XyVgX;o4}YIgpDfUrI`v_LQXo-%rCt&e-f5k0xyCeotFG1q>i1Zoqxb=zC>7KU$n zE5t6Ce*DA>y8zWz54=rQ8-gy%aQHDn7gQ{6vr-(lCa_{mH4#61S@YS6^x3P|`HZ$# z-}>Q?bk4DD@9_3oj*y0Z_@uA;K6N$aO{ru=jQFd*3oqIwCIKrzxkOum&rHEZNL)O2 zP`n92iXXjV^%^p?wXUOo{nnO${qY8_I{6yDe7A#T2(R~UV%TGdApue#?ec5GpnE_mZ|C+ z{V{V(7L!66L=wxoqloV^u^dj5JyfpFnb)6pOf36*jab&lCYJp{BbM#KDMY3};3`Z! zdmypw4;ry-4%Oz<~HDTzI zm7Qh@!n8Rdj?hLQJ0>>MHGMW)s~32eX>T2u65LdFLAWF&X+4*_ZF=fI0`|F(8Sg?C zMI5AjA;c%Dn$}g)e`I)(St#d~`8d1z=ge3gN-M3^OPOXiP+HAnkKm@7>N0M^e7YM% zS(Go;{Dk|be3JB1s(F-qsG6lrSR36(6-x0@>56zlu#FECb)WK13XteDHLBFB8VJ@-gb9(}5E8bbJ!2&1)n}88TxQZZ9aWAr+c*odoTo;~OGGxGZ z8~OOeumS3v>sv+Qe|x5O7V|1_fV<0!6CgYnhjL45K~F>J=!1?JDl20|P3z!>I_cX6StPlndkmp<&$@eW z%MpE?Eq^LM*}_}LFWufyUH2ff@B+*d`(=F<+t+;+D)t&G(mqa0n8nx|#PD6h z#vvELD&=dTOQkVHiu5S*rLM66&E8?tPYc8)Va0zS#{OGP%q*6pR<9C zz3{FN9$#D(-zx~6yGzZ(?04$dC`0|*%iVm2GJ*IqW;)aw{5){g_*iLlDCdH-2&)0Qm0U{T6UTint^>*yz*^<6%AK9&u>b6$1p;5qm zt=L~&JT74WXN#@jYOeUXaCK4f_-bsNG>tq=CvoC%m#19|&j*e14mDh!Dm~7oEv*N* zJkbK*MRsv=vSr@RslYwP#YmX`CXmI_=R|9u30hof6Lt&^-UL@{5$DS^xH#8iaO6Vm9g?KlZgL6a9EWNzQJFPA(@@@k^gAHcXl)b7^1LF}Q?-Y+5vLodM zc}iUTETjdXe)#rYP)d zCG?b4EhOIs(isqDb7(08qFaKpVkO9+oD$bqtOT8-Ly4;`lz_#>oaurf#@Pm)c+`s+3p;05dt0Jk%{@-MCUXLro|v>mE6gDkM!&q%x-=zEinr>TT;uz&3GFOEzQA*_gh0W zJlv4=2e!-`E)MW|Y8<8NIC@QM_{Cl01FOkPV)D}LsIY13RbzBRn6&9AHoE96%xk=P zRM~}(>6>Gwf#$u#H$aBou#a>)HqvoC0+Pnt^BpkM-=wDy*h-lKTlq;Ov`$M=P=hIQ zjjal(NPK#bsaa3BJmeMzt`3`pVG_7BW1rnse|Dt$?CvE$Q}ri(l-ys#{fSAV6zksu zi3YH4f=eWX=d+uQUnYTtW7fk7#IZj)3C%yH7u@mp)03V*wtl{O((``(d@$+xqt$X@ zeOf8;rwl24C+rW#q1W(#w*O{taehzFf@0uqr@G z6L9aO#pl{1%>`VrMrVcoY|Q~kL3Une*j==IRD&cbwMZ|!Sswzx>}JzW50K@?*kzIB z0vx%>l4GWSAtp_8ZWhz5@s-k`j!uYY@RbwoL##hKzP5w2!}^0BJrsFI$h$v9VeIAz zFZvozyr_X1nY*MettozCBF3H|hGxCy!@SR!`3a*HK!n!rHoeTsO)r;kH^;X~ZrgBs;F3_ z$3L?zy^9@8CERbtI5r7*)HeyM<+Q~kmZ4bUiy1aHlw1FA6Uru5XM%KWT~$6uff+r? z=L^fDwmiGgcWDf4ak4>6P7&ONzGGvIklg=`qr@zTtWBU=#3Efl@D8jst^2GFEk>3Q z*w!?kYO|R>G_Se^FuQ=YD5mko^I}7k*v3XJpwI`zWsK^Q5(=p=za>`1wI*ao-xTLA z7iBZDOXlo1^4<<(YzDPtwDJ%x@Gw9ZWVR(g#l~pSkr_sezA(GlSsW0S1k&EQotw=K z(S6l)tBt$9ank4>wm&8Qlqzs3@7ra1AfwFSO#9TCfI((83dViPdIsGOvhww>`{d$; z4Vc*^zpu~8Y(q@8%KRnMyRSsq81@zAy%A!?VsrH81qxfuM&9$>SIHFm1)Lv<7 zRJEZ}Go;2;#yW|T|3zxDK3Ln#~tLdTF+)Na9P{HYztW2Y(1fs-pK& zxse@xmnd9$0UyjfkoqJ%$)J+mM|^M;&4Qb)gHG?ud-*U_G@l(!Q7L$GJnelX z?ET{ISWsoS9I_y0JG{kbmE^LclKD(&R+EL3-}u{Ce)0BKzw;PN%A*u$GeKyz)4SnM ztihp|7A33~(9c?B+=uVrx%>63bXadKm+4WtssvO(KPsp9ZCwg(NZfI=#;t*4S&MPD^9c z@9wO3{3dm-9i5CawDDk92tna;2!9BZ_OH~UmpnZtp~gi6xfJm7Z#0J~*VO-oe|_ZD z1gfe6id`dK`g?jdL?{9ZGQp@YhfZ4-OZW(*wzv1Kch=rO@6vjSQfe8G6!Paqcy5lp z;Z74L9HV)Pc6WED&VaqO8ODQD__HV#L}>bFuEr41Bi{oCss-CTX-d|ucYV+{PnKrQ z9||ThO{`V^$4lXzR=H=tzsTk1;IKJ<-|-h#q`XgCE=91l${W1|1F9tTP;DGzh8=gI zwM~1rm1DbrRH*18e#keVc&M2EN)WHtpACL$tI?j0RM~aAC`AvH5shE%fjp9+)3?hX zeC-43$X3l&nx?fSvRv<1h>Q0LEq*t>bK&{N-tzftKlP69e9P=NZTb5PZLMYtPvWrn z6yzVEo?p%*f&&*2FN<4cO=>HX-jnHxps^Lf29MDh>NF@+(%`>w+-Xb20f1n8#29*D zS~vsHlf;MYtP$W)I#{+jPu;ok%cEFPFO*x!j%Uc71;5Kp`OC`H=mdaD<~j7~i5^1BgB zX+(2_QgGIZ40>O?RU{zsZTIys0g{5gv*`lAji}MYJ*9B*W;$Z$GDQdeeQyDt=&FbG ztB`U=rgr_4r>zPDXqGqL-@BVt)L(n`?QOo{%Z6K@APB9U@xA3Xz*gm6 zTTbgmt|a0$^!5aIeyE~$?E4dW_Pz4jv+qyj+V>~5Yu}$7sGe{&)Q+6{{!Q)N_iyCg z_b0V?Kh+$6w=9Gv`VwVUGsW4>ES9hm>v#+2N&70L#?;Ob(0(Fis&CsV0iEU!5e8#_ z-Y58uxzv>4A@)YAR&o1x2Q7;v!zfCAS|*r`urWvz<)x3|STiP9L|yA=6@f53U(MXg zqe_QbEs~zo^t+lbi>_T2tMrp08)@IR;j^KfNb0oQOVrT;DLY(~Pr{_WIJIHhb9QN?(Dq-(P8M@Iv_xu ziN#u-6&#n0)tZ%WKB@LD9D72PPouprHQHkWxAr)*jd+CKOJaNT>SZgmXT7{=LapA* zgU8kCnhDRFt$wZ1>YC8%DjHx`s#-17OQV82zmEdV4*W)kH;*-tl`k~}uN`|b+~J!f z(y|@i=z`&MA7Qc^2WxLrgXDKAFESm6>{Ug!QMC;#2cUa*M)U{2_oak>@Vl51_rdRt z89^WX?#i%LrBXgH%&sObRU~o{$&r-Da#OO6vG>F1kYQ5Z-6$k`8YOqtC0Yy|LP!vY zq2)kLe3k)5!IzRrHZ0>YN={bH$Tl^VkC=cQlkJi@A!fo@nNC2d>Pv5<6iaWV4EYvR zemE1lQekpFy9@H>zucSz6Qk|yxJoUbD+8{@@=aP$tIG1EE!3KCpYW2=@vyh=8+)59 zjFal7=3OSE`j4~^Z*+k*qk(^dFDB z5sTH&*vN0j=C~sBv~%21p0W9CH4C#;GJap=e&eOyJ8dgrAOem5kxZ@ZwhfBxv|mgl zM%h@Fflwn4XRJ|3L8M`c>?Tg-N+SOt5o*@y_Y{DB*Zp<1ixv3}yz=rljR@;)=o z7w}~4Qdv+NvdOi?X7(}4Pa-L&kpt5(0T~@JM{OiKBQSt6;M{9mw=e76Wm}Iqu9Wv# z(H3noKJwas$^g}8vO|(#Dn}RJ4>pBk?Kwm^*j)e!vUPBJ??fL=gg%7|K@P<%3s_S;8{k(F46xX!etv3nrqZ6j+?(c4s|I8K}NA$bL zUr;Ygr=->8fj5y`OIs5!8%%GcTvNkrdDk1QlxUCjYn_NR@j=tf%O)=+q-3@5mStJ= zEX0b_;m!R#_LZ@{jV=-jeF<%a2dY9}Yg^&HhIGcd)^F2d#vOiW-$W)`*rbL_sF@4R^g)z7SdwMTsc&4tkU=dYa@cS|T9Y zERFWs1i_#;?zK0vC7upRdfq;~)QiV#N^oBt?;V}|-ng7cJ6z(`F(HqaX^B^ZST{jP zayLsHU=kPbr&?vUUxa~ng%tb!SI|9Zyg?= zz2lgK#1`8-tJPdIwG0JbQ+>UHi|f5x-rQX8{pt6)BVhZM_k5_a3cUSA|6rwiu7&BV zwP7sXKU5m)y?vE=lgf^JKy_)?cPG|T`v|x+lkx1 zCtGM_Q^3+G3(dcLn;K-{gwZZ#9jr5iHXzP7>54=fV9(yPJ9Jm>Sx|rT&%~)Tq*W0= zrsOL)U3tnOxX}fVviXpc?(ho%+r=|49ee$!7L&oWx5baz0tQr2r8BD9`l|H}CkCcV z3C;N;k?qIAc7Y1}$A)JQ0W3R_Dgpc+?_MJL3Ct&~9y6c^&xiytSme1Dk9Kos)6hZe z<)u(r;wKwOt*@vEyG^yqZ?5?7RiDbW<=waP8|mRM^ZFppQOnyOYITzB&_5wEZu2^g z&21dP!RB^}o70ZI4J6y#5=}On9T^39h!&AAY57oY9~&#GlKuAymu8pn^V)Y{NEoU)ooJ%47yS`Sm*mrObdI z;a7IRoBSo{Y5_fD@gzes0rEwKHZvxs?{AREv0>C0F4vHASQv_f1Hsk?o9*@W`?55P z#+d_TI?R3S!%$_+u>(723POJ7GnCD<$T?Wt&YluL#N${9*?Nl62`xNaVWBp_O0&vH z@H5Hff}3#XlELB1YR(Rc7#Pm2dAKa%bfa@kF5Ku3@&COS*%H;h!9ZZ8m2$zymhu3? zuv&X>(90HN=<|UI>4`!;FAr2H_jGo7%=J5z{AhQ}q*y1SaftTmM3iEG^#f?3DaAIs z6f4eKieV>~7?_9hkzx&MGU{QO{>>=JdM?P;%UU5*@p1*3tm4!wMlyM3CTe4}^2Og% zx7PK(^D0rSNlD39E|LMxM`%HjC1%W)ng)=PdjgU>F>3^JnG&$>tR!I7*&qSw?2rVk zStm$9v+XA3X(eF8DtcBD@X(Y|!c3%u(fRC%CWf+Ij#0wsd?xmL;O8`>0p+37AoV*F z<}@-CF(_dhTu-v1ln~eih?d7`oCOcYli3Sh012HLpB5-bV#j*)fx_~cFCEC z-NHjNH?YdF4y;GsLHW@7M|uNy=c_ls$2*F%(HokR zQ1g1CK5@^gr9F8st@R0?s^VY6VDKEAM!VQLMzBG<_!*!7|LL8OyM&eLi<njV@^6d~~t`@B%3SxHl#ND&6H1)b=ZC z@^7rk%ejQ;{wqJ9^^&J?$vaQxC&0dg%a2p^Bz|A$FKy>iz)KCf{asd*)F2f}4f@z$ zp9T%v9Stw{cZ7x~ITrr$j?-X4aEpU)@Rx*z7l8#5#MQFAR^V>R%ja+C_&c6F@D-u+oMPn1tGI?x16rg&Cf3}2^7IE;vIcY!lMQrh-PTEycvXr5- zeC_k02fv%%x$x?L{o>t!{k_Ex{dd_~kmJks(Y^pwA2tCw$w@mA&%9WE-w~W}`2m0s zKYZ;y70yAhP#zF0l=F^I9_UUeU+Zr1d;BZu!~euf$kef+#oJ3dElmT7i(xa?pN+el zPw`1hBYHAFh&y?E|LR{x(JOCn10QntRuhSNdmmLH|Gh)Vf7b^-dglvY{OLdYm>bw6 za-y4i!&rBaD;;{vQbQQ|#(Pi08t)TEc>y;*HF&Kx`XaN{oSu0 zd%-`x?FD~oj&?8v+h5nMcxvE+G zEY?>fr1dr8F7{UI+t_7EQrY`r$Ne4)cI>jA8!q$&w)RSY-SF=y90-MR6ohx|j^Lf0 zj-d7F@TH*m9~H)b#xTxV<^#{WqOH32BIzrZd=VIB-RNBp#{dwSQ_DwPhKR|uDLvOX z5lmV1Ia|tdHcx(CrvmuvxQ_ICXCYGtLMoJvC`lPN2HTRbSnL}247Si?&%=-lebqfH zWevU_ZAbO?tF4hPXfDzUc}i^4wvCMA}XS|F!+Bq#%4<-Z;b;u??d8x z=a;MD__;V7Tkyp+F#&N8^>h>yqnM)8oK7P|(CLm}v0FFMmRI7Np3eNHmVdtiT{}RR z{}K<|^9cvF+B^TV@y<+m$132RwpMP`^E*`!R@ob7`{Ox_1;HQ+_bW_*$PSh1++U?# zFlgl0Fld5cA!x%|mB>X-Ak762%N^eO)y6>ml(lvqETn<*ZvG#QZeAR^3B%CzmgJ|x zKs}@C<`e7<9$owZ4Af?Pf{vuNkfeh(T>wjRW|Ex%=CX6r;BXQ&LEY6S>OdMg@LN>} z)>;S5xX1Gurx3;|(25RcB&&X`MTclQ2<(9kS4fI*RkfxV>1ep5vUZ%i#0|5KKL<0KVZyzEnM&zOkc70n=A65s+2Uc` z4at{2vycW4TY=>254AT)mTFK?ywlzvXpTDf;gQVzp>_ym+&ko_JYyi@K%K0~GaP7b zXTM7}P7fVU9Lz&_uI^bQ6){-IQT5ix?vjB<+QRZiTT}r61>9cQjLd z<5kV|C1sYZB?8vKm_mjfupltBVfZ{KQd7bNjBUQ(Fh>7sfefmGD9tNTI)W-~Hwkjo zvJN)nXf9p0Ax9z5AvwAfai1GSE=AvAAC`vwEE(mz2FlJi9-g2;RF3Bs3`f!q05PL4 zP1?r1P10^~aIX>ufw0fMhu!YYX_gWrjk<1pLQMnsou!|=Qeu(`D?UjOt?GDVSRJV} zIM)@!LtYk*C}(~VtLUl@H*#7_hqAyJrscYBFk9q{c7@w4Ucq@b5dMH7wl>} zOS))FHCci#rmeQKp?s^YVj+gNdwZ*S0_b6m77WG#)}WX}=4!pppit)(%}6g$|DP>K zEpgd7|4-PpWitpXiliiMe!HCef6Qt?@*GQ9t$fXXG-R$k(=DCD)eoPu9z8{HN*)fo z(EM(-`0sD-^xt0#zn6#KCx_oVt_c^n`$fJp{O6m-)Qkui1=17rKz`7uJ7v`!gqy|A zutK3BnYx;xF#?u+{MV4nUmBpcahAj~Tp230(>cs{oonNyDXJZ^YqDzU*egU6VWP5N z%z%@=HW~`O#1hMwqV#a2&lP|X%VIrZPvrE@$^M1E$=>O`!W_`y9>JTjSGIR^RoMIE zmxSf|9IJuMPAs*mv_v%XmbFA}#9|03HaBNw@x(-}5J+svL>3Ob;`rNAt<*WyFCK1K zOn3h%YblUM|9`BRkV;&SdBd7SP%y}Cxzn3nb(!w+9n57ojOUOtfSmR|qb+*U>U#sW zfXS)}%A0YbpqXOZt2G{}6l;0m>&~l|wD*0T-^jMK*22NJ-TT?}YCB$`#lAFcO_npxzqbxw7S=?oyypKGHdZgSwzboGCL>X9or}xGCPZ%r2AA` zMTHL)j0dbHw6f%u6FfGACu(KKj9q7UrlJ$M62K51W>4!4C$wp63Y#VU^;30 zO{_jPneZvqmt4u}VipD((ry!fQ13ReFSOajAJm&o?1A>0_=9?{i9KM0NqE3jvkmPu z@h|F~CiaCkn)riyqX}a}IHfI2kCUAA@QoTy?GoYdHYGErW4%GXa4dNq|6i0~B9Jj1 z7{X7cgZ3}ub@ocvD}TRVvRM=MH3X2v5eto7lKWAXNhNW#?2$?N1x}BZUB1)u1vpTa&ik<1(J*YiBw8={yURu>(-{t#R$tRkyOh&U3U^+oWjk48O zc|g2H@57t;SG+$i-i8!TcgG|mx$9}`V@caCHg67RNnNzgMa=)1**MRqj@ z7w28Cdw<3$fouMUY8R>93$@7QKt^mQ3J#05wIe%2SvEb=IYpt#7y2b6LUuhjFC^uc zbq9{Bf`79DvwmxqPs;CDLBsHkSdNGbDV72G-n0(@>`+VDS1V&`z-yz&dVGXV3Q*9k zfmv5{!q6D5j-Yzok@fayx&Uj?wxyy5+uHeWL*QcvIT{EMN^xOtze(=UA{$x2soFZ6 z^}h7R3e$&{K(COhnBPFkBB#*-;Jo^Pp02=XpsTB?V~#)7bIdu)Csv`8Mbl9cQ9zo; zgBWVkJZ#H%>zAI8t<+$5WMT&wAJtxy8|1nwUr)gG`?-kT8vk^ZH`NvRa&66*>z3e4 zUJ+le<0K^KOMWZdN=gm$CGSzxU_CNjV&~9u zb8TXO6!(09n}_8@`{|@1MJX)WBo#$H9LBc2b>sC4>^vZERMK4{OV0@JLGTit{j~Ap$&wpIvi`Vv4sj;)h z5!1)_G^q5GBhi7QF<~(}@YRcaR9^hUjB$o&Wc|UbAhXTsZq=kbT2bL1LAsSer9T~ zR=>TojF{4_{!ovYniv`Nn$;F(IDMu#!!y#9ShfE5qY`m=^S|FO5r_EC6sJP8m+11% zA869$wMa&bB&}&v#(?EU9J19VXJ-mxW$(S`8*w;m%%pfpK}*gyLHqJELkouju%JfV zGLwksU?W} zwy4J7JPvk1^}Ejq_WdxKu~K-*PiD=K-}~!&;sp7X>7_%5-?$6it)BG!N)l`to07)E z?Lye_-L<@B%cyq#+;XRhGRfovh%|(v^qnEYfTjJxj)qgoMQMn1oT@}A=K(jv?Kt@p zIC~gnE!=KOpI%PRDDm@K6RGgw|f7X6Jk{5W~LV+Q3_^>xIgP%+6p@%h%sdR`80Krp1=IS z2LmprEbLj;f1|EG1QJfD{+(9+cvLIZ6BlZ+(3|=F?uV`Vf=e3Q#7_uZ-N5C~X?mS1 z|IXhL?v=PlP<{176;yYHPQTKN)ae*mIsvR>x2o607(Il@*S|Yx^=d@^lY{f>zq1m7 z^L|ayxI!25S70Y zdG}+tjqE^+jkG=^kn0Au+5`61$YhhrfWxA-6>$TbW6^=@>M5;g;TvAvBJ#8)i>dw< zc?|i@2>Fc_v`P>94Zh~A{B>3Vs<~BKD61;!57O0Hmf{(UP?T=K@pZWQmP5p7A9_%L zgvE}wn2sLxITKxTLggj)Fue2LC!3<7ZOZc|?%^CC`$7=lRp?@L@ zT>By}ceC<~5n2%ugWS{(dKshsRBGpL@JsxW54a`z)_Tz*e9G}z3^Otw0qoWu-Y4hf zK(6O1z)w-c_!k?YDVbo9pC<+@nBkBJP0HT`i^#h5rnk7jvn8~g$C6eBanKfuXZ5F6=F96U z5>9WO1>TK_SMdIz028BCWV&Vxc#-Uh*6x z^@jB`@6I<9{CYRRZ&2KLL-Pu@^1?(1*7cW@H-&P2aKO9T*zDNg1-0 z{NM>$7ddzlQOw>1Ocmu@zl*&?JA&zgU#d5MavdVgOozYtTg_IDte?nv@Jq6p;CB zvvIo?iZUlwU78Q(M0H^6vj;Qk58?W{J@K}Ku|Kb_`x6$l?y8T{Z*L)Ilxo&)4F-yA*VCCw*)v&1*BE!F%?77;acw?)!6o;~MFs zYb!QtMK(G~W{`9<>$yeMb~M>p-fIlBX`GRsG4ZhoMd?$PiF`iyk;S!wpk(%>9SX1iz zWtVc!``%Yy_U+f6`trd&wg_%gD)edFdW=4utJEP0`Vro{LcDkR5bp`BtwTK^7b&qa z(Dl|n5rxiv#*WW&_M;Q3x8}d!>~q>C?_WW&OB0xc5i9Tg-<34^&T**8W#gfGl-_df zAAR@-ANbloFOKyo?zl1TvklM9-W^!FcL3awEb5(PR6RcP*+ni~=4;_%T-@m0%y946 zp=G_}v;~uuLAHG2uRa!K%ZL3^vht&K?{2y0dtbl#t+(C0Mgb7`mEJ`_0?Z(rO zp`DLu-NXQ%Ff3;^h6G#=jo~IA!wu&gIYM z#NPQ1Vq+TojF0DOm6Q=$wXJU>(_qLQc~*l+1lCaR=6n#R&vy_Tz58T6i03oO;B~AH{SK)pFOR( z2{eniF{z4RdseNUQ)# zq2G)c=!=)j*yy>LPN&VBj5)c8x!KytP&ZMX`KzgPE~+tm>oEFg7Gc%{FYIj4zFY_a z69MtW%&aZ0d6Ez>&u*q*u4X$dotjSwp0-ziZKuE3wnROw$wFFFOz>{qVm64UcvI#U zu&Ru8+l0O4I>Ea#Hj zw38&IO0q+mJq4A8a-9lWwbOjtoKmuOXeYV7$0|e^nvFY`XN4gIMTMa`Fr;DZmTVTw z=kQX&7o^C|eD|zh)}_*^{Csu=pA~aLC+Wn|D1NW1R{@4zCBs58-}%H6tMiVM@T%oG zBEg+@4rLfzEYE8q>bXm|VH_09V1+vCDk~3U^>%e7q~+Afs)Qz{`@$3RF~RjLYHO@A zX;);b7n+Y$g@RCxaJe)I$_X`G8rLO+GBU&a3&ebSfPYfHolDq5pOFezDbctT-;jRX z77U=zcK$m0Y_Ee~+TLHgtS~u%D*fnf;zSiVhmU78x((94jPq}lCY!WgvW1Pkl9hYo zrh@L5x^*_k{T#0}71V$8Hg2+Acrbxzx;_*>+fhs@49iZ`nzF!j@<`y^R#QUXaAMQw#@FGmPbBtike{*}RO(a%z;(MDLLk zP*>0N7I0PCQkjgKdrAZH;owisxhTe2k#C zVpg)DGegBD1JuVV!?C?h52i!>z1>%+pa&lMPmY`|`96XYi_itV*Sp>&Mks3I2xRdO z{=!K{K0uo_{Pd|9qX7EXDc7=F#)KY%qWV<+QU{ZKa30)i=vJA4ZK7Lc06g75cX=0~ zs)}G1)}i#N@@^||iD(7KtiY?bf_o`wmnV|?oBOQf-bTqTaZ!0+T_R3B$ovEPG`{t$@~FE8X}u)p*uD2wb<`yK6Xvg(RfZ||*qAF1);WFP)V ztx85=GiY0ihhC2 zU*nzQAN`=7OR$7jZ>KVm<*oWP+(<{#B_Of6#ET&wGKKr~CN4#}Cg57-;g3;e2>`u! z+)m>PXP=mebm0&G^uQh0zW(}E#ncnBJ?TPzJ?ZyzVTKvGz($+$qhvzV40>IlcMo@R zoupS~fjx??r|Zu^u*?EE=+aoA23*3)1C+?5DOQi08BifS*w53tq?9MC)giC`=$g zv(=Jq7!aF6lUVS2f4SE{n9r~lszDaU^d#qvLyVZ2#JW;Y1URybD!mz;^q_e@yTeXK zxWUL;Jf}K(-d(QNqbssIt|W?H8Th*X?WNh}TtHuji{3Z2bw}ULISA8Fv5CVv8CZWD z1CDNMkwA(f-{_lw(Z~pxM<#1qRQ~3L;`*Zf=3V_&!jA?P3yl10w7m+^TIL{+_kC!B z$YA82jDxJ>+dTcbjgSqQZ~F^_Xf{qkKHvMSO}brCAqdxCFnGcv<7!)6xiBdPv?JOE zUEzFrIzfV}%Lc3MNICAfSQ9{EHZ9h`vw#Y8JJ^xcVP}zMcY4yF%Xgskp?&8Zc_9T5 zZO_JDyFG;qCBEorJ1h0*_}kW%P&q?o%Ifw3ES!j1lv2rT>Q7QpCgc=tYZYkp%?J`9 z2jbAt#I&)~7~2r5m44X@h!x^2{rKH!G2Oc->|_EL#b7QRTxf)_CEIN485^Lo-S|4? z`Ov$$qzkyRFPTGC`~JoGi2>GYBU2boIYag-63P|)**AKpjxJl>B&+htPiTU?%30Uv3Cc>L&o0gy&oE@ zFMYV`QW#K~N566Jr`|is2s$ecHTxN1pt_=S?naX3oq-!M zFol7u38-P})d<3S(aX1_tE|z*Ap_IXf`MrVV2l`;8Uy$y@2@(!%mJ+XSP!7tM>Nay zXJI`vvhRonrkXWnV4B35-&mfnOck+YhR3x|Rz=+HKvtWttmg4xU$WDkO=2oW2J;e$ zG$q-U`ulX|C3G1Vq?nfwe)S0m6YWbMnaQWFY1iu0A~vR$e-BC-afE&E+C9icpZEY6 z?a5Z)gtVg|NZ65}KGET`%9w9pBZ5t^!8+QC5Ag(j)k_P7%j7&9DkadSLuoNwszo-X z)%wzFkg%eZ^_T0xOscq%x8)!g=*k|3E+FMPB>iZWN7+BiJ$i|Q*87<0ICSA?uGI)L zZHu-8+;cnGf;^aw_Q_DX-b%Y(iez?JHd*PMm$F>((#=+ChY2Z!Iu_eJ$l>JTF2WwN z|2kN0v&MY(G*lAVw47s(;vI(B>vO+c({%yCaAB+xv_ui^1@^hk4Z`2R0MHpK zV78A-e}6+#Bfde8^QUnLvS8BOr$Nbj-_dSiHOW+HVxLRWPb`j7-R{%`{idDL!g#Te zPBEC)WUd_ux!_(y5yllSC@f(Py4cj?(#H>a?BPUXO8V?A^=;S@6|hEm-)oi^nlx=hNOnXY7rk#&bkva5E&+X83` zeTTEsl~mpUw6$I$C4Prl$-M97&3Q0{vJ?c)PI-x@^da3PrnLXX^zq7Uui;)J>syP1 z?{x@2_Nb&Jyd^ZyuZ`u)!%UPJpJu(a9Ojz)7D?MOfkGhks=(k5dvqG zmz=E2Qc^V!lObfcHs3!=WN4saDfORC9pC>d>{eraqlMIJRKmdFyiAxmJO-u_9k+h{!BuOT49!Gl}lnq zM7SfsQ}C;y^+lg8m6g0XNdR-RF>70~Uor>zi%2-3jt&frmc10I95h;0MkoCl@&LaD z_`HIy@`7gh>?vh>mA<`PHx7vn6<_w={$isZ_01+#WhGJ5h7dT}zR;OV5|si8S`LCy zFYWcUOz&MUqZ*NvUZZ?N@2D{kmq$6rOGU?Xk<3Us9LkRwj-i8*H84$ER~;GRzoarn-#>Hu5FTy&G8JA2jMt`JLNrXos!elyN1J^B4)CQcjY8gWbLWOxLpfKWe zvEzu`-RYgwx%QdWy33^C1oY*-U3-O`FeVx}16-i&BV&}|P;$>u$k~NakTtk(h|dm9 zrPY>copqE2K2tz)E#I;o`X}F4;2uRVLpcr|Bu(N1tt$S+BJtQ5i zA(IlXe~l#D7%ocd=g?eBrNmb&Qgwq&&r(9sMXe^c^IIVbPYhqpK@57Sz2Uxs1koXM z4Al$1KvelyiEBhoVo{?^g~7ya8D-7>PyLooHhP2X9?@YQ0dC;yEy<>B$;N_fgYqW} zNiiyaOf;A$vKpFLnu5i|t1KY20MVs*!B#;DyXx?+Nl*o^9*dIj5|gCAqxH%~e1*w< z6F(o^1$k@wP8J~a#YGOIe=aq%{hxHc~a=@zO~sZ7Cw&^oqsO)-_#mU0&`( zRPhWG8aDtQ)-{AU@54ICndK_yC7_e`ZK}H$6t!~i1u$?_?!5rgj>^3kKzmWShcifx z)WS#Ap#jZj0hk%r=ap%V;{q-d3z;K8^S{icxlT~k2YGo*ON%5eobvL3<~PHREAY;SVy|jVgRluQ|KDXUt2& zqDTK$o%I()zqf1QKvHXZwMVfB*l_WE&~^Rp>sT{(0;m!rT!TgLV5eY&gc~8BS*V@u zP}+U5v@~Yjk;2f90cU=)LNoUtRH%UJ7|hxv(J4EOIj>-1J;=Id>HqUxOF;-exp>2K zSo<6$^kqNb*vYN}i@|O8zGjPHI@KF=E%P@bHn-gBd5J3FT+nS&wo2iGSxmMK%2p{{ z(5AFnse28^1#(nWw5NBC3*>N!rA61Sj*42uezIQ&LK)a24Qn8e@PwM@^ilPMwXuH# zB&&v=AQJrvkgpzk!kXEi!0%d`Ij)d=@S~CVejH;ralIrD%^Ki>P6G{9#TBy`oRNo) zk|WP}h;D~U_P+noy-z6w##!9OQGQ6%4hkf>G{O%j%{94g=J9R!?MU zs8FQ>kXU0?1>mkm=H1Al3W4QO?ks2oU$N7j#D#GA_9hJiv&06#ITXEj%1vr6l{u){ zAVY*!%fIlhg{g zoF~}E2Xeki7#b!hB^qG-jUh_W8&Jxy;D=Hw!QYhgm5^@*As>)ukv=BUQSqzM;!uvB zJbcQxA&bVLYwu*L{g36*>-g<`LK81zool@xknUzTy-&f(s@UyrYrXhXRqTehbzZz^ zG$iD@DNXMar_RhSnC2t&tQpl^&R|hL45}^ zgu2md#Lvb0ZOj_{GJ729l*bQ$kj_6QwBp9M-JhVWGQOD}A83~OFy`j!9#$^hsi>*! zPn(+mZsHZ77p$BTTv@qGk=RBjuE!Bjhl=M9HB()M&X}8;2U{+t-0}Myo4tIgEiHqM z{L(F_Y#!T_LX!A!S zA4+JX5U$Djg9IGd2^Urf=LA!<+lH+W?g^IYftiM_(3rudw}DxP0Z&z74<~s+z|;k)lpQo5Ob*JpyFU$T zb@!GuYvkIkPj2ERYERw$pY34ag((q(;G+Q))ZRPf%+#e~9e4t+_(*T?D;3IY(5%L` zb2S~kLV8E`ZQlY&Y{>^LE-)MRlpf>^zWjirEv6pVrPDcIGO-kjiU;-^T*N0Ta~B2 zioY4%viKL0aU?i=xBXsF`{~be%i>Z;pkKt;BVn-O3^PVVlGK_yxdf0dS-SG!yFUi8AZS-m@L(8t5@;b<&u>=v`qq-M5Jb9Au@@& zD1e5;iF4K|LZgB(Zq)ChxT=5dZ0cw74@b*c{d6)bkIQz@JNinKWCHGZXJJNJkF#-{zFt3{T8{rrTo@0Ds!^%p4aY z+8if*7!Jl_%ry!C$4sX2=8Bnqig{mWt2xZF5y;^^VvbivX3de!u569aI=Nl4WLE~n zsV2U0!aHN#?|n56{Kd)TWyd48fYyi~6VotjuRHj{~U`^boG_YuR%j3(yewL^Af8}Er! zO}vM(X6#-?)!;@pCygAJGDvBNeZPox!(i$ilUK$!lo$uF#$2KoSOJ&lh4W}*sE%V0 z^0898#82~`kzJpOH2QMjzZwUlm7QdlV>OWJ)U`z^sjL^F8vWL zlKwLIBNo%%ch6V)2bqub5A(pd^k=1gdg)(vWlZ`n)fG#J5~aU7a(my&I zMx?*@dB02QczQ6EHWF~fd~hoE=>ydj!F~=kVbEZDGSEUzv*%corEnUmY33YjvJ^){ zHBHBwM$;v=6(B}%Dt=Q>bfguPd|z69v30=@ck+dn_fK7INlt1~HX9JjC)sq+c+=j$ zyu#NP_^!~6`7_9`BE<8v9QlOg z_M_=(Hz0LjYgTw&iM=nnex=u>M;^!Ctz}zgzEOLL^;sp~Oe`9B%2U9K28-6!wx+2p zTArnVWSQCw7+d+!OQBxVhq^M|NCNvh5Fl8X#`?|VU`;m~wWXZ-hM4h$j|;UpGt4}q zy5iuUP_|BelVf+NZ{EA3o!C26+R=6zR=eeP&YP(^chu}sitv(~&+D%{7oqz2KEnl( ze#GQ4v&h)M`uJ!^UOKUB__B&d^--`I@mtoTk%VSwYzT+E8PMeuv!WTjjuR2n6LARU z0uI;4EALA0GiD*c&KSqjsHUbDg%t@G-bxMOM8l)eoxW}Lz7?G`$Gd(Mk^C{)2{saJ zlF?F8TM?IpAb$NF0db41@b;E$mnQTE((1MiuXg085m0(*BJ4`Rn5#PKVD~;Gcm5om zKD+K2&orn;##1qbFY+sfFcYsapfLoLm-gEqsDviP1TN}3Jhq3q7gw@26+|)j5O+tMUB&3cB zXI97I&bH(_8HDY`OmT8TAYGDDVj%wkVNSO5y~eGZplv3#1_BYu9NiQ>XC$H@M=YD} zcRDOr3_7RH$tDaPtpUqsH)mwh-YIt_v+d}%Rj%MDP8H9D*02yD$15*`Xnn4zs1|lL zvXxm9zIPgM`W>a(eT=uL_NdU%JyH&>6r4 z444DNCW!{cov0@}pYXQi2i7cP?n|fz*zQ)GkQ&@wPR9xF_l74t&!JPl$&p^lrlV+E zWE1lAM{-QX&LVb;mjD+Pb7t$aX5CZ9=3dEkJJt$o%FG+BbZAmw5 zJ>|R#zFnl+2326j}l7X)z3bw{|kIY!-RG|jlPJXPvuq$7z@DwH4dwjHG z9mY5vr~<{0PIuH}!v*^ah?pGRQUF`r(Y@T<76-aJvAvd4Pq({+UH{TdZg;ZzY4}TR zk}`$}Gl~s^NYW=5+kM5nx50oy%C~;I_fA&^@J#@cW;Le0a(C<57AVgCjtD1KK8KRRcO6OTdk*c0aUGLM$LlJ1Q7fmJw+V za(I=!SURxSzT{@_)oe%kGfnbD*Xe2W5!1?%D?tqvA+MsCjuU=Zd*&-Ig(i&F19B7&DVKEx zGtJN{<51M9jz5^Ij7GQUz46rPR~cu~FU?75uj<$G78rl?Be1|Qq}Eh&x&=nV_vDcc zre)~cR_{ai#{y$$Hf(AqC|D@Ln&hM}pUnbedEGO1az+rRFU6V0arN5bJ&_AIU2TcA zMSE0Bv$X{~5$d%?MMR@(3pwc@`fH071W#DJ-H*$PZ;vi35NeGT#hFRfmjV^7vZ63z zUG9nkT5YT-f(WkVg?REoSy6nYp3{t5Q60~?qLBQz#e}fLMi`vLRZM^m>=Ac`MTCx2 z(H>D=d`|VE4*9Wnv~J)H(g)ZZzh%n|xkT35^Y+CFn=8+L$#BO*e96GruPhm|l_i6= zWi*!zE5`K)Q|)ay4wk3(qP9z?Z><>DnVhuRf_O2-ghld-ab4EI+V~fB-$*r5fLDy` zmFcfCZ$d=iEf7(|)VVwl&5t9N??)|o#kk&}xF18~`r(JTro3WYU(_tSVq725lvhl{ zs9+C507|e+XqH``j=W+TRv5QZ+pKVmEslCu-mqO6ivfle~2r*E2iNUg_ooji=(FDH}$d(u@E5&;&fYfbQpcI zIs{5jbrefPJcs3q;g{%2+Zr-}OGs`*As-d}qrPpvpTNcdzK6IG?#j&jPoNuIRsVE!hWz zWXXN)9rPyRd3;HEM@O+Q{iK13GXYzS^}i6Xua;}tcN%Y~gZupivC_#Ga z_Z`yqD5T3K0qTHk?fjXffGI2}E^KwS6b-&?bGPONa@F7B94n9JRYfZ^#K_9sNmEJ;pK;C#sH^{`sbBIg`&~0oB z`o4uTSh|EL>Kc-C83YrKfY{GA?r74u`QuZu$&bYI2lCeX#|quKu+ehKsu_E8wsY++$ZMTLzF0@ z6ZXp>m=JopqAa{cSc+q@qAUzyVntaniE3;)CWIQ==ou%+6=k8`cP`~=MOhfe$BMGx z`xRD{g&&f#@K4K87EYvDKFPA66+$wwY@SkRU~YEcq?cluyCRw%vl^@@I zV37yRxSOQ?kiK*+aqAc{IKZh$-@J=>M>9t&pHzFH;JjIFWMMT3iukGPF)CW! zFP*-(zMNIhAMPE!ZYs^#eq`1lZ8Kt3z_$1@;nWk;Uo{@he?_)>rZd%UCA$jM_{Y3=&Cb{Bwcw0Xnwx$%bmzJLNtyGMcjzF^no_Hyf~vKp`|5RTK!tc)E~S|S9X4Rr>7 zg*xEV`C#_W<_f)bHH?_pTmOxSv5ap@Nez>f>m6GTdd3NRryaCr%jYm8rb}B&LK?T< z|K=3s^`@uk5swmwe`BvL*GBAhI5*sSjVuUM$~R7<+CiFk7xVh4 zvc)=~cTM-Uz8;WPTJj_>i|4LNgWP*FRbKNuw=bku>*Bu*l8ptzuJ;WIC#07~z@-Ev zW`c~<7Jh);bZhw;L9^z$#EH&6ePhwusX$4IF(bt_&p>(t?C&DmbbbU+7Re=^l-H&@ zx0wMg?=xY>uJwW{d06uKmA#{(VGY0%4R3oO+co4brsWAi*ZZuX0eUhxj200S8WUg_ zN%vTn)WzBJrkgoK_DXdL z(^Y}(@FmMyEYPlgjy>eOJ`5uq(KITTp zqEe9#OtU+>!pr}e$CvXRFloHb|U99@3*Z7_Gl57dBSW z8=abx3}$6$q7zsqPrQj5cumh{g=fxk;1s1qCY2e%XyPN@Gm<7&AMl?}icEC7V{B8Y4PQr3tw%;uRo+f7GrFrXta{nJNUzGo>Sd5e zRu(bCCn&eH=ks;JUMtvI6=ix2^YXMKKhJIO@z8Ac(V_vR( zVgk5^r?p|DpxyP}eLZ8lz)La(LVP{O77n1H`AlrY`kGVF0G`uylfmkuef40CSXe_E zN{iOj9H_baSKfTJ^R~!~lRai5M1HW0vArJYco2WYRdr;Bfku@&Zp0uT^bDr};(gDr z$T*}kOz{!|13Q%yqh_Q~Nd!a#hlUD%69_{3mi!7KPBiMrzt{~_YG=3D4J2ykws13T zwHS#isiXil;;4t-%8ZB_^r82R*eW8LZBm(QuAxK9|5VdypdF14V6<^_IL(0e4fLaT z-OUUT!g;%f4J2BMVZ~B%#Tqrzg^mp@3}tjenw6hMVmF(^DKxsV!M!w_UO@Fn=6jua zxpz7m91pA}onW@3@Qv-D4I4QpyGlAt{^w50|Ip<>_TT5Y5Adk)A0D8NUFgqrxSH{N z2%|Lt@w7=w6wozn+F#Fqd27987hkWbiHtjz_lHZi*84R;#={crV2Yp|_O(GxhW$LJ z7rj5aP54tcvg4}s_U`s!BBvPz|05DjB@H)qY036D5o(TcW6IP(|IxecX z)U^)wQ&z1NF2<8SSWH~Rg^$NT!a>`6dmy~Z&m{bYJ2YtyjAJsghla3=G;s#CdAli) zK8Q9mgRoOr%6$ZH3?nFKn?`WAkQbo7#J&XWYk-`M};bhS*%rW$%l#89%f@y z^>%d}qt%mpYdbP3>=PH?7z<0%Q#~_2!2g{ZdTdHrNdCL%GNj_>g*c|3*hLtB%BmTv zH1&K8)0URq9+8$eF4(}hB=tN4q(XD7jD2Zq#FlGJalu-#Xc9jg;A#O_RtHyUA1WJA zrSP|uq8GKiRdQA%5c-KcQ=B!SN!E@Nr*yPQwyfG?YCD`D=GvwN<%2ZVVl;{RXtmhc zt`lp4i7|0FSU08CJ~@rlZv1kOm5#U1fjp4|eQ67(aL)-GT|mpIz$5umEH91AOXSZK zh_MB<^riodx}*X_+t`Pmltu`)MRA2&G<5^C&6ftn*q5X-jUt-GxRyOz)yvqV3XGx0 zK2-WkBP}1-=V4$-Qmc*GU+V)L^>(C~^a9sXS!YV|Cj)#_@oGBjrV7 z5G9I<@QtDl?I2*wbgzknDYtNBh&w$yOu#HOIG-JukfbN=!!QL4c4TRH8)xyT%Tzu{ zg=-0UG{QqlTxZ2nQqs}xbpJjJ`567D*Mum%ogOpXJ^Er$gIy%#yN0QR!fcYTM0f zNUl{^N-eNVqu>R6$0sVh=IWwNqtuFF@c+H7%zyVvh>9A^t9&F;C1KbJD4(+#h|`gT zm(WG@b@kLtwaq^TO|B-|>o5YwUo!#YJ38Z^8!lvv1ac_PR-HT3F9c-NH3 zD!kGolmGyFRe~u#sy?3ltpOFfMaGe!M>P6nQ?-&uiP-7K*f37U_B+y$YiStY*d-ZK z0FL+>#<}!8$GPi!F(8R!643W1;+#(`!_@@P7ztuz1iEQwmZXyS<)K2 znLshoPuhEN&^E~jXHSk3Cg$`L7aKH1j*F5{Y_4U^{G-z`X#&)Kk;b(;dtC-&n>VTwF+*E6C<$P3;fugn#3L($YGfgP@EPZQ6TD5R`6M zX->2aL1{}FO|-U@IlZ7X5x#<4n}wEzT+KqJ#jxT#lT2Gd?pacmQZr$c1FKkP znT!q6Ujo8)5_zc~CISMOEAxY8tD)d?M zmzcx&3j@zY;T74)%{ddNaWgBkf+QcPCxBHFrT+Z0qYGU0(r14N$&fN5) zx|~^7#~zN$nPqisWjTW>=0RpS1kw*_Im7m$)Rc^4=0)&@&Cw-13NksDk0S^RV}_ZW zyWKzTtt@uH$E3x$y9LiUrM-M*vE!-ZABdIYvXHy7*nxbTK?(OK<*qDtK z*tAhwM*YeU)aZ2F?SspQcDv!_ z(+!1vOGNyGieGDNiJmQE zFd@6DXARfO#GcuirAw0OG8#K;%6R~WPo@)d(h(UjY4|LT;NjlMhMQ+%CvnP)9o(^X zp5#hR%NGVojPv>Ug%%f5i%-m1wfK}<&Z2^>32+OD_MaH(mxDRTd4{pZ)I9JdIIHP-+$;WcyUes zcI&~5z6R$98(EiNhMLi8nwm-=d0(MCys%aYQ7JG+@|MnGT=kU#vqCgsYCLD6fw!0& z8yvsH47fawuLiH-(}Ls22QQqLSxxvW9B%^pEIIxG8a&A>6W2D`j1QiH8uv}u$dTR4 zbP>BbVK-57AM?A1mk>gcq(9@j%&~k_>ej;Bzo{7!4Ke5@hA(b|QkIvFq0y>{8jT9| z55peuvK4y-{8ULW>D3mxh&nz&f@x9m04!+5Cbpn8O=-m*0n3=exnhs-Ri+8pA2N+T z^z9L^n@W4vgsj4gS)G?5Ur4rP+E8-NQd-lRS3mu4GeA!d7!8H)Q; z;G6sD0es0ycF>VCSt=KDf;^TI7rL6UtUZ10^PbV=l3&#|SMzV^Ck3)uWN08F*d+&0GB4O`!B zW4zt4=Y5s1VK;1cUtQhM{WaAMJL_#9y1fRtYr_+=pdi<5XT3H?621U^b!^KVxV3$l zZ6QmGy{SoBf^BuDRxrFJ-yo7!pe5)ua-?oyP_f50Ae4q8R`=P?kWTY6c|JpitSs_L zapj=pj|w))ZR6}yQ~d5UHfgIuD_+mGeD2uZEH=T=B?;XTNr+7>wd>qqMr_i;m?!3# z<%%D%M0Qnw4(cXhfl7FJ3rf~1OP#g4SalohFvpN*{kDjV7qxa4Mrecm$!jcl=5|0sW#NfUPdvAL&%1(MqN^39jfW}QztUs zpo37Wr&LfEhU?i7>Y@J=>Y3HkcCp&3Hq?Yco-StM@J=<7c}&%x0g&6O+Siig5&9BT&`I;n^^XMNR@L>YwiY zwU5c?vy82m69yq*P6H7(a}~;7Hpta`tDjkJ2+6H+B>!^*$?el4c}hsOZZe($$&hM5 zGIckR>?hkelC9pQk*wUp%S1AE{FJVd`hy+x#gu0N8Amek3CV0>gff+yZwR47*iO1{ z(q_v*;)udDP`L8r8AnMF;5;%WLwjQWT)8B{aBY`;isj@;N+jWEoCEO0QP972`#Hk!2R3{8{l4?oXmlDl}k_N zSNSHC_Ne@Nq(=(IC^Y#_>8Pw)h7)w`M4re-a6WeG@Nul+`#JIyax1)f&*5d z$)xwU*GYgA$agrU4<5_s!0=ps_;}QV_+YFLfgAl`f~pVIClHUxuZsQl<`HzU9~D;p zYIdZF@nv+xhvaSzi8^vlgE6@y)nJTuq#grxq&YxmBAt64illQ+82|i31ml07;v5~9 zEX$xA6Fo;IdZbGX3mxe<%N072dL*3kO6bVRXeyD4M>(MqHlm+~9BPtJlc6KOzFYhn z1?4$%?PSSQacx8LG&vM})a;vd-;WeOB5Ha=OnCq|MCj!X;jzepRJTB;4$xg=0zH@L~A}Ksq&d9JQmi|VsV7PM`=dI z>zUGw%y*aAAi1(!BaMl6%U+$ie_E&4Xl5YgY@%ht)V5?A6})2^(DW{87PW>=(R6r4 zBJl8EC|}cV(;KoK`r7?>)MAet>71mL#{~N}&}p1-ZqC!`NVTKb14=2BS~#aR`5HmUL z8iau{j56R?!~xfsSQ~2h{6?l=F%vYw#hkQcL7t3`OerSh_CgKE6IhUtJv%cw%ljIhP3P0K+XN2FB^2B>ci23oH$ z1a-4xsZ)(ZN8_M1Z9sU3QRluI`VNqBUlE5a6b0_^6o~F$(W?PD;7nPZdWAT9wup0IvLZq zl^it6vzew~nGrQd!D4AcYr#TgCRoP2Zh$3=S#Q6oHAvch$jkC}%LhgA2mZh&o%!tT zD!yZ^_<&he1X-AHU`acOOsvyDD{LF!S7^^LZk@g6vpXAgokukXvp%YVgS4D#l3{47 zY0t3jg7}=dyCGjclhyj#B>B3yZqnoh4K6IMt2GBLIVJz-AVddUGV?E_WQ~eF2I}d7 zVy7V9HqyN@L)8@2IIwP-^$WCZCJur(H900_m zT$B-)b@=@^Z-K08;(CAH%FN=JM>EFOS}j8_mGM27VzC~SutJte+^m|on*UuVK?$3V zzG!%M5pF@-zPyOg)&9Ey0azQEJLD-ddk1kBLCL3@;PCH(3GP&#+U0;WP6ge zWb94xsLYg1CjLhFl#1+Av90nI8yF6wDp6405Ol5H4{GSrRoI!^w@DuwV{#1z2#~P? z(=HvDr312`x%Q+-6fF7i?1Iv>U3WR=k+Gy|s!}!+`bop;ctQ%bVpc}%M5r{gyyjF+ zh{{z4W@W$v5*!(>J$DagwdDck$h_Ew1(AfEz^n{9z2Mll?_5M=0fh;NtUNID78Y^35QS`S3;i26J=m(#U_Cwjc=<|m1qf5OZ zYp}ImCQsFM21>&!Bz-7i^3ESUOlmwI9GaALo`X8=%#XVso|ydLX}DYS*Nmk@eSo>U zfyQGGPc;7H^w0{eAtZeUTk5aOgURZd#J3d9c5P<1BMc?-5G5ARsp&x;FCi7CpXDE5@XX3ZC!F|es0e(Yz=Yqk$( zz&KXGfUqqOMQ(=!$8?i66u{@y$fVj@g=?Tcg=VkvMwWQ90k=9n$Y&8}+Y?tHzn!G%sl-vN9i2a0dq@`#fw} zR()XRcJ^)y1A}IFBxiujES!?;T;DEE6N9I6f+W0?@s$Q*+QOi5m1;Gy zbUF;0yqS!_R=}W`ht=sDj5Jpu^Fx(a{+qE(Jl{nFe=21dr1Wh;@p`OeuTAF}nR&?i1s6Kdk=!dQC#!>1s zkAyPJVClXcVZ!g0{76R_lUzaa8-cQMpd!$-!JHGQWA5|>+Q8f>fu1eq&XqtNb4yUB zQJ3hXNtvK!0zKN1=r-d?{8z;2xHV$5pqCZY2Btp?)CLX4=yoz{71@UfkoOIT!r3pXXvqo=~n6){{!jS^+BNCgFkE$FO2&RCA-DxAjQ6Feps=8*9EoeCd%y>_; zKrP$1XSy(Yj@v9{XW{v{emK%M%_Mi{wj!x!N$;@wUWp+>y`(&ZQDj7-p%w7pL?3dL zeT3`GLeig|s75L*V?>F3VsfOT>6nDJO#3z)yDm%#!m+Ad+A?Ui*Il*LrEFK_zd=$` z#y{H$+GX>Jt%P`D+U6Im!tVgCyEf53C%tR>=)c*!H?-<^zicJfHcH0pgGXwpV%tuP zMA4a|%)aPKQ)c9kpvHx%li!n_uoUnz&<47wK)J?EDs0x7z7i7uKvl_eC~oYp4%m=>}H zX#7>}jGhXRa-cnT7T0Mta-;b)Z!8vsjHsdrMfdjH$>T08Wm zpDv)I^N>?Xc+VJwPnz%9GYar2R9~LLU70TA_T|m?rSZxczsySBrY^p(>LN^?x>{Bj zvC}|dlH(lef|D(^9 z1JoXjoCpG1tsppJ5OfRz_AcmTl<~nIAJp-o8As=MhsOcP6lkB8Kv6-o2O3Nla77k) z8WmBU`Xd(K;pn#lUG*Tb3u2_*xdnoX-gJ97a}G2S1sdV2iVrcC7+Kfi#atg=R-J^X z(4FvJb%>o=zWlxUx;`NHvaNO5L4hImXg17|OrbD{NQn$i{S1YTrjJ&IjkdMz!|QA` zu95V@M(ZLl8yPHhRkztn5egfh`^k>57fZ$J%{|qd4Ul$Mg$>{rtHK6;VN(sk&0z?{ zT}Bj5VA!h?3LC%>%^33LC(%k0pHG00yoWFh@N`$pnefV-uJ?NEa_` z0HbqGy|4icJ10V61DI3RE;w%z)XA!_0nBj+W?ujX@}M?GunEk;s;~jffvT_p%pFx> z1DO3)VFNS!s=@{^aKA9~oG?`(zQu%1P!?lZ1Cmo#74J0wIT_0ua2$_i4KR+zvIZ1z zyr9_bP#mxpx7MV1hZQv1-){wt#`jr4qvgF;&}jB%D`>QdWKo-T_AZ)5jQ3qJeFe+% z=~fggrY~t}t>0cTePNDe#$GXfp;&{571LMPiRz0fU-~tT3oE8C7U;ufZ(jtTzg2O? z^u=<%cILQ`X2tZiV)|;B(teyxUoZQSGktw!DqoH1tGQV-TE5({-}`1AE6V&#xSyg$ z<#Z`h-Ocsh@qD>yx$Jp_VCJff%nj`Sma7wk!%!_=Pcl?bt62}>4OZj&KGsOZni7ou zbiy!W)ibm`&DQn7tYR2bGr|qJIMU={o7KBn(ZyJd)lx5VQfGLvixr`IC)YbIGD+y2 zt0-4hT^x3LgGbY(mhg`DK57GReOzOw6f5FE=DNgU9~xH}&q5i7u5g8+d5t#OW5^|_ zVbIeS{c`Tv{n?^-Tc2az^Bu+PpsQ`TUErWtvG@IT{LJkfT)=1RFflLu)2H72p_hO2 z+WoJ(hPbhAaRL4nax~xvn2rWXQZ;1HDCzpf!EAJ*OoI=P#%vaWNV*oW>7gHMbvEHzx}@JV@e#Qm`OFVr#=wPevMLj&0nX--HZVRX4W~*mk#zqjf%xT&h4V5%XWZUiTI6pHLYj2T8FsZ%gEp))2ms+(0Tg=e zSpfhy9S|$U2u(kIqebj?52vlvL`)iEVGh^!^@Z6!&L+o*h0>`*F{weoNF%91mC_*V zF3j}J|7VETR}PD!%NrRAWLuYivgdo}F;+|uEboDchzG$5(nuzdSlR+pdOA9Q8p4!G z1=C<<-uRPNIu(5dTd(ZnUW%PaJT(67dIBVh6(F9d(U$=vs^L{{v<)Yzn4GK*spUmO z)O5LdsM9EdA=(J-SX8v_iamB<7};fw z!1WJIBZN}QMBXX;lJIKe|EhZO*z@cOU5EYXT(J{Ak~AT5D|9aN!4*Y#EM{NSFdtvE zn9Gb0W!~aLi@DVNQ{5ADsoBBrjZSEwd-V{PC4&c*)!vvQV&MHOvXqDHBQ{_u9J?YY zlfJ}$;Q|a)RkTgW5cEecEauDt>7cBH_w({M!g#dHzKsWBML0}S-UbQUzG3$PNmGHk z3~2Zb`ToRuckYbdU=L#oNjW%%d9=-+W)ahETL$fh z(7;*K#>^dyD!!_OhG2H7@sNkPl0okSW>|y~{o5MPAE@z6m*1C!fNuEAGz0TbfVS#E zlm%cDN0s}LyVr@_T$Wo49yBiVxc!7EjD7f=X%_n_e zAr`>p9u;)|WLWOC!nUe&lhOCH$lIIMiVbOd>XjgKrvgCGjcxj{Kd2p2BMDA_>YyD{ zF~K@T`$|nMnrqmL*;HN%=|!*&O4-H9oHA2oT4{tRPAZ=&*X#dJ-#8#AA5#&xEjBeW zmKQu@WABa1(8mZG9QDQu+99>UmENLuz8lF<&jm_YKvFPbR_xP9+1#@wne(aZ|7Y** zVI}1coU<7i5An+fC!T$>E%7BUT z4;NL*4Jv?otT_a=|+@=RD7O`JLbU`Tfozz`s%!S}VZ6;*d8nG)n?ma&>Zk z6&?OJT0)_#`aP&Ls6Wv9esr|HKWw4JN?jpwx(721<{u~w|B)&=KLmy0FZX3h6k&az zmc%2K*teD?_T9zRkDRdnE2RFs%%-Fh>3rN_WX$2SuwvB1a&mk!Vob*6fa7H`nNgYe zuG0vl8syUmQs$1dMhVcG?QbUps+^1O@GjDpj~Ya2LW5Goq5Gcc$j;^V^g^q#B&(L% zsTf&q0PExKBdTpBdqjPYGQ3gSKhV*0s{z3wASs#kzNfvq6W@vWpm6h9C5Bs^0x0hd zi&9`G$W^ftRapt0Dj=22%Rt~g+9NBs_nSJ?a{Jc@r=oyXiLMDx{|`U&>e{?s z3In$_Jn~2@NCAw@*ZOV#jCR9{Y z8rLF2LQH|SI26gtgfbb}piIFyC8Ru?5JI{q9*Q{xh`G+|_xDai%N)$N$9mTc=l{DK!_l!T=NUL_bASBeT{9eED)!1Uziy@+d`HNp z@#MKfEj|!P)Y4hYhE(e22p;7#3Uc(c_YZXTkk0zN+wuviVLmLN&Z>FT3&?PO(g`P) zdk?ja+yCuZY)WXr2fB(9IZ_(ak}FYu&R+B61R3a#6hJ)ygtH+(h*=ixw*Q5rvbiKw zb(rjq7_#x+zU59HZ59QKlSfXy~Qu z*FoCC1hA6EJ~JIKooeqlzRHS%2Q=>*-EueZDPwZZi}C@25;D>)cSviee7AR!*kVl6 z^&7_hG_N?QxQv5#e9Ijt5@~YNYG5EztUFQDfjU+9mOKAU(5mKN`K$)D$broXm1mN` zRk5#Hpe0>Ipsv{GT=lL86|;9P2T04+tZD5ufqo2IUzq->x7?*S^1U!xsveq-G$e>wl zMyp7+PQ234W2T1?!=eY>c@^{!x7>*Z1V((F4f;$EabXst*Up`SzE@d1gJuzmqUp>y63Ux_;d6UG zp?qPYY1j%wSjj{OA0Ula+-UZ$kp`4OHnu1}h}PCdTLRu6#h1m?X-}qjyzi?dpzP{~ z!6bJ50mVNc#lJ_3C;9Egv;1CGU$pOurq)85J65mKGNxPZ5)VqZ+`Ye;5V{u3c3GEs zYp}?58_65*G=zwT*k<4SEd2YlTkhC#u`&f^AR<#(Pg;wfE#JlNx3~YBbbQM_tOt2crp7MRnp&? zz(EXKUr>gZ3E<#IZNmF`!uzWyy#J#%VV$7rD|Gi(Pk2w!ekpzBlapQJcZjEi-=UDc zzwkR0QYN6w)ja!M&3;)S4e#yyoS?mCp^$jZ(v-1lSCDipcjDJOKML6Xz|+sVhhGd- zadcCn1G7tMfx66Lu=i{BgUAvLMk>2+Xh(oH-jg8E#eP;KCIb52qVO7XtfE>E-_iUn zU+fp22lAt7WAOzJ+?AJt%Wk+wVegG!#}zXktBs8;YH>uU#k7#=@WjN~t)8?-Cl5!+ ztoIign=MJsYWv4z+!uIH^|Pb}%$kV;9~;Fah2aO(SG(2#Q=`jlLK_W+B#?%mC2_`J zlkYE(hM#2#q^J5>s<6fzkhc9S6<(L5fmHKT{47<+&yrSXmgvn)>jCJkC|4?yuntq+;mtESwiuH1 zQuZ44D~~|mPZ@!H*VHEM^K>5Y-`z#aE<7M@$mp7|m1q<(OpmBD$ynp8b(+7)xTe9TV2@rwZHw{TRoX# z47EQSq}z^Sw+#2!Z&kCA_T0g->P02juKVr|0;$LN{rK>b2=7KK&8*0b6o%5_D0*q$ zQ3S;@N$A*#}LX!DGX0x=>3Y-ub^ zkSo@wZz58q7KSiW$ey7Iss`S_bns z$^(Nrr)Tl->Sj59N}x+{|7X1n_&;7A2CaTy2jW#iI`M0cvohH6pYrQZQjaiY0w&TA zL4R?4OEi)?2fH;P9$y~o_W$D;qUF$&&#x`e2$U+1gpZ(|_Jz8Pwr_Vc+)?i4zTM4b zXVpKc31FTcFX1yYQ@ljK?QRx1#LJ&u31>Q#yIB}0ce7$ibxVaNx|RW-_{-|K{|}B_ zU7q{z_S$oInB*YQJ2r_>zdzS)ctj%oSg(#defo`Yn(oM0ULWt=h|zPso_6)u=6^yf zcHP&5S%3bGmo4u4TKE2(d-e(dzUl8vEqVna!X#cQFPsiB4w%#`lIpFH&n18{w9}EL z28-ss=lUCbVd`XOyf}a5d%t(9=L}C0cm5^!0Fb?uq7Iw%7$Hmk7jOF305(1d+am!k zINPkh_fJ0;VL%+5eo|Mu?2~)%&1v?2^A}z9H%hzA72iMwoW;U+I5VH%QjQzeFAmJ$>_+D1YtE&;1V1rE*%i ztFsy-~Jt1VYj3n(25p?gu>P!omuSBd^C;b zov+Z#>%aD!c{H#8{syCa>tFqIx5GG6JGZ?ct=UQa>d)QG^;f=4Bd`3??|-rXSt6qe zi=&QJ)rD8As&2u8>qIJaN$Ght^3#>0p4PUxitGBVzw*_cDI0hZNLpPh3%uE@`utZ_ zIy_mcd`TD`Ys|c~A_DQPKVTt-0>fXtkQYKxrPptL=Z`)X4Yx)}9CB-fC6x2O;FgLs zv{%T7>R;03q9UVOr(!Ze%N$2u66;%$9amGyK`mGK-~m0zpDQ=^{^sBEi$Vvz&q2DW zt=@d=liM#6au}GbfX5Aj^f-5#=a`tr?u$tj-d-*y;emyNr~AU%CQi5JmlCsRB!)*b zIaSP6x<^GT)TO&`w(0H%!_nBM^Xi1&a-YWSCL_0kEkZ4WM1^(#WBpNVDZj&>oDkW*krTdb6F3rtlAzipcF<74MZ|FD&8P`zk(A@tE$_$bb$hoE|bQXZlaM z1CSO}c1&9ghbxGB(=&9NgS9v6V}*$C)<^o-uMhQ6)n|lD^7qzhJPalcf&SgAAL7`R zdZOX`NnRD(<4J$>lln$;eDow$`UEu2-}%?@*ZD{0U;a0I?)_o9?uK1oR;>?&s~2aS zFzG`OUPP75U{;bLM_jzfMF9lwmqV}F8GgHB2q2S^4|Qk)YZfX7#r;lkC>s=4onn*~ zu$|&Tr^R5KIU)yTg~g-{B3>adCkB0$11%%|AszuX+50wfe6@# zn&F*@+a+iCE0@+A%=8PEIE&G~4mTQhkme)7Wh{56N? zb#5p^KLa9K3vMa$B|@0?6hYf`;`()WMymFhvkv zcqq-v>Ah5ld8a!@Q4DReGSR1~h2Le2q7;4yxiCf{HNOLh z{@op;07ZQnqe+4>!Zs#BxUE6Ke{XWg6X={|qiCA93k2Wm(KT=h(yfAYk!f(eOi(d4 zDR3?%3opw<%e;(H07Gk4kjlRSM#d|C=d+fA)%j)`3m~UD#c@+ogKOudr*+YZ z=l$%B+1U`Fy7F0!E7O^{pC7q$V|I?w1TQG1mv79t| zn7&PnOfb+3or23Z>hqlfSn#<{0bKBGDgX_i8r&KP*~c2@Oy&Lo4NS`qNaKn0W1=^n zw?G6lMeR(?a~FUc>?pOOeG~ zm+lO)e;Q%P4naNqbIMR2B6mlW1(;8m>4YaM@<=+6tidg;))U4Iz-%Q#XUHrzUnMGPF@@;;g%i?kxn?P3xfVYo#FhB3xZ53SQj3|EhJb8K?P-Y zO!p>MZzE@Z*wbtP970+{G&$z!TWDt$!a&?gEXb1uh+B#I_%}doL#NJw6BPs~Wnzp{t+Pnxh0en66blHK1t@qk&KikkXO!Mu)n|=+8kBHQ&}yS$E;kwuZ0pg?u-40b zF>rSnvv6=jZek9yRYP;(U2O^K#*!8fL0PuwLFSGxMFm!J%-F^E`!v zp_Zya;h>Q^;h=6J3mnA2QnSN^gQ^G|EER!+st6p+6&f3*!ogf592{c6DJW`&Dw%K) zVYi^@jd(0;b?m+QRIT}u7-u7gGUn1~zWG>J8EUj`T|7=k^`WoUVDsUgoHKwoV=Z3| z24uJAziWrh{~7M7)oz^mTXydJ`1~t!X=Ue*G`ps$;r%sLpP7&6-@SL2fBmt|UHqcD zxh(##UK$q<5h>OW=pnNF%U+`I=*ZW*EzHot}1fs!%5@)>y=k$K2Uw97T!XXfQj^0kyfpmL~oo6y#$(ynf{~p_5y~k?U@oS49|7MQ1 z1=4TtjR^J|f|C?NL0C$rKQ{%d=-b|pJZj^ohl-a_O4_<%&T483H)mT~fcJdN>uJnd z(Pqq?wq3@IHw2wIE!ran9tWlcl+q~7gICDtRi1~R66S&0LOuo2zlVbqN+r~vku)RL zy9NS*?6ZBo1>VmNfYIzQ2$)LjJx=>`C0~zK$>u|P6NB+=s^sg5D$kWl?A7zBQl_ga zFB-oGC zjncvDKAgP@ z+0kdGJgx^k^5gI-U=U2ler4Er73`R2np6D8cEvFg|J=wf*lcjK z<|G=i(=b>IzeS%Gzm-}&4SqY&s6gc-Fg(9ojUVo1uAFrO{7$`csK03X&*YA1GB z&#buVRhrYZkTrE`(H54S4RoZ%EItq$xSR2q__Bf0uRko5-k|r8E%ubvAFhXD&{gzU zMUVLHQ;$}cTN?p(wYK&FD)rmi29WUKcfqU{53E0=$zVH5yOkqa-c_MTr9s@BSt=)? z@SY7PG2=c6Fx$#PfsIQq2W8_dmZ}&oJIWfcG+l|tns@Re5lSG@a>)}5T>;)BNM|F| zGus02#Q?|Y z(^76(lb|5s5QOKYNeBWT5^FPp=xx4u(vvoJ%;v(2;+$yk0;34L=(;Cbcrj_=h1?SZ z;e|q77~TrJ2=|0nI2vy7g16B-I#n4j!bQ=p3cSF0Z5P6%kf$i8T{p#M@wPr*ysA&s zM~R!&^?v&1-NVb`p2>uiApf(Itug*gmSVn9?7i{*8EL23d&u0TDJ-b_F&)8~`?B{K zI()a6?kPzGK`>Xo^aNg#u0)aXpo!b$eWQm@Ow5FfE%=%YVM6@!B`CM~s;dBa;92&W z;~RE{WrB-l1g5`oHV zuwaKK@DYsG-6NQ-0y*4gQ}P~Di85sA*3EiT`$BTm;=iEm#Ty^%vxP%TK;GBvK(+Xi zvKAmp)jk5uxgK3W6v?3%1ZuCih+P4bG(<=eJKrN*JA<2QAS9M_bXQA%iRhl#1+$NF zKsXi?4OvXn>xLI2MW+h$NMn&58g0;4r|n$sw$XAOrq$ZL4BJ9;vo#^M6TQQt2w=od z(z9ULo}#tkw;ZD94$wS^`VgFSjm;D=YyS-8Lo>EVq2jeoFCm^@K%nasYSu1vT1fksXNwYdc@cpGNtlUP~n(q*)rAfCxr>8OpC$fg6LRVxwI zVts5u%Qsd9c>)`$h@3W9_t}HtZ|uPcsfb;WUG0cb;F0t_;H>56Ne_7-tAn9$5RRtN zXVj7@I0fHQ^_DQKVuYzRq>*A>_}CJj4(c5Z(XHy!t+j-bdQ-V?U8-u)59rvh^)g@d zI0kxXESrvOrC-hY5*-2poxU-{GSbY+N)t&EK}VftAuLFULa_v8=~+WRYXwg)XaZ2Vv{Ef$%l{%ra1?r7LE~6gjUX$dZeG|YWi*cO zVYrJ+%WwjI<|S!q86j*7tYc}hsxhcXp>eFs8J(6^6G0PYXM&|&XKB~xu^*xgrtn2$ zMwy2vHB=R`w51}JRu!?dxuQdFsSy+n++~YPTh`Iy!fTdRG&9J&W(b_dTEMhXkJ4?(?*ieEygDa ztyaxk6n`rjc{O$cI})0vS4n8SoA|$^eMi&J<)N}=M$#bQ0@KJ6`YKGPBcUaoC8bZ5 z&{w9G&{q*B`1~u0*JTN<@KB_)By^VFMFq2jX6}gP65HaR+w-^XCZU&Cw@B!#ETAPc z(iEW1c8Y}d>Kf{u)s=vn?MOx!3Cps=w&_HxX+a{iu#AQmC{zM3j%4)HlF>Ui^r?nV z6VOlF%;nYR`d98pK%@29=tj&NGr}PQ5@!Le)mO~8J~!BUQ{No{jfipeY&R+K6=SrB z=B0ay=x%!pB6 zqa@pGTPVOYTKw54Ek8wmTJE{08wt&``H3ajERM*6+JTy)71SzPcT4ROj{w;gmKE8o zWnCegTWVJdRw%N$x{3OjWwVxbm2eiBtQ5|zimq^ODvEG!inOc`C!C*dNz{iE&M>wI z7tZ%->i^-TB!g_poDWdgdWrg1$YQdr z@%s|N$O{->h~|a#A9Q;$EKKV^V4WnnU)OrUfEmIT$d>~DsgXLw^3X z`8(R=oqw-KI4MuONj4#WveD%bdTkJk%w}VU&|?VE*jSCRTR%wL8*_s;2;v*N4QgmA zH$&eZA(5-}=001U#283fFWq9{Dz*(Nsb0`1pd(L-_?3^ z2v@{EB;88j6hvZUFb1p{&?ZqtD@Wz&vPGZan>+80s*I@s+2bY1Mw(M}$^x(@$X^zt z1$0IAYO63W1D@2K>-8_!lg~MwH~?^>ionQ(IkRn%18SRyLxy-m6^9AX1uo~oJan4PS}lQT18YiKriy_VQG^z# zPo%l1LWyBUArn|b6*yg?%neh8`)qXr_{>Itn&xyC-jF-9Ns?!CR~<5A-V2*o`UZVTKh#hJ&`j?D&8wB`_pyO# z0D=ski-(?tzYo>Wa0L7Bs!P_wZbTN&E8txst$^GvYLgk*VFp6kHc#>&_)w4AWmmfa z8k%;A{+K4WwYDud-GqbVPrQB(kNQj`7Rz4QHMC~=k&mn$pobd*aNk!P@FWse|5T$)rW+g=9RTWlfbu|dSl-14UT2;pCrDk>ewch572Q4&{+r_IZPP}4uVJm=> zl?wWb)in)>0podz)!kj#>)G<^CWO)I_F3Jmw0BlF8qR(-Rmu6{CCpVTRyS33S2sVu zdaq{#`ftmF^YujHU?T-P&k1b-#X?gZuNtFm&D2o^PLr z;H%iT!Tc~TC0B)aKqbsMRv}+x|2AKfV1J9R$!@vBSMBF$N9J~wcVvF09!xmB;5e(4 zw;o)jjC~pe=f6{yZHf-GJY~@zUY&e>xJsSG=_Lj&m^S2=e zz_&hE_OLdvm1vEPjM4BE(ehAqJOf~N6ugqk>Yb;01OUF>uXir@)`&6TBeIyd)0b^9 z0xQ%=E82x}x6ulVp@^<`_)|6`Ya42Q3<>wkmsmHhb8sFEIvd!l&kk1;bwC2ym;B#I~u!#i_ z9$^x&-J;d$^}J9xh-0<?}=~Qw!3B zj|9-xgpY)-tqC6qnOhTv^BKWm5;;iEA%#IHsw38Koa*>`rl7IvQnX>vfujwZ_t-CC zkJAyye9fs{(cfjQQPlA@=Yd7t6(nt{<7-YD!+1>ahCZMc;&rd_6qLn77t8crLX)K0 zm4WgM19)8Vbcwl9!pOHvAcWsya!=Ib_A~5X*Ca8dx76!3;=sZvx(tIYHWm1ud52F0 zs2JPcbXqIQadY})y)M1SW)`RIl#EGIzTT>0cM3fvSoNiBW=-5p$(cmcn(l;OnH8Vz zq}t+uaLy#D4vub2W|n^v-MCU(VD+3LEj|QJ$;?8NYDo(sZ$e&t#3(nze9GLVB`*kU z%sfb?BG!-?RY(jzBr(XrtldE2fP~9{XbIF?!KgCaV}cKRV^#Na3OrLY4(q{Krf+?bI_8`Tj8tL#AOiK$*X zAQb-`Xagg_<%*04F|r+4*$%A24!n>s@=6A(0)HjmN`UFPR8XP?PwI^Xi8BQzP5h^4 z_H}0V3)rBJq4en^sFcdEk$vjvPJR;cr2Ruy0Xe5yzFiW%PwE{r{|{weSP}2o14-)X zGe{_hJ#Kuwr?@%5>!2DH3%oh26Co%=Zv{!hk?1g)x?0eZL^8s}^ocRqhPm9S7jTqTcg#y{b zD3d$P8weO>eVg2yVU%H;hRJ>DCK{7Q;lNCq9KewW$>f&M)PA_BC>quUCyBajly$1Y zDAQXqx!YA;g3L`}lo18O<7{}e^8}BiH>^-FV%Ji*B)cT?1VuHXnFk~gr5p?S!K&Os zvv%E8H<7hgUAkc#nVnB-{~`N@$}lJSZ5|)A-P(sueKLg|59u96_z{E>a(NiCcnG1`jMIE zb&Q6a)sNh~PE}t0$j)n5#p)C3(JqAgz4{9odKXKe`eUs?%&Zh`m*91>DiW>LC5%1m zJH!St{q?MQD6Ow$5Z8fTijhgdjjShLo*tGkY{`tyKfc?T#c~xU^;W@;LO-5X@M8*d z1Z7SSZZu~3jVtX)$7gTEApovHNsNO4!pgptt!#qguwoyT+W{4)X=-qv;U6EmKexk| zj{3XV6>tat*Td{Cee21VI{;5Fo0i)8gjEcEk!ox%MWKs}e&-D)7^cs}NE=M?(;G~; zpIq_?H2H$xdJ=aU9)ZvEDK(Q($fqYAk9o%@9*mJXk8nvyQ2F=ttug4VP}=HaSY zfAR2((IuglD!6DX!RDFjn*(SE>RYlGQvz*g1L<2&#s-pPAQC?fUTzM88`yhj1{Jep zup2QJMfiD8+xjSjD#gu^@X+8Xpo0YEFAoG|U|j}{PDlymr9_s6Sj^|aRBssdW5Z|@ zro4sbzRn^{@F@3f%@F5XHjM}b`sS1ETrJSdQ8GOty6qLv905QaE0B+aT|i!}8KOQ` zU^{%ijqU!)L3k@MJ>_bx!1Vou>1_J1!t|ZfFx?STo1_pK)7d{|u3OMiV7k$0cHm#a z&o-_noWTK>^}cMJ@%%Ozd*Ht!)zlq;?R&3C zK0KiiPe~|Y9X!WkAfE}2gzCW!*$Dc#iH*SDun~mT^2K#gLWF6;v;2%nD*jcNN=F{* zhIWiduTS(RYU7bgA9`KXs9;GEEhA)cF;ujHgcUCtQ|Lz{$go@2@V$9Xy?{!JkO3@v z!aJ)J6(zQ`l&B#$$?QxhnWjYnO&>B6=mpC}+72N-1mbo`2q=cogb4^^7`o<_V>mq! zk(4x-vBGm>vNz_xtFc2Q3gO2X0^L{ux{C#n<^sS1Ok-^(jIFn(GX+pzsYi3EZX)3| zcj>Kf(4^>YGwH2bW$CRn>^&$}b~EX%s?ugcrz$iTRY`AcS80rtcMGMtFjpQ&Z`BO* z`4*@X;%&=&MO{v(y&{;h5iuC7!@HgB7h7=&WBim^m^N1Yg&Vh9yvz~THgTi2y@GvX ziG(KTsVrFq*v_`4mO`!SoKFveII%%zrzn?ODFUg|`m*B_YN>}SFH;H7J@B%64Psfr z2`?+VWQIP=s#cBmt>|2~{v^+dw4k14CGdJsV54Onv#jG1p1YZsl{vfNaS71n?O3~} zDwb7fl9shp1?>mwl|n5m_j&O+%Zh|e%erH_Xc+(bdc;%`=g&Jsx1Vh3RS%c%1K(~` zw9Wfe(f038MPulA;H>7hQH3*FlT`i&Y%XQ?e4VdpkMnDMO)Bqed`&8EM}j+=JGPwU z;=41>n?!$fey~s6(RS7hZ$0EO60LCIj;!oG%weOi4wke+tSvB6os!C1q6k2^FIjyWF5G+#FE5|T zd{UNd6cu;O+Wa^b9XCV8E~@3TR$ee^A{z`rDLOj$;p)tLEjsbX5GY#@v3TA zgC7UUQ71P@!jBD-k!JXLj!*(!?Hi;hK{&wSn7F*QzW@23aDwRjun;tJn ziBSwH&UD@*ABSm)qa63Mc3b#}ZBgyT>UliXI`n}Lr4i1Kz0V@6-iJSEDP}A*Zpv9^aT=K-;VkTYJ-sb$|L; zy)}KjCP=K=*C>_%D&m#)w#L<22_6egzq6|`X?8Uxp(-}{Y~Iztqc!EM#vDB6pTvu- zCLoy6F5!eilTI@qzr(jY`w+Vc>aBgnP_qS^XxZ{VcSDmTJJl0`s1`X_8tXA=30+bPr>v?69$N?|@zPcxoTxp-q^63li zoc=_@X-TpR8(H8Lp$@OK3cZA~l1 z%!zfwI$9a@Nn<9`EFAd6%ryu6p{RADswBE(2nk2sY>uf?h4kfCMQF>akha`ZbPzo? z0>fK*z#pMyKT)r+e-<3~*gt7~`OMfmz#EM}=U(f4e+bP|YEhwLFR7HImc)^Tj%y|@ z_cUQ4p`d~(t7ixP25MY4>Rjrq4&r`cdr?QtOGKM$m z>5X}3`H_QyI%kEMmq_tZs|-|H0e0}jcJRe8n5w+|1D&lWb|$u@<(K5ClEEYaAIr~i z$7;4p=8`I6`AbDCzbaz+bA^_lQjIMaN#1elA&-iVilKD2)?v+(oI9}%$+yk$iu29< z%nIZveDjFZY(2e7_GURP;o;)ykakT|kN&g-Z6nlOEKfF4>>Q*667cM&V)XQ6{Nwsh zmKAI{Z8xBLCc6qN!aL(EQg4n1YgX+a>@2j-L%3DWL-_q;5<2=XZDhmhHn*2NjLZEC z{g%t!Y(IG+aZ1W1EDt1KQ%%?3j#An7K*mq|+u!1)QxiJAAWx4?D+k~)f-SgdvaP6G zpMMcyC%??#Mad30-5Mqpf`%$^Z-*LghC^#Ax7DnHgu1N;N|J;xc^$hsuR~2@IuV=- zcTi+@_NvM32XlATqFydGmA&tb#!{QE(-3BIV2P-V*;hhR585Lcq>(7}PJTjlje7%$ z@v%O0wauiU1&zctt@9eB(QA@fqsL*T zop{4dk875CT%VeAaqgu;rN3$XOmI^GZ_R84gYP=HppngIs>{Xn_(ET{ho;JM2ISMc zaR7o@-DD6_*ECXl*9K`l^teWfQrV0&FT|LIz=fZl;dnTd{VN*yo(AqcKAfQR{TyIt z`Sz@8>DahXx^~3lJcD3TGh(%M+G{Ma!ndm>QvibK!*3O}v`GrX1kSdcBtmq{ z=lkK^RSRBwpIg!6^~f41=T?9l)7?hT-!-)@CW)Y#O*s}f>-qkk5$wkhgC*w|z_-Dt(z+8|(^@Bn$8#PZZS&uFJ*G1qk<62=>au9o@*G_Lu7woHOYO5@}3OTLWnY`7|1NC3jb@ zq;QLBub>~-ini7fIuW3@>n(=L)m>^a7F+HRA&?jPP>>x2DzQpR9Kwa7rJ5av_Iu>j zR8Lyf4H9+uQY1z$_iDq?Mai_&uk|)x^gO#`q5f`5{S{jmF?N=kO<02$PTpGTWC3k! zskf~HAA|}Fnu7|l)MEY~o0nQFIp>vVCDKwOfz)m`fmD;0y41u{t0paVuF+Cc?D6F? zslnKJJlt98t$II^s-=l<6IYM4`xlX!Ak2^wuu5x7WG*vLvanWS7y_N!-yW9KLLn;hjk52@0A z>pe*-`F6ER&}!cZhuXKa-PEYGjG(2`QfZkgjTZC=4Ay7~BLbJGx)LhwiB(#>@ls^b zFBNBGO@=?YEUCGl61lHbbCD9#az(GUeN)cQrnV%c<!yrD9D%F@%yFhnETVSrgD23Scaw!c8POJ;4j z_3&o0Ku|b}QtamizfgyFJ!R>)NewQ{ilXu?8m<5kYOp>9l)}`cFK8j!YB00U69nyx zTAbA670i8=T70Fb#owx=77GZ>1$N6)C3RTqmKAr@;b2=}2d9g8#1ckJBQ7hZcxybW zWuatC5-yQmk~jUS!KXyH2U^el_=W)5)3>ZC8x>BhDIaE}nCTS6xGqv&blyfiG{W#r z;dm);$O`!E?8gTu)KayP(}1i|nP+YtC@O?b zY_2H$VyqqdV<8oGomY{HbzP35@y!??jA>Mi0%bTO!- zvd3{IJPg?}WAX*8=9s7q5~pnkc}gJQ@^7&B{EfN3+)c|)w}gXo!~w8lb$2cMxWsZE zcKzR2)hFf{mGo_xfG*o$-WQ|<%AyO!TgxAr+2=$m12KZG$}O$Yc!823RolEm=l-D+ zg{qpB80R>fV%*^27Zi)) ztb>{MhCz($0gRD_mUxwO{RzO}Z8%uyVV+vWVC9DF zq;Hecxu9~hX!laN@j)tfV>9bvc%mDX`*m7uhvbO)NDnhItW>$%HC>gvRU;j$L8^PG z+~}iM>J?mhS>+}M1VG9fLUeExcLP<53Qk$o*6IuQ^vSkzBQT5wy2{1OR|z8U-1H=G zHX3*4xy`x{V!>G}5Kkx1TLnKCy7&1svKXPp*NiSB9oLZ=@g1rI1B8p~ZN7LuCuz-- z?tOvyxAuZFdoN7dS(ZKv_VtC;k_JWbK3Pz_S#XiI2R7G&uTs2?NGlcZc1>6DZq;bP zt$4S}V4Mt0d&wQeo9l)}QLwZvHn)<}BDkNZY*__Ik8AYihf~3k6irk2tAgVNxt}{( z82JhnJaF48xK_Tcf=fr!^j-YXqJm#8DmWfxVQD;oX6|IB(8t-rzT}(0xBr)OMIT?! zE@tWD!>CvI-UcV2$O)=b=`ml3X9j(F<)s9ib|roMxBL2hrXtI1OPi()0j<$;nh-T=$=(RNg1W;|Ic$0?VguPD@oM!!7jq*BfW(RsZ@0)Db%ROmg_&Vlm_+(NtH+;b= znGSEDPxe)I)hA6g7X~s|N_mOWwItw)PNStX>TrYS(I<4*6>#>6G(Mc- zYJuRLzWSv(*3TeGQR2FHT>kbPOEXsfQ!936thQURGrnQ4iJeiLj-i+iw_%NJ&`5UC z*F!drtd87v88*2w?(x`M2!|*YJfa0!V8vJDLkPoqK(VxoG=YxT9;%^~v5w zZWTn0!WnA4=EA`}nv1gbP(pG17>W4i`%;=ZsrXUHH|5Nw}_Zw*K!FUpBU(89t;W#hhGaTldlY+sVyCengVg&fyXpTsN!zlS?C3i_- z^eef`$lQh9+!l8s%{utY;{abo=DVi4{Dq`yU3`?ePTfx&#-S?mDH>}Cum=h_6_h8; zVrCBGg{D~tVZdQzw)?g@ahS)=TSU8E4kO;8(!yc-pen~WGVnjU z32;iWG#7=xqxv!Vqe2_d?S`h&+dpSz>lX zaB!$*#5wFDYU#)^tl7v`iN+-zx|JuS11Y2Mf|L}{L8t}s_W@kq2=M6hLEg?3Q1?QM zuV~7k$wWIRq_vaszOgyl^n$FsxAWOrmU&L*rllgrjjXu%l%XJ3h`lAkCi!zk9_rr zH!h6YxR6a1=9Qylj0hS+Mg$3mlAi`#Gd`ybt z!<@_}%R19aVlqd{pzAit0S}jF(7B?dy3ag=$L`Z+S)Y!!F-p>YL0~(&Y4|sKikUwM z^J9!Jr5G?x60Z3oETcEqts*II<~CoGe)SVszta68b_4XpG0nC88fHz2n&ATDV%Gf4 zW6rEC?Ix6s z$K;80%nW0B_?Q{!Wnr5@CY-WbTaNMfe49Y?OMx+PyjBcKD(q|%p#0093nMUQ-$$T6 zF$kB+wm=vO54tU&5z5J?&&~*Ql#KU)<*)HGi%~MM$AGsd%oO`4We({0+=!A?LLi%}={Jo;2b!uXMnUmmud+LGnSc2Riak3z*=83}Wm zH$Fwe*atv6B@)Ko_=QNAV|LTp>uYa3Foji%sh;YMUkrokc;mIcZ94}SdbV>)_(~k) zqnc#ql$x$Lp0VT_t*^cDt+G&US9s$)k#nbn!Jz0gj`N4}!Nb{`rhX_s_(0%$`{1RE zS`(NP{E|WfP*#PC6nDd5e&zi7Ub%g}72SR7KgP7#FAbK|)ca1GeH&%I*2$ZF zhuX=!q?q{tL<%n6z}+QK=FHjWq0too@_?DMvZ-}KYL=~F4~kP5oFe>EQ8H&SKM?Qe zLs%1hk!J=!NKQsf<;CY74~%kNpVh3WZkqp@e}!rTAuic zM%MMj-z8&KZR2E-r?DsBQn&4UWXNjMT&b}Fpt6OcF$dZhp5aD#&{kIv~gVPin~#zyz;74Gz~>mDy215^7Wipwn5R#tJVJCwb}WP z4{9FdAi^sbKwoax>jZt`(nAmTZZwP9m%hku!nux5J@kR47Fe+UxKr z;%u(6m6H#FJrie%ffMKI$3o78tq`2&UWu?@8pu?b+?eajDpLV+*T7XT1cMJm%Aj>O z;>=f`w0Tks8-;02z|TQjGDf)(GzQAOh0_wEi1OF>ECi@E}HSWrnf4hBz*TI(G1QJyO!EP?%$=ciza;W(|I z(9A<7R?=)`1!ey&+YnkUg%@@5Tsb_cv0vC>k7Pod2VM2{e)C+FsM%I;C5Pn3Z?aZX zqN6IL-L@)1xm86ZI_AvS4jy}K+M~m3E5RU07O$-{0H3W_$ehM~uLdHR-wO=*GSU*_ zseI;pE%ZI{7zW_=^bZky*?YHkQ$(6hZMV75ja@E>bNR|IE zNv=EfN#bFg5|LEEaea`!MgEvX@d)32H{u^?dvOqs3W|A)nm&Xr?A7yZy6K*h5vx9(t^QG*Baam_tpH>jzhg_6YwK$Nb<* z(GRW^6=VM3N>SpyLe8XHzdyKAR4SR%v6`*a;K$9K->3?)_5Hz>qU=wV0|n#0@78Ug z;S|NIkkm%}npSw{p*E@_)W%#PwUJV(n7K%5Bd#4D1?q#A+L-Qbw+VFD`@Y{FSBn1i zaW#E;{iP=zFg(A5hqAil?`acHVqM@NHF`8#t1;t-^KD|JO7)(r3C$YKFs!8Vae-}3 zJDj4UYl<-{`H&}qOs@F|#gvFbKC|iKdm+60En9hux<;$UM1f7r(6wc=y?jHFgPVk} z*sVeKJTI*Cm&1O%Wlf&Z7PUICpUVwolTpp}0=uai^IV>iJz_X??ZA!MIzLmWp8RmU zwa!N=p&KrZq_=2X;d^U_fF?wIeBP|{?B&GDLA3r zm&QaaVdcgtI8XUyT?*4Kr{E&xSGe`1Q%(U#lo3iXd!kcL0UjIqnP$^m!EeSs^Uqt_ zisT|!jhce#ldjY^cC!N-(+}~@kecdV6t2*q_9J||>~EYA!EjXeR6XVUvxZl%S3gld zB^&p#`m#PQ)F08ux%$KUI9q>6AIJ42eaz}7^-;}VXSo&5dX(1ZP1bTu(^AK)`J2?T z_dNd|rAMXodz2nidWX^iTYd`|98{vyp=ww{)CtLq0@~0>}TkoZ^is=c640iW8h9~y40mD{R!=}AAI*H7VBjL|=M-*%RN(6UV}en2rta9KXa#Dc8< z*-14Xa_IHH{=Hkh`A6no{x^K?{UO|_#|8_vgL*K3jk$^$;QjDc_!{4!z|2i_xog<0 zJXrU$+s$6P5q9mghd;AlUBew9^K=fknt%3%n;d-8w==@#o`kFf1QE;OnU*(OOpuCB zsRIQplNE8%dVHK8$13ksSgJUcz^4v#)CN;iZ$8siY4whBMBp&~xH@}P$3)8s2-+Zo z0TDLYb5JeVkdGE3>iKJi<9|B8qt6V-`4|6~U-QfJZ|Jj>z9v{x`eqyEZ*Ej)Umg|N zK$O*~vf(>xcNY%SGvKat_zvL}5)b|)QJCFcU4?Zer(?0&UqbjwY{;J>vB9e6>%c(1 zEF2I^NjMC={Ax+<%+?d*C;EYPR%7G9j%X^04NfGdDY^jCh>!{r5qlg1*;w|SVC}ma z;>=EUa|^R1=W0Or&XLV71UCWcD(O}{pzsZzhD*rr&qu!d!cSioV^|Zr&u3Zsh9DT9 zu3+DA*Um>f#}98@5n!)f9@{sJ^HVPFB>% zo;L+>DxcFYWt7X?BRH)I7TgCFo1T>zh0_K6p!k*vTH6oe%aF8pH{7U0uf<|#?y3?i zkY8Zt0hl{onLVx-@l^_*wC!dElr$i<=*9%r7_#6Vb6Bg>+wyHILfxvfSjk#uC2MzO zCDe+Qyv{s>-o#4aVJ$u)EhhK~Pc85fZoGYAN=8AKk8GHa5Z-S-0!x!eJ^0A&HQaXu z0=&Zb5=uD-s8b%iM6ZaKbgF`zs7lkgn0_cCLhgq+Qa3RN4C(A zYTfr#0e^6mwaig+*yW?(DF1lWpX5ZeH@W)ZRDQw*0e4k4sbAtJ+<0JqqE8*Ae=6q? zNPG~x*iCa3d*&!>i|VG@(hk44(7JfgILj6B8#kc}TAFPZj-xcH#8dE?nugUUPo+nY zdj%O-l#N*g%&W7BsBZ_Sb=)5?{{~^_LUc$?ZE(&&X@yM{cb!M1VQ3dQKX4wHjN@j3 z9nlG_Fvi-9cJfDBE z1uw*Kr@Tu%ovJSJbgE1|5+19FXVfMh=CMFLorc=PqpSj@M3LjNK7VsFrD8q`;`!cI zb#ixc9JUyy+9~2VOgU_|MjU4e+!$?$<4}NRN~+hj6fjvKBxt-O8Ye=U4H8!*8f{hN z^CSH%x+=G*$QZKDZDD~7v{q|dDChY4X=LINPfJ23sg*^eEGJ3GT#O+mu_n>TVJM%O z(V&hGMkJm~!tny%LO5RJTL{O;_!h$PaWwvOjc_~;iE2oof-~Y2oPo`y>sKVm@OdNyDV?W@(5#llG9LVG)iNX-POf5yDX_jDU)Kbj#Mz z-Kf=bOIN`*Ms1bbt*qCjfi&Vse<#ctW`(hI?xqas0T7U;G^$TB^H5QKCG;hZoywI; z;R-EH+DIteXrXasI&YcZWj)*+Wt2Gzv}BI*TmO4#nQ!Pb>z*~WaFo=w#4V;96sg|8 zzh1llUi1RNrjDe^*K4Gd@r5LjbitaKPmK=!283CXk1#zg^WcFN#meU)`RJUq=ySXb z+4fDg9EKo8_1v6IDmWE^B#1@ zTu`c#h0(5(#z1+ukmY4?vQh*Qq(EF#!XE1<7@`$mO?!F{j;b(LbQ6u;5cJ^tR!e$t z)&Zk-78c`dI%ii0wM5NF|2V-ss9YYLRj(wq1UoIg5}Z|4NiAur7&VJe4WkBVp_ZuE z>0rA)C(fFW`jc8xmWZ|%y7v;PZvvvvX^GCQP)qLEc)2?NQX8%AVd(sE``KULsp`8s z!3t+x?F1`~wK&0& z=84)Z;&Cr{@_yrqIw%dvZAJ5PqS!FW9jKfFxlwGHw96^r3S05tlTJGn=ydrjy3)A) zJOv82c@{@ir<{VvD8JpqQU?;jPQnv)COlC`;fXp3Pt+6jOfQ5(>HtG& zzvYnH%cHkLN-n}>hm<6i98v{j{657Yg+Ef#jP8y~$|@)3q%s*>g5_q(<#h=_o|H%- zm#`c=z`BEviYCs4=g8ft zh&J}SPOWfA*$=FkxNwp_+eG)+F_jZ`E%P!^EcUW{&XUjeG~lxEYaC11hgK(4Qyf#_ zUe=kzcKCKZRM`>ehKf@Q%!>KbkYZ*mGdC?W4^TJcb*}4a7E2R~!gF1$0;-{IJtx0v z7KvLp$s%A#&gWceLAm4tTP-NV1xA08(eiJN+U~F-DA$?(0}9HowVh2I2PB`B<)nZN z57rfB@L;)OikM7?*dr~epC>V?u}MsRg9h8V35W)Z$s{G|q6o=#3&~bR7Ln_gQcXn& zsCA7EK_O#i6Wn7^G02&MNly`vn_cl}xOvcB@o4X#1X_6i;774<)Dn*BJC$}tW2>So z7+V#LmZdpGEP5vtS^8p)obP!5EEZeMctMg-)V)}<%`6mK-oJ+yiodhb-?^KuUPR(4 zwtA6?jjf)|^F}ISt1lQE*uPS*p$C?$qpge1yZM|F6>h+{n%S8|t_sDJt z&Xa0dwVOan_jWFW#X?rR(ovv8+t#=#<|Ft80ZH#dvyK7D7O!l#KLX8K7XTKu4f?Y^ zZjOPSo;2%x#z(_4l4iZ$(X2H(E9*45KDY*>uqRf!uvrF{w#l7_*9+4K&AL;S*+yvA z?W$lLXx8mQu?`XAy)1n;F;yC32R6D*>CRNGE@mwj}qx(uXKbyv+A0fEi} ze-Q$*-pvx3g>)KfYu4hlvvo6(amQ!z&`jii-staVCUT|a?*rot|B$l+>EbZg!ZhTe zkfTd`&9%>|LimWl5u!SYsxK!7E{TEeM8jnvD;$@-(yC=OPoxSqiVvERZo?`isJgq9 z*ey_W?mbHEGKdoEFv`iuZ-sJ(jx*uGE5y~(m-0#via9K2TUhPtzns&ku0zMu%SFBL zkK_(em(KsleiEf0#Q0&F$xcT{DruyBdm^NKU?cA^9l>Ug5|X( z!t6j;Xhi^{LMHeGs+LO=9hSpGFfUn3+mI9K785usx&;B4!omY%VY(^QS4vLMEw*nW z<~607CS`)RuaqPsIh)`Iso{L3q^gn$-c$vnP*pO)OO?h*xyM)v#VB+avj$7dem?)B zU-yNAZsR*^fP;u89g?Nx68XuIfvLyeJzmTZWlJTT6=IG8me0s&`zs2t4zxE0unv-2 zApuKUnPlO%4oiWZ%H|)6t1{i1)0J)rUK&SsS)2;5a9ON`SFTzCuT<5ASAKpqyzr!4 zuHO9n|MFIE|1Wz>7v2jNNYC`q5OVcha^wlV(pUbi97X@h{M-7>j-vm2vwxgNo1vCZ0YbL=wGxXOJ#?$V)J2nDaFhNW^f8P4>nvF zpHYJ4#rbgJIN30U;~Y@Zwek-su|Zon4j~ERIO#2zMtsv=fXVvUW<};ala_g5)9MVA zod;a@{595M&}f)t&tD@fd;S_+*_qe4iZ!Jnm1qFYKM`Z<^*F+5=+Ve%hjC!(q=O@n zk=TIDSYVXVyUXBZes$)rXD}TFxfTpmYRD#{Ap-ZV}W@&_OiVITEcp#6vjBs4R?nK*;q0fv^ zCe{v&P+BUC@K|Py`Jl!HM^i6Q_A#%*1}8}vo3f8Z**lpHYA|AhGO>%H8Z zRE{o?*^hOL!|ch3Jy%`lDPr-BJ!8utQ5Fq{Zn2YTs}dbaU9)Z0F~-8gLLVr0PbgNl zhV)*``jWVHIX0!AFQj|hb78nB7$(|0QqXm;OR*D*th!hlXNr}LV;@F{xjpOeRtwPU zb<-3wc26|B*OtamzNGPB36<8ddSz- z5$MB|P^PnW1ZCq1skb;yJX7|rRp=Q)SGSvhmix#)Dc`e0QTCCveDq388p)X1nM~Q- zb_6Y@JFMeAAW3wQ`OuWD6Ch{%8BrXmqvQNc*}E-b-6g_Ej+SFnYRO%+gF_)(9mwQxm6G6?h>emxiV&YK%yxyW*@6(VS|b(~;QltU z9!qM1temGQh5t~LjU!yhx@%;Gq_qr(qUk=6D9A|~3sVoF?88La0&Jpej%;_s zhl#RPl_`$)NzI5Edor3t;eS15J3=8W6jI08KFzJdrH9Ljmp3KqKfw8kf?KK5Fex|ON}=G!l`0;u z0;bYoj>8qkiI}%Y@5VFLMhytVR&hkmnr;~_#>$^)D{=m7{rRo7wX)iV`Q}#tOy&c! zVNT%#qb?g5y=yKo%1mGcd12US=BU?_Sh5rL8^Z>_g-n$F#;|cT;vps8Rg;ObHpj3z zqNEr$j&D4sq!>01gk(RcQR*Erd6tr5*l@^LGHmvtVRN7pn-ZD-?8%zQ{6Pa&)MFlS zv1K&YVzFqL#bVJ2i^ZbBmH16B;~8tW=w?Vc2lPxNL!w z#7I>UhE1smcA$zdY;uLhMybY@i^K{}7^wz{R-0LYm7~V6Szw?tY=&v?EdtLIY7`#2 z50EksJrNI8oU(YY;3OU@Seb{G@xWT}g#-uP7pw#_V0F^wp!B$LP>kB1w#*BUTkd7yQtrR((W~pS|E^xk&bvAcCZT4<&2lJu zTxcVnF4aI`VA8S{-OJ+5Hu+`;U<3+>A|cGK6)7%-(Td_;!>{CCJ_v-5gV@A_LQ#}^ z*^1&}W~bp^K9D8{{|o-pFdv+3ZB0&eWlhc=gUo#7UbaCM%!eZl@R*wW5Y;5dt9;@j zDfx{csqh&gdb^*3p9Hf$R{qw8kf?KH)+$cBP zN}=Gkrxg+Veh5vj<#m1#cJwcf)<&H1HhFoN^JCs5=W!59q4%gGhhoS=;P@tYNU}h3 zMK`VR1u?4gRagcWa*TY90r;~bmicX;$b*-^b(Tu_xp;i(IXD~#>$KmzpAuRp^(luc z4^RXFC2sEEMgwsmUEWuIU)Jx!^#V>Jub)tEMRje!{{U3-Di{x!-Ng3jD8Lsl8X z(7F7bGWei;*14=6`P*ySaK6l*sSZaY(JVSi=``Y$QAQ^z*`_I@laz|nl+j5_)Nxr# z&!dyg>;1nl;g*%b{8n_4`^w{SIU+eWzCY=7ZK*;rdCuF)P-d`5ZHVn zg=kJ>!F3wkA~=|{BgDx@h&z#+w?{nyoGiTklM_yQ0Xk$FbB@^0G65V|`nW@|qVB7c z8m%ymMmN_{Y~0Zd5DCD|Ix|i5kT$akmuSr4r9_1Ed5=&)+QFCYcBF{Uk{=Y-uRBq2 z8qyR@;l)|ne1#m=X^Uc(NJIf*v!|quKN%d={0Fp{<2prc=oi(TBNt0ztV!;eLQZKU z*DN-Y)@W1j_xL?M%MTERZzp^MnfOMqu}Fw-IIn;QaqoopV9kb2s3iSpc=FR zrJmEwrrOrE8qtf5G>?H>-c&WJsdAV+Zp}|j#O8z+I=l&;Wm}q#!fhlqlbJR23M9tc z1m+MdeS1KkV8qYx5>a12O=eJAi#ad0_4FILnCOpI@te7LtyBEnTnzT* zr=gqq8*(hn&&}WNI2cxEa<0yv-GJS13GugVQw$WjdMWL;)&nh`C|b9{#wmmYZ{eAt zq~*CCRxQV6^H8j-ioi-Pna@RO#bu^F8|!zguO)vzkl~tE^i{Y(Cf?>Vk+JXosfU-V zpPmg#8kqN|>v6%Olo^qvh6v&+QdHKPKF+DtYsObmkT3-7(Yg!MN19xq>_|kDkVK@y zHAcc05r}bVyuK~@Dp|_m^degnN6zc^Xbd-}MMC2+7i_V22I5xV^PaY0>ARtII5fC& zTRRhGCVT|y7?BY4`n8r$TLKs17qZi~LDQx7IEuB;BW{Ne-mI=ME*5e}{BUQwHMq8F z9Pm{}p><#!_^$;zKGd^Y`tLMtfMxW#YYa7BT3e@tc%ZKD3S@)QJe0g1Ug!m z+C;Pzx#}dV!)EvXkpmjMfX$D;@vlU*_5AJsmCqc*(0LxopxaOYFv~B&_`gk>kjvYT zLY<7Oncl7(Qh673vi)2rj}Kb1s7~U_zakCrin^8;LgGj+IxCTJDYlDh6`^>vieU0q zC0j+XbZe8XBKVcn$y9_osc+;8&d=SLZm{C06MNDsf2?-`lJkqR2E=fZR@tBbX`g(d zIX7`hXsm~B`6_x8{ag15kvW*Fi~(5xX_qkq>yfDpZA#x>l^$6aJu)?Dow5Bg4O(Yx zm(ieg#@ygWZV)E%$wp^{=Q1A;i?2=;fZ>HcnY6R{)(rC4=*b+EnO3#ME& z#C707%;Qeh5E%?yve5|h?-oQ{-+~6e0|XVTAa$148;uaA&K*85b|hOL#V~1vY-Y{> z^iTivKYJmmf*WFn?SP?e^Ih~4hhy*koxg^HN%OZml1ws*$zf4vnPf=@SjNke3vX6_ zs^0lCy%S&oC*BK?=ok*LW%-{N$*2e_^ZY6cDt3fZi`;aWzHv2V=|z&tD55ryO)y#H z1kjRnlMR@K7SOb;3<(9Sb8duh74x<23CcNBWW152m&ewYUJP-C^!oC$w2{cw7@n!# z=2KFGAxUazJ^7`~P#>kVN_xFrX~8mvgDB<_N( zhZt+Wc|RqzUc}f4F_wkZmpj6Wr734r(p~FEe!eT*+RrZuw_lZTGxg5k#l5NIxfCfW zdQ#|-<|B%R67dRTmdsWm2{`py7S!l+emAfPAxxTeIHq`f={ZcUg*We~WD0gm#0Syf zB*Pc>35JpO=}DCD&yPF|;9^_C>mmV(a1ZkNe31yS`JXW$Bkn-d6w+Di8Fw)iN* zO>kwSdV!1bfWhuy@p~E6z?;}G6L2T7Bt@FmcgMzG_sc=4{yvq_ETLM`oKck=!&yi%X( zxF2AmEXymh+^Nc?oa|!aB%@t$7NcWwJ{DN;Ai-3wcUOwx=?2xAV9WAy?6Qhj?sPON zC_tYo!$y#e>7&!JF&R2X>~?HRz;MGhNC|zyig>=UD>+b3JF9O6_&}7f{ZcWui2zSP zOsDuya&fXN)6*C=@pQ5)Q}Oq6ak48_{AldTHPE)n9w2hJPr(igT*Q4Jj9mO@s$@=B zSxj9c)`2Zn2CzRweiDa2%O|d7)>&&&PXs3|SFM9A!d5eN+g6hqg_akMg^jDVV~zE( zK7R%JSddQi$qQo4&jWv(NPI*u{E`7~_z}~uLa#NN7vHy8&!y&|CuO<09X@yrN^`!P zw@de?Y$~i82J8>pM2g4rOwX?;nd`=W2Iquj#}H$uxZ`Vn0V&ZMV3eg6P@Ay>a#y(V zT%7U)Wykg)t!lFCF-t_Y7_)Qf#h78Mnu9>Q$V<&9kx;=W9UZgwNVzb{dB8gvS}b5A zivWM~W3?>mJTI(VG`9ZgWHiKsKj43P^54B=x(b%!vp0Ojkw`flvrwqbUvswb-XQF{8h%^{OE^;=z=}JdEMH~3$&b6v(d*{$;GX&ZwjV<9T%Gko@Q_TyHQYLI znb7X|fQ`g`B=CQ5!HF(A#RE8hS~dd*rnA443t{*YJbOCnon=kFTnnCc?|LZ~);Bq% z)LUfAE^AIx?2}RzyK=aA*J@H2C9gE+Z9J%(H-4Q_={Ng{cjbE)!)o67V9NTN*shot5FMfCf zW5=E;Z3XfOK@B*5ewtV-X>{7bSf9U!HzA(~GN`$R?-gm9uTr`z{}71}eBFt!ukdwW zU-i1w=wC(b0Tc{N+I^*Oal}R%QB1yk##1+A8LJI{gRAZGtuQhW;S?oXf_&!lu#%?T zpT7!=I91br2Q5;fhe5R&+81SwnbZ@-_dpwDZz$XE@aRH|4M(G;l`L%pOItCNhNUqS zGgBI9Gc|_NQn<@bLU6Uy7m_?=uP-Z8a6xK$cY(dKdu3%ghoZHzqh>`3c+V?3nrlV( zniZXq$o}rvl)l4P1V_mFKMi`;_rq&DJmGH4w)5b_@RN=ez=}3J7QASFtY*0F=Q|8H zxB`DOD+)%GEypA89?XUW8qS~nIfv}{G)*)Pcoy4GFA@TVCuHLVwAmqXGX{k>JFEo{ z?0gx{KPt6K*xPkvo8ifFe)co$VMz&w92VbRJMHZ?ZC?6v(>3i~st0N1(P#D~EO#nx zi9T^AZOcmp;~mTHhEp&MeNwXQbdM(;$x5DOQsw+Ke0{0!#hLOpMZH<#@Pyak#ZSur zu%-MXi{YP+1{uylO*H(r(}}va`p?ycR3qi>Y*qUx|2$KL_RpD^=Jtsq z8Ogm~eLfh`#gIFd;ox_5?tlf5EX6I)%bvA~MvhF`re*9e-L^K{DrJmRxn4(zqEt4Z zW%ls4B2ZPrD1!C*Mk44_gV+0NEo430bUu@KC!!HTl=}p%8I9zp&_Hyd-prTRdar9^ z#;xb@=@9l9Y6o;4=P_paPmVK1>6qbdedkEUp9XIZB{k{Tb9E4kC9s1~%%g`Pd^y>k zCpm~wQ(*2KFzIjf_L#mU!wpIXSF|yU`;w=`5*9*Jbi$?l3*y%sInEO|*E?&B1WDS6 z&b9gXN(|>vMrL~+pbDP|mhYq$RyjGAUh!z$?|EESYV6kUg%WYp8|V3v~qVx;A2#|KUa2yZ-WLXM5NCe+gI6z`8mg1mg0G#&@O!X~XgN zzPeNOkQI2PJ~qzfxh}U z<2cIcS@%Qp2(#-_na2?)B)`9#iU=}=H&VGpX;J^RUv#+vBy2%YgnX;TJv=rB ztdko;=BSyH*Rpc^!WjkB%F7b1UgSxwpwZ~3Dw-ZMYVQIJxvKs zzCW#rK2v>^4;(<3^dT}JtiZV{lBkp`gez#`nd&m%o7!h8To7sa!#_9av+uMzNX=L> zhqP|){X^~71N~63WcOc^53#qKwymM4wvmCGN&xZG^6CRk&6b-Qez0r~0Jju&^?K6k zzvItzQYmcmcG|lp!krrV8zk|IiShb!n?z@8!n{jce5x%#ZYFhJP(44rfQ_+YG%5Is zbLkn)D7C<+N8=V54cH%}gAOieSuQYDQ3VpzkiC#2ur6qr7d?z2k1GFTR38g(NA(#Y z?MPSr(q7#9EA*}p0)>%Ohx#_GFJ@L3$K|Ub@jfMGoD(!QYI^Xn0FKfCVyD{s075W` zKkWn9anfObW^6(%FV=ZEz0vLH)Dy`a3#lAn)p_^+is+%30otwx=uMy%YuEf(Z3eWT zXIxtN1kcE)d2o0}PFDt>PI&Kza{cq8>KJEEx>xCuIoDSBU$2fP!4=UDoX1$i2J4xP-QUF|Y- zF-wwEh8WPd*R)lC36ZswBCyzr!@b%K(n-q)RHB_N<#H$CL7?Ng|J+v<$CO|BZkH1Pr0nj|M1|{8}#du38j78dFS~dB+rcGn-=Uuwj_lLvCd^ z+gJ+3w1pJN*@pshjsV+zY)_#r zX%n_23ZxyrCQ*Q)ENQH?IGDquI-!w`#`>j{C{Xs+tTF0p3#+L`TLmq1q5#)WFSdui zCbgv&4cDWTDBxvi zB?@@YeMM| z)6xUl`cGF`^+5z{Sy^pA7mDeFme6{Mt5kXbE8n=N+qZ|8h|6vSW&8Oho$~+K9w=gE z^bk>$F(2pN;SIh=sEQv8*L~}~dl%4hJAiUIOa(uLViz5)LVR5a>w4p>ipFP?J_1zG z3D&1WX<8%uy0OJo=kv&cvSf>P^Xt(k!Np(>vRY*9L?jE;iq|3d!{57J|MK;|!c~xy zMEXadL#WjDD*v`h# z0k&6X9OFcQG<9P;thLK;wZd_dab6Lp`_z&pZQWrTpDfIP!{D~j9Y)q2B)5>c_#E^o zWD@Ca#q&%6l!db3;o!#+jl^(8PY6I17=0@djYwt!C*+iDOFt~J2vVubdH0y-Plq$I z1SaUP88hY(eQ9%V4Tc(}mVBiYc@f2ye5E)ArPvMGYB_B}plgW(#M6&P^2rI=&;-(M z!(mQ8uTT>7(^aC#E4?CKWGuuL9mvw`#EUcnMDK>rBb}RcO7vo%;Ls(8--L)f4c3_N z^PvT_TQ~y-VVa^BEkDLQuswfzskN2j!)MHI;q_hlgvt?7%osvBj{= zju3<)nM*?0;$!#bYfDei@>ns7;}oL^fEsS!y8rnUX5W5%iP``C{o&Tj6<+WDOI7xI zbMDDQJH5YPCN+PnFOmb_Pjw@79t@}VyC|}_ZCnX3siWA}s^w6er^GK3aZ;E)fsFHu z9-5^?39fgXV-s9oT}wh^lmhDqG$n_teaz4vsKGW;1kP{Rl4a`&B*Z3Bn53fhHyDcC zZCt#7>V%n#Q(V@r+`amz1|)Gd6}ii3H)z3bfV~{3AtOSJixw)Pp7+S>=e5aKC53jE zsI+{rrT z=TRz8S8v~fcPyyO4S%Agu70~OXzx!CU{EWD(&)Dg#eLI2Tft>0Ee*GvL0)GKHz1r< z+!X+w9o!3~FvtV3G!b29WxV8`??-*@kevytI9q*^P0?RF4?YaZc63;v+Hf`2runhj z+1h!&51}pkMsc#RLC?PL&uOEn23t`1tm8?|anSdCO@S4rP_Zaqh~URog(!sDhlrjZ z5l&&>57<`T(f%t`x=fElANQdVz&v5m-pDYsNYLuo~( zHt3!MBe-${&(uCJY!0dL&b*?VVF9(EJT3tbTVN{h?UJ^GX1QU_QWspQF=Y;@u`T}2 z()A^5%{~@wswgyKFge5m4-XsoVmCVIU%claF;7eLL2SZ%lU`@A zCpz;97wk|Hryw7Vn7o?M6VU|W1oFFUPm7Z&qyTF(pRS0l7F#3COf>`EA0Tm%4t~Fs zag3T2U-L&iaxtnfc-1GbqBcc{wH7Hh<2g!Ks32Tz4w2A#9g$ffDo^*o;%>NHy(JzE z4{Vs;aQ?Q%FXecK+U0+e%TbWqvTWlHtbBQ0ys9^C}LWKs||6^`~iQQ?{m`@asdJ_*Y;-7?o=@u(h zU4y+Stm|HRd^$zyw3sTA^@6DZKA1?cPvJg4+li?9|Ji%@D7&gEZ*)J-tLjvR9f%qU zw!4n;>xvDRbT?mMi1+L48b09KeLw8Wa4_z0^xzN2xZZ+0K45VB+T)|4kbs4t1c?|m zKnVx|1WO(g5Ttl01q3X4hKE>z00jgnUQ$Se`}@tg_Veshr_QMpNVG(#eb(N4?YZWA z%{A9t*s>)=1y5r;9VH6$(|=R_f=Udib*qJOB<#&n5|A{wJbWC&V7604b>L+49lC^I z`B7sxfTR{V3e_^hTq^DkMo*XwuqSL^U{S;9*mn9<%zA+4!L9Hx_eIbt79UfNz#I!3 z>|jmMj~s%+qQ+HUZc@zSeSEl9ZGf_V(0jZI!0}C9Ax5h~Ut$VjCr*3i;Et$94A7wa z_#)Xx(Dz84_nKlYbfdP(m(dK#PBd$t9-1N8iRSI$(~#>#b9Nt}i6>|G@v*rxLQU(I zmQ8>7b!nne=*T2sx{a1fAh*K~16tYu?q%a* z3P-RB2Se!Ia*hT!U8EWZ5@c})kYTwG8ZLhP*F#`xtk48c;J_YSZpO-5Fs9ApxW+Gx zSW<%s$vE$L_cNu(;&)JA1<;6B%cT>P5I1J!#!ui|gFz2hZ(Q=Mewb-1##zHM98;6< zhp9=}9R$~n91FP2su4eEd)G6i2%+5eyV(S)2p*xjy9+8;~qnlDR9*=;hP+JW5 z1wT83r-&xVo2f@nX2O>6Ne&6D@dW<@&s)sz2l*FRo#0;(h0Nv1}C1z6h)gQ7g5%!8T=V{4|FL{ za(n5ZccT)Y5vd~a--FH04r5iA(NQ(%(U!_~a5rUqlV*G}UW_j_Uf`p_c)J^pS2)m& zS3chP@d}obdugRv4>7vcWx^#Q3AM~0_zp19LZ1t!g68^x}@N| zWXYO(O!6GuQF#7PTbR;n1_Iyi*9=`GmL^+$S?~@JiZL!xVw6;h<4y`TDzX^@)F$9oIB4z~e&1!4mDWKH6v99p&~%|p6&f2HnnYbGa6zLQtRDRXKHzV6Wt+t zSuC*60l<`G2cTe+NsOfhO*lfMyiZ2gwZ&VYL$RBVma({0jsRncpYy=~d3x@dro+zmj2&0mpay)ePaN;IJ>~ zC}pFxb;Y;Dy7HNXbw#rXqUy#-WuO_-t|~KaT_MWM-zUF%H-wgzY2&~*&Wlycih>K| zGWzWymtjU54-ex>4iBTx43F+ji8=qo#4!CKtX(x4t?*phwsv;3ii_lcxv+%+)0I%u z3a2bKt-wxFu|e7pmk6`o5V=r!kQLS=@$9G*n$sJ4<8ypR61&o&qd+zoiqNF0?ZgBg z5ni*cLv=l$gPB3{9R5V)WGf65rdc#ep&fT zoRW)iND4hydT11JTyHe(D#{VKjAC%E7oQm}QYJ^-!Q9|pY|~^;j}xwMgXjWw!hp5u z5CFCSR^7v`Llqh`_MUtOW5>Y=$rfO3FFkXHwuvTaHCPxNg~}|Mc^u3NHbaP8E~x^> zu8d*+Dux9dcpI(&ABt@xCUT!eiL0Ew3vNgtZ7z14r3QM4uDMZU;v46Ku&DVh?*g`C#Lj%ZPo)1C2m+MA@ia2v8=0#K-`KD+P++p{$e0;K zJMf6?1D2RtHyLn$Yz0A0ISbcQCI|bDgs-54%khMc3@0{+4<&34+r{XxJ)@<>>aaa+b)-rt zAQLY3HpO-a;L`4t)$ZV|*Vyiu4TtauIKb3^F~HP-L-Sid;I4)P76vo}HZ!`;4_GY^ z`i;k2>60<{V9aWIDrwUrTkI?!%ca~}h71YrBC{y{;lvJUpCTs~U9-^Vw*o)*_gS1i z^59vsK051$rR<}#Zs7NaIm^|}MY|M+|0a-%mzW7w%uJAL&)_1?4Y}t9bOF9Mf~W-N zViFhOuMy5O(J>~UjyEo;U4T}aferUv47HLfC#Ncgh8 z3J5SIMjcG89ajHft=%RNsKDiQmf2#+nENB9;J%=9+#PPn$GB zSW}9_A=()i;3E=V<*Bb>conIQxR+=UhZ!{WRjmP+>^8(QL<0*!6h|{r1Ch!?xAL)~ z2%#iNL+Da)#MmbUYj|3*Ru0OBF1$C}zj&|2DiKOg32W#$;y|v3H4M))tReF=D`Gc> zH9)9fq7*t}Kd(6444t#Dj6sXp`1xxf9=`NdCGnBM%#)Bk$Ga=b%sTz*vs+_kC0_Wh zpwNsx&CAK>l$Bd;5sIYwm;}pXV~&t)EMpY*MN2e^uVD#q48;LO{Bi!bu9|bl@*R2! z>sR6_R0Y(jwy{x_JVh;GOO0%qM@kSB428KF@@hH3!+-TP@U*PGFbraYNqK^y7Pl*# zc#htN!z!mUYQ1kx_y{C)pcX_;Jqu+hhmm!sTA>vS0o>4Psuk){4ruI2wL(wIA&o5D zK!;V%XDr|c5-qTNK^N7sq{4=pI{aYG3$=&%!9l6Bjvw9lp*}i(aQn5o=J>%S?v>)F z;|KligTfyryxLZ%2~Qot3bZtx#SKu+C6bw~>Ek)kpp z1GuK*E`rLiLnAnpn7=hs8mm=ld`6W9t+t#L<#=~zb%t?jTGSc0rAjbRVNxyU7{Jtn zsx{hZ%26EXg_^_6=;1e0`NAAhW+hZ_#wtHJ_k$6{Jzm9;P3(q+@abE;if4XWuccex z!Av)vH{uTFg!~|S!&T_-@T2%YW|VRVS5a(}bHsyWb6mgkH3lL2onyrCx;)uLycfJ= zvIL-mZYyLBFWh>uYMf2-er$L-VRs-O$ml{4RLV3?-B~x^Uc8{N&`_ z-0j6rj3XT39{361*(cvcGKaZ}E8}-Xv0xl*XzrpQjJa}AO2s`0%0bNo_F7A>7mPP{ z^^xzz%sY@%W9GHgUC4-#Qx+K`KWRL6Rx>{i4X;nvoB465{Ko&{y`-5pG_v5?f{`dO zFuI|iD;q2BORBl%rj=G)xs2d+;2 zoPm83678Hmtf;*ELT{W8l^vhojY#|9olLvf5%8 z)01E?_(i@!U<9o2jSAmDK92myyaBS~c^}IoWz5TUKqv@aI2-}F!k3nji<#M6Fpm6J6q%4S?b0ZhO8h$!= z3FU$Hza#7bF+j2)qoDg)*m#Yde$XsPWc~vGbLcXPq~tX)4Bf}=f!!+a_&l#g=G|D> z5i`mNyX;5hY*eYD!k&~SBSVlT#B!2?K2E-)$(9Oc&0ELo`Eu~Oj)R?%S(Z_!KFF<`3zPOBA%|(4xjQWa)Qm?nvt<}Atk=jb=g;-^! z^+NUToRQqf>Zc#@P;Lr&&ZywIjOAGy(IHp_$U}jc=RY)bB@Cx@yt)qbffzp2tp&n~ z<>1Izu(16HzL7AXk5mpYA)evx+EDVkL`j#KO(KtBa)ie~SY{XsVaF^oV<}i2dcUf! zh5x_>*rgPy>zKh99f&PSQeA7n!%W3R25*S99@RA{)!fVocSVCpSsHNQPPH_!6p`9{ z)v+rlNpP+Y&K^+9NlOj!D#_p5-#%?$ouR`ol*%mbYLH5zKmE?oz8d{@i0Be0>1+0d zZN|o8&?wlnZ!o;C?})R2nN$7#Uzq?F;U|^gOCo&2kKtrMvGLPeem!Ibe-~_d3V*}% z-M~qtsDO!S3`ked6j!YmG%WQ%`|vGLUFJHRFyacnDV3fRU=GP}J=FsZH#}IRTkQ)7 zWZe>J1c)hgg&`=p$NP=`#d{7zP&)S%FQfuaf=5c9L=3;pRT!kaFyx8YoP__X%}_2A z2cO$z>royqIK(I)E5s;AB_@1vOsJ6eL!PeAAqgp_5W`d$J0%4{4Ki$ zBoAXQ5GoREdD~{UhURbC^TD%m3tQysZH!JfP$b)+P81 zPsAvn{saR0t)cwJPs|79X8E8+lwL88 z=$=A0P2+#tMfbLy;}haIt1-+wo5W92llgi1gou*0p-@&g#`fxdC+Gj|V!4^-zHt^k zQpeSs5^7|-6Wr7yTi-Y@HDV&EE%NnEv+(sz;OoZ!wu|v*d_9XNScmY0Cy4FDlP&V~ zygWe@?Q9Xgi`BT<>4{{QV_xtV=@cSU25WM)OyKJHi%yCkEZ3Wh$_ngV%u#e5X@ z(5KqbAVZ&OjOw9JA`^t?`K3>kEd~-QQ`A{X8Kw3vDI{QAPEVUniohY}1 z@`-X|lusZzwDG^~qI@U0BwH%j&DI*e=jD=^MV}UR3DVRWdVq~n)Fi#F%`jCnV>w&g zq)vAy!zNR9u&KpZ?EJzen{=LM*oNzwI)3vlWImeeMaQEWMBX?YE;% z{KmNU`<32>*^thgk62-xd=Yt$)cI z%-5GSOz9KrdGXSsrpF~L8?*0`_Gad#SX#t-B&K(9daC3E;iOGkE*WW*o?1yPEjG4l z=DjkP7IjGyIdFBWh(2Hh&|BQ2kza|0YWY<_BK~+k8VY+5J33uu%T+C-Lb5{->lXQP$frfAglT4J;7cp|eA z?ry2WT^Ei3$m=f8pF;6nP8`-5ma`iQb=^)H3fFz0-OLk)@#*%32NL6yK(CZOZlwCm#qM6({ z2Z<_Dju93DyU8WRQMbsr3>Ib315JSr@Q8HpG8ur`=dx*t&*M`jp&UwrIhc}<9wr>> ztFC+u1@JZFxBfwtYs+CRRHv@c+CQIBOiZlPEzSGu~Z$byv2WP3m}k&%1JL}fSe z6KTwa@FxZdhW*mB6-b-I1LUAt-bsH-^f9fPB4kz zcn1^6U<+@JZM^%3pVr^gNF&5#FT6d5+XkdfxQx5R#_R9~N>+rAkKl4>^vSm#_&edgK=Hjc$;h1BqCm z#V$e%BttIHVi%!B*8(ke86Aae%LTdEMdSjh)eE%PMQDL)#S669MQBl6pv5j@FOb&1 zAQ!ucTwnvx0xfnCT5#tQC)x}1?hk(6jY#PNEp`pLz+NsEdgn%*(m?l+Mp{PQK@ECg z8yDg>`&obgX=~aJuDyC}$dY6PhE{^HpY!LsYw%z15v{bn@bq6RPOz=EbdnV-Jhk|9Co-&sZ*z;Iix zoU(?-6QjPI5DXMJ=KE6i5H%@>oI?q%yv|*c2qK3aVP_}A1~u~?{K1(SR`oq@;Eb{G z*M|VC`6vQp*+MGN2+crw?BFHkNx3BD6pSuXHFf5gtgKBWK~@7x~D`h)=7i(2R@ zR;5E12_aG&y;T+gb%zRv5+o9}OwMrm9p$tC8SzF@d86OL774tfFOeDSSy>3&BegTZ zLRh1+gB>iS$qxzewg68K!X{eofP`pR)sX@a7#~<<79YsB_>}c&3rVO!5ixSgj{FC} zQ_`@3_6xOAScDAnfRk8j(lItuqD+GvN)_W;stGw*HQLWA)?7KZQpC=eD~89>Yi}tWx(3V$8n=P0WsCkgxDzFag+)yif<5+_$=0G0ToU( zheXP|zI{~S40@Mek7)hg_yG4jm#}U8UqFjU;$)XHzRjf``8HQVuzZ5=3M%+}2-zJ-qWixd`j11q2?V;s57DW$e zzWhokN8}ACE`)Kxa{u0k(h#VhQRb$67aWhB<3)Z7kwu$jSx`73IOz*gD8dcaOg{wI z>Sg0vK_KPvFXE8f=-L0IW?|)=?6Y8Nbp6F%s$0|V2{^$I42yjbFtwFXkBRDJD{3%V z7$ty8*wONFp#(rD3jCCRKF)_=DCL1j%kiO5%jrm=BmqaTPKNS;8A?6CK$t2)DMPcN z;FhFF7%{E-Ez98;ma0GXA7YZkSAGF7LNS6Ua4blaQb-h(B>4AQc~PBxC57g``=N@1N12ddlB`ZC$`5!)UYtl#b^h$8bDJl(t@^l!zIWNL{!Wm z(PgciN=R3xMahet%FD>H0WSU?cn6rr2L~N{`>Xqko(;q6(AA-M>q+>CpBbmnx);MLM3&f$w>-$;a0?8{8 zWoaV~Wq~Lb6_PSPZcq{11~C4=2#hZ6XN6_g^vr6SO#5)WL2jTtfY0zoXkbxjNZNg{{nYEAjB^rvci@ft zulv!RSFPW)@<6K(kKzy+KX{lu2K(uoW6%8tKPI2yN6e%-nC7pbKUn`PTkkeXlDd@r z%f7W076cAG;NY4ct$~k(QDDE{Qkh_#|1MwuhhTz#qt{&-6Q9~Au&_~W^x+|E@u|`` z`dK*`T>sqdc+JhZDYe@$O5fXh5x(WaO+qoWflVJd0spec%CcHnByxa`X8HfTa=<=~ z9_PU53-$?LUdAATi_JKp$8s{M;UuY%$f;5FE}2LUL8i#!?IamM8AArgkb&AGB7>VH zgOetMlO}__sbttF2+xvXleC6p09DguV2W{q3;=GaRA9{~gN}*JRZj+IHZst&)lr6I zKp#@Slcn&AzNOhV^rMR*X>9nt{7n+jH;zg0NU=~>iyD%_Ph~bGsK5c6iMnqKIl@Ug zg{S_Xx~Y3|(grhIS=3vAnJwa9{;x#;K`c-g>?15DQa^i(uw{D5X}eOFx7NIV5+sw5I;&H_I1N*ci~?Y)8(jn=q84*<}~uV@#aZ` zu+alBK(x{`*0J8DoTvz*q-WT1oG1ci;#b%7VTJ$_`CV(^Ca@}`Ok|GrY4&hy;3Qb` zDVQ`dVh z53zt!x`(R&7un`wptiY4+pKT!E!bv#3-bl#bN8sg=JzQ`PNsjTb~WEf)I8YI3AFSLxo7XpW0u~XS$dZ!341Th()+5g zcLK0@c!$IOe`hrT%^Z<^C{(G*$RwT|tC%8kWz?nCs4o@0wJx~bHIC~yX4&$j-`?!ICl<@p*v2eGT@+^Dq|pg<~Q<;o%f7{ zVn1z}yqe`4DLUr25$Ucz>?HRKOk$>KnMW+0sreRxDg+-guq|5!qOpUKmwwHT@Ebuz z&cfDTjVT)aU%U~XjF{zLUj*~;q#83T2sT@T!70z+ z3s(wl#;R)$B&%{t5WGDdwGX+V2ip&d-o(7>!{jg2>Knv=Jn`bJU^Btx@rITp+m9_e z5Jym1WXwbG=Rv)@4=$la!C1lA6%S%~uo0iHxy#UuLm}+o!ONv_S--Pn@oB;mRd43I zKqy3kE6c{K^9!@$^@cSh0si@b@Os88K!xIUB#GBIUyj-*oi_10($y)v-gQ~4c)j@p z#_Nt4uM<59ew}MHbfK zB4mx9d@H1%zjqe0zIg$@pz=LhP9W>i^P~337LfG@0bb>V$eIKvel~wcRX1B)eqb;!21Obj^cDgr(sV#c99hrUdf;^d>&5Jy*0cPJXFY=A2BVJ2+J1@}X zQ;fIm?Tqc$DXVwi zFr63}J^dRuxDp8n^C}&9*wxEQ2n9HCC}3qYdm>OeH;6(3aGNy*j8)}-#q_XvSj}37 zX@SNEvOynCdFtk%VaO*j4UIz{mVB>1N`Qs^_&W?0aE{wvsGu}^r~qpgGP1TAeTqS1nd7tVa5I*nU;b0L05L9IE*g`t!zzB z?YlU&FZpbaBL_-6xQHaEL?$YXA(Vq-q8LIK(8|+V+|_>ZQrTeNg)Ztt3EA(JbG}zZ zD8Vlb9CX?mEJ7sX3dp=V6uAVfw?qIWu27WeH^U2_kEhpYgkj$(!qA_MFzf^O%|sZM z1}3sFBvV(epag4q>5W7|hPWpaWPtm}Kn1%oK?cqa@#b_U$gtA5Fx4|0+dXk$;`PUW zP$#q`(teg~sxMh(imga(52d!|3=B^#IdNe4j3;liPeAsIGqB|?{NDJ^U1RtSYWRgO zFO&9>r}sK>VAF%^u0uOkbbaT`%OJc=r$Bs%3Si>y51%-&e&ZQ$SVjYkpZn6ejEx#$ zSmYM)ZK!|;uY4ZC57|^t$ZYn*m|WP;t>?Z21vGTqBm1)>Xo~e0ZhM4EgMkNd06#YN z!=4idre3`AA$|t5I~we5dB(DiX=QtvSIbI(tP-#Gn_yRWU07o1@IDe?~14F{gRN zY%x3UaUKbjj`k`a;8|CNfeTK1_0I2K^o^~b{8HwlWG{Ya z!X{yi4Hx294Qp*ZKGu?@hy$k)Ok0u#IEg~o-u9mXIJ}Q(NTREY`SL0-g`8ytIwF7X z|J4}^LP`?OMOYTgsM=Pb@KDDq0#O2DCC*X0LE{ip9Y*xl7||oAy>|LfuDNaP1t%?F z8llKev-DFjrZ0N>?hV5a|8nx+1w;eUoo4B$V?^J3?i(AQnz-fLk3d5#D39tpHrDCl ztnFAs`}GG#GSz5V$=|KYy9 z7Fc>Gu=MsA(RXgS;*_f%yZ!YaF0k~@VCk1)Oh5GA^tT`Q+0WN~e1WBRf;oISM)dU0 z*4%scZ%)183k!(e35b3rM)b4Sy!eej{O()l?X!UBouH(rV?^Kl#`!bf`}RYp{&r!` zvNL9fuf~`@?f1`2e|P(}SKPaR>79Y;*J4b+@$%FkA3W#m={FWIO-w)A;bpehV@&^e z{QSwgo}2kU7PRzE(9&`xy(g!RtLyN%OpR^i8Y0wy2@FC zZS2?FfS#~#3YXD3dLgrp&N?|uv8UloZV5*HwP9}Yvsd9``g@4Kali`x3*fxhFJTrE zfSAUyJN%2J&l3O6IM~0(%Chn%0o#6&q$WuRICv#M>XY}78H>BcL0X=UmzxvczQS}X zPZJB+$;*7eT6cisYmmBz`Zqp6U3c1@9MV!;{`uUArlTuhKNwg3kvPgdgtGWw2$l>6 zy=;?#;Y)ruGZ$HW4r9jID?@G#pPP34E-hAM^XmfHM0yjw~M>y>E;h+yZfeypL^C!!|c$fc&T8yPE0 z*0Jn(?=WN?>o8g0KBwjJ=8^S7?U5CS8YQKWCjcv1akz0u$@*05!^|V=M|7CbKIGok z$%kae`fWF2aKym@3@-X2+TBvpEtKQ(0C*kQ7s{)3jeH;=5fd6IP`JKl>8 zSw}iS*6%(qMw1rilol;aN(mbR!`5J*9&JslN*Kq9rOCR%kac}0$eI}D)OY7W)_9mp z=SkMJ+3~J3WL?_{vL+mdt2$#_VYJ&J>u`3MXBx5&cY>^mVQ%>TJjfb*N*|pkS%Q`v zO6v^D!CSG1i$Vpq+SVDnv$pk)`ABO_R%2`0wyi9GpBnEQ7$^O`X}hzY@O3d+8%|;x zk~JRhC)<R%`$&T^~L)0yuAZkJdU);K17*jRo z-TA8EiR^eEG*q4F1XUB`y)dTgd}OsvhiN=J%*}?Z;~ggJch*I+I@e+5k@XYv6xOlq zc<(S|9qTYzPj7ve9!qP?#%)e-Hf4u-lOgM-4wH3r>+XIYSwA*UvW{lQd#xesXeY>; z@cSR14_RZszs+F8#_TYEYRI~=!({z-XB;MPo@5=#j`w0i){#z-HKByR)ftDW&Cucc z>@YVNvaat0SrgoQd+XdAOKZ%%^PaV4$Ggsub!{ieni%hN>*I};a6De)OH5)`)=ETp zI6KTU4OxdfOxE+~qlDvO?mbUw9m5&~EX+rtlIG>PVOwtwYk#tLTkY7=f9?=1kCREYQt7+b z-7BS&4p)*M)>)F?-1^)+PfFX2E1^_bdXWFDBt4|FBzOy6AXOne55oUt?~3*wWSATDEb+t=s}&O=<}Ts()s#FD2thr(F2sAD?3ZjKeW!i zv5d}}pj;|QM)dbpg7$Zopij5Xw0T;0zVjGAGuY)yP`?8NO{~#;FCOfC)@a(C#GvF> zilF-_L6>%bpqIs~#?Qwd{mjYHI@CpPJ#*E_rLR2m&Dot@NkS6O$awT^dq&8lOAU63 z64dJeK@)D^d9klM*HCCIp>=Lxt11^Iu2N&{QG!-tg34ir$y_WPz?#a%;+ZXyi&a39 zQmu=rW&qH~q$T10{k(NO6w9a?FP0X4asQY!ML3aNCSR@<22my~oq^}$^#&PuuSo_T zPI9q*6c=ZOGu9~a9oDFkv#5flM~A(kei-xle5`ItZ}^R@Gc72VNavH~v*}U!p1QzN_ToG2F4@|1I0XvbcE#xwVEyKEQ)ejhK@fUYLutoXqeqhTS zdiMic0?fM~*rpo%?k1ArPV9czhQ*@F+ug7&Yht?}*b-pf{lJ#wt=$i7N!Ho@z!tB4 z_XAt9hIT)&C5o~8fxUS5)Y~|MeRniBGTGeym_%mAyC2wHyC;+Ev3r7TwvV>#0ltgl zmK&ChAF}JVPMW&$Z|m;UuVaVq!_WTy#cywZe$xm-cE|Wm@F%_XHQc)QjI*yg|DIDX z;cn?8aqAtubp&p`cJ_DIzxe$pCZ5Bs!*FYd-Z})gUikiF=bd@hZyxv&I$Vugf7V+E z;nqc)Mn)gG?X^=;U}q)nysLNmacA8H+fP3Iu5Vm+Kl)=u`SnwYZw+>0XwR+BP9g%qJusOf=wZvOT&iSpc%Ui_9 zF>`xo4kdwsjLsMHH@2x^6>1do2U|zMw>t{aX5;9!!4OmV+L7m7LQPye1s2*%{)M)LQIyi2p8_z!@# zPYZ1q1wZ&RX`CoTuq$YX1=^ZZTk;oKn#t{}LR&AmU1+=Sg4{M-NNY_k?+S8zvRL&! zgI9#M`!CRTH=^wayf}JGs-De_x8Hlmx4!-GCHFO`XY&CU3Nrg7>GGgZP-?4WeeInO z7_leo)Xczo%6)gfgLIG`db-#y2dqiWF~FvGQ15cU{z-Fe46tj?ef;F#PmVl2)qrJR zD~dl`36Cnu`m>YgvG`Ik*vbRqgQbmhr?c9brTo&)n-vA(rKZli!?}jGkLDHb#QA_- z(m+^-$xNNLX%(i#q$_xH6UVsN`@wl|b8~v^`dqIQd&}J@yn@b$x7{n9BLDzrc`4Fl z@Mp;v=sR;Z$F!R1u!z&rKFz9O;i=`U-W1rMwvbZeBXWl6BBx2n{|^w6FW}EOprhRmEl%eh89Y>qeFeO8juKfN_tX!CE5InqOs`E*%J=YwDGAER!bJ~C z`y%fKXhOD!&p##Yp7+NM>F2ML{`d6G&h&qgX}?7KQ5HShG@cc+C`zFzi%LpZfQ(|SUrv_Bv{mj2+oO1A-k<{X)b3@6hs?0 z7w_0i*(-W4W;o~Md)Z$0PR(%UuxUS2nMb%GI7=EU-qi~n)lAog z9QDjAl>CqEM!IgU95r$UIcJgg=kwFL>nhWJhv766f(>qx_C39ej7|%6-F?#D>upq~ z3bjt~xM{yRqZ_A8|3B6KRoDH|G~Ttqndg>7*L5|r!q==J-KxO_@^?`q&TMLfujKo4 zEczLnhWW+k#mTI}O3^%-SbXFSnl@9=QyoHDG%g&3WkPGlB}BZHF5$0q48|oC3m?0K z1^I%yN9qt(rS4|ZCG@!<7TfLH1gAaTt&|BEF1UmJ>JBbf4;Du=GY3}Z)HZ-Po$>i zcqr@ZM6!Yjjf%huXXbPiqM`rGsS_MxXF6_xXrN&#Zs5w<3THBIz^^Ulm&(M_S~o=_ zp4G8%Z6wD_P2E}#Wos!DxJjAl<|4@w{DF5`!7ZeRVTKoMdmTgK6s?=HIz&H)CInJE zFqk{7gWH*uVDCUq>LRQ2AiE1Z?~07oxlP*l^zO}AwdC2pTW)yxsRn*yb}o>~A(dyzOIY3G|bz#9*VbGiaHLL7fCH(N$tk zSBWWs&Hia>y&A0~?*lr4&z6FaGS`$}Q1L?8cp2H!d1FDBkt==Woatj6FxkRjPc(g8 zg1#VlCSc;_yh$;Hs4*Jy>~GDRj7hM9btERVJ8G6#4BAKv_Q}MO5=k;kPA5d>_rDX% zZA2y_c~W9n2De^N8U%4%joeH;qp+%sS5(FeV)r1N3CJr(zzIM~z#-Wba09J`ZMuVp zn?oyT06Ju$Iw{-;&gJ13fhWX>h~KqSNtj#JOJb`Nh9mqNR-un6m=GEP-H;r8uM|1=5uVvr&4_H;1_mRQDLJ zo)@aS^T5WAHlq6R=3uwM)x8S#rfo@KYzfuXJeW~YfiU0N9OgDqy+~mmy81qGJKA&C zd-A}B!6DdpowYN#dJhGAw0*PKn+G#?4ie^{?G#jd3iEi%zO-r<7v+JC&AbHrg63ei z!PScu?BVvgdXGGqv5$i=f2TRjZE*FThO1NdrBzgWd0-n3+40+ET+NhIGY4D>rb3k^2Wfx3bnAOQn@XPbf>Weq%rB+|+QaVkP z!^~U9 z3|q8;>fCv&v2@>V4s#o*HuKg^DfVd9YUIvajobO&kLSYAt$O%o-nu0Pc1vz&?!47- z_3O=HZUfb3-n!|hNl9!K)w%OlGY5RWIoPvvwO1D_M-YkgR*iPA3-ujmSI(L3vw7}B z7G+N896ga51TrXx`~xNM9Y?y`z`dEsj$bh!+~-bYjm!T)3hYMV##Y(fOk~%mSf(X5 z&z;DcNZ2jSVQvG}W+FS4g1J>T&z;B`4!OE1*d6dgd;d!PP%p8*F&95K*MGb*lNXv@ z0|{3lUwDb@P#=z0A?y9eUCUQYFF|J3I4~O#`QH9CM^*8rWc_hS)S9Ip)7 z-p1>(rry^bx(>3AW>yzcOX?M~q|U`kT~Ze>4GNUgBFPP9Qm7b)LhuwJT4h!?2i8KT z4oNMtI1KGeGsGkdAOhEvVg@C!6Kv~z0DF>K1BXuFbUhbUL)Yro^ zW$QM9=B&ZRt9NP6M!$*GyX4aGYcG?zUGE-~N{3tzVfvS(z3BbeBua$|QB$VLEoOwQ6yuUS*Ks6!H_j^%6KjB2V4QT_&;S*9KSb5+}iwmB%~S6dqiA?Ok#|tu0y|n0PbUftf7wU!?~2 zZ4S()7nV>MW?2^Dp1BNdqYUlC-cTmj_bh4us5hi+pu99BjeB?xXk$V(wVQTcm{m1V zrVvMBI#B*z;Y3tvo@wVR<1OV7$5<7Cq2nK*eEcKVz&1qILVJ`_T{hRlP<0~?S&`ay5i)Q-jZEOFo#m`HNlWg z4P%BO^`!O2Ht!`FbJ^RRDIqm^zj{$Uq1R(8_1CIA&Z*4qGl%;G z>T=%F%ES1~OY{65`W~~m#!J(#aZ{6&sgE+NYdqJz0xv#J6C=gms!mv)v&tOO96TXH zXj0>*UP|TwwCawUlyI3~idV|{t3-SX!8<9)qu^Q+atTy18*eV&=L)wakBY5H%IO=UTU(CP0~wk6dcMm57+lb zC6fxFS21ZNvtfBQ&3fHp8eAlQz1XifT+?9>Gewgob7w=;3gDQp;Lkm}@%0E?o~ypX zVQ?(2dinG>e)rui7hHg%UWX_{eHMRyr4O&h?e90Z>@*01CmR1%>q$UaoSE z06*c+;ri<^{2H^!ctB5_i@RFg=g(>`?jd1GC%hD?lvNJj?H^25@n7NgOGzg^1}IU} ziI1|;Y$QSc`AY6B_Dyl8+n>P(Wi9UXOTFaw<2CV+&bepwTa#zJIyNRwSf;>}6vvZu z7vSq)z#I@)Es-FLZ%7lj8Xs1}*H)u)ziGlRf(0c6VtWtCo?+;~28U-HuA5CT2=*Hv zLvVyiygdxfIwq{@z{w0Ai^p_-JSMnr94X24*o)_Eop@~Qt^X_Md}wp-0IF9>rS0V4 zRyG{l%DS=5@z9LK*l<2ja%^34!op#&6*@M+#j&l4$2NXB!X8anFi9_*+>S6IB?*HQ zO32`pCL!ejMGoa+7Rrzi+BikR2FGP2hB-G9o*NHyI40q#FWRoZaO7iQ)hRd}SvY6hj6*Jy*bjgop`NTRBK z`PH5_XZ99mS1-aH9CcMK>Q^tE_Ul^2`BER?9t{?+5VzEweo8A=fQ3Z36FVI|Z3}Bj z=yHVY(U5hB)XqexE3k67F7eCJq(_?T*U@UsIqx^zqhVlG-mbu^K?+)0MKNBefmU*r z3&F;w&?X|4?JlCs?gQ@H`ER*y;CUZU&kY+%Q{8$>o-{Sx5!LbamV_80th59w3WgCJ zFFYT+XYbcmsfp_m`lr&HO$_I}RSNu#saA0RoYIwB-YT`_MujyLLot){*eWH{*f}Lv zLqkcTOWho{=~k)H8tSDHyV+tfa)b5qU?s;_Ad za~r5ODQDBam=CIRQ_f8K)}_tC7WNR>=WJX|%GpecLt4tk$xS)K42d#$L35bfK($FZ zTc2W&R=GMi<;-OFo!uPlHc%aIl`_h%4F!^$VPqfvsG$K zO6j#~7IU{s8L%&E4t5);-b<(AL+vY&#d+Jii~`xv6lP9u;lxX{YnB{A;2=9siq^Q7 z_&NCzQ9YgacY2##;7+b`{H0#!PS4j@=Qcf`L#l2#Id6M8KQY&qrQVLrwWnBbMP|$_ zlmo_OY;%^fByq@VY7&9;W^-)`PR$zf!d!|WFHypU;NDX^81m}o+H1G$(Eo$N8oJ7@ zhrC2;qr_pHUC3Hozi19^tLhgp)9$k@$<`#yt*&&N_2M+xX1(~b=3uv~egSq-!5(iP z)iT${=w+=?OFR_kYVlZ-VZ&CFQ`G_AXvY1&+kI@cWbx?GRlU8AZ-dh`XV(=P8D3mWNkt(@HS z^n|)Rg*r~?cn(6s=(f7GB`0A!KJa6%iS1i>6b=&GugMs>KS;alJ#E@Uqxh7x7rjd} zM)Wyp@A96_7~N^}{I4>5x!#m^B-Cg2a_x}zinlJ)|C$R3=Th&vO#d6CeNXS@%pTOM zqbgu9Ucd2A@bLcFQ{C0Rg6dz?{gG}!2S4%oDchybmCDTgH-aDq1-g@8m z3!dC?+T~YEa(Xha6#2kF1?OwXltuiKSw}1LlATvGkvpC2OsFskwUUY44YGhgtBKqg z1Aex$2+G1;(W`izj^hH%cg(BEe#wDdpu{}zT?rEKVN?Tjk6CDK|`Vd>=`CIe^yqgBm;YOc&2nLoD99@3Fm8b z%U5PcU=>I?^Oe~Vey#RRzA_ltNV&;ZJ}8^6yppR4&C`{U_#CAxCl%+fHr@&Qwm8^$ z8UBXnk_b>Ynl3Y2D>O9%KB zCFVv8&Q9JeHQJCLhX5$a(fY&u>WN}KeYFo0t%vH&p`K_iHP6aKNW7zJj%o!TQCf@6 z4TfHziostP{{pUR#iN4q7kP}NU&JX$AG@P z(bow)Kc?{Y6?^RJ2R)FQcpRCbtZ*w4S!+7t9CAj($WT<7ASA1Pz}nC1mugbln>bpa zpxuBokP{bih8_v(z=>0?tNz@z-IKV+Pn=sdC-^5aniDw3M?jNE0){@JpL3$mg^)W2 zatFMKF9vp>3zDE?2iuS=^cpyQuJjz($MqF(BgN?2`B8zbj1CCQaB})D9Bf%}-|xNW zviCyRyE9Agd=g^hpcIRWQC{z>!rlp>NMK_8u8!ZW8^3GD?+ykWzrN!7F3?BU(*>7f z%#<(LoF^GN5{q*Q#z7KZ zrP}9v3q8eZP)UE#?I~1)u5_Ez<5q+2berAdh&0Sf4?&m#%9t7$fh-r14vK#l_y

K4-uIY zllHi_X5m&Mke%L@pZ@7Rs!$!f+iwrsBdv7FHGyUc;R+YJTN>_cvPxUib|mQ*LIEuQ zf;O!Y^XlqUs2t@}Cw6W?454?H-Q0Rd)VWyEDs!j~>fEZn&M73bGd#%L*0_LO)?#{k=U~rWog3@! z9K6{&Hx@bvTpF-i=RR`mof}`cbMO}p9Z(Dyx(*HXj3Hv8tD8%G4D&~E4BvL_-5fNA zR(5P-i0{3tbCW)Xqn$BC4elC4l<7Kw!dh(%VFP3&(Xf$hC0OEcmM65Ds| zwv0^fUNcX;_+j?NMG)k=JG~G$nZm zha}&S499{c6c)V;+3Dv*M>iTZstU6mAuu8(xoEafVn_Y_5Bo-oPm|ioZ7q*Wd#Bz2 z(o?9sT!ALy@HC6@*08~Z1ut;0>w#sA(9oe4TD2NhxC~&SPttiRO(Sv!BgG=eYDiI? z-BoLEGo3PzQSir@Qv-fPujm6Uq4Z9a+qF;tGr2?8{0o7_3@i;8@EB89J|_+~aQD$! z^X#EZT1T4YQ+x-UXPjg?8n-sCkzrxUFx4oAUQ%S>iEg9C%cnoYCrFwrQI4-%|9^9O zUzu@m#gM?|Z9QC}tfhR=^g&NG=nSQKT5Z`~n;moHz-TqS;}8$J8mTk7i-z(3G@3)qtc>wx zB4`;zV&Y6ICo~aqlmGuz#==Ul`N7l zSV83!ZIqw3g34=3hJ7oj+^P-53?yrk4@s$zQZBclaF@YDfZ#;Zv11(6D)j0^m37w? zy&(BN!xN6KL`!A;xKVzQNVb%77iDL$V~Jv%ijDFpfp?9t0f=BT=Trd>YazVG+u7?oLR$U>R zIgB?YlPhPzsx>r|6r9y3(pOAQLrx4>-aCBH>N&}5iX()*zB=b{HP6pUt}?;Re0_TI z%JkXkGkI_|orGePq>ja6lGMqYWZrU`wZ6&*le`bZ8C>RZv^#?v=%F_JPBAqCdC=&g zMnd1AAnW#HQ`O@`Q-DO` zbeKgSwc)-Nz$1tV+-`kKBa?Ep#d*87nzzriJ9%}^wmZ#R^PeIKYx7o&p+0vZPyBw2 zqZ!V+Ri0z>ElG=a2agOYce>h%bC1!C)|oE??gVEvJUz_l!yO`HGg|76(JC{K=?zn1 zVvA61LWfCcS(55y5Vlxid=HaCPi;=-VfryCZTc}Q=QItOs~dG?T5iylX*sL5!M;N< zlPX(pG0rb$BY&B!nC{h_JYO3kGEHP@*S{MRP57&p*MFmP4Sb@vpTF>wD_GA-`llL< zU;ZyfYGw99=19o1@c?s%c#|xl08@CdC4Q z@e;n6j^)$cy+l5#Ia4F{8oi5 z#?CT$YxA!N9~#GNwPYDutYz$0^_W}6bs=7y~^M4a#pMz zm(@-lr1Z+<`D+l=kO)*iE1;%fH%`VIAWz8lY<=f4d;vP7ERQ91HlW$Y!D2P+>=$jvyg2)Qu2m>L@0eE*GM#Lq^8 zQ8evIOgI$JM!0Wn#k`?X?sS?0K?K@5L)w6yng}6RBjcaO1`kI`YEG@l4ckq$#Lc$$w`2P*eP2!;grm=l8j_wnvdaZNk#?qxRiNhrmR>1ey1sL&HR4# zUx1I7*qK;Vz~22VeDKkYLR9>~whl||oCvMSV9H!MsVNS?KV9!`h)D~Yo<2GiYbneK062g4#8MiTAr9VTw1c3qNSDSPE87o#gh*x!T z8#m{O#Ugjia0ATbhe+Z%vD-$uA0_f+h3$@4`&Mvg1eiyQm_akIwy<<| ziEsk@baEp?0(oPSF6fuwM55z|YK(=v=a%WE=hB8VQq6Yx_AHLL9%F8D$-7~igRDMY z%eQL&i;+<62IGxc-*}qJ2}jH{sncLdG@TXI|N0ak0|1}cT3W+H;0B;9{-|23OJ?y$ zz1j*sZf|sqLRYF~@prN!ZH`D!>Y6n0dg7OY!Q!FKMAGA+uw7j6}!B)iF z^4k4s0Zm4LKd*OoO)2_^S__UPTc?LK(6}cL!JZF1pd?&VBCLFgCH`sLHjJftS$TXWqz3;;1^LwuA-y&)>U+8p~;<*wnCPl44#(% zs~vbyDZAo#9qSD)yfdikXQ-PWi3+;py;G!VOTtY}GZ&?rX0GyX&HO{@n&f)36V9c= zb71mDsB*1ck82IPuDr!vYq;N5;zf`(=~SHwg0;*6G1j&%L@`C5o~~^-pPe#q5?F3w z)g@&M6g?Y^B;}dRa5Z5%|5UHC->u@$xb13QNc7e6mNzJ>JMk={ z!FG88AI%v;mMi$H@8!^$msb|Nmm^-hyt3fE z9K8xvQm`{ig1GS~NG&f%^t%|s5?a}~cuiw>RyL4ZvZUfkIcYgT3D9qBOr`qHcUGcv zlHEVUHI_|i`tqNpZC47YcX{Zzxp;4?2JaCU_`;WlM!Uak?10gOqbjqEAM5Ce8p{xWpS!Dx_ zY&%U^nk$F+xkx`Z>nGpB(Z+9W=fxs6{w~o$V;A0P=LA=|t^t~nG~I4Y(Rb+9Cj7<} zAgGlHf%P1wg6@X3OmLEc&9R`$f|Ez~uj;dH?P1gia9%9g?9V0m1?>ttrKe@e>LbT9RVqw9Sz};q8oy&}n>bRz{m*0p=eYQ`J#4b9_ z!>DOGySV)XjrS$_hvW-%dip!L90p`N9xL|)%}J6Q5q)8VHM|e0xkamCLtJrs@6mO! zW>#$5zskR>mWrjmpgC54PcuSLCaU%){IagvuV3=Z`e?tPGF2*Pn=19bCErvLy$N~7 zJqru8oiT9kky3XwReMKDnYzpcp?FbE+uj#o73DkLa5wYu8RgaUTr0UZrU^JumJil&Q}nHgB!F`f#l87nu9uMg7V zi<6BJ@_%%abd6OjzetsNEr8{(wXjQ6G87{#%Qr_qvd==M2#X!=*`0Pf<$I_cPHKcM zyB+M6QiNfD|=E|AO)}e z?_5ToowC#^)%*oOh8Nw{IMr9~5ur*1*sq89rNJ?6PTE_sCVL@o?a&ULXmZFPkRq{T zOk4p2WUP{f{JPzoX#K{9z}jWfPud_Tvo%gLF3f-39$%9RAU%1SFeqitc-`;LD8P6x0=uwpS5ye6*{eAZVhi046ltRRH%HWZS$(6pfB!e3Zx$q!D{{B%K@3J&Vwl zrl_aLGb^6xDxRR;Chd`wjSQ}yle(Mq`HIoYKYx>PH(rGt66Pb9rb3QnUI^&{7}Y1L zm@{)S^JdYR=d68AqpnF+rhl*Zp|>GVv!ic!r|nEFln*ioo2UU`#VydUSpnng+>Y=E zE2!C=pSA+%CAg(mP)3r=zBZi68dj>PHkb%KypG zbT;y04>9R2{DnjCxV4xVGp^@-n@BLOHDT+<_4YCC0_#TMr`#vvOP#6fq7PbbuDg^sFhlsntYW+8w}tZbaJ-0naIq@1t=uFcw@G`6Bz9WPHj(iV8GoLhu&ZBX?B!CKcBEEi zY|#(Q8>0>Y)v4k^+7nA+#RQlbYhmEE#tV)o zD2Abisn(JSjU>Rp=lPpUHh4Yq)THGWP&+BMm6mVgmI*Z5ly^NX=QLveFTYjVjE4nd%7BV$>VH)hhP!ixrpeRv|W}!^yXsNP73xtE6m;?X;FS#Yk=P zTA0wdxFY3AgN4frlabfemSO7f&+Qe ziB!O+!~7%;JoHVD1BXwViQl#0`hIu1!Lctu`XsgKQ_X4;^lg86^3m7J{;%62k?WLL9s08Dmx^_I~#DtV1gd0m805!|Sk@V&qY zUoZ3%zV;#vAbh4j?{~!>mT3zk06L8>qavBOy3xt@x`~V;9j48`IqKMF9z?0qq(M7`bcA*DVN{Wpk7%Qhqr zk@kHg<}1?vEh^w|{PJ`!DN`$3pWk;4%^Qy*9fNRwhij06p; zI*^+hd7)bGate`Q8N6I?OFf)R*7p=G+bclVwqOV6eNZF~ys$Jy_x$Ck0xa?sDGN5B ztjS`{(5*9TuV@d?6dShz!tge77$xU(*F@K&Yv_9U9l^(Ic2hkv+cpD8aX>U&j1k9D z#YJ42<=X$IEjcI@^mDG$&vkwMJa0fxKmz<`!3RQ)ngue0pSsto8y>rBJ75=mV6RvZY?eme`Svf)4oFP} zD1|=j0>#Fi5nss)hx{H*Idf!+sC$)G+!X(fD^^Oq)*cV9MAdp=MO-ciVB>%Tuu;z6IjKUFijxh9 z_HtF$)GgsU%^a|(S~f0Riu&ihbA!$BoUd<9!BNu&b43NkME?HQ%+4}pv{oM@yk~7h z7#xj}5CzrPS_VjDJR&ZuQbuVJr9MI`^?~rUUbSK$hfKU?dupccOUVk#^#Fcau%Gz+ z-ETv=Sme_s2jU#pTbyDZ{P*}?I6I1AxLw1r6S#qeT7wG$-d4F#a1u1)>MAeb7vS&h ztbpCNO$b0iV`sJvrq_Z4IJo4ee1Xln>%?Y6!Z9w+WBMrB+j;HKD*CLWCYO;N`N?3 z?*9qAuC)CDJ?a77bj}v!Kfi90&d(WSn!xXIwtYYMs(Wc^5a&>@=07hmOVRfH9-hH@ zW(J?9AG{^(0`*yvw+N6sT6~I)okXUe0NxH#B$}Wf%s9r#f zgwt~#S;$AYXgP(3(U5+y!zihFnzi(pEyI4!^^Xa9UIE7mdmZ)7#l_HH!xXVaV zBhUgOKd@uK%dtcoS{T2V`cXNy|Lo0YUr~(C%+25Z7gw;5H8cD1 zPn>?ma7IR#5+KjZA2I_6r(qc}ab-dGJZ;i*)Wr4s% zk^aX`Vl#aQ7Z!;oQ^JM4fekJ01px=lD;pQB$smYwN49SfDMtpE{NXc()Fb>gV&%m1aNkn*cS*5a2l6ULuUn)CH? zC@AZgxf>V1pe1)>^B-EWfv~cTBHIZE&e)_c)AEsx^Ru!AtxBndeEyPrZ)jM7Ckr&Z z=CN!SJqT+Qn^w@}UlTMyKcEPUJmx7al8JW>WsOee;9VrKX*i|Oab(-IZUzO!GqION zV`w_Cn*KDs7LfF*{Ss7&nLbO^1QiBbmz`RehD-gGU@Ec~SWu9tdj-J2@C+Dnmr+@s zVio`a*TB;YoG~RS(hB5rpgv`!>ML9 z*(x4yL{n@)y>MqXT-PkPnjz-4UB?iU#lRX{To|%WMEj~CVirKyV&`#ro2-=8**f?p z+CDol&8>)*|15>6{5swABLn)ilhcHRE=#aGPC-uQ`o z5+o7d3cZc;^Y9*%LvkA?)^%l($p*o@gIs ze`C*N!GnrcF-Tr7!ibNvo-_*YE5w?3Mpvz9^Gc^?Ajo%X!AzP=Aj8!^W1$>lS&_6Bk?U{WvK3s0c zWF9HMU^A}YgE=gEwi=jlzcdo3W{6k~oUJt-k*P}nN{aTlCY(1pu6O#$bfnyRK;vyH zQ+>SoOw&8IcGXsBRO7Gh7wcxS7pX5iWdCKY;{l%V56cmo`07)Q#>ls9C& zynH>_8`rP#Ld%Bg3tCK0;uPsri)ZE!ZvC;au*4WddesGdZvFhigJ;%@5x9Lm6=9*j zkX4{KCH8bppIEwK;8fdMF9na!S)c#JqQ-|S-sB`D{?t1?`uUU7BIemi<(o}PObwVp zb)tQhh&JLDG6V0+TPKShO=tH9X(lR%J9NexeE}X5p;>g`%SEjw0l1dPRgY!~1Z?5H8XAU0`v`*KYeOYU{E-!7J!G;Su z-fDn`Cw47?AaG$xW`=gDj>=HR%ShgG=pWioY&Ag+bghU}!h`V@LKP@=ttC*mIo(@N zGIx9H$qW(CC&f|5J8I^ngy@sjB&_uFWwFHWiYMzb0!C=4X(2%7bvXUjnfbTwdtZ7* zYe}}QSROqZoD3vt=;As|B|8|X5!f|#1p=tTww)Bk;Dlg-q$M^T4&()Z?*;xM(0RG} zcJ(4Q;QHcJb=cp_)t6J%?f9F@Pwi9;uZ8cfY1nw5wmQQ{HC#MV4k)hJ(Rb^5`s!>R zu0~r3nfxkaH?RRbC-;5er|ISJIMWL%wXs+28exm3gc)*EiJ7RtR7D zORu^B(l9>Qjk95$L=AR^RK8fmF#nO z4da8xvOV=&!K^eRF?m7$`o0NoPeB{T=R$5jmVl|iUyOdgwA)FOMi&fjK>nG_%UYaE z-T6nMT>j>O(Y-nUh=!yOea=57M0EaP0QmVM=>kp{;tmEnT>`Y>^b%B~=yXZT4J;C) zf4RpcEw{Sg?;uc_LwD1wQ}ZbTo4F5xyYdV&@4~v1dt7uBiyfb8D31QZq~>uEE^be8 z6`-X>M?|;JmJkuf&2)~6pYRbyPHcr&SGi)QmhYK(FtkiKIB+*z$}G`bfb zuju~j!(i@%KllW?kpbJKz7cYQ`WC7FLGP_;|A02D19NHXG7OBFeIv8&@tK5cwNb&_ zMw+3HCi%m*o6M{OeZ+c=jVDO-rDZC-z_>b61olOYky{eR%n)-tzeL$_RyHnfEvln9 z(@g0`vD>S25gBHu%515qXpo)CL$QEtq4n???J)@kq~48d;%0?Sfr>@j+KuG}8(<19 zz`54Zvr47<&iS%G9)VMigRCoFaXHA7y=JEgi-C@CIi}U@IXSDlKg?|1C90t5HB;R#_7BrX|^HTiM`>mE@u;kj-IpV> zaw~Ws;!5osvTnm_Tn&FOGLwuuu0k^2%`ZvDow^3ec(v|f(Hn{OsUOjm>WD5OmpvDD zL|0muj3D4r4{O2(4n`wo7s%0~3hhIo>B0e{g3N3;7W8!)Md$=E8xyYdsWjy6s!c`J z4Fo(UuBijS`EovMAOrxROoLo|jRl>0nHdbB<(?oZs#@m~&@1Qnc|pQv@=Wj>;YD6d z3DZbPa!eQ$)AAqb+0|z356mXhu+Y=yLI%HL$SMa1H5J0OGWb`x?ssrx(of0-om&1e zgx_&x$!Bh^ERsEDihqogu<=(q!a+XGO(vg!U~L}+gM6AAM&=;PV++nfoSR)p=T}%2 z408@|k&w5lnsdGL%;>}Cnc>!#{V)zraGnu8pxLzWJliktOl_XctvJjy!(?TealV9| zgf}b&6dCIy7*E1$)TS9p`{+0mlQkC^>MvN1+fZvBHYr%k+NM2P!pvn(3UNI~Ma#q? zbxwomgNZUIT;Q9YV+wlnX zcD)O{kcAXd=NXo5%DABdV=iOckp!^46j3*ktG0+ud5E=jpbSJWPHZT*Iv z#O;jjV;zfDX(7LAI|HP??uuqpApFT2SzR|>o(Y;I6T zbnX{#qV5c=E&NaY*ca>tu!50?`et7f4vaLmys<8)^w3rV(3c4{w%MjKGb=DDLKzB@ z?zUj0bXXDrHtKK{=pZzT=!KE(jX?DMYLY!Xf?D7;bVjOt0GR&KSJTvH3|gQmbr$xc zi((oMr8Xk;A%sRVIu@jm3Gk!T3idPxYX!R~AEXt~TVzAzbvyWFK?Szi?IB!-7BYU+xG6?@ zFyzvv`tezQC( z-}SI&tME(9Mgu#!*EAF)oR9TG3!4N7Sif{j-kFZ}GM5T32A*&%R1tmz*>tJ3L*<6= z%Ixi5CNvJ@4Moz0xf%B4e^7l}i0p2ZIDAW_iO(OAi#DC{Vc&r1lU(=vR}5oZcJHrL*BANzz4H@W=P0yejSig0@n;B+d>H}H}_~#m~>g{L<{JK2_Aav^%#?jUQ`%L_NzNz>#JAhN`OjM+X~lK=c6U7_T?T;tT0{4?ss{lQeWgVrOt zYpsc+xAF3`G;3ev|EU?9Aqx}>Gn2H&`Huwbw*4VgiZfblgwI+N^*3yNARd#|ne19# zjj7d*cS?9jW+>#LVdG|Vmoj8Vy)4R%P=?IVofxvoAe3|kECe63m*He+z&X3h2tw5k zZ^C618D9CQy_CpWCA>D@muKh(SJb8i-GnbPHV18ebi>lA;k@r_Zot|Xuk z#H@Kpz9L8WT@l@L4Y4QqVI!d1 zSo~Ifvz2c+<{|%IzGS4guC?hr0I_*-O0jgg?JVcDtKkYh?|r8bMH`JlbkA7}AZVqy z&&Clltzm8!>t>u4+Z}A%p0Fh`pF-hXIoR-;D2>+tW33rL&i9Btu*2aZi>)^pJ5I~ZzIiGzrPw~U z)HG^sU;E^_#;ZJmO70mlMg@qlX)Bi9u=*Ubfej8?P|XZt_-qC-qFG){v~Iu|jUJS5LA`Ug znZ*GQa+}F%Pzm6_(+6GpML^ThxXpym%9<%3fo%lESg1JI^;1}>xz3ESg_rlkRBYf7 zV`7^6Rw}dY6Er@Hn&IVeCd5}Jn2)4N6L&5sj#HHmU-zlf#wJwn1MlxvrRU}e_FYhy zc6ISsbZG_8(Tq!BCXB=~?XGO>#gUiz5uH80w_xvALp#X#Ce>mR6#Hx3;;0=YFSOdGL0S&eQv&rpW;k9fC*f z$OeHmb$nFoq;Yn^cHRJj2e!jHiP!d^#pxAqmvFKctIyKGKV>j3_sdAZ!!MIJ?AaP zAJ;omB$&_YJu&{)akrrF7X`Y7XBPCXwTGGY$7(@quw)mK@P7fv*Wp)Ot~~&7)#^-i zvmNXTM8ZDmi>~il)UKR%U4EhkN)PY$8(c#dl;BqQUdUlkAkPf(W`;^PFl~Z#4!RAB z4~BpO{U=ZuWNJ)Am8DA;n-E_ZsCY14`1m)k_-OPWNX4&Gguf|2#ItDb*3|>~CLJl_ zb$hEMUsp{KbW%k@??72hSFmUayG#pE_?&E=YU+wPfnS*~A5^lQxT=acK?v~GbT)`% z$-@fYI9$L9tc$fq-iw++THepEic3`SCg%Yf&4{US5mWm+l@KYXaCF^~(TnJH0e-ZB zCYXl(%V`9fP~Pu23t$GvnZ@Ax%!e(S1_sH9`beJQZvIO{oXM^Y2;r@Q5Y*y#t>R2x z$}P6XC1`7XQ6?r^eJ!mw%H%nR4>F1D-J~(7vZWu0z&4jj<3zt5#OA$!EUqsU<{G2e zeY9#3CLzexo-^K>H$?ea0F~Oys@M|Q=F>ROo4UNL6IgNv6Ooc-F|5Qi`2hx0X1k}Y zV~rxQ^l}6;dn}+4E(dq!KXq5r#US^LNF+uYFEc733*71q%=37!ZZF{mDD!{xRd&H~ zu{J@ZB_yVY3~PAhwR(lHuksO#vRx%ot4G;VDI@%Nz(9;qWY}Fx?*JNgEuW`(-#qQt zwk-Yyujs%o5xP(xL!H^D^uD`TDXEq{Xs_H>wK8ABKL&wi>S9ATlOoWWjXL=r0po0**> zF=QC{`w!Tn;T;23Q@WxYPF2U1XT<8~>O0vd?yl`v(+;XMvS#7tTE~r0CG3RAF)4s5 z=tqv7pbZbkQ?Wqwx=03a*&0;jwMm_as4<@UoYow*w_x~Xp;_+Sjt`mF%9d5FzgQ*} zUyQL&M)kZ}pHZjvP}_<0IKNILrGQIzcp3N5ZjHvvCE6I#{ut}SP(MQ5u{H6tw3EPQ zRUL^2ET|8jUF$xStW~~XFB`ZjaKCO6{JJT>@a?R4>J@ws`C0L`>dSjKT2J%W zz0)SWhD~jkAGPxF{JOV$c>t%}Y30NDtKZfA{x&OLlHU=^ZwxyaV;obfp@)G zlEjK1%8<;k=u|?^)|O_Wtw#SOpfpo8HZx@1pWPv!06!$<@WT&22@R z6>A!~J#rkr&iXi(zwx?m96tP7;e1hkQx6XJS^3HNn|pA+%gUGKw_V$f!;e_`Df#;i zhld8@Pzwb6-yy^u3eNxIMI4F5`VohlScrSCAgK_CgqS^W%!n&zjYhj-`tW5|Xc?hm+mi4zj@;2f=vV9|;uW8h0 z)g~L6CHbx%s=vz0r}7_&A_%Y=MD@7$%SXQZX?uQRq)wW<{t;X1Blfe`)JF_vKD%k~ zh_%O!qK`=IUsr|YDfzELmm>qX-^v%|2YXQQDJvh&@9CKwAF%Qz`TkHI8Pa>Kd_14) zVKCdQyqUkUXL4+|@{{v#2gVlRd7YI{z~}FDT;?`xZonbZU;RWEwNyV%Y9j_2c84hSMav#;a9=C&ve$3@3(p^ zvA}rH9&8t}qI|`X5}D%WC-I+30*<<{nCf7~*c zJw}qb%RrP#XZr=?Hd^QiTsweSq+kMf^auj?kh)n3TqTF^2wb-144UamXoaYrdk@^r zzLaob3_IdW(!>N#n*{NR@i8=aO=}joB*9FNHxb$9_b9)OBafG_-w8P4$m0@aauFDz zjMpR?V$5m{dp;zL=@7E>Hzb;Bg1?gsOCHkp?b#&p_*8k zey}HLZf4P6~OCb}n8ZU11f z;-FsL+SRM8V2G>4bL$N8I0ge0YA|-(b|Qm8*4=)v1KnTW1@=OG{8(8GQ4a!p-;O%i z$AoIu75ZTgEN1hOVLlF2Pdd!I{-qA{vC=(BmHWXCsNQ&Fun$l7{X!nP=kN!idRG^P z922U^blng0Nlw-O{;x-rK*xb<&L0xYn@$MTW-s=#81@otGVVDt*vElto%jUUhmK!x znu*v8b3pZdM~3-0P@Ox>8@nXXu~PM-K@<{%&>cqx`#4a&#KGPjRM+EB2Nw^5`4lIQ zZAXUrI8c33pz2#rgn^h%-Af^4R1j5Pb7ZiO1Jx%x*xQevs>%J{&p?9a{kkK=d>p7= z>M-v-A*w!U5ZHmLANF|r1gsy%yg62}c#4C)@!fR_IVN6x@*tSe!$lrHKQhe6fojeU zGp2WQ9p+^TLR?Pk8D#{KaL6arwr;u&}qNW z)rnW3{T0Wi{SEBIvZ@oe2TjU5aZ8t8b*zK&gv0b>{>c3}{9p{!QBE_k8?(o+qntVj z=0HF@x?mop!pg~lCm}l8bj9zszEt|WjqtYu!U3k7fA)*BwMHNJ9fp8?E5283H~ zkA5!J6_hrzS$^!progY__H)qO*;mz0T;Tc@+md9EY?cZsM z@iSg|SYjj@S$s(=TxTMKJnplL6BEfrOh1SJtxghG;^>RExDHqTF*2Uy8!YL&9<YQ%LtmG^8?(fobk$zvGOyH zR@L_>3-+A72te1<@o?NsSWc>S+!qpsUF$fDP3m}44COp7*70U}&%Y5~p^n=~Y3WcM zub5u5yWdUq8p0r}v37h}-^^mb z$$MD-so45(`O`aWT8KQqME}VLSiZxH$Yxl6MJVC=$&c7uu=l>|n5Znyla;!@y2EFz z)05nuKP<_A_pOj;*K9d@qOlZnU1)*=@S6lg`~=m6*7OSsxcS=K-+uKyuiN?8B7D}N zY=wC(&*l>cr6Z~$IU2cD-mO5LN0>A8S?lZbh8>vAosOLllE=D1ZJ{eH$K^NO1fYZG zA6t;huf;kv@kNLI`V*{&^8jI=3Fjy3a=a)VI1jJ-!I9@-eVLb0u+U_ihxbSRW25kn z*L~*u@44Z@8$CacvB$%)AJN?P9}OrxZ1<-gyY4@tD6cLu>t{nJ-2MK^2qo#{l|qxT zS>E_D!@^*Jbgrgiv;1MiR5}x=b^x(`L@{Rrh>hmh-&KAg5bh_uJ!C{=xC83CVFALW zE&=)%4%X)RqnHC57OrYZ4Xn=|Oz}%eegp{lAp!?t881W!zHoQZ4~WmvC!g(arKsf9GOK^x5BX{mwo1*+tw+ z1G|vx>%EA+tELxn2{oP1tvDw-KzZM%?7MZ`s;cL3{n;n2NKAVVMbG5=CNEmW?bj%h z%J<>B?JcQ%`cNw0w?AP;1-DWRrSo0mMa#IQL_H5Merh!`5qfCHB-*kfhP6ffY-e))$K^Hz! z@BECFXrwg6HdOwShKdpmRW)Cm%H_VmbX_(GTSu>)+jQ+!&TX5TghQ8dUf0I!^VM|o zan09b)6EB>>ood(rz1z`LTeLYfBOCkT~g76u3z{|gVD8mL3Ew|7@*67fsYMcc>Dso zZo%fEOZtUE_oX}MzIx|Zzw*GcK1*gGwm2fAe2$}N%jYT-i6sd|^Pjb%!6-5bz)J@m zwVM2KfCo(ejW+pL4I*%jk4y=%se_-l7R9Eps>G%4^Ad3>-qE{(szv${(4RZ(g8_Y# zGpPss9l`k;w6DFGg#+Nc>-ACu21koNkroB$gMXJ{^FBc|*eVpuu_)4L)ikb2r_S{P^OR401vBYKCUl;Gy}bLDjFoz$2eb zC9(oUw7VZT3>xkVExyHHQi}^KgrK^R3?(i?-K>Q`j=taQT+6TIEzFawJ%A zhOB9Y*`O9C_MZ2G0ofyz5$a4Vg+>3_53^9%c%mP{rE~N~s^zuovK~;`STIWHF>Z=m zBTqB)=tpng_^Uf^`skJ?9ix%jQ3&0I(q*I$q@y!w9{pTo^g~C@V3zV-?C*|okeYb=D5A#YmqdgVn1LGz0;_Cpk#Y0RXyE#<>$U`Rf$(V z!w2_TFBv?zn%A1eUkVTm@Zm6ank>PGgMUtQhR+V~!#R4T%FbozQV76tM?>0y0Hd`a z@^9PwhHKvRrZ3#TQqzM-(%{3f#O*$ntL291OEn)(l-Byle5+maqn}_IpOv76ZG7TO zpZkU(Ra`Gx$G>*0!Z0GS3>dOc85i$oOw|4-)Fp{7X1j8 z%Uyepf|9D#|qb^7xG(C>9>Uzpe5yf8ODhiU#DuU6yvUx9hBS^cy@ zis#XD+<|8GjXKDyZ>D$nX1`gD5f~&i@kUA{_-YnE z97j}tjlZL*uFo{5KKN~`X^?-L!F|SK$s28BY%gy#`D51Od!y=L=ForKzU50F`rvmy zeW$JL90POg>{l7Y90y9AKL;<XRL-@AP+s)jxNn{>aA_o_Cbm7}2P_ zypT3_^y23I-w$k{GS?9|wrFH1y{!wS_kHY(*KNE1uJ=9dQ581>nZz^U2oE`$#2fE3 z3LP%r_2+~`2ua#%j~gob`>gAFy7-zBsZtmiwGTFiFaD1}hDyo7%WKJh&QE z3N78=_yglA$_9$oJ4p9H*lAJxjKS4#G#Cjr%g@GYMr`qCK&RMMJ;JW)<*KG%wh-g3 zEg5g#7oZt4yYLK(w*1hF6eacvV~%6xm;Eh^`W0^+ivnF$%o}e+)c5Qp=e)f!;s*T{CRf_kg2-}IrF(|xFV3-?`BlW@E;o;Gq{jL>D3 z#pW)j4BPcG>fmIyOS!zpiHF=QvDQm^D!sT<=S6%@Ov;6|8ed2ersVm2Z|ZAWe#~iq zU8lyiJvFZC)QC;3Ev;C36^x3jBNrEOb*d3RQ~74EQ5zRS&qsS|M0!>(UWrJyVCrn_ zIr5EHVz17>>J0Kk%IkcvUe7}1HD>&+p~G)+{U=c={H`xuME4fgW7)7895v{lGd=MK zo;RWs7I|!YSQ!lbw;HLqJ+%$>hJB_-+I!j*rOOK8Ti_pZRmtvnyU$i>Ohjc{ zWLIYceN!nD+(U^zHE`=GP?9ul3$l!V}Sih)0@Og4Wc@W-6Me*+9Wct^y*yIdoGQ1tzk zKQi!62r~WvTwyxc0H2xfmU*-o`1})xn&e>3u59w(nFJxAZtu#fgOsv$&SR2xgRMl$ z+)n#aHI>see=XR1oqakM{ z=e}6>zgUQJY#H2RVUayO`C9ty6!Tblo*xRYZ`ThR^`X%*4Aa>jJ2eI{9(fC3DBXFo z&0IBpoGRx8t!$9u#y{k>hXt*}DJZkTzS*6wNm6jz5+J0KruPClDNj=Yht+8Gtzd}? z1cRUJVP%{Z8sVzmd#cLle^t{{D0n(OdbWMCieD=m+p{&PT3M@?9XqPP$`lIkh2D}C zlG;$m6zCfk$NjidOT^S%ZO^CIV;kGu3Ua)97li!D6_x{7cV||2t?G_s#`v~0n1;n{ zoq$`m&Bkz9=qlNQDAXCONr@365Ex54aMgUp0&B9TN_yE<VV9Y>`6k(bw}0pe&z;skhO$HC}Q?FA=)(gHguPW?k1@}v~-5(9s22f7#bUN?=0kECJL4EemGTn>Vb4wPg{H_4jg^(~~vhv3jma3_h zmA|M8{d66nu6&rnMn4uUCAj)sVX@u`LnOGXPvBT)vs{zf&kWLFIOM;oMu5(SZX4^< zL`?HvisuOL9Av7=!s(@Kog)ivMJMX;BwvJYm)V&0etVIB`?vNjSuxZ+G-luOMfmpA z9`aXiQ4xQa3_$5N;!oi_(DFlxjz-EpgU4SB$KD;j%*9b;h|V(j~Dj zF^NTP0in2GVo_DV=pt2W$H+xi0l~v1W_5BX*A1M<#2a?3oWG$`j%MwUqpFzBE^lf2 zk_aHQDDguHU%40inWE4m^&;=A8zwBj)Kd7urjUL%c{b4vK)Y3e{$C*d| zftyX2BxhOL9-e8u$POyxx$A~fIyrbOB?AEPNn~|C;Pl7|eZYxgdK5n3d`q1qsiV?# z%p)KCtG6(n&83{Y(s(Wldr-qxKM8V6_bXdCOj@tl(TmsG(Th68fLcE2wVac1oZ^^X z;dq;Kl50{9h4aIH8~IMX;>5X83Op|vgQ1Sqv>(zQ@&sZ)N7vKO?$ z>Ge9#UIdC_JK=XlrMRMJvhJg&OFKLf7V2e_(qQc=!+`reka-|@G%S-+j6@id@gAud zWk}jBL$tqDl_?1VB0#AxU05(mI`xl1GG#v=8z`EPsxabOKm2~!?&z3d;xthnnIHoc zW7Xa0Zw8*z1w)OzyP<6+S?@-pL?kw|qWm=Zm^B8|ts|OxQ$?>Gw`W0ra zPP`ox@yf;(QIt1BHhKt)bLo(HtZw*pVO>KbFhllHd)X|^MgtQQE>Y&3;J}+%`Tz2g zzG;Ge4Op`r3j>De=3LPk>^;)N&v1YsM(|9drEZDvM!DE&K9w~xu`x}DZ24ah91${3 z$LNEsq<)}7D6>!tbpO4AZpfjV1}4H=4W`mz(l>(17G;2mUQE39m>{X}(;iwBF{Jnd zL2yL{fgRCH&?d^lISCA?{9f|>;hnRr74Bs0zHD3Rjs06@tQOok3-Qa?I` zhXNHvz`SzvkN0q%90z594xOq1a(c1ywlkWH564J1uUOdk(QG%M!a%PyucP!JEnArb zB~s&tAgwm&PO^0;{;wE9bv{bh$F|>;>jSxAt`Eck3d_R-T^}ZXMp^QU+TtU>^RAB| zUnGBQ)4I7ng2Mx$Gkij>55pqU0vX)v`Y==$ptA1z2oRuR3#@^zk6M+zt`DnntyS4^ zee_h>3qmk!69azSSCLt4F>u;Hq?C`Y0cLmv$f;vz>MtpI?N6o z=<9f(V}Cquz7C^e4byMR*AXWD5q%vt7LSUrBmHggb^Kz0uOo$MI=&8dc(AXd_HE_s z(6=35hke`Q>oE00)E;HtP-!wx96CiEj?N7noT}{DoE!HY2k9QWb0fGk)QSJIl37D# z%an)8pD{)(U%x+NoYH=O#ssA`f5tGn>l*xg=t;d^3^n?H1Z`oce2O&*i)gh#mY7_0 z4x-yu9t)|w43UtP6vDm=5$CqAK-MD>UTQe12Ct2SIUVE<*=V)g+2wRF{|20iQ_<6wOoe`@!y@-3$my`y zZ*e*VI!FHtJ_(!-!6kvyA*hTv9SEM4ZiLez^0CUnfYU+d15a@}1ouP7O^VY&LXI<5 zdBIF%b2@aiwTN>oBQ<+ehro<&AWO$V`2`6K7Jst{kJGO`At4QQn)7(yTPjjHsR^p35 z1?vnJcraY3IIQIj!EoR0w!1u{;_NW2G=Htq^~uAY|5{I7_2!Vu#_=_5K^k2Rv!|uE zxk=N}kG~O%95`YlzSIfs+RX}k7UJTY3t=7+dnyg7JK-toOS7dt9ws`4bbe&Bm4Fnh zZ1^S8lr;v!?4Am#CgA(s6&1EhFK=->H7AoVz)jkcX_GMyIBpMB0NU_2e0Yf!s1Gl0 zRynGQ21nGx(%Jc58(tPAYgqoZ`En$PAUuQGTCmFddLL5y)(}t_`PAVyuPY0@1Bv2@ z;F?RI3tYpd{7yQ=i%zwPuc%1UGDsGQ(w8v@UfTNq*?a$BJFep1clONQ=WLyGByGtu z2xP+SeU(>7_nF6mGL|5`_cW(~m`hSPDOZZBm#Xkb{z%Dwc{t_bQWb&^U_b^Z2;zXb zCRku!Y``W8kc+~P7XiMB_z@z&fSkt#5eNw45XCr&$Tj$VzTIoq%e(yS9Lb2GmWCHCmd(NI8>_n0>$EM>dx; zxn_k;P)uW0r(H@>G8Sy3Bb zjh^j+A24(Ukxw?3wOU0zfgXr={+&`Lg$n&P zl~}x>rMJTFqequM4St8|&0%|~*;8!BAqN!Zp_oQ?a7&b|nR?76)1)4TR0{eqB)&IM z&<~JDY%FP1(#jdy<1B{6elsfR=V8jug5ZT&{ynt)I=Ft0HB_<#%)D>)~9b9Oy? zg+gV9kWs_JPc5C1{s*JV;t&cE!NS#u3TBArd$JWp~G^#i?zwZlR zXWcAd0XOHLbZM6eX->h4E0COC&FNm9GN_4PQ5kHYW4n*1UnW~&z6|q0Y&~#z3f@B7rCTX?54e9H!Lu%-p$Jc zGq++dEL$t|f_}APFSxzfS|;P#Si}e|+pG_^^(*A6m_QA=EU2yCzgr(R2LZXv0n$_J z+nQG;3qkrxvScs^Eu4tBhV_m^uDze=f>Ixc;@W!qLPXE|ds&Bwo_6U%$*=CG8l^&L zJQPFPG201puCFH&!y_!_YKKeYTD3i-IqURy_YF9FuPC5$e>*KU|1#MaY%>Xak`G^9 zd*)(unlXgu>X~Ar1q@9Sp__DYypG)i*p*yNCF}%6loy_08lDBLL9iR#vkVgj-!V)X ze9ZWSgP&Mtwrm~{({RIMcgd_FlE4hp)NX(Zdlv7q|Bo;&2g&VYu=Lo%e&3 zN6M_%)rVKe$zFh>IS^uEPZwk(Yi3eB zC2pAQlF+iYzT~#9nv$;)c1XTT*dh5gM#(1!opH0=X~GI$vx6vFIDR9FT94TXh#1}3 z(_*rkojstGRF+q*DMB1S_Vrqrm%3gv%*2P-Nl>xa=xF>%<1|c*cf4_ELtkZUMz#!m<+(1=t?D{4F zfY2MdsqoDJA;?S-B$lO%NJMg4O6&6S4BU=~nBQTN3rGMAJfrrujGthT$<&AQaZ8pn;~!xwamvvkk2C z9z~Vca2-@+dvIe=z3xfwx_C1w}L}6bJG&< z#=h$qm+gg(8CPvU=K*(2oe7F;WA401QRPrv2NiktTxfJ?**d?dD7qNeBV%pLbp2G6 z5MSHpT!iF=JWO#lk`~EI6E}FIYw|m;MAAa}U9Ln$UT&IItC9Avf(TLf8~7=i6Bj~Rj1qMc`;B$B^@NihdzlOj+zM-~A+TGL#ih*CdV z2R?MBRtq1b&6j6q-+6JT#UZNc>sv2tl`gwu$r*+{x%Qqbi@*xOPYE^rql8sygp~+vgrpJdS@7|hZfOs66>DhLa(+=v= zjrnI0km6=_%b6<+Ml*GDr6(=vg~eWpY3ak_@))K^beU>5bO)fr*TeMf>ck(9-j%AR#J_SwB;hw6R&|LY+I>L6npgT8d2c39ZwYVO@%&{NLGN1h4f2%D`iPL?h0_or#R~}y zS|N6Cs(9p)NB+-ib0P~jLYRtI?_4*aOwJV>H)@LWF4@pq{S7R_M)M4(Kf{A9(uT8w zHcGCOFMK1-ofi+L`?JLT;g)#LM$%K~_+>gGF8og!Emg&w?b;W2b! z0Y8$F_`+J1J}5Hq5*N<@OH9$uP(kS<*|mA+7fD~v zk+tg>9r&E#2{%kDRFVR^-vY~|8rMjNF-l4o%~ei0X}a-<7KU!JE}T+e$Qz6F#XeSv zt2pYAPr-7$SYiMR);N2Ex6qMr+Q^nBm+WJtw8ejf+$BthWUmsvF)3QE3X3W@dvKYq zFf5||sLgUB8pWcK-=Zb%^<{<|E{6mA+7M0fE>ut07w4A!LyFcQx9^}eqdksQmVM=k^YY*VTbGG_Ou$JBkGfPzWF zUD+u?FMY_;kkhZ2`J1;}^6Fam#hsP`e7g5KCD^oq+qaANT6?$m@E?170H^qG;rTm5 zyO9w^Sw3p*kMG@n8_$n{3}KuK1j}aLpP>i?-s`(Q^eF=}-K!zZV;S>jr^OU91Lkdy znaAgY!IIOw^BSyZMXvKh(v(c;W#)0R1MwSX3`2t%7Lht`db_i{hJ!b&zhb)gF^x&s z6JpcaWx*jjQP3JuI9PA!mf65wb!l`ZnQ_=d-%P4uTR~%`Si41+CjRT1qJF`yEqA6 z&D3ibH<4KC^EW~+_be(`&!MRsG>sH;qy3{*`?2%}Em3WyAuC@!0ie_|QR{IoQC>AT zZ#bY=FHe7y1j)d^bb@k}H%q+IwqJh_`Tbw#5~_FsD&>*)+y_-n7wK~b(<=Q;muNKi zz1v!MAY->sS#l}iYgnd8dv?$+!<01zRB84|?U()@yGq?(1Irvj1zcHCTEuvxr#B`~ zm3pa7l)nm{IyQY4=gXXEOq6!(x&z7*F+UPI)0l&3!rQ@ifpEC4fCswQ z`ngZ60ujT>Sq>mT9LJ`wDGt4a^8gtW1zDW@T{(~j)5R07EoS`Di+*vVBG5X;OGxtr zJuJ3kvmcfrp4^P} z8u|PT@%cyYY|zcp#kdRjO{FL^w2_!LZ9C}LdGBZ-}JIw@5~mMdqbOJ6y) zZk_v;^X_*xXX&C9W+@9Rr}8unTII@_gq5?^SUH&hcD#|299S0Du*FacN?OEO%+bz) ze43_UmNN$m?1=NvU0XaJca6EFD|y#Z!l^UUYc4@;aJ{C-mFqQgTL=PCQ5zc$ zORc`Vsi=7U%obG6*}|drh@!QNh2qQ1=$$Oio3ABx$INqgaBLbsfaYUyvlJ}t`0xUY zr7|xKGJmB*7W`|A_KWN9@aW5Uloyvse9eKr#qNF_dr|{%QjCQu-P?c)S4Mzp_jsU2 zz(TS_uy(VYuLY`>ISXIj5>Y4MsCZ!ik)@<}zbT*c%C(Az)l#s#m!tMBf$FP!Cjyeq z?Xu37K{k;BE=+x($MbaRU%8>_2g~bzFl_l7{tIG=VwHERd}Z<2-q+2P zZtcPoWibuCv*HI^Z< z=;q=CDvXcJAk0p*!|YH zrT1z7kbnJuzTBta9`_-6pAT8%bnj5T&+l5}Oz-n`I8TJe|Di@)z~km618FyXNt1Cb z9K|gsW3A3Lj=hi02ks)x$8kXt=i{}SkCyv5qTf*-+~5mauIizAHPHeqLhY^67k2il z9?F}7;?CMM+UYgsK&5^lIIX`g0rPrIpEsn zTNCVsG{D{-!0yrP*d|zHBG@;t3dv!ALKCkHT!)(@b&y$}q2ks-Z;_APw?ZE2;^L8U?%O zsQ%>2V6Ow!vkvxM>qoWiIu3Ipb>>ALA6*&db)cGH9a{^}2-O5NjiQ>pCV_ouWw6(Q z>WvQev4-61`VzCcWsz{Ji7?;3GR*5h^(Ke;@EHjZPUek*y~R=e#+AWd2dXza*hjxr zmwRhMHTkkeVGaW1BmeDO$m*WMe5wKSS_Oz%DZ|WYXE$exo6ZTUw*;`)FF=Tz8%1?c z_HI}aW(66brAbdybb;xSW6H^!9X-LY+KQz!ImqDAVOZ6Tte?i~vF6`DPgNOG8*x|! z*WP^tR()m2+5Cp0K5We?v|SNB!MStCJJ`d=W*%?mX;)>z{3yl#hm3WJtx%i*0T;!+ z@^86!SDY`I`== zV0slW9RsyHVJhsz96PEU^FJ9-`8c42w@(EazVvVQLBS9}2v7;_|IyKYw?8AN))#n4 zuix)*0)t*7s7E{I`aHjgms0?c1@%~RPdCt*eq!PVgt+Q03^Ypc^lrG@{8kEt+4cEBjz+z1E61u+lE)8Y|H zU6(`z_vCggyG0=XPI_D7(0g(B>p*Mq)Z&oHv-c^rCbLj{kY%jjzou7Zz6UX;R>TUwJi?5eGc8X6ko#VP>6Nu;z?{aGKEiGY0+7?iU(@9_n!fw**3{$jewya^`v!07h9-g%NBYAZJxwg?H|^Z; z*eG=wXGi~M_}qr#6E=d;j%J=sCC-`9(WtzceKsN8v&CB;4js)Fdj#Wb@u0VKxfIyr zV4Qn4(fD)4Hcl3enGK@B=ZKtrqPp8yyx~Xofi9PlZEgO3^oQY_QIOrj)=r8 zmDl|a{e7Kd^q{Uo&$n>h==p#e!m6>K>zw%i8`MTT!qO66`j^s%LiQ5+Kn1>zKOb}& zcoCPMaZLOc&)<6Er@!@{cYOVJav;5sp8?nx@HWwGSJgWFC7KW-SMWMWmaw_oX?Snd z;htuP3sr}TokaIR*hdJZ@F0D*dxu(Kzvz4>4`YC^+w2etwy4;-6G%M?FNOaju?}+j zs*J^kz+zlBGNLZDR&K8gIVIx=@!gGn>g{zwIHCRM_Dlr>V}|x)ow)g(?oGiRlKSkI zyY~uqo9*abENH*k(*ws3vb1;s;uVTVvLvyB==ch;;rcV3hodC%0E-|w0J%Jur}z$;ub$72q3AdZcq=|+usll57Msl$$w7i#HH4_Rft7o z3*e+yr?mXafaT&D34(lFUHI@68a`sn1mx9_ z4Hsm@*2zJ}TdS?D=oS0E7z8D>cQe9?CMv93)#J4IFeq{e&Gn32wP9s<0onUAzUhYq zHPS;ICekGEk+k?=7ET=bfhz;S^JQydIMk5ZX}=Pfbgw=-FL375OVNdOcpF%)Vz4mL zyR%-q*WO3Fv6C@GN%6pTNQR9SdUp_}6r#v>O+=1#DcU%=#m6dMV0)(|&D9jUR~`mG z`(;C7wXxG^6a2XvZ=5TlyG7Y5)2hfnSbe{I#D)S4%#dFzLZauvf!?= z?xf_wp^O-vj>`juc9U{wM(yu6nlHIxpq?cV{7ey4=XWfbm*2U>P8;b?o<2GG)9e>o zOYmEG&5tUL%L7-6vcSDXwX^!z`y&5uWGc*Zcq78gLtR!Ho zJ{K5pj^A`myPd!E^@u}`-ezlp!kwGvNOwO2~SRWAC6Exx~p>N`x>*C~=0j@1@(+ zj>bhY6godsHLr>W2XmlRjA2w5);z%ac)3^}%8DtSLbW`>17N>jtpQkP!YeuxsebPv?8>}3SjmLClHxB+n@=hR1 z++rZGa;;<_ppK3;5Q3H=U0%Aos{_j!2(67~H$=m-oJ7EDIc-Pdgv>X{H2EX6Yz4ES zWo84%b!-)Enc1M+0KPCG24&RJsmumtKM3|gt)}dVeekxkZy%UdU}(2A3s^som^{RtJeU1)F6nUHw^;oAQ}V)x)-yq41$TEo09DYL98ws4FWjU8Odw`6n)0_ zLes8WK?7&$6hUNY*-#0#cP0dK)y*^g*#H7jXR^8~gUT~fW3kF{ietytUd^fL=Y}KG z#oZQY;3(Jv0<U*R>@avjp&H(Anmr6tn71L_ou zlGUXN``c`ImTAbfjT|<&*|{bV9F>8?BIWL~7H@QL>!lMDL3T!RW&8HHdKh##x##8Q zl>UnG#_Xip80UA)My0KBe#dN724>5YB3Frm&zNz@*qVGP77m@`-o42+{UqC)qg3^NaHCxP z9i`6T&7}AU=9_AVZk(M3)0(vAU`NtH+hD77tiBUahssqx>XWg7Mt7sdIBm2m_A843 zi1ly?A-7s&K0L4LN_>hmO^w%T_tr9zua)p@2cb!LxhAb&r@v5~uY>*EtaDq@Up}GE zt+|`d7$>qi)`}Bb;dWNjU}ck?Cs#*yW`Qg_5fF~*3EEr@egb@I%R`OQ);vVZ;<)S( zbspG@6*NX_c@w9B#|u~<4Opwjzy*6H_1_5dnsO9iRMRy!0^jo>^&ZJH6xGC7 zwVIvw)oSeyI$qq8Fq@$%iU$>01-NM^93StD;i~}4iHR4)fZ};rScg2qw#J@?G0Gv` z#N$t9j9N#A$7tHa`bosf^){xjB9U0^ZH+6A=~DGRrOw21YyY~f>BT&fjMQ5b-Qsmx zuk+HKmNPN-VaBRE{22U|(vHkq<^wSQWaG1=)zU1skNwL=!66z)Yo^gSscf3UGRv}Q zHQcSPY+C+fESq*dj8Sg+MhI)`(MUSs(yYjZnX0g2*B{eBBUiKA(4GrBW6 zoVERSevVAK>iIb`>BVNwt<5!FlTuE_ENEElzd(XLXwXgyF>%J#r!E9Qx;%^HVi17%# z&bGHPn*8Xyv}11Lh|iPl+nQ=!JUukkdeNRhaLa0MB6w}3&oe(JTrNzDcE2K8Es~># z(;w%w$Oai<8|~~}V4Fw9{K&+r&rhx9pw`XVe|v1Eiha}$**pH9*Xyg)#tqTqvYwhg z<|%W}T6C95o}xC$7|O@hP0`~rlq$=I4dl{YwvN&%?CJ11bM)Ca4IFu11|u%A(NCAT zX-AHetZ@VwEy3aUs4R{btE{bOl0CAQSsPTYsdY^9qZ~zNR7B2Vy3U*r@KpvXT4PbG z;7M~oWhk$x@_O7@EEVV7odx&S~47keNrso$v&Zs<` zId;!4e4J4&ICCM7!AIroE|-r$tSJ7=IL>t9O2s5&X|;h|ht3qMUJ1;@JOq=D4Z;T2 z8=MnrfTbf_KjxpJJ{?Ad^U&mKspcg@pN=~~()~<1m#UuxsEGikBlPV-*nP6~t*g$* zxwiFiZ3m0}Co>%A&Gw&4lfr)2tPcBKGfenhec0?GD>#MbqhkRoel?v^0!C1POZkIajG zwr?@S5Qa^aK^Eg1tjU0{EpV8L3)&zr!yKLxYd0_k}rI`}g8x#qZf~YB^)pK#*!x%@3Mg3ClQ48%Q>8so~gIrHNyLW_c&Tz9I5O*ZG2Ko5mMS z9Cw{B*7`LtJoGigZ~!tQco;|!+>!*m*9f`j6lhN7}huNrK!pHltC72!;|%iEsfXj(^4k=$ZW=)+4ZAwX+j*x5E2W7R*fIwF+TO2E)nlM*km3uwK-E+ymrw6cpu7t1cL z{*7Z7mnc6oYq$q1pXD_i(d>m~CG3x-`*tdi3_B_q9MyTm6CKN=JzX9_Y$Q`-3$!e1 zIg-qOxTxir#7G2j;XF~9N+lE9ud)EjPEPE&vZg7w+IHf-NYJII(s{^$CwKaI zGz(gq&uJTBw78x~L@_2~6v>!yz*s)jRTi{7sGR@BZ11&0H5uPy?VEdVs%N7IBOkK% zO}%3wqdZEhU@eYX`_|rP>zU?x{%@^)TkqW=|9$zqC6g^S_5OY6`R|4P-yU+?m(M?J z?Y-VT^*s9Yf722f?24_uAJ)^}zb!Q0;GHP0Rv5Po5G0fLjE4dFq$mLS%2^=f^Q(^h zm_wc|jnPzxluD`UDf%Sp{8yaBvGo+S?-dnOmi&n&6-j`!7ZNtRyphjrQc1ES zTix36)U!}aEj5;6zA~Nm*jWA#CNGOq$<>3*WoMoVpL1He5UH15Gf1sA5dy8BT7hwP zln_ojxXJOvP!LcU3+X30Gay_-{FdEl;hKH@4e4Ia31q56%v*yQ4%nk``mtqiwZOry zblQ3=JCt)gi&`66JyB71r2)rAz}&!Ua&y(~ZvwdDsFmDo5HL@qz`lu$Y{@UQzLo0l z<>?6}MIzhU9AJquRT!DD>CFb|#wYXKphuDQ{uT|J|82D!TXGI;w?K?Roo@sc#Yz5` z_uivQCWAJpYJn!U!c+8TO2KU9ltF(hRDS(`qKY9usoK;-Gsrh--Poj`K$iEY9FBDD z*hczBMlzdEaZWb75-+=jDaD)=ieZX5DHP!3IWCgK#@Op`6~J;PQoUfOk1^*DN!l*q zk0mZ60S@npsx^tdA5oDb8KjHX%M?il7lGs~f9YUbzAeA#s=-!9qMhP!i$qIg3}wM3?CT+!p3xp~U@wN##-`i@to{{tw5d!N`#S%b-`D%}odN4zdIIU%tF}!nB^-OEpYygM3UKw#LaN@&(SWi& zs##q1zK2y2!`6ELf%WdkkQp%KRIaT)r-ns*DhE{7kXNv4U6`G3i1_5X5pgt2Ti4H) z@?OQ2qrBH7=v0-t512RQz!A%JxSF@CDW=EoBH6>;t~L7i%s;y$5v9)jXQbETAR|Oh2NXYM9ExRMP~lmw3VbP)tK12`J{xL zun9Lix>-EZdXATZltd^V;s2(s^lnRfOg;IGO6eV}Ri*pyQ=JwED|NUs^7ybtbNUt1 zm#2$I?C+L|`rc@w*I>`AQHNWrjbp~mHa4Nr6ShlTsOfN4C(N}hd|FA7^u8F1t8rEe z<&1^ZO8dB=r-R(vSZY*+hq6AB_HB_A%4u=ipM6%krxep~-}}kZI*W-q8``Th-FbSK zq-v{3ICVU9wQZk@WNYrQfuIWt-Gn&fmXY{?Z;_zh4-TRu>dVYy1-b;{j44HZE&c{) zTfcW|?b49=O1XB?JRhRzG=PO`1{*XU(!1*Ck3JB`bJ{OW!zQUJV3Yq~@ndg#@V!f4 zx%-2+n}%H<5DvzfIJABonjPs9ECP{H2&Kvq-&D-?suW-Zw+6>*DX@DFzSBgmEK*oY zYg4kWTJ+zyeoW*qZ##`ufbk>>jkR>pb@S=}z3Z>whAqWi@8WNn8v0#nn!-SU>yj;X zd6qFfa&6ktVy>VnJGM3z<0H_(>Ty=uaD(iq&p9A}f`TK^+@!XJvqUI6Au)zaRr`*W z2eb&wd|b!+EPeJT_HA%Y+4)Fj!eUAohzo1`K;AeYONdDb?%=p`0A6R>>LDg9+aB3r zz{kF!lG#^gt#)Zy9z&Z*gQb9^3ks8Do}qDfCJwa?Thdjw$RDoHpbH2|3j%bWYiMXE zfB2Q_4+2gJ$fXgWVo5(RZ7vmkeO4=;M6IcG5}<0fX|bmqQ=;XRkMTv0An!_zNKz>t zF*C*duf&IZyV z6OLWg1!nDy3;{Jdp`%GaXvPQR0rvFzy+1Qe!UBq+fUe|)%o8yY4;%mV-g+p|d!+fI zWl6&3(@R(=^|F(EzY9;;YOU6tBC?`=9maM(-Ji+!!cz+_#0GF)*A85uOlcsjG!Hg;I+Tt3d42`bgDxZYfwivYbV+dJ4uFT}OUkQ!|M zy+JSU7eh*uB^Hul!9xwHNO?Gdv92p7SZ48#<7HM!;$I|Ec zh%nkUs|(qJfoa+$-+d|G0dlWjh26-(6McT}rTHezQnI#RMbjLeZ^A59=hyRF*9qh4 z?PHTRFw>l+XFp+;4}8X!TJMV?{Gr3 z^|I&!l-bt~f*P~ad~y=5XbWf&s`AZhE~VB)a~njMLc+XD0NWdQ`~)!GK9D3|5HDTE z4~npIwTHh*LMa%%hs`d5Y^XLN>d7fU&EpVkM@nh51NL$7BL#Y7Ekp=W9cdVNvXHh2$xJN-|W5^=tGap$ptgV>#4b5Zq97MnlTp)RH9#4@&LO{q4r%J z`{pkbDSH)~>k}x{MdP7k9S6%PTd2<|R@gNj!)f4ZidzMK?A!tbTEyi6iktN+^m_)%Mk7QsyPt}LL zWwr+tXK#V_ac@Z&7y#0wMm{B{#@P4Ld|HkUu>ixoq+Hl8bpS`8D_Z@Qt%c&*?UoT= zhCV09)IBS?<~#5TIIJ1-uWzUADy2-rui-XqX}^)dzed^6vVI$7=Ug)da;HGq+x4fU z?4A6O&@}&wrqZmx<3`!$yum0`uTocV2AhinGJwpb;HgLS8TII$cz3cU`KIj1x9ty- zUEM4U(n46vnM!g%L@X#vUWEmrDchA^1|LCok#eYcFN!e*!YQV;EX4$y?#DqfjZZB@ zF;gYQ$ogFk#YBRrdw0IoHksEdmD3TD*k;qQjY((M5`Lnabo zceEr42|M6-VK=}nE^)^SYvQgAyQ>Hc;!Z0y&utS8!XfPe6;+vc`Vzw=GP&S@-Z6`) z;lX)d^0`_VI70RMWkq(KNgSNj!Yo>KCNgd1-6(O=;wlq(5+qU4D zW222@BZC++a~RoJEDnv>FKdNFq?Bm&gCJ}(mlX187_D=qTymE_Vg}aVSST%W7fVk zMI%V+s`uq)pPq`g6i9$R?YLebRdlTWw4|94F43%=d>Zwnxb*+-cL3E;G%eO)mGiZa z8Yo)(rk&8I!zyNsvmvZv(+px{bx|I8Uels^&AxuuR>Ah5e7`|gX=b{q^ogiUO-OFR&VZVp(*s+*#9gBzPvp=zKJ;3LTPD?jZ3iE0N_JMq8 zAme;Vdb{pOLLCF}~PJ~lxt&DL-(s`7{REv5DvNqA*I)bgL72f?k#c=RAcMd86W7Ao;mcGTWsY-Gr)#45GnZ|R(vAqS+>A*wt-^5!;m%L zRUVzD)6kWbBFN$ogt?`t;IrxlQX%eD<(-$cN|%yBS>%220k+k<3g%z~K+ zOUbg&R9VnyVXx^J7%hPn4AcCFFu$&t#d#H7b{+ z)H{l2UzJrGvtT|L=)Ovz-=QH;hA~lsZ=1pfIU@dKWV)MQ#s)a{q|0Wet6Zn-D9_U9 zUD6M%#Kx5yTx?9?AtL{*wXp;-5}d#cfEGFlGp6;YoN|BE3|N>p%$RYa%{v-1^X_ZM z+2{y%#Fg&i9+Vr$1I;ML1+bO@{*J-892}1E&9l9axCaG{Mh3VyvpqEJqs2Y6$&6qt zh8CQdkk9B>v;e*(2m%SaXc9t9QG$C+NKFL_L6(=Ec#Orkz=(LX0&7wbRqA`tRn}29 zlq9M*=**?QVd92)mpx%!+4)tqLT_tRll|6>ekYksqqYcs@6}7g@#m5Gq z<@cr4Z!I7<-XLe_xgoh>vW9h^DRrF{=r+cm4cwp%Z~C|r1>T-`G? zpjx+zM>LFh?^@_7qFI~QF`w|&-9C}qCnol;GrTs#Ww$VcAV+l6Adl$QGBwIZbg(+X z^{%u!k2nd>CUYcGg8d4T%apuAgF(ygs`lyvJt&W@5DUR&z3CI2a{DqmN`R$+^EPC^pB0WQlUbi!5-37RtR) zuE)X@2$z^iuFl)?B%@5SUPsXl-3Qf(ZA$#;W%ke}k}E1b6C9ItsJ0${Dr?2)co5$9 zwbK#K^4mG9iiz99>a{;6uzau46uuAsZ=O;xm4>?@eeWpPIiamUM7vZy($$KXLV2#`mf3Sd-H8ZVG z6JxHX{HYW})uRQfX^Ns?(aVaD%8b4{hBs(F1APW0M&0JGo63D-F2Rbqir2$8XQF!Q zqws~{yp;vLQ)-chy{z6T-Ljk>)XymynnUVmM|&lmCYH}kWvsKt4_lSSo=>!uN;Ze* zO_|~(`;8w6%bB|YD(>%GEh(^lkhlowYSq?H$Vfsjj=#x+|Kfj}ZR>(iU(V!bf zh5HSHdX7YwmOcY{W1|LFoZJTuo!a2AHC%*_!h|PIa+^v~DD6aj+8Fiepd`6(TXl?7 z*>~CAN4mvYa-Dj(+o+7BL{gaQrnTEW?4CRU7m9>|@Q{Y=K-L5v(vUbozi~)XSt9Fc z8~cpj*IuC%3{1q*>QO(U(U+h(aY(D%tK6WD zC{Wz%CR}}rc1;l0+5pw848P$$u>!$OdPet`YCY!Jlaed(e_OaPv*yp&M{~g5{0{M3 zP>~IXYS}#Y^;*l4wcKB|u!WlZ%I@qXJa^FUodyLX!-;pb8RF+To{b%1v*HI=cp~nK z)KM8`8Pau-^t22bJ#BWUHEW-@r}$(WKG@*_JqZpD8V)#yfzD8xKIiz8C(Yz8KRN3Q z%CeT=ktzha=}dgX^2)m6D$GOZdV1UR^iEw*H#%u3fH+>EW(-;LNrOab`F;(nBO7!L z=R_qtiAr{eb3ol7H^21xG(+dng*F~6k$>sambbptzWq_`7pWVlp3(+Ozjp8x^JVjq zV;mq^Ox@5Fmu@D=J*r@bYx{+$)8%$yf@76_W$q3#8<4XQ+8ZBiV8C@j>7wR(mf)0X zTDhK0z9}w0x}GI`@i19@zRTDI`=wNOZA6H8TubJF2x52xFZn?mq^3E7N++{^4VT-ynWS(~+XASWSrWqrr2j(JV+hTilQZhy^G#7yv)wJZnz?rAD_WtQX8( z@G?63G+%=(ELD;?cF5MRfkLItjD7uBs8@eyceyRJm>{S+d$c%6Ez6&ZbO?{7J z76Rr(BJR>cF*$A!)HsxhiyS)X`W0C^U4`D^5%hX>@LA1}8wDi>8u@!G@| z8arRGFcM)d&Gs@}+m~d&F4B4$Y28A&(Ru7)M;%r%mF11q%ytf>7}c)8X_4+NW=+O( zpj65}LH91`Otu7l%mA=$IygPL!TrlNXNrTx^n8Cx zxH((dm9R`*`a>go+4xLqZW$vN(HRsY<<^eqi4?txJ8wM8lv`^OxNOdQ!c+;3Qu;fg zMxo)GTccfFVcU%pdl4gODk|y23I$9i??-$4r3l#iz!H(Q5W2QQ#a3%;Lm8sdBwJ`G z4IZ4;6E4B4PQ+jmT}9W+uDAGdh_!&Ln2^Ro#(Heg|AD@=KMsx77AeJ*3}$GFGzop} z8)zvmsge|p%_shD&-kqRnbnTjG|;YdrFcBk^pgYKFS`NgBb8i zRtl4;M51YyQ};@0s!Pr=4zCe3v`~s==kehBO_(E_9$t--ijdCW*%12)5;3nc33i*N zNy?mSHgWpR?^Yua?RweFh8eRAs5MQ<*o%cka?1#nsB{jB0g%BGgcgD>z+yu(bJ*e{ z1OO+t5-mo$CE_c)S+H&b@EX`iXG6n@eOWiKzIQ105uK0I75^s9QV1j_d&I|-`g0Pr zjJ&G-ESj<9lf?&-H8;pCtiMH}73)4H^r*;Q%zvh@Es|f{*ZVW&T`1oo+8T$Ede}uU zb9?a#`|m7XaxF`g&K}Z-q)B@*r_~y+WeHUkOti4)Z?q(@?K|agY7KJ+6KTRi8N$Mq zGOK~kOipy(a7n^g+W!ZL5P5;>JbT^_wxij_=D2)uM4{}(lZ#_FDCYfhVaGOfhYc34 z*pgVX(D(nfxbJQCCsStMu{OIhLjOg9mO@L38rXVu2>lU`U3*iH|EwVN<`zeXqX=7= zOrMc9nT)(;7#=L$3bQDcrKv2W2)LFJwO~_=0qt%E0)rc)iEfta!a7I@q`OkTW*WDa-zZ1r>yt@ z4+wXN6Tf$d8bZ8hR*-Gfjx678kFjj}0k~{2-JSgw;(#0#IH+%W4a6%Dj>vqoa}lRW zUIDi437-$^UcQQxynEVwF}$2^fg_g^58~qHZ!M<3!gS)V(Lv^G3rcVE3&mcOY>OG6 zY3k-#aSM@-uUDj_V7TRdf}w?+FpC}0q;I`XAYPt6%r(FEXQ=$A4Qmg-*Fe^rr|r_j z(9PC~JSn|>9<-F{49MYEAsX(nW8H`5bi9HGI92o3s`*HEgZpao_#S7C=Nz{r-NOTw z%G?kTddnOQ7F&7XF}qVGKA?%f@#28r6$nPi7_sl+c~+zJIfM2NhLINcz1v!L;IZHG zYD1&EO2pzkmt~#-tu!{yA>aF|F9-<1a|R;~{;6uD_rAI@wqqAh8k=QDUFFy$qglDi zShGB2Sp`>F$-7&%jC|`hK3=4~Zwn=}AIe&rO8xZ!?(LQ{4$ncKN$-_!=OKRJ7Lzr| zu^Rp94YJg<+nF8W*2P3yOUW~#Ti zoUPwNOVCj`-QrRyN<>gC9f`Ygcb4mFK6yDbv0azN4ICKXG@lT4utRAAmRf!38)b@- zX+rzFgAK~QVqN)pJ9WCzQ@n7+p{My|hinS_P;Tx-A!7UGe2dSdMGJhV&)M+|K4GgH zzr>qjE=X;^x%~nWDjeH~aCv%@u5Oa}Kv3MFlPa_6UiCcZVw-oH?A$8w#fBC4?vw?h zUFx_?%wDCzoYI7a=~M1i3EdYBY;kyr&mG^P?Yi;0g^d9h`)@HQ4FhB|xBT6szo1HM zMrdczvG&~BN&67m&Ed}T7QHjD%n{ZPYNb7o=1D)6Uc%ZTIBQ3a`c&BJv`0sqEnl`B zkhW@D7W-v&xGdx*QJ@y?T?@Cv6K+0C3s*@CywU+%Z)!IwJ>p7>-jy1#Fe1w8eM3}l z0@e<@StHo|wxnbZR<0~&bX*e->wW0I(k8h=+K2Fi&uct2^wX!UhD5P~^4_2wxF;2h zh-Lh{x-1FOZi!{WEiOw6wOeM+8DO&PW=f2yL$OSFi_5wCEwN0v#bud;$M9_2BWpQu z50}P0n*;YS>?JUaURp9Z5mKRVj<1HRInR+~JX12~W_4=ZV;?f^(T4)};HZXs;Gr7# z@XJ;<_w@{Ok3a*Z#yzQVj|`{CJ@jncW1QFI9+!#2PQ^ukFl9O1;z1J(fmRfPY$e>F z+=4}$EC%|!Q04U4#!@a}C|8^RTX&wqOLA-glUZ8Mw)rnkD1(;XzTWrWDZ1lRM9Jun z&bjc13dUoS6ru{WFq+wOJ1)Sr3R{*BI+Y{}ncB*}ivxFRRNdYkAtRvKe6O&^O})>0 zqd`%eey5(C>D^k-5%`cbwtENb2?D=ijaz!3Rn|kc#`N8Wa{~1%RimXG!Ex9wPQCnZ z>`~XlY_m`!)VjiWMGFeSZS_uBmMI%NmMnj@oukx>dZXUs+cC5?U{;LwY*rb3gi@TKp<>#!pI}M#?dX3FbUQ}uX0$S7!mnkMt=ft zky)qCThwPT-kJ$uLtg^hh~J>^0^1gc_KPb+YiIx+M%0#3Ai#{q)f*3U+hN|{fO)&a zyv^hR$OVWR*u)qZ*gcvh5@uBJViasxMo2#S+8`2^MRJ%zP2j3fO*n*5efpK_Ml}i5 zM`6Z763m}GC#arsm~VM?9p<&7n(XbPVD}vCKVKPasY}i+t48&-gMIvlI@oKXYFjae zsXCzgo|R!<2UT;Zz*go4d8`%H)J+*hbr2l~R|b0>sNUdUA8LTTCR9_=WfbN>9tT#2 zc^#-`UWMwVAfR37trgWcct*h{IhmO8WvQesm2nsCaR`9$|%g_ixbRWTN&nc zpn8+TeB_K!O<9Riuvyy$_Lo)$dwEn_I<1Dbj|M`*Ru+Ei($L_UoGeqwTu4k|FZ9S(W~d z-H%o@%E>tUwi_@lOS8h&S@&n_JU(apWz+?W_l|d%Ha$+yM30wQ`8bh&ySQP0P`g{D z&b<=~K~>MuO>$RIdf&K1Hf=tlW(Sktudy;Op|6kMXniUBT}KDBsAYhjt;5x^=FGp}9O+K*+NG%DvW-CLYUMlh;f z(_&PbFwLzzWqye|PT6aC_h+3IxPJgns;I3xuh!dZGx|>*l0>C1E2b2zGwGkD>Lv4+%3O7( zrn|&$i|Ww%$rM3wmmFRpn1?HmU1+PbJhc?>9m}~fLMlvx>IMp{@)Z+jVWg@9VPR+Q z@ifct>=b-ScMXwzDabLqBM^X#mJ?Hd4WVpJ{(rM zS{>GGP++ZeSqbJLtSyvdC97wgCx$~}B)pNSMa;D7VZ{JCve88HTX zLQ2fg2 zqa0Lpx28*IV%xsh_RBdcEwqIM^-*fw3Olr5kmF7 zpSh{o3QwRTFVXQE5v!e|ZwLuM6VB{`kZfjI69lL#AiEOVC$=UQ0*VyHCeIX;u?}m^G2us?fZ5fO4Zrb3_j; zB$+tidBxq1dEBBw0iGeT39P4uZrhLB>%l*)O4@zZMuXv<@|BAEiN9Hu0%FQ0iyiVM zjYR@3)pT7NrSyE9NhEieT}fIVlBl;D11{JvNoP_&wa;5uC?xNi7;IqvJc)K-kMwx1ndwy2D|^hj3x=Qy_; zY;K+G=aY)^!}_Mxih`WOA8USU2v~fXdZ+xdZAh2GBPmpBIqV7VlwO+5{$N9vS)Q)R zGKf8X2_lZ%l)W-C*%#N_K(+U(3u8*uhBkunox zl7*Cswufa>6;3u_%3Cgz#4WPcdjGm6nM54IUdD+`>O`4T&PSx=N+wPDL#vZX9g|6R zZeg-as$<8bld$u`CU*R2OyEOqj|iypXiX`z5K!9kEM*pvFOps?r&@NyRG6sJ$6nO@ zm~s`fWW*;)=J#CN_p+}dmDHJ%p>W=Q@+?-;D9*>Q@apmjoqLh+(u#sit54tFrts3! z0_@xfFUuyURAc2b)Koj65D6~}W^v(V@hfLjc#+X>qVTFF1MA3AWuO=}a4)OL#TP3n zQA>uZq!=&Ds_ue*Fp(jvCyAdM5^=_?I`BLJ6hQ$qo4^Vj#d;rB`AXK+Ke48u>{-b(STBvVh5?M5|U2nP>Z z@ua4WKuly`Bu7Wy(V;Ml?5PqWSd6{_KgC*|cSg+)u)p9 zDNr(mDtQ6~6U>G77QSW$+1HJ76V`^LCdzBLwiEZlb$MW76xRf2kq`yb9hhbK%YK&- zwcn_Ovftxx=vrZE;dlMp#BT+PM}Ej?-$1w7UXOGUP1$)64oQWAAz3_pUmgW9^l-9L zC6(}fsm_vM@WT@XdU^LMC(~hsWp{y^sxw#R2+B&mLOg^FPE9z!J> zNxQ)6WH(`yg4KjalvEXMnH5qaER7P^P#Y(djl?F^1i4i-Y{A0A zg1nMW3Nz!r5(Zj290_;uBjvh0XEgiyjExHoTIw^7OF9gmDO6OM@nAHX@niJoye;iH zqqZ4pJlK6MmY&}HU0X8rCedy_FMI{zB~5@;7^wJ^uQWXVe*u_3{PQlYIbI;ar2$qZ z8FpP3^hi)`-biFmDZ)JPHfWH+x#nZx%Lba>aY<_smY)m@1jJ&Hfg|l0AwKPc*m|d;}q@B&=sJN0s0og~`|2wZK%ZwLiHzk`?bN ztckAKzq+`SanMZXWus4WX(pZ~C~4mR+7`~Hj`!6Gbf;6*yj@r0us>L|J|?$4MSDG04kWb2??W)2FO7U~~nI9=Oj;%O}B6nhz1 z1^E+PDt=UucQhpaPAlb4(Yx+<6i%?*cz_*u&t=W!OYZxpB{))AZEtH zj13&?MMkS!*Tr!w%h}hZo$ct)En2=uCz|?y4TXrKO&c~Cfw4!3&rkEv?=EV2lShbb zlel}`H^iOZ7d<9iM*?^%wWlBr9>XIz{FqGuJ?fZ8`69WDcrmjV57>*W?km5@Ap+Z~ zo}LH&BgI5tAB3cx)7g(XQ-uUZTU;`DyFCW1Szg&e65j1LtVxX+ej4 zj!(qT9ip;IcX7%-cXC?zG_F1yV;TKiTJQ+~;G+=$j!y!>v;lC)0Dzp%)p$n%NDDp+ zNPrPRI+zJ06(dTE(^KF?sfD|KTd+wI;S3j$!Fg_;I5p3Q=6Um}$7WoW_OzXz^0QNV z8cWlfkw8I0Sl`%rggvNt6P?xb_#!aGb;DT9Z=BB5i;Ky4_>MDCC}rMU>tugytbOu8 zY^;HIOKhwSmW>0iTjn_qaU^^VCsvEH>79JsKNp-#-!?Ymgp} zjkPfyij6g-93ab$F+lz6`(tD6>r1h*_Vv@&C%nxR#i=OU82Z7`kk@XS|A7h3( zB&Y2ySQIj@Mjab#kerN-HAqgx#u_BYV`CGNlWYwg6C{TX5}2?K$)VU-gXFH*ScBwX zY^*_YOKhw`av(M~Avpvj`^8qL>;V|Q4vEW48 zO=wQzYCb|D^LS{rrZfN}a=8mUrK4`{PL7AEdLQZx|C^dM9hg*t*+70DSsEJ)rJvBw z5PJVJ67>FDMh_Z2ey!l*W=!x}I4WP2`JGbX0dzv1^jXyB zNs&kFYsm?qAQ+Xp!<-|g5YS@Sk=@F%#cjpNdvCpaX^D9Rj@}>LV3#^^N?emd;p`x) zbpLJI96i;@0ZH^1Hf-^|Q=eE$3W`6D+-Cvv)QNfTTes7*#-UUMW!W_4yd+>wE1UnZ zTA$%kf3B1|NX`R%ycrRXrcImfn-xzlf7me-z5?IM~pXXud3mLf*SyDCf(TD+h4q(<@2$ zzXNbm$BQD@Xx*;Q)OQ($@>5Bm%34{D6fak(OH+L4wvPkBQ;V;BgugM4Gq!%X*7`?N zRa9<`sQE}qaiR_W-94X z(ldbyz;?h#q+8pb@aH0Z2dYJE{y!wH3s^6``{Q#F~6nV-V2mu54bzG1fUyimR?7jKn%3e_$TZJKPlWJYdXY zMSq*j4lZ@3uQ_lo|;!$jY?t8>1ps?Ty}GE0b=>d(Ph;&0eCrIC>Jk zS9c+EBV4sB%Xepc^yV{?Dh4>7;MU*&-uJ)px(ELk ztwEjQ2-G9!xW$zFJ8Zr!Dh_M09>af%w2Y4hnJc=jiR3{QdeL+9&sL z`E)A_UEJj@6pt=0cXD{}jrNSlfwx2rVeUl@oOaM??)PUjnqy%!H+qvs^HisXFTcS$ z5;c4~jOLVM0X1&~Qi(?f*)}3k$d|^)Yq?E>jkVf^UI&r9@q0r=B4Xeaav+8eG>GAg zfBRRr-~OeSzkca@qXyB_g42`J#X^HFoW>N}v8du=OO_oV(A>&Y!h^-v7^v|2XMbcU z6J7&a1MY>^CplX8`!ho8mjYVfceA}V0j&gkpF6aE{O`x0bz4O1+ZFifzu>Vy{)caU z<)K?xcN{-cLu{^$&@{RDx~K>;HPXH75^W9fC1Xl5?c?7a#(7gR zbqIWq(n9pzp!9b^p}?zlrsQLvec-mQzV+4bexFhL%6Q!XE;u42Tz=!$h|5RlP`Lc& ze~GxHMX0Q;8(*MFsCdF>kMTAfU)WxhrBk8iJcRDZtK{@JX`Jag*s^2&i-{7i#<8ZveRs9Bj>;MZ_^&3ay z4X)}pj>Q{Xl{aJu-yz%Fpu$d*S{YV%C|}8dE>9ogiapE}lk=n+PvX>mv(Xv;^fDP5 z#B=NG?giCPEp9r(-;#K~+9oizR-RC`&C@Waa#vK!oJFK64qK+Bv|=@kPF%_o@A^%# zS>mOkr7CK`-eyw2XL>4qkX}s>nu?WYJL2w|5{NFM!0s4ylrI#AZ|j$pSycbz6e#A% zdO^nCF7GRsXm)L$DKssk6aWQ->Y{vE$}0Q$81kZ`E%t|^p&(M)UeXquGEQ8VXpBSj!%gw9 zEhxp7F%KAl>8a8ZqU&u6u7=R;tUxKJoSyw~hv*p>?09-crRIy11Qi=2z?;$oU#tWb zecc4rh#qyX7sZr*(Ig0?m|`ns9zMrlW%;l}eNrde{DL#`Hs+gpIacH4@+9h!I^M@~ z_+8WOHXPpJfB(VO5ftE|dAQBxwzHP87x2XSSXgE{j$oDE`p**KqyC&QQp7>t`+28-7%OlR>uV?KcmEj6Nz5!4dBoe=Zdz30E)=ZalREJ(Bf{h zlQ)kc5JSHKb=(~*>0SqHgFH9$>CHEOaf!`$aX0<%w6D#Jd-QqcC(o{C^LyI492tQ< z)mLBu30nGDChoJRb8_a%0YTaGET?*qJkZmSgNn38xvDQ9zC7Z)#Pc|rDmDjOg=aaRcJxULWHm{2fXPujCls43)vbI6cBP2Dg{vVp&Ar44JM;L;8A;M=(WTr8 zqQj)vD31t^4vz{=ii`CdUr71;3Hr@efc-97sz-`YeMZvG=S;j9RuC@~Q4+rE;w7Fx z5$$&*g0Bs>WZMAV6v>Z|~mD5Aze{=P?) zxFr0B7UE|PH9ljRXuF|SJgH2Y!6KSPJ0r)mL<=}}b{b#Kp7OOg7MdMd zizA;#x)F~s`^&AxliAZmrOBPXHI&9GofRk8E1a}olJr;$ zygF#Cm~?eh#`!8wg$Y$xYo^2rZ#33S?ND5vet>D0Fbb4NALfEbxijytzGOg-bHVQ? zEA=EjB11%nF9torh>re|&Kh->r7BOgNM+TxiGq|U_YvB6ZL)@tqwksnaEyZNc=e%{ zDl%U?Cd7bd*OA*hOrmGI()%(*dV9y9YpW)NjDjra?r3q2jfL>7Xl2FYio*w`orQGw zkP|6tkjPeMBrprzo3=VFZ8e2FhgD8h#u%nqG+yfnj+3_9%J$MX#jZ@%bd6m1;o~u{ zYJ19e0+~KNQF~#Mw%P_Xc*9rG?w#7^lK^yGb%dp6Im3wUIdyg3{%thB=6E@8BJF&w zh1mB>=HY^wC&*)>uWQ%I~h zRVt&ikIa|_8CNYOW^Vb4h8Tm5qn2+hgbOt&t=7ryCroV2%_OGQ2TU zY}s`eKdPE!i^3xXJPYAC0qDR_T6mkl`_iiqE&_nyM+>$B8D1m0Ci$~U1Y|o#nK3Eu zOT|ff2bB{VO^OHXw{Q57nbv-3vq?)T;T-ntZ!0MTYayJ%|DK1f@k|EC=64I9T<;jk zW0P{;p6T;ezU%gyVftA-jd*&i=N{Uto_?E>AAwmiRJrt;t4)6v@>qw#bUt;><(4i6 zAK`E6{mauA!pyt_cKQ7or9A#EF0?IX=#h_!FWQP;D#<}xq4ul9>FNoBCCy| za}Cv;eHbvtqiYyl&PiZxIG5OfeB|VjPbci5<`Qi4TW|S+9Nf6C8(N4d*BG6ppUd#!rKE;^wCX=KDBH ztDl~2f030MO`sLlXj+4&>fghqG+tGmq!&nO#B%2h9gK2i7pEUyf4EyOCMOlH6~!+zWSABUSN}BX`BDg@jzHnGTq+iB z=qjy3x(d#ZNxROH?+j8;)exU!@zUQ;7G0B{<`!1Vc70R4jj3y&9Mv6lPhXs*J=({t zhlcV<=WorRkl+_ys40(O&rvW&hYKB;BX(DIF!+V}>OrGvJ;zn)ffYD+#T#7JZ@6Dr zZ`A$5ym2_b!Bzc@Bk=}T^&19`A(E^54fhM{8$*8Kdu8!dsxKIbti;of-*K#T3tdel zZx@dGT5Uc*(9*oI`rySxfZ~tUWJ(d{Pj?5AUI_fo^LFIvi*&MJKK%%GkNzGe)~m^T zxKQZB)=vS+v4?T|*D3_$B!362i|tWToqIf3KfftmnC^)9o8E!f#lBBn2=R zfUOK;Y`dw-chThMu`c=XTuy=|Df3S+j@Fg=_-w;1!O)@u7GeDrz3JK;`i-PgrM>;< zR_pqL=>k1)Kc4c+#m;X%i*JYv9Sl!fnID1CqjUPtwn2-;FIeWxDZz`Om5No*#~%)T z&_V%vs!AG(B#=n!`C6H?*>`2leWWCaEP2;Ut5dIct(+Kxz(3HkFN{bj#pq0w7m2n* z?DdAcpl9}xu(Giw>~3Xj+NbQbn!HF%2q?j>$qPMW^1`31Bq;-H^QS817yd>iFPKK(M@p=GM51yKy&u|QObkY; z$xqrMdRJOaRn2v*<-{wrrkbQwMMbYOW5(U~C3?np zEPGGt35+Q^2w^!rsVxc*PIuZZv2IT-4Er+vK>Q23&#Y-bT7CCkZ98Q48FVAvViZ9& zvPfeR%=3~S{g5!#aMjfo^9JL+`*G9SO;a5+`P?5^cw z38}SedFBYw6Qm6aC#{kMlWPeG_EBS3;xic@_^>ZQ{}tWa)4ao*HNp?u8@sY&M)=+( z^d26pDBtfu@ZnBH`hEwB4|li<1nYN1{QlXB`2CKk-|tk^?{`H0ey1XTzXR2WJ6x6D z5kWj88nMwa-?e>I(ZyG!`rpe{*hf9AMi9~aoH2<}K_u{n0h@F!e;_xKziiC(9Hl^R zvJ8!DZXKLJ<(lUgvR*>PzlqA4O1pN;lN<9Qi2#(7#HhBGEVC0+|5|kRzL3@0zUFz& zDi+Q)!YneFMbwk9#)!%WJZi6VqyxJ7(m!Y`$o$|9Mbf4w4)<+wJ6}T{%#=+1Ebwm? zKDvE&2Kuwc)xw4r-kHl0H)%e%8`IBrF#5CXC#W8sPd1vzyKaqG#%i{ z{^&Z!DhGoBys5rXMCf>bGyiiLR6LMKi1hVw0>5>sdO(ap@(3YQ0ooIwn&$}QsJ7-n zPI4ADu^RW&U&xBv&66GdEy5W1TV#pbF)*YJw#xe7(oeXx)&1m%19OFKk?W6pBmTQB zTK*BX^^F>qaO;Rp&Kx8uO}7Py`RfuJ!yu3{p9Hh3_u%r9mO zzyBCE$7YMm7~pKa4JW*+mZA>9Hq*N9Kh|fDY3-vhY9ckV$8q^(&hkATs=!UthxYo~ zh1i;J>nGXX{1S92w57*zfsQhq5tNN4coRXNc}CqpEH04NOGRf{vzGLQ3dHpckF|=TBKvy+J8d6HRo96 zR&(RZs|CKmJtyu|QFT^Sl0TvUbKoj_&c@W35id#q=VtXm`)HOwmM8Pg+WOht*mZfL zy5oNr3BdfZl$7JNMHi9A2Uyd*oYvna-t|G2 z_s8=I)&xKbv3V-O6VcUSJM*Mbp5r*`da+ z=|54LaqQu~Mh`qN*MDOExO@;6sqJ~cT&|3gfF>^+VB_qC94$^50+ziL0_5+Zbh2+;0S|@+!FXXSpt>-j;as3;(Hf)8ymcQ?{KP6 zbxZa2L~lo-vrq)v@^x~rg4;PRo^Kbt_R`Pq%O4kifbPf7Cw_d%pw)!a(+iBo=5SK2 z;Gk~kSQ8v3rQ7<%Qf;21dDL{dl+QL@+(M>U8f5h!19Epr!0Z5P{ULR3ws- z63Xk~CAvjsO)HOQKl=Oft$_|Q5`gAg;tz;vDiVc6fPAlAi8jRvL*(uJ3B?ur22U{i z5~-J8)cXtPKEQpf=H{`?js8AHlDjGVOX~DN4{7#$jg#z=-uqp_)6qWD{|L4}B0Z2| zEg#Wejt)d+(A<}Ne7fe7zj*Z91W_RdG&PrAW5DxDPjL2V&|f=k)_|8MY)@_jDAyAR z>!A^?_OmVfEcz)c)<`E{gCovvY0qA;RidSEe%LB+juvgDWL~gU(hIfSL3z4o7iUkc%7 zQT1}g$ZpTWHVRwTLlF+P|1)_bswW>kyNfj!eLX^&jc_9Dr_2|IqjlRN_V12?`37?x zV8CZ)_t+Gd-*6yjly9Ueg(|<4u*Q@8kyIf%`;*eyU&76n`8c>I1(?atT*4ik{SF*> z0sI|<4HhoS*8DFk??A3mXiq=H96L<;hMJW-8n`Zd^iJQK)!1aTT2g|BS(}3o_cqzl z0dqjO^*Lz+ZM<_QSN_h2%zgF+cL982o0Z=R2U-ry#qBl2H&FoK5cGy>4)Soxe~D)U z^a~<}t!Kt$qjeG*_ussYFK1J?>#6#tW466stzd(WrtHU)*3tqy*Sn>xBD0^`?mAj) zcikOO-f*Z!-lkJz(PC)ht^saGDe8tRt_uhxGs$P z>hn5>%h+g)3N5Oi2v>SpPAbpSB!@@M{iDedqO9Md>TxBET2@pqbY@+A zrksnpZ6%s3gwJg$+x$Dde^T7yob3R?(gACNJJ!$QQ1lAriaVXGhZ8)$Vx+- zFUiJ<>e6axKjlPa*}lgT6%6LQTOoXIQ`y!as*PgBg)vxLXkzWM^9F0mNDg)=MdQM> zV#UaIqNRYpx$>%kHQQ&}BdneF0${tcJ$Gs|mWWvM@Ym#VC5`3!mz?tNR>C82aPNr3 zk<;vc3l~m{r8(QnLe!hsh|Gp-Su%ciw!~%tn}*(VO(3Pk7jV{Vk&;Na$Cu`IC(q+) zRX56M+m&45+09u3QfhtLK7ejX4605`gJb|a$RS9kLQV<$$NwmZ(*5kZ>EvR4sHaP5 z=aN1p?x$K|3&k1R()yC-(%R)`QhSo@4XP3r%jk59m0q9>r9VC`EoJP|ZHw|C+mvRh z70$AyzPj2li+*KkV|_+HIdO`#)->c{bBb&g)>;yA!SkPIiiC;FTh$b`{u6V9tZac~ z4n1l*6pFK}b;WL;0`Z!x&oWu9#2Z9Wp*on7lG?;Ys#T03TC7BGeNgI0ZB`M^uIxFx zLN5t-b(-CtlZ?>(->O|fufec(jX)*bOn56v(9rgT8xCvlQ?*E}PbqlAeOemxwfCuG zme!|*t2P%IL&V&^umkex6mA{3ZO%Pha&Qeru$X!-i?^k4 zgaQ;t!1)V1Q!z3SpBwEzD^!$Wj*Qic1(UaW&H2fqKpT{yP=E+1${&r4`;TZQ8r&Q9h+kva%G&1 z)F|V^xs>r_j53}L&qGZax1l?_G@21*JR$(S$@t2og42cUWVQ+F%D5pw>(uI$@h_fT zWqcWoo?T@;63mD)9`S`T4!)Yoc%5KO84uVO8b_4zT2E_G#+O0Ch%&x*qN*w5qeNx4 ziYenmL^Yy}$D#d{6V=&O#)q&rqKuy}SUbDQ_`fZuj7M?gu920L@xNQIrZ-U;H%$+P z?%XTmpIEapjzD)kT&wC!VhvtX)0H(%nmF|{rGHa?m;Bha{JtnYs06F_j8tx(P+dKB z_5YYkFEwq8-KW|z9>mpZ+kds*IXK_6?X^qinzlVEoy|?Z_C9Oc_Gq7`ZLhu0nzlXC zXH(n0pdg~wT~H8FkIs&_b{XyHf`aH3aHB&E`)}>6eL+ElVe!ZWJMMylIC0}-8CJZY zAf5|v?fIf09>1Uzw5mVpnAKgXH6Wc-dXin|&<0J_s zo%zcFbc+zRbJg0AEz8=gRcET@TF*JDZZ*L?oYeQP3E3FiQ(I?n73a|Ci4>*Ucvp@( zbx44T6ul6i>K)pCy`n{V(y}8A$Y(=J41Tb2{Eatz(2-7a@PO?qXM5?O)w|cW5y}A1 z#-6fX)c!U#qt^;-UI*56sQTzffhF{J1lXFn(;f?K+cv=4z5!kWtG;^y5uW^c1QE)E zKmbK?OPkI0(DQ9}7Cxg*ajxV>`d!;vXXtAjdpSeWnpT*hGamHnhDw6-)y%jOE1c0Z zoA2vUHqDyK)l75y499M|$)jxS5(TRndq$w6Wm^$XAZ0kJFh<5rluRYTTf|`l1!X=w zmq9Omix@ zhCbPc4Sm{L!U_=Z>>UO;V_#27JUyTHGQ5Zg3j(Xwi-{-4j)SG#3Lf>f{3;TX$P_0P znG}TQN8hNyQ*P7_2|#r*E-8heLLl9RMYlrOg+`~>r9rN$`YTQ^?m zHy$LDZ<(4@D%pgdVTsbrH2itR+qzkx_2z@Ijc_BmUPYL;A;UD=0&h(;gqNP9bf{n1}X=7 ziTKO*O20#(FabU{B&wR$^mJ`{x|$xo+gaTFYk7My`PICA<)FKRnb(DG@F8XClRd z!LhXB6u*idRzrJ_W5VF$f&QbbHoW>B(aG#mi)7z{`0`<{hg9C>rH_ehSH@(SHYQP+ zKna?Di$^ZOKc!pgA|<2c);WC~>7$Z`aH-O!g9utVE%TQ~ntJE|XYYN0?W(H0!SnC_ zdH<3diSQut^W59{x?ifXIz1mBP_|Q@^GXl~dvto7uCJ!1YPzPrsqdSIJ=G}1d_7~s zLjyzvje-giA!;N62}VUbD(DjsqDF`qFhbNPM2LzSHAvJ5^ZTu}&p!K{d*8kHy?5_R zUJ@hk-n-A)d#|0I%LmMd&|uwKEQp1qAyET}yvklq($A*WkFs)A1v z^@5R_1m9~t25bkM2qz~{!=%P=eYy)JZVc~E-yUZCCA9c6I+0w*^d+@@gusM@6ojAu zm|F}7*t$oCNXyoCgRP>T#euSsMo# z3CyFWt0tOCfPii5aH~*oXCQ8ghYGpi4`FT!%YY#O53W4!f9&g^!mp#r?io>qh|6}IaWu4s6ec2|D1h;kPrU~MI4LOyK`Q&n7Ac7g zPrcA)(Gz+QG5yz4_MTk#=Ctnpt_|5aOVWQWY5vzhu7`q9KaOeAN?kO<8QMeQr~2K{l>-r@+1IX!QniJVS3;xx;Bpuv zte|1Zw>OSJ%80R2=PHfPH&dQAkT?UY1FrEy9|#b7m+w|FcX@3c-y52Y4mspX2!@Qy z2UxM{L;UdS!*QiPf?;NQQT)HLBp$(sggd1`K_ManFGZndBZYD#g)p7fPza@hfl*Ny zkH|NyPRU-6AuvX`+Z-Y5p>|E_TgP^cs7W*t^PC}3A;WS9`WAbPYc1*g=@)R)<2yex)7i#+$H zZPEc7JPJ#6i?xZnVS?#{G*|o&auR}Y)d3=I1JGBXIulJJRKMIgtuKQZhDgE$vA^vdjnVkDxA58jx}xE)V1k4J)B|1d9ieI2E0jF8jt&DBI32Pa=ppNd#GL_p z&?G<`SV4#R2WdmNT;d`N&b4q#wvJJ11qA64)R z!Xtx7Rpv+hThSq!)BJJNrIx4|P|dKdLcwa8eB9Tpc0;$eP$gEN&$b&j-?P zAVvThHjqvSQyK3kdw9hiZ`cA7g=vRu0cl3U+k$i9GL7H(|CnSNQ{4z!*BZh&oCXcT zND^F*D}{v{V1_ef%BIEL>_cr$`kSK$r>jtip}rtDkmjfXMX4bIg%n_oazvrp0^T7+ zboy(+Ijd?z|K7{qm$7Tr_|S7XbuJ(I3WtNjHK@gFO_~Rjad7H)4@&GE{4I)TNl} zlIluw2Oa6Frx_+O)s>(OI=WKL(UqM1agMGus=Cs0>Ppn=8Db3kTSNhJRHiaiCTJ+4 zFqP^)zb4V8ux{gizBzp1{e0+Dyvk1%G0T=X4$xEAdhFA=An@pNpi zDtpdQ>WGhBu1?EHK+x8y?rGX&#@nKkBO&x;yV4vxG+q$Z@BU+xWqYsVZah&CojOqv zz4k;wbknhk=zXDINe{{no|>JM!On@`xoYl=xFpE3fYPc-iQFi29}U+(*(xWyD>yED z8xtDQ!7x}0Lm{ti?yl6f(wx}vVNg!0H2L_+rlr_B+ec@h1huuicI8!gJI33)D_DP4 zA{$$b@GLw{ufPZe+t8z?#WPTVYOu7jDcJsE0yGqt>m}M9r7-tZmMT1f)d$Vtv-VE* zMInyYVdyGdjE4TH_9MEIbFtXG=j;5U1%LvHP1)r?)k{hXE<7;mI8mR~DgaZTwF7wp zf=9~=g_>{0ni!cNXz!PZ#DX~%ky5f9k!(t0`837^yv}+pRy^cGJ=L5u_Q76q&#}p; zk1r&jg6%r-=?`vj`4o)ZOFpfVgK;2h`1AvYPZ0u>T#9)?E))l6vPfB2%g2l>)qW^o z8Ro~7B3t>wR>HqpQ~6iIwsyn6I5dEUrJaC(OVZK%gnwIgG%NnSCBW%7;8f3ESn@>d zWYPxH^ZXG^BAIbP;#~kx0^};hqy>#?_Zky3o{R;#{N?}}G^DN;s06|+Q&S($^kt$- zf^Zr>)jEf%4tnD>HAvz&VEjQE9;JA!w~FFv*fka-^&5{in)Kz@zNknfP{@;glV5{r{a0G@1rn#(i9x6|n#|iLU`@d%;7IQ9pSy-d z>JxCgL$@`#B@M@^KnnJGcunx^0BQcP#{g^aC?EkZ7;kl2P-PcG-tfS3@&l~Wfb|zg z9fnI;Ivo2KCm~(v*#-vLX#+m&koeY9iw2C7`sRDEe5B8WhZK1z7irSSSvtr%CciNn?G&{a2BaYnnT;$ z(J5G)$l6n!RcLn{LFeiJK(~_^Qw$_LZi$5K4ZOx?=IDkn#JLAN+sv$lze##N3_^Q# z$P989*oxexat5br*b=L!8XqS$=Sl=lE_o`{fC2;6=^W&ptm0S!9EUw7#7RTWJW#h* zk1(?2ySQR*SMZJ8?FwzGju5;^+KU7U+63`_r2vbN2$N2Gf#3y`eww_$UU=WMOdci}%{)v=Yk2r&$LFHs zXp9AGF%%pF2VLm|Ggm?-WSHW13(gXePn7DOQXcnO487oBkqu&%H&TRNSV|;8MRO|` z^rV$H&ZiZ@Ck|`(yk9hzl=>X-`3%7KBY)7D4uOsf4rAdprxTzda{`hn{U^JM2A29A zl_eoArHV@@R(eBH&Lp8{@y4m#IHJD+#O1veT8B((Z8^K-wIdlGD$VKeaG~dW?1Igj z7+268phA?eZnx}~i!)UCcCYX@C_QU1vt+cPAyG_IZP|?!CazX`ShrOu?(|}maHV^pcI8Knlf66heqKh0!fo;Av~*wQ-Y(1P~~V0 zq9oNs&|8Ic5WwlP&;Zq5&DD!kgMWrx0OJE;YAh>2z)+4GKcmmkI2RAvAFv+|*dI7} zt(qT5w~ZF4@W}e+E=15;|8b&G7S%L!c7wEyGim#52@W|COrHMbWF3K{5hSYw+@wTD zU97L>rf@wFqzE}j0a6zO6KrclSB-Cb>GA!0uKLr~z24<~P`zrr`fj%nh=o^;kG>o3 zAa1cRSCCZEopc{0Oms93%HTi7WQ7k0MjMV>4VXCr3P22uDiFi3>WT?GqUiq*_~3JJ z0*c=;@gKFAA9SRZkp#SPbQL6bcoku+<)JP$febN5kQ?~xq6cgXxWO5Mi?n$ki_%hs zvqmareG6#+jr!_USgSlt!2ZLLB928+x`z!IOPa!fHA!G0EgBdx7s>fhL&+xI`CB%RXZTB;0Wk+8H>rK$ZR1`u^q9D1K zZf2srCZ9(!zETg<<+Ry@`OJw#_Bi6*fQBG_*vOPN65}gM=oNgAme5t0ol?*AArM%v z_7Iokx{n{J-WdBscU1i0ROnATPI6FIsgR1mU&*}}{Et=YQyY!2bB&lmgA(x_=msYR zEcaNhVqy$)f-CeGw@>JO>$T{ei@{g}nVRs8G=WURJW2L>6z#+b5}0lwXNqGEm3saf z6Ty#k8vLPo_(HL@6%aHPAP`^Q(4(Ye$ z6Y;QqgS^h*oKijDS9r-`G#XfW z=+a$6n~vY^~a}Z2%n*fhE2w#EPe6_wTF>t)(_XBr68-rQEje6hN^q=rVy7+ za5ZfCvPX$7zJx=RSWEcw67(khHnoj6hWKPeaDvi)DVPc~4zrI~(Qgv%(Nof3H3EKY zYDKRFk6_DXQL+^bcFlDHu9AwC$s|FnW;j18U^VQV9*s0L4WtH%l=zJfHa%9$Vv9Xq zm`q!jvTFmsoK98u8V>ClAcfj^p~A}Q3ONO}%xjcnlK>tt$6D35VZp=ArPv?m_-}%4 z2V)d{0i(Bp$zWP7hifsJaSbGY9m>5h1NTche8MC5BDpUk*P$v9hd{GTFJuhXl|JQz z*X;ERlaF&pO0Jvmj#PHz1khlEjNLe=8dp3_JdOj}O;ysN=c;}wr3E$%fj&?H)&4In z(%zCmD65huWeBc{oL1BmC4r4tsHwYQLdeA7)Fa;lH(#YsBNST}r=f5Bfx&I)iX%csFWizS^rG3^IXZzCqx?KbgdZ zzyYcF4OT24f3VVWvnW<9AEqq(8&)ho88E+*mdD^D80PSi=?uSf;6v?P1>~IZk!$^u zD+vuX&L)6BeWx-iDbGUcAP9(_@>&6JjMLr8isuwRBXN=nXU*7 z`wkM$c2ThtQk;`w0C3?0fYNneH=|fW;VZgae}Ipu?bwGHEyEVlg1alhKE~RBy7~U( z90iSvnE^wm!67SU6p^DLTU4?+jK0WaiwT8^33<%Q78QRE$$KbUQn}^I788>27?drP zdMaB)%4m*ZSH2u2*+NNov}DVNf}9c)xk?Q7AoNC}odP?4|8IO4m0<)KAG;b?TE?qa zuR}KE{~khx3t;WC*Ls67?#lB-Kl*ELcnfz`+=7Rf!LWqoVp1-1{AIG|R^IpcPOA8e z3K*x>Jz3Wvd4sjd6*OMIfqyQ<9m?biIl045Lhp)JlFB79GRcX_hSDDd!~z~B;iZtn zl}o5d##piN<1p@ahL-`xE8czyw~4ZKk#5)6Zn;X(zGN-I9|`>^Rqn8h4vp3)n^0_d z_zz73iOJwi)}n)6*f(yHBA(HR2j#28&YD+7>^`}Z;>vDzb;3hU&rv()L12ZVcOhA2CUVr@Qx5{ekAOF@wT2nwt(#?lRgKxdXt*-_f|nuxOF}ukXVNRe{^mpVo+AxN-8Pq8|b;|iVe6iX93&IR6 z$l>lADT1p|=olA^%Z6`ayn_uFUL#GQx#2Hff@C6}N-Jt=kgjPvC$6HjML<~O#3gS4 zgNA5XxHgKb0F5ADw1V&BHI4>I#bLmn%8UWYd$DOiXw~rGyn>WV=(j{lme0QgoRfjq(fG8jSoBlI5d(I9qvRWr{~ml@|UYS?2Xm&e}!a|y+36)n}#U>(XR#0r@L zUqJ+XWk5r~y&yAXVY*2Ua=s)hlk2u{-h2~0%YmFt=X0By7!z-XG2v;0j0wn2A%5xG zI*p5rN+!%&uOPoFWeXUMhjtsT)6*$L;WyUOtiR10hXQC_ryc z0YvfZ@Z!DCJjhpg&&)hrg|DZa9lRbNcj!a#xi!hst~%wR-!%fkx%j3>`Fem4n~Qi) zGXp#!kgcK|v%e7)@BM_Jc7ar-X#Y|Y&{_f0bnxCU$v*meVBV#yk6^_i!nH8U&0;FLxp!Jx5W)1S;t|Kwm>); zBW;QyCWx90QbO8eJ-Uf6+vl(G-dOht)N8!IqsdDcPOKpqP7$CmDPGXvy>zux0T1y+_+JERTG0qH)|2xxX@>n!rrGTFt>4s zGZ)GObw0qnl}Vun=5oCXx=Kbo5*TtCRU=?33MC%_MNta?}(P=7hikV;S? zD()@Q_*=$HF%}ctTz+f{*igkIHsrJH8LqxjhH?Y(PY@ZiwpqgBA^E&a%&ww z;!tbKE@)j`S|=T$uLy8NL;q*MYc;lWZ~#uApa{7rQ{|fp5T#`fOWWZ(%3SH?tG*vx zZaYc8(9|o~gBRPPEWxYWk3vcj4l05_HPfLu7GO@EQtNOuk*QoD(|#YzHd=;;%t;8b z!FaFuDLNl_P&^}`(u$`@zv&5T*nnb%r?5dK5jKGco8WD#x0WCf@FFA&0H8#G60JhV z$OSpB=Fvm;*cCyQR0P@AjTj2hYWlDsh{_^}WIJbij001B=nKO^1P?Fc-*pgtVAT_{ zYUh6<)|U*YCk54kktMRukV}S_aK$0x4#SEMyFI_j`GJ@;p*^MM+t66jAuV`I3bE2Ak%m|3?q1__qem6VLV4KU*V4&ddY6SnO@j%0C_IyDZQ{=hrCRU z^t4MTy;Mq5%LE5vy+M!g`c2L6G?~Fc0k(M8_AY}5b|o>+CakX8^byk`2fZr5ALnLv8tOgJw#IbIu0iy zd;WuIE!IQSGw)yu1w2EFvNNQBp3qTth7|CCBiDvl8?!bps+2BP*@n{{F^e)d{eyM?RlX>BA)N|%uvgUEn>{` zEy}2~MH%@$VQ%PmO7OrYG8;FDgP=#iAl-IY@f{@@g*<*oNk$%oq>&Q#=^Wm9lziQ|TF<@5+a=JvN5y6+N2T;O=dsIlKp2X)8 zB|L<&&|)qO%(AhpOqiTyDPx0WWg@W5VSbq`EORCZB#8Er5s3s^4+2#wZi8fZkb_R% z2Dnq$h8lS3d?N2P0gAd!fU>LzD9eg~vaARw%kqHk4(RRX5u6lmif!yYoA63@+d`*Z zgu*g!Isi=DLI=_Vw$P#dL0gy&6706RJOs&2MdAU29Pv_e9xjp-HJixEGN*4Dca}Lo z#>9qY4mL9GEOXG7ac5bcoHymkN$O_g%v0ZxvoK6bP8K=;+Q5ONnRzfkmcdl$PUAIa+NOg&Wk)id zJK5N#qrKfPOdho5V2rN-fMpI+GTJP2aFWqxnS+vyHp?80WVBh9AMI(m5Mw6~2R|F_ zJad@QE^v{KHVYj9bhKIMK&qq7LI))sZ5C#uZH76|0?8&Bk^-~nFtgC|S@>j8bdld)dPj0cL$h}PW!5oTnWgRL+l%N%5d8CmAwD$K|-2UTH4 zmSva{%dL54ByVQS2>hJa4KuRPX;+z%g$@A9j4X5@Rc2(NgOV~M3)f^zE5O9~7dUj2 zEp)0YGZwgBnURGKNb7BN2lz=_m{BEV#&li+HUL8|b|6${WT69$G9wEetasY#4lq-; z&;dr7k<}ew3^S%P14uQ`j19KX0cO1|bby((g$^)>1(Z%UofZgT2fZmN_FKbA@FY?!^0_b4m|qPBvA5u=BQ=DlBxG)v3Zlr+=L)EOY?X zslq}BBLIZ4XQ6{SexeY>bqhDyLZ`Y;6~5_ow86gVfVAEgI>1lb!i*^CR7s@<8V4|i zd8<=}g$^*g?VAoTJ8hu@%#7uu{IFWJ8<&2KZV-z{$kZFt} zhZr)8QRI+9CNYW}LdYCOQAP%m;N094#)QshaDKj<8O%bbQJujobUL4wdC5WtNS(nf zbdbSMZ~+S)q)FkXX}!r7I@NUs<9)Xyoxv=0Kw59BJHSuc!i*;A3{Hg^2e(O_=nTdq z7Z;tuEOfBmX{$THOxZ#Q7@fha?f_$Ea4Jr82IH?wt_{NAEOaQNGnj=AFgk--=m4WL zn1v27I)hp00CRv~XW~R>F#fv0=nQ6|1B}jK7COM}5U^S30JGf|I>6`*=9>;MW(KF? zgv(;nrfkv{I=~#3F1WZmz#O!N4loC7p##jcEp&j{%fd_zph?a#z^Qp6P}wr&toP*p zyeI+J7DNdcq995zDg{vj(x3!D6tsj5ux{mSBWp5^QY4E*77;5BMMS1J#1Mhv&_Se0 zMgpP_&v3^C0>P4rlAPEvk|ZykRFI&|>2q471Iiq@RE(g^fnB8t${hSi$tKCN$rd`b zRftdqIo+rbVW9)hdRyHg#H20EsF4a0BThMnO#)422*7kPQ5nKQ2bP_-x&zCUEp%W} z8N%ugEJlW;0*&m`B+xe4LWeLaLjb%BjLHxeI>4w5VW9(z$`BShz#JghtHV^Fk#n2$ zBb6b5)1{2c5EeR=*78@_0?f2(59^HT9ZxM9k$Q`X1gtPfZ1vb9bh)uLI;?eY@q`T zB!?@|s+h~P!2&2XQxEN{NIVJ~6mk;}TlHD-r~yZaa)+s!+MV@Ol7~lP*xdjZKi)5> zz0aJ%K-BQW$)458bqORE9@9IQI71ZRHXs-XC5%X-QFt6Ur+K_PpobXMR*lDL<3Xam zqqj}cyPU=GC1%O@bWna7?0GVqALXtKB;c&@ZX%goiVLROX)g$7R zGb~>UqZt!$N^FH(LQT=^|Gz3j0(92!6Pz6T#ct1zaFum8zC5Bd1&4~_4<_W562XH;#-r4kOJ(h|f`m z{6;w9hj$h30EN&z7+`=+G+2wy|G0m`v^j9nre{qlHa?JWvDDZD4DzE9J$c`Qj#5j9 z;1lwq5N+$@cRf%bnoB_aZppZGNviTx2L^|RN0tnYZ@=@dCrKZ8VbOz#q&@ug7hVVA zKJ)B>KPM4~@zUL2dhE~fb!cdO>s`0}l&9-{j&&81p(+vVc7Ly}LvVIck%193iO1fx~? zGD0FA7_3G8Pk95bgzIk0!7#uU^SVY{;PQrVoXc!GYSK#{40R3Wyq{jEc|YB8-uG<$&+UHv&t0JLKeyBP_YC=l zMc!{U{8;fsG2qxY76|!9C**s!;ysu#f5#Q?!G+@d2Rm~9OTAn1MAyN^xR&ZpZtfqC z8qe-ojQ{S18vorL$Nv}HCz;zj9rZozdoD%90jP6DT{p%S6T?;kYcXgcXJ=65|mS)8OdrJ$%0eefGSfFRh&akCG$K`%_fv_L$gnSPdd)eTn zi+ypAS6J+inQdOr`2Rp?N52~ZcpzLL4mc2YVu7CV|JNu2x6rhM7+G7+YclVch2KxU z)>i(}cGRQA|7#uPU(b~NLxCOtj#_YD70 zJN(^D|Ir0vfYDCl-!u8QKAIH))<+9Of%VaXkpRgNQVVxCJg~Q|6zrjqdv8Z6*s~?z zEK7loLg1_gVt}(cjepNXz=3T1J7Rxep$7jz$HDIz{`+Tv|Ne!-e}6~(d&d0P63}t@ zk3ac8?c1r}jqscH7ijuV`<>>0&&K~uOM#B#f93*Vf98TAzr1_omoE_V%R3?8Gs$;d z#{3#0y^dtHhO`kIL8RRr?`Yi1Jj~VM{&!+xZ_uN0WK-@pJVBDV} z-;LxyX7K-G@3>#jxn%0MbnCHp|6|6jr)Ql1y6!pubqmD#uj|D5J=^r|u2}55VSOYd zZ*%O^!yVu5N+%NZZ0U10y&adn<8jBEoqKge|Cl-S>gACq{YuZrA+Q|rg9ODRPvhTl z4EeP6O!Uc?ryF~B`^`=d?cJR>J3X8CnOjpglJA)DZ0aTJd+up})Xe&J)sGhFv_I-} z+TTN!M^F2V%2Pb;gI||L{+K!HJJ?&l7RtOCgx#^?+S0ShzH=6qy`2kX+1uICviIn0 zH2fydbqTV6(TaNDda3J9Ha*E~qs;}$oLrdT1-&|u`@ms8o$(LOVn7cr)PNrBIH0{# z+%tnsH_O-Vg|gY~?r5{=nf9{MZe2Pmt}7R4+p==Ob}f!ydPnS!A*b}7@xOCa)eZk2 zL#I_eBZ1?c+YJehAqU-_kzjguK6}#(<+C^4(Pyt`B)DmIZVNXpl-t5h9o-gsrrhnG zh3C@lh4Nh5-O+QYXDo0q^IYmi5FA`6=cR)kotJt>g2S^T!Qq7>!QqZ1=-DjTHw%q; z-$H4``xZ_ko}L{GOfM7*Om}2~UY=sANk_y0u51@J_=Qu7oi^C`O2=icF@gj!*#z=G3Uz*S4A07(EKNwvnEf zua7mV|0;L5$4rfXMS1lt+x~SOI^Fh;MioHdzki4;$XQo@3rfm_rmWDQNTDe!6g0XZ zH~`umWzYCu?JbBY5iv@F!1Lx6j2nQYd;|iq8)EM*42>Xv{wE^HUqFwYrHHK#tBt^I zOv0l9IX33Ul`V|?0c051(a;aClQ@^hrEQa2kkkZ;dCm^rh>v^jM4H31gA0;L#HR&l*t{9xE_CxG%4ecPyJ@;xHmriqxZiY zVBoefXKvj`YzN6*7kcNO?Pb;djYohtNK^`w06(jzVM+pMg&> zIIr<;#|Xd1`-YGD{K_9&{A3+}Z^7@{UgljzIG7NyAwJPgL=8d5%`3l#Hl~~3G~IUkjHKmE zw>ao#-1{@z5c{TjSvTF!jt1@wZ#Uo2eeLLWKRQ$QJsADK5w?utMRB#$uZQ7UqdTZ9 zZ6Sdru35`rv0$CAQa6MEPIhgh=>M)+%jYVHalV9zZWt0IphwWHp&`kT#+GG z7RqAx%@cP)yKkPjrhCgNv%@^&2QP6au7p0*iQ5eWQ-5m76&9@CGjPa>%h*(yxX7X_ z6IZ88agN+J(sqVMc7{q8VrY5k3`H8?D2{+z%NdHmrI?|bx!BH7s)qBCOb84&yBXR7 z+N4?>3jtMTsG>Np8Ja<8WV=MYw5oE}!`xW0Fad=L7qkaEq;rEGx_xdc2?AiMR0GPG zD%{f7ae_MHa1(beB1sKLhvU`tUG+aZD!82%MzYv{?I`y@dX)ReW&Cc&zi;#(JIej9 zIm-Q?J7fRzl>lOoqT<%H7RVfED*oh271AyrCsoKx5Sn(j+i!^7ZZ+6`s*n|D@7Gp^ zOcz7$fuLVu0|t8`t#2?67mRSC;I`Bw_sx9+Xo)51u)EYFe-~sC*d~3Ok3?*=bx(JB zqGU-taKuWv1iRlbi7y#}5%8})7<^&G{SEi4b;$+?%|Pt3buU~?L-|DVGX7hWe2=x3 zUILwA@WK^wG@+s4ub8N_9AX6zqRT|}U3w7|U+5c?G*%{8!p6b?#(r{S{nRA15N#9> z6KHA|*QQO^+}O;}^*Md*nMoi3jT)$9%|$-xC(jew+V{;yKEx~eBAB@^%W{w-_Fc)e zfZ%qBTCG-P?i6usfb3m(R~Vq9+8zbw zM?n@}dN)QqG#!VD_gCIVvftnM!)V}wF*LvRs|LCp&pEKAQ7SApwOpt|22|4s*{d>~fd}CF zxXFBh2CH*g+K?z&qzg(Ho^mH61GC8PLiS^!gFsK1G6ZFmYtf9yos#MV-|+{X zJkM5Y_wt+rLLnps29~jjG>TE- zC<{|)ho(CjUz()eq`Z^9ng~Nc=x6|czLDI;nQ2XnQgm;wNIJmTPX34|!#%`7nPKt& z(F@iR9Eg8fv#~aeCetKvG5~~DGBw3mFud%YB5|NO$_snsh2iEGhEB9}2|e?o$ijeh z<3!M1B#k9@~~=bsMzO1eDMtiqM93!Ew*PH# z3&NIX=ExUUN=E+)z7lu~SzQwUGERJ)%AXT3H3v?<6HL74Inf$bNJh+3co|S=dGJj5 znj9VD1l;4{IFiNGkxQz!W$QX^G zSenJsAa~yY`0B6*`4Li1EIH6&q;KAffqSJ7@;t zA!3#59_nW;?S8p*52EBD7&Q>oECg6Bn;|gtxVaq!z+*X>7>IM}S@l+a)*8_SJUHCp zRowE!`wOxMAf+eCA&x_`EZMgipS5oqZC!Y93=DlH{6#np*vaWE(YA5t4y;4ACF|f< z4ey?1GSodU+$TBh%pB&JN+J{tl9?$FdS+Zba>J32q4%=^5=csQ!nfD4hJF_b?^kEy z{f)x&)kVwupdqo?g zxwK1Id1pvHl*MT1MkDJkOv6L-*2oqvHhDiZ()r`Rh&9srBi~UY?WADskVR%B`MP|@ zGb>oz`2tmv_6pXnR7;w@g7uBG>TDFO<+{lHq@7^TFEX=Huq;SjDp&@Z-?xKib_$k- zpi2d7iPGcx&$LlEPZR~~TVaWt3;t&_k-%u@+YJVEk6TEnBuZ|R&r>u0U!@z2m>Udg z?5lKVAlm)eL5yE8dqTylJ#MxnA$Ua8JJ~HfoH8@s91F&hHE(U;>;R7N=Y%o5h@ldW z>PHP98>yUf!%!Z7^5-}Fc=wZ2Fa8&rgUj%sSDP5xSj9aGlvR9<8)fEXKRY-RB~Wd~ z@KHINAo3SsgL+O)v-a(Dd4WRwc|mbmvgxxxxs5_hwRPRcp|&>ASk?mpu{{`_7(JK? zpZulj$YzfSP1j3i)Pz;x(~XVyXR(KGUVM({qYkXue)1O+t3B@=(Uz@Qs{dQ-?W9YK zt@TbB%0;)eo-e`HbhJgxL@?$376e<<(H600Ubcue^Rh)83j8SDi@|tf&Q8QZB&0=L zxE5v-PE-g599D&t0XPWcjM?#N+)r5cZrNrAYoS}x#sEeebm0ok;!8I$ zX7Sa3bm&KV-z2=GQBFddh004pKMY_)M&U)U*yG6O!jUlHxj{JQ4d6A&#(L36iN+X& z#k#Cs=2PY(E+rw{7~}A-ya6^ml+-SLTT;C=j^2hYkizxv@X)D&`eI1Js{`(9m*ASm zg#aZ=jv(b^)5|06eUf)G(u)ru49gCFCMz28rO4JZml60!Ep0Kpg9K_E6ySo>&ZrS;PoA2V=_?Q<5? zz%{5io&lDxw1cJ9V9bdc@L!z~f`{5c&tNG?mOw0NhA?ZJ3`&mbe#;nqebr6JtLhz@*OQw$MgaD{PFK- zj-2nltn(T1G-YawjqIM28`;)}>N64Sv6%>VY;R=i&?Cib=V2IelBLkC3SK)ypK>Bv zVyo*Lix^Ku^>kXcw7WLS*(Iz?)O0tBNeCMoc=^zekvbc+T-dz$i}oHKlh)ER(!B9! zGb`&cDD=EL)ZWE9h%WH8N1ng!ha0cH^Rrjb=H(?&7l1&vLxjt~eZHp~W&RcCq$MTK z55frE1cK`4?%~b>2C^cmse{rsc>#z0GrjOhd4Wh3h?TbR(M~ViC@(-=DYh`QzS@4@ z^ChXdH2H>nu9|t@a~)skY=nPY_!fkjy%GMqY1M4s)7i@bwnv`y${=*H+Z8>(`?FpP zQkO<}bJi;(J`*&vGs0U4x-`Pe&MQiUrDlRaG<`Ble&2&FWPTTj`DJ&3^!c!`G*d(N zJw=}n1B-C)Ot7?aIhon#!$QzZ4cYe;A%J#H?vUv*69mBVgz)*eCCD7ZGY7HQ1d|yz zg8LUD2TpC4Br9Tn+d4`~xUEtU2g$oWPr--KIkZq-#~-z)C|%FsD{vFnw>HXKbRlbc z>os1)_|tTG6)T|l2-o4QQukv|%$GFeHt3|9M7$s%^7dilu-_!>jN>bppNHffY~G6U zunx0k<^zW3yn5ulVd!v4&TC5T&T9;5nnk61Uc=?eib|efU{=X0rY9Kq70blKADm!V zX<1XBu;uC#Hk$f`;n2fcdS*KL;krRj7EDl88bBrXfimMK))>SYkk|`(0))sc|Aw*R zDNvMb(yw%#dQ=^<;W{?{?CqPs`s7C+|KwiGL>gh!qo4@nq+c1!mQN&*b{G?tBJp6} zZ!2z8;kl)z5WIw#Hs~72WT#eic^Tx8di5bN0Y!a7B+e>z^NQ8Y%i=U<+`NbZj5okPLgHG2Ex_m3;xMVlUU2>b)9^%%&Er>$86~b@mT8PD*r@S~lo_YTT7bOc z0a)g9eSef)E6Bt`rt-MoTs8p_`>d=P;VJ_hXWd_qzZHJ@D zI(g@mmhV(CK}qh>;Ia%4B=Ev{_%06VkUxmlM8QPRb{YA?h*YSTIi=(M z;j&Q-pAz`-qxcdik-qcjOgQ45l4<9GHt(qKp#-vvvAu>#sWt@VTjcMai_A|Uf5LRZ+nG2%?iQsOE2QZ z7GC$lZ023BFyUPf z{ct6lP9;A0hXQ2whP#foo1WRO`r%4AfBYA*;d1`ScQjlsDx*pNt&H2LOtr8w{#Yys zExbRD?VBi%2EO${fC?5FlUPK17`LxjnT_uk^;8I$+S7t)1ZflFPZig9sNk2A9jg60 z{$1Zqwfb^Ft1shDgBsk*&_6}Umvr_mH&W^YP-vk>RC!AXn>)ND zYC0Un{Ms`D4xiRlv7!GM4`<7II9rb8n5;}sF?gEsE>6Ult5mYf_Mo~<1sX~gHjXSF zp5QeL=(5mi1A$EJ7Uj5%zPZ_u?T5H+$+rmAm2yMd3Rip9WOhc`7d=Qa;jsS^`8+){ zdKGta_X?vyz3;e_`$7B&9~ixrIu#!C@!(hb_-^1<5>T~6HS#ncF!OWknbSq=6*@F<5J!;J+2>m z?ELXx+_0x1oY}T=00*j$eb5j%U~WZ z3}!^V*||FHjN}Ygr)4Cg^y;)x^`0Os!dO)G>}Y0}xl>C#)nrwXt&Rnrt+fU}P?)!p z*p>lD8v=9YfyvW93wEPfxoT=3LnSxT)y-kEz<4^qYSNpGe^0Qan z3a5q|9^I{v5SwBAfx|!k`IhaseqoKeJ9Kop08L?kCuw=gg!aJ~5=kNM*5#r)G0t!; zF?b7gBHVl@Q{r2})8c_y?}0zE4H%1*&Fz85TV8W|A`|2ruK($0uKwzCAO3*&d}Q~W za`L*neeZ__gqHi>p{``IY-@WakB9E>FA=|&5%K!Fo_^`(JsBk`-em|q(2cEq9SG%5=eE!w_q~WWN1`Ycx5TDFw z__5o!ee{u+e*M5+X%!}#~~4)%7{4q)K!yT`uMJ=e$!VXjvR+X+?NsY z`dhF5;7i~9>GR+3D-q8)4vF}KjED!f{_yTUJomu!kM@;_aLZZ z#L=Tc#6E9Vew-2U%O8LDLr?Gd@(uq-Kh?y4cO262>5PWI_{24bAO7&Jd;2O8tH&V? zpUG(Wh4+2(J5PP(n(JVr=-;+^;AqgW&r9?EjD|ZVpPl@{i=TMu>AniYR~&~#{7FW{ zdp3Re=HGtfXP-RMS0XMy8bs{#s`6|`#2xqVIP#r68=p96u%;`}0Tc+tt^}EQdVD84(xU3f4FdXY)@pPTc&y z_uP8J``+`^KlgJspLR58*k}FbXBiEjd~oU;KRI;h(fxg$&96EdMC|j@{PT>6ci-{C z_g~!enJ50gelnssK`yjJ>@y9Y&uI9ETOWCT(+3~j`M>v*hQmjL5Bofsf05DfgOhjM zaqwe5{r&s;x@&&raY)1kUz+PjgNS{e&A-ezal_Q-KKkTW?)-dTXY) zi;rLVjq5-7*#F#5Mm+Us(C~O;#6LR@iTJyW5ug41=eBRV?V1mNp|3jPvZF!7lb1cy zdkwfsFq;%uJx|K{A$sqhz?VJekAKI@o{u`gK9OA^oZZml#!6DXXhl5;*79PUrV5pd z>HhSKrLtbXLu^())w;~hrFdy!zb$EstPZP%??jAyE=$?T_wZ?eFb>wQ0-p5 zyZwm5GCM?Z#~I=G^iob}u8eiOy}CK{OKG}{j?uyxxNk{W1B4+Jh}@LRU1P$K zR&X2E+^S-V4jEUxh}%IDBMVU=8oZ2+>>)8?9K^_B!Uz%gS-cWeW?M*dgpBleG6gIm z=}AT8FS&38K_^fPSC}MlMV68l_lJ13Nj}&;14%IMR*+ozAoA6N0a2%pfCG_ylh71Q zdV=Q<&G;O#wD5fAjL#(m;g#Q<>A57ot$mEbi4CPeEpW38=>hGHFW$&A7cb)ySar|6 zxWHHYg>vb}p&&ve!#~5XNiW&$*~?^l+41$f%avxD#eFQytz^p65Q5f&KP^Nw3b_r> za2}unC!8CRgqdbRL&l=mPY^gSJH?_vlT0NOFp3A?_ZbFaEp^UN?sM5PY|IJ98jc(R zJis1s)?~+OLZ>K4>1SFV^^odGNbpjoZwFD~mNY zn+NYR4=i=>Fc1Dv#N%%B;Df~)pED0$F4ov#9&9MqxX(P8EJAg^dGPLHjfc&H8;Uh{ znFm)DYkbE%_+t^OC(MK27HRdAdGKPf# z$#!_5JxX3ow^z~l=HIQm_kmAuxaDryUV*H*QSJuSVeM5)?pT-ze-L=|HXT`}K9^j8 z^Nd!j7kD}9I_7CmR|ypxCHuZCpfgIX!NA;cW`tVzjx*7xv|{P6n~*Pqyk$rQQaB7%qkgKr1vbtRX(E>`8${BO2P^ZBzu*y z89yTpe3d1-l0adtatO_k(88&gT&FQVga9d0%1;!)< z``bYvRN%dRSp>RIZ)IU=riQrZ7h%EJ5|-!M!P06lpxxCV&SidPp(dE@%RUy2|Ya=g?I1d=0V4b{XuXMwZB(##l> z;tN#-#LU%qeN`m+40Dy+P|9ftY({tEC#25=!V|g)pBW6LD1m0T`UkT5W3y!9Y%`fO zC^d=?Z2Q28^@9Xk z+S*OBqAj}EPV)_h)j5gmOaxQKqy@o_?c6&zm;A~Vn9~Cju)Amq=}7f!ZuSo{~m zK*QLf0V8=vBmOXAufw`>K1?V06_*hg9JUVZ$uGt?SS?^t!S{&<9$h#BD+g5R3*?gl zcto$xS$8VujReREn_SE3j}Z7r_*wgonkZ6(8tPd?M&j2i2>OklJVpxj@V$)rh(xzg zKO|@jM3%63h6w;x@ENIHK&=u~MFaByk-&k7l%?Rq7=#?P%p_aJ3w~UE6W&2*akX}{ zOcizsA;ix4Q5lM1S(<>Y4B2fj0lknV7vGnJfgd0tZHnFjPQMgAGz-mvcf9-wv;!nj zAIWmXh8agpvx_vmZ%1hJdIdlb@J2PMpmn^#9aFpW;_g4YH>T-P``RnLXAa~)Lmq>=Bl~)pkBHtp*FL3k#UHeOe{LSe#N5X zkbk!*p~jwk5y}wk-WMU%*bOd1s1YD@5kft@D4|}qD4{-mQ9`|PQ9^Atm5WRdIdxIe z8dlLoDETCg_oCDJUb!e~O*_Hj+kqhgUjD567;_xY znD>&7&e=V~zaOck=8u2J+XnqVF+M!Q5&MHP9kCzVC&u$7*yuko8zfk@fdkIV-UK!d zBxfa#Rx5B_$LZ-z1pE3-1Ut4fb$+Z1*UioM^SHa5+$o=bK67%(jeLQgar7m`2Qt3% zpu2_R<-3I22Dj<>DW|APlW#9lmQwPU*UjCSdhRI*LZck_9z_*PL zj~<&BO4hsb%<3CmhE$&Xc)~Nq2FGd+SgI`BAcU4?Aa*fWlVe32lt?J8Q$~v zDS1-|CsMp6u}ek?Y3WQETF_eydgU4$#ie*Id5OW+^Ug}5@FkD^eq3EwMB z_`VK)n40jt!jz@r1`vtE9y|>-w>mC$t`2JrsD&Qfro})nN@6Wo%bT{y+bE8sfR}!b z8N8!({u8)UP!DCGKA(a5#|+fxZh7>^tABa(iyDu-0P1`5po*^+o3F#)oXH~xgH{)z z!~?n{#9SThd=Lr?9l%RK5$QjJsjL9Mc9>s449ZEhQGrJ1gjK2$5$X&6DAsGDI`3M)w)SCg?rIY8r z5?5qZnrIm74>V5shFj3~S~_k8+5D@!L%IJ`ndwT|UgC)St3Qy>(`MS2$OeR4x7~a% zzdhkD1$zdxTLNWVJybu%D7cZ}Hcu*?0Q zc${h_x{&sh^?WI*)V`DUWJwrz2@%sTh`M$n&@TaO2f?e%6GeS~bB%i?=(V zNL^>OlbLhB*SNanF2|VM@2ZS!f5 zk`H4+t97r8Oc6&YBVU(KCon*Eznv<9RYrF3z4pq;_fne7UK!c>u%UlDWn?#BN(O6t z(|%4YW#kW~_Sehz3wfgCfP5~=)XU=a@_l@PL&*!6_`n6sR@cj?Q!;mRy&PKt=X&`M z)2i9^@&W478o~zex?8RWly3&HftrT>PVzfKN5#C0AT~p>G|O;AtO2DJ+a+w4FmXj4 zj<`LNt6Mb-QnenL-9x1C=yiAOs{|}=1qcl`TZHCM?VuTmhs+Kk>)za{R&89mr?Spq zK^B5h0|9rHLXkx7xECQX^my0KHuMmcA2-Y?r$*5jKWi=S?h0-)*ccHEH!jyMs=K?L zc>h`wDH&L_ypPQex$TB_W6f=+#O1>H!4h$j_qp9Y0eJs+k;wgOYF2>x%GYg~OyuMy z;r%6xmiHl>$osc<&-;Cs`gga31tQie9_`{KEOwcD()e+#7(aeMb!w3qKl=!zA3QnS5#8H+QL?mL$=MUfe zrE9+Y^*h863NOb(#FW{mS$JC3pC+5^I5MQiu&<(Lnq~1pldKH@SuO;CEN1~AVG@D! zDH?>9Y|j+y0~lmz&Ml3p`vn9(<+(LJY1pM@1eVsLks)9O*ugP5t0B5aJ|mrjVr~Cs zYehi^s)eF(qPsZHM6hQTr)Kqa->))?*m8!zYJ`-Ll%T^B5lh0pA~05hNL`#MQ3Ig> zgSDZ^Q26a4(AY2ngH;fvijy#T2V+(ZKoG+rcp#?t%EfTnDB(B*o&tji7R8ui7dJ|b zPX<{#7*{TC3?QbJ^v@%GOvQNc;<$o#7!^zmRpNY0lP92%Qe*yPw08V=5pLW?Lk|wv zAiGg&y2u4WXDIMwn#`VzBs=AEG&5SiUgM`pd}2zG9WpD>(HpU@;Nt>72%+?P{RP=# zgOt~PmWq=#>J4!g=aOPPHbNb?C_zm%oH3RikgoRlry*%+Lms7FN#FyDHJx~9 zfxQrDSl?)OZVbxtm37J_eC>YTh9w&oz z1~T+zkaju)t-(;HB-d!t;;>{9pkYkpXstdBpcPh<;Pq;d1`cdDL+pb3puE2p#gHbA zC`QPM7{EWAq4fP(qO@uvmbdp6%Rb?Zx4H{B<|2xdsiO?(+a zhybuBfXVI{tmToznhAGuvTCcz`BP3#j9Um{b+1@1mnEACSXY+}IQh{(CO^I5*gk%( zjh$%WI{8i1=W{7D39ek@>LOIQ3DK8@3O`)3QY=iRSTR)iVI#w?`W9uGbMTfwN*xOh zrZSA~QkcMF6hw}jQ|8xYMObg{n^;DP(W6YgmIBO~?e}E7(yai?=D2bQwDT5oJf;Av z<>okn>W2GQsq{j)`yBI+8RqAdE-?Q!B)CfC`!j_8lrjGk-+TQ2@BHAZd-mbjjsj{7 zqDDnkj`@usgZN6Be@+){=EwVF8gvh)A@8r!UvbL&@Qur{emmbdtbv>oSOc9X`G)mV z_qd^MIR6Ia_+-&@{>F?^KA>N@bib4_$~C|K)Xmo%`tC!wHAzXVZpJG#TiuR6=iiwj z^ob0i!@8AZ{Qgh8_>;RgZTZztu4zIj$N8dWh}ah-A@+}d&VOg6y`#m)gzGEKTwipw zu=2jWqlFdrvv;(xJLlOrT3}`7f!kK1p~5Z=;2&X^p^jB^KWw%jb?Infj{iQ}4w~6H zT386WbhLoxO?rH(9Rw|+wP#BC3@#@Yj%G?A&@Gm$g3Ae38N%^ETR2XT!^h3T?dRYl zBoh4Fn^vBMn1dL3$Jxmab2bOFTpCpKmLoSqy5Cf1rvYY2VakRl(y?xpL}P%enpu{` z;X|6mrb4!guCtTue~hye_dXV+<~#u{(*%gK(?Ie}J7{K?PQyaboIs*wLJtGMPuoE- z*8~z4mS$?mJe18e21#AN2GsRyAo*20SZ0?%!a~qYjh4wp3^iV82SFdGQKD3uff|2o z2TRYW0dw|@5L~&-tXHk(N*}0EX#>kO?O^E{HCiTnF}!hoI|!hr;ZhcM2>8;@EfAW( zqE6|tsT_v5*;h_?=2LE>Mb2Yjm)xL~s_~qO|61IN3V8Yy=)@1w3NUh{i7~nL!aXwX z*GGBtYHXtRwAuDgj zLDy*e?BFZ~Vhy@N?G_+eJrdWy6aX<1$Mve(JyC`0klgX&8bWlq;dK`bQwBr^VLFjR zn1E(r0-LU3bdU`+=VXw4B;`W_sk&oewaCD(U@$GSJty7d*f}9HzX;uKWh3xie=fD$ zO4TDjIM4@vX(d4_KyT3St8Pdm>)sv)ugilt)EH!8ew8i zXG5A@pxU>w`Fh6{_*n(`or3wLbMlxgD(ZGtZB!xJ!i2V$U)-bU#M=Bp1U zetiW0;XY)zHZJ1`V3^28DY8(SsB;6TkjTo!HMb{~K7wfoV5U5)NgRCtk~HfO1@R!SrG{(RJ>G<| zmmjak>1s3aal?`z$i6N}#n)L%q%}ZP$C%jYAzK$_q%_VMyf7A-FFy`M6z)H1G=x~t?XE}7l z&ovZ{Ia2DFy5uJDnqI>>on)s$mTh(^mRY>lz@z{XVxSN=meMlGX@g8cOSjackW&u~ z8H24a8L18rGvzjp`QS2vs*v?eCIc1$TY5Mk!OJ6Y6GZLhXj#xIPE7?)>5HWnniHW=6Z6+pBFqkfBh3P-);4aVefLt)k@c;+t?e&qABrQ+{ zbYXU53$xi?C3nkn-^|du!GWTUlcX8wsr|H}D6e!1$A&3k zS1R12SY>BN(a=ydZ9thxiMr|fvRSG)Bw#UH0C7pQZ~812U`T3yKXNy|*8_e%EMJ8e zZsZ$qWC#=Jo5}7}-R6*w`?@yl!-E5Sux*?}GBv!8G9XNLdK1vdW%+4 zteDcE)|(91>B~E{le1za&OzwA{~51?UjGRnGPqGP^(k}+Pmro?v%n6 z*ncj&8lX@|ZRTj~fkJXWmzo@7ORNra*Vgig=wwZt%)EAv1OS^_xs@w--T{zSehi)T zUrzS{u|KQO4*hWOKa@HJP-OYK|4{kdZD`g-?7usIj6gGNY#*xb|i_m_^A#mjjX?-Lo1&PA$gXB{DI23}0= z-Ywc8ucB?$ue^@-a_XR29)Ix4Lm&L)2fzA)y0PQ>m}Lz_2+QJ^N`x>SYAW05JvAJ^ zG{?#`5yB8Fb1%CDqos18ML@8bIXDp~lX53U<{^yOZf9WT*|Tu|*s=e6z-dyc#UAjF zA~F}<9?-af+PEu4xBr7g7ZKE6kk8H$)D8%FuodKaGd^(G%a0gayEL5Zm3L!*%B82t z?LReOw_sBq^zbxqb$IwY%BH$!T;=Q;bKNA9j}h`(?N1z-7A=DDWxFZs1Wr;J6ffMJ zTN_6kVwRKm!va5D^6eaGcDyt@KRLyqvle zs<<^0@LV9|n@D&&d&d;={AB_Q`IvK=AQzh}54pJSMaiw5Ay@TGPotY*k9ijYyIN{- zpOR4-u1%&)5aFht?09iroo;+#B5~LUKw*@NTx4VI(g^~GFm!By69ilhz*})ijW60x z+xrBL6T~2dB}XW|M`I3|=mBBJ3ryHepk3Ec>wa(PzVM?`7{Gm@)Yif0-*gmeZRSYc z!N*hpHB#tF)9xI6=-z_^4!ZZ?x(T(Z++j`T-g71lQ(sZY#_-jw_i-G!>-{L6zy?L{ zn)?hE_-b{mprB&`NV#U^xB>y{7QkCUGOE`o;fq9=W15wyGNFpKCy6BDd6akqeO0(H zsJ*0mE(+n-^ff6AYcHqDFWf*<)`V3CN@M1q1150%YVeCrEveU(vL-J3lQl&K3TuYS zngNz{2?L$sM<*VO-{SMnS(8-L)6}FTgLg7C?h?vZlRfh3+$}2_8Xx2for5~APle0u z4UJc)RcB*pG{(KB37r-3qO)h>J+f*#k5juhG+KaWXK38t4i@n8Nkb!68#+TtPCTz6 z-gG#%jT&Y67Qr|VQPL#$;CB?!0|YV^i+aL);kb+L)0?B^%V--bQ8_jLWA~l6@{1{- z(c)Xw9>E27?I#Y<1%3r}SpH?L!;Y3KxCj^H1_6M)p<_3E%T=6K!P-R;*}NZTfAhz` zqm{A$Tb~0WeX-baB*nlKBrr?Vt`V8J=(av5+A+kjD;?gwh@?Y5&S2(`|KdJ_nLqv= zrQ@T%@1{mFzH^Xc*lkSE{hr}qxbedtkZDHY7Y=Vq{D+WUID5yIqeEF`jV1z^c=AmbJpVhEn= zM%c)~TsD6@O3PG`6$PdU>ym^vbEPKE2tm>gQd3UNOBbh7lY&vjd~;_wbWEjY1~kQ{ z^xrkol#l9RoD&dT*C&e&C4L=r)RjWTHr51taQT7%D|3dQMr=2;{=w7Mrzwi259mw`F-?cz8Yq_y9c6(mO08BXEdJs*@6~RV^^vy#VIReg2T5SkrMBHCuPju@ zy}uvv@^8h_lIrNGx;X1S7JVKEukl8g44i&C9-V%AbUFxu&Q{WE6vkA9CpnLw&!QIN6wibD4n?p9aoa z24~Gw#HUtVnuBv`2ItZg&Ls|d@F&`n z?%1w$$Hokt@(ujS<`qsv&NtLKNx+OM#P$UhyC07G)Fn6t3Ljdx}f7jK}42RCZ7yn5!T{ zq!WbjRA5CS5J;S}$+IbZMl_A4n6QFdPrzKG7x^gmc;bD2GXh=<>k*_I; z9AIyNuYd_IaTHKtZ?nc_JtC>J!sR;baTS>xaXFKqZNO(bCU?nGVsnpqx?P?sHd>c; z@^uBBP3*84ovmyqH!|#R*62*lfX;&!om~dtodU3q&3=o{^XBORd8+7WU80k(E9mTP zjm|XN$)UskW{u9_8PGXm(ODOuS%5Z)&vbM)1}U#?HcvOnQ$14cC(!v zI_z)O=p2{l&Ni`S8JSl>F2Cwk(W_K0Zx&!z;*GlqBtExFXS!%VC{I_QbeDO$Q=aOot#xtj zzff1!?Hvv(r^mYF;ms+wgX^4G3Hyt1KQmim%mT6!fUaB_t#lR;LV|^WV8$eg!XXO? z!QcYIXIwzSVS-_n!qW@&L~n2w5ZHVvqf(z#L}84|I14n(l+e6=Mioi2Iu%I{fhdKB)l~^4t5XT((*yVn z=}&@D)4H_HjJ^$%&x+M1DM> zcVxgn+l`H4fg2r-Ms(U6Cugkqc zvccKDr1n)5b2lae+s`2PC0>W*4i{d^(envJfY{cE`ZM5&MV=I&C-H# z-)_wkr$J1ec3O0riYc{}P!Q2lLO~=}4ZF)DDW)igXM6OJsUVA6Oc|-0iK;w0DsC2!K^Q_XGY01m zyVamexk`gBJ&4o}sOIg|yf7BLL(dk~4#A&GG)@Y2vAXQaSLI+9X4BNE?kQCXjwri!SjeF->>1vkp2j?_4%$f$7& z!!j1!gU1{nwN5EIT3hg8Z6YMPlp+NE%RvZgR||yj`kWB5CWazHY9|ncb{T}Y=}*^j zH8Kc7&l`je$YVuFYYRfGO@y?za2(7G4nnXlv_J^2&j}$b*op{Q1#B!>hkJ!&H{D(7 z2-&l)v0yVEbA)tzr3h(lL5Q`9kk%H2HUut0*jBYb2(QlxAuHO72wB-S7TjwPQawx& zQawyYXrDny6){CfYYRfGO@y?zAOuYe!0Jgc?D#Da!t322goYu~z&LORIVmqvKZTR> z!dN9w$_tud<}NQVy&xely>Lc(a(bPdUcpgaj=_ysfWeJCdFKjpQaOamw@8FN1`p~W z1`j7i$NS&`*Y&A7+Y(p20QUtD1Nud=% zPI2}ul5I|tIIwn{B0|=yZ!9=u_H757EIG1oyOD7qAc&exIkInKZSLE&w(Q&B*yrrq zV8UskSmJdl?O^*r!*J$l*(+nC8REu@wC1>*Q(hvE7kv}M)XSS+ zh3ld3)8t~Hq(`{iDk3Iq%LrU}-@e>M1_PH;hrryg@un8~n;PW)Rs4E}Oz{ zoOi?If)uXT;_?qty~yQSy-QX1fjBOP;|Pv*Z~8}8a^UaB6myZfvzAsF8=BjI>uGAAaxn&#z6ChcF@?Ay0&w<_ysT+ zi|pGn4$EtsNDM#(c#s*Yd$1(rVKLD68A_xdw*!lap9q1zzZlAdu#sAe!3F;)15j?B z5UVtxR}3M5&^QwRjawEwFBmLK0&B@fEW?RE$X{jW1a9VWB$w;dkYs_33ATz2ni%u> zc!5{$;j9d6AJ?fNZ6@oauv+_AI$vgp2}Xc43K(O!q7(jd;gXnO;IR<0t!0d?7*eVj z#STGWHB^{`FYcMMd0-zy+DR%upzTDl6V|r*eJBuh(qZ~}bdlCzva$s{@-a!sw-yiN z2D6XrfJT;em2~ntQU@|QSgZe91SrH>$lI6*M#>e_RDd9ueN4JpCY}6%fepP*uE+eA z>-po)-SX&-SO4Swoff*Z zc#SZrF+W|H#FrrE7h-l|+ClgD4V8yF<3&grA}&t)b&mQZcfuj&R_rl%lD-lqS4uoI@umMjod>U>f~a+u zwlpf_iK_5K)$l|KJb`ib{yvW0+^DXYkv%HuKvbl9h1F5-+^Z3zwIu9O0Z@ipgiBan zUB3>CY$ZWx)D@O#I)To)q2P0KAmD=$T0sxG%?N*y)Q&`2eOE4 z#TwXpc?~c5+lz#AnIsfXa-k)-V{0&HWb9*-7UOYX(sSy?0cZo3PW*ZxUTPrq%P)Iq zH3^__;xC*V-X{CV=Ejk2$!Gs$S0oqJ! z^G#_zYSa4JY3l^gi6$cWH^p&E1AJugF-$vp0o)CZtbu4ECJ`$UL3}ImBZ+}+H}C|2 zhuDE>b<-ShIURab0~*`-RN&Y^IW`+prVwvLqDm+QvDq zGqm4gTuDuLP)it8gJB{VD)+DpjBwTohIhtJn#kGI322#i5=oRQI#R~bzia{P{{`6y zGd2mac3)htB&T3&5L|k3Q-6TG(M4PurJC@8jVi;qThLCp)I{hQIjNa*;=e%$k-1i{ zLS9E(m>W5+qMNv>8wQ$T%odpoNP{b(o(jzy?E)7|k(MG3FGPstGCE*qymN{q<{|ju z&5*tU3{#ptk@|0P#A?Hg@WSX4JD!l;2aGcKaqw}ojB9zzvQc5>{LwS$cEB%*}RcjWjHciYRc95;ww6nKcwF4{N z@m^tFb+m$P)n?mv)i$lqxN4(y!`lH8v*vXIxAnfQ+8~AoMznyyh+hCCTl}Fc%5qJe zRhR2fmh0aS`qe99?={}eP&9y?%-|tw!!gq;mMk?%Bp}$3c7dFoX%sZ}a;Y!=lU|n$ zc(}K~&@t5k4rkh3QzxnVf~}A&DbP_Ra-S?)zLcpH6r~vx5`E69HDmO0l_4&HP>^b$ zlX%iXy0OOqpL6IjTP0@b5s^+6w?g0I z_KH3U1N$ZnrMbZ%0s7iujqQqoVJ2t}(DH%a2^FCsRD_05mFEVPsEO^MLedBWRcH9b z1r=}*PQphx2_NAke1wx*ZV5C`Hy9Eb~XATGp#xDW^8GJwxH;8L~Qq#5QBQ~-m^ zJg^!XdSKT1*WM#LPm%ig(;<(YwS1QgmhX8bV6!Iesu)P9`XChr<(neyBQb@k`K4?OC08(&hz=rt18J|6C zQWcd0hFPlz?P{$6&D^6;TAW;hVhM?%qDo?>x#b7MYBt-ffW0H=`*E-M0Z5+_0_-xaewB7 zbHur8qa1Pa@D00-jUUIa25hFou}{+}WH%>zq`#o~$$_dpP0gQ{Zf51Pp<*Jd9IU0> z`iQoO^=16YpWpD~-A_)v_+Ka*yu>JeHd<}}b8~FuL~D_j@H$y8Xh6l1NEenm0`DCA zsp)qNb_&m&ZY{WP@p4-V(4Tk5oV|c3C9>IU+GB|2qqxDq5Q1PvTZgApQzUP=QR4&` z+K1_+!JR&M$v7}IN7R=^A=`=RaeGd+pwhX4gM}ugHCAav7bmY)yKt1mg^gVXbtA$F zk>{V|VfDf09I%}}vD)+WHx2~6WLfqbc6KirNPi2=W-s;sv-j>%mR0q=?_O)|z3Z`e zRqd*-rVELewMYT*n=Zaq|abT<;lMMdWZ!T7ifW2_}FTQCmgvf!IDG7*X!$`%QR@^HrrRj=T;0+ zvwVhw=(+&W+2J7SAvj;D$WLXvL@xosS%aWTn3<68$Rp~=Vkk2@Gt;Ttj23-IW_em; zeFQ87@|ChNKG;aM__B22!<-p?e)b+bUT%0)USjXqjgtF<6TMTy44*CpLTOdVP^$jY zCC(jG+*}DI&Y2ENVivnMlsI>oam1gxjUnRD{Ty+_k-OPGWpc+;MYm^HJB`c^DYuK; zFKWHnn7Wc0-=ZTqxpPtTl>g1mhhxb9)`mwYHTOf3;TZ-1Aq(h_ywhpzqfQhfJn<=e z0utzZ;>os|)w?4ErLh|J@NTgVB@#r!Zk46SnXUsKS8{Wl zfu7d2wv`NX+P41V2kjC6VAzeP-0D%W)zAmU7#N@Aj&i=0c4QNyL&gX(Y*;IN@Y9aG z7!ElBOKvsvpV>NzrleMhEy|%{MTF5#(%2|SX$kx9!=@?>u>Tg$)yjujn457* zAfCB7Dw0&>pIqQ`^_!^mJ3o5QuFAAF!B$8e=0}o%d|hG%eBT%g^IGYK^pbrfwq*-{ ziBDEtX7f^|Y1zjrLq9AcNO62_G7yjVBhyU(^A3bc|#HuoS z%|BCB0*C^VYI0M19FB|go=e zm%Bgw4)hL&vT*>!oJ6cTD``7S;=VWb^7#9cO|%}xir`T#^*P?e*DWy z{U);*)8SUJy2jN*FzB~@MGSg0dzbw_ZD|I5aA*eo4{OVyKN*@E%%Jc4w_XPQ+7Lgh z_Cz3i7&NP<4xd5q53~$}zTaRso!zdktPO+qFwCAU25q~(ibq$(qq`#nrS(*fEjtEY zd4}j~ytblz<-$Rs^%i{ZC~h~8GujmjjfKI%0pzicEjag30N3{AY3O4sg;V_uew%O4b^ z@}N7Ef%y-GfqCQ2U%cfFZ@T9LcMLKx`!Np zI=dFXb72t6VKOedtF#r0vW}9TfaPlGLiC@nM6Fy8oA-e~na9CeZfI?IH7gD1rz;%L zrbU^;8W6T~F*LG}p7e9#1k}DF-NU7Uw0>bK{*iZDJt{m7$nyAmQ_BZ<`HpU<)oKB@ zyjyfBfVufI0ANSATl6XCPI|ON`PR(2Gj~1<#nOxRJugdk;D@d4b6bi#FMQ(UNJcdg zT=9sNxpSWrvsH{GDB%J%*Sa}For_&%nOcjj&jf?`u$?>0IyZi`Rw1oT`S@8P)IWaK z8kw-v;5R)^gWvR50ym=0ppMLS(YhksyJpBg67js%BY)X=-Z0UIi@z#o)@1e```xg# zGi$dV7%JNEaPU5@O|;?G&|E47t1sH{`ESy%u4u#KVmtgI%w3#W*B=lJr?X4dm9=qZ zIT)^0wBdm`QTdC!HbIey8*icHNMHViB8qW#*=x)O)8fK6{PQK(Uj6Ge$i(>eWBTHG4oS7ZLU@Oz~+SD z&ekg~{K@Cub=9lC`ON>^^HHsz)W;ThPgz>aCJa+^NeRRJloEzHlLt^0n3hi%CbmN& z+qSIw-`rb7!OXz4D32-F9Jw_oA(LyW0RTrsipJkBQ%dW$`$Q?Ny7P| zW}8_c!l*>-o0PBsL0IibRi4mFer888RKDyxO?pw{I?ZBipI&60uKG?B zA!U_xPp7r&eKuwE^eSd6}9(0u~ z9mM{P%6+c77LpU(kBV${4Y#B8#ynqL$t9eJe02a;>Yk;>t9v0ezQ22&h-4L)3a{J) zh>h9|;hZdnT7CkZR{e>^XlNDk2WY)mu~or<&QoLwvX=CI)Ie5n%+~=JWVQ5c8OU}< z46T0I!7{LAo_dH`QhW)vRS=oh^P9jn0NNW?O<}gYf0+poegq9;Uw8--}&hqjYAp+{UQY(kRFu9S!BE? zi~ek*6#@}@(wcmhsxB4giY15EJkn~uLQJvV!J0}3^@)sCa1Xa4jB4vzlE6FW!gQA5 zYl|x>eifd9Ns@?^PkE2qj+L*eIYzHxB^zL~RHai1JOV*3h*8y=0-E(t4i;Aak|;xa`KV~u{)tkBuz^kX)m zI!dk4+xx81*9D8Hy7j=TZ@lZWcfIDJiw8xrp02qJnH^T{+c9O04nqjH8X=4wyM*wR zTSAfvvEP?%QxqW@h7j&BLKuIF5LTE*b4+oB`)bQau#mDG_wBd#kq1c(Qz8n>&oIC3(Ln1ZLH@>XS*Sq+8Y;%n zMek;-+0a&%M0-r}^|x1TXNi%JmBf;|$h%ezwZAZ`Z}#)_S+~@sg$t9s8^u!jDQW%1 zjw^D9vpWj+38?12@Zq;wu@|#fo7a21^({F-^(9*hQ&a;o&w6Q5|1H5$I$Esgx7tc% z{it$HzTF79I5=oCesFqZ7wa>Q#KT?z_=*=@Ary4~C&hLnKj?{(^b*B83>P!Y5ye1i z@U*g8qJWmnDVw7i3e(bWRnH2j&8fs;m`N=R?>iKRDGoxr7C+J&ETUAQS^c)O(rFXk zh!Sy=Pyp$74d<}7D9M*Oscl&696w~hscp_$XzI2_2~((Ri;}Qnko!3CSqA2p6E2xg z@8c>V6yNxTV*sN|F@O&nt_MV)yBWaajceiGYj1;b-a&iOyasr}`b|S(UH+D#cUsDc zZ#f?0`{F6^Gl%NSlZD4zRWre}B;DO_ba(vG#$$%2JNSa=?$?LHb&1=Q=+3lmx8Ow~ zO}@yV*M3c5>8aMYomg`+@e;e(Y(1chxEZ0H{(ZL&L8SQaOM=i7Y0GtduiAb}5O(jo z)hh_EHw0`v+K6-+LAXNFe3A&lZ;s?1j=Vhmot3gWyuY%TeZerkt{>y4JAHVI(}zpq z@P$ZlG~hFsvdpK`-5GNgCmVlgv(Skb+}iI`+}iKc!rE`%DXB7gm0Uh_;9~9foUQ#< z{}fKm{R4Vb7ng8zJm8Eatpfi_VK?1g_z6CI!COD~*v$`pYu6w{a3VJZCyiq<9x<_= zMExyF)L-aI)K{-ed&>tP3bTZWR=WusbBhYZ%}#f@`iw#C76Ut@&2I4A-@;|L_Mquf z^?y|i>F33ehBXDr_xGv#H0P~cX9{Mhg-Z-B?HgS8%6z4Hj2mn2S%^>?oK_;_SUbZT zEL*@!&q{>1e%qL`F!nlkC`qRx_(7J+gv+~ zwz1qcieF!9a(CBtczkldeqx;&ZGERK@lBl|neF~y-5v|MU#6-P{uHSNGo`f*?t0U| zEh$UmDCB{oMJI$g$@=+77qdQE@pYo*49{@=(ynOZ@pBowG|B ze`&g4(z_zZrFTb;O#q9Qpd2* z>0#KHScNQuSU1PMH1aH)=6ZPcCHLPI(t}^`4#m{oSPbpT4_x=&JAU(%oBM|bQ!9A3 zrS_Zq&aOq-K@)xI2R;ECx3p?E$d~tz@!sAs{)OY)XBT|iB0S|Wj+GfVV;nQF#2ClC zT=GlEN^ zS!;mNPZSuvwixZj1x9cE^>;t@+5dR#6Ldymwx}@Eg-|RJFNB?xS}8(r>mA|?9YW7o z1BCudF~nPnA-<^?;v;W<`-krR{$t6vaOFcBgwNH^&mm3NvbNA=!yZB-DiQCa zDgev%a#WD`tKU=U2W9XVRRl1UUY|oXI~E1 zY+28jJ-dXSzdDoFK7ti1V?su)eS~uW-~%{?E#b}Di=tk;c9&n7u$*DLH*BHY`0QA} zb=2>>+WmFF%p$nHg@nhT@9GLiGV+AHyP%#&sH}+zN8D%YRS$pX!+ZDr_&cxb)4xI$ zLzB|J$OOW63HQ$9=exSL7}8b6kbY9Q<9>GSzOR4c(LFbxH$Vd^CjCsVV;vFKmCdS> z>#EBFI>Q@4`0$pre{L$qHmt@`us^9Y@jSkWV28_resc%_VqtJ8{1ns*{4tz@%B!&=(f4(rzPrLCpKu7o4B@GmTOMFQDkMq6bh69Qs90mN&|rz*CGMSSq&n^|hZ^E+0&9jD83uut;F(hu}8^-PluJ`)ZAAS15gSWl)TkrfsiJ6}L zVlSiq!~VnFFZPxYMn6h6;9dFlrc1%|ZGG^3YXQ$MUH{3?{^-tkeC$gWt?2>isy5(V z8lX?u_NM>5W;A+tA58N?%JrUIGkRdU`?rZm*KX3^9+DdJN$(3&;u!GvVKTWC-*rCVB)U z{Sz|j|8-_;)aw1I=AZjF7M9=~AnQ2sd2Py8OU`>vynud2!f;;QOI89p9ID!x6BU&) zlLesa^vQW0Y6xL0jGnpCDnN~FCj!=~XCvFmQ>#%MwZq+4w8v1SlJnZ*QUob3W7b%b zO`)%InLi`jv&!>PIWv`=dArCyyF`CEdo0?XjsDrj>>YMq-8ii+<|}H09#+zE{EYrp zy-X-TU8#39QeV0eUv10}5Hq7i_o(a@HA$|*273O)s5V(tb_+MR;PT|>kK62(wi%z( zgw9ej^Y}TjJ*kVcovD4DmUf`z+rO+ z$}c$=+}i#MRA@ckN?UqziW;-DXphe5!Za7ssn_hY2OH_czV^Bppi%~oLU1o&Z{m(NKF`T4~RwqwPsXCG=02dGVb1CEUL6dw9g26Q4y_cW5%1W>G;XDn!eq^( zT@hYRCk^d0jJZWmYTG);3+=7+_&&6cr5m=v-J027Zx@Vs1Df{OSD9ylZAt9w0grtJ zX9i+_#<1UNK%RVp&!v;E5T_9dtb-D3kU;BDB*46aP6G0G*v#73sc(0j2=FSsutHQ=OY55ZvoqF$H0*LYz0m%|4n@Nq~ZZO_kPd9juyDps*%b88r zFT!=k(&HrEnv!lc(Gr`~tK4Qfx($4#Bd=(~j83jhnST{$p*(3g4fQcO-Rg3-#p1i( zpQWp!Wdz$|n_GIkPFHON=0pJ;a%CZlDYD6@AosB3fZ}zc3vFj%n||uKB>Us8GvZI& zwnVdJD|-i1l|1{9!UhTuCfU2ia-I{P!eRQH_%C3aYEc0@9g(!GH4{3#Plu=3A<4Z? zWuWc72WYDGFD9aozTS}IlDX>Os>i88-v59NeSt$ibOGcR$3OrGCoMN-0rqxX52L#< zirBT&_@}6RqOz4y?>hMOc1_cIC)^5m7gGcJp%o6U+xl4anyu-DZPlrB{m@?XS_V+z zLQ7>Xck(fv*shX37@8*T&G`${=(^o$ZMS`hZ&i1*nQY_#;`vZs)VI;`5dgK~+T$}j zvz?H+?@-`2Y)R!cpV@ ziKTbuAcBferM97{zk(_m?EIUp6iEPz6P4Jv}g4QqlEgW~xs#sp|v5txaNfE5qv zi@F_0ULyxgwym$`dv%BOCgU9zlBjVkT?>vW2W@+VhwI`Olt{E-0#*47FRPw_?u?;O z!f{0WF*3(3jW|@fQkqC!qd#6ykw`S%?n1xz33Wi#iEE)can18D>shHfG14;>`gLDJ zWw6?lM(`cjvg5d#X3hv{{M{26y@!MORW6!@qeSn!7P?e2s}-vig}$@bKCzwk={~-* zT^T<|U0**Yq2MSDz}|ZQkA8jqcmDDAr^(BH)b;hFU44D?FYdkaHT%DL^K*~NzJ9!` zub+C;r(gZ1y&t({!%^AS_c-;!)9WQ4e)q?&_~PC7Szw@_29EqbL*J7W8?Z5xi*r~2 zmTK?5;QA<@hNF9*q16Ix`R&)20@%$K+8O|`qkAW-PdtI#o8=2=*qR9lokOOC`KW3x zb1q9l2FU23vPW1?;=hV8= zbAG2UJ!gG!1*=u*ITHn9kB;=5c`H0$q~{DOJRc|xH;2%O>Rs9bp$D}~WYx?{W44$1 zQ*AvUxjR&T<|7g_Sv~uW{r>LK`I%-_9R-QRPvvKBPL`_~;Ojjs1WRC;{LHJrFG3hQ zb_wCB{7i%hv;Po9teyayjPI^bB9C)}SP43{L#kEM+Fr$eGkm{N#)J2uXm5mc9Y>x5$3L2p_<1w;J;>rdp z{PrSr*{HBG^K z8g7q3?6}W(x7JDxx$l>{4eO{npCWvKNLMq(T`YZRw;VrFQK6bMd@1-hCEmf=@uRW z+6K=-K-=y`uY~6U210JcQ2;{(2+5{-C-Fv48CXC5W9!P4M0+ZV=|*hAz%v-n{`h>T}+u7ieEw@`-Fg# zHY{W&RnN1i6V4Y+KJlxlwaX}tPq3!Q+uF6oY$5wHZDf0+GdHqnrJ~vVXVccgK~jUJ zwwoF6LRhXnZ9#U(_Qq*09@HE|62~KTKpK*IZLu+ytPnGA-6Srgq!ZfrKAdGsQ~&HC z*=`frt{?07>4g#BTblZSO+kQG)a@2jd+T;zWN`A4JbtRAF7U(No+(U8fqCT7e0={^ zce@Eq$#E%$6}tTD@T$LtU&g9P4=hI>N>lrC&{wGYLa0Q93+NUl=f&%NL2~ipp-WTe z9U8JUHNa81;tw3EF9s5XvH^vv+ZL--d5zz)lIT|sv99x4qq(Vm+UqVA$u6aV_D%wD zK$%t7qCKs;<}5W5;t#8?bMjl8O}U+X0cU(;z^2^S1ZfKMaVya;bCDo)g{|+{^}!Dw zyz=|Me9NGf=vHTsCJ$?Y@9Q*C;w`q0{W|l#uqn5?vNoG?dl+WVMs3mDG|N(f^<~$p zt2AKi)XFp9f~=5CPpw3}Bkd=9R&ckfWUmi0?;V0fK5Zm2dF+zN^?f9Ac|jt#e(#%K z{q%J=UiQC9uPT@DLt%T0LMn})CQ(erQ9I_J7yV8FSj}IzE%ByjRM?leTC0zYj*T~( z6O&V|>6vx2>yO(ocl-$(PyC&yJw0uAp3%tAIhvhD7W30?WC=fMBdhZB^hQ?W=V^_s z&d={OvJrkxv=?|OZf?|JY%iYR4)yZ!?obWPxkELw!5ylhq>JZh2s}t@}uQlDFUTe5Ry*6$mG9dU2x?tP6-9VDN<#jG){oe zpoV4XE3-e{p2a(|+r$Fo+-lrcO{(Pi=ao$g;}Ujjx`io$wyBL{$6mAexM>#Hk;+Fk zj@GeYS=|ckjAVO$W7@-%02a8*l#NEpK?!Js-GZ(7MqsjLDdzU3N>#HRkqM z0I_z@E`eC7wj~flLm&c!-9Wsm#bfncdF}x)OEWxxjk*oMj?Tf47x7=Ib?URa)_|X}DQ8yUu{0n2H4xf0V{;JaGd2hDNDqj6W^4(>jurGy+EkOa)ir6;Fljfr zNt+t|6_a+}Pui5WR7!s&d-czHCv9G*Yh>$Z?s)KuuU~%QwI3VAQC^eNxw*-DIEr^cvU~`B@oM0h>Wiyp7eQe~ znzjmdal?@kM!O#FC7rx{-N@Fi@^w9wU0Tq4q-4>WOuHUgv<&4u@<^F-4*IjhqnzO+ z&Dv2;;bJaR&MhNPQl@y|KYA(qy}=e5+1g#8zK675f8?3s+US6$Tsnz@K7(E$HPA~G z6K*Jp{)UQ#LB@C)aRcOXMZUpYub7vwk=rSXn3F4Oqzrbk?u9qt#~zxP+3sgljN zIlj}M9UeZ0t51+K)qZrCr(@;HWw$tfw0oh+D$tS3xEvk1YI%6tJLu@oX!Yo*Y)-EK zg~P?+LEpBYTUNo>x;e}IT1)7U7L(yuNw-K_Gt2zFeIg^@f_r3Z_ZHkeBI6B*6d8wU znQK;C=z^dUbC_kCYpL&dD@KQ7O50pq)|583xN5aHC^wB`ck12n@2i=5!!f=iJ@uZl zL(E~9^XTEt|L*CwoCSMvmmRWuRd$G}Fw0KUTx716Sc)j9axeNIke-@Tc2j~Bq)Q)Rb7VcZ;ElqnldAvPSY*<5TKu@KYROuv#t zu!sw8HJtW!TW^#Y>8oe*c@#cfkMlNRR(*Ws+pLU}UZmuB9ng^1mI! z3i+yBFvFD{&7r?$QU`OW1pRl8C#pZ1*B-_D8My=qmq2-^(qqW6{+j)Emd>%hO%G_H z^r3UCKNE6kl-o|8$02j9X|0rFo#%)YIo4WWZfPP!^JUoB0)NZMa5>gv8S#=TmmgE_ zq&1A?Io4x@Q(QLGSe_xSgN%0c8ep zQ}$Nqmcllp-15D7{i_ero6)qPQFVQue4AGIyd_^LxwX3obAIc!R^9_6u-+apB*EkD zhw6brL5r_U0qFF1r-g1Dx-%R!OeppCg+J!H+th=P9I6LL z02<~)>+Q>W*O!|Q)t5DchGi4<_P|5q-b3|(DLaedV`~8BAa%{*)_^qt=4Y@JcV?@R zQtL;W`jCybF#EaIP_Px{eOL24RO+|b3eo2|eo#iWbc3^2>NhQ8!R>>_S$v&7m-o%= zwUxt6VAI?Wkp#|kWvasneD>F)Bl&K0`MxdvJ8C{CP-Rp7-0^hQ`2m?Nw#bjbOU@l% zNXKDSXYeif(dq7N3ug;THQ!%ZY~>ts!Ewk_+$xmQ!YUNrDFtZtsv_B0rFFMst(%j% zwk9ual|r}bjKApDrgX+F{$rV)%2eAEGXJXCZg;4R(}#m0R^58{o3Fp(je8%vXZuna z-?nF=?a-*EpHrp*^=q}TqMGe1Ms#U0 zq7Ux&re$^O1ONP^J$t_O-iNR6TjsE7F)en~?A?%2;$n%xd6o|;DPdL+SJ1jZ&V1Z# zkBc%!i#?H9-#QdG)_D}N|CoJOsmqMTP6 zSJk2@WKHa^Z0p4C;Ub^k-kGdcNX};^TdY%Ho9YNMP+wX06L-~ujYC=3CPO+=&$P)U z=OHbrYT1!$C^4VsqRk1Af9LEi9+cL&j zb#B%9gS(gSJZbi!^G6z%dxz)_i?biE?%ej8WuZf7#55c!rj^F8hLT%XUnse?KKr!& z&KFvJuiUy^4~T;wy>jcDAziteec2sKZoMyL=T*1f`s?q0>a+jx*e77f74ATWM%%{w zY|C)ted8vjjtaR|8qrTyHli-ERgBHNchONIwsIc{%0)4{+)q;NNii=YtV?Y5ZUz06 z*lN5lF=IZ@?PJM8)8YL`|M)cZ*uBt>eN+RohltOpZzBxQeXn}?k7c7 zVScK~LR)RQy@zL=(#ldGw`O`1kI|AP9@%nNdo6q0>%@S@T6>(%Dn9_eD@nOZ$3(`c z%xJe&F*$bnFd<7COF1il|FDb-%Gnn?A^UNmZK!z@*u_rBT}H*6lauHMDo12q0kbfu zVeT9WD0*FmsJu}TJfw}URHISbC=|uUhRT|FG!l)T(%V4B6+((yH+fYm%3^92Ws!i& zl6h)#N7}`O%YVkony4Mo&?rqLyou6Z&(3E<0u~&SGTM%kExOB&4g#uz#qo|bSw!u( zE83A_+%4{Mi}D+KddNp<);>5!aw;X2YACPT41=}(B>h?jZlXIo?9<@Wf4WwDx+X+2 zcD-YJGWbGEuUeFK$@2^+M)l}uB@{)PzE?RnyOg2Mx?E05wjl9fqQ3 z&}%7Y%~9)vpF)Q@fn`_*IIFo{b1fK5I)JUAAyamp|0Ua9xfAeL-f2|Q)wCnsMW^zM zv?>S@?#wUd=d7xUnGX3m#V}QwGe2j#s4i!Ij`<+n%AKpw38W+YUl(n_s)c2v)`3PS z(kge2odv*Y>wijBV7!|{4X(;hW!%Ct}O;UUM#9KD$L|*T`G->OJllJj7&qCV}NcP$I}wqDlos?mbg%C zExXGuxE*or!tHip%nS)#5OkCrpKPvBhDY5tSZIe^1IQN)ARv7e-2@(wPdAN1&@h2y z4o>ta8;O$w4xafn#u@;sYYvjkS_4bUi=Wy1nYTeLCvwGFky9rJQR|li4l4_Xi0 zY58escFf0nufJzkWm>thm5OmbZZ(&fwzceFt`x&#Ub$>7k*iH0O=Taq-_nNdy|qLx z*8^+p=Y|y?+RwdwEfD~!%>8@SJ2BR^tR?dIK}e5kTO|oDnzza(&dZGpNglbX^Kw@+ z)J^r}YlrHK2|Xl(nv<-zW(W8Ytz{F-$EF|g7gbZqMgwo|jjw#$=xyRyr@MoP!nIo& z>m00bhoNiOtd#E15Jh+YeyF}YS?KN^_1u4*1lsF02R`@)DdDZ`)AoCaBFLA&-t)Y| z4v@N%>&pYp0XV;61t=+UU7?3bNA~7GzG%AFKe{;?HRpBLQfeAVktybNwX#aRuIsNT zFV*VaWp}wlxd8GFkE>g|H#{zzlvFF3a{LnC6iieqsmpum@m>487mJzjklefKRHf|O ztvcUsrN_5xE9BIFI#qJ*&U8%gZ!-^ z`{z`~QZ@-XGZCaj6)dZo+b3de&PhMJ_oLF!tXEW`bH(YbRBoKT!S@aO=GG8UihH)q zmUDX!lm8Ugi3L8z+XK3k2guCHpbo%Xly8MPAs)jk>W(YZMo2@$k<+gnulLs&$T);% z%1rEXqhr16`IAgg90D@S-snbv4M-=QwJ*~!9Eo2^z$K}*=N4>6=)TGPsfl8i2Di7U z5muhPHvpBAHo8X_RF>FjLR}!x;?MygFt3O9+e}haYzIKWN(BnI#OFScMth(bm|Z<&yUqjSBkL ziFyTF#_wVln)r?ZgRQIeWGGb%eT{}vCxb)BZyQ3~eZ$1u?6EKI9x24#&kE^qMd9)O z+l#M$``13Z>u2A#IxRiojywbD??6e3pWt=N{(soImSelQe&QDwP9mgWwwiW^&xep66co0 zDYNb6w#n%AN`GT4Hx&+%>T-zzW&pMHg$yO+j_#1*--VUgGd)FWUFK zEZIR0LT#UR1yn08u45XTD<`b*_`r&3m}tlJh=!oaTM9+`Rww$TA7g#<|3tC+iif zQ0~&8$(B+gaExqKesUA$k1~FxQ{UxL^@s9emvf+-JnV9c^%^Gnk~z>fy%n8A%7SvB zp^d-47%mscsV*+iD-AWx zA;h4E>|a+-wND7YdWbH%gm43flFFo7vACeu+Cfi?jXYRYe(%h6te+R9RU0bQe}W zBZQTCspK2fyB6>%t%;hqu(CR+I8g3#(4)HOy^Xzr<MX>+%$N z%oQZmgF-lF*C=Nl3R|m1VJSV}r^P5&j=~~6z{N`jdoq_m;b_m``WLnx9tul?d+lo0 z2NZ)dNZwjc)WFOM(HROhEOctJ4*?53y9u=#mXBx zki~vBSk2^{uYC2MK0v$z9*#QR@ia_u*cHjvNs&%_}$j?(CcL*kKA8V_$G4x@0ChS;TWyv!>c=kzNar9u8< zfx=a2#?ywu`S_)UzHv^_Hwr;1ePf`YT%Eq551?TniKTDo1Du@`^bJHz5X9LJO*A`H ztVG{H%lN;YzHv@T-*}*;Zye0^jUP-$b0N6MehP622Vkg0*?Ly+nPZH6#`8K!@cAc_ zh6zsn4okcIUck}}y0R#((pRh`LmomMiS@*#(p$_+&2l=_3we)FFDltzYYku}+hI%S zw6jt8FR`O^oXr4PMA$^btF)Q;?Fn`ocRstcNl%pj$B-M@`HP)Nf8Lp(`*x{4h2Up@ zKANZ6CGS_-O*NcOrA>{cL34P%np)A5jf=740 zGHviQ-C&Qv>6Fq(*8WU7*`A8GU=&Zc*QGPOJJn&OPvlyfN!RHc(|n_%HWoWmp|i7R zw%4b#d}qB|-DiX2dp3qNdI3#vwyiUfv92;<1T*ObSW#+goPT{1;ZqC6hCNjIs>$ zhA}@VjJ6(9_zGsg2Mfb)+-J>9}=Z zMyIV8^T3RCfwv~IL`dMyC=c4bX$QMmVKPg!C~*?-CGBY*=eeeyvv&l)Y3sWv0x-H4 zo8XCVty5ZZfQ0ZcLxb+s20#(ec^9gfZU|C>NII^}*+gVX!mg+_V{i^1#b6<6F!8A2 zCSYP5u(&G$Tdd6-Z6^YA6b&p{eAx(CqERvmO((93i$h6v-05^1quYm(?S7i&a7I|lOmkP;)^CCd%UX0*>y92d^&rnF@=_Uh;1^}=$V>{3h^_AyW4BG z=s^n00N@F1q&>@TI;+7Q_adek$1j?oJ`b0Y9i0sfS)G`(Q0-zz%^jy3$J>ocXY$O6 z8Xbf*;c}_5BzkP`tcTD#@I7G3k#uoJFp*Af>rAKXq0e-^$d5IccE8hXU8D8DopnIV z%#!t41k>fF{Xp%D?Fp!Bf^NUcO)P-f)Ugrs6cp7sv(wlpj5Q(a#zx47NzDfu8#}-` zqAlo2V_3&jVrH-7Bxzfey2hiS3p|l`;XkPho(*>yO`a-de%lbKfAo^$|QjNkX;E=3<~g9!Zg%dH+8+GmT$K!`+dvRVvCosyF4Vq z0Njf2$T+ITBbi!WSSy+5Eqla%f3JuTERk+?pPo~o;E1GKUGxrGA0pjqkDep#={+vP zDNB92)%*SRclqlf-Rcu|eYUl?=lR?0db9P8p6BoK*RSY#{(xPdYF*m%{EzK=tMxW_ z9Xw$CJ?1aI+g%ioeln$DT^ki?Iq2b$clT*+j9aK>2Kd2xeLirM_FA-ssNLExS zMUl<@rRtAJ)XN5vaEgOXgWM4o_PkSAkW&C|=&YWMA{DJq86k^HL&*Ht4$SOqt@TZ+ z5s(WqRM$E}3;oIEjuB!ycZu2ns9bqHNMx8VxxuGZCXHUA(`=*5&T(69N8ULMLTHeY1+r&Lxg=2Jq%-?}L?YpD&&lAy|+TcT(`n>f4QwVJvc`p$>^ zckCr)rp)(!jp3jl6Y#|(v@bIpbxRZ#l2FsAaamMk->{S?fGAEGn7a3Y(7ggW%E53Q zHJC8%1QVCgLWRL_bjvWkj=Eq3(7HNzcQwk_j+8nVx&jbG?#@Z1+7E@6noth-ONaqW zVYL0o0Ay@z7sgbKZYZ1#`Vd%ITg3N&1auq<8W+9G$W}y3+QR@?WKUbNi)#;#r!V;} za0F4E!`iLegZk8RLA+H~G5CCFj&IDz^LZ$kU|I^rUVN#;GKX|W2`2jr z$9nhH!sTT3 zM{YU!^-Lwpv7gHmjgujA?B~usM3%YQw=DC|1>)h;hnHi&Y_9E^ZGM7yFw;G->9(1h9v{IZg4kx0bw(`EW_Rfqo0|F<|9#}W2u zHT!=T+bG2Ck*sc3EDyQU8pcJohnIT7jiU;Su;0)h@k#wEp^K`b)&r9H6kzI%+s*L| z|0G*yINPPMEggS8u6kEwbWtS}HM%joK%}A5{6iNlprCqtQcdDz5OhNiqa0{xP*4aBPML3lj>@ZR zk56n(FH9$Qw-w5(&&OwXszylFX2WdHgd(tbo9lpf3{SDP=fU)NKDc(}UDNSDh%Sm8 z8L9;Xe$!EBpuxydr;6G}?S`z`8iZH#L7FJbDKrv=%GMQy%8G|V?X;2YA4r{}OHrqg zDC%@ng7fLc6JrK=Nw;kp00m+TxCH7nD(Z|o>f|R-CqXVKA`)g@+-Te=vW^%9vYi<_ zQwX4-&#IdjezxL5mqUzhDCP#0SY)sX!S9I{ao6jwu;ky@%#61HdryqIPakor(d<# zz$NN6&}G+7#Ykacz?7M1Fjf3ats7Kan8tw0yq10qi{gHEK4}AOUZvwW8neswwD9Ev zuhOahh6!f4vUbObJbM%p2<^UO1(=0gbhEBI-8lE{w1h6PbD}rEMiFLkK7dD%|q^#7aG|?{5U;|70cNr z4p6Kf5*tLZ(%f)8XprP7(bcq@BO;6mE-`H&Ahe}wb`6BGu*kGpAfC&uQ_fwa-wV30 zhTH@50Nht3hjqJafPNJCtIBwO4bW2^uKOBD7zGnu&%u3Fu9DElRO;-C-#1&K%I|x+9vi)>5>#t~-Fq-I)i>U3ciFyCWzE(5BVR$u-fb$;%l+ zQh;1(BJ%+@N_EMBtb~{xx?`N=U{yXu37$!SCv=dGlR_fIHz7a(NUV#@6{F8FCEF1C z5~9_C_NZjIQAv0>^7IKdsEe<(tjIktf^p%irXwhB(6V&moUxamMF1FaajjOMD+Im# zMIN%Qi-LvP5>%8c&$$DP-3Jc=Hg*oi0(k5k+y)5QIYbwL#5o#>#n(z|u;&^)XG^r` zgSMs_fxM*NK2&X*z9m()<0KBdF7}SN1kKJU994t~So%lo$N_?EK`2s&jieyM8J(~5 z=Mdkl&e!{MNbWeDZ}8_3+MLdh_vet;37Xl>@X-#g8ly6Xyip*vEa{B`=J85Q*eDjd z!5sm>_3jAJt#d~JV_HXv%}76|SXDyDPvo0!c6EM-K6IwtwBjbCc$&Y-;nQ_^MKZ6VQqb~@QUDIIA;&Lq!b<;ccie+^~SVp2X>4aT`=({ZqISbkXu3Kj5#={p-I z!Nv(g(t1>Nrkvb~VdM&aP%S$=OwllM=hC1$H&+Y%6t!NmkpIj>@(& z_W%35f?j{JBu8%AI4=sb)}4I*vhuG~~HishZ7Zdf}}`-&Gee4iL<+jr8P2J22(e$taPASzpkCz^VHp zPB``-K?uxK)2zX?%d6u6>x;k6`ug2eq^#a-N=5PNVJFqZ&{3Ld{^;mwsiv8ZPE0i$ zb>v82gfB7B+=yH^F(CQh`F$zeCS}VoBXYHPCN zOaP2Zlaclz$xNs1mj||W^pRkL8R>}h%G^-Wz(1hC9CHJSW-X9<>3UHWk-*)=9ibhL z#1|ncj>Hk6G>*gzAwZ7cg8G@ynV;kbcXL{m{BV3vlEd*m$qdK$BrP1@lbi^AZ(i(g zL}&wGG1fB@B_srd|XPXz0bjk)>V_3HP53aCsY1>1+@KRj@(ukSR;rfSCPU z-@_6iA+>_&Mbn2^#++o5IHxm_fJRfYL~O?yR3NiNu)4XAB@%D*8{VWNi`k>R6wzYj z%}VJEGAoS;eL+5FR_cx{k@6j9iRg|jkY1DYm%PaGiAoQ=q5}h(F@dU>O1Y! zQoYTA!Q|NtPqyor=w>wi{l#vg0fL4obOE*EiN@x0jUGWXV`jcS+YwEzL^Mu)5VsQ1 zNT$_1(FmuWXwV1MZq555bjK4-e#a4w?s%dJcN|eW4j8U6`>?U3<8~3vc>23MtuHmw zO~MMCZ6fXXqp39YN1M~9`J>-UPxME|0Z-E#b((h4I+(s#Qq@rR8L}D5UR}cU-CHX) zh0!;Z>5Hrz%JfCB%OT^nRquv@Lt6T@S+-7F74r&IYeulhUL zT2n)J>MX9tRUkPc?<8wV_(mhUTv5I3+1VvZ&I}F<=!_4+%XzuZySyi1hBVa7l-o%> zfp1|j)iqnJz&*R5A*gsI&PKLdhnXBPxA`(-*c0*f5j{O(b89Rc!8ODqc2D=0`p0`Q zGpQ4M2b?9j(<_$*2=*~YG~p1Va(M(xe_4n>q;(fdK)limaTL=W;t=&g`m_>=KU7@} z#GPWaQiva{E)DU6Kz-?dhYRt~C}Fik;}Am+mFF-w3U{7i=u;VUkQ{_!CICcA7mQTx z1^li?lICDap@V`X>qe3#0M(7=0{S3H=_Df}Nl_{ECK|-_FaX#>t*MNB$M)w$-6iZWFwZyDy^)#bVOWJ|aCNQBT9orDFN#Eh8F z0E*zNTcF8Z@S|re6dSu}O0TakR8uS}w@Tu0dwq>CtiMf01>(pec z7L^yv4R?1qqMDrRFzctDzz(a3+!7sLvxJ@_k)Kr(N_;qHM2TY)y&n8zPeo1%r%?#r{#H^ z%T~)hZKx#9)eru(zmn36pwdr*zh)Eh$6e?YVa4UIqGCnXDhnn5X&LjiLtwu4IAOlF z9OfTeyTOyZscNy7z^jCfc4W$muM%zP)uBwba#{|N!i$9lrYMuWdh9RD_P&84RgLsF)jnTH$^zeOp>s8c#fpT5LXibS~_HGVDZ?`$w0h7K`B&6#WF zrR9RLRd$6)?!AO^wLn*Q`6iJeDNG||D9MMKj>!+DG^w`IJn*TI0fmo|7k8$LE)so+ z{|j!7`2XBU0F8nbys^l}@jeDP_3i7HUlNd{4ITh1hhrzW2rQtL zsN<~hPUAnpc;ttY=zkL9X3@kt(OyietzSz;IYH0@dYuM}J)WD=?7@LC>MVsZWe}I=byqgR=jvEl^hX)} zYEIS6-Lh(w+=?*Q>j6-_KRj7+B`sKQH{eN67nPGMbCb17lq9h{EZXZ0!q>qjXX{6D zcw=bQR7T|-?58Ys3&c|AeYGvyOC5u}DCp7CvDDlK*zA@iM0@f#hi(<(?)A`fiSzxSu2B~aS)g6NY=Y_u1~ZrM#TR-QlU{0 zs+cX`3nbZAn;4Wm-#e_qXiwS-rqsL8pu{n*0@x*M0F)5s_l*~F`uamhwD7nazC1bK z_hbX6_4=e(KzBW9Ej1@e;dF2eWs2P;<2;L72PI&+Otj%__zV;EC1RCgiK@6*%MRf6 z(_0iJ43Rc%w9Vz#&%Keu#@T*3W!>xM`h~r!Dyl zU81dgU204T3%uZ?Pxv%&Xo;`jsZtZ|m@YicJ`ryu-66+l;&2V^W@AM`+MKz+xPkv5(PIiw0@_%(8$!@Z< z``;_C!3s8kDw1JCConoO`%YJ!?0pJlMG9# zhztwS<%fmyknxzr;s?&{lcb1h$@q~Pgu2koV)Tf>YnLb@u5aO)zET`Xo<>H zfQd#_c86}yW%p^r#Xv7=%!9aTMC`L?>5h&RDxT`#HZNrSJ2u zvo@fAv}Z(BJzdnwTD&~b_N?-Jx5_rG+h&#RZMAr8XFaGacTzO8>Skg=00T9Z0ZCtl zrb3Y0rYFD~sHp%b9Dyh-mXLPJxi0Ojq^pq2tcg16bQJ|j%DT!a(p4<_i%XH{O#FQP zVG-D{YKr$-IyI##V)P~ZAU9J`Z0>7iB0NT%!2DAR^D6XK$^f!UL@$ye-M}uTx|Am! z*rie`5Y%Fq#OYvMA>~ZX(}9FP;gU-|VnbCr!R^+grV>GEqtC6(iQ!b#p;|hw^dHvN z3Q|lLF4L)Tpg%7c`BKT+AJen%46V77ucp`kGdMCQ~DW8C-p-? zB>jx1GyEtk_|8y<4o_}5VD`N#Y|N|P`%A@dHSeXcz&AOpDnS+&MlyQaSat-S{GtIR zY#OF*Wvr#@M7q$_i%1DxqX!o2nCAyb&$%BLv2j`m*vqP~aLF`ck@R>cYUjM`z+{4Q zr};P^x18*Tl{nSTA~sceX<-}$M1|LV7>9`a9#lW@iq9N2ff`i}K6AUbR0zkvR|?~x zZOK|f=1T>Ss1J}(C(BaXYOOm>Cepc6o=0{NzoTtqfb&wZVoT5cq4Bn7XOCP_4qUnM z=#6F@?F~0FQp~fEiXXIwX0SI$^2&zGyN5YokVc23cZLWO57d1OZr7Q`cyD5z*%aW9~Oms#nb{;T1B&B^Rr!-MN99Fb*nh)Ewz7g&|Vf5Dn zgdX}^0T}w|uVVDKw-m};DgEtDq_DxoOh?irjdaF}|Gmsf)%H=X7UN{nv^vHCL8-fh zk-e=$!unsD6(>FeGl>HRWR0?=*HLjN)rZEWuh2lN=A2gd@h0qANFrZQ+Ny3$Wg zjStsZoLWDBJg5r?P#0py-07}WZh!@X1;v}yD9IseNeeA>FxnZ>PqQ;BbAqFma@zEO z)<}(Xq?MuI>Pgvov9vL%Wb&#t%vg}pA!65+rn`bRrW_gbytylAV{#zr%A~u3HiqtJ zSElSr$_AR09(8vY%-!Z6<%DcvGL-UrBowonAwMOjm_nraDNXw(X>B2$+=r5e)^a-O zX=9qTi>*h*l-sBd8t8ggg7i2&^AeKQ_<3P_&Vh#66>9?iuibsbMV z#`X!ioUU(A1Fvb|fMTen6DXRB>dH%`7S?k~=5)kU!V9mIG@$X6t=(tQ43CqFHlEIk z?~SV#APb$+8R@}Nc+=zE5%AsMj)3c&juHuZmKy5&7!*pIMZdF>TO>i~2`X=iS5oUq zW3WDrv@0CaRhyR6ZdzL6DW-eh+(IEw`LIQXqm1!Nz3p)!h1;hs|It`6PgeSmg1+1|$ETnPz zs%w)RnP9*|8b7&`Vjl6L$^!FKW!mvG3K($FYhyR8yXV9U{II(5BzHEipL9~>^PKn; zs8s3htsiTC(&?tCi?rMARz~#@sqD9e7Fbi| zPHI|StD2_FL`%UBmstrS_rDC&{5?43Bw%y6m&cRE3nQLM2-otGnXXflYkHI1HkDPE zXu7ob%o4Vg}p<3ls9uy=jZ?(fkyT zBC{vl${c?e8Ls8Pkyr)2)8s=njFr^xvaYq%gD%i&hk5y8R&SEozj$&5K&G?$weX+b z$JGQ5XVV5M4{eM#wTHb-krP>ML<_ZSmk`}m@OV$x6#|iXT(q=gMnT9~`;^oSiQ}iU8(eRADaa=EJ70GrNM_W>ql8tNu} z1R&_wenxopq!%PmoIoNF$i`J{fHT%PVG;dRM_K25i(^m>#8BT%N|QjXqWLUJz^TR4 z`W$Px^uwGsEvEGo8=H5Y<4JbGUANd*HC5OGfWF#{o<$T!Cs$JK*}&%}EIZQbp7Tr( z4qJRv69mB(LA@0Fc0nrD91%H6>)6&|eT#8e#<%6W3O~(>IJ(_kFz4E!V=qQ38VhAtbWqu$E?e>7~zj#umlKsQZ z7fy`m3&dmTn4wnpI%C|0>2Mo9X^}U@fb71ckJ%8A8gkG!4`KGOwr)HfJGl~Nf4W`S zCAIA7+m%w|UZ<^ZSOppF6jR@U+dnin9@^r-Hhe*OM!aDUFk-bet}-@b_LA0a;0~nL zjclDp)+{#!nK8TQl$uVP{%s0}>Rle5*^%wqb+EGi6={vnt7ml$Od323eWmXpk$2sK z08cUk()Oucs(wcRM8vgAdyZrfls#8Hb7Q+M*+__&WpWaTC@$zL;@LbuVPVl-yY@d; zdCk_!f0ToGO((#bBCj^Fw>SrnDVuf~!plWHu8H)SmZr;!p%#J3~<@IklC+b+Tg{|z0XI~=%r9Cmd+ zT%Ct^c#C30h<49n_69qZ3hm)4hH+T4CijGY7C(j6?67vhw`&0nAS`yXnQ{ggX5K)r zbXwV_r}H3=R`*RKGSQdMh0qQAEH}(^=x9ur1K7=dSX{Ob^R)R8?XqAn$1azeWTF`N zIU<;o84Jgt7WG6V_wo`g0{F8;c(DjiAvH~34qj5CI+P>c9ER$qN}*CT@NFnHYWQb5B8*YE6N zd~{s9H-^+Jo6Rx9Y5i2ta5SU-&52bkHJA0kiR~ooSGuGjf)^urIJb$Etrx(NNfp=u z>KXpa85AX1`J0xLz&z{WPUwoh(sF6H98u&N5eP{6E*`{Wi_z;&#Fx`%4}xckfcZQz zUU<3k#7vDq!I8{R3W_s9m?O`L|C%1y{K`M64-&}H5I91Y0aPdfuwEWSLUC~iGTQvz zqLP=F(8lMx&~|5$0S1_Iw0&+QNsvlinGcDx&K&H^eQZbsbPwmg)f5?&<)R9y5$i(gpiIodVXaAKFYrz$vB8`t^XjqAq^V4y}ve zZ5u&3A=73{VSpIHp`ECkQi$lB95|>&9Gh+7KvF+7kr{2@Z~>Btrfl;Q8?oAP+lY~& z2z8j`$K8oCpm+E`mt53`rnneBrFPv6E;a5tDysVv>vE#*nNi|krqXNXay-IRB$5A_8}2pV5TEd%;l;**Mq_E^?^jdv+$=Pa*@*m z5Feo%`ZUbhP1eSL6$yH}S#r~z(-x%*=}8nC+sQ}%f2G})uIKyxShYE@qUY6dhSvDb zNIXql-eQSDbr7=}zl9iNy zh;hK8rOmpEptE9Zw#((LKx#q8Sy7W!bW~9}x;G_3T;{v(I8Bt@U*^6lA%kKJ9h|u6 z9Z<~M=T=(cj9oVm+Dt&;>n8k&^fitojS!s7G_e@6m;JTP@rkE$4Y-qHpb>Rk-YiS$ zaMj2tW0kM>l&FFB6hNK@6jtt~UkJ}qphE34OQ=L(UX7~4t+VXzDX|J=&7CT=xjE|!M?j@3RnTz;=OkS7u9fD_Wi7#0{)+#kiYBxN^)zV^hoAHYP`m zm)Rt%d#?|cymS?m1ot9fInK@8O}?~`Z5`ofC(<*xi!_-9TZ~;8QtoH17b0H-KFIqc z78|aAx*1Ij*4G#;{1Zmk`nu5+)ZcXK`^goifjJIhS5<>~F)dZA!i3L$ZrL8>L-4}O zZDod8Fd{BL^9eXcOewjARGh*^`|Aogf(tpm%@;eysN`TV?WyAfd1iS~4F$ZAIKjkK zSXfbAnWo;v4E}4=0Z4%{|8;h0B(W+bJKJsLF$6iP8f=bVb!u{{E(3Y>p9fpNbR)Kx z&|7Vobf;rAO2D)|B`SA!6yfv|!QC;Vih?6d+q}%8KA}r=BGhEm=aV!1=S{e1EtS5S zR$Bk=`*5)<<}oRFUKDwNx(XkU6F~9nIY*=TTsAKt8Xemy6luD<`7>nC1fQNxxtUc|q$uHnvo-|5eLC^-kB*`d(UM<<$s% zqu>|94L4n!-CzUK*WA)8W0K`eJ2B=Q2sHzOW|$KqewO0%C2a+Tpgn41kkk_!a5bN# zIPg_oRR9Tv0a!8T1uH-%Sjkn=J!Z0G2EfYN(>8Zc0IcXf#gIZb-6||F+6OPi2^89~ z=X-}Wm;@p@xKpiQETKd`iU?{r#4@Zh_WU}mfT@0BiL+aBRC{kQo(p%WcgBG5+_+4W z#wQb!<5Yy$>xhK$N(QBAORR=ccnrl&>#5Kk(7j}9Q33|U8jT|UcZ5{DUO|jO44FYd z@M_cNBsn1xAJ;@pJ5M$pZcF_qB|5}5tF3=C&M>CW5CGJV`Ndrz2@Qp{B&q5pVQe6) zM%ppLM2v?gy&+CGMz4*#w)wJdHJtt_Jrmxoyq!dXUW-#LV-91<=fAOoa@!C$C*2UQ zxf9i>g{BUeHsM#3pcb0iAmxJ2sAemj9?M?FV4bgquUo}3M(Ks9+r@FDAEPoqf;NyV zIe;oi{GXO~6x>zv&=`y=4wN=zg}XYm=5lzMm=Gg70c4P0>!*_TZHwBt_drh~2;ws@ z_S|9FRQH}c@=4>);Q9*~Cj@aG?16n2q<`WJ=~S`{2yV!cSl(QRCb^lR#O0go2>wfb z_*AujguW}LM_(L#Q_BY6yk~2mO5defG%4$^{#08J2zrhGQ7bkN-CIIL%z|ul0Z3y6 z2ToC`Y>um^CTF`*OZ1pp|^BJ z9CQuJGpB}s&W9XcMi01SeKl#!qpg2-(pZU}eoi`aGG5@8)G_`RbmP$1>IfWeWobwg z7K_MkcRHjhMX^f8#bqr`mdU(Cby$c-UO&oyA;HU4VgbDr>_k^7{fGxau#!NwRo*C= zEOh0nEiy~8@fRp6%;S(_-L=CBRic;*fLm@${QdxgMzpe-c2HHq`F?zXp<=i_aGPCl zaUHuLx3YAB{1uSR1&1(u;(%SSP^)^XcqUd@;=^UGS}SM9PguHXqrxl3v*MLN)QxPE zzV6LQmC{4mhZLpCo}Jxrm7-Ol_Wj;cXg~X$RhwJL?s|9mk^6O)rP=OsDgA#+l6sl_ zDX69vF6#too$Z2NQrCu?(*$#ZE zs%1tI?U=q{B;$fwq8R%mHi2kIEZVX#iPa+3#4Wqr0c7gZF*%>8&{y%r6Zmz-6Zp}3 zItb??`Ii0FF;6%o4T*3nwwDMyi-~Y#j6paQaDM~sae|$aGHURms(kQtd{+*2y32{} zm}0gcX`J?q$c0wpjZa`-UdwDcdOAZr>!YVL<403xs408&KxVS1Gk^O867cBaR`2&^LmZgh zZDRE%@8o6cg4uy6Ru*2NyoXs&lumDDlvc3c3Ab}>yu}irREaVBx!st~?z>uI;-Ad* z1H(c^k#;A)-aHHs|5PF|Y3#zKL34+6Dm?&K7Mqo<)sqdgpzG{0aX_YD^N17{Av%(Iz*{%y-z5B0GbQvoe zGX+HTjFvGgX)@s(X)KK_JSR1b;0Hb?T1MB$Qdy*-a67`ON$at?z{?C&K4!IH5(_1t zHV(;5iKZZt2gN<~#Dkh7BKQghos3c7YtghD0OWXzl^8xJGO^D#2yNidRKh61 zjx1_VqA}YYGQP20MTBVu|L*xp40Y$7DUpCKX`KiMT(;1KC~8IxlU6#T=tYy}aQV*& zr!)BFr)jM-c_x|F)9NAXIkeCNACrG(l1F#GG9_j*BgK8p+V0FQ68?zWEu-xg>%7+K z&CZMzGizsEx?W#s@r8<7D0TI?Gg%3C9ADWWDssao1~X$L(5#GfwvDmHXOfPl(&uEE zoF`&d@;RSomkV9^4c>*3?QP|7uS>K@1@EM7N>b$*hwXYPfOF}zevW6Q%9Paiuy4XN z3Swu2Zk>>BNXczsEem>xyEMlo46aIgoZDw(eR_h%(&k!pM|pMiB`>zSvm@7U3f0&VCIhfQew%I&GifZfgAN9MEhm)@y?t7afEcp^f$g zmfiWW@KO%q@>p69XzT1b@uL~YZ^pJh?_59E5}SF(VaGuFwe$h-}!1O7Awc zM;m0Icfw#qx|}qu^DWWwdbxmFhH=9eNr|``THpobnn7TfHBMVaHiz3&Sa-wYGc0Bj z8BS;pFokJ!AyuRF$Fj6WWUDz?DEMH`%5ZKjO9O>I!rW5#r^NMb;UC>{EwW;fZ-78{ zhfrSqv{ooO>N8rUg=Y%W7@O14C&z&7f?n=WfP*nu3xc)!r1sJo zr7`aiA7VilcdDH!@M6tqMGK69FFkK!M%lJ%<8PQ2YDG^%>YLJ9gOP^4VqDY9>71 z%wB5z4Q`@`6tU!!+U`l;0WCf4wWkF~xF5V}MC|W4qTboSNoPv&rfH7aWEeAo z>2!8mXI;7h+Dtcy_>|Wyrreo!LF^7oV41@_x*>}c6o-cOLwK4wEv`kkU#5j|Vw;_2 z+7wZ1DchNyb*$#`#5DzxLdStpp)H6{bnWj?GeOpA$q%GL4|sD#OJ}A;LGbu=J-QCm zv!0U?$H?nEI_3K~nKCZl$N!{0T5>ymW@Kn5{v3eN=k+?H-#|ru7Y#I1?F`mgcV?%x zu`}s=G@~ACxj}wTkF^#dKgTsH0Yt}NY;dNZ>NB&>PDjEtF)5W!ZG(yl3cP$lPmM4?zofX*D6h^bDLub2mM18@Q)fLD=p^*}TkI%?ghG zfA-!5Sk9`<_wIhXclW*}d4mx*gqeA}&6x?`=rMlBA&h#)yt};MalTULqo}F*PMxyq zo2r@G@k|X4MV+q>LXd#m)F_DDL~_=PSTEAKHW+-`j$CCn%FI=8#fb(Oa!fNww{w#m3GmUcx}M+ zG2rBgig;J!mrau2%2D9=#J@w-e2B}~UX{dZI|?h^Up67Zhvb?X!~)Y)VG7_27cKKd zQ!bE#{t*|BuNWW1Eg90BFD~IWOiuQRvLlVk$nRZloze7(bb+cdm&QmnsNogW9C8bS-O8x`EjWbN&t~cWkuzy6XWwpkE|NoxN%YbiBR#E`C5Q?P~VwuEc`Or-@Kh zY`#6(hNj)vyv$P9%BV%xyGg2gfU5gqFPeorAN4?gyGA;UEl75cc8ew$^%&aOlmoP3 z)S1|{h_KYA1?Zej3wWWLOKsYBfu&uc~$&urRIHf@NRy{l~6T@#xYb?`cDS|>W7023kJrq%JeT~nJ@ zI@8(YoP*U^Y>bAvJko5m?~GCyc_~G4ek_aJSa!9s$O?n|qXh+<);&u`JDb+PwCRK* zL}(ptS~nP*LJ3D0&Kb4}Au~Im`Hp`w9?*gzbmU8AVO~P|^dXXfjLqP&- z*?o5EY2Rc3=-GuruFT@yQ?pofBy5{mysPBEu9(Fbl07ktWwLcLix;$+#o@GOvD&~a zCi_WZ7DKl?Y!+*o-O`>ji#fEFn8mxvEZ!|=7Vjprc!AQdbTW%MP_7>mv-n*tX0a?` zEhWt?-kpbL*k%@E5$_u9F0*)dDf~9G7&34s=kD!haVWvZc>Wd6HCd~;O68Q2ZAm%b z6hyUeCX|sHPG6vqF!n!-8A_f<>PY_B^3PXr&!}*nvh=@W!=pj8&PJ7>=DqD4ip*HF zMH9{roZzAEPJPy>8m6{0gO}~hK%DKYGrl}Cd}lk`nP0P=rFJwpP-g@5I?f;j7?dBQ zbLv#$-hJ~!YH|(Yu9@1^Dq>!NDD1EVGf4EKEfVcyCnQ7Kd%s zJGtrIc8_`|Kzy1jk#^!ugt@%D!d=?Jtrgm4Dqh-RL9p576|=jyfln?9Ol zxdyfB#&=g%F+mE+^x0#h%#H*RXucjXS+*VL!elD&o?FvqJ1RT%byeMue`2PqTjuiC zp345Zy~M7q5jQrk zi#Vu}jUFzTcJ!4uY4kH*+%jjhzbw78$hd!KZIV^PO??aR6XG|kYm2&{{be)JJ~3ur z-_?9uW%F$X2iFtd)|LRfG22NsLWVF`D@zp=tk20Z+n@FLZUUi1wEVvxc4=ULFxW>H zH%Ijx@dc;kB(BIwYShRd5!F6}HNUt?yxSx;+2Up`JX@Cn(%KEQ#`^Z|GG`~OZNCnf zk0Y}dZm?R4za3eOgGQb5h3rLo=Z12#{KZJS1~lSc`y#)T_ucTt)t`~LoX7s`{KnX1 z$uck@C*imfAK?^xyqF}4N49U$mUTtV13jU>bew>9jsx$qGN}iwh6it61|B0KZcPB4 zV*uf~j(IHs2;E=+fu9CxxOtB+!}y~8n218KF$n_YNdVj^m@N6B*W)9Bpi0?ju8dfH zJ!kbaUB!QD=^ym!KkP5yR+aho1$|rNzuEa1w}N4Cq)5=8Bg+RJ)Fduo-!GW{iNiJ{ zf_VKhySSse$%hZS(}!^9XzcG$PJCDaQ#-jDSNKLY)3@5$guQ~twU72V=X1`Kmh0TI z_J_GGNG%6x%T?F1Ht}^HHf#A6-||ap`K9f*4CO?_YnvomQscvE<7L-)xvlYIwfDs7 zt|R%3j|@E6eBT^cSgrNQEH8C2zU*!6S$T=Wmz!1pvZM~XXBvhDN3@KL;Cwrq08}tF+IJ;0Y%GjLV%z z!0 z{P*A>k@`OpI8{BUiNN1?!$DTEPrd{pJ!0TkXWC|w`xZ}eC{J-6FCnskZfS|*d*nzX z7RU+RQYNNd9oKClu=U2j@&Nu2A?aFX+V7lDNepI4F#Qg6!ys$SB4y}@P;gCvLqe!2 z+)~;#+SHihni{DCt=*7bn&LQ$qFiW<8v1PnUt3gCYF0G}pmyXy zUpbR+Av?~9W#|4H zO4Gq82w*9LK)xdHe6TEWf(l8cmns=l1|VfXHAd7c$yW>gR+y=le$T909On>Q>p`;o zU~9d+1jMfrBBH7I+uxV8sK;m7=WZ^BSs}_x zHnpdSC!C*ZGCa*B8t;Z~vPcZ1mL}ND!XRF*S41a1R9SCAU!}Md{?g94C_kPKqX;@k zF8oH)95r?O-LlVX>X7TpD-kRH)q+bYQc(DcMybZ9YIF)Dtxn$iCWmY2%BgRnPr)~EI?m6p?tPQy7W82j!lh~&pc9JRMDksQ%RBu9KHC6aGl zdi4X}Jpag>9<{YGCp^~2usN`*~Ze~Lzj~JDVy>->iv2C*CJDDuGbK5hI9DeUbhoAOV zl_l{1*c{p=oixrPUj)W+Gcu(RX~S|)xsv40 z8D&j?Rmq~!QVktMEcWoe_`*jC9y8zULD9So2N8ucO0-NgN>FBiH*6Tc_9$MH5d{ZW z+7~?Igr4KKr53?h{J|y9Z4yLo@)KXizu3g|UCKo8x%*b(eC)VP~ob z8=82iyf?-!YUXyAsL7oavVEPym{^;{AFYA#6Bg_~G9{JE*3Pr*gw---?B7Ukf$y5N z%m!s{Mah}YeBvjywKtYdOr~z>7|8p6|7d2YBMaXps?0N7E9#&zx zfkt`W^p95->>K0f`V7&W1|LbVLG-+cBP$iQ3`Q)FMkYN-2@k@#57L!~%0=vOQ7P+Z z&<;BGrLpnPE_R2Pv?ge>3n6t|mZ?8XXBEZffLr?`?+r^)e0Wjt?^>5CM^>|DAq?zB z2-6jV(cmUb~ zLR$-t5DT_(y;cE!Ef^oEr}!`9%~qP60L?)?I(dkI7~Qu)`yd~J;|An|RLU3_BH8K2 z(q=AbZHDe%T9@k%Q{UD%viO}tiUP7yOP;cl*AbCY{E~m-t4r}f<@nDrb6ME>Sta|Q ztydMRhVxHhCHRI(!aUq~N6Vy}*Bpld>tJ^?gyA{J@J!owBGV{fJPN-E1&r^PqMI=G zFA^Td5BqLtE;7d1PctkszS9)@gfkxmqd{a`1BDwV zs(z8T#dnZ4Um$IW#E}$kP)#BZEeHa#VTvQW0VR5e8sEkKe0K3-7*6-9D)COmZfo6Q z^ZAkZ^bJCLI-g9$1y+*y02~FD5>^O|2wSLcSX0a@HbVw?v3y2CA`0oAJtT#NdphuobX0EvBU3iPe26T&{dZd64J>0TQ1Y*dxD`ap#W2I4yHJSeROW7&KjWYXb| zCg;lfa+s^l{Y$}gu(OY$_>f$sz-TZGMg3)plB`gjX3lYG(x&zsw3^xPJ1?}Rsxsg_3$ zVOSu|D#YZ~ z0MYD5N(#~kOGqlyGB+AiYgkJ3YDkvMqbbX+hEsQ*Gg0VT>YWe_yCTez9?-H~9TIPr zAjDO;{(PyAB(+ddx>3?1DYf|;3fHvE7w%%s7YS<#6PIh)oU|onLTAwOZ<`xjr_xZo z7(mPwMqsJQEn`s1r`aS1B^1zl=Ho_sX$F;~f%cRG%DcKHy}3Z9j%AR}5w(&zQlFe! zkd)WepsikTL7<*-o$82*=Ex+Z>)!m@{47Lrevm#){_&{Wco4HKjd5j|mID=cH=G#7 zF%sf=r3k%hxd(=bELh9*53NnoDvQ?|5S8(gB^_wbr@UP@s>KukrmHB$Mx>F**vQEv zkpqL6j*WES&)7&jq_h%v$URG$UCZ0ikh5@MRpv*L=w*+OguTRf9r!B8HDEfK5!Bv! zE!jLggvm7$ilBoQD@I05#7(dQ8WDw{yhw1R>=zYHhnR$2@<2OOcD;#mZOGb#(RKKd z4{1PUEhILNeAdu;%2kkvVSE~{0^>@tZiHrgF1+YfyYc3MVtNR)D%|=m)HQmwu+JO8 z>y8zLN%u`m$v170h>kYdM$A1j0!kf;_^_eMxGgg?;X?1phKvAmbgYzU)lU&x1$rc0 zV6iff?#e81V7DBICllgpCpBGO4E70%iIFKTBL^nG$x0&tN|7gK!?;X`h)&OrjOJ79 z?ZZnP*9H&}ZrYGD%oH_vlbZyYGMit5zjX3geK8j0{8q0Bjg>4l#@JDFP`HgViB2GL z;sAq?-z3TAsdgC6)BYQ~Dk6O%#FJ`-L?Da)FV21k*w!Oh+rzAz7AR^+go7CI`A-(W zltjN1>ScISOal97sWi!_VJ-{=W3UmV1Cf+=1F10(V(8L=D5Sx509yxwj5G)pj>H{~ z33S?21s6r=0zv0>*MhZRf$ntDSCR_}rO|7mM6TGqC4Ti61LWva{kM^*^3yOyE&Foq zC5H}GMT7`AvlS9j+&&oso+yyZq8t~JX3Yrb0Ep7%l%eCIN=q`5M|DqsnD;4>jf%*W zH5?*?)>0ya7DQwU$6+rW1kM+cq;sQ_6=OzJ%BV8Dl4Jp7c>@==`<~6s!i0K4JKD-y z_+VBx38@j0akfopp2v}MPm3fhfWCB^2FlyOxmiw8uuMGYiyYNqRYLz(L!;CA0lpo z9QoxL#9)^r2q($fm6A@akPX|A7|ec652TLeHroqpV(;oEtdioz4&lrpVoXwnM<@D*2xE%o^XK4b z!9h{L7cT^dM1xAvX|m7@K^mf!W@$=VwFdE%VoL&sx%f0m7nHqF0!C6)D{*WqWw$kX zWwNo(DjeO+4GPi(JP=Ue2BENo5zKDSrU`mntc2rd6JAO_3np~xK{)W-Wj;l^q)al; zLvGwq(G!Z#Lr!i8f4dIb>@6VgJ^{z{-9G9>}+ ztuvWLv_(8{G<@(E(PW}eQ3p3YB0iz~sJ@b}TTs#w?ex7;b*npy{ITm6R~F`Tgy|xy zYUV^?uuf=zAPCgBw5i1hq~~TQ6)R>b3QhJaMprZ>|1qPM)Z>Ymc@yBE5J}D)jwD(S zr@S0T%;BhHPZ{FjOJO0GSfbIWmp<|iwHdEOj_or~wxIBRUV{j{644Nq}C_ zX#S-cl0Pg+R;p1rKM2Z91SL_3I3c{2nbzdlHry4&TNNZ$$ zvd|)GU^Y~BvzW-t6R^p}h{znm6fR(x9pZf5Fx};-)#O&MzXy$2#QV^oXjZNAmxQ}6 z4jRb7RzBjn1vMhPWVMVpqCv+XD8Xj|%}Tls;BrY^Ap2gcIv5CEG z#|A-g-Yf=TU=nwQhgAZWZ{)C0N-VIAt1p>+Og<-e-2p$;JfkaPyHpzs6$S_I7sj|y zZWkm1X~<%hua{|@#4y`%{j@hf?aGhuJot;tZJ1T^GV8)cB~Kpa+dta3D&KTA zUpUz-_>6tqn{VP{1t&RH7XO|r-_Y)AihVw#Xcj6}p>5B~ib;vL1^XHGrIn#IW`#@R z2we1Mf-@6mKDv+z2K--8@sg9x*FkmM-|jyxj~X zkSeltH?=+?5(OxH36dX1^le;)vk{qi<;7)R^mgHcTQ%V)#ABj9{dmlE!+KS#e z867PTcy*HSu2s=;u|+zJST_)oywv0$QgB-NmoS7IE>n{y-_J?<=9}R=4Ts-L(6QPw zj@l(O1SKwIJfy`DmZ4ximXH~(xqHNo!J~RSR;Mo(DD?xW5+H7~ITteM1^6+bcV*-9 z;tL-h8spO>|KmM2sYH3mRii);peQ>3%c*?s9Gw+DVsF%uV`T7ogg{s7}AP7$hwAMqAAeMobzLS+oK2 z!Uk^W;%ZwHNb(*U9uh0Lb>MEq@>eSLPQ~iOFuFQ!8LV)A1zWQCKw}66KiTfSMdLY(1A)7A{I1(aHtl%5c{BtL?Cby!#M<_h==viQ=3& z7YZgljQ`8--gccy)@61brt%rGJYMEoK?V4AjY< z_Hc958#63=8NT;co7aU4a5-Umgw9I|`^-PZt8oRE+!0NIE6X4@9cmAx{41I`ZngsmmgMRp?))|;QbG#;((0aqW-;X+d7J>C=T_WpiB!1~) zeeOQ}0iFBR@=ka_XH{D;>?WCw?tsoIN8R-3x-%X+(?aVCM=#9121&eKBBnb9!mb&u zln<$8*&}i{k$LXnexOjB>-wl34xhNoukkwiZ?(gHZiyjF)&Rrk5(UUrHw!_oya~DL zO&4)WTmIY7;j1mPK~&pUv~GVCUsgijz!K26MJS5rRFt&9N?A=~Jp`Qgm76L&))q$y z;}7GpbJP<5NA%NTK0s}{TgH}YNxlXaOgJ9=Zu9Pl*2E5#@<7tGnyLY-?N;#L zgX5j{mI6M&8iMQ%bq-wW96&z@O0>KD zzxV*z?4HOv`FDWX$oe?2RdS$pewrtN{{K0LDIP!9jx0|!$U_kn(ot7{wPJ4%=8u;r zz#jLl3wsVtAV%1$u5J2FE{9YFHreE}jMU_hN2A)gwG^VXP84&3y79$i_Gse8!Eu{S z{vtm@wsQ9uL&c0J;NkkAd2OH$RM0NXazk|n4tb0PU`^vWd(+0d_ZWK}Rn z1q8tpgt6dui?*MhbjiONCD`czbk$odJ!$vjpHZ*QnO*Tlq^RtE{4?5Bq-RYp_v7$W z*%{cuia3&rYYBeQ&TW(hnM3vdIP*jlOy-X>huKe93@ty2joverJCwNTR1?VLKv940 zmRy3l$6-A_jY<&{;8DJp-k z^c{`uboToKEyThv9g5z>FUsoGPB*yUs#EVZP^l5w_y536%r**t{$qdM+dr-!7@l#7 z)^KF<5>5$qt;P`%c=*xXFLpzxts;W>0j)^iTly0H3j<(WAO`WVjHE=%!$;>mDf zPw&-`JXWm$MhoIRQsoCx!leRc9S-4hLtL4LD|(ZO^VnzJ-dFzbA1djmA@x~VA#yIo z^Hh(R6d}tB7O8;QOmQvWj<~=%5R(Qqalzh7@`OBsw32?v=A>Ujmmoy z*v@^H_L8wmjZN2Dl9)}wvq7SSgB4B(Rb+lnDhq=A>xy4yi=1^-mG7pDw8Mrf3Rbv( zc4IMh=2uGPiuTWuvv!@cUj5(ct3&XkDX@508g6K5Nij>RLvWo=jq-g6HdR+Ty%Jfi zJxfD40#xh&_Udpbey_C?D8ndHkbQ`}F0xYe7Ai8Yw^Wz2qS9vURkZ3Y9F~@dnY)PH zw7$1Qyq8_hY)XKAyCA;GNqp0$dppT=d9G-gGF1lgg}I`oQ_WF|&dn7e)c``VKi_RF z1z?=~@kyxsDmV&r%tU7 zCR1eh{Mgebp2+9mf4hUH(e&wlo<`EAM|dJ)(AV6`ll=R%$w8WgHY=}-(pb7oGJFgH zBe;y*L~Jf4rF~;eC5}f9E1<s5@~veOz!aV#W!5lC4>&w9j25*G^VGBHV{bW zr+Z3SIbk+*QT%&#!uj?4&*F1?E-dzjvs9N1Pt9|dL(TIP!RA`e0cX0TBS>loTv%q# z<+54+H%XA|ZRpkThwHW6D8)C~GZPtJ=1cChl6g@jEqT~V6jc+2m#Ws-%R@HRBZ-2> zKU8-5nMxR_&)Xa9zuM=*%q6-A7m!VtcG8*S^{OCMx`!LRLd=<|Med0%t-UavXFDsd z05~StyzXwEsjt>-o@F-*R=~hN6#gKYV_$|=Qu<|0Fm^k26=Bc2mU7kYwO3;{0u|`F z=2D{@RF_Zf=&=D zb`V^?JqQ@bBC~<`GC^ZD&q^ArK>loc-PnxO)9KwIHcB(bs%`iO(vg)Q(%~sg*od8| zt(H62dxF!5^~4kGwRfxA|6aaycJzF$Km1akbvAhBy#=p7D@Sp(qN8DFY%6Ug3 z1l;z(887|vsHd;LdE2^9+XK+ANP7{tGZ;^ZC-GE_wvuVoq_a@L=Z$g^y$V_OB_{4awC<)bWBSKT#MGa{=`wh~#Lsc^!$j@>_bG{FxWjfv|irD>&wmPH!cx&c|P5HJXf z1)W<;7==qZ;!Z?xiH-!DUh;HAF?IyU*}PtHk>w#Z#3A*JlIn3vN%c6Tr21qFB^7`^ zwiRe2A|Z&d9D&mq1u}?=*iYEgl6@GZv);@JZ`*XHmX@Is-ux)xO*p5-Ao&QyqFlEr z;Z4#lk*sbdPjKf(i*QykCWcWrNg>ElkuX0u0n`sEUc zwfJoN+%+=@iURRORgenpr9kYkM|z~-dh_>4-%!{+p7l z{Q5*dvMl(u;f}~CfigGC0*Ax7S{BU4{5$yyfR7i%N7-l2A5=8|wrG^IGXL(ITSB-i zX|6LNob}@(AzY9x86P|4mgA3j`lJ_MF{g8W&B#j8tYv6xht`Mp=Lq2@hr9TaE9Z<5 z91iD-5N6{Tc~SEl@A4KQgzY#+p3^M2^}v(vs}{ExW<>GeJ>Ncj)6M6edv7PA$lM2x zJlag40VDE!rIKo?~Ly5QHx|Ma%ozkcQN?K(#6Sg$!oxWtl0WaHq04|V~Q7)u`|IlCCkB%E1W^~q&>+GZp6 zGP`dNxkx~m!m6|(<6Nj?KjqN#%w zxCu~+CC&zX9bw~5bDrlLC)I}fht1<)`u3|ID*2<_J|CW1uO_Vr+iBh1 z%1Z0i?X*q=rh{AnHgWm8LAvo*-1sYP<0sh1#$TCA#0MxN$tACAuS5C18MC!U@^=qN zr45j*8AKguWLQLW*zAyYl}6rn2T9)!p4>O$EXFUB^{G+dj(Bos^knYTp6u?&Kcgpm zF^oC6`SM@fbKYqWU$FL&_+qWd!WR_MFt)pXOYI70Z}^|ObpX#Cq`h7X#tuQ+cbg}r zg9CWy_GfmBu$hCjr$d-qop(Uk&K;y}iII+;#rfDPMJVxDe7$`xn0{ex(`Y|o&v1I7uw@_=kV*WBn&+W*CBUNE1^nwqJ1s_n2D<>C4?E~ePCGO7I(8Ae9 z10!!;S{TTMS<%8#vsgr2=H~sF~_QC}_sa&|dO-Eds>4=lo-}LhNPprN1|1IvV z58yk$w@zBW?0EF*<$AAjh+%QyV!l>hp6Cxy3LH1V7{I^PIK@1t*X zM{oDzpV86VtpjpqkL?9N?d-9AeBiO|d`10q2zzWggzelO+aCs1om{NuZUEF4sg4;1 z8zz??+^i^Pufp-yl77fC|7g2W2cO6j&rQ+f#!l|uzzK?h-;xT;-EdY?+{7^3iFV}A z4p|ZrX*WgN=48B72{USqdWD@zC2S+RJvkxR{3Ue)`>R8^I`oZn|9e&<&O<4CgHHc( za)}=;gSS+pxkT(lmo|I$)33a=VRyiOOZgtxost?$mlKHaDnShrqhpA*yDrM0Tri;AFJ$s+R7l!YLa+uA$#!1j|7G!AdTYV{2=viU zE{>{G3On;Rd{>lIjvuNAB6q9t0zzD9Cnjqf{T*tTij}!S;FTjct|GF=HL8?uG_W$< z;=5KdkZHPJ{)YCfS#8{d7E#MZBb7yUv+&USv(J%ZD|sUVzbf7Bg_ z)BdR3Rnz`h+uo1$X?_f#ruUYr5TACa6`(W`Z}yl`-X#jNKxYLK1!+uUR2ge{TwZ$D z9ng?2-YC2=Mzqm0)lO5AFhKHYWTxa@x&hj2}$QhSElO$YrG|bn9l9FI@g~r?Z`2IY*HyoTD!HJgG`7B+ z1SP`jOmn1LQyr;^RCG~$fYDoSRP#nJzZ8sKOjwd0BN79DE3MtsDNcb<{9PnOUUNrG zuu|vn$3feCcsHaN;(7NZl8mLj$Idap5O0ua{h0F0~4{WtsiZ^?};G?`SyK|k_BENVXcrv7Gob+}d_}r`oD|rLa&t-**|yl6Q9?oMo{cQbZfXC zGK2`vq=K9l&$`PEP*X8r8L9}7qsT6k){zT{uj<7B%RJ$gZ7#hjZTkP}xHN2Ua101ji@1gPnV@nPhLe=sS;*GSS+zb%!t#ivHu5(FGb zOjL*&kYF);zZ$-nzCRD65Zz>^Q^8u`{yq5tP0ds_1}!KAm|Akmwdo9drE`s%btMn8 zGt8JPUJ08pv~;O;C-hM8&L1f&3!&~#Jm|m#%_d5E?1-RT<)n&JdT4i=B^{n@F%TeW zYN?dU85W!BvIUPp+1AkRHJZ}(#P;^Vngza9V`u(>_A>Mr=qw5~K3FQ#n{v(3ThguG zj~nurf(y>VA4sBQ+V)+x`gzwSAB@&kV zJ9)NjEeDT~Ev1&Vi^w@V%!cW2HAHaH=QY=|s&52lX|2_v zFTlo6s6nT}Y$D1xkj#p z|4hSo<2O4?AjE6*H@Q3b*dRZYjU9%vdbUIPfE&uPWGKs~!asEyiLzCf#K(wW8&)*+ zzH*6^X%s;YR^&EBtO$y*B8Y-4)K+Ae0w1=!LQ$|ibZqR1j=ei#WA5nu@SU5^|I|Xk znYxv(gQbHN`Ul&LPlZR=NNf{L7cg@+hwvvDT%>o_)sPb6+7z1JTq2WUtu$H0w}2^b z(VUJKc_WnnL@Lngh*PWK3yB^LwSfj3Y9T9CAkOgW(i!)Ngf=G56dq)M`_CNNOO?mR z3&?o2{w7ray-J?yH$(M9&iR0w0obdIU3WY)1Qs$9Uq~)44?}Xf`%7g>8HTw36;~Oa z?D;{t#E`1!Q?4%I25K6B@__qqO}OD#m3-y-{n_&}J@1)4FV%A+dxk-Rc(?2s?g-F+ z<{40XhQ5*X8H|;bWj@C3i@J4pTu6zC;lOBYiZsVZrbu(FW{Nb*_{F3%O)rOgbYxw+y~|y8%(V`5Ulr_wUrUO9Pkb8CLQVr^`su78WNRXZ2i8wTt@;Y za@~o~k_k#y$KWJ&^6WuHV~LW~qkRitj-zcdmZ;NAduF_IjD8MJ6|`g1R#NuRq|#q@ z>?Rtr4y$zd73(nDe%fTu=ju>)2RlU)q#T}X28t{bbjLW$C9INRD4_iD#kze4szq~u zRSh-aq|89k1wiSu@m#Bcq6LQky^Z99WZ8uQBlx^dzpb#8&jqQ?~;qYrVd!v9BuCcEzzkc0{bSyL@uJ9Ww z^d$9ntv?;7pK>;)CO?~^cHQwmT3R6%qZ_aV^g~6XtXnv-_zpq?AIAiJX zTlRVha>jSiMkP@&_NZ1-nZT{M=}d&JksQ?N-MNuMY|4$HypO(Jz>;S%@jDD7nY5PW z!`8iK9BYN4wL~KBAUG{!#l6m+E_+I^RUk!UB?&mDobOGn>tX|XHR1l1Q6OPSw=lm; z%wP?(cf)51e`W+Dd0|O4{b)ew2q_I!8Q2aE_bln*EQ-Gg zO19go#Zw}1^MZDfh*E>mpW*N%lbyKVx3wL$~b1o2}+(aStW!78jMG2d<%+Gt0 z@R?}^ezy^1ZV8+G{5A^BBqAYa5vc7>27$yve7db-g77hss&>6TPHC!>1Sq(b)#lcJ zD2o$SlOb<+8Q3b3PO`>daEXn|3Bj}W9deU}bVG@7850OBf4o^)OkVdtngNU0)3yXV zRmInv7Btw46jU(Wa9@*d+-4chuA$v!LC%+oS-htQ(_b zgcM|YLP%}9pKWm$$5WFcxbL9)^%kQD*N)L!o8GY}OrDq0vA{*^pLuR=;NsagbpNf&)oRpXfd) zVhTjq&Lbm|ET}Q`Hhk1XR2^37;Nx_SWb9)>`QWlkJ5vt7tDeBh>)~1(8oTHD6kDD= z;HirDZL!OzJ9S!Lj%t4s3`^W-50H@4)j2Em9JMQ=Q9LO8P^5`5evy`OCLcL%5-(MI z%^bmiB$(hY7=^xlB4>u5tNuJEV4)QN&Ft~-+j#FOTiUjC%(wx{2}=Yk!gZ?T$*Wzd zKwi4$MM{N97LPN*Zu(yFULR>MAZ6eHx@S;zDOS8&H3j=vOR2$2+HHWaUUAX6iSaDxF*nPfxe zwFUnur-6kbBXOIST^eEW35nOX@lr8ou?KC013D70VmALXrHb~UnLA0!nw3?Ab9C}|#4;4A?VQ<8R4nNkCO9I=}n8jZ)iIR%!DWUkZhQtM@8CO)4Y=g4s$n96?r5R60&Dr?h zh|_W1kAKEAXm9-Ku+zoN9rAhoM3ZYP#KMIRZ})s&(;@7q(;;latRJYSm*1tnEo};wleLYua^h#~{dw^#_L)of|4}WBmj)|v)7$#^ZdFhckH3%1 zFy2SSdj%hLPb+v@riBh|h8qp5yu6I<06spTcsi~;*Ug>UXX722es+!HUdSTtmB*~~ zk~`$Ma~}G&wkR%#Zk7a$FJwExE|wc@y#a57Ky>G#PIq4wdS^~_Ef=ekryOwfZY4){SM=h^+Gwu;)f}K5-vuT{aKYCCL0^~j0pmZ&gnR|sBLVh z_?EGayZily3-|lw#-^Q>bk6qi7yPXNl)?pnxzSzwx<@zKVRQ>^bl_PaG7yoBuC-i- zJ)M!QZcpn(wpS&p5ew%WNmy=(T_d<=b-qpQ;|hT-w5g`{dD42vZivm;!rZ6w6QD~4 zuIW}TAYJAbk~182%eETFt_m`rMYc&86;8%@{$|b#r#aeA#>8K_L1WhS;GB>-RS)5P zvI9700hA#))E3=(tEEF4ooXpgT(y2+wH9`&#R-*03CslVE!k?(PBAp(QHL^ZG3i{K zS}@uE5TartzTQq72#~@!I8wzT&FWk??TG{(L&;21>yhQ<*kjdda7e)2plR64_KtS} zGX&Lkz)L%9GKBez%WTL!D4YS67Fe#BWnPJ2aiXo#AOk+88Wq-&wF(4cG0pO}*#R(u z#_Ku*Hf(3WhIIyveupL(?1%g+{XyRpx9jn<9J{CzzdiVwx(e%9gMT?7bPs;nfY*_@a%8*1P*(0-Tx|;MN44xwoPr7{DjY^D z`9pQHXhEdadbq8<3coDQ~WD%DHmP)E|ZT6JAyizVe zvgE+)`O7Og$V~^-a<_n*1I=O+bYQ??YplR`0#+8yGP>BdP0dm>n~&b{~XxbT`yRE(-T7MvjxjN z10;4Y5^w8?Ug}C+<4oQ-r3uGLX>@`V%{|%#I9A$ z3q2vkKC`;l^#qB1#?2odaC6t(d{a*h#y%s&i2)&YO^BNYgxLMcr8*$Qt_kt`JyFel zX5YNl6K?J^B;GwhV)r8P#sNEbkHmWiNbDYoKko@U_nE2vfq{k7wT1I=PYAKkl=DRc zk=VURykdaF?veP50Xuh(#6Jv>*gXRxMjf3-6Qebo*=Q$Z0)}p z*xFs&+Ryfc5c|y5-Z;=J-HXI;4JfgDB>to)NbEDcvUs3Zy4EYd9uQ*p-2C1FA$CoO z-{}b<_L+fm$^ePobMqquBzBL)%Lhp89*H*(kk~yE|JV~G_L-?24J@3lEu7!=gb@48 z!Z~k%#O_7nWj#USwo0X%zqN;3+*;DgE^0|Dt3>FQq&$~d)|Zh?UH5I0)>Rp1>+!}U zCj<$Bxzm`Wynjq`LewXpJ?DY*UViNAt+$kv6rvs{Ng?W_WuE+cmJ~v%(@7%h)47u3 zmTQldI-Lt~+?})4NY}`bezvBhw2PE>RuJl?EcfjMnP)RW!A)_xGAn`e);2g_&ft9P zlv|EJ;^~uKe5Dhdy7V|rUJ;TSSr9ZvlU%rDsn6%at+(dFt@~WKjNQ;RBw1cpvhPKF zkP&y74@-qxcd2meX)4^hAE2eett%DosAT|eO@-@jt`+XctLsurE5okvlUz18)@S;# z(F=We+ni-lx#j1@EGm~LlvtZQ>dF^Sxatr0Kk}_ZI;2t26|pHLmPpPGCC)*D=57)* z*K|1mo_#2jfe9nO1qn0Eb;O^9Or@!#>l@KkkV@>@y^;9U!rLt@7X?9IJaI{(eA--6Qdv10;5j z#BBq1?jDK19U!rLB>rf?&fO#N7Xu`AkHnu1kk~yE&m17Jdn9fhD3p+O5y})6g**7N+1Y-AE<-hcT5c^CZ?$!$&_8Bv;?+G){ogd=cHx*B0Y|Bn$ z{Q6g0H=Mok=oeqIvq81=3{y>Kn7;AGoXChr22|O#n!dCrRM}_Z@jnd+v1>y7X-^2T z&veWaJwalhar2(N;O0KV;a-TaHQp1S6a z^`GvL=;bSKkXtbrDC({i_3Z;i-92ajuqT||XNvl`0TR2X#9IeQ>>i1?43OA862H_F zB=(sr;?D;bPS+OBLp>qHK2y%m4UpKqNW67mYj=;t$9sarKGQ4j9O#v<^~&`Fk=Q*q zpEf{Z_egxYCnB-WESz5rkk~yXZX2+3_egwXK#AQW@!JDR>>i0{^aP20W^3=#3tPL- za5&xz9QK)k^YxxEbDtq`!vKlhtCed82F@HHaX^XPBk`&MC3cU*YX_9rJrY+Bkk~yE z&mJJLdnDe_6D0Q8f@Q&A!P4~x%V9ks#6DZF+&{2zx)+Ie^#qB1CK87SBC%_c_`pCU zcF)a^^#qB1#?4~`Ztj|!4<8U>_uTxx0U>rxh*$Q65c|y1K7D}1?z#Db0TR1M;@5hD z#M|cVpy{nQ78BULoE!aG}8l%z3 zUcsWM7S%16e^l8ksPYu-ML)H8VrtTQti|C}G!&PoT=Do+H0-`bQ!(quQdEk{dj?ju z91l-5Yf%jtso$)rUWu~EzEx>x2?JSG8k@VMfXB8S-u+XC)63WY@K2Xrck-oQelss8 z7_0}orpx&8o^X1fDen7wg2X;s5B_B@%SL-^qIij+tE$PbM?=z*bt%hXK1@s2otCVpTC(m3Xj-x!qa{a8 z`?c!EdQ|ti5tZw8qkXH!QKB3BObTu3iI2I@ka$i{M0uYf@w%QMvCs73U-UvB_8AU8 z)C(N;88hG66K3u+BwjK=V)tv+9}JM#JrW=4iIv!AdS%H#uVgFAkz~nNYhChb5t>`_ z)%=o=8$(#~)#5+(gq!EiANtcaf9R{p3coh_<9jy!?efO~61%6wlLqYEJreI6P-6E;{9R9w z*k`VYkMzP7(Puaedx66~)6KsesFm&|;`atf>>i1md!knQjGbTY2@?BEugn|hm9Do5 zelrk>-HXH*d&13qCKB%(AhCN&e7+~_+-G{_Jp;YcwO)C7K#1LQbF&wO*k{cA*S)}D zpQ+|Q^n{uF42c^DNbFuBJ~KdK_ei{MU}<-c#8(HD*gX=T=m{kb68*F#BR(ta(=)OFa=Tfcqiw|;ob z(hjGzkA8!4LG~mCU!N^qZt01J=`$pr-xKNBXGr|+0EyijjJFNgxqBr3YCwtIBk}p3 zP-351jEj0e_|8{`Gu9ts9y})6g**6#VM62`}Gxr3CeMX4i7$C8G^XBQEAhFN5 zd44a{N}u6yv==z+Gl_UqPnh}Xa=CIyu%h)}6ntzRckec;+%r_#XI?p~aD7g5=wtIL z`c`e$<^@stWAlde^U~n%3-4T2T4>k$mYS81&8v=c0})rza`n2};7Z&^d3=aVi8@uL zZQZdOo^vU=Hh1Szb{gDl4IWC1rP6qX7e59F9p0W7B>hAIUGNk%s9v)BZ0WVC@745H zS^z4Iom4JqtZHtbdG2eV&!}u84%A9}SAhXg4lg&D#&Xrm9jku~1O+iT2)}RRO5rTo zCA$m8!Yf@%^p&>yYB>nFB00Mtx#BKJR&P--)dc6C?&nG)waD6-k~dnfkc!Lmvz-}g;qosCC!e=A}S^LvByT)Kuzk!%l^$~LUf^* zlgoiKTx^@G@sFqD4?2y1Vk$PG(BQ}4q`{BRH2682{E2k%vzh#fH);G6GmU@FCVx>n z{uw8K(VH~*MQ_^Rm&|_fOWvfxFPUlZFO|#bt?=Q>X5fTgTy9jNU{YEooJ5c=4JP7S zj@-Bk;RD<5A<45e7+?4$6Qhfx@`lyg^9v$G*f<{n*OkXNY~?cf@K>s$U%20WJ3j{7 z`>`_3j|jxzy`?JBFfdUlC^vg3OGPN9n*yY-8(>r!`%1N1J|sA}&i`KMGk!1hqhQYp z8jQQv`H-Rwry4c&5;p2m2=OAJfX|7k=CJx6SxMs)CXq)!4M4SMBpMCxvYX&lp)rD{ z;`L|*p*O|Juu(n}wL2WCN;JwaODN6}ngWp%CcC-g-UPkV7qvYDyJ=5z-~igAVfqk( z?f_ci0U8%TOY#7Xw*oY70PPWt8$e?%09pS_qC8x}$Z%txFf!bjFC4tLv{V|68CV*Z zKA{1kSiskEMp=qDG_#Zs131`&>7STNbdf0{V9O7!6wQm~^KagMi$U;#K7-`a87zY1w^oIex`R z94=F%{20@~%5aPC8Utdwu9v@|J&V17#`9Ncfv~%(9B&o0;XQ(m(Xw_fju_Y2zH#S6oYGQc1ysxrn!rp##r>S#bFJWEnFN>r&hJC0XI zR7G_)Z*dj6a4lJk7Ie{9?Kq4Qg2L;!X`XrS+&h_WxzX9%Z!dQ3dr0H^{$0 zwrV)#kSi(Z<&TvQPtpExT7+nja2m#HMR)K+c%6}CnTN#Oq-RzE{I@B`ZJFA!eqaO; zj;_c!4my(UU5;0UpM>4`TvZh}h#x+(KfiwAgQfZQG=5;bMNiT~<+yfW`t!WF!n{id zM6C42g<)H=upY7O53PS?aytoSLneBwIOW>tx>$&R6 z2##jb!B;sv?h**d%zIlmi5IF<;9(pbCu+i$e_%msf}aw}6_>^iD3=q_m77fnm3CMM zQrS)8Y-f;_%v5}(DBE7`Jdytotf-OEN3-Mbf@FBXG{b{33S*NQP+~wAR{XlyH6O$u zK^6iFMrDOQ%ZZo}HVuG4Ya&rvIb3(1P$|k3t7$=1NYNL5Wn_XiB_3r zk!x^3T>gSqYMmNi8JE?++7G60zxp8-%xT-Ny;f1{)ui=cJFTmxwO-v$>w6`wYxK>k z2Bkr|@mJjV5h{fiw18LD%2cfJyH^|~VUaZ};F~d9Yn7F;2c!}g0m+(S2`wq*miody zP1DHO?vV22y-yzZ(B^wLzW6Wksp9?ch4cA4wpc%HIQFG`zr6aTb!!fZk2os(?fjrz zPiQw21R3koK~qabx7w|KT!?}z)NgfVb0}W+KbzdgEOCo!Jn+*AFLGhG09 zhv>Me1vdl5iy}J0FbVH8@dRao(^FXGa_uFD}+sSg|J!or~ zsSeec1m2v8zjC*%iaJDCSOsD4ScSu_!tnGJ{&<&K7@xkvQ!`a~Xr>DHSp|q}Iv_V& z1t2a~82hZaL~Jcvq-^Y_VL$WB8GwG=Ds;fh*bPCZoiYx$KBVef7n$F*W;y_tUu42n zwv>!dx7tIn2kXsq^bp?XEio8y#MinkUu$EbmTPFURgu7;p}SkEu)uUC-Fr(WJPHOK z*pdiovK&GxYE58NaJ{$D+Ysz{-s)WEEw>JJ@*K}3VIN||jr}iAp~?KruRxp$VP0Z% zH_|?(31P0Ei7-#I3iI1rkim9yrBcQ{T1#a0vX#xUH}%VyckzRFh(PAYPub^a_>d&O zOu{AjKpAd?9>lY|SFl7MOM^#DD&q-!PgItdc&Yn{_!WCoO@>dJyy4vtOO%gAT8Yap zg|H>#la|h;=e>g5oAHYVL_IvxwLoLmZ2YP(KhBj~H}T<)Ji^10?y6{xvU);m=wmou z@_9%}fFeT#Xx)aPr(Cb$QyMb#P(khgUO>eQq-3LM#A zi;`=KStMO7=7qe7RcX8mpEt-nq zGx3D&$l(9N9Am}qD{VQ`w9T4J`ih?E_;Y)DJB zva_L88BKFU;~5h+tMSXpv5IQ^TsEFRCPyo(lh2;>z5bZGA` z3~edW7Z4eR`fakPTh=ORcoivHoYdb+5_&;)-3?BVT_Cu&C&-4doKrytW+f*vWz{@S z5h5rNWR7NbRFL6{(WIqdZoiixS+W`b;&cA{V86jSIFQ;z8O0AvVZ zLes6yIeQBE5UFHZ$sEHX0yE}WJvfS|zUennyjC5&C<+sG->P57zzF4;` z4UAiw%nhU*kIQVWIs?p2?}Qie{FZ(b|0K&hBgIx~4xIzl$g}E}ilWUFpkYs&ViAMJ zU4NJWB@z=X=sm$=w%&BGKxtL6v`9{x(>O$=w*=D5Q0s=;>*o4 z*Oo(JeX%`%BtyvUt!z{ituD#bAt}nsJ0wHzkaX@y+*_$TazW~jToB_dlg+sucjU+B zEf^0?yiLR#YzQ3|IM}{PowKY?2Wyo&7_1%{$6Bop>zLUi!2PRO#l(c27>M?4tKhl?>vypW*!KhEjJL{$+_7t=LQ1kejxamW-*Y&vn-DJiVcK) zv+f3RYNvq|=R{iqHYY5rZ79;=Z|*k3_%JYN+_T)4FgkiY^%Yh0dg^N@?se3M0MXWo z{V;a=s2LX{iE&Z1sBg0c<-B&|qIK1qGcK~_Zg&>-BW7QCYusDUsXC7!H)lO-W7#yi z8M2Gmeg+#k`(i{!aFt@yJJRVRtS#LVlCA3WTV`LFwcNy0s+KXCNA!|2nK785I5RdE zIUAUz{7Bx;n8@ve%g*3O#V#hmIXi=X9ZaT3rh{oX8f$|9Gbc(Q$gJ=d2$p&X=+xmQ zwlt$f2pE;HVrptS2>i-HP6Cf@4^az7>_`59H?PjZyDoJ0H41-e)6g|*V5^vLKHfPOl?jFQA)(qO_*1w z;nmJ?2W&UhUOR=)r+x_(t<=64%R2*%WkZ;EF3-P%9<=4#O(Uv?T&h0-P9gT?n)8$u3+2|Kw#_WCp z)*_aMy;zd`-Hu>njVL~|J%;I^>BQ-{4PL)!?kE_&Xtqs^=^(Ie$r;$Zl*sAXVS~NP zY1M@7mrMss%HugjwL{qGD0w|LY(r)`2;Kl}bdMWha&bX# z!5hDf=Vb*CsV~DrYDXRn@jASb_mDcDq@Vh&_u#Ua4)N7i1x}|ni-WJ^E%P;WdN&PR~>*{~cnS+eb*^Wo~@-12fXr>Obkrk1f=H-j}Z};AfjJf3^V6VfQ=yA6lq? zj4%ITq5b20`3nVjPVwbmE7U*Jm!Ds#zs{FmUZ{VuFaJsbo-2I$IlerZ->ZH3_X_oI z^5v@v?ceUpe^97@pD%x^Q2$|Hep~_mCw=*a1$dtK<(muiwk@e&X#cQZIs89XsDF$v z|6^gkj`QU|D!_A!FTbn+&zZh_V`04OeECg<`WO51Zx-6W!k52Nfd6V=et!Y}n|%3s zh5EPq@(qRd@AKs+7vOo=mv1Yy|D-Q}u+aYVzWkO#{cXPdn}zldd%)rUR|R;E@#W_f z+CR>huP@;96kmRQVZP4vgFMqTE{}sOcSB3gl`|<}1^>6a!PZsLm z?#q8zfd4*UeoX;C5Bu`d3iY4#|F8!g{;w?H=NMmpYyqC* zeEErm_D}KUj}_WK)0aP7z|T5gep>-Q7yI((3iYq>|7D^5ZNB{R!gvqcBK(hpcNW?|)|cN}sQ*o0 z{?kJJ(|q|K3ia3e@>>e^FYx8(72v#NKZu~7dwUw&nw{ZoDU)&f4i z=gZG5w11v2Kcmq8rM~c8O2e_g2mnlFE*0RNG{c6k0q0iLh>@}C#*bFwf0O`-mozWkv={q??lYoY!R zeEGSB`akjI8w>TX_vPO&)ZgsOZ!h5g9$)_B0)Bq&%hwg!f6|v`^3w%2X{crK*-zwne319wvVZ6`z@-G$O+2+fSFTk_<5r@ya3iZF@ z%Wo^dbAm5Fv{3&$zWkX&{d0Wzbp`k@^yPOK>i@`>pI&JHYG3}Z;mdzp!2c<}{OLmdvwZmph4wf2@;?>u z^Fv>LX`%j4efjr2-V*-3!IyunfX`cf`F9HN-0RDKQmFs1FMps=f2%LwQh?_VzWn7v z{a1bYt%dque$3(d;X?g2zWk8_K2P%HXB6t6;me;c)L-YzFDc;X5?_8=0iGZG^1}=5 zU+2qjEY!cnmtR$A|88G?L!tgdzWnyW{QlOL-(7(Jd0&1-q5W5U`Kg8ZI{a~m&p#F5 z|Ee#)xKRIFzWir}`ltKyI}7lf>&t&rfd3+2esy8ISNQTj6xzSWm)}r;=NG>Gi9-E5 zefd#^`Vac@7Ypz_?#nk7;Q5^|f2~meWnX@CVZ4Vu;qZA_0iI)h`F9KOeAAczzR><@ zzWlcZc-AKM3+-Rv%P%X`zucFvFVz2;FaLP~{+oRHnnL|MeEIJR^?&8dH~VoV^5jup zzOFFdXMFj~h4H@R%a1I;f9P)=K7Ubw=V)JkR-ygleECU*`ltHxa|`vq=gaRcz;m82 zzo9VROMUs}h4F6m8nsgi5<2gM8;7>5T?nrVUDUwE#f8Cv6s7{CDI}Ep@ z@dNg`xHFEmu?D2s#u_+I&=LR9wGf`4=YhkNp9e?Gi;e*daq+QMSPhTyTw&a@#tMhR z=Tw-^LSu*!4!B^#9l*}EPiw6ae?$t4S2*XUT|Cm+D3qfn8d$^!2p;CA-L!pLi@&L! zv;)VXxG5KfSWBZ2jrE|4gy*c;W^F1xSwIAYqW`UBI|Ps*;B~T|JDR6~I@Y6Ik%VhL zITOND2rJp4mN`FMa813Op0v!Lnbpbvio=Ud#3oHF_{twM5L!y}hwN~H4u^t23Uq|h zokn*YrDH2J!Bn|?2@F<}felx^J{1$-VSA%IXvZGrq7&OUjp{y6fO7Aoc>>f0=jW}N zI;nk@mP+Ia0BdT_&L}WkhBVAmPoVZ9%2xUB(lB znTp5_M0#GLSr2$4p zoOJS%rNP<$3t44lOR?-pu0<0q1`@3q8w-kx}Gjb=$r5W{!3`>KGyuPIZJ#hFdszWIWu9y;;vM;;_D zOyQ0#XUZ37KB}ZAbh&M@dHVn0^(Ey@h-0Ic{h=u(x5!(lry5>4jvzKX)t0g>kH@33 zR>=wy2fs4vd6LAFJ)NG^Z9R;8mR{aVl8wcIL$t(Ma_-;B%iPg_YtJXWN_8@+OsWW< zv90ASD~%!)y$*^jdz5TcpuJx?N(5vOuW^L1hjH;ZA~G^j6!C4sz9}Wm5-NUpDt0*o zC(FyB@gQFHlt+L>*95ip=5tAwUTvw*lefE>Dd59f!(R4FxQS0g0kp*=+*iD$SMj*z zv+@G4Maa=hwv1=g$MkTz4zGTwTw-YHEZi7Wlx#Z{Cj}$G)(lDVA(uhT7NVvON%X~O z@>2MH%kxIQEv1JsJB;+@Mnq9nZVu$F)@>%8OX1m8J24Q3q&aFUm4UAuvD$>@+%iZ% zG-{Hzz~Fi|)5#edzUN;$dq$a1XVJ5*a{$oIYp!PqwykGxi`K|i2TVRKyA6)oz?NqJ zOQrMMErtA?rRsho^0XhVG>%9p7hkM1kQK+rbC;)m&c^>nq$=-z{4=I1U)Mu9hO+sl zQv_bwJa)=0#~<iVTI=eSxdzHQESeC^SKmIgS5-*5f zw9i~7xsSSpJu9>eW7d!=Xesgcn2&tyz5g z6<6K7^*axodc^lHI;6v@g42b5RU!AQjYkXiLZ+$}%2c(?ouQ|aGF1sGWL0he+O;y9 zCTx&b*(IwQm5uXJcTk@(sNHN}`!q(a{tAj+?k%8+0R9Krkk(~GIw4yqy>Rjw&!2q$ zmp47uwooEh6-NX$B+_tYgBx{&i_9C*X>k7JXKrwIj;xLr8sw`;BX4o(ETUnda{ld4K zHF`@wYU)kEA)!iauqQyJi{&U-8AE`JrG_E%2K3qpDh4aOpggyMat=eqA!Wz_z)!P3MFuda!ZRb6S;^@l*@NTqKI-0 z@eQRmn}LAqjUmlkjSKu3cg>S;&B(VV@*PShx2DOpCnmQh3bw@jvzuAl>un?7pK2tl z4*9}d4+WL=CJ$xoq-sl0L?zob1Qx$R)8zJ?DXs<3^@6sEh(svcolTa!+b%e4xiPWM zWr1Uuf#m~8^4}abvar7pgwpVv?Cts+0bFlw8#>16!p zWx^d!kc_u|$fUUZp)!^7ziNLm`SsAC?PmbxW`^mShQ!z#o#t23QVo=7B$Dkzb|C@8 z&Q(N)p2Re_eLwl~u~qr$X0gZ3y*=X*>+_a9Ze8ZX z%d^|#9-f-i{hB^x8?(djkh`$OO!xJ8A6_DYF}>b>_}jvEU+}XnzThpmRnK}(9pD4u|9|%01z5A}s_*+=_x0U-yKhgoG&6djbH5plx}_P^LZBYRYrfWF zBnE*H5A!k}-lBzVgk=IDL02&@Hz~Q&R9xkjOBI@m%4%X!G%4XU4izpH%5GJWa?7Tm zMM%;-Dru_hxG5{n;9!&Af35vk`}@wFzM~mw2I%UU`|kPZHB&jxc7mJKd<_U@DoesVDz z9Pa6#Ji~h;U0SojOLw<_@ZFKV))2!3<+^ous>P|v`jexFJso_qrh_-+f`+@(%NN7l z`PW&WxQrnX8%SVvH!W=-7`-H+q}22<5jI;?4Tlkb0Uph6{3aP>=thGK_A5K z*$!g3&EIXvmnPsd z9K=Je%LG}~x=fH&Uzb^$iT}3B>c6SC`JrsVCTD;D6aVp3pFaQ7|J#4ExYE>2M2mMr zC0knEI^-DMd0pmNPsD#;Z|>Pl#N*FqA~wqAfUm%W0o2-47(joY;FIW=g|(-DAS31m z;_v#V48&nRYr_y$K{Y?YhS0RC6klC>dNMCPRYR#mdky7>b0CM$^fAQ)tUdibvHwtO zPr3j(0W7iBo^%2Bo=omfFvMx?>BeAj@#&q1TYS1*7N7pz%8IJW^zOk@S=PLLaLydY zE1UnabC)kV`oFo=54V1z71rqhK538-Ky{z}0QQ=XZ9T~S!03*%S!o*IEBihFq>*a% zs9hUc3l>_R5N9DrE3mvIbJ-y!0mT(;p=UJzl|1gF`9H{0cXampC;r1nuKvsa;x~WA z90M+Fg@g|~2`9M_NB0m^9Gx9^bng6drXbiNd!198(FyX)9oO>Nk$)FyBwq^$T0ioe z4@lT=blU^I|{qU9qy2N${Fv*k`*NE&>tak-Xz(3#&5w+ z>z+6%o`5>Ki3m+fP%*^C_Z7V1Sso_iHs*itzp=S3dHFf__`Vc+BWSIS@KX80xVO2nllAEi4vY`|Hy#iHiUe`oHqRw{?@MTu_yt?;bcO+5H<%**=x zYX5SNzG`Gy*POT|BRG18E$a+_7>AtCityAKv?7H3yqEFjIl;GYukbT@Vw)s9RFSeJ z4glw_=dbinL%;v4w)qm%(lkS2I8a5Qo>1gC1ug!8ZxaKl%{j?@mFM$CR~5(H28o78*9l%TCIz>Vw?FHw*)~Uh9nSsXpR|yMrkd)eB;MgZJ#<#&U_DREbD}Zk2z>@_K6TT2?oC&9C zqf%!CM|OT*!u1lnR}zC?sA1LPfa)-x{E#oC*v<|KXXT@Z%52-pxmfXj=8&Gsg6Lek za8j4%Xs$ly8Ch|>OHfxKo~*E5_f-htNLMNc!WV-~sdFxU?Suu&g;})9IR2W=tN+_) zutYW?|Jsp~Bu8}@t+9%rf4n)4=g|_9j^h?<|FMjyPqxip9S&FC?-P8aNn-|QqVHMz zKjSWpL=@hRy|KwNKDUeT?2h=~7O0R8KB_)v3iy;?;bxIX=9m=g_#BU9X|-UbTlJ4W zBeh$w+67vZM7-T*c|_|1(jmIqdw}_%6X%})L8EJg{DvX_(s}Z)N6qris8u6c#eP_N zU@(7BD|MsCY&Dwoo(J{u?7@76m9x&CYTaFvbZbt})+8dUMvS)9VJv}J?QAtzI)KXW zuePg;m|Qswqm-K#hYGZ z)3vrL>QUZ&G9BGKW|aInaX-SAknjgtMoO2aZ<)5EuP*viWPXyplkZ&>xE~Q zgRawmWD=-xM-m@42~hU!VfhMngZU=0WtAAVS#sreb?LMKHIwbph^Ve?s58}0LprUX zdaMTxvRQV&ln*dM^V`GsGDQ9bv-x%7cM@;$bbd1;n;%#o9?1{=W4K2y@pSVwx;lq# zCDTO{A$Vk*hkh;NF;{m!rc-X|F>ZV+ zh8%4ZJ7MWcC!XpbQ;|VWe>4KiWPSmg7Zpj4{B1Gc6KF!|gQC!`BzTc`577k7WT#oloyU&Kk z-)#<|A2oef0+xn2`Mj8FTFQh#a7Edo{6L;Zi*M;%K-Q zRKUblfH-U19b)bfIM+eW2RWviQ0_ygQII1A56yKnwW0ZB)}6?9cSFZxO1@^B`_}w| z1$=i36>x4gm33!3TlWnlk-0sA>pGpxw**^GDGJ%3-f@*a1^ z(BWzuyLvLo(Tf`<#Y%NUgj}vp>kbHM+=1U456d@QQI6xJ9LJno)+t-&xF`cjIm}-R)W|PaWDf3d0i{vJLua$f|52?hl#8fP8lvKI$+pQtHxVPu+gSK z#1+jH7&;MCP;8nq9p9gpOnMEsj^Q4pQZ`(rOvgUfi6r^Ekhz}dnP@zWCaDX^(c=-T z-Nr5<$}a9F*1#?7TDPugq;pr7rk5!w@rEfnXM1WJpybFg?xt{Ty0{|fR4+&=%R&A| zzwA2)6n12XW%JYWLAY5L+1bQgg^63|{KgCS*^uJZI@Cy8H-b-$hQ*1aZUujYHGuas zq2GV*`+k_85p`Wm3*MLFjXa2KBcB|`p&Ukr(p}$rv21+RM7)OI`^2^%I5xUO2m(0P zD2^9HFPiN17$@0AB%@o&?t3zdkDY zOk*aeWhR(}u|;P`H!$-#w_Rzz_s8-YyZI&k zW?!;7s68FBVYlS(eGo_eX2elDXS#{azcp%BYm?4n&PZ(}XMFTn5T!5Dn*6*Vf~TD6~Qde6?!>U9w>VGq70u0n~< zUeCR29=HM`akDBm-0$n=et+KlcH@5cPKSRn8g7&_UB-Q2Znq{k!^$l(zhwi>36qD4 zzL9AAEHERc7xhd?kv#asY#k;I3CvL`Yr9k3XnM7P^1jXveP3)UpUH)}9I<)u5g7Yv zhkrY^c~g!^*2rFwzzoXg=c3r>cgW?#IqnFIWm38^f97lN{b6hjDZcj`W{%d{d*3Hd z3r-K7Kx3}T373N*-$)Ox$&tQ?MK@Uqu2(vVzvE+p0)jU~`knnSmBL>V;!!p$CZ{L<_ zo@ySuBa2`0|LKNvsGs@_z0VWd44}BRir6t#JiR#3lQb#vCWXNvX0QjmiGZ%kC~Cfw z$(Z^UbJA9iH7TIm%=^}h54bZ-knT+G-!r_kt;IXLw0vhc%K6Ut4syIRTffjV{-5Ff zyh!c_C;2$aLcf>O?}yXxh4lLq>Gwyx+Yk89lm7Gd{_{5f`BMKm?LQCtkDlt{^jrR; z8ThhuyFT@H#euc)V-)tTFz`$b_b29~x6Y=rRQLl^*(XzMGWN-xGb3lyTWbjFhKTX( zKYD;#Q3;AlMq75KKGYGb@rmtY=GDIkWguxWZ_cjo>Udp4Z$d!EIw|HgbOf4YpG%(b zklTc6>-h7=$sIWPT(a=kAy{|}iA*fK=h?9En6VIxGQVPCpR<6>riA1vuGF?q`rJpz zesdK1AtCvw!=BltB%b-g(wQBpXI@XTm5)*`vpq`k_Z%F>%&-8`)v;6~lj*Iqb(|aQ z7ZXG(wp)KGVwvX%Z<{l<%8X)8d4|pB2;LvQ7@9ZCk?W1hVTP#>rQkkC$aLd0GC9~K zbkSF>qurJ4$cDeg|y7q{Wi@1;Cc--d4zA|S2U-OTSgE? z9$pG&*M;@qze)=|VIey)mR>G$6kmp$(Q|(MY?+YpfCo{i&OhO8n96hk%h!$p2%FxbVDQ!8PS5`&g=u@}MFp_bp5>z8f> zrtwz1IWn_ikexuCxD25&t-z$5R%i%WC-Zv;+<8iM3ii2Zq)!Al5y$0 z$(*DaSqH)gR{Lw#q5stKmo+Ek1QSbgVWL%Jjr$iP#QaH4RV!vT$}|=AIzU@)XG<>L z3B&YE1f+0ZB68>Fd{HBx%wmN!?urd;Xy0NhrS73xreyFIf4d)<+f_6ULa7BJJ(Z$; z%QbYPM_56`p@(cGc_mf|)Cd1VltDe0`r!sqQn!^;A-^6a_kcv2B>Z=penS3LL?CTE z|C0vEqA+#=kX+8#*05VdV(T>aibsVT`7zjTviaYRn#J@+8!-N7rH*#aBH+CEcK+%A z$X(C3xs#V^cu1ohQ_1dN@X~Jhb3dUvEA+do#D9Hn^D3~!w1f3ze~X>-$i`qe z8c$YM*VZusb_@Tf@kGgz#akFCcH!Q16Mta6dTvxtL;;%?*KETrmUpXK0EIy|G|um9 z#_!)rL-NRA9j)h6@h#gY=q!FC@1R5W#cfzW*7QHFQQ1(3x3Hau;JEh{b-#WPi|N00 zqTIyqJ=Zq@)%%0P-s7=_dpy?MBZWQX9(l2H5;Ihe_;H7O+}R>1NdtBBb9|57)KiCM zfj!|HhWSXtg6+TpW_@D8_Mup?y>+Cp;D3K%u>cNTk?BDJ-FYI&P{xVCO@)a-!l(!d zxu?V-Dp(I8BvaXwBqYD{XNp6x1# zpC<;wu}h=F3aI?ND4?tm1pcD-3x6>wiN92$9fH3T<d7WNMd`;$?GwM%}_Kf=blM?sM4@-}hQ+0=j z?avC*GwSb!|A#+6>yOXm{OG3Yt5X>?*!<{l(7M_kRdj_4M*sH6PRa|W4y_lf# zVx>9tW(&QgfHmk0E37{$m_RV}CO6`}Ro3b&1UiZ4KY4I_W3_twnA_;f8IrMSAe zx%m(K30;4o(fQ%m5*@ZIefm9*Y1UtqVjAPO5)Sn!4axeEbt0(oz4uP;RnSvM|@;UXde_2OR^E7wFLEX-qO8&*&J4q66qS4jspjPmZ^A+~a4q z8whkLa4~-DH2m1fy|vg~`9W>G^F#W_`Jojk3G*^PcA#TtXR_1MaWtRVPEp21(Sy;! z`NFtt=iZiOD&w-1>9914jSCv<06MmzV|#m|dXjMFt$b!XMWI7yF*>9Ht29k>Z!INO zerSQuxA{(2=N57bv|p(C{sjddu)-TD`v!>rZaE?tc!bC0M^BwR@_v>Y?_M;mg!|f1~!o zFthwQ;Vpsl9jU!~0JW@xa2LzedViyq#ipdipA%|{QtwFZ?E|R2Kv8rbwcg*T-5Wip z)DrXEk=n~f)w0}PJAhj6Z`59Wj;Lkk5*{T=??Er!bI;_SRximw-GrjSmRYEx3}m79 z#=Z=yrl?ctNKxQ=h)pjc4%#jgw^?V1j}&b z$mB?C86<_Wph=Gx%OKBQ7Pm-Yl3Ftd*56`1ojw&b@hx_H^Q1%P@Zd_==2W z^%J*{gRQLzMPk`*%XQYc%I{0MrpSR}Hu;J6d~om(6mfZft6i#oqSn<-4pPj;k;+pY zT4w)j#SCzv#tR3>rjmg)9|~s`oXR_}2i^i_6`gv23r{Z;4?M-E1FZt6KS!D_oXF`t zgk9jgH4Ik$l}6}`#k~LB$g%p02lLh=!DZgcSM1}h z_kT_!$0P|gdOVm~MT31A4@HlC)OvrTwnmT7E{A}EVWH`c5&1=nXP5bU)$rwPhxa#1 zFOReSN|f3vg6mr8x1woTKv>RuZT|Moc>Vp4)_4D0*ecHriqpOb=1DW&VL_oLD_#`C zkEqbfMZe?udCGtV?_Bi?I@ODvpUgK@X*`~PYE4gzTQB8{Cu6OeT_5Y^H8a(Bb2OWJ zVFblr-g43&F|rna2SsV=D7sI__^T*N%Y77irWSuAMQNdQZzHwv#*KI#9;BY87Jom5 zj?s%S&hyU7>m)Vly^9Ut#zsd zyy%+`vdQ!o`bsvh_~t`w5)}%46`SY$-W=}oz9HI2yI*GQqunpJ_R;QFSo>)A zF>4?1&aHjCdlq53z>9#Gx6s31NOP$c3Vq!d)Lkg=URQUyr|xv!h5KBUs-oAvio4& zy}<4Rb@x2Gv$~69b-Q&Jnd`c`i!^qxsJqB%_jz>}3GQBAcaiPxWp(!|yDzP~SJ-_? z-M!52{dM;uyZ6=I3+&!och9r?;=0R>>|RuNnXBE2y2~u?j@Mo0cXvMlB= z+o`*cp6ia*z0>EqBXtk;_oi;U?xWh?+-=!@clONqips+0XT}%w``DTBZFE@o6(}tI zemU*>{W9A1`=zv_{kkuqUB7RnUB6#UyM7;~9lhC|pzh8J}d{Muf z^w;m}>Bn{FH#ViUyOkp00#5RnM+0;`?9l)`p|;)t6o+p#0M=!i0jc8a<1^zMx}sYd zCX!!$=a=kBdQ;ZY(L4Xx_Vs{Tu}zq-&9lRInHkayG|Ppi=dDX-9fU!EY5)@UW_Hl> zu>V@rgBxo+v9>{-K)r)(C$p8L5}u_iur$gxC_W%EMZ3i9mnc{c4);Q6)UVNb$A6ke1ybW>w+>=oLPjYrANcC{nZPINbW zKs&PNXwum$wIf509-X~PJF?$s(b*~O$ZV4Xn7u|jveq})c|AU`|P}4I~Zhn8M80a4)$2y$Lx%D^eVqw?0m6yu*LJ6?0kuKFvM~^W?!ZqtgsxC z*;i->6D&t%HrLKsc1Z8d-lUy3vx7C8y+u23Wd~a}dt5tjV+Tt%d%JeNk{x0nZ9c)~ z4e+nh&O6w-&dyhB=WE!x#?Cvn^R?{kv-2+Pd>uPavGeuX`381wv-6GG`Ah8FV&|K* z^UdrKU(CKmJKxGqa$&xW&E(kpWi~PMvu{_Izrqf2%Irz)d_!J~Q!o;0p@%>SX>@zem1L|M7+oSyBW1C*Z`3<+RRzneP5 zo^IauE$ocFUr*1d*tv8|*2lE@y;*IkY@l0HOEwQrcHb%0|MlH>>E|1}@7B*Zb>E|( zZ|S~GKVQ}TW&M10_gD1u&h9((^RDh2^z)YPFX`v;?wj@V_U>Et^JU%F=;tfCuhq}I z`#Sx+se7w_zNmYfe$I4Xsh=_zUx-Rqv-{q7FF)P1NU?r80}H+GM^Y^&}C zt-GrJw?hc1x+U^==1?O?Qc1KL&4^9^X^praem z=the-AYyBJK7%%s&y3Gwe`(lHy|0g$d*ULhk?BVE+Hc2>zRRBL$~wRrDFHKJnVSY0 z-!WtjXd{H-Y(N`J3}^$|sGnZ|O+NN2$YqHj?6`{~6r{!qo5om?C%-#ZjVM3gW2J#{ zNnxW5wLp^;yqpF!Nx|D`K$8@_o(42Y*Tt?g5bE&xKN`9i&P>>F4PwmKoe@b>87U%HC}ZCno#4#H=qeM-h2iT>RV~= z@(_dX=sIW|6 zK4oSzoqSBhY@$C^XDSns^a_l>-C{P)Nd(1XjVSU#8RMuMY46dq>zdZgXAb2MQVH@O9K-dPUA=*IOAQwU( zwn5GZgl&+$fUpgc=ZNkUZyW>~%GGZfax)-o)8|G&*ao>C5Vk?C1%z#o{eZ9y!WGN4 z(CQ%7OXI!_sV=i+x49k$G!kO8o&+UM)4Z_`(t0R0M)xI(AhFlA0 zW}80y0bv{DYCzZqxe^ezK`sY`ZIDX=(OReFJ_|ieKae`%tmGf$sc;nAAh!d;Hps1j zunlrEAZ&x&2*@?Nmgh{}%Q!Zv+8)9XjE4Z{7F zJKbZYWfZ6IQ*^N&jv2b+ehy6=~wYniXlYz?l^k8~cSZE7HEUdgq*5 zu^e-~qTU=yd*zBU-ta-)w2H_&W6Cl+LuyA|$gx7csaD6rKtQl#g(y?ejs>;6k1}*H z=x%h8vmr`@)TZ$!YISK>2g7x47BCPbUF|&s<*4oihFe6#+iL5`xv+mqI z{C)w$ZC(|qauDYXii_()d>p2W1q{SoC}1Gwd;tS7dj$-{NN@Xv0x?qE5OX;ZgC3&~ zLK2B#CM7TsbFF}ZnEe6h69*mv+bk&yo288QhH6UF4iUENG(&T!5Tp>k@TnqFC zkRIonRz@)JW#Bd595`RoO9InclN2i#Ps<^{etf(^q1`aQY@~d7rgVTW?uijLL2X%pfgMGe`?>M(c;?mT%1RuW%O9L zV((W>LE;svuyY9=<#<#n%s&D|Er_k-^TjCMuJ1eDXy<>lqKavKle|`HymDbSIWk?L zBzt9LvNBkqG+!^-=M8)xB%WBIhOwoxB9=Pll16yDX^h17G9?%;XK)cs^fE2f z2;}0(BBS2Y)gs6utlq*R?lhgPNUgU}>Zk!#K}Hc@Z=uw&j(U>ZrBX*K8*@#Ao!F`s zj4Uf~G}5hT;ZaQmt8c_^Xj8=t*cEN6zR_a=t734M->MkUQ|h4lMt8ieoZ-Crp;q6B zMNtRUHDE`ysrp8Atu|HQfO*iS>KjqZ+Ek?jx?G#8Z$#H?QzZ{Kd{gy}w|ui>69uXc zyKJIhwK-!Gt*p%l*hFh<^FcPz>e_rIo2WW%KEx)fP@At}6IH2A)kj?OP1QGE_sv(c zdBZnf!zQXreN{1mX49tX8&Q1PROtk|Qk$x8M3rh&H56zXZK}QzwWLiIQ=qc6X(f*P zW3O>s_Zr6?uW_W*P9D}{UgP+rmpJaF630ua#Bo2BINlt3iQ`@>alDjD9QRX+ zE>=Fm)mZrmzhmViBM~bf8KYSFc$M8y`FMrhQ2BV7-B9^>k=;=Fc!Avq>kXb~H&i|% zS+VjFnTwT=NMo#gL{4MnBN7}dACc`?`FNGxQ2BU;-B9^>ncYzNc#+*u`FMfdQ2BVC z-B9@`_cK&JGFM~eqg>8V`6$2A3Ilw&nfbBuQNCoTd?ZN`3Lo*2L*XOpZzGmITB)O# zK6YI#QHirH+(5TB#!?6jtg;$>VL6 zFybj(*DocHSM*E4g_Sx|@@S=wR9dQdPvsS{)N#U$^AS&_jyX{AV#sc>_K|30+8jch z(bhghHM|U970|8G{>iD^>X5>?y3)PHQ z?7g(FOUBcy8UG+wGfK1N>dVc)Kl|FYv@wlq23bi^)4JOw_}j!gM&b{^D@Ech*U z9@35sH!*`YWw9Ue8X;=wm+hvy8krNF<8_02(eYv{us6j4Ie2h)3(rhjqJ8T7wZ_>`2 z*||zfDRm?`7XCQ+EqMDj?Yy0x+w6R$c2w&46g#EV@e(_w)bX+({!Thw0smSZ@h*0- zKC`dW&eyX;!eRCe+WAIyl9#8N$K>UG6PwtS**B}px3ELfLz^mo#6ZlxO*^W2#CX)2 zM+{4;c~tS@cgo$^+5Il+6RmjhyEzIqJ!GE>K0Zq_QbFH&{gTbu)9-hj8S`CjRqyfo zUDfjGUB*_ZH|oBHV<+r>6UXY8YCiP9sQX5a)$iAz89znQZ}%=tg?`_8W_(M(6!_iL zFLiG>^h+5Zj|Yvqx1SjkZH&6d&y4r=OU>U^{Zh(zMZcJ?%lgG+UD7Wm>!N;Dov&X^ z)p`A5s`m7YiF%51NSUVF`o$#O(l4gy=7{3V?-@O|_|JLE$JQixBN)eK8F7)gV-_O!-GK2W;m`9d8}3~~J{ ziP8`85d-7i$-##ctvn<0P6&k^Fxv*p@BWr$Anjgnvia`rTXY9rWcwW6!KHGS;e!3- zll6j-OX*fVJuWiwM|^;SyULPgZlv!qvgUI79)tKIA3)qv-82*B2l-*1y{&tfZqJK{ zKbyCwh|WU!Q_SriX^P_&Z}=1{fN9Fj+ih|y_CQj(>8{GE%l8dGdmd49(?@dr8DKG{7cUV0h&p95ZE$`g0bJ6DwX&PpjEN#Q@> z(oL8ui6fTPj3dHL+^MWY(YV(W)0TR-e<%_0o{Z`ld}>}P7Q`R?v3#9goM{|mxh zT-7uJff@bGbS7O-jQt}%b%vId=ze-+x-)AMdmOW95_@#h_n0I0nCD0t5e*+{6Ddp_ zgST~O#Cm(8Vl-#n5Ta(^o5p}h&!basArJU{Wpr|jO((`sp3eLxxkrwFH=AzuaxZJ) z`0r0GC68z_aE0UL32ALs$77`Bp0b&b*Htd*D(Z!wtzPe8)3tEybwTIitaIFH1bX%Z zY`S*Iy{v`f|7vP!uksWocVAbzSS41)B-l%)~Yw3VD>W2P$-qFb~*~woo{09^Mdf_C( z^xV;V6LzZmp|tgy?r)^6N4oc=t=D#cGi^QE{czfPgU;efu?KnPb8oQu`;U$fdg5pF zSl>UzcPx2*bhg5CJ~@gBH3^{rz*o#qN*2pxbIjzp45DKu$7P~9W^!DnnPV^|6a}zY z;@)B`RWOWWn`ea7k86bTDnAxlLJ5{*&>YIN96K%S(JXkVA>$;`V6Ked=^iR0^m$*J$KbSZ*_NMp1+YXqi=HIc`KI-c>*REmn@l8L6eJ%3!urxg$2;$;`{<=a)Dv) zl?zSYQdG#3J3R8$JnD5SIAn&|*lga|W@^l4YQY@Qnq~L>OPS>1iT-Z2>e9 z-d_Msgs)Z*nZ1(scut3>&GfpyyGCc+K0x|>7@ZfcYJ0wAHWj@gx_AX;9xz6(^oceb z&}IyaMh$2)W^Vzs8ABM_^t2gsyMoP(vDthpHU6NUb8DV&yQ}l>>iid;&VRwq9~6t# zkTS&xvC1q2GgHWtQ^agu@3)vuYnDS}KbzH8TFfRj3#z#vS0t5Xdyneby5^y}yR-Q2 zEWSI7nIea?f-j6&3>Bvp#(PzUhk&L<$X@4JPd=0$PgOPGS)JPfFy(P80H!&}ZRc}v zf*W~HkMG@mbdSfOC@;MG=$>as?>@R0XBdxuQZ9=o$y0{a3ARD%9OK>XhSW*MW2T0b ziN;aaC>16xS0*!0$Qn}1k^j6sx@RjNJ&*2vuHBQ8uBO6|nSw`QikYr33qnKmxn0 z@{!omvn)pVGtD`@UoJ#$g~Kme^16Uhk2!f=KvIP9*nZQ8Og#rfR&lk|w>Bx`s z;H<#q*^RHwZ?8w>)_Cly7SEHxL4RFZ z<48T;6&v)B7V6DTyz@`|q&nsG@!1W%SePa0onH|=AMjBDdzxA#padvAD9@dxBXIJ}IQBRKeNbyEqK(!AV z=_8=1=T$CsW6DE+zF@^BHj~QyeS4_DR<-CivVQw~eRIuMEEf8W=d{V#4(gGV_j2Ue zj=acQ{?|Nje8(fvd$7nBN(vPyNzOHKYI!N-n&;3ygL84W<^*uYa(1*2XJ4_ipSOFo zrxc!(vtzzIKnT}Ev2ndsyWaJqx*L;>&(ie}wxi-FS1ospn*;^+0OtInQD8FnIir9v zHkzQL&_qQ%G}$Ad^P5ND3QveKeM}HFA*fE#)Y`W~VVj6@CnUVctG!m)LpWwAIUaAI zer6+?4m+aD4aFoFOw{N7i}^74bcTzm8B4-b-(r+tuz^egQBoe-(Q}UU6j2*&sgllDxt`#tx{CWWc8SY)^ z@IbJ87XrhrF~4Dgz`z8i10a(Va5gR1cmF~#)mxhdb`L`^J4qq!Ugz4qr z4(}Hj!j2dCYJnk4PuqC!D+Puyy-D2R%Yrdx`H4Ifr%l|*Mv^B93=AiMlE5%DPuWG7 z_feK^7cdO>tpWzYxaq`POvEtD70of9jx@ts!9dT|(lgL=rGP=GE*CJ+bE$xVo{Iu; zl~wECXLKFQ&)@57X3WMD=Xj`@N5%NPm*0=@dmq0aFx?-%6r&AI5Hh8 z^6gNHX82w0)yCnRhn9x^pg(VC*xb}8s8$kxY06v8S63$E5g&%UzrJ_iej4XX?;Y^Z zGH?|}#vHk=jm`NwPT$(*e2t&g&G{-nE1UBbekPmq2|we_`Iw*4=6uA@F!_G^FuIc) z?jof#{Qc+tD(!M94blFI{4R+Pt>Y{Xe|$5)OM*`nJbQ9QLZz11D*w)xSAZ4KCTU=uNL zVCukBC3{=*RehR}yW27{ww#O&yWf1bh2Raj=3DcX$G2C-R_>O^nf|uTY5JO;`rAM8 z&bMr@YxZo-Cwxyt9EbP(;X0ZyTXTq<$0dLl@k0TmAwq+DLTQYkJ zNf4x|MreK_adlObaBDu|3E!nr;}!1tD$VF{J4>TupNKRqt=qisU1$KDaiek6N8_Y9 z_oIGir^N!!eOh90vQTX=kTR;fM78DOws5gRWIu6R$%XmS^`fTj) z^qB5$RUz)iN7l<5PxLO6E$I=XJiYG3fQQ4|PI8a(vJ(S34G07P_@->6J4m#1ubHH__XWQ;N*f zS1{i&(zkVW2BHlYCYa4<-o#B+xN;M`j%DyRnT@wyZ4Tka4#1LJmN7o1Xc5J#I8w$p~-p@|GpA`;Se|GmXa&BsM8nKuEW$Ds% zOIziZki~RMdWK#s-^e7I-fBqnK`@q2AkkIaXUuYB462|nvmB--`nt09vO=GNFlTvU z@yWr!9!1b+IRcCAbGw8tc5XD*8wWC)+&(YsNn8l!)@B^VZTC{8@`iKMpDtR^=hJ2v ztF(=I-(AJN?)G+YoonooX+9(W2L`Nvo!_H|yV>Cv2rf&i?Q`SFI4RSS*gHqt0U4pmoE zODo!9YK`WS2vM`{9D`7+7dKi@NTNn3&e#sOC3Pm=**>F{#KO*?2Tr_HAGeQJF75nM zVcQ+I|I5j6`2P7|ceKch=W4$j9x0CiyoS4#O2i9TpFQy4D<68*$y2XR*pHt(vi6df zzU<|n_loXRg8uV!M^=xYc+rdRz3*f~{E=Ue|35u< zWIS0}eP!DHQMntV2ib#nXV>4g{Q&GHV*#Idq2j3hCA2hr@s~K%@PmE{)~)?czvKX{ z-(i0-0M`GR{;vCB&*W!UlDYYJertvInXUZzdNwxuYsK1-()rC_MCzX_u{h{F_Et1( zR`TI-)p)6;1-9l&oB7)Md}$9Qo>ZC5F!HWROO)XW+q)5VWvLhrd|^vS;t6|7bc0_U zxw&Fh%|G_mA$U|H_sfX#B^2aq=!Z2Oan#1sZ zXxS;AXwwfZJFNk=_ahLS)|8WDsIh6$nkbm5on=oC`|&w9k+2a-5C#bwkpy9oun|cR z1_>LH1YwY{5lIjR2^*0F&&*vF3Abs6g!M>*Fi2RBBnX3q^+N!dfIj7$mGk5`;m*S|mXjB&#BMHJFVKtKAUuC>05-zS933|I~5i?ke!d)s*LfdY{T}l&FGeGgsp5N`(>M{ShmqV zzP)uCAErBm;u;xqPD`5vR)}G+Vj5W?3|34dD}=#{X=H^kSTT*`BMeqdBP(2EUDG4E zNoh73OBf_ma*)tyEMbt)Xe?on&}b}S zkkDu>VUWHM$w5M+v4lZFqp^fRLZh*SK|-Ukgh4`&#)?X_ z(O5}oHX2J9Bs3Z;Da}S>34?@2V+n(V9*t#6Q~KnzbVrz!!r;Q^N2#J6+TOEEm8{u=Pee@ z&v;f`N>nZI&RZ<3pViv{?z^q!v4slg{#XDlq-77`B2{n_tm8=SewUt<(}V8KonduGGKkWLxbY~u`L zFsF=YgE5R##3qaX|t8lxZ#5*ni*3=(>b zLbOYbQIH*hgvKZcgM`K?2!n*iC3qaX|t8lxZ#5_*h6uuC(t@KGnrlA!E(B_=;vip}w7`Brb)4)a2NS-sUF zV3-*~S-e%HaoVErSz7Z3?^zeOL1oKA>tHOTVQ%g9He2KmiM>rl#kXQ zE3a_9r}HRl&>c^~4wgV^x|=NK^|561*rNUX=e)zQ$9|G!l1OcI#tbupf*8QH&bUw@ zMsKyV+bft5{$gvP)M zgM`Mw3WJ2kzzTze#=r`LgdPJMY&_PjF(Oth8IClDRu~*<%&agt(imA`aHKJ@!r(}cfi-(ClXqIGvvE3v z!VwC3B1eRpfo&WQp=Mwk*F&fo*v9z~3P-Rdkt3$wp5B_QGxS$R)ZE!bF! zN25moTb3M-B|l@yy*SXTpi(rQz40rsY%!$Ind!s=PZJ{7j)!UHLY45K{avgQUJS3F z2O0PC6ysackdBAxh5^2OXkX>;xGZJ;N=z>*6`~^hrf` zo9vZuo|EuZc9D0BN{SzayblcV0VHnb4E-c~7Dw3LPq9~Bst>VOU8(b=^UTG>{yNFl06jQ zw918J%&lpa3&%QPh1-r{Gp1E89AiFBt6VsS&6rlX$SZG%W^w8ok19EJ8<7NIkkEKk z!XTmXsDwd6<53BNgdUG7I(3alB_|9nG#-^ONN7ANVUW;xRKg&k@u-ABLXSrkow~-O zk`o3AjYlO65*m+67$h_vl`u$XJSt(3(Bn}Brw+~E7;m{@rnDO4E!2Xm#&`=wWlcFl znW`gOs6b=wfEI1xC<^OXpYe_kUgKNIA%i20XC(}dG=7yZIMR4k!r(~bQwf73JswqX z@bGqu*7Q|cNN7ANxn_{icvQk5q4B7MK|522!+ox>Ee8Nl8_VL#iTsPsh9b z{K1JXKXPD63%z5tk12^I>vA%;T}d-`=>{1~YRAm1xIu;~l^3#}@S^%t0$@S)rvz~4 z)t?d&Zn%1D*`G2elA1 zEQ^@@7qtX2!}?x5fTgN$No<{F-`&$Ms>Dm&6c9zMZHXeb(;O2;>{!zhMeLrY1&$ZL zE;HH^VpDTm#a~VA!e6mfKw+!6DWGsuOcYRada(Szds~K9mCm&Z}IIsJ-0s{dz2hth>1Eucc3JkX-A9u;Wm-Fe~aA3%# z0*1r&gq!ya7rIcuK+^dF2IBV$7;clgyy)&T@SRs?o@I_3bMQt|#Va%a3V!!5XcT{m zj@7yTRracL{R#GJzVegoSx{_F`KQ>c*~^>kl?ke9jp7jFhm~#I!m^DgoJ6{;BW^t$ zTxMPZ-{UI_!yA~^!SH@~1JgQcj^PbV>+m{;H!!Vo;27S(vpmYe;B(Wnqxe_{zc{q4AZ4K|w3xgv)iLT(f;6lm_qf&DMY4ArFUHQz! zBdf({UMW8Fq dE}ru7;whiNhI{VCeC8XhRrN6^`pnWYGO>Xr)vL7@m{NJ6uJEGz z%mNypSwQ163kWy7oP)G50dp0T+Vbf%4Z{>mq9tEWEz9C1r%o-)A|^*hEn(6nF_W98 zmSs_!rj{UXSWbOr1VywMgls($!janka6pl~ za)#cs@j%Xi|JU*7xZp<#RxlAoJaJSJGoq9>D=!$wL2?(f@`AAtlD?Rg7mVv58H`zZ z!PtnYi;4o7G`iy-!PR|KjFs{&1DXOBVP!B=z#^;+WC~b>75PsAi?A|)DPR#+W`PAP ziW)<}qWGl-EK-lPdkRr2>Y- zJz!DKa3K#^1O}4Mm%{_`dj$-)$yh01$+6o_`s5`yo^G-uG-m@9*9#b^xK_YG#eM+; z6;}%ws34#a6{_;kfZ&Yhuqh7_rXf9qNWULBGx$SAO@Bncx?J(c?A7Ip5Af268d3cu zdo`l^DfVjAbdkN9jKT|Fj*b{0NL-ARTolSIMBaQ`vyP_^2U|Rs#+R#@4OpOQ9bU&! zVAIN1$8Zs+b#NU+aZT&kI<_OMFx4>>*0c(64xsqVSPtQu_=(%$;>0^;WW660H1U)A zK|vEg34?+rei8-+J@Hcr;RsV2CzWyL`m-r$AVVlRh<9K_RtQA}QC1b1AruXC4`^VA zP!y0{*CJ#iAMx=m**1k*j7bwo342nG*Of=IMT#W!r({~K?#E+J@Hcr=ZI}i z*QB)vb6|lR9?F50*_H!2urk?l7zY;kpkpDSCw__{ToXUJM@PI9NN`^cERf({99SU1 z{Wq{cf-p$viJxK!*ThfqUKofbeiFt&H1U%#2BL|dgfS3J{3Hw#dg7-&88kVd#7}Dk z-eD+;liP&%Ld`rj0lrYPj!lR!)Qn>jf^x5jTUdyoghv;* zmawU1SLSAE)j=)M#jO#PTB3_vBPg{5XD<5|*_HbxxT^??D0QvGO{*ntS}AeUq{L0* z5;vW|X$%n*3)D~N?r+H5*Tk01XJTiT1n*TXFs1TB0KBLXlz=9J63|3Y0>TaR=CQt@ zal?YfB3MchOBeJBm$!teRs_sj!h|bA<}G2`6+!csF!_?OO%nw{7h**9Eyg~HOHyVL zl>9(yO-WPrhuhEeM%A~HG6c8ow;5D!Im?(jj>pEMMz$%++ zf!j+=wjdP=BuITh#qjo?pZGA)p+ir&j5beUXbC>$z?M+9w(H#r`6^7(Wd}H(Ejz>f zZfwOP5#@5^Va{T~teu57IgIB2X5i85g6-SK+cv?jt8aoZ+QS--swztsd&B3RB2ptSF-t%L*&{$YNP7 z8i!a`p>2(2WvFWR6w3+>=k-`tU?AY;K*m#Gpwweof#H@smK7N8{qj(UOK}JAQUSx^ z9?Pm{xX^{tGmvz?fPwhE0*2d6v1|_OZ(1K|%s`BXv;qS$*Gtbp%(VgrV)hFdi1CnC z=M2OU5XHdyB0*->WXTfw%l{n=#OTG64hCZO3K)oa%7~GY3dGzlU?7HoD8|>gBRRfK z5x2~PzlTWu9y>Gm89ngvv-GPm^e?biW9VOEua^A%DtmQR@)PXU6-&LovZ&A+M{|=5 zSc<9R@;fqB6a#Ya+nV@_sri3>i#N6SgvBaM>*zX0=rFB=>lmTKvJd6h=on}jR!7l8_kfmhbre-}9JCCq zqiCbv$RR}eO@NIMLIh!OphOt_Xo72D@S_Q>g~5*|uoebCdcx`uKNHKVYQ|>Bs5{QFi2>^YGIJj zgw?_zp$V&nK|)VhZIQiV4<-lS^^VdYl*vIn$WIRNECgqAP&E!U4a(%e%ZHu@WpYrx z21O0Z0=V&dzXHPj)^*Pu)mSQlRiU`xEzeu}DCn9bU5aYd zvMgbW2Gz1GWpeV=vMgzeK-97Fi^h=;l(l3E(>6bvY!0ja_ zFRYEr$Q9m70tFP7ijx8gCnbRb8VMB8NT7gL0uPhf(YfVlW6`7zlMI#{cs|$0Wrquw zvIIh-@WQMte+e%<%hH$d!aBz>`3F>GB)nzh9cnVHD0ii%4&Z0;^O1j*F{dSJyWZ-U(L0{4BrAryYnEz=M?WLFIC{<203Qg~|BUaFvnl&% z1q@VNEnuKR-_CHe5U99Zz(55SUsUA!25eByzu5Ot{BcZ{%HWs!t)CfuO8J-HrQcLM zQ^WiZ*{k&pf5cwR&HOQYH8=ACK2TBX8_u&=>l^k<&V`2^KlhzXrbR4j7(m)i@3BbZh1Bowt0y=r8+y>Vt zLvp$Xfx?Jzo4kuKBHVTUW8^&GA_cPpr;_4h%wi7H2D_K{g59i^5p%X zpvkwWA2D{5ZxIFsO}<4K6!hd`FK?$%zp2ZFh4E>6UTR62p;c(-OmxnxN2iLhzT5Koj$Fz%zqS;25cn zfwb0oNwR3^$kQlmCCRc{k}NAV$zsVZ{3t0c^Qa2LOwm7Gs-RRg$Ok%|Zx`iT;|{gJ zqRJToaHcXu01T;o5C9+Q?F$IEKP$E(Gr;mqR5iqM8LhnUqn(2KO~R(QOfAa-ryxo# z%R(pDQ!UGaH%%=?__Fd3k_RInd)l0fB@yy7o-nfVPhMOUv9=|OSbcg@$3zjUc?Pva z5vvIYwZP*g)`rBEI4XT#I4VX8D2x>U1Qh;>Z2}70#4Q1ZTOP+H@l#97wx`ejnfxjD z;%+S)Def(|VJ+~lvQ1rKTjiDjxK)`X047!52#E4mPL}1*5>q`@HL^{GTYjfFA!3_a z3fsH|g(v>0rSQ*NPpsnFLTRE#K~t z{WA&FRpr(9Ye2QYz{)oPjRXp4Bv3#jfdZlgmXl=(w8Rt=cvCEqoUfs#N0g>RBT0fk-8 zNW2xtTdv(X_h+Bp$_XUyp@c~YP1$C4m2K2n*+%V`ZOm-h#^dnqtuM+!*p|L9lCM+S zWBTZhXR|cX(1NyA0yd?v*0w z*|%P<1lh0fx@pPMf zecOmP8}ntOw`|`Jn-w(R?XV0`XNse!Qe^?l7&wYHRT{7if}wUgas;uk!NX=e!|GJG)X^UP|%a~iwUnL>&FBV2~E~d z7$h`VKVgv2Wc`FeLX-6q1_?b`zgr>U)ujEHHX@-(`w4@DChaE-5}LH1Fi2?9e!?K3 zC+!y#UQODM$s!V(w4X3YScwB63=*2OpD;*h(tg4qp(pJZOPrdtp9~=+G-*F!kkF+4 zgh4`+_7esPP1;WwB=n^H+7hQG@t4vddZT*~Nuf*)z0o}grBJ4Z-sm2thEQ`ingpOw zi0MfH-Z|&?nHD%L<(1s0YBFxJ@-Y^u?@3ilj0Fx%IW1<~dJCL3O73l~QEGNT}v8=ZxhLFJc zG7zy#mZ7lA=US3LwG_U2%k!V|&~VAcJdH8SYG$dLmRVsFr>SR0~XA z;%#_HODvV8D=d93Qy!)Q-HygphdU%aO43cvG_K#%6+BhWsdFQP0vZ_<(8!>GD1+r> zSq3dNgbcPX1CdoO?8*`d8-*{)U&71u_5K)t@4sYq6TXvmtdec+21E`%FO^QO&oO|K z9Lv$b*2@BlRxHUTj7`}tu|tX%^gM-EI>n<=4&{i$oXMk&`@{8-{Bnk8dN!|gx-UQE z#XAGa#N8(tLE9|8wL~zgMpGviI|;_Sk_wO2PJ(f-q#0tlli+m)Iwpon@+2`FKbDg@ za%hU=-K}@Z3qvI^zckdml0`1_kounjmPtr*qkv@w4(8_zSf<}#zE{BYJSY8q<^MGA$r53Z&?HNQK|+%(5e5l8$&y&Kp|A48 zYq|j%I3d(B6-~-SsAVdeq=`@jlMl7Haqk`AC*~qIeu~ zF{L>Ix6t5+SsB+fm$eNn3bjFMfk~A&0(Rq5F9Kjm<%9rS^vVDMPwS!|RGT5quq4o46uyaF0t&kt2~=WboRJtV$6NWk^E*qQqxYTESD)V-LfGOiZoN35%&=k}a_N1Tv*--|0?!vI6#fjpHc$dtO97kpwwY%I3`8xALsQcr2z#V) z?5SyB`76~l$dVQ@xckDBrIq_jLkYAjL75vl3>H}CM-GDpmN}BcV1Z?xFxO z@i16mAZD)|9*FTUSUm$Vw~a!9ftVBq=aqZ>hrDthUU*UiP<@BtP;We`tMkimJgKYt zin?)q9ypI(HB>S?<%C zwoTM26z5*CXyJAC5N3)+3$wGEV6kZ7cJ>u47A@>{6ouUrb;fwBi8|fh5+w#g+|q&t zGTg?31tQ$Kf&~(UK|)W|8RM-c>U2Xzlo&{GTLl(KaB~F~NN|e<7Dx~V2|ZEgp46vn zNFu`1B?2<+q@u(?g8D5+ox&EQPGO5tr!Yw9i8|w=;lg*#H|E#zxr&*Xov zw$W$uz3*w`PoWUg6MsJa;`HLewBn5r&E$Y9*O|MINx-+#wCqaX%KKztx(0kYS9Haf z!kprY9~kfCt7Ko(q8^zHA83lZ@0f9v!;8P3U zV&#nhcvD#-pb7W{Gy$K0=x!IkGPB^IbwN$aAng(e1Wit&T7t~0<@tBFHA~%6E`%r1 z-7fyHb&XQC6v4PG@s0T!@agpMwn$kG_|yWEmw3CdE+{2aSo&PL+a`go!gA6^ruz;K zcX=E{wibgUVO$FN)CLPH=LEpH$}j;<$S0r)`2<86EGNq{*uO3)g;?0-lMQ|A%6Lis z5*}2){e$`!j_!4QC+l+sdai*Z2M_v^TT*lO1_TNObD1|cT0#P3qHHq>%XaY@ z_(ps>a_gSF1rfFVSU~T1wh~-$)M)&L)`X zLQ^WPvk4}`P!t%~*#xgEbhcrQ>ultV?|vR2>Gvd6gZbs5WKSBS$o61S~%<|Gf=N0 zEG%{uU#-V|-V45K6HG|cp-VR+A;R!on?OPsI<#555{CY4mac?BLQfE3zH9OV8xLL> zBs3npFi2=Tcwvyxc<{m?q4D5_K|+rQAHP7m@U^w%)hv8%EqOF+_~J$8-Tp8n`mS0S z61OHSfX00m5ZF+i^UR2YvelXqMZst1#SE}o!u(IdCL64lWr53ccv!EL|JS7#3*akvDPs#x!*1HZ%3)DPBXl)G*_Y) zPKtr*Q5Yz`2`GFMy95+=WjRcEF;FTLvRahB$r@ch{F_6&e$68v%r18bx5mK$A#BA> zEIpjK^jcl}^wa;_|1_M3Wz!c;hkfhA9urey?X*gkJU8xwK4uQ zoMvq8o}Pvi7|we`2b$&x1l%lOpwyp+)8XNk{AoCW;ojY^^Ep(UJ@@MbhQlx7?)chJ zxX^_H29nMfFc802z;K(S6vc|{QOUtd9#wu+kP)pO74?pvrSH^k6^}}B2-B^6d1D zT1eLxiwl^pD;5_ph4x#?K3$Q=`TFW?LE}QWXTP&qSbCF6P54XHcYDo}TKdhBTKdhB zT7pK-*Ux4t=wnumlS1U<-f3%EOw~>?RmX~{%4R9aNSX7dP^BXJn3NQ%*=^aO-&*mi z#s&Vk>L<}`jIr=S5W~6VYg7fYh{G&&fsm>dFH9`Z!4U`kPST~~)#;kgG+inzD4vrV z7-2=alP(ojWIO3nVMVf&E)`Z7Wx7<#GwV_u1Z67u+S;-f!$NVb!Tb|wyQ--^$zIh| zpJK0Ss^4X=78?8^d-WqM(xB;UY4uA>t-892x_aah)YT)8OdfG{^#`V|9)<_EP&30V zQ!_uYn$^{7XgI&B1~d-Z&AY$4bYGWNda9@^x#@pm=UG#ObO-8cxV74+uJp=gD`!}@ zY3Axlj-TczL)AF$!WgQ?Z5P%FD?{hU;w?9cQ1!!GZj_R+ex-C65&vhay&^7AK!Ym% zAmKlCPLtCFRxOa~_^$BTW^I9BZ@J%EwrUGxd&@Cv+4h!8s~O%f_=v%-0cJby2b&g?G9WNwTfyDm2`} zzzojX?S&WEJ{N;$cB#xfKjUGCPh35}7Nmajqw_x|ag86>E?jpB#C2Nw;@Lo`=bxp9K7fbzPCjORh}hCt2k6y`qx% zVMe4FHoovlX#Q9mIx+R&ZQtcMq1I#T6`C{?5&D+xnNu-1IlBG}zqvO!_JO^DC_^3@qAmZH-|q`qBlDNw-n;rDI5P6Qb(a#Sm2(qt=9|!kBbDA?kG` z)etS)M*Z4ZE&bYA zE&bYAE&bYAE%4B%O22}}@%^kSXn7q$3BsR?t4B6YokDC+o#K%Ylfw`5HnzvNrN6Kz z=s*+OUoNKqRW$5dgNvHkHBx( z2#9kx3Zv(rE-ZbJhNrB-@7KFOP`caw-YVT^H2f>;Zucu?yKui1-tG74kTHOsfcm~KsiQ5X}gS-us< z6zfSZnwrwBLqembgh4{%KnjC|b^heckvVRV&^VCl2MLV>DGU;NGQP!@jotT8E}%RE zh-%cgFo@dVPa#0qqJb5*sJ?|kRAXR;K~#@{HLsTDlvFq6RJLJf@;UG>+---_W(1|w zptKo5VT&UuY;gpIL1{CB!l1Ng1T86`0fvNT1cgCDGlIevM^M<}2nvIQW(0*nLeB_B zTlaj97c$0hXw-iC7xC<}9+{OC`JF;-w?QEe@rav~N_?9*L@jX5TbejTE%44;nm9x) zaL`-&EuCWV&t@oM{-Wo=KK^ld1TlzKmFD6>GulPoYY*O$=UFv`t&w-#8p77dyRb!h z7q%$x!eCe<@4{eJkG$LJjHZKS>LMjy7boPb+_Yrnc1l+6Sjo!WQ?hc$%L3BV=HUucihB6z{!Cn21l{mQe=R>D$TD%p zg#uY7&ThXzmWi|bE)ZjPz}i2HpD*A{oag4W63(kcK0BE>*DgsNbs?ZfUKZCD=*z_P zzDwStRvI370PpdE2PO}=_vkAP^7^!NFx)b4xvn(qO6aY@y+`lfmG0&}?w8cvD`?P4 z!*I*IN9n5t@A2jR-s8(#S{EI{wd@y4=`cf^r(%SmWmlKg8(7dL>W7wXYUzZbWt&Pm zVQAT&O1c+{S0TF#7aBD$3@$WEUf7}+C=4z%^_9ZlLZjY=!G#{>UR={jpKIC}Kv(vy z0d!Rl7KX+ZJ=k)_t}%e>2T?r+@Nljv;>qZyne>1{j}mc6Ru?5p7(8txOBg(DBum($ zWC>f8EMbt}BU!Iekt|syNZ8;{ zaUX;&N|vxi$r83GS;8QpN3x>J{Cvt0vX7)7YzMi_ce07uQ;-KyEFAoDym6UjG~t@J zG%mAR;GMTLF0)$Tpttn9%rcsvO_$li(gR#(2t(4-EPHUlUM)G;O>eR$UI%qr( z6f)#YTkRm!y!j@$5Nh6hV|#>}H{Vzvp^&3jdk1oCo$~3Hk8OQ@hzLo?AVNMvUZ9@5 zzm-zOv;GyZDGOx2^;z=dRivacCzI^rQ5Q`jXI=eTtH@OSTAvHVoGjY4=BcA%;TUqpC0RQ%OeN7S z)FOrExYD=D7J152xvkYza$Bpblhv5pvdRf^QiH|ZmIThLXk%_m^5#{v3%M=Qrm2cH z=C-)f;84q+$}bmt-_Wlt^wr5yX6~0KT3J_SZhulTbH8InJ8Dp7?xr<3_1;~XIqz=N zUoYL2nfndvZq&=*A2u_`kyyhXr{!gv^P#<|%nF~%ppVF`GbXAC;sZb@R6pWGD1g4QEc}Mky({nsb9P*;u&dC8@$tp3SRjgy9yf zL~ASzx1f1RsxaJw<|V1Za0_}~QWIh}9G9Yf+>Am(<0MHLK|H2#^eMgL6L zqJJg~5*q(Z7$o%gXC*zk(wClWk_s}R5Y;3Vl38u?d%_^9$s7xVs3xf(45E6H3eP+} z8D|~EcuQjM-t%e6Vh}d>$-#=L^L~r+u72E6Bk#hvqek9^aYsG!9zF3!-Ze#F>P93% z*rL1(gM>!jg+W3i@4_IVN8aOrfPwA-qIvZ)dB~-r9Ww^{KRK7X=)25he(=2Boi-LLQKUDpI%TG;t5jPs0(3my)lo%;CG`ggu&@XT?m86J?bLl5tz!$8fzn} z3uzrlXw0K9NNCiBFi2?Bg)m6yQ5R8THR?hd1}-$}LKq}8=1~|VH0nYaBsA(m7$o$l zi=eRxJDb@m9YgLwZwm>!TPPuu-WC!00%zG()d}BM-Fxeq+m9rbq#@_t zG*}IZG>Y9BbTp^5Nf1W?-#QP+8AqqW%ot|IAK%DF3J9TK;@BceI|Qs?APpL65HNhd zpoK8nFbE9-(}V~G6Q#kxG#I6EfPDY|TKlo~xu>3eyQ(|6>0j!ez0N-StiASn?X}n5 zX9Q3)!6OtCrUsxLKlxGj1M{Uipk{KXGi)2!#r(|<3r!i&83WXyLnzQW>pi^)aFl4W zvNR2sqS4}hUV7lvgWzJ7Vz7~)auROC7~7em(UQ*%@f*SYfn5z@SF(YoXmI{r64-^$ z%`vorU4k%xEwc@ZATU!iizylefs;nEn4&=t*l2~oZk&4S_@q;B!U7X*Lts}^C>a^z zq<2dLyI@r4#1%BT?!}PF6Uhs5{HUV2_+>i6`^2hsyL$=b&sR96^WXrZpWY`N}4bX zN}{3(!=NMznlKDXqMixEpp+G0#w5Y29g1=0lI|Ad0=>wucM0-@mgu~h#P3Z^eT)=_MQv4}d> z)<;OpGv|DuNMf7`14R(0F1{$`6}hf=s_r=F+(t6latR-?Mi{x$r%ELZOIumrZHQW=#ER zlRgIcxNpuxxHZaAvGPv2QRba;qs%+yOTWA`>fbMs7w!V55sjY-h6;hh6AyN5g~WAy z+1#1uc=FM%u;9Bpo{jDt{MD9zaeA_z*F)dJkfi?z$4Cq3phT1G{E}#r2|&-|!Y=`) z!_naTE}K)j{lc$I;K=*^eje9Rd8dr6^iDr(an*~@^!t3A!tsuY5jYm3!r>hw` zN>W*qQ3E~ZPutSjA11!uLK9$FEWKk{EIqZ+vRHa*qh+!5bQDlLjG8C3tgw%X??VTS zf*t5fvJw!;>JNAf)FcsEBM_0aBOuU@BqJat89ypoCYsS(zJ9VAO%RBrh6#;>C)=)H@0Tko)(()r4-8Vh#k&OhwZdCPvbxBtx2u7o+pZ^XZSd0;K@(OD~Gp!I4 zz_&bxM>cXiBggrpxK&I-kYuq+(>kbWWfb*t;qcSIRZgwTqbdF?x5M+ zwJbMtJsw_=g0Q?6|4~Yh*QZ9iU1Sq73Di+u3*1nUrZ+^F6S-w-!BV5GllE$$i!t_ zwjZ@i_kj+E2%}iO$LS!|2|+xJ7MAsaaNEP70^A$?vOdn{cQn;y{Y!z zVL%~?1`!4nl0^){fI`V4#`&`5$rJ$aLNXH|3{*&F0)!Q30)!Q30)&AI$xMJSP@!Zd z5Yh~qWoZUUAeZhHkV*o%gaN5!m5neUm8`N62BeZeE@42bB#?V{X$Fu~@V-iKS;|4k zw4sv-$|q7t7&@6qAz|obB87yZlZg}(hE66@NEkX*BvMEiP)MYZFrZK(g;o(HGjj?qP)MYZFrbh~Az?rvkwU_NLL!BP0fiDNw2B~^ zk5h1gLNXsG3@9Y?al(K?G9M=lC?xZ7!hk}_eB3I6L<;G40EI*f2?GjAkeo1}kOavI z0}6>05(X4Xq|nARw^QbzCm=l#%$1TK)>@*|$+<~>V1x$rQh1X5z&oIt-bs=lcn7r8 zJ4x~b?|_1Or#$%q0iJW3{2=LA8%%xx!q5XwBW*enB5B1YMTBj|B+q^-n=m;Pzluzp zC^Xi?pd<>7Fbqec&elf zFiq1$3{0RKfQEURLNSM~0~#i3HFtc2P0wJihha{-06=F9P=gMkKnL5$EINb&oeg|N z2I(0kx^|U_M)N{S&w#@Qvw_c_x&a$A`|kWo;10L-v62no1Pv}*#pS;c8)N7nV`$Se z2*Lo`^bCR|6cf`k2$E1tOwS+)Y_visCaze~k_I+9PxjsEF#?RKoiiGnP{%86s5dRz}tZg(v6 zsM?U23wH$2!z2Fl=ui>x!|TGJ_6keppf_ogcW@R!iqiu zVL&07SP}*lN_+(4ra<75c^w@Kh+!i&M}$HOc@T-2QV|Lv90SxCXhI=_Oh-2cnox)! zTzLFADXTeu-nuM_w?G#I6iKF2gn=T7r$87elK2UPfg*{QKo}@e;v*QB1@_xGZgebw zLgFJ3R`d}FEBXk80fodzAPgv!_z2>r(3ZnTXu+*ANDzuaX{OE_p`sd-IX|Holyh{1 zK{5G{F3lt>E#5)XlZ#6uup)hw3KSmG98kGYLg(5RC4`&nw3 z#UdZSP|wb?SYH-PAE8Ya3+YS24)nc%vRJIm1h@6)xoF?4{nW3@tIVOxeqO*2z(Y&f zEEa;GqHGomLC{Y&i-jOq44cJ55X{92p_BMQdCGsFy7Sry3-LF%vxTr=xe(5v${;M* zt>K49tE361D265r0od_IyK)v;EHMF@pK^Z-vaRxW;tlZ&N$*A}ej(|7D8(-%eHbN) z4pxu@k$(cEc+$l(N+HcGx{T-${4mG5J?|V&$QO*rVX$0@6G#}0ec}WX26jnS7YHjl zfrP=>Cr%(?F!m)*AUIfX0}5dB#MskwgcvbnIB>Dng(Qsu8u(bD5GG~}hfz}~2kAqCB1vq5Fi<3M1qlO15=W3QP$Y2!2?Iq+oIvA~!a)l% z9YSY`6R7?u>KR(7Hwu`cg!-a@89JyZ3YejS28yg7nmB>9ouESE1QJ$s0tqWRfrNny zi4#Z|s8HeriXZBnz_U+fE*u%ocEJ~CoyzPpgo@6fnm{l%6ErY_-Y^huoxv!nywmmW zTe8oHcgmeX-m#WCI)l8kiZl3SSQBm}hojvNE@1pZeKVX~H4+k;cZEde-AJ+2jiVAU z!c2ILWK#W>y4t5e5_6Un?|>+g76gD6F+JZB-PW%xR7NPmnxQ#OMJ*O z63m4xBb{8xGLnY?@L;400hR|tW1c+XC+h+EKCK?OPz44mDI6MB;el8R7iW$21I-i; zO{?_-=@bratMEWUg+t>iJS8N~m0W|6*H6}CTnYURKJse*vMx>`-lP#JIvpW41x4i| zR>%qu&^24jD>&Gx(rxpji?#e!wKRZ=d`=2+F@Q?2lVE$k8^KO|?fGs5!$gn=KhqQq zE_vnzi{Q%W+5qY)I&s&Mvedp|M4c;6SQt&`iW3$_(z)VsYF-e4t~P}KwVfu737)wwXS!SZ+fN0)4|HZ_`MNR!X9My6@x#j8)``-x!XqM}Fm%97@;< zyBY#xXRTycLl9yfU?_|So#MD>)E#MvU%3P2qj%gfhP&`~s6~h9u0&)~WPr}N#=vJ?pe3Q3kCVL%~SOd<>@lq@FM^ok^qp_UTi215nHfI{0+fiR$u zgfIvL3P}KiFrZKpzA!0*2rUGg>#Z$d1_fGRppb+w2m=a9_<}H?kc2M?0}3VK3kkQ= ztnTOfl0iXDEno%(!hk{&z90-JB;gCffIze%i(b3q`L#M%f0Qc0|hFd&s=@)8E5 zl2{vIK&m9xHn{y4&?3QNP4Gj@KJP3&^)zgZ;;aq)kmv@&(CM79; zR3|_o(G7$Fg+wI5hxp-sYo zLZTZ80}6?5APguZx`8mDP@)^`u8{521khfP3#f~gc7?2!8LWX6vnzx%8PH4N$*vII z0oC+QvMYplKs&vY>P*Crb?+QVz9De9iE13AsR%Mo#U39QAirEuFGgCTqLga8# zuex*DgkB*^Hm+AshPZ}_)U^;C7v<7Vwae}~2^~5AN-Sx(2B(K>2wu2`9thV^OM1<3 z)`uw*xFgg6vxe)9wYak8)rjMMszYP{NKx>3qH+ntm?bKgFpO5BatXsYB`TLNj8KWn zwTl>u%B7YD3ZwWFR4!paAyK)60fj{65(X3!l}i{nAFgS{f)MDwi;zkf>b3 zfI^~j2?Gj=$|Vdal&D;*^%Ip#Ee#YBl}i{r}Z`iaV= zmIexm$|VdaBr2CMppd9s!hk}eatQ+pB`Viw{azJ*iD5|UX@u&q3W1-%4}>C8HwtJ7 z!>9|3Kpl==0X|7x#OaXA0*n$U!gO^&+X3p9I&3}&x4Rg0=sE$NF+dGEgaRELzh==P z6zJfjOp6YoKxZeQ1|33y&MrU=I{NjHRralnTuA#?uz?PStq~$@W2FhmdVV4It>{W) zCEN6uUzs;svTua}0F0sCw?YsG(C%9y2%~3@6(tBmXO9&n2;)Zg@e?r!jA$ND1~MtL zwDp0F&XavBdcHg(k4#q0VG_6Odr=@4bYie+P|@KU7DKQ5tf7Vnr~2m-x?sPbW+u>B zVNhR*DbsNV%xDcAXuyol(2)krh^P)VU`9aoWG9;vkeD)BKcFybbp>HXQ$|?Plo19E znwT=epg~JanYE^gDWmlR3W+HrtZ2#zE1ELGfI?!*2m=Zwrp#K?#FWwc0foer5mq#1 zgcVI0VL%}sZZDeOq1xM}|&^o9M8go+(W6gQz_M-s(ND5Re|9Sv6y3I#xe zVE956x3#Q^QKKaUMG})n7$}k$G{QiU#GDZZiX_I2Fi@n#l-bqn@-3L$GgM~E5)&Ux zSz_daDND?JFl8l%zRZ*%G@!d_WD_Ri^|bE$y;~27_Q?^1+tus1e}s47yZdRy797F~ zzaMTw+=SU!!H;{DIVhBS2Zz;ZvAq~OyZ%KgJT0r;o6uqE=(;ak3iccz6)Uxq{Me2 z3@rbEd>6uiLNW~}3@9YiaKeB> z;=2$A6iR#->pmsE3*8-{koYcy0fl55P8d)~rs0GEg~WFu3@DWNF2;R=j!kC4ba+HP zBxaIOXa{bsHTsNDD2FjXjW#0`x`C$}7+ppvR0B^nFq-WA%C4ky1J+D@7s4PGD}xGK0dp7!>aLHG@JZ28G}8 zFoQxU24y#(W>9oWx<2bdR}3UmPXyxReHX&5?-Fvqwr!UWwn#Z)NA9b;Y7B6fkEGSn ze5!#9B^GPz~Eula>cCgf_bk$EItP)pfeJ_NyT z*j+vZK|k4DJ_JEI*O~g!M$Frl1iNJg!#!fo>d$7 zi!-TjYj^p83~&n_8;6yr32btc15ati5}%YD2*aQFq=XfHQo>;P6Q7hY82-d3B@BkY z#3uze2e&x!N$JJ{h0!>6TCeDnvK~-Kd{V-ILgJGW1{6wsQsWjEw|&!*g;aBccVHon zHbSt+05!gcI>)lX+xQ;p9?J&rPU>(&!s(~<`5x9qPP|jPw4g}hn-T_!B%Uc@ph)7E z5(bJSUMXRqNQqBsT;w#eMn@JXBnu*h0fi*0Mi@{?Vrql|g(RXz7*HsQr`ZT&;*-*p z1BJvVB@8Ge@ifAKLK06S3@9W%DPcgN#3z*qBV7eJ5iQIlf~xhw59sk^zQVc^Mo4BX zgh~`4nX?coK4~&*ArySEyKLT4?vwg7z0Gbq@+;hG!x2d;iL24N!!gr4*cB3Ypz{tq zG`)jeA)DEBWOtzZ$k|BPbksQOO-JF&?*(_gf74N<1*?J<(KjU^@l6Rxd{Y9fZyFkN z3q%#!bc7w~HcU%Lf?`<4T6)K*oxomt$EcpbVtU7@AID~o)J;cyL^hj_NL%WcK-=M_ zqspUt(@_Z4(eDYlH+1iHwJ~f;0^_VU8Iamx(~%sV^XY0DXGWqmj8xyIBZ9?1q#yet zSS&;uXC@dXqPXdZVAu$F9}GCyO-IMV%z%11@cnSpk&jChW(Eu=1pVq~1_TDx>c3(^ zV9=`mD;5NHyiZqg`~L|HE?xMF#f7lxD4s%aY)dvBLCP>KaC4INZ$OeykWvQrb3PH6 zyp|IN$1s_*5C+FEiK7z+$1s_*5C+FEnX?cE$FOA10y*>3CP-)E7;>Tm!5>QJ7@jgys3dagrclY;g)mSgnYj=KiX<^p!a$KE zVoDe&QZi>TQz*w+)21XFfc_Qu zBAK%gR-CgCR-CgC1{9Jx3t>Q^WX@uzP05^vZU|6F<}8F2=PZO3=PZN)g=Ee`7*Hsg zv&giGP9Nqh=jxz@Mmn+P+rXL|_~x6RvxIDbuwKi_*nU5s02}#;I^i~=9^#P_*)5;7 z@R{;i3-6TAT6o7e@&5hZg?}ePa!fGB%&;Az=dCbTX@UM#K5nt*8 zBj;oS=smjFykn%Dcbw0|J4WVt$GJVcV~ zm0X}LNvc}ZaSwYyK%gY!!~_Ha(qkkb(2e9GASKs&4(s5~Pr5WlC?k)^9ndY3i&a6c zNF@S5rAQnCK%7Vu0xSoH#yoLW`u-sGaG;V2$(--=W{wVH(jaMI1b^g&O8Gu}Iv%T9 z4osi192lw2XDkOs^79U;-A81Z7=iys?Ylv02 zhC&P1(B^s_Cwvojr+U0^PoY?|HNO`gzoW_d6&u3IPavfgIl1C4Od`28SY%B0LWX>d_TcqXwB1(i(vVnd1RykXZ^qgNzL`24)qX9R;pQC|Xd|?}yhj@<0 z^A1+-;5Rb(!8c;?;-l!6N7#M8}Uv$D97%7iK+ z3cEW3puNIT8a6gnR497b1`Z7fDlsT49Dd^)#;=?!041(?8GoCb^Lb7{@k@#LNaA=l z>f!Je^vTSh902+%#GM?# zX%09?q?UiQ>W|vs`43>^aLj{N=ZP9xU5^%9*o$YJ&ip&Vh_rQk$86L3l%dvL=NWr-GfIKSBg1IAQcDw943*OokmA_{QIa(F2X}_GCYevQ1Lv=Uc*xeEH1StLv7)3 z_#BSICvf9_sVzhY35y&)R?gvL=ZWTyy1SsWR2fremFjMpfA;Ba>a0@TO`Wy6?p~+P zdfwFNW^;5}l zQfOvPjcH${N+xs*w}SRvPg81IH?2wWil8Amo=dH{y&(I1W&HM9wR-baa-DZ>?9~*U z)n*Cm%nDCU=MR1JWAl}K5~gDh<#whvvExO2yn-)S-+ha&rpadi12yu|3m;~6PRb_c z@&y(;pJa6$GnG}e$`Pr;Ni(V}CRMJfH1JvO>u6s`4ncQU^M|W9iK@p!-DHJ#fJ3i} zGn4YhO{_3eo6i4iVF~Xz+#cZ|qeam8zH~c-rL0q(_%@KJ#Yu6h3fmZx`6i)Us|J4T5I(eglN)H4fCS&ai{~ zKy8NL1GT+c%24XScSe()BkzzVW@?=-wolE}c6aejB6P9~*}*9|e1r`?_&aFuK#fnf z=W>Wt=VR{O^>(){O#xc%yvR4ln!p%S*-=t(EZ_ee&T88S>p0vkKlVb1wRn=Q0SM4R(I-^}-4n+HrU%aZ=pS?g_`-7g1>J@s{7Nmg+F+?Z$ z+MdjN?U?e>k}-W12LZfWpRDA6E3C33zkeQN?z~?l3A2-|PNt~jS7VNLQ0T+#{psh- zY4an(GFelbM=3+yrz9*>fi!{k(-cx73jslSU%kWTD*1aWb7UW0f_=Vzhp^9eEb)M) zD(31=D|~RIPQGui#PeT}4vcOC&p$w(?_ne|ckxptc(<5aopjC4m1L z`1x!0L&ta8k){C>Dv_8M=P4uH+#Actk6>wG1Yu~hGldF&Q0D=mORe+Sw}}9IfzChc z;Gb}CUw_%bKV7K*DF=VJQ2%}hKT)WEpM!t6Q2(TZA6K}N>`xu=iwdN~L0OQSp`G~C zCgl>A2E9vI`is;yj-?;sxa45zJMlXhmVQu_nXvR2aN7t!O9aF4^Iz7gP0!1)at)`y z8yslzL1Yf9v#2v0cyES3?H<-f!A;Hl&%Kgt=D)6&+_ZGmE0yN#tN-GS?|I-IZ+hTM zl4R1%_s%IdHK8SEe+8nxBof%np-@z5;vG=zcnijXm@kYZF41&Eg! zhHrNf0_DH~Om1)H*mRrW3wBUiyYT~EjJ;aaE7-%F$?LdQ>@kA98FAd)q~;I>2Su>2 zCOFcp;Pp+kPc;t3L(KuLE>~Pyb?V|(jd}y>qUK4Q6-b=QAFT>xC84r|;e8``8~Qn}cX*T>%TOC>xJsVhuKW=@&G zxhR$yGS3X+gAm7*8D=Pjf~)6%fuOenZYiT~6K?9=m6J{ekppJrX`9d-k`U4{4e8jt zkPM831$7B4<<#XMgoV>A(U0)WH>V$Q#^{#m$LMDd%rAMXSBOm=>t=qZSBTBocYXQq zzWJHgz37&!sSpb;$t}U$K!Xj?5y8<(TknVr&d+<0Q!~m=;^)0S()4q${?IFL{nBrJ z_3LGR-b({f&y}BtgCDk@ydN1DyME!tfxM!cn)w?dY5(@W-TC6v?>+U}KNk0>z^}g^ zNIOt|JsXd?DPD`5QJlI+>+zj`^IZAPfrAs@IdE`mHs#=g?;JUJYklXS$6EP)(RU8I ztd;7r0@6{J3DWA$pS|mhJiaY64Z(H(;J{=p#Pxz{2r<288q+I?8biD~TOFvV<=bK! z&Y7IO+*{sO{^H27cX@TzntkCHZhiAZzjEJgXT(wzSQgbBjfG|11ghWZ8uT3XbrI{= zM68cStiN{b#b5cv%kI5@f5{~3#VOL5Q%aQNY^SK$O0o5F_Mw5v*{giKImp=?Jvp1R zr;mQ>_y6H@?|JY;tGf$>6*M8}RtJMV*&5FIHyx7b7kr6F4Cnl<+4V+s21dg3e8MVL zbc+IdVZu5;Iu!1qaC6yq7!&0Z!+OKXE+)Fci0FB)fn=>|t2NNz{I!qt#UTD6F5^9T z+q>TJskh$q_b1EzwcCRKJ6L}W%a&Uo)EV4F^TT}(@arQ%zxmQXe$Pk$?2iu1qD*0; z`ClJN^xQ%d`6fTVz$Eka_x|sfzW@LG+_#oY*Ve0~2EAaj3G@c$ysfn!w+Y;~W6f(5 zXkOqXJa;B?7a~3-c*+fZ;w`*3VC-?*^Ja-)yOUg)d2U#q9VhJmG(^=BMx+%{}M z9@!w!Jp0wJZHdZn;m~g)ajf6P8uao^|Ilw7%?otsKRmDnnLq8D;Gc@~(YM_3SMPq{ zH|Bryzm(*}oTK^uw&fTME@twIzA642B1!M~otJ;~Yo|Z=iLaK$Oi=BdEGBQu8rR@r zCPC1HhaF5&Go92I9BebGA86jzw#1+Y$Dl9jlleD-@sMMLJowpnfAGQI{?zTazUi%H ziADeI95E;kFyH#1-rzE|!W1Pi=$%NjaRhzw*WUTEcfRZQ-us?1iI3BhfldLpO^Y5G zN!`(5GJ7^$l`U?w5NY4)HIc!&Oy^q&f7^t8a2DydK9}jYqec4o|NTD?yyU*OzT~xK z7Afvu8mI!zFWnA{bS_<{FgI$ZSt5^QmuYYo{?0y^DFh(b*v|NC=f-8)HlaUf`xyV$ z?HLy)HKw;=F})OKjTXmc(-(gfLit^Q^J`*Z7~Rf8kw+xvXk^+v1CkuSSF1l__t7$ICe%t5o~R;=et zhyjz%S?-}2+IP}J8%9DLo82wH*Ofcm! zJN`r{Iitud?@FQ|B;yR-L#yBsd@!PVHIJg}nCNIzI z7+LSieay`}S35@JJjJa(duDJ+Ca>+w+Ih3rW6jxj{OapJ{K-Fh>23J(TBUfN;I-gQMsDee^sQ>G}DOzVCm&{LFh_{j(+XJXdMC+p^FxIC`FMi*b*zgU3zk%P?W* z><%8^mi=Rc6SQzpURa_HhvYS9lSA?f*@iJ|>k*J%@_*0OR?Ltc8)o7mJGM2OX2%vH z=O#P0WW{078}h=&r+{bJ_=I^)vhk^aXR`6>Y_s3CWi~T7Vfs|x^8DxH_OVYafADpO zKmEm5mz@xEj&|hb+p>G?oXrl0pUdEfeFkzC=~l**Lax@}a=L?B4OT0t)n-Ah7R;7W ztAosn+_q$`!6~ov&gI^gDa^Z?!|Ve+0df<`5nHzEvI*R_b;)4k_?~_8&Q_-5hIQX_ zX8S`tu$6~+U@Lx@Y-2|W>1K^BaH~TCY%5=mdDAyY!{7hS&y}oOzVh6V^br=Z4BMfTSxY$g za$_GUdvwoQw&erAgHvAT-K=HXB9?=*u&?h+x_E0;UVr`eKR9;xZ@=_a?^=tIy-}@t(n(-j1b;ozlRo3seEJ?n0Y`7%(XkC(gM4fi9)<&>R==F63 zMITWlJkQOKxa(WA8!4EdbGGIjtkLjT!?Rs;-pXWzkZ(4)FzI>sjrj{a&=9s#hB;i= zM%gTEqb#i9pR34?9CfqR`?=1U=DIM~@B>$zPaAA6@ckX%=v&}f=SNG=(VE%z92j@b zl4b7pA?So<-{u2St=Uii>dSuj&A;`f_r0y`AkMg%((DP}g0!?hiCDi)FL_?`+auP$ z@$rY>`li3S?-LS5D`cfb#t@_jb$aNwZ2eel*6TM{U(meyDlBKtSMsIGjlJq#xz4IN zjxXAcpWANvI6nx|sa>c4@;1HjlWzfZhg7ZfYKJB(S&a`g@Z%n+WYyUhqC)3j?dq(W z)eh8V(AxAI{>;pEKKo|8Fsshgrt|94CaZD>L*J|Kt5>=W-q_O}$*0R+Rl_@~#I2UU z!r_L?5CyHxrcqG58gD&Ndx|2lAFsmGB`6(vhexT~R0LZ5$+~Uyq$0ft^N-%Bc8390 z91QqE|0uf%7&Y21xML$5bth%p0bFelXK_bG04ACz_~=m-$Z=70zB z28t-}t537JO8(x8>t=@^}R4^HF*x!L>v=GQ-S;=ZM?{=70KqR1qoM}51o zmc-`@ml!T2tUDJZt!0DR1xM@Mo1^tb5FV(8tlD`s4afLjcM|C|%8m+ewSS^Urba8( zTD>vSY_*}Kov!=9tu#%e5T}AhTus-(P8fA}l1-%QE-1T;RNVw+cac+es_LeUs+$U` zZb}v7s;chLr08sUKWoyQL#yZC5c}=4`@Pa#tx5bFRNd6?*HlKRu+@}QsK6(2M>^cAdNrhNyf~h`E_^gaAEK-rc2?>1X*3StGLWa7M;kNUP6DEUHe^k0(!T~Eub&=(@ zgZK71GLE6)$T(IXgUcbT4qr&z7?o`JNx_L}2gz=)OS0P&qoE_mR~pBaIwDNlw(9Br zzD`twdcr&+@x_`+C&2BY6CQFV*tanNmO3VZl7Dp@9!w-qREUBGHpI1PMcAb}wdes8n z+U*q3VZne?GI-dpOlnaFZ?6JsZ_M!~Z*0U-pJ;5ber;p*F@V9F&Z?XUe6?Dw`*{_< zwCP+8RKu)?78A}oa#pJNv#%ym7}zqonuY+@@)ibd2EVAox}8PNzrB@gQFUasef74w z^HQnJ2En%Qlw>BxeS{*X6PPN4pW6sJVDf?6uqRbDGiU10>EgJ7ZnX|j=hZsL&(GB7 z@MI-lc>Y`uv#as(OeS4*+;|S3Yj8GuLc${qe{jZH%fo8j*J{8HD7%GT<0}>KM5*D+)>Ki{(RE9j}RbjB|ll8LyYH{ z(!}%Ts4tpNXCXXX{;VM7D33702qvzf|GBQ}gV$Xmmr|#%K`&S8SM9OibCLFm?qsa$J?@~gD_So&Z zDKEk*zZr5vTbwGwH|`+@GC|O3*>0B60u)(ol@|%cC#j|a4<$q&f6Yjp{A<-m)dyD) zWXn&9@7T^y%kPfPXEemRueP^~-Z78~OU^LMUf=^Met-e59%j55%0f0Y;^u3eTQro2 zcIBp@`gFeZHVC|_@8$xX4?4K7?;PaL|0&dWo@3`%3hg^btn=;xyz?UpLZjgi2x_Q8=fPS+rW>wARMtK zq(h@o%@B#LlE7k-B;|(6&BS6m2kW3AsDet)H|d5~ZDX$_xyw zQCh_9$<1jztv^Z|EL)5wyiTJDBO8e(NF-va<MFn^?jBWx&w}R5AC!_;*2lhEw6K1pl`c{NGky?N-$XTQQt^XtFf{ z$If-)D`(${Gplrh)Ulnw+{1JNZg1!W{2=GVH`djO#>9vltXIid9C=PX}+4I-EWC6XWdW9&xnZAfxr(cD3sL@pOU5JBB(|Bchr7V0~Eh zQi;X^r-S`m!(^#iVLnTV=L`|0ZTPed_5h0eW8&@BuI!}|nO6u2c0OuI00O|>^xiik8n0-I zcRuQsNoG?i;57b$sI<}iUimfN`EK>jJM_-!zum$Lbj$a^C&Uj{`RTtQ6@#S?e(0@t zLbgH$^K>{%4NY2TccEwKy)tzpIQdvY#DjP&%~o(QWGjr)qot4B$WV8;1~J6d?v2q) zZsc$^8~713MK8G#yyQmklI7bYGDBwMrZ=8Rv#Fy@FI6TR&TH%Z6&+>o&coH4sYQ1l z9!SisnC?QgiaXy>RCPC>$2fC{0)HYZW@aTs17@T%Fk)5$oOq%k7&K%;fmY1x5h0S- zv+F{sTy`53Uk}HduNMop((7fopfcGTP6zmlA)k|_qd4q36zQ;UW>%1mAiYTvH`q32 zJxm+{o@6PMIQ^Ey4RDoTMVBdo518S;P6=cJyY`eIWFWu2y}C@?CR(F;!O8@fhhr_X zl$FMM^D;sHpvbzJLFc7(SX5Bjy|ZOgne;YtaoJZweKZ@VTBt%R1SvsO1({$fCF_<` zN!Kn4io-xA1S?@6YJ?LCnRWO2(b>4rN~UuWmvJ3PnRu*(OPS8t6g3cU%0NKXvjwds z)0&kqfR@AnyM{@(xu*zS;R_% zZS{t7|5%?n%^-||i1Z|P^Nh~RsVD@bSUMNI^N@?J`52w^TRRUZTq`?Iu5+6DgH-HV-mk#AvD5JW83jRB7;P3|fk0^k!*u(j^7x22Nd=C3r%-0J^9{#YK8pPN0w3@Es^dh@afU^_M|CIut=zOlgp|`sFe_p8n5267kI)7WJe_G&Uom-=+oKddbt07__k~noU&Z&b! zc21of4PMmF&Q^Vn&96khm58OX`6xb%{qkjm!csbznaA)Oi=RsjmB%PmZ^%}FaXHV9$ z7G5SP$V^U<_sB8=)lho^lm9x>h_wwYWyUtaS!fuGH@fgtmnAm7iI@f;1f-syZbbmr z6zch@2*`lTatl)tEH>f}GM4>IdLs^Rthwns1UXca)jqCvjpV26Y%eT-jd1-IfPmHr z+lSY(jJ{zabFhB0j@$DSZYn$e*>6KQ%u{|nzZxBDU+gmfh&JBFbP4~D;pFzz=%tsU z%B7b!E@cc210qzue)19&uolOK<4f>p2air%%o=-rjf+vZT5DX48v9vechUx@x~`4g zzKvZ(L^97Aq~C?YjJB~0mG`iXovhJOAOjZ-0(Ut4D|)-MC%bl`C%bkvcBMUG8xD(| z9t$*Qdcp{i>&Xt(ke+msp3s`RHaII2YRH;n=*dL@yPh!jQF?;(w9pggWJynuthK^O zbdcs*?{pfS6n{47-p!ZDyV0`2pKUw*kxi-i<27b9Cu19vzKsbY67Ziu!QnrF%7Q<{ zH{h?$VI(B+tCaqe&;s?z$p#Vt?7P{V!=En^{HYisC$Zr0=NpCoc#Xk-EVeP`+d%q} z!G9D5hrcd#099t^cus<^r1Zyv#|rcx8w37hV~w#Ce>Ugv=Su{Cv~2Ka+YbLWY6$*Z zSBcWZ7_(~wYf;(;bAclLnaN@Ncz%f2-AKrTDWs_inyK z@aJkxq(9qs_>Z85;Ln&!#2*f(Z-ePL(grnE#J`S$!(Z1*fIn9RP*;=))=3n9#3+mS zQzJQT)NG;;&1R#S_JJ6>J`h8BzhD@&5ixXqAcoQhU}*Y4v|JlRR@x8@gACLFc6}ha zA_Ic1>jUTg90N2y%VkwPV_f^z3AX z#HXTV*OsMp2-mi6s4fGv(axROVCUwmYj$o?s;t^MZAChFxN19hL`ucZq57secMP!= z$v0Z($lbGc=T5HOIc-HccRcCbiPFxY`ldQ}YJ;6Sy>{mg*EqPVj-0k4otv-Okz0^b zapX{aQ=MC^ZEWO@3g)ZI-0`(Lr>#im?nyegRN6UIUr*;CvnTQH$^=aHP~+r7jblvU zP~&Wq#(_{m$3Q6Qp+bs>Zoq~t<oYa)kM8V znMy+MF_>U%I&o!;jS85Fp#uD~(h9?g8we98`-RE&P-AbC#_nUw;l#~2z~}SCt#9No zjoXlyw7mALbe5rRoy~eVwz?!+3XP-1bs((;4Tg<4pBtr3qck zD4(>)h#kUaqM*6Mi8>k~DTe7J^ma%t5pAomJFM$!FidA6b_hC)4(CpOSA$`#tMx4! zyh9C%*o8K#u?=3b4ZMSo7sGes@7gbGEV|2(>-4hOu2y#|CRwFN>%qPK=|9wzo=&wH zK;}6MDQytkWTFhWueFo#=5F5&YTRi@p(=8|T<;juyw;J0JCz)mflR4Qd!_+P4e>Do zssvzd>8KKud+c#XShLxkID@}I6gsy^$9`vNO*!_)7#|?zBEt8F8$@_HA{?I}!uo_Dd?GwSgg+V)#uJ-D7?HSsgdYlTA;M=O z!mkX9h6o>#nX*tgK0$=_2|;)vJVAtSlP842cw$os!!qt z5fP405Mg~n5MByT5aIVmgz?0t5QgIINBDv879xBqB795TD*__CKvk?}AU;8a^$9^( z)x8(GuSbOO#KsUtyGQDZ>=bm})Kp_i7HVz}IB}(MQE+0=GQT(6;4ph;_ynuz z6SC%aEIh$QzqiQ~Sn7l9$z|J^9RQtLO;#R*qU0+@QOX;GT4iIRR^@%6HeV;TZc`BAN6&s3k@Jm1wjI^k9O1O{$mqA?)@7Zo+BqKaC`5>-3tqN-g86Q3Yu z^a&wNRP9_3Rn;!5prYDw^uYy3G$M?yc)}&NJCcFosbmm+5(!7~RKjhQO~ebmJsig< zkB>LTWt5|J<6x?FlfjJkkb|lAPzEzT!NJrgWH6&Wk;mYPmufc3E{rz^)zuqy&g$& zz!T8ejUiilr-8n~kS)EI0x>*mCh9#h8r8cpnyB~4npE$~nxfw06Qr;{A%Y)S^K2b* zwCkPmQKtC9arXPR=yi%S4nNZq zPJdD7eD{2aDA2rcjJQL1zHHhR%`%5a&GK+!yUBT?m!(ATqhyf6Dj7oIC`%Olt)1B7 zg?>`ohTyl`4W8s#&Epi6@~u-;k?#+L$s^@kC$%Eq@dJBIA?$@e(Nrsnauj}wvI@T!WivNX;U92B3orE1tRx#b z#-^x{G&Us)DMquzqDhQL6jFSGz0fD57crVeM@yqw(hG@Z>6v$2ZU{>WD@MQZ_yTLv zLBLLvx}JTvECDWe_#O9YfM#-f9<~|Q`&JDy?2N${rt$Idm-2iWHYJsL>R`8)<5Xb3 zeqiMWPaz4jj+Up!+xQPkUDpj{Pe|u(-TjiE2&lAh0|)d8D!l%vM#&0m7(C6V?w4Jf zxYT8kVl9}6PzxJRR;Y#HVJ$_5i|eL@fe07jVC3oi#EM^OfLNL1 zOX}li($6x~bcf!B!O3UW^E;su{WkM>{L_Web5RXL8HRp*WXQ0Lr#p_iT-9H^g7nLi zm#lX4($#LdW9rM_dD&`DUcTDRD^|O?XSJJ;S?%UySG#%T3OCPAOMJ93)DmT`$D`fS zpB+~{So&?Lq3v0TtIm$v-@)k@-D%9`@UQ-iD>}c+^8k9tw90QLfxnF5jR3uL@px(M`QZKKAr0vc?=wlCI}B&tWbB_%pgpVr%?T z7hCqZ>lr)tF|DiQFRcEM?6So4)P3+pn#9c^8%ISlVe0t{Ft^r6aPmU+CXA4M2322xs(5g| z_9Hk?s4?4Kz(6)JZ%3T76sOvC304R3%_@<{fa|6oE-=b?Jf!sx7@;ubw-w57mGT}S41wgdhp5Z!A9DA3 zvY2`Jm{k5;qk;Iz3;5wn_bGtY7z`92$ z(}CHV_3JVOdU)=J3@t=|iolU;p-zRT=tEU{&Md_qbXyVslt~AH zzGvMZqS}??S`ub$3bQsNvtj~V!r@+_uA_wl$I2NUMTzMP9%fRVltFSHM^6 z3%JIfD69!+-ovOepvLIS61N%tWcHWdwd0awZ7nc z&!F)=xek1>NL7mOJQkqJ=&SVw-_rxb7kr7GG>&(Z6z0IY6R3lXYdE%&!@SooLepB@ zBXG&q4fV%DedKpm@}p>;&X*=KyKOjIPDMV9c0uZRbY;n(gwsxvZUfaw9_njHpD>1` z5B0ll$#!dFSi>TDw7!fF^}8QKI*dX&$?}jZEYlUoaA+OHYKpWD&N_n3(K04^tYM@% zqO^2wM8imPL}?khb-+pphg0igJfRF=82m`{s4hRgPDb1uX6Oewg*Nnq;03F!bN|1y zBS~gx;7oELeHzDsfiua0^npYJ8{JLz)B2)c=mUAqq&p>?34U~(Dbu#0haRXs&@Hy%1zJ9_6ys%5~H5<_p>NlcI=N({a8ihOn}T66YI>x=%TckU%gg2#Nq z&6jW`HftzJf!ae!xkZfOzVrJP?`oa*M*cWhIwO>x)^wo z63%(6lkgz3Zx@CLD@BL^H5&pbzUk$xnu(B{(O z@)?-o)xR?kT*KjM^?oI^=%XbgSH6gvj9fa$G$XelJ8O$0hw7Uex!`oJbL7e$(4=$a zzG%|9)GalgTPp1ws;{SW;CJ|?@GXa@)gw10t`)6wXoni7Yz~$1Z8}{we0!o)ouc}B z_?Gj(_zxo&X0GcTIn@>Cr^Z2dpkpAEOcNl*)-)y|jsvOQpFH_%Vd=y-#(J~7DIb1te-vVh8DfYV1lt}FUoq4 z3Q)nQfca=?g=njIrPX!qf1OHgsIk{nYQu?J{P^9_jp{qj+pHC?Q|8X+iCdpS3Cj!X z>>QU4`WJ8$7qC39HgN&96~6#M)ree3EhP41Rf8pX{*ifF{eQB#i#mV8?{$}A0_679kJt6R+zuu0#Zfx(y#OATPdj&;v(+v$-1y05 zfPj?j{?uXL7NXY=JTx21CYBO^7ljV)VYXoSvjcyfFl zy8?qwqYtvw8=4k3ax@LZv+A)AdVomamDWT1?2RS)B_@cg+RzQZla;_^`f zKE~ufJjRPgaRTTZ>_&HluePsZa9zHD(7=909D~F+3d#sy@-2!cRN?dIIpT{G`^~5EvJ92AHB`<##H{{GF_7z_XZ^)59!qj+> zon?L&(B{QR@y(ikD@y~|2IxN9fZcXNYn&p4Ch{siX0A-r;1}iV*~o!fL%&@P0%Ia7 zo*Uz{PEg!Ks0y|rv(@kiKz+KluZGWhchCTDcfKg1CIVDmle>u76TS(I3?69aRn@NY z{q$+YXt!d-cEJoXP6ujx{99hbx43pDMWd3p^y?aO1(<8Q!Z0&B#!iCih%^_R!0FT( zbu3xwHsSG~#%3+F)Purb=QK14cG)xZTV~ zvWC-be0xpa4qaQR9;{RW*bk0X5?>vzWyPv>>5r^uX@7XWnlR?(`%_nHPUG$S>eE40x-LzGE|GthuUhq_&p1yTz+kVXX>^GFDy4$Rsv!cbl*(oqL6s#>?3YI|sm#p1trO zzm4O&hS#}HlGBy+Enw#INqJS35wNo4k(g>Z@qz5ra_TK2T+18Jl|FRt6dO~^*)F|= znpi4Gw&N$L4(h~OE+dVFRy@k8P%^a~+EYZUmXjkW6r)NpAX+1NMB(fvN7Z&~0o|es z4L31bjxD5xctRG`N+Yj!-WkZY=Jm^v+ru;ZxNo+H4&Vo(pW_Gwint|?UIP*6wb52{ z1ZN*q+ZC`uEg!vpvc)!Z2-%EYxt8pcwQ8j{4z0<>K#@I9GZ-0>3BXlE*@|3wd`ce5 zYI-!rq;R7gjfdw&qVOw%gH{yIZ&^T)P!@RSy)+3RSS@c|KiPCBi6xW{$Q5p&9brs7 zr@!u%hvd=b^|ItHV}ly<`x5B_1`7ZYfS26zOsPB~pLl|-kjzyY1n|Z6lc2IkTHY*Z z2GXGpPw|sFsu)NZxk?G+d#k^mFkr(9PUXWRIBH|JQcF>X#e%)|-76V1`{qpyiR2ed zlWFmC`F)o37>7evSLqFInI7*K>%$()RoY{*MYyHEzQQ|dc%7KTa5NuWVM$w{EWRLM!8>5`I@ zKtoROB9S->DOFyL_qZ$20Zl8&4sk&9zQX}%Fk1*fLmLDy-Q$rs3_1q}QzO2NYDR2@ z?1iyKM*xXq>qi^$`*gI?mgzArfdFBqQ!?6wnLf#A6K1+3qfMCUk&HHBu|w?4G8Byw z9u9sS?UXs(XcxFhN1H%{fQ~kS22&kv0!^26v7VJfE(rlv*<7rXkMhlOrSwY zhnYY_lzACu0wY!YFnh)a%^WKj3{M82>C1@#G{_teK!eOu02*WvB<|-quu0%KSPX<% zWZ9!8qL8p2@w7VGGoxia^b~a>>v?88Rb)ntfE^HFM#4;Qg&7GmofT#z%=A^5kucL$ zVMf9t+1bmZDKnBcBQv6Zrn+NB0!_Qhj0744lo<&$m?|?8Xu71#NT3;Npow8AaOh$H zn#YwH3tX?vNT5M!Av|u7pAW!D70--bE`b}6A;TIBl^F>%$S5-sXnK7-JZ_L#3P6L5 zG9w>1$T(*7l7UY3OUB^nwl37L_8J(%| zdtqSm;7fT?SqkP=^lCvVvoEP+pzna-Ely2)Sy`-kNJYIKyw8q?$O>Vm{~{}dneL0M z5N3KWvO<{YyvPb+vG45nFD81Mk`qPcC^$IQcA`R{X;wvrK=b}(kWT1j5mixPP17SF zFi2p+ZcSPVe(xQYsE8j7f>5NJ?Z2#*`&=L67m6N-+6@md4z02vCN!B9no zK!c2m3V{Zhl6xIxB=ikDm51u_&TgN%v_fd&~B6#@-1Dk=mTWK>iL zG{~r^5NMD&MYQ+Tz1-q1kSWY6jt8JYW+?y-GWP_aLFQNh8f36y=U!xxf&5sx^~(V@ z3R5DsWU&Wb7e8 zh7=;i02xAv3;N*HY%NFgSsRGAh9Y8e~+02{g#41QTeGQ3)o{Aajan zV=2(N=PJSYYmre2CeR?G5=@{$<{m+tK!eP&05r&`1hb|=#!0YOCyZV6sS_+#JD@@4 zjJ$%1#~^b$01Yyy0?;6{9DoLylLSULphY(T%P|Z985clw%aZW`$o;7*0oMY8Q4jVW z3;_s8A0QYNK+yjH0cijM5&=STRJma8AWpgLk3uGz#gIkRilK<;6hjPAD25KAO(F@{ zeT0V0EDnk#s**(QI8BmjCsibXnRhOWb^y%arD_B)gS%=Gz)b&0$v(}p7=Y$!RU*_u z<~4^yO@q%u02)Hf2VkUzS0YZGatzg@F$k&-0h+caCqhkw%kcm-xGV*r!9{fl+cda< zn>adNp^<(16x!hcG=xzd0^}`W=0i<`jOq~9G{~G53<)&IoKj@GLL=w)`A4clfTyL* zQmAPtb58&oWR3-(K}K~5+cd~PhO9zU9RidrAE^!@&`{=#yn;Z3%;^9$$fyosO@qvG zsA-TnsmOSRwiI;N{wTCKDGubK?lQ<63qXU+(Ev2aEC!%K=12e9mSbvdNdYf7b8uCvWaMtx3fiH<-#NWO<^siNA z7M~%TtLiM?As*!bCY;X3%Mg<3qp_VbZms`!<=6q1hOIp=gXBAIIWqSnqWUP+Sq- zvJ?zW0D0u3U}#DSyq)tm1w*q$49N$Wg5lFUYzl^^Wx!B^-Hm~Ae66c@+mnL9VwYa;Q_o)5;Mf`qh3wwVQztX zvdUkm=W{0LNBbw?W8lfUJb6T(lti#KpR@~kzAd;rXbZ{Bz!uXyU?JIKn`ld(2Wja* z`PSjFq4g1I{iw7q3o8R@-7m-B9pQa&P4T{_ybr+u^hWaD&e8k)3K8BKFo3@f3|fN0 zwM2j+B+m9kMYwAHgW5kd{p9TLa6bYr_zf%qMwspZqc$;OcKrxG#3I83caVwpkctdW z!f|-Oezs@=Kz=4Gks|cM&b%d>M3}MjnV;L58LLF4SkFvtC2~cWnFAxV)))Od4tH9Y zJIuuPL;#vMpA10r>g515@7CxOr}O6J8h#>hf1Ij=W$|{1m<28dpm|*5PpoNPbU4&B zC@ln_L4G~}O*c7}fJ@**wUACAgTEFT4L}iSkU0@*8f1772V zMB}L@H0G3YPs!N_o8G@-u&H<_PRNUQ$kJ-Aig(Cg8f+@w;b3d9$=q>Md=7yIo8(?G z*d)M0P{A|;$H#^QigyOq4To%@BgJ6TmLls=Dp0)`Y&r)hxfd50p%`r1^ow2dg`q13 zo7QOFHL?U_pur-kUko<6MqFhdMRHZsV3VsVQx`M|k5nKUY zMvGB3!*|tRj(s-yCHcvh@weXj%$pJP_y_Q4^5oFUV>%54jK`Gd2vSg(g22v=v= zE^(kXqdyt$N{Aqv>l~3C4S2Q#7X?4Nbr0AyJ_cAtVzY1Qf#3PqJlZu+=6@+j)H?s0 z+Yiw&+sr@dfL~A`H}17~k7}pQpLV|YIrsoB5o#+!EkTzh(|YHN>>8x9j+pjCe0jbj zzyD7BcHZyyIKXjY1C<>6hicp|fi7mveA+kf`ior`pay%Nq3%;Sj_CG-LOIzt;oVGqSJV(cKsCt;~@GgoBu0ze7ksMIn(iW~RGP{s-3>w~xxW?Kr>2?LHkMP$M0> zkA(3A$9+UFuXVoqs2b0;9I^*6Hq}L=JaC3FKdMEc-d?iE(VS z`s}x@@NvDem;zz$qk9*x{Lwvk@aUzNqROS0HZDbU-$gaJXXg?W+@YJ7KwHS6n-{Z& z1YKC;Vid0C4wpl?bO(3tPTJTV+t}^f*u^!3aB$}?6l4R;p~+pSET>fLWDVJ}b7*oW zfIK>JVh4fT={_O186b&0cRks)3q9GjtFbHX3EOZz*(oh+bEYRdP{Z|P2WrR>q@AQE zo!Calw}JgYrY9Gn;CgZqDoamrP;ThS6oAqb>?@U?^yA;@0RK*>(Mj=Va}IyLL`GtG z1n=+&-ah_st@NFPz(3p%DExycj^Tdy8fr~fuQf*15y@?Vl$=fNuoRjqaK3L;Oa0@9noA-&z;a1^u^*+_U&&eh`pa$$Md zowCP#w0Is6s*4V%^ShB#YB49-&@ol>4CLxz3&Dhtt(@W|TP;eJRXeAxNaqgAd62$y z2%kwe($1m!raFiD+=e=bfY(}`JGpk}v=!;x@uYJnN;`+@o9Y~9$s6k2>9sqDxZPT8 zsjW!o=H;v(KXM4~m5dy!Z>n>MN^Gce2*|B9a>v*1oVFsJLo5)8`_3(ub`I6o(>aI) zB0}(ahDY#n#yZqEPRr9s4>is)|6XYky$AcL#P^EB!#HG!)mP@j`5 zaJk|z3Ky}!)sF=fcCf(Z6qp2Fa>?c-;JaDia?lABE@9zP6cEDdO|x(r3QPLL<+wZo zS-67mJt!b>)O!pIk40etg)3R$BKmwy-qFP+*tORq{3;Z{$-TWSJPw6ZC_J8pZ$Sb4 z%S$8(ORv($)KR z7M_9vGO~F29k@ioQtto@2T?#eQ}0?9{t*gGK;@|{d?yOW6_xM8zdBey%-^3qSYO~T(o5(0`!5gHr}6VIc=m2B`)Ax@T+4o% zxu>=4r|>LNQ?sAIv;6&WJj>r7!?XPTk%RR!JXiPG2kWQ#`^_Z`B?YoYRSxtrL1w+)Mz`L(8mN|keAzp z#--1?cN&?Ua@LC8L=MEL-egsz%yR!ZUNdp9{uB7A%~Woy9;p1XUcL;ce?E_w`#|r5 z^&7IEy{r3knr05(#R8Ayjr!IBK|+wLi#7!rg>>R8^`Yqq01kXcQiKDJfGjA4Hy7}V z<0J;q^C-2DzuN2oVbx!vKq^I-j%KosNvv4uX``%`jUob+HBm%otx6nlU?YCW}W zP(6S)alJGzEJq(HxIkplb>*RY;E69I7YV)coOWp(NQ~@du>?lDSSfY6b{c~6i|9M# z?1t>w>|Pz+lT85Uta~&ZuES>{h1c%zKBxeQDLOCRL{}agI|dfWVoCY?q_*xybdPqt z8)WJOk$&$}`jM?q;Hew3r;`>qie1lwI-h9)tKme#_m>c*0Q-{4{4oPjp})sKKvN2~ zfjB*&5Z*kF%QIB#kor43)n+PpdRpR`0@Uz=kISFQt|Ki+Kufr@7`q_CK?4SUpgtqM z>k<4uu^9kgt%sH{~yGcYV=$Ooe31c zB&qiw9aQE^I=t{+|C57;jSoE0y!W3SG*X)A{E~yFIM0j5s$@SG_wmkDep$|~hlZ>@ z??9!BpyYlIi@J6sMWq55HLGL40HgjDm?9+gz>f-3bOc7tE%g)`fvLv7fsI!?ACbJv zpP}zv$^JQg?@IPh>3icQeedgVg1z{dZFM}y)H$uvb%h_4W~9;& zvXURWDn0q-YPMV5mP<16Y^K$vsb+9uma5qyy7`std+Fs@vYbvn5u=Y^%dW`8?mtGI zg)7xdsAgUCrI!70cB4b!S%M`5ppwCM?E@e4^82%Y=kEVN_8fOr&7i>{CXdgc&@0*A z4C=j-^|Gt@^WB_LRI;bCZ~xvs@Kko_KllP0UzEnbo$z0D@NXwv_U}A7yUD@!WzTh2 zPt5+KySgU(PwwhT*?)Fd*Ji)ut`4vj%*T+Mu5pF&&wtxU42qaD#@&7R0y7-H=B9g-&@kCH~&MPnH{zMvQNphP>uU=S!HbVQ;av8IgW;Q~-t zW}yHS{(x!lZQ>0GeMsp@P4+w2X_+uqSautZ)p<2m;xdTbVTAku3Q#!ZWC19g0yiP4 zDV%b=02EGHDgcF3?uo#JQ!)zqF?VxWx3bq6j05Aq=^HZ6kZ}Uvt;RUu6fljdKWMkW zsssvC!xvA0!qf`|pfL4(0VqrjCp~#wnEG@C0=HAHbW{&Ws52@IE=Hth$i+i04(xM2 zbFtgw4;10;1%3w~s|+FXkpM-8mI^?Tp?eBIk)dM+pvchC2ux&13yo zyA{PbM4kBMIJ6hyP5RZTIKSj8u_}uyan6hV1p)!wAuqdx*Z~8K#&j;=!0uKg{+VO!8IU94FuPKEE))|0YS<~cna5mpuZl%?@8n2EBRnv z41;Age3lZc`EBg(ZMPfz+#bH1=+m)UD7Z9ZUdk3{ImIn(l4}BdwPt4Va)zm{vRV+@ z7>RB0QreK^SNRwtlfJk(AX_zgGD(fQ|J(;^+S)J!=GgovDY9GRdMKL&ZG}m)D8_}l zoM$HyIz4O52O~$Q%NeqF)E=Q8CpkhnV>ydu=))S6Vz>|O%g}r%LvNE`+FolK%%S`p&~yiK_x6MPzpy&@0TVRno&5)1jVh(5;KN5fjjl}>o z2pE6^ZwIMg)AECirIW8f2CN z&>(Y902*YD1)xFZD1qS^GYYtK!MuctB@mdwWZu^^h@6q;#RUt`(jLgO1`S#Sff+1l z6M%&~#*Fr$ZmB_YP>)&zo`L|(%V`YiQE%W&j{-2Sr75Ue)~6-FJ7v*CKc$+r@TK9r z^>iH5?H1Cww9b>u`u5$RDIn#RT3+7J@3PmT{TS?3R-FoYWlwY%;hV_q-c@@a_xNv_ z+4lqod%@gP>+&o1Jm#@iX8RoI|DBs^?%I9vC6`XmILPzorbZ^GF6!*~76WMN)?&6V z7f;)BoL2B4Enb3h-8$I^RIYSB#^v0eeDEILAr{`?NsOQ(FX0e0-DTssk}FIo90@k+ zE=Oa9F8O5i@m>|&IkypDr zv6j5EyQ|3QSp%L^Z|5O?K)UQ-wo^Xm?bZ`_jKQ;NsAtvP%~mHmVN)A!h(p!eIn}81 z0aTr-?eATjS8kYW^LnPcQ%H3&4(qCRFQK^N=1lG6TX6o^4xGa?4_q!eG>M~EF3EOg z7k7^SAwZYsxY5R|@Lh0Rb#PUctLZKds=0Lb;fEh?y*S%>_bo_?j=0s3Mcv42b5E*P zy3<)>UwyiF*=)9OSNC#&MbY%Gkn$ehY$J-E2Y*0(5Qm&|iFK zoBinYy6n>kuYnl)LR$2|1YHm^!_7jUdWR;lzr2S&bzPsvv+muq*{xX*Xyeruz3$!J zE9CWg9bKIQefgg0UgqBKsZ10a=!|^NTQES4?p3JH;l#idvA9aGxC)E(I~^9F8mV$? zcG)dmsEj@N{0nYEi@WE*6wgKS_}5xI50f;->e2`VFMCW3)!LbFxYzg9AGE3YUzRbZ<9~M;u4z zP`#vkkI7qjNy~AoZ@ag9s#OE8^1tzH3}BqJcPG!fllOr^aU>iD`9STX^}N=_*-M_@ zWFztYyBTZjmQ;I+@r05J&NiOuJ|-WIi60<(5q^Lh&f*gSV?&A4G9vz+ztGdXuBn`;_Zs=w(UDc!p`uXf()#^N43OV5x58S&U@dkB{;(@agzk@ z9oG`~NuYE>O9!-cQcK)6fqSqFeC}E;oz@a}QQ#gNUEX`Dmf#?>#7z~r2OpXx?yErQ zh?cmu0wuVgy!YK&f``fycUs`yJzBa>OUJd8Yw3iRxc34zVW{}r_i70aCQIL^CAgq0 z9n#VnEj>+33lawCUauwCIM%#DOBytgy&A+*?|r}CJEo;)kXLX{{15QA!_6Dey4@e- z&kT2O?5p3<#m;N(o^8V+X^vCqTb zg$!f|Vi5wu-5>rgq=%b8eDN5H-yVxcQADDszk3A5C&%Jp6p>Bp?=GPDq*#QkYs#sk zGm6*5y9^jedaA=2#V5wQj0Z?6tKMZKU|+m@?Hp6r{A&@Ckpwoaih#`H<2{65B&$tw z1()D5GTCpDzdwn*IsX0xa^Obs`{T&K<1aSsEb{k9ai71~P_PUKH2Y!P=kK#|pTEz- zef~ZZ_gnbIMxG`9{vdW}@E03;j`A0K78d#Y1E@EK6vRE^)m%ZR?BR=Ee2bu(JqEjS zh|I+YYDb{4`TI)#UUHyzn7^0Kwr|ZId-v?aRX(vm(B;xjb~noNEbl&0dyq{`e`oaz z{Jrw2mCy5c=Tj@E@Jk0;MG1f5^>#k0CXm|%W~DGJd<&oA6iB>>@GV;MkcLP*oO+c)P*H^85h$VPmmjCo{kpei6`=g zd(pUZ(@tfhhT|W;FR~p9;5x^VD1hmdTRGh13a~Oy)WtkVdjuNMf(j)-8d(LAj>GWE z0*LezhL>^K5ct@MLYVS1W*Si674jp65-`AC27nEP$H@RnlpQAnK<);-ZrLM3tRRPq z2(f~(Rz!#uaVc932A`t5|oWd)I`IdAP#I99`jK{%+vYi#LN$nm|T>+-3B~T{XUE z2BJSzQ}PE&g@YCQqHs7^u`kMqgOyOpe2Is-$%M+V;@a)xKQykTfDD$DnF^M4nF`i< z!Mac)F3o@__!0Yqnb3VSGlRkj+=_?xT)jQ zi#LPsdJW&T8b0dJ`tPdn;e)R5p|V!^P-iQAsJab&dhurPNomf=j=O4nr7~CJ%a_EE z9o3}%L;tSup_^Cu(BK>R^y1CnqofQUm1Ov+Kf`xk_%2XQu8-(DDijmV$QK*h&AGL3 zb>n*#sn1b+Wemb-9#X$P z%k@fJGlY}XxP}xb(kxUagovBeuOUPHq<#%M;VAWMmKk^v=qhBM9nf3jeSp`?5Uo)rR^7CtE z6kJJu{XExS7T3>l{hGKw&-H8L`dO}vxIWAEB(BeJJ&kJ=l*#Mj8uesye_W%Spm+ox zuD?94(XgZyS$om1P)Yrom2(foB^wxjWnALp{wmyC4-Ov3#cZ&MLH{2}TbYpSLO~|numWSNjJnTm3 zwwtC$++e-S&Df)E+#Yk2cgGFkyWKp#$BpKD-ITu14eT#-v->q}jK9`R^g_l?ub9XN z(g#JDM7`p5vXJzZ5e8GQ_${)ZdVG3>In^t^Le^EUI4)zWS3Drwt5t$o5~r%(3klF6#H)Jl8K@ik;E#?`FRPI71(hUDWUI;kkbK zuI!9{{~MmeMcVt}qJDob&-IIW`>cMkYtQNz3-*kDzk__@C{Ch%Ufg+&Hk;dWg<%q7gO%SX6`*LC?8E@5?DKFTGWuFJ=`gwb{R zRxaUlUA~P=*j$%i$0b~@%dh7WCfDWTT*BkJoN)<@>+&R*aJVjiE0-|1E`J-B@V73X z;1c%M<=eT0yLI^_moT?3zky45TbJ+P64ut`Z|4%u*5x;H31jQ>KjRX<*5x;G30v#( zcW?<;>++kqgsFA;EnLFWx_l>>m;Lf7F5zgU{^wl6(7OCqF5LtAUvTA)(f^Vw_m}=x z`atm95Qi4Or-wMS_`Nc~p~dfo0S+xaA57kD&j;*BqUZg|@3!ZCwj|N>{^a-A^Zw+& z*6;6OR}y|6XIBz_iplTQ&xIkIV#wH@LqWZhw&TXrPG8MAMh@oQ=JF2yY+|5GJ)iI< zPgnUg`z&uR-$Raj?it-fj;E`YLHLbP7AH@y?UF%=&}!vfPBB90vik49Bp`Lif|xQXaAw8Kh&OMGuYn@Iv# zVUv*1iqUY06vd#@+HzvzugsqP+2=jADEe>cpG1#Dn9WQ@y=(x;!Hkhrf6k@{+ia;^ z&};Fh(>`qwmni2I#c*O?QNZX6UXeP8c}3N0C$CRf;pmi9|37GxvDf$hplQWd%j$7j zWYznuXL~=D>vwJ6ubAuT!0=_g)bX!)Xz8E$sT zFB`rx2Yz^cz>xaaY6igrkM;jAOxWW1qrJ~;u`*%Bck3#Vc!e1fJxH|${vmH6KphxJ zU*Gwb5LXye8MDvR%-7R4YmJxK!Zo4>WN`^|fm>v7RiT$#!ekl9idHw|T^LZ8ctWth zdb1O18=Pf}GFB$chl66}(cTpq|G7y+??l9CFuS~FgXxBt-4Wthaf8*L(jyl4^gAlG z;H2LXi@|bMoY~uU2E*yK<><{m%3a}8#p*+Y7X^oa*01XK(4)Oy(eKlb_AalT>_fx` zQCdP@l&C`8*b35sE>Z*w(zQ%=@-3cj(k+#Kf>;-unle*k$!(Vg=j{Bpi8G6S4rVX# z;Oi6JUg9om(nURV8ot0~*?47&d9iG7VfA?<{~Qh!HS*7HL#=(MR;%Af@;P3Q%Bw>C zeU?G>old*+8y@fN>eboLQQ%i6^6UmOqF^IW$F;z%k!RK~B`#>Q@3dK_&>Zj1C7u{< zcEjty$-JQd#r9`Vf^65n(KNqpnDYJ3y@A}$fGI^Q_b zfLG(2HoU4i#>>LweB*=B;2W3b9ei_ky}>u4N1V_(3Anfw@0?vPi2#ZFV1sx1#ahNY zb{D+!aE*6N9IQh4U)ScHI8#i#BiF?|-qEs?I`2H_{!r%~TUg_~;~TUZ@8IZT^-(tQ zz=v(#nL6*R2k+byyt5s=GYsCLLvM(U z67M*!8t+8Eh|U zd1qMTod;ot^~5`I7rgVXHt&G1c-u|$4!-La@7Rhk=N(+;B0kMKwjj;t9lp+cV0gX8 zJ8oju=AG9$?`#C`+#9@eBzR}x7U!LXCht&DlXuj*ig%)2ns(?Q`BC z?$qKPTR!Q$V>|Xa?>y!sD4orCr`-A3bvE~o)OhE9=bg>qo%@1!?h4*nyv2EEvB^7B z)Z`ttuHv0&mw4x7lXuG2h*nQlyc3Of-l?~-u=?N~8fLsh!oXtDWj(kX+cigd89Ojc9dN@lG__d8gjS!s>%}XqfR1 z4Qukwn=0Ok%0+BmsJ~z5opyf1Q}IsVk(U67M*!8t+8EhwpT)(|Vh?ji zF??neoSjed84qp(%`dYWkG#|T2lcE&>bI0f>s+Sz!bslCxdxElDt%L0nh!@km}E9n z&0Bl~HJFcAgUNabN%l+Ir=~0@;+u=$D5o~}R40ylk$1n`Ich9Ihwxq#gm+AY$Nh4+ zW5NpR%PK6MHur&~R_1!slls4+1J<|L+7<|Ka5-ELODvy)t}QF&FUzYjY-=x(>}{D#N7 zy?WKW!e5ivsT;_Mg3aybxE8oIw_DaPB`(yVW=s^g(d$zPPv6@`yi?)USVyA}SHwFNf{J+ODwpkeCs8iNJCCaRKWM81-A*ENcf9ku zs=wgXpWrg$oeH-`yi)#2HU#hofdAq?f|lQ zrvk1K?^L)s;+=~3M!Zu2*LJ*~5{@lFL?Bi^ZibHqE} z#bv}h6>x3GI|~6I-f0nM;+^u0yNn}ycf8ZWjqP}+0>0WyCubaBass zCjvmc^BxTW@y=NB35?`7<~?8B_5w!c|F`{VeC~FUsB}CtZHZo)>NmB(>TK$3L7b&kHwZZwax_Dz!2i;l^%UBWkdT#bGXRYZHq~qHD7FtSV$~ zS+3?5hY(Pgcw%!)`DQg+W>Bl{EMuWQ!+3L7CR!;XP2$GGjmxEeAO(&dDeX?~sMNJe z3#t%qWRY(@VsdX%bQEs9&lR1OFdgm+(_t%2hnFk3z8Y}Skik? z;_@a*(|fEkBg)1rQzJA~Sbg+4jWjcYMmEieulA9Yx*nBF?+!iP@y-i3Mt;NN6k5G% zDti@f>;{s|2**`3BcfkQTy-w{#Z>XvT);8rRr>TsX9RK4mU2B5oLuN zAN3)V+cy+mxvusXGWjy+Ap*7*vOgL;G!7m*@NlC?hHGK^dblwQ(?8nen=$|-I(@X_ zn`pEfM2(P%)d%0uFyk8<*5sQkK9_~*Lm_v(HNI)*H#`;J1fF`hu^UL@8^=}Sn=ITY zTy?&2q+Mb9Hazii1C#TOH?F}qyO`ex6mC@Dd^O`8y9?fVOO1C-9DuKQw9PwvS=+%o zUE#*x>0>3{30qUV6RSPMJA5awkC4f0oOcM?8t)tn-YJ*69C*0Vqr)}csfQb*U7B;= z-Q=A-Wb*EcccRhGJB^S@86l@(#ycHLT(bCFR4!ukLc2os?fl}M7=-FolkZiyu^UL@ zosK0gS-4TS>b&DfyF&GCcpaFWcYH7!ytDr~rw@7FY`C!s)ysdyUGPqQnTzp`Snb_6 z%{yJ;#)vA5cVeYjW0}kTLME?u-XUmPTPjvAb2;#Eqeq8pyi*T1M!Up2t>s~P$Rt}H zR$J!M2$_@-a@N2Z?{qA4$>MWSxri;6xj5e1ywlDv-ibk|UNzpS!j0WP67O^@bIHPu z!d2%TN7@ytZ^P@riE;l?t^FgIip%Pa}n8t;@##L8tZ2Oe(p=x~j9)H>IzW$Q${#5=7eVr6SYtJxB< zXmn@Dq>PZ4OT;>sxn%LVs9eP6g?5GN+xZQTx1xI0c&7?Cb^}Sg)3MAY`bD;maMgLo zk#>dZ+weLtIq&#jGv3` zgjO{}CK0kzXd)`F3RQR4gPRSRv?Gs-gIM_9*hnFh`l_&ujZ)UcM%CJw0}Gj0 zD5OEmQc>5-EfykV!UvdT#A2$CM!P=|vzSFYWMUudcpycN`UsiGkscuveHGIVnc%Be z$b>H^6*AGT2PtOJ9Wt?)MLT3-pXzuZL2mj8naGVEArnPx+94A>^$MBrNvJ|5w$VZv zvFHw&Sj3_oGEu}PLMC$3N6170qX?NOV$%+p;HS5c316yO$VA?%6tUEnG&(MDn;DGPzd({#D;YR)kEnr9_HYbcakVV)2~ECbCb&6tjttiDFg} zGEvYdLMDpYv_mEqG9zSSK`TNgv5y5Xc8gdjEaedkg=aisp-7QOEG!PT%2pF}>dNFb zXlhG!xve`rY(*^an3?!qnisJMYgXdB(uO43@pgv>q&vLbp}Xtu_&y>QRx^V9wIRq~ z6M}qcUc@4h)M_gn|8TN2FJh6sCB#0L*2-u^EV^-xsKFu@4s(IqIS~t0h-hD`A{GuI zpf2%bPQ)UET6JeVV&TnQndqw^P2@Kov4}l9aLIebqBQ$FViD@6o)NKNOOtA4w-oqe zwTQ)zTfOYLYnuDv@EC2p91#mD-92IvldZJ)hnwD`-1GWyo}-N_ zVzF^U5sRfVC?)GRtUq~$e`Ui0G8~=3Py` z$-S=cs`w@v-RX5L18g+R_=bix`6hGmXQ8pshaGQ?Z`%3AH!%p}o4`|#SabtPeB-!k ze3L~igsaXsjoR@lNu(zN^hU z`}7=jMJysPCEj_fPsrk(2pEfZmNfB{e#*HE)$eiMA?{2)oGY~>1*j!1dt;*ZKjY+h(rw6C3Cyc2^^y=uHuMJ&33 zB;M(WlxGnO;i~hFBkhXzwc&MOa^CU5Xz(dwef9kF>j$dVT%s0tA+iN*R{Ty zBy$%2;OV+TH8g`euq+nqJp%*2}b|yl9ln_G;lthu1Y0p2(vZE$;NXT79&FR+-n8 zRyDn@;q{kyGb*nNRfMhSb#3RD*EL3rX+pYnuWLJaAy=wJ0F&3XzOW=?qm(tVQ59Z4Ft4k5Qzb?+V%9X< z^t!UyUFr0k;)k5$bv3tV+v_R^+!gn_%GnrRS2+X2>#EI=+Fn=ujqD%_YvOr#5SGG)&*L9uhlhd=?>uOHVw%1io z-|)K1(HLG=`JBV+DyMJT>x!?@ysqraXI@uX+{x+L?R7P$XWQ#4w{Lh|<@64(tGv$P zb(PzKo6}Q%ZFhRg!|P5@Ih)<-xuY^yedYJcKbxXZBXLD7jWf!|B)VLZ8+bAf{LY3 zoVUX0Tzfg3o>aQK(=%ErCHmW&259cQ`S!{HEgR1(rBE*0t47*KcQn!rP#W2E-egY9 zs9efZXsM33W`MTyOYe&Ds9sGDMguwrNK&F5SIv2oIX#7|u0%UhFLkcdv(=o0$!C3U zTtkUY^SuOY?!0L&)7BJpqfXC7Ca$Gqe8ycEpTG0txzlq^?6yPpZ*Lo)Yn9V;?S`D5 zi@yE0eeVl6a>h(3Uwpg{#gxjJnZ+q4dZfl9nZ+r`jb%+1XFV*({InM{36Q4A=Na8_h1MK5;qlgBW>M3K z{>X7-9Cd!L9R`j$N0mxR1hE_ElH{m#xgCr`i3YC+->9}d5Pq1 z*2G3tgzmr`H|CJphvSCB21>ulRNGH?FPAgVN!xLwuidY><3{e1aNNkD5sn*eqkW;Z z!vHQ5Ic``>CC3e)0al)qZpV#zPTGze`HjMHBX>zSZsg7g$Bq0(ZO08B6FF}9`dyBj zRjN;ZlWxb2`Ayo68~KgGaU*9*IBw*&3dfE7Ms3Fp{t|QC@bSAjZfpRM61)3N{U*5F_)V;4#2De6+N$4$d47{XQmd_S{KLt@JikfymJqv!P%ES1H|fSTq6YJu zl#76k&*ya*f^DJln>d7ky2KME%IZy%Tefj|1{J?abZ6af;>}%|XzOrIV>j+MS+IGR z`onKh8a?he3FRyNCT#sskJ;-RV4GUaZ^CXa(pwipZ(R?)l})~1`rWjtba%f=Of}MB zA8P8bx&8N0rNfqu=ao_>mhDv|&2K^@O^2nCP5UqNgGA+0`a(%`yfq!RonLBCj7Rlq z@=>_oq#H=mVI5b^{>%I(!d2H{9jP~OuHU59oP^0IU2oj}b=Zdery1Zz{U&T@Uo0lS zN!*3)_cb-!&o-~$Ci_D*z1BW&U#a{iD>vjfStz}avi-vLk>4b=t^M16hn$D-Jelpc z5j?c|Qu$5X#Z|NY>VA{(k%@1(_7envNyx_lSLS|pG?oT?T67P+mDF0Y(I9< zh9=~aH`NHD{s2&+9!iVSO}*BdL#B#_ii^m3RB+~y(cMu#C+hL!2%zysRndGGEtLA0cF`?2#n08pH&yCm*>GMd z#ZlQ-HPFm18ffYx4Q#59adOskydITHZ3w%@@z&JGc7ACbF&5RUX5v(5Y;^-k>Z9YT zsgKbwC9b;q=t#YJb+fAtuLF})q&KdiKBk$D&aA1AXOC7F+7F#RNzbmO=+IX(egB zjpD5Z9j7eb(qM)muZ|0gLh7S^fv{)jfb9#!S*4l18idDIg0?v^`;FzHgQwL+Mc+0j z){L92Jj6n6ON&0G&zHT5%(mSps>9c;(yeM3C zG4Dt1IdQVdc2^(!(4RIZ&Zs~EubdKeuu+YTo-Sls zEhaY7=LKKW%|=<)q&|LIVk4=KH(-U$-<;Ug!hNWZoILD;1oo4sy<2_cFfiQY9wf-r zN2zk5K5En6P#>jKhWa?XuD?ksbp1`5 zqU&!`SzUia6P5l3O1aKgWt8UQ6`ae%)_2xKZjE_kXK`^XlpnL1=rlO7&b-QoHWUmS z+EC0sy4#QbW;MgcYr)1iFLEoeL{f2bAgR@+xHb5RM%DDUEY_C2CB!aYYh@T$R{_Cp zT*)YOn8_$CVS2e`ht=)EkUI`FZJ|-VxqAZ>IA?D!qhTF7V>=B|YRTT3IkR1BbqA3@ zSPEy|(<31tb%*{I%7^aI-)wWs%WK{?dB!xSx&HPdcbKZ0Wrm^NEXFK@N8e@{c7|;` zDNqQjLns9~Tayjh)@JJ<+twkJRA@9ChfqpFhMuB6Wx|Q+M>LyGt}1uKFPkF)f1;Xj zqTxQ_xT;&WRSoQq0IC*Q5pK1 z1Ykpd+lSuvAny&+ghMciq3+xbzh9)RNpE{YZNfnfSg7>2h28WvaB3k?S^* zG_)r*toe}v2hz{C*EP4eyw}v?@?JBG%X>{MF7F?7d5?EO@_q>8)aK`1Pgo9=4j{qJ_u$e|03W@o4X7 zM;zt)wA<@?1(poUAwyEDt#JH9-ZJHF*S9L^Rx4xn0&T09svFmc8q8jImH)OQ*xL{L-a7KPNn!vK23IoY zBjA#rxLnc!F%Z|mWz~JD(g97c?1fc&c6D{MTJKr)l#i+LL*g(kr#@#r9z7L3E8nx{ zr{8QTKs;D1dlq{)de-z#v!nK*dr?@$UCUryULGyiv8ryjtZd8@R;@m8ODyURNLm!( z`9YFfVxtmk=D86z+q>Hds_?7nmyY_`n;vLk$QeZdVY8-7CHX2E8C~; zm+QH=_IDSC{b%|gSbpYpc0W7uo@w77(Tw8M?9+dU5t(hwK4ZVf#-I6V-YWVJ4DO!{ zivICI!D@iMj$-}j50Y^@dT4;Bx8Ucvk{=q}?{@`v_)1me_}RZ~MI0ZDae-6B5ycgc z4|Z6{&_CIGSg)wS&;IFOra&S#dKVhUQ{^>^kzY*y_=;eEt zU5LcbdFJB-PK#7)m=)hm6MQFZ%R zW%U%D_Cf1uc)#!yHoTAXpzou0qNL~R3k#y>1^ye(qv;<$E1F)N{iz?;@AiC}zOMc| zNSY416!k8PqI=_C4t^SPG^!7p==}S->3q66JK>c6@UVb>Klyz|)H_`Mkq_GCn9EOn zguyc6Klx98_#=P*r~kxn{2!lsM&ADsQ4jH?uI@WEV;Q`zj+~kejLMz#^*JTXWGP1X z(`8Zqig;S1%AMf%D(oVwRU@hiGTRu(sq6kHalISM5WlI~bbNx)gZR{f6Yrg_h;`XV zPq%-iYS5?rQVsfrszJZ-_g?(WkNx~d{{2t28gxIj;|-!|6c#31FuXd3AAJ;Gh+5em046;8>M;{E?yC5{O*Yb%Qr2LRqiSqyGpg$-ne*B*4Af!0# z(wivgP0M#?7mW0!1K+3mjt|xkeV=jgqdivT7Jc>BK%!6|2SF+dd-20ITimm%@ddp< zeo?R7Qw&(0q4;+(fCQ#PsrLQZZ}#6efrKahqNn9qR=c`TiY50%|CB{}dxTnMqxT_F zEVtmjaOMIW$*WCx8$?P#yEFSc^K$qqwQ!DZMd{{9{5F*!y>7M zMD(T3#wWiJvbrNrH$z_T?4-mjQ}OC-U|NM3_4JP*lV-9%Ix!6Do%-w61@Z(navw~m zUb`JS)#NallLFw2!)g+ifOQ1S?lR_?W}yAy+=wsWT}b8)+ux9J&ef>aNPi6B`@r z#LA)(FIpqyX>2rgUL&jq)F|}oOj3WgCFC?40T@k6$`Kt$q@$+>5s%9ovYItyH8lja zeIE^3T_;Qu4f*+lX~+wEHw2fwHv}Cs8xg(?NF%b88nU#nhAge)rH+Pt!Wtr<@GXtV zr}l0L-ezwID*&^Gpe3hG zjtE03i$CL!4kaM*N5?c3<3W~}#nPw*?K<(rz17bwKXiLT`9*VkT0U9%7}qzHe;+Eg z%m(C8*TgdDt^Mr*lB@Yo7^=(D2^Q?%dumlW16$8 zMU6)dF|!R@SM{qkjdziJf-hUv`Kmd~eWc9I*D5`np=uF^JsTmx>Evcjv2t_8%1!lE z2auf|fb8sycIrTmdC|RfHb2jR2p>Rtj?ZF_uA>G9ZUYwjM#B$$Dg5<~C|dJ)%`M)+4qs&3c4sd=8Ltwo)f6daEqj z%1A-Z%@PO&X1UR6)FYubBp_NKVL+Jptw;JMvATz5V}l;q*cffpdt|*V+R8{k)E?^* zTVj!h2A#x#*tDO3xN-5X3e0j#u2_%Qw4H#s z>IM*E#L**?ncY3Iv_y|AEsZ3;vZ9ecUbK~wfFN|dN95tGcnqDubKA6=fVkxX5DV&9 zkI0wN03zlO7GBKaURm*~)!J#bCNQeihKE|S+`}@r1b@ZC=u%E6Kv3@eeAHH#OO$qj zHOVp*H&=Fnsz7{SOVu;x5>^H7`&u~L0PFb;E#Iq!#5oYS3WV5xQc{#!S(zG zH;;rLK<_FNz9(FTw!7de6y62b^Bdee6n+436$;-Iu43U`a1{&hg6sJW?&&OEdjN2? zZgNk!S~%GSR|_Y*;Cg<8n=hlj6}WJU0^ttzaJG&*V;jv?ifs2}d}nN?$x4y%p4L%k z`8Cscex{nun{?^P6+0k_n-v_2i$i>9;2}Em-spqjkyLI}>ot zlFXzo#8*weo7sZuOytX45R-*KPgPF?Vwqn>4SXsNW&Qj$;2r@i9zZuY#b>^O5@`p9Y6^hT7EFrjwo)NQ`_m5;-s9A-VI@$3ouvY_qCTZ2FfOx8muW5~??M zy@sH4H~Q7B2wE_iQEJ|8UJB%yb~dusyvfbixbdU<|8$t7+(qT~{~a(+ne z$rADW7E?k(PfhspNX7`VEc9!;nj2PHo^SsUKj|`mh@W&>KbG5!pQ1t{mAXFy*EE*=d;}xd3L0mtC?|r)YWa$cG&gY zzHHbu(y}CNq|4Z=>1cOGI!t59I>l$5GG66+5dBc;K+>95Rz@pz86=q^9VomgNe0=9 zB1^CQPwHEdpXWFEf`ytWQ@#wNOyftp!b-S9nRh62&iBYUbSCM^ zRR`zqx}fcLwt!w~dVJumbou#|dB@8Y{?D86dcI;fKj@+2{`vH9TX?w;9sBigb@}yu zRa@JyFOQf7A8l1zl2rb=2~Tdsv;X48XvnS-{SWk?Ioa3tCl3rSb0~*;+Iw5~(~*5S zezG?i@Xds_{65)xYGa^^>=>(k-K=M-Av<*kL;Gp9C}mlhXB!$H4?&uw^e z`6+X$*=8-{Q{!LL*Ba9W`wT5SIAFj&Z9PG%@PxmuC+NUD;cx2+b0kmr+j;^`@`S&w zCyXdh_}hAdhma@y^(S;Q{)*wrrKdK8ysJghdT9%9HCv=7-7V6S?iPg(O=-;*=}C8s z^rX=uaN{8xo?Lv&zJ}?-EjzXwx1Mz44%-)W&5_WP?vc=w25!({Qx8urJZ08&7dq1% zI(t=5y3y%LcdzP6105K!MusOxPi^RF7Y1o5-94ly-5B(wfq|OPeugK9PqE8)cTM51 z>7XG!Y1Bk{$f)7T!Bghv=|V2i)IiQ#XjH?KeFRAp1<#~o@hy@B34i#)+XM<3{c5RL zDi*)--tnLRE2mGx${RzMOC-L7;`n(|=UO|9^Lf1qHL9`S5rU`~eH_6v=n^NzNW#rU z)Rm!$9U+Lz<cgLl5_qD3K<8p3y7Yp>GO*!g{wZFDB7(O%lfaVhQIMbVchGoZd z{6Tbln((TL#HPQ&=E_QMsn1-pI$$apXm5+9nP3lQ6vNkgHg4L4VEM_7C7ZOYnX1bh z+^Vjuf_E5S=BVMCs8^ij^POJxtI<0M6Ag;dlYZP_WFX^M{7`1&*Y3Sbb?B7X;e8tx z%&{-@c*FMM;nzMV<_%AeJ$kse^zr9?P#{G$iE&)4nnWfa!IB-tx6Y2ef^B6IJNA7z zi@}phwjR!?Gs=dVAX-ZBnO$0dUoDEm?D&nTK7aPBW#=yxiEo9wVKV+0e?@6fF@&vA z?)xbBr@bfj0j}#ElxXd@QSqxL5ztOXSNkxOebnxh@^sJw7@&N40^zUlGLSkY?bw%UoAgnomPq? zYlhYBSG#q^aU(Q+bmau+_kF*wb;Y3B6{UcnEBfuO2$pa5Lpf?j#cMx=V~;OKU8|(C zz#!g*>6|+^de)h)Nislwk+RSg&PS5eb`_7%R~d%-KbR(099J|;RI}s16=RfDlU~hc z%_r6D*nCpW!_6m^F3@~ZX)4(hh)KLx=~(vc2~!Cxh0zk#Q(xR>1lUGH{Hy3j3tld; z0jbgJPnh!8zk*~pe&_9;XxYF8$Llj=8gdHTczWpS|f?*_KBXWDh>+Uk3zBi|IRVrCN) z$nnwa+|ns&W8=RT8%t_Cv|{wY@Z8dL;p7TO(vydS$}A%n)5YxYzfrO9Fd2(Q%acEl zl%ZIAYy4NOXv(}aJh}1|YLDvs>q?}-H0jJ}d|o>0J<^dK5gT_7Pw`(oh=Trdxu2!+ z_Q}D+*xj)1fQAgm|5DP&^kpQVzPy)O++3z-IJx2OCcO?NkF^;p7Om-(WmP<|im!+gU$owt$eDK8FQt_FCJqyQ*TfLg zeWoQ{gvtaZqmjYvIyAyrl1rz?e?tSSk$hlyeK=hb-JumRNArhV%@^sDm9hiGSF7cX z3b-;9+R-PAwNIWbe&9oRV%Bw03_tmy$s&xKnjhUwwWg=|ppW$B%6e<0)or{R9wz@7X7LkM!sDh&77JLVT#-vVKM)v8Af^!HZsE;fHm+ zsgmj|Uz$mA(A9d zAiSzl5DkOJ?cUz)8AG%Nnhe=K9-;c1H0j>Q!w1;(rugQmC3D1RXV*$G@hAKJv_Wl= zB!s}|fMsJ+ZN90_nzAkDj!YZvZ%oodgRy?-w(CRfuX`VN8rSiUtIyS^wj0hATNmzO zKnJ6Tt2f0^V{<+vRm?y^vmu=5)Qch!TF4Dzly4!e?Tweh2|Lh~MJ}Gc_tazs)7m8)`@k+q z-iiBE(+SQ9g^zpf3o=KnUYaA8KshpN3%(PHDannJB3J=8t$y{y^JM!7}|MAphn@3l9_sEc;)jymT zE=s0%our+r@*J{IsZ~3!FP&mUr$8hub-Cl&h(yQRWgJQcwo3=S1R$|Vk3G{j5fWmSWlhG>8+P_c4sV3Sh`^!?xU%OyQpE?I?|o>#a-XR zW~qpZyWGWQLj-~SEAfb=2itpH-l8k{y|Qg)sSkwzEsnbL$pjeAr=xNP01{nci;m{^ zbG&4GpS?)KNZu}vxvsXcEKlaq85aJiI9wc>g(0}HB){X)nR%R)9=@iHMZr8OpOqN9 z_bZh5K<_i#I6|fJ9F^OPo<435j`M(WC7O=9xvptZZw#+)e^}~Huh`i|;M_PRyomzOPKMVjdoz85Q@C1b0#T$N-1aH4;8NFF+G^-p=<;m!s_j+8Y30`AC zdv=BW3R9E(IuU$Z0C-&hKilM;jE*@7C+_i%+8PsgB>F^ z&HMu!b_VT85iQS~ygi`{tc#2fs5FF%cR72_vUUFy3Y36=HV}K`?>AAb2X>A-lbFjd zQ{0e-sSNm<{7hQL*G3Suq#_843<@iG*Au9x;$P67IU<@%eZp%9awD;!$c4;q;fwDf`*)6i%IDQ$S;V$X(tCA*Z?nFaSI}g1 z5HcV-h*ReC4x(&2YT1VKy#k#HPQ2cLLB%pLEN~_=P5QbVHPKtx3D+jUc|R%sCh18y zo`&DX%KKYngSZ_3Y)rm@dtkWi+w0T28cP0;x?ww}htrMum|56c?8->9(MFgQOy^a7 zwP#NiyVXwr%ue4|DkFb?eYk8fR|(ssX5c96S;8Rg-0T(xgJYAX)bxcRuUIZ74NO+) zQdp_rJT+a`&5GvhrDElqZLe(0xn$0^MJec5fR_F8l3lJmsjTm~ce-Q|*G2Cw%W>8; zh3V?Yvl53Uq`dy}FEo?;&G3@1dcbv2GIeqGENA0h6R}N~BI1gfO(YFC9Z%$8pfL;W zcjUlWoL%U6BF_nQ)A2;koW28vqbT>&)8chN?A=gz8xy}K;$ZOre^`slPo^%7(lWyR8(f|%TgvP4J zT<5^U-9HDOo^-?0lWur=(trmDRFzc^y3PSHnhQctxgByN#b4hugiAxE}D>6ut7dJiT6_zrn6FDk{IF=q>^*vAJhCU4y;In4Hw@UDq;3qLrT`bWe212d`8l*Tp6R(}k z5{G*r`BiHfL}b!ZwJ}Y%-F0_Dov|4yJ$Wb8DLnwy#(Sb801bcK33WzjICaHw2@}ZY zixcYnGo#_sGXs|4&9c~}1wLIFEJN+)E<#p}uxQK?WUg0S7ep`cu}I>%e48vwQ$&RF zQ6kQ_(o~cTMH!#0@Jwd0OItZyRNTE~jtbjGbxj@*_3`ISpsR5lEkxr;av84#j(Lg*)dti10^}n_Tz%luorz{T zgsx@-W*tEx(DP*QK8#aB$r2^{A)dTvOaq$6M`^iN@G5rsulMc=u zo$J4}o{vd#I?QYebD#7jBu0Yv4CiLOL-R99BYE{8n$i#ZX?$UF(q7UpUfLJp{vyA! zC-|!%M|f#vnq3-ZPTEfoANE&x)m}NXRlZ`*TD@>)YuewSo%9iNpGSsN@(5>MSm|^G zBuroWQD0W4*I(sH_6S8@G@E2;XE#|0l>wczpe>4tzAP89rR6`SlQU5Ei_k-ITW{FvCDTgm zsstm>j%7OKOGMCZUFXd#VEZ>RFBm~zyrv=@&4ydF%#X~~&GpSQrQv*w!^5{$A~Uq=9zkFr*qmSwHB zt9q+l71P=Px+al>%@Jj*W3IMVGbcC3^X<+AKfcFFuz%E!_}Ta(oSJz+C&8}xNw9WQ zk%Z*|odg?)8jb(GFG`UV@8go4#W_LazZdC5pu`QcICf|J|1|Q)DK_H|iz}@N&mV`v zjDN_}z3@0-W&F!th;$K7C-l(hNI%P8awog~?9kRTEtbLP=1IkujXsz5qE9>MGdU3I zhr3F7E3DV8m-CZ~ty7Q4e&8$?MVsY{xSwp87e=48H)nB_-}wLZ@v$;zaWvlepI3v% zavUEtMz1z#oWpyZXJ`RbqEmTuTsL(bul#K3I9?j6;yH&`#apvGkK;9pwb{wF3<5T& z;x~FI?_NXqAv>CF?e-YDIR0^bH6OY-@^SoYuePE4*Z}P?&IZp;l^vWUigfx_e_-Jc zjM8b-$;fQVr8shTFX9f5W?dl3gi8!6UTn!F6G(GTP`{berjHMfr$d?TsOQn_Kl;(q zI%V3H<&0*(_z|WkKVkaZUwYxnrN8)*U;S>a#%LTcy=5lJtKsbBf5*~I91Y7Qr?8-_ zf4?|H6FGDKizeW<+B9%PpOISB+^3Rs;`n_omUon_WnU(wIe^~Et0pE}OsLtP8HxEr z%R4nO=@_JPVwy5}=;V4}U?q+}Xpwr=>1p^}?5KMVf}iq9mg+Kl(THcdYNI?Oc|@{_ z#{H;H7}QoM`|B{b&X5odb~ zi%H~pSX4u)5J?kKl{j!t&F;75a@Lu2t(RQy+MAkN(^2;tHYQb-ja{x`<4&h;*irW^ zyUUKcuR=1Wk*kX$UbEL}_i3RXj?fz2HD%BD+X<8>zWQ5j7+NZE5hI=d|} z9r;PG^9Fk)Z97gwhsYu5)sp%W?G-x1-kE0>2f>bi#1-m{R3H&!qc1t#`NqznK5tZm zM(Q8B?eCCyd<5C)jnAowImd;|w}AWB7Pt3{o))sfofG+rvGe=cS(-e>6{9oaG2SQK z?Qu+Ne&G3!SR)wE8)`)DFzsh|X@qDgZv?Qd5ePVI29|g_5)_L&nt=e`vl-^z-Q&PV zc@eEM{!SdR9N*zpL)AP1SYT(pC)f5;#V=U5jrWomFOL-!ggCyEtKu=R7ri%YY zpB3Y!3$pwzv=9oa5}~t>fY^s-Iu7z4>S{DyguV35vmQ6rS`!@`$z#t%%#^A!13m+wT&`hPYs~Q-9e!0vo%dVhJ3mM&~5CMHK{&V*2QQ02_91M!BYPC8t zs4VqA^aolXA9fMi-q5u@)mE?}5`C^Ut>I{!^5*-QS`;hd%irl>rUjOxZ@l-DC-46N z@efwYKQSA;pDB6a)(JPx_BqD)?@GkSs?q{Vv&^1_kxzshPj`&Xp)%X*s@x!jh z+gvWy6BxAr#LLwF6MMD)gM$Mae0?VoqraaHU_HyrLjm@&#jYf9U|n#1ctc%4KUFP9A1xuNmjd6|ZPXRp!!wPiEBR!RzJ8eV7r2>S1Ab@nIi_sIA& zKW)B%2L?^U>yq@X+sg1NZGI*m+1Vde3q%e33zx9Wh53n4TW0vn_+m;j+vtW(trTl51mlN^xdnpz9RcB(8iM12phyS?yLcb|(;wcYSHfv- zpVMNRVvx2G-Bh0t^aozUAF}D=bZs|8X;d_jC}?uw4+~^a8LavzdV97#{#&k8Gwa*K z*)Ll9(eXcu^fLdaBL6Qm^8a|`zt+hALzX@sztG74AI#j?9)EuXy~^@`-OZ5kKlJ<# z=5l2If+xNb4EI=8Xwps-t&s0ck)w#AvWq|Ll=lU2<${?B}5=!+{T&;xzwdsfSqp0y9QQN{9wJQr;( z(^=NF{39DTJ|wv~oG$w|0jvmNRpxLUe%Z4#mr0&M2 zmo|sV6*i0{oQcw5%cNpxS39$n3G0y-DSKhECR;%3v;6z^&#HY@8vx4tPD8si0~}dH zRQY}zLe>UIF_z}y2I$^w&DWH(&O$V?_;It#eIqVeA}cabYDSd>@|D?aemOx=;Iq|1 z_9c+59a>k9nfVl7^}xi|r>Vnv$|A=2rrTDe@m;sx(TXD4ZhdZBc3F#30^~(P*%~d{ zxRSOz`24`u*rgy*Mwl60O@~^K$h?5@XLcAkUf;v+V^o|lEs%j9n^73Xr#&O<9RH?P zpp78+IhZk&wsi&ctnu;jWKG(IM1YIH!3@Rly7|&YDBYzmxuxr44Ta7Y(EG|p-760b z6yW1&#+Hp;tN??4RBVN{-s^k0asF4+JC|a#E{M8W*$FuP_wce~1RCRXA{}!_KS$xM*VBa@kXZDF7)kH0}u~kmF!_SsyN{a8y ze$;Yl*N;Z7M|=97-l%OLpE+VuJ_NZBPj5F7# zt@fhi_p#*|ysrlB%wCx1w3I_iD=xhepEnBGy1_=&Jh&g)r4iIpYs5?AhW^J+<~P`g z+DLp>Mbt+EA&I+rG_{YW>&-wMX&&s6#YThsn{`A>K<(j(mP^e&%g8!8@opr)rnVc% zF9|q~MXN=B?H}$D`+ClJV0rfG5Hxd5uosl!wlcvy&>04palDj;{TX2MVqZz657{vO zrBKC7l{?sN{C%#9Gq7lVLB8XEQb}nvNK+N3X3u@;tuwngm?xaICu+~Xy)!9$$tX;l zCN-q2D>)&?p0`}gZOvS}%Ho0hy)S$pMjXsjqTI=FQXb&d;i z8UNc?56AubVRNS4RjNeiM#;97HblSNMKr}O`rqT*3k_p?AvQTDe8l!bJhf#jwcUgW zgE9SSL5vJg=9Y9sV?iY?b&3bSmwgMuHCc(dy}o9TC`DY$qTiL;mV}B zrH|3JicNhE#V#lI)i0*=reWOV!z<0O`T`gw(DLf%neQ%E*+4jvRo5ZPe&!Tau&Ii{n{NB|7tLm@(SB?7YO$$+)@srJ zMhfHZJv4m4E?hM05D5FP>ZLB zmG);9d;{)b%a`R!uSG`RA&`7}*ZWP<>pF>dY5FLoMN5|4% z7yhV}s^8EOEqax9MasX96k7Mb(kW4O(-tLZIHy*5Kw&V8H6A?k-P!?zht^1I5XkC? z?h!$4(vzE$6^4$Rwb{xyW%s05Cu5bz*ob7*tsE9(EgUM#b*Hx<4c2XLr1 zj-oW{MPV;H|B&~eHDSVDNZ=T1gx4XPErxVkJ!-Et%Mxu_H{`v*9#xx+IuH-*+r5qX zCBPgEL1Uoq!9l5zwNvRXR9?Ss>HtE_+vAY`m-TU2lrmO#nDU42>;} zHB`t{+{>qdDrptDelDv~lX2 z=)ldHZD)OG_Ivd%9bn1pY#2hZe1B+V!N83YCfZS?ShEilH<3=0b)z>#7EL)~H5cpO z1fOn^G<^T`E*hwcj~4v!?W-Ui(Su|5pf}yoMteq(@;dDV@hkUeI@aBEOZ%Lekdv^a zt5%Dh_e>8JEEZlZ#@|dwEEvOCUZ*~!4R39ccRcHBYq(YaSuEDr_ze1T$p;t{T5B-7 zdWNReXz}gSL-!_%7TJmm?=>j^!Eiaw6+M)3tBZ69qe7mVW;-6-lW*5AX( z&c5qZDKrPv0KP7oy}9+6)=cw)F^vn#|Rg5X{!O9~Aelx&vC%uc#7c)lQS0%TU;=wp`6`L-BF?KjJ|7aL4ZYYe4?_IoLwnbpYv4pt8vEl#rm_LYy$WYE}pv=TRU`srlQL1Bvm9)I?}TG}>s8r6LK7KGqh|BOmPf zKwGbQu%KL3W2~xWX?6F~3mTqThvSG(^~~n^Im@86!ws9K%b_8 zhf{B19rajpV>Gh?ork6?mP(M|#-q8NvD7f1jAG^?PUH{xat0~r(evagkh!6S;oGS~n6W^)xm88Y9 zHuZa?ikh25OK}zT7ybNk&7oR-NqO!_nGvoWe_v@q^$>@$eH4Xf+hx{gvZAI~DAgf5 zSqj~BS#YG)X$7Z#hbq0U+F@`h)*LiN{pA;@wxn35-0(d>_K%#{bw#SX6u^a0W#!0V za@CIHgtlaJx?$Kd8x71-fx71<(lAvR?#JQp|g=~6L z{w%ZNMAv>u0rUf}RbPbuy@>I(w7h$Dh~XzcWI7C_L9D;9HL&cd-lEn|O4bJ#MD3|aad+5}wvcQ~hS>TY`ECys>4ubI<&Cb=dnTBb z4YW0xTtW24%r4*_(#ANuf@S~APPA7oy$#p%8{W$*{~!UUlaP1oUG@p>1boiY+kid4 z0X~Z^aNgQ}5jkHpm`s zY>YH#WddrQOwR(Uw~m{U51LBBB_aI0rQ^QN@~@`+Y-q?qw3IKQDp|L}y=F)4XK2FB z_QI2}&n0X~*Y$PatgnxVCFI4s?57N?HK9?hNY|crQOv-oMx?9N*u!j1P!vowD9m>O zMIY5Qpg0BI_QD?Am7rf+qulNB}uegblj;Yb{W{6|3wPNg*$tbV5!4AOHfbXJnx|YM>WI`IN+6KI9M)CXytQApTr4g-2 zk6u|Bt<QiC=#;7R4s|-OM*qpg zxTCX+m4clr3f+aBTnBHn(`6{Mi=90G0qg9HT&1s@k-xk=TCTH`*hcz#Pul`yyf3zq zzHa;BX2M=P$u%-@p#HB%V>!}Y=cc%AM{r?vjRGo6;aAMA98|3wlmFKoKhlzN~Z zrAh|uBCy=0)tkAQLC*hOu-=x6&n|dx3nRBF_jbX1TUZfI zwPzQ+w}sXdc$3uI1@CPk^a5`Ze7oS49P835zi4j%<=e{ZzkFLc{dXBh3)!~kT0#(A zQ?2E;$%_!g!Dt3dbIGz@zU^H8w{y=0w^qG3eG7{L?e3K}hrZG{Kk!!EKVMSa z7G5qS)qXu(Uo6l5-#ylG*n;}G>z|$Pv3Ylopz3I0ahv}wEw8Mut#52@ZI2IaAKqTG z=(ZoNY9B)>)<9&z&h)g;(D|-Jr-x7aLtk3bpFR7%oFhOUf)D-Kx$iwS{xN-sp--Re zHsTWf*~h-u!m-WR1T}JEvK?8jbI1F$KcEda_4x)j>E-Ts$*pfs`jo)0oe9i}T?KE2 znFbuT9DJR0xbv%utuM9q9xB^==+)6)ecumRKCv;L(_VV3P9E(t9U^;p2Qo{p0q-BP2vTo3UPGvXT zK<_7J*5)nN`>f{rB0S?^B)lZ?&#|Syz8f zmuD3AO4UFs%5Xj71}3ew3xm+-)jjCct?qzMUttPM;&_d{37z?4Uv=H)5HlrsDVq{Z z^6$o2Yd^F+TxUaoVYy4^>1z#%j}r3t~~{pbUZCz^V9XGCJS0-qb3Igp^xwUOk zw`@aD-vxe)`PN>nUMU7AKd7x7Y}eF+L!6g^+^6}e85&FLpBos&S${GP+qOQGDylh@ zsBMe*pd0NW4l&f$Fc$Rx z1H(8m#3&x#G|>`UsGKf0^VwokxnZ@j-iKF*I*(?pln2+=(>^rx2Zh+i;;vC@I~Gs0 z-Ms9?4>2h-B!|*GJk+5C=O8GVyIlN6Nbsq2aBXICucVwQ4|^P=q-jth-MtNQsWQB^+2 z=_?o6k%sL>O!kdV4xWNmu(scETermrB8=FSih@Q%PMt<8r0;Y^)7H{TY{QwP)-_r@_&C zTyB)l)bxv^hlk%VcpTBxk~C~R%r=U=2iOFYrt`*SrVG9O4G#~mXs04%b+I1B_9d%} z)pUofE|$|BvbtC-0hFTZe$moHgMzvspz`z-qdup-lB|rn%eMu9la7L*G) znhde!Y#-Ri9~!(M0v*g=5cOT5AGkJ}e9^B@kZiQ;RCyxE_eRNbiOnaAk|I~Q*(qT5>SJtduJ5;gOnMx)4ffwHsHP$?KdO|P4U4Qrj0 zpelAzk}Txq6ZjI6L6#0Z zgNa=p1_fJ4t@(Xv(=Kl0?KQ_TT%j|u)GLf3iWY5v+I8aZda*p&fY=v`b=$l7iH(&e z5L&TVto!1m>E`CTwh0Pv_mb_v;6}`rnk3(_c`JM;25mt)WA2yG;(0?A8ROkpD|9q_ zY{PrcY@|(CCx>*JO>9}lhT4=XAMCA^yAb8_X`^)m#j(55pLRmlVOW}W)-ukrG)Qi( zV!Z+9F>)NB+tQ*UpI81@`R_RwG#;WUbLg^s>6se+`}UC6IXL(Ze~5w>qLvO47w^AWzO zIw57zo^9te-PES$`M+Xwb7?VXR+MGnrbj+Ly=!**1MdS--(@d*P#zJJPL5LEHk5l< z!_=Q0I`xJg+&bGfhr;;%zn{VF&yMJBa*V9(5I#AqSG+6dWmf>@nANz=>pS-PUH1Br znyg2#j;8S%nS~MQVeRQsB^6jp& zS;aoOY=JtZhdPKUefSL<>RKx*1j11h2*;F<=M8~y%ml*G7?WcNhNHftp!XSUbGSG< zxl7Fw%fg-}{1aoAtxeP8;YWMMnanL$hYt_Mn#G~VdVk-3XXEdAwD(K8+%Ar>o$~vB z|3iaM>-Oj;PZmD_J>O-C+OF>MkOK#uZp%)kT`!>o!FOaPs*NeL94(q0kv!Q|u7Lf> z!^0hZ=$G+qHKyl=l!4&x0zDN#5b(-Q&M9zvgIBzEG0S#h7Pqt$w}=IH;Fi0bTmJqq z*yWep0VjSrN{wt4Cx#KDh+#zeJI*k>ydj=BY!&ZN1YlHzj+J09d@3}infE%m^?HTd zH>=Caqah{dyl9zW=Mlx)C_h&o9eK@aEqSMOEIcQF@4Tv8HSMb#7pU4e$iW~iU?FyG zRoBsy;Gtv2L&j@lXzjh#kJHu zn0Y5Bjy)Ea&ZNFIHx$83v45le4#&L-zOESb(y zu*1D1_xh>gkY7k!T%}@X$ zb9iBx>BMz$qdU`sH&>EUsjn}workvX5X%r~yGh&grmyu*_SGl7ne{FYncAWww0Re8 zR$9z(%BOL%v}9lPd_0venOTaAMZRQhDdrGqsk6;eIm4hY+nI~AOM@D^67GfGsd3fOnkt?pD>R=172(lU^RTBEeA zH8$=_%bIQDuC#i0K3nfj^={Rj_1=%}Yz&ikrxG&&-knO!ka~A2F>8`{rxH&jnm-w1 zdcI$dRP{`|HpTE|r97Jwv--}a#0=S)l$iAmAC0t$hXG0i=C;ihvSn;r4t74aG=wbG z*p{Qsg8TYtQ&!euE&-sltWh@FO3T`0qph^8NjBO_%UWckt+e`RUqR4h%%j1tM!QZN zG1?6(^3hge2Ea#Ki5XHKZ6#(+^3hgeHljYvbrOhSZV-zPvl6q4e3+G(LGoc%V%90A zZJ3o<^@_$y!(0+ReHNsUA-tRtv$kAHi5ZxSDKP_cAth#DSQOr-Imjf@95aTD0e8r& zk7}eRoOQ86uQo`JmXcDDUP+8so5V=z`G6QPDlKcR5u?(w#u_myEo-Y0qtddb8Zj!Z z>UOpAe4Q9Yn-wwAzASqXqY|@nofwsv0dQheVusX-QHfcToEVju4K*+smIj5MONrU* zPK?T#Rpi8|#0=7z^m+#VbV{sxr6k6ZFTn;F5p0IgiBX9e7$-(0W?(L+*E28|Qep%b~S^ZZe`esVZfI6!vF>4WkBIk)T zOY21v>D;_O&ZWfcb!Qdj%qntLQDO$^OnN;7e>x>rol>$&DK#huFk-w6p|gq-Gce97 zO3c7qOs{8PE~LZ^jI)Yf&%gw$lzhumz=)kPFwQDU%)mISC@}-$tfIsWjI)XoGce97 zO3c7q73^w8<0)Y33aj?Nio^`eg_M|qc|Ij(V4h2f85kDhN0}KI_$TMvMe(iqA|4UH z;c#-3qU7TXNh>zOY_P2cxz4ug={no0xhyG9Y+Ew&<&+Y3)+4piF+L_K>keaMlCsV) zE+#4K3S(lDvW_qwCaLNMb-^Pw7KWiK4zBZiaBxE~I0q{+tNe=br4loc&cRB|8pADv zqr{9PorC$CC!RB^S7P?MbFdP#ikyR$m_a&|Ue9{ubV{uHq~zdIm}ziZ;>0!bh zU?pZ?E~eKrFc(r{2F5v9uV-L_gG+JZ9L(RmXU-adD>3UC=U^pfV4Q=Mn1OK)R$>Om zIarAqn5%;Qz_1i2&cXc6!8iviF$3cqti%k=^9Eaq8JOo%Vg|-JSUEE=!NH{(fFKDj zKT%Bur&D4E=DJlO!IOcxmJ%~CS5smJ=1NM;z+6^hr3T1bCjX)$0GTW?*>WKhC8GYi z1_0HP!l)+!1VNBO*QXRlg%sMKQs^2|0FhGE9er&UA1NVRvc56Nl68xTm8?fhrevLA z0wwDQlO|OcsQI?WB)LEkER`s!iJg!nb?M}SgtV;AD<&OC%W%0EAuYr1QiQaued@`U zWI2}-v$tJ{NCsuqoJ~11JZDm3))A*uV$~a^5D9UrF?5Y41L!gYn0ZSsrJNa-izzX~ zav>#VSX_pv%nS?Eq|qq_n#iXm(9WjBtYch;06y=S(Bwb>60@GUZdE8T z19L4UW?)=~C}#%dO3Immx$Iy{frf{ho{^Y3Q3DA6hXm(uILG|y$w!0W7XbZt@Kj!ax;R` zC;uSxaC7J9im}9qlC&bGJm<_FEwBB@uUyhH5MLqN|GCpH$$3%^Du=_Gf~ zQ`3>OWr$E~aNGY7ue5H-`=Z^(Hqv(KRwBhvN2(8LLVc_*p^~#! zpBWDa(wcUCRtE^EH6cKRfPh6MAh^r|DqG?DlC`*vz-k2(I1(l#37E9-WT3Neo%Un?iOf0kLqZvCz!CW zVU?ai2!_SZ1x%Rbw{$CC=~?+cFGc05Mo6-%N(lcyIH*8AJuqoZJDZP&EEZEKqo15cYAXsv2N;hmu&#<}b9QiYB zN;hoEpJ7wFVN-gBP3eYB>2++Ei8*{1HJFaiFXAOfX68U7XTV6dK2z=t7s&=o$r&t? z4V98JR3sZHCD%cn1JonT_2ZMQ36u5^)48v<+muG6r7N+XlBrrNp7kNOuh?!WM0_&B z1dGTlHcQ24Q_D2UzC1kHw`Ip=T~}?*(!;~EBeOQI#O;|8m=1vnc!$fpJY-SN zbbE57sb&=0n@dZ+EWlQTda2X9KF;DYE!<-XeSF!&g1ozI(n6xo`a+_+XR&Y(JV$)>(k^eHA5HJ}wP+Lp7_CJ*iYB5ZO-Fnw)4bQot=B8u zAgGsj&DSDnWubqcXls#dU7$^%8g7)Ak!mg1BC+nn?A!Ai(0Nt2YT8#fYBe9)LkY&0 z^R002#nsmH-7P9>ujjk_i47JAmrcGK0_s}NcZ~H)OiD)G#UWYed=tdfWz?-HGox-6 z^qmn!$!=syx~}DVJCF4~qO=`b{quvm+%E2p^+F%jtuHD%0un7E(t^ITqm%u~p*5EG zYL$2BWN_|uo60e9awZmpAmqJL*UxL^uBnKp>};>`epGX zYpH7l)7Qk46Q${ABcT;g5TIRafyp&}fZ{sA^tD`SzOLS|C-i3#PqJF{4*fZaCmAx= z45rg~lC?%p=z-V8ldK2ygkHNpo>WvMMPE;T3r~FRPW|aK`}E7>NmiPkFrr@(Pcj60 z0_x-OBtxwywDf^^lC@M%pti4!Cspr=vSn&NPao=9PR-NyK@amHZ+sPRXdbWLFfD>w z9*iehEv_$2Ums60WUetxzdD{|t#O@U`i6Lt^?+*)Q++Svnnda~&DmgkBTqDsXV~-v zY+n;kGHiN6ue~XrWZ3kCp5~J;D=ovOCye#i#*+-2o-m>h#gl5R)rWHGTwL(}l(*?D z*P%m9ALdf?dxqJyi0LEoB*UyHV17$H$uR2)m>-QN8D>2J^JDQO!>lJ@err6bW5z>w z8POFA#q@1lGT~<^HSN>0U*``pka_^fulENTMm+%I(=k_fQYAWOZ`yjrwvX7B^0RD_1Vn6QQu`k@9|9Jg66V2Cao^?^Lm!?(jtjkL)0o{{OT0_R)4;cb(t!a$fH__ug}_WJ#7h%yZ7T9m&W| zW(MRmOgnkhCQh2gWa5?8fBJ9#x=Oq7kd;MOGx3Eg9?^Q%s8g>l4HzQ8B?dwfQ&R*r zAW91E;9MPZI?H|mPsP8uk-p)%w$FvC*s>Hyd95kS9$x(@$E(4{_Xg7g|~kz zzTx}OCuHg96Y^tzeawW_7AND|dEOq5Z|8XXcjDVFZ|{n4H)-_U@eOx}J|TlepLm6$ ze6fQt`d;cs zYjrLGPN=+XPqg0)cV)2;Jf7(KQ=LHrj?6g1--}|Ob4PH=mQYnD=Rs53d*&#W+N+&4 zQsiw*pUz)7uGjg1DioRzsnpj_*iIKN``?BIoBh3ArG1d;i6ng_NdW|Y)R)USDNn{H z7}n6GJqQPMPxlMp`*%(x$s>$t!iFB+x2pHC-pBr(n~i-(tcwdyGQi{OI^y?h%RuZ? z#r(Uj6LbV0aoA7Z_L$Q@I?{(DhaGOhBV0Ek7p8tbxn=ej{iX?3KM=a48b}F*)B+h8~ZDoKi9Oq^M1JQ$= zRBN&1tYC-B?qN?m zeD33H1lRTyu&eDU^i3PYd2{>6hh)o!6tk3;GrK4pg8S^@WC(x2>_u|+YFnTw=|+G) zTNKdojP2=s_jq1LmCepyMQQbAPuDl~VD7Q}!H3OL7Jd zMz=pz#2+@WbUFmoL8T>1vs$hj!VUXbf>TJnavhv~XXu+q1H@@jDHmr|84eDq9XOJN zUHo*!5d^4KkKwJZXViq;n+I25gH+-}V8#vFKQl`EVPI?006wmf-T$AH2WwL=5IDtC zFlfe90s%?D74~X})V+iO5PxvJ5(a(E2>u&T$)Cy5p1=bRgOjJOA13fok$FQH_}PLm z@J|SX0hj{B2k%Z87{gr)opA!8F4^LQuM32`?aXZn1m7P}u9z5bE%C3WU3b zuZC>U=~3Je2p%{Df@e$n3k30h{9lZs7YO3?k`S;hXeSz4ZGj-p3^NZK;Ek4Oq$Lmr z`wIl?~)5LqfL}WGO5c2j6+TSIz=-B?DV6+QwPu= zUfTWSf=4u;sVKushlWfj$8(leyX3+i{2!*$DKFkkE4cvsNS%Di-d7e&oRDK3NsWvL zZ2aJ7VClx@Pk-MJ{MRr4>5bp{;{S^tEVK59B&JLjoc{S=dHu8h@|h=p_#Zvtbfc3y zIw(fd7^d*jGry*C#~E+lp80;>bRY$rKt+-xB`X@i-c;oqAf?&sKStxcd?Bef^{gtN z%HBuDXy^2I0DwPWgV{w$gDUi#MG(a3U6@Fe{ z6{(OS2S2U7_5(tLt0*v#&9iS0Rdrsib1aM`wIAg8q_IA7kRunU`?}R#6Ye->Ot>4D zpA-1PfQ}k-$R8u!!&AW*9Aa=r5G|o*ITvKC8UXI>9`K4c9FTP$SV~JZkVbPwLQsul zgGa}O6_j^i6&{*(2hDfw2hFH(VHx$$i=@Km58CHJKof!^9)ekfAnStQh=bre_JcsP zbs@rYNL~hK1{nu%ZVwx1Z_C)Y-@)>`-?h)!bPdK`VFSWnhJYQyqK;SggWw)uqu&L~ zQ3uP4FTep~&g)?+2L>7?jtyL6N_|3l5K=H)ZtfWmd>kn6Jrxz`nsMF#BME zi|;`kgO!ye+n{YF{l2U$1~kXud_(3;xmCXUEWfjVEUVHvL}fGDNKpO=} zLC*y>^x4DuBY(EAezpPYum77reC;#8`Hw#Hz1}VG4g=OZFg#-0K8!Z7o0OCNo6der zcKYN`HX2ls1-FX)sBiV3eQD#UciP6=mu6er2M*qM=q9+Ql}9vmnnQ1GnY%bG?vT!MPJ6u*pisHjxt~8%b1~AD&TLqoxkAA zm;qQG?JVbc8>WnW;&I+-e$QBu4e1I88>_M{eFVvTq!dVndLMUX}dwiW`VwKexzjW@(E>-zr3p&bA5BrXq-LeNV zLK(9sN*yZMY6xOECAW3l~4K< zY(+IvJi&i)aJbdQ501hMZcXt6EjKtSG!0D0jxHli@wcv&*VC3uy*(Y3Z@Au3Tf&ST zC4ww=6prCLn%!1MGdl=U^WSvAQYc;SsB_95DNRo+yOE&<8@2OK_TnRRi}|1%W%4M~ zTnqenQeNxecT%2p_&X`jP)7BpNGCs&Rbm%kz8AY{QE2z0{<758GFe8MJ7-ZV*ft0Z z#d~$mqL{h}n;#v{C`C(JW+p{jmm!qaU?g^z{J>86njI5ZasAmmk?0pInl5rJfrC$5 z^#!}Ul0H(A!Z<(g4<}oW^HbE5hnEt<=$@S4&da_f&ag z?sK~DpR^NPfQY(e_a}nk|nsWBuYp6)QW4V z#foz_sE=trXLvEB*93?OE+-mD3Ps#~j8Jr0NDoC5-RQv*U8s1+v!p$3FRrvU-e_CUDx`!-Fi z1H}4zPj}ALT2*yx)v8AzRK@|pQQo!U66RLiHulEhkfv!s*zxZ+9K%jbtO3N@T2FCx zwN_Q#TD9sC2wY;2C=;ZFH^Tu8 z)Hh;=U?qN;41=|*Az)n%gO>Pb&x8c->sG_yrN&(WOn~z;z)z*&D*~8^=m7BNV}<~} zWElo(EiU1~BI{^Gl7CtY4FIt9SxT+z5T@3@6Fz_0{Pg@Pc zFg5N9U_!Z<0e(JyMF11~9RPkgW(Z({$peO~8UonWFn|dvuL1m01u!-43}D(NDBOVE zhEHy9_qL5sz8=3I0Ywx!FqwdQ%61G&6iGr6mQIF=sH%p9jH_W%hVXO`ti;S&t6^e> z8dUbtZ4_DY2+!13JmSv9##axIU=jrW&`{E<*{%uXX1h(Gia%%qIsRZ1sH!1F&DAhX zt>O>TwH$viWy|;jTM6zQzbmo463anXgQmiC!=s*WZ1grvXjB4L^ymbv(PJf&MUPG- z8$DJvq|v$>rv0Cf@<;0b(L^Gw*ZE^XUwKVAQIj;jZtl7$D z5VoAnVA!gNLD+IuhGDC!A&b`4Fq5{jGGvrKYxp&*lp1Jhkl5{8ax@Uc#Rzg3jd~*^ zhsq|?$DK`PAFr%9ecV}b_VKEQbY@q>sJ*h{q%%7!F4%p5i0Aw)bd~X`N#~4D!>}2jcfuv8&fex_v;Ns=-U?VYLpyGX@QWD& zmfh847_e0h0qbfQu$N;E0sDg0Fkq>1duBb=+y>4}#x%;XZibzWcIzb zVId)f7RkBvZ95AV1WXyTsGEf|!&N0T(e~MGPA0#a+ZK(uC}4*>AZ-VGv>ER$P#!E^LaWCIQMu z4gpF47$4VL?W?o9ikIpY0~aqkCBSd1bN1f8F=BPAJ2kQ$0 z5r$*HaO_y`SQCb$uGM5pkVy>&fd&kT11&-<(118`phXx28ZaaZ&M+9X@KvFZG>?Zv zz;NhL?@$wl`&_F6oTrF~gS;3XSb3`9;Xo+Os#pyV+q@VaSZMNin03NXTc@hEs_OJC zWrdBW2*VaH1_NHeT4{ywS!r8ojCde`!@+<9!^6;6riyr|c|dBds=Bpm)gufWBpVEP zKWe4dLuqp*Mi{0f8y;Y89)`v$RfM6oN>yuB)eQ!#9$`>h27@_K4hG^|3#GAQYGX0x z#b7`y_b@aTsUi$DwY~;}sv8VeJ;I>tpbQ37`daB>D6MdSYF-R@F&NOOJq(RCst7}E zjjGnFsv8VeJ;Kl@*0Bh5&Xo4B)G=h5&xK0+HSGY5-rr z!IVlnBepr#5Wud60emjj5Wr7a4Z|=s?h4@NmRE_A^7HX40vJbe0QjYtAsW6~0bJD( zz^;Y?d?nTpz+b2UrpBECO!aHat3=F;_yvgvba`g8$%nI1la+utXPT@@h^mHoysKeM z{$^}ST>edK%Gf+LXw}?^cR1xUlB;2wQpF#n>xe%j94f-2_(P&qB7fY2Hw0H=c_o(bfFvNK zAd+jVMD^(=dX#|mK>(FV7ClNNdwQ%yvZ&M5F!lRfq_Tc#*_^butEJIE(9mkDM0E{KAD2yL1D9x($Ahbn%Zf{MW?j981h}hVc3)-1NoST7 zXD(Q)!6RDo*DyJFOF584&BMMjJS#0&Ji-V3i$`G4-7!f7Dc8VoC9~c^N~I@>pjb8l zuGGYLkm2b84#sB#;L4N~z%nJh^Q1C9HS1-3degqDAxqiSFiW{IK4lom`1B+pj)_mHSQXKPK)6l;&JbHp!4)=ktzvBqC_vLw6aY1i7%%NyJyX6;o?5kk-_ zRAzW=vElFn8j20NDp=O+$W4M>iryKu`9nWRuh{bH^I3`8?S&&O73G)i_)qB|WBXwB zDK3A@d8_)t3e|vPI8QEmoYJc6Rx%u>e3&lr#Sa4pm#DEAR+Hipc-p?NEL(CC!X3cSGytS5HLlM$i|Kq;jJOnKz@ncHRbzov=;dt09TxAh zcco`f&N&aju(d5J%BVaxTH(SnQISp-P3IF9#UTtRYi^!kJ{Kt|6(#9tcCf; zu-8d>xs!^kRvK`qwG<#U;~(_$hNAkbDV*wNW08xN=^UOWsEiNLPFkoo4=TUd2AVQ|e6c2fhF}s3pJG{} z2g-Uv6vE#S#Rf))C@oN^ZD|JJob$ui3{%@>t{V-x08nh~)5ZAA-1e_plTT}d)q)+T?V?z~ zS_bmj`S#7i8|0IDF679Dj0U-AfWTwm-?t!_fykfH*@jB&gmZmDS`k1Uw32yRq3@bhj#e`D0Sc^WW$0)n3$(Irv?4eM zJEdqP(~Rw+71waqMJpkzgI0W2lU71`Xa&k|(+UT}*VwrcgC`5m@FA3fEv6Tsn7q8U zx#Kj3O_S8s*`sSEH)?(sp*{P36WWvVyxz*=$9 znko*I)AE&DfASw3%BN3cpN?lTU)eab=-1UAh8To7MMVOr`=3*LM(;|$bfT^H41(G- z7VV?dL{T=Vgw;U8O1tJItfXR6$i14{v-{AJ+5@l3AtuzGFP+fusq7}dg#$shiUiiw zauwylU-1wRQwxL@8_%bORK9pzXN_V3 zp|Z@V!pS?x@0otK^;z1{C%8(1A18GvM=hFKS1odSK^##Wb_(46@*)b80aAkj-9X|5 zo@8wzV;KZP?fQq1PKaF6gHA*M)$yJAR3*7 z$s>Yh^4K)>lV@s^N0+K;Fg5W4#RHK|p0Q0H10)X2Q6bfM5E$0(c4qUWn2B%(#op$L&$2{mEh7d=Uj)j#dSgJvo&SMR1S)Rni&I-1d8iyNwZvsiqj{$HZ8anQW7ih zHo*-MvGvedHT$-vN*aqnc@+j_b97+nw%ce%!iv!lts6g+UQNqq7RKZPcNi4=f5e7; zV0=#v_)i-9sG8v8G6(!MIEa4x`T_+&0+z~BRMs^@fyabIj?zptj-my6E{tS5PEj#f zrD98|wSZ6cSmSwCJ!6t$6(;aTcd#Y$LoZC`L zWp}x=Tf_Rb_5CBk~k#q(a{aoZllR4CshY0YUG@)mie;|(4)6EM(j@Tj|O zu=&a>8(w*z{765IN9^y8;<-Fxuuz%8_%uYhIV7-wceq??0@scCGs}108zjE$VZ2}B zpCjkHD*FD{S$jEFNA!GAkn?=ddN8#ht|xY+Fyu5aHVbjc-^I|0LR~Ur-ZQ_WM-j*) zl`^MV5SMGzwNyFMykeIZsGXeXq}ob;PEI#WyYNWJFUOKHhxwTzo#3GvD@x@XvP;Up zTt4%CHTy)la=c-5E}WgY;1)Ps6HGm*HGES@7~5==qb3dD$>#+F${&ZbqCkP*zD>Il zPel2t$Ir|uU=s~cB#4C)GcWB9pWTy;hpnqAtCc>oaZnX0cQ_fUDt<2jSy?-aiH6lj z4*V5Xf(iq9=&SN~b8iPn-Km;$GR+fMK!B|E4TW%05?&}p7OsM-DEC9TJF3jYONPt)`aqdrF_Z{i$UK zht&w!rj}_STxNno6tHPitC8NET8*sc)M{ke)H3DsR#QtFXme^c8roxOjmt~5Yp34w z)Veg>Uk*4vzqcH4a-tyzY#y;rYd@3^R=m;;80Fasa1`$${s--*KX=`VD?6E;z&&Z47O`mlMNui7 z*83L?OKDwgH~(T%!qm@Th6_41+4e7{P`md<+wDC_mf&AhmiI+hSx$dbmX}8{OLB^I zgE1z`7tP{>O{oPp8tWz&69!M{@-;aG@S7n7GlXCc4!m#FxpD=3YQm5)oabT2(s=c8 z=f?~)mMs7MknU!zs(4|DQ1a+=Gget%7*<&}V?nfpAxLw=P+!%3PG(u5-G}k6X6*9k zZHV-3Q(B^m4UN`>;cF(~{%U!lPF8!kN`o-GRxkVOquv_AFyCJo#(BGkFpTrI5{5zk zRr3~M=;W06nN3W@)EZ7gFPNsqL?S~AQ+2_FzgU84gG3yXZNX%&t_7RcD$&GBsEH=L zzKEd>wYkOOsEMJ8i6;LY%sMBUOfYwdCw()_b|C;15&1wT-@kI@D;?2@fD<>G(c3hOhl`I0tPu*;wvdrv%yzn7iKgW z)-5!1#aCz;y}`t4;48}V?tm)G@fBrxcRLr4Fpi@UmLiWSX{PXksjqq)DR*&W18l zr9+!59;z4onNV(GjfU=*3IjI*+wsUd^@AmTxqOQmR0qV}6m#dF+mY?i7}1r@~jA z%|(2z%amg>68KZcm+Ww2Pij|zdldw89DL&bV%=g#C=)2Alrai*$7cg&uI)~gg{%&g z`K%_&Liui#;WcO;oC%v{yyOWr*H6Y3xRts6^s`c2A1bftHz=;ZGe|c=*w-!*C7E0Q zg!F22o8S{upc`|WM9jQ>=k}8)!`w#g$B<&k<)Oh1>Xm!Bk}cW%APO1@^LvAmandoE z%3F{1j>;&vG|lV~N27@*rF#k=h!c$y&fzH=B>3j&8jIcaiMB}+6Xfy5Mt!0w1|$*= zO`1*#w5B-viI$0QGAc9CHf*A8x`}3bx1VSZ98I*g-Yquc^=`tutl=OZmF4yBD$7xg zvb^3MvqUwd8;mj0>D{&_xHQq8JZWt_d6K@jCYoGSrhDIVqL~sLCRzhu8=7cmPr@3Z zV9W`RFF(<0e&+6pHjNW)UzEAFJ5d(0I#A}bnkWn9O{G{u*{vp;DDxH*?X#n7vnfV< zVXE0=b277UD|oVZonRf>JL>7N!eWb@dz2WF1z{B*#wtaO`U^s|-fFTHMqA0&4O~!b zCR;7Cigh=Wh%N0~x;T?W91z($Gg;|PY`J7jvsHbbf(#`-(xvwymL=J`MN^Wk+mfvZ zifu1j4-$8yET;RW$;ugj!!#e7mcQ+tTwBFK$=0pnfHeDUQ4lPkZ>}V*rUp2iY~A*u zV74%|ZBw2lvCuRKMy6}Z(?yf5TO_f>@%UnZfVMI zQkf|~vnjvjraUvBd}Qm!8NwnInHFU0CgOV2uaM37m{*Besk4SR{R)|~ylkzq9Q`WG z%hs4B7)du6W1^<~CfEY|@WH)hD~quB8=wuT6;8JHy@Yk12`^h&!B)BPd z`dpQ`iF1`EP22#ji5rnWb5%+UZm%uT+?LUt57F$^=BfiHh-ZuX^mA35%8O^tJGO>< zey%FZi{~oK5uCETc#c^jIMNNqm?(lHgq7mUbG0s>TXR+7xi38j)ZTio_Udz0IBU$+ z3MS?gV%nSiey$Su%((9}SJhQFS0$$F`mn-dJ?c=M{g`~4tw|}%qpr$ws8g0lUCa{d zNH^5QL^oH#=AYO-?GTGq3rls;9+Y1$$l6%D?(HS<1su5WRHLNc z>Fkl54FtXNf{)0RUhz~g2;`P~357kYtj-l+(fdevDs^aEhI9O2d+Sd^s2RWajWlSGyxmIw^ zc_9g3euOq{SPzt$yyU&|*(uS>YPwdQwb&1!1RChG|4Tq?)I(XIu9uY_#@DyzIsl6p z*$e?k*>j_v*_W)p8}64(AicmqeUt)|+4IU&6?~CN4yp0T!VV5%w@#se0(wIPqxc0c z&)dtX?DP7?SN5#^nh!*z0PPtmpUN&PLzKAyAF8Bx#86WqMSW@hb2RSbc#ENhIS%pAmgzimxP_ct zV^uQ-why9I56pYT)(_2m7IIZyL|74o3Q0ZYe9_}OQgpG~O|!j^M|Rt40@^&)_7~=Y zS(zRf^{p$ek>z>jy*5+qK7?p+!NL5RqBPSxjt`;%?H#!+;KV?X?G_QjED+m(ePk9k z1Cwd&wPJ-Ur8kYBV<^FFxkHjNhh#2yK?a#HYH~>c8GctYNBA{JtVJMO^V)EVZ&3E_ zVoXO1-bBxxIQO)HDNmF>?a~npV7!QN2oAd;IDE%LKogZ>Y_1f5G6b%9%@fnNXT68% zY8o(N!UWEMWj1LHP(*HIc}Qxn)QshVES;q`>=k>yy(GRsz=(zH5vpS35kr-jcU9a{ zdGQ%Jfr|3=@2NR~G-$Cru9ckm2|A$=#ZbMlUb%>Fa8*|&JW05B;+pDgxs@rA@`<9teS%Gh9%U5-0PN5 z6LPOv!jh1CRYL9tmz#MZ_XcSB(`1PpE`sope6MdhjhMBpVAfI3N4^d3%Le4rdC zte;O_eL(z$hnF5`TU?Isx>j%2KMQ-9NigwcC(AA)%f9Sonf;Q9EW6Z{W%TU)Xy@UC zTXz+ohRC;t9Pu!||1|qZn_ksr*@w|p$vzNL$-cAq>*ZATrV`F1*>_F_ zgY3JhQdK^T@_xSq(t_Y6`!v8N`+o8^WnZ}Vm=m^8SH==Tps*T}rrfg;MCPbx7KSg` z$L7(d>;nkbSk;VyE!l?+sUFCJBq~+XMcTQCJW@&&Zp^WkaMRaJxOHsN^umo$$a4gc zNQCe?6K+^7n|eRXuMp0Ar*M;+=Y?CxM&e4i(XQ>N*_CJ1gqxY2TPEB(AghEMkeP6! z1ru&SV!{o`Ot|shDcm}d8b+ci+-UkXa7-B|y<{X-(#zm*w%9GCSA+jGrI$IoqV#GM zbfW4mlG@U%zUPaXQ;DWMq*uNClJxrSNjeN}mGjeTU%QVMv7M!6PxUqb`;y^oC*T3W z4)G^2PfH|1r|4-^>SBdSD^+D^g5CME#B7%eV!^iS-d++8g1!WM-@c&W%ky4{uz>+4 zRt#ppC4KdN|s^G#mtK4nB;sHJ1w&wpcJ0o_gFy}LMP!2Y z{M6^yO?5x@86A5^6gs`uMHTVfd2Rp$i!JQi;#YM+p|Rt!=wPf!qb_Km5;jCh2?QE^ zgVue1?d#U!SG6uj%gax?r`R>AnYMNspmN0w&>` zF6wFMF#%taf@<+(B5kO_`v8_{(WneC9hI36KvR6V;O!A@M=8D#d;q4P)~DQIWDSKYZ9ZH<5& z{5N#8Uw!JVwO@Yu%U{m90z45cyU^*fE-{emk?9`UfitcFt`5OKK4cHUU@r)O+t`*l z_yRNQJM)}87LpL`0e950VFX-C%(ib^z-{h zE}xG!Hn0N(eVpJK6fM}Qu~JSv^HM+&>96@PZ`R?dfS-n00d=_6*jb_0Xuizc*)|Gj z42{YNq*102&MyTksWG=Kq{grW#B?mX%CXi_a}DJ3C3ad&Dz^uEyuK}@K>1&k+)~f< zKKo76YB_-tkSUN!n3e9_ z5Z7^!hCX{!==Fc5Aut~oc)Ol|d@cdn_qIx3XknyBt!Hs?x*^8=EWWYrXYr=oRc`K>khd*xlygY8(l(7#C*<=k7ZLqWnUoL} zE+P}F_;F0E+6p3K78emE%w=TCKvKB4yM>nBIvrNI+GHHeC&aJng71m&XOSKoGL5^S z@jAU?0+t2fo(vc7YFjp3IBXvnyw^w}7vRP(UlS-}U`|k6toIeu6eeH{%Z$$m zJu*#;9YeBo6udnS*-?rwOvE%N>pI5oEjq0BK(}GIiCP(CqXC9pLYE*6i@FF)tQPjL z7?b6^#`u783!>ByM8|#|Q+O@t0zOa$RY*87lB}OWXE~lY2T1i{Xd*>t$sf0)Dm>qD zbJxVJt)a5Qq#6F^39&w&%`Xq{&hY~f8E-f}oj#JiuDx*2eJ`%XQ`vPrfAKrP$EoaP z>A_!c=~sE?jk{)`OFh9^%a@cl`)9(QEj2ih#PaPx6oMYb&&)Z>_jbyu43%6um=i>H z^pz-GgpZ2zCJpQN4gE6a2uY;fDFd(=d*JlpboSFGdDvY3R-3!x&i|rO1mo;ytl3-~ z-gia}T0;@$sc~qzd)qy7-7vA{$aSelV0@n*+3E=WW&7-lLv5RPJ-hp6tDd0*`ktv- zSspK9)EJNXg2ok;Us1ww(q;S{=M~+b-!BXoj;c(W8C4D7DK?}Ff_n&N5~@sSNU4Kv zu@%>qW`s92!ZU$&&j?RA6UDJ0=_!s~xYyM$Nar>Eg7|Cx{Z;*f;#c&`IEls!&Pck- zxpvw=*B)62zU&j)>jxL!Mvv)XqsL%m zj~?5J4s}|NJvM^$J+_bElOD5<-0t+qb$ZIui>wraOQD^tOy3KaDa1hBb`#TTnV6Ve z#hNX~6_ZEuSEMV2UD7p2dCJHm628)3`coT5vO6Vc+x~qJWSai2`|Lq9`zr zDXc8`-=zo{H@BV3K_JuuZYrMs1R(WXn-2FSI?%_v*`L2 zPk&mj2G7&a>)G@4XGc7Ho_>*M-Y$;d=@(T-o}xW?x;AU-kSl^wJWqe}WSwekQOS|N zmXj);{wxg(^UvrPwkdgq1o6o@pRX-z|${aL>f=>}C0+;*p8n*?dq#Mo4bRg( z#lg`ot6%W+=k*KXFZp-kMU0f5(=VtNjVrG2;s`j`bY@L+WFdHX`q~*sa7~^rqA{MX zLKfZYh+65!)0JN1=}NaTQF@c7UmQJ>i@M#!n!T_$Pq&qG$*{QcIi?ytZ1kAP(&#Z5 z*`vqfJ$q~f+2rZ>pvMj)G+cFhiKi>(DQoidz)a!kc>SD%lpxG7VT^(Ag3$6x*nv6u ziGCUnf;-=2;G%Zv^6vawJral|g4NVu<=UpoSv4m&Fe}+SNi)r6UoeJ&&q6zpYl9+H z$MkaZ-sxZ*wM`j}GjV7XBRT8zU8z6KMF;t0klfDSea8q6ouBLcqLces(6vC+w z3tw}G5iP2Lkvi8ahf4!Pw3i)JTaCrA9AcJeER?t3e{%uKC7TYziGw~uNvy4?meWS% zffm(*b3Gb)Nnd2;=Rq?yCx6`U^(+!G9)WSSX^8Giyw?~o$&gnyaI}ufqd~__O7u{DHPR;_&-3je{EvDA5x8Sg;?E7tT9mx&1LtF#s!fDL z(64)@YF9LW9dpG@9Z&QB%{a^0<<20O@05*Y;>dW#*{57GrP(TTY!fX*qog#}Lpj*+ z;lv%G;~(=!T|tgHOVtvR##%vhHsQPIeQu$}RBI9tobK)@ zr@K4KX?4ed9z4d;@ZCTwy&GudbOWuNZlIOZ4YYDvKpSZN$5=z|22JVRped&tH05-I zrkoaN20-sI&eiG$K&*YDBc0u=Nl-~Ur<+MIyjb)GFHScar>8-}B zO8OWJ0Ie$G3t}5RF%ACso3T|cY}rRG`0%mWkJzzbo_}zdXF;;@0An#_^1)-o$rjn< z|LA4oCwiZT4SbOmA}yP{qtF!)VaIwA6fnnp&_6QS0S^E;d9^~;pO4XPc!$5RmufMZ z{gSbYHDeWtG9FG|$roDEgMW&HO~sNFM#Pa91V!V?p?NlERsU>(V`Gq{x^WqH#Bz+z z*T*$I@Q&zmIs$Jxh-qnds67*l?|*!YZIK6CbT^4NS$*XnR! z;iKdz-i_{-J&z`gJ3JOZMeN+)T<_u1rz8uDtU3FVqpBpTTqv2lHaWOK;We(!SyfWU zpZPX3Im$QzRwwv`l0{V#aT`hsCzKpKx}FPx$EDni{3<#RuelYwHRZgf6;;mhh{Mft zgx)^{-SYD&edg3zwG5U&xXyTw<&@+sTXZ#@Vrv71rJFJ;HV`@o2z4KK6V=!ZsB_a2 zr!uq6P+FWF0gM5rC(J!5c@V1)&B)AFjka5+g@zS@Av{+EcJB!6kFs?1gy~RDyV2uF z%gFK;Tkw_)G_2nuvy*XIGj%Z;E{w}!Oft<2X1keZtP9Nhur&FMBaknuxt6!D9j7z3P;(Iz*r1qBZbK** z6*5r{Cg#5UNSp#BUxDNeR#q~(70SPKVsDgl?sg019HbplP9*>CL$^e^(A}rghH{xK zcaL&!6y71qu`KpP`QBEAEDq}370Q1)BM!7izGKy9t%XO*nzVBley= z=?pp}%z+Um)FA9S!gOb8`)vrqlI%qY(~lv9Dc>Tl19w_8A63v5vLz6vm39O+3ij9S z5av*XIW)q=7+a!2=+l#FpGk$&!~{{Cb+6ZF-Ot|=cadP}G+h8b$h3twBh!dCtHGq% zA8$44x&yp@v$QuT_wr?@RF%kpgdb5tgXVZjXhC>9C zlE)7^lM*#0{6i+m|_dBW$fI_q#2| zcgqoqq&`F}h74~VRqLMGp9>$bd9#tF2|DkW6?GGAc2)JB#Sd}jJ`uE!&U4K^Uw~gb zO(PWJ*WPEZO53)cJKJ0}4hkB6&128+1NNT!bbq!LEm->OSJXo65;`XwfJ)X83WZ;1 zTF6eRjEpR5opN*Hq$n~O8P3rlBLi6xD1@$~`4ag>3(h;CXdw4A_za1*j=<(6+iQhF zKQf&i+8lh0Aia_O`RFlEZ?uNSjTcCxoC@>$NkmwQ^PJG4JC8)Dbx+HqLNhuOk+Kd) zN%^41Rlu3OJ1j49L$TcirjawJ1%Vs~y$+9@hQ8@_*620XMpj{TUm~f%F|9v{yq# zFlRsoQ?-o>@5t(@-5MUksJZ$3+E#iftU{l!pXLM()ABxCllG8)Qp2I3pTdGm#s6_S zW8x^Eht}3lQ`553Y^av-CHJWxv=ASS{qCov`0@K~5?cIzLIx6-*&qhS^ELX2&7>PW zFqUA*I-5%qy3naB+A^RWvY*y@ZoJHXRnrNQQqo*83U)!=JhxUj={Q$SPK6ZNt#Jb! zHsOX8LXH`dMONgl1)@TE2QUIM_?|DMpC`VR<5wMXko88l3CG2#ozKiVpK-qAgx1y< z7Cg9NjZ8Q|f^W@;O_nET=a&;JtDr9@TqpImAt-;_1NH(G5(1vJut6(z<5UhQKXd#&y zRWFUq${RL7VK~MNnM?6Q2KcO6FmcVQ)67AP6C?3o$-!l*;vEWZBsm8&w&E?@z`PU| z_h`GsW!%tME^4+p>?l4rx;NTaBMiL;!CKN~Q$n!XEjDzpRJi+2w^1#){KfJlv{mcx z=x8_~P~JMEvbLk!VbHErU{?O8#!}Z^@)YfYX0>_LZnk1_H(Qu<_YI9uKm}nZQ==)k z4q><3_T^&w%}hicX_J3qae$8N!w2OUN*F~lI4$NAi~B4iSsapAh_kgmEZ=Ey$cTuc zP@TiPEH;eY@FZpjp4N*)XE+S$FgM2(hh@&8C^8jQ(oq&(H|pq=$HQd`>m}2ExR``d zhoBq}1CYRm)FJ+@JE~jEj>Xw!=i)NCjzMB;6oc$g8FgwxAR?&t!$xeI;*RFo0wNIa zf#EX|n7=7t?8+s8qYM90e5dCCH&d>gZ}zPK(4+zg$aKjg0GH{v8m{<&;1MZn{sAFm zWaKPVbKA-8rydUz(9x>K2d9H5Q=?NHEDlS>rU|k)#Ln7jQP&%Jlw=$VR${wV@97Xcu2U!1;m16S@+?hh8A89i_ zSw?tR_X8nr)emiwL}x2RtHD%ES1Z&7M;oJ&U($n2szrpCO+(S@UbW&-rBw?TRa&(& zQl(XkGF4i&QdFf~%d{HD-&vJbt4-m1-Z zP{q*%3slr^w&?N;%Eu~5M@lhvXhTe^a=2A77p2RJ6jEopg! zW#5%|scB(8;&ApB?b6CSZQ42)#hd@&C-ud5ofV_S_i+vMU(nzy&DGQbi<&W77Tm|e$_k8TD+J~*O!{it3FCi7G^oL z2e;xpmFC)hy_VQi3vy~nbvez7yjW8M3i6C$R7~hj7v-&m%45Q-nT$BMSUZQU*l#nI z$I4)CH#mypCWF2$oijdII$D@cwA2lAsxNqB*5HjRVV!bU(Hcm`9MS4@y?9vlra11l zT5)iQUBeP}qj*^QrZ|kPRvhHz@&F2X6)?eJL~(q-wc_yUTnpd=&uw7m!7Y5#51*pV z!Lq2l7gR{2mOOgq6Z265@-zBJb2R!WfgZ{JaaeOTvZnJfmgk4K8ZA0PK0p5Zz~uL~ zbKTN)UvN(8sPWvXbK>Z^3G~&joWERGj%QYnx z92)YjDX}HC>Y7XH60Rw|zldv!P0_af8t)Oq&&s`mC(t*g6r+wCFtWth%DYpb>&iDZ zwYS+nmm~>2k{&Fpl0&z7P-%1D$lrwvhbGaHWou8kYM8;c8%uS^07xq~T~l)%CM+0r z1gJw4HGElJ>4~!nV{20b!zHTv$YP5x;;q^?Z`JnvK(T=_Hr0u|oVjC-ZE&(5-YT6y zj5RQ&5BezgtsLZrNxs(ZMs!?FicQn*o#TqPGj!ZLu5_Sqa9nXFv%1Y!qT}iyz1}v1 zm4Npdp9^-}40D4XFAgZpIj&{}7Z2lSt(DTNRr3YCv_HhpigIP?;kn74at&`q&HETj- zzN<}!e$$L>NC8Ku{0-rq6oA1Pk7HwAKY$h$5_|$vq6Bxwfpk@ju*tSta{z2N#!-}J z-4N^n`P&YE)`j^&+QiSH5nhLEW)R3hVbrR%+hQoU4Gr2K78;x%1gi%G;sH6cHui2o z!7$DrQyVCpT6Ra4qtY4fTakTqYE`{w&M;I>r#gk{l{`|Qiby8K!=Y53^k5FHdyhYNo2Yr$WN`;>9SGLpsp@@pAE zBD;$F9eLp`Ql%}uaVHaFW&FoQno;`xGn|jUg?qKwl51;V6VA#y>Vw-*OK8QxE#DSy zApLOh_s;wP^yN68n4LJ_6s91|OgV0}!DbiR$0`DZY&8py85htT-#)h3luzk^HKOc; z&c}5S-@)d5L!5IUPV9l=a}g-{xF#$in5sZu+Nj2^B+(XGag8^yQG>$O?j zuLWmch>^DaoTGwqoPkDBzqx4YUaxR6fzEnhZUnE_eY`ZiUby~SUa$KZvZmKd)6%5` z4ysyBua{bGdcD}4BLW3%a1*^=>R#KsrA-{516tFssFFhsKEThQT~f+q{}z5QE!WsN z9+H@ZNHUaS+8?KRdE|{YnWe(8(IU5S)+sM?RMCAHAWhBiCK+5HbiGqdmoRMa$55dT zz9mAfHFDIZ6_Zl(+bIWP;|)k0H)SQEF81K2Q$KUuB?RVJ^Zv1~w)ptpsF~=dr^WdA zc1~sXv~w!6r=3%oUhSO9Fl^^k25md1GSMx^;*4AI@%1XQKPy|PozvZ&rk&fa)7_n> zo!hR{>W%^3ijS{XX_~+7oNl0-=5M=BH_)on8Uq8Z6(3)3Ox9R8K9$oAnsU0yLpd$b z41iXAd>w$MvE0t-20(RM0N7_*@$vP>WEXb#Q#q~ASYxgD_aZVBmZ}53&dfdkVmGREpkE^RM4oV9+b#X<#{%9j=IX zjavuG2t0B@2-}4@TtJlk;bUa31#?T*T(IZiVp#uobrBziHj70#^dAk5WmF*;<~?_<_)ycP<$7mk;DU>WuAStyP{WKYhk65@2+Z|EbA6i8Lh zA3~M9yT$hrb+I*e1f5}TtYYZyG=}ci-BdwI(?Z}Xh7R@w!G%d@^xOy>TgA|^pyR>` z??nvVDpL1rGE#TNWhAg1S6M~sf(j?;lhTv`7;ex2?7hKo?**6nPtp`cc|MRzYC*V& zKVG~t>$U+TY$!*|(k1}39NP<^`2WAX_sg7BtHI=ZM_%RjiY`AjU0HkL^;I7dL(kn3 zeJn!O$kaf$B45=8#4LaqesN3GSKy=J=!~(2x>E)Wn|vZ%MlK%o*q&1H;B(D`3NuXQS#wN>BFJ)Atf7! zR_Q~$aN%G&z0Z~ANq3rsf8@?~42EOCaO_y`SQCb$uGM6Ee**@A1`LSxAJDFdRD6JJf{XKG&)M=PBahATNf81FmNtJqJSRZ6!w-ws|o; zY`N0lLHFT=f8=^R8~}y`2YLsZFsM2`OQ%*n!mvfM!7yvUfJ5DtHZqJbY?5p+Y(yBe zA{G9T>tUDy!)(@@HDOS7gTbmt7+C3aFc8IEqaMQdU1<&qui;_Ji^0I^ib~U^wN4l~ z>Lp)a*I_nR&SO{A4F;7}i2*VzX*6D7MUC@XjJ&7o!Js!Vm|sc)Dg@otL_==iy&f|J-wn$!0IM2;(A6*yuf-bD3tqDt1~D~se8U|B z41Zq+_-tAS_#6=$9^hwVh5&xfG7R9Vh5&Xo4B!i~h5&xXY8b%OxGR8>YRdq>5WgY} zU#S3oHD(ClYZbs%4FT+G7{FI!4FUXe1u!-43Sh+iGQe-duL$6q6~Iqt0rdj-LMGH3 zhN~I^*wrwA&&3)7_$jMl7^cQu0gOtt4DjdUR|N1S`-;)4^7JT<5cYro?ux8e~i9uYJSFE+ksq)Mrj zjr6kBFe6FSt4n3RmI;C$?|S?;%*o1T5Vk}NHZ_v6vND9N=PGPfHDpt|8fH{ph$AAi z@ENONcA>0{M8?+bPdFL~8XB(Yd^GBfT2`DsE}P5-E-5Q3P9K*Qm$+?rl@%B4J_7}k ziB_C+W?69x1m{s!T%w(Cw-4^h@br$6l~Vatt5kX#4vJ;Nc~Yr~?;yj|100Oc2Edgm zDS%~4dgn=Hd}`Lq`1GcIRYNrFYM7;58K1J0WqjHVx3CO7-U*kWItxb2X8kkKAQrF} z%^)_j{)Lz!V6Rw)v8bwsfORzt*h{g7fPLO-n1)7;xp7d7u97beZ~w9{ZSp_%({bE# z#ia(Bix7qvvWtvx8}Y=s&h*i%&K>8H%7LSK;-zh`uTDkMg>p7N+@GnyXfn?AI69Tz zr+SOAVzkqO+Xva@zh*Zg=q5@oIb+YALV9$9y{@RNE)7>;zDws)@)%xi6$lYjtJYdErm6}C(poVFB=$rN)o9B87{Cw^N-EX_2={-mxamL0wIsDBI9mm! zfg4ct0U@IG0S@CMmJRfh6%RC!@B>VLgCz%~*akxorC-9y90J2%JI`;!pCy239V*1h zjtffI+1*l2KAS1rV@eHnUpVChW--ZC$w>RuX@QT_t#W|zn`JQY-(^(hVJ1rXa5%a z66w0TtkZS79B4}suwUcEBzt%@Z~Ju7{UnKX)U7_&z@_M5H{NFOjgXo0Ilv?3UmlN0 zOKevnDUT{Sp2G~ufAHAkUaqD8ISpU^7pw497f$-;E_`*<$r9MxpZ>%yhpp^#8l^5< zh+-tI#E68>oGBariF+l4=FN1sHO%Vq^|VM}AtjS}_QyKA1yx+KkhD2BXs2`I1sD{0 zP9ue8xi6xylJecFbOqK5bR{xFa4f zd!MY=p(vZ>XzuiG_Awn*e0p>a(Wm{xu*Oc9w8^#x6%5ov^@!V)+y-h1ESOyc>k)P= z-3e42fegsso{GK7+ACi_cV#!3eNk9M^b?U>zNwTFMqebHfi-G{5W7|37V zi&ex=Y6!J{%Z4X5JPJd)PPd5;nk2KNdW8`Qo;^PN2o2w>@3xR>DsK6wN+X6Tn(H^8i;%Z31`|{jx6& zgQ4JnTt&Z#gp7i#wG~nDDnic3AXYPe#Umn9({enj`Ry;ZK~Z6mVio%1viw+RrJd}AP6R0urgNBFSfK?X=qaNSJ5wVpUBGa)XMJ4@T_eeT1CGE zlK5JWeyNr+f8qIE)=yTR|CQ%ow7=T-szupH*A;tjJ2+RKe}{+FzE`dKtoFUS>9O+a z$#&B^dwIuRJ-<{DJbR6$ig%;}MkiOEe|PlaYHz%ALN**Z4GLa){(}jjjd*vqCG$veNXDiSD%JaXH za0GdO z;&^_VeY4szLE3zvC^;+Bi?;(ET`Geg#fo!*cep}Gh17r=0t)tq4vN0}1fOR^#K>=4 zJ)Yg*E=u;W8nM`?tgYGa3LI^00Mb6D!`c|zKgB&%Y`Ju}nyNmnRF&l)5~Sgyqwa5xcAB4L z1n&BiIHU|=5s%ua>ibopHY=}8{N9hrSKEb1uM7K&Oap5N6IbWJwsX*iAR_+G+Bw8e zk;C7m984AwUPlgGlN|mo)qy>c!{4Qx>d<6^fDKN))2$1U>Y(YMkM8a$r@K4K>F$nl zy1S#C?(Qh3)g1%6bsBfz6x&cs53jq5}>q4aZXQbhDe?~d2&sbxv3z6!LDITKL zm{njat|j@Im9Nz*AC{s4#H5s znx(^i&y?=F(mfr>fB@D_O6}4;cglkx>ABLmMyu~M`YhbLtS$(B*X%fk#pq+ayAv6> z+}dUN*YU?VIAQ$JV+8yRi_vHFVs}H$4I55PNSwe#&O{)}#xSw*?6qTHlGtfJhU zZ*&#q=I|in(xUxVQEsa!w^am7SpR=35iH(!kIRO0Yc@s=-~Bssu>lqk78+Lj+wZ~p zv?mDMQOg9e3b_eW?yZE}cnssDT*fd_s(w9Ge$1Qij59ERB=Cn-l-p{`Id>;Sf&Y7% zg5Qy18DPV7TkUUOQ81qUih5U3Zufv7z;DnXR#9%ND7TeT>9x95l$+BYq7D%h%Xhxv z>1j9^pACRlQErMyxQp8zF80#?@?pRgjp#V;Vv(~NtD_q^KRLBC`1u*hP-1nJ^qv-0 zZFqVcd6M>0t@cw#=QC?HT1Q^bQ>B$d&Sqw9ms6W9k(&p&q2VOW^eD5?sm!XImP5|0 zrjX^T#9seVGcUi5Q@d4D-(&6j{p;Dp)!jX*xV-Z6$@1LEB0r`@W!B%1XIFom6Nc$j&4p`~H~0AK~J3A|H;CD1SHx;oZp-8**NrS}$gXMuHQK+~^DNal291?>SB;S>MZ#cwboAOv6uw}=-eu+Fb&!0{(I*t+M#_7qPTPB&)t z@ijYq`RmIYKdb|sf7PMqm0s3=A`5XQ)q&ApSsK}WXg?a+edu_$_ka7-$juW*BbOd3 zcOUw*q>)w+8#J4=h!G?HdYnl+Lv^mY`Jh*DLn$7$8#RF3b=KKqlbzdMT7G?}?stqHS$71-xz|12PG zs(S|>5+8ZR_=rVdB?`gG#9qEB{n82jp2}{XU}7?3AD{tVkGP))`FTbGR-o%TnAEi~ zS$RPz?vcRYqGyjvIj^7}ZqE_8bXS<*&x1R&|JC53F2|f(>Eqc0^Hi@7&ill_z>RpG zE>f{Q#npUV59-qr3xsi|{HIkN$6=^&D$|EA_I%_C?14UyWvOq3g?CjSXc~S1{`OavehFuP^5tJaS?A?VlbkwU0&!=3ib+S-vaQABq2ZWg?P0>{8h&v zJiviRG#J`DG6w3aPO0<&uU3d<$;tTicUe`&r%d~=^%Kx{^K>n&(wt|NCU<9`h&bFo zEsyqWRo9kKwNAVk%!gWmeHTk1i;>og=3~|u*2*X5EKB4vxW~nsu8SYdC$?X?SlgLT zi-}fZC&ikUk>+bGo=j)Iq*V^>2VYFflwIGGVrnUVf5+vQiQKwJgPstc>PJF{Q(>nciT)xLrFz4mg8IviJK%U8cw7wyi=-Ott* zU4i6$Sb3SemZifd>bSNgXW@C?W1R=YcCJTJN=r;`J&Ipjk0QmO)GN0EGZsZ|qhzak z^8t;4)cMGd(x4b>l=}0Lt>YKNo%y&JX_Q7FU!%m%@?u;YrLiBSu~y+3XRY?z;y$qh zIaO=plmomlVT*8KIq@h7ud|3~Yhg?~EiDS0ID>cucs;V@5Lx6iJv79gB!8)nw|MECUX#Kde6# zWA{WKU7D62i@`Bs7Z{nr`^)qb3wk@#FxirxLrh6(IP8zIOV2xR$KWBGr~nJjJR`K2p~%{ zM zmRGasV(oMiJKX@3#UPX*M>J}ZB(`3yPZ2z1+$|@1=Pm|7AqeMT0-V#u6YPEVzuW9* z1^oPUk&91-496C-hm%)^I)*~Td~GO#5|6jjs(9{T;{vSSe?H;}5oVX2$amf86T8eN z13-70zYzsWR=zn=1~8K0QOoB}WKT~Y$=*;<54E7kfT;yY5I0*O z^q_PN(9jLgu#1zKXhfb^I0V05{6IO(b(q2S z7&fLSfLN@KLT5}QZs@6BUKx63+LC?e@+u1O(kMzklmQFubMw+9d8TuMOnz}B4+B}v zsdGJ({HnvCpmBXx@gs=iOefvd$@?il)xZ&3!e5&lpJjIbZ((*`?9DYXErT+R<5}n& ztih{ca17?`XALlmzA<@n?&QLVOdWQbm{A}6c}WwK&st~VIXQOG2fXk>`+Rkpj04sU zg8S%AV-ymdOg=g%dSXHw(`Yjav|7a_X62=kM}Lts0G*28Z|8Qh)3}6uo=hSc*+&eP`YC8uXxcq$ePY z>BALH@m;J2_e~zcSC8`i;?M%$Hj2rK{K{~?>B_m$XNL7aUiaWh4c&B8PqVQ$^@x!R zQ*ZK{qiV8sg;Q#{y8adE!|V_qCux@V`h&Fzrcfe$>pRROzxo0OrW50=q&z6nT$ren zZbizwErp4|kyX4N*Xx|qqUIEuD}dGO>!7Zo@4(I1?QBW-({o;$BxPz}N7YNxN0Jmc z-tA>mQl5-Y$34SK04FH$_Y2gSnZu@{3Qy!m;t-m+O~m~D6RgR2xFKGq#dI7%JYoRVQSJu8P%g=5huYjd%JVkL zL8^y}_(=csK!lI3c$>+i_;`|>GL$z_JQ6YWeA^Ev3~V|bDy{EO5~3<|3&)f;XxK*h zfTbzNj)p_+te*+5HdZk5-g+w1V$#fB@B!Dxhuh@E*Q98A@}go3;l694bj|Xl8~~a4 zSW*u4l-dZ?Cr$ujW9a9MMWsrE6~H>5%=$2UM)b_PSs=tfW-i2CG1W#-uos=zW>J`l z&SImg8sXbni7&yX7N<7xBxptsV*o1IY?hCVE9{|z?gcuMbc>mcmM05qp&pWr$Vx-V z&-kv?aqS3=1LxgdBBW`3uEhi^{O4cHqTFc$r1{M-++RRao{^c&eT(U?K~AL zq$B50v-+YHd$hdSzcx{xDyD*RnU%YW1Fi26PnCMPtR#;FO2?WkO;9tpnis654a_ZT z5=d)pQ9rhYiJ(L@zaTX*x;+J&~U?joBU9$?H`+xH&1W&^ZGg$>n$%HE7eztU557XEq;DQ6eH=iHS8}uExX~FfYc$8ZcL4VhtFWgMhh~x^cb;_b?)? z10$B=5^KPmkBK#4&c(zUFuO6a2Fy(Z2AtOk0A3>Y#|{SXvD&yCJOx$W3dWx-~d%gtQtM z*F#zj3Z}WBc#nhPMQi=t6-ivNgxdEnTSD#Qmn@<7<>xG+_SuV;Q2QqAMBntP4l=TE zS{FlQW_Fpl3#)?8gW2;z%nCV2@SvycrAX&}6jr}AtgTC9xFI4iPi425DrG7f$JrLq zr(nvDl2yg4q@zvMXAneY}ep9d^zN-bF++51De`Df5to}?svc3ktHvF=Bpd;evYj{hvjNm@O zqqY=Tb)LeC%YbxkMH&@j8C4_v$FNDKd|>U#Ue)HL6i2TEjy;1~P>>cZ_lL)?DSU{i zT*H@Qy)F<}G8|`b3Ql39zz+2rWq2B4ADiQG+U3{6J&8xL>7k#LY#(b6GuE=4K@8sR zL-fRvTn6+NSNNrn5w|KNX;u{pwh!5R}58a4w7Ta<)xM`3U zG*Ls`!015dDx;I)lEUr)7hA>p4xhulG1FIB{SYjHKJpX!$f@E`1l|KCSuO{0m|Yt7 z=+~gs zooh%W#_9w!84^6{Na@Lwn!!29(y`Nv0mQ)w4w$#{=?I5o2+8KO5t8gaM@S6yT7ba) zG7Ff4a!L#b-og?hY5F<@W+yp&CaMW@&5oXaBpC4e$MWovF+uTMNuAmjn2Xyd2Dll;!2U$#oW@ z-^Bp&L0BZGchj&qqK1q|HtITL?gozwAVH)usYTPq^PW5zXu5;v^(M{r37QYGBGP4p z0uA@@$93_?b0=s2U!6btg&BAPOP7v6j=N~D;*ZtJ*hE{f+eljze_Ye7W^*<;wVv}U zVx_CRpXFC*aBXm&N!E#%QPal>45JDBDYY6 zV%^CbBPk8uh2ESX1HQ@g(>=FJ%j5Z;6TTfQelRtpC(dF(t24FLFc5Rmh7 zo-+aD`>GB*pg`hJaj>NpEjj3+=W3~_DYu!{z}sTLjG0j`$lh?7u6NA4t) zyP~5%NYmU$p;Zi}5GO$|vL$`lz_4%&xq|nK_ zNVZgpVP|357LN|1#^h6dyd*&RRN7UWP&EIY0=aJ!S}U?>5&AUttDfc4XWq(46a)WK znnpKzQPaj@LK$RLq#`8oQ1ux239}L}DzXnBBTz#K>Dkklzx?I=@gn^|nSX*Q%Bt2U z=BW_qR@zKSQBa3I&f-7Wr?P`Qfi5`UOqyvforsN+C=Gl;HDtaAXx^Uq(+7ef6L&Zk%7E*8Nm%ecdf&$%UnKOc%)Ql z6ps#|(I*xv1LL>U+5haI2Z@}}1K)$Sl0j@$M^8}PyL&>0Tw%*SA)~t|WbE4$=PNMv z8gSeIQm3Mh3f4GK4Xo2u2P>7EXeY-3tDFYj$#Kvsr-68K9JtD9Vg53aDwhv5kX(V8 zDcHeb`d>+>KI-HU2%bG@tL6E_$>oVtrgGhq$q+bh{(?Q1%gU6g;5Mj-gKD}uL}+!0 z(CQE&f2(1ngGBj-w(i(f}z`QSB{y;~6(6PD#yyJr(N&Jstk+C6(08JikMB&wi(^u-Od7t2gNyI&y?gfU{a$_ZYJdR60toipJ$tVKsO_E&5M5Z_ zJ!@IgUsk(k3FTqSWqsS@CEL1rp_#}|PD(1Vwi)qaOss84ybu#>n-b5*#M;Khb20J% zXYXC$YziaPvW->{ua=HG!pTF&A za?aUjKi6Kbz4qGc-6kjJw1D# zXUH^Lp2N5x=u|T!P$KY-*GTT_SYsohqF?~cg$FtUS42LNFg3!}kudceuWl}V_0^Z{s z3ET;hL#|gNLD(b`u-dwA&gB<5`wnC{3)PQk$E_1x${AXJoKQJJTnOn z>7CpS2aGpbb@c!v>wj<_I6xzarh=C0x&`aW5hpFbWfjQi@0t=ZFo+D1F#$m96h^6f z%_EEmukuE%fWx}#7~ZIzyiv=te%O32r>nhPau@JYXp7Zf-fTJ` zvz2A&Ft9EU^%bQ7^9`H_xZDAet>B;5GJMe#Us)x=t>B+l7A<%W{6FG*9R5E1d)3Rw zLWo-#xQso`5o?9*^%-8K((tf8=Xy`DGE`2;1o0MIIOz!}FCT+r(h3!qkHKjJHDtUw z98r&G&T9Z=6oK0%h-#Rla6wq1@rpnz4%@>Ce}x3k6v813AieOaSplx{9DR69z}bB5@<|R3;MJ@UK$>TVCduo z%%yk$!VhY0P*LRb0~{RJ9HAn7^^O)}Jx`3Z;qY)+{;Vt0_=eiZDp(u%1i{CPLBulH zx(uO!UyL#fLKnskT-k8qge(IvjM*`YHQf25647~ z*d4(Iv~h$<*WCdo5v0OJ1bXT&yk3CjfkK9nV~a;@Tk#2of>WSS&ziLi1BEZ9JWyyp zLQsHI3qhf9q)-C-v!>|xhOid3Xq+9!MYA&!5s&oA-0l;*BalVi_*no7MMpfKD|h-8 z1T}d1@c$0K`aCwQCAGm2Z~}9|!RYlOHVx9dq$9c&UNFX0;Tvl7INFVfRfTV`_Qo6h z9r1>`uF1{r5pS@<#T)$1e*^L)?NJ?6k&~n)9H>PimVZdZUsXVNmk0lWKlzpXqlTe7 zTQHDih$t~)1plbc>Mj*PoySkbXC@!uZ*7-!!v%=I6LsS1fQEe>cry*_>I*OsC-YE! zL7RuKURP3p;5^+gTY>1KkJ}>qh>63{i(y4oXs$d0fy6Ax<`-5Xge0nUNU&ging+-I zwKBqkv{uP=5jn+1)Xi~(QTP`!@VGB|p<)Tb?ewip!2rRJv&p6qK|YUw+Eo#_r-ET* zg=Zo9tyU5KI>T@RE#dV-gdRL@AlJa@Ig!T0fKvD-H)n-!auZkhCWpU;Z*s&|_$J3Q z3g6@yhrGdr1zJMug-k~q4#_u%Bl(r_&FI77o6(2EH=_@SZ$=*u-xLf-I$gA02zj(l zlfXysG~bNgX}%e~(|j{}r}?I!)6%uzdLi}Ex<(c-de``7^se#E=w0KRg04vi0_%kt zjMf1%iP1a2H=}o8IAh7-jlEvj#c0itjf~#Ra0ZjB%vvuDWwgqMGn!lxlgHw6{6@b} zY$Kr0>S@)L`Ep9E=_|3Ce>mm}2a2|@#9CD66f^o>sg)Pl`C$GhCeRXem4N>4JVOvl zOfajt9&(tROU{Q{FfPgquv`Xy!nt6F+WvfNCUb=mW)*>}5CakK5b?l4Hby#Suv+jp z#<{2wHHh3&h1`Hm9(sucz`#Lx+zOl2Uxi?hLcT&ZjMt6UIOB5L&!<}J#Vd-bc8=t&8+}L!vAjhZRVl_X7aDjS&nD(`5fGgQA z&;w$I;dLNg5z&Lh6yP%hh&9Gg9&$HH=2HMsUTj0<#X-%Y=({PG&}p#v%bfsa9>Rg+ za!Ez0Q|gqoF&aD+=8BMhr50(IIKc;*qoj?Q)|FKR%NW8fggOw$h4<8rS^tf!AH%2M zYc|hBL+I3El7l+&EeMl?w&O#)(yEjQCCENgQ4h6pfwY~6NsCBtj7yBa^uJH!i434faAB;sPXp@ zb)Zii3EL{Iwf|pX8phv-&JD*hd<@7ZAB6bfG~#nmjP-zz{rI6)hK>I3Np-+lqpzwk zFW|zW0!ClsGr13#k&PciI*^qJMO?YA;p*&lUIdnDEV{{-wUuV3*{m;4CTJxpy>q>7oV|P%yoo=J|Bz@B6YvoAx4}d zyzq}9vlRKemJk#OO0M9-V0cIv7RWzCo2MxliBHTfczR5 z136(~TUj3AcRu(UZ6f9xttlZD&JFe*^(`=5iV^lpLeohwu5uI5WvBJmKFBjFU`mGu zUgDI1jghG^GLZ-xg#TeUH7o!7VEpcs#Z&SX5snTI^0AguKpWA+kevIx2O5j0?|Ya| zDZaN7U^nwV?t$gB_i+yd)55LDQj?!wd6CvAT%X~U{pI3BecVIE6hfN*ut(5|TvTC# zEiyVL7-ry-iU6{gwpA3PEcmLVqx>aKF*qt1SsQpp035YgI4X-GL>ljvh|SF>!pprb zD}4A`Aux%*5m_w9$!QEnljO?9a*ABr&r|{rk83NNBuMwyL9+Z*Sk&bY0lQ5&q&BtjM0eJe=B1Y^AfMLih`oPqqS|F=@DXRwe>PuP3?x^-A zF^%8NQZ+{p3h9BfK!-w2)UMPeiVN%{!V7@!vK0cgfx2V`!?R!pstmb^>z;F%@pZp+JG0H1P4%`JB0eQ*CJ<3aQ{R!TVA+_iJtIz8w{zU3^N)W`a zxO^N~##s3>P}CVKtYbWQR4>@Z<>2IFX^s=F0o$=NUOvi!Zh=<>5b_heg2C|kWgr#o zLcSu%sDBLR2UFMt;TaP&&zJxyTjGqPtQ|+?VVpA-b>(r4vGPSh7050ay;gJ;Sk!W3 z5HJPj82jz~SeQW_r=c9NI%e4i?21VYgHt})nbZ=-b&50Tp7N>9CPIusZw^))FHpt( zxpIk&X4B=<98~$DT|ON$&7z}euo90I)0@Lv%a1y20enzpD#B)3bU>ZhGIZHhPH?Vq z(B8pbR3ac>#Z;D`^0!o0X}oNgPey=E34&&m=BeKVc{9h5Z;znMvy9gf#bXHc^w+y5 z5HSpa2>UWBM1p9~`P6ObkfT5_O^4P|f^-?} zbO)sruM+Sf5U1r#EuReJ1X|)_i@pFv^`*{4@;eDuJS3lTiE!M)#c`tCH=u2h~ffvK(sU2 z14tIoQS@=)G@zUtfzQkNvJ%k}C6^AqVS16wWM#Tvlw@Rj&Mx$rCC)_ATcY27yA6~f zov)aLDO7<%D$3fNNlw{1M3&<&opeKExUgSn4&Z=NTzad%$mo?Okg$z6417lsnSs@w zQ=J|gVV4sXl!h|qycj2jmQ$PyFcA%8SS3UVF*O(4M0EqkPx(}j>IOvQfspDX>h{zb zF7KYPNehe-Op%X$B#AKCg81{#s6l&Ds^pDhixA}OvSRQ;UcHY&PRsu?8Y1e0pA)EL z>%9ae)Voqyz2{<2YX|{^u%P5TS(qCU7|nXiN2`Tu z7X#}EFnF$uOtN<9Ampsvvc;320V6Tvt7VhqvyLJi)f4niSLtD}8vO&Cp(1m*{KA9)_QEnOQP5j9 z&%UZzSHn=kn!-zoXxS*51ORGD4d7BzW7;D5;Jgjr%n{{6y~x258@vL`dn5U<+{Gv4 zzg|)i<`!4oJJcI}B_Ea*Aq7pEv>`Wx{8kvIS3xR}h71)@G(QFLWdqhS4um3o!;g#P zfr=R5r;a`eoZx2yj?{_VPx*CNoCupbq9q!OSVb7r-G9dHG5nhU3>esCDmp(xI;lGj z0TZEBL7B>bK&vG2T&p=`@WHK+fx!0Afv-d-0^7o(M62wRJTfy#Um&_!qTLW<`~-wS z_Q;PLsEV${gs6jyGlUWgLy$m?6&WrlO#~&j!$KOpS=2QlnTl|W#mHaWf>h(kBM}@b z5h6rc3SXZ&l94JTfs*g1QsGyrg^X0C7BW(_|8Q8isC)zoU7+SKDWIMqQyH!*t)18_ z=ei0itkM7>z7*+4Z{U&%2o<6O zJ9M+ssI)(#oXXhC=&_tdAK0|vk&q7pPMRscj9X2``~6g=JV(0$Xb$YE9N#k%KKMH0 za--k@eFfPl6w_;e)$VrPE{zXVU06r0BFc0Kg5n&PWew=9k_tZWRS2|mjPO~M$njaFC8+xGmwdptuL5)OBxarn zWM6V~`_^%4A4-5hPDLYBFywsxtuf;t+mFL>bRdYD(~%sVuhc46fmV*4X`&o55!@ai zCL>cEY%Cvlm{{|T;g>R@34xYG3P%+PD3HhNTQD#zA{D;yej*B4)O^UDvA%@{^bFTD z;NvC|6`K`%Iv61djT!)vXO!@eXnWEi7~nPrn*-#nX6;m8Rb*Z=ww+OmpGGU zaXb~7d&}V<1`#%y9(DF&js_J@#TPt4nEd<(-j#p`p-ou+XLCvKw*G8xu@Eja3}82n zYWQM+7}Xf6zr>lsHOLe$kf%74QD5Eyd9o~!6&d7>jiUwHlIqbSWD%h5`?sri+%v#C ze^CYE6)^_75jgWNC^82L1%1F1im^zjiL4)M7b#{q6Ge}9xDi2#CQI*~_#iGgB)=;1 z@FakRQ;Ts&Unfr#dBn*P)%D>?GD(_q2w(7)EkY4F$vDB8sN0x8iS4yN0o~!3L)8+2 zP43~>QiqWfm-5m96-*JU{D&v;5F{j3rL}hw;f$L{Cl!i0E@SW?m17Av3G35{Giei+ zjU^m2;Z`w?kJDfmw96_YmsU*YxGiTI{=+s?RuR6G#o8Xcv|Y3XeU?PK+@Af0=~^Kk<1oB{J>A_*S!z)RW;SD0poXuZtZVsNvET=nZuQ&nsX~a1SR&652Tq~qeUneid2M8)G*m-51F^iYL z)QS0T6Wa3TALTD`Y?z4g(WExac|=e_umDAg1GramngrnS#$m=;4%L@I{9bM;hF$86 zRVwpXhaYnX!|UUOD1J%Ho>&CQ3`?UgX;q^XbLi=UrNeZ=(mY+T^su^MDcLHl;aXXT zfzE(|4h``JpZP5~9_#=KXW2b88AAya&6`R@uo)|M(xU}c9NZiU*gsJTLWk2XnknB& zD0wg#fS*1#Q*3YLf0*y^C`PZhRLGfOp5fMkX86Lx_S>|Nl39lUlz=enuoDpER^K=; z22R7^OR*!&8lRYPBIPBV9e!g1@ANm$i-lPO(E(d!$>e97sj!p+3}n=K-)RQgh)GF* z-5krje4GwwOD5KN`Fz@L-bGcIa|EXE?-3|_P%#&Pil0ezT@bI&#JN}$mROu);gBAZ z{dJhG2yf<5tQIR)_A2GJe?F(90gK^Hl9boFmkUGGQ2ri!QB* zlD5LE>QW|^lE{o_R_erZg54pYu%oHb44DWhW$aM|Fs1{=Lc`2Vtr1 zA>3tlkr_GI(OY4`C?#Th|Am!$8P7%`DJ?rmVOXt`E=^Bi*dJ@5>648UOC{K5IFQ1E-#aD=y$o%$l#Eb zDhTZ}5#9d~$HdJG{~6jTH`D#`K_R%2o7$|wTke5ns;(*h6l{7|Sm~$e+iv-=A#QHN zF8**4O#M{G=WQYI(_3hX>XRoN%bamcnL%y<8F{p7Ns8soj?|(6;17~~guY-iE3jb) z@Zd{E+sifn@aRFQ!o?jjDY}>@#u`QEx|%r%F0r#4S0LjBK1@QX;#@ z=|vXQ8}VEKYcf36L?)J}kxmee6o}9W_+k8ur9L1mgnUlh1cr)toin4sZp0WBO6R|a z_sK5osuL79<4RZn2e=XDKpDM_NkCG-CQlb-lJ-`Z;Ec~xMQ1pZE|KNPjJ688*m$Za zieKUcpo#*jZ5p%z@m8P~Tjt0;IeFe@(QrL9f5!%>rEFfP9{j-&3$9=UXvy>O(Vv7e zMDK#oln;E8btq2)R6tUMY}bkgB|L6Pm?5PbD#BD>zLSE;0VxU}7EHSa)!DT20YrfE zN_A-zfcgGFn3pFPH)YpY4qI_pA7XR7fNM98OyNV>jOmbIe#=SrM#uV{kj$*H5U- zP;G%YpgY2J5IEgR=wdjewyi9>7e;_Ln2ZDXtT^C|yBEWXgYy(#`80t&Tsb+*o{%}8(%libHkmbu99}wXHuH4GpFQ4EW6a6-qSnQM_ zuPnr%t@u_%pXeD6Lewd{rySlAU~lyB zMQ~t%YFj>)0~2 zE0dqi~Zxr$30&pp_p_yO4DiWtJKT4gE zL4FjN-}jVrqR<7$UkM9@VU*lp(%NFoBr|JD=A4Z&GgT$Z|~vuvbNPvYO$R zgKzj!rqgvA7vva#7cMs~a4yOWcp;#3oThT>+oogSnciOI2C~@d zoGXe%n1y)_(tY4!g}!uco7Vj8oqI7X6fGQafT5SpkLduYn9`Z5??ztV zrFpY?rtcr1W@slqzboTtA!`+A-AtNfc1XCqy(me-3%t%t#h8_?1gkl`d;@+n7S$R| z7MLMYUd>CP$Botea$X7;9#US+rGOh)&xIPS{csP$kzBlFd%h<@3q%F9E`F#A4n*J_ z9vm#SQLK_=kC?1qnSh3E5RV!F5Y61^5ogJ>)h1k@7xO>y4+yIsa(~e^IjJ``%;2wONC`G~8a1nC&!L9u-vIJ3ue36BtX|5Neln(OP2;V{qEA8@03Lz{cH>8cx zT?c%77Dm(TD0ECO9_7pa3)(_q?)3Va zE5XjH64KlKehGH>UtbpZXAX0&P@c#2Mxw;4W@j;RpOyh{JoN6`{6o`!CpG#NhHeoGZZ&s}j=T zy?zOH_^Y`Nqr{u)Fb<23?C?K(5ZGan?{D)1(~bd1c4N6?l$LT1AN609;%TqEfWl=o z=SuKNl|Ud90NO86jHgdYiHI(NTElrf3-2{s9Rs#HW(?2XA4JK;jsZXm4Fuo8rfDj}fBv37=gAZsV2R0-S`{oezco?8!a!(?|3aQ{Ry5x|C* zkMNQb%yLOdphRXl7Zjb72`6E1GVk))I42Xq1@S^AGgpF>sY=LX?($2}ly#ew;OCW_ zQ38d7|C(h_F#b#P@f2WS2ciK8S`PbsLoW0^v2Sk<`=0ZWjM%qdUI_N(N)Y>03BkU7 zehG#+cuM0UZczeg8Tc1k{tGRY?ZZP#bp?ias5y+i=MatTortFO+Z<|AT_kGiQ$!E>x|xxd92s~$p!-236er}0M`sNZ<)AzT1GA4aC+gdx4|S4D}&Pa27* zv9y6(kzv@Emu7umPg?FrSieiM62()*0k%o7@2-x2zq|^UJRP(xIryuO{q70++fArRyc8ZcyfSb&lq0=3Z1O>M z^bOh!HadoaEeJn`eHD6*5J2eHQ`~pM_6u`hG|dbrEH!%DP)ME4R1>MQz4M5G7t>XA zWL*$DU2qaX=e^v@+M&?cQdgEaiTt8ZffZ zNyoOC|5fqS%pIbWZS8|NV4&XRZE2!z8TnqpEL0M`+MBwAVYOSzj^uTK&{Pcrn`n9- zg+|d?PpPDaf;Ft!S7)F{%Dx^*%6%r_t3TYHc zzz6R*gy4f5a)4*3)jSj=`oIlGyG!Kga|p526cX&!)XA~q7Eb-do&C55ffI1zHR!;F z9sV#*2uL3MMaB6Z6i$(Zy09F?=h#lJo@;1tDdi2}d_MnlM8EKiqfK}gPHLrfMngycL<#AKNQB>S%As%~LMNFL6Q@IjjGKG0CwLqHE+heJI& z=@GZ~Lmh?GE-wKJ76H_V8RsD*kWi2jNXhxt1@dN@NVppggG9<*(NVAwjlj8GFmSi| zx8vhoW<{xoUWY@-UC{!B^h=D6kR)A-j&=C=`2nfmjPlb|XtqLW5=z4(iU`z&! zohW1+1?3c%?R82NmpuSEh%;%?9UhzQp??q0mL0Hrc|=e6Z0TrtC$Ua;raxh@Z^XP{NKnwgx0a(I=0vZ@f1+@C; zK5^^CBYakycg`L`^-#ST6b45cu9?j%xZ7-0jhKV*Mdc&#nwJ^4JOE9KD+LHbf(cxb z3F`JP+=2mc9+0w|936T(da1}*D1XL9(Jx7Nq<=FQbO?8|Y$z~lF{iXAcDDJ@p+mN~ z1#%?p^}bJF$upk%4!jys?H=#c8s-J#^5&sk^0>d&z4aT=Q1mmN$Mg_jt7bsY1HGu#$s2SW;l+ZoROKyC z8Uz@({{57ekRLgo z$MgX7p`zw}mB0aN_eIT*;}#*XFabDq!9zh-R)>nh@geB}Y?tg9S3ww3Sb9O9VfaI; zwS^PFbUr6usV6rd_&B{wzo(|0gZC%7`GMQeurSU=QLD znz|)K^OGsYf=VNRNd#bYHlVLb1mi&b7-J^Vb|X#RL_aN)5A(q;9N``|`7|l`lYc!H zoqF=GhfgdgU*xRWe6uu*C8b0yB$arzj9P6<2h|#^NdHhBZ0@Iq%a)aJkYR3jFx)CCq|1c2P&J&rYa&lZGnI%HfNy@xEdh3o&*E`IPDMsXnj z1$joKD$!7>9hgq>rR62oV$>G7lutaXTiSB@S!fxtw|8Jh0ikno)Gr`^Bqkn$QOfyu z#2IKYcRG=l)2`V8wJwYYv=reb!gW1|;aK9(ie6KFb?kK#yBaq`2t;aMc4;|Qu`M8v zq3F4w;!=hKG+}VrA?Ns!31?C+yHurupB@@_)s6~aF^i)hibL(>+fw!vcRQV8bOmE9 zrDurF39MvJ9=-^Ymjhl{;SpSpEg;*{e3}y~8y$2E`XX8#MhLJ)1%gnq1ZKsAnS_oA zE12PleJXWIb_iI*Ee1WE>ADZCUHVKLdK_43(22E_C3s0AMd z<0@YrhCsFGHftwJf$!k>gM>U~<#?lycQUfP4he6RylP43(OC>?i=zU$^SGFeBo2o1 z1h1F`uFOjj>ITMuW#fNb`3khYC<8q)=x2NR&~ifYTkOx-0VUU>MP9 z)FFJ7(RTo?zQcg!jtGR4srd*bm}3D{z)e+wpv^FRIUOAbKm|L{d22Bti+QPlO2Z3c zm4Xn7Z$uhyQekp1a*R|Rkis->QC~hg3_Uh`LvXXGx00JFXnWo(tWXPHj&)yWYe)k)=BjB z_qu&wJ6WNX12xp+tY3z zvN(xk+}-X}CNj<}C)1M}=#4v_uCvJLb(1O;`DdC@V+yWK`nncZj&o!`(1+^2R2=>2 zMIN>}9u1DcHIdA?X&LunT0F&X(%6NvlThXXT&Lpdx2NlD(sjxZV!e4|FpQUxX9CI; z_O&CH?Qk;vy_^Ss$jCR%iW-xT&{ls)^}njhFwRC^&T~r&)3t3G=S2^3=*y3fu#nrPO97KObsOCnI_uQ(_r!%DQ6-jH}7%sO)vSvyPKaZ0^a<>L_+lb9WZ$ z9kYv7BJZ16-x;WHI<9eD?^aw(@q8t&>~jZxhs$#>@^I{|$Qv7?5eV!F8`eV_9FHI8 zdLn)f{(1P=l}fuF{Zw}jBzog+Is=@A3?4)meEb%Cf+hH@@`#MhebHJvpzHFIlfYwBw1Yv$F=uW6`htXVL( zX71d%wR7v{*3X?ccmCXlxs7ud)YjC_t*x!CtF5n{S3AG9p|-JhL0wJV+`8Jjy1M$h zd3E#a8tNMB7Sz|&&#kYmudA=GpI1M>zM;Oce!;w&d2{F0&a0bOKX2Z=`STj)HO^Zw zzh?g2`L*-w=GV`kH-G;8hWU;27c|r~%x$P`sB5TinAb4Bp`oF%VL@X}zt!h!Te zelaTO6nn^~2i)#hZ^peos9<OQxxt0#>)*oX2C%AJQF z`;v|&H@i+I8%ukH?r4HgZ@`ruse&{DCbv1;;}}H>_b1?5;n(3NoQ@9eA9$)BmHz$(LqEj4BQ6+C?Ioo<5un02BTa%5c;;0d=j$6=-T~!WBdF z>mC8$0r2ls+^z0UCm{VhdtE}=Fm|Ba@wgV_M_K7TABFq*_!*`h3>Fnxp`vgoGQN05 z$@J2r#ze=C85fA!6DCZIOfjbhrkT_2qe5lo4C~k_j(xH{r=-fPvFBQ~<~`PZ*8PEx zh5u;%DfnmWFZQ9xgWCtMd)J*cXPtfB^*7G=>DX~+toqX%Rn@1Re?j}tcD(C`o8EKZ zCqDnk*S`MEZ~gm=FC8)h<0s6TTi?*M@RZimFW7MdUViHHk9_@G-+l7MmyE!evGTTQ z;j-ner(YO%cieRA?ceLDG{_p?rmqSB+7ytY7V~17{(=<-J%oig>9W0$X3z2@w5 z&%f}p%Rl|Kr=EW9;D5cA&b&K2@ct93s_%K|vtRtilRtX?gNtw3RrBs+zyH*C53OEv z?s=i`xaf)1uly#NYB=SzmSs2Iv|;nW%fB2loc4+tsMWOM;iw(ZhD&@L%5$4(Be z4wZ$@3Ry){#;gr2vFBhTVSLfJ(x$-C$G1Cufs2kGdOUdL9{Z@GEB|bt6Pgm47MWB! zsq~_v;-aI9&Iz3yTwXjIu`o<~ZprMxQAH*8&;xi?J@-s|=&tZ0dz`%})EGWFc;%t- z)56u`=h)@r%Et{|AGq?C=_QkQ-W;qBE(}>?r$vSytH_oP{SY5l7&;UjdcO3xx7!Vo zE6$%Z^l*6SiD2=xg?4dKV|aPEv?yD0jD2q4oXF5s(`FP;iL43?U0d|AyGo}9=H3yw z;@J~IrNQ9P-O(#v3z^PIMR@zJz|doMnLTcdQG{ib8L)z(kQEL`tYVm8#s;G1cxys% z;`mACWNWH5eawvD(cziqMS(5WL-wQAlh*gFr%IoW{LuQ5^{lx+_=5Gzzya$O=V0J< z3y5l#p1APT)ob4Up$~od?bp5c{da!y^VfW$C={80%Bh=vx9@v_Nz>*xY&z@m`#=8B z7v}As@Q!!h@F5=)iHNJ$#NG2h^VzZ)p>T1@q^a{4G~IjOGe3?r+<4Qyq2h(7b|>Eb zo>co6U-`|sov*%e=!3UbRi9Y7@%G(!eB`cs?tSp{kAAhNq;&GpO{XneclSNt{?6{u z^rI?{KlQX>7nAHmEjX310|<5pH#FkSX{KO$P7m9;LvrQ z$E*w&58ZuX#j=v(qA?Sjii+pY4on^T+@kn~(v^|o<;%)ehBu69y&|-{_-K1YYlDsR z??nqj#aGOqKJ;00Tc;u2_8R_@Afo87&iqwj0-02HYQAUjxBXMj{VK--6x+^ z|7^Z6-z+X~m^tQ!hL4SnEvTM$$AX#}FRb|8 zG3BccUi8A6HL3Eow?BHvTI0#sI`?~btTUc1UvKPxVMEOev5g=9*&Unq9e81rV1q0M^<}qdGl{7^n=ClB!7};jvY zV=hG5Qk1Mj^{5pSVFp50iPXw2p;3#^Gpq&ZpV!LK=1MaF?^DwZo9j#~R2uFytw>4H z=~fx)GtGvvCRz-Zm@^}0cff>Ktz}KO0(LZjbHrAWInD&!?W3(@@PDyohTwBw5;4J& z%>k>z+-e7`h*@O+1VBJHFyr1m61{yK9Ip~#7h*ko5Gg0%QnZD zAvS1RUtesPUnw{2cbOf~BomeqFyY3r)`Ij#-=|wa^A_u<31iF?!qZEt>>7;CvQ9LY z0P+?L-(j=btV6Aq6~wqtvcl#o1e*!vE*j;M$NZW3zMx@alz~b+V15+!8`cL(<_6ww z&L1}mqb#=PqQ;PUiaj%EhEIhPRDA^0Vz%1^WRbbsw8N7Hs-`)`92>HOUkP&{QwdSb z6LXo?uh6d|T+6JDVWwO}Sm3Q|V?u)lPAR>HSqCV-F z#!D?hV61sczzFq)jE&VhC+;-t_LdJ(y4c+~| zt3$@oZvK5QB1{MRQ>xcSy1<841ZY3tgxwy}Q5-n;Zk+t@a^_#4+}ii|^jU%S0; zv1NQ@`#BT8b*626Avt+r<-MjcYp>aH=P!fCBa3!-eSJa5IP{sHeRsYS{F~eT&&3xE z-T!C9Snz|hs#gBWGR}T9YsFwgIP~}_v66LY_mAh_`1my;W9ygNZ~jswV61uLj<0`g zddS#O^vN49|B7im|H{U1eR~Ud$H~{76q6yP?djGjWW8MjMU$NgGG%5#Ae`sN! zW!!g5B6+uC8ei^ysNp)Kzf5b}A@ujJT+6E7-n#quA>;cG-BO&o$}}3cKKA<+KMEPU z;+K6Wv?*ZJKm6OW_inX~rQmpL)2Xe{g449YcQomE|_zBzNz+5zxX@|5zz{tiRTxdM)g?1A8C!d= zyVdP&I?HupY1e@{MOoCi!q|pBJLp^2Krhx=%EadtgGEXTW~!XkSYd2NW7*lVI_!0` zC#q$Km~^lVGB!+#8t0?k?sTlrZO;t!_ovd?rlw3bm5yz8oASF8>m30{fUX+mnl6Ag zo2kwWbONZctUIT{t!b>UtBcon)iu<_YUfthcGhFvAFGyTkWrcuVCt5t^Tr+P1#p+Z z$TiTPh1Cg5TrAbF!fl-#6w+I;rc$1?1^Q1Mw$M%u-jf6=<%>_tfeU~ z+Zu08%3>JSR@g%`Zj-|y0J5+zpubfx`C0l$`-yrnb0AT>BE4uH|XhUGKtJxYdo1us>I) z2Qpchvb$^Cx%Dt|xpNz9=6A(v;`Oz)^XDy?*WJ(^@2+zj=g(_|A*;LE)5UUDa2k~} z{ccx#cRJPA4x&xBCt)XXX=XNVni@4OM4#v3M;o3uhPSX;cY79w1~e9)7B$+?MgxAd z>ChJ9&E0Xh_u5{SN^KeF7tOC=wmj%%K(z6JUUy@1OER@B*%FH{m)!!`Tu=|~I{Z<; z^y+-ekZ=%?>l4cFP4p$QG!V5Y6RFdkNG3?Hio10Pn{7{}+l5(mEOgpnI+lA{NZjq1 z60(Oxx1$+?qmfbACHX%Lv1w#_25=*fyB~w1j=X4FEYk<(kxumYyYW+7u-&m`m6+l* zxTKFwO{#+mJu_?Fw6Jl>?WO&L1P%K9m+8Z0O`k_nZK)icC57<%V%yPKkJO~oiw5dy zPwk9l+;$)nj6j)0ml^`{=91L5!6NnMRKCilva#N@CM_x7Nnr7n+@R@pk#r*(^dO|6 zb}Bj`G(;{4o` zad$1aotrjmiS=PG5lYhF9Q9y4f6)^?9|(2a%DfFfzvYcf zZhGxSmS6mrrl-u;-}gbQ~OTg zed~WdRMvKF=^mE7>FMXE?fL$bXY>BoANbk>pS~ z|FOVXYXFl zZW_tVt#Tc_9_nfnk*Q$HpSi)=ZBQKoE>sPil zoWtw%YwEgrJ#hZS0bZxMM_(h)%kTUEua9m1%R{{G`0%aYiBA2AN#@V^LYL8Yyb8xUW*@i-#2(Y`PH9C2(XF=p4rH2wBsia@LF~79Z>@AlB&;K z$?M6xt_%`@Q`^oKyuSUTZ!9MO4@GV(Apm<%{qf7Zes$pAUm+mhKkniw5nS(|6HXA2 zufOLPFB6d0FK@h$fV}0J`nw6pz6X~6ntxl7#v0bmv$92N`TbkmyzHr=_iMw#!ovz;Y16;S8t)%0)U@5t@wlw;<|6j1LrvaWX0p3nf`fP2fy)h!$kn({`dUp z4|M?GDZyV%DgyxjU_SWNalpi9qSwyY06;$ev9g^X2OvNBn}b&^Dg{2A{o5@85aYN@ z8$J$GoALBLulzO+#qR9WCZ0ZFGUjQ+6Ya-g5qkdo_``RX0ZvC1zxDt&tLlDxc}43? z*yWm5O}uFq`nNOqjoYii7k+Th{_Exg&UaK)U2>{n9Q^7XOKx6a7%x4TnsaC!;E;S| z;VW4Gee7V-%OAkH`}*D+UTt|h)`36#;MTf#8OG<&N?fq_4#T+M*_j7V|D0ibCe`tw zmZuD3>&EwwJMnjhas0b_FTZw*X{<~9>f%Y@M4x*s{p}rnrm^UZshyv_(=@(aT_3pj zdDHmAiOG|;9d8*cOX^mp1}x*~^Itnq{5{JU7mx1w(*oPLFR<-`+E3cXoEOUf{L6&_ zqvoN{_TKyBfbpk+Qxg~75HuDoeer_W1x3c}&n=vH_30tw-q)YlHv8PL@wSzp8*{-; z5#y9oz7c%pwPIt;F)iP(zoFEavFEW%jLxyf%)zes3xn8Web=w6_dY+t_`!d)eERnv znrs~S)(1Xy^;f4E`yRjEUEe+f^t0{1dxspO_|czr#1Nyf`(#2&x@ zCpE^(Jq>-~*Bgwz6L)-Kvbxyu-X^jlFx>>z`Tl{I~4ISM(idn0+7IP|;o_BK5Kj-sK}FW=i(`}UCWiCuS${mo6`p_1xbPdep$ zk)bZu-?jJ?E4g&py#|#edbEU@Y4Cp+Bts%E?CYXMgd; zGv&2LecyxYAL?6RtX=URbr*iK*_iptv;za@pJ6mU^(mvZZIcncbn7R-{9>oEYli)S z^II=Ab{@0ww8pPrVeEP0#yev7-E35@dFexoSKV*yed+X?#go5cbbKe<@Na|9E4$C3 zLs%j@XKXk#<789f>T!n1aVOT*1%Hri6HGeW2ipew-R9&V6sR^DJG$NU3VI7A^`dVJ zR6T6gLDpplPalYH7N4aheAz3-n+L=?vLV%#aI=HpB|pHA!i9Vkq+vX*e?Qb|O#cyn z&*l0)vnD$6EW=BzqG{SCzn+p}BVv9)nBa zBGr|Sbqy{7?79-YZEjZ&c5-9A5ZzchWnoL|ft3c$dDbvL$C++lCp2v|-v;wfW*|L? zbwHvovoV{13(}wm-u13(X_M^xZ{DDng=vBFnFGDq1Po|v(@-p63~J#FCfv-D9(c5P z4{eEl-xh~bVy}~eqI9oF^k!RPn=`90_O(zn#~S$WB$7)~$?nAF0c9iL%ghGs zgu8LxwkErJ2dKKJhaNW#kn%p)Ll*G0bu4%K`ZxCVuT1y#OE#tWP+RAtm?s9Xk-lEp z{bK12y{T+QBT{Awys6^7saW#tu0CbA(Mtcat!P&FmiC-b)$cfNSOq%XdE7u5r!rt=bczxJ}*scsnipPflH!dUs?A<@59b}oZ-L%#Iy9bSzm zF1!k2&FDG(Wwi+U>JLbY#^N7+Q}n#X%R1%il}n~DTv%S=o(O{`ofMrdE{J$P%DjLd zuRp`@Nct}hL&CDxiOIm=Pa@n{k3b{LN{p)p zuqOYc&geZqS@6tx$$w9tnE(8eem*OfPJ(wgiJ>Nwc$-VF75e)Lg40TkXJHP_@pzgv z(3#l0*-ax4eNeSQr^;#e4LTmWtI3GPFM=(P+!gLhgY*+kx-JN(>VIyWf@ciK3$V*n zC$Tn~<9gc*0_A?qW&!7clcNUIG=n-XZKwIq3-X>X#QlkR&mX}(eQdn^cj2BsPXF6o z?-W}qV2{4n%#Ir54GH|H`+LvVvmf|T3b=7C)0S-q&jyDT^EFMeB8JzdvKzg9hz+nx zy6Kg%%<9w<(%A;?wd6hPvde%0X?H+g!=RgXeLUNZHp!LZY&HarI&!boE{pPz=&pRRp&RUJjI*xawaYaF;l% zwxnj$ZW&7sRyh!_b7Z7w*@Km*FJ-WAGbrP2Rtl8Ux>VJM_CfC07V?T_Q&p&`JF%UT zsSUz4OHm8QU-T1Jlo-IoamDqP6urPyORqv>Z8m*Wku_hNs zB9SE+Myk&_&#OrJj%O~Y?8#>PGfmai@l;o)%HImAN~Ef{*7>Fj?1Ch-nK@8==D74< z&dg$+!X^M&#kZ=M^i#A;IujAhgf;;DJSqOBn{r&yn&PZZz&gB1v}PC^tD{CYu7c5& z$xaHO_E9N^qOQ=#YzI76cEA9;SSQ3!0dJ+lKKBKt`%^1q5_isoiozYX;=hC2llf=b z6G^2HX-{|f)z?Ig#b{#?if#l~@A++bo`~naqXjJ>+GG8RcB(ejTWi5Mpnrm*sP4pF zY=1zK5_eo|Ev5$gv9*=y$3|>|7)7e1`?F{2B!v(->D4S6}XWGIS2Q*VMGN)_e9vZ%#TkH5Cqp1q|b6)Y*(W$peqW zZ%tR%Kz{<=lwQYrw_%HmdvqWcsQ3_Bv8`}Ek9CULtmoFNgS?b{)O+5kpa17PT@;LJ zPYBKF*NXL=KC0w%`f1M=!88D{bAuamgth~>;)nKY~afLd&y{nJoZcSphLoJ)m z!p?CV=QWz)U7yvvW^%vOh2X>PRve207m~0I&2ux@jmztG15hxKpHuC6>o$4gJ>*yB zEr_U)uXeXBfq+lC+!9Q#cP}0QTjmR$3fAUwqc<;UNiVvR+`OdMjir_Tz0}QgVMf%$ zdg++3B;D)$5#;w{*>zww88#NH7(|9Yu8v*A2rSd9{ddWKsn2Q)P?){Au>}C1zfF>9l^imWb%iSVzxx*^Jo)!?ePw@N#E;LD@B=F|sAqcPkVS@0$K@^Equ4%A?NMw* zqcHgy-g6h8N$=isFP^!0@}B$f%*B)U+>d82n!M+&c;>p$d)|g;$_9=RxAOZ%!SgTi z41!4ywkP8G`3@kR+i+=3k?m@k7$a4a7v$&t4?Jgif(OhrKm9)o^8E_Wa8SwQ=Xn`v zs_J%Gf#$#aHQw>WKz`aQNCVRu*3NH`hJJE?elr*gwq(g)*n8F8{PG8px6@5Rk?Bgn zAAVRp|Alu6*`R|VB_rA=>PmopC$p>#wi$}lb}l{m?D+zyMN)efW~X8G{Z{&Q@jxQ& zYVcvH*xr}Ix)I9Ia9I6LjX}6yet%y@I@?k(8eZl#yu;Qy7GM6lUvqM(gej-V!TV^V zI)8F9u22;WfJYoJ7UMaD=OfAP5&J;MzZT`@;JN}f2-1ox+{;zlwRpY}?}>v7j@b6p zukJ-U7w~;Q{UK=`fq4UZtGmiU1oID8C)i zlYI3hW6VH0>(a+X-1cnF_o*K5NcXAkZdoL^Z%d`OxM^eU@G`&yti_NKAugyxW63q-S91K;I}ip2B+?P1LyZ z%EKE9GoE=B@5vvuMuU;#tYbS=r1mbF(2Pk-I>()Bw>xz`(n^sQ@4FZvNW!Beo7t_?5=l9%*WLq}jIN2O&iJ`- z{zbP_(9ibH!FFgOJ;rl*PdET_YOc1XV0^(I5YmYgkaJMH+xxe6<2{_k+WqAbc>BVr z@JPJOfSD;`><3vhBg!`7J$Z0p+idu3yd#dFI#^FOw{Lc{?Oc}7(wEimbUDBrj1hTn zL^|<*Gk6SL)!IRkDJcB+BAtB&{Uy2wRq9@(5oY;ms_(tvG_W<}JvS%&`qJ&FCHpF# zNi*Dzg<-cnCN^N06#$IDB25E0#0J>2H{j@4`yxFLMrqM(+6jlP*Z`&ts@+raawLT| z8c~jP?vDdjw05}i0G(mrU;X6D( zuFE80o>T>3t3w*;E`OY_BCP~ze!n~o)d2?Cp>CJAm3YUt^=3hP z5`H2so|ht>{nc_1MqTW`A&qUTG)OHR_`!;|mu>Xp9gUWhsn`M>_K!S~eAdPf=XYc2 zE$#HBY!}MelIZOP=(viOTkT)SxyrkhjIAr%o2fxRwxfN$N-A)n0V9TMmh!H9t5!4lPM@m& zYC7*>>C)$>DYZfJ^hwKrL3X(~PA*(oL;`k*MtN+PmANv)@aQ1?Ud5)+L<=*a2A5gr zv|veGnR0qC0RyK+jgv6$w`x?{1|;e?Tn90l5jFqK&c>K-cTT)>PEA#9opv>5QoIv7 zIaher;;3;B`p&g0>3T#xI)hx#ou8bH-3tKkw^RM^kMdKjau5LPMLV# zs-CO;n7nSQ>IHcq5j=xBBm#sl{WrnwQr&46BgQHbi|MvyYqnsmwuI8=Oi&hd8mNh~ zBhXH;K@LHp`WU+Zu^lJ1tjhv98MX@ky@iscL(GH5Xf z>0*@XSYAT-wWI(2@Q;nfLr}4`-VEZ9Apr zE%SEqgsamy2;(p9%ayZ4?+-6kdQSzeB8!x77kt`Y3!JT)3b{cQOp}O?8a^BS0qPp(;7a-0g=+-Y zUR=2z$>2&^JcKKCubXkD9D6^m)LFgfkK&oSk@x(F&bJz4QM;f1Mkba*z$%exVgRIS zCziGoniao06+)ak5-r=yv7=1h4(EY$VYPrwhMVJAJT6t6p-bRWDt4^p5;USM#hC!= ztycivq}Ep(;5@8vS7Q$;)0V=PGk412;VCL3GpvR=vWencq&Y0nf9DRH*Z(i0?}VxB zCUg(<_Il=htPFwR*sBCe={*l%AC~Gk)sglywJyb`0v&Plw}!=?Ldwt(tBE6j*TPHE zlZ$q8T7y@gjz3Td)2o~_pQSp14*J*(LnwoGq@Y`4VK@75EuIP;GWLc($j z%^q$S;8)!L0rd?!9m7_`9aYXsbd3Eb459aJO{4~}DM>P|a+W5b!imv(1cYJr@6DvJ zT>({0m(~LXH*?b%sBCjUwbLfm!+~w}nzm)!F2zQKRxmL>w~qvZ?NCM&$ifsipw?$# zA~1?}fqW!HKoTk|_M^Cz!yYIN3fRS=4NqCz$>N9a`YM2F5TVPW!jyr{VOOjR<{838<_zZk zk!>yV8}nOh2G*(iRR!An!P{_v7)H|`kmwvsq5&$no}nHj#EFtRI8?w8{35k2gW=#< z7WUX^ClajW@hBc|k^)@tVy3BVGjNBTdt$_-F8U!keNdhe{wC8WqXVqEsD@)iUa@W$ z2fU;rZ;wO6RRBO7m;41@4xtD&z8ijy10A366ZMAGK&Q_SyN<#sn_H?>kF|tN% z6>h@;FrYH_^MDZC2G5%`$=<<)Bxh54h$22TWI@3vVXxlmpD}@$$Q7MOxG8S(Bw%|} zENL5-F2pK;My*3o00hEPGDtc~^vI?r?DZJs20)LH#QTnXZ~qPfo=T#h1>zB5MC>lJ z_QK2F-|^RSA6=$7owVDAP%Rn);t!*9fEegu2C>>f!=B?wf({Z-2aX$nyq7b=i&LrH zWM;7zjPGx#Qt!6Xe+UZ)y_K5n!8s#`jR{J3_$?lxAwtUAKX7EB}L9snM9<({+Q?+z$TjtCxZrJdO~xYU6oR&TtL~X zK#mtkZ@fKjvJ&DX@umm5g|Go3oGq@~?^I%Igq*P-`aUqSo7?lVRQ==wB9EnCTJ)el zdSxJtTSny{T2a{Iz2{zZBDoc+W|em?%vk~6O@M*m5=lq`kK==csftx?Qdema{lb12 z6xq15VMF6Q@^q}_707`WQibLXU}C*7$OoyrB9ocdxLibW1?2{;f(T&-8wKPr>e4Jy ziX(^@0-XWfVi^z+Dis`L2fab)FlIbi#VuhS^GbIGRi)C95#-l>u`NQ?>>qeKy>(Ed zcs_O~kVRvP>h*>V^BUL6aHs|?@sRR=y1&19b>9BI>{|JM4t zv&*`L*x>2yf5#fiFYE88dwLrWj!>udp4$qZTMC|!DR@R~WGR0yY!2t5o=5S^ukW0K z{3{Bc=M+3|E_hy4@cg!d=UMuhzM4=GTHp%mLa6Jt#fYQ6Vg$zOt}}~#?I8OzHf>m2 zaFDE^tY%e;8MURByY7;d+s(Zjh+6GPl!G7R|8e}iuos+<>t{7Qyyray@WC;2$-glv zi!C?qBTxPjF|jlzaF`4}vRsp41dwP-aipIakd7`F;(EjiVo;s6Hv?EZxCjEssU4yw zXSVq3aDn!bbqe1f!<9B&*+|#Rd?}d%R@`hD4*-S}aQYG8^=h2>dkz*)`oVwV7sdgIbl^)|>@v-vs6i)y2yU z_pGc=!Z z{Jpf>IC(SpD0l0e4t5uF4`7N*c}LZmi6qDE#@lq#D6kpM@w^f1VE{zNLmQ&v=l73t zL3#%5(f^1&$0TarsGqpDg|8|%Ob=9NF7 z+ZS9^mN2#A$W;VITTBmC&Zej_Gq3D_>aso?BLU^KbQK*F@H`*oxF6{CIg4`K2LbZ{ zJ676UF2<^A>t>Xpoc79W(rsz}1Jy_E=Q^^I1y>WX?=x7MwPcy+ppM5;7yXXBx-LXr zgqioeL-(gyyp-W)1b4Z#XKlrnpFE0otFUP~R%D20=w)0YzVBtdipm zp2iN+@M+_ZxX;JsdkS!OOTn`zuRYpmE_i=_!Lw8Fd~?C`_4=9f=Ib-9@w(dP%xWyK zu;b&&9qfaitzth8lQ-INAtx9pa)d3qkT@gW9!cQnQX+3g6okC-#(Yx27`h6c?<{!U z?mcryn^H=&)sX{y9pj_Fvo}6DM4~jzyiywmpm}4R3*A?F#5XHEe&z+5;R70PFj{)&;ldNDMC$W(%{(S5(GC-DVVJ}CuFt!YxBlP-+qXdu93#7xhtbxFV z3l?Vtg{+CVtjDe%xIdF<=u_jSVj(%DE#~E3Iu}t~7&+MZhMg0ArI`;JDi=!LpsSp- z#KNHm2Nuo^{P=9A2UZAVRHMSMy*F68D|tzGHf}|rQ>kq_rygdX3w1%Q;Z!lQIP?lT z(|w6K3SR9^=(4Q&bxW%6G`xxWK~Gj)zs{$ck!&jRPQQz0`BIzZVq!ehhF(HQrc2EZ z&=Xcq9j#gxi&f5Xu$|KAMqEa3xt$4@PC9jqq04{roy`5J80MmjRz$3G$SYZau5{@D zO^kpcAqHX1J|rR50CnXkE!anZs+B2#Nl#fdE$TcH40R;i)VU>#Uq1V+IKTIf?efYyWP#SYnE|y3*!NYLFg)XImQY7;moh<-SZraS{ zwF~u9eDAfRykyvxfJsG=OqF75q%Kw~wk|O-sWmv&O8Dm==U~CD;w%9*TE+HCVbzC& zDBAGqIXg&4-~*u4VV_npOeoMU(1ddVs)Ss_pfWsu;8_mSd%}Yat(K#?H5iRQgX~7$LS-21bdZs|2iRstE<0d{$Rm zbtKsMeXFgh`Nwq*Hb0!y+^X98M%`VG$_J4U5eOX1Vpw0#n>*X7o$b`k zb{J{dpHs>RMZSuG){x`RRg{Nd+`R~)F7u4(b!s>d1^H|9vicd(6fE$>v@`uvd#%c_ ztZdYp!T@m*qe#RN1!eO`8=#ebe5^p(WFc9V6p@@BFU5xvV0ok|`Yf(trM`|;;uoL} z3c{XEG5~uc%b-M3vQAhE2nux8CrBbt#hC}PT>p$=)i9E1*y3NU7W^y;<%EYSafGBD z8x{cGTFAfF_%a@JMfp`cZ08>Y9G0prHZG0~BM(%)bhZV@z6e@y;$n8T72c;NZFA&CX$uF1}+;)L2M870PP!gn>8KfJ^>F%X& zZ)~tNiG?FVA!aho>Yzhw5=N@^G3Wz0E1zmhrB+d2^~`Rb!4OLeSo-6GZKi zJx3czoy>Bz{#Ygk)&$O{NZV?Kn|F(P{AG@AV~wnE@+(t4UV{l<66?pw6*=6ha|sexxqN`Pd!^?Q7EIJM-N{slC12E0oPCt-piVWnUCJmcOs!OKQ!BRb$%np`4Lno!mz0Gobb!z%aa? z<@Us4>cEs<9Y{C1=dCt`lsbYn)Bj`dUBDwt&-%^++Ypx9G_YBgOQ;#ZRu3&{F18so z7hA1XPs`J-mL+x1n88++RMp*bODegl)ZH>B5WuXLCEP-=0pCbS9>T>y9E@2YV6a&h zb1@|BI!{$@8vtEO6s1O9$}u{XZsn=sdLVEzU%wF-+O-{0@b-) zgEr|TFSRiMK+J-aFj}H~0N^=@s)Md7lQRGz2F2KfmR-X2j93z?= z@Fkpv#!*T5BePUgu;wky><~LGJhDvwT8CF@9aF;yKm?mC?|){v2VZUZfSAWh7i#C} z6dE9q-eZ)rGhq%c2DYzM-RNPgaSg;$^nGLxR=PGOavR?Dm=3>{w6w8Kud%L@@^E#Z}RQySQsJ;z%SxoZQfx% z)o~oSS((X3@SyW}UWa-uisC*@juZ9Bq&K1lm?%fZLA}qgbI1y>z1n^Mm#$r!lh%a! zk(q2K@9|c9HDZp$K3S@_N1=-t?`64hgqhDTVo8ZwuLm{)%4@ocEMR1UeEA(&9eB+9 ztw3R?uxrPrz7w|*iqFv-(N)%aNNeH_OBrqqYb(O9Hftpt|2Yto;U?fB)yM#HEb7w5 z)6y4Dni5G{+PoO1ni`?`PtQQ6gS$BSol$Nc{)J<;VCFzeMoTL55y+T5Z-k%#Mr_74 zWn%$<5893vtt^`ZAU?c<(WlwH8#tumAElksV($FF(ZZnMgPYR`D^Qtgo|n#YoFU90 zZTOf{Uk``a-Pqp%`)PnSL<>G@jpNrICxawnlkz}PF%j$gpoUya8J4B zs&yNoAX+NJ+*%~Ce{FVpYQL8L(My0GRA^@t_nl$pf^23bLQIZj4yQNg5FkP0KHFjn#a@Hlv;w z$~}r7Y%(p9u4i&OPGZTyU>>*R19I7{zi^!OkR-+{Yw75XI;40v#9vZBCBPcuY$(wy z9?yzsm2?9oP5q&2wXU#}c)l5$I8b&VeX1tT&K_0kOO_y}Ck1NMfVo>DOYtep@%Y-P zo*q8%>=7o^crv6l>ZpWNE+R?^x+-;vOeG*Z6tUDn-=VnvL}WuH3}!8H4VV8tn;5`U z`YdLntcwY$Y&>356iL&xSd3=-63E`>*zA$)18-Cn7MM zV9E3_G9*q&MROZ;38?Bb0$53`;XBTDKKtHq z;Zi6O32F}{LDY~-RH`3vWVbO2?O$b+Bniu$_bwsOwP|Hm0*11}n(8d*LDk10jAA_^y=X|;@1qLIEUb^Ue zo3n|J3_DJkjGQ&jsV-78GOp=JkR?wJI)`US*KF&o_ihF5LTcG&uQH^hv&zr}MXZqs zyS7GY=+$OP=Vp#HTN2S>3*iI533*k=d85tl?Xtnugdx4$fS8SQ@|!M3lcY^g+rWn- zEA=&J>L4;IKy1s{Skn%OdVKS^Zbm6AY~ErIo8~}d zI^=#k_PWywVZA&cik`S_Mk#U!Ir}rp+cvsd66L~!%Wj+{I52swdV7qvv5wK%v<^;r;BJtR~iT?2De8_UX`G(6UNBCHrY(L2JPvZSQ znsa~3v>*6QF^h*K)rmjd)9b-l+rnOUa$*~?e~0C=x+UXm5E$}l&It*?d^lE# zYHR#$>QT(LEL9tGDP)jGneU?Pom@4MV3!e#Y-_XNZet{$>s(z5UWZwq&P*# zFfLnIj1SsLmNz^W8XxA{`}x+|6uo6y(nK~1uHqFmHy~AFviP|gW%%}muf3z8xO2j4 z<9wjnf{ND`9_;UII4q46k{096#trI_{MC)&TtH?RaQB-09FPtGoRA{g%(9LAamqiR z@+UWkc2Xi^@$E5CCJrPseY00Yc;8{F&H5|E1l4BHyb6@#1p)#yKUEAM{XI@|oSOZs zQ~*ubL5FZTieA{2bw-5G!cNjih>f9y1hp3?=Ha8N#Z&N zN%#B!pX^nZtmX_71s+w@D-&xVbnpNT)FnBn%&g{|hD3g(AtIPDxiV@M=0QSP9$xTc zSo5P!WtlYC>@XSUFBxI|xa3LM%hFmY=mJ~XZEND$c1gjNqB*8mDGk)R5z}%|Jd&h`a@puo%HpB74%A*=Nlm{ zljd7u;8N-r_+GJ9euJy)Iz{+E}=qUjomNzJjUO_RerA7P8*<+FS|`_coaAV zxt8EVQu8I3`p?#4!`b0`$n&{s)ur0iKT(-TU@(G|& z=0$IrF<_)j5y}00j=tvacuW-x$Gd$y3}Z}4`*r|V_67C(ySVogF3}N= z5`-je^85$+?qj&Vi>tmnu-`-L{?sWHL7RB=PTouU#CuF``_T-FWY=d zPTI>rfMIqd?@o3;bTBj_VitFEHss_YZSVi1?1NZ?``gqVmT=yzFeQqf<+`{B8Ow+vNrRWS5^YUuJ3l zzS{ls;~qK_zMhGZ+WeY%7@H8o=K__wculu`Em64JGT5N5-LG-pA=~)JJkzLq(fl9W z7ojTS&edsoV@wEjoT8lgxT;)x!vcq4-m9QtTfA57iR!)1EP;v}6MY@;6_>4KT)^%O ziAn^(bc3buqm1Z+cX1VdfLQmBOF0v#B6C6AQ4<&yB8bEGgM9lLeETQS9)y0AYEU_9 z_>d4)m!>}J4L){pC{0D+gkEfu8;$d>2{B|A9xshDw-0_|bJtPr?+|0?UJ{zxek2Y| zLLc$rXhSiETKtJV%e)@XBp%QoQpe5X0R^3*d{xC;b38xmZ3i-1ulxQSn5WyUmKZvb zOvC2O9gB>#fJjnC5G>v7hwCP^M@+)3;5+(oaGi)?{@bk_;)dNBzYfoe@Qv)DZ{kna zZ;tEV;~Fzqbt~sFUevY}fygW!NtQUODXBFv8BNsYrr(wAfatCy&tNnxa2a^H1h!L< zh0Ix71kNt0ln9Ew+}@hr+?g~vs%Y2e{ZF3%vhXE>p%HMZSASGPRUl{+z+OVQ;Vy)#`5za=EGlTZ8 z8~FXWGe?QlHd+((^(GX?HC6;me%qJIV1h8=5t60^bOT@PlL<~81 z=<3mY$|fd5>6d+S2X#y4oa^xEabM(07z0U4zihZB7%J?>&SzN6B`NCSd422J^Lev1 z5hY@#BeGwX02)1vLY8P9)zQE`258xjZTbXSZZtz8-zPAht z($wp4buya+%%V{2p(|kB?g6)A{AHc;FI?Xgb7(S;s_`1Adb3_V2pAd}ck4>4cemLB z>=|f-Aw*11aqhy(suZSz5Yvxp`(18tuS-S?QO*X#UdHX=H+L=(^M)m{ z9gX4?oU&n#Y6ZLG!~%K}ZX@+IJ@UEPSCj^rdV-ZKgjbexqV|Zy7JGadZ z_e$#CFb@_if6BOQ+-NbSE=+p>*2L4%cw@|fwvp+qESTrUl^!&oFdK8z?g+xMn(>HQ zy9AZzE&3Vx1krnMe{utdK#R^kDN`v_^B6}kZnVu<4Ta^YuOzyhnz^|XBHod4ONpX; zH=EP|Ra3vok^x3- zRBF6r4g<@F-8V1?q7?1q6Hgc|xj|_v zZ8g%(DU3!2S1p~o8{5=7R#_{`6G%JLND%eEb}WI>&JZw3z+pqnDGX?oQk-1jp`elK z+?5sqZW<;OBu@)~35#-OY7)GT2oHf+LrX+iZ4V8I9`Vo%)py8L^X1CCVDwL2L+_0t z!IxF+Vf71=ghfZef8VT%q&rrpr4Op3Y;7b>NsiklzF6No?ZgIhizOWqtRQ2k0J=`h z-l~BL?Vrfn*!b48lgPFibaurlGO^#=vjbf|dg}(4V72**s0MR@lhI}hH0-36p-%*8 z95pPJ`D{Xul{9M5w@J*F_L^Ia%p~n3=D*ddyU=5OXJI zPtGR{uyn%U#uQsw;N5qal@jFkd$5}54lUAQHC{x9*qlM=VRE2+nXWs!9)@4H>`BZh zZ7b-Sf(P1E*{-W*ip`)21milDS7fct)<&xdniZMTx)&k78Y{Y0cTHhOh@TAr<1M2b zf6?n7=BdK_gCVY5W;S0!A$FDg4Txl~%rrmyEzV2c#}$_DKwmNz2uF*;;I3g#trSet zsO-(nXQnxg6R>I|ABCl3igYY!GFGYcZ&2r#aFs0f8dr_)I#*Gv*?rsW5=aKh6 z$?y98on!B%530X^@7Vpn7`s=@@Ot@Q8hd}o*!zzfyZ^(n^8eS^z4Vi+|Lc%1ky^a5 z9`9$?)>c-}FV8+Yzjkqcc}2wV+RWqK_SFawcd@%M7T+x>^qHCKlv>LGaj0`voG|u1 zAJ1`QvBamSJ;cYHgKPo9*J-a~kdV0Lm2<`qVo3o@Y zv>}I+JtZ{Lf#VV&d*$(-fcWRU-EGSf7K=PHI)1Z7@T@TvTt07XofT8B4p*N(1~22F!z8Y}ZHB8WqN6W2;1@I0uWr+cd1`|f8;l|A(?#-Usv@8K$c-(TS>*^h?< zG>M&vHcKehy))6zO!K+lc}Ih48aMksaZuFbkw%;?>)aXLYd$j8PaaHFO*GEZ#w2a* zbA1li*Kt)}pQ=q@m9zje&7Y#Y@W#n@AC+C?C}c?s5qW3REd-j_08;j@XVAvmzSd*B zNvEjwGOr6%R4Lb2l0RSPR_umL zaV{|wu#0JovqpGr@g6$OCto?$=>3B`8W-tX&fojE7j7=FT4^7$+eJ&V*c+a+n^|WV z{iec4I&T=d$3stgx2g}$)@@`V+2~&wpOGYXBgk5}dxiE8G2!1qS4M~!OUpU6fHZGs z_>l_Q$5{UEKlC+?flKe|KbOsWHEsqgsDgI$6_L$gO%YJencGX})ZX^?{+NMRvAEJ` zJwve)I-Z&1ptIaiL`Umx?hecSDH0|2d4N?T(s9~4zeDweLc|h(P)gOTk{10p_^P~( zI_oxg3lRs-tSC<{&zhK&a?(xWC}ieRjF|vlo-^_yOe7j)s|oY#qCPFD*yl*@;|uBH zTB<-KZM|HSalF}O!V6#_I^S>e-=K)Fv01q^hz5W)oDEmyyFVPL)QW`nAmJ_JMlH;k zjyEM?s=cm%&GsJT79=M;K3z~Iw)v_iS4vN?t+Vq^R;uS5X_hs@6jceOa-kORydN(c zPsXfO8;!&X{~`CrY?Gu$Xpu-rB6l-)C2x^I(;1vLY6)0OjGKs$ZypbhYP-$5u5I?s z0dBatdzZL|^`0EJA@MP2Y|%Tj$!@tY*X11G2D7Qc^UDOaVh38r39r!!B8!s+cU^AZ z5cp%&iw)uPEe<+@37NS8rIGe+?i$CAm<-E8zJw07tOm6naPVYYCAgslbY@jBE~2I_ z%5R2Y*42a?AOuU}G6^CQyTM!&Xl!eLQcl;M=1nFDE=G3rs9EXPaWkznMZHnT-dUds zB1G6o;7y%Zs!irpv(;)T&B+O@30Udo^t45-Djk)^Am_LFaQR6d!mW)7HT+=tWMm!n zU9_{Nc_W~c^-dc|3qYJFeNAAe+GoVtHJ~-%co0G5t=p!KS`+kyu{7B{VxCz-L~jUt zkaEgRXJqLCg@6qKp}X6GmzDp3g%+fgm8Fw}xzlEAPLPd+~%ze3woo=Lm*W@LjZnkwN+_%g%sCKISoVjeCvmbjsTGOu=`9$R*YC4`(BTY`!^vnL~A^e zd64gY+#*G^|6h^(*i7iVozn!Ez}QlU`Yloi-;^e=^S9#T?f%+*8L#@VIi`r&J6yYO zn%#k@6`p3|__H=h?2RNR{#W1U_LpZMDn$$Czgm9cJRV%WCkF~y5QGAoym^Sla0n0! zDw*m*qqS|Usvmk7ghUuk_RSFtVZ?&8(RlOs`xrh4LrLwMyic3byic3bXFY}9zPun< z66^!taYtj3c0cMl4YP;K`{!{lSx4Ug48QNG-T&;^{l~KgvPWUUMF4;xW&9^w@9R*I z1m%<9&<^Ashygn&8{fjBY0O%?zt8_}cWjdQZ5X%}v(Uze8Q06G_m}w-Kl$wIMoqjW zizIZ1(-z)-n(+41V5j~*Gr9T$cQjhGbDD7=qG;s(Uvhsp_u>Qf4|Hh%G-mxfZ1W`Q zJuElxAJC3?(yPz&d0REfD%6u5h*DTz!X1d@OA=+7g#qH#8~bb0B;)wpCB}{Hs>;34 zYZ#Pe5k1P^mcp`45>0|a>M#*5X#Lb1+_&kRLrJYnhK@ z9n5Qb?Hc2V2l~0UBhfjOsq(sZVbbx8)krt-ClYyGp04#O_Tcam_B1OwP&{9RZKK&h zlpYQwCDMvD~cLR^xj?qTk1#uHPTmcf|Dv;`)Pe z{UNSVPb!P{mFU?6#%GmBwd$pb$UadYbwbD*^%bv(GW|x$uYDn7Hd@il;$kSVr~8u4<3Em zHhVw+gYFB`<{SpBTm~rv5os?sEV~K(ryY%!0Z(>7u$S@1O-`gsP84YVqO~Hj22t=M zIbpaOv|dsgEO=Z+#waXuD9DMuYzo@Q8R(+UoFC1-%qTE7aNktx<9>4jQ}fWXTUxD3 z+3vEnjs0SirU-k6KHOv{bbCBZm{~T2faoby?HapcJwc8FVy;i9Y7u6b1cuxDum+>>Xkrle zHZrxnq$}7OfUGp*R(04Ys_NSXP{6Q;fyMweY@QU&GndC8G_~JwEdh{bNoOV)jAMd% zmfj1)l6zn5aB+NUw${uu1HgI*ZI_Pq(zcU>A%NE^K#%;YB{UiqU^Q%t-9^>K7e5eP zd>UYR$RHd@<{0e}T2Z|9$7^}xK7!^Ce@45qd-zD}cea1R^*e?r+>U|xqRCv%nb?^7 zIL@pTG?3zHgI$+h2lVbAa^Jq^bMQ#-muFE6{#*C?UOu|Izl-uua+Tk_?!Ov(QaWDI zL-q2?IbMJN^JDj~AG`nhxX<=?#@bK4WcFu%?E5c^`+R?5?EU-3?tgjg{w;C;+8_2g zy`M4F`+sAs{2Svw=i}dxz5lMU`VwIOs zeh9Qjo#m`MG>ka-RJ!3LZH4VUO#uh@5U)hyr4wEzog2n16K@*3d?q@zR;#xVZ-@C} z)Vs*WD83j6d^8~MR*3HAdeJ36L{OFzPRe~cmn28_pR9Aj;W>T-3XP_Tk9Dq#FiQn< zb`l~);X9(%Fmjw}PRK`;kh8K$LIaHnxW~d1*?n2YjAl2vE>1ix{@pST?E`$MPFH9N zVk}yDbVb;}LrtKTmU;q`BKqOJ9FkDzkig~0qY2Vk|8mfrSVsx~syAl{GiHZ!63K$4 zssx~0W|69}n`k38MAi}9G@SieSzH)gb#)ixyi2nX03w1dJ;+Qo5dpTe@`%ICe$1ac zKxv+c%c@gd^C;nKq*CoR@3vsjeRR+A6iHt-opWJSE^;+|FUYtfB~kQp3*+NaYxm&- zv9AF{WD`C>DWS}d0Mq3yQQHM&eI2>(B zv1x3=G|RmWWX4cm{=PdJSGWd0JTtQ%BE}eb-d0_5J7Vn+7TN5Dm0}7E!R8dUQo68+ zjdh~A&vrrsy&G{=Sj*(O$fF!avZl|h%y#9~IMw(N{bKqW!SsR%Wu!kig~fG{k`{iw zT8fpxUXLLZnw3n*-m_IvUIt~mFcRL%B&laN@n(hLgIuYiNXFvE(o{6bPtza6wZdU$ zmdW0gSw1}c9!NBB&|n`y=eA?Ivb;W>ESC9I2}6l?r~8IyVwUxo6-_<`H?;XEkLG#@ z$FJ>Og;bNGS23CmG;@JwX4vKO_7p-|cIig*OPl-?e??$t%zhVi1nhA(NShV(^bV(rkX2>E2%v zM)jt-*7#k`b?E4GHd~%BuNC8+y4iqi(wiqyjhhDva|K3mfrFf|@WFy}%{h-5hCg$8 zdN$@Gji#(Lm9*-!&@zS;#D&Y9xkBie$m+zaY8xPRL`1_5d8+o3Q5)p&(!T^`&*_Jg zQduXnNbxx!yL zw!fva@o1$v+^Y1Vd2y|H)&y%Do|s}_a{6ElD+jCa;|V|V1^7DLFA>Adep?d^19-FO zrncK}(PB)D1(N3&O2WqnR$&<(=Zx+eaUZ7cv8^GtIf82#HiG|0e5X|M!T(3NS`%_v z`0r{*HYJqwjh#Y+ij*lRx%j}C6h&jGYG8z%_$6mo2u0aFvgxq3FnYqnc2H@_K4hAdTVU+A# zNI`rjo?z|J#u7`4k-)BLXJ8})#$+-;+lQ(c?h$IqQB~Nafk))|*_l;(4-Dl_8$mE9 zUz1+Hyfgu4P^?RB{Bed}WuuX2=vJJe|CFormC{wdli&Z0zaQrBUHsMG{YbofH`gB> zd-p%byC38F<74lBBHrl?|H-j;KNauZ!}X`f-u+CxdoNeCJ(pwtAPLgiUWsu0~Ius9nW*i^vr5qj_>06^oD+zJNe*jmDK-1Ol z*#C~J`1Lw${w(eNFZ?NA$N$P-OouHiTiZ`EPa#JOpfp-XFIFE?D4BM zxPAid^tdXn&wf0ozZ%fl^N%jfHRqR?&o9qV-PJC79V6V(V@@YCxaO$kl0^}$f(y9| zjs(B1oArGzLkUY85>%V-Wlno=j!c}ek&>Tr$AV~HP^MFDX;POkO#XvDQz&IHDYCOpIgi4jTcp>!6jAUN6 zmeiP!3cH`5gvs|sbiZ8&lcSD`CG6zu6%lO^T&~~EGAD~>93+e--v;24@1oi{Q@oi} z&6MfU!HaTtKHIy_x~7cmPxuY!xPGTP946ec{5Q-lX}Fb?WD)C761q5^h!SJ*QLGgfjGkY1|yhdAxn-_u^+2xL*_% zSd7G1k*#DuWM}op>gzXqdfxnVHDpn)w6jx08zO&(LzzMJf9os0Oiq@uf$FcBu|E)k<-XNH6%`l0IV}`mC`44mXc|p zvXr%Ji6RkNwi>*~cx!46AGC+-Na#dci+lq}M=U0(m^zIBVPtVF?in<)e03FH682gi zH*P^9%KkL?)4m37Rf=gcBbBn_d`ng1c95KhHuw^&6KRR0jsvOt)%u7wLy|$*4cHbJ~zZNR642FS!Q6>;@&^r9?Zu` zO&Zq1+j`I?qcRIj!6h4~&>{R0eTk^|$ZTzG)r_{bY;Kq{c?XC3I&qP$gNDhRr3bZ< z6grwmHv5Da<}Dv36D9Y4!7oE&&*iclH@s16QdrF8MCuDfZkfFUD3(fO$EMB{TOP?! z6|&Mve1ecvoQY!wKlKe_SV5V_`&x5wlID@#c}x-MY#p=n$go2Y*4AIMxzavZD2$1O zpnbZl6yeMb?iNGD3MOF!@LiHh6f+4B6&*uuso$B?hpoYeQ$tpSjBrj7!G)P8jD#Y_ z{<=Mvz&>+0nG8_dAc)uynHYQOqGeuU-2nao1=)V#uuw}8b^wwM%rG@CLo!(iEP3}7 zMxlrM`;OcQd}$F1i#m$UlH0?R`E0eZErbx6I%_{}SqUSjDDo|#9o1;aX6mBNKzzB% zh?0$r2?HQh(9S&uP@jG#9hn#;F42vI$+Z1)JU5x|`aB8Lz^Jyya%04K2Lxe}qz8jb zdyZ0B6is5Bx<)Z-Hbt7EN>O;C08yTD4BD6!I0HIQLxZxgc+!WAFEA$4!Z?g&HKY_L zVq$VfQ90`zVhN&C=bYU>ci)C)Ad6Lu0yH2}^ILYCvrIvOL^B&&P?NDf28Zgcz(hLgyRfU|1SrcMi0>LE+Q zr?DDwDS$4t#ae650-KiE9>rvn1(ikaC`T8LK&R#ipMsbyY8OaXhhvC(1gsI}kHs%U zkcMRHdZEE2!TjLvV7uWY*~$H3Hy7RZ%KE!BB_!!tiwRmWe;CDcE2=szc6;+9lL)#?k@=6 ziUU|d<=E|{9Uca;={YDDPZTWn8hMWb57X(b_^IypLynZ;+6M$^M~clcu!0BM8G=7_ z`$bP75KA3h(Vx_`fsS@V1#ug?lUp}*^zkH(XGX@Rz;)*#$A&ozxW6VAyT^I+A2w?3ro`0IMrV_(*5oi&rrTD6wc zHnTk+cso9x0|jc$j*WGs;<0y8?Xu24q%-5w6t8Wb#%DO3URSW>^Im&e-mwOhAf#4u z>@E4NEwu4dRFK8SzAj>mjm_OnPMNXS1l&i31MiI_A)7lUY3zYfn7E7d-A2VOL?+eBm%{+YO2 z1a{ChYEjI?Xl_{gkUDxh8KE;F^DHc4kFgx+y-_@7iz~6T_u1utu+8$KlAj)gSk>j$ z*j5PGfZYfIBlOK*0I%Y^O*VMhhFL=Z|Lyc-fvnZ^YPxF|mw`zjBvM$EH@5N!0pXN=Nwh6_%QHZ>i`Jey z-?Dlyb`nt`TMzD!jjJGj6Kxs$)N1#-*>pFlT#J^=TJ{C?tRHXIJ9)Ee$|oK!HfwT> zQbQ(W$eA>7vUMKqA@~}7uVDebwQurHL;ehPI?d%=%qEW zaH0tyOx0T)8Ou!@oWIQmmrgY2y+PK6tri`1PS(?2cGy-5hnsL{$bPi*>af<;gC?== zs!3ch(uq{)YL-+6^}T}g_^jKM1$5Ttd`7f>$Z0T3oiqVa3fd6=F^we$w&NR3>1dy{ z#aq%7FrDXMAcgL=BMT-L$0Mpfxn1B4Eh(tix@qSoXoU!tDyaPpugLtX3Lk<3erZGw z*CS%5G1#;XP#d4Y)GD8Da*}dP5Dw;{C0bbMJYoVd7wm;t%o4R9S~4an1gQw->?A9B zwpbLkfr6Dbd}%Z(zA(TWOs#nnKm&|)Uc2@{)qX14$)GVSWfP}n{X0b*NYZnJ7Mt@W znhSkLt=QP1VN_^GJ5b>E0z>ubDl{_#JZxT)NP$&ZGk=U1z+GcEBlTY6+V6S(!J_xP z!tN^ENIV^J?pFbH%6#{UeE%Mly9cqVS1jbH!6 zr{U-6d?f~xl`Gy6Wj(2Cu32&_tiMaXivzFW2FaCN{MhwSW~kAInW*ICDkexM6(76U z_#M{iclp!x_u~5dTtn=93PF-iv6cf5G8A4^3gmn^&;y(J;#^^8z6AjU>f;3 z2g5c-5sk)w{`YRn@P+Idxd+YqL%Kra$sr91e`A!#zvUTvHZ~ex!2BrQ z<9qm%+$!&XJnmb-soo!>4ZY8MO=kW6!&m=VSLD6W?=GN#81QRe(*+ z=U9N4wpGX&JD6{;p!CPhlK@qcxSy1~e$lMsse#iis$1xsBE>ifUyBWd2U;5}h2lp! z_+-R(G0okLqgq5BY;k<&%rx}ndtJ;_Gqavvo{BVh%QC|-AtVx}D|#~$YRP4GD<%D% z3Lv-d-Z)9RSja)-h{jv#1czkP>zbW9hFwavxr7uB+Xlp;3z5Kc)=a!s72ouPoUVAW&z`7kz_IS8a(-O zXXZmiNfPTx1O0vbyxWhZXE=i3j@!6H!2%94i#gARcS*dJFTiWrh6ftM5)@ehFSq}5 zt3edSI9}6rjC=&Hz^|>EjCF7b8ES&dhp{;>z=mN0#$yGo1KTKbF~h9D$Zksm8UIP0 z&|Wkt>Bat~WkAz2h{X7;<(r6-1QszH0J-jDdu4k>35=bbkNsmi(16rDiA3I(IT@6> zG?2C?^AULh&QNi$k2Cu2@QN?7uTH1xES@4Dkxs-7tcOSpFa#TTcmb;*4eC3&!1N9? zPDM;aY0V^Vv4U=xX&kDAGeN?q7)_%+wFyQT=CX`BmYg+HmkVylQcY4dW&^-kk4PTx z1r^II8h9jjK#8+BtN7<=(U;qsGA6sWwpMNR1qzmK1poSR0(&-$fz=CUC>R4Z>fd4RMH)o+&%v`;NV_ z04ss#0s?0?&cLiCYK6$GzO@Rzf(_s5%mNUXccct=^dmc|dOnTnJ7EU2NfxZ^GHZjG zdV&=XZ665_`_j5A&uO%eqDm6+8HTTQj;&SdSM?RvTqPps7I}#rar#8l%GiwOw6cf6 zf?cI_^lfg-%|f$;gA2R0<3!!8fLfMgPi$-_BGsNIo~3nJ#!Oo74buxV%LPOFEYEJ? z&y>+5i7r>hVNE}(6Jv9*!rrPNvsQyI`?*d00X07-H#?464P*yZ3{FRdhRx?C23kPy z6O=*Q5Q@lSAwxSAC80cH*5CF;MbCT_^u=dFbDZBo`Nzp%{|l8xo~PITr>>$Bvl`4fQ(OquB<=e>#i8Ax)Zu4IjPp^;l_z)_%{+xmY?9 zr$A~;=wfaMCI)cHX(b-FhXV{yQGH{)6_O=qcQH~^%PAbMLS<6Wth30Wh1HJYTw2M= zT{~MsEHCj=%lfX_@O2sxcHmyZ3wV0a78!dU$ok5DyyA`yuuG=8OiGoF zc6oSZ@z2bag65|v&>syQXyg9_gHa6f?Q&V7`Iaw}0j!p>)QG`pZsuI~=w7v;vHc_yG^#2^gA=coK|NwYFvwo!K9NFS(pzN#bwLqPNr*<; zQ6}SUCBxC!BmR|}NUe8eNrT)MJYkk#^q@^v9%Qk`5Pzg2TVMXaOWXsvj&4VDT%1*O z8i#pZnq@dt<(*3>bxP?tb~=>vimVy6#F?xF3C(tuR)cX4_6BQ8A~FyG-t8|OnYU}P zl$cCQi5dfs2ehveMljN3BG;Cw4YEJ%Jni6}+}qV&|B=7Eqw##MJQUeQj*JW}SgMUZ zUtSc;jNjo~omnUFN>a_2Zs%>sW#y@;JDy$LWsHmr&#Z>iRP(ml8Y#*I^zobB?#SZuc|7V5KU8Sfn*b*yoozI_dU z5)3|j8ENiqNt--2T6FXm01a>zH!3=P*rB8J(I zK4xovR6;F+Nw(4Fy2Q?dH6AVp{r0#2(YwC^AE53AvA03FrO(?*0usf*eFX02(G?|= z^i(p$Q8>RdX;dg)usT2z;|iUk<0?*!tybehjPGNa%irfZ%k{)_j+tEkWn4ASWe?i? zV$f$6x3T>!(5?SIEKa9_-1^(ejCboJUJ}ro%?I1g14x6TqbU%=hC)xE+pZGLcbONQ)7|5?YG|idKtf#NwYJK=O>s*_}M#wNyA52=_Z9}pAJ?jXf;exQwI zo|$Y1fqmYLScAxcWg~PyoHPgoBR6d0dj0wB-68yYiRJ*g!lz0~5BOi$F*%8LLRc7` zw&)5HaqM*DmxWD&oHS#*5Pgm%-neo*BGs~H6ReA1&eVfjAO}wS_BGnF4apuyTDvJR zpp*1LW;FEz5sW`HyB~-T*+$4Z1QapQnbPEN6zm9C2oHL-dtdXu7rodhB+*Baw&_G} z4WVR@)o3%DQiA4cg~#!Vp>=yGcKX)2zQX&8W5;s#KnNgz;J(o zkZY!Amc_QZVq{P$D;Eoyx2WcSPYfI!4n+HWfmyrI0AxDN$_m~$?)yG%^7bd9=h%?RCecZ8z_H*rsP-t{h zP%F-=0qI&S4(0y;fB)Z^0bwL1wF-L_s3>&tAAhXzF+2>p8Y1QcA02M2rv5n=JWzpbo-oco&6&gs677@jx`qOle#;E z8y>(St7v_R8{Wh5`5eGd!dcyN$iK z>|Nas{?v!|CSQ;B-EwPv1j7n8&VJ&tzm~Xy@1tGWD$jZ-A){f?ccqkN*~4ZbI=1jx zTmhkgCpkxu?xa#2`F-j!Z3^QNt__`tmlh1%Z0`vHLmq9O>XY!|CnP1Eu1V$(!z}? zh%)6b(Df7I`iXJF>h z68nI&9&xP%uYpx$C~Fp+oyPk=`B>xASl|DXt8y?LQYlAO`wHu7M}A+CRzq~#oWN=U z!CLcFD@dY-HW$#dHRj<4|pQ(NEl_FJ}Tt0dbpj!5~721QXH`hBhH0kblnbVU(k z#&bDuwMt`B5D363;XR!CGx$_B9ms>T*u%Nl(i=~85Di*1JSzy9B{NUtqh?H;93Ydw zFL@<7f|+M*A^}w?4Cuw`C25(xd-rmp?)Ye<8zupMH zm(rDDQOydNeRp}I1D*LAf81lYWz6|pA+5sR?sY6^Fyt~z;lro{uavHRDJ-Jc%2Uygf{Vz{(xOa?57lpWJ@PvLOn1}b?7 zXF9S@_2*wlfAanVWBpqjYi}6$S^oV|KF22+w#N4+=n%zQ9*(_VjC)8gg_}FY`o@VK z?#{$3vNsDIt)keOIObI}4*IhYLjHcZFN=ey0XYqy4EK?I6Mk`UdXrQK=A5|P4a*A^ z&KrTqx%Q2h?Gb!cg46*wgwl>g1orWuyu9GdIu?3M?adC<@t|iX)MJt}J=*Ja&hHJ+ zU!sc&5A<@xTy#T(@lF>R(0Y5lJHtNMyymhXjzZ<`DUXqhdmQf(`QJNil}fF zxsWB&M&#q~i<%Tni5QC$HyV%t570@k3VSWA))ZAm2pmpb>H3lXsTZ}%@Ul`ZwZK3k zChb!rY|@Y4g<|=kNwLgFC1u<8g+x;>qqdNKF?v-P+F^^jNhuRTrZWj-uQ_q-J@5!| z@a+|klDuN~BXE<{tFvi#mC#=XJtqAVjT>USYV_L#KA;q8I|N+nYR7%xBuH!Tu=Yr$ zaL>e!$fZh{ilhw^U&%%h?+;F?t&Zq>P@n>VY;Fhqn{ZzF=8-xv>89&VZX_ky5rzVT zB|}~dk_Qw20K-t6%lHOOrK+12lS7)|Rw1hD3Ty{9 z!Unrscl0%ss2OV|#AK-u^#g@OThx3iJZ)QNygZQ7)JgrQLaHEfvvu*hD!-?7v!$Y? zDh;OPf23Tc(+89+l7TyD=HQg_(}bOfdu8?_@OP~P3tI|_=~5?^{DK*jT@=uZy;VI} zC0+IPvH7TaXI-)ApC#ayE#|hxF|G}7r1q>F?DJRHNL0S$ky|o|O~fw|-)5?o!PE*M z*NIYG6k9{eGKS1C0;v1IC*-xcvwz&zN6**y`hY5Ah*uQxHl|MU*fbdl!K|z!Yf#Y% zHw1yjLu^ViQ)w&|*>|Am64+yvcoYN&pIS1uZ=qwgLDJY?rLLh*KCR3&LPWxScEh|P|V%{C5VrRjY@V*!C-ng^yK7!^gE zn9V*cm`KFd-mo1SBB?uLSr>6Zq~E{|MgY4)=Ze-v#*#i{hZh6+t`Y$E%x zkTNS5sUD!C!4!%@!wi}Tr1Acy%Q$kJKgXEl3sExw^qyrWFx~8|iQ7|lZcCRj_mqK8 zYn7dqD8kls3I1`hH>@(t7CL8^_8EGkIZF~mB~cp7vt-aQ&ekOzjtX}IYoIoDI%o8gRGZ{ZVT%Y9BP3gO z=;@(*jv27C1-4-4LoJ4jIlmnf^G0Q(Des}b*XOy|zYn#1|6y8WVvmOcNEjC3Ky|sL7O)6YP6;NL5d8T2`iJcCKM+HDCC8 zDZ~}6kbNH-NYtN%ngY!HLAOKbF%)iXJegGiqjGT4)QZ2udO{}{Dn<@2;KG)!i0!P> z=G`22ciYLwM`=%E3M+pf7{&o1bd+GN41%}Sy);Bdr%-q<_p?B6eUBREicPxK1ATI4 zi5ya9PX#;^RmdYn%~y91gGCkIk^ipJPKnO&{>S=k?R$9S{FwR%iube&sZ+43cbh42 ziv%ncE<^lirQ6MLWsGASXGSvoZq>oWL8!vuVUj957n(Y>d-NaLh+{?J&?HkFOc~%f z+}K%gpa$jxDiN~EoxbZZ!-nzi&sza(G;6ilPjlj!Q>?`B3_HN zV1|%C^M=3u|Lz)bsTTwq4P6v`f*%r3{w&DC@Wm?Yz?$g{9$_8J@sT^G1RhxOlVYqm z%O~Bgrj$i=sOI6o0zpa&k(9`r6@9}Q%Vq-P)#cpjhj}cI zR3^%PKtgugLH3mnXNy-(zbw!P&6x)JK1W3}W$36UL?C&|z+;8^2f;HSuTM@k)l(t?l>d5@HwtBbQO zYyjk4A%w&8I7Q4OU(Pfim^jvWh(2ijcd&0Bc`cAz@AuH+7{1dGVM}XInJw8I7(=mv z_>GC6uGdkg^olE25$$Vk1Z9?ZX0-Nz+8Pp#g_j82CKP86gbg2{zSGo~w82ZClQxDS z51z#GvcvzvoKoT06eJRYK(cq!tu6yVGgN32LdcPzdYX4W%z@*!&U%Rd={u=gHh{z)Uq@Y2N_wuAnWjGZ5M_ivew*um z$Mr9`%0`e+vSKFC11n^kEEw{&ney$Y-+jz%3v1tiuRV27U;-AEbEHY=59xB4XZEh} z@J#d0iRMF1Vs}SB&Qh1`L%)hEQ(kmOx2_wZsHk@n#M80nBM(z$sq?$3OLlC(##Lhr zY+8*_J~(K^`ykdorHpcs=emE&^BN6QT8&da-|=bOi8^$dPli}N->#eE4a6lwXv?*H|b#w_ooksHjBXuvmQDiMV&3g zZ(&BX$3zJ_4i1CahbE4DXbML&oFveeoWScyF_CzP?}nyu(&maWSYZMg8>bxA7E`Jo zec$1l2y!B-&^Oq_^M zvNmWqES|?JHP76yiOuNtA1<&o@FbWr+0fVM1}Y6w^(uB!DU7est#eF+=J8i86aWMB4tWsbjWpavbyAi?_N-ANtMG3qq0Kj1B5u)A!`Worm)PO!$pUs^~3k#QT1_wude%1fw6 z04N##LW>Z>S;gXB1OSnRx0o7;eA&stb59>@OzS&3lV0L^2FMK6lI*Nm3To`=DRXiM zA`$dpGV}S2i#i|2hH-;4GpWjLH10t6FC3-67qhv?3TnY%^{th$R|tT*{gLkNo_Wu8R2u_l(pX&RL=|6Iv-@nukWtzeOh zGj{)4?j>!`_rJ#P`uB>zQonyL_wvWezOH89c=o{OKVb2a9{BE8X)88b%ik$-yK&~O z$Cd8p!1Zr@-35F8RM)5a{!PE__2)I~%kOS>pU(_dDxJTik zo^UUI(EZ?wY|VDTn4e$liL~emQXzqI>~Vs`*yEhcvB#zR`TYE@Xs}gT>L|;?oTQPD z8?OUB4Lg%WHiZZVBaR7PMZSBd#4%ybhLK%n&qWrlH_JxQ<0z_IDACiLQIGPctLR)^ z7vlP|xIPxwvvEBa*TuM=kLwaw>|acZBU=9D+=~{}-!i}T>~YDDWDCr*`ui2$Uoe}( za|m+T!O$%A_p7{zae~1_MRqEz1FNDVWiL=xJO?BdQkb)vsU?x;k`U=(6}zS*ek{x2 zK`6rw7;=L7KoT|{d-#~qnFSs^af(4jNz7UfYe`tOKw*`7WH4>XRSlr4rl#vHftCXb zLlinQ18u}02*kOSpmb#2aWT8~r)nigKN)PvqEpDudGN~+1xKYP-_|wYp4ZBsOVhyNax+K5k8K?CwtIC-6LInYX(*{ie{yTI8#z zsuoJ`2h9NvGIh~ADZd=Y>32lFhoG|wJR!;CY`>5f#GvK45X{yFnCCq=TjUEs3ulG$UH zv#|z?YwLU142WSr6h>|ZXz``3`k^1wJajg5Aztb8V(jl@F202OKj%+#k@tTY_c?cO zkNdeV^0|Bc*!|bWea`KpQNN5>kXv8uZUh?3AOYbIPZDx30nfX!a%5P;Td}!_hNf%n zFcYsjd93kj`ur{YiNPS7xg;l>JJ?ZYq~l9&$kSSFJ^Oy$oab}5{QpRQ*6D}rTIEN> z*+X}BU36DcJDWkd4F5I^v|+OHyI$bet?!jcKIgkN5ZdT1+gwVC(}z$ zg?Lh~jc8(Axh0c`NQYteXTni3cs74|6CprzB3S^KEXs)4%!t({5&U3tL;SJ*n|D2= z33fk%4uP+vUC~6~)19H(T}7t&WLI~uoVYR^?harHZ z>|hcCX0nSEu}==RuBS9qbqv>Z(oQK%>5&ch*J$?=zZSp>H*&G;<}_TT$944Bm&A>R zu4++Ma=rTRjK5rewsrbgiOYP0--pFzcG;p}fF(eD!iC?GV~y7TIPEHqZ6$B7GvChvdyE z=g}2Y^+G^)2eqGY9p^8dmt>t5&LKyvz2nL0?)BP(#a^+{RESr?OSu%@pVC`5^DQwR z4Rt{w2+_(N3Us=K43bP{+(l$NSH!LxHR1Md6n2Z94boXUHUqdFnJJkz*-XU38(ynw zbm~;%Y6?(Zhb07x>F0#a413wvQaliZW0f6HOuJMoNDf1>@LsU*Ww>j`c^>4#O|j%Q zrSDoVBq*P5dY2|9%<91n!cQ~M*S zui~S`+9x$h!fsWDyYY!)T8Z7k!6gSI6CcqU6MxGYJ8UkP2+j?<<=wU{n}%d$W8QU} zH&zZCh8S}WO$harTxYq~=Z>ZU1rfZ@x%WcPVyGBS)0-Ofy+lyp`lctn_m+kF7 zCm~T|suX)bdm*FVNv-SfpW+VbUA6C}ORJwc*2)}~c)Ww#HuH<<0QA)j;u@f>oi$#f z?7nz!D6`waWVyW$-GLn-m7N9+?C1wIDU(T*9lcw2VVmdxN{-&Gm~#p1tBDPiP0_8C^~V3xj_RvAJvQDnVFUrRI5(<%pW zbC%vHCdTxMu>DTRsV`QklJknjqCtcNqC2TyZ%f~@&)&jqW6Lr_Bc@?f%~lQl9EQpg zeUWWbzT81YK23a7L#i>_QG|4}P8~$hj+9z~bY}~8P2~DCv6O>o4C0o!>XHL)x1mqbNd2v6eZ-237aa)V;Ui<*wJO(CA}d6Bg_ z1ZG>N;o|&0*vrkMlPr~%c2Sdi2m=Vz)R;&<9Rhs1e-d={QrFY;% z8q@YObmK=H4MGVh3Ha3Q033)86}Z@rGFPgGzVM%W;BC^V*;MP`HJvle#AOD(h5r=} zf8|3gX%%`{#wIxjW1RgG-kux)W@Z znP8jm3SXH;xcqdU89fkSdD#Bpa9>5`e*j`F2r-Mf>I+qNB^b8?qN(LjdIZE8qeCCj z_lo!W(PfvtWT`pRZ*X|Ireq=XALT)u2l?Iue@4&Zp^iTPdbzueNV1bO@nb==J`Z`% z3~ev)SEq45JKn!OXz0~=|9HDEE2J5R0yAbaS(k5E7I@%(MYc;;MAZ}YKa3^Qw6nsQ zArm`r3Mj`hGH8enGin02JNY=(*jhQ(_;UIZUlPkA+ozcX z0i47AwV)`@Eb>C8?3=^+$}x3kp>uJ$o3$_YWW9s7!6J>-0Am5I!(ixK8A&jsGnLHh zpVBVPH*gGyAg2t*DO{aX#>*#>5XOO-y3w{hX9t_wGxOEH#Atk~dA2S}2#zVw8(*1l z2+)4BmPE4XG#a)CR~;WDRTt)B)}}I8(^ifhZyZ+8D|G65ztG}3-;EIBVi*BxP`TG- z8(R$1XJ*dKE}vREH9vdm?84%FOGKf3)|?+2AucNqhN^W5D`Ws_J%^4X;GT6OT_UV! z<^>DMg}`4qw!2716-nMrJ~^yhjuNAUM^><9SPY|2W6|X6XDgelSW*qhR92jak`HWc z`Lz3zH*$Y;SmXNsc}c)r?l0M^>wVszjQe1c5oYWRKv;AM0lTTOj*4ZkRgM3QS3T%& zOuLNlf4k_ikFP|wAbUyutI6vQ*n?&HuZr?Hp3mnygL9XknB^jTk*CiS$Q^LqfRq$! zGz(eKHx{&Us9e*=PwRW-0@HcI0jJQ-z2*y0;!Upa<00OC0Y?f4p1VYtC>7HcxqVM+p%lrkJ#I6WrB(oV;Z8?si}v<7C#;= zNJ52s$Eonm4QfJe6>`&ID@I^>&3M&i`LV?QaX+7r;a-w~_COIIWV2OXw`R0@nx3+> zGJjTWS0rzcyjb!k+`;ho=F5}S7ak|dTOYx%^v1!ZowI|-Exl8u0AwpxkGfP<<;^)V zj`%SF=;b5Fj_1)WS=@$*x)ADK1B5)^e!0F*Q5y!}C=}?b3*C{SmT{wEM-=kP zhvJ$@7sHrXdUPqRP(8?iIlp=An;b4qs&-Htbeq3?JFGg{x2~_wmMh8RR_`)0=jQy> zzHAqIoDZt>l|XDZBipcY7%LxuI#Lnwonr~aUISqv=8o@ zN;}Y;pu;AIIi5X;FWEJga-M#UAx5eZL%DYYsiFd2#I^#C6^K6^Xbm+I&ks9qKwB-i zL`o;Wo>b>*>8ZJG$vRR%0wO(R0tU>0QTw@->5DAJC3zQIwXgLEzU32v2|DwD6QGHk z^bB5@nac6`!OhOHcJ|_b5sC$ER)7UJ@ z232vr5PiDozyKAAOW764=(m;_+d`+Mm19bRIXR>Pvgj(AigxyD)uQ0U9 zX=>d(3u8ZLIg{J?l2zhZ!Wr!tGFxC$WsEbS=7eXd26|6-t>Uf@eue3kLZjJ|jJc!{ zvo06Fh^h8;AaoCclut6eSplD*+}0JLhA1nm?BrS%@TnH}8{m=2f#DI4ubcx)U(ISG zR0bN^2-*d(tud^?g>f(~;a_jNMe1kUO;7`xHpx2ydRZB$!`&Olr&{cLl(yY9(CE&v zByq=gL$M$9kwuHy9aL)0QJyCS>>}MA%SOzW6=HD} zPcY<(05>nf&C7+l7!zGgFF8AsObKE7^}+0p#b1e9%lD2G$}taouALqJ(4T_Y$Bh&xe}cA89!L?_TjwL5kb3bytqVScu=MfQm3 zG2}Jr8>v_T2#J)*-RjwdGc7Q5;On;G_ifSsWv-oeGGu$H>xr$!KCbV-7Kb}Lf+`DI zq%R~-Dvh%c0*}oXaIzXc&O*pvqNli@%MBCvQdKJK*RsK`VM9Ub=FX(CWgcZ6>dWGGwAX1YRJcXw`X|qE zTM>gbi%;4Vs93L=4ony65u3tvU>H_0iy(bRNiI(Urt3hNyE7U}-R^&(9r=FDdL9Au zB0Cvg!V;DBJGZpFDl3Cp%6DT#AgI@O(feTE=Me2V( z^?wTY4|4rW=1zE@2t6egYsfEfk_+L*A?||+>HMqSmSq^WoCj_OE(B(ZS@Vd^NH;Ri z0xP$7+Z#xeYz2=>8j>BIgoiK>#K~4|zq=xicvNdAC6{U=Q zC8k+B5W3jtYzML||2H|fWcS3bzB+|y5y+KDDioVjr;ti)5h6p5EgiGI#OQ2VK zWIB9%e(m1ym0Rrfc0*>2e5FesUg-W!wwug?y7p-PhWE>Ea=%7_^l{9`>C*_8)89XX zX9AFUa&O;NuYfImuiG8J0$QPd|HWhXPmbMx3HNQfIqE&P4Xg0b!{8sB=-`GXjz4Rc zILoviX171G>3)izgDr@xdeq+sxXMoFmHgIK|73@)fA#Um)~kO1sk2P-4e(dToLq@mh^=wB+wR0l&pY0K^e_F|u*eHKN zUp|(;Jm;$Wd;cx2>)d}gf495H$XRdcqbcr%K(R`RYDnwNv?&{|CV!vApZ>k{+rG}0 z{kvatO6U@Rc%$9_&dcwx`yc$&AG7;+?|i9Uue^T!(^Tx|{>k66_iz8U-;xPnBj4xq zu%3H5Il2yRgU!wjeE;TVmuBY{R$pL_o>vE_5UoJ z^m7jFZ@q($H1DZ>BcF}K$B3*uJo*`7XE5}eZ0qO27qVH)`*XA{+@1Gd8~0Cd?lhd7 zPbRQd&)YaV5AUBG!wCF-Wk{I!9SB^PgMcX$MoM3H=%{>)5B5cMC_t7~LEsRpqkPwk z@5-#3ZRCtdW|Mx5r#Z{9zm@Ma7f;dNVO=h5fB!A}T#Y+Boo&A(zRUaHxM^Pyx^E!& zfug>;CU{=c4*SwCku;@wmN_}!U)Jp6ZqCgFFY(@f1Pep9p*wNs#GN?g8~b$pqta`> z__Ep>zmz^6zQ&NN)%w(zw#?I?180YSE2tQSb;Ti8*}oFxQOm>k;a$(e_Y(G&Y$Wsk zFKK_ecCTCz^1VH>ljeYt>Fyr>OKTF7LHyYD$l7ww&rUVhh@l#Uv)H{yJPkj#cVS~Z zc8H4^#LtDDswormsX`tA?$pP6IPp*QPUlFvcfcJe#iJ zABuZ1D4f7Pb8AXCNVo4G9iJRH@7T}HTVt;SocbPPv>75R9{r!D@o4;5D zyxhlkYIn20?=Gj}Oo#lI!>RwaNWA&mIQBKPma=f%+W`l{7vw!N3;|BW0)LIp25zDo zpXN)i^uTmIW7mAQytdlV@YMk0sH)yjOi<(06%(}90GhG>a2*TXqiU(xXx18GM=zz8 z)p2>dzYS+4eY;d2`zBQ~`vN3oJI(uEb^kriZ@p*F?YVab#~N+c`*HA+Q{~+7kId%y z<03LF!Jrl52#X}6cMu3clPioU+gQKEo=g4bAr<)k)314)xvc+HQGecl)mVGhDF4g% zUmNeAf%|RahiOwpXW{8>^~d~gLy(!SU&4uq%}GRIVP#(}8TlGHeO>!l1#cRE;pK6Z zlU(2ahZ3r{H#ClhU9Y4hW-+t3V;1`MzrCIH%?|$s<8Q|93N!EbM+GQRZ4FGKz1#*z z-C)WE1|_BN!L~sZ0E^<%$7rKZ1^?u8M=-Xn0w*|{sXuXKGxDUP1S};y@BWn`eaIzJzBslVaR|%ykmLgsT3ZxPRG^K=e*J>qmOtzv%aSjE%ZNKxzOYo5J-Oy4S5 zXLyvGb^5}8p$;h?j?tRd=`>yl`+WZyxpk_R^8}*d(%SDXKI%NmCI(A zbSdqcgg4TkJgsJ#pUs_vts-4JJktx)yVSc@&Dt5l`J2UtCNER8XbtF;TD8mkRkIwaYH)i)_e-W4Hu4{j+P9}tlNANM>9p1$L@e+cb&dhm(+xytD`~Nid{l|@cKQ(qgKX$KpA*w&;`fdEyefBTyuXDVAG1i`B^7a0T zN3ZwyqsQKV+SvU@+-H0DMg2MdKQwm#&2j%1*WJfbd{@1F$;@@1@2|vt_Fpl<^gi1= z5%qnT^=R|_XZWjs|C%VD{dsGY&-H!bSbMLF`xUdF45gfoy30ucg|+vh;bt#}LYE{( zFt$;CNqOe&f7k+}-&62K*>iXbFW7^$n?xq|l^zSU(CP6i$t@Qv;AXjDvbe?GV+b#b z?L&t<-VH>R(S=SNguVVkM$=uA+b(mG^S8zL`Op2(DqC8!hKf@bcV~>;Ja#iO3mJW) zT$GwB`i8c=FD0@+G$osdmzKR+Z<}DW;dd)TQq<6nA;lJvV}S~-uBtK9b8sv&#bzs` zmds>`gxy6G3vc2|`gjASQyEv(W11IbdKe_-RIih-Y6k@}wPW#PpJz${GwX(pEA|hg z9aMN;Uk3Y3)?{t~!K@(akcm^Rr(sKg<$yHT?Jay}lrsvgeS~$#xyLLuFw=o5#f*vx zK^slK6yyIgP_$DUH+7UYh<&U%#O(k?JblrFZ zRXHWwcNG6e7i!?@>uYfaEZBf)ztwIooNp&N$MElcl>cn5i31)-cK-#n`~RJLy}zmb zdN4sHC0}>yUQLEMgqRjuN)S)Q=;Q!?L=Td;U8z4d-*8D&$;x$dZ;xXY2JI!Js}b)bMpYQ=!d8m zV^R^GT+D^M+lR9Byfbq2oJ+fd@ERSz$3H(li%QJp2(YYsq;flwa7!+tqQLk4Q`%lK zu>$R_q)?*#h@##lO85^PW0$1hc3pIif47bU-Hg#i7_v66TU7V)ISLbB_F+uFS$SdP zqP^&!As^b6S#YFa2;&$LcxG1R7Bgm72wWPv^c^#Xem8OwffWQJkX&KYC%B-P5=LpVD9tLPT^GNLVXKBxp0_Waa-_KE|{itnB4HR^tlIfqkc(=?I#cT~>#e^1`(Yxc|1a_=_Ew4Mn4+R&Pdm4^CSLx^~)mL+a*_KT7 zusX5%5%e+>?lu#Nq~s(ddnL2*B43AqqfgfGDHo$4KZJr&t<}(MOUQ|6c)bfbQ!v|f zfC~r{$0n#|%?e(D%HTVdQUkBnY6R9SDIL~sUN$zfZ$nI{N!!3dbe8L>EON`9)Y>nn z=wJ%^-VfA6nyv;_MiFRPnJV2LlMyf+FuOWafN=p5=W6|o{&&xDx?G`yRrH8 ze?9S#ew%hL(SDrYCpSBG>=Q7fcR|ws_@AL#XlmPs4Y_^u?2EwegSpxl-&+e z&O>tQH{mN;7O!t`!L<~MeqoqpJl0Ocyb+D+Tg4sh!zQ}|22){zHe|yyn2I~Z%-pTn zCyYCJ(jVb>oySd?L-M$PCwR^*|7%e`?|)+K{+Hu^eHgvP{%)_^Iny4@TG)#@3I8Sb z8t$VJLj#5}S>a4|eueElnRnyYMV*w(j$`5cq^hg}3yHhk8!TgYM*P%X@8l+AnlWaq z*;D37O+NjH=(F*iizUCLsbI+9XgW|RWJkM|>zC(3wQ-1%G^9NKR-3(pcXfZ$!n^9Q zH{9iQ6a2ttL0qgXyvFM&)JZ*$s@(k3%OmjQVY%KEF+is&hmp6D}+u4H` zgpi*LG?vh$5`{q}wF1;)s@SCAqBQn=bEh>m_DHt2%AD3GcFGawcpYmAYA3|~wNq0t z63|p5?SKd;Br3W^MD)R2wPQ`NK-q+otj=>gV8o)?4$V@6`kR2JX4~BM;w0BnF;x&y zNy4r9~ zb~lKW>R8ZANA6d@nUj%5e#wbK`1QP-mxP{ue?c;qIc!Lv?8u`)2+zI!h(a84ETuDI z3(AiGWx{j6)$@H#aQ%32+=1`$8vdVS&*FI!st*Wh3c9)rm{-(ML05 zVJ5(R&!K2D%%{1O*GSehEV28*?!5fE04MykL?8W zhPm49?ov2?uYr|T49Ez$ICB-oF7BD4*5jn=VS3K*wh_2LB=iY#^t(m4Iy_QL>G25N zeP&H_kh#a-Lg%4Xa_rHVmc2$rg?pg&dIJ6u{#Fz!!rW)R*O#TS}O3xkG8%A?0H z(!EGFCcEAYjA9acjv4*~3+X6=g`8@PXxQ^DiODR{dZOt?Ax z$cf+agR}%}-@{wXq-RUfw}%vAh6(OGQdS?Yu`XjI@ZQ#=y?`Q1nRSFYrKZ5jMDCP#e^}cm;jI#LbEnhDwPdocsQ5};%&*MXq7tMDEQ#f zO#cp^&sX2-`PuV)en0D}^LeZyWHfMmkS21*XpuGhg~^Y%#_T44)HE0iR<9O~^*ZT{L%k#5y zXJ${Hod@!ekU=7ECE6+a2 zX1?A>-Pikg0$D=+z3%JpJKT%T%ldSGx^~~?eq!ui@q4m-Z|r;B*Wd5{KfJvQoMv}j z-#@n03u;U@2vI;D6Cty4_DOaFA(@0Rv$GqrknAkGlZz(lJhL;;?hcuq8RnAgB0{Pl zpk_v!GeMW3rZ1cr2Z>Z6jc6-A{wnq-=FX0cYf!YXLhp*|Np)q zzd7eQ=XZXW@BQ{0cwg5yR`2ValV?@eieIR&FCMtQWZ?QJ?|x(TzOL)_5uLlR`u+R( zTQE>$HnXv=nOT*?+z|j2gTIM;*2?4Wl#B59-sJIeIcMeVeRI|4mvcQ)UH>hA>pHT< zO}91UlFX{ECpiI%Iv^+KPJM}TQO}Gs?%sj;fHtc?e!<9+#>oHA&e*IF(*=TRu= zApVOe;NtGdU^1=F!gooM6xI3tHMcH+d$9cDnIN8HQ+$kao%8x92Cg6Ax}M8B2d=+^ zYr#Ukzrx?5iTkUHe}@!v!FfUE4@Oog1p?a-Sx7VnI!yHtzWJkRdMwsEtX{Q4)OFY> zC4C5n%F)`U_2TYym6vg(&G4oC4VaE}8he}9$+5^SP^M3zlrFDKLG5if2>VX zCfT?bV{i&?E*co@z~Dj%w2?_dMO$cfgK=VusdY+=G}Mq&4-#KPG0q|iZ}x*VPihgu zSP^E5G*Ez?x#z(UB+n?k;xo_`a?f? z!N@+~Aq7Z3%8IkiFj!>gQP?vkhyXd&75qOq~AaRFL00z1)*@^M? z-t4vay-cF^0wLV#iB{r{yCB$a;2F{Qx6;Bcnw*CsLX=?qn11=8gh0pGFdN8{l50y~uASHJ1;EFZ*zAjj!^gYNo zVRT{!c|X;Fps>8*m7>6W1;xx-KfQ=fqP;%V#r%eLobCg4+T9SXd)P&HIU3GKiLn#X*$H77 zL$OsMB7oMq+FXTV=mMi=I`=hDY1#})IBQlPBXgJvH?;kN19cX=V}Ba=7mm*t~Z zw9B5&m9qp+ud+)DondpWg6uKb=A}MsDh1sN9zsu*PC_hz#?ZNOTOHFj-YA!W9I^M)FnwgA+mH-dGK;7C{am=-IcRb`!<&xOuM4Qi6Q z^d;?yVi_5ys$#kco4NSF^=%PYAd1KwJKSCxS9Peu@x|k+Iy7IgMXl(1_f{K#aJcw} z8h89r0fOGFoBhrin z{0coRn^8XNv}^sARokW|#W#ed3Bim-RCq+JCrU5&3Wr~d8*&Xg;Fib3=~Yp1^P8u5 zEbs+_h+>lUa>df<#^7WP1XpE?Mt$On?XtTClRTMs;ccT9?ccMhP`CgOeTx zCi~Tj^xCUFKfW9G=#vD+ptacNb4J#=9?4qy0f({-5-kh2P|l!lxiDjjQIbqTe~g22-Ilq~XxcFLmi{Xf%#XvB}e` zv8A?&3AVnj;JW6OJVD=KkpUuA3bar=(~7j0go_3{VzV9hB1Nn#jCEuYwc~&6(XIV? z1p^;P?sJh*gj+>j*27LKFd)#jHhW~WI$RxP= zX8y0b2eC@Bi`L-MJ{}dla*aPWs8~lPEMgcp~q! zrpm$BKdtRY_x=m=u}(si{sJkHNM>kc?HtHAG4=ydJ@UZGX-f~D+t@4C z@7$c{7uRPUW<>vmgoN@SUn3L)0+GTCYgcTxkx*JSpG*8Am|!}gX)9#NvR2r`Su zPA7@nyqZeqSMQvdT)!J~!2ld^062e+GU!1*LcHV{p4+ExrV`|uQC!h`vhAb1nUU+o zjV=|ieJs?jmR2Ll=`eVwAMzXgB*4u}p`ptQa%VbIL;h2+4=+m^sy}Okvl^73On2nG zx49krjc@f#{yVw;2G($s_EuW_{S;Pr`qmPAF+m_8hMw)dAQ@;lLW_lf1q87-&nfHU zxGV2a&L8ArTtntn_iQ2_^w>jh-RyA`rod__6*2nC1>wW2So;G$^k(f+*JtjZWsZlL zTxptQV+fvEUq7~qzdb7Wioa;#RDS<5Aont&6joUY z0}BnpS53v=%YrrCES+XRv3`7 z25cAO*6h}i1=pw+X6IX(+02yr3PJpFkrMFSLbgd;s!kU$6eE5S{If_LmcV+hx&UHf z<*c$cqZy73PdcS7vkw-@)+=nUAO_3y+#{+jj?9*L6+ZcZ6psiM{oyH-su)>1B2ycI zNb>1T=s31rG;$*w0Jpy*sABRM=`6E;V01%?rK(s;US*}!*TUKyCqlS--^*EOy#glr zDX5T^1VXZ}rfXzh5!O)jbAO-AIb|dv@Pt?j%=d2JGkVBOpJN?bmr6#vT^(P@W+Iy` zP-;{HDcBn_3-`-~=mnkZRwqMWws-9m0rgkj(-Kq>k&J&56l@|S3y;t?XeWINxvz*# zHbEAvXY-G_H6CE*CVJPHGOpYc`i(vv3+ntRx@LI1lxq)(sfD17jjx81S%pBTjSyf- zD2+iGgz9qx(B_|YNHj?=#}k^6i~PC})h|08_T>lxZc7 zHp_!PBDx^L1t+PPuPDYjYz8=P@kpi*HOrzMal0mmhvpg?sGWIR2z?|F*G)X8l66N8 zz03LKmwFvvN57I$zewAm9bCuZGzlrqOf@o4xXDV8CVc2Qq4GHNo>2@d&1hWFv|oP! z0u}Vf8Exye;Bs2Nax|;+Hw&W@si}b72!ZrORe7Q?630RT*R2j6s$~e+=_202 zg+yi@_OU{gB-{ySsM!WLSm$K3v%&N0f5qYXbF|`HH~bfm>&yN6Qo;2>`h5ZYZwC)w zs&SkRE^-`4ES_zB?pWXCx0Dk{wLf`b(t(z=!HmqwHP(dUuE(qFy?j%_%oSEbG_mz7 zpV|1^-OJ%fo+y zFjn*wKQByk&wg8S48Cd$0!71V2FH41qwS8ol{rd||MFk;I^7A!xdu<<{xrY$X)mMA zVeVZyb=|G5jSZ-S6WU7WXImedG{J46&5Sm$+_Pn4LsPtc{$zY*q7l(=GfGpj>JX<} zpW{uL;wE&nrLNkYGITw5-3+X~bL8~8+l?m1$ET2@CMIgq;@`YUWTXPWW_U9Iwy&wq zIA~y5@^MwObd11IoOIGaAY=2Y;UJulxkZLE_J_1SQB!n3`49kD6kFE)pS>s)tZ}T;@6EJ${}6hC=8#+(J9DEdSw|ta>s|eOkoR}fYQ0)Q4?_pJ7>6^$ zuY8~LDLoh4i#H~yxvNdVI7?LBg1&JD?@7+kdkL%cDiM0Guyj5ZHX_B16OQLPzbE*Z zyts*y%fA!!C;e6ZmE$>7rq65y{(NgVmVMnFc?a)Z9`AWrX&FuHag!ECE$}blfx$JN zAKcYgR^$M6bs}LbF&$6=@ppDV$M+8Lz3YG7{nXXErMQmzBDU(*Tk<00dK)>x^OyQK zS$jdN2}vHdH~ zAEDL$ehJ5y-!}-R0;;rF+eEjv3wyZ4Ga<^}yB1JocglgSae!m#glrl+Awu3W?FsY& zLxSZvIxppA;X{waX<4eqI<~Y2*rBv~?(B6(p7H_LfmUfX?_Z~_b)?)E>|8bTcA=oX z&S@|z@YYaShgFeJK}m%#V**o!xCl6&@EcygB-i{duBBh?&u|!r*)ssPdje%$qk@C1 zYd-ge%6iZPE1f8gs~8Ff-# znUBi=tX2b5h_SGD)n|+0B8SvSs>IVS7}!{7zktUF6E^Uj<_26)v>&7oDrtN~`AF>Sz;dI^ zEU>e$VIQSue~MOmaqjQ4|Eu$ZSJLYK$7uzFSA5X*=JFiZf`iFOekfeZWyTXa(Yg@O zfXo*26U&G>c2?Y61fpTN#r3iVh7kdpWUchg;wq3{2jd9v;Rz(e2zv90u~_^A`vknN zXN(&ApV8JfgeQN*@C{7pO$T4^OXMYT(} z8!K>?7N@}10w!$&GMfItu(ZVrvk835#W8%IVeVR!pQaVf|03;^X>(t{@i#9RQH*KL zn_HBdJwUP?y5@XSn`ht2wO^$_opX@=zdEjs@HI0mlXLJ%mw7DY91j*gV(1kXF4yXd zL_BBfF0gSN6pVSOLG!+)M-04&B(@p+riUy7dzWfJ<7txt4UB(c__;R0}_;- zNqQk>WPU@m(LXb$&mtreAt2-knIAgvgb%xXxI`;i_noxYRO|T#u9asn!^lfiY9U^T zpcStu`{gvvL^P&RL;?!4n#qeZUMVF3JSxhnb`F3a%6BuGZh~SSL)Jp6ny;ITw(#HF zrttH$S5#yFUt9}+m6DZ;QKM5eoK2Cj3xTh+ockrU}LQ}B&BM((_;^N|Ziq`)M; z9^_g%4U#OJcc)ylef12yBrN5R+f;qrS!`XrySlGNetQf6_CT`sGtgB>p zz&dd_W?eKAdvek?5i`U1xERSg=YdT7NDj@RdI_!BXFK|9OGve^*xG3eiEfT(+O@ks zKY!JpYpz*1dQE@+>OEIp?k5}QDDYi-x>s~}+Y456)&g0kKkDnKx*)P6WH_cYk2^N6 zzP7XHio1yNxo-37iTr87?q9j*E)T`?kOEvl9DlUFIKNIMJLy}CYs?J2xKPc#2ShT1~%OV7k10Sl|yO;^b!^_-Bjjr=Xga# zFiAz8T8|R*OjhNp;B(XKdVbVKz;c^Op?9lC&-62Uw71hj`0xaCB7x1Q?o0gD12FB| zMaZ?7O!%G~7wW~#O@tU7{@4X0dx53b(N5BSjCP9lqW^xu$k)(*3$3n?)9$DJ*=YZQ zRxvk+s3d2i%uA<`3^|d^7u?2c0%T&lX2#U$?aTuHmurcGaiFr?|#h!5#~vC~*d*^Y&15B=2y` z>ch1r=K?6AxHELD4LSJJ1Y(gJ^gE8LucehP@M&7fGS7L)ed=dhcOZJ!AbQpSe`b7~ z8Uxb;amzBQchjGcO?7{TW%k&0yhoxjm^m@w!#@ZNPg#K7z9^rwvX**A-6>?=3Woq& zu0%=IO#57=y#*+lop0oK9Y!Wq?sE_yg_X+KHGqVmSbDp3l4{J=N5g_Db~$p0es7|k z9C+GR<}vj9mgpDTBImP4S_NmcBI95wV_ZZ$E|G{0d7ZSFy#xA_uWDroz~F##4=3R! z$HE-8SXUu~!5|@$ESdepq>p3U>&g=0SrJ}HMuA~#_LEszbriHCglF)H;d(U;Zi53Q z8XeU~2;!X_C!7vR8V3(V-O5QwQ&*K$r+r#q4$Q%l+l(Aa+K15Dr097AInV5hcrBE* z(w%locIK)cF}`M~s_)_lvfz#US@#T9Q)km;o4-}q))rAN75gLnDfV~s9Pcnmh%OY9 z0Kx9ab3g8K{~Kt9JAX;rp-uT=$Nz8~%j-q11u*i9`8HNl)^{|nT|;Nsn_M7K!l&KS zIQ{(?=+MrZ1+16O=|W?|XtsErT@zgqS&{(*{f6;=OEsUr;`*u8^##A@^FB^{KKG%u zqD@u>Q8GPdOD(i7nh#?5&cQvPvaM}1IhGN5qIl2Yn6wV;(K?Vk08lFtKSfMLsVAyU zrdbbH$QHzLjvU7fIBe!g)*Xiv^mXn%Q_Bh`vCWaL0HBZqsnUcd7rWN1&f9ZD z^;Z&2Fl77iA~pLp2c{im0(>a!ITQBcFUE7cf3s9m9&A;vg#1;;D^^6{s?Job2+rk! zlPz6vw{0o{xq0@%8KPPcayLCmjmlXTXm^U#dJa-yvi95h9XaQ_JcE`~>FqdOi+4lE zQzGvUU zEi~7-<;chbyeqwOMvF9vus~HiG7|mT&O?E_t5h3w_aWYYcD$e8&q=W_?H(X!@!64! zKI!@M`mX!e^t31y{u&A3@Jzidkttkqd^Wy1^tQQdu?P&}0e*iXzw7&D+&rPRigC9vNcS6@f01y<9E=~PpXWqBcGu<*z2Nbz z`zE?`sbP%1*zv6m+_9{vXqC#SfYf2Xa4A!wB{*BeOx|J+7yU1{qnx0X9#8liYiKrs z5>5&&2}4$AG^zx8JTVwSfQE>PEN&u6R@dMS^d;GTo4y?5`1WUb&h*Oi&8;1}P@nRN zY<(^OGa|7PzU{==_s${X{6Dy0*V z41sB9c3T}lYl=@wShFsH&34HGR<7uHr#G{>>Z97{(^67l6DM6*qxsGCWnZZznx;?Q zO9}&^(%V}9k5l8pTFdscqJoG8Ib+etn0!WdS!qFDu&5q=%h#y2G_GB3X?1$u{jP)b!h6!FVRcRQV3O+1sf zT4oW!1P@*6D|6|t&c36E(Yw~^k`^dhCvQ)Cw%*fkw^>HpkRKV?7}vF&`IlTjp5OnTR<`i&A36U& zOe=c3OsnU=kM^r+Yrc&QN6Wp-^*|2^W~rnh%_7AMW0<*Ngw1=?`bD{hI5UX*XQC7=r!5+ zjC2PuCQ%=pbZ1nPhB%f7Sf*LrYdwpavrk39uMGkt833d&5O#^`#^?mj4(m==P~&v` zimW{r9+U=h?(nFR%+uJT-m|+694~YleVbw@VnqK5(q&1i@U0{iodf$4m1ab7!jLwI zP+QPwH)sT+K%6iPveT}NR_G+lgqAyIs5$8DE-=199lmII)23Z##vssa;PH_wKJ9pt z`0;YCCEw)rFLNz_?0KJY-uusKFRXrl5!Z@=`2ekCwtTPi#}`=5ro2u(n&SQwc17k#T4gB4ebcSYcNq#jMYTI#RKH<@gCsf<5`#H zwiQJ3N4B4-1fM-Cqzr%S)St9{DuZ z=Hp3yUfP@4;KHan=1B+=gzbK{`$(}Zz-|J3FKLKv>{=0zX%82&Cy00LX&D8Np zzIj05MuiJe_QG(X5~&T49|KR=!W1fi5)z$-C%pc1?Kr-7ab5d{Kh3pt`rNB;`3pa5 zH?MQ=_H+N+c<$x2*H?S-T$K}Xf-F+pXo5&|*COV%G`m7nEZ=V{FFxG))=tHbhw2#x z>oxfyd>Y{jZG~RO&&skPACH)0ci6{A#t9uMx9JB3-;!IO?CVU`h8y2uW@|F zke0ZsztF_HYffkVu9ZSJGp!sD0{B6eX;ZqLe&q+$e9{&Wu^|#z;oV_pv@Y~z2Bn#( z#~^m%*Ie;qcjN*3doKM=TGXSSU*Dv(5CcKzEZkh8maL-u`)j8$leSX>&$1!L^c&GY zu+0F1i_^gsye~O#==&i#gnnh8TjhD#;kSR@_s<^Yxi|8>_Ivy1gU-hbALjXsd7hbD zY=>(h0OSGrIrp#4t&M*A1D^ymwt9t+T;YUkq0_&AX%^W)<&pi+&YQBh^T zRFUX=`cmR|mzZX&P(){Zb>1eh)3p5E#Q6!H5O?|~?FE~?3GE?E89V|d_?C)&+$k%o zo@#Rp$SWf?$x3EE<6RgX%8Wy&G8A$eHJ*v{;&Uy#~3HgO#b)% z+!u~LM5|oKoe#S#bQP^&>o!{XB9GI`X7nOj$w=>|6V^`{KTXR=&8&5?V@6Y`vNm^UaYT-?; ztd{fiESOZp7&HcY1{Xl3SdGS89BwX z+S{CO!s)-}zT$MZz}o;pvE7$#Wx?Y2rIkRYbNxSS%Ahuq!ivMVqBY;N^f- zbVo-2!DVYLVL5Wtm@O2{Y6!7_;@9Dc6i0`kO4I>#<4i%pYvkJ|=SV%fVkX^HzIBNC zznfOJIDIqhf}Un)K4;Nb>rhmKuc1R_2sSMLQ@ktvOz$pRVLWBb#Zjp??txhPGmNqG zkB+z1co4IguM$j`cfFVl7LZ2O<`jKs;!lpys0BmFWi~W)haWlenBNkwHu%QPjJK(o ztAIu99X7{gv$@vAGgL3zerP48AMLO{iz=|zZ}=dJPh%cD>={J2`qtqwB9GC>@?pkt zE#pYo{pv4zjG_7eBJ?yEx4bru5=jXlUK=^V^OAd}b+B%mpk$>}d+zl-C%u_|b8RF( z120PMVek1}{tuV$>PM_zXIZ#U@SJE&YkbXgpffuRhI->hB|M+a4pZ}`AC2GR3kgB9 zma(xf@(3*mx%{LU-~8nOe=8+~zW?CH$tU@n%M}Y$ZnqaZ|LG2szfRK1PV}?1 z+S@PE{s+e~M;TSul9XaO5e%di`(!|WuoXOb^W3RJ5Cr(X)a!=2YvT+s zZH5qWF@qAtYI8I#!$JsEHO9U5U|(;t>Smwc_fpk-LDqlBKJh0*p7LlGpJ*{jbyk=h zhg0|<+hcsRj<7^Ajn>FMfOpZC?=bx*;qKeHmYweb+5@zC|8Kdjb+PAs#SY7*co}Ui zyT6a?`n^HA{%GOTnX>`SR%#;Zr_FH5VHjkBqdeQL4hs6OC+xdah_(rFZ;m=kvIDPoOtIKr}_M9$C!v^qz+ zCff3juiP;*R_*1dxE61{?yK5+wH=GCV}QSC&uX z@eJnIy>0UF!2<`MJKnkMvPq$g#W87B-MAC$lz~*{ufc#Z37UGyvYlfLX+jZ?hp2RF zo#?nTggj%I@ZL_(1I;KN7DW_Nw+c}qL1Z9ECgf@7S;0kmWflrc!vxbNY%2NZ@}hRn zXTFwPz25osA-k1CB((0CMevWe)1#RO;l!)o@JhU<8Vsa(qF%^COd@ z$0j|^C&-RB!Ru%5QEFqD#i;v^IUr;*JbfHJBON^P4I&KcnxUmx$XB~ua4T&sPv6J2WV7Fn_8DKZW8`|S zkI~9j_BLAem;HRj*ZTFh(_UBIPn;fS)lBMASmEY{49J8XR_^pe5>| z`ovPPAaEgR#fX2^f{k@>s#`^Oc;W)2*gUu<+cnW}UMecdKnumsiE>5 zrNA%hZ10zjT7;-zD-h&I*qCKqDqSv|?AcO22sbmb731U#!t>jBGq~R=uN>n!$uU1i zE8E)H_Wg+18N(){2q{`-rd*oTILiSRMtc#WO~Shuiv%=>haq+1P!>SioR#5x%#8Xz z6A5qjmoJF{N<;xFYDuP*GcdWK3+go81#SPxp#3EAENKAi3O!SWW1)RDTgg0-OM5;d zT;iA@Caj&epqJEvQ4V{Dv_G=$P*2M%*~q+Mnz79-OF$fx=L@5)&c&@bp7{W_@H+(= zB^hTp{7*!fQJ+-dc*Te+E3J5FRM#KlVIH2_@p@>+$a|E*(>FOJeQsm^1g@^mEz4GI zna<~zgMHA zil`rw(YIp>eCs*3SK^0O+U{18hkv=HW)O*0yq+OGAr@qb)l{TsruR)#(4I4ctel7K zx*2UX@!cTW+``Dn?HBB@T9rRZD_cS0%O7%G=lqQ9*kSPmGqmDYZ>Ciq#{1&_H(coY z$11ISZ`;`%?&EjGC47`t`fPsh@3^jOa%@MZuYAIekxO_lgfZw>%K#TC6ZnS8oTnllXz}LG~-^N8N*U8V96g|F_Ve>;aP@W`YU{UrA&6 zmAdIXXZ1haOvYm=^5}aZxD}FS-UAIqhrHPPohRO8qM5xURX#X7UCNg0|_NPWh zdOYX#p0t9Ex0!NQcu){oWtS^3?6Vbpx>PaKDjDceBWWJ!-cNt3i#KCw3<~E^Dw0Ly z`S_%Em6|^?{N~T8yt%z56z%Rq(O<2nLrsp+CEg$z1eQ1`K&E%Qq25$;Xqn^BY>J~# za(m@u?3Bg0*x`@1Od}`wUB0UN_h41_{{8$e9}f2UdVnqv+o^7n+-qC1kp?Afni=LT zysvni$)Z-}rirvTNok}mQEp#jTXNH^hw2YfjhfA1q@UqC%Cormq8%ghU)1v{)%Q%` zoo8t(vSi=rj@-_B(j`NqHgh|)ImM^L7P^<}wmSpb19NSlh~G1NXUKKEd2aQ(=Z|%6 zrC2Km_H3-IonBULuO;GI9O2|-z%~TS!pA^p!~6=V&9fZq2zux*64$_-HI-wS&2!i> z*XayW()lOdhp=(_CNTIqE51rZgm zU(yDEh}sImg>}M?vsAZ-;O`tPL-5$jf;2o|2`<9(li%PrpP!?ZJ>avn%7wk`8+TYN zSkmCL)zLVpv)zh_kq*vWZVC$%0}&MGxrZkY?mIN8h$f~?;LGtjm1UCkh0q4E^jhMG zDvaqc5miUyF;D{5A&^V05Wt|Hde&$XS&Z|UdDCjW} zBF!LeJp9_^XxZ_48BxXo0u-%AKxM=nj@ZoG;}aB^&OF3Q8B`2A25LJH^q=avE0%uX zvdQi%uDBvbgG2)H>*Px5;JmeUd)0zJY_2AuwbsJL7OjJWk1wz^4w64)af*4TiQa?E&W< z>%dy~Y7Y)tsLjNLoq<`#K5Jv2b&K<)^9b#vFLGHT#Rany#Q@QU5(+a}5WomE|tE^nwn#I{w5Chy~$oUVK20f-fn zI01G%Tr6^-5P0f8yCWcMo7@7YBf8G~j71pbVHg3D0ws9d4i&m`2>Hbak$I#>Fzp)y z*=&tnPh4ad(lnJ(irUt5n_8`Fs1u)!Q-^p125f1?88?1F6TZQE8w?yrahV<^)`woF z+4_v#(z#$3W6?y_@sPsqZn3x}fr&@O7e*F6c#PeyA^$r2_7c`5p?w@7{V+oM<(7%r z$$a7UohR5U>9+5nReVv>?{{-8TgMZh)|TCObN#K=b9Zumadn-t_Di|{Ros6itz`56 zNUPX|575e&^)cEDX+J|N*&%&UlU7u$ftkb%<^G$IsDc!BfL-GTNa>=jlflf^1~W-h zwp9f%O8pXunW<0&pU7((&{r$4m2Nq>->P69b45M;lYVz)k~YV>&E@G#=q~3FRapVmh*X=$}D>9exHfV$S z=5Kc1@j}`G~CVTzWx zGX93nGr%=w9s_T1wb$^O5jP(e8ruj0k$p5t|EXbB?;3jgu<6z)tM%D}udHkDTXwW+ zbH9S?8uovWYuTZ5Uw1#<<7D!BgKNbs=k<2D@rd_P0(7&BMs90L%YImqVnn5gL4kB7 zlh*0R4e{jBpycw+xiO!fPv_%~K8q)hZgLX3(PYc=jl;=}YMzV7Tfxh-XWBMs*{+?5 z)Orw`t*RuA8x=*lV6wf9HS#f~wqm64->Vt9Fw>-ZB&CI=&|kx|w_>aj&qqvj)6eFt z<6J54z}q7uqt9>{`Yu|@mI*6w=UQiCnL+_R%RJR{*_Ol{`TmMJVL+^LOqT*%R;km;iIxwda-WQ-Ll)*btlDDY^*xe)FjO>>v-bMrt$C z;sQ^iCVZnjv!#p6*d{Si>Oeu+JwbYN39P#W#R*jmWRvPMK67^CL#j;^U9T=$LcuOwQR=cGvtlt@s`3b<$! zoF)5_46T$!@EmA9Pc{!E9oA^Uk+$+B#U)E5u+++YBxHVle4I{Z7Z=ub%DH>vwFg^E zU5t+tZSO}!A6S?^2A!pL&8ZFbp}#||i@}rHR27kVM9&EkEeB?Cf$S%`omMf?-YPID zoJ~6S<6K`+U4MjY@z_hh)p_qrY2{=12<_9W=aRSn4fhpCGd<=wd5TuC;J-kt*t-8g zE1sNmjocoOnSDfvU~Gs5r3l2N;zXfCjdlu5%1S0wtvW-NvKlqAU13glC<|L5^@m04 z26g9cF-2Oxv9qm!b8ZmA7tR?%1|UHB!DoV*7KChlx4=v(rm+oxuvahH#F~ir;X#!yNBakCwd_m68Bm-uN)j>zpN!L6Bp`e&a{UU*c1;7I6l$7yuNF z9Q4K=+kC@Dr~zEz_P+yh`j?4mO-1VNA%2&>aJX^4G^Zjk%Va03JSSc4ZkXWS#f9h7 zTsP@dOUKznL9+=aw%HFfkOeYLKj1;w(?p%pSKLrFFYjTFUae;z=P{w5&`MSPu;F_8 zNiu*|-01G17~^^gYbJhGtWBo&%^sefo-x^zk@QfLg>l;tDm9!OS=%V&d6rCY)6y?Y z{G_jLM;4?Rt7BWErtY$i?~Hxd_miesojqa>SPjdBQ@}S{LD-~f`DuoTLpqE~=O5)n_aggSirV^$sRNNAVWocj zWqMn14@YW+89d3(^GLk0xqQzGg~H>D_BRqlQ7^Up8br-4y z7s%_2uk<*!yiT}1%Kc$+?r-M4;PxZ5dugBWOxIlo;dp`j%7ZF!EEbCmjhr`fp4qe) z>iiG+hAUEIZrADu_;I|VTHj7oRNZasUC~&O!F(-fmFOIP7`puAfb&Tfn<6-9HJs^T zv}w%s8!ueFeB8p&9bQWj&0KrW{B>f2Z|iKsSnI#g&d<`hK%Sog8LN0mt6K%q%r9*! zP~H*K^X4%SO2f$xknJ7!u+jomni0}#3C$8-p95MI3)<|FvK`OM-I%smU8AuomKZeF z_pR9kAri(I+bRpUjUWAwf!Nt(rLl;=*>Glv|@U6 zY2|o_tE0G8A7p_(gp0@^%Xxm{XB%YQO| zN;s4PenbPh!}#sZkTlj&&EB0CJ!^;62}wG2lxyh{Z>Ozwjz8vFxmV*?wd15tbFDbt zd_U>jgWOl_{$J6mzXQ+qIGcPf`SnY z)2Ozbg|XhX$^*zpKynkxt;6Pw34*(34cHQ}XAm~Gc(MuPi%|q!YV&?aC^zCMN=IH? zqMp32Y~xvR%GR2ccPD_3A7$1K-g^$DY(PRNOqm4kD z?`gF)70d%Frmz-de;DmByw`RVv~MuXiHhlZ7U!P0zXel}DyGTs)QTwnLZWYbD8Y6H zG0fiEUEUM)WWa|98u--Wd;SxL*r!F+z(7*P?E^D&%E2N85^G?UaO0yvjfp|3i$g=D z<_e1sg^Y6bc-!82e_TIATl+~r!L@Y6ORsfXSK`h-t`!S#KkW|Myq~!G!`xTw#3yKP zq#eD^W$<3Kucy73`@cjxRlWZYT+0qoWEOFOB8vHx#|qsufi%1mRy6J2l{I2lu*(o( zmn7AM-$iQnDnLcdTcUhcbLCEv!*@P>NqZE*v@R}g(7$=4?)H48}1G_-52KcSR zt9gXE=22-B=67~ET5p#AlKZyU%rHi>7rFR@&vE|o#EG_#bDZk~6$~U__#W;*uezVG z^&##*f%~7Nous|^+uUAzC#`&^gL3eF+;8b~wFs(MBIT-U$tZMTg#FROL7@=6xmC;_ z_sHYY2xD$9Tqll7%-iTh(E-ce$BPR?WG@&|5xxL11C6cJbSQKn2%V8U29kgdWePQj z6irLQye%2fqSn-_;ktTKot>TQ+c6Y-xxSu#N}7@T{oUM`-}YB%#pm<)-1k4?zU(Mp zq!n%1Kj}X9!Tnz6zU=aahE#fwug1{mZ`$+2Lt@u>=caU3|dVY^A=$QwH04WY+pZr)!&PH`7&o+0Q)je$N2(pN%9tDm87<*f6|Lq#D( zmEAiBK3BhJW=A(*>LWMn*~aJG*l&t3KZYH&rYm| zBB(|qG)w3>68dOx`)ZEpqg&=^x}-slafZNM4M8TgL0B_jJ*xs4qUXr@dv{n(x}@)S za;;drpQlv}UEcpquH~D$c&aTU_PN&czf4=lN^PfK{yxviFMQs`w zqJ1Z=s+Bx!x8{6?m+sQFscEIhjQ?#;!ypHzkX%ns! z?tY5<@)4yx^E>g}XK4i|+sQXqJ+E!Im~6|lau!ICP-PO)Hjq{_MUp9HA`81kK1>}7 z=~wOytJfsySJ5Eym=(7|DZ)cX!~$rjLT$}jGa%F0LY8}p zVaj*Zge-*7MsK03`gVaHvsRMds&X!&kE;HxLaX@X>YQe->BUKt$=BEV_s*@Eb-Xpo zwByv`piMPI!jOO*vkjKzUeP$)$Xr%m_-yXQpayHST2qstZT>PUkjxbuFsz=em)>69Y$1cgGR?oaMqZ0Jkf=FNz zC8G|#&&v&9tTo3nS`khTu3AN{b8f$lP*ye62ObBH9%<+ap<+e5;JpbjYcl zyE?hZxA}2O1DzFdG!9oNh)NvL#-_=30+lmNqA_$xNh`!l6jE=7*HZ4n&ZuVum-v7c zlHX1)zSvV3I-PqjhYZavw8hetHPc+TXiiN(m$5U^xq0&T*}Vt$%}!0pC<#4K=A`^?`uFfGOc2o@xh43WAb(@8VemHZ7#EHt{$tN2rIiGFh z`;rSHgNccrc#B7OZdpx6qGQ?0R~sLPK}n+*hz~VClI*y0i=5HX{Wg0wGb9qhTq4b) zhp{7Fz$2f7N6QD1JpcOVyDa-UTFI_|LR&+4H77#(qDoWY_Pc zm5ls$+6!nOq}@yV_(MLQ9_?3ieK)Oq-akz%S@zwulD+?&Rx-^sFK`)rkybXE@1<2N z(a+M#&ir}WucG~X+9%Ooc)0B=e*xEuXDhZHQ(`+*1YTDu+tinxQ5xHhJYsFK=p<0G zcDiw)^rq4Rx6ecKRouu0g`%kGHF_xmlN|>O20{y|$JbvdJWStcL>VVUW>W!pMPT&1 zd_I_rECj-e5G7xpL}Ef%qh^DcmYIX{oiA*gl)*?NcXgthhJO*{hNQ;K>4wbW8 zhK*Q+)YTi*2~r^W^|MFX`52eX?6A7EtF+Rm5(WqJG}7+(Gdw51Up|+xI&zESOv38f zU^8JkVf1XUd9E-y!+2zWJR3~jpiFAp@Z1se0Rl0q^y7jcF^W_M!W}K{#K^?og>V%cs2sa+65ONV5fEvJNE3^<@li1i>m%Mq}zNR|<=U~q+PRv=GMSqQe z&MF?kj<8TgP>=fxf1*h`_IawkmpYw52-3R0p*o2knua7wgx9Pi2cbgVQP%Y2rz&1I z9x}YG0h~V8HYre&Z`+0AK8qY*QfTo!%&9SxC>9P$cm~r@vTBzIOmq#Q*}vvmc<~|HI=*MeZEn|2JV^Ywo%?$3 zM`%UUKS?WEoX;h`JoR?R!x>urK4=%;64$o8yt!m>YMZ2mYSYhifEy1w_mCOes$q$! zz~oWHdHvqYxhrN$xIre4@Z@{e`l~TeP06Z_A zKdG?6sGq^(5lN^l3%Sl<=TUd%Ej)h-&*%4Z__fK4pGO|zxu?+1Wcib%9|Icd$ekXK zXZi%Km=e3kI=_SGlxxH~+X1!EnNV-l3%+)KmoNTENI&^K?}5d<%g3AJsrOLt zclcfJ=kGq>KrHTG&+oEh4IigSzoY^3{CH0BHdCtZqTD$P!E4V&&)v^+icj47T+K#| zw^_#z@VxB3lg%DjiBhZhQYOPX@SN7Eeoj!eu(rZ!Q^WIUl^Y^&^fT3fGi;W=D{fb-r%rT_U9a;?TrSqI*fT~8<4umZ9n z8St`1A$**)H8_9PqyDp@J3EUua zr~C&Vw%^t#B9(sD&A0Y#&i3N-{ZkXtChqA2ot}B7ekU{2WMZ8&ebMJgK=xA6S@KCw zA%2txtpp7pKB)96vv{rZ?orPD!MaWPsQenH9#AGGU20QR-5fUa_92`P8xz&vqlZaO zmbfi^suBdjOB?`7>g(>epztWNh|EWIA>_biepD4QqPHaGW8S4@$Ezer{w6Do>W8Yi z+LVh}I{m1EyMnaZm^@m&J!GUxt-I0(u`8tXjCGpYJ6NMI6cA|7`Qn_qrn=caG97Nl zi&JrwGIL(Sw5ahmA&@4x@{n6XEn6xdf^lgOJu;pJj`mhs#R8|DD9>Ql(k=AYNk5eY zuNB#|HCR24x_=WkHI!4}>n0amg3=QO1Z7{>a+x4w1);Z6cbNp! z4dPjUl&+bYQ@Jj5C03XktD(bUS(J;loT$ZlAlOY=k7rlwc;yLSpIp~m#}nLtCeOWr z_F~#!p%vaFz8uiUZ1Zhv5i0?thCUSzvwp^m)w@e_-M+D7O*vK2T^S}LNJr-&S*#`6X>wIET$*>$MOO`lEoFB zldI&k12PSRvE-E8(?=DBr}^3F&dM3GUI8<$Ag^4WAmLPm4(Wu;<;9bmCuhTTG79uT zkC0`77wIz&GFT&>YnYJgAE4|V1tCPd91D~$tYPt*7bGu!Z*&nt?uas6Sev_d7R$8_ zsHZ*|q$T}R^Y|X+7KOO4Im68<6hQ`znXo`Obsm@{sKBC%-B@KYR273)5S#;SO#jNVZTPx;@482Llq{~5 zGp&Vi@}?IC9j29E=l5w9&!0FsNT)Bo+x<_cXyy0G=ibcqOGmd3`#J5Sq9~uqZ;eIAO8-nm7q9(4oteiqH>%8Nh=5h(7Ps z8iWCe;0e4gSCX=RdJ9yywi*)JJ`oOWkQcphB{9NcoKViK^~ZO2eXC75NUY@e4Tl#W z1{ijayz&m@kdu z_PPgbiN$vVwGebj`owsP-I!smu(-56TcsX~a@LZVJF1lHdaWt{?uG?zOeF~UkqH+0 z(Fp%>SPdDk-H}fLKhg`YU3U2);qxVN{Vv+tZ~A2`uD{<(Tl0t4b1itz_dmt8`0kM$ z^BFj%3H9ThTayPOaX}@h%dpyxXG|WH-$>q_GVdFCUUsK8A7n*bxMiI^!~rohNg_N) zuo(3;#2~Os$@wBKcuD8BIrEnYemDiF9emBMtZnG{tEet-sZD}pAkFzmbgnItEtC^KZHnkYIOpNB46t`^X-&d9nCvnJP9`!cwOSHH;p z%ekhLT#MeklJ+p|@6ujEdx-F8JhbuaYlS|3*nhWfR5p%WciyW3EEX z37FPgy|<=vO%jLFm5~-GcxWdpYosEJtdpgx8X=7YzOv@n)?YZ(Un}6G_fq zEE$!H?JiX#Qmvt)3ZF@B)fl$eSxbE%v)BxRFDYm0EQp+74c$hmKs5Bfw#nzt_}BSl?Qh5dYiT`b1fg-uhA-IByl(C;U~B++2m;( z9vd=Et5}rppfy>7R=&G8(@LLskXA7y+0VmVE9U0;oBo}or_gdd!VdfU1o{-VP>mMh zClhBzP9Y83RL5QJd?p*{0&x`+HUpYTcmsXW1wzIqHN1t7c*|#7ct!-}45UJF7TKZU z-;g*@G^#-9Su2zPqM89LyC}fwWfTk)GRh?$buR)#N-a1hnW85N48(i^EJ+SMx&6!? zDp7t-(6fRiNu(qu0$3eH%tpd8vD$kEyyE=y0HtDzsfM(MK*nnb4n66Xri0|rmOD)k zj?P_=TqvYSRdraX{o|bme_Ly-9g!v@^{~r6@4lk5Yohb)&T~3fV*ZLs!_%YtRi+TS zcv$Xb)bl9gxPNVKtaGEoOUD4lA9Ew#_^_X*v_hOqrnBlh`{(9QjCbh8ses5n7lw*! z>r+dMGSJwq^+N0QCS@8lm@pNVPMU|D%=nxBx0z(U`*jO$vyY6aqmI70&h^^H5mk9x zS(b(K)Q$JJ-Q~5kPpfbzV-$X#`%~Qi0`0BBrF&h@`f*xaKTIp%V&dH6Pk9b!UMDVp z6Za)Y-9mdFZPrno=UP6ce@QDJ$$y}g9q4nkq8Znm_WOyuw=@NX?g0jM_TG9(tB@}a zGEtB)lUwg}FC!vlae20I+gZuIfjXgH16Z=Fn@(jKqJyqWSZ+h4_E>aOIKVk}RNk|W zh>>YV@IBwIk@j7hMz7NgDJ%vxuviNs-%Ma8aL1t@}y_Md`q=w?|%XW-_9H*W~LGeFNo z0=1*+k1_GB_$7_Df%0 zF(-o|Xi0miOFDDN{<0-J?#1q>Oq{=*YvJyxXx~FCKL5n;bo<_QwDtAB;##!i)3oC2 zyI$h831300=d$0AbA4HL{kZS)c*GabO1Def0jxR=z-*GNvrP?;UNJuPI(Wzl7_i7V zg%CAXEo5Ke4jwhr;Zd4pg27uY8w?PV@yx6rs|%_YD>AgGQULgUVdY-lK*}QagHt_K zDQl=@)d5>jr9Dp*b;{VjakWz|EkCz~`EI$l)%4?P_8tyC3`Ng!-=aXNgf5=jv(mfQJ)rqB| zM}bHxvm;5|v z=~F(mT#N0-6nLRec$h#;*4ShT3{B!yXoy5lC1k780q1L*<+sqAwqoI&O4>(u4GbCK zD!mQRb}=dJLZAg0wCzjSk~jLC-{uB7>(KDSNUj3F;r`S-!}xd1#Ammi8b4&R&9`xn z6Yzl9mKQcwym*Tw`eU0a$X9k>3&Lh!{V&>e1-Dz*T=!L;m!9!!w6*^6d9FpjZv1YK zTS{2u_})gT8&`LVxVkv<2 zO#Qd}7OEzQF=IP}(cjIe*)@>~_pXL{M<>FS6*cB)oGwL>j3KSK8NJB#v+e;cX1;W8 zgH16E@fxFzh11k+3*`bpB0BqU!b_=PGH$Q2wVs5PGZV)py%dcXn+Yli12StRgbzDb z3V?v_O2lv>D+pYdcj28|Sx|=0*z_7bO?G-yGT+Y>K`8q(=}f#i#RZpf%sj`;IWCq2 zL>;@!H#I4Vfz78WUcA<9KWN4S8Yg54Atg+1E-PwRVLvEyCX;F2Z0fE#h&3RNJj57l zBZ?U(BPN>rw%-nxV;Q*er%TP7Mn+ zUDwm|!a+y9uD?0X^S9t%grB%G<+iBJBdEe{4q@%RwbDjOK zajo~>Px}no8_b_8Xf!C1U}|QNKAJJRCg`tB%@%1925oGNactQl5~&0!NgR~Hr39i$ z%6?QH#m00Pl4(5DJ`iz1LsVJQgCKN?-lKhEoFiuP~dd*9cm9z=NJz1s+0mw@sC`(TqZ{k=>aH9+VqT$3{0hO48AIpY@uI0JSTflZID0 z5a<}kf116ia=W|HJIzv%UJDgEGfPd;ye0XkbS{#{ktqP+nZwC$UP1Fx5fS)HNb0jLMNdnZmB{@(n~R;SA{86&eOv(Wc6SSC~|&{t+;PRKEcA-Woag} zUilK6rJoLLtLBr(9SsLgzvk=^$L6fp7>?6$WGC zPSc-qCzD>J?d-d`uQ|Og+ML@~I*VW?l^z%ya1G9!z<_3icbIDq#6w0W%=0+h7fVxe zTbCRo`eIQ!tFzYPTQu^l1zcQ4!^R1^=;q~&o-@S}>_YxGD|xJ6LxM*}f1qtsNE(y- zyPd!92=5(aP2NN+dt*MIYkbWB?R|*nF5tObyQw*pge8y+vT85^a(R%y9lB=Ju**Xt zjlK*?0OZ0u!eN3Zyo+fg9z8Nr*K|TR(#g1)%0&V3G}@76iMV>JpROi2p%@}!l+|DR5kzn= zo4U6wo8*5-PglLWMjNta<%#dWWYhY^FDc7e8^(~RSV8eDEB;T3VZWBo@p(aDx~}gk+d|1k}-jc5zWe!DfYJ< z)u*kGueCh8S}p;+Eqiz5qs;pS%>U{C%Gd3?XeG-Sg6Mo>0k{ItH?Q0?(SQf0rdfLg znlfufrZV1H14lr=?dx*+20yqCs#b@OAft{WluykzAJtV+=G^c-Wxj&xRU4juZ-!wu z`NidXHkUYeMH(K#r66Ks<1X*UpeDAs_>9H6N2c-tw_@=pWRhrHIp*(aI1U?7jablM zKDxI_G@O{wbIr*0obEK+T;5`+N0~%K>nEuJjYVo4+@gAfAG5tgoni=uFyGLud_?qU z>a}iTEBSb7zY&(HgbT8OauUe&G~3y0cwVtx2f@xF2zqq8x*K^nzsokZZ8)lAJ8h_jPZEY z1YvuI)38(~p>2rMH!EZ??K?b=4_|>{7PTcg(<^_tLahzz{2QlrzJCprrbKR=$aDAc zoMbR!jCCeD1@i!MX<(Q+!h7nT?!{$Qku1reZ{fWwTJLRZkuLA>_{b-CPkeC7_uav` zv6fV3UG|e42*S~NdhbSdnQJaZie{h^p$p1gUVw^)zUbe&4!%q)73y<0862ziAT0NBO|Zp{XMomfpTy_h@T#d0C!1qW+4QhHdTWxP#L)#^mNfCa9U_7 zX`8+uqThqsr=r0K29tPF5KKZhzhCk1JnrTIr{(fHdm!@ZHGu3xo6C#%$hx=lT!-f; zEtEqsjW$MyaK>aDB7)C5civ%q94nZGyWe>ibb7`!kk@xZ)>CIpB@0*-%Hbn7tm&Qu_R>P&u zEv@=+8afm9VUIQAbCJyEL6;-Xq)*YB0XUHJLMcXG(El9#7Xd2P|NZo>aetUrx^Cgw z>_u4+Iji|lY*bkQ4ZkcPr+`UZP^X`zuf6nTaKe5fmI>!ecQ9KIlXkaJDm+fFn^oB5 z@A;#i0Sstu0DRDG9EEb47cUyJq>N1g{W8r2x!Y!iy>C0u#=BzRSHHpe?GMn3FTRUb zes9(UC0-U!x{XaWAT=aNDCfZ+aXLS+PcAi`1;q|d&k#m6WBzYd-Vzd-x2^AKqHYLq zB~KJ1I=yER6K;tyvr|pMM3q20J(lL$K$z^P(kcsJhLr&ueQ1^JHYC;N+8w!qdDS+~ z1+GQo-%cyo8JKUV=e@1jAV%Dr=~7P6v`Z21h!r4wgv7UA2->K}D<{RkD_&uN1BUMc zwHE$$e$@H%J+#W*u4Ao)YO_FK;Pt-9OG9r}Y<>hCnvP{+ib#={%Lq#(w!oVrqcl>* zSU4ipWGaNLU>m$w1@=0lR?SJK!|>PxE&%DGj+Dpq(bFeLQ90G8h@(W}Z|z{Z@JA02 zFEl=$7SP!_j>GJZ{1$T&pGuu}@XX!RaZ|VbvLAD~`x|JV#CuoJ%FmEG?-5z~(MDaH zBz6C|48tz9h>ooHHwiL5eX*(b8_5Sgtd1Z9)bds zJmRaW#2T~fnnNj^Lhj}y+DKo3|7ySEF&57loQ50WH;8w#Vx)ry4>SoXJcZ;WB_Isd zyN+TOgIZaqAqWZwPORXq;D=F#A|_W+fBjP!rU^}D+fSV~zp#n4rjapDR>oLUC>FMS zUz4-9W$`l}Zl9k7|ru;=>H;IyP(s9VfNdKrib{N@ZyZ5MP=!p2K#>7nYfe6u_ zWe~mYgTP2_ulpj`vaig%v29=Z9APngXbWdVC$ z-9dPf$)Ot9ItMIT;CzhI84c^?pa4Sk?6HV)v%j^Jn31v{ZFmw4bDhVlkW_@960oaR z-IFVbVCUz}S*T4T20_{I9R6y9Bs1T>OM!t*#?WC`pL*DbK8tMtvVmRF#P&w}H+I&} znx7!5$ump$eAGe;jQF%CU1c)a7Nh#$>;sqem}d|g@j>%9;ntAHhsz4wE2XLFq8XN0 z7vn;6^KuEjt%K^0?ECRHzRYtiT_*A6UvMqo?nAWFCG!3={x84(U9>e%NFMNW+`pdZ zlh)^Zf6jg3^S+<(xUbjH>iQ39#lx@u4?9LKq&+i!+Rn^v5J;c}Be}(Rn7Ic}0x!z> zllEN4gE|0_u-=o_Aa?0}WreYcxd7P2S>$W(&gr=hJn*J#!k+O8npdwFz!L|g0l0#! zuS1uVp&h;GXHlQLjhO=8$0Me5v-R0u`d)AK7c7@XKG;gKHJAu{g@{S^DXQe+h%hkg z8Qapa9-QPInF7!39G2WQ)_G<|=NG>qUY__c!T#otEe8Rwb7aH(-Mr=YN{%WwQ}bBI z%fRKe`xwn5_Siccxdj-IjWqFaP%Z)JjRNN3S@7> zE`b!_)+8~|RG&=1@lRdr5~hBbC&Y*$+BhLKSoX@Z@E&Dm;_KbLRn zARn{-_-CaCk_1c{vC`|<=JLrEV&r6UcSwh;^>Tc>UA6B#=Q-ttJ$?%@)405JkmZ$K zE31zYPeMjTDAE8y*k&}tR$Y?)cFPb>>zqSb3gr#r3cFB2*Rc5CPLuT9r`y7hhU z$BDCg$N}u``n}n?jnPcwG|1eE0+$c%+4dnDT|O4@K=)>;N;VkbvoT{4R)aF*1#vUM zX5h^*i)8=JtMC0OmlvM=)6VZ#X%(aP>$H+Dp87MM)0gyQlgq%V@Fcc-gc8*SZQ_8$Slr3qyU)b z!?-}mHN>k>;mC}QnG^%rc6~SGiwMr{-5O#>k+xBzI(gT#)et^>pG;~vX93|c?eS+> zS6ROk?g#ht8y|4}d6~A3pL!+NwXJQC&*%RAGS5j~_#0a3+mB%XjBz>`hfryvd(lf% z4P_mR;iW`VmyDRylh(Z_i~Sqi!dhnAlZd$IQ6b_WrkvxZ48A_{v;V2RFCXVx^zdBw zVfW8F9v!3=-TZ!9$!EC_Ns)u%=Vd^x%zasuP^F70Oo)oHSD=5;Y!wr(1LSK#{V}vU z-;io769QQ2ZpP#!Lb+O6H~-_Se!*dC27;ODL{vBR(4Bb8y*1=>^ZYk6m-_kiV#$cF zaQ2wUkzh}h4mY7%({~fL}B15=^3Pz1z+7CLePlRI%(C~1}Tv@zRlyG zZT)>t{!`;ZiJ12YMl!#cK*OUrFshKMfw<4wIbkifE5rD7xD*&*N78XpQVy2-$0X{< zhevZOEsD6mV3kr&G0qw0^+8(gLq5H@aG3b;wR`#pRK-!U@!By$-LTKSn4}b<-pCA{ zk4r_8^W?%!fPV8hVmC(FgAGgeXdmq9s#T`Con_3$DC z=3G&k9zs?G9;L_5Y~A;4b}nO=Bz6vJT9!6|%?~?VE-#gJ%S!h+4m(o=BB zETF+jwz7uxD6>RRumU8|a@!Q?SF-#*O~Qe78H4nV6l2d1^xn zFY(&;5+2CB+dvo=pd;5Ut}aULvv-;u)^pXW)#v}RYb7rw0wcAee(F4{jJKun*M|Ti zzJ+OUsgvJv45`-u#6%S)Z$*osAA;8mKy0EcO*-0iMg1z%R z1(sNhXRe9op@CgiI9pRgt6n4cB_C*`lPaPiLS1s*<`7T!X$9vF$^u&5Do^mgm47%8zxFsdQD+(BK*EkdNhpj1>O*Wqgit_}q$3H9$by$M)04v> zB^|qZ)5BB~GD*WB&W$szTb_bRCxZv|BmRLIx;?YdC&DBTMz1^ax?gJ7(0T{g@+p3i zR(7W6|FXv>yoR>6PyH6xiV@3Vm72>P1vh(l8AWh#45uqx6_=V>ZuD?MWJ4J(+nJw2 zPK`Ntues*wiOP1^kLa8{aqZ8gv#cJ&I9shMcf^Xzq1HXIadPPr96Bdf7P|TQ>)z?` z_-b0^K_uM%DA(fddHq4I1=sse5x@>Fmzb1&kOLA#Kog7MXVQ#$ii%Ke2U8@;#xEhS zSV^0K5|-r*BIhgEgxms66ckc-?vhRsMIUyNvUJWSn-9z?8cFjuss{YqAfaDNa}@F% zdza7uWwfdXochSC;{NZ^%Kw*g?=8y#&mIwen+Yv{HH zjPilD&IcfuiEn2^Re=Gg3K>@(U~6t}%#Ipc8nvH>m(MLR!7X0eb7tDhYzTunPfbG$ zYbt3ILY8@W9c*&8_47n6$f0AWnd5;Lp+aiXSus{*)Z*McX4xZ0@sU#L1vYnjRn9-v zyj<%qnT0e3l%QRJ>H)=TokLwPq*V{c6ZWw9m?4pkm6g@8KjJh$DiscVaa_4UJr|1b z*)GqDps2K}Nmz4B_s*Rz{_pA=S_O&Vlxb6>CKwQ(Q#o;UnV@DBmjb#>QjAS=DG*Ys zv64I@-34@IpYVrCob%LIG*+dkOfMho-#h7)czk??ICBbAMNbxUP>{erepq#rOng|j zI1QIl9F3ZAK>JJ-`?Ig?gXP<+bChG{BLvxa+`8F9WK&D&s1m8HaEoRGjZkf27Hp7y zmBr%QP0opvY$o^!sCLr5m~xZb)znxY_^ac-wi?+|3x!H?rT``M5Jr{Js~DUj>1C9C z|0D$Z`=J}pf^H<8eh=5u?f%JsalgwAwBl3w`x@7Zwae?IcW>vu?4e)xZjY&dCaw72 zeYEFQ&;KCTvWMpTZ{%9?%;#yJNBf-jxE*hmR&vt&qy45|jXF)V(!KAYm0u|7s-Pt$ z1(^zbS9Mp!ui4C7Eyj9?w(F2bf}qKiL&OTs4E!~>%_iVqPLQ1CV)=P_#(!h`7#X#q zc>WUFfNDfdQDap*VWds)i-OT5*C$%eE!o?|x4+kGd&FemKt)G4DIFDhv(K|Vo|DaT za*OY(1lQVpa^s=O^)N^7=Y7eLd;7~ona?lk^pSYLbrMGCrH*}I5AyuQ{OP6`2^Y(t zh1h{9dBpg8*a&8j!*R=Ae3JuNIkqpWr#wzS%O)YIGu=F|w3K-K&!;%gBwu+DSIK-o)1F zu-9bG#f0O;SlV$E{VgLD>(#Kn^8HR%?x58i24NwQjoEGw4Z{|NzJ7u}CF5_IZ#hS{ zy)(HZf^Y4T8HafPVfvAeJL!o>&8SYHFYNUXdhE%@ipE&YR`JiAKzzjhs~$5=68{@f zDCFVD?t(+k&0w<-HO0e9ej!Lg#-?~s6;=h4-k(ki*f{OIHpjRSCs5g4C+(C5go5Zn zbFwH=^Osr&7OXZPx7s3$%}+|*yQlB03;pS{%u%@*$q&x|Ks&!S`Af!dCcVF9Sy5ld zi8S*m`!>3)f_!4CZOU8-8p8x>fg1|$3yE!v;V={R32kvD#N}GZW$B5(8%ca?2N)@o zBSQ&PxQJo_^hl0yas4C~iFwOAg46)HR^*Rt#zqLX4oqsXVBFUGW*}p`))%qqrO53A zl}=oJ%6d_7JvT+{)xRwk&p_Idzc!c6lELN?o5@{j^}cZBsN_m}L?eJeA!*8DKv4v% zu$S{pxs3cR3+9957*cc)PWBDihNu>#s-L_}_|WbaUc2|{mc`m*cxcOW9AiR7SY*|h7E8;I%VR_Yq=IZ%IlAFE&j3dH(UnG z`8|NDg8%P++7xO%1qn01?vEN3koP?ayBc&&Y zoHoYh_z1hbeOR&gIf*>fU)y_n1FN*)-K!jNDHh&C9>ENcGZmFC$5ycdE5T@HE(EqQ z-j1F0l!Y}TKtMIhN5Di_e3Nb@heX~u>HT{}KnI%`DsMy92j1k4x-~g5esb$v3a%j> znd%J)dSBRflcu7;Mx3pU4;F+@%*pi3)~(Xj9cSyM7dGX+?8Vntdok$a{h3c)VE&Qc zIpO$3kL!F&`8l(6)9u7wAA zeceaeX9;fyTT@;`#PW9}2wFb53n4L82sV69yKZ1ps2N%rtWQ2bNZqE?LlYDVp%|ph z74?Jr7MW#Q=SN8jY)f6xi~_egL|^(dFONOT`n-ktA7nlLnpQDDxh^|@yB!OD2iKQW zzi+or`$;tq-b3okBGWa)IXj1p(O$1JVSzH%DI>xoXpD1fcY^_yZKx{N&J;%e4{h%P zr}tIY`9GjS0mZf{P+gRV6zHU6o~Gq$T4E+Q652GwWEujc&NInOlA)8CVJ=O>s>=$x zh^$r@w7R}lysVZ*{TD^WJF=)nQOhc9*K3u_0)o_g6?FIg`CiWN{GNFx7uf&2peMiI zbI$pl%lH2Mp6_{pu}L@1u@A!bXJhPN{RbB|hk~1qmTH( z%k$d4mQt_1M)yOm-%aM}@)Q!l2W0d#=Gmz}sf0VJuY7eJB~A$o;V5^qg!O8x?E_2H z7tfjSjDT4&I9{*wR(^lV`tg~#pbp;6@8aJDSlA5*4V`F4@8|a?5B~0(APYf7^=vpK zrwMylj)eY_)DE&bwb(}eXV(1(Hqy*-E8wS3y{Fdo%IdheMjGDi%neD??0kx)HVQra z4YU{CDDy1s`BGatmH9W+Hsoa5X`C3Yb4JH#a*!V`nROES+4MB0ihUR5(i)Ru7pJcH?bpFTA09 z{kGe8aJp^v%SS{EjIIGc#iABv<^(9)2G zA*Mp*l#Pw6%EA;4@~}mj0K?+2h4jMaXp%_tp^=F#eM#aVTz{h9^f2o2S|d%m4a4u$ zRLHVAn=f>v?2sbqJ?;aWX{4bZQLW?gkuAM1`(N#|OwZ=I_6fg==UR7pGtYwmx@wW{JXxVO$469)ae#Zs(jmbH`4qE)bniX1b z^~FJ8mVk_Hz(X4$Nqzg51V?n0nl7@s3}HF&q_i(d z*6?C1h6}?fE#Ps~j**C3hKM(6Ms`m2H4aLa9N)QuXenlu$58tNlWrX7ehDWa&>RR>Q;bAZz7FyuFOW z$0Ed`epQrQYFtCbovbTiMonf+$SgLrf(Ls^r~!>hiNOZA5$j}e5BmZuAmF07sP6hI zO%9X%7QT`^_Y~^)s7*3v)^OUY(NU6w7cpkkB%kbHpqX_wjAJJZ7Jan^U;XPDR`7HI zm`E5%14;N?7_`o+a1kbJDlJSq}3i~>ZDo$Vi%G>-lB24oAXP6x))L>8 zyJ}&fMK{4d>bC@Yh-%+|AU?o)yx?rgT%~rLge%x9_9-4Kh0p;6xyj;OHzat0ACRk> z=ml=J!EFGrQj9cx@}9qF=T!eV&yrhqe%N)^@1*SVoG|nbo~3{1^B_IT_n)EOFgkX{ zM?C-RGbz>YUP|%cK^Qw65tbDwS*)p8mP?t9csWMA^z=zGe4a#@O8Q@sDLD>?i<%Lp z${y$D3xWjL9{%4yymkz0u=M&pZmvhBSBR0dNOLdZsu}Kei5&25qT-65Ka^1G7VQLB z2=NGF(UuxXl+gyBGA^=**3i(eaRR9^09+sq8yU;?nM&DX*)aH(-wxesPE!*E6nd z>WTT~sg|&~5qa}?EM=!Hj%fICPm(udE`2x!SNGZAVmnfwhe2P+M$x>dF>MFQxD@`pm2B^>`_d56g@5@{Ex(n7X z(!g0jJ*ZNJCItY`N)LBZ7@qh>lG9CR4W;akTmyf* z#@-A%Jr{{bA}{Rh@@NvM`apcRip3rM#t9$?(kE}ZJL%a2OjCE#wq)53f3uklmH%)7 z;fWOfWF(O+9=2{bg3!8zE*MP8%3|O#jZ9Qi$ljHoY~y<3#SOe4t=2Yi{S@!Nyn26z zXYIlLl#1^gvy%y0qe=}|xLGPIj;s~?>2+TDmu){lek*nSiI6N>dZD6#Qe~26UyLG2 ztNW)($1ES~aL$4u-E;N(jy5_JCZ~c6Hdrx{&mWZvlBk;;lCv(JEXSX8eT!3w>y|y0 zqJ_i+pv1-4-RZT}#nGk3r8T+eVW=zH`~CjHqUb(ZD?Q-9A-Z0%xve9tiyK?@Ru$|(d!Fh8aCS~6Y z_DO4JdIscyNODjM@E&GSaSX)*AuQ>rIGINRRAs)?2W9+;x`HWP`%b!jAdC}C za;WU9%{zLv?_ebcFqERgDIU{M-dqIYuCmgqf{y|{=qnx=)E4B-*7 z>W;dkgwz#ax}|sJU$uSy$9NXJ{TyY@X9nXSew*KG`RK2B7C%WiO}M-CGcJ=qol@|8 zic9^3(k1DvZewJVYyqo1T#GGvN8d_ zp!b~Xo~IoT6X4gJ!v^@)huc2-w8v~@1N<2EpQO1C`1A*DfS;wFWWnUYsh^m6poZgE zfcE^%dlFN$77DAI_AtIull{j%y1ZZ^cc)io=Q#sxCbz-Wc<%F`Tdl_P&aoPu&iDUy z+xCCH_4p0y@4kTbc--H#*F(}P|1(#U!ZBTGI)Ip9E~g#J=9Q>z&LS$|;6XHwi!{Pt zw1eevYv@G!Tn@;>Z zvrwceOC|p9r@rvB_-(bK#W>gNJi_nttL}4~yN5F3YrOLBT-GV=8uJyYm*lt;7r}N& zJ^9dcwR|kON}bM8eiuE_Jl%Y()odnu7r&cdHqJD7`xA09+6V55_V|$t_h^14-h|(E zMkD>!h0^-)IuFM0z{R?p!r_0Dl44oVNMhg)dgcnNJ8L=Fqn}6UNAb^xIc0Un*@hOy z&z+rr@APi0`N_iUUF0+0R6$C$=~G{F!k9^K9e84T-bb>?%4=1eWJ;mj ztWUDu6xack@`3oRcQ@ZxPVEm-${sgn=OS##D~JNHTk-i-9d*~0fo7n<0ZfprB4?XP zTJSyXulxtM9}docdZo%XU9CW$`d8a`%Z?enmle%D;n>nJ|<0O0E>Vps`tQY4$b(v=f)>KjqifPA)^Y{CVn5AskvI+kO?VNR5sue zeH37|TAm$ok@+o8d3&_T*)(hglw#Jh8e(kj4shL6Nl@7?K4>zcd&36C;<{vH^Hnv! z7FL!3Th%fwbWJ6nm&~Byhd607aXBLrWX^C}QHNnfza*FtdXkZ5f|E={ZAXi!);l!v z3OMTSOxXGgwbORe>Lf0&aN*f^w9_PXT~(||CY1J5`sY1br_*woQjtU9v!mVd`8D!i z3Q7Gvwx&lsW;NxJL7DE`_+2sBe@MBL@+<$TEz{k|v*0b;r;PV1-iwCZN2wU^-=n;Y z@*zsm)%)0XD7Md+f?fzdeXgq1PXqozlV>onaOS z&b_AKh%l6ONOy5xfURYWvlaS;Fllf%tR<5z?R4mg1N-J;R)aE%?ucdm%jC)6pLuo_ zErp%Zq%H1E^RpQ3uMk#BN)oS_Bx4HQ_Ec<-{+TU@(U6i?vJF;ta;$)rr9F^Kz;Yiz zg)oja`NUCSBU?DjtGnps7HFK%=_gD*9aJ0cGL#~zeAGag9ZN1oee$316CWWbC}b31 ziSMM>6c=a^vjz_B(2fptDX6g9_bSH))^eL!o~gseC!Eg5t~iy8FarxngHSKB8ca#! zBW42yw)-pvFmg$NjfH(#XY6mU07qsBgk3?5LUa*v^|^FMSg!fSlk#1egMfqW*B+`} z^1R)uYgJkD+A*&su2$F?G@mSnA@5&KYt{{qjotsj*_xHP*Wfhqh`DpDf`Z-cY#XPq z&H5qwD0VPEcVbpRYm}{`R7{}I1r*o;dNXkLddMTkydjSh_=&j~UOXHYoU_^5y-nN$ zay{lUd7U8fLaKLG|JiK`@1v}3*^m9K`%oq*#czI)Qt=1LR|fggPx8BL5?}N=_a`2v zl&-Nrd4%%4l#`TK{)_vX4^q}K)vx7Qw)5;i`PT37UOw#)Mg7P9tB>a>rR=$Hqm=LE zLCWV*e%b%=d8Do4CY}%T{=ZO)|9yl~vT5Ea`WUisi(fvMQvDR}eM8W3 z^{2u%Qm5zGHf9cqUb@@7FGv2Y-L)a-zOdF1?hET^Lw<7U7jJ6$+W-INFYELozAxMM z>nMd&NekY`v-s1~zQk$8Dy4k-`FrB{+j%eB*hYNlSNUBw^7HYd$3AA0@x?*DlzLh6 zrOnh+f3KoEKsl(Vt)3E zr4WC;Y*BI3E==_YF4<(drocBG)xx!i;sBijzickGOnQT;in|nLEjDz z$mXKoar#x93HHvi=w{F{BOs(TVwg%-4ck|zVWrj)jb&2*^g8#_pJ3G1tC7F`=9A)P zSCA}Jz>>4B3stkXX|Q^P{$jmYCAX;t8L1tGrDtu9R#dlRYTfofev`$qjBPwU0x*Wp zu9;P*^9K4+ytN=s%1F*Uc#G*ACW7QHvKIP#fOa~&#!=h36GZZw2`7QNS!ihh+SMTg zu?^;n^=Qc9@dV#D8;|bM7LeKHRx%`$`($}G@&{r!!gk)LzU-d|Q~GZ9QR=Pp3d^Dp zc})=&H7JyCWJt~o&|Wk}`#Qq`9Q}q*%rFlmXcolZ^d6x8h}W;+`~HDPYQc6m>mW9ryZD-|f0`yA4@BZ*y{O!S~}7^{+Z_|Mjk}pwuHcdh^ab zw0HaUhTmd*zG^xN_8|4O4q03KwIAKmzrZ3#RsI#kY9!Pk`JHxo4Cxl`fHvPFf(eqi zosrV&bNBKhMl3TX3wrRTK#pX75Q5>#)+P!ba4*T$lXCq^I?YRG5jnx7zbtXWwk>tR zECs=+e@mcIM1AW%go|m<(I@f4Vx?rmwj>XxWg2`(7)@F%%J+jHFo`+c9qE_fzWB>F z*?j`Z$G(SW>1Us!yoEC2!z<+k5`p#}lL;?oej{Uo_8&OhJ$UQk$u6dm?ykMv-D5Z3 zymwFc&@J6QlRwq(9y~O$w>x>@;NHXC$^B!zj{c^yr#`Uo$|t(6m1Fxho<&DX%(_-6 z{l(d^5#r)H=!`_{bsna@@T;+1Handwzi!t=?C9IBYYy=he}-H+(6qrlH;KDZ_kCXh z5CKjOu#!yKxC9q7zL=eWM!I&@EG9{^%;pdxUFoN@?aMdW*??T1gFI{RekjUgB#2lU zD<5X#iYYJs5k`#|UC<9egj2G14mWogy7pC_ zT740HbPBHi8b@wo+t9mp9$%E!tcF34MlN%D)Ed`D<3S?Pbk)E3y5YA?x7RsEKRRz$ zZHcOKPL;F6<{$JA-bX$2zcyRv^{7|?o~jR0Px|J%{-_t9l*LTovKIS=ID z=Y^$YnDT?jyPI>@)5l05^+*bFCA+mS@EfzL!!lA&IAZALVhH|H6Ce z@A*D;h+Ugp9xM7hS%BoHGwKd`kZa4fAjV=GCasCQmukv7dY;n0oto!} zgn!DS;@kU5b~;ctLJCY^E187pF&f69w5%p!O|(jkJge9O*&U#q+ zcnQsJjD)Inbb}8QIB8qqt)WYD4TrC!?mcn9qRadTGBU^!x7(AwLKJjq@w}7g zhbb+lb0E%f6-jZ(NSdc1a@-^IrK@&QNOaljfB>+=j!RfpnYh8GqLrt+WVYLcDRg zazNqprvxd443$B|i9!I$??TsV4js%sSi|q6kyMwS7kInRhhw@ z;FkbdmK%#uDi+xQ*2e!Hqk?f`e>C#fe7+zLXBz#M9E2Rk2VH}opK3t-jy#+&kSoOt0{h= zo=alVx~YtIFN&fM7u-w{3=?atQVMa`Ndz3L1wO4!Zi=l6Gg(1dkBuf>C*}yz@m-4xk*>BR2M|iLM?k;=UCd(gq8>QsCl(*i(^M%m+F-yfd-QDcVwOI&N zK(@uXTS%oaq!x2Mn}V@W&hQ|>q4$MK5oKuJ^H9l1kS@I=ApF8q5Zd5RJia!&9L*Ad z8~w+BcT_v4T2t`drb~#-Fka@%P+&~zTwb*Ga ziIt8NQOSlOVjRFfMAZ5GWt>zwQb$TjX#fx~hImjX=ye^VOHt`a3`Q%{L7$oHv3-Nt+2^mkAS_w)CU@+`Swbn~XpCDr@H`RDOoF+D4k z@_GI|rTj~ss~q>YQ|kR|DTm?ykMe$m-&5Xj+}AxZ0*Yg2ji8Hk7M7VvE$*m@bb%?q z8qy@|5?YeGw?>Z{P7dkzo{PbK4P$Bmk2lx7Zni;|!LhIF5P0*z&^9AjD1u%b$s}5= zc*ZuX!O}}@Q!=P9$R+Om8NQw$qHN_A;<=7L$$h=*nXW^RQ)(Y_UvvMyoA+1pe(?Nn z(%>fJSXpDCM`j;wl)Xv-{=%titl4ITbqj-*U_bFqty>bvLHO8CJ#be?2KtSZ zBxyyyH+zs*sOzl44JFO=HXk5G#D=lEe{B<-TVRi^pH$`NfiNZPVMe)=j z=7Wo6iecq7Dh1Lv##xa9yV+CB@aUFdHa@W=+4%O4xJ}_rlr=y4uRM!Se2P-GxrE!a zC2ZNUsZ-}4N_d{({qCxM!tsyszRUaHq`ZalN!PglZ_u`|hxawyikb(tF~v2vhJ7&U zKDa(aTZXs=ryKPDglD^~d~59!lH4k?q<|6p5XH98azxN`e1vW~JLyNZ6wyoe!sphks%h<+ry z4=zf|G2*-gMvKt~X7F+Tx?4S-g73>~QW-pDrz~|-?-bQQfwRB}riH29GvIcP(vSRI z>jQuy_D2mDy1KE(zWY|{U&X)nxt-7z@wEC?YL?wJgZx{R=@o0K&DUk}Pil}+faw0{o&8oC~h@=nN3%H`Iq^APQ%0}gGsZs{R@;=&-1PS~i2D|;Ew zGj!a!pzFq-C~=hb@`H^vpppV#VWZ(;0@DP3wLB(P8rYmj=5Eo>J@hMnIi%kU=){B& zLl6f~;sNMS^y>@luZAoJ?;&iAdFQn*hY#t$tV24pP1+R~vWzD_;kVLW`+svKRyMQP zSP&Upy@%*$=kR%!aa8bY%&;0pXJnh>m3Aqw#EWm_<2bP}Ou;S>;FRFn$&rmK%uLxvD5_YwwOhebW%WF>GN*{_1mECctl7G9 zBzlICw;fqB+wVE1V-rNQ_Q&lSj_LW`O6A45k-kU$<-YV)_hnqmI6Jg*wq6<1lJ$Qb z>nQmB9m<<2zv4QN6-~aGd~lTaI&1f}lv^q9pcEZXInA@z!UZi^pm_^i*mk9W=_4S>uUQI!rFn}Vlrc-^zR>$$ zp8uRpoFpM;fKohfp7P1noO3E9FdPq&5U*)!@i#Pu8mWFGvDFrB&z_H1B;-)@I3_` zaTl}i>yD<}5AQa}dgrzD^ELEi-yQs55De7v&i&NWnbcc|Ld=<|kB51$Ge<+)=O<}@ z$@9GZ;h;xGOF8E-w{lA9*-a>btO!mbub&Av(uD{`(N$6|%yD}F3}2o247Sm)^tK$6 zAICnXgtV);8FVfiiOp7S%BE+uNZqQ_ygSV^DNMQbKOP{@r}lG_Z(%0hub}8G%#0k_ z%3-%W*M4Bejx*w7n9o@3DzV0nQ;@b}(hQlN>_#%u z%N>}(Hw)j_CCPH5ETav|c-!YjsZ&@OKkslKN#1q>L;@na0;s?&^=&@6c*0gaqC5QP z)bOucaQ2zS&sXi|6 zphhGkjhV8+(tG`|=JKrgrv;G$T-<1mXPM(OYbSImCPB^fXCsvd-e~M8+DGpnHN&Ie z4K27CnrKv3nEiw75n@=PqFD}~sXB;I5XIec9*x43Bi9tAkd#mZPq?fY*Cpci>@G>Z z&`c+1(|eiDw=QtfMGA#HaZ;>jmzNipiPQ&#nkId&EMv2x;fd?1%R4la!N`J6^b{^Tm|8f4g{=44BW~ z%CqvC{yC-m-~si`$j98-2K2JFW@cbm1jN?Rs*(Duyy=>$^g5@%#`!q#u8EhkLwN$> zK7M}^-yB;oEX)P+oQMTt%f4%M{YbUVKwXEze`_i?50{*!Evu0c)4^_tNbi zcWD8Y5HY3cTVCLdw;KJVNG~&AVI5Wk$^@An#)CMsrt}v8XD&flk5^@} zQb?;Gbpu@Ostx_RQkp5K9-;$kH|>Yovdy_eABK#n0r&St<3r7D6s_TgITPCM(d(Lm zNVlkAR_wiOR&*Tc<A!= zc$U9++$21KBx)x&smeej8zHI}1BTUFH2OuX$zi*IbjrxAu~Co)dM+R|Lgez97Q-YW zRS6MIHqwNUjnXIN@4%x2sT!Hy7pvdg2$-7UNWwohCZePX!{{GGpgO&FdXMXpWcZE5 zkFglsrCx2((w08!^f}h6Uf-*BIBcDw?DBiA^BZ^;4E}Qbp6?(1wVNytNhm-F+~(xS`Y%Uz%Z23m5T4+9jR>TY8tNO&T(P zcGSNLFrA)$6`Jbm+0o<=YSb4|`4%e_I*2oX>kVpE3oTXjrMIs@HXNZy%dJN#>|K&O`WWdY5soIjOQi25^fC zZH}P#q?&dW7oP{r7y(Sd?7*^L!1+Y!gi;z@ZZ!+Ippbf9WCuPF`eMu$vV)zS%_jcsQ;H%*5xI4XH9BVXkvK6gfB6F^UlQfE{W9gYrjDYIrF|h1kFi zC{>cQ#1wd?qE=dnLiTQK#sPcJ-sy7C>nLj){mVQ{#z;K)Yo2BM?~S>S>YFJg2md!p z$y@(QDcYU&x9-|xIr8%PMxKR76Oo5Zi;WeXRj-*Wr*gKB8j@51DV^3SGMraHxvmDQ zvAAH$#L%Cc6~>mv?e7+buJ6GW7ndxpM^IRyCblq6{M{h5=vs5oLY2X( zMg|gysB-j%rloIGjq(?82iZ|tGzT!OQm@yerE4`dFy@tZLmeE^v3kJ;;SJI$&j?su zj9={b{Vwi4y_#9oPQNdh|I{hD-v%>%C&(xfhLzshJq73^#HUBDP?BcB_#7J|Bo6hN znG%-1!o4si6~ttRETbJ(^F_{u%?az|5ekrlfC(ne@>R_&a@`NCB%5yPIW0qDW&HKJ zS)+_IESCW2XmJcx4Wu(Q`=ciKmd(?z)g!^-BDprNQBD2EGGC)ydZM7(Sq0+gy=$T# zs{?5WB`h+h**KEOs8vvXV9gTY7>M|#0;(!G!OZh?ubeULJc}N`fF)Z7=%-1BzA990 ziH{jeZ7XR5)+y0o?QX!CwxzGm
Hz|*xcAeMXZU7Q~HVn&;!eBMamm#EgR~uzYqS46yw6MX>zwu;!kF<%5q4_tiPS=aq`zYh{2E za04f+we#5q9vg`PU6#(eQk{v;I+*F@E)wRHL9kjRoM0{a0_+5%MI| zTuitu7n!r=HwXo~l~FYy6zFx8P}mrR0(|uc#9T|EfKaLlg_A9p3MMeb7+fAqWDf-f z4SIdV*$1U3voiF3KVe!Le{>HxLod6p z^hV9Cp>|X8)b3i3o|mXPjF`TzX!N?x1I+_bZ;OA$&u%lvjm_}8(;rl!^yYV`Hy+Zz zH-}$09m?3`K*-Yyr_-6KjCc}J)f1oi4SnFhm-+WcRFuooK<3ixu$;%rvWX)|^wi_G zBUDLBVp4)fMRBm*=Hn6|Z|(U_Z6Y6vcky)=J*?%oH?JL^m#AT0(+F`cS{6 zv9}IUaGn7Yt@B~NB8cki0(R7jdq=*uaOcL_ow@XNq4lPS%?{6>tJy}B@KAXUfL)*< zXeX^MSIIou5U6=q<2v=1XQ%IC|Iy;-zWk!Q?$pJhU;eYkU3bnef9l9R$(=6BarGZg z2}${|R}BN?{Gc|BfGOGRD0%7YBp|O!Z{kxYAx#toAaF?C^S@i~vGVr>5hE78V^MjS z;wjZx0NPKqda&nxjax&FpRkdO^dEYDQXNp}R|_6b=+a2RMz5!}(Tj)}mn(Le>hc-8 z)M95Y%QE#o^q)SVmmlTY@=DJB7`5l*k}V#6k~{2i=YLBRho}y$Mjlr~k#@e-au#z4!b2BL(c`tiz2@s?&?T^h;^j>7k`%5FZ5uPBw(GSam z$64%8Wzjjna>$GLPuu zjbxc^e2tWE`^QvfuMI-*fDa_II5Sb30mo)7hiKQcYM8goFF3&s$mkrp5s@Af1m$^rG2rcOTVUBVQSbKthllv`pjRXZuLYb zJYnBa!)RzIJB^0q7QG^-7@x3L)DWMrSJW^O`Y2zCPuS7$dLj!?*lDF|NJ4`h%&3NT zXs{gsYG{Q9%eq%XP$-pW?*nUwC-99&%TsbyeD1uKr%Mc%8qo%org4rn*B-V(&!vPl zSQU%S()ox}A8JAY6PF&5ATXbw79m$(GZ_?xKrxP_Mu-S*) zH>?s~6o8S(MLKVvH`4>n19{r#$OKd}iqUb8{VZev*@Wr2osZ&*?grK75w?u-zb19; zl{ac$-)=F@b7OSSjy`JDN(<2)Q?$m{S#X|agrR@3<(JZh0^+3AkQ0HsCDF#9R+;z4 z;Bi8)ncDKJL_mzcg&pB1>lt-VJV!>|e4_J?5HMPkI_izQae<=El_#4DD7LXzkzQn? z?n-1|1U(3Yb&Bxhf_iw@l?HmPhj)F=)3`=>mk`Hjk#lg!c?b-KI6z>}mQkbCgjH6_ zFrtE1Y<@23$D@OdR(G+93oarzM5>S!jP9I~>H5w#2-HgE5!shEXz>jFMMITK-)CW= zsiEIzDDEd0>)Mf(MdRqb)F_)zpBJ+yw&FCA`BJ;yb zq5%V~Tvv=)$PW7qVv8wSuehKTEs=3OA?z@x)~vC!`zK1Zz#eXh0dgooBQT-W`Bcik z_I#=iS7s#l^ooaf#3JEzvX)=?e5zDB9t;obrP&*+FVb$*HY6(n zN<21pW803)2f+BlBes?g!wXjli^EtTTFXaTm9Q{d0+^HbBMNto-~1h92bC>a0%#&= z!&RdYWunFdr8appWh}Jpq)rENqZff?$Z;TiSsNz!MaC7OsHuF+5 zH#ekMiO3(d$}Vj{)%duB-K1;?4Rw{jhF|eK^RLRJs{vXOb-0W_Ecs`)xdp{ha13xwb?2jTCuj; zq1=$6SA1H$yT1JYgod=}57rL2kM9Mx&e5Zh?^}$Ud6v6b(Z<55hydy6xb{K~G6G-0 zFDx4fNoOWAq?-nrA?;z=0$>P_I%{7{*JSPYaOj9zd=+bF7RyOZmOPH(+CZ|1UrXMt zx7DDg1z)7rGpO^(f-+82S9{cG&eFQtqekTPT_z_#rC^ zb~T*A=F$8pA)riC%%pyZn-a%owq{4Ij^oPdtcqb;5Uu;djD2 z&YR2Lh~Y-Uu`gk{|yW1425$>qu2-v%y}aC=MCntyNT>I z7iGi29C5mJIDXA?~th^dzPB+dO5bAeon} zP=rQ&{un85QcejskVS+5KIB{En~Hlv7fR-(2SLE_nf>LP@t?8Iem`KQisj?bef)`&T9)wYt%M^aR8%%x;+k?-g(C4_u~qcM5$t$9+u!2;hEOp}%-}G>ujYm#eKEyR(&qo8#t68dy-%Cg zEyI(PMu@psL1Zjhp_s996Fu2~{j~Uh1`g`7?p^rml|g=V6P{tI0Nn9$z-T_JD%0dl zCbG!{u$z=F*(e_R-0v?odTD{H#6ySbZjdFWt8$qbI-fMb=3nPbh*~yN{6753#~HX` zai4!opTE*_cVT*5@1M!b9X#M9d==^a~EzAwUC zfqNJ;sH;Y{(CAZori`RES8hDXPvjmWZANmBkv1ba2JszvMYvTMWHKd0o8vmPdQf(3aSJx&lfx)G(qikd9 z6@RRro)(!6#iZ9uaKI+hox77SBBt@p8Kt#W?{U~8fs?9+pWRZ34_D0W!A`B zDIQ=u45PWvhqN7)eSucJdeCb?YxElEf#@}`GwYMc5~^x*u>iY3{8q|A1P~6dZ^voB zRV;n}an|TYU-+!q5RxZ$47jS&LILYRsN2MBF3hU%c~{dc95OXPIP7YmdUzO^zd}P= z^aqWxXIrHOc9u&!r=IZfiyMa%Ko(A@kJMV(V`qtvsw_C*8uX~VumEQ2S1=NzHz@>T zMu(m?S5g*jw%=LstM7M~ZyVgOSB`vY6e%c?NN1djpEPXkEIhAKsE2IXIw~CcCBm@C zNg^msWh=xn5-?;HIBFg(tG=PmN(?%um|r3&x)?krK=}t5&!=c1PWoCA?^Wq5P<_Hf z>G#qEMp)doMpez1OYDbUEAkNiZY*TaygP6Kv`bElrBbopnoGY|Iw*e+3^)>e4+L?< zNa^bfsHFJqFNk_aOR?p!F<;V(iKxB-FDlJZNEox!v$=#pcE2gJYkemf5`k>q70`zJ zv#z{o2M7;L1)!URkBRKlTo_s(MfZ>i-JILKz znL!XOk=v^Wnd|%$9cYjPZ^5^3V%Ufy9BF%-ClWk)6x4TNppo+h>zQbc&x|(?3z?DJ z$VHiOjo(f&T?%jM=+)LaHR)`j(~++4zZ z99yU(MQ(~;;jem(XCC{nL46|`(l^!_xheFHZ989F67>4 z04ky!AjktXdi(@AR0Cci*;_^slETYl3%kV}8r2c&bg9y^f2}sUQ%_OO;j`ONU&VUMFuo&{OD% zB)r29c!pUA1YC0qhZsLrXKVuj+lfMSEGv`R^y{-gxn z#>gD(Bn{ZmB)q7f4Yb08CiTLm*qTq;)zOyYkoDKMvmuyE-kV}zqgNy!P5PU4)HW+Z zX>FP-H_)=Zx`%)TeJvCxBm&$YqT}^6T+Sl_2+{@Fc3#~5F9>w=laoYAE1<}3l27T! z6z^}=!6_O!Y6j&obTo+&s3}$x<2UoFro?Y%G&~uVWir+R{-L_;_hLB+9qPx?5u9Nl zaKBa(p7#a$E&8#A+*dJ$7x1gyd;RkCeH8O zu8UGR8z_54AG^!6-9ZFc(PcQb^8{;CPjD0q+Qs)3$?baenEkS2SDFRcN#1$(U&z=B zdc%_hymTl{q~y)u)|QS9!=E(L26rHz&-sC{1}BDLk&V+FOKYe75!Ga;TaZ%bO{11z zt;J!>Ht(tpBtSX#&i?cOESqVcP`a@WKgUE&uIG5${dXyamE&zu>{&v^-LK$^qi+qH zc5W2Ow2n+a@jj^DmcPcSW>+`!e6s}hehKBxtRweJZZ>IUm#|LZw*nM-wQWGHOrqHBqj3caBV&>j|SXpl=;uNY-U zgGGbi#E5Hk}1M3o1+%6uRjI8=oF6wQ|E6DAGgBlGD+OI-b-F zPoap!I;bMvg)6sQOucd~kxXMG@i^>VVslx9>sYLsoVBRoEA zpsNV)$(FbVGkBa-T-i~Z^ET<91qUqB|6aDE3P?)5>}`Ra@n_l(cjNduAzAacN2KEA zTlKJ1zO#+! zg4`$wz!#Ouoq7wsz`)`<35?H|Pc!FnN!h>=P0EHCh8B)Q{tYapkk)3ImaHfP(dNn! zWd)Qfmxv4^l(J>j8i4>m2C8+IkmF9{f+{abg;*R3x_0--cQr>*uiJMA1$$*Z&#*7r z_;0Cjw^6t`VaRlDS5t%uiakNH(z)&QN+>cZwzv|*l{+bw%;ru?<@LCeQmpZqxoOVC znrO6~X^4N&KJ1;md6jqaO(rv=y}FD=2Ck^ry|#BUI4vvht+^7hcSU@n-scphyQG~ zGj*FTX{3+Iuc@^TpAk2Zi2R}ev9Ix6W`fBz^gmsjybf-kUfJug`XCRZs#s%9u6f!x z*dFE{C`{Pb1kB(0H1KhUr>$y&epe)~>$k5>n2{}Z_iyIy(&1UH{*K!ns=*hRwLz;| z*2K0_DY-)aHHLhV#+7y@?*Pm;Tx4H#raop3H4ov(tfA&Zl*_O!K7gv$0Ql@D)76I)D*tE;nVhLo zHvuZkSWQ^k!!_Ey!O~asKwR15>l8?i>8wKRhuxVPh;P6cMHysvHDfeT;TjbRj2yG8 z((9c1zL!5pF<3{w(P zr`$FQPDToX^&d?DVNAxn?*bEOkn>SJ3-AX%Yw}mP#K$As(dIhPjWiYDL?{4-B7^{&DIYXP=ED*2t2$XUHRx4$t9H#dq6-@1l^EbfD!~9A92uY*0Js z18y$}FU6n#^e1TBT($)sVe2`tHB*GJMjey2M#M%bT@`JfX{V!ZK_ff9AAtT^T$4K$K9MG=elggj|2{YbUb3mxWDNZ+0c9pMgHmE z#d`$N(IU%w+~Bnr>`HLTCkZ(sn^Sv*&O7Ep(rU3jShP6>h?i$@3i;Te@_V85RAr(2x|`Z|VOs0ZL^YJV8bwVOR4 z1QhV3h}i=Pb;a-O=j_Ns8jOGFFm6>Tx;4sTQy7ImQ-X{&fr94EQe%V<=@j-3fYG678aBnf?WfH;$SXH+iWo7FvN)Q&nHTk8rJ^0aG<* zvSeOVPV2U9lzR~kQUY`UJKYOJrPR?;?V+s{O*+&)v{mv8XFC%?>C@0y2E7*8Bffty zPrW2OgF@h@)u3vFA)jTO;_{Ghxn~&#Qe=z{vLtB{QK_yg?qGaH(_%HI*{{48YS6PJ zIVHf<5;AndC?^oIJU>3iIcZmJE{P(mZ0n zlnmpk5Vrc~KEwM=j?{U&&%qwloB#Z(2J~has;wm1Z#DJZCa4+JCMcZR1bwFE#2wdk zsdlp<9UyAQD^&)Q?tO}uzuF<7Nc<5&ztwarSf8mNrCPY zEi*V}*q9VPc5ym{34(ThCm!iLmY^;fOSm~t z2C+7-I{=RNXt8n#sk$Q~%fqlff7p6LoQ!6FBN0ABq`-VuGXSui{iH%Z$ieK_M7VPI zbaZM0-O9}K-7(BT1HtUF!?GgT2>Rb3lT0guPksaRa+zf4Z8pbmCj*93gcohQCc_4d z>KS?gKD4K%*^FuSSMRZfY%5X>(AnB`{k97to^vLQY>EP>7B_H4+?PCe=G@m&T9r7$ z`92ozaVfWUbq~(0=y+h#*}y#o_rg6c<=?gU)(}DFvoX=q-#n*a_50x<5}iGjXHdy8 zy-5HqTuqvfU2Pd5Ilnta@XfCXuFTPc2`E$PqJk~)?6LvAn!c2{l!S(@9Dd_1UQfCE zRarDll`>;Cb|}fD-oiFZ|v+ z?;VfTzeVY2BFKCXVmqYe%4H<`8oy`?^S;I}n8GaHh~%(wKZG1;nmEAc7!F@4(GhSj zkGd0s?wH=CJ0h0y4gpZ35#3;cmjOk27>|RIIN%bOg82!dinJ7zE(sZW&yKlXRs5FJ zYxUlM42s|2mwn5AeS}{&CVrt0muA<2s~ZogM_e-NC|FJh!=$QNW#^$*r^-4_Vq;5n zGx1sK2}RDg^=wpAN{8xzL@#1MO`=}Z9J;O z&iHqUCC$wUr;`J_^I8f8Q<41R3kyGcvQ-y(y3 zF1_k;}e@R0aP05IHWEmnLM(9nAxM8-O!$n*5g>-9Hq(()hY>p-=2M24<0{ z^E#)c(t-Ia8n3&s6w1;eZe4resTQ5`ctD8|?;RlS;v;PbDaD<7C8DZPLd`L*1xP#j zxJAu)Q0d%~o+~l?sr#F)X6x?ct|Ufe&NdJB)7_T-1V=&9LaVfG$Sv{Y6un2P)`&z# z(G!m-eW9tg9$VdK_h+Ztb}VB=MA*>tY(G@ID*hIuA-m68H`wp?HzW*no>p&GN#u{I}zL20U|#oi&9 zd?$2O3}gYP#WPL#goY?dh{f%fB0u08l7Lfi7(Bx$x@Vg1?}-V()dZzj(R$$-*5`wg z2;IV<^XJPgXV_<(F{1aCmyL{&G&ev)r^eSzn{xuXuz#cWhmY1Ger?E>w4o5!an&Es zum9)jKMr4MGBM1jK#hm_FeZI3LUkf~;J-lrKC@$Z@8Zub=DgKflqOHrNu)P}@_lKa zc-&3sZ&;4B$UZaiaa0UQ88?-5J(@}nolBQe_iaau^gi2UROY~^O6-H(Hn619$+0xC z|D{keV+kP-dN+kcOhST4zb68jHH#1OZT40!u#D|?o?g))<@`0=B%EGEh}P1r!Lf!8dH zQ@rl0wrZ5Dq)@$SpSl)KPHGCEk$=@yo;@a4Jd#aGqOgdbr7H1zJUyV%P}|?!vEH{O z)k{;Nq)plbHB^%eX9FB+_Kchkvs4g~*)NNxWT`ksJp}0A}m#tLy+EAEa(S9uDDTz`US#V%pgsI|!ko1WF0!0H@G6cpOf1GLQL|X8$pK z<*()vo$LnAh(8bS`w(9+`TA|a_^c3^7Ot&qr{1_yjl^taI}s1G8=0vcii&m->le&5 z4o0XpZzcZ-vK2aSzKWF&g3w7$=r26S(Utv5;4dIE@1P%Mzp94ntX7u547g|ASu$uP zfiRIr!r85|lCiPUcZrd}Q0~(w_^Yq0mgbR)uvr?}Pv65AN?Fh7j;51oLgKxX^@m`7 z$~oc2eJ~*us8gf2^hTNo(DnQvJDonL?B|i<_#KQwDN%ZQi9>+!Od<(*K^N9Ta56#o zBiWzn%hJ0?vK3v1FJd8EM2}+YM#jE=5r8Igw4zw5>7&fTk61COFCPVzoIMf%C^Q;c zoV+7i^!5oBI=}2VF^v7lo+WY-Vv#)0O1+ym(zHSuN5_31MLGi58G^w>wGP3T~ky%0Tit2K6#R zZw^5Ig^;r^df3re2pzyUOnq8Tvj6ON_BEbJEe)Bwk6KWtRHCTw#%VC{LP1!aeN+(M zfVpVDe$6qY(MW9&g-ZMxll=>egSSc^E-Ye(|NhU4wQnD2hTz3A9ldxKYwn?dV3!mo z*Rm7#QAxQqsma|A`daRNW}p61#?19xO#;pJJKwiKu16lk>|^GamqXGx80nx8l4r3t zE=iR^1vN?)_4Ob|i2fobI@N+_?e&oX9fFVPOSRF05cXAQd?>x*0V9Rg#TyYc*{!9L z1MJb{md396OrXd4FP0B0%W~KTI0EhB6zg#Y4M`j!Z7MFkt`_`lB?%vXKEtud)V1iK*t%?b@hM8bT!Jms{f>;b}{^G5R z6 zXPNecLFqf^Uozlo!L5Sg@?0C|RqNA?Pm=(t+$o7jbOi;g&V(&1rT7?&HbJ9|mRa$z zHI&YUX7OQbD7_EO;(lu=-4lGw92f7a^KVw8{0e5C$`pfn4|)r{!N^C9J(^-TB4q6` z+%gk!$i^iToFeD}mmd=Y6J5%!;>$1yFo`)FRU#D|uMJVZd^*+W!-Q+|bCA>^@Ypbn zK2AeA=wN9UGFjm_`i9DwMT3>BH(C2^G?$~m*-zA(xcvY#ZV=$GyxE*~eKEla|xGQGS$-Mf3LJ zj)kK62B{aLc}MVQ5^6CMKDTs{kY<&)*(u~%dnmSS@#KxZlq+;VnlTDDY7+~a0dHT} zo8s|d@87&?t8cs~Zz<4wsHZaYszocG54CFD($fqFE$v}|Oyp}%A22a}d5wNk(`V5B z!Q`GBm|C^jTQ;h>n|LAn_W>LJvhWk#l=}lP3E7W@3W0=+`9{z#wT?_nG{d%3G=od) zQYoAP8y|c#!^um9Li9SIR2&V}|14wj{juhsRm_V*>~eOp6mNXt**%9!*xYSNo*FsClBeq#{c3mH5B|;Uz@x_E9^!A$E%p~ z{bun57#ZFL_lo|=waImWy~;BfSz{C2m=;h8_7Xs@7TGbqS{9SDNrsaDTD(9Qpo9H%n{1+g!m7LGkeB~UB zUN4ugh~r-U#YogaFq$a;LSxyovjxSr#PV^B*KR%*Z$4o+<>@nTE}ru2<9-i2+k+#j zNGcb4_6gnS^8xLA8}YabA(G(S2oFWxQ*!cEAri`6x$jcyam|N393uIWcq*3nnFK!( zz3cH-U<>r`9{PN<$o7skx-&(5ck$#6$!Boh!Ef! zUQk%nunRQurzoYK!v$JWIO||laHQrJq}W&K7aR_bv@AGM_Y0mkIC4I};KW7y1*M}x z?-vmq(HkNS4~~cuJvai|YQYgBNKt6hDU`?du^bd+4Ew4cgvcxxXO+~dNsZt@0t*)< zHEyU$jXxTe8aA}gi|F<>zH9;&26F`o3fCqpOl~i+2bUbm&a;)U!aRm0$4Vm6ar5&M z9a^-f#us+WbxJv`wRMSDgX6);k>u_+JNOfFesWoTwNmPr}#P%PF+de-DFo3q#%5uHWmFCw<{%JkJ*)W zV9zWNr0)^^Fz*Wo(3zi=oM=+NdRyWW(O)$+`qPMl&H3iw-mGPw(KM#^K`*H{*kaNH z(M!5nma4@}2Q$yg8Vg%wG~ih0@FuTB*;HXe9FxDfEKN=`gwg;=2#(@yjZacIr z-+%alhvxq-xo3X=TlgjQ`S1SjpWSl^jeFDlHM)1rTbTA{&PEG8ZuTBGmp#HWfrbrG zX)!=Rlc&kT{)6+Rm4?VP%6T?5&*^-+){S=(0l{bv^)?k$eo?@*Rp_*a=AdKN$~4-Y z;y23#qv=96tls!p-oT=jS04ygt(Q&Wx%G*EgODi=;=y z9rUDB`GHxsijz&in%!gjCm6`dCW)R*WG+3`>@(h{^ouodn!m*g&r)3}`#J4CwFSg; zD?DdAV7rEITXeR{c!8`&=%mklrEdWx4&AyceO7&Hy>Rjf-Jz{eCCCY-rHsPt&uw=r zeRBYe73pg2<&2fyh_JvP_@)>=VDQw}d@@ozq*C)@v1qc=XA?du&mZ0}W^YUcIw1NsEPlvg{*2YEZDO zOWDi16Ba=?-=dbd_CYx}pJ2hW*uo=*g{B>I*#&&yMRO{?@H3AuQah>G%<=(0BM-p( z95mA?i*|sm(iuX@Ft&pnW+wkL9XuIc+z2cu6u;~GhZKe3G2B9%LPs@h17857BUH-$ zfBf>}Y~nz9OAE(N%LK+;%KJ(y3#72j!d9_U)IWbW3u5`uKfP0Vd-Ok!EdmC-Uk7R}J*rF2A>m&DJ5ykw7Cke5nOc6o_P8RR9q2!g!q zaOLt+*00OU39ejTQX4hMOG=&udAX4*mzPx3rXRrNpG3AtxOT zNX)DzF{il~C1yt5!%|{Sd5=?Nk0|aj@F`R?Pfebti%ezRl5Yv%GK#TIA|M#ep$cF2PJ06xZ_SuuxtquvsrwFH;DC{a8hYLNz7*P=d`vYF)880B~IU=2R>gt z@E2TWo=*8yE;|x@SV3Hx@N5=e;?jgC<|C(Vq%J<2#ph@@;fcY=r3p`%`imQ%M%R$L z%)Xg@Px2@Fo!Q_%t4o9`LZw;!HE(HpwTYqZa27LKq9o@DNz5%SG1IC>%8Ah)r(b>( zs8G(B5So=VDTal-lG|y$9@RDwtx~1z` zeJZgNg9i5L7Orr$ggiY=0bOmQkpzyRLj|lyrS<&Adl842?jH#CIW!>i4Co#DoT}Tr zrznnmx>>Dn>BHOl>EuX5x%T)Cr<}iO#Edfe;j7XoDS3wj8y4;NVAnF$YxgB^)_f2D zjM2A0-15#Ww}M4Yy*pV2%M>24`DO2xbfqI}W8|zJgN?wj%((4w%`OiwSRPcIi_K)R zrFob?gW9J$vYbclis6SVv%Z*H>xXT0Q4+EKY>$BimDYb;s-@EnagyZ-6&FIJPo8ep zjJ!XMZb=D)aI*BuXcPu-{myg@vnd))>ynQ|36Z2N*dOml|RP}0o7qD>BRtvBaD z2ZHlTrm#BAq=b(JNxe*s7rC#co4g%k)JkysejN_yw1!$b#+$6c-GB`UHl&;U$WYEi z>QX_;Brj;T$&YN1)qjmh<;sQZw?m=ebMm}Wv<~%yKL@f;hISloJjjqE>1&@GEzGKH z!QDd(6OS!&Z2rjAO{&B1Yupht+Fv4ah$YQ{ud)Z((IF2J{&f+97VpXGa=EZA` zG;llI0kYaLAx1;1C&a9ve18)XVnEyF7|3E2)PN9%83lh&+i)TyRI@QmH3N~D$4s+v zIyDcn&DR2Z6Rb`lb50@qvkzD-#`@&^_T{uVad zF%%TyrPbvhNhSss@ODC*Ffd#leTw%SmtH;0H(l%Xl#*{zZmF_+H!)BA&e~6erxVsD z4Dc_sl6^c@Z@L534svDNtTpdzYMs%1ekcc`9PZL2g(Xa$)j<-(VW6pL7Tm2x@0 zdoC_PQI=NG2*bet>XwG&+Xw(0kbom~fhTN_1fJGFMzR-6((*^lSKvO)nk6c?fP4dk zmZ&$FC8`IaR%a&;Rfe9rF>|)uD1Z{+I)|`4oRKKM{BR7Fl~Xa=;ZV~ZrdNc;rzgXX zEv>u9VS)O4GLepeFUF#rvK+J`wQgacTFiIYwh+cci5)g#qU8cq7>HPYrHWP@$uA_OumG&!dr4XV|BA-(u?wpMAfX+tM;N4KIZ9=`*p>I~ zv);5i29LAx<8|Kq5uCO)GuH`GqRW)ULCpvCPwIy0jC!!9_-ygjmT9q_cae=~Va;a$ zWpG&qMF#)4Ru_GrH+iMLtWcq%jp(A#&VBrcl?4O_cNs(;{KBs+O#iU5_-K@0Lo&=) z(zm3%QUNhd(d^A{4`xj~;rTObI&r!0&Q=!Ua7|k=o#C3c&R|&NZu)B$Rc|F_K%Te@3m`gj?2_wo<SFHoY*7-g=V%G~Q$A?- zf&NIyy8zf^K$Z1uU)v)gNl^~fvsLyts*SqhcdTb?TL=Ld8m20}-XzPuL=WAekpN5g ziea0+RuwYg|3FSa2a0m%Xu1r7;j_E6Ud}eGl&YNVowaJVajU8W-P}R3AO(Xsg!&Tf zADKcSH5C2i{HhnO#6hF>j+#02H!)qr)-uVbq3}_dv*m-7YD0B^C@P0^{W~s3*Pkc) zCV!>Q8}PN!mpa0iE(>Z&sFNg><}#(5C~B5R%OPKtskkjh(t?}R6dGY`xvV;LTT&hl zy#HXovD@-Ue9$MCmlvxl2|D|^_=1&Wi%0o3qr&Y`2&^l(m(_S9s1UJ~5ZVS7XPqO;#&Ft~FnD;`=@a$JK?B*+hBpkcF zKy0`;zl>Ak%9JXPE4bbKyEL!mxIB*Yc5G6!xVN)V{MMWPV6pMg zycWyinC(5q`9k}@{W4myw;vxlla1_N0ix|`DG3>z~L=RUt>{Rl|BvR zEd;vMBNM;FoM=3(zlZb*!dOBLkT^Y#;b{bscV&QfmEp=qK+PlXWsrGyb}rqriCE5} z=b;0eRSLZZb>=?u)r(FQw*vU)sniSQ`gX**PuONscW|C)63sH`?roeV*HloqvG`kg z_Qf|FF|e|*=TB33-HPRg0yNQke=b>wmuJgMwU9iE?DFJU8^Kqra*_paaqCO97G9?1 zb5)C!flq5#NjLHwjihj5Rc>N9ug?f{O*jFQVZ+A}N;gArI%_r7MCKLnGy($>$kX*{ z4n;j9L@rCc5UA>=(E%mhQMA3c0Rc71|EVXbypmS&EEVwYeWT7qeKvi)6qZgwEh=UO z)}K{{aeKJUzG~Pen=Oj}!A6hU4)!{+y?J2%>_h+KzkVR;W${93A&Hd|N_9|GQanvE zAhrCC{K+FPx@-RQn~!~Y>`rnk$T8WNZ@QDRs+;nSWSDHU*N%^fmDp>iM^?W^WsIaa zGs2#0dp*0epQ&uBUT1LZvY}W)YNs4V*Rn|}_%A**a-iVRVn8Mf{1<{TY<6A6~{)gaY1{;~q^5Lqrpqh=HD*o9S z7}XYys$1N`-Xt#_An_AEg(_8SVKQkvd`n7;61XCkGogzORY)lwT?@sTqqvSE^udSb zPkr>me>8TNWe+)U!C9ESL23Uj1}F~v6G2WDO(RG?*Fi^jlAL6IkmFSGHS#7KfgUHJ z#k&~`htG=KPXF!HUH1E##^CRl4E~%bf98{S&L6w)eLp$oR5f`cd#Jvi7SdVmyhfW1 zi7|$A10G}UvUs>XVdSIn#j&pby7d!C2S|X)S8=9im-nXvzF6nkJDe5H-)$>`1r=5V ze<$zklZTjRH^R#IHdn^`*=x0d!q14Y#ZO->?k1?rKCNmvjO^LeiB)XDMy{of7182F zbBK+adP6;Me-VPQ<5xs@eUgGG+AVyR`?4T>tuziJ)gS3bPIgjpjPB@rly7V@UYbwl z*=wM(RkPWs*-UaW4LvfF@s@ zfo4y6A?m%zb|on9Mc(W5}UeF^I*_dskSmZo}sM9P?EJVR`u1h+Zi|?~s zTIwBwhs%xLdboU+t#Zv3)2Wflr>TVtXEXiC{tDHf(TLt?P{>{b6!fr!#gnFAR~zdk zEB^dFlERxRDQrTvFPq5aOTQB(Zh?e>x?HvjiSY)LTwBWU0X@!;J{rTDd()@d44D;u zy4|0i?Qeddzg2XwwYc1P;5!r1ZhYxSOM}B#uxF1CVoJ%`hi-rJLH%9nZEgpd?B%xQHt1tGNl@j zGa_R~IaO@o7|!ws%HVYPQKq4rf=eFOX^tsk?o5>JTSemO-8Mm_TfvxmTh+?^JF;E` z2Z=EFRsaV;5_8MD+85fi{efZDn#}51&(d1XS|C_^zKm&F7W%eP)kFAB0H#Pxl_HplOF5Rz( z6H@T8N#GxBgM+9v5Lp&lIU4gh%h=*P9RG0TZUF3g*L9lRDD8fQNiXh;KOn=S1DDPC z|0LrXrhAiBe;*|8Mzq2~$$Jqk&s*|_Z#|dfwSdkTdLmK=uHDcsa8V_C^bf)~@@+Yu zv+ZE+RCA%XgTJKa_jdAknZK9j+q9~DU5R))`3{!E_L$p8{0no>e(9|e<;HV_=yNG-hrf%>?3euxTP~qhwLLT5o6+AhnRL?843i>!uBT8>_1j=V`tH!vT4|HQ$W z2fq8e$`*{;o|K;5p{3-r&k*<3x;r!C%pgb45ip;@zY1f$%(e5~P>O!RUb}s9R$J@f zQXkjk`a9^jFZyDHYG(){js8xx2mL|q3`A7Yzf|p>qo_2#Rv&f492}DPbQ-$SFS-gH zxHb?{8>OHaX~9XfkuwsN5!f1}wbYj4z<~tq0n##3s*#qF6r^QjxU!10K4j@9VV8pp z7l9^#ZYomQw5Uwy+V}V5d-5r#vON&obfB{7^gupHWmEZ{gGPKtWr1`>m)Cnhg{xO- zpVD>-GRtV~8Qeqy{an!3)vjFd*46G@5ax<6UFHaNL4`${UzWW$Cf=MGF}o|j%nt_7 zBUwrA<&mN!=krKRQl9gYj(8CPbs3(gk(|-Vy>3tz{p6Ps4booY%d)pf9W2hIfta^{ zA71(G1uo0B{zw2cm9H$nfS$L(Y;}*2sB=Z_$O$=s^gF7*ECk6jxj-P$R9a4N2mjCW z?Y$`vAqY1xJeAIv);?-hOukiGQb%faLmT=!Oix$X<@%F>RVJ^6|t9Ej_?Tm%kqX&uHsSs-68L&@?VWRFwFj?u4oxtkwT1( zHEMck*#s-?xk9R@95OWWW4Do!C(x8TYsnN-U-?F3Q&%MIqN^QeW?7;Kr%YgLP_zx? zAhsuP+NXpC)3WyrG%>~*)^2!8xLd+uhKEu8Bf7e;LJlB&Saw=Hx*8#9C2Fn^EsFM8 z0d}Fxbxr$$o@Ls0L#lvD_Biqc3kYRkYc&CLPi^nbGKu17Gb~;h*LXfF7@y%NOkc$O z(IU1b&C1Tr)jNxv-XZp|qqh}@Q(XK=vM~l_i=RKd2O(?~w}dUw2U5NxjlTLKZ*(AM zR7$=$@Fr`Ae%Rt?x})C9XVlY7^g1})cdmweFJA@sJ?q1LT5wN*w&~+D4te&D0{Q6y z$WIIM)-%AK7UT`%_5;Z8^wmU1Gm13=6xVv09i3{gCpM4414zvFwnMuHoaSwE7dDW; z0+di>^bq@yL>475^XRqPUNm*;qW8gjt6t~>Qju&J23=f83!mAF%do#ydX740nZD`c zigDz{*Yr30n0wvJ)+atuYt3^}ST2FIVrm`x;e#3{nQQbGv?uslx!`M7h}$)AjqEE? zhT$!mv2bZ}TRsCP1-8xGSrMG5X~qtUp(%(MJ=<-m0;8gZqgcWz5H&^*!M9+;koG3- zfxwYU0$imuvc)s?D8*=U|%K7yJXrb9cQP#s#{(NLAYi zXQ7Y<5aj|bSf?le`USG&{DhRHLi@HrOf9W1v3dj^oKdQ~yrrnd>>iT|KlLieVp{ky z+Ruv#@uFELG`EnQOzORg+N_^=i+Z@08)4FZ_;WEFBq^EE8~1f@*s$)?N8qa9x80+_v`bax?p5w`>LGo}IHGQrK+S z15??56EOtz*ydfK0N+4E`hnTIW;=)!q!++2sGMjdk6vY9Vt7gR*XpK=rl$G#5zG9D zf)MqdOZQC)K>{6PGm~Bnn$LnJki%NYyZ^_*?62M?snp>u*L>^moTJvUYcY7H4m$xA zhl7G#e^B9)!>L4X97j2dfyapPoVHCzp_BOZz(dxT;DNo);}^5FN<%Hr)$~|Ss_|Nrtg_T=cG}mh{Gbo z5V3US&_@&XkKhZW6Scd7SR&B+^kK#4wH!{Aq-}GMf@fnu1Q}7}wjx!7hdn51e-A0iAL zcY=DFn_j9Z?bZ><5$?PsQT4lF>6q{`w=?)c1h%vP;CxHJo*FbQ9cBix;+c3TG8!eU z6A9qbfJCJbsxVwgr7Ryc0Eqjd7#JTzL@XHNlq?abY+0^aGW78c3HP$nd@{8Kd^+u4 zVt`0NG?^&oc>)q?Z(DvzZw5YX&PafRW~m3a&Ek{dFQ^*li3GHGmXBBkaVczP7ED_4!K_-E{T(g#dXNLiJL<*DxM0(+BosDGC!8c9yk z9tlghCOQ!Rs&GglC;aGbx7)#Fw-F_>^v7m?X)s>1tKDeD5{X8ugCRR&bTk8kX7ZiX z_hO?cUja!BqC4B~DrICGX(AfzcbS}7i8LIiJReh49Wh%M-Qp2%LFBz5pM5zYDWzyE zE{6a*Bpse(>a3RQPzt(=qRd{WR0NJgz6}SUUhd`gEZ1Yw9jZJ3#_mAv2)5pK?0l~X zlfQ+eInMmM@|UQG#2L`(d_X zXw}IrdGC)>`67G5HAn|FdK~JF{A{2LP+#94RhfSlr45;S?ndKUj#E+}yZO$1hO_k` zr+@9iKCMhn3?R=*t9S<3iEpD9A>jqrKIq{@^k>F`fLJ7!=Y+o26_&Q? zjcw{v7nj6W_i(hS$m~|MF#fzA8rn3!`~3WDRC7-PKLe+Aezqij#sWX8zqp!S?-ig# z{(U?lItu~t7?U!7@=S^(9JkrYTF9x2;J)1t5yMrE%)R{0`Fn`Jfg7t@qWOKrJamno zWL%%U$#Mg$nM*d=!6fM$5GEo)mwh5EUn8`hdZP#vBV;mdv@|OLx8o%`DO+e*3n5zz z$ADCHWZNe9q`j)OZGnrVIQ>SACMI9H26fE>+#)GnQU;(*uiC%R$A`_9+!&U!);Zbr zNpbmLE3}H+44>V=vl#rB(TZ0)4PyJ83A=uuR{XT}R%m7ytvG8#D?jja>xZ;|vD5%R zMjtcBj2qx+wYfRlt?q({y}avjG1&Mn$xGPBYin+pb~{n)>d zZz~_WW+A^M{4lrK;sm1=CPe=o5zwIt_ekd3wcrig{QLAsDY8sh8Oudj{k+0kyvmC% ztS*g|PuRfXO?vZ*DD33qXHU_%^Y~Na{cYKQti&C$*Gp~nfA44 zG9BAmL1>TGTEI@vg3!xoEdzGmgPh^CR*^gF0pnvAttc@Oq3QvIZle`HS48NTUCFSoW{DaSM8jXxZb%TVo^$?*GtYAa*~xLDNjvK8I|3+iOh?*sIsx*U#p!Vza{OJI z$bPS)8iD5$JWDnF1!vhdT5I@ID?r*qYYl(1_E80nk*0KhpLu<~dS)#|do&z3wq(}i zDAGrv+K%RFMw>ZJiClMB>?MFY@Pl%Jbzm7Kw5m|;l4?FE5bC*~$tx8km3sP&6m3ge zL`CJAd@t4!Z4cgq*fTZ7pj4#ABWlUM@MhMVn|=nc!G(FO-81EBscn3d4wU7oB(kW{ zJJ7SgG0YQRiIE`Y>zFeO2RrrG)>Ao(Fud~%(zwAMsytVMi9Yz zC;FrvQV*JqU3#qH_;!GNH>cEWJ~1nSta_O)NL9@a5o`8`C^2|{dI_|R!!HMwE|d({ zVqCaX6s}b(P9YQ3tjr9>6%p-p#5xk(YoUa&j-;Njjua{Y;K4wo?tr`=u{GGmq8Ftv zoWP3mm=(_(uLq?5Zua<3$qY*t#ysCZ|1ofLe#J0Ik^DBDbEg`r;M>y_&25F z&5tePN{s12W5sX%ch*4>bMI{+3M12>fgpQ_B$A6>Ir|^yPQEjkzxGTpi49J{EQ102 zc(QluZ5#?^gjEh$7^p`}%x~V6{A@^pgn>?#KVX2>QQM$^`+4?m&;HQ$LKq86Vp(Hi ziI_=VABQh#nTIxxxD*7xvm;1D>|{|Ln_H6K=Btz{86BFa zlH_??GCQ2Xo<);%f2LfSjPlZ#%g%KY5*QBo_^qfha4<*PsQxZCdsN2Y0C>?84jNK= z07;A{L3I$?)-vz|pvKA{0Lth^e0nCdQlLpf(cFLPo*3jfG|?g9Fk0vWDH?b+Bz%5x zD5&_O7%))PR1|yo5>a*Kqt!%_C#2svm1&{})pU&TZ{@V*TUFmokK9w9A^U)W^Wd4g zrS8U~p=a;WnPMy#=55bVBf=KInYdTSXU#x6G1_b^z*gkeC^xMM!9NASVpvG)1Xzt% zK`En1+6q<@KFmJs5?XerSWH@E}_-|l06}xs6Vpk zl?es*$QgrA*y-A66(bB3LVCQObYl1W!>lc^BKhM9BL}4`vwL2!ku?ZFR*ac(QN<8jcS|}+Le9z`kHLf4&$dFlj-C)kM z+1uQ?WfZnn&gFl;_iT@*Exfs!HLK+tG|}hEwfvY5SsFzzXL#s2 zgp8flm?LN?4Hndj!TLUjnwwGW#zNLkg9W$j5yPaY2w{>m zEE`p@Z35fuk(hDBtZXP+aUKpYg`o{a?d4F2qpVswK{84q4@<^H3-B7wYa;o?IO;md zC+>b6cNRw=%9k6q!;NX!op>d=&o;%26OzqJ5EAdmT8yXf3_Th%zQe z>A6?&$g~((SwEm7FB*;ok*k7DxQ#3pBJjGu!cwsLI_W}1VvT${B#hg8YJJ{NkF@8= zlX6mvi0Vv|Y1TQ!+MzdLxXr{84TSnDe0X;MqyM}-cq~*h!t0A6Ge=Qen%}T+Rga|Ex{Er?dJ2h%Dk1T z3UzjH{6N0B0F*ne0=rj%y(!lIXzJ zqoZvb^)`!f=2FOWZk}SfAn#%-&4zX$WQ0Sep>(M|*H8w0QT#h1s`EtP)3#7RF|IDYshRnlhKf2L7R)-A6 zxsJY|C$zA@>3TgostvdVVQs8=j)tp{>_Nzjo#4$lJrfjE2^I7SpDP_~O8dqB4p;aL z&I%@n8=j$W?~O9GQLv5pf~Ej3nl7FqC~&I|3~DgD(8d$wWrUkkesfBQV8jR#Ab|c= zV26%F8vz+4Nmbeon|QcX*< z&WqCq_z315pu$@MDi{mPOql~3kK4RS_GPx_@+(@nX7MJ96>8Ngs)Rd%B`jN%$6PaH zPzpn?pu+llRZvME5n&>=xwzX=DZSmoSagXs0`R@;0idBUNPp^;CY%kbdW*eJTlI0> zv(>R6hZA0DbvstPPHPv{byUsWe8+|nK5Fx-WdKB#f?Itl0>N!#qLHmcxsANt+cq&F zS;MDU=X?*!9vXq7lMI3f^q^RUNYN9^`rAcAT))yXnKkJCPC%o9lRM5ZWeFipbmJ1c z(df^re#4Y#bp(ndT^lIVwchb89|-~E?(Mx%Tl!?sK(2}akzysX#N}=G(dx~l!?I$- zjOB9|387_f+Mf+T$VrlcLzGx<`hy@B{KU+zXRlCLWm2i86^4>23Wu5Pv)fPKf$%hi zah4X4P@*~kTWL%aJQ_#96XgiLUn3xLC22^fGykIe&2$+NMy`#DIRgd(iIG`?;aF`v zN+yNcVKn*Js|-ebLnD&4;e{meEU<9 zkjmHMF-0OQmp%`uL6K+B$OIowU~GY>Z53&;V}V&=SNpzUsXZqQjDHlSuXWw-b&8cn zP#l!jMt9^${!9IFt^{sA1g7;<&NTfs{h5jqmf;$}79!Z&oOQ|5Wa-!Zwn(-+3EUNk z-IKjF22Bet9;Mp>I2&S(_3*p&Is-n-*plAFAeZIfBK`JJbA3@o zZO=g^cIqkm;*WVyPc(bEA+-&AuweOiR57L{+c9o#7s|+s(>szY+d-~jitx3i#*JQ) z{L4PV`F0C*LLTA}K??ze5&^h0^(yP#*0_);=7-kD;~>>4H^X(hFJm2|`@3S%U{xwt z07?V1!iMxMj1BP@rCzSsKIWdnz$`P#3IrS9)BG%Xc)M?REyyKCfv_j0t%QIQ3{#aIcZ&oz#5oIQc%;$aF2p)| zU~dByT1QX*{Lw=+1BNd8+`1-uijO>~a~`)AhkukR8|68Vk(Bo<4ADj{i<1D?OoH(n zP>jIJ8Q@cM!vO%14z3lJyPi*XT46!&^CZ`S6_#j)C979hD*h58GGPvw=0j_&oWs%j z91Jr%fj0B@cP#u2e>V`%^miHa*u`4usG|EW0g2W4_jh{3D2lWCmPJv%8a+r{G}?R@ z`}0h=4B|@M`XBK0OTZrSES9$rhc&D&s0oFgRTk@qFnh#BWe zG|tEJe*`XGFFdOFNQ}$*hitz z_#z2mL+=^Sm#YIQL$?H2WY$l?!_2IQOAMLy%y!7EXU@Kr$%3g^zJEYd&KcB(V~w3(ScdZ>M2;uGKnO%)U^VXQ^8seMq)?SGWSGt zdJAjW&V!chWje(6WG#oI!lr_?3~Jq42BhP@VcKk7nVl$oL;ds;8D|C;Izo~wk+b>_ z0NKIRdu07`tpSbGgpu1b1E8hsGiJdLZtT&GJ{Xbc-=ITc6D<{LsFOEfWUxbOL90KZ zUn>4EUMddo_9WkM5aVou49I-qRcJAL>C@DT(g4Q7AsZ0PO}OQ|jqFd>*>xM*4(j|8 zeOhz%@+jkmf4su_+rN~XT1xouH0b_}X(waSpG|qx7R;bO8#~6Dk!%mjBQJe@+B3>y zT|3bRvYKQclZU62?1Q2&K8kjN9cZJk)Dh@uU4?4;c`8(gOH-LbbjpD>?NM+YxMDLH&mCw7VD zv8c_b)LPr8#I}W%w(Mk8R3G*QDcg6@7liO*-SsW-BLVF0-RMn1_gLldWuQ;BYrct? z&y~+?SAfESpiA zM*tAP31mjT`<1515QiaQg{h?SV3ZOWz{uQ08{ih=+Jdp>opm=$xkv6(RrMDo0B&5<4OY&u*k?D=_46S&!kXCv{$*WYz;WoW^A4HBVtVtlpD{7JyL;j?aGtGT8 zSPj;uQ#||5PhbO2gv<#+&65;Dc7#CgIXv}riMZVls9NfT{A}{OEi(^gY}$Syy+(Al zN=$O(E;swh0x5V6%~}p8e=TI@`{%Nsw|tMV4=#JJ6-aYsH`n@$J$d<5U!af1{F@Wy zp_{e<W` zQii@6169j>3}*+Pw33Djx2-XPizsJUJTug5{qxe>v;hoQubVrwPQ5Y}(Q(Z8^N4$^ zSEe*g5ipC)%5x~qBocyLsk$z!VwP*j>y$ z5IWGh`n;#`U}cqoW>+%658Pb3Gq23R#N^_#(OEBj9k%#@YmVB?gq9}9B|9;U<8|j# z;-qX-CJ2~FlJYX#4i(WMZ#657Gj6r0h{ZZ^$|it7K30|08heP-9rJ`uN0Tx@;E2*N zJH?G6SQ3KxzV(M=&w5r^R(?>d#g|f(Kqk+P^4fa*yF)tGzD6T<@>+F5l5IzSZ~~ga zXi@+F6&|TXp)zaMnW-{E2ijmi9dI4nyd;K7q&0M+x-FZq{VD4A8;Y;}!tdiyi*b#R z)F4+B%-&K71ZN3fmHW6{hN4nRWkXs1vXUXdfz?`T@PzUBkS=DmB!G(*HSy`dG-Hx~ zLMCQ8$$s2AqQYo)#0fAGhr<~!4&vkCi!jYmWUC_n0yxo!#ar*0PeDi%ZyqTY!ma$O zXz8m^OI?y0YMG+sT0m{rP}?!o;qtJrx$;S!G_|wtV}-Ff(EpWNYr5GKa;+lV^od|P8+;*0$!+3EWCt- z@>O^lK*s>PBTb?{2JKrS0GKG0 z-;k;22#AXL?b|EtJ~SXgDDQ*)SR2po@7HfrAZ=LU5^nYS_~2*86i9Uf)?veM=h_||f~|2o9nuNA#{}&PAXH4r#5}k$kc!!LvLCaw zXSVoh9pD3bo9DIK!q3CZ4DjrLTD55+ZX1LYwZ&9|gS}|B8(^l)YF!r!YfBPGc8!Hd ziumAajglH=25%)nHX8dCF}|?yfxrWN-v0H#M|(d5biBxBRp`N>Gkm<2nAfV~tz3qJ z3ws4|T9yqk`D)pmf$Oa60KbEftUvjc$ayzlKE>5;PKQZ!Ws^`B1$Ih0 zs|Q7s?)>7BKU@CY2DN4x-{l^sBcQ!;{^`bD{D09(-BKmNw!E^USv061QS|k4&E<*r zkZiy%^T`K#t$C|6snH?57%R>b{a}jJccct4uVRSUxEXI>JBV?nJt9*}woC?=`7=g2 zKz&3!#d7ZvgcI;(Svz*0^2YS{#(eUI*?yM&?Gg91irCuo$*c7l3Lm$r9c-D>`r?`& zK?+M4v16MLNIIzO7EN2Q#{G-h&DfW(f}6C;&cOPSEYlPG;zSg6A#fATXLO27Q+$c8 zgGH;7S*(W9{=WS3*I@8ARds?QQs_Pn!Q%+KB=-5{p~GB;!-jqB6-{<@^UPoAji4}D z1NALvaBayNC~rZ7t4h{DjV;S9pd&xi%Hr*TN+kVk;Xn66a9m6F22K$d;l*%LlNT;0 zU`9E8iI&11CO_7BT_j=FUjULKir8_gf(2tr@C>+7cAw$KO69qYIXrJMg;Vbm2ijP1 zC59@-$Y|Xx?b}`)lz%2*0s}y6?`B_CiF)8N77a88S(&OX0kco(Gz*c#m}*IDTH2{S_HpC;)br1PZ}v^J#TM;GZ-?`DNrP7E7e&>z@qlGAfJ20Ff&eEO zV}a#h=g7e%G8h;WA0iti$cb|zgGt83AtJ{lLvV8C#7XYw`}?ic-Fwg03v7sm%GT`e z)!pmyTfg`Et=}R!fqj{M&V=aM=%w_Nh$~Z?md5%N42u+xsV39Q^yW&No$~BXsU7D= zbz@UWr`keWCqZqVty7@3&Gr$XXnGfNN4YiU_1oQ+?&P;TV*h2cvT7WomvjTv8U|FQ_Lxl9FAKaf#hZ5`5hz6i0;9`npr^#cc70`kCHf@n z%`$AW4a#C~vauIKSQeK*rO#NtNxT<`O=X)<8Ek^lu9tlBUI3VY13T7)aEJXXF@5`?r>q`fwfiej4RBeKO{H@xgch@jI6P1Zz zmLzO5R}F-fd7eBssm$*XO)6$sdnJuK)=etVsx+zAyGaEYEEq@O?*c#t3fs&900E@2 z2_IbGiCs!3z#CbT3LdpCna9aNbUYJ`H=IM3%&-pdI@kh|GI?Z5P|PrE82LF@Y|4J$ zrJayc%gVLgh2>Ezxh2y+OX^R|u8rhwLJ&l#X)A|QWi725{kn}5M~0*!xf(^gt9_3@ zOq2vcpf_4!HDy}z56NF3EV=xSL3mwJUEKcSr^qw=1GHBBe|sN7ZMlOJ zP=1?>GLno%p#fLe2tl80`?n>M{$ST^zX!c$zvsVxpy{Yj2{R)XmZk8~F*<%iUPI0< zOQcxNB?CFZ@C;2F_@fIpu{9A>DP81=^wYn!z>4fT z;W;*ZU^~j&`am_+@^Y}TAHibzthB=*X+nw;MoyDx^WV$CHhG}bkkP7K_{7p%y<;;3 zhD!AQ-%Qfh4M{v;Z?07yuvgavUZ`suBv`futcE0Gp+F|jsiDgy(C%oP8hOO~j z_$|73SAV0y^J(4J4A--DU)imBOA1_Lb>7a~OofzKo#w8lm@A4#^{4+(crP%t&tO4Z`&fF||JBrUYV~}05cn-}XD3?dMWPw;MC7eOY;5!A!v+ABcZQPN4 z-u$d^+oMbcN492rv`RUi^TsP0nVnTmb4mj*?tP(D7Cww8lg}nPqct9tmXGu?p^1x5 z>#6?enW-)X_QWer>#4r&%v4uX{lA@tQ_Z?JP6T7(MU%^KAuElyxX0)qt}#D$YMCXmK0Yo73!I@<2>Fk7T?2n_RZM?B%J zyj62y3$du4qEY?n_k??aFObwc;jLqM!dnBL@Md<$%Gp-Hw0pvdTv5N(&$=hP-f4Nl z`vzq|==X&80p(bpaMIqWEqTHT7SUz!gyYpemM5H`fY$Tr3EzCW&-R`(vt7~l>CMJJ zzH+K1k$yCnxCkUmPv6zdPn?9xw7PoyPQg*BSb)==Z$Sda8f>%v4uX%@L=kF;#!^%v4uXz3H@`>buWO zbv4zex2(SB%v4uXefDWh)xUFQs;jBqcv?^Oe?K$T)l_dd;Z$o=Mw2}e`HOK+2Zyws zneA$}*Pn2XSFlIyR(=6WNQ!DZLM>pPr zbdo=M7;xVi3@BN{#Ol*pczt^1RR8G4U}UHDRR7+YsjjGc)oDG|zkg<`tErwkt*3hb znW?U(dh)cM>if@3bv4ywusV%>3ZFSM)zws!oa{87>d&5;>T0SQVFoXfww{^oYPNMWO7{5@A|2g+p}b|6RFW;0x1^UzvIpbsvD1Q)#yq-q z2Q!8#LyfX_k}z`c5u3J;@kqYwxmHYwcOXrZ8=5g6-l0aB4-e-r`QJD^Cgw&XBO5;8 z?BmLSragD^Y>)PEL6g6&rA^}8PfVx&2(0FR?VihYYGv4|Hr=)jY}4e5w@>t?r@q&@ zLouWMwsa$RyOpnRTS{vDytyr%(GLmOwxzG+_h4g(j&osi8qV(Yrzn{}_!Yf+hwb7W*%wsdIqD_V&!lD2%S)x44Tedgn@M>*s%uI(-?XhI7aj&6G zOhf0m`)M*{yyhS=J8xpnF3J5rxb$xBO{-XBv0~m_J-L;_A#BAOA(zOA+I6zZ|o(rNzT8k?M-8A`+k9q}x!!KO_?v1k?8|r(iJHZr*#EPrPQ_jcZ z>DI=B&FPK^BmU<(PB}j@c?-F|`BMGh=ndtKpJ(dY+3lJ-eYz_pTYvg$J1}F}CW{y9 zEx~Klv;D#!o!Mu==gq1stgu-|>yO1cpG-Ism#oojx}Bcj;Ws!sYm$V_q{kO3lgwDh ziqt;hmKmG?ww%xF+jG?mXkbM65jlv;fbxiNsa__+5Y$6iK4Mq%shZazQ2=y4)oB@% zyhXdJ$0y0kY~s9bO^}rtL-9U@vSvPUN#jYS&KHYc{yPpWQC4OL%I?pDT}7un`(ZbS zP7=wCburdd1$(Er@U2s5Vi$%|_CuopeRwK#7J z;^n772KhHzB}@@Vg(d3jQ|c_V!R3-&asV0!>eyu~@61A8d|W&LSeE{|Tvy#Sp>jN?CA+NTk*b6qeKFh_j*$$N zDUCR$BVWAF6^@NMa}dB>5YhKhXLTxb9-#5$BbPK5q1cgp;;mqph~xt_Zzp%?dGTT0 zsbX;53U0T8TJG4ptiY+p-cSoa7AA!YjWkhJD*uUC{uBM>Y^!%1y`;bVi^d_u2Ds|0 z=|K5}tN292*~QF?ff#N>LieVUVQM|wBZlE}f?K%K$DM=BfCfDT=}fvS^*sE#zS)$S zn0}erJT}KqL6Nul*^j?V>WMlA|_EY%E^66Oa2lAEWKP*fFZiY$SfJviRO<)%q#)^}sU9U9BqO6Hy9?JGF( z(abqc?oD|3bCaS!by$35uNf6|Cwp3_5~-Uy-XSu4BeyLa0pXK42W5oxD$eE+UkFh* z%8&@lz(UAyB$+^yFd#T9r@6qkHM8D+;O$L}wopI{cqN42re1`vN0G{V#1gHtZRvtv z9~q)pZ&LHqAM$S}C(0AHDJx;((8nQ+bGel8>QqoPvWTNakmrddcX_?xBb zgA%R6Edbty$wS;);_xIw<(x|zWl!$Vyi>;!n`<5T=m}kPKf1%t-QcNILz{FJJ934- z>WR!6`YC*)Dt+^I=#Nq>FiNzyqt$PS$BPVkAFvs7JfeEX zQC%vRFr*))>7kcLlol068B%|zDil(G3*12+ z3n*Nms}wI)@_S^sA@e9l(;z@bi=+3WDsrg1#Eo1PN5*(b*p1%-Rc5sKTYsUL@+|Y5 z24M5)FxAW(W(elF2IaHh<;AG1g)nX5nd5-I5#*1E^udESV}S%NAj~(KAI-k2bB?$Z z03oK!dR_fo-W$)J(G&X5yCSk)D!p>=qtf2eO{V%g5=>7zf1(YL9Md%2)bkSxS4ncM zDmckQhw`?YngEVKA@M$a&pS6UW7gHYb<P8;w zFae#4i(YJ`%E_=02S=xukY#(4B#1@95JurrShHTYgRmehin(xlj9R8qx|CdCY5ftZnuv9dsnXtKOp z!F2>VAYd8uG?${1<_xT9TYA9Z@lhCeqp_{=iQ*(9zW!;nm%?#@*CL!_X7vrc+zdtDqvM5a}sn1xDq2| z01UyNWRGhu%-MyBF3|FN@ymAnX{$6goyL0Y;$wCO>UiG+W>v(m@3@Rd0E*gyo>RUP zws0W3G2n<^=UB7}rhQt{brE}Z3`sVPF>Q5mZnbbi=VNYZE~I``>+V#?5*ES>fc_AZ zqb~2~)+K-dup9Chf3_n|IbZN~y>t_pr3r?BClUK8CM-0AU8-xtx;zWlLUQA6{V*6D zx<>3QStw;(j`70XBC_YB*-jg3oN-3$853#+5m#~^%|Z*{hYy5Q@gVvHt0M4fG^rjk zbC1XfutBbMtqGudc@#1I;$<&%XKGVj!l+QRS=1$r3XdgW_Nr~P1}vz5bY4A!!URA? zBs$WNnRrU)*dbW#>_D^)W?;YzeuVe>+~7}-O^*g#@ZbtxkJ{0y4xXc&F?z(0B&o|@ zG|rX4Q6b2u8Lopz#o)KRO+!R5u!HvLu@ZJut2>e$%giN$EZcPo0D*`&pk!MTN_2&GVws3@ST|7sBs+EDK zHN9bJKnTp;Tvx5C{N`@8Jist&>jO6E%j@d{CTxJjW##&Sd8ezh&rD-CEE7a39ih_X z9a0e0L0mE>A*)`=g=>kAn|8b1dNg#)}^Qo&jy}4t5Ubo4Z@gV@jx2ui&9uTxN6sFmf>NL=dEGg5sV}TUXc$B>( zL6ADzQYn+@{d&{%OXHN=QXw|AACUTT#IN`0`kByX_O2j~T+6L24nf{HWU1x`gTm%f zJq2}o-~fP%z@+WVO>zr28eCC<8y$LMRB-kg2{y*SbWGT)3}Y;&T&&&9FLJo-1K^^@D0nB#!ehHmCs!Hhkrn8w?CoUtq1 z;0-Hn(9MV?wB%SKd~wrMNAiw}(?^BC!JzIKQfkVF8NLx2YCU$4&@X+{*JC}g9_z_q zkCzj5S(fvubQ$#)e8CUI+?GD3PrM|Zx}g*OO3SOuRX(@aPUi0lKU3<-5rdP7?O#h_ zeacg8jlleLu&DG&+3coR*plSq9AMse(AlF_P_rZ+wt|`^@t_sJ34>`7PFcIZ3-9aD zg4x-iIxJXL0YxnI4Q^KR0^6*n7vf$tPEC`vkP9bP~H5TJSkZ zvyZs2C1Qc~;n&#u-69|0p&2P1e@Mx64_gLl(>hAO!}m{r9KKe}f0y28i?#%%VTm^$ z{RfqOT(uj4&9`m0{$eq!?H;|ZPeFX^4ZYY?{$HP@x8C}vv=MkvF19c*M zGB~=w$iPhnNeS?BCF*Q3vGAIEq1(<^N)&3k_va4B6y6ppOc>XpZkT0hluM$8sy?h3 zrqa722>~mir?ZJ1jZQkl!CcJWCLpgH0CM=onR`F77Z+s@2(f#tV&c=IDJIKSf*M%U zf@i{?ASF^MAj)%I-UH3J*ktdcXqfWtQcq4&?!8@}JGaZJ_oB=W>BiRooLa~Cvf4a} z#ulEhvBma$t=8JWLnkfDRAN*mHfBc0inJ%G-{H_=%~4ba+-)zlplyB?nKniTwdun_ zrWmQ!{9D6}IqLLJB!w74x4P)q+88a`ub%7_NB>@g&WFHZZYh~wgE!v1uqO6fMdw;n zkPgvyI>(oqCG~sZnY(e5;yTHQDE#eYdc=KNTn2UNh;+Vc>(ucJY&|xvR5R9(pXKN8 zVZ*M;R~wfx9a9Q|pfka~r>F;o#krtHP`P&9k%?76iZ4C;)b~Xul<&ge#1(n*9R5S8%qIUoq(!xH4!OZ z*OCGUy1aHXp9g~nt~igBSG*K|#c6VWRe!r^WRDT|(a@~Vq*vOKx2~>2?6iSX`?WX@ zT~xSSSb!N69+yDxvoE`cX(qi~#7%5o-nwGatiHuY4P7oPny;DEm*PnS`UleaKf|^0 za@tBmn*H@oI#i))_D$XAoqJ{v-E@2F9r^0nvg%I-XZ}lIWN2xmj%fzkXfBEX{x1?aak^U#y-SPtrHhofcGB)@*oovkB z`ELXYW_Njj;g;q_(`)RZCKKoGTB%XawK}hw)J$nY_?B1**Q2Z;@~)`L*sKNqRWFM? ztX>xRSiLOrvQTEme9#vl%0oCa=O@jxp@yQOXZC}Tl&}572L=8L9SUv@72v6clJaeU zObfd-S50v#AMRNaNjZ}X+uV_TRYxL6zR7E7dCYojj+LPTg(Lg6bD4Z?zGik|Y0p=e zo7eT$%}NKPu{Gw~neR$|ZfX7^&M_`E znfzr~{1wG~r_#QsnuHKoJQ5L|IISKO_K9s-3~bQ~1s2wKK;(=n6e4?CstzT)*d4Qs z=qqoFA>`}w_1T}_M0G;mt%z%IN9jt8!D|f)Ohka==$Z0taS=M4@PuX7t#g~8C za9YV)_~;q5qEz_8F(?vT|I=NExWe_6=y`v-(=M{ZHl-|2H6^v*Fu^teCwLp6lNKMC zjw?XB588obdhrHso!Hf5YSbluZOyaaxq<%;~DEt{JD^YjE4 z)*Jb`@e$m5Z*UDtF9rkPi*C>AMdVoR#gbyid?qF4BX8k4DzRG|ZxGU31o-MoQ(}b@ zMRv%_W%1dr>$^^4GwB=9Lu}0v)Ai@&NH_JuyaA=A73vMzn5kh3!#$Q>MkE3Y<&h5t zeY;3ld$q|aKLh<1Muv5Arf~=5B4k_C1`i2x?QU;OTj$(aY7VSs@r7>CbnBfH`Yo^C z5n`eK@c-B^--h@g1t+IHiB>JtECcX#1Rg|mh;ns#+JX4(pY_2t8CcL5?O%%Oc zbmC~A;N3Jg_I~MSM`1%I)I4_1?0A)#Q1dvuvdn54E44C&S_5a?QRzB++kFNKB}=w4 zLU~*@j9nFjTuP(5cbFbJx57x0UjTTx!?hsvE>QC{l{6Z0f%!G{^s48g_t+2`i$ z9Bd{)!T^0F0a-sLCLQ`~PqKejh?So2ZTtR@eeGaLrT~@ly9u~p(KM>eslv>u0U&MT znO)NYCcM^Qs!_i;n1X_gm1obKa!YCl7N1DX`Lo4;SXJpc25=axmSz$7z4q*VU;NCc zC$2MZO&<6-3PxK}yzR0{fM<{>>E?xUxF{Yz`>n7v^H5v-$Jp&-)@=qBM1mDQQ5L%V zu)?RxLKikx_>2__kzAr!;d5nS?em=-!N<{1GE8qOK5?Hwi`&}3is!>Za<-+5f-;!A z-ypxGx!l~I9t_t9(@4*7~hwVeF^a16AO2yc^R^&^^q8+|A|% zD^dFH0I-K`L`-^Us3F{Xuq^b3tnmJ_&>OPCdsT>-wZMKOBES{Rh>e#pTT~|!ieYO+ zaLgwY=PHOKnIJ2zuW%5rS&u~|~PbyRw zZ)x^j*E6@$Iu(&P(;pZi(m#4V(;#p~QwJg5)!yECPclIozBsXnj2dmfF#P2O=PSi- zn?rgZN!h88ura7gtYV>^{c6CBy^&8jc%pWu>D~)=@3r^$w@u|Y230%&9G{8t)9GcZ z?>1vSam_i#)$lBp!(Ma#CBn=!&)%F`NqiD$VSDmaBzamCqMHGu5IhNyE#2Ed4W?VT9XDOg#&PZ&L&ntNm+neI%SH7?9A-c>8#ML8XK&Vpp+99he9 zjhrKE)$OCf$)vTA5N0MG3nO(!Ts5Y&fYr*swtIdqHcOK*O>_-9G%c!ytr~ob{}7V* zg{KYS*GJ8ro0Yy5;n=_4`zLb^jIECe8GwtE0~bNGL=TV3OFaM<8Op^@VDTmebPcO) ziuKn7?Y~H*D)1OjDMvniJVl0X#az9vVQiMR*x$OB+hE%B} zxmGr%zGyU2Z7IG_MTx5Vv>t;)sQDK_ev}7MfkaRNaS9`n>+XFVvoQ$h}xcR8TT587s0&<3+qx)G|CA3>xELs8>xL2hQ zmuP4{zZVbX3sfGAPEb38d$E1` zHnT15E zVdVZ`a)sHiDpLWK#d_Qr1>dV31U0tfm?nCj4_rh%BM2~`=e%;FN$#SGMk$s(?0wK! z(Gzu@ND8TXvr>a?PaID!O(iee?9HT=ArIh8ED2 zpLzrZUD5UQc!FI+gtku<3peb*c|B3=;&+WPuF2`O>1D94wbRmo*Ginwt8vAYorOFy zoSw+fGIpl$H}o-{Ui3?>Bu(tl>asMGUi&Jr!qf<2fx6CAd!4J;HPLz9CfNIU@s1tS z>si`aw_{qdJ8SvZH5s=)??UqVI8uz5MYyA?+i=zN2)0=(R5bQFwi=NQ@Y{-ZFg- zQOyxN`PtJWOp4RZ%#PkhaunzDDd*>c zzH(IOoN|7qV|mza04ZWa@96a?mm00Gu?uyr^2NrE-e%p1Be0a+dx>r~aKi$5@1?qV zS-y!|R^@s#+^Xm2<}cIFdHDwYT#%3HXWI8IGv&IQ$v1|VUz)EES1-xeg{#f^`Qhrq zJP%hrDZcW)G(dw9YcE1d08)1%gajD%H9|%J(Lf?Z1PBIM14JCZiA!OmLqN~~k_G@l z18Cd$1&lllA6U@C00pM60)mbHJRki9KKf}Nea``O>OeqRL?E<`&RYy+sj&k}IwxOS zphT{P&{$OgEuqH)UxqzoU-cy|VQeUQER=w^VduV3jm~e(&!!q_HKO!hoEb+^M!e1k z9%skPflBVci4)@GK<-@1`H2(ZX^n6?lX!L90L)?rOV{EG}@5O4xEVQT08N@osUQ7)ByY{t{TB;b&*NTlK z`Yyc1)*ePAz)<3ovQZ_Pl-}4IeTbTgUOV5Y;fhjvoi|E?}aC zaL%)k80+Bm8;d!1F7qxU+bGG+H3O@L1IUDv{DIYkj))2=fcDD*Yy@LeWdS;bv9YoM z9YQ=V-g9$Na5m6-H(#$=Sx-bY59o$TBf2&X6QP@eH!{kwMcun9LK})35vjvlO2n`! za{Lll@<<*6SRQFYpv(gyfCaBYj;xdTTZgpn0;TTHO*SWRNYxO=gimqUh&z(8ZwBD3k``*Fwl}NF9F{a%Tx(X}b+?w$Fi`f6lD7$Ey8{ViU--sS)@WT~iXoR~hgIELB>nG4>{n*9OSwHg19_O%GO|G`#q}-^)~~ z#wb;R`*MuNr~)kgea0BTsQZ!P$^yPp4sU$ZCZAcMrygw-dKp3ZtOgC4Ic7wo$QA}V zp69%M#Mr{YAmP_ja1j_FBn-FgWA1_&6G%K4|7sZ%$`px4w?!bHFRcb-m1S(aPvfT<;NnQdWAY*^rM{ zBsB|pk%cF;`b3-bO)S!0>FSVs!FZuPsqdMWqr=v&VceZn6`VPX`6k}7J~xEb;c-uyf5jgLaiAnzO{v)Au-D<+aIQ@6-I=E%vNHw z)dcUowM?{>HQ7~jDSW7Sld#>Vra|X-`VthoZ`k*y_LPoFzl#{N(st2Lgbysc3qk<_ z1lbZw0RbG^0dgjNqn;DWnn)c6!u~{c4WEFU%ZQ+Ba+3XoUO^XW)vH=>;JFYDjtZXd ziAg+onfN)?$l$2+ZVO4W%1aR?e~6E)hg|Z-Xn%V@(Jk&m)q_t66hcGP6OmKd{h;MV z{lokl?vNd_JpF+6pbGPaG=r1&n+Q0$N4j4t1V2!TDADw#3vAlBzPltLTeD7+>yZpsa2R!_fB@Sssl!VzkM#rSuGhi z$72AWVY3##X(juMn@sCrDD>S}d-j(qinPpzn1N+*^PUY`29KJCz_FBKn>33#b0IF_ zjx)@@vPXd6 z-uAHAyW*4W5LLn~nhH!%X_#J|&A!$z9Sg=7T+f=%p61vxoYZE#@<$KzLz@E{Q8np$ z=p=Fk={3PU^1vMTBU~p}Os`8XYhDJ_%)7G=1(hL_>Bq%}aW3IUG`@_NnPz}NB9YLO zIfcrf>e_6u$~GaNL{p{~Y?=#40B1coW5le@Hmk}r>^{o*i6%j$Vbn+IPo>3t9&MLc zMONKP#gI5G^$V1~(D3@wkgZIuNhG*iTQXtNnx&N9CRTqSN?!F-|vq?FTqL(9=8p%!!b z3IuL7mj^Q!15I`n>J0cH8Dv&f7v$J)3eukjG1Z)1{)f-qe&^racK@@~fp^SpC#RLi z-(#FaJ{Qk)5Cq_)aO`b8v)>^XSZ_cq#rNSw-_m?jZ^P9T&PWaR7#PBLZEAb%t4+<^ zM8Axy^j;Qd(I0QI#8XN?lqWQ^B=3C|wW7FFMXc^+`4$g!k++jI-%X(82DC~pI->8b zji;KjiYy`s-Hlkg<_=_QNQ$cmiwZtAp83lm>6Qs4w;t8I%QPB!*EEa`>|%K2-GT@W zUC(D@WOkrYF0R+6UK8K^bsQj*^oz}&NX8&oDj>}<5iD(NP#TLL6iQJTZRNt zw69z@LV~nzzAe44pHd(3MIAXXrp4;1-dzU124k&-`SGVmMYCvB$=gix zoJp%Bd@P-1Hw({;#bxEl5l&*O91#gQw(d5Em1BluYo$Fk^m@QnG$^|j1QF-9s!A%A z5H0HAHTtr&T52M?(pH8nbkT%>>anfg3%=P_M4;k&As74OG8N!4b)Xh;Pble7ssFw~ zEJhhdiA!x6Ig0cZs+)v9tf8=&)_Z*I*%y}KA?ZD~I4x~Zi_n#Z0Co?kfTdny)tR=j zoZN_(X)2@Fh<~S?jL15|WHhBu#tEH25&P+%GhejHdMB6x#?CiBwC@wlU(!`F<2v~IP4_w(!*hta5q4kbVOzwYZ&G)r^!iDhQU-{N-Q^iFRB75D!tPRf&kkQPM#L7Aw#$HBA8*r#NlDg2aIyCWoA_jTgF zh@){A*TWr|=sjBigY8m`asrBZF{y-wa4I%4?tU*Gw_zOz0GIb5cw^#++D%lvst$!jbmu-|YOyzukDXV&`6;w@7!} zD8BRcKbXVOQ4k!!OSDWowpFu#55tybX4(7^116KF$Fp6xGQD7jgUq^23}x8bpd^(z z@U)|0tlH7A8&4aqc6YHfNlf|Czwp)@w0@x?EfuM&L5$$yqB|iFlV?m7T=|<}qs9@Y zB*5m7ZBh0q5J4J@4_M*+cyvOd>6EXzPGPSxvp`w6tBE<(DK8I~m&(DjU-AmYWuJbT zge8+-L=|woA1{O|Sfothlgl6#SJa&ScUP&j@oPbJi-+Mh{o-@qE#1xlm+cFR*Bz3&kUyB>IBIghUh2nH~5XAv|67*Vc=8H%i&1jYLdWBkiG zBD7ScdPcpMG-%E!XV+5?(S^}6ka>}L{?KoLYQ?IuOmlB!=;YMvK)EF)E)XvQeMc7- z^03Q*GB2gL7L8zKC2$omfwT8+ptXPmkMJ?psqwMi_0hBsGv`QnFk$HC< zwAv{H7Kw)n(`=d?lWwvt9lS0e@9RjHM__kCt_7~|W4|==GAKBJxI^@>0WShoQ%v-jkK8j&a!DMGE^sgOq@xJwRz4PD!^HCun7Cc^W?=VDgC#mn^fV6_ zi|D97Mx(-cg?P&3$@WPWt$8xOV{0SC8i#pE5JU2ilynInN)YU^EKgq17`rq%U@$Mv z@^Zi=4o+R*b>!-!TxIfVNX;C?bz!8+vKo#PtLW%&^D{ElY@`YLhrLJbW;uB;Oa4L) z#iYB<^kg!6X4&JzEklfBEr%JHcI7Zo0XvA5*wS>wy!i@7cWJVVUd!^@$3nHCktl9* z2*p{55EM63QXC+T)W-JZ^jOq3CN;tkCdRpgFhZ8Gi3@BGMta#wQcRr`Q%JE$C0zyx zaZJ={WDL^CKk`N_QTYJ4?6HDFKK0irn5XDK#D8N#$BB3Wj1vCST@f&AX4{+O%qgW` zT5w{MfU~P}Ddd;R7=@+U z$jMhto;Pv6o{bn2?w>EsmAE!l;+GOve!OJPN?h+LdF{O*`cVrB zE&E%I!bp-f#4ckOHHYOe0fTt0NV=B1n7z#tn}WC!Cb`yC`p-;^xo#%KpHcP%p&E zPn8F*%8*u75?^4vQHea<*H0@qom1ttap`@7gUTy7Xk3RG*X}MLf_1GF?YlZ!XJOl1 zr`K^tqbZ61)ff(n!V39aV;WPPBuSd>mMIaE11LCQFQh30+tP#T!yVX;4_ka6`k02` zxM|ELz5*Y3m<0UN2GBn>&xV9L{!X)D!}Rf%{Mu)U7gSyYi^^@fRo*|{y8(-dVcvnR zU_zDaY@@Kw8t04^!%kTa3d?nF1^>&r#B(fuU#&-wa58vfeL;d#&`jc``pLCd)4skO{)^78A$P}Ff_fHXG>BxMO8EDo28>b2*044YklbrS8=^x0|4cew%|ZM z7C>DPk7ajwE{d&<1JI{g&A^(?)f+XyV`;|TN&bqxSWvqpWncjCJt@;lH(uj=MP~d+ zJj$l0&i-8Z@b(Z6Sc>{#%5@a=lR?y9IH+7JuX4dLl0mUv1#xg9k%l>mY}MT`nLb*n z*F_U8D9ChuO)yXVT5}`02~I);0I%{Ob2>y?{HqD`RfNRXKH`%_mXJaJ3=eWJ!h5aR z#hw2L8{=>H1VF_;ULm+Ll*V%h7qs?_0%UfSt$BitvkPB5zqX~`h|&bUodmh1xtR3E zW|R3lF+q9r9jfwOy1IIYOi+y=)}$6?m$vFzU{I=A8}?l*j=@qOP2aw+qcH5PjZbyt zAK2RX-HxNcy&V)xePl4snz zer!hAAG`{a#=^g%U*~SPjUjQ(_Sog@zt8qi*>Ky#attKV_CQZxX?v*5ZI58y1L{&$ z@yX+F$xR%Bl_P04lh5j*6q>psrQ#LLM1{uahcJ`faQXUw`AVZktjmXA3Q4*pqeh0B zp45z*|0Sbe?|~YwBO#K?<1?h3-`%-1IovgUvGJGsMMM9Zej(&to$Zakvg_h^fg1X65^wOZmplB-vskZsqR- zw5_*-7h9a8$HF5(c7W*owJ-eAE#{3i)BX)M!gy!vZs$%AQ0WM^*+! z`VLDr3s3ts9f@VLXQY-5@+%i)E2MlW%3PJJOZfv-XVUDD@hiO?PH8OG#N80WEkHpavPuY16Z#>uGlW3p>{ zZpUS{)WP?l)tL+*DzdtblQG$W{&=DR|r$u4>Yx&_@pjFKlfo24;18@y6s9QQbEN&>!?Wob* zBJ>j_({iWye|Jo!2@C(G(Kspkdq$h`SXh7`?p}a2ErU_yY4#Dq5-1<)=vXP#i_SES z7x!7#W?Lt4`lIYURZ`19dKA7h76t-z5cA+!bNUD4xA;!D6YH#0{aTt#D>UAJd#o|M zX{7Mss*vIjggYZ2RW zf!f8nG+$3A1$e6U)lE5Pxlm@>`xqe=>g1FU;Ju27Hi`2XqXw%I-IE~SNW*RjF?$7L`@rxITs;;W#09^f*pkOYR| zT+tbZ4r2f_gXcs{BSe}x)4-QAz%;^AN&~1D&NLY6ahZl@pd?sR3`OB~9My5xA$;)t z&Kz5V@cpQoy~;!ijDhtBq@30t0&75D6fbcm10O)vYokD56&*|^Hs3(~qwYp<&Vb0# zMoItAof*_$E=EkbwKRnXl)P=@X_|B!Lj3P-s+PgUse-kCNui6dP^R2*j#*NMFX|YR zf)^dm!NP485l8k_v%R;PZLK4Pvo=JGOs)L(RJ4Mv&o1r$@)zWNHD|YuQ<*YfD;>(Y zoDmMh0HYN&t5!}KKfxI~0z(<3bX=xJ>9|ZIr86Yjhel3B=I&ap$hmS`8V$e{Cs{+$f|nz# z+n9$5Qqv>4gH8b-;}v%_+tQz*xjGsg%?WOD&>gN|`UPCUvu=y&8BZ7qI)iqEm|T{^ zJ9q+yTGQZUp0|pyfp7anxwRu(eXs8$mbs z50=8x#c)gC79BtR6&4-CIqiYrGMP{%pb8wc<{*PbyQy!_^~2LLE-R!Bu(YB7=#XawFnIS}UIj{)48uaC?Z>I;CONwbmz0?3P=x z;JadDq9r-9`=t)7Y$$7@vla;eYm(HEekk84zLt)uqLO=2FSZeDIZJQm{I%F|`pUBT z(5R)4j@OczHe!^KFM5WrhXorc%4jSfwSXn)(-ur6VR1mmDD(!Jrmsh^l6ruoQy7d{ z9KncAjrCj%jy~*A(^6b90v>_@{w z{|7sHxem(}Dx*n%RE!7?zHo3TKwzfvL0dyJa5eCqJnt3D4`z0WM|;VSkBQc|z?|bC z6aq9nR!gR}Q0$-~5ElpHb_H9j*7So)qxbkhNPMZ_u>NVYDQZJgARer@K!B1S+tzf9x|mGS=7a1DZyXaEyqJxaq^EHMjqOdp!riTn(`O6aC8- zB1qtSnJ5~1^(Zu7e-`6m=l`kr1C<-XnU1l#mB9^hb9vCfQ67RxwXZ5Wn8^1~7{NAedD$rB{U)c~2*SejE?L;!|o z^fJKe(lEq_y;`JBlW-MVuJiCk(ngE@~gK zs4?71ZvGal&153v%)L{5T+er`a+BP(^XFwFzjk}`&`3^x&{p2YoBng`!X=&z7LN8N zp?I@?(b?zu)q0ZK-KwoxskL%*1bFMR&&=_s_d}41w;!KKaXzGjk7VWfFz0PJe3AWL zu)Q?`2b5MYiIFImJ$}Zv8bgu+7)gi|P)8q7m0$R?hjgfrRi9j%JXAHK1|Iws=9Rbd zFg)u*HAJ4!89#+Jsx14{2zLB2yzpr46!b$@@^G!>fR#L0l?c-J{j+`H+f$LB+?7iQVQWw;d5#dP#YQ#9vA*fw=3O}xa6$Ry-5BVl&0C# z94zAgeovTLKGm?_6B_jS@VODtK3tW1_3qc$HKHUpDZ-IGd7SzBI&_^ISm@gO+D)#a_Y1MYEO7(VzGg*8} zd0`LEF6~kHEHkTv(okkd#$Gin7fIPLqJ|g_7H_r6#G!UtJe$xD3q5dGUqbujh}S($jVtUDgxZ!~PIcpAM5EgE?;-ppvk&RLC68O#*WatT3q|-S zImukBa-3w2^HnFAPpB%OVcJ-(V}M7dS8x+^iPu4fHi9SQL%Yj3=sZ7E9cDh@24h zN?x`&k&qZ)u;~nejo}yF0TYbkbQzqS&QB?ohQ1nTE0FspGqfn3PGz%ScJFq7>2d@TF@zyYDb zL3oMIz`)m8(5EdZ0VxR?Jb1RE>bzIePM8jQsj&y%kq|7m=J|=QfgAI^U5!RLZ6`1- z+P*47y`G_-W`A0Ks zh6o1nGY5^f!JaI>&6qY4p=BI{A{3DbtXKp^Mp&uHVbq)%in5i&t1-e->DnDNATh*R z(pZ(72Bh-ZF%v2`R;BX(q_JpTyHk{|fB*L;!R$)fHX%PN(=MO^pzVoz@=v0iBH5!cB7Tlc#=!~{X?}dMZouKVTnYviRnrggXtJ6%-gPa zDGGgsPF4Z=`_jesgVO!F7=9^A>blroD;c7TEd*VR7oq~j*YT37!=-)}(8XLF*=n#M zUW8&Lr40G{if!sCF1fI2T{A&MIj}{SR(JNNI)hP`<^q@?X&};dQE3-UOJNscf(Js1 z|CJZ#6yuhphKde#@(CB$Ba*7|#?scIN#adu0?gaL&rF;%kk~ZpNc5u0S zpArYq3?~ygd@%d7{Xs&ahx3Mp;O2<2LZ&|y*7RU7AQbv!*qe{5kjQM*VDZ`~?H$?+ z6J~|qDhq41eWxs}wfn5sHsh7Ov#AEl$+x=R6U%Bhl-uTm(CL4YIhSyg6YgVzp#t5p{wB*1P z7VQQhiNXlU5h%H+@Yy zUA(WUY?gHby8RE_I~+d)))1gA4WHtI=?Tzwh{>P;2w7lPY-`*BZxHXfT#6KL^R*79 zB~4!GLtZGIoxyc0i5&cj?pMB}?pKzpbmiA_TVBY6Npptg6Yj)>BL@G}F{(r}_OsO* z@+})PG$b>^wb@-&d6R|f%Ola_^y~jut7{ujOOMms_$hdtL=~s{U+Jal%1dS2QOC?z z<+{AI`f1y_B)##FF;|Le>W<2QM4z6eGC27VMeC4kp9Ao&e)pCbo0UhCQ^PQGz8Re@ za|At^#O2+3`zoh>WCIs9bxY;+!OQ#At=l>MV-6Iuj@YQU=6!PVe9ccK!n@yuIe=sb ztOE(ITlJi@1M(8+Qq5U^94Mu%SGo1a0psO3pC!cg%=+X2ir`&+<@ejg!=u<`@T5G%cvIwaMS$U+(zpU`=UbQ zGiuzCNInZkqApb`Qh?}DVO9-|REp)Q?$svIqYAKIhoF*$9h?Lz^`p@)M`53fTKg&= zhDIts4jS#!^z8FGW3n4Bpt5$HV0(jF%G1L&jYiNzV1Zec@pfR`UPP`n`>TQ`4oQ1YIWzq{@;VUt$#%Z!84dJq??W|bt z`zOttqH^0ZEL1h$mYWt@EaAMiowTWSJdri&0GhbvsGB4z{GG@7iY&HjNVKBHYb7LO zq2#D%%FsIjDCr(m$r{Z=`W-{oG;Qb>xZvp1dMi%2u67_pMB{AoZ9wHH+|9s+S+XK% zDx3i{LkdXt-=eie6}x9gaY4nGqv0!4zt%L;%L=w+<(;jK%@D)LYp~ZxUb{(uUrjt0 z0GHE}Cu7Rn$A#m=?yM7{GWMJJ5`9p zk{6IN6igc_ekXhYcbRyJqIzwz1aq_;A9bmz_}rB|xwZ(P_e)|bH5Y%sB&Je>F^Dg~ zlMgfrMkAjjUSuwq$DJWdER#-X4 zVUk=;>`s*^xmY8CSoP?7J-S|3gzts@P;uVETT}U}>s8Z{-Z{jFwRirtEUei; zH$fti!Ie$yq7V{PYrn#!ubgW5^p2Nw4neVwSO%L9`n(Q1$vS5MXS3}e=?P}W!SF_T z{GnzR6s|TrJ9d=neGO>^jDDn@YxV%l0T@F*b!RUTJFKxwkEBBK8_%vD&=VTT{?fUr zJ~`Oz*+I^rvZb~w!zuLfOU20!m9pAY6T~+Q$jxc|Fk2gsG^bI{wl*GCpzvl>2lP>t zzFn?d`to*^9DTA^(*k8wk{5MFdy#y)D6gqc=2L8*oEldo(}{?HRhi}ssm6f^^p@!< zCD(#5i%qU+&!YHur@b{Uy;QouCI{ZfL={U{4iALwcyT^QLwx4`ugo>3&zhJP%&ElD zT&qA^kO#e~J4t{IR_|+aq(!rM%JBC{O_-1yk@BTj65xoUMX5tmC@nk=#KF`LHl9ye zHi`AGnmnJcgpMX>@R%THM)UPS&a9VXr<61!->;+@m82OpNi*6nX-GRQNz)yWG)S4( z;HZ?`g4e8+EI&J$TPi#COl%qzT8x_X>y}5q;?$PfoQ#VboM$p45E3T+M*gjGW#I@b zo*Ou@w$5P%z+ddGDtYV19FAE#{hbW+FuLmq(t~UAhvf70Gt0>bUOjP0743Ii{_j z`~^SNyx1_jn5&9eZxYdt`^!xDiHxITP}KdTjEiCMH0HwY-df?j;o)6X2{3Gw#*ooW z9~G%9MlT-qx)({YLI?C+;kb{C+c8WbtO*BW%DQtF4Gp-X(kmm=hYX{j((MFIA!;BdN25VRD zo#6Gsy%U-Q({l6y5-cK#PgQ86Di>Dl!yJ_~)wNW!!;+i3Y-57Hit(Pz)~$)q-4fZ$ z7E+qHfB(|r9BwM#Gp%PgTb!_^>4NiWIp7J^jlyi3G#}Fq2$83Rh8|K&hh*?OakyCz9~Q#<#AsZ#iBWl} zF4iVS<)zBlKQRxRU%^?HzZR?_Yb4uIzw5J@=J1NeuJU0NV`gMA2%PuLaDceUQ_+z~ zVSq#sBrT+vHsrNS%^xek9Iso!TprDYY}b$!R=Id6j)w*)udu1jOoG{102!F{Y)!c# z(ld)pr6_}Ohou4w=(S2&Qi>;FCKf(hj)teRPd$0(-yLQDRed8fS|>@@Jw{uAcjp7h z(Wl-J?9;E_lx}KUZqSDn9K9Jw)p*jT5Jf8xLL^Os_bXd+1J__8dUmx|Q?^2_^?586 z(IIMW9C@>lJ{zIaETqUr2sVrNa|hlF`GP!3>&+G z1KeiwgVF6B7xiC;aa@LIvR$CZ9n(K;95S~pHbbf%(H0YuuI=0oqJ&u3mq^X@^?xzT zxc(p4ZI$h)Qa$$>R#8-=GL`kIp1?kgm~)5y@&!;ELV^NRz7wkr_&`wSCe{Zf zQIg{O#9w2WR?SaVl33t0GWbvZWkv>D$}%G-6W=EP;eV&9hKQXFQ$tifObt=FNxKCu z`la1~;<#_<+;_y$_co*PC9H5>kF@8BoDZAiPB*rXJ`fHMoDRq7xGES|{Y+uteb@>H z2^XWK$so(wZD`j(F_~IK(Iw5xfZ1j_?TZnG<@-~7SqaMEOp1;nj;vnUl)(N|Fg=#p zl)#_sWi}-!OQ8(Ufvyg~m#9eKDi_f4vcVhCj?&@{2vg2}@eRJ`Bc@YC^e5cc=9};p z$j33>oH~HQ%bGu$QBZhee6#2Jm9izzJ%52XuyiSH!*J_U#fkxomZpu)1c9C)*3B(# zA3PJOR`r;3+KQhmi=()=;+@DXm-kd+QcuNEyh@iqYc$;~=oRVH62Ar&;#LG7u*mQE z3(&JCqacP&;Dz!T5~_{v_|F`moxfW~ge(FrSZrP{bf#a&h^G_mc~y30z1mHH6C z;bL17Kd4&j#;PrAGA~I8;;~ccp)=RDI_M_B2#iA{*^xyC$#l5&|How zb1AlQOqoOKp6RK`BqmYtl}t1x!w0WA;|d~^WD5jrq?dteP+>1KHP2lqK^mVH6jEzfSbFTb6)1t|Yzx&!*{K~}<|#~yqbq{# z>b_Safj8eMXY4ERTDd$ZvTNTeOY&O8hsD$rDf2dv1nQtZ+Ln}gN<@Y)wyaf~T<|2> zpFvoNJ@UDJkka;v)0#_9km~y~Uw)A4-w&460iW!JVRZzdf8VSQoc&?2y8dQg6s(R| z?C*)y9X=MTJ3NHd@v^H`r^M8P5tA0;gJMY`gngMl<@qN<{q#VPVE9`bUuhEV!S5djYvhk?9dRofx{NZZ za9ZS)H{>A`lLU+Lty`ELi6V8)!zaw3@?aFCV`WWAd2zq0`#(HtMTLN(3aqx+6ao_O zkby;*;>YyM-fD?O`4$)WmE4vuO51!TV;x}GzrM?&C?tox)B1~l`C~UxF6A+Lmu*BL z-j;6_IW(B4N!;z2iwz;v$QK&~6}{cR%AgP^y2gK78rW#Q$}pp8F-TPl2rqXC&qxha zPx!lQrMOv6dZykTO*o9Uu36W$>JFH|gehoQc9slGQ=Bs?aY1#Sbk&(RiE)#{>5CIM z9stS$Cqm>T*X&cLhv>EPJJ3(yTnU~6vpy%&NkeDoLbX?H%Ex~0IC{1kM~Vx2(z6+T zsb|lv)Uy>PcWQdJ^+&rQYyGivhNwyEH;n-A)OKbnfWg&o+n=V}q3So&yh8n+!@RGl z-zo7sngq;>QJv!2(q3bZ)Tx$$)4?TR+%sAMUZF>C>{Fv{3D|ZaFttNPi?0CJb!eGA z5SK^O*aEEu%k(YKf&#Ag`deXyDQZ{l3f#e|^ZjJjO1}Rk_auhTK`qsk0GtRjS;*FimOqnn!0bTQHEx9NgKRz2J8ov<@-nUQLcq2g9uvsT7@(?y6k5TBMOQWH%8$Pe6-X z&c1RK!|LgrI$e32@Ip26AywJZybSQ?zk{ouzYYqP#k=Lwy~ixo#l(kO{ASlvatxV| zFyEetLwg{NF({NwxE3QG${ppa^EIV~9Cpp`@8bgdBugW-;g>imw&OgdP#c&@7@DsE z%@;s(3qFHrIDS%19ji%*Kt|+v&dH<=PH6WKjM$+%LadIO0x>cuTO}GoF)Y^&#pUk~ zJC-f_A_I1;9YpEz0VK)C45iQNTbAr7n#&FrF@0bsp~~w2Xy`vgJlBl<<>nbfX)c!I ziaM}gF^X>u9|foI&Df?QA96!{!?3#MQT4^uFxx{3bJ*f4U=P7A0NR*`%a#hb=+Pk& zkJFoYLTsgclzZLE2-RTWR?RC$cy8{wk+-~+tu~|A7IXjBnq772m~9oPcsTEuIct)>C`SG<}1vG(jaEiIb~VK+qP zo?nF1I}THKb#%wx9?F!INF7eE0r4#=g^Ga5;Ncx!V7@NB5Yb*BNAr^I7pw6~;tMf- zg>r7`kV;p*U4=(&?yAEl*+-mw>SOzR>SH@^hd!zruVkQ)Ac{*?5~?GsFq9*xm(NG0YdGmF&j>Z1Ck?K?-^d3SLLfK(70cKkZea#-WOfx)+ z?G{VxS=Y+G61JyWOXN;m-?I?PBkOzZ?2tcW?c)6Du5j+a`O~J;ZBPT$SnCzW7t6|z z{>dCz?}>CdKzUX-y{_4AsUOQBLLB^7E43rVp|)aDx21~&*=}ttox|RY_NymJKEPR{ z?SjP%TS#$A4zHs#?#O;+XW$8Zpd}9NRrI5UR15pDJc>~_5!05T@z1|ge3Z$dU0di$ zwKk$<6?#!Tz_H{^iRz;;DfZcY&yt5F#eH@s0ahu}*}Ke)=Zxya7PpO2B*hXve88K+ zprWz3WRuvUSGUy6>4qwd!IYjl8$ir$h`rvmA@&-y9WRG98lP{hlaG+9Bp+ow5vrrp zic7S(i7JM!*gk;fPZ{p0gNTU2hm~|T6Ns1fZ9F@%BoOx2qNbbZ>C37DA z4=r=Zcl6?sIil)g%N$#2igXJ#Kx3ze3?i-7FiLY;k|!#9P9rUu1Mu7^s<_`F~N!>%)JEUH~y1IK3f~3h*8-J zKDR$yoo%J@Ec0t_gPUI#19ant0ds{cqs`*0lGj@sW?TUTJHztuh`gZ_lEqQaqogQx zQ9P*P?h+$$9r+aSI|>O^@w^KNe7ljq|DcQu#NSDwtw3}thFu^09JVffB4!JYW)jATF--a#gW7>LhVY4onAB+y%xNFgtRN1@?AWLtjWlF zD!q9U;|IP7wX`9YxLS+EqBO12fffclP;htI~DQ2GOXi%(20@2@s&VH}gX?pmr0 zuTyp`9mje@{4K9%A6_)fQ`xVztk#D|daX;7<@I&{N8TEe)jBvy%5n8M(-ACn7(^AQ zeA$7pLK$M&PWJp;qLEuO-Ej=GSfi2eL?LLB;ilwbo@aX$)u+%yjSL@5QXFX8{&*Ij z%%LzXg#=gK11Q1TYrfdt-dxtE0;!)%d?}aDQ|BPTr6tQi`&09Vbnmo$NammZVfhZE z~ztFVQAs?Ev}bm$BZEJuEmW4 zwy7ICwmEV>$AS|zT z{a^=o)z+3|PMR4DE9PFhW3w;5{Q7y#grs0&<>E{G6c%5iQ*Nql%Pxj+yNI9Z_Yz+$ z+@`q7z9po(IA(mt32jj@a3)fh+M2wlj_-w2yi{yU@|?`d_M{%%O-QO@V*><{shAVg zDTb;VKiMPW`6KY6tKXxaRk08W7TyV1p}BP zy;VBWarHJ3t}PsyG`raZ5GijYeB@#;J8PNu(hzD8#wBN??ebCYlUFp@$GKToiayY* zZ!$q3!JsuM_kiGQ+}hxXA0Ok%!rL6c5NH;6#)knB=eE>a2&v_eVmPk;u4L^qdk-j}oyCb^rlgxw{Y$K<3Z zRMq@NYGfN2Gd6@CdsBKagd%&Z^k4-|u7cp0jwwG@nJ^!p9H>MyI-{PE^T~3m*YlXHrbk9?HJ$E9QCNiJpg1vvv0ERZtf<_yE*P+k|Qp) zk&b8lUKD;W4!?`A7JEP*VJI;B%g7bx5WcUO^s_oG{p=8$x9O(R!O5oR_!M7FwbJVQ zRD&RzYEhq4Qd0c*5ccv@B`Y!dv#3|%ZR?1&#py^Hu>*feS*`<#1O@c9(6l|K*y+Ck`5!qab*WG0Wj5?5Sak~}3&SJrbt-zx-jljq3 z5pzo1B5;mt#%f3$Nmr?))N!z zbJK@E+*@7(o5d1yC^f~xs5X}7cs7N;VpEq2gO%a`r&Qpgz#wxecS2GS+mq}nyvh)p z&t4f2I!vy8Ahga&dMl*2FTHzja)ee@)<2P{$D$dctK531a*toL@)an5D55s`V;sl% z!Y@dO;}^?Au|Dl%i!(zFz#kt_yjWBNfu3qcktHw$0bs~bqK4y2g&F~yYRKdGRzt7* z2NCcy6r@FONAdY)WjsAc5Us>Cz&y%j)Pgk!AX7K$vFvy94*W8lwC`m< z2;oi*Ba^5rX;~On(=T`tw{z;oL}bXYNXh0bV)c0SKxe(@<;imNaxMX?rjVed>`eNU z63RE$qj*M{JBxU;LqB4Gi&>um%}!2=c*KgQ$f+IlQ-Co5*cG**YFeeFZEwCQM+BL2 zW#Y?JhHObJRy;=kX%co3Z>=GdeH&4mHhL5H%+9={*V0P-WG8R2>Z~M(M7>zL7$U^P zrE<4wLqZay8)1>2!%<|F7Bm0%Hedz6>5}LqTG+~YJuf)GH$5SoP)0{*V8htjFPMe) zY<~%Rc+$mz`e<1Zc?PrP?}8V+(yk)tfP! zRc|KQU#SXDwSAF3yUjrDeE_R&1!u_cNOsCLwy)y!NZA#Xg*FB;@b2X8omUcS`cIGi z(H$T9qpy7`rxtaQ@}iUdW3Vh20bS4*Bql7&5@UBQK(vpS!?=%^h&Nc)t@w`g_5GSb z1pS+~n--uLHG>L3&YrSya6->OH?n6#2fnvfYpnse{??8O7J3d{&yeaIZ(9o=Shn9} zS9wyRG_o1#5%gEPK!id}^!_ zQc{mwwBTmbcv^JgqOgOgwh@UUQ>AMAkSKz{hNO|Xh$@b(9;Lk22bCL@tGqvd#^X@zFY<-&-{r;Zf0)nD`^MbwO>j-{ zyD!PU8E8YbSat7e?bwn8D^-Qo_IqoEe;-E^df6~GwF*)+nA2xBZE88 z(A^exTwBcbxVmue(>%?XwL#UTGN3{WG4oDDCSYm6IF`oY;mS|w0j+b;m>2|6>&D8d zgBO`CBE02DebpqVjiQGrqCQpdaYz_nkSPSmVY~RJr*$Mjr|7ajSVU$grq^?3H;Y9A z7429YC29p^Wry{^&d{mpD`d(6O=|iI9Aps&7EI9x#jS-eR&9AIn$H{K_NRU-nq$nC z=H6sBQBr!?(!OLieLW0B&P(s^A!FUsT1`LbmlhCekzCL#bMs{jWFq%fBJo3N&qR@f z1JS@MLzMRp-!$;axM{%oS7YLQahY&LXJ7uOz)Ol8fDA+)%D+`bDI+z5nqv7AfrW6R zZ*R2921!z7!)bCa<2K^4YHC{p19m4xEj5nHteSz;IOHb7fDwMD1qKt*b!HNgOa=ru zgQ#O_3X@q(D@3W_ch3ThSnt`#_e*(bM*UYc0+ zjX8T@N;C^#kDJ?MF(9|uPJb{2r7QDAa|C|CU^JdMV|`O-(^^fTy=2orFx7@8HP)cY zwhW+-0FVw^Gfxpx6RepfE-iT3{C7v2Oav*pwMzoM6R*4lhiYz?NcOJm77>X`L*&#^ z2m~24iAoe|fcGI0reb~O2|S)2VulnKinYx{Yqmyb{J>3_7L&G^+qSyGJ5WbSX(oUPjcU%I=n=JGen`su`8YrY6 z&Em4YI_G>MChTU%8iP~u2}w2bB#EZM-1qAD#%&x7 z9CFm!M1*RX0I#$r%Fd+a}qQW+;hFL*_{XX zyzi&4>vioL(KfK|a*QSkb;s&?9K~r|4mFEgAp@}q@XlwR16St23av^Tu|os%x@UcN zw|)&NJTVlrNK?#8b|5H0AD}iM$^1p*<2_cgzgF^2D-i}*56vQx$lZ&I0XJ^S@KDQE z@x!WkqJ)c~hp4&V_l6Ey!Q{{&6DzB-U4hB9{d94R4(Vl*0b+l(Lur!9EeYp?@o(r>`Zm7UJn0+ap zQwAcOR5g%Etc4Cco`Hy#j$Q(4D-#w_DkMD9N`>aB%Jhkd7hd_tj#~x$0S^8;`vE-B zn9OmZnx@Ws>Xl?)3+IMOf;pm;BFrJ~h-8HlV_t|%012&7qAbo$S?D6vRLz=@JFy(S zg@uu0ia}30IL~Ar7gaqujb0l>QI!p%XsB+8QDmyPFnCY_Q<+s$Q@~V4uM$L|q^cM( zH`9J|a>(wJU2*okJ_1MI=Ly}R1SX3yM|5}m<=DDJOJfM!Bzq+A8@LyY3!RbTU3eAs zdvj~Lqkhh$Pxy|^;OvXCNrK!RUq=kjXo>a!PNa+2p6!pIn&oEp<XMm(i#=g{KqjE^HCWJ=<%;YDBYO7bFRr8YrYBgm22%RGoa% zzBZCfFz|Hni3v>{PmRla?M+GnfI6EK#JZ_hJDLP1i1;r~s=__;#eNr(KTj!!%NzNT zh8Xn#SoSw=M|1QW=bez{KYYRNcN5PHNar};c;#e9 zGAdtbQ=I!udTvy;sn6C<9bG-kqUOg~6w8ESl6n?1Czj7_3Duuzi7~=Ia3Kju7LdH2 z><;5nVtkr4Sc)To>Q;fXBWkwp+q~AR!@xFqE5zpu&@ogSnV;B|s}EkaF*b24FRXDp zY5rbVg{))=J6ojlP3&w1Xo6>eR@x=7nP1CZW0(=C?;VL5?7LOa1< zW~#g82`zP)QLn&N_o=uRK6(Xu2`90?wx;B0B#ZAxXLO}R zT5eFwe6ZQUz{x*cVsJx@K#Hr3bNo)O3|Og@*JxB*fpphsR9nIAs>XOnrOXz0m4!}~ z_U651q0^BSl1HIZC0zRj{+VgL)C)1pC#mA%0zKenj&RYz!$u=)pAB5kvP^%QDmkVd>K2*{{%De1MGgw!cft0#&;dU{?60cj2= zaI>LZJ5m@Fd1B<<@=u(kVwwZWSmrF=FQH1Ho8_%o;G|QVQyh*fNSgrFZqdjdbFwhk zk)v#lp}Qavm{tf971o5r^D0Q95HVlUEuBGmz);IGhgsZ>s9&y^^eyeo*CQ0)7Z-G* z_w;P71$F;__TE3ruB*E9y!XEM>Q&WyRrN~0E&0cN5A}3uwLPe_+_oE7GrF|`m?4=! zmY0`jE&lKy{NW|Jd$5P`VrFDp!2$%hJ0c-LfV(3TgGFL>i^edbF(8POD8U2)b|b(^ z)WHcNKyVV0n1oE`^WFQLbMJdqW&JQt(lc1g_3l0Q-t%MsI(zT4&pvWZ^Q%)~j)svq( zv5y2ggZF9Uu=k1Dst^CgrzswIaj^^U{3BW%3%N-IZZv=lSc)BD+GL5ilu=pYt@I|5475K~!G$(Q>W(Bl?l5V%RyH9Iav z<_Fn2_LRAAXqTkGo~!gcg8?7Y(t~XsLR{5Ol^CG!jma33Yg39@XzxML%r0R~3*CdTQ~o z${)sf=(gxyG?!G$K758D;0vAO|MV0$f%@p9I+lwkcHrC|`Tqa*E9G6)8d{ly|FEva zAZ8zw!It>HA>me0nQEzPR$_qQbCtTtTxE|6x!&pI@raX$>wd{>J1#&0a|4nvk99S8 zzk|fl<;+MG5Thw@5GhIuIkY&hmdxmKi#+`&xJ6z%r`4v%9RZrfWy&1@^Mw59`Oq%U z*kz&8Z`&mjMIK*sr9ALo%s;tbW%Oa+;qMT+_poHnBadtT@Y$n}6nsd9Ao@u7T+Y5~ z6WQeS%Xmyvf9eUV?gwIdyY>ps6#F>{7s9F@e%BZFp`=vB%SP>OOT`9RV7!YQAmU2S z*0Z0W<7Imrg%YFrA}JB}Wg$j_6)ZP>5X|ZLcsG1b+sP7clK5nGs!`%5kBiP|xddSs zY>nB;xrLTcuWo@nR+(Zb1wX#DY6KbCE+C#UafVnxJSg*9{e}K5AF>ra!rZSyQMwLf z3xumr$sqwJ7RU%h1FxLO7w<7hc+=nJ3uQ7)lprjS5m~JGPGGu{Dh$p$0W(1}i9iZn zI)T_Z4Nf35xJ+U-Bap`(qlrKce)qfxgwHRAK#D*hO4fl3K?DL+7)~URb|8>WB#51M$4x)PtTMvvq$Pr+JP_43si`l{>}nGia9Cq`@#vV6WP zw)pquBY8+XIQWubm#s<-QKqx@Rz|OwmObrVmRLA|a98>aUw9bzsjRNs7et$DM}{ly z=TujsoUYXt#IPAPKWv>@U2$_WhE13j-CX<(VH3Vm>X=!v`bjlf_8qg;R5lqSpfU?6 zK!1(1wJly^YN_h9NafK9XwyXC=z%E``R!b&iu`s|iZB~x%~!)%J{P@%=sBO1mMv8i zsnFCoQEA3Bb!nj6T<089M8hKfGFu88L}%{6r1tjBM}{-x7Lzi!K>IOH@z(PT7s5Zb zicQJLlU12TtCA*+1X0OCE<`(aw#g5-tQxEOEuvhr?3yfd-pPy@O+Tu;d+&LMRrZ9H ze{PU?b_p$T~id}QbA1#kgqvEKx!|%uR1BCh$XbTSnzo47|dRG z;(Wnlr>QW2M_bV;00T3p)cNv+Ld7sz`Lnel!V|4R!E4eVW3G;+JaZ4+I-L_z)*;ti zVfp5YyF$jfV{;d<=_v}Ki~mg_X#FgNpiR%rdK8)&wO9b=yTQmIk_4x2Je zc?>2K=^sWCd06gYK4?{hMaR{X>Oe;(9EAi=j}@AkKulyTl&NvQbh6kmGak+Sj0+CL zUq`Ai>v>b-M+W}DGSQ^jENAbGcig}K%r7Er^xgS=4-Y9on*ENn{T1cO)3>KO%#pW3 zbzGn9jHYBspx2|`=D_RF-F_I-Nlp~$3SRscIOnYcQ7qaC9Ttr{H~9CqWd1^<5t{j8 zZ02~QnPZ*N^mA%vJ~Z>+s~JV%J?_nD47ZGID6jJ_`s#s*O3yqUtfAfpuzcXqZ~fvA zkY)AJ+5)BKd?{HFgsfo$7#GcDmXn0r9@aaM3p60@K#>xa1vp}gW?S|%#Y zdY~2`4K1SkT7*78xwRG=wJC#++L591W6%KPp^M0GkT8`yI1$WBDz#8E)rua7BC@|{F!_mbB z0*%OdeiCil`KEpQXs(tI0_0K#EKh2XhGOXkpY3q%!dX{Fze7mis*Fe;Dq`#uv(@5M zIx0v)39M-?z|N$m;lcZDE59*$5v4V>ILBIB$L&au;e3~v&za^y6XuRBTCqB*FvF3Cs!(ptVAX{H! zR_6rp;WWSU-kUo?<6`f`z4}~~IZ5Pd4#(m+onxOjsaF&mB@ERFDEA8}&CCCWOFz?uUqso~5$JQGi9h9wDZ&cJcusoMI8y990 zAxUO5mO52#iia@PSngE031O8ty0B9HpraS6etw;dCXHl5@i}jeWYu<~M)KdO zU1USlNJM~)sum5l4j|}%<4w*XJS{!xMW2&-E%qVDZ{TcXFUgcwC0pjUS2HFT!SmqP zHIvV64=?^knAe4PqX13N<0{KR=-yNoX&WI!1_H-AB*I~hqCV0PO~YnIJz(CPX$qv# ztT#&i9uon7k;0tXnYA?2tk68@6`wHbRdk<|^u}}_jajfw>!X?jRp3ifG@^D@Q0qC> z{d{eq2kJxhLGJ3Veu%p?A}LiTLjRDaQjB6(->rs_5>bRTm86@XSU~@9!!S<5obty^ zNm_zVO-WixO417YGs2*eoBIFs0(G2PBuJ}RX@wjzc5G@j2d!ikg=WJ3NHZ5oFVnx- zAD03k){S-Sz9&idzdLxM&^u7So z$o=r)sNosyALq{E`*o*H(>J|17rUduW)JF@1P;HfUsDCMU$x8Xt9DcrhY@irxwT^c zKQOhsy64?ea%Y2*t3K*Y`WV9qnO}|t4K^r7j3;WXJK!F4Mo0-MSOm>c{DQzQJ`jng-6aGz^yEGwl=`hHu1Id=6b>|PNq6$eHwhf*PtN5;)sg)#-h!R1d zxR#VeQmYCY8aj}nK>{g=z$lTd^`_90VDiF7Js(SjjTS#mA(`K$(u1W1z1n{>X zV#%ti%|1s&_@HJ2Lr_xI>T;+dyX9G}yFZY~73>b@m{2f;1w|`K`n1Uqv-jX2tgfCV zO4sopSa4)AG);*!sjB>rk~QOQ<#C%DYmD1u!GR+K%t*_wA5AH4lh-A@xh8HCuTGh> z^2$NiM}PBC8GSmdHaA1%pjIe*F}|`$7(-pRBquMOyENd;IqZGW6khOH^^0ly`+=ARTNEZS|hQ^3#9ziFg0icTPY2ho)P^UV+}hd+s$JmE3LiRvwmVD9_|L8~%S=%Rf;- z!OZS*58&ZL5z+YG72Lwvhop=GsAKFRBW*wXSKwI5v~IQK*6Nns?%*Iupc9WL>nfLv zWiH!4)Y?eXFoXFA0f+{^z=-aXP~W0X7Zq7;a;0xf5nw}`XRr>;Riu2|hxKR$cA73{ zAJ*Wcae3##Vcu*b`mWVSTlr)}`fW@s<82$PrhGo(qfYW4_;-!^+EFgCEjF#sU&R<8 zF-DOS;RR}k3-nJ63OJvW`Cg!Ds=hAOEZLRv_;^O2S*|>z&mxF3vkU)P5%ka*BM^Pt z=W2s}JI593t@&+)YF)*xuK>{Gz9^FuE3~R)+qv_!J+QG+l^ugC?22Qk=r(DfSQh#!{5+c(L&*BI?&1AcoZFI(#;({sCAv{peeBqyry-qs()L+D}BL> zDD8!c7@009c)sCcKEO-D_qQZkBCI4;9a?(y`{89>f4%YHpj`CRQ62Dur^2%f^tt-i zP=X)X<&wnpZh3Gg^zM*$jd6ud(NU-xY<-SQH7@z$xa=`oA*m;UzHN#Txm?itq;Q81 zN8(fnXt)ax=}4JSyuw>(mZd&eL%C76CrLu`^wUNXtEk03&WL?u5mSrxQB5iucC;CT ziafsP0cre^v%XcKc#q_S66N6EjsdLBheUeR-kydR%58<0+abRir^j_rLmk%`}=MC`yKraNSlPe z#*b6}=41jDoAIsDE&O0CKQ+>)`}**QI(KV>EZ=;$v>9=G{2e zOXtlNz8G_oPu4}dk;5uFVrwY>V%7n6NOqZlsn{58YSapnTqe#G6pgb31r0_3hZHpE z-?s=QZ`oRG_?S>6T)S*KoZCDdtQw1Aj#8g)3@+GNF0D=qbG3Cy`aKry-Y)xWSeR*c zf)zjjNy~A@Znkwn`X69|pd46(dm1qb5R&->Z8b|{oYWl0zBF&5zg3%mqp3miD2|HC zPT#`v3_+5s)~Uc{-ymD}%4PtcD_yG&(?3M_FN%x=zFJUI@8ll8D*Ky`kbhP7*By_n z{eDLo=U99iJ9-s`cbLdcI>V%asXYQHWgNnY8WU2dm}6Jy{Bt3nGq|9fn%wruux`>C zYk3qjXicfyR-v_XEe{1!)1VGRX0B1-;|Bwp`cfnb7P}M`U~wo{wzEfrHgZBr6)acg z1a`f@4o6nR2UHe=1?AD!Hd?(3Y^8u=+`M8A&oh(J>sT9pN)=8aeF#sNJI90!(4Ru! z57mex?F_UZBj9Fnr#KGiy2<_ z0~TmMtiEvleHLi3owyFO&B&6H+G>YDag67u!@D2myRU_Qs>K0q={#}!l8!Ctp7W4> zRe??nSnKreEcn`jIwn!?0@bs+B71Jqj;I39iaaVr-IA#(hz3hyqs7h`+Mu~u;fnw%B{-RLvy#73|Tai<(KTKod^P*`k8r?qw-ss+PCQ==uwyA2olK29I_x%ojQ+W8N=BBH6{Kli^Dl%Dg7&nnw_V|TdJJ%GX zNlGfT&k)x6G!!43Pf#{CO}Jx&b@(*EasMR1-bX>PB7=+KJ>BX!!zBi+KnY_%BkyNA z2v2?EFuXd6%Z&DgjDzuq55#3`yy)}NqV;<&pIo(m7Jt{W1U{X#gpJYD@-EE?Atb!z ziJQ&SLYU19!kl=E=Ol2gEN%__3!yJ~XvkaA@X&ZFYP~%OUS8X~cZz~p2j*M++sDL2 zgBNALtzUU}Sjw<1fMVrIg+;3fMlxv?A<{?ES6A0ov~A^Zq^6RVRC{}H#N#Wf{h|S* z)oRY^tf7)mW+oE&lf0MQcm`Q;33#yVM1RAHji!=oqL96a+Zv))KrocU!Neg7(Bu~# zaq=FMR2Y+9?r!~t1PkTv*>?f5gcwR94Dl327&`#5T@QQOG2+VHjTXJa{#JEJ(d6vw zH=$OY=pc>H`Zbv2a5UkBa3F2mfc|lmn*CZGc_{4_PCp5>dT?QWzXVaT^x`QcnNmvV*^CLR#rdzdcn{VZXR^-@f z!p!*#K1uCp?Ha8wJ2#j$M7id*RyNvDwr?o;^XhGEIX2w#R}=24CMgx%skiSeyGQRF z{GqAw_sS!vIavfVc!#%Uj`8ocaM*i>mZu0nx?k@+l~t$Sj9~xQqwby;G1F57Fp!LL z0zH+zQqx7X@4k<82XC>Olupb?|AWQ~HNbc#C60;|X=lcJH-wcC0N{c!ST07e%*wpw zxJ#%}RH7F)Nc%`CY#@u7&;!{N>U~XEXI}zg*Dz&M2f(X?09Xrnqx4NX$;Q$^7`-@a zO&ZAm3q*?`zlqGB)B~Nz01}f4_Mya^ubP27U+2Pcf17I8)W~+uLW^1uX49Ue^!wV-WVgUBh?P) z61&=IC!e)BZn=8^2AWFCGd9(nffIs%%#4p~3T5#i_RO+)AoM+p2h8u$Hq*61M>IY5 zNpW_(qZidV`}WHD zxEWfVc2UCxZ!~0%m79!Gd4uNlzLA>BYndj1v&a|wuwwpm>RVy3L$BV4!Q1|=clSC9 zByX{DN}NuE@4n5;k=myMVz0Zlb&^Zd=ADwu!6zJtUgit!LS*!tMVTGF=V}AZ-)P`e zBU50ueC;m`?Fb-=2LOn74l5y8(aRyg3|+cR``S=A!UW` zv^mu9U?eFf^YEPBx@L?Z_Q!NdOG{bU-C{bziajkl4oaXzz{f2(kC~%91AVTDuB_G9 zEjP+`w-nql9Xa=C*({Qof3pdEB2ZU55A3s1WpS-0>&wq5>^Hje@OgFz&r9z?TOnk& z8DDF`-ybsU)GICYHSM{{#+0h_?W;C1U1VP^a|J8~PQmbCwN>YQeAO9aCK)p0E-WXq z@fZt^5O}_b47jEB^ctFD0K{5d4cQ-_MD~IRXw8TXkrH%i=e@f6u!5@2H_BE=uUsUN z&(TMENndOuB{c23`>Aj3ZELc08h$`qyGdN+dm0HP!;fK+o$A}Ohv$KO#Jep!CVQ8U z-pM5BOOoMXT$5CHZ?Zigjb0!L&aRG_Z%rabo5C(?PSccoj{O*GjK$*+8xNafVMj2y zN8@dZl$%y1vae02gK{q)Va2fF z9hMy=a##7_D{o@prstT~lhf(iyQ|OH9+En5$LX2f)wkc<46n0~UB}P|wOOo6-9FMs zbve36b_ymrf|pF!r%C*FTplxC3tf3KI;w?CmK6&vNXoXnx3GASRtlkz&+vc>-F>~I zcyeYay~B$6Wj48&+!hL>fFxM$w|&{EXAah6HmKaRCL6!^9q9wa zyjuTCOBKP+?yx$l;L*WjQC&R%u#Gqi?Eodjqndg>>s$;=AsIHwf}6NEON;D!B*A{5 z2uLMl$_~sdM9egPq^}nWU)xpZaR}P}8Y|ryz)77RDQ%_F*aB+eI1JN_&+2w%ywGV* zr`jeBiD@td2tgAB(VZX$>F+DCEes3W)@T=<4?y+tklg3(Qo7Q%4iQ@W=<=Bl&)>Ct{F`6@^=z+jX85 zu3D7QDlM{l&+mL*ZW`S|msr&5r|nvqh#dzPP4NS!U?``H<{s9A1pK-8iaZN0LO$3{ z(Yw_lvqtZ4l;}0%&v(~_5-sn5IYEMUYWdOtE{VB$CUq?t;JPV}jySw)`Hdg=;+w8$ zWGePfQR(0p-sMCDV9a>(lvi6Uh6#_=jQKZ+5EYkxPp;hRaD9$U_3at4usm8xUg7tG zOwp-)C+A+VnFyD?0z@t<^)Zf)GdfYM@7pT`G8g|R8Z{qBUjLh5YKi2>+kLc;Tp2uQ z3?SdV)X3I!J#+8V8F0NM^N1zLS;GQDhsMQj%23iwSyh{-!+AizJjuDU_g7 zB=~f?Ib|gBP12NwknifGmHgL62?6L%G+(I;MKoVvZc*qY2go%JEx4;XZQcbA8%>Und4Rsyfe@lCG^P`b!0Q^p7o>w z)H~EkvX3~ts8qsVc)4+(1Q|KR;o5!9pfGwrgrTleKA4QiKjz?P) zMpVwX+bHMf(y?+{B=A-ZUp`iT#qQA+l=D+I+-)`w9sn_Zm(sEn4y1cwBT$SY&%`P1v z<&0@KOcN)=+y}r!bRp8&dbc5*f6BggBO!YGSU*lhQ**cu3mqnf=FqJkA%?Q6z~_?l zs&0S~J7xa{{dx5$m%o?N8+Cgl(W7&1XT)RZgMkr`a9K0rp{}pE*b9Sq;-Ht9ntaEZ z^Vzp9&51~_tu+xHlTXJR;GB7aeWLVR{r_Sii5G~;0`TO=YRbnAh}6!v!}ke`~b zvHgsd{O)`$w4b(;C+ZU6{&V=m&*o}zskm=U?ot-ocP-TY{Rptwu5Ctq%*+g$Ph|G% zRzmZEm0Q&(tmLfC5UKDZD%?Ta?!I$Wo&w{vQ=~T11?y2}wml#-z&$j45`^@uYC6~* z&N!CEcwmg}5K^^4jP@A#dB|+D=pwg^>Sm_rs&j|3zOv)tw&7;`v>IYCscH16;a6+9e!N`bZ8Dv*)(3qF=SCjsXJDRWv35xXarueX{hr2kRw(;fh zyW`UhdU_b)G~am4KG;z6!nSgHZ#l0!PAuFu;+z`P9*Kgzd+jt0bl4fSF2FJL{-d?0nKMqs-V##JQNLP;bL=Vk}Cw322ze@&!^LuzUq+KG=hE>Gh}PVi*|+2f3mRuMRBCNeC%secaPM%!oiTM}IBfyZ!>SaUb9V<6$&%Rw947@)b4Z-bVNuvN0@V|C`kCm zM$_p0fNszyf~(8t4mfIHt}c-*3P6#}#Io2nY@2+icO1OgMe4EPv?o87Qkb-Xp}a>M zK$0H<$JMlKu?-Go38EX3L7i7`6Hx(Orom1k!AYa6ZzrrBgNaRl#60RZ7saNn5hUE(GUj zq^`W!8ixx}2>=qbaJgH&Tg>K1VMfO(jGgfQw1+IGB7wWZsg`wxL&$A6BImT*Zp6_7 z^RNzLSB74GbTBP1>w9fORNTlEc`yl@;|GVI5|c#q2MMdrBMe+zNHaZ#{x8pw`H7@3 z@KkoW@c%Yh@!Im}D4JUnMXuyxH@gQD$WNX7-BNxcjgWnoBSPJ#lamw?V&NQILTz9b0{BR;akGT#Z?^s*I_0uQAXpAY9rx-{;acOrECAC}(r?ibr z{F5dnn&KXvM}*3%Xu~d3;acL}tg!R2Y}~G)V!-5G9aHSj#u=qyoKz~b&NOY96?Tru z-fbASnPNoLq%8vmeaSkANQuG=vuM0OOcAcnxlw~nl}etYMPr;NneC$1f^>ZfM9(%y z5~fSz#2ypQb66$5`@1cvBx#E*m9*tY(iXK^(w4VOfk$oMLpTIKQQAtIDw14qs$Er~ z@`Kp)dMzp^)hK^Qlt>`l;9f~%4GXomk6A>oTzi{N?M+tTa{0Kn3G3aYi5q!4g9Z9A zX_2&Z*K}O~9qG!I7X*+1+7v)gvp*X|0kovAJz1tz5G>}eSwp1gne;|epDilb z5boN?B=mjftSgqX15M5jYcV6A%Q?kN#ZFCE9GWg4@!JZQj|x}F8x^i4Z{n)d#KM`g z$(rh=CMbpyo!7#Pbw#vMmrIf~S5nWRUUqBsva4f`e_hKqNAUw`$@>I}RI7Xb({__a zKrJYpSm0p~y3|gkheqwho^ErF4XIJUsHvZ@j1H^CF=5>lK!TT3=67t!*xG{_+tMwR z*sYH`HdW%`;9B9>TCshc_O*g5Kdx!ildI4ye@rYqI=2}TR>H{FXsL@us@hw~Jz(}0 zR<0Imxm@13=4zpP$V^wSeaW`R-DlYtt_CzLZT4*0-w%UBm3JW16m&?P*#SnT^#xjf zd*M!~k2@>45Hm}Xz48ZtrGMA*;Sc@a|Ko~_ctfbXKV^?WLlO(6t*JM|HP_v~3&RXo6mIY|<;@EXM zvTN@-vTG?vmYcpSdDVQ65(8mnBrvw)I_M8Nvf7!*r#WdEk^-U3L@{MB_H={EWiW}b z2+K%e8qX_}y8;LPo*yP>HD(niKdgmJs)9DVJEH+2Rk%pPgtFg&~x7oNuQF1`itb@EViMBE!32#Cyl&?@5KXDr)~(w zOk2u16CP^Z3-d#LojJ%gs@Tu!cdFj(J`kJF7QvyLH+{-pZo{>oR|MVm_}iB|Ewu%(4?<{AU54wO9mZ_>hv*6l?}Kuf34gCOL7~| z+hIyJ;B$L!9n^zglxNR3xgLRB*YK60NfB4JQCX-q#_UttFChTPnJc!n;9achXNhB*wm)`oi17^+Od%FFmb|2bQz&aXCm<oSQA~NoCkWouF-kds$j7*Z!+KL@qhR9muqK){6!2h`0Cwz zw8AwZk2G$G6Zz_1&oLK;1)T_!Gv_3EKM64L2Oa#r7gx^~EyOmWKjeKeh;UW^*OpnG` z_>#l)7JbR}>|j3I^lEZ2k7;mmwaeD%mJfZMaFKz+MfUCcTMrlcUfaV(HaDY1&OGtu zQ;ld53pqx~JD@eO^Is|C<&E`v;-(8&Km+2Yh9d7SZXL~o6se<*85sl1_+n|@&AbfV zlxY}y(OfuWi>~7%)L=RW^S`2E8VYroBE1H~)5H>Cth*jzh$acGTBgVtR-)RLj1C#m zlI)sBSP83(go)TZ%R3hwR$^fb$u4Tlr-Bzo#n^nRvNh+^U>Ak?lwjhO^QofLJ^osY zmp;Q#^v~*9Tmsu#eMy?JO^dQt3FB={<2&3O3)A@3{s>2?l67ht?{ekII{l0f%}^|< ziLIK`I3*MA7oXT=ilHNhaCkXA%`x9xI#nSZ8(%tAAtPYNa=o4^!{2?QRyUeKD_24a z^KsABjDZctG8h@ATB0&8?GQ*!u)*STq)e&-GC}mDp$7ai9;MpiA~uq6@(FWG{&|^M z@6zwwHQCSWR~ln+ZT4QfuA;g1b6sP6hBo*s1=dP?H+r2KJYc7PSwH0<{H{IbYuoFy z!B*&lAS=T`mKu(rW{y!*XdI}f7zbZTv?e7?<5FlE@Yz)8fdlrrDm2_U@uZhe+RG|* zNvW6BtXwdsWW=+z{2~2ff1(s+NA0@$2p*m}ZAZ-r*NMm&rt;Rs& z+DQfqa$$9abew@$;J6qDN^IL;pv1Q4!9d2h&jSOwCIuo-*cSfp?j1`7M> zo{fPHiRcL~3o($MG#Kbxpt)wCr@33fK(^}$2Ks&NK7xV1 zreEmmIP>?{?K&~gSGkoO3+yw?o#y_?J{AI%#9>1SUoZ`g8#Sxa(6bsfbZkv&7-gZz zX@x8dG&YXPK#Z%RQoBt|7Mtvf0rD2Yi}+}45Hh7hjtxlSO%;Kr#~fL*uCy8_N7k413xRw|zkx8mX4gr` ze39D#1(C-=50GLbzczMQFo(;)tr9(=R+D=u6Ba!vk-08DaW!MwpZq}}UsMQtQ?n9p zhNrrtMz2LZBW}8XZEjThm`~8^*D1dgqSO*N4>rH<5aGf9qdNp$@c*EJ9Mp8d)Tv#4 z!chvIvRQ=JsZgYmJa1}?(SIU@hxs_Y&<9*Q7;U~4;A@#4Fd5!=ecC1l`X5?q6#8W2 z_NEl|u~68QqAFZV4Kdb(vK=@vdfv%UYuUa-?*wO=`zAK;MI=cJ zV({>KjWaMogE}2qjw4?fsf zHGSbSG*?L|bnsZAwn+P%4jUD!S5O}!P}k~5&`4@Z{D@Ja8!b#M3r>k59vuVx^0}hN z5?9A#96V+LZ{Vs4A$}F6x2$;XgR*H9JZozs&XSn(=3ECAFOwjW% zo`a$hbJp0_YRRyV0s1_>zUHnvOAI5?9!6Zd&wJ_PHJxlTqF+h)`M|hJ#}Oe0EG>d6 zKpXc`H-BLg3adm?*9>MX3xBH~;R)+-X7L3@W8qw20ew?K<}NgSLM?^fhEnvQ`D zaosQE$9#L*;1@y(=S&V9&l_^!k@HIp<9fJQ&E{_*)}`_IB0@t%2EUK7r!Cd#o4+@& zNY7*9&v##xn$YgRFX&hRS)Y_ws757U`oP%x#}| zj#j39;)q3~f_ak)N&}#a#x?*c(S{;KHWv+q>xrRNPaLfQ;d)}EpeIrBa32Uyj5qYe zdBc2pHu@p;_88b*^hwYS1i?-owql!OG&2nDd818-rk~*R z@HAhtQIsHoAOUC?B~e@A2&Pd+^6cur|Wtw{M*-bCo^4|4l8Gop|~$dX1G5HrD>kJs)i>l~`~z#OKC`z;S!xuPG0cA0Rr z#C0btC!~9@&E?~HCTx3}Q1HXpo(4kMQZ^$j*02FoXJ?`?ZYdj3=%yWdVcRi@V!M${ z7(MODR9}qg)ODUJMMm#VT`5JzpKDD{7y!XF^N!=3=LsnnN(BL*M+#S@OX7PNvL(nPNd({zTCS9kPOTb-_U^m`w$|Uii&{R+SH1tSk~1Nfu-%>P1=3lx`@`6wm_d z4zwgqIeS;$A?gBiUV!(`T1y2u@T@;xz@}EJZO2Y~D9e0{Zo>s})vd*qN49W;q9^<- zsxOX5(iGK!mU(CzD}P1x3pT3DY#{Vci+drA=9JDFO<^<#)P%bYn~iyXPtSb7sbWy1 z?S`O^vUp*BD(tKfZ%U|V;%n05>k6`TsMwuWwbWq?OVMM|d+4y>U@t+4US>o^86jr> z_+ewq%Fh`#r{K&B1`m|Yu|tj#aHC}>pI)^Jo>!+^g7?tz36zIZ_>yq(uKZ_oz^C&w zGsZ}rsV>Hb2#MWEIsx18GVEB=bD_lCCW4=6hU<>@i=Rg?R@Oyk8Kx%UlN+@^ zW3`i}mnx4~?TCUOQtehF?a@XW4YM_nnX>kj)TSeK`FU%vP~seVK&z<-XRQZa>%n#E z07Uio*nvXH<46bG=n+C3m~g;#S;$LCjJS7JY~T|pQdm==XiVbg6s~{WDoc!Y-J{FB z5G_3v+LY*pwCOLJ`R8RjW0|WIRwL7?zvr^b%F0-lEQ!o^#Txk{8YSrL#WU8jSibSK zB9{EkMl-^S7dHB%ld8P1(eZsytQYRA8)B-a5LRi9`&cS$d=5#6HyaHdPKAvw9ZH3b z&ZF3e&l|&pIfaBn0SR!EZqLYPDxBCSXHY;IpPWjCjml4_!bUgvkQViMqr+!YVPj}d zr@{tgj%d~vBR3&~!#NZ-K9`{JHyaHdOofdupm3LC?O(FKYl0TgHK9dO<3 z%;{9v=nOPN6MD1JnUkro(U}veu+f?0sj$%*cwU`(oufs1kyx+U6{$v6*64{uw3RhF zvM-i3`tgi4NqvoOJRQp#y@1cv3yw@M{S@*vi_nt*6zKR_EJWVKqS#lAgJm+B=)) zt&~B#yJwVpxg%emQyF5 zLrd~Ay1}LZ`pu8dot9RH?uyHXdMLz}oIGXB3vAs>FGMp=3e5=bMWZ6GB)*VWXS!jW zWzqW|@;nao#MnR?Rz`-y!2|DMR9kJFA>fheHCE6&TIB8c{h*=dbL`|JG6hC0GaK#D zGqzrbfGEK%dV-|eF8`b?1=ib?Gr<(nq8hNWvfqxNA_q){U8YnpBTiXGE83BT{9Xq8 ze$VhrX17Dc?zHzE$0d!Ag$CJ}KX&UNganYz*84tWf zWws$%W!XrsH>SAv$?OHYsz+l@J6IS(0P{j`@KFIH>%H%v=AFAmBG2t#nL$VMSLQ`o zw%V6pcImdQmu%U*Y2$|V>lOzK^K<>)>`bZurn~ktRhFHsx3Wp&5~q{-8B5^4G}WEP zddV;-24506b2+FlH|!ofu2L4{|t5&MrS8fR6QJ z?VGg*F%A*lGD}VAhNk~X{!cJVJ5vS>+gSF}x$QP+^`mY)JbJ;}k49@h8m{ul(jb31 zf!+x1rE?`@tOG+zBfZ!@RG0Z#=OYXH5Kj1Dm?O*jxBC7gJ~Z3HNHg`_4ODwkNtWbz zrz#ta4s1}q+CI%)VNxeH7vFg4+~uouJi<Q@rUn)pR3gxvBr&Rg%;}s38fmvm&W34v9*LEO(wb#MLnI}ip#o%=qmG3$4Si* z*+KLT^~#1@hb_I}|J=dT&ax~=erlrhEIFb`yw(hM9pPE@Nl2>Lt7-&;&q`Z#q4;4q7=hRkdC@wWzhVL|uf8Ws6+*c8&U*PTiZok)&?~Wtm;=+gvEAq( zyt9*f0f6zo$Sij%)ev3(h-cHRSbyBQ{2j}zKS5q=KeXD6x})Ts(q^AP zWF}lzz<8%2Y6XZ-$j1bZ$;CT1(P$Y$n|?QqO)_B^5@Z@iwkhNMuK)mTE6sd|!T880 zM?cNzFS(?3$t7X>h85-h1sGhJ@69!F1T(FhypfMYj2|SZ8j=`lFz1Fb=2VlZ+1OhI zzqM#w9+z3vf{{qwXKP8AO8H*{U;~ZuoRf1u<@%37#F*$=USARozI1K_Um9n`wzwbb z%z6sOI>Wu~!DObs3xoa@bL(i2p zENhGXGzBm6nx^0e0S#6V5bq@5wX(&Wc(f*zxv_ypyf08NHr&SeG@Acw_k25FT+FN* zNj4|y)OCHYF*W+cMjap%sU;$HqF&%Om*pGmKhuf>1YNTDnH|k)tlubczdNbMu7k2H ztYckc#y6}b#uMCZ`grM_E)CMLdsc5i+aNxC>6|W&KjM3V{=%E*gD_U@1)S@gi*#uc z{y9}RUstHhu?o3QSefG{5R@(_Mv_p`-u=Qnh;~UC8>11!2sZtH`AEsXWfnZ?w<_)ByRAJess*@_rDg_g^x_j;sKp2{nww5s z{zGi8ADiosHJ5)!tYB6vQ_V6Hvf0_$oShP(*2v|lrUoz*vET=a-O=S(cP5}<(`Q~- z13N|7%?7Si!B_*4IIPxqvwD@RFilJ=>dSdn$(xR)+f1wNSbKCvC-Mdm#(o7pwuj>4 z1~{GmpATbC+Zko-wMAjU*c;cyF>qVsy|Iq2q4ZviA#MaG_QKa?ouR#@BIv($XY_`2 zGJ}gQgYPNYEGx0MIqULY-t89p?Y6qzwthQA_X&Z4=BKzZaiuL30n-sD+@m!XgWsE! z?aKSJ9k_KSMSG%MAR1{`mt(XW?<0*0z{XCEb`2_e;qO|gjT-o56|46w4?WArdzP#& zI#yP15MWO~BT4m3yw7X&GEfbYWotMRh;NTFuCbi6^^|%Xu`*?*}RErP6)4c{%l} z`Vggasq_G)^OSy!(gn~duQ=fXJF<6kp50lJ*IktznjzGzsE#WVp!&}QKYg+loV@C0 zDaZ9fIUl~AEBkV@Q%kR$4OcUKhr>GDsdj3^I-0zzM>@;2FL-meLXoqGr7M~WGyNGQ1 zWOOF)o3n|)@Pr^98T8Fx&kUy0J_uagZysAJ@dEelrYX)lCy+mpA>fHLVo*juAH&dM6=7v@WIm%jj4$qqPfba zdYhMZP=r*l&8=xOso<%=mS%?;im*EKIdccJl9bp=Ksfr?9~ zTpKHNJ5v>}nClYvHRE(EqIaB}iKGP40oG?kpuW80ZSdycJ?=1P{7}LPa@PDbkm2%3 zYqY4}ldaLZa$UK22a3j%*4CLv1do)I4N>Z+Gn#{u5VB=R8O z^F^M3KaM7oKgbrOg%E{cE_;qB=Xt)UYD7&}cPRr^4zm>OazdpED>pq!f9PCggHSfD zvgzvhCr;?_#6BcI%`m|-ytQwjV4ys)mD&W!J?W(v%vc1>2gb6lTP1<9Kr?r^8cqW|+X6E!QqtKE5asX2z#UV{ zYoe4sWFjii9kQkd7btA7Mw2HH-hi3hzRX=*W~_~Vyu-v=?@M7tt;LC-e|a(|kICNU z)8E=RJ(k}HN}r>c*0mkr*bDO15mX@u6!7krTqcs(8#U|Y?h&l~^N z&5G9{S(|pn)GYYILd?Ll`cz9IpJP#5Lqy?K+1FZ{-mc2N+R~wrS7l#mAy0v0QO=(m zj)>tN%XD$Mt{nJ)IeRSUEJFZ{e_6F~K@>}Zu*U14YXEctiUV7WE*Cv6*y9J(?^U1% zIFYPZf`_Hur5$dPx;AaJF%?GFA%42Ug>)597dLcyEiftn$ZuTg+vV-|nju;Fmw4GNWxaAV`kM>LNh=gn|!|tvUaT zIXKu#RDo*MzQdS@H3ZF+3~=!Fe+y(v`Me<-bsC+GAG44VPm+~De40gG#g$ZFX4`vp zIDZAFfbEvj(ybP5Q~Vv;%S4sUx?~oaC|4xD>O#(jx@M`WtE#ADs=7kXwJFU|%r@31 z<~i`@kgQjWzc^FO)M2z|BpE^+0`Y*?7WZl796(TS0Ab2Kl+y%y#%>)rsgr_vXIAfN z-l=9^SM9ugC}GhpX9b)oJDHZ*GAw#C(I3iTAbt-MKB!|Gi2&^h2<)a-pU%rgCbTc!Yh2Th|t^QIm9*q%PL9+d znkG@evGMwI^Jso|$XeE|y0?vHfkuDWmBzu3pat5|4!h8lDXzko6bs6D*H%O3DkX7D z?>64#+q*=K{v{DI-RjQz9(}9JPN?*p5YR5(yL69g-mU)6`ko^+y4C+t--D7a$KW;k z#-a!PEql^!dYqm^U~g}alG9H~fZPmdn7WZ7fmyi+1h3%~i`hNZ<*zhC&@m9R)fF`% zyhg+YpsX68#-ueXodPtSek35W7Z7=-E^tJitqV3AX1^N?=#gkMbW1%bTT0Y#_$p`N z*8QfbtApNyo1DC?BkBXJp7cy=gV@Jv>ojZYoVzwc{-fFqkx^e~_u$KKMPNjNN?RnH zTXOWR(|TTEZAi&4r?9Gm&wQ#nNQl@}^#xKyBFHe{rfjFjRP|ep5*D>7|8%27p@CD? z#~LMyAe^c`)F=@>BQ&iSb$)oKbA+dtr);$FD`p=P4dkwfOn(oFYGdQJ47ELOo1Vnf z>MW&J*JGImFj}x7sHz_yF@=>#-$kg;W2jKL7GxW8KHasM+-wLMmx3lR6y)autCnfU z^HzR$epelIl%=R4CN5}a{~taIWTyu2b8}7o`Gaq$sGEv*V(tvyXd=B(XPHH>L!ai& zZ17!EkgyC0+M%!LHq&$uaiLyX1LfcoX2)~8RO}?M2(O6>3Z{^y;%c!;T23Y=EDJ;E zeXz)j80vJY*=woD3S6@7QPv@*l)?Mef1?g+ogQK95fPu6L4$><*;fs^3xhVfG4n2) zFYsOVAT57ag8ow8W1_KRP_HSra7Q{;Dd1O1YrCdc(hoY@HO1BZg1Aabds(pSxp)aB z2Oj&p-oDOWTjI6rDZF}j_4wa?dLOSr9D`4(!mR=T)h}_{<45HErBmEoDv;<&5FQ!_ z`#n_J2zELZ0aa$b_w?EYE|mQ4spv*IHoa%m3X>N*gdpvF@VJ?un&i=6Bwq-zLfi~K z63VF&$H0)uY)9*Qrb>Qx*(}UkuW6!5pwz#z`=E;1tv+ful}NQc|#o4S||WCz(~a})dBxIE0IvJx(-0rzDAQ)TGRL-Lf@_qiLk8!S02LGgsN`CN;+Zfu!Jrs? z?9C9OKNCoS0n(qOMbm@-tS4YSjib&|;+q%AONXZ3VCSs*`Pmm|c`27^wLa>S)sa7A z2;9k;f=$7k*%|z$#w|pP02F9?vteCV>MkQ1JQjLp{bbI?SBAYjJ@_O4^eQMs2h0gj z697QxQ{%SB)BsRD^%r!Zx;DIeYCnuw-6z$j-lqwJujpHdq78l9GSN3}$`ZsUS;6UJ zZEjc-ONy;M0wI++6Az0)R8tvR8Thd?URtwvgRwv0B2fq%f!Ie4rffXGR+=>1b^ZFahWd`Y1Rw_K7T_Mp7aivG`OS=$L?{zlQ`$t1#gwYs|TMG z(GKZwD3k6ICP!B3^4n^4>1SGFU@gL1#RN}lsMSM%^yt2fjNYa>6}y;^#zU~f@NrxU zI*k#AxankyOXhLfb)?%YOI5MpB=ko}st(`958Q-W>Q!Z-C5w&k#AXB3PehYGM21JC zsZoHFfM=bGyhruwHqV_oh0?flvAuiw1lr5KY3X<@m|1%z?}Lnb2;2)9u`^PL8xRP3 z4E0Au)F}AthTeAuy)UUTQoXeI-K>3wAsDUoKE&KWdLJYqJ5Z`0MH?h{Y&13tZ1)P( zU+r~j(SgCAN={a}g7u1B%8zt?h{qA&UxB7gjVR&v1s9RPv<%>7ZUclSr9obaVy@Ws zT8mubE@+W2vHnb>7hY#q(hz@~$4?^KOp(OLer@p+lmtccdVB3UUX$b^lR?lVt?{Tz zGE~|?!**3tmsbYuVaZ8B;>q@4npTli$rh)>M`86-_3i}L;qpNJjDPS2ll$iChV-;9 z6K5B0+*=e|5n=k5y^FCv#syd*GWrLwJ}#!`N51|jbo38xH~no<6j*#O5RYnq-vkGV z8=T4{0P;x=GRr9@Qg9CHN5%lJ@DK<14Rn-7yL#Pi)j+PbcD47ms??Qyu#yPD`D(JE zHBGT(!%|lIyjgM+1PhbAW{)H|bXK5kpj#En-|7P>iG8!VKpvEGRd*kaRnb!%Jf;LM&; z+ZjRvrumP_thL_`-$f2V=B|9VwJ^yZysPV!Px@^u}vADB^Sbmoqgx%TZ@&XDEHUVO!^JpCer?ne@AgP!jDDEDQ<(o*V`q(~fUDRmTl5Ap_%L1VEjJw9ONyV~ z4SeJ|KtK&OcZch>W(p>mv{ul`82HPI4voW4xjOx47Wvav_U|9fzG}Fxgl>NNsJyEzEeR|lnnkr3n+~-tiY8*y zsf-rAtZvm*h(LQM@L?>7Xf%@2$jTB`wMAV^tWJ=|=Q@6RIQ5KY5+DSG_2vBSLc@Hy z{x&Swd6sw|2TV7XaQRR3!tHY{0XqlxpOYD^sA}tt75$Eigv_h5(~zvmWLDzrvXFt( zmTQoa;I4p9oxj5o7<|?$ljWief|=407>x-k0!aTEH?45Xiwij zEr(=zO-i&wIYXrjhx5_8=ul9{1C<&XXs_{fln)XLM=YYSZJUq{3r9>Y8K`OKaJV~? zOB8Mlz#Rjh)r;hdLI=?pF9A%r)Q=I+9Mx>%|II++wlfRVu8^m0V)FM zXsbjRZ$1Mm=JcRbZq(0Wx!J2g)<;o@tS>{w2#?b1(Y#Pni<$$>8iH@d1{t~yD2X5` zH<6)<29^GiajqwLmcb-V5U438A zM4fJ6wyQt2f@BD_t8ZFCGH%FlX%QY)k;kV<(#;}znvy5hY2y`CL9et~wUf#~Z8URK z7Mu^KZ92lzgS>+v6FS1Uu+-Lta^s(oVZ)9?Mi$xon1F`BFkKl(L@Gd>>`ap!W(y%_ zLC_#|BJ6kxrVSNyL*GMP&=LYj7UpeYPje>2r1DUopia|fw=@09nc?7G9||4T z>(ZS7Z9H#pu7EP|K|YEm)WYf9nG^NEwFSqA3n2k;{AGuX%P1c1XqB&0SV0h4NI)W@ z_9N2Pm7Uwm^|xE53z_pu2W;pNWm%pJn-Foc7!p^dEc4s^a40LvQn~=g354XH!KYJg zxx;R>tL_f>C9x3M$BdQ~I5@LA7)^Uv_oyx%7S(%y5BIsRTok(?It@)x#zjV|Cc>Y> z@!XzqX~69#|BZbhX@1Z47w2jiYPDTvTEveQJW$E0h|csr(91W+MV1r2+T^osExC-? ztQsj2-d1;pS`x*c#zA3M9j=H8=IInyTkX9rSC`n+X|A@|)eKielk(mySL^IOb#l?3 z_PMhC2)NHJbb|L3!9Q#7X>-7gy{CN#7RpR$h=!y3v~8rY_t;lr!6|IXQP?LUHY2aq zaFZx5{NnR!Zq*1uJ>fm@sqyov!o`Q57 z!cyQ~Ukdfdvtn`J!%wBt7!3#S;z*Y)qlp zS`G%FVP6j!H&V6`R^oaMPN%i3;NY)|V!E0uRE<{>nXb?>FUdZ7VInBWw-DC~ezl8N zp}?z9J9Y?9x(L^(>AKQuTXK!!e!v-mFWa^>TvNQ(okKTMh!)P@GpxIvO)KlTMvnyh zqNR0CUZ`U#d?^wblSUF_!&Rnuh#ZA=WCd;R$UcaUc#C@R+UQVfF$=y9C#O0=`OPZl z_GXGrk;7<_KUpi&lf9GEw(i*hR2uWSk9SYSC}J$DjCD}OkmRZzJb>?AJ)CxzSF1wb z;$=+QI4~(fXchj1+GoR)WG49&x}()WQddcBjo+Z9QJI#Iy%Ws`)HPRjnmlM8#!wNG}hkphxAEspC93xJ77=Xt;&T&kHs)TYIx8c-v{&Bhkmaa zEfB$hBZvCkr=~c|uKhmq@ zAo*`ruR7;4-zPtX#a2zHSV*SqU;e{KDGKZUEMYS@;^%y$yj+De2}1Y&9>OCxqFEnZ zF5g^cNB0kY$=3Svm-W6e*CE`5NWk`8DWTpeVgbYY6CM`)A*}M4FT{)`TY*x+GDYk9VNGOqzqxtBDjD_wOC4IkdaRW3wX3b-tY*@*F1U)MhsqYV?U#=*tW%=g})JPHlL_$6j_uX?VqVX%N9HEZKEk0 zJUuJh_7X2p!XAL-oW(he(;Ld}wxi4Wn<*bLc6G_zGnzJSD6I$Cv5?~_n(}~XG0#+_ zhQcRo!CW0zPmMk81`^<09X-J>#~ubj!lwhS&!iNy|FNiZ@m_fJ5ZkeFyV-&*u*e}=86*tLP+SOz_kF!6EX}3XZ;3z=580`Qpro_My|Bl*cu=_ z`O)N6R3#W5JozS5K8X}UxzTnKLOlxY#bFDI)?(oWgj$9BC+yDRot+~_Bu$mf6|-XP zQi5#O`@3XQyWLxNch>jT+w0{5MKk84htqWaj+SqiL(lq2p(^}Q0&E5HB&h(%PTr6uFyuo(EpR=o>K z(XdIzRi)OE$U&oZq(D_=BN~=kQ#35z7>NmrHb6|id5N_jZE>~=N-HB0_OsE|>)n$7 zrm!FvBQ(Bm5B?PcLuLtX(Nyt88W z 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�E@^ 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

nkyoJ7^W9c3~jN;vc3sOtk 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ψ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

7%jb0-+Ae% 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

B@n*FM}mz*gwh z`EvIiu9=>dDMNw5xp|!_Q^SKoEbJty3tPGlO3~p-9|Xnd@T4CEhZ+t~`a*Ds;_#$D z1cx>bFZ;xlqQSK+Jpi|I1W(Ed3e%UxlX`>Fba;YiP@E1=+7*-IL^FyX{p_>lSq)N9~w2JjgQCj(K zpjF_8kKhSDK>>R?3EhGcc6id>pokrw&`pZc@Ylq?#NU*(;Ujp`UZppD1W)i0+~_HI zf{)-vf58)c1h@VYyu?QWs`EXjrTNzJnp8~}Gpk4+saC^Nv!Mh}!3|Hr6FdbsJOxki z6x{F>Ji$|N!&C4oo;q!l>hHqNi?~T&8*Z}A65N6w_w)&Ff*Wpb^Hs_*+}!S~zzsLI z{R+5fxIM$xot%JPUB5a1ZqBmwTkeybeM`ULHje5&FrJSU_ucXXH)h-f)ZX6+PxYvb zNvXmSZ@%j*Rbenk$8=kSIqIedBh0!$dA*sI*GU4*Nn$X@oPpb3_DCJCxIFIg2lYUUWZ_@ zj$y||u!xJ^@t~Q4MVyDdZGy$Nac~MhX!dRk=Oyti=AWKY3MZzt_mS`lnU-kpC^;gR?<{k1n1dDYHITZwpxC}WJ1dCLV%MK_b zSZo`oz3_QvO&@g>q%$H4qmI5{5rt7lL9mFzsG}fQL}AoX5GL>^nQQ+hnM>Xta zoQ9(ybr4Z#I0}MA6dI0#U=f9eqaavBq2VY97Ex$83W7xxI2?=5G((~0C`e006wKG2 zTaXcjnxo)aCMbn)wZ}C~gc&;u7E#cldOAX|hysV8@Tq3+5?$?gPh^9b#JbrSji#`b z?zUmXr?5dNSLq{J9Bx`e@JJem8*YL}+#GKB2_Es|Rte{=!SCdJ{tg|V)5$Fk4A%QU zJ*CE+nm3adJyY-hoI$n{$S)Y=bOQM$gPchqpEStX1ajISe*z>JjQKk_-K;Yc;DV8q z{lrxN%+LR)wXA;~wd%0QV?U?Rv46|o&X!*!B1Wgq?7}gs+Lr4!7gnz#c8z;U<3HQ8 zi$=L$6yZ4FnHE=uxGI!$f|CFbOz(CyV>g()+1V3LYs~UrYh-k6yge~FHQSkm}Joh#OwqPnGiX{6?FM$u&c2lj+gQ5nwt#~Z4RER_CWYCltI~9 zI=)Y=OG^+P*XGY%(eZnpAj>Ix=dzjz6MPApV>D}&r88#?9N?EF6DSZuVbBPTFHZCa zzohDy_Gm#W>&HN^=$9UTb_w zsC>KIb1D6xd zl!XF}#hFu<)N^%e+C?+RV2GCT1z}n4xWhaFQT@Rz>kr>%p`teV2&&X({w@lO_8%*Y zaZ~twQ6FRbkdsF|jh2g+(iZLHL{=OiT`<4*Q}L4>`e+v*Ypc z@$+?@Y&_pqO}Jnfoln$n#%Yjy&9U}3`saV`H-2FFhK!8zmY?VKm1E@E$`04BQtxn= zl_i-RmqKJb<_=Ak>$$t=S;j>Vo^>oU@i_kB!4ws9h&)HM&U9$C^DFZCMnkwlc!VVy zbD&xG)xS??riC1-~h&C6c(>poL>imyrp@10Ub zPs6Le51qgB-!qt+eOVbgFBXXnRX7X`U47Z>eua94-C$OOCUo-D%QbZDz0h5S7t{p+ z*Jvmy2ye8t$zqX2ma;9l1tB8H`to17{c}mlmwnRurSQ5R&;TbEawASj`=jIdq1vT- z-7m`=Xs1y@6OCYul?1_8f0-*Jo2e!<3otFvkt`DNtbnbAKKH%u4>Yu36S*`u6Sd?d zwa}nq!OLFv(Quc&?z6^w+3UV7)&=RfWUu=^zr>o^>2*IUKBUcbw>#1e0@al=Yr?*k)jhXqDY^r*Zopovl0@!uA-Ymk(casf43sR`m)#kXh>=MLeD56 zdCALwe)a&HRV(Ux0-zzszu}mJ83?}qOp3bElk)U=+3Wr@;C276^QIgzFFeq=Kdgjr z?yoG&N+gPZ^iNo5e`IC7d4I3DlCM9E<%dtFA@e}*3G*QwJdSjSHFFvYE9t}L;<_$> z^YSP)Y>&?3RdK!f&*a^og?8KM$nZYc=+A4XrO~gwFRca-><{;Nx%O*0_AwGl9hKc# zXT`bx;1VYxIr`g&bw2x>9G2`+#l}+J>RJn+x+Ny^i0 zr^)V=eyoDIywjak;UG9`%jDE(sb)bQXNq%H%UrBw&T5&9wdkyC7;^E~HmhU)lX$HJ zO+xSLP4(;Qg_dE<@zDi}pW#AY?R`C(f!|Cj_&jeywC=$n}p$A zD%Yb6{dq^IH!aw|`AMd>v>fMSN|+=oGp>5lhm>?LDb*g&xHmWVkV!u4Ts7@DE+yyl zMLclTS9>!M(%f#&(sQSOODAamvyR9@U0NC-j|B+r<#h|V$uM7_1a&!WEt@cxFW^jW zh8_{dL|Xf-Eqim^dsUkPZSz?Qob65^2n443qw`fDmwjR+e8)}T#KWiOSbjJi;=8({3 zV2OAyBj}-(>{|_W{*sM2+PsXY%Wv#*eRD~kwTICx4ThK@y+Ge2m+J9>*_lu9i@Z`c{EHwmfbi5T5m)7vKKIQ@*}c$A+)PKJWg91d!2N{!-Q zP^&?e-rAelN4;Jq{%D6uF|!X=5%Ui5*&BKj-8W^0D0&iy#$rx*b*MY95p0yS1yZy< zBK37b3XN;BO32{*9xFw6`C zfSl3|OGo2xnW*=?tB^_Kf1q@q3B$%xZ#bv_X7fF{o}5uPElLuGaypvVS91Dr7Sgf} zO0IX&tNr(^7D`r3i*%c)&`K&^0CLX6^wFR-r_~P?$fEl3(Nx#M8Ua!Ww{mS*nxY() ze8M27z2xH2l+LM86H<;3+ruC)lNwDW@6(bcwWm1m#w#~Y6Rb!(OA=P_bWQ{}%#t5D zXoefZu`?gF=7H93@6H%o+2A>YJp%9H>bjtP)V{-IKdP@N(ua&;QWhN{k&7Y9Y0z7) zA?CY7Qa7;S&?=o{St|ufxSgl6A^Jti!x`a%6kW$+&Fe!dEN+`y3rJ1z={N@1E@{&>$eF!t(q!j2eF?!0y%pMFXPPs`NJ zOGNC^%LH2*ykxV4YZ<-7v6Zco>1^C?ud_bM)ErIF>T{Gd+%GaHMNI+aY*hgz#L*iI zEki(iV;Gmw%k_tvy(Li%9IR${9FBEBa&sho9BI_>yvA=JxiCj%79^7sX}jXuolx(% zj>4urYZdmcP}7kb5yae7Z%JS(4cUMl@!&iOIBki*2%w2c*_6J(w7Wyd#% z*oo{OM27;Mp`y7-$Fee7RuQ1VWa=&C`;?2p7?;BKr6Tv{?!|xzRon`mNU1d6ADp{# zf%E(nih`m+qv#}92a+A2W|d{P4i`g@*tJCW3!xasWB0D80QWcDiHK^rf*LSY>9pob zO@zGS4xFrWZRrXf^w8rzG8TtAAJ^)+CIXB-ohM{mD`4F^KAmT8}xH30Jgzuh>k-zA#W^ z8cv5X7ckj3mH>@*%scxEUIFa1nIblq%#M_)5;9n{UDK*Gw6;szCTIa3%NO)xSc4s+ zQ((UvmiZO=zWd12%=h2d+n+a&KH~4>3?iw)Y*+Lspm|?+-wN;RNaX}JcQ;U5Jg!pZ z^b=ethodG@FXdIbzMwGHG|=+mUEw=r4u2|1d*}t)GwV;G*zu#v9Kgxjkt*R(zbjai zw_0ag93pT>Rvy1tLkJ~PGvks(OKR|{p}m-F2Aa{5$kls+29_y!)&bO0@-0}N;7<7o zbNC?LWkn^0$a%dN6ZnpcdnynGRnhjnNBQzE&z!iWg4GFhKdl2B+6jL@r$n*jOH)(bJEFf>13&4>A zz%<=yD6Y^be#%Dr-wPwM6uqNvXX-9GI)ib4bN}j9WLwL|e{^KH#)3nW1&781!^NV* zRy{5{z=n;L-{1P%sg-PH?eG89W6hPU^TY?qYW#x3|K1Q2ewwA_Td`sh;*s3maDT0S zQ%!NaNQ9cR*XFfA&^W`9Db7}uYuRkX>tmT=Li%|V0IJ!RIOJ#me-E0WOwD`P`QW1bIr5X8_UP; zyN|!MqxVX~;pd^os#u#TDDNon$npDnP1Y#Jczb~vlugsQ8>Ckxa?k}nsvd!=)_$@C zsNpAv+-UG2l^O1sBYczKpTpG7Sq$bp&U&mPE zX*1ogkB_fBK$kwyW!)AI0i_WTUHkA~ex?ChKOH*k5L!(Q9z-|yR#E3!Xp^)<;;$Z# zZ4kCg|AaWKiU9;*k8pCk8^!WzByFgWY+&M*AxFaGvT zZ{A19;NQEl_M0F7tJ<4aAGr@o&mQHcL0L6cS~`%sV_l>!rk^IQZxBejid&dR@9j1B z-A6$WH+3#d@%fBd`oU&V)=?dYU+hj_}Nx- z=z;qEQVd}g^5l3_2(nV!W~^m5W_C+NPgwwL`ui{XWVsLFzytja^=-Ws#iZpk{A#)J ztbQ@~_9K;DAz)3- zAJod)wYAS5sANW6k`+XlD*1u{>31fCN`rYX4Fumb`?@UM?HgpiG!Art*@;efE~ zM@s_j$vo`Z+7kz`yqh$DzoHvCA(Hn<6S|#ku$;z5aGV;Tb-*+MC{>fym|Fkz@@j8X z*p4wbH?x#eO~CBE4ZYNON~TT86HN^xdjd1@QDJ^On1r~Ps#i6yruc(DD49uNo+rapJaz*D zI*De|FL8q2;E;wmw(BqoR#2TbB5&5IHQaf0$<5+!lMe7>q2dz4qE`ueJ8thg$6UMNm}17DwBCera!<0AK#C8iuMMP7e2y{rOpa+ zK$H#u+OxqjQey`<63+;|v{aK13Zw{14RNHl4c{9X4&_rJ7C{;vCS z&c5(>-51?h(<=G9?#r5e;qSUH$5@rPs+H4B1{<2&&Y|9&DCX=G#=7n(eSCNHWqfz^ zWqfz^Wqfz^Wqfz^rO_P&dg4wLj^lw=`goxAWjxUOG9GAs84t9+G=MhHx_6=p91oh( z$AhLX<3ZDx@u2BT12hAmbEodKhcp@L27M}hJOKJK9sqr50AS6u?}T}cZ$|0ko6(m> zGgetHwaoa+l-{V!ilE79HH(NZh;4L?@6&&C0vsxzzhwo&;LG>+AMr`+{G({SM9Ibj zjKyGD-aF8Shdbi)3FJg)398gqAY(}^AFWc1jEA#*Z`GMd(Uu=!Te^C&RjoN%t;F1o z{dTnGh~qE?`A8np&)=-2syy*LmZc)!t5rApOjDX=0OqG9!nYlTSGk!5uv1?E)n1e; zFSGz6N7WWUT?UvIz;mCkG3+)oKD8CRJB(eyF~%_)448s6=;==Svq7JgdGfUE1VI zMN$*cExVRg)@lhh2D41Drw(b_86RQnr*QoT+U&<)?U2qy`UoDvJCT#s6@CyyR z4ZarmD6eVON`z9q%m!)ORYQ$dQ5PYsb;HCF`$gQCrDFD8EXYxAy8xlm#w=oz^#bl` zqM?&0vQs2c-CNxr^ePesl-e#Mk|>rM-(@sOwA&z2F3*HSrPba9iAw)9Fv+_>!csX2 zdmVxs)@Tyf7lvEXoKs~_R5_*L5LHV41A&1m0iJyY<|pNLp=~NsrG49oB15?vRicZi zhxnlz;*NNZw_;b+}Zeip>uz|S!DePyCE)7X;t(w00D3>rX_1~phis0H0z zIb&DCIzh4E>HCCzXX`Fi`b5FYUBk&2PzH=l(yq0p3w%1g9C;-#V89#fFn#dc5f zYy8$@7-(@?chYLx#_g_>!;5LJNrtA^4QGPsw@qO#qNOtQYF1f~zr$X%*v(RzCa}W! zY0}OWw#8J`Z%xiD1k_+IGv|i0)&!0j)rM8Z<4H?a;xB1I+e4ePR_mm9LlyT)wCI$R zwrQPI+B{kx3s~4LX3$f3o2hPKs+z$gM_dNh;{&kX z8PAGYa+kDi14W@K6h8e$NoW76Rvuo<{IBSksZz***qe9MK9ewC^6UvmCUb zbk}y2Vk-CEeb<0-8ML4|KtU9@!Fd7ehxP!r5sld7QzPBo%T%Owxbev)27St#pSYA& zjuEl~(+_io64!?5F*;?xRx-Fy_=eb)Y!z}H`cr!+ZS=?_j z%%l6urTy1RhFRLb(I$RWhLN@DQe~JB(!peyx9yh#s^gA^?B%seLX7A`7Wa#}LY%fa z_bt0*m?Qhedy(?;+e=4D$Jk(qI6<;z24v5oLxnCXy>0&{|T~v-?(bm}3$uY?>_D$b6`cG@;7&)dUV7Bss|=MYln6lR@H=h#($fG6^Kd!r-Fw z1|(;S${u4yg>YO1nTwHJLoU%ha)O5iNK7u$*d@p%k;=x&C6`ELNiH!eGpUfCLBCMd zup`gi<1`+T;8_-!h#Fm z*9k6f+wX#lJzMIS$t_b&(PXMAnoL>V9)F|c!HDPb7>N>w$rpyI>1qlV(NMn~E5FjzE7YL59AW0xt+#fqHS>XjR>00`z zKrr%YR3I4nWCDQ}n~Mqr;uqP7Krm9#1_A+Cp4>u#;E{f38Xarv{>fG9vtV0z1%CGNye2{IVY$5s+0^P=OuubWUXanf|}8c zZ?#m~elbFHUhY>3a#Y`tF3z{Z5e3tWFi6r&DgKWYsInIMAtIzK_7zIVhOQvP3NzYT zG=DI|v+D`;0YzfY*SNJ(y$r9sFWM{8mS|WRH{H~uVP!yj#q1+c4k-JT&cKudaUeC6 z#SDt~`k2o9n06>i(-^V^wusL(2zX~uvvAn~gz{8Er;RC;8AqC(P9y=$^z)AlY#&WS zC{>C{L;N-_2-#JL0EO_Xs`_yM%}?8KbDhWy!}&u~KWrXh>Z7?C$*_KN``is?J=fUH zl_w%Z( zEEn~%q)r~jjy|sRa~Ypa_Y_F!Q0yy1YvXy*zLIavU?{YqbYf8goovShReb)rp!~Vz zOu!7tn0-X15?_k@<|wf3Ew5yRW_7kF=uTL?6&HzF#Wor;*v^3N81#h^pJB4)7BdI) z<92!AHhd&!8IeA&CGJUc6;e=viMkIMbws=#RC= z?lrnWlM#DUDv8=!qrjaIaCBfu{zLF)+(PExPxCtKuTqwRh>bu;ehg~<;%YxdMC7@Fx zJ{^~7+*aGkfCavYgJ6UgA5?G8?&8Usdqz*#{Ms&YSL1SUd^fNf_cy%N>f%PN1@eK}!PQvR;{f>$22z~6OWR?JGu z-})D@EoJwU_Km;(?GCe$E;Hz@lE0qlDEPT_eab%Xr7?L$7 z2*%JxHo01~F>jPjsGvpbmp9Kk$jwMZy^N-{UbPmBjy-zV!)Gx2II} zBd??woD+w_PXDKs`PTNUNqCmyS(47|13VD^!mqO#ulK|f2lF@D>zYzu&*uYT!nkhs ze+@i3(&E_)QYfNYX+7> zRj;Zuy2z&V;Wl++A%7{cGfPfYV1U!vuhtx@S=O9upjcm*m8W0Sm});~waehjDF&PdWiviip-V9DR)0_3}8TSDKxoE{vT{8%zdeyN90ARvx5jr;mfCT_< z$)hSkbPO779gNQ!E54EvYYiPsi8YXxQ(_JHrIc9fJ9AS*ax9F2 zBpW0BIxx)BkXQre$&^?F=5$J|0dp!P)__?}i8WxD$^vE$?|Ko0o>&8B zIVIMBSxSjDU=~wi4Vd!=3^=b70P|eH91p-q{wS3$XYR#@#Laj~MiP|)ckU8cSZ4^0B2f_-6!XzuT z#Pp(TUR#n@%T>-OeFi3QAr+XJGO9EYw(K;AZS}1x+wIGzrY51xqIyE|kyPd)N=Xls z&=8JwM-kz-JNfkeo#18Makp|L=~np__+i@x7u}eI4HtuqER^PZAozP)9YM2Hmxz|WR=JT^Yu_9`NOZ2RH8Y_n#Ixwq=aTXjH=^IB9sBVCj<)|spT0}j|~z!)|K z*dZ2!#C$qp4vKO+Wk9r4jv7AA>9ClY`SL_t-lCIHgk0?0HEcTtR)eZHb{4evyh>xA zLsw|K%gmgUc$(Xa`Pv{xcjV0@-PxcA-6eNQOfJ%Q_4;43Q>x}(M!+J738CD1Bg0~+ zRIqtiN4P(!apaoe3@K}U#@ zzgYiC0b(7*Ct}u*!SFUYm}Sma9mXD{4&${DI?PiY#yKP6WKw%w+d?fqPje2?95+1u zY>9s3;zKU`%@H)&pV~Uj$Zk;XkV2XSEe_y-yh(E(oa3oTPj4or{>^j8B^kS6E zb*)=YE4qnJ8{_(Py$zdwj2kwE0MM{?eb~A>-IEn_MDf5j@2s#@P(=+{FaZr|--cFZ z6E-Dw-bskMuD~|J_ibhlXA4z7XiIpTOePK6`A+h1g`@3znfj5vmPbD&KcoZYV|qp} zu<}ixRBBN^J~s7PeT{j+GZWG$&&)5+wEA&Ut&E>kHl>#KS5ry`K}ZCXxlN}45`>A89Anvqx#1{IzON9O@w`( zW(F;tg-jwt(ulyal7;eI8{RW*Q9?)sriCm!n0>un=A^6)j1k+Lv>%CDzi7b@PRxGl?pLr-g6Rsm<-zAhEhwqj{A7t;aLvn)P> zcluy{4iCR#_F(=rf0-cDk+0atXYjrlOk2+H&(1P9wy;i%TcOPsQ^(0pgT?EV{2PSA z%C!K7EDJHmXW-JUK$%nK_&Y*^ICw=OYmgIV;Z#^D<-64XN}W^Lxi$t!N{dNxszgU{ zsy1UTJUT7$lmo#G-dq6zED<^6g2;ix+f>NL)BFsq*pdBkDPR=|>M5^Lw;71{hbGWKl|_x=p0oCteVw%ET0@5(L0V6+(nir#B>27U23nx^TIK+8Ilz3P3?m z8iZ;FInM0X2$g$A6ETZWE$9RH#nuRw3vp|NdZFUM^{BdTN`#65C=%*~`fTg9G<1pOE@6Npn~j2%$nz6E)quTG#Z zO(WK*FiqqPEaK|n<*N@f6-PJIm5I_=Q4w_7@&Ryei-xTsEME#YKiSTE)v4-LT(~=4 zEo>P21GFS?ICVB^tTkH%+__ zpWuvX!m)f!6G(zNEJ3~Ju?%3ILR4Zal5r$x3B+la-Axb#p(Y4UGs`6inscu_bp;Z| z>u&h~E(vi>I#RI`gf0a#Vmf!wZu1A;ihTBX61ZC8ni@pz1SedEoK`q-T7B=7kK%F# z#~@GnAzr0zCOchzj8GHm`UyP+G{RtiMNDmv5xvr)>lq`lWdOW3yJn%L?n6H|m z_l~l4kK8&>=ogtEvQz?~=-DoxXd@w>0@ktJoZF0dKuqYhMf%O{G7VnTIsQ{ zDk+eiRk?yx5EByv@zez>7q|GNjfW~+>DvjPmF+4+NulD2L zyVjz#g9jmJ36*9+W(e~sIhFvn<^S-y(!xQKe`jLjl!1+_Ic1}$#KH}mk&lIUnE+*I z7J$6qybzIb3w&jFlooPU(w90rxRGji5m1V7IIP18IopjPXB7|@5lnsERopn3PLw%K z(K!9pKcxQQZl#&mEM4Bs2#G?gY);ZD7_tT<+ioi!&%%ft>*Z`T!JJ}aQ0<;#7w1xj zyFdn814WJ8-UvBMPa7d;>90l8aR6?l26dahRN(~MEO zgmc}kawe*QqG^jUn|qAeT_MIS#HnO3WHDx~U*lrT&NHsBhjZ!qGVYk?%-f53Yzt2K z+%r!{#SaAv_-z2-W-2B#{52OJ+AT8784_@Cqo{~?k0&dbhkL<{;I>$NsAeVd->47I zu@BjBk2H>5(W$6zPoO$&6gxv>gNi3BUI00|f`Ht6?jmgBPK89>DdRVaB+roI$r1+_ zArZ)SdLUUiihK$Qx!(Dr6&j}MAslCB2#gS!zXlmEq zA&gCqdA{>D; zVaF;{`xGtAB(AN8m99Sz}X@!OD=bD8h=Y)FF9eL zb!riTLhHH0^zX!ZxGT(R)wWH#`tRkzi{m_C9@b;L7=8An&_vkINeMKfFQ^_Zj#SHX z@)v_Z02323A(08s4lk_xyHtP;2g+q;8MROwa+_+C_yTH8JhWl;N~hvpX9XElqPr?{ z$pAT0yBK<_p7Fi6IFmH~{%XEi?xl6*D^*-Q&@Qd1P{BP!>WSeSd zudG|FfOeSN5e`(wA^l{m|3Q06bkueLxCyta&xmJ%P-laYMDo)EF5eYOQ2l3naZAAFi{0fc^3-xYEb zcu*yCT)kU%Z8^n~HLsn4gge;TUH#v(UBd*EY!0>+hfCY18fpPd8d8q1!%o?QAh$KP zdF(1j^J~+O|H4Ap?wLWvVwGu0;(`TcyiExkHXpPwd0BXU>^wBqj)9a4m2qaz9c)Or zfq=>IJl0EB%!wxZTf`IKAbbV>wJ=j%a0*tv1$a`6y$_uJY_Cmr^sB@OJ z!BkrTK*HXKG7^KNN_}3lEK`QMXqQ^8UCP2_7|b2E3~hi`8<{EBLfdji{(xnjf(OeS z1`-R}8#dDoEW2uDJeIq(AM`_lNs<(G10rlSc9)Lsp`&3yY`*SN@ITQvBr0@hL3Yhn ztWBJPm06w3)j9BXLuuZ9BXv=JeL*e5>U6EH%_Y&|E(HVJMT>Qq#oCt?XQjNce5f98 zB`M-ZtUVeZktMv;)mgbNwHMWos3{;;IKDgv=qCy)r(41mNXSEFxu%&aDP+QRng|7@ zv}48(rA!Ku;$V$_COfH;h@a~t+Abf``swS7CLMMOm2`INsBuA4@V8aLw${5i=nYa>Lj4wOu7+q8J1ydk?;={o zZXqDl%NVPrp=_ICyizmp(T^y*;nOiBB?zEI>`A2*P!|<(=cPl+qayCCet|*LERj>1 zC7?1z+_QQEKK@E+`2}@N!)Qavnt>`YtgtmiOM&)mTpv?;i2}7$!L(v}C6+1ELMlUK zlGrbuks#qx?|mGe)nX7~XEq4M+aPDOq258~Ji3mEmpV3kEia zUlxq`1vOTFrgv-p3}-x&a!}YgE$oOHn{x1cdqg?N55lgt?=En^(EQ-kuc-%l4;*xt zj8)XBG2d0G2WvQ!E^tY7PVpZ-m>IiwnVGyar0b?j(nVyALT?54CYE)au^h$&zkpm){axsl= z0Mqt5odoJ@QV;74)T5S0$i`$a#3X86r{31zV?KrjeYiYa|f}4_#0rxyW8X8p*|=kzBkijijt$+XVsp zbd1C3BhRXXu+7cuBZaN5mt&tmOer8^cLeXfpgwYY$>qkogTk}8s5)|kR(!EG#&%(K zBt0EmOdBbE%vgnFWi_`Bau#8?Ea^>!WR=a?@3bh%v(^-nu^>C;Fy&%78%$8A^Om4; zYZQ`n96>oYp++lxq`nErs3Fxv6t7LWB?z(CETZ}m`O9v=iof|>Q%4HN7uQA_K!uc% z*1S`WR_Y3Aar^Dq4!>w?tS(YGj=IQ5y)|8A>PxY)E;8jwx=0c6KkFj3ySijuh z8)+R?_-bn%9U!!h5g=Y_T1TIlN$IGc>vWEE^6of0S?-P_lmAmtH=<#*HCe|SqmB`e zm84_DD0eA3Mn|1gjCz}hEKcemiRF+=I=CebWA$qz4WoEmD4ka5nuf8e;1V>9sZdSB zC@QRL7?ax;K3Q17r4V@Aem#+2_tTpP5vyiF6W#P(AJ-y91>*y}Rtm;tiJ%Py<4(ti zT$#AN$%R6_>!K1ZLqQZp{{b(aG7S?nCy$_5SK8GOzAh*kj|C;;gD4q6nV}cpbng;7 z5|%<#i$W#)4!+S!64iq^M|xeBwE`0Kw7JF@ETFY#iNyxtus9w}$cmBy9}Egfi(H1Q zo@SW<(8jr#77%-q;7nuqi&wSnK@nh^V>T3QH>HBDH>UfHZ2O|sa>X=@5sp151o=v` zZ4kg;rJKAZJAZ@d=a%ej4>U!r`I8FGC*I<5+mSdnJ75@jc)JQMd2z224d2=21rh)Y#^~NZ0F5WBfbkyC-?tvB# z!rLLWyz6Ln{z9foQy@sG0Y|!^j#e?HB#T{0M_YZD!bGSDet1boE3Z}?CezV=(RNbO z(e^gdcWESGA~qgrzA*&?-4c_Op5)TAq6uVB_v?m_oQYUoVz{CvH)`-SKCeXp|sMoa?U9TJb0;^_CYc}P2-Q>!OUY8phrC(jz?|NO>r|ETJ zpTLkn1LLcr$pP8FpH?>O{1yk~N z8)a+l!enTdvZfX_MWn`P4Blwa(QTSt&`mAc7TbEDA3`K*daVM{OKJp>6Eq>!Eu`ei z5=4s-C=4x@_lRNK11tgO#?Cl)lT^3rF{{&rLlSFaddYGmY(&-V-l)2*)dl6RF9>@x zDy`MExg=Vgmg*MwZK-ZkI|`K@y`@K$w5XhYuZ1Z}NSZE>IJwo964YTy9lM0FRvZGe zvh=}jcH_iSTLf?dTa4*(q>hsw$yW=TT|pONYRK({xk=;wE8QfgLkw9|hNrWB1TRrj z%gRMeD^GcbH3=JEF@^J=80%B~HjvRK@=8TYeY{FNRi&=-I_()A<<-am2SZ+iR`>+3 z0IM3fZ!Ttdg4Ze2YP9_DKB=`((i8N#oq#K1AN0b!(+&~sJ`?;(fQxT0 zb-M*aUN4ap$#@sTC!|PrJ}!4p6vv~h-$I!B5$))4RA$s>7s)@QcZPq3XJkZ7kyBaPb(AM@*~hz|*hjGXJmJ@}N4f}0 zM4%3N%~~HGA|R8_1^SS!^w-e|^1{~AiJ{%vX(dS4Q37;(EhxcZ@$)u%SN|&#;Jz>; z0rT#AfSB^e2rKzIgA#&p3-4+-Fc0mczQ8EI{b)0c3?qw1ga0|UH1L`YVNgmRl{ zP=UB!uJZ5&C_&dE1|w8F`xL$Bl`&X^p%Akl!x#`?6n4XF?SIzin9pEmX^g#doR!^& z_gTo6nN!=^+=7HRb_nOPvM#=;Smlr%3-~GWLpXLnsf&gJS+&qS>$}B!l9T)Btw{>v zpSNJ9Iy1=GS8-a!3l;%Tj1&rbG5OcZ1Ws@|vrg&2Eq?Ve^uDY|C}v^#&RCdt@vf)E zu~#OkfN`wYtRm+@TMVCUlya;hjs-n&SQLg|lCVtSnvH%(M8O45l(6HEl)!4H@f}!j z5-LD&^Z>~mn6Ps^covDl*h0h-Pj{@BB55tlCY0Jm50fMj`Z!(HrC7D{eL!}59!h~uJS1fb^kNVZ&?23&AP*-DF!{o`jjg?;b;XjL8FCPurAHqEl z)5fK+qLN2zM*mNZ+BgA^J=G2gB6AV^4cQCreS1wZnD`oEPhfdNIMS1C56{R@q;$Ch zfE*}gU!=OMMshlLyUqF%B!H%d`qB8vJjM{WP)>g5HXD$w7hH=GG^L* zfL0GYL9%l#)`0wW)1-lshR+4g9j53=ax$G%xmQB)gj-x|yZXgERhW~S2dL!m$@{2| zNI^YmZ5!dpQ3?Q3TZV-?_VoLFCI9HnE$$r!s4M%Yc#PTn{#ITT?ap^S=cc`TZrr_V z=Z@_+Tz_4E+x*<@%=A>D|4sJnF;NuVEJy?OhQXq(zN~BWQ?0z+=`Kw4CfOtEx~%?3 zewKdnijWy!*~vWd7E&$d+-R0xSMD+Cn<%6NU`)y}4siA7%|7r8_ebqBwr&Hun^^g7Bn~eI&C({p_t@GzlcH!cK0l@jIx`U5L0XJxs;lv zx#t$_8-sOn@U9qVM3BMyH;m^BL zH&o=74RGc=S(dd}WNdd~8+K8ols8gg(voVZ52$?67_)YXmZKfyc|~h$(XgEV6L67! z)O@=R__iC`LEF$UKvpHVzKU_8nJBjZBWgkd$#cnTS@6RsuT&GPIs zItXAKpk5GQbDz!)T27_vq6d;9CaKlZLJe9Q0Bszs{a4nT_uX=;I<$UMy>%PWI7Rj+ zR9_|f4`d^Z>|$KR19yp(_gBMj^Q~gS^X=A+I@WIs`FoaYOLO?K9?$qU35P~R#yr;H z@W6N!t{R!-j?yvQ)@+Jrx+gsdcwrVFJ-I(Lo5Rm2Y=a2m~OE*rI22kycVwZOMU0rw80l`Uf9lPT9iH#BuDdR?YQ(vm zs1xWauRhganqLQ#*BOS^Cn9*8%Uav*e!bKk2JiRG7=7xT0G;)^%>8kj8E4x5|^`TdW8MikR#vzepA9%1e}vX zDdBxm*&uTVN*2l4%6i9~UX4g=6C;s9KYqMpPOmlOCqW_9xEWdpVWO)rPI|44(`8mT zUsb5rkqY^pdNRik>!!T)*7YRKj?UrlYnfo?4BFU}&7&do$Q1M;XCLePM^?^Bnxr8L2>i?HXube;2%BQt%M-DQ=G~gejB0u5 zL#Oy~kcA^r*(e#MUXEJ8rFke?VYZ|ez=W0d!K2$0_Wsh%)u1t8yoPoAfy)8Lx}xbN z-MxUJy|gu`fKd*Kvj&M?!}TVWV5jl341wl$Wj+4a>h*Fxd+lDYqi2`nu^PZY^9uC; zd|wgtYQ!@_jPUk9X!3R`GWP*0jxh|_NcK>zjDle*>2-v5tD9wsvscEo4?^CyW1`R7u%?vY9srY$f#+S934 z^u>d$Y>}GryRD_247X$!!c`_qVS6Z5Y1z5kb>ISWclo<-Uj;CVH36fLIrcgH?=tvB zXST7tWcZK#<;L&}@pbrH5To?~?4=&?UhhHZ>jirt+o2V*5jgX^8UeM{=z%l-O=Xmx zrhnM=*A8@Ys$rW+HDB4aw8sH*_5fyeZ zyTdueuBzQB5!)=mJl_@aoUuF#-?<(h)Xi4UZ&;o^WAmVUwmhG(JPPT$zMj1y z&j&4!;)kx!1I<}IzhrsF_x(ob(sM0at{v-Zy3kt0EUGO>ANn}R*R*$sPSUU(azajp_^~I04idhZwkUvJIVFvLd$08`d!O21`#X?J3^k5 zmS^YKdQc4nl>V~i8Z&@fgHp69BPb=Zl~78crL;csUPtM+O`&w#Y(I4K7pwz{mbxBY z*M~emV|lcfKbF0=kI|k-Euyy_@-_x@n=7tefw&4hWr%aiW{L zEJ~u@(gjc<#|*V^880C0QI&dv;6}wdG;_&?bUx;i3vE^wt%FB9X(cXNGk=n|+HuFR zSlwb*t-V4LR-Ur&(S8a9{UZDCWWVZvUOR_DCPz-~P1q~o%-Fsi>S-S?zs+5C2g)zA z{+HYC9(GEO%NL!)a#m@hfxt70^q1qVgedi+1EeO5ihM!8ILyj7wG`^CRleg7eS>2a z@~NcoUHvbHW@VAspxIlmUaO|%UTl@;wa4lIwqP-n#k!PH`{g0{vh3xEN~h?!iIRf`33zn zUuiNa#&+S(*uh~5@61_6xhI59aIuyo+PXPw-I_7*)aG9L+Oo&D1)Pjr(%y$Nq`%!L ziT=iTab8wlr{C9Azo+zjD*R?H3J0XP2At~?*rGW2w$FzC0AJgD6D@I219blDQmA>8 zjobqzg;wCB)TIaQ-R}9MQ$P+Q-pb*PZG{~*Fu7iR!2zy4tBX_(Dp#-6p>i}ERB08s zAXKQr8c@}c3fcl7ivHoiap!OV3FrfQ0}^q%JD6!=jUcgX1G1DUA{%aZ2AL$ljHK=W zb16QEls1M*-^!I;vf;ihPZCjzb&5)SELc_A>u+fsy*P+*iRjiML_M(+G!(icvK3w@ zXe{~E#qq|WF^9_aKfw{k7)E7)CJN|()BS5v6yO;MyPRZ4Q;jtAAXny80SDA z9klY>4ZT*44GwfS>^w45P`~ni>csKS>ck1#4(+J*>YuF_^OL=at{q8b+3p;gypwC1 z5?%Md{cqvI>}gqoEuGsMX-IcAHow4<`NH3IUv$};-=5ekqnpqCp2OxBT|?&g4>rH( zYB0YCu=(W}YK2zGUxxrxB4l(9aptwRL64L^zDN2pzDN2pzDN2pzDN2pzDN4f=n-(k zYdVJ}?nEpdKN3nG54XOIhg)C9!>upl;ntT1+&~B8>m2IdX`21O|3=2VOR4eD>C1TN z^kqDB`qF?77~ra%L!CRN&yPHK1O}y#he2P)!=Nt>7-$I*taGT%x#T$C}}+a5vEx=$6>*L|u6c-^Op%GQ0VCPDoZ%c4fBn!onZ_+-V4 zEG<~Q{;~TK0B-cg*khv;*An0WRRjIT{2GvMIaHzP22mJiYk+fkO^5m$^k`hG(dGr} z50z9*!O3ity#z7~c}ED%SWTm}nHxuPac{embC6XdACZ*y&AWPGCuq4G5$R9X{4r8OZ`S_48t?b^;OEtL+91d}E- zN^3%+v?er4YeJ*61~gm_H?qa+d&?3>nk_4>*|O4_Ei0|jGT|d6%QUe)D!zEjqk>D7 z)@X%57^XIAU~E)O@zP^B2$p{LM;)clQK7_2<4fWGs?IM&{q`nHcEvA3{2Dt8-s~l& zaJG~P7TP81k)svR<|gi5;*QAD+nd=DG4W`nE^=(NBjOO$#dk!g7Hmf(ub+sJH_PG} zc0@|Ah@ttVB8ldgYRH;jD)MN4smQbWrJ6F$FV)nxFUX3v$74rS-{aLwDSdp8^ksaH zMwwExw(&hunejc+mqw3(+jes7h{PhsjfB$2!>upl;ntV&BcU(j;ntT1+(2jhHFiW| zBjcb``grK{Wju8HG9Eg8X+Q@Iwku;tBqlQs2BnXOL0`thpf3#=Xvy|o?1;pW#nE)Tb+V{)w9PdvB{2Upq3rvwRI=9kXO|n@5LrN5=$*Rd>XF`Av-esUv z1O>aZ@O7Lj(t@R{j6i$ks=`Xf32zXEY`oqxsIAp4G_JPH9jwKYW#@DKW^1b$QB$rS zRdk%>6v79}xgVYfvRLP1B;S@0Gdy|FP@UY2CZwk)jDtl^Xa_$dKn`)Uy<{_j!i61- z44-l^vY0zUsn+myNVTw4VXb$cB59~=E=4vsS~EB#+4UlJXq)M$u2eC_qBoKbbXTc# z$prkX=Z&QH5-tz522%YCnVjaXypdwhGe$4h=shOi9?b&j)8&S*A@`vp%@1t1WRYFF zBA2DNOav88P!#i!0L6)BHgs(tk^0{vpPvdU-^om7*pe`cJw{C?8mQWo&Gr_m@xtWO z`N39Zx@7Sg6SJ7N_EfkZ*_udqtAYeVdyBxBm^WG|hBwqb%)yJ4r`d#fnqiq*%tMr? zrw6k^|EG?CUAD2g7?Z9#5J>A}QLUBM7s~rHMpU$-c8{%k!t5r8J;jyGqC-qP$+Qt#F{r2&Ud6KGk}CAobebMti*w))0Tj zUbEg*y$-9=9qP61!F?RVc)oa`wQT0;ZEZPqCKun;_6Ba9GJk?i-^UN&fr=Nj{vTP4 ztmmhqk+>(X1_)w6^cFGxa;dGDafp8QYTx>QWM(uokdQC8e5W}m8lrbnq@Is+8D`8t zxJe}u#3FRP34sV+n}>LMZ%6|C_dVufB5iuH9_c|fPeR68Ol zwR5R8wI8?I8Hvk+bbaksBkj>fY7eoS_9m=79jfk{zq5wn!Z_VbZ`QY`L*uHLRucql zOMswf5ZopJ#M`eO068a_fCwlOL~QVYXi^aQ-GVLur1^tT%p$Wyu$GKp5}^5cS~n;2 zlasFwI&KF{aZjXr>kg+WQ`&);mM+cEF~E>7U6_#(rz@n@jNzEqy*}fs-UcVLNrdj5 z*?J=9;zDAr^jb=+HFGv4*5J`dd7U-D&!@y%4^O~KjUMXVhIm6_t@uhxtTl8jCDuS% zPKh<(mr`P_@61h&!Lcv~9JQleCT1NNeul&vFi)n$8Zf6*Vhxy6DX|93YD%mD!&DY9 zYb_sw6}X4Zf;uo_DV|sZW;rF+fLTh3HDDG~Vhxz{1`If_69DsEz#I?2JZS|P);cia zl{PEu@jxtLZ1<7`Z;LBTW^6t_7Pr>yn^)x2D_gj)NLT0*Vy6P8eG`M4$2nq9GkTAR`r z(Pm%=tdZ`PApyxQv_i_VV|Q^wZ4NChGdr5!6H>}p$05lQ^10Dwma0r#*VUTQlZfQt z*`kc*)Sj30a34Nk67pj3r|1#?c;0G7m#-7Ok(FMu*(r2|a!bl&G3AZ(H#`tXac{Bv zwoV>oEXT{TMh?EOZ=B`xZ&VuFQ9kk-7Rc5Q3NWa ziIrDohOCck4zR}2wnK1yQOr2lZO@OCw)}vtNIqUr+)-gzeI9)-3({jN!BP;r{@c2BIQ|c^^zlY?)`3toQmV zt1$`*gy~jr#-lGSK!rH^4@+IKNBX4n5yf;QwMcpeS&e`#(#Xu;x?MbCEj~TE)pR@= zG3gPh=-^Wp{z-cg!>xDNl;8189dM@oi#Cg4-!c%G=efN%M|;rf|DK1DQV22ovP5iT zq++{BFYL&4eh^?)$m*#!oz_IysCW~$FR+S^bz&2L9GW;rs2eqY_Q&FIhAo;Jn4kfQ z=!MY;;Z1@KGi<`X^E)A3ly#!}UvMWnu@f-Yts4nr)W!+?xT+BoJM2VE*JP}Lf}`&? zcdk`?MQCqxbLFd>nJcY0LamVzvd#@!*3g+0fdS*kNCXBJudKYqHm%P6W@dhAzQ(U3 z=TS9eouA2^`Akku_T*(tD?T5MD+H!uJ9ZABIln$DUebn*lA8%3j>5p>29TG)#NwLN z>ie@5Cmq-muwq>ZjL z;MJ5_a~+$guB8j;GxgJV>O`$`6)iwEO>F^6!9xBCvL1TPa%6Ykjx0z2R0y8_vHV&8 zZ1gq|6)P_L+0AfS83K&Rc|7&;l z{`P(C`zP;9o5e-c!Y$ub5`~+4Kc5e9Ky^lu$rTs>Kz%*+m6M=#ZXcBJ!$}l^H*2vh zIxM#=Zyjhtf)XZ(mtuY;K(m%UOog1JQ8?(qByTpEiL8ui(Y{XGVmo2`5=BBT;w`r` zI0VfUlf*Sv@aV~cd&>A`ag7z2S+R|a={F2!X&;`lkUyVwlP;j8>-PU#77-;Lz%7-> zZBhy9629%PBQ|_7`GTxfaQx_C-uK5W5AGYGG2JAFsnxcTJlMKUhVaM4Ri+z5_U^ag z3&SdaslIGaQRu?&c(tl4Nheeb-r&m5j+Vv?7#gulzUI3LtW=aNrqWQ67 z1AL8%I=}PkTid4?biFR36?&4lvN)K(NJ%A?9RvfWkM^Hs(f=j2Zg{2dkG6)wE*f~- zRW9U@wZNvzqWALQIGDeJ1kmwPQWpe;^zgsweIP>Nz-(tiikB9}(b7kAFdB7J26vdQ@&?&>I29$|t`42@QP-jQx+RZVs?7sHKJcwf%pukWWI_ zLjD?qmM=kW^K(3AoSaCa99c19BXX8lI{Cr9GM~+mp@Q8fh>LSV= zhTkqEyFyr;&xTHTJi2Fec98GsD~P| zCXI>iHl#5h<48_{##CaI#vX;RB9TFFMq_~RS_{zM275-`P*ML#9C1hK5UcbTe?C`G zaNRDEGZYjO_H|dc73=?{sVa?d%m_n)1okVXi~KDA6jPr3b(H%N$I7-ytdfR%eemVW1r@ z-&dutwJp**4kNK>ue2+a@IZ;&L=FMOXnhJMbTEGcpbmld#kGlB^CMc1NIWmf`f1gA zFn?U{XeA+riSq160T`msUp(w7PzQZyj6d`aau&V4M31_T`Lvi(|M!6k&cPYa>EOBC z<{)qR^{<^2<11}=`tR0gH`2Z(M3z7P9x=$7k$j_RmJa|#xSJpBP@tmpK>i|+Dsdwg z+j>E3QOFSC6g*Wb?;Fi}YX7I-3iQ&ho^B21VXjQ-`5HCYj<4K2HL&PJYLHH8E2shH z2-M>#;`Hy2QpDo)1t3R>8p8ds+%RVQ||P+-I(etCr*z{^_3eM z1N+3kvkV(e^-dhvUYP2g#=vegY(MdC&Ewr0v)tiCT8K2OcH=t+0(?3SyYbuD3F*>| zao{VW_S(gTTc%131?yNrtIi76QL(zm#Z{g1 z6JLHDob((gh-Qz8pd>_dJCZtjiX-o0vEV|JKA@#9*eo5>btnBG;bdtrSDRYN9yNLwsRj`my%K-YN94~?t(cC9V}r>Zw?U%7MA7hnu_DV2WQ%=$6hrYvj%3Nb)!1ESlCoZPoPq9r~0eoX+Vyff{UnOy;RNp_oCcV8Xy}c;B^%gQNHY|8>b&MX9>^FMs4L~$k3ioc#W(V6z z;36fZ?BMnJ_O_F^efG9Xxn9U+!#wtLB{7ei23*%Um^E=-Lh})^m&qUy26_20XE`SO zic`^b=Fve7f~4iANYK?vHphdwe9E&K$1(wL74{p&Wk$CqE{ocUjn=9Q%tvf*Px4}j z!YHS@SxL4g_@@z^b?X!2!|U%Z3t_Xvri>eGCdyZG^A^3LbG_PXfTUo8hIx_bn@IAE zNky}Ibq31KrEzuK8}rjwD|s+KY^ugKe39;E{DHR1ExqzP4 z?;8&0r}YGj!dUr$*JhZs_fUcO@wpZh<5JRIt%-Xh>zoa&bMGkYR4f1+O?HvOu}vx) zx&B$7Qf9QJaqTDQunCs(K~5+czoxJQmgs21y8PJ5(eCdK-T(WK@F574a~pO4dmG(9 z=CxV(?cFO_>v;F;BM=2fU0*%yMpVRAq+3IU{FSaNc4z^-zSyZpzu0BVVL&%&&K%5->N$<)uAVpCiZ~_~;Mnc|l|)QUr4Gyfw!vHt ztBidlw2Nc)=>}HUc74ZTHT5yLL&FkZ0~X$;-4UDZ+LSBXE}YiH8#2N>N9C8=R>ctH zTa_`w>0d9g>2|_6H(iro&Q$3q>heq2oSqBVj@y;>GR&n3r)YbG zoA+FO+!of-%HxK>C zl)iRFbhFakV%)F{3pXFU`ndViBcF_PV~bTrv)cau<=a#GxiPqL;c%1FY9%fWTQ#k& zcl3PZ>Z9k0U#v)^t{r*nWFY};boz;a#$ZjOG`ma5z9OI6USXT zkfkel;=SzNeLY#O6aK2U{XsaZ5AG%D3QjcDg6r4WDCL=2a8tU1al`iK4={bp`LHjR z+jiX7@}jY>6m*xQiVU@W(gZ)mZI~hi_xxp-A8hKtZh)e|i0-0$!D4Tm&uh_zK z-HsFsn=oIP0_Y#fd;tovHfVDlcVdTD&wXoVFvkY1qXUlF29s)>0`49E9s^6wjOB}p zDIcz6Y^s4+bJc12q|_l%SFX6-uBiGUF!m4YsG(TCX395yF0sLp zneup*o)qXRT?F+zcFeJgwZ~MhrbAz8YD~|5^vV=#0-`xtyj#Ow`M@8aWK4pQBdLA3 z$ynj(k|wD$s!0k8A6aIlSuoX*Y_O(yQ`H;kk)qORy&g$*g_?R4PZ}p@$Bck$kr)Q{ z@)#OrN_|jc`Ej?49MkTOt;tcIF|TimSp*g_s3dKZZ;a2o_2`!DX#%x#whn_VI;lzR zaUgA|WxZm;)0d;d;%HP@0K^4R{1<=posMG7zB-B>z4!81b?m;;k^8zDZeK$ZsAWRg zZ87Ln22&M|7jp70z1X z*9YV4>qhN(P1@J`{&zpCg<^YCsjT(FS<%qw+9v%P_Id42RZcW6GSvr7k12+28IEWs2R~;fy5Sqb>|6&cY>s-`SxU>dG)=J@g(+x^nvZQ&&hT9qzW-w+~ zR@_CDw;IbOmczs4#P?@5ve@l|{sg?p9RlrOwAR`hQw?&`r$n8C(01+C6tvs{o&62g zl$%QH((dofHRZ^$#+owIkgTt0O(AgRWHBYH0atUsjC&X)65Mxa@yPrCFuQj!=NffJ zfBk$c=5B4jo|yxqhCgUVQAJIy?(LPK@1>QK`rD=Vxlh(5UF_1Z%jIo8UCC)rY0mb;CG`_lQ3k zM|B09@M?J#lA!3_1(FSmZ@kV_bD7Y5OLoFmJ|p9Y@TgIV6?aH6)q9+b=%QH}rhy@RI^akc+K`6idnN=3BKEK8FN0*n&;*&Ki z>Y5zVs99{C1#k9Z>kl-5@$rI-(1FAKzjukt*4J?mo_!FsMM+d_AvD`9E(SnY_~bk~ zoa}!yYy!Xw*2()1_y55gHj^S(QY>h~hHTDn9ygJ0YE)_%2jZuGP9V+%so~N=?Ax>j zvm32uEB{svL`T1?(7>AYAo?_2g$Dj??d0X6h|NS;bhWnj->q@%f4icZ{-7?)a4D5(GB0AEq;-#?`NFSQ^0J(krpvweb?;w_P_IoOonGU+l7qj$=DGkr$Y z=aYOdPvHa#m&UkFH{@{3s>NwLE*8LKXUFi8o2Yky=AJ(uh&=N&Bd1pFhV`3hmHN*)IpBwM6dBGjJU#q08mZ$#U&GYvT=Zkq?AGa0Tv|_SgQt7GIy~B`zFWs9| z58IKl1Z4B97S(p=q2i>m-aS_o%zS$XwX_r5sy*CJf zf3jDja7Nq}`||B?XMDqrIezC@H*UEK%hL8sC0~xJ$cvWw8xB&sLumzY3g_Y~AOT!J zP6Wo5A=0j6Y#e@rvE^cHH9+|#r=Pt4hdzre(vyXK8fJHijc4>mXg*>bPw}7zI)p93 zq*E{l0WhA{Cfi{kY^M{*EEB>4SW~-c8>_;=8ta;%n$j;(ple7-f{qt7(1Qv;*LH`51vyGHw9wB}?9VZlKs)Zg}9MJ9yka)K)66nyo^_w;NnX*PZRcT3T&G6b<@7;151}8-cjvdK zZLax%iwl?kCuc_?9)isyuyBXwVZ6+sz5#dS403UbHvjp*0(cM0)-X}-zNg&%zq1CL zR6!U-={vbl5u(Mrks*R1Kr!vxt%y+(Qjm#AZzvbv^yVXP)Xhn`D2$wpmtV8>Lv!s= zWPg^aZc#z5siB)YVF5Gc5xIX4Cd>K3R0JykH&K4}=;~r7088$eZ)dHX%X_?Z!5vEQ z55QN&AHV+<#PC&Iiz0Yo~m+3ASks=sctLFGF^|- zE4Oj&lRQ6PJ~vxTJHpEQ|AqZf`YN|l=CeRJt*}Lw^#BGOfmO>r%@5`NDX4?cwmAnE zv@`!9U2|Pbgx>rMe&vjujvo4#*iXJF_UClDMjb0~dJD^1tG^fOUjdqybLd|ATnA@X z^Qc$ecX#46 zP}CgW+w#Yzhg4Spf~tM$xSer$Rnay9ZbdF!YMCCtkw-WJ@d{qqBfpec>#lv$z6@J? zNv1}S>jxlOHGejtb2(nbHS-(Ywjy$-qjps^c(TzJ3`I&Urp-crJKTZ9v=+6+Ygs?U ziYH+IT8dEPnD}4|?Lz({KZ>N)tP@rQw+^+NvA zs+w-9rdzLOQm5t&pia?Em5`;X$)!ya}p-r)va#N)zy97ut-8y zS|k|(@GEAmVH9JNTw$?q-smjImpjdL^JPuWzPh1H-}J>fLrnv0LPhX449>o|>6cG1 zp@YM(&e<^=eI9jX*eV}+cr|K)gTqwUc#7G8x+N@0zP&0KTzX%~>l&#|uU=(2s>;Ok zy2dJ&@v*yyWRhOX10e>HC9sEh8m6nDbV+SI!W~$`B|sRq`jjVQSLhE;ziF}S-jdzs z8;7nPWG%mFj^pALT^-EqmY=I76iWC+m7s$R|NX7)-L%tX6v6?{F8qMgxI8*Ir+3T6 z2mbUa293@OsN3{mRtFMLtYTds=JPqXJ8Bb= ze}A?QVZChWJ`4cXWq4V}2lk*{{_y{>TbKUNlhSV9qG4Gs--fDSp&EHWX@#~(-UKX7 z+tqz8?0&Y_o*>#~x?WO(T<+f(pjnZkQ6v%%jq1EIJ%kh_HO}hK_R8>?hCzH;8?h{B zvmu5o)|9_!IB6#vro@scseM-6{5feS8RFs5h!DGyNMj(eRLm<%rgm~cGiXvr`@{sP zZ>l=DK-<8rUu!m%*TQjp z<($%bI%NubpeE}9$mw4p68UmFwU;Cf(L_|&!-A{fde{sqHgs@&A09+L%19}qQN@lHEeV3PBqvx)qB%=) zf+dL)>(E3TU*a}LDkWNM(;B|%U~j30FCK)Lj>9)%=Qx^+OHUzBQ_L&>5-eZK5 zDX4JcFn>m2fk-wnD`JyateUCC~IuU$|G~R&XV1A4=-k0>g?C&gNc;K`vR-WtC zS-GXUkSk!0cMkg=HY*>ed%ynvPd234tXw7inTNriFRQ`*pNmN-YHq&fSH%GQ?qxV;P6)r9NuM*x>(5N*3}+F`NsxuO$UN4}Vp4O`B=c0$jh| z4UfFt16xr!!XZQ5W`<+Zm>DjU6f>A^-%i4T5pV_40gpfV{2`SafNPmUI3ozxvIru3z(?E?ky|fif|&Hf zrqN_MtLwRG3a|v`ionBL2gglhafa$ghI0q=2L-7Xab+}^0Fna2p>1mvgzs!yyBSbc zo}vewah`{+kgDQrRVsV*ZKS$WDH|Qniw09#*4iX)Td7mbE1@H_^t3YxOrop?1Pl`2 zySaVVCPPk3o;mD1s9X#yq`4$#X-1J$s^;7T7HJU)vprY%&U z>&t<|!yCev1EXJVJB$~LmodeHHkbS({tOdr2~CpFXdI16G2BsXPoRp`Qt$TShLI$I zxS_ayBneQjuVG0A4NDa+m1MZQZloZ?eqAvalLVERwV157zl|9R0fOQME&E2O$2z`C z1Rb7LpZ5m|gx6!3>1T?0uCpuV%LCZNiAUw)f?xA@-i)9c9pewG60; zDXB3|N@|Rgk{aWrBpauSh>v^HR52GZXF~^|j|QO6v(Y@>V#N5p0Q11^0D6zf{jGog zD2uL=k8z+}&z07IffBI{b{ZKCb{TxLew}0mXBzcwDghN(}gI82N*{YW&G1CpdfdB(H0c}C=nYlh4FLVt=lI4 zhw#fYB)j*&2*D!No3P@<~CTj1_CNYDiR?&Btpw z46Qf}_!$Ql&%^*!Sd2)hMjUWbjkCx71=81#BaPS9MqR}lRM80M3rP%Gkj4sAJ~y+Q zkkpFd$c;V_r6LvCAj_UhA>7Zp<&0U~I4`i!6&)DHIBBCr!Q96D!VdW+!4O1i3$Y9C8;Ak815(cDQQ*bg^ zk^~sM3?4@?;MZC01j0@X;m0CDWaY0Q6`8j|hL+Q~UUWC`ji7JZY$K>e*CU~rU=$;v zXkciKx!88E1A`b{IgRR5fR&z@k~RkSE0FO8mhVU&mWT>lwmqPNYYwIkWrJPxKfhgR zA$FXU%DZd_Z`TE~P1ZJ@9RUFN2LahcyJT2Nc&yicx`hO>B z;2>xLs^d)kEuH?8_;VBdPja@!*Au1H$?RCwCYFgq1~`)^bFiXYxzM}-y>V;vQScp-@j z7kdpVT(98ZI)^H}VY^9%cAg;EAK*oD05a?Z51^}xowfI$jMxcLF&sPZ|946C6QW{V zE_QCYO4wQR*alY>JMaC>C&psu_`A0VJEy0%7(3`ajdsqwk8!=qGwYGliNCLU=!Y<~ zs)#Bf+RO;;NP~b4Y;%)q?R&QvK|~EP1byuqkk2=MBC(jYI_o)ArC%BAInmi-?66HT z?EK9&z|OHRCDt=SKEM7OY0`}&ABhK>qn%}g)g|d#?t9WbmqC=MO%YSj@=edipn0`jt(t(_77$oo#yTy|$lF#p43k3b@c=CDsuch=W+>!p*Ta2B^o1eM{*m?X5Y0ou6K4+^v z*A>G6iu>cWSS$J2e+{*ILPUs^OCJ51&j+$p{mD`co-=WEKQ3 zgz+1rrc2K9^%ouBPS9A*$|Wa{8Y}Lku?so!hH$G<7&maE(S+i_UE#152lJ<;sJ7}3 z=4Ul{OI+LR)hD+cQ=8}R2#9|0XdVt3MngOLTeOl=`QCzSc?;L_48=LtU^DE?AYk$Y zMT0Rw`tWEBAgYW2IIHn>v$Ja`UrM3~sj>x_^Hw-|C zh)I#B6NrK%ml~CqQ}M{5<`FK5N{&f%$RoITNWPu?!plxx@-|nl*(jlWl3$vnZgtyy zPw?#vCu``$QhNvzW$ze5J-Q!RzmB%$qi9|xMIpNuEx4REv_aI=?p{)PQx|zAiENStRU;e(B zq;vO}K5$^bzRrP*L)o2shdVum{5ZKQ<=)}0Vpp+~Q}{d0Xp(*pcH$tr9tv}1wdus1 z(Nq$dGV<-}bb@+*s+!4<=L+;eO(dVrvCZ4%2~)ZPpfAr}EZ*TV0F4F%gS&=MueUuo zHD!I=IC#jnBVWjhfo8q=%>^?ceaBVLs5aRCjxrm8%qH%VznksvtVjpAf2CuTKF;t5 zXF8ah;SXl9DZ`)l?C3hvpRAKYAlCb8x|{vau+dI;An0N`Y`JaSfgl4P1@pXGZPT$R z-TI(!qD4OzHKkWyp6nQhFHiHn7RX=5-wx&<@(#Oe>(Pfx&*DzF<4Xo>p!l!1$Bqn>@G+lP!nSd`X98z_Q{OB`%vp% ze38PeB{)KonmFE3jhqeQI-@Mr3kV~>a8*MxTb&~ww~bQss)n(n^u3Ky3RgAQC^fHY zV3g{F61{s(l$ebp7QK6CYa^zWmlIvZuEEaB?Pa(+A@x#MCwzzXGWAhMQR0R7U@Yq1 z&s>9T#HYWQwh<$`_jjzjDBv=+%cqIjZFmpUeT>)lr5Q!x$R>}i{^7~1u6zHfkI+WY z@6-)jzxcMK09*BN_?L;D<*nYJ$1Ujb_kQB4W9OTnPqZ_#1^wa{Zb8p+2gjC@Pejo2 znX6AeUwM2yf)GV`o&R+8vGe!3Zp9~8xWC1fr{Ad3Ph8RD z+H%_26R`7V*MKqq#-m?|*jb#fsg~bWrLT5%6pIDp(M~dIY@T+OKh4hesu0iHS4|AO zsty_7{6Ip_2=P2srC%BGTs4P`pS%Xx`JG>_)~EWq^>Zgu`Z$aFB^hqc5r}?E$tM~{ zf97f+$khRL)8C0-PwZ#4Zo7H<50Z7_#1&1j6HTYYEA=|S&szJ>@)sRJOZB~68Jy+V z(fIdrE}eg4*YO>4n9;WNZ(*Z^FlhQP?z`1?j7|Z#>%zp(%paVs5%0Ebu6v!1-{5Gc z(a@Zp`iDg9Cwesw`jH<`tMUp1pE#&#PB(j)@!a=Zl=|a#XLE-c*;d-hd*W(Pf5Yni zHwr=QEAI&D|5lZLWu(8h)mCpv->~!R*8n@;IGM0BLN_bA+}p9Xc14Wg+>VRV&ZTXM zP-+-)Y7`m72*0h^agw%leJY3GS+fSva}k+5^FzNoA` zmKK{Uqn#5Mx7b`7?ZoZ$BY$%BCH~dQ=SVby-@Hrwzx<_ywUsNHS*sW4%9nPC`utIFH2md>& z6@9r*Ki~ZOw9+qL8U1i{b4xMw&1;OIl`p25G=ibUCsX>BVd(T$J0wMo!+(yL$}0oK zR@2YQKcqEEl3(IKZ~1njpXDo}pVM2tvTqA3`(IrH>@3#g;yVBN!cxVTu899EUM;Ec zt)IC13WtAlGSSFdop#QADy5&kBHCGe?iTZ&Xh!(yYk-}<{z#H>T+<;ydS{k;HdSRJ5~pMQ)#iIeO2H9*kE9!V@_L~MTKVQf6UA-yuOdCQkAuw$C44>)$lYO17_vhV4x z4AbD?v2y`0KNYIH{O~ogxLRgghaN&)Efhx=cj8;8iW(nR>w>DNjhy&ehlre_&5e$o ze(kT)=xKpSlmGD#CXsBVZsxco2flL`*D;Pb@THhq(SdI?pmb(V8PYM18y(l7mM8yT z$5?4T5kr}c2Zs!DxA@w>LHo!1TIcXSxjSV#M9qIY56Q(SISHk+(lh^eySo13 zKow^-Cv-{U%0IbTm0$XKK^N}$HFqEWkTn5DSh}0Dg7LxQg;4tH@j{VHGhE>QgEJ=4 z^26P{a;IS*lUe+Ei#$g~IH*)tI21#wARN$;fzIT)roav!Rb+vZeA<`dWeW^NHK>&q z0F+jI5@H}JAO=+^@BvY#`A`fxy4TI%Z#0Wvikf9Qn8RFKF+93*o49ahg4^O}Wtj=t z;`dkV)71|YBXntZ)Wt3Zi^y>#^3j_4iP}XE3`fh8<#E;=4#mDLKl%=W52P!rEdGsU zO~cWWBb7-6Hm2in+eZ z#TR)%h!NxHEn(pJaQV5fo&+KBdLSW|U_}4HV9Dhc$gti94-}#GziGEyDQc|wLPDuH z8WnBhA&eO4E&3n*Ih#)^cYruOc=;&-G?MUq^`JJ0t63by&;HL-9fQ1eU+4bzefj;n zh@kl0HXqBy8|(2C&rcjK-=#yK5N@3D%X5dzpEoWLFFVW1Mbd(Qq>9KZ8_zmpgJRR? zC%6oh@IxgZ`AhEp1GXm0XO({L18ko`b_i=o=c97&nuzVl>cR~1x6~c%6!A`&at7;17d|X74~!*Er}HeO8bCpY^-A z-AH}*n;hyQMMi-v7K`~CGJ+VtA@pcSJsJw(RhmVxhfNmjAub>_lra=tY*ov^hEsKB z!ee;xu&?YYA*X$ISEHR!>{E8TR*7~2*Ho7yM2U7ni5?3kqULZFAJ@eWqHNi$reC?& zkYlcKy50qF^c)27m~V59-FUYurrY=1$-4QNY9(+@z_axs8!gvKp2f~PS$c*RKVw(Q zMX+2^ivmv=_S3>T4OjnIL%sqSI%_1E>5Z`tdgJr6cl(MEZHa*=xrUi_kZ2v9`V+0A zWTrb|wbX4n%-(8Ocg?<`+sL`$!TkFI;RY#1k(H&NTYDS$Vgh`gB@oeY*1`>Nq6?MN0X%Wj7pqH8TzaXWNqR#lDuqeoRnQl~%peMSg3v+|c*-U{ zL9AI%3bjUSiGC7RC&82qvo8aCq2EVNO5%u@CPs7%ABZHzIX6V4PmyxO^hm8lA0w?? z9Hf=~cZZn?)H2-jC6u2&C=Xgb%ojQNYmfDiqMyD+XLDS&wtuNpo|54UzI#WJQs?ch z#hZ2J+ala4iy#{-R`#r|?1@MQd_1a(8{7=QodFG62Ic9JkT|TvzASxd?xG(YRcX}-^4uh1ni!(W>E0WS5a#lTT)OLuMZJDz zolKGTb-zr)>6eh%ywmD~XF&E8wr$DC--zJGIMQEs`6U|?h^+%c1qS2gfPWTB{<%uV zkqDVjwctC9LILaY(=8UCE)$B62*&Zzf@*7w%{#5}OI|iGM@j zl@?Ss)J+=ug~0>`;~tH?{^ksYZzx<{(zA>HC_`@J)uyf_T7#4WwYA*pcOZT7L+mxJ z&_txQId7p1kK9&4Qj(GKvi1WylMwN5J@gpl{SjpY6e|+4X4}cA(ZfiQE{m>p%MiTM z^sUYiHGe1%AzG!-#yHx2@UTRzP=W@%utR~ua`?VummU9bwuG*^RQLN1iwAld)3)=) zit!Pu8A#RV>rDu~7?cT0LOz;{?bFPp2Yux_>|jt;znCC$WM- zeBP${3~5KcskG5-G(A#DeUGJ%vsR$*GXq&4vMiJ;qhwinG<@b5tY*%I3D#r^4^DjG zKhOlUS5wPndg^5Hm7$PIRlhnnX(5jz^mDxv?>LF`qxV^^HmJT6>9|#WC(LoD`c91F zk?K3*z(jc0&pE=j8Y%qB+c6>L(qGleQY}4Z101;t6>}_`(9cxX(GSqQsrFZsUBYnR zRQuXwcawhqayuqp<4v^-lih3e`(G!!&(E0j7bhC&O|?fS=d*i{>gmrW=V$%tE0ewJ z=6BzF)Ci=)y&l=ySYZ^fwQJ{xDD(XJl)ulLpXP7RzHi#MllE18q55H;VQ1H6UHfp# zKFsXHYwW|T?ZebQYz%yOQ7tyJN&E0B`*4SSIAb4fw-2}JLk>&sqqk!NpD(E06ceX9 zywyJ6Y@ef1k+R7?-)NtY+UMetM&p_{x@p>C>{BW{FRJ!zaI9O#a)ZeDdEq z<&*z(nEZbVlmERi`R|?b$$!t3PyV~7eDd#`^2vYKlu!OUr+o6C3X}icF!|pJlmG27 z`TrOu{~c34`EQ@{$-j5XC;!NlPyW#g|FF*7FA9`D z$lRa$LFfL2KK#Mw{`7O3`;&a0pCgho>fP2j_cfzoP!GcVD^s!9rS$f~wu5LFw5Anu zG5cW^iFXVr6T)QFginbV+iMJD8jn=1khc+XB%q$()JqRZ%bWldyf1I+P1-xRzJ($y zn|e)4vJWmndFC4DHuXkHL)h$Oolx%Lrrwy9Q{B)l)7GI^*t#|eWo>NqDpRkrvBUEh zB^y2c^eYZwfbd7C075Xi&1!CQ{zn(Q16Bp24ssPA@xjJy@)=6+8!SAPrO!}!_h8{o z+34ZOy7CZ8Y@ZS#ReJ zNltGx^f{wtW#xcVlfXt+_3lJxCaVi3qAo5E=~6a=1mKQ56|nv z>MHjSk&6uQe0XNMH$W1m{KIqlaH`rOmv}JESa7F%Q`Je>=pUTb2Pw~5o*T;#>BJIQ zd^goa*x?ct^Uhs-^8a2$#}mD`}vAhFNkj zQIrld=3pWV7-^w?Z_kM>P_9(Ny3aN%)B3prKq{Fc9GjGB^!MU)Z?k7+T-hR!@V26% zZ&VpeJ3rmqNa`X-#I5HdN~v;f_?M=8TSE2c6}vy%QeAFU8*cmvz5)>%^4e2J2-H9K{m$~IPKxhz>sa-}o_I-}wG;$RBH(2X|6 zrJ-EbSjb|r$uObmX8H6Q1EsXIFkTO&sV=Tk&=>4I#^rc%voYUUGE{w5(CJ(`tgN|^ zQ&_FJX^I?{&I>|L#W1QI*2d0|W0r73K}X!Zjf(Z@s)zMd3mIh7V%=hkgoGEe0!>tsTvE$+ zgVDy}e1YA-Qq=kk?2HTBdC9IXI6pB#e^Fg_5!k57fy>m#4J2N}dynE~uy$g~(l{8}!U9flFHgq65<^&q3cH1w7*~ z$Wq`j(gP{v;tcWKAUnXlN%NY>4`tac6QFPKpQ!HYO(a-u7n&wDs*i0cQc?O(p;Cli zR!R0Fz`#*f3Gg~elVt)LyTs5k0V!qRa;yb*d!#x@*5EIdsI|&~oUMAgl&rX5y?Sb#Md{2i<@W`a5l1>?~4$e z9}whxGPJ%2(|zJ3$o2293Vs@=$Q5HN#_6*mbojQ<#x6D`2qKk!N3U$??aX#EL}wId zHXg$;v*Drnr|U5;J;`FLdib1XSzAB5R|vL<^+gqOD9z zThS9DhShRzQ_(PUGhrC$Ip@oq8n@hts(8k7HN$lz&seEuxRT`=7poa@-S`5%g1O@! z&p-wXvI2?eZ7vB^K|=y)#|{(62~wt6ZiQJ+k7T3AdUgqws3r=&=pS|k5lNX9kc-C3 z1}34s*85|Km^}#yqDEWFHV+-k(j&)uW5z;6mIdi-8$`JxK9u!sJlr#BPG4osV^s=S zVfNWHJYcjcE~S?W#cHRGV>BWzEe77j?Z_#WRxgt?QKhVUlyF zqoxyR{SHzy)^)j}`{U(`hNWw^&yM!e5=QCaUIhXJXt6Yk_>Wc|(4s!L_)Wy7x^t_m ztHRCzT`U_DQ5>?0Q71vQW8@c_+)wYCzo$!S#p7pQ8ft#D;kGY4CQjB#5OOs zVaQ?yWZL{CMWWBiidFgSq#OoVkX-nVXAN5z<_}nB-zPq?eGt;HIftj{H>fLyV;Uy& zklQJqxF;c`4Hr)%62jy+B?c;ep7|aYbBVhtN`o~L7;P{O?l>%l68*E>E9G1;zIbJE zhb7tXdt??Fi>$yD*b^AoTQ4?7iU*n6PsU9PBUE(Fr2v0h?X8fXE=!*&AD7BUP+9hY zP>FsdyjWnX@M~s{^AtmusHOi_0qoQdCadf^xwAm7SQJ5SL8v6zrm(VNoL`oluvkgJ zl})^&5^q70%cUT>_?MuAr`+jWQ&$}q8+s=5$d_QLf=C+VQbfAdIgCO(Dh25Kjj(YQ zA2eD@@K^N|skx$Q8FJ!E;6>7VwTU1X08iiGBK`64(hY*nO9auE@AhOkV6nj{lJ63i zy0js<-_~lfCZQar8aE zuTTNz-Em%U#dl7Utc{KsYY0?4->=XCCdR5G$MsG62P*9wtdwBs;KQQr+eA)i_;2aE zrIz6I!OG$|V=2E>Nx>t5GVdr;G`6>*h_D}-m^*|VW+>u2mu_dRsdo0>LNXr%DNAIF zE+o1PsKgAflHjOFt$SqNZBnBKlrvM;I->#YW zX9?Fn|JlJ^H6t-T!OlBCfQqmx@PhYV-bYnM2u~jrRHL7r!Dn!Dk#T%jyNVmbc0Rk} z1x2FYfMVT#8@_Hk=x(;7U;0Fn$_LlIS(Cf34qmPGdy>05_jK-V^B(+K7q=Ad%IVYc ztet1~T^srO$Dquoic13_wW~YY2Q>#hL+bhY30oX;TGJ=26N~)`K-KjJnmyhHsyt_XmjM=-nIi zD)AZm*a@NGSoA9S;m+)-*neQWY(B@#{A}_dVKw!8sy(wOSss()q~FQce9gEVM)HOG zAY=J=xRUSPqGw+X^sGoeUQHJ61o8;ZXsBZ%i5*qz0X>KG=wTtDgYlL$U0N$Vj#q}% z^ZPa&%-3E82AoJg`MF2pd86gJ9Ypu9vk-l%p}S3l{!dN_n?ZhmUC?)Xk_#ZZMak^{ zF_EW^Z=eXN3;JF35|3#q;MK?S7_Ek#CRU`igcps6ovy};lw-6O$9gmSH}BWX#z;6< zhIqgw{rtU<3G*$zTnmG^b7d`@T#FjB$^C6E?*=hWw#{R91zG(Q>cumR^7wxRzJ+tf zmGyy1a@eMS<;aOYRHxSvida-)uCKukUdJ0sE33iEdZ0U55P@NN`sA&2FO3{#t&@3W%k^+=ftZD&#-$5J|{E1lr3`=4#M(svi>l-$9YU3a$#>H1dCP!dXFnVl5^J2R`E*C~wO_52cI>c<^5W?3>l@>${&=~p$8a$DE?W86HB8XlY>N#i!?P(vdC;;*Q{7X@U26J2(EKG6w=kPWr{jceAK zm+|!Pl%pl1_e&GHkDGGL9&m6~#@`Bk$nu6_o{C%=2ido08;MX|>t18t^Py0-JxJlP zj%;Wk!6r}ZuADrL<2;xrWS>o*nxJBS`x|iP;rHlYj3c&pC_@yw;xZ1W!{Kd?AU^tW=}M5W4k)7!wj zEf3*+E6>j+`)_SlSg&o@5W@&zflshvGooIvjAfJYy6<`xZWH%Ob}C3DbsyWlgS~Ds zy~^8tu-6NDJU)-S-mp6F{hU46yEf$V_DEb6v>gQ5NNt%N6p#UT)aiSQfcIh3ZSUZ_GlU^-f23XQ7vR zr)xK5pl87aKR0whvf*ik*d5Sk`J;O1jVFZqe8%<=i zjHa74AUAZfk!>QLxmlx}-WYp?h(;_?D&0VGlhz-xL#gzq!5^hM^f8z74CJ93x-Ef8 ztFfn~&yCYH^~s2(F+XJ0Gp^z?&dM)_nI8scWyq1UiibmEjgeSua<& zQEcp@40X3Vfz>DAZOKKwj$%8}B@wXQSKV4JDq+O9s9_6S)VL{J^qTd#=nzK-Y2I!X zXDvf&5IAZk=r{t=oj?a95{0xv#FFq7(u%%}W!nO)ygHi>Pn!#V`Xg{TCo<0ugD4p0 z^Fl(wDZ3$|!Xl?4iyYD!)W9Np4&!V6=Q{tH^`95`&-MOe{?f|=_>6$g|D&?@;j({_ zW3;LuAFSNZoyEZ)ClwB8|UTB+` z8o`g+2B@B1WSfV2vPxwKIyFLfG84PTbpF{I&oVaEzhQ^f!L0sR_bML(yh$7aON+P$ z#vySM4$F$WbmxrYba(m=+%Drx-5Z>hb@#xuGMFAGFm`095?fNh9{un zHKgy4bG|Z!1`f^=jN+E@x>3z03U=KO&Nj<~vrQuDKlCXd(bIt8j+H5 z!xg6`VM6NR{822~OMG#^s4Yjv&32^OedIo@x#@qG(Tcj@1L`h@FQZ==zJ5&sMW9`7 zt8}>&^5nr0n!|u?1bxL;D?~c|LlI2G7Kq|(veMG# zCD!v+&&0h4N1)Nyz5(H)k&V7)=Arp(@8*OTHqr4;)=|h1=r?4Tc3aSI;_XQ2Yz6w= z{_*h<(QjEsq2DWL#L}3S_1jXd5b+D5m>7&yOvgw^2}pnl>x6_u;jIP)HE-UkZt-vk zrefoukEhhPCJ79vIa||7v4~9?*NQWOU7(6~zO*MR&Wb9roz{^pSzIu5Per4cA=Q+` zGS&32Xi8OCq-K5PoJVlFFyvB=cw8g>VB|e;0tY8?Z4lLg3wNm2qK~esIp?<5}A*HVy9(5NxS@?&x#@W~~-A2>sH`a@g0_?83%e5MU)40`rO> zkp4dbjnCpuB6=>3RN#JuckrfoXRcU*{!w))qRBEIi&>*jmxR3lP8zUDmBV(&Un$?p zB#BEFy?b=LyRk}X&X4;5w)r@*&(oUL8*a^Jf7dfdM57h^5t3)JZCz_L_lr}d)(HQv(T1_Ej-KGb-s;f}&)*rA~&8-E>BfWk!gx z#TAt*Ed_>7OLye#qZ`smM%zJgC45O_)C@F)se>A7{n(xx0TduVdbi>2NuCsw09pB~ zb@5F@*$~jj(>y?{t#1NH! zD=d_5i z6kq~pdW}2yhJ@G1lL}OWnu^v^@gr=7{rEW4J>SjRHq~LNP1W1UeZ4GS^kKD=H=Jw_y>*NLGRMv@Sz(CWF^-E33QbMEH?CGDvcI; zDj07#XsHlIPi1u&A}UqNorvUihRf}TQaKsgXJHTeJyYqatXJrsM=Y9$l~H6m9v+5; zu+1ke+Gz~++D2P!L`%-sg5`jhp{seFv%+FcYWuSz9R0{POApUBcXjJzwvlE2JGIC}O(VGz1N|U6H9nv&Mt-y&BB0zqc zU_R(kqaxh2%OMzV7h8WUd^OIHR z(vHe(VUmK%iYS{5VJ{HmNPkDQG9&FB6#_@PJ8FbA5aCgA2sb{lj7D?DmMulG+leHByKo?eOz@Z^LO*X`gA5~WPl0cC^%Xad3tEN4OiEN7a0 zEN7bb?oONH?k=;IVmX5&2*)J!x-m?Gt{cN79=kED#hPP}5KLYNs1*N_RxVsoGw_W*~vrynk6 z+UC7v;abR{ubyKQ8n<|aFO1A{Dif-7#_8$hbPAB#6GN{Q<3g`+<5b&}oAr%T^sV!N zoJXYHFa(oeY-zB1O{vrDH9RgSpf(aOnGQCMfXQMwH34HzMd*#p8zUf@I$C$+7HG$~ z9Z-xxRl`R>MPNe4M2~B_hD;$aLOsC@_F1uOiK$|2VwN+I zkZw3D133z~Yt3(kb^{7g2gZl=+gg_n9Tx!k@O%s#r*v6c>0#Xb26EIK3y_T?8QGG- zq~l4yLPalR1h4tQk-(o%jRY=kHJ=$-Q}e^I0D{{N|M(Gjx<2>Ht^K7~D(H7ljSqD1 z(sYd?y#5-b%)Ed6@y8l(pe=iNV_ti; zR*?xu5%=bTYx_h^0^&gO!HmYtu z-FQ82FH6SgALx(9h;q(%Qe z8+DVdBwE;D`jsdos{AZp_qf*iF616bH!y7d%{y=E(mW6M9LzfyqV;9|mN(sD;uGT$ zmD0kCPtdB6hOQr;SPkJx;;DZDf`=#KIE5#ZxwKw-?I7bxDirC6B@o*LU8F#u!D1Q9 zMs+1)6j^lGOMz}W~~*V{^YIDbGbJGo~w>G+TFaq%%`J^#$-(oDENn zMQ20HMpsuO5a88r5~s#`&=QF7*cxX;Xd&N77AV~$^j5k_xSUYgtv`u%zl#H}dD!l7 zWz`Fn+wE2(5G?Is-bA5K8HJK!CqZw(Kf>H1@sGGFEQklkv=pMnG;3?e9=<0@M`5u? z#iCU7YNr%JExac%-fs7WXRmM@luH+JYS~tYw|5%hUW;O@i@QoI#NDkhW*DRLzgJK33^Y3?*uBtMskeQZb(`t&>`_yGwO>_h8OGX-dAv zOI=Wdm!oamQbzOWZNx7m8azcHsB&BB3THHf_P3UEW=V8*ve2HLvM{ol%G|3iz%W*E zHFf#}WD0~(huk3p3LNC^sUIJ2;|NKPXb=Hgf^rSw%EcG^@k z8pUuzRT8@xPpCj|3@Cgy7rYR@KSEXT4I%gd#gf@EP%LxiqYqa=v6wR^_DX1$QGy>L z&62Ljwn+D?0h(1{WTaWmVo?N|75QaM*Ej}97m$J#LbCJ=>DoF#x(XSjEumKkgFdz; zm~X(BNR_77p-R)5RHx4cHJN@Us)YYe>}DiK)uk!QVRUHqHU!8yJ@6qbKT?sklxJhW z^0kzQ=qZN(&rEr)DVC%Y5Gc=Nv6wxH_E*y<0Jp8OeuZm^RExBN8BUf&MOZdKhVfIYi$M zm_zV3!VIES)sZO#-4`+_vB(HdAdCLa0+GB|*oO??6GZ zjb#hgWZ>~mMX^@WB>R^k3IZ# z`iC#l{5SvOAARTp-}umP|E2ZUj3&!?F0f?gw+?KlHS(>pBBp;5E@WY}ZUw0*PzJ7` z3iQLyk|xr?Yrv($>2udzf}+M`sj+fbSRgpd;gaI?;ZI^=@dY|~3yX_5ANb@SqtLXA z12^J?Ln3$ni7S+07tcAK9Hlx?O)qyG{!pA^bq?YXF5h^sl@ zKw3ei;rY741GoV8(cfJHpz$=BFM?0lapA^#i@@cw%0X}kn`sOIaHWb_N7!%NM zFn$*NY-KgXQ`sk#hU0u|-sii;LCpD;PM@>cD;&)9v)Kg<1Do8EemS^|DT;xBG@ha^H65|*)XySnaU5a~6h$9Jb&GM91uy4Ag*3ha{CnAG}l z16pxkfypUfH=wOOiOa@(#4!P3U4Sf90OI}j$+62RE3UhO@aOF^mgp*p^(fT-{j}4s zv{NA1(N;Jg*V3MZjqmMCLW+1Dmam$R{<>CPyf=bVUvX46dhx875QphIp5|!VSd`V> z@t;AYM~(}-b&wC~!t3{0*emESPjvU`_dMG_p+`S#h_C1_I-`tPz!YYGrHM6;b}u%& zFCmvQ0XJ@rHXzfY!ur`W-|sJe=6AmG(8ckekz7o5R63H)9qP?--5>w|G$edyHkXYY zc<9h=Gc#F-6Z`Z1dmsPew{(o(9}Xz`Kv7Wz(a)-fz@XXNN!812#c;^%rQs{eeN>(l ziaM8#%@AjBmp|;`=Oz5lIp$8bj|V#Y+Fo;}N3?+9Y&h%Op55%(!`WUQnlp#9jykAd z0>iiSJp5WL`IIM2mvwi=;Cmuif(T7J4^@v@d%M^V>iu>)x#zrY#47p!@c^i>S9y-+9J71@F_1kB9 zd+C%h>{Eb)?(6>pGud9zg`$cI)VQiq{X7L3%}*Q5_(G)vyvRGz#6bb4wZ{A>zVWud zhl70lfqV8Q5`4@HuXN8Ga2x`6(~rCRrO>8$zDUFngjUC;!QCinSQqgnk3-j9Tx0&T z|KSgyOiO=t!@6xg0Ul|OVnz6*qw%rL;(7k7AO4H?9r@J9{&;v52z;9Mu4*sa`|^aH zJ|9~HsLB%*o-iMsP>(|J)M8(z9ZrT6EsC<+$ksnDVphF^1@bMBNIwxEv|`pi&sER= zRAhQ}&xQwj=02*`o~;l6)wOg6YLRcMjW7Rj=U_2LSc-;tLPY2USnZ*pIFzSzc2lH8A~#io$&UA=l7I<1{6 zQ%#2On8k&)I|i@uUAllPSPZq-DF&`{h46TGt5Alp=ZvvO;8kpQM>0`uas2bxcm``> zC&zY7@9!K`7;;IRGVjP;O3upKvC&aSjFF)#c&BRWYokQdPox4IAJ};4xMStXPA?4u z$a0Mu1>i|yrl;BF3^7~7HC z&KS+Pw?RO>N{0|RwR0D^2Lebooj&Rs2Lq;e?%&H?1ZyUOP&t=4JtRnYi*}C)h2bqG zVm&s&A-RfsHd>|>Lu!e(GxGxnYp_){!=MN3xN%Cg9XV2&R39*If0|qkxT1dAfC0M} zk4@?xxhLZ9MWNsoXfv>^8PHJUura6=i;I~la>Y#JqQlq|%Fm>K7UUvd#O47dTTlfq z;B9f3v}|e0mnz4pToOPKo{Y=F2y2k%WH<|r#ZUMkQV*Y(ENhHX&)*lH~H)tHG# ztJyJr11_JOo0Go}HVnF}Zp5`&S#j(KAj`5ew3cAnY@3bAB~mK@(N<1w;|(M7xXO{= zWDJPWau;X%rF)`-8Z*B-oB0Km7W!Z-^oG-iMaL|XS@Kh`AK8T5kl53XUa|1CyJ0&h z)hVIlj-S{q*1^O}<1+0FzFy<%`i!o6PrO#u_Z3a2aH)!PdW)3AhNH2sgLD&GWgwlc zGEov+Wowac)he?NhLKFJHxl#0W+L5xpq%Hzfk5-{3-XQ(L(SHp(j^wej{HFn@#n6I z+NM_df=Ii{QB<-TUK&*enV5FYjP?H(^$<1jOjS+HFTO(}>`U@5eXgQBR*3)t&nhBd zXAK|%&py^_C(JpZKxuMt9%w|u$)#EHw`Jz+^qbjN*q-+pl%rA84fByWfvs|}7u7bh z(X<(aY`{sZo|1CVQKK9nj)Tuooc5O|XrFz{vAkdZNp5&WoSVPO{WR4RRtSZlqbwGk zWR>)^#8MfhAYw+h14)NJ$?k9l0Sj5_Ah((zAvW{n+MCjknJ6lIV%9k%DsiSMX%f*7 zVeO$qh>qIqqE>By!vx%vM~jb5R0yl}pr8<}WOY^^CKX{30Tl@`>)gf$Y&E_5e1HQn zEERQKb`T3XWfUm?ePkXMuX$)0d6Sox%D4rExd&2aHZfz0TTqZll1Ag*z+&(IWj`8N+?E1$_D>cbe`LUxvN*QNlu|c5 zh?kyoE!(SlL(zN^FFhZsm`^|~&F+AQ1MdUQM6ziPPDRyL7i|`UCGM+O^QiB`t138A z&CXAm(POZJ`(p`p&%FjpB2sZ1$QLC0o3#6pe}DgxUpvN;>%tyziAa%P+=5V+ae`OO&~3SzKSk-6Q~_1?D?dTr>OKeH=L_D-32%jx zp_QAZq!xX-l(1m{S*aR)R!GxS>9`H~S2n>biFPDyg3nUV&MZO&^*bu>w}+|j(Q?s~ zGv4ai#GuNzp}&>ys!*}I2lK*g<>$$JNp`cwRn!hNygox+W)92|*+h`R`|Z7MRJff* zjV9Zmr)Pid*B<|sOYPeM0TU3q0^zC_=5zLyVV>r9vke0n0uJ&L;V@i7sY(dyeG>-?0$+U~^>wKzt4E`X( zj4TX4Oax2mo?{>z$6~2V&wKRD0UgjZ{Yy8m8z9%)H#lLp{pI4un_ zGmC-5HWM#oN(hRZs>sscP*-_L?{ca3~IzZesXGiVOHtl06FLiG`YRouS zcH|u;lt+xx@oQ~4qmfH{re2-awvRb#OtV_xX2jP10EdSg$gS8;O^sAfizC5oiiRV> z!fN*55o!4;rd6pp07<^~jaifZToW;GmvSSp>PT0%^gfB2S$!A2h~AQ1Vag!bj!?{D z8Ou&H57jH(8k9iK3*P`O$%s})qr8&k7+D+Y0-V@v3Qho+43N9)>7PeJwm9B3KM&kU z@up_u76|^lsDOw@Q4OHgSvDPD2i|Qt6Pvp+%~N%kD}gyYSPw$w@o=(MlVKaL@z6O4 zB$FdjCHSP-3(+>iR{IIx_mpQbnP|Ah9w&WqO*Mal@gwU3MPzT8Nx-=;{jp?YQ-f?? zF_bD@6Z7cPzb}Z3q@};7>TM%PW;u~?_fXZdlV%JdO4&oF8b|2%p1o4VKF5DM(Ijo4A`+ z6kukNIQo&4n8c(Bpp8<@?! z@g_TUwaqM2)YZg8J>!i961I?P&|Xm$ofgqLuy+trXGMy4@KOE?;a$f|8A>5w(;U#iCr=zKK^7b^*~N?55R;4)!7E5@L! z$C^2Ua*?9jtvGpENg)P5DQ7DwOO~=!Nm;fOwiAnbxaEnjh?8EVa48fiY%&%p+?quS zVc3h5K2Vd_KKi!SBnto*Z%0U3L?U;6p|~j8YG$Ezdl{E$iB$RoA)(x;laL^X0DV`L z9>hP^^_gZZQCyVs!ZG6%*)>jQFV~yF>&wf{$#x+X7_(ZpF?vN~qI%)_azk;PY`jU& zFy<*zM6_PBs1MvIt}k#gkGuQp!D}$a?G^QqIRdlC0|~SK1YpLi&`|gGftKx}88>i>OYFLF3oh z*0`Otm0B821R$KS{~6s*KKpxvZYN7`dv>>zc5pi}yUDYCr%OxmS-JYeW9 zB+(^3L2@uB5*MYihK}tQ;J% z7&-AMPvb7J#dvUt{U{`0mR&zRGG9}y<>3d?KYbgJlDIi!+ZFj+pxeRa(FtAM2wia$ z$06_)^Ft{$1rhdle6;GP;RF?8FS_qA_&&A9XGTqE^ndZaUco~8p(HC4)Llx3ST-OP zU@cN9hwbDH+kmFHK|M!)$IZa)>Oihhy_@3MM^&&hK|z%#V79$kFUg2qQm z!HSgliBemxq{|CtNYjIOBQ{a~6N0SN-3igqO9@ZZ3&wQ5U`)n@s*LF|^nH~+zlt$M zGAG7_s`YivY`!O)IYfCHP0x$7NY$EX){{n}P&HB7YW!qz7s?eZu5ywBWUkc1cQud% zvO(GELRd}9mDL1Z49ZisYYmPdoc`% zQ_Z*y)e2s`&B`{Ewq;Q<32cCRqod$6c^d&k%p8=)|KUGJJH>f!bf}jzEX)FO>2eSz z_<&BHobd2wGGs-`gNN$wu%B>ol25VNgzLy)9pMuu&ETaYPgJ?6I|xjbzPx-fxQ?8f zTJz6EzBsoI?)bPEPOmMC1A6|y=`|mkKUa(9v!pPeu`@#KvpVWFzmL}az&D{YvV5pJ zE#@i(Dw@=$IRh|?LqiK~li_N2^MtGm&Z^nA492x{HH>y{UXz8u?GTuhn8RinyBCuZ zz_XLdLox}qvPsE~1WwCFXS!Rk1+?y>U(@jzMMKNf0|jxK(Rq>7-bu4WIN0rUPqacb zBA>(>$9dVRH7<};oun)UyWo~8X;rK^(}`RP7UxM#Ru#3BON{pA2hWq@;H2}UI3bHT zDhx_|ipNQH($&%c-i~am9mh(AV-PYw52)`9B_xf}Ge4kcVOCuAHc!`BKmAiVY%bv- zBhf!Pvb)mBj$(^ohwX592jJ?_LP1;=4`hdJ^#Tobz(?DS0-E>)<{O0!il_3FgoQ^I z#dsi(J}(a`<~@?UnOFS7;_#DMSUhca?4sh=g$8EJw5&WUYjz|%+9UI+Z{$d_^`kuv zKmTKK>2x*`+|-?iicG0T0$=I0q#k8+;i#k@6{(MyZ>Trw6Ow5+LGL-&>lcjvY z%o7CtKz?@!qm5A+X38Q3-$GKLsxd_>!DCqCjdMR`u|5LFn~2{09%m#5j$^1Icizct zW9%0kme|7Hv+iisWd*bw404BL9$anhv`@gwnt*64tBP-yYAdUXnU;#mAZlLXFsY6Q z13{KiHv?Di?U3E75zJb4%E?0Z^PQG$5#vQG+joXkBi=t8ii4N1rxs2PC5Gv8iz`Cl zh(X}HRR){EGdwgaQ#NsCK)yXzpIp2|xTp{FqabF7DjL<@xm5=!D5FUL=$d%P9p@TQ zMp5AHj#}CFR}=eeyBUDBZDCjInSg?Rtq-Ctn9T@iEJ5@9?3ltxGEMm@mS3Q=V6|=5 zM3e9R7Dp@F?qpW9Uk2$SOr3=ZqIZh1BT7K*4p-6L{M#hS+Ohy}Gqf6QzS#%oLtCnn-&S2>++<1IBu5am`!5-_D-XFZZrYyaU9D{0sPgr`{ zWvC=Tgc>=<+@b^&$OuJ|AWLr}KT{Zk6Qd*fY zFk4D#h{gtODcIbKuVm?MXq&7^k)>D4uvvN`Zz#pgWH`GgORr)`>6AOWEJQO5MmOkr z6#RWbrjPr5OOD(@@Rr5L)o?spF)+VNR)D?1;KD@slcTlxz^pLa(DLX8dz2uCbCXiV zG#C9*T>7{_nt!+vxD)t5oh`yxI-{+Ss?#G*s!*3^s-y~v8pFxB0jNr<=%SB~p1H{y zG&GX61MD2wk{||P6a=gcq-u(k0$E**7$8&7bE6l;oxf@gnX(&0;vz_k*oj7bi&9OjLqY)Fy7N> z1ThJ>G!-pz91mp$4n4=?rfRX=`3y%+OJgeS+IBSC-1lakqx7`ho${3jhFrle4&B!W zj@TyDUC{**ChJNLj5i;y6E|G)cySFPN5l!xP1LTNYb!bx!qHg^AhFF(A$a(kp{h2b z&3umr&KW}@7l|wSHmPssTbzQZdFUppQI3)a&4cwQZg^S^ahhB)h*|IED}a^IPDDht zLmuE#JBpp`Q(PIMNjN>`{IHcxi65$OOz%~U!8TgObVcj%J(WkfOmmR+uFn4JS>#x% zpPnJ{9B1(7C7wC4+DzNn1rksj)pFIJZKgjuE+{L`?y`d2DyRt0nLby|S^9uH6e+UZME5NN zDL@z}@@g62Ptclb3bR8jxoXN1DH~&oHn?f4F7%YGoXHW>&=f#%9yLmc-CyT+0m_{ z_3jo;#8eR5xA-#AO6YE-jVYeoT&!^d4>Pjs8E6>;*K?m|>AZRd(p|yH%JVG7t!Kc+ z4I?hg;w7_%MR64X+}cec_%kK|M_5MDu&PN$@vum%h=@uHjxZ>a+ch21CIkE2F8N=Y zWbtmFqCC2vK?r{CFC2vt_Jl0ORwV%`tw^xC5afykYpfImg&BY#WLu=$sw8RACXnVT zC9DF(weX32fq-Xx^Bycz608S{l?1EcM3Equ2qq^~VAg=Dh-s#PsuXJBRtE%CDp)Ei zFkK25R1$p1l>`S$ksv~<#UboAl&B&x5mw;LU_dGjI5qbS=QQhWn6LImQ+3SAb74(J zo{RV#AWlGi&Z}uX!xa`f!l!lObF_>29L8d0VKP!b1UfhD{15a>o7w+^<8$15M1hW}i$H`SZPqY0$MHl{78yXrPZAZO1B-)1LtyroL@^rh@?we#Ja4NSxNdd0pz!`x89wGYa4!Y-_EaEvj#EEExII9 ztBi)}heD1U@+`!2MW0YA0;`-;-OEpmJQ$=2!apDes4TWR#jnncw-sg4*cDL7`FW9g zqu)t#W8{P8NG8@{s(Lh{;#?-_z!dsw8XV5l{%RVMW|Owj=VTO)0*B}lW`7lwTcl=C z;t$gE2D_PI>uink7XfQFt;gCodE8Yyvq3VL%DJ9hp{%0PH!4`ZOC(MYX3J3eoGavt!HR17?wG#2oJWl0a@@dAVza@){Ex2AYOhkHOwlOJ7cFCr@TS(KqURQ1d z?)D3v)mt93h$iMP4~o8k4k?evO>wiu@<8hALmrP419|9p-H^xQhJid5&htVZkMXk1 z=&#>gmsfq-se6E$ z7x#erhr18<=Cj$dC$lWPJ+(iSr!$N0A|~*&_Uz}-we6@&;8b}dyD5HVNpzuE+&Ar| z=xDpRkJ^(M&QNigsx2?>@NJkOqdrT!dum^oje)k$BCjkZjNU2MSDtOFf&z4F}%r8LhLg~CV3NcYsf3lY?4mkA%O>9k}4dSCNQhJTy z2?tG^JVGq@c}ky@mu1)Jj{R$%;J>V3xUlo=%T$`8-kYF%k|||X4m8|;#@-* z<2AOyXJfH)x_ZP0Yj3)Gq){}byCQbP@3PG|*IuuF;m0_-r}n?ml?&uEwcq6xb`aw> zSO^vFGq(^bqPj0z!$ViIS(W-)4Hq@>)ycfxy)IlYzTFu!S1$d3jM*w?1r*;Y@3ty? zov!lLtPB%#%f4o_$Pr(VMgDhv7P(zFi@fc5#kJ4RFRp$5 zSHAuc?Ot94DSkx}ZgqcoKhSD^Lv(NnWhI*_xl74ZN?ua3kX4-Hap>6*r)?k}9#i&Q zaE_a@$nkb(kuTnuMeg|{S;1q~zsLhcI*w4U#6bb9uV{H~gt6=N_5@K~AS#N%lwFtp zpY9%DP`$=CRE&CF2U%r9gA|d`(HyF0e8XO#dXcY;<`Bmh2f{Y0`yh1DwFv5{2&%5T z_7_O4F1@xFbrxm;QMQ<>CiIFiV)WZhnQq6g!X7cE$00|GpBwM)r1Ua`5pt>8U&g6t zuR2gmF=1su?=(*Mu)WIdV$KVSB#-!`=rI>ns=SD?jk2CyCxPrbpf##c4(S=Wxz(f> zT_=TcdROiBz0ur+xM|7?LKXz%#IPUEdvN3+mh@?DqMCB^4#E;eZy=&h%ewvPVN?nc zW6b>d0^bEc9+)GhdE7c6$6Pk*m*z-OLa;*v;r#z&m3>JTB{r_}MT$i|Kv7NmnP1|T4AKy~7=F|ADRX%5xt5bG|#%1HQd%R}8CnM!^DW&LY=*lqqi|jh{X@doSm; zyZ#}EFy`j#3x}x10?zHr_V7yDEABmdsJDj-IN8pL@@((n?hTyeZQPC?ti$gh&+u(5 z2F^h&knr+*kFq2PzPUgTk)SwpC#xHsB$Ok_xhvZlhd$y%$EIsT-}#H#E+6{Nb%##5 z>d+T_=pziB@(g`ML%*Ri^j#YIP7R$uVd#o$P!8QcWauMEcl5S+;h$10)fCQ&My;OIMoqNYcQAV?aSA9MBMWlye*|pN5rrm*wr>Ci z`-G4P%Gr-)H#2w~i!C^XVd-q|h66xF*$%eeF1_!1EqIK9_Xgq#FeFZN^D3Jns%30C z22Eh$#)>V8=>zA6I3`}F%1|rQ*<+tE+tdBAY!37vCYIz*Fr~v17*PbrxyCeDuLi;w z8qH5*E@F#dT-W0=@;Q)Y4|sD!Rt{C38|o2hF|>z>Rp=6?Ll49;*LVwo7ii_@dV3Dg z44;K|=6K_S*v|vmT(;9jp8#NhK~P8=J)B1#EJb5+_-uC+ja9~f3#Z}<(NR`>w6}|? z&29hyBLHBI^|7-%VgML+0KAR`WNpNrX$c4bpd*kN!%ykQvX>GRGJA>rc`f@u?9$fd zR(C;C3istK>lYiE9ri&~E^pF4KCF#(MdpA4vhVmigJvikY+FXbCVHdkXDzRhiRc$- zXu@T$!SPh%7ff?QNC`Kg3wVVQAPARS>aVGJTeV7Flt9JV;QKZ}!?BvwDIT{CI4r!{ zU*^~CqzYF?sWVvKA=!2&_>>=i*PC13W1xHWLq}%$Ba;k$N@|I$%6z^dc#1t0Zt+s5 zs5%_$7ozI^HZj6@7TTeyjqdpi|M8RG{nVEpJN^Q22jyFDt}STojksN3 z)BT{{HILp0Ifbb|wfq(QW!m`*BTN6}m+5C-*R06zLheV+{5@ac@OA#e;ADiS_wxG) zd_(}Qi!1!bIL+&)dhMbDv4_S)WA}N{hLw+vm%5MIgSyb6(7B=X<3ccX%+VwwFnbc~ zBd{<_Xa;<>d66}4uGtMyY%d$8OL`cJmQ{1Wgbd2I>ImtZRO?{d?*>G-(tUusKCY2m zoIrQ1aXVxsc6vLzTIh$5y-7-(AmbU?ZdZ-ylR0t3w2-kiOZ3_%jN3*@+a{VWw}~Wt ztTxXR&kDEl%j|kcoN|e!a@UZHGzRoAUtu%DyKblgs&b~wG-hKdnw&-ipkt6NKcfj8 z$q%M!(=QXQMc6+2b1-P%*l|U3}ZHL*2lqttsWBYO+t7>n(6?a;V8{K zVl`c1`{QEmjpMcSt#Z5Qc1GDW_!a2@P*;}6mV?*o{9cV9B#Ff^xko%uu}UDm2WE=U zPl|vxoFxZlHjJj9aw+-gB9CtTK_M*f9g(N0hd zzw8-EpH2Uar+A_#$&xuF4Q4?q-ZE~9_HSpCpJ(AEv&qjPaPsp;M9w5%92VtSNn-Fl;7o9B zOHYsLLkH68zge=YwuC`j>pGFdz~2uy^p~LM`N>dS@vxl?jqvF|SYr0muzyG=ezsdz zUtW(6gfS0ODt*$1`6K#;LoV?f`UnA;Nsq;`EDrbV%M;+Gx?Eg?No~i6MMUa_`;ea; zDO}T&e1#QFPYGQAOSat_2QA4b_Ie+yc?+C#lAMLMDI>zkzCUV2ms;9Z5O6SvD&RYvPFLemqEKb|;8hO> zEifs3P@NMwrmc&2+7qP%0)?=>{~VW95nyuJkOzXLc}sHm2_$ zOy3>T_YJ1+Q~J5#GSNpt;)UV3xny+Z1TNGX5Yv=A#`9T-TYlck*Z~p2`-xPzU*I~@ zjgDdXJX%BQd8Gpymvv0(l@2T22BP%J038lg=nyCXqVxj0Dl0?j23VD^09@&YrAh}I z17L;k!a&1DWMjGK2^k-QOvUM)by3nla#ojvslXaUG!$gyLP7FrFa3vi8X}fpiXvKAydCu6k{6>sL_Rq{B>9kYVi?~@P~U7M~U|nF|fDcs96`rkQIEG zw!HapESorlg%G)gj`78YLz(xl(l;wsC-!kZDbO6fZH5DnX9V`VpE!sYhs8AnLx)3` zwwd!`;Drx~VjV}&hxu4L0R$zf{?i03D!|jk40aOzS8w=l(|`20W!Dqdp%ZHQL|Y3> zlPUi4VS7`L2>t$!Fxma@J>7XzKJ?}gX{Z}NJzjiTR^)Z0?_Be#^f}uRCsyv*Pzg~g zN#CW?!Vh|HFcBm9tgmKaEb~bp#TfI4{ZZ`VL4Ta$5mZrujjBVK#7nPkoG%}fd-%p~ zy#b);LQ{E`!*3~4j~!%6nmDl+F&en{kIVk}T)!Jj25Lkl^=c=tuv$5h;{{-q4rSp? zn*n22?U&%X)V;G?XV(SM zB=6hN7Cfu!Hc2^?AlrgBv8#RQlln1l(+C{HUO{%E{7N`Ij=M04gMm5yt|xL)`QHH(`A+r@=}ktG9xysn%2lKkIE zzfd3Qnuw3`W+Sz?U**llrZ<6+u|WlRp1K**KzYn%(8hT42*gbm+`c>?_arbz+0Ib& z`6(LrF020pq(gf z6l4qRHrwFBKbRofGxf-pI_Ya~*+zJ7Qi9ye6PwQbti9nGHi@)R{>y?Bq|qykCX>b? zaYD3M=NrH@WTj>{l1;pBygAQ?PBwA4w<+61sNR|GCYlxg4l2~XidLHzAcf#LQ{)TT;>;9XG}QGAijdIZ&6Hc3VhsZg zvYVI-7Ckjkg3V>df>`;9DQzJ(u+>g98Uz9Xx}=_;MEqTtO!muFtcd@fOWl;WlK_Bi(KFrd!m9})%-sDTRj?v`x``B+kq5{YD%!&lW z9BKF*+yF-&;=i|MNC&{IY`;FQRSCQyD4%U~k>mO)D`fOGE%EdZrCbt|Lmvu=ffeWx zjwav(YP?7{ISy^P-Ap%|RoMa)iaTK6&%>P+6-MSmL1sX8p*AO2Y^oVf0Nkj(h=eKMD9fSV zhHSzW7}=yJFemDdD=_-DRAATxnL*tt6`0F^$yV(>naX!J7)cQl2n{tz10VA}W<}`v zSuSpny0Ss)ikdtZlr3p3qv{ZULWd610W_}LGigW&?c63dru|>tCN{3y#9Z~FdhFmc z>7wK+S_*ADHL?Wjc{)_O=6nT;RL z8a$B40YcV4@iSHC0Hh?Z-$lB1ml`!mOQvcHd(iH=kc|KNdpng4*&iR^ux@Ot5p|^q z-kwOirx5>pclk==MV=Zgrae5MxzAegkxB!_0E=!qe?c|cKH~i6AOG0bzV#;;zk}&> zu5pY0>}GF{`o|C4>1r$EVhr<-edL|L_15C$9#U`M7F`f+_pvaK-nGflnl0%eh znW%>Znhq)`T^&au)$?K0U*?*jIKnYS0-=N0G-lkBWhb=nsSt*@I1GC8nN;72qqdzI zCNoeJV{qVA`l(>oG9D{L8_GKAKS(X1`^cs=C2Mkk%dJ9CG128#z?X?sAi8)Af4=2!AFyZ^Qsd`Qm=uu z>6eTa((}3xf-_?hCGy8GiH%`==kXMT%Vobr{a4N=x4tXKX-knqBn)v4<+!*|1-y= zWWtV(G^~1_zIly;WqMc`rs8isHUz1NqC(zOv{tihuVG)1qF&=NhGUs+Wl$HII49F! zG4^{mUA3T(c{~M_{BpfF=W`3Bo{njoDId0VFMTcGW^GeSVP+IV|xRQVNdNtgzTA1xWf@miJJksW*z#V z7}+c~_&qg2Qe6js!5)D>reJr562v!f*Y=>iG>RW$e9S{QU^h6v;ggr-A8JHTG2_9c zgt;zMQ{$ydtVkN?io{ZHkmWgiUNMZD#^zlQ{uSCsTfOlkgwVyoFgBisEQBV!Gi(p} z=LDcI#|F@+kv;ybrYOV5&uEq~x zcFaIg%eB`fAxB}tYjO|=`X3ku`r@eProv`hx$XJkcD;2^*z`<`tu_&2mL9ukMaUxh zH@}j|>CyJHYARqpHqxFLksMMeW5YKy_mCvlMt;;fR!z_9S(3ih&SBQ&ewn1d9$vJ) zm!zM3H!DwuMm*bi{U`Zf2&ZUIu*JZ(RO8?^dOVu}dB3ky*f{}v?4{pt-a2EO2i`$$ z#DX#q{(vqLt&Vtx5Si#1$vpV@(1qzNvNfv*Le>Iw%rSy}04^JN444L9@fs?^!grUL z6*VfK&V>L-`iixn@AV^rJ=4v;f{ca#kmBVQWOa%adxIBzr$&1eDm%)pcr-%D8G4vA8iVc+ltXZ>+kv zMQy=c6i`R50S-FhC@{$ycjVq3VN4jJT>{7;1T^L=tE(Sm(+}aeF)EZRuxl3jf?{I8 zrBAWa`W=oL4IS2F2+ZqIxe#S7l~g6F8K}Wm-QwKC!O5Wh|U2g$BKnA4-yK|%75;6*7Q}Os(`3mGz*)KGMUf&;q4-xUaSoGGC$l>=e^Mhff{ZA^%@Z9$l4P_p#V6H zEP-}Z4V>21^wU~^+PE;+Il6%b6O-2)ZAX&rO7(Gs%uNMD%|FR9Q~7PtlgS8kHli^w znMr<BC zBS#RFI?4H*;1cjhqX)6k+E~uoqqVkFJj#H3CKzr>rRt+&@tg;$pm)>S6WpTwMy=k7 z3gqZ<@)SbU8A$exwQuux7e{IG^e#--q8@bfiBU~waZMXM!AI>4xjbzBQ@Ytsy#o;_ zR(`XZR{G{*(gdtCG<`zc;yhWa?F0he>izjkqycgNpcJz5MdQ!4+6IEVq9u6Nu7izo> zMQZ+g(8Ud0RW0`g$iCU)AKBrxEW@8I+4f!xEAx$$+xr zPK)*zadlU+)m&2aU0QMB)O7cH-sezd{{Qe7b zm^tGU7Z>o?i$oWrtmI0OSmIFr39s!$sO>XW=EPuaUnmkQwc%+4d{wei+eH)H1l_RK z3mjICQA^J$v0hl*2eB@ivIpTo!(;~lAqfQ$g~=WuCk0Jj`yl_GFVme)P*aed^!Cy^ z7?*#X$Ed$Rm-OZt3p@sCwa+8l{wlu6qli$Dcu(+JP$w>5DFftSUuR{2WAhJx5&na{ z?i4Xff{4Oi0aS1vP4GTAAUrZzkckd*%wLA*a+0Soo|tOFlrZ#EE26c&$FkGz)dMfK z?-^0#$CfL$$pej07xbEusK~*d%$!!kgVh>;pt@8O3*Kcg8=$<%O-I*7ERK3W+Ld!e z_#z2Y_XuMJV?q*Ly|0ZX>V22R#Ae2GA(|LD?#Qo^AmpR%(C$%_5yBU7wA}K7ktVFB zA<-ps;A8wl&S-p{N&A7l#YIPT$P&OMcwk&+ROgHS7Nc6OB!yA2s-9s~Amab1Q8_{c zJB`7u*U9^dL)9c2GafB84yL~&83H*{SfoYAgmlu6in{WyqP`R}O-ETg5UBf1AfthW z7;roTJ2a(4ZFE+_M?44+w#Jlhd`{^VJx}Ro=u&z`)myfcBdXA$X_Y9^Dq+PIH7n6- zVBHppgp=f3)^1GE0$*UgFF=3E>4%(U`iz3d1?wbQ)u-r3Aqu*5Yv0;!EHx>|Mm1{Y z!-TJ%?QYcEHOmJRnyiI!*}#i5hk*g9NZY5r`hbhHC23lgSOBXg+hs^BAXT%-oL;g} zifh4@j$OB6D2SAjC$(`=%lku>P4iOLG-?&3OSa(G-93+52OWVzd*K0bwLenUE!;Xe z7KQaQ^@bcr>rtIu8t~zzv#W)f>|p-XUq8~X&; z#O1`jape@>Zc|Rtui>ATkBW-ADLqq}LC*|X$(`^9uEuVu3&EFKQVe5mNp7pC$FdW3 z&0K`4!rW!>V$&Bf3`Z_41CO>rfU+Df7Z7(Yjt zZ{6Wh3P}g(PU=-NN>a6+9$vbr4-~myhljRjQXfepa&Zv=%5jwG#n z+EFb$-MFI{rY>*W?k6^cL7cN-VZxLz+qDmAj2|S|UFUoaeni;ZQYn*K4KvVL8PEOW zARhzbcCtUe$DoBA%$RWUM~6Ach=A;^df|lCUHSCCkwIYL@4npUOl4wb2Q?A`Gc}}{ zt?6Z-w88B_3!O%4*){7kl(CVkbeXO$pM;2cpXX|Qp3l>N74tEK?PmYbNDYkJ-;5fe zZW3!?p@F@b-#%NU{vCe-&Y9@Q0Z2wr1V-aNbzd>VbxEMMr%&pIy&rp7s>hWCNX$3B zR_A;j^_^GPKAD{xx@6UNTY&q`B)-`PmI zi5H9wx--5(yQ^y&DYZn~v-52+r#KnfsQ{pUE3Of2Jy9wHPw}(H5j+ zF4|-!eVQ)2JfZlPS)fo*;UGe4y!CZpiFS{5@Nkt7gUKztN5M{s;i~|3Q}mhAgBZOHuwytrbdoSypvUsZRoD7edp-M zn@wlv%}8PwlRJ7HFNJ|X)LuLWC5>@C#76J?9^6!H2zMl<1S;3jW-^CpUJuH$ymay> zJ!|Y-Idl!QfCf=w9}KEvySTq2udIA3kZ7xoc0i5aH`+ZpkO9Qm7>&EXK8tLi&DCz% z+jt!r+TyVOoUomCdscI^^Tl=NS!XuMkgP{u82%DxYEe(D9 zItw^He@~Zf;jSN~)~Iml)(?b6N@o{KASZhWJvsm$j><;b#x_vp^iU^1X*R~LS@ZcO zyirXRysGr|+U~ZU;S#nLz~VcenN(}{Pne_|WL{u{vd*%UL~Bl9_`QWqpqgC7Si;&( z0-g4htgTO8QaieruC z@{9!)bB*B~wc97@-`{6)p-mp5+!DeX9U_wes7mQlqTw4-+jU-~Zr9(PcWFgh1d89oX(zgD1?g zO}2Q8re3I5G8daZ=swfeW2LnWeW(^v=bu@5T<#lTR6Naz zWe^`3#GRw>-q2`6l^RhsU96XMiB4xmNoH4vpm$<0c#$yM+sqPkfSC|$fu05qn9lkk zOY8_%GDMgMnPxdyT#GT~+cQ$o2LB;BU^>1Yp3}yoXr4>9wVP&}y?DgseaO*Z7-DOG z@Y-H=N(BpTfK376PLOM$Z|DPH+kTO{xf-3ljW5h-psi=jY7QBDoy$Z;;hAD=>)IL8pi*Z5nu+n#KrO z)S-DfsUxY_cDsWp^}6iL3DUU^q_ZIjxT4wnm9i^?D7|)J_EuxXKs zS9e6OLa}yX1m^?l4+F~F(7{DMxovAZo~~EtekgIQy3Wc)5*yA4xHO!tsT?iBpmnV* ztr>B21}X=f6=26&v8OP@z|O5PAgRG!dcZBHTS&*;d0}JeJajZ0P60eCK=qSotEE8y zy5C$A(RcnH$yiDLr05O^!sBx7;CwK=5{QaNrK%jYXx(%Bh$*TiM^YC(Nf%_P_r4yj%K;wKaJ{mBK^d^70+*xQ z{N$ya9{(+Y8f=5NUuQBY?G8!$$aJLzLBf=rut(rER`v+`xQ>)Hst)=wtmRu1NGLB_ zEbU7>0YXmb%`ksL5e0tb9Szh!5%TixRKcnskQXbdp8mBh3Wf-*W|N;qzys?wXlx+} zpN{v^w6t7l+PMJv#u^IKt+s1)-1KL?h*XzQq%h=)2sduC!~JuO{av6fm4%t@Ya%*% z$2dM3%;&p=78n13*c?hGLa<1n0f8mI;YiVb-;Q={m(%pQCWZi23{-)fE?HASJs zOX-Nck-WoiLXgzTTZouZu`bdX+ix?&GI3IBBp{Tw^;G@b-im-5$cXiWK}mResGdev zyi{Su;t}a_T_v6DkN>p$KHY2NcjNO_f0InGw?Z0{SHDRzEFpnSZfC^#H-2xaU(2@# zwa|I@kzf4+X{{nHU;gQ)|pxeRl&>j?2{I@Vj}bmD?sQ-t1v=bu4Us%8c3z(F<%=)CdZHm>g_(5 z{`FBH39tavOtE+*Ez-%ONM`)^mOK5&!Y&9SqWDISUM009|Bb}${m6zmTxzbH2lEI1 z`yY$O1ZMU8q6AlSg%Y2SC17AwGEo$L8D!)ht|pU{4#_x7*bE$K?FmRjl`+V@yV+OeE&z*hW*JkU{v#Cb_xM9P)&OYsMP zQ1w!>CuK7x<*KLHokYn9FoOmRQ3i)mK#2u7Ai!ZX6X($hN+NEVu&P7nvWCB9{c4Mvd5b}BC;26st_k15z{+&MB~vm%-RQ=+{yp_=??J|M-tPjLf^q z6cqxn@FK)&mx#q-OcD3~O~k$NqNNx>NWfTAu~IUiFK1b+@=~1bTc`?Jr!gTZWP#cM zboYZU0O=2NLkJ|yhm8t=R&HX7NWGJ3jQW88HBuY^I-aIo+%K+W`R+;PEoOCWRbq77gwaU)r55=!e)-y(I?7HA)!Sun5sVUC=jEn^8b}(rftuL^Cc{nXhyJ zXgc6=$h1u0v+e}NYspEU!1ywo8e6zBXRA^MQ?Xd#3Rz>Yv zMbAz)A={-9VsG>u=WW#{ctz1GAnI9)3s;J3&3pt4KZZA<%E;s>8* z;0HJ60)b~)+`FSKPOSrB$dX>9q!LoDk$vw}DeIOA`?P?dFS14rEBW)sti|dOKv6*)9XL>3|?22Z)_=**jnrFNCFIG^ho~Seb zqH$UvW=>;}yA7AjQRZH@eMZ1H6HrhYy4ejB|_?9~k!pJDxVM z(P{4&R{qDI#0jr8;&+-nE zOY9(B89sP0@9bmSG3fTj5BECC{b!ga;E5!BblzJpqs7#8Y{AZZ^0KPc;*iV*p96_L z#G%D_89e|1@ZYvE`#qJK3)_%EI02$8@Wae4BUywnck%3|Q$ZCWW#Tv!6(j{CgUBcGVB@+`b^<%g@ zA))PPX5e(VCM*{bf>yks@)|%@ZU9wz4WcSHh^o8>Qk5G>RbFae>@jA42(k`>A7%3~ z?VRVibwpo8WidB>z@J%X^bBOz$tpQGEx_tK>yVzInr_sy$Sn1&Mqunz=hzq2${4fhy|SVO zBOfAV&TUl|bu0-%#1-!VIt|vV6r3XLWqQPNn^r#?9$gN7zO35LMagXe&88OUMKFn3 zEtSlQRB&ujjGXEsQY|*3x0pm*l`C0Ttd5FcR>E8SHDSU>j=)U}P(7xFSgE8ExMdCz z(vQ}JQ7m*xWU;Re!A4@p3=_LsLk6iGO^;eQJ?7+y$X15j2-|9ND>cayzmZ3Z7Soa-T%GbUb2(tKT3pi*;myFNV`^|xr zvWv>Qs5eVqqK&xDX>9uLA?}F_%_PgzWTp4X;4kypeOQe-xFXP+oP638q?EdZeEv4+ z@9=}sAqdn|EBQL>o3RzkjM*&yswz=qe@0{XNT@k_gzkrAu5zc&!d#lgvsdb4;Yw z7ExR>P{K9+tLXY-$*&`DFJyP)UA>ub(Kh7*%eAYFxy&-!8JxYK>FcanVp+P%xioFjnJSK=E+ny6nhRZ@SPUbs6v zKtT>Ht>plOtzxo~JDU1ozd|h90&)j9$4CU;mwWmMLlAoMw+1YouE1anEP}B#(~G<* zL2V35y>?FX7w-|Sbr=wD*MM6~B0dNRy?M-l(qm4TG8T6r*^t%1alP2_$;7@afpbo5|iI?h%xea#)|gX#}c zbMW;?sQK4X>PJjW?EFeIg(O)8fwPJIbv=m9A}k^|AScd^tvj(qL92a6uuP}U@Yq|6 zT-&>H@PAM7YsQUu`9d>=t&I}4CZA(Og~Vm>_u@;6rRg+Tfrf~~OoH4#_1VvU`|McZaU~f@I`Z}o-J3^JrFkPU>E9HqVV+l-~Y9ryfpkKs$_}KYE){& zeE7ftQUVT#jc>}c8M2}1nv2P|GvZBQk`yvk1JaoGBFy$S-!zkevl>a-fMJs(Nd&_t zhq1RTce{Zc?Q4_%)$4bFudZ`5bx!rwIYlKG9m<z9b(Q^SSS<+^hSea6seq>au~vIn%hs-?+^5cs z4kN4rI(fh-eA69BB>K&PPIye|?;TaAF_NyQ(|uSwTtRZ9%n&%s0s6V|fVxYY)>wxI z+G?P* zUo&x^ERAolfrpgbvtXBGZ3KU0vF5AwiE9`^C7M1heL^aqgwoyz5A4nEFlrKrT+AlH zxt2=vt2V~ga{*$A!V$&k3#O&ZHKuMXKqUzOzyarbFN`cBtS+!*R7xq~)bk7t><3|! z><7~}HTEiOjlLXh=5S^^)r~N!_IEVsp@&crj-^itn}=A{-*;ld?|tx%GWi&fOCC`h z=b`Ph1b3?E7+<@ArHNpFTMXK=rh2g{ZG)q#Fd>#lOg%m$xy{tDc(@wYys0)8`iTRx z6+yR`M#|+ydrn9{zbGG6X>BkZ4MbK*L}#@?ZzI{rS;Fy1?%a$-bl!-lLP1f%M;?(% zo3=2+2d5>$-ypqT2oVf zi}R0`<;z2s91I^$7Bixn@G7>r!|`CIAs&{!Eo@j(g}bw7=+<6FyL@>4%d=zh2~v1O zzvq7btX_Cp{l-AOKzjU`)^xfcIoLE2M&gixOz!W+s~M(iX-&cCM|;zbwof&4oqr_X zg%_M}=G$*3D^1o?Qkrcz>U=JnT>n35>bA4*!KQBeLZjJRSKtZI7QJa9>~yhUy8|l2 zUH%dQ8wi@a#NeHx6EqtY)lY z@D!^6!Z5iD+5H}?;A6Z`{nV34TSX>M%2t(5By!6D<2niKlR%MEuQe+txP;_&`52ee zb}9eB+94h7RL^IDkg514>h7Ug`d??=cIT&EES#OEU>vt`8S;b_mwske)!cvVW zgoK9vO5#H9c>ey>pG0IN6Vfhdh)jp38Ig^HN)r~({!J&c5v`GoL?RO^MJ6Ov;=Es4;+4Of$&=LhBI3iMVy4j?M|DXEmg{El+X z-C=!pLRTxin&c<&yFU2|Sdax4?3c1IFnF{;bU%kgghvMuusk%}(Dn^m59x?Zv(UhY zqOC8h3yl?$_E8v}7)niW*keTP+K=&12Q({0u*N84`DS64aL^RC?hpTK7#gh`afp!} zZ8}2(@oP&UgUcP7IOFrHs9EAK4NDb&vxlWN8_#)I$bz+pC6OnnonBdi)|1I@T1D~4 z?-l(It{cP;`bmBD3VB7#3HlJJ=yvrQlTT9VRZw@nV%&3MrV zSL;sq-wiG*nmXFww67sD)6$x4Z%z*{G2T=9?PiWF9{>=WmTrc;$ckBZqIB58bz^2q zp7l4EDYjX{+vElcVaB#>C?=-sdsoP``{`VvKhJ+?h)wa30uEeQ{5lWv+7 z-v=0CXgI9Jz@(Nmskbb<}83VCTz_@VG1> z7|M3md4agF1>V1s(#o_IJY(Sf9l#K7#~u^PSk2j;9pGYD6v>$sc?Io9iY4{TZT%mXnXd9CT6>&L&Uw zB7Y_;=ambqrDQB@9$|{b4>gYzZ6;hu8Juim>+WnPHz*y!%0l!=33dEG+uSFH!j4&d zj{NK_hTfJpX=?bjGqB;I``8sI3kh@{(KKlqn$cK7No>K`d$Km@!V-~hZNJBV9Knu3qtt^P=JR;ay8OcbQ! zPC_d*BSN#63Pp^t_}gfNPExsC7uZC=G6tehxZs((mV|9uOi*wMup~u`2xy%4eSeVM zFb%e6%5FdtIVJQO^CV9yleNT-OdXD8CJ!K@VRpNdAQq<{;YqK-&Ywto!PR17{K!S^ zU;&h+f9W>v%H1!TRe2g0Y%XszGHex33$o&vEz#lk@J^(|JMA@XfO!jr6&V`*6CE;o z+7QVlI^^aRMru4sJ&Op|D$|*#^lJe}lVT2W2hjy0;q_&?8NO8`(v@b#^{Xv08Pg)D z0X(^aP@fecM?h=?tZUwv3zhi?CbkNBN7{BZbRU=OmHN(m*}7*ky8tKUDIB^F@Ao^! z#Hkq!Y`CvV7{LuwQFfe%ZSWR(N+{5ymc2n)ee{3vQ zTdCScBkDrzMb|yNhQJo~*dXF*FM(2gqAx=xBoVi*kmQ@VMarQ%xJe3Y$GJlE@Ut$d z6jGq1gqH=tM)w?2!NEHI8{Hwrn(E(38EabQToPRTKj=2IT|w|M{Q?Zz?}M3n1P=n3 zqkme<%j}OWHbTDABv`MWU>${hFRb+|`r(aXcpsZZSPZgQ2rhWy1p+$cP0yrb_Kh zAj*(%wAy3F+1Sf8J z0@Vgksw{&;>%Mv~O@MxNVAC7*$s6xg&3m}`eqHSI3uEsFBP0jKx9QLAgk&%?cYHs% zQSQJ;i)C8E_;(=L_<<#UN5=AdnD`F32tQT;H`#j-6>&sTv_e8Akq$cd-mFgRPG{;M&E-F2VS2^ZYj;*TlOsw*>syv;l4K_QfK#9-R@EQd?2+*rJ$`388K zV(6QPh$j2a_Z)l^+z<|RC?`CH?tQoIEvw* z%(H*2yUQx;uFyMnVR&;+vsW5ee95sSR%NPb0t&cUvVy~G*c-$vW}(A7YaIN}(fwQPiav>&kpW10>sq zbybrQb+Xx>#Bc^#*&OZS2B)kHSwJZ3-`DhQtkl4|zAn@41d0WvyNcPjnhiDdT27#w zeIOr3Xgo?&!&=qHnzD}qiy}DUJ>OxZgi-jQTU41Sb`Q;y2}gU`N2n8b21Qb`v7_t+ zK=0C5e*)B0!z4q}0xMVhlt*bHd!2cbw6)m!UVD*6B1Wn=Ce#d_&es)fCE}WJ-C7mJ zpbhwf*GZlSSk3`#3IT?X7W5If3t`;?s_HtbYO4Gdk~DU(VzYY@S#G_%O^de+*&f+h z+PxzepSi-@d=ys|nWnftw3$<)g$)+T6Bmj|p%)h-nT;_$wO;IrmKU&*-j8Z<*YqpqiI%WqAC1}x8P$rs8 z_ISY07ZXw?qe>gRut0|7=TncZ%dbes(7T_n>WJHhSxxN+DUxkSA_Q)_%)^ph$u@i? zCCc;T_Ka-9*HIE}!`tn(C0@Ie!c)AKvLk>h$u`vBZN5s|kP@>E^&|}gvId~h1StKI z8R9Fc`k#MyHar5EPV;YLb+*yr@tUtgsrieaH4k+e|5F?yN{OhaPxOVpVc$~B^mD;C zu+?^H>=SEesqvM3jfeWnyP^AW(;1azyj2{xNz*nG7BI-sZKTWfBkg>&uBo6=VWQiQ)s@jix&luHY(BN@;25MWZ;^=zhpkeY*ps@7+81E+78#%4gt- zWDFiJo+51l+LFbftf!Vy{;g7cyl0HvHa}YDyhj=-z$pEQ{vx#G7Cpg=2dCS$4i+o%?oRc_@a6rdkj_Kh_x-pS47DC> zq5ScCw8d%H{65m^O<8NL-WL5n+)~&Hy=nEP_4`n(w@tq!0NnYw#Cj z?f$qsFW?{a3)QlXB+6$hnZdU3qS>33w3>-B19RMD#vE19wH3M%NMQ7YerI=QCt1T~ zr|I{~vjD6+!pxLyj5eO=^hlgd8lFyXR=+Eq-rRVY4RibRd1g`s)o6ry$`RY}e$8mH}qaWzaym~XgKg{tw zp@?3F@Kqx<(d)~`pt(qTUc?cvE1%_CV*>s*w9cMLInMRqLu%CCx49E$JzQmem%70y zYp7Tpv66(2f~piyqlKtc0~ITQX37#w65fIRq!Q7|Q52&~P4Cqcw!|}ANs!n_12Lb9 zm-Tgw(}k$w61uedK+XJ>)>`WJMzs2pjh3$MTPNddb*@l;Td@QUnKv1J`c_!=h}>`& zhF3Fdk-{LS7P1*W=mUBMK3G>(Zuq2+s&b**1zblWBwe3He>}~#u=+^|4k6YO;YHrg z$K5AwP1?~qXtMQufwyDmDc9%BWo?g=%yKZT5;siz;0Q`t6XBXhpz@L;24#?DL}aZo zNFE&#iLa7Jlrd$f480xdGO{StWKl24B7vxqMY@|#BBwZ?m6s05D4FzgHba8sG@_pO z%OW>hYVTfXCSh~~!f2<2(TiAod9ei2OJFw(RMq3(jad@OmspT55}E;sfu?d{wqR%T9R-p`69p2>8c86%h|4IDUd&|_NH5_s3MBmH zCXj9rm=Q>*FFfph^#p!>CZH=7FBdzpSl zd$3Pqw-RYU?EEtW1HBgxaGiLT-}mz(|a7?)Fid6Y|w_H7l9 zaB0zzEK_i4fuzVlE-gn{E08Adu+)SV^=$~YJs-_-*$4BuM+RjZNvGdwg3COFD?tqWVvAMOF-p4;=4CBi%2)GYS=bg|Hvb7il;i!7*>ITGeWI zz8JZ;Hw&uIz?0`OCJJ)ds;Bqg+iR-0g)9{x#8Ha=P9H{0%qz79H^cD;+hxW=i}f1R zFk?oNZm?ixidKA$8D|jj25!p<_3;L;j*OxixMMy8tj6V-k>9=EKF5~Q7rsG)&&u$b zH8Y|Gm>2iwa|W(C4;ohqgVy+$8UKFyi`rq%#$(urHu0H%3!G2_W>i%(%)NnQ;Lro! zfM-rCGBnZ-i!=o6@>vQ51m1R7Sba_2!OMvKuP7>ky0=8Xb9X#0g&n4YgdNti9la%c ziT=!mB}0Y%y+!&otI1@XxRC?_YG!!qK$FHL_UYq%kgsh#Kx(#JH)H2)fWq13jA@dP zsuoBtWpcqgJ+PMeEmR5vs43DqNlr&7VlO0&F!Orm z;$?J6E0nh8@-3iLIhJoVWQzm)Hg0M?cOwb*aEm7933lX5)0f_L3l7?MB@#gkj3=Au zw1FB&0{+sspeqel><6f74oVEhHEi`X?BuM->dz^8Wl5QwtfNc`w1Y;=)gU za=Fnx6WwjXMhc&-7do{ArzPN|iT3RgLJ8eH^_QejAuN$g-}Hd~oHjk6;}*wYz%dY6 zeB#JR+{l2$;K}2EzmoPq938d;(h)V3|9Dk?xNUnN9HT1X9C2p8i0t#y*QsfD_Auh# z=KI9>%d=C`1t>hJ-(^+lrhzs;Fgr7G^8-}&s(cp3Tuhvq^vw^mwapKal;r+a3oXCnZQYrUfy$?-T~F@sOiA{Qi$qJFOzW5wPqik=2khia`6MBO4%rx zw)rWIKYBNVhU9FmJ$Gs}}nPo;yn#YY7z_gY`^I2aoZUU zs4t4r)C$ZP;S!fTZ?*GcTkqNjSqpl%A5s;b`$R-MtPB~YtwNVUKmMDC;ORCg z4EfSn4!ST}&TSogR&05~(i_y&6Y&3e!4{=D=MWQ@`s~W9Ojt0h#0+GLVTM_+lnXQ3 zHOx@Zi%nsP2Q!9jR9@oB43ea6emcjAnY;W@POojIZUTc7GYKb{e7G$R7PnnzHSEMl zL6liZbMdtDIs87cU_&Ho26qgRWV?%R7vGEZ>oU=FvH;hdDMMzhdzzNg#cjy+o!5>_ zFTiZ|qZBBAbLHlISweb@Lz2}Sq5-C;5ul<|D0g{TAkEXT#~o%#gN`mMDsU%OU%44q zDzBLerq`-LmG_$pmoOEN;L`)Q@xn#j7@sc+!7&xXu}%oX(Cqmu_gvlKB-5FVbRbo6 zluL6(o3c-V2jrD~dy?nL>M0A)mxVPC+=a5RHiV01VXgnTxt~B|k>mTMe#!OvxPEbZ zpU^KZ@5l6u!~2+i@nFjg*8=4c{jxy$uzp#{Jgi?9G9S_}u(%VaWW1C$eU|Iu5`DPA z4e@0(bu)VUz;TcXTyStKbNLd#yv(~V_RC9LzQ`}1;c};6UgQ$hPEdTB%iJ$HVm1W7 ze2UASU!LdkM!)7Ec%j9m9h3qs-AbL80cPS&qU4DV$0_jC?J~Wl z-uEX)u|@`tb5Fg`am_~IM}Ee-R*tT&U4pKR>PAn6Y?fc)x9-ddJBAUUjBTPh*s>M?m9_ zkoD$UOk$WfcK4LplFHU9p5mnJ<3DD-z!DnC&C7atr2BI!Q^p-df2rArwATh)aaDq{ zb}@op>q_qGzoET;q(NfOtmWq|y0BMkPdbK5&`Z%$-OHUEA^KQ{J7m&veg$f5hGX(m>K)XX+&e{7jI5Aob=<3r}mzPW)hvOXJUXD?<`dxE9o zm#NOU`ZmGFbUu2D(~|VNJlMPU|cPVndoWZ@N*_?Aqqr&<9PQmFUXnw2VC~ zi#E(*ElseNI4fHl^$|<>E*Z+9EmJpOs=a|askQs*Xtk)%&;zD(a>mBDgg>fN>l7h&O4tTpx73$!yQHHj458Y>j4MN+T#@ zU)JgVTE-~_*Ez=TUs1};c0a8I^McgP4e=8Z446@={o=du%*C)nKeLHn8gs?N(V(0k zwmg~}elxdtm*&!IVTWB^5PM{Xd^IA?1!dOW*07kwq^4Ecunv8bFeNijdSnt7N4^Y3 zz1IDbMkQ3JnAN8=n1mc=n;4*ASc_{9bg>$!B!UgJ8l#FB9Encjc&5VO$ZR2ukzF1$ z$W{E-M#cl^q#f26;cPj=srm@b2TKf5nC3qp=O1XC+Y|SZ50Prm4?C`ZNk>KT;*&7o zcK3G@_dHLl_QjLKE_&RhCKf1f;Q3*3p6jNxH82oA&mSg?mdv5KXsHg1f6z4!OBwe* z;yZ<#m3A zi5(B&(-=3Y01q`K9j^?5;La(-9!4CJ;9LH!K3X8)Nk*P7-5yd!upPBTNNyMuDt>ZROeHJE?>vKstZQ&gI)=5V@y z8u$(YMFe6>!P>AbcVeP@-nbZ?&~@*c`5IZimzTEgmarCIT!Y!y*}RXU`^!nDCA3Yw4BO@Y-&SEt zUA>x@gKj=7rInG&{nkjyMK#5YPR!RdOOt|Y*;GIDQ@?>e-mRA6%-5B(D4VR3$s{5R zyrVghCD(3}XjYx4d?m47tSa+I`$2VE!puy*WC0OoOYOxHAgP>Ot3`{|G4*{3pA-yb z30;&ou{Okp;W%2F=;2Dj&5@fy1NXW0QTKp7IjkitX?xn70m=D_4-RBs;$iIwt`p{g zAR)2vov^6gmvaGcEPPir69&?>{p=1$8f1OPy!5TG1dEV`&@sQ~hIjGd5>D42uYgr#1-(Rt=r5)5?e3 z4~CMrUIqPL5Fbi~mw#+@UNNM8X?I1Uc%gcQpF3(6PLSs;7@>@1GfwuDWdYbQzyVAC zmxxl_ujGBH@QRdLalZfLEZ+Gs+;2%LgDusHOQ6FYl&+Q>G`V4)d6!HEvS9A~)=qPE z4KpEV^gdlCGwqex%?kqAa&*Agd}hD_#Srcd*^0x@M2@Ujf;L015CR5Y4i;Wtv8*#g z@;d~gf}`Q^)Q~TnQ{{!B+;-jJpdR+O-fC8Z;nP}k`sa3zVA|m98sj&(f+Keas+i3N ze?j@~uMJG?WSZJXI*eN)w47EvxJOjD*``*&(h8IuyQa27wW#tg#db)Fkq%b@2eUK1 zDZsZwa&Quhbr;9-0%S8jVTnl@=KLtFp-DfPmQ3_ZmS5)3q*(^47Sma01;+5(GPMLN zdnA?6S^-w9B;{^>wnQnZI&|W*FkZ>X~9i?TmYT7T4!9ZzQHtu5g%V|j+XB@sn zx#DC)ErmsmLEb=%8Bk|1DuKnkemctj*y!DW@ygF`p^Ad*wWt(!Yfp?q7x3QO6~;Hd zSCuid0FcJ1UB=fk9I(Mf)mr_msr<{rR3;Jmj|m$EylzbNIwv-h=M~m(Mp{Mz|gwXrh0R` z^oGT?Fl%T#O#(`BQ1#}eC0gic*)tKzjrgYoP77X0xMqt!EslAXFxWQf3ggO%S_vp$`U`!x0C@uX6ct~2V1uELS0atxQ)%d32-Be znU1R(IqzccW6iuZ-=W!Cq!sS&$t|Ozg2piI7h?b$cEIARSua>rXxKJY#lIzxZkn*E zNd-e#TCD&}WRs6YE=A|l-pDG?&rrp+sIIN<9RDb6U0P3&;w`{O<6 zt^470Pb{16htfS(>+WX#t#0|nDqlXNPbk*Nij1t>DK}g&$}`2|tzw@FNC2_TdNe((r>e>iDsv4?j#CCH$BQTeOma z_xJ9AY-BD#4o4F3qC%2w;?=-8{~rNEb`b9oz0R8AZP z2N->H8XKy0jUgr7buCu=nGeV}vH1nk%&(xkwr6^`f+X89TIH9B?6y_7ewwtN%VTbU zp=NkWs(w#WRO^$PZ$8Dbs0D9$m#u{x7l$6vpF{-0J?>DKCgIWCTGSUYODJ%971FVY zNDB{zf$TIrm@m!_3BTiB7l01ObkO%LzoHXraj~}i8ntY9jwSCb3{i`({HWFf@5+6} zOYfC%G2K+Fhb`-B11+;!K_qSwX67r1s6_XvZ~3D7HLGCGA#_+X^Ca zl&-D;fhG7HOhHKmfLRKi!*%ro&y9F6gsh~CC~S==^m<# zxwtS4&v}qdHjE8GPC^*cLJgp(fHoD}>=cj^JX2iW+VDj4el~cfZ7f%WC$#7gm1=Jg z-2rdfA>}cyP|h=Oytvh>Y`!R{+V*1Ne_y5W2i{&T7{kmF3t-(}kk_suV zktJxM2@wN(JO&b}^rHiAAeFIvI#Yb)tEXsw-X#tK!c%sD4w%2FORO^~vRznRE<}0! zxs^fy1|_@Eghn8EAbO)wR)~S7WxFFF{Gzy^0Ln*3GPbB|H;JCoLsUxxJr5m#?8QAQ z)~ECW6gB@vL#DidrwRbCPQ|NajJ(y7(>uZ8~S75@qL ze@=M+EFk^VHGve^pXv-Cy`T@{?^HMp?fYNs{e}F*nh@}WXiR-Orqhu2S zyMcdQ{%z#nCX}@+;~gG4t2rUNBmkfq48#+cQBxO(T>&N(52ASV&P(Y78;7-D5EBEMU;vnOaeo^=W{s$KgGq4{xl#I>yR+l+9Z`F$UEyqQ zNZ{L62Kk{)T}+z|>DTU*%d)l|#)12{resv>N&@aX?3k%Ri*{|I)oS~7X@?<(x*F(X zxU0PJb`KqYurATH8^$aT4`r7BUNNh@?0Tblfh@cT!qOUrIg~66r)zn1l4`(m56N^O zT3ggGzq&1NJx$1PPiU9sGAbQ0a!E=w4=r-Z6l()oj9fYcsGutRSQToeK%?$ikJP-Pn)KEP^s=Jl!KB526NVN;7uG4A@CFD{)v^*%3)bv~J zx*T{1`mWvqD395_ElClRXE({mG;udLqRMm-K)9yXU6j$^*+a(Mv> zT+`FSS$yHgWIPF?E>erkt(rZ<7H$aLq)@KU{lC|Z%?es5$7EHEE z0+-J%M?iU)fh{Y_{4Jkbc7fUI-URR#TApdZ zz75SHPBK_H!MK^^oyCK%<9cT_^2sYl8Yg*dp>y-bmON674jnI75E)UetlIQm#1AV? zA#CYwbzb9tfzno63)_mK(qz)-v~Hv266;bPHfx3%B@gJsRLJ*J9ryXX`Z~wDF>5Iy zOtFklFShazk1w?@g;}NKx42GA0HALcU(;*g4y9Y{;Xq-=>SkTY-qEWM{wwkrIYrO0 zu^lY(io<5Fl3+}}=Yj=FGf#938{%UoFO&Vbqf1K9BTOp?wt*@x- z>Kwqwr~4|lg3K5Hz$CEdG8tZ^0cw4YRixfxi)B0-WZ;XuL~P>@?u4d06pY34pURf> z1_g1e5&X-y+mW1ts(1&~STxrzQNr>VYGVj&XRbK?TWs3u{+=n*awl(zC1yPUFFJ0C z7Pp3mdY)@96IIQ#z}2M4J*U(eJ4Ju!luR9M(Vp#XMIGg)S&Y5Dc25Z{$uW`u(ja#M zqn={4^6Y{ZTRB9?-eW}#K>Y9uf^a&Elm*{3yKaI zF)aSE>OBYxG@ms1CTMO2;$9LVZuo+&BaxuB1rk^|#H{S_NIt91xqxYRza}GIFSF1) zYiy5|JoYEcOG}I(QX9okqTcs8`kP{0$f?8FW41CJw-z}`irNJ!{0)G@Dp5WS4-0MG zryb98(6S&5(dZ#y|Ku5E>)5qS4C`8-ThK!=cKWHf;)G%%C1SqvYo z^DH8Ip%Acc2?#k}&<||R*afOByYPRi3q7S(pi6Z8|0wSnFI}>ybjt>6@~1d^Bd?2-dYJKazP2U|ay6U^G|S4+#>uB;)-|CdZ!jxnSeWu-e&B6k5^Drs zhHuVo2j)-iEv9A`tVQGHE5d{CEAH7}Z4nbPI?^&EKrjV3FBm1AiJWQ&C71e2HZuu_ z&eXXXGagG4{pqVC_D-rtH6OQ<(_S+GG-@=N*fic(>h?QD7elU1(lM$x;>mRZS6>9! zTde1H%St}(d?f5^dktW(F$rZN;Yl3vzND>lRlt{nDY_L2D&R^HX z5FL&JJzmJDm#sHc0M1CAgEYjt(7q&6Oa;-KnmBt=s5LJ}H$%rx8vOoqgeYhxcsnj2UL%4=M19ui*rR6K7*1i=f zA9FpJ#wNu-Z!7A2Z}T8emCgw=lOBsGF?1d zyel`j;jY;djmn z70Cw6WWfjXM^N0sZPNuix5Az!lpQ;{;cc5US_B9(QT3I+B9>--rC6{2a;vYH9JF5C?ki>;&5Hq5Y7n)iIP@8K zK(Vbjrr&h3RB`c?N*9VFpRAXj`;;8~yt2z( zTjRu2nL%Na7`M28g;1stO!byPs^Y0eB$Orj zw*@YTAXQQmGs?J~{l|W6E?VkBUrhr0z-O?}wq~NN=jsKfxgnWl%hl^At=v04A;bv9 znct`*hI-cA@03Z#v{_M-Lm`e);@Zq4p^3uHYK(;YljTxVXD>%=D46C3E;x9-gRhi* zJ%omt8{hrAys#xq;9cT{=^$G+$q&ZQGO1W1Ygx&6Cz-APXjfXMNSQ)sK z0uAQ7xpX(exS@XWR(Cuhs->m)a;@Cg=IzmrU`mNvsHa|Fi3Gub!8CzbkaM~wMshn{K38mkmW#;Vk3 zGa4(04A7-A^%*E#jYXz>*abpd6*^u~-t=TbP;s>}xjio;^=F%Z`)o%p)R- z!&J%)2o+w?TxG&b5;2RF*+x>Vc%by#PLi$dYtZ;>sCwLnUqpo0I;*tDe!@bqn5?o}Nj-7q_qiC`_sO+ifS1 za&3B6NXc;gP9Vy7apLn5X*U&*_vuBc^x|*V1)Uso=-(3hafwmFT+9kC7!`mht#zvaHzfniMnppwD5D@5RlgVUo0Lkmiy}kz`)X+(9#Tm1av`7 zmWp05^QPXQ>0#(W>WQoZIr!Fs9}O{Hhh0+r;DNSvkl=fxdDylE*4f6G7>6(7B&xWN zI4#*c`+9biq5}F{gry~Ixus9wZ&urs^n~v;W3$?*DhE5p8yJTp-fRF2{<&xzi7Bv1 z(nJ5#e-+A^LLi%lS*hnlHHBacQ<@Y4DnN3`rz@yo*_GM>n^H!Mw^)n=x&d}VB~Lx_ z0o`Dd(o(Q`DZ0UCN^26-Vp`myg2Y=c>`0m#38&^ za$b`MXtNiz+Rdg4Lj!gvudN%%Mwa#LvRcF<8@1GPChNMv=CyPKRv#?V@@X=3263gKbq5YL7|rBQ0t&3G zt={v2QouciS5$Lwh&mLhqH7{SEitQ-=bcd*N%&6dm*ja0fl+e375$P_Pth;(wkrC? zaKl#Zt5rZkbxe+fCBhy?ttBwU$@sFCc4APj5y~PbU);a;Km^aJBfN!x(?bRV|>%(mtcvGTq*?5cfv|Cq*uK+Pv<|U-fKx2ZYu6tje@)5tlR$c znFL|A^v4Tn+4&?30@!Mr^&tZ?LYF=drF+&tqMu zpU1k+JYRJw^&B$@8LyFE*dA1_Np3xSCv8@79H>WS@XDcdXq29=j?552*Q#6{mLXcH zzYqg4Oz)%m$3#do?4OIQN_YfQtNB2reZ>mEvNeJ+2%Yh0YCTSyhaRgpN~Gn0SLI0Z zsxT@G_*Z^heCAb8hqf<>PoW6BuOs3Gyh<9Al?QxKm=swg`C z3elq|qq1u~h*2}HP|{b;Xw?(BC+oo5efP()c&f98tmzNiF0iyE0F5s>WvoAFR%L{u z`XFmGO1VbN)UC6zWAEd31jn3LSmV;`*}83bcpLULD^$U@E+M$tv5cP`GM!n_<6SL|FrTwJG0A*q zu-*bUVI_Q@KukN)O5U5;#t+vF4LR5x3mQ@9b(BH7wj?)Jit=lj>FmaI$cR;z{FKrb zx+SAR{goP_Fg_Uo_`oO}a;^&vKY?F?J`m>~gC@fGY^Q`$hwXmpF}PU`)y5AhTl2a?B^9S4)@*z-@GDY|a@MrxlqE|;QKm3_3r!O4&A8i5>zu|R zo|O$Mc*o&0)BRnK_LdO72Kacto?a2hZ$)OgSp4kyQ`~PWnWsmry^#D9@6PS(h|hB? zyN`dux%>HNiaLjXa$K`?>tyeU%Nqy37XF#mm=n{oTw~>tbLP2CN6sN^${l7#REs5r z)wpLYV;96A@6=gy;Nf-gP6B-TcxU^{yfd=Rc#PbdEYsGs$(PAGjxD?i+nyXIyd+|s zma`x-g8SKXE%$|~ZCbvGnJGviu%soDh-W*xe~{v)uN}`=gyfYC4M^`XG_FF|U#Vn8X#@j!s4n zL(&wkjf2+02=Zz3`k;7P&>$&U;a$_|Bq94miZ-rJ+f5wTHf4)jmS;<{OrjR|!kR<0 zEf*+Ro)MkCN4u8qc$$iyZ8veuKql^U$+l{=l%2;si&hjCOLgz+;H|Ra)quGrtPMWR zL`?YQzP)Rk!s~B?Ny5+KTX0<;|3@8u!h%N9{C7xkl-uJe`trW;BVNwSfH%^x~R<{oLDlw%~2T=FrBm#RwiW$$Gq{!|8gv zp}E%4R`2Bz_W#W&IBjQg`unJ5e49x!CfPMr&Px%e`P=F_-&~1R@fGcil771%ONX+e znt}!?;g?*|CQ%Y^%W;=UM(csLjs@;9UkF4K!Ec74-nv(pd6^T_SR{U2#bRwXD`bu^ zA3{1=_hoB+OuW|gRG3Ru@`x}4E>NHBQ#@u$gPpcl$^qrypeB^dR%)xHBKE5z9QMhY2$l-3h+YDi zbDqx#y&S5S$ISWQVSEguOlZqvTPjn2dSIzJGj7z@xeb$Uzha9CWgG-i{4j{_haG)w zil~!4UWO8&#(eh|Q`3hNHTKOKd3lkQ}t)H)0NGt36@}obm>~oc&%9<^C1*Pu-(|6t z{^ir`2{R2&c?6_?#O!j3BEd%@n*C03Y$*;zaXxfKHN||Gt9JH^UOhr$xnr84MT}s_ zrBm)mHJMJiqicJ0B9i9joNvo5PoX>fU*WV@-{s5a$MyMj?(&_9OE{=lM7m(RY?k>* zJ@5hK z*2@rHlMvBk5yKmJX|4PU+LUd%&f#trcp?FYJgByc`n-z%>jGo1S+D!Pn&P7jnV!>P!$1ABjfik3(EsOSmkFGBk% zlR=<(hcG!Rd$Qw4x}WRFD=GSOQG6!KtkW@W`Be1LX|@Kbkb5Ii_hKvJ!6FNyC)*GX z6(N!AS}tr01fGx1>*N}vT8sB)n;bEG!4=?VuNg0@oay(($Ome0p4qS{fm&2DVNJx2 z>Q5OuK>S@R`M>`cD=|TReXOLo_=B=Q{7#C|tjl;BdoM5@yMtU}G=2)h%BsmO{in*O~$>finVn;3y=-*M?d zi;Y0Q@r{l9VdaWE*7wo8TeF3%_#N9`U#2%NQx#liHShh%=NQm%vJcj-2Awc<$x|Gm zT2Ax`f!E>J!#rEL0thac<(Ez|Lv6M22*|-eI`G|g&oB2@p{d#1LQgWo3XSQo)JPh|T zH8H}*B7=iw<&kC&ExX(?&Ibp?;L|!N-L?eBEfnOy$-z=XSxjXxzLA`eakBWZA;-oA zGID&R1}P>{-qB8LDRK|+%O7`tTD=4m6UEVgDXzm&ldqit?rgvmzEJ~hJ-EO74`xjG zNZ?JZ3^!BvS-?a!<8-sA%Vy()ERu>iXS4h79a#GMp558^F+E(pCFcy8?~P40i}Sp9 zA%?^l`Km8Yz=!EeKQ$h*k~%FeTge)fc)!`*Wyr9dxB&niMl8yS^@zCeFMBwzKM{+L zPY8XhKM@tiCuZEqMhW1nBayBbTOA;?gVDBjy{G$;fN zvCx~f!Y9i@Z_x@_&K*(5>_+pNm3PWK*G_k8y!-M-m&)O%k?Ey}MTkYU))rz>tykdE z*xp7Mow2C5z%hSZ%O?T;IL56sOAD&__@`GutzEPwJX|@bh2V=S>#n%u{G+VdOcL{a z?^e#S6EI@hKam;HJyR%nVqobHKx7pPK zSFhypm#Brtsa<(nUPsBHGlCe^jSr3I(!wY%UY^<@W#>tG-2bY*raXwY5Df7G^p`2gO!L zIVVfJbXe_;aT1ly8kAVpppWd!(Y%A1EzX^Z=f%ZttC@t9sv2U%TpQ!rG2fkLFES=| zag@p@_UAfu4K}MvQA#rCAg40z7z`sHKG;2>`2+~Q!~{8K($J`qpCkwAV?Ihrsi83X z_$*qcPG6mpvOwOk@&*DLO*e^9!Dq|%mzcfq+vXV{(aoW2GD(J&;)Jl5ak053lPQpx znVRBiN;Z^11&#$9#*+^F>P*V3rmTC+pwP6WRER7@AM>0)_JqdGjfOFKt_6l%xWN_E2HgM>P#|cBP_qh{K)5p~Jq77e3;ZB8 z31eXo{6Y8vJ{z9tpgTKIUX>(7RQ-GpmOJgBlqkHeq3}9Av%XW6+)Cc9q3h_DI@PQ? z6}z+(MBAlSMfaw~FmP;0TCmD(xLFJvZ35a9wURoE>STk4+wRxMg~s%ENa7(8f!#A# zi3IH4#^VIQy}@=!^(SzN*Mj8WF6Tk+>5XJ@%r+H(Z-Wv+2z=c*2kLKv9himMDIyzw zc|(+I3&3w>SA}POxzAYQVX+tOC4hb(N$QIU=|UjM3XqV z=7KLLml_1mK}?HO31=;9b99OQ^EozfDxX3P`))Jrqslc2EX0z4_kCGn(0o2Drgd<$!B|*+Di8pNfIjk zN`8Lk&-r{e&_skt4z}eh+{MpB{$Rl$1b*0Hp}_mEtHIq_*B@Y-Z~@-vD=sBq**Yo- zZg+t@X#o=8k9pTn0R&2keGJTnY`TX!hV`aT#ITNQ`-^11J|bwV+5Hj!kcvc-RxEC= z=`wJ$6%D*(taN4RZV;q6{Po{b9n%#2+~0gY_4m^Umvsqe+WWDOy!*F*@^cse=C>mo z+qqvo5MXBa?|l^Zv=VPOlZ(izml_swqR+eFwzsHw_5kcK%vh#0w4uvktm-lnzsJEw zhHVt@&pG)rc6BUv^^=#%u0Bz9^>o$MU-^YokN$@*zw7_~yS2LdTm4-n@SW<*uA=ej z;CU6PtMnty#g7_D5m(J%5@5lYQpf}YGAFQyb^7i&r)c@isgwlGDR+T)*-BiS(*{DC z`!ewn1|RoQTdA%gP069#(EP^J$01;=NAFZ>h0sw;9P zao2wiX!V;FzxtCO{qXXkzxn*1|ImZ3A@;G>|9Q~rhdQf;_X@Uh(|H}_izn-Zq--&^ zT6*8&(t9aN@9BQw4Nn(a`k~XG6LpKMf2<*fB%P%yyxeC#o#XlnuagE0^W^u z#=|CVcZ=UCPl-7YmTJ;DxOCp>(s?0CXFjP(XMHJ8TqWuxtW7#oyry(s5-OW?j{O!_ z`U4l#&pL#5(T76#qUzGw{TJd)OOno^PdYCp>3oYz=cNJZe49&WS1kGj^b%s+dwcE~ zQy|paKdXBCnF`@AeC^;vzy8s$zwga!;JfCfrb@Vbuk5T;iAp}Jv!>cto#iNyr2WX# zi47dNKG`SGCX(W_#I1MsgYP#QlNMeG;=?L*JnTe0~#xitmo`2g{!Ds}BY zR3N_AUjJZ!ui5k`9VQ{fbAmC5d<6i1Sqh0u)X!aiSKrm&Rh000SGjfo*THKuZV$TG zsI-aHQPbp1M`;tOb0>$TDQzXGN2Sfkc0j_0Yt!3SlC$b+ira^VR`bF^L&nIg*i?K~ zA=w8q0&4~bGqQ%N_0ZJ~4)H|c^>el~PPoo4f~#2?zg2OEcb|RlM?d|! zAN$C!uO$u#2=0ZoG(KB(wPtCYsk(aM9l!WjpI-Uc)30BHkv-gxxz}fCz}Q-Nq}EjG zzcKs6r}%lYKgK_wHHVVVwL9Q*mA^qASA|0<1FpGADVwkz2l!p_uoX>YC-#(hGdA!j z<8JGaBWw(PJd{4hQG&Zh&Ii=^z9+n1K9T1H)I>N1KaGTCkM_-tB?)GcG~enDxo*|7 z*rT%6cLkom>R$Ck4qWs2X(fnWLc}&rF|NI%^41m4`~@mWcZKQ3 z;#%v4r{DX@XMf>x{e@p2Ypzcqh2*oS{bVu-Cuo;G`XTCqSFmF8BgrW_EeIQw0TGG@ zAoc8`EDnlqTA!tW_^FEcQ%2>2)(S&Q(fIOR@|MpA;OYw04ON0yPPr+y$mlVc@+g}w zQ&u&d<7dXButrr7DI8<1F5wdQsaO3?)o=V=9kWvcgf}>4NSNcYTQ(f4ft@tSiF{Q4 zW6K|02H@3(W(+(60j7H-^UqHY;^^Mek zHQZ|n`T`IA*W}OxsfN5aLA|2@IyOD3rY8)P=_P+9tI{Lc0UKSS29POYnax6iJEOiXXs=l(l{g9L$I{!1PK4rB&v7r>x{T<>sZPTM$BjUk zgXk#}Za5+&iWC{q0sy{tq)<1RnbBTT5rO^uX(2JNV}H3e1LK9`fAtAC+?5zu`9dE9 zdjl&Y^bXnFH9Y_`BU-FuEJ!W&Zc) zT=?RO=^aC1h&>0*d{k>UT1@cw9&d``d>-{m_E=MP)-+Nke#Qs4Gpjb!Lvl2x<|WD) zM(n_2u>*7rV$@91cm1&FvXC8X_9mR&_y5(iqu8wCcnpejrpw-&yV2PU9n*l}4y<2j z1V=MUm{49eLK+GbE-;T;R^Quvqt&*+`UrT5>So{ZYfI+c538r+LE=ffy2iXmmL_om z^qcTdlXw|y30H4oDaW#GkC;(D?2JUqq&aVa@1laJK(tgVEj-iMe{-Wjf9$dGEwpwb zV_+VZCve!-S%q&^c?{TKO%KMQx3y%T)dWLJnj%a^>}v$}#ep)m`scmT7ZZ0OH?kk- zt)~MVI)qdfUNeLr&?pF`bVl0WA>L(~@(Nv|e1LmeR%P~LDwkH;0k5mxT_v+04c+MN*!W%R#=?*^g=3(Svbh{>BFqp(oA@DN`XoP05a|*L zDBVDC>H6N*e)M51q~+u}89H?afCpR^`>cX1UxkqgKsEmA*Spn$8}IY z?TzWa7zSQ~ac`%CBB$-n%|tS}{OfG$gizwcmJY&g@BtXuvgiji@@-PvKoSN_zS-wx zcA(VeK-zzXJ&^X_utQ6R9FrhC(KF)hVYkvfm3i{w#)$&8do0gS})j9383IEZS; zQ>CK-GCvBSZTAjv1OHv{ZJQ$UEO8-p7t4SWUZa$^f;_AD-CqY!O$0#Q{2p)irby>a3SMojq8df8SYjtW@)y)R zu}#Ne84?}6EyBh0Uzo|Kgf0!M1D-nL6#)vZg{j)G1x_1N=~K7z)o0S=c$U5+mA>sp z(lh$NsFcl#Em6 z%2b$DD*Y|K5lR{B$?+eQ&Pkze+LbGiXxC&O#EUYK$Pi=^G)I_5JZk6D+~l0tsTq*S z5@2|hppUUIjdwasYoa)R%{UqJXi+(2?9cWa|D5*x`AB3%9Bm5ZW>P3nCTSy`Pvlba zFhappE<_V)mF4TCJcMT8-F<-v`(Bfe`4;&GeW83tIL0ez;lwm5x&5$E2W2R1^IZGe zgwT%e8+nzJJ{3Jg{~4S3JpELzeZ@i9&OJt_T>E|xQ0Vt|-O+c^wfbImj}QhG(e1K` zU?Mt$VNGXggh%`Gky@{#{N)9X$1!-*SM^(VguoBe0DHi9`pPJV>q+@Z3a(Tja?@)+ zV9?JF_8y?TFzLh&+*ixF&ncclZbn6AEs&@`-To{k{pt1tlhdDWAI#`axBpK?mJIac z!impGUH^IhCWk~o99!I?N9egxD0o>aKl#!{X@~_WLPoD*nSPQ-I$J=f?Iq>e9?p48 z#?KM~ z3g;Vl=TH<;VhhP^}o4AftNWOtHncDOAp^059+UlB?H5=;Dx4H0Ak* zQ~6OKK|Gi|38n|eC)}Ir$9waZ)RLXBQ8Y!`^OtMj^u zNu(qVhZLwwl%bnUJ5!w6kQ#!odGTyjOrJQ>$cr~u#b+s=j>QvYu?(X7uz!kOQD-Hf zT0T77%Jfwh74fN(;{-@dD}YeN#byY*yy1+fZRO3*7!=HFLzah;5Q<~iGV*~Og|7jZ zjE*zxqRF89r!@ACt+8kYy`E-JbC@tFiPdMtAU*&k?-9m04#BwyzvK_tLll+kl0lGb z<25&PQx(fxB`i~?bYMhf7E<7)gn!99Ud9Z1DW<2Aw3lInieuAPx0jgPQ%8BdRw@` zf!*6#F39v=6mICfINRe$m(;EP-|*tFQ+E7|5vRZ*k&62sRntToqi zLA&S4Z6jsj?%OmTUJ|;+&b#x?nC0|J&N3ACL!uD85zG3;lEk=V2d>nBR_IEf87h|X z95k>j-NVb!4rTh9EgxBLM5@+H!kGG|J^RROXUFX1`yPyfV&_}I24zVWRlLNuflyg? z7yO$$acQVBh+7HuqQNGE!qlvtXe6fQqBsn{p@-tbcOzn4nuFr94t?SKN2FoJx(+^& zDpM^yJYFk6Ey#*9wF2-vD=yXw@a|^C!w*(~$vQ~f}FJo-6$1M>8hL&}|#Yl`P zv#DL$JflEkk?Tdn2xG=_OUMCmcpVeqXVc*r#@5wxKBqcm3QO-Xn36~sH}we{cHlq>|8U-da#*P<0`hs@R&H;} z=)KDif9*@!!PN1qJMx8@bR8CE-k#sM4{>p02p`U0`p(`>T)lL;w~MAk?~Qvy5Pk&q z*RIA7>FOnZ5L>@VoF~#ajCe?f>QTp$w&BRJj2AXB(+tIN1T+ny`^yPOj%WCaoRM*w z&~Vs9yBd)Ot^o~$Y?{~+jyvf!sc5*E7CDX-myJ7dR5Lw*Dg_B`H!;BmR7L2~9gYl( z#mt@Ii9claw9ryMWOhMFQ}Q!U=IA?gTB?bug=XSI%_DNh2@#xw1}y-7ToyOpFEI{n zs)q?RVM15z9t%j0xBzjJkXlD<8&b>aUd4_8FzdPkv~m88d}Ho9K27dA<_~vWmui^5 zo8_+ShMOZnbL!GYch|j+n()@$9yVgQ;HBGGe6P-&+*sU6z83&WW@b9JNjWppe=WNT zb5JU}pz`TAdpf~#4wNuj-iY1H+|hjiicv-T+rq~E#arCvdk2#?CcAlr98ud~S^8FU zCy^wsZfP9f++Tx-jNi*p@OeS+i1|vNAzPAlUSfP>~c;_ z9qOVLduv#Jt6^%FkJ)Q)tM<0n?)<{W!k!r+*;v@5b0@jGOWsADJGqfMg`w*DcCZk@ z(;=NZ*-lQZEu6r}0NeJ)T(8OSq;us`BB4{_UX-syCJ>sJshPmbqSK}K^p@}f;R|oz zv0_u9+zNQ?^#X6lDx{X#m(+ur$5;MFYGjF0`-l^e^aP07k7ilAZrBfCw;}(h9jSV=n82*4W3m}-|YL0J#0vo7pNOR(@=C)Fy4Q0EJlGbAHtk3p7ac17T?cTel z^-d%s|MhUhC}3+RU8Z{;+jPkH;Zv{;z-n_7=s4#`T#kh~O_VJj$G5yUYM1Y@ypnfFl7mSuF{~1*2>9RA{x|YjsE3YQkB7;XvF^K508%{1e#v_-V-vb7E3YJ=L-5DoYM&DTR zSC4enxg#GTA2XNEkm#q_MS0&9gA$AGyxC}#w%tiLVz)T!KmzDSFPW3>p7P{O;V-r@ z(`Zhc+fl8UMlyex-%csR>{Le_v^qDFQv&r+TuF1k%7>RCB=#ZRXiwhTem|a$TI%=X z%`(b$yJ?K*-uvLDFVNV)VtK5Coyi2;e5_cs_~ z$qpO!eeY@WKK_`E<2cpu9!to|I>&CfACZsJ&eAUpF4@-o`-}#n?ylu($SOv&(ue!? zC7uTHf(dzTr<}m~XdSc8N~)AWYewKCG7_&8s)?=hqQl@yi%Y&RPrsZNUz>30>@Hl} z-~!nY8I;!ZaE&o79w-xK>Z>3&3KjaoDv$R6YD*o6zMZ?L%DZjcJzd^a!7HWGVOyVJV zb+-%hTwq749%qPKmv^R)?(#AeQ4`Ikw%+7rOM+jMp#%A9b$H4FZS9(QfT!txdJ8JO zzzf4PG9H}(azsodw;rJe!WW|}EZN+z7~&0nh5b9E8~^~7f{E_n z>YE3)J-%jKhsAbq5`{3s~J7hch7q`@GI8JRha6XT!{3t&<-P_a67vYaLm6O@W{qq)Q; z91g+EUHbBRL@b3zCDJuwlruK1hg}B{E1f&w493GnYE(2DmSkwOAfgcNvDhb(vE1w9 z;ikQfH_~@+0ZYh?s5#+*73G98So=q_oFfKD(Zqv&Ot0wRo7WAoaGbubR31%^GzhEC z4#!b16&#m$_BLZLn;;94#ux&9eDk^tof~*Ivy83W# z+WX*v{HA?C5qyJ=;``^Vmhycj_jq5uhgDzkoyFO{dWB&p>qi%7dq6%L57~MXyy>`D zwzOj6B*U(^%lU98(+KYP9rth2$(y^v=-b0h2YNTjnlJ-I8kLDs$=}v%@k4|qUTryK z<>K&sa{%JJbu9uS+(e#Rp-tHz-NZhzJnC35DqyH_z;9S!ZN|yetVnDObRbRBFv!nL zSZ4&(-c9D)=O*|1|v8c<(s~X zfEtUTDUI?uk&h0z$6Q8k z*09OF;;`k}ZSpJCF1q!h%G48B$HK-zn|zLj8Deh-U00aL8a8-7voY7`I_aIsaIXz|2h|uq?H|1N zhi-C=DsLzSx85=kCHF&VD#uQ5D?1H$jh(LSc}GR&CED{PYT8t4LEWdXX3rBJA+a~6 zu!m^R$G0qoL2K~VE7|V31w>TlJ76D0tCN*)6YKD$wrI<5Nw)k#7R(ld#TfIrRzn`| zNi^hXJ;)mga~Lq>;cTTLAO1h~-akst>%8xK=bf3I*`1x;SzrO|VzI!T!IIpiND-ze zkd+u0FAgPvF=NR+I6A7LbILz-de8;aQYxdWr=SR1kb}5Pia4}QJ4}tpw8*q#4w_Ig z<;cz2f^F8OZJMT2*_I_pq9od;EjXo9Cgy4S`99CR@B7YT!C#^zJIA81?>qOs?|tum z?(_RT_qkgd@(j_Cd6OX@z72*v>I>pZ0_!i5ArHuU-*Q7CCX$gTCO}g9~TuhIQrZy zPBJpa;!zeo9O3wV%$alo%GSJkCf)K}IDuI+jKKZdaps#g^J723ty8~ zf_f&GI6SBpNYK$@Bfejo^QH$9U?m%tcpyO;L#p&7D^Y;5 zN`Re)jZDB45k#Rq3UTBTYA_i(O#h@2(hghL1g)rdnNLi_PsFQ#LTy{iukIxv-D^{BEfXtH2nN@)4LQ(tcUcDykBI>! z>_f|1TC~9LiAeTs65_d(!6!8vIUz(;DdYC7OBO;hul|5$a>}bmzKbmN$a`?gT}=Ln z9-Sp3k z8iYcmcz?f`0cDz7@%Wf;Zp9+(B$AUWuBk5zv5rP32QQ7((1?a~-5+aG-q&yQ*RsRp zn-2{%jIMT(Z0#y+7w7Wz6`UKEJZMvXXIRSIxc}iR^ZDF8?X=(O3=YnwzZ{yl?{aA{ zXiCXh3{$av8=7+V?!r_uJ=Xe<^eNZac%_Y1-12y|cH}O&^^E`Hvyw9|kTsGIz$~9*Y zYvq?yDG@% z>YqzGByUpQ+4Rz+#*u1Edn?b{X6c6;uHeStT&5` zw*L*Zi4~aO7CzV!tRyavf&z$VB@}`!Yp4duRq>44ZwpfiV^x@+n)PaL30)aN{YB?n->ml$J&9=~)BybNphI1MVsg}*VdXvx15u5-5Y|n%GTSUm%IXYUGc>#@poC!*E(1Zt0Qxc-PPDEvn+J+bK#eb6C6dZaZhkAm~J z=!B?Ck60H2Y9b0yk>hY!ow^_^PVkF3+$=srE_JSpp7db ziItoq<=hR}d0^pe#GFZB5_;tikZ-2^0owJ;A0S*>>YW4-uno|d?oEo*!G+Qus}v*;7kU~o8?8#N2!oBpwx-oIVyhBFay7Jp!e0+s6%r>} zWdsNws1@q8sb)0ocSyfZ+xmp7U}VD8OKBqE>ZLT1aP?A}NT^yHT%?JFsh85kG&IZC z>*&k$XtxVru9rdz@NYmhRtgn#DCLXwx)8twrK>N6`)7qOGxplK9F7FQ?j>+t*mD|Q z-y6JeugP_bI-XQ0*%*5}n_G|>LPlFJge{3ugr~!KqYRva!f&?039<3t3!@1vLavFJ zga%kxZuqGY${!)ELIKr)LlvCh` zPYO5QX(WrD$5fT}*wTTeA#v4Em=rX_!N0M#+uXn3 zbW=>+GO4l=yDT*tCflqG&Bm=uN&&4epjFz3hFuw}$^?NxH^pHJ#SN22|CvZ@YrK=F zc2mQCVj=*euV$sh^0bjQm!o|uJ=zQ2xiN7B{d%;CmxaQL3#EdS=f!s21e z2qU$R1OVqwDI?6&^<{DD>0x*M@I8m`VRzH);N#N4tcX(KB%UBSiPYqbOzc_ZOx2P_ zm=gvz0%}&E07RUjpoap8autt&P_`1{waM8b=Z^;C02y_SI4s!Lv!o2S8yvPPoW;aG zySmt&G#@Cj-AN@_>Od*(0c32GcTMnl-+Yf>WgI?(Q?{0S8Gt-f2Z%vR0%gGQsK&=k zy4YE%Km!mB20w0C)6iE2qZz@Ce*h`Sbi|MQ_R;jxX!Zm`eGq1jvW8|0JUca0R#S6f z%rj7L?nKz}i0aN9RrT*%;^iZ z;9S`tp+IVIw>QYqykUni%0MFHo1BmU+tSB?)Z)iZ>D<#hB>`cK64a z!MTqKAN1>}e%YVzTjJ;vhQj!l!lK?oz0`{sekp;$^xN=8PKSl>&dE0u7KpI=Zh()N z`fm6M7b}2v4xfTeC{5t|=_UIcZwINEjKMz_-fV7d$y-}0TU+$j7B6Y-E^qBlS|j|* zTQhWpP?>1^hHkaYCHBoC`dagL<@RV58?begB>wKdP)`^t_EzlR zLEG?VY*7lc|UB|TM*i^|-Vsb?ee*ppx`3EDEWSB+HxQaV`pDh5*15TxaM{7T2^*NPKk&Wf#P{~X=Cp)9 z;Ju|lu?n&fJD@N4m(`DX>w+ZEyd;pB{AgHWoI9dCk{}Tin>Oy~qG*rvMTrv94+;9P z3FD=^hP|*$u?)%px1|7mzAi7y6xS*Dnn_v@Kzr~T8z;-H&gEw4%T)*+47w;5_ktW) zyE~(D(7|Za(V~=E9v=+WsB##ctB^oCdEg^iWb%z_8gwA7b@9G5PD_77?iVFC{Di$|yQ6b-ACBnvmH{3JbS8 zBJ>N407nCpnyBzeR7RaaQ5Sky7il$s4a}oqlq&)~CB{h9O%hYxmVFFf%qOJ8V+Q2_gHBBe?)KF9TW4lhcP1*K6s4S%F*)?@Tw#_+>leYpvQ20wuvyTl9RpKDulv zGW1bGl_ zy2DvBP5!m*%o&}V)A-1?YB^xcMvL3)QsyeW|Iy`WG4EPIr+{!pdA7JC?MdRqQ*f*v z|4d3c!+W)Vl^5kELEk5WUkC74^zj(+-EKtt*&5?yKV35Qaw>>UrQ?g45KG@vcMy#j zc)RgqN2lDZbW>Is4Ud!K>kjxn8~2X!^5?R*_jks|psC?DzTF>o(^zUfkw~nuaNdn( z6#<;;3w@tq7eB!_xXrC|eZ>l|=64YPCq288gfF0;-1o?Nl->t^l)q)xkCq*_wr%i~ zW%T9MV?**S&JthBN=F=n!kKY#Y7au+KFH_v5mXy{VO~(s8@G;j^es)8y*?tSkte(O zw;+zN(=3<5whNDDi{=N0i|H{Z)iZv^H_hUDfxTdxL^~fiKJ3@4G!Mx(Hv5>Zc0!I> zXIv-H6K0*4oggf5*U`}|5`i+x7mn%=O3myN=@OKqQZLHy1Rp+ujMyD`vdjHb+M)Y0 z@4J8DwZCr}`d-`jhYPX0SdNy&RJaHyHdG9YGL+bT2+#y56x`PUqVZ3_67&gXA2sux zNatDj?~Hj6wi#lwYZa?j;m8D1buBzVcpRi9cZW-w_HHB#4izRYV4fsU!$qXq3`_(O ze>-%+g8O^8Ff|_bz_xA$;(Fqhl$fY_Jj!=gmn67#1p zoGz%u@STOb7^~B>v<`EL;1WNC1=|H}d_Rfw+-}${Wg)IiMF<<(g33aAEhXJ<$UWpd z@nM$_?NQFyCgUPPpl|3UkO{@4kn=g0tXRSHR}T)1MAl%g_^R?9LsW1E!8z`1*)0w1 z5Ia?qwabCZ9sfd?Y(~rK<6d=@OsIG*2~{|li@)rJztE#r;H05D6FV{eqbne>d`Y)r zCr7jD=H?!H|EN~69fnkP3r{88!VMzo*R(tL*jY5H`8hV+t86B!G29n+D$$_gm`6kj zx)w@p>CbyzjopixL{Inybb=NEshwgu;G`J?0<5l+%2WDo;AAQkblQz~%kPGWm*qFm z3|ND+(o1G-)^-*L6tc571l0If)f}pTniKL%chfS;_~%V49+jWB`slfrt#7!nsXqGp zW$U|7v25Rlw_$vLryHk2`q7YRe4_;rSD?kv72z!zB<#UZfF0EUTh=NV)^UiDcK{9K zV52mj^t+*r%R?Fg=a3e)jPQ)Ta~KE~p8@4XDkBH_QW&l)Uk;TS=L{FXBjE>B!>jll zAQJRLuqmkbYx5Muin36~2e29Tv7%PM#w%_Hx<=|i9~#h+KhP|%fr0AOXzp(5!eMuX z8_NlFcY~O7GPJ?Zh@_+L(n#jC?fqE}yY6OPksZ$OW^v7-Jr@@4rny~uZ6VCP8%92d z`06i7qU{O;gd4Ae{YWit76MO#%_3c;FvOvp7&Zp=;XxQheS@uP@HrS1W}MZC?Yr zi#QlKVEhcO0Cgf?x|&@1662fx`koi-OSEzpVnQP zR?XCm*{VBjB6SaHnSOGZ1QlwiK?scobj4q+I(1(BFTuNa$T1#SWwuqB!JyHUPtmVNk;|%j74sT zjyg;QQ9vH0(kP)k(&#E$<6}egkl`x-`eyd+41F=h9cUx$CXD*uma4wQV|*}E>w+{B zfFl8I2C!5IEu7P#q&(0e(uZc!D60;QCzEa2S<0SF_J#lOWTk>{!qab2jR>3(+E+iU zRn~^jCnJpcHoBM%4Ad>ZE%m3ZfutPy07(K9=LB-(6#_}Jg3Tz(Jd35S%(MJDPV!J< ztS6-N*o=;tO=Og?n@LdS*?vme5yF*HDLwjXWKs-;FB31Zaf}xEB~xrsYLQF}6y}|( zL4nblO8a5aE<%6QG1vk0FY?QgTA`i-q49}M6J&97-`(z82 z0K^h_jMOJ$^2H?N`wb&geYM+1#o(%-i2Kb`t z)m!^YVZ9@)#;M3mjfm4>;KPD(^r%xS)o5(czraCMySRmt>`NO2Tap~Iz=4H)r$=TPh1VHnkSnOD!U zP&15qL}Cp+JvLe+qO}P^(SnkQbi=CpKNJUi15?)uZ%_`unw7yb+ZLf08QvTGZDvM} z9JLkJK+l*!1eFS3-l(qxB0Q6NuJ=eFa<$&mGuUmIwFDwVParZAv;V?dJo_(0-KKp< z)_@r|@(yllN0EdyWeG%v%3^f2gWzgLGU{sk?=W1g1R`t{wk}_zk6#f-N&;V>y9&l-XnbcA|WC=Zc*QnuPF{EpZSQI(>Rb4QqGrn!8|0#^AHJ3XL~E3Lty zu*9FE;9W^+OX)U=&(UH^6WrHJvZTZSK~|JWZ3dbVPR%g-9iAq52R{f!kfE_c)tNXT z41sb$+OUL0V0r;k=(ehCM zTMn-rX&l~Y=TbF5NdQ=<)&Q4{&%8J6guRM;;^bhcqEP+p2JQ7jK&dkDtY;R!hDO4* zVT3xCg=@lfy1X&G5y2sZ8qZ1s0BEEOqK;=GxtfykOeEJa;p3S|z_#(tOs@yOcwO44 zmPn+cKmW<|SO8~D)8AmtJ^(UrMs zk}9fI;8GcVFHM%{R*JAvZh`0~w|He+Sc==XhUPF@#8YH)8nyRQ2@1~XyLD+fNh77a zJPL-C-!0Y8M8$x?=yX0GhFS~Z&a2C3cjK1q|Hu$G8h>1?yC`Q-wtbC9k zI-Fso5*=|wfB5xZ&=hr}Eo>>hZaRT|z5D0~F@YiXg}X;@3U9*N=DlTXU!LufnZ2;d z%Ud|0@YgagM06p*HVC)+cp9%8ORK`{%X4VQy{t7-f$XO;$*V$2>}4|zzE1V zt7_Ii2;}aWv84ztQ19ejx@1QG9#P>QunFA>2m7=nhWOW5mXFtkZ;v}pUJrBA*OkuI zd4I8?U&RkKiYI=Ao6;pT{&9ct^Hw7YjZH)J8qbZ@*h=ucSg!%U+-{u7cYMt!sloP7 zUsR^T%e%k`zh|`}${6yA@N0a<3vwTluWQRs5iCcLLhs!;-KOo2(}fj^F4*t_JGy|1 zX<2^*S^M6@D^2@@mri-4Abv6$y9QEUaQ&ma(MkvZ)z4C7MOzwp<%7}sDaUBkRI1FE zR2fRCWi=EF`Yw&`UGGG#B~})x0Du~W9W25Ito5O%{+IUL3|;{C>c+OfjGgdcP%9fJ zgnGPj+xgQT@)aRE`*R7!rTJE6W##aJ;-${q`PNln@JbuTT;QILtJ`1ePqbLgp5R}z zI#6tbsN>vgSon{4S3}WWYee?otg}86A`beGm%-v2wVfaek7ZLKZqS&M9{|U50ko|O zF3Bb*MF_Doj=IjPZ)_gm#{{Qt1@@V-LUzZ9y|(0{88*_~+ersVZ)F?Qw%P@4Wb#{9 zN3ejHzcxu&+1}$S2(f4l+BYwycH!Zs*H;Nn<-Qt&0yyfURNK;KC@#0lsGm1DAkNYu z6leOrMrZR<+6-Rgv~rXj*{Zoh2_*Wa_@Kj11pqI_uXzn1oHnbFJ=t@WoWzB;-NyJd?iIy&_Y-qDsedK1ag>#t?tU<|@H6y(4IzWKYfQ#Y*%K_k<06M=`7PxfcdH znX{)^QlOZXX@-!d@kg2+YUe5B;byRu;K-Y}u&R615SZm$9qz}uUg9&ial!k1#GFfp z$pVBWLN7>C>|>4i%Pv1dW$<@O59QkhSTzLB_;D!$3pXnS7CLW%z_S#;1_WmNRSkhl z^fZhHJmVM*hzwq04>bgy)X|i$34ItnC_~Q;sPguc%?%7@^|hSsgdw)FEo}rbC0cpyt}*+;@m(>A`Ka zy%L5Oq~lGrYd~Qx0GODxAF#^s?7$txrDup!?a@cE)fg?T%?^Rgba+PY?AV{^KmjN* zlAeW)nz->Pb`Fsludq-nVCcKg%Pf$2v5|tes^i5UYiy-d0BjTUwq1lc19od`l0xHq z$OT&HSgk9@eCviX}n#|K2#4n5n2Rm@U!R+en8lfAM#1de4$$XrXJj;^br6e zc6_txD?TffsS$wqp5aO`)AP6~{hRA~EA^a6mP>oy`eu6Gdbytes1C&zNDM5RbAXYs z2q$8W1V`agVM}{(CA9eg#gV4Kwy(92$#re!PeiN(Ux3+c^eYKU(plc<_q-#Qnks5GVNdqke4k2Vp0AcA) z*fq`=+gkTz+j1Nj2c1ZGA|0hgtpm$#f98dzz- zFSr+_-DK*drU5%gWMwDGNc=-vlGftH{)R4S*P0)-gz`&*O;~k_#w7*V*JvPqgFSY9 zSF8icP9r^#Li?;N+=$KZAO&Gb=o%~mjb=UTsP$-8b2l3B9&;;GB{UUcOE0GA!lY&C zWSK}=I#JM+d>IIEAVwJQ=Ocm5P#HHTM(i#TXk!1lFjx(PjD~Cxp;^v7gdGe0bW~(> z-FgBbdgB8a#LHNkbcR+A$oj*w8 z8um)Y9g)ri#695R`gbdVbAIm(n!9l`nI9@6?EJ*@Fe!DX<2iBjq{r@& z%0Vg$AU`F7w>fMwZrgOOtwRC>J9W#h0MOW#iLwjoR_Z}3^#Jn9exII5|T_@=t`6-u+PqRZrm&sQM^Wp_G|oie(ypeLgfhluNUXw+oi zK=%>_mYgV8gordqP%>tP&{}lqqPgtnY%J=x*{;T{P*(>3L@}HWKM+hK)LMQf26{k> zMU2fBrU@z}h|SS{0Io%LikI4!8_|q5=PFjbO=<}xA{KJU18s><$@p#w6-ISGhj1~W zN4cpI0u4QNp@}(T$jmIl5Y-lR++hgPOuM!#8#V>wmeY^W8S_@NKF9`VmK5$*d|K$g zn+o`@EloZpOD58w67q~u4?FM=zDQ6BHp z!c(X;FU>=v{s|)DVVFlD6zo%de)2?U;sPbdIw3M)lE#~{aeR|O_hK;^PO_*ZKL8lK zSo&J_0i+NL`jm55al9IoVRXy`3WZNsdc|}FI#-E%+$Iv6avkyhf%O$5?b$6+8dZSd{Z+ z(NfT78NcWBd#?IDso#^;@1cGV*NdM|`&W3U!4^LfIP<_%uSTR~sluj{56K8@NtdH7 z>L;Qb4F@&H{zj(Es1EE9&D&0j=H9kD z&@#(>(5o_=?CAk`i0ljd!B~Z!RxQH9XdufD8f>7Y$arGcGTXRnWu;Rg6SjN3(pbzi zL@zTotIshjJCIVS0zi+;4x}jq$=<=A{OwBusYdd;PE|uE3W%he(sLVp=^6VS(}B8} zH+N4uegUiY6GwXgOc@EZk8K*=Tk>`+PyA(JL`5jzR-}p@*dtmk3Z_a-o-CSlfT-f{K@zlRJ>ZDUKJ(14Jav+01I@y~IZgsbuDe4w=4{PZTeUCpt%9kI z=X+QWge}$yZiIKai3z?WXFKq~(~=iI{$~tN8PakMfoS03*G?gSCBO2+zxeEze(%$d z{OmvaYmOi*aR55=?(k`t_lA#0oqCs+s(fsGl<^P#SseL=EHe7uznN%sl0G*MZ%nJ3 zdF}W9nT^=81KTOc%ODh( zj0)`qI-VcJLtZS5e+$~4=UZR$?g%J9slhlX8{T;~_Fg*uI)-V%r+w9UWJCaLyMzGL5Xu<>MDJRfel)n3KmfVg%)zR$ zmS~M7&eSWxp}_szzp@!|_TcE71Hg0_Ksr%+qeOwSTeMSltHMip;!KBo59X3#;9;av zPzT14@UrmEHJQ}42|g+|?e+zdg021v;dScE6DXi49dTp+Pd+0}$=*H04}*Y&H60M^ z1Q7Bq*2e#3M}hJ2%f}cS5-_CpM-UvkvH7lG_eT6bv6%!aPZ}MXUoSuvY9A&yj%MoV zFBvUTQhZcK&%yi_K~~fx($uXoeI4TZjH(WPNwu=x(|>vC>TE?S_$m(+7{wu1wl&by`ODj7l#--JRfBfnDfBjRR{_GQfC9R5YnY6kr zy#I=>E~Tqq=rrc;!6eC}XYV4KH`dp|d{rWxGa=(52I_}tZ&F<+uv;*cMsA_3IjpY)=~LqK{Nbl5OO{pU6cG% z1hxF_eMFU%#h9slc-~*Yi0*owD_OWN>#SIvf!Dc88lrXcTJjy0b>3igroGM^Q7OI7 z4J?C{bufAPR@dvinKd@A^H%bymUaF!tJCs2q>aqI4oaim&AnXMj;r1BWk6+Q_2Yd! zmZB)O)}i!@qO@c#jdY@DM-yI@#9U%ut;*>O+~wNpoz9z$kF@Z(9nNi)&j{C-6V-T2 zjcX0q;1*ifyJnXBC4QW6y8@YF(>gIH|Hpity` zgLhgpdEUr+MH4qDt$4N;-fVEMH$P&%(0g`rc|pJ(>VM3m39>$`sdhON z)SlC7s$k6pj%+~W4#JBrM;TXc0W^y=1?{mZV2U=+!U@6>E}aCx$KbK+Gzm5(5eF;i z8vw>8z_7Ruc@}gv{|0#wyD{R{z@J6%KbhwW{!8MlN;Qgi9s^JL58#tOwXtzBEBb?v zn@vdWKf>33;r`E3HeHrINf~_2>buufC@BO6I8O={?WwAT!Oy3}NACk+Sp|4NXDY-R zt@Xh#_~U}gwnjjdD3u0-&wBY<{wLok!vY=Iz>1ifg2Me03v;&zmGEL z1^m+zCXQK=sK=%F-8EEXLQ8j`m?1BezwvWPa`Hf?eaw&&0xK>xIw7!i)97=VRdu^}-ip;YnLni*25=A8k@&dzbFD zYeQ;}PFu)YBJ$NtC$DjtR%GL9Heh9*%RG7vmj#yFxa=WNi%VeR7nc>bP;psRuC}%8 z8bxodW;YDC>2ed9fjrKRui(*K%Wl@mYw;Lgw&qfD8(T`K`aX72aJgNX3s<_cxr2asE_af0gv(vSy}EpOxKEc8!=TH_#&D?Xsm5@m>*>aDKU4Al5URYw2mc<6 zG*_UJwhePoB<^j@z!PBdD?$&^-8W*@f1s*r;_o$vR~8LL<*`jZqoS=PUjcI+UPV)@ z*3=coUaTcUGKuL@VJW{u$*&8!kQUc*E_t7%xNVd6?*n7C3@n7C3H zCa%;laiuU!Tq%N2$@g$MVBt4;4(eDT9?7_4Z6$^uhC^;cx||9jfs4t zE-S<9jNUzIHCwVu)@_-sGo`v-fQYYCq%o?4a=gOe50X_L)}g>o!bs%a&Cts7LtKdV zyoC$#Y)80o+`?^K*uE>z8PTstxe!VE9xf!4dLI|k+1<`%!B$+f1^XDkb}O3=JAT<- z%7wGP@8Uv=xes$8#SL*OVISu;G`NO?`6*oy8>e+09nA05bw7Esb-nUnem~dZ0a)d# z^RTnruKDeQVxWHeFt;my`$=xE@Y{3TUhTJ!a{C6qeT>^{{Fa>j;aa~XrY^iu;*A4D zxoD}TDQ7Cmc!7j^;zyryZ#-%5-2-@yG-KIDQjq0nzJV)|s_r^$9&T{*3?-+Z_zk^y zlT}-#+7SwG;5dQ*`12>lA8%S8{A)GHiP|iv>rWVb>IaNj>IWNdsKt}GSc`xJv*A2q zoxxO^bXX3J;c9j^+5OG9zs=;U;aG_eOnVI&wMoB~o z5P=`^8^4DuHff0y^sI&yd;Z+&6szS5zB%4mOVfiIK3piFx&&e${)0dJ(@%Wn zD=(kqCS21M7w&ZC50;E(Sb|XDHoo*C!2!j_h!?#njICBWg#FS= zR7`*e+rp%65I_Sn1bU2xZfXUj?6_fmU%Lt|bov+?D2$ zoy{=fykx>f#C}!8uK-y{bmuF+Qi1|LS#^0eUmZ?rsf2!0YzN=Ou1;Rs)z5y@UA2hj zs;h_#$%fQb`XS=eT>LMlGozU|ME#nzjDxYT9jvk-~ZX#7MR$c|*6^|f*L>#)A<~J_F9-@}7bZxPYTwM6yVcP|V@_v$Q+Qs(VE5P@k z`nU{$LGh1&R`|Z_RpR>(-utTwS-x1|`yYJy-~PydICJh#{^nm)bbso}C)91B`{RBq ziv7ip!X(6VTZez~`G4`)<7dDBAOEOP>?U-F+t<;3>RXEL_x}v@;$3~V>gwfyy{V`0 zzIsp5Y3hXepBT3PP^*==doLxDSIjX*yb32ap`mQF2~Oeqcze_w{HmTo82o;rHPTiE z1#ApHA-zD(hy2ML^Hu?N{GoxO^}*u7JVoO*iu>EP6oVpHobg+fx#C{GMWHKB`>i^3 z%5PDVij#gjr7yhL8uq*g=PjdldAw0=2v1yg2-AaKtA_AoJ~A&Ofz;&??DROJs8db1 zAxu~lFXp~UmUFEd#S6B7L=KkXdB4@Z#fyHc-HFfnEzXwWS--{MQat0gI9+r~9yD)` zm(Tkxju(TNF$4KuR`aLxp^nwyZhWXxy(u^Fn=%$B3$Twt`vImDvz`G6@Sd5gQQXI^ zZEm$WkcqDf%t4s*TjoF(zeSJ-13TST}qt(=t zhxM~~%m!z5r7%7Za>ys~I8c;R;=HcV-G;8H5RZcy(ml`X3Sw?(w@Vt`h7i*5lwkhB zuWKF^46O|vf&viX@DCg##q=Gr0*6`ikf4NC38?i1nU?mYP|R_WU@s}IY%`W{%KWa= zyspa4Xl+rxO}~{hnPzp?$jh}%?6z9IvufG14*2=aDZv2^TMRd+7gcBGsqdz1gd z3Z>GNbv-?|tquQb9SLzSzWG*w1)@Ua-?2oS+Xp$#whae zXRF1^n$@c91xDSpB9EH3T1Xx%Vp+zTFH!LQlvfydJHH|V-eveCN7S8mcR@jlCwPw6 z5u}Ha$v253EFoa9Y8O@Q0HrTx6#`=7SKdj!v6>&Nqu=`l3<_^g%qY8zBkE+ig7nOP z-Q3UW(Nt1B&Q2d6O+?jWqPW;IpNs_mwCS%%4lgAsf^>lS@lp;`k~*-bD&6oF&dSkNi%t%}w3DH2M+a3+dpo9pCV zVzkxs;sRwX`xH;t%05S#POo~RRtCob;mJwGV$!B!`p6oQ9g3TvqT2M4HKPJ=ec5#t z(?`~j3S9fCSbcnuKAuw_(X%vY)|ZMGt14DZgRD0d&u=QG!9ekIRk0d;h6XQcAEFdh z8XQvPfvDzbI#o=ABZ}|aR7`{WDZaNVrosFas?U>ZkY(lvO9n zS;{3nn6VN2&5EotEr_kyZ+vT0_22l`Db1{aJ>5hY$G-iyACS86?he|4GHSF`r;s*qh!_0XP=+)eFF`poI6;=sj!6_uhn ztF9>XGkz-`;JW$nN^T$Z(yO>V=eIa-i%OkmeFSwH4_vc<|V*Yhowj@kcUJ&%XRPx6|$_$NLucWozX zC*IV3UzNr(70Z?(9RKu^Z-^3uRwux2<085T>6;tIQ3zGD0S&(VF|IIfq{C)-V5HQe=&e59i;9l%6S?AL38v1EZeul6AP_Pxn^N3LH)q+F;6a?mOXX zr3F|EGmjkZeDrYmK~|tAA7TC3q?x(p2EQ2@m`xjo{}jxWQJ?IMhJ&Z{%&bv^gYOWY zC?4;v44g_}d^ZjDO+$8ZpXgc#E_G%-r9L!YMs_a(Xpm$dvW<&FT{!yJbn~Yyd zIe`Y}0WE`>6ACeSjQ%LbK>bpBRQjdP3l}rya1W^g^S6W5+;i5>(%}DAKLtd9XAKQL zSM^-Ly4XV%;rc>v)EoScKNAU$*q#}enL=kt8N~d*Fz;A;m=Q0H)(o|#zNha&H6g!h1QPri6t=)j^`_gd)x3buzj|}@h*=H*QDQ1h56$n5ZpF+hbbk7 z(!PIhqDd3W0A{R-WzH-Uy6ctMkA`_+wFpLy5*aiJds>E|@KxM}2EpH$4`xzm;Y0BD zctp64a<6%cF13)nC7R!aHNGDmguN5&R>BBt$9iltSY|7lG6L(0pft49MfzrL4E06) zCw@&d549LRY2ugt>*=dgbO!~j1Dz{Hg&ajv0K=N0=~9TaGWcE1;+7+u{H8~iTrD&Y z(mYSDHDX;-2Qe7{645Koge?(gwo{Eaw&P1ut`!En%)h>peRbq<>J`)ft+6Lq&2WmE zJ)*5hIj)Lf*Km?lAz_zHj-fUU^DfNl1;E|pjJ3%o*dW?dOMX2TukVZ3cg5>1@%q?3 z@#d3$v%DVv$JaUq79-SV>2@bAzW^DUl}tyDG+lQ^TBc8(;z1>V(e!IR>DScp_^$Pf zBl?&{j=Q9$a#V!QI|&Y(vMTu7CS%UxIQ${GWsMK<_Y5wX-y5e?_!%I7yf^r~&#zAb zlu9qdgw}?iM=pv{l$5JQ{fjD`684#NksJ}`n1u)CJTI(7KJXs0hBHPqNy8~|VdistJ z12)tXDskYNdC%2fJ_yWc7_5y9M6aQO;0ES3VNwI+P}Rsx$Y}>N0RWLx;#)ON8A-+X zAPh%+XE;4e$`NtNnYwF1KWC%1L6+o4Pt_SQN?jjo4jzuJ^6OD^Ow~eG zBeetB_!)Koa=Zo15dJ|I%q)~X=7;S?Vso&a-$a1M<{f)}e;j)NaGbEw)Zh!%Gq}x2 zLk2Ic<3pPwR5+!YalzLiyEqF%C^MYQ1UkE*1+B;h%LxDm;z`iOfFf}g((hMNUWNbLQp)8h;!AVDg>ps)?jf|#O{Q_g+wk1*U;E> zu85J$gPTbP*QG(=Ow-N;)2oWu?t^7jYuiN$2Sf9cUR1^sUBdKm zihq+*)R;G+&J?G?h}%ykJ*tNcg)_hsLQkh+g2vPV6O6i!(*XEK9i?0B+$woDEm2GA zPf>Pp7V$nA&%tCK&-VQ22vgHWV*9+#i^uug;HQm3DX7b z^}&}b0@k<0%%#E&zT)LFBMuv%mUvhi$*5t%l1_yNp*)o6RESbfqbH$@8illqoD`1L z67ufmi;0^~MTG;sgj91d*2z-R1irG@+O#v`g(I8)Gk&d;koMY%s%o2m_7f4lK=)WE zT97PnjW`Wd+kT*QIFs8VVp1skqwuVvFE7jJPx1l0^jxiFFe z1}6L0uGa;kQNlR%$muWxYaI-`veUxSb&cyscE*Y^hTFUdW88i0yK5YT!7g|L0FF2W|j#K_w7Km^*_=fq;9vENbJpjwt;pD5s+sW zJu+x;5eu1$V+Wwh_16=i(0kt5-)`0<+R^so;(Q!9!64aVm@G`QcHv)rG!q8GORz9k zG6W{IL)(ZV5C|}7{ATLXf`Hu>U)7;t_O1g1{<~b`gv#)0K=P0WGN=J|wW~vAU~>&X zv)yJzA23Rx0`7G2V?M4PVOPX9@bZkcoyt)`q~8eDXj{qeXcd&0VsU#L`wW&e(ULj+ zL0G=7aR5PV*fOcv$!oLI^VvaL(KPb)a&~%}9p%`o&5r-H*?A_bXnW^NPtUT3zpUxe zDP5+#?mQlr-_h4OW|x^BI~s^>ivs253DQg$GIIjETJ1}k9Y=NIbUTj!1}3ciPbnaB ziSy8O)%3?!7`u5n0I?y3<1*yT@*Sk~z`_;$kbt*A6%8AgFfi@4#IkAaJ+ z!x}U~)cjG?=C2dyu^)P4^JnLokweWMk9NgX|4BMww8G?T2?6|K-9gH7$IeJ%0I}W8 z?WJ;y7{F@-q=m9UFLR^nBOP_m5z`~n?k2;ob!Bu@#yDewV6O%qBXkVw)u^$Gp0<|t zY~=HW9Zj`dG{rnV!rAn)g}qnB21d>@4KBOUBxL3QD>aM0A$Trxn4HjG4?Z&f;6(Z0 zp0Nk9`dA~dbdJ)X4XN;q2_DC!M8e{>D3KBid>){&;o=6W8|&brt{7WAK$=iXXfg=f z-$9B}Bktt_*F!f9H1>f(T$3x@jZg+jEObND<#+-)s)L}CVT~Q|U>zFiAzJfw#|X8G%y5h_LjtZY8mTY>{^d|Njcyzxri2kw2KN3YjF^;KnFPdU zi~z(DBch_1FhUO;BgzMk5qjVlksb&mC{^E5k%TdiXfozjt4fC-lEWke`=xFJ0yW?g7kse(sB9yvfMg~$!QafAuZ_EMrA2a)4d918y zRrJ?%EO&yrN+F1fm}<(Xl&YUkWTbY~54FhlzT;$D~dd)yV5vp8TF~_1n4=~*Ev&pQ(&)Afn;Uw3Qop!v=xU1Y!TcHSi?71Mlq=X& zWBy`844!ebPQ3x{oqo2}bAJlTl&?yA{%TU*(Geq9rK>9p3{4t}q_&o0T9>!!-6^Y; z2iY_C|DPKeuM=Yi?T>xxH^$0jyI^Yz0o(){U7MWUQuwvvI*8w;S~oqroQX?Sw}vj* z63uG3QaUc`CVM5qm2U&<01SzMbzw*FmDGP4D84bi$11{g+-gCe+XLKcd6(PoDpmU7 z^^|@LjR%ag8Ca%m6GEb4$Xbdz{7CviRMa(neC{BjdfXB}XUo55nlf8xfAF<&v*k<^ z@k0NI>iK$nBCxM23c!cQ?RIOBaoCiwppFCDht7(=77J}zMehN@8DH-$i*T3D#_HVa zkSSH?n8Wf#K>&DjoRTgJ3G4UbqGn-xRi$a8wa+s;K2H z0S90K7$v%2)RirffOVgQ#UelPN1W`10Hcz9yJvm4&tx_FD)2#JNCTYprFonBbTEs3 zpOtRRZ;gv2IQCM(|hVaI4VDPNr>2(0hLB*t9$FLnp_5(?7K@9p4 zhs&*X-MBn(a*Q1Ofwi?gyeZDij&MVS<{-Q|-t7zr<6S>o8}DFG^2R8s<$?!5aJSos z$lYEawtbX}X@yrAGM>?L0ozY6=!!A?`DPe}T@m7tIS`*xVh*F$*vmgml$opFqT)aD z5*!XW<~z83F~?Z(=o^qCYHbt5SvAkdodNx`$)PnkW!t5wPpK)gWIwr5asHj4bL^xk zO(ECaed#_|cuPWC4Vq{Ks4OsB)PnsDen-MFKcr4PZ!wECTCrHQk~XY<_^#4(Vob^W zw{+e7x8^%B{IM>Ygm<^PnA!EnhFq3NxZYN5bTBAg%I|9qPZ<#P7~PGIG6%Rh_}vQT zOZ2E^D{;TxG#v%_p0pATgoC}Tjye!@Iy9h!8`WJW%xA4_)75aFpcTt~(h(6dXY?$k zx)gd_SD;JD@fUJ~>GL_ZJLMI6l<=2=gzEwo3FZC>RwdQ$Z(;*-#c`$+S-r#aZ^Htu zR3`KbQ<+e!jhMiJQe~3lcC2ufX*O7Ms7%)URw`2rERIv;+;+Bdu-gP_3SNy;Ii;yI zeH#dGi!L{@=`{Bho6gX8;nUOBbK#&2QKp$0H+=+PJR_taP@MUYW+Y}P8q}Pj$UK)Q z@pC!mwJB>X?#racMHg30tF;mi7#7l|wGu+BXXJ#Cc;^!@2z_x+8X7Y{c=*6%y1=#o zY%3fK`aul-ocSV@#e85Eu-t}fre16=EgI2Kv_cBHpfhyjL@AX8XVt2}k+>M^fQzn( zkSnBIs{DCi5xSEh{1W~g*=!&s=A4icUzo8E<|_I0bRxhARr3W4gO*DN^B14FNK<-} z%g*JxNgx#G+Yk>lMR(}z@sWE)OB+LjO6cI@GaH0q)LUZu#ukU?YIrax5lkaC`V$)a zjF!9=v<01wF?}NOP4N(19R9xXA3;m;FGgfiE!{;d-0+qJr4i1L4~i`xk@*1xdyy`C zGMXcyF-$SlWSf9%Mrc5{B($Yyo8Y_=HuPN?WaQ=(qhY}-Exy90pAb8M4M#} z;x{idkCUQjEyRWTB-R2*Op+KmUaH=jb#Z@lG}^4-0s>QFQO$IEh>+JNPl}n$05C$g zb5Z2`Gjyq>7;|f(k)~%!`9<}D-PwEGCdJ3!Ln!Zv&$zV^N_#Krz8v-o-Hdi6T{h{y z3zXB=;#fH!-c31|J!9qj6oEQZaM`z-+3r14uu7eH#%h;3aS*1U6BAMsbz&S}5fF2w z5|8&L0$|>wE$Q}@$4qhuzM2M^vApb&mE0|QY$JDjJPwk(ePM6CPf|dI)Jn={8qp9l ziN&#k$eG>}XXZr(DNu}4h!ODHYi)tQbMy2tbHROKM*H5Jrk7+)v zp&1E2+#8`ZT8cL8V31$Q1Jwi^wmBT+hjhp4Vz(qDsg3yOD?&QkbAI@+E%o&SoNpjy zieqcW+WXuqY|q=_v)0G0T6>MXvc!0?R{-+iC~X-Xj@HN~G&*T1rHWV^9qKo@p?y_0 zI_W{05Qo--j6Ui7tb@=+X3XV>x7n!LWQ4S3BcwgwH$P#nJ}E5^%M5rm@1su(+Hw_I zZ^SIJ}w<*vw)&u^2n+Oj13Cxm7)7RMt^%!RG`uOq&4K zZp=8hH(V|49}E_OTIVfN+P|~m-+4t}0M4isWncA;N&m*Ae*;X1FoGS!40pST#eCQi%k`~AQ06yA|gJn>nsgHJ0sF6$Nd>Q`}~_{>=8#q%m% zE$;utT3s0Ubn%###5357t?Mlpz2f1qdXMW@@#f;>FV)(+%-g-qZ=+;R4}RJE%jl=W zf#44b^kUEERcZHq$zjI(7Ld3SwFNQ{ z!C0dj9JQx`v5&JcJrD=riUQ2U@FXr=S~b`P=iburG}!>9ciK*y zX;KPlr_bhZSxy=COK!fleRbGM-4l9PXIhb^l3uc8r`C^F><31qW&N}Y)&oK+&En7y z{Une&IILB*@Y;r`d% z#7HMplAnm}~>JzB-8qnoF!V0`YCVp!K)U} zvoJToj|mp_13Uo&DVn-_gSBDfzf3b-8=vrat0rjB9t}P&Uvxx8F)I}(vq)*NoM3zZ zSF@g(Qac$N{sf?La7}S;V*>`=i|%xtO;kMn6Q8AMXITV`Lq+lGWjt6z+nA2ofh0xn zJRRD?@9C5ds5-BOTGA}0>VUR8W4a2JGQ5+>!K3Y2<8^n>a802{x7A zK}p;wd(7S-YqE05*?B;5qpSfTZB(Q;e1+pI%8iQrxJ`4RCvh&w>Swc4H$=(pVQFun z0l-lv7|H||60UhJFc1bih|TZihQ^aOrmf2NCH`oei;b1?X) zX4&T2McNpA+Vm!lhTAI9nm|dvL|@>bqISGdrt`HWT6^Fvoh~WA7A);oUZsjVmv7ov zt9;W;h*DPL^liW}epV$O+#iqlU_l2yfYMtJFW!YBznrZE`(S<6bJoUcI+c z1FC;&WNTNHHk12Rx%aSHIjX#9=->A&;g&ZkFe=EVx}K#k#S)36Uj;oMXNv2aJk zeJRE$!}+E7qJvMO#b2U}jvy-c@s!vyM`_8Ek+AkwLKgByyi=O%>x3+I3=!hcaB$3l zi{RyBvTq)4H?o@*&zmiFuw4lt%o2e6$l;ZbjCyhi@}&0=VK;W*?tE0S31ElNSOU_% zLkKQ1MP(glG}FcV)=3775kj2ZF0S`+T@X~m>~JwZgle`p9PoRQe)aj{K!F$v&9mN2 zW2SS?52Y)2fV-qBp&hu{Lki9{t)E9^ckQsogS)M34P^>JpkdHoXAoF;3V5$mw!7(F z?76PGrWoVwd*!#XYB=o(ybE|?yYj*g@C9>O;3JcFD1ZeAueD7_!4}64s~O`6C-srZ z+D9h!5rVI*uRSbh8y0!}#M=e|)3(8-tI(DFR<=#V0mq_MZDbaeEFk~d^3m~Iaeu+Z&g)4Pg z4lBAW!bZ642}A2@xa!8{u|Rf0=t921Ym2z^2r_pw4P6KyIipj<^R}<+y-Q9M`0vqTw*O0Dnv4y2{68!&~&>?NO#$ zu{xOLv4Cud<614pbwxR@{pGlZ<+vt|WQ00!G|+VkzhTbWJxE7bq(Z6&#pAy!+x&Ok z&K5ewl4$EI-p)28`g}9I4lAHDc5;@Dc5XACZ1a)t)xb#zGvTy8-;Ia?QL=`}TEGOTZj+^a!fmrz_3ypB&ZTRW1iaQ7%LR^ZeclMid zw$&!rICJqiBd$bBi;$a_L~;W{=sv4RJ^Bf!MP)=i|D#h<kB^|_MMMHuivlbA2YD8%dwZx?+11uqK>0_0TC#@0a zY|qkLcf;oOo}MYRb!wdxn<+I&ZInJ;a=Sh*9~&E-~> z$w(pcb}l>OS{pm_=#z4;t0Ra#eWvz#-)%E#JE0pA+uNYV>Oa7;O|aM_g5qA|$SG>F z0|N-D|H=!W!|bt;!X7<DX^SsY*2J9|N&5y}C*;w}cNcEgMUtM?wK zsl9SZ?cj@gKALog1uGD|gRl>Kiv|ip=(9br3)|H%rjcJbt#;6l^a8MzsHgf7j+dtG z+qiIu^*SpMT@%xE2$9IYL_N0LxI`G6(_${-sga|d>RO{!vkz;8ECrJKC6%MZuG@(& zaz)?s-xvEnWRx=%067?hCd&Y{Vrw57x}aodz8J~F-u+mbJ64jNXhDhCWp81INinKXbN_gJ&Oo2dPe{; z6m|T5>t-5?2KTU)Jnn-_CkvzUvE5UgY&$cnYurPv2ipESTWXQQx>>%&_)y}%$8_vT z=2l;K8Zho+dE}JbNGz6sxX5ff2}32k@KrNcXhH7*Dy(@GpxE&{AIX#`mRp5#ldGe&^5o&rVzTrw3trc@J{587QZTRdi{ z`CAcL^;~iRh(^dK;ij*Lq?hT_r3$0(mb#-pnj~GcU7!w$w|(gcEO@s*I z(0jqzZ1UK2pPP|1bbcI9~rq!t=6B{H*>FqZ;|Qa+$*Ri3@nN7)KgV$rV%%TBV^f zqKI9Ep1=^$<88o(Kdg9DaJBJi$| z_j|yoDdJoE$47J8CDSO{e!&c$hDVTWMl{7W$t1b?2>;XWKf;6Ye06oVnjXtQft}Ib z-U4BF+#;tD6tuT5wzrqoM!{t!{-hb6(xlXD8e+HGUS0d~`CbI(90lrg>4O71W)Yo> zmJ6q=RCovjPsZfJ1|-=*$7Jdc#~y$qBOcr=12VqAPdayn{XB-4p7U1u4T_k;#N7&a zpc{8rVq%(_#p_uXhVTzA`>{88=`k4>~WtfG7 zuu2EhqzMPuBgoURC+ad%hwp3hAsE{Ms)M!}4cu?Jcqnd+6+e)Qi7v0zKAVc0W5o}q z;?`L4!>Je)OpSwyRXS_1~)|D;)oIAd=_ zi)A^msr3(WYB=NZQ;$m%2z!bV&dqZ%;eO!HmAs1l^p^=(IcBAT7A0jYoZ5!HiB|2GNkvuTb$%UHvA->E!*(pVP z&|h=$yy}a*!Gf}8i!YA7$&l@f*pd1o@6iWZ>S)Gk)?m!WUzu+RbMYwK=zJNVPQC`9 zYELGN3a^Ll*_t$Z^4|D{J&evcMmj;PCwhbpm~E+AX<`C2c!Aw#g2vQFWFi_(9!G;Y ztAThMnz+p`K;;q;>Q8Lqm6R||TGX*vYipc1_btPU@Na-0Ea0u?clwgRhuwp57s1y6 zJcW(GF>DV#rVY3-@El&y*J(p82U*C{#SYpztxM+Ne3DKE@A~R&?pLz9fH(uj%UkUZ#My^(cBMP*O4-FQesK z7=Z1*vlC@3n#azil@d5L*5tNOxhkqq zL^6;e1i~qUi!hqLnK#IOfj7)LhrV9VS%&SqhC~^&AsJa?GtD1}^cNVjw2#z>k`Z~`>Z2^2D<#r&*SpX+2 z$Z|W_5BphW4`?ZS07pSFHxn!pG0V)W{bcA2+ZY_4cTo9R|qglodk_kSE{^437ITKPg0UjVorc8lT&}o@wAfSD^I=SI%x*SVjH^?sU ztIDA*FE90Z3kZ=p>*evNHO3}O^Y$A-ec&SBj}Cl-Y1wI8{g7#Tdh!ISNN_#0Hto$%^uG#I&bacTY) z7i~T~H*gNqu?;*%R-Pl8!qONs0dZ2(Qlzp__ zF^Pw0{mN7AIAuFoM|N_hy@@iWw9|UX?SjbJ!Zul^_JKQg9U3j(*bG!O<;`lywk1M8 zHpOR`f`2nm75oToHD>2OB>dJvrH1OZH9ui7X=m9_Djom^&!VABu#t6U7(#nE5wfBD zz%3CVn+6Yvvl!|*{U@H&hv(>%V2|9M-H4yvDq~4kJO`#e?89?1=Q;kfJ$tOa;!egnHh=zPPyBGa;o3njofKH|lBZ3bP0NjRRT# z^<2}B0CB4Yg~51)Qm5DrsZ(GXa1NY%yMho;HRj7b7jy2k6YEwl4+;Im-ug?}1mZwU zHo!ygRoDAsZz|Gkpy(gW^bvEwWl~h8$@e1es$!<6+^~@`J(g=pFDU6TxFJdxBslD( zVs$Wnh0wqBC(N}|`--`L(r-Q_^3g!~mY9*@Ax#?NtToNINY<};PCReR0lmtv3EV<0 z`;e}jU7fz5tWJy=a%1R@Ou^Wn<`Gb{;WMp@bj9ou(&jKrO{&NB)?k~WlJuC3z}$xX zoqd!C5R2gn!b&^?y?HJ1UHceFBrOEgiFPn&7;4r8FGgS!Ga;>i!f>Z6C$)|kS4T-c zLtaeho@x+F+qgUuU<gZTv8l;saJJ`8-$n`Wzn={R`m$|I%!d*w%=MR6oQNT2h2c+HbAS8ElIGX zGn&;o{YLc*`H*9AO=}=n5ajBWv-9YfCpFF4#b2w<8B}1Fe_LN|njN*88pP&9=E4;!day z_F1$ehPK6brhyCQY#ZtwJbRzetu5X-K#p=@L(bsB$0+sw#$Jnex+kJtoJOWR^tJOR zQMTj0jCK*$iy!(&pQUI}7O`akONh^?zPnUlqiwVN?S-l=wAZrJIG*35o~&`8XY-g8 z6j{yfLaeP_(AwZjKT>u}Jv}5xQE1Ce_oybfLp5}jctr9!6~S)7R&b%cmfwQUvMsOd zIbj?}y4Xvq(P1X06b@{O_w-62*EIiHq7s`mB6W#e4HJq@Y8tx};w@36X+CWVaq)dZ z+Y@X`zMUUtnBdXi%fcYx&Mmc2u!*>gNu3bM;&)TMRo5E=C;@UE%x?$Z98ral1vC-& zT+!xx2*2WT`-q@!+pETp_sM|P%n5(uR$8!)eC41`wR}p=72}AhD=Zu+$boY03%u+c zo%!+4zMeGqlEenDdTCRFc zmm@gzDodKp;^9jX8%hrIQ71ND949syhlovEp_mWoRg@+5Z4`;k*_?dwRH%sUbi)Up zs0~iJnRyD6IE?SIlgTUNyb=Zpt27K8BdFK6ZAZI`X6|L3g#UT`4 zTanC{jCuP2-1Kf2e~`-Dm6{2j>@wo-O-Wg87bjte=2UNMAtgdpn}b|NG{cSAf5{t_ zaQN&G8)+L;G3mx5pi0Ml#(a8Eb`x8aUMzv6sXD}}HB!N*bv&t`Lz&t6xgV3#m~#Dj zv57ZF1vc%tYuhB)Iq?V=oi_XJYmslGiJ3OKSF;7SArm5=Sce-QWGA%*)`TJSmJb`I zcU|VqJc>ESpnCURpNL>NY!{Z z%KeuA`la?;D((U9DIW5iZJ|v^EaU>spMT{%h`S@|Ww|z8VkoT-{#aXCQIfws`!4@o zJD)%+jXLQCoSCK7Bsak~x!bbZYl%e!RW{2#ltzBCq0qEjQukBAG}4;#Yw%yTJ~V0s z!gNWiP7am3*d(az3(T{*O&T$f0N)rPbs5@yQ@SN#%j1;*l_QQ+>&8ZJ0{GEKO}(#x&VfHe+?4EdSQR*mS$Fvf@30ntjXq$pJtZ;jq^#{$e;d6rNJ{L44jvSB3sC^V(w1L)c!{7w9d zTdHr+$Y{&XapmqN?r!1Au|c)<_uD9m>+eVGg#%Q34~2wZl_w7~6}9Dez5!^<4b}X( zS%fS2BofWcxdXlHL2X6-LbkqQK7rnYIaYbZ`pQ*c@Q3h72f&;uO&8iFI45EhR|3<~HjW8Q7fl*+-x_!ou8K=Dcf9PO-QT#BuYJMz+IRZU z?l0%n+02)4wQ0Z&u`zdm3^;AtLp~Tam=VVzSwzgkyjX%&Pf~fs+XxgorwHqVKl{5T zhkSyM2=|zs7)|U!2&$V}Fl))>NN&ma*-#NxTVzVVryA< za6Z2-*#>?lZ{&&kpWH0-M9UUIVj}Aj?C4&K9n*3HY1Tm}C{oPB9rGtXP_!&e1eY*s zXpR%W0(P8r?m=qtvD(xx@GDL|I3c5kiK1+Q35B03Ft5ft#d;&}tkB~Kg~aTn$fcX= zoRj8P^H7B?S)?3A3nkxl4R`aDEfF!?k@X(<~tJ(?h9N6fY)S(UT~PnHs1VO%_a37TcylNmdh zAK@zb_m`A*&*hDFqJVMvXMj?`iDPn(7+l{h1_?5AvnMGXW0EmKs0->|Ml>=NO4Fg~ zzzxTx>xo*lbS09of+R5I3)VD+b}1`y&evrnW{uQ0@o04#a?^Ii zE2#`6iNn5(c1;+M*JNS*FMy%Js*-w9H#C}C7#e?x?SLO>H@daR+8~q1R?kp58rq7* zFXx5uCAeEsp&fb833cXj@%p(~s;+s-dOdHn17Aw)^QsOfNQii6jB&OZlyk-n_ z0w@A8ns2dE$u>z@vSk;?RubXVv&3<{@Ib9wpQ5X zji%NL<-G@lO-%y!y(VF7>qa*%73$HJ|EGRaON8h(W+uAjLdL+>2uJglExm>H+9S`?yEb9J1XBV26~Mol=1B@ z>#rTTsg#;98?YXw7mpL4l-+rMtN`bug`tsl1Q zUdzxXmL))zgk`X*;~(;1Cdyl$S$=Er*2`Kif3Vsnv5AN0l@Qzs!U%9CA~9gVGl*cY zNaRFG446R)0vj+yfD8&a!5Bdl5JXJ;GA0;e;C;S(pHo%0)siJ66K4X#eXCBLpZn~y zf1Q2yS)EMu(gj(XnBcn4j9N#qr&u_$BJCoeuTC~=4_Tr*0!pL!n<}&z+>wL_YYDj$ zK2;^aACh82!&D1m9!U0k94!R{u+)~y0PM-A+m>7!fIXRMx8%|QjM8&nV{${|CY+qO z&_3bk`WqY$Fy)u^+7M1ODmJIu`q9x%hUTq$^H`F53$&5oU#tavu_k)s)felMzF41n z9sfetDH5{rLayoyg9}yjZ z5bUIzHUReQ6ofG;UZ}3-aWf|=J|0Y*vbrZ!Uwp7!{Qgx`RoN_V z;w>nyH){NTSlK3beRhX1i)w1B>!qXw)m1QR$opV@wv~rF*!YObD^RW3{b+;JZ)x3V z@hVB}q}~+7D~>|LGgvFE%V2(sf>%RZD!#q}Hk|dRi=F7craqey^MmQwHaf+Kn z(NM5fjD)f`!`8$*`Hllz(5>V?7{Lpts-&t zdU}X8STw8nse%dAcBTwgYQCgE}<9q}#4eDN`3URR}rF`pk&YMnV-_^WnmAh2EpPz-zQ1RtJlZ$v0a z=P99Jhv6d>;>e+Bs<=V|>g?CZD?F$)@-GcEnm5;Ch3fEDzzXJyX-L_0jHduH87}iA z+<8X*FLN33msoX7tj_#pav`~1(4XpRwxLPPcx^RY5BBo)CbfSC`x91WbC zs?oeNbj@|RDWGf;g!m5nQ5Xy97x&nX^-b=9 z6K`_E+R*Kdn~PR$r9p(htN5YwTd35yrW9k_Xrx+ga^oyzo80Oj&23b3VEo2XdyrFx z_t!VM$#jixa%bnsM~;et5)rF?acZM0?sAj5#VP1k$z0MvbOBTvce(AHbG6HD9oVXM z3z)a|ci2E-E@vidP%Xc<$&Q{ZDJhCtQQlF3Epu#e99Cv<(FVsOGb03-+!kfPV0>$6 zYuhw%pN*^L+1#cFl5#z0cvh2iw*apo>0Tr#!&e-S_&YJv`B=PhVn+&U zAgSLjF;-*!s=RsV32C>vgF+aZr@b^t_SeJ#*D7`AX!ez8L|#Bha#pkZN9%c%^~ukW z@dX~dg-GjYf&B}iG^^M)->VLXx~>Sv=vW8?hLAQ|@K!>&PtxpiHVdXWe zhJhY|ovIB(b=^`>v+f}$G(;b8#>R!uCVz4RSV_|3hOZ2|<9?$NV*UvjPKn>Da3Da@ zepJV#o16$8z>?7KG-}|ak~vPJo@@|M8M7=I<_lX6uvm5=UdDeyoNKVCl`f-=!V8ss zvi^lPIglPq#kgIYKQ?QTB8bQWq5*k!G<)8U%{nKWj2(t_p|G4wX{!;~F}FPnqWCI$ zWx=_$RxzI#Y=o%LW*>vKQakvRhjRTsrW(Gxm|{|h(?Cb$uM{RF4%VlLHye-MxX@Z% zF8Mez!+d<&E1G}q@B-|=$~(@U=tCqcD50WUnm@>jBbk;G*lcHLgu~jG;70H5e{2(Eq zbs|B-4$4R(JkHsI&O6Z8MLR_H(77PBe?{e|P_EQUnRSMiop{fYY6q>}*K? zXc;*`{7^|VL3%0#D(dA}sxe82EWRF+q$D%Oir9`1ri><)lopRBeW3+l=7xYKH9-r4 z(SvmUKfO~vc%1QPxR|mt5rXsi`S>;{zWHFvmbsGAhm1%ZCSZ5SbhM=d7~Xl%X~eB2 zXwsU|(FT&3#>HQ5NPAS$M@AC9RW0)z->M$%pW7qTQDLZ^&s06y+3-{5m^f=adZ2-A zou1s^Ad(BedmEVC`Q_SBg6K_gBboP@&%V6Ry!r;&Jp3j9iT=XtP< z$*DxE?8$1z^HnvY9>ki5YPvz}0u9>b6{G4}yq`EHpc&Ts2>mqosN&>p*SrCu3l#XW zV_;^L)&Wt81gV_{VPVloakRWGE+X?uyoj|f&}`a@zczv2U<)D^jAX}2Hs>y5WXSVR-7ZK zLQ$%;^Tpo=MD~?~tDc7TG^7+|piAbnroPbb0b5l(JW!$1(8maPZ zqkbk612<NC^YgPHroJ zw|WjDuh?}oI~JhBlAA)C`9b&YFpt&`ra8O3m#!cglARUzy!F9ZB*7I>$c4asmJJ9y z1Evj1{1|QPGM!3>V4LBbD%VMUQ|DAwH6$VPJ$cQbc2O=0OK;r{A1pvFwozl;QFY%x7l3*Bt z(CHb@dLFR~hU{$XuryFvDOh5IG3F~0)6iWaD3O=}LgsL{d?Fm&Mi(W&R1}AOK;i3< z@F&xNsByS5WKoWu%mzBobE_{tG4}oqsuCi$^aC4pNow_S%x!=fI z&RbR-h?q5Ahiyt3VhRX8PpG%Yz}d#|K!Y(nUW2&-+Ud)11#_lxnmENfv{nx~ux{nq zNx(k>^}YHs7wq>ak@mSG)Qa!aJCNV5Ur5EQego{cmCrTc?~>8Yp-=3a%X=dReXyHy z2K_q-jvBx}0{9Il2jdiAHPo)pZXro0#w)k$YycQTR&faa*sp!Gid}?rI&ueHEk=Uq&Dk|$r4SDl zDAh(!M<(_{Rk|eRLqi)H4{;Vz&$|fkdW0v{&0p1)cfRr3Kt6PuZx=BiWQ}QIm8OGk zZV>H{Pb3e;7o|->A7XBPKiW1q-1rQ3l~(bgT7s1&?N6&T_3C}}YD$&N2L<)9U;T=M z>?tOI!-1>NT>Oa-v@mcPzxF46t-!C?>?VPdE=B6)wQrxxc!=fnr5ZF@SY(7#Kre_Kx;I zd5I}4JJXTJS+KWis?d7lTwyxupR6sEeVoJuLvZK4PCPi1nZ*(+I4j=7T6_W#Vp?o@ zcG-sPF}-jb zk}MyCOa=ahr(jU=FZY&Tc@2_VRDL<6R7?=~s^IP;!O>1@ zKFkml2>3PtA@>(9uNkh6@gIo0jb?=FJn6U;2E z+@9Tq0AKbG6X64TyTTBn-!-RFc1NTJ=IGoI5u zKY(C0zZfc@BXZbTQbxs^Dr5OgJ z%ve}rl9NEz%9m+ME@0sZD-UQQIRn&N)A_FDJYQdl;wo`xwX{I0mYCjM>&7vkOFRvU z!hf9%AxOIe%qqNF9)nOvkB4avNT!w|b4sEOI2bxKj7(N1wEw z!jc)qH|RNj0zs zz5$iG1O;oU^UpSz@w>W1^GRVL>oP65-t&N)nI6pWV`jDT+>I?va__(&%i5xB_X7PMZFML0d!*G}uiwM1?gsrH!ak>8>~=P*4`H`swv@xhHB`-@EK!2xww zfi8q|H7cNeYgVCs;Wz4YwR79=kOS;dQ^w2Hqv`710#nA=ZI*cxJP$NL>mwC zv!a-~G&rS&hXj};+$;ey8b9L27M>(#BY)ID-7Kxn_k8IDqv3+f?$iwUvS0P^85vuk6dzCp6gab)-FeUaIRdZEejvV!akD9 z8Z#Dsq}(^5m)y>P&dr4-myK~tmBVFpVI_TF`dr%1*P%oXMS%-5@+-R+iHfRk#Jx9D z%R1plTBQ=0%3>B6DzLK1ZKzT+C=S*z2Ku3e3yCyjK`JWIO*0nhNlt%s{|Tm--X@9{ zjaLdBBP3ya>2*lTU+`kyM@6D9b~wOr?$PPyTqW=$q0FGpTtGhQB~Sbry0SOAqPrgU zHY~1lBqJZqD(~ou8J5gCu%!FKTrG58q%03--Al-RAx!0kqBxk=L31$~2D?GA7a>Ku z1t14M(;K+LNR5Ht9_&jF$i;DjjBD%-@5>2!qn3A1)TcmU9e)N_k0773gj28 z=v@G&PUfSpEG%wLJHIf0k*=G0QTIYUtBVT!cp*{y1dKrKIB-#Cun`;fw6%bZ1PdF` z>yTH7L-_*6bTgMAw(~W4+u){W$b)*SxRKfzf%p$P@x{chJIj;?5s7Mxt~U$o#M7YO zn_YVSNg=F zy0$QHRqGP%MUPe5=! z^HErcDwlzfMJN!RKaXj@+t$Lb%@tC~Gh?ne*}|00J6H7a-{)K@PT&xW#^54HI#A$Q zj`!|63IbdLa_6lJ`81v1qK7?=ZDf&*WJdL1&k+DGgT4UCJz-C1bhKPhqSm!9ZEF1} z%E~1oM>B{fqGZr7J7Bo7^SE)t75*!>CBA*c)fc3?z-)~w6`FJzsg-%JIJDSOVSe%e3?pI? zBvS?8EFPPaOnbV;nMi6ecm6zkk|Lw-{xaQN%qaI!2bm|y%mJC0*^;UH0+Mf=lT7zE zkbG;EtopWLnct@hg(DkhdKZ%A;VO$IuSG^D`QV)7shQp-B=4V-3^80o^8ID<65jTf zZ&SSC@)LSI!Q1Zg%|>`9Ju>lbrw{S@WO<^>QYe`rt|$4iImrz1a*~f$$r|EeD%`0d z&U%GckmU~F3$nRWG8Jwi`L;R9RCp!Hw^qr*lWkbmXBX$^@&$uH=X18)FcG-em*lI& zInD^ynpM>8ToWm36?5i}P`qGYAkb$+=8khz;<=&3IV$n<AOH1CjsAyd^tV_OBwyW&z@`Z|qTrF!N=(Fbl`!T^wP&j%#+vOVpUKyh*`{XlOUjqEGhn{=_iPX|zc9R< zr3#*3zEJi0@`Xk(k1y)XPV4@eDse?fKU1CAQoc~)%J`xZvsU6*kydvSBPL?2xU$z? z(FG?Rt}@8%DStcCi-zFqm(sgxcr3 zPz%Y_H6qeJPF|W_c06gehZQEv>DA@Bzbs!bW-@{NJgi07Gs$s^*M;`_A4Ei#@Vd-i zU#!v{HSXC9x&>vQe(DrLTq*B999ON<^fJxSX8kG7`QODMmRl_;T- zIrSX&#&lb8{{|*l-TnrWSi{eCG56*S@mb}*qGj- zV^_rH^bP^r;tjsYn<%`&%e?tk&S2mZ_6u3Q(ES`4`ty7#@N|jeo59YIji)8PD0!Ol zwaU|kFJYccie_m;`cPR$ug%-2QuzzGJ+IjDTOUP9KD*eX-_BPsVQ&e^!?>l z}sPjL!Nm;bdX3Cd?3zz+3C`T0^ z%-d3y=oa+NRA)8<<(eQxmnyJQR^x%Du{e5@va8eLMK$F&+91q)xVF2D%Ldk7KGw$7 zl0B7=$`HUJSx0#kOS{b8`iwY&fo75S7SQD{?0i4=_Rym4v_2nM)O}%_MT8l7eLkJP z5NXBwedR@of(Co{3mGJg1}3ysaABs=KzlhO&_H`RGtfYLIXBQids!W5puJoeXrR4t zR@Z1CFCdG0Bq+Sl#Hh>jO?KBKy4DYD9z_g-Ko|wUR-ZI?LQPfHQ{(*emyxJYVi&!M z3NAY!BMf`i@HFn<3bAbq(Kpu$sm2Ls<-Xd=IlV0CSq(DwkYdw4#YaiiNx?psoqF}& z^c%BJI0DQ9vVUV*s;lSid67lHd@#KsX!lQWrg@m1{W*ZQGOiES3&@rmmSR>3HnUEm_D${0*1 z1dB%NWhA@_7zPThajjjtrO>gAd=TLtR2>#7vqSp}*l|WE)V5)dBCP7Df5%#a9rjgZ zw>YVMAafRceGqD1zC$_&k@m}XI6nl~I4c5JuJl(y_bGazCHTD^~;GrkYlI6FZvr$1Z1sqtm@e(S1<iEx-tU;)y)!|t!Y2VHU$1`Sl&%?8JZj{bUc3%*l z)e_q`mQG9036G3UyMf9Lt4AyYJ(&Z=;?yQ0+f5lyEU>Hx4(5YCGXrv70R`9{9FUuu z9)-fdP><*E_<%p2&m;b4N?pq1UVq%cBR*(K<(`4!9)DcL;~szP^0?a{CwXK(lo#Jj zNtxY+`o%K3xLmK#60dp|os)8{C3KP2SF^XqmS(j6v#9`Q(%>{Gw-ihGqqcHWVL&*c zbtvOwuoDL-S$Cd|Mq;XPCsS=I45CA5{hqjHHWgI!^;ONQjF2T32di7{A8b&smg-M! zr{NsEpI>G24HUTeb^5S4e8_v3VT)ZDh&K2?ATze0cOj35{c#KEDL z2_&byw?2D7?-#Dm?$_@^?zh$Ny7k#!{X(7Y)i182_vjbO{t#~U`*|+6fx{*+2?)ZB zyqllt;4)d>Qc;zAq+I zH}9z~vwS?q9`Px#PJ>p^6W8Vk^YdzDqHSe})LQ+@OJ9abwaNFFT>fO)*+=* z*}0_FDs#1l+cQ_!d$!st!-$B2)Gg+@{qnU=45{)tPbaYP==$4Mb>9kcR;ah8&Qx#Hak!lZB2HNFj}GP0AciTLPUtBmFKI;%R=$zt25`8 zFLZNxd{GJ0S+(MK4MBP_ESogCb4W^?I2vLvZX)7=1Hr%yhvKOCC}#Nq*Hw`xqudge zWUS_`{CUvO1^oUTG*rLH#!qmSsD2;UFEsTrE}u95Lg@W&$yF;a!u`_MQ|H}s$`tl4 z7UhTjhs{tYoUF`eV;rolOp!=d<_k%!txTn|GTHg8R^~aplnbH9ONswoUTO;xL!?v3 z^Buu3A}lRU5vv>>qhSFw1-aE>g#pV{0GDpD%_^9DBa>{HA$>so~y22lQ*wzlUD$p|yie1h(GaSY$!x*Efp)puI;9;S}>`;V-gOUk$5r@$+ zbx#R8*Dw7#UwG(c)ZLA}u!4bEL(&2uY;HwxA!?!bQkAs$V>mj)Vn$SicBWhxCiy`!K)a#{AvS ziIw11#Ap^X+w^+pV)a^T^8+v_9bGW4E`Zp+OXpwA#DZgma_bwXixyXbRX7~CSjb`@ zEBTezJ1xED1Vq|Hc1({sK`q){JX^cppsif%E-B6=bmmoQbmVZY4)m0juuh;P~g zD6Caw%7*C|V1k*5ylA+PKswVX>)5Rt(nP7Y^Mrv@&Y61qVYEZ;ZzE^YfrFv>PzNaw zwYyy!=IQVdavHx!U=Sg`l6Mttr@~zP=|V2MW+%9OfwEoSyOnArA5#q+Maydkr=PsW zL!4*x_Ej^(3w2K7tKv3}5-p5A^iTb6&Wgy~;z7_$P(GPjb*#chuXnfov?c&H{V1w! z>fJr<=!&qn%wnL_PDbWBl)zjET8U(xKPWIL9lJUfO zj3k3icSN^GKbF1Ru-ZDLQs!AaY>Mtk(9zwCYD887T9U(7aIZTB9ebo;Eowc5k^8J! zofT|Gg4G~qvPl~WMuVp`cO$|0P}9R{b5AWy??^COc$*`^nqkvZ@0goDlspn_AN8+p zBZ=J(Dmx8592=sPtS!uwSvW*TMuL&W??5g+I7dX%ALUv&k?tcnm18i&qu59Yr7Td# z#hNAcG9N&fUt|;Mji`>YWjZHKA7iY3WG$q> zLo#?qAIXi%zmaP>(jn95HFjVtz!)wH9LVe*RZ#WdpV+Go1?y}R%$*kF|!J5BvKR%*ybImc>r)&ruADL5j3Ah z?ZZf**5YL6CZMB%s(l(kMeTRiY8SxjB!Xq~@#jkE$&HCGAf&vSt;@OrZ@^|AMRb z5e^OYp8}C)R_wJ~C*vUysbu^=WJi;5U)xlE;V)A>*tEzMMwSG!DeOWj#m|c6)u~Y( zfm|D|61MPXysyK;t74o=4;w?5@=n;~%_Pz}{_Z2h(>FZClTxR$m-*>nVnki%cRi%j zcqe##t+a?1Xo8thIKiT5tH7l@vTJ+IFp->R)md)F{y@sHdm$QHfn6qJsE8qwIf~Bm*b#JvAYyRk5n6Px z!FxKYb#NY)wae3({oq>aX*l9gF_*{)7XV*Vjyj|ehpbGw-%_}wt4vX=lp$a6YO<0_ zr5vfjsi{n*EUCe#NvTq^cPYxN-^IAy0=}M?T*{fI@c7GiRLwh0L5j;`Cw5Xz(Fmz> z*r}(|AyRLxQWfz9e;pl)YZPozI3WDU>b}l45?7Uuc<>bO+pPhHWTvWc_p;e$njDf& zxj~EH9cjFNS#N&LU_=fID$uss_*ysTo*>GXU zo=iK-q^U{mvNnuur#GOdSapyXl8O6-4#oq4px}~18qsqSZZs6GA*@vG+@#J74V}RD z=%ohOMPBAr$x7SiWXL;V`Zd{2brFmZZ22_%bd2@C0`c&iAMV-QR z8zrUzGm9ExmejHROFBL%_`_f833*_sXf^f3`Hn* z^UQ+DWU21FZ4C?#4Ue=(#}nTY?hVQxG1f(b#*(jfH zeG9R2JVePI{y0TyD6xw1Wkt@ipR^~P6v#=DG4y@lbLSHxI!PG?uQ>2#YAaS2kE^QE zs_ewz;>{kRMpS89R?3mQVBX_H)1$Ht zDa;|S+)b3jsN92$NhWUWqAW-;5Ska#dgci+z!Bl%p|<+p___Q`#aG$dDQJFl7DIhuh~cNnkB(&I>Boe_s+s~ zwIoVGXq5>%PUR%>`0d#|3F)Og6?gm=Wg@YA&rmvev(1fNpr%#I1kgo@umz2XBt()@ zT$_IcyTZoAnD;+ z5{(a%gvjbrcD9)wfpbG;-$09`*9hkc#a7~3LVd76v*BR_ zqdyv1R*ozyM`lompF`5>BSS@idWSA+k=QJk?39GRlTp(J6rxf-iFRMNW?G4d!%nn+Y!Lh&O7Y{byE0V05cRcqqOs8GZ`kqT+bI* zj3^VnuoaRSZd4O^Tm&)HoQoaKd3EOxsKI89*JhaT6p^f~>w&DxVziZ`DVwjlxholu z@Y+hQu5`I8?AF1|z8eXlmvR#95-{IcRy(`SM5&i1H%er8Xy5wEuZ*KxTObh^(3C_szL^NYpWv zd}U5M!X5ab$&xa@%8@6eL3L6yzlJp3p>VMq=l#Y@VfjWU_Zk(~0+FR5PZP&EvwILY zksD?jQ%D)Ihg{dQ-T9Ww111wFzAj>e<^U&lW)IV$KjO6uvax#bFhv-FqzROxibIi# z-dS6zC?QW{*Z@;AAbWpBdh4T9-SE@}B$vl-)z5G;cV`M(k6}DQ>XjHfrQFopnY|U1 z>5ZfGHE!q;TuacIwSML!Ho}+y49#E8;HMk_dO^&gYImZv%%=Hxm-ri_`6y$NBDlcB zg?s@OkBYx9$QRVUczP6UJ7}ZYhr-a+vwcVQbxelRZBnR~+W2R>M|pd>?P38d_Ll^A z;41*SI%;4ndqAYHgu!=W4?2EokiO}Qr^gU z(uS1C$N9odX-<4#kk~vLl_o6jsB(LWv%^akW70`!8F!6^tzNE60cL_VV)j;EFbZ77 z4`TBc$6SqAfUr$qmi(ZPb*G_+qEZ`1gT};<@{M_bRl{Sb!8~{@6s^{xuzDUm?vVTx z@L1jw;IY|v<4jao8YW;4Vgo4yn~~QFkK2;+D?C00ECL8}uM4ovb=Jrb8M&aG^oS_c zq(?*%p_m6zK(2^Fh;{*mgb;=(aVj;D1OerC5&4$sIwb8UbPhQiB^G*jTyq%ET-(wL zfzo5Ao!kMrg z%C7DK0U3J!brvr@xJse6eL`#nlN9$F)xnK8E%9@)*|sch4|&~?h8JK0%f&4K=x|(8 zFF?Tj6cRSH0I`v0|H2t2N#B|s%PBJp+4;XG3G_}h^3b84^=CAaAFR4@>#`EezR<|B zn;Y@I+yj_QN_AKBn@t1d>GVJ6jp^k7$QxT%^ja$J8Ei|NUpaU`@9XfoTI*+b0?x^oH4;@P-Gy z$!xR!sm@7)F3-+3uP)RL_C&0Tt$s~2FZ4hNlw3_mQv36Z8j0Q*hju;U7?=o#RaO<@ ztEy5$H#-GrjbWv|6N7(2P=NV$YafOpyF1uG zid|t#Wm3UdWsI3C9>P-$gqm4`Q|??$3Y`2JqELcz?PW-11!v*%;T~~1m%^Gxk8+boD*)J33;6*N&XNwvkRpYUPFs?Ci`lcD#88@aCMHS2 zWLJUrcc8x95L%@q=J=KIHjAm-Y(0Tx?xMQ=nVI6GOY-fpGR z9h|$H+gpv`-F=~YIm~1^S&I=?>O1i3>+lYyTpgC#M4i8vXTt;oKprl3v2#wfxTN>W zHb!;)^&qyahR&Z6I~T~|0Ts^1;}Q224L;f(+*Px54QsMz;pI7_r@&pE*GOPB&%qJM z*pDxH%~nWz^f4+j{9_c!O|eer`@W(wTglvo+3KHv$eg<63Q|JCkE#TPMm;aN36Wo6=7sII&5DPuH!nYtSA*>2Y|UX?*R~C;#6WahKoi7 zq1{;*m)8O;+(JW&KPR;xUtXO@+w4#&QoQD{*$E~QO;q;YaBCTE)OMt{M{(IRxs>n* zyAi!ecvGXf`4{li?6r#qOOp$awQ(Z^0&(@o?D2?DEoNwL&i5jm?%+uR@OCg!`xUcV zd_u8G-KQhqGf0Ln2Y8Lb6@V7TvOQP~w&@PzqTzA7v?wY&q*Z|zf>j~A8x9F{a&A5P zK0Dy~wzv=SW`q|~FGWsu=(FAx39cMO!0J)dqL4+EcV27w)f9w@&u<=bB{rsFUW#lW zw1h(I1(nKTiFtv&#@OR^F$H2V|KYKW!>WX%%enOd4CNgwIYo!Yh7|3|I@q~IEvr@5 z2AYi_zU|g?g3^aDYU-$Z8_v7R!QQD2Bl8$2ppDL%FwT7}K+TLTL``Df%qVq=Jerpp zJgwL$N2_h#qbssmMlm@%Ejm>fp0XmK;eWk^7aYk3DI#Z`;c5m5u zIq#woee=GLtxiB=$V?T-V9&lZg1on=hCj#Dvp3a=YE?s5ZOE$EYBc+kGu>+!e>n@Px=q!c*ZK0a=mVLBA&WhiSQ@=ENn5D*C=K#%a2Aw76$3J9 z>MW2}PC-11jsh{5HK60goc>{(y+I-LMuHSlfqugcIevB>7m)(HGDqK5Cx7H2=WO+| z=5>xsNCmreTZ6A_lvo`j#M`7V8O1~g&G*kq=CqYgi_5-WuVl)jUu!3zp1fKIRa?c^ zNQMz5MrPI|@5?r&cd`ulqW-|ERmKQSh4dC47Npl9{6Mspm*Jc}iJmX2;yPO{dcD|V zhM0t)g7ml+YteGi+cP|dQkjdMF6oPsN`FKQnHg})mw%j5dIZlCJLQlJW3o4t0(9{B zhFl^GN%)3nWHt%U3Bf{C)wdsDD{Zb$Y?r-NyhfX@xG`JQ)>iRGUhOoWz*hV|Zx-0x z-rm8R1+=!eck>qGq_m1Z;>}`b**8U#Us3};fZvqf1njX2+{h1d#r6EajgVi9AJd^p zBf`bM@VLzBG1}7Assiv5v=C&d708rMd#hZ|kts>NX(k`&?9S6ABs@cO8J42RFrd z0g#Rh9ubrG^x1gD&jVFa{HTgW-gDui#hYi0p7MYR2-!W73=kD(_k9J8@URFvgMCQ9 z2fil}0v^vZ5JrX=IOc93>SeXhb2$*cDw1Zt^e*{3=DDDr`?sM^kF<0p#(JqbnnB?vL! zC^2+iU$IRZ7))lcU$oehWt+Xp8jJCXiCd*~h$CI03fmflSuxRC zRwZju7v%fQAFB^B&iFhcMCXl>J!oVaV!5X;7cE?l7!TGHhDYq(Nbhk3bQ6VbE47M8 z2KzWY&97sS+@RRnUn%YszmX6N^$@yIRI zTpZ*lV!E=np3%{GGoyeT744He$35MQi)MJxGVc7oy9BW3=^M!IUL@CeBmCOmFym7B z4vDOVOgHfY;C|hTwhB5ag;Mi)ZK@_D(aNR9(sgD|Ini2BC0& z;AUeDiH=31o`PfSePB5&&od=qAV_}96_>zKb!ZxDDZ?snS2OK|7L$mJVS@gs*V{~u zq@}C7Bx5iGi}<-lmPhbO``KvJL*j?FYi-7)a%0yvQZ1>rmkQ6Yq#Ar$;%v|uV1W~f z`T9`bwRuwtqjd(TMP#n`LfgB!mONj>1xscon(6uQWI1avF3Mb;C)etCb1$uG6(W~I zyhi(esvVI7j)7Sx)ae!2>7w$AK1$AX6aR9)Rs;o0_ZPNPnX5ylF_YeO*s<*ux}yA1 z0B3xMqWJ*$Q}2q(uy!`n32LQRML1o--X|r z=%;O4H(TOu69vACFfgZ~I}#|{?`}0xEF;6wGJ;P`>feRVo!x4&m)WIf?llBL-OP$$ zk1)^f!sMWh&>=^C|C=|FHx^_`it>`u8hzyrXS5jo6=H-86Q&D4qS04-*JQE2t2d&B#$3|M2n}!rsBBjw zVUcmD5$>n$v{Z|1l7@&Nz-|Gj+D7pjnxL4xp3p~*(`zbK7dl;r8%}dez=pso?3L0g zcq=k}B)A;IRh-DS1ZLu16ayS;3in(&wL*ND zjYyfID8QHo!&CvuuzjVxyohAo_5;~JFED@=2kqs4{q5`%+Rz$y1Lrkt4GHBL2EEi1 z0xRIx6Kev7l+aec=byHN9247z8`wP4Xvp5lPF^eEu*sF9Hs`uy6q4Dr)zV?F&ny}?TSOzGNiA0@uyhW3N ztZ|L>GKj9(T3f}N{78gJiTf<~>uV_+Rs6SV32T+`eY2{%WI3gT|F4$73ThSKswKeY zP5`vIL+RkcIqC^%0;(XWwIX0x-^}73KF^Ym!b9?~W zccqOCJSe?D@ry_+VwG*CuR}8zW{HTZB$1v7^B)@;G_d>oL1ZQtN5s2&Oda#e#Mbc` zsb(HL2C_0J_!_llO2S$Slv<+!DVyzgPT>+G?D@(5<##pMgAYCE)bje+Cx70g5jewgUuHoFLHhWXW{C@EReq z)@J!QG1EDyRNSiPX8G&mq{muLQ1p0N?)v?zsU8@RbpF!B8+){qe0}{m{>$+O(GL%D znMNUK44s>vYX>R}7oiCN37qTJ-<{cc&2o{mS@73qt|&WzvjL193R&O;gy3q*^d>~0oLUrR8FJkidB0)eW) ztecz73W}dOy-I3801?X`+5$Av5W!)vdCK6JjNmvkfP-Pdcmqd1vu{B$;Gr27rI4p( zODQZPrJ-(Ws&Q*bM{{2~Avur9XZIxoch7y6IFY6`0YQMP9t}yoO06>eBek4hWZ0Dss^ibaN`XK1T@s^a_*Z@8V{JylyxF82z?X?xv8qje zl-%6|Xu;LG;#9J;As_f*9~|xlbmn0XGNMgHfPzYfCO+TU7lKJTwO3~*(bHEZ2wG*X%KmEQ*VG~vHib^!WPkVQ0bsZja+ zIQ@p4oi{qav<{ZI+DMipOSIgrip$2%;L$o9%Q||OC{8=Z0MljJvSp2B%K`%gnI%Jl zV?42TwMGK5S;C7}tc2%UvKmry4ZSD&&^tCvzN)v7PHWM6i*JKP#!w4$`fM$!uVwIz zfd65Z_|6@`yJ`?IG(16eQ#UUgo1moOR)i1leVtiMLSJWiZweOhx>sWrx^irhaL+bn z_=NNuyTRL3`4UHOvt{L-bu2;bkgP`LQBAs&4WoM1&^Y%VhDNqI<2=byA=@GGDa-f3chlCHuC!8e{TSzuBu^IxQl>?GE zGXZBy;5CwkDW0NrDDz?ijq^TELf>#}!DYK%}tg?Ec1w3`sopi(}`6L7hVpTv8 z&$Tw@GLK`=Wn`-_*VQo>fgZ}rP-f@0c~i{i;+R)Qbceb5?vVA%dPKm6vO?6oxf%DB z86T)+Bw)qdjEBpN+znIK$cc<9V@(D$1V-e<2V|}cjmu$izd*XECO=yKl9UPMjCbks zzks9>+juY0pc6lGDH4xHT4KJibi>*>8C(Zo!mBV(daTWpG*>+H`>=+ z2_#?Yzd0it=K|3oBAP_DD85-E8a$ThYbacPYb!QF~XhMv_8d$5PT5sU| zYVC&g8fVLDjW6?8iD`2VM^;}>vPyFLEZtxtb<5hLcXDP3tRfCPEIa$CMOOo-FUhAv z(`Gj}+ZB6nQo9w@DKi@ygvL|P{gQ{qi?M+J}iRYa5GbVW|Jy0K8ac?zt4VaRg zUFC1LQKWWmEGu@LEjaM80)&r#$Jsto8e#isoSh=nYX9`mc&`y5)9?}VQ$j|SMbO~U zvXsmQl`2mwe0MNBewId;6_1}40ARc3`^SL-n-`D>rV1Im^NHv?@BqPaaAwp-y$zs* z$Z`Qedxt>cz&Ms64Y;9*(bdMF4*|&MSdwb~Bw`eTpvTwKPODA4D-s6=F;V5%5Y0Gb zgQFqUZuX~}N<*Ns3&N24{w?`u&G;Tm`!6Tb0S+BI{Wdv`*dske%fXksYk{?BeRp$a zE@P%Om4T)8f7--L7QnH>PJq7Ay3u{>2a57{1vFVcw2>BMg_biK=R%s(R&k`EJuvx| zW6Nw9s~eE_bgOv0Q5Ad4p6lg|3%L!8i=CAdLsx?;+@zOv-Yg3T(?q5AWd~QcN2956 zW=Xv`6sw3HDqAUmjlzH|pRL2tbC;B(iMK)N?M;9+K+6oIYx@cei_j%%jZQI=tl0Ug zna4LjMkCn{uYMNrus2T+-nD1yp`!DlY0+@^U9sDe?m0+r>fK!v@k zhT&5cs@mYggaWEre3C6=1@DNphFyl6w#r%IS?7~ZYHZmFpZ8QN+!wCEDtc@y9gpHt zyMtu)FGFjvCW=QCe&$X^DXRBlZQNIqwaf-(`KqbN`=-L?$*G|YzFJ#x*#be)7b6rMQRC+9 z)oJv7oULg;XzL1EC#78n42@RvGDL(ben#zr3`w%;5n>Bk0l}I$KyQz^F4`cr;PRQ` zVFW21%vX+G2sa}hoZU%7>>;mt6~7x$j?HqEc>MTZeJ`Jor;chRgo_4>YfuSoG7-%%=pjurjza}{yRHAvzrr2RDJb= zRIt+R;D!U7TIrfdJCz;nR&1KO_nm8vtxg^|*CNtH3HZRdA^-k!Lw@xdwRO2p_EC`A zZs?SCZq>1)k5CCvcsN3VVLY^C2CvrJ%amcf{qR4<<&R@fZ2b?T#PE(wV0=f%CuV8& z&P2AE&G?-FE|!xH_E0F)DW4J{U%sL^P&VZNUycG10Is|TmTVofMHC_DFnp}r%S({; zm|539dfZ$o{UdMqvdc~X=&}+4dET#o*lQpL`7!!Ox2AvOb^RkRi@d6)u~-Lam-eN9 z^xVS)EP2#AntBI~d{vVisg`AnBx|$}F&>YI@mNF*<_N%fCMNt0p)5ymNM^wS&l>a$ z!b|E9CK9=!KVikk=@?vG3!|5FFWR}h^|%*Jzq~(czYGV~g2m9)j>=BM#34HWWxppnP5fE2Ox z&JqUlaPL`Nu$tv@mMuNu?BZf)L>o>a_2eI315|zKWwr?a{UQ)Z(-qS2-x)tcoIb>9 zf;eXIDp%Og5GN}s4~Wx?h{JE!kS8)$qdp6dp+22{>I3tI>KGLgec@@xc&{6%&$)s6 z@NU$noA*wJ`t$-H*m0Kl@r6!>B>G4Isi@(Cc__^SNgZ=24H2ellx9z$G*BEdc~P3N zVppUz`Pp(8@7=wvdp3t7d-8w!8PQ=rs;|L+gwamR6k$JMqs|2KSAOBW~q>4c_qm#<-oH`G6UUS*>gHF%hiD{G?&t!x<`Nw>tuy4;ygh}^%&(QFL&M~ zX3BPd-irav3k&RMM|bQJJGo=#XX`|THU(kN_QXluY)yL0_$GU^xKDJY5<$tllicTc zx!ZYM<&P*6-odJCr7fL9*OFcG0ki!xFI@@6gy~?0OoA0ftp1e)S}=&n%~_j-NnL)~ z*r2lb`bP3v(I?Z~PJn>KsX$b|nB60bwvM3$txg_Y6h&QL!KFpiriaHCd2XT288TFd zTD_eki%he%e3fXp=ou{cH1e<9g54Dx6-$Oyql7fCc6LYrv^FiP5Uz+kqo0S4(B zaj_K(-p&?_1Lsaeya4k%pts)Q45av(CN1x@j;0YLsfKsQc$oKK_9SWNxIiKWZ>SHm zc16s(Gn8rPOFVz;9%;YNw?iD`e)wxp&6WWIF5_)GB|h5x10vyQUI_;zs%Co zQonAE{X*1)2bD_7&%h4(IGtc`MzA;gz#h!}%*4+iZtlQ90tAl>9kuQmywH6?HR3{V z^vx_{6r;!@9ot#bvE9}1AZgFw;q9`H_S3OQlWJQ3u9A)o_R+CDk&f*y=~$;u$8N9a z77CK;Sd4!8Q;|xUZQ*mFJ6=mm)a$6K(k#OCj%T4m!poX}_IT^OouLagG z@7(tWguK!eS|py3V|C_4vU0dNREUqYSpjhHLGxoa^ZP}F$k^~Bf+*!DI(PEG(`dIim zop?}84kEVE$f7r6UD~h~NtUw!z?ZQO*|qL0V6VaQmL6lQL(VRp1=6~)PBwS}^q50E z80os;h#Bj`l|aEyQJs|^xXEN3P$65UKW=ih{oLPiM#D@No98`T71ETU6Fv-!!%f2vf#Plv5_p zUiK;N-1fh@C3ceI!!g6gXW2{V4&kHWs!<{l@(fKR4Vp+K;%v8}iNy2QrRTLSY%pTZ znT&qdYXkRXW24k=o*mBJ!x4fA=Q%*H#$l_({FMJpZke%*B6w*;NeCx2uwN?+Ly26~ z&Yanp#S_aTGpf&q;Dz-?8?@!*R{*kptkfx;*bnzldh&ks`6t;)uUbE*;`VRf5kB=p z{z=s&*}V83aNrB4FiGxWK~IT0l&&oh@Gmc&DsBL_Q4MLhmBVF~c$&Qalv!_}Os0$fi4XUcIB z&B$?vqYWjI{NHe#I*(xltkpM8pc=V>A#3znAsv^5URsia;1Ys(M+J@<=3h}B?Fg%^ zatIkPN>tJtZ4nyzF&R-OKI#r3CB$uFj2gv$`3keu>q3Q1d_~ddvU&3Aj0ml-PRw&v zZ_)ci&vP3i>GU9w*0KRM>jP|U>HnlCD#Bzfq{nN)nEf-HxEMgnWhWiM$O}ZVTy{c` zIP2r>_Vy9Gt?C%Z@!Oko9LH~$FEnv5^0e0|FuYf;E<#E}OdVFJIgaDuN<;5gU?}?4 z2&iB>UI@j8f2^Fu(e|h}>wLgsNVx)~FH)U?rpIQ1R1{`eUfmSY13uW%HB4UJ$8X~C zvWYJT7hI^EHNHJIVa3ZvFy%uC&E39ggzMxqp!?p;fLLfhod#in)}XcKY&1a7#VmtU zGeYodVR)J!gY9or5OgsM2x4+%0vQ}<9ZE6FJdB@q2%cyZCoxI%uN;LmZJVM-eH5~W zJnf^Pfu~_wFkJbx;2K^{iw9*p-r6|{m>E2t9I>B<0i|(3oMx#81jAAc&Kg!bi#UcZ zoW$6u>B&ZR92ZE#e=b+LG1~2Ji=Ix!Jt0eZVhn7Nt2(kQ15(*KrIF0+Cir>m#k!9G96BX?F}Eg` z067(Vag&bVgzV0pVJ7BSMi}6n!(|~~w2YkOv@tc(RD6EJ;j%Et0aSLr$_>#Ck89Oa zY=CDbsOB@?0IE5M%Ooo>ofW9+hszqc@|37*gO4g#qwjE8oR@&L#`Fv~A=LqE`?pD& zW?_q1>l_vg6fjN8G0`tZ*$unS%sQ1;xM>Cy~LpN%1W3k1 zcn$EwC6%T-nUtqko0f$8r(HjR|7n9HMPKKMGgvCf@r?8NReW(}?)+t4t+Ei~6d^*s z{^SaE&?r{D+>{|)1w-U?LgRQ`R*T50aI_MsY(+{!53y+CvL}*`i@+}pp#-F3d4P1? zu0}g6d#R~KA!LO@@09QQKIv7VDR~IgBHqklcb{RmQe5&x_a4}pkr33}5&%yYgPL0c zz{z4za}vsk9P0oN;o;Zvbsv{sSUCf)&Xfp@mTaZt)u0Ytyiq4N$jT;|7U?UxX^{i3 z)J<;z&{R1G(x%gBaO?aY+_gHdmUdoaamq+u>zCv3bd_>#siq=3P18U{}h--seA%R6Us;(J6vf0x0GC?ACH*of56 zp~dEWF+R96wa`7hdAv9V+l)efkN|F3tPe1tVFq=@o|nrDGe5i`kxgGQ`N<|MOmwpi z6CfsChVvYVqe74Il|oD-Ur+5nXrx1No$VYi*O^y=DU>+w@(t0&Bmj-aAugfiXS7GC zUsO{=OPXi$wJOoi^vK6g01C4`_4whBw^4n(-cS74(_9n1&Z-^lD1 zT9y{`27e<d*(~ zMqAY^eC}QLcsa^$%OXxyR_q*)b95hg$T`}PI8Qrj^pL5Tdxkd7Q|%NjK;V`}pR1P9 zBr+)^OK+%90~lDq*2HU#?|JuO21y*pc8prOlIM z9IXPz(Gs3ijDt(FbnmPqBpk}{CI}q5WF#DyKHtDQRF02}q?j;W3vVOsjh92@OCO{e z*;SiTIHg9mmP;?P%_Y~dyKp!ry(T?hrztwRk!z5j;q^&_9|~|EMmz6lYBK`S3D^rm zA3DWi?$cAVD(U>n+U_livm9eYv6~R@+9T*MfuMfQPFL6!Fouc-m?1lYA&}=fg<-R< z0rwUgQtN||ddLYQC$@(IQtK?}Apec3Ee#(F9|T^p#}#(} zU)(*&aMk|OJ`@jc0mXG?yVn;`d~vKQU$REaBcS*o$q}(h6S@cd9<>pl!D;h}?ouE1 zgi!2^Ks(~#YWO}f7vE)io)^<~!rePocI#M7A9V>3*@mrQd2T`}1G1YoYsj7&vWv(# zvWIx{M&;@bH=;VK391OP8&NzSc8f*h!Koivjv?d=^O1mE3-XB3x=k`N-+6Eu=A&xF zy|NtgR>>Vnw*%_tZF)h>q`XGvjB%SZA*qb6Zjc@-zt?^GaaMum0MD5Bws9HPRTNQkMzw^kO{?0C)WwUI3 zmgm_tS0&Ew<2XMm0drJve{OYWT8g%e!acwd1V&NJU z@O7|O0kV}UkU*jcabR6Cl^p!|{me%qOloiu-Bj|Wn4roB(P1R6bFZMp^^KykYmu)d zI;+Li$wmYxE=y8_rV%{Il|hk$nPmT|S^{X46(6kZm6;qIXrKC!wK?gMkCvf)xJ zQ(3#$n=TjSR1ykLQ`wl_R!(K3e=4z@a9f&o6Q}GJ>_9sxsHvp1rjoC#$~z`i0bk>- ze5wHQr3&l{BNPU|vpIfHUYoau=Zy`Fjk@Pe^JW@Gqp0T1RE$PZ&6{wH zY}LGBiL2&KT{R*b*n!PksGHi$d1BtwRQb-lsipGW+Bo%jYs@!qJ6aX>;r6>geblr1 zzZ@wXUymdWK>}F+r!%-M1Jj@qkrck zB0oq(3a0@oY8Ig2#e*ON8M#BDY(NHrQ9fH({IV$pS)_jMQ&atWV*Se8A@fw8=5tz7 zI0cOZyirTSx~I_6(bt8MoS-Gn-&fr~Dfm1PYdxmdP@q$+Yu9n>LO(dgy0#y;E~v#R z)^+HX5+Z0m168zSt3SZF6dr9$I zT+=Dj?pwbK7b`#kRmi7;!q;{l49$v?T4#@KcEi)ws-RdJ4|2b}Y&I<(f89Qq{TI|T z#vzMcf7091w7gKRTL08FF;ftkR!cE6)%Y5vf z-_)@Ll>(xmf#{lh7`pV0d@u;8V&D3HFZK#u7M$4ObzzSLL1Oa58=5@RVA7L$L{*`l z6Qr|N1Ns!w1$8tq%9*)CB;q?VF&Ue`Jq2B|;xWJeFnOoFu1WW%x-XnBtCPRv%>1vD z=D|mI*GB z$0x8a(>Fq=uH(yXX4J4?kpEcAgq4C`-zM;JpE@1FQD$}W>!HVM(wjD=;v|?+`L;A) zP>p6yx^+{kU|}o?zAeZ*^>0&~(h0tyF7vIEFRFjLep4zCj@mbrpZd2gn^G+yL}JP< z&d;cS%QvOWp~QB+oslo8f5Wt)dE~VY)!gyQz|qp z-o+|dT4oqppZ-C}FuBPPv)Dz33Iv!E-WM`VY)ap&8vcX~eQ@Y(O72#kf%WMgW%vLY z`hbC|e2+4KXI5^EtY7Bi-qdeafiA30K5Q{0@cRRUB)g+WMtNCDT zK`3-`G7Pm}}8)+8SSDw=dHg}>k~b1gM3o%I>GxjNa4xj}s@CSQ3`@^zO$OA03t(z_f(6 zlL2=wJnGP}^#}wgVOP()k)xs6W}yNHVGHmK7C%^-ttX%%RMCgLwmKcK(}Ib^2gpb8 zu&P4|Bj~1U32{KKhMy9>RRjdSmS|>B8 z4=^cKOSg=ToNLWbdGq_|e6y_hVr$akog{KC43+_*wz2Fi+LCWg=aa;N7UF*D7aJ6* zZ1(~Hr*p;X0DC$Djdbv4 z+RL)dvMVwC%m-hA zey$rUu*kf`Jhh(COIaBzhCIJi)r-e4X2p7b^A|!ry%gR64KNd7(Yf&zWv#Qb%`5S& z<`X^BX^RG!<`qdG2pxJ=tO!=k_>h{cnBs8JX0hX)s6(CoE`k*|Q^%~O{H>=*YFBJx}){ApzuT0dHoKZ3E$8Ye9p%K!FWAtdfrDg=<)Bepx%*>R#A? zSFYgji`_b~oK|Ft_x1p#L@KpbG*zWoCTRr=pG=+iz8(IsoYkVuEnwyFO+7#!OdTmm z_={xLMS`O>#@f2lx-y_mFCg6VcKNP`TV=zo(C~mEZ;K{@V8`q?z{}Jl zt1&$2ty&b>g@MyTIZ&!E8r48$eK^iY8^0EUhucW;Agv8ki_MUT{#xr;R5d!g)4l4C z7A`o5u3{UJ^d{cI-2OtVIf(F_65%x%*zyulY{l9#HuIX=Kwf6Th0}&L+8MPOiO5v_ z`sNgayg}<(vo#o(@&H}!4J{aJHX4l<|LK1N+S4Qb?(Q&)m@y1$U(Hq_lC?M4V&&1A zYQ{)=V?NNgpk;mz3tE*7gi3(2{M+dJtIBF*MW7n?qgZzCBN|q7tnwx16X)HLg}iva zNP@J1u9o4erT?irY-}K1TX!WBc1Na>$N8__5M6=-S<|8WYE+=7fJZsD#0*lOmYuU0++-^knBx?nW6>3nz_qQ2A$bPH_Cxt1xPrf;6UnHxRnT;s-T zt*%{G7it0JugS$d%m~yQ)ywEFu3%FIT8Bw1LgqJ0$QYjItqYU1H*9x-H?QsvYCKv* znA0G^2Fw4qEHUh`Jg+RFWtYZMx;mriXpLzGezh#M&`WXYI*hW{wx(i1Ne3x2*l43# zsck^4Z6HBem^{3pF$5n2j%^7HAlBW!9g{~E`Hho6Y62UGpjGJqdM=#chycUffoC4Y%?AfO>+*sAg(0qIff)_<-=cbrSe3Dl!MZ-ByW3LipY6 z$M0C>9Qu5pU%$u<|! z{U{qt;zc#g)$i%6EU(%0M?ZV?osZmc%OC#P&FmcW=_~#TCN_QNcRqCcXW##!`}Uit zo=&rAF`I9Y8CJI?V|j%J<1F{!>qX4;XhJD}SYU!2-z5uEt$*%(A>=HV?*D^u%i_)? zW+uh`$qX9|6inDh$qs)S0ZGP_&Ae}{e=*Mw?W^eOv`|9GI7NbXGt{>G;b?2*o>K$O z=iSyU&^+?cq3{36KYjI<4+hYD!9NK!I}U&2Pv80NHywVyXwlOF8Jp}cy?gtQzy85D zy>@?698}w#Z`x$rx3_-qzDM5tC)@uDMED0yS@?E}qy6h@w0C{-hws{T*Bf8ACye&5 zq<@=GGyQ?rziscQ-|+X}y6EW|?OO)Y;rff++R+3(WM8`UxJ z4ID8{=rQ3hb)39L$?LPL{cS66QoC>q!l!L_D28aZGGL81e;sFOMz(~hfVff#VHjHs ziz{S=(&diTxLFMO(`H)`!oo{QAjf9#fwx*8qzETP+W8&t!Bn;tDVyrAfwix_PF@S| z`=A+8C((B3K3*Ed7bC6>PJd?m_6PU;&R^g89|ZluVpZt;poXD^ywBDQ^<9limyH;& zsJF$o=uU74WN^J<{7=*%Vrq_072TcS2TSGWU5JQ;;T zYq20ypxP*j!v}$O9j(LUUdxNa4N6sm8;Dnf+viHS^+PL&&C~(3! z`u2dKhvG(R`|)4MhLP8Utgd~JG_DNc*i{rPDJ7lR!n>>}<@7s#qndiUJE8|E#}FKe zK?B3;DNI1TjcW?bkh2&+s7b}q4?~O9b6xf26j#1n@hNu=$;Y+DmWEk@SyFaD+lm@D z7?S6gApw0C`juU-ua7P2v6ji8Awg@pxuKD(cVb!ggHfsYQd}af=|6tocmL*l2mkbo zzo8}4lKIOKSW<`0_f_2?=6^s-z?R;Pawp;N7Sy3tA;3-Yk4a%RA_gdg0nO>k^}HCM zeC0%VxvpP=>4858E2j=7*2|!SE-n^>#Pu5*8&4M`9;zVm_8v ziyahfan~TR*&zXZjseBS5)`%=jsuGQrvQqLrx7XsrUJ$9?EdS%fBj@3@zimmc>+irJOxOcPMr911&K#@ zJ@Ust_~v~_KW8HC$t;hjPAOU^0L4S60E*Lz6c1ORc+(?~{NodE|LP}OPd`!&oB$FJ zp8_OKCsKT+g2b-J-};t2KD*hfe_#rxPjAPhIC}O@H8b-}B&?|MGRWB6>XCI5B(zNE|r@NSscb z_-cg{w;VqF#GgF;2eK;q~rK;m@b#GwijJAUU|e|pPDzWLVQJL%=| z)VW7{K2Vs;3D@YJ0w_)=Qhcof#Si}bXOHfD^XDG;zn^}j;K<3bgd#xVyQct&(}@&c zuOM;g%degNAAhj_%m4IK5Glq^0E!=+0w_)=Qv6*7ihDnH?-LImyyJ`Oo_?fY^ZmF; z@#9l~#OXwe!xbbBeE5T3e*HI&-11jH1*8~10VuY;`(H;R{rd_OJKy6d-Xrk>W@NiFl;{Rvw-J|U)s(k;o*52oR za*3m*Mb^(c?E9ztMjOrFhMF|2L6yf*z&RMnA+9&6PBm|P~p^>xK zs;X5rYu0?#tXWlilPIp%ik^##kB(n+&9=)QedfZKK~x;D6I5KW8>rZuRPks<6=!_) z{?osG!AHOQ-*=Ti_FR7)xD!mQ*$qtWO``Zkg^4RK{J>=&x$pxIf#{cdPRb_O8SSg< zb^{Z8lO}#yVPgI7E`kKB zR$=1%w@-Zgr%yd~@0MNWk3F|EU$GNZ+_@X5*qcQ0M1_j4UvciYeth58Kl1u@onnHzzR(L=~XHX}{H9R0G&3UUrO{%~a zYMvqH#QJqSdw)ePnd2yP9NCYeBTF1*Q*e}(II>XJ7<5vG=d_y%_Bm6XG_G>bpUijL4_2THKPP~k+{ZZITtu~+lsAxuZn=^mV85$J{_+dkpwS2$KT z6TKi-JQ8Qmv7%_IdMJ*CVi_tbCaPg#S=%rX;!nCzaZHJd!=^)pg>q-bPa@^)0xG(h zXdj|tY3bg1CO8BxWfyMcC^Bo;$bq;nMQPHfk})c3c=dEB2#oQYnNSca zn!+0p#Apba`=h?(Aeqyz)bD|1@adKqtL%|=b|4Cqa*JtuCqGaT5uhOo&bn6y{*6j7 zDf*01JulLVk$>am@jts6$NRL)ZbdDB;@p4v*|k?Z@)<(yUiNtI-3&uN%U$Dwddsty ze)cTI9sHR zfI3h{F_!h{$s?Q=L`S&v7WrGw8|q6{w$6_cx-IQP;hbt$tP3P1CA({%D890aj}$zx z0jE+aoYAzZ&XzJT(3#R+&EhlbOcg93f##*&%P6SkSa%c@A)rB7G!;^O4!sT`#WYj1 zHF7Cfb{@qf-s=6iQ2h}rvo~<^T3RpW6dSMOw`E%j*w{fxum|ZML6E-U{9zNKVi&xJ zU}B*Qo&jCbY3e&~d7cz(udSiW4$ll*4d}hPZTo;xXf5A4FwG`{r9hR~9zLpyM@bBQ zargEGgy4VCYAyI*q{@Xw?zPRv9zOk^NB;GXPoDKwA?l^r7O_QOdSi*I2&L*#JR=u!f)uxW2fMdi{@Pe^wtD99}0yaf)*p$cn z=CF1pQ*;*AfMTD;@hHU(ij%q!Y`nTeSzAH+^-m)W9oZMh)y?ME%^&#P!?)bD=02cMYu<45j(-9Au)_xA0`qZ3J853)(-EBD<3llB*1zfSsaq+-&eT@Nm4H;hS_ zbTcUvkRu@8hi)~x8RaohI5WRGg^LY#lcATu&~Jq5VQAv%3#O4r`x~20U`zgR-d@Sj zI`~aI;JS7+>RLXjF|@v-W?cv34lABgg#DT=ttwqUUO{4r$2l1AMe+8KJu6ox*=8QMjW@pPPfFDZGt2JCk$>9c3RqT7S? zF<@IIwgzf5asl115vYLX(28nj)G=+2d@w0QawUb9u;1CyyT-v3dM~daemZ(_nq!~& z=;IfD;led*n91xQg|3}R3K_&~56vqnR41QZltLmyWH4kX8%AWv+mbxkFeMoVDKr|l zNk#)E-!%hfBJK`)Au)8%Oa@M5&h9;-!N3_s4Al%Ad=15KD=T8-#UH%=oX_0!h*s!# zZu>y+<4gAHX3_svorF?tafMhA7z_CMokI!Tja_}kL*IJji@!NTi|1?}H-c*YRC_0R zEH|Ity|?hQy~58AZoA~?5B>hPxBTV)gPz&@8a>Zc=sDy5Pj7how-;{w5Bm>#X6xuup|Db2y9-?Qj37cSmp!-Qj&r{I+f7q+Fhv?aB?Dc$wo)3Ru>#x3d{|CPDvHggAm{{$R_}OdZGk%si zzchJ$?!HUUeCU~LzA(1`kk6bwM9*F$pVKS!eCm-;J#*o?tIzn_endVTIJrmUvzzz{ zlYLDsYO52PTHNjKBazSK1E0L+sXL$gNw1Sn>BZae9Gbm9wb;%6%sf>JlMwZ%J_&ib zt(CpjpED}@ec-9@-+1@G+;R79`;m2V;2zTNy}LK{JHx3|^!waHkNwMv3x0HSpWHE7 zp$jL>eVdIv@Q25@ob~F|^%wo&)=%BK@w)5wBY}l~W{(8cUek9g zD*Sxq{ENSK`PY7N(f`R`QWbHx8!q9g`VF{-2a^m9=_)Kv-czEGk0I(XJv(-^H=`* zo`I_hVBlcqPWsm6RuH93|Gn-%MR`|K+>py$ozQ?}$j{S$b4%kEN>^0$hUWJ|e zfA_r$xBT{j&p)vrQ4eb-dqh2Z4L={K@bk?z*M8}&E6=`1`?p_i<9()ej`{ll3Y7Ws8&a^+`(ZfDZBJ`c3d;5Py>`53h!@kX zL|TD+6eDA?)Io`iBLK>c_io^qIHI9oGh_yLQx@YLfOI4xXf#V-^JCko9xAg`P| z62ILwcNFEsfIQtwGbVRO2*^`x&+)p!+t)N{mDS+Z=QPwjPsWwup`9Z9Lx%9)fA0vt z>ZcZLQbV|%lWPI9QIBVZO$SQwt;kI5K^OS ztv*D?V9b#CJD00@-bF^$8LKmxyc(@Xz$m;`(b*i;`1^20VUsr;}eoTnHps)_;e;2$vriqA&~UDYSlYo%p~~ro|eE(=p@v> zxX%*u>XU~pVYEtMj{=`8sS>y;jf7)Df(2wl$GS3NQ?>D+uhDZ_A6JANW;(jqwu3lQ z{E~zTf!;Y0?@hZkz(|w;Z`~P!X)|m&9o?QWUz_hZ5}M6tJ${V~>@1U}$Ir=^Wn?VQ z@%g09vFql_G_D};;U03nm+`_C@@5pB3oYfCGb_`~M5O=aT<*5RrrmTZ zd~r{+SkF#dK1OE+XT>8mdBV;P@J`}`me|2ttWGM~gwc0AnJpSIIald#d$I-4dTC@y z7KEEe-+MAN7e!phuEp?VgjE!Donfn6^5>dV_maPbEKWNIssIcxz!E^<1qedJywI)% z``b6P78)UkHoR)p20QnPWYrB_cg|KG{d2s5t~5=MbdK`o`*fx-QcT2S7vAz4?!2Xl z?v_hhx1Y@j6lq)chgok(Ug!6PG*{$lOIHw(&#?MEKV0i)wMq9dCS{FWvp`DB)u?yn z8c;D;G|-icu#G8#6Y4oXjd!&t?U5lm7;d1R{~lCgQ@4nE$CU%Ajx>`bNdcijC+wzs zp14eA=KjMbx@4xefLXY8Xh?173IjUimzIc+1Wdf$83?yUp3O&wzCX9wIIW2h(TF=( zCb<{05$){JB(a-p2nJ=HgqW@SD$x~+xkS%(#uAHNK~@1Km^CD zRBy>Keh_5Y2_4vBoBH}xqH(ZpZ=xdV57p|8YC~;$qZ^?HKHh|Mq6grtWn#(YrmpRj z)D(39SL=pV){%U$7=BMD)ff{23$18oa>IF`vQ7UNXV=+dZ$8vc8_W2VnG=n%fJ^@b zkFKd^ZsL_%z9u;d!)R30x9>i|T%YD~lqCMSAmnx*DhYyGJI+x5X}0 z{gg35Pw18e0kCrgR=C`-#F_XCtT-E6%|PM?Qa96+?1ogCY|_TyjubBHT@v_xQ?|S~ z|Hg@K*#>j}_|p<>15*T>aKi_cSQFYLBuF=jPzq5xyNN^I4AVTqEAR9|`U|S>5UQ=e z#!6$^-?+TXVqIpnP*`H)(GPZw%ce}m)@ZglYyBeRz+fUJN9ub!+}X#cFg2SC4H0m2 ze1wg|qkcA}h26sy?t*CRbx>5=(50&olw=oM{*h$fNAIllI^xs%ZX_UV)X*QKr1e-x zbL&A8SDuYc;zYGD%fY@cGe$2-+%IB|T;oGORShvUEiU@$?F`l6jzb0NYC|RZiyDX= zb%$~Iu@m-UC~*v&8PN|f?DUT1E7#aQ{@$_YpMU;8pLskOMK+IScYO@sPCmS_B-xzn zz9jPb8nTL7NSMINvcYu~l;}OG55pfIL@JJ2$`R-phRC3#jLy0!SsF`&tS?3*(HM?9 zBUR3lnB$eru5ylvImShumU8SOC9BsiS2FEp{z?NoQ9D+5BGc09k{dC%Z%r|A$w{Hf z3xU?E4I9{ZStL2Dv2OxJSmreum=9{i2NAvcjdoX*ho$nAffP!bY&5k<+MdWpnlagk z=8c5bC??A*ST|%%IcQ{Gg*lPDy>42$bh3L;CG|T^(Fkxi*PzUjx2OlA=3Xm@P%iqp zFA^H>3HzfEb=aaN{repi!VwqSa{bLebaZY5ed3vm(a>`}+6TvtW#SqXRWHcbQ$J6+ zJ#k|o8(~3`ta7-N8;mhlDxsK)-fS?_()dr^xW}{L7q`H)X8OxH+m<>xUOJVVigfZv zpXPUcrd%L2KYSu?s9-qv^S8qZnQZaA9IZl zA`*g90$3&C=q}-6b8;Wnp(`6%qg)eU7k_0-o2i;&fZosUOOp-^sdOjWNUrKbd4{4n zh(x$n!K-8*XUk}kGI^(Icc*41PqhLoeLXj5 zHHwvY-K!7YVZ~t7rP;ek#nDjQ_dNUlcm}A}&8n8WT6LZcf0nhrq|x#2y-^rdPGBS` zy^dqU0^5#oUIKMfV-}<*aHu!(v?yKP_QWPynE$Gw6a>ip(#`#$#&kE{su61l*6U|p z(*ZBy#KtUU_3b8xPoz_>SN(=MBcCZZPU=F)Oy&hHd5wa}1yMby!*;xM9xWt)0 zmz2YrjkNrUx%-rgp7%#WGLa5BfD?RR(3FYvNJ}${^hVM1PaU}m^&Nmi`n!8kw|`P(|Q;z+Zf%aVYEGxz4pY6(-LxtYYnE&VUW{3K~BR<{W}Whk2lla z=;YJQVx?fF?l>8Q948S&N$V-!JU5!XO9x$yX78j8%)+JFNo=>nkbN(2@Fjc^DU?Da zj%FuyxUU;{W#|E>nG;5y@ja4fe2?Vm@6e!;C++a-tpqBi^5fgW1P${S(IleHTIZDV zQj$h+z}JF=E5s2o86yd#e!h85;^Q!!zwl|`CLj#JKwT9r`Q@zLH%i}C198oGds*U^1hB#zaM8gbA$nA6Dt z>Cl4Y%)h!oUf)GLqfv6YIZ83aYo+@rJQ{SL`HFczLh{zif0D;Mb#Ov^S2 zl&a0gqI6%?z|-w_Y~vNAxm;(j;Q!yoM`}xH_<*&7#pfDrNVm*c!kSjdF?+kp8D)QS z$T5qq%E4PUOwJ~1o03DHX4RIP)HJ>Ct9fAoOq0x2>di$Bp;ZdZAR9FsQLa@@!T@=8 zUM*!Q30Md0j$Q{vNdP&R50yPq68#@yg)DYbNsxK92Brk4WL8%Ry405s$0VU|m2eJ? zh!jC0A05L4B9^cO6hQ@`Nus6B;LLHFgQS-ULOR~p@tH2L8V#wDp8-2 z$x0^Lb`Po(9@@}>jg%<`Io$enNh;W8`qmF{(^{tnh_36v0NE4KO>e{^aBIV>#Q}y_ z#G;%UoXTO8MJ(RM5(Ua(I7BSUu}OfBopKnvSs}-UzRF>sXNR066}jpgs6z2hs_mFE zCl1#!Vpm2E9AQeznM6r?$iTHqn3TZ4)kcy82Ckw9m0;jXYOp#OxY|fk0uqX2&5=W8 z^_vW9d0)h+0D6nlyB;~ZYg6jpe=xp^$rYDxOU$}lY(#;V$pF1C#pct}L1l$Pky$jH zFXEXuSw|uX9%)=wbXHsmfMz>qvYjtdUND};c)Wo?7M%1Xth)JZ$cpAOl%uxr*raYi z>-j!&eOXonw99_ZAtC1+X;RQ0@gLA*lWo$Ulu!7!q#2vkd%2Q#{61wH zpOPL;gL}D>dK0-E1RCrEnI|@RaefPuU5Q`E~K)_!iw3_Y=Qu!q6deU5L94%cLjZv8UMBnCiCWrYsXA#Wq`# znirf3o{U)56|eeA%1I^~O1noZ%o~ZU*`}!)eo_8XN$ZCn(R76Mh=)_`a(*}Kj`^Nq zJq>jGioMEiU$GieNf;(HQ><)A^VAw$k3LkR5rA0+Jj5mxMFmGKO%4g@jW_XQ^O+0nwFNKztJjTzb<}#ig zrCdK~8d%t#vlArz@-iXez^Q~gw?so{UhK2cI%a~daSlWsqpXakrl+q+;LLYy-BomO z7Zjo2jVaxlnZ&zco0~^S=9l49Gqx+T0dMJFFI<{!6rGDt^8k3$h0RV{{-cq`tbmo> zYPrTy?&gnUt^Ps@3p)qch$AHrlsM%dDx`f7V;+r!&H@OdJ-eit_Q86ztLWQ@0QDyN z!aC+c9&sYW^X)@a-Y`HEu)$sN&*BHp*-X7%zwE(#O20Vtx9OK79v;&#^R`L*Mf`VI znBJ-vtvhD6fZ9PPZ6Qf3Oe>Ld`W+9y7l&Vrryhl+0hQS=*rH9hLpyEP31dm?azRTu zjPtyeSLs)Tbk?XO9#_(q%1G!U*n8K(%Sr2+Q0QVlZZ2-*oi;6uszj%=Lkk-y)XuB) z*uq+I&Em!ewLqEBLallt{qokSvBvTCVX=}k+KZx8HOWdXYguF}PE&msr}`*#XnYM_ zlhAnn=Iif1_U#K}N6#1=zw=AKPT!8oT6fA>001x!00OJ8NZw593aw00;YsaRQviH; zf%a>7!?4OG6VX7R7KbE%J`Jd&Z96omP^3LL-_11-*KSPHu zmQPjn$RfW>Hrs+A6oUVHivTjVg24P4`L;CMAi)8^EBKWa{*(X?R=6ut@!!(S6zK-k zyj$VMiqQ%Oc*!5MV54+n^LCfbN-Z-8YxOq&bBV9c!wq_eXKx7a>+!UZ!w9#o{5TwCW2skJjjlpU zn}1$8-)AIbc@XBo)Cx7Um%?xO}AboG90OyQxuR3JNj|VpH4pO?z43bv_0Qg^m$5F`w&w$``>6VWW9z>LTZS?g*;oZk@O;N4*MWQaG> z(nv2zChUms81%VLcJ{imA-Cl7jT1GOA$vubr;8?WZY@nj)3iB00bv=zAfUwKrdDyA z2WKsxR;F$T|HtC|HTkQNu7|Bb0;`EAO&3Kmy6$9Dz^hN-r=x8*i}SYJ)COXEah@{1 zefcO@DrZ28#r=`Vy`wHJ$|b7(jxjq&_~_A%&f*$#c8-kfN&XA7<|;|kz?$QFHrAY! zy45)3BT|;F=bb&HK6qzIqJQ5pQMVnA6+=0PF~Z=`7!@rv3g2{6F)B*u-R;*pdSTL0 zDB`ij1B}FfqRzko?E2(z0lIge2;dfIeLISX++(#X|d!;Xo z1gc7$c!3L^Q6|2H-F&Gf{bIh|d|$f6KO`PA-VGsCmf$zNTwJJE=I$$YRfMa4R=q%oLtxOKWq zR`Zq7iAtKazNBT?F%gVKVFRKX>+f{jcs!yKaF`}g zLXv!=W@KO?)0yMji}drB_G_FHyB!iLkHPawA{YafWVW?UY+yg3=krBW{+czNbfEx1 zum_LIVI>zoW!0uxc+*v>Q_DdQTXRZ4eo?$W$B@`|@QJd>HVUK$cJ>pE#j%&fI~ zhtRJK?-*)mNSWPrGmBR`?mco0nDa@+7~UPNt<}ux%-ULQ(JhkaUPX}RM}`C=IoV!2 z%5#`)im7GRaggVmqCDrz8D)7=%D84Uwra9m;V6t-m(kVdMps{5mQQbRbsJhime&of zQkK7>bmr8CN``*}SAc}b1omMi!~5zo{6(8n3?Rscq$_i3 zH8U_ZyS6cnIpx!f(#jy#YfohO;moYthtvJxO2xc_m(mWL&r4+}vPvT#B|`sDNKH(; zn7K&1;|#hsn15GVj07}^C?f(oh-7snQ*<;BtL1?lwt(v19QMoMKC0S=(-W&)>q9WB zo}m7@B5HeqMP5<9AYJE&7gUF7@3k5B*{IL}CLv*U2`CR!)ti74>ruAG;Mn;27hIN| z>`|;e1;$G#Y4T<~Yq$7*Rhjx~eZMMezlL8ln~AFRDX#p9%RV-wK znVG!mQ_5;pg9-3(@y@rJ>1ckn1jp41Q~ls`OD6e0N~yLn(AG?+pSKYC=-<`}X2}n* zI>dk`&|HG2mSKdRAZ~jxN{cT>gZ`p<9sR;G5%A_M8KBFM!MpQelMDiexy^6|ObrM^ zwA%O+p|3^xVJAbFi`Sv!SU6&3n@_IvIV9AQ4}&~4;`nr4xAvkQYK={NeCze;sqH1` z&qb=sDa(4D_qN94h8V8_%K<;08)sX3Y2LeUtc?d~oO6P?%-n%*6w(sbdr*v3K?7;pzJml6TUdP$NvXoBg?RsG+6M{urJ$<-7oebv1o&Zag4B zDAiEG2~D0UkPw|N*Hq%8D#|%B!3%9C12i&GX)`!+`ShR5Pr0K~Uy<1_4{wh)sH@6` z9T%Xd9y>08tom^QX=}A9J|eeP;u8~Hl)KLresMWsgAYvU?}eiR($=SUYz~0|No2(> zw#QZ?MsYe=2yr8=ClMK=Xqx(I0l1MAMpHj8z;?)XM%2pyG%0B5o^t6+aRL0FNU_1P zjAlC|4c4Mrd;)|IvJ679IT40NpZ1A( z{E4V*r2lV)sBM0*KNB?q+$l_wgm8;R=q)_@7Y#HerTeN4*%S2`>mt_~2^K92S0g$w zBl6lR8=9=;LR_}6t<8`$A7P6Kz(_)bd$=tTRJo<)Qz8|USwXm4tdb&^*=$mb{)6j9 z#X^k|3Kh01^%p%n? zTW(C>r{!tNYArUyfc6kxh3=jt`A;`w=g<+r8Q`askxE67A|o}kiqci7NX{WrOTTD_ z7*+l|tY=I=P)VxSgD+>*q6tZ%N~VEPpsEZ_54vPRu$Wxss6Yic4inDdxCLW5c1#^wR|`D-n7+T*dLs}+9@$@a z1~3GT@Y3RjkF&pw7#mn;4r4T)fHmn$>>xbHVytGl8K|_2HN0`(^{7SD3(?U)&(O1m zIuK&}J`H;@WE9lWxG2VAWgVrkNpU`XWfn{Cv{Ws?!%Fo@_Jw**z=9~M3>Mv9?X>~` zhKOw!aji3#`O!S+-34pS%4Bf81vQnF}OshFSxhEf+J;H}H z{DZ?hw$0XCpa0L2e=G5)p3>>_RRk7#&+N(_Z*=-k=?skh$CW1&SRk4jn4u(-?}1Y~ zgI;p2N)FCY6932GDV-rNxmqQMY9+t(M+44a+nRNTPU#GLNum-^Z9I?7J2fA!z5p;* zJ6SV$ePgqJ*$2Hzzig)6s9(0sPUv@NETt%+DOoXzqbw^Fcv9hH{KHSL{Kzw3!J6IL zizvAL?B{=c$sOGGIH|V>p5OlbgC97X%*}ee^@`7~dG_}o#WAu;uXld%(x3kDTi40m z$7>j@RrT77O*ViVd(|$3*?QJTLIbc317LAuym?BA_><8UK0*wKGPhch?Tva7VS@gw zg}=Z`SMf%u4Aseyj{&nv#e2gL)qn!dm1G4h zti;7;W8hdAlVcG+>Xj|vQzd^}(DjzbHx)6oGa5B~J8r>q>yM6Gu}E9f!}ZPOF7;OT z$_MSrPKkK5Y&6L2lv6q@j-K}%Y!P=Ci;eXSzBJF#oHEvC0|@=CS0^`H_bAIVBo>D{ zkcH=hf--&FNW;rlqydr(go;cpRy?U2whl?=j)b`_2NnK%!C`rdC&z1;`u-@vJ<2vLSpj zG4+!g1c;LQClle5jZ;6Fxs{Fjggd{jCJCpSI5SuPel2AJ`6C#3X4FeGI_Wx+MZnLB zfU{-!EK^*8a40k_mg};9WnW~HV!V3X-WyZJI@>A{rM66I0nawrkGa7t^cPP4Hk!!K z^nqlIqFk4~p#FLle!zT|7d8)}!d-_6Eix_-DyrL@^D8e{dSs74-X;$3N zyvzuVf-G?PdIq*cBJ*EW`|(hiCrP1*TZi6zZi%bPM2E~0SC)wmmL)P-FqEWjAe!hw z^3b}@JMoswheK#@G6@7}yODg(ktn#>rGFwzEIwjt$4881n~arqr-FcEY>q*)-Vy*U z8mnN^riVZ#qQ)?Vu7w05r{(j~HYZ_gRbRBjuRNq?hvOG$EP@%wDOe;&B^xeg(sFFd zHXcmc*)zs`8KHrN`OvN&*K zW9pdd0O=c&J7s;-)JFZzCG7Bl5L=iWnQTlu&Ek$!TQyJ$D5$(C7xCT6KiVnMxfPKm ziIuxC&6Z`$+#@3FD@Y504qyY(xT<^DF=IrtnfmJ?8ZyX6jK(7vd=bnindyZ8n)n% z(|O>NTC2oNCv?CT+DUB`Khon?Mcddje=*5cUP`U4f0gBB+o{du!HSBu7w1X2?WLoI zhhKm|gYD(MxxHn_bVY&B%hOmo6GmbW!UWHBnUT|IUfr_W<% zt0{ShcW7?6l5d(_T^pmL1Dj!%gbP~{4+NoTUerBvsiCf?L|u=7>1HWnAmuer`7;%D zJ(|!k4^Rg*l`+(5HuGXo*Hex4j;L!&G#%vQ%t$jLcc#T$<06}gxiDZxsl(+0jFS<)#HH#yHic&zUvP@q!(LI&EYAW$i7$)ee1w00Q zbur7WLla&4YAQ+g&w!N-t!qp;l_Yo9J5Z8` zNO=dE7}%BOcW+=YBFZ)^k~IIo4$Tkl+vbP%ZSy zne;Y0ebC$XO{KSq4S!L3ySEa|JL>Ho>FvIm^|nJUy1@_d|I|y2}#r2J2ao|+vXcHG+z?V?)AJPkGkG&Mxzle zT%TR`5R>Z)+IDe9ZLKqbD{bAQ652Buv~@p^L0hw3snXUt=`8s4pz5WqwX3I(r%_Xk zeaavNd5X4{J<;A324k)@J(-qx3Wo7sWUz+j6da16IYrY?3cwO6Wsh_ARCeC_Cm|#8 z_$ML5+@z9m|9*uGNBsCQUH)%b$RJ(X($xwk#5Kl3>5dv{T1m5g&%GC=hGNUjo=BR{ zXK8tpL2c6wK9C=rbL+S+hB@Pc@o_EmS}-aLwcCD!tEHINS`pHJX64wcWYMu~UkvGw zS-Q58O|qmN({&&xtJ1;@`XN5`$0tuH8>3L(IxAGjx;yC2+6e)Ii6fcSXqJi%&jpQy zC&I_VQ?q>PDW3=o2)TXb6FMcN4U|uVcEUG`vpWX<6DjszwybCusX1DR{On{4!){N- zMViTj_lWUOovfPsN$OfSH?pwH{^Us|_%kgdKY1rUG_8U|8ww#!%lOfvtrL5|hbSu? zCKtkCtApx)G1BNIK)*cYda^p@IvRA@GTSSKI>7DjgwYeuD3!Na+R*`;jRK3?u3wXTJ_onk$^@NZBT&(8GYXZ80W?cQE4ksuG)i z6`gja`)7<)+;QA2cV=`YG8n$+3%a8SEya!KP0?++ON}5wqv5S7Y-fk#Vz&+Q%ph(H zS4h}yLwH)Yscq77_&lV?(ikvpdl(I8V=GLC9{Tyhb~FI-`S^#XVLIXAPfQo&19b8y zru!4qjl*X0tjM2hKHxoPI@6vOv}T8bi%Buq+;*_7YGoLqF{>R`Wr|PwpRo5hWs6&C zzTDf;4O+u->q-3(Z&$MY9pZ53&wPJY(e#t76ssEV&aypebQZ^TKV8>$9^QzE?kVQ~ zgZ4^cU+CF(LfL*a4s&4EN?n7MilL$W zZo2|X1Vd7|j**@cj6KH)8`pLjBUyzJ&?+^f!5PuuG%-IqDi=19WS@1)CQmDtv%VVzskXM~Xtit>f`e0I_LCx1a1&OX+X zVF(6L1%}xM?N4Z2&Nx#VhI44K9(ONeo=OX$riS{IbDUWh3AGzQ0HJ zr}gn)IrG4gntFL^$Gvpj$8H~Izf^JSQ<`hcZGFJPJ=4Y9EXHmub}+Wt8<;ICmQ*II zbUPB_2!1~H6~2eKUj@|tDk3aSN7rywFLto#}QW1Lv=kxR18}9W;)MoKP z50_vKcI?i_uiF0LZJ)W|tkYzy>H;Dy9vz`4)tjoNMgEraX5xd5RM$C}x^T$1PuBuNZ5W^_EA0g z=KbG{T?pM(7i!%VY8EXQ0D3xf`IvSMPK4L_G-Li&BsU@TX0n(c^hC0W;S!}uYt_bO`d|(9WJ$L@$f$O)NapRLV zGnfMEif&NtaDcP~RR;%oixE^{se?+;azw5`6;lKx+lgKkUWWp-fgS|y<_g*wNn;AM zXLm#Ej8j4jvueP7&#&Wr_Yv%aB~pk8u7SMuMT5*CZzA|e3&_|!kcU7u>{%~b7aFZI z;Z2?CM^RIpz+mU*Dj0~9#NHElhR7j!MrS06XL!pg%SkxGM&KE)*4BGzH=D`>2oCU( z{^QsNC*MT;V~5%=g)Vt>!Bsg_qm(HouhkymImO27_-*|_wRI_v*lCzaCY&e z{SHnidw?{uvCbc<$pr{~&*Xvxi_p8r0^urw>uh$JKkArq?weDp*zA^j9{cnUKY8|N zuQ!=Cg>cXBCR{T+Dk|8^65;C=s9&f+y|5C$zrFN|Colc{Id}bhI*Bj^)WN9)JH15c z*opEczPe<>BJ>v$!$pI(#`8I%pfe;P`#=Tg9TlLvic@YZu1ne301C}EQ03Fo=3ZkX z;ODZU|0%qfC2K;?7|J+#*STrvo~E73Q>y80U8g;aV=knvjXEa4jFjxiWE}I&55i#@ zoE4W;P6O%4toTqZ!6xwMRte0$lhfrl0!fTW(!rb3WDx979-cYg2d@GeRf{P)&47q0 zTMkl3ak&^Yt94DZL&Jf~?DmkEXdBh3fayH8(8?6$%|?2g$C(vixvm3?y_h{j%oy3qaa)`Z2Mw&^Iq&iN< z&2fxMQHR`%!Ri#!Gz8TieC#|-y8_b#`qgRIx-o=l2qy_};<}f!O)(CPRVlDEccSZV z+YNm+%X%>T4udhq6C8Tw)^HoK`k>oc`#$KS<)EKj4tkR(jq4Io;8XI=#4%su1MX^; z@fI(Xw>9Bmu?x|2(q(6>MN|s#P=_Rx`}dM{T00p z-QC+0XPcXP>L&9f7I`w|MnUF&lNgU;$F$gvou3xZG@}!b3n4A#iCPMCT*FH7XqAW| zkUYX2%9AX`i5vY4MoPYs`$_ z+H?bX68|&bjMEGIvYQvDsccpXEn8G%=2YJE0#t5iG8&aLBAL&vj8b+=<>5#?QMqR5 zHb6|C+crw6&eja@Ru)d6rWO~9+sG9)3wZAjX<*gJ)>k1KkrPk zw7$F(vC>qFHj@crg&_mZ6}VwUqV0%d$PJXbF=c6P>M#msI9|)ymBAGR9YnlL1YTDe(`aHhCfh$?}Qo znZsE{neW#`_@WC<@8v1SCGwoTA!!Y*YqIaOIJlh^m#@ENoZ&0N$t=%WQD8J{ zVh1G$;w@|T^!D`+3=R#?8kyaiGk4zn1CpU)4lR5ww1D6nK47R=NYdFMDI;nAP_cld zUw_`=Xpl5-sF+RCk3v$Dq`6+#Jt3)wq&Y(zPL&m3yagkk4)l`L8YYp6Jor1L}4AW6gi;pQ*gYSj;sG&EEUw~1VTmP3bV zahQ9A2feP-!-umdH851PsOyQ(d51eq)^@zanro1{MP;{ze7MN;ojF_%)ehom_q z^>|%p{oH|=OH$M8+7L?3BdOuYSrd{t9SkLEb$v7>9Y7Mhk%ftsA?ZL}8=e$remFfg zl?0M)DIzqhHz;R>wa%^?`tMcz9xmH7h>;Zid8w_`nLIG{)ZhAn<|OSTu!bp&XcI|% zMiDf0T_ej*YevIneV3WMT2ig`jPA2RXlOMJ{l7Zxm@&FGZC$TZSjpk|u2GqJl;9x< zVoNp?Rmpi*vKfU+F4cvVHbYy*YQE#7eqd8!nqHVGe?m845{k#oXgCID(`!LqDt~{9uG~X=NY* zzLE?~TA%+210t&_mjz4bW!7mCaBZ|^bb%yfvY>U1QY1RsiO__{uTCQXkO6R?Ot7Rl zl?6}}WE?(poWz&3VW6OF=)$zxJTJ|aMB0*?S$oR_%?yMSuZaOzUR?T#+enJH#Ysni zEm|?9gkffySa*6aG2P;s6w1Smcvx`#ZF(q!S3pigOOp|!>kEgjts$w4pn-c;+;H#K zM~!nJBSX!qv`sCteAlMXh-IoPxf^%p{p-e^`7X^ef!rK%0J=EIg+eeC{4zFNoGxxa@)BK6Lmz3RBaxbP z<$PL`D9-ilRDtX10T;RJhjpRA^)kuerVdKaj!5M(o{VEzoUViJv@9N@DP&o}T%=~| z=tLvRvam4+!&f}U3y3WXD^C=yuXv2N7puRzZ+L-*Xf*jhnu2PuSgG%fj3&v_WS(MO zPGU^s8Srpgxr{zg+LYCCgtN+G7aiD@-ppyh$rCvT*5l`?VR=5V zvlB^({v6ZS{Jh=(GhzFVQk*&|-tdHMnG%kcge^}3uTPOL8t&;q38&bz10_RdwR1>h z6Ub>~(HokoLWf!Hd{URubQ+IRA%-xeg6mRdubD%}Tfoe+h`G zrr+ArxjA^k8k(O$I+S^$^mTb6YNb&;IwcXH8pR`3BGFXIgNV;n-ED0&5$f$UebX=c z4Gi-&5b=8L;4d(+xUm^P)&mGv%xMEx zORfNm@mZO&p+QqyM+ye~ds%!oOd)Yqtfx5n#3C1@J;mSAo~IqH1YM5-L$og%8aBOPO60T}*O7+HI>&*-azf3-&CUn%Vl=sAPSXmy> zcd82j%8~>mk_h5T%5a~GrPV%`!m+g4w@4?_fH(|5Qhd--41+OEY`tJK~lwIP^61joe2A|z6eK<8kHHR*l7V4cNtEF zHIWrhAq5H-F&onITv*a>@L7p6qaUsj%zH$&pAH+ZZ>Lcl@6)i@Nj@tDP9p zxHWp#wEK+$d+Y}0W8Pzj@LGz@xv|qu?r_iRJM8A!fiV~ivdxz9*+`aT#O(CRT0mE_ zpvom|1bBq8CBw}F<3Pv){;6Hw)DRWd?!jzGltRQgeNa>{z0H^l*d58bz>FK?@H$s&NBH5}o_Y?i=90)UPOG1z#;(S2O?#)G@mNWFM^4NxYlGXE`KXf|q_;yS z2T31MCtECF(A|N&^>#hjAHT?rU@Bs2ga;r~@ADx=fU^iL?`MB;jJfN>MVSm001q%+ z>Focv1|N zNg%+Af?I3_oA_yF@ADVs*hv5I15h>-(k9SiMdfzs8LCn4HW4+fkn3DDvVrY-TYu3A zOx*p?uyzv%p`0!VHJW2(>AfcJ^u#&o1m2kcMT=G#ZBVRtVd&?*toM{|5lxN)zh%oH zzHex~!&m5*z<6M0MLYf0H?bN|`WX-^R_#G@G!G$|j6Gyom+Y#Ei9zoVu!&7NT0huBKEgX<`zEflWHL#E0c0 z>7j^wX)$?C7Bk&J0sxQ_L5mKgR-)0RC4xKL43=nmPb@5iRxf-OijzadUZLhYsVZMW zZ~19y-D{tI9pCBAtt4n(0hfy64er2GjOy$qC+VOL{U` z3-U}ZGdW>2gAJSmDqsjsiA9X2-^i`-n0WvJFWr{cN(SO%#%o9s9KX!hOx`JPx)o= zqK0JGh4?aGi|6ZXk!2aAa@&^r?Y4efJ>x5kb@Lu8fI@*QG%HfGmA;;L7q61`(7IMs zV9JnH0CxhE*i#7ilW>ea6JDr+@h^3m*wg4i^lSMDGmAR$cb{-@E!COy4w%faYWKP} z>&upzuF4IhEGV>8^#z3{fCZI2(}E?_{x7`h?9`T5J@g2f0vH_|WOIq3DXoc?#j;!f z)kHpB6WsaMRX^HS^<$h`f9h51zL6eaj&(I0gK*xA;4%q|P-=OWfe5p*QL|AE%DjY9 zFfuZx*EKQ`4fT60!52sY|rZzI9 z8trM&JPkmuQmku$qu%|uF5R8Fl+M#qKZy7`pcmon{%|!qRlZB-1^NEOf__B`X`(yC zq*u%PhnZ3@#%I@O7ZZbKm!!pa8fG0MD)FY0I9oz;vnSGPe80uF8*y?mG05v2?H1v8 zo{THobHOwM!|^XHb=LC#Xuq?Uzb;9}T4%2q%g9ypK=R}0q&(jh1 zq*>RfJ*k;R_9RNk?MW*ahuV{7p2P|#2~NNiC88&vSki#*A3}&X+H>?f*=Wy=j9UFl zb0?j7Yi!xyf*E?^$@B{TZgj zoE0*`5^_AjG`R}Ig^sx*hGea=33nRB^C+ zaY*h|Db4KJTxRIizuD+&sg&zCS=O;N2>NPe|ed2`H^3Q5?pH zQla^MxIMs%5RchKoSS&Jy$oCf)}W5j``&ENtP9X}nDr0_7P9I;8)9y_cr(`Z zZW-&k%&0dm#v4~WwIWTs8E@@~Ay#ZEgss=BF~1q8p7_hb8lHNIqw2_6_m&+@;wDes#|PN;%HbbeIFn zyf;l~b|np(YTlRH6?C?{25Ha9zPKd1zu0=?%wI^Wb~s3pzDb?YuxTrJoFw*|Ox0ta zV0ugiA`5dHuNKKrZDlq2TvZYaM9|D_Ddnw5rOktU!!Le#4D6appX)nan}q7|fr>mh zC~7@2p&++-lSc1(1VH3^FI9j0=jnq; zAU;ZpJ`8M_kb;1CJA` zZd09ze(Hu^B$GDu{^5apB)vv?C3EK(4WWiCMX+BgR9J`}WL04u$MP$eyQdN z%uA0iL=u;dvYH1nEAZ(#O0%&C{_yygv%Y`*S(kyp79@L#XNmXMU3>lA7eDg!-DxuR$JHp{(^CMgH5P#7vmStFPpnDW!OQEBU=pvh=SW0zxVhbh>PRO9YJnXmj(F%+zH*LuI`+Cb z_K9=<N^kJ zbk6w}Y}~{(Ab%~Ug0{0y*=T7l9vi16+RmQm_3i9SkdAm6aM+o5PE&`j?d-?+c6MLC z=-Sb~q}*^Fa4hB>UsnP<6S}7Wdk%e?2(YvF-a<$!V71e>+R!dw%^O<*i^7lSm6y*p zv_qjJSEmFl;nmT)O*G_U=1#}3MCC^+QS;SHfB%bb-T35f7VxrjNFlI5{)SeOzpba# z&I+g#&o1r{7ZKv7g$NZ*BO>HYQ8>0gyd=V~KimZC6sZIEN(8;o7ICI#?jWnw*7W;u zoqwPC$nRF2zWuvzD$bBMJ@Bt(UGwP=to{AgPha@%;u9jzkhM@;f8&?Vy8C1IZhQLf zq__hoPRzSuuL-j9e21+2e24TUkYm=P$xH6r_Qb{8u6`~l{-~v`(A%$NU5i?&V>Vl+ z-DbWz)GeETr*9P@l#M+;@!iuOI`=DI|1HMYJM*mgt!Hr)^w^`>p>?>dc+zu5$+`2) z`@i<3e|>(cQX(syZgg1;Tlo4gO$ zl0^4j=LeCXyCfe?+DM1FF7s7TEddxuQ$q6aE&dXhzZ4RYQ#IO-B~pwUJuNdtsJ=Im zK#66p2x>6UdR+yKX2-LNMD_0=KvXiRuXy&^Ad@)sQ;MpuxG2h_zOf&D|Gx8Xx&F$Z z+-q)+zEaNjsUO;S@1m0mPcXMJT`rQ=B_0&wD4>&Wdi5a_ty81GNmXiHK;w9okm)B4 znZ|9d#RI~&iYkK2(Pe=nOd73*KITzAS?`lh^Ft>bArPJE!rel_2md$~1s|7N&U0eQ zO9N9*Mol#Ia9?i^b0)bjd=K$)25RXeahQgEO>vh;QuX7`!BQ7v8>&v6^dkxt;X+SS6+_u zii?X0h}87on>{jF)x)6m$j^<>s>c>$@H4P6r$@fyVuQW_s@4sPUx^=W=qVa}0^kNQ z3v11e!sT);v2_MmA|j|!fpa*LuzVD*BC`uTS`CB8duUysX2u-)mF9eswiU)_6PD3geR-Trt*Mna>&pSY+3Ep&*+pggZmLGlcH+n;@IEv*MH7kJHcN;>>-)g>snI^{dK| zmJhKacWn9%IU@Tlae_y!;_;V(DQ>MDZ86DKNIbCA@^CHnVNU2IV;};MXGc-rvFXFO zISW7Ff)A@tL?qM!a>k`TMVUt?6Zn9NBb`KE7h6f+SKJ$RjB$r;-cbKQ=229AY?5NT z8I(UP`;J*J&a+MCO|p?P20_&}iK~cUHjgq})Oj41fJh2OKN}BvaI^)k5e)kJ#(Sv_ z_x8Ieb1`Mi<)7$)5~_aP@(Mn!&-lP`H9XO-I^I-UgMGMl+C>=O8ow~;{)xFqdgDUu zM~BimaUaSy6n*Aa5+jth9@Ie)kwus?*|H*t05!G%udK{4Y7RFA7c|WCXyV|m3gM%E z!h>itSpa*4oU4QiOrT)mxT{1NJBw`o@Bv; zp2YS`D`laBo+KicAPIfas+X2zn7sH2Eh3iv6?PGa(SeVL1Y;Z-e2U^LjD^u0d4}*+ zTmm*JvX)aAmBs=$ETlOy!WW^2lOM-3ai*?%4Gk=(_u~Ba@IjH7@?@qoFyf@SGT9jj zhm@zkC}o0p=7?j{MUW8ad+i&N*XT)OJ){-+W7C|srOQWChw?9NU0gDZ$q|5=l>QeU z4ZN)QE{_z&>@CvGj9K9Yh!=N3}JCy6Hh%2s4)MqoBZMQXuj zez@mTm*>CMzZb~;){0i}epI!>FsN;o6pEi!ss8O>cwHdK-{0tUfhFF5$#x3iJQH=m z07oXTDFxdimunK=N2R$|vXX-JCH7F7aL27xGZK%L$|Wvs4tKvz5X;;V%pMJ`?8fzb0Q9T zn&OGXfEILbEY$}`U&t3LF_u0YAR!A>a2>-o(;rN=O`To4;|63zD!S|};Z3}st&C~3+E_`2Cw3sv!6{SD1@WU(Sk1GefiUb6z*B5vQrl? zZoc-GapK~O_4Zry$WA$pbc#n7YgQiF^ETeA$>mN@Bx159N)Y*3Fr}1V@biNM}5{oAaA@+2c;JJq1)aq7G^` zg)>muby4%k*2iKOJ)9a->cn1)tNb~Jx$gy zL9(rXEm1E4%-%~8{sK0?VPV$V&z4aE;g^*0J8C`Ppq-*hhTqf98p|jV;-NL?Hyrvg zY9!l9)fpR)!)3cdQfTf~%BHzj z2X*)rT?|EsExcB&)MKm^*a*u>vsVpuYdKpva%Y{8EJ0++uj)z$@1Fch8sT|ZR=KK4 zc(G0iZ(+b9>Jk=&LNSfc(Q54#UDaw>thGbCk`Il^3u9|Sc%UdV!8)R-ZOMC<``yvG zjvuht7B3~QQd>oIQ5VrXt;C7Fy-%N_{{TQA}-(+Hse%AKNLY zkRek7r}p%*nvY08frBO1wEL8Lnt5csz)PIuX1)6 zW~)%>Wq^r8I@D1$^H>}z^rv3xXhGs5wnUE+SQ+si)e{hLaE(O`KuZ@>5pAyxI|kTs z_GtL8U?j6PA~NS`$OdIoVxwYJhg~vQvgZG@#p`n4HX|rY&33AZ*YKL!IIPD!ZV0JH zizQmUh>bvnRxjh66DY`FHb|bzOekUSK4=0iEuPBM1gE8)5~PqdVOX`D+CafahB}O{ zfHy0%D2}ecSVFxZz<6I|mb&EA_=m$-w`%-V^yK;gXbsicKfd04-d%NQ{m^>rHlmS5 zjwn(664AdnTYW(k9YhyI^#_TRkBGxh-`Pg^4cC`plme|bk^_?i#ST`*akCEK(EyI$ zMsBSJS0vt_9-JL~aO2>Eg93z@<(h-WcruqvD+-$fNfyV-MJx&pGDr<6SswpD-Ynyl z)F1h33bcq$Ytf)3aQpfHjBidYOo7>2qOw>dA;IWBj1sR4mbY%KVZ_LAC&fpF;^St` z=S!olh#%g&fSE@^7cjirT^;B;4jJQsRyI7)XFK}Uwx&feC^%Y!DIz|8@2cZK%nmzX zDfGw1hA~~$wMAt$d_1L}hJ_dYDioVb1+~ge=+rB8AY&mqXdA5vNEUcuq=gYvD@GS( zvZ}V^AO*_|jn&M8vs7YpC?+LVBcRp}1VkA_zL3{Q=A?53S%qa@tfO(8%wZ*5g#a7BxkzoxLJBM{5sTDt|Wt2%sg(E9&5-K1&~sf z+!b196-;y$#z~L0aoWQQN2&_-*i|9#C494Zv2GqWOOI1}Qc|%U@MAn?0^0g$d}MbV z`I4r^<5?iD#-rbu#F1wWMk#3DT02pHT1D*?GhkC14TLka#=?MY@>?g1_4pkLYB9sk zI9ke3yU+MU4{EVCQfR{+WdDn9Za6kK+|^u(B)29{G5c^ta_BJ`P*H+(2@T{&HwhXJ z#AAbotU!-?38SOOuF>J$B_9UwfPF-bQO+r02RUbHs#$ZCWN>gW9dwO7CT?4sc(d+W&NK~0rWhDF&8{2W&={aISloN! z1u%jWduiv2ya2RU8s8N#Dj}oW@S?{Mtlq5ytw5l;gOWb}m-h8#`t57<^)>a|Lr{nY zFwi_3#a&!+!xoQ5JaJ5TH`)Hfsj^+$TNeQ;t8ENeSMg9S7>%^6$1d89?~z7@;HgYt zSWyA?5_-p{Rxv$fX@CszR)?&#i4k(O^r1D4YCrNSPV8y=vWc^TMw;%J35J#2)G8&* z3gumm3dki1Z#DagY!#VRc}rp`tiecWMOsOmi>9ZXergGRoi@~_>sDCVmO|V~|7*_K z$Dn(O8bQ3rMlhzdT9NrtEY_gI)ogw5Ln@WD0r^Pc2-F#!%f^zHfn}%5XyK_@OcGPn z3~TPzX$2WIS$U6L)@+spUvD=YaA;9mr=fBUsb#6=a2`xZYZQ6hoMh-G=ph6VBtw^{ zoETgU3u9<5%8@K(Q#k`A$Cnaq63h_mjs+B4pDVaV>k%Vi?#k`c{q*e1J1HtSIZE^; zGgmFB@riL)>ABFTs7&i7&2FS#?CoZ~!AT`G4Q<>3MAzW#qq1_kR;~4YXQi&%sbku_ z(iXAax*^v4eoejgfo%01=G{vGUV41Ww0pu_3t6!&b~?xrG1#j-8l!}0_R!D*1hD$` zRrRsn#ozZ62^&YD`gJxL#8$DRl`Q^s}G&Z(sUaFWshJq zPaX=vWb7KWoRzGMnR#NL`}iRr)pI`5gHYsh$+gD}0{h}-Y~rV(iHmhN42^I7=L%P) zh}MyBd}5-qCZqptbwa}1I?*F61ust*t<`;z`{_tXb6Y1&b?>cCK#L_YNgW$8nLaMv zm@mUv0|o0R#yc;|u+Sb0bJm{q?ge?}kzL`HG>%Z(MP}AHb1o;vmU4!f6q8*uOvR3P zWL@e~XlUrFk(vgWDtm_5sw&~r-{0TY?;P*?z@$PDDmst6SlPs_E)B3%vc$dTf>aU( z!DBLH^~rem)JK>0yprSM<&$;E3brijkRXcV?ZcDIs_NAey@cGfvUp_>F#P5XbDkU0 zOS+Q~1IXPFVo}Sbt^32kNXtoxRa!1sW3nQN)p9M@*EKLT!u}J|;@r1O@|$UZkvzT7 z{1ei4K$h6j135`FF@g^cr=^yIP`e&mzgZita>>axzWkte9`)00}28tnbm(?FS)YYH)0W=4(rYnQm zW+AmH?ae|Fy$jkba8T`Z)WqR9uu&j6ur92h$Wr}LpF;B;gA;M>H&;h0W=WL zK+@qfnkE8Mna18#PqVEBnpbC364Gjit1$PDw~Az%o5%B$?HC+CGMP`cG2y+oQ%+CE zTRc5=ZHik2e9?_Ct7Yy`)RUIbajpBDbm+ynoE&)&sxgCEP?gr31pleqEn=TaS$9XzhDz5oM;s90R7TBkO1Ncur+09^1fnkRUGtje9Nn z7Hm;=xw|arlP#o|$HZ!weNfo#I_3WL3z})~bfZ)p61HyIf^{}_hz`93BB2?}ACz?B zDa-QY;GuALPBk<(7-E=K9iv3Z8$vl2S)J+h39sh<;Y-77bPU;h&39z)HTRNQBIuX% znhmcs$C=9+F&RRjodzfb#sea0%p%?c0=YL9n3q}|6sqc|Mq;LFAfzw=03Je^t);3G z1zDFPYDTP3S4IgNEY)CoH8EhBo!j1@qtf{%2Pr)xO%UT-(u7r$IytC?j$&47G@*LT z;11J%jZ8%rUzR{jhQ2wQYhSWcOOlY!FLTnUQ1S%gka z*OQC^^PDPh*PY`qVLaVW2KOTKYV;QkI|iHSP1+d@TgAM&d@%YMZBqiD98yYF+rpQ! zIY9hof)9C3iNP{~m&{+@g8yzn((A=mlTr-=#ja?h`i`bHHi+i@+a2&YkB|KoH4s&6 zF467Y#j;|k-_vSh9}e-fn%IXQJ*^V^lHzXxH+b6efj1;6dN%BOl6GOEpNvb?O1QL> zZ3A{3l^otKTjdguS6qxLh95zYfK*j%6594OWD*1Mov?n>`Bk-#fu6VJynWA=Hi>YO4qAmZvUn`1>D89 zGfhK$FH2D_168?9EHz1)<|nsgG~K_otV5q3PbLb7Z!qBm=Ml)ilK;79(b}t#lQKUf z@Q~+_DnAVlM^Od2E)oZ#rG2-isql=MHoMy#r|dd~PzmjFdQT^o_=ZC9c>;})N4ruo zZ_MY#ff<`!Pd%wuS|#;L^S8YQAH}@>{lD{b?|S#wKl8d*9gyLoYs|_(Dh!Ypw zRl|M<<2=xgzv0H0tE$;PC(2`EhXgNKbWy76Gc#5$#iiZEPj1FHN&h z2?+pkD%He{oCk_;lKj)3vs@g!pR*7tw7*c4R|sC@1KZ0taGXD)s@>mnzxmr(s@`>b zDOE=w|DAuo=YwDT+%wmu>byzSa_C-{s-;r(jfteWqOJOw_nNq_WUE3IBzi4v)$T#N zh!VL3W%dpSXP&Qrjru@)pw;%@_x}68{JZe{jGog z%D*^u^z)Be94o`Nd(g0PBx3Ch8wO?t!zRr~4Rl?wCj$m*8N*^Z0k7|KQJpN?Xv4DX zc!y+w6W&t1rAd|Vpx;X@X=z9VuPg|DiVP^olDl%JlVynoDNc;bntHf9WKFRp9MoJJ zYZ@2=uwsS~OiQe(W$!U-dWnu$$#r5olBc!8#O@wxOvQ8q#x$TJ7*kBEQ1Q-XP_c|L z#ou`fjOn}B30jE#$tqO}_jlICjW$baGg(X+au$dYV!BmMvJH2y(tT7MXWm3-qtZ6> z1~&Q2#4_mQEq3o(vM(j#AVYwrI`m5M8o8Z$jgV5r!I^#3RuxzeupA{er>Qg%%JT3m zg`8p_`^_XnIay=*C3y6`Rgoo^pa>=|s*z8jw(F|I6IARjvr|xMPn>Sz`^sDs`SUC{ zM?#G&7v_^N19*vL^AJe+$KuBG-wk;w1ms89A74}0V&Ogz^ayCcj7^4(7^vn2EJMe4 z!ax&a0me)AuHHCaGC9t!);3XC048cV6Omk$9855g-xg%_r-Zv><6KCd++iLbW8WVl zO1Lbhz-NG&T70XLw1gZfVx=laijruI$lUTgr+8))GFLjq$#fEOxQODO!$pEzOo{Q8 z94?oMmdpf`mqod^JOzvL?=MZkBE7gI1xuN)q~PRM!JjBwadx}-&D*dM{auxK(iNtJ z?9N!JU52$Y@bYCOI^lGwmF>7HQLoPZ%H3fyquN`qN;DWcXvW2}na}-)5CyRo?akzzV?vy+ zET@~C6`2<*|H*(>{^KA*`*`vKtD}5LoOucyAg~_}g7pHv@3lJ0p7i;FI!sfWDDLIS zuaH%-8{L(>L@SLV*_>mDYPR;ci!qKOVZ;} zow~tdj)T%mI;nbalGKFMEcLvS()v~p6oUCqxhYE zifl*rf#fhe%dJ(G`M_);swhK6)eeNDUYfu#-Rc(MPXm!W z`PE;BX9_7`Cvl<}7_KRuf)|S^1CA_xSJ6pf)$^}L02VIHH=;6AX0*Y{y5e1aeIWp1 zDqp9H3`lojz8;>L>d*frJd*^#s{&H?36}Kv(=>cY1~d2ZQk@N( z+K}gL*wlt3XJ%@RjDh2VsWq7@i_Fwo`nj^mOsz>&SyW{h!_)?&OD3`^J6XtBX6Dy) zN%`tp` zTL`U`u@_6vN%uq{=NurunzLVpIY9EC=i1hdfWo1G-9Rgii6g?Q3XzG-YE8C z?Hg5Sw&sv3mOGn9SEWxk#f`3&mQr-L=8)>@+p^KMf>c-3mW{5JKE2?4G^!wS%^}r= zsb|yZs#r>QVU~@q6`|(hM%Ri^nz<+;U8_c)aXuP-=J{y!!t>Fn=84uEr@d7*$^nhw zpVsA{l9ev2d+@`zBm_j2E7^}5wS9?|e`<>c7lj#%d7Da;L-U`?xWuP1>@EoA`RT5l zMPqjB5}&)g;>y~yZF=)64^`&v2SJHV#_XiM@3ZL?xt}Zo74t(6^3`|3Yu1PfJ55;5 z*Y;QdQ!QYyrciVntzg9SS!Gy4;&~WTRP(p4dPizjtBFOSh zpM%gGK{N?)sz_bVktfbSTv_`+^Y?x7Q;W6ySpY*O`~1}HAK}-x{#Cn^j{EK;DxxY^ zSMe!qan)U~S6q?S-wx8;T~a!ev{y2*DL7m#S@6b9``aRI|a%ZQ9jXS|)3ftW)=5VF#1|NoFlRjFB;E z7MTF14#Pt5Kc&^_J?<%Jcrh?^IkM6HxMh>6V?KSgh1s=P)?fJOY8sd1L%1-$vz>!i zw{V5j#3Aj_uJg&C=7Ij?+?hxq>aeyw}IF3y!#<+tf@Xk6Lx@v+!L zXBbp>sdj3pne^JZy#AxtPSx1QVTT5--+R@DhR01Icw3|jr*ird+w;R7jhh!}f`S8c z{hGcB1iNaU5ofh)=YUYxgs4d$N7)`(FUa(#97F-{pPWf%iycb3vNz1X;|JP#fWGk3 zV<d#D**Att}sirw@eNlyBp^9+-i*9Lbbhz^4g17JNAwDc!^v+ z5H9z?S=2n}FX z)@L(Mm6M~TPK4uT_dQ%LTH6jqX={OMI)b1JSlE=eDy8^s+Og>*)32T2^kLpE$&d zfdx@0w!q-ZjQ;SC%K2^i zZP_$~zB#|`WqfH~JqJc_d)c8r2O_mEaME@XWX(f2@!KfT<65EKG^0vrdYTidq*Kg2#(>HN>PQGZ$Ow2#U%16JWMmA<0z(EWWzVO1Ptd&h4L>O*@iy?Q` z&1Sr6QL$|m(RmxZnl@E#%r=?2=@=t5br^FhYYlLSR0UTYO7P$nKO5!WYvDnYhQU5L zxf?VMw&b;Xo5hurSp(ugrdHNC2ucI3 zxE5*B$kjR|O7~_v=&-U?8i-qk581hiu3}ukFe@zs5VJG}lRlo9E~68Q4i+8gVZU>8 zkNlvni5M7+0X&_XvzGBg-c)_sf@iV=*q0gf+GchuOu26Jdot0}EJxlh2f`GAcI6y- zP5BFB$YX4pbVNh<=du~}HN@8)YbePY3WKF-&C!*Sp~u3eban>8OTeA6(rcbsvFhWC0xw7&;)`-_b9p8K`J^4atB=+Up381X@g$NYPYBjAganLU5%w|zL}hFy+sXSb0qZL@WV7jQ$KjA#Z&Z0 zGn;Z10JKI@=2>8l%>~&uiyqDx*(9tnOg)ohOVaCSiqP#^wzjJzp@8<`27~^Zlxvt7 z1DPo_2E4IbY(L4QR1*Bj6v-HNEfEtXGN0IUIc|;K1cL=+d&OR#W8b^9O=7ig?l%F< zIFY0eGJ6vO8l%Hs{iFqEg3P{-^BRvQ4&A~Pkl;WT)@rl=lpU!P0EI+j1KWuEIR2LE zX6-r5o^>!ub1hJszDNu&AV4E*?5+Fno5bVjA5kEY%9J`QRA&2=_3Aci{K)I$^SsGJ>W`OuD-tq%)LF2ozG>tFh@bUzjt2e2NxL1Y*k)O{G9muBGl1hEzb`2lR(hmciY`)wGbzWr0~49ZNTt4qzwipa)$47lYR} zfK!}uw1^9M$dcpg>k{#4ygJi?YpG~@ z1WEi*W@gkpE-WQdd1&Gn>w8d*UFAq+1XtD?cxdQDn$9^Ic0Ev#+2}exgmj(uG7=-% z4ijI33c?H6Rp*G(4LK5o>Xm9trM;Xd24LSEV82}USYW@DtFEcYR093jXl_vP4~5a# ze(f%hwGPa6zu;T2#Lk9b>RpG+rB-@v`5E1eG(ONvqiD(6TWS%F0Gy!rug6m1w@)Zg z!@8pr=F><1K;hI3KXLJ=l-0YqN|^@5nkdfRM%4z)K&6d3-JJ4_KP7nt$Gp6JJ})^t z(lDP|32RBqkp>rPkT&9e|A%==%YY0D!6#M~;Oo-Uw3{e-y^ zdgCF77yAbI#p{I7l};}$KYhe~gz2+8AnMczb=Jxb)LzeHhC)RB66P@C31M261izbO6Ux{XBz{f zlUF;p-e1^~#siLSifbS2Lr zS2yI}DwBs`-jt5RLY3Wo%nW;}%D-a@*Yl+qD_9067(u=(_lZvXH@sN$y>$_hUtWqY zDChJEJG1BjlmQ0!%GyimN=78)_p%=4OV96-T~&@k_q*D^RA;KX5^ zG&MId{XuB0%ixq(0ydSmNsXErX-lbijcmW1Q7nV`DoVpe&EWe~PyUA`=n^w#V~QUq z5SdGBa%S8Cfx|*BGIx~d8ZCiW1&?+AMbmSE>IgqlykY+pre zlB%RicwtAe4!?zn>%RSpm`+aLu7FT3Ret(s397vK)Y$D_TktF})61*%e7n%6^C$cP z0siZw@BfIVc9`X{+ynPd?Md-6WdNDO$!|Xfj{Meb=BLHXHh~Pwr&ssu+LHu<8u|M) zDFg>%Nj6{=7NHN1khz?6CF&sG)xBM*eZ-0BKGQvYat;Abs24m&!xbLx(ZriJK)WAh zrirR3@qR;U+)4>$K5dIQhREXJjU{_lU?WmkqcAORcFad()Wfd@h_oceEu`%0uhW59 z=nI*v2Ua^0Qa5RN)_<)eTgDWA1@~;yWWGjP9>>-%?QWo}@>Oc?hkUD<>A8Vwu6< zfowtefdv;?RjIq~Ys5}P^2xg_HEkJ6TYGpsb=p#9KNB4I0Y6TQiE$CKZFj*$wXi^S zq$aLKz*3jHAJroM(tJr-q;q$yh?NDIr>VujqQR4w-6v&X`?G2}*Q~?M0K!@dZj#}P zdO}w-bE&|Gl5~V{Ln_qFBM8G~196TpExsgvhozc1Rpzz*N^88%oI#5;nf2Qm#oWQE zv|I&DO%AKS(%p8+RfD7g%D~8PW?J%x(%|2amNU@FaKSAoKYzr8Qji$N2GL`99YmsG zKgtTpi$vHab~eZN?b8fAWh<7$mmZ~SmFfN$KGjDxYy=|X71a+`_}&0{_ODG zTx2zNx2I_y)ffhA)27A z`K#$ZIdPFM$_**lw?SW2Le0*aL1$D~Y61@F>iiX$&9epr>#iD(r!KYzW~)~?oVCK? z{Gp6$xIDRiH1RiQRl>3!=2;-Qw~62v-ljR8?rp-+?rPR@_TlDBeNBtyMmU=eOK>(* zcQ!4=vmrQ|@BIyPHg{$y~!P(T^>X2nCEbq?dn4HaIj$$(*?rbKp zvspO^-Oq%LJyle9fySP^C@b%5>)s=>weRe35mulY>ker_H0g>n{}YC5(`}hcyD)3A zCB6~pV7Vi!Kc8;R-}IXdIOmRX)=j7nQ8pM?5yEIAF%}EMuYg7e5kP|$TMV8$Qa-!hU+SVS@gomwL&Nk2@bGJPPMrn=Tb=`zXW0%&p>4|PxmABBZ5v1kJt1xw= zngZ(K*B%EbehdS}OC7H9HONnYK#*U!6mp!FqRvUHBb_odI_fa9y#yO~TK$Wb)?WoS zj_ciJu%TN@=-6}pb>Q#*5^(%~Ga%dEj zJ_=l)auj@zM}cF!icvJR6JZH0K5e65CF}`|;t{>O3@u2mHb4tjzeEcnvT_u*>{M|k z>2g*viZLZ?HqJa|kZT5a2>);$^s+i{w>qP_mq5(wJSO?ddn4On0ov-EvN|N78`0M& ztbWky>)PZY*jB+CBji2ZS4w=1He(*I@ysxbuT)}|?=gP_?XaTETRg3oY`l*=OdyYH zSOUL=8UlbVIN+J7D(mU2UV?yU|B^DCoi%uhs?PQ$UcpOqBakKSuRgEdB!nt0#3FM{ zN%7R|_*>)xiTv%FDib;;_P_V1-}upA{P5#nH6M9`i3&DGFn|e-nTgKDt6CL_JWj9=Fw7@(I3x^K(92A!7q3c$5K(Ncx$HRCEE`%J|IFkk)kPZVH& z>mTeZAw>SO6__9W((6C=`M>$~-?!^#hQMSqT@0qpawokcE#ZZ}dc!>hc=f(Q8!3BNz7vlCr_WN$RPi zOUkyKvYVZ{^x-H7|cPTU{T)({g`R$M;%;%`zUwTAi&8$5q@Epdzj$w{aqp}&?%!wz)-~?^U;o*= ze(Dn+_{7T;*bk{PYQ?H7s8?*q${P0x5clIUqiz^Z-%}cfcT^hpLtlOP{y%*GmtOyw z+6XugkAQP6MVG~=rPK{d`Pa{ay8lr{_vHIa>fT;a_or?zneZR}^$oxEjW53Po&V1W z;u6ZoOlb4wF>%jTblF|GEO8$=3*tT@(QQ3dMi--L7HZI0a`lHJH|Q$4k5pJUAzxWe z(UkJ-3a2R|^0B*15q@Gs#zmoZd8wvpZeRySFo40gGZ)~ccJRWD9MjDMzMVOL*Y`YJ zypBB_d zxqB%q&bk%(YbL=Jac_jUYt4(1)%$1#uL6i*^*-~jUwh;=55M;{@4RgUm50n8X8e3HpVf!&=!)72}YPSV=_$`xqv&$>! zhz0iL%L(j_rNDCUR)iuXRdWZd;7MR_ziV`aNvKleF%t)dEMu)3&n&Q-;0^OVtCZBE zm416-l4@A1SpR&Ojflu=typd-5w>QYOa$%Puw-mI&ULnfBX|)nhJctQXz}9Pmf^)^ zTp3WOSwP(;Gji(c>;mGiRVMeR{_1xN#ax0lx z^N9F86`Y@Ym4#0-az`sTAOG8T9KY{lfAiVbje_&eK{(A(UCW?}V|h!-i(@D9K6?5A zp;c;SaGJ7IHI>nQLP66?GnJ9&_jI1`h`@Z`xlYTV;k8#-8$ecXY+ZRnqG+CeA3tsS zId6|5FTRJ!``UMpwj`CYt;kCtQq9Ci!DThK7D7w6{Wc1XCIpraOlJTXRDjG{p-M&p zQ(QUd#zIR2w5XuVG(~yS-eR#+uG-!4^?D;=y=S62YRBQyq+IY}Qr%WC@^=2#W5{H_ z$=7=bRMVY0qd1>tI*T{3YI2F|t$7t|Z@g)-j9<*$C(P4#U++sPELHVbM)A}qd~9VO zk14+B70v2bajqu$ahN!sr&$Cg752?o0z>zG7ipqg-!kXuai4r4BLVRrWXQw-hyT&e~{|@hcwBn|ui@t8>ow)c+Qm zHsmMdvUmSNE;>6T*#2ZETXk-g1Ef$V({8P;KeC|f$@rnCT+ZR>;#Zd0CXxtUb{na1 z2nHCv0I@x2Oc}7BL_aup;EPAKa`o#98+PZv zAoO(awmV3_HMZQnZbb1mXPGw#m;OZMV#$oz;Qz)j__$uh%Up;S$j>-NEbQ52LA0*N zR$Zujjp4lJ6)=b|afcP8dp_p#5KBypJQv}l^7V&Sz)(cdjL7oiHyOU3a~$sV z|4|`46D~Xx`A>_5edhclpZM~-{_@VB_@(!bGQibLks)9l^xJJ|wuZD)L>?(-qcVwb z7?x{7j!I-2sPMtq2^94KsycwtZs1+k)fv2%rJ^wnC5DcPD{0Tsyqqvp0Tk) z8z#jbsbPI+vwrzh{yr1*El;gJG;IK@1--a}R{TaWh0w@9;53$I)I^mLx3T}>FTMG5 zCm%lk&HpY4PKxWN~q8_JU5E4-39Q;gj~#R%cq)58%%H-Bsa1gM z?uM!FV4k#_W|Z>A6t1AW74=Y~RM&;)q>a9%?DC~g7BP~$iHBUsH8nqGdSgrt%wl0p zVQ`2=3S%t4ztE*)rJFv+Jb>HGG0Bh{N-_3z%m~29HtQZOfR7i@V3IV|?$>PSgeL}e zUN1NRzV602d8b#J;akE*DskIiLl_>ll`O8p2I-k!U!2} zJ0lRQL_skvVzXaM@L&sx!yrH%fnYm{^u{Q9lz7NAdgHCpI{UuHnLOA(y7!}tH8l2L z+UH0QHig*b4kq@yO9Qe?b(W9vHdu2fFW&HlIV_~cuD;;V1}=C?-qyd24j_2rOiKZDP!6B7vpf}r#G znNP&Ibu6u&b6bTrqh0ZP_olj_?;?f`Q!L%yX4WU495(MIrL>=HSs(W_LTd6*ggDS} zgpYg5G}#g-cX;Po<>cN_I=R)(wc**JLNl$jK`n^qb%lR52VsSmu?jC^gLuKxm6nUpwZe-5!rngL zAQ@BMb-m7nX)9a4S|8`kn)YcZ2-?qJ`n0eKOTyULBCH#&wKG~_H{D2C z{k^l0)peuw1mcl(S$z^6%%`E+8>#eSNBAiUwa(H0hdq%ab;?K2LZ__T|8A+!Rn zDk6OP*#D=YPFZ)QY;kh6?(!PO|6%j(NVWICS*X1y?nmI+0M|bLUt<87{4TZyucIg?Uafsf0fu?m z-Tcr>4e8Oeq;0oGkzGO)`Q(Q2iT^Y|Ug%{@9BO$JEUl1c!qt${3l-DVEb-%!F0&!1 z+$Y&?vC*RYka8=nXU3?OK(UJD_KeDxTWR6(J1sNDDo;U(+ZtK0)Q(TqkF|Wco*6^C;h%cq zuF=}`AaU0-W2~CE>zOeM85q4VEO+KL$p@xkr8A$!&e8&K9WV~jpX7kdb+%F+@YJpA^~jPWl&|1)2BburktqGk*;~(lgL3`&y0a;bld-wXU4FlpTD-HpPx(9 zvFgki2f|Z7Q>#;hTFh$n$^5|iH>Uh*;YJv;Q*Z-?meV-f!=*KL1XV`|&7IMUygD|` z^+DVqljaB}g&^>NP3#nHN^>%S>)kId)%^D2= zvC~_2RmudZA^b8z1CI5z5=;OX&l|exhYTBd*z3?gDV58pVep5{lk(H z9E1!VD+zz2`4H^#*gSr-7n?q%sz?uGecdWkh^MQ6n4%F3U&Erwh{_KTtMOG)u3=wfx=BC3O7BO zDAZ}=3WeQ46waO(6ms}(WfX$AfI{P@GjXBr4KXg6^m-H*E%?W%9Rd#WX2 z$RvqD!XJ@(PWMUR9^>w7T|b-VE=4X{y4DL|O^T2_mm^m!tZPQyQL$ zYyPHWVZK(o!U_Oqf|-{Nu!YfaA&|Wm>l(qbm_(Z9b}othmXrmW<}qF1=b8riDm8v4 zO=C93u3_UFNe^UNII4+yzAY$fZGCek!Z3j64+^vaOLPC^e<}H*7-xRG?w1H|_p!zo z@(FkG^;nH15}{LO5kSWZQ~u0vCt7YfXAxD%|e(4$)>Lo-#Q|F3-3gG*=_O^KQ ze#zfgLoB=+M@k{eZmspWU;r~Au1Kw_CMm?X5c))KSmQ={xl(yxs z8i8=o)~-#Jn0&f;Zxl5z@Bao1DHYAI;`8`@&0_s(P#Q?eJ&bf-8vnhzbZb6+0jbdB7sZcu`=iV4 zzSsGINAv#ZlAe&woR+kXm`P+b%g#O5ga7(UsDPf~y!<(*0Ypyt}u-%@Ikzo$N zl%)HFwq5lb?-t&6)n9Jrgv}a71r^?KH+e0J<~nL(SN(^{>BS|sK3uGBP?&*RblF%y zHG5IOhah5>E|iffCVaC?QO!du9W(dOt<3y$`(|MQLOkHF;o!TaB;`i9M48c@oGB8! z{nw;STh%SSaB2W#pq~$)E2ZW3BUzBT(>-AVY6F%I5yrYjlSh*3y1-KtaXO*XScO{m z3vPm~-Q?2R={lSAreuh@{+C{JYURmI`PT~CQV{MOt$FSc_a?kDs->*R^{siWr+A^b ziIUb%O$4~ITKmX)*nxU04ZG2@;j|Q4*TatG!nQ~pgs3H9hl#@)qwqgi*l|8kxE^){ z6S5w5ls=tY)%CCg?_@pfs62Gsm&*Tp(!vhKMXkZeBdH>f8nm>tV=~6NdcVdKjX)gtH1m&J;5|`jo{C4_wgDN{*8J zh75osmMdz?%*XtXLL{F|Cp5BL#$n>EUQWCzeO0ugqbTT1|FZGrS1dm4vl(i_{m*C~ zajjM?KBPX>`jXJ$1I3eX+tA^>su4N0G5PiBVTa+kYOZ7guY;kr-_r--0=>!oa z(pOl!0Ou>OU4Zmx?c&Q~c`@0y_1c9kyt!YXRSa_njG;+x9k~O=y$oR?BYMl1H2gi5 z!kBi}doQh)>0$nh&@*o`&dz871vR^`6qnh$Kq3i?{Q zD~mkwuptYwbhWZbY+kM8)454&u_22}XR{%z(ih3V)+_^`{aM;krt6ko5!6P5#X;ka zmG)-q%`Ry%-027YFfq3Yi(7? zmyNz?M&axhj4ataE36WK<tbf`+7%)CweD-3Z+>8EjKY%>Khmq! z_YsmO-M=@PU<2vI0-fRyk7FSCMQ&0 zN)Y`yYq|t2GkVQyu7)&?H51i@vKFeceX?MARD>a~tg?6*^MjDk-;9ErUo{ zG`_Rdqe3g49Selpwj&mxzrX@w22-b|ry>bkH4_(*+j)UO$X#M;yXr?8y(Y>e0{dV- zQ7G!>Qbk=bZ&PQbT+U%%ERZYcUG<~hptQ5yT9~2vmozwJN!TDyYl5(B$WDF$m}WDx zB`SV|G#QT$NRwHiWn@UU-~cE>ABgS6Z2b(>s}eBCC;EMNH~>oz&# ze8##>UX4{+x5-+&wAjEbgxMW8BXU5ODEh)stlQ-OcsBVTLddbyCja3xEl$43FJ_L8 zuZgEPq9}&yH3mcIbYGpI+5%}V&uww+Z1}l;59Wy2)S23(P}`gkv1-VMubrGju906- ziW5`Z3=as!hEMnAl`TVuAJt6511*|neoz;PE1GE#YEh}{zS)>XGh;kcG{Xi{`LpwB z*RpPC7n9nF0=A8jU#wOmc5O~G6dux)Ce{fI2kH{Yr_J8r(!c^=V*RgP%m6Bv<& z?oaxNx~m+~28&&onixN8=CgQuU|@ku6V*_t%1{n}HdZ%pPc{ek$*6bnD$i7dDjg=ElW95XCMA)u<LSVMV}H}wk9gL9At%>&o9)L=pjzzn!nB= zWeZphHmcdy50S#AzBmzb)%lX>VI{ID!)$6YJ;3a2815--SH`*wP7eY0SUw!FS7ym$ z?0_TRKqyuP0cMimj1RqvS+q{)>^Wl)`^sM>K~(El+V7X+GM1+|+ilxsNj()fk}zyU zIr?tQJC5lrC&$7zNzUxk=ve;v<2ALITALgfzbffqSan}Zo_6oHA)q}~@A1c(ah@z{ zrZ-)YmNgrpX6x(+YdZ={R_iP8!l=Qj(A@@?RMhT}$H19>8!USht7)K+^y>)@R(Yp{ z>U^yRYZ)7=!Ja3|j<1@sFi1&RrC?cpu$DUkFK|$8o=Mbf$F7@q&V} zcLv5ccDA^Vv{QlW#;V6x)?CH-&=D(8u(Nc0$`7)_8zX2=?u@g1W1UMBd7W7zM{r5W z+h??4WzAJ^$;whNf=fj4GHc6BO%lOme)mrmaJL(^yw?7BQl*DE)i~I%dlt*AuCNw! z+x_D0)XkHg5-v4aAG@iSn)1Nrkw95VUF!M$mR;#+TI5Tr=O?uhU*+9LWT|B#A8Pax zm%mS2EKJeKMv<__>ptwuES9m7eZq-tH0C^X%Drvwz%ZU7HzHB8r$wsgry2_mcKd7f zv=J?=qb5@&vn21#ExlALoXWeI`VM4G6aZv$GikVzo6Kt=UmPKLmb^r+j6S$kjxX|S z>NiXG@wE}Y9+*>vVYTX75?5s*gNnW$65g^^oR>^dhjHNja>By~L`&JYQgw~>>Sk_e zDnIgDA6cw*A7s9xhJ&vOj(Y}5QbLAuP&SdEbZ-ta-Fpuul>M>L)0p)HO6$dt(_+Zn zlm|w#h7Xw!R%eEXjH0p8+mO?JJhtkLvv6Ym! zi`g7urU*H?%_yc_SB>ZYFBkL%amlQ9J?k(oAGwVy6Bz1oLZ=`nfS2Jk!Bk&k)k~@L zLD8u4l=sM3QOgXJY-+zEo(o@13v!ZqD7S`zAEaZ`cHpg<33(Dg4UjQU>WiogA{9^q zqsT?AZq~lL-=%6^@6AX&oe-uS4XREBa5mGQz8avX)$L5y!MHfkT^fT5(;5u9&L$n< zS$hyxdF9k1>s%criWLZ|t-QXCrTtZx)}Dp3vbjyuhRx z>Y!lf%u+pLSpP|ewbPV~2t0>CaE;P$+WfXOQV*{UlXOdeGG|S?l}%!OdZKhE^z|Ht zyzSnUxQT}lzI+I=0$=r+&EN-oK2wwk|5>-U0kPPa%`o7pUY9lixx?2D6p>=H!)wMv z!qHULJHV|c&63mByC&M{K_Wh zvKdjb1sIb8v-1PJN$5z=oxCk^7LL6P#^_Qmv*&&otR}qVH!k!h^$-qiAs;O%fUPt+ zDV^F0x~G$El?rMVWz^`Hu2AWuKb*9tsKfYMSv%{>Rp^=wTgNHNRUF<`x28#H1xZE9 zy7_G{Td-nvZ#`L?us;~&S#Jv7oYcU^vdPd+(tS*lG9~#jl%#5ZO1eDJaRl{c=r_w? z{+5hDkCcj2*@RpyQ}A0+F3qB1=sk?cl&$Nt{SR(rkPu_!-vq+@ zn>6UG)7#V`Py?X+vEPjSH1oT*0-cm?gg{#You)dH4_6ZBQbR#J;wk{ey}D}20v{9dg!8W%&-k+m?{V_ za68#HeW)X2TlKNEQr$o*iUP%?X<%pjp6EPD^2dBL^dYaM#Eevw=CA&7@L-|Kpi<8^ z(HsBaO3DbBsg#q@LQT)QbCAtS#%Hrlt_x@7PT9D+;KZsr-sq4@2e9+ASw|R~=1t)- z$rq)rF?;-1y-^vdoi5taj2OOx*qDy08f{) zDM$t5sSZPSi#(pc;!tmcSMbNka3||(niR$842m3!AUB0VXc?EMWx1`_z+_&(UY6UU zqRNd|n3R{o>1rpJi?@xk>em?~>fT;60htl4W@OeG1&Hz?k7>vte4*d&)r1@TOdobD zl*=bcOo1u!gAYB)Z-D=(8!!;+_S!%KdNo)np#b~=8W+ZGP%00D4dspml?UX6az_H? zhOq++z|r-7H_#dwXql{cxqd;yX5{XQ?GV`l3Nufp5#vTwCmX;Aas+dMx2c1$5$t>I zT)!*+na-vzt>JK?HaDOZP@5YNrW$4N-fb_l2Q#iqKr86?l{^%%0&bKmgu=h*ZO--U z)GGx4>H4sUxoqjXJ2_#eK-+L3y8(ZYrUL ztMO@ZW{LZ*w}RRl)VgMZsao__)pObp8DhMa1AyAHPBO#yq-=BW5I}|0^R$noR*h6_ z=p*GBZkas8Y}#SMI=N?OLk<)f949^_qE0Sj4Y$p3jpuxvs%b`FB=-S_HZ&G9DupkB z^HGkE+8T4HI^>i1n4s+NXk{?A1+&x_?w}&Bezt`b;9Igy3;o2SGsPB#M-! zdBmIl`soK2Yxza_k-z7&`+;Dr#F#*K?HowPFx`Td6Ty1)!^_6hs0TNJxKpHC{%7;- zo37*Nmhh=4oFocv^+0qN&cjmZ1H(7_l0#ZccblnAVu}CBoHNo2b$YZT}NRQro=C> zw%*)&cfb9EQwg02DW$6e*(Ctxm$&G1(gZ~>P`e0Z&1OO`66sz| z3N5A!9)q=CJ(tWDSq086HZ%KPL}veLk=cZ-R1}$g>l`98q1`=qIb^9#ko7$%kVz~` zmPBSA8HiqpY808Fd5bnYGE+dXd}J0Xmyy|Y@%kAevuTUWm`|AU$ZR9Z-6ONm;*6q_ zDUZyi7Er_8Y|0|DsWLK~F)op_6hRRpvrw}7$ZVrWX4AkyuZqlOEHW!GXptGgp&~Or zs>qDEaWFCqeLE2b0a;~aR<^L_kr^$^ix`N^kP^5+kr{r+G{1EA2@|9b^F=zUL4nQY zsB|)$whwEHI_87PgIO*zqg#uX5au{CQ?WcCHHJmu;|!76zgc8v^1~c-CY6^;m3EN2> zrUwmOHb(iX!_kseUnyGR5I~!^!8C)BXjm6^`!{ zIV)7mnmgO+&C2L64aYDx3ZDqaBsEMR!ltj#>l3{#AspKxkBCX0Yat%mV;~%}s%1Dv zC52;KJRFWTS!+#gfEp{#aJ_4B?n>Oe?~!DjXXO)2eXHH|7-Kn9a5jR*JSE9MdSP zen*F6M)VD$)dm?+h76*7$QFTGI5yq0MKy~;HS8iBOJs#D9IGPHDfzTr%w@np5snc! zBPkY+X<8uwPk3ccuZ3eOufi^sI}%hLkQ3@V5-5k&nYEQS(Di;b2LlF*a15;AMHsoe z;!uTS0g4cg4K<=V%r{2(z}NL~tUVNt&17x4qhdtchrXGp9xX(fg=75 zaO?sL$4Wp92!&(nW&i>e-uAM1paxY>!2!As&Be^AUduKM06`o-W8CA4#^5+&FRG!$ zXAmxwrbS~aVFtF0#wa!CQ!xsYm>{)7WKl$8V#SuEQ!5P6Z@NI5wo&0SX$ldIT@7FZ zFv$qkLNpepiKZ1OiBIrhBGi{g)%Z(o+K}9`Qnl!}Mf8ksyFW{x%Fj({-calc*t(!M@sOuhSXr!5-m z6yp>|%%PA08{nxGoeOG@>@JMfd<@Ln&}e1*WR@7~1j@E~5LKPch9FEfY?#f;%1Ghl zvOyRYl7EwN5M~B#+So*qHt4Z=$Z4!;i+Jl_%(Vx};y(poR*7IBa3c_Zy zEoTnGuwg?%7_TiCgrRCQojt>UHsfw0176I2A!_0zn@2Ps**tY~%K9551)WU%OZ92l zGEFxs!bkHUHG0uRg_zDOwNy!*Lu>|XE8s#FtcPh?|KK4?C$ehRdI<`3lG+^{3sx%S zu_%;xe+vl%n@HxAcxsBN0ZnR+2*N&BPsUl~^?xF)SX(O(=eViDN63iTcwvLJ9R}z( zru+vsRq)g{Rj~4{MQi=^OPsylgal(ev%9gz)^0n6#7Vn90(=I6dLqL&ADGW_I|VVN z?;v6ESWDFLc8YPv6M&{czEYl=`JwPw)!`qe-Lm=B#G!IrE%7_678s zE|GGbK^+rN$R&?#Die%~&w6MA(-dayYz|0f!nahg6ec~P7d6v^_$OHtpV78dPk9uE!lbm@G){-BK6}{6n0aVf_~!M34bbihv&EVcMF*NWHAhm7+SC)u4l*#WP3vu< z8@v{sIbcYNG7Kg#(m+uPF?|#$W>&h8O%Vm`tOyBqDl}Peuqs^Dco2Nm17HpsA$iuO zpBOqC?a3{WCvUn{D%v)Cjr%ODuPn$u6(EK^61vm_ln?EZfFy&Hh0X(t92)>91{AEe z?#TF@Kd=%ESd(-jHY=v0zlJP>Znl;95->Z1dn814?d1>~wEt{Von1b+Hp-c}i^{9y z3bSzLPmHtfe)C;|?z^UT??I>Cnru#tk2UI0Dal_)oSk@FVcB6aHY{z>!(Epue$ z!2EEg*G|qP`5h_|9h3a^d^K%huOH)eUZw9nwGZe!wGPi29KW%Nmyhs0C%X%Ok8N7$ z{%*+DjE}z9$ai=o#*bs0`f2`5&7$*hDBq!P{>Hy4Crdkriue4{rxwY;vtQ;1HFJ1Q z8DwYl^^Q4dt@-pVb6MjcQ2*cEx4fRWRP=ftsg?~!UyAFSXWCQ@7woa5K4o+OP?g^G zv%D>&?Wgm_?w<56jfg=X9T-jiXsEiKm)OyjnCVOM`@xV6x)`o0B1U=toR5r_=V=q} z^Z6pfM!)U|;G;wU@N^vk5>WPrwmoYuBG5KBNJRXseH|Kk{^?Lbx+4r8D_LwUg?aAM z3N5=YlKiMBnkU`gv-CG~b97FLj^F@|gVB^Y*)B9lIf9FOKsFE9%4V{A1`aK`^25$B z#;{_ZGjJ$LZN!-$-sGHlFN`|KnfIu~IrA>Q2F`Rsa?g+-q~X-uq6

WejO&|h)Vla-k|`94sj3>dV*tPkL#6^^Yu2pG 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 z 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%0A(0)2jA2Y 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 _{*L-+^^b;PSVqqER~ZurusyqKq4<3tm!mf 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 z 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 R@EV##%=Od9YW3M5K^Vb=n#@W3T{1r zPRvX|14gk-zBdr~i0T8%LRFEF`eaIopSe&o?@2zYGTqR5h2^5@o|)YmvlYG%15uHx zIs_{et{3VSNL7JE+qWnPrQX23ig_0b*_3WBU=hg>o&1sj#ZjMlLM% zHd%>dGz>9}$Dw0PMXlj%=@?dF?o2v{6htjWM0osJ(lH$Aqji~djJi)N=op8SJYW?{ z9pi9|aNHOj183A&9iyob2g8Y4!jvdHYOg_QpK_m+bCA^bqtg;h)iz{LmM3_06^W&2 zg=YUfZY{y-VvzWkVWP!!bw`nk$l2^p#l7J^x~MBeNnuan%N(aGFhrR}_AQgnDkNzA z+b;`z1}N9eq?ib)ECUf$a~Bt;lkAF!WElv;hi?T5qt2*WXw{co70}08#r{f*+i0Yw z$B!m8AYjFi9x$nzT4sWb=%=2CR?$y~6VO70pv*ce{t-@6v&6L5QAw96%KKcVugjz>kTmtJb|B@_OlYi-jl7B_sWNt@ph0nNt zFh)19;Qz38U{&_bCq+7f`J~npm2eL7KoFH@;2P}WX!UhAtK5~lUxfV?y;GPEKcr*o z$0aGp_3U^$3{asg6xCcqLYs=>a9!KYQ{=!F((HXZAi7>K&gGPxs8#J1Iu7kpcl01j zH_r1RPWL*Cw`>aWmf^ux97bc}DTZ=3`Q9TozBRPrsY(oXcc|BgIVU2q0PNYo-5(at zt_=Y%LGnyMF{%r^(4=&9z(=i0jtfcJ2JXuZ6uBqU6DHdGG(G_<`)7j~5>Wb_wc9e6 zLMpWn3987drJk-LG0fPnPt4gW2Lr6BL)P^c(S6iUhSy&5wJv$_Y)y|?PitVvy5(m2 zqPzA6%yGF)%$2l9fb=Ymst*@ZNYWDkN_xtKc~GIFep8pLcA4q&VY?Is!5OjY4bJyN z)Bo@pB0V9LF>4MBE1Oh&Oc5Y&-<$36=a2Jh=9fw`;v{;lqRJ`RTKdlrg}Mjl@-oRK zD~EUB@liCJDV)^byF5%~dkS!QgKYT8RE`P(lD%Lsp4{>|c^w`%Y4#P+3Z@q*U` zY-(F-@$?}IzyZe!|LUZ?DfyTzaU|5cH9Q;UXHQf>Xk^aB9u$*c4CAZ~uw`yX_%9u#nsJkjrXuX--<2E~j&G?A zM}_47u%lx5$WI>nVN)RiKj`jAQXU(^LSQqMHMT|TiRV5%sZGmh zY*#Oo`cVi0>W#8d%=7R>%0L0|Aq032@0N*c@*x&StyqtG&-ta!$r*@=Yg#u_*D?!t z=<-;G@U!d?rLKhv$-ESp;SuYM!BkS$GC8J6T~mTuQ<`(T*%U74lRGHokfs&yJ(ZNVPFc<}cW;!0`2;b|O z``4SC7Gr-owL90J+P?bK3R}xN(AAc*ec5(0Qj1qfSC+erpw|oK#&7PD=fZC&fdYMl z8`sT+@CrD!xctSV|Ge;01OzGIlP}ut(X?Cn)a;?<#`4OcZ~b&70ex>Kl~VTft(kJm zU;phleZP5=a>hv`w;hatN<_;x#P0;%mGm6m(VoT~1i$-Rg~-Ldw!5*+E?^GFHwD4O zG`8ehe_aK%etnOI#jooby9#RQpBHc6uAJ5RtkpF9Wshqy(feoroNTYvjkE&_; zkrSVJ_oohh>AjBvBtb!wKGhs-Co!1+ucz^mrochVh3U42 zS@NN@v6v-^Fw*8cYtt&m+v71i&b50xUrFQtkxM{k1sDW?HGGCTugf*;itrm-Y=T%Y zPp;)NXjtz=BNu^Jb{9|dPU{2GKXm6fo2NyzBzs0hrB@quyZv1|hJRaU)x;c~D zYbh%mowFy4j>_?|I$F7)|0Wc7DX+b=q P9{jwFF+}f_6XOoFuw^xPAWY{(;`VMk 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

l*E$vGr!b0mzpPvxmv|Kn@YID>qCb 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

V_ga zMv{7y8jpo50<}fPO;Nku9ZzEEr)Z$X!*T2OD(^pmTQ!Gc(GQRug5g}`~b!3gSymPu;iS%hnlYvhG@RJ zs7hF@lqv7>=If7DM+SFF(-r#g@qjHLn^0@QNXKO7kVd0^i?|cF>(pTjT zGSHW)@=s=LlE7q~Q&#GY9eiFxf%Y231P4G3x0Lh7^h9M9TbBHA!Y$Rr1Hl^>O)OsT z++YTR4vXn>(1o;b&Y4=4dl&f%x|!ITCaNKWqMmTS+4GG=#!s* z`>^&&2GeT#G=8Fek{y{pymV@__c}=b*_!3VUZF0*_q7oeqt}0`8XL-_J*eKLB?#jsk*mB#sWz6 z7U_^OT?J5@8G@!gLetD~gO{h^nH9JKcqga=O7QZPlz|RHS&iU~lr-om!^ZJ&mu$Hp zIx;3eu#QA)f^Ms66@29egEO>oR;XudW20x&gz1ge*A}fSp`iRWW5X3Lu9g6e8?|Bv zP+-bdBa#LQY(AA>hRFhfkz@{bb!bHJvjMX)rB*}mDUH0; z)VAp3SGbq_${MCA;pPOIGDEa#s=wN`>W|r;RU;fBxO{)w)*+#g4jr#jl5v-4+&*@0 za&{5UnLnShVSDNLY@_$|SR9^prcggZA$zS?ciPoU+NrdQU1y4;9tLO39;e+>F*goa zQj2kbS%+vLh#=0SG8+|{oTei^*fUlWG|Orsq1aVp-9~yl1|=S54u+Q1LdOCREmVPL z1KbMWHA+JywRABdmV%eM&r0xI3wei^m?RRhsD)IYn!M0URHgT;xlWk5_QQ^6Tw)bJY>MAa5a2q zC+o;iila?3u&)l#FtkODCSrT=FDBX?<2g_TfH2cnf!&ZIa-jF%Jt#d1sj$g z!Cpf%uVQcj7y^)K4wWx2VTnmA>+wi1 zX(jZZb1#V{_(R+HsA{r^c>Ts`XQ2m(=I#hJ;gN z*LTm@_1iX0#g&eCv48CPqh?mWesI<$ql80Rk>Nb5AIYg;13dao`B)scXI{!U~V{2Zkl2O#CcdisvPn{<#dC1pYF7rhTdmft z*{@nDY5EeARn8Jqy;$h0e8DTfz$(wnM_`90bG%yoY_`hXi8ffdty)>-BtHy&01NeE zaBb91Pko{_vu&W6ZQhKpj)s*`p)TozA=a8<6(clb&JHWH7$#k*VHRvdw&j0npfJw$ zT+2gfA7ij$6=~d+M7kH2M+Q|6xM{FVvjWM(a*%LWl3er&J>q9L$?ZFRwUp#Zl_yB@ zvht-QPbxoYl9$bFCyIftBqUFod8kPKlGBh5`=4 z@-i+=PNW^rfhr47y|@estSd00Ajq!ZMD+*<5HuSoA%y|C@cn}={n6HT#i~rYXlURg z+quz&&qt}I#c{W)si=2HQGXnqZWWjH90^N-oL#%U$XJ=o>A}|86FfZVbWKsW?7mV_Zw@gIp8+S(YqP4p$)lI-9yno9bdonxXjtKOm0eeq18)5I94)9O=S zZ>P%MLfxvj#J$6b@RsPABOYBu2vYF)}11R4_1BBd$LAa*Qr#sr)(HrZ&y z6%)=CtjtPOEb=J`&8UQiYm4>lai)$!Uts0!6ve=wy3SF4Vm`^C?&gjIemv~U@-@sA zqH$ypOcF;DM1t1C$oLkWtU$j&^F~8A2nMrT8#RzlVcwnMBeMi7m}9EMy{G^bu}X_6 zwY2#i6BgCEP`^$9){FNN3R4do)4+|G(V~m4yQFp*6?hbn1Yvs;CkKnS0*ia#hv^v8 z2U;ibf!@j(=)pwOF`@kW!zkG&;R!{@rdwf|VHM&|Fl;2Mi@VtvHVBu>dYkH5s6VdT zG%YY;;Lbk^XiNaHoAXNZYIas_F}{ogU)q^0^2=k%|gsTNfJMc0EDR7 z6$AkEYQe`X7h92WsUI!nz>m$V^%4er@h)e;0nYnAh=^UZJ)ab|P1PqKy=eGH-_J+b zJIj28H_cdmprs$+BdnKYK4L9l@FPi`ghSkh5wgsO|82;J@2Ngyq*~^~UmWt`UDb!A z-dg6v7Y_MQ(hxx9go0&0{I5ekd|&k;hZZdJ;V%sN@cq??6U%=1{|@=^1J#F|{jyAp zFBtOS2dfVu)iNLc{E!b7sTYt#o`q#TeEyIR|FZgUdf5-3H{`<)RUghQ`{8v%KKyX? zAt$vh1M2@Xd*Wr;byDUR*1rGJ+VgcK3#Ps6qFU{;>>BQX znQK;5>IK}ikZD6hz2Kb7?P$r`4>07_i~GEK*;RbJA!$JO>vmm~QQ0$5WsK@=H)R?q z#|vxE7aYj^McH+i)iPdam$nYp1jW}}rWc9{`Wc|ENw0>8&vn>H{=$sC{Y<~X=$b6w z#(HXblX+=dp^Ss(#T=RNr<%EYxS@?nHp{Xrn`POR&9dyuW?8!8?0VT?4Ae;gVLTP7 z{qCuH>-zeO!@O&V`OU=2tOzOyLpwE_qwhqwj$q+TX#Q*LP@uE3I!W zAy(G6=C+m9rQlBEFo*NWQ}mZld&`3-D|)!mRgKRUz$_RB&GBS>=0KWgbhX^*YRNP= zXMzp62jYI8HMhkBZ!BYr2W~Q3oGu0H)cIht9F;NFR)aT9Ht=03VWv-Hh8U~Ihqo~i zz>U>0$D6{_f^}|tBt-tzSm!GnC$ilulQhglSWyc5GH7!({qO6$_=Z50_%9mktLT3+ zjT7IDc>hzr!6oAsKiu27XGPYj=4=Z!vvo1SP%lzt$(#+n5~eSGdL>L>&?|vYOs|x7 zHZg0`7ZW9(JZx1WWfGRj;5G?kTA)cdQKseIv3Ss1|Fpn@s!c0lTZd`Et;d`eOu)F+ zv|yrtT3|-HRcYep(}HBz!CFlV%-3h_SnRh=3(SjVWqveGRFO}{J6EY5#LXsJOtY4V z5X;_!|MF^D?ia2KY2i5421C78QWnroYH6*#_G!WSOuS%Ntpg}fk-%&CGr zu5vsR7OJd^Uu|TKzGa5omKe;z+ZY>#Hq!_60C6!1voMBsYZATD(oS zfdk_>8?e3)KxzAJA|6)*Wfj9yc2$-Wr-ao~aIP)RiP6LPK!lQZY{Ea^^U27N03vp4L!Lx=E$IHI{G z93kGNJ&!#@CK7O$04ewfn6~5$aOQ#lWMhUAbs_Ra)k2?itfqy2*60Vf54)?Wte-{t zD;rJwz6w%B8kxQuLL)Ekj ztnBD)<5V<=4iR?@RqEKUpUxUvXog(6v7N@c^?I}+G5pTB#TvH$Gtr&caU>| zLrR_@`F?iVnu+>uR|4)}V^>&VpTULWdiBc&`3Fy{R@{$eM^*O3;FZ-mJzjcrd|%7P z;=bSi_#&1qSl=XVK_JDfE$(AgS+WHUQycxr+ycMP;9Hm0m@#`)L0xtTYekCHz{zLK zeQ_O@q-b(iakm=kd|5kh&ydG%tc$x&J}W{UH}LYevgdU(reF*x+#@8HPp#K`<9hOB zT?1ZE&by-dys7p6reOQ@ukNP@*;3f}NW1R=Pp{b_vTN3bZe~4Xo~JHybF41T4s>zW zyVyy($aUJq&Z@fD(cb#dMLWjyVe4W*!Go(t!SnzMrX2+=m6lYtJOCAyr&fi6DR~(K z3hV&OM+^!AiuTEBS{0XQNJs?%AFc#pB0&+?DVJzny5=0df*?$2fi|GX&JFyIK~X^A zkyWEmhG~jI96UlHtMDb4*@}F{W%3pt8-*>cGY1sfF=^j5C=4jxs}Pt~ap}kaig7Lq z#VGv}#ayRcD&N|%QQXwBNkFk3$@G5>iUSD_t(pWHUQ;fwI|&$wN)m9Lk|2z&#~3j) z*(ZSncKXUG5(J|qkm#nyF{Gq!Yhq^B)CP#834=)rmQP70vw|vRge7xKNtwcOG}>zJ zS=|5Wk1fjnQT8DSo?38WI4NqEW6f!h6hj=>M{;r>_eTl=I_{68U61=C1>YX`M@+nq z|09XT@wUV#<)kC8wQtE_0RLy!IHqiL9QXjf?_ILRm3ei5l0@p64ZGJ~=q&%jYwd;c zm(deEzD;Xjd1PZ@X{>W|oDX5( z>pOfzsw73oOqqt~vl~Y0#FkF;U+FO3-&!&)8|yXh*!f`N#l7ave78c>nz!{virN*b z9?B44Ii|=>PwF@lpl*@(OH#m`1jE43&XObF681dTPF&C@Y_oi-x~ClyxH}c{W|!>6vTveY)Vh-m-pwb;kQ517{pO?jBwj@E$kg=Y82>BhTJku04wz}dJHf3dIJ0W< z=_v{Q3~Q|UbO3vX*wS`BlV_CN`g$;T20>#}`E<9V_^rO$MC@bNhWXc5+eoNQ0;HZ& z$=I&WS6?eq+GJGo+BSa(0MwG6m*EF(dr+X4?FU=DH<7%Tx9y9A#MS2$cDdgo?Z4FM z+Wh87qdQG)3q)@gdt#EbVzfJDWB(%nlop_%A^LDEk#rnSiQvmn3=KAuL!_7tP2z!* zSO`2MbYu~A2gzv>@NeGegg0!-c zZk*L8j<)4qmtf3Wi|hD&qbloeu+JN`WOx|_Z9 zClH3aK#6$-e$Ls)F@<2v=5t-kO^JsH2Fja#q8IxZ#WbJ2v}UqLV8)TgB@GE*-np#y zG5ak#zi?^o6S`cN&&z&%{>Alsbvt**&iq&4-3?ZF#|`4xVm$C@L?yj>2z3P6vm1d8 zv*M6nn$u@R%>nG|FKKM#2fTEO34~Y1(SRO-%{Bl%4M;-fx~C0D$XvgKc4H`62S?+V**5?)6K+s|8j`aipYK|> zQAy6jIh?_NWXY^#mA31JqqdaOd6T%gd|fGVV&c>C*&vo1xZ7}PjWJU(R{JbbAA83x ztIbj}WrDoEXm<%|YMI@U6C^7wjr*S%R9(?3@vpkV+##SIM6XH@077wD-F!APndx@MFeFdMkMTS z4>vIPG?z6nU5SstienbJPpGDw#_TyrjZC7)YnYs7WbSD`*N%L~Xc!^$h>T3_N+1Wx zE^QeSlIWhlu|Vf*Ua+-sxS?>|h5F%EcSgVWwcJQM)MD7FW1;OYEwrpVP0k+RLYRhC zo9~L%3UY7f0dHraeyHK~-y4j;gADn(I;-vCv~+tgJ}vxOk}2sQpjd_60m}5I1B>u$ zEW)o?1RXo=!>!lY+12^F%^;%jJafm+BjtpRIJ?_=HUX01byL#@d)b1!{c^pSm=V=% zR^~+cG^6-)yB(x0m{!3AFK0;%0VDA(`;~ajcIWa=cOH?MRt6mtq@X#}0jpl2NW;PK6}^yjqCVUF3Ce0Rof`QI{bSB_ zm>L~wxtS%e%v{mx;+M%#2)nwOMeox5sOgI5?COo=vlnMgrkr!irA%LC!j7QKvq^qB z7iVMq$nfEVpv>dsVFGwG6Ie*N=`NIQW^Dd2dpXApVxpbvQwovbtV zqmwU}pi^Z@+eUYlB|zo^M`cNGjP5EMM5oFs{0M)0`q3%uR_N@cT-uIK(@OqOmIVBZ=h*~oB{%s z4CZ6@VP5MK4A411TRK8XMcYVimQ4GpOdavjO(HxZenstm<_Odt;3B8C3KIaF+A2&Sb!w|H>5@}hg%!06Cv!gw6nl*% z1I*%NR$#VR6$s8FUoCQ`$AUsqSCVe?r7AC+PC<_x{_LqeT zFn5-P2{5op$#VqL$Tyi_#Q}y!per6PJR?JBMlGg(>sxYb7nNfua0M3jmOdxe; zRAJI3XGRq!qy|jTJ;0%R%fjSyXT|}pcV<*!0@CjC^91hl;siox zMinN&I5Vm+>Ggr~^8}dvWnlu0GowCFfC!PB< zqD1w#s&PQBh$6jEjm26JQRMpC`cVFAEc3TvYUV0!$EQE?jEjm2 z6JT6aRG0wcqN2hC7#9^4CcwC;s4xNMh``1x76x~o0?dFFb)YOvfZ1ObCcxZT7AC;# zD+?1~ZZ8WHV340wZgsw#yJojb-jYd%Sgc=c#b5nmD$1a2|7%SDN2xGQcO{T3KL?A5=58`Q&gcrDA?X7!U%LF!Ts_cBv^$>r7poL zOd3CIa;d@uNS9z0CY|9HE>L08X<^uGi?ncWS(tq863qK)LoUH8OhDRQex3loSQb_| zi4q)@nTWeYowx+^DD8_&unLo2A1FUhfZ1ObCcwA^>+=MdAi+_cxCHYz#mr5{;3`Zo z;}WdG1Q?fK6(+#A1gkIs#wA#V2{1SWNLiQwbGR%_fH|bX$_&sl zf_dx^`9znPZrNW>u#N9|Bejj;T1udLIo`t%lz{rO1gcO%|H~3kLkU2XB|-<@zeX$x zPMmGkAY_^)L5r!C1S6(X5@eV{N$_CWq(XtZk0&Xa#i3X#Rnn(+f+p$LPOeBOOWHha z+JUkJE>|OzC9t~|p)Bd2Fu6pt>@5qEuU&~q2PMtiRKA(Ov%4%z5V2SmR@jJ2B&bu- zaEU^59RiqXPY#xECa@eR3lmuOmxT!|u0vF30t?(E>O_Sm_F1CPZYm2C#JCOt_!KdV z<(mmGu0!-@0?bi^P=yIFM;w@_(8Re*>?7A9z?ouZfB9yDnLEqE1ekqgVFHZn5Y?Fg zgAAn#&2r3xFZee0F z#4Sv;iF&oji4X-zC_up}AC}}&Q4YSPnNv!YGS%aTEIC215##L^6zq+_#EsahEsTC;)ltO_RF z8qaek&ren+`5}s-LFP(zoKjoG?(0IwLbR+4ivRQt_$ze*EDdx4(9m*Yj7u<7Lw2V{ zmxvs~YTy<;EirZo{wRZcSWzI9Gja^CYcq801Pz7mfLCQ4W=UV!F$h~|z@g6Vv8mq3 zbgK@t>wf|#kecz@;4K-U^OcudB)0OJTZGP7FGVe|jyU&w1*347W$YoNUADEp!83*S zaX~YANcBB1G|PZ1^U?b8r7;jP*M@lgw)s#ZA0UQa&wKn z%$66TqqJ*SMCQ$O57d%fGX#y8!_DD;qrpF9zr-rxzkdbzvjO-s1kri`_R1b`4Nl7* zgubrW0|lemM@E6TJ!lC9x|w+bRQs`Bl!YBR!GR`trTtU&jEFi>Ubt%ZVB)7u)pkl> zE25Kc{M>Q+sYb-(VmPwz@#FD(>A-#slVcg`SM5;g$bM3ms^LoiW8B zJC~6o#>aLQOoxcq^J`{7mg!REOn#IP+TLM$Vng#6u9>_MC*;>m&n%Kn+SyeQj!^1TZeRjQ%>viFp$!C`!Yb)QwHBqN_ zeG}J;l`?p^o)6bdr@Nx?95a zL9QPat`Bg%5U#iH>TV5}?EZOlxLnxPJs%6^g8B}k$#7JRbuY}FH+TVT+XS}z7(MEA zFVfG(?lw$|$7&QF&A&%Kt^9lSGnPM2KjZo1^)r!Qte z*u|jVi!Ny#)bEA7uiu~LJqZ#ULLOvrEeLVTt7 zX-gY#FoHIdnAHoEaq9w&LwVzAI-Nm`f%s#1bRX+?C;;7kkKdsJboae}hZ4};Evf?obZ8Lkx6>deB|rcf0*=r{AF>^z7gH9ZEuXPx3p|gzlc~ zcPI+oJ;m=(6}r3J?@$)HyTb2K7rJ|@-=Q#c_k(_i%Fx}FeuvV~-4FR4YD0HF>~|;* z-TjE)p*nQ;G`~Z6=fA2Tu9qT^B zZ_F#!{SVR+w>P?1>vwmf`xE*-Qt$qxeh<{UKV{GB-DleKdiOut^Q`;R_B`wUCwrcC zud(M@_hk zVsFo@nOw6Ey*aGc>aXOpM*!6EQ~BXjUJ_t8XVM@P*J=6>}~BruIMro z;UIoFz`@LV88|w?(djfh{cx}&)oZpYN;sw|HaMs+fkXSL3=U?$2^^CV4wyZ_!T$4Q z;9%o!V`{2N2y^lSW2}V3w(1U*mkHpQm}pM) z!=bIb)VW-qt$A*`r**NMXTAW zDB+NA!tg4y?{#& zQJ@-3Z5Al~T~1gj9`I6h)P=ReY~~{on7uZBI4~+SU>JT*}pk3J`!Py2$(SR zT*T#~k3v7eB|{JsQ_WwBZ+Nr9U>LM6;qt9kIhHlR{Gu7{1o1m&eDHK&RA|7kq?H2m z_Uy9kHCQ;*&k1;Zf@)jeP@d?_B&;ZJSHuwLGb^x_x{m#U1h!Z z-fQpk``6CzG(VcPcLSWzga#;SXbWVW3s|gPtD}R#_4)^YypH#dQ*s+qDI7*_w#+8IoFT9*WTwOZ5dt% z&FEP__FQW|^O?`@=b3XMu_YliF+41ETaRh5V zY@-v%n3O);ht(+?1l-(Ud;_quLuwUPbVri0ai-n1k$GiygrE+GY>)_`R;F4(Zaxxr zrlf)5TNxWka!R1-GBA?GG1&0)x3YcYNqtnV;t2vk^aQgL%oC$`|JAP8rnBpQK2it& z(L8t-Z_1U73v82Y)jUhrX1zToVniEf^V^-}UK+VBdyL!LU9GW-|32-Uxc|n+2_2^o zCHL#dhfMwq#(Wo!sbUdEKqz)1hiFoDY#wW%KS;l{w$kD;45H{y!5v5^hbuyUwl?&Y z?yq5x3j~h@+!r@FgIwB_W9cHN76?hQd+Y;N$zzkw8Y^4|eBG^I4zOc^bH%;7%sxZd zKC%Re_=~)c0s()?J+a4yO}+%n`gNKv^;>l0F!Br?@rnBmH6oIoQxWzec*})aZWA5k!!k+-;t~0pxxGS0jczAau?z zY|6z?M*vu_d3vifsA+8C&vl=c>Sx2bLP&reuhu zX&*aE_H(o7M>oK44v*MT5TBckYN~upTf^89pvvqRup^=hhzaZ%HI=v|;3=@E zeikZ^V#)oIGdEONa=(N@{v_wY{S!;>uVYCD6ks(hY0V3k9K=x{OZo_Mu!pnc$Pq-4 zoh2gxfms*xAlMIAXX31$-a&~Q&{I7#7nLoJ>mL%&@V#zU2L^(@Z ziYaHw6BU+p4}X9q-N)}^$(_!UY+GZ-D-&ic$<8#9C4Vupq@!wWmJC|5V97cyDTvD= zuf&q$!&nla$}AbMBbKxbUCxqaEgA3>Sn@=LCCge81Q<(NAI_2*cpXcAXTg%8U$LZj zq%D2wwB)E~B1^_e6n%eZ&XS`5t6@oNUa;gKj`~>AN05U(oFzw&AcE{H8F7%aBD=g_zt^tp1jiDk-el)VAbJp4{Db`(6OA6w$$Sbkr#4wfws4`0i?1&`;Vru-zfTzHc zrzWLM*&vDlGeOn z$w3_Tv80b62YWb6jvPS**;z8;AZN*^NlQ))u;l#OEO}EsOWKp`U`Z?1$bHE%)h38V zPh*-}Sw^lU&sJDcL0x>$+)xZ59*_0*vE*)N$*qAUiDMZ{vO`;B$v=!N`IKr&K|DlD z*2O-}a0RF`O9t$SB?Dq=e93^Pz>;SxELql)Ai!AC`f!%i!0TA@`2|ace#MgBk+!z0 zW64p^M3#(`DEfYW&XS`5t6@oNUa;gKj`~>AN05U(oFzw&AcE{H8F7%a=uW*mnI`T^W=+=#F2eZ$CbnzR@(7Q9OQrG_B4^s2BpZzMNMTl+Cjeo0ZZw{4 z0+8ZA`>B~7;$W(^;3ill6=Vfgeg*T5d;L_Bi8iPq65kpTvh*b|>v4WzX^b;#D-Zmf z$Zr#m)fb)I`@5gpS39$A3$$wZg;v>OQ8cG`>_0`C4f@lHBlw1mx|d+wUkSp7kX6x% zN3GHv7)5;q?uq)S&s2@_vNeW9Zwi(T9?`-P8G$&sS2C&fW-+5x)NKI46LaE4yF7(<#R%A&Kk>^e*>lKrd|qXc-6WX zI&YqH=y&8CdQ1()p{*h+EAK2sWg~~KjKRpX5+4vFDqvNyjVD@4H~mg1Qwm?lqWT8b zj=A@8A%I6{38xMg0)%XLECjfq)cRl{fRdMkg#b!khC%>kSVJKIH9INUNrXZGE7_nBz-pVFM}Rt{(oGt36Y&8>3>E@}RCg={u*~~l zA%N-<1`7dHmka0(b*Tj>eP9p>-WK}co!TGDtyazK>53Zeg-xV~R^$2b*Bl8}BP(NhegH0OW zQ_^&C1g;=;g>g{#@LHMoeppS>p_TJ0fr`$v)~@p+1a1#hAt-6S$`5HANxkxmuUvaj z)y#W*Ypw;|Ud9dY*X?DZX8~rKimM7Ps^k zf?F0d?^A_a=J|vx&%77?xnGy&aK%*Lkci39%sar9-Lp`iAonbo#x)U>fUn@5Ra1TC zhzW==_ssfmqiX~S^$H|nhQ)J#p0aoLlS@Xg@8^lqc zd*+zS!5;3OjT}J)*^R!4gWNsK2_0E8I`bY^^B^ord4<$`vog8#W!`sVu}npak4^^t zu?1PO-(HE9*e7W6C$Vl93L9^su<>|ZaAT^O_k~#RA+`)&M_|jCAzDwGZ>qwUTb(UC zfh`fJ7A+|i#9V1kq3Fjww`%5H5D$r#49&dv6~dIV%GE-ca!w)ODX?QT%~y_=fB<91 zP{bk6b68HHl!FfaiXFY9yrN`y=6&Fq$c}LmMcYN@eH36d>}bskb{xb}A3HiUIoQM5 zanz`@2(q)|Kp~84ACy@?J3f_}_l55MHHu*@r|`lGOIqeVe-f6wyv+Mltoaa2hMKFu zk}*T%Ea~pVKmgMnioO8mHfPCLqZTvo)HB2Y=F^i?5X5DXSF$39X5OvHqNq(PWtIPn zn?W@iGTIMGenkrdU6Vac!-u9nt8V(i-ILfS>(i=fzOt5#WniI@Lo7Kgr%=j4mx^J$qr9r5k0nPv6In7&qUgKGypIB`h9&#z(*|+W z$CB$Vh8a162(q)}KrzhIq$LM4@9QXrsi{v>8p57j2TO*$smxe12bE%&|LS@nXvvr% za+bWDG+!tgjrD0rNn=Us86rz6bMVyHrwQUAT5@RS-HI#=^jXdJWnEc z0b3Ir`|{F!A)~4kh^6^TRT<@qtRhKt`DwmTOd9K>$jMv!yHqW5E|xhv27L{5Nb^ZB zR74M1d%VM3s07s8O;iV5KI_7m&0n_hwX@kI`G2&-(C)k49aW<_oFm zQol;`c}FTXsY~;XdZsSTS0v;|0S2e`r}?aTk>(r35u931^A$BR1~!sh)~m&?lYdv-I5{ zV{oUM=3_N|DYI5i^W~Yf!8BjUWyLg~W!47Md|EO&nC8=x$<#Iwz$0SQ4)^pZ3&o zSD2s5X+C#^xjC5T3z@8#=Cj1wV46=k$H6q8a*iR*r({k@^Vyfs{x93qC(o;u(|mbe zttQPE5?L|LXL+^3G@p`=gK0h`9YdN=8PJgCV|xNi^I0S^=GDq+zI;V%O`0zxvSOOg z@@j)=K4l#T(|pQ0hBTjYpdrm?30cy7N`mHjwQ`y-&#Tp>`7Zd{?3m`WyxL%zPg%#o zG@r7LAPmQ;N~^YLTWOMAjR3pycz+Vs6=7{ zr;-y2-d25HE!cf}aP7R>_MlR%M{si)d9?t9`XR3tjKKIFj6h_xE#r$LFu7~FGeYHc z53iM1>xb1e%h0@2NXG5))r zApT^9EjKw^@v@C2F47@oM&h+)wW!bcJ>uZk8s3gRIV!=ZUKOP?0uiBis} zn&vJ?31UTqX$HSB23 z3w9jDQ6D?5JIy_E1QBFs$B2WR9bNmN%wV=kn)|8DtIZMj8=dO5yxR2@mb4&#{^U9$ zh9N5=$DSa>WI5Gctw4$K-^&l;Z+4c96(}*UR!Vh0JrP4eJVZkd&8zjLx=T5uYO1>& zF|1aeRD<|s4H*kON~vxQyl!DYDZ^AsTZhV%nC9(c$x+WlmW-1q`Y!TnqX4U6$-c^y zK^*n5s49g-=lsKNN+<>Jui+v}7sOtq7R~@!gnMd-XM9Pk^s4h;Pkv4)tmkap;o{;#+WD;;G6Q+^Gif*$B53H!lbA^SJq75I;n! zV-Vls=7T|eZNoSi#Md^AA&9ToaR}nG1)_rZ0w#}}mxK6u+WfVdXUyxkXhp4&tn#T8Fb&ZUg*FC&e)Vv>76Xhb8xMyW$HA*QpI|_#- z*{)^~NO0-mNG>C4UOT92)I7d5m-7;NkuU*ZbkuxHRN$w1Dww>Z!gHJYqUJ6ldz&la zITm!YWG$WPi<(aq;W>{5TzS;I=+8ZuG>0pO>4wAvhDOZ+Zb;NTXz!Y+dB9g~n64ZX z01+0Zvp(Fc85R>L#g9Y3azMPJG(0~dYCiBxbU?~sx*}>m3a}an#F`gjx>D3U^xNlv z_}v`rbw$kwM<55Jh?++nOc6DoSvzVzQ%+_DyE?FCjP9%_L^n}kOIB}-Eob|p=Hww_)ci{0 z0YyIupMj{kARZDA7#cOVwB`jnmZIiQGKn>E1QBHSG9nIgc69Ai!;Vj7)O>~z z-RMM?h3F1dSkgjt`IE5Z<*i1UC?~S2`Q;ehahANCI@=A-k}TL6HM_-7p6hAH{vO-=tCUN>$a?~@CCF3ND zzKf{&D8Oo1vM;YZh@(CYx$Z>P$Pq-4oh2gBxZ;yT;9V7i6qfG9e93eg4BC{z~mOf@08kaAv?9W^RM$LK9Y zXMMOWt5Mg5=t5Yz)UQHxA>|yN@83>m)H8JBB99Av%4yC4}e{s0txEiYOJL<1>9lRID7L z%cEk0A-WKSiXl1+iVcS76fYbM(J5XSLUamKg%BMZwMFZ z@9J1gY%oNpfZP65LZqEqxTgy`6}#X@w!#{#IQrIJ)3N{@*tJm@ho3!F}MJB0&R zoQ;f$5vGV@5_@%UhnC<^)W^hvWuphzj){@EGoficf}6{Ti3K3k4>7S|=EV1`6%(s_ zc&(UNKddG@MJ}~5F>CE&bQBIt!c@(Oi3J}jj^r|8Vzq;+#>C=VbHVCfNp1*@j)`rE z8uK(NJJ^_`obQFcn3&6?UZ>)Gla7(|4Mdf1qwopw=zP1Sf8{Z;qQ79j#b6kAUB z#l(m*Mz)l7dnGk8ML!6iftZ*ezTB9Yg+6OzVj*Z+6B7$~3hY>Qz{@c)5YQi@&YhV) z2fP#=Dg|pp{Z|an_Br6Ao{8)jCou+?{8L?{0IOj~YhJKpDJB+R?PEv3yN(d`$Pq-4 z-2sm{$l1}g4~h@fUkOp$7q6boezx{`l!^ncy&dvs_1X@2-aI$&pKCmO`3`u9b>t3s zDPCI6lU!bnOuKyPQR5l8*8VB5(7Y_I!j!HITF#;{YSi=DyIRe><0y&Rf+sok8r>jP$E=1NU zg4gSFz%ACDbEs#Uo)QP#9BYZEDr0b`>VW$f*W&ugvICy`yn_yS@G_$VZa!~t!1cAu zvkm*mr9LY==zx!LH#p$((1Qa`d59eFiL%dIcEEF=chCXH{g=xd9dL7bg9EOw?5-4F zl^t}z6%7auxIFaWfKwbI2YeD>+_88HJzlxq{xwjAAKc@W@9!QjYfJSt(E3fb`Dy3^ ze5yC2TngS=kVnBO3&wlB#~VxuHC@}|B{yYK%6eSO;|)vGt3c=qk2lyA@jZhc@7fR7 zd%VR8{eD}#OKlKuGBT#~uX zG1TJ?d(pbW>&>OXP&$n$2;Rmh(|V@Q<8>j>o2{7Elrui)+GFv;7MEqS@#E`XK2-GCwOBNLEQjtL@9(Ub z*Av=|exh)LRY=jd8NCc@Bti%*1oL_-+LWS=;Mo`v4l%FCa)zyZE~2R0ka%`_1c7&(xXMMOcn0FM=+slcH~ZWv2!8$TB@7CCgP8=B`F`l_5mmERf@hmI8-s%&i^hYtT-gqh8Q zjKQ6%dA(6-lRS%4Hm`GwcF?@Wo|Z)$&1 z^b}gO2kFKwTG{h%(aM;1iBW`C>^cD1E4$~TX zvaY7t^dx{q=8)tL7?R`;$f?nj0avRu8mT8ig6T=?!}X*FU#BO7ZCC178Y7s7;rV_& zIqI1@Jy}?^qX4VXlh(Y@lY=-ak$o|OG=hyq%c=xY9SBQ1C9OfJg0Nla$$;%*)JE!s zMH^q1le$~91Ej8R+m|d_kvcmgN?Z?Gw0(MV(2|wnYxP;OYv@U9p6ki$E>};UgCXia zt7Q6b9eQ%Z(DDLF62yHoD}4Y)_n3%gc39fqdAFG@D(ZAY3kGQ-dpPeZ80D%-%F9Hw;{Gu>Z6Az!gM^D&Jcz`= zhH6?-O%JHGiT~0k&QKx$lK05Zs3wEJQ}$nO`xnmiu7WPBKz6q z!!`hcysx$B!@UQP3-;`X6_%{R8kgMIU27fu%@H_+M*-A6eO4J)J`&iJ29ZrUH8x%U zpyC+Z1GSk2Kk)0Nwn$Q>8>4`{G*?ZJ^F=`XNy+aR(r7?f`In1kbAm42^fy%v#Lf&K zBCFbCvkSv2m<#&U8U3v`_`2tTMq_?*oR1%lkGIG9zvN{e|s303%V?HDM%3TMHv0 z;93~Hy}?NM_Q}IYG1Qtco*4oorCGHwdV7PBs;VasFL+b@MTJ^uKQDf{n8P>k{L-AA3;fcYon1G_e4VS6lz9>}9i-#exjK7tTn$MV z9NmFqI-Pc>$}!>qacFZE4k&R9WuuumI_H2eo%$-Fw}&5W=hE=QY~+}koMWcH&N0Xs z>FTfRLAQ4b9XJm)&d;~!tJEm!l1>ZKHn(@QNv?EYb2d;{AUYG;)*f239Rb1*(~%md za%!CXIyHW+sFA5CWcMsHJv-Z;tPh^Ab> zOvag>$Y+`jeCt;b4%oK;t~E8oENt&-usA*4o~~k1SdlGlSSevqO93QvnsP8p{(%-O zczbYUr4s?Y;}MHEdFCH9-Q#FWjSuw@ctwH1Ng$k@Y)@7pRFCpVn(|gl5UO%R9!yh< ze@YNWkH`8idob+?Veoi(5}Wcr!aN6Sr>!|74JRvjMYYt_-Cw>Nq$e61^qO)!VYTWkBOC(P#?^i|K;{lVCY zw>S7s+2^z6BnJ4JdF+H3O0&p2HleFxtL2lMm-nvlUt{Jc#+x&DU1R6j>CJca62G6) zzRgNMJ=SeUY%eC0d@qW7v%T?`6OiGoW7TwuA2(lTwQT3fTyQ#-9BGmGBx=-aW|J?U zYbx1zW8?g6I;8@L<-@jU7dUHq4%`)GN5g7<25>IJJvknw?lC{x-L3Sj_}Ql&Ig6d-n3Lu=q$xV5YX%d zs%LhT9!Zm>H_@JeE&F4sYC3YrsKNOo1y)jSLnWe0MIH5>!OnRGO%M_q>P|~3=Cjg20m%_f0rTKf(1=rDG0c6f zNd>wadaDIAC#Cxd&WkJx+|Mv8uUYP4k!upzBW`dK1k`em!nY1a-%RI!X$qkkvM)Jv z{Lf}HiOiAS(Q7(yFy(2O@no)1dhoMv|$3Om4AOA*0x0_3ErrY#}gzt=`37~LLGNJRS?-#Ok>S>8MO8sv6hfeB0 zcRn3jrjeunHYtEU-^iinWe1nDkN(rARvOt<_KSAh-uXeBlxEHlJ%IQQheg?SMsvGg z-NqGG6o07^=)5mH2HWpi7E=irE>bj~d<|`|(FOb|T*QC40Nb#luM$V99S_#sr0BM*FLHaiZ zq+w!&>+-~C79)YxfocoL3Q!w>8lV@bz!9h7M~nqbHz67|X^m_@Qq6cT9YaZOe@&QD zDjby@??70)B*rAoK#7q;^VZ8jyM4 zmvawv{!*+s8+z90+~+hGu3=y;v+S3+dnIutM!>shPSy-FMnX9|^Vvr=3+ixtE@UBS z3_6q9iKvhjIcgxmVZ;^0?!g=tqToRcD5xNu0F`R$45}V{(Gas9;f1aV0wI);GL#KI|{maQvn z0PF((94xsaY1dThUUx+nqbtHAxy|HH;_jAxM{_~!UG=WWK_GTl0QMbjAPe80 zf72(v@Vo!^4{v>isICv#w^f0)0%h0c(Qhi85dmvPOaZLII>9xUtwGk)96%5F6i(hj zLM;QB{pkYOVQy+4uzi@FE=&){tOYpi`&5Oq_f%lGL=OM(8KaCVCkJ*GiuTeKV|X}v zKlDy~FDKleE71Fef)*Y+`@<)H;Ws~h;qYbC0#L(+<`w%8Am%cAuG2jgn`1M==5iIp z=3E_2gL|5@d2mmSWijs6WAso{IlOCos956bb5Z|pyg3=8HUkdoIWy;Gvk%#E(=Z3s z!ZbvkVwff=!Zb-G8Xz}>#_~|}Filc~X_EdhjXS8NfE=>16dseivEG2(fP>l>lB;!4 zkK_)j++rm15%=h4H*8>qj`GF(+Q?u4ZT$k&g9x>vN!OGzXFirKU z-gt2N?jJzF=L-bf_sHM=>W3dW`}6NH^8mPWkC_11xheuCmn&MrNT#tjXbMB51=5td;!N4(Qnwm=Q5I^rGdiV50G#yj-E z3y)cdgPc}_nO176H?`brrS0&T+NTrw1++DuU$9(aEL^ayUzYNm2sES{713!c@v67B z1>POmo?8_S1&C6=ZH!@cuhgqDYlN95Q&P^*b9lLeyf()C8Zg?>d43Iy?P6e}9lBWV zyho%60AmWmP8PZ2&VXY5NVD0xD>>r-QUb<}?5^ecRcAE&YBSa_3 z1=Am66lh=l>R0!Cj~*$&S(usmf0AVEt|UgPN%pnfd`R2sETp{~uF=}PiOw;(iDAU; z99ZE|eY9UOC)70;Nq;jl-#pjIE`IcpmBvHesU^n0a<1VyP|a1E&^Y_Y^3Nv|ekO5^ zAU>4L+H8rE!rLWu+sv<)A$78btq@TTb;26*hYWnX^Hu?-_NBB(t=(YJhJw3~L z8*1paGEr{wik(^VdT*@6t-OJ9gPF9&P?zpX$CUL?5odQYc|^=#xziXXJa`mN;kVm&=HoGt7>^&cFE$F4P=d+Ns%ZjTsGc;l6i$6mmA{J6gHSX+(fMBjMqTI0F5emvp!i1CCsUiol=@?)p$h*=)i*zOt?@iiKR@C2i1CCsUjBG4TstoLHb(lg zbyqtohLxSUnSm?~qjQ;8{ME8f7R#yBv^_T7pcEK#osg@BrF5xPlq{LD=%Qh=<850? ziocNE?WZa|wYpXXxLhI1?>W$D+6Lm}%HFvNkw2MTXuW2+I}J2^W~kdV={qU)2FuS_ zDVFxEII+!6LlbHm1Y&P8oAJsl)*heOrsxjVefH-$g!T%5x^wRjBWRK4$$`f48J?UY z-;`0I#Lr}rfQ3rg7W&!Cvra515%#zFnX<$lJi+9IhjnX4rBip% z!-dv&b*JgkMl-E(b|(dS=iVO&l=ui3IB}HH0_phNC+$uzHTe1<3P?(kCv`FrY!8Z! zlk60G0)du=Y?B0^P+V zfU9}gE;d1qfz$`DJCzwxHP;o+2z^&)!^*j8XQNr24Fd+_pcXYL-zr>8?%(7ET_?cZ zJfXkeveF}dII*caCzCGB;**#`rrXVPpEPR!qUpgJ=leJ5i;~vewCM1io4PY9zz^Lr zPxH(m>F5QYu!Y(Q6X?r5_5wY*sju)$G+{iNFR;~APFU0{u%PTF?V19QCYWC*v>g;| z=IuHk6G9jQFv255vL%|G%G$51mD*m~XfkahKYeMV%wj7Qz38Xf--_DE zZc8gAuu)+!5Z7c(lb!cFT^V;;XFZDhr)hO}8%CZsQd|hkJdML3j2DgPTaD%nA_bHz zEO&lQ9@;GHZtM~uUN)yatAUmC@D51GAyA`DVQ(E@d5_#=w(;c)k_c5ZNZ}^6Mj96K z3cTtJq+AKXXb6`*E}QAcY4yk415CYLiTVm41qxb8>k>@;+nW?3|H{WN#Vf zK*{;$xdj!A1q0ne-9~p4frJB%iC!Tr?Z%*_+l7Mio+v2KJG6Nc;HM|7y{P|;pK2!z zqxw}kJe5=O>{9x+wEfVr?rfHHTcTSDot$Q;q$&(m-DW!3Z6L}UoiA8mpaBAxyA8 z5!#VcnvqkyrPw6tW0QDkY$8EYW|Nr|`uVmwg&r?&$Qtkjh0r!&ES5qIk76ZF(Ur^I z$u(s!$T6Bm_9|9Zp>2|0M%(lc6r%0lj?x$HGvS5aQb-fI_-odQKG9+zOG&{m7PJV3 zN?y!lEhHdoj&f?kj={pIm4K6RUXe1Td7X^&D*85N)6`DIxeOA}j8FukO|7(6d1|%( zDu*CU?j_8vW;zq-`S$}oUuro$-;K#-^sLDpXL4z-lbJBN42kI*E<9xly6}|xcHt?x zd<8Qu(U}X+%bNEfyJQ=e1(ECXe&M-cP2mYvQ;Lsd6Oh%#d8PtA2+v4h5S9r~u15$@ zP%0@G#ig`smArzeoM5_5o0oL{L|Ib$4p64+gP>fSBAJ9Ug=9n$N~q?N@hp<@WR#2< zD?}=!6C!d99MYLuhbWwp1hiUx6QWK$fpmf>%*}&QqOi&}UjtDHHGJFL7-V;OLrxj+ zSRC+JIu*FZ_N@6jxBLg^ma#rje|e+>t*wJwazXy@k6YST#4YW}E$y6JaA{*eM3#57 zFJrhwcDY%Lrkkb0WoFb!cz){hsy0Qh%2g?%5M4kA<%iQvhM@M(H<6DK z!EvZNIFltR(RDp5RhN4w#{NO3N3TqotCAz<{+Zp>?cmm#WOv8UTsA@LLzkR)*d@MY zeBjCHROarv+}T@19hp~VX7A%Xo(p%{xmzb(;ItN=-KGb-li4`LtW-ku+=5Z-Rznp1 z!>tBlI{J!%Sq-gxW?M3kXR@z0m7n1h%lqyJV;Tt09{-AviDD(4w}%+eMGO+m?(BGs z0j0C{1Rj!N0n((?LCOLyP-6E9_49|MxS{LW#8?l;WUNgR!oS(=1^!GdR@TT)^4c-) z08c3$_tO!(T znLurxzI1ESEXoEU(s}J@KoECga#C9c2qT?G-p(rwB|YUKV>nW$mfWo5Fl`Bo&?j?W zv?mTpjD(##*gnBXn2Zy|VyVjHh;_shk@k&G=rd2CicuPfHMI#{xDjpSjs4|a{HdAk ze6|8NRKLg#joDB$ztw>v&E}hptAoz}o`X>2+y*iBzwscH39v!1M)|3mi83+C?+QY< zAf~Sg!2$*AT8($UR{c@LVEwI+S3G312Cp>Z3?VK{Gh~BP@`V%sqN)5DM4fE_;~a(6 zfRU#G>1pGWe|L;p zmMT&}#-^r#LZr4LuK%MD1fxbBnLPZDIzH5&jnC+Dh^bge+234`l$EYA+D|G{){wbw z_1DCGdo%l9G}z_T3~GatQ%b`#n-pWH5F?==L;tt$YQ1r~sMtF< zpYOP^)aWMsPjLqCT=|)?*Gh3MUHtnGz5Btxx&H(I;%Qs=Rqu`ORISFo*2xL(axn=6 z4CqV7GokVk)yt1$L6$zd`u7XBKXhkrit}Ii^&fie(cW}A`AQG9a~AA%~94N#i&9443%=U8N|c+ z@d_SPg25xymz-m^DRFO|K~3m*TIzy5sj^@D_0<(7uJfKiGGHuw|Jx~V%%;LU0jQQ< zE(>gWRL$}m5W&92MGABUpw7>Q!cvaC<)K zjZud}T*IsyyxT?6ok&{alzUfQ>iNQ#2}`nIHlD%s&}0p_wk);9_@9~>Dzl_4@p*x zF@lNP_2*l6_QrOa1mGo|ROiO47|bpp*xZoQDHjqSu!yJ^oT>i3nf;R8!E{%2#qRu^ z-60N>-+8z0@S&xaH+YmwU&|HMb;#SismB(h8V zZ1SeIc2I6O|HV`oHA$WCV4$& zL5oC7W@;!D9v(`en+jq}j;NheXp{t^Q0`AIt(!(CZdVm~iAEK$hOd3bMWc{MPNNf% zM!9)sI$ojCd?-evHi$YJjiA!aDkKQX0)47e`-DYKqNn+NUhL3Mp5su~xX4q$(yE3$ zPe<|`H}WJYoKA^6ry$Sq5_#$z^4#pCxlzj#<^_hYwAiTV<2--zYhsY|>Ms1A&WE$6 zwBA{14}yu0iqZ8+B^?K8kVe{cE{Huut1lit)$$GEBKbimn&DHeJ47$3=*2{|^iP+R zHXFs+TOf2-J!xCMu0LbTU(;FdBW;=1Sa=JS`ZIStL2^-oCVUIck-E6_;I;ekSJ zO7C+s&bELg}*1=k)uv9BIM@GWRMH3+k4#JoPX-p2UD(9zK_ zj-c~dX~1-D>EzpgXV)7!u72tZ*Szs4MOt%9D<6H^k2K$CC9-D4X{3e98{64ctfDEs zkHQ=MqTj0g<3VZ3!WrBhxJ@q;qtUC5Gf$ zG5XF4SshA41kpEJ5_$Bd^%z;xYJ!oN($cxaMBC4@lp@vEiw2Fvr{tQgKVdoT<+NX+C(*-wRfg1K>0rEsu0+>B8UL|GUkjBuyrlPXCFh zYBEq2Cr(pGyK^F)1DMKYpqxZ}B3v;@%)T)z#JmJ(YW3KQmKvRRYs*XUeVmq)X}tTM zaCgO@KQ6kVg$voGa|=B9bJhe)pMTAahW?|vTWR*Dbv)VZO)Y(?weldapIdmNdVKTJ z$&Xz9%4GyHSijxmGJ52dG8*iUiRRw)oxno5pRBzpToRWl+%Vl^G{WP@Zi652tG4j} zR{qC4>`r(rQLOy_Ut1mE{y#Y(?w{-De(8HX0{7c`xSadNBZ2#8*W`ZoWv02!XXlrL ziN!ss4)UB#z`oXN<&P~U|IG}L^#RF3s?c*gT@wc6g^c7GoU{}q%I)KP0=yZQAMibc`ZJl_NVm{B2O!&SjML8{e&TYc#pHrdy5z)7GKjz{U(@ zn?WOUTlS1OvzR3(CyZ<0@MB92cV2+C^Kk_ajAi78-}ldd{rJOwDhFGtncw-#{O93_ z)kxry6uCiW6hbbQ#x!s#&})f+zIL?Aw+)J@=Dsb?9aFM+PSx& zU#!)gHVDHn>PBsEPun{mT57(HA9^_E2BCANJBNt9)`Rm&(nPY4bsmf38uK9VpC+6j|p$V1(ZUp<5khsE@(U zk%#50g*BtP0hxPiubnVP(|uemIeD)CnXMDhmIaE^Ll&a)$KB8r{<#LDonLc1N)s+) z=mgt4%2StW1e1yBMNahD6nu4tZ-hvUL8sz30uVaIDBRb$Z^G77h#H9ACY|^CCgA`+ zwyY?m#_%|w1PsxPbDRb-bC%OU#250m+NW_<2FEI9>KQmpv-&vZ8n(7=C2pc(VB$2H zZ?TD+&I#0skyjyGBzH@G3pd@Mi8nQp^OUp1=%yl_7Tu&7jYWa)Du*92l;Vn-kayFQ#Fys8)L)3&JOeINv8? zc%qS=dmDQwd^e+#a$usa5=$GwwN)HOlUpq(z4Gf*ufZph)rFIF3^6C!bPq>`d+(N7 zW!CTY`>m7Vcp@CBkg~Y;DUR6*i-I3h&{Y(6uU!%-2)+%bybbBzc;_CEn#W7YQ^U{Q z@y;=802$jGh^mb9C6U+k#uz>y_Jkr+mY^xznBr;@O8Zi{rQkjQm}|K*9)zgv!Qd>* z-umM8mGNcJHt#wEZ_swyAJ15E#?vVuw1n~$_hOF!JVsb~OynnQivWMZMFg4w<@Bw5 z0cuR&I>BL6P=nx{+)HlAXR}b;rLhtj?tqgPjEi>CR2Ldvej}ZCLCNIpbRWT)CKu&p z$pdY&;f4gcNYWxw&gXgt5wG#;7yGno@e5mKXejz+(E^n&$9QIu^?l)&gVkRSYH^@H zb2$G6K5JcqLC?#IvoULCvcq95=nj=g5pUl|1NFXxjj-@JT~6+xGeT1F0wS5oFCd87 z`~sO9h47Awpp6SiE$Oi%Bs|<;5u|x2JBT*@VroIZEGn_=B&z#HqPkzglE`@`dEAg+FnJsE3#e#Qeu27* zBOE2O$BP5QnFYZ{rXdt3QbhWz4=T)%-mNuMUq zk|tXOlg61g;x=FCCZMn2EV>cFt(4MiI#2c%B}Ty`BiWHsT`Iac+njcHR)IH?-h8_XjFOBIHB4TLIL_f07jX2@w(wLqm?K_4}rseK* zhwSV&x)*Y{Otd(PZ@RY)7{Q#~f{f1&e>eN_2<0Hu)v+2PfTYWUJTcmq9Fj__+(R7g zC<{$J3;*sYi&x!4IPEAY64MO`3aPvJzI2D3MXKZ%*&AvQt!c>*WICH4=~d;s$n<&c zda6je-uJk|e1YGA$0TxtoV5TkEo>J+pv0>3mL`5N#W~g90AO>Rae=rUMl-B%%??xM zh#qrfpaV8VN^`qI!$eqeOwE>)BX71)DeDusgc`IUzLcz&fJ6H^Q=HPo~Dm4>*Q zUx|Z)A!Y_^9N0`6hcchm0)MzX-w<*!-%xN4Jkue0>{C9jewplrjBMTl9bYtScem0L zhzaGhFNp!K5~ExN?-;}64!^vAao^)f=PzAb>0Df=UrZgz)~eH>L&6$ZRWSmYhnkIP zm^jHTSEap5nBa7sQwdd?yZ7bernT&)b#R>h=%c8TcF^R=$Uqi25;=jOu!r@Lr2vIm z==`mZKl@j6X5B=UAqu@H_9FAK@elH1yw*Tk%q=lB2;~Nd-@ug?70_dt*Vf>}iY!Fcyk7A0B^paR7mTSiTIv z42210q!Nm5L@Gj5%F*P1o`T*fR;=Sk$JjlsN_g(>R*75TO%~QUPU?{OqaPI|^oMth z@tmp(# zELjjw;g*NT0ez!N$K2}h;z!G(KiIP+t7h<+4UXY+k_afq*=#y<>rSL_O#XIzyir{d zc=dm1VL}r4Os*ivahd>!m3ke_K1hk=5#(x?X6Gnmiv@ZVYKvB<*8Z8s0{kf$PU;;W zDWs!SHFBawhnx6+gBoz0XTyVW?O;W!-F{}%CNrhR4>U0BWNpd100x4U<3aLF>p`C# zm)K@i@PLUZE~pD{ARPYzEONz?5U!%(7d%w6VayaGb0u$3U354b=q!@7$S|-=VKEq? zZs4&(Gdme#B5dY%p`xSEzz`WP>1sGp_GK(sTmVg5grkiGmvhTg*GOQA3bCmLki3LoSr$BwQ{< zg5Fz{aA8&ujEm?c56B^%(oKbQIy2tg1jLGgA*MFf(B|yZE}&v?&jr*vXfp_?O=SUP z^fyQb@JdN2Jym3I4R4JSDUw0Crz#n29!duC1#8Ga^IapD_Hg@YBm<{{?#3C+mz)s7 z?7P&F9p`dJZG#4@Dk(UtkRZ}&SQ;*stbzg4!vt3$oPr3`d;63hLrwQo1XV#AAT1YL z1A+?q07)aoRpN@Fr5z4UY@H-aWXkvCxUZ1F)YM2$j^AN~52P1L*&*VtvYE%io3KQw zEM{SZ2{~gL-a~^Pw$zxH>Y4B2sY~*(+6lvQMP?VsXFBOtLC9l37cv%XJ)GyoFazXn zV&2N?T1PV?YwKvnMyF&gSG?$6g(lh@cjD(ZKVmTo zEn89S7vRj*P)zhB#G_K>NIVn(G&{#sjI4I-yGDvo%P@NL*qdftYZ->3c%Ylyzt2Xc;Dd;wJXxfF1P~L;YQpJH48c@J&d{{FwIr7JBHCT0p7!Hd_%*_L;V&mvEE(`>vfA#3#5YM># zK}MT;e`RuTH`asY$y^9Lnm5rc5{x2YTbjr5^msu7VPTmunMCW@>&4=<*EmS4MZXCG2VfC+ z=Vx?J)?SzQ=$@}OiUs%F8_!zuMokp*S4NJq|B5M$6N)oUfIN`lhiqtPuLi>s5WGt; z%KZ68pF{B2c_2t>1wQ&Il?uG!lsBhwAS44=hj* z%q3i?^l@Wd4}HnvlN<8-EwM|UD-FQ{n|AJFoH);zhggt!J`y?(NpaDs_(w6gEX}LA zczb;{S5e0$!Y);93C0Z)O<&`}Es+gMQ^{WO6UvXB^o+;GvNzf-qb&58m>#S{`gcY> zhSeiI#$kvadsO-?27`INj;=Iv_HVDB=~CEmkQoqDAC!ue@*pIIHpOOaOGkSBdqY+V zldLROFMhX0RyKDe#q>sN!^A4$;DJf*`0S_R@=!A#lo6X~O`C$W2z-2{hu-7sJnSAn zNTURRg3{RI=Uqv2B7WMf@_8UJNay3e z%1Jb2bi_s}+D4MYY|p~VUu}Jl_A+UuEmqmM?ZKCLZsi6>SWNi(ZslQqjW7WN!^6rJ z;gKaRYklsM?rY@uyeJQH@|`xmJHp`f^yAW3-sOL!aZ~(R9)Z$*`_uH?vij z)|3HA@`i_4S=LrTLqiIvfgK&Q8J+(XFyp^y*Q@yPo|#{3C+*_11}CTT&l+e-XH_w* z&k32qrEd&z)#x^P0hHV5{F3c}mB^<7U8(*ocHXa>n3fI5g3Z}qn`xbrNCX*#R$@c1 zgT0Awhr&!MG5LBvTugmCq`*Q!%bqhhTfpu?ILgsW3sS%nSp#n9an}32*2cu2Gnkij z@oG*zM;X>MvXu?LXq8guVTYO)y2bK3Dey=E3*wGb}qu*?DnEw+%DjWK^AokZDpJKV6X9l4t8Xup6nmL}B z3Q~jfdu`j_lEKWqz2+RmluDAFoC-{wHfGMZ*|;ctvQ3{&Z0&{CR+w*rE%v|!@$XmZ zB}q{Wk?>_6|Ev*wWM8~W8CLuzhW*rm0ASH1iyykux4E*PvhvlKylg2j&`YxST9NL2 zNNKjRRa+Cm`0SZn^TNdY8r%6~yWQsx?K&$z6d`UMXl(arT1#;Vk1A8KBAwdy11nZ| zTv)dz{C#e;(Dh}beeps)cjJY1dlk<~R`S8VS^eoy*yx#cTm3IE{2SF)aNM0ZZ8OagwN?BT(I08fsxyRJX&X+#Z z8FH{uYW?L*yUjiy3x$+gX%$im;;`>%Y9oAYc4;p>#6);bg zhM`u#+$jx1w}4s0h*P`DEqdIL2RaiIMD)0+gmJZ^#}dXhz%vZ?)jrk}oQjti?qXtJ zk(SQG6!X*}HxFVgayZ;Y%*q(G>>-soZp&U(RQ6z}76m}fY>M4UHB1PRm+x!6`i4f+ z76W&;fqGJ@+YMP-NFc~lFEk-#*w6>ZyUXcS_9#+3-R@_=wJm?$ksBJf&`$AL3*D<5 z=?O=qU4b=61y?qOhjGDs2q%(O@>#~@eESF)n(YJ&pvm>vZYfD18E)-C!%cXKdw_xq zQ>9=jSIOw4*rma;01#$Qa|y$fNyF}GLAuZ-zd(s`;ZjsoNd~F=2KaPJ zGjDm2PelcWz}B!#*kKtYF%fo?T|n&4T#I%IRl6`i+tCz;@gjeS^#DwXRyTe?2N|}+ zH^?BriGs!u1M>1s16rAlaFY==NM4~L4cic34y4^!ES42`ixdMk4#Qf|ca&G&f_@8> zXbR~w3JeBe55L;_Oi8TS_8_@q7VRmj{ zCAHbRI*+$w4UjI*lB`J{ILTVCw^dHb%X=Glb~nhyqd_%-0lFsD4yDHK%Ir0wr9VK! zUBnM!XqAEt2-gTdH6H18@1!U%89F=$hQgHNwn=W_K^R$c;=nDaikGVjKbn zkLd_8oNa=h>FgznWl}vwSOa2#7}z77&r1F`Q}R0Mc8F~x1R;3Zaxh^(X|B1mk&ca3C5?jk&czt?;J5K44Am|~ zAq>B5B0RR1W3*_cgYraLxOPYfJ0-7rmQ!#)xVwPy$Nk+!l}p2s7AdF-hF6IB0k?^F~;}GV%M1)%zGI zem||=H_*--XzDC~j{&Fqc`hT)M0igj5j0n?cGlM*31=wg0x-hzb}-U;voU-Fnunk1 zq9HdUd}m-5z`|Vnw+zCVNoNPE3$!${y}`iJMXHP%s90)tQLqiB-M~H_!(r@WirCJM zKl12Gqw{H*-pG9PsS8)hVl3@*&E!a$7#m2U@wJkI4IWbp9Kt;tARseT6(T=VI{`ftYJ0QC$OYT!W`@}Vxl1>bdyzs#-s&nS7|tJV z%H}w0-WyCcCE&vssk$j=&PfOdfTa0j#_a-e>JGW`f_Jlt7srKo2|+F5p6VL`rZ)&m z7{MeX;C~wd?>yU#qj;7^@vIS}n46lVm?aECReh!>`-U+khuMVDlnW!1cxYB8UGA=H zc+;JP)oklDGn$#d=>PD>FM=`zhcva{WoR)>pI+_e$19~o(w!{gH_L`;)p1vROY#sX zbhWml^OmU6P-Sqw-h3Wpvg=q-Si~2Cyu~i~*_i5Z2zvHKU4zOkecfgUf@%A1eLA_= zzzh=Z74vkYY}Tyu#^6{!pkBC=ggEKv5H(w#stxq;C`b8~vfQIz>H0Z4sdlTn|328j z_cb-jjD97ss4LRt#lEIoJrWwjr8g}u?u1LJG&_zO=Q!e&mEpBpGmi-TP4e}{(>yuY68?GJRKv; zce^YH7#09u#jivkSV|5DnLvefwC;=$ZFCGJPNDS)Uqn~Fi)fzoWpvSB++j~$l1$mA zj;COKxJ1%VOe(D(bcHrt;{v2}o1eMJ)rD*Y-9QHv3IR!6=nTZQd68IrxDhcl`$&`I zQ8RuMyGX484N`)XN!m1KMvlVUwmlv9Ur+qBg|u$Lw5?3?sI36%VdAF`rWQhd8J2m9 z*U^B5o2;tV`o+my2oY1jSk>?ZF&D5@gh-*4c2_Ch@Ec1WHDcalK@JeRS0){MPDi#o zePC*gm_w6+Tt&=b`&|=n%(I27NgiotOhB}f0P<=>qiSUDOVoR>Z7H}$b_#pNHU=Dj zNULF5bnaGi49<+{i9H9U4Qk#g>7#}!hieldwBG0}ZSI@x_D z$7gX|K8?Cx{Y{oU(09_0Ak0Pyp|fSw-)bbT1m3&QV* z!u1W|_rsz63&Za>hTm@rzuz2we^Kj5x;@=MB+^j7BZXZ$4;@SA>~iX%V{h#lgjwf* zAhZqH#3Sv;eGls9i`mRzx%Uzt+3s)9Bi1gP{U1Gh^$z=C@ zBRt|+->rJYNJl`ngpjTI+wHjt1HZ4QO~qqC`|Nc8axaUmxv@VzGNcnm&=Sz}n>t*E zYR4P!?H48-MPPy(b5%^ViXldLH^t!@+JRmO@psP^tqrQF<=B=>y%{dUDz%&2)pkiZ zCS%Q@fplxSW4Y(E>$Jcu!M_a%945H7~77Tz{f%~#Z z*W1!(I$e8zFEfy5(`P~<3qWzTJ+eoSSUXY3)dfnPX@s#S(zU~39e8VC-X?nTm(!XX zv+2UXyXh9ZUX5FIBdhGK&)w-w%e@-`;W>7BT>%0(eNOrehx$7Ekr#9Grt}#=eKU{j z@;B%aYbU68rF)ipyYshOi)R@4yVYsY(@n)=K>M7Oq}+>QYi?X8#MXAg2n_z+K;Upe z;Sq1ZSH%Q3t`jE2hmPf4Me7Lfjd6H}cAy8iFxw@B7*so*G91SXP8rV(n7CSRe!0>0 zE|Anm*G>ySpUbCN>-ISXA^>)`sK^234cyoxL?`m57kdVQqpYtrXCUAsky8Ti)THxzWeSf=Z5Fpzhr zi%8a-m|L?OL`t{06kuBp;B^BP+NWN9{O%?*5#fp^m_c3I4qhuVMS#oT;u`YfP+K98jS20dc!1a+ETv)t?EZ?_iDGVr@9 zWl>M#MNj@1(2l1EmwVm|t-0}BVY9XqMv&@NU0(HEdzI0(;|=(#nBYdciixxsVubgQ zy~eTJOM(6cyxZvrfJ<0@F47~m1xURaiMJRq(No)7j51P?)JNA&3uU@?+A~6NL;&n= zA;LutZ{S8(h~Uj-y3Vm}bbY-+@ z{Twsx#`GpX-;BIUZ?^NaBPUC_Qv2Q4Zh*igzaI^~$6r>GS; zqO{@~AfKOZEv^Cd`gD774X`grw-na^d??*kTm$qA)2oVW0KYliRa^u7u5@>C%>Z_% zSKD>U7I9QPrqooun!}z$$!#1chWaKB-9yPO9D0Y6mvXq~5YB6otq@lL;H!O~Ouq)8 zJz7#LjO%wgOw(uBwHBsXsAMnu7%OD*OsWZWeAW%EyLBY(vcfT29xf*aO_VH6xSeTP8%Z%F1;Vb%%{&Ou7UH~^t$32#2oMskq{zO z5(W5J*neI}ZOp3UK@039>2ocHMT*DbQ-p#n4rPuno-__bBfH=HXz0C>J>aL?-JymX zaIEi1_L0-3N9o*qQnc!}NNU}PFQo{O6eYnZc%U#glPM3;nhCN=sW>`~xt(7H& zbsI2WoA3dw^y1`w3D?svPEL_3;64EcE>3e{J%VCBY-|nbj^7n_cyV$v{tilKE58$r z;CHJN5yYTyq4Yb81Xg%-kr*DnJ;!4S{yj&6)D)^25}vDLqx&Kq+T9oHFxh>H4zt}O zIvnX{I=s}2Q*Y_MLRa6^{YD*Dn%!G$uwNehcHBd{7q_ zRXoh)x5x(;>o$l0{AbSgbG9@6X3mID5RUsM&h~QFN^j*X*|zi*oH3R7 zEBYJ*!4x*+$~aRw5V#Emmb#PV7gm}-RUkJcBMD#0RD{Y?3;q!!)dCUX}Gydah>js_Vp3U z2M*}!K&k*AL8WVTxK^0ybZ^q(w(iY39B=w;K$$ijWDs5gU``?S#&n)Xf$}J~c@Jmb z%Ng(IjG$Yp=!GPU@OvX?uiD=21pReH9rK0x7Dq;FKOXCFsqd4LPTEy4|o%Xj};0 zLxWQ~-AdSokB8{Ag=uebbm4S?Q-b(Hs#1r<@rBhXPVd#}4kNYWI!$xD-lNOiIbxC0 z&@s`(S>jhL=yYmtOuIbFXul$; zc@d|VbV?7Leo3bbgyl@u3%A0|7j<`MdNrpPbjlVgoIasb7DID-UZ+>tM15YT+tO!q z_i>$WF&h7jPIuV!p)(rko*cK2>9WA>SzQ*meN>mTIc`^*g!`pPNEfao$`xwuh#?A{ z!iD1SD@oE9C(l-s5S|9~)@v7LvWwsU$Vwx7VRrEcImV44&$L?#yC<(68r`xGY6RpTy8xwUo&Fg*;kKAEBi)Vw{`;xuX zPq6e#a+AWP8mj_yVH)~LJzS9ufb0g-|}q*&k<;Kn5JjDeV5GBs=bD+)JfuvC{=5$ z&xZP4rt>IR*QP_fOzARYLFYF^`d6rzF(42-hy$r|A$nt}ecnoLG@rz|Z;@}}gb zJ-gP_A_wL8ZBiO4LRQt4E&5^#L)j2j`ZN@yFQ(+3WPGq9K$eF(h6TURD)kWtcBAvd z+KOGLs!~WHAr6aq5|RsBZ4)OifuS|KTFqqBoR`fu^I0uYSuqRt{${fsg+nNa9MA$h9@>2@JZFxxAoNH!Hwuw#hY-HLDlK|#Slz{#QLUaseGKsgKS!rIOd}Aj0CxTq`2w=L`I?!NUZq|AQ3v<#$^$xrE z8L-0#UAJ=;iXO0rR0_DL15_o0-)JOrw5Z+zTRfIKXl+kId6ZF2c6}^$5XHnw2grig zBMr*+^Sc71+jF^YV1}#AzgWl^jKgxNph26?U=RiV(y^JdldTpuLoOCpCJV7ie!ZW? z_)@6VU}e>ymeg6CB%8Q=L~&;Zc!A2| zNc5_sZuunaOIZELb+4_MUfBG^EJ756EltzsgE8t7i74tynDQ_~Dl%eC8P*qNWw-Pu zwGXHaEZBnc@Qh%h$(#m@FjdPfV&iC&FYU*n(}duAKoHP{x;s zaA*CT-Pb#u9^ayRYx_R&xgFMcBig*3HN{#jd?qC_=CTitnIE(%V}%6Yl%U@CgJV%q z+Dk%btMRTNVt*p7P05b`!Y5Z6tkZb>w2oT@8sYNN8x|z?<^-OKT=94oxLVDx;247P z#4gfQAPdgCA0G{6M+@C88nI?^bM|NigFCC>fY)ykIr-b0VXfgRo6ZVCl?dX>v33Vv z7w|qK;Z2Jr|l#FgoFt6g5uSy# z>KJAkPe?sd6d)fPQepIAlw2PADW<9V}4E6}r@>^e;GBzYW zLCU13*eH-P*yy)%NPsD=qIBMl!FZD7^5k7iEM7nFuLwDm{fI)d?wTb2b9xJt#IxImiWxaJ8>> zxxE4>uYk!bfqY8ZVMA*YG);2jS4-yvG0A@83rmS`$Xb;XgL>=ddOTr|W*&Un9w%x0 z82sYoN691NLw6_^6@5gHPxIyXKmW<4<| zj*TNXikg;-4}lO6=*apE_2_;#Mt+lFcaGnqoU6nWw>-kHym8k%+3GJtzP`VX3f7lt zA7d(aQ?N_kL+-DSoqOLQ?c zm2(e|^omJ|;YpZ*PNYs3Gn6E}VH|(9-l0A)p`V6oa;k}^k&U?Ue}skvC{ZjnFb^bIai%q;#GQ;y>q$}nBttR)IKw`4G+ zxO;*N&gX~Rr6yPAy9*fJ+hB(>fULs2^!<1ySNBQQx0e}_+z(59N zgs+W@oHZoipeNGg`NtTe7D@RX1KiR%z|+FTfgiS(SSY|W`G8lpQV5^R(KndyztH~yFE9RvU$LZLrtQ;T+hGfZcQBR)=FJ6Kmk z2bhY63jq|D+vaGmd+GRvT3dz zT8$BoI~ra_nLRJL)pHJ2sz0UBneHG!PUOiVUl@SR2^b!DQOvNDHv7WedhmM=S`DR0 zQ0;j_qCT=_34c$Cvsk6}S)N#rYCdQwM@(tZ*)P*62l-;ZX9Sa5tO4AS`?*w#(O|;B z`h(@-Gavp&y5rHi?vi!L77Hw|Y^?`Y{}V|cWJq9><&m*Pyofvti&eJGoyoIa2m79` z=T1mho())Y__<&~@dK8>`N&fkIr#iVZ1uC{=wkmu#N;$!RSW|%WT~Ke0oTy7&9)!o z0>6dHV#oyGYkW;Ak;c}{^)udNQqbFSSU(P#9e~yrJdCE6SGX5hSSDT>H}>#f3W%)N zydS-{M0?RuE~g7$HuQc|tD)+QJ~jaz+*|s+WhsM-w}Q=G=k%o#_FS)Ix$33M6LGJh zDnF_6ljwz^JkwR>C+qTdgfbCPjr+cY>^(3E8e!J}gstCgqc3J;32sBuwwDM+rA~MJ=f;5WdVkIi|iC6)fDV|FO(+Fnt6=D?vHYeM#{9<6~MeuH>ap z{K*ei*(fumM7w9c$|vDL)VIp~=gZX^Dvs-hXi2OTpl3I41oAirTtJ4E{KQ!4NAB>| zyNThLmQaYK!?L^gz*`^^Ql#HctR@+qT|YC)G>HRJI5*399w^XXRt+9@cq2QOP%$sVRgWmz)bGa@vugPgpl-u)Xd$mXpz3JfAHWPV0vY zv#^@gD#X<=_>PJJ?Zr5W40$F$oXd%4%worArOr{*U76;m6n1Z|z zuA(vv?V%zgFb@MLxE^RZ0DD?LYPURr`zfg;d{Q47#%c(S4u|n#Xj?Am>3GRCF>}4& zdV`Vd843sPU+L0XVME-#FB&(**-f`3pg+9=1<1*M<|ohv{h_kJ}0$A$500ePB*iVzDndl@aUO^?3H>Xh?Mq~SZDKyj4{K<$9TImIW!~f zO?XZ|R$QL^iD8!raK#ll*yU}WG%4L!zqXQO+YQC!%aUWN4D;pD@cV>*krYSti&mi3 ze*xnMk+#UU#s2im5&>Zy`emOZ7I7w$lkfR5Oi$P$@dg_f>u|F$K%e9e98H1$6z#!T z{|8ulL8C~{V0bBd*8pdws+FP(;OTg;-S-TQt>Yhi+p-zpuRphogDk9vh;}epwpm7& z36h7U5mw<6ZFCp+AKEqoO_%plf`+u>WJzWL67DTHPIkP774kq~hDeStnnC$m9s*eW zS~&_}bu?w1>%e;tTGUn(cprd`9zzO=KXYL?F=>thX0-CQevHMj)AT;+)@8e*56%9! zfB17lX{%@^PEqj;>T!+{6G3&d=Dgh>hpXlnnskrkAc5cgIilIbF|^WqtM|p~zG$)h zvZkuEr?mV45FVFO?yryV`YZL<@Z}-;=RHK9_GcC~Y=HPP`hwe4$itFEmRn)Rt=^M* zbgQ?;#dE8-j7u_eTVx?ObARSAcycrM(p1CD{fl+_@<=dq8@mdn^OD0n>WUHxKV%s6 zlqa90%7)$h#Ghbm9x{CIR^|Ah7Zk%u53bA|R=KBgIV;m{1b&w^}o z35+=|oRRCT+4$1x#!F2CTc|n}4NU@Ma$Xu!Sc)^uA**HpOON3hV3WaTfK3LU0kTGD z2AC7|*=N90?`F>>Yyh=}XMk&{62@Hog{OE{4~ zz6TBRZ>>T8VHLUNh&*L-a-tfg2G9HM=|v0@*4_L4`=Mz1Ys^5Df;r5Tk^OaCB2wK^ zrJ;O$FUaV07KCTbjSVgWr2)csGAEhS8KjJ?DO>J#biqpPd*SqV-uMJ8z^AP`YTmXI z_vUQrDk1J@28&oyfStk_&*v_$?Yjg@9)IDWfpBP^O}{Dp7j1+ zSr(Qb`lCM-0a@1POh8T1U|U%)I0@}LZxVVakkG#G2NF8Df`pEK`S~QFZd4_@*tFS| zMC>Q!58b9Ej`589mnB5wEg;T8-}7*D=@8XWl;y}~29t5#n;L0Ozk#o>T4l0z58K&_ zZQ+VsN}_lnf1$_TeNsgiPCxjGNn2^D1`h5jzWxH>$PfcQJC%eId1vaMcU{^#< z*w%tL>Tj45U*Ef@S@hp*g&prgQ^0;-SF`67v2sRD{X|1Hd{`V17)XOjsnvlxa557z z(33N5XD*!j`;R_+;2RJ9_CEz1kr3yA_x|*aUIBoTB82|-8$88OEalGah)d(W-|;WP zY5!vLck6En=z1w6A;Dx;oywrXMoYxXt4(ek&K6lPCq>4;7S6}~yp(?zYlzrg%NBn1 zV{f|cE>5Rk%mR>@N|+qxc*_>Pxcv9)6y2GSjyrfg#w#PDk3K%5JBoqVsj9b7?CxT; zxL8GSXx_nd#XWcp7kL2sd+&c#e=@E)q78< za1Xgg3QvoTD9S3(59K?ZXgn3Y&;cCSblq&R0<} z1p{~hyEVU4_cM*$czc*cJPTFg{tW1 ztBUM~Irim(Z2%W{UEw73v+%xaP;k){qcHMn8xq|SRoKTN;3HZNd*?V%%DoT~-h$BL zZmc2opyxQ8QZe&5=3xXYx^19-AGw9(=C{}uN8%Y4_823*H_GktR*nb`@_A>6;P@&_ z#s>w$xv>l9V`s7xMGi=H;xuH7%ta%(_TvA@8Z3phz*208kJ@FlYzbuA`222JiW&4O zmNLTJ+Q_A+LW&+ZOa+OggFXYy)4>$1Kl99+o$Kx}0@{~?>m%=e_fu~>-4+!wIIF41 zSTN}KFMU{}DbdC#X^E;`I?yE87vJ~x5pgv)n~sLuHf+KAE~8Xpq!8Is9{?lkg4}?**;brR=Hkml?rX_i?p#)=hgrZ>)iEf z71x1h6(y&PONe4Bd#gHrM+tJ~v)fo*JQSOLb{WrxbZpQl4~d?~1h8wA_iTbZlWq~m z#f39n1O)(89%>;y+%NH9{kXq+)W?0TT2(b20nbLnqL&i7Dm`OGx-E=+?o|1yx=Aut ziPMQ1!b|;8(>b(?S&1IaYBAO4Nx$Sku6ug_x~{Tu}Rv*<}ol zG8fds7+AoG8FQ;F0<3QiexCLBfQ`)kg`s9EQktn|dzjh zf#t^uDvy;u9@dy8#HzH3@-*pkw`cRL-^sS;3|aGkIlyQ;H8)>37N>r!T$}y2e{_g8 zvFt)$4;45(m_>Ez*DoA0shYv{S^{AcxIx+3FUPCqAG9Ljjn1q1N%k$VnU3|o>82=A zj_n|9jA(dVHdY*~m)8L*-pB5u6HcP=30HoZXK`H5$eI}j*lJ5~{a}Zdiyr02A=eIP zq*AXg*7)P?)wi~68wCc{>K8e!(^)zWs*iBk0@KGfymIoud}jthXF6=0`JEcl9CfHElK~ zaxiRmAA+LfCPxyaZKOBIVW)JYgSwYVf!tCIc39{A63H#7aH4tfBVR9&aL^7VqASizC{(1^Gu9`E07j|ff~UOiQMn`(qfD2kCw2V zfRgtX{B!k@&N%!*ecT3ou03vx9iv;XDh94RO0nN^<6x31UTP>N81Y>o;-xq0gDH=y zolm{DYx&qmGpJGS%Q`X?#o#U*)PhYas8oBb#(Wy2P_6cgVw2xyFe6Gfzn(-^e{eIU zX=E>Of4ihgFX}g3okuaC{1lbzKBbfT#ohF)YK+TNm-Tz$O2eKg{6pr2QP1_tm#CiO z)-tqPX^d0V&3jS?&Aey5k`vT)?;oAP;&-yHZ}W=nhz%4*{>pBqLj<-3B!S0?#olf+ zkORuG3*ArU=!FC3H03WGY+Nh`-Z^tOgVi3tFcZtz7;YXhF^F9_-aIl?4cywQkwCIA z&1?Yb?h&|jtQ5vJROw6PNgXSVNAJ&AXxEF(T_UhPtE9Ul_x9 z#hjhqivub*YWC%az_1%0A{g;H3BbUSuF)s41W?AJ>2750#G`!#2+^qhW(ifRlXZsm z4fvc}aW*dV=AqSN7Po$5)J`wPPYm8X`Dp)Qs_m;w9 zwT~AQ*~n^ak=Xyej}Ey z8MM4E+J&TwxTC_!v2awIBP!;U#?*SBri%10e93(}_P!No+hfIGT5@|Dg+ae@gdFCl zhdpI%un=+80I?&-p5C==`r(p(9Xr`Sdb|0L;eTsn2;<~|<7_-MA*Y+Louf=j+5uAh zWyvRfemA^!?BNy4sH2&*-L9B;&{#U!1jo?%sh|B%Du%)_$Rm2k>GC14NG$BP!n=5;UPm|d`W!x0o^FS zHW&E9=!nj;kMb{#!Dp87zDT`2+D6#_)-&*zvRgj&Tg=*WqW5zyg1EG^Z))E*pL*rC zI&zE10XN4>`1#7Ou@+LakXHHU?xauUl9Lj=f zmF9{h-{jW9$A0nsUwF&EE`Rug_xi{yo|EDYTC^brI$(R|GJo5~n-Sf%#oh;^q%4F) z;tI($p_nZ!w6tKONVU>ZKt=0oLX?6xc|j`jd2IU5pu56q_G0hHw;5cm{Yi|1c>2PoYzLSiCxkn`MlYv01=!P2rY}QNfh)VP;pd6hP-VnlJYX~tcnboH+pYM1a@yoLWft4N%^>zHvY)^-!7=UoWV}~ z?mXn+>R>?SiC<-ImFvqRAK*87tUR1@BYn2r|F^(H1IRv^%F-;6mq`jJqGgM##TSlU z6~xLJy|tg^+tGKvavz)qVSJQx6Z&%KPVSwuGdBvRqLLs*p6wK|)1Oq~8j){#!znr=#k` zl%KRg5+<#W-mqqQh#$629Tx7Z4l6G&{gj@a&b`lR@Ba%^9#2a9vgfYQXDjZ#wtJTl z3b`o^03DBdS)SQu6SmQB742)qCjK%sfjG1;Cx1GkRoAZxJ{o{SA?IkIEv$qqBfsA| zA(3UB82LW#1d6bC0>`fBZzPOr!&tL4abn8VLLjCWWUPUr7v|0j)gHe4HdoJWu6*TO z<_fIbM<^W{A?sW}wT8Z$YGO${O%&;b=eTsk?=LAY)xodSxlp(J-l+!PT*-U7i8CK~ z&uFK~RE#SGrh?j~qZ0&K5Z^p0UXmLh7Np`R0ALzFUhcie)JNx$yaq7S@*#T;VA2Wh z%+6&qyuk|E(aEx{^QdBS>RDPgOBeuwhaq0%c+z!nhnN^Z8dfU0^E_u@Vo^4vy)TA= zk!%nLtz|=liOG;{vSD;+U~EL36TgTw7pM)SiSrxM&dB*+MA|B(Nzxe7h9wQN-GuyP z%V^G|v81cmfKP*erxO+UstFTdVTXNx)xj39|r1<7H>A1;M`Q+z$3%xm^^-%A=pMwr~QzkQ`k?ga!TECsZ?sHQ8 zCr|Haf2sVI7CJeTV^t543AT|QT#*M9w!$9aXzhPqi5D@DF5a~qE z`xd&~i`k8cD;hPbj$p zVuBYN4h$X2&2T7?NBp0(KogSyF*&Jojg~KTO~nleD_#MiJj;n!*33R0vttBm05Qgk z0nw>|7+n(xt+2<(TjRq(sJH=P#Va5>Bs&mXGTgufTAycUOQQiqn->Fu?c;!n)|xtQOYjhY06*nNPcm>1=$qod*Aq^l9nx36wHVq(hUJM9XSbaEj@}~Je>0wCP0Mc%^ z+QWdTMFYedtN>Ai4v4jQQJjxz(Xv~M65SU)Vz}#Pz5SWix2?LW7=K<#OT3|k2)h#e_AdF!8 zf>Q7c%#$^kbqRs#B@E2tRaFA>$r?;boClbv*8=l9Rowz}DXYNr>zg8&`|X2avo0Yp zy@Y}3wc30v++eM{uE^&e!&>D`{7V-BqXYyDf8k^XIjo|Lu5F3f1SlL^C2T|z5CFJVi; zT4UE@?hz|tt2t@x3cLKQxTILrir6U5JDryA1lMaBHL10X4NX$ks~7Fzbbvz|_Jkm=Nlvn!wajEm%705?W1q30qp! zOEs+~wNwj>UM5Rq zL}6X}#%`7;Fq=uZOaNEL_)L~Fhpziy@=W)1U5xJ*(CCV@JiyJKx<`b@u~7a=+8p2t zzV~Xg#0Z8+bDcqIyL>qD+sP}1C{;LMTGiPb7Up($lO@OnV36S!l~`a$&^@AfJQnPE zr2J`425Fmpq};VwPWXmjaB-91<=q*Nw~M znBjU**-~=3cU=S=czaZrsu5(@o!KtIOWC~4_`v`vSF&6e@5zml-uk6#d3~vxviYTI zIflgY*fSqr5>o0*)#&=HLbTSGs_|l%s_9GE2Prf2H7$fMze%mSs}TRLYEa&g;+7SL zq-bpU6b!t=^O}F|#A5H@TSYAxFS*)NKeN5}D@9u|ea1*h=5?LL=97L#GC}&}iDBVl zA?WMuIeqPq3N{g3B;4*F%e5`Q!L^r7iiW=a^yk$&)HN&r3*CW=gJ-`5J#K+!6|N-{ zr55}c?Z`<3Y91L1lSw(-EW(2p+QGMT1h+y9l4;l8Q6S!YH_x?Lwoyk$^Pz*fe$+ys zb?Fm{*3}B1jE=|`ve$rWdIgHVweC|Bw?b;t`&5Y4Cx9DhtpfE;^bOxkL)u)4-X`*r z5&-79A8WxFG8}&E(TrHMtI{|whhGx@Cg6?gE^^n|S$CbCmg}tWiX;4`NzqU7GERDr z8i>LhXZZNxl%gY=JN@LD-Qx|0z?wB2ULj9!016nWL6?5n$hZe6#6BC4$Bl}m9T-q) zX@-r`bXujwqv`%)(YZV!MVahw##jZ7P{}&cQ>Y{!e4+GoqY{INPU!~uTxVYJ@7FOD zRmqu`0F~8t29QE+LQRBB^%bM5Av;?&tID@mmlx~A$)yY1ezInQ;4+tVhx@=8vjyqCXx;&Ir_1u;#0=>bt^RYGgS+8>_i zh;rr6#DAC%Vg(cYzzRB4miYapYLjUa&r#9Dgk!QJCZ>7E(#38v<&@FZ=9t$9>ZNlqG12VC6RLVysO|~ zIma#03crxVU3?Cx76~^(QyH~T-Bl9tsy1%9TkA^U7E;Q6?PuWDj>}7vYjnGbn%uUC zltiLt2)FoD#3v=#Wn;=mmaio7+=jA~@TZLg{J67{t2KoHRVb8QOL;_!Xj5W=)t%3U zljd`fm0u-6br0G)hbHPMpR}a;#lc9G#7dA4U`~9}a%mv1u_p4_E3)hP8b_t~^-wji z7FMeeFF*^c(B5;{mjS?tl_T#RjL<`%`_;&}7?{r2bEmq$olaUcz>#J!AWtA;%@PJt< zzCI~(Phqs6UVqmJ@J0?RV0h~dP{0aIa`qfG8? zaN#Unw)!30hz_z8ZDmBVR0{*>iva2@PLY10!tE0GGg%sz74qp-3jAQ zlUGCQlh@7_?YZ(^X;(A4MrxM0Ae)J>0@M=b?QA=M%oc53AvRXnA;PcxL}UuW_hm$!1HagYpd^<3BbR2f(3e>`&_@!+gKB#DMO|`xdZm5%M?&xA2pE!`@)uKy9HnI=yV9#xA zSL;ePni{vJQV?B@i^vGP!2vZ448mqdtmCaf?&S;@#6QLjSPPT#aWufa~uRbeOhcDQ>0{1A_0i5a$r9U5y9RSB7@D z8V{@~nOj5R)p)KLW6D$GwPI|6F~aFa6S~M=cNei6@qn$xgb=iicKd9|(zM-(mxz_k zh=RedI=)$vuXxstco|9X$_qhJ+oO&u!DL!C0|LI)p5~W0uob!GjCHWM3;lZWi;6Mwd`zA`Iw*c%%hG-!bMu(hRGL zJ7B%_U3!`vHibZvO?rF;hAz&NyZi7}db89ve3hP5$Kk8=RBHGtz0ITyU8NVV5s23c zWZS7Fy>76H5ujhaep?bzN{S#9T1<7AfTjerE@=rfeG^lS5siCi39 zpx4gTLL@_FV;Bag!$p-oXy^@^W^+YmjFB5God;h~Boz-vy|udtr7>wCaRBmz2}>T1 z6*F2v8x_EWr4m91RLURPl&%s_IdNN}NFGp3M={@1*%I8S!sLVCG`Ytl3o}M!90VM; z5&2{7nxI-37v>k>)WN`@5eA~x8BGB$yrm{?v7@}Bl1hvlw$UT`B%JoMGVOPrWl|Fw zxULT66U?!#naXq(#}t1S)idgbEVL#mDp7E_&aYiLTLOUJc*dKS5fK_zu|n0$bZiSz z1(dEX=S3_g0nj^QtG7%IXM&xgoyIkzwf0(XBz$&iq|I8l!))#D{y7+ygnz5Bhr;flx}@aRVX(T9FAeNftzJGD6ny45l=< zrIk71a+#d$JHQNg3%e2kDCW9zU?$F6dcS7CT3EpKvb1&3&a+FCd9-t~Z6TNtKLtd? z&qbz|^Ki4kjp9nc6&t7WcABs_-v5bDE+yrkCFOVY5JNBk6tL|y{5V8mYmCY|4oc6r z#`+tnja0Md#U_Z5q#ZLpl?g3xoa(d^`>%ziW23evp9Juet&lMm7&aI=NFUk88~Vs4{BVcaJU{Dg_s7uC`|DtBJjL*g$Gy5RJhur2ch+VQ z!?EFti~NdAAlyuKSgLozVYq|Ff?-C};{*#WYZ6@0WOlO^UvFds0}Z)#RjdjZo46Ni zQ@@upj^KU@{fvA5UPmM_)_9rU4?HcccU`~7*J+HGa`Pe&OE}5Sjk~CTABk1eYp&?U zEYGdb2L{}Z20L&H?Df77HwSm3sn817alnCl5G$oAw~O~EduYjN8N~s?b&FzF=|)md zgid!3z$McTG_h9Y=QfcC@T*zTNHJC0IeBrMf5mYQc^T`-O%IDy=7e{LXuFDNmX#Ww zEZB}Ty{)bD8y@9u*=_C$Svn<+0|u~altQ*=8!T|up9+Ju4m9?{VD*LuODp(w)nJjw z25U-#rBQ4Q7Gr6HHPslbsWS}Llm=^R6cOUA& z#zz;5H}uyx*jp8&zEiBbjZ9!SN6t_{jhq63FoHiW}lFF3M-or4E+7~E4_luGS7X?9T zI~KA_fwQf?3x)QuH7U$xgmkQrCOmBlAUTV8NIl*kiej+E^zllr_6c2uTZFJ`{EbjN z*bt>ouwSnm7YkmaI)OrgCgJ-D(pnIv{B$bIHZQhYFcQ0;1F0G7D+NTibr0fgiyl!Q z9MWd(*H9}UKYqr|1((JsL2S233#(z^#b8)#Q{g=$=~z@`P9)8J;KKJ$*<2RMYNwn?H8%?0QE0JOvkAriuWZ#>H|p?3yS7=I=+SBjaBiSMNd9_$uv}gPxTX#fIEw19 zvjkp8by{01yhqv6dPq<5c(6TnfS=E;2AZ~Tkwp!$_7Y1xYC~F_4IN+ zvol*l0Q5n-PM|Y7M_pstt|Z${BobFEct=@ZdmmGy7pjM}foodt!`c7AKxp*$L4Qbe;kYh39vwmnvFD`>_I{;$q^8wN-e=x@wr@6tH$REFmyRKyR$U;7Q6??J5dVVYlH8 z7sFO&2zKD*~~d-r4%v z+lju>1@odYywPsi7+#1N5}7-TGnBWa!9||(lTfoU?g>aqE9-N1hI%fpyr)k*zLb>p zf_@tlqW2Z^$BjDu3*gH8Tp)k=uLSu^DpSPw59Ck(xgcNRKK+8@{O{Vh{Iu?=M3UU+ zYA%U#3!8L)k;-KX7PgeS!^56*koO|nNH0x(0+E%OQx?qHc%wMuG7eQZhsslCn>}H7 z-I`x1$Iz|$d|wtW>fCLiiQ>c|EmUP~CcVeadpwnsl%=3$^!`CC+FxZouJVYN3sMX} zo<~sd&IXCGJzAUh4s5IRTGCvSM}eJ6t*1zIiKu#Rp;YPlxZ56Bt{O|2m$(j=Ebgi5 zch#+}*(D2zDQ-1$gOr4bG-!<1^3yXv^L)F>n8|_#yw<5~tmJW>Iwe8Oc9`z0&&{7h zc`!XnZn9a=ioeLnW0p>pm$^XtDr->f>fZZ*WA~{n2D;~KY3VlNkAo2HZ?o@1ymqWF zW0*;WqMoh(f!wcg_FeC8K#4jO$7yT@nuLD$r8Z2H4;pzMFeRUf|1g-U-0iw&*GYnx zP$hDp@qa6w+n(Sboti&K|AE16w>s zr;mS1L^G6%(DV|O;mIsxr$&A2=KXTj0@Y>VUf8_s0gIHH^iwi=V@1{Vx3^0G`QtC~ zIPQ=8c^vb{x2QgD!*Wl~@)vmB@Pldc!-+=X9scoD`1o#KH^z^})XS1L3#F7^YF(bZ zQO~J;eUl#7zbx6quR({oY}A`OKouQ-d@qmFv9|JIZ|bBqwcY~2;ZT%ngXjHr|GKZX z)w}d|s{IunirxWT^Qc_q2_pm^-Ub~2zflt5R~a1=f3cBxG$y{UP9%%hOekv6$|-F) zV=r3NTk;Qj%gVR1Rh9Dbgh(bU-x*$y`|Eqc>(Lxd#Nd8Qi_MKmHmSNY`(K*8L+ZvD zdz(Bz-0EYx?2n@`P*tG#jaY0dDuxIQ(82WZJO~ue&8I_oAu;H1Q*$0f!Z&Ik@qX2W zf3hZg^;Z3-$AiW4_wu+yUt!e-y@^p9H%kcEoT+er#L>GcCIspVSmV|YW{9JVE6I31 zYUm>!E7cL6Man)J6(D8mhdV2HBIk&0D9)}Av}3YLug2POS)~UcEzqyf7zifNas?~1 zqJmX$M_2{-5e_8=OAs1!3htJ4ajm;0n{hK;z$&rS!)vR`iR)p?F38D`hMa76$XL^> zau!t7;3Tje@e-0?$txL>Cm2IghRAPZ`B{r0MZ<)!35j}8zapi2rn=!jNek)kyg~AK zVe`gCa!h1BF)SPWY1}x*37e_7va40kAEF(M-xsR`Ho-VX}qdd7DBR6K(W5#$QWw4WZ87xW`ZZzZR8`4zajbLk27xh6d%d;9o)x2_oYb!i#Lxc@+tIXX88!@X*v+G zG))J>i%2>Up2GG27Nm5r88punGhxcZJ%sy2iJJ2K8P-8O!KS=2#3?_cDbK`fRO6Mz z40sk{jtuMy-$5a(VpoYXp`>C$Rn8gZoT=Fr?s{TZGgVH;Gd8-}VONJp0^ciP_XLAo z86s%H-e7Yf4^!z+s;00?BHbkY&2HI+?JN!%Q%V^k3O`~@CEpFhuI=reKYW1pYkG4%N}Jcd61 z0gs{2M|cc zodZGdf@)YJflz1F)!(uANVCfG5$Q`0<&2aQ{o&*;J$YZ1927-&;X*Hyi8vgqXbO4@-2mL3$SQx(1pROKC} zoSU3F3T>4`O4^`zdn-ir-fHI;*s*V$7h7&34BNIxG|?27D6<1on2qr$){9Y_DIh#=)3QFzZSC<~Q=o;b`Ap*Y$eYPmr?biO*?m za+77_Kr()6q;eWM?5`U_;{G~t)5v_b-S^k^XeYvz9>uoF@wiLCARq!#esULD`0j+s zd!D57FCY8@_>TsWvvP|-Dt{qybY@ZsNPBitd2?FF@(`Cv0;wnh^$JRn%2_^W{zB7% zQlvGCwOQ_pR-oFgiE)|WPt@cx=sdK$MAMiIyv+WvvI7HZuy2S5dw4BZv^uc(7ITVT6i3wgsjwUifwm#8t&AvV4Y;>aTi z*cE9*Bn_=dDQdl9PWvwBBS4-ol0GLLB5;N0OMsj&SNP{&ko@=_a)q;D?z3iNj>Ku& z*VCqj)bigrfpLVUB4l2T0dr42Ponqd$6C6YbmZPV1_V1Xbe@5^fhAP36Za`8=(OLE zomeKGKQ}-V57gLj1#CB60oy~afSq%41(e4;CQDr3`GfW&PlX1D%P98Qb?VGSDkIu zIgKsFRLOZ;?H8H+(AEwWu(P8)w}d`vpUCu}tx0b%w(v~4!+<@F)WPgGju4R>JY6x> z3p$)o1ePiR0VVm+@Q0GPIGzsW%Q}?bUk?iB&8^O~J+( z&KhS4iwWShNQV5zNQTZit5HK$5DM_uG2&?`nBOzY1GBUsGN!A)_44tt2FMtyWkHme&IFJ4lCZXP0mVMx>PCfDJiVPLWs;tM;-u^^Mo-47AK>+N7sUH zOLC9`>$PB6mIC=|=`$FOrC1Tg@+X+|e`6}kh1FtZ*%)?tz)U#xGF-_v6I5mxojb3P zgw^zCMGK?JcY+`;Buf^1f8nZ(mM%Bz&n<(_uJQ-3L#ej!9Ln5QWBe9zQZnttT?&A~ zhlFGzfkn$EG3|vuwyQ6oV5E8hLw4BGvVp)nd`Z=i9Zm+qOOvZ&2%ei2IVZw0H2OO^ zTPb*Dgc~ao45z-V78(krG{;}PliFRof+0NmolID{(vET)g(PKL=T8(OE-Sa!Cs|V}5R<87MP#vqr1wN*r=h!#0Y!(&Q6cM_X%AN5;z=P zjA|Ps3wXEvMlrGKov{;-tlk+|jc#~vsd^hHb$MQs!OplA_B0O0+C>s#Qqm!INp_oZ zW-u_00!7l80UL}WUlZWrCiMhHrrhvS)r-(id+)ZuMF{N@3=eeE9f#J>kGl=Kjywyq zS(Cecq+wSbHZFvjExa`6b@dM3G^^vgPZi5acUBpJ3v+cj^pI9YBh^eNm1@kw+N=uA za=V))$WVZ)4_ai{rkUaO4Y=XTSuHtNwynV~-(=RuI_9Jey0sqQN74lYG=zFZF40H7 z3kJvj0lo8D8$55U`_r{adZl34`_;$k=+G+ct?yLdyH($<<4q7!Y1D-w+pPtu`VKY5 zGYh;_M$NOdJ?v#$6e!67`>nb1Ry7Sp~{qIc0EgD<#ua)VNUL0Fq z28gIk`O0*^aI)?ka1v_H&2_g`PTXp{oqi?<=bw_u&N`74j+-FIACoym!J;`LW0C%CLH+1!-jZR8G$tXNn~TYL0JV6-EdsGZ?WWKRIC_<+Q?PI3gnD ztj$M-T{CBY*CVUW)c)y_!0Vl+pB$QHNtozTLsl>uv&{|Lj)TRuIm;3;Dw}0g;qB6| z*lhRwS{vrS-|N9kU4u~zj3_qIJ7p_S_<@3Y^OK0xDE`AN>@88L(qgDkP6rb>1)IOt;s=isnWZwybDKu`V9ju2ZqMC%K z6Q+L3DRR&jHxdruaj@A6sI_XHmC{-rX~iN&Y%7`N##F(mRAnSau%_po)pc258atbT zv_O$ov#yCILcLImYKnS!YxKG?_g_=+>WrM4jCmG_o5Pke3M!VM0K5@qqV7<^_doI*5P861?kh$_y1zeN@p<39{Hh4R*ZGmbOyOO{m zQ}m+qrg5Y0_eo|t_h;l+&7JR}YJlY`@xP12J8ic;FpRUlG>Iarp$Y0TM=~7#&L@_V zUJRR{lq1cQCq`N=ScCor_HY7wOCE#?I=Bqc=qWNpP}dg7IZ_3&Z5u0MhAq7_H}cQF3jFDuqdmv zGJ0T;nQCK2w0SIZv`jZat>Hv=)`e{lI84*z2Ab4SbbeUsyoOC6TC#Ys?ef-J3(hEw z=QK{D?IDRIIF#ON9!j^q(*ur`D~N$~9^sr0*5}fh4ZLBMm`{>E&onj-y-Pu!&^my_ z11Qn0{savHSvaAdYi~($o&rx&g>X53ZjcF==w~*Eh}>ywqhi8++!+JB-4h`*oK@#c zy3VS@zZ4t|H!-mTzKO*y^I+r!W>9zaGw0Xx$uOeg(u#T*;gi+`LB%QdXEuYbl?@$Z`m{>;S0}iDzYOO$b z?E@a{`$swJZep>7MCObHSi`(NXvn~rxGSA7!waflWlQEGn|~~F!#5*C=8L8jkT9hj z_WDTpFSoK0tOH>>Haj6ojsMGP*x@waEDHbaich6j4WuO)6h^{qfYMW%U?Mz}gQ<$27Be3{l)QW;`(xKZjCsvuuq6aY%KA`pU+^!#*mDv$_V7?ZRd z@Fjw1U9t!^K+BTj+E+4Mv_iGTNLXu-^VzGlOz8N+o0&wgbyOnAR11NsI_(M$Wsl~L z2%|uTosHf+!91`>|F~W?ON3oEmNV zeV`nzT;#)Jnba%y$bGL1-p&B1^Dz!wDpSKOn_c#WKbY!mw;Y*bOVL?{MF~18vHfhR zi+Xy|0#hjlfeQlWWO8e{Pl{DB>d}ay#rCC%EsU92i}Wm<(UH(%vYkYsgJk$bTVpCa z&|g-zc5+t0Sgv>ig=j4*gKhJ@I_YyE;L3icZB3~=%a8Lo>5qm%`L-$@|9)YNG!8sWC_`s~g|JTX zqP7c(zx*>mh$gRHVQKQH@DqFilHmbcIaFv4fqpdK7*eG;0(j^_LxJQ^> zMI?8BPp`NXDB!Q@Yl>d6-`9B&lWhP@>i=JWZc$d=N0)j|G?jE zi@krW);e&5ou($4aGf?{f-lFAf+$Bl(%Pmz5m69*!8E2GKcl*F!t@`AVw43BYMt02 zNYqaXQNfI%5!ysG7zyEZX|cylR)RH?j=4t zkZSLriZQK#`eT9>POz&lE-coM^9qEU@@-tr_68&J=7SMS%qlcJLJ))jR9cLam9Vc; zQ_}u8vV~rZ5dzkFfw-ClLdEsu7NtI+VO@+VMu`Hd=I}FBG-X(()3y*Z)6zOm8s2?s zm;1l<@uiyeb40BhoazyiRM(Nx;VGcWOQ_=}dtYUX; z@Ma&_ornvXx2+krF0|hc5pMJ8iILh!75UQB1WGhbp^vybV!@hm-urV67;?%fj`cNP7|-WNVQBP_ z&05AxG54Rh`ZYPKC8C1O_y&-vp?Q=%EOjLD5Li3uMWb;E=6t)~V!GJAv{;F%ua}25ONW+-tE$%(OyEilXo+|WQ^IzQ zOc#5$+6+oEN$vsa8g*$kQdDa~ll1}J)v{1bkiJG)x@P$7y!JP!O$+;9j5~=Mgo*Ea z9(OXR;V93t>GAVo)JcSVB7VcK?Y&kmZJc$lR`|~vTxM8SXC-Taum9EKi0XKxEt4Ef zd%yj9IChaq%>?@|Kv1{?`LIPM+oBb)K!8~etFMB3ke7#TWjPTnGUkrqlV2qo>V&yq z*g+ZZju}b(I9|5BObXgy8;|o!`t8i^!tT^A5{#LcD)@+F`6#9`$ysTv}q3lg^!;%ErmMcrM6WZGSY?vM9QAgSB3x7tl-=Jq6*A&cy?6=Y>`k)75h~52B&gVLSI6zLdM@mxdcd$s))VhY2SUsvif^bkFGmd2>um}>IDB~)UHeQY> zk_uaCG@i;TWAOFr8ZP?b^ksjS=)E6O6_Nk#QD;|pPYCc8mL?@U!(yei|=n5_^p&1!&7e23_C3{qt{Fu>*8Z?7n3w*D8}ks z_Om8zW_s^8YfLsIY}S@E2{X(DU#CECyaLYPm6k>Cqjr3PS6{B-u&)G7micUWk=A5j zXSMwgOB!apZ2xN>ywbD@k_Nkx`!1ZH?SHtfmCdYe`*(AX+5WL_o9$nLh@ai||DlnV zE`do20vZNPw*Ndx*?hGr*>)J&Ase>+YcJA-E2|i+&xlzwiN#gB+5Yu~&(Zd;CBp1r zRQ6i)O({mXl*+g(yQ#ALk8<^s`QH%$LHlEQf3*C_r{NfwL%Z?XDGat)>v4)0XAgi( zd?@dK;FFfg{ahG#8AhSFYF_}ghHP&g%4U$k-~J`8^sfYsfVjQlfxP%7)sai8FPP>6 z00efbm@5Nddk6~Mpg5dB7!npX3Lhd^XmZlI&$}kpp6tuTr?R|<+{`8BAac87<|Rp8rR0>M< zZlby3$!1{{n-1S)>?-1Y@f=Mtb%i9;Rrn}jEo!joVS(uF1vP?ShTS+&w0b*XX%6VK zxR+{z(|9a+Q&?I}g(VH02uoKxy@K9?Y_}jFa|x~h;!wYjSIhFh3P9o24FVz6|;F;QiT_x#B)`s(WaZA*Wl3^*H`4?D${o^-!bVld9c6>VgaBf zxaGm*$j6|q7(tL(Xm#9}&Qe+12-CG%9r?4-yaR8mZsb@RIt+Shm7z%kQa)v8>^D`* z2jgb+OxY_7rD?~v*@Z^lZ*s*@9(0wcwTwc`0rgu-4fEFHT^J(R;$hujX2;0>(A2eW zP24H8)Oj}Bi(HpeLOg6Lam|zf;P3Qe@0qX|(6G#BxA|t$orAQu^q`43Z+3RTmePW@ zjd0uZZKc#%86(SGRoWj?`8$TJme`Af%k%N%)&Z*za*OJWwan1;US%DS^aKJTvfjp zs*JlEwr2R*z(sgt;Sk;=kVzo)1P~iJ7To--gJgcPh{Ixl+xzdfTnn9nb00*M5>BjJ zbTuu;xv#EZcCa%}cYo5{j_gq21h2RDrJZjB2?05NG1P>RI}uL0v^d*J`$2jLtGvm8 z_ak=xu{C@UW;Gai8)-d=j4UQq@1)w*Lv;$LQ;hgh4`p8p|8;W^B6jV15S@;PHH_y* z_D1pVle#A2dfw_4$Gpu+rU`6U&n3Wbf93HdTp{Aj)*8wd zonp_!i%#d_o*Edr@#)CFFC#Is^|d&;b8w$u+aMRXAPhmSMEPnSo}UK~2RUMY>ACT6 zJmvxqH>ozv!);%Cn1`Eev!sp%_|J$fQ5gD;#{a>KaN#QP;ex z1e=izTzd~t(Y?WhpVKE?J9bHQjYQ)z165zddK!bViii6=zXJ6&w7P5@bVjkvH+t9k*IghN=J(I&SNLs zgOoNm(iSdD0841wc;?@ezze)R2q8}bf$W6Fq%(Eh6!ASA-nyp3!i-~KlcuO(yUHC% zu7o0c$KL>}RN|G|hGJbIO-G9dn7GufO%@nTPN*cJncawlO@ zL4~#ZtHE!6ujnw;oL$v8(?7D>BhfCt?*$1sRjr&!pVT zXu48>ii5{dS2aT?NiDn-VmUK8j#sm9cVFd~rdgY6yt0+%^3Z+2W@F`|t7#B@bmhV# zJ{o;jm{gJidHGn3Ibcq@A5f9trF)QP-tZ>7JR|;qQnSyj;+w#SeDa^l7X2A1zGDUpN^y{@x zq_F&{PoxaS?}qWhNp`S6jVDrqEXtF+VU6QAK6>|n>#=w6+-)36!D{g0p%h&FnoC|N zdZgUbJc42=`%Ixx$dw!;sf#& zz01l~Dnu$<%JJ-q{2)6a`ov%I_U@}zr?|u(&lb{GVy%%z; z1;D5gqfX`HqH-#dw{X$98&9iIQTMp0n?F!@GB@a|WWmG4LQ>aTw3TnXPS`Ow7+*+w z4{INXUhNTv30LH|ZOR{H-F?mSWPN|gdOEeNdom&zS-}7j*S(YLJt5aga&hmFrNu^$ zlh!S88g1lb%}*_S@mkK%<`Hl6IOh@TE;L{|oGvch%Rw``a73h&?_5Y;MZJ`(5Ju`v zcMT?r?u|sm1y9O$8mDTC@$Xfo&_Lfj{|$2-CE1#v#2_^&F)ZXCH$%G-j$T$SYl|woN*L}5($hcb2$LX09>=2{MP9^dI!`V+b9}v%x8x(>`TmB zL5OikWZDOzb#+%TmnaSh4x(;X*_z*J5x7_v=yH{<`7OjCm)$$&*`V{LMZ1`|n_-$L z+R$kG3T8Q(!~q)9WQV*8)u`P^jR@)%>%nr5-ahlpn|&(nm@C!+(2;k)`>D5`Ztp0j zG;C8oZ0#FS;m3;&G`9Xm2F!+Q;+2GnWd7lhr1>l3GTtp9__yMb8H|*9r~P| z>9fPdA-+>@6c_)W%O^gHIlTAV!A&&mnhRRSFyctWV&`}RA%Kbb>_gZL6O?r$9MSUr zT!#~k!S3UcVHe1IdGtk0xrawUR_Z^|K;+GIS{o2)`FB+!d^sk5y-IXDqUHRG61V1u zGcUM1*I8KGCNLZUCUPo-gT3%&2q9`0?(CR^Kf~G~RFsRmu@QEi2lF5c9q}Wu z9%>Zr$d^%6gD5crd#DIWGUC0`H)P00d!u$X+c`5UDp718gJLh?;_qKx2KDusZx|9O#<{2ZZvv%!W)vE!K8`;h}71(JOG7XOazKsW2wz5S_`63 zkqt6^90m-k5SWls6`5pIOZ)1ca+$rt4B4O7(Ra^`Y9`m$?zhPmrhuW#cUn4wwCZf_ zF)MUxOaz?l;XWRS>Tn^AAS8DUq3wgN1>wingwXX(Py`FsEzy@)L>fCC18LA2mX4Mg zmxlt=G%t?U;>rn1lL=ULyi;QzZjMH>VE*g9<@M^gaB7|KK2?ZSKZV=I&RfK7?FaP3 zqSmh_ub~zWFbz1d_spkLOS-Mlwvv4#GViC;>vZh*tI2KU4_&vYyo=p`%{Zr99h)CM zgozLyHtmZah_uu4FD&T%SalAQbV&msFv&d_^2H!zL1ACi&BflQ%`|5@EtsL$kR<1#uEVhVDanlqECZePf zx2^J4wY9Ptto2RF=+&|YMhTrOWN+I>`#@4S7|~7N$sj$FjynXwC<90#Z7M(er_jE<1Q#0Wo&9{19`VklZ6iv98zc+Myujp+#8-JG%s2(IJog zAv!u{$zk)}rz?FKUd8!htC$K0olBDzuN^pisoSQ23LM}`p^3{jbM3f}0GBgnM{w9m zjCN=NkrIzrkzi5Fh1jcKmPjY!c&}9>Ou)P8EoH{JIf5XouPK-Q<^Innx5oF|9$m16 zdsrV^hNS~qNh<5>7nVNr;cuin78lXSvhBU&@+1)3#lAn4r%9TCg5C+Gnu#AlHro4R z$piJK!aV~P4fzrWkf7n-=-H;h^D%2QcimsX_m?%jzUz9OO5$HQuOH$8(b}Bt)Q5Od zC>S-1 zh^MnwjECwlPiz;c7>1Wuhk1N552+^GnPlYQ(1ek-wCRNYLaj=%K3*fL6hd@17*{(c zq$WxM^807Z(aRX8=9G1KJ;?8$B(M3bKl6!lH;*lv|rmyMHi}R>#** z49S4v-!@`=-i#Q}!EKHnh)_pS^jhZ>G5!XS2lKc-j4@+rJ4b2x*?0Wr*Y3Ktd_q5R zHX12^+9LOiG451;?PQC*qh_H^wU5e>6oc`34Iy>G#}ToG&4_VW-(Xx(8lI6$?Goae2I)gy-ykJY0mkJXdav3fF( z)sw|tKrsfyzF-1H?vmY7E$B54IFpNP(HXOCbq z%s-_dqB*a5sf=mPrX~z)&ZZQYBC6#%9QuTG0aH??HA^KOL5x#!xUH4Vtk9Z6wPJrP z+Z4g%{JfaIuYI?lbKI7XciU24wOnchBHW)fm3EoMR|dSEUo5|4x0}RRHZqb*iLI>Y z4V%+x)-VcP0w=txNO{l>xX$GuknIg3c&`>V#thKoIXGf$BVIrCatK4^B)~)LxSL79 zY`2qCY&;$~`wyFSG`(%8lDKSI8r)o7`5HTgg=5>J3s(;L+PDZe7&09$rqGNu^ zq$X+u2|<1v?W0cL!cRwa!bonlqA(WalE&e<;5H4ZruGs5HLn}*?4`+R)>UQ$vwaYA z9O-B)DIm~NS)Za!(bJ(+#MlI>l^zZ#_Wd}xqN{_kU^HW=`c5z|l#x!PaAQ3?@lSyl z%fH;l4F=%;O3DNRnh+}~deQL6#>tq(BagSBU$-Ym&{4?m8yI#)hQigT3N|gM9ylBC z^k%AZq46wqyLO?8I|qYtD)2oB)ClRXbbyUN$Y~ExJZInG`A)Wr#Q_04cYX%CyFoPY>A8)fSl5b{ zf>Q@ouO5h2aA%_MY1}(h?6_f>2hG(mLjtxm`HrU(3N|jfJ#DLs5R>Q1Tl?c$`Q+O{ zAqxt`BHg3W+9PHJ;Y31|9vHR}LxYZVCyUuY^epgcE>)g~or^VMiqVo5EI1{%tuY11 z9BM}nLk=xW(}F0LFI&ItY{4{f?4?_swa~3SE;`TLB_x_r5V)N6`y(YK&WRgZGV| zpLEY8eTqFZp<5k*(~Z6kNIhn{y*Cg!0GXIXh2cqrsCAsJ;W5}}i@^r5H$A@_;D!&k znha+Co4~C&3GJON)L5sVy1ZshBc>eeJDEZFGL2=*>0a2 zj&fxNpW%qifjt(QSdslQLLu(Crh3{lb4Hx9gqwss6A>i?)}Tk*5dokxU;OyRhD-8Z z98}ZFa;Cl1l|mSaivsnzcYJb5R{ZyvX|N%OO;|P|zVrDP!(7`aF)S6^#4sL!4X0No z0b*ElL4ijDBC9M)H#sB29Sqy$txe{iST&b#qIl4rS!D2{nJnqcM3$}Y4jvw0a@OglYzSHut)f^`LH$hD`i)#fMcxVO*St-!G{DgRozEtdH9GcJof201uJ7ACt9TgZaV8$_vuF(Q3XbPjJV38=-G9ontlsk0)My31YbR)mYyo0gNbv}f z6G?u9f?Kn? zN*Se5{_WsXm~uH*o1!g;6`b5&Rg5|uD6$R*D=~RrWj>?SipDWdZV&^bktP=3Hv&Rxf6OsbZ*&KZH&kSqt11A7ir962MAGJh^6*nl=Z{v2`}nPtIPupc!COC_zF;~GrmwR!Yn~uNPVh=2nI#<`I0YAm zH}5XOm^CF!2@bE)eE7eeG19)dun5@J2kt}KVh#9 zz=h8H0`JiBGUO3sx{-!P&MGl0|Jvq$72?A_uuOqgqjOrr&Tx>Wjyy*7kqV+^$+O}f z$VLOUA%5`2!}hL-8h9BKzOCK+MDT-=R}2|AZX$P*>`>bKxW!sAj%(xORhyR)J@<4- z(wlTgqbeQL$|cO@BV;G)tgj|R5mEw+KJ!QQTuL-e>g0+;=`nv~0bCyU#|a*v^vD07y|)3f>#FWO?^l0! zOINZi$(C)Mdl50G+;vq6cEG^K}=|fLzG}ZAqJGeB=h^PwfEWk+`f`pvLws4 zFzR#8y60oBCyk~LLIINdnVR4w6jhw3_htQY)tPo7EH+0K4F;yhqrp$vgWN((!@@x8i zhR)D&iDv7l=Ic0H-#N4Qn+u;K^UxdajQ1X7M4-1=?@adUoheXj@NW(0ZT_w1-zu)P z$c{`@&;TVDiV7w#t}-g{L1L-Qifitnej3=2%ag?vUdfyTK>fQraA>T%ab!a?>V#_Zln}Edyfl1 zxPN0sx8C5)pjKYzENn8nO>{+Owv{&45DLsQZv8w+d= z1)R0BB)6%!c(-t6)eLorPN^fBwQOIrsCk0fd7cJ%Kg8!urc77_&ykA4<^52(->?!q zLu<(@ZkHy=CM=>XV_EGCr>;*k zO!kz(?4v3u_B*pSs^HjxStlVl01=|H6$lp)1Z_InU$oxC!jK7;ccPdyZF0YkOq#q~ zM?B&KI+7l_M@Nza_v$!)b>pCpY#wq*M~X4-*OBD}4(rHL*AM7O%jM7o;Z! zhC(N|Kf5g^1w2z0dvWow6{D7kO!P-9I(u*JbM|H`&fXks(C_Tc8kcpKJA3*eID2}I z?#-ONIT|x-9MaQ$$=TDbD|7aEP7R(5&fa`-_7t+X3#3;kE)d)VMW4)=NN}V#IeP*i zA<5ZWbO211>1_c`=nwY+?Hfo_rLWPomhfVh3#TM0wl){4&fdd3(ZImg=v~tz93QE| z?9EiY=l5AlZ_8i{=Gxt!AbhLw5FeFmceguc@*fWPsa(5z{B)dC#1tXvNZ$uHFmrF@ z+6AL(uHBK~+PyQlc5}hCyCb-E^TD;l^`o=R^~+s59L7W=IhA%b>b!f$30%9Qa7n*w zC(aq@+Bx@`Yp3V>UAv>O;v51iM&z&VuDW)KPTl}V@6OD%(`%D!r>o?9>1vs4cL?BU z>4oVk-eP*Ie7xVS6LRU*hHCki#pKrQ&0jB{?I`Wj@lZIby}I6;`Eodwr|!>5k}}2Z zjdfbmq}aJV!3Rm6-~%Mplp_o)v~!L8xxb=cfC%p^#&UWr$s_E<8)#y z7Xb%nZ7ONY-Raf#5<|t*YssCu+gb!TYtY^Z9^|Hp^1=^KXK&R_lSmj(i+~wUf?In9 z&yW(_kPDLWFJvZc}~JH}md%8u%8dW*j}a#g2HzsaF1r%#mb7bi!{ zT0|}$?03p=@InUePo`{prtws#ezckA;N)5MyJdTftGdhGGW`(TvfzgxkY#QskueCL6+&lErOU3Be+Gk2e)W%aEorUOxM;1Q`S-TcK~H5{aG#VVX)IP{f>_!v)Rzq+@gD{j!$YG{YaAnYSHo8$rRr3>g4&GW7Z$9i3ukq znv`%-;%RM6Hi@4y#p(FyE5LI#$wvqBp9mtUuJUW-x+Re=^?J@08M9<8lrdIfx5&8O z`MkSi24{}xMr4-AJkCt&F23K-=}tg?7|iN>f-fLaSkoj@nT-VOOFpEUlkEIc?NYPU5hxL^{ zFbjrdGRuZVixzKIzhm)k*Aa`iS4S-JZ8~0b4gA3oOF5&XG$6>!>M4H84c6gcunv_5 z>j-zrU@hrx$jV=gT-9LdHyq`P!E)0Ccqunn_xBqtj9)NVZ<(?oqq3y_LKZ>#Or150 zxgrgaLXt&`pk3$=qL&U0Fk84PC1Y7P+m*~#h{a{LU_+TAMf3OismvBOE}E^Na}?MI zO(e4w^plyb{lRR-Xr1WY25Mq7j}5Sa8qAv3UV|Y{FGgQxrshl{!Ny(P>d?zd<8xYL z@p&*)$B)n9{9s}1dxK2WQJE-cVjiz{9#1C9J;uyL2V74szP7flpyW2TD& zK73d3OwWogrt1XH^s?Zl#|2M%JaSqdKdUtv3uKIuu}j88iM9HfbsANr5jt}Uj3FX} zIKzl&e5{|FopAgxn4Qm2m@3k|G-MVWPfSxTbS0XDOw+jy^@M8~tD*4~pDDGjm`&v6 zuOuhO9?6a-3MV9*C@9Xo-m+4YV4^H2!bB~i^vj@$U`pmhCdy10Cdy1#47v!)=Jk6P zl+EcH6J;h0q|d_`>R4Z5`$83iOcL&m^baR_s>>5K0FR^`w%uteh{2!8Lk2YcbL@nr z4cCg3`$`-3B%_8#bMJC*73LbR3bU`_eU&II)P(-L*}1ZiVWxRD3K<@`P{<&jnK4@v zO{lI?N?KR_236y3Fj;&+SMe4blZ%gI7v;$4_u}-*8ctfvpfZ2qF&~akqFRQPF>jzg z-H=JN0hh_X_ak@aTEe>;V6IONnLm(;Xc}G5C3&8X?-O}aNLg`%vJIKqkWx|MlsZ-C z5_)y4#cih4jwC%Hl)}}yDrYEZ;YzmDSS8_H&sN~pe!(**PxqVJ6WrF^FZEnj=5VbO zqOYD|I*fNGilb|jqiA6JCgALo>I#dYO*5Am3T%W0oFeE%?`1C2c~H;by-+p*W`z~J z3rZj+EdVnbAOHbarTL&D2Tf`_L6HMY%d4DvR45RobqLFfW2Thtwr5|wJvEGc1Cqr{vRdy!Nvyh;Gc|<_|_H(uqksk)L_G6i#$OW)ObD6az zHSpLbC=SZ}kXNWADj>6yyrM>sb`8rao=~D9>{Pw(gS(hgiO zS7F>FS_~UKu{iap1*{P+kD<(`$2>Y@4Lq6~S(&FW)caWF(J@mt6iirWL%|?_9_H0A z4E3I}xyr|D%!h;j2Fq|3O+9wz>d9cHE)4Y&dBb8UqQXxx6SZQ~lymiYY?=n5d7ed5 z%S}^`^?6{LFiB>b&QFu{qe-hi8oMxI9UrI?L1~Wc4U+P5ELNt62TiiBBBol++FX3de!5`6i{rRG^zE025@c9W!DOz@S7y?JYFbct;+*G75-&juod zqYVrRo{dEaZi7*Rr{M@OmAEUPfvuKg-JdZ<#wr;DCANwTYHJ2qmNzm%WC~{z5sHuW zbFdSO9|p7VIU4^HNy7MCz>`t4T+m812brI9JNH+(_K$0ctbrGEtdZgv8Ih`u6-H2+ zd%Z=Gx0DHdKnXY!c!zb2b7e{79nv)kJWK462ej!Lajq@q<$!)CDQF2j5_wiMOCs-1 z!9n&soI1PL$C)me9SsqmMYAIV6SRgbP|zjtMKn7yMnUh$0tK^^O=yie+ssd9c5J*U zYM7{T&bryDY-4dkv!gbq*4R2DQ>STmTA3*^v!jy2Q#3na@sBah$6!&n4$Jef2#Cg( zeBlo>JsM9^kDWWSBmW}n{$O@84@G3m7$}$>kX(`3(Qwrh+UykURAWxvh%KkXlHRp0 ziwtN@otoCG9Vw<*zfa=iE&wO)6hysmaPuA9iKxKM*AP7OHJmrXds1D=DHnyRvp_q2?Fd&1!OAEhA5UHO{pxI4p(!j-X@x*&jjWJGolfy{WRT8)6|%?| zS0pZ&X52vV6QV>Kb;`j{p`BxAW^Q;LWH}ehI!TQ`nm8!Kmn~fe*`_tc#O{5WeOj}V z{ie=48>MI|3@HtamR4$`GTT&%nuwyzM#VA+q9==*h@MsuH9b}~>O!&(%G<(eXE$m( zm1JEt&WOpn^DAmPt<@Q$tv%hSso5VjDb_f}sL7Lc&1@#SC+lRd9>Zi^7B#8+&vdfx z2_H4#1)Zyf`c5w{lKBY*cLUAO$&z&>n_285twGV0NIS(rb@dI_`AM4(4WH zX6}O72^$4@()0O3R(KF{0CscFgRAaiZmBr*&bBXzAQeO@6c~ zxrxVpw9}t#!`z&3K ztELWXzVsfnvH|VUW-HpL`nswrVr^5OTFEl{!2)SWJOn=S>`zjY9Y>(!h_sdEQXCgn zf;_#AxSjwt*UgPHsMEYYUv<;qLU(RrMeXhUhb!%MWwme8Oj)W>O; zYExujqdycGSgAH8+E#SHS_@gx0gK!7>7yWUe(Z8|k7fup(w3Ih<@EP3*Wz@R)7NuU zFJ{Z>YiZ_z%jxUZQ(8`cPgqWW?>Syh-)2!CK#- zpUT$U?Wgi__xq{L&Yga01x==hGTnC^yvYy)#=q zUlv-gKK0e}MPz+3nj~YF2^_&)C>=z@;fd#QLH0lQybWJI>t;Rz+wpj*39J36RzL{m92Ei-?mg5fHPl#iy z@nAV-b&ch?T}PHb*sJ3@U-@1`gSquM9A*g~I`^yFU$7ox1!wH)L?4OzOT^=0GnRqY zBSarkVIlgUn`J#%Ede0fh)J=fFn&6C zEavnxVZDbu4#7g%WEXShvq?G^l46w@gpT$6!jmc~mU!e$CB=>y*Yz{^g`^n#rTk|# ziaBHJ7L@wrWTnu@Tesk3$uQK_Lkekdkk7;Q3vA)h#;eOsyQ)bs$@S?Z#aticNwLTM z9+O*}2O0`gun5^Y+4sVj`DSr(Wj9>S7>mQc9_IMyO^9<82!%LDgTl+>9OceJoMRPO zZjzKR3mKJ|Vlr!#WyvfJPv*n2Wn@AuO^33C)z8tD31Y*@hLcO_vFI4rsk>Mv`pLNyzLZuc(oE(q3WO z&K#$h7`e|-p1}xlTqW~{xw6a~892+lk;|)O-bm}xl z+-<>Joril&-npu}$K-|L0xPNtX*oFXggbIsmd;m!W9#Y6j2*#@-Ftqm2KS^3vamO@ z?!I_&7D{PxHRbwjTgQ1bY;@Ji)`)vT)+3~N%URggi#t&z zCssdHoVl2FI7fk5U zFKO9sZLp-_rUyByi}))c$eSm-7}i+8(~hH7^cwei({pQSO9Gwh;&dkq^3KoTZqB#A zEQ7o1CP?ao{@{-4Tn03|jov@~{-Hyv76X|PRH5a;GPH#L zVY5r($x3{g?e!Z=0Fg)Ac^S#~2%E0rW|yH(eaJ`O zM*ILd4cGiCKH$Hlm(3Z*@lIW(Z83F~p3_x&Zg2ja9#<1}Tnxv#aLjk6rZ9&!Vr?SU zgbG6@d-cv#2y9glqTp7wi3)aYR}Ilr@>E7K7EJ@lsvMjg;l@nxoM-`FT_jeUxLB8D z+=aQ5z!*rroUR7!FKE*Ux_>@shNjVncZAwqn9Zgi{ zW-0(369dBW0qB?*5ZMSo?>PbG!5x(+M;gKke{iVglx83eVQC4{5c9gGFv!vsq&2L7 zC@UH+VdkVb4>wYI?__hBn$+WXXzGGf z^w0w3VWF%d70NVcMg4yNOdsg;&zil)u5OFfTbs|@)E#Pn>UQ_!%$8EpSnm$Y?$0Ox zEDY)lK0yexjnB;JBhPFBZEhi`8o25 zvf{zu6O986W=QT)@C)P<1v_O4YFq^Kh3*WMsB9-_$%*I_k-#>e2%jlTi}208hTETD z#l0H!efU3(o~@(IY>m-8gtXa zQuXCtlsjvpbZ>83qfuXpzDT}CC! zQzs5ToY;VuO>+5&3d=g(#K`5T0yl#!crq1|8u9@~0mlccmy1n_&N8!C+PaaV_Ny%T z>r}UI3%T@-&>P&~{Zry}z$}KhBmxWA!IjQdu!32ofPxVct$2$VDo0T^C`Z2N%no4%%`QR3ikT=i;B@0i zC_Y^(i%*XsXFF-yQOO&e%HN~SUG2kfkj`urK()-3{vK<#=M_nZNT~T7ky$?m9ifW{ z4caIny_wdoEn2j*HgT&5@)ve9h8a`&Q17rwfYZLWy$r_D5W274dvHLw{ZJKV%H-iH z%pA|mMOVUrx8;F4o3aDR9e%#KU9c=NaD!G!3cMH@Ab5YkgZF6XrW=Pn8NXuFHpG`Q z-4!&N3|^+^&Yo!-8ED#$BF=+NTX$qx5HH!srfI84J*V7K?y|^jJ+66EJCm^!pxekcQcp_?ApReCi}cQApyL+SKzI^CPSxXk72ktMi6 zN3~SP+LM~vRHjsmq^o3Y8(;qLk}7~RMiKZp@%gl<&E3;UAM5UI z0lcjWw*KSp)UBfHOH)SR#U+KCAv{k6KE5YYuF5IKH$=tqiKCMz7mG3anfAr9X{3*#FZP2z zU+h8&f|VeYzSz7;L@7{$n_f9`!qNmBqcpDjP%KSw(VDjbickY%j@MioX9&*OYz9G{ zn8@#~!c4jEslp7inJUbb<1t*qFfG!=#~rqqL%@pV?pLsFjFyE20mnk>hWbr;j8LOIOPrv?GR+`C8-=)Cq!+IYEKdihh?(4M;E4 zRdU%-nf4m>O*)khw^!jXaXK3B(XFuz;|S_h*Yn|6UH;(|hFTOeN>(zX;f)UP%=kEI z0z9+Af*YsnJ;}I@T0^99q#*D25Hl+wS<0^rTt4xnZEoeP8z_-)g+tfMSy{*)l zsb2wam+~_NMdPe!1>Y`G9^bA?_(8tixm|n1q|#3P7$N9G?M)Tz=0#4S3N z!Gj5Piuq9Nty3HyX=I(M_?&1+r{?}pjAB`L+(B4|1Z<;Yb?cP<*)k7Hjn2h_KhWr` zcjxCO@h(SXth@MSOq$ygxGPByU9y+#`!lI##C%o z4}QCtf9ruyYFx$p-lW~Ckc_jWqHW|SQ9AF6tb?*{%Q`c4abljxOwK%!nY?4vK}(^d zV#j$$iU{Dir^027F6L&QtH@uAbziK*pTex}NQx|L!>$U;oGS5-{9xC(hbDlW*ekyb@%O8Sm+ z8q~cjZ^yJ$dBn=M1s%CZN5(OB>xd4X(GeZ|2+Uugdo{ML@o||EEtGLYM;6LZWn^(N zOFHSe9$l*=qAX6`%R9`DWaAhNT7j7@Ps5#Zc%{`fjv;Ly7<+#As`PO=-%S0DKUE#_#_y`^f4c|2Qi?+SZMNAJ z@0`sdv&lIqUiZHaR74<^(=Ap4J;-QmBSjlBuUR5o(NGxqR4>wh(xXxWclzl$n?-hX zfTo=VHeiHXVDne?44Sqw!fh!lI5`NJ?yaiYd2g77(u~X=XBL@W9V5wnSo^4kwPlF( z;!GFogN99}j`x)6cpP<{CX2-la2vd;GEq#bISy@$0g`tW5{up}5GyqS5-XOmGPw%R zWE1}KzRY?!>-Pgr6LCZ05z=}Uu3O<0uzt35vhe1?d>N;JIl;Nj#UwT`4D$qdB8XHK z-jB7LuHg4R-CllnkZ#{&x_!)b`?_4Wk0sqcj}k_cOCO7}7796*C34wkG8HGw!!9ZK_4Cv`{c?Wu3YKdEtJ0vQsYRQV~z4RNBiu~-7_sS<%8PJj3>;QF3O@Ae;Mm0i*{CWru{ilA((Qax=J}w zG@qF~Y?;i*F@CJ1m4ZFAEJZY^p0j`v!ktovqy8FClg6~EnynYihvSndZMrhf6}_Q) zCZ#e(Kypd;4pZl30`GkaFlh!QJ(KQG(lggC^Tq@KF;$3VN*ykfaNXIj3ZlkPkLq0F zu3j}mXg428IznF#SLZ5cDsmVa+jT6JpupBXz{%?}88jsZI8)oY+cYcSEU_l=v^oXw zboJfa0(e_VQV}Ohc5V-)?eo0DzPM4x<@5)f;itQ;HGs3$xSWB=GM^|UQuT3)?apz= z6fOfNQ7OX}Mhw8LU5bnS&W!4CbpU2GhyMX03uRX#BS4UsNIW%mQ1VrtfReArNxFJK z?i4Oxj)CI=0W)k7lmJXUrjm9G-OqBm)IxYf3Ix2@BdTikd6+JJZJ(Q0opg8r!uGp) zv&VDu^h0p-^c*~uxp@cZT(2*+VvgkI>DHCGdA#3}8o|w5NN(PlpLDoQ_|u1nGR+Ol zRMO!p%(O$Uu({8aQBvuoY0RlhDj!8_kYnjx#vu51FAe!1PPYlR(5OsGB%_y4Ks1bQ zPcWV!C3Q9?8_oom?rcmpyypZiokF~RmrhJG(4}+6J7JyT0keLlyL5Ner3(Q$uCLFQ z^h9-8h7U&wor)Khd1(4A`dXn*vEQZBCzDHO2t)_0$AEV9+K!}CuS$wP=qi397O#ch zbWmKbqZ+B>TsT%s6;E-Rp#nD-?x@U+3dVYZXR22eFo6&}vlULY@SbEYBF|eoA>>7} zWXL!VETpg_geaNoU7ZjcWo4RVtcM>b=2Z;}@`X$W)dfIuIrT0An2WRbBETf~a^en` z(kv$~*B#z%05ehTdCvmOWLgwiMD*2xQI^$-sf_M$#a|;Tvraiz6AaaI(~PDeOMVd8 z_`#H91#Ij9IOB$rrlu+@cbmTkIP=$Z_cnD4;BBQ}Awp$^hufTFMpHwi>X?=zUVd{5>s2tt<1vc)v{J zLh!*BlMklUnYleeA?G{brUC@dnDpeSHpJaDjUL=yGO4tH3HXsx*_vjsZ{&)b`wX94 zy}KJmj1oB_xM9R7C4}d;8|$QSTY}M-fiu^vF9Sy~QohC14_rnplE*!>XC>Rll5l4& z+jj2>T(cQ^rr$LaFAa3foF7k^ZCj9`qr3U5yQ{9*qB{cSnk|%*Hy=fXV!vyqPbSyQ z5E$f-;mVl9wX($9NmFfVv)(r!j!&Xg+sfG1SfO7cL$)oKTX*Ji+4e4knQ|52y$mqv z3b}4co5*$RQ#td-(}E{ywxomUr%ddnC{&@SPSv@@T^)PAWZTsE0p6Ry1H8AARH(#E za|>*m)ii9W@dO^=y$QVBdrO^a>NZ!ASrQJX&Q(Ih&$Md1IrTu*shj0)YvdrOPQ9U? zIrrH%=P7tW6j_#V6EKgXN+p;P-W@jGnb}tuo_A(moRZQ&P*Y{s>@|oUO!bN)!k{di zoP-l(;b3-NE`i9JfLH`zR$_^>cRN<;Y}Y5w%9lH02zbZGR-63M7#k^NTr+p}js=5x zv>aF6LsY4vni)lxZi1N5Tb&%N-=-UTTKTx@?pBx_Jku(t0#7#{?jKj(TTTw%)936} z6K?wl9>(Tn`$0zTCjy`9xe;y z`IX%A*~q!=Sy3LtYW#`MPHlm&yHDWQp*)s3cH*0Xj-B(~33G1y%?6rI)7@3a?yTqB z^vUGd83LtacQ_^5meMKe)OgLbK&?TOSr9!QG23&zq~0Y z0iAQHq*H+8lIxuYFc)wE`!s=Exuh%P%FR|4igzdQs{C5cO??<;S^apvE$ zLzgc+W)PUZgt!Z*w^eC6C>JNQeu7+FO1rsx7SnEff+u!1({37GeLSVzK5)X-$q&#S z{hk)E-plHpK-@Whm znPhY+5Rc!Eo12 zLv|%J1T&s5&0V&`WP3Umo0TmYWU;*|k3m93t?5r-sAr(77(Qjl#JPcr{tWz4HGSC}IcUQPe^)MPH> z-ih3qw1F}gNns2s0`HepGhNF>T3xwJ_T9+wg-l6Eg=nlwovL#Qy*l=M8LJYF%%7H) z^k~-Rgb8j96g-Q`OPUIvh2?@9=>*RrbHOdJ5q!F$|FR*d9Zn#lwY>$^T9h}ZE&!Z; zv+M*@#HCs;y8&?4qVvn|?3O zj2n)?35KD3M9b+}ei3WO%boTm5OWuRdHqu(g-AzXk<%$e(sTW(8f9G< z%nq6Y6ZchJyt6)DrB5c`%n)!Fk8V72ypgFn9*S8Y&%LKt?6qbF*H4F|v`au>>v{4gNBDoOjPSZA-w987WQe1t= zxk~j1UBCd@N}tHMUiYAiYa`e zjZxHIy|MD@xrhkh%$E_^&<33OJuX7LZBPzOWY@>f{iqe}1WqDHhAZYL0JCW!@ z^13%CU`AYQ5Rb$3v2)b4L1R%W6*|FK6uioNoSu4>)rF^GamTH%Sln@oqgKbXF2GqX z7T0<`kEc9}+3Htv&=<`e%bcdLa&4}a(GaGaGNp`gxk}I1DmMkgJNq^+FfEf7 zESCmhb*Qu9mYsMS)ajKE`K~$V&(;EGZpxkw*TYP~U((=x=~?w><0K5p&(c+z8@QNU zwL|IjxW3q77~o0li!H4vbO@b+Fy%3pddQ@yBK+pH%-eCZ95%xX>m}FRf zT#{ZT=c;mRj+ia242al9*2j;16l zcTcMq04K-IoP=!wyshGQWd7WBzKWleb*L0d6kg_)Jyx!m6T57$yJD_EB2Wz&)9t*(2aTflWj+<$T|$!U<$j&rmUbyfUY59;FL~dVkEfjv+^aNy>@53X zwqx{Ra~WMl=H%K7Y0k4rdq0|Nj<7J|*v(I|O`m$z5z%>srQZ*mKVDi)KZLZHo`dF@ zAEuPyz!6d1x-vhE_bV+nAN;WW$qzf@BckH%{^}vq4hTYJ-8BqX^JBd> z`5d!@%YyQi6lYWxWXnr}aCIfcS>wLo_vnxp0BP^xusiV>i^g<@c#U4Qs^>csYlq@i zTt(4YI`*u!-E4>8Sx_qEjXea<;!WjT;H77tClo{mbt2 z-l3`9Ulq7@tKeC;>VESe1W$<|~8#Oz=vq+(=tFcCT(Xm&6+W_B<$W_IGJKjy~F z4%W+RK`~twvxB)Yvy)X7nAsudyI^)|Pxff%+?gHIJeZxc8|^$H&5lftOwZ%j?8Iot znBaohAxg={KhH+AbKaR9%*};p$9IjXZ@pl4@NzO|HFIGz$2N0!Q+%+}XeTAi%aX^x*)b-->=;vAh<1FhlP9#{<*l5K@! zJD82i*iKBcJu%024%C}u=sWQ|nE&-}4&n zAKS1+d)gm+tzR%i(wJ^+@78r^t^I>r4NRRfo>xt)KQQuFG*v{RNBKa}{>0mL50}%8 zZC%960gW93JY7rOmCM{UR1q0=ihM(>J`}M&RKc22$FKg61yCF>QDlJfAOAsEuZ*V2&YRGl1-My%ThDB-Bp7(!^@qq8n+`qd{GXBgs5;HCF7s;Cdb zfV>b}^^)iD3i}R&8AW@ylYhGLY)A{KcCf21hif}S6Gf{SVpm%BpRA2uQ)9zhjd(X0 zzS4jMxAQ6vK2`iA;&b zu&@~3#m;H<_8qdza{oVJVL^ynl^K*_nsxb+b67yzeJv)KpQ4}w%|*yoiKI{ zVTJ-#bX^R&O9hT>X5GGTuX=D;uNt0iO!jL3NqxC3^eiLW1kP;UzzItjxK^;$Y>(doJi)Wj(*(Tpv1M|Ku__8|lY481**}v{&gqa!kdgZ zPKzBv7g~c&U}~EW})(jUzWj{s!q#Z5Q66s+noyhRv&WH`jp7_S}rIz^Ed3@sI z>lzzxZoE2FgzabF@nQc3p*MMltjxcPt09R*c8uh5V)#N_lw$k8l@ zoD9xHc0>L^(cA@RvIOmo&!~NkUKzH@ zIvi-5p(x#AQPe>=_9dP{fV)&{WDA%7WYD_mCs{4D7 z)Y(Lx>j&91T*oCwAas17&X6%j_VQk@t1t>YBKbU`qYX;}Q4QA+l#yoOlA7^#8ux)h5CiuMbq zMvF-SE)`&t7;&svUu+P&bvN`@-&kxA*Y#SjD0t+?O=yr!`ES5^^2SZSjB2}t=G5^9 z(5NVKVT3qDoVu4eRvU^9#bwXm)CHj$$k?|7GJJd7u?xt6os`(|ky(E{Wa>FG6U8MR z^iQ+6?76UOpx6d_iVDtV=Q17dXm&2waZV|;VXbFm0?Y2=Ca~--&Y})d1=G87E)d(^ zrUy1$-Poh!M$LHdYxpJJ@U_L-;u0FZZeYVF`WrrZx(#2KdSRkiN5hk7KmwSeCPaQ2 zt9|)YL#R$d8`JVF*a*5!q7%dnrj=IFW-6mW#xxLC4wk@_y+ZwZClCGFs0S&k((4e`T2HKgK#&4wYqB4!&kVvv2kz_+3Nj4T629g9GlW~V6ItzVf zq~YTthK!sM17crh1fPW9e0oBZR+qyNLctMRXDF-{V(S75Yo9Zm!E7V1ZM$3CSAajNE&l(y>XB@iY%QLn1LHAq>v`HUi!!pRGWlyc-9$2&Q z&4VDTc2O!eSzNY@;@pd;YP7mo+bhft1Vax4m=_`KY7PXfF7MdD%PgXU2iQYi3svjZ z-D^|Fu1y__=h!S{xQwb*>(G=uxpl}4>DsGnSMm&pX%3TD*S2t*8H>X{EukhOi(MV= zEoA^R7e`9KGW)uY4WCi%Xt{O0)e4O|S8%q$&Ng$l*?w&o>z>9>Yl?N#wI+6Ov{<*b zHX>6#ift;|!gf@I+UziR@(K&PiuG5+nRq(SsG%*3HP5V%78fZ(SREY4`a~HVmL8<~ zZhwVy1er6){ehPRS*Sov)9^7~UyHBj)0*QEoX7WFIkf8L=Bt}Hkj*ld#)Yg07qTYl zM_q}Lx3JB&WQSO@x984k z5SoW-DD%myYFoNfy@pKXdTRiq6`cAsd{L2J9^|)W308cP&7?mWIiZ zL-8#yD%SW=jPAmvL}B{~@oJmrJh`>@RD1DN#(#S8|72%tIQx%wb}?u7)$DXVr+-=7 zCC1!;3ck6(lzl7pH5`+ZfT)@1S={h8~NA z^k$oStXLb=g9G6Diz)z^e_aHq7*R_I%o6AqQ_rX!taGI3ZBf>S-(D&y8RJ{UC3?gz zc;UwKg3oOzFQ^=kj`CRV=T)gKM1Ou4A*Q0@+H~Uu_{tov!}lBOOg0pHJXKLBkrQAdbTz_Ug&H#T{Gr_6MJK88zc}Y|GtBLAs@wwORF|pHY7VG63*#_RD zba)JtHY$ZWWZsPPt~qqhhKcVaRFlr3V~9jx%^M>dqm2{4c1OjQqc`#Z_eusP6kwFl ziDLAnh|Z+gwkJ9^Uva&0ZST5W-7(3CHD2`P!jaY8CKN>F;A@*pG<*L}Vxu>-t6aZT z1{CQa`n|eQpboCg6ob4HsR-DMJcMLr!p_?Q}HZ&eU?6gToa#jR{WCUKz2wr2(SuLVj% zB_c+X)T)bsLW3O28`c4Rs0u|-Yy|pnf(qGduW7Pph0gv9sRO!`7+;=5U5MRY*YO#( zm-*#ObA~7;R}IyO4O_K|UOhMjjpq<`5t6b9Do-jQG|S(RLlbz;a!sgF8{jO^mim&e z=n2%wjs&0^ypKx11TA6HYrNy4W+IAyS{{ZGCQk2ThCVsrzlEw4lf=EA?0t*%X}<8J!%7?0uuAGqMxwofp&sDQU=9jI`fx z+QF;>@CB?Dg5UmtpuT8#3%R4oJV4sdSO`1pEHv#bw8U@P?XP5$BL*<}LVtKCw6AF# zl(``8u+>RKbG;a=&R=X&`+XTEjrIq1)xJ}IYZL9e{HXgMV|E^uNpVUef05FI*m*2x zXUqAWfSq{(R>{~I4V~DTkQCc?J?ab9EbWa3xCzb<$)@ z?wqT4$IZx(>*}4#?28;UXB^eL+lC43Hd8cY?w}naV}$YN<-ntj=TL=+Sl>(Nnw7pJ zyaMk93tfmf>W)un5K&ox1)_tE0wS^Xmz#`AG{$yyno_0wf{YW2;nn#mDQSE;gSO?q zZ|F3*QEC*Q&m#ocN%;^c%o^B_^pu9fZqEE$^TyujD>@TO^T;%^KBK#jtGKu%8bn1i zYvP4}38N_kJ61xuAh48Qa5QRvaz3IlA6+yx*6duw$06LodUsvvIAS)|35ZL25j~~T zMXcPSxQ|qgX}626ZkTpMoA5&EvU)KZbQ#M-c!qNN?4r0vvOHkVVuOp!FE;AVvdPqx+W zm#(!CsZ1vLd%)e{$!e=yt2g2>u4>eq@XtiA5H^vaB%iAQ z@@03~hPdE!elcZ)3K!TCJHzLPpiDj+>2+Q>rJ4}g6zQ1qttc)@)u?PV+DjuPnBHPc zp=-mUS5|%WCZ3{&FMp;CulU`cyA<+B<13zlFvHLK59e@E)jhwG4HMliK0tH^_Jq67m;FEMf6QK zfjn==na4SS2Z;HuuFJA0l~fUGqyH^%OX`tKWAaNAlis{DtavDY4CbIHEORj2>!pv?(Pfm z6u!R)? znIM>d8=dDdUuQ(2nTEExFa9S$k0clE+~oPKRjn3LizQ8A&QaIpoV6ndasG5a7x!-O zPCkbrOvSKtf=(v`Lp3e<9sCMMQZasdn>kwH_PXHVi{^*Gis_r9`lc9b(!WX0J|Z_E zeo#tGI?Czsbc=@xz4QdZuTDgm_()Chxs-!K?1X9lmsV03LQiE!d`~otBqcm+KrV+!5u~qNIOXiz4F#jZ0JI>zCI<&cqH(YxaVhj==siN|T_?FRXJ8F2E2$~~gS zp&#j+;i)&TZ)~a-8H|Jsv08{yCMA-U85oeJ(#LBRfHSsA=X08s8W4C}1pyzn zk*<;Bl^W17;YKet$Q~&AN)1Mo_`-7nb;nOKnUxyA57XU?;O*EXDhjNfr7Pq=ShmG} zD19OS0jgc>Pn6CO39{pq8UT-_2GAyz8eAMKZBs)cmX57ye1zeUSa(oUVg-@6K}MAt zfcQ4XHaJ|_*7u5jCVjjxhs~ z?SI*gZnob#40v)+jZv0uq~4kuoz$=agOfs)K~IJybq1mBjK|GAfcu;twKl(EN5;#> zVr9n43;Jo)FBnah(pXbm)Y%BX7@doaV0$Wc6C41s9r5)q)e&DGti?O4vk`NCpl)K5ZlG@Bvb=7B&rvtgK2F^PLr$HN40XuBP}qpX zFRPmvk^dC0>3P&cysmbBU){vzqVr9~#n+>b+Shm2d)>t4h+eZ;pXw&4;@H(?TvcTf z>r^*EZ|v$`A;4y@o47QTBW%(j`KDMm!6Q~TVMA-(@EZf@Jn3~4>uJvNx`}{Ow{WaB zF`QaZK5#h}gD$mi2V|^n!mta-fSu|lyij8hGM5&|L58A$gv>;7xz|lFW}4Sc(0SBN z6zW9kCOSIKscvFKYn38u zH+sV_2c?ZPoSqoa@CnAMQ!mhP)lHmM!?RwPDAxDaO(@tAA{ut<462*hSV+N%85pX3 z;Z)G&Ak$wr!9Ag7U>(Y!dr7aaZlXv<0!30iMN&OhHv#zv76}xlMdo&^V$(t zJj-d2YDcVYqDq5MH=&}DP&ctDkz`XM$)-M%TvluvND>Xx;E_NQoh_@Ipm-}1qgU?~ z{A*4!U{=Js3Df~G(MF+wH`nljj(X>E`J)>H3J4{26PHswvoWAhY`m-6Roz5)cZY}( z-s!KK=!Uuplu2JL1KOkyvb>T)WA!Jiwpf0TM$xNJ4T7vy;;CKWhO~=I@Skb(das*s zgN+3mY~UTd%)C2zfN@`;nU&%4x`~Q)$m%9CuYdvs)lG0v-9)>rn;6mRoTYWZNf_y` zn;3~Jbl1c#ea^zh5Dqut1h1Rua^`gtPvOk#Ce{@jH9UQBu~Bssmom1oG1N_Hbi7!n z=vRa1#ZwffYe2o|>P(UaXQCHXH-X%#ZeoM#CN2uz^_j1m;PtimdU>X)ZsH@&#!xCb z&t@MO`&&Ao$+I=fHA)O*j~UOzm27d&4Ye+{wInubK{Z%eHCGaChECfWCPKPJ4iiku z##xk6k#4j1fAgGPGlVDSk_)|t$~2@`t0~K=Kr!LaFgLY*Bu-IKEIS>CVGFrix+5h# z8xWtKpkChKW$x49xTLE1;QliENr<|&wpC@rMgVFyiT!c}hzI4f)*t{r;0>V_Mhq2r zdQFBavL;W}7T zbuK#;Rkpfylw_0Wii=uTF+Ii^;?hT^gm}(62VzTx7Ff!66Zr>g25He+ zmoI>ap8e9ukS5t^?as7)0L%@CvNdf z>HXO_eXB?Q<4PFjZ$8CSS2w0P{gL824br!E{=sj5{yQIh&$s@Vr64x)3sacZarnt+ zzo;A9oPNXa9o58v?|p3c3xE2tPapJAZGPNFTb@NRP z4GOaEpt+?ptiv?jqot+wh*FF5U!v~q>V}@At#nWOP5vM+l8_r1rm~TKD-!})dW3ch z6QY3#O%eaQYn6RNDI@zM#3~>qh*+?pgtq3r|e2hop?qiZ-R&mGLd_J$C!X3 z`8wi9mrNruSCVSBY+o^i(%ty7z=gaSF4Qy^aUoaRxcBK5F0{H>y_^ps*sf4o+_JS< z=#7@Oa+auxDIfftF(o=7jBzP>+Qr^_ zs+p_rJo>{={L#Mezw=}NiX=@tsgsW5xToI! zv+%=q*<)0bI-VjB4n6~myLMZ~x)GB`wVlw9e?vR#zuIkVLTR)9YQaf!=T{bfxcWtR z{TBMVx$}d6{-zsV#l)ZHui>PpJ)?f<=$ zy>}#Kch?6${Fk%e`q9$sZg!*EQfgB#H*Kd*gBiE@RlyYoR(zGTUE8(YI@fj^qqgIb zOxx*6D3fbDR~dmv2WUGQ5~T8<#BQ!X-f-LJbt6>Bv)<=sm`m;)2hATERo@=K%<&!E=4A&=8gS&*~WEFu9vs1P%WRoit4LLQ9W|czV{yf{2zY)KV48% zyLMhsRDFKg$rRPMlcIXvr@r>(k01K--B!chr&Z4*MRj@@Kd}|n?@uiEsFX*jmmwjp zXzu~@r6zj&_9-UJe5z-=PqicXR7-t66}IQUVBSKY_hL>%pm!bSEf4gr_#U z*Bp!v*xxyeZRh59{rwmJ^6&rKS6)L+uN*L<4n>={E?NXR&FSyDLm~(4lV5n~-GBSe z*MH!{I3%*JL@n~b{^9`RkM6y^P42!&Kl{G^lYhAT5B~I@u8$7bk{qxXU_W^5TI>*q zXZzI-u86>_h&Op)+d39+KHWXA?a>3{nal&zqatMPf)Rh>$~b&r#3>)tBcs`mn)9f} zyv4~QAM7=|%T~Pg^ZRdIdgDJY;A%B%{8WiJf2ZmzB*$ile1&ZlA8beT!Jh3t7)V#0 zuxs53!=3E+!w6Lax(8>h3x)2zekycXfg=+A>)(Crw+?-M;V1v+0BqHfna9|Nt>WVp zatd2>!!m3ue%Q6{hdHS$ei#o1Yy)2i+po``ltubzOBdwWrT{t6Hg#|2h@BB4Ka`04 zw~5HFO+4|l_uoGASI6%C@wNd(es2}+P-jY9XK0@mk*C!c(Y19Z6-nPbTV_atILo!o z#CaLJveH3LQrExYHtWAW3gbhXVDWSK1(vP|>I(fwNjx4S5-+)a`PV%gCOz2 zfi#Zli|x0qEVeH*fhUXYzdBqWiL>FfoJhUY$zVuAtoJt`ve0b1a<{!$haBo=xJ8N4 za0_JGiO!qB&27;%Vp0)KwORG{SG@L^xk*aG67eXTib5jX*BxH76TS7ui^wJP;%G|v z7U8g_XMD@iVXjDTiEo*LZS4GqKltM9umAo#e)34j=QYT$%PbfcFXkIO{UX1*jw>k~ z`)<^*%9&ZZ%u+`hg>vNAaUZM9_(e>jbP1QK*R>3VD|GSnH53b25>Vga4t+;0tF_+| zl7G_8mP+;?ENw%PV#uOG8rrmlB$X|OqqfFWVizva1PPc=qw!{&KGxwO|}|4TS^jwfEsFt6Vkh(&UA`V7pPiQ zTTI0>Jek&PL{ezs9@6zJPDe*%6xhLqQ9v1O5D*<9gz(PV|7~Z1YWqoAuwVwAE-=Lt zp;XR#rg>cfCx#yX{m>gr%d=nHL9!H95hs(DgNu9jf6J_*I9c91t(4dr3(3su)E7o# zPL*zLe@1uJCLYIf^}{4rpMTpe_uY2r=o>#8Qb!l$${6X)%GGh{eL=3!BzE5vwx%8Gq6N@{E8KYsg%Z~OoD?*IP(<`$`C1~41YLaS*g0TZ$fsuZ$+=XOBr z^@mD-{dbl=D@7`Q{lOIA-+kZvkN)jzzxp>HAC%&KCoRn!_K z{riON*FXE;ZoTKbpZ&f6Yk=cBTSYcGzJ}}>9?<%@=ltac|LBWGVqyB3H1ziN*M9gz zcg;Td{kcJOeRmaAD?Y@g1-i=Wd03MYygB=<(Crl)V#3d-5iQnE>mQ`EM=HW z>9~1P<>}ua z!(?5tLXKCL!tv+HK*1)=+RlBS{n;PQ?|b7L_TSw5isJY7zT5aa@qbY2@f3)GAu96d zk3~ekOJ9BG`yc+?!+$qCfP?!+5>vc$mMmg$J7j0x z{-x5+9M1#k%V5!@T-?$K?de-Y!rYjyapRXPfM9|IsPv7?Y|NPlE&3)t6K|GKKy)18>*tPT`0|=i|$VG?Vyht(@ zBr672+!ZG(5L}^iS?~RVqWre(B)N{OYj}Y@X0m#oxTYRhRud@xWzP6h_Dwt0#yXVh7{l5=z$C5gD zQnJFO3NgMsyKw)l2X1-r>fS$!Xd%L|pWgS$pZ@hj|Nd{^cv|nDvY#w4S=#;KZ@lBy zPk!UAH}}4q{dWK3cVOz9(S$U1?tagY-+aq=UjHwbiDi^Yyf7|hM)FLKOC68g7t-gA z9jNQdu+)EVHZ(IMnC_H7hck($>g~^qb(Kwz|7m*nDDwg|%e%`;iTtnrdbol zb~93_tt$5Xl){eQ(|WUya4c7T2=8Xe-*DC}H}i-P_RpBV^HcWh-FI<}b@y~iIk0fc z4 z`{+gHINA$}VY;%_(UKCyaO%Xy1T!)!cDIZ-}!Ius)Tl4V8(h5Wun>|Ur@&1IIZO@!*})6HZ5csu+#N+En(?xuxVr0G!G0zLi&U` z6fG57HF`755oxu5O1i*EK109i=RK_sEII=F+q%C@n9%rl%L|HH8d0|#sqGfS%(er= zszcEzlP^DD7m&eL9Iy*0Wos?i1;n)7AM65p+Zwudu~18k@YuwJaseJ&1!j*;kHWWy z!E9C`yhOjLIV?oQQTT)Rb67-5(h@~LKegFygTp%3lQ3p~xba_^4ZK9@xVjQ3a*?v6&BIUH|Y%7lbPv2^P^U5*yMl!>$D9H2(A-j-dS zx3=$}V08svf9C|ND{!2jU}FQ0cTBL*H^;e&&So9oIngO}oSo=&bi93{)75eBMCU0w zB8^-4AUx(6R`5%PL${8iayd-0Ac|4_lc)kweN0sUWT|49X}qsHE*0bUW8AF8Q$_Xh zpkkhiosf#5C8GQRmY*x0%C^cnj`#FlSn}?v28tcJ>qc~nzS*U}Ms>!zIai@9RHiW= zraRWH!V8724&%`_@Kuc(6KeU2tD}ncc&^k@R1-~C6G`yl>!vG-1cULLt|Af)$!NNQ zNH9bvTSmse0RuO4)gbi*d1Y*)VhD@KERE9OpDR@=eBXz*XpxJbj8h{SYe?bRYF%rL^hx1=dTlzEQdVKyJw5!%S)Z2Vbkn%fdV=V=& zU&@K<{tSYp8Z7++@xymCsdtG9rVHXald!v|T&?b(!UnXz6@_&FROhJ@g9B3?_6B<@ zn&OjMV0pOsIn8qB$*sIY;q|bVE{QAD3~LgwEhny^N#W)QmEbp2aFufp!nG2<3#dv%{Z_Yuie;z@4=h5ah&HZ(M{}ShO zsB5)uwk}>m-Pz)x4NU?p+U;-0PMocG+D4ASnnQAH#_tIr-h&1&1uI^_jB6y(>pnRil5GNy2Vbl zhRPicUiu&)^GnBiOPrc%f{<;kHSnn{GYXVKidPn@nx$vXbdt{;a z&?PLXwAEdy|glN@5SF!(t zbP4?}sHVd<(2f2Zs}DxQ$ADyLVvX`lUl*w+hl6cfaK|at^HwugfbwyN;ilN2vn8$Y z8n{n0zFHh?fJ`fq+1Ju{w7N%4_N7+td_!Xj-*1i#A=qnMnNGdA1F#ttrtp%V>mBh` zMJ&R_lM5Y2Sr$4a-=ROt7g(X)GnO`QtBCebrv{-?Ef3rlh#iHZbPdE%fESWeZPtLWY?HbjX7!(&az9<+PS=TDV+ znqo?_7?&*tr_j2%JsMWgaH4DKEKO}9`?Pi%Y z>w~-9Okp*mVY`w=^85xu2_~%7_%vqA#+%J3PAEy^a13KGY#2rxMmNJ4%pv>-d+B)$ zqv@a0Fv1WOPEa_3js!;XjE)9L`Y13;Zr=#3Ft}ZLOt8Xu#s^W?@s6NTur4f%c`_Sd z)@4lA#o0@n$gsqZ+m=!XH=vMfnu$->8?8Y}Og^kdX_VYj;;uovQO#15B=qVxk)9;# zRLZW~>?xhliXrLnzG7H3eU8--_vo)pZaAs>eXVCiB}X;ihehhjXhX4+1`6FjYIT$k z48JKlHNv|FZa^`|o#{AXGvv>l$wnxfQ8t1-U@Gmv1hSp%>9vFW#!1@o$79V2I-}g4 zn&IF+i}3Jriy&&A#2S1eD%erBs>B+Yir}$e5l9v*fjQ79)L?{uqksULxLZC6Z@G0` z8&Pm4X^iLFroKowa^D%l&g*-!JkKMoWW&i5l5}nH5EGFKl42s#6x6?{<=$5CQPhW# zkZw9nBVj7QjKtI+BcbpP^Je&KuMeoTt~0I!rbq3c2ntyCPxLgJnhvzasj;DHSB0j@ z=16U+X;E7shVPr& zw(SN-amby_YpWU?{m-hv$$O&bU|v%5C<2{Xo)8sm#x&d}eP2=4e6WR2q7S;p*5@*f zjarvNMO|C5v@PM2)OAqOsB4SJOkGb^)U~-}7RLm|O&qfVbv;@tj#BA_<_%R9Ic`y| z$Va2HqGzERdMjFM@^b?fIUAP-+FisyCAir6o*j_#I zxgWgu*w;S&$8WmDsz)#o#IKclm&d%|`@>&37>i%t@29Gweke8J-Jki%-hHz_{q{N~ z=UO--UO!^XjNO6x%L*lpjnT59iuw%Kd*7Nc{nte7?^^p&KW%0+K{O&gfmBSr( zqC+vD;2VB4CAvj!d|l2a+Al3KwvvT+9!|x352fO=&nuR9*7(Bg?0x%w{MnDbYfxcP z-wcveA8FXC1ltRn&gjZJfrV9X_>YOe$K~ceUZ7<;FPPt&c!4CMyQgI0uW1&hdaM=g z$8Sab=kERN+wRBb80uZDsO8Id?D^)qZ~e?4{iN3WLH67ChU$}X^mcBf z^pvDm{6D!KExD(1U^U8K2}OZh=+Kl=RATiQiPgHVa;X(AkKx^Db~T#|D#6!#%TPIN zU|GmU@3%9EGLVhlYZ3(ir1q~&{oPOW8D4DzR3&m)1OEh0jVBm&Td(!~$GN#LlYuZ3 zatNBG#h-7Kqx+mjKY&xL{-kKgUYES=mF3H{2CM8le%$jE{mB=Q2b$ex#kcjf@=s06+_-hxTGRVr;hm+oW^LE(-;EJ zGauU=#pp=jP4Z;CYV_ttVxV@Q-c+$@Im1NLK2mT%W#Yc?+&fe24Yl9n&c3wTzHbS% zwglm5)!W}ux?!v_D~wa>@LFE)3&< z#ts3V-iP@@oD)8AI+#E5ZDBt77-Rmy;reJ)F47JqFAFkEa)4>Hfd#n%*slFv z4{xCd6Jp!l7F}7>a)P$kBcOF1Ma>$hL~vD{+w@9X!C3IDtQWG~jjQ!00<{?O;;_Xl zYS1giFyS}5Xx&8mhx{G=!k#IN<-=YvGA04)xjf}pl*=Q5DgXUCZ^H{Xz`@r_D_La< zHz@In&E}mCqw%29k<1wcUwV2fqqsMa2?*U#oS-^*&fiKLKdjW^sIry`p6I zn_4CjT)w+oOa}B?vVR<|vz@RCwp7FaWYA1{VZ_DDzQ+m|zyV;5Mkp3Stzm*O;g4OQt^Y5Gt2@TnxmHbJi_|(v>3RoR z)P#?cP~ahvFeHfp&;gS}3d*chiX1znES>!_u+WHx-eSDs=#~#SC8Dr5 zgKxKGDOhK_C-;R8dlqld(6y$1>TH^`XLDq~BF%KbdX zdt3G4Tv(EFLfiH$C#J;x&NuH(BHq|RTE#ilM}*84sm_|Z&)^L`3yvp3VCpNfU?zJz zUC490V|oK+CRMbfi;{2J!_$pt=}s7$8_8d_e^>Wj)4Y~`^R-g+6GY-el4kb(@?W&Z ziB4^KPpu|G{?Hz2ztyF@sEiMY$Dp1mMk!R>4wJ|x5?QBQE0f4(XeTj`ahGzIu;~!G zf}sa0#e|Gy+kCKr*VcP4kq^UdC}D5yuxvli=zs;L#z?t3oDSB>Rwt9fG&AQ_PzFLv z8OY0}3}lAVN9C!N0yIprP}mzmv>J1(K{A<-6wT|4`U{1GSUDgejD>(Ko83b>6hGRE z@|RkBbhD_-TcC|`R>?e!ct_?*E9<;5Ta$oEl!=L?W82?m8B_HX?`nHrZ*2daV3GO^ z+XzRA5(AYIrBIh&lUn1^t&NubBu=vR_j%PiF?>1F(|`c3=O^C(pQlF6=F0BYUwx_N z=KQ?0!+W!B?`^}k-uM1|VW!r*G}ta%o#$=u)+z-XN)YT1>HYSy9HmaQSGz$=pus`D zf_B|vTsXeBfd14K3}9vkj%iq<5r!RVGytm#3$h1rSw$!$@&ey&gqDK%A#~bI=tb}U1{j~t<4))L0ELuc6KOq3R|%wy`xq{ zz{yDzWijw#9N8YsM>u=V58H5esIt4iWUe4th(6 z(Yr!mj$u#PWRXDR=XDolTlxuvh_CZ1!m=|!?_#eqEI|xStS?r}xh_EvZiDXtDo`RV zpIY!wZSik?$ zbT&11G9h&R zjSibtRcRzJN?5Bg1K#XNfa82vbqs2@e4g-*pdIZsaB+OiiJQ-BcnN(OUsBi^G~O(W zA72uP5QvWVOgG%3ZZN89kY%&@VlzVqb?xAX$4-Osq$Z3WBQI0n!-hJW#T<}i*t)IO zS~~iV7T^zX3Q0D}I-Gp!i---T>Cy*#wdc#=$qsx9LvmLTo}Ob$>w@Q(VBO-79r5 z%>`W8y-F9q$OYu?K1~}`y0oxWH#Zf(sH@8h+Yt8(H`k2U2}qfV z4!=~Izo(T(^{Ue5U0K?-UntGlWNF3lD^UM>i>RybNAilQLNAh4)D-TKoELMghD9=p zdTMnfpQt91WMqrva@s*sBbR6g*^OEv9bIF@66K0OD-n(^Hc~;iL^1dw5zHvH$tiWY zQ|bz*6l*!CjpI(!M?K=)0+ImB*sIDK;k@Cw(9>gu_zMH|F!{!I$JRr9RA7=sAhD+dSe zHz_i)nBtsoS~pK~4tmzjzsNb=Y2Cbyjp|LVB^2tUi@lRJIOAVh>CV9To4q@)DjEOE zlHGGAkE}di`cxZ>$ex4}&iGQQSl428XOnB#c5h4@{`$46v7us1P+b>e^-*cE^qZbH zMG(T(CMmc&&zSlPN-o*`O(mV8$?vKN9J6agGhYA;Gf3yJ4LaY=KBVq5`!=PBSDAqt zr0ewpiHpoWkN25kWyh~7J6@KkjM_$x*~4SvWHb1B2fJZjHn6s&#XMMuYnz;q%Wgx7K(rRxP->H?L%+${R9bi4C~6 z7l|tBqq47uOH!+gqNC}z5v;6AG*>&y-jHd;QCiKO#e8usIuVU%pYLquBnqF=zl?>{ zGi8*dJ}aVDlIkjLmQeS3X&@`Sqg|UQC>pL87t2Yz80UO7T{%uyPDsYB()0oL-xU86 zRhPM6B8tO}PD_!+QbPfUYB4?gYjuRSajDF{-4N2hON6}sT#U3#_($aEFkHeLNapG# zo5?~6DZNsq#H$%=0)%?!7xL%7;=jeGsQ$i4&*?WzOR;L#ui$+VOzVc#z2DHYkk7!@ z+=>66y|)3f?5OTM-@Wgv>ebh)s;>SN=)Tu&D6K847t2x)^3L?FwUNAd26;lkDkdhp zirtM^qMO)}Vu%y?ZnBW}ZBG^5i)uPo9*;m&#=~R*ft~YQ0vE zBfLWa6-0koG&#*svZ(HCGu8!y7X6`B2!tUM5;I$ig+tahdP2q9l(92--E9RX&5Hs- zuYqv4)fgQP)B0+OmtjX9$&kX!8H)3Zt?)@M-ld|Ymmm$EM}5j0cHBHCIS#3s8kfpU zdk4sd`q^E~K}te1s=zE`JCp%{Nzl@>P9bU{%sKrsi{#G}=EAzFl;bI znI>UT@ONg4okorMOqRfJls_vWWtZ+Er}-9-!xk4E(yVDYv&8}f%e-9>QDH!U(im*a z`4VcP2qSsJQ=*u&2$?-$f=|57eH$r{jij7MlX2Xk^EB@NOyfQX>=J7EpVGUu2iD${%}Wtz`zRh9Ej{QUIVr0e2*USCyPVJ%hb z%cmn7lxg~oqrRkw7Y+NnOj6Kjbe%7!(Y6b*0zTD<2{6*v4V$MjGg94b+47duR4;&-~i_*0RgZ-STX*`g9F|i8gfRuq# zoR9vpgu#y~?f02?3)l*~i3Qx^e1n2o7Z1WeSOfd-v&aDORPjk|r=7}K-Dp{~bBobe zop$c9lm}gCjvI-nh@E1fGiw8&*Y6hJ9#V$xe6Qp*(?-jaMuCxTF;aw-K)2pIEJAVj zthVhv1Ph>!AMx2?(Ul)YIGmzoxp2N;&>L9Y7H-^Tm<9_#vM7Vpiw9eg8|N^JDqkxF zjp>eSez-{8kk7TYqUI<*8gWC_8br4jO&W!}T)Ba~*fB$c?vEE`8-ZIDk+LI=ZzwOS z0(~yZHUhWLou1WxqU`l-0w$o$(cj~S=+6fo#~ldh9cltg6AvQBBtveaTJ)Py8E;vp zUo~esMO7Z*aR=%AjLMc!;5_O4MD^6`N3mgeiCt5PD7?v&Ll%}aeXzn zxaPi^c%0a9OsK*RFKNnVQcNU67MML;j9i3D7qngBf&!%xBh3_6iIJvhnIgdQ1uPqh zk=jn7@~*^4BaoUHS+PG`fHoXr+mZ>yh8XK&q^L~oPMWb`BQa9DdM?XIjMT6JO2U_h zi}%ECG)!r@;R_MRV_eH(4%E1o`jG~NsbMTjT!M95tVtrQ1qDblr18zD?;6vLO0jXw zs0A9k6mB$Xf;$=4jZs=SgC;t;WFn^Rf)>FAsfJTi<%4l67-CjnfW~Fn$92|iB@MENq#Wb(~SzBEIJZjSi|g5P_*p5-%ruSO=KeG)utL=qdqIqb(K=0}Eg#SF(TZ z8++QQ0+a|-ggb6v$*)qoX)u*aVbwQq6K#7bk4HP8Z463za1?ERDv!rVSH39*SJ@Hr zc&xUH^c@UlXUO9*5~uBLoMi0T5VPR~sg7ZIW5EAliYH^(*bc+kVK@vUi`7ua$p?GE zi);+7q$klAJjJ zdloYxoD9ttL$l>!U6otzC~wnm3gm-p6x@Z|uKyPVUF|xtVXrAFh>jbj`^Kg7XTu+r z+is$5TgE+EB{9KF8xLEtN@9MA4-IWtd}k86*q(O&Jjp1kRs@pU88>Ld&gHJSfg3hA z3pa()Ro_!yLEG>d&h!&urvQ3y=y-=dk# zykkoSsc$ZCt#xIa_tfalU|7wD*sYnDs?;Me!k4T*TM&!}wNiV(jQd-Ujqh7MEvHLW zz_6EZ$8|=>?v3maqpUOP3PUee&G@GtO=}Q4#+z_G4cmP6*7Q`yP$j}d4qne<6H}_ZV@{N>nZ+Gll zUqh^22#j{6xZ4Keyb+?0gH|dZ1wHu~=*dSwPmX^*1?&s=X~gHtsh4QPshJ*aw-FXE zg4>8)!D__O;4@-+Fd6YhIE>0`=*&hcb|sq-qiCbkfl0be)(k>M<5DrhmV{Ps8}0LD z4rln7!J0!3MSVO$4G@6>WP^xKEprI(+AagP&Fk#&GGi`0YoNp6hk7wfFj~$(gf%|e zT{hKYuSCSM<_qaGnhp^-8Dln;L{oivCiiK|8i1F)_T%CuMfuRZbzU+nvYgdCJf3OG z8e<_C=k*>rUWr7}3AANEP_nZ0xu?^ zJ3VaZkzt}EgTyQ~fi=2k?1tFl(pWiTR6ZD$>&5yW7nP$$`RaD*-8#qxQG=ro6 z-7R#d8V7`>{(rDo5~N=J2P8zLezV zX&_M%PlMn~DfCBYN}_%+fobQGoYBxDBF829<9fQ0^}`%0wF+xpj1HAro@~*!h0m8G zcd4{>FS=BMJT)crraM*Y`4PK#&9b7qr}=%y6S?$GyBp?Uh2>EbxWi4Ivl6`#pKFe% zE**`#m>mM>-}{w&wbCXZGwo2p9{d9YOAm%dA1-K!%g`Oqww%&fjTV@4bE(W zU*_5YdD7ufS8j<<3^A%YL0aSpb)EmW+Tb#hjlg z?^^P*_Hah@^<4G?M5w)>Y{Ht>?#^HbFQ!rqcJgG*ju>VW&gY0?HsRciIA+^#7^_X;HRkVum zHF2;c+W2t|^KjHaO(WJY>2i#%<-_-Db$NdIq<$+&Res&LuR{+^4-pmWC41WpcO)*+ zsZolpzRCTyEsC39Sv6-$+}4VAsjV)i4^c6$J2>Euy+PL8Z?3cEj(Gh6TcPocHz6gG z6rPG>>E?B7pJd~oOxrAyb7MZ9MSK{6s{6d?gq^>aPRUx2RBEgTXI&drdOK*;ARB95 zxs+s4jrxR1QF(c)^5-p&7&?EVyswVV^6~qGFWaoknRSK=*Y+D1(y)fpXjp_d(K_q3X7COYA%~Hi@Uk zgH2d7-n5cIQGZM^v-bUy{_kti;aN2m;+xk>j$6)O*}o&WiSzObQ_UjdCjl67hSs0G zzHAvSBBEH&#vvDIqs-kLz0I=XEi(f~07t}skWPu!(}$CKL@pM`4{%y{TMnbzK5x*( zwM?R{cs{(%J#YBbute@Rx4(A9Y`DVdkOcFrN_-TH$)W=SnUF^1ef^Q8MVa)STYPq+0}Cp}mK;N9^ZJ}G9I-sy{YX?lmt z=HlkDJd832uJn#rrnMuz@6-Ff_>L3&{$UTpjyYNej61}R?I8jT*wD)f&ZGbNgQPD-Xq!YV5eQIY^_`;ilbAK8B)zo%>QyG8=NBu(K&CMyKNt@YoA6@L>L)Mi*oS zRTokk-83n@o(3vROs}VD=mWa=7DX}OGF1c{fC&bSD^;g{2$Twkvj&+@8fneNhikB& zB8q3b|G2Cj!p&nHf>`i-suP*U6VQyf#^a)$#|bjZ1PiApDED|rA`2%$JHwtXt8Iw= zG_?8yutcWx&iHHcq<82;%rCqvCMQw?)Jl5_V2EIj*#2PCc6e#vI|R%)Sk7td*ubEL zejNr`zGadfjzou;%7w~J{3Bx;KsHH0JaU|>F-9<^}W; zv9-si<>d-*h3f55^4kgKElapelHP=r%$BND8$?@|T!uuJ587VjD6QLx-)4EM1JY3B zPpU1Cq%5tfH?dksUBa|AV9VZwVGeF7>khi3N^S|i);)S|ed~YT*8{;hq4w?6QnN8V zF9=y>KqJ~pyN*qzGR^&vR>Yl^MRS;-Y=u!vMa`Hb6}Az_Lp8wadZfZUBKF(%w94_) z^5mp79I-@ML10dWCWc!9V3?r>e&Sx9e+U$F21QbOJl(V&!I88cPp9@pgCwav;LBh+ zNvx|tcv68Pq=D|_JUo&_!`nPwHmut}q_OSA^r{B%j+eBY41TC zTZW}Bvxx0L-HSg@xXF#nf^1B=r56Ghh z)_c=WIdg5DFwZ!wCSs8`Vvc5&>=>7{(hRFSQ5dSgN=M*iiESSo_5|+x+~dRxRxoSy zgavvj;JuXSBP1L3k`=ovtVzSYd$)j+XI?-p1O`1FBqU+gm_u)+tPS z@!g6->K{7t$0?R$=%U!kK(Uh*#ZHQ1Cr2sPUyWiPk24yI6)mk#v5Flmip8GBT;Dv! z5=ZbQGkrXLjAB~{i}vL+1dI+8Yc~Gjg1w1);vkA{YUYJj83D9e#z0{ND~189q0QsForGa;=XOo24yHZgmZQZK5Z57aW3uhuVB?*}!QkDc|hX?V^XDsn;VefQ2dSC|Rk3Q|8tn zV}eL4=NHJ2k(iWCP9tH<0%Z+b)ix9Kh1E=gP!n*=*Wf5;YY9+NAO|jCMJzpG{}0*c$S5m*2uBEjD8h98BJvQWhfycfE|LQCaWB_Lq&nmz{#{L zgm5K~25zxJ8j}W1(V}f*tM%ES(BsCS7Don7p@t38VThD#^fJD@N4zq> zJa!6P!cfrjR*?=RA1Va00w6a_E?5wlK^yW;A~#ZdWZEuAL>@D&36ubt+7HXTRS4?M zqE#N635KE2tao^tuTa7$HIuJogB=zPX+`qz^epTaYk`ZeLH}Uzq%MqTKgvSo5KuL3 zQmKgl8s3`rqg1|^o>S9)l#0&LC3TJV6EzNS<;=h3il<;ZjO)XTSWp#L0)Ua)WP70; zT5!S{US&JTu>A=F;m3_jW(8MLnYsI6_tD(I2>zhTls{P>svFFKbW>k5@u$n;8y>K@(NR>HpuI>*gknez32avcO)Vru)h!KDFO*2*qaZ}8BULID zT?t`SPIA%1{o2hupL7k{lMm?al+yaEjzuGoXs&5uvN*7Z3{;^b%UuuJ(R|GuCXLA$ zlja0Fi7hYV(%1TbO`8vvGM(^{Jpk6o{J}~f3g=0_&}|EJ?*32Oax)zWEoDIIpab=! z15FI3kOFcYr@+X;wODXjY<)9&o_#&Nus)+V&xEJGpDKqxT!psTw?8_Rj;o5-(Wj0X z$DP+;c(oe*=_zX zqA`(?=&LiBkMxDLVwsUe5<@uAfI?pZV7;-}JOzo(7>QBMKB@_bO_f9{3j;9Rh(=N+ zS6C&9$_$c7XknB$t^^M-&J>8y=Aj^23?jX836Ig+OwB|PqVPj;AlQWi2Xa}fzTe$ z889yJd)wvZK!V#J=3Sec4?_QZrOnMto1>Ey?L_;7znV6e{Gjps?8@)L2!~%I99A)- z5?RNk&CNJj@g~=Uo_H7Gw1on>7BB^%_a47tvRD%I-mB)9B|-1KYKocLd9RvcT#Z76 zK<%>5NEt-CpglyE-ob*)n}mEOW)^byuzHrXz{gM*AT zynvBJNM-v(9u~G0sxjZnOJWOHH7bP2(_|vyG#Ct*5t7WQ&)Fk-VlgA7u;&*L_9Qbh zHr{qV4IZ}Ov!a2at)6b^G4rOq>&r5nwb(MHV6|wS8iAKB!z&DZJ;{ z8yxHzfxRTc-VE4hHo^etfG%j3BtVxmQzD=uvp9teP);KUK*6=V!k9J+LhLii!cF+K znx2b@yfftTD964b+b~)m^(|tx&hzM79(6j{FZJ|XX3=v)E{}G`X4bwHRo#&di%Xk_ zs8{Z%t?al!+G~5zo2tB!;nZBKvjL}`VQ!04&l`IiLjJ}X(XK}23$XEg zMn5r}$jx9YW6T=7UO-~S)HT;ho;_MkyjFt&mWLPG| ztS61M#SQ|qo(arah9PRQH&I>1u6x#>9mO#4m0iX2!xMp2!qfT11>vd2a%XG-(*nXO zp9|tSb~}2Qj|6U?qlV-RAZfWZb0r*q&AjXjg#;s$htx^+%2#|WA^^0?@k&MSMZ#jL z%f{E!12#VX!q|`rh*S_jIxii4-&qS@5sxw%z<010139zpRdl#C37JIv6765;1pr@) z6@#Z|E8PLO1hI?`4h@rmJLI}~4tdecB6fugJXZ`E5N*J#av3QG3`s!)=I2cauB`o?84Z|B+LH%SBg8kv#WY|u z4A@K*YPs%zPOxn=Y))c#ETROS9 zkPc8SrNAM^91p=9uPz8P&rv7VXVbS_;fQ|AVF^pD%-&%o(F-~(<%tPewQwBslxz(# zwVGcQeofU{%O008cROihdtIp2wmWNTHT~0^Kxu-W{hn!Q+Zqkc#+hPpISZsS?itx% zXKe^z=W*^z9urLXB6f4mChb^&$zQd01yUf9U^q3FNR*Y@Y-q4`mNM5a1traI07~?vWnQ zV!&FJ9_eA9k%L0AyPl(AT1yUAtCNFWGnpf`$tssf;)*k(2;!uV69miGCQt!i$@l+I zDQELwZHBxQJ+($&P*=7N4T&n&CAmNe@Q1aOAZY^87eXkE5KISKhcSrVuR{k2kBlh6 z_g#lwpA4){Cxc=z;lexmT}1}l&xi~r){=n)o3ZhgUI1rkjB#XcBcjnpWQP;Kjvul7HmdJ^C#hGX^%8)!>wsepsV15oJy zbZt;Jn>R9D_I6=|{ZRZ$E^IXY$_Z9u+i)et78ZWnK>ebD8gL(CsNrZ_j*G_Bo&SAv z=K9uaT5$*Kaoln@v4a)CssBn|sO?{|wSedeV`Hu9_>GLFz{(ymkZofc;R9I9b-66cL0nnU@0_9BB&*i*0i2xrP8XvEQwIr4BebAyVng>PGlmIr@m#vJ6IV$ zWGd6QnX-#gD^{Vr)BWeWX*5_Nj_)$pWkenkFK#mt9%d~+a4)acol2# zx$l9+6CZrXYT8h68cAsTtOq*LFLW)_aT51Nvy-P{I$a_);oMU(Ov`0=jKVO;%J(|q z-OFO6##~vm-3kVbuQsX8@{L=0IKE)#0>n}X4l1z``V7ZUl(U~RrWuWj&gS4Xt@2j* zi`*vf;a3NpPqm52APPgAxg_5|y%oIa*xp1j=f;AIvKI_xyBhS3dtWccZ8VCfk+zAa za7^WM_?rkcI8W-TH(34k47DGLfpjltBP_=gdyD~gS&?-~HigH}bL8l9C8-$gfnfqpcknfPM?8hATT!4F}Bm2=JX;#7H$ogE#Nr}SGL z(6uq%E1KUIM_98q4Y!9j3$sYOyJ>KBJ7*fxIbPBvQa1vpz!&AoPssb^V$v#Klw{>R#BUro8%J;x$88QYGDYSzTv(=FVQVZSkcNu^(r``saLt|Va7lnF%-tUe zN6s2^Bg3U2*p!I>9G>a89m0OQEjY8j9WtvIs++C0LuR!d0udoAaN>>1Bq`WydoW!M zH9VsOZP_sMW9%mMU5vyxtzQ7=!19k)M;c3%ZzV(6GDs;6&LxJ_H7cc)Ew+4AZ9#x0 zQ4(85(ngJ{#kWM|s=?-l9BpSfz+_pyAu!}}8Y>bSb_R)~_L>2T8&CgDQ%>YEG4>R*N(PpqV6ZM~hbRg6_USCY# zDySh$FfEde#%2}QX&5s$+eDrzxc!M!YtvvrOE{Fx@a$zm*gEdKoW=li79d%dr>y6} z*gPwdbsA%HPp-I;d#`eWSw|ISgRvPA#f;5+nHyHEZthlN%8;qKmf?nGWysK6WrX7O zBseQTX);Ux@Ld6x{xGpj3ee?(vp<7trSa04GEpgFNmE$7B)^#NjhEQ+-(bl=EGU4T z#Jv)OjUhQ8TE;G2To)I-vfz8 zJoLv5`z|nIL3biDs+cpX(5JdA26E|&4k#mv8cs%MfoZ29&83SCEl6&-2eQ?fHj+lD zWUg4U`6y0v!1p9n=TIjMv?pProZ2IHuR#zg1wQAaVUFLUlwzWvOK_9EEs-c?<{(mW ztZ$rBGzqmWAw*fVky4c5l#()>Qk3D85;H_8q>fZ#l)^}jQi=(Qd*~ZLuC=f-WMV=Q0k7(kSkQgP~?3~!uvZ&MOyVK z%*qd7m*jU!IfLwuNm*m%=kKw}1Aap=Q&oa0m`6(_%b-Dlo~P|%G{c$pOMUc~^Fwn?TgGo%nBaTevwUj}87F4dlbYw05>Phd?Ps8X z1h~Eq*Sngj1O`|;162Zpo4nMty}!D6Y4Ze}NrJPBk7y%?QEM=LE5R}#)mt9P2}pGi zMsfmD9hQ-tfK=rKNme8UNGI^aF%^Y*a<~UnH}#BiV9OCBEYEB=0>$F&^q1j<`-W+?E50XhfVJB@)p$kd+)8l~bFMhpY-@nMBB?lBkAI73q5= z@qJdC5K4lESuaOQLGYLkW0ENFxVRlK=~+gQLkuw{wJ~NV7k8V!<`~cP#)(qQPKT@@ zB1Em*Y7tqV$EidQpQ2{3^KzTi6qe4^a20MPJAvoI8Kg=(8y z32=pYJl$B10P|z*VG17S;Q6s>sc61r2P)+~+L9ul6FkltYkXF-!3<&EgNRz2B>>~) z>my2eTZ&Y^;;>d8(7b#_HR|?JIIm4oVcI%B(rxGTWO)A*1WLD-91SDs){@dkTRMgt z;Oe4q!GwLg&D>xOSDGXZtb``}8Wrao2@!ndI|!jJrT4wcPYbLap%7|PK2GgLvo>Un^6?yR3yb#BIq#J0(S92g+$lwzl`}T9+LP41rceOIOhZ zKR?G0F$S*S2MGbtv}q!+L_%5rP4A#RnKPe8O$y58^sL`!LO{kb5<2r-GP!rcZ49Rn6K0?wZ4KMkb5n! z%lRt@_=+s&*D?|KAs(6SWmtr9qnixnF`jN~;n%9cwIUWMDHCb+lxC#G1{cp3>Gzo- zEg+Zaj??dvrZ_@ziwF|>c)NZPR|z|3?>Fgp66sdIkdcU3PEd!`2`;tMVAe-bzU~~* zKj?IYK#K$SOjG_QP9QL6BYXIcDTW$u5h4qKrzb}3=_~@C?u&qUnx?G0^xwh26GFf-E}>01LY$-&a^f+`X(%Al*$S4L0SRYuM5lrOO6u zKnkv7i)y@qLb215v!S`d#hV9eTkcbjwDMLJa&jz)t*=^50Bw}qk!;GRR+1rx08F^> zjV9yf`&2p*4_k=#_4r$~XS|3_e2)!|N2eP1N5m~_1g^_MpXk& zLbIzRClEsqKcKVgQUZNKlC&xUOu7b`%0BrzDjRlgFBL19PjY!K!RJ;c4*%mu#$~~z zSs&PEv5m#7|1o`{_AhL3P+V3GM&yFVj!PREg`0v@n=<|xQzLx#=fSA5{%2T4RIYSu zhhQjMs)_GIO>&i>1Ta5#+M0HRns&sHca0K*hgFVk!lULjXlG4(ZM8=$p*?tFctXU^ zjcaH9uf?X9^DDJ*=H+fx1WO0mn({zy!Dz3%w6TltJJjju+3x6JNb>Uh0Ees+-iBH@ z6=R}KeR{6hhPv`796df7B-zB0p>YDO&lQy75yQ5K432G!lZXtCzCMvfV)Ngkvku8& z^RjJXV%1huH{n!=laLc0u??7p?DW+MkL^u?2H}YWWjqUT&KThVY5#tsz3w>ebp!3$ z;d!IIX+g2f(Ce#DRphr^Bfkr3&D$GZr%4Q*`l3Zp^ zyu@A|vitfHOv>K2f&mty5luoXk587kaaEt8zJ~C1>(f~Z^~LHFjX%x$6aZn9^=+!Z zjAm8e>HE8>`sDwd;M-(siRY{l>78 zF6Y<$jIAa=q2+;vU~DzH=F-NGQd6~>EZ0_(i{ffR&7n1u6oBAgm3RIDYFGKA)cOr- zJ$2*9czg2igoagD#mM;_!ct!T9XSHYAw%HG00V@#8}n)&HtzrgAxT z;37&AJLgJEdEtSJGDL{WvgeU~$${mJoo5`L8W&+4MjpWS;fr8)nF$DR(Vmt`6HnTg z*%NkUYq&w($m5pARz$~hO%Ra$p_(?;rOg-IERw|eH`BBafQA@7YY!+s)R_8oH%p$G z{juu~sx`Q1fd9Azcg%}M0oYlmSZ+}3ZN+NHZ&=r#w=UrG#noo%eNZ8@iE>4gDQ>~m0(gW61>Ds_N-WuP_> zxTwi$38+IILIFgpqR9S26RwIkw<8zsT7^Lh9U<-R&ns7VQI<$-w4vL zVa!gFm^6%96{zEkhfquoH8c(3S}@O#xJ$9D*MM1U4on6bVX_w5T1P5)$HeE|&FS3pD7E1ioQ(pi*1Nz@p>t^z>0(wx(#{1=X`> zbB(Od_H^x~3g@aiYb{I9Y4qO}T3zMMT2eAC8M=e6p=Pc`@z}$;I3!f{lnp@k({)5^ zh=~bzav^~8LghPzCV`}ztGpM4JWWqU;A#fem9mT^u&74}F|gn>ZwY`s?tmFQW`Q-o z4TDILa)7A3<8I(kjI&Ppz;6Wncgn|K4?YdHmBXJq{?<3$_}4f8`t?#|I^1s%Ap_F{ zWInWN=6(yhPv|9o&gKxLe*0ot?bHPBZI&}(Eu z@}vN$#hAZp*sVataiIeBDy$1Ycl7{qMo+r;~fdkn{P~Te(Uev^5MV! z+G~I9U#)}Bw~T^`fl99H7!D^v9t~Xq4e|5S4iq=GZ+Nc(J4$>o8pDgoFb*Y1!<4>vv&83A8E3__gbE|m_=iM{ z8<3*Ypk1>74-&EHzUnY})*;H{)#N!lqJ(UyJ8>L361XChB}@>}-Uhd^(wc+ywj_wCpI@gv{-EnTj4t8>{5lE^r(d1Z z=sug4>8E0lwN>!Z4?oRSFi_qzu~`4WIn57nu}1Y-ON-l_7JqvKT0FN{uOm6uXz>TV z`28RS$7hrlH?iui<%`v-hkm=37TJRrU;OMa?l1;lj93`7}`OPTVv{yd&$?x9!=^Ov@o+Z&DCV`+yw`H?< zQ<7}j(xlfBz=Coe1TfPBYnn9TOr@S)y+)3$=>)F%x63qj+T{}u8RUI{l7wYbr@it= zfA@_?U;l*C$2is#7&p)bO!N1v;-p4MhpEu(TEPgsUvdTE zX~4S%zex%s8q0{J`}7h0iI20*AQMZw{7MD*S1UyS`rm%_H;>-_jjz68Jw#(T2qLc` z+Kw1i+Sf*i9&$Af%xtZZRK@=xPbR}_0UNhxx@QI7_Yf~atbrL*!}SqLK#n4zWr?qDRtmuU|;KGdkf zIX&6VCZbhSJ}sFS;6scn#vIFj`Of1^nsU*Nnq(!T9^lqYmW+JOa43_FH-FRVOqOQD zv7HX1W-Q5&f*2xL8+QtkTZ__bNOgxcw7lI+{x5R^VcW6j{x4>(MemQV~PWc@&K` zVKy|@xVUPpyX6r#QZ{&uV=YHlgb%NwtFgA_TRyG6_hWNpl*ez}f4ivgYIwM2Lbv>S z)KOFaza3{mcjdODzy7Ive)s5aI9nV;Ks5~v0Udf~`&DKxtmZ(sJ_lp~G1G0}eE}zX zBTnSSRDhF!8hRnr@FvuJ&p};-nmC^fHJh0Rr_wgv``QHm%3d>K+uvKC1fbZ~y0SMu z2`Z~4w6 zH-7zp6N_sl;%XPwL&kO z*!q#}%aVu=fTF zL0TJvw~8l;WI5?~>OY9R&6f{K!tQ@j4AMOfyOR#28>qO}p$mJ;vDGgOy$3yXdCsK*cAxp_kz)%In?#CX#ln>esDB=^CtN)gpIpYbps49SIPXaA>>bYj!U-VWdM!lh6nIFlyt*IKPsTRKx|At`G3=G?Bno%FE zoSM#UO>N2{BWN+}u6pOTrZ(qT_f&G@vxF4SZB30icP7>T+}4zg{)pM)9&WvS(7>~ULj7Cid%?Gd2^*>NH&6WE2ZjxWRh(OMEMard*x4J0#*W97gkttS zPAKFA=dNqLTyxk)8-8QmvkGk^FrC-X=_AbjI>a3+GbjGybk*qu#=v$e=x*F}(gs8g zR{DRksqZo)B%tEo$y`v8F3YL#TW zk7O!rijMTzr5_5O;xF2E$aQ2lml?hPHUqWkk*7p3%EtaOR81U_Zd@T{ikP?AKzCmD zkB2RjEOde>AUfu*ZM+6F+-4jg77l~h!02!k8(ln8ZL_>aQC}zq+&5ag9T73#=!aMU z?11YeQ+`2X!cSX)5yN6aibu>At`lBtc&t=H4Oi0`^n!uTEZYG&qL$E;gGE!p+j%OQ z0SG}X0MrjF!_2@e2l85Q0zuyPJfn>!)85bJx78wm5vPJ*ixtqf z4Q0hWXp6#{;an{RG#Cw zx>r#b7u{Z^KU``wxl0ek3GV-z+FJpM+=Ns#?dl_nzgk4C8<2AQ!xzn6gPdYqXur$o z2nvFZ{d3x?@Ou{gH@q;Q*#Fe=eI zo6?FE#0ItKjxv=Wit&05h)!rjy36dyaunoT0PM`F;TX$ zr`5hEz%^@(ZZ2BYxn&*TR$H7jAKH?}K{=&7+VBPI-{_5V=a*%B^u($27dEORkw*&}xvE?3RlmGr!7D@kpw|R&bDgIcwm4lb3(&sl@ixL3BHh{;xTY&cg9;20G0N zlLS1SWwvwg-erT%PPbo{6=a=fg=TpADG4*RLJK~4jq)g zEZa_=948dsGB1CByj0E1>>$VTD%aj#4LVg;ns z0#AQZE0q~UtOYul500OwPBGjUWqbU1zSfb8vLcYvb0md@99x^MHhH8x zNW`8~lM;0ZH5OtiTUR`mGF-;vB#DVkXzo!KXP8$Z0C94fxR7=hUrgp`TV71%!^DoX z3Pyt|(?O!ENzhEaRD$Gykpw6zMl|$K5PM^kR8N3tV;t2?Jvc=y*2i%ZgLN6S$Q!iJ zouv`6)^2JSYEZ>B!MsUxM9B*zmLnW)WA2$Q7O}f?33o1zn2xG2t}gCb%R4RE*!ele#g_ zpCH&(RvzgE8Lz1Mgx=c8rq&~Upn^W+ZiYjcE;nl$?dM9Kc(GQTFgMi?Q)Au3;IT0{~zd2nP}L=s;+Ekv1`O0_}N++*m>f0LYQP)DZ)C+0Ob zxL?EKjMwIdBwO+tLklym6|Wa&1DAY<8RGLoH1JgOB95pNIpZBi)f1Q(ab!J#dEt>u zg?*>J6dklaFYIctG$9P7&_oS)VL}M2s-}iJURy83I1~efg|0mYa)P#r#GF3SuN4iHsj48_gJf`o-vZTV{E7}U{LQAk9LajWCY7lOI)ulmIn&0wifvx3=$--}ZqR2k5 z^8M@vJ_`4}TK9%r!zL?A0S3`wUT&dW(exf|{GUpBAbasHejjaITfX4M2dsiu4V%t5 z!tF#LFXw_+xl8N9BL{QpiFRk&lu#+6?bifRvZjhM31#YXQBpJVqO3DCt3*~38<;hx zso;|$cp}Gk(CUdVn~M>Y?V@u~e$A9X?wp9li2O+n;t%8$U9P0KER!-$G$H*k`FboR zZQ|wj*uihdi_$6U4x`+~TXOp9;N`?+>(LiJ&@CJKpvm9ijBDi*^%w)_v&dMG$Tr1z zIDu(oNLYI$9%VBkvZoB^l-y6rEGIG}4Cj@+pyX+qS0$#-Hgu1IDYQIo;fYzm(-I#6 zjzn8-=z(5&kW4aBEa_*Ckk0(f6VjQVyx1xqREuaB-~pHb0_|I?R;WQgX9T_kD}8Df zj=n!xNu^O8KPcW@TuRiR^5OeGcc@W5zkE`^Ddbh#Mh*Rx;TR$SDwc8n3OG~@WQ^-P z*knjmurhI=AU~D^0>Z4+2c&=L$6wEFmXtfn+w>dzRX(oZ!sT*#%O`57MSGBe5vb4Xu;6+%88IH1ZuOx2 z7XJg)6PT$PX0JSR%?>(f=S%>B=l9G}mmR0)qMYl7y5bDmuP&NH4{0lO@-GW~?s2F1nsP{IV_$A21tqAXixWFmyM)3m7HOOL&GOQh)P>2@Lk&zY8F*`< z_wYkJYryEqFw3v#c`)H}D}C((vEM-|;|AAv79F&yjta4>qVV6tncKO~hD_*;MV|=Q z+$nBxj;7#B-?u9;nJ!hFdPARG2Pd?u{h*nexS*~pfTG9=yrD)xHqKBw%7PUTfe~gR zPC-O%g|nl;aL$QFMfxx1n$4`}7n28vz00y+09Qrsj5|w6;pLhK~Kec)?=)e z#hi}HQIBpi;${NwA1f@=rxFz~#~O?jcQYu7<4ICvcmiBbkX?OXfOoPiErQlD{64nYguNg6w!{ zCT=bHJ29C-h{?LU>GPICGw#d;dEchVxib;>40I0B1 zbpjk}atm|g4AGdKj8_K8yjW>2l#iD~DizaE^J-NCu!$6E&%{cz8ELiECGoHQxYm@S zeCXc#nu1}9dg(o#n})1T_VVr5cj6+VLv#5aBg#NuQpN;GQ=!DAql*pb2C$TG2SSDb zPCjf~goxSNZU*Sc_Iz+S5nhBJ*{{V`bU&-;Nw%!LrnF46*7@C>Gp2)albN6DVkX3k zN~|n`jgGeQ6JuUmGGfpI$^68C*OrW4%)zvhpQRu)Tk^7QgwdS|!+4PjcO6>+9CKm1 zdtc7Ycf%c|40aYfn2mbc#gpj;gY$SY-C^(?o=m?OJh#}!bJ9YViswr5S}dNUpZVfE z{md1+^wTYN>L=b!r@Lykc{A8Sj(O$ zl>;reWsz$DFye%*8J@2O6_3`DO7&K=FcV;sfM)gC89l2?msNN-x<#r$#9V|8yiFc?0P`EvEa3#f0I(98DD@V+PzM)=yF~MJ7#$bO_{LA!}P0zTx!GLtQ zj32J3)UCNWysJF*fXhyYAFR_kxx}9jO+N^ZxGY<36`+ovUXFM$$(U zAs2uXn-)emv@YW|;*ni4&ku84Y;CZ^tss#{1gPAFc2zzC1gQ=eqS z3NC-Mt5lcLOx_7Nn%CZbx^Bv@F^as~?k^HAvzo-oBKx)*i^TN2jc82b`dn4X6jelo zIFU2sEL;H%0SxEqj@ap9L9gs`nBkn#w{Y*Je*2N5bnPpypb^;=gad2vg;pr4Hy$Us zX}DN5A|A3(P|tj^pjE4gRWYjEn4^t%&~T6`I+!PkJLkh?m4Zt#)5SgdOq#xC#&j`f zq{&d)jOmMe^tmJx(&P$Ek*42QX)*(=hqwpVUUT6t!>=x>N^y@ls+f>y`JTlAefLt&v% zfZ3e4?JZI#FFw1rtiL9Z-zObs*2SSw@68nZ4|?SMWaJy0|pF8o!a^;?i9% zeghrT3(fbLN)F1!Z*+xhvcgJy(M@^$gxM_#2BA(D;iZ%baVfhI&pAMzuGX6&8GfTh zRaZAJhz*2`siJ_R_Du#7?@-g}vJ|zNIFTAmY)owxku9-l8X(d26XG`rvupT`U$c#R z?rJgQhfFsqWClJ|EI@1+^&)u2Z*(Q3SPX%fBoVgl#Y7{TF!mHYb25`z<_b0|XHmcf zU#yDhGF_m|Kp+?n#BXLvTF~@a(Dc!yi~MGWsWT&*0UA)bbipq-rHk{qZH#6OS+8MX?80Xdj5P$*dRlzBbhj?PV%9qN z3R$E0isjeGSI13Sa1_Q~jKz#I(uI=9vn~hu^lT-@9Lp;sqj>QE`BcIOa!d!=tZC6q z_sJp7Ea7I$n;1@(9W!6=GdBt5qnFz&Q@Kn}GBc-CxQIl5w5WP290cAX4pL8riy-}o zi_}x$B(k%?N$RO^6LD&!mypV4jGhRC%EDk%wl6qM`4d-};H{dr$DkIPo2O$BVn&gW z;5PYM<0@lf(@5h=rSUE6HGT{tmWZOdSn#Ud0?9Ve7b}RcdV(tU)pvlD00Znr4rL`^ zc-8%TDgo1z7U;ND0*o)-ALW(8{ANc=z+j@P-7Igxf*!@MrZ&NnWY#S2;4QLByYlN= zZvREn*3S1ayxfk+|Ay+lol{BQvUkfu*bb8tzQrcc+ROcd)mqx+028mQCAvDS!6ViN zj49N!2R%Ssw5f~zw3QJq_LG<04RS29yWrxze%A^>5vk%^2)=UsRzC;C*f7#U`Tn4( z&>Rh=OZ`B#w<;W)af@|Fp)>5~JbqZbxATMD2%u!E5a?MMoPB6GId_7KsKD(pB`lK;W99c4&bs=&Gc&uho8XO7q?%{+ddSALU*;!HHSB9q zlz?fZM1e?3{bz)f09xZvh{Sv(kmC-kFObBI`h|cFh4)vfG?y3h15#NtL@?Jv<~`lu zH$r*PZrLt+2c3-2&$BXJ;741`aA&S5N{bPSO+38?Z0td1AUYipecAKhu^rzlEdOy}Z-KW?=AT~@K&ggC5#;s1KskcURp||1o zz8`FFC0Yq5Rfi|EpkZmke&ZMS^&p_Uy137HZscLuOW1q}afGxz;q$=)d0j)r$MUes zPQ7h5FRt$})QrmY+?YynM0DzY$4mYWD6_9!1dFWoSVNk`5CnwEr54NU5$MlAJS z1DTMb@pW|&Y-reB{;?N$sP)EP;1*`3(uIm_Xo%Nniyjv*3^+#|r9ggAUP z$)izLY3)i&0yYh6%GFV9=;W8dcy1al>eZc8I7x+*K^>KMh|FKXb}m);m9~YY3@M|v z3|Fm`Ayu@>5NxE@lOSJ!av+CTk2W%zW5tmxAviG=+VEyTj~dOb`>g+|VcTL92E6Uy zWD-(G4d#L~WQ>~2YZ*Yx&`|$+#_~xCLo$_1#${Zq0RbZKbOJ}Kx&}nVz<^BJfH3u{ z=$lX9RQ{X2Y-==?YYVdFD(Seb9RDn+BALoN?9rZ`rMwdj|2;i(uRKt9)!I$ zc-Su^d$Ha4m{jDd>)wdF#aTb9zSEDYy8vnmZ0yH=vE!h-yCzRZs5qJ1#N*~^Qr0;$ zcg?$zpM=nQzMlni#LkaL1{yr3BvUb>kxXoE9?R?6t zau)^6`?9)i7n_@h&6$;7z{rp%Hn*J$w+A*SIlcd z*hm#@F^RzesA&U|eUxaW&P+D9&pY&Y%(f5OK&Spjcf5enWZu_iNHp(n7x&S|kk%IA zN#=dw$`!Q;4;n;+=?<1!Xw8Qih{T8IG=)A#{-{bj2j0OSARtjQXc)`;BK})qnSNJ~+J+;dXqSHr7`n zoQKMa5|xO$_F(QCGCVOGv<_?5;}KTlJ}&A+Awzzwwdu*o!n&s9Ju3{#EkLRWl}($t zt-W}J?&#?{iLl~|$}HKEZ{$Baoby@9euF79NUqdtf>p&;O@EQLk~oU#FA|dzH(5u2 zSxBBHi>|+HQ5O*sC7~vPTgr~fo2I{P8%akrg#uuwc!<=MBNEv2gy#--jii%s9_g$l z&lyQ4!L^28sbLHvMsP&l;LL+tAY-fxPF)D`QosVlCyNL_KoMe2$x zE>c&PgSrwGmkWvksY!7;zu+e7M)4fiUv|0vvcvV4ZLYs8x&AVA{lyiR2^?Lvgz=H$ zG9AG-#buEe)+#Pi0j0Pk-15GG;sQgGh!0>}lC-`piRz|IfV1hMh>8Fm7P@DP=hjmg zhkkKhJ%tgQFLu^b7~3ty_Ie6bu&t(uP%{IubyVpXQ(P8ms?RB3`RclllBi=boo+DY z#}yZLI)cJt)?2!43X2(P?Pa;Hqp+e!%&b*d%(cnBfi)+kBPlFBIdzWdDRJ@CWJuzH z)oeNzm94KvtnaVwYD8Uiz;=mKJxm(Lo)&a$7s-%Ra8>)eG2HHCMS+dTRT)o{#vseF z0NVn|%82hU4k+-MLB_gavb01)XV-A9s7;7tlOc|sQeBo-aXFvVGF+BchFni-8752X z^arvulhYkf)S4ZH)@mlLNLxK4vh;YvrrZSY$`QBjx-5Of{N8_}ysz%}zP^8Wayz-H z?xOM+li5;TmQLm+fJ|GytO`P|JO_QH@TK4>HhepH>)C#<3`{oN?7)E3Qt{8(z(mX@ zz}&+hq7s{Je;6iSiOrg{%)MED60czHEs&DLW@GS+q>M6nc!0Azvp>KPoCmYX3@G$# zN${lo;Thf{so9#g)z&fx*tbX^Yr&diXn~oyiy%ysOu!}ST5u(CQy?XAljF4FAk@1R zsueU^0GY{^*qlePSvy-|dvgG<1#YDOtIj-xxf%|X3jYxHY73p?VZZi@aURi1I>X

)wc)C#)Zl!B{`co5v6VppmCoKTK@aKDDZ}rJ9b6i_NpQ)1v??+(;rH&{tQRDh@3Os!-48{j@?E}ZxA`u!bW&`xyruc_;nV?sg2-BV zGUqN|Y9iQIL(w(fQ^>5Mz3K8!3^2Gv;oG8GIEz}rQ(XrNm}-0;>6u2psq6 zSAweXvbB=QOIJri?BH62i22OtoYqb*x!Sq1N?4R5K_Z^m8t10I$Wh#R*UC=l6Hg}^ zk%x4oPl9-~HoBwkNS05P=%`!I(qu75 z-Fl+9imZ4~<*18Iv~F`W3_g{kuC>D{)PM_bALHLh`l#J;Bx}_2IFbd_3>Nz1dbURk zEFkXyO$kQ28X~hjj#Okr6s(WFw;dS%iOI@qI;~kdjRz^SmYpN< zWcT&N04L_Xs98JBti^Q3x1d2XfM)F?GQeV(wL+|90B8-%uT6o)Fl&`1DPSbaXRWd% z2h_6!Bk7}wnzf5KdJ0%JTt{SqyLVe1ckia}V@5PE$B^l-41^J*$$}<%DO%7LB@RRf zSs_doG$G9_Xca&#G9WG3(1MrWqL8*&x1pJrUu8p6Kf#+^Z{tt|ye(2yz#9s^)g2wz zlojw+WjWrI74Vj_gg4R+Zz)lD!>ifgm7aBG4zfp^6-zi1TiS;^*-V`M>xmG_lD2^e zkxXfo2r(i$M0uiV6IJFk%}trpBum6;+$7y5R9M1ey3C{~G#uz0HKu9J_7j~hJPy;2 zATAhD3b1v2IO(Ls29Az+(75=EB0F$~&f4TpD8gC;>1l8#TyV)%-T;^XC`@a{{gJy- za8alt!Hv6IswKyvt}dqNS<8AXAi;%cK^Odp9Xm@d*VH+Ti4X>bLC#3x ze27;;ZRvd4#)iAPm2;?;&Ln@+bTT$*;)sYxtPPqiPhoCgl??WVv`Q+B0n-KpSrVj` zMCEeoXTKsT{pNSQ7^jg>zG)``mzAeswwj41|3a^Po(>)7zDoKUhbwnQxzjL5QS$Q^DSMEt7QE+gb*9Jy=`1kaXb#8tibK7 zEa&#h3fw+r2}aTl#*`>--?z;;NS&}Xb&a{cN{;Ewn!X)dC8g`eRdS8OY9TTjVP`{o7xGc`WDK%UeEmFNaFDFrClSx`0AAZ>NJB1Z?@hjS9zN zH2=l#eu`q!dzk?5*Ejvgkz)83UJ!JYm(amVgd<*u8w!puCA#x$Ii=K}?})H@Y^| zQy7z?hg!bgS)aA*pWYRTdFtU#){TOboHjCd+5ofoj{Foq|LHe5kaS7DPv|Kp!g+rS z-IS{cp$%gZ5V=Au(?eV(C>IvLq0#QZ&H8_M1Uk})T&ccmV3*DIsdexKW>8y9Z7lHU z&#$_)xm<1^Z3_usu?fHI;3xp$M-@0#=*U-o^)DZ~|4r}u#3L`2DVe50!^kzTe0-II zbR`X9clBob?^hK(6Stl_F7*T#$6wR}5h$98K)%A@Dw#HRAEIc6{bS&4E_-u4aq%lW zQI)72N~j%mEMC59tx~%TSeD_EMGmzD61)U@AxdpSC~u9Q2eKb?XUYq z*V<%^*Rd)Xqjw-L3))mP#Y_NRxrrO!851q)%Xz$kHeVq+TtW3zzm+kUsbs?NX_-P?l z6eOhRaUW0n`F&JH`}ccYznx`yoK;1dR7{{4Q#+q&q;~UC*N;20SHAEUZ~O9zFRcFU z|DhPeDMvJ3%K@I1*YQnZ*9~i?IV^ZSfA)<|(KuGiM!=s)&B6w*o;drGOv%rOl0|fC z{-b9vD>z=Uf)CyLj;|cQ;e#JIX>P6Oc)>Hm3pT{}IcBhy8T?gVF@w=1cJG1m{=b23 zl#}I`Zqx7c&h|d@xR4>Z)z>oT0W?#w0rJI|#}>8I-eq1}I&DcS(=C%?gx-cS)?Lzc zjyNxW>Ax5wtt}_-c)jsFakkH%{KI#A;-0(j{RP_yPPaBH^6|e^~T?Q_*?J#e}8-W zoV4?dNjn>%`y7K?%ix~Hv+8|f4z5GI{mAjx{mwgo>plPDxmop$&8m&ieQs8*omJ0b zar}3xS@o_{?|Jg?zwwb%$FDy(t)8)IwIROG&8xNZ>RG&6-CfPA8{c>0k6!!Q8xH@A zbJOY>n^qg4``oNrJFA|>tJM>gX7wxY`p`pPd(*Fe=F8`dN98j%tv1B>xp}pAUVXDw z-TAY|cy#aGG8#>nziPkR{%aYJv?EgZhQnTMCI-Vh`!%*BB9l2K_E-BO7_8I&NM%gY zMg&H8ZA4hCHcpNF_5HzYgky({+@12fak6$+zWDdweb3=9Kl;Y|Y_fKe-KZnG(OWCK zk?l%gGLo&T+KzF9RY+!EW&%4oE#ia_FN&9^mi8m;%*htHo=8#bls)akbjq9m$Y7IS zXWWPBU{`04%{L-CX(OUDI+ymdB>^^YA_6ks9|0JG=e)~JSs-9A$(|s4@U_jMNr%Pv zMiNM1QXm1cK>FqfZLe+=q_{O?qhcFEBlfd*ud$!KapE*2_vf#riE^rZ$bNgz9LWu< zZMbzUmP1D4DTs~|nbK2|FJH%$Uh0AL>?ESIJY{Sc;D((Fdc}?TmEpg8y4qf?2Lbi(P2$yg4 z*~zZB=hYRd5p75XM%Xr_ws$krZVUq-U4wz66$b9T>D}La;4MeL_$JfnHbjA7!+}^d zK2Y2*4X51Sxa87lo`X8wisbichnwpLDxB=)MbnR@7d8rTvMy@AxDjd`8xb!?{4l3Y z(Sz+=UOjAD49sr%nKjt>USvYumEZZ+pMB`gC;sC*w@VHmL&jT1c~D!EK4GD@Gg?E# z6}Hi@8};g_*q>0rMZYyv*zD&Jk5kE`8=#^YaB5USS*Cw|XEfRG*KUqZJ&UEfzl&p( zuYBUJZ+-q3AN}|ve{)W%8)XkaNcVsZ@tvRZ4}j~8`UiX_%bVO@Tz=>C_a15t^6=Zt z_v>GQ2i0{$F05|wtWeBwB0FmFv%7Fw^Rh~NQXk_;RQM4Mf7gXLPgt$Zf{EV$Puk@l zv~_7wNS4zO0vU{Go+)yuLGDNmxaZ)oiHF9@^~5sLrNUf>@oJu|Eb9{qf(;^~cJpKQ}%++8=vYe-0@Fhpw^ygyhroC)9ZM{kh3n&P)H@Tz{;r z`t$a&{@A#wIF`853rHJ*8Y-a6_(mZ8 zi}64{k7$SZ)(}1!|GtcO{QF*SF1I>rLa9DWH9yxaIB_-~5yy0Lpq$9M77W z-4wbT05LwSg3IHPNADwfqW@kqY6$){NvNG!|1P{Ig*Lp1XlfsUU!^wpzkwqr z$rm(*+lG+J*`=Z>&tR3NfujGBcd87p%lTfJt2`m!uY`+*zE*|4)p+uK>Vf&T1iqY0 zy5^!|=+RmncDqV;TE~LarefF@3|RktK3dd{yw)G$H40dr7dH0mUO1Ar40H@!#pwz- z3z3%53y&eJ{J_Q=W%3;u<+T&lQId3mKmGm@5P$<*zZ5 z8zG`6Yc=du4YHT$H@LMEMT$E51D$~LN(rB&N(rCfQA;@6Mv1+g%~!=A)vdV}db(YH zOdh+(vV6b)E7}(}_7Ah!PP5r;WO)m0mWM~NRWvVb95ze|!$$~}-YnmfRhT+#DetPK z9I}*~s}$krjo=7`H#yy)u-F^7A`u@dBzOw3u}4}Wl@rAxi+XFMVo8$hzD|op$c- z^hT&PlH9m^RN>v@w~j{Z9BFI1M%sEEBYDGtQX5}u5Z*^)_hy}MAmPD=5apkN$JBYH z8>LenogPUC2Smru4sdeCDk+*5F_4#KFB3}CzUWU_ydvP3OErI%V+~;Grc4OZ)bmzt zm{R3RwnnYnBgxh#$u&^k4MFMjjCbUu!AaeMe0zeeRJzsaJxY}--8$|Vi0QR4rCZs{ zF3WC#IFx$DrOlJp2Sz&6NJEIstXIWZr1Oj#>9VbmNsfo}odngd^AGUNC5CfH=}_VF zl><#%C>oKJVGnZVLJrI0(V|tQJcycT`vHOJy1%AEbJHCnb~UZXVE|O4a;Roo$f=F7 za%h|&{`QTX0+s>Hy88q(^DzBY*H7}y;0DwZrrJ3n-^Qq7o<}p>?Gv~p;i}_IaugG; z+Vg-jMl3U`Kc88bkW&bzbYG3-Gkh`lvAr{F>COg$cO38_H9a2Yu^=M#c4PMnQ5~;7 zd~S+vW(8knym>xFcwS7=pO;c(Xe-FDKcU%Mb{ST&M_6Z9Y?mMevL82!88yj4Lq9#x zm8laPiZwJ!7NmU~0k$;7TQaBAhI-iZavg06H7uO^gs7uoLDs!f_WDVTolWruA5u&E zY)tdPw6s5tX+A?N?UbeclSp|DT?>)MK%--&o=Azc>JAyZKW^kHTw2K+Nu2aYXjpxO zN-XDy6&E$vz`P|T)+#=l5+k6-8fCZtIbh>h&qMG0ob36GXnBhSnM?9Vj1H;#l3Y`e z3@GZ7TqJobO(GS5aNUk^6S?K#hyFkxIq{0JFUfCFy2$e>(&L8rdn$!phDpQ@i0j%zFR zi)qcaSy-E`hEA_F!>UVqHrvd}aOo0C+Zk6>9cSWwp?YUlWMwbC^Af}lg^X*8Vsl*@ zNH<>C$e=6ZlMM=)2aIkPQ@S?Q@`HKno(WQ?tf5r^8Mv(I33xvXG@3UNv@Psa4}D8(Cy_jmV=xyeEr`G%qG9E zu@CjyR1TZuc?o+*ZrA#t$;ltqfRtdUL0*puP;lcPQI@qyt?#KTS(>UqV0BYj;`p$V zk!fy?)Yw2kf0*`Se6VM_qe&5;`sr!HpKNTRN;jA8Xg(XQ^jH4mKE_}nDXM!x=MP^i zJ=tvL=+mu8Vw@mv22(>*Oe8QmZM8#LrrQtO8nyQAeqK6o%GOK+R@fEwD=r}+J&_%i zQn08rHAEJxUSU&;{_TnjT3-Kie6uu=EIC=e_faTvFai6eXvWBeQXIR^{+VrqOj3H0 z(j7{_HI#1a(l$1kbu`*;8YmPdV?z4mgw95@bB;`|D(#XXJO8b~ELr~sQ~z1~n59z| z*Fg~*WdxvgK0Bzmh~ct7{A*yhVGEUR3Kin(PG35Et@lV@@jcR4cozvfeMzK%*S7q` zc&q<_mS})&lsEiiEd?-n=i#&(o~X>|ETBqZ|_^J0k zf3l0c!L213zp_09tI1J6BgJl}nQs34o$uPlwZc2yib!i<~SUH$66VTiN$Sg0UVOIcFVSk*(D%59?Mk9|0*pxweu3Km`#E zvno^-2@DGlW?=m8+8X#Ed@Y`4u=mRU+;}lz8R(p-j<^E?VY0|C%kBfwLc={m_(%Wn zK6R>we8#f>F}xTwhQ%fM*BM`)7??})IM%#F5H!MbeNGqP z5-|jW#n*DGe7w8T zP`rQLv^iK%)ABH5Cd4T*)V+SgMemF9m=SSma2F7HOI02d%=4u2DsP+R$ue`iJH*-K zN```Qyp|v0ExdwJwVJuCM+LVQp*$sRJf-YR{(tPff0SL4zoR zvgP}p<)~y!E=iVTVVg#`R({x>&~f+5nw39TYqEOrN2cUq;^39ZTH~=RSRo4I0nsQ} z5YrSBCst3}gJ2w5Y2>65D@5Hf6A=U`Sq93Ep#?FZ9t`75OlLmdz0bM#zS1u{p-sqS z*`;^yIrpBs&p!Lt*=L`9lpEJt?fov{aS1}Uzq;c63tx$!4yS{02^z-JnxQd9HfC)> zHsU1LbIe?tZ!sD1Y$~qITYd-oQM;5ft%h2x$~>q4$*@n=mi|?UT`r~>352a=P!L6f z?9O`zYvw}H+er~MR&2dBIhb|ZuJ>t|cw3XRO>!@_-wagn-{$1c(7|Ux zgug6dm@s|)E4i$ZYCbhkXU{fnN%|(bz%BJYuMOg1SilLDV05_9UM=kCViPy}D{(WJ zD@+sVi!T45`er430PO`E=%}UuS0oUSiXG|XJ>L7u&uWN*sFIisH9jXZ(MzZNX`i=Q zS;<&#)LEG^6znMts{-d1Q~)Eq93CnwcqI50BEeIxb$lGo!K64p*7rUW2LjEq_02j7 zp*V{H?7HYwnTKp_SGLq39g+d-&-8v)G_LQ9ar5?nV{8<3WE2qtvk8FMduiQp0WmO( zwyZI!pcp*$bP<|TtK8H3vgddGs|G?cw44&K~2DQ`R6EE;Vjy}x!&lqh$& zi(0RWV`zMm$4GwY%XU6#V$f1SmKm$SGZu5x(+w&}M`IQE(Bi=^m~*!#$4rZCZfv_H z`BY#l9^{SQhXWK`Q{u2l1^t4Tb0%0*+#0aioK62Z*j$CR**4pAHuKAT)oiAkF&$Qb zPQVNmt9(Ug+89Ghcae>2H1JJRZD{Nlz^|Q{eTPz!T8?BhK4Aewkx3cF@ z5EYL8jJpak|CzfI8=9m)LYS`x1Z;doaGC*x{sWw!1stOcYxTq2#re%x@d56P0<7-i z+|kC_ri{@soyKAe-xR|WQ+aFhsDg=^D~m{+UXpL<6T`9K_G1&6OxWS6Vt+bM z%%1#g_x`*$du;9f_st&r$bUF(LKC`aifHb`z1z#%?^xgO&89*i$t=y>a?M=YAqWL1 zx(7#Qd->$BSl~dSXuTq3I}*K}QuKDBl$dy3qy)gh)xAH|ME#PWnzS(EM2y^hU4Sz! z)DV6eC4Qn5&6)L}F8;vTMD~}f3k`lSrle_nyy0L|7Z1zQ9a0wuv%0!?IJ=y>i1N~n z9El}Zy%mJ7%f`AWi-#6_jYu@)L2`j2A?Kv2V~59ji$Q9=0LO^E5RxcU8Lq{PR)oMA zDT`jRBEGLhMtjORDSH+&S01p{`bqk0vb{_$k89F3uryypB~m<3+jhwX-b7+`8Z^luzS*!C%L+M3CH4t+m>0qKUmoaiP$?#>>8*wIr9xQBpqT% zkYuT(m!ysjoYhGp*#O%e(?#+i1RK zqJigxA6b*?a`yU2B=z&6;#@LPu9t2!0LkVYBt2DlkZjg<&%{U+7pGTzUo(szp~BV{ z+?Ip-iuA{2VO6$7uIzxbi@*NcxAogFIp)F9KlspOf0g7x{|Xrw^MCS-{||Ns>`&#= z6Q8@1%5%Rk+P@N_2?`VA=M!SxysxNmBvPR`2Jg|( z90gB6G)8bEyajg&OH66s9M5ttU{fjrM@|HEiDtyXvk>31GWo-)uIOHV#`pwA=J;G# zN_!!*An@RoJIFB=X>h*UKA}A6eb#iKY%Bu*mzIH<+RI+u@49*Pt+eN!ZbALnyI0)^$rm2!eR%3 zPz7!QUD{rvci2e=K=($WDXt_U4-8g6XFDaurTGnMxL87trp1=3KwDr^d~NXw=s3Gt zeh*1${*mBi_8+D$whU5YnGoxEu<7`JTLrEyw(BSc6A68bZVc;6k-nFvC+3Q8*2>r1 znjBEi>1yv|W@9lv?Kp}*NOG^7HQfaNF~_fDrk#{(Z#MZC*7c_~RB|q5y}$AC(bIt- zekEmr$5on;W6ki-WTquYO2T5`z!GkP&JmU$IYoN(?ta!_;iLC=wl>qCL}$BZ#nJbZ zZ42kOyH(X3n9&*yujoQe_@_196~w)h+94qL?CyC@$6>?2KMLh=ta#QiqN=N5Y# zE)Rnh$H|76B?eXwf)|`kYS+#c&G$XA-1TH%(VBwHruznCrSqu+@#-)s6=NZe;EBpR z`4~TgkzmQUwkAC?vbW_#lgGbrA%6*OZ?#$+`L`_em$8mkMCl{XouIVo3rnS`+n7kD zXOrTWuevQs`DKaMyueyaF23+J_hu8M))rYnNWp4sAW86(*;1O@krtY0E9&tc(|m#_ z=!%t;--Kjos8ma~@~3D$nVD*UcGXx}Vj3qj>Ilc#Q@(W!6dn5E06V^vq7w1&UVt!r+4i&6> z+0Fd?$eruiJma)N|ILIMWJPj^qyf>ysUf*{EG+zFp^KydMkU!k=XDSkA)MNB%)$?c z2($T7{pdXvR#Zipfm{a@`-*F|T&oAjD4d7oT0NrmHz>M4LAxUGw$3C(2Gmh5rZ4Yl zA=<^D)J9BdAk^a%MLi6FY@M)>XZwn&^2?0qd0*}k31_vU1U=RdASds_ZbiHKa!G1jJ$#maSE z++xUG7*uPykB_9~YUrs}xg0vg`LY2T#Zj$*2l3G;<}vkX`)C9F@_Q_3Xr4RJl=ehH zQoO&3cI0=S06IFw)sv>UqJGR%EwweYkp8&nodv)niUqRPiz7HEJ{%~3_{RArRE0M( z03+39PjXRwDflD_LVyQvO^(vaG;R733xMAHvZV5Ou@xF7lXO$&5Nqp6U!NCSaIIzE zOM#&v%U1=2wOI#33TYS!7T+lQ3Wj^D1fIYpqJO-&R+z9BYc)eL#L2GRzuF zYtMWejhR*~iB5m@fm$`t2{Q77a2Z|N(&s#c^X-UZV2w$x}kpW6{`Wu`60 z2!`$F-^7iz#_pJO{wRt)J3a8Ofae0NCTBkk0+8syxUaPzLA57{xhh^(G(%dHf9 zngh%<259;6whCI)9yJVvMGqQ}+bJq}^NY<9kHBc&Uz-Os0v!SU?(DL=0#Xo{SYU$a z6+T}LQ%h`waMw2q>fMqz9(gGW=>542$DpKm<=wX56zperOGMQk9NIbXZeLw3<78z3 zeV~eW*LtspiXi{u8)X2GKh1ba;s58VSY!R)g%IjD66(>@>R$6P=ilaIh(cmGBKI}$ zd}J35pWJBuRrDkS!&iV~w}(o;0z?)^VbPO!Qx}3K39aNN=ehUu`w;W@7&&c`hms2>Jy-ZMPf<_poN4~BKt)p7A*@P1YZv<%2w-}?*S+c8soB;lq5ZF zF-9RZ!W%5w)(l5XC0a{lw|Mkz-c-_Z7~ScX0Fnt0>LZPP$FInwG459igy0IPZ+usx zxi)k9*ISu7)ivMcu5%gTlkF=M_StNWN&$lmsk-=Io@`CplVfYw^2pk?BWrmi1kY&^ zc@58VK1SNb51^?Zt*Q75>m&#Ui{2AiW-d^m-$`VL+y0 z)7C~gG@?f^Vhz>?aw0z69Rh?C5*!elp4!l`#B&iqCME!6VuH}Jp+0tF)7C}_h?+4# zXs`xICq7L+of<|Ih-MgJ)hf^kL1Y&Jq|*VAPG_Vu49Hk)+S(`qX;W-~C@RhEPSLQ= z!*FS1V&#qVEAecm_~eBmVCv+3Wqje z0KtJN-!fqZxd(X_<%<8(#-eur;HsM(y99t}2T1mO2oe00pAVuxZ!qGO3e5H$0Et8G z@<8HEyC9GYR(?K^{=5N+^XoeY@+g_GE{jQaPh1d4wj^8-lm5H`iO2jq2lDKz0rK2M zfMg-=fIXTG6wov2hvJ827l9(BQ{(v5~w(yi>A@3YPK*~SgC z8p}*hBFHBvM<#~_xhPEPEr{Jxkjtu;IxHzHP^3w3d)^H7`BIQ~q9Dhx4uU+`(!BY7 ziu|umk&IVmpmn&nuWu(V?M2 zdlIq7lWv&PaK$v{dqQi|&&nFV#7s}tb)o?2+ALgCJq>h;mw+zK_5698>>Vue7-oBk zmf`}_RFkudG7YU&vzm6Bp>DTF+QUPwPimGD2BsWp%?&lHDL)xN)HKbX2LPy{oYly6 zYeO9-7`%y%`8_ezK}J@?eTf;OhVMc%L=E?aW{Cd0S>x4ke+M(finlKTq)(>KpE8KI zF9f7NZ$MVO{T%@L-EE+S;jWCdOJLF`Q|Dt+M%sli>CgW?Ouhn;)dcJkKx#sDA)3?# z>_R~L^9E!!0sD4_8v${!@hYaUoT!bsI3J70to(eBg+Ffqva}f_Qvfgoq~Ie&&?!iP zYDvgiT*~;zCu^}Y!leHv2URjTo**dkLbu!P(e}99R=%x%VCzhwMJR;7xC`{sJbwPNCNGTa7u(&7=jF8xug@|P_(q2 zlF*wF{8WF#0N}g4cYuBUetx!r>ua#SEG8gB_v4C)J!3089vmdU8(*-NVtf$i?pk~h z(Ne?*=^Isi5a&VbdEtW?Xpav|LdSj|X|Iyfhz)e4VSv<- z7CC%k#HiW`IWnrV!FMU6)}@L}Cu38b-DKzc9_Au?O)!!LGk#A>3HnE74C~*kld@lU zHBwe29HKCn(Y_W;>_fgc$^^ZF*b&b`ujKN?E7&I`=E$NPZHbTQO@k7EM^Mmu-hv}d z*MwKcFPom?+0QJ_v(i)MqF{M?(b7|dC_>Z*Ys_iy17s3WWQpP^UYDea-wx!z{k0Qx zX1wf-LH^+D4f$I_P;eWi%U~z{B-=~8Zd#C7ffB|`fpo;agk%{1R0B(K&2bu5gAkZWJP(|0`dMpuYhtPq{RFq7s)0zw_DiO1uor?2Fk zRc_Jc3}u__85aE2VRQ-fE;ET*Yuh074+Na9~*~5^e~w7YTZ7AT!1g z8>klOS&R+jonGHx4cVsVXo+pg%%#bUV+|?T$6(N_BfSsBK$V=OVEd@&T(U$X2FyBo z4Wb)+v%RWcosWc&Nc;E*Sl(~^DS(wnNkHTPi%CXIg+8ivPM|Dfi6q|yb&L(t1|06o z*r1F(>I@)(77BsSHEiQbJ2I}w>i`AK14pU=$pA-I!Ld3bA%HU=GLje(<#8eiIOmR( zL}gHFIsZ2AudAneP@3#J_B2pk$=?m$CAWGU(}T{k9+= zxzK=pvTx_5Hkkyz^+ONd1!Km5c~+wpopXPHfv0mlZGhN#jLiTFUbH-9$YVR;I_@A7 zVpX(jhV`7Tcmj?oQ_&2ku)HxWqFLyQW-+{sRnyk z8Zmb5dxsjzfx7ru8u=tnYW|uqNQe0|ooxbC$`; znwEF&T#xQn zkgkAx<*QjLv%(4X0OHYR+^gg-Tes?kY%R-44y_G=k8s&h93WduNDj&O6asok--V?Q zz|!7m@Aqu1y}_*aCBGvxMpJwGNa@n-cX;v{AhYa>_WDU-4!m~Q1Yp?!3Nj(~PJ3uN z{pLM(Gw9n~b=e!Etr5*Ti9bH=J77;Xkxr-l`V@&DTwL?8PCM}rCvU>3#r8WeIqpq9 zOPo6DG0G+m=gQOdgHEyItsXI&*xv1<3m+oaU4lyM&J}At5)vi%mj_NLw-ItZY!cFb zzJios+QJbhGq}1XgU|itm*?5tp(W^9P;0LE{O>$HpFAYP^em9{KZ)6abhB7raw7Uo^0Q;0ycV}DRvzD0v#VI2Gkwi)W zUEGemY6RnmZ8)}pB_EK~F<~cK1H+dCir7o0-egEcI>gSXNrR%xKE{MaL$>3yqe&^b zChd*;F_q&RWbmlmpqa7(_R*pr@)c5K zsU@dFpeYf@G5wN*?@9emk%(NsD@m=vZ}A@l-*oZ=yY-gzRo-FRpgW7B-)8z+RNoT4 zwiH$D-~b0Z?{c2ooNe&{dSzQ=jW%x4i@YC6`K?Vx03!hIu#OH;NaK1J&+{)5_-_ zW*Mir<_@yhoh_+cLl`F-5LRuXp>IuRN5<<@jYn-mAH@shmU|bKD%I2Rp&S?3j8>d%thiOGj4AV4U&CiV3@UyYz;8HzDE|#i+~w%e#EMBPF)X z!0aH3mf4r~S+j%e`O?7b7_-<5RaxHIoE&6_2a2?#>zovBT*|uhcA^0am{()k@Uw1x zUvO*kWd;#6G0iYMGoyP+OIhE8 zt~5oeYq^ZN6Iqe=TZ()p4e70(h7|KDX{J`tbaFq?7Ee3!1lnyu;U^|rs+qsAZ+qsAZ+o>$r zPElI0;I*`1J7&Qyec3HoL-THslMz&!S$;|#=$?f)_+5015iHBh2 ztj4v}%9o5@!L?PFqYBLF?^nl#y7$Lm542*dtM=)YP@;jRNq=-)Y?7VW5&$khyQ2MMY1|1p9 zgH%pF|L#y*c^At}R*CkxpGAyt2vB=4Q8blg6ko{kru2A5gZ^@ST$;M~zwQT5#kV-U zb3#v%JCYmyS}Xkt*i$d6NmuFUVDSEF`9cIg->q2>-Ah^zmQgz`D(hh^s?67FJz%bb zI#fjGF`2ndM}RH@GbmmSpcnAWz6C6>cY7oNU8#%&QWlMgw6q#k{QFORDXNSNBf_>$ zZ%uMFq2b>aTfhS@EZuVfgk-Xu`V*k6M0~6boB-3QhKSNQ%X(kxvSp=b`V1G^<3YMbPD#`s+~EFLphE@q4l`*`%@x1~S_GWi+sGK3h>YaTkdTOP1Caq#v+EY8=G=Z8|3A}eA9|I7 z-eHyi8c|=1k@s?zm}k+D*+Sle%IpY2NMna}0DXl%#q}fHT@?0y(X46!7d#+<#>+*P z2%%~sCrNBMjO^Gx<_?pnZ2pJJ*~yAr>W{(0Cg=<+G$b^GDHF6hm`~L~%*yr}P%9Wd zadBs8xrFmfRvEwZWTvPbwvroeZ!y=v>cHRXemvU7yg|@2cW#0(evdbGyh)J;)cML1 z+2k_(O8|;3-!#0l{v>uu-0KHnDfL}YSQ_nNlfMak!PE z_!~Zoi|J)f61;$K>I?tr#QbvK6#erd{Fsr}chlndV}B}et2KP)FJH7}{ch=S+a}}a zb@#4a)-QMg$p7v+b!PQ2q&uli15t z1k&qyBVHNg5+I!Ish@RK9v9|oCRv!>yEwE|WR--Zuwjc72ver1WrGTGu(lLvA-$+W zFt5%N}(;e&T`pKXOd6~*LLSOWT0Uh25->A!K zrVv5t|NK~{`ARL0U?k{JX1CJeBXa&@a?bVs>=1f_%SD`xBRY1KynhNnYW4nHHLkEY z(TtTQ(^?~Pc!58B#CSwl!ugNP2{>1k68(*-uOsrj(8^s>(InS5t!1C!TB>=>DwJe< zuTrk^Xje(DIUR;2aga~8Uuj6a%A(TO_Zx_s5V5Hyv_~G4G4qJ?7;2uI2FJ`0YoqSj zf?Vj8+E9WJE&ezRjHoqYp^zmc1QhHod+U8Ai<}RSI>n8@-}{DHtbFy23Jk%#mdfOI zZ!m4>0Czi8+Kko?u|qn?$5{r_tpj2`BSfBOKoC&f;?TbR>z{B&pPm3D3g}5Ya z2wxqmdvAwD#~9;qPLRlVoKE01aq44A-l?cB7l}qfYY6YamXC3wS9zWhvskx~%{WyY zlODrWh;Pw(VVjlsjp#pD-kNQOyYa^c4Pj0gA08HLbR59LLlfD_pTFP;!O}%u5%Aw@ z!+aK+dp>f)&Kf7w2y7|Fvdqpu_J4mO9Y2&-c6K!xfeR!-a%B-xB725_qmr1la>Nw! z4bhph1a6X5gu~O=*!yFkQRPa(b73=Krb9?+323HC;64at3$&@tk>d1Y{8Npz^z2kn zIYs-wz~h2TB6Db_#L3H+c2KAP#92%^dE$!>uk|j@o-`q*izCGkS^OFo*}cGB=#&ui zVd#vOgt{Vwm=z9}-Af=D@oVx3*x6Lyf`-#rmA#jh7>*>?AscZ51u2j6jVAb8jxJE6 zxtUJ(vIL5D)Luh8Mb7|~*EC(ro8hQBW_@LlqP-}Gg-mlMLnC}y)pO*d_UU1K9e!-? z%SX%+1kc4NN44y$i*0*F%7DoxJi;U9*5<4}297d<_R9IAWiE{BnI4rxH{T>=F0FEq zDp6cHd8@1LXvj+K;_z5UB2dfurt!5f9Hh;xj=Z6=%MupjmchPgaMRdM2L3Pf=)}+v zF(9Lqd=ibH^nqKeaAa>}EtAE##7INOk(HzolWsC$w@*O$d+04c@sK~^-$_HRoJblP zd#fo)14&`^6=^h#35_&DRU{2JY4st(|!is6$QUP+t{(xktN-)Krc|5st<2twz?(*aBmo~Kqv@_ zAjw9N4xQKOks-Yt$41K6om<&Z7z58Tgpn@w>IkMAKO1pWG~Ne#5lwGhkJ;9^mpo@i zq@&Q|$Z&?#Ru#aIYHbzV2%Nk4Ahy`s_(4720UFFNpb)FZz5DuO4cLZ4nv;l56;2AT zr*@^~XX`e=V>p(YfsU0Y;)ax%`CxQ9!5+}pU@CQ#0we@&+bF$Fia67DTGX`LfocTa z;^!_=DOpg>@@olRNYS?T2JHZ zExmFZY+#cHPNti>VaED>!s?&?H*}#{MUv(fPp}L{LESee{uj~r`06cNFWTx zJq2)R0-S64k71N116zFVL#BmcOd?@^&K-b7E}#p!P)hOh{eMqn zLmIgTavf~cA_90B*d}sK6$YOoip67e)DwO7QeCm;#gyuT3yQXf#7h*r$e;iN*aSXC zsh(s$6~!U?xh4yFRP#7xV{@dS=16QQttq`O=*={MeEq2`KF85Wq;qGSuk11s^~7c(K*k+y=L){ zKe0M*+Jff6$y?wh#I~3VYfktY2@9BP`FQgnT~9Gqb{5tz)8X|?^^Lmw?$H@<($h&B z3&`GR_Lh8#%lYw|H3`qaxH%(vBg$KOs?|3rL9i#%bj^@f-|nY%?^*Tj9&3Y7P#fF`l^@m_NUiG4xH!26nJQ>MNT-}qu9(*~6=i~s(>UVdO@??VbKs@i1O zh7}{+2UVx)YNSU{kY<>+W~Ib??~s6VaVjMYui5a6cQoo6HOVsqpo|U_5Op5{o^N4) zX$cf&zQ_nZ+qj5vfNQvnNCYZLo2bl9pty60Z8+~6AY7QTu4mTKyf+HFrb)S0-LQ;O z&f-KMDa5pRrsvYS%MY5+taIT*2T5Z%_M1pDJ5)N2r;I9;aF4GrCu)Fa6;crn#6`gd zOlflsB7py8>hlv^1XgGX=*9N+LYx>(zZsuc=ox++N_Y;me8rVL16Z9SOmRCJYY z2pZ-FSPYvR>$JVdqI}H1V>gVJ^22%!EphgeC&gErCTlO z@kR`W0(G_2r&WI8GienR?QE7R--miI<|4%JoWquimD*$ZT}!^I{(XPqg9{eo*Jo$O=p;( z;Cu}DVY{pGwD3V@GbR+hM|}ZQrj7rn@ks`nFM)NT6b{DpB|O9&Z)0*x7&@`3eG{dk zoAWkVqicppGMnM8VT5Qz0#cRo3q->-mB2yIb8s6YlNIxdN#X3dk5}Lbka?o7O(GG3 zGNPFPnfxu_WNUJ@?LDX&Dw>>}*1T(X_7dYNjd`x2dN*8{XIy&X=u-P0HC(9NNS~DO|jg$;uLvG4D2OYVu z$YMGV(bkERQg|=dkZzcEYq1vk#yE;R4hlu59a|4^?H1i%f%fC7S&sK7RS4pb>QP=_ z&^@R>pkHu5uit?D{pEEH`$t$o2-D5U-9vK zxP>I%$qy897e9d@-VrZr^ziS-Pzqk+-Sq}8aWc(cNwO%l^|ou($YYUn5D5z zxomu{Fdd4ft0JZo_LQF*hTyTC(pH4E6<;(X0ILN%AQl0VJ%y>@MRgjMEkmZQjga?z zGR5Shng&u61b|!>f&b&!8V?=TR*yTXVZJ2uYnTJ?$6-Dw*1!BP!}_mrm@mrpVVGmc zt1-Q}@wGAi3*Ws=Z&U17&GZ-IcsB*iXmgH#73w!qMMVmiRKDL!9Df;hhvjs3cFFK8 zZ<{AUvn;V=Lwsxkz`5V)!n^-{i@&q*-NjloxOBXJA3hRcJ_-k zJG(-(Y1(75v(MI$eo0kphH=ofGTtjY`*E4c%WbMhRftU``?@sKF{)k`JXlrd^c&17 zO|;IN5#?)BxxbZW+9n*FpH&itOpXFPIm~&r^dvWg+~}IcQhqOM zU@Tah!wlzK&Y$-3o?$O<>#@A0`R$un?#ShKD46B0r?E4{Keu~7;nPx^8@u~UHk8e4 z)3|i1%8|ap3PK(4vbPrrtW`dM!3v9pRb27?Vpchc>b;;J283;4&@8Ta@i)IbPiKJW zYJHcP-U>6)65Fg#PwlDa|Bs72rNlC}>?SzKC&0W{V+^c@B43P@Gp2a-i4#n4{!#`Y z$AxofP(KA4_04_Y9DJ7E(@%<&u9{mCG}@LEo*h$Nn6D>;WNQM%_pqX1&#D(+{m>%4 z;Kk*=u*DY}CO!7TSJ^GkV;AVGR!kKAk-WuL5=)%s>G;bZNIO$dMM_$fEA3a;C6yd) z)Pu!I@m@Uil%N?6J{=NILOEIS&5tm{D+6Bra9Y{%ge-UGn;y%%3;(=BUb?Yk_ZeYQjbb(Wz}R_R28Wg77xwbfg7oLHBI7^? z%QSL8DCe7QvGRq@jdQTVF~+SpU>)ewwLWnn=5I9Wq6#q1A3&|U@t$KuWD43x%k$9H zRp>J!T$mV4mgl2`=rb9Ceh(0byJ-}MvO?PDrjX`hr+;2ZMa(~{NT|D3((h ze39&Bkm$u^bC95=Y!-c#^0t)CCQB<4Vo;2ehD0)naH3e&DxR$PKxQr4EQPNfMy&SA zN(qQ?6B#;6TpL{adJt1mYdIH`(g@`9r8M6Aa~UjRh>TdkmA#@rrchjP2UlK1d`Ho3 zIW;TUB2GI3UcRjEZ0X^djoFT&9yqDZX}CJQml5biAFOEX@Q1M_sI{U=yWFqv$=8CtdaH|tQkw8TXh|WYJyZSYL;Xx`V{$8?E54@$q0jpYDuylf+BP&U#*4oOnPaR zuK@w%O21+-P+>sfAC#!XR+#738GV21vVK%9dCB_y_9RMo%$D^4^QDX!R=Q-tq1=~N z0cGliNl-4L0btg^{81NG1uigeL**0jpNUhGIWrLSB zy=q3luxh!K_4SG<g&B9E zvPhf{LI1f{l*I6oG1juwmNUIJik z?{8!_tN1|HU*is4ZeFw1@=(?%pu+6uwNim=iz}2CcP(2co|xTpKbD75T6M{eJGioV z;B8!883yjEH|gLw1v(xVb}+4NZ_j|ZO3c1B#T|3~_52(pyT;Z0p1FUne~l@XwfzmI z5jOO-FK7c85L+q@hw@@22Fn`MHPVFAJ$GYFt(j9hu!864wZOwJ**~!;uF1zp-(d|A zfoBa*<}GOw1tFt=#uS(}7T?7b853x187h*0hHUW1^z*=v=PZu5H4k7BOF!4}{mHut zK^RQ(hS~Q`Y%M&jNa4F^Q&{gVNYD!Z$+|!VbF0c{qz+qX1Y%l4W~>| z&d*?|9A25AoS*B4%HbBQ2uORdai|B1oN+U_Q8%l&VR>b+MK>hIk{%mu)y+-ZEOIlW8!|<4yJv2&ojZwx z>3o}h-jLs_2FtJ-xRL4 zS5is%RevIag;#YcB3AfRuOdQ)M|CVBQutHfA_9dsb+3jv^-t&u*kd#eUqT)uXy_8| z@_;R&j*&8C33H5&;Yx^OM1(2uwi)H}T2XdGiLx6@lx-nZ1F(@;6+>r>8897b;kR9;6pKXLfH9JIcH za(=2|GxUnyug%AS?13MjGw6&PH}Exx-#E}1VI|i;M!%p7*m*4yrIAA&eaunFW6MH1&5h(fXFHb~B;dObWPnH~mm zDvIXffq%*a8VEjgkXFA?Uo^1;^McQwJ zrSYPHZqQ9Wp&b)Ev8VFdm8$Qbp*Sk4P%98jY|1{tefb@IpZgLBGyFw(0VuQmMSSHw z_K*lL+_zAalTvvg9L9xhr?@lzD=EdgQc4ANvLrV9d=#hl?Li_myCG(E4Eplh4Js{$~W3-cuc8oVVwGSYcegYi6?eQN7FHTQPW= z2p-JiY=0~_7LUe&x+{x4?_mnh&z%!v`IR|IkjC<>LO3oPqwTxUlGZ42vT$Gfymn3l z0j8iH#L${R9#sEivlUSN-^<$JG_73%#nF;=ZxjN-;8O=AT;yQ>~eZO9zX=Ad0 zWc6Hc#6)D9-f3_%;B+L@_IHQ$on!g+`>?i^7SaOYT^Y zYs{HB6W>)V4341s8h>ZvyBhP$P04-9cbcnlU-F%%e%zOQr{#Z(f*pkg9{BO%+V>fr zM%{kQa1PSJ7ImSbl}|xLj1@KPa$0YOqGSjUkv$1!8py=uryF}je+HB5RWw>MKb;y~ zCQL@@Sy@k~z({pZr$(zz8BZ&PbNM`-(nhUt4-eykvytMA3W2|VV8?NVAqqA#cfdSF zSSei@&o_bGv&P`h1Uq4Zl9z`{q}~raQ@14`uuu}k0;tj83T#!nA2u*!SJb&9R&vrihjBlauOs0X7hCdmjJnN_t0?-lE@akd+A~Eb zv9U5u*WTLK&Jd$rm09XrF|0=E-Ge zeM{zIC}MEE#<+YQeY=Treq;kx<>=c!<@^j=Ty0rgZO}NlDn5_vNN-|U;S$03Gyao5ESR) zrUV>RvT>5z(w|1a%SR3qAy(HKV4KJWnd%_bSo1#)-czuyUKR!tX!^Qr4sWKLP36w)hCVyGavh_i@)mk&&sKILP2AuFA5S zNGr=~Vy`R%of3^`H1Fpq5<7IwqxvMI~xTI36rIg#r7*YWYIB=Sb3cqdVY2(^Q$N;a7QEcX2OE{^5;kzI#YG@#)F zSxvlVrbWZo@YyCoNi;A5jhb>{rZA3$p!Oe12ex!3dQ`I%9VmBkvQVLQ=pzhgSJF6d z^(XbIID9kEj%N`Zg|IZAo5KB~uMRS+YZpzdz=CZ8OeqkkQxdV8;xkkB3|rbWY4v=3 z-(bS1F)Nzk_aIZyHQ18u3W79gtxU#&nKd_9OVv93PHU-JcXyQJGDl%U><|J(__F+P zYxuMp+kgq9#()Xq$8|{`qNken2GpuO61UtvxGvP<&9g;O#Nbu=fVO#pmR)b!sQQWn zZ#RNSuyOTSt@$G5-a)!v3gqk!R2-(_##q6< zy3??GIC2AUso@DhkZ2w|AqcrzDTwV#8PX^8LLy(xD*bF`D$37|Ohx(W@(N=pAl1iF zwln(N9MRCFVYI|3AttURRK_h>iv~#}zbecSHso>QfT_+5HIq6hU9y@-46g*)Y+^99 z4wT=Zr!Kho6J)^z!hLX)<4;BKl^h0xZB~RR<$4Es^YCuUDv;&l-INgVe#_c%M2s>+ z2Lo$mB8=uc1g}+^!f(ewnkB&4wt_i%d_F~S7Lc%xP0ETqcbSO<@;kfY*l_2uTF75 z>79xzi%0d_`&6)L&Ye){baD9e_0rS7rP58sEBcMk=9-LQ@-kOK=Z&KC%5^*z2~1Q% zHs;AQIu8qfVksX*cjA|IGC@Kem!=KNI(Z919hVlXQPxe1cfCz6wNc5%Jj53R8d`$ zf{|nkKr3}l*S8uR)Wu4B&=LjO#xqs6#p-EBdm(>Q>0N^q{pH!^DF zaJvJL^$h7niNh&LO~)AAZ7M)t@de!}$yzt8sMIUzoavn@NoV(pgbEjjU6fG#mO!;p zT^&|EO-Mjv5*+Zn);}$)3uce?K|Nr4E3*uzOzem`NX9IYd9e`FvXaS5?o~xnkq|zZ zX#A>iv)EwbF(qwB1Y-iY(b;FaN8PyVEHm!FrE6bl`AvN$+?sw=AH^QzlNt&>y38)D zBo;6M159s+myDZ_=^}%`2g|{eBOs2+_|TY)OOI7!GJb(E30A@Q(5Pr2=!B6B(k@tl)bf||@)aNWoCI`UJo9v2 zKyMMjZIM}b7~a1dWhzHY;#c{Y zkm2?_EyV=ot;nyyy-^VDlwV;!kbDK{0yYy2-M=C9gPs0nqnhCD4|s6{)MkCm`@Mgs z_zxON$(^2-^R0yjf}V+JG|Dh-*SeYL7!@v&;u|S7GqNg0pTB|98lu;l5o*DM45T;N z`|FUT6Vq2jcTT<;eqZJ&&xZj>;6RX2pAjU+f=zX<*Y87VpGlfF=GnYWl|kyJeg`r%XVoW>shD*K>dnW6K6eBe2B>Vw!dOPKSVhg?60VRga2K4Om0X_5W4=8P3bU+DR{f-6{t;m30Zw9pdrAVDd2)U4+ z%s1tlV$YeK!E$`Ri%6O@TTT;RU}m$_Gv6*Q`)5?^YR?>TMK)HOscTQd2^ug!22PBJ?2#3 zWC4t_c4X^8TwCVy>+H(sB@DjVL=CxVdvhLE0W46`@}0*dlX@Efu(2rOHUSuu7F#8D{@x9B61?laYq6W|`DB z^NuXs2xe(KwfGF*uic&)x)n|6I52+J1$7&>u_EA{bONUXoED5uS$VNvBYD!VO|dQd zwMqG7S*4y$Cwq1b!qcY1(WWtgnGG}?+aNfPV`eN@$0|Qc`EpIHa&bsLH)}g@AVBY| z3a=Jc%wo`Ei=P|T{fo~=RT0&EU4xUt0fFBR3VKorG_t6r;|BYzmV|2@+wnIncDV0^ znun}}`PiFeeTuE6MaR~g2e`3Ul2HHU2KazFXa;t^r2yM zZjbWujFme0St^JKKB3;Nj0_>epQcIFRM&DM^N1lz$hz1ceQA;PGGsyW8L2wU z_-YoM;kiZA4J`&(KJ@73vE?&;bJ>sy+c~L~7#8IpTL!B;E4&wgh|;_W-gysfInEh0 zxdoBG6!3E&!^Y2i+8;A%6lD$sEg7>sZd)?u_kT&_6b~hcN+P^an(ePq!XVd&Bn%yI zf-qJipr7JT*k*#2K%rSP%wO*|oKIth7?QO95K#O>zTCoHl;~ltMJwc`H^2hfrGZ4C zWxgIu`20inKski76#woca5S3<^FAjM>$&pGX3}A4J_+GT8t4qWS(|0Eoq=spl!+Qa zYY*n(XSFu(sNA-Z;o!i?9eskcP%&;>PcXmLp*Fa27{54~(z>do%IhrXeflMV7Y}eK zB**_wb14^mVG0$6HhwVmu#HSNE6vs-wP;U=4SEGMUrdP{g>D;;Pa@(5vEFdJ_u-gJ1eeoI3JBp2*2I`^TX14>6ZwYKOq>S zbl$Ho`nqc2(s?RKXVw)iBb|kUXT$vYj9EBDyl_4>!{5_+w>mNjQo*6cz$5wjwUPY` zJ2?8Pat18+`qD2v4SV&+b+Lo8&{)X0067m6a(NrF0zuots3YbvE4I3JHAy+q$W`Sa>q6dlYU0>G0P zbz$-CVxY@7bdVhuGeF8SKxBM)rd;cd%tT8mnQGJK389_op4VDmH8K6x(aw%M?p?drM9^1x+EPOaX<)n+_!HBIJOr8DX<4w%?WQBIL=oYH%un zWoXwZZ-LohC0jxw=?lpg*bsen5i?TzvGh_U?`f5=R_`d(gEV%SQeCl`4`dQ;I1-=V&ywd1wc>RQ{s zb<*NEUHS8Hxx0Aw?63aB{y}NhkV1i>6*iAH<~EAUNz4^-!1$hN!F4_Ws+5>?s9ToTMReu?nM|6ay zUPY?#>P)&gf z#>Mcf+~O|$c~rXgWFT%Sx8MtmVO_J07Hcah7RGE@IDA@nctLD2*Xx+KhtH@Er5GC5 z9gSZ>w1t2s+M=;AmM0joje~1w7h>dJ2;9HHzas3HB4NKQ67YSgEB$GQk#)Fab7NtO ztx5bI>tgqKN46<$NT=8UyuR4sW;)*JoE1ZrYP#GQesnX*jUh!h6Wkakbb|qIO$iIk zUWoaph~p{ub22$6F;n)?1j{fgYv{D{1$*xBM1P$>_XuStuh4UkPV}$z=Z;Wzg#K_C z>qK8iqtM=yl%2UoWydGjk!S5KQnu7q*~tlZ=h<`5s6Bh`^hBRuefJDy$ZMWknqXU+ zJ@*1-$ZX19oakTc&z+-e-pXE{=;!|2E0n#Q>bd=s{k}hUV3JX{vV)WTfj@VMva?q9 z$Rx`&_T2@_maOc^Bq4$J-Nz|o(m{JqPWG?&=Z;Z!%E}fe`)}~)PEdBz%AT3*Z}R6( zQMPDhXD0j8{@k;a9ka3*Ci|QHxwDk9a=|ywO|lwh-+hU)BUbjxWdBBgZXR-7u(AVF ztcBWh4^ej5$_`ESxB7F3DP!dW3R-FLS~p?vxVuvXV5Kn545j6on3qD?+bAuq6w(`; zb$L$2dU|TPYIIf^HceeL)6n+tO4%5)nmy)Y3QubAiTnyR&5gQ|oEFGpAhxsdFHBQT zq(IA$upOG8clLLLx@|--1di~BSsm#N6~NB6f@?iib8vKw!)cWM&g~vkVSEAM$?_Kz zvUN}DmsQ`>`lapw3D=+D8aB=PD<~tBbV+r{i8EGy@(L@za(DKkmuD|n`H_`Y&h+Z# z@ccO|KXZ+hW5(?l!>za_d&SC^+E#uw%U53BIKb~_*u=`O*_}NSo(IrBTgLn!+z;rW-W{FIl!0i#Sp27J!*OMkr_FZUrY&mOY! zMK7Ob(LFqW*vgN2`R3i(6k9hfw%yYu?$E|$9%eUZ24bPvn z^21)f6>mg%{l-zNUvz~A-!ZRGDd{s#Q@ z`OEpcmOnP~<=60cHGk{*yNW-yKNF8nVwrrcbSK&qZ#wY~|NpvtV)oPre}zmm>3#VX zn1(yB2@n69r!p1?T4bd$*Z&G43tI13Z-yUQItYri_lsH!mGoG!oy`)95(j$}SC6J1 zi^|lC(YGCnrRMhx*C1iMywt@(OvUn2Eqgig#-A@Ww3lN`czLO;y&RD_9%@R>ZNznC zEQm%~63_jddNbzcNGDh!#jmYVqb}_w1ruH@ex)pQMn};_jli2? z(BjHl6BETk)0MJ=>=}LiWAbM41bd48Eu1t{y}u5ndt%|Ld}Z%%KWvXG3I*GSr#Z^O z;84ijVdPwH65niSc98C$P5y=Ka5I;l`AOcD37Nc5GNRNuka%G6iiTUFg~d{dcU3Y6mMp^L;{j{z8)% zg5uL36%yg}h_i=?ShT~uckC#2sR#g#N>`~yiFiT#n27^i6jYT`_f zS4&M_yfiggHS3a4(Sc7q{l%n4MYc}R5h4$+xh28)mJtz`nLC;l#0*;0pCOpJ=CY)=b37rj@uGFYn4(8Cf+EwG_Jx#0qaIcAs45yz1aRD?Y47x5J zUgHma#%?z!pXuI`Jj^g@phRHU)I`p6@XQxKE@=X(m*hZEACIBG0R4P}Y>{m=Rf1y3V;)Q%Kr=pX8{oYclq*p0zO+*AuRtCCu_con@`^O_y!X`yc~Yu{hf4}J zRY;d(C!W+o3J-{KwbJL<@i#h%=e)BILNaPOmc>Iys6MksE>%(K$twbAa97;XV!VwJ zej1jseY6>e&MYH%<1M{ie^0AZXV#F1!=*$0eLf1ttrad0uED9uFPOgu42{gBI|igC zxwo%9x5Qh!`;pH!^Rc(kuMK2{%yhmfJ8rv>gL@NMt<}T0+kEc~j>Wgo*>PfNyA~8H z|Dq+o<*eIl)L$kPq(Gt_&KkibxYInCBSAPHu~AyqCC&7gcPFB`;Eh`MCGq4JD7($Q zOdU)?HW60_w91gz>ncZGIpw z4t??RT7UFB{qgczpHxntyu8*gmD4XTuk{VRB@0pxwcDMZLi6r-S3Ye{FVAwNgw1+Gnu+F=@paN?aO zMjuikg5?0edi`a+ju>6iFJe^Q!6lIsqjnZ4mWzivXtL1{@&^~TI1)~zgU^t!LJoK%Ig*f>>El&0ek{Voyxq8) zjl10lViLd(tPJ0)hR&?Fc+U`p1kUb%ElWprd(Ra61kHGsWGF11e73*i>y_(iFzZfM#ugrYr;E zwE^O?j9#q`y(-J-xy9-Od07T_EKo^lN3hy_%xH=`jk~hfkR%oYl~-ibid0MRi5DXTW*=_Hip4SEYkrkX7i)P>;6%(nIUMQF*VK~A;Yu&BsU?*M+E7cwifO6s>ujR+qwJ^Vb>zyBL;(l--lWue zpemd3@U2OybuU}TO^xi_yCJHhlz+@5li%LF|G^Wr-bH~;>D@P|T-@dtlGzj2tiRCY z_{i&^(|M3fUY696O$-5x_3|x|ITqlSc}Fbi?VwRS_>1zuG|ONkb8ihs{1x!x3nxjQ zD$rxyEsZ_Y0CI`|Em?&+&QB=pM{!`Qvl_F8cx3<>=GDeBF6D&RfUDZ4mVJl7@QMXf zoseAeXBk~`wLo=#8zu2yrE+tp64)>Vv{>Czd|f=!$eNAre<{-(u? zsG$qRr7cl@p|~{RDDdG(3@|yJ2z%@JGDt0sKWuFHMk2D9FwUR*DB&gdQVtiso1egh zw{yuva1S9uZU&5s1xFPw3@gQ5K%+Gd)PAm23M{$6&^L;&oAa+52K|DV7fmyt?S0-{ zEI!=A>pJ#m@RQf0zpmBu}r)--Xx10noF7SeEuL^dmnD5_t88@~j@6gHdU)}wN@wjD3ngPV~czW-k89GD8_{|W)xroj&b+UaJJ=^j47Mh zVnorzD5NOi4eWuRPz-28)A`0M_WA8}2+?JSb4W~(oW$*xEk-MCkgkyvf|Q8AVS)@= z_X+6|{h44B?Lz!&`tVQr-oH0b@xl6gLTAi#R&Z3Tm3- zU%=}AbOKk6lf+G?_elisL` zJs|m*?Vfbd3qk>P{D=@jbfBb?E@^c|DG9V~-UjE&Ih`J0mn-K;6z!MebC#T6qc`&2 zzS6^}1thpnO|%Ec_Oa^$e0S@@YaKcJy#?}plc&$xozRkiU#`#!fM2eX$IdUwNTy6O zYU~OvCHUpqxqcolubS)k!zBUDgK&AZRwn$}Yvzb$^2-g%3+9*C&Jnrfm-!q4OKI^9 zmKZSfivO42&HR3o-y4KHDW-fjcF97kIyQ%(C4QgHc$D9ztbdb!&t{~NZuMuz1LfSLQQa<4 zxz!0}dqpVQX?usB1JLtGWqZCuq_P9;HJ)$p?~tcw2WrI{&Tpbto1EAi2yooVqr84y5kWOfUH(ut@=UA7ajhEGW&TJt*u++2t}SbgmDoR44R(^%jM(@X*WJH+ z2wkghs(zg+f`N({whD6KC!~F)qUCR}Yr`r=RdIzXM!kY<30Bco#Z{_kdj#lWuV<0b>bq4v7A5svub&9@6RN*j6%$^; zvY@>k~>#qp)SEzoKDz5Mfe69B48ddaFvBoQi zdb5hPsu-wZtyd88W)llQeuPPe8HvgNtTQifA+w5JsB73|s+rNYx;gLSmu<7(qv;Gh0{x7or zt>V&`v;J+m|IMtgIj6P)WeS13BEAhS@+)Q%8a*I3yWQ%4FkfA-Uv2ezAIqKB{|P{a zkL&eSR;^i}l!45Ht;xT%{^aRQ`mWnj`szBJy6pzDUZd^+dDqlQ7Ju~K57z5$zb$2+ z&-_m{|D;~C=eBfPk@j5>$y&CZYmlim6%6Gc)fb8*S|@myT^`e=^%24JA|I8ZY=SCS z%7T(tmUOcDSpg+vxv^|Li^eio)raJBEzM=_&Od4d>AxLmp5G$vusd4OCMYFdKcRUM zt71aLnd~;Ga)mCB*(LgaCf%t*jDneTo32<(2o??(0U;~AjLubMJufqyhR4VnsaFk| zB`UYyit$9BZ`+;xp?+`QoqR>Vx9(2AtluBloqSQhdx%3!=?9&Bqq;KVUC}TvG7PS; zw#Sn#oeE&|F4L-Lv=yQZM4A#H4wWIpmH050G4qm{r=id*y=P^~p>SjZSw@<|Qi`La zev%55zKrS_KvG17QRzpr@PMqE+X`Et-MblzZ>EeCA} zv&I#>b*$q|@B{4%MpwSQTn-AR<;~iTjFR`1?>q9Fif4Z9OY=$3Vhf<77A1?{T%_a~ zP3kDYYS`DmiGge7I}tP(2Wkp?e5Y&S++t7e?xxG z%wV6Pf_y4IIQjsaMkc(zW61-j9_)97751IW@gHRRos5Tsp3dw|0hFJ#Sz*6BWC}1`<$*glJ}Gfgr8+&xt)D7K6mVz#ogkm z?c@(&;8nrq1MXmNrlDs0OFe1s=cwp?#R#4L5VyWtGzk-8{L7moaV7B;1#W>n=#xRA=(tFw)KRpmbhvL}UV|JtgTQSwaIRjD>=}(0*8(B=3+U z+aVD|2<6B=n|?8M9uiUAT|>H!tEs$It&2gUU?)$Shb=>SM(xD{}{q~iM@VNy0K`RVF)9dmUVaUo^WZ2=r(Bhz1mZN+T zjsjA8c&C?_?Th@$x{uVssCe^wwj;1o5#E)d>%7PZWZ~vJ${P77!VQ?h`+okZ-#@}v zKj7xyxNJZQwtwHJAq9N#l@Hul@kC&_1@O|+U<|mG+Cd#3@ zsF;SRqy;scGa3V1^tptXE^;@*Sy?T~B@sG`5;moJ!j$mVL8uED~j7}hy zN<+e|mmPNq#J>WoFU8r)BGX#YIb+nJR?|v(&j(C3U<0`vU`ykzkD8#W)-zmC5%T)G ze{y2JT*ofO2t=S`lw2y(&*fq&$_g!lx`?%hpx`L8xV+f~O4%r~X*BQ5ViT_KGd;mJ z>{Ft7B4Sb&Ue0OpcLU2xUNhdq0+tm+g-}(=8nN_I^#9TZ!0)tv=vf% z<(x62q%a&mz^2K!alIvInwyly+i2j~410>ftmwo2xVMvWfPECVV{!B+_#sK>*8Dcl z#2KY4*ct8b;C<2>_OZUOEpYeCQ=}*I+w)r#6s_f@9fDzJj$`iqx*yC4)*Z@wHpM)B z=Uji6wZg>Q%&@6^yYhVEcAtZWu@Uvo?mN){y9Cy*d^buKHv;|vduA6utds5FX&E^? z`n&Yw4d=IbqX5LS7)N}`p5m2DweH>p>j+a5gEzlTQy=d34e){JgxA|?lP=owoPY!Q zGg>QaVM$4W4cVfFQgidRPGb9+A_i-X-_FK0s456lf}> zvo2M9bNKGf`EG!c(%8;R+b!=uH@gZuH!|K+!k45*BSLN_NdmpzNpHcI$YRvbjohI# zYCx1GiQ(bF3O>esbSzC3>T!{V#Tg2cj|UoX9-yfpyFYAJ8VzFuobeWNKmc(5g=?>R<# z>dH=0LQ7tQ2Je|4VhZZ7Hx&RI) zApr!QC_&JPhco>dCmjISA*y~)e*x)c-2s+$S`dki>ESNcSO>ce81v)U0OmX1ZhXZD z1WpSs5u35v>Rh0Qy7|n$;=X(0h8-viTD4IzVn)k#bB1Mm{sZ|6+|(m{`4)8@0 zM?7zjnp6dSw?ipHwODYli!-h?U_#q%dDoAq%XdJjRJXw%4`j5vJ8wbq&`gf&2MkMe zVRA{O_^u?L)WF$;Mp_bdT>u+CMGi7U{z-!H><&G+gJ=%S5FQ%iTRaYfdseVfLUCT+S?IcQ*mPDL!bZa0u6NV%#uS`}i z7E6C*)?`U0%cesX3yf0`5yT)s1Ooyb5Iw;bJr*q((=Db=QzRm7hab!p zh>7Dgz>lw#M3lakBav*5=-%nMkD=N){R41@t?AFGOb(oz8Rw1rv)ulfD$<8udggn% z5+GBka#uvj#&d`BMn-%+JvZ!>wB<_zd?jF>+d+gHvRr`+~etQ`}-#n_Y_$AbLo}} ztdWpy#_eIR7YlbopmvW<=P{^HM+7E+!*o4qD3Z6Fofh3-rsB!!8sz49WgSX}PDwOR*MW z-6ITmq%H~I4pF)`TDpc1M(KgF6s5hv7878uoKDPekH?4Qr8s;aX+Zt>IvIc{`7pye zsR3d%fYN;b_c4XS2qXqP3?frJ17*`6&=W@>H*QCd3T2)3MEObF8bNp7kiDtww~P_= z`%T%QP=wwy@(?3K8VbIwOu|o(_A`Ls6rzgkXfne*B9d>-L%*n#=Ih^<|F>D^J(yX@ zU{_EL8!e8vM(x`mU+edt|27f2_i$ajds&_IhBDsq9Wh@qdRIE&VMmIanZ=CoMpj$E;U1<*te=+M>g0?yJ@2y&?1?5|w+M4`W+( zk|K1lx?>dOy@8V_it=S55^BSpM;S7te0Z0M@Ri?6r%Pzi&E*78qpa3%CT3yL4* z@+}rS`sLZ1Lvv^Z;R=Z}enKy7@PgU5Hf{LX>k+W5Wl<R)3j<-8?bRIAIsJs0jOuYHXaa zzo0@!d0kZj-c{X0*q_ob7UE6)hLjSQ%Il%M(AQWKHzVw3A%0fID&GWU!7qR=8z$_; zKN;w2h>pytPm|pM@tDSEM$op&;t2t!Ap|wsYDCT$j17X$^J%A>-#OxLN=N-n02vfH zBeV{Vm-J&INu)tk8DXT4^F&cnpU`iZkaK=*Lp-a}lUmiqS;+Yh>g`eMEsQP>(!5EA ziwwoQNpX-y%&I}sG|#j2hnzm@8bq+ZAUxRjiT@3Ks`>%C4EG~aEMej4Al)eU4SWN! zE~GH7qp}&30eIFhnwT0E2AoZ#@k|8kC`6BpCSq{H8mo&PN&t}d#yb zjlLg&xqv;tvFgCkhp{BdsDLQ<#!|6YWuW52;+cI01gCjTz zEzL#;fnzIsX}wtTMjjc9hmuKS!XJ4;X5KwnZVaIbK+IZ6e_bkB?1xxR6b^WP#paq2 zEw14O=_T79MMGwk;Fl1s-_;K2_$3!Fq83D}KJ9`OwVzDV&%5v4Th>%*YBW{(KT1Dq zdt0nk6gz&2oi{JSt^bp2@w6yEi#(NKS-93phVO?ASYD_Uw`5|Lj-2Y5^A z=j?-TDD@}IeS!TpB@57lr+kl<)E$2k%AbklPsj4?t>F}(!CQN#PLH$ssyp5dLuk51 zcbuQI4B|eo;pvFLJJpZroiWN;hxgy^Ldxm$&ZC$IeAC56HXR7rFKYNo}Z?2K- zU0Wz?SzUfVZPbHmG%4gO5VIavb&ldFo;ZJLqn7@u+Fr`)1mq7CkjgHsX5J9aCuY3h zr9qO_%vs%VlLd9BVq~f|ZRIwC<^vY^NL}^sbKkYeD7YCPh2k9TB^$YTFE! zg{_YiwXYiJ6=Z?1Pc-TNY<;_pWm!W5WwV&Pu8f|YVb{Nl!5NVGq^Hbbhz*8ld&F|H zN7x?3KvZ}%sqKyY)^cFRj##-)>oN%GSc33&&X!Xd$#7_CI~oVaRPQ&nA63nO@u3+u z!&{)2)ii3y9O>8-N$6-;*xqD>(&J{;5L>{?hFFEf+a07UvcIW^%uhxK%SbUkWkFm+ zdk7=Mx;N@c5|Qt6?Ree_kZftEEE}7ZKg+;Gcj^UuuWCaA6HF&Y0M~Wt+AXk-5x_K{ zP39(U2kxzo6LQXdMx`wbD3gfn7H-3IkffLmJ$}`!ZxH3%+IuY z?N)k5XMF;SmZsR20{z=x?;YX;%#uI`O3-T=Isp|0YR<3N%2`}4_dI{T)o8Pqa0L3v zK3mVspA8p|gIIlGEH(oWe8G|q>@34IG82EjdKHN&CVu2lBcnNOvxWCx74s35&~8e8 zngdxEP}~w$ePyc5z;B+e4H+ugYp9}qTKy4^Z1uFvaz`dArk%rM*|~|IPp7@<><^Ku zZCbZ)uYu6NCmK4`a>a}!-#63W4(v~DuqgCr!NUghZTmh&nU0M@URIm{!jL{Hyi^Fm z!TJ$Ov?b9_4k5;1pEf6o#W9|2k~gfCNwf8|&E=}vnl)>x4TRc$L=tbXD_j;+%-jvB z#G(XKQY4sq0LrDT#9G`U3RsJQ!f_hlM^<7Smz*1dk))kXa_BB~MaY<9)@rGB9}#hw z$N(eOcpb{b+q`$2d$(plkcAx#7$>Bu;%a3S1L&C7K+HXoV<5>4bUx|npy^|NEN^Hw z`TC=h35BTQ1!^q)4>2}lU&-znWMJxQY}YU*@J@-?AbI_(X4F(W{Wr#)y1%!PO!-j| z!uR?^ZT8Q`?Z0`VUUBwY?RatYfw&VG2wnyC&zhnTPupk|Hy|ee*>W$$P$gD1W$336 zM0qF3s53c3nG-AOHAr4X_u08er!ck7Dh*ynoc-|(&!k|^a5E`BCrp1C?h0NyGDebq ziKm{lPZeF9r``**LRD)t;;-J$IcR=J8mH)esy7+xnAirthO{_>u-fEb)Ba<12TbDq z@3FI=$!u_K-+KLPwV)jfYsJQF`luxk)Uxv4I~aK2om8<}@i)q1?!f>S&na)4!xRoV z?9Uw0?Wu9_=WWRfM+(8pZM3Ctm~LK#pm%+ixZFGkv@rm4vmfeMooC*Z&g6i zzy*Y(bi|iX<9@HiU!a<9xVk17yp9#-dccHBM?koC%rBdvL_bG`Z2Hu<-(CTqnw0#- zzF4C9`M=6L`}pVg@otb{1q9(-j_ir;05};wLR}(A3?p5HJ$DGK!evUE`x{3in0ZBL z0W>CMku%^M8Bi%?AeLcX@|x}vusJa*hU|GkbD`xig&gotO>UuE*Y;tvaP%6V6SaNP z4|G5uA>b3+aV`R z7-tmf=qD|NvO*s5C2_8;U1jM|=-|9ncXeil4?2o^bnWX9i1>N0XowgnG@b=?zc>?8 zkf!$q3Rx?hwr4^^VH>s^#cgi}>%6@X66zBYsGji{qkQ?aXrEeAH*3X>9f9<%a~Ntx z{y3$5#}Mfgn;Qp>z%|B0ZLY$)a?V)s_b`vPxO~lla6`QR+@XrbXsOwpBB=PFii|NQ z=}$Rs8Qa~iKcn&nL??U!x_ZlRX<9RvuJ|Th3@|DI5qdKIUA>2aeX=csGPd4;@d_5@bjR6lFt=EKC%2SObk7i3L%HSTFZt(5n)p`>Nu z-X)ZgpjG7EH`gv{#eP;2A9iZ4WodYV-!f=bltpT#Xl|HR><5kF?Cl847ES30W*{>W<&C7Qd%e26Qe9rIE-zM>oRu6up;dEu>7A z<#X1mRk&1La*}6!?L>L0HpOsiA@5PnbZsJ0Xxh$(-;MBlm1$D>X81iDemD44%kT5Y zki@|Z;$_k}V$?zV`6iLxG(nnhNRP}m6KFOlCZ*%>us8xCEZQ)wD+1dpOhsrh6^Q^y z!~K+tgTsHbiRsBsEvYw}t%*s=*ChBS{&d1G zIhK~VLo4lY$sup5(B;x(@u{N6rR55nD*9ZS<~dbN4~W-C49<2A5O9sQhOz8oZ9>g= zG2+1-KbC#QDh!&9BUzVZHJt&w#B2`C9A~maIScJ_7IYNax|WtL`dq2EARUd`dyOcN zycR!m$`)7yZNB5Z%)t&^%dBFGfMkyI;U40%n_Lfe`}a)iSPY19pM z_%&ogdLF}+nL>MxnQ_rI8x?4B;6XwUG~V~vc)76Fe7FzdDopP^|KJb+7T*H^7T?X0 z+!8K_Ab_?j2nanSMIoBk%F%QB1Bc(4hV`7(KvW#mL2X+L&>$a}X@)R4V5TwJJ&(V~ zLKGSp)_8#raNbX5NmHnY>Ysu7;SkJ%~jq28XV-d?L`uVh@x)lt6m;IZkZ z)_r(usd{Ux*ch$y%wPDRIa;Y$k>L25M z=-Bjx)1uJg47CC&O1TWAXa|>p6wPuONYPF%11Z|YrDkXNAI*RG*mV0#OX?CC&$Lp> zN9FnH8wHqd%9&wlJ zG_qyJ+MN~iLCJv|WIF@dA}_02FgpRiM@Qt36XxThcq96_ytd~xp#1D;xo_5{d~>w? zx!BIt(ee}KvQzufN*daaafd6_zjc3A3c?{ltM4g0f+r8VPB>6n?(pE z3w!CZm)`HC2;)|F#Y^Asr3XUkbk3O@jks9Hls|wfd|;#ic|%3bGreQ8nNHp$+@TSACs0y9+ZVVTrl1p-Vg_GC(I(C zW~&PM?Q~vl-qDJiG3iBI?;5C*G5xUeD1m_=&)q%PNx7Yo6cM4rNU=~1m>1I%Xni)D zmsm-k-*im)&~$t-wFKBocuXacfH@K^0d@onPwo_`@r!G?fhZ|c$nXU%x>4E?{Crjq}69b0b70IBXQ7$6R;V9;<6YZzE-{mQ@o zy`TJ^Y0{kd>u%g|QPL-n@w&uo0QG4Fj;0eMJDODLrBQRHbOBK_ezWh<4Q0 z*I-$T?#%6jmC$_}2`{_e?_zJ_(`n?vbXcl6iCf8*J*ZL<3B{-Xd=rHEvf@SkroS6x zG1qjrn~PCE=)0ajxMqHVru6thUODe&}Y{5rqta?{Q9FZJO^ zKQ3rg-Z5cMY2*NbZ?&ej>5)DiJ5o7XZ3^=lk?shhN8JmvAFKP4#B{6(=5QU%tiw@7 zBbE>|@HgZ#?@`?1vEd1H3`}b`s-k<)smCuUE zr&>ri_KDbI4!T`#EuzD2AHX-(>W|z$m~`wjc`e#zP1qqftniVpH6-vf*02BHzx1R3 z=i?v$m(M|lY_Wk(-c=bL@DFI@nigAx!ZkNpmsH=dN9Cqo4s!!ublembR(*9^px2Dc zBRIZDMG?0rnBj$TYU%m@8kDgn-y3UK7T%x?`q_Z~wVJd+8f_MgI7~>uLw%Ck;G0J39p(!$~2nR&A zn3<(=s|}&1k%ug|lr&z$I(7@lQ0V}2p#8M4-Y^Il;ro!#+#GZbhh&*_&pKmk z6c-MefrM!F8oFB0qm;w1Hr+IZPqwA5xDE=6iMCukgxmK7d)c%&v}U;7xQo~23+2^h zy56iwH4n>l<1Wr%EZw1bM+T0DmgKbbxkl(1qN#ZZOG_W&#c~ve%#CK0AbVA2ld}z6a~(wK^DcH(K9f?na=bPnp+oDAoB^kF21G zl?%5Wt1{pMgd}C$-NJIv+LWXpbMc1-v~Rt$F<7L|4zH(KiT|=Lx_mt`pQR?Qmj0S2 zsxN?;FJY%V;>&@@>q*H1km(fo8#%q6l}m?p7WuhW0E^+;J_(2$cWGW&&ya{HH*iOr zQC{GVR$Nq+n1A(db-#WDu{Mx7y`TQcu;CkRO}-VOlw@Ti!LkPh7^&PoN{?lN3eTU9 z&%NOydF24m@Pkx4K70w68gVsz^ouRSZT{u2F-9} zC%`10(q`)~b+e_>R5lO^x`XEM#C80{!QNbUIOXhY>Sb60x7&yNuCs@m>-k zG>r^yJFgo3b!MC46H6CnlNbJ0p@QfAOAi&Ozz$pY+rwoVsUjHnuiq^Sy9MKSJOY0pxkmr#g+bw7uFDxzg%J>Klc{U8e&6CUh&{xV(3O^Z#neIS3Kr&SvxV=-+-8y zr5#DU0&l%R(=VxD7710bdgbTDRZXtGkZDxg0p(#Xw1M- zalXidoKsz?PzTd>Q~Z#bY6_J(%e!fIE^!+}pY+dvpp;K7B+XoVMm7*GhxsF%Q5`|r z7~+pAoY=w}ug}66CFvr>6SE4gq`s#PHkRIN0Wf;#-1g5TjT+0#n#-=Aor87~8Ao8< zU+N*q=J|Up zFR!FAB7h4HI#8z_cC?g!+)lS@L@)63h`(}qn;7ii^19a!9!o!=x;|@?aEq3-NkW1- zWmd28(d+uD0AudDuIt~bG&H@JXJNUCHF?QdL0X9cE`lb@1E1#G2hX4vvX zH;dcHHBIC!5c6NW_+yE@y28z61TG0$`syRDjuGZ`5AJKA`S79O`Qg+sG%?#G)C{b14hAGQB+Hw#QMiw!f^bnMy$`;fF zCqC4xkl6@=5lJB~X7v|^s3HnNToDERiYTbuEp4Ja&p745OsY7_wfg&gxWjATOjvQ> z1&{TbQ9{RhOeJGTpU47G5<~QAc`}U{HY;M-bYe(S>st^*vk?$1Bl|$;IP;-vILHVw zJUUDZw;gsQTGg+f zM)vy^`PHOe7RlrYnwKJ#+arzZq}~w)b;hq_CJlXhN&dav(svUMM@Px=3>A=arlsGN zJi&3uA|cb3!L}34fIiGyTlgaN3~(teqpXlu5H~B@62dfHvUmccsKti4RL<4!j<8QE+3=@i%{*lDI5%8Ij{bfM!(?2Aa!CdK7ao+RSgPs#IT1tObhkr(~ z=x9D?yum1U83ZfqaOSUgUQ`Ua=YV(Eq{Z zW{BFV5w+-%TjsZx&DKUShd6w-ai7+kObvLoxx?E#cdR(`pqY0kwOgj6M1ix}Amfxb zvFsWCo2Vb5aXj)e?J5KX7Uwqfy!-Y+8@Wf_W7`TM0686zQLK`FNDs;xaT8i09V{69 z4EV%b?o(Ppj-Q)S%XLLIg%qJy(^9;>#3$TwYoqE|6c*x5PdP%lJD#%=l_NBccc3H7 z+aMT8LW!SHlF-SRBy?w%W%Po5M%0)eOfgDZgp8=7u2a;%+8`o9Wk0P@O@jC3ruDC4!%qTYdd zTF^8z*7%JjCW~kU9w^PIJ+$%JSeA?qYw48LMH96Nabhq7a&tqpsAY=`_mmjCK^EXm zuS-z30U%|HmzeRqqn&IP-KaBz;a9M+$SP?FDk+ztJqnTj)zWAfPsrw)P? zWj_bI!E;41;T;g>?k>)B4YSn-ZU=TZdC1N1{CUWxf;8CbA%ZQ8{++ zEZd@G=3zIHsp_bsN7*ravYa0FEb@_JiLSuk@GBA>sYa%Nx0XelRXIT)%haY7fCRwa zSZdQ5X55pVe$Kt$bQOX?pq6^uFo7ir8B8fX3Ja2yHGrkbC8hMG1g~iCE?NA{*JHFkh>I^5qg|YDt9T*1a-Yd&QUwc zK+kO1TJBQL-BX2b$Xz-CMX}taGkxv9)rf|2LzY6(9^iaGBv8L^?@x2g97~pyZJe3* zh`qHBLx;5Em(Zut@B4;RC>iibjFbt1lgy5j*d;9HS~*Xf6hVV_0~U3A!S-WmYg3b{ z<^kKBY=_poa-NcnLpe|9I5^GMmTET%z2h#&87QjArH4}s8Nm5$r#4$!99f@_T7^8Q zV8lGhg-FkKdcsrCPU%ng8r5YHP0@LfhgO>Q+u_$zI8$!FZ_g)|`DBRYV_T8do%SfR z%TQlqFPV~#M#_w~!X6$FxeYERgGosSed@;kFzm8FN`g9JCu-0?hM^>=eh&cP3aC4F z!iH@4waI)_teIWKdS`AlQD-?q6SLss^|fRl#X$jr)%W zmDO;VLZ;5ND=8OD9m|i%J0ZI*Kus=l3~)21Z-Nd<*x|$uCX}kv?N7JIt)7ofSRFGmUEvnucO^d3QN7ACkEFWd=4YF`)mGtNlv)2FI3oVS{&*2uG{L7SK9VL!|oge9B*+<2we~ZkPk6su^G#XQf?{R!v%jESL;w z<-}K3YKc&wr7Q~Ik1g_&9I6eNB`i^oK~w-oHnpU9iW6?*+e@13obxKxq)|exB+Rqw zqZUgiPB*NJdvGjtf1JD~BCC*B%akPY8ptzyiJ+{Yui-S75{dtVC3>bP33A$VTIXYk zF9{iYhM}srl1TeJl4*yVDHS9oIfvJGL~ookp%L}EG;)2W^2AAG9JVw{^EoQbn*An{ z7oBL2C~>au^DMn)(l5ji!`sqV5nc{OJj12v7mn8*&li;7tKnBj-%7q(tr4G=Ob0*+0I z1nv87X;FXiT@0?xnx{qnax+z)bd;lIov| zdgPYjXN6r=tq+OZXRUX@wAkO2v+qI7FzF{yp-H5(NHp0A^@eG!Rm4nD~y`0NVOGyb{?#;Sm*{Q#g>q@Y$lWIg&DUF^Q#0e4dMU4C{+QCP-632 zP32R~u(-ikoft2v9r9=^Rf_?3QqrDcBRS^uXQo>`{Fll|^?E?1MRECt?l$!|?tq%C zrT<)??fz!3-u!U$q1(8j&Q*ktX2|S=>H(5M?=TB5z%c-NlAaRK>qnT6=Id&i=N)Pm z?B*6(P#t~|2drxfA;y#S-ue+y6+fial!j(;nk<-SEK|WmFz_^sYf@s0ANhsfpdVE! zyHjbBG(G-O$xcYBu)lU1269E*3=&B%s2ZaMn*}>bi^mj$Wqm0g;a0A-aC^lsALeC6 zaqbdlCWw~k)=i~rupwD?LR~Mg_|I6)VzbHhX#zF~ak5;=4PAORDUvwFY*L`%dP82J zW^t;{X8(r)z2||tJZ;&dn#Bg?*MIDCEWg^a{7_*O$NcTO4x?5hFOX)>0N}Tmf1LN& z(L$fh3Ank3W1K9DgdJquEKXbmik8Nba7J`j=x@j=Mf&o$<;gOw0WLVLpFW!mC6yuv zlxFU|&JTL}@KuZa*SBkhvTRAg@SYwJFFJ56{V5B*^s+UTtwk4E91&$@oVk}pKIg79 zFN?fxxGeI!P-c>y&$|@0%b@2u%@Q~jI#o}9Ox+QZlDZP&EvnHhE;J35gfGIs-Y}xp z9|n~!G`B%jW_(*zt=|k)wdGVVjiTyiGoY%ilTlQChT0$bXo;J8nap-uvGtOnrboUq zG9^KH)`~Q=gZ0aPEo^${I;P@_@A66E?*%LwhZ-3e3kq8?n@1g|WiJmX z4B@&nEG^%c%S*Q6MADG%9aRjO^Qr2I_8%D%8A|7*V%I?R4*Qh+iMclOu0JWi;f_tK z4XvbdsK5KvrV8;tyj{+?5OxjOzhJM;Z< z`u{4b#s?z}TCDvU(x%Fzb6LNwL-k9tFG1rr`BfkJ%ZT_(Z_@wObDtF_t!J{DvENKf zK>eX#c?%D@UOeX&lHy@M?t})tQvDQ(GTAfMCyGA2$vb=;nab<%wEVXEU48v=`?|v7 z1n4yZ92HYD<8k7A7T6p427v0DrE#Heg-@A%nQ<0pLjTJzo>8YMMLO-?zm9g2p0|&Y zn9y_*`bb#7OVc89Y6eSeAPs91 zrdyN1E!LsOHCdGmBpiYPx??y+8QD_q>q68ez_YDS$&144N`xgnAKM=(&*U_*qnf=p zdZT+>iQB(v&}UGX{1C>3;SAxMGzuBueTqjqL|s@ug;t|GBCqUO|6PJ;28neqtKJ&$2~Xs(!dP~;($hWL~z zDQ6PNeNB28e`M$-*@S8hwDlf|PaYv)huKr|L5IAHWQx;t2`h%1A+Mr}2sABQR)C0^ z|0Uo{Q`L8&uG zJS=c7jAzaiJ+WU=xhWi4iEirdwex!iIL;*i4x<;XVeC5s$mRGnqbvo2JcKL#S=ZwL z6J&{x%X&PenU(Pud9din$s$?>dhask?-X83#re?CNqZYjRyc(JWK$j*?Dd%BWuk{% z%6Pxa$+}h0=ive;t-jt9F2;YNHL{nhh2X3bbfos$L3_;iWa+Hp2@=52L3?@&XVs!U zu4fFxy;78$-Z>eZRZwGhR*@NWPF9$3(4JZZd}Hk>xeZO3)5#9nTXb+NYA8$QI?Wc{ z>7-BR%M4JTUol!OERouws1n9U59;bS?`#5v7 zz*@={G*P4%vgf74X+8@Mo(1+3 zaQ}?D@5*@aE;)PxHmc(td7@Za^r90^;|r+M%;wz@H4hjkoEfK7jgBZl;f^T!DMwU2 zrlV$bazy#PXob=RaTggLJNnA*nXzY-8sm)>NVM_qUAU@5hx5syUWvJiZD zYs@_*OlHa15@03sNgOI;{;5SuM*UNehB5yX_%rICdNpX;tI-D3dHnc5jc~+IHujxs z7k&fo`20WPZ^<1ACGE}0*@-lIrdM>hH8RwYbKQ!f+;tL6Oss=GHX5N=W_e;J)mX~>~?i~JB`n27UkCz z?H%*-vmbS0&Fd8VHmik|JmT(8#5du=MmBYoCW$6a6yPGLNLs|AMQ3qaJ3K-hV;^dCyi z@bdJpT-ji=8_mPsaeAX8s#j-$g*lvv%g`9Y6L_7;u+;ko1FA{0l0fMjY}scgS0*ev z5aE5Lb{}h%rF?*nnQ!#3CG(<`)5mskPV;4e!Xc(I;4p!q^6?AfZ27IRFNSn8LU zMU$qw3NLPoS-b!WgIi#dV~`{WwsF|E%y}tQJ`?oX{6tuofK95C1xhix1PECvTTORU zTIQcAHG2~2K%Qe=(#Pm6l-`KaOayv*kG$vf93?heOn?77f~tP5=b5TQT?x-q*{X4IBIy)RC6=f&N|O&X?4bi;QGEHK6^$!gy}zkc8$4s-Fa zRPi(Oy!y&y6;BTK7_AN}{T}Ftai0$wpk?Vn*?LOWr#)_c(t5T`yqEfXej@8j7In(R zNYn3C7=oa^*&h(s#U8M}JaPy`#|BIK>ehccHdnw2d{1_oJrJn_FbA2@Hq0Vtp(VOx zGm0W%bh)5?DP5TifU60%@P0%q#6&os!WYnJz!GLro?GdUc5*yUSQV-S^Gfk-Ev6n( z^x|{nox*|0cOT4ugc`vljNiK=Gf_Mf9&Siiz|+c_#sr2X?8pG?Q3ju(9Bl)Y-!>n+o5Z=XzOy}{E0y>jJebw+~zY}nT1u3A=6~L zVf$_{ALO_W zh6OT7{FLe^Ss7H8%*j`&$F_4M1?H)jqf%psCyhpznu@gypL6)*$jmFhvvE#SNBn?SVl(mWqrzlbs*}feLLtuElm(ewV9S?7DlC z9!-QBe3W?P;-fqDs1+Wuw2)roBY3bhMQ?(&hLbivf>*bTMtB5_%_r&=;pqzN_8UOW zw`$=I2s!~$pIDw+!CnujLWNXJWs{-t2Lmxhn8@=Wo-Y|ww$K8>4YSVh(5u&l0QM1} zrsma#0E?yPosiQh6mglFCBR~OlWk5<&Dx7z!I^xe3;sA@pWNsrKmemoQN!{e zD;&5iLnM|tjE;4Qar1*Y{rDHM-QGGqrY`fL&*||?eFnQ*`57!QnnD}pd}c}=!8F>) zz};~fthJFrJz@NV1)85k9>OjP;nqHe84Z+=Mf2#Q)mSit&J+SGluuFUU`t2hYh9Ws z{vt{Fp^O?Gmu)F+`@^=S+Ov31n1jYY&$urVWfgBw-nPY)> z={a69>q}ckR*Gc5RI$2fy|M2KmnG@cE##4#Ik#WNd*OwEBYVCB1SLX%60$7$ZiD%3 zNno?x2BDT2PkBZ5H9jd_t`n!f_^?b$lr<42ft2^hKJ7aSfcIkX0T{@{s=<#Dq*F$0 z6Y#_9SzG9&VLH^zWW+838G$-1Xu2W-xG20^1o36jE%ydg!vWcWtM3Gea9slSV|xSW ztVy#cEU%Co)M6PnDNzY0`$U2M@rfXQVT47H6E()VDsvQs3*cbla%-%Glq9Nf((DOe zT5GHpHLLmMSYv@)dQ)p`Y-fu#c3!AOfVjxoZnwtHyEWG6$#&LQQJm5myD(ynT`*W- zO;nf7oQw1-Yipyj#$t#Cb7YNOtgNxL7_FQHXG4bR6>6N!u*23^Y#z{jkORTbX_G9i zQ$kZJN>;4U536ffLkM%x>WT_jT3sjAf;LIaxz%-!R$t2MN`JijKjtGfaAXzag4`%&AfVp>OI|F_syS*_zXO||?|HqEmq zeg(#L=}$K|Dx2o0$Ioj#F5X8fJQ#G4&bAR7$y0{JpkNgqvUi*&>0m-a-7Be0m>48 zzlL7| zVIr7zs`t>`x%jKBwYPE*V5 zXo&{|fGW$hM74SKb3o))wuG%j?JTKa1!Z#;fs1R+VN(q#xB_*ag|8xnHcVlilBxy`81P_Hxj*^?%R&%w64KtD!W`=!4!kDiUs;L=M@%fl`K8zG!^I$3B zEJlhk0eJ1kNHM2Wd2w^3m~asDb}q9VQyD z*il3?TeSRW3Tz2~UA8+jDP&2@LU>2^TJ|T!#g4A8uoHWaAKqgf8KIKez}K+WXfYA! z7RUo{DE1qb>gec;z|AlKer6Z|zrw{%B!CO&z6{$%SBzXhrZ01X2^yWjq+P;9nqi2! zrU{m+p_{jw@y^%reOZ6iRT^6w>~?wpwSB-8cfe?ld4T8e3~ewmfWf_jp;rhf>X5e~ z@Q=R$%bd`ZR872`5-(Ov;qc>gQE6 z<{=FPOqD_>BU)e_+P&)z5YR}*J9m zZ0ZpfwuN~f-j}uE>m!pc)FDyxE1Y>nlurxEI9Qw<{p@4ss?M>v>dI2{rsNf_aB%%_8P!3Gq}Sh=Z?V~Wp_Yf zroaQE#cXR~-N@hLLg_RzAT!F8`Gi42JTiwV_fF`UkXO)X#*2LjQP*f>=U#8b-9<4H+uRL?vAJ&l_>*xB0gdO%@IL^JjlqM|-mzC~B-niE+o zpycGHP{%DgQR-x|p_s(-{G+WUoosQe&ejqKLXM%zn1D;ShW30DKmZ$U@q1-}m@ffA zvW1Z$=@6vQ))qiiZ;gX*7!crO0EGA&_9}%dlBh!Airj@Q*AOqq!2!oJkl_oVXKT3P z>$3f3p|cuyn${ed1xQ$jDCaS1Dl!W^*L5g#z9ODB#4MP5ZK=#xN6PVDOE=}GJ5r7U zrFbBI`mtQQ$=rMo`9+-K4g%6H-o$=JT`O$!Eo=tV^ zy4nz&^t}iu!AISR01{l(*9aKFgKdVPK}#)Zz2WVSxW8!oWgPWJl5d5mxK#5Sg*bvR~X{Re{m` zmUTE@BFpip-B!t0M(wsn1qgtX#e0rrASrDs*m8#u_f9?!U4xGU14Y+rYD)xObbu`Y zsSyNLm<2#J(@=@nK%7&E1o$|A-VT^6-_8gEn|(q4r#m4|OJ+q@FND`(g{r)yYobBa zpker4uKB3VaK<$=X)`=9!!h0086N8Xf=|=3qj8wYfX2ZtPHcFnysJdsVU%472)*RT z($FY@RbdK6m2k3P54i)Nax>+|ZNGQ&f{_mL0xOg0nAu(n1g4I7j}WX7X&KVcKO`^{ za+3Z;*uyp)q8kZ14NQ%M=-#2vnp|?JF9u}NnW?5YL zDarkcPn7H5ocZ=1!5B*-?C~Fhk-0Qnb15xK=7r}@`sA%cb-Q{Gj`%V{b?-o>ys2?G zwzI`J+yyM7{}`*%R^&U}RNR%AAXgUl+g%J>o!Mzt9d3BALl2N0P2Ww$EGC>;Ory98 zK{58~ojx}T++BooxK@NBlBI~lSznoAh?STiyj`)8s^~@vOe?&ixH4caOYtfO6SVSs z`ev%5TsD(@MIY!`VsI0Gv~U-2qr%B}gpn}oxT{J#mj7YCjFZ(IWT?(ks!Z%cpO&pl z#^#A*(9CEtkXS0o-lW>nzbn(9)F3c*S%|gUKQ8mvZWSt0T}Gi}#lsEB@fOC5N@-Im zSw=n*+oBWXe2z;*@1rK43es4kyRMaOlFXt;Gv%XU=vhbO*sXEY8N={6=&QzowDJna zfmc0baxf8~!$5}mubisG{nr+TTlAl>@p)+{^N30OV5im(OfhTRn>UGz7KvoQ^UzU7 zU8-pFz}f&_K94T@SRd6ao|$IvqZ~>%3-w`vN?0ss8(ST?%<)1bkhoQM0)Rt3tg1VB zXVmg7t!>ouO&s}{+O>^(Dmv%pj$7oNOe?SKN)IT<2y6pQKz-qf?TaWKTnIohY z+VgU75ky1#QkF&Y3@)K$ zVlaR*pudarV>sVb70~}wUsOa9Z{yA)EyfXNQJM1up+M$H3nZ7wHtG_Vv2x5MtPWr5 zZx=}ZT1IJ6&0NUh`&yAoWkt2HBC}JR?h~j%1E=~V4B_`=f3U+PmYJe1i{rH2(~mpv z%ceQl3|cuJeLgImFf0^Ih=#|Y>vd5cH^}sDsn5{r4yx?%GjcKD+)%VX3HhR_32x$- zSOu5DC6>WuUYUm%%;V7qQ|6gC(~l)+&0}LktAz1k1uT_?C2m(LS#z1&eU+|2VygXh zHtS;bpdEZS);%sKiNBIb6n0dy*Qw%N@PEP`B`T0~mN4LeZqerGX4au8==$^S<-EO21|3qaS!m&d zWD`PDS*8-HsJ!S_Z=SS$;v;Vo%=B`;d2#ET7jF6HKpBtJM+9_Yny@#(2w?ucry|ov zZJ<#^s??i2C)3j|=&k_YmY6CF}YU8Y-p(fA& zxuuA}DA}G-M=;a`6}9kQ>#A%1s%<7l2e z#<~X=Q6A-d@Ye?eiAXGzY<**+c`r~Nyo+PM35yh}&{YiQ!eK)=Fi02&;1yO%zjC{2 zfN^A5Ky=CYd3`qY)pyaa(5^M;AJrFdmnhVw;hj>??#tRAz=5njB2>zSbAVNZI%45x z_+ItWqJ=x+#B;jjS;;mmrdLxb29gZvmgssrDTR#;m!b`lAWwY>rDS~2)kd?(gOQTB zY=tDbj+RIV#JQItrNO4`xLB2mN9_a*hwKIh)eAS(76{=HAqZ@cPZUA(gp8(y=G)c? zQt*VW5h56taBR$?7$AV}nI4+e2PnRYRXdI=SQ z>t0*whGP-w0tKv)uI)(2&j`|`!$_BgZwluSeZe_c!3fqhKY+Euu#PojIG3^0H|b5n zjH6ox7H>jy#3DI!z%3!^5N@dyi-LSj6&_lfwiyFnZ)iq71kdEqS5`0EnzG|y{Yg-S zb8@k&9;{#N7eD%Wu8QBQQFxJNpZ_2{EeI3c=E-(R$TssnpzBv1&=a~k>ml{ zJV~#9$HoSq#iHIHETAh=n4_v<9x#^@xUO?{QNFa{2ZF8ho-hmIKh+8`KhR#S2=g2@ z{E7)}=_=6|&~tzX!{r!|p4#QekDl$Wmcp&u$0?RMo$0WR5$a5DND`rEW>$C{a|8gq z>5zbrd<+q+n#Ims0V(+~OAZRa-(pG3%MYW(A+R>9+ z&ROsT7GO=Opg8x`k8EHhw&h=c#2@7w2a zqS+Cb+Dy;294EG84O=g}Vx&_6=Mjh6%kVPslBG|RpbSepUc)5Mk&h+@{Das zJR`rA5K{ZxF~uCLKP?&!#@MD6BzW^qanEvPW<+jDh2_@|>*dSBEGCh^pi=rt`GrN- zguo}X3yoj3DWh1fEfRu$o9DNH{;kI=+lPh8U!q~RnP~$Ny_7lZPz~|c zlodkAiE%XChTixn+@7(0Peu}k_s_uz(?2T7Qg84Y#AXfllu-f20KTf=jdK`@knhgo zdmC}nFr$J7Ok?^ zR?!9xkC1R8*kn^xrb&wn1e*aIOFYXfj3i$YOS08=f0UnX*YjW1*!JAYUK7v*P2DG1 z7>!fnaSYn}rsP`1Ghj#2fO~_*^e1IX9+3RY!cxuO%FdgMKTv-tA1KS~wLiI%Je0rw zL72epq^bMJpVuE6G&IwU1Gj6AJE9tE9wEw(pMIpg|;6Co}<#?DY?3 zg9o!_?EL!1Z~n+hj__?5J!`CQe&jE{MM_%hJylm^9}W7Aav>0j^$s#4XjY)~a>N%{ zLCEb(X9&K22hnY3`Tz+PxXOi?o>Ja7COat}ft#H0w1g~WV=lW!O2}0Z+#}8pa7P^K| z29l{SH;adVQrT?&<97yG16zU-X$c|C^iLIbke)TX3t5^(S%?1#J1_L}`gFYmI)o9k zgIMvLeBGoMC4nH&OD4~(&H29MCeo$}>kP1+NWTEYfR+}v@0u{`h0*nFJq7~WLgp2b z_~#-Cy22)2CZ89bU~zG|l25Ge=SaXOdWfqf>%1eMVgb+#Y*5R2^SE{)7y(dcwNiwx zz|k|2p?rBZEb~}^teYPftYV};imFVuLR4m+v1#9f%&M11s`)5s3Eg8N{WCjEJhWSl zSl$a|*XfMlUWH^0vhu&0NM;OpJ0v?hgk;D)#(HWRoa298_&*$RvJK`Lwgt>H?A&lH z9LKy(eQFf*L>emab8YAYO&5-#k&UBfd=T)?>odXih*4XnQdLHf4CAgNqV$M~;^7M6 zB+Z%ZL25iLx*-|E^JGSpblHOqbkrd{r~G@Pdo2C;LRGC7eVBdz> zXXE9cP!s@JOV6_5Cdvzta`9m;v(enilu6_nOGpclfyE@q5?%rTVFxf>uPL_l0`2io z^|JJ;b8^ADiR8jh4U+A29D@cGm9Jl~gn8$+^kHL?)V=6wbGUlKGw?%rV`_TdKxG@2 zU7qIlcS>1Daob`IMc^w&JB{49z@aDF%xijG5K6EFC>YdoFcagw7IHAxb@{xNV%qVn zwn_0E1KgT}nN}&^nu9q2B;;UjdRE&+DOTwS&^K%-p7pG@PYNz%KG?Xh%m#D;2V!?s zzaa zpJ52;cUsd5Dbvss`V=G=MS9g24mBk0q$-r{20-Zw;!65>=WTccje5#KLneP$z&VzH zzF**+2+C@ClK!B{5cT2)Yu_HEzxuH#>M@8L(0xU4)r)hJ))A}8!4`RkZk0X4naP?z z$KiI7J)oS6#5^W4jxm~RZ$q@ZqLrPBR(2~|sWUS+TgOD;_2uVU$BJM5cFfnFvwmap zgyw(%MaqBjkAEYUU+|pu=q=T&7pY?VxCrFb*%$@xL=jAGKMp3)F-&?!FgN}i2qrg1 zF!g&vE#qO)wd~7eM+^j$oVahxd&`syj-5a-d!q!Cr-0O9lv`L4{$CS`fa;4CFT$pY z%{upDVvse z0?8T|LGesW6Xr?D{Q;8rG!Fnxt{Kc{9N_9W;yb5!6qk6U_|}}WQ3W<1Q_jgA#gjZz zpl-g?9x3SeiB`VrP~(Os9?*cYlIR`Yy61EAS@?$T`NnP?x~hhCk95EpTizP&0P=eA zDpHapI&kGFePcn5zxSN2ok~nx%=h*;PI7_^T zi*)Etd9RPsopA3M!ofqQ=#d6=QauBesKN#F!9}?ipcvOkuaAi0qr!;LDf=+!7TJKE z&kA4k=lrE5|65I{2#BUrYp+jVZ1v|o!E)NVZo#cSVX5`q0uOweX07uU<{Br*rq}0Y zF0*FBOoRy-gF7007`u|XqtiuFk?snll_8V%$br-loC*w1QJXVoX>On`HN z%gPv=m$|@YWrp&q=K@y^&N!HMgNJo&6ly*c0Ees;#-!mngfwsmo_*ecCq_3&=%cM# z`c-Zwt+8r2{)XVIIx(~C@vL`M4H3Upsi?MWqF&k0R@0M~)4r~(VFv)h>cRS*{IG#= zP1Z2OQu+g}vyf^7ABZcU&YHu`sgsI;{+uVzGjM`~hI`WiF#+W{j(9lPim2tkIx{J3 zdhLn&;*hA*drQg~;mxcn%a(sipylg}+3ZLWeO%7cSfq(Ni7OCNtM)mmh7E%a_B_C@ z*+t87fn2pds3UANUvZYr6D~KR<0n&YJ0qA^f!zmJs{t4@UdNt;EwT+RX5|3P;kG(h zfyESO8iCrbXrJtgAbhRP=4@NO{Al^wVrEVI{^=DC#j>#OK9O$$Y%9L-hg##^DbW;d6Q*LJM8v$_QQKb2-DKCOzi=unNN0JMTi>e1NXVD zaG$+7+?ND*=78^^^DaB&mkjbtBamMbs@seL>?JKW`?B2t`ROnxy%5NJtqzqD0^3u30LEKe~z$zmu{EW*IWP|u3Wr@A8J>s|it1R(q%Mz=9Q?kTr_DW=l zy<{gbS%MQAKu8G$u;e{k#fJV?v0-`}v0?R95gUwe3=@>atUtohOl;T_i~cT%4GUYv zhK_RAZzDF?x+S+tB{u98o83DuHduC8@!pp$Hi%(-@nS>j{CXJf99a{A9Edn7_f6sc z%ESh1xfaBRC@CySU^97;CofZMSa=o02DR}e6B`yJ+P@O9A(PmUy`ET1coKaCgKJBM|5Kp4c3mOe;T}SCeyGFP60N_1KF}P zuVroI!}xU%*F3+_A{7z8PqYTB^&@rm77(D`49a6=%m6qwyis-WF}SWI#KZh_iU#>h z57ytJSM_qXtQZy@e3~t%-{p2h44eAGk=%ACdeelk%CyTX+CC@oZBJ4E5Cc?_7`lKU zr>$rOD(!IuJnoqJj)Y3>jKJzq(^0FolB7Z4^dw!FW(4yAk1=}~w3f2oI}uHnBqN&q zy{G6YbO*bEq)an~SgR6Mt5(fQp?0Dai}%+*C=o6^HMh zegUEE9(_^b67y7KS@(ZBp8kaeXPD<#7}w>jZ|f1-APH3^H@kfdvm_z*vYyCl!dDv~ zGD8aUX7yvtih)DQu7tnzq!7xDi?`~Ux?kFj&5%9Zdu-SyQMzzij&!)nJ*MIc#)72D zp3L85B}#f3Gd{@#mSVI+iZVB(h)@$A28$j()oPX`U^y_&B#T5vFSFnlU-XO*$VmHqQ?G+9EHGcsGW;&3|8rc>*PCoh0a*tpu(yi#23$td?H%Ndtf$B$1!V zW$isCEQ9p^`aPR4@0WF$2xmet4pIEt173oi-Db+@Jn6K_0WnA#ae_(xCko0I8IPB& z<+H5mIh{B_GAa(KDh z!WG2R8n)hFo@6&HUwhh4zGHjsq!XFVNpgx({^aBU3k`O%NvI6JPfTJJ=l8;-!|L(L z!HSPrqoegWUP*gav1P%gymCKC$?PI?V;msl> z9jutF1AO!yIp=4^Vs+0GL@@4Q!||Rp^|NBtevb_v<^w69cR@(%-AA97MaU=%qMr4c z^&7jb&oKKsz%%b65s7hOYDQ`*dPc97Lru!vP^=)lE(B2$=u5XuV7pqrziN3t5N&-R z1|`sNU-y>oF>HtE`VNsuE2#p=u37@QrPy;yo~Ois{#+F~Qa@68$(23)R^D(Hi!lD8 zjBk&Bmz6YG!uR4JF&UUlvk>)fFiFMOKvygxOsO2^niGPS>gZ$Qd%`K^f&FciSgH~` zRVPLtB2QR&8_Yy_oQS-ZjX+a}P%cU!o#GTHI7Tix(Dw%FgD%P=r=h44C)eulmz`V} z_iMeRrzCHs|ML6zTTIB5{R+hvTJu*R`<*DI1PRzObh-S3cRo7!ZX&_ZjO5`V@udml zq@Oj!M}36;vx>Pd^@?u}g0kd3$vVr+c`yB5mpg43&sbKZZ$uppB(Fl zzU(hepxvAQ*t?k>)8b+f2C9Yf?&4&)?1bm~v2~`d)<`{;J{owo7!Y$ZRPSW6zH$2Z zH-Ei0m?@q^8!Db+(G*xPk>%yrUgp1P?q~UrQwaw1VrNJ?rB#acDn-DN!Tq^IeRM}) zSpbU1jd$X^Z*p5-rXE z*`P0$N2+^W2%0p;ycO#Po$-toiGn<6XNvumVZB)qq8iD@Mv7>GEMBoFv?0~bm!Tl5 zxhP{Dy_}9ld?}|)_-#|>b2n0MVv5S$4Q~ieXw4NV@<2DLG6j&MVIkNs{6J+nYK5au zafx$WmnR7_&iqpG#+K^dK&)qmkg*FQrO#=z2wLk^{X$cTMmCca(a0w6J)>V7?N93$ z)$NjgNea5DU%1Yb`eg&qMg0=u{e*t^66%dEC5!Kix<^gCp*5pi&0_Vf z(~oc$PqC{P4|8Yx=}`c5bdNE?3u=)T2+OIT;v{0J>4Rw&Z$p&4UYtUe*h6*P)G;xT zMhxU8f-;@=(BAqGXF4d zkYqbhMx2Y(Q>K~2mlXd1zqPDaFhU6srE^zV)GN=fyG7+36Q1wkPsBPa19kRD9E

zdZ5i7p-ki%<_T?>^5A5UO8Dvf>Hi}_D5Hx8e8EytgD^l6wKh>gg=P9nNJ2w8I%96z z@GzK3#Jixg+tS}rG&ZD2sYJXsTCVN^m^CVab`;Dj5zL~kPF-&T>{TUT8UnVozzW=} zw*a?{rZR+V2W}41h`#hOa4RcU1rH6=b%s}c0{Yp?HWN^RADqC;?f@oYn~_*gz}BpN zToMX;7(antDoL!vUvtF}gtm^y`g^jS{>#uP&~BZ65_R7H!Iq|7g6_1fP-~Q1HGpLQ zru&Mo#&cV|Nf~jXu{s|zR+FIF%p;a&r?#Gbw-l6Mq3)1yj+s}ccRDP4wE_p;iHO!4 zU_=v$_{d`MNFpP3ZlA+M4AO3CjlsQ1>P`6pmRv`Q)NmO~vqNJeWwypsX(-a@FVh9| zkT5&Srw;_(GG|*E7Hrt5G9n|FXy2jRmay$YT;%q`o3K~5-HB{(uxW@nQK8uTj&S7y)u#9e{3+|=lx0&mJVk1P5;NpXHCA4Y(b(TkO||Fi`(2S z07Iq=&d&on(&rrNaAua7`ImK4)+*Z;`+L9M~1LS+-EH&~RA))B}wAf@)A*#{HYM>{G2lvT*EN0z#~` zQJ1^ppcgUBjW|4nE1efXB-DpEm&}gD>cz9L_GAMM4oR6B)8@~x?4UDHe_2&L;VAG~ zB|wlLg$7v}640tguu@9SYqz2>5eg_mIbGraN~BLrO$-Xho3eQ=kEK?n%VVik>A3A2 zo9106#C_=+VnRk6Bgy|M2K=TWb-?qJr|86zcWb#-qr0ys=Ez@cZEPy1kn ziKIvFbbOCZIZ;Fbp;iH*sfO7!3kTrgk=6Hoycv1J8-N+S zS^_HI+X`q7!>vxps)nUer(@~Rh!5PF4ow8?2?AgxR*0b{;Up}Iaq=Mpdw`RP<^~Ix zyEZ%|l8AW8D~KkEej?2Id*W^JAIsf#zKeNr3X7&vc3;T}A_Q4Sl+n*_0W?Z$*z>Jg z235URboF{>Jl1Xi^##lx>wz2tbV8~1=z>UvP%$w{BA>RTc-g8F-*ptbrjuWCl>a7? zq@*YMSu#3i!IE#!7vu3%xcah1OkEl) z?Jq9pq;7-K2=Va#Wh*Q#Afebud?n(17+rv}sXS`B?12u=>J55fm1cYXyYiml(xVkU zrB{GcpAt=l4C!a_?fG)-kKEc$8aX%2V8l1nBlSrjOR^PTHR>=P!Q(}BP?ljaHJBF! za-k^vi;0o9Vh{2kDQqSA*Jz9xRJIr^RaZHdh5*7iavZ=+l6Z0@<{GO-m%q`idC?elzT=Gzk<)c1Fhi0!V;jV zE;4(ZON<;tH7zwqIBt+}xKY}0;g3KJS;M&E6c)0kci{94TuY3KM%h+G*I5q4Ojx z@>>BQ%-)l-BwUTh-QZwq(Hs$TU#}mhO3aOIK;hOjS$-dva|}bFMdb&ug|K`SN0F{F zET4PxyZXiz*E1f+ll|I*GI0}(N1>A5z9=x0>;MoG(HUzkvghgs|XNQV_6PH0LReH zx^fB-fS0S0u~eEaCvJ^{0-;kR-qJfG_5*_1K|g|EdJF_=Q6UThz_hDjUo-&NYmMbS zVF&=AzZC#RF@qW;&C`c3H3%BBRSnt$B!QM9a3C`9S}C87$y|ex!ft1?z-{$-ew&Nj zw;}YMAM)_GB$n)xyxq$71$p~+okC*r_LHm{Ip!;Q8)F8l&4jGUgV*qT=39;pUYp%E z7(|v1EC(hR5111%npp;Hk=?4HdAnvQzdK@L=8KpWr`*G=$yR-zncaXDGeebHKCOv$ z428UnVCeAlq<{VC!Q&!U&Gf8pJ3YlOJg%+y^To;UU;|(JyMgLNR6ZcT?gV@_4uZL6 z5cJ>Hr>(Ja1Rd6xDGr8U3Jw4lP0pt|t*{{XdF;{13QM%Ylr?B zvX9Z}f#V|4W`pBqEC}SfoGTIf|2j{9<4b9qc{0({$)l!AQqyd9n{;zcUJfIaZa%?m ziE@|>U>sJa5mU~SsGKimuZ5giEfMA(EL^r6SI^{9j9vw)A4DFp7m%`_mLmp{OKuIB z;j3!Zi=k?8N+={UzR301dq(qR*1e|vi10^=Zg~$HW@Y$kJAekv z=MY`&tDz5&Vu|Xe;@d+TpN$0~HP)piaNRVyVoGYgfwy7cMb5QVKti_&V1aBl!y?8u zXp>|R_{}MjexKZeP*Fr0sX$6d%`nC4kYgl!#*;xzh!p{cJ)1};0`6NomMbm!VuAw0 z&u z6y3d`ErS5!uN--0&xCV&3vJns7S}U|LoAZC{$U-T8Lf6jo6+sGn#!$Y0DHwq|L* z3)+aOOG~gx`EGsMI%b=CS8V=Mh-28&|9BSsgo$){~TwQRnBu^9;8fjghO35-JHG3O1+siq+ zD6&_!;ARLWSV-IgjYp5|n51O%*bXJ17}dkUzA-)gcD@sF3A`V{B`{A%a5#=wgGWMDoCKvnfq(Z&Nb%;5H@gEgrQ6$;>fo3qrOK7c<9?81U%%7swu448C*} zeb2Xcn2sESzxDx%`(c0j6(iV}A(kZB?fzU^`fbjbI8f`KV5mUb#CF#c&Cc4KD}NjX zkG&cKr^Rb0Fks%%A=@&b)}^CkPjU7O6vS|0{XBwkh<-}LmArKCT6>~?!_r-^0f|K`;Jb%j& zfT(^r!ieiNb?i?4IpAK%^!r1Y(e=q=`_L9QYBM6J?c-S@kN~w&`xUmbCg}y>d4y%> z1Tx%6vYiS{ZhVN|w%NxbCaEj_ObV5Qu!tLq5^8nvC$ZZ;Mq`T&gW8rLfxScc*w_S; zJiz3kUIOU$10T$i*VSqd5RGUd#C07*Z0RU=%GpL&6jH};h+RQ^Oi$aO=5T4+#_eTf zG^C{E+zx#ymyOK$mhgdf6hoE~RIEo`Mf!?+;%xg+wg)o3F6eA*VrpEkg@aS*c~@h` z5_At1jINBXd+w3xN5znPy*x<4KC8)blfzHG$(|H)<8}v}VBJ5z{#VII$fXVZF+6rj zeZ3>=GIaQQ`vLX|J#c<~?V|(cXD0UL-Jm$Qf~l8kfXhNH1hQ{rr;w0dg3+n(Ac(QF z$Qq0h=s{aqh?yr~{B~jtL1zSZ>vFcl90fCIPln8HJhCR{C7UF6O32dvsohhvL#dVO zTsLESr2}PlC7)!o?r65<)N2Sy-}-I;W2f8nh}?pPMjevQ%^>c(WS?kz4%nz!Ijbp>8#@9Yqbdfn4?oQ+`a;7N#;Xhoj6_;c*##ND}2W}fBID-NPI+TGX7N}k24s8%d19tKl zH=x0qxM4&_Atp3nGa?wGnISa|5yO1GYwdmRx%a)-YRNX(6zbBu=j?ON-fOSD_F8MN zz1G@!+(xxGaw#J@Ur{-K>dHr|e5A@z3bku)y_qY_$Sr#dfN^(%^XP237W!$HF1G!I zbpTSvl~G)+?Pc48KH^$HclV5!a_r`0q%0TkSmBhOk^JuW>3Tocx4B;zc|Vs_bb#FJ zf{~p~+*^_az*blx=n?vNvEoHgvK4U}Q?cKR*p0QK{S+;$=&ItNe)jn{3;rJaH~u;; z)Zp-G4GuNSISg<{YFJPJ6G!va-~h0FDKQu-qd!)p7XyT`yDJnKgzQf`RQ64PYUH4f zL~t5|tz?7o-dk{X(nh%$7nbA%nORs$L`)yW$>`X^au44sXNceh*L#rEi?)OSvkK+j@8 ziFH*xD~Dm_wmrtpyzfxQdrFMv*d2rBAfHHXD3&VHlw*@Wv-jBFhyJ8$gty41EncIp z?u#T|$p?!>9fpp5MIJhr(G&IhDs*msYo!wBO&Y|!p)D|LV;pW=B zSP+xYvFLD~MFdMuH`r**Z9i%qCIa{MY|upDeli=FU=p-cDyv#` z^?R%00qwUfX-t_b0$4mYJb>JJpgpo&c_O-kZIOw($V*GiqkG{l;Fh1OB80$4GC>v1 zhbb!f=s^vn;N!jqQt)wK1G$8tn!{TiFh{Ufz~O8*!52`tNaajD?tozd%@NQ9HJ)lV z-QwQ3f{-swmFxlJ>9sv{FtfH7!vOiJQ1#EBsP26rni&d|(5qRyiQSoh%eBR|0v_s{ zUaz@M_bH#{QMaQhGu_FuNFxdN@F6!n-G!4oDuVGqp3cX)TP8 zL!cTF2m1*)pYU|04%)`kWmMgPrw8{gOMeGX#~ZdeDlf^?F`Wosj8#TwYNo!8pJz@o z5O;u9;+3+RLX3=?%?Zg3SR^OFV1uut@iEiD==5qzd|zxteEFq#{-DY8g8*RfS;SVe z`*{(EuSL<^d_6aODotyZoHL0tFNU9!^8ofFp2J}T4-y(m3UJ%C!!-#|TkPMNhf`c| zv!uotSD=U|6{%KN3(iJ-uxgFI+oSZD4={b?rAZ4=!VT;^E*VUaj3p}-WrK#8X)WGFo>L|H5w0V2?RD7PO7N;o?*9av(yxf`#sEzRNw-+O+K ze>c-_^8iP;=;lLQZ_VABJ+3!!_xPv^i4*;>eieE~I?R*0_NbIw^K~un^s>74kuW-XRg537gic7LJcZ zpqLX%Bg{x^eA6P4n@#>Sk2T`YhSx?xC4Pz1>Rv8s zgy+kALx0EnVAF!0Q;Le7(89`>!*qnQw<9uoOnU$iLL=hPNS~Yw{{vkuIUy7EP4l>K zq+=kA{x{2WVGVOsM!dU#Z7jY8bfb@-LYoANw(7W$jrW6iuAa@j*0nPKj*8=XsCqps zkdd5qmLIDWp-(iBX+wyN@S@fRKCm#b`LVo4$avj9R@rv4#u^ zqQ2DLd--D}^ZFiJ&v57+e9rQ5?~kgag*x}u$#<4IDKh0P6P9c+p^nSnki(Ahs?Olt zmLFxmI>}sz5T8jW*XQjT4na8?3WgNX5weaf_PcW zjBibPlKlCiuO#`8iLC$hk3X;aKg_jzDGxF1fK8I}{9FqB9k`Z%?CT+ep zX!1k5AdUI)tOf&d7--YxaG1}pj5tY!Z3sO*GoQEq@RcLN0jJ7 z??RMPFctJQA&GFn45?up=sCOJ%+M;a)sU2nVz4&)9pT%#vhYiQd{*Ws;P^76v+xra z*JYKwi9IcCr8%i16hH~2yMLCQsmg^5fjd9n|25{pDn3zCuX+%bxl>U`EDT%D1D5>Rig zF(lTtM`_jjfyLr{J$M*`$p7M%tZ0pg_n&6Z+)>0^Nth8c7ro~Je>NOj}j$jQ*Pa=G88@bVcuTJDSncP|+ z>&}m!X-HM{1$?PZzy?aNS$O78rbWbKfBed4Ac}FG~18>gT|`IvTz_pzhWnDn-Zc|&QLz9f2jO4pPJFPUp>kza9Nf9 zsVgD1f^+&yaVVlL(^OL+I1n1O5Eg^Cmn?XLDiV;`Y9P_5$tUcJtTPD^XtURPu5BxT zfG*9McwRJzZaz2e z4}=U|1b9Vqi#j(@5B{+uM%~E`X*md!Yqs@Ai>h*husS3PPSHSE%MgZL+7QN$h9N8* zIBacWxr?}lP-Jum7j^nKiJx$SCfP#pz%NdkTQoX)j3Qs57?`G-2${})?SIeG;hz$yMzp#%q`#|0bxU+>0Iy^=1 zxLjLuPWnyiyl{|Rr*;SNqm1ihIP}|HN{mBfwapJ70Ss-`r5{ibK(IHz@GWf}g4E~# zVYIBABNQ+9(Ish)&5?Zed^xJIyclJB=7>3ez!cQ>#W}v?GN$IpWjj5G-gt>^2q;Lv zPzxyfpkzHpM=kjH84>-gsXc4X^Y^E-&5+o@-lUzFcE%gVI@^&k1%sY7d^h=YxDX7N z$U3vdm73?Tzznv&N?B&|>Qq;jBRDs}Jl1u~wyr1NpCw_SS$LGPsy-Dce3|7B6^fX=f0 zr_LHWz;1i0z>L*GHwNqGi?Uq#Fx2Ish#_)l$>p&QCid_WNj`Kbf;jD$+A<{(h)RXE zGk(cFOZ5rATvk=5I~cA&-isaf2l?IXq6qVQva75VxJPv{SJ^12j!rX4O27@}PjwsM zRp-Lpx|+Rhmb1_wB>azkq{&*mj}VDSk1x2=p0XqCG4>VrQ?Ac=5VOk|t=#71YGlJ2 z@=?(>(>~zLN!Phf;5{7PZnQjy4+6dG;eN0yjMMC|ZQI-eX@8yJW@i|n0BvCbuLI&- z5g4->X>IA60_)rGF zk7Y+xrYSkem9wu{HuLztVi5}yIXShPjD?(CaT(G0h2uT0U(B?p^~**V#`1ky8=TTF zDQ_@A?<@9lq=bGsS^^{bK50*n>KFH+llsLF^_+gu6|hBf)Xc3iy6sbHoTv3m@7L{E zseNWs5A^AN*M&>l6C{BYclJVxQ|&^Xhvo+ z75{ReA+>x;d^ylq>O}hbA>(L!swb1@) ze&f5@lPY9PVANgAuU$L&dzc?{D825{3n6r}gxM^cN4o|t% zW}Og;#l7TG^!qqYx`#-R(GvWopdQWM?9ceiCPBz|CrpD`_ny3 z^uhXj5OY*gdZ}$}lUY`jv=z5|c|tZyc(C$qj@R^irf2)odSbY!JsTp^6)c`FvkA)} zz|yJnWm3bXcIg={Ie+}8WEBY<7+PX07d#;hq#_i7#%n?S!u=iJ=Gas zr{9ls#2gW^NzbP=19mvSO`7~zyl1%v7Cv!Wv?soy-|OHT`Xw*KNA%15e@wsdg%9hOXzEAx zi`VH%{X)o_`i0ND$O=(>8f!+OX^+uP2)%!nehpFkg15nO!K=eE+2874xp~6Sc1jD99g1a8!uUwI_)_4q=YT^CHBW#|-O%|vZ35TNAMhW0| zt2er+3LTyH`Ax3-u5U0lzhOpE-dp$Cdqi18_T#??1Jy(j6X59)Y-T0$`iQ2djHEy% zZ|FYZEzD0VC`!^@@xG)CmhaKO$Hd6305=9uC<*sfP^GH2b-aAqsF!rOh45jyNh7iP z3<#&b%B!V1{r#+Ys@GM|d`4@Z|5+kaj7#E})6rZ!MNeW0VagVeK0@{MzXBik6D)ex z-YtuzRyhQaN!)5Ua8vKRiT%2cwiG+sV{TcWJGR4Y>ESy;UITAmJIwS>hT^BhJ6!I; zOJuc1p?OmFA8U$TQ#HkApy-+gWSw^A(g~Tnz|~W^BkNo)i>W3lUS;DBUjQ^1M+})Q z2dU1S^@AFKUjx;F+dvmrfl}&7t2O!SYn{W0_HCaS%l&ZVfoA_qRZ~GB}S{3V0FGH(pr!XJs*hNmXH>?!A1gr{ga;i;cvp>H|I zB0Pm$?P&+)*YF3RSHbk8sTImVWIkR9iKjG{p4-h2vZz@b35`(E1WhfQGkmcehzPF892OBv7D#(U7R)Q-2rgh6(Y^fKzk#fsS4J`A{9=s9D-)6i zS+EAmS6D|vtV~`UFEyEraFrJw8UkmE03h&@3|k?qn1$yI<=}|24S9~0;7s#|%n8(r zW-X8Sfe4C`D|CEA*}9Wi)fRm1f`e5GNgBCR@{TfD;|@=Xc?;efVm`(l-YZsxfW~_u zR4wR{JVY;3v$IL-1n+8!!aw8+&)o^R@hEaRbkCH`1#}3I4vqQYqyHcCnP`n(ah*Ds z(ky=9MqO=$u@+X)BTCP{AewEdKsusW#v4R+hKEFRN#{s47~lf(00a2g%S&90&%%!h zYMt>C2jm$qaR4`#&v^tIm{JYUQVQE`QS``nY*?{CRD&c(;>Y+S7#NIKV7Oqi38}L7#lDS3gp$Z zmdz)Uw?Ryaz-N%lsR{cnHBpPTQMn?v>>Fo z+H7Ulen8zWICllxSei~~{T%RYsGXj}$eOBJIS=VP1o-bN*G1rwl!T*^l zj0`n{#wO~j{7yAz#kb8I*YQ-YCK5L>+wcIL(W=vTBJuc-56$ONHH2_!F-kECRY@cs zW8lffz>u7O&5X!15xTxo5ULv2Gn;KDLvjm2mG6DR35@vU>RaMHKI10$mthKh181I<52cu4;xN}^UI;AF5-lR* zICq8@tP!KQ@SRvB7>qm-O#7*nCtUX8S+@dHTkm;hO8D0oIxmr&A{tu|M z|6yT=aD;^{OT-+CmXro{wH)aMq8sU=E2sGLKLH=-9i2w%eE$3H{eZPwoCLR|D)+$7 zej|t@?q7pzQcVIq<24;++I>y>&2G}@(o@AhwxvjFHg)u9P_^;QtH8T>h@L{p5C|@Y z_EK9fF}E=?5Dmc=rql z;c$p$8u4Cg6dC&sec#n%S$|0!`he7N45uLlxj~8awPMqfq_zuTFy{?EQ6{z61yZlW z5A?Ly@6a$j>)ElgE8;oA+sHoYv^d5J(PXrkD&|NtFV3clF;jVQK2?l$#fw{0#m~lK zMj|$;#mb}Fc&`prkLx$C1*;d%t8~3O^~=rDXMaVdH&id`H@;hRAR^1Ok{U-R5Qp9< z)Fe=@)`Hi5KqM(`5b_5dqbFE_!T5wisX}2M81;pt$+aO_YCcx5cgY9IQJo|%a>B*F ztHJd35l=K=a(h;UC7fW%Xdix|8Y@EVBzY)@v&U*}nlGCFM)g9R)7Yg+057{bO1n>O zel$8Z(T^acNDmJsXyS-2nLWb^OTgB|g!S+E;Z5o>+?Z8o{}`m0D{tLkuvD|`6azJ0 z;va$bg6~ONT zi131aSV;r!OwyteJYZH}Q$=Czl8S~-W{T7%@%3ePUUz{kNJ$G$!B6I`~g(1U~E3)YI5oVJNFzfh_kOA@ke!peO7JW ze}wHz{eFV|O~sG&U|Iag9K%m*EH{ITge=Uu4XB#gjWd6f*5e+qLBk%%&^IR7urg1A zi#QCf_~oPQ=8^e8P#J(>4-J5DSewJ`0JmqBA&11$an<>dd^Fvz+2`)Iq`Au z60!as8gJj6BWxVzibRHHRt#LQ+ry#~Jm%c6t>-sBsNk6~tJnZ+mKG9y@Kntk)dCKn z4}0a&jJc!u`-QCEhqi6J(WGFGmNH!qo7=|yB4uCv(a&xs)nf3;P<{u!$++*=UKG%Q ztiuVBCyBx%Dd%iJ`Pb-jC2Ut2AzWbeAp~L5&^Y=9`IQKDLey4PCQR$>ILl}}+lh^r zXFKX)kEp^#ym>D*7R&qzo!eV1t7qO#bAzXvPiJFX3XK#&#sN#QCQPti4cnb;hlDFk zBH>E#F>3_hBHUGe@hMvM{p^(qZPfcz#^Q+IC&Pg^PzRn;zhg#IiqB=5J9=$Q;%CO! zhtzl<(1?~m2Qe+wD{wfv2f3owb)(i-+)WKS-xG_mdZERJcQ6nZ2SU%;P1f$E6DCNB zU9)bS!%Y@n3&B1AgyZyz$99JyCAeazL4@%Xz8j_ZT&IayuCWvKyqp%igQE|A1TqnF z&oc(!#`F<#^&8GgBNlasiK!0`iis1%3m*_gEpTWUzgNiNjD{FAnzk>vRQRMQKEuI> z!K^uP^tKWHlO6b-v0|_>`jEQ9z$_3DCEd7ZJwbBBh5nTS2ZaS#h(d`_?b7;=+?Hd` zjN9t0A#wa!&nt2KY1gY)(j+tze6fthbI_4Bs_cThiJ9r+v|dT0ewJ3`E01P&q_goA zjlTHG#SFeeCXF%rkNfh}qDRJgBbIq1mU)vJ%gm(lev$cZP){?-NIGzgNILyENFp7U z?k1T%3`=VHK1SbFc8Wmu`Tn%J!tjV?OVz3c7{9&sw9;M3Y&FCR^oq3 zs^`p)GA2{5=g=Y61as4h5PI_(rOVT$C{5QFvCxiUEnBvvPJJ&z@ z)jS%PR1Au*Sx4*S#0LOD)xK6g*EsLZwuvV+VsG-C7GWYK8zPuv4NoBiWVhAy!hlty}P6Aqgn zMYn8#6G6Y9o14wW3L!5I{JMCPb8}6+S>k42ypf7M?>Fr7S@$!>L`&gP6N)l41v(WJ zN7R6#Kl)RRDT<={0M>{J<;*v69+nGWAB(RnMkiP$+!rl89QyqF1my>mGtP4rcBeR| zbJfxYIf&2{>BL-h00)@*W-LFk_~bCOQQt7O`$ESxQKgtZ&q`m+M(YBovWG%{2lfZ^ zj46bvX)2m#^$ruz&+P;EXf2ZB}=H+(5~(@4nT7k!v0 zzf8p<7U`L+Jfi0eu)h!k2XO7)UF-d|pU|3VdHb5lbZLldcFn}mka5j)P$HLcG-Wcb znM5^)+J-`Pv6i&^j7=kJzld0y$XXrT3o9kB7cBTH&rg#dbNK<`Gvx0ruqN6rzGbT| zdv{5g7QNfyW_=IP7h#McRYcSYiK`;v9k{YK6vRCdlzrO;%^r-DI&T)@`yW#L4M!o~ zisH^MHm$8p>$sVsVjpc@IVyL+Ag4R+gtNvHMXm0-2$~(Nm)8OnZ=u=$uIWGXjktk* zPN(94ztK(WBnmS7FC{Ks>4Bw^fn=N!krbM@#MFqj|KLlzOG?nG%7K z?AtMvlap5>JY$1oE^OM3cId~cG1UE>qgYqVAqmW{RykN4I z^2oMo6muy{BZDgmE^D*w7#D+0&KUd7haALL;maiT6ZCTiJ%HQx%68D<@}f%=hyZ%0 z0lEybrg?1xeNLdyZ3jJ*APtIU0Nz|oC&05IR_8#TI^Dp|JE61wzNHYBu~FqJ`R@LNFc06n?z>~+}t9^qpid=O7IP7EKzdMKqz zX(%H;5F9>~h7YhK&OD2cZWzjLG5;nYp9dfCa2v|552fKF=*!?k#*is|=-8zRKBjX* z$5$Clw(%txnxjZxCj=Ow4xTI{81%h-sS zV^F94&5gVN`F}c(+}Ic72BMAEkCK`M{)t*pwMO4B2SB;_W|s2AOUg08>_$2m zaH)QN)F3u~s$&A&tCfO5!UCiSA=k9=M#zqzW6s6ykdY2rGAqjAq$hdTM=#(@5L4%O zQrMpt)sF9`)!JLpf1cKR0w1d{0LeA72PD)->RioT0|sp>od8oqf$6HN4Lkyybb z!iK29kY^0a{V}85&u5wP`yAp1s=Em7w*6i8eo2})J}a)!QI5nZd0J0GG~-)&)hab<=c4P%xpfmMy z1`!l}@7C5P^@q8w8CQM!;(3bdqvKi0FxCE9w2J$TB5!n=iN156p1Dm=X<+sA%)|7A z#oP3R+XzgZ=Lg)}X_h7#)a=ufr}fk{zGPe~VTN)Cv!ZiskjwA$aAN&$8^U~?gQlhN z^?ub;QxxJw_0&|LC7`oU2rx>=&;kk^#7-2Mrl#_oWno(KxQ2if{2-r&3s1ulAH0a> z!q>cai)cRh8tct$^xGeVKH_87o#JdI^;aC9BAZNtADqh-Hai(Ee2lX&T+Y5iX9DSX znf192u<|m|5}mByV_faizZ0iI##6`E>!ynA!^tebWB731yESK+sPM4AS{R*5jNF{8 z+cMYc{tf0%8cfj!({D8jtlr<76j0l*)pyi$Cvu2|3;`0nX&Xz?s;x4rvz@1A8Ex7= zQYZ^n!TYJ@F-*tPgzaU}`!sR02LfZWW+xObmPfvOq0gPSlPVpHP(7YvLe`n24yvrk z`d#3M-R5`l!`;2ST}z#dz&{~vDu1VB?Rs`Eq|MK}#w6B+2gm^gL;Yi^#7<9GaG-0s z(-RhAM*_hsD?li#$y=*sKu1;p6q`VZO~4^%M=g4Q$b`#DG0rJa5P&o;H;#trVU~Dx zR6~VNTJm|TIg&Fs_eM;dN?rOq#;=XURNo&acuhd4CIBIb*ak z>#)k0&TcJGp1ts%Q#|j1d36}6ptgNKIXechWN}R&FnPcYE^<;^4JMjv2;Rq1ABj_` z1Rk(3Ub0omU=+RYUe?#<6t4LK-V7?5H@M_mcdg4@Xp|Qkx`?;VYaovAfb?))2sOt3 zZMxQ&aq&Q>Cx|ieVQ?UK=kqu6SwuZ)v*(L!0+y;**-wX zYS3dA2}L+Es&%gwkH~#ZG4j3PzQ)}QR+>X&iRU7L^d_3w_V$ZhBcmZkZ*c6QIBJlM zz|&eevSFXmhA4Zdiuk>^o39GHnGf-rA>f`Uoa^T(mdD&`KpwA_QTlAu1ougg^FdfR6 zyB0R#ol~elqjOz4hm)1*P3l}no%?J`Hc-BE+<;wHfxx0%2LN8?Hz(Tu5TbA;Qmb6& zOi> zFlNh<9D$>SZkJw(6)S{Nk6F^l^a&YLYI!W$xQ)i~w0dNTP(7rm!das6Jyt9Ft)R)R zL~Cm*Ra@0-nZXjLBxO(uu81aF{~_0}lMUVs_}{#-o+?5qt6pto@Sm_FBL(0ZD`Wmw z`|Uku;d=59w2C^M{6kC>+%1j;b`C4LIayGb=+tY{xo=5Qis|XlR#(*!{nD=j*P`S# zN%AfFpc;sg?b`@_N~%4GaesNySsW#=NyEz+-!nFq>X&iOwC*05)Mt$I(Bu_N^j)v- zTD^SZ>Rq8%`GhD02#_I@Sclr2QxnUWGL@dMK?`89kFoM*0it{g?WQbL;EUynuda@*nJh8Fn$CJ@d z=%_+U;pT`WQo{`;nOrOOQkI|c>_t8`OA#aFMF@-(S8Y`|*ERtER{`+bY-i>U ze=c}fq0XJ9XCJp0aQ{6FP+GT|jyf+XY&S^Vh582KU5q#SLaW6`uw~8N$5s-UdN+pK zzx>O8LZS(~y`P)(t__a3A-&B*C4*E@{W_pPDgg+D!#!soQd_N<^7tV}5;gaI{9tDx zuLBX0md^pqVR60v*r#5uWXK7SD##F?(AgvWMhg-l{G^7C4@d{<$p< zD1RSOR}hR-TG8h%*&H}5p*n);c%XitHiD4D7p6;DD%jVb(+?43nsNnSgQ2||y@Alo z{L>Yv+~ZeJ&ytO;+GdX7LJ2UYPSJvN`jVERaz>5Y52v064WJ-wNCFp+I#nUJhx7Mo zKhj04x$z`L7o(Ck{Fyi8 zS0nN2-02M?t4Iql;VUFmD-dO{9cd2|PazVCkW~!w9h-<@UNccat77;|oI7xkj|NS| zihDwfED24N+950y=5Y)uj(*Idy-_FSIm-|FlqoF*t_^Sirc#QRhdxr}Ob6Dr<-5VN zG9W7xM1`Vq!VWQE=J=fWmQ*vG1rRe{ktBM+>=As755d}RL9X?YjWJz7r}`6%1#MUV z6R#uhfv{bD|HH=DsZ6y{@MNO^vDdEteWReGf=i78h^Afr$Rm?F5P|LL(~SaoEYc&1 zJ!^zG1tKxR4K6Tn2*#dXu-C4=__lHfsvAYuxn{r@NQRY={)YJi7b1T&kGUhv0`D1u zz-&z0;EMEM8n<>BHw-)3kkLY)kiN(svD9HquxjzWQcacvK@jTcreEw3R2_obX`h#g za7VDn8OJJDC=o-*h-vJk;-DUJ$d`>6Kop&E8z88r&A90md&kx&J=2+xzzW}`8FTb_e{BV zwJ^D7%}RKU#!O~RxFcw*M`|QHpzp;yQfL2q!Vh6`oHHnjFUIgrm#Bq_Ar4IRd(Kz z(G~^HW3;9rRX-Jt51EQM%ACjr?SxSec~Gf`<_w0sdJ$lWV-`|0!Wu$xO&dgTqp{Sm z7|q0DjkS1yKV%>^`t?Hwns&oOMp2|tKV*~%!3+->QU-#tWMoO5Ler%UDGC9@JQAkKYf_EmU0u1x3=Bok!J z#|o)uOb~ZkdD2fCA3{nsh~NU8@eB|+GHoM-^V(s6c5D!V`ovp~HE!m~XT;1-h5Uv> z6rbhjP&6zixLk0_O@eJ2n$i>kQJgBEsCv$NZA*3!#(n*G#i|hKc#l~|EB1yt2!d=y zO72jz3u5cXK=X+X6eC5|bH`~6l||Ku9$F|M`&q&}gD3yHUOZrqL*LXnq9y?SYClCw zj!@*p;wAK@812~MBr?#H$1*!KxfjHC&mZc@&tOx~jEQQc>v>H&Es zsvf{Cs-6=rH8!Ohprszk|M4}bqw2}7W*+h!dkRn{X~94{M%DK{sy^OpIaId2T=-z4sXFzoI;jDVExs8FCKBVgU5!k0|cENptZh-e_xH>BGNi2 zhtcvHF@ucx)Ah8nQ|RR*1f%3#dwjr@JHEw9m%E|^N&}sd&=yZUMw_(;#~}zsjsXv_ z&qZm7RZ$=jhqTq71lUhHYP7N~z2 zQGSdQF7$ZJKFu;9YXEIsK$NzJ+_SppxmX1P`i}68h(G>=6Ii_cG8ZADquQmA=;a*NByBH zi<)mKYJOD|*DCDzuvdvxxK`BsGDYh2H3IBfJ3d&#bD86-Ra|H$Uo93$5TYXHb#|8? z!#&U|Zr<bc$<=t0hOTp^f5NxSnZG1q0YE_>Weo zapoW{B$x=%$d%48?OsK}bhy0ES(-j4Ot~JX!{r(9nQ(c1H61Rmny13$t21B1G1gWM zbYnTF#mE#*oKdh_SFb{pkYp%hQHQW(QJ2+%@@TfE1KC_pLZL=a>YK&_Peaz~C_Q)J zKrtF<9PFVFr%7DgcUcFj%JmKUl-Yq$rd_Xb7#%|kAa4wkTyQN%V>%JuoIC7y;u{=I zt_jLPt0HeHPm;8AVsWSgca0C=-PDI3gly;!cTMf-E^%)ITytP&D#5i$v!Ux8n2ZlK z2i7VJmjMjjYO*`Ugq5xdQOB|ELaQ}+pY)~&;{p^CEU}NK2r+mmC}F0^!$~x#Obe0H zq|l=X)2<*4OqiJ`Nx!Q3BHqnJp2%sN&8FE31}VBIu`+B4Ufk=LTe=ZS<)$#S`9b}E zA4Wmhk${VVI7QCMe=rt02uvbp*@CGChOa)$E-g(N0OhY+;?@u4F3>Bhe97uVSV9{r zD3|1=t_WYInVKqB#0P<)m{;pLD-JYOz;@M6L5qK zqY6N0OVta1AgAw;`?z{ach&XP=KrbE=*i#c2N`v++M!8whr{~qi&jVdHe-Ees@BI; zTlKBgg{fLK7iZEdXbg-TtV=20_D*;b{iZpZsA(6AO3%u1>x>lLu{-YXQhWuG94B;C zFDY1{A)7RYTH%NpBTlC-wE2#M+n8)5b!D_Yt{VKyancZT(SQwzaa2u}C{@!Gw2ZsM ztFygXVzo58rHl*EnRaQB?|p%*fx&2J0|*W50%#cB0U`r_YcTs*G-2L+zA=~v^JC2t zBmE^iUYe1g(f&~mm_j7Ufg`m@oaY<~FLKC!ckO>gb8HTcjCn~eAt|1mj;q{SdyAzp ztZDL(Sx$;G<`!%69hLzrFgB*JBw|CYH;3sDNHaX1ZmP;eS@ zSOWy?nX@&sOg09hhoKG0o&zp>4m7m?RcqM<4{wc%gHM!Ki`_T$ekoxX1YKP5dad`b zO7Cw=a7c_Orw67NnM?|FMsbG&u3iRVW2Xt{dbQU0hdXNgbW0ll(u~G0d-6<5Eui@- zYW%J_NIZN!Y5bsV_}8NGLwqFp4jO;2q4DQ0rSW5Axgw39tqq6)#w1w-mC5E{ia$C7 z>NkHHS~aV2!T=!{>D6%dpz8r8jnN_2yZ6?$M6{ace4cJ;Y?hu7~ z!rs8##%r@g^@hEH<;lJ64IG@@W0})_jG5lG&!kmEuQ~mv3z|&P@6{)od%$dMIt1rrx0SQS|(_lTp-A^@YYl#wA_sVpQOv z?VXy-bc-EJbPVmCLNJmT3;|R$uoWt=Knq2W-6WwgY*Ct-OoYZVSq5P?Jhi_g0+1|| zTm1Xp<3F-4HX<(ps(upVj%RJKw zS6SvK$)gA#0RaWO5eaO9Q^zojyy7#q)0aA9`!CwLjs(i0UsqB4(ir=(Ve(v|$pgWH zT(v^Z>%<04&c_UB2Oi1pwB$%keT~@%l~Wc${0PhzAxj6dll7#yffNrim68D2wotX; z5s%b95&{DYN5JYo;ycu*P96{=N)R9J29Ti z(HkHwxhoKJ$o0Cr%`1F{oHbgQ!7nksXk$UokI25Q*hL(9=H9}}Z-KSoqAAHkJf2~g zFIi<*M*)NusF82y}yM6R(Q+L=N9yeP3h{G+`2Bd z5$!F@(Fgc4*w7hr90ETES7*P>C&#<63s=lXKOyYe&`EfEP)*qWqsNrBEKj_7&IrGt zAkI;lrHpSd05nD3JMcj+X=QXYBr9Cdd}QRDN^qe16VN))TDr#doJP&kYcO>oBm&aG==duyVlhWwEhlkuuvIZ_mpgGejaW zVRL^EIMO0h6p=YROn3Y`Xaj>xgF=9qew8wMm+9Gyp`LZx2~3pt861s zSa8vMf5}-=JY8JXEBw5lMtb+0eSf)h@^0C@q-_yAS+viVdvITij#^AMm8!^n_4XWJ zdAJ;ClME~L;0a_inuRz~bmYROqskoqF}pnYd6DUXAI>`vs*1ibx2r^l{a`^N%6(4q zMz%3n+A+q9?C-bnLqy@b6&CmgeHd99)3!bOcafpp#$Gbybc}==yp*~d4=Jyz6){Rf zJktbr*0NoHPON<(cu>RP;E}W|y8}Vf+Vv;Tw4f4eJ=5(WENte z7ZoWqEWQdF6?9R*3fu8l#kb^W;vYBzRoz=Skfo7{Ql)rO_(DDn2xb4`NZo{7C{tdm z+kiR7PvoVD;lsY+gv3M$u;?k~fV?Z2d2B4O(T#m%!x5%9or+0*Vm$vc`m9J#>JF|m zY}!*BEy43?NX#B-@D>=qjW zgX@@18!=v0j72A~A{$?xuH09aO6>Y}CKo6!7w)ls>5}EQzg99K5t&R#2_SYE53xyA z(syfz$!#{rLj|&xeEmj9<=j1E%sA9#4VAsOf*H+0kd&$iumNF_^b8nDd(fSv{roC` zGEekGIlFO7fQOhr0+TKg0I7g%SjjwH1WVPfDH=oKp z7nD3gQ>~!$Ya0CR=K);DR$M^O8pENGPZ`MB%W-BnL^(g#$8t}jm%kls zt#6b!Pz;U~o>H#s8ZTk)RyNAR;e+eR6~`PceQMmm0@@XZ^&%$lIV`U9b`z(xMWqo2 zHBG&Zrd6?;yw%zVTx-)u(^{nc8*H3a-E`CIb<>CIrjbaY=~QH!(%=!fa9vldG2_cM z=BW8$^dYaOKldB#v;3B;%V2(G#s& zj%Ig5?lOx4(wj}ybVEv=n+R*p{h;2AI`bIxamJc2t`7U;h$L&B(UOMQH{csUj8Q0n z!~9TIB_VFm3|K9001Y~KBGI+{P!3Y0jf!xW&xM462LtJnj0K4A( zP>2SSJIXaWRbd_?o(GC|IVrR0X4LFsF9Gn)?`LEET1 zB7YVMM`JT|U;Zq957y`y?O5l~jI4t}9vg%JgP^8&1{VtSe7Fi-!qcTZM85*irV7@p zGiI?SpH`&xbJLRMQ5NRjA)LGe0u28;0xJ*k<35k2Y*b>o$`1Er1Dn4WXzi65}WV~Pz1WSK2Zah)< zXOl9V;@kr;M*_{fY+=Tf@}8YP^`I^98z8 z2CeI)E*Fjn3aNOM%v*^G6NyWS4$(j<@dv-1h>;18*Vz-v_u!-SBaws4CPLc!ENFQawO{zAo9;i~YN00)ck*@Bgjw>&xsK!K$ghh}(v+^Q! zd65>^3%w?%wBS&dAm$n~2}I6MG(Y3fc7}yntg&|3a?ngp!rd; z=bj43%)8N%{WagGbC2IqWo0vhVmK0%G4i z5a@u#`T)np{@I6Ay7%PW;O{b?Jd!9^;>n|^aVt*fid z2lME`^y3G_XgH?bghX{5O5f z@x=Q0MyAfp%2|r9tP+w?(kT#*la;eAz-?_khu&)w*z^sl6856mE{y3U=)=Z>NSPrq zjezTG?vHPrSxEamkHbPblFA`wO<3>U7#Gqv)(h$IRw;^y2j6JDS`+z~S~5%)#y~5p zl$O`lDIgW!u~oH!ZI*#r_XUpGMY9}ZRVnb8*6~VL$5=`LiwP+(i_#V6z@S+uNUJe@ zNjMx9H#SzmH!``muY$pf&9#|T@QpB$nN={I@^!HG%;5D}hFHPfrKQW+eQC^#aY+Y@ z_NDQSg49mM)8e?iPD@gBhp&V6F*xhX@#<@^#C`P@E^#sEd@Yx_D4kPFT%GQR#*Nd2 zXo^#}k~_7~(-akzYZ+*yUf(kdG!??VY_*4c^@>i*<=0~MS_tNHdiAP_ikVnHhwd!b znoHB!r6>?jEmgzP6u{qNlfGV(2F?~|)^1DEtBO}&*^(3*7j1u4SEkHFrpk_Xn?<+V z@FUlkMcHjQ`EC;5Fui0fP+TNX51|VXhovRsnlUKT`qxnFX)5Yw*m@Ff!fH`Sm$y}8 z35Yq*O!s1vjpdoGAGJ6{AZSA-8VIO*vOMf+c_<#KI`d<&{jY2tXb0`ZAP9mDU4LaW zH*xms?6E8T1`2|m+M>^vE#;xO_j*Wa4i5RU-F%3^`fU&)KW`W_0i?r+JiS55Bi~sr z29yszkA|^ST3(Qj>-I0W&kKu^bn+mI_-~8WeD#g|rEY zowl%6v3yEal-9cQkIPry_tm(XrebPej~v4!pfBd!Bw+8X>m4@>i0x=GZ^m3ogA0Ue zVvDffaDhk_{cKgmtv+q^F#xs$$WmoqTYf$swqptUAZ*F*70U-vM&Gf-28$J}QVY&* zjMsbW+m>>l{VHz!cf!X1wGR~8wtfH3E8q9;ywtw`Qz5D0Dl z3i6?1?T3v91Go7rq&SyxDSri=Ak*7*3;lvl`5fU`_81D|N|FEv?e?6P(C z_;bm_W!v`j@f3O@q;cd0b0ma00Ma^IX{JfUdWjymgOVM`8y%EzS;>6f=b|Ec{tg7O zPO*J1dAC#^{Lk>F2On+bvw6U@WX=Tv@WosdF1lSb=FuCEn7VS%kZDT+>Fla|@=7bj zIJbvFIBBC0ReLXmO!rV&jO=QJbbl_n54+Qd8AT-gppGI68Gp{e?(v4HZV?l(owBiZ zFRUp}p;R`Xum~2Uqm9vL|0zXw?xC1e4|}bYhLQ*(=UO)Ew)BKm_Am|+QY5Ujjz1zJ z*%AC+`VW=Mm>}Bs@Uc?&a4I_1#{ET#_2(+g8+!H*$ZYl2{D_w9vRrbFHqvOYqoal; z|3Nbzj)Gwyf22@i%~!l6hy7|CKx_4-Wb{+&%GD%!X|QWZ*G4RbVTW<}!z5as)8qKr zY>w1!4#|Mra;4Y{q;&~HvDZ&Li|;UEd;Bm9mFOf3zCQxpkbfKU)-Do3Y@_Es1T5yi z1M}lSZw!~xW+P(-_!tWKoO6+t_kjidMkoON@v2u}74_A6yi&VIlwP=_^uj9w+0aDJ zGVg%haXe~$TpOSQg>Z*sht_MNP1y^DK_`37cQhs=E9$Tf@jr}_QqDd{hLTgWfmW*Qwt0KpB^hA_Qp_qhH4-`D)UQo!>Z((OGyjt@ z3sF-Zg_@&@mVFW{1{%K*&tn3Jeywec6FMpvWhq&(n2_mHhSrz>)vA=GS!Gs>RZfoB zPLYV?(Sk;RMw}PgJqv=E7TE4lNMh<>?k$&J1CTEQ>IAHl*v}_-k7Fj=2IaSU$K^U1 zl7U7r?c5IJh`>d;QLn#pc-3>@XSXBv7v)JrT;HP=C2*|z9x~KnJ>fp9zBtvVlbL$> z<6`UJ;&HnRgQ8;##~M^d{F$uGY6{70dhz(ZCqQKo|Jv2JC2v zQ8goygb|F{_>pH$AiQaLJd-M`jGi`bP7?M4R*mNH4Hp}g#u}6JHYM4v!L1t+R7X4%Y`O}^GQ44E-Ns|w#t!{gtb;L-5>+R43*gP*}ftC^3J zAH!t#Mt6P^lieF#`e96VZ*=SDG3lN`YsbnH`5u(GLeO_)MVDzy78ko2{@)$*zV1dP zZZkbG&d?>8xY{BoD~1`6aRoIe3!7VD6uJyHd%UP6^AVe2V$u=vk!c)?t`NxHmpxmz z!|M&he)zXUMKiS~>8Gp;&NJWe)28)l2Fp@31$=FiQWICnI;H0Qv;bMMD=3owPTjpG zz3E$0Vp^04^P66uT+j2P8|$fhl~sS&5^3T*t2CS%ZpC(dj!WxRR*_;{uPUtOKX@s_ zxt_cRs^jN75W3mngzusEpioE924SLqhl>8)8{&-6%pg5Ia`YlhFnd%t_@$wdt z@(7Wcw>(c~s($tCEu9MdJB_zeCCE&B&{)pIyE(aDJ!hm}ldgHPQHYV7qE0C~7r@{+ zU3+rSpO8OvzJ8+Qp|43-{0Y>)P(LA4=wf}NG@-9am;E);f{yAZYxZR1PsjnfR6kJy zP)mdglqjpkp85&dK6%pfZ^-sJth0R%#7~myn>J#yRPu|4OsKHXki(R0rXfKoc~V36 zQPQjWF&3HujhvyDf;Rc>S8PR~!^yO-a zs4JNj61~Q-Mjv-Y+h{Jt)EskY3sS<#4o0YoxPY-^O?`dW(TuX#2&+PjSH#JjPbZOQ zBVQ?z%E#k0(8gW!wkS9(ON3(y)?8|%Mc5QnBh{D|B&e-UewoQMTI)%u4jJ>aUiE#- zRly%k6US!!TO`oJLch~Vv%J%3b@)y?2DNFe*|sLeiF%r#WrSksA?pZp?Ho7W&g0v7 zm`XDgGF7FpG43y8WAeh)@Lqk@&JwNpk9V(mh?Q~BvMx3XHTNQ8aaW?!q%?_nKZKk49)?p^b|2q z@rW<{>Ss~4|BEUZYh@Qkp-68|T66?rA=O7pu!P1K5Cy>(zGurIP`9Tbka{T+@KGsR z!#})yf3>)=z9!%JUH$D8WqjMfGJwdWD;>Zvd~u}05Ir+BM54A4^AAgbkKp#lQhrGx zxWfw!>J^S8l;0T1eE7L+r|ub{iFQ4>$LRCRzldk98G&Z0!;F=tMXgl7_pf((OGiQS zjxi>kp@38tn_?Q!aWNjmmUsO8+4GR@pNMohclqYT&90Cs>18zWFg+2spgEKl*eO5= zii&Zmn-k(D-LcWB8Xi%#AaZ|KH2zz=(YSJl+eg;fFaDO+rs?*{C^rEEpi17P>jpB@ z;ZG0Ril$Lm+$7!kzNVxoyq};!dJ0T6WtsDnQF0iM7PkZ?kt+hzvX}+08)qUgm>X29 z!pe$`iQqB#qu8+_G^8Onh_9?J=I<`)kg~#@J$^BN7?XnnTj2Lkl(>-L3TdBo!B)?s z@w&lkV$pb&_=pXe(o&*5uJhAXtpw*X1{VH<`rMV#L^_vUVrCw2d1{Z93SDo&7$&9# zNJ^cF5=YdhE0(BH>^8uu7QK_MSQY|{1{M~wB(|)RB=7h8Etf_|~J7H7l01cr6)T{or*{YSx{kesyszYN| z-e@qTLE;7Jtd1Xenhy&MLR%cL>K{yA<;l|PlgGr34IiYBlKeKb^haM12y!bl49!a_ z3qxJxwu7xR5gqJJR2J)bvu-VADCOCtl$IDpV#Zynqw}Yua~4}fp_x6|lM!8`#Tro@j3Vx>U>c1!P=+6yt zbb>5my3~xln9J7Ltxlu#K;roSJyEiGgJe~Wx(KEuc7me@R@<(aBbGf~WN*qtfAnv> zVuN>H?K@|3=-6NS%Ahku+#~>nL<11Ah^C?pdsX&PDfh7GXMPBV%NZ`ZJtdxbH2Z?c zL~DSf*>ipgS@R0DR?jj&oe5(n%g&3cAARQY`U(QoSJ3#;?1IXfNY%4{`AeJ3FwN!B zzYQFD-5OiZPVX80oa{LC9yENE%xb);hY?O^Vi<1pB#)(8b#Y(NB!>SK^-Y#8DRYXM zLQP(Sf0?C;ne9fZi3K~&7G3=xfP|S=)(Q$ELQ(=egIn)oQe7;58L*-GCi)(^OeDrrI zk%8u%FL=#pXv@o-$&DhDQkS^BFFbR)Muoi15j)6tc(ySM$!PhOWJHt1H!V1{V)qfF z71Dqtb;$H8)8YgM{rV*3r=@lJ`*(oATMdWX7(B}17n&CLX@~Y*#cVX(GUWgq(Qpg6 zShid1mSmmuS&h~??>rfPUrJy&gKSe+h-bSD6%eb{KQ>=+!${7p<*v|rG|P{H03Fi= zAYm*R72~I#3U$Iev3+3%%$4Wfm(_ep8=U#%uT!lqq`QZYhK~-w#|{9UYBd1T8u3&M zyKYO83tBqGf|r>x{jbm^KKp}Ifg2 z4yCa}u#ZWH;Nm$lw?Wmr@P#X*hnJeNm@*MxLt(MW2@TQHobdZ3X=eW!uUr`R_|Mr| z7rrL-(BbEj)r}Z48N<5Vv4}C|tZSAxHKWx^EohbETmr>8FnUK_-ripB&4ibxZmbyu zexoM!(M56K@{?0#(e?tADeo8`QHWGfOs7DJtqi|FmrYntBgKuYgMbbY6ER{dE2?C# zPBL`#DO)<)rTGIa+8{(d)<6tmK$N24M%J<9bRL}=kJc0M=q!$*_b)Dfi~-m%#;zI; zoKKq23o83q6*1_c3Fnik%Q2oj51+IqB1Y5zDuz!;8?V4&zR^0NHLMZ45!W|pC*)~h zonVbpbCR!kBp7Sw9*i{#bd)CBW|Z@%KuxybGHUuN5iC&PLuGU4EAG*R0qj0OXb<6K z?R^#JN*YH9p3)ehh~ma%kBaBNgMo0^XLb5#&u^l}gx|2N=ezWQQlRW!Wr#BDKSJoeUSN(ZvrayMC{ye#Je?swP`V(q=<^8b==#T$iS%2(Z z^=E6QKX$MFe0t~pgyPHeC)D`L`(qW*AOF3w{@AgnA3qS6!WoZ3MXm*o>(s0!!S%C4k$Mq5(pv{_WxMP1SwHcy18tJ2}xCfX1$Uro_$O}wNo`6XL(e}n6i zSJa8GcU|&|I`KDOm$bR_SEx%`dsjABu4vu0yDq7?Bx?wNRXC+j`-^rR7?AA}RX0l| zOq~l2hd;T{;G2}A$uQj)g9+d%9d{gGhR90E)VA^YS3NUI> z8;HKE=sc3!0A^Z!)UE@Ve92~7t}PkzAMl}Dca?VBn4Ef+PFr`=>QNb8`HtV<=xMm9 z*D(47APp-u>-H|~!o;F%NJqaJn3!aP+L*|OU?R|hLdi)?HelUoDES73FOvQiX**gG z3~9Ss5&jlw+mI$nV@PXHQJN_PnrkhiIp6sU=nIBGp95cS6SY=V09FFXrl}b-f@8rH zyZ)O(5cC?;hB-t0P3<416ziYS<4bbcU%e78s~u&d{cM)@UxxTgqxg%aV}sJ>j~i!A zcW)@v!{Otti34-vP;!I;{^Gy+Z?`s+syq5uVS|YxJktNem(Ei<^3v=W-fDgfmTi+_ zQVa1VviH*|k6KK$1To(>4_LH&`AE}Dj7Q;(V)XrL>eifdcrC7qBCUeh<7S`s4)aF2 zO@3oXvp0sDqYOgEmMMR5ZW{f7ff_tZTYruWd+EoaozR?d0J5E}Vw-iAJJvpOW z2(%%#MoMs=GQK>9kB3s(baaga0WrlnwveLf*w}SH}l$^-h#+f5|(GZ}{Y& z;S3a%N*DwZ$=Z(hUsvZi1O-azSkm_vV76a9uUN;B7OtFA67M=O+`O`R^T+ZG^XP-R z!FdJ4ZGUXRw^T#ik%D}BCuoD8yX47*HyFqF;jz{o{i^o>Fc$cqm~bs}`&^J_4zGi| zENPg4l+L6L9JBSx`61!!AOC^PO|CSagqsn(>);OfA>>@`oKQ)~Jy;AxgGH{u!aU%;ET8wUe&#Y-_*2MRjHA=Hz-!puQ>WlXZrnNZHL6~`W z&?ZCJoLU^7Wd-%z8&nsqAkv|{-@EDvxaV&PGKs`ueC*f^CF9rV77M{Yyr(EK`k1{P zgwSKINmfS!T^lPObYZ*C|BLd-NO4o_F+RgFoJlxTu-KqFMbNRrT^U0g7#q1ovQ}Kl zP%H{k4jof%8flI=R7o5P1I&j47f=mFZ)PZZGegm16q-ZP69a1uMNbT@F%&ulsyP&v z{Lh90Pf451chKg{Q1oVpqBlDfw)eXmA=0F1k;gSj+PHy-(8-z}nm{l{0To|s9K8Jg z!lo7{^VE0;VSsYbTs*1zs%l#G*c%zxsd)QKd$~Vj{Ic=Mt@-pnqJ%sxct0p^iw8@xqPSOT8swg z^?yNI)Uo0%`|wq{wOoB%&jL*tU_W66&ZeyZlp528#M%{(&4zbXLgX88hru6xEOfK_ zkH36=GpY7gFX*>ECAKD;0rOYlyiL3^Vd6fF>d98Nnf#Md+an?+~+$s@fwW+k}!ovR#~7ppwxllLM!ZBXq9gzj2zCR@BusW zm=dO><(kkrF3M%q%^5R&)C$$wA%TFdH($D1d&&G!6+GhNL{~ol`;9smW1XYPmX5(F zkl8s#{YTc^nt)T%O#rc~Mm`8!G#170lnP^~3llQoGe^5<1PZIqL~9Vq4|a382GJ-H20G#Kf{YAd7&W@DRdc`!ZAD z{EJ^X52%BB=@~)g^$Dbsu{(la82F(hn!iXQ^`k0A7h_L+F4;Vips8v|vwJe8f)NhrL8gW?6zJI$)7m4pzx}pd=^^GuPb{D7>tJ zv^tT8KcFB!((pa2p}Leg8$}#-@quUp zYKRL<0J<0#%)|G-v_N^K0wX)NyU6%lHW9azlLC#9k$)U_%9u+`aB`52H=ryTBaVWY zKxC%$!h{|i)B`Z#Pz)n|56NI?UO|W;*|IE%72Bz~s+!qMIR*JKK?x@-@{qKJ8med< z@pqtp=Z$2Rz$j|#Bn?7?&=cJ^=7QZfrVIC0FMI#uqf9|LduoLTudc% z+o>~S8|9Vi(gksRazM_;Zx4Tdm*5gmYi2H!U@#ONPzQ3S6TaDrRh=E8Ni5qNI!S#x z9eBHvu4#wOmbPRwwCTBfG|4A-86S<16FXV*z7k@myMQw~WsFp$WCY6;q4sSgRcF20 zX%r$!{dv|>g1Xitc~t8frq;$ZJ$w8Dndn*}2)Fe_)a!i0+KUoQy>Z6`(?rcPhG!EP zB9F|D8F3+bxAApwqZ^}K8Enj~6Xt!KSZ+m9H=q_%dQ2OrCuVqFuL%_a1>;BjhdjpE zcfzr37ZRK-H6sE^xA4!b0wF4A zVudlvE#(D(BYzQECe2`KvQvXjFYuXji}+T(Ovr>x@9FSIx)WieGa17&fzN+N`9no5 z@n4)=WsIoGL4O=rAQ#2RaIb~vdcn0u2WVtu8vUlAGZmk)^!>IrN1y>7>lydLw6$@3 z+N?~;KB&sJ0y41imxQANnY7*YGKG|*46+@vaF*UJg1SE6jdz=2#KEw9bq)8)Bn8VBMYikIw@eeCUyRWKS6Rpe7gRkuE&`!FWRLYLHK36)T)sP zwCefK@Qz^@ux#nfgD>!4^I!k^W^(qpFuOH(QiP8OVzR;N0fp8wDsmp8uAV>3i#paD zUo=&yTmNn|SE>`rFZwID1eCn6a%=WZiuvm8{MZ<^91{3lc6-@grC79FJ^91bRqk7ZVZzi)&1lp>6etUn>lwx+w(^rxUHru7yH4ZTp$&EL&i^Duk@DIWGY z7|9R)AqYB164M1Snke4@t9+`R&_+QJFMM37fM9lS=DLw~0h)l(a)K&_mdjGxDjED; zolw*~TvtatYS*P0Y~W5Zo>RNL7d?0d98<+3QJkA$a&V`HN+E}2|DR!uHb-G zQj`|i*>d?I4js{9Cdo5d*8;B<+owaSmlIxs%BR}9L9EeIOWDW)AQc7&yGh- z1Z^&`uwkJr#Gv>q>#7(?$g@mF&ma+*yJU4x8eD3g9o3{Us>AI{A%d(^ee}OTL!)qf z)WZ5A6|Jpmm};ozn4IQ&AM519w)#DTR&(@yh18?9z`0(+Lx zQ`v+GhKJULJ;+*|nx9X_<_fl<(>1Jqn(CuGl$_lu3`u^8#TBbw~-HHT6|%l5@kQ-mY2 zEvrXSzseqFw@5TaILM~xoPDV1=?o-|R9|G@r(Xv30@@+7*akitj~1Q~_Ve3RnkhTD^Q_6w37<;sV|-1#5(@htU`TO(J0LT z`=CP!T`%*(enzQpx&YViVQ zK8L5aFADSv=F-K*vzQK$W73~Yt@5n|Z}Zf@*#eTz6uN)-=RQAGrlB$=_A3MP=~*xV z`Xp6^CX!a~{nIiYX&y&mMq?x9HP=j<*EgsFD(KX9P1`*#ADXqnzLRG|a zVJ)Frxvto1>WZ+|&Vx|01Wph8VwIcO8|;+>-^v)GaM={lNDV6;j9zV?`Cm4rtz~}Y zcva(Z(&*iG^<4v5Dt9Jeu)U3dMXJ*TENP%Ow-N9(Rf}k!YY?!A*$CK-zM`@z`sMgP z8~uYb)N6;;dV{mntM)EKyT;yZ(xgGUw#vCI=?Vp#xrh^zQWpF|8l?-FzfmY&{%H;>FhcV@bT&GH?2# zw-NrML25vAjR#?BC#|K>ap^;B$N*F^IAM=DN?OhL)vWxQc#m!jP{dd;aU23r$}onH zl9`rzXOEwG@sE;+S+5-5JiqthhmK$R=gHA7bWiSAZF0W zYrZjv4|WwbWQ6DS##GgKZl&~r-}9*y*ee!#5sZHElI^ng!qp)whD@fKc@+WhR@|=K zwdFthaf#cxTHL;jmQ8WMNI3fC?_r|HzB?78v(xL%DMSB@wwfPCqtNcyc=02GsrQOt za{QYza~XVp{$Hwv;3$hu_i}oDWi9;Nl&+`*(D0UpZ2IlPHp6yNQl)f_RE=Bq&?c2(+|y2S(-EM68x%0a z&`ys4CsrDVG2Mny217)RUVcG#V%;&q--sha()x(b@cDj1X z*8QEc&pG?C_ImHN*GB!8?F3I)4Zp%OA-B(koF0&u@VtI|_@ll{d6A#VRY#bR?N*?g z)GXZ0f>i6MGjp{!_0HIIHWC!Dbo;LdP`|n+VO)FP+Csxu3b9 z64G2_IxEZO9RD`*&oXTia(DM&QYCO4oSBS$3+=uRG=nh&N7yPTK2G%M?F%kT$k)cw#aHQUqsg%joTs&Kl zUV!afO+UA35clfOo%h{WZ4V5Ke)ER|pmvtaAo{nzOIP>U#rCl6@Vgk&V5_Rxskkw2 z<_+*hpwuk{NO|TAQ$?e6dpdADo4H+Gg3xEe@rH_|kNSxyLa-R$_hiYen&NQ3ow-2o z3;YWG5B_jO{A0ynlMw$n`o$Ed^h_|-ib&n6G@;{RUWz*k$WAOL1$bFtZE9E1l}*1C zfElJ!kElnQhHwpxWV~}>>wO%1KQAzCIb6v@vW<$jg}KA}^LEWONcX<5T|n6)U0@02 zfPxu)xlvzku#@-?cDB(re@j>sH3A^XC4}$#7ce?mRNEUHvpk04iNIZ}l`}j0 zXsv=Ewy2)90@jROg^gM~TPp;$j;vKDto^mr9<155fok;?{6=#j>s7akp^;Li4)g&y zEO4zH@NlU$VKwZF_}sx71?jH2i=da$|4DO9sD+rMs9ivrz&e6mtfr2YkCN?u?}u9iQ+2<Oofmawy-vAzCp8zbxWKOKL6C;mQbvA70S^o8Gby&rE#32&p0v!(m9 zsGhs0Z2waeZ`|vDW$5d_^*j3-3~j$|zipR!1+b&gm==WI_}!sTG7D}-@IXkLf$T(K z=rXxyZbzqsI^kfYKxJGRo6bC}zl$$xmTcN&eM`4zm>zUuw0_l!~bw>sZ zT)J)`FQ!pE`}nTm6X`_T^*P#K#e9m>R&GDIfN}JnLV}kcgJ~@t9R%)W3scV)5^k5b zcoPx$xIVkm3T76V#_GC`zNaGaeKB0q%(;q~(48F>&@>X+S!(#{VsO2FpDG5g((jYS zV9XmlTM+T`e)A0C?EW6JG29Ac^T#9AE-l@aVONZ|AnQK$DS-G1rZ?;`K#ZYt4R*80 zbb^JhSMz)Ey+;N&z{7fB2g*f0*jzAc{-5TLhBsH!TDn^@R#@`tW)wwxG8UFh3Du#) zI4_p&W-XgM=TvRss@2AKFcXfnTYd6;Nn`eq z6`0Sto>ThS+@PGwLCm$3^OMfi)N$nCru1l+6?zTKTthiOQl_muS`MO2h^BfSJ=lZO#FGeHe{pdzy_|uWR*g!AI>S00}PYP6CYJp}uwja+>=D5dnfh zb^wvaZ|qZu=nxPzfTRIH&;ZCbegPxI;RA~n3d~vy1hXO5`RLdC=r{Q2U*`aN@jyVQ zNXEy6kvcBd`aDu_D!djYhm*`ucXXtJcJ)rzPyQC7wf`SIWJib^OP-D;psU#n9n5y^C? z8os_kzCC{0D^Fk7pdpbpu~MXMoB?=cz{(Aik#R!j6SmW`Wu(R$So)9bU@b%rn-JIC z%;_6^KOHuUX>inT^A-*gnjQD3*9A(6-2_H9=95SnoSAz>bWAn;Tzy`lgLZwgQhj2$%vjIew5 zxzLP){mmELz~T~!Cc`F8!X};Ns7>^W1+w$b@g+{tMGX}JWXPfJy(57cx|(u=Zt#HP zp@mE129*YNgq98V2r6kq=~URPFr>8-Y-@4eO#+_DZ<{FyRlPUAw~?+QJc zR;!cGBd?cn7x0H84f1KAN+;PCZ#@ItEBYh#lrHgtUPNzME4uD6L4agdbjkJGn6Yt+ z%6C`m0F;J--mpl>qy_MfuyU+Bj{uD>nL)N zrY3^6Ps%?8-pQIIFv^}+lfDTRvClW^)tWlj78Fzo{p@CkoG;6vN#EvL13wB}1$)If z-T`h!UxbcHlrW}_MIKh|(ft7G^8>06t7 zV9W5Q^%R}~fI%x+zxXI8^)vqtvoCZxLtlpmPl#kyvd1iTUk0DSpt(10((p?&hXsS? zx$&cB`0}aqeZ%?OaY}!-hIyrR*a)wiGj0y%3lN0D*)5;}frX)>3F(jHbb9HYyVCAs zXy9}S#e#qq&vQ!76EJXsc+WLhLP9iriNaA(m35c^7Eah$C|Y|Lcv;_bq}j0sg2VNU z&e4-;cb1Y1#$%p}8o^pho*gRbQ{Azrx_X4RDtJlaO#13UdneVSnonBEld)#J&i5hH z=fbu3!BXcASHz%hjXE#v{JIF-(Xbe=lGYG*rUHpxg1nIc9IHNkwSREM9 zjpE)krP?LwXn7PeqPE6I+jAz+yHoL9ytS=$0xEt1T=k(C3@e}5}OExs0Y=1juCqIV=>&jvZJI1KC=VGJ2nG01IAnm5YU{GO0rr^I6a?7Nh!`gWnLu=q2 z?u`q+J(jzxht}X()ELLVs?eHA4fN|9T65vAKRpx`cKV5{h1NiZPrjI_Fj?YG;Vb>> z3=8XHr9Xeji?8JuTC>x{hk$Pq72xiVh;%bfUHKS2au6*hkBzQGkS9y?=k%@=fYpgl zOWt%?g@-X(PnIr015NTCpX(*&+Pqa#yoblzTQO2(|IWDXGE_ezW@x11RExzfuYZyH zZ7msLAZL@gPgk}xyyA1Eb`WhV+Of(wy&JVs_yF?O_XDlYt>PeK@S~oth=W}4J_hFjL4{!zWentl`s1>%uuT$<{-AcG8Pi)J7^|V>d}$N&VwV;SvWhvz$y4{~2!ZuVBvgLl+ek5CHj=5jbguOupcAuiS% zIX`l}2es`a%M^q)*NP`UbSsO0E_vImm%{Fjp zvGzS#cRuw&v*2uXnU`2Hqer&rby`oHo(}0O-&^67#hV*Z>dR=2oHb1HQBdn2CIyIb z5Ts<0jPzf#s&PmGQm_JjjQLG`I2qyhM^luJSe-gjaVTs|euCYbGpFV|rp(ivL{MZz z{9W-|&ws+_#n9)L2t}AFmYg*SM+^?bjn|eXg$fkJ=#=B%bUOT0>CqLy&{hGg>z=rX zfIQiFtQMYCj0TLE#qh|17FS z6daIaBP>jaL}7u-_d(<4Pm3ON0 zO7(D@qdrT2A`4Wfz1wzjc~EfDpv`wqduMZ4UmN3Ny^;tNttY7$J~3Vgr;TiG@jB#~ z#`VizxK{syM4U;#a(8y8ZQ9@ot4MNvYfIVt38-}?%ZvN+xRv!+@Je@!p{la}Vq1te zF8inZ%0uePE$qTHmuCr^7BzcK?wcBu9%>I5n7RGg^d3vJ4vrI~vZN2@;3G+rqSn~Y zN@SQ4`ck@B96(dj8Rm%a#Y}6zIyRY95fG1((vwZgt{|u}yCRc)TrOR1`eX7Ld+?f-|YWd}qg?p@Szxd%b;{K^s>ck{il3jr-A9 z#mtT~swUP$;|E_`CFy?9$KM)|1d7)I0wm&DoRxmkdr1?F-;mym3={?uIr{7^5Z>N$ zpDRU$<|uzxrEEGPlKxMBuhFX?hCY&T!{&p!@q!B=36M6MMzBLE!ZgQ5-Q8SbA-AtI z!}MvT6jA6gJz2R;%OjGTk#&qQ&oZjK1w7Sj$xWm)B|S!%;VJFA5xs_Qf?iI1yOD&y zohunbKD^8K3Epz~UXhzMfhEC%IG${mAwLUyJ(`mvB1+sCG}9@bRBfdbeFKP z703#Wz}1u7bb9c7n;jnpNKHbFQJE#0{wFB?wf8ss8<)r9zQ@NX|6l(CB8XQ1NZj{m zgF51gGRA6zuqt^@sK2*(KsXPbFE9UR7~L5mJ*B7gdsI~!D=TWm4b(BT(Q#B89jO`% z);Bti4sCP`*te zdYS$2tsta_59I}>n*K9skfK5Z#6A> zMZkm|ciO);&iB4=jfIWdXR-uW16HrzpfyHJF%QckCB(5uSZSGfMA1{Xay1>pvS!{i zGmg*$p&o`avzf(2rv*1wt68H^q7v4>wC1iDtu_2AMvK%S+5)Zqvq5FBzB~}t4>nN2 z`Z^zMWSASYWy&WgO$*78RqUP4u9 z4?8oG3!atWMt))g+l&1(KLXB4=srN;n0}AvgDtebfd$gam$Jsx38iuvYujckP}}4z zH%#vD`Oe7}U2g+Id9WrZCESnOw#5l6cmY`^h1vIJH2e8QD~| zA!fZ&u&9vK9?8pzu-RgCQf-apq9Mq5d%P7DLBAp1ijE-ML8^p2;;Ih(gc}^GD(;N0?LSiO z(6v&RfW*~;Zm!`5{I0Im&2`*>`qiRtc0x@?7uEIL${N@jcIsz)xK2MIT%(_XOaz4^ znGtb)n3GyU!D84Fudel=bIKMx1c|F19tXo!rD%k+a!|1HJ0?18z#%B8J6$lSuU$B3 zAYDK($POUV_#-rcl0iW70stBS1Px$o;}Y>+$Z3jPN3O5N3!?SHvW1>N~ zTQs3!x+Yi{v1Xc|7SINh7S0B)7R;l=_$ELZgtxH-JKx0U2@OF!L(X|!PjU^|4I!`L z8nD}RT*o!7+jQ)Nc}ZZ{gb0{dLpq`e^~$vk(k%oFFr;ipgLGAcbn^|;!7n1bB`3s1 zHz6ZTXl(Qty>!oGqkJ)dO?M5hMaDVNUk_KLNZew*hw5zz>%|%@R4=~ek~r~x5Zi@{ zbAQ0y${1j=y%jR8CBN6S?$@z3cln;)F_+*xw>2$McC%N4xB;xgyIo%{1Nx0YCV-uOQ^ygJDjOEQi zFjVF$fD!(bwPztIN)uy(Tg%6-n{d7HbsOd}7(rFJw>PV82*{g^Z(N;)ecQFoD-ml83d83 zpe|MrM5lfO$VI4rWAm{;%?C^?KDjn*k-D)(>IM_co$;P9FDt8Ic0KCG(_}%~)({RT z3&6A+{8F}A$!_pJy()^6QP3-FW16UIDy&zmXg1x~JVFXB`ToJ0#(u|aEO8n-!>E7CzVB4X5jryf6x3560gS*3u- z9Z?lZeP_?s4h_zZjp15dT1}B4v7nAD27VxcQHrrEDc;C^buD}n7@Sv-ZNAOk71>N*^~C1x?RloL_1VZKgCNqVsp5W_B#Mq)3cs%P^PNDC~8%^tK1$ zWwMtB+Zi`4N3JZk)-<@8o2H$u+%%M4veBWjwjjq#*zw|E*5@E>mlf(;r^g4g(&YKk z=IzLyZBw<1tUtSqMQ;MEa|4*~U>16Z>=G5z)U5iK?jinJburyT|Fi04x`zeKiY29c zxWH_~mFX7xslrsF=`qgijE4crGpt}hm&OKD!oe|+YdExU2PMOyh1XKaaA=`U#uyGQ zRP0$o1|hnf7(xd{hK>T8!bE(i6dCIGU>)cIpO!UJ!+;lLbV~6j*j2XV)4MO89 zn;EE#La;7cJXm$4a1dtRY*Z~tXA@z$D8_V$l(iBj2IPoSYhmfuL7(a=y61gN_n?M# zGu;mhWbH}dIRYy^rzHiI+WB#_*rmeBO<}uub{2u`#jp0y0de-$||Bw+k_UhrbYfbk|EoE>cU&>4Qj6{o|f!v1GshzVRU zhPTUU2A^Injy2d2F$TBHSe*^D$uxiKU>yjx8chQK&FZjDw)l`w2LDe&vjqmVC{^5b zKraW;gz^E*8Y&0XHc~EqB$anPGt5e?xy7}G!9W8J%<2e-Nt|*ev5T`Sac&qVTZNEhAQ3OOVyilawo2kC z2-DN4ccv%Gowh-oh4~$KP0^%^NIYtaqF!0A36PDZC`y*5*nl)?iqb8mDGu5>HN$+B z-J7N;R_jf)5MS@we;;NduGBCIF{4IN#N8pfi^zpy)+maA=Mvp>JnH#dnXfHK=h-k9 z^~6@s=k%7OCnh!9^h7fYO-TbiS`Ct(uZlnw2VkiC6B~d_$0rry4@F{A)Dxw~IRi3$ z9aTi&rTXH=MiE3`ytcVPU)0WMS4`0tuWxS97Z*W&>Y9>ZI0CV5kgB*LtZw~0hQeC5 zkfvhZRCAPXg0|&dA{~*L1rid-7$)1c``{=-$DetmKtQ96aZREaKeIxgUEX~Aq zy{tCfErB80L_QgArD~L25=c$OBn7TH^aeosp*P@a>N=W-bVKq?5rD>lG}U(7Ej(dv zY2uI`0ei`E0Kv?ZoF6sNs?k{3-v14)B4qLdZr8fIozq#Z>U>K)X#AF=|7>HjK`G@6 zroqY731n-m0VSCl$L&D{EH$5c#PF5Vh#LWH5a=*>ygFsBxact-;4zP3EtYba_jn!5 zhMR@${7u^+RNG(`PykjB<%|%9DcwsEgjOlcM-o?(j^V5K5V9O(-_fi_q@{?7!!Uo7 zkfXdY@t%RUW7vU-$~L9pOv!+H}w)NfypGQNE^d(OU?=`xe z{4Crzx}CTO_h6#4KQR#Q8{JMkg!@K-J3Q1O0TQ?{4)p0{=CQ@?E=}t8lxltZw`ivp zK-x~SWUb49Id-~6O1TaSjX8#tLJrwVO2vIbze*>r^EDpMsQ?s}PHFa7O$+`1+m3@^ zzV)tUFdL^0^=kW@2>gdt=@&&gXU3#STlKcQXz3)#0flpcFCWeaL9esJs6J&ITYk?; zA$HuC$yn3SG8uUpHH3o~ERj%++Vj5F8j%n`%~nmY~N}>tmLpQPrwGYCGR4V1~x(6GnWu(~? zs5>A|;MFgNvqUNcDZmSODX)rhpdkmWwbE8yIi%ugVE_rxaM<*WT7ZR32qvx&!Kg@_ zi>jZ-ROfZ+C1I@p8H>-L_-r0mHjGv)DU{=+KA%d+IR$b;F(4)rDdW+qa^cFin`u~{ zBB$%fkr0Q5uMwfnsh6b8)mo6MA|3kEq!a_OwmNy!=2oafJ@?+b#lIN?M0v*EEtJEP>IPx`lcIHI_j-H6^%Fsc*goTJM0Ofcq{s_ah8%KqqalmWMtu`ingSOG1mhL z2>dCOs-?7J&vX?!#Hc7u6~wWcj|_1-HFYqf(kZrM2Qr4T&4N1hJ4hdt#J3z-p!MY} z$}v6@C%^%v_f>gkE-?->xs3QSI-6+Ot?UPbHZle zM2}gzQedNcsA7TGOIMHo5iv#zYb;bU&(EWOZzZ!t81z0|I|+U z2As0`sa$PWmdQS^ciEUxai2_4i&G!gFwhmX{~!~g@p{k-lToz2$_RGdt#X_WtBS0! zwfs_=GBT9E#MlwdgJ{;xxxAud+D^_JZ=DPIx7k61uz=1N1oJ8W=Sp92$b32VKeyoJ z2;wGyQlJAkMENoN9&DliBNE5Teo!dV)C&#M^oD@7KEA6nidCkV(Y}GNf29ATCd>=S z%qM^9RDQKH#R$B6w1mFjTS22TWK$;r2$lg5xKAQ~ zclIx2SMARJ7s>A3**_=6hV@4y!m+4Dzt;0%}d9+}qVIp3Ht7`5^E^Y4p*0B-K_t=fr8^Y3k z7qZ4{NPI$ejVzp1q&DG{&<2Dem&-&5!F&Se`!pc`I-{u&+O91&%IO(7!R$ zRB3{KMktAkb|w;uymU+yU$YOwj=@~*0n-|g0f%WeB0w$HCJ-j9q2!N=D;b`)g|VH_ zN8)Eg0?(v$>o{Y0O=2c^-hc`p7YBs!d(!bkH|u@98IKZd-VgbWSsq}E0;c?Sem;cx z#Z2*sK7p@4Er6y2ePOu$6w1h zz*9@Azb}u(JX01$d#LOA&MBNPa;J|@vJ;Tl=@a>2Bp;jXnuI(|67HXSAT4cNQ82dn zX+%zlTSzN@#$2+s;I~XG5&qchD)d6-HV^&3N)Hctyfw`I)@n=^S^W&W7YE)!;m`+e z(zLm!DXqO=@tgOLS=|BcRw0Lm?d@nj_p3b|T#^!pg3){NakOYQc zb6Vr0WqW+~^3Y}*5Gki~$qw;-Fj@aEjNm}A+fl*zxov=2p3I+S$!5!7hRncxO zxkJ2kvADCsQvhY@K+r4_ml(3R46@XUV6RqWoWhIXy;cOL@wZHWp(bmTywro77cMf- z_8KVgLmv?Lp+y!B3*>6Z?$X`8raAK#9Sq_TM-3ZzatBzX4i2!NMgmXqE~k<6;*mi{ zHN5a{O#r|5qzORR(ES}1Z8S;^1>f0aLjLXH`0Z`+Tb1t47M&p#$jQi%WY}<-S}1D5 zm|fkO`px0P&Z8EDve%Ewp6OCdNCcFoCc+jS;NWqYXoVC(=*bj8w%jp)3;_Wraw}5K z8+A_PL!nF0@qrT2^CFww&FrV3Jiu$bLNjq&k!niw&I8^t(#|yh(j)8~fJ_cT&?{x? zwR`5hlUvqY-znoS&#hj>zZCvnjn7kx${k2@GsT%9X06?=sxArGi3vkxNuzAF*XPyv zFT;61^v7r5ylp0S1uEHOBOzF)G#?t1lc#5Bpy z*juTe+5VSR?wq#$t4C}P8xh+Rw_A|%NlkFPlfU~JB6+03Ql{1PaUnu)r*;>x%iWb* zQd#j4i%@8pwwgt{{0n0&i)m#!BB4|+5YruMQj6@intCVtm0>Blui~rKKm5B~vsf!_0d?f{DYQcn?^{#d`+woUQ=}+02Nqq^!S>y)Sq$LdhxvhxoE1gV`gK zqtuJF+9srX(gt=n3gP#9q*`Z3ukvtRWU@pxMk+a)(};8v$i%k_!J(GpR-p}yPFsbP z!Bbm>HjzGawxzfdx4)%U)@tK4)o)h#idOUuyGCMIreI>pMDd1?98rY^nTo?ZOaVfj z26Tyj4r5GASQ6*WiVd76d}r>6S(3B#)E8EXM6d`N19!EWEMIaN#u`?=9kS;b*2CCA zxt8Izq>20^4w1=S1*(wsjs%LVL+t;^eg8+E_J3?A zI4Oc>8y@U&ro`B#&`*nM{G=SkUJkMn#Vwo-5mmh$l3}ev2J~R49HOZx=V!-I`8c7N zl=E{qbR=~93r=<73J20L*y3Qa=mUiVustL zBb7zuf;+R$BZ5=Uz^P}4)8sYA7sB;IqjejJ-cpQ!23m_U)f`|aYfIEOt?=5n~p#hW(076nAY2z0#fVK@^ zun5`$5<$VNY3xAa+J>XN03f`o0mAhS5Oy{|SZsiBT>}KIB?R0csY;@ zl=Cx;qCj^C<@~fWAllp~;BST2w>4Wv3}Lqkv~U5{WJo&0HB(_zw2EtbWK%>QRQ1}X z2&a9-Z&s!pA1lYlS;xo05I*i~rlO057C!{;T^kbdZ6osCkqWIaP6do1jKQDB2rf0F zf7-WROJK=B6g*$ViC8`y31qiqC9S}<+^7pB9KsiuN<3ruWe`Iq4y~RP#H|TB4 zS(=jgg#9&q9dCk7O1u&EEygE+0!2#lZwrz_%R4l3M_^o|DYrA@Xa)nAgopfr++%e@ zKnkGurT_)R7*$h%9%5{)DL@?&k4yL5EVbGKn^-gx^Ab_H<#xstGpeHNbWzxjcrpyZ z<2G?P!I~vG(wRv$K%V*GTM;MXsapx}g`z=dZ0~AB5wi#a(tZU+rL&?ri`bcNb33;f zf;fhDJ(F|V)5TK$B^wpc3rO8$8x=UI6D7Qi8x<&C&Pi*+?=cpS(2r416o*gRU9HX# z;V0vaglc*rYHP<#d)Ifey3&7qXt61(A?9}08jk{yRHclr(PoPRPvRB@o@v_k6w|AmAoxr#jK(brP_J)Mn6=!_HZEJ>&OQHpvQ^h9RF{n}3e{Z`)`jxT{H*t< z)10Ga?J}=426R_6FZV1xuo&o4+RL11S@VIux=pE^xmIKYkr(v1f^1~yK`Q)YmZkz` z#e*FvdNO7gl*&05v5!Ex3r4wot#2xBs<9(X0?2o_oCGwLhXu$!u$=)k(?YElzx2Es zb6PTWe&@gpS1FG8@fs6|kS9yg5(xfPKFQwhVu>o&o|*kMcmdUaFtfhk;5O ze9~0o;1xDWerXptOt6L@RZ$IJ=9$4Df~VB*Ei;1;uXOffhLXPzH46sK`$Tr>Jdagj zwG7G`SXj*f)d<_oSAOnC2~&q zR_V+|B#ChJ%JN%@LoO%37bph}k~m3#BaYBklp47%ig5W2*NfOW-eOh1={Bc9aNqQ0Wk&@x zo;Uo;v?vRN)xw{FR>E3qEDq%%d0o1^wy=J&s778JohSWOqfa85n&`0YVlOd3n>bF` z8EOJ}WIf-z1p*srGD6* z946d&ZT@Cck(F?gKJEiA4Ai7(j#%S-9?!@Ybob^9#qaYcl?h;&8TYAa$r_KUWZ7(-Z!1NBhQ z2up2pcV=R}N$#fmB$v}Y*lcp!@1@y=6kN0)uEK)9idgajA_4~KZz;A!Vp=Wp8)d#T zj#S7)5W|aNE_o5898ZG)^~`H@*4d$7hyV?QT-(!7x`AEiv2uic_hrlghlb=(ACQlD7cbVAfJmrNeJr7Wy6;}#PMTgK9(2!1HpE0;9^*ff_CKS*LFdQLbrzi?vkW4R+%t|m(&fl$Gsy`0xi~V5iQ>rE3UCiJ z^_C-JRa}uHTdXwSh#_iq4YRXi={Yi1JLX6FYIBc_5-v6Okr&5%1+^hY(mFT`b__-_ z=AqXxV)5ExMvNpdM$ASZEQ=vV%*!n!UXT)$)}N`EjWS~7Dit7;hFG8_uVm1_T^3{H z5Zqx37hw&i~z5#9urF*~iagcwkBtEmICw2`!gy@h-Tq%MqM-UONy z-$6+XsJY!fV3ENBLKI6FBWkQeDWXO~N&`R8MAUG@2_tAEJc%;`TB)QFp&7nJ3wQ>= z(*aA%ISGMan6_rdI&`OPX4`2c8pY>z>VLl)#{>QQfA7-?rm7=A5!JE&sYk^!X8IrZ z2o*re#7Ayz{YC$Qvt<3h{sHFL{4HN=PWMuj;1e%OH2y%@>e*jK0GS;gfDbSRkeRkB zjE)D?$zD^Em1xJh-Y9L048QW(91wJM;5DyVmmEYKLV#+`} zgr=qZ>Jd#pP~^SKN(XpzAEITgkA+3RYILh)#i)qR8-=xE#NtCE==pmy5Ryf26l|!* zHf;1{Q5$B55?`2>Urcd?>2xY#MpTJh;$o(7Gpot!ho4!6$*K^WW9xX-erXTZw`hDo zR>p!|iG>8_r_dzZW`)>^Atub>2v%C7 z>k*wPC13R;64W3v6Uss$o8!gWL8K(-3vJw@X+v9cp>RkVzxiNT$BI4}+tevB(klJ7 z5N<_{-fvqwt*G(ANI0STgN$@YJ{YO~tdQNsjysb~3_9RXZbehm3lgBP7BA($i4RuR zG*&2)KZmG>`pgNVdRukSG4ucnNO}J=>9_&Ciw9er0mWQXB6CR0*R%;{XlF5Pd)p`m zfWD2!UB-NRi=~aIY6?JC7@S7=b zNK~=MJ_(S4NVKGRbCZrlDrI6D3QcZOpl{Z>w9uA7^;9nl$_^W&&<^RGzm#;&mSu?* z-em9}l0MXzyVcNzIN3AQR~FfXH`vDCg;tD)@z%Ld9GreHo57TO9^Mo8{TIdnM={DV zt7SfPlJ)eo3W~fE!lUUb;{ZxHioi5^dDb%sEjY3ASpX!ua#DiOhZYnQ&lDOzp*MX~ zMogokM|Xp#qv^OmcS&>-6|fG~cqU}p(}R-e5h;Z%QB&D^ZJJ?BRHWaS*uajq*y#=h z#;f-f5?x4$_WEBqYSLIeVOd;jY?jkVb;x})B7Kso#Quy%ENKnWVV1VFMs98MOzWqS zMOxKND&6HXfzHQEAG`jPxE_$!yFWVK(~M5MZ#4N*r|y!g?sV`Wy3m4n4#Bsx~+@oP!8l0?M1XjyXBQpBK6@T;jgxxnut?u>Vt+vMb0 zRvD6DRz=MZX)udu#CRN`-gsUOa)T$!S6ino7;>6l` zC{o;H@@6oPO)~71C#-DJ0U-2pyLe?#X5h%XT$x`q7R>JZk{Usy<7DP)phd=mp?~7TvvZy`lBdRG^u@xIi*snxI~gBn?_w z=6uk>a?H`hY9+wy4f+Rj=?6vqm{;b_z;ep0TI0>=3GJp1=*imliSZxrtDda0C+f-B zg=#%{ffafI&$k$Rg{yfCql8LWCCr6~>yunj4(o-cIeiW5{EEH7YyFDd#B2QOG-0AS z14KOr7bY~F6ZJKa4Wq#7TBr$L;`z?<)`i?u=cur4KrEtf)|hn3l!j{=#E*sor}!X%Fh-g_J?` zq>{GYmzv-eIxbzw&_SwHHMy#wPbMy;PkZp;m`jqnBppU6*A=oz@lpB)kflh~WxK7&Pha~a4?Uqa5{1|k^I3U2`i35?iBCE` zz+$2DN}-#YW-iw?_30V)5y=}-pxQ9>j2bt_XIySd&lHz<63hA++ODpj{@H2thC|jxghvo*|SsWKZTdTJVlXvNDqL~fJkU2fjn zsrRfGDq|5(78~et$|Ptflg#twl0&{DOxi=?3o<09!2X zOvFDLi61(;g!oaMTnC-Huwr>}$U*({DH1;NIUDR=fX2DTyR5wv6BZ6ydhFd8V@pC%bfZV;jcd;A+D>If@4-8Tu}a! zyFl$6a@M8H$z_gp&1`zdlSrl%crY-b>cR@cuvt*OvaI#U*kM`w<1awgKJe}36sOPM zoaF84(G>=!cDI=Z;Qoh|2Bx`kfdcE&4=cY&&1$juh+MkjVacVtx7fu!Hvgg(E929{ zQc{f1K8$wq)Az%ij8^%Ybpa>buja41F^v(n%%(j4yoF7323PX&L=TGxSHgt%78mKY z#`y*PqSan-7qMGW_3=^3A`Cg0Dwm`$_EhU=NEAKDX1+;`I1=D zZKEQh0h;d7jhPe#nZwg&aHwmEKWF3k3{YX<@#7iE;t6RW(={s|yxISlj)>Y~^;w>v z*VB|AynACtqvC|ww^TFoDi3vFMT;xiGpHAq$b2_w(i>ng}k*0-kmKWLGE6kix| zEWJ1~V3|f))0Mr@(xr?8McWf?OBa?bM(#bl&{9fN=S3`U&c`sE@g)ZNpku8T4LQ&p z?xgW*wdF~(6O~t|G-*|ea-BwfGwi8=xm7;|P-=X*@O`eO2@)S?m$(x&9ZJtPy@-BsskE>@OGx&&$R5*}WPQ+l&9WV3s`3e#`m&xETo4&{?0M^N2NjTQxm zxDrNvdV-FdXxr5`Q$Y0ug_up*kpV=e?cbn8%U__{8g^dRPjCx5Z-C{rwsd`#ns|Ss z3H3%5S1I*xq7?lx>g+x%xW>eY#%{>6oAM{bN?9KUN6u1OpYk?l!-iz6*T=m9jz4bt zs3L0L$RTV=gTBzSZft5i0?Y(OytSUA7rSo(kaex9ZEpd+akO>c1_;XBK)-IvPZ^tM z)rZxb4CbpYUFhx07I+1x zf_X#ieY_3^8@s`^U?8v?c_*Y?nXTo$6wME6zlk*D&b*n?x}*#AvHkqIuZ; zf6BB$O3RlT8F;^Tke3H|EoUU2!%oX#G~;5abNY$+SB}G^^P*+A^A{KOP1MtQ4J$>8 zi>-vMA{FSHARB|`%=YPlIE!zIhn60o!K;y z?<|}{)hafF=~0R&Qn9>69|9eoa8vsso=w`b6BI-m@pB6;knaI)y}h(!-luhu$} z`jS35n&S;ly>TSRsEh@vAE(t1?*Uk8dGJkQ)9~aK8y;7~+75o^l7`P3eevkwAz-Mu z0mjCaojB71gR@@~^*Y0-l<}W)%b@`Jq{G)%&XNOTv-+fS8K1nQPfpDpU^p#911o^> zr264KxX`ns2FS4G4eOwU%Qrl$hIItO??AU5v=CEtrERp6kyzm)H5jq7>8BbH*b_0e zhz%OP*`f?zFvsgCRl;Q6yyT9^8)ateTV@p3piWYpk^W_CQYpyh61JM`n_Gy$SX35P0|TYZa&A*pAy_o>vL>1Xq#QStUP>Q5!@t<#>)rT6yow!JWKlFh24 z{@v8-ry|noe7#=Boy6WtZwy=AxvCRDqMqm-`MP$2NpJwZa$SfMA8WQcM%Z?9iyIus;G&WcXY(lIgE~%rNcxQFNh9Bg^YHHE`~aibh%f&BS|2< z;vGq{`W5d;lFhGpN3>ihdU?e=qSeW7h>mD6^c$ihT6_J5=!lkjzacuJmE~`Ujzoj? zm8Y6$AHVV)N&59G!AHypPRgL72!tc9261izhM*iL=$=sm&)4g|#WddNNsuA*k=8g;v2Yc7zxnLGgrSSvtWZ}qdCC>@4xSZi*J{y+n;|H1nwJa}C zCDUg|G{6?TTy^6FHwRcUTHK?xU7mu?VaJ>J6T>&BH%n7EMI-<|nQLOjTwY7X78+pB zaN%4RpK+-KqrQx)@96i=_>9Zzhn~^HS2d|y%lan`)D_?2#&1U*-p3+)CjPg~=uMSXFaFP@W0 zb)L6qV~I<50#vVQ+SfCB_S*Q2%h#o6=3c`;bzXIR)?3=crJMZSmd?=9XZ6-;Z|U`1 zy1ifRO|{uGs^1r%ak)P|Q%mxSomL%BcuQ~K(hd1;OHb0$6ME}}w{#v6r8jaJy_^S9ZT5`n>-dbzgXx)C zl6P-ebvzCt;p+TmE}ee6V>(AmkIU6dporeOg-fUA?psgu)?<3>QGe@ATsm!c-#W`% zkLs=G{H-^08M))Pbl;Od@;SYCp7+3wLm?$F^&&>{mXPwxF#_Cz!UTPB(rf-!E(`;f8L7 z&y_djNA+0INQ~o#u#~>GA}U-8uT4d&@H{&&ZOQ)`z5v><4STv3ewGTKLCVw$@uI># z;q~cjE26^JhkdC?6`rQTC-ub{uW(;@L$|^wsPK#)6K$jl-whXoldidsWD1B{3RCp-7B^4PA38A}_4+umMUwuosreUWlf`?ucl(N~msEQc)bwSyh z+ajvHHKaV^hGM5YGEag1^zv=to4dVyoL-8e*_Ow{Zw|L~A3nyz{XAq-Di3c7Z|XjL zl!xM5OZMs@$>yHqS@H_ z+}2pcAo+YL)ZNdI^7(QZUK8FNKYv||R{ESEB;3u{hPOo2Sqv#f`1K9$RN>b6vEj#o zxP&U6MT6Ibw{;u58DJIRTZXY_zb^?TRq(oDwAtgDTvVlC1w(kVWcppEnM$&Lw`xOS+361oDaAP1#NY0A6*Z!9mK6 zwUY2A1Mi*XTC9ZDRg5R=F08vTyOlRSO<`iFR^>8PzK!SX^f}DWq#}DVQEf0GWi_4W z&cu?{q={!+-0i$gLe+bC`%64eXls?8FK^1eo9FBI7WeYAVQ=wnUgHq7U^3P!g_Q)8 zs;N?zjf(qtn`EsIdPfm=O(_)xX3WNeEcYC#d<8dV}M*PwSThmx&9@>Zf_r6cDSK6IX+&9I0kh zjsn)qIkq=uM2BVdAMwUgx6jMe{0Dkt$KK)@{Vwb+&g)I$3xg?9R`W&fOl?Xvvz%63 z(0ho%kaW$gevmuUF6}GA%7f{Xc85fCRkEpLbYHPtP{$)Yxu)Bz^TkcsNA(0z9JXrV zEvtWy%Ov45=?JDXvh=5i{~Nd4{Jme`^14)6{qOxfEfMNH^j)m0{`bh!nbp6jJAd#? zTqf3()t~gQFdwqamW;LF>{%pcHcS&d@QX25qFGX(8m%Ay^kB43`v!6GJp6udv&a!z1i80G;s@=F*b) zW-r{R!cD1=v=E9ju+%ymQsFu;oY0$-snB9XkYp;Hj)etrce;OBSL->{M|r$w6d#}% zny}V;qW~KgU4se5J|W6ZiXKjtPDJwqqZGx6W-SPFhlNTQk;-Kir-){}DV>OB zHKx$4ZcOtRQhK3;XH(6V21P5b*#C;gIeH|9HGgb`lRBG(g3IJaAMq!|iV?%818>>h zKJI~Y^|<0Z6v{CmOsBq=P!DF1fT*H4AaGp#D+C2g(ieW2-*h~Ap(oGi$-vISI&YV( zcq4Y~k^@EjebQzqJ)hmlyECGI59RaFr4sx-^0Cv)*(VMnbe12RI;x=55uG=3(9Dt% zvuD=%hY#pY9ltrE2;bUn;-h)9z!=7*WsI z3RZAh9cOH5pLef*{KLpT4hvwz#Tw$umzC3bL@MQaek>V)y{Kds?M{m@vOC-F+bsO( zxB7QE7{x=OMzk$|r2dUgK~TZ3wguV-_y!K8hD=5j?AaubA|qp&GDulqA&Ic)|6S~EVVab9WB+?O zC|ij)*bw^&@v~$s$_>-UKw^?ssxxCT_HUfyUxey{B^_194a@haJOukmyunJM4v4YC z21FbWVywr&KeqpnVFbj{=0jqpl@wd%QKc7QOZ7Mi zwV%K{a>E)2P*-PV9Fpf>`DQf+LX0&uaz_}EPCKiBI^$`H4E>U`6d_fs&?4*m%&O7@ zv1q6)C=ne5Yx0mQQ;H#XMoe!?N#3a2^k0YH0`(?#9vHfP-H-(@iTtC$+Had#G|nWR z*k01m%xCj9g=Tj<0GJi`0*HM1I#X1gv5nyk0i=Z$C&0PnXB;@S_EZ0Cn^{Bz>%7Gf zr(FOGJ`zF|3z{Khu`?2J?D6N>VxW*FI<<1|T(d*qBYF3X>F)SyW+d-lK7UnJHYwl? z`CyVj9sE#hfFFjCe|vY#u^Yo172y8D40xlBLtwV02S2>>mQYHYgf7oJ;2}JAjA)W{TSRznJnB4Rzrxy9=8wOT6y8C^R!G5TMyg zu{(RbK<*8}!n(j@o=(B;-i4KObhgfU)!br+h0OQ;lMA zV(MV71T!daGe^*Zkkcde*(uX6peHZJM=h|b#>L?$ND{OgdlH79AWOvW^-UvWyf!2v zXWH76M$9l={AwJ&a(c!AGFkUH0?Jg7i6j00_yLBfSu&tl{vv^B(ozTOYKjOm!HMU~ z6N5>rf1I^f14Z3?7h9QIIGkns8}bA{Uc^2Xz_28QT-vArk($oE0v;4Ft!Y1~7ciws z=vwbjBcaX`w(fHP?ljP}2AkUTBm&f19(oc1>RlLm5&`Oc8F~@{swa(nwl1Azvpj?V zpdw*Fiw>FwA_Hm8xL8ke^o0;{y6)@fEu)qG?|eUCj}r5cR76+tX^&Z|h3sv6ru@^# zRq;tXwf2N@Nu=wW4mupODyn`9$y!CGhqTaE5#JM|-wazt01>rms0jQ;9`JN;J=kI_R3cjXzd#yd^pGsSIa397RCBA1r6DyvyN(5DAn*aH_&_h3rQaqcYF zgWWyIon>;cJMb9?X|xSc1!NSMK($nEv-AR*Fi_g-P>iXdcC!>w-)=BpY^v<$G(ERj z(w)%mP@^~<68c=6Np|l~j})>ecF2~L54#acrvIZzHkK}u`S~ne1z^hxZY325$s|dI zS&=MVjy*R^R|wABb|sd~*l6jJpW(6+i)Dc%vB;mZLSo&j(OuorJ=~F3N7V)7)xG>6 zt`1=$xT!lXX*Dish3$>u>$dKAM_P$unJhT6EI9FKy*V;$=^jc#D(@6%F@izJ(8w*Wf7`tgU%}Y>%`5hYN9xjSb=WJD2s!jCc z2p+R~=s6ncBBX{dUQbcIK}0cU$3<0V)jF3k1f#~-lIpc0@YIT&uTW&kTei=f=92}2dhdC-uqsRy0Wp+V5_4VY4VmRWK+EbkqL^U} zWOeaw59cb`lW0%=;U6+7Z3S*2e~#&^)df-xW}ZV*Cve9{#k=-q%4=x}N8?%p)H6m+ zB@IX?WgA~7!ES#54JtV#rm>EltT{uF_rO_fEjlTu2+xVZYjUtMb$CVE9K9UghK_|H z7~n!Nu>^ZtRj6U68kFDSu8?`6U)2GqkNO^cW!JFHiA_~tFO~IpB_6p1+R{J1InqC= zkLZ@UUXya}-85xcbJ42oO;+^3?c`MJceW>sRB_ojhtRk3?Es`SLL7pbl6J_3L-FVV zVEVyH9S9_S$tS&(c$|!y5llM#pj!htq8gNg6Xze)@73^*K+q8!zc+gxeKeb)E0@`QF3WJgQbkAMBW zj^M&9shk~bZfgAbawJE_%D+64cHMXQn5A9D*8XHaD;w?zf6UR{-llme5tZ<XjxSE&4Dfifm5ewqUX7xW20wV?Hy6N8LX6ZSISI z(t3>GKe<0P*>dH>4Ig_^=eqoU(dM!5AOkYEdv*~_#u1_r>q8ic_1S45*?EEo`tMjSBfL)H}%Eelm8E+l6M=FgYOp&F3| zk%b_lhu6X~OQdk#IaeqZ1sAkM3x*wnlEfq3h;&Zl{U5fO9ia%jE5kL7EK2N- z+y!E7(nGuLf|jdIzp~!LBZk@qBfZ^B$s5LuyOE176R#6LaX294#CKFf|6eu8Wgq%! ztmldby{v8VgOuvb`*X&ilv3rY%sFy<$_O9!lj@T7ACZmDO9XXAIr8PQr9dCAf}Yh_YwqE)XI=&ZTA1ALD8QXm@oTSIp~F0 z^pd|zrX1xB-kGmnFq&mmI|uJTmCLtdlEEAPfHkbi#g>m4r1LpqzlK=HJua5-ZRQrx zyt^xu3));PzEee=nJqXY2@0reQ$FpawS;sug}%au;gwDrcknr9QR0j6Zh|i&-oV2oWU=;34C|A`0z<_{3-A59!k6QajLOlKg7G`OAr` zKA5{mJ)S3-dJ>2W)F<-dK%Mfhy99s|ie1i1kvZ_^njmIv0?Q;?VQbI|LC#GHjyf^x zJ*lLqPZ0AkB&AQ}744DwCa-vVB4p7dnh^MuDq3|<2$L+ir`>>Qmhze#LM)hvO6MRT z37x;uBL3+?R)8#?k2*{=HW?idTW=}tVWJN7-ichOrj86I%Po8y)Hd43j=uztq5d^PHM<5_gD;-oH5wVj}iN*(0zzBBI$TUHRiEN?M zfr=E&fO0tzCZ$|XgejM2Hu2U#alk=NpdyRH3H(9232l4b9jD!;bt^-HFezvDu(DrD z4cbNuR;Uh{b{e%3@PW&Y3?1XnJCw9{pLzyqxWGX1YFcM-0;*IRnZXd&XM^c~#Oxko zZ|>*#kW@e5v6@UHyWFV3xA=-xE5w5WXwD?OOg--CeZ$8rU^8(nZ{`707-{Etx4d5H zDr-tj4kQ+f&`SNraon2oSN7?|;~o(st~|=8^K&b*D0Vc8#;5b|^7bgu)&RmCD-QShv$E|oc5xZmX9-LB)CZ-1n)i%G)mN>7(>*rGicRA9W>Ru@ zeX9-lTS9VP?*lx3%wowMI}kN~ zpV0Yo-P24E_Atwp(Nlh9hgejb1+2RG^olt9Y$trtP118Pa7#nUKT0C zAa#S;C8bMyHMp9dO#6 zXAcJAGxK0;o*7JF`xo=9yu3JS)C8XMJtQSxt2w$k~;cvm`0iX^Y4 zZR&v-h#QoX=YmUUZRs0iiF)o;{#8~&EKJspz8;hZ!AOcm`L%Pv%sLd0m*`z4O*TWZ z5T-lbd3B#nk4mL=p~UPLPuBrO5^koaQMja7L7i39Eo4DhUJAF6(woRR63bCh_sysb zRx{l~n{2d%Ro%j<5LT;GVN?kNW749M;L9az-U35;fN8K^hyEi<04i>g(Kxf!3u}a{ zYvfGP$4HPmCtqfv^~>*sY1m^Z_fFim?_;SNAypnQ&_d|)`EXQ1w{9^f3Kie! zR=u~_mk1(| zw~WHpwT+dDWea&%W&s{g$IRTAEorF$mNE?iD%{J|FDOr8=kOKh&_6>9|>$4 zD+;jmX|2pb$o~u%m%2A%C$j7}`XH(d$F3j80!?XD00)H%s@6y0`Yc$fl2__~KT|@dX>ll`Yz2r@w`MfPe?| zqlwvD+%N4#0U9tJx`2vM+)YW`#i4$eGG2wWrM6r)dpLkvXAcK$EEczQcW~S)ZHB@_ zQK9MV-&ndND?L_Tlz2~*rx@{*r{%R)C8K@UvZTgPHHu5Ji)bcek&vHp&SZBNi22as zp}8&rG61WI7S9wS+C8(V7}R(l7hj=f2^*Vn$tA#R?rj?ADcU+3AksFH@u5djwOo9u zCz4w_Jr`+Z?rqk&)TDi6Dhf@=Z&)xL)G4b&&3Cj53Bqnou3ey1STkslQg$v8?#cZP zgc>FHrL2OTe^IA7KhUZVWvf119P6kL9o=C+PzO@_Gv25UY?T?n0s#lbhhC8C0A^}# zq&nakao96k`(1V5XmZptm1;K8gdiYEeoCBkQv{8f8wjs}i5uxlDnk5qiogeF!aP2JMFMQ3`6{YLzqZ(rJfq$YOPGWgpI z+#}Q`TqhuWt0VXSTz4XQ=M06!6$K4zFwH>lHFcqdlLp-A2GkGKdSNoE2Hcb8xKR$K zr5sF|a&Uk-;~M3FI;9*O<_Fe%NWjY~n=@f8l|Qd)U^;y=t@-BS*pbLhzb)@F(%efy zh^+r5)7Ry7t(XXr;m2a=3pc|?f{5XH>wCX>LSJlszrMnq-}F$^G<3M4&5fpesI)i$ z5qPMVE%TxOHuJX4`cJ@JstRf%lFd8_*`=pbXK@g0u|Y!+-_PBPoXd}+#w4|=tnl>! zYpo*yY2y~Co}UBwNBKFVm?u0C@(Sj0J;1zzLh%-<Lg{`q*o*D)udJZ-BJ!f5Ub#*IjsMyoomtN6QD3#|(70{m1izEECT81V z(NcK0Z%|nl4EGHl7h1F_A@g)fk!YNIqw&OjA+aTqgP(M&8_{^dTl_iQ(0DY?B8|hd z7c13-*O@UvpgFDkTv zq@&PAg|`8TMI)MK8^s(NC%r~OncxZL8UEUxrn+D*&5lzSd=rJk&$|1@pO7 zCC6_bqb;oBBsaTtn=I?p-N>>l*XZGa!!`b?tbZXwl#Z9H@$btv66}1|(R@LtE~>6n zG?|K2)InGkIjWnY2~w`46vNZ{LFwsVAe%Z^bqF{hN6N(o=`M{nvSMbU?QLeAM@YI02*47UUGZO(36fgdR4?w8%w0? zh@=#?q}$*rox##HJjIl{E94g2%(752oVq=TCK$r0T~gGm7L+jV(|I`J=xs>`#fgW{ z^jFS$a>)ST^Os7YpX=pg$!^vB=aI)rL8$-c-?GQPo~VD%epmH>(4dxUN%Eit-b=UO zifPYfyg&1spIK&=K+MPPPyVj%VbgmE595Qw!IXmA_=yS#6W>2a(grHf3%hv2=Zp3j zHTx%GgS_T^kxsFO*^_9*>@+68r*JZ0yS_FAv3b1tmo`r?)%;&Q zZ}S>_FhGbV`#%}s-yqJ^-@SF9P~r{I?Jn25LXK2c@H_IpDZ5u$4+o#z^Tqp0ev9{x z+OO_+*w%{rV%hK;5xj;>(u7YOJe$9_>RCzv47NwoA{I|GS*W}?g1;JHg?vYyHLXHg z=vc_y<$~kHv;>w$82Q=!yDAKp?Eho$UEuAy>U!Vx+-pCR)$E<@yffEI((E)zyZa7( zW^OG7Yo%z9r#?@Q$Md<|U9Pu<9xnGDq=5zqP@ue|NR^0a!jWpgQi~J~wAhFRLT`Zr zRfB@$h(bV=B6xbfzyEm5vDRKY&z+XyrXRBB9Ba-o|KmUY@Be>{p_jR_bwwzx17)hg zwA_6c+o9nT4{}KnT}wV8%cxj4Po$H3j$6t1^LGJ%*)WQg=@sn{Ws&cX@K-@?b-`W( z+S29AG>!820sd0TY1woQ3m<3zxh^@Xx|G?nT@W_IN&C?c*jxAm?zI5606)RV*UQ;S%t#)bc zx--_FzF}fxc}PyP1`1EGS;aRjZ%6E6Z>7Cb^TkON-0i8bk1v0BsXTP$?$#QnWySDB z$E!PEC!Xh_d-ZDn&Q_)y`f1JHPdjU=vof7+P>uvaOB{ujy)>LY#9EfMDUx`grs5f5 z5ew=ijZ+pRFNus+(92qu|I?67pU)`EWOmOkm8P;+?r5#!uC6VM`P;BAv~loy?(8I- z*6CcCDrjxs%FL9OB$f&Oc5QcSMP}67+6ZWCwfv^|Y?TI;uO8QD*BcO}D_dvq;_<>D zCMmvOZ>=55&bVvpiSn&e6R*tHO>O^QPdxF&np=0cIar_f-<+*|L2FaC@h)(Yt+;Ck zbGX6J$-3RGcD6xtP-Tp#w>D=Jt<}TpJ0|wlH`>I?dcZCia+4HI1#I0RVa!E?rSWBB z3<;gS$!~H&n5v65_66G5;wk0KKq;!U6(yXdAE-^9)L+Vk&(_}#VuXG+iz3_EnHoh6 z!dX{9&-#oV4tma2678aucU4-O@;c9fwuJIuaXh1ZGKa+BHtZ&6LQ?b(t+&@&a&MF9 zU?G%%SXUqrUARy)q*~yj!F&;feSE^46~gAeVFAw{F78|hk0%Y*0U6Qoyr#FTn3!)+ z(2p3t?vM}MY}Iw^9Ihtq>Rhh&*#j+%2B=*>pU+ihR~K*vvCwuQS5OjHIxo&XgDmA< zL*wK+eRo&VU}I%Rm+%BX6T$a)%C1tm5$@c$Na)1|>yBh!Y_Ja^#C<~(^BKmP z=Nl7j$u9KFaK0$~0#W#dqVNWMdLE2$E=+L_46+q|RYj8fk3k!WNJLfW+M)vmxiTN@`(KeAmjYc+_QHeYFy0b6B)iQo_VGb^88S?3g7hcrSu z?X9#{GR;OzV$9%G;kY}-3=PSeS;iP?+7wW$5fa&+e z1`tC~*N)jrC1|9qN_4KaIGsHJCf0Nay?3yXYo^XVPPyEHfi8JG$R}5KeDYOZ9(S4v zbNI<2KDp}2{p2v8T-ou-oyR%KBWtx0`d<-wyo1-hIn*$7sNM&^FLJcEDx?q=Il;NO zxHq{u67M0Cdbp{`*V$F!gw&Jm2d9O8@V!q8p3?wseE?3?A>3~%?oEcDU)&qlT^jBy zs>T8cjKV?Q!@T|H+ngy=vv$n5;{}dIPI}c&n+!;k^>@7e=(Ni4KGK2%6M+*c#V$R% zTZVgw@gti%wV4(`UCR^d zGE|}YI&=t1-Rv=wH(X5yDy(ed`C*x}?X_6tHOz8TIwRiPUKq{oOR`I+bcT)uoL(W_IU2?@hKb;Z;zWoK)+c^MUP5( z=R_R7VQ2PY`3=(>fBM_oP}jMa_GZwVYJ0LEmczhQUpBSH(x4px=aSjk4Q@|L`zS$el$C)b%l-@Nlff}UfbJ|$eX-ko&)@R z6lVfr0AoA_p(HK`%5+GU<&*Dn3@6a1@<&~LmotDFxD3V&TZn4bpIjTdhs zn_lBoh6ae3OWmv|)7w}CTuVCOdaZ+t5mXOS*!iTmaic)7I1x!f*uX9p0cfw4a2oJR zufJgu$J~8TEtVnx(8{{6u`gY&93G zAOP#56+2o#0YnH~AbJj0cu`ytVfEJBbGZT{+J1~HCor$#su=4LM#yu92?^1w19T<> zQTYk4I!);pskVNc*X)d^mgQ%#_^uW`?5eb`#AaVBHD6%Cf6I4J-TZc^h< zKIVuN$Yt{M!PQLcNwl8G=<`17dIk~p{s=1SL_R`i$MyjnOH)gy_9FvQQqSVpuI$VhyZHq!ICYg%IX`Y{=4w+p&-D7`Dyf!dO0|rkCw>CI<{A{$b1-=*=W0%k=N0J9=K&LMYI)H=_SrF-fC(S$^2O7$}12kyL*9T~xM2)l*C{#^e zgv#IG5q(mQ?6Jf&m+|R^UCI!)?l;34HQ49Wpy|N#TzpVbk#U~E{l_z~d_(49AwQYM zLVl7X;TV&`9r!dqNfe|r210=3r}FJDy@{SC^tBhXeu~QhZ@G_5pIa(%zt9v{6TPQU zyELrRNgS^2byABflbfy8*rJnC7jxb(j*pA}Cn#9VcaM$&nPELqVEG?&G53`U1`mNF z@``MfOqgiShf-xI=oBAIm0;m3y7OX&xtjBD*7znWX3qPq(=X1>ocG(;nj9kJWqwL+ zs{fVQq)0EyIHmNQ!|KcwOCS)MJKN<7Ow27uoBSjiAvUjbVq!O{QH;#MOV`%6W1>UAT5fdPwe`xw!s)xqGSq_tR4~ z`F}rM_;}ZP-FvOn?n)5#ABejS3rX*?RAE)(!0K1C@>wMvi6#29rR^=Eqk-GGa<-_X z0wG##R)uKIQf(`b7^0T>Dlnmq#R~a)dyub3OGU2cRV(>*SxnT`8|_tvZwYU|$!?Z$ zvy#e4yIBeZ-23n>LTo7y(%{3b)?lF~@jdZZHSqJ+a3j&G9Ea z{-Bc23=_FrSmByltlwPK5I(xwg4r91KDAm-=eN#ej(~0y>;(ttOvi?f`G_@p+OaSb zS-G~0KDU@A)`*80W}4pOW_W^d7L~x)VC6)Oz_-dP^r#wT_ptJ={((75$ z7HLlSXGlYCg5famJ2D+<_YGw_Vwm7Rn!$UW@!!vIUCU2rBz!(#3#;d?4qJ>`iz}E$c@Oz|AaF6S=^CdL{?UZBxGIO0yv^nuOihG z+PmIC3&s6sgAr9J))qA{=Zax+^-Em2jr{%#S8gM}U*^h@Z`uWdekl7T2kS4}P_8%1 z`p<=AUv5L#k}X%%?w5c+KZDwd5_KN`rL{&{A|bi^olxmPa%w^fq`|r;GfK4yDzs>M zEL{0D#~sI9VQ}Px%jVV!Z5c};4^>-)dbC6K+YJKJqry;^ZJ)@N&hot+e8+)&T9*gS2%i=%WXed?Y*M+HBo|%1^j0nH3Vjb9 zL*FE=^#S&c8Q#e1C9kmt&?@#t;gotR6vuEUN_li<&68f2mSV%>)(CwLOEFOcJAFQd z5~U*SW~Fnk?ujjUq5xeGzTX}QkdM$rOp!hpa)nGq?5InpV%fK3w|z|T`j4d$RB1$V zoCpN<6oOC{br*$9)bJe{q>Eucn~XTf;+O1w$j56=pY9MKN&<7O6OpEl{##_yv>z zGWmXjs!Wj8wZ+*Fw@-`Yr8b*@_M-5psP~|~ZUu~wx=T^(A$QsEeRY#}b2l@4nufVZbf{gT zPcMiZV=UH5VT{>UD|kx_h<+C2nLH1Fg?g!DLR_}u8M9sm{_;+By?-LW12k$Ih1@5QH)5JJYf9qtcfO#nYC%Z1jpcuxC#vJD3F2C zrlKnkiP0rEpjDMuX)7Sns`9I}7075+omJWj8faCqRoV(3XjR3PZ{{v1qCG0-BNntWqez+Q;DSiDAp^!_yn(BXK}w zYe6FN=CEUUU4&mi7*xzK`5l5IiTYegTq6-Gw?;Wd|2KLc&cZSuKIXtv(z-d6R*-)1_E*x=7rz}^8v`LU5IK#udmt) zdL+(`^oSRte6Z6-ft>l@jklWp(_4cGXWeRp30}zhZqSGB7|aKOCF_92mvcP@unYl< zRkHy%hy*WB9W1P2bY*T47GD5%B)njtbk5O8I!Ck426p6dHlo=W;j1f$I_*U-h_Ihy zw4+v6Ss2UG4NtKytdg_L0mQ|^u!@~vUCLu+SVhHPUIF=HrT1BB*a`JTLD-DGEW&XD zaDCb!kA-2Z%eRJD8CJ=^WDT)2tdjpvYv`;En*k4IbRwD|sia_RZ^eT0CxS+5#%6rV zJna)0I;CPW`Z8CT!m+*9sSEVAqs)<5cnIqdi5!%gtz%I`qTOtbiweoKGUhRR9v6UZ z7~Q1|OQfwHknof~ie{oDL~30wfG}4jglX)Fob1qzGbEqP_JWvs$5oY8i>fj?1kS~Y zRbyu2xVotlnJCe{Vnlsv(u5VjBBMgO94g4W0rM>BAm_N6s&hQ^0vw z*#cD7Y1yEhqv{KA``CKX;l#zxN>q;xq{c#tNY?dSb_!(4=t`Q!W!$yIog9fDFthp*PV@UX6CPPwQR&^%m-}zodcfXoB6Oxhy3VmRvgzj^F;t|6?GBtSbx?rF;6LwqX0Rc$hSgj z73#M=Drpx=)CN_e<|8vmRUauayU*yz*wXo84Vy1ng<@J)btTi;l^_ilC2APT?MM_B zyzwP!!M`X<)JBMgB!y|PHwG$;`v%2-RoseErC7{ubn>;RMl%6BLss*w3$2fFRRoT@ zJxmE3XHxbY3%@#!LH1U&eg_gECW9uC0Zt1Cxh2^i(1HNQnnw;eYaVB1RJoyEk*LD& zJyxiMn}8^U|-ZjJG3S zp@BjzSr5r6t#T{@Ks|RX+DFe3H>%{jPN7CZvieAoEIr+wpi;^ggR8|Iipf`>1$z^d zz`HoCo0h$q1Z9t4PC|@69J^%37h)+|{_TqMy``t0dYg9~NUa7jDy~?jc4WnsbMT#? zhi;SN6e-y*%fJ`11y?n4N)k>8Toh9tbFTN7fxgpbs8mE&k21HQd$e@l0yVDWYhhuX z%P=3axDgjkEc6B0!XkJ?M2W}}yI@!$n;c#hvdMkGK%NSPY|>a(^@eMcdJaxsOBVXr zDF*V87EH}uhZQ=sjE>W>8Yd}*5_{^&3+Wo?$}rBQUE?&?HvH_fxK-OW__TnU1=f7< z$%4vr2Yc1QF8rF+5M$Pp&Z@?Fox6|K_?UTHb2XK9Iy4Qen_6D&39nEYHNV7f$iX3bVW))jfqD}*wvJMa5)F5X{+)~-4*`5 z-<+hRrmbW(ZAPk2CP&{^0bEz+rg(lajKa!wWlEM)9Hgu*`AnQLU)mP($4Tc-AG^+q z7&ZEEFkkJvvMM~+RV;N2f$&)F=K3+A5v$%@vLi;jwO(J*Zt^dTM4{`@qMV4mD!Gw1 z#vpjw$V0qOAiU#I`lD5Os`OcxNmBkRZ9Qnu?(Ax%M|w~`$Un;+5=A%nmMz>)Z+82r zyCunFw~v>3()lFX>_wxoOv`5cW?vg1h&{z%0(lF9T%OqZm7E{T#vy_&>O@U9ZteT2TnF*l21e<@C1!<+`(ch z46$2EX~5M7G(w{}TY9qW-Qz4%8fsT66OpiD;1={O~NrzZ) zfN-ILpW!_R*jUKkxsn;_Y3GOQN?OZR>J4%=vp4itQkcRKxZWNZfh6UIx*(}(DbhR( ztuBT7JPRo&gc<7cdJrbciSI(5NlD6y5Ub>yX}8W4!CZv+Hq981FWw6#Ow@;o2XfNM zvd!>05|7>L+_rEO@9nkXJ=Jw*M)j&ibsIg~x=gnrzRE1!KKiQSbldBz7CBpB`?R?d zKMV-C%{oT&WHrea@sa8_DGMA7cL@Kwqz`*F`QN1{Er`7{t|w*gYSXb^?;g^&?3B73 z2W4va7ryh=yWjDFzrP`Wt9Ef~?$&k&L-*WYu3U6We>izzUthB2-xPc2kcRjB__Zos zBBHI0;@h0n42#u8-&O+;4Us11vaYBFL|xW$3T3<@QMUf6x@#SOqDRy|$n~L`yM|vm z5KQ|7w(QgH#FY`ASSp%AJKEJ!_FUt$%_>R*wPBEuDZiSE0sEaz0dcZ`FKgzTpWj}@ z&c7rsDDf3y7f}3&`gJ!8xmg!($~u*Sjk_t2RB~q29b}P>UO7^yXuW=OdrVacb^Xei z?bBnnOUz=8f6NylEWTod@S5J3e13Zg`?>+CmH?3I-swq`D6qs?1i&fI9bn5}FQ$DeJjr3h%c9M@?Ji&=7@<8nu7T9RKg-CmYY{tES` zdG)5Yj@Y1!u^U=r)os~mJhg39#H8I0HS7}K5M^rX zy%<}tR6*TR*d0VN6mZ7`YNvTglBEy>bOAw8{5{fI$y_eYE82)~DO#nyDqH&ey!;}_ zR;$5p%Ia5+s6x2!X1D!epV6N7JuJ6YiuS_3hbylb>66YIbM$tYwKEw`{vrM4^%q@G z`G;DzIA>N@^VAygPqv0W0d7sUR7AL#=R{pgvekgU%61@hyvhND;}D#qArnyIU``iW zMysQw*a`z?wBn3_Ahl*o>}r3V&5}kvjv5k*qy8a?vLT`rWyaqjT2ZdM2ULbN!3eYw z=2$l7_QOPUzmqHdnRX+Bnn>1J8|3EN zps3IW#kn>!tK4&$&PWUo0N!}K0rq9_hJj`NMyw8cVRdH1Gt_d;v16arHW}F}TBxIE z5=0?xm?|WPp_xH9idIYQ!#uXKwG@5>xRMT&f@BQ(P(i~+fI6nuQ4pGaBAD6#a70*l!+WJ_nLgxr0gnzpDZXK?z@z0GWYP|k0Yk{|9jF4uMZ zHZk2^?|DU-`y0$pbz&72A}B&ZccP0|_}-E{}H z&Zaftcs&bKoI`6O(bWph&ZRYx=xPO$^Jq;Zx|0)9EoRoy+4(>Wv$Zb(WF79-(X~uJ zy1uZpYqiq#)?QujtU`dp&ly>e2|?1IH)Kn$92o(7@Z*`h0$zBe@8%GnAJgZv3;2c4 z^GiMcvOF6Va@S^C{LHV*&hl5MXOsS_k)7?YR%hqVRQ}|FR9c; z}eYAWVxa2V1#-XB6s<@JM4u zc+89q@R$u7;1MDsJVu2sV~l<=Dk%T}H8&vkAe!INafT3vROqPzBpI&b41puk6gZJY z9URD1*N9Gpyq0RtY`jJhb_4#6DC~yu8eMRMB!>W?Z_PkGLk{tYf&`Xm#G8{5n+X&~ zED17qq~HuKKf#g(0!JeiIQqMpe?8`hOboX!HUZtb#6&k6x%nqMZ8qreQb)xg;SzTR z1}-)%!Ra=9F%`?^oX9Jf%H)NKq43X|f?<-*F0F16M>!Mz?mJJ#BeEtlKVTAr6i zn3uE4wbnAHAA%D0+F=~+u%v<>blPE=ZtON{hh@?Z%g_$vXon^4Bks1|S~8SB8jJ$8 zLngH_Q#(vBJZT3LU^YT2)QwI%oMG}$qBb!BL4vfyCdeYy4z!{jHq)AF2U^h%TWC$S z1FeWI$=Fmo(29JM)=9Mktq4JBotfI9DiP;Y&DmZ%oMVEyOFQTpy6#duYNhL*if6y9 zX|%&gCImU{fTup}w8I%dBQB8c?9>j@c*cSvM86Fe{;crcj+$U`)DEk&GbQEFuZ^fX zPR};`wsqMif3?<$MxHb6u)ikCyuhgpuAbr42v-+5CBv0d2URD}CAy{L*gM>Yg-EcehK6xv?CuRMMqUY{fQYd>MZb)&FvMhtUtF$bIPNkzu)&{W3WAGg zi#gVAJREJr4hfs&1{Fe?!?1KrAEUt)HsQ!~qiWyh*cA$s>pdL4=ca}3l( zjI$D;$Iv#R&*?d+F|;A;T^qC*+F<>lKt*>^xr*GP;$2dxAVCTDnkI6Fc$O`@3MHfg z{9r)q6qH5Hm;fWx0yv<(fk;!Kpq?U>nkaXZ>Xes2b)p<`2X9H0MNuvjgs_8#!EaE+ zfOnoGL9ziaMvNGk!vQZq?4D^H@S=nJ<)U%3X*dHxvK4&DgjfbmEx%n%tI&7n;9?XK66|*ciW>NG; z-5EuV$!jOzXF;#(vqvO=s{Ee66b0Mj6$e&+w@e^99L;aGq6_ikucDr7Vkd(re{uZb zrJX;#B>r$q#}9&yemXiK9?ID0TxX;)C?W@Ba$M-qSpb3FjigXO0ad(%&Eq)j$>h?6 zq>N!DemY2MdKVr}KuWWbRA@I!T9S=JUvx8? z>E%FD8$3yk%Nbr`ggTwSS414BYMG-d0%bF)YFtz`ZdA1)hpJ@t6;#D5vrrX?@l-`r zE~P5{;HWD8;HXMJII0Rih^lB6RfQ%P6RKLqqXku&dO%V`F(`>dJp}v79w5%|NvhBv zidVJkSB%sOLxu>3J=0ou2CSGL^R*DKT5>|c&hz{*sJG{T7xsJ4B&&-0Awx-rH*9g zNW_6Zk*%2nrq-iu5b6|Q2J=nBThnUeT#jUe%aJHE(#|r{BI}7xS(@UCk<(0m0jX(H za1Cr2BRqj!fo(xT!E9T(u8QaRu#m-|$FXafHW#<^KU~pbb2Mpw1n77+Cgot+iY1C~ zj^&jr`Qiq$GbZY<g9P(V0dgkE-L$!Z z#N3V2N4mnhHxrwr?!{c0DbuadE}TTN?zu8yX%+ChL$#W?%&F=$bo8Mld2& zUP&-eZlyER(h<>SW0%k7P{K~sLP6{DZj@c7akX*b_*2d<_c#)508i$^-9;@p3e*;dLw`b4xG`5<_z$PK2E_`hSX2Df;sA&9@)_@r%V7G`%b zw>Xd%#u9OGi|1&uB5vW2z?x(HLawlVhVK@ou1sP43{0uKO8m}x?h)(pLlfNNe}@l^ zt7o?CDP_2vzRR%~m?n$n+p@^S>tpmeazFbKmZxsHuzDDGS$_{zGl+~z0&NY414e9( zID}28v?=@lKxX>8(Vh55Stk$X?$K;~L?LMH6IZg$IVnD1XE%{5ul>pel{+gE=c)v2 zB7qM)_Q3X1^C4F%kiYDs4{xVRF@NZO{x(18TW`}{KAGRw(YjZ8`g~J<-^1y%haXVu zM1IG|lGbb@AI|T!mPdS_y`LM+iI{ghw_kVp`T6!gOZv-uzrCdU?U)#aB~?4%5t701 z5h3mMLW!~HMzmSQwA~V+2uw=$W&II z5`>$S5rS^&mKM2w-sB@(UrIlj)aFJnL@(jW^a?UVToYHZ1mfgw0-|d zrf>9H9khMNSU|b^(vfw-xR6D-1~vsk#Ay7)d;X znkv5_TMy1WzGMX=dw0S3Q5o&REq|Tl9?U(D=xy9yuQDtyxm0QK#g>zyel%`H?=47>Ir61&GKMj{p2D7Z$f^Vkv@9#S+FxsV z(8QeUrQ7BG(Uo}ds3XbA=HJjgh@2_7Va^5tsYj#exCfy*H^lpiI#A1N-fEe=f>3FB zs*Kelo}0vK;qL_WpwpfvppVu$n$_^1jPX*YtRWa;>rNF}u}PtP2X_B+ap++FVUr!I z!Yp)y)Z=8S3CIrT;q2C?>NZRot7Ti0ZQ@-~#IvDt@hN@{0>T^A?#3I`?nVZ+u9Q#D zwy2WJU?PG&-8v&Xi^-E@U7u}kZ8XDnBff&>kYGr360(gdwYf;f=h5 zi7dN%q|fMYeR#<%Gv^P;fPwbBTOeg1OE|+?n7W0$KRdc1++G61UXopWtpYSi5(+4+ z{nD4PTu{GVe64IdSfwC(Ye?aqiAO;@ruG+pI5hR$iRIO-vwGWak_Ig~hz?|M*ZEYFK zCZT;vDU24WQ)?H0Z^5u;*M&|JI!h#UR(5V6p>+uftxZU1XSKaLe~E}&oww_)G4CC! zq7f5EKHr!gkUF8uCCoxzCXB9F51vJp(!|wzN&i78aHjMFFTi19w2aq@p2~wSE5*Q& z7bmc+4zMiYy)`l8xkm0<$at=i#}+c4oZ%NUo)p{9+8uCcMO|5EINu9r^WZY!I2$!5 zudEQPJmwr*(25rj7h(&`e%#x~DF|;REv(rK@mycfA|a$wm-eV=ahbG@3_+rGuI>^f zXx+XNhgqE%mF7$V8X-ecCkBs~f5>*V(hM@6_J)Ptk714N+X-QKABIw{>p2u2-bbLM@ z`7f)<#S@(=RVqO~m{zWB(#$JsgMnO|*?TUQXE8d(BD3PTEIj8dKzkQra_>4T(AuCW z*XAriYlE~T3oU8qbM$~H${6Yh*xA;}s3dzy0Xy5pHZ&+;XQ$V?28&3MyG0|2Vz8EO z&PFXVERrB}A4sU4HzElsM5_q}^ZmkIN;VBgHujr-pY8u5K~fBw6>+O3tw}#Re51St zrl3GsZ5Ej|8-QA8VzkPD?CEcJm7^I^EBspbz9uGEIe!ct3j;}Z9r`ei*#(tH=~LFl zL;THe`^yK^W_2ziski99`Df1c%QDQqcUy~hJFVsJv?UMD{Q0KcU&V#sDT;BnTO9Zkzf0&iMO=D+nxaK(CD0PEE%vkA^ZjC|d{o#X$+*U7EEB zS!=rmpF=Xb$DLN0q`%?d#p{#HvzZ%NQ(2XLwt)?62CHnnxGYJ^g*7!&!gV$v9 zF!aMukPpVn6?vI@LHBAi2R$p=4f=L5DU*)lcG_zhiHb;q4v>_hL1@Tm&|pO)FaWDN zTq4nn4enSP2B&(xwH(e5VJ^u7r$ojiMQz|zsHliS?~(~XDrTb`rV2D3e7ZCfO=TBj zfRD*#B1ZcZ4MkeG`{T*1$JWE2NLnc(26k00%5bysQD>_@1&g^xiBy)NBjFfi`f@Sk za$p%v7_t)?DMK#LJwqCzW@AQ&M7o3_O+pKoSwpNT@c3Go0JC9vL=Q-kc79nTV>UUn z#0N{#y*+X1Fz)c^vX!RmSbiZl@U}8v)Y`fBIhrUPON@HbN-AeKb1=OYZS1$o3sywA z%O(Zm{*tv9i?e66Ht-rXF#uD}mT5`D2Bm4a7UC~tD=1rju?)ixIh4o67Ye1v#TT;t zXDq(hU!&(f`t6gQev}GV_tg^XWYW(;`&Q#1EJ+%v$bf2=mvftK}T zu0uQ@oj@T6rG9jRIk887Wk1syN)2J2`Z4Y&I+cTpzCj685kubKR-R3Ew{P{H%^~$z zzNoZQ1_@ae{ac-G{)KiVZy|+z8{hP8t7wzn1A-!==$iQQ%49ftis3AsIUKWk7|u@N z##uk^)4bCBgg$L#i3r(`bFC#O?gJ>|2IeeS^@5)-pokj^#8kpyX+se=q?lb>#tjHiXE))?Z&ln+*y1v*YzbwOhbM#KI)!BQCk7+&?VGc-u;J%H#$gxQkeZ ziWp>=xSmv2#@h0wF{*^#m0PSK@ik5I(+%GM-vi$S!aP>Nw?*Rvz6~1%zQrjgh;Mlt z)W8%Nho``}6PV%OYz?HjYGfemn4OU@JM__yK*9i%^}-$Y4y9B?cDd)|v&uGJrrso- z+Rm5z{L97;z5^#N(IuGbdQ(=tL6#wFp~2zl=6md{QcIw-N+o&7JrXpw;FGX)AuR`! zXUOHvJ=O;-_(+`-?fH9v-O2U$p}KPo_p`mWe|kyB(;N?MPeXL}^jd?SXT{F#^Tp1D za{3`<#TFXRft;(r?NaRLcl=V%&X2!T<%^xqKOstj602@0O``sJNEkj}cXc{b_uxfs zqfEeArJXkw8(PV%{{aBa8hdJ~yu19Ow9qm9zli@dW)qG}V~OLOlg4Y^^grscjoKG;Q~fmR?V{3Mk&ql zO`3VEYDJmKhUNNe!3S0k(APmf>!#F2SW$*q#{Pk3LF`4MDH6O#e|hyqZIaIK1^K)= z_n=z0C{27G41x`U$<-Gyq0P^R6_R_)r0F5;J!LKT8p8xvv{J6RgGd-$MEPvCQK5(p zk*cO!ZQYU6xWULOTkA{>p__Th+I&$am2$d;?{blMo3M?Ob_%*F=Z+srX z@iFdstv|izwH3*0`=JiSkR@1mDx1LHJ1XS3F3vWL4Dt6eem|H0ujBt5_b`;zY)6%~ ztXscWOPbm5dXno)ZOXT1i&XA+Fd3@i#k8!FkO2QUAve+K%B(Jyfy-~1zS;^w);M~RIA4h%$xMPQ^ApZn zS5u`z^_C%Cb0Uesi`0Fyu$OM7Tlkv3xK!VfmdP~P{7=209$4yG;-{r*EYw3r4;W`l zlZV_RK|Sb8nqzjfjFU`P$W+naFvA>$6jw@!P)Lv4#y1v;SNLyl>QiPH?`{hg!Cn|K z3+cyu1GDNL^4uO&Q9s{OP;I;zk1)bYE<+uIHWsl*!g%xv zjYm~MqGZ{0;FUuqm;!K_73FfH#&^P9@-3>OgK8DC_4?Lm{FbIisQU2z&O@h)@R`P~8$#*X$#=*v%((?9OJmvnu1Re1LN3}tHs zqG@0{sks{&Ma9O?ov&dQW`@m{J>t5+gvs~($Ex|m-*fuAK~sTU*AV;WS>v7 ziyU^P2>x4ztmdu{WB#a4j1d$SKt};I`y7gv4jSz_-np}pod8^`dtfYh6a6u+12B~BN z59TVcL?3NLHsNLlpIWVGr88*7(M(&>O zwdMlA1K0&1W^xITEd4%er1-2B_s{s6T)r?y#?oFPVaBKWX8%;97_%a#j9II1k}<25 zF>CcrGG?_h=5u>NvA>=v$fM-jD8`6FBv^abB0DiQ>n);!NIq1jZ1ihoAFWZ9H>)HuR*-9Gc0+4E#&h=_LCa&>vpg5E->q`HdLq z_>%2QRqvsiJl&9ayUb_aE~3`OMPe3YEB)0%7Mi=Z6>&LEzgzf+m2+BLgyWoVVmH_{ z^1~?%u41Q@A?$XmWmd%{t;>j6D&jf7^fP`Gt46Ha=V6VZt~|G;L^u9%jo(tmHhy1AS&YA*l|o_Z(So=fX<=NBdJN-d z!-KBzi?NgOYv*QV+_yiP2*|vb=)T>a@Jhwr*>%)+_IA93xsmTX>N^K!ymRoV?;K9w zL2IwiHpt&H24pJMx7s)lGL6^ys;`!_Q^laIbLCbLoY{@xicL#Ood;c6OeOZ* zP5Z1K5{HO}L?!YLioy7IVi4THnr-SFQG>M|GS$yu z##Q?bGF6^I{ zD`o2-FNW<^HoR*3n?OfoQS+S4AsiHI(qV6=vp^d!rfg^L!faO)euQqFZ(*V%EqFV- z`L!LyqSY<+Jr`K_oH{;~U67rfS23&5Av!7)#bjT14@gFwt@<}4KcF@(3>> zMiU8fmXi>ClNdk#S^Eb}O3VdIgSSLT%mHIl$uegWrw|fz09bD+arg^IkrD@w_Q36_ z5a=df38L-k1K|6~loHB@b;^mr?$YN$n-`*Dq+3*o(UjKB#AvAKAZB_?i;-iK7L>&z zB}{Cv6-jSdarW`a330oeQE|D8+1bNHm$uya0 zv^JFQ3#*k7$HUN(QrTrCL+$ce7nU+UNcJ@BA!56!^vk!>Gni-Dig<&*4JCQDQA;Sv zvz=2ea*qK7C&f@7=(WKjmpLZ(E)~F?{!gr%+ctuqyp0RZ7M2_7k1-9~C2?d1N};)^ zyJChGQnWb1vS7qw5~^9DL~=3=2{c5H`Ix-)w!Z1&xotB&6-hA-sjpuRRr{{(!!e1Z z0EK0N!dg{x_CROyedhp@HS6K8(>5b!fVVEMQF;4l^ST}5X0)oHXb}kAl}gi|G`ZKF z2;3uspV#&s^|b>XuXQ=IT0&{t@^rYkv{Lva>{*~#wt*0c3GeKcfL+Cz1&2Av2pYH4dhE5xN#?Hb$&pIu#}*yyTE!RzpldnANcHDCG)$2`WVB49gA z8g3j9QJV+i6Lutjt35NvBG8aM7IIw z8Ig4>KPZd{KbYBMGJ`sL2dYKhD^E$}Ju+f-2=#n)PCNP&-a=dHEHtDLCKU@fmS!sv zg)1#*eKx@m7nGG8C7vih(j5wc3>HrO){>}-=5CdUAQdr*+%=KQQOpANWJG|9O|(^U zk+d)oOG*wIwoD?nNY-Ue#IhjihD5#9v zY`gAe<4$y|4bzt1;D;MPcop!3?xG{_p)26k4Rnu!o{p^J9CZZPC{EK+0J_xdowC*Z z#+qO%xp!Aog6X|@bGzjP$TXDO?sin@1Za-(nm%^$-m(Ga)+gDgJ>mgs5tzls>ycYM z3G6bm&C2O+mh$E!wdDJ8aZ6`nm8V2mM@_5pNCEs-0Z%d0oRS8>tB|QpjT4p!XU*|H zhq}o?uU0!1bHX01 z*%4~)cU2KokO*>`cq4lUayEpBodn@o<#V*?yup^huI^sTv|P7Nh9Rg{y`$mH{yq+&2^$(V2uI1Z9#{n=i5w zi`fd8Ow^@fbr6`-TgN_gwHR%A_DfLsSXI3Tlge1xMzg_ilShJ)N`^;CL zX}KL}w!DI_`fg^^ke6#!I6ZS59wwS%3>8!;H`p10`1ND0RnBzkhD!}=ulZ6&Kl-Dy z_8f!@hXS9xqd})eFV)PJk&}26&~{Wt^(xsgTBeY%wtkqj{JsD40WB)h+B|`il{u^; ztElk69;9AES3LNY;=!!UkSjM#r^i>g&(77qS$RQ!sa&bn>V1t(oB_0;zrA+d`qMW| zY&=6J0_h;5Nt(6hn{lLdXFV~dxJFP+fsuTC$hk1SZ&JZ*#SUc!lI{R4wT zr|X6-MAhkfUH^Y`=wp?%ew9tcHK9-?oaEwU(|I!+I2tHb>H80KhSkQ z*mXbDbwAv7Khkx-pzEHA>zF@M&>i=cu6vH2>G-|Ybzkqg@9Vm6blt;Q1Ce3A=NU$X z1R$lMkCm(CTgor31Q9ctoC`ztG=ImRqOtR4^IdMo2-rLSxA(COD{sUmB8X)@N?Au( z^HSbe%3LujD+kKW@4W)SLSVA8uBD_q24sd@B6DO1z+}}G?V8I%@`vZL$`qyRE83OI zNP?NDnc^I3ZJw#P2@f+_qSJf4h7` z-uK_y_2xIMGvr!7CIEkiTMZ<7KN!L|ACRLX@zzjAj`c^}RZK-oKf{*zWbPD~0qH&7 z(w{!bEg)BvvjUW$2SwG#HgIga)@q>ptaYm}x78N5Qqy8hwtmH}i49EzWy>zBEtG0$ ziDk8QBXKJzb!13Hzcn@ioyNF2$r>p&8l*7>B&h?nDQnuwoovv@f$ew>TN_nk+(KJl z_(g|JHWfIwkXt{$GBPbA+sDR94A=$Rgt?5Zh=i$XEQ_pKIc9ZtFdR7@trX_(BlU8e zyMxSK+082*v!6=7|D7s+9LyiKzss7h^~4Biubfsb2Qm# zWvwi1S1+h!JP;^QEZv%?h}BpDyU*aq?}^#7yM#O|=EdH`ag z@+@U-bQl$|*!-))gXbpnngc@|o&iQDG|Y>j`R0+JDGL?bwAD{U1!E~t@#;4iLo;M7 z4L*5YyJm^|O8(dH1-}(fq|_p;?QN=!${NMM?c9YZ4z<>YchH!2@oU-HTv)N z8a)yGn(s&xBbN8m!M0!5WSWFPSIuAd#BeZ@@E59;29k7!sm9mzR`bJpqr$9)|3pD5 zHe(wN+}+~>`L?6z&~Xptuh#4vl^D? zs=G>9_dk(UwCsN+EqDI4iL#|RAt>QMrZ+;Z`KLmcNIK)yVcK5(N@IQrL$MSRL9d9- zT-WQS!__0MOE^|7`pA3#m-~pl+vMGeo*y!f?fos+*Jk%;9e+;nBS*o;;|Vr;gSZ;# zdxJRl=vXuBx8?>N*hXj`87u3U?d@13LvOB?qXC)vs3rhp5ViG>OHW|{LSy;ue=H*s znc_$f5qO&Qh6+SX2MXp+M_ofq2<=QRpW%_F;pzMibpg z#JBh;ttIZO@@RQrOKCvADB^A!ytJi6zc;Z5qdh6uzVNDjz{YFcuarXRw;eo#Y@ z_%iM}#v!Qu5>jwO*nWf|l)HvdhS6*guvZ)e*M?p{2tV8-4no;md&%bE%U^)W80(Bd zw8}~y9MglMh9E&5(0S>~p*t$Qh{D;&k`VU!_ZkkR#*YJs2?Foc`<*lZntMBs0nveXq2+I8WufG?KG4e5?es} z;+jXRMswx-4tq|r8uq!fc&-f-5Yz!XT-e?!o!le5IZ6n0=0N<6F^YJtYxW%R*f1XP z%+%wV-gL9QR+X-e7}~WURaEX!U=$VR5tQGmRkrCr!2=olVj2ag%E#Cor<)JI1_X)3*?H9tbw@4f7*{!qefi_n!ju9p_6arz#SE30aB(S4MCA>3 z$q?df)pL+=eHT{wl6}WnjQgw3q(V;RI~!QB2EupW1PJn|b~f65Qv=V%{^6u`HVCta zcr)J@-pl*=s)?Qx?OW6_OWzF}QBIOA4r4`2Brf3XtpX6N#6E4)(2!Tb*~DPXo=cu6 zg>4(;FPjaGgNV8pvP;gU@b;%Zv1@_XBLob6fc*pILUM4RQQ7I4%CW<=5Z-o$r?}tjhQBKgst&Pvc;L90-~W)b#AyB-f2_ab!2#b`IZpwd ziOMALl}>m15)cOCv7>=z{5*GuJ4w8Ne}6?rYc^N+j*S>`~*q@frec>UB(m^GIv?*mUlWauyX#wg*+7-k-TIX539y@K^+Y z;i(Q3AZz6aXL<*!;+N_6kP(%j9q`cp&Tk;_MG&?8H{GS6jl@u!>Li9PXm9I;Ht}5r zZ4+qS7X!3_lS0d81OdT<){+o#zxF6d5If{S{iMUDKz*P<>}#B{FU0PC`KLepz=PlU z+%rYCU66jL6Vk!RU4~b2m(6U7-Gpx5;N0k}iYPw#ds307<@*(M2)-KpiD;V0SPh40 zve*z_AY0QsA1x@dBod%=nTg7X#<-j0+4DNdGQU{&MrqL31*H;?JW%q~fe`b7qzjmK z?qb*`yRdXF-!E@0O6Vh#y>VMmIJpK|+Xv>>S-{Y%6(f zqVi&Q6EM`K(~Q1ho9ivKrmGuG?yAF^-Dhu%ai)%#oS;$sFX8?qCk-z;Fp2Hhc?|;+lA9&B7KJoQTgxH7--q3(3tMLpD+}9GjwXx?R(kGDyE;LBR zcKK2aGTo@I^l{;gP2fdE3Wkn2o%nB>AmKq9B00R7qEwpMH4|M@e3S>WH0*cdh1KgL zDkMLjGz|C*xI+X~t!ZU=-2bwRy)oT{jeHDrqVhaa)kwSqC)aahIB{XeZq#rZy3B>w z{PrxU>BLJQn1V2lfDH>!kr63KDA5az%f z{o~L4*5%Gps6;TsDg{MPqg_o09O`^-m1FE zecn;!ZZAnwh+h)Mvrg_uXPI1^Qkz^)|4v`et)w}nlRNj4CYj`WcSjCBu}MaiBX(u` z7%k4Fp!tJBe((H4BTJb;Zz^cA@UIMX8fEyhgucUG2dQU+^vBFGR zq%Kri?^CnT;w*w@a!$40J%t*1Pr<>zQ5cSY`1(|b?=?uf8w!y5B=ety@>J6 zooF?tNr`c*lZ=IrooKzSvzcI%QR`7DGm{uC9p1?Q_Be=0kdUG!r6LA0Lqdu&1qTn`9onTDB{MN~WIV>=Z6y**aqXib6N9Hnm zj@u$NQl~YO8d-5A(fGAlsL>{OrVVx?UQ&Xc*PSfQnZ!N?J`<&S35w87@|kRFghsyO z-KLUDv~>8`C+IU_>RG7aD9%!XwOxgLJ26fzEUi=KEG6L1wP3kEBCNN|#I~bYJi=+W z%j7DCqRZ6h1E7tfcBqlh4N0cD<5*lKfDQh8^i2werBF1XMp#kQxX3Z=+h(E0!j>_* zG^LBv)YBC%f-Bw;j`Bm^LG;_J-iM=3H30`*DR8hvBtPEM3!G4D<}|;&^Pa_BsYiZ| z3d~jB6=EyjDD=CJwY{^@?Z5T@uYKYV?)&Z^{eCaq&RHwoWI6?cf*Rcf7hX{KVBFok za6#7U1O-Ki2}bh&VG6E1OHpWpb~z1a8m$iBT}E2q@T{A%HTpO~t( z0NSbXcoLSGn@~_nizn&uury&NEn><_MZ9X397Qi$oO6d~o)(W93Yx`ya-rrBQx&a5 zOXZqqNF_8m*O4oX25%?NSul0(16XM^^;qn_BZbOY&NGvTybto`S$N2#cvm!a&O_x1 z4?R}M#}kz2UGd2qNql%!)RDM3kyv>W^*va?d14`bt7=GR_he(`EH;}tyWVj8-Q$?u z>*qQol+5naLR%*y=gS{D$zXX=yYlZVSk6kvnZ(FO4pP^DI14fMQrC!@f8VBKLX2~* z|DHaXo0GI1S!O$v7>U-37(ad-#5ni1W0CKAI@BvX1+;iFrsJvAJ9BP3&UqvtH7-up zbYx}vOcwI)*B54Cp(n+3w50_u6tJ@}$-Y^H0v`VJ@80=|9shXW;-lw2Pod@b>LN#b zX94D&MP~cJhxfkXi#xyi{U7N8W>MT{0Simu*yQ>I&aqgIz2d>wBmZ0x4I2&2I=z24 z%k&lr98=sDlE8MHi+C{m939`i%>{K>_GozuoD_awV^W1JjzrAV*=S1Am)(5bJ__rk{P5n(bNs^L_HELgq9 zJHWkbQbU2zT;Rn~tK#p}rm7b0SV}UZgcVj|XrLfkcIQa&(ixsSGz(q|qAlwCj+tna zYQ7mM47LVIfbk?ttWGw@KlK8pn`DnVH6c(E&|>AvZn=Q-GE@l}mJ38rwU$Spt5y^f z*E)-dyQu3};2e@kS~iy<6iQYOAfiHg%|(v7#0-7N4oG)D@q(g3VeUEs9!x zFhsv=d8|vSO?4EXb%9wFpA}$=RBRbJA9`NfcE?DHerrWu>Uk|~2JUf6YACFh=e_Gy zO+nQDo8ER@ObnOs}1e-kP6=mT(FbfMB z;MY;6twPaCQGi)-W#N^grnS;p)5?YczPP8NvhcK^A}IroMgN8>tB)zy#W#;B$Xs!FrYPhwQf2Sh}Q@ZB9@S7!|<@ zAN0fzS-g(yw&2mG7i4I~02Pn2SPIMv??73{jJBeZtTIa}u=`*r1-9wxD6NH@QU>s) zwIVsk0AY`bX!KR`nEp9tFpJqWFfIKfI<`7*V*s1ggaMLSeV&_DZx?i6@%lKgY^apX zt1$p`=jQcQzvHVGy5`kp)8^HO-CX^p>;i|U!lqC7@w${BQ*M+@b412&P6;p&hc>~m zq;(~KTQ6X`MeL0kM53&?@qOI)VtaYUvb_~7l9_ttt3Un4FTDO;AKr6Ieh5^DB`x1P zz1o+qFq^rk<=ejnW>|yxUHiM>2W3$Ut6j!UU|mbHoJPcwE-7)u-p>N@~Ojmp&0A={$T0Vr}jR2-+kZu+t2P@C__(2y$5g*r)(7y4Lz0!6msjD zc0)x7wXnE>JJGu>1H86fD=40|DXCm=a$dWcm|W<$^W$0LP$YHM{7(un|L!v% zzyG#-K7aVk9$*%VQHR(I+idpKAs4J}C6NosW<1YxoAK;(^&`ow5-u`Eq)ChzCRdAp zG^gea){9(RI;Ti`!sch}5$(bCI;yV#xJySFu{tp<9VJso)<-@6XegAa=imR9 z`AALX`x6B%{_DOEf9|#K`1n_MTDHB5XE>@pas2vq+pcD~`yk2<&@J9Z(9 zOSAmWP#%p5F>Z^*Xj>z76Qd=y>Um6RbrGXs#)z?CVIs}fA2%@`qoj#RtrL|r1<%a6 zq)7x~%xRq{m^Qg{DQRqRPxs_nAfTSdoL1N5&Py6cEz){DBuz|dov1poN&aD#G_D$| zr=YR5NZqt(DXn^u((0ncSp?1GaSNJxt%tzJ0_$bkJRNCqtJ8YL@{dI6ZJo^mn~X}& z)*^M&qWNX@BBON-wAh)^nga_g`m^=I?XDNm3e4+t1#XwAQ24WEw-ymPuk`-iT40He zj?ugm)zPLNElO}42G|kAqOC;gCPnWI#LUn!kRtZi@ry;XzZ6_fHZFB>>#EyyN|~W* z9y3GL{8PbftxoOO_xr!`KR)!@ho2!Aic)m%=~X3XidAvd=t328MxGwQ5V!#t@AyDk`w$l90mnvxNYXB_tiFzP9C; zkc1Eb6J>5!H9rvCF6cKbhOOqeg^g*dQ@{1dr~cyCKL7IVe{DIbE;tLf%iu(`mz=+~ z)vbdlG*7i~x3;=n3m$d58H8}oq?iLwu$tRCFLw4)n3s^b(WP_zt9eWlR%0-ysxYs} zM@Xv5_xDT#y3jncY(v{49JgHIxX-=peV=*5o4)ri|4)9uc-U_+^H{xFPor_2J1!%) z9(|Z)efi@2AMNi%*zc)`Nimva{}`Ap33$mJHBxNe=Jt3ZdMNSGwSSC>$7K7M7-@T! zkw*--$Ngg%JzKPhY_`SyW0KEWoUM=`+L79YEz^KorBm#M!1pKbw`GjlwfF&dsolf= z-0je%-NXL$vF*Qq&u@P9PyP>yy{>#gQ5tU%Wl|lHy4kF4TOsziQ-JH}Vvn;M1gCQv zia=Z?PvHEklZ7)CcR)4?oZd_EaJmdtA?`ZzQ`foWw)>fDrH^dPf;41b;$~Kr{L2NT zaWkt**Jf5-C@nU#GL$9)LkI=EZf2R{=ACbcu4zC~tV7IjV#b>qN1^U_d{)%GApi5v z=`xTy-G^$L!?a|vldhlI;`}M1OP!LV zJW#;-iGm9ce)i7yeEZ|y{#!mgg9{PyUdI@msl$E3)a^xx2t2Ws0*T)$GLo%Cx~>5C zbwSs#<>24^{bygX^Dhtd+U~qiHNDXqba{~eo+pnkJHqa1i8~$w`LJR^312Kgez2f~ zPu}$x|8w8l-udx~9vCjnI|I4M)RJak3$?(M?Cm#`Cruf>^WES2w>y9P1K;|^{3D4n zvY+1no>xEdvd2Dh|NoiWK@(n29p{dU|19>m37LAwtN-Hfe(zmh`tAOwU`NHb_t;Uf z`&f;`4}J>K)5srtpZ<;p5#&$E(58rN22w0YPK1=cCX(|i1|BuTYKEqa@(L> zDzY~9?tlE?9iRNb2k(Cf(?&bloL{GgGV`Qjg+vsPVQ*~L_g5?Rfbt4&2TW#a^ z`e26qYMVG4g7l4lZF^}6Qa>@mbviL6ehN;L?J`-&R|8cxCwLE_a?nPyZ(}+Ywhv;) zR@Y@%kGE#o@K95V0jaIiQTUot?y}5pco?U&Btui1*-p6K{Iu1!fM{y}#G`I~2=O@G zTkPT5dvC`1G_YC3NjXMLhC~a>Ck*G)z$Ccl)4=8piZXbO3utpuHR(td>Xj! z_E(ut1HaD2E>wJLRRAu&2MLno4;jKF#5|t{?g+O0aHiho)4)e6I5|STV?GUBRJIiX zwT__neDRYRImC&J(1>L;Es~Sw-saQ53eL=@fseTE0@Lliu&YQpYim(3Ar-5x%#v9)9 zN1yoS!3SRP*;4)nAt4+za(pKieWi%6r|EtrlV(lqor;5&Y)JpS`_8xS+k5w?zgEg` zPljaKgui|H``+@Y&%ghR|22PO^3(jWDpbg*qQ1w90r|DAsG{wh+xcTv<^%&O6lbjC`Qj+0rfaa1nN8zr&H< z2~EbD<2j04-5B*=&&YndP3W-(Q|CT_rDBnANcG8v%IA+&Ng`M$GQCOEH`X4XXw=tA z?9$mimd&w~#gTsP%JnfmIe)B5GP{My>0n)d$fGZ~5%$|Ib}f+;_K{9RPAon?QIV4_ ziT(E!ET2DCW$uY_uJzy3Cv!7@tct3SyD|(7@sU!Eadp{n~w9xs?43~IDf3l z$yHg*AFDzItXnQ%g;9sCQolKuwtQeWm+OnIR*$hh$?96Q zNGsX2D(vJDJ=OVRRg&G~lVcp_k5&0NmFe@xs(kW=J$79xOl#Y9sYfZWFM{)>z_wU@ z{#X^(q=W+$p617@e6w7svRUI=7T>T{RP%;*#qG6|aX?7P_D^iF0nkLHzlCOFuY$^y zo@`E;iL*4{_hFr@!tNFnK=Z;xW%xAfskA~1KJMB9$!Vu4jGqII=eNrvtSp_%cJ6MK zhRZ|jwO7g5Xlj@(fDSaK`A!AA4o~Oreeix35q(1twX~Vd-WN~n)uF7qrBrK`hUl-9 zKT*Dk-YSBU&o0d$d(}RJq|^Dt)=PKpuEkYX;*)D6hFHLWY zvxxG?tIua@ORZ9sdFuX869n#gcEM0T|ASa+^}YsEp*<3t|LS(J$PZMfx0FhG-?K+3 z*T^5OiWIJ}>qqRm`C-lFunrsJHTw}0iA|um^uKAd)$kjX)A3t9{oJq}5*9u_Y&N#< zQ^QI7tcX%#uTX6ItNLsPutmVOJC!!PDzm+C0a!WxI3x(^Jzkw|m+;qzhKBx3Yut<; z4F+xG`s@)%-kvj9(DJWi4k1u?qjh`=z>HTHGU;MDFo-I;+rQxX&u?Y9Zsws?7&AGo_&y9{Vsp z`*Plh!>HV>VX&Q-A4cWo-owy_Q>D&tzN%8L-x39n+mg-(?@uopDM6Nf2nzl*a;7h< zAf6z}@>MHZWy52;(kfN9RhebGy-M4a0Za=qgW)NAQPUKGdx~5~8*ZVol&Iv@xFgHaqmLzY@?j@-2hgG-c>6P6o_b7oum>k(gPdWxm~;r9qyYGl^R1a7Pk7RQoFx3 zz$gd7L?as%ZF#)(i=g}ICTs2%b>*cW8!21QCOO$`1_beDzZ*+Gge8c;ftdmW#hb06 zjE`g>^H~n1Y#zt`ps+lcv6*stxH2@9m%)9+vHMYYt7n5Cm^VOj1aUxs2y?IBha@%Z1?9Q&xH3X8TGJ_OK+5!^ZXmt0HJl^ z-flk30_PHaSGJTMZ}8@j=)BBFD>~QDj7^$YUm-@Fk}!Yg3l_LsmgB8VJ{+Vg37 zQiD^a)^Nt2p$&GMS3QMEEIXBOr&N@n-Q( zR++-S*v=-AJ6Hssu}$-KEe4P1HVoP%fU5-}a{ZS%3}kNbYU!8}>5mhfkr}gLhGoy$ zD0j|=0RxltL`}9pR_u=El_N5Lw}ZO{7zGpyPDm$CQ&`gj7 zj0@l$PB0b|78p`1d$U6vo^w0+;%&wk01jku#-Q=u#>)2_0#=mZdhYDAp;mrtephTI zdxuw>Qv*KBTq&;8_i1F;Ul(WB)EBaFnAaEhMEVtfo>iKt{54} z2K2Zt`u!w;?l`^2*C7zlr7REY5)dM1h;aRMny!&lGmBaZfZ5y^W)r#6ys-NCDAS4l zxLp#9BSO?6ntli5DvN5n{!)kWeP&(vCJSC_)RVKqu>zaS=D3kOCE!$JuujxANucJm}|IYhRfr+sCo<{U8*De6KR>zHXlw3Ot+&k;By}M7~{>5ScM66y|AGOknvAB#J=*xaajUbP~zzBygfJAVo$h zCMM3We7mZF6EbO;k~6=#)t^_LjEG;fd9E^-J8PIGqOd~}Q`K$KbaZ)#gcULZD6xEA zGTpq-M3I>R-13VEy`0~fnt!}mlG~1%bdCM`;@}wbXnZAogC2GoQ6V02{`zIWV%W+Q z7!YW>sLIw25;Bo<$kh%x=Vn)O&Plgob|p7^&MwT?Yj&S{6(K&EQ#mJmnozzYA~{%P0kG+r<@xqBBzq5(EA#uGk z?wy@9&mz$Lv6=#XfkpZvi$KDslts`=PI1kf0wQ>3YS6Rd(Trz#;l?6FggiGIGLK>k z)KP)e@9GG`)TnmwV9PoVtG8?WTwH@)xt68RZk%Mbn_X?c(pq11Gmx=*Lm z;nzR4pjs~V5!J%AHIwa%5l$xb<4g&FU%j0zw>tWG<~B(g)n1T45Us@eZcL*-XrgT1 zgOWkc4DK+<@K>>r0%hLwYw`xm4wD#AvXm^c;Wf6h2fT3wZg`+fC=QpitQm|`U&NSb zjZ^=&JIqEz{hNiJ54(_@a}vDECW3Ru9RVDBS;?-4;-FmkW2s^|mHg092r|0nCWpPz ze6XvT=&(@xXwl5w0e^=R(%h}!P&Dafo}`YiFjOKiB!>%fn{GNJc{H^Z@{4Y-3^c1_DIvaZmkgBRGOmQ(cBWHFB*>#No@=Qb8e+Dj zh zh?_0phI~qXez+Oo=F)I8s0>9t|5zzBEa2`F@oph^pNV%(?*1~~Y3W~UQAR}E%|&*a zxUilrvP1=#Gf+dAZb0)VPwi02VhbiHpbIzq_EkIR zH_UhVYZSX+Kr^qbb3ZsKQA!3QTJ&HioGF8#`A_oj`Kj#qeXAhlN65}2zoa~?Ynv$A z%;eB>Sckkmby z0B|riCMbnK{F4dpsfzWD#UxDuQ^^HH@90JzBj`Y0K-tv^m0dROulz}Y)l~A850`btL3rRzUMjm@^6OU7igt+r%HHrr}TM&v{`ZN-2zn1cwKgn2ai z#cX#Hho9{(Dsr=}#smO2+iFZ8b+fI;WS-n?tFf4EKh2#akngf7=^_?4&1y_OK!qvF#&03d_4hvdu%MQ5{NPIC9naEs5pVp5u+LtU>q^3F&Xv# z_<91&zSx)m*&Z7cU>-MMx-68#u`vPWkQ$wt z0+CF~LGoco#B>K|Xa+kuLul+2${I^2XE1hJ_=*?Pfme1_LQBb6Jy1fuZT_EBP#>e}jRcz$e#kQK{PPP@MJK0vlC4U&%HZby|vBfj;){faR zKBg%_hp{nD2{Md}X-ZIGOiWXP2;*Uz3N#1>TRT`7hAud`lixiDt1;=+aj+Vbj~_I? zRAU09<6t!=gW(n`P~&9bGdd3D-?VX;QN0?I*Bu9|G5L_=U^ONn?ToJ{z;BO@1x^A7 z2Vthkogq#f2lG=3jN@Q6Ccx~EuP4Cli;W2|j)V1j0*vS2AWj?y^KXio+l|20m|(_n zuo@F!90#j00mgB#8WUg~2dgmw=8(YNSPkODaWMa;z&H+8V*-rhU^OPd+-qQ~F#%?8 zY)pW09IPi3U_1v0ae^S3DNeS>#srwh?Gq9_2{4CaV*<>f*q8uwFg7N@JgUaR3}{H4 zC~OJKC$hw3%f3XEi26G%0H~H0W_$zt=qV zlQfb>8rj;vpJhC9EG)p85w;U+&%wlwb1Ej~qBy6hTmFNpOUc~SvE!n+xi%hx0}42a z5*!f3_e4ny5{Z@Q5FjGqAszuG@da_>90WL=A-EEe_z>j)HzG0Ne!gq<-oL%)p&1EC zCFdI9`R(1id-dwoYpq`0y?QmIAq6DL6pn06qof|sii(ki&S79p+DK2dUs zW;t9YR!X}Pkq)Xkv??@{#KhB~~bN z-l|Yy1(|bYVg(u3A<9`nW}(bkLFSAjQz*2PrS94@5ZV)EVg;GwWnu-Hqh(?RnZspb z1(`!-Vg(sAM^&M9kYz13fmGNz`RjJ|tVywH!Y0ECZsuX*A!b8je0VghKo5_MY6FNp zq~LzW$~YSd>F5Z%kZfbbY(lY!&UqMl^t@2ss@^ zGm!{gCnTOe+M1xpI7+})W-hk{bJwEDa#1YzBWSKD>F>6ajmt`K^mS4L1WpsT;Ga3h z;Q@|9CFO1k{P97ZuIR%tEN#JB1;>y*Vqdvv1Qmtmh;2nzwpsy{bD$FrE%@B4>Nm&R z3CynlxwD0FE0SdRmWsTc%xHg^pomX0Lm^nU7hzpVlg$1xJlmQn6 z^47SZ>AXxggzgpgL%vaLJH*9wwDH{S=H!bS83_59oQ)MnMQ`S z&$LL&Q52)YI^ASoKxidNx4qVZq;o@;N&0eIu82unEV+`ThxQ}s;b}S?FuP<)$JI0_ zDwlGO$d!t!?A%*$&?ux_N{URq=3+&~_A&C*W9Os&5g%ZWDvd;#%pyLeY=DweK_cau&;2Sps4T}iyHtI;@QLc|9w5X8PF z;-c(|;{8YKnr%EFV*X1CF+X?VUF5pF`<`+!qPIIkW8)_7Izc!(u2x7%jxq|vn|iV# zUy6!RzTS6qhYn)KM&i^?Y#Ch&)y!cV3NtvZ)@jnq4eAp$&@%N}D8E`QAa)V8i2CMp zZsJORbiZy#4XkVAx=``P=S;V9+jhH#@YQmwpZ%D(Id%I;7JCaC6*}4QP|ykHrh*EG zF{Ug#glQ1gr{EN12vy8QN#CwienOJQ#bPERqOEKsT}j5^;wl;~>_glkc1PWQv)5U~ zM+}v%U>B+~!=pcRq(7X`zxHlBY-r{!PBB9k@n95S9jQ~(0oO+BDYVi2f4cYHW9Jkn z^wt|ApCpPC&m1EKqi`I(KW2bAO0itoNh_<9icJiswjYakbvi)EjN2a@FqLWHn#pkKL&1vSQ4-qB zk1-@*)CW>06E>CUX!utwW3f*o2+onk?yKFs3|p>o15M#@G(KsiY1;O$%b8FNz|2g8 z6^pj(aBdOT!+YR*pzP7y5b-I@I+9?~Q9ICrd!*&Gh!{@Kx;$|)ft|lF+Mn^qAt0bG zm&hcavmwWqLIvu>l0B$r-bVvTg(XJmATr9is?i&(^KrtV!0~q5IT?ys_y){Uv2xo; zDeHQnz|DCXBL_Z>d!r_3*G8X}Z{VMK5D0OzUWxo5b{0!EU}v%am=Av*6C(8AnD}|Q z@-$NAB?b*xdem8(RL!skn5_*M_!oTrq@S$8+st9Iw!qpNWVU0nR9SHMS!?rbx)55U zdR>;lIh>ZMQEB;hEFoQ!dd<3a)a`J984iw_y!8fbK2bImHt+U_IY%7qMeCa}*j(e% z@_a&%WE>$6?EYE3IlqHb!8IVk*-mFpXJfI{sLQ~Jr$7nu{X%dkIj7e^wQ@ouo@^Sc zHwdjDp)gh#JCc7VbCr3*KNME_Id^0nE{5=|<_D(n!u%L_UVH>mgK8!0a3^Cq}8n~cgCdl8-*wT0erg6SO_ZOasBw1f( zRXrK+zcz|)h_{>4WD=;%Iugei35QEMnJ4iizQQo)X&l5xoa22UWmIsx+zj_%bBvkI zF)pDW3)8`I4qlCLqBthS57Z)id^Vm#jQ%CtAiSy+L*m2^kVsQeti_73Eg}&#kR#y* zNu=46dMF!FZ|HP=mRuWe7l*5tvY`N8K(bMBvgoX1R6&Yso*Bi!z{DH!Oy!3m_2Asag?eUOD;6dH`={!A%0Z=MMJe~%@O@hb2 zT)mMx`DL5c8-9=|bq8>%mw;*PD9S6IhBVx(d7V$- zLbh@F>eBa`;`{MK;=bqw5b`<>?G6snBR@pw86ygDC2%56yum1zx#%Y(s2*j=MmC2A zFd&8EzaCp;qad^T;Ngmrm@p;~*;t6g#Ew162o!B~x+p>L)9$zJh^)@(a`^yXbja8O zU{KN<%>rG58nr`sbWqu7SK^q@<})w+RHFN7Vq|JYF+lMXN!%cIhqbFj&<^b`kDLzF zIC6fNCe=v_Lry2rmqm^u7JsGEU|Uxdws2MI=SXBviL27URjHkU2waucxyoKchowtS zi&nWR%`2xx6{%5_PV3=Cgg|HlT-9){st}kdl2C-Jpkhhk8Wq3Wj{Y)N2nnz6qN6{g zt}Q$ISGf4H-q9cRjxLzl&248q7j^5ziC6U+-T}rDsYaMa6h$#J{L~~sRitRBo;j$S z#urW1QN<~O6!i(TMy@DQ^1Zg64{JEy0TYlDWkKMfP{^`87@H&qte%PV_Wed{-s=o! zRZG0?D;iUgl}Xftn)x#dGF26#`$K>#Sq7#sF~Oo&^-K%N^zKEXDZ0hOHd*@;0wIY8 z5m9Xhv{NqLJgSX=)y^)(t&g z6Y2L70}p#GOK+QECd}kBZ`?L@Z0>ye+J5Uu*3z`_<~+UE(V@aAfFa3wr~5PE%)Poi zx4=7zYa=A2u%W~ctUfUD3EwFDlNz6Zq@UXAXc&z?8GjGkarQ#(;H1zcx8v-p?f7OR zRp6j@VLzUWN(0iUk;UCVbrJ@>3#~ZoC6bM*v!Gm#N!WmRbk4Ck3{8tmh^B8I=`-)Y zWz5H+7ABTvz({0ka9F0H!!n{fR>~y3&a#K%J+y#1lT5%A#_EaO=@p-*#Ykf>p!Ewy zFoE6CEyUp=ZkG5{t4~6%tM%m~O3ThyDPEZ?i>!f~$P?vm6r7+(Qx1h3(Wd>N)yiMK zzYpTf3jjIMXB~=$5^!3-MW_cB782&Y`3~*{p~McEo!Zi{M9!cMlUT89$;k;ch`>*2 z?2^d&vr!T;mx2YHwd^TVGpu@{ELO~lkhIoJTUMOZvY~DuXr$CaVbt~AqbS3{dC zqncoVRzq7@c5cjG*xwp1zhIyZ71*oFNl7G2MUw~|63oh+W=MidC?QeX=F~(Qvhf|t zt9QK*Y`PMyXvF=*;ONR=Z-Lfn_BdcT;UH#14)r+N{aO)%VNgl2aWV4q?bZ;Xu;K?& zTht61=JeoTmnIDZ*vUSD#0nhnb)#VD)~gGKW)9i9m)$bhm=ioKd3EZWM~%VeQCeYT z@i41{ii*LqNr$=uA8UsmK5iNx^8!X^3-MAAlA|a)HWHx3c{m>KX>+ou!aYibeLAF8 z*hi`G&k(5<{%IQjyvAgd`F2;6wHTZGKM^8DtDMNL=HZH%B2(N-_Bbp>F{V<%->rL2 z=!sNETh#reK4I9MNR zG}*x!)JAzW(gaKjfF_QC7j7Fo0^W5qV+^kriLO7cwH!<;qf*v^vHR-=NlZ!FO47n6 zxuyew2d_riP=K#SQU?joCy(LfdJ8=Y`@cpty^LpmrU7MZRsHqZSb>!?-7=d_iV)T; z7hdpW%cc7pc7RsQjb7rXEAbV!obeNeobgj&Jsok~l}>Y%tVOYw;zM#!GuZ>k4Qhh) zm!IY|S)ZIut|RTn{n`3}1}k~9X-3*~SfyxyX=V*%@s4?$5yCJClHOe+={B7UlFo#) zAbefY@m^WHF!4LhRR@+26`XJ8o5&%~F9#NE3l!RlV~Yu;k1g13j4cXqiEga!=Egoi zp~Vi6EZF-M}YQnBS5<< z!&w*s+Eo!I(MEtaKjjF}UegF*EMy~q*yQ^@0vJhsNw^pYViu|%Fs-u8kN|7DwjQvI z^E}wfXcWq94zvorvG(D)t>L*{8=f`TX?Tt?GCWl7T1TY!-Y_OZsBimW4U4AeLrL?s zjlwuOy`yRz$@eMl)|lAGlEH{_9-~){eJ1vy#aQ}uyTa3_+l9dt%V095j*T6~)EaH- zOwH70Ii@~5lO#7Ydd z6^~@l@cp_SI)Tjk)1-d3e@#J{`0w~fa`l$ql9b^Njx zXrRe;8ILLeI+rVz0zB^Eah_AuS;z>CUdSkP`r#RLt_Y8`eN-SrzLH%?4$+Pq~l zQ)kdGFxy9p!T8jaj8U4Vf$8z7+2j)tPP=+1ML>waUkKhkSrj<8v452n*p+-^V>X># zHPxTC-LzfV^pW1xSmCYFEh|<8IWMjv3Rp!ypo)GVRP+O?NZvP_SFDIGyts-eU=>}X zimnM2U89N;D%zxqw2a*Sm=gla^~e}3!`>4+iv?NVpqLYq(^FGAGGDNiEn!L^Y)jIO z263_0IZXsgHza34M&m*>7`?;TN|1u7*;L(9V1Z3Q{m~Jr29`^EyD4?RjA&Lu(f)}S zwKS?yDBaSm=-Af-oHq|m1;WWK{pZ@-wbq0!y*+4>-qqQ2kMy3Gr-2I7aE9i;+q0qW zd$juEdBsKBQ5d#lM7yV9q@Xyruh>b5o~XWdwxfVLNfghnnn{kEd7M38UH1Ihaik#e{>_fTl{t%4?BY zq3VcH^&DDiIypTB{h;dEDeD;e8>{wk;hQt)sz%YpML)I5PNMX=jk77e#3~_6=FS}h z7|#!VM=w23b_>FH?dXKajfxGubM?(*Q`yztFH_l7p--k(>=V@D#q|jVs(o_U`{X+H z$#t{IquuPfRr=&PEA)vd7I(`&fjg^xl67l=9yvF6YAVw>qMkW9AanK{LO)7%JGi&V zu|k3)KJGtH+#zuluN%+yu2t|?lQkwY<8(PiCA#!IqDUGa&v=)rOU9P#QXk?f+#;zo zVb{=C;g?ZOl9L5Z??%}mu_^Oc^ae?fGo7I4uPfwpcQn5P{-yc@J9=z&C}b+mN1GI`bRiqN0g|^ zg|wj4`0IsQIJrfT8OfzvM7#A)PqOh)uz6r@5&1+Mw#Z7gBn8Bds zSnn#cpx89Qim7M0a}1+nI(dcF&3v(n*US9d%dPU$^>4TPw>zkPh}!XUT22c+SHZAk z-2}b9QGB>auWzh!)W$-ugA;6O8t9y{D+lMMtdqpH8}dV?i1-L_t#tkKr0cKFM~vRP zIEX8(nhQ3Ev_uD?aNz7f@>BrmARW69ZA3sEArI{FMXW?&!c2VkW-xfp3)F!D+1M zoj)iHA%^(m#X{e>-jzf(?Ad{;RWBAf5N!B|V&fI~9l9=}9O}i)&1EeHvs)bzy1X1V z+&m5GuBNmsA!?Y#fIhKNXs>?Zg%^_b5DR%5s`M#{Ke-HpO;#Cfvch1eO>F{vKzw+D zY6qRLrCLe0dC&=)E1ggfzvv9suMVmc0Ci}}b=~2q-i-B!^-MlibPB4Z`%!ht=*AWM zNb?72rloy!u-ZpHDjW>G^zbUZT>LetC>RDpfpg#*F^}0+GJ%%Uu7IL&otPxOr64osB%wlzOm>Kt;M*wVW` z9}h+gE|x0@nC5}Ycb?PQW-{J&K9_OUH=~jXip^zYkjW(SHV)=8$Ge)#Xh_F)G`(@r z=Ce9E(7vLAq#4(&f=p5m%eEiQo}1ku!|8^?uq({*pp_sSf?>$?4&^cRd+`vfU}^S~Sq@tPXTLD+As6jXuyFoN#;Z+{V)0 zyJEQkuQw1~@N^5RR}tO9+Uix-X0rZZmQs&I8M8qqtrIz{++u~2b%$6WG~F)gYN#>g@p>P1WRT-4jErN->4 z@g$DS)#b#X6V-Dk=tArn?CiMr!nwG&S15*l{Jxrwg#mNrGW~hwGW~gFwLe!dJCp3n zqCZRBI+$&*Vu5a?w>Z;agzvsl>wZ36LTuprpB*d&%EXWfjz!`g4H$VgtK9?y-;!Le z2%wi1*-Q}&x#_hmTE!jqg@d&(r%|A~bQ6}-Zj=Rbqb;Z1$WU`3F8W_e6!B zWUx$)+?Xqa<+R~qIc2z9PI2?KE-I%G6>bM%+8x*XeJh>FUJMpuy}(%tu%Cia?)v#m z{qvdP^FmxM)0U=zrtZd6+j_>7^Fy*(`p+q)GZ_6zt}iTH{!sW*nNQ%V`=7fv#BT*@ zVR3-CF9S0v*B4w77z~2iEy^&3iM}#A z6MYfGS<{&XoP*EUGn$62=Myrh589b`X08=&dae1lKaXJj&1{!FU(NG#;aQ*@Nbq{# z_d#>gq3Hl%$+!E-VhVqNGd*+!7rL;+C3jM7jL$0IF{{LKVQyr5W}-=cnzK=tpXbg- z9e%EwiR7mQ!QMJ_L&OwA^qL={5w$|j zM)rd1qcb=UW;3(VS^fUtY{V&tM)tzl=#c8#I~yIeI$73f&P1P=qamjgKpvtQT;Xs6 zJkRM9?y1=im(|bX;dxW}CNJWB<=bK2jJ6f3HnQtyqf^jMf;eJI-0;Fp?x%^oxN~+tj5WU{0UMx(3vUXBRXTpuJPvsex`}b3q%j@)2f3 zRvWxoqwDUYN_Fp#a3?KJzy%cR+Xt<Zp#F3PYD+n^M<}Ql`!8#bZ`(H5;4JqyH%@4Gb4q8yTceXBwqdtLfuFTO zX#O0VMsi;#*HSXe<+k9vK_~88EGTOM7SpG#$6->|jc5fFdn?!4-`Gf4ZPH?eWg8vI zeY&lgCuX==0-i_#NR8-6)8l(*UXfZ)tN_w61Foe4~mW^=ur8 zcPu7{gqohg=)lP-umdQXa-b_Y#QWpcbt049SDdwJHO$LLu+W{pD4?Ip5?$siHi4wc zy=Zp6r+NEsa{-jzcUNlp*_zK^tXSu|FSrkaBZAh>+i*!Ws~u)<8x_rQEzV63(L|k( zCyu)CHAgm`Lh=_j5OikAUyzwNPr?fWCeD@N1#b~BQnTYsW(KmDX083Q!c5fEXGh~q=CBD+tA(C&EfbpOmwY1ql3;&Ebs_X(xiA)$Tf#ajq8dU9xK1lPDaqB)zs-xrAFt<_)3d(uTv!yhDbM$?c~vpiB&2OpRQQ> zQ-9@8y=6X)a;&KPxsvo$tTPrFtTu^PS|;TcPM)k2&r97aj~%iI=ph$LK57S-$YJLg zUCBz_1SLx{PD;v%Q>dR~3hh*NJM@|Ac1R$@nH3{%Xzu09Aa1H0PRirk#x5(qbB>G# zrQI`XkRf9b9Ni@M^Cuc#254~(1_}%cgcB>_poy0l5P|L~F*I`c`Sd^zKf8XZ*I%5{3)6ts%R{et?bqta`m8I1!h6J8DmE`S3@>Eemq1rN8k0Im zNtrdK$V~?)QM}zrwQ^tJ$*3EjjVG@wjTXA7!t4>Q*1ATx6w$4Vb(>LNLWK{;WP#Yt z_E^(IR!yZxFzZy2b;@bZW~C{erUcxbsg6-gSBz+Sg()zgo!OF%*c$wZQy`+#566p> z8&->VKoCb@8z+`z^#;4-1R*qH8YbUJ{4{0U{k$o-IR6Htz8L4B`-2v;DvYYd(J~5! zD!Ktt%d^wiFQBmpxKPJrUu+gTm#T?2sp4i%M|8wCQZ+pE=QbEU zO-btS6aP!H)fQU2g?^C^+#*)KW*HVGpN8`^-YP>}Qf@;h5V~J*qLZU2x7zomy}=<3 zQQBC|RLl}e`#HZQgvN8ndYYpewc(~Xt+BbH$R%@BQYzFm+8p8W8OU%melZa%E0uP* zh?Zg+XwZQMTeqfLw}wF+fwZ}g20on_mYfHLN$sX}d=gV8t0F0*iil3sM6{@wd;@Gz z|5l@Qn%Z|0r%_bHBAiJv*(kC^Bp6`>r|~+uzx$9|K}M0)vQLXBH{*sAu?$tA5AQW( zHj+?7hIha5Db8QZ8qKX^8>kOsSKB;x6-|K#Z_^c=D($!OV!dX(8Pmy5e24a!1VNw@ zBhh|m35J(N?KCQ^UMghU0DuZ`GgPVo9mygS4YX77xJwGXzyP9%4UNVZWwJn9a?s@E z2a#oE&d2pxWYi)B@9HKl6YyfK4$;EN@ZTGp#__)BcayZO8eBB|7-tvBVNBg zGBDC_&eSF9Dz7$Ga3V-W**C?2SLs@3ZRj=@#S`{FvyB4<-84V)Ml8G<7{eP=?k^S_ zvm4;7Pe>o*pHr#U&vK%Eggn;vxu|T zrAUva=f5j};{$+ttO4Y`#BYq3z)*Tz)RMA`8~d+~gMycqu{IhrSa_7&Ch&@*5vEEE z5?tXz-e`5^Td^^dHzjmO&jV(1Q!9OaZ2h~^* zjOtkKS)#zc>*_3slByf6RaX+p`SpG?)GUtN(;9pVF{p7qq^Yx@(LjFg!$z#YXL<>} zqsLnB@b2OZ@rSGs5DQ^d!V+P%G(ncOjE0AYWA>2()M`PaZ-tm8vvkNE(9vTJokdiT zEx^*LRj@~lU9I4nfl4lB&!M*r>Y(ccl%&BJ2T0ry77Z)HWsM+9V0W8s+vMF^p({y) zzAG9Y7IIno8Jtq6|ESzn{0xvi2k{lmy?H1rlKljm3KmBW8dgKki^_~Z2 zQ#lLT{*>J#Iro46kHM;aLS>^(a(}!!3Va396!WH)K7`(V_qKo*w>)E*5~=@Xc>Qw6CY|?HUBRvKQhjm zM85Fb!exDa>M?%1e<1>@Z?qXV4M(!=8+JgOtV&P5iZx>)!8VDIU};#ed6Ug@oyY{` z93AmH?xz{&AwPsTp!WE*omwO)QLw1P|e_NP8$(03@g8ZvyOBTo85c-NJNxF3gx7>uHqM91@yj7e zF}g$2fsmvq-E5{S*FS&S;V2^ai1ybT`QL>k#my$r`#4Eo4oM1_&%Qh1F7nTYBn8iB z51#1v`5%QO0@D-unBDtEej+3dlY~N3(r<^P5t2}9>q&Y?NE#&x#ikk$eM*`vp+u@p zcYIIsheNJ$lF$+lh1Ye2!53BOzWnviFSQy&M^N8EzoFF>OMB#h8$_--+$l$AD2{`< z0$vp-;p{$VV!iMM*QftpN$*}Cy^>VURCRw7%@px`xU)ZK{%azXVKA`@I|@Wf!%=8% z-`}{?|@9%!AJY1IcJ33w_ zR~SA+DAkRd0X}wV49?uEfxnwC1x%EECVl!d|guxIm;_XApLHuPr@WL1! zg1F$cWMnJJERLnabbBR_idU-(@pz;&)M7h{Zhjlqjxxam*A{&tkCBDpf`i}ON!kxI z3udgvU&=F&iG;V4B2dtwF-Gk>-7*u6VRLO7fk5;6=teb=qzSg_-Hi%T(vdUC9lT>~ z+zt#K1!KVjS$e(fXz{Gd9AuBn8HWsB4EvA|oDUQ44vKw5@$tMEr*z`E_$9_~92aG& zl$pK5rI&Z{Kos)Zxf7*Vf(Yn1rQuLvXOa655r*y*mUn1Y2%AA4 zx!|e2q~6YctQ;6_S0r`z6Y?fbU6K(yE#D$S5N&K?lJ+V)C>;Ungb++Ctn0TFf~lp= zIy7YrK;jN73KLiFu;ktxFrFiAbWz)k1bqvj?O%*I`eH=r4~v=ni;Fm4j0}BaQvYHE za!SEpePdexg5Wp}O~U(Q4lOf@9lTIJl;KOk{|OlI|14m@3rIVnBJ`a?`d|!M`OV-n zwHr#(bev3V*<9H&69!rQdovTU>-fR&-vfgh5e#lA71nyIw@k8TlT>!T=DW0tq(XXt zWep{%&}7E=nkl@3tmyv7-)b`jSR;qYHEDRcID-5$$;<2s`pqPd)1drOSk1f%leu^n zb|>k;5k@(SZezBn_; zF%Riv>_SdGj!)sv1>n;~IH-{=A9LLxm4+K1Z&)Qz47@ullS|9BeIw;|BA z9kWpTdd6m@rxTP9CLtcs|KlSk=c9aE_cv_fNl_ch^4GuP<0Ln0$=aX|rFir>eqey6 zkItiO@fc2Nm{0;n)?E-ul6_16;Wfql<+|LaF?*)u-bHj*RI`ZF{i_El#^WJ?EJjWU zzwfQWY&>8lgp`wB@Bo8eJ4CACcZksB!mq&ftZ;?m%i=2Rro|Zi9wZ}snp#9%nO+AT z5lWj%VjXRnFna+}t;9`Vz|E^2;9Q_}R9?G~^9<;o;8`Qf1DGj{Hpx$rspq}MVilB6T~J1rd9QdAb(!7T_&#Ze$6f$SbZYA=%!8jx^R;Ui(;QsN3PJR)L1A3vr3Jp_Xn~#i%iB2h>i=HG-<;Z&)XyVYv@HfxwqKtg+tK6WIrtZaft>VfQs-Wej=c{V1 z(DT)_g3=)kJ+CKtHb$HFB+94?hl#W6XMRadl|wxvKr_Du)^ayd5rSNM>jP6sH9o=r z{H0ahCoTB0A_Mh?NfJZYf;e+6<9KF4#_-yzPiSi=zvfkL`mt=R=xZY~k>H#_$h*$D4kA!ocEZ;OMmD(GX*`V(BvA*#Wb&z(8|@gm z#TaW77z<(S0Z-W0ek+xZ;*03z+MmDb2#Fmi{ zWu{Qb*sWk8>{Qf%SqlB3xv2YY5d=hFMPBuvC$Y4+k^l6;&7b}j$y%pBnN8kzAAfBu z>Groim~DNKDE--Fw&jj{`pv2PvJEOnn6iu)N^Q8K-#m6-e*;UE8?ude=+8?ym^eji z9>}(kiEw-EY%|wHtiMAK_Q!KrqH?S!>!z%IUpA2q-AA<835Q9DSxRhDiA`Pt$^eKG zT8lra-B-GrDFR1mSBudKE` z&Pit0Na4sPk|vVAh%&Q_c|Vi*6vM7EwlB^gdnILby${=cACgRQnTk^d7!K+x$5S=< z7|R#a!u`+!eKGy1GNwQK-Wr4E<2YY@QbR-3YL%H51}b9%L7%1yYw8I21Ji1VD4H2W zn>QE)ZOMr^DglYzJwDZZ1dS90Uwj-bm@TmE1mVIY?;3*MXLtpqV(+m1<*Kn+O!APM zVgxmPpx(P9^d5yqWU-B)Y4jU*`%MqYsG3IU>hJMZ_rJXvrdE$lCr`8nYf-$OF3w{4 z*V8r_AP(poX(}lnNK(gf06^+!fS;+}hV-j(mqUEK0#R5R$f67{OROBUYsJdZcDb2F z$C*&83Bv+Xig|s4Y-UGEyLyb`rQGlMJ(BtaSzyNlUVQo9bdfr!6FR6;s9PGHr-g|=E$I%F za;1PKidMtIidL$DDXdhf80I(T@aW53Cfkh0GzBt;B@L4V8z4zrBnf?E?mDM2GFBy_ zU<#LmkqUSH8iH}3Yr~C9 zoH4RH7}y2NVvZa^ZBbkS|MxC`1w&&BrL(tka{+zCGD5W49SjPkY}2rO?`l^t{LR*e z2Yhdb^@DzgwcSpBc<){Lop<*;J2eqPNVG$FeghxQ?^K+b^BeYekJ{RFhiS;p{&2?c z{FU8zD@|*zJuRt`_RLPx8l`ww=jVuLTgybOgWQIZ6lWv%=2zdX9mVfabzT8*^VV%_ zJy``$M7T_-3JVT@_@gJmw-e^l)~@_xhpSV5YcbU97e#nfbazQ@CqHAV} z5Qsc_4TJVhn!@9G2J{10k`E_-<=&~;w5?c(M)&4`noj=HluqEq`W|5yFN4`X{F*Qu z3D|m+dEqgdty(c1R#yBaACro%P~GP@I8Uj^Hel^K4u?K0>a=RqdE5I~2dk#h7LgU;KJImHh z(Z&&k?=CoD__qE!W89PP;bEZIt;6-bJql(@mnu0Y3?$hEK>x$f+N zhGH^Wk07i`_ZQ_h<4~<_JGlXXEQsqteW7v8LKxZSzq#`#c^R3ag>3iSI@KS&i$)J; z&D*Bf{-VhF4FbDMJhC3H8@a2;eGS3Qq&HfX__1OrV8W0MV>Sb3R1eAp!Nf7C4z#Yf zz!RxiVvJcjC<$Oqy0AL6Jj7{22>#>z;pbM#;qYzupj1YrVb&k%2TN?P4OYeFLTW8- zAE#Z-?y0v~`*%m@cZ$p9a)n2Un!zD+DRlE38FE!;o?5Rz7#EwExyE-Zk)K2t6-)PV_mQ7>7UvypL@8!+H1Br!4pe4rW}@|t{&*>AN@bRzwWNy5QYuEB zR!I6Ai@X~A4$Y#t9OBhK%nTWLX!nxfN++Q}@&23Bj4jHoO$* z8(uP{J~9T6nTt+zKW97ObTlLJXx`B=Zo`d&8@k7x`|}fM7Q6AHlON@gsilDY5|72g zPo#vOvjl2K`B=j1ECHg11kJaOGnQ#Cc35K?Q!5+ij5zR`>gHs_Z)hvg_=ORINnC~U zBtZE>M_YCgUG(<(pN;>g3X1nZ+iKXrnwJvS&n8dkH=T}<$0zlOG(U7D2-&j@u;vmw zlN?nFQ^^zhWn=a@zbv_?CuiX*7=pPmD;cOHdgaWlhyn+8iK-9k?5&g1RZ0hjvXoP# zFtJdn_1TCZK{ZkHj4FU8r}YbssGuW)s~M7pg1?!@VnA4>BTVod0jh)B`?_ClKP z6NKItA#r$?F#h}=oh61pzsF|@;BUyBFoZ|5ZNehWw(4g%vm1ds*_O~~X3A=`a5G|n zD`Z+f7ypFw$?SfdA;gVGXQfdM)XGixDnXhHEKP;GU zo4;HgjkLb8;%GD|^p6YGLUynHV5FdXcY%m*yRu~?C}_r=qzvc`%=JpTqA^Yb?+hA7 zxlxO@ZsTS51YZdH7222+P$z$sNA`b>nJ6*M+Pc48ye^W5!v%B?t*Br;^2aT1(@9=C zRCw1Cj3EgA~h-9dsy;Xc<%sZ8_V z%SVSNUpbaQw;3MIdj?q5m1nD^T9A2LtstgPD{KEp(23XpV9!j3$Tc{f^CrtBmHrqa zjUQDmGNz_qNJGt_6n(KkijMUI{fw4rjC*6G@iShgAuc-e!%sJ)$psow_X-suk)gp~ z-03L1$Q6a9J^zB|J17+h8ABLl&EQL+f!w4xga$#Q{3(`3qqHDUpfqa?iz)5S9HKO5 zUx3{wZiacI_?npw`U6UL!UF$trSM%5nYGepr7R8yguX+BW)Y1e+E_k%>Z=_*g|UPV zqmjH%6fHHkEA?tK0u zU@#PDY1Nxv0e`Do1CbzE#bf0Q`fr`TXdS4CM1yVHL}urI<+Jlq_i;_^sd8ybOhEp6 zo+T-FCoz%~{OeB=M9_xCq8jsPjgvs;MW0?_!`jDGvr+~{lZy5n9<*;_~Y zLnYABo-S-}&_wgB8wvo~4+kJq4t#$`Uljlj!)Sh-+GET_ciZ`VR(2ZqGPK&Ic;Gq7 zo%G-bNT1Lw!g18{2avj%+YTA^$B)fT)Nou^0^BKJfMcQx;88VvT>v_2c;eW{cFjbA zCx-&ibP}xf$L1z$KsS^?_XMCD20%9~0UBlnTv((-js|k#*xdFS$W0~48w1Eq1CX1R zfZP;Xz8R3%_`dy#Vq`KtAMG>^|q%+;ugOJ4=uc#sTI| zgL#!;?hG&q8Vby-fVnfkoCYQ#bwx}f9kN7T1gmi0rP5uxmz%=4ls8c%-z7eI>3A`FpoRTQQzFKOi~Mnf&SpJxl?tZdrF`uz90a7p#gni2G{`fdVnrC&>N1;ovs6& zDS@6LF0TQdF`(x9Iun52Xh3hw02_e*5I~=Hpg(+U?uk0k7nVSuihDO2&=(ren}q2L z1JIic=uH`515nwI=N)K%Z0<}Q=#3>%qMY7jKyNgla{_u}06J$t=Q6+sp#Kh_4<^Q` zFFH2&WF6>DCD3Q$-kbrw$$;K0pf?4eHyhBKGr$I*F9s-4MaBL34+j@x76352)u%m&c)S^laj>iLa6%46NBt4c@eq%5`9hK777O4RiG10MJclBo z-h{RfFkZ}rRJG7+S?)Q$!Q+jbLI^qj-Ar;$IbfFThdqa)*S;`+qR6ptCV5IZ;L+>` z&+#OWGYnM$#t#wGRXGriY_I3QzcYJ5{&-%&g%!xhc)T`mz1s3;&tpAA8PI##H4fr1k5}h61_;k( zzOD=?+iaI-c$mkl%8jHSFc;WJ8a{iDXE?y)&iuLnVVXM=1!11lD?9_?tg>FdCuF#C zCV36t8OXBCziU(E^8A|cy+4z@itpMBxXiyZL*Vj`>F|BWOmZjR8LqQ!{{0M(lXeSf zlttNgxq9P=Pom8-BWS!o+mbf}4YtlCxA0v~0TW*SB#)c&?E(JgndC;kGm#C`W=Bey{jCH<_)qi`*Sd!gI*(^+HHF032q!DT!)7eK&9*TnoEHDh^qoFM8 z%%h;sB)P*+nx~X%@TBeNrBU=MCuj~XJwbD-a#9BBlqYCDQ%S$#`sihdE1$~~GzZHQ zH2)_@rjmUbYx{%`(hs3u@kYvHrVyGu$!1IUkt1a?s&#rT*e1+_fEZkxEWvgm%|v4> zMMs9n1i67}F{*M-V=?LRM3FEZ`EQEQnD5ka8&&QmaU;J{lX5w3S>+k0r*u;^zA*le z#joaFS;FoCI5GWX=9b~uAF%}e0MH-U|G&SQ9}Y!gHgb_Ix%F|UVnI=Wh{bF`0=}sL zjA52As7w~mOuC|wzTsse^kHS4}>{lwUE0J7*xQ;InL{#FR0!@E_I?= z;Yp!tMqV~J^2K@VWG9g4)$xRCHHeA)U^Nqa?4Ow*3RsfAUU_tG7$t9qvq_s|)lds&_fSZKF`xZJmTdMV`drI3Ge1*e5%A4N<`Vp|HM!MHH!_?OPk5Exa` zCdTV?6c|lqE)1ue%lk0I3O#qaS#e@81+tn8gE+xm7*02Xf^;^aFPwJ8CwRlGpf|-@hu4YXI&vh%wmO< z8DU{tQgeC|v2N|Rr{vQKvX-OG&AYnHK7DnMB?!Sqb&(f-Nqfzdb%r9R3QrNcc6Wp} zFnIU&NAK>9nQm-mLn!`iNKOI0b;OtM;=QWHmX7|~`EPsgkBeox>?4BCIALh}<5O(e z6GWFJ5FQ7e@l3(ODc`>P)f`)A$2@57FY>_SyzEvcm*pICg!&!3jwTgN9` z>m#7%deczR$X|}7P4r6{O=6zauAsh*Kn#u@1R*Rz;lY6s;=P6&p9WB>(CQpxSN_o3 zO5KJ7nXU?a#8b4&ijuXZD@F!|{JjfrW4s7&o03hTZr+LJBS3`$QeVT*0WUetBjw{wa0qbv$Bna5ygirUE(G!8oUZ_>g1_sTl~WN7Rc> zap`fIr#(hGC~xPXgn|tM$y{SrXRGp)zx^=*^utwqDDX<}?&@DP(aZa}2B??JiSpe! zF^Wa;7G(wC2w;!BM1=sNP>K9ZS`p7WOpVC|RtcD0{2Mluy^!>y`e;P7LReobp zrUs0vW~KRqj}^cmA@ln+!n8mNX%=70XilVF8hE@nOpbMASbusm|qUc{gb-+(9ZvgC1W*q)809~FZj z(7bFPkdL5F3>dIw9={sl$`hQt>=bB8bt`=GL!A9yQg|v8;l-@%`{c(LEP#c=qVAtN zzHst&uYbcshxTX_j{7~9CM_&UsurR*^S{It`VSaKScmik{NH5hT*@OxBJ$`*@I8cr ztg^xyS!2J%BsC?S-XlAb>0?LVmEIC<^A0Bhv;fX81Y%xIcgob5Tj-szoVE0SHnl^o|yz0 zR)HNqL4eng%4-~Bkac9vXhKt;Fq8$jffWzHH?L=;2a=6ia=A00?Em0=my&*?>?;ZWWe4NX2XZry|`ifBT* zh{{sJNZ#k4H?r7|;5ccf`0q|N&FwnSa1T(JE{S0I2VWZ^En2CFjZRXaWS_g>IkW zWio#V@SUKBvJ1tI;AgWSws8XuSqwd>7g`nW| zD4EU82Kvuug68Z^MYkgpJ72{voB&K@Od&N7XO~CQsAm4O8ZKO#7~PJ%!ao;J8I_5# z4WHX*(>oIh9AIDJGA9zW3T$YVrd&D&glx5~h11EMyczOeB)+sN5^E$u(eK>fjdEEVZ=L|ZYVTO)+8Jcd7`aeJ8W)NqF^4EXB zdcDizg0zjX#N1#1>SrE)!`I&a56{@%I&4$2!S?-ggaDmCY0TY}K?D~`7o+Z&BNLLK zrvXZrKfq|bzsNfX<-*KAFza-3i)`GYgP={gPDcgy@#0*9`(cGPbfCBuGf%Yn&~mgv zdzznx_*RD=0=FVZcYb$N`X?vYcR?jvr(2my6(Oon>6K0;XeWuTQR&W-N|=31sl*DO zsC48asC0?Ebo%|qK#O?k!#`W{(qH}gpM3nG_kaG}b7eIxVkKM}|7BPShtZ`(3as?- zMG)x{S*b##3M*Y2k-mFQq8BQfsF1eyawH0T^v{2=%-FDkw5@@U(A+k9tvF15ztofu zUOFatrv@k25WHzPF&%kFpKAh88$wSCd!R(`U~N=NRO1@IxA!%;IiCM8P^a_9N_F~G z=B7cNKKN_D^^tFX>df0YF0n)e9;}Oi;iQqm=2%p8%No=u1|!25GfuQqC3uHhfnL$FN>|7rOXiR1F)d{*qV^BpT z7NEu@j6o(7)y`$K{T_Ah&z&gs+ZzU*`^#@A@qGVdM^3%*n{PY!iv-hL(z}ZkoQ+A< z-reiHdz~{Krf^03@2zV8YVYnTdv|EL-VJK)ix<(m%xG7&BQC0UD+;e-VO*NRGXvxM z)4BheC3kqaz73N5rx($;3|SX1xe7(VDlC%gqNUjbQ#B-)wWnglPx4Z7lf3NPWUe;i zYf;bV5DCjVa|3~}eUT-C%YsNvaLtCiqu&~6Wz<|%E4yiHq9Uy73Kvn45?mNOn@LUuoy(1rc!5~2J;JjwC z?|bvl7JmC$gBaf))q_W_>#pD6w>ECwHl;-!QEW2*_HSsxO`d&=*7vTDAcUW6Pc+Na zwX}=^EOfG(pc~spc@hEg)9(UA_iGv@2tc(v;()uB2^uVtjr9S{@=TBQEK(!hQ*FWY zly691Zq~CHTS#kdvgbL4+ZR?^VW7}xzih&rep5}@^!;i=Z&4F^-h>^MCh%Ns!j3gH zVaF&tBcT_5&6*%D!|zKkWQ&@Rc@r+HG=b-86E0g*6D}LgXhMAj_kGrsWf)2e=&a(h zE(ZfC`WXzAKO)}AC2}y*qsBN7qH2E`Dd2$Cz#2Oz57K~gpiskVoox<`X?Kbf#mdBUN!^L8YX!Ef((IyC2 z{wbr4wmC{6TaGpl8f~ac+0G6~Sa0;@iyD3TB{Z4_t=j0zmo)k_*60c9U&PxrhFD{x zv(VEgj;N=#>r!vDR8NI(4*VX5Vy>MYvOTUc&Np@1T(*cdmt6vFX!okL;Yzqg4Dl7C z4GW4Z(ZN)0K7VWUk(=~dc;}73uO;UoFy9#Tc3=vpO`QLw zP6Fgzr_IuAqk+Z#r)3k(;hjphI`3$IzN$>7E`c_*dsW&@EuqbWk4gmO?7kM-{Jhad zgZPD7vu#mpwp~JNz;xBtY+KTrw^?g+KhauRbJ+NHX=@hs^ePNd^z_>?L9Apq9o}n$Ep3r}R1{`i+GU|t$+7to zcz}kl$^%@vw@4Gd(d={?ITwvDOI{)4fXTBifDjZgfI%_jUWF}Q@n81Yp5 zq6RhfaFxTlmq0`av?>t^RJ4eQe|1qrJW$m+59y`02yn1qokuKRFx-z0^3|1&d@if4 zCa~&7%M~qJwbgP~*J9S=D;a8-bKH~|%(>57u4Vi|FKEtr%foWqd0PTl-kg)2SZy@X zW@XN?{!%W-@mw|MI%_iLItnuzns9a{GwyrS1c_X=38UTwW_@K7c&;{qy&W{K`7B*v zMX|-TINnoVw+0MT&!Rzrp2B--5f6WRrQEe~GxSj1_NWYqVQBD?1|N*-(obassk5+9 ztde5*5?Gi9t;)iLbEz(Q-kzsqg!E6uTg=oZ5E;Ro@z7YoO7{5It^O2-#Q`B+pMX}%&lQ) ze6qZ1>8Pi^pp}t$Y4?(mE%vo##EEEa8RajjzO;5+sA_y{*Orl;p0#Df&wouB$;KLV z>61vO;SM}V#08o_Ewv`-YyeG&D^1|J+64U7*U*I69oMa|9PNbgQXcp)8DxAx6m2;onXil(+i}Pj| z9A#?4ccJb6Y?1zWcB8p!=RLd8?1#@xt6gY!{n?G?lh}e9j2GF0m^1%MHky4gebtR- z*BpyBnje;%Ms*|p*^Opm`S~JwWf!JC*?)GUnZbK7ULgt3ZZxl~C7#`AmOCQRe4pKD z&M)Mn_UuM;@G)I(sC{;$c@QID1^SpNcOeFQcB9!y^z246`WS`Gu>I^t^95ASvm4E9 zLtJQT`0PgWN*gr);v3EGPrdw3-oKHJ<_k69*^Oo`?AwWnXE&P1k~QsfJiF1%y4ABA z%^`*x#?IRJMyvawVNYk|csz(+$*mzt*oaOz<{^hl4i|cK7=jJ`;YanTLk&OgVIEjd z%Iws3u-to*ZGs}x2|@flLWqtv3Q&j+_@o2L$UzF>FN>gUJGc!`PtM<14E>{Sety;*PM?~1_ zepcUsWAT0%AQaj};ehOXY&Et~H1hViwxykV-%&Xop!kVawL)Hbq($~o?6epNhY^0+4SSx^W_p@&Y1;FTPPwjAVHiw?!h44___Xqq*+?5axPag~ag+buT zmnZRSxkqE4kg@3dNw{nxIYO8(-3*~G#MA0{?A$oS$xa6~bWaRw(%E3pvq;O0k&nk| zLQJQ)-~tZ0#-#(r2fre!Hu979JLUnMRGBvB5^7xdZFxbg&rd0QLm4%SD2hbhg;p#8 z9{ns|bWiAmG)bx)tIk@IZG6qwX6#&hNQB($bz(%5nQQn z;_ep}ZjO+e$w-lG!S9TZ*Q2uLBfi!kSdh<@CD0p8#*0(#R%Jvvaw8wwf)*j0%{0}c`kG-osk1XGwkbHsm1c;0Vm)ITyKzsam zZSAqVYR}O{?Xh>Y=h5Zc6Ou2`o&fRE+hYJ|kN>W%J(gGPIlibp_OA9kwtRa+@&(!x zAYOWV3;^x%-?g>J@~S;27PZIT)t>h*-=2_sf%XK57vG-mbmC5-xix;LL3O8!BZ(A$ z>lYDJq*U<{8G&wL$l~Yr?q4CnN+()MN<7W|yW&Vky>%BjfBvSDaFY@UN^Lrf9E?=) zf1FLH6}$95NCWJSi06aC0q&2<9%wAO#F^1sE-zu|Lo25FO(isGI8}-Vp44e7C8+Dl zq!&YyuDF_>C7uD%q~-PCjfuO@yp<++y|3tFDDZ(mJ-6sCJWzS1#W;T2uE9b15xMa` zjHp-V+{lVyf;Qr&XXSetQ9BEW-xfqmbTZx9eV5`vcpWdVwk;zz&i>x8ESszi5r%q6 zvM-gP^4hz54T5(<5Q_06H9JHgP`Z|*?1^s4CDB{KV*(e4M z*n4?wp(xxNs2gcTsG>gt^D62dVR4ClxTHT?#r45nM3z$>}4MSM}O(L=(f3<^5(J1JK{xZRbXY*%eZdN>MX(j3A=zI3~eFdA1zBsYv< z6fIU5#37+}u}BSo%|*H;4;01IP~2%%l=IfEt>O$rSqvSjyttxB$Z{oDL)J+gl_Zwp zi-L|79{NAgi$sTAd~usoDl*P{dM}Mcg8J*dv?B?GEG;P*9?M_Yoow$9mh$g!Zs=aT z$p_N%TE6tIej^MUjr;`H-V_2s_|p>!+KuSJ)5*z10mydp!sIDKwGmM<OOAPeQLmG?Oeh)}k*1k8*j0E9g8M$e{PcrN$t_lb=wXv0Q+z_Nd}lA;TJ8u^z8 zDOqDz^m*N24as`==UW|8zYX2;BZ@Nu88GUW3ifm;UrmQgJ>5qvt8B&}d?vp6%QxMXewF4-T*~R5yVBvxRX8f(3fl)9s z(ZgX^2}AO7T|n{$dLYYM<+Z9GOoU4_ATk&AhSej3e_4CHDIfI~8qQjV9QX(nn2&qy zW5x%yF$o3~QowBkM;3ys0jxD;;teG|Pq_Pl>4qLMPJhKiP0i@L?4tBQ8*oD|1d=+c@~D$Q zJYrv}yBnbn_a92p>C-xP|aBO zTt)4AhQ|#BDWtZs4Er0yHy$TyL%^6)f~?Fdhsvn)JKmep@7aoe8t z!dGi4K}^xBc4NE^G2>;%u_YN{+Gf@drCZsC@YK%Aep8s{^I~o9Ery*&{tSzj9W`Q~ zR?-?d(w0rBsJ$U(+1Bz6`O3DGZ^%}*seD7OvW?{%GL@|ltR#Z=t{~*A$k^YRCHM7* zMe}BMMV8)|4QD&=ICh^B+D28S8BP0FSk~+cKKHM*UdkwFSf4>t#w@C)-GgtoLEhA! z$x&}7t>C-sGAc%9xyi9P_w}u^b&+y80|L}^@?c?RX3b;0VV&@CWm&@(j4(-lgbaK= zi=_dDg!Y0zUZKM!#-&S#me+)lB`!ynCH6|b)TYsmhRcpD8nvq7s#jWP3+X<<13LOhu0 zRM*I>a}?IZZNH>G$+3$_3Lb;@KE0`z!>(tJRGr&csi-!$ktJU)c|Wr`)m;qby8S$6 zd=kv~BxBsWk(CAUN7VHR4TotCCR}O9@1Z1M*Z>{gA2!pd;BeBknUmxTNZUgnIyujh zcK0{T=msKb5C7+nlQuC(^Kpxv5G#TrWu9+(%`lMu)m85*%C}bWO{?JxsQiQ4wc+_7 z&xf^fwMPr#pq^*l1rudZybcqQpFJ$=tQ9eqxz*2&tp za;MTk1l)1aFD+7^YmVNo;&&bmOoz$aVLF=6wL>+dB*Msw2+``*Uo_`XH8?yeT`{M9{+ot zX*BvDGAgwOR5I&cq<+r|@(k*LXSV7fP`FwvW8v?`&M{Ic&HTN(GzymChO70= z_U0p_%Z)v)-!YwIvd_@0KPl|Z!Y#K*W$ZOI8KGJAyf;5|{Ny}q%4zgc?jxd)6rq>l zg6GCvJr9SqCHg5-PJ5;Qyd%A5WN@K0Br|aTJBf!>rdap?D)zhyo(yz8%g1D&n`9=Ek>*?1Q z>DSlOKgN2ISIpBc_8Uq_+N$s`JQZK88=#Q1iAgHUS|8B*xwWqQsHi0C!CvY5cRJZj z#Xu?>2OKn~m&SXItVuK+}XiT{J z=%PMYN^!0K=95T5sr6YQEUB-RY z`NIR%#y!>f=LY$Mrh5uu5~`z)Y6nywQZFQ0BAQ|4!=Aaz*;a;>KCkCfiRYR=q)6#4{3FeG<#w>D^!{X!zL3_gYVU+#2erp8N=5CpS5XuGNlJ=nZg8%Lg!wR?@!RG#=eOYh2e zNLjjEq%h!vZm)Q5JKatTQ(M3gZ$;+9qj`i6k@gP%Hl)^y?=~-RD~In2Gr&9>e+ST( z)lM5*`JLEyDD9DCpHO?4^~c&=Zigg}1`mCT&Eszne_U z7ORxhK3~oTKC`LW#1A8Wp!wQHvHh{Yox(#qk*IlHUB|)$m3+%KY=-iq^golz*Yt<= z!y4&(Y|CjVKgsYh%{S%XAq*Lwo)zg?J)O?*{N=i_=cm&=y&R7`U1plWr-R*m85;9?h*DX%3uFb zd;^1zO!17%*7YQI@h904+J{U>m>G}r-#V=Y#`R)3SDbmV{J#ixQB=1R*xu++emoYj zDQ%SQ5i*Rs0B1yIk;v)RJ!*p%gg+WPXB>~a?^c>9U3AK0#+*g30AVDz3wF2}rh}^C zr_md>+roNd8JA9UdfdIM#EyQV-YAtFg37;XBTbk~(g&}Xz0E^SG69IG0IKB_p=0=yfo7$m0b%&NAj2j zF1#<>m~CM3Dx1hQ>cI$2O3m`lzU0dZUgUo%td( zy9t-MS(zt(HnIZL+VEN>mr;`bsa*F zYIif(MV<;P6n=WvSEmuN;HW3tg2>a-82qNQ>2dwKo5Trm7wv=zapDmC?on6Fl2v8_ zE)B;`az;uC5i$Sf9T*LzomO;QC{SY8B0;&!1QQdMe+?NrA5CURlsdXt^MH<$Zhl64 zn;kd)BF8nQfecS4HKoy_M@Vy}QH)(d_PEPb!{~bWoG4IBx{i*Gi;i{Pa80#BrFqo- z(yy3kFRjp<9S}aFT*`AxZ;O8R^(Og((o|2#=z$octcH6BeCTJC8%`g zdhlYlBdY|MLexoEz5F4K+alNtpz#?&q8uJ_=wG2qz4Jg_@Rh zJUeQe_HZ>7yXUf>yQR9C$TH;maW5>!VH~@;zw|nvTb@M>Y5ylKr|llZc{`#azPEO1VFM^@ z-8zOM8j}iz#R|QG>(GBS>yd#GN$^=?W58{z++DnP-zkN@jRaE|L)jSBaQ%28 z@)aY1@l0c_*)RM0L8wJP@7vb|$1Bhn0eO1DmsG{gyabN=vh6K^(_=(q3T{r7F6TpS zxtvl`CyrbGM-|Ni0}bULvV_uB9?IWm2`=%L0|oP#R7vl8RDYp+qGL*u#`#Sf7f_hN zcBmOB`TEk*_+4r3($e7iSM!Y*DWQs36HA~lVWD%GEF+*`+M#@*v)^r0&Y!^s-A~D0 zjYiI_!=Tl2a$|6X{pq2qL*YUbmD>F{&IIygI!hzdoV4z*3Vq`ue7(-%@~&EdqUgv_mh~MqiEl?Hi)Y^kP|qRVxobm4v|9 zSG=*X7R!q-qiCO>_6>2yPiHo|iXWyE>__FZOlV|TswVsov*w`MT`5_wCHXWhOoGX7 zZ4>O%P2q~2(hN2`{-4x79hyI|**%?s$coZ1Rma%l>6pHrUYfq1&LHRMrOoc?@Vuv6 zGYyU$As3kJGG0KE>FAg6$3cUNJP)_ri|+S$-5nil^%}`OA^n8iE z@3Xh+b?TkAtz${WSD(_1YJL>RVkbIuozktxoHN-qs3y>b?OKAd@lY*^ZW}KWXiEH} zv*}s3;*bb2d2vNkipt!m}acSnx7qSpTJ{Q`rcZU zKaJqowQOnrw>)AZ7b@Y}_@{4(zN)63B}zo zU0Xsiwm2#CuUcX`zOYtq`M*pjl-(dQsL#ZB>P`OCd(#uFHh1)w5cRRrPV*Tm@aQ3A2>-I3$?+lS2%QCBd}(FzgGHf|WS@q0-q`G9L<*=Q06K4dv?A=TNJO4Xs4 zv{I<_dM|l`^^!6aoe;0kOL38bv1}*|^CO?y)Jz%K<@Gt(EFLa5i^Y|Le_G9q+z+l1 zjbJdQ{AZd2Joy%nrwLAST6RByA0XIw!&h=GrbPJ81fP5FukxC*UnnV?N{C;4Q|&Vlgn0l#TsNozEr>fglyIUp1CY| zfGJC7E;aB6t)Rm5u3C__X2uroD8xc9a5!n88V2f&p~_murGR2%*$@X{3H-bP*EpW! zhYh&mXkP-JOMx3e+Cmj&b?j*^RIf(QrDR!4b!>;WMNBF!5x_qR1ax{P z$&VWX63g#XdzT_$m4Xszlqeleg;K{*I?n+gI1FpkKMOahJk}zGB)^4lTk>>Bo~|b| z9kATxY`}qFN?LL`8SrHD8?g_jI%SI%>JPKmKA4F42kx&S&DCVTa9m7sE;@I;|75Cy%GN0{)zwEzVe8gr`cP(`8}>>ZvlZQvb;^ zv4ZJ|GO^O8<7HxnCjNWn!iFvt{C-c9G;D zbU4Zew4TpEp9Q%doU*!*>MB+z%ft#+C(6VMR>#Z43Qdldi5094mx*<(4ui=dN!mQ7 zlnFx>lk-*z5gp8CX?2-c!Gx(rC|<#YRe+FK!Q@PtSjXgSdp12SOimakNPZQQ<7Hxn zCP&M}3MPlk#0n;d%ESsL2g}4dCda|#fW+#YWkBGom`K*;AD`s=!4b2Y695}li8D3YS4t?PFA;-{Zy9?FDJmBVPD(dqJx8h!@_s z+zaot7jTpG*D(E-RxU$f*z$KYOSk;tEW7p10)B1zZvXX+5mbZa+A~40TK`2*!p~(Y zzA(Sk@3wQdm`O=EobBwq*;Z@PC;>nga3P)>Q%}q%*JUYZ)=(>FOu*eGhHkYLtmFlC z`$6v@Ls#3j{`t4;yZK9>fAKIdclCm4g2K?beM@sQ#IGUXpUpcvZwV+onpIr8486R? z=w!_!hF)%QA`!iO;I@xd1A)uG8i+sn$UU$7%Nwr!gSQPEh~2#d;p8Z~UTu2$e>Ir< zYqG|eR)KlPouB;EkN(9q@3_k>rg_;z*7#RavQEHUo?iZLtkI4UHT}}%PNSCgYEerC zbf0L6f`vG;L8+p!r)A^{Z%CY(Tj@iuBky;04SYs#0{ z?}mr{jQYA-^!%?{^sH1uvdbtHJ*zgOMjol>)I^lO@8kjP6Xkt?ZiY3(G#jS=0cPr* z`UlvlR#n#iZp(t&ZnTY}ruUQs|Rhp5pBMeT50f^Tx3&bj60;lmvAbx*Y zAXW(z`1M8t@z!O5I2B9`=q7|?js)RIFFMNlPnTMi#1ERF!0>?GKJaz}RSH=%JyH z5up1@0|VNtjIy#|u^QP>fCfs*Eo5n5?3=nX({CS60jo9ioBM`-Up>+f;i3Orqh=d+ zmggH8riCo94U~sdg(&rfh0eSWRJr(G0s+g$APbRk_7>k8RRpfdSs<3T{rR84AzxCh z8n8kZU@?^jeCT7P2%3Q&2Vb}#Q#1(7kvW~;_2R|hpv;={vf8a)G^blI{WMN_{{P$K zb%)8i+6*1W@qST8KyCV0W)jc zVjtCI=T3!Kn%SPZ-x#_HsJc{hH#f>%4eoE|zH?Bja7ijyMwI}GL-W!A1(JEh2dsSP?wb&>(T9!b^S|fx8sbi4VORoVs#{@V*fP{|nDBNJRICQCe?V~zv_ z3d|cK(^|a8lVlM>)pPtt4dz0mi7GJ1l);aT2$NEI;;?48AqOZ=pUW5XNB-*lulnE{ zZolSd%2&wb-nscY{+<3Gc~c=zG2E%n*O6~4i;x{Vw`snVt&--^E#~j|hcA8Znoqs$ zn%AohhEyLq=!@PGe~Dky*EE5xRWW>HiK(zLC0r(+uAbEhVaGc+{grU4D7l`Zc`? zU3WfiSynWBPDLaUf2Rwom-gl_$pe*1Zg^Y|N{}*|6Rlb_$Y{>MF*rRL&70@JT8++& zByxlUn+JmG#4t0AY#^!H102TEa+<5Z5uAe#&dX%xrGZHc9x??%DZ`<#7;mN~>Ob-8 zM0dcs+k&xM!yM~7gk85%8_%l)B-u?#B(i!DD?va>% zmjeO}WKdTm6LqqU054%omR==NZ__WyRasy^H*n;8pw|_qhnc@9_bX>Y=^| z!-_JF&xtHx3v_*tN4-^!*Y`{TEf3xE`Us{HbiN&dv0;0gjtQ^;O-e2Fc>1S$gm5FU z2gG4oZ%GuIWI+e#;ivxgf8KrgQ;T2!WzQKT3D^0&@ob?a8Q zIyQ){W@j<%uV!^;u5NYTv%1xty}H$X@9I{!VRfrJXLYMPcXg{HHflBL?)=rQ?oq2- z-S@3-b&o!^>RvllAO18D$o0CLP$h9YztDcqzOQcQ?`EilA}K0&qz7+}SwsQ)u1w~r z-3qTD@>8oO_QY#JHD1119o0INpozz4n=j60DXao5$gHq)-d45a4UdNXotYq@KCqmA!BI}2G*(=gkiwjW+)b6 z@^UK@gk4m_fB=C4;^4AC1V;x;%APosRt>}@ij=HI3oRWC)|hAoAlMo`IBviyAl|(! z5W(d$5Ik1{VWD%&VWKk(h%g-QTNa2_!bC9)2ow}y;{D44u}YX&WT7@V9sv~}TNa8_ zL4_C-8e)AKNMd0rUcPf#7=(#JD>l}DMtwsu^`B)%D5{)8+oZmyjGU zciV5L5|W$pjTmGBw~$Fg@u=|>w8v@PZ0GW6Wx3Js3SLsS6PAyi>pVheE+e4>c2Itql3wZtWJDaHaec*95*rYtbPn&K&1f=H6Qu*m;dYp7DO%nE1BI=sA?UrVmR}vC1(mx`#j-6(GBJ6OZ)ROw-yyR z-bS1jhq=Lzh2z{e5?3%N1zUH?&x}o1=z^~1_+h!GzH?V#e|bU=x-61iI0OUqUc@4^ zmcZ+{DU!|KF26GkN0mf_w}Q4^%$5xLE35eA*8FR3yZ6(7 z^wE#L^>-|Q<`FvR=Rq&?pS*GZ%U=1x&%f{;FDMs9w4E=QG5K$c=6X&`sZY7#n5|%= zm(34ruF;%Kla@_V+&9iY*wO5{*hOV#Z-yD=H`lRBq;-D=KN!rA-m0eE^Va>a}B&yt?y7?f0KGo2blvR4`LjFvH&aVn!9L zQ3Y)72%oQ&y>D%)j86Xfy0YO3#Ij%Ro-wviY>xGwDtK9A4wWRn&H7FuL(ZM=8)3@UxiUjqKWjS8)q87uXow z)3L&m*|scmBfR`{5Qg4%36)TR)x^K#4eh+$vbuyk+jQSEyIATP?&x@KhF*5fG=yz+ zI}a_9U=8~&Aduh^@l2QUt1irUp+=z$>f37DjSbfBm4k@GVG&p+*7RB38qMfs8jY}%1T6hblI7|c6H^*ia#?$CD`<3J4K^9XhtF zKd=MD+m)Q5yUzxAM92<)#MWJe$Fm@7l3Pg(STpOrNl^RLHBF$Kz^^pir4mbfTuAnb z9Uyfy6RWJRsa(ep(z6{BdmV&2Lx(t|`Dc(EumO$D=3p`K|CvT`&s;Okt9&%!L(Oy{ zeFiZL&oST}9N2+V_!wk?D%+#XzGdx)m)Ej~P>q3mO3LGZC!O`2@`!#bFIag{o}*G! zB-wn}?rt-ZUkrXSJi(T|WqomGUmL(G=E3m;%QT8yp7YQHqvp^9rZm8moMj^c!y@ue z1>M;$=yD0Vv-Nnx?D}MYJ#}|2@6J|DNNiFdRTBFh4f+eS)9;P_DOIw68WtR7k%@JJ@KhWgWW4}c35)3O5%GJRM+{0 zWr3wfyBbW5{O)eda#)V#Ei?L%(BXDt7q|Pl1*1wLo4NctCRh-8uHmzymGyK`aR7*@ zXAqteNQcaAY!`tC^_}*NKxpJnH1QA#hy%9m^^GDyBcC-H0V^(ldx)f9M$F|)?LdRQ zPvkbdA(e%K5a7DTuj>KJ2>>`m6qFi8Si|xt4+5r+i$5j-R}@4ZyJsT!wBcSapMA5) zpCo&0cth{jFEy)|_(stR^oe(e$rrs`AAZPS3AE3Azc zGEfQ}a`HlEqBwWw?71#v`e}j@?xP9Da7alnB{8Hypp5s?SfHKd1j@M*DCcS%_P9QY zNgA%!G;@Hgl6#D&dS%Q+B4dmumXf9l&uO>KWyeb0+wW+tu$1k3KGEtla+5y1)>eD4*8+NGtf;;E0;Zo zGv3f-rG+A+XFEJ5F=x@4T`Nhu&Kt5@RN^zrM_(~}CQGbb)mfE%)ndX_enlj}8RU7t zg8lAPa5;O}wX`eNImNICK8HfW)PP8Ch~Ytu4>|PGEN1wFUe-$w@wpnYVABSJSBzh2 zFZ)myXI^Fd{5wvLQw)nvELI?edeTCJui#@1Lv6X~vzfO+(1;FiS?82tT?dR(oG$f@8uZXVvZCOD!u9WXv-m{N7c z+ENxShKL@X-%AoP11#!<@l3rqvD>gXkv^J90~Lc?h*eUJ>;M&I*&&h}(L{(`yS-hX z=Y70q_bcWvwyc-GtDQ%-EXuc~dW{rB+layDbAN?q=P_d}uxOSQjaf-nv<8uroln|< z(1O7aP*tJ29Fi$G$kAeEPdhs?pJ5fG21Ru>sVf@Nv?F$#-$y&=6UxoC(q-DKjCpza zY6otP%glw z@Gp+;`>SIPPo=|2si%)SLLUJK{j77uBB;!8suuv17i0)b?6CAb>%7E{xdbJ1C{p}v z#`R%a(B|nZAZj258b3?IlM9u+1g1D$TSi;KK?Bt`U~LLEGp#=ewjpM+@XZbyk>`cH zdWHp$0z|BedYNXc!PVXew`eN7&K5GNK@r`)b1*Lp+O-HM#;l2Mx_#NMqfo2sA#1?! zu7_c>sK|QQ)N)VH70PCoXfuQ-yMXfw70Otk#ecb(X{<)Tc5Vy-?yZY>z-msLC0G$2 zUONI0@?u3izz~dsdXLLtuCQy-f3*u2-Q4-E4wD3&9}P$0HaJd6bW(oeZsR$TJR~bR z6fN2KX*sP+M%745IQX1i?|e{iX4AK{IW{ie*8gXrd~4fTNQ0)SG6)HNArFha&1Cdz zAVjLX)+(Jv>M}?OsW7^V;IuxoNkm3(3q(DI%J8Q!h*f2T021k`W&XMW;FNj8K$K8=25%mK41tU%R-(o8Qr6s#7U9d#b%0LujZu51*!|5~W0QFI6VdpG}N^NMSuWl(SUM6~1ymUFyL$b|;WUXN} z)g?i?U`6@_5>u)2u^6kOr`zBuI2IT&`0MB@DjJ~N5w%AeMnfCbfCyL(XhqP|fRV5> zoJe?N6M>k?fi$WKQL>s)#^2b4_}7y0xa3+9I(*y`bbt$u3@#8qFi5DZz^HgC!KRIx z%4=X!DK&O^k=eqEB}~@G^GPjGUS%orx{#@KYx?#L5JA7h_IsDxV=lMTCXEzU#(^fp zXuFcy^u3aSR?Eu7tBLD}hj>*yeSYQrCtg>E&{6Xh>EbniG&NtPyt4xFw$rDXY|~46~F~+Q;I34Tw7scmxZ!65aR z*0fqUv}tFxsW4U=rkYj4qE&0ti%;h#r4J~@U!$$0XfdJr>MO?a7x;J(i2b9#lw{@PLsvT^oMM4srzsi7x#%Qdgfx; zf=_8xdFzxi*Rt3AP*cmwA)0}mRe|+5t{5G%` z_QYhWg$%S%DS-;V_C~5$NG3hCLn~$kVf$n{ajc{wTb$VJ87eAR9d~}q%}LBmiy3Ar zeovulL&Wf^&1O|M!f|WXh#J#!>l7L@jdnz1*fqUJea+$kv}V=3npN{MAe}<W08qHw3=AA@J1=fv;`|e05`z-&4T7owz)LJjf*-x^W*mG(G*s zMvv%|P~|+4u`vwkV`Hr`jN`I_BhQqV0Cykm5N`0@T93GNubVOlWCX#57loh4`HQ-o z)1|){jOv|hqwFGpu)eW%w4BJH)#{_^$4X?%j_COjgidbkO^o2d^*8;N@jA)ifV=NG zP{gO*1@>%-`w{NG@Cx)(x%-|_G_-2j>=Y&cO6~C@8iiBFcoLFm+dGaVj*{kA>u*PoVvB!T*`+y5*2ysNqd52Ur<0f zEBoCCekm=!jN1)XgYz%t%Mm_3=WktPur<>vBEEcKl9TCTf- z%?eXbJ+GM9$qdHmjm_%_=lSesiq`h-gwAnRP#%paFH8A+90mS$yF5^6730WY28MCHzQ48)o{8Hd5Epw80&S&4RbPjBH!d}%(xrwp0P_fS z2i6LG%Nk#CkXi;=(?vRoga*u=Dy$qN0~M+*WMjHis-46^nVK=^28^CP^~R+$nP~b< z@AU$ysF%)4SOdIN4P6BDvGS4)`Y~G3&_)uQC90MIKIl&7izM7L>G(?4;)dr(2EEQX9JL`lb#Mv;D6(+a}NHu<@pHp(Wqs(Yqe z#i7OL>>DB&KitnuoFpOWQ{-f|svl)KFiu+)YEU<|=(|ozvRFc$>qVFw$QkS**m4Bb zR1s+c-mpN zem%3|*RzIDp!4flC(EyMnF0}Ne`#0VBopE*oc@BpFAlw?)rK*S)wBYNOx#LAk}90m z_^+ABPa{VQ%@_zOQ)wDhW;Pxzmwg>!@pr@uE3S~khK$2)@jNWjY-KH&iKcELN`B^( zQv=z|C$U1*LZCm(tsX!*c50QHF(X!L66l5My_x&2Hax`H#Rq-`!_^b8lnlGVs5Qa( zun*A~`V^-sZb^CZkU~=LsvL{cFB@wrZNYe@%hjo%r3aXX-)+u6Q5*D{H!G^4)sG-8 zCk8{BY>|8gO*R6=jY<#ao=e|V2$iq5#Hp5OwN?JQmOPq7W+z#+G;g-vO-if`gqXF(xIWEm zTb(sxW0Kb2)apq#Eh*SV_Eb!MP@1)-O&aewS9S<%Q+F@6dYnU14dGqyG4EWBQ)4rq-@w6+x0kBUxNX4avGq z&z$&TXoYQId=rvnnLLVq18>w!2bH%!niC)bvdD_dvk zCPcI2eS_@MJc~4&#WjMlWzx>LXjbS>XjY9781eHgV68_wj?vM2zeaxEq{biaS`%Fe;-9;gSb>_H9K^t z3am~h7iA!ZqKsU^fUyGCAey)(VJb9MK36i>h#8wN$e(RP(_=SVpA{Qk3=EyoGz_3t z(Ic%vn=aZ(gE9n|u|U>=aQN_M}eVn7(D)kz>Q0_UVlQ7lpX+BMtS<)mI^=+0$o z>m~K`q3%HH3iyX)WEAYYq>tKln^yMozW>8B<=U9l*S_&~F(?jR~~D+a>6Z_5}Kr zm;v~3HQU*0E&!tSbCc8aEs(e$d zH2<<~KxkN4P=Q5hrTLe?HCFHJ8A!JF(sxUQcFNcMv3|d|$|Iy5Huu}9nZpma!w6H* zEeyTbx#3z}ZHtFyK8XU}U<#Cv;8O1JGi-;qwW|e*P#;FQ-A&+^g>5wL@-^zB_RwIy z(;k|3d3{9`?fLh7_@0-2`L|y5>YvqY)Q*XV+DbeG-!1qVnMj38aZ!1muFB{y0kcT! zJ{7kS1DdpWmBhzp@+WbEO#V!Y+Cb7S`62N``K3Dz9yM2Oq-m!cY1&eF*{H4;3OZ-A zw_`(okmdVt*80oBUYd4!_dx$&Rrmi32d}>QAKvg+fAe-r!qbO>VaY*7eJi`;wO|oXD$vtfq6WJTIAL zBS4ZnZyhwl9=4we&@^du)!9)}Q3XBdtim`vr>obYZ6BE>tqwn>z?3*Pd~Y47^;e%QWnO_qL4URaD*f6AL23Drqf%oo&!Kl*J@7nwudbwdYyR+u zc7OiHPrdktrwyT0wwVTEXkntzWCS|zFPi;Ko$c>a&RXKBc$8*qzW1=a zqmh%6Gd};t&wk~1zq#kY-~EEP6G(STmD3fvCQF+@@}8_n6UL>plVR$XUeS}rw*NTg zCbdK~Y*Xb1j_Fzv8}N~`4wD65Ia}Z9YGE%n&?HRr6ke)1%=GY;X`VJeUxt#mYS@qp ziAUbBA;W>`pN5TE|4fjv)!orS|Fj%iteTJ>Y%Y&j!7o!l9DznmIj6sll@E--ipe0u zis7ePr)(EU2AxmtG|WLqF*xQj9kx@g642V>5N+qihX_S80mjtf@si|G8lsO51EvZN zG7yYR>7GxAtVZGv^P|-c^Xbp!wRe3$CfMSjJa4sRLPgU8$YCOo#`x4m0ZJFLF7cac zu3x2d&80C1PlOuTE>#UKK$n*=AVNpvj|MK>wrXJ@z1yKNmRke1`zX7RYD;J*RB@}}hh%mhK zSlqDc=v~Wf${O9VEtxc2mJp5d98F7{uxusBg+_UXm9)LY^sh-PnNW$XS|-cK8W;r? zafW-j263W?&GLI#qWIOLSf5xG9*St`v#>B_R zZe7O?vMFnM-2g6Qa$E}mc8;6twNW{r)E+=9UQ6DAMk zW|S^(Q_2dD0s4Gn;3Tr9S4zKO4|oOp?9n%UY(WQ89g@D*`3tq7;2z1wIk59MhCLjm z)c}u%2Vm*g75kY8V#BNt(M}+vO%Bc|;{xF*vU$LHZmi-*RHd}aGt^23ZJBS{ z6}>uPWNz|6u|b$>%}cYQDzLFB->?Png;(#(^jli_SRI)*Al}~fNh$iB@>cu({!=w? zT_+U_SP*K=)i!JQNjNjq3rZ^|#m}IaThhKY+M*S-9xC=(&CeCc5fARiF;SO$xMyh# z8_yRLR|t9ejcUD^&;P}@zj5R4yFd4m_gm;Ip{b!eVw?GTi6E{?mI&MZq;58mY`9ruQq4S_ z8)Q1?zMc$COuv5d@O6i-x%w4f%gWazVtVg*KE4DkU44gWY3-7<^mJ5L7~m4xgl1*5 zAJ}FxA`SLO+tT4`6-PwLQI4Zr_Jc1&?>I_XjCCTk?a=em9aGa zqkJ2-0&LB}?TU8`FrS7|5k(N=5wnABul5SyBU41DGZ1jk`BWf^&o3pj((+;das8F| zuD@s+YE~*@141$1=oX0>7EPGUjU1bbep`q*TMiZW(rKBt#hG(j?%CBgoopQq_`ET4 zi3@6yB`%~{FL4oukbnipXomwrA?|{}%T>a`C%dnpcdd(vk6@)N(dSpmhv(=Th3-7v zSwM_6EMOr!&WFBuGA^taPtJV4-=IbStm_DH9;omjf=;?WYHL9y^!m0IYzvNrFyI3W zP}{(HgPF13SD=9kS-QkSV(}pOP1?%_z|dPVYnZ-wPr;2j8M=b8rjAT-brUCr{#;|% zLGXNR$JWnsr3A$-W%=tb12?sQIXIW)F16#IN#Uj_Z|JgYpw;5u;C1}V?-R@K#iVJkDra)eZp%k{DGX;2TcC`I5pkp!$H>y3fj}dKIsyth z38&1ye<IMo^(FFKrshL;ZXqL?@xl|-a5XPK1pUUbJ!f84+ZnlL%%O6IBYHDGH zr~G!5X=Y^!pewWE;4(C{_?EaA==4_+AodS=PT690vy?c6)}_UbP#gl`*6w6w%arV0%2dfUm07eF8cFf{>s8e2?Vgj-TEt90oof2v$3Ckf@>Lfvyat*!N&9Hhsyl9} zeO1v+TG32ZksvK*!q-IA>04f2e`UF_a6G%>dBqsb3$k%_OxA@ahZAFzU~|sG`!kNF zhf%?%?nTC&%AvC=7CO2X-Riy8Q_nL~9HR)jnCcjrP0fk!n)zZkVK~K_d87{iTl`LT zHNi<_xYe$d(4t8J)Dbhf<@yoLiq}L2aLPs5S_ukiIReyq*Rs?4j(`g?(WSkNQt5Q| zBoEiSfE@3llkumlsp@*FZZ9{wGy>KMy-v{j7{aX>MykA+sA%eK5rWh-C_n&$Cdq_U z81Rag#qILVe}zEoe3t&QynahwFZFv_%K2Jpc1^~YH++`Qh8;of2W8}j!_Ito`(9;# zEYAQxHc^o9_Y7e;%a9Vc?2;1VV$%itHCA^UcxQH&*XgEnOmBAy1V+};Q!Xq-1rZ8; zXAF9yfX5sM7-mF4J~J^Nm7jd^BCRu>_qXn_YR)P@Ved4Cy`y2J84jHAIiOnLGY9-* z-dJl%(S#Jvp$HP)vS8(i@orOj`wa=%ETZ4W*-b;WiOV8$p_d892^9(1jp?UoBFJqO zO{eq)EUOJ?Skry0sv#0{b`ZX8or%&$;$rXDnJB>QrVtsYOgV+eWu}sFqenVJ3x!YS zkv00sX4jesnV_ZC>^kvbbwI#6HVO*|g-(oKSHP^EAZ~V@h;t{$>97&tR2d>R7Yc zVh)&yLvR)`4P!g?A&U+ryEChQr#q=^&@ee&*W9GBnz?*-O>>+2Z2gu9pV;}sS+;w= zarJh-R4!;b=1dyPdjfGRfGL`vu70RW-c(0iXlX5l7_R*dE0ows?-4BuW}>LOPSwCS_P7vjQDNs5#7Jcb zxwRC-x6NqcaZOW1hGuJfp0^i9k$R)^`-UEw#R0+u6}0aSkUU)LkIJeJaMV#-)vJ3T zRh#yZPkD#18KEh#SuPaH`b=R9F}NL3DjuKWl_`bE$3YR+QK^CB5QoPw08sAY!es;Hr&2|8u^KFbSkXY7o)Zkw3$N+Oo_-dS`7xpTR{ z)?wQ7uO^AMmf&pC9l}*7x>FWb&UWi5&r4*73vqDN^A(0Y!3j`>f~mo5ZpTIK`uXQ| zkuWf?2>@~$=gu`ODfRvfenUpg3P#(5%;$ii6D737ThsP-*pK1oPl-n)%b+PPsY5kL zK1ZzqF&7UOGK;*QD|A8&G&Uh&I+kr)_^1)Vl)Na1jQ;E8} z>?hY9mjbrvlgSs`jWv~BU>`>sab^OuvNIs66`eK9F2Wc|E5DL^PRDEhxi5uuC{!yiqG;9BXAx7I}rXjYo0SuT)> zn`&5tnWPXfDxw+|U_C`t!&0v*5=|hg7G!TwckQ#zg4XGUcUI>K=H<7cURu8(`*Fp` z=H*d8h{Zm_@7SH(grm)HpeO5ysPqaEuH9)pv#*Zu46mXj4UHiyn2@c$B7b~VUflQ= zO{r5)-qJj3m-gEEJG&CL7v@JOyC8eg>{>`gTM*PBmX&aYdX@I7SV6D$ST8_P4Zey1 zf4r!n-tAD!9MKQ8;o}bsRO`V0x&xd_lNS#6ZhwL9U7USV*KOSeq zoaNEu8~dqHRXoO8`U7tXDepU_%t2X&&}QWYn1N$Ek2MhX1Q0}@%~}sTFfq=%~35_a7vE1bl6VLABrP(2@#fQ>sZ`bOWSe+ z5$%RypBF*8(CA|cPaq}rm?$Kvhu%EupXwnWhAmn{J(XD$%>wUyS5|2AF#?xMHh#Mp=!x$u8E-;~QsP+lMCkv^Omuj9oEg6MiL{nf@P3?TD#@HvACLlH(-Jpj+hgcl^VbK6lNh z-geDv3FMcJHar4rJ&!U`lt0vb>~;=*ATtTx{;eo!JtH>0=(|q;cjo`s0*2jBOw$aF zJG5A0ig<%B4gq#~+4?nKl{Y#cmlB!G;UaEY`peAbnJ zZNE|YoTdjY#$YyV122>Aju>fTR2da-hHRTdLm}RbTx~EZVusyu3K)BwZuFF8gZzzl zSMcr=LiNr*7D%Qx;fNrrO{YZcVM)-Ozsx2Rl#QU1&Cg>CB??eZ<-Wa`{0*iFBhP~ zM%syB{G!Z22+&ppE(DLubsd9~kow?}}so zfn#@n`dzpD@vHyEBY4c0pPec`-)m#vdGPc3X9u*EzpJ&C8{c@#Yd-SrFaOyIv$H%x z8GZRduNeIyGw3%CF#0QN;r^Q2?)~&1ee|Pm{TnJ zyi9r%GxUvUcngM*mFHSHxprk%1k9j1%FEm2zAtI(V9|GSwk8E7v5rNNn+UX(4f$+) zgG?6Rdl=1;1%1C#oCcX#gb4r`XLEVP(t`O)VTQsPwLvd_x7ps&oPR;4ru-JI_pJ=h6 z(73)YrvJV*Y>4v641VQlahqAgQnL91W{+@R>g?^lIxosF3s$j<*oS0EMVBU$a+bcu zF_IORAzZK_w0Zbk8E_}Win6fdYoym10Y2mq#xL5q0^eTK)8F&nq=%1TivSki&#xMl%S$h_N>m$j$VjV|3XyR$lSTorY!BO>g=p2>-_vQ8@0%Q|U> zb@M{SPJ*_ylZ2>&$>loPkd(46-fmqSGE(4{upq13Ui{prG^C9|TqtU)j-XP-C;gE` zNTkfh^!xJ0c#QdJbXvSvH?4Sxa-j0n@3WkSebjdwiywrp)?f z=gQ}m6IT}F&m)p}ftW*qWOaJh?^adGe~*<&0$?ni%NoFiRI-n39BAwL@ij}LraoZ$ z3iXpn?FxopN6I(KZ|NoiZ=uV8T?N)ygc%1hKrbXMhcAl!7P-X5NIHN#@`^z2glpD%GnlQ(gw{+X)m-}3|Pj(cjQb4FqKhOR2bKX?-GW}^H(l&yvxI!CT zbC9}iT6i+i+7O^^1Hj7!{saJCq=hV-zxNxj{p-Jb{U3be+e8;ry-WMNym9rKmsgcW zXAF8Qk8BLtrM8800jznYE?_jYf1(g5jD?I@d9`0e$lx>i?bz`|JxEyUm~ZMB_`E!} zYZ*i+Pol*FY^41KxODn_{t>0Urs9q0~i@dE{p3B5>UH3N$>EAQcO+RR*+HM3G}F zH=^Kmk;g`UYnEUKk0>GRtZ|mm_BDL%IKj(%gg-7T&Nx?t#|Tyf@64~xngr`~7JXV# z$&AIi@uZ4QODJiY^l5RAQZhM-tc>jG5h}6&(cFUVYvGs801e$Q5DE$Va{0t7c=|kd z{?qHLh#}z)U~vxaXC1cDMd2PRkh9 zhyoA{h6<=P#ADmMQ?ZIz)RV8aE-!3D1v4Mhu?u5K9AyMB?!tdB8s_0mHl=FvWa_A- zfU{(oO>_`m&Tj|j;92rv$JXvu~Btr8dq)>Td+MHX*K6BvC zZ@u^WZ=F^Co}^!JZhdEMvrU{~9Nykzpn&BQqS$h({7d^iud*Hr%ycUx;6moiB8}P| zj+46Zd*7UBzU#OXxAFPo`~UJS-~7U#-E+HvIS#|Pr`$5{yd04j+?;Zf@90kW zeqr~2lfR<518B`{{jBb!JFbCMF6s)_x%^p#lfrS&HV^h(zJt({DhW<>z(&Z9N(eh- zy(dxiL6$mT7loaAZzSlm&@YeBoHhsfcuBt60<{42D*4frHQ~F0$IEZH_{n(Cczm|w z;%pXFRUrdpoT+{8b?%>WMMyQu&t_E&O^AhHw~*5}EWU{(oz2b5j3zp##!g=S7}&5Q zV5nWjv5N^hcFm{%qbJW;*@I*Cs7Vz+_YOlA(4s9$QJ5zz5ZTpopcI5Fj zssggg933HxW7qC;p7%jkkDW9>-{Ph%-v&#)<$Ex7kp>#Y-}S{zL{%p)BFAhiphqf431MYrsnRuaEm4@gsPNkKmJB4lq~*b;op1mlz4v zk}Da+ZH$4USjM%pVsH>`kuqLhcM^jL+p$kuf^4)96*W6?!+SwcRwR8N#F41L1>Un} zrx1>|fz>Gc(mJpw!OLZi7dWpX?I^*wS9qzU7E~&#=0|ZzFL~{7s#0a?S&*NF8BvFgVkF89J4 zmV4oK_5$=b3drBF7i1vo!{zihCzc2-JYt_smAAc6LopTgACPq_xv{I6OKX283xXHp zqFk^E=MQ*bA$pHYL^kqbiU%sNkd0A-!w75?9F_i|G<_UFKp3Me352GERltO)86$u&W?T}8Rl{<5+lRc)(j``d- z3cq6mbNx1G-n5S;w6c>6Y7Vl;rr1$%oSf_#NoPZYn%6p=*$lp9`zxU{OLXwarcrN@l~WDlN3?^uK}qJD zhS~OQLv8XtMjMP)v{Gi&C0ByANzHO#=xzP*uzE4WlqrP@oJ?D{zWudNeDohabKv$b zW##J=)5gnBVh=^g-lelc(xlX~#hN8qiXX>{yzC7h{q+BS@panIAawXM8J3sdLQz-q z0B)i9(=m?m)!AI}7+)DG8p$Lf@Z&GK<9!wgM02#H9p~0C1_*sU1Pl*Nkur;GhoAH1eIdO*+lp-Q#3wRanL_6s zm}4nX+XrNjuY>G?k&Q=UN$S7~Ym2H8sjx=Eo~urJMJ1wUuTGYfIh`J$^yZ<6yA-1q zNUg2O*bL>?3K7#d38<-v5z|5m%O_Bxh-smOJH2ZW(~L|KtnI`dtuNM18>z2W+z7j2F)}!43mt z>#8D~oXf!hSe3V+^5(M{`t5Jf8s?1h{ratrN-J*^ zx0e@{@3~Q>A^q#?^V(2dW7)u*1tGohK!@L{8pv+azqCr@fyzT3wv(6dx<#*Re<@C% z-%;{e&pI>P5T-45r(Cpm5W0HjrurR)khEqS8rJV_W||t2bkmd6Ouw@G(>hsBarXY- zeYvjc&~I8#v+q8Aw%ohT=bste?OmoQkhzcJpm$sm{SJs5Tp07Bc*#M;j zH&5Z_sN?V_xI6}KFH!kZxjD|wPwM7r+??R%>AHCaH~YBxDcwAioBjUzb}re^-Ti5m z{|q;50q_2-ZZ75KXtuNabGrF?ZjO-!fXjc$B^EASDy8NLUinwL`PbYqW$5x3xI`W9 z{-SRF4L4*0>Hb^Y{5x)raI-@<|6ViV#O#02PiOW&n#YcW0?*>vmgZi`3-){L(eHoQ z(%h|Ibh8Eh{`)OWw7KHn*+$sn-zd98Uf7`vdGW9L78RzrjBoY(FZou#KhL-NC8_8M zsj)w^rFmSxDA>pJ`%Dr5==T|0nn(1@2`h*7`_wJXL;C%REzL#!K80QI`hC)t<^lcA zZ)xt=FALIr`h6np>z92Cd-VIGw6EWbX{j9loI9yTqu=1f7X)P#iWWrx0Q^{_zgsPE=*{@7hHv!!_%t+CVk zI`*;ucfWiI)Ag_GaufL8(!8Yj4>!;L(hSoPby-S>p4urvsR{2^?RiP3ZW4bJuWYCb zfI;8be&GlsCA+;u4|mh}At3|sDv;)~R)7;?5o`wL0w3)tegQD&6$nKv&dNZAp91iq zS#g+rV|}23+qI6cGh>@IbekY0hCe`hJ(`+fZ!Wtbz`9<>;k*DHAlt^ndwr- z^&N!vJ&vh!z0)wtbLl&Lc1iIw>RyxXDaP^s>z*c#(BTs`hL`W~CPV;iO6Mz{`M$bi zkU&x2Iej1T+N%*g-#b1VdFr+rf44gRL|BLU>XPEA!UZ`WEcD?)jSFUtz!Ft|RpJ;> zUwV1|KvLq2bTBD_JjB>ZNst3xqKAjLJRz|T*WXxSZ7#d1!sR9eY-GX(E_W2$gv&8- zslbtkJT95aE1~3A(d1qUrBD(C{$rft9_tkM1I}^epAKTNMkOMOFOLSaUSFg221jc} z!r=c{?v-+Rl*?xqPZV~?!7fXvM+SCLRV#s6BV#x+9Z81+V!w<{B*^}IIZF}QSxJ(A zQu7ItFtLehHGJ`61Nl*{USwX#pG z=&hsnsCzk=E``&#_NXq2SJY`i{2VS_x>Rr36I%I|@T9ku6DS0WYGt2)|6jOt-iY7p z3E%(M@TB*9{Ws2?YnrUX^4G&aYZj!uL%MfX z{9EbXS@Da~y?H3zTNZlLF)?nbaLSd_hBVHiAaS4y*GVPH$d`$Nr0-C!78?9=l6F@7 zE9vekg}kI+O|V!1tp5~-;#tKnhpV5{8&X@c;^)9)@$9Nxum9(8^HWxhz4TLhsT#Y6 zH2I^A;w)EN&Mr)|+2AToqd@tzgk z;xYR9F|8=F;v)6!zl0AiQiuL)b)(AnS>->X^5=%~A5r;Mefz`36`^cX@w{;LgT=3g zs|$)N!`0)9Ukg`Ti>t!bg{p=17}3`oG4Byud_yD4x21ow)?{lZ#tAGKA8#qLAjDY8 zkT%8*X-_k0fSB!Mg7f`D8I()0?YXhwWfeE8x8*8effL@AjqZHCZ8p6YSFsI+w#o>$&K2hd`LBNtS|vxBCc)3v3ET00dN zV3XGTB>YK;L*`*A#;A%)Q<2h)HF#oM1K7j@Z#g$IJk7|LtsgZmgB$Hsu26%O<(SwX z-^e{16=};_B-Q>gdot(7_f4MP&g6hhIV99VLKrx?%MCT^pVW<7Qw(KnDg_qLw4Mz6 zjsVzk6F}tLN&rK)*s)xe7Ay3DJZ(9^(zUd19L^40$U18nF+dEsra#0ZD+p?ML%Y^3 zQ0i|HwlfM&>tAK*4iE=`ehi1wQ!sn_cv@cfoPiBqD><+#PsN%>W$=xgYv6tPMUcM? z@bp*yshyJSR>830Ww9Ca(Xt?I6-}9mX2<#|$yO^gkcf$AbKd4h|}olK@a!Qq2Ya>+4t%~8=<{@g*KLZ`U-8-clQ+<&7c`o0}L=&{_Jiq-Z2|16f?#OQ_ShH zdQgp(Y0SoVj8HXzR%n!Rq_5B@1uePfO{0`UeT7CTi+zPgDF^Gq9!e?1?BR2mddrN*{Po)=X!nZxWhPO~c* zyl&sLdrYN#Kr;cb%$(-wnm4n9C@okazH`*Rs#m+2q9CY;^7sy-k&=3yn`vc43FYw} zR9;G;%~--UCHs;Rt|_UPXqm1l*^|7(H6^=~60Rv(NJ_Y-q~Z}F7j2vpV2G_Bvy!7p z3D>-HBq`yVlEX;}*OVMeO1P$EF)87i5?YLHA=N3V*^z!(Nv)z~@*MC^t)FGOreq-! zQl@K4P9!yRP08`3glkIZU2GlVqvUW>57(3&N=mqnv#P_3D=YyNJ_Y-WPeh^ zH6{C!5(0!MsacMGSxL=s^vg<4BwumOSI3hQt|>W|lyFVS(WHcHN{%EYhpgts$lS1* zl@JdV@xwJ=5fl|mxTa)(Qo=PQ`;ro_DIwx1e#JE<^tUR}5#kf%U6wbaHiId>RJL}q z-NsnlZnxT4QggS!%KSUdjh(XgWV^J0%@AU45gyTeJjRP0Kai7nM3-~A3@=(BMKmbO z4;E_FWm=?+2SeSHC(+gNQZ0;U-8ac%6-f+8Hw`Q0G|%i-dLCbvnLiN!0e8N2`~$>FabuBgEy1_qxk_~_6J}Pmb?Rzq`<&Q zp)djFP%KPGaE}FIA z$TV|MkhH1Ef;P>qn0ah+TZz=#WIDqUbC+DrTJ|kA!xn_;H=Uavnbw=gWRdY(csr5i z&BjiAt%P*akYn@)lgd;M`>YncD zC_~HRVSSndOy4ix7R+ZAoK30SI&IHN(JsIIHW02?$>zUPz0(z{eU%xZ&Gc(WAW~e= zpqzIBAA}4TK1O0dk?Fz-P>oekDK#NAfEy}Q!h?4CC5^c9c~2W^7P`2$~l)lDz|$h$uBt3!yeW=|VjLuWd; zTYYfrv@*%qa=f~>ZMbww2X}KETtWf{2iLZsk^$!=2A6=f<#_htIk^9?9^73nZ6spe zSP$;+F8u!QAHVU7-+0+D5!1)I#y08bu7q`ibQV_*;a&_wHDZ zdnMFN2wp~7SeI;HtI-3o3pKx4PfMTr+y8m@;ZH4o{g;Q({fnaTRfbs?otN6t^AjfU zCDER>RDKty`fd+ec0{_jJO>di;9c(py8quJ&|wkR+T6V1fElUderK!a-FZ81&P|Mp+0xc`07M~Hj)jYTwIk${`h}n`d zGsy(FLUM6!!gweu5;eJ4Mu>=)pyx~}@~2(yAAuJm5+j#-m+y{LQ>gPLHS77<)q_fA zt20rnX@&`zc&9{WGu?}JX+yxgZWu5<*@?EFilmli+sy$cN#2A70sSB^-~Wd}$s(m` zrM%?j8!II%pMT#gul>TF-+T2n|DWhtDJxwWlqqGNw}Ot9OUE+Z#gxFHV>SKY`$nZ> znI>~-*Y@X{3aAmQ^SNEBSU%}kn)t+b+8OO&{{>__ZnHKl|Z?E?Mv&mZvB!9#0Zj}tp*$*_gd^&*r^+>(+ z@BiwRFMs#nzV4HmhKjbqPtPKbn7l;CWF`m*xy~Y$wO`rMX}GFaZN6k1l7)$by|hpx z7B`6fZA$GLby=nlEfyt0VxGpp!Ci0@Rw@+>MSc!6;De~9IP zsJI~X-_i>UXKDYFWu$RIy*6X!F)j!rUS(cm+Vddgo|FYh97si!%+YfisgSaOk}74v zlQi@iOldE=+{)E9etU8joJ`V@S1^a$qBNg>(I1|8`CoqgUAME-QyDKpI+BT^Hyuf4 z%xDjlm0(a8Ww^RY)dEG5l8ikeJ9HqQngUeq!EbnknBcZ=RLL*-P^1Z z`>+efGRjj|=XNY4MoUN5b*JX@pEm!ZrTIc=U1Ob9AFu4y5!Z}5}#+izczO zRYk#pw7a8j7dGISr|D}t*y!@W&57(`Ylx^UjFPNU$GNLe-z<-DSG9<54PQ~mc9>1g zPHV3Od)T$%9%`?Qz3XTYVnxOHtdf{df2A`@$W&}G>esiXOvarXayN>FHn`n#SoY1O z^4Y^A$!RnDWeMmNGuohK3GH>LD2YU7*#k1$D6%!{zzPmd(vrt?_FRi2wRuLz=B)KM z1>4AU_D^23c81Lmd2famGtZUMLHmSiPllF_0^Qm`+mLEpC26@=Hz7$2<4^#y^|I-T zekqqHe7@IudrX4K^R!@hM2-Od7*kEt1$a}PUXxL7ebe#k>Kj9;etq)Ai!`epIemco z$M()A?48E2cho~q&cgeHXfQ)oIV2lu4;sP|1r56&T$HdT^0b+BhEc#Mo^~WeiVu{2VnBTe z1YIA8#SGvlMNK+iGc!fL<~rr;32Ov-wj^Iq%uL2^mmZu2n)HY!IVfzSUfl)gJ?#P$pM=;lUGOX%&go_?DW?Vramg<9NY}fT=z><5 zsdR067wCK(1+LRBK5g-NSd4=rQ|AB~}mCG6ft< z`koa;kJ&HKm2E(8t6zICh#uvj5qeEzukctEOVV=EA1O-bq(4GgJL!-31m(z=kDU6l ztKFEaPP01NlSgs$PWL#LljR9X!jttjFAf+gP-atGg`0M0#-f#M<;rt0))1pbQ8c8x z;h713W{ehRovhKKK6oRVEkZJTU#+vO&*jsjg&h(N6RK`Dj$+q^8 zF5b)+2uqnS*y`>G!TKVE+&K&(EH_wq2}!J_YU{9U7gWn47`STdaI3Z`UZ#_0qDPN| z`0#(nfoTPB%%>N@3FAY10_XN&;8f#d^rBG#2(!#5$QY}ExJ2P(l~qe?AH-6?$XEcu zyiWZfnEi0PymeU+DjSZIJ7%?L$vj$_ai)K7dI>HxlQd`C-|t+QgnSI=Lx^P=KIDx^ z_Z5yS;~|5P7!Rw!38xN&cb6g%--O92d%jkWgG74+eDHCm!5f z3(3(!DR{1`qcvjqO%zHo{ARp2{04w`y7k$PAWHrF$Rzh~%uc|8W|c8))Xx1xByCL( z95I|kzg2x|Ob`VDD`r@Z=W87MqamVN?u96sOh#3cNFCu)OQt3LR*7VC&lQt|pR3VJ zv*zs>FW;~f&7QJkia0@{1=$o%(isZG4a))%WVE@N5*dB6m@r4{xCc%}?zNzr@$%)% z0GczBEp*nv(lM;~4lIE0Ip7+FXWB z*P}3^bZVEoyfsB)L$2{j<v z)_dd2AV9gZ5khij|6@gmDQ;w}m5egq`jqJ&QgnAL@7P9ztHve@hV9fdfTg><-BZUB zx*#f%z}nu$jJbm;IuvnNi_%jG7EA{7GxrrtQywj1Vs&B#hlZ1xOlg;28!?uKm-{Z-f~E{%su>o562~?#U*C*y7Rv?aZ`slt z3;lr2`y@<_TC0w5Th;%39h^OpRP?zNs8Jpl$`$()NsOXx;_W(eGOq4rm-l zbV0aDt)&Pub%EiJ)>5w1E?{z4K^Iy|*vGCBuumcrxEG*SuLgr&e<`t2fUN~&*Lw9-&&88{gxEtvF zP(!n6ftB;hDJ1dVH4rWG-YF2Emp~+R+ag zM0amUqcj=(AVqLQ zWJyc1q!J}&m4_t;Q0LO~yE9+j|E@VRZV!_abQ7s!6Ny=$OU!EhRKz>0;2gT;yroSZ z)o#Q`sL8`z0PXUd-&K=G*m!c%=8pT_$YGYx(HkZ27bD00wk2|vtsD>PEs;ab91rU) zkv6)kXXkh@Z;2dg=Xh9eiCpEueXwtd?A`mvlq7@m=`E2%_x_#U64|@;5Bp$3Esx|a zk-fVR&9&Sv@y0wLTOw^6UEH4;{A)qIdKhhqG(o+37U>6WOXNt4G)E^Cm}$%@{ax4( z`Jo?bG+%&G$P$5R^*qsSu(PJz-TD>Fp5fUNPH)SKLftwTtz$7i! zAee8Cbqh?=X;om}79R*qa(7i=)?Wxr|H8l|YgYp1`)e@y;v~Q%Z`L4~pNn-1Oww&t zVD4&GjS5WidR1W7UkFV9!oVb_R|4j@YB2d?C16q;X|@c+wMeP8Yg=oz`>DJkLb8TC zQgZ>xj2^rvK42R`N$M>gut6*RLU;a!ZGj{6R{(K}2k)>i6dbQM_;?}_iWCNc$nL}D znl&vp)=?G(qM9@jXDvp7sCP^tT6^(rHD_;IYf&IhQfvazj!2b2#QQWL`yQNv8PF@C zJOhSiW?D0bp<2WW7cOEA8MROrHe4thI_fWk5C6gtQVV5mq;#Q-cP=kYC=;Il5J8o| z1nLT1$+=V3l|YhWK<~V~f@O^^F`%Q%5_{I@5(D}d#(*`tG|`^?9L7i0{58#pPEWU{ zZA9zYNCW4ykqulue`(-+{<49qztF(>7dCM9{Dlv?yupOGB}%pV3zzBX5nas@4TM*X zY7gPnVYN|D5gjeeq zqA%AkjK1!QI)LcwsF9J;SN(b*aLxhb3m=!DcNSl$2S+lYj(^PQqJ>N;{+n3g&08MIDon~MX!j*o@4j6f| zU7GnS0L>uQjZd=~oXM0#UHPz40GIuv@SS{En4k@mr5u8QdLv60-+P!$1&zUgxHPOX zNg(1mP`;#WKeLP$&J#}x#I;hu3_i|1YsIL?&7~iEYK)PUk1hT6_|lKtdd!#&R)0Z; z9WsQzYsbM|FIIx02EFYIK2BHUi$I(F8w&9 za~#$7IZJBo=O<5iwrKi_VQ4GJ0-b7T(~{Z}a2=h~^6 zu!(nSnxF!be=2>4t&iBt%&yWVAqA>~(v4cDb=hi47Go`Lb=<2;nq_tg3%P~|I?XEi zp!TDV^HEdlpl0VimV|Wt$!kdcI8F|$Dg&{y$u>4+jV)P&rZMm&8tt}y!>;hQo z>jFzgWt7;Uyv2UHqQhBj#Mb7;Hs;=55-OrF`k+b> z3+ikGy&bw6uE>iOKmz)J*nr5nEW6MU+l$B+Ame>x#4gB44$>&cC}1sbU2d?54!MP` zyTYX3m*c#KIk(}_d`>M?;zY)ZqPeCaYQZ?$IVd{8CY(?V78ppYq8MIRRAAK|@EW=! zvK3z2G?q`7WP^r6o%XAyx?^kGImE9237jz0h!|y+27aUE&Zm^YSWC>ASr+*UJxmb` zq+?F|{`olcgZjpSPd91}15X zAVYd`b*qQZL;vCPa5WbaT%9tX*WBbh&Zhn-riSvkM3i>^j{$ySkaAk}$1g=#2|F9j7*M14>tNFBlB0VH_b@`puXIfBO}mc-JL$Hnw8 z?{YjYQ2-k(!{a(fe1OM6H)N0Ot8r)?gSf{wbR2wnR2~su9n`gqL;;l_%?5NSv(KG4i5IRMDmjZ z%F8P0PnVTHp0kE0L|A6}hfE@L_BI8JWRnc=I-s}+1^`uAKcFh>2UKPKfU2w?P?hxp zs^fqsz!l(Ba7&)+u;BiFDO@BJCiQv*y|A1BKww&UGlBG2EKIsYm|J*ra~u#3L1Adk zA&Qr_7kTuc2YD4bPxPacF9*=6vZQSrcaZ&*&7R!_V&cW z1Ttd6LY)b27GhzIoRR^G1SZL8fi%5i3p)G8mX1(Tk8L&D2O53MLr_lAV=le^6g4*5 zdN1jdjkd~?F4<_SEa{Prw#w=bsWUn;IvMTiENvg{Ug8L&t-_>UA8i#T0QhLDFoD!Z zTZPFu`Dm-K9&N?%(fM8y2*cb*EI!OCOd9fGR$&5?53>pr;1^;;HCC!&t_UBT1^P%J zJQ53&z8sE)2{4CZVFJuzEKGno7z-0%Ad^UQOba@m#1ilrj(TLW;7nz*@p~WX(S1s4 z(yNH^SU)i`0_lJlF{&)-tr4TjlFk}2sx0ZN5u?hIt{O3_tnR6LsT0E!VysRxcVeV} z$?Jg_RhZQ4#Hhjq04GKjCXhNYsxax26Qc@~p$1IGzmG!q#lqxsC&oUicVbjw0@CjI zc>?@GEUd9o5o5)dz&6MkPK+Y$1Q;hq6(+qt6hBXZS&W4VFiwp6JOL&UW5pSCYLGMb z#KHua-LWtMW+4_Pz??8(G#4kp9FK(wFvnErYKj!5F>!`D5H*TDoS_lyAmra%973-uc)lPTmfzqQazFXB8DD?K`WeFagwAMTJR^0En?y;pV9H1i1}z)53i=cq&Xj zcUDnh(vY)?3KNia$Ilbs7h++Jl!{d=@r6%{7HIIE~I0mfNHg$XduDk@BXIVP|-H7ma5=^)=8 ziiHUn3$pj5yrz5)o2h3w)U_v z3|(_@FTV#4R$)@9bFd1N#*Z3bsxSf4Iaq~BXSjt5RJggHgTZrJxX-9wg~{j6!75A| zat>Bu0@CjIc>?@GEUa--ad0KfG`OZ?r@%M|^C$(zIaq}WFo)vj2{4PXFagFnSf3}r z1P-pmiE}Xjroikm0#{*z8RuXXCcroct1tn^Iaq}WFwVg$On^Bius1a;apD}zzbP=z z!75CEaSm2t0?a`JTZIWQ2V!9YjB~KwOn?a-T!|AV>p^j{5DODvPFNF~+!J7q$HD}d zW3ey+=4dQTfH|VVS`BDRoG6G7mQQ4f$(F^qz&5()jZ~CCwUjXGalVHjC;|1cgi)b{ z{>KtfLkU2{5}~6}?rByfK}*om`Mmmb7`)qyuFMTrNf^OJH{?LRr#3VRAsS?2CoT*DgdPgOXI2B0?VOTn830a3lmsehN#X27N|+1QwcPY z&wxPN6AKf>xC{aK6fq0&%>)>iA$l_b=D0zq!UULO4ooG`M7aa&8kZr!nPO%!zL{X= zU@T04IS>mIU|fc%&IA~EC>3ZfLjWnIBbOm6OfYl8nowZ^%<)*50OK-5ZzjMTjc+Ev z9C2VOfwmZB*XEjO55~d-81`m^!#;twKNcpy?2Cm7Fl-$UpC`Z|IZ}bfVX3y^0-!eH zY2%>I(=H|C>nPXpX_r#vU1b)j-NvU~N)wuuhxm&hWGOGTbat5F2?o8Ltq@=~t5 zz6k22vau&|=LhwDZyxh}n_O#lsxFSio=oN$&n%ZYZlRdVoNKw>t90y&I>F5^;6|RS zyGCl6KC(V6d7feINq1Pv>?fxGl8g<5p7de9w*E4U-ZM}KvfnQp6ec-+r5}@Q1?iX; zsV<#b>iC|sLXYc&s9uyugzGfjGm;6BD%Rw(Yal5TLFc4KNq-I%fjDc+5PtJ96e z<-0+$2tR!G{y2+ZpLJtMhWV2ljs44a!{Pum8rqn%YUdFIqT0PW-Pp5yHxy(e9$BM( zLUf~%5Ea)cQ7JHKIZ?z`A+tF-QQiAa@kWf3SLb0g$K$0AdsdRbrc!iQ(iUrLZ{ZkL3S8>5sI1@1#GH0r6x%;u91CSE@OS_DEg_ zbJUUFnoGj`LH(t+jychM@!cYt;d$US(e>^OyVGWD0%rQ>nSq^Qz30L2wwc<_lYpot zj@hB7nY>Z%wJNoV5xIO<{oaG%_+Z%~pwFocA;BlLKhnz9Osq>~HeB53b zqUKEh&;OsjF9D3Rs`meuS+hIw})u7p8HkrEsetKWM?U%_1t>KTdiNQ=xsuQJ&{wDt#{*RDT z_xxQ$cr!WW4Z$2T1QWOvVf%LVz5``W@!K637yCJvc&CE+@evtV2(JP|7|f8ng?)?u zVGMcmKLJCIgrplrU`-fR~cmi&yGu$L?Z=<9x_?J09fkW1$P0=5%%XzXcYSGC|Y*7W03@ zHhOf2JqVIZyF%K+%4~v+`40aqC}(oC7QzPF5eFN(k?Uo6A#OOlkn3ezmRC?p6+biu zNg*)MpvIvhd(!1!{CXWH||BuLv3_6Zhk6Rr_%U+>?LBr7r+e#znE(*Mcj_WJU z!AohtWx&@-s~PCv$XN>Ip=GE$ubya{D5j4Q@I%IlWrk#>Y#{L;r{U|9)Agi#BJB_m z;rt&FMpa&bL>%FrfD%EOH-&OQpMW+Lk=ymjPeU=O$_tbTFT4{_!nOaVP$DKU;&dba zFd{Bhd4Upvhj#)>`261#N(2i=gz`E$5Mwx1s`3IQA`Ef0NXt@>JLuaI!M zQ`uR;mf0!fp#e|69~O2frMaDn^3a8ZaZiB+sp=XMae54fgtG9TRXSq;1FhqM3X z)eLAZtYp3;LVXZ&_P8?X+4E+Vv&WT8c*<9vQ>V%cg>xlyXElURGOMzqNA6@7%)7G+ z#QcA!qhQPh{ls_trjM3LW7Ib^jd`?38l!$9yH|YWNnonHNDJyGF71)gT#922)D?g2 zyR-+y{C`J#S~?f#Z{N~c>ASshPrc*}v7~HG*7+x6T zT~81Z^DZCnn?wE=SGs=6@Q2Bv+fn=Me z&&NWkLNAc$#y;sp&Y>4bHo-uF@JSoG)J593o?d+r2=tAiN0t7xG+4(CD;s|vGxt_(;(ry0(A#LOy?5z=g|EVbxJmOE%Ma!?9ACFldkEYRm%8A22_ zesSEyc@Lq*6UvKqlR>@(ggfN`Sr&G0Lkm^W${^fOXba*|H>ce1mG)ixXw-!lwStT@ zM8Z1K0Kb&o99b!DC#1jAZ6DjqLtiR`k`|)<9ryq#H0%p(W_-cF!@hto@df`5`+_wM zU-0j+FQ6xU!N0@4U>@-W{|@`YOkafTu_-{H2Abi~ zz6>1^zl=O0t;?d$&=K*=$RpyHAtM6Z@F&^Lp_QflIuhJmZAXTiUq+q@ei<2Vei?Zt z_+<#(fQ}KV=HN=4Y&9};vgVJ7Rel*6I(``$I(``f9bkZcY&Qp1iajtAhA0U}#*oN} z5owiQhQNTHAOr1Yd!+=?M(Rng$|KMazYG~I+Jo%0o2``+cpIrb3Zx;BqZTBq-E2aT z;On4T_(tsr84?sE_(ul_IXNm+7t&?ysCY!BkXR&oh17o#~`7V@Ab#o`S1QK+FC zxdtGJoWNZWJl06!#0gNiDG{~HW*&bfA<(yx%K*bm>NVq)`qsK^3u@sMp-8KP%o_P; z#RQRgD37|8VMa%JZWy^xNRd*4^ zUr;1k!QEgo{3HCOTLTq?usO@7nq{-nSjeTWCAWvs6>-Gp$+%J`L%aa$Vyuw2K)uG$P`2P+74+PlAtWZ+7x-Z}@; z2A4DVx*jT{JT1o)V*2=ZCpVqzYLRtVlW^*vtVVc{J!$ABqJF0Z=TD*nj~}eE7O4kx z^y0VK5zZ!b&@@!wT5k20yEzTkSjS|0>=h;0EBcEYv5)8;0RvkX<6Leb{wr|^D00Zr zR~2f6;zxC@gGP($V{!T?MiRlhXg&1xP+Yc0v1ka3kpesfUBSI`&=n6p6=;?>*mDZd zpdAmIxEZ@f!GjLDo>f_AR7T>p>^J_}eHdQ7H6C5y62s*;mjcNGM)Q`B-TRflee=1G zY~qG?K81Cuxk$l8{%U*qcW_q@$vhI zV&f+mr^d$ayMO+vzx?{~m!ILek%ZWfjw?KLP`9rTEVouffDYS3$8?2`S{x%>z(ymn zA=D~#h;}`+)Up$qC2J5`fDfVtXAu)EvbAgkw8-J5Bo~Dsmv|3|NQR*0-eG9Dl3Sq_ zkvw$mC%*fW$F8`VXQL6|w~Ceh5D68eVOS{;3l0YL5zAn#$WFBb#LC}EET0~RmCa-` zg_U1@{<9C>|FJ7>eCXm4(6aR(N-Tkq&;n{8vB=K114IiX-QPnjzZfP_UMUdEZFk;( z%hPZC;qg5q@z8;wbtbit--^^1K} zuYJ3Wb!sgyem!VL_PNG?N7nZ6Km8g%Pp$E9g(E^T_2KwV?oQ+y3!ewq*l_%McU1{D z|M9QaJo4&)ZoV}`IT7||KFpcF1{9*!Sebe5)uKk>>KF8!DGh^54A&jb8;Z_hLzwBX zn&L1|43FR)R!aJ_WG@zrhP^2cbBf)ihrTAYXoTZ~bc_QfeW6U3^uqXt*8k@5HN)O|AEwBtOSGX(Ha3YZ-e>|g(tB2d*Ax+oBwUg?;brU{)fvj z^w?cjGLY@T11 zc`n=UJTJi<06~j@QA`&XVmx6XmebT^34CiNK1hH+Jp%1aP5yqZ{NKL(M9aIs9Tgqw%X}VeZ-FciEJsbHDB?&8@B!Fr(0g`pgv-I`iMPP6SaZC zxN4nR;G9Yv{0E}u0MVg?ClaOT0rM&mq`*re4N9d4E!+dhfxs**;@&@MEpUTa8cbn- z1*UAYS76@b3QoKEhYvrzUr<{Ac zX&o|G_^b73#jE14fyOC5P1M5`fpLgRm0^zJOwt)GCGcDIqq%?uR7d6i$|D-(j%d{X zl@Z0<5yb|L2xKOlM(w6tmU_uh;jEGbC6!0=IsQ3GP=&VvY`HtUat?3ozbFaH1c)G1 z6F|lTTVW_42m9wRz(u+40lyn_8bSMll(j#4BxPl zQ4el{RMa9$(J$zu6!d{Aya6s_E`0!*f^PiMByJ^RXwWAY&x4RIm13{m2w96;q1H1bEU}JS>nKnUY#83MKySAU11Z{A3w^MHCIlkEnOB~j74o3|IeFNl zcQ~*Wy@!4Dj(kWVco*G!Ty*;es_ zQ;XbcsueE%2qn3qK(d;ZC|4vVB%tVn7*sjN%O#B(N`zkVX()q!W!2~X%X05h)jNn` z80KoAus}UgHb{KE-8nSf9?X69pqI3NYIZ2h?g1_U#b2@tM-V&S&wUaHh8Vn1>2O%^ zmtpY6sU^zl?mta5Mu!xaB@*57nF@P}QJ1b`UQn zu8Z$s55987BGZTQ4c-z-iN$%sqnJ`msulGfiMEhgC?gPI z9B+PnbA*S~jE}#`@y*UU?PPI}5H0>nv03ECV0T13Z<46N@VcPUKxMGTynJ#+2;g1^ z-B)~b5rh?^dAJPX0|EWR#13~NF|dXlB7B19IUK(@w+{EQPjGoU6rY)MUun)lb7%~H zFln*S1W*FN_S)yigUg5@K_9%91CuN9gXe~WU-Vt4Qi*EJEt4yY1c@O+hmUsrj=;LO z@;BjkTCE%CjoSKk%t^g<9q*C9#QQtwX}v?e-;R4cZRgx>XBiAIejmTZo=~nW4PMj4&FP^Ft0cBT2yas;}w2F0?5=P z0gfG;vFnH^*}3s{n*)`q(IA=|yIz{LX^n(14$J`uvo5|>4W*bv(U>1PA~lRSM+Emj zu>2NB^xgMiM5u)j^R`G~WN)KcZ)9*M>ydG*3v&;)arYK6e*@UWA0l7)b@uhaw=ns1RP{A4+%_K$H}R zpoFHll6vc5jtivoIbK0*59;Upcm*ll%_~q%8s~g%XQEk=Q!Hz-UfSxjtmgm*oHp@Jw&d_-9hMKz3Y(1iwD zN31Xc)D#9CQG+hQpn1x5u>~^Y@lD>Ri-vv@7gnW-S{D!bL>TdYNK-h;4e4J3Y$ald0p;ex zI*vVEYHjDRD=hGj4P=BB?1Di7-i%*xKH!gIzm6F`-S^rYK^4=5 z*ZrjJIefB)e&YFaL^LL<67xWv3Su939>c9|v>6-0I3G)DbLKU}uwxT1kb3OCuE}N_&I7FEW-@E6TvjMZ(As z0!|4TtFqi|$O$z9X|!D@1mB-sK*MFYr`3 zxEWYSOJI<4StUl{w!lmQrwn?YgTB_sFIrbI8YDG}Y&D8&uGE5hMYbvdHI6 zpcPUo!JK2fvV;dv8FMyD*lM&Q%>db|B#u7TS152G0^?+>0GbSFwi<=bG+V*zDGdiS zTk(@-tHLM6R{W&d%KJnZ@m^r`UP7{ir^`_s1d3DPwf7j4#;K7uE}x9C_o<&+dP;etNk zEg*Qq=2p^I3GrseFT&CsTDQJ}Lscykbut?ob)Y5}bx0x9bD|^?KWWqzJ}K1klSZBQ ziD2Trpw4?q)Rj2EBvHqKDv1wG9>QxeKdpB7ye!Urg z^jm%o{SKev$Hn*f-~KFQmialJ zM#{*HWkOWtzBP^$R=ggQDr=l(M*kXDhR!rI;umPl}@WNmG>fi7?{5 z!05dsMOi>Ffvt>s6g7+)ixe{wr7kndI_Iebni(UmLO|1(_>u+3uM>FqDs!M$K_|cu z3HkBG3@{1$c?*tSSA%3ij2LTM7))3qpit8osum1F*hUi@!oF6tW|Z9^iuM@Dn%qikE36X?Mj- zyw~oEXJNUz?uwnb#}mB#_0}HV5uAOvD`Y8vyJE|6uDjxmNq*y=+Pvx=$vS>_#p`I8 zw)3BOg)O<8S7>1bkT#|O$Bxa|4Fz|_+iPw|mbWc4!ib*M?h06zPllDdf+PF;n=Oot?g}+B*In@>4{c%FU+2668%ofmlpvF*~&KjjrDevVg=7-^jIwKEKuqfQwi_0KE_9`1_hdPQ*Bc-QU< z5{($|EF|l&a#!%Zuq@yE+!cH;?h3vi?5@~}^h8p(BE{H;_wBBr;)m6^K$H;9GQvS4 z#s~+E7#P{dh~c2w$B2a>^@z2*;vX<#g%LDd81yiAMHE8I8tkrcMKGlCE^u5C9Y3a1 z+<^07z@Lb!xE>4yRTK}22SX&t?y&2@_+cbaB+G%94g4S$1W)G@C$P_t0h))JxNkoO zzWe~0%oz8%L0DZPZkt6a0velm!2}ND>R$jaUTk$ zJ_JnyuPfob!E5dAD2DdK<)&CVD`T6Zu!(~CI>4*+WzegoHe;O8TB410 zM#Fp-$4ZY-dmk)OCjKZrJ?W36AxkFy|oI7Yz2nD%xLciL%Q%?J+9F@V#G2vx6iRh$& zS?M`<6gYJ5keACrd*#|g5d(;tmyrM_4VPnjHd1I2a@x~;KeTZ`hCo%e~T!+SxU_mZe9aezrJ2H%Qv zCqRuuIZofAbLV?ut8B1X@Kg;z;<^cR1An7B~8htq~ubeWO$}LH>LI{DR5i~;P+9M0z^&5@QDv1V}8neqa;=ej6Y~UBYTuM!{B_ZsNnD4!G%)+tCHV9epor-Kz0HZV%y`010GOA_YVwi zuBq$jZE_;9&(ICPlpJ^-_-myIQRA4kVzgjNQVtHqK`xK%3qzF2gc8mMVHogpbW;pCZFxMS2?rQV zk7bBN<4`+;frP^UV4?801P#g4$FDu%C;JxSJY2-{ciEu+2&V%grm_s@aMEYP`*OV2 zx3N}8j@XI`IEuE^DZ7jha=c(g5szRkj^mI%Y_dmr4A(nk6X?Y>0IEpbSXvt3fw9GO z_T$JOUD7>d6D1Mya7)^%O(@U^%<7WvA)6=(MsQ17%x)-FzisH2bkER3NyaR7?=rE) zJf4v;PWWSf3X+KbRPq9G^P=2T7V*oAHZ;YEQ{?)h9L-TvNeW{^@O=$G&U3pV0B7Z&0kqn1t6X%MET(b zu?uu)-2;0C3?TIFhV(I59oW-j#@OF<%osklLJ2;65glN2J3KLhM=O4}vfIKac83m? zvm-9Dh`2MiPy+A33uqI$OGrB8tkRDu8BDNpn7>5tB4!Hz>e|4HngV1|F@Q8At&flu zVB$omIlyWx9!bhRSwtkA47l)3Pk7k$R9RamOBqymXC#cpoHN32`}-3-Bexw=SYY;u zrvM&?0-Oa%iJGcVC?3ed-R`O{21%TLWyB0I8l+zy!2t!~&v39f5P(Wd8KpLlJ148z zq}KtYbLezpq7_qaL70NJA>y|)X+!m-I`;J^A7Y;+^QrFkgwhb?Jj_9UR06H= z4l>x{u>b@EcO(RIKt!PoFk8frkp5T_k~LO6fPAPMM}m55Ol9rT0DdY>It%^;c>4`qgEG~(0Q7+*si#~b+?a?w|sdp4vr5Ns$Z z#L|%D5Fsc{{RwIc^(akel(ux4YDqf`I2@%v9J=oqE*u08$4I&Gz3hD;fVaT2 z8U#_*5EyrPH3;O3QbV9bjkf^ifH?w~TTDNgTcK-eG~VHTAeeW{2SH?^2EkM{1k7z- z4T5>I)DSRH<1K)RpGO#u%}2eqiOn4aFn{WOAeg%fU>0f+OjSd`-09UIn9ml#M2)uq zCVnqsIGBI(+9sHL3Siz~xo9Ss+uUEcG2(?91XI-zFt>U&2|RdM>4)0 zkQgOc@QwJR-iH!A?T`;xaKRVe2R^A9_$dP*)%#F{r_V_Z`MGA)K&uhoT7>UfAY$Kv zU0TXaJiHUzidbQn5OMPJ&_034G7yOJL(RU@>`qEcZ=#m5ktkk6Aj)sria_Kqj1H51 z|D1vupu0lZ_nXyz5ldW9#A;*|gfg)~p)9}9?5{z5s2ZZq6ofM3noU7SKfoeCul%D!J=d zF+eOX4k#m}uo`jVxEkq+E399fIIdrsk_$CBajFK=Xu#l}@Wx(RS-(W7GvZvo_@jgG z&geTiqnhyCSsg@pg*hVODIG%yuQ015JkF{nyh05Uo~j{)SC~~2-px|ut!O2v^srv) zsh<`V1&V|>3i<`o`e-XmdV7kONh(8LXME)QtX|26LeB=)jpXQH34f2PoA^cGwKJv#~ zSBFu_RfT;&Q0`Z3$p(80Y*0{z$p%z~wU{la!ej$g1NJhw*;C#)+N-68NCT?EG?@#$ zp^^43e~1PA_bs*W^2a;L9~zr3j|^ht0>zWCN%5ME3p_$L{+}=x(T!^=`hG>-h!+e$ zaw`o#&8^?@n3CK|Q&BHkg&G``sv+E3Fcmo{nu_A?l0I9e7u?Ev+CRtf44TTz18pz7rh>qI=D|3keFYpvA*x%m`H^QBOYPQK&36tYG!j_f3;a* zI^uChI1(Nmc?F5GagbAm8OEcEn@uNDY{S&=|B?1g?wtg|H8_W z=8I29&&X)sf^LzScNX^k1>~O<6PTi245XIur0Jq&bE^|=KI!r;Oa#FLdW!NAWfFyO zBA^D+0d=X#%L>FKFoljiz-*9XZ;t+--G=01C!f!e6D*FUm;Rz$7jynkDH!Cqhpe-gCEVk#6+JHRt5hczd3TJpCOeIe77C~#I*;s+`M)^uMr?R?dg~0}23%pdzqnZe?v7 z4;2wXDd}q9;tJMBiWI712PXlJ5Mav%I6{E2L1IfqfMZesTRyLp9PdDG=iiUXf|zpxmt$TPrWLDV z0=Rr=I1R@F)WwgOW&pW*>R<+hNzbo9a)p{NBwM&Ug)cZ?()XAS2cqC^7qpLr5ePU& zOf95QNluIRZ1Gvb4(dB{Ymx5EXbGQ@c7WxfQg5_SQWfn1Y__fr1E4td8pjuXr~tQB z$Z6mhNb#R60p221=6c6s>J5KrSdPQsU{vCiq#^~ep5RLeLjc7f-5dXSJ>Ua-K+|g9 zz0HAxzK}%(`o#VYEWD@)g!4oO4u*H!5v-dCV6d1#uSr6SXYp-u!~rMhb;dJtOSxVm z^2`NAu+G#%;SvDh!@AAa=-H3;LQ8}DK_hF##pLr8|%Lm1Ph;UuF-0h>!D(F9RWrF$y_x z6S?H>aT?dFU$or^KgL}q1Vf^4;Z5)(IW@3ViE6?`E)|hQg^#kyz(x46#|&MBd%Ib! zNlbWmZ$lSVB1sG@5waX{&-4;5XqC~6E~vzz`j=l&DO>)S@)+eVbrV^vkc}5yfP$gc z`?;9$?ENhlV0{R;-hTnvzxdkUkGA3cAJ}0O?|NnQ_ah&_Z0ov{j+&S2wX5HE$e5i| zKQ^hdF?z?9T}xly_Lu6&n|7yzHfF|*aj0{Qz9zfJ%6NwNhrVjMGfDKzg|$7AZ+CLNUBtIHT$D4cm~jv; z`|7JVtl+P%HjFta3-lSy8BEK@`J5Yddum@^p1_?i-Ac#}BZab@bNA|}gBs95Z=xsN zv7WP>caELx7-zRCoZgIjBpC%{rZ4YgI-S*-zMf>R$;q!x36?NZ&T4$(vnq%;hVdZk z;$rN?l{h%zghbB8dS@ctl}a`_?Nwc=&b;Gf(`(k|C$$$jXs|Pn_wAF5)JxtsIe$hQ zhoFseTeVezYYCpG;7a)R_5JYiY8)Id%abQ+aX%G*)9~luKbLMgGTD?%&o!(2(p||^ zHV4|d8htpZSA)L_{JGDyxaYW>_Z9)z_c|9k7giNjO)ffj#0Go%y3y9p(AEUhN#Tz( zQ@gshwsvamwA#Ab>9sRz>uVco8*67yt(`h`>a?kKQ>RazF|~eb!_>y9GpE%~n>uaU zw7O~2r_GpFKdoU}Tl-pE;v;#?%?pX4K7?K4Zp=`WX!~8fVO`udSb2Kdrv5etP|k`uh5Y`o{X14YdtZ z8>ThXHB4`q(NN#e(9qa0v$3{uYU8xVy2j~^GaBm~8yXuMXU+tOGtvD_G(8j5X5!WG zxjn9J$s-vwf+~L{}~~KB#bbZp1JS zM_cZ563>(i!`jGor8`nJ-Kp-5wOP!;IjHZT+}ZdeEZIcQnv|2vC$cUxI-1bc7f47) znjq~%2(8Jlb*@GmocmjGt@PSR^&~X|?8N(+@4Kq6m_vHXk<)~0P)Qz)-KazOL!p?+ zsNv(tXKOYjy3$FJ%p^_ofB8Q^`!@fx_WPebUyCbo?#hYPsWs^yXZ8sWr?QGSlbnrfvG8yLxkjSy zHqC9O>Z`h6?=783RHpeji`4t>*J5>p8I?#?(6Yq zn07E23R&S$Bpe-8G_m-Ql0!>lWu@hTm_2&*nCLk3;J|qE5c|;Z1aqQw#5l)3-kwri zZPwaTt!d_6);-p}flo&MV*NGvH|q_1Z}k36{a0Ocd+q6GTy^zz6Mt4#e#(-+zFu8( z(mCh0{bI{C@4x;7_k8+Gk9^~aZ+-jcFaC0`5g0Xk($wh1TfYlSSLU{BKV@{mkN} z%T7P@ytXUff9c zm;B8>GdwOjK03B!Y{|M%QRvXnnc?Gu3yLNqOV_lg7EcZw8Y;F2?!%{=si)clcSL5} z<@W4wW90bYC3{DWkJOBsVpo(`ln-1Txa7t|iVxa)L$D?|3wub%M+Y9O%$E%O@X(Ur zz~11%^Cf@0#cqghK4{wQk6O=I-?g4C`9buD*1uanHg^SI zuznqQ$$G`v9oS=mP|cEKXPvlo*|oRc`my(3^}!F{{+Tab{^?LST7SZcr~TK??*_(> zuWvZ*^o#HP)B|6hv1{}dSHAyNj}l3UOP3{6=REX<2@}JSqT;a!*UxOa`<~~16m7Wf z`n$tLvrgVZoRv!|9%3>+0bJa~L?UZCu_fqO$o z1&#_-MWz=oox8aqI<6=(e%Ab%c1I*yJ1$sZPY9ZG8Uv>UYXU{#Xn2luY@j4sZ#M-G z4F^iX%NIA)mDYu;BSo8!S-G?-a@@E>kC{03;OJ6xFt7BGa8YPcL&*d9{A$yWJ}4SXwicC6Bb2UN*8Yq zFDN?9UbwiyMt*c?X1Hi`{UHNiFw3WvUV2k!U-7`#-?yZrbW6>(-@RnvZC|`(X85?k zIiX{U78F$l$6WH@*{M?kGsC0ikOpqt6WQ{^w~3sG#vXt z`@(2`_Q0Qua*^JH77ToJY{}`-Lk6zcywJX^x%{9l%a0g%;rM|cOtB9QSexe@F{&wO zZrL^P+N33cqJVYjsCi3H82H-kkQrDNoG{(mTsAq7EIF-c;8Tr0BOU?{~i^@v^jTlT-q;l!z){=wlpdF4LW)}xTMMa?qr0T#^M;C1g?NeZD!QF<% zJfURvZ%SiE6-4tX_~X@mJ{|X5qul3}xIYnpRD3TDIL7tCcH`VJ+l|o&J4ci_?MM86 z^7iA8t92%4?%Xxmy1RYK;eTzfHr{aRZ{6Eo|2Ol6db6ma;i%FV8a`Q;m{~LawwbjP zUs(8GhgU4wz3zo&%Q6+qZ+Y~#<;F9K6{+vuw!-*v#Y$t>3oW%TBvyUu7q^|Z^Q9L~ zbBvzTcbj`pH+qe*fy8(dQ3BIkR9t&d%uGQzS#TB|X&ye|?Bb?q)Epl$qu}M>@%HS< zapO&=0Tluf2%&J1b(q=2>VXJ~6j_IwmNgShAFv?w%)>3)Ear0%1jK2Nk}0zS8w!^}ly04Y$W88KIwR=6ax z+O(p@p_8o%XwNho%1rbaEH;mdnwxnsr`FMq4Ut_jAMks9=0ka6P0}HD*U_ZnPnm1a9jxIHii5yZ~ZP#LK zmUXN-7nrxO2RDMjq9|{^aMj5EG1Lh~tzF~c& zcxvFiW_|f2jIzj{iWbA>3HDJzGjbxrWz(bJ60^-FB17hO(~cY@ST)UYW?9${J|5vf z4kku1Pb_6xzXe<&TqjtoB7C!sxWLzxjR_4J$g_DBvkq!7uS0JEc+;ywGD{)Lt_HFV zY}ho-mE!;iT6s?h9RS~;GQWn!vi;9Q%PW2#4Iz% z1@R?(7xG7}3=V!-lSiamgRu0%Z<~?H@8~f*c z^Xgp4*xUV$Te|01#>Y3EIp*7^+QyfA4w_YUw`ok;VYc7?>!9(-?Cl*-%nTcQANs}9 z^-j=uaC_Ow$4&?tw~W8`^-ui3FxpGLeDis~4;!~G8MyO9mxYbPUJopq_ONCA=bUo~ z?){r#%>4f8)r)>>8D~72w-T`J_da<-qId=R{mVJmJ$ZT9*znc18@?J17|UM2?TJqw z5;nGkK6Bm0kDJExudMp^ch*A=9Dmhu;YqMTPyOAzd(R3QGmfcy-2QOTsOmrYfmz*_ zanFtEo;w}W_*&-!4Oij)%k*~b1-x%^olyPW#oPZJHoo`3jYXMDO`~zcV}D-w?_pzG z@}gVArv;4Z5C3t(2RGR88}#SeI#a1^Dv{inP3Kdc*+h4$E!WrEo5|)E_lUUyAJPVx z(y1nAZ6deUHKFpE4Bb1~{I5nUop(^xrY4rHS)1uj)vV9-)l_#RvTHImYts3ejz?h3!1ddp z^^m3hXE+LtrI|BRx#bw(ymYQNk?&YLw+lw@Qu@ofmi4C4FZ^SPu2T~|kl~qZ|H{6e ze7ZX|Z}sUZdNZ06U5TEKR15rQeYqiH6Hi;NsVSdXpX$N2JDuxTkWHlo2ADEnRp{)1 z;T=Oje=eWumhpF`yVH3ZkIl-(;dG{Z(z&(p{cKFbvTYa7M_VS_CO)C|Sxzh5I&x3z zCAFzH)saWxbf=S519mpbcwxk5Q)2kQk&;EBsrsLCx* zWd*so4np?qzPf2Au1@4qZK+LpSU9?%qU4ULeT9H>t+j)TC#*h2X4-_x5)6&v!vvkOn!V z-y?LfxF?-YdrwOexxB8ps&`E`kxVV_>C6BpWJ6qJzInZ5fd3lC`v&APVDNv2F>sZ7 zW;wartlvk~`+@hN5dYh%E(YEY@D}!;Tv1}^d=wz`lqM|)Nh##eS;dl1XKcGa<0{qm&wOX$;lV6t`N?I(7h!19a#^MMJi?<;wb_t*d6 z`SA~a@0l}r|GSTTEO;(f!DkBnJ<&+U-ph5vSrQ?|DI=7)GL)emgYxvu&4 zSLik{emLh5tSW}lviv6m(>Q<0(R2wI^~*j+_lIGehS)y-+qQa6Ij<9L+e9~tk@}!5 zj^lr8{vBD@aQf%cbzr<`j-$)XIQ-QOmAw9U$$O9Gbyv7)3a>AXf2NMttJj`6i`VMA zU!Tis(IYRM%Io7B8_wkQkjv{jd41`eF@3y_PaSr-JTJKYBfLJg=8Xq<-SV-UzQybP zQ~v8$yjH!2ZQr;)ckrkhULX7Zfd+=Jo4+KYxXY z{BZgC5H{j5|QKDS6*9WBlyrMC9Jbi_bk0*Gradzl1vfu^)VGO*O7}HvXk*2Cj>~vi+B{ab5Vm z_kC?XuHX2?eZN_T>!06$&{gzbUU%vDf3_Ca&d;xe2HS_*wj|3$?7kl5t79jG;PfpnSDIoGQzu$f7 z>=Mw!8Gl@lO=(8?g$dQPXc^fgWtTR27LbgyLMew4?N#iS$zSFrrlq^ZSD;V z4da*hXQu330X+0PGV7IdAt!c+Uj7L5sjIu*|EK2nA|C$3k8Y^D#xTBgdivZQx4~cd zu9dT(&Uy8vqVHNpc{29kUuW9JJ%Nqq zPWy~)OnIT=Z@-=uFlrz8Lf73t3K)OwJ28FU`-8^pc`u%uI5%WW{^G0|mz^9o?%wm% z#>r!I+ z?}K+9XS{q$;>mk|Qfn-Fu%SD$r@`1UX3M8n9X7}K>G6NNts=YF=zVDZ?{2JYHM(A3 z@s|~ecBAWqk?sX+dyJd!ed+R_^j~D`sK0bW#V@WiwkK~&HSPI?QT6d9ul)Il$Bf3a zZolzUPyNVPR5xSXxflJnvGdz6t}J`{Fw?m1u20?3xzOBo%LhIYD&1(-ZhZewzjpim z=FZ}We=zH~m(4k!zB-zDs?Hi%@jmEB{*RNy7+-0c+ zUp;q>@xzIGFI-wP&bVpX!@1|vhZx2ceLEkWc$o3y(|-HF+A}MRA3xQ+`44r+7_+zD z`r7ixk2i|G@T;eutC(g?@4kQK1Kl%?++b8K`{k{3mfUOX_~ps9a}Ijk zX#cl-!)N=S7j+*0KwWiCX*o6L$RlKTH43#+3^U-=Bc{ z6ZIc;YW@dNVw{BgIrxj?&;Py|&vW%(i)e?!)0)1VmuZwW4fiaWls_E$M zt?A8ltxqH~`5JAK)O3JyGd%(XESz*VZ98={Y@As&$^B9ow)EP*)zzpzWooLUqkh`V znaR~NQyq=d>S|V}^GKeUQd>Q(wtBjhRzXx)_za;Mos}_zirja=@K}ZoWRRq~dyxW= zaR6sWUl)vW5kRC0hCQ>&x=c99^oDc}5miLJ-jm8^nDIfwEX^bopi^$!)O|NXTI!oS zW>9CFw^!vFG?6x!;*a)lhvrgP#29;DPK_GIP)eK~vz+r&Nz{F9!YIMlOz1>VZ;ZL1 zj0IqRFm4h;`7B^!WvY`hDUZi_2y{b6KqSFR0Lm9gwnS@&U_$h1OY$^u9!A#!gIwP( zO{J2#)(oTr1r%&dalf#@QUKIMUJ_OklfJXBtIJ&&5R_DTKxmH{K~4e|Kk{QZk$6z6 zhqHKIwbM%b8eRZxjS~TYS?VzTgCT#gzCs>K`(7z8fmc${>$az(>Q#unN>p@`0s;W~ zdV-h&j@P8f#gn~uhV*!9qL-v4tvkrMpv30Ps2BA8q;l1cH{Usj{`Zj^bE;s`!mEM2 zCwI8VGJMPIB(w-8id3F7c$og4k+%encY3oKEMU1*vf61$0XO|ldumgv15#JXv-WCd z5glWIn>d8X+>p-n|D&Pj-+Hk&(G_YwLl+9|ul#=2H*@&Xgjg&2fTpWl8OzGu0@BS z(+U0-zQ?>0b}g|K!qnstY*{UcSt-=6V4mH2VmnfEa`|cpbJ|Nhu1@7QrVxuy0R6q` z4yP)c0BNiZOnI2^QjDr40@hI0d(7Hs&xK_ywnQbfsldKto+b9TqpK zfW;q)D4^DCn&~LASTZNCgW8$X4Mhb>TDfi+9dOkF4(Ev6YMm*#D5W7{%{Nv-03{7^ z*$T)Y75YRxDLDIkQ^>;t@|x)}TPi#=Sy9en68offV7?L2)6fzxju=l zV0;JAWL$|}YHM6-@>CDe8C=B)vDp09TO`OZSfZk7=x9V>ym@@U#pyaj;LaQ#stwX`(O zpfHF2OESw-5J+8?#66@}R{{%zG+LR<&1hU8xww^FFaTD*A3_HT4#{21MyZaxQRL8q z&JsDyB^naq^Fyz*X4m&*HaZE2Yz4Ol1x;nLRLFqF?!u$?mKlx9WjK;u>MbS8X2T*x^8mUH|9fn*%Fz??I&#TsmU{{1n4jb=$Sr*xTr0h2 zrTWZ;wzaAkOEt8m)JDw|r$8vAlKNq#SRbimYgR87%twT5!D!clOejH>@|(&wA@>Sa zB227A7vdbeX>tI=nNw8G)J3?C!Lys^yQ!nQ2@0cHu<-zuu?-4VGM(px`jE+vq@m+` z4gRKhWtc6Ei~wlR^F3xvF>x1D3;_Z=xmxA_mRvN}fSb)23X2QwWXv8EF$CJOy|4sp zFfGW*Wk&5}m8IQ=#UcsYtWD8A2iS;Zr_Ep4vUu6jwzj5bD29OOv{c8C;Fn(7nwqpS!Ibb} zmdZO2=+phw_`0F#V#I1<#yX6bw933aS54OTB(37^oNGwSlD4cbzpPWnlZ$s#-(8Z~ z7|%m^od)p((sBzUIGES39Exma)>Gbs@)B90L2{|K8p&J{{?l(8EY0aG3;Tz+nH8d2Usxqa1ld0Mw4 z{Zd!u+*fF5kg}|p#s#ao(Eb40XP_g2JqI?f_v4xV|2OLo+6WA~CTBOwlLwm^f)%CM0zFau0tP;1OFIKK*mnAJtOwT{(yTO^%z`o>;D4v8DpVxN1ZvFL6Yr$ z8kk+D@~PbVFX{fVMD*m82T|$Tg@&L&ipgAk0qP#*>-#@--4rI^Bms+X>8Z#kM%aJRxI61!uJ`|K+LPb*C zq48ugJLoN6&}fEl6lE5rAPQHf68X~;*&bA+tqLP4{T@$^P3a~{|Ed$JMythMpoT;% z9(og`PPG#+=y`r8tCL95prKD04AW0@q6Z!o)ELyOmd|3$z@r3%9b*zLtkB2X>|$R7 z^HB8;j_vKUK61}7MWCl#O%F(AN=kdqk)Q*8rw6*5th-m$$BZ?g#WwtL-F2V&jx_2% zcMW+S!1FBpT{nBIfe@Xs7Jpn@{LeFe&zIm{1TUp{&k7&+r&H=m%I!O(9?-2lK5e1~YnTXIrpZY(s{L$zxP}22 z6^tae=K0Iw{nhx6kgMUAQ$AGRSn=(1C`0+?j!~7N#X-xg$$1XnIoIxYDp%BuhUu5C zLzjAH4m$yLFoGIGDyd^X^Ebh@6Z$KDps`r3!4?! zrm$&|QW`u#{fCY}nD5Zk3T>=~an{|3Rk={DuScr`u>M@ToN{iEQ4Fc(c`S7EZWE#~ zD#Z`C3Ox?IM|76}K3OXv)M%kn`GOZB(bHe;K$OENg^@xLaZ%%{q`AqicBu_5c!52G zvtLra+^YFZwK5L{_4I2y5^-^nP(W@jJX_E{?VxYW z8EeeJHG){i@wmcofZ5{?9#6$q>UB2L*9&Da*9(7N8jGCFFn0~gVhoJ}J&ViJb-?jk zPD=EsMfMKPhJW~?A>87R)Q{87T0zyU+cL1Ur zx>g&?wsHF|D?o<5HpYl!Jd{^Q;%`|;M_+FmFbc?tu8l}-ltm2wEiq0KYW0?wrbd?A z2IU@Qp8LF2KeuKw>p?0M{z`LVCM1ST$1m(}WxQ<6W?+7EO*5XH9W#)YVHC#c4P(C} zM1oY;NYYTZQ&Yf(2t*c#5PXZ!L4WH!LD3%N)N;53>3BFbl~1fxz8cCK2~5v9bd)MYE(m~4L48R=MG`Gs%b?S|jeP8b{wn=T z4A}DTbTBdu$?SSGAVxjpi7vXTcO&dd%?=QZm{{m=`FWX*J-!c%=m|ijLXYzh^I(rI zNHAOHX1ZWwX0nRKboo_T9^fLOMPA5gUU3yi$g3T$&PC*>8xT?pM%1N)N3!p|jp%y{z&cnPu?5&3L zIJGRhsz=;isibu37HFaBNZG0_>(#m?;a1v%1#+GYp2w_en_1b~X$CwP2m&8tF)0)# z)mJ+noH;0m!?QR2JXPg_*oLd+4(A5X+ z)q6q841SbbZ*;AVVh9j5V$E6Aq7?Btj(PrY&u`A@Tn~g zkyYZ89^pOw3@%cOqUt};rMn+A*Wc4I8KyG*_uVP3BuF^H+R7woPN{Yuon%am$Bb(M z*BOA9dw%bHLFKEvaBl?Mu5WFqAHeTZYs14xGK{aOC~ufn1OJT5&GzTVEQX`O|9tY0 zXX;n{j`TUnzqt!@!e@Xbf2Zj3Sl;CO3jN)Eo-yQk3Ce?JxB$X_!c2-ZPdHQX09IIo znK8CEE8X#qQ`G+YyYNgM{&Tp}A2Q6S&>G#}lX)P571Dec+HOVLA43eCegx$jrW+gk z05H+YyQK{Kd2^LbT_~f%W3KHc>Ji#li*mFj3gr?V=l7*SCDg=V6W}`&U<===JUNJ@ zD|7Tge5dc!OEhw*9wxdN{_JOrEZvjZi87?~ALB~;@oZVI97C8ilcy3m# zORu9Yb(L}RRDW369Ke7O9ET5I@OcuTeBAaJy&H$E*L^fRMm3{ zkO+2ZBVnW3>;GKv#sc&|pZzO;2%CaeRb}_1Bdh@0@j8p`s%Ut79+4G97qd<~bDt0k z%uCDexUi>7Y*4|5j((wCcU;;e$fmeDu?Nu~p|EkfHzLpi%LMf4dAv?;wgXZj!d#HbZ=#b4`8I}g*kS~LZb*GYJXyc`PbuB5MATNH({ zFqgT^H?|}6v!kid@j6Xy!ZNP2S=37fJtm$RBwVy*^1!wm*QP<7Tr(sDsoQ`c>cdQ7 zL8TjC0?3T|;s3Qrq=16ztD$UyLD4p^b03MQZWT04aLjbW;jat~_AUo*fclS95L7!y z((LTxo(#Z?j!#|H(#lj1&Wr@{N%w0K-K(h{ia7=;+5uM?z9SN!*8xg&!^U(vvi-ft-9c~;xMF-WpXtbS!MKDK z%p8cx45D|@Oh9CVYccs)C-2a775${DD~)g^i}&LhWmAl*XL_cH9fYX5oUhQ^hv6VT zx&Q#CHX(tuD+N>68<&h51~f!`!i_TnHOkS4e$W{(K=PF!|7s?jbga!l#!{pJH;E)E z3kN!=9Hd@E;P4gE8rt%JUiCkvBZILs!)*$~u;31OtTFCPCx}PuDw7$_uqGD6Jb zNCXf!?ExW8cXq>4RRJz{$@dV~y$q2w{>^&lEvSs)>X>axr*KnkeJ z^~G8QjfnAKq}y=E(v(am@~U(Sj#iH7B>)9t^kjW8dsQlz)Mg=$1jNSXfs#V=j*osR z-%?DuWiANBbuVQ_`>Lh$=C5p&jJgTNzYrnZNMV`Ab{dmdszeuyqks=Vi=7 zO1QN_Gz{d>6^j{FfH1@asClY~hd9uezz5?TCMu<=*FA@!PP`HrYLPIag6Gl%Jw~SB8yUj-f`UKQ%GMCViy)T z^&8xUG?S{1E-dd9sSu+g>ak1D+fK$aNhoqqy}bp>E4u20p^=^9`WE!+q@s^&8P?Yt zi6Uo4>Xm;A(qVAE9-0(=%a!ALd4)je&GbrIXVOVRq+m3vGp(ZY1>9E@M>%nIaV*Gh z;M_8ySUg1_R9Ppg6!^(Z&#~Y(mDYl3JZ6r`vq06YU`;mWLKJ%IPJEkvwvK_^^(I22>M!QkFZrc0=-Cy&reKh}HB$tKKL zRk|9K%R%E6#R`ZTQCudCJDJruTZ@tjxN8B;K~Pd>QHV$45fo9;Rb)2k2_^yQC`WF6 z8c9y@2o41d(L?AQ6oyn}$(aT7hW)Nd2 z5VT*3++PO;u|L^u4U8{c3qV>)!o=uRq^dvDCkr|b&cd!((j_G8{DLwI$pM+nTuqRW zUi@+?ozkj(+rSd_Oe~_Bmq{m(OX4L_Y@)G6CUQApu97TZ6g65B5f)12I8{`u);Ue6 zlqyPIB|4!>s8I=JQ+|0mR9q#R%fx1!B#a*@#F8C|eIM%!GAXH7F&XPTx9L{Qk{bqe zkku)1WJNt3BBiZjjOKXre3u3=bvqO0WyuXbk?*o;oFbSKT*Lo_2r=ra zy$+t&+YJ+SxcgFE%XTiX1lGcOA+fg=E$V#0-h0Lxw7my~*;JT7g}d4?G$Ffvd1g>^ zia*viVr6(IPERG)>!|mBQl2)VRGYYWk#U2(C!P2%_}8xyE|I)ta$5)T03FH-a*tkp zXr3C8R+XPH8CTk7@04NhKPW-V%$lJvW3a1wblhgXn;GxlB2RM|+}PBF9aeM#VyF66OUx)QsFM+KCI?#gI2SH%!3Sm@+t(u(RDwRj*;97{Gs?s`lk5jAGhfEeHDu@RS zp;ReDFXH|t)~zSL3{@4|X$T8zVxSUmhs#I%Qo6Zw3yq&IVEFu&?_Ygr7QxRm2$PuEkN7%UuWTZ~(hbi-`}{ zg-^=2$eu1=t(HD0m@uA@6skkrH=`bX$8NnACXe7Kh#rNM)6$70nzy_v# z%o6TYSq^&1Bu~qB&V$FJAMt}MY(?mjaiz8{?m=GM%0xPcSWI^YzON-X41|$}m2|VU zX0V4%L<*w5t{B1ev6&D50ck8dC09l5C%uV#p-=rMjI@myD zEJjF23o7&gNLpYQccBN|E=Xh-_bljRJXyI<@tUEKTz(1uRLg^l72d0ehs2pxLEr7* zI=&C8amh5~`T#&E$hjae8B{wd@6eEH~9^zLBL}#mPW*Csm>~6LJ2CWaBdS-$E~jH?XT(JfGe>3|@FLJ!3W9ij9|A<0&AsqHX$=>dJZq==+8f&~ab z7xuVv zVmEM}fgSG>&^doy6;o)gLa_e-qEEw^GwIV5yoUe)PGT*`9_=s|UwF$w;@m&1N-VMInU8&n1V_m&=Pt6R&g z9Ua8$O8GzYWE6MDG!om9kcSh-J8M%@r{l!q)YQh>`i?|xa{9Ds^)qJ9=xpdrcGjgD z>t{6LRO3!2*URDLOmUD!U2R*%hEqAB+^9M?W-P@VniwbJKJIhy|FQS(QI_RbecxS1 z7z`Mu&0rvaxe_9(9(CWIZjDBxno*h77+^h;IMJtIb=y47`Wb=P#gRJW?TOSXlC zv3W=kfkEN5023BgvT#gRmJBzPq&Hbk*8C^pLpgkVVW`F{8Q{m!|! zs(Un}#(!jG)>NN+&iS3+bN}{x?;rQFuax`$mf!M0DffSO;{FR6v+NX_W7#KUYn$gc z|NB3EtN#R_`mfmHbUlog7e9tb5;JC6>HGnG7ToB#11Je00&*cwR+I#mOkM@E|%2-9-{}kn9 z>ucoK2xI&N&t;250KvI!clm$fUObz$m-`I|*!eWizl7&0uh)uSvlKaXioa{~$*A+y zyi-hu`AJkkngY~?ohNv%x>6@SjQH=c0bb$V!@MiIdr4mPY}WPs<`c^y8%(|XVfQTY_9UbtCV7nldDS=pcRUVPHQ{;+J`^+%M7h*7s>C z|37#y8)CWwF*>N#67&oK3eK(ba6i8P-0Kf}tf;5M)nX}q3zphF?{uD`eEKJ5IrNoG z)_~_)pQfGFtv|;z*^LJq?-eiVc)X9~v$cr!T)K%9iePEBsNyw%WkW@Oyq%BYDub{o4hkDg@!_{FRcy8HI(fH-+~XK zQrImGTUN}aLQfjdq>UfuJMGWfZwT%Zx;a3GToKXVU#5&~vdnR#IO6{Ic&@#as-q>^ zT)C-%?Cf?Px<1}dzoYCip6eTNI`IK^SDs1EZIAPLp2-$p`&AZR3<1yAc`tv95Ve^G z+f@WeUELzL5YN!r zw9MfT?~$(Ic(Tc!t526|oZ<5N;U)aERC1trd101iDNIbYha<6K>%#MMpLYHvQ`6MgU`Z@o=f#(~`FCqNx?oYnJR);*c ziQ{rK`Jk38O@Qp8)~cl_K7gTgBA228%BjH@-HAiwl)8iwZHD}oj9dUDKUc~5+#a#8nQIddY9k}{vk_*N$}R@x%v6a^V40t4R`i%D#r*fOejgs z6eNToM2QofOT_$1W-qaS2%D9^L*gs>OCnw7^mN2Qq1#e;_2Sm~;c#|qSX=>jhA+t& z0{>jlqEw7B1-Egg>>*`%NHiHoZUs0XFE<8ke$`X?Ws%-_>?AsLUsaFn{l z-4@2nU^+OXUEE^`{dg6T9@B?VjK-O8byXJed5uv5l!wzDG1W@$R-PQb2xl*^lsO5F!s#MI*+? zmm^L#!0%ho2cjVWjbVtU*mNUIh1ZgRMpnYD4ZH!^PT^54&I{)X4Edq#ejVd{ojy-! zkTfnI)9PU?$_87eWzOL6@Kwt-)I8Z;Jw(XR0_3DVVp$t+S+MjY6g2I#ULZ6XGE?P_ z#e&S}YcDxsp*wE#wMqe~6Fhr>Qk2-5jsb67`77>rXIiRqhDQOOwjRz8<*|F#;R4o2 z0|F>c`B#DL2;%tXB6Z${QlVecOXl!`yb5q|P5*!eb}(MV%CIxQ^`sQO>ZpR*n|qtL zE-~Ra%1YOAZf7~#ydpj3Xn_o`iu>9bWGIBAG(@j=o6JQSZeY3(=*r%B7DhkAGbD3L z1HQX2@ZCdd^w&~rYgx}*VK6IG%+?M&f{~z>bNLIGpPrlTCKkKSxM9BRM-9z7Q6PCq z2^+9lI~Pvw6O;qNy`Y&Hi%07ND`;>w9i%I^6HTFZgnfXoV(jFoB>ICz4#y5<${Foa z_|n$yOqekwtrMdSGr%*Hk|M55IOVD*w8m2uluZeWThf=UFP-^H&k`}9FOl%V(DFff zk2kiw1gK#y*@udFN|DruUW1M+z9MFEc|9wVOE+IH_yn(uNvlhlGnKnRX#>YH*q=48 zK!mnD4v1*B606zGQ^92%m37PfQCmG{KY|UsLK;0BI+OUK`JmUucN>CGP(^qKU=WPV zGScgm%E_l7p+P7GxWEdx73xapgW_Y!8wJuu={2_Z7I4`Mx24EcXRJZ0==!Lr+)=5%V4R4w4M&0?TP~ zK=b7A5n^c-BumhHK^K~oegm9D!EACyS=g7YZ;-Rb@}b`gSCm+HusRw{d&ST_d#oSfBgeLATI)=L9jh)LCccH*UR=5$W&E&j8Ygk z4Cx8e(;{Q8s)o4o4pE7f&d@lk$Ds()ZYOO!1YpO)zJRFYyoFNJE?&L1q~|AvRg#`Ge#j#o$c_jEr zSD@u~$K?}fT+y^83?Pl0xQIJW$rF~8SVlBo)7aYk7np%Xcka1mr82R+#a_Z)%O{wT zR2_>51+RFVLeV3?w%y%atHDss2n$JWW6tC_U`%F@1LI_ajE2da73T^^*RkQp@zRv2 z@H%ziLdZN9zaEChnwDjW)LE@2g>Zu{P+uVEb@mQW11ga`pw3izP>dxa_PSY)SVc%L zraqRhHdwK9+3m$bXf`Z^AqjT{h;JR4N>y53l-ER03X>lTDFt3Tm>i1 z%Ls`~Zw-=Bxh0gZo<3u(-Z{Bz%G(j)OH(1=sV#h7bh>5wGQk7OY?j-g0RD1p{AHWf z2fYjaaolj&KL*33q>lHCk&mm~x>PF6Vi;BJmslPpk904c-J zu*seXx;t)7QVVCg3n27-h$LHU zDozD6wc$)V5idymn-C|ZO@YG$=RmfE$<}U2w#DyPf;a|W0|*2wd}hMwlA=*EzMlp_ zFi020U)Z#PA>^2qVNV%*B*K`;Zyf0D1bt0huEtF~WOf$wCZ9M}B?2W4=_rU=p=fcp z5X>lk4#;zeAMqoE3zP&Y8Vv_mtCA8CQ}nD%F5fgaSE;1DKxV@$wI#SLNM`_3b#OpM zRQFtaGkTJ}@6wAyp5U5z7)izn@sKB>)#r&M&`PYW6%el(elubQfJEeZ6bK{M9*f#&cHRENsa+t5I1~|-m_-^0 zGfODV2vUaCr;;H)QiB=^H^RF}nnR@vv+ETyX=r+ys?=V642Z1yTpp#aZV!T_O6{I` z?lDOSakAvw%Y=IhJP2$MI&)}4(M~=Ix;4*m+~`34fvfL*nAs5E0<+cq)+kU}az%5|dO zRu9n1I*YU98q@y`9Ig{jEO&8bh9)u0wsKe73La^5_c%L-W=3R%A$#Ha{&9u=54!i5 zAly_Hatl{Mzm7Vz*^!TtlE9sfnZP5=BdKg&Ycf$+_WSY`IEE5bg5QY~4gjhhMUMq` zC;x)jySLS!7%bLTrquA0^^>u6)OXp=lIHDgV$w4Gofe?`Mt8gWNVoMFFk)+hf#XRK z`u*Fcj#d->2sm6@$xxheR=pfC_ROUwUzF@<>YrQ?& zde>SzaUsVndfTU9um$CqC_<2<#Q!>n*Y`HI$9~xV zfJJZV75&ZVCb~QhBCQUNdiR=M?{NHt_oYnM&Pu2+wX!iBLK5(X6Az+^qyAwC0;nVQH{qC3Ax95PR?X!rpcE9i!eTFtc`RqcAYZN1V7z0;sg@ zVNR6XT<;}GrHQ!|(WCO)M=300kKZSy<0uQNMo4n&ZXbLvd+y!+1IzQOW4>|iC)%%N zihWR36AJ2-VPk0n+xE_44~2Ad)WhB;Y@3V^Mi6Mzmyk#5Z>0w20UI55XDONg0U^qA z>*TNj{xvg81oa5rsO=CcnVi`0X}3m9^`eH*VVk<;F=XQlU1q^rhaDr z;uVxuiG1rxyj|GSI3O~te>$$q=TBJUN2kJmLY{|r#C~rkV16GD`iwdR?Na{U>;nidF9)o)o5!U}BOkn%m%A)!fdIZgDzTBL6{4h$~ugA>N#$!whfwWyu| z5(#t>6ksJq#s{eCR|{Z>EiI3mi3RrblQRG{YFQpzGE08(a&pKcV zJG5~CM(7SA+m!A0mLr7N3(nQFph*O3vTc*EcOBjKIO&1@3BD)xR z*ZYFyA%h4YF@&FsjOl}!!mDIhLHPo8qcgWyUYyth0k{GZhu=Ql0DE@$Uw zOHylqBa{oZ)ZxRZrd1t!mtg9mfYSrktf&>SpERS5hi_$+W*UH~u3&t+f?hIa5= zX4_3rmX>}2;ckHU*8(aM7(SF#>grjH?c{Q-zDLB|t`E<#?e^#JpBZC(g=c@a^%2jbK6;Cu0$pH~% ziDM3l;M=eJL?G6?NQr4n=(XpndmH}8NuRn? z-~Zi_)9N2{m2RQPLicL>yJ*{>34WJ@l5}I@MMDhTF7_Asgjj!Eo}|e#ylnKXEd*=3 z&G9t7ZWw~J9nu@8e4J&4Z^*oaiwKt9GD#Q>OMoT)D7J_KA=$lV;TtBz7)v=7rOoe7 z`GhFs05h`5{-Z+#T}53YTtuc0*HHvE(WDxCI-!Rp`uY$vy|U+mIIAICmN{C(^ zXedGkv`!DIy)&DaS69zvF8GX>ETf)`O`IquuTmhm4AR4$F$|T>oSK6p!^F8;dYaba>2(TKfcTy+9kE zX0kM2?Rk;Txjk7}0 zBhH>7e}3u+4-otE;z9K#lv`pWTD?hvyRdhCv_gsi8Ta$|ws0;%rm!hSzx+%aY*}TrGtz)%ZtHSX>H;#pT)*+< zx{4B5h8PN=cq4lTiYy_vb@&04hZz!y_Q7Fkp}P$hGHIP(ptFdFX7tSRs<*O@ZSw|e zxu~PI8PQ?4hNrrx-u!s@+(82K6tQFY=hgI*YS<7s{YBi48zB{!y!d8slz(n+aZlki7~}dn6qPU_9TrG2{QC9&&D|ke+ z+4@A~05-HR3Ra-(1_iW82j(yrr9G8=ddCi|PIO6MG%tV;`-}t$(mA?^V^gEUD4_TVfql}Ha7TXx& z0!EN?6x^OFQNzfV1Kq)pynlE4%4^lii_@ZKyQl8*x zc~`|}xF#2DGx6SM(UCsj9=$2AC;FcG@Q`7Ug|1e;+I+;+5vu6eI<5>o=Rr<-^ye~2 zE*v1@9-+y3KFq1-Bb>bk8IzclJt_phPu}NTmj)N1mYYEb(Ta$iWr6TMD_xoN`%2%m zXg>VW7?^2(`&nv=w>HHL$ZopHpRQYZ-OlTK^SZ+o1&j_4UfLqB0os;`7Y3Owg@QTO z$G`D4*<8e>jhC=}a#E?XVJbaHgAfPMJDp}hRb`2#K6@V!Hj%up?K*-HQO=;%417P4 zviZ*3S@{$`dCo_*?vgQUb?dxxR62jpd^tTykIRi%Hk4rR*dt`nCOVvyuHX&_WN?hE z*r;bk!=K*TigP*;!4wqsPB;*Bqymb~p~&+h8%#|(2F-WcGE`9G$`LSPX4ql`5!puP^GSZakFGTTUfM`amo0cj}^^YuT z;tR~%mB>^GUmxerr}myWZSIPD{x1>H){nTWgEi{5O5G~Q zJq>(=N)4pK@xowUL=KGwG@L4D^1TvX1VAe+ z)trXYhvqko6^3;ONNZ5|$mr6XAW}SD6k_&l4+Rb9 zy3%p0ne%*ByUj7S+gjH^k7}5e(pW`Cf&WW8S-oPZr z(W`Pgj}*${C8K1Hv*qX+pMf~kD-wiktR0VOTbicNhSqE;J5Lacxl5V>CNf8J6pVJF zT(}16*hE*8Km~WH^kQ;5b%$czVwr$bJnquf%l>@IZcl_WtKb+LO`}8)h4IFE)w|;I zpDQkqx4nlsz+({+#T8_wmDfhp(&?#X_c8D21esieAppgUU>{JZtunL6!k9)2I{Q-h zJ!eJy^z_A<=Lz^S0`o4nXO6eD{2c_~SY--yVU~$)sR6Nmk;mT7_{5vlm3OXnD0i^2eKfCt&V z7g-G{sbMGq8jqxZLZ^(4PWW`|6J?Ocwdds6VaG9;no$ z1OrO+KC^sdu_Bh~Y2;N*FpUpmk;>IA?LPshvV0k(31CbR=|L=RS1{~BdIPth{@`Z1 zPy6-^(L_G}7#%1=XPwmOM%CSe!?8nFY})l)p|8ZvON>HTDty{sOT|!@gi`^upv+T6 zd#8H$o15CVQ;$CS@2+z;E?_+a*@8rBS5Nj%J@!O)SF2H{$eW1m!zlzX0WX|9);)Es z`=(>vUa$9JT~pR5Hh+>GjtKz*PsY|GY;?WLdMX)U-)3o-e@saDxqlE#L+D}uGk zG!wVxRT(NR7{AO-G3TbOJS266Lqw$aV7HKh-a8hShIGAx?!s^!LFmRnGfDZ#3T(5a7k}!n8xJbwLkt?76{;&mpH%e#u0AF60l}IW{ z{;3woI9Cnz<}=V)zj`_{k@$D2J^gzW{}xp$*+(~RVe#WD>|Yijie!cmO?6SIIInU6p(#0DuD1RS;qTib=azXAq7BU(CGW_%9kjKQk z&iI)6bf|;vNC!jXVyP0lQyJyFpHb{bogNh`Di#o^T}wBCWW>|9jm}Rg55&hn%S6W3 zIaxrbxyaKuti2jhhP(;?X#W-qc|w0C186vPl?g7PEP;1Wcp%16Ktb@czHBO}NxawR zv4HT0Vr@%NPlUZM=(tFc8Y_U|DI@_9$~bo2dAz5$?r8cNmZf|lWdrz0U}niS1310r zEfZ^;Il>;bv%Gsk79R69x!P*J&N0jjT_YetnPkl$pbEz^PN>5Vh65tW5g%aWtTAO& zAxvw0AbVwq5W;}wnd^(Ct1io~qx%RBM2|R#gpW!V81qZe32NCzc;SzUh?ltm??NJz}-6~DGJ1$!OlrblpplQriUyOh$&R@poJT|jj;OG_auj9e zk*#t|&iT+NfHLnvRIy?5ei7xN^qupDU3#e_eI?=@zbr>w?V}xzAQENJYn%81o%Z^b;|NKy*Pn(Q@?9aYdYinC*Okc9d(k-2XA` z9cp(zOcz$Pryu!Z8aMn5?`b*HpC@&RY#rmFavKO7PrVK7f^yA*RHyR=&mQSqq~5Q^ z2&33P`B~^c`Cv?*L;DsSR9GDL4;kp~1kg|JQP`Ce;6T*d2fOUPt}Jik z$B00RJVF5PHZuJw`u7VzL);zL@5F&dHlntVhNlb%k%j6wEff zgCWC4bwT~O;qrU`X88NrUX^wO|JFCf&|{FQ&;%~^dEfxdh7frq?#OljCs!VJ{(!eL z4z08OfQCDlx0jh6YaEtRAKV;yLLkvfmXjxRl>MVxAe{iW6p^g**IE17hdQKc?sWM( z)Hmo=y5bNCxlHDsI5s#Ao3)VGisQ@hNmLB>D~&73hOrbJ>Zr%EoQM@VuAe%2IVzsj zHV>uU>`m!vFk3XJy-gPF` zQaH;`Pm>sdWK7~_h@aMsFNIF{LAf$TJ6_hNsT1v%fY)4}q@L5$==bThbed(Q9$0sR zb#s53RuaE;I{*4tztra(|2PO%c|*$mf5iRQx9*2^52x@BUih~;kt52 zZ(>abVT^XcSQxRbh8vACqq}@y4|%T7;xWnr4)ao#QLR2GiQxStxPxd2qPaKX-hpJvM`NJ${h5F@AzLp!EqaT~mjZ8> zU|31tPm2G-9FLXKSj9Uo50F@9x#$ zJ&U#5bMVa4SZnRq5bxy`%*(Yam=4yq*O+AZ0MI!MWErjeHkhx;$88{AA{Csla03r-piRj@WN^*)u-U+{UxHr zmn`{hEuqCH+l%KtB4U?<=8;H4<#nj=?oDPwpP?F%7yHtkwZZO9z2#Vn_KT>6Iyq<= zdJU+mP)aa5%mH>&*jT4FXqyR+1eoXy+6C2n@wf-8V3l^;^#o2320EmgrealC8DIBl z{7GyMS&iv#Du2XstZ#8(u1v*xo&eiE{-V_=fVQ?db~Z-q<&B-Kz3n9?(x#XtJT_P^ zGT5uy*6u^Mtz1VFPZ7`Jnfk2G_$ZLErQY7UJ$5fgn)<*uR1KVK>YG`~8PUT`)E29$ z_78bidwpMAmQ>DJn+r~R1$eXl`OBfrF&takf^2ott5Cvhv4DljO^k%ZF7#H?Gn3~R z$`tjRlF41U zOT@mth52%bCd@)V3dpdp?(UawoD@TwHrvc-& z+u=bASEjR1>Z3VYfb-J%7APd81jDih7Fr)DO#~pOM4D?GC6ZA>jt=><=L26zJ(cWi zaqM=u4OpprsixFryk^5wZS3TlHCc2!yvWL$QlXTO(YQGZ5hVyxe0i!| zNE#r>$tnqXzJwUkE>tY-ilXw7zZ0thQA zN^?T*43DkwED*w^2agRjAB#vj!4vzO?QKg1U?tTJJ`$c_v@OcjABt_zs?(7+TD?jD zqbt%2-62*)tEc7is8p|Mu7W*h3T)caRJEd|f7!d-c!ru@4bu}`CH@S&jWu4H-3h0v>vO;uek#og0&06|k zD$(-YL~e$mU?8&l+7dW&ZNr`OTRYc^;;Z=Uwz?d17F{a=T4y=zfw+Q9Q|O5aah>(9 z^B47-QICG##&+VvnRoYRMYlCKtug5KJpP(jV7cc87VrfCP2UuJ3Jbs>__{1jGYA>F z?KpQuQH`^a>~H}_3v_GM`~~bI2a-W&xhv}uno6Z-*9H;#zX)5ho<-)Qlhoo|+PXu5 zg(2%BtL=;(?`AF3lAAF5lZir;gv>JtnJA2=c$^f z*wzN;Y>X~IF?5ZVYh&tL0jY~9Mr6_`7|$J97~YWX!~Pl7^{qmzx3T{*P>#-!iviSM;64V_LJZAjp5LPl&YRw5cv>zUR*~_kbzwPv zMSXHi?_r(F{X2e43fgffkKj`9%P|$45;3`~ENKgZ7=LR>>Ux@ z9?-}~*-uZ&Oq@zDRRU|$g7f;Rm!(;EHN!h6kk@G!&#!DG(#@(|ez+qf!(2&%%Z1kL zuZZ3>NmHMe%rnw~#8TT`L9x=nJ#YckBX$3vY{++K9Vf~TD*UYYv>5u4zeGOs<`hD!>;W>ny9Bvf^wXu#M$nMyE&#Swv2Bc6kp z8^J#|8cRYdfe<0-XuT{$9jGao`0mAb&PGgtYP0Qr8&pG(hy1`;%3E43chhK&smH>t zrZ=X${V4&8RWrxBXO4BBnYwuND4v#>VG&|Dc%#1VtC(bod^ok`_>QR@Ps-n5@m&ggtjfUhCABpCg&IR2~ zmqIguiZz{hEr{HNbU>BCgqQ;+$Trk4P9%fLGUYs2^;P;x_{aX_>vq*L3ADa!*NWO4 zF0J*_u}SAL8~cH`ljAv1pw;ZeSjQ@!c$d{CmvUg5^0nt_H1X-h0PF?$(CBrXjy_T9 z8v&43$%(hKso;K@3QDnwuXF1|!9poM@tUKyuE>IDYb2iW|?&M1$E)Dg> zdu0bo#}gF??9tT{53;l7h1xSX)0yt8re2Mk7`7u&e>S#mW{_!)F1eA>{bK+a&w`Xmn!eORzAIZ@KZ@(bAv;!=(?eLGLILEFI#*GYon<>VdleVZGN$OPKb+ z52(6v0`Bq8)UuBKY}Fohv+3?pxt6#rD~$w#q@L?!IQtB$sh>E=vDOqAg+3KzGSY!w zYRij0-oxM-^-@b81?11&pCbWiuy?`h<;25bP`{VO$RjrkEO1xor9U-ytP3Cr<<=I* z#&XXF&%Me9uN>>1iw0R2wpwIk}#sHFVLwVA-uC(21CV z_e<(~o_hZj*Po<4=|5iL{zwqz0OydRHqd+zOxz0 zl{!xOGslH!25vwF>isD40X&9ph*$0G7d+gNU)n$9PyJzv1R&b}AQ!;^8ykA^zF{nK zDgR~kMgEiQ$Xh+pBA=p`nLP$QyJ#xKpQC>-ZEbCnl#P9p52mLtjIKZ0_J#W(<8I%7 z^ThpyiTlU%zT|ZK3wi$pebTdU;r{>JeYms6?-SU0>2BvEKlyNHiR%{vpO0~+@A5*C zRtVi$xjrau6BJ5H&X$G=02=KsZ$G*SAn}7^Ue;1y=A_`#PM}IaiMOH?=_1$E;6Zgq z(CbE99byiC=~LM9x&A(XTK{|Xt$+~fDJ2gal<)p+epl{4HF5vH=Dm$dGn)g|uY|); zzF~X4m7}kAk>7f!b=2Qq<9>XjR2W)AiWXq0VsNWMZL7M!ZWBpH+6+-dsDojot=U6C;BgGk_BZy_M%_i(_V zYl{zRaHU(V!9A#|tE)(>?h;WK=c+IHP{sPpce&usja=XOF5Wz--j%v{+Pxc=15*+~ z6>p++-7WAr@wfoU#N#rx6OVy~^q?6}v{*YdQNHf{@_bef%xM+!@5Q@mp79--^j3!U z?fy&P2Kjh@YhJ%Cuiu{6@5t+i^7`SterI04E3f|n*9SK3kzUV}E`|~|z4|3T^_vfM zu7lI&h%=Gzkq+-5&!H61N0SYaWHw-zan1*97-fE%Z(hswi{AgRbD>UzDP$AUGV5q2 zBtsm?6&M#{viVG;4!7YNf1mm|wy9J4BENa{rTArPzlYDmefhKzzWgvvxx%l29f}We zc{{&$m%QE1=5YqZjz?6A0Mp&S_FE6x9%M!$I>XPU>w9a;@;f~pj}B{;V#->1Jd1i2 zqBJcA$xjTM^XNl|5A&Z#HN8?|Lhe~e?rQjcy`_VP6JoULeCguM;_s{e@zPdJPRa;%L%M7}UZOwl#IXIyoc;>K4tAhYvv1^wLKG~I3D_cXFO6CA zm?8CLO^Kkbcl)I4Okg>@3fqRMHxwSyqQ=mjv83rj~UySa9WM0Ruzo$ zlkiYF)OAo|ShA=-W6^V7!trARup9Qa2}_kCMG4=n2=st*Ao+bZmLP(=j}(U0cQR;1 zXjyWtV%iK|=~EL=5`xmRrTX&;EcVX~SJ3^3qeGNVx4*ctKLd!#WoJ{B5qEOQ&^o92 zC{PUEJwYTCCAD>@folm9PSEYs1?t_Ut@?98we8GpN@Uia0AgD|FDnxLGCr<5>3G|E z$CLBJJFN$owq}a!quelRALA*90fT)x!o2z(8d6g&Z}UrGp=68+7)Ybht36aH&L|ym z#&yWu-f3t9%jqWa`3~PDWPVi0TGw@a4#=ErV-X0(TgdB;ew@RNq?%J$dvGn*AYj{- z86iMJiU4Z>A0r`&Za6G#%CcP`5RAfsP>yk+f)V%J00S|$rTZKs=A*N+vgWJ&sFyJM z86G31<7C*5YzpPDi|}B}8-Wz+8q^s(Y%V4a8*^d{`>)IS`JRV~Wk>IOoEM8#;4t*? z?Az36m#)dlwheZ}I~R2nEnk*vfx~hi-eEvsmWwTgLdz%>WDuS~sKFd$sn~1LBxa=7 z`IEo%kp1TW6xXkT&Qv{DDV&7A+_p}EdQj|gsoI=crIRo)i3GqjcS%2sUvIijmDSDn z*TT==ST@injKz7j`lb@HLi?0Ep(2#_-F(Qh@_(b`_}zl_?5su9gqP^r*&V^@WWI+YR{KSsp`@9(NzXp(A`yif9GPj_qSx7UuJ7J1Fv! zBhoe$VJNq3d(^u5RXdAyrq?Ou@-w(JP{oc9(B;$ou3cl$TC0HN_n+f~p5Cp=edyCg z)PvBS$TQ_i!57kbt79ni!6Cv(>S^s;>2tL3s?lGaA)8chBw_7!`#Op*@yTJhsonH$sDbm0f^slsteqqQa>`ess}M{V442C5MSied3m%G@c5Y^pH=S(KrojQ z#B;y?Dg*<>-^5eELg4gz&*LP~E|La8jCh@d2DwIN+ch}hN^+bGz~*L7Jcq@S_gS62 z0`!sZBF$&vE|sLnSwGQ|YEJ@QaF86ts!XRg&P2L*PDBvx+C;Gm43;PqcEBJQA8ccM z=3}&16nKJ36gKmfQNsHG8eq6c4uzRY2@6e=;~uuWMeSi_g3AC}A&N@7dh-cMxwPeW zRwEhdWQ+ZPTx{eJ zKZdc+K9e$&bRPe=4|QJ8^&7c!|doYTE2j$*jSUgu`;LeDmvkD;@T8%R3V5ri05dlWixqpyMFZQFy|c^e*7e zpr8_2QRS{!&d;kjEql4`^G)=l_PwgT#Fw&7 z(EJyDdeos5YEHCbJn0_u{f|)38@U$U`cLy)`8RYh;&=aW#N#70-ypdsuD@G5c-%!Q zSMNdPA{OuFp$q+zlmtAEy>^{C%2|(}qKz5uYhRUy&}XC+ePFqto)#&1P()wNw2y+J z=CF;$;1u}Lg?$}(@8-VenwZ`{f|6#!AC%L|r=f$po z`mOVk&*^l&o4@bj?=SNgO~)KU$*CBGK%;=Za`c#;RkLO8p8CHd55qs{KJ0aQmV4O> zujX^Qsd2Qx5o2$-pfvD^#?C@?19}d6lXQ*yR7DN;w_P5{#3$c+2yHnY<>F!Z>_>uqTA=_TQl53YSy_Ku> z`B|<^RVSgNDtc?mu0eH6PtC-$s3aEwzu1TA=4CZF(5W=lK2&YXiLK-%(qIHHupl=G zPvb+|oeA@_6MtHR17O=tq)e|eGRnD1K5;CfvBgBBqBDQuxPRj&M5*xLYl8teSlfhV zOJzl54|WCX*Rpvp`OkC$AVJ)1(+6 zfT5g$HQ2hoA|)0AYUeYm8;4&T|3zC%X`CU#AB#R3(Zc?TBeM}Xe0H*{tY_xx4eynH zg%}4i*tM^{=61j=+aw_0$AvP4I#-d+c?<*$_cnjWp_kP|h1KonfUFYCgL@Sml=n0G?a^3P0Q2Z5kDHh3*G9q7IoDf!qDIjN-;{9v_%&?nh|@1g+WZ2>@- zb+PWO;jY3`tTF((;P~d`;YlUz?~Sfc@+OfjFa}Z%+mAVg4yvR&f;*H83Mz^79R=n6$&#q3p|D(3p%K7j;$|22|W%m zZYj(2w2A^tV>QVI$t@MMw!1vK1rr5DE62tvXr03&tlwUz|3$eS2yY{UhJz6dM3v;H z%m)$NV3KGyv`HvBQ}^UxK((#R8|Y6GHqCAIO9j)@&&T(v4=Ll#k_NwN9{nVpsgJLG|tiQlN8nx@W;S)@0q8jE5*{>Eewu^-Yd4(VAF2 zx>6QWk=JotN671(QL*lB1YE499Z@1372o&>3VQwEO)f6bpr3-QutOkd)fV~mPcqoq# z8hMwF<3gl@N(=RH87W}Mrm>(=k-I@Bs|i5{KouI?&i$rObs$}~t6AuEhrJttOJ|@P z?2abmtiqct8Zj^cO=(x5ig{3w2))G4Q7<*Hp#xg1GkcKLrhkX=+kfKok90T&z4F_i zDK+Hcz=TXJWGhIY^rprR$9KB zqMXi)FZXZaUj9|({?TkF{U(iOYBzfkXB<~DNMj#U;pA@S`!`DF8f#>BpNl-xw$f0TYnt|)!| ziHUp3h3&C?eByqKd-*h$?{(JbYxz6Zq%_&QqI4>(@MO+~@iIf5-g0FJ)q{dT9fiPz z6db3pEi@A$C~+-T1bGmm@BrThF08JXB_%I*h~;8HWWtnK7}G-Q#Eyas6^4i{8FmDO zueh52bpq>QM}@+TXm0F*w#W>sB|~5cmNa~TZ}Px67d2Qiuz@I*j!oeTOn;vQK`{mI zBe}jv=XoXB!(;=FqEE&5Ido9w@kN;JM{V{NG&v*AyL7A%cAA0>9}Uqus=j{sQB6q+ zi6gkOhdcGQdgegEz7MD1t;0e6X^c;Cp}-{tH^`XDW^nUmM6Ok8~%IpqUMkWNGe z|9eaQzwARspPD)f?`bY-w70fv9d%hp&ZF@h=V?()k^_K1!4R5^Ft1`mc#1M)e1OYLnAW;AyV{oe><1di&#vXF|TYjjf*X0q^owAWO1cM@mz_Xf&}Vf zGd;{{0wFOUsONFP2rywxtkJdMN*|Tu4bt40Ie`^N2P6rwoOPtl4|jo##CJ3!zGq8< zjW&4E4DCgpMq8XYZeCV#`i#hRNDf`-sK9?@TTO;ej}$IlyaDJ#umRKEkA3lxj&y9n z1YM@{_Pe+mhc#Z57>4p|c|3R0Ln}qc}Q1j?si} zBL|Y~XBn0loTgGX>-o9!mm|jzctM8A*d3Mg3@sl!au!c-7DbxcglPvN5Vz+&KQH@y zVc?uiK|-BndwII6jCUEQh1&S3n@|SPV0tV8Pi*cqwE$iIK-oqLft#WhTS1SOZswO# ztLp4?`q|91w}F5Z4cFe?wRQU+fJdb=Ma`#U=%IhXLrH*CUU4<47CcUOM^74dx%Sk0 z0y*0VNPy%1!3h{y3a10vrewu((wE?B`SwO&L3>#t zT2oEJD*RwMokPngR5C>o!x(F*t6Cv`rZ>5tOF2`5Sh8v(C&nN3hlV^S-3fyEl$ulE zH%&t|bq6)cFoSkDmRu!j#tL`20!B{tFawuaM)OaZ?XTjPPXj z2*4wisqqMG8BkFMRGfyIjnMcvHuab^h_O+|Gh+qe+i1H_5FML)_a@SgrdozxfSx3Q z3YvlKJKF0@9>Uj+e22K;)Nt5v#q>uGoY@$$;h@2s&~__}J{hVxEtU1n2A}KjFla_| za+|_zko4`0)bdZdPyO+noIVstCNGeGMEN8?`C~U9?wo|4{1*K9i(E}LieOsQfF2O^ zH4zF-O{RsBVGV|znPs&j64F!#=+*L@STtgxc5pa%XR zf2^zJP;ZdL>-8h>;w$URqV{C78MTOBkL32XBr~q@S{ZKkzTZ1*+4CGW1^~m}s3DCm zWqbznD4T-*V_G}!;J5DoMBdNmeR*GUz03ZfzwgcW<^KC7?%zqQis~!x7x-pwq9G=j_~UqmjPJ(8z@N&S!9azGwCOOmPfHXSqJfA%)7uRXA^A04G9(@-;~4{8Rh z8sIotte2IEtkp=GhjK-WD>JYnU;U5rr|W;1*YD5k59IX+^ZG+vBULtYwYRxKs#d0I zhhwE3i4s$aM*>qy99K>~nP!zfjMTZY6f65#+}~!uYTuVi-%A%?fw#2~)(AJHnmhbm z?A13j#*$0?Huv(Ws`ns>ujC#%i~gF%E(wt#q4^0ooBY+oJ5H|>kBW+uM8KrEO+h1H z0f~vc+aI)^8fD?eYdgDp3nG@|0jetpy%*18@Sz=LWvjw+B$KLftr5F;CTm}KGIPv;@I~uJLvK?wrRfCnBO6u zYI{#d>ph9?(=OntKRVrg^hxIHrL`L%DQm-$Js5SxqM7JFsCl7dciTv$^Ce$%q@$R< zzYa`)Iagq6xbvV|%M&<^Pf~s_=YVeQoIoUD*QIqi>{{#Sou;dKGlOR!7oE<(q@Q0; z|Lzt25E^Tgia0hdZ@+w{aw=tS>?t?d=|6MCI>ShI4a^oEig&xb)42l;%m%?Jh%xT) zDGuMDOIy!E+!`Y~cf6}PDH^tfC*i7imXI z@W1zWpB8wKF;9j|$DyHjUY#A#_1zpT%Ms!+E-bg=~1e zd?SKhwTBi)YUj`whSc4DOw&5)(^3aQfIly~A{%g!OdB(Ux==faz+6^GpEc|$vk2vv z)YIxI?-%v;kXeA)TqjwR&RXZdri}P6_EL=M(3!~60V1HuCP6`MTXobn(8XyEQM>4z zcNC8+H|>RHsjX-tjZ>tH%s#_xO1PG?O8h@vLd|tY^Ql#B7Am?uHf42=+a6OM9V{Nb z<$K48#ix{3Z#8xOXNUXf<%V-4s(GWIB*&|H?~P~wEmIrN-2?7#zV?V|U&*a~jTmg{ z*USBX&%J14`uRzxFrHs8S%;cQer=N=fAy_>@}QE44M!>7)Vja(bHiRR?48u`tj|Sf zf+mNfjdrD!Y4ZL*DN7Y7Ryw|1MjVaHl2`c+v04>GOJxjS$r$9TR=NuKV+SW#sx{8P zk!8v^|0VZ|wIjciROJYN!Ny>UmlD|xl(IjQ-$rD~=z7KbCm($j)c@Y$pqbCNFlOoa zQ6XVam*ew!yDaQry}al=jPhWfE$nH!Lr>n5@i;%rO6*Js{II z?1lCg3S(S`Uotqh2b zeoc*zMuQtt$H@#R^iq8o{S@s62wi5A2y^FDp#Y5dvQY#WspPw3MN@W<@f=zO9Rf*< zas%Q;)0SFbup(rKF$>2~5D)U`MKO`nL5o3}RYrSV>S1(Oaxt&Zmv1O>M@Gbf5fpjF z0=1g5VLX+exU0xus0P!S*>l_I1Gbmt8%gk1;Kex6xTQHIg_U|E2|@>rGs8KU7`@U| z+CU8l5go1js(bu&_nL$j{g}GAynmfAUpl~#2vgfv`Mys*6>6zb=^MV+PqP#@YLOx%i$KU~soc(&pLYl;mM2%rmWbIPI z60MEEMJ5W3QTNvFtDQS2<*-dH@An)irjtz1x`~2snyJ&=h`h!WqLUOfh7(&;P1mRL zqG6-MOjf!>(Gq)0XrY_EI|@!<$I5!btHci#7uc}`FDO~%78}@PYhWo6>xD_w^OL4w zyO@RhLnKDkxNTIyS60BWvk1xy?+2&bcdgCP!dHZDgkwU*L?;qlK$s|cQ|}h-jC#f8 zFRFEoz?u&cC~lEuGsiYWJGyd9L%YEBYzcPM`0m-0R{Is+N4?oXO%G|hsj7}5(J~Af zh*X>!BS^h9ovFY$N5ZOG!?`3?XVwNLY54wak)5A3@$rul4JtrGVWnLcji}xsm5=OH zwa$qG^|p>+a5i;4S|uE>=up%(x*7_hAtfxq;RC(Cy??@58}t~<8J9Q}r&$Gy# z%7s+!uW+yYR^|R@x&MlZ``5PaKhAr_A(ZmEm+w!x|6AO@e&SyK1IoNx_`QLzc}%| z?%VILPJFNXXIkHX9rv;&l={DZ;{IzU?!R{8{!QFVS604%Y~ucRnU8k;zc+FJ+Y|Ty zX5#+yChGhAiTf4W{`Xq#>%P4{d)$9%>-~rMEqJOTy2-+hDM94(Q|6{U@QwwQqmqI8 zy(9LoDr1zN)N5OH{yx7?x9&fW_qs2+(x5|ds`xl7F-F?f65kKHGFWA@xxe%FhdXcQ zyN~iGokJVjkd@xd(L2d351j`A!EMZTd=j^jS)~U?X|Mb?3rfxwIx9bZ-4l`H?rOVkoV(uch zxE#2Ci90@N!6%NiX5{P|-d`~xPT9X8@=;H}^Mb#^u#iBGn@|u1GVT*>iB- z<9ORu=IgTLeSDa8mh&KFk5SVPHMPJ&bUK5fob93Z^c=oogx42B1(Tr(<-me^MhAy) zY|o%Z8!VT_)?p>t>o!n`AsFQvjIJ@OK;k{}2|q_NN8aKQE_;@gGqg9lyn2YELUW|W zVe9H7C{kf*N-nICWSy*GLttCSWI*3HbYg_+)#unRxpdpUysG_nt(YET<2B~z3!K!;v=>o2 zIS058l7_9@O6rb3C+9@OzFW0{%d0Iw9?g*XQ-%_;E}jl8snb`K^H17~MKB;-gUcq! zjDU{KJnqJ`b!J~Dtr-t^4~kmU)VS_xe*ya<8(2xZjX$GAeC8(n!d z&sEc6c7c5gGBpU-Cx&VOA|HswHrmbm=hk+0wvs@yt+lGmySL=L&m+0I9g7z`EPhvd z-#+(5tEdd|7a_`Lh8Dd*-(aalslIgH&xNf!nFs@3U(%8au|ZaxIV8DyKfAQ$OZi?m zma>XE#&ZEQZ4_ON#+B*VXF@TZI%&oJ*fG9nlB8Ub;8m((b&UJ96gvDz=da+V@p9Dx zQ@6TPQj;RcO1>ZMqHMZKtT5}1B^DnyWY!`wTRCr+=PMcgQcU{C~bzXH_j<+ z2d!rIvUm-x6kfo-SKzZ%8vo4E=s4zCuj|cukC#$?n(P8W@(MHUx_le0*u4E zNWdPWq35+p`4^)}gu6;-Q$9y_Z^Fejoz@_?q}khAGV9_}2DS6pO~^U9g9tCd!HM(A zfKXSpm&amB6H|0L>Zr&)UBd6>mepg#=h@B1aaU?WSzDgF{QU7tmlw}XcNb>PpR+4b z(tc^_HC9p)>~n&THKr`CDGZ5s8z=39dn+|RsDRW5`N_g<;(gTU$FgrsHwqam*)(+{ z+u1b^KFujy+3(H9`mJ~$kPZf@Ddx%LYS0Re9K&K-1f+DmX)dEfNELufC0pV<3VSmBGM zY#=HaJuj18t~2sb7K*S@<$R(bB*$vNuhqqEm8djVndz#9l?}wPJp+7!AP%lXD@ZqF zYatMt)hIzFR(6F?HIBq^?7*);Sv$rjE~9yqF@@C8o6y*>K5#64X z{lh=9ew&zLa-Ln&=9o`cj|LS7uMA_qy!#B6+2Kw;m`m4#hKWk36m7`k1Cu`F1^y5O zBDQ+CljwP_WO^>OjSfUHG`r$ z3@VPD)gdM;URCkSMzF=Xe=RK0;LJEJOj@ZGXVkWHiMI$Gp*&o`eGs3mbtR^jpA~7; z!Bu#w%Ws*hVw6=#yJ^&W!KfVn5s1`_LWA7f#bvnjHnhx4%d+=NZ0} z9_a<6n_+c&DZM|WyW@T8b~<;dLvdK8FMox5$?^B-1DQ1>yx?39x^IH~VxFunV3}?r zwy~l}Oy{Tj&GwZqqmR5^cWfbuXt^ z^;kmu;#$oi#Z0R5n@FJ{MY*tc*)y?23aMW&qFS&PApY*HP2_f0!Ev@}pqGGu+|UNN zheo7z{D^uM)ut(4oTr?ksy#72Sr1LS3eS!of}pZc7hy0=!6;A!z&0km&~JqC{)=!a zE4zvY1Ia0ecQ)Y=Uqlp118Ff*pOlHC1^n83hvQ~5{7R)K;}pXbt0W;iT42cSxnHE3 z=3YB`V>D#P$%miZg+U-&v%|4K3jc}NBB{-l2FIcDd`fyMk78>xkKrnYN4w27G*adg zjivN2zDlAcEVdkH01ytK8X`VIrbz-a*tBv|dCrkR>UoBNHFH>rFV-n&qA*0EFYPdv zn7m5SG@tJL9cpZN%u8a^Tw_6hDhPJcx-nuUabZgJu)t(2i-=xg$dVi;iyv&VgaSqS zA;2b;I>ei;?-GpWR7Kc=v?RPmI$T~)dJR4ntJ82dU_ID_G-pWKmq|mhuavZ2M9ihS zCL8zas>n2)KZ13;Ec|37WvaH|Sh7O?HQWj{YQQo0W+Vm0WjwJqS^!5sLFuvEmhgW% z>YyjBFt#sBvD~WEo18k)Bp7xNMGtMzkKNjS(l9FS={m@W&E(~U)<|wk$prJhNFQ#h(-gDk3NBqKFIxWpGUD7d076;HDGo z-|4q?`=ysl%exr}k-)cVWnc`-cpES@`(IA=qCa+TN*vOLeLzMcJ)1*lMi3NV1|jCG zl&#~-!jgftl7T3zx~&i`%y_m&(@5Cn`LTQ*9$X+2PFR9Mqw4|>@D!QaK=%D|;D#pD z(4`;k836>CSRDe&3-5gKA!b+&wXwTmE!u<2nJlhgJ{w_#+-YH|fm&hc5%cX_GE7y5 zsBD-G7cM#wYAhY&6CiI_~x{)w{iy`K>6x;({i2nMB0g2KS(KGL2-~>s z?luUHNl3H2gGSxMg zbbl@PHyenAmyq%FZw6A^0}h(mOTq=C%>W=ki--nHgJSYIx0rIWeZwLN{VJ4!2|l5N&sR>Yu0A?E`PdVu z-a0(_#G{X|EI&GU?9{2p-~84$ufAn1;D{e)2Tqj}0tL*s33JCEYl)d(Tiq{V@q15j zj`9;nPcNe8ke)a247v*?II2t(GCgQ2h%B4ifzjkhLDCIy_M0B**;#uhO)SvcE~HcX zwAJJ;)l?m1&<$Dx3cwb*KYGzG(WUUhtHa^(43HG;mb_Y4Ct6z;{IWA^ZioSn!k`2p zuQ4^Kc~N$E3@yv`I8ZmD#5qz|>TYqZ3N}O8ZES--)_~x!f(H7fi)uIHM}geuXD_NI z4W4??do>f4TvXyu^@)i_Di8tOt!V*hwg3F7sVj7QlY_3ghIBsF>nXjomO$!@m_>nq zU7C6$Pev*^sY(w0*ozx%i^xnVrH;323?EpGAc+)ACSZM=5Hj`3elRF} z>(Qm_D-bIBM6p~RXrJ=?UuppW^y?T>ogdr)Dg6QFvhGdpDR9K5akhVgAc5x5us1nR$F3ald1eoKUOq&tm7J1>F0Yg8|^*CcMbNUat z7cBh-*GpVyMz@%gy634Q$OoGXvaC!Zi3;Jy+LI=HsDqeUNrYB!;Wdw48DcYNS&liyG6PY3T+tYm)sI0UhvKl#>lco6 z6pQigT;K0(N|;;U?_Ju8OheX3vv2QaT4)`K4VkAJQw7)@@#Ps+LG#H#NQ7@$Eh1Hq zRNKHNmDw4&QAs9JO--NTG3@4*UAB3Zz18ZvWpS*?DBnDB?4c5sRJvz}_AtE8VE1%l z`_(;3=nBWuUbTem)Ju;5_m7ZbSEv5ePQ-^cw6-2XOL?f>)Fj@Wm$ynlgvz5g$` zzKN^co}_tn53Eiq`9Iq`J~t@SCNm`B`(cPsC=VDcI6twUFhN0d_rrT)Qqv;9gjDnw zX-V7oZw%K+WuUymAkL<9^jx}z&e`XVbmkf3N4ZKaDRWTp{7>@yGS7d9>myw8Y1$Ge zYJp!&;bBveCW4kCF7<5~JFN3jl`#3R(3e*zsSWTsO-FY-3q% z@l(PTdq}>Lbdc4KkrfDQszt(>Qf zx?csOR&;5zsI+2|Le}M~(&QP+d zWs@oOHqFkSJqdmEmXg0pIq5*uUTXuWOQd--uR6pNZJZ?!RX36>!)1!4O5DK> z$!)(obPLqSBxyD+`x?03T*d@DxKVXW3d z?3~bqX-BYd-MRH9zrYSmU!G@dALA;Vq%l^t7%oG>7CNn8QaN>s0a>3Eko76Pm5-mk zEqk&(n<$v*g$#C?+W?6}%zwLXGZ1?q4*u)D7&t-oB|M-_Pud&YL3W}BWP3rk`A+<` zzKe|3wKrp5d5NZ+61KoAooj#u^(1N?IlP5(r0jv#+Jjw>_C7{?S7`6|xXRa1e(*XX zQyL+Z%!-Lb5u_{*A{ixjB3oD1gk|2}z|RyA7$};(CS3=cX?{!3mR(#6=RyXTaNlUY zcS75V??TgxAVg-lu-}x9i7zX)?=n?Uuk=?DsQB&|l5wkxN&SQFyI<_SCusa_u2&iF z-{&fShl1Px1^1F?Cgwq_?eqKUgou@oR@rl@a12F5Go~@JD{Z8!kbi@wkFGXaAa2?W zPmcktVZKZcE-MjGgo2+~PbE@)HwmhymSQaL=PI}_WB3^N((ip1V<>&}QgJGDMFQd0 zA*fJ_bavYR~6Db!d#0<4i%EL}~7t?8!nM0xUk(Zs-#?C~o^$ z*Il1u0_GDEkM?_=PcyDX#`X4ojQgWpzy8&Z+pDG|C8jdVcCRsp>Wc;Dkmc9`VTm*y zfC$`cX|*tA$;y{rqRyx2qv*qv%R!II8oj{1^ujZfyF519O)QcmBuFJfu!ZBuMksfn z&mS2CEPjBibdsf9 z!P7GbAV!R!fhAE%i@Q2jK}+bf^N*-gxp``x+zW4}T~u9WKFUtf6eps;qB|EOU8Jm58Ns32J{_9td_}t#o_6GN&yRUrz z2FYla2|S`@tAOhWc!*1|EEX8cmcRcdHDwSV3V-7x$VHHAwYyu4a*P|mW(F47gK=uW zuXao9hg{tg*Hoa=T>Kbg7ry;nu3DF8Z-mcfnVVJa6??fL+;>1;YOn<8({GjYX8}#~ zCMU6MG3R*4jzJC-2A_|>9Tq60RYR*YzLB)SN(a1GzxrnAY+vH~Xsho($i4hi-#N~= z)^3iiP+&k)er3qZz>0ekbqT-pUEo|;8Rn(Uc9zG5v8U>>EcgP%qJazEKcF?_OlNFW zjZ$W*SBb>Uk?>`q9@;dTp8GL`EN^(~MKfSJGG0VZSXxNAgPHtQ=1a2Dqica@Kfv{^ zt@-?$+$&Dn^Eo$2#R3<5o2OD@Oh%RFfV0o6TbZ7|93;Bf>cp$!1Qua$Ba#)7eg~j* zIlP?F7qR+Fg46J5z~zA)e=0U`U};2z!3L3v{3)WFP|OT>PUFpIXKS2peT^4+B9IRD zX-Acv*jR(_7U#KD4))z35fy%dCTTz!)@?0R`yZBqPBSJeNX*loP^5 zopA-_k}C?YZsxso)cRScvzLa#l+{|*D1cz8t{9(qgoEG@>crLPX5nwDtw#unK!lJ~ zF^dtL6r|xX6Xzizc}kJ2&sBcPJz%CS9rmw<8wi1#q4e$_6|#^#ax=|S?Ycq(uGk5; zUHJlsQ^59xo})dPWf6sQe&wYjoikj&{MHeltM@$DS?+&`>lbnTt9k#MT+eZTVm+?A zT$MBS<-Wgy2c+5H?JWdUjLXDBr%@@eJuo!+LL&lCC~zm()-om>r-C!w)UrBA#8U`~ z>-*i3Yg-Cjm`;n?W~sxT6rO6OU5VE1U)ihvp{mmsuaKfzz{$)h0*nCx(|2JWMb&wf zPM)p70eHA9AvOfU!Y{FOexC%w`13P=l0)9I5q#H&xQgcd8rLu53P>**q?ZiNi__C3 zBKnGULVG!*gcOVCTEUwx_7vYmjL7NJF%R$(?Qe5m(T2{d3-q_hP51aDm{+m*MPJk6niC$aZ}|o46P(Q`Yun_eR&QTrKfhut`iXlnUXs+K zjSZQbv184g@FMD>_YF761<&4H+u4^jIZCV9EUt;Ufy(eWA~YHBQ_EM99rR}gIE=-^ zzI5L4eVPmot*nOBFtMXOR=^bp^fbbQ(;d3u5l|)Q6YxrO&?5XGV^i*p!aw{x_g~Yx z{~x&*Y@OT=8^XNv(P~$EGoTk@T|8*o*XVi@^CR>!y3@38M;v7mkDXbPf02>UXFc+m z%~+kn>8y5YRC0qP&9b$PZbE*1e4@P}5yb*a3wW2wN2h#XWxkp2W`-h=u{}?d3lOpX zj4Xn>FwoojTh>Q?@ut!;>PCZYe#7~MHb+ZmwN9>FsCe4n1XIl(=LqfIF7qlr@$Yff zJb&$b$8`(ez`gc*S)Y$`uXO`A3YRz$m3R!q2lXfFj$s}?K*#|j92=eW^-MR%vq1Iw zVO}J}Qt>p{n{%BsuzZycIyI%6rh|k+QXR4Oxnu=t!etvA(yr-}2H0X*M5x67jJ(qT zK&Yaa$^dAMDNU9Kss<;4LPI-6dg=mn;=5$S$^{D0#L22SbT#9=xVCwo@#%B{hK7Hq zT?%s98mCNra0x^RV@N1;RC$1986zTq0$P*8dL=l--ea)yx64IW!r)oF@}X8yznO8) z=Gc~+x4e}A&x{DlRGB<~p)}!`HpZKt^rE8F@*y{X7A{tBeR~ld-skXd8LUaeNV z60vxxHy9p*dHNo8z*fKV2z_OO3z;mKK zLv*X61SfR-0LS|Ag1XiQ%xnQ_i--*vybQRP%H6qx;8SL{Ac(QzpJdG4)?9p=d+qVr zy>VIbJ=|+<@5S zSs|@5d4y>2UM;Jy3SiSBbsRVT{Wl1QM?7+JWJk}d*JRb3Giky{k_ zu~bvImZdI$TdqPoD@r11|BVmzKRePy! z*9TZ7+f`u2_0eT5XPi*yE!%Q%W*V(MwR7KsnEup zK29`klGy!e&Yhb&iKlk=IPTvJ3+5sHj++w~`;x9S@oA0KXx2C&7qWBq`n;lssfM;k zz)?S!I6K!@k>`9U9%U%YXk6?b#p&gV>}IF4xgRoPp~L?T_rhi6{{P}$epMIV7kK!G zxwicY|2p^5Iep%r9p_8m!~NH_>iHn|U%>r`xXRP{N4Y-E^;fdo?{O7Pd&8eQ;2!IjrfV0dyz|gaNA!pohtgu?iFGxyX9r z7Kp~Dzv%2E<4Bzb;p1R4Z8FkM(cx zG>ODrlfn~o(*++K>VvscGXZsz#l|O+301VA%mG~rFfv1{#szKB9}YV^48qDwfQ_L5 zio%~S3uuRb)%hfA`sJ)`fvNw6d->Xx`#=5XLryRE_kyVcLoZNXF!!Hxm7VGH-XD77 zw{Vr+aG9%MtH9FJig6F*A!b0>7;Ow|0v>u2dX~e3laV`Z!LQG2-AXv^lVjiH`y;#*HwW-M0m0(RXMlCz%8Vh>%KckSB}P2!6mCr!pGG ze|7Qv@h6TK5B00_7t|Okij;5)sta7(=nF{h0I3BkHFs{GeaM%zwq#sfzHh`oAjaKO zX_>1TYy^d`lknI4A1e}^1^9Xmu1`Rg4oZM$^5Z_TmcoOU4oz8e}O4mzin>6hKxuVicM6ui%DcfaiBR#ol&ExJRO z=hbDA#9*}XFxI(Vx?%JQX8cOL)SvfmpKmCSmO{jbMp8d+pVa zac%qLe1dz)I$!mH;B8NGo#y@)SJ9oH=h~JN|99@&`lx~v9{OO^Kj5nRevYehe*E!o zj(j3t&h-iIFLRaO!zNeNQ*gw*?GG*7P~agTxoosVBj)7Rm)ADf>}V@w<`VW5Tn4HP zTtW<_1K@&mM-y-W%J#3^P>l?|4VBmO>QtiOEK+vk;&1?`uoV4`0Ha%z|LPp~ZJ(Si?j@_1 zwfQOTU)#Db`|=lg{tZ0;qQ7*c^LDOfznx9r;xv=AP*}gu55# z30CxaXzh?(hEPL%rGfuKl4vkYM4gS$m+T3&Ztob^TIO4Q^Q(zAH{aYf+e0^2%6m63<5hF? z9pRHy-Zu_yPJufdoUk55%N)rpe8#d>qf+`G2G&;ebg5VNI@MdYQu+#st$7h zNa&Q*N2)QArS?<|v)8#xeNSh7D*dwk7*vR zO$()j5<8i+G&DCelQh!S*^|s989JF6=h7zNrHG!lC`v`eA{?!PQbZB7XjR0@MT(bW zz2E^v1z$Y}1^E;YD6hw(@Avn=JnLC|_T*ADALuh{?X{luT>kglBbusSRUuC`hC*s| z->BB-e)@e$^y~a9R4Rt!25u~qhi4T^Z~waA@3d^xR)2Yw@_sA^D!Y(55xyY{BJ%VU z7)&SocwhR*(D%)p;_IE?yQ6$h@n@R(z&Gt3aVUrg{ocp(ij7^r|5$f_yz?N>i!ZMK zeDJFnQ1>+sPmILEH(Ub;D0j-WxlE)!wL}qlR7!fxG-V``QKzL6PUdye5Y{cZSC^LY z%c$Zg2TfVAa0PozY%`H*k@cL}r~jCL6fn^IGg3wsAEamO9T`JxA8(|Vv6k4b$J}<) zA6IT(T3tj?`alrJh;de=9@^a9;>Iulv;B)%X!L~}D$hZ%cb_K{4>hT0%OgTSU>Mi&~+y3k9 zx#jvs9(vNZKjFS`{Of+e^P(4N6^r{FwBq+aLHh*SchJhdb1$vr_Q(F9`z4dUt+&G{ zcd88rPq8>saS|_*WZV{zaHX$rI~d?_T2K%%dI*bo`gQVU>Q zU%>tK*5?tgbwAikX+1`~7;a5vHhrB$B3CBtyE&aztB5LU>1(nibB^}z9{Q3Uf4BT} zo~o0j>+lIs72Vej6C@Aa;l7-~aX*9mkK*Sw`&CM~E~)^2@`LMV4v!LYctR1tGxN91 za>$SjOsG8++*%AevWq@-ri1q0h9$T+dw0Y<$8&ean6A^bs|QW)t{%OQ=cKdQa|(AV zq0`o{MfguytcNY7F-chu;`}RLH9T(^R(ls+WGSr|T_pU#mm#6wIMIIM(=uEfLJ?$4 zDehYN#%)7(5K$#!vJg4_A9C}*-h0)06`Rby2vTOUrfET3ksJJbd~ zZu%kjtG=9eFZb8oYm+HwuvNQS>RW%fpv+;>EqyzLt>C`_C!Nk`>0k9Y^ScSxPkx=p zIVYYcocN2vPJ<7FN!w=8dBThi%38n8*M`ejHLYAcux*0DgtqGmbms9DxzjL3kRysA z5hb`9IlGKWGL?Fmw@Q)9D2o&0jA0MtH0AM6)^VH<8pJd;wTc7vzC{1pgDZd7ZPt7T zQA6|-d1HRFiUI>VQIOOn{~WvRJi|({$Uxa0a(1q_@$o+W?vC-d$DQG^d`prIYk>4^ z;V^I%i7>b(<0z{kbGes(PNirt@lFzJSRUn{WRg7E|JK7+Bk|R3&3NY z+j-vPvikXEx}AGtT=B((f6D6~UDy$+06N2?{9s8wUY}DdZNeL~pg8p0)F~+0$y1Y* z6`I+nzjVAQ_bJ=4GLxOzekQ}E0~TMV59#EwE`w%WA;T&Rd}&s$V7Cxk+IJrZt%3

`Dr66(fQTy| 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

6{u>RgkeeoM-jy+Hb*aa*^iCl~@))V-T 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]() { - $method_name(WasmExecutionMethod::Compiled); + fn [<$method_name _compiled_recreate_instance_cow>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstanceCopyOnWrite + }); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_recreate_instance_vanilla>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstance + }); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_pooling_cow>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite + }); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_pooling_vanilla>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::Pooling + }); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_legacy_instance_reuse>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse + }); } } }; @@ -88,14 +122,82 @@ macro_rules! test_wasm_execution_sandbox { #[test] #[cfg(feature = "wasmtime")] - fn [<$method_name _compiled_host_executor>]() { - $method_name(WasmExecutionMethod::Compiled, "_host"); + fn [<$method_name _compiled_pooling_cow_host_executor>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite + }, "_host"); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_pooling_cow_embedded_executor>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite + }, "_embedded"); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_pooling_vanilla_host_executor>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::Pooling + }, "_host"); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_pooling_vanilla_embedded_executor>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::Pooling + }, "_embedded"); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_recreate_instance_cow_host_executor>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstanceCopyOnWrite + }, "_host"); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_recreate_instance_cow_embedded_executor>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstanceCopyOnWrite + }, "_embedded"); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_recreate_instance_vanilla_host_executor>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstance + }, "_host"); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_recreate_instance_vanilla_embedded_executor>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstance + }, "_embedded"); + } + + #[test] + #[cfg(feature = "wasmtime")] + fn [<$method_name _compiled_legacy_instance_reuse_host_executor>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse + }, "_host"); } #[test] #[cfg(feature = "wasmtime")] - fn [<$method_name _compiled_embedded_executor>]() { - $method_name(WasmExecutionMethod::Compiled, "_embedded"); + fn [<$method_name _compiled_legacy_instance_reuse_embedded_executor>]() { + $method_name(WasmExecutionMethod::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse + }, "_embedded"); } } }; @@ -153,7 +255,7 @@ fn call_not_existing_function(wasm_method: WasmExecutionMethod) { let expected = match wasm_method { WasmExecutionMethod::Interpreted => "Trap: Host(Other(\"Function `missing_external` is only a stub. Calling a stub is not allowed.\"))", #[cfg(feature = "wasmtime")] - WasmExecutionMethod::Compiled => "call to a missing function env:missing_external" + WasmExecutionMethod::Compiled { .. } => "call to a missing function env:missing_external" }; assert_eq!(error.message, expected); }, @@ -173,7 +275,7 @@ fn call_yet_another_not_existing_function(wasm_method: WasmExecutionMethod) { let expected = match wasm_method { WasmExecutionMethod::Interpreted => "Trap: Host(Other(\"Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.\"))", #[cfg(feature = "wasmtime")] - WasmExecutionMethod::Compiled => "call to a missing function env:yet_another_missing_external" + WasmExecutionMethod::Compiled { .. } => "call to a missing function env:yet_another_missing_external" }; assert_eq!(error.message, expected); }, @@ -473,7 +575,9 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { match err { #[cfg(feature = "wasmtime")] - Error::AbortedDueToTrap(error) if wasm_method == WasmExecutionMethod::Compiled => { + Error::AbortedDueToTrap(error) + if matches!(wasm_method, WasmExecutionMethod::Compiled { .. }) => + { assert_eq!( error.message, r#"host code panicked while being called by the runtime: Failed to allocate memory: "Allocator ran out of space""# @@ -807,7 +911,7 @@ fn unreachable_intrinsic(wasm_method: WasmExecutionMethod) { let expected = match wasm_method { WasmExecutionMethod::Interpreted => "Trap: Unreachable", #[cfg(feature = "wasmtime")] - WasmExecutionMethod::Compiled => "wasm trap: wasm `unreachable` instruction executed", + WasmExecutionMethod::Compiled { .. } => "wasm trap: wasm `unreachable` instruction executed", }; assert_eq!(error.message, expected); }, diff --git a/client/executor/src/lib.rs b/client/executor/src/lib.rs index 5cd04b9e4ee6a..fefb84ede9105 100644 --- a/client/executor/src/lib.rs +++ b/client/executor/src/lib.rs @@ -51,6 +51,9 @@ pub use wasmi; pub use sc_executor_common::{error, sandbox}; +#[cfg(feature = "wasmtime")] +pub use sc_executor_wasmtime::InstantiationStrategy as WasmtimeInstantiationStrategy; + /// Extracts the runtime version of a given runtime code. pub trait RuntimeVersionOf { /// Extract [`RuntimeVersion`](sp_version::RuntimeVersion) of the given `runtime_code`. diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 85c33ecacf8ff..1dee739c50f9e 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -46,7 +46,10 @@ pub enum WasmExecutionMethod { Interpreted, /// Uses the Wasmtime compiled runtime. #[cfg(feature = "wasmtime")] - Compiled, + Compiled { + /// The instantiation strategy to use. + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy, + }, } impl Default for WasmExecutionMethod { @@ -71,6 +74,9 @@ struct VersionedRuntime { module: Arc, /// Runtime version according to `Core_version` if any. version: Option, + + // TODO: Remove this once the legacy instance reuse instantiation strategy + // for `wasmtime` is gone, as this only makes sense with that particular strategy. /// Cached instance pool. instances: Arc>>>>, } @@ -310,22 +316,23 @@ where .map(|runtime| -> Arc { Arc::new(runtime) }) }, #[cfg(feature = "wasmtime")] - WasmExecutionMethod::Compiled => sc_executor_wasmtime::create_runtime::( - blob, - sc_executor_wasmtime::Config { - max_memory_size: None, - allow_missing_func_imports, - cache_path: cache_path.map(ToOwned::to_owned), - semantics: sc_executor_wasmtime::Semantics { - extra_heap_pages: heap_pages, - fast_instance_reuse: true, - deterministic_stack_limit: None, - canonicalize_nans: false, - parallel_compilation: true, + WasmExecutionMethod::Compiled { instantiation_strategy } => + sc_executor_wasmtime::create_runtime::( + blob, + sc_executor_wasmtime::Config { + allow_missing_func_imports, + cache_path: cache_path.map(ToOwned::to_owned), + semantics: sc_executor_wasmtime::Semantics { + extra_heap_pages: heap_pages, + instantiation_strategy, + deterministic_stack_limit: None, + canonicalize_nans: false, + parallel_compilation: true, + max_memory_size: None, + }, }, - }, - ) - .map(|runtime| -> Arc { Arc::new(runtime) }), + ) + .map(|runtime| -> Arc { Arc::new(runtime) }), } } diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index c514a93be1d88..cbe6e1a0bd101 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -23,6 +23,8 @@ wasmtime = { version = "0.35.3", default-features = false, features = [ "cranelift", "jitdump", "parallel-compilation", + "memory-init-cow", + "pooling-allocator", ] } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } @@ -34,3 +36,4 @@ sp-wasm-interface = { version = "6.0.0", features = ["wasmtime"], path = "../../ wat = "1.0" sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } sp-io = { version = "6.0.0", path = "../../../primitives/io" } +tempfile = "3.3.0" diff --git a/client/executor/wasmtime/src/lib.rs b/client/executor/wasmtime/src/lib.rs index c54c8305f3e4b..4d0e4c37c947e 100644 --- a/client/executor/wasmtime/src/lib.rs +++ b/client/executor/wasmtime/src/lib.rs @@ -38,5 +38,5 @@ mod tests; pub use runtime::{ create_runtime, create_runtime_from_artifact, prepare_runtime_artifact, Config, - DeterministicStackLimit, Semantics, + DeterministicStackLimit, InstantiationStrategy, Semantics, }; diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index fa3b567cc0abc..dbe0b129757b7 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -80,7 +80,7 @@ impl StoreData { pub(crate) type Store = wasmtime::Store; enum Strategy { - FastInstanceReuse { + LegacyInstanceReuse { instance_wrapper: InstanceWrapper, globals_snapshot: GlobalsSnapshot, data_segments_snapshot: Arc, @@ -136,41 +136,42 @@ struct InstanceSnapshotData { pub struct WasmtimeRuntime { engine: wasmtime::Engine, instance_pre: Arc>, - snapshot_data: Option, + instantiation_strategy: InternalInstantiationStrategy, config: Config, } impl WasmModule for WasmtimeRuntime { fn new_instance(&self) -> Result> { - let strategy = if let Some(ref snapshot_data) = self.snapshot_data { - let mut instance_wrapper = InstanceWrapper::new( - &self.engine, - &self.instance_pre, - self.config.max_memory_size, - )?; - let heap_base = instance_wrapper.extract_heap_base()?; - - // This function panics if the instance was created from a runtime blob different from - // which the mutable globals were collected. Here, it is easy to see that there is only - // a single runtime blob and thus it's the same that was used for both creating the - // instance and collecting the mutable globals. - let globals_snapshot = GlobalsSnapshot::take( - &snapshot_data.mutable_globals, - &mut InstanceGlobals { instance: &mut instance_wrapper }, - ); + let strategy = match self.instantiation_strategy { + InternalInstantiationStrategy::LegacyInstanceReuse(ref snapshot_data) => { + let mut instance_wrapper = InstanceWrapper::new( + &self.engine, + &self.instance_pre, + self.config.semantics.max_memory_size, + )?; + let heap_base = instance_wrapper.extract_heap_base()?; - Strategy::FastInstanceReuse { - instance_wrapper, - globals_snapshot, - data_segments_snapshot: snapshot_data.data_segments_snapshot.clone(), - heap_base, - } - } else { - Strategy::RecreateInstance(InstanceCreator { + // This function panics if the instance was created from a runtime blob different + // from which the mutable globals were collected. Here, it is easy to see that there + // is only a single runtime blob and thus it's the same that was used for both + // creating the instance and collecting the mutable globals. + let globals_snapshot = GlobalsSnapshot::take( + &snapshot_data.mutable_globals, + &mut InstanceGlobals { instance: &mut instance_wrapper }, + ); + + Strategy::LegacyInstanceReuse { + instance_wrapper, + globals_snapshot, + data_segments_snapshot: snapshot_data.data_segments_snapshot.clone(), + heap_base, + } + }, + InternalInstantiationStrategy::Builtin => Strategy::RecreateInstance(InstanceCreator { engine: self.engine.clone(), instance_pre: self.instance_pre.clone(), - max_memory_size: self.config.max_memory_size, - }) + max_memory_size: self.config.semantics.max_memory_size, + }), }; Ok(Box::new(WasmtimeInstance { strategy })) @@ -186,7 +187,7 @@ pub struct WasmtimeInstance { impl WasmInstance for WasmtimeInstance { fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result> { match &mut self.strategy { - Strategy::FastInstanceReuse { + Strategy::LegacyInstanceReuse { ref mut instance_wrapper, globals_snapshot, data_segments_snapshot, @@ -225,7 +226,7 @@ impl WasmInstance for WasmtimeInstance { fn get_global_const(&mut self, name: &str) -> Result> { match &mut self.strategy { - Strategy::FastInstanceReuse { instance_wrapper, .. } => + Strategy::LegacyInstanceReuse { instance_wrapper, .. } => instance_wrapper.get_global_val(name), Strategy::RecreateInstance(ref mut instance_creator) => instance_creator.instantiate()?.get_global_val(name), @@ -239,7 +240,7 @@ impl WasmInstance for WasmtimeInstance { // associated with it. None }, - Strategy::FastInstanceReuse { instance_wrapper, .. } => + Strategy::LegacyInstanceReuse { instance_wrapper, .. } => Some(instance_wrapper.base_ptr()), } } @@ -326,6 +327,48 @@ fn common_config(semantics: &Semantics) -> std::result::Result (true, true), + InstantiationStrategy::Pooling => (true, false), + InstantiationStrategy::RecreateInstanceCopyOnWrite => (false, true), + InstantiationStrategy::RecreateInstance => (false, false), + InstantiationStrategy::LegacyInstanceReuse => (false, false), + }; + + config.memory_init_cow(use_cow); + config.memory_guaranteed_dense_image_size( + semantics.max_memory_size.map(|max| max as u64).unwrap_or(u64::MAX), + ); + + if use_pooling { + config.allocation_strategy(wasmtime::InstanceAllocationStrategy::Pooling { + strategy: wasmtime::PoolingAllocationStrategy::ReuseAffinity, + + // Pooling needs a bunch of hard limits to be set; if we go over + // any of these then the instantiation will fail. + instance_limits: wasmtime::InstanceLimits { + // Current minimum values for kusama (as of 2022-04-14): + // size: 32384 + // table_elements: 1249 + // memory_pages: 2070 + size: 64 * 1024, + table_elements: 2048, + memory_pages: 4096, + + // We can only have a single of those. + tables: 1, + memories: 1, + + // This determines how many instances of the module can be + // instantiated in parallel from the same `Module`. + // + // This includes nested instances spawned with `sp_tasks::spawn` + // from *within* the runtime. + count: 32, + }, + }); + } + Ok(config) } @@ -373,18 +416,47 @@ pub struct DeterministicStackLimit { pub native_stack_max: u32, } -pub struct Semantics { - /// Enabling this will lead to some optimization shenanigans that make calling [`WasmInstance`] - /// extremely fast. - /// - /// Primarily this is achieved by not recreating the instance for each call and performing a - /// bare minimum clean up: reapplying the data segments and restoring the values for global - /// variables. +/// The instantiation strategy to use for the WASM executor. +/// +/// All of the CoW strategies (with `CopyOnWrite` suffix) are only supported when either: +/// a) we're running on Linux, +/// b) we're running on an Unix-like system and we're precompiling +/// our module beforehand. +/// +/// If the CoW variant of a strategy is unsupported the executor will +/// fall back to the non-CoW equivalent. +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum InstantiationStrategy { + /// Pool the instances to avoid initializing everything from scratch + /// on each instantiation. Use copy-on-write memory when possible. /// - /// Since this feature depends on instrumentation, it can be set only if runtime is - /// instantiated using the runtime blob, e.g. using [`create_runtime`]. - // I.e. if [`CodeSupplyMode::Verbatim`] is used. - pub fast_instance_reuse: bool, + /// This is the fastest instantiation strategy. + PoolingCopyOnWrite, + + /// Recreate the instance from scratch on every instantiation. + /// Use copy-on-write memory when possible. + RecreateInstanceCopyOnWrite, + + /// Pool the instances to avoid initializing everything from scratch + /// on each instantiation. + Pooling, + + /// Recreate the instance from scratch on every instantiation. Very slow. + RecreateInstance, + + /// Legacy instance reuse mechanism. DEPRECATED. Will be removed. Do not use. + LegacyInstanceReuse, +} + +enum InternalInstantiationStrategy { + LegacyInstanceReuse(InstanceSnapshotData), + Builtin, +} + +pub struct Semantics { + /// The instantiation strategy to use. + pub instantiation_strategy: InstantiationStrategy, /// Specifying `Some` will enable deterministic stack height. That is, all executor /// invocations will reach stack overflow at the exactly same point across different wasmtime @@ -418,9 +490,7 @@ pub struct Semantics { /// The number of extra WASM pages which will be allocated /// on top of what is requested by the WASM blob itself. pub extra_heap_pages: u64, -} -pub struct Config { /// The total amount of memory in bytes an instance can request. /// /// If specified, the runtime will be able to allocate only that much of wasm memory. @@ -436,7 +506,9 @@ pub struct Config { /// /// The default is `None`. pub max_memory_size: Option, +} +pub struct Config { /// The WebAssembly standard requires all imports of an instantiated module to be resolved, /// otherwise, the instantiation fails. If this option is set to `true`, then this behavior is /// overriden and imports that are requested by the module and not provided by the host @@ -452,24 +524,16 @@ pub struct Config { enum CodeSupplyMode<'a> { /// The runtime is instantiated using the given runtime blob. - Verbatim { - // Rationale to take the `RuntimeBlob` here is so that the client will be able to reuse - // the blob e.g. if they did a prevalidation. If they didn't they can pass a `RuntimeBlob` - // instance and it will be used anyway in most cases, because we are going to do at least - // some instrumentations for both anticipated paths: substrate execution and PVF execution. - // - // Should there raise a need in performing no instrumentation and the client doesn't need - // to do any checks, then we can provide a `Cow` like semantics here: if we need the blob - // and the user got `RuntimeBlob` then extract it, or otherwise create it from the given - // bytecode. - blob: RuntimeBlob, - }, + Fresh(RuntimeBlob), - /// The code is supplied in a form of a compiled artifact. + /// The runtime is instantiated using a precompiled module. /// /// This assumes that the code is already prepared for execution and the same `Config` was /// used. - Artifact { compiled_artifact: &'a [u8] }, + /// + /// We use a `Path` here instead of simply passing a byte slice to allow `wasmtime` to + /// map the runtime's linear memory on supported platforms in a copy-on-write fashion. + Precompiled(&'a Path), } /// Create a new `WasmtimeRuntime` given the code. This function performs translation from Wasm to @@ -484,29 +548,34 @@ pub fn create_runtime( where H: HostFunctions, { - // SAFETY: this is safe because it doesn't use `CodeSupplyMode::Artifact`. - unsafe { do_create_runtime::(CodeSupplyMode::Verbatim { blob }, config) } + // SAFETY: this is safe because it doesn't use `CodeSupplyMode::Precompiled`. + unsafe { do_create_runtime::(CodeSupplyMode::Fresh(blob), config) } } -/// The same as [`create_runtime`] but takes a precompiled artifact, which makes this function -/// considerably faster than [`create_runtime`]. +/// The same as [`create_runtime`] but takes a path to a precompiled artifact, +/// which makes this function considerably faster than [`create_runtime`]. /// /// # Safety /// -/// The caller must ensure that the compiled artifact passed here was produced by -/// [`prepare_runtime_artifact`]. Otherwise, there is a risk of arbitrary code execution with all -/// implications. +/// The caller must ensure that the compiled artifact passed here was: +/// 1) produced by [`prepare_runtime_artifact`], +/// 2) written to the disk as a file, +/// 3) was not modified, +/// 4) will not be modified while any runtime using this artifact is alive, or is being +/// instantiated. +/// +/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution. /// -/// It is ok though if the `compiled_artifact` was created by code of another version or with +/// It is ok though if the compiled artifact was created by code of another version or with /// different configuration flags. In such case the caller will receive an `Err` deterministically. pub unsafe fn create_runtime_from_artifact( - compiled_artifact: &[u8], + compiled_artifact_path: &Path, config: Config, ) -> std::result::Result where H: HostFunctions, { - do_create_runtime::(CodeSupplyMode::Artifact { compiled_artifact }, config) + do_create_runtime::(CodeSupplyMode::Precompiled(compiled_artifact_path), config) } /// # Safety @@ -520,7 +589,6 @@ unsafe fn do_create_runtime( where H: HostFunctions, { - // Create the engine, store and finally the module from the given code. let mut wasmtime_config = common_config(&config.semantics)?; if let Some(ref cache_path) = config.cache_path { if let Err(reason) = setup_wasmtime_caching(cache_path, &mut wasmtime_config) { @@ -534,45 +602,71 @@ where let engine = Engine::new(&wasmtime_config) .map_err(|e| WasmError::Other(format!("cannot create the wasmtime engine: {}", e)))?; - let (module, snapshot_data) = match code_supply_mode { - CodeSupplyMode::Verbatim { blob } => { + let (module, instantiation_strategy) = match code_supply_mode { + CodeSupplyMode::Fresh(blob) => { let blob = prepare_blob_for_compilation(blob, &config.semantics)?; let serialized_blob = blob.clone().serialize(); let module = wasmtime::Module::new(&engine, &serialized_blob) .map_err(|e| WasmError::Other(format!("cannot create module: {}", e)))?; - if config.semantics.fast_instance_reuse { - let data_segments_snapshot = DataSegmentsSnapshot::take(&blob).map_err(|e| { - WasmError::Other(format!("cannot take data segments snapshot: {}", e)) - })?; - let data_segments_snapshot = Arc::new(data_segments_snapshot); - let mutable_globals = ExposedMutableGlobalsSet::collect(&blob); - - (module, Some(InstanceSnapshotData { data_segments_snapshot, mutable_globals })) - } else { - (module, None) + match config.semantics.instantiation_strategy { + InstantiationStrategy::LegacyInstanceReuse => { + let data_segments_snapshot = + DataSegmentsSnapshot::take(&blob).map_err(|e| { + WasmError::Other(format!("cannot take data segments snapshot: {}", e)) + })?; + let data_segments_snapshot = Arc::new(data_segments_snapshot); + let mutable_globals = ExposedMutableGlobalsSet::collect(&blob); + + ( + module, + InternalInstantiationStrategy::LegacyInstanceReuse(InstanceSnapshotData { + data_segments_snapshot, + mutable_globals, + }), + ) + }, + InstantiationStrategy::Pooling | + InstantiationStrategy::PoolingCopyOnWrite | + InstantiationStrategy::RecreateInstance | + InstantiationStrategy::RecreateInstanceCopyOnWrite => + (module, InternalInstantiationStrategy::Builtin), } }, - CodeSupplyMode::Artifact { compiled_artifact } => { - // SAFETY: The unsafity of `deserialize` is covered by this function. The + CodeSupplyMode::Precompiled(compiled_artifact_path) => { + if let InstantiationStrategy::LegacyInstanceReuse = + config.semantics.instantiation_strategy + { + return Err(WasmError::Other("the legacy instance reuse instantiation strategy is incompatible with precompiled modules".into())); + } + + // SAFETY: The unsafety of `deserialize_file` is covered by this function. The // responsibilities to maintain the invariants are passed to the caller. - let module = wasmtime::Module::deserialize(&engine, compiled_artifact) + // + // See [`create_runtime_from_artifact`] for more details. + let module = wasmtime::Module::deserialize_file(&engine, compiled_artifact_path) .map_err(|e| WasmError::Other(format!("cannot deserialize module: {}", e)))?; - (module, None) + (module, InternalInstantiationStrategy::Builtin) }, }; let mut linker = wasmtime::Linker::new(&engine); crate::imports::prepare_imports::(&mut linker, &module, config.allow_missing_func_imports)?; - let mut store = crate::instance_wrapper::create_store(module.engine(), config.max_memory_size); + let mut store = + crate::instance_wrapper::create_store(module.engine(), config.semantics.max_memory_size); let instance_pre = linker .instantiate_pre(&mut store, &module) .map_err(|e| WasmError::Other(format!("cannot preinstantiate module: {}", e)))?; - Ok(WasmtimeRuntime { engine, instance_pre: Arc::new(instance_pre), snapshot_data, config }) + Ok(WasmtimeRuntime { + engine, + instance_pre: Arc::new(instance_pre), + instantiation_strategy, + config, + }) } fn prepare_blob_for_compilation( @@ -583,16 +677,17 @@ fn prepare_blob_for_compilation( blob = blob.inject_stack_depth_metering(logical_max)?; } - // If enabled, this should happen after all other passes that may introduce global variables. - if semantics.fast_instance_reuse { + if let InstantiationStrategy::LegacyInstanceReuse = semantics.instantiation_strategy { + // When this strategy is used this must be called after all other passes which may introduce + // new global variables, otherwise they will not be reset when we call into the runtime + // again. blob.expose_mutable_globals(); } // We don't actually need the memory to be imported so we can just convert any memory // import into an export with impunity. This simplifies our code since `wasmtime` will - // now automatically take care of creating the memory for us, and it also allows us - // to potentially enable `wasmtime`'s instance pooling at a later date. (Imported - // memories are ineligible for pooling.) + // now automatically take care of creating the memory for us, and it is also necessary + // to enable `wasmtime`'s instance pooling. (Imported memories are ineligible for pooling.) blob.convert_memory_import_into_export()?; blob.add_extra_heap_pages_to_memory_section( semantics diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index d5b92f2f24a76..51875d1eb6b50 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -19,18 +19,20 @@ use codec::{Decode as _, Encode as _}; use sc_executor_common::{error::Error, runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; use sc_runtime_test::wasm_binary_unwrap; -use std::sync::Arc; + +use crate::InstantiationStrategy; type HostFunctions = sp_io::SubstrateHostFunctions; struct RuntimeBuilder { code: Option, - fast_instance_reuse: bool, + instantiation_strategy: InstantiationStrategy, canonicalize_nans: bool, deterministic_stack: bool, extra_heap_pages: u64, max_memory_size: Option, precompile_runtime: bool, + tmpdir: Option, } impl RuntimeBuilder { @@ -39,41 +41,42 @@ impl RuntimeBuilder { fn new_on_demand() -> Self { Self { code: None, - fast_instance_reuse: false, + instantiation_strategy: InstantiationStrategy::RecreateInstance, canonicalize_nans: false, deterministic_stack: false, extra_heap_pages: 1024, max_memory_size: None, precompile_runtime: false, + tmpdir: None, } } - fn use_wat(&mut self, code: String) -> &mut Self { + fn use_wat(mut self, code: String) -> Self { self.code = Some(code); self } - fn canonicalize_nans(&mut self, canonicalize_nans: bool) -> &mut Self { + fn canonicalize_nans(mut self, canonicalize_nans: bool) -> Self { self.canonicalize_nans = canonicalize_nans; self } - fn deterministic_stack(&mut self, deterministic_stack: bool) -> &mut Self { + fn deterministic_stack(mut self, deterministic_stack: bool) -> Self { self.deterministic_stack = deterministic_stack; self } - fn precompile_runtime(&mut self, precompile_runtime: bool) -> &mut Self { + fn precompile_runtime(mut self, precompile_runtime: bool) -> Self { self.precompile_runtime = precompile_runtime; self } - fn max_memory_size(&mut self, max_memory_size: Option) -> &mut Self { + fn max_memory_size(mut self, max_memory_size: Option) -> Self { self.max_memory_size = max_memory_size; self } - fn build(&mut self) -> Arc { + fn build<'a>(&'a mut self) -> impl WasmModule + 'a { let blob = { let wasm: Vec; @@ -90,11 +93,10 @@ impl RuntimeBuilder { }; let config = crate::Config { - max_memory_size: self.max_memory_size, allow_missing_func_imports: true, cache_path: None, semantics: crate::Semantics { - fast_instance_reuse: self.fast_instance_reuse, + instantiation_strategy: self.instantiation_strategy, deterministic_stack_limit: match self.deterministic_stack { true => Some(crate::DeterministicStackLimit { logical_max: 65536, @@ -105,24 +107,31 @@ impl RuntimeBuilder { canonicalize_nans: self.canonicalize_nans, parallel_compilation: true, extra_heap_pages: self.extra_heap_pages, + max_memory_size: self.max_memory_size, }, }; - let rt = if self.precompile_runtime { + if self.precompile_runtime { + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("runtime.bin"); + + // Delay the removal of the temporary directory until we're dropped. + self.tmpdir = Some(dir); + let artifact = crate::prepare_runtime_artifact(blob, &config.semantics).unwrap(); - unsafe { crate::create_runtime_from_artifact::(&artifact, config) } + std::fs::write(&path, artifact).unwrap(); + unsafe { crate::create_runtime_from_artifact::(&path, config) } } else { crate::create_runtime::(blob, config) } - .expect("cannot create runtime"); - - Arc::new(rt) as Arc + .expect("cannot create runtime") } } #[test] fn test_nan_canonicalization() { - let runtime = RuntimeBuilder::new_on_demand().canonicalize_nans(true).build(); + let mut builder = RuntimeBuilder::new_on_demand().canonicalize_nans(true); + let runtime = builder.build(); let mut instance = runtime.new_instance().expect("failed to instantiate a runtime"); @@ -161,10 +170,11 @@ fn test_nan_canonicalization() { fn test_stack_depth_reaching() { const TEST_GUARD_PAGE_SKIP: &str = include_str!("test-guard-page-skip.wat"); - let runtime = RuntimeBuilder::new_on_demand() + let mut builder = RuntimeBuilder::new_on_demand() .use_wat(TEST_GUARD_PAGE_SKIP.to_string()) - .deterministic_stack(true) - .build(); + .deterministic_stack(true); + + let runtime = builder.build(); let mut instance = runtime.new_instance().expect("failed to instantiate a runtime"); match instance.call_export("test-many-locals", &[]).unwrap_err() { @@ -202,11 +212,12 @@ fn test_max_memory_pages(import_memory: bool, precompile_runtime: bool) { wat: String, precompile_runtime: bool, ) -> Result<(), Box> { - let runtime = RuntimeBuilder::new_on_demand() + let mut builder = RuntimeBuilder::new_on_demand() .use_wat(wat) .max_memory_size(max_memory_size) - .precompile_runtime(precompile_runtime) - .build(); + .precompile_runtime(precompile_runtime); + + let runtime = builder.build(); let mut instance = runtime.new_instance()?; let _ = instance.call_export("main", &[])?; Ok(()) @@ -377,15 +388,15 @@ fn test_instances_without_reuse_are_not_leaked() { let runtime = crate::create_runtime::( RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), crate::Config { - max_memory_size: None, allow_missing_func_imports: true, cache_path: None, semantics: crate::Semantics { - fast_instance_reuse: false, + instantiation_strategy: InstantiationStrategy::RecreateInstance, deterministic_stack_limit: None, canonicalize_nans: false, parallel_compilation: true, extra_heap_pages: 2048, + max_memory_size: None, }, }, ) diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 35380da11fc71..c895300fea4d1 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -21,6 +21,8 @@ pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStrategy}; pub use sc_client_db::{Database, DatabaseSource, KeepBlocks, PruningMode}; pub use sc_executor::WasmExecutionMethod; +#[cfg(feature = "wasmtime")] +pub use sc_executor::WasmtimeInstantiationStrategy; pub use sc_network::{ config::{ MultiaddrWithPeerId, NetworkConfiguration, NodeKeyConfig, NonDefaultSetConfig, Role, diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 660f31b8f1529..aa95223619b45 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -23,7 +23,9 @@ use frame_benchmarking::{ }; use frame_support::traits::StorageInfo; use linked_hash_map::LinkedHashMap; -use sc_cli::{CliConfiguration, ExecutionStrategy, Result, SharedParams}; +use sc_cli::{ + execution_method_from_cli, CliConfiguration, ExecutionStrategy, Result, SharedParams, +}; use sc_client_db::BenchmarkingState; use sc_executor::NativeElseWasmExecutor; use sc_service::{Configuration, NativeExecutionDispatch}; @@ -121,7 +123,6 @@ impl PalletCmd { } let spec = config.chain_spec; - let wasm_method = self.wasm_method.into(); let strategy = self.execution.unwrap_or(ExecutionStrategy::Native); let pallet = self.pallet.clone().unwrap_or_default(); let pallet = pallet.as_bytes(); @@ -141,7 +142,7 @@ impl PalletCmd { let state_without_tracking = BenchmarkingState::::new(genesis_storage, cache_size, self.record_proof, false)?; let executor = NativeElseWasmExecutor::::new( - wasm_method, + execution_method_from_cli(self.wasm_method, self.wasmtime_instantiation_strategy), self.heap_pages, 2, // The runtime instances cache size. 2, // The runtime cache size diff --git a/utils/frame/benchmarking-cli/src/pallet/mod.rs b/utils/frame/benchmarking-cli/src/pallet/mod.rs index 48ddcc7ce8eec..227c9b2f8a7b6 100644 --- a/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -18,7 +18,10 @@ mod command; mod writer; -use sc_cli::{ExecutionStrategy, WasmExecutionMethod, DEFAULT_WASM_EXECUTION_METHOD}; +use sc_cli::{ + ExecutionStrategy, WasmExecutionMethod, WasmtimeInstantiationStrategy, + DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD, +}; use std::{fmt::Debug, path::PathBuf}; // Add a more relaxed parsing for pallet names by allowing pallet directory names with `-` to be @@ -131,6 +134,17 @@ pub struct PalletCmd { )] pub wasm_method: WasmExecutionMethod, + /// The WASM instantiation method to use. + /// + /// Only has an effect when `wasm-execution` is set to `compiled`. + #[clap( + long = "wasm-instantiation-strategy", + value_name = "STRATEGY", + default_value_t = DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, + arg_enum, + )] + pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, + /// Limit the memory the database cache can use. #[clap(long = "db-cache", value_name = "MiB", default_value = "1024")] pub database_cache_size: u32, diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index c13bbb3626176..71d258a68982e 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -271,7 +271,9 @@ use remote_externalities::{ }; use sc_chain_spec::ChainSpec; use sc_cli::{ - CliConfiguration, ExecutionStrategy, WasmExecutionMethod, DEFAULT_WASM_EXECUTION_METHOD, + execution_method_from_cli, CliConfiguration, ExecutionStrategy, WasmExecutionMethod, + WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, + DEFAULT_WASM_EXECUTION_METHOD, }; use sc_executor::NativeElseWasmExecutor; use sc_service::{Configuration, NativeExecutionDispatch}; @@ -400,6 +402,17 @@ pub struct SharedParams { )] pub wasm_method: WasmExecutionMethod, + /// The WASM instantiation method to use. + /// + /// Only has an effect when `wasm-execution` is set to `compiled`. + #[clap( + long = "wasm-instantiation-strategy", + value_name = "STRATEGY", + default_value_t = DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, + arg_enum, + )] + pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, + /// The number of 64KB pages to allocate for Wasm execution. Defaults to /// [`sc_service::Configuration.default_heap_pages`]. #[clap(long)] @@ -675,13 +688,12 @@ pub(crate) fn build_executor( shared: &SharedParams, config: &sc_service::Configuration, ) -> NativeElseWasmExecutor { - let wasm_method = shared.wasm_method; let heap_pages = shared.heap_pages.or(config.default_heap_pages); let max_runtime_instances = config.max_runtime_instances; let runtime_cache_size = config.runtime_cache_size; NativeElseWasmExecutor::::new( - wasm_method.into(), + execution_method_from_cli(shared.wasm_method, shared.wasmtime_instantiation_strategy), heap_pages, max_runtime_instances, runtime_cache_size, From 6913e07f07baf8fb2d7f066175b3f39cce969b43 Mon Sep 17 00:00:00 2001 From: kostekIV <27210860+kostekIV@users.noreply.github.com> Date: Thu, 19 May 2022 11:10:49 +0200 Subject: [PATCH 0824/1472] Make fields of `EraRewardPoints` public (#11422) --- frame/staking/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index f17d09b413606..331095774b741 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -369,9 +369,9 @@ pub struct ActiveEraInfo { #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct EraRewardPoints { /// Total number of points. Equals the sum of reward points for each validator. - total: RewardPoint, + pub total: RewardPoint, /// The reward points earned by a given validator. - individual: BTreeMap, + pub individual: BTreeMap, } impl Default for EraRewardPoints { From ededa465214e308d18f12d90515bb49c974c0d7d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 19 May 2022 12:54:40 +0100 Subject: [PATCH 0825/1472] add missing events to elections fallback (#11436) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add missing events to elections fallback * Update frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Bastian Köcher * add test * fix * fmt * Update frame/support/src/storage/types/nmap.rs Co-authored-by: Bastian Köcher --- .../election-provider-multi-phase/src/lib.rs | 56 ++++++++++++++++++- .../election-provider-multi-phase/src/mock.rs | 6 +- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 36d2373c9f623..7d8559050f300 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -948,6 +948,11 @@ pub mod pallet { compute: ElectionCompute::Emergency, }; + Self::deposit_event(Event::SolutionStored { + election_compute: ElectionCompute::Emergency, + prev_ejected: QueuedSolution::::exists(), + }); + >::put(solution); Ok(()) } @@ -1057,6 +1062,11 @@ pub mod pallet { compute: ElectionCompute::Fallback, }; + Self::deposit_event(Event::SolutionStored { + election_compute: ElectionCompute::Fallback, + prev_ejected: QueuedSolution::::exists(), + }); + >::put(solution); Ok(()) } @@ -1792,7 +1802,7 @@ mod tests { use crate::{ mock::{ multi_phase_events, roll_to, AccountId, ExtBuilder, MockWeightInfo, MockedWeightInfo, - MultiPhase, Runtime, SignedMaxSubmissions, System, TargetIndex, Targets, + MultiPhase, Origin, Runtime, SignedMaxSubmissions, System, TargetIndex, Targets, }, Phase, }; @@ -2038,6 +2048,50 @@ mod tests { }) } + #[test] + fn governance_fallback_works() { + ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { + roll_to(25); + assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); + + // Zilch solutions thus far. + assert!(MultiPhase::queued_solution().is_none()); + assert_eq!(MultiPhase::elect().unwrap_err(), ElectionError::Fallback("NoFallback.")); + + // phase is now emergency. + assert_eq!(MultiPhase::current_phase(), Phase::Emergency); + assert!(MultiPhase::queued_solution().is_none()); + + // no single account can trigger this + assert_noop!( + MultiPhase::governance_fallback(Origin::signed(99), None, None), + DispatchError::BadOrigin + ); + + // only root can + assert_ok!(MultiPhase::governance_fallback(Origin::root(), None, None)); + // something is queued now + assert!(MultiPhase::queued_solution().is_some()); + // next election call with fix everything.; + assert!(MultiPhase::elect().is_ok()); + assert_eq!(MultiPhase::current_phase(), Phase::Off); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { election_compute: None }, + Event::SolutionStored { + election_compute: ElectionCompute::Fallback, + prev_ejected: false + }, + Event::ElectionFinalized { election_compute: Some(ElectionCompute::Fallback) } + ] + ); + }) + } + #[test] fn snapshot_too_big_failure_onchain_fallback() { // the `MockStaking` is designed such that if it has too many targets, it simply fails. diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index afce24ff6e3f0..bbc2d6d43beee 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -18,7 +18,9 @@ use super::*; use crate::{self as multi_phase, unsigned::MinerConfig}; use frame_election_provider_support::{ - data_provider, onchain, ElectionDataProvider, NposSolution, SequentialPhragmen, + data_provider, + onchain::{self, UnboundedExecution}, + ElectionDataProvider, NposSolution, SequentialPhragmen, }; pub use frame_support::{assert_noop, assert_ok, pallet_prelude::GetDefault}; use frame_support::{ @@ -379,7 +381,7 @@ impl crate::Config for Runtime { type WeightInfo = (); type BenchmarkingConfig = TestBenchmarkingConfig; type Fallback = MockFallback; - type GovernanceFallback = NoFallback; + type GovernanceFallback = UnboundedExecution; type ForceOrigin = frame_system::EnsureRoot; type MaxElectingVoters = MaxElectingVoters; type MaxElectableTargets = MaxElectableTargets; From 2f28ebfc1e430328e6c117e70eb0220a6e9705e1 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Thu, 19 May 2022 15:39:43 +0200 Subject: [PATCH 0826/1472] Fix renaming artifacts (#11455) --- bin/node/runtime/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index de6f8eeb9f1c0..c1e6dad7bf0d4 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1410,8 +1410,8 @@ impl pallet_gilt::Config for Runtime { } parameter_types! { - pub const ClassDeposit: Balance = 100 * DOLLARS; - pub const InstanceDeposit: Balance = 1 * DOLLARS; + pub const CollectionDeposit: Balance = 100 * DOLLARS; + pub const ItemDeposit: Balance = 1 * DOLLARS; pub const KeyLimit: u32 = 32; pub const ValueLimit: u32 = 256; } @@ -1422,8 +1422,8 @@ impl pallet_uniques::Config for Runtime { type ItemId = u32; type Currency = Balances; type ForceOrigin = frame_system::EnsureRoot; - type CollectionDeposit = ClassDeposit; - type ItemDeposit = InstanceDeposit; + type CollectionDeposit = CollectionDeposit; + type ItemDeposit = ItemDeposit; type MetadataDepositBase = MetadataDepositBase; type AttributeDepositBase = MetadataDepositBase; type DepositPerByte = MetadataDepositPerByte; From 57c420ca1873ebf68ca12d5194c16b1f9100fb8d Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 19 May 2022 12:40:31 -0400 Subject: [PATCH 0827/1472] Add Score to Bags List (#11357) * Add Score to Bags List * fix ordering * make compile * in progress migration * make migration compile * remove old check * remove runtime specific migration * fix warning * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * improve migration * fix * fix merge * fmt * Update migrations.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- bin/node/runtime/src/lib.rs | 2 +- frame/bags-list/fuzzer/src/main.rs | 11 +- frame/bags-list/src/lib.rs | 40 +++++++- frame/bags-list/src/list/mod.rs | 69 +++++++------ frame/bags-list/src/list/tests.rs | 111 ++++++++++++--------- frame/bags-list/src/migrations.rs | 105 +++++++++++++++++-- frame/bags-list/src/tests.rs | 21 ++-- frame/election-provider-support/src/lib.rs | 34 +++++-- frame/staking/src/pallet/impls.rs | 5 +- 9 files changed, 291 insertions(+), 107 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index c1e6dad7bf0d4..c98bb5cc13f85 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1572,7 +1572,7 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - pallet_bags_list::migrations::CheckCounterPrefix, + (), >; /// MMR helper types. diff --git a/frame/bags-list/fuzzer/src/main.rs b/frame/bags-list/fuzzer/src/main.rs index d0586f0372ac4..c17fbe0a2f77f 100644 --- a/frame/bags-list/fuzzer/src/main.rs +++ b/frame/bags-list/fuzzer/src/main.rs @@ -70,13 +70,20 @@ fn main() { }, Action::Update => { let already_contains = BagsList::contains(&id); - BagsList::on_update(&id, vote_weight).unwrap(); if already_contains { + BagsList::on_update(&id, vote_weight).unwrap(); assert!(BagsList::contains(&id)); + } else { + BagsList::on_update(&id, vote_weight).unwrap_err(); } }, Action::Remove => { - BagsList::on_remove(&id).unwrap(); + let already_contains = BagsList::contains(&id); + if already_contains { + BagsList::on_remove(&id).unwrap(); + } else { + BagsList::on_remove(&id).unwrap_err(); + } assert!(!BagsList::contains(&id)); }, } diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 77fe609ad8123..7eee8fdfa23d8 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -82,7 +82,10 @@ macro_rules! log { ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { log::$level!( target: crate::LOG_TARGET, - concat!("[{:?}] 👜", $patter), >::block_number() $(, $values)* + concat!("[{:?}] 👜 [{}]", $patter), + >::block_number(), + as frame_support::traits::PalletInfoAccess>::name() + $(, $values)* ) }; } @@ -189,6 +192,8 @@ pub mod pallet { pub enum Event, I: 'static = ()> { /// Moved an account from one bag to another. Rebagged { who: T::AccountId, from: T::Score, to: T::Score }, + /// Updated the score of some account to the given amount. + ScoreUpdated { who: T::AccountId, new_score: T::Score }, } #[pallet::error] @@ -212,13 +217,16 @@ pub mod pallet { /// /// Anyone can call this function about any potentially dislocated account. /// - /// Will never return an error; if `dislocated` does not exist or doesn't need a rebag, then - /// it is a noop and fees are still collected from `origin`. + /// Will always update the stored score of `dislocated` to the correct score, based on + /// `ScoreProvider`. + /// + /// If `dislocated` does not exists, it returns an error. #[pallet::weight(T::WeightInfo::rebag_non_terminal().max(T::WeightInfo::rebag_terminal()))] pub fn rebag(origin: OriginFor, dislocated: T::AccountId) -> DispatchResult { ensure_signed(origin)?; let current_score = T::ScoreProvider::score(&dislocated); - let _ = Pallet::::do_rebag(&dislocated, current_score); + let _ = Pallet::::do_rebag(&dislocated, current_score) + .map_err::, _>(Into::into)?; Ok(()) } @@ -265,6 +273,7 @@ impl, I: 'static> Pallet { if let Some((from, to)) = maybe_movement { Self::deposit_event(Event::::Rebagged { who: account.clone(), from, to }); }; + Self::deposit_event(Event::::ScoreUpdated { who: account.clone(), new_score }); Ok(maybe_movement) } @@ -302,6 +311,10 @@ impl, I: 'static> SortedListProvider for Pallet List::::insert(id, score) } + fn get_score(id: &T::AccountId) -> Result { + List::::get_score(id) + } + fn on_update(id: &T::AccountId, new_score: T::Score) -> Result<(), ListError> { Pallet::::do_rebag(id, new_score).map(|_| ()) } @@ -359,3 +372,22 @@ impl, I: 'static> SortedListProvider for Pallet } } } + +impl, I: 'static> ScoreProvider for Pallet { + type Score = as SortedListProvider>::Score; + + fn score(id: &T::AccountId) -> T::Score { + Node::::get(id).map(|node| node.score()).unwrap_or_default() + } + + #[cfg(any(feature = "runtime-benchmarks", test))] + fn set_score_of(id: &T::AccountId, new_score: T::Score) { + ListNodes::::mutate(id, |maybe_node| { + if let Some(node) = maybe_node.as_mut() { + node.set_score(new_score) + } else { + panic!("trying to mutate {:?} which does not exists", id); + } + }) + } +} diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 2e65c3be25b24..d95c5de8132ea 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -28,6 +28,7 @@ use crate::Config; use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::ScoreProvider; use frame_support::{ + ensure, traits::{Defensive, Get}, DefaultNoBound, PalletError, }; @@ -38,7 +39,7 @@ use sp_std::{ collections::{btree_map::BTreeMap, btree_set::BTreeSet}, iter, marker::PhantomData, - vec::Vec, + prelude::*, }; #[derive(Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, PalletError)] @@ -227,6 +228,11 @@ impl, I: 'static> List { crate::ListNodes::::contains_key(id) } + /// Get the score of the given node, + pub fn get_score(id: &T::AccountId) -> Result { + Node::::get(id).map(|node| node.score()).ok_or(ListError::NodeNotFound) + } + /// Iterate over all nodes in all bags in the list. /// /// Full iteration can be expensive; it's recommended to limit the number of items with @@ -310,7 +316,7 @@ impl, I: 'static> List { let bag_score = notional_bag_for::(score); let mut bag = Bag::::get_or_make(bag_score); // unchecked insertion is okay; we just got the correct `notional_bag_for`. - bag.insert_unchecked(id.clone()); + bag.insert_unchecked(id.clone(), score); // new inserts are always the tail, so we must write the bag. bag.put(); @@ -381,16 +387,18 @@ impl, I: 'static> List { /// If the node was in the correct bag, no effect. If the node was in the incorrect bag, they /// are moved into the correct bag. /// - /// Returns `Some((old_idx, new_idx))` if the node moved, otherwise `None`. + /// Returns `Some((old_idx, new_idx))` if the node moved, otherwise `None`. In both cases, the + /// node's score is written to the `score` field. Thus, this is not a noop, even if `None`. /// /// This operation is somewhat more efficient than simply calling [`self.remove`] followed by /// [`self.insert`]. However, given large quantities of nodes to move, it may be more efficient /// to call [`self.remove_many`] followed by [`self.insert_many`]. pub(crate) fn update_position_for( - node: Node, + mut node: Node, new_score: T::Score, ) -> Option<(T::Score, T::Score)> { - node.is_misplaced(new_score).then(move || { + node.score = new_score; + if node.is_misplaced(new_score) { let old_bag_upper = node.bag_upper; if !node.is_terminal() { @@ -402,12 +410,9 @@ impl, I: 'static> List { bag.remove_node_unchecked(&node); bag.put(); } else { - crate::log!( - error, - "Node {:?} did not have a bag; ListBags is in an inconsistent state", - node.id, + frame_support::defensive!( + "Node did not have a bag; BagsList is in an inconsistent state" ); - debug_assert!(false, "every node must have an extant bag associated with it"); } // put the node into the appropriate new bag. @@ -418,8 +423,12 @@ impl, I: 'static> List { bag.insert_node_unchecked(node); bag.put(); - (old_bag_upper, new_bag_upper) - }) + Some((old_bag_upper, new_bag_upper)) + } else { + // just write the new score. + node.put(); + None + } } /// Put `heavier_id` to the position directly in front of `lighter_id`. Both ids must be in the @@ -428,8 +437,6 @@ impl, I: 'static> List { lighter_id: &T::AccountId, heavier_id: &T::AccountId, ) -> Result<(), ListError> { - use frame_support::ensure; - let lighter_node = Node::::get(&lighter_id).ok_or(ListError::NodeNotFound)?; let heavier_node = Node::::get(&heavier_id).ok_or(ListError::NodeNotFound)?; @@ -510,7 +517,6 @@ impl, I: 'static> List { /// all bags and nodes are checked per *any* update to `List`. #[cfg(feature = "std")] pub(crate) fn sanity_check() -> Result<(), &'static str> { - use frame_support::ensure; let mut seen_in_list = BTreeSet::new(); ensure!( Self::iter().map(|node| node.id).all(|id| seen_in_list.insert(id)), @@ -523,7 +529,7 @@ impl, I: 'static> List { ensure!(iter_count == stored_count, "iter_count != stored_count"); ensure!(stored_count == nodes_count, "stored_count != nodes_count"); - crate::log!(debug, "count of nodes: {}", stored_count); + crate::log!(trace, "count of nodes: {}", stored_count); let active_bags = { let thresholds = T::BagThresholds::get().iter().copied(); @@ -544,7 +550,7 @@ impl, I: 'static> List { active_bags.clone().fold(0u32, |acc, cur| acc + cur.iter().count() as u32); ensure!(nodes_count == nodes_in_bags_count, "stored_count != nodes_in_bags_count"); - crate::log!(debug, "count of active bags {}", active_bags.count()); + crate::log!(trace, "count of active bags {}", active_bags.count()); // check that all nodes are sane. We check the `ListNodes` storage item directly in case we // have some "stale" nodes that are not in a bag. @@ -667,7 +673,7 @@ impl, I: 'static> Bag { /// /// Storage note: this modifies storage, but only for the nodes. You still need to call /// `self.put()` after use. - fn insert_unchecked(&mut self, id: T::AccountId) { + fn insert_unchecked(&mut self, id: T::AccountId, score: T::Score) { // insert_node will overwrite `prev`, `next` and `bag_upper` to the proper values. As long // as this bag is the correct one, we're good. All calls to this must come after getting the // correct [`notional_bag_for`]. @@ -676,6 +682,7 @@ impl, I: 'static> Bag { prev: None, next: None, bag_upper: Zero::zero(), + score, _phantom: PhantomData, }); } @@ -784,11 +791,6 @@ impl, I: 'static> Bag { Ok(()) } - #[cfg(not(feature = "std"))] - fn sanity_check(&self) -> Result<(), &'static str> { - Ok(()) - } - /// Iterate over the nodes in this bag (public for tests). #[cfg(feature = "std")] #[allow(dead_code)] @@ -809,12 +811,13 @@ impl, I: 'static> Bag { #[scale_info(skip_type_params(T, I))] #[cfg_attr(feature = "std", derive(frame_support::DebugNoBound, Clone, PartialEq))] pub struct Node, I: 'static = ()> { - id: T::AccountId, - prev: Option, - next: Option, - bag_upper: T::Score, + pub(crate) id: T::AccountId, + pub(crate) prev: Option, + pub(crate) next: Option, + pub(crate) bag_upper: T::Score, + pub(crate) score: T::Score, #[codec(skip)] - _phantom: PhantomData, + pub(crate) _phantom: PhantomData, } impl, I: 'static> Node { @@ -877,6 +880,11 @@ impl, I: 'static> Node { &self.id } + /// Get the current vote weight of the node. + pub(crate) fn score(&self) -> T::Score { + self.score + } + /// Get the underlying voter (public fo tests). #[cfg(feature = "std")] #[allow(dead_code)] @@ -884,6 +892,11 @@ impl, I: 'static> Node { &self.id } + #[cfg(any(feature = "runtime-benchmarks", test))] + pub fn set_score(&mut self, s: T::Score) { + self.score = s + } + /// The bag this nodes belongs to (public for benchmarks). #[cfg(feature = "runtime-benchmarks")] #[allow(dead_code)] diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index 40a174b35a5d3..9bdd54289fd88 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -21,20 +21,20 @@ use crate::{ ListBags, ListNodes, }; use frame_election_provider_support::{SortedListProvider, VoteWeight}; -use frame_support::{assert_noop, assert_ok, assert_storage_noop}; +use frame_support::{assert_ok, assert_storage_noop}; + +fn node( + id: AccountId, + prev: Option, + next: Option, + bag_upper: VoteWeight, +) -> Node { + Node:: { id, prev, next, bag_upper, score: bag_upper, _phantom: PhantomData } +} #[test] fn basic_setup_works() { ExtBuilder::default().build_and_execute(|| { - // syntactic sugar to create a raw node - let node = |id, prev, next, bag_upper| Node:: { - id, - prev, - next, - bag_upper, - _phantom: PhantomData, - }; - assert_eq!(ListNodes::::count(), 4); assert_eq!(ListNodes::::iter().count(), 4); assert_eq!(ListBags::::iter().count(), 2); @@ -83,10 +83,10 @@ fn notional_bag_for_works() { let max_explicit_threshold = *::BagThresholds::get().last().unwrap(); assert_eq!(max_explicit_threshold, 10_000); - // if the max explicit threshold is less than T::Value::max_value(), + // if the max explicit threshold is less than T::Score::max_value(), assert!(VoteWeight::MAX > max_explicit_threshold); - // then anything above it will belong to the T::Value::max_value() bag. + // then anything above it will belong to the T::Score::max_value() bag. assert_eq!(notional_bag_for::(max_explicit_threshold), max_explicit_threshold); assert_eq!(notional_bag_for::(max_explicit_threshold + 1), VoteWeight::MAX); } @@ -154,6 +154,8 @@ fn migrate_works() { } mod list { + use frame_support::assert_noop; + use super::*; #[test] @@ -175,7 +177,7 @@ mod list { ] ); - // when adding an id that has a higher weight than pre-existing ids in the bag + // when adding an id that has a higher score than pre-existing ids in the bag assert_ok!(List::::insert(7, 10)); // then @@ -246,10 +248,7 @@ mod list { assert!(get_list_as_ids().contains(&3)); // then - assert_storage_noop!(assert_eq!( - List::::insert(3, 20).unwrap_err(), - ListError::Duplicate - )); + assert_noop!(List::::insert(3, 20), ListError::Duplicate); }); } @@ -317,37 +316,36 @@ mod list { ExtBuilder::default().build_and_execute(|| { // given a correctly placed account 1 at bag 10. let node = Node::::get(&1).unwrap(); + assert_eq!(node.score, 10); assert!(!node.is_misplaced(10)); - // .. it is invalid with weight 20 + // .. it is invalid with score 20 assert!(node.is_misplaced(20)); // move it to bag 20. - assert_eq!(List::::update_position_for(node, 20), Some((10, 20))); + assert_eq!(List::::update_position_for(node.clone(), 20), Some((10, 20))); + assert_eq!(Node::::get(&1).unwrap().score, 20); assert_eq!(List::::get_bags(), vec![(20, vec![1]), (1_000, vec![2, 3, 4])]); - // get the new updated node; try and update the position with no change in weight. + // get the new updated node; try and update the position with no change in score. let node = Node::::get(&1).unwrap(); assert_storage_noop!(assert_eq!( List::::update_position_for(node.clone(), 20), None )); - // then move it to bag 1_000 by giving it weight 500. + // then move it to bag 1_000 by giving it score 500. assert_eq!(List::::update_position_for(node.clone(), 500), Some((20, 1_000))); + assert_eq!(Node::::get(&1).unwrap().score, 500); assert_eq!(List::::get_bags(), vec![(1_000, vec![2, 3, 4, 1])]); // moving within that bag again is a noop let node = Node::::get(&1).unwrap(); - assert_storage_noop!(assert_eq!( - List::::update_position_for(node.clone(), 750), - None, - )); - assert_storage_noop!(assert_eq!( - List::::update_position_for(node, 1_000), - None, - )); + assert_eq!(List::::update_position_for(node.clone(), 750), None); + assert_eq!(Node::::get(&1).unwrap().score, 750); + assert_eq!(List::::update_position_for(node.clone(), 1_000), None,); + assert_eq!(Node::::get(&1).unwrap().score, 1_000); }); } @@ -359,7 +357,7 @@ mod list { // make sure there are no duplicates. ExtBuilder::default().build_and_execute_no_post_check(|| { - Bag::::get(10).unwrap().insert_unchecked(2); + Bag::::get(10).unwrap().insert_unchecked(2, 10); assert_eq!(List::::sanity_check(), Err("duplicate identified")); }); @@ -397,6 +395,7 @@ mod list { prev: None, next: None, bag_upper: 15, + score: 15, _phantom: PhantomData, }; let node_11_no_bag = Node:: { @@ -404,6 +403,7 @@ mod list { prev: None, next: None, bag_upper: 15, + score: 15, _phantom: PhantomData, }; @@ -435,6 +435,7 @@ mod list { prev: Some(1), next: Some(2), bag_upper: 1_000, + score: 1_000, _phantom: PhantomData, }; assert!(!crate::ListNodes::::contains_key(42)); @@ -464,6 +465,7 @@ mod list { prev: Some(4), next: None, bag_upper: 1_000, + score: 1_000, _phantom: PhantomData, }; assert!(!crate::ListNodes::::contains_key(42)); @@ -493,6 +495,7 @@ mod list { prev: None, next: Some(2), bag_upper: 1_000, + score: 1_000, _phantom: PhantomData, }; assert!(!crate::ListNodes::::contains_key(42)); @@ -522,6 +525,7 @@ mod list { prev: Some(42), next: Some(42), bag_upper: 1_000, + score: 1_000, _phantom: PhantomData, }; assert!(!crate::ListNodes::::contains_key(42)); @@ -586,6 +590,7 @@ mod bags { prev: None, next: None, bag_upper, + score: bag_upper, _phantom: PhantomData, }; @@ -596,7 +601,14 @@ mod bags { assert_eq!( ListNodes::::get(&42).unwrap(), - Node { bag_upper: 10, prev: Some(1), next: None, id: 42, _phantom: PhantomData } + Node { + bag_upper: 10, + score: 5, + prev: Some(1), + next: None, + id: 42, + _phantom: PhantomData + } ); }); } @@ -609,6 +621,7 @@ mod bags { prev: None, next: None, bag_upper, + score: bag_upper, _phantom: PhantomData, }; @@ -636,6 +649,7 @@ mod bags { prev: Some(21), next: Some(101), bag_upper: 20, + score: 20, _phantom: PhantomData, }; bag_20.insert_node_unchecked(node_61); @@ -649,6 +663,7 @@ mod bags { prev: Some(62), next: None, bag_upper: 20, + score: 20, _phantom: PhantomData, } ); @@ -665,13 +680,6 @@ mod bags { // Document improper ways `insert_node` may be getting used. #[test] fn insert_node_bad_paths_documented() { - let node = |id, prev, next, bag_upper| Node:: { - id, - prev, - next, - bag_upper, - _phantom: PhantomData, - }; ExtBuilder::default().build_and_execute_no_post_check(|| { // when inserting a node with both prev & next pointing at an account in an incorrect // bag. @@ -684,7 +692,14 @@ mod bags { // and when the node is re-fetched all the info is correct assert_eq!( Node::::get(&42).unwrap(), - node(42, Some(4), None, bag_1000.bag_upper) + Node:: { + id: 42, + prev: Some(4), + next: None, + bag_upper: bag_1000.bag_upper, + score: 500, + _phantom: PhantomData + } ); }); @@ -720,7 +735,14 @@ mod bags { // and the re-fetched node has bad pointers assert_eq!( Node::::get(&2).unwrap(), - node(2, Some(4), None, bag_1000.bag_upper) + Node:: { + id: 2, + prev: Some(4), + next: None, + bag_upper: bag_1000.bag_upper, + score: 0, + _phantom: PhantomData + }, ); // ^^^ despite being the bags head, it has a prev @@ -739,14 +761,6 @@ mod bags { )] fn insert_node_duplicate_tail_panics_with_debug_assert() { ExtBuilder::default().build_and_execute(|| { - let node = |id, prev, next, bag_upper| Node:: { - id, - prev, - next, - bag_upper, - _phantom: PhantomData, - }; - // given assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])],); let mut bag_1000 = Bag::::get(1_000).unwrap(); @@ -877,6 +891,7 @@ mod bags { prev: None, next: Some(3), bag_upper: 10, // should be 1_000 + score: 10, _phantom: PhantomData, }; let mut bag_1000 = Bag::::get(1_000).unwrap(); diff --git a/frame/bags-list/src/migrations.rs b/frame/bags-list/src/migrations.rs index f8041327f10be..a77beb23bd667 100644 --- a/frame/bags-list/src/migrations.rs +++ b/frame/bags-list/src/migrations.rs @@ -17,34 +17,125 @@ //! The migrations of this pallet. +use codec::{Decode, Encode}; +use core::marker::PhantomData; +use frame_election_provider_support::ScoreProvider; use frame_support::traits::OnRuntimeUpgrade; +use sp_runtime::traits::Zero; + +#[cfg(feature = "try-runtime")] +use frame_support::ensure; /// A struct that does not migration, but only checks that the counter prefix exists and is correct. -pub struct CheckCounterPrefix(sp_std::marker::PhantomData); -impl OnRuntimeUpgrade for CheckCounterPrefix { +pub struct CheckCounterPrefix, I: 'static>(sp_std::marker::PhantomData<(T, I)>); +impl, I: 'static> OnRuntimeUpgrade for CheckCounterPrefix { fn on_runtime_upgrade() -> frame_support::weights::Weight { - 0 + frame_support::weights::Weight::zero() } #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result<(), &'static str> { - use frame_support::ensure; // The old explicit storage item. #[frame_support::storage_alias] - type CounterForListNodes = StorageValue, u32>; + type CounterForListNodes, I: 'static> = + StorageValue, u32>; // ensure that a value exists in the counter struct. ensure!( - crate::ListNodes::::count() == CounterForListNodes::::get().unwrap(), + crate::ListNodes::::count() == CounterForListNodes::::get().unwrap(), "wrong list node counter" ); crate::log!( info, "checked bags-list prefix to be correct and have {} nodes", - crate::ListNodes::::count() + crate::ListNodes::::count() ); Ok(()) } } + +mod old { + use super::*; + use frame_support::pallet_prelude::*; + + #[derive(Encode, Decode)] + pub struct PreScoreNode, I: 'static = ()> { + pub id: T::AccountId, + pub prev: Option, + pub next: Option, + pub bag_upper: T::Score, + #[codec(skip)] + pub _phantom: PhantomData, + } + + #[frame_support::storage_alias] + pub type ListNodes, I: 'static> = StorageMap< + crate::Pallet, + Twox64Concat, + ::AccountId, + PreScoreNode, + >; + + #[frame_support::storage_alias] + pub type CounterForListNodes, I: 'static> = + StorageValue, u32, ValueQuery>; + + #[frame_support::storage_alias] + pub type TempStorage, I: 'static> = + StorageValue, u32, ValueQuery>; +} + +/// A struct that migrates all bags lists to contain a score value. +pub struct AddScore, I: 'static = ()>(sp_std::marker::PhantomData<(T, I)>); +impl, I: 'static> OnRuntimeUpgrade for AddScore { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + // The list node data should be corrupt at this point, so this is zero. + ensure!(crate::ListNodes::::iter().count() == 0, "list node data is not corrupt"); + // We can use the helper `old::ListNode` to get the existing data. + let iter_node_count: u32 = old::ListNodes::::iter().count() as u32; + let tracked_node_count: u32 = old::CounterForListNodes::::get(); + crate::log!(info, "number of nodes before: {:?} {:?}", iter_node_count, tracked_node_count); + ensure!(iter_node_count == tracked_node_count, "Node count is wrong."); + old::TempStorage::::put(iter_node_count); + Ok(()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + for (_key, node) in old::ListNodes::::iter() { + let score = T::ScoreProvider::score(&node.id); + + let new_node = crate::Node { + id: node.id.clone(), + prev: node.prev, + next: node.next, + bag_upper: node.bag_upper, + score, + _phantom: node._phantom, + }; + + crate::ListNodes::::insert(node.id, new_node); + } + + return frame_support::weights::Weight::MAX + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + let node_count_before = old::TempStorage::::take(); + // Now, the list node data is not corrupt anymore. + let iter_node_count_after: u32 = crate::ListNodes::::iter().count() as u32; + let tracked_node_count_after: u32 = crate::ListNodes::::count(); + crate::log!( + info, + "number of nodes after: {:?} {:?}", + iter_node_count_after, + tracked_node_count_after, + ); + ensure!(iter_node_count_after == node_count_before, "Not all nodes were migrated."); + ensure!(tracked_node_count_after == iter_node_count_after, "Node count is wrong."); + Ok(()) + } +} diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs index c63ab26d59a67..01c1642f882c1 100644 --- a/frame/bags-list/src/tests.rs +++ b/frame/bags-list/src/tests.rs @@ -35,8 +35,10 @@ mod pallet { ); // when increasing score to the level of non-existent bag + assert_eq!(List::::get_score(&42).unwrap(), 20); StakingMock::set_score_of(&42, 2_000); assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + assert_eq!(List::::get_score(&42).unwrap(), 2_000); // then a new bag is created and the id moves into it assert_eq!( @@ -53,6 +55,8 @@ mod pallet { List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![42])] ); + // but the score is updated + assert_eq!(List::::get_score(&42).unwrap(), 1_001); // when reducing score to the level of a non-existent bag StakingMock::set_score_of(&42, 30); @@ -63,6 +67,7 @@ mod pallet { List::::get_bags(), vec![(10, vec![1]), (30, vec![42]), (1_000, vec![2, 3, 4])] ); + assert_eq!(List::::get_score(&42).unwrap(), 30); // when increasing score to the level of a pre-existing bag StakingMock::set_score_of(&42, 500); @@ -73,6 +78,7 @@ mod pallet { List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 42])] ); + assert_eq!(List::::get_score(&42).unwrap(), 500); }); } @@ -145,21 +151,20 @@ mod pallet { } #[test] - fn wrong_rebag_is_noop() { + fn wrong_rebag_errs() { ExtBuilder::default().build_and_execute(|| { let node_3 = list::Node::::get(&3).unwrap(); - // when account 3 is _not_ misplaced with weight 500 + // when account 3 is _not_ misplaced with score 500 NextVoteWeight::set(500); assert!(!node_3.is_misplaced(500)); - // then calling rebag on account 3 with weight 500 is a noop + // then calling rebag on account 3 with score 500 is a noop assert_storage_noop!(assert_eq!(BagsList::rebag(Origin::signed(0), 3), Ok(()))); // when account 42 is not in the list assert!(!BagsList::contains(&42)); - - // then rebag-ing account 42 is a noop - assert_storage_noop!(assert_eq!(BagsList::rebag(Origin::signed(0), 42), Ok(()))); + // then rebag-ing account 42 is an error + assert_storage_noop!(assert!(matches!(BagsList::rebag(Origin::signed(0), 42), Err(_)))); }); } @@ -182,7 +187,6 @@ mod pallet { #[test] fn empty_threshold_works() { BagThresholds::set(Default::default()); // which is the same as passing `()` to `Get<_>`. - ExtBuilder::default().build_and_execute(|| { // everyone in the same bag. assert_eq!(List::::get_bags(), vec![(VoteWeight::MAX, vec![1, 2, 3, 4])]); @@ -196,8 +200,7 @@ mod pallet { ); // any rebag is noop. - assert_storage_noop!(assert!(BagsList::rebag(Origin::signed(0), 1).is_ok())); - assert_storage_noop!(assert!(BagsList::rebag(Origin::signed(0), 10).is_ok())); + assert_storage_noop!(assert_eq!(BagsList::rebag(Origin::signed(0), 1), Ok(()))); }) } diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index af366d5b8f919..27bf7a37f9622 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -168,15 +168,12 @@ pub mod onchain; pub mod traits; -#[cfg(feature = "std")] -use codec::{Decode, Encode}; -use frame_support::{weights::Weight, BoundedVec, RuntimeDebug}; use sp_runtime::traits::{Bounded, Saturating, Zero}; use sp_std::{fmt::Debug, prelude::*}; /// Re-export the solution generation macro. pub use frame_election_provider_solution_type::generate_solution_type; -pub use frame_support::traits::Get; +pub use frame_support::{traits::Get, weights::Weight, BoundedVec, RuntimeDebug}; /// Re-export some type as they are used in the interface. pub use sp_arithmetic::PerThing; pub use sp_npos_elections::{ @@ -223,7 +220,7 @@ impl __OrInvalidIndex for Option { /// making it fast to repeatedly encode into a `SolutionOf`. This property turns out /// to be important when trimming for solution length. #[derive(RuntimeDebug, Clone, Default)] -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Encode, Decode))] +#[cfg_attr(feature = "std", derive(PartialEq, Eq, codec::Encode, codec::Decode))] pub struct IndexAssignment { /// Index of the voter among the voters list. pub who: VoterIndex, @@ -467,6 +464,29 @@ pub trait SortedListProvider { /// Returns `Ok(())` iff it successfully updates an item, an `Err(_)` otherwise. fn on_update(id: &AccountId, score: Self::Score) -> Result<(), Self::Error>; + /// Get the score of `id`. + fn get_score(id: &AccountId) -> Result; + + /// Same as `on_update`, but incorporate some increased score. + fn on_increase(id: &AccountId, additional: Self::Score) -> Result<(), Self::Error> { + let old_score = Self::get_score(id)?; + let new_score = old_score.saturating_add(additional); + Self::on_update(id, new_score) + } + + /// Same as `on_update`, but incorporate some decreased score. + /// + /// If the new score of the item is `Zero`, it is removed. + fn on_decrease(id: &AccountId, decreased: Self::Score) -> Result<(), Self::Error> { + let old_score = Self::get_score(id)?; + let new_score = old_score.saturating_sub(decreased); + if new_score.is_zero() { + Self::on_remove(id) + } else { + Self::on_update(id, new_score) + } + } + /// Hook for removing am id from the list. /// /// Returns `Ok(())` iff it successfully removes an item, an `Err(_)` otherwise. @@ -504,7 +524,7 @@ pub trait SortedListProvider { } } -/// Something that can provide the `VoteWeight` of an account. Similar to [`ElectionProvider`] and +/// Something that can provide the `Score` of an account. Similar to [`ElectionProvider`] and /// [`ElectionDataProvider`], this should typically be implementing by whoever is supposed to *use* /// `SortedListProvider`. pub trait ScoreProvider { @@ -513,7 +533,7 @@ pub trait ScoreProvider { /// Get the current `Score` of `who`. fn score(who: &AccountId) -> Self::Score; - /// For tests and benchmarks, set the `VoteWeight`. + /// For tests and benchmarks, set the `score`. #[cfg(any(feature = "runtime-benchmarks", test))] fn set_score_of(_: &AccountId, _: Self::Score) {} } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 34d7a176670f2..4de1ea36cb591 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1343,7 +1343,10 @@ impl SortedListProvider for UseNominatorsAndValidatorsM // nothing to do on insert. Ok(()) } - fn on_update(_: &T::AccountId, _weight: VoteWeight) -> Result<(), Self::Error> { + fn get_score(id: &T::AccountId) -> Result { + Ok(Pallet::::weight_of(id)) + } + fn on_update(_: &T::AccountId, _weight: Self::Score) -> Result<(), Self::Error> { // nothing to do on update. Ok(()) } From 77889d108c0ed17bd3c319d640249e68260bf15a Mon Sep 17 00:00:00 2001 From: Alexander Gryaznov Date: Fri, 20 May 2022 14:20:41 +0300 Subject: [PATCH 0828/1472] Stabilize ecdsa_ functions (#11486) --- frame/contracts/fixtures/ecdsa_recover.wat | 2 +- frame/contracts/src/benchmarking/mod.rs | 4 ++-- frame/contracts/src/tests.rs | 1 - frame/contracts/src/wasm/mod.rs | 7 ++----- frame/contracts/src/wasm/runtime.rs | 10 ++-------- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/frame/contracts/fixtures/ecdsa_recover.wat b/frame/contracts/fixtures/ecdsa_recover.wat index c196e88094d2c..d694b3215e86b 100644 --- a/frame/contracts/fixtures/ecdsa_recover.wat +++ b/frame/contracts/fixtures/ecdsa_recover.wat @@ -4,7 +4,7 @@ ;; 3) Validates that result is Success ;; 4) Returns recovered compressed public key (module - (import "__unstable__" "seal_ecdsa_recover" (func $seal_ecdsa_recover (param i32 i32 i32) (result i32))) + (import "seal0" "seal_ecdsa_recover" (func $seal_ecdsa_recover (param i32 i32 i32) (result i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "env" "memory" (memory 1 1)) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 57a330ae275f2..4241456389ec7 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1949,7 +1949,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "seal_ecdsa_recover", params: vec![ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -1992,7 +1992,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "seal_ecdsa_to_eth_address", params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 2125fe24d1a07..5a6a29786c629 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -2277,7 +2277,6 @@ fn gas_estimation_call_runtime() { } #[test] -#[cfg(feature = "unstable-interface")] fn ecdsa_recover() { let (wasm, code_hash) = compile_module::("ecdsa_recover").unwrap(); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 8764bf3690b82..c385b5d2f7cc2 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -1059,7 +1059,6 @@ mod tests { ); } - #[cfg(feature = "unstable-interface")] const CODE_ECDSA_RECOVER: &str = r#" (module ;; seal_ecdsa_recover( @@ -1067,7 +1066,7 @@ mod tests { ;; message_hash_ptr: u32, ;; output_ptr: u32 ;; ) -> u32 - (import "__unstable__" "seal_ecdsa_recover" (func $seal_ecdsa_recover (param i32 i32 i32) (result i32))) + (import "seal0" "seal_ecdsa_recover" (func $seal_ecdsa_recover (param i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) (func (export "call") (drop @@ -1097,7 +1096,6 @@ mod tests { "#; #[test] - #[cfg(feature = "unstable-interface")] fn contract_ecdsa_recover() { let mut mock_ext = MockExt::default(); assert_ok!(execute(&CODE_ECDSA_RECOVER, vec![], &mut mock_ext)); @@ -1105,13 +1103,12 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn contract_ecdsa_to_eth_address() { /// calls `seal_ecdsa_to_eth_address` for the contstant and ensures the result equals the /// expected one. const CODE_ECDSA_TO_ETH_ADDRESS: &str = r#" (module - (import "__unstable__" "seal_ecdsa_to_eth_address" (func $seal_ecdsa_to_eth_address (param i32 i32) (result i32))) + (import "seal0" "seal_ecdsa_to_eth_address" (func $seal_ecdsa_to_eth_address (param i32 i32) (result i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 11dfc77616e69..850794fc9b09e 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -74,7 +74,6 @@ pub enum ReturnCode { /// ECDSA pubkey recovery failed (most probably wrong recovery id or signature), or /// ECDSA compressed pubkey conversion into Ethereum address failed (most probably /// wrong pubkey provided). - #[cfg(feature = "unstable-interface")] EcdsaRecoverFailed = 11, } @@ -214,7 +213,6 @@ pub enum RuntimeCosts { /// Weight of calling `seal_hash_blake2_128` for the given input size. HashBlake128(u32), /// Weight of calling `seal_ecdsa_recover`. - #[cfg(feature = "unstable-interface")] EcdsaRecovery, /// Weight charged by a chain extension through `seal_call_chain_extension`. ChainExtension(u64), @@ -224,7 +222,6 @@ pub enum RuntimeCosts { /// Weight of calling `seal_set_code_hash` SetCodeHash, /// Weight of calling `ecdsa_to_eth_address` - #[cfg(feature = "unstable-interface")] EcdsaToEthAddress, } @@ -299,14 +296,11 @@ impl RuntimeCosts { HashBlake128(len) => s .hash_blake2_128 .saturating_add(s.hash_blake2_128_per_byte.saturating_mul(len.into())), - #[cfg(feature = "unstable-interface")] EcdsaRecovery => s.ecdsa_recover, ChainExtension(amount) => amount, - #[cfg(feature = "unstable-interface")] CallRuntime(weight) => weight, SetCodeHash => s.set_code_hash, - #[cfg(feature = "unstable-interface")] EcdsaToEthAddress => s.ecdsa_to_eth_address, }; RuntimeToken { @@ -1993,7 +1987,7 @@ define_env!(Env, , // # Errors // // `ReturnCode::EcdsaRecoverFailed` - [__unstable__] seal_ecdsa_recover(ctx, signature_ptr: u32, message_hash_ptr: u32, output_ptr: u32) -> ReturnCode => { + [seal0] seal_ecdsa_recover(ctx, signature_ptr: u32, message_hash_ptr: u32, output_ptr: u32) -> ReturnCode => { ctx.charge_gas(RuntimeCosts::EcdsaRecovery)?; let mut signature: [u8; 65] = [0; 65]; @@ -2069,7 +2063,7 @@ define_env!(Env, , // # Errors // // `ReturnCode::EcdsaRecoverFailed` - [__unstable__] seal_ecdsa_to_eth_address(ctx, key_ptr: u32, out_ptr: u32) -> ReturnCode => { + [seal0] seal_ecdsa_to_eth_address(ctx, key_ptr: u32, out_ptr: u32) -> ReturnCode => { ctx.charge_gas(RuntimeCosts::EcdsaToEthAddress)?; let mut compressed_key: [u8; 33] = [0;33]; ctx.read_sandbox_memory_into_buf(key_ptr, &mut compressed_key)?; From b4cc5cc85661d335874edd937551dbb383323e39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 May 2022 15:48:27 +0300 Subject: [PATCH 0829/1472] Bump actions/checkout from 2 to 3 (#11463) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [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/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout 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> --- .github/workflows/check-labels.yml | 2 +- .github/workflows/md-link-check.yml | 2 +- .github/workflows/monthly-tag.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check-labels.yml b/.github/workflows/check-labels.yml index 74fdd9b2d8188..de204ce9d3776 100644 --- a/.github/workflows/check-labels.yml +++ b/.github/workflows/check-labels.yml @@ -8,7 +8,7 @@ jobs: check-labels: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.ref }} diff --git a/.github/workflows/md-link-check.yml b/.github/workflows/md-link-check.yml index 868569911d471..0ad56f9e1b278 100644 --- a/.github/workflows/md-link-check.yml +++ b/.github/workflows/md-link-check.yml @@ -12,7 +12,7 @@ jobs: markdown-link-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: gaurav-nelson/github-action-markdown-link-check@7481451f70251762f149d69596e3e276ebf2b236 with: use-quiet-mode: 'yes' diff --git a/.github/workflows/monthly-tag.yml b/.github/workflows/monthly-tag.yml index 9fed865396013..ade8bd4717c39 100644 --- a/.github/workflows/monthly-tag.yml +++ b/.github/workflows/monthly-tag.yml @@ -16,7 +16,7 @@ jobs: echo "::set-output name=new::$(date +'monthly-%Y-%m')" echo "::set-output name=old::$(date -d'1 month ago' +'monthly-%Y-%m')" - name: Checkout branch "master" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: 'master' fetch-depth: 0 From c96100c7085499710c0d66184e2fa64a3768f088 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 May 2022 16:22:01 +0200 Subject: [PATCH 0830/1472] Bump gaurav-nelson/github-action-markdown-link-check from 1.0.9 to 1.0.14 (#11464) * Bump gaurav-nelson/github-action-markdown-link-check Bumps [gaurav-nelson/github-action-markdown-link-check](https://github.com/gaurav-nelson/github-action-markdown-link-check) from 1.0.9 to 1.0.14. - [Release notes](https://github.com/gaurav-nelson/github-action-markdown-link-check/releases) - [Commits](https://github.com/gaurav-nelson/github-action-markdown-link-check/compare/7481451f70251762f149d69596e3e276ebf2b236...58f84fd654812d0d8da4e4d4a559eda087daf8ce) --- updated-dependencies: - dependency-name: gaurav-nelson/github-action-markdown-link-check dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update .github/workflows/md-link-check.yml Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Denis Pisarev --- .github/workflows/md-link-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/md-link-check.yml b/.github/workflows/md-link-check.yml index 0ad56f9e1b278..4b6b9166be2df 100644 --- a/.github/workflows/md-link-check.yml +++ b/.github/workflows/md-link-check.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: gaurav-nelson/github-action-markdown-link-check@7481451f70251762f149d69596e3e276ebf2b236 + - uses: gaurav-nelson/github-action-markdown-link-check@9710f0fec812ce0a3b98bef4c9d842fc1f39d976 # v1.0.13 with: use-quiet-mode: 'yes' config-file: '.github/workflows/mlc_config.json' From 934fbfdd29da7fa2acbad6000e1d61f6cb195f1f Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Fri, 20 May 2022 22:16:35 +0300 Subject: [PATCH 0831/1472] RPC: Mark storage methods as `blocking` (#11459) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * client/api: Make `storage_keys` blocking Signed-off-by: Alexandru Vasile * client/api: Ensure `state_*` RPC methods are blocking Signed-off-by: Alexandru Vasile * client/rpc: Ensure `childstate_*` RPC methods are blocking Signed-off-by: Alexandru Vasile * client/rpc: `ChainApi` make RPC methods sync Signed-off-by: Alexandru Vasile * Remove unused async-traits Signed-off-by: Alexandru Vasile * client/rpc-api: Make chain RPC methods blocking Signed-off-by: Alexandru Vasile * Update client/rpc/src/state/state_full.rs Co-authored-by: Bastian Köcher * Add `blocking` to `state_getKeysPaged` RPC call Signed-off-by: Alexandru Vasile * Fix build and warning Signed-off-by: Alexandru Vasile * Remove `async_trait` tidyup Signed-off-by: Alexandru Vasile Co-authored-by: Bastian Köcher --- client/rpc-api/src/chain/mod.rs | 12 +-- client/rpc-api/src/child_state/mod.rs | 28 +++--- client/rpc-api/src/state/mod.rs | 60 +++++------- client/rpc/src/chain/chain_full.rs | 7 +- client/rpc/src/chain/mod.rs | 19 ++-- client/rpc/src/state/mod.rs | 136 +++++++++++--------------- client/rpc/src/state/state_full.rs | 65 ++++++------ client/rpc/src/state/tests.rs | 60 ++++-------- 8 files changed, 164 insertions(+), 223 deletions(-) diff --git a/client/rpc-api/src/chain/mod.rs b/client/rpc-api/src/chain/mod.rs index f5f9524264e34..c7cc97463983d 100644 --- a/client/rpc-api/src/chain/mod.rs +++ b/client/rpc-api/src/chain/mod.rs @@ -26,24 +26,24 @@ pub mod error; #[rpc(client, server)] pub trait ChainApi { /// Get header. - #[method(name = "chain_getHeader")] - async fn header(&self, hash: Option) -> RpcResult>; + #[method(name = "chain_getHeader", blocking)] + fn header(&self, hash: Option) -> RpcResult>; /// Get header and body of a relay chain block. - #[method(name = "chain_getBlock")] - async fn block(&self, hash: Option) -> RpcResult>; + #[method(name = "chain_getBlock", blocking)] + fn block(&self, hash: Option) -> RpcResult>; /// Get hash of the n-th block in the canon chain. /// /// By default returns latest block hash. - #[method(name = "chain_getBlockHash", aliases = ["chain_getHead"])] + #[method(name = "chain_getBlockHash", aliases = ["chain_getHead"], blocking)] fn block_hash( &self, hash: Option>, ) -> RpcResult>>; /// Get hash of the last finalized block in the canon chain. - #[method(name = "chain_getFinalizedHead", aliases = ["chain_getFinalisedHead"])] + #[method(name = "chain_getFinalizedHead", aliases = ["chain_getFinalisedHead"], blocking)] fn finalized_head(&self) -> RpcResult; /// All head subscription. diff --git a/client/rpc-api/src/child_state/mod.rs b/client/rpc-api/src/child_state/mod.rs index a15b1a0e7ee05..be279a97463b0 100644 --- a/client/rpc-api/src/child_state/mod.rs +++ b/client/rpc-api/src/child_state/mod.rs @@ -28,9 +28,9 @@ use sp_core::storage::{PrefixedStorageKey, StorageData, StorageKey}; #[rpc(client, server)] pub trait ChildStateApi { /// Returns the keys with prefix from a child storage, leave empty to get all the keys - #[method(name = "childstate_getKeys")] + #[method(name = "childstate_getKeys", blocking)] #[deprecated(since = "2.0.0", note = "Please use `getKeysPaged` with proper paging support")] - async fn storage_keys( + fn storage_keys( &self, child_storage_key: PrefixedStorageKey, prefix: StorageKey, @@ -40,8 +40,8 @@ pub trait ChildStateApi { /// Returns the keys with prefix from a child storage with pagination support. /// Up to `count` keys will be returned. /// If `start_key` is passed, return next keys in storage in lexicographic order. - #[method(name = "childstate_getKeysPaged", aliases = ["childstate_getKeysPagedAt"])] - async fn storage_keys_paged( + #[method(name = "childstate_getKeysPaged", aliases = ["childstate_getKeysPagedAt"], blocking)] + fn storage_keys_paged( &self, child_storage_key: PrefixedStorageKey, prefix: Option, @@ -51,8 +51,8 @@ pub trait ChildStateApi { ) -> RpcResult>; /// Returns a child storage entry at a specific block's state. - #[method(name = "childstate_getStorage")] - async fn storage( + #[method(name = "childstate_getStorage", blocking)] + fn storage( &self, child_storage_key: PrefixedStorageKey, key: StorageKey, @@ -60,8 +60,8 @@ pub trait ChildStateApi { ) -> RpcResult>; /// Returns child storage entries for multiple keys at a specific block's state. - #[method(name = "childstate_getStorageEntries")] - async fn storage_entries( + #[method(name = "childstate_getStorageEntries", blocking)] + fn storage_entries( &self, child_storage_key: PrefixedStorageKey, keys: Vec, @@ -69,8 +69,8 @@ pub trait ChildStateApi { ) -> RpcResult>>; /// Returns the hash of a child storage entry at a block's state. - #[method(name = "childstate_getStorageHash")] - async fn storage_hash( + #[method(name = "childstate_getStorageHash", blocking)] + fn storage_hash( &self, child_storage_key: PrefixedStorageKey, key: StorageKey, @@ -78,8 +78,8 @@ pub trait ChildStateApi { ) -> RpcResult>; /// Returns the size of a child storage entry at a block's state. - #[method(name = "childstate_getStorageSize")] - async fn storage_size( + #[method(name = "childstate_getStorageSize", blocking)] + fn storage_size( &self, child_storage_key: PrefixedStorageKey, key: StorageKey, @@ -87,8 +87,8 @@ pub trait ChildStateApi { ) -> RpcResult>; /// Returns proof of storage for child key entries at a specific block's state. - #[method(name = "state_getChildReadProof")] - async fn read_child_proof( + #[method(name = "state_getChildReadProof", blocking)] + fn read_child_proof( &self, child_storage_key: PrefixedStorageKey, keys: Vec, diff --git a/client/rpc-api/src/state/mod.rs b/client/rpc-api/src/state/mod.rs index fba023e830262..54bf21674a8bd 100644 --- a/client/rpc-api/src/state/mod.rs +++ b/client/rpc-api/src/state/mod.rs @@ -34,21 +34,17 @@ pub use self::helpers::ReadProof; #[rpc(client, server)] pub trait StateApi { /// Call a contract at a block's state. - #[method(name = "state_call", aliases = ["state_callAt"])] - async fn call(&self, name: String, bytes: Bytes, hash: Option) -> RpcResult; + #[method(name = "state_call", aliases = ["state_callAt"], blocking)] + fn call(&self, name: String, bytes: Bytes, hash: Option) -> RpcResult; /// Returns the keys with prefix, leave empty to get all the keys. - #[method(name = "state_getKeys")] + #[method(name = "state_getKeys", blocking)] #[deprecated(since = "2.0.0", note = "Please use `getKeysPaged` with proper paging support")] - async fn storage_keys( - &self, - prefix: StorageKey, - hash: Option, - ) -> RpcResult>; + fn storage_keys(&self, prefix: StorageKey, hash: Option) -> RpcResult>; /// Returns the keys with prefix, leave empty to get all the keys - #[method(name = "state_getPairs")] - async fn storage_pairs( + #[method(name = "state_getPairs", blocking)] + fn storage_pairs( &self, prefix: StorageKey, hash: Option, @@ -57,8 +53,8 @@ pub trait StateApi { /// Returns the keys with prefix with pagination support. /// Up to `count` keys will be returned. /// If `start_key` is passed, return next keys in storage in lexicographic order. - #[method(name = "state_getKeysPaged", aliases = ["state_getKeysPagedAt"])] - async fn storage_keys_paged( + #[method(name = "state_getKeysPaged", aliases = ["state_getKeysPagedAt"], blocking)] + fn storage_keys_paged( &self, prefix: Option, count: u32, @@ -67,32 +63,32 @@ pub trait StateApi { ) -> RpcResult>; /// Returns a storage entry at a specific block's state. - #[method(name = "state_getStorage", aliases = ["state_getStorageAt"])] - async fn storage(&self, key: StorageKey, hash: Option) -> RpcResult>; + #[method(name = "state_getStorage", aliases = ["state_getStorageAt"], blocking)] + fn storage(&self, key: StorageKey, hash: Option) -> RpcResult>; /// Returns the hash of a storage entry at a block's state. - #[method(name = "state_getStorageHash", aliases = ["state_getStorageHashAt"])] - async fn storage_hash(&self, key: StorageKey, hash: Option) -> RpcResult>; + #[method(name = "state_getStorageHash", aliases = ["state_getStorageHashAt"], blocking)] + fn storage_hash(&self, key: StorageKey, hash: Option) -> RpcResult>; /// Returns the size of a storage entry at a block's state. - #[method(name = "state_getStorageSize", aliases = ["state_getStorageSizeAt"])] - async fn storage_size(&self, key: StorageKey, hash: Option) -> RpcResult>; + #[method(name = "state_getStorageSize", aliases = ["state_getStorageSizeAt"], blocking)] + fn storage_size(&self, key: StorageKey, hash: Option) -> RpcResult>; /// Returns the runtime metadata as an opaque blob. - #[method(name = "state_getMetadata")] - async fn metadata(&self, hash: Option) -> RpcResult; + #[method(name = "state_getMetadata", blocking)] + fn metadata(&self, hash: Option) -> RpcResult; /// Get the runtime version. - #[method(name = "state_getRuntimeVersion", aliases = ["chain_getRuntimeVersion"])] - async fn runtime_version(&self, hash: Option) -> RpcResult; + #[method(name = "state_getRuntimeVersion", aliases = ["chain_getRuntimeVersion"], blocking)] + fn runtime_version(&self, hash: Option) -> RpcResult; /// Query historical storage entries (by key) starting from a block given as the second /// parameter. /// /// NOTE This first returned result contains the initial state of storage for all keys. /// Subsequent values in the vector represent changes to the previous state (diffs). - #[method(name = "state_queryStorage")] - async fn query_storage( + #[method(name = "state_queryStorage", blocking)] + fn query_storage( &self, keys: Vec, block: Hash, @@ -100,20 +96,16 @@ pub trait StateApi { ) -> RpcResult>>; /// Query storage entries (by key) starting at block hash given as the second parameter. - #[method(name = "state_queryStorageAt")] - async fn query_storage_at( + #[method(name = "state_queryStorageAt", blocking)] + fn query_storage_at( &self, keys: Vec, at: Option, ) -> RpcResult>>; /// Returns proof of storage entries at a specific block's state. - #[method(name = "state_getReadProof")] - async fn read_proof( - &self, - keys: Vec, - hash: Option, - ) -> RpcResult>; + #[method(name = "state_getReadProof", blocking)] + fn read_proof(&self, keys: Vec, hash: Option) -> RpcResult>; /// New runtime version subscription #[subscription( @@ -285,8 +277,8 @@ pub trait StateApi { /// /// If you are having issues with maximum payload size you can use the flag /// `-ltracing=trace` to get some logging during tracing. - #[method(name = "state_traceBlock")] - async fn trace_block( + #[method(name = "state_traceBlock", blocking)] + fn trace_block( &self, block: Hash, targets: Option, diff --git a/client/rpc/src/chain/chain_full.rs b/client/rpc/src/chain/chain_full.rs index 2d507f7b9b684..c00c6e5875d94 100644 --- a/client/rpc/src/chain/chain_full.rs +++ b/client/rpc/src/chain/chain_full.rs @@ -26,7 +26,7 @@ use futures::{ future::{self, FutureExt}, stream::{self, Stream, StreamExt}, }; -use jsonrpsee::{core::async_trait, PendingSubscription}; +use jsonrpsee::PendingSubscription; use sc_client_api::{BlockBackend, BlockchainEvents}; use sp_blockchain::HeaderBackend; use sp_runtime::{ @@ -51,7 +51,6 @@ impl FullChain { } } -#[async_trait] impl ChainBackend for FullChain where Block: BlockT + 'static, @@ -62,11 +61,11 @@ where &self.client } - async fn header(&self, hash: Option) -> Result, Error> { + fn header(&self, hash: Option) -> Result, Error> { self.client.header(BlockId::Hash(self.unwrap_or_best(hash))).map_err(client_err) } - async fn block(&self, hash: Option) -> Result>, Error> { + fn block(&self, hash: Option) -> Result>, Error> { self.client.block(&BlockId::Hash(self.unwrap_or_best(hash))).map_err(client_err) } diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index a79c66e0a18f6..a300c80271fd1 100644 --- a/client/rpc/src/chain/mod.rs +++ b/client/rpc/src/chain/mod.rs @@ -27,10 +27,7 @@ use std::sync::Arc; use crate::SubscriptionTaskExecutor; -use jsonrpsee::{ - core::{async_trait, RpcResult}, - PendingSubscription, -}; +use jsonrpsee::{core::RpcResult, PendingSubscription}; use sc_client_api::BlockchainEvents; use sp_rpc::{list::ListOrValue, number::NumberOrHex}; use sp_runtime::{ @@ -45,7 +42,6 @@ pub use sc_rpc_api::chain::*; use sp_blockchain::HeaderBackend; /// Blockchain backend API -#[async_trait] trait ChainBackend: Send + Sync + 'static where Block: BlockT + 'static, @@ -64,10 +60,10 @@ where } /// Get header of a relay chain block. - async fn header(&self, hash: Option) -> Result, Error>; + fn header(&self, hash: Option) -> Result, Error>; /// Get header and body of a relay chain block. - async fn block(&self, hash: Option) -> Result>, Error>; + fn block(&self, hash: Option) -> Result>, Error>; /// Get hash of the n-th block in the canon chain. /// @@ -126,7 +122,6 @@ pub struct Chain { backend: Box>, } -#[async_trait] impl ChainApiServer, Block::Hash, Block::Header, SignedBlock> for Chain where @@ -134,12 +129,12 @@ where Block::Header: Unpin, Client: HeaderBackend + BlockchainEvents + 'static, { - async fn header(&self, hash: Option) -> RpcResult> { - self.backend.header(hash).await.map_err(Into::into) + fn header(&self, hash: Option) -> RpcResult> { + self.backend.header(hash).map_err(Into::into) } - async fn block(&self, hash: Option) -> RpcResult>> { - self.backend.block(hash).await.map_err(Into::into) + fn block(&self, hash: Option) -> RpcResult>> { + self.backend.block(hash).map_err(Into::into) } fn block_hash( diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index a45651c5e7990..4b5b74950a486 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -28,7 +28,7 @@ use std::sync::Arc; use crate::SubscriptionTaskExecutor; use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, + core::{Error as JsonRpseeError, RpcResult}, ws_server::PendingSubscription, }; @@ -53,14 +53,13 @@ use sp_blockchain::{HeaderBackend, HeaderMetadata}; const STORAGE_KEYS_PAGED_MAX_COUNT: u32 = 1000; /// State backend API. -#[async_trait] pub trait StateBackend: Send + Sync + 'static where Block: BlockT + 'static, Client: Send + Sync + 'static, { /// Call runtime method at given block. - async fn call( + fn call( &self, block: Option, method: String, @@ -68,21 +67,21 @@ where ) -> Result; /// Returns the keys with prefix, leave empty to get all the keys. - async fn storage_keys( + fn storage_keys( &self, block: Option, prefix: StorageKey, ) -> Result, Error>; /// Returns the keys with prefix along with their values, leave empty to get all the pairs. - async fn storage_pairs( + fn storage_pairs( &self, block: Option, prefix: StorageKey, ) -> Result, Error>; /// Returns the keys with prefix with pagination support. - async fn storage_keys_paged( + fn storage_keys_paged( &self, block: Option, prefix: Option, @@ -91,14 +90,14 @@ where ) -> Result, Error>; /// Returns a storage entry at a specific block's state. - async fn storage( + fn storage( &self, block: Option, key: StorageKey, ) -> Result, Error>; /// Returns the hash of a storage entry at a block's state. - async fn storage_hash( + fn storage_hash( &self, block: Option, key: StorageKey, @@ -108,24 +107,24 @@ where /// /// If data is available at `key`, it is returned. Else, the sum of values who's key has `key` /// prefix is returned, i.e. all the storage (double) maps that have this prefix. - async fn storage_size( + fn storage_size( &self, block: Option, key: StorageKey, ) -> Result, Error>; /// Returns the runtime metadata as an opaque blob. - async fn metadata(&self, block: Option) -> Result; + fn metadata(&self, block: Option) -> Result; /// Get the runtime version. - async fn runtime_version(&self, block: Option) -> Result; + fn runtime_version(&self, block: Option) -> Result; /// Query historical storage entries (by key) starting from a block given as the second /// parameter. /// /// NOTE This first returned result contains the initial state of storage for all keys. /// Subsequent values in the vector represent changes to the previous state (diffs). - async fn query_storage( + fn query_storage( &self, from: Block::Hash, to: Option, @@ -133,21 +132,21 @@ where ) -> Result>, Error>; /// Query storage entries (by key) starting at block hash given as the second parameter. - async fn query_storage_at( + fn query_storage_at( &self, keys: Vec, at: Option, ) -> Result>, Error>; /// Returns proof of storage entries at a specific block's state. - async fn read_proof( + fn read_proof( &self, block: Option, keys: Vec, ) -> Result, Error>; /// Trace storage changes for block - async fn trace_block( + fn trace_block( &self, block: Block::Hash, targets: Option, @@ -203,39 +202,33 @@ pub struct StateApi { deny_unsafe: DenyUnsafe, } -#[async_trait] impl StateApiServer for StateApi where Block: BlockT + 'static, Client: Send + Sync + 'static, { - async fn call( - &self, - method: String, - data: Bytes, - block: Option, - ) -> RpcResult { - self.backend.call(block, method, data).await.map_err(Into::into) + fn call(&self, method: String, data: Bytes, block: Option) -> RpcResult { + self.backend.call(block, method, data).map_err(Into::into) } - async fn storage_keys( + fn storage_keys( &self, key_prefix: StorageKey, block: Option, ) -> RpcResult> { - self.backend.storage_keys(block, key_prefix).await.map_err(Into::into) + self.backend.storage_keys(block, key_prefix).map_err(Into::into) } - async fn storage_pairs( + fn storage_pairs( &self, key_prefix: StorageKey, block: Option, ) -> RpcResult> { self.deny_unsafe.check_if_safe()?; - self.backend.storage_pairs(block, key_prefix).await.map_err(Into::into) + self.backend.storage_pairs(block, key_prefix).map_err(Into::into) } - async fn storage_keys_paged( + fn storage_keys_paged( &self, prefix: Option, count: u32, @@ -250,66 +243,61 @@ where } self.backend .storage_keys_paged(block, prefix, count, start_key) - .await .map_err(Into::into) } - async fn storage( + fn storage( &self, key: StorageKey, block: Option, ) -> RpcResult> { - self.backend.storage(block, key).await.map_err(Into::into) + self.backend.storage(block, key).map_err(Into::into) } - async fn storage_hash( + fn storage_hash( &self, key: StorageKey, block: Option, ) -> RpcResult> { - self.backend.storage_hash(block, key).await.map_err(Into::into) + self.backend.storage_hash(block, key).map_err(Into::into) } - async fn storage_size( - &self, - key: StorageKey, - block: Option, - ) -> RpcResult> { - self.backend.storage_size(block, key).await.map_err(Into::into) + fn storage_size(&self, key: StorageKey, block: Option) -> RpcResult> { + self.backend.storage_size(block, key).map_err(Into::into) } - async fn metadata(&self, block: Option) -> RpcResult { - self.backend.metadata(block).await.map_err(Into::into) + fn metadata(&self, block: Option) -> RpcResult { + self.backend.metadata(block).map_err(Into::into) } - async fn runtime_version(&self, at: Option) -> RpcResult { - self.backend.runtime_version(at).await.map_err(Into::into) + fn runtime_version(&self, at: Option) -> RpcResult { + self.backend.runtime_version(at).map_err(Into::into) } - async fn query_storage( + fn query_storage( &self, keys: Vec, from: Block::Hash, to: Option, ) -> RpcResult>> { self.deny_unsafe.check_if_safe()?; - self.backend.query_storage(from, to, keys).await.map_err(Into::into) + self.backend.query_storage(from, to, keys).map_err(Into::into) } - async fn query_storage_at( + fn query_storage_at( &self, keys: Vec, at: Option, ) -> RpcResult>> { - self.backend.query_storage_at(keys, at).await.map_err(Into::into) + self.backend.query_storage_at(keys, at).map_err(Into::into) } - async fn read_proof( + fn read_proof( &self, keys: Vec, block: Option, ) -> RpcResult> { - self.backend.read_proof(block, keys).await.map_err(Into::into) + self.backend.read_proof(block, keys).map_err(Into::into) } /// Re-execute the given block with the tracing targets given in `targets` @@ -317,7 +305,7 @@ where /// /// Note: requires the node to run with `--rpc-methods=Unsafe`. /// Note: requires runtimes compiled with wasm tracing support, `--features with-tracing`. - async fn trace_block( + fn trace_block( &self, block: Block::Hash, targets: Option, @@ -327,7 +315,6 @@ where self.deny_unsafe.check_if_safe()?; self.backend .trace_block(block, targets, storage_keys, methods) - .await .map_err(Into::into) } @@ -348,14 +335,13 @@ where } /// Child state backend API. -#[async_trait] pub trait ChildStateBackend: Send + Sync + 'static where Block: BlockT + 'static, Client: Send + Sync + 'static, { /// Returns proof of storage for a child key entries at a specific block's state. - async fn read_child_proof( + fn read_child_proof( &self, block: Option, storage_key: PrefixedStorageKey, @@ -364,7 +350,7 @@ where /// Returns the keys with prefix from a child storage, /// leave prefix empty to get all the keys. - async fn storage_keys( + fn storage_keys( &self, block: Option, storage_key: PrefixedStorageKey, @@ -372,7 +358,7 @@ where ) -> Result, Error>; /// Returns the keys with prefix from a child storage with pagination support. - async fn storage_keys_paged( + fn storage_keys_paged( &self, block: Option, storage_key: PrefixedStorageKey, @@ -382,7 +368,7 @@ where ) -> Result, Error>; /// Returns a child storage entry at a specific block's state. - async fn storage( + fn storage( &self, block: Option, storage_key: PrefixedStorageKey, @@ -390,7 +376,7 @@ where ) -> Result, Error>; /// Returns child storage entries at a specific block's state. - async fn storage_entries( + fn storage_entries( &self, block: Option, storage_key: PrefixedStorageKey, @@ -398,7 +384,7 @@ where ) -> Result>, Error>; /// Returns the hash of a child storage entry at a block's state. - async fn storage_hash( + fn storage_hash( &self, block: Option, storage_key: PrefixedStorageKey, @@ -406,13 +392,13 @@ where ) -> Result, Error>; /// Returns the size of a child storage entry at a block's state. - async fn storage_size( + fn storage_size( &self, block: Option, storage_key: PrefixedStorageKey, key: StorageKey, ) -> Result, Error> { - self.storage(block, storage_key, key).await.map(|x| x.map(|x| x.0.len() as u64)) + self.storage(block, storage_key, key).map(|x| x.map(|x| x.0.len() as u64)) } } @@ -421,25 +407,21 @@ pub struct ChildState { backend: Box>, } -#[async_trait] impl ChildStateApiServer for ChildState where Block: BlockT + 'static, Client: Send + Sync + 'static, { - async fn storage_keys( + fn storage_keys( &self, storage_key: PrefixedStorageKey, key_prefix: StorageKey, block: Option, ) -> RpcResult> { - self.backend - .storage_keys(block, storage_key, key_prefix) - .await - .map_err(Into::into) + self.backend.storage_keys(block, storage_key, key_prefix).map_err(Into::into) } - async fn storage_keys_paged( + fn storage_keys_paged( &self, storage_key: PrefixedStorageKey, prefix: Option, @@ -449,47 +431,46 @@ where ) -> RpcResult> { self.backend .storage_keys_paged(block, storage_key, prefix, count, start_key) - .await .map_err(Into::into) } - async fn storage( + fn storage( &self, storage_key: PrefixedStorageKey, key: StorageKey, block: Option, ) -> RpcResult> { - self.backend.storage(block, storage_key, key).await.map_err(Into::into) + self.backend.storage(block, storage_key, key).map_err(Into::into) } - async fn storage_entries( + fn storage_entries( &self, storage_key: PrefixedStorageKey, keys: Vec, block: Option, ) -> RpcResult>> { - self.backend.storage_entries(block, storage_key, keys).await.map_err(Into::into) + self.backend.storage_entries(block, storage_key, keys).map_err(Into::into) } - async fn storage_hash( + fn storage_hash( &self, storage_key: PrefixedStorageKey, key: StorageKey, block: Option, ) -> RpcResult> { - self.backend.storage_hash(block, storage_key, key).await.map_err(Into::into) + self.backend.storage_hash(block, storage_key, key).map_err(Into::into) } - async fn storage_size( + fn storage_size( &self, storage_key: PrefixedStorageKey, key: StorageKey, block: Option, ) -> RpcResult> { - self.backend.storage_size(block, storage_key, key).await.map_err(Into::into) + self.backend.storage_size(block, storage_key, key).map_err(Into::into) } - async fn read_child_proof( + fn read_child_proof( &self, child_storage_key: PrefixedStorageKey, keys: Vec, @@ -497,7 +478,6 @@ where ) -> RpcResult> { self.backend .read_child_proof(block, child_storage_key, keys) - .await .map_err(Into::into) } } diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 0e20832b30508..c58638c870ab3 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -28,10 +28,7 @@ use super::{ use crate::SubscriptionTaskExecutor; use futures::{future, stream, FutureExt, StreamExt}; -use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError}, - PendingSubscription, -}; +use jsonrpsee::{core::Error as JsonRpseeError, PendingSubscription}; use sc_client_api::{ Backend, BlockBackend, BlockchainEvents, CallExecutor, ExecutorProvider, ProofProvider, StorageProvider, @@ -170,7 +167,6 @@ where } } -#[async_trait] impl StateBackend for FullState where Block: BlockT + 'static, @@ -190,7 +186,7 @@ where + 'static, Client::Api: Metadata, { - async fn call( + fn call( &self, block: Option, method: String, @@ -212,7 +208,7 @@ where .map_err(client_err) } - async fn storage_keys( + fn storage_keys( &self, block: Option, prefix: StorageKey, @@ -222,7 +218,7 @@ where .map_err(client_err) } - async fn storage_pairs( + fn storage_pairs( &self, block: Option, prefix: StorageKey, @@ -232,7 +228,7 @@ where .map_err(client_err) } - async fn storage_keys_paged( + fn storage_keys_paged( &self, block: Option, prefix: Option, @@ -251,7 +247,7 @@ where .map_err(client_err) } - async fn storage( + fn storage( &self, block: Option, key: StorageKey, @@ -261,7 +257,7 @@ where .map_err(client_err) } - async fn storage_size( + fn storage_size( &self, block: Option, key: StorageKey, @@ -290,7 +286,7 @@ where .map_err(client_err) } - async fn storage_hash( + fn storage_hash( &self, block: Option, key: StorageKey, @@ -300,7 +296,7 @@ where .map_err(client_err) } - async fn metadata(&self, block: Option) -> std::result::Result { + fn metadata(&self, block: Option) -> std::result::Result { self.block_or_best(block).map_err(client_err).and_then(|block| { self.client .runtime_api() @@ -310,7 +306,7 @@ where }) } - async fn runtime_version( + fn runtime_version( &self, block: Option, ) -> std::result::Result { @@ -321,7 +317,7 @@ where }) } - async fn query_storage( + fn query_storage( &self, from: Block::Hash, to: Option, @@ -337,16 +333,16 @@ where call_fn() } - async fn query_storage_at( + fn query_storage_at( &self, keys: Vec, at: Option, ) -> std::result::Result>, Error> { let at = at.unwrap_or_else(|| self.client.info().best_hash); - self.query_storage(at, Some(at), keys).await + self.query_storage(at, Some(at), keys) } - async fn read_proof( + fn read_proof( &self, block: Option, keys: Vec, @@ -454,7 +450,7 @@ where self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } - async fn trace_block( + fn trace_block( &self, block: Block::Hash, targets: Option, @@ -474,7 +470,6 @@ where } } -#[async_trait] impl ChildStateBackend for FullState where Block: BlockT + 'static, @@ -493,7 +488,7 @@ where + 'static, Client::Api: Metadata, { - async fn read_child_proof( + fn read_child_proof( &self, block: Option, storage_key: PrefixedStorageKey, @@ -518,7 +513,7 @@ where .map_err(client_err) } - async fn storage_keys( + fn storage_keys( &self, block: Option, storage_key: PrefixedStorageKey, @@ -536,7 +531,7 @@ where .map_err(client_err) } - async fn storage_keys_paged( + fn storage_keys_paged( &self, block: Option, storage_key: PrefixedStorageKey, @@ -562,7 +557,7 @@ where .map_err(client_err) } - async fn storage( + fn storage( &self, block: Option, storage_key: PrefixedStorageKey, @@ -580,7 +575,7 @@ where .map_err(client_err) } - async fn storage_entries( + fn storage_entries( &self, block: Option, storage_key: PrefixedStorageKey, @@ -595,18 +590,18 @@ where }; let block = self.block_or_best(block).map_err(client_err)?; let client = self.client.clone(); - future::try_join_all(keys.into_iter().map(move |key| { - let res = client - .clone() - .child_storage(&BlockId::Hash(block), &child_info, &key) - .map_err(client_err); - - async move { res } - })) - .await + + keys.into_iter() + .map(move |key| { + client + .clone() + .child_storage(&BlockId::Hash(block), &child_info, &key) + .map_err(client_err) + }) + .collect() } - async fn storage_hash( + fn storage_hash( &self, block: Option, storage_key: PrefixedStorageKey, diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index a375a30d2c1a2..53dd8ebf50499 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -61,31 +61,23 @@ async fn should_return_storage() { assert_eq!( client .storage(key.clone(), Some(genesis_hash).into()) - .await .map(|x| x.map(|x| x.0.len())) .unwrap() .unwrap() as usize, VALUE.len(), ); assert_matches!( - client - .storage_hash(key.clone(), Some(genesis_hash).into()) - .await - .map(|x| x.is_some()), + client.storage_hash(key.clone(), Some(genesis_hash).into()).map(|x| x.is_some()), Ok(true) ); + assert_eq!(client.storage_size(key.clone(), None).unwrap().unwrap() as usize, VALUE.len(),); assert_eq!( - client.storage_size(key.clone(), None).await.unwrap().unwrap() as usize, - VALUE.len(), - ); - assert_eq!( - client.storage_size(StorageKey(b":map".to_vec()), None).await.unwrap().unwrap() as usize, + client.storage_size(StorageKey(b":map".to_vec()), None).unwrap().unwrap() as usize, 2 + 3, ); assert_eq!( child .storage(prefixed_storage_key(), key, Some(genesis_hash).into()) - .await .map(|x| x.map(|x| x.0.len())) .unwrap() .unwrap() as usize, @@ -114,7 +106,6 @@ async fn should_return_storage_entries() { assert_eq!( child .storage_entries(prefixed_storage_key(), keys.to_vec(), Some(genesis_hash).into()) - .await .map(|x| x.into_iter().map(|x| x.map(|x| x.0.len()).unwrap()).sum::()) .unwrap(), CHILD_VALUE1.len() + CHILD_VALUE2.len() @@ -126,7 +117,6 @@ async fn should_return_storage_entries() { assert_matches!( child .storage_entries(prefixed_storage_key(), failing_keys, Some(genesis_hash).into()) - .await .map(|x| x.iter().all(|x| x.is_some())), Ok(false) ); @@ -150,17 +140,16 @@ async fn should_return_child_storage() { child_key.clone(), key.clone(), Some(genesis_hash).into(), - ).await, + ), Ok(Some(StorageData(ref d))) if d[0] == 42 && d.len() == 1 ); assert_matches!( child .storage_hash(child_key.clone(), key.clone(), Some(genesis_hash).into(),) - .await .map(|x| x.is_some()), Ok(true) ); - assert_matches!(child.storage_size(child_key.clone(), key.clone(), None).await, Ok(Some(1))); + assert_matches!(child.storage_size(child_key.clone(), key.clone(), None), Ok(Some(1))); } #[tokio::test] @@ -179,7 +168,6 @@ async fn should_return_child_storage_entries() { let res = child .storage_entries(child_key.clone(), keys.clone(), Some(genesis_hash).into()) - .await .unwrap(); assert_matches!( @@ -193,18 +181,12 @@ async fn should_return_child_storage_entries() { if d[0] == 43 && d[1] == 44 && d.len() == 2 ); assert_matches!( - executor::block_on(child.storage_hash( - child_key.clone(), - keys[0].clone(), - Some(genesis_hash).into() - )) - .map(|x| x.is_some()), + child + .storage_hash(child_key.clone(), keys[0].clone(), Some(genesis_hash).into()) + .map(|x| x.is_some()), Ok(true) ); - assert_matches!( - child.storage_size(child_key.clone(), keys[0].clone(), None).await, - Ok(Some(1)) - ); + assert_matches!(child.storage_size(child_key.clone(), keys[0].clone(), None), Ok(Some(1))); } #[tokio::test] @@ -216,9 +198,7 @@ async fn should_call_contract() { use jsonrpsee::{core::Error, types::error::CallError}; assert_matches!( - client - .call("balanceOf".into(), Bytes(vec![1, 2, 3]), Some(genesis_hash).into()) - .await, + client.call("balanceOf".into(), Bytes(vec![1, 2, 3]), Some(genesis_hash).into()), Err(Error::Call(CallError::Failed(_))) ) } @@ -347,7 +327,7 @@ async fn should_query_storage() { let keys = (1..6).map(|k| StorageKey(vec![k])).collect::>(); let result = api.query_storage(keys.clone(), genesis_hash, Some(block1_hash).into()); - assert_eq!(result.await.unwrap(), expected); + assert_eq!(result.unwrap(), expected); // Query all changes let result = api.query_storage(keys.clone(), genesis_hash, None.into()); @@ -360,18 +340,18 @@ async fn should_query_storage() { (StorageKey(vec![5]), Some(StorageData(vec![1]))), ], }); - assert_eq!(result.await.unwrap(), expected); + assert_eq!(result.unwrap(), expected); // Query changes up to block2. let result = api.query_storage(keys.clone(), genesis_hash, Some(block2_hash)); - assert_eq!(result.await.unwrap(), expected); + assert_eq!(result.unwrap(), expected); // Inverted range. let result = api.query_storage(keys.clone(), block1_hash, Some(genesis_hash)); assert_eq!( - result.await.map_err(|e| e.to_string()), + result.map_err(|e| e.to_string()), Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( 4001, Error::InvalidBlockRange { @@ -392,7 +372,7 @@ async fn should_query_storage() { let result = api.query_storage(keys.clone(), genesis_hash, Some(random_hash1)); assert_eq!( - result.await.map_err(|e| e.to_string()), + result.map_err(|e| e.to_string()), Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( 4001, Error::InvalidBlockRange { @@ -413,7 +393,7 @@ async fn should_query_storage() { let result = api.query_storage(keys.clone(), random_hash1, Some(genesis_hash)); assert_eq!( - result.await.map_err(|e| e.to_string()), + result.map_err(|e| e.to_string()), Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( 4001, Error::InvalidBlockRange { @@ -434,7 +414,7 @@ async fn should_query_storage() { let result = api.query_storage(keys.clone(), random_hash1, None); assert_eq!( - result.await.map_err(|e| e.to_string()), + result.map_err(|e| e.to_string()), Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( 4001, Error::InvalidBlockRange { @@ -455,7 +435,7 @@ async fn should_query_storage() { let result = api.query_storage(keys.clone(), random_hash1, Some(random_hash2)); assert_eq!( - result.await.map_err(|e| e.to_string()), + result.map_err(|e| e.to_string()), Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( 4001, Error::InvalidBlockRange { @@ -476,7 +456,7 @@ async fn should_query_storage() { let result = api.query_storage_at(keys.clone(), Some(block1_hash)); assert_eq!( - result.await.unwrap(), + result.unwrap(), vec![StorageChangeSet { block: block1_hash, changes: vec![ @@ -506,7 +486,7 @@ async fn should_return_runtime_version() { [\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\ \"transactionVersion\":1,\"stateVersion\":1}"; - let runtime_version = api.runtime_version(None.into()).await.unwrap(); + let runtime_version = api.runtime_version(None.into()).unwrap(); let serialized = serde_json::to_string(&runtime_version).unwrap(); assert_eq!(serialized, result); From 4fe4fc471bf49bfcb775319c9f830bba70bcb884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 21 May 2022 07:24:24 +0200 Subject: [PATCH 0832/1472] InMemoryBackend: Make it generic over the key hasher (#11488) * InMemoryBackend: Make it generic over the key hasher * Update primitives/state-machine/src/in_memory_backend.rs Co-authored-by: cheme * Update primitives/state-machine/src/in_memory_backend.rs Co-authored-by: cheme * FMT Co-authored-by: cheme --- primitives/state-machine/src/basic.rs | 4 +- .../state-machine/src/in_memory_backend.rs | 56 +++++++++++++------ primitives/state-machine/src/lib.rs | 10 ++-- primitives/trie/src/lib.rs | 3 +- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index f1c09251faa5e..bb387e6406243 100644 --- a/primitives/state-machine/src/basic.rs +++ b/primitives/state-machine/src/basic.rs @@ -30,7 +30,7 @@ use sp_core::{ Blake2Hasher, }; use sp_externalities::{Extension, Extensions}; -use sp_trie::{empty_child_trie_root, LayoutV0, LayoutV1, TrieConfiguration}; +use sp_trie::{empty_child_trie_root, HashKey, LayoutV0, LayoutV1, TrieConfiguration}; use std::{ any::{Any, TypeId}, collections::BTreeMap, @@ -310,7 +310,7 @@ impl Externalities for BasicExternalities { ) -> Vec { if let Some(child) = self.inner.children_default.get(child_info.storage_key()) { let delta = child.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))); - crate::in_memory_backend::new_in_mem::() + crate::in_memory_backend::new_in_mem::>() .child_storage_root(&child.child_info, delta, state_version) .0 } else { diff --git a/primitives/state-machine/src/in_memory_backend.rs b/primitives/state-machine/src/in_memory_backend.rs index 457d89b8c59aa..6df23cdb7096e 100644 --- a/primitives/state-machine/src/in_memory_backend.rs +++ b/primitives/state-machine/src/in_memory_backend.rs @@ -23,22 +23,36 @@ use crate::{ use codec::Codec; use hash_db::Hasher; use sp_core::storage::{ChildInfo, StateVersion, Storage}; -use sp_trie::{empty_trie_root, LayoutV1, MemoryDB}; +use sp_trie::{empty_trie_root, GenericMemoryDB, HashKey, KeyFunction, LayoutV1, MemoryDB}; use std::collections::{BTreeMap, HashMap}; /// Create a new empty instance of in-memory backend. -pub fn new_in_mem() -> TrieBackend, H> +/// +/// It will use [`HashKey`] to store the keys internally. +pub fn new_in_mem_hash_key() -> TrieBackend, H> where + H: Hasher, H::Out: Codec + Ord, { - let db = MemoryDB::default(); + new_in_mem::>() +} + +/// Create a new empty instance of in-memory backend. +pub fn new_in_mem() -> TrieBackend, H> +where + H: Hasher, + H::Out: Codec + Ord, + KF: KeyFunction + Send + Sync, +{ + let db = GenericMemoryDB::default(); // V1 is same as V0 for an empty trie. TrieBackend::new(db, empty_trie_root::>()) } -impl TrieBackend, H> +impl TrieBackend, H> where H::Out: Codec + Ord, + KF: KeyFunction + Send + Sync, { /// Copy the state, with applied updates pub fn update, StorageCollection)>>( @@ -70,14 +84,14 @@ where } /// Merge trie nodes into this backend. - pub fn update_backend(&self, root: H::Out, changes: MemoryDB) -> Self { + pub fn update_backend(&self, root: H::Out, changes: GenericMemoryDB) -> Self { let mut clone = self.backend_storage().clone(); clone.consolidate(changes); Self::new(clone, root) } /// Apply the given transaction to this backend and set the root to the given value. - pub fn apply_transaction(&mut self, root: H::Out, transaction: MemoryDB) { + pub fn apply_transaction(&mut self, root: H::Out, transaction: GenericMemoryDB) { let mut storage = sp_std::mem::take(self).into_storage(); storage.consolidate(transaction); *self = TrieBackend::new(storage, root); @@ -89,28 +103,33 @@ where } } -impl Clone for TrieBackend, H> +impl Clone for TrieBackend, H> where H::Out: Codec + Ord, + KF: KeyFunction + Send + Sync, { fn clone(&self) -> Self { TrieBackend::new(self.backend_storage().clone(), *self.root()) } } -impl Default for TrieBackend, H> +impl Default for TrieBackend, H> where + H: Hasher, H::Out: Codec + Ord, + KF: KeyFunction + Send + Sync, { fn default() -> Self { new_in_mem() } } -impl From<(HashMap, BTreeMap>, StateVersion)> - for TrieBackend, H> +impl + From<(HashMap, BTreeMap>, StateVersion)> + for TrieBackend, H> where H::Out: Codec + Ord, + KF: KeyFunction + Send + Sync, { fn from( (inner, state_version): ( @@ -129,9 +148,10 @@ where } } -impl From<(Storage, StateVersion)> for TrieBackend, H> +impl From<(Storage, StateVersion)> for TrieBackend, H> where H::Out: Codec + Ord, + KF: KeyFunction + Send + Sync, { fn from((inners, state_version): (Storage, StateVersion)) -> Self { let mut inner: HashMap, BTreeMap> = inners @@ -144,10 +164,11 @@ where } } -impl From<(BTreeMap, StateVersion)> - for TrieBackend, H> +impl From<(BTreeMap, StateVersion)> + for TrieBackend, H> where H::Out: Codec + Ord, + KF: KeyFunction + Send + Sync, { fn from((inner, state_version): (BTreeMap, StateVersion)) -> Self { let mut expanded = HashMap::new(); @@ -156,10 +177,11 @@ where } } -impl From<(Vec<(Option, StorageCollection)>, StateVersion)> - for TrieBackend, H> +impl From<(Vec<(Option, StorageCollection)>, StateVersion)> + for TrieBackend, H> where H::Out: Codec + Ord, + KF: KeyFunction + Send + Sync, { fn from( (inner, state_version): (Vec<(Option, StorageCollection)>, StateVersion), @@ -189,7 +211,7 @@ mod tests { #[test] fn in_memory_with_child_trie_only() { let state_version = StateVersion::default(); - let storage = new_in_mem::(); + let storage = new_in_mem_hash_key::(); let child_info = ChildInfo::new_default(b"1"); let child_info = &child_info; let storage = storage.update( @@ -205,7 +227,7 @@ mod tests { #[test] fn insert_multiple_times_child_data_works() { let state_version = StateVersion::default(); - let mut storage = new_in_mem::(); + let mut storage = new_in_mem_hash_key::(); let child_info = ChildInfo::new_default(b"1"); storage.insert( diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 97a9ae8d88cd2..e5b521588aa79 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -143,7 +143,7 @@ mod std_reexport { pub use crate::{ basic::BasicExternalities, error::{Error, ExecutionError}, - in_memory_backend::new_in_mem, + in_memory_backend::{new_in_mem, new_in_mem_hash_key}, proving_backend::{ create_proof_check_backend, ProofRecorder, ProvingBackend, ProvingBackendRecorder, }, @@ -1347,7 +1347,7 @@ mod execution { #[cfg(test)] mod tests { use super::{ext::Ext, *}; - use crate::execution::CallResult; + use crate::{execution::CallResult, in_memory_backend::new_in_mem_hash_key}; use codec::{Decode, Encode}; use sp_core::{ map, @@ -1687,7 +1687,7 @@ mod tests { fn set_child_storage_works() { let child_info = ChildInfo::new_default(b"sub1"); let child_info = &child_info; - let state = new_in_mem::(); + let state = new_in_mem_hash_key::(); let backend = state.as_trie_backend().unwrap(); let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); @@ -1703,7 +1703,7 @@ mod tests { fn append_storage_works() { let reference_data = vec![b"data1".to_vec(), b"2".to_vec(), b"D3".to_vec(), b"d4".to_vec()]; let key = b"key".to_vec(); - let state = new_in_mem::(); + let state = new_in_mem_hash_key::(); let backend = state.as_trie_backend().unwrap(); let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); @@ -1740,7 +1740,7 @@ mod tests { let key = b"events".to_vec(); let mut cache = StorageTransactionCache::default(); - let state = new_in_mem::(); + let state = new_in_mem_hash_key::(); let backend = state.as_trie_backend().unwrap(); let mut overlay = OverlayedChanges::default(); diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index 358cb43ab4e92..1dca617acf912 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -31,9 +31,8 @@ pub use error::Error; /// Various re-exports from the `hash-db` crate. pub use hash_db::{HashDB as HashDBT, EMPTY_PREFIX}; use hash_db::{Hasher, Prefix}; -pub use memory_db::prefixed_key; /// Various re-exports from the `memory-db` crate. -pub use memory_db::KeyFunction; +pub use memory_db::{prefixed_key, HashKey, KeyFunction, PrefixedKey}; /// The Substrate format implementation of `NodeCodec`. pub use node_codec::NodeCodec; use sp_std::{borrow::Borrow, boxed::Box, marker::PhantomData, vec::Vec}; From eddf888394cba28b048bd79e319e8b27f4b414f3 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Sat, 21 May 2022 14:13:09 +0800 Subject: [PATCH 0833/1472] Unify rpc api and implementation name (#11469) * Unify rpc api and implementation name Signed-off-by: koushiro * MauanlSeal ==> ManualSealRpc Signed-off-by: koushiro * Remove extra Rpc naming in the structs Signed-off-by: koushiro * Update doc Signed-off-by: koushiro * fix merge Co-authored-by: Shawn Tabrizi --- bin/node-template/node/src/rpc.rs | 8 ++-- bin/node/rpc/src/lib.rs | 37 ++++++++----------- client/beefy/rpc/src/lib.rs | 23 +++++------- client/consensus/babe/rpc/src/lib.rs | 12 +++--- client/finality-grandpa/rpc/src/lib.rs | 14 +++---- client/rpc/src/state/mod.rs | 8 ++-- client/sync-state-rpc/src/lib.rs | 10 ++--- frame/contracts/rpc/src/lib.rs | 6 +-- frame/merkle-mountain-range/rpc/src/lib.rs | 7 ++-- frame/transaction-payment/rpc/src/lib.rs | 8 ++-- .../rpc/state-trie-migration-rpc/src/lib.rs | 8 ++-- utils/frame/rpc/system/src/lib.rs | 14 +++---- 12 files changed, 72 insertions(+), 83 deletions(-) diff --git a/bin/node-template/node/src/rpc.rs b/bin/node-template/node/src/rpc.rs index 7edae4d81474f..981f375d0b462 100644 --- a/bin/node-template/node/src/rpc.rs +++ b/bin/node-template/node/src/rpc.rs @@ -39,14 +39,14 @@ where C::Api: BlockBuilder, P: TransactionPool + 'static, { - use pallet_transaction_payment_rpc::{TransactionPaymentApiServer, TransactionPaymentRpc}; - use substrate_frame_rpc_system::{SystemApiServer, SystemRpc}; + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; + use substrate_frame_rpc_system::{System, SystemApiServer}; let mut module = RpcModule::new(()); let FullDeps { client, pool, deny_unsafe } = deps; - module.merge(SystemRpc::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; - module.merge(TransactionPaymentRpc::new(client).into_rpc())?; + module.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; + module.merge(TransactionPayment::new(client).into_rpc())?; // Extend this RPC with a custom API by using the following syntax. // `YourRpcStruct` should have a reference to a client, which is needed diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 05aa973e102b1..e5b666195e1bc 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -37,12 +37,10 @@ use jsonrpsee::RpcModule; use node_primitives::{AccountId, Balance, Block, BlockNumber, Hash, Index}; use sc_client_api::AuxStore; use sc_consensus_babe::{Config, Epoch}; -use sc_consensus_babe_rpc::BabeRpc; use sc_consensus_epochs::SharedEpochChanges; use sc_finality_grandpa::{ FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState, }; -use sc_finality_grandpa_rpc::GrandpaRpc; use sc_rpc::SubscriptionTaskExecutor; pub use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::TransactionPool; @@ -120,15 +118,15 @@ where B: sc_client_api::Backend + Send + Sync + 'static, B::State: sc_client_api::backend::StateBackend>, { - use pallet_contracts_rpc::{ContractsApiServer, ContractsRpc}; - use pallet_mmr_rpc::{MmrApiServer, MmrRpc}; - use pallet_transaction_payment_rpc::{TransactionPaymentApiServer, TransactionPaymentRpc}; - use sc_consensus_babe_rpc::BabeApiServer; - use sc_finality_grandpa_rpc::GrandpaApiServer; + use pallet_contracts_rpc::{Contracts, ContractsApiServer}; + use pallet_mmr_rpc::{Mmr, MmrApiServer}; + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; + use sc_consensus_babe_rpc::{Babe, BabeApiServer}; + use sc_finality_grandpa_rpc::{Grandpa, GrandpaApiServer}; use sc_rpc::dev::{Dev, DevApiServer}; - use sc_sync_state_rpc::{SyncStateRpc, SyncStateRpcApiServer}; - use substrate_frame_rpc_system::{SystemApiServer, SystemRpc}; - use substrate_state_trie_migration_rpc::StateMigrationApiServer; + use sc_sync_state_rpc::{SyncState, SyncStateApiServer}; + use substrate_frame_rpc_system::{System, SystemApiServer}; + use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; let mut io = RpcModule::new(()); let FullDeps { client, pool, select_chain, chain_spec, deny_unsafe, babe, grandpa } = deps; @@ -142,15 +140,15 @@ where finality_provider, } = grandpa; - io.merge(SystemRpc::new(client.clone(), pool, deny_unsafe).into_rpc())?; + io.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; // Making synchronous calls in light client freezes the browser currently, // more context: https://github.com/paritytech/substrate/pull/3480 // These RPCs should use an asynchronous caller instead. - io.merge(ContractsRpc::new(client.clone()).into_rpc())?; - io.merge(MmrRpc::new(client.clone()).into_rpc())?; - io.merge(TransactionPaymentRpc::new(client.clone()).into_rpc())?; + io.merge(Contracts::new(client.clone()).into_rpc())?; + io.merge(Mmr::new(client.clone()).into_rpc())?; + io.merge(TransactionPayment::new(client.clone()).into_rpc())?; io.merge( - BabeRpc::new( + Babe::new( client.clone(), shared_epoch_changes.clone(), keystore, @@ -161,7 +159,7 @@ where .into_rpc(), )?; io.merge( - GrandpaRpc::new( + Grandpa::new( subscription_executor, shared_authority_set.clone(), shared_voter_state, @@ -172,14 +170,11 @@ where )?; io.merge( - SyncStateRpc::new(chain_spec, client.clone(), shared_authority_set, shared_epoch_changes)? + SyncState::new(chain_spec, client.clone(), shared_authority_set, shared_epoch_changes)? .into_rpc(), )?; - io.merge( - substrate_state_trie_migration_rpc::MigrationRpc::new(client.clone(), backend, deny_unsafe) - .into_rpc(), - )?; + io.merge(StateMigration::new(client.clone(), backend, deny_unsafe).into_rpc())?; io.merge(Dev::new(client, deny_unsafe).into_rpc())?; Ok(io) diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index ea35678a48b8f..c248d33cb6c23 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -100,17 +100,17 @@ pub trait BeefyApi { } /// Implements the BeefyApi RPC trait for interacting with BEEFY. -pub struct BeefyRpcHandler { +pub struct Beefy { signed_commitment_stream: BeefySignedCommitmentStream, beefy_best_block: Arc>>, executor: SubscriptionTaskExecutor, } -impl BeefyRpcHandler +impl Beefy where Block: BlockT, { - /// Creates a new BeefyRpcHandler instance. + /// Creates a new Beefy Rpc handler instance. pub fn new( signed_commitment_stream: BeefySignedCommitmentStream, best_block_stream: BeefyBestBlockStream, @@ -131,8 +131,7 @@ where } #[async_trait] -impl BeefyApiServer - for BeefyRpcHandler +impl BeefyApiServer for Beefy where Block: BlockT, { @@ -174,24 +173,20 @@ mod tests { use sp_runtime::traits::{BlakeTwo256, Hash}; use substrate_test_runtime_client::runtime::Block; - fn setup_io_handler() -> (RpcModule>, BeefySignedCommitmentSender) - { + fn setup_io_handler() -> (RpcModule>, BeefySignedCommitmentSender) { let (_, stream) = BeefyBestBlockStream::::channel(); setup_io_handler_with_best_block_stream(stream) } fn setup_io_handler_with_best_block_stream( best_block_stream: BeefyBestBlockStream, - ) -> (RpcModule>, BeefySignedCommitmentSender) { + ) -> (RpcModule>, BeefySignedCommitmentSender) { let (commitment_sender, commitment_stream) = BeefySignedCommitmentStream::::channel(); - let handler = BeefyRpcHandler::new( - commitment_stream, - best_block_stream, - sc_rpc::testing::test_executor(), - ) - .expect("Setting up the BEEFY RPC handler works"); + let handler = + Beefy::new(commitment_stream, best_block_stream, sc_rpc::testing::test_executor()) + .expect("Setting up the BEEFY RPC handler works"); (handler.into_rpc(), commitment_sender) } diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index d5f21606c62ed..af19d410346e3 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -49,7 +49,7 @@ pub trait BabeApi { } /// Provides RPC methods for interacting with Babe. -pub struct BabeRpc { +pub struct Babe { /// shared reference to the client. client: Arc, /// shared reference to EpochChanges @@ -64,8 +64,8 @@ pub struct BabeRpc { deny_unsafe: DenyUnsafe, } -impl BabeRpc { - /// Creates a new instance of the BabeRpc handler. +impl Babe { + /// Creates a new instance of the Babe Rpc handler. pub fn new( client: Arc, shared_epoch_changes: SharedEpochChanges, @@ -79,7 +79,7 @@ impl BabeRpc { } #[async_trait] -impl BabeApiServer for BabeRpc +impl BabeApiServer for Babe where B: BlockT, C: ProvideRuntimeApi @@ -239,7 +239,7 @@ mod tests { fn test_babe_rpc_module( deny_unsafe: DenyUnsafe, - ) -> BabeRpc> { + ) -> Babe> { let builder = TestClientBuilder::new(); let (client, longest_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); @@ -250,7 +250,7 @@ mod tests { let epoch_changes = link.epoch_changes().clone(); let keystore = create_temp_keystore::(Sr25519Keyring::Alice).0; - BabeRpc::new(client.clone(), epoch_changes, keystore, config, longest_chain, deny_unsafe) + Babe::new(client.clone(), epoch_changes, keystore, config, longest_chain, deny_unsafe) } #[tokio::test] diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index cb51d71b20bf4..bdb86c125e20a 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -66,7 +66,7 @@ pub trait GrandpaApi { } /// Provides RPC methods for interacting with GRANDPA. -pub struct GrandpaRpc { +pub struct Grandpa { executor: SubscriptionTaskExecutor, authority_set: AuthoritySet, voter_state: VoterState, @@ -74,9 +74,9 @@ pub struct GrandpaRpc { finality_proof_provider: Arc, } impl - GrandpaRpc + Grandpa { - /// Prepare a new [`GrandpaRpc`] + /// Prepare a new [`Grandpa`] Rpc handler. pub fn new( executor: SubscriptionTaskExecutor, authority_set: AuthoritySet, @@ -91,7 +91,7 @@ impl #[async_trait] impl GrandpaApiServer> - for GrandpaRpc + for Grandpa where VoterState: ReportVoterState + Send + Sync + 'static, AuthoritySet: ReportAuthoritySet + Send + Sync + 'static, @@ -243,7 +243,7 @@ mod tests { fn setup_io_handler( voter_state: VoterState, ) -> ( - RpcModule>, + RpcModule>, GrandpaJustificationSender, ) where @@ -256,7 +256,7 @@ mod tests { voter_state: VoterState, finality_proof: Option>, ) -> ( - RpcModule>, + RpcModule>, GrandpaJustificationSender, ) where @@ -266,7 +266,7 @@ mod tests { let finality_proof_provider = Arc::new(TestFinalityProofProvider { finality_proof }); let executor = Arc::new(TaskExecutor::default()); - let rpc = GrandpaRpc::new( + let rpc = Grandpa::new( executor, TestAuthoritySet, voter_state, diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index 4b5b74950a486..232be4edc8aab 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -167,7 +167,7 @@ pub fn new_full( executor: SubscriptionTaskExecutor, deny_unsafe: DenyUnsafe, rpc_max_payload: Option, -) -> (StateApi, ChildState) +) -> (State, ChildState) where Block: BlockT + 'static, Block::Hash: Unpin, @@ -192,17 +192,17 @@ where rpc_max_payload, )); let backend = Box::new(self::state_full::FullState::new(client, executor, rpc_max_payload)); - (StateApi { backend, deny_unsafe }, ChildState { backend: child_backend }) + (State { backend, deny_unsafe }, ChildState { backend: child_backend }) } /// State API with subscriptions support. -pub struct StateApi { +pub struct State { backend: Box>, /// Whether to deny unsafe calls deny_unsafe: DenyUnsafe, } -impl StateApiServer for StateApi +impl StateApiServer for State where Block: BlockT + 'static, Client: Send + Sync + 'static, diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index 02a22a838b8b2..9540d94c57918 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -37,7 +37,7 @@ //! ``` //! //! If the [`LightSyncStateExtension`] is not added as an extension to the chain spec, -//! the [`SyncStateRpc`] will fail at instantiation. +//! the [`SyncState`] will fail at instantiation. #![deny(unused_crate_dependencies)] @@ -125,21 +125,21 @@ pub struct LightSyncState { /// An api for sync state RPC calls. #[rpc(client, server)] -pub trait SyncStateRpcApi { +pub trait SyncStateApi { /// Returns the JSON serialized chainspec running the node, with a sync state. #[method(name = "sync_state_genSyncSpec")] fn system_gen_sync_spec(&self, raw: bool) -> RpcResult; } /// An api for sync state RPC calls. -pub struct SyncStateRpc { +pub struct SyncState { chain_spec: Box, client: Arc, shared_authority_set: SharedAuthoritySet, shared_epoch_changes: SharedEpochChanges, } -impl SyncStateRpc +impl SyncState where Block: BlockT, Client: HeaderBackend + sc_client_api::AuxStore + 'static, @@ -180,7 +180,7 @@ where } } -impl SyncStateRpcApiServer for SyncStateRpc +impl SyncStateApiServer for SyncState where Block: BlockT, Backend: HeaderBackend + sc_client_api::AuxStore + 'static, diff --git a/frame/contracts/rpc/src/lib.rs b/frame/contracts/rpc/src/lib.rs index 599e80676cb19..77ae3f3ed35e3 100644 --- a/frame/contracts/rpc/src/lib.rs +++ b/frame/contracts/rpc/src/lib.rs @@ -173,12 +173,12 @@ where } /// Contracts RPC methods. -pub struct ContractsRpc { +pub struct Contracts { client: Arc, _marker: PhantomData, } -impl ContractsRpc { +impl Contracts { /// Create new `Contracts` with the given reference to the client. pub fn new(client: Arc) -> Self { Self { client, _marker: Default::default() } @@ -193,7 +193,7 @@ impl AccountId, Balance, Hash, - > for ContractsRpc + > for Contracts where Block: BlockT, Client: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 12e4e11f88256..75032d40f492a 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -131,12 +131,12 @@ pub trait MmrApi { } /// MMR RPC methods. -pub struct MmrRpc { +pub struct Mmr { client: Arc, _marker: PhantomData, } -impl MmrRpc { +impl Mmr { /// Create new `Mmr` with the given reference to the client. pub fn new(client: Arc) -> Self { Self { client, _marker: Default::default() } @@ -144,8 +144,7 @@ impl MmrRpc { } #[async_trait] -impl MmrApiServer<::Hash> - for MmrRpc +impl MmrApiServer<::Hash> for Mmr where Block: BlockT, Client: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index b0be19fdb22a9..75ec42321ef5e 100644 --- a/frame/transaction-payment/rpc/src/lib.rs +++ b/frame/transaction-payment/rpc/src/lib.rs @@ -51,14 +51,14 @@ pub trait TransactionPaymentApi { } /// Provides RPC methods to query a dispatchable's class, weight and fee. -pub struct TransactionPaymentRpc { +pub struct TransactionPayment { /// Shared reference to the client. client: Arc, _marker: std::marker::PhantomData

, } -impl TransactionPaymentRpc { - /// Creates a new instance of the TransactionPaymentRpc helper. +impl TransactionPayment { + /// Creates a new instance of the TransactionPayment Rpc helper. pub fn new(client: Arc) -> Self { Self { client, _marker: Default::default() } } @@ -84,7 +84,7 @@ impl From for i32 { #[async_trait] impl TransactionPaymentApiServer<::Hash, RuntimeDispatchInfo> - for TransactionPaymentRpc + for TransactionPayment where Block: BlockT, C: ProvideRuntimeApi + HeaderBackend + Send + Sync + 'static, diff --git a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index 531bf463f6523..b6d403ff2fcfd 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -122,21 +122,21 @@ pub trait StateMigrationApi { } /// An implementation of state migration specific RPC methods. -pub struct MigrationRpc { +pub struct StateMigration { client: Arc, backend: Arc, deny_unsafe: DenyUnsafe, _marker: std::marker::PhantomData<(B, BA)>, } -impl MigrationRpc { +impl StateMigration { /// Create new state migration rpc for the given reference to the client. pub fn new(client: Arc, backend: Arc, deny_unsafe: DenyUnsafe) -> Self { - MigrationRpc { client, backend, deny_unsafe, _marker: Default::default() } + StateMigration { client, backend, deny_unsafe, _marker: Default::default() } } } -impl StateMigrationApiServer<::Hash> for MigrationRpc +impl StateMigrationApiServer<::Hash> for StateMigration where B: BlockT, C: Send + Sync + 'static + sc_client_api::HeaderBackend, diff --git a/utils/frame/rpc/system/src/lib.rs b/utils/frame/rpc/system/src/lib.rs index b044035c8120e..72ad99e435f72 100644 --- a/utils/frame/rpc/system/src/lib.rs +++ b/utils/frame/rpc/system/src/lib.rs @@ -70,14 +70,14 @@ impl From for i32 { } /// An implementation of System-specific RPC methods on full client. -pub struct SystemRpc { +pub struct System { client: Arc, pool: Arc

, deny_unsafe: DenyUnsafe, _marker: std::marker::PhantomData, } -impl SystemRpc { +impl System { /// Create new `FullSystem` given client and transaction pool. pub fn new(client: Arc, pool: Arc

, deny_unsafe: DenyUnsafe) -> Self { Self { client, pool, deny_unsafe, _marker: Default::default() } @@ -86,7 +86,7 @@ impl SystemRpc { #[async_trait] impl - SystemApiServer<::Hash, AccountId, Index> for SystemRpc + SystemApiServer<::Hash, AccountId, Index> for System where C: sp_api::ProvideRuntimeApi, C: HeaderBackend, @@ -251,7 +251,7 @@ mod tests { let ext1 = new_transaction(1); block_on(pool.submit_one(&BlockId::number(0), source, ext1)).unwrap(); - let accounts = SystemRpc::new(client, pool, DenyUnsafe::Yes); + let accounts = System::new(client, pool, DenyUnsafe::Yes); // when let nonce = accounts.nonce(AccountKeyring::Alice.into()).await; @@ -270,7 +270,7 @@ mod tests { let pool = BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); - let accounts = SystemRpc::new(client, pool, DenyUnsafe::Yes); + let accounts = System::new(client, pool, DenyUnsafe::Yes); // when let res = accounts.dry_run(vec![].into(), None).await; @@ -289,7 +289,7 @@ mod tests { let pool = BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); - let accounts = SystemRpc::new(client, pool, DenyUnsafe::No); + let accounts = System::new(client, pool, DenyUnsafe::No); let tx = Transfer { from: AccountKeyring::Alice.into(), @@ -317,7 +317,7 @@ mod tests { let pool = BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); - let accounts = SystemRpc::new(client, pool, DenyUnsafe::No); + let accounts = System::new(client, pool, DenyUnsafe::No); let tx = Transfer { from: AccountKeyring::Alice.into(), From 7a28c62246406839b746af2201309d0ed9a3f526 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Sat, 21 May 2022 10:45:57 +0200 Subject: [PATCH 0834/1472] rpc servers CLI: add `--max--subscriptions--per--connection` + fix a few bugs (#11461) * cli: fix RPC CLI nits * remove needless lines * cargo fmt * Update client/service/src/lib.rs Co-authored-by: James Wilson Co-authored-by: James Wilson --- client/cli/src/commands/run_cmd.rs | 17 +++++++++++++++++ client/cli/src/config.rs | 7 ++++++- client/service/src/lib.rs | 19 +++++++++++++------ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 6cb0de0ebd04c..b4a3885e39906 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -115,6 +115,11 @@ pub struct RunCmd { #[clap(long)] pub rpc_max_response_size: Option, + /// Set the the maximum concurrent subscriptions per connection. + /// Default is 1024. + #[clap(long)] + pub rpc_max_subscriptions_per_connection: Option, + /// Expose Prometheus exporter on all interfaces. /// /// Default is local. @@ -459,6 +464,18 @@ impl CliConfiguration for RunCmd { Ok(self.rpc_max_payload) } + fn rpc_max_request_size(&self) -> Result> { + Ok(self.rpc_max_request_size) + } + + fn rpc_max_response_size(&self) -> Result> { + Ok(self.rpc_max_response_size) + } + + fn rpc_max_subscriptions_per_connection(&self) -> Result> { + Ok(self.rpc_max_subscriptions_per_connection) + } + fn ws_max_out_buffer_capacity(&self) -> Result> { Ok(self.ws_max_out_buffer_capacity) } diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index e38d34b92c74d..5e91cf6c74dae 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -369,6 +369,11 @@ pub trait CliConfiguration: Sized { Ok(None) } + /// Get maximum number of subscriptions per connection. + fn rpc_max_subscriptions_per_connection(&self) -> Result> { + Ok(None) + } + /// Get maximum WS output buffer capacity. fn ws_max_out_buffer_capacity(&self) -> Result> { Ok(None) @@ -539,7 +544,7 @@ pub trait CliConfiguration: Sized { rpc_max_request_size: self.rpc_max_request_size()?, rpc_max_response_size: self.rpc_max_response_size()?, rpc_id_provider: None, - rpc_max_subs_per_conn: None, + rpc_max_subs_per_conn: self.rpc_max_subscriptions_per_connection()?, ws_max_out_buffer_capacity: self.ws_max_out_buffer_capacity()?, prometheus_config: self .prometheus_config(DCV::prometheus_listen_port(), &chain_spec)?, diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 027b704789635..24ba670cfcd65 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -480,11 +480,18 @@ where } fn legacy_cli_parsing(config: &Configuration) -> (Option, Option, Option) { - let ws_max_response_size = config.ws_max_out_buffer_capacity.map(|max| { - eprintln!("DEPRECATED: `--ws_max_out_buffer_capacity` has been removed use `rpc-max-response-size or rpc-max-request-size` instead"); - eprintln!("Setting WS `rpc-max-response-size` to `max(ws_max_out_buffer_capacity, rpc_max_response_size)`"); - std::cmp::max(max, config.rpc_max_response_size.unwrap_or(0)) - }); + let ws_max_response_size = match ( + config.ws_max_out_buffer_capacity, + config.rpc_max_response_size, + ) { + (Some(legacy_max), max) => { + eprintln!("DEPRECATED: `--ws_max_out_buffer_capacity` has been removed; use `rpc-max-response-size or rpc-max-request-size` instead"); + eprintln!("Setting WS `rpc-max-response-size` to `max(ws_max_out_buffer_capacity, rpc_max_response_size)`"); + Some(std::cmp::max(legacy_max, max.unwrap_or(0))) + }, + (None, Some(m)) => Some(m), + (None, None) => None, + }; let max_request_size = match (config.rpc_max_payload, config.rpc_max_request_size) { (Some(legacy_max), max) => { @@ -498,7 +505,7 @@ fn legacy_cli_parsing(config: &Configuration) -> (Option, Option, (None, None) => None, }; - let http_max_response_size = match (config.rpc_max_payload, config.rpc_max_request_size) { + let http_max_response_size = match (config.rpc_max_payload, config.rpc_max_response_size) { (Some(legacy_max), max) => { eprintln!("DEPRECATED: `--rpc_max_payload` has been removed use `rpc-max-response-size or rpc-max-request-size` instead"); eprintln!( From 6386eea9ecf33bd43e6ea319cfae27e18d32fdf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 22 May 2022 09:19:07 +0200 Subject: [PATCH 0835/1472] Make `--dev` listen by default on `/ip4/0.0.0.0/tcp/30333` (#11492) If `--validator` is passed we also listen on this address and as `--dev` is a shortcut for multiple CLI args, including `--validator`, we should make it consistent. --- client/cli/src/params/network_params.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index ac5039fb89754..74c2db92c3215 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -163,7 +163,7 @@ impl NetworkParams { let port = self.port.unwrap_or(default_listen_port); let listen_addresses = if self.listen_addr.is_empty() { - if is_validator { + if is_validator || is_dev { vec![ Multiaddr::empty() .with(Protocol::Ip6([0, 0, 0, 0, 0, 0, 0, 0].into())) From 3a4f9659728e9ea9e3c9e1f6ccde418ec8dbb752 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Mon, 23 May 2022 06:10:23 -0400 Subject: [PATCH 0836/1472] Fix State Trie Migration Benchmarks (#11502) * enable signed migrations in benchmarks * T instead of Test Signed-off-by: Oliver Tale-Yazdi * Remove 'mut' Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/state-trie-migration/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index d78fd7d9ca932..899250cc3f3c3 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -848,6 +848,8 @@ mod benchmarks { // function. let null = MigrationLimits::default(); let caller = frame_benchmarking::whitelisted_caller(); + // Allow signed migrations. + SignedMigrationMaxLimits::::put(MigrationLimits { size: 1024, item: 5 }); }: _(frame_system::RawOrigin::Signed(caller), null, 0, StateTrieMigration::::migration_process()) verify { assert_eq!(StateTrieMigration::::migration_process(), Default::default()) @@ -1146,14 +1148,7 @@ mod mock { } sp_tracing::try_init_simple(); - let mut ext: sp_io::TestExternalities = (custom_storage, version).into(); - - // set some genesis values for this pallet as well. - ext.execute_with(|| { - SignedMigrationMaxLimits::::put(MigrationLimits { size: 1024, item: 5 }); - }); - - ext + (custom_storage, version).into() } pub(crate) fn run_to_block(n: u32) -> (H256, u64) { @@ -1292,6 +1287,9 @@ mod test { new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { assert_eq!(MigrationProcess::::get(), Default::default()); + // Allow signed migrations. + SignedMigrationMaxLimits::::put(MigrationLimits { size: 1024, item: 5 }); + // can't submit if limit is too high. frame_support::assert_err!( StateTrieMigration::continue_migrate( From c0ee2adaa54b22ee0df5d1592cd0430961afd95c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Mon, 23 May 2022 10:14:20 -0300 Subject: [PATCH 0837/1472] Use API for pr-custom-review (#11487) * use API for pr-custom-review * bump action tag * temporary: disable draft skip * temporary: use staging * try it with the prod instance * revert draft skip --- .github/workflows/pr-custom-review.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-custom-review.yml b/.github/workflows/pr-custom-review.yml index 6cb16d931d6f4..8e40c9ee72989 100644 --- a/.github/workflows/pr-custom-review.yml +++ b/.github/workflows/pr-custom-review.yml @@ -37,6 +37,6 @@ jobs: if: github.event.pull_request.draft == true run: exit 1 - name: pr-custom-review - uses: paritytech/pr-custom-review@v2 + uses: paritytech/pr-custom-review@action-v3 with: - token: ${{ secrets.PRCR_TOKEN }} + checks-reviews-api: http://pcr.parity-prod.parity.io/api/v1/check_reviews From 0345460197179a9f2b3a6310be99360aec69d513 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 23 May 2022 17:47:36 +0100 Subject: [PATCH 0838/1472] Introduce #[pallet::call_index] attribute to dispatchables (#11381) * Introduce #[pallet::call_index] attribute to dispatchables * cargo fmt * Add more docs and prevent duplicates of call indices * Add UI test for conflicting call indices * cargo fmt Co-authored-by: parity-processbot <> --- .../procedural/src/pallet/expand/call.rs | 2 + .../procedural/src/pallet/parse/call.rs | 92 ++++++++++++++++--- frame/support/src/lib.rs | 19 +++- .../pallet_ui/call_conflicting_indices.rs | 24 +++++ .../pallet_ui/call_conflicting_indices.stderr | 11 +++ .../test/tests/pallet_ui/call_invalid_attr.rs | 20 ++++ .../tests/pallet_ui/call_invalid_attr.stderr | 5 + .../tests/pallet_ui/call_invalid_index.rs | 21 +++++ .../tests/pallet_ui/call_invalid_index.stderr | 5 + .../pallet_ui/call_multiple_call_index.rs | 22 +++++ .../pallet_ui/call_multiple_call_index.stderr | 5 + 11 files changed, 208 insertions(+), 18 deletions(-) create mode 100644 frame/support/test/tests/pallet_ui/call_conflicting_indices.rs create mode 100644 frame/support/test/tests/pallet_ui/call_conflicting_indices.stderr create mode 100644 frame/support/test/tests/pallet_ui/call_invalid_attr.rs create mode 100644 frame/support/test/tests/pallet_ui/call_invalid_attr.stderr create mode 100644 frame/support/test/tests/pallet_ui/call_invalid_index.rs create mode 100644 frame/support/test/tests/pallet_ui/call_invalid_index.stderr create mode 100644 frame/support/test/tests/pallet_ui/call_multiple_call_index.rs create mode 100644 frame/support/test/tests/pallet_ui/call_multiple_call_index.stderr diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 60546e1a96779..ac52463b8aab6 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -42,6 +42,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { let pallet_ident = &def.pallet_struct.pallet; let fn_name = methods.iter().map(|method| &method.name).collect::>(); + let call_index = methods.iter().map(|method| method.call_index).collect::>(); let new_call_variant_fn_name = fn_name .iter() .map(|fn_name| quote::format_ident!("new_call_variant_{}", fn_name)) @@ -177,6 +178,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { ), #( #( #[doc = #fn_doc] )* + #[codec(index = #call_index)] #fn_name { #( #[allow(missing_docs)] diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index f532d339f1205..75c85474dcfe7 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -18,6 +18,7 @@ use super::helper; use frame_support_procedural_tools::get_doc_literals; use quote::ToTokens; +use std::collections::HashMap; use syn::spanned::Spanned; /// List of additional token to be used for parsing. @@ -25,6 +26,7 @@ mod keyword { syn::custom_keyword!(Call); syn::custom_keyword!(OriginFor); syn::custom_keyword!(weight); + syn::custom_keyword!(call_index); syn::custom_keyword!(compact); syn::custom_keyword!(T); syn::custom_keyword!(pallet); @@ -55,14 +57,17 @@ pub struct CallVariantDef { pub args: Vec<(bool, syn::Ident, Box)>, /// Weight formula. pub weight: syn::Expr, + /// Call index of the dispatchable. + pub call_index: u8, /// Docs, used for metadata. pub docs: Vec, } /// Attributes for functions in call impl block. -/// Parse for `#[pallet::weight(expr)]` -pub struct FunctionAttr { - weight: syn::Expr, +/// Parse for `#[pallet::weight(expr)]` or `#[pallet::call_index(expr)] +pub enum FunctionAttr { + CallIndex(u8), + Weight(syn::Expr), } impl syn::parse::Parse for FunctionAttr { @@ -72,11 +77,22 @@ impl syn::parse::Parse for FunctionAttr { syn::bracketed!(content in input); content.parse::()?; content.parse::()?; - content.parse::()?; - let weight_content; - syn::parenthesized!(weight_content in content); - Ok(FunctionAttr { weight: weight_content.parse::()? }) + let lookahead = content.lookahead1(); + if lookahead.peek(keyword::weight) { + content.parse::()?; + let weight_content; + syn::parenthesized!(weight_content in content); + Ok(FunctionAttr::Weight(weight_content.parse::()?)) + } else if lookahead.peek(keyword::call_index) { + content.parse::()?; + let call_index_content; + syn::parenthesized!(call_index_content in content); + let index = call_index_content.parse::()?; + Ok(FunctionAttr::CallIndex(index.base10_parse()?)) + } else { + Err(lookahead.error()) + } } } @@ -145,6 +161,8 @@ impl CallDef { } let mut methods = vec![]; + let mut indices = HashMap::new(); + let mut last_index: Option = None; for impl_item in &mut item.items { if let syn::ImplItem::Method(method) = impl_item { if !matches!(method.vis, syn::Visibility::Public(_)) { @@ -182,18 +200,58 @@ impl CallDef { return Err(syn::Error::new(method.sig.span(), msg)) } - let mut call_var_attrs: Vec = - helper::take_item_pallet_attrs(&mut method.attrs)?; - - if call_var_attrs.len() != 1 { - let msg = if call_var_attrs.is_empty() { + let (mut weight_attrs, mut call_idx_attrs): (Vec, Vec) = + helper::take_item_pallet_attrs(&mut method.attrs)?.into_iter().partition( + |attr| { + if let FunctionAttr::Weight(_) = attr { + true + } else { + false + } + }, + ); + + if weight_attrs.len() != 1 { + let msg = if weight_attrs.is_empty() { "Invalid pallet::call, requires weight attribute i.e. `#[pallet::weight($expr)]`" } else { "Invalid pallet::call, too many weight attributes given" }; return Err(syn::Error::new(method.sig.span(), msg)) } - let weight = call_var_attrs.pop().unwrap().weight; + let weight = match weight_attrs.pop().unwrap() { + FunctionAttr::Weight(w) => w, + _ => unreachable!("checked during creation of the let binding"), + }; + + if call_idx_attrs.len() > 1 { + let msg = "Invalid pallet::call, too many call_index attributes given"; + return Err(syn::Error::new(method.sig.span(), msg)) + } + let call_index = call_idx_attrs.pop().map(|attr| match attr { + FunctionAttr::CallIndex(idx) => idx, + _ => unreachable!("checked during creation of the let binding"), + }); + + let final_index = match call_index { + Some(i) => i, + None => + last_index.map_or(Some(0), |idx| idx.checked_add(1)).ok_or_else(|| { + let msg = "Call index doesn't fit into u8, index is 256"; + syn::Error::new(method.sig.span(), msg) + })?, + }; + last_index = Some(final_index); + + if let Some(used_fn) = indices.insert(final_index, method.sig.ident.clone()) { + let msg = format!( + "Call indices are conflicting: Both functions {} and {} are at index {}", + used_fn, method.sig.ident, final_index, + ); + let mut err = syn::Error::new(used_fn.span(), &msg); + err.combine(syn::Error::new(method.sig.ident.span(), msg)); + return Err(err) + } let mut args = vec![]; for arg in method.sig.inputs.iter_mut().skip(1) { @@ -223,7 +281,13 @@ impl CallDef { let docs = get_doc_literals(&method.attrs); - methods.push(CallVariantDef { name: method.sig.ident.clone(), weight, args, docs }); + methods.push(CallVariantDef { + name: method.sig.ident.clone(), + weight, + call_index: final_index, + args, + docs, + }); } else { let msg = "Invalid pallet::call, only method accepted"; return Err(syn::Error::new(impl_item.span(), msg)) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index d73a01187bfcc..03f1553293a47 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1553,6 +1553,15 @@ pub mod pallet_prelude { /// used using `#[pallet::compact]`, function must return `DispatchResultWithPostInfo` or /// `DispatchResult`. /// +/// Each dispatchable may also be annotated with the `#[pallet::call_index($idx)]` attribute, +/// which defines and sets the codec index for the dispatchable function in the `Call` enum. +/// +/// All call indexes start from 0, until it encounters a dispatchable function with a defined +/// call index. The dispatchable function that lexically follows the function with a defined +/// call index will have that call index, but incremented by 1, e.g. if there are 3 +/// dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` has +/// a call index of 10, then `fn qux` will have an index of 11, instead of 1. +/// /// All arguments must implement `Debug`, `PartialEq`, `Eq`, `Decode`, `Encode`, `Clone`. For /// ease of use, bound the trait `Member` available in frame_support::pallet_prelude. /// @@ -1566,16 +1575,18 @@ pub mod pallet_prelude { /// **WARNING**: modifying dispatchables, changing their order, removing some must be done with /// care. Indeed this will change the outer runtime call type (which is an enum with one /// variant per pallet), this outer runtime call can be stored on-chain (e.g. in -/// pallet-scheduler). Thus migration might be needed. +/// pallet-scheduler). Thus migration might be needed. To mitigate against some of this, the +/// `#[pallet::call_index($idx)]` attribute can be used to fix the order of the dispatchable so +/// that the `Call` enum encoding does not change after modification. /// /// ### Macro expansion /// -/// The macro create an enum `Call` with one variant per dispatchable. This enum implements: +/// The macro creates an enum `Call` with one variant per dispatchable. This enum implements: /// `Clone`, `Eq`, `PartialEq`, `Debug` (with stripped implementation in `not("std")`), /// `Encode`, `Decode`, `GetDispatchInfo`, `GetCallName`, `UnfilteredDispatchable`. /// -/// The macro implement on `Pallet`, the `Callable` trait and a function `call_functions` which -/// returns the dispatchable metadatas. +/// The macro implement the `Callable` trait on `Pallet` and a function `call_functions` which +/// returns the dispatchable metadata. /// /// # Extra constants: `#[pallet::extra_constants]` optional /// diff --git a/frame/support/test/tests/pallet_ui/call_conflicting_indices.rs b/frame/support/test/tests/pallet_ui/call_conflicting_indices.rs new file mode 100644 index 0000000000000..395766c7cd331 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_conflicting_indices.rs @@ -0,0 +1,24 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::DispatchResultWithPostInfo; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + #[pallet::call_index(10)] + pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} + + #[pallet::weight(0)] + #[pallet::call_index(10)] + pub fn bar(origin: OriginFor) -> DispatchResultWithPostInfo {} + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_conflicting_indices.stderr b/frame/support/test/tests/pallet_ui/call_conflicting_indices.stderr new file mode 100644 index 0000000000000..5d0c90609c2a1 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_conflicting_indices.stderr @@ -0,0 +1,11 @@ +error: Call indices are conflicting: Both functions foo and bar are at index 10 + --> tests/pallet_ui/call_conflicting_indices.rs:15:10 + | +15 | pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} + | ^^^ + +error: Call indices are conflicting: Both functions foo and bar are at index 10 + --> tests/pallet_ui/call_conflicting_indices.rs:19:10 + | +19 | pub fn bar(origin: OriginFor) -> DispatchResultWithPostInfo {} + | ^^^ diff --git a/frame/support/test/tests/pallet_ui/call_invalid_attr.rs b/frame/support/test/tests/pallet_ui/call_invalid_attr.rs new file mode 100644 index 0000000000000..118d3c92f360d --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_invalid_attr.rs @@ -0,0 +1,20 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::DispatchResultWithPostInfo; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call] + impl Pallet { + #[pallet::weird_attr] + pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr b/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr new file mode 100644 index 0000000000000..3f680203a262f --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_invalid_attr.stderr @@ -0,0 +1,5 @@ +error: expected `weight` or `call_index` + --> tests/pallet_ui/call_invalid_attr.rs:14:13 + | +14 | #[pallet::weird_attr] + | ^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/call_invalid_index.rs b/frame/support/test/tests/pallet_ui/call_invalid_index.rs new file mode 100644 index 0000000000000..0b40691ca43a3 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_invalid_index.rs @@ -0,0 +1,21 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::DispatchResultWithPostInfo; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + #[pallet::call_index(256)] + pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_invalid_index.stderr b/frame/support/test/tests/pallet_ui/call_invalid_index.stderr new file mode 100644 index 0000000000000..1e07a4974bf69 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_invalid_index.stderr @@ -0,0 +1,5 @@ +error: number too large to fit in target type + --> tests/pallet_ui/call_invalid_index.rs:15:24 + | +15 | #[pallet::call_index(256)] + | ^^^ diff --git a/frame/support/test/tests/pallet_ui/call_multiple_call_index.rs b/frame/support/test/tests/pallet_ui/call_multiple_call_index.rs new file mode 100644 index 0000000000000..5753ecd076c80 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_multiple_call_index.rs @@ -0,0 +1,22 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::DispatchResultWithPostInfo; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + #[pallet::call_index(1)] + #[pallet::call_index(2)] + pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_multiple_call_index.stderr b/frame/support/test/tests/pallet_ui/call_multiple_call_index.stderr new file mode 100644 index 0000000000000..ba22b012745c1 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_multiple_call_index.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::call, too many call_index attributes given + --> tests/pallet_ui/call_multiple_call_index.rs:17:7 + | +17 | pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} + | ^^ From 644e59a35322a1e5d69f1e7220cb14150b476ff8 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Mon, 23 May 2022 12:56:42 -0400 Subject: [PATCH 0839/1472] Create Script to Run All Benchmarks (#11493) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create run_all_benchmarks.sh * Update run_all_benchmarks.sh * Update run_all_benchmarks.sh * Review fixes Signed-off-by: Oliver Tale-Yazdi * Update scripts/run_all_benchmarks.sh Co-authored-by: Bastian Köcher * typo Signed-off-by: Oliver Tale-Yazdi * add default for $1 * Typo Signed-off-by: Oliver Tale-Yazdi * Update run_all_benchmarks.sh * new weights on benchmarking machine * prefer `--chain=dev` * fix compile * fix command * fmt * dont use square brackets * Extend doc Signed-off-by: Oliver Tale-Yazdi * Remove +nightly Signed-off-by: Oliver Tale-Yazdi * Add error file an run execute everything optimistically Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher --- frame/assets/src/weights.rs | 144 +- frame/bags-list/src/weights.rs | 20 +- frame/balances/src/weights.rs | 36 +- frame/benchmarking/src/weights.rs | 56 +- frame/bounties/src/weights.rs | 60 +- frame/child-bounties/src/weights.rs | 44 +- frame/collective/src/weights.rs | 136 +- frame/contracts/src/weights.rs | 1227 ++++++++--------- frame/conviction-voting/src/weights.rs | 54 +- frame/democracy/src/weights.rs | 172 ++- .../src/weights.rs | 116 +- frame/elections-phragmen/src/weights.rs | 104 +- frame/gilt/src/weights.rs | 64 +- frame/identity/src/weights.rs | 196 ++- frame/im-online/src/weights.rs | 20 +- frame/indices/src/weights.rs | 28 +- frame/lottery/src/weights.rs | 40 +- frame/membership/src/weights.rs | 68 +- frame/multisig/src/weights.rs | 104 +- frame/nomination-pools/src/weights.rs | 87 +- frame/preimage/src/weights.rs | 44 +- frame/proxy/src/weights.rs | 120 +- frame/recovery/src/weights.rs | 82 +- frame/referenda/src/weights.rs | 120 +- frame/remark/src/weights.rs | 12 +- frame/scheduler/src/weights.rs | 148 +- frame/session/src/weights.rs | 16 +- frame/staking/src/weights.rs | 310 ++--- frame/support/src/weights.rs | 5 +- frame/support/src/weights/block_weights.rs | 81 +- .../support/src/weights/extrinsic_weights.rs | 81 +- frame/system/src/weights.rs | 28 +- frame/timestamp/src/weights.rs | 16 +- frame/tips/src/weights.rs | 56 +- frame/transaction-storage/src/weights.rs | 16 +- frame/treasury/src/weights.rs | 39 +- frame/uniques/src/weights.rs | 127 +- frame/utility/src/weights.rs | 40 +- frame/vesting/src/weights.rs | 112 +- frame/whitelist/src/weights.rs | 28 +- scripts/run_all_benchmarks.sh | 163 +++ .../benchmarking-cli/src/overhead/weights.hbs | 6 +- .../benchmarking-cli/src/storage/weights.hbs | 8 +- 43 files changed, 2291 insertions(+), 2143 deletions(-) create mode 100755 scripts/run_all_benchmarks.sh diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index a1cd77faee82e..453df22902ba2 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/assets/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -76,13 +74,13 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (22_102_000 as Weight) + (23_081_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (12_124_000 as Weight) + (12_782_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -93,12 +91,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 34_000 - .saturating_add((14_683_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 34_000 - .saturating_add((17_080_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 342_000 - .saturating_add((16_533_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 36_000 + .saturating_add((15_327_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 36_000 + .saturating_add((17_817_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 362_000 + .saturating_add((16_692_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) @@ -111,14 +109,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (26_632_000 as Weight) + (25_993_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (30_048_000 as Weight) + (30_795_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -126,7 +124,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (44_000_000 as Weight) + (44_054_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -134,7 +132,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (37_286_000 as Weight) + (36_948_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -142,95 +140,87 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (44_120_000 as Weight) + (44_446_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (18_309_000 as Weight) + (18_381_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (18_290_000 as Weight) + (18_215_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (14_744_000 as Weight) + (14_885_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (14_833_000 as Weight) + (14_834_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (16_654_000 as Weight) + (16_033_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (15_351_000 as Weight) + (14_344_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn set_metadata(n: u32, s: u32, ) -> Weight { - (27_588_000 as Weight) - // Standard Error: 0 - .saturating_add((6_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(s as Weight)) + fn set_metadata(_n: u32, _s: u32, ) -> Weight { + (27_805_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (27_710_000 as Weight) + (28_466_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn force_set_metadata(n: u32, s: u32, ) -> Weight { - (15_345_000 as Weight) - // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) + fn force_set_metadata(_n: u32, _s: u32, ) -> Weight { + (15_604_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (27_552_000 as Weight) + (28_278_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (13_755_000 as Weight) + (13_556_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (30_831_000 as Weight) + (31_252_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -239,21 +229,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (56_267_000 as Weight) + (55_281_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (31_964_000 as Weight) + (30_784_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - (31_806_000 as Weight) + (32_011_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -263,13 +253,13 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (22_102_000 as Weight) + (23_081_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (12_124_000 as Weight) + (12_782_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -280,12 +270,12 @@ impl WeightInfo for () { // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 34_000 - .saturating_add((14_683_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 34_000 - .saturating_add((17_080_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 342_000 - .saturating_add((16_533_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 36_000 + .saturating_add((15_327_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 36_000 + .saturating_add((17_817_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 362_000 + .saturating_add((16_692_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) @@ -298,14 +288,14 @@ impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (26_632_000 as Weight) + (25_993_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (30_048_000 as Weight) + (30_795_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -313,7 +303,7 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (44_000_000 as Weight) + (44_054_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -321,7 +311,7 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (37_286_000 as Weight) + (36_948_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -329,95 +319,87 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (44_120_000 as Weight) + (44_446_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (18_309_000 as Weight) + (18_381_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (18_290_000 as Weight) + (18_215_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (14_744_000 as Weight) + (14_885_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (14_833_000 as Weight) + (14_834_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (16_654_000 as Weight) + (16_033_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (15_351_000 as Weight) + (14_344_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn set_metadata(n: u32, s: u32, ) -> Weight { - (27_588_000 as Weight) - // Standard Error: 0 - .saturating_add((6_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(s as Weight)) + fn set_metadata(_n: u32, _s: u32, ) -> Weight { + (27_805_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (27_710_000 as Weight) + (28_466_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn force_set_metadata(n: u32, s: u32, ) -> Weight { - (15_345_000 as Weight) - // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) + fn force_set_metadata(_n: u32, _s: u32, ) -> Weight { + (15_604_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (27_552_000 as Weight) + (28_278_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (13_755_000 as Weight) + (13_556_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (30_831_000 as Weight) + (31_252_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -426,21 +408,21 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (56_267_000 as Weight) + (55_281_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (31_964_000 as Weight) + (30_784_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - (31_806_000 as Weight) + (32_011_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index f35c0aaee6d6a..8a8a14a75218d 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_bags_list //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/bags-list/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -59,7 +57,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (46_965_000 as Weight) + (51_415_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -68,7 +66,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (45_952_000 as Weight) + (49_459_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -78,7 +76,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (52_928_000 as Weight) + (53_682_000 as Weight) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -91,7 +89,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (46_965_000 as Weight) + (51_415_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -100,7 +98,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (45_952_000 as Weight) + (49_459_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -110,7 +108,7 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (52_928_000 as Weight) + (53_682_000 as Weight) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index 435438055b333..dd22e7ca778f8 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_balances //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/balances/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -60,43 +58,43 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (34_200_000 as Weight) + (35_278_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (27_263_000 as Weight) + (27_822_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (17_425_000 as Weight) + (17_943_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (19_979_000 as Weight) + (20_974_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (34_783_000 as Weight) + (36_078_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (31_620_000 as Weight) + (32_794_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (15_750_000 as Weight) + (16_227_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -106,43 +104,43 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (34_200_000 as Weight) + (35_278_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (27_263_000 as Weight) + (27_822_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (17_425_000 as Weight) + (17_943_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (19_979_000 as Weight) + (20_974_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (34_783_000 as Weight) + (36_078_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (31_620_000 as Weight) + (32_794_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (15_750_000 as Weight) + (16_227_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index a49204fbf0b90..24643bb391152 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for frame_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/benchmarking/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -60,37 +58,39 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn addition(_i: u32, ) -> Weight { - (106_000 as Weight) + (126_000 as Weight) } fn subtraction(_i: u32, ) -> Weight { - (111_000 as Weight) + (121_000 as Weight) } fn multiplication(_i: u32, ) -> Weight { - (119_000 as Weight) + (132_000 as Weight) } fn division(_i: u32, ) -> Weight { - (111_000 as Weight) + (122_000 as Weight) } - fn hashing(_i: u32, ) -> Weight { - (21_203_386_000 as Weight) + fn hashing(i: u32, ) -> Weight { + (21_059_079_000 as Weight) + // Standard Error: 117_000 + .saturating_add((1_121_000 as Weight).saturating_mul(i as Weight)) } fn sr25519_verification(i: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 6_000 - .saturating_add((47_077_000 as Weight).saturating_mul(i as Weight)) + (425_000 as Weight) + // Standard Error: 7_000 + .saturating_add((47_172_000 as Weight).saturating_mul(i as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((1_963_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((2_118_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((364_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((373_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } } @@ -98,37 +98,39 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn addition(_i: u32, ) -> Weight { - (106_000 as Weight) + (126_000 as Weight) } fn subtraction(_i: u32, ) -> Weight { - (111_000 as Weight) + (121_000 as Weight) } fn multiplication(_i: u32, ) -> Weight { - (119_000 as Weight) + (132_000 as Weight) } fn division(_i: u32, ) -> Weight { - (111_000 as Weight) + (122_000 as Weight) } - fn hashing(_i: u32, ) -> Weight { - (21_203_386_000 as Weight) + fn hashing(i: u32, ) -> Weight { + (21_059_079_000 as Weight) + // Standard Error: 117_000 + .saturating_add((1_121_000 as Weight).saturating_mul(i as Weight)) } fn sr25519_verification(i: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 6_000 - .saturating_add((47_077_000 as Weight).saturating_mul(i as Weight)) + (425_000 as Weight) + // Standard Error: 7_000 + .saturating_add((47_172_000 as Weight).saturating_mul(i as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((1_963_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((2_118_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((364_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((373_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 405e11acea5aa..a1019b3e5c52c 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/bounties/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -67,43 +65,43 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(d: u32, ) -> Weight { - (23_620_000 as Weight) + (25_277_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (6_655_000 as Weight) + (7_646_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (5_720_000 as Weight) + (5_712_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (26_958_000 as Weight) + (25_220_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (21_457_000 as Weight) + (21_985_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (17_483_000 as Weight) + (18_341_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -112,7 +110,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (61_763_000 as Weight) + (63_146_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -121,7 +119,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (28_862_000 as Weight) + (29_362_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -130,13 +128,13 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (45_129_000 as Weight) + (46_519_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (15_169_000 as Weight) + (15_363_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -145,8 +143,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { (0 as Weight) - // Standard Error: 14_000 - .saturating_add((28_850_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 18_000 + .saturating_add((29_482_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -161,43 +159,43 @@ impl WeightInfo for () { // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(d: u32, ) -> Weight { - (23_620_000 as Weight) + (25_277_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (6_655_000 as Weight) + (7_646_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (5_720_000 as Weight) + (5_712_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (26_958_000 as Weight) + (25_220_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (21_457_000 as Weight) + (21_985_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (17_483_000 as Weight) + (18_341_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -206,7 +204,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (61_763_000 as Weight) + (63_146_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -215,7 +213,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (28_862_000 as Weight) + (29_362_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -224,13 +222,13 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (45_129_000 as Weight) + (46_519_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (15_169_000 as Weight) + (15_363_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -239,8 +237,8 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { (0 as Weight) - // Standard Error: 14_000 - .saturating_add((28_850_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 18_000 + .saturating_add((29_482_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index 002388810b8a0..d11de89bcf5c3 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_child_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/child-bounties/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -66,9 +64,9 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) fn add_child_bounty(d: u32, ) -> Weight { - (44_503_000 as Weight) + (45_917_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -76,7 +74,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - (11_661_000 as Weight) + (11_855_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -84,7 +82,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (24_162_000 as Weight) + (24_488_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -92,14 +90,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (27_924_000 as Weight) + (28_645_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - (19_332_000 as Weight) + (19_760_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -108,7 +106,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - (60_363_000 as Weight) + (62_194_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -119,7 +117,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - (42_415_000 as Weight) + (44_136_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -130,7 +128,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - (52_743_000 as Weight) + (53_168_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -145,9 +143,9 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) fn add_child_bounty(d: u32, ) -> Weight { - (44_503_000 as Weight) + (45_917_000 as Weight) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -155,7 +153,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - (11_661_000 as Weight) + (11_855_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -163,7 +161,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (24_162_000 as Weight) + (24_488_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -171,14 +169,14 @@ impl WeightInfo for () { // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (27_924_000 as Weight) + (28_645_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - (19_332_000 as Weight) + (19_760_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -187,7 +185,7 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - (60_363_000 as Weight) + (62_194_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -198,7 +196,7 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - (42_415_000 as Weight) + (44_136_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -209,7 +207,7 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - (52_743_000 as Weight) + (53_168_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index 1280ced89eeea..6392f86de6530 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/collective/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -67,12 +65,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { (0 as Weight) - // Standard Error: 10_000 - .saturating_add((14_493_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 10_000 - .saturating_add((23_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 10_000 - .saturating_add((16_909_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 8_000 + .saturating_add((10_362_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 8_000 + .saturating_add((56_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 8_000 + .saturating_add((13_187_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(p as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -80,21 +78,21 @@ impl WeightInfo for SubstrateWeight { } // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - (12_790_000 as Weight) + (13_571_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((73_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((31_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - (15_087_000 as Weight) + (15_851_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((135_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) } // Storage: Council Members (r:1 w:0) @@ -103,22 +101,22 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - (18_269_000 as Weight) + (19_593_000 as Weight) // Standard Error: 0 - .saturating_add((8_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((7_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((77_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((40_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((203_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((165_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - (26_624_000 as Weight) + (27_221_000 as Weight) // Standard Error: 2_000 - .saturating_add((161_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((82_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -127,11 +125,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - (26_527_000 as Weight) + (26_295_000 as Weight) // Standard Error: 1_000 - .saturating_add((127_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((155_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((130_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -140,13 +138,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - (26_352_000 as Weight) + (28_609_000 as Weight) // Standard Error: 0 .saturating_add((6_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((154_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((68_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((203_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((161_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -156,11 +154,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - (28_638_000 as Weight) + (30_497_000 as Weight) // Standard Error: 1_000 - .saturating_add((133_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((162_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -170,13 +168,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - (29_946_000 as Weight) + (31_402_000 as Weight) // Standard Error: 0 .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) - // Standard Error: 2_000 - .saturating_add((151_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 2_000 - .saturating_add((201_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 1_000 + .saturating_add((73_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 1_000 + .saturating_add((159_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -184,9 +182,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - (15_778_000 as Weight) + (16_391_000 as Weight) // Standard Error: 1_000 - .saturating_add((206_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((169_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -200,12 +198,12 @@ impl WeightInfo for () { // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { (0 as Weight) - // Standard Error: 10_000 - .saturating_add((14_493_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 10_000 - .saturating_add((23_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 10_000 - .saturating_add((16_909_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 8_000 + .saturating_add((10_362_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 8_000 + .saturating_add((56_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 8_000 + .saturating_add((13_187_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(p as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -213,21 +211,21 @@ impl WeightInfo for () { } // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - (12_790_000 as Weight) + (13_571_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((73_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((31_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - (15_087_000 as Weight) + (15_851_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((135_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) } // Storage: Council Members (r:1 w:0) @@ -236,22 +234,22 @@ impl WeightInfo for () { // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - (18_269_000 as Weight) + (19_593_000 as Weight) // Standard Error: 0 - .saturating_add((8_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((7_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((77_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((40_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((203_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((165_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - (26_624_000 as Weight) + (27_221_000 as Weight) // Standard Error: 2_000 - .saturating_add((161_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((82_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -260,11 +258,11 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - (26_527_000 as Weight) + (26_295_000 as Weight) // Standard Error: 1_000 - .saturating_add((127_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((155_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((130_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -273,13 +271,13 @@ impl WeightInfo for () { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - (26_352_000 as Weight) + (28_609_000 as Weight) // Standard Error: 0 .saturating_add((6_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((154_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((68_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((203_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((161_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -289,11 +287,11 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - (28_638_000 as Weight) + (30_497_000 as Weight) // Standard Error: 1_000 - .saturating_add((133_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((162_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -303,13 +301,13 @@ impl WeightInfo for () { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - (29_946_000 as Weight) + (31_402_000 as Weight) // Standard Error: 0 .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) - // Standard Error: 2_000 - .saturating_add((151_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 2_000 - .saturating_add((201_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 1_000 + .saturating_add((73_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 1_000 + .saturating_add((159_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -317,9 +315,9 @@ impl WeightInfo for () { // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - (15_778_000 as Weight) + (16_391_000 as Weight) // Standard Error: 1_000 - .saturating_add((206_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((169_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 256e0ffc9d808..c6e83d34e90b1 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -32,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/contracts/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/contracts/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -165,12 +164,12 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_641_000 as Weight) + (1_684_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (11_282_000 as Weight) + (11_878_000 as Weight) // Standard Error: 0 .saturating_add((758_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -179,18 +178,18 @@ impl WeightInfo for SubstrateWeight { } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 5_000 - .saturating_add((1_892_000 as Weight).saturating_mul(q as Weight)) + (10_240_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_899_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (19_908_000 as Weight) + (18_012_000 as Weight) // Standard Error: 0 - .saturating_add((48_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -199,9 +198,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_per_byte(c: u32, ) -> Weight { - (200_315_000 as Weight) + (206_036_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -213,9 +212,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (252_036_000 as Weight) + (243_162_000 as Weight) // Standard Error: 0 - .saturating_add((121_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((122_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) @@ -228,7 +227,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (177_274_000 as Weight) + (180_607_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) @@ -239,7 +238,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (146_086_000 as Weight) + (146_032_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -247,7 +246,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (43_995_000 as Weight) + (45_113_000 as Weight) // Standard Error: 0 .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -257,14 +256,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (25_007_000 as Weight) + (25_722_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) fn set_code() -> Weight { - (22_940_000 as Weight) + (23_135_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -273,9 +272,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (207_387_000 as Weight) - // Standard Error: 88_000 - .saturating_add((40_577_000 as Weight).saturating_mul(r as Weight)) + (205_061_000 as Weight) + // Standard Error: 76_000 + .saturating_add((40_732_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -284,9 +283,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (96_692_000 as Weight) - // Standard Error: 688_000 - .saturating_add((313_348_000 as Weight).saturating_mul(r as Weight)) + (97_971_000 as Weight) + // Standard Error: 741_000 + .saturating_add((308_361_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -296,9 +295,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_code_hash(r: u32, ) -> Weight { - (107_076_000 as Weight) - // Standard Error: 721_000 - .saturating_add((370_976_000 as Weight).saturating_mul(r as Weight)) + (109_052_000 as Weight) + // Standard Error: 716_000 + .saturating_add((366_257_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -308,9 +307,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_own_code_hash(r: u32, ) -> Weight { - (207_147_000 as Weight) - // Standard Error: 112_000 - .saturating_add((43_974_000 as Weight).saturating_mul(r as Weight)) + (205_748_000 as Weight) + // Standard Error: 87_000 + .saturating_add((44_474_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -319,9 +318,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (203_029_000 as Weight) - // Standard Error: 31_000 - .saturating_add((16_811_000 as Weight).saturating_mul(r as Weight)) + (201_898_000 as Weight) + // Standard Error: 55_000 + .saturating_add((16_703_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -330,9 +329,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (206_641_000 as Weight) - // Standard Error: 86_000 - .saturating_add((40_239_000 as Weight).saturating_mul(r as Weight)) + (204_668_000 as Weight) + // Standard Error: 65_000 + .saturating_add((40_459_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -341,9 +340,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (205_195_000 as Weight) - // Standard Error: 85_000 - .saturating_add((39_915_000 as Weight).saturating_mul(r as Weight)) + (203_240_000 as Weight) + // Standard Error: 68_000 + .saturating_add((40_270_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -352,9 +351,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (213_345_000 as Weight) - // Standard Error: 126_000 - .saturating_add((116_249_000 as Weight).saturating_mul(r as Weight)) + (211_535_000 as Weight) + // Standard Error: 73_000 + .saturating_add((114_954_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -363,9 +362,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (206_141_000 as Weight) - // Standard Error: 96_000 - .saturating_add((39_999_000 as Weight).saturating_mul(r as Weight)) + (204_653_000 as Weight) + // Standard Error: 71_000 + .saturating_add((40_188_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -374,9 +373,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (205_569_000 as Weight) - // Standard Error: 104_000 - .saturating_add((40_046_000 as Weight).saturating_mul(r as Weight)) + (204_690_000 as Weight) + // Standard Error: 82_000 + .saturating_add((40_260_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -385,9 +384,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (205_782_000 as Weight) - // Standard Error: 89_000 - .saturating_add((39_757_000 as Weight).saturating_mul(r as Weight)) + (205_004_000 as Weight) + // Standard Error: 62_000 + .saturating_add((40_018_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -396,9 +395,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (205_465_000 as Weight) - // Standard Error: 87_000 - .saturating_add((39_605_000 as Weight).saturating_mul(r as Weight)) + (204_341_000 as Weight) + // Standard Error: 93_000 + .saturating_add((39_920_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -408,9 +407,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (208_900_000 as Weight) - // Standard Error: 108_000 - .saturating_add((101_341_000 as Weight).saturating_mul(r as Weight)) + (208_702_000 as Weight) + // Standard Error: 115_000 + .saturating_add((101_441_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -419,9 +418,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (132_788_000 as Weight) - // Standard Error: 22_000 - .saturating_add((19_129_000 as Weight).saturating_mul(r as Weight)) + (131_983_000 as Weight) + // Standard Error: 17_000 + .saturating_add((19_153_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -430,9 +429,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (205_111_000 as Weight) - // Standard Error: 96_000 - .saturating_add((39_317_000 as Weight).saturating_mul(r as Weight)) + (203_768_000 as Weight) + // Standard Error: 57_000 + .saturating_add((39_316_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -441,9 +440,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (263_644_000 as Weight) + (273_930_000 as Weight) // Standard Error: 3_000 - .saturating_add((9_593_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((9_513_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -452,9 +451,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (201_299_000 as Weight) - // Standard Error: 903_000 - .saturating_add((947_000 as Weight).saturating_mul(r as Weight)) + (199_311_000 as Weight) + // Standard Error: 601_000 + .saturating_add((2_181_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -463,9 +462,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (202_730_000 as Weight) + (201_130_000 as Weight) // Standard Error: 0 - .saturating_add((183_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((184_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -476,9 +475,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (203_795_000 as Weight) - // Standard Error: 759_000 - .saturating_add((52_720_000 as Weight).saturating_mul(r as Weight)) + (202_063_000 as Weight) + // Standard Error: 100_000 + .saturating_add((54_190_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -490,9 +489,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (215_805_000 as Weight) - // Standard Error: 158_000 - .saturating_add((127_687_000 as Weight).saturating_mul(r as Weight)) + (206_528_000 as Weight) + // Standard Error: 120_000 + .saturating_add((136_384_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -501,9 +500,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (215_300_000 as Weight) - // Standard Error: 143_000 - .saturating_add((229_183_000 as Weight).saturating_mul(r as Weight)) + (210_309_000 as Weight) + // Standard Error: 138_000 + .saturating_add((236_583_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -513,11 +512,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:80 w:80) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (459_865_000 as Weight) - // Standard Error: 1_733_000 - .saturating_add((235_448_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 341_000 - .saturating_add((66_363_000 as Weight).saturating_mul(n as Weight)) + (434_046_000 as Weight) + // Standard Error: 1_678_000 + .saturating_add((242_928_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 330_000 + .saturating_add((66_716_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -528,17 +527,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (137_820_000 as Weight) - // Standard Error: 77_000 - .saturating_add((31_956_000 as Weight).saturating_mul(r as Weight)) + (138_934_000 as Weight) + // Standard Error: 34_000 + .saturating_add((31_927_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (94_007_000 as Weight) - // Standard Error: 589_000 - .saturating_add((328_631_000 as Weight).saturating_mul(r as Weight)) + (88_315_000 as Weight) + // Standard Error: 594_000 + .saturating_add((328_984_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -546,25 +545,25 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (528_794_000 as Weight) - // Standard Error: 233_000 - .saturating_add((21_533_000 as Weight).saturating_mul(n as Weight)) + (529_349_000 as Weight) + // Standard Error: 223_000 + .saturating_add((21_065_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(85 as Weight)) .saturating_add(T::DbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (543_507_000 as Weight) - // Standard Error: 270_000 - .saturating_add((9_142_000 as Weight).saturating_mul(n as Weight)) + (546_447_000 as Weight) + // Standard Error: 261_000 + .saturating_add((8_709_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(85 as Weight)) .saturating_add(T::DbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (129_893_000 as Weight) - // Standard Error: 471_000 - .saturating_add((313_807_000 as Weight).saturating_mul(r as Weight)) + (118_849_000 as Weight) + // Standard Error: 518_000 + .saturating_add((309_800_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -572,51 +571,51 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (532_323_000 as Weight) - // Standard Error: 204_000 - .saturating_add((8_729_000 as Weight).saturating_mul(n as Weight)) + (537_039_000 as Weight) + // Standard Error: 235_000 + .saturating_add((8_071_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(85 as Weight)) .saturating_add(T::DbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (131_771_000 as Weight) - // Standard Error: 415_000 - .saturating_add((269_174_000 as Weight).saturating_mul(r as Weight)) + (125_427_000 as Weight) + // Standard Error: 635_000 + .saturating_add((276_126_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (494_409_000 as Weight) - // Standard Error: 280_000 - .saturating_add((50_499_000 as Weight).saturating_mul(n as Weight)) + (500_356_000 as Weight) + // Standard Error: 279_000 + .saturating_add((49_746_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(84 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (133_366_000 as Weight) - // Standard Error: 400_000 - .saturating_add((235_761_000 as Weight).saturating_mul(r as Weight)) + (129_046_000 as Weight) + // Standard Error: 408_000 + .saturating_add((237_117_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (447_828_000 as Weight) - // Standard Error: 197_000 - .saturating_add((8_190_000 as Weight).saturating_mul(n as Weight)) + (451_122_000 as Weight) + // Standard Error: 200_000 + .saturating_add((7_750_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(84 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (121_933_000 as Weight) - // Standard Error: 509_000 - .saturating_add((342_550_000 as Weight).saturating_mul(r as Weight)) + (118_085_000 as Weight) + // Standard Error: 526_000 + .saturating_add((338_332_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -624,9 +623,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (578_648_000 as Weight) - // Standard Error: 320_000 - .saturating_add((51_767_000 as Weight).saturating_mul(n as Weight)) + (569_270_000 as Weight) + // Standard Error: 294_000 + .saturating_add((51_071_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(85 as Weight)) .saturating_add(T::DbWeight::get().writes(83 as Weight)) } @@ -635,9 +634,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (146_890_000 as Weight) - // Standard Error: 789_000 - .saturating_add((1_427_230_000 as Weight).saturating_mul(r as Weight)) + (124_818_000 as Weight) + // Standard Error: 1_251_000 + .saturating_add((1_455_607_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -649,8 +648,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_542_000 - .saturating_add((15_063_367_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 4_575_000 + .saturating_add((14_645_061_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -662,8 +661,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_267_000 - .saturating_add((15_037_276_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 5_742_000 + .saturating_add((14_623_917_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -672,11 +671,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (9_081_513_000 as Weight) - // Standard Error: 18_081_000 - .saturating_add((1_388_391_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 7_000 - .saturating_add((9_653_000 as Weight).saturating_mul(c as Weight)) + (9_081_635_000 as Weight) + // Standard Error: 11_326_000 + .saturating_add((1_335_139_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 4_000 + .saturating_add((9_575_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(85 as Weight)) .saturating_add(T::DbWeight::get().reads((81 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(81 as Weight)) @@ -690,8 +689,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:80 w:80) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 34_560_000 - .saturating_add((20_828_575_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 34_958_000 + .saturating_add((20_700_850_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((320 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -704,11 +703,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (12_124_898_000 as Weight) - // Standard Error: 34_430_000 - .saturating_add((573_971_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 16_000 - .saturating_add((123_415_000 as Weight).saturating_mul(s as Weight)) + (12_091_206_000 as Weight) + // Standard Error: 104_884_000 + .saturating_add((635_259_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 49_000 + .saturating_add((122_935_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(167 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(165 as Weight)) @@ -719,9 +718,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (203_422_000 as Weight) - // Standard Error: 126_000 - .saturating_add((65_317_000 as Weight).saturating_mul(r as Weight)) + (203_315_000 as Weight) + // Standard Error: 74_000 + .saturating_add((60_223_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -730,9 +729,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (411_079_000 as Weight) - // Standard Error: 20_000 - .saturating_add((354_947_000 as Weight).saturating_mul(n as Weight)) + (355_672_000 as Weight) + // Standard Error: 25_000 + .saturating_add((319_519_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -741,9 +740,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (203_192_000 as Weight) - // Standard Error: 116_000 - .saturating_add((73_562_000 as Weight).saturating_mul(r as Weight)) + (203_117_000 as Weight) + // Standard Error: 94_000 + .saturating_add((77_363_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -752,9 +751,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (227_572_000 as Weight) + (196_575_000 as Weight) // Standard Error: 13_000 - .saturating_add((244_646_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((243_479_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -763,9 +762,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (204_922_000 as Weight) - // Standard Error: 112_000 - .saturating_add((51_349_000 as Weight).saturating_mul(r as Weight)) + (203_938_000 as Weight) + // Standard Error: 97_000 + .saturating_add((50_708_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -774,9 +773,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (247_293_000 as Weight) - // Standard Error: 17_000 - .saturating_add((94_654_000 as Weight).saturating_mul(n as Weight)) + (247_065_000 as Weight) + // Standard Error: 8_000 + .saturating_add((94_160_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -785,9 +784,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (203_511_000 as Weight) - // Standard Error: 108_000 - .saturating_add((50_585_000 as Weight).saturating_mul(r as Weight)) + (204_389_000 as Weight) + // Standard Error: 86_000 + .saturating_add((50_663_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -796,9 +795,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (253_133_000 as Weight) - // Standard Error: 10_000 - .saturating_add((94_606_000 as Weight).saturating_mul(n as Weight)) + (284_700_000 as Weight) + // Standard Error: 9_000 + .saturating_add((94_231_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -807,9 +806,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (280_685_000 as Weight) - // Standard Error: 627_000 - .saturating_add((3_062_997_000 as Weight).saturating_mul(r as Weight)) + (235_813_000 as Weight) + // Standard Error: 521_000 + .saturating_add((3_044_204_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -818,9 +817,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - (212_204_000 as Weight) - // Standard Error: 469_000 - .saturating_add((2_034_397_000 as Weight).saturating_mul(r as Weight)) + (204_095_000 as Weight) + // Standard Error: 495_000 + .saturating_add((2_027_914_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -831,265 +830,265 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:16 w:16) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_507_000 - .saturating_add((747_481_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_604_000 + .saturating_add((759_511_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes((79 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (74_627_000 as Weight) + (74_210_000 as Weight) // Standard Error: 1_000 - .saturating_add((593_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((601_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_587_000 as Weight) + (74_123_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_294_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_315_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_392_000 as Weight) + (74_145_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_381_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_388_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (73_823_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_780_000 as Weight).saturating_mul(r as Weight)) + (73_931_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_768_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (74_072_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_946_000 as Weight).saturating_mul(r as Weight)) + (73_829_000 as Weight) + // Standard Error: 0 + .saturating_add((1_957_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_981_000 as Weight) - // Standard Error: 1_000 - .saturating_add((930_000 as Weight).saturating_mul(r as Weight)) + (73_760_000 as Weight) + // Standard Error: 0 + .saturating_add((932_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_690_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_433_000 as Weight).saturating_mul(r as Weight)) + (73_714_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_420_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (74_317_000 as Weight) - // Standard Error: 8_000 - .saturating_add((1_571_000 as Weight).saturating_mul(r as Weight)) + (73_496_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_575_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_373_000 as Weight) + (76_036_000 as Weight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (76_013_000 as Weight) - // Standard Error: 10_000 - .saturating_add((6_848_000 as Weight).saturating_mul(r as Weight)) + (76_015_000 as Weight) + // Standard Error: 19_000 + .saturating_add((6_954_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (88_704_000 as Weight) - // Standard Error: 16_000 - .saturating_add((8_824_000 as Weight).saturating_mul(r as Weight)) + (88_247_000 as Weight) + // Standard Error: 9_000 + .saturating_add((8_957_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (97_846_000 as Weight) - // Standard Error: 1_000 - .saturating_add((471_000 as Weight).saturating_mul(p as Weight)) + (98_336_000 as Weight) + // Standard Error: 2_000 + .saturating_add((474_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (75_010_000 as Weight) - // Standard Error: 1_000 - .saturating_add((612_000 as Weight).saturating_mul(r as Weight)) + (74_565_000 as Weight) + // Standard Error: 4_000 + .saturating_add((627_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_636_000 as Weight) + (74_414_000 as Weight) // Standard Error: 1_000 - .saturating_add((681_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((684_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_196_000 as Weight) - // Standard Error: 0 - .saturating_add((916_000 as Weight).saturating_mul(r as Weight)) + (74_346_000 as Weight) + // Standard Error: 1_000 + .saturating_add((911_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_349_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_176_000 as Weight).saturating_mul(r as Weight)) + (76_649_000 as Weight) + // Standard Error: 0 + .saturating_add((1_183_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (76_861_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_383_000 as Weight).saturating_mul(r as Weight)) + (76_995_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_696_000 as Weight) - // Standard Error: 2_000 - .saturating_add((655_000 as Weight).saturating_mul(r as Weight)) + (73_927_000 as Weight) + // Standard Error: 1_000 + .saturating_add((666_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_522_000 as Weight) - // Standard Error: 50_000 - .saturating_add((179_720_000 as Weight).saturating_mul(r as Weight)) + (73_479_000 as Weight) + // Standard Error: 24_000 + .saturating_add((180_808_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_292_000 as Weight) + (74_048_000 as Weight) // Standard Error: 1_000 - .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_299_000 as Weight) + (73_894_000 as Weight) // Standard Error: 1_000 - .saturating_add((882_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_289_000 as Weight) - // Standard Error: 1_000 - .saturating_add((883_000 as Weight).saturating_mul(r as Weight)) + (73_728_000 as Weight) + // Standard Error: 0 + .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_120_000 as Weight) - // Standard Error: 2_000 - .saturating_add((899_000 as Weight).saturating_mul(r as Weight)) + (74_049_000 as Weight) + // Standard Error: 1_000 + .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_599_000 as Weight) + (74_118_000 as Weight) // Standard Error: 1_000 - .saturating_add((851_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((863_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_622_000 as Weight) - // Standard Error: 2_000 - .saturating_add((854_000 as Weight).saturating_mul(r as Weight)) + (74_042_000 as Weight) + // Standard Error: 1_000 + .saturating_add((865_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_504_000 as Weight) - // Standard Error: 2_000 - .saturating_add((874_000 as Weight).saturating_mul(r as Weight)) + (73_885_000 as Weight) + // Standard Error: 1_000 + .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (74_532_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (73_788_000 as Weight) + // Standard Error: 0 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (74_130_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (73_727_000 as Weight) + // Standard Error: 0 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (74_172_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) + (73_825_000 as Weight) + // Standard Error: 0 + .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_356_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (73_638_000 as Weight) + // Standard Error: 0 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (74_181_000 as Weight) + (73_688_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (74_045_000 as Weight) + (73_895_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (74_246_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) + (73_860_000 as Weight) + // Standard Error: 0 + .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (73_998_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + (73_864_000 as Weight) + // Standard Error: 0 + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (74_035_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) + (72_730_000 as Weight) + // Standard Error: 7_000 + .saturating_add((1_432_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_511_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) + (73_998_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_346_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (74_305_000 as Weight) + (73_708_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_319_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_214_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_321_000 as Weight).saturating_mul(r as Weight)) + (74_033_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_322_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (74_073_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_323_000 as Weight).saturating_mul(r as Weight)) + (74_203_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_322_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (74_295_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_986_000 as Weight).saturating_mul(r as Weight)) + (73_990_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_010_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (74_109_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_023_000 as Weight).saturating_mul(r as Weight)) + (73_918_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_019_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (73_990_000 as Weight) + (73_927_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_993_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_001_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (73_940_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_056_000 as Weight).saturating_mul(r as Weight)) + (73_691_000 as Weight) + // Standard Error: 0 + .saturating_add((2_062_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_261_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_326_000 as Weight).saturating_mul(r as Weight)) + (73_869_000 as Weight) + // Standard Error: 0 + .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (74_014_000 as Weight) + (73_890_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (74_220_000 as Weight) + (73_866_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_323_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (74_139_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) + (73_793_000 as Weight) + // Standard Error: 0 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (73_923_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + (73_695_000 as Weight) + // Standard Error: 0 + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (73_999_000 as Weight) - // Standard Error: 1_000 + (73_743_000 as Weight) + // Standard Error: 0 .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (74_312_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) + (73_781_000 as Weight) + // Standard Error: 0 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (73_988_000 as Weight) + (73_941_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) } } @@ -1097,12 +1096,12 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize() -> Weight { - (1_641_000 as Weight) + (1_684_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (11_282_000 as Weight) + (11_878_000 as Weight) // Standard Error: 0 .saturating_add((758_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -1111,18 +1110,18 @@ impl WeightInfo for () { } // Storage: Contracts DeletionQueue (r:1 w:0) fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 5_000 - .saturating_add((1_892_000 as Weight).saturating_mul(q as Weight)) + (10_240_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_899_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) fn reinstrument(c: u32, ) -> Weight { - (19_908_000 as Weight) + (18_012_000 as Weight) // Standard Error: 0 - .saturating_add((48_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1131,9 +1130,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call_with_code_per_byte(c: u32, ) -> Weight { - (200_315_000 as Weight) + (206_036_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1145,9 +1144,9 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (252_036_000 as Weight) + (243_162_000 as Weight) // Standard Error: 0 - .saturating_add((121_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((122_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) @@ -1160,7 +1159,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { - (177_274_000 as Weight) + (180_607_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) @@ -1171,7 +1170,7 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (146_086_000 as Weight) + (146_032_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1179,7 +1178,7 @@ impl WeightInfo for () { // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) fn upload_code(c: u32, ) -> Weight { - (43_995_000 as Weight) + (45_113_000 as Weight) // Standard Error: 0 .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -1189,14 +1188,14 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (25_007_000 as Weight) + (25_722_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) fn set_code() -> Weight { - (22_940_000 as Weight) + (23_135_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1205,9 +1204,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller(r: u32, ) -> Weight { - (207_387_000 as Weight) - // Standard Error: 88_000 - .saturating_add((40_577_000 as Weight).saturating_mul(r as Weight)) + (205_061_000 as Weight) + // Standard Error: 76_000 + .saturating_add((40_732_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1216,9 +1215,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_is_contract(r: u32, ) -> Weight { - (96_692_000 as Weight) - // Standard Error: 688_000 - .saturating_add((313_348_000 as Weight).saturating_mul(r as Weight)) + (97_971_000 as Weight) + // Standard Error: 741_000 + .saturating_add((308_361_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1228,9 +1227,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_code_hash(r: u32, ) -> Weight { - (107_076_000 as Weight) - // Standard Error: 721_000 - .saturating_add((370_976_000 as Weight).saturating_mul(r as Weight)) + (109_052_000 as Weight) + // Standard Error: 716_000 + .saturating_add((366_257_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1240,9 +1239,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_own_code_hash(r: u32, ) -> Weight { - (207_147_000 as Weight) - // Standard Error: 112_000 - .saturating_add((43_974_000 as Weight).saturating_mul(r as Weight)) + (205_748_000 as Weight) + // Standard Error: 87_000 + .saturating_add((44_474_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1251,9 +1250,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_caller_is_origin(r: u32, ) -> Weight { - (203_029_000 as Weight) - // Standard Error: 31_000 - .saturating_add((16_811_000 as Weight).saturating_mul(r as Weight)) + (201_898_000 as Weight) + // Standard Error: 55_000 + .saturating_add((16_703_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1262,9 +1261,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_address(r: u32, ) -> Weight { - (206_641_000 as Weight) - // Standard Error: 86_000 - .saturating_add((40_239_000 as Weight).saturating_mul(r as Weight)) + (204_668_000 as Weight) + // Standard Error: 65_000 + .saturating_add((40_459_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1273,9 +1272,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas_left(r: u32, ) -> Weight { - (205_195_000 as Weight) - // Standard Error: 85_000 - .saturating_add((39_915_000 as Weight).saturating_mul(r as Weight)) + (203_240_000 as Weight) + // Standard Error: 68_000 + .saturating_add((40_270_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1284,9 +1283,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_balance(r: u32, ) -> Weight { - (213_345_000 as Weight) - // Standard Error: 126_000 - .saturating_add((116_249_000 as Weight).saturating_mul(r as Weight)) + (211_535_000 as Weight) + // Standard Error: 73_000 + .saturating_add((114_954_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1295,9 +1294,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_value_transferred(r: u32, ) -> Weight { - (206_141_000 as Weight) - // Standard Error: 96_000 - .saturating_add((39_999_000 as Weight).saturating_mul(r as Weight)) + (204_653_000 as Weight) + // Standard Error: 71_000 + .saturating_add((40_188_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1306,9 +1305,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_minimum_balance(r: u32, ) -> Weight { - (205_569_000 as Weight) - // Standard Error: 104_000 - .saturating_add((40_046_000 as Weight).saturating_mul(r as Weight)) + (204_690_000 as Weight) + // Standard Error: 82_000 + .saturating_add((40_260_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1317,9 +1316,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_block_number(r: u32, ) -> Weight { - (205_782_000 as Weight) - // Standard Error: 89_000 - .saturating_add((39_757_000 as Weight).saturating_mul(r as Weight)) + (205_004_000 as Weight) + // Standard Error: 62_000 + .saturating_add((40_018_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1328,9 +1327,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_now(r: u32, ) -> Weight { - (205_465_000 as Weight) - // Standard Error: 87_000 - .saturating_add((39_605_000 as Weight).saturating_mul(r as Weight)) + (204_341_000 as Weight) + // Standard Error: 93_000 + .saturating_add((39_920_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1340,9 +1339,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { - (208_900_000 as Weight) - // Standard Error: 108_000 - .saturating_add((101_341_000 as Weight).saturating_mul(r as Weight)) + (208_702_000 as Weight) + // Standard Error: 115_000 + .saturating_add((101_441_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1351,9 +1350,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_gas(r: u32, ) -> Weight { - (132_788_000 as Weight) - // Standard Error: 22_000 - .saturating_add((19_129_000 as Weight).saturating_mul(r as Weight)) + (131_983_000 as Weight) + // Standard Error: 17_000 + .saturating_add((19_153_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1362,9 +1361,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input(r: u32, ) -> Weight { - (205_111_000 as Weight) - // Standard Error: 96_000 - .saturating_add((39_317_000 as Weight).saturating_mul(r as Weight)) + (203_768_000 as Weight) + // Standard Error: 57_000 + .saturating_add((39_316_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1373,9 +1372,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_input_per_kb(n: u32, ) -> Weight { - (263_644_000 as Weight) + (273_930_000 as Weight) // Standard Error: 3_000 - .saturating_add((9_593_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((9_513_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1384,9 +1383,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return(r: u32, ) -> Weight { - (201_299_000 as Weight) - // Standard Error: 903_000 - .saturating_add((947_000 as Weight).saturating_mul(r as Weight)) + (199_311_000 as Weight) + // Standard Error: 601_000 + .saturating_add((2_181_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1395,9 +1394,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_return_per_kb(n: u32, ) -> Weight { - (202_730_000 as Weight) + (201_130_000 as Weight) // Standard Error: 0 - .saturating_add((183_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((184_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1408,9 +1407,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { - (203_795_000 as Weight) - // Standard Error: 759_000 - .saturating_add((52_720_000 as Weight).saturating_mul(r as Weight)) + (202_063_000 as Weight) + // Standard Error: 100_000 + .saturating_add((54_190_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1422,9 +1421,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { - (215_805_000 as Weight) - // Standard Error: 158_000 - .saturating_add((127_687_000 as Weight).saturating_mul(r as Weight)) + (206_528_000 as Weight) + // Standard Error: 120_000 + .saturating_add((136_384_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1433,9 +1432,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_deposit_event(r: u32, ) -> Weight { - (215_300_000 as Weight) - // Standard Error: 143_000 - .saturating_add((229_183_000 as Weight).saturating_mul(r as Weight)) + (210_309_000 as Weight) + // Standard Error: 138_000 + .saturating_add((236_583_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1445,11 +1444,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:80 w:80) fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (459_865_000 as Weight) - // Standard Error: 1_733_000 - .saturating_add((235_448_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 341_000 - .saturating_add((66_363_000 as Weight).saturating_mul(n as Weight)) + (434_046_000 as Weight) + // Standard Error: 1_678_000 + .saturating_add((242_928_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 330_000 + .saturating_add((66_716_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1460,17 +1459,17 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_debug_message(r: u32, ) -> Weight { - (137_820_000 as Weight) - // Standard Error: 77_000 - .saturating_add((31_956_000 as Weight).saturating_mul(r as Weight)) + (138_934_000 as Weight) + // Standard Error: 34_000 + .saturating_add((31_927_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage(r: u32, ) -> Weight { - (94_007_000 as Weight) - // Standard Error: 589_000 - .saturating_add((328_631_000 as Weight).saturating_mul(r as Weight)) + (88_315_000 as Weight) + // Standard Error: 594_000 + .saturating_add((328_984_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1478,25 +1477,25 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (528_794_000 as Weight) - // Standard Error: 233_000 - .saturating_add((21_533_000 as Weight).saturating_mul(n as Weight)) + (529_349_000 as Weight) + // Standard Error: 223_000 + .saturating_add((21_065_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(85 as Weight)) .saturating_add(RocksDbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (543_507_000 as Weight) - // Standard Error: 270_000 - .saturating_add((9_142_000 as Weight).saturating_mul(n as Weight)) + (546_447_000 as Weight) + // Standard Error: 261_000 + .saturating_add((8_709_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(85 as Weight)) .saturating_add(RocksDbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage(r: u32, ) -> Weight { - (129_893_000 as Weight) - // Standard Error: 471_000 - .saturating_add((313_807_000 as Weight).saturating_mul(r as Weight)) + (118_849_000 as Weight) + // Standard Error: 518_000 + .saturating_add((309_800_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1504,51 +1503,51 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (532_323_000 as Weight) - // Standard Error: 204_000 - .saturating_add((8_729_000 as Weight).saturating_mul(n as Weight)) + (537_039_000 as Weight) + // Standard Error: 235_000 + .saturating_add((8_071_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(85 as Weight)) .saturating_add(RocksDbWeight::get().writes(83 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage(r: u32, ) -> Weight { - (131_771_000 as Weight) - // Standard Error: 415_000 - .saturating_add((269_174_000 as Weight).saturating_mul(r as Weight)) + (125_427_000 as Weight) + // Standard Error: 635_000 + .saturating_add((276_126_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (494_409_000 as Weight) - // Standard Error: 280_000 - .saturating_add((50_499_000 as Weight).saturating_mul(n as Weight)) + (500_356_000 as Weight) + // Standard Error: 279_000 + .saturating_add((49_746_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(84 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage(r: u32, ) -> Weight { - (133_366_000 as Weight) - // Standard Error: 400_000 - .saturating_add((235_761_000 as Weight).saturating_mul(r as Weight)) + (129_046_000 as Weight) + // Standard Error: 408_000 + .saturating_add((237_117_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (447_828_000 as Weight) - // Standard Error: 197_000 - .saturating_add((8_190_000 as Weight).saturating_mul(n as Weight)) + (451_122_000 as Weight) + // Standard Error: 200_000 + .saturating_add((7_750_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(84 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage(r: u32, ) -> Weight { - (121_933_000 as Weight) - // Standard Error: 509_000 - .saturating_add((342_550_000 as Weight).saturating_mul(r as Weight)) + (118_085_000 as Weight) + // Standard Error: 526_000 + .saturating_add((338_332_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1556,9 +1555,9 @@ impl WeightInfo for () { } // Storage: Skipped Metadata (r:0 w:0) fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (578_648_000 as Weight) - // Standard Error: 320_000 - .saturating_add((51_767_000 as Weight).saturating_mul(n as Weight)) + (569_270_000 as Weight) + // Standard Error: 294_000 + .saturating_add((51_071_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(85 as Weight)) .saturating_add(RocksDbWeight::get().writes(83 as Weight)) } @@ -1567,9 +1566,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_transfer(r: u32, ) -> Weight { - (146_890_000 as Weight) - // Standard Error: 789_000 - .saturating_add((1_427_230_000 as Weight).saturating_mul(r as Weight)) + (124_818_000 as Weight) + // Standard Error: 1_251_000 + .saturating_add((1_455_607_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1581,8 +1580,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_542_000 - .saturating_add((15_063_367_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 4_575_000 + .saturating_add((14_645_061_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1594,8 +1593,8 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_267_000 - .saturating_add((15_037_276_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 5_742_000 + .saturating_add((14_623_917_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1604,11 +1603,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (9_081_513_000 as Weight) - // Standard Error: 18_081_000 - .saturating_add((1_388_391_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 7_000 - .saturating_add((9_653_000 as Weight).saturating_mul(c as Weight)) + (9_081_635_000 as Weight) + // Standard Error: 11_326_000 + .saturating_add((1_335_139_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 4_000 + .saturating_add((9_575_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(85 as Weight)) .saturating_add(RocksDbWeight::get().reads((81 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(81 as Weight)) @@ -1622,8 +1621,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:80 w:80) fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 34_560_000 - .saturating_add((20_828_575_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 34_958_000 + .saturating_add((20_700_850_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((320 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1636,11 +1635,11 @@ impl WeightInfo for () { // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (12_124_898_000 as Weight) - // Standard Error: 34_430_000 - .saturating_add((573_971_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 16_000 - .saturating_add((123_415_000 as Weight).saturating_mul(s as Weight)) + (12_091_206_000 as Weight) + // Standard Error: 104_884_000 + .saturating_add((635_259_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 49_000 + .saturating_add((122_935_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(167 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(165 as Weight)) @@ -1651,9 +1650,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256(r: u32, ) -> Weight { - (203_422_000 as Weight) - // Standard Error: 126_000 - .saturating_add((65_317_000 as Weight).saturating_mul(r as Weight)) + (203_315_000 as Weight) + // Standard Error: 74_000 + .saturating_add((60_223_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1662,9 +1661,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (411_079_000 as Weight) - // Standard Error: 20_000 - .saturating_add((354_947_000 as Weight).saturating_mul(n as Weight)) + (355_672_000 as Weight) + // Standard Error: 25_000 + .saturating_add((319_519_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1673,9 +1672,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256(r: u32, ) -> Weight { - (203_192_000 as Weight) - // Standard Error: 116_000 - .saturating_add((73_562_000 as Weight).saturating_mul(r as Weight)) + (203_117_000 as Weight) + // Standard Error: 94_000 + .saturating_add((77_363_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1684,9 +1683,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (227_572_000 as Weight) + (196_575_000 as Weight) // Standard Error: 13_000 - .saturating_add((244_646_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((243_479_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1695,9 +1694,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256(r: u32, ) -> Weight { - (204_922_000 as Weight) - // Standard Error: 112_000 - .saturating_add((51_349_000 as Weight).saturating_mul(r as Weight)) + (203_938_000 as Weight) + // Standard Error: 97_000 + .saturating_add((50_708_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1706,9 +1705,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (247_293_000 as Weight) - // Standard Error: 17_000 - .saturating_add((94_654_000 as Weight).saturating_mul(n as Weight)) + (247_065_000 as Weight) + // Standard Error: 8_000 + .saturating_add((94_160_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1717,9 +1716,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128(r: u32, ) -> Weight { - (203_511_000 as Weight) - // Standard Error: 108_000 - .saturating_add((50_585_000 as Weight).saturating_mul(r as Weight)) + (204_389_000 as Weight) + // Standard Error: 86_000 + .saturating_add((50_663_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1728,9 +1727,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (253_133_000 as Weight) - // Standard Error: 10_000 - .saturating_add((94_606_000 as Weight).saturating_mul(n as Weight)) + (284_700_000 as Weight) + // Standard Error: 9_000 + .saturating_add((94_231_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1739,9 +1738,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_recover(r: u32, ) -> Weight { - (280_685_000 as Weight) - // Standard Error: 627_000 - .saturating_add((3_062_997_000 as Weight).saturating_mul(r as Weight)) + (235_813_000 as Weight) + // Standard Error: 521_000 + .saturating_add((3_044_204_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1750,9 +1749,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - (212_204_000 as Weight) - // Standard Error: 469_000 - .saturating_add((2_034_397_000 as Weight).saturating_mul(r as Weight)) + (204_095_000 as Weight) + // Standard Error: 495_000 + .saturating_add((2_027_914_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1763,264 +1762,264 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:16 w:16) fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_507_000 - .saturating_add((747_481_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_604_000 + .saturating_add((759_511_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes((79 as Weight).saturating_mul(r as Weight))) } fn instr_i64const(r: u32, ) -> Weight { - (74_627_000 as Weight) + (74_210_000 as Weight) // Standard Error: 1_000 - .saturating_add((593_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((601_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (74_587_000 as Weight) + (74_123_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_294_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_315_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (74_392_000 as Weight) + (74_145_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_381_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_388_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (73_823_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_780_000 as Weight).saturating_mul(r as Weight)) + (73_931_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_768_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (74_072_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_946_000 as Weight).saturating_mul(r as Weight)) + (73_829_000 as Weight) + // Standard Error: 0 + .saturating_add((1_957_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (73_981_000 as Weight) - // Standard Error: 1_000 - .saturating_add((930_000 as Weight).saturating_mul(r as Weight)) + (73_760_000 as Weight) + // Standard Error: 0 + .saturating_add((932_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (73_690_000 as Weight) - // Standard Error: 3_000 - .saturating_add((1_433_000 as Weight).saturating_mul(r as Weight)) + (73_714_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_420_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (74_317_000 as Weight) - // Standard Error: 8_000 - .saturating_add((1_571_000 as Weight).saturating_mul(r as Weight)) + (73_496_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_575_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_373_000 as Weight) + (76_036_000 as Weight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (76_013_000 as Weight) - // Standard Error: 10_000 - .saturating_add((6_848_000 as Weight).saturating_mul(r as Weight)) + (76_015_000 as Weight) + // Standard Error: 19_000 + .saturating_add((6_954_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (88_704_000 as Weight) - // Standard Error: 16_000 - .saturating_add((8_824_000 as Weight).saturating_mul(r as Weight)) + (88_247_000 as Weight) + // Standard Error: 9_000 + .saturating_add((8_957_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (97_846_000 as Weight) - // Standard Error: 1_000 - .saturating_add((471_000 as Weight).saturating_mul(p as Weight)) + (98_336_000 as Weight) + // Standard Error: 2_000 + .saturating_add((474_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (75_010_000 as Weight) - // Standard Error: 1_000 - .saturating_add((612_000 as Weight).saturating_mul(r as Weight)) + (74_565_000 as Weight) + // Standard Error: 4_000 + .saturating_add((627_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (74_636_000 as Weight) + (74_414_000 as Weight) // Standard Error: 1_000 - .saturating_add((681_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((684_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (74_196_000 as Weight) - // Standard Error: 0 - .saturating_add((916_000 as Weight).saturating_mul(r as Weight)) + (74_346_000 as Weight) + // Standard Error: 1_000 + .saturating_add((911_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (77_349_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_176_000 as Weight).saturating_mul(r as Weight)) + (76_649_000 as Weight) + // Standard Error: 0 + .saturating_add((1_183_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (76_861_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_383_000 as Weight).saturating_mul(r as Weight)) + (76_995_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (74_696_000 as Weight) - // Standard Error: 2_000 - .saturating_add((655_000 as Weight).saturating_mul(r as Weight)) + (73_927_000 as Weight) + // Standard Error: 1_000 + .saturating_add((666_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (73_522_000 as Weight) - // Standard Error: 50_000 - .saturating_add((179_720_000 as Weight).saturating_mul(r as Weight)) + (73_479_000 as Weight) + // Standard Error: 24_000 + .saturating_add((180_808_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (74_292_000 as Weight) + (74_048_000 as Weight) // Standard Error: 1_000 - .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (74_299_000 as Weight) + (73_894_000 as Weight) // Standard Error: 1_000 - .saturating_add((882_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (74_289_000 as Weight) - // Standard Error: 1_000 - .saturating_add((883_000 as Weight).saturating_mul(r as Weight)) + (73_728_000 as Weight) + // Standard Error: 0 + .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (74_120_000 as Weight) - // Standard Error: 2_000 - .saturating_add((899_000 as Weight).saturating_mul(r as Weight)) + (74_049_000 as Weight) + // Standard Error: 1_000 + .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_599_000 as Weight) + (74_118_000 as Weight) // Standard Error: 1_000 - .saturating_add((851_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((863_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (74_622_000 as Weight) - // Standard Error: 2_000 - .saturating_add((854_000 as Weight).saturating_mul(r as Weight)) + (74_042_000 as Weight) + // Standard Error: 1_000 + .saturating_add((865_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_504_000 as Weight) - // Standard Error: 2_000 - .saturating_add((874_000 as Weight).saturating_mul(r as Weight)) + (73_885_000 as Weight) + // Standard Error: 1_000 + .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (74_532_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (73_788_000 as Weight) + // Standard Error: 0 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (74_130_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + (73_727_000 as Weight) + // Standard Error: 0 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (74_172_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) + (73_825_000 as Weight) + // Standard Error: 0 + .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (74_356_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_338_000 as Weight).saturating_mul(r as Weight)) + (73_638_000 as Weight) + // Standard Error: 0 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (74_181_000 as Weight) + (73_688_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (74_045_000 as Weight) + (73_895_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (74_246_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_341_000 as Weight).saturating_mul(r as Weight)) + (73_860_000 as Weight) + // Standard Error: 0 + .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (73_998_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_363_000 as Weight).saturating_mul(r as Weight)) + (73_864_000 as Weight) + // Standard Error: 0 + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (74_035_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) + (72_730_000 as Weight) + // Standard Error: 7_000 + .saturating_add((1_432_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (74_511_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_335_000 as Weight).saturating_mul(r as Weight)) + (73_998_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_346_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (74_305_000 as Weight) + (73_708_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_319_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_214_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_321_000 as Weight).saturating_mul(r as Weight)) + (74_033_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_322_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (74_073_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_323_000 as Weight).saturating_mul(r as Weight)) + (74_203_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_322_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (74_295_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_986_000 as Weight).saturating_mul(r as Weight)) + (73_990_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_010_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (74_109_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_023_000 as Weight).saturating_mul(r as Weight)) + (73_918_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_019_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (73_990_000 as Weight) + (73_927_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_993_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_001_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (73_940_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_056_000 as Weight).saturating_mul(r as Weight)) + (73_691_000 as Weight) + // Standard Error: 0 + .saturating_add((2_062_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (74_261_000 as Weight) - // Standard Error: 5_000 - .saturating_add((1_326_000 as Weight).saturating_mul(r as Weight)) + (73_869_000 as Weight) + // Standard Error: 0 + .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (74_014_000 as Weight) + (73_890_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (74_220_000 as Weight) + (73_866_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_323_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (74_139_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_343_000 as Weight).saturating_mul(r as Weight)) + (73_793_000 as Weight) + // Standard Error: 0 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (73_923_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_356_000 as Weight).saturating_mul(r as Weight)) + (73_695_000 as Weight) + // Standard Error: 0 + .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (73_999_000 as Weight) - // Standard Error: 1_000 + (73_743_000 as Weight) + // Standard Error: 0 .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (74_312_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_340_000 as Weight).saturating_mul(r as Weight)) + (73_781_000 as Weight) + // Standard Error: 0 + .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (73_988_000 as Weight) + (73_941_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) } } diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index da15aac0b47ca..6946317475ae2 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_conviction_voting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-09, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/conviction-voting/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/conviction-voting/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,7 +62,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_new() -> Weight { - (159_647_000 as Weight) + (145_945_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -72,7 +72,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_existing() -> Weight { - (339_851_000 as Weight) + (316_356_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -80,14 +80,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn remove_vote() -> Weight { - (317_673_000 as Weight) + (298_447_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:0) fn remove_other_vote() -> Weight { - (52_222_000 as Weight) + (48_705_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -97,9 +97,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn delegate(r: u32, ) -> Weight { - (61_553_000 as Weight) - // Standard Error: 123_000 - .saturating_add((33_092_000 as Weight).saturating_mul(r as Weight)) + (51_221_000 as Weight) + // Standard Error: 140_000 + .saturating_add((25_392_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(4 as Weight)) @@ -109,9 +109,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn undelegate(r: u32, ) -> Weight { - (42_037_000 as Weight) - // Standard Error: 582_000 - .saturating_add((32_296_000 as Weight).saturating_mul(r as Weight)) + (34_419_000 as Weight) + // Standard Error: 517_000 + .saturating_add((26_295_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -121,7 +121,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn unlock() -> Weight { - (69_017_000 as Weight) + (62_414_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -135,7 +135,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_new() -> Weight { - (159_647_000 as Weight) + (145_945_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -145,7 +145,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_existing() -> Weight { - (339_851_000 as Weight) + (316_356_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -153,14 +153,14 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn remove_vote() -> Weight { - (317_673_000 as Weight) + (298_447_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:0) fn remove_other_vote() -> Weight { - (52_222_000 as Weight) + (48_705_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -170,9 +170,9 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn delegate(r: u32, ) -> Weight { - (61_553_000 as Weight) - // Standard Error: 123_000 - .saturating_add((33_092_000 as Weight).saturating_mul(r as Weight)) + (51_221_000 as Weight) + // Standard Error: 140_000 + .saturating_add((25_392_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) @@ -182,9 +182,9 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn undelegate(r: u32, ) -> Weight { - (42_037_000 as Weight) - // Standard Error: 582_000 - .saturating_add((32_296_000 as Weight).saturating_mul(r as Weight)) + (34_419_000 as Weight) + // Standard Error: 517_000 + .saturating_add((26_295_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -194,7 +194,7 @@ impl WeightInfo for () { // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn unlock() -> Weight { - (69_017_000 as Weight) + (62_414_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 19bf602c5d291..50b4f3ab6ba22 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/democracy/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -82,15 +80,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (42_560_000 as Weight) + (43_581_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (25_603_000 as Weight) + (26_887_000 as Weight) // Standard Error: 1_000 - .saturating_add((167_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((134_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -98,9 +96,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (34_248_000 as Weight) + (35_520_000 as Weight) // Standard Error: 2_000 - .saturating_add((135_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((131_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -108,8 +106,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (33_927_000 as Weight) - // Standard Error: 2_000 + (34_793_000 as Weight) + // Standard Error: 1_000 .saturating_add((138_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -117,7 +115,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (14_714_000 as Weight) + (15_401_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -128,45 +126,45 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (49_423_000 as Weight) + (51_233_000 as Weight) // Standard Error: 3_000 - .saturating_add((275_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((189_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (7_321_000 as Weight) + (7_650_000 as Weight) // Standard Error: 0 - .saturating_add((75_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((30_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (1_325_000 as Weight) + (1_341_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (1_283_000 as Weight) + (1_360_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (15_355_000 as Weight) + (16_021_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (16_597_000 as Weight) + (17_350_000 as Weight) // Standard Error: 0 - .saturating_add((90_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((46_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -174,23 +172,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (37_695_000 as Weight) + (39_418_000 as Weight) // Standard Error: 2_000 - .saturating_add((258_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((170_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (9_456_000 as Weight) + (10_239_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (19_915_000 as Weight) + (20_483_000 as Weight) // Standard Error: 1_000 - .saturating_add((609_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((565_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -198,9 +196,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (3_787_000 as Weight) + (3_871_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_852_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_038_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -212,9 +210,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - (7_890_000 as Weight) + (7_597_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_856_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_046_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -223,9 +221,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (31_190_000 as Weight) + (32_554_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_753_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_903_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(4 as Weight)) @@ -234,9 +232,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (15_121_000 as Weight) + (15_440_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_852_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_972_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -244,12 +242,12 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (1_583_000 as Weight) + (1_662_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (22_681_000 as Weight) + (24_170_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -257,7 +255,7 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (15_599_000 as Weight) + (16_470_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -266,7 +264,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (23_663_000 as Weight) + (24_547_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -276,7 +274,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (21_928_000 as Weight) + (22_596_000 as Weight) // Standard Error: 1_000 .saturating_add((61_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -286,27 +284,27 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (21_548_000 as Weight) + (21_589_000 as Weight) // Standard Error: 1_000 - .saturating_add((123_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((125_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (11_797_000 as Weight) + (12_120_000 as Weight) // Standard Error: 1_000 - .saturating_add((117_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((106_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (11_930_000 as Weight) + (12_563_000 as Weight) // Standard Error: 1_000 - .saturating_add((122_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((105_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -319,15 +317,15 @@ impl WeightInfo for () { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (42_560_000 as Weight) + (43_581_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (25_603_000 as Weight) + (26_887_000 as Weight) // Standard Error: 1_000 - .saturating_add((167_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((134_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -335,9 +333,9 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (34_248_000 as Weight) + (35_520_000 as Weight) // Standard Error: 2_000 - .saturating_add((135_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((131_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -345,8 +343,8 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (33_927_000 as Weight) - // Standard Error: 2_000 + (34_793_000 as Weight) + // Standard Error: 1_000 .saturating_add((138_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -354,7 +352,7 @@ impl WeightInfo for () { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (14_714_000 as Weight) + (15_401_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -365,45 +363,45 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (49_423_000 as Weight) + (51_233_000 as Weight) // Standard Error: 3_000 - .saturating_add((275_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((189_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (7_321_000 as Weight) + (7_650_000 as Weight) // Standard Error: 0 - .saturating_add((75_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((30_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (1_325_000 as Weight) + (1_341_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (1_283_000 as Weight) + (1_360_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (15_355_000 as Weight) + (16_021_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (16_597_000 as Weight) + (17_350_000 as Weight) // Standard Error: 0 - .saturating_add((90_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((46_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -411,23 +409,23 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (37_695_000 as Weight) + (39_418_000 as Weight) // Standard Error: 2_000 - .saturating_add((258_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((170_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (9_456_000 as Weight) + (10_239_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (19_915_000 as Weight) + (20_483_000 as Weight) // Standard Error: 1_000 - .saturating_add((609_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((565_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -435,9 +433,9 @@ impl WeightInfo for () { // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (3_787_000 as Weight) + (3_871_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_852_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_038_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -449,9 +447,9 @@ impl WeightInfo for () { // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - (7_890_000 as Weight) + (7_597_000 as Weight) // Standard Error: 2_000 - .saturating_add((2_856_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_046_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -460,9 +458,9 @@ impl WeightInfo for () { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (31_190_000 as Weight) + (32_554_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_753_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_903_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) @@ -471,9 +469,9 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (15_121_000 as Weight) + (15_440_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_852_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_972_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -481,12 +479,12 @@ impl WeightInfo for () { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (1_583_000 as Weight) + (1_662_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (22_681_000 as Weight) + (24_170_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -494,7 +492,7 @@ impl WeightInfo for () { } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (15_599_000 as Weight) + (16_470_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -503,7 +501,7 @@ impl WeightInfo for () { // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (23_663_000 as Weight) + (24_547_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -513,7 +511,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (21_928_000 as Weight) + (22_596_000 as Weight) // Standard Error: 1_000 .saturating_add((61_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -523,27 +521,27 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (21_548_000 as Weight) + (21_589_000 as Weight) // Standard Error: 1_000 - .saturating_add((123_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((125_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (11_797_000 as Weight) + (12_120_000 as Weight) // Standard Error: 1_000 - .saturating_add((117_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((106_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (11_930_000 as Weight) + (12_563_000 as Weight) // Standard Error: 1_000 - .saturating_add((122_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((105_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 54c519681922b..d4802210ba23f 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_election_provider_multi_phase //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-03-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/election-provider-multi-phase/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/election-provider-multi-phase/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -68,33 +68,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (13_342_000 as Weight) + (12_920_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (13_503_000 as Weight) + (13_366_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (13_688_000 as Weight) + (13_487_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (29_124_000 as Weight) + (28_656_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (21_950_000 as Weight) + (21_910_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -102,11 +102,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (17_274_000 as Weight) + (0 as Weight) // Standard Error: 1_000 - .saturating_add((191_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((210_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 3_000 - .saturating_add((53_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -119,11 +119,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (145_826_000 as Weight) + (97_857_000 as Weight) + // Standard Error: 2_000 + .saturating_add((651_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 4_000 - .saturating_add((604_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 6_000 - .saturating_add((72_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((133_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -134,7 +134,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit() -> Weight { - (41_579_000 as Weight) + (43_892_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -148,13 +148,13 @@ impl WeightInfo for SubstrateWeight { fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((882_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 7_000 - .saturating_add((144_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 12_000 - .saturating_add((6_534_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 18_000 - .saturating_add((1_312_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((900_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 6_000 + .saturating_add((141_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 11_000 + .saturating_add((6_817_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 17_000 + .saturating_add((1_533_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -162,14 +162,16 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { + fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((835_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 12_000 - .saturating_add((5_395_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 19_000 - .saturating_add((1_243_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((885_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 6_000 + .saturating_add((205_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 11_000 + .saturating_add((5_532_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 16_000 + .saturating_add((1_138_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) } } @@ -185,33 +187,33 @@ impl WeightInfo for () { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (13_342_000 as Weight) + (12_920_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (13_503_000 as Weight) + (13_366_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (13_688_000 as Weight) + (13_487_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (29_124_000 as Weight) + (28_656_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (21_950_000 as Weight) + (21_910_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -219,11 +221,11 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (17_274_000 as Weight) + (0 as Weight) // Standard Error: 1_000 - .saturating_add((191_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((210_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 3_000 - .saturating_add((53_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -236,11 +238,11 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (145_826_000 as Weight) + (97_857_000 as Weight) + // Standard Error: 2_000 + .saturating_add((651_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 4_000 - .saturating_add((604_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 6_000 - .saturating_add((72_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((133_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -251,7 +253,7 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit() -> Weight { - (41_579_000 as Weight) + (43_892_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -265,13 +267,13 @@ impl WeightInfo for () { fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((882_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 7_000 - .saturating_add((144_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 12_000 - .saturating_add((6_534_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 18_000 - .saturating_add((1_312_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((900_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 6_000 + .saturating_add((141_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 11_000 + .saturating_add((6_817_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 17_000 + .saturating_add((1_533_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -279,14 +281,16 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { + fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((835_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 12_000 - .saturating_add((5_395_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 19_000 - .saturating_add((1_243_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((885_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 6_000 + .saturating_add((205_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 11_000 + .saturating_add((5_532_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 16_000 + .saturating_add((1_138_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) } } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index e973334b833cc..6cb2924fd7cf8 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-03-29, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/elections-phragmen/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/elections-phragmen/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -68,9 +68,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_equal(v: u32, ) -> Weight { - (22_981_000 as Weight) - // Standard Error: 6_000 - .saturating_add((232_000 as Weight).saturating_mul(v as Weight)) + (23_819_000 as Weight) + // Standard Error: 5_000 + .saturating_add((242_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -80,9 +80,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_more(v: u32, ) -> Weight { - (36_170_000 as Weight) - // Standard Error: 8_000 - .saturating_add((219_000 as Weight).saturating_mul(v as Weight)) + (37_141_000 as Weight) + // Standard Error: 6_000 + .saturating_add((259_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -92,16 +92,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_less(v: u32, ) -> Weight { - (35_798_000 as Weight) - // Standard Error: 8_000 - .saturating_add((241_000 as Weight).saturating_mul(v as Weight)) + (37_494_000 as Weight) + // Standard Error: 10_000 + .saturating_add((227_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (33_060_000 as Weight) + (34_528_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -109,17 +109,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) fn submit_candidacy(c: u32, ) -> Weight { - (35_384_000 as Weight) - // Standard Error: 0 - .saturating_add((124_000 as Weight).saturating_mul(c as Weight)) + (38_330_000 as Weight) + // Standard Error: 1_000 + .saturating_add((88_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (31_555_000 as Weight) + (32_770_000 as Weight) // Standard Error: 1_000 - .saturating_add((78_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((81_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -129,13 +129,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (41_531_000 as Weight) + (43_413_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (30_762_000 as Weight) + (32_206_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -150,13 +150,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (48_287_000 as Weight) + (50_135_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Elections RunnersUp (r:1 w:0) fn remove_member_wrong_refund() -> Weight { - (4_747_000 as Weight) + (5_063_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Elections Voting (r:251 w:250) @@ -167,8 +167,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:250 w:250) fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 37_000 - .saturating_add((49_564_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 62_000 + .saturating_add((52_093_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -184,10 +184,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_656_000 - .saturating_add((29_011_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 1_658_000 + .saturating_add((30_489_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 689_000 - .saturating_add((49_204_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((49_624_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 47_000 .saturating_add((3_352_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) @@ -204,9 +204,9 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_equal(v: u32, ) -> Weight { - (22_981_000 as Weight) - // Standard Error: 6_000 - .saturating_add((232_000 as Weight).saturating_mul(v as Weight)) + (23_819_000 as Weight) + // Standard Error: 5_000 + .saturating_add((242_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -216,9 +216,9 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_more(v: u32, ) -> Weight { - (36_170_000 as Weight) - // Standard Error: 8_000 - .saturating_add((219_000 as Weight).saturating_mul(v as Weight)) + (37_141_000 as Weight) + // Standard Error: 6_000 + .saturating_add((259_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -228,16 +228,16 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_less(v: u32, ) -> Weight { - (35_798_000 as Weight) - // Standard Error: 8_000 - .saturating_add((241_000 as Weight).saturating_mul(v as Weight)) + (37_494_000 as Weight) + // Standard Error: 10_000 + .saturating_add((227_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (33_060_000 as Weight) + (34_528_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -245,17 +245,17 @@ impl WeightInfo for () { // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) fn submit_candidacy(c: u32, ) -> Weight { - (35_384_000 as Weight) - // Standard Error: 0 - .saturating_add((124_000 as Weight).saturating_mul(c as Weight)) + (38_330_000 as Weight) + // Standard Error: 1_000 + .saturating_add((88_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (31_555_000 as Weight) + (32_770_000 as Weight) // Standard Error: 1_000 - .saturating_add((78_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((81_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -265,13 +265,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (41_531_000 as Weight) + (43_413_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (30_762_000 as Weight) + (32_206_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -286,13 +286,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (48_287_000 as Weight) + (50_135_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Elections RunnersUp (r:1 w:0) fn remove_member_wrong_refund() -> Weight { - (4_747_000 as Weight) + (5_063_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Elections Voting (r:251 w:250) @@ -303,8 +303,8 @@ impl WeightInfo for () { // Storage: System Account (r:250 w:250) fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 37_000 - .saturating_add((49_564_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 62_000 + .saturating_add((52_093_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -320,10 +320,10 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_656_000 - .saturating_add((29_011_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 1_658_000 + .saturating_add((30_489_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 689_000 - .saturating_add((49_204_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((49_624_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 47_000 .saturating_add((3_352_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) diff --git a/frame/gilt/src/weights.rs b/frame/gilt/src/weights.rs index 6084d494c5c3a..99e58d070e493 100644 --- a/frame/gilt/src/weights.rs +++ b/frame/gilt/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_gilt //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/gilt/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,44 +60,44 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - (32_753_000 as Weight) + (36_598_000 as Weight) // Standard Error: 0 - .saturating_add((96_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((61_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - (124_814_000 as Weight) + (92_021_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - (33_544_000 as Weight) + (37_133_000 as Weight) // Standard Error: 0 - .saturating_add((86_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - (2_648_000 as Weight) + (2_807_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - (41_549_000 as Weight) + (43_275_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - (1_583_000 as Weight) + (1_693_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) @@ -107,9 +105,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - (35_836_000 as Weight) - // Standard Error: 1_000 - .saturating_add((4_008_000 as Weight).saturating_mul(b as Weight)) + (37_977_000 as Weight) + // Standard Error: 2_000 + .saturating_add((4_129_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(b as Weight))) @@ -119,9 +117,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - (12_139_000 as Weight) - // Standard Error: 6_000 - .saturating_add((7_819_000 as Weight).saturating_mul(q as Weight)) + (11_367_000 as Weight) + // Standard Error: 7_000 + .saturating_add((8_275_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(q as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -134,44 +132,44 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - (32_753_000 as Weight) + (36_598_000 as Weight) // Standard Error: 0 - .saturating_add((96_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((61_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - (124_814_000 as Weight) + (92_021_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - (33_544_000 as Weight) + (37_133_000 as Weight) // Standard Error: 0 - .saturating_add((86_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - (2_648_000 as Weight) + (2_807_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - (41_549_000 as Weight) + (43_275_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - (1_583_000 as Weight) + (1_693_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) @@ -179,9 +177,9 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - (35_836_000 as Weight) - // Standard Error: 1_000 - .saturating_add((4_008_000 as Weight).saturating_mul(b as Weight)) + (37_977_000 as Weight) + // Standard Error: 2_000 + .saturating_add((4_129_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(b as Weight))) @@ -191,9 +189,9 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - (12_139_000 as Weight) - // Standard Error: 6_000 - .saturating_add((7_819_000 as Weight).saturating_mul(q as Weight)) + (11_367_000 as Weight) + // Standard Error: 7_000 + .saturating_add((8_275_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(q as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index cf164d3cbd73f..77c5915f0ec99 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_identity //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/identity/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -69,19 +67,19 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:1) fn add_registrar(r: u32, ) -> Weight { - (13_150_000 as Weight) + (13_318_000 as Weight) // Standard Error: 3_000 - .saturating_add((253_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((203_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn set_identity(r: u32, x: u32, ) -> Weight { - (27_745_000 as Weight) - // Standard Error: 7_000 - .saturating_add((210_000 as Weight).saturating_mul(r as Weight)) + (27_683_000 as Weight) + // Standard Error: 8_000 + .saturating_add((242_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((289_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((307_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -89,9 +87,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) fn set_subs_new(s: u32, ) -> Weight { - (25_184_000 as Weight) + (26_126_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_722_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_826_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -101,9 +99,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) fn set_subs_old(p: u32, ) -> Weight { - (24_144_000 as Weight) + (24_645_000 as Weight) // Standard Error: 0 - .saturating_add((890_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((893_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -112,13 +110,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (32_167_000 as Weight) - // Standard Error: 8_000 - .saturating_add((46_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 0 - .saturating_add((875_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 0 - .saturating_add((184_000 as Weight).saturating_mul(x as Weight)) + (31_546_000 as Weight) + // Standard Error: 12_000 + .saturating_add((110_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_000 + .saturating_add((872_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 1_000 + .saturating_add((182_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -126,56 +124,56 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn request_judgement(r: u32, x: u32, ) -> Weight { - (30_009_000 as Weight) + (31_117_000 as Weight) // Standard Error: 3_000 - .saturating_add((287_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((207_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((331_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((347_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn cancel_request(r: u32, x: u32, ) -> Weight { - (28_195_000 as Weight) + (28_134_000 as Weight) // Standard Error: 3_000 - .saturating_add((137_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((154_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((328_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((343_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fee(r: u32, ) -> Weight { - (5_080_000 as Weight) - // Standard Error: 2_000 - .saturating_add((202_000 as Weight).saturating_mul(r as Weight)) + (4_884_000 as Weight) + // Standard Error: 3_000 + .saturating_add((159_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_account_id(r: u32, ) -> Weight { - (5_298_000 as Weight) + (5_015_000 as Weight) // Standard Error: 2_000 - .saturating_add((195_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((143_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fields(r: u32, ) -> Weight { - (5_263_000 as Weight) - // Standard Error: 2_000 - .saturating_add((191_000 as Weight).saturating_mul(r as Weight)) + (4_947_000 as Weight) + // Standard Error: 3_000 + .saturating_add((152_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn provide_judgement(r: u32, x: u32, ) -> Weight { - (21_511_000 as Weight) + (20_570_000 as Weight) // Standard Error: 3_000 - .saturating_add((219_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((213_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((327_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((345_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -184,11 +182,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (40_654_000 as Weight) - // Standard Error: 6_000 - .saturating_add((179_000 as Weight).saturating_mul(r as Weight)) + (41_448_000 as Weight) + // Standard Error: 7_000 + .saturating_add((149_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((908_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((882_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -197,18 +195,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn add_sub(s: u32, ) -> Weight { - (31_573_000 as Weight) + (32_346_000 as Weight) // Standard Error: 1_000 - .saturating_add((151_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) fn rename_sub(s: u32, ) -> Weight { - (10_452_000 as Weight) + (10_211_000 as Weight) // Standard Error: 0 - .saturating_add((45_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -216,18 +214,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn remove_sub(s: u32, ) -> Weight { - (32_711_000 as Weight) + (33_083_000 as Weight) // Standard Error: 1_000 - .saturating_add((150_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((112_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn quit_sub(s: u32, ) -> Weight { - (21_975_000 as Weight) - // Standard Error: 0 - .saturating_add((149_000 as Weight).saturating_mul(s as Weight)) + (22_517_000 as Weight) + // Standard Error: 1_000 + .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -237,19 +235,19 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:1) fn add_registrar(r: u32, ) -> Weight { - (13_150_000 as Weight) + (13_318_000 as Weight) // Standard Error: 3_000 - .saturating_add((253_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((203_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn set_identity(r: u32, x: u32, ) -> Weight { - (27_745_000 as Weight) - // Standard Error: 7_000 - .saturating_add((210_000 as Weight).saturating_mul(r as Weight)) + (27_683_000 as Weight) + // Standard Error: 8_000 + .saturating_add((242_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((289_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((307_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -257,9 +255,9 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) fn set_subs_new(s: u32, ) -> Weight { - (25_184_000 as Weight) + (26_126_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_722_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_826_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -269,9 +267,9 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) fn set_subs_old(p: u32, ) -> Weight { - (24_144_000 as Weight) + (24_645_000 as Weight) // Standard Error: 0 - .saturating_add((890_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((893_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -280,13 +278,13 @@ impl WeightInfo for () { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (32_167_000 as Weight) - // Standard Error: 8_000 - .saturating_add((46_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 0 - .saturating_add((875_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 0 - .saturating_add((184_000 as Weight).saturating_mul(x as Weight)) + (31_546_000 as Weight) + // Standard Error: 12_000 + .saturating_add((110_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_000 + .saturating_add((872_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 1_000 + .saturating_add((182_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -294,56 +292,56 @@ impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn request_judgement(r: u32, x: u32, ) -> Weight { - (30_009_000 as Weight) + (31_117_000 as Weight) // Standard Error: 3_000 - .saturating_add((287_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((207_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((331_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((347_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn cancel_request(r: u32, x: u32, ) -> Weight { - (28_195_000 as Weight) + (28_134_000 as Weight) // Standard Error: 3_000 - .saturating_add((137_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((154_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((328_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((343_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fee(r: u32, ) -> Weight { - (5_080_000 as Weight) - // Standard Error: 2_000 - .saturating_add((202_000 as Weight).saturating_mul(r as Weight)) + (4_884_000 as Weight) + // Standard Error: 3_000 + .saturating_add((159_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_account_id(r: u32, ) -> Weight { - (5_298_000 as Weight) + (5_015_000 as Weight) // Standard Error: 2_000 - .saturating_add((195_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((143_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fields(r: u32, ) -> Weight { - (5_263_000 as Weight) - // Standard Error: 2_000 - .saturating_add((191_000 as Weight).saturating_mul(r as Weight)) + (4_947_000 as Weight) + // Standard Error: 3_000 + .saturating_add((152_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn provide_judgement(r: u32, x: u32, ) -> Weight { - (21_511_000 as Weight) + (20_570_000 as Weight) // Standard Error: 3_000 - .saturating_add((219_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((213_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((327_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((345_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -352,11 +350,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (40_654_000 as Weight) - // Standard Error: 6_000 - .saturating_add((179_000 as Weight).saturating_mul(r as Weight)) + (41_448_000 as Weight) + // Standard Error: 7_000 + .saturating_add((149_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((908_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((882_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -365,18 +363,18 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn add_sub(s: u32, ) -> Weight { - (31_573_000 as Weight) + (32_346_000 as Weight) // Standard Error: 1_000 - .saturating_add((151_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) fn rename_sub(s: u32, ) -> Weight { - (10_452_000 as Weight) + (10_211_000 as Weight) // Standard Error: 0 - .saturating_add((45_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -384,18 +382,18 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn remove_sub(s: u32, ) -> Weight { - (32_711_000 as Weight) + (33_083_000 as Weight) // Standard Error: 1_000 - .saturating_add((150_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((112_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn quit_sub(s: u32, ) -> Weight { - (21_975_000 as Weight) - // Standard Error: 0 - .saturating_add((149_000 as Weight).saturating_mul(s as Weight)) + (22_517_000 as Weight) + // Standard Error: 1_000 + .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index f7d4d1441da27..187499b1f957f 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_im_online //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/im-online/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -58,11 +56,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - (74_137_000 as Weight) + (74_221_000 as Weight) // Standard Error: 0 - .saturating_add((125_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((41_000 as Weight).saturating_mul(k as Weight)) // Standard Error: 0 - .saturating_add((291_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((294_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -76,11 +74,11 @@ impl WeightInfo for () { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - (74_137_000 as Weight) + (74_221_000 as Weight) // Standard Error: 0 - .saturating_add((125_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((41_000 as Weight).saturating_mul(k as Weight)) // Standard Error: 0 - .saturating_add((291_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((294_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 1687237394fbd..5fba8fc2377a0 100644 --- a/frame/indices/src/weights.rs +++ b/frame/indices/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_indices //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/indices/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -58,33 +56,33 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - (21_121_000 as Weight) + (21_333_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (26_843_000 as Weight) + (27_479_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - (22_174_000 as Weight) + (22_802_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (22_191_000 as Weight) + (23_369_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - (24_813_000 as Weight) + (25_740_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -94,33 +92,33 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - (21_121_000 as Weight) + (21_333_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (26_843_000 as Weight) + (27_479_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - (22_174_000 as Weight) + (22_802_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (22_191_000 as Weight) + (23_369_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - (24_813_000 as Weight) + (25_740_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index 3b6114a73cfaa..d3626dc9080ec 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_lottery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/lottery/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -65,28 +63,28 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (37_257_000 as Weight) + (39_387_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (8_966_000 as Weight) - // Standard Error: 5_000 - .saturating_add((302_000 as Weight).saturating_mul(n as Weight)) + (9_353_000 as Weight) + // Standard Error: 4_000 + .saturating_add((297_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (32_282_000 as Weight) + (33_157_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (3_903_000 as Weight) + (4_015_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -96,7 +94,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (51_489_000 as Weight) + (53_539_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -107,7 +105,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (53_046_000 as Weight) + (56_103_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -123,28 +121,28 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (37_257_000 as Weight) + (39_387_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (8_966_000 as Weight) - // Standard Error: 5_000 - .saturating_add((302_000 as Weight).saturating_mul(n as Weight)) + (9_353_000 as Weight) + // Standard Error: 4_000 + .saturating_add((297_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (32_282_000 as Weight) + (33_157_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (3_903_000 as Weight) + (4_015_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -154,7 +152,7 @@ impl WeightInfo for () { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (51_489_000 as Weight) + (53_539_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -165,7 +163,7 @@ impl WeightInfo for () { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (53_046_000 as Weight) + (56_103_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 0d4936cfba1f9..7372ad37cdea2 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_membership //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/membership/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -63,9 +61,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - (14_884_000 as Weight) - // Standard Error: 0 - .saturating_add((95_000 as Weight).saturating_mul(m as Weight)) + (15_572_000 as Weight) + // Standard Error: 1_000 + .saturating_add((48_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -75,9 +73,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - (17_612_000 as Weight) + (18_090_000 as Weight) // Standard Error: 0 - .saturating_add((86_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((43_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -87,9 +85,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - (17_580_000 as Weight) + (18_199_000 as Weight) // Standard Error: 0 - .saturating_add((98_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((54_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -99,9 +97,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - (17_610_000 as Weight) + (18_238_000 as Weight) // Standard Error: 0 - .saturating_add((199_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -111,9 +109,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - (18_208_000 as Weight) + (18_911_000 as Weight) // Standard Error: 0 - .saturating_add((96_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -121,18 +119,18 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - (4_661_000 as Weight) + (4_843_000 as Weight) // Standard Error: 0 - .saturating_add((70_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((27_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - (1_574_000 as Weight) + (1_662_000 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } } @@ -144,9 +142,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - (14_884_000 as Weight) - // Standard Error: 0 - .saturating_add((95_000 as Weight).saturating_mul(m as Weight)) + (15_572_000 as Weight) + // Standard Error: 1_000 + .saturating_add((48_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -156,9 +154,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - (17_612_000 as Weight) + (18_090_000 as Weight) // Standard Error: 0 - .saturating_add((86_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((43_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -168,9 +166,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - (17_580_000 as Weight) + (18_199_000 as Weight) // Standard Error: 0 - .saturating_add((98_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((54_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -180,9 +178,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - (17_610_000 as Weight) + (18_238_000 as Weight) // Standard Error: 0 - .saturating_add((199_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -192,9 +190,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - (18_208_000 as Weight) + (18_911_000 as Weight) // Standard Error: 0 - .saturating_add((96_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -202,18 +200,18 @@ impl WeightInfo for () { // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - (4_661_000 as Weight) + (4_843_000 as Weight) // Standard Error: 0 - .saturating_add((70_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((27_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - (1_574_000 as Weight) + (1_662_000 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } } diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index 501fb9c184194..563dd20bae63d 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_multisig //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/multisig/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -61,17 +59,15 @@ pub trait WeightInfo { /// Weights for pallet_multisig using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - fn as_multi_threshold_1(z: u32, ) -> Weight { - (16_534_000 as Weight) - // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) + fn as_multi_threshold_1(_z: u32, ) -> Weight { + (12_456_000 as Weight) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - (30_917_000 as Weight) - // Standard Error: 1_000 - .saturating_add((131_000 as Weight).saturating_mul(s as Weight)) + (31_781_000 as Weight) + // Standard Error: 0 + .saturating_add((93_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -81,9 +77,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - (33_570_000 as Weight) + (35_669_000 as Weight) // Standard Error: 1_000 - .saturating_add((138_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((95_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -91,9 +87,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - (21_051_000 as Weight) + (21_326_000 as Weight) // Standard Error: 0 - .saturating_add((126_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((91_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -102,9 +98,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - (32_581_000 as Weight) + (35_296_000 as Weight) // Standard Error: 1_000 - .saturating_add((135_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((88_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -114,9 +110,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - (39_215_000 as Weight) + (39_872_000 as Weight) // Standard Error: 1_000 - .saturating_add((221_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((147_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -125,18 +121,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - (28_572_000 as Weight) - // Standard Error: 1_000 - .saturating_add((146_000 as Weight).saturating_mul(s as Weight)) + (29_680_000 as Weight) + // Standard Error: 0 + .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - (18_032_000 as Weight) + (18_514_000 as Weight) // Standard Error: 0 - .saturating_add((151_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((111_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -144,18 +140,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - (56_353_000 as Weight) + (57_404_000 as Weight) // Standard Error: 1_000 - .saturating_add((239_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((157_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - (44_544_000 as Weight) - // Standard Error: 0 - .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) + (45_860_000 as Weight) + // Standard Error: 1_000 + .saturating_add((111_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -163,17 +159,15 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - fn as_multi_threshold_1(z: u32, ) -> Weight { - (16_534_000 as Weight) - // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) + fn as_multi_threshold_1(_z: u32, ) -> Weight { + (12_456_000 as Weight) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - (30_917_000 as Weight) - // Standard Error: 1_000 - .saturating_add((131_000 as Weight).saturating_mul(s as Weight)) + (31_781_000 as Weight) + // Standard Error: 0 + .saturating_add((93_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -183,9 +177,9 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - (33_570_000 as Weight) + (35_669_000 as Weight) // Standard Error: 1_000 - .saturating_add((138_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((95_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -193,9 +187,9 @@ impl WeightInfo for () { } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - (21_051_000 as Weight) + (21_326_000 as Weight) // Standard Error: 0 - .saturating_add((126_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((91_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -204,9 +198,9 @@ impl WeightInfo for () { // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - (32_581_000 as Weight) + (35_296_000 as Weight) // Standard Error: 1_000 - .saturating_add((135_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((88_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -216,9 +210,9 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - (39_215_000 as Weight) + (39_872_000 as Weight) // Standard Error: 1_000 - .saturating_add((221_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((147_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -227,18 +221,18 @@ impl WeightInfo for () { // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - (28_572_000 as Weight) - // Standard Error: 1_000 - .saturating_add((146_000 as Weight).saturating_mul(s as Weight)) + (29_680_000 as Weight) + // Standard Error: 0 + .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - (18_032_000 as Weight) + (18_514_000 as Weight) // Standard Error: 0 - .saturating_add((151_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((111_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -246,18 +240,18 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - (56_353_000 as Weight) + (57_404_000 as Weight) // Standard Error: 1_000 - .saturating_add((239_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((157_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - (44_544_000 as Weight) - // Standard Error: 0 - .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) + (45_860_000 as Weight) + // Standard Error: 1_000 + .saturating_add((111_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index 6a5a38ac0abf7..ef339231fe7bb 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-11, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -32,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/nomination-pools/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/nomination-pools/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -78,7 +77,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (122_806_000 as Weight) + (124_114_000 as Weight) .saturating_add(T::DbWeight::get().reads(17 as Weight)) .saturating_add(T::DbWeight::get().writes(11 as Weight)) } @@ -92,7 +91,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (114_398_000 as Weight) + (115_734_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) } @@ -106,7 +105,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:2 w:2) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (128_370_000 as Weight) + (127_873_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) } @@ -115,7 +114,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (52_338_000 as Weight) + (51_510_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -134,7 +133,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (120_866_000 as Weight) + (120_744_000 as Weight) .saturating_add(T::DbWeight::get().reads(18 as Weight)) .saturating_add(T::DbWeight::get().writes(13 as Weight)) } @@ -143,9 +142,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (42_038_000 as Weight) + (41_267_000 as Weight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -158,7 +157,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (83_220_000 as Weight) + (82_234_000 as Weight) // Standard Error: 0 .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(8 as Weight)) @@ -183,8 +182,10 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (143_981_000 as Weight) + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + (142_699_000 as Weight) + // Standard Error: 0 + .saturating_add((5_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(19 as Weight)) .saturating_add(T::DbWeight::get().writes(16 as Weight)) } @@ -211,7 +212,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (134_974_000 as Weight) + (133_702_000 as Weight) .saturating_add(T::DbWeight::get().reads(22 as Weight)) .saturating_add(T::DbWeight::get().writes(15 as Weight)) } @@ -228,9 +229,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (47_085_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_222_000 as Weight).saturating_mul(n as Weight)) + (46_887_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_277_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(5 as Weight)) @@ -238,7 +239,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (24_192_000 as Weight) + (24_030_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -246,9 +247,9 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) fn set_metadata(n: u32, ) -> Weight { - (11_448_000 as Weight) + (11_336_000 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -258,12 +259,12 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (2_829_000 as Weight) + (2_927_000 as Weight) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (19_017_000 as Weight) + (19_184_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -285,7 +286,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (122_806_000 as Weight) + (124_114_000 as Weight) .saturating_add(RocksDbWeight::get().reads(17 as Weight)) .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } @@ -299,7 +300,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (114_398_000 as Weight) + (115_734_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) } @@ -313,7 +314,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:2 w:2) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (128_370_000 as Weight) + (127_873_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) } @@ -322,7 +323,7 @@ impl WeightInfo for () { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (52_338_000 as Weight) + (51_510_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -341,7 +342,7 @@ impl WeightInfo for () { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (120_866_000 as Weight) + (120_744_000 as Weight) .saturating_add(RocksDbWeight::get().reads(18 as Weight)) .saturating_add(RocksDbWeight::get().writes(13 as Weight)) } @@ -350,9 +351,9 @@ impl WeightInfo for () { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (42_038_000 as Weight) + (41_267_000 as Weight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -365,7 +366,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (83_220_000 as Weight) + (82_234_000 as Weight) // Standard Error: 0 .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) @@ -390,8 +391,10 @@ impl WeightInfo for () { // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (143_981_000 as Weight) + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + (142_699_000 as Weight) + // Standard Error: 0 + .saturating_add((5_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(19 as Weight)) .saturating_add(RocksDbWeight::get().writes(16 as Weight)) } @@ -418,7 +421,7 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (134_974_000 as Weight) + (133_702_000 as Weight) .saturating_add(RocksDbWeight::get().reads(22 as Weight)) .saturating_add(RocksDbWeight::get().writes(15 as Weight)) } @@ -435,9 +438,9 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (47_085_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_222_000 as Weight).saturating_mul(n as Weight)) + (46_887_000 as Weight) + // Standard Error: 12_000 + .saturating_add((2_277_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) @@ -445,7 +448,7 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (24_192_000 as Weight) + (24_030_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -453,9 +456,9 @@ impl WeightInfo for () { // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) fn set_metadata(n: u32, ) -> Weight { - (11_448_000 as Weight) + (11_336_000 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -465,12 +468,12 @@ impl WeightInfo for () { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (2_829_000 as Weight) + (2_927_000 as Weight) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (19_017_000 as Weight) + (19_184_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 0d7f583727c99..801ad627e07d9 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/preimage/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -93,58 +91,58 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (39_239_000 as Weight) + (38_459_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (24_905_000 as Weight) + (24_172_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (37_451_000 as Weight) + (37_200_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (23_397_000 as Weight) + (24_071_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (13_407_000 as Weight) + (13_974_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (4_202_000 as Weight) + (4_401_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (24_858_000 as Weight) + (24_756_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (13_763_000 as Weight) + (14_351_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (4_262_000 as Weight) + (4_359_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -182,58 +180,58 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (39_239_000 as Weight) + (38_459_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (24_905_000 as Weight) + (24_172_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (37_451_000 as Weight) + (37_200_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (23_397_000 as Weight) + (24_071_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (13_407_000 as Weight) + (13_974_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (4_202_000 as Weight) + (4_401_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (24_858_000 as Weight) + (24_756_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (13_763_000 as Weight) + (14_351_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (4_262_000 as Weight) + (4_359_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 176f8683e0b5f..a0df59204f673 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_proxy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/proxy/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -63,42 +61,42 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - (13_323_000 as Weight) + (13_918_000 as Weight) // Standard Error: 1_000 - .saturating_add((114_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((66_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - (28_825_000 as Weight) - // Standard Error: 1_000 - .saturating_add((254_000 as Weight).saturating_mul(a as Weight)) + (30_328_000 as Weight) // Standard Error: 2_000 - .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((159_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 2_000 + .saturating_add((64_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn remove_announcement(a: u32, p: u32, ) -> Weight { - (20_594_000 as Weight) + (21_667_000 as Weight) // Standard Error: 1_000 - .saturating_add((259_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((167_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((15_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_announcement(a: u32, p: u32, ) -> Weight { - (20_316_000 as Weight) + (21_554_000 as Weight) // Standard Error: 1_000 - .saturating_add((265_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((171_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((18_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -106,52 +104,52 @@ impl WeightInfo for SubstrateWeight { // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - (27_696_000 as Weight) + (28_774_000 as Weight) // Standard Error: 2_000 - .saturating_add((241_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((150_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((111_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((67_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - (22_849_000 as Weight) - // Standard Error: 2_000 - .saturating_add((140_000 as Weight).saturating_mul(p as Weight)) + (23_571_000 as Weight) + // Standard Error: 1_000 + .saturating_add((110_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - (19_350_000 as Weight) + (23_613_000 as Weight) // Standard Error: 2_000 - .saturating_add((147_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - (18_878_000 as Weight) - // Standard Error: 2_000 - .saturating_add((112_000 as Weight).saturating_mul(p as Weight)) + (19_968_000 as Weight) + // Standard Error: 1_000 + .saturating_add((74_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - (25_743_000 as Weight) + (26_479_000 as Weight) // Standard Error: 2_000 - .saturating_add((25_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((37_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - (20_484_000 as Weight) - // Standard Error: 2_000 - .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) + (20_816_000 as Weight) + // Standard Error: 1_000 + .saturating_add((67_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -161,42 +159,42 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - (13_323_000 as Weight) + (13_918_000 as Weight) // Standard Error: 1_000 - .saturating_add((114_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((66_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - (28_825_000 as Weight) - // Standard Error: 1_000 - .saturating_add((254_000 as Weight).saturating_mul(a as Weight)) + (30_328_000 as Weight) // Standard Error: 2_000 - .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((159_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 2_000 + .saturating_add((64_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn remove_announcement(a: u32, p: u32, ) -> Weight { - (20_594_000 as Weight) + (21_667_000 as Weight) // Standard Error: 1_000 - .saturating_add((259_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((167_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((15_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_announcement(a: u32, p: u32, ) -> Weight { - (20_316_000 as Weight) + (21_554_000 as Weight) // Standard Error: 1_000 - .saturating_add((265_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((171_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((18_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -204,52 +202,52 @@ impl WeightInfo for () { // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - (27_696_000 as Weight) + (28_774_000 as Weight) // Standard Error: 2_000 - .saturating_add((241_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((150_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((111_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((67_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - (22_849_000 as Weight) - // Standard Error: 2_000 - .saturating_add((140_000 as Weight).saturating_mul(p as Weight)) + (23_571_000 as Weight) + // Standard Error: 1_000 + .saturating_add((110_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - (19_350_000 as Weight) + (23_613_000 as Weight) // Standard Error: 2_000 - .saturating_add((147_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - (18_878_000 as Weight) - // Standard Error: 2_000 - .saturating_add((112_000 as Weight).saturating_mul(p as Weight)) + (19_968_000 as Weight) + // Standard Error: 1_000 + .saturating_add((74_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - (25_743_000 as Weight) + (26_479_000 as Weight) // Standard Error: 2_000 - .saturating_add((25_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((37_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - (20_484_000 as Weight) - // Standard Error: 2_000 - .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) + (20_816_000 as Weight) + // Standard Error: 1_000 + .saturating_add((67_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index 4e5fb91ae69e1..34a58b9e51ff2 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -18,24 +18,22 @@ //! Autogenerated weights for pallet_recovery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-04-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet // --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet-recovery +// --pallet=pallet_recovery // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/recovery/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,35 +60,35 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Recovery Proxy (r:1 w:0) fn as_recovered() -> Weight { - (3_667_000 as Weight) + (3_732_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Recovery Proxy (r:0 w:1) fn set_recovered() -> Weight { - (10_149_000 as Weight) + (10_201_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:1) fn create_recovery(n: u32, ) -> Weight { - (23_154_000 as Weight) - // Standard Error: 16_000 - .saturating_add((235_000 as Weight).saturating_mul(n as Weight)) + (23_334_000 as Weight) + // Standard Error: 13_000 + .saturating_add((201_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn initiate_recovery() -> Weight { - (28_857_000 as Weight) + (28_358_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn vouch_recovery(n: u32, ) -> Weight { - (17_841_000 as Weight) - // Standard Error: 10_000 - .saturating_add((349_000 as Weight).saturating_mul(n as Weight)) + (17_667_000 as Weight) + // Standard Error: 13_000 + .saturating_add((342_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -98,33 +96,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Proxy (r:1 w:1) fn claim_recovery(n: u32, ) -> Weight { - (24_927_000 as Weight) + (24_591_000 as Weight) // Standard Error: 14_000 - .saturating_add((222_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((242_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Recovery ActiveRecoveries (r:1 w:1) // Storage: System Account (r:1 w:1) fn close_recovery(n: u32, ) -> Weight { - (28_201_000 as Weight) - // Standard Error: 17_000 - .saturating_add((272_000 as Weight).saturating_mul(n as Weight)) + (28_763_000 as Weight) + // Standard Error: 12_000 + .saturating_add((142_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Recoverable (r:1 w:1) fn remove_recovery(n: u32, ) -> Weight { - (27_531_000 as Weight) - // Standard Error: 10_000 - .saturating_add((218_000 as Weight).saturating_mul(n as Weight)) + (27_357_000 as Weight) + // Standard Error: 17_000 + .saturating_add((212_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Recovery Proxy (r:1 w:1) fn cancel_recovered() -> Weight { - (9_015_000 as Weight) + (9_068_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -134,35 +132,35 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Recovery Proxy (r:1 w:0) fn as_recovered() -> Weight { - (3_667_000 as Weight) + (3_732_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Recovery Proxy (r:0 w:1) fn set_recovered() -> Weight { - (10_149_000 as Weight) + (10_201_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:1) fn create_recovery(n: u32, ) -> Weight { - (23_154_000 as Weight) - // Standard Error: 16_000 - .saturating_add((235_000 as Weight).saturating_mul(n as Weight)) + (23_334_000 as Weight) + // Standard Error: 13_000 + .saturating_add((201_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn initiate_recovery() -> Weight { - (28_857_000 as Weight) + (28_358_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn vouch_recovery(n: u32, ) -> Weight { - (17_841_000 as Weight) - // Standard Error: 10_000 - .saturating_add((349_000 as Weight).saturating_mul(n as Weight)) + (17_667_000 as Weight) + // Standard Error: 13_000 + .saturating_add((342_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -170,33 +168,33 @@ impl WeightInfo for () { // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Proxy (r:1 w:1) fn claim_recovery(n: u32, ) -> Weight { - (24_927_000 as Weight) + (24_591_000 as Weight) // Standard Error: 14_000 - .saturating_add((222_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((242_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Recovery ActiveRecoveries (r:1 w:1) // Storage: System Account (r:1 w:1) fn close_recovery(n: u32, ) -> Weight { - (28_201_000 as Weight) - // Standard Error: 17_000 - .saturating_add((272_000 as Weight).saturating_mul(n as Weight)) + (28_763_000 as Weight) + // Standard Error: 12_000 + .saturating_add((142_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Recoverable (r:1 w:1) fn remove_recovery(n: u32, ) -> Weight { - (27_531_000 as Weight) - // Standard Error: 10_000 - .saturating_add((218_000 as Weight).saturating_mul(n as Weight)) + (27_357_000 as Weight) + // Standard Error: 17_000 + .saturating_add((212_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Recovery Proxy (r:1 w:1) fn cancel_recovered() -> Weight { - (9_015_000 as Weight) + (9_068_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index 202901bdd10bd..d9ddbed49e883 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_referenda //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-12-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/referenda/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/referenda/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -80,14 +80,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - (42_395_000 as Weight) + (30_596_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - (48_113_000 as Weight) + (40_115_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -95,7 +95,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - (53_624_000 as Weight) + (45_739_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -103,7 +103,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - (52_560_000 as Weight) + (45_741_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -111,7 +111,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - (54_067_000 as Weight) + (51_422_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -119,34 +119,34 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - (52_457_000 as Weight) + (48_714_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - (28_504_000 as Weight) + (24_896_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - (40_425_000 as Weight) + (30_511_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - (65_974_000 as Weight) + (55_662_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - (8_904_000 as Weight) + (6_659_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -154,7 +154,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - (181_387_000 as Weight) + (109_530_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -162,7 +162,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - (179_753_000 as Weight) + (110_576_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -170,7 +170,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - (53_592_000 as Weight) + (39_327_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -178,7 +178,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - (53_173_000 as Weight) + (39_179_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -187,7 +187,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - (55_770_000 as Weight) + (41_251_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -196,27 +196,27 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - (53_922_000 as Weight) + (41_009_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - (26_906_000 as Weight) + (20_228_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - (27_943_000 as Weight) + (20_456_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - (20_256_000 as Weight) + (16_202_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -224,7 +224,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - (30_964_000 as Weight) + (30_335_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -232,35 +232,35 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - (31_763_000 as Weight) + (32_700_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - (28_892_000 as Weight) + (27_225_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - (29_666_000 as Weight) + (28_355_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - (29_740_000 as Weight) + (26_515_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - (29_661_000 as Weight) + (24_991_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -269,14 +269,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Lookup (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn nudge_referendum_approved() -> Weight { - (55_736_000 as Weight) + (45_164_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - (32_726_000 as Weight) + (28_026_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -288,14 +288,14 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - (42_395_000 as Weight) + (30_596_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - (48_113_000 as Weight) + (40_115_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -303,7 +303,7 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - (53_624_000 as Weight) + (45_739_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -311,7 +311,7 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - (52_560_000 as Weight) + (45_741_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -319,7 +319,7 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - (54_067_000 as Weight) + (51_422_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -327,34 +327,34 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - (52_457_000 as Weight) + (48_714_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - (28_504_000 as Weight) + (24_896_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - (40_425_000 as Weight) + (30_511_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - (65_974_000 as Weight) + (55_662_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - (8_904_000 as Weight) + (6_659_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -362,7 +362,7 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - (181_387_000 as Weight) + (109_530_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -370,7 +370,7 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - (179_753_000 as Weight) + (110_576_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -378,7 +378,7 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - (53_592_000 as Weight) + (39_327_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -386,7 +386,7 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - (53_173_000 as Weight) + (39_179_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -395,7 +395,7 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - (55_770_000 as Weight) + (41_251_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -404,27 +404,27 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - (53_922_000 as Weight) + (41_009_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - (26_906_000 as Weight) + (20_228_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - (27_943_000 as Weight) + (20_456_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - (20_256_000 as Weight) + (16_202_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -432,7 +432,7 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - (30_964_000 as Weight) + (30_335_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -440,35 +440,35 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - (31_763_000 as Weight) + (32_700_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - (28_892_000 as Weight) + (27_225_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - (29_666_000 as Weight) + (28_355_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - (29_740_000 as Weight) + (26_515_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - (29_661_000 as Weight) + (24_991_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -477,14 +477,14 @@ impl WeightInfo for () { // Storage: Scheduler Lookup (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn nudge_referendum_approved() -> Weight { - (55_736_000 as Weight) + (45_164_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - (32_726_000 as Weight) + (28_026_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index 50b0fc3ebfc19..b667a03bbd472 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_remark //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-03-11, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/remark/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/remark/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,7 +52,7 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn store(l: u32, ) -> Weight { - (18_328_000 as Weight) + (9_699_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -63,7 +63,7 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn store(l: u32, ) -> Weight { - (18_328_000 as Weight) + (9_699_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index dd00b8dfe6cd6..d56c3208b44af 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/scheduler/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -70,9 +68,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (11_587_000 as Weight) - // Standard Error: 17_000 - .saturating_add((17_428_000 as Weight).saturating_mul(s as Weight)) + (9_814_000 as Weight) + // Standard Error: 13_000 + .saturating_add((18_293_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -83,9 +81,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (8_965_000 as Weight) + (9_050_000 as Weight) // Standard Error: 11_000 - .saturating_add((13_410_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((14_029_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -95,9 +93,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (8_654_000 as Weight) - // Standard Error: 17_000 - .saturating_add((14_990_000 as Weight).saturating_mul(s as Weight)) + (9_717_000 as Weight) + // Standard Error: 14_000 + .saturating_add((15_584_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -107,9 +105,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (9_303_000 as Weight) - // Standard Error: 10_000 - .saturating_add((12_244_000 as Weight).saturating_mul(s as Weight)) + (9_422_000 as Weight) + // Standard Error: 9_000 + .saturating_add((12_812_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -119,9 +117,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (7_506_000 as Weight) - // Standard Error: 3_000 - .saturating_add((5_208_000 as Weight).saturating_mul(s as Weight)) + (6_504_000 as Weight) + // Standard Error: 7_000 + .saturating_add((5_410_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -130,9 +128,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (8_046_000 as Weight) + (8_690_000 as Weight) // Standard Error: 3_000 - .saturating_add((2_914_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_951_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -140,9 +138,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (13_704_000 as Weight) - // Standard Error: 4_000 - .saturating_add((8_186_000 as Weight).saturating_mul(s as Weight)) + (14_613_000 as Weight) + // Standard Error: 5_000 + .saturating_add((8_479_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -150,9 +148,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (12_668_000 as Weight) - // Standard Error: 5_000 - .saturating_add((5_868_000 as Weight).saturating_mul(s as Weight)) + (13_356_000 as Weight) + // Standard Error: 4_000 + .saturating_add((6_112_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -161,42 +159,42 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (13_946_000 as Weight) - // Standard Error: 4_000 - .saturating_add((4_367_000 as Weight).saturating_mul(s as Weight)) + (14_254_000 as Weight) + // Standard Error: 3_000 + .saturating_add((4_529_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (13_151_000 as Weight) + (13_680_000 as Weight) // Standard Error: 4_000 - .saturating_add((3_455_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((3_559_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (14_040_000 as Weight) + (14_821_000 as Weight) // Standard Error: 1_000 - .saturating_add((89_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((85_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (14_376_000 as Weight) + (15_029_000 as Weight) // Standard Error: 1_000 - .saturating_add((576_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((595_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (16_806_000 as Weight) + (17_498_000 as Weight) // Standard Error: 1_000 .saturating_add((102_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -205,9 +203,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (15_852_000 as Weight) - // Standard Error: 2_000 - .saturating_add((590_000 as Weight).saturating_mul(s as Weight)) + (16_695_000 as Weight) + // Standard Error: 1_000 + .saturating_add((610_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -220,9 +218,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (11_587_000 as Weight) - // Standard Error: 17_000 - .saturating_add((17_428_000 as Weight).saturating_mul(s as Weight)) + (9_814_000 as Weight) + // Standard Error: 13_000 + .saturating_add((18_293_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -233,9 +231,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (8_965_000 as Weight) + (9_050_000 as Weight) // Standard Error: 11_000 - .saturating_add((13_410_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((14_029_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -245,9 +243,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (8_654_000 as Weight) - // Standard Error: 17_000 - .saturating_add((14_990_000 as Weight).saturating_mul(s as Weight)) + (9_717_000 as Weight) + // Standard Error: 14_000 + .saturating_add((15_584_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -257,9 +255,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (9_303_000 as Weight) - // Standard Error: 10_000 - .saturating_add((12_244_000 as Weight).saturating_mul(s as Weight)) + (9_422_000 as Weight) + // Standard Error: 9_000 + .saturating_add((12_812_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -269,9 +267,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (7_506_000 as Weight) - // Standard Error: 3_000 - .saturating_add((5_208_000 as Weight).saturating_mul(s as Weight)) + (6_504_000 as Weight) + // Standard Error: 7_000 + .saturating_add((5_410_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -280,9 +278,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (8_046_000 as Weight) + (8_690_000 as Weight) // Standard Error: 3_000 - .saturating_add((2_914_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_951_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -290,9 +288,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (13_704_000 as Weight) - // Standard Error: 4_000 - .saturating_add((8_186_000 as Weight).saturating_mul(s as Weight)) + (14_613_000 as Weight) + // Standard Error: 5_000 + .saturating_add((8_479_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -300,9 +298,9 @@ impl WeightInfo for () { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (12_668_000 as Weight) - // Standard Error: 5_000 - .saturating_add((5_868_000 as Weight).saturating_mul(s as Weight)) + (13_356_000 as Weight) + // Standard Error: 4_000 + .saturating_add((6_112_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -311,42 +309,42 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (13_946_000 as Weight) - // Standard Error: 4_000 - .saturating_add((4_367_000 as Weight).saturating_mul(s as Weight)) + (14_254_000 as Weight) + // Standard Error: 3_000 + .saturating_add((4_529_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (13_151_000 as Weight) + (13_680_000 as Weight) // Standard Error: 4_000 - .saturating_add((3_455_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((3_559_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (14_040_000 as Weight) + (14_821_000 as Weight) // Standard Error: 1_000 - .saturating_add((89_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((85_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (14_376_000 as Weight) + (15_029_000 as Weight) // Standard Error: 1_000 - .saturating_add((576_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((595_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (16_806_000 as Weight) + (17_498_000 as Weight) // Standard Error: 1_000 .saturating_add((102_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -355,9 +353,9 @@ impl WeightInfo for () { // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (15_852_000 as Weight) - // Standard Error: 2_000 - .saturating_add((590_000 as Weight).saturating_mul(s as Weight)) + (16_695_000 as Weight) + // Standard Error: 1_000 + .saturating_add((610_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index 39276fb0b17ee..eabb26dcb32f4 100644 --- a/frame/session/src/weights.rs +++ b/frame/session/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_session //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/session/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,7 +55,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - (42_131_000 as Weight) + (43_230_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -65,7 +63,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - (32_374_000 as Weight) + (33_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -77,7 +75,7 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - (42_131_000 as Weight) + (43_230_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -85,7 +83,7 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - (32_374_000 as Weight) + (33_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 9d43cd8822600..e7f2e06e6dd07 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-03-02, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/staking/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/staking/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -86,7 +86,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (37_238_000 as Weight) + (38_923_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -96,7 +96,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (64_061_000 as Weight) + (68_860_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -110,7 +110,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (70_069_000 as Weight) + (74_815_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -119,9 +119,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (29_855_000 as Weight) + (30_797_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((57_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -138,10 +138,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - (57_313_000 as Weight) - // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + (60_515_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(11 as Weight)) } @@ -150,23 +148,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) // Storage: Staking MaxValidatorsCount (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) + // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (44_448_000 as Weight) - .saturating_add(T::DbWeight::get().reads(12 as Weight)) - .saturating_add(T::DbWeight::get().writes(8 as Weight)) + (48_461_000 as Weight) + .saturating_add(T::DbWeight::get().reads(11 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (13_902_000 as Weight) - // Standard Error: 12_000 - .saturating_add((7_421_000 as Weight).saturating_mul(k as Weight)) + (18_839_000 as Weight) + // Standard Error: 11_000 + .saturating_add((7_658_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -183,9 +181,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (49_580_000 as Weight) - // Standard Error: 9_000 - .saturating_add((3_362_000 as Weight).saturating_mul(n as Weight)) + (51_547_000 as Weight) + // Standard Error: 10_000 + .saturating_add((3_610_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(6 as Weight)) @@ -198,47 +196,47 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (44_180_000 as Weight) + (45_828_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (7_922_000 as Weight) + (7_646_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (15_436_000 as Weight) + (15_974_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (1_091_000 as Weight) + (1_248_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (1_204_000 as Weight) + (1_350_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (1_208_000 as Weight) + (1_276_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (1_220_000 as Weight) + (1_321_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (1_473_000 as Weight) + (1_517_000 as Weight) // Standard Error: 0 .saturating_add((9_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -257,18 +255,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (55_815_000 as Weight) + (58_451_000 as Weight) // Standard Error: 1_000 - .saturating_add((808_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((835_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (903_077_000 as Weight) - // Standard Error: 53_000 - .saturating_add((4_434_000 as Weight).saturating_mul(s as Weight)) + (895_257_000 as Weight) + // Standard Error: 56_000 + .saturating_add((4_978_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -283,9 +281,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (79_440_000 as Weight) - // Standard Error: 14_000 - .saturating_add((24_005_000 as Weight).saturating_mul(n as Weight)) + (71_290_000 as Weight) + // Standard Error: 12_000 + .saturating_add((23_818_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -303,9 +301,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (99_118_000 as Weight) - // Standard Error: 20_000 - .saturating_add((33_274_000 as Weight).saturating_mul(n as Weight)) + (86_724_000 as Weight) + // Standard Error: 29_000 + .saturating_add((33_575_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -318,9 +316,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (63_335_000 as Weight) - // Standard Error: 2_000 - .saturating_add((53_000 as Weight).saturating_mul(l as Weight)) + (68_577_000 as Weight) + // Standard Error: 3_000 + .saturating_add((55_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(9 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -336,7 +334,7 @@ impl WeightInfo for SubstrateWeight { fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) // Standard Error: 58_000 - .saturating_add((20_386_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((20_425_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) .saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -355,22 +353,22 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (61_486_000 as Weight) + (63_865_000 as Weight) // Standard Error: 0 - .saturating_add((809_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((839_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } - // Storage: Staking CounterForNominators (r:1 w:0) - // Storage: Staking CounterForValidators (r:1 w:0) + // Storage: BagsList CounterForListNodes (r:1 w:0) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: BagsList ListBags (r:200 w:0) + // Storage: BagsList ListNodes (r:101 w:0) + // Storage: Staking Nominators (r:101 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking Bonded (r:101 w:0) // Storage: Staking Ledger (r:101 w:0) - // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:100 w:0) - // Storage: Staking Nominators (r:100 w:0) + // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking ValidatorCount (r:1 w:0) // Storage: Staking MinimumValidatorCount (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:1) @@ -382,43 +380,42 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 878_000 - .saturating_add((212_233_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 881_000 + .saturating_add((211_756_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 44_000 - .saturating_add((30_364_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((30_413_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) + .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) } - // Storage: Staking CounterForNominators (r:1 w:0) - // Storage: Staking CounterForValidators (r:1 w:0) - // Storage: Staking Validators (r:501 w:0) - // Storage: Staking Bonded (r:1500 w:0) - // Storage: Staking Ledger (r:1500 w:0) + // Storage: BagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:1000 w:0) - // Storage: Staking Nominators (r:1000 w:0) + // Storage: BagsList ListNodes (r:1500 w:0) + // Storage: Staking Nominators (r:1500 w:0) + // Storage: Staking Validators (r:500 w:0) + // Storage: Staking Bonded (r:1500 w:0) + // Storage: Staking Ledger (r:1500 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 95_000 - .saturating_add((18_439_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 95_000 - .saturating_add((20_382_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 3_232_000 - .saturating_add((4_870_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(204 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) + // Standard Error: 86_000 + .saturating_add((23_814_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 86_000 + .saturating_add((21_657_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 2_924_000 + .saturating_add((19_067_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(202 as Weight)) + .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 29_000 - .saturating_add((7_552_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 32_000 + .saturating_add((7_861_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -429,7 +426,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - (3_597_000 as Weight) + (3_688_000 as Weight) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking MinCommission (r:0 w:1) @@ -439,7 +436,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - (3_198_000 as Weight) + (3_414_000 as Weight) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -453,14 +450,14 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (55_725_000 as Weight) + (56_962_000 as Weight) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - (8_946_000 as Weight) + (9_465_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -475,7 +472,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (37_238_000 as Weight) + (38_923_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -485,7 +482,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (64_061_000 as Weight) + (68_860_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } @@ -499,7 +496,7 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (70_069_000 as Weight) + (74_815_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -508,9 +505,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (29_855_000 as Weight) + (30_797_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((57_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -527,10 +524,8 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - (57_313_000 as Weight) - // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + (60_515_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } @@ -539,23 +534,23 @@ impl WeightInfo for () { // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) // Storage: Staking MaxValidatorsCount (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) + // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: BagsList ListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (44_448_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(12 as Weight)) - .saturating_add(RocksDbWeight::get().writes(8 as Weight)) + (48_461_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(11 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (13_902_000 as Weight) - // Standard Error: 12_000 - .saturating_add((7_421_000 as Weight).saturating_mul(k as Weight)) + (18_839_000 as Weight) + // Standard Error: 11_000 + .saturating_add((7_658_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -572,9 +567,9 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (49_580_000 as Weight) - // Standard Error: 9_000 - .saturating_add((3_362_000 as Weight).saturating_mul(n as Weight)) + (51_547_000 as Weight) + // Standard Error: 10_000 + .saturating_add((3_610_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) @@ -587,47 +582,47 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (44_180_000 as Weight) + (45_828_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (7_922_000 as Weight) + (7_646_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (15_436_000 as Weight) + (15_974_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (1_091_000 as Weight) + (1_248_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (1_204_000 as Weight) + (1_350_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (1_208_000 as Weight) + (1_276_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (1_220_000 as Weight) + (1_321_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (1_473_000 as Weight) + (1_517_000 as Weight) // Standard Error: 0 .saturating_add((9_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -646,18 +641,18 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (55_815_000 as Weight) + (58_451_000 as Weight) // Standard Error: 1_000 - .saturating_add((808_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((835_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (903_077_000 as Weight) - // Standard Error: 53_000 - .saturating_add((4_434_000 as Weight).saturating_mul(s as Weight)) + (895_257_000 as Weight) + // Standard Error: 56_000 + .saturating_add((4_978_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -672,9 +667,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (79_440_000 as Weight) - // Standard Error: 14_000 - .saturating_add((24_005_000 as Weight).saturating_mul(n as Weight)) + (71_290_000 as Weight) + // Standard Error: 12_000 + .saturating_add((23_818_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -692,9 +687,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (99_118_000 as Weight) - // Standard Error: 20_000 - .saturating_add((33_274_000 as Weight).saturating_mul(n as Weight)) + (86_724_000 as Weight) + // Standard Error: 29_000 + .saturating_add((33_575_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -707,9 +702,9 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (63_335_000 as Weight) - // Standard Error: 2_000 - .saturating_add((53_000 as Weight).saturating_mul(l as Weight)) + (68_577_000 as Weight) + // Standard Error: 3_000 + .saturating_add((55_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(9 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -725,7 +720,7 @@ impl WeightInfo for () { fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) // Standard Error: 58_000 - .saturating_add((20_386_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((20_425_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) .saturating_add(RocksDbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -744,22 +739,22 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (61_486_000 as Weight) + (63_865_000 as Weight) // Standard Error: 0 - .saturating_add((809_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((839_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } - // Storage: Staking CounterForNominators (r:1 w:0) - // Storage: Staking CounterForValidators (r:1 w:0) + // Storage: BagsList CounterForListNodes (r:1 w:0) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: BagsList ListBags (r:200 w:0) + // Storage: BagsList ListNodes (r:101 w:0) + // Storage: Staking Nominators (r:101 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking Bonded (r:101 w:0) // Storage: Staking Ledger (r:101 w:0) - // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:100 w:0) - // Storage: Staking Nominators (r:100 w:0) + // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking ValidatorCount (r:1 w:0) // Storage: Staking MinimumValidatorCount (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:1) @@ -771,43 +766,42 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 878_000 - .saturating_add((212_233_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 881_000 + .saturating_add((211_756_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 44_000 - .saturating_add((30_364_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((30_413_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) + .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) } - // Storage: Staking CounterForNominators (r:1 w:0) - // Storage: Staking CounterForValidators (r:1 w:0) - // Storage: Staking Validators (r:501 w:0) - // Storage: Staking Bonded (r:1500 w:0) - // Storage: Staking Ledger (r:1500 w:0) + // Storage: BagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:1000 w:0) - // Storage: Staking Nominators (r:1000 w:0) + // Storage: BagsList ListNodes (r:1500 w:0) + // Storage: Staking Nominators (r:1500 w:0) + // Storage: Staking Validators (r:500 w:0) + // Storage: Staking Bonded (r:1500 w:0) + // Storage: Staking Ledger (r:1500 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 95_000 - .saturating_add((18_439_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 95_000 - .saturating_add((20_382_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 3_232_000 - .saturating_add((4_870_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(204 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) + // Standard Error: 86_000 + .saturating_add((23_814_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 86_000 + .saturating_add((21_657_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 2_924_000 + .saturating_add((19_067_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(202 as Weight)) + .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 29_000 - .saturating_add((7_552_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 32_000 + .saturating_add((7_861_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -818,7 +812,7 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - (3_597_000 as Weight) + (3_688_000 as Weight) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking MinCommission (r:0 w:1) @@ -828,7 +822,7 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - (3_198_000 as Weight) + (3_414_000 as Weight) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -842,14 +836,14 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (55_725_000 as Weight) + (56_962_000 as Weight) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - (8_946_000 as Weight) + (9_465_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index 292c7d3e91d06..fc85a031b0852 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -168,10 +168,7 @@ pub mod constants { pub const WEIGHT_PER_NANOS: Weight = WEIGHT_PER_MICROS / 1000; // 1_000 // Expose the Block and Extrinsic base weights. - pub use super::{ - block_weights::constants::BlockExecutionWeight, - extrinsic_weights::constants::ExtrinsicBaseWeight, - }; + pub use super::{block_weights::BlockExecutionWeight, extrinsic_weights::ExtrinsicBaseWeight}; // Expose the DB weights. pub use super::{ diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index 4db90f0c0207a..d1d5f8320d104 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -15,32 +15,61 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, Weight}, - }; - - parameter_types! { - /// Importing a block with 0 Extrinsics. - pub const BlockExecutionWeight: Weight = 5_000_000 * constants::WEIGHT_PER_NANOS; - } +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-05-23 (Y/M/D) +//! +//! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` +//! WARMUPS: `10`, REPEAT: `100` +//! WEIGHT-PATH: `./frame/support/src/weights/` +//! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1`, WEIGHT-ADD: `0` + +// Executed Command: +// ./target/production/substrate +// benchmark +// overhead +// --dev +// --execution=wasm +// --wasm-execution=compiled +// --weight-path=./frame/support/src/weights/ +// --warmup=10 +// --repeat=100 + +use frame_support::{ + parameter_types, + weights::{constants::WEIGHT_PER_NANOS, Weight}, +}; + +parameter_types! { + /// Time to execute an empty block. + /// Calculated by multiplying the *Average* with `1` and adding `0`. + /// + /// Stats nanoseconds: + /// Min, Max: 5_295_788, 5_473_440 + /// Average: 5_343_308 + /// Median: 5_323_240 + /// Std-Dev: 38368.68 + /// + /// Percentiles nanoseconds: + /// 99th: 5_470_141 + /// 95th: 5_418_269 + /// 75th: 5_355_579 + pub const BlockExecutionWeight: Weight = 5_343_308 * WEIGHT_PER_NANOS; +} + +#[cfg(test)] +mod test_weights { + use frame_support::weights::constants; + + /// Checks that the weight exists and is sane. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + let w = super::BlockExecutionWeight::get(); - #[cfg(test)] - mod test_weights { - use frame_support::weights::constants; - - /// Checks that the weight exists and is sane. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn sane() { - let w = super::constants::BlockExecutionWeight::get(); - - // At least 100 µs. - assert!(w >= 100 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); - // At most 50 ms. - assert!(w <= 50 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms."); - } + // At least 100 µs. + assert!(w >= 100 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); + // At most 50 ms. + assert!(w <= 50 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms."); } } diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 158ba99c6a4c1..1a5a4e7a460c0 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -15,32 +15,61 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, Weight}, - }; - - parameter_types! { - /// Executing a NO-OP `System::remarks` Extrinsic. - pub const ExtrinsicBaseWeight: Weight = 125_000 * constants::WEIGHT_PER_NANOS; - } +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-05-23 (Y/M/D) +//! +//! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` +//! WARMUPS: `10`, REPEAT: `100` +//! WEIGHT-PATH: `./frame/support/src/weights/` +//! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1`, WEIGHT-ADD: `0` + +// Executed Command: +// ./target/production/substrate +// benchmark +// overhead +// --dev +// --execution=wasm +// --wasm-execution=compiled +// --weight-path=./frame/support/src/weights/ +// --warmup=10 +// --repeat=100 + +use frame_support::{ + parameter_types, + weights::{constants::WEIGHT_PER_NANOS, Weight}, +}; + +parameter_types! { + /// Time to execute a NO-OP extrinsic, for example `System::remark`. + /// Calculated by multiplying the *Average* with `1` and adding `0`. + /// + /// Stats nanoseconds: + /// Min, Max: 85_423, 86_142 + /// Average: 85_795 + /// Median: 85_790 + /// Std-Dev: 162.37 + /// + /// Percentiles nanoseconds: + /// 99th: 86_115 + /// 95th: 86_069 + /// 75th: 85_937 + pub const ExtrinsicBaseWeight: Weight = 85_795 * WEIGHT_PER_NANOS; +} + +#[cfg(test)] +mod test_weights { + use frame_support::weights::constants; + + /// Checks that the weight exists and is sane. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + let w = super::ExtrinsicBaseWeight::get(); - #[cfg(test)] - mod test_weights { - use frame_support::weights::constants; - - /// Checks that the weight exists and is sane. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn sane() { - let w = super::constants::ExtrinsicBaseWeight::get(); - - // At least 10 µs. - assert!(w >= 10 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs."); - // At most 1 ms. - assert!(w <= constants::WEIGHT_PER_MILLIS, "Weight should be at most 1 ms."); - } + // At least 10 µs. + assert!(w >= 10 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs."); + // At most 1 ms. + assert!(w <= constants::WEIGHT_PER_MILLIS, "Weight should be at most 1 ms."); } } diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index a016fe6e7d037..813183ecce188 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for frame_system //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/system/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -68,7 +66,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (2_864_000 as Weight) + (3_235_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -76,21 +74,21 @@ impl WeightInfo for SubstrateWeight { fn set_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((389_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((407_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((285_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((307_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_prefix(p: u32, ) -> Weight { - (753_000 as Weight) + (0 as Weight) // Standard Error: 0 - .saturating_add((630_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((672_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } } @@ -108,7 +106,7 @@ impl WeightInfo for () { // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (2_864_000 as Weight) + (3_235_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -116,21 +114,21 @@ impl WeightInfo for () { fn set_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((389_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((407_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((285_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((307_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_prefix(p: u32, ) -> Weight { - (753_000 as Weight) + (0 as Weight) // Standard Error: 0 - .saturating_add((630_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((672_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } } diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index 33d7d6a4b9e37..7c130d69c51d6 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_timestamp //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/timestamp/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,12 +54,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - (5_247_000 as Weight) + (5_490_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (2_604_000 as Weight) + (2_618_000 as Weight) } } @@ -70,11 +68,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - (5_247_000 as Weight) + (5_490_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (2_604_000 as Weight) + (2_618_000 as Weight) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 2ba15a0c2fcc0..9e49dce410ef8 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_tips //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/tips/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -60,7 +58,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - (25_262_000 as Weight) + (26_613_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -69,7 +67,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - (24_162_000 as Weight) + (25_001_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -77,20 +75,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - (16_435_000 as Weight) + (17_490_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 4_000 - .saturating_add((231_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 5_000 + .saturating_add((183_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - (10_427_000 as Weight) + (9_634_000 as Weight) // Standard Error: 7_000 - .saturating_add((507_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((343_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -99,18 +97,18 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - (40_901_000 as Weight) + (41_967_000 as Weight) // Standard Error: 10_000 - .saturating_add((281_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((264_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - (14_636_000 as Weight) + (14_917_000 as Weight) // Standard Error: 4_000 - .saturating_add((29_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((61_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -121,7 +119,7 @@ impl WeightInfo for () { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - (25_262_000 as Weight) + (26_613_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -130,7 +128,7 @@ impl WeightInfo for () { // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - (24_162_000 as Weight) + (25_001_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -138,20 +136,20 @@ impl WeightInfo for () { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - (16_435_000 as Weight) + (17_490_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 4_000 - .saturating_add((231_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 5_000 + .saturating_add((183_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - (10_427_000 as Weight) + (9_634_000 as Weight) // Standard Error: 7_000 - .saturating_add((507_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((343_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -160,18 +158,18 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - (40_901_000 as Weight) + (41_967_000 as Weight) // Standard Error: 10_000 - .saturating_add((281_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((264_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - (14_636_000 as Weight) + (14_917_000 as Weight) // Standard Error: 4_000 - .saturating_add((29_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((61_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index a7033da7b80ce..8063783b4cc22 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_transaction_storage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/transaction-storage/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -74,7 +72,7 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - (41_286_000 as Weight) + (45_011_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -84,7 +82,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - (136_957_000 as Weight) + (98_295_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -112,7 +110,7 @@ impl WeightInfo for () { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - (41_286_000 as Weight) + (45_011_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -122,7 +120,7 @@ impl WeightInfo for () { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - (136_957_000 as Weight) + (98_295_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index c846a7f6885e9..4ae82d3b230d2 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_treasury //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-04-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -32,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/treasury/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/treasury/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -58,29 +57,29 @@ impl WeightInfo for SubstrateWeight { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (22_063_000 as Weight) + (22_397_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (25_965_000 as Weight) + (26_004_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (7_299_000 as Weight) + (7_415_000 as Weight) // Standard Error: 0 - .saturating_add((103_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Treasury Approvals (r:1 w:1) fn remove_approval() -> Weight { - (3_867_000 as Weight) + (3_827_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -89,9 +88,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (24_020_000 as Weight) - // Standard Error: 22_000 - .saturating_add((28_198_000 as Weight).saturating_mul(p as Weight)) + (25_129_000 as Weight) + // Standard Error: 16_000 + .saturating_add((28_612_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -104,29 +103,29 @@ impl WeightInfo for () { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (22_063_000 as Weight) + (22_397_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (25_965_000 as Weight) + (26_004_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (7_299_000 as Weight) + (7_415_000 as Weight) // Standard Error: 0 - .saturating_add((103_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Treasury Approvals (r:1 w:1) fn remove_approval() -> Weight { - (3_867_000 as Weight) + (3_827_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -135,9 +134,9 @@ impl WeightInfo for () { // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (24_020_000 as Weight) - // Standard Error: 22_000 - .saturating_add((28_198_000 as Weight).saturating_mul(p as Weight)) + (25_129_000 as Weight) + // Standard Error: 16_000 + .saturating_add((28_612_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 98cc823f0ccbd..127e5ccbb12a3 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -32,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/uniques/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/uniques/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -77,14 +76,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (23_770_000 as Weight) + (23_990_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (13_759_000 as Weight) + (13_472_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -97,12 +96,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((9_387_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 16_000 - .saturating_add((967_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 16_000 - .saturating_add((799_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 13_000 + .saturating_add((9_507_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 13_000 + .saturating_add((912_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 13_000 + .saturating_add((801_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -115,7 +114,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (31_588_000 as Weight) + (32_519_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -123,7 +122,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (31_125_000 as Weight) + (32_024_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -131,7 +130,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (22_955_000 as Weight) + (23_948_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -139,8 +138,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 12_000 - .saturating_add((11_761_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 11_000 + .saturating_add((11_911_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -149,26 +148,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (17_808_000 as Weight) + (18_448_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (18_342_000 as Weight) + (18_704_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (13_423_000 as Weight) + (13_925_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (13_453_000 as Weight) + (13_902_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -176,20 +175,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (20_745_000 as Weight) + (20_949_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (14_192_000 as Weight) + (14_531_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (16_488_000 as Weight) + (16_623_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -197,7 +196,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (37_207_000 as Weight) + (37_593_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -205,62 +204,62 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (35_432_000 as Weight) + (35_304_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (28_655_000 as Weight) + (29_353_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (28_898_000 as Weight) + (29_323_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (27_890_000 as Weight) + (28_806_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (26_538_000 as Weight) + (26_744_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (18_961_000 as Weight) + (19_485_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (19_116_000 as Weight) + (19_494_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (17_154_000 as Weight) + (17_456_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (16_060_000 as Weight) + (16_780_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -271,14 +270,14 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (23_770_000 as Weight) + (23_990_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (13_759_000 as Weight) + (13_472_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -291,12 +290,12 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((9_387_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 16_000 - .saturating_add((967_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 16_000 - .saturating_add((799_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 13_000 + .saturating_add((9_507_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 13_000 + .saturating_add((912_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 13_000 + .saturating_add((801_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -309,7 +308,7 @@ impl WeightInfo for () { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (31_588_000 as Weight) + (32_519_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -317,7 +316,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (31_125_000 as Weight) + (32_024_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -325,7 +324,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (22_955_000 as Weight) + (23_948_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -333,8 +332,8 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 12_000 - .saturating_add((11_761_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 11_000 + .saturating_add((11_911_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -343,26 +342,26 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (17_808_000 as Weight) + (18_448_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (18_342_000 as Weight) + (18_704_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (13_423_000 as Weight) + (13_925_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (13_453_000 as Weight) + (13_902_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -370,20 +369,20 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (20_745_000 as Weight) + (20_949_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (14_192_000 as Weight) + (14_531_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (16_488_000 as Weight) + (16_623_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -391,7 +390,7 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (37_207_000 as Weight) + (37_593_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -399,62 +398,62 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (35_432_000 as Weight) + (35_304_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (28_655_000 as Weight) + (29_353_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (28_898_000 as Weight) + (29_323_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (27_890_000 as Weight) + (28_806_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (26_538_000 as Weight) + (26_744_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (18_961_000 as Weight) + (19_485_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (19_116_000 as Weight) + (19_494_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (17_154_000 as Weight) + (17_456_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (16_060_000 as Weight) + (16_780_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 34dad8d735a2e..d3cd7530c2584 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_utility //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/utility/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,49 +55,49 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn batch(c: u32, ) -> Weight { - (18_598_000 as Weight) + (14_744_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_374_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_549_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (1_650_000 as Weight) + (1_412_000 as Weight) } fn batch_all(c: u32, ) -> Weight { - (13_988_000 as Weight) + (20_835_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_481_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_704_000 as Weight).saturating_mul(c as Weight)) } fn dispatch_as() -> Weight { - (8_463_000 as Weight) + (8_889_000 as Weight) } fn force_batch(c: u32, ) -> Weight { - (13_988_000 as Weight) + (13_155_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_481_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_555_000 as Weight).saturating_mul(c as Weight)) } } // For backwards compatibility and tests impl WeightInfo for () { fn batch(c: u32, ) -> Weight { - (18_598_000 as Weight) + (14_744_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_374_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_549_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (1_650_000 as Weight) + (1_412_000 as Weight) } fn batch_all(c: u32, ) -> Weight { - (13_988_000 as Weight) + (20_835_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_481_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_704_000 as Weight).saturating_mul(c as Weight)) } fn dispatch_as() -> Weight { - (8_463_000 as Weight) + (8_889_000 as Weight) } fn force_batch(c: u32, ) -> Weight { - (13_988_000 as Weight) + (13_155_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_481_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_555_000 as Weight).saturating_mul(c as Weight)) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index 140c1889d6e54..356cd003d8848 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_vesting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,11 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --template=./.maintain/frame-weight-template.hbs // --output=./frame/vesting/src/weights.rs -// --template=.maintain/frame-weight-template.hbs -// --header=HEADER-APACHE2 -// --raw #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,22 +60,22 @@ impl WeightInfo for SubstrateWeight { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - (27_037_000 as Weight) + (27_818_000 as Weight) // Standard Error: 1_000 - .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((69_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((74_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - (26_627_000 as Weight) + (27_708_000 as Weight) // Standard Error: 1_000 - .saturating_add((82_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((79_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -85,11 +83,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - (26_672_000 as Weight) + (27_854_000 as Weight) // Standard Error: 1_000 - .saturating_add((85_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((73_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -97,11 +95,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - (26_682_000 as Weight) + (27_738_000 as Weight) // Standard Error: 1_000 - .saturating_add((74_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((71_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((42_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -109,11 +107,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - (42_066_000 as Weight) + (43_640_000 as Weight) // Standard Error: 1_000 - .saturating_add((83_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((71_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 3_000 - .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((45_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -121,11 +119,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - (41_672_000 as Weight) + (42_850_000 as Weight) // Standard Error: 1_000 - .saturating_add((84_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 3_000 - .saturating_add((46_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -133,11 +131,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (27_627_000 as Weight) - // Standard Error: 0 - .saturating_add((86_000 as Weight).saturating_mul(l as Weight)) + (28_683_000 as Weight) + // Standard Error: 1_000 + .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((68_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((63_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -145,11 +143,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (27_143_000 as Weight) - // Standard Error: 0 - .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) + (28_510_000 as Weight) // Standard Error: 1_000 - .saturating_add((72_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((65_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -160,22 +158,22 @@ impl WeightInfo for () { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - (27_037_000 as Weight) + (27_818_000 as Weight) // Standard Error: 1_000 - .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((69_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((74_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - (26_627_000 as Weight) + (27_708_000 as Weight) // Standard Error: 1_000 - .saturating_add((82_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((79_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -183,11 +181,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - (26_672_000 as Weight) + (27_854_000 as Weight) // Standard Error: 1_000 - .saturating_add((85_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((73_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -195,11 +193,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - (26_682_000 as Weight) + (27_738_000 as Weight) // Standard Error: 1_000 - .saturating_add((74_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((71_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((42_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -207,11 +205,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - (42_066_000 as Weight) + (43_640_000 as Weight) // Standard Error: 1_000 - .saturating_add((83_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((71_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 3_000 - .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((45_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -219,11 +217,11 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - (41_672_000 as Weight) + (42_850_000 as Weight) // Standard Error: 1_000 - .saturating_add((84_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 3_000 - .saturating_add((46_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -231,11 +229,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (27_627_000 as Weight) - // Standard Error: 0 - .saturating_add((86_000 as Weight).saturating_mul(l as Weight)) + (28_683_000 as Weight) + // Standard Error: 1_000 + .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((68_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((63_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -243,11 +241,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (27_143_000 as Weight) - // Standard Error: 0 - .saturating_add((88_000 as Weight).saturating_mul(l as Weight)) + (28_510_000 as Weight) // Standard Error: 1_000 - .saturating_add((72_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((65_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index fdba734db64ba..b074cbf00d40d 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_whitelist //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-02-25, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/whitelist/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/whitelist/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,7 +56,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - (16_254_000 as Weight) + (16_953_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -64,7 +64,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn remove_whitelisted_call() -> Weight { - (18_348_000 as Weight) + (18_515_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -72,7 +72,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn dispatch_whitelisted_call() -> Weight { - (6_618_241_000 as Weight) + (5_870_296_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -80,9 +80,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - (20_619_000 as Weight) + (21_179_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -93,7 +93,7 @@ impl WeightInfo for () { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - (16_254_000 as Weight) + (16_953_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -101,7 +101,7 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn remove_whitelisted_call() -> Weight { - (18_348_000 as Weight) + (18_515_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -109,7 +109,7 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn dispatch_whitelisted_call() -> Weight { - (6_618_241_000 as Weight) + (5_870_296_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -117,9 +117,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - (20_619_000 as Weight) + (21_179_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } diff --git a/scripts/run_all_benchmarks.sh b/scripts/run_all_benchmarks.sh new file mode 100755 index 0000000000000..8d0d3d5411ed9 --- /dev/null +++ b/scripts/run_all_benchmarks.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash + +# This file is part of Substrate. +# Copyright (C) 2022 Parity Technologies (UK) Ltd. +# SPDX-License-Identifier: Apache-2.0 +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script has three parts which all use the Substrate runtime: +# - Pallet benchmarking to update the pallet weights +# - Overhead benchmarking for the Extrinsic and Block weights +# - Machine benchmarking +# +# Should be run on a reference machine to gain accurate benchmarks +# current reference machine: https://github.com/paritytech/substrate/pull/5848 + +while getopts 'bfp:v' flag; do + case "${flag}" in + b) + # Skip build. + skip_build='true' + ;; + f) + # Fail if any sub-command in a pipe fails, not just the last one. + set -o pipefail + # Fail on undeclared variables. + set -u + # Fail if any sub-command fails. + set -e + # Fail on traps. + set -E + ;; + p) + # Start at pallet + start_pallet="${OPTARG}" + ;; + v) + # Echo all executed commands. + set -x + ;; + *) + # Exit early. + echo "Bad options. Check Script." + exit 1 + ;; + esac +done + + +if [ "$skip_build" != true ] +then + echo "[+] Compiling Substrate benchmarks..." + cargo build --profile=production --locked --features=runtime-benchmarks +fi + +# The executable to use. +SUBSTRATE=./target/production/substrate + +# Manually exclude some pallets. +EXCLUDED_PALLETS=( + # Helper pallets + "pallet_election_provider_support_benchmarking" + # Pallets without automatic benchmarking + "pallet_babe" + "pallet_grandpa" + "pallet_mmr" + "pallet_offences" +) + +# Load all pallet names in an array. +ALL_PALLETS=($( + $SUBSTRATE benchmark pallet --list --chain=dev |\ + tail -n+2 |\ + cut -d',' -f1 |\ + sort |\ + uniq +)) + +# Filter out the excluded pallets by concatenating the arrays and discarding duplicates. +PALLETS=($({ printf '%s\n' "${ALL_PALLETS[@]}" "${EXCLUDED_PALLETS[@]}"; } | sort | uniq -u)) + +echo "[+] Benchmarking ${#PALLETS[@]} Substrate pallets by excluding ${#EXCLUDED_PALLETS[@]} from ${#ALL_PALLETS[@]}." + +# Define the error file. +ERR_FILE="benchmarking_errors.txt" +# Delete the error file before each run. +rm -f $ERR_FILE + +# Benchmark each pallet. +for PALLET in "${PALLETS[@]}"; do + # If `-p` is used, skip benchmarks until the start pallet. + if [ ! -z "$start_pallet" ] && [ "$start_pallet" != "$PALLET" ] + then + echo "[+] Skipping ${PALLET}..." + continue + else + unset start_pallet + fi + + FOLDER="$(echo "${PALLET#*_}" | tr '_' '-')"; + WEIGHT_FILE="./frame/${FOLDER}/src/weights.rs" + echo "[+] Benchmarking $PALLET with weight file $WEIGHT_FILE"; + + OUTPUT=$( + $SUBSTRATE benchmark pallet \ + --chain=dev \ + --steps=50 \ + --repeat=20 \ + --pallet="$PALLET" \ + --extrinsic="*" \ + --execution=wasm \ + --wasm-execution=compiled \ + --template=./.maintain/frame-weight-template.hbs \ + --output="$WEIGHT_FILE" 2>&1 + ) + if [ $? -ne 0 ]; then + echo "$OUTPUT" >> "$ERR_FILE" + echo "[-] Failed to benchmark $PALLET. Error written to $ERR_FILE; continuing..." + fi +done + +# Update the block and extrinsic overhead weights. +echo "[+] Benchmarking block and extrinsic overheads..." +OUTPUT=$( + $SUBSTRATE benchmark overhead \ + --chain=dev \ + --execution=wasm \ + --wasm-execution=compiled \ + --weight-path="./frame/support/src/weights/" \ + --warmup=10 \ + --repeat=100 2>&1 +) +if [ $? -ne 0 ]; then + echo "$OUTPUT" >> "$ERR_FILE" + echo "[-] Failed to benchmark the block and extrinsic overheads. Error written to $ERR_FILE; continuing..." +fi + +echo "[+] Benchmarking the machine..." +OUTPUT=$( + $SUBSTRATE benchmark machine --chain=dev 2>&1 +) +if [ $? -ne 0 ]; then + # Do not write the error to the error file since it is not a benchmarking error. + echo "[-] Failed the machine benchmark:\n$OUTPUT" +fi + +# Check if the error file exists. +if [ -f "$ERR_FILE" ]; then + echo "[-] Some benchmarks failed. See: $ERR_FILE" + exit 1 +else + echo "[+] All benchmarks passed." + exit 0 +fi diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index ad33f55a9f363..6d3ae471d1cf2 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -41,13 +41,13 @@ parameter_types! { {{/if}} /// Calculated by multiplying the *{{params.weight.weight_metric}}* with `{{params.weight.weight_mul}}` and adding `{{params.weight.weight_add}}`. /// - /// Stats [NS]: + /// Stats nanoseconds: /// Min, Max: {{underscore stats.min}}, {{underscore stats.max}} /// Average: {{underscore stats.avg}} /// Median: {{underscore stats.median}} /// Std-Dev: {{stats.stddev}} /// - /// Percentiles [NS]: + /// Percentiles nanoseconds: /// 99th: {{underscore stats.p99}} /// 95th: {{underscore stats.p95}} /// 75th: {{underscore stats.p75}} @@ -65,7 +65,7 @@ mod test_weights { fn sane() { let w = super::{{long_name}}Weight::get(); - {{#if (eq short_name "block")}} + {{#if (eq short_name "block")}} // At least 100 µs. assert!(w >= 100 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); // At most 50 ms. diff --git a/utils/frame/benchmarking-cli/src/storage/weights.hbs b/utils/frame/benchmarking-cli/src/storage/weights.hbs index 63f896e1104b8..51878141d1449 100644 --- a/utils/frame/benchmarking-cli/src/storage/weights.hbs +++ b/utils/frame/benchmarking-cli/src/storage/weights.hbs @@ -49,13 +49,13 @@ pub mod constants { /// Time to read one storage item. /// Calculated by multiplying the *{{params.weight_params.weight_metric}}* of all values with `{{params.weight_params.weight_mul}}` and adding `{{params.weight_params.weight_add}}`. /// - /// Stats [NS]: + /// Stats nanoseconds: /// Min, Max: {{underscore read.0.min}}, {{underscore read.0.max}} /// Average: {{underscore read.0.avg}} /// Median: {{underscore read.0.median}} /// Std-Dev: {{read.0.stddev}} /// - /// Percentiles [NS]: + /// Percentiles nanoseconds: /// 99th: {{underscore read.0.p99}} /// 95th: {{underscore read.0.p95}} /// 75th: {{underscore read.0.p75}} @@ -64,13 +64,13 @@ pub mod constants { /// Time to write one storage item. /// Calculated by multiplying the *{{params.weight_params.weight_metric}}* of all values with `{{params.weight_params.weight_mul}}` and adding `{{params.weight_params.weight_add}}`. /// - /// Stats [NS]: + /// Stats nanoseconds: /// Min, Max: {{underscore write.0.min}}, {{underscore write.0.max}} /// Average: {{underscore write.0.avg}} /// Median: {{underscore write.0.median}} /// Std-Dev: {{write.0.stddev}} /// - /// Percentiles [NS]: + /// Percentiles nanoseconds: /// 99th: {{underscore write.0.p99}} /// 95th: {{underscore write.0.p95}} /// 75th: {{underscore write.0.p75}} From 3d5e30577325634c3ed2f2a27544858b56b21979 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 24 May 2022 14:37:04 +0900 Subject: [PATCH 0840/1472] Adjust maximum memory pages hard limit for the pooling instantiation strategy (#11482) * Run `sc-executor-wasmtime` unit tests for all instantiation strategies * Adjust maximum memory pages hard limit for the pooling instantiation strategy --- Cargo.lock | 1 + client/executor/wasmtime/Cargo.toml | 1 + client/executor/wasmtime/src/runtime.rs | 17 +++- client/executor/wasmtime/src/tests.rs | 112 +++++++++++++++++++----- 4 files changed, 106 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03bc44a0a848a..5b2ceb36f6152 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8278,6 +8278,7 @@ dependencies = [ "log", "parity-scale-codec", "parity-wasm 0.42.2", + "paste 1.0.6", "sc-allocator", "sc-executor-common", "sc-runtime-test", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index cbe6e1a0bd101..83859ee61be34 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -37,3 +37,4 @@ wat = "1.0" sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } sp-io = { version = "6.0.0", path = "../../../primitives/io" } tempfile = "3.3.0" +paste = "1.0" diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index dbe0b129757b7..8f6826653f27d 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -341,6 +341,21 @@ fn common_config(semantics: &Semantics) -> std::result::Result std::result::Result { + paste::item! { + #[test] + fn [<$method_name _recreate_instance_cow>]() { + $method_name( + InstantiationStrategy::RecreateInstanceCopyOnWrite + ); + } + + #[test] + fn [<$method_name _recreate_instance_vanilla>]() { + $method_name( + InstantiationStrategy::RecreateInstance + ); + } + + #[test] + fn [<$method_name _pooling_cow>]() { + $method_name( + InstantiationStrategy::PoolingCopyOnWrite + ); + } + + #[test] + fn [<$method_name _pooling_vanilla>]() { + $method_name( + InstantiationStrategy::Pooling + ); + } + } + }; + + ($method_name:ident) => { + test_wasm_execution!(@no_legacy_instance_reuse $method_name); + + paste::item! { + #[test] + fn [<$method_name _legacy_instance_reuse>]() { + $method_name( + InstantiationStrategy::LegacyInstanceReuse + ); + } + } + }; +} + struct RuntimeBuilder { code: Option, instantiation_strategy: InstantiationStrategy, @@ -36,12 +84,10 @@ struct RuntimeBuilder { } impl RuntimeBuilder { - /// Returns a new builder that won't use the fast instance reuse mechanism, but instead will - /// create a new runtime instance each time. - fn new_on_demand() -> Self { + fn new(instantiation_strategy: InstantiationStrategy) -> Self { Self { code: None, - instantiation_strategy: InstantiationStrategy::RecreateInstance, + instantiation_strategy, canonicalize_nans: false, deterministic_stack: false, extra_heap_pages: 1024, @@ -128,9 +174,9 @@ impl RuntimeBuilder { } } -#[test] -fn test_nan_canonicalization() { - let mut builder = RuntimeBuilder::new_on_demand().canonicalize_nans(true); +test_wasm_execution!(test_nan_canonicalization); +fn test_nan_canonicalization(instantiation_strategy: InstantiationStrategy) { + let mut builder = RuntimeBuilder::new(instantiation_strategy).canonicalize_nans(true); let runtime = builder.build(); let mut instance = runtime.new_instance().expect("failed to instantiate a runtime"); @@ -166,11 +212,11 @@ fn test_nan_canonicalization() { assert_eq!(res, CANONICAL_NAN_BITS); } -#[test] -fn test_stack_depth_reaching() { +test_wasm_execution!(test_stack_depth_reaching); +fn test_stack_depth_reaching(instantiation_strategy: InstantiationStrategy) { const TEST_GUARD_PAGE_SKIP: &str = include_str!("test-guard-page-skip.wat"); - let mut builder = RuntimeBuilder::new_on_demand() + let mut builder = RuntimeBuilder::new(instantiation_strategy) .use_wat(TEST_GUARD_PAGE_SKIP.to_string()) .deterministic_stack(true); @@ -186,33 +232,46 @@ fn test_stack_depth_reaching() { } } -#[test] -fn test_max_memory_pages_imported_memory_without_precompilation() { - test_max_memory_pages(true, false); +test_wasm_execution!(test_max_memory_pages_imported_memory_without_precompilation); +fn test_max_memory_pages_imported_memory_without_precompilation( + instantiation_strategy: InstantiationStrategy, +) { + test_max_memory_pages(instantiation_strategy, true, false); } -#[test] -fn test_max_memory_pages_exported_memory_without_precompilation() { - test_max_memory_pages(false, false); +test_wasm_execution!(test_max_memory_pages_exported_memory_without_precompilation); +fn test_max_memory_pages_exported_memory_without_precompilation( + instantiation_strategy: InstantiationStrategy, +) { + test_max_memory_pages(instantiation_strategy, false, false); } -#[test] -fn test_max_memory_pages_imported_memory_with_precompilation() { - test_max_memory_pages(true, true); +test_wasm_execution!(@no_legacy_instance_reuse test_max_memory_pages_imported_memory_with_precompilation); +fn test_max_memory_pages_imported_memory_with_precompilation( + instantiation_strategy: InstantiationStrategy, +) { + test_max_memory_pages(instantiation_strategy, true, true); } -#[test] -fn test_max_memory_pages_exported_memory_with_precompilation() { - test_max_memory_pages(false, true); +test_wasm_execution!(@no_legacy_instance_reuse test_max_memory_pages_exported_memory_with_precompilation); +fn test_max_memory_pages_exported_memory_with_precompilation( + instantiation_strategy: InstantiationStrategy, +) { + test_max_memory_pages(instantiation_strategy, false, true); } -fn test_max_memory_pages(import_memory: bool, precompile_runtime: bool) { +fn test_max_memory_pages( + instantiation_strategy: InstantiationStrategy, + import_memory: bool, + precompile_runtime: bool, +) { fn try_instantiate( max_memory_size: Option, wat: String, + instantiation_strategy: InstantiationStrategy, precompile_runtime: bool, ) -> Result<(), Box> { - let mut builder = RuntimeBuilder::new_on_demand() + let mut builder = RuntimeBuilder::new(instantiation_strategy) .use_wat(wat) .max_memory_size(max_memory_size) .precompile_runtime(precompile_runtime); @@ -265,6 +324,7 @@ fn test_max_memory_pages(import_memory: bool, precompile_runtime: bool) { */ memory(64511, None, import_memory) ), + instantiation_strategy, precompile_runtime, ) .unwrap(); @@ -288,6 +348,7 @@ fn test_max_memory_pages(import_memory: bool, precompile_runtime: bool) { // 1 initial, max is not specified. memory(1, None, import_memory) ), + instantiation_strategy, precompile_runtime, ) .unwrap(); @@ -309,6 +370,7 @@ fn test_max_memory_pages(import_memory: bool, precompile_runtime: bool) { // Max is 2048. memory(1, Some(2048), import_memory) ), + instantiation_strategy, precompile_runtime, ) .unwrap(); @@ -342,6 +404,7 @@ fn test_max_memory_pages(import_memory: bool, precompile_runtime: bool) { // Zero starting pages. memory(0, None, import_memory) ), + instantiation_strategy, precompile_runtime, ) .unwrap(); @@ -375,6 +438,7 @@ fn test_max_memory_pages(import_memory: bool, precompile_runtime: bool) { // Initial=1, meaning after heap pages mount the total will be already 1025. memory(1, None, import_memory) ), + instantiation_strategy, precompile_runtime, ) .unwrap(); From a001cbb2bb38aac3a4603426590713b2a6d96453 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 24 May 2022 07:23:05 +0100 Subject: [PATCH 0841/1472] Optimize offchain worker memory usage a bit. (#11454) * add missing events to elections fallback * Merged * add some logs and stuff * undo a bunch of things * undo lock file * remove unused err * fix build --- client/allocator/src/freeing_bump.rs | 1 - .../src/unsigned.rs | 59 +++++++++++-------- frame/support/src/storage/types/nmap.rs | 4 +- primitives/npos-elections/src/assignments.rs | 23 ++++---- .../cli/src/commands/execute_block.rs | 5 ++ .../cli/src/commands/offchain_worker.rs | 5 ++ utils/frame/try-runtime/cli/src/lib.rs | 2 +- 7 files changed, 58 insertions(+), 41 deletions(-) diff --git a/client/allocator/src/freeing_bump.rs b/client/allocator/src/freeing_bump.rs index f14c31c79c483..79d6fca6f91b6 100644 --- a/client/allocator/src/freeing_bump.rs +++ b/client/allocator/src/freeing_bump.rs @@ -216,7 +216,6 @@ impl Link { /// | 0 | next element link | /// +--------------+-------------------+ /// ``` -/// /// ## Occupied header /// ```ignore /// 64 32 0 diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 9a1b52d354569..de25355f0ca5b 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -169,27 +169,6 @@ impl Pallet { Ok((RawSolution { solution, score, round }, size)) } - /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which - /// is ready to be submitted to the chain. - /// - /// Will always reduce the solution as well. - pub fn prepare_election_result( - election_result: ElectionResult, - ) -> Result<(RawSolution>, SolutionOrSnapshotSize), MinerError> { - let RoundSnapshot { voters, targets } = - Self::snapshot().ok_or(MinerError::SnapshotUnAvailable)?; - let desired_targets = Self::desired_targets().ok_or(MinerError::SnapshotUnAvailable)?; - let (solution, score, size) = - Miner::::prepare_election_result_with_snapshot( - election_result, - voters, - targets, - desired_targets, - )?; - let round = Self::round(); - Ok((RawSolution { solution, score, round }, size)) - } - /// Attempt to restore a solution from cache. Otherwise, compute it fresh. Either way, submit /// if our call's score is greater than that of the cached solution. pub fn restore_or_compute_then_maybe_submit() -> Result<(), MinerError> { @@ -441,7 +420,10 @@ impl Miner { }) } - /// Same as [`Pallet::prepare_election_result`], but the input snapshot mut be given as inputs. + /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which + /// is ready to be submitted to the chain. + /// + /// Will always reduce the solution as well. pub fn prepare_election_result_with_snapshot( election_result: ElectionResult, voters: Vec<(T::AccountId, VoteWeight, BoundedVec)>, @@ -1118,7 +1100,19 @@ mod tests { distribution: vec![(10, PerU16::one())], }], }; - let (solution, witness) = MultiPhase::prepare_election_result(result).unwrap(); + + let RoundSnapshot { voters, targets } = MultiPhase::snapshot().unwrap(); + let desired_targets = MultiPhase::desired_targets().unwrap(); + + let (raw, score, witness) = + Miner::::prepare_election_result_with_snapshot( + result, + voters.clone(), + targets.clone(), + desired_targets, + ) + .unwrap(); + let solution = RawSolution { solution: raw, score, round: MultiPhase::round() }; assert_ok!(MultiPhase::unsigned_pre_dispatch_checks(&solution)); assert_ok!(MultiPhase::submit_unsigned( Origin::none(), @@ -1139,7 +1133,14 @@ mod tests { }, ], }; - let (solution, _) = MultiPhase::prepare_election_result(result).unwrap(); + let (raw, score, _) = Miner::::prepare_election_result_with_snapshot( + result, + voters.clone(), + targets.clone(), + desired_targets, + ) + .unwrap(); + let solution = RawSolution { solution: raw, score, round: MultiPhase::round() }; // 12 is not 50% more than 10 assert_eq!(solution.score.minimal_stake, 12); assert_noop!( @@ -1161,7 +1162,15 @@ mod tests { }, ], }; - let (solution, witness) = MultiPhase::prepare_election_result(result).unwrap(); + let (raw, score, witness) = + Miner::::prepare_election_result_with_snapshot( + result, + voters.clone(), + targets.clone(), + desired_targets, + ) + .unwrap(); + let solution = RawSolution { solution: raw, score, round: MultiPhase::round() }; assert_eq!(solution.score.minimal_stake, 17); // and it is fine diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 5faeb5d8cac28..a15c7482105e9 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -544,7 +544,7 @@ mod test { use crate::{ hash::{StorageHasher as _, *}, metadata::{StorageEntryModifier, StorageHasher}, - storage::types::{Key, Key as NMapKey, ValueQuery}, + storage::types::{Key, ValueQuery}, }; use sp_io::{hashing::twox_128, TestExternalities}; @@ -590,7 +590,7 @@ mod test { { #[crate::storage_alias] - type Foo = StorageNMap), u32>; + type Foo = StorageNMap), u32>; assert_eq!(Foo::contains_key((3,)), true); assert_eq!(Foo::get((3,)), Some(10)); diff --git a/primitives/npos-elections/src/assignments.rs b/primitives/npos-elections/src/assignments.rs index 9422ccdf65884..fc88ef40010b7 100644 --- a/primitives/npos-elections/src/assignments.rs +++ b/primitives/npos-elections/src/assignments.rs @@ -120,18 +120,17 @@ impl StakedAssignment { AccountId: IdentifierT, { let stake = self.total(); - let distribution = self - .distribution - .into_iter() - .filter_map(|(target, w)| { - let per_thing = P::from_rational(w, stake); - if per_thing == Bounded::min_value() { - None - } else { - Some((target, per_thing)) - } - }) - .collect::>(); + // most likely, the size of the staked assignment and normal assignments will be the same, + // so we pre-allocate it to prevent a sudden 2x allocation. `filter_map` starts with a size + // of 0 by default. + // https://www.reddit.com/r/rust/comments/3spfh1/does_collect_allocate_more_than_once_while/ + let mut distribution = Vec::<(AccountId, P)>::with_capacity(self.distribution.len()); + self.distribution.into_iter().for_each(|(target, w)| { + let per_thing = P::from_rational(w, stake); + if per_thing != Bounded::min_value() { + distribution.push((target, per_thing)); + } + }); Assignment { who: self.who, distribution } } diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index 12c36955c26cd..204acd879312f 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -142,6 +142,11 @@ where .overwrite_online_at(parent_hash.to_owned()); let builder = if command.overwrite_wasm_code { + log::info!( + target: LOG_TARGET, + "replacing the in-storage :code: with the local code from {}'s chain_spec (your local repo)", + config.chain_spec.name(), + ); let (code_key, code) = extract_code(&config.chain_spec)?; builder.inject_hashed_key_value(&[(code_key, code)]) } else { diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index 9aad901829772..50780f4513b2f 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -131,6 +131,11 @@ where let builder = command.state.builder::()?; let builder = if command.overwrite_wasm_code { + log::info!( + target: LOG_TARGET, + "replacing the in-storage :code: with the local code from {}'s chain_spec (your local repo)", + config.chain_spec.name(), + ); let (code_key, code) = extract_code(&config.chain_spec)?; builder.inject_hashed_key_value(&[(code_key, code)]) } else { diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 71d258a68982e..c09a33cf3f16a 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -722,7 +722,7 @@ pub(crate) fn state_machine_call(Into::into)?; Ok((changes, encoded_results)) From 7ca5e877e184be30d583b4bf8c6856ab074ed1dd Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Tue, 24 May 2022 13:10:13 +0300 Subject: [PATCH 0842/1472] add rule to the ci job (#11511) --- scripts/ci/gitlab/pipeline/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index f7ce974924d60..e896eac7238b1 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -31,6 +31,8 @@ check-dependent-polkadot: COMPANION_OVERRIDES: | substrate: polkadot-v* polkadot: release-v* + rules: + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ #PRs # TODO: Re-enable after https://github.com/paritytech/pipeline-scripts/issues/44 #check-dependent-cumulus: From ce449a53d04329e346509ae7df5a30a89b4f51d5 Mon Sep 17 00:00:00 2001 From: Achim Schneider Date: Tue, 24 May 2022 16:17:23 +0200 Subject: [PATCH 0843/1472] Contracts pallet: removal on idle (#11202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * on_initialize -> on_idle * use remaining_weight info * no weight_limit for on_idle * call on_idle in tests * attempt to fix tests * run on_initiaize when queue full * add on_idle to weight info * add on_idle weight info to on_idle hook * add basic test for on_initialize with full queue * disbale check for all keys gone in full queue, full block test * queue_deth as usize, add comment * comment was removed by accident * Update frame/contracts/src/lib.rs Co-authored-by: Alexander Theißen * cargo +nightly fmt * update lazy_removal_does_no_run_on_full_queue_and_full_block * remove changes in weights.rs * weights on_idle -> on_process_deletion_queue_batch * use block number for on_idle * use BlockNumber for on_initialize * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/contracts/src/lib.rs Co-authored-by: Alexander Theißen * remove outcommented code * add check that queue still full for test * cargo fmt * cargo +nightly fmt * Update frame/contracts/src/benchmarking/mod.rs Co-authored-by: Alexander Gryaznov * fix weights.rs * add lazy_removal_does_no_run_on_low_remaining_weight test * Apply suggestions from code review Co-authored-by: Alexander Gryaznov Co-authored-by: Alexander Theißen Co-authored-by: Parity Bot Co-authored-by: Alexander Gryaznov --- frame/contracts/src/benchmarking/mod.rs | 4 +- frame/contracts/src/lib.rs | 29 ++++-- frame/contracts/src/storage.rs | 2 +- frame/contracts/src/tests.rs | 113 +++++++++++++-------- frame/contracts/src/weights.rs | 126 +++++++++++++++++++----- 5 files changed, 200 insertions(+), 74 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 4241456389ec7..8f17cacff328d 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -202,8 +202,8 @@ benchmarks! { as codec::HasCompact>::Type: Clone + Eq + PartialEq + sp_std::fmt::Debug + scale_info::TypeInfo + codec::Encode, } - // The base weight without any actual work performed apart from the setup costs. - on_initialize {}: { + // The base weight consumed on processing contracts deletion queue. + on_process_deletion_queue_batch {}: { Storage::::process_deletion_queue_batch(Weight::MAX) } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index a8d1e18efd2cc..edb7fcf131de8 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -380,15 +380,28 @@ pub mod pallet { T::AccountId: UncheckedFrom, T::AccountId: AsRef<[u8]>, { + fn on_idle(_block: T::BlockNumber, remaining_weight: Weight) -> Weight { + Storage::::process_deletion_queue_batch(remaining_weight) + .saturating_add(T::WeightInfo::on_process_deletion_queue_batch()) + } + fn on_initialize(_block: T::BlockNumber) -> Weight { - // We do not want to go above the block limit and rather avoid lazy deletion - // in that case. This should only happen on runtime upgrades. - let weight_limit = T::BlockWeights::get() - .max_block - .saturating_sub(System::::block_weight().total()) - .min(T::DeletionWeightLimit::get()); - Storage::::process_deletion_queue_batch(weight_limit) - .saturating_add(T::WeightInfo::on_initialize()) + // We want to process the deletion_queue in the on_idle hook. Only in the case + // that the queue length has reached its maximal depth, we process it here. + let max_len = T::DeletionQueueDepth::get() as usize; + let queue_len = >::decode_len().unwrap_or(0); + if queue_len >= max_len { + // We do not want to go above the block limit and rather avoid lazy deletion + // in that case. This should only happen on runtime upgrades. + let weight_limit = T::BlockWeights::get() + .max_block + .saturating_sub(System::::block_weight().total()) + .min(T::DeletionWeightLimit::get()); + Storage::::process_deletion_queue_batch(weight_limit) + .saturating_add(T::WeightInfo::on_process_deletion_queue_batch()) + } else { + T::WeightInfo::on_process_deletion_queue_batch() + } } } diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index a9a78f12581d8..af6dbe3c62bfc 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -224,7 +224,7 @@ where /// of those keys can be deleted from the deletion queue given the supplied queue length /// and weight limit. pub fn deletion_budget(queue_len: usize, weight_limit: Weight) -> (u64, u32) { - let base_weight = T::WeightInfo::on_initialize(); + let base_weight = T::WeightInfo::on_process_deletion_queue_batch(); let weight_per_queue_item = T::WeightInfo::on_initialize_per_queue_item(1) - T::WeightInfo::on_initialize_per_queue_item(0); let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) - diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 5a6a29786c629..d4a5434cd5a46 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -25,7 +25,7 @@ use crate::{ wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, - DefaultContractAccessWeight, Error, Pallet, Schedule, + DefaultContractAccessWeight, DeletionQueue, Error, Pallet, Schedule, }; use assert_matches::assert_matches; use codec::Encode; @@ -35,7 +35,8 @@ use frame_support::{ parameter_types, storage::child, traits::{ - BalanceStatus, ConstU32, ConstU64, Contains, Currency, OnInitialize, ReservableCurrency, + BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, OnIdle, OnInitialize, + ReservableCurrency, }, weights::{constants::WEIGHT_PER_SECOND, DispatchClass, PostDispatchInfo, Weight}, }; @@ -1610,13 +1611,32 @@ fn lazy_removal_works() { assert_matches!(child::get(trie, &[99]), Some(42)); // Run the lazy removal - Contracts::on_initialize(Weight::max_value()); + Contracts::on_idle(System::block_number(), Weight::max_value()); // Value should be gone now assert_matches!(child::get::(trie, &[99]), None); }); } +#[test] +fn lazy_removal_on_full_queue_works_on_initialize() { + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Fill the deletion queue with dummy values, so that on_initialize attempts + // to clear the queue + Storage::::fill_queue_with_dummies(); + + let queue_len_initial = >::decode_len().unwrap_or(0); + + // Run the lazy removal + Contracts::on_initialize(System::block_number()); + + let queue_len_after_on_initialize = >::decode_len().unwrap_or(0); + + // Queue length should be decreased after call of on_initialize() + assert!(queue_len_initial - queue_len_after_on_initialize > 0); + }); +} + #[test] fn lazy_batch_removal_works() { let (code, hash) = compile_module::("self_destruct").unwrap(); @@ -1661,7 +1681,7 @@ fn lazy_batch_removal_works() { } // Run single lazy removal - Contracts::on_initialize(Weight::max_value()); + Contracts::on_idle(System::block_number(), Weight::max_value()); // The single lazy removal should have removed all queued tries for trie in tries.iter() { @@ -1761,7 +1781,34 @@ fn lazy_removal_partial_remove_works() { } #[test] -fn lazy_removal_does_no_run_on_full_block() { +fn lazy_removal_does_no_run_on_full_queue_and_full_block() { + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Fill up the block which should prevent the lazy storage removal from running. + System::register_extra_weight_unchecked( + ::BlockWeights::get().max_block, + DispatchClass::Mandatory, + ); + + // Fill the deletion queue with dummy values, so that on_initialize attempts + // to clear the queue + Storage::::fill_queue_with_dummies(); + + // Check that on_initialize() tries to perform lazy removal but removes nothing + // as no more weight is left for that. + let weight_used = Contracts::on_initialize(System::block_number()); + let base = <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); + assert_eq!(weight_used, base); + + // Check that the deletion queue is still full after execution of the + // on_initialize() hook. + let max_len: u32 = ::DeletionQueueDepth::get(); + let queue_len: u32 = >::decode_len().unwrap_or(0).try_into().unwrap(); + assert_eq!(max_len, queue_len); + }); +} + +#[test] +fn lazy_removal_does_no_run_on_low_remaining_weight() { let (code, hash) = compile_module::("self_destruct").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let min_balance = ::Currency::minimum_balance(); @@ -1779,19 +1826,10 @@ fn lazy_removal_does_no_run_on_full_block() { let addr = Contracts::contract_address(&ALICE, &hash, &[]); let info = >::get(&addr).unwrap(); - let max_keys = 30; - - // Create some storage items for the contract. - let vals: Vec<_> = (0..max_keys) - .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode())) - .collect(); + let trie = &info.child_trie_info(); // Put value into the contracts child trie - for val in &vals { - Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None, false) - .unwrap(); - } - >::insert(&addr, info.clone()); + child::put(trie, &[99], &42); // Terminate the contract assert_ok!(Contracts::call( @@ -1806,37 +1844,30 @@ fn lazy_removal_does_no_run_on_full_block() { // Contract info should be gone assert!(!>::contains_key(&addr)); - let trie = info.child_trie_info(); - // But value should be still there as the lazy removal did not run, yet. - for val in &vals { - assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); - } + assert_matches!(child::get(trie, &[99]), Some(42)); - // Fill up the block which should prevent the lazy storage removal from running. - System::register_extra_weight_unchecked( - ::BlockWeights::get().max_block, - DispatchClass::Mandatory, - ); + // Assign a remaining weight which is too low for a successfull deletion of the contract + let low_remaining_weight = + <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); - // Run the lazy removal without any limit so that all keys would be removed if there - // had been some weight left in the block. - let weight_used = Contracts::on_initialize(Weight::max_value()); - let base = <::WeightInfo as WeightInfo>::on_initialize(); - assert_eq!(weight_used, base); + // Run the lazy removal + Contracts::on_idle(System::block_number(), low_remaining_weight); - // All the keys are still in place - for val in &vals { - assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); - } + // Value should still be there, since remaining weight was too low for removal + assert_matches!(child::get::(trie, &[99]), Some(42)); - // Run the lazy removal directly which disregards the block limits - Storage::::process_deletion_queue_batch(Weight::max_value()); + // Run the lazy removal while deletion_queue is not full + Contracts::on_initialize(System::block_number()); - // Now the keys should be gone - for val in &vals { - assert_eq!(child::get::(&trie, &blake2_256(&val.0)), None); - } + // Value should still be there, since deletion_queue was not full + assert_matches!(child::get::(trie, &[99]), Some(42)); + + // Run on_idle with max remaining weight, this should remove the value + Contracts::on_idle(System::block_number(), Weight::max_value()); + + // Value should be gone + assert_matches!(child::get::(trie, &[99]), None); }); } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index c6e83d34e90b1..b18c259ebd433 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-04-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -44,7 +44,7 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_contracts. pub trait WeightInfo { - fn on_initialize() -> Weight; + fn on_process_deletion_queue_batch() -> Weight; fn on_initialize_per_trie_key(k: u32, ) -> Weight; fn on_initialize_per_queue_item(q: u32, ) -> Weight; fn reinstrument(c: u32, ) -> Weight; @@ -163,8 +163,8 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) - fn on_initialize() -> Weight { - (1_684_000 as Weight) + fn on_process_deletion_queue_batch() -> Weight { + (1_664_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) @@ -196,6 +196,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) fn call_with_code_per_byte(c: u32, ) -> Weight { (206_036_000 as Weight) @@ -208,6 +209,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) @@ -217,25 +219,27 @@ impl WeightInfo for SubstrateWeight { .saturating_add((122_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(7 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { (180_607_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) fn call() -> Weight { (146_032_000 as Weight) @@ -271,6 +275,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_caller(r: u32, ) -> Weight { (205_061_000 as Weight) // Standard Error: 76_000 @@ -282,6 +287,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_is_contract(r: u32, ) -> Weight { (97_971_000 as Weight) // Standard Error: 741_000 @@ -294,6 +300,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_code_hash(r: u32, ) -> Weight { (109_052_000 as Weight) // Standard Error: 716_000 @@ -306,6 +313,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_own_code_hash(r: u32, ) -> Weight { (205_748_000 as Weight) // Standard Error: 87_000 @@ -317,6 +325,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_caller_is_origin(r: u32, ) -> Weight { (201_898_000 as Weight) // Standard Error: 55_000 @@ -328,6 +337,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_address(r: u32, ) -> Weight { (204_668_000 as Weight) // Standard Error: 65_000 @@ -339,6 +349,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_gas_left(r: u32, ) -> Weight { (203_240_000 as Weight) // Standard Error: 68_000 @@ -350,6 +361,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_balance(r: u32, ) -> Weight { (211_535_000 as Weight) // Standard Error: 73_000 @@ -361,6 +373,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_value_transferred(r: u32, ) -> Weight { (204_653_000 as Weight) // Standard Error: 71_000 @@ -372,6 +385,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_minimum_balance(r: u32, ) -> Weight { (204_690_000 as Weight) // Standard Error: 82_000 @@ -383,6 +397,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_block_number(r: u32, ) -> Weight { (205_004_000 as Weight) // Standard Error: 62_000 @@ -394,6 +409,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_now(r: u32, ) -> Weight { (204_341_000 as Weight) // Standard Error: 93_000 @@ -405,6 +421,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { (208_702_000 as Weight) @@ -417,6 +434,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_gas(r: u32, ) -> Weight { (131_983_000 as Weight) // Standard Error: 17_000 @@ -428,6 +446,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_input(r: u32, ) -> Weight { (203_768_000 as Weight) // Standard Error: 57_000 @@ -439,6 +458,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_input_per_kb(n: u32, ) -> Weight { (273_930_000 as Weight) // Standard Error: 3_000 @@ -461,6 +481,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_return_per_kb(n: u32, ) -> Weight { (201_130_000 as Weight) // Standard Error: 0 @@ -472,6 +493,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { @@ -480,13 +502,14 @@ impl WeightInfo for SubstrateWeight { .saturating_add((54_190_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { (206_528_000 as Weight) @@ -499,6 +522,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_deposit_event(r: u32, ) -> Weight { (210_309_000 as Weight) // Standard Error: 138_000 @@ -526,6 +550,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_debug_message(r: u32, ) -> Weight { (138_934_000 as Weight) // Standard Error: 34_000 @@ -633,6 +658,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_transfer(r: u32, ) -> Weight { (124_818_000 as Weight) // Standard Error: 1_251_000 @@ -646,6 +672,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_call(r: u32, ) -> Weight { (0 as Weight) // Standard Error: 4_575_000 @@ -659,6 +686,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) // Standard Error: 5_742_000 @@ -670,6 +698,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { (9_081_635_000 as Weight) // Standard Error: 11_326_000 @@ -685,6 +714,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:80 w:80) fn seal_instantiate(r: u32, ) -> Weight { @@ -700,6 +730,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { @@ -717,6 +748,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_sha2_256(r: u32, ) -> Weight { (203_315_000 as Weight) // Standard Error: 74_000 @@ -728,6 +760,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { (355_672_000 as Weight) // Standard Error: 25_000 @@ -739,6 +772,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_keccak_256(r: u32, ) -> Weight { (203_117_000 as Weight) // Standard Error: 94_000 @@ -750,6 +784,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { (196_575_000 as Weight) // Standard Error: 13_000 @@ -761,6 +796,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_blake2_256(r: u32, ) -> Weight { (203_938_000 as Weight) // Standard Error: 97_000 @@ -772,6 +808,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { (247_065_000 as Weight) // Standard Error: 8_000 @@ -783,6 +820,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_blake2_128(r: u32, ) -> Weight { (204_389_000 as Weight) // Standard Error: 86_000 @@ -794,6 +832,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { (284_700_000 as Weight) // Standard Error: 9_000 @@ -805,6 +844,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_ecdsa_recover(r: u32, ) -> Weight { (235_813_000 as Weight) // Standard Error: 521_000 @@ -816,6 +856,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { (204_095_000 as Weight) // Standard Error: 495_000 @@ -1021,9 +1062,9 @@ impl WeightInfo for SubstrateWeight { .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_033_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_322_000 as Weight).saturating_mul(r as Weight)) + (74_312_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { (74_203_000 as Weight) @@ -1095,8 +1136,8 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) - fn on_initialize() -> Weight { - (1_684_000 as Weight) + fn on_process_deletion_queue_batch() -> Weight { + (1_641_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) @@ -1128,6 +1169,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) fn call_with_code_per_byte(c: u32, ) -> Weight { (206_036_000 as Weight) @@ -1140,6 +1182,7 @@ impl WeightInfo for () { // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) @@ -1149,25 +1192,27 @@ impl WeightInfo for () { .saturating_add((122_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn instantiate(s: u32, ) -> Weight { (180_607_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) fn call() -> Weight { (146_032_000 as Weight) @@ -1203,6 +1248,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_caller(r: u32, ) -> Weight { (205_061_000 as Weight) // Standard Error: 76_000 @@ -1214,6 +1260,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_is_contract(r: u32, ) -> Weight { (97_971_000 as Weight) // Standard Error: 741_000 @@ -1226,6 +1273,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_code_hash(r: u32, ) -> Weight { (109_052_000 as Weight) // Standard Error: 716_000 @@ -1238,6 +1286,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_own_code_hash(r: u32, ) -> Weight { (205_748_000 as Weight) // Standard Error: 87_000 @@ -1249,6 +1298,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_caller_is_origin(r: u32, ) -> Weight { (201_898_000 as Weight) // Standard Error: 55_000 @@ -1260,6 +1310,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_address(r: u32, ) -> Weight { (204_668_000 as Weight) // Standard Error: 65_000 @@ -1271,6 +1322,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_gas_left(r: u32, ) -> Weight { (203_240_000 as Weight) // Standard Error: 68_000 @@ -1282,6 +1334,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_balance(r: u32, ) -> Weight { (211_535_000 as Weight) // Standard Error: 73_000 @@ -1293,6 +1346,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_value_transferred(r: u32, ) -> Weight { (204_653_000 as Weight) // Standard Error: 71_000 @@ -1304,6 +1358,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_minimum_balance(r: u32, ) -> Weight { (204_690_000 as Weight) // Standard Error: 82_000 @@ -1315,6 +1370,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_block_number(r: u32, ) -> Weight { (205_004_000 as Weight) // Standard Error: 62_000 @@ -1326,6 +1382,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_now(r: u32, ) -> Weight { (204_341_000 as Weight) // Standard Error: 93_000 @@ -1337,6 +1394,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) fn seal_weight_to_fee(r: u32, ) -> Weight { (208_702_000 as Weight) @@ -1349,6 +1407,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_gas(r: u32, ) -> Weight { (131_983_000 as Weight) // Standard Error: 17_000 @@ -1360,6 +1419,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_input(r: u32, ) -> Weight { (203_768_000 as Weight) // Standard Error: 57_000 @@ -1371,6 +1431,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_input_per_kb(n: u32, ) -> Weight { (273_930_000 as Weight) // Standard Error: 3_000 @@ -1393,6 +1454,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_return_per_kb(n: u32, ) -> Weight { (201_130_000 as Weight) // Standard Error: 0 @@ -1404,6 +1466,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_terminate(r: u32, ) -> Weight { @@ -1412,13 +1475,14 @@ impl WeightInfo for () { .saturating_add((54_190_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) fn seal_random(r: u32, ) -> Weight { (206_528_000 as Weight) @@ -1431,6 +1495,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_deposit_event(r: u32, ) -> Weight { (210_309_000 as Weight) // Standard Error: 138_000 @@ -1458,6 +1523,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_debug_message(r: u32, ) -> Weight { (138_934_000 as Weight) // Standard Error: 34_000 @@ -1565,6 +1631,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_transfer(r: u32, ) -> Weight { (124_818_000 as Weight) // Standard Error: 1_251_000 @@ -1578,6 +1645,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_call(r: u32, ) -> Weight { (0 as Weight) // Standard Error: 4_575_000 @@ -1591,6 +1659,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) // Standard Error: 5_742_000 @@ -1602,6 +1671,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { (9_081_635_000 as Weight) // Standard Error: 11_326_000 @@ -1617,6 +1687,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:80 w:80) fn seal_instantiate(r: u32, ) -> Weight { @@ -1632,6 +1703,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { @@ -1649,6 +1721,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_sha2_256(r: u32, ) -> Weight { (203_315_000 as Weight) // Standard Error: 74_000 @@ -1660,6 +1733,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { (355_672_000 as Weight) // Standard Error: 25_000 @@ -1671,6 +1745,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_keccak_256(r: u32, ) -> Weight { (203_117_000 as Weight) // Standard Error: 94_000 @@ -1682,6 +1757,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { (196_575_000 as Weight) // Standard Error: 13_000 @@ -1693,6 +1769,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_blake2_256(r: u32, ) -> Weight { (203_938_000 as Weight) // Standard Error: 97_000 @@ -1704,6 +1781,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { (247_065_000 as Weight) // Standard Error: 8_000 @@ -1715,6 +1793,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_blake2_128(r: u32, ) -> Weight { (204_389_000 as Weight) // Standard Error: 86_000 @@ -1726,6 +1805,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { (284_700_000 as Weight) // Standard Error: 9_000 @@ -1737,6 +1817,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_ecdsa_recover(r: u32, ) -> Weight { (235_813_000 as Weight) // Standard Error: 521_000 @@ -1748,6 +1829,7 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { (204_095_000 as Weight) // Standard Error: 495_000 @@ -1953,9 +2035,9 @@ impl WeightInfo for () { .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (74_033_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_322_000 as Weight).saturating_mul(r as Weight)) + (74_312_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { (74_203_000 as Weight) From 48bcb390740638cb2aa83983cb4c3b0fb0f85db7 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 24 May 2022 19:24:55 +0200 Subject: [PATCH 0844/1472] Fix Babe revert when last finalized block is a leaf (#11500) * Fix Babe revert when a leaf is the last finalized block Without this fix the last finalized block weight data is wrongly removed on revert scenario where the last finalized block is a leaf. * Remove redundant check * Added test to exercise the fix * Rename test * Give variables better names --- client/consensus/babe/src/lib.rs | 34 +++++++++++++------------- client/consensus/babe/src/tests.rs | 38 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 683df9ddacd62..84a3c618b3803 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -126,7 +126,7 @@ use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvid use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::{BlockId, OpaqueDigestItemId}, - traits::{Block as BlockT, Header, NumberFor, One, SaturatedConversion, Saturating, Zero}, + traits::{Block as BlockT, Header, NumberFor, SaturatedConversion, Saturating, Zero}, DigestItem, }; @@ -1875,13 +1875,10 @@ where let finalized = client.info().finalized_number; let revertible = blocks.min(best_number - finalized); - let number = best_number - revertible; - let hash = client - .block_hash_from_id(&BlockId::Number(number))? - .ok_or(ClientError::Backend(format!( - "Unexpected hash lookup failure for block number: {}", - number - )))?; + let revert_up_to_number = best_number - revertible; + let revert_up_to_hash = client.hash(revert_up_to_number)?.ok_or(ClientError::Backend( + format!("Unexpected hash lookup failure for block number: {}", revert_up_to_number), + ))?; // Revert epoch changes tree. @@ -1890,34 +1887,37 @@ where aux_schema::load_epoch_changes::(&*client, config.genesis_config())?; let mut epoch_changes = epoch_changes.shared_data(); - if number == Zero::zero() { + if revert_up_to_number == Zero::zero() { // Special case, no epoch changes data were present on genesis. *epoch_changes = EpochChangesFor::::default(); } else { - epoch_changes.revert(descendent_query(&*client), hash, number); + epoch_changes.revert(descendent_query(&*client), revert_up_to_hash, revert_up_to_number); } // Remove block weights added after the revert point. let mut weight_keys = HashSet::with_capacity(revertible.saturated_into()); + let leaves = backend.blockchain().leaves()?.into_iter().filter(|&leaf| { - sp_blockchain::tree_route(&*client, hash, leaf) + sp_blockchain::tree_route(&*client, revert_up_to_hash, leaf) .map(|route| route.retracted().is_empty()) .unwrap_or_default() }); + for leaf in leaves { let mut hash = leaf; - // Insert parent after parent until we don't hit an already processed - // branch or we reach a direct child of the rollback point. - while weight_keys.insert(aux_schema::block_weight_key(hash)) { + loop { let meta = client.header_metadata(hash)?; - if meta.number <= number + One::one() { - // We've reached a child of the revert point, stop here. + if meta.number <= revert_up_to_number || + !weight_keys.insert(aux_schema::block_weight_key(hash)) + { + // We've reached the revert point or an already processed branch, stop here. break } - hash = client.header_metadata(hash)?.parent; + hash = meta.parent; } } + let weight_keys: Vec<_> = weight_keys.iter().map(|val| val.as_slice()).collect(); // Write epoch changes and remove weights in one shot. diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 9875ff00673f5..e0590fc0cd86e 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -814,6 +814,44 @@ fn revert_prunes_epoch_changes_and_removes_weights() { assert!(weight_data_check(&fork3, false)); } +#[test] +fn revert_not_allowed_for_finalized() { + let mut net = BabeTestNet::new(1); + + let peer = net.peer(0); + let data = peer.data.as_ref().expect("babe link set up during initialization"); + + let client = peer.client().as_client(); + let backend = peer.client().as_backend(); + let mut block_import = data.block_import.lock().take().expect("import set up during init"); + + let mut proposer_factory = DummyFactory { + client: client.clone(), + config: data.link.config.clone(), + epoch_changes: data.link.epoch_changes.clone(), + mutator: Arc::new(|_, _| ()), + }; + + let mut propose_and_import_blocks_wrap = |parent_id, n| { + propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, parent_id, n) + }; + + let canon = propose_and_import_blocks_wrap(BlockId::Number(0), 3); + + // Finalize best block + client.finalize_block(BlockId::Hash(canon[2]), None, false).unwrap(); + + // Revert canon chain to last finalized block + revert(client.clone(), backend, 100).expect("revert should work for baked test scenario"); + + let weight_data_check = |hashes: &[Hash], expected: bool| { + hashes.iter().all(|hash| { + aux_schema::load_block_weight(&*client, hash).unwrap().is_some() == expected + }) + }; + assert!(weight_data_check(&canon, true)); +} + #[test] fn importing_epoch_change_block_prunes_tree() { let mut net = BabeTestNet::new(1); From f2d5ece14b335504f6ff00ebf3b625c56afbc5e3 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 25 May 2022 05:47:21 +0200 Subject: [PATCH 0845/1472] Document benchmarking CLI (#11246) * Decrese default repeats Signed-off-by: Oliver Tale-Yazdi * Add benchmarking READMEs Signed-off-by: Oliver Tale-Yazdi * Update docs Signed-off-by: Oliver Tale-Yazdi * Update docs Signed-off-by: Oliver Tale-Yazdi * Update README Signed-off-by: Oliver Tale-Yazdi * Review fixes Co-authored-by: Shawn Tabrizi Co-authored-by: parity-processbot <> Co-authored-by: Shawn Tabrizi --- frame/benchmarking/README.md | 14 +- utils/frame/benchmarking-cli/README.md | 47 +++++- .../benchmarking-cli/src/block/README.md | 118 +++++++++++++++ .../benchmarking-cli/src/machine/README.md | 71 +++++++++ .../benchmarking-cli/src/overhead/README.md | 136 ++++++++++++++++++ .../benchmarking-cli/src/overhead/bench.rs | 4 +- .../benchmarking-cli/src/pallet/README.md | 3 + .../benchmarking-cli/src/shared/README.md | 15 ++ .../benchmarking-cli/src/storage/README.md | 105 ++++++++++++++ 9 files changed, 505 insertions(+), 8 deletions(-) create mode 100644 utils/frame/benchmarking-cli/src/block/README.md create mode 100644 utils/frame/benchmarking-cli/src/machine/README.md create mode 100644 utils/frame/benchmarking-cli/src/overhead/README.md create mode 100644 utils/frame/benchmarking-cli/src/pallet/README.md create mode 100644 utils/frame/benchmarking-cli/src/shared/README.md create mode 100644 utils/frame/benchmarking-cli/src/storage/README.md diff --git a/frame/benchmarking/README.md b/frame/benchmarking/README.md index 38c683cb8db5b..f0fe05cc140f2 100644 --- a/frame/benchmarking/README.md +++ b/frame/benchmarking/README.md @@ -43,7 +43,7 @@ The benchmarking framework comes with the following tools: * [A set of macros](./src/lib.rs) (`benchmarks!`, `add_benchmark!`, etc...) to make it easy to write, test, and add runtime benchmarks. * [A set of linear regression analysis functions](./src/analysis.rs) for processing benchmark data. -* [A CLI extension](../../utils/frame/benchmarking-cli/) to make it easy to execute benchmarks on your +* [A CLI extension](../../utils/frame/benchmarking-cli/README.md) to make it easy to execute benchmarks on your node. The end-to-end benchmarking pipeline is disabled by default when compiling a node. If you want to @@ -150,9 +150,13 @@ feature flag: ```bash cd bin/node/cli -cargo build --release --features runtime-benchmarks +cargo build --profile=production --features runtime-benchmarks ``` +The production profile applies various compiler optimizations. +These optimizations slow down the compilation process *a lot*. +If you are just testing things out and don't need final numbers, don't include `--profile=production`. + ## Running Benchmarks Finally, once you have a node binary with benchmarks enabled, you need to execute your various @@ -161,13 +165,13 @@ benchmarks. You can get a list of the available benchmarks by running: ```bash -./target/release/substrate benchmark --chain dev --pallet "*" --extrinsic "*" --repeat 0 +./target/production/substrate benchmark pallet --chain dev --pallet "*" --extrinsic "*" --repeat 0 ``` Then you can run a benchmark like so: ```bash -./target/release/substrate benchmark \ +./target/production/substrate benchmark pallet \ --chain dev \ # Configurable Chain Spec --execution=wasm \ # Always test with Wasm --wasm-execution=compiled \ # Always used `wasm-time` @@ -200,7 +204,7 @@ used for joining all the arguments passed to the CLI. To get a full list of available options when running benchmarks, run: ```bash -./target/release/substrate benchmark --help +./target/production/substrate benchmark --help ``` License: Apache-2.0 diff --git a/utils/frame/benchmarking-cli/README.md b/utils/frame/benchmarking-cli/README.md index 9718db58b37e9..e6a48b61fd227 100644 --- a/utils/frame/benchmarking-cli/README.md +++ b/utils/frame/benchmarking-cli/README.md @@ -1 +1,46 @@ -License: Apache-2.0 \ No newline at end of file +# The Benchmarking CLI + +This crate contains commands to benchmark various aspects of Substrate and the hardware. +All commands are exposed by the Substrate node but can be exposed by any Substrate client. +The goal is to have a comprehensive suite of benchmarks that cover all aspects of Substrate and the hardware that its running on. + +Invoking the root benchmark command prints a help menu: +```sh +$ cargo run --profile=production -- benchmark + +Sub-commands concerned with benchmarking. + +USAGE: + substrate benchmark + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +SUBCOMMANDS: + block Benchmark the execution time of historic blocks + machine Command to benchmark the hardware. + overhead Benchmark the execution overhead per-block and per-extrinsic + pallet Benchmark the extrinsic weight of FRAME Pallets + storage Benchmark the storage speed of a chain snapshot +``` + +All examples use the `production` profile for correctness which makes the compilation *very* slow; for testing you can use `--release`. +For the final results the `production` profile and reference hardware should be used, otherwise the results are not comparable. + +The sub-commands are explained in depth here: +- [block] Compare the weight of a historic block to its actual resource usage +- [machine] Gauges the speed of the hardware +- [overhead] Creates weight files for the *Block*- and *Extrinsic*-base weights +- [pallet] Creates weight files for a Pallet +- [storage] Creates weight files for *Read* and *Write* storage operations + +License: Apache-2.0 + + + +[pallet]: ../../../frame/benchmarking/README.md +[machine]: src/machine/README.md +[storage]: src/storage/README.md +[overhead]: src/overhead/README.md +[block]: src/block/README.md diff --git a/utils/frame/benchmarking-cli/src/block/README.md b/utils/frame/benchmarking-cli/src/block/README.md new file mode 100644 index 0000000000000..7e99f0df9d43b --- /dev/null +++ b/utils/frame/benchmarking-cli/src/block/README.md @@ -0,0 +1,118 @@ +# The `benchmark block` command + +The whole benchmarking process in Substrate aims to predict the resource usage of an unexecuted block. +This command measures how accurate this prediction was by executing a block and comparing the predicted weight to its actual resource usage. +It can be used to measure the accuracy of the pallet benchmarking. + +In the following it will be explained once for Polkadot and once for Substrate. + +## Polkadot # 1 +(Also works for Kusama, Westend and Rococo) + + +Suppose you either have a synced Polkadot node or downloaded a snapshot from [Polkachu]. +This example uses a pruned ParityDB snapshot from the 2022-4-19 with the last block being 9939462. +For pruned snapshots you need to know the number of the last block (to be improved [here]). +Pruned snapshots normally store the last 256 blocks, archive nodes can use any block range. + +In this example we will benchmark just the last 10 blocks: +```sh +cargo run --profile=production -- benchmark block --from 9939453 --to 9939462 --db paritydb +``` + +Output: +```pre +Block 9939453 with 2 tx used 4.57% of its weight ( 26,458,801 of 579,047,053 ns) +Block 9939454 with 3 tx used 4.80% of its weight ( 28,335,826 of 590,414,831 ns) +Block 9939455 with 2 tx used 4.76% of its weight ( 27,889,567 of 586,484,595 ns) +Block 9939456 with 2 tx used 4.65% of its weight ( 27,101,306 of 582,789,723 ns) +Block 9939457 with 2 tx used 4.62% of its weight ( 26,908,882 of 582,789,723 ns) +Block 9939458 with 2 tx used 4.78% of its weight ( 28,211,440 of 590,179,467 ns) +Block 9939459 with 4 tx used 4.78% of its weight ( 27,866,077 of 583,260,451 ns) +Block 9939460 with 3 tx used 4.72% of its weight ( 27,845,836 of 590,462,629 ns) +Block 9939461 with 2 tx used 4.58% of its weight ( 26,685,119 of 582,789,723 ns) +Block 9939462 with 2 tx used 4.60% of its weight ( 26,840,938 of 583,697,101 ns) +``` + +### Output Interpretation + +(Only results from reference hardware are relevant) + +Each block is executed multiple times and the results are averaged. +The percent number is the interesting part and indicates how much weight was used as compared to how much was predicted. +The closer to 100% this is without exceeding 100%, the better. +If it exceeds 100%, the block is marked with "**OVER WEIGHT!**" to easier spot them. This is not good since then the benchmarking under-estimated the weight. +This would mean that an honest validator would possibly not be able to keep up with importing blocks since users did not pay for enough weight. +If that happens the validator could lag behind the chain and get slashed for missing deadlines. +It is therefore important to investigate any overweight blocks. + +In this example you can see an unexpected result; only < 5% of the weight was used! +The measured blocks can be executed much faster than predicted. +This means that the benchmarking process massively over-estimated the execution time. +Since they are off by so much, it is an issue [polkadot#5192]. + +The ideal range for these results would be 85-100%. + +## Polkadot # 2 + +Let's take a more interesting example where the blocks use more of their predicted weight. +Every day when validators pay out rewards, the blocks are nearly full. +Using an archive node here is the easiest. + +The Polkadot blocks TODO-TODO for example contain large batch transactions for staking payout. + +```sh +cargo run --profile=production -- benchmark block --from TODO --to TODO --db paritydb +``` + +```pre +TODO +``` + +## Substrate + +It is also possible to try the procedure in Substrate, although it's a bit boring. + +First you need to create some blocks with either a local or dev chain. +This example will use the standard development spec. +Pick a non existing directory where the chain data will be stored, eg `/tmp/dev`. +```sh +cargo run --profile=production -- --dev -d /tmp/dev +``` +You should see after some seconds that it started to produce blocks: +```pre +… +✨ Imported #1 (0x801d…9189) +… +``` +You can now kill the node with `Ctrl+C`. Then measure how long it takes to execute these blocks: +```sh +cargo run --profile=production -- benchmark block --from 1 --to 1 --dev -d /tmp/dev --pruning archive +``` +This will benchmark the first block. If you killed the node at a later point, you can measure multiple blocks. +```pre +Block 1 with 1 tx used 72.04% of its weight ( 4,945,664 of 6,864,702 ns) +``` + +In this example the block used ~72% of its weight. +The benchmarking therefore over-estimated the effort to execute the block. +Since this block is empty, its not very interesting. + +## Arguments + +- `--from` Number of the first block to measure (inclusive). +- `--to` Number of the last block to measure (inclusive). +- `--repeat` How often each block should be measured. +- [`--db`] +- [`--pruning`] + +License: Apache-2.0 + + + +[Polkachu]: https://polkachu.com/snapshots +[here]: https://github.com/paritytech/substrate/issues/11141 +[polkadot#5192]: https://github.com/paritytech/polkadot/issues/5192 + +[`--db`]: ../shared/README.md#arguments +[`--pruning`]: ../shared/README.md#arguments diff --git a/utils/frame/benchmarking-cli/src/machine/README.md b/utils/frame/benchmarking-cli/src/machine/README.md new file mode 100644 index 0000000000000..f22a8ea54b81d --- /dev/null +++ b/utils/frame/benchmarking-cli/src/machine/README.md @@ -0,0 +1,71 @@ +# The `benchmark machine` command + +Different Substrate chains can have different hardware requirements. +It is therefore important to be able to quickly gauge if a piece of hardware fits a chains' requirements. +The `benchmark machine` command archives this by measuring key metrics and making them comparable. + +Invoking the command looks like this: +```sh +cargo run --profile=production -- benchmark machine --dev +``` + +## Output + +The output on reference hardware: + +```pre ++----------+----------------+---------------+--------------+-------------------+ +| Category | Function | Score | Minimum | Result | ++----------+----------------+---------------+--------------+-------------------+ +| CPU | BLAKE2-256 | 1023.00 MiB/s | 1.00 GiB/s | ✅ Pass ( 99.4 %) | ++----------+----------------+---------------+--------------+-------------------+ +| CPU | SR25519-Verify | 665.13 KiB/s | 666.00 KiB/s | ✅ Pass ( 99.9 %) | ++----------+----------------+---------------+--------------+-------------------+ +| Memory | Copy | 14.39 GiB/s | 14.32 GiB/s | ✅ Pass (100.4 %) | ++----------+----------------+---------------+--------------+-------------------+ +| Disk | Seq Write | 457.00 MiB/s | 450.00 MiB/s | ✅ Pass (101.6 %) | ++----------+----------------+---------------+--------------+-------------------+ +| Disk | Rnd Write | 190.00 MiB/s | 200.00 MiB/s | ✅ Pass ( 95.0 %) | ++----------+----------------+---------------+--------------+-------------------+ +``` + +The *score* is the average result of each benchmark. It always adheres to "higher is better". + +The *category* indicate which part of the hardware was benchmarked: +- **CPU** Processor intensive task +- **Memory** RAM intensive task +- **Disk** Hard drive intensive task + +The *function* is the concrete benchmark that was run: +- **BLAKE2-256** The throughput of the [Blake2-256] cryptographic hashing function with 32 KiB input. The [blake2_256 function] is used in many places in Substrate. The throughput of a hash function strongly depends on the input size, therefore we settled to use a fixed input size for comparable results. +- **SR25519 Verify** Sr25519 is an optimized version of the [Curve25519] signature scheme. Signature verification is used by Substrate when verifying extrinsics and blocks. +- **Copy** The throughput of copying memory from one place in the RAM to another. +- **Seq Write** The throughput of writing data to the storage location sequentially. It is important that the same disk is used that will later-on be used to store the chain data. +- **Rnd Write** The throughput of writing data to the storage location in a random order. This is normally much slower than the sequential write. + +The *score* needs to reach the *minimum* in order to pass the benchmark. This can be reduced with the `--tolerance` flag. + +The *result* indicated if a specific benchmark was passed by the machine or not. The percent number is the relative score reached to the *minimum* that is needed. The `--tolerance` flag is taken into account for this decision. For example a benchmark that passes even with 95% since the *tolerance* was set to 10% would look like this: `✅ Pass ( 95.0 %)`. + +## Interpretation + +Ideally all results show a `Pass` and the program exits with code 0. Currently some of the benchmarks can fail even on reference hardware; they are still being improved to make them more deterministic. +Make sure to run nothing else on the machine when benchmarking it. +You can re-run them multiple times to get more reliable results. + +## Arguments + +- `--tolerance` A percent number to reduce the *minimum* requirement. This should be used to ignore outliers of the benchmarks. The default value is 10%. +- `--verify-duration` How long the verification benchmark should run. +- `--disk-duration` How long the *read* and *write* benchmarks should run each. +- `--allow-fail` Always exit the program with code 0. +- `--chain` / `--dev` Specify the chain config to use. This will be used to compare the results with the requirements of the chain (WIP). +- [`--base-path`] + +License: Apache-2.0 + + +[Blake2-256]: https://www.blake2.net/ +[blake2_256 function]: https://crates.parity.io/sp_core/hashing/fn.blake2_256.html +[Curve25519]: https://en.wikipedia.org/wiki/Curve25519 +[`--base-path`]: ../shared/README.md#arguments diff --git a/utils/frame/benchmarking-cli/src/overhead/README.md b/utils/frame/benchmarking-cli/src/overhead/README.md new file mode 100644 index 0000000000000..6f41e881d0572 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/overhead/README.md @@ -0,0 +1,136 @@ +# The `benchmark overhead` command + +Each time an extrinsic or a block is executed, a fixed weight is charged as "execution overhead". +This is necessary since the weight that is calculated by the pallet benchmarks does not include this overhead. +The exact overhead to can vary per Substrate chain and needs to be calculated per chain. +This command calculates the exact values of these overhead weights for any Substrate chain that supports it. + +## How does it work? + +The benchmark consists of two parts; the [`BlockExecutionWeight`] and the [`ExtrinsicBaseWeight`]. +Both are executed sequentially when invoking the command. + +## BlockExecutionWeight + +The block execution weight is defined as the weight that it takes to execute an *empty block*. +It is measured by constructing an empty block and measuring its executing time. +The result are written to a `block_weights.rs` file which is created from a template. +The file will contain the concrete weight value and various statistics about the measurements. For example: +```rust +/// Time to execute an empty block. +/// Calculated by multiplying the *Average* with `1` and adding `0`. +/// +/// Stats [NS]: +/// Min, Max: 3_508_416, 3_680_498 +/// Average: 3_532_484 +/// Median: 3_522_111 +/// Std-Dev: 27070.23 +/// +/// Percentiles [NS]: +/// 99th: 3_631_863 +/// 95th: 3_595_674 +/// 75th: 3_526_435 +pub const BlockExecutionWeight: Weight = 3_532_484 * WEIGHT_PER_NANOS; +``` + +In this example it takes 3.5 ms to execute an empty block. That means that it always takes at least 3.5 ms to execute *any* block. +This constant weight is therefore added to each block to ensure that Substrate budgets enough time to execute it. + +## ExtrinsicBaseWeight + +The extrinsic base weight is defined as the weight that it takes to execute an *empty* extrinsic. +An *empty* extrinsic is also called a *NO-OP*. It does nothing and is the equivalent to the empty block form above. +The benchmark now constructs a block which is filled with only NO-OP extrinsics. +This block is then executed many times and the weights are measured. +The result is divided by the number of extrinsics in that block and the results are written to `extrinsic_weights.rs`. + +The relevant section in the output file looks like this: +```rust + /// Time to execute a NO-OP extrinsic, for example `System::remark`. +/// Calculated by multiplying the *Average* with `1` and adding `0`. +/// +/// Stats [NS]: +/// Min, Max: 67_561, 69_855 +/// Average: 67_745 +/// Median: 67_701 +/// Std-Dev: 264.68 +/// +/// Percentiles [NS]: +/// 99th: 68_758 +/// 95th: 67_843 +/// 75th: 67_749 +pub const ExtrinsicBaseWeight: Weight = 67_745 * WEIGHT_PER_NANOS; +``` + +In this example it takes 67.7 µs to execute a NO-OP extrinsic. That means that it always takes at least 67.7 µs to execute *any* extrinsic. +This constant weight is therefore added to each extrinsic to ensure that Substrate budgets enough time to execute it. + +## Invocation + +The base command looks like this (for debugging you can use `--release`): +```sh +cargo run --profile=production -- benchmark overhead --dev +``` + +Output: +```pre +# BlockExecutionWeight +Running 10 warmups... +Executing block 100 times +Per-block execution overhead [ns]: +Total: 353248430 +Min: 3508416, Max: 3680498 +Average: 3532484, Median: 3522111, Stddev: 27070.23 +Percentiles 99th, 95th, 75th: 3631863, 3595674, 3526435 +Writing weights to "block_weights.rs" + +# Setup +Building block, this takes some time... +Extrinsics per block: 12000 + +# ExtrinsicBaseWeight +Running 10 warmups... +Executing block 100 times +Per-extrinsic execution overhead [ns]: +Total: 6774590 +Min: 67561, Max: 69855 +Average: 67745, Median: 67701, Stddev: 264.68 +Percentiles 99th, 95th, 75th: 68758, 67843, 67749 +Writing weights to "extrinsic_weights.rs" +``` + +The complete command for Polkadot looks like this: +```sh +cargo run --profile=production -- benchmark overhead --chain=polkadot-dev --execution=wasm --wasm-execution=compiled --weight-path=runtime/polkadot/constants/src/weights/ +``` + +This will overwrite the the [block_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/block_weights.rs) and [extrinsic_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/extrinsic_weights.rs) files in the Polkadot runtime directory. +You can try the same for *Rococo* and to see that the results slightly differ. +👉 It is paramount to use `--profile=production`, `--execution=wasm` and `--wasm-execution=compiled` as the results are otherwise useless. + +## Output Interpretation + +Lower is better. The less weight the execution overhead needs, the better. +Since the weights of the overhead is charged per extrinsic and per block, a larger weight results in less extrinsics per block. +Minimizing this is important to have a large transaction throughput. + +## Arguments + +- `--chain` / `--dev` Set the chain specification. +- `--weight-path` Set the output directory or file to write the weights to. +- `--repeat` Set the repetitions of both benchmarks. +- `--warmup` Set the rounds of warmup before measuring. +- `--execution` Should be set to `wasm` for correct results. +- `--wasm-execution` Should be set to `compiled` for correct results. +- [`--mul`](../shared/README.md#arguments) +- [`--add`](../shared/README.md#arguments) +- [`--metric`](../shared/README.md#arguments) +- [`--weight-path`](../shared/README.md#arguments) + +License: Apache-2.0 + + +[`ExtrinsicBaseWeight`]: https://github.com/paritytech/substrate/blob/580ebae17fa30082604f1c9720f6f4a1cfe95b50/frame/support/src/weights/extrinsic_weights.rs#L26 +[`BlockExecutionWeight`]: https://github.com/paritytech/substrate/blob/580ebae17fa30082604f1c9720f6f4a1cfe95b50/frame/support/src/weights/block_weights.rs#L26 + +[System::Remark]: https://github.com/paritytech/substrate/blob/580ebae17fa30082604f1c9720f6f4a1cfe95b50/frame/system/src/lib.rs#L382 diff --git a/utils/frame/benchmarking-cli/src/overhead/bench.rs b/utils/frame/benchmarking-cli/src/overhead/bench.rs index 68f3f6597b466..be7dac24021cf 100644 --- a/utils/frame/benchmarking-cli/src/overhead/bench.rs +++ b/utils/frame/benchmarking-cli/src/overhead/bench.rs @@ -43,11 +43,11 @@ use crate::shared::Stats; #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] pub struct BenchmarkParams { /// Rounds of warmups before measuring. - #[clap(long, default_value = "100")] + #[clap(long, default_value = "10")] pub warmup: u32, /// How many times the benchmark should be repeated. - #[clap(long, default_value = "1000")] + #[clap(long, default_value = "100")] pub repeat: u32, /// Maximal number of extrinsics that should be put into a block. diff --git a/utils/frame/benchmarking-cli/src/pallet/README.md b/utils/frame/benchmarking-cli/src/pallet/README.md new file mode 100644 index 0000000000000..72845652de653 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/pallet/README.md @@ -0,0 +1,3 @@ +The pallet command is explained in [frame/benchmarking](../../../../../frame/benchmarking/README.md). + +License: Apache-2.0 diff --git a/utils/frame/benchmarking-cli/src/shared/README.md b/utils/frame/benchmarking-cli/src/shared/README.md new file mode 100644 index 0000000000000..2a3719b85498c --- /dev/null +++ b/utils/frame/benchmarking-cli/src/shared/README.md @@ -0,0 +1,15 @@ +# Shared code + +Contains code that is shared among multiple sub-commands. + +## Arguments + +- `--mul` Multiply the result with a factor. Can be used to manually adjust for future chain growth. +- `--add` Add a value to the result. Can be used to manually offset the results. +- `--metric` Set the metric to use for calculating the final weight from the raw data. Defaults to `average`. +- `--weight-path` Set the file or directory to write the weight files to. +- `--db` The database backend to use. This depends on your snapshot. +- `--pruning` Set the pruning mode of the node. Some benchmarks require you to set this to `archive`. +- `--base-path` The location on the disk that should be used for the benchmarks. You can try this on different disks or even on a mounted RAM-disk. It is important to use the same location that will later-on be used to store the chain data to get the correct results. + +License: Apache-2.0 diff --git a/utils/frame/benchmarking-cli/src/storage/README.md b/utils/frame/benchmarking-cli/src/storage/README.md new file mode 100644 index 0000000000000..820785f7ea20c --- /dev/null +++ b/utils/frame/benchmarking-cli/src/storage/README.md @@ -0,0 +1,105 @@ +# The `benchmark storage` command + +The cost of storage operations in a Substrate chain depends on the current chain state. +It is therefore important to regularly update these weights as the chain grows. +This sub-command measures the cost of storage operations for a concrete snapshot. + +For the Substrate node it looks like this (for debugging you can use `--release`): +```sh +cargo run --profile=production -- benchmark storage --dev --state-version=1 +``` + +Running the command on Substrate itself is not verify meaningful, since the genesis state of the `--dev` chain spec is used. + +The output for the Polkadot client with a recent chain snapshot will give you a better impression. A recent snapshot can be downloaded from [Polkachu]. +Then run (remove the `--db=paritydb` if you have a RocksDB snapshot): +```sh +cargo run --profile=production -- benchmark storage --dev --state-version=0 --db=paritydb --weight-path runtime/polkadot/constants/src/weights +``` + +This takes a while since reads and writes all keys from the snapshot: +```pre +# The 'read' benchmark +Preparing keys from block BlockId::Number(9939462) +Reading 1379083 keys +Time summary [ns]: +Total: 19668919930 +Min: 6450, Max: 1217259 +Average: 14262, Median: 14190, Stddev: 3035.79 +Percentiles 99th, 95th, 75th: 18270, 16190, 14819 +Value size summary: +Total: 265702275 +Min: 1, Max: 1381859 +Average: 192, Median: 80, Stddev: 3427.53 +Percentiles 99th, 95th, 75th: 3368, 383, 80 + +# The 'write' benchmark +Preparing keys from block BlockId::Number(9939462) +Writing 1379083 keys +Time summary [ns]: +Total: 98393809781 +Min: 12969, Max: 13282577 +Average: 71347, Median: 69499, Stddev: 25145.27 +Percentiles 99th, 95th, 75th: 135839, 106129, 79239 +Value size summary: +Total: 265702275 +Min: 1, Max: 1381859 +Average: 192, Median: 80, Stddev: 3427.53 +Percentiles 99th, 95th, 75th: 3368, 383, 80 + +Writing weights to "paritydb_weights.rs" +``` +You will see that the [paritydb_weights.rs] files was modified and now contains new weights. +The exact command for Polkadot can be seen at the top of the file. +This uses the most recent block from your snapshot which is printed at the top. +The value size summary tells us that the pruned Polkadot chain state is ~253 MiB in size. +Reading a value on average takes (in this examples) 14.3 µs and writing 71.3 µs. +The interesting part in the generated weight file tells us the weight constants and some statistics about the measurements: +```rust +/// Time to read one storage item. +/// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. +/// +/// Stats [NS]: +/// Min, Max: 4_611, 1_217_259 +/// Average: 14_262 +/// Median: 14_190 +/// Std-Dev: 3035.79 +/// +/// Percentiles [NS]: +/// 99th: 18_270 +/// 95th: 16_190 +/// 75th: 14_819 +read: 14_262 * constants::WEIGHT_PER_NANOS, + +/// Time to write one storage item. +/// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. +/// +/// Stats [NS]: +/// Min, Max: 12_969, 13_282_577 +/// Average: 71_347This works under the assumption that the *average* read a +/// Median: 69_499 +/// Std-Dev: 25145.27 +/// +/// Percentiles [NS]: +/// 99th: 135_839 +/// 95th: 106_129 +/// 75th: 79_239 +write: 71_347 * constants::WEIGHT_PER_NANOS, +``` + +## Arguments + +- `--db` Specify which database backend to use. This greatly influences the results. +- `--state-version` Set the version of the state encoding that this snapshot uses. Should be set to `1` for Substrate `--dev` and `0` for Polkadot et al. Using the wrong version can corrupt the snapshot. +- [`--mul`](../shared/README.md#arguments) +- [`--add`](../shared/README.md#arguments) +- [`--metric`](../shared/README.md#arguments) +- [`--weight-path`](../shared/README.md#arguments) +- `--json-read-path` Write the raw 'read' results to this file or directory. +- `--json-write-path` Write the raw 'write' results to this file or directory. + +License: Apache-2.0 + + +[Polkachu]: https://polkachu.com/snapshots +[paritydb_weights.rs]: https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/paritydb_weights.rs#L60 From ef661427da2f9cec68f871ddf8e2de32bc0402ac Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Wed, 25 May 2022 08:32:11 +0300 Subject: [PATCH 0846/1472] Introduce `WeightToFee` trait instead of `WeightToFeePolynomial` and make `WeightToFeePolynomial` implement it instead (#11415) * Introduce `WeightToFee` trait instead of `WeightToFeePolynomial` and make `WeightToFeePolynomial` implement it instead * Rename `WeightToFee::calc()` to `WeightToFee::wight_to_fee()` * Fix typo --- Cargo.lock | 2 - bin/node/executor/tests/fees.rs | 8 +- bin/node/runtime/src/impls.rs | 6 +- frame/executive/src/lib.rs | 10 +-- frame/support/src/weights.rs | 83 ++++++++++--------- frame/transaction-payment/Cargo.toml | 1 - .../asset-tx-payment/Cargo.toml | 1 - .../asset-tx-payment/src/tests.rs | 33 ++++---- frame/transaction-payment/src/lib.rs | 54 ++++-------- 9 files changed, 86 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b2ceb36f6152..7b1a05b7067e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5134,7 +5134,6 @@ dependencies = [ "scale-info", "serde", "serde_json", - "smallvec", "sp-core", "sp-io", "sp-runtime", @@ -6285,7 +6284,6 @@ dependencies = [ "scale-info", "serde", "serde_json", - "smallvec", "sp-core", "sp-io", "sp-runtime", diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index a84ce1470d877..cf794bae1d307 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -18,9 +18,7 @@ use codec::{Encode, Joiner}; use frame_support::{ traits::Currency, - weights::{ - constants::ExtrinsicBaseWeight, GetDispatchInfo, IdentityFee, WeightToFeePolynomial, - }, + weights::{constants::ExtrinsicBaseWeight, GetDispatchInfo, IdentityFee, WeightToFee}, }; use node_primitives::Balance; use node_runtime::{ @@ -197,13 +195,13 @@ fn transaction_fee_is_correct() { let mut balance_alice = (100 - 69) * DOLLARS; let base_weight = ExtrinsicBaseWeight::get(); - let base_fee = IdentityFee::::calc(&base_weight); + let base_fee = IdentityFee::::weight_to_fee(&base_weight); let length_fee = TransactionByteFee::get() * (xt.clone().encode().len() as Balance); balance_alice -= length_fee; let weight = default_transfer_call().get_dispatch_info().weight; - let weight_fee = IdentityFee::::calc(&weight); + let weight_fee = IdentityFee::::weight_to_fee(&weight); // we know that weight to fee multiplier is effect-less in block 1. // current weight of transfer = 200_000_000 diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index f73443920c213..4973aed4bd4fc 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -59,7 +59,7 @@ mod multiplier_tests { AdjustmentVariable, MinimumMultiplier, Runtime, RuntimeBlockWeights as BlockWeights, System, TargetBlockFullness, TransactionPayment, }; - use frame_support::weights::{DispatchClass, Weight, WeightToFeePolynomial}; + use frame_support::weights::{DispatchClass, Weight, WeightToFee}; fn max_normal() -> Weight { BlockWeights::get() @@ -234,7 +234,9 @@ mod multiplier_tests { fm = next; iterations += 1; let fee = - ::WeightToFee::calc(&tx_weight); + ::WeightToFee::weight_to_fee( + &tx_weight, + ); let adjusted_fee = fm.saturating_mul_acc_int(fee); println!( "iteration {}, new fm = {:?}. Fee at this point is: {} units / {} millicents, \ diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 4affc26f831fd..55b7e926a0fad 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -576,9 +576,7 @@ mod tests { ConstU32, ConstU64, ConstU8, Currency, LockIdentifier, LockableCurrency, WithdrawReasons, }, - weights::{ - ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFeePolynomial, - }, + weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFee}, }; use frame_system::{Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo}; use pallet_balances::Call as BalancesCall; @@ -866,7 +864,7 @@ mod tests { .get(DispatchClass::Normal) .base_extrinsic; let fee: Balance = - ::WeightToFee::calc(&weight); + ::WeightToFee::weight_to_fee(&weight); let mut t = sp_io::TestExternalities::new(t); t.execute_with(|| { Executive::initialize_block(&Header::new( @@ -1153,7 +1151,9 @@ mod tests { .get(DispatchClass::Normal) .base_extrinsic; let fee: Balance = - ::WeightToFee::calc(&weight); + ::WeightToFee::weight_to_fee( + &weight, + ); Executive::initialize_block(&Header::new( 1, H256::default(), diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index fc85a031b0852..a3df199496922 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -140,7 +140,7 @@ use codec::{Decode, Encode}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -use smallvec::{smallvec, SmallVec}; +use smallvec::SmallVec; use sp_arithmetic::{ traits::{BaseArithmetic, Saturating, Unsigned}, Perbill, @@ -622,7 +622,7 @@ impl RuntimeDbWeight { } } -/// One coefficient and its position in the `WeightToFeePolynomial`. +/// One coefficient and its position in the `WeightToFee`. /// /// One term of polynomial is calculated as: /// @@ -647,6 +647,15 @@ pub struct WeightToFeeCoefficient { /// A list of coefficients that represent one polynomial. pub type WeightToFeeCoefficients = SmallVec<[WeightToFeeCoefficient; 4]>; +/// A trait that describes the weight to fee calculation. +pub trait WeightToFee { + /// The type that is returned as result from calculation. + type Balance: BaseArithmetic + From + Copy + Unsigned; + + /// Calculates the fee from the passed `weight`. + fn weight_to_fee(weight: &Weight) -> Self::Balance; +} + /// A trait that describes the weight to fee calculation as polynomial. /// /// An implementor should only implement the `polynomial` function. @@ -661,12 +670,19 @@ pub trait WeightToFeePolynomial { /// that the order of coefficients is important as putting the negative coefficients /// first will most likely saturate the result to zero mid evaluation. fn polynomial() -> WeightToFeeCoefficients; +} + +impl WeightToFee for T +where + T: WeightToFeePolynomial, +{ + type Balance = ::Balance; /// Calculates the fee from the passed `weight` according to the `polynomial`. /// /// This should not be overriden in most circumstances. Calculation is done in the /// `Balance` type and never overflows. All evaluation is saturating. - fn calc(weight: &Weight) -> Self::Balance { + fn weight_to_fee(weight: &Weight) -> Self::Balance { Self::polynomial() .iter() .fold(Self::Balance::saturated_from(0u32), |mut acc, args| { @@ -690,30 +706,21 @@ pub trait WeightToFeePolynomial { } } -/// Implementor of `WeightToFeePolynomial` that maps one unit of weight to one unit of fee. +/// Implementor of `WeightToFee` that maps one unit of weight to one unit of fee. pub struct IdentityFee(sp_std::marker::PhantomData); -impl WeightToFeePolynomial for IdentityFee +impl WeightToFee for IdentityFee where T: BaseArithmetic + From + Copy + Unsigned, { type Balance = T; - fn polynomial() -> WeightToFeeCoefficients { - smallvec!(WeightToFeeCoefficient { - coeff_integer: 1u32.into(), - coeff_frac: Perbill::zero(), - negative: false, - degree: 1, - }) - } - - fn calc(weight: &Weight) -> Self::Balance { + fn weight_to_fee(weight: &Weight) -> Self::Balance { Self::Balance::saturated_from(*weight) } } -/// Implementor of [`WeightToFeePolynomial`] that uses a constant multiplier. +/// Implementor of [`WeightToFee`] that uses a constant multiplier. /// # Example /// /// ``` @@ -724,23 +731,14 @@ where /// ``` pub struct ConstantMultiplier(sp_std::marker::PhantomData<(T, M)>); -impl WeightToFeePolynomial for ConstantMultiplier +impl WeightToFee for ConstantMultiplier where T: BaseArithmetic + From + Copy + Unsigned, M: Get, { type Balance = T; - fn polynomial() -> WeightToFeeCoefficients { - smallvec!(WeightToFeeCoefficient { - coeff_integer: M::get(), - coeff_frac: Perbill::zero(), - negative: false, - degree: 1, - }) - } - - fn calc(weight: &Weight) -> Self::Balance { + fn weight_to_fee(weight: &Weight) -> Self::Balance { Self::Balance::saturated_from(*weight).saturating_mul(M::get()) } } @@ -831,6 +829,7 @@ impl PerDispatchClass { mod tests { use super::*; use crate::{decl_module, parameter_types, traits::Get}; + use smallvec::smallvec; pub trait Config: 'static { type Origin; @@ -997,35 +996,41 @@ mod tests { #[test] fn polynomial_works() { // 100^3/2=500000 100^2*(2+1/3)=23333 700 -10000 - assert_eq!(Poly::calc(&100), 514033); + assert_eq!(Poly::weight_to_fee(&100), 514033); // 10123^3/2=518677865433 10123^2*(2+1/3)=239108634 70861 -10000 - assert_eq!(Poly::calc(&10_123), 518917034928); + assert_eq!(Poly::weight_to_fee(&10_123), 518917034928); } #[test] fn polynomial_does_not_underflow() { - assert_eq!(Poly::calc(&0), 0); - assert_eq!(Poly::calc(&10), 0); + assert_eq!(Poly::weight_to_fee(&0), 0); + assert_eq!(Poly::weight_to_fee(&10), 0); } #[test] fn polynomial_does_not_overflow() { - assert_eq!(Poly::calc(&Weight::max_value()), Balance::max_value() - 10_000); + assert_eq!(Poly::weight_to_fee(&Weight::max_value()), Balance::max_value() - 10_000); } #[test] fn identity_fee_works() { - assert_eq!(IdentityFee::::calc(&0), 0); - assert_eq!(IdentityFee::::calc(&50), 50); - assert_eq!(IdentityFee::::calc(&Weight::max_value()), Balance::max_value()); + assert_eq!(IdentityFee::::weight_to_fee(&0), 0); + assert_eq!(IdentityFee::::weight_to_fee(&50), 50); + assert_eq!( + IdentityFee::::weight_to_fee(&Weight::max_value()), + Balance::max_value() + ); } #[test] fn constant_fee_works() { use crate::traits::ConstU128; - assert_eq!(ConstantMultiplier::>::calc(&0), 0); - assert_eq!(ConstantMultiplier::>::calc(&50), 500); - assert_eq!(ConstantMultiplier::>::calc(&16), 16384); - assert_eq!(ConstantMultiplier::>::calc(&2), u128::MAX); + assert_eq!(ConstantMultiplier::>::weight_to_fee(&0), 0); + assert_eq!(ConstantMultiplier::>::weight_to_fee(&50), 500); + assert_eq!(ConstantMultiplier::>::weight_to_fee(&16), 16384); + assert_eq!( + ConstantMultiplier::>::weight_to_fee(&2), + u128::MAX + ); } } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 519433a8ce0a8..51aeeabe99db8 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -18,7 +18,6 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } -smallvec = "1.8.0" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index fb000dbfdb103..2d4da250212f2 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -29,7 +29,6 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" serde = { version = "1.0.136", optional = true } [dev-dependencies] -smallvec = "1.8.0" serde_json = "1.0.79" sp-storage = { version = "6.0.0", default-features = false, path = "../../../primitives/storage" } diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index d72a288ac7a33..5b1fa157c3f10 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -21,22 +21,17 @@ use frame_support::{ pallet_prelude::*, parameter_types, traits::{fungibles::Mutate, ConstU32, ConstU64, ConstU8, FindAuthor}, - weights::{ - DispatchClass, DispatchInfo, PostDispatchInfo, Weight, WeightToFeeCoefficient, - WeightToFeeCoefficients, WeightToFeePolynomial, - }, + weights::{DispatchClass, DispatchInfo, PostDispatchInfo, Weight, WeightToFee as WeightToFeeT}, ConsensusEngineId, }; use frame_system as system; use frame_system::EnsureRoot; use pallet_balances::Call as BalancesCall; use pallet_transaction_payment::CurrencyAdapter; -use smallvec::smallvec; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, ConvertInto, IdentityLookup, StaticLookup}, - Perbill, + traits::{BlakeTwo256, ConvertInto, IdentityLookup, SaturatedConversion, StaticLookup}, }; use std::cell::RefCell; @@ -83,8 +78,8 @@ impl Get for BlockWeights { } parameter_types! { - pub static TransactionByteFee: u64 = 1; pub static WeightToFee: u64 = 1; + pub static TransactionByteFee: u64 = 1; } impl frame_system::Config for Runtime { @@ -130,23 +125,27 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; } -impl WeightToFeePolynomial for WeightToFee { +impl WeightToFeeT for WeightToFee { + type Balance = u64; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(*weight).saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) + } +} + +impl WeightToFeeT for TransactionByteFee { type Balance = u64; - fn polynomial() -> WeightToFeeCoefficients { - smallvec![WeightToFeeCoefficient { - degree: 1, - coeff_frac: Perbill::zero(), - coeff_integer: WEIGHT_TO_FEE.with(|v| *v.borrow()), - negative: false, - }] + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(*weight) + .saturating_mul(TRANSACTION_BYTE_FEE.with(|v| *v.borrow())) } } impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; type WeightToFee = WeightToFee; - type LengthToFee = WeightToFee; + type LengthToFee = TransactionByteFee; type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 45c8b8f479c9f..d44f8b1b894e1 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -66,8 +66,7 @@ use frame_support::{ dispatch::DispatchResult, traits::{EstimateCallFee, Get}, weights::{ - DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight, - WeightToFeeCoefficient, WeightToFeePolynomial, + DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight, WeightToFee, }, }; @@ -283,30 +282,15 @@ pub mod pallet { type OperationalFeeMultiplier: Get; /// Convert a weight value into a deductible fee based on the currency type. - type WeightToFee: WeightToFeePolynomial>; + type WeightToFee: WeightToFee>; /// Convert a length value into a deductible fee based on the currency type. - type LengthToFee: WeightToFeePolynomial>; + type LengthToFee: WeightToFee>; /// Update the multiplier of the next block, based on the previous block's weight. type FeeMultiplierUpdate: MultiplierUpdate; } - #[pallet::extra_constants] - impl Pallet { - #[pallet::constant_name(WeightToFee)] - /// The polynomial that is applied in order to derive fee from weight. - fn weight_to_fee_polynomial() -> Vec>> { - T::WeightToFee::polynomial().to_vec() - } - - /// The polynomial that is applied in order to derive fee from length. - #[pallet::constant_name(LengthToFee)] - fn length_to_fee_polynomial() -> Vec>> { - T::LengthToFee::polynomial().to_vec() - } - } - #[pallet::type_value] pub fn NextFeeMultiplierOnEmpty() -> Multiplier { Multiplier::saturating_from_integer(1) @@ -533,14 +517,14 @@ where } fn length_to_fee(length: u32) -> BalanceOf { - T::LengthToFee::calc(&(length as Weight)) + T::LengthToFee::weight_to_fee(&(length as Weight)) } fn weight_to_fee(weight: Weight) -> BalanceOf { // cap the weight to the maximum defined in runtime, otherwise it will be the // `Bounded` maximum of its data type, which is not desired. let capped_weight = weight.min(T::BlockWeights::get().max_block); - T::WeightToFee::calc(&capped_weight) + T::WeightToFee::weight_to_fee(&capped_weight) } } @@ -776,14 +760,12 @@ mod tests { use std::cell::RefCell; use codec::Encode; - use smallvec::smallvec; use sp_core::H256; use sp_runtime::{ testing::{Header, TestXt}, traits::{BlakeTwo256, IdentityLookup, One}, transaction_validity::InvalidTransaction, - Perbill, }; use frame_support::{ @@ -791,7 +773,7 @@ mod tests { traits::{ConstU32, ConstU64, Currency, Imbalance, OnUnbalanced}, weights::{ DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo, Weight, - WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, + WeightToFee as WeightToFeeT, }, }; use frame_system as system; @@ -879,29 +861,21 @@ mod tests { type WeightInfo = (); } - impl WeightToFeePolynomial for WeightToFee { + impl WeightToFeeT for WeightToFee { type Balance = u64; - fn polynomial() -> WeightToFeeCoefficients { - smallvec![WeightToFeeCoefficient { - degree: 1, - coeff_frac: Perbill::zero(), - coeff_integer: WEIGHT_TO_FEE.with(|v| *v.borrow()), - negative: false, - }] + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(*weight) + .saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) } } - impl WeightToFeePolynomial for TransactionByteFee { + impl WeightToFeeT for TransactionByteFee { type Balance = u64; - fn polynomial() -> WeightToFeeCoefficients { - smallvec![WeightToFeeCoefficient { - degree: 1, - coeff_frac: Perbill::zero(), - coeff_integer: TRANSACTION_BYTE_FEE.with(|v| *v.borrow()), - negative: false, - }] + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(*weight) + .saturating_mul(TRANSACTION_BYTE_FEE.with(|v| *v.borrow())) } } From 6c1d754b87543fae280bd5099738f47c16166a96 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 25 May 2022 09:40:37 +0200 Subject: [PATCH 0847/1472] Fix node lookup on fork-tree after a warp-sync (#11476) * Fix node lookup on fork-tree after a warp-sync After a warp-sync, the error condition was triggered by the absence of the parent node of the first imported block. The previous lookup implementation was traversing the tree using a recursive **post-order** DFS, this technique doesn't trigger the issue. In the last iterative implementation we were using a BFS instead. * Added internal doc warning * Small optimization * Specify post-order DFS in the comment --- utils/fork-tree/src/lib.rs | 68 +++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/utils/fork-tree/src/lib.rs b/utils/fork-tree/src/lib.rs index 45957f4390532..6f987fa798461 100644 --- a/utils/fork-tree/src/lib.rs +++ b/utils/fork-tree/src/lib.rs @@ -289,6 +289,11 @@ where /// index in the traverse path goes last. If a node is found that matches the predicate /// the returned path should always contain at least one index, otherwise `None` is /// returned. + // WARNING: some users of this method (i.e. consensus epoch changes tree) currently silently + // rely on a **post-order DFS** traversal. If we are using instead a top-down traversal method + // then the `is_descendent_of` closure, when used after a warp-sync, will end up querying the + // backend for a block (the one corresponding to the root) that is not present and thus will + // return a wrong result. Here we are implementing a post-order DFS. pub fn find_node_index_where( &self, hash: &H, @@ -301,30 +306,52 @@ where F: Fn(&H, &H) -> Result, P: Fn(&V) -> bool, { - let mut path = vec![]; - let mut children = &self.roots; - let mut i = 0; - let mut best_depth = 0; - - while i < children.len() { - let node = &children[i]; - if node.number < *number && is_descendent_of(&node.hash, hash)? { - path.push(i); - if predicate(&node.data) { - best_depth = path.len(); + let mut stack = vec![]; + let mut root_idx = 0; + let mut found = false; + let mut is_descendent = false; + + while root_idx < self.roots.len() { + if *number <= self.roots[root_idx].number { + root_idx += 1; + continue + } + // The second element in the stack tuple tracks what is the **next** children + // index to search into. If we find an ancestor then we stop searching into + // alternative branches and we focus on the current path up to the root. + stack.push((&self.roots[root_idx], 0)); + while let Some((node, i)) = stack.pop() { + if i < node.children.len() && !is_descendent { + stack.push((node, i + 1)); + if node.children[i].number < *number { + stack.push((&node.children[i], 0)); + } + } else if is_descendent || is_descendent_of(&node.hash, hash)? { + is_descendent = true; + if predicate(&node.data) { + found = true; + break + } } - i = 0; - children = &node.children; - } else { - i += 1; } + + // If the element we are looking for is a descendent of the current root + // then we can stop the search. + if is_descendent { + break + } + root_idx += 1; } - Ok(if best_depth == 0 { - None - } else { - path.truncate(best_depth); + Ok(if found { + // The path is the root index followed by the indices of all the children + // we were processing when we found the element (remember the stack + // contains the index of the **next** children to process). + let path: Vec<_> = + std::iter::once(root_idx).chain(stack.iter().map(|(_, i)| *i - 1)).collect(); Some(path) + } else { + None }) } @@ -1468,6 +1495,9 @@ mod test { fn find_node_works() { let (tree, is_descendent_of) = test_fork_tree(); + let node = tree.find_node_where(&"B", &2, &is_descendent_of, &|_| true).unwrap().unwrap(); + assert_eq!((node.hash, node.number), ("A", 1)); + let node = tree.find_node_where(&"D", &4, &is_descendent_of, &|_| true).unwrap().unwrap(); assert_eq!((node.hash, node.number), ("C", 3)); From 0f3f48962a3ede7f84c0bc4119a8eac08aebd43b Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 25 May 2022 22:24:33 +0200 Subject: [PATCH 0848/1472] Test for the fork-tree post-order DFS traversal requirement (#11521) * Test for the fork-tree post-order DFS traversal requirement * Fixed typo --- utils/fork-tree/src/lib.rs | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/utils/fork-tree/src/lib.rs b/utils/fork-tree/src/lib.rs index 6f987fa798461..ab56ecb6360b3 100644 --- a/utils/fork-tree/src/lib.rs +++ b/utils/fork-tree/src/lib.rs @@ -1441,20 +1441,34 @@ mod test { .unwrap() .unwrap(); assert_eq!(path, [0, 1, 0, 0, 0]); + + // Test for the post-order DFS requirement as specified by the `find_node_index_where` + // comment. Once (and if) post-order traversal requirement is removed, then this test + // can be removed as well. In practice this test should fail with a pre-order DFS. + let is_descendent_of_for_post_order = |parent: &&str, child: &&str| { + if *parent == "A" { + Err(TestError) + } else { + is_descendent_of(parent, child) + } + }; + let path = tree + .find_node_index_where(&"N", &6, &is_descendent_of_for_post_order, &|_| true) + .unwrap() + .unwrap(); + assert_eq!(path, [0, 1, 0, 0, 0]); } #[test] fn find_node_index_with_predicate_works() { - fn is_descendent_of(parent: &char, child: &char) -> Result { - match *parent { - 'A' => Ok(['B', 'C', 'D', 'E', 'F'].contains(child)), - 'B' => Ok(['C', 'D'].contains(child)), - 'C' => Ok(['D'].contains(child)), - 'E' => Ok(['F'].contains(child)), - 'D' | 'F' => Ok(false), - _ => unreachable!(), - } - } + let is_descendent_of = |parent: &char, child: &char| match *parent { + 'A' => Ok(['B', 'C', 'D', 'E', 'F'].contains(child)), + 'B' => Ok(['C', 'D'].contains(child)), + 'C' => Ok(['D'].contains(child)), + 'E' => Ok(['F'].contains(child)), + 'D' | 'F' => Ok(false), + _ => Err(TestError), + }; // A(t) --- B(f) --- C(t) --- D(f) // \-- E(t) --- F(f) From 158cdfd1a43a122f8cfbf70473fcd54a3b418f3d Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 26 May 2022 15:28:32 -0400 Subject: [PATCH 0849/1472] Storage Layer for All FRAME Extrinsics (#11431) * add new trait * implement DispatchableWithStorageLayer * at least one transactional * all dispatch is at least transactional * storage_layer api * add test * storage layer tests * deprecate transactional tag * i guess no reason to deprecate * remove transactional from batch_all * update tests * extend trait * cargo run --quiet --profile=production --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_balances --extrinsic=* --execution=wasm --wasm-execution=compiled --output=./frame/balances/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --profile=production --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_balances --extrinsic=* --execution=wasm --wasm-execution=compiled --output=./frame/balances/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --profile=production --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * fix copy paste name * cargo run --quiet --profile=production --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_utility --extrinsic=* --execution=wasm --wasm-execution=compiled --output=./frame/utility/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Create run_all_benchmarks.sh * uncomment build * update number of steps and repeats * add skip build * Update run_all_benchmarks.sh * Update run_all_benchmarks.sh * new benchmarks * Update frame/support/src/traits/dispatch.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/src/traits/dispatch.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/test/tests/storage_layers.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/test/tests/storage_layers.rs * weights * Update dispatch.rs * doc link * decl_macro support Co-authored-by: Parity Bot Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/assets/src/weights.rs | 134 +++++---- frame/bags-list/src/weights.rs | 14 +- frame/balances/src/weights.rs | 30 +- frame/benchmarking/src/weights.rs | 50 ++-- frame/bounties/src/weights.rs | 58 ++-- frame/child-bounties/src/weights.rs | 34 +-- frame/collective/src/weights.rs | 126 ++++---- frame/conviction-voting/src/weights.rs | 46 +-- frame/democracy/src/weights.rs | 182 ++++++------ .../src/weights.rs | 114 +++---- frame/elections-phragmen/src/weights.rs | 102 ++++--- frame/gilt/src/weights.rs | 58 ++-- frame/identity/src/weights.rs | 190 ++++++------ frame/im-online/src/weights.rs | 10 +- frame/indices/src/weights.rs | 22 +- frame/lottery/src/weights.rs | 34 +-- frame/membership/src/weights.rs | 54 ++-- frame/multisig/src/weights.rs | 78 ++--- frame/nomination-pools/src/weights.rs | 86 +++--- frame/preimage/src/weights.rs | 38 +-- frame/proxy/src/weights.rs | 118 ++++---- frame/recovery/src/weights.rs | 74 ++--- frame/referenda/src/weights.rs | 110 +++---- frame/remark/src/weights.rs | 6 +- frame/scheduler/src/weights.rs | 146 ++++----- frame/session/src/weights.rs | 10 +- frame/staking/src/weights.rs | 214 ++++++------- frame/state-trie-migration/src/weights.rs | 42 +-- .../src/construct_runtime/expand/call.rs | 13 + frame/support/procedural/src/lib.rs | 12 +- .../procedural/src/pallet/expand/call.rs | 8 +- frame/support/src/dispatch.rs | 9 +- frame/support/src/storage/mod.rs | 4 +- frame/support/src/storage/transactional.rs | 63 ++++ frame/support/src/traits.rs | 4 +- frame/support/src/traits/dispatch.rs | 17 ++ frame/support/src/weights/block_weights.rs | 20 +- .../support/src/weights/extrinsic_weights.rs | 20 +- frame/support/test/tests/pallet.rs | 19 +- frame/support/test/tests/pallet_instance.rs | 7 +- frame/support/test/tests/storage_layers.rs | 280 ++++++++++++++++++ frame/system/src/weights.rs | 30 +- frame/timestamp/src/weights.rs | 10 +- frame/tips/src/weights.rs | 66 ++--- frame/transaction-storage/src/weights.rs | 10 +- frame/treasury/src/weights.rs | 34 +-- frame/uniques/src/weights.rs | 122 ++++---- frame/utility/src/lib.rs | 2 - frame/utility/src/tests.rs | 8 +- frame/utility/src/weights.rs | 38 +-- frame/vesting/src/weights.rs | 102 +++---- frame/whitelist/src/weights.rs | 18 +- 52 files changed, 1741 insertions(+), 1355 deletions(-) create mode 100644 frame/support/test/tests/storage_layers.rs diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 453df22902ba2..e8f1184cf570f 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -74,13 +74,13 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (23_081_000 as Weight) + (27_167_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (12_782_000 as Weight) + (15_473_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -91,12 +91,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 36_000 - .saturating_add((15_327_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 36_000 - .saturating_add((17_817_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 362_000 - .saturating_add((16_692_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 37_000 + .saturating_add((17_145_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 37_000 + .saturating_add((19_333_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 375_000 + .saturating_add((17_046_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) @@ -109,14 +109,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (25_993_000 as Weight) + (30_819_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (30_795_000 as Weight) + (35_212_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -124,7 +124,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (44_054_000 as Weight) + (47_401_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -132,7 +132,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (36_948_000 as Weight) + (42_300_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -140,87 +140,93 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (44_446_000 as Weight) + (47_946_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (18_381_000 as Weight) + (21_670_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (18_215_000 as Weight) + (21_503_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (14_885_000 as Weight) + (18_158_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (14_834_000 as Weight) + (18_525_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (16_033_000 as Weight) + (19_858_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (14_344_000 as Weight) + (18_045_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn set_metadata(_n: u32, _s: u32, ) -> Weight { - (27_805_000 as Weight) + fn set_metadata(n: u32, s: u32, ) -> Weight { + (32_395_000 as Weight) + // Standard Error: 0 + .saturating_add((5_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (28_466_000 as Weight) + (32_893_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn force_set_metadata(_n: u32, _s: u32, ) -> Weight { - (15_604_000 as Weight) + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + (19_586_000 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (28_278_000 as Weight) + (32_478_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (13_556_000 as Weight) + (17_143_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (31_252_000 as Weight) + (36_389_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -229,21 +235,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (55_281_000 as Weight) + (61_854_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (30_784_000 as Weight) + (36_759_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - (32_011_000 as Weight) + (37_753_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -253,13 +259,13 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (23_081_000 as Weight) + (27_167_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (12_782_000 as Weight) + (15_473_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -270,12 +276,12 @@ impl WeightInfo for () { // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 36_000 - .saturating_add((15_327_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 36_000 - .saturating_add((17_817_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 362_000 - .saturating_add((16_692_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 37_000 + .saturating_add((17_145_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 37_000 + .saturating_add((19_333_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 375_000 + .saturating_add((17_046_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) @@ -288,14 +294,14 @@ impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (25_993_000 as Weight) + (30_819_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (30_795_000 as Weight) + (35_212_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -303,7 +309,7 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (44_054_000 as Weight) + (47_401_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -311,7 +317,7 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (36_948_000 as Weight) + (42_300_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -319,87 +325,93 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (44_446_000 as Weight) + (47_946_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (18_381_000 as Weight) + (21_670_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (18_215_000 as Weight) + (21_503_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (14_885_000 as Weight) + (18_158_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (14_834_000 as Weight) + (18_525_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (16_033_000 as Weight) + (19_858_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (14_344_000 as Weight) + (18_045_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn set_metadata(_n: u32, _s: u32, ) -> Weight { - (27_805_000 as Weight) + fn set_metadata(n: u32, s: u32, ) -> Weight { + (32_395_000 as Weight) + // Standard Error: 0 + .saturating_add((5_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (28_466_000 as Weight) + (32_893_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn force_set_metadata(_n: u32, _s: u32, ) -> Weight { - (15_604_000 as Weight) + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + (19_586_000 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (28_278_000 as Weight) + (32_478_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (13_556_000 as Weight) + (17_143_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (31_252_000 as Weight) + (36_389_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -408,21 +420,21 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (55_281_000 as Weight) + (61_854_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (30_784_000 as Weight) + (36_759_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - (32_011_000 as Weight) + (37_753_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index 8a8a14a75218d..a554a9bd4ad1a 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_bags_list //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -57,7 +57,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (51_415_000 as Weight) + (55_040_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -66,7 +66,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (49_459_000 as Weight) + (53_671_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -76,7 +76,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (53_682_000 as Weight) + (56_410_000 as Weight) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -89,7 +89,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (51_415_000 as Weight) + (55_040_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -98,7 +98,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (49_459_000 as Weight) + (53_671_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -108,7 +108,7 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (53_682_000 as Weight) + (56_410_000 as Weight) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index dd22e7ca778f8..f612d31997996 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_balances //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -58,43 +58,43 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (35_278_000 as Weight) + (41_860_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (27_822_000 as Weight) + (32_760_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (17_943_000 as Weight) + (22_279_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (20_974_000 as Weight) + (25_488_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (36_078_000 as Weight) + (42_190_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (32_794_000 as Weight) + (37_789_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (16_227_000 as Weight) + (20_056_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -104,43 +104,43 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (35_278_000 as Weight) + (41_860_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (27_822_000 as Weight) + (32_760_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (17_943_000 as Weight) + (22_279_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (20_974_000 as Weight) + (25_488_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (36_078_000 as Weight) + (42_190_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (32_794_000 as Weight) + (37_789_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (16_227_000 as Weight) + (20_056_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index 24643bb391152..8b36601940cf3 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for frame_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -58,39 +58,37 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn addition(_i: u32, ) -> Weight { - (126_000 as Weight) + (103_000 as Weight) } fn subtraction(_i: u32, ) -> Weight { - (121_000 as Weight) + (105_000 as Weight) } fn multiplication(_i: u32, ) -> Weight { - (132_000 as Weight) + (113_000 as Weight) } fn division(_i: u32, ) -> Weight { - (122_000 as Weight) + (102_000 as Weight) } - fn hashing(i: u32, ) -> Weight { - (21_059_079_000 as Weight) - // Standard Error: 117_000 - .saturating_add((1_121_000 as Weight).saturating_mul(i as Weight)) + fn hashing(_i: u32, ) -> Weight { + (20_865_902_000 as Weight) } fn sr25519_verification(i: u32, ) -> Weight { - (425_000 as Weight) - // Standard Error: 7_000 - .saturating_add((47_172_000 as Weight).saturating_mul(i as Weight)) + (319_000 as Weight) + // Standard Error: 8_000 + .saturating_add((47_171_000 as Weight).saturating_mul(i as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((2_118_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((2_110_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((373_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((372_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } } @@ -98,39 +96,37 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn addition(_i: u32, ) -> Weight { - (126_000 as Weight) + (103_000 as Weight) } fn subtraction(_i: u32, ) -> Weight { - (121_000 as Weight) + (105_000 as Weight) } fn multiplication(_i: u32, ) -> Weight { - (132_000 as Weight) + (113_000 as Weight) } fn division(_i: u32, ) -> Weight { - (122_000 as Weight) + (102_000 as Weight) } - fn hashing(i: u32, ) -> Weight { - (21_059_079_000 as Weight) - // Standard Error: 117_000 - .saturating_add((1_121_000 as Weight).saturating_mul(i as Weight)) + fn hashing(_i: u32, ) -> Weight { + (20_865_902_000 as Weight) } fn sr25519_verification(i: u32, ) -> Weight { - (425_000 as Weight) - // Standard Error: 7_000 - .saturating_add((47_172_000 as Weight).saturating_mul(i as Weight)) + (319_000 as Weight) + // Standard Error: 8_000 + .saturating_add((47_171_000 as Weight).saturating_mul(i as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((2_118_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((2_110_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((373_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((372_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index a1019b3e5c52c..d3e054cfc6351 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -64,44 +64,42 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) - fn propose_bounty(d: u32, ) -> Weight { - (25_277_000 as Weight) - // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) + fn propose_bounty(_d: u32, ) -> Weight { + (28_903_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (7_646_000 as Weight) + (10_997_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (5_712_000 as Weight) + (8_967_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (25_220_000 as Weight) + (28_665_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (21_985_000 as Weight) + (25_141_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (18_341_000 as Weight) + (21_295_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -110,7 +108,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (63_146_000 as Weight) + (67_951_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -119,7 +117,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (29_362_000 as Weight) + (33_654_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -128,13 +126,13 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (46_519_000 as Weight) + (50_582_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (15_363_000 as Weight) + (18_322_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -143,8 +141,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { (0 as Weight) - // Standard Error: 18_000 - .saturating_add((29_482_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 17_000 + .saturating_add((29_233_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -158,44 +156,42 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) - fn propose_bounty(d: u32, ) -> Weight { - (25_277_000 as Weight) - // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) + fn propose_bounty(_d: u32, ) -> Weight { + (28_903_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (7_646_000 as Weight) + (10_997_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (5_712_000 as Weight) + (8_967_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (25_220_000 as Weight) + (28_665_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (21_985_000 as Weight) + (25_141_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (18_341_000 as Weight) + (21_295_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -204,7 +200,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (63_146_000 as Weight) + (67_951_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -213,7 +209,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (29_362_000 as Weight) + (33_654_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -222,13 +218,13 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (46_519_000 as Weight) + (50_582_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (15_363_000 as Weight) + (18_322_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -237,8 +233,8 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { (0 as Weight) - // Standard Error: 18_000 - .saturating_add((29_482_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 17_000 + .saturating_add((29_233_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index d11de89bcf5c3..ad08e00149a30 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_child_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -64,7 +64,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) fn add_child_bounty(d: u32, ) -> Weight { - (45_917_000 as Weight) + (51_064_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) @@ -74,7 +74,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - (11_855_000 as Weight) + (15_286_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -82,7 +82,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (24_488_000 as Weight) + (29_929_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -90,14 +90,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (28_645_000 as Weight) + (32_449_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - (19_760_000 as Weight) + (23_793_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -106,7 +106,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - (62_194_000 as Weight) + (67_529_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -117,7 +117,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - (44_136_000 as Weight) + (48_436_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -128,7 +128,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - (53_168_000 as Weight) + (58_044_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -143,7 +143,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) fn add_child_bounty(d: u32, ) -> Weight { - (45_917_000 as Weight) + (51_064_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) @@ -153,7 +153,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - (11_855_000 as Weight) + (15_286_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -161,7 +161,7 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (24_488_000 as Weight) + (29_929_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -169,14 +169,14 @@ impl WeightInfo for () { // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (28_645_000 as Weight) + (32_449_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - (19_760_000 as Weight) + (23_793_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -185,7 +185,7 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - (62_194_000 as Weight) + (67_529_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -196,7 +196,7 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - (44_136_000 as Weight) + (48_436_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -207,7 +207,7 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - (53_168_000 as Weight) + (58_044_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index 6392f86de6530..2f5c6f590a999 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -65,12 +65,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { (0 as Weight) - // Standard Error: 8_000 - .saturating_add((10_362_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 8_000 - .saturating_add((56_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 8_000 - .saturating_add((13_187_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 12_000 + .saturating_add((10_280_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 12_000 + .saturating_add((126_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 12_000 + .saturating_add((13_310_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(p as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -78,21 +78,21 @@ impl WeightInfo for SubstrateWeight { } // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - (13_571_000 as Weight) + (16_819_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((31_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((33_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - (15_851_000 as Weight) + (18_849_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((56_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) } // Storage: Council Members (r:1 w:0) @@ -101,22 +101,22 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - (19_593_000 as Weight) + (22_204_000 as Weight) // Standard Error: 0 - .saturating_add((7_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((8_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((40_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((165_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((180_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - (27_221_000 as Weight) + (30_941_000 as Weight) // Standard Error: 2_000 - .saturating_add((82_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -125,11 +125,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - (26_295_000 as Weight) + (32_485_000 as Weight) // Standard Error: 1_000 - .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((39_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((130_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((124_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -138,13 +138,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - (28_609_000 as Weight) + (33_487_000 as Weight) // Standard Error: 0 - .saturating_add((6_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((68_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((66_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((161_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((157_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -154,11 +154,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - (30_497_000 as Weight) + (33_494_000 as Weight) // Standard Error: 1_000 - .saturating_add((48_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((58_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((124_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -168,13 +168,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - (31_402_000 as Weight) + (36_566_000 as Weight) // Standard Error: 0 .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((73_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((63_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((159_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -182,9 +182,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - (16_391_000 as Weight) + (20_159_000 as Weight) // Standard Error: 1_000 - .saturating_add((169_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((173_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -198,12 +198,12 @@ impl WeightInfo for () { // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { (0 as Weight) - // Standard Error: 8_000 - .saturating_add((10_362_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 8_000 - .saturating_add((56_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 8_000 - .saturating_add((13_187_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 12_000 + .saturating_add((10_280_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 12_000 + .saturating_add((126_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 12_000 + .saturating_add((13_310_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(p as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -211,21 +211,21 @@ impl WeightInfo for () { } // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - (13_571_000 as Weight) + (16_819_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((31_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((33_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - (15_851_000 as Weight) + (18_849_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((56_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) } // Storage: Council Members (r:1 w:0) @@ -234,22 +234,22 @@ impl WeightInfo for () { // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - (19_593_000 as Weight) + (22_204_000 as Weight) // Standard Error: 0 - .saturating_add((7_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((8_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((40_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((165_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((180_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - (27_221_000 as Weight) + (30_941_000 as Weight) // Standard Error: 2_000 - .saturating_add((82_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((77_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -258,11 +258,11 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - (26_295_000 as Weight) + (32_485_000 as Weight) // Standard Error: 1_000 - .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((39_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((130_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((124_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -271,13 +271,13 @@ impl WeightInfo for () { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - (28_609_000 as Weight) + (33_487_000 as Weight) // Standard Error: 0 - .saturating_add((6_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((68_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((66_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((161_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((157_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -287,11 +287,11 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - (30_497_000 as Weight) + (33_494_000 as Weight) // Standard Error: 1_000 - .saturating_add((48_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((58_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((124_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -301,13 +301,13 @@ impl WeightInfo for () { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - (31_402_000 as Weight) + (36_566_000 as Weight) // Standard Error: 0 .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) // Standard Error: 1_000 - .saturating_add((73_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((63_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 1_000 - .saturating_add((159_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -315,9 +315,9 @@ impl WeightInfo for () { // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - (16_391_000 as Weight) + (20_159_000 as Weight) // Standard Error: 1_000 - .saturating_add((169_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((173_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index 6946317475ae2..330d02755cb8b 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_conviction_voting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -62,7 +62,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_new() -> Weight { - (145_945_000 as Weight) + (148_804_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -72,7 +72,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_existing() -> Weight { - (316_356_000 as Weight) + (313_333_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -80,14 +80,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn remove_vote() -> Weight { - (298_447_000 as Weight) + (300_591_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:0) fn remove_other_vote() -> Weight { - (48_705_000 as Weight) + (53_887_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -97,9 +97,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn delegate(r: u32, ) -> Weight { - (51_221_000 as Weight) - // Standard Error: 140_000 - .saturating_add((25_392_000 as Weight).saturating_mul(r as Weight)) + (51_518_000 as Weight) + // Standard Error: 83_000 + .saturating_add((27_235_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(4 as Weight)) @@ -109,9 +109,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn undelegate(r: u32, ) -> Weight { - (34_419_000 as Weight) - // Standard Error: 517_000 - .saturating_add((26_295_000 as Weight).saturating_mul(r as Weight)) + (37_885_000 as Weight) + // Standard Error: 75_000 + .saturating_add((24_395_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -121,7 +121,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn unlock() -> Weight { - (62_414_000 as Weight) + (67_703_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -135,7 +135,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_new() -> Weight { - (145_945_000 as Weight) + (148_804_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -145,7 +145,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_existing() -> Weight { - (316_356_000 as Weight) + (313_333_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } @@ -153,14 +153,14 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn remove_vote() -> Weight { - (298_447_000 as Weight) + (300_591_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:0) fn remove_other_vote() -> Weight { - (48_705_000 as Weight) + (53_887_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -170,9 +170,9 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn delegate(r: u32, ) -> Weight { - (51_221_000 as Weight) - // Standard Error: 140_000 - .saturating_add((25_392_000 as Weight).saturating_mul(r as Weight)) + (51_518_000 as Weight) + // Standard Error: 83_000 + .saturating_add((27_235_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) @@ -182,9 +182,9 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn undelegate(r: u32, ) -> Weight { - (34_419_000 as Weight) - // Standard Error: 517_000 - .saturating_add((26_295_000 as Weight).saturating_mul(r as Weight)) + (37_885_000 as Weight) + // Standard Error: 75_000 + .saturating_add((24_395_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -194,7 +194,7 @@ impl WeightInfo for () { // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn unlock() -> Weight { - (62_414_000 as Weight) + (67_703_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 50b4f3ab6ba22..45686b43f7152 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -80,15 +80,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (43_581_000 as Weight) + (48_328_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (26_887_000 as Weight) + (30_923_000 as Weight) // Standard Error: 1_000 - .saturating_add((134_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((142_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -96,9 +96,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (35_520_000 as Weight) - // Standard Error: 2_000 - .saturating_add((131_000 as Weight).saturating_mul(r as Weight)) + (40_345_000 as Weight) + // Standard Error: 1_000 + .saturating_add((140_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -106,16 +106,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (34_793_000 as Weight) + (39_853_000 as Weight) // Standard Error: 1_000 - .saturating_add((138_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((150_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (15_401_000 as Weight) + (19_364_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -126,45 +126,45 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (51_233_000 as Weight) - // Standard Error: 3_000 - .saturating_add((189_000 as Weight).saturating_mul(p as Weight)) + (57_708_000 as Weight) + // Standard Error: 4_000 + .saturating_add((192_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (7_650_000 as Weight) + (10_714_000 as Weight) // Standard Error: 0 - .saturating_add((30_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((33_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (1_341_000 as Weight) + (3_697_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (1_360_000 as Weight) + (3_831_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (16_021_000 as Weight) + (20_271_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (17_350_000 as Weight) + (21_319_000 as Weight) // Standard Error: 0 - .saturating_add((46_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -172,23 +172,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (39_418_000 as Weight) + (43_960_000 as Weight) // Standard Error: 2_000 - .saturating_add((170_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((184_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (10_239_000 as Weight) + (13_475_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (20_483_000 as Weight) + (24_320_000 as Weight) // Standard Error: 1_000 - .saturating_add((565_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((560_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -196,9 +196,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (3_871_000 as Weight) + (3_428_000 as Weight) // Standard Error: 2_000 - .saturating_add((3_038_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_171_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -210,9 +210,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - (7_597_000 as Weight) + (7_867_000 as Weight) // Standard Error: 2_000 - .saturating_add((3_046_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_177_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -221,9 +221,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (32_554_000 as Weight) - // Standard Error: 3_000 - .saturating_add((3_903_000 as Weight).saturating_mul(r as Weight)) + (37_902_000 as Weight) + // Standard Error: 4_000 + .saturating_add((4_335_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(4 as Weight)) @@ -232,9 +232,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (15_440_000 as Weight) + (21_272_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_972_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((4_351_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -242,12 +242,12 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (1_662_000 as Weight) + (4_913_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (24_170_000 as Weight) + (27_986_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -255,7 +255,7 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (16_470_000 as Weight) + (20_058_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -264,7 +264,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (24_547_000 as Weight) + (28_619_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -274,9 +274,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (22_596_000 as Weight) + (26_619_000 as Weight) // Standard Error: 1_000 - .saturating_add((61_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((56_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -284,27 +284,27 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (21_589_000 as Weight) + (25_373_000 as Weight) // Standard Error: 1_000 - .saturating_add((125_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (12_120_000 as Weight) + (15_961_000 as Weight) // Standard Error: 1_000 - .saturating_add((106_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((115_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (12_563_000 as Weight) + (15_992_000 as Weight) // Standard Error: 1_000 - .saturating_add((105_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((113_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -317,15 +317,15 @@ impl WeightInfo for () { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (43_581_000 as Weight) + (48_328_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (26_887_000 as Weight) + (30_923_000 as Weight) // Standard Error: 1_000 - .saturating_add((134_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((142_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -333,9 +333,9 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (35_520_000 as Weight) - // Standard Error: 2_000 - .saturating_add((131_000 as Weight).saturating_mul(r as Weight)) + (40_345_000 as Weight) + // Standard Error: 1_000 + .saturating_add((140_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -343,16 +343,16 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (34_793_000 as Weight) + (39_853_000 as Weight) // Standard Error: 1_000 - .saturating_add((138_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((150_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (15_401_000 as Weight) + (19_364_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -363,45 +363,45 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (51_233_000 as Weight) - // Standard Error: 3_000 - .saturating_add((189_000 as Weight).saturating_mul(p as Weight)) + (57_708_000 as Weight) + // Standard Error: 4_000 + .saturating_add((192_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (7_650_000 as Weight) + (10_714_000 as Weight) // Standard Error: 0 - .saturating_add((30_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((33_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (1_341_000 as Weight) + (3_697_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (1_360_000 as Weight) + (3_831_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (16_021_000 as Weight) + (20_271_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (17_350_000 as Weight) + (21_319_000 as Weight) // Standard Error: 0 - .saturating_add((46_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -409,23 +409,23 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (39_418_000 as Weight) + (43_960_000 as Weight) // Standard Error: 2_000 - .saturating_add((170_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((184_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (10_239_000 as Weight) + (13_475_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (20_483_000 as Weight) + (24_320_000 as Weight) // Standard Error: 1_000 - .saturating_add((565_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((560_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -433,9 +433,9 @@ impl WeightInfo for () { // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (3_871_000 as Weight) + (3_428_000 as Weight) // Standard Error: 2_000 - .saturating_add((3_038_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_171_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -447,9 +447,9 @@ impl WeightInfo for () { // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - (7_597_000 as Weight) + (7_867_000 as Weight) // Standard Error: 2_000 - .saturating_add((3_046_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((3_177_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -458,9 +458,9 @@ impl WeightInfo for () { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (32_554_000 as Weight) - // Standard Error: 3_000 - .saturating_add((3_903_000 as Weight).saturating_mul(r as Weight)) + (37_902_000 as Weight) + // Standard Error: 4_000 + .saturating_add((4_335_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) @@ -469,9 +469,9 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (15_440_000 as Weight) + (21_272_000 as Weight) // Standard Error: 3_000 - .saturating_add((3_972_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((4_351_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -479,12 +479,12 @@ impl WeightInfo for () { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (1_662_000 as Weight) + (4_913_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (24_170_000 as Weight) + (27_986_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -492,7 +492,7 @@ impl WeightInfo for () { } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (16_470_000 as Weight) + (20_058_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -501,7 +501,7 @@ impl WeightInfo for () { // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (24_547_000 as Weight) + (28_619_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -511,9 +511,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (22_596_000 as Weight) + (26_619_000 as Weight) // Standard Error: 1_000 - .saturating_add((61_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((56_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -521,27 +521,27 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (21_589_000 as Weight) + (25_373_000 as Weight) // Standard Error: 1_000 - .saturating_add((125_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (12_120_000 as Weight) + (15_961_000 as Weight) // Standard Error: 1_000 - .saturating_add((106_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((115_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (12_563_000 as Weight) + (15_992_000 as Weight) // Standard Error: 1_000 - .saturating_add((105_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((113_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index d4802210ba23f..68ce00dd0de32 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_election_provider_multi_phase //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -68,33 +68,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (12_920_000 as Weight) + (13_495_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (13_366_000 as Weight) + (14_114_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (13_487_000 as Weight) + (13_756_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (28_656_000 as Weight) + (28_467_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (21_910_000 as Weight) + (21_991_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -102,11 +102,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (0 as Weight) + (3_186_000 as Weight) // Standard Error: 1_000 - .saturating_add((210_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((202_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 3_000 - .saturating_add((77_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((60_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -119,11 +119,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (97_857_000 as Weight) - // Standard Error: 2_000 - .saturating_add((651_000 as Weight).saturating_mul(a as Weight)) + (137_653_000 as Weight) // Standard Error: 4_000 - .saturating_add((133_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((640_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 6_000 + .saturating_add((48_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -134,7 +134,7 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit() -> Weight { - (43_892_000 as Weight) + (49_313_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -148,13 +148,13 @@ impl WeightInfo for SubstrateWeight { fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((900_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 6_000 - .saturating_add((141_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 11_000 - .saturating_add((6_817_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 17_000 - .saturating_add((1_533_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((867_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 7_000 + .saturating_add((107_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 12_000 + .saturating_add((6_907_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 18_000 + .saturating_add((1_427_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -164,14 +164,14 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_000 - .saturating_add((885_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 6_000 - .saturating_add((205_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 11_000 - .saturating_add((5_532_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 16_000 - .saturating_add((1_138_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 2_000 + .saturating_add((844_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 5_000 + .saturating_add((150_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 8_000 + .saturating_add((5_421_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 13_000 + .saturating_add((1_167_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) } } @@ -187,33 +187,33 @@ impl WeightInfo for () { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (12_920_000 as Weight) + (13_495_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (13_366_000 as Weight) + (14_114_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (13_487_000 as Weight) + (13_756_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (28_656_000 as Weight) + (28_467_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (21_910_000 as Weight) + (21_991_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -221,11 +221,11 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (0 as Weight) + (3_186_000 as Weight) // Standard Error: 1_000 - .saturating_add((210_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((202_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 3_000 - .saturating_add((77_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((60_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -238,11 +238,11 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (97_857_000 as Weight) - // Standard Error: 2_000 - .saturating_add((651_000 as Weight).saturating_mul(a as Weight)) + (137_653_000 as Weight) // Standard Error: 4_000 - .saturating_add((133_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((640_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 6_000 + .saturating_add((48_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -253,7 +253,7 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit() -> Weight { - (43_892_000 as Weight) + (49_313_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -267,13 +267,13 @@ impl WeightInfo for () { fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 3_000 - .saturating_add((900_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 6_000 - .saturating_add((141_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 11_000 - .saturating_add((6_817_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 17_000 - .saturating_add((1_533_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((867_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 7_000 + .saturating_add((107_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 12_000 + .saturating_add((6_907_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 18_000 + .saturating_add((1_427_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -283,14 +283,14 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 3_000 - .saturating_add((885_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 6_000 - .saturating_add((205_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 11_000 - .saturating_add((5_532_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 16_000 - .saturating_add((1_138_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 2_000 + .saturating_add((844_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 5_000 + .saturating_add((150_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 8_000 + .saturating_add((5_421_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 13_000 + .saturating_add((1_167_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) } } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 6cb2924fd7cf8..5ad986bf142a3 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -68,9 +68,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_equal(v: u32, ) -> Weight { - (23_819_000 as Weight) + (27_798_000 as Weight) // Standard Error: 5_000 - .saturating_add((242_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((238_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -80,8 +80,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_more(v: u32, ) -> Weight { - (37_141_000 as Weight) - // Standard Error: 6_000 + (41_241_000 as Weight) + // Standard Error: 8_000 .saturating_add((259_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -92,16 +92,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_less(v: u32, ) -> Weight { - (37_494_000 as Weight) - // Standard Error: 10_000 - .saturating_add((227_000 as Weight).saturating_mul(v as Weight)) + (41_313_000 as Weight) + // Standard Error: 8_000 + .saturating_add((255_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (34_528_000 as Weight) + (39_218_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -109,17 +109,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) fn submit_candidacy(c: u32, ) -> Weight { - (38_330_000 as Weight) + (41_348_000 as Weight) // Standard Error: 1_000 - .saturating_add((88_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((112_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (32_770_000 as Weight) + (35_522_000 as Weight) // Standard Error: 1_000 - .saturating_add((81_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((92_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -129,13 +129,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (43_413_000 as Weight) + (47_887_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (32_206_000 as Weight) + (36_271_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -150,13 +150,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (50_135_000 as Weight) + (55_024_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Elections RunnersUp (r:1 w:0) fn remove_member_wrong_refund() -> Weight { - (5_063_000 as Weight) + (13_089_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Elections Voting (r:251 w:250) @@ -165,10 +165,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Candidates (r:1 w:0) // Storage: Balances Locks (r:250 w:250) // Storage: System Account (r:250 w:250) - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { + fn clean_defunct_voters(v: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 62_000 - .saturating_add((52_093_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 40_000 + .saturating_add((51_848_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 38_000 + .saturating_add((537_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -184,12 +186,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_658_000 - .saturating_add((30_489_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 689_000 - .saturating_add((49_624_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 1_664_000 + .saturating_add((30_736_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 692_000 + .saturating_add((49_739_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 47_000 - .saturating_add((3_352_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((3_363_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) @@ -204,9 +206,9 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_equal(v: u32, ) -> Weight { - (23_819_000 as Weight) + (27_798_000 as Weight) // Standard Error: 5_000 - .saturating_add((242_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((238_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -216,8 +218,8 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_more(v: u32, ) -> Weight { - (37_141_000 as Weight) - // Standard Error: 6_000 + (41_241_000 as Weight) + // Standard Error: 8_000 .saturating_add((259_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -228,16 +230,16 @@ impl WeightInfo for () { // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_less(v: u32, ) -> Weight { - (37_494_000 as Weight) - // Standard Error: 10_000 - .saturating_add((227_000 as Weight).saturating_mul(v as Weight)) + (41_313_000 as Weight) + // Standard Error: 8_000 + .saturating_add((255_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (34_528_000 as Weight) + (39_218_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -245,17 +247,17 @@ impl WeightInfo for () { // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) fn submit_candidacy(c: u32, ) -> Weight { - (38_330_000 as Weight) + (41_348_000 as Weight) // Standard Error: 1_000 - .saturating_add((88_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((112_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (32_770_000 as Weight) + (35_522_000 as Weight) // Standard Error: 1_000 - .saturating_add((81_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((92_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -265,13 +267,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (43_413_000 as Weight) + (47_887_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (32_206_000 as Weight) + (36_271_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -286,13 +288,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (50_135_000 as Weight) + (55_024_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Elections RunnersUp (r:1 w:0) fn remove_member_wrong_refund() -> Weight { - (5_063_000 as Weight) + (13_089_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Elections Voting (r:251 w:250) @@ -301,10 +303,12 @@ impl WeightInfo for () { // Storage: Elections Candidates (r:1 w:0) // Storage: Balances Locks (r:250 w:250) // Storage: System Account (r:250 w:250) - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { + fn clean_defunct_voters(v: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 62_000 - .saturating_add((52_093_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 40_000 + .saturating_add((51_848_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 38_000 + .saturating_add((537_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -320,12 +324,12 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_658_000 - .saturating_add((30_489_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 689_000 - .saturating_add((49_624_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 1_664_000 + .saturating_add((30_736_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 692_000 + .saturating_add((49_739_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 47_000 - .saturating_add((3_352_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((3_363_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) diff --git a/frame/gilt/src/weights.rs b/frame/gilt/src/weights.rs index 99e58d070e493..952080a2d030b 100644 --- a/frame/gilt/src/weights.rs +++ b/frame/gilt/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_gilt //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -60,44 +60,44 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - (36_598_000 as Weight) + (41_605_000 as Weight) // Standard Error: 0 - .saturating_add((61_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((62_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - (92_021_000 as Weight) + (97_715_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - (37_133_000 as Weight) + (42_061_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - (2_807_000 as Weight) + (5_026_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - (43_275_000 as Weight) + (47_753_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - (1_693_000 as Weight) + (1_663_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) @@ -105,9 +105,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - (37_977_000 as Weight) - // Standard Error: 2_000 - .saturating_add((4_129_000 as Weight).saturating_mul(b as Weight)) + (40_797_000 as Weight) + // Standard Error: 1_000 + .saturating_add((4_122_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(b as Weight))) @@ -117,9 +117,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - (11_367_000 as Weight) - // Standard Error: 7_000 - .saturating_add((8_275_000 as Weight).saturating_mul(q as Weight)) + (14_944_000 as Weight) + // Standard Error: 6_000 + .saturating_add((8_135_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(q as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -132,44 +132,44 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - (36_598_000 as Weight) + (41_605_000 as Weight) // Standard Error: 0 - .saturating_add((61_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((62_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - (92_021_000 as Weight) + (97_715_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - (37_133_000 as Weight) + (42_061_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - (2_807_000 as Weight) + (5_026_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - (43_275_000 as Weight) + (47_753_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - (1_693_000 as Weight) + (1_663_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Gilt ActiveTotal (r:1 w:1) @@ -177,9 +177,9 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - (37_977_000 as Weight) - // Standard Error: 2_000 - .saturating_add((4_129_000 as Weight).saturating_mul(b as Weight)) + (40_797_000 as Weight) + // Standard Error: 1_000 + .saturating_add((4_122_000 as Weight).saturating_mul(b as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(b as Weight))) @@ -189,9 +189,9 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - (11_367_000 as Weight) - // Standard Error: 7_000 - .saturating_add((8_275_000 as Weight).saturating_mul(q as Weight)) + (14_944_000 as Weight) + // Standard Error: 6_000 + .saturating_add((8_135_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(q as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 77c5915f0ec99..d59611e2e1e82 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_identity //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -67,19 +67,19 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:1) fn add_registrar(r: u32, ) -> Weight { - (13_318_000 as Weight) - // Standard Error: 3_000 - .saturating_add((203_000 as Weight).saturating_mul(r as Weight)) + (16_343_000 as Weight) + // Standard Error: 5_000 + .saturating_add((229_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn set_identity(r: u32, x: u32, ) -> Weight { - (27_683_000 as Weight) + (32_920_000 as Weight) // Standard Error: 8_000 - .saturating_add((242_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((203_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((307_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((300_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -87,9 +87,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) fn set_subs_new(s: u32, ) -> Weight { - (26_126_000 as Weight) + (31_009_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_826_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((3_053_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -99,9 +99,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) fn set_subs_old(p: u32, ) -> Weight { - (24_645_000 as Weight) - // Standard Error: 0 - .saturating_add((893_000 as Weight).saturating_mul(p as Weight)) + (29_712_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_087_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -110,13 +110,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (31_546_000 as Weight) - // Standard Error: 12_000 - .saturating_add((110_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_000 - .saturating_add((872_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 1_000 - .saturating_add((182_000 as Weight).saturating_mul(x as Weight)) + (33_943_000 as Weight) + // Standard Error: 7_000 + .saturating_add((193_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 0 + .saturating_add((1_101_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 0 + .saturating_add((194_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -124,56 +124,56 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn request_judgement(r: u32, x: u32, ) -> Weight { - (31_117_000 as Weight) + (34_861_000 as Weight) // Standard Error: 3_000 - .saturating_add((207_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((249_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((347_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((344_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn cancel_request(r: u32, x: u32, ) -> Weight { - (28_134_000 as Weight) + (32_906_000 as Weight) // Standard Error: 3_000 - .saturating_add((154_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((147_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((343_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fee(r: u32, ) -> Weight { - (4_884_000 as Weight) + (7_591_000 as Weight) // Standard Error: 3_000 - .saturating_add((159_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((201_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_account_id(r: u32, ) -> Weight { - (5_015_000 as Weight) - // Standard Error: 2_000 - .saturating_add((143_000 as Weight).saturating_mul(r as Weight)) + (7_919_000 as Weight) + // Standard Error: 3_000 + .saturating_add((183_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fields(r: u32, ) -> Weight { - (4_947_000 as Weight) - // Standard Error: 3_000 - .saturating_add((152_000 as Weight).saturating_mul(r as Weight)) + (7_887_000 as Weight) + // Standard Error: 4_000 + .saturating_add((182_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn provide_judgement(r: u32, x: u32, ) -> Weight { - (20_570_000 as Weight) + (24_623_000 as Weight) // Standard Error: 3_000 - .saturating_add((213_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((230_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((345_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((339_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -182,11 +182,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (41_448_000 as Weight) - // Standard Error: 7_000 - .saturating_add((149_000 as Weight).saturating_mul(r as Weight)) + (48_143_000 as Weight) + // Standard Error: 8_000 + .saturating_add((106_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((882_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_105_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -195,18 +195,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn add_sub(s: u32, ) -> Weight { - (32_346_000 as Weight) + (36_778_000 as Weight) // Standard Error: 1_000 - .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((112_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) fn rename_sub(s: u32, ) -> Weight { - (10_211_000 as Weight) + (13_895_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -214,18 +214,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn remove_sub(s: u32, ) -> Weight { - (33_083_000 as Weight) + (37_707_000 as Weight) // Standard Error: 1_000 - .saturating_add((112_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn quit_sub(s: u32, ) -> Weight { - (22_517_000 as Weight) + (26_935_000 as Weight) // Standard Error: 1_000 - .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((106_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -235,19 +235,19 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:1) fn add_registrar(r: u32, ) -> Weight { - (13_318_000 as Weight) - // Standard Error: 3_000 - .saturating_add((203_000 as Weight).saturating_mul(r as Weight)) + (16_343_000 as Weight) + // Standard Error: 5_000 + .saturating_add((229_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn set_identity(r: u32, x: u32, ) -> Weight { - (27_683_000 as Weight) + (32_920_000 as Weight) // Standard Error: 8_000 - .saturating_add((242_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((203_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((307_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((300_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -255,9 +255,9 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) fn set_subs_new(s: u32, ) -> Weight { - (26_126_000 as Weight) + (31_009_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_826_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((3_053_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -267,9 +267,9 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) fn set_subs_old(p: u32, ) -> Weight { - (24_645_000 as Weight) - // Standard Error: 0 - .saturating_add((893_000 as Weight).saturating_mul(p as Weight)) + (29_712_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_087_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -278,13 +278,13 @@ impl WeightInfo for () { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (31_546_000 as Weight) - // Standard Error: 12_000 - .saturating_add((110_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_000 - .saturating_add((872_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 1_000 - .saturating_add((182_000 as Weight).saturating_mul(x as Weight)) + (33_943_000 as Weight) + // Standard Error: 7_000 + .saturating_add((193_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 0 + .saturating_add((1_101_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 0 + .saturating_add((194_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -292,56 +292,56 @@ impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn request_judgement(r: u32, x: u32, ) -> Weight { - (31_117_000 as Weight) + (34_861_000 as Weight) // Standard Error: 3_000 - .saturating_add((207_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((249_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((347_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((344_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) fn cancel_request(r: u32, x: u32, ) -> Weight { - (28_134_000 as Weight) + (32_906_000 as Weight) // Standard Error: 3_000 - .saturating_add((154_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((147_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((343_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fee(r: u32, ) -> Weight { - (4_884_000 as Weight) + (7_591_000 as Weight) // Standard Error: 3_000 - .saturating_add((159_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((201_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_account_id(r: u32, ) -> Weight { - (5_015_000 as Weight) - // Standard Error: 2_000 - .saturating_add((143_000 as Weight).saturating_mul(r as Weight)) + (7_919_000 as Weight) + // Standard Error: 3_000 + .saturating_add((183_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) fn set_fields(r: u32, ) -> Weight { - (4_947_000 as Weight) - // Standard Error: 3_000 - .saturating_add((152_000 as Weight).saturating_mul(r as Weight)) + (7_887_000 as Weight) + // Standard Error: 4_000 + .saturating_add((182_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) fn provide_judgement(r: u32, x: u32, ) -> Weight { - (20_570_000 as Weight) + (24_623_000 as Weight) // Standard Error: 3_000 - .saturating_add((213_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((230_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((345_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((339_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -350,11 +350,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (41_448_000 as Weight) - // Standard Error: 7_000 - .saturating_add((149_000 as Weight).saturating_mul(r as Weight)) + (48_143_000 as Weight) + // Standard Error: 8_000 + .saturating_add((106_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((882_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_105_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -363,18 +363,18 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn add_sub(s: u32, ) -> Weight { - (32_346_000 as Weight) + (36_778_000 as Weight) // Standard Error: 1_000 - .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((112_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) fn rename_sub(s: u32, ) -> Weight { - (10_211_000 as Weight) + (13_895_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -382,18 +382,18 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn remove_sub(s: u32, ) -> Weight { - (33_083_000 as Weight) + (37_707_000 as Weight) // Standard Error: 1_000 - .saturating_add((112_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) fn quit_sub(s: u32, ) -> Weight { - (22_517_000 as Weight) + (26_935_000 as Weight) // Standard Error: 1_000 - .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((106_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index 187499b1f957f..34762e66ec301 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_im_online //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -56,11 +56,11 @@ impl WeightInfo for SubstrateWeight { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - (74_221_000 as Weight) + (79_225_000 as Weight) // Standard Error: 0 .saturating_add((41_000 as Weight).saturating_mul(k as Weight)) // Standard Error: 0 - .saturating_add((294_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((293_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -74,11 +74,11 @@ impl WeightInfo for () { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - (74_221_000 as Weight) + (79_225_000 as Weight) // Standard Error: 0 .saturating_add((41_000 as Weight).saturating_mul(k as Weight)) // Standard Error: 0 - .saturating_add((294_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((293_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 5fba8fc2377a0..6635d45272048 100644 --- a/frame/indices/src/weights.rs +++ b/frame/indices/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_indices //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -56,33 +56,33 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - (21_333_000 as Weight) + (25_929_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (27_479_000 as Weight) + (32_627_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - (22_802_000 as Weight) + (26_804_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (23_369_000 as Weight) + (27_390_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - (25_740_000 as Weight) + (30_973_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -92,33 +92,33 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - (21_333_000 as Weight) + (25_929_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (27_479_000 as Weight) + (32_627_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - (22_802_000 as Weight) + (26_804_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (23_369_000 as Weight) + (27_390_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - (25_740_000 as Weight) + (30_973_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index d3626dc9080ec..193958cfd41aa 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_lottery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -63,28 +63,28 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (39_387_000 as Weight) + (44_706_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (9_353_000 as Weight) - // Standard Error: 4_000 - .saturating_add((297_000 as Weight).saturating_mul(n as Weight)) + (12_556_000 as Weight) + // Standard Error: 7_000 + .saturating_add((295_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (33_157_000 as Weight) + (38_051_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (4_015_000 as Weight) + (6_910_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -94,7 +94,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (53_539_000 as Weight) + (53_732_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -105,7 +105,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (56_103_000 as Weight) + (55_868_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -121,28 +121,28 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (39_387_000 as Weight) + (44_706_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (9_353_000 as Weight) - // Standard Error: 4_000 - .saturating_add((297_000 as Weight).saturating_mul(n as Weight)) + (12_556_000 as Weight) + // Standard Error: 7_000 + .saturating_add((295_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (33_157_000 as Weight) + (38_051_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (4_015_000 as Weight) + (6_910_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -152,7 +152,7 @@ impl WeightInfo for () { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (53_539_000 as Weight) + (53_732_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -163,7 +163,7 @@ impl WeightInfo for () { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (56_103_000 as Weight) + (55_868_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 7372ad37cdea2..714d53b1936a8 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_membership //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -61,9 +61,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - (15_572_000 as Weight) - // Standard Error: 1_000 - .saturating_add((48_000 as Weight).saturating_mul(m as Weight)) + (15_318_000 as Weight) + // Standard Error: 0 + .saturating_add((51_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -73,9 +73,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - (18_090_000 as Weight) + (18_005_000 as Weight) // Standard Error: 0 - .saturating_add((43_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((45_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -85,9 +85,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - (18_199_000 as Weight) + (18_029_000 as Weight) // Standard Error: 0 - .saturating_add((54_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -97,7 +97,7 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - (18_238_000 as Weight) + (18_105_000 as Weight) // Standard Error: 0 .saturating_add((158_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -109,9 +109,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - (18_911_000 as Weight) + (18_852_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -119,16 +119,16 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - (4_843_000 as Weight) + (4_869_000 as Weight) // Standard Error: 0 - .saturating_add((27_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((28_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - (1_662_000 as Weight) + (1_593_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -142,9 +142,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - (15_572_000 as Weight) - // Standard Error: 1_000 - .saturating_add((48_000 as Weight).saturating_mul(m as Weight)) + (15_318_000 as Weight) + // Standard Error: 0 + .saturating_add((51_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -154,9 +154,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - (18_090_000 as Weight) + (18_005_000 as Weight) // Standard Error: 0 - .saturating_add((43_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((45_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -166,9 +166,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - (18_199_000 as Weight) + (18_029_000 as Weight) // Standard Error: 0 - .saturating_add((54_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -178,7 +178,7 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - (18_238_000 as Weight) + (18_105_000 as Weight) // Standard Error: 0 .saturating_add((158_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -190,9 +190,9 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - (18_911_000 as Weight) + (18_852_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -200,16 +200,16 @@ impl WeightInfo for () { // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - (4_843_000 as Weight) + (4_869_000 as Weight) // Standard Error: 0 - .saturating_add((27_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((28_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - (1_662_000 as Weight) + (1_593_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index 563dd20bae63d..7946b96546768 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_multisig //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -60,14 +60,14 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn as_multi_threshold_1(_z: u32, ) -> Weight { - (12_456_000 as Weight) + (17_537_000 as Weight) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - (31_781_000 as Weight) + (36_535_000 as Weight) // Standard Error: 0 - .saturating_add((93_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((99_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -77,7 +77,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - (35_669_000 as Weight) + (39_918_000 as Weight) // Standard Error: 1_000 .saturating_add((95_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 @@ -87,9 +87,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - (21_326_000 as Weight) + (25_524_000 as Weight) // Standard Error: 0 - .saturating_add((91_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((94_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -98,9 +98,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - (35_296_000 as Weight) + (39_923_000 as Weight) // Standard Error: 1_000 - .saturating_add((88_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((91_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -110,9 +110,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - (39_872_000 as Weight) + (45_877_000 as Weight) // Standard Error: 1_000 - .saturating_add((147_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((146_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -121,18 +121,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - (29_680_000 as Weight) - // Standard Error: 0 - .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) + (34_309_000 as Weight) + // Standard Error: 1_000 + .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - (18_514_000 as Weight) + (22_848_000 as Weight) // Standard Error: 0 - .saturating_add((111_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -140,18 +140,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - (57_404_000 as Weight) + (63_239_000 as Weight) // Standard Error: 1_000 - .saturating_add((157_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((161_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - (45_860_000 as Weight) + (51_254_000 as Weight) // Standard Error: 1_000 - .saturating_add((111_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((118_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -160,14 +160,14 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn as_multi_threshold_1(_z: u32, ) -> Weight { - (12_456_000 as Weight) + (17_537_000 as Weight) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - (31_781_000 as Weight) + (36_535_000 as Weight) // Standard Error: 0 - .saturating_add((93_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((99_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -177,7 +177,7 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - (35_669_000 as Weight) + (39_918_000 as Weight) // Standard Error: 1_000 .saturating_add((95_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 @@ -187,9 +187,9 @@ impl WeightInfo for () { } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - (21_326_000 as Weight) + (25_524_000 as Weight) // Standard Error: 0 - .saturating_add((91_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((94_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -198,9 +198,9 @@ impl WeightInfo for () { // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - (35_296_000 as Weight) + (39_923_000 as Weight) // Standard Error: 1_000 - .saturating_add((88_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((91_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) @@ -210,9 +210,9 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - (39_872_000 as Weight) + (45_877_000 as Weight) // Standard Error: 1_000 - .saturating_add((147_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((146_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -221,18 +221,18 @@ impl WeightInfo for () { // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - (29_680_000 as Weight) - // Standard Error: 0 - .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) + (34_309_000 as Weight) + // Standard Error: 1_000 + .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - (18_514_000 as Weight) + (22_848_000 as Weight) // Standard Error: 0 - .saturating_add((111_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -240,18 +240,18 @@ impl WeightInfo for () { // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - (57_404_000 as Weight) + (63_239_000 as Weight) // Standard Error: 1_000 - .saturating_add((157_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((161_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - (45_860_000 as Weight) + (51_254_000 as Weight) // Standard Error: 1_000 - .saturating_add((111_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((118_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index ef339231fe7bb..ca89f982c60e3 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -77,7 +77,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (124_114_000 as Weight) + (129_124_000 as Weight) .saturating_add(T::DbWeight::get().reads(17 as Weight)) .saturating_add(T::DbWeight::get().writes(11 as Weight)) } @@ -91,7 +91,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (115_734_000 as Weight) + (118_193_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) } @@ -105,7 +105,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:2 w:2) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (127_873_000 as Weight) + (132_390_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) } @@ -114,7 +114,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (51_510_000 as Weight) + (54_743_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -133,7 +133,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (120_744_000 as Weight) + (124_684_000 as Weight) .saturating_add(T::DbWeight::get().reads(18 as Weight)) .saturating_add(T::DbWeight::get().writes(13 as Weight)) } @@ -142,9 +142,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (41_267_000 as Weight) + (44_259_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -157,9 +157,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (82_234_000 as Weight) + (84_854_000 as Weight) // Standard Error: 0 - .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -182,10 +182,8 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - (142_699_000 as Weight) - // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(s as Weight)) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + (146_992_000 as Weight) .saturating_add(T::DbWeight::get().reads(19 as Weight)) .saturating_add(T::DbWeight::get().writes(16 as Weight)) } @@ -212,7 +210,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (133_702_000 as Weight) + (138_099_000 as Weight) .saturating_add(T::DbWeight::get().reads(22 as Weight)) .saturating_add(T::DbWeight::get().writes(15 as Weight)) } @@ -229,9 +227,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (46_887_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_277_000 as Weight).saturating_mul(n as Weight)) + (50_964_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_333_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(5 as Weight)) @@ -239,7 +237,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (24_030_000 as Weight) + (27_196_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -247,9 +245,9 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) fn set_metadata(n: u32, ) -> Weight { - (11_336_000 as Weight) + (15_056_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -259,12 +257,12 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (2_927_000 as Weight) + (6_294_000 as Weight) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (19_184_000 as Weight) + (22_444_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -286,7 +284,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (124_114_000 as Weight) + (129_124_000 as Weight) .saturating_add(RocksDbWeight::get().reads(17 as Weight)) .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } @@ -300,7 +298,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (115_734_000 as Weight) + (118_193_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) } @@ -314,7 +312,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:2 w:2) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (127_873_000 as Weight) + (132_390_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) } @@ -323,7 +321,7 @@ impl WeightInfo for () { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (51_510_000 as Weight) + (54_743_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -342,7 +340,7 @@ impl WeightInfo for () { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (120_744_000 as Weight) + (124_684_000 as Weight) .saturating_add(RocksDbWeight::get().reads(18 as Weight)) .saturating_add(RocksDbWeight::get().writes(13 as Weight)) } @@ -351,9 +349,9 @@ impl WeightInfo for () { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (41_267_000 as Weight) + (44_259_000 as Weight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -366,9 +364,9 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (82_234_000 as Weight) + (84_854_000 as Weight) // Standard Error: 0 - .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } @@ -391,10 +389,8 @@ impl WeightInfo for () { // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - (142_699_000 as Weight) - // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(s as Weight)) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + (146_992_000 as Weight) .saturating_add(RocksDbWeight::get().reads(19 as Weight)) .saturating_add(RocksDbWeight::get().writes(16 as Weight)) } @@ -421,7 +417,7 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (133_702_000 as Weight) + (138_099_000 as Weight) .saturating_add(RocksDbWeight::get().reads(22 as Weight)) .saturating_add(RocksDbWeight::get().writes(15 as Weight)) } @@ -438,9 +434,9 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (46_887_000 as Weight) - // Standard Error: 12_000 - .saturating_add((2_277_000 as Weight).saturating_mul(n as Weight)) + (50_964_000 as Weight) + // Standard Error: 11_000 + .saturating_add((2_333_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) @@ -448,7 +444,7 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (24_030_000 as Weight) + (27_196_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -456,9 +452,9 @@ impl WeightInfo for () { // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) fn set_metadata(n: u32, ) -> Weight { - (11_336_000 as Weight) + (15_056_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -468,12 +464,12 @@ impl WeightInfo for () { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (2_927_000 as Weight) + (6_294_000 as Weight) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (19_184_000 as Weight) + (22_444_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 801ad627e07d9..de3eb6607fe8c 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -91,58 +91,58 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (38_459_000 as Weight) + (44_380_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (24_172_000 as Weight) + (30_280_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (37_200_000 as Weight) + (42_809_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (24_071_000 as Weight) + (28_964_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (13_974_000 as Weight) + (17_555_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (4_401_000 as Weight) + (7_745_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (24_756_000 as Weight) + (29_758_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (14_351_000 as Weight) + (18_360_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (4_359_000 as Weight) + (7_439_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -180,58 +180,58 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (38_459_000 as Weight) + (44_380_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (24_172_000 as Weight) + (30_280_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (37_200_000 as Weight) + (42_809_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (24_071_000 as Weight) + (28_964_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (13_974_000 as Weight) + (17_555_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (4_401_000 as Weight) + (7_745_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (24_756_000 as Weight) + (29_758_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (14_351_000 as Weight) + (18_360_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (4_359_000 as Weight) + (7_439_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index a0df59204f673..19beaf4d1401b 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_proxy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -61,42 +61,42 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - (13_918_000 as Weight) - // Standard Error: 1_000 - .saturating_add((66_000 as Weight).saturating_mul(p as Weight)) + (17_768_000 as Weight) + // Standard Error: 2_000 + .saturating_add((76_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - (30_328_000 as Weight) + (35_682_000 as Weight) // Standard Error: 2_000 - .saturating_add((159_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((64_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((73_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn remove_announcement(a: u32, p: u32, ) -> Weight { - (21_667_000 as Weight) + (25_586_000 as Weight) // Standard Error: 1_000 - .saturating_add((167_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((175_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((4_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((18_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_announcement(a: u32, p: u32, ) -> Weight { - (21_554_000 as Weight) + (25_794_000 as Weight) // Standard Error: 1_000 - .saturating_add((171_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((173_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((5_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((13_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -104,52 +104,52 @@ impl WeightInfo for SubstrateWeight { // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - (28_774_000 as Weight) + (33_002_000 as Weight) // Standard Error: 2_000 - .saturating_add((150_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((163_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((67_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((79_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - (23_571_000 as Weight) - // Standard Error: 1_000 - .saturating_add((110_000 as Weight).saturating_mul(p as Weight)) + (28_166_000 as Weight) + // Standard Error: 2_000 + .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - (23_613_000 as Weight) - // Standard Error: 2_000 - .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) + (28_128_000 as Weight) + // Standard Error: 3_000 + .saturating_add((118_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - (19_968_000 as Weight) - // Standard Error: 1_000 - .saturating_add((74_000 as Weight).saturating_mul(p as Weight)) + (24_066_000 as Weight) + // Standard Error: 2_000 + .saturating_add((81_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - (26_479_000 as Weight) - // Standard Error: 2_000 + (31_077_000 as Weight) + // Standard Error: 3_000 .saturating_add((37_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - (20_816_000 as Weight) - // Standard Error: 1_000 - .saturating_add((67_000 as Weight).saturating_mul(p as Weight)) + (24_657_000 as Weight) + // Standard Error: 2_000 + .saturating_add((87_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -159,42 +159,42 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - (13_918_000 as Weight) - // Standard Error: 1_000 - .saturating_add((66_000 as Weight).saturating_mul(p as Weight)) + (17_768_000 as Weight) + // Standard Error: 2_000 + .saturating_add((76_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - (30_328_000 as Weight) + (35_682_000 as Weight) // Standard Error: 2_000 - .saturating_add((159_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((64_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((73_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn remove_announcement(a: u32, p: u32, ) -> Weight { - (21_667_000 as Weight) + (25_586_000 as Weight) // Standard Error: 1_000 - .saturating_add((167_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((175_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((4_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((18_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_announcement(a: u32, p: u32, ) -> Weight { - (21_554_000 as Weight) + (25_794_000 as Weight) // Standard Error: 1_000 - .saturating_add((171_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((173_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 1_000 - .saturating_add((5_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((13_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -202,52 +202,52 @@ impl WeightInfo for () { // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - (28_774_000 as Weight) + (33_002_000 as Weight) // Standard Error: 2_000 - .saturating_add((150_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((163_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((67_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((79_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - (23_571_000 as Weight) - // Standard Error: 1_000 - .saturating_add((110_000 as Weight).saturating_mul(p as Weight)) + (28_166_000 as Weight) + // Standard Error: 2_000 + .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - (23_613_000 as Weight) - // Standard Error: 2_000 - .saturating_add((120_000 as Weight).saturating_mul(p as Weight)) + (28_128_000 as Weight) + // Standard Error: 3_000 + .saturating_add((118_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - (19_968_000 as Weight) - // Standard Error: 1_000 - .saturating_add((74_000 as Weight).saturating_mul(p as Weight)) + (24_066_000 as Weight) + // Standard Error: 2_000 + .saturating_add((81_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - (26_479_000 as Weight) - // Standard Error: 2_000 + (31_077_000 as Weight) + // Standard Error: 3_000 .saturating_add((37_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - (20_816_000 as Weight) - // Standard Error: 1_000 - .saturating_add((67_000 as Weight).saturating_mul(p as Weight)) + (24_657_000 as Weight) + // Standard Error: 2_000 + .saturating_add((87_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index 34a58b9e51ff2..0887180a533fc 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_recovery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -60,35 +60,35 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Recovery Proxy (r:1 w:0) fn as_recovered() -> Weight { - (3_732_000 as Weight) + (6_579_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Recovery Proxy (r:0 w:1) fn set_recovered() -> Weight { - (10_201_000 as Weight) + (13_402_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:1) fn create_recovery(n: u32, ) -> Weight { - (23_334_000 as Weight) + (28_217_000 as Weight) // Standard Error: 13_000 - .saturating_add((201_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((172_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn initiate_recovery() -> Weight { - (28_358_000 as Weight) + (34_082_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn vouch_recovery(n: u32, ) -> Weight { - (17_667_000 as Weight) - // Standard Error: 13_000 - .saturating_add((342_000 as Weight).saturating_mul(n as Weight)) + (22_038_000 as Weight) + // Standard Error: 19_000 + .saturating_add((307_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -96,33 +96,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Proxy (r:1 w:1) fn claim_recovery(n: u32, ) -> Weight { - (24_591_000 as Weight) - // Standard Error: 14_000 - .saturating_add((242_000 as Weight).saturating_mul(n as Weight)) + (28_621_000 as Weight) + // Standard Error: 13_000 + .saturating_add((353_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Recovery ActiveRecoveries (r:1 w:1) // Storage: System Account (r:1 w:1) fn close_recovery(n: u32, ) -> Weight { - (28_763_000 as Weight) - // Standard Error: 12_000 - .saturating_add((142_000 as Weight).saturating_mul(n as Weight)) + (33_287_000 as Weight) + // Standard Error: 19_000 + .saturating_add((264_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Recoverable (r:1 w:1) fn remove_recovery(n: u32, ) -> Weight { - (27_357_000 as Weight) - // Standard Error: 17_000 - .saturating_add((212_000 as Weight).saturating_mul(n as Weight)) + (31_964_000 as Weight) + // Standard Error: 13_000 + .saturating_add((222_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Recovery Proxy (r:1 w:1) fn cancel_recovered() -> Weight { - (9_068_000 as Weight) + (12_702_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -132,35 +132,35 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Recovery Proxy (r:1 w:0) fn as_recovered() -> Weight { - (3_732_000 as Weight) + (6_579_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Recovery Proxy (r:0 w:1) fn set_recovered() -> Weight { - (10_201_000 as Weight) + (13_402_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:1) fn create_recovery(n: u32, ) -> Weight { - (23_334_000 as Weight) + (28_217_000 as Weight) // Standard Error: 13_000 - .saturating_add((201_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((172_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn initiate_recovery() -> Weight { - (28_358_000 as Weight) + (34_082_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn vouch_recovery(n: u32, ) -> Weight { - (17_667_000 as Weight) - // Standard Error: 13_000 - .saturating_add((342_000 as Weight).saturating_mul(n as Weight)) + (22_038_000 as Weight) + // Standard Error: 19_000 + .saturating_add((307_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -168,33 +168,33 @@ impl WeightInfo for () { // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Proxy (r:1 w:1) fn claim_recovery(n: u32, ) -> Weight { - (24_591_000 as Weight) - // Standard Error: 14_000 - .saturating_add((242_000 as Weight).saturating_mul(n as Weight)) + (28_621_000 as Weight) + // Standard Error: 13_000 + .saturating_add((353_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Recovery ActiveRecoveries (r:1 w:1) // Storage: System Account (r:1 w:1) fn close_recovery(n: u32, ) -> Weight { - (28_763_000 as Weight) - // Standard Error: 12_000 - .saturating_add((142_000 as Weight).saturating_mul(n as Weight)) + (33_287_000 as Weight) + // Standard Error: 19_000 + .saturating_add((264_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Recoverable (r:1 w:1) fn remove_recovery(n: u32, ) -> Weight { - (27_357_000 as Weight) - // Standard Error: 17_000 - .saturating_add((212_000 as Weight).saturating_mul(n as Weight)) + (31_964_000 as Weight) + // Standard Error: 13_000 + .saturating_add((222_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Recovery Proxy (r:1 w:1) fn cancel_recovered() -> Weight { - (9_068_000 as Weight) + (12_702_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index d9ddbed49e883..d48ebb1014d48 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_referenda //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -80,14 +80,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - (30_596_000 as Weight) + (34_640_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - (40_115_000 as Weight) + (44_290_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -95,7 +95,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - (45_739_000 as Weight) + (49_428_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -103,7 +103,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - (45_741_000 as Weight) + (50_076_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -111,7 +111,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - (51_422_000 as Weight) + (55_935_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -119,34 +119,34 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - (48_714_000 as Weight) + (52_921_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - (24_896_000 as Weight) + (29_160_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - (30_511_000 as Weight) + (34_972_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - (55_662_000 as Weight) + (60_620_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - (6_659_000 as Weight) + (9_615_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -154,7 +154,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - (109_530_000 as Weight) + (113_077_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -162,7 +162,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - (110_576_000 as Weight) + (114_376_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -170,7 +170,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - (39_327_000 as Weight) + (43_901_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -178,7 +178,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - (39_179_000 as Weight) + (43_279_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -187,7 +187,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - (41_251_000 as Weight) + (45_564_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -196,27 +196,27 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - (41_009_000 as Weight) + (45_061_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - (20_228_000 as Weight) + (23_757_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - (20_456_000 as Weight) + (24_781_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - (16_202_000 as Weight) + (18_344_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -224,7 +224,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - (30_335_000 as Weight) + (34_752_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -232,35 +232,35 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - (32_700_000 as Weight) + (37_055_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - (27_225_000 as Weight) + (31_442_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - (28_355_000 as Weight) + (33_201_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - (26_515_000 as Weight) + (30_047_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - (24_991_000 as Weight) + (29_195_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -269,14 +269,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Lookup (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn nudge_referendum_approved() -> Weight { - (45_164_000 as Weight) + (50_119_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - (28_026_000 as Weight) + (32_203_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -288,14 +288,14 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - (30_596_000 as Weight) + (34_640_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - (40_115_000 as Weight) + (44_290_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -303,7 +303,7 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - (45_739_000 as Weight) + (49_428_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -311,7 +311,7 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - (45_741_000 as Weight) + (50_076_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -319,7 +319,7 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - (51_422_000 as Weight) + (55_935_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -327,34 +327,34 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - (48_714_000 as Weight) + (52_921_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - (24_896_000 as Weight) + (29_160_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - (30_511_000 as Weight) + (34_972_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - (55_662_000 as Weight) + (60_620_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - (6_659_000 as Weight) + (9_615_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -362,7 +362,7 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - (109_530_000 as Weight) + (113_077_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -370,7 +370,7 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - (110_576_000 as Weight) + (114_376_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -378,7 +378,7 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - (39_327_000 as Weight) + (43_901_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -386,7 +386,7 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - (39_179_000 as Weight) + (43_279_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -395,7 +395,7 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - (41_251_000 as Weight) + (45_564_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -404,27 +404,27 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - (41_009_000 as Weight) + (45_061_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - (20_228_000 as Weight) + (23_757_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - (20_456_000 as Weight) + (24_781_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - (16_202_000 as Weight) + (18_344_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -432,7 +432,7 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - (30_335_000 as Weight) + (34_752_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -440,35 +440,35 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - (32_700_000 as Weight) + (37_055_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - (27_225_000 as Weight) + (31_442_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - (28_355_000 as Weight) + (33_201_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - (26_515_000 as Weight) + (30_047_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - (24_991_000 as Weight) + (29_195_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -477,14 +477,14 @@ impl WeightInfo for () { // Storage: Scheduler Lookup (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn nudge_referendum_approved() -> Weight { - (45_164_000 as Weight) + (50_119_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - (28_026_000 as Weight) + (32_203_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index b667a03bbd472..b8bd4618f8def 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_remark //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -52,7 +52,7 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn store(l: u32, ) -> Weight { - (9_699_000 as Weight) + (13_140_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -63,7 +63,7 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn store(l: u32, ) -> Weight { - (9_699_000 as Weight) + (13_140_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index d56c3208b44af..dd7ed8104420d 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -68,9 +68,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (9_814_000 as Weight) - // Standard Error: 13_000 - .saturating_add((18_293_000 as Weight).saturating_mul(s as Weight)) + (9_994_000 as Weight) + // Standard Error: 20_000 + .saturating_add((19_843_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -81,9 +81,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (9_050_000 as Weight) - // Standard Error: 11_000 - .saturating_add((14_029_000 as Weight).saturating_mul(s as Weight)) + (10_318_000 as Weight) + // Standard Error: 17_000 + .saturating_add((15_451_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -93,9 +93,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (9_717_000 as Weight) - // Standard Error: 14_000 - .saturating_add((15_584_000 as Weight).saturating_mul(s as Weight)) + (11_675_000 as Weight) + // Standard Error: 17_000 + .saturating_add((17_019_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -105,9 +105,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (9_422_000 as Weight) - // Standard Error: 9_000 - .saturating_add((12_812_000 as Weight).saturating_mul(s as Weight)) + (11_934_000 as Weight) + // Standard Error: 11_000 + .saturating_add((14_134_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -117,9 +117,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (6_504_000 as Weight) - // Standard Error: 7_000 - .saturating_add((5_410_000 as Weight).saturating_mul(s as Weight)) + (7_279_000 as Weight) + // Standard Error: 5_000 + .saturating_add((5_388_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -128,9 +128,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (8_690_000 as Weight) - // Standard Error: 3_000 - .saturating_add((2_951_000 as Weight).saturating_mul(s as Weight)) + (8_619_000 as Weight) + // Standard Error: 4_000 + .saturating_add((2_969_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -138,9 +138,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (14_613_000 as Weight) - // Standard Error: 5_000 - .saturating_add((8_479_000 as Weight).saturating_mul(s as Weight)) + (16_129_000 as Weight) + // Standard Error: 7_000 + .saturating_add((9_772_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -148,9 +148,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (13_356_000 as Weight) - // Standard Error: 4_000 - .saturating_add((6_112_000 as Weight).saturating_mul(s as Weight)) + (15_785_000 as Weight) + // Standard Error: 5_000 + .saturating_add((7_208_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -159,33 +159,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (14_254_000 as Weight) + (15_778_000 as Weight) // Standard Error: 3_000 - .saturating_add((4_529_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((5_597_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (13_680_000 as Weight) - // Standard Error: 4_000 - .saturating_add((3_559_000 as Weight).saturating_mul(s as Weight)) + (15_912_000 as Weight) + // Standard Error: 5_000 + .saturating_add((4_530_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (14_821_000 as Weight) + (18_013_000 as Weight) // Standard Error: 1_000 - .saturating_add((85_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((87_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (15_029_000 as Weight) + (18_131_000 as Weight) // Standard Error: 1_000 .saturating_add((595_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) @@ -194,18 +194,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (17_498_000 as Weight) + (21_230_000 as Weight) // Standard Error: 1_000 - .saturating_add((102_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((98_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (16_695_000 as Weight) + (20_139_000 as Weight) // Standard Error: 1_000 - .saturating_add((610_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((595_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -218,9 +218,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (9_814_000 as Weight) - // Standard Error: 13_000 - .saturating_add((18_293_000 as Weight).saturating_mul(s as Weight)) + (9_994_000 as Weight) + // Standard Error: 20_000 + .saturating_add((19_843_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -231,9 +231,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (9_050_000 as Weight) - // Standard Error: 11_000 - .saturating_add((14_029_000 as Weight).saturating_mul(s as Weight)) + (10_318_000 as Weight) + // Standard Error: 17_000 + .saturating_add((15_451_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -243,9 +243,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (9_717_000 as Weight) - // Standard Error: 14_000 - .saturating_add((15_584_000 as Weight).saturating_mul(s as Weight)) + (11_675_000 as Weight) + // Standard Error: 17_000 + .saturating_add((17_019_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -255,9 +255,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (9_422_000 as Weight) - // Standard Error: 9_000 - .saturating_add((12_812_000 as Weight).saturating_mul(s as Weight)) + (11_934_000 as Weight) + // Standard Error: 11_000 + .saturating_add((14_134_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -267,9 +267,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (6_504_000 as Weight) - // Standard Error: 7_000 - .saturating_add((5_410_000 as Weight).saturating_mul(s as Weight)) + (7_279_000 as Weight) + // Standard Error: 5_000 + .saturating_add((5_388_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -278,9 +278,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (8_690_000 as Weight) - // Standard Error: 3_000 - .saturating_add((2_951_000 as Weight).saturating_mul(s as Weight)) + (8_619_000 as Weight) + // Standard Error: 4_000 + .saturating_add((2_969_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -288,9 +288,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (14_613_000 as Weight) - // Standard Error: 5_000 - .saturating_add((8_479_000 as Weight).saturating_mul(s as Weight)) + (16_129_000 as Weight) + // Standard Error: 7_000 + .saturating_add((9_772_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -298,9 +298,9 @@ impl WeightInfo for () { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (13_356_000 as Weight) - // Standard Error: 4_000 - .saturating_add((6_112_000 as Weight).saturating_mul(s as Weight)) + (15_785_000 as Weight) + // Standard Error: 5_000 + .saturating_add((7_208_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -309,33 +309,33 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (14_254_000 as Weight) + (15_778_000 as Weight) // Standard Error: 3_000 - .saturating_add((4_529_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((5_597_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (13_680_000 as Weight) - // Standard Error: 4_000 - .saturating_add((3_559_000 as Weight).saturating_mul(s as Weight)) + (15_912_000 as Weight) + // Standard Error: 5_000 + .saturating_add((4_530_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (14_821_000 as Weight) + (18_013_000 as Weight) // Standard Error: 1_000 - .saturating_add((85_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((87_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (15_029_000 as Weight) + (18_131_000 as Weight) // Standard Error: 1_000 .saturating_add((595_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) @@ -344,18 +344,18 @@ impl WeightInfo for () { // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (17_498_000 as Weight) + (21_230_000 as Weight) // Standard Error: 1_000 - .saturating_add((102_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((98_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (16_695_000 as Weight) + (20_139_000 as Weight) // Standard Error: 1_000 - .saturating_add((610_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((595_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index eabb26dcb32f4..40ae7f1be4265 100644 --- a/frame/session/src/weights.rs +++ b/frame/session/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_session //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -55,7 +55,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - (43_230_000 as Weight) + (48_484_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -63,7 +63,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - (33_000_000 as Weight) + (38_003_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -75,7 +75,7 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - (43_230_000 as Weight) + (48_484_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -83,7 +83,7 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - (33_000_000 as Weight) + (38_003_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index e7f2e06e6dd07..1bdfb01bddc86 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -86,7 +86,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (38_923_000 as Weight) + (43_992_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -96,7 +96,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (68_860_000 as Weight) + (75_827_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -110,7 +110,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (74_815_000 as Weight) + (81_075_000 as Weight) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -119,7 +119,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (30_797_000 as Weight) + (35_763_000 as Weight) // Standard Error: 0 .saturating_add((57_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) @@ -139,7 +139,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (60_515_000 as Weight) + (66_938_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(11 as Weight)) } @@ -155,16 +155,16 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (48_461_000 as Weight) + (52_943_000 as Weight) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (18_839_000 as Weight) + (23_264_000 as Weight) // Standard Error: 11_000 - .saturating_add((7_658_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((8_006_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -181,9 +181,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (51_547_000 as Weight) - // Standard Error: 10_000 - .saturating_add((3_610_000 as Weight).saturating_mul(n as Weight)) + (56_596_000 as Weight) + // Standard Error: 14_000 + .saturating_add((3_644_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(6 as Weight)) @@ -196,49 +196,49 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (45_828_000 as Weight) + (51_117_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (7_646_000 as Weight) + (11_223_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (15_974_000 as Weight) + (19_826_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (1_248_000 as Weight) + (3_789_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (1_350_000 as Weight) + (3_793_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (1_276_000 as Weight) + (3_802_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (1_321_000 as Weight) + (3_762_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (1_517_000 as Weight) + (4_318_000 as Weight) // Standard Error: 0 - .saturating_add((9_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((10_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) @@ -255,18 +255,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (58_451_000 as Weight) + (65_265_000 as Weight) // Standard Error: 1_000 - .saturating_add((835_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_029_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (895_257_000 as Weight) + (903_312_000 as Weight) // Standard Error: 56_000 - .saturating_add((4_978_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((4_968_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -281,9 +281,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (71_290_000 as Weight) - // Standard Error: 12_000 - .saturating_add((23_818_000 as Weight).saturating_mul(n as Weight)) + (87_569_000 as Weight) + // Standard Error: 14_000 + .saturating_add((24_232_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -301,9 +301,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (86_724_000 as Weight) - // Standard Error: 29_000 - .saturating_add((33_575_000 as Weight).saturating_mul(n as Weight)) + (98_839_000 as Weight) + // Standard Error: 21_000 + .saturating_add((34_480_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -316,9 +316,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (68_577_000 as Weight) + (74_865_000 as Weight) // Standard Error: 3_000 - .saturating_add((55_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((64_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(9 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } @@ -333,8 +333,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 58_000 - .saturating_add((20_425_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 62_000 + .saturating_add((22_829_000 as Weight).saturating_mul(e as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) .saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -353,9 +353,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (63_865_000 as Weight) - // Standard Error: 0 - .saturating_add((839_000 as Weight).saturating_mul(s as Weight)) + (70_933_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_021_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -380,10 +380,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 881_000 - .saturating_add((211_756_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 44_000 - .saturating_add((30_413_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 897_000 + .saturating_add((213_100_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 45_000 + .saturating_add((31_123_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(208 as Weight)) .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -400,12 +400,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Ledger (r:1500 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 86_000 - .saturating_add((23_814_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 86_000 - .saturating_add((21_657_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 2_924_000 - .saturating_add((19_067_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 116_000 + .saturating_add((23_745_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 116_000 + .saturating_add((22_497_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 3_968_000 + .saturating_add((20_676_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(202 as Weight)) .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -414,8 +414,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 32_000 - .saturating_add((7_861_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 36_000 + .saturating_add((8_097_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -426,7 +426,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - (3_688_000 as Weight) + (7_041_000 as Weight) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking MinCommission (r:0 w:1) @@ -436,7 +436,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - (3_414_000 as Weight) + (6_495_000 as Weight) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -450,14 +450,14 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (56_962_000 as Weight) + (62_014_000 as Weight) .saturating_add(T::DbWeight::get().reads(11 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - (9_465_000 as Weight) + (12_814_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -472,7 +472,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (38_923_000 as Weight) + (43_992_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -482,7 +482,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (68_860_000 as Weight) + (75_827_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } @@ -496,7 +496,7 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (74_815_000 as Weight) + (81_075_000 as Weight) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -505,7 +505,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (30_797_000 as Weight) + (35_763_000 as Weight) // Standard Error: 0 .saturating_add((57_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) @@ -525,7 +525,7 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (60_515_000 as Weight) + (66_938_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } @@ -541,16 +541,16 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (48_461_000 as Weight) + (52_943_000 as Weight) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (18_839_000 as Weight) + (23_264_000 as Weight) // Standard Error: 11_000 - .saturating_add((7_658_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((8_006_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) @@ -567,9 +567,9 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (51_547_000 as Weight) - // Standard Error: 10_000 - .saturating_add((3_610_000 as Weight).saturating_mul(n as Weight)) + (56_596_000 as Weight) + // Standard Error: 14_000 + .saturating_add((3_644_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) @@ -582,49 +582,49 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (45_828_000 as Weight) + (51_117_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (7_646_000 as Weight) + (11_223_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (15_974_000 as Weight) + (19_826_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (1_248_000 as Weight) + (3_789_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (1_350_000 as Weight) + (3_793_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (1_276_000 as Weight) + (3_802_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (1_321_000 as Weight) + (3_762_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (1_517_000 as Weight) + (4_318_000 as Weight) // Standard Error: 0 - .saturating_add((9_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((10_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Staking Bonded (r:1 w:1) @@ -641,18 +641,18 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (58_451_000 as Weight) + (65_265_000 as Weight) // Standard Error: 1_000 - .saturating_add((835_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((1_029_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (895_257_000 as Weight) + (903_312_000 as Weight) // Standard Error: 56_000 - .saturating_add((4_978_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((4_968_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -667,9 +667,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (71_290_000 as Weight) - // Standard Error: 12_000 - .saturating_add((23_818_000 as Weight).saturating_mul(n as Weight)) + (87_569_000 as Weight) + // Standard Error: 14_000 + .saturating_add((24_232_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -687,9 +687,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (86_724_000 as Weight) - // Standard Error: 29_000 - .saturating_add((33_575_000 as Weight).saturating_mul(n as Weight)) + (98_839_000 as Weight) + // Standard Error: 21_000 + .saturating_add((34_480_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -702,9 +702,9 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (68_577_000 as Weight) + (74_865_000 as Weight) // Standard Error: 3_000 - .saturating_add((55_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((64_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(9 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } @@ -719,8 +719,8 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 58_000 - .saturating_add((20_425_000 as Weight).saturating_mul(e as Weight)) + // Standard Error: 62_000 + .saturating_add((22_829_000 as Weight).saturating_mul(e as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) .saturating_add(RocksDbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) @@ -739,9 +739,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (63_865_000 as Weight) - // Standard Error: 0 - .saturating_add((839_000 as Weight).saturating_mul(s as Weight)) + (70_933_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_021_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -766,10 +766,10 @@ impl WeightInfo for () { // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { (0 as Weight) - // Standard Error: 881_000 - .saturating_add((211_756_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 44_000 - .saturating_add((30_413_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 897_000 + .saturating_add((213_100_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 45_000 + .saturating_add((31_123_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(208 as Weight)) .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -786,12 +786,12 @@ impl WeightInfo for () { // Storage: Staking Ledger (r:1500 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { (0 as Weight) - // Standard Error: 86_000 - .saturating_add((23_814_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 86_000 - .saturating_add((21_657_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 2_924_000 - .saturating_add((19_067_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 116_000 + .saturating_add((23_745_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 116_000 + .saturating_add((22_497_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 3_968_000 + .saturating_add((20_676_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(202 as Weight)) .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) @@ -800,8 +800,8 @@ impl WeightInfo for () { // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { (0 as Weight) - // Standard Error: 32_000 - .saturating_add((7_861_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 36_000 + .saturating_add((8_097_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } @@ -812,7 +812,7 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - (3_688_000 as Weight) + (7_041_000 as Weight) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking MinCommission (r:0 w:1) @@ -822,7 +822,7 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - (3_414_000 as Weight) + (6_495_000 as Weight) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -836,14 +836,14 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (56_962_000 as Weight) + (62_014_000 as Weight) .saturating_add(RocksDbWeight::get().reads(11 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - (9_465_000 as Weight) + (12_814_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs index f08b115378f21..f2566f949c058 100644 --- a/frame/state-trie-migration/src/weights.rs +++ b/frame/state-trie-migration/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_state_trie_migration //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-03-04, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -31,9 +32,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/state-trie-migration/src/weights.rs // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/state-trie-migration/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,32 +56,33 @@ pub trait WeightInfo { /// Weights for pallet_state_trie_migration using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { + // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) // Storage: StateTrieMigration MigrationProcess (r:1 w:1) fn continue_migrate() -> Weight { - (13_385_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + (19_019_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - // Storage: StateTrieMigration MigrationProcess (r:1 w:0) + // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) fn continue_migrate_wrong_witness() -> Weight { - (1_757_000 as Weight) + (1_874_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } fn migrate_custom_top_success() -> Weight { - (12_813_000 as Weight) + (16_381_000 as Weight) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_top_fail() -> Weight { - (24_961_000 as Weight) + (25_966_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn migrate_custom_child_success() -> Weight { - (13_132_000 as Weight) + (16_712_000 as Weight) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_child_fail() -> Weight { - (29_215_000 as Weight) + (29_885_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -97,32 +98,33 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { + // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) // Storage: StateTrieMigration MigrationProcess (r:1 w:1) fn continue_migrate() -> Weight { - (13_385_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + (19_019_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - // Storage: StateTrieMigration MigrationProcess (r:1 w:0) + // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) fn continue_migrate_wrong_witness() -> Weight { - (1_757_000 as Weight) + (1_874_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } fn migrate_custom_top_success() -> Weight { - (12_813_000 as Weight) + (16_381_000 as Weight) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_top_fail() -> Weight { - (24_961_000 as Weight) + (25_966_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn migrate_custom_child_success() -> Weight { - (13_132_000 as Weight) + (16_712_000 as Weight) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_child_fail() -> Weight { - (29_215_000 as Weight) + (29_885_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index b09ef126ac6dd..ad52ca48f68c9 100644 --- a/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -127,6 +127,19 @@ pub fn expand_outer_dispatch( } } } + impl #scrate::traits::DispatchableWithStorageLayer for Call { + type Origin = Origin; + fn dispatch_with_storage_layer(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { + #scrate::storage::with_storage_layer(|| { + #scrate::dispatch::Dispatchable::dispatch(self, origin) + }) + } + fn dispatch_bypass_filter_with_storage_layer(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { + #scrate::storage::with_storage_layer(|| { + #scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(self, origin) + }) + } + } #( impl #scrate::traits::IsSubType<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for Call { diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index f8aaa5fe37749..00204b7a4d906 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -433,6 +433,12 @@ pub fn transactional(attr: TokenStream, input: TokenStream) -> TokenStream { transactional::transactional(attr, input).unwrap_or_else(|e| e.to_compile_error().into()) } +#[proc_macro_attribute] +pub fn require_transactional(attr: TokenStream, input: TokenStream) -> TokenStream { + transactional::require_transactional(attr, input) + .unwrap_or_else(|e| e.to_compile_error().into()) +} + /// Derive [`Clone`] but do not bound any generic. Docs are at `frame_support::CloneNoBound`. #[proc_macro_derive(CloneNoBound)] pub fn derive_clone_no_bound(input: TokenStream) -> TokenStream { @@ -510,12 +516,6 @@ pub fn derive_default_no_bound(input: TokenStream) -> TokenStream { default_no_bound::derive_default_no_bound(input) } -#[proc_macro_attribute] -pub fn require_transactional(attr: TokenStream, input: TokenStream) -> TokenStream { - transactional::require_transactional(attr, input) - .unwrap_or_else(|e| e.to_compile_error().into()) -} - #[proc_macro] pub fn crate_to_crate_version(input: TokenStream) -> TokenStream { crate_version::crate_to_crate_version(input) diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index ac52463b8aab6..a5038ec399e2b 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -267,8 +267,12 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::sp_tracing::enter_span!( #frame_support::sp_tracing::trace_span!(stringify!(#fn_name)) ); - <#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* ) - .map(Into::into).map_err(Into::into) + // We execute all dispatchable in at least one storage layer, allowing them + // to return an error at any point, and undoing any storage changes. + #frame_support::storage::in_storage_layer(|| { + <#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* ) + .map(Into::into).map_err(Into::into) + }) }, )* Self::__Ignore(_, _) => { diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 7ccf796167297..51504c9c36e38 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -27,7 +27,8 @@ pub use crate::{ result, }, traits::{ - CallMetadata, GetCallMetadata, GetCallName, GetStorageVersion, UnfilteredDispatchable, + CallMetadata, DispatchableWithStorageLayer, GetCallMetadata, GetCallName, + GetStorageVersion, UnfilteredDispatchable, }, weights::{ ClassifyDispatch, DispatchInfo, GetDispatchInfo, PaysFee, PostDispatchInfo, @@ -1469,7 +1470,11 @@ macro_rules! decl_module { $ignore:ident $mod_type:ident<$trait_instance:ident $(, $instance:ident)?> $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] ) => { - <$mod_type<$trait_instance $(, $instance)?>>::$fn_name( $origin $(, $param_name )* ).map(Into::into).map_err(Into::into) + // We execute all dispatchable in at least one storage layer, allowing them + // to return an error at any point, and undoing any storage changes. + $crate::storage::in_storage_layer(|| { + <$mod_type<$trait_instance $(, $instance)?>>::$fn_name( $origin $(, $param_name )* ).map(Into::into).map_err(Into::into) + }) }; // no `deposit_event` function wanted diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 7135ead850b6d..7a960776fc755 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -30,7 +30,9 @@ use sp_runtime::generic::{Digest, DigestItem}; use sp_std::prelude::*; pub use self::{ - transactional::{with_transaction, with_transaction_unchecked}, + transactional::{ + in_storage_layer, with_storage_layer, with_transaction, with_transaction_unchecked, + }, types::StorageEntryMetadataBuilder, }; pub use sp_runtime::TransactionOutcome; diff --git a/frame/support/src/storage/transactional.rs b/frame/support/src/storage/transactional.rs index c46eb9258e0ca..b02552bdb0e14 100644 --- a/frame/support/src/storage/transactional.rs +++ b/frame/support/src/storage/transactional.rs @@ -158,6 +158,40 @@ pub fn with_transaction_unchecked(f: impl FnOnce() -> TransactionOutcome) } } +/// Execute the supplied function, adding a new storage layer. +/// +/// This is the same as `with_transaction`, but assuming that any function returning +/// an `Err` should rollback, and any function returning `Ok` should commit. This +/// provides a cleaner API to the developer who wants this behavior. +pub fn with_storage_layer(f: impl FnOnce() -> Result) -> Result +where + E: From, +{ + with_transaction(|| { + let r = f(); + if r.is_ok() { + TransactionOutcome::Commit(r) + } else { + TransactionOutcome::Rollback(r) + } + }) +} + +/// Execute the supplied function, ensuring we are at least in one storage layer. +/// +/// If we are already in a storage layer, we just execute the provided closure. +/// If we are not, we execute the closure within a [`with_storage_layer`]. +pub fn in_storage_layer(f: impl FnOnce() -> Result) -> Result +where + E: From, +{ + if is_transactional() { + f() + } else { + with_storage_layer(f) + } +} + #[cfg(test)] mod tests { use super::*; @@ -229,4 +263,33 @@ mod tests { assert_eq!(get_transaction_level(), 0); }); } + + #[test] + fn in_storage_layer_works() { + TestExternalities::default().execute_with(|| { + assert_eq!(get_transaction_level(), 0); + + let res = in_storage_layer(|| -> DispatchResult { + assert_eq!(get_transaction_level(), 1); + in_storage_layer(|| -> DispatchResult { + // We are still in the same layer :) + assert_eq!(get_transaction_level(), 1); + Ok(()) + }) + }); + + assert_ok!(res); + + let res = in_storage_layer(|| -> DispatchResult { + assert_eq!(get_transaction_level(), 1); + in_storage_layer(|| -> DispatchResult { + // We are still in the same layer :) + assert_eq!(get_transaction_level(), 1); + Err("epic fail".into()) + }) + }); + + assert_noop!(res, "epic fail"); + }); + } } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index edeb7fead7c84..a6fc88dfb5e76 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -94,8 +94,8 @@ pub use storage::{ mod dispatch; pub use dispatch::{ - AsEnsureOriginWithArg, EnsureOneOf, EnsureOrigin, EnsureOriginWithArg, OriginTrait, - UnfilteredDispatchable, + AsEnsureOriginWithArg, DispatchableWithStorageLayer, EnsureOneOf, EnsureOrigin, + EnsureOriginWithArg, OriginTrait, UnfilteredDispatchable, }; mod voting; diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 443941bd8d771..1cec6cf837aba 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -101,6 +101,23 @@ pub trait UnfilteredDispatchable { fn dispatch_bypass_filter(self, origin: Self::Origin) -> DispatchResultWithPostInfo; } +/// Type that can be dispatched with an additional storage layer which is used to execute the call. +pub trait DispatchableWithStorageLayer { + /// The origin type of the runtime, (i.e. `frame_system::Config::Origin`). + type Origin; + + /// Same as `dispatch` from the [`frame_support::dispatch::Dispatchable`] trait, but + /// specifically spawns a new storage layer to execute the call inside of. + fn dispatch_with_storage_layer(self, origin: Self::Origin) -> DispatchResultWithPostInfo; + + /// Same as `dispatch_bypass_filter` from the [`UnfilteredDispatchable`] trait, but specifically + /// spawns a new storage layer to execute the call inside of. + fn dispatch_bypass_filter_with_storage_layer( + self, + origin: Self::Origin, + ) -> DispatchResultWithPostInfo; +} + /// Methods available on `frame_system::Config::Origin`. pub trait OriginTrait: Sized { /// Runtime call type, as in `frame_system::Config::Call` diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index d1d5f8320d104..b86334514af2f 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -16,7 +16,7 @@ // limitations under the License. //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23 (Y/M/D) +//! DATE: 2022-05-24 (Y/M/D) //! //! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` @@ -27,7 +27,7 @@ // ./target/production/substrate // benchmark // overhead -// --dev +// --chain=dev // --execution=wasm // --wasm-execution=compiled // --weight-path=./frame/support/src/weights/ @@ -44,16 +44,16 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 5_295_788, 5_473_440 - /// Average: 5_343_308 - /// Median: 5_323_240 - /// Std-Dev: 38368.68 + /// Min, Max: 5_303_128, 5_507_784 + /// Average: 5_346_284 + /// Median: 5_328_139 + /// Std-Dev: 41749.5 /// /// Percentiles nanoseconds: - /// 99th: 5_470_141 - /// 95th: 5_418_269 - /// 75th: 5_355_579 - pub const BlockExecutionWeight: Weight = 5_343_308 * WEIGHT_PER_NANOS; + /// 99th: 5_489_273 + /// 95th: 5_433_314 + /// 75th: 5_354_812 + pub const BlockExecutionWeight: Weight = 5_346_284 * WEIGHT_PER_NANOS; } #[cfg(test)] diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 1a5a4e7a460c0..b8a52c164d8fe 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -16,7 +16,7 @@ // limitations under the License. //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23 (Y/M/D) +//! DATE: 2022-05-24 (Y/M/D) //! //! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` @@ -27,7 +27,7 @@ // ./target/production/substrate // benchmark // overhead -// --dev +// --chain=dev // --execution=wasm // --wasm-execution=compiled // --weight-path=./frame/support/src/weights/ @@ -44,16 +44,16 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 85_423, 86_142 - /// Average: 85_795 - /// Median: 85_790 - /// Std-Dev: 162.37 + /// Min, Max: 86_060, 86_999 + /// Average: 86_298 + /// Median: 86_248 + /// Std-Dev: 207.19 /// /// Percentiles nanoseconds: - /// 99th: 86_115 - /// 95th: 86_069 - /// 75th: 85_937 - pub const ExtrinsicBaseWeight: Weight = 85_795 * WEIGHT_PER_NANOS; + /// 99th: 86_924 + /// 95th: 86_828 + /// 75th: 86_347 + pub const ExtrinsicBaseWeight: Weight = 86_298 * WEIGHT_PER_NANOS; } #[cfg(test)] diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 792fd93299705..b81941c45ff46 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -205,8 +205,7 @@ pub mod pallet { /// Doc comment put in metadata #[pallet::weight(1)] - #[frame_support::transactional] - pub fn foo_transactional( + pub fn foo_storage_layer( _origin: OriginFor, #[pallet::compact] foo: u32, ) -> DispatchResultWithPostInfo { @@ -373,7 +372,7 @@ pub mod pallet { fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { let _ = T::AccountId::from(SomeType1); // Test for where clause let _ = T::AccountId::from(SomeType5); // Test for where clause - if matches!(call, Call::foo_transactional { .. }) { + if matches!(call, Call::foo_storage_layer { .. }) { return Ok(ValidTransaction::default()) } Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) @@ -611,13 +610,13 @@ fn transactional_works() { TestExternalities::default().execute_with(|| { frame_system::Pallet::::set_block_number(1); - pallet::Call::::foo_transactional { foo: 0 } + pallet::Call::::foo_storage_layer { foo: 0 } .dispatch_bypass_filter(None.into()) .err() .unwrap(); assert!(frame_system::Pallet::::events().is_empty()); - pallet::Call::::foo_transactional { foo: 1 } + pallet::Call::::foo_storage_layer { foo: 1 } .dispatch_bypass_filter(None.into()) .unwrap(); assert_eq!( @@ -640,7 +639,7 @@ fn call_expand() { assert_eq!(call_foo.get_call_name(), "foo"); assert_eq!( pallet::Call::::get_call_names(), - &["foo", "foo_transactional", "foo_no_post_info"], + &["foo", "foo_storage_layer", "foo_no_post_info"], ); } @@ -744,7 +743,7 @@ fn inherent_expand() { Digest::default(), ), vec![UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_transactional { foo: 0 }), + function: Call::Example(pallet::Call::foo_storage_layer { foo: 0 }), signature: None, }], ); @@ -785,7 +784,7 @@ fn inherent_expand() { signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_transactional { foo: 0 }), + function: Call::Example(pallet::Call::foo_storage_layer { foo: 0 }), signature: None, }, ], @@ -807,7 +806,7 @@ fn inherent_expand() { signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_transactional { foo: 0 }), + function: Call::Example(pallet::Call::foo_storage_layer { foo: 0 }), signature: None, }, UncheckedExtrinsic { @@ -857,7 +856,7 @@ fn validate_unsigned_expand() { let validity = pallet::Pallet::validate_unsigned(TransactionSource::Local, &call).unwrap_err(); assert_eq!(validity, TransactionValidityError::Invalid(InvalidTransaction::Call)); - let call = pallet::Call::::foo_transactional { foo: 0 }; + let call = pallet::Call::::foo_storage_layer { foo: 0 }; let validity = pallet::Pallet::validate_unsigned(TransactionSource::External, &call).unwrap(); assert_eq!(validity, ValidTransaction::default()); diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 29074843f4bbb..d716637f82895 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -93,8 +93,7 @@ pub mod pallet { /// Doc comment put in metadata #[pallet::weight(1)] - #[frame_support::transactional] - pub fn foo_transactional( + pub fn foo_storage_layer( origin: OriginFor, #[pallet::compact] _foo: u32, ) -> DispatchResultWithPostInfo { @@ -316,7 +315,7 @@ fn call_expand() { DispatchInfo { weight: 3, class: DispatchClass::Normal, pays_fee: Pays::Yes } ); assert_eq!(call_foo.get_call_name(), "foo"); - assert_eq!(pallet::Call::::get_call_names(), &["foo", "foo_transactional"]); + assert_eq!(pallet::Call::::get_call_names(), &["foo", "foo_storage_layer"]); let call_foo = pallet::Call::::foo { foo: 3 }; assert_eq!( @@ -326,7 +325,7 @@ fn call_expand() { assert_eq!(call_foo.get_call_name(), "foo"); assert_eq!( pallet::Call::::get_call_names(), - &["foo", "foo_transactional"], + &["foo", "foo_storage_layer"], ); } diff --git a/frame/support/test/tests/storage_layers.rs b/frame/support/test/tests/storage_layers.rs new file mode 100644 index 0000000000000..05ed60fe90196 --- /dev/null +++ b/frame/support/test/tests/storage_layers.rs @@ -0,0 +1,280 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_support::{ + assert_noop, assert_ok, dispatch::DispatchResult, pallet_prelude::ConstU32, + storage::with_storage_layer, +}; +use pallet::*; +use sp_io::TestExternalities; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::{ensure, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::storage] + pub type Value = StorageValue<_, u32, ValueQuery>; + + #[pallet::storage] + pub type Map = StorageMap<_, Blake2_128Concat, u32, u32, ValueQuery>; + + #[pallet::error] + pub enum Error { + Revert, + } + + #[pallet::call] + impl Pallet { + #[pallet::weight(1)] + pub fn set_value(_origin: OriginFor, value: u32) -> DispatchResult { + Value::::put(value); + ensure!(value != 1, Error::::Revert); + Ok(()) + } + } +} + +pub mod decl_pallet { + pub trait Config: frame_system::Config {} + + frame_support::decl_module! { + pub struct Module for enum Call where origin: T::Origin { + #[weight = 0] + pub fn set_value(_origin, value: u32) { + DeclValue::put(value); + frame_support::ensure!(value != 1, "Revert!"); + } + } + } + + frame_support::decl_storage! { + trait Store for Module as StorageTransactions { + pub DeclValue: u32; + } + } +} + +pub type BlockNumber = u64; +pub type Index = u64; +pub type Header = sp_runtime::generic::Header; +pub type Block = sp_runtime::generic::Block; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; + +impl frame_system::Config for Runtime { + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type BaseCallFilter = frame_support::traits::Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u32; + type Call = Call; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = ConstU32<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet::Config for Runtime {} + +impl decl_pallet::Config for Runtime {} + +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system, + MyPallet: pallet, + DeclPallet: decl_pallet::{Call, Storage}, + } +); + +#[test] +fn storage_layer_basic_commit() { + TestExternalities::default().execute_with(|| { + assert_eq!(Value::::get(), 0); + assert!(!Map::::contains_key(0)); + + assert_ok!(with_storage_layer(|| -> DispatchResult { + Value::::set(99); + Map::::insert(0, 99); + assert_eq!(Value::::get(), 99); + assert_eq!(Map::::get(0), 99); + Ok(()) + })); + + assert_eq!(Value::::get(), 99); + assert_eq!(Map::::get(0), 99); + }); +} + +#[test] +fn storage_layer_basic_rollback() { + TestExternalities::default().execute_with(|| { + assert_eq!(Value::::get(), 0); + assert_eq!(Map::::get(0), 0); + + assert_noop!( + with_storage_layer(|| -> DispatchResult { + Value::::set(99); + Map::::insert(0, 99); + assert_eq!(Value::::get(), 99); + assert_eq!(Map::::get(0), 99); + Err("revert".into()) + }), + "revert" + ); + + assert_eq!(Value::::get(), 0); + assert_eq!(Map::::get(0), 0); + }); +} + +#[test] +fn storage_layer_rollback_then_commit() { + TestExternalities::default().execute_with(|| { + Value::::set(1); + Map::::insert(1, 1); + + assert_ok!(with_storage_layer(|| -> DispatchResult { + Value::::set(2); + Map::::insert(1, 2); + Map::::insert(2, 2); + + assert_noop!( + with_storage_layer(|| -> DispatchResult { + Value::::set(3); + Map::::insert(1, 3); + Map::::insert(2, 3); + Map::::insert(3, 3); + + assert_eq!(Value::::get(), 3); + assert_eq!(Map::::get(1), 3); + assert_eq!(Map::::get(2), 3); + assert_eq!(Map::::get(3), 3); + + Err("revert".into()) + }), + "revert" + ); + + assert_eq!(Value::::get(), 2); + assert_eq!(Map::::get(1), 2); + assert_eq!(Map::::get(2), 2); + assert_eq!(Map::::get(3), 0); + + Ok(()) + })); + + assert_eq!(Value::::get(), 2); + assert_eq!(Map::::get(1), 2); + assert_eq!(Map::::get(2), 2); + assert_eq!(Map::::get(3), 0); + }); +} + +#[test] +fn storage_layer_commit_then_rollback() { + TestExternalities::default().execute_with(|| { + Value::::set(1); + Map::::insert(1, 1); + + assert_noop!( + with_storage_layer(|| -> DispatchResult { + Value::::set(2); + Map::::insert(1, 2); + Map::::insert(2, 2); + + assert_ok!(with_storage_layer(|| -> DispatchResult { + Value::::set(3); + Map::::insert(1, 3); + Map::::insert(2, 3); + Map::::insert(3, 3); + + assert_eq!(Value::::get(), 3); + assert_eq!(Map::::get(1), 3); + assert_eq!(Map::::get(2), 3); + assert_eq!(Map::::get(3), 3); + + Ok(()) + })); + + assert_eq!(Value::::get(), 3); + assert_eq!(Map::::get(1), 3); + assert_eq!(Map::::get(2), 3); + assert_eq!(Map::::get(3), 3); + + Err("revert".into()) + }), + "revert" + ); + + assert_eq!(Value::::get(), 1); + assert_eq!(Map::::get(1), 1); + assert_eq!(Map::::get(2), 0); + assert_eq!(Map::::get(3), 0); + }); +} + +#[test] +fn storage_layer_in_pallet_call() { + TestExternalities::default().execute_with(|| { + use sp_runtime::traits::Dispatchable; + let call1 = Call::MyPallet(pallet::Call::set_value { value: 2 }); + assert_ok!(call1.dispatch(Origin::signed(0))); + assert_eq!(Value::::get(), 2); + + let call2 = Call::MyPallet(pallet::Call::set_value { value: 1 }); + assert_noop!(call2.dispatch(Origin::signed(0)), Error::::Revert); + }); +} + +#[test] +fn storage_layer_in_decl_pallet_call() { + TestExternalities::default().execute_with(|| { + use frame_support::StorageValue; + use sp_runtime::traits::Dispatchable; + + let call1 = Call::DeclPallet(decl_pallet::Call::set_value { value: 2 }); + assert_ok!(call1.dispatch(Origin::signed(0))); + assert_eq!(decl_pallet::DeclValue::get(), 2); + + let call2 = Call::DeclPallet(decl_pallet::Call::set_value { value: 1 }); + assert_noop!(call2.dispatch(Origin::signed(0)), "Revert!"); + }); +} diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index 813183ecce188..bdd2d64b2118b 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for frame_system //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -66,29 +66,29 @@ impl WeightInfo for SubstrateWeight { // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (3_235_000 as Weight) + (5_453_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn set_storage(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 0 - .saturating_add((407_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 1_000 + .saturating_add((600_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_storage(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 0 - .saturating_add((307_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 1_000 + .saturating_add((510_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_prefix(p: u32, ) -> Weight { (0 as Weight) - // Standard Error: 0 - .saturating_add((672_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 1_000 + .saturating_add((916_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } } @@ -106,29 +106,29 @@ impl WeightInfo for () { // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (3_235_000 as Weight) + (5_453_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) fn set_storage(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 0 - .saturating_add((407_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 1_000 + .saturating_add((600_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_storage(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 0 - .saturating_add((307_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 1_000 + .saturating_add((510_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_prefix(p: u32, ) -> Weight { (0 as Weight) - // Standard Error: 0 - .saturating_add((672_000 as Weight).saturating_mul(p as Weight)) + // Standard Error: 1_000 + .saturating_add((916_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } } diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index 7c130d69c51d6..6b4ebfa74dd87 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_timestamp //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -54,12 +54,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - (5_490_000 as Weight) + (8_080_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (2_618_000 as Weight) + (2_681_000 as Weight) } } @@ -68,11 +68,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - (5_490_000 as Weight) + (8_080_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (2_618_000 as Weight) + (2_681_000 as Weight) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 9e49dce410ef8..4979618473fd1 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_tips //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -58,16 +58,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - (26_613_000 as Weight) + (30_669_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - (25_001_000 as Weight) + (28_768_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -75,20 +75,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - (17_490_000 as Weight) + (20_385_000 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 5_000 - .saturating_add((183_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 3_000 + .saturating_add((166_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - (9_634_000 as Weight) - // Standard Error: 7_000 - .saturating_add((343_000 as Weight).saturating_mul(t as Weight)) + (12_287_000 as Weight) + // Standard Error: 6_000 + .saturating_add((363_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -97,18 +97,18 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - (41_967_000 as Weight) - // Standard Error: 10_000 - .saturating_add((264_000 as Weight).saturating_mul(t as Weight)) + (45_656_000 as Weight) + // Standard Error: 14_000 + .saturating_add((276_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - (14_917_000 as Weight) - // Standard Error: 4_000 - .saturating_add((61_000 as Weight).saturating_mul(t as Weight)) + (18_525_000 as Weight) + // Standard Error: 5_000 + .saturating_add((37_000 as Weight).saturating_mul(t as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -119,16 +119,16 @@ impl WeightInfo for () { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - (26_613_000 as Weight) + (30_669_000 as Weight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - (25_001_000 as Weight) + (28_768_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -136,20 +136,20 @@ impl WeightInfo for () { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - (17_490_000 as Weight) + (20_385_000 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 5_000 - .saturating_add((183_000 as Weight).saturating_mul(t as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 3_000 + .saturating_add((166_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - (9_634_000 as Weight) - // Standard Error: 7_000 - .saturating_add((343_000 as Weight).saturating_mul(t as Weight)) + (12_287_000 as Weight) + // Standard Error: 6_000 + .saturating_add((363_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -158,18 +158,18 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - (41_967_000 as Weight) - // Standard Error: 10_000 - .saturating_add((264_000 as Weight).saturating_mul(t as Weight)) + (45_656_000 as Weight) + // Standard Error: 14_000 + .saturating_add((276_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - (14_917_000 as Weight) - // Standard Error: 4_000 - .saturating_add((61_000 as Weight).saturating_mul(t as Weight)) + (18_525_000 as Weight) + // Standard Error: 5_000 + .saturating_add((37_000 as Weight).saturating_mul(t as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index 8063783b4cc22..b8bc4890a416e 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_transaction_storage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -72,7 +72,7 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - (45_011_000 as Weight) + (50_978_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -82,7 +82,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - (98_295_000 as Weight) + (106_990_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -110,7 +110,7 @@ impl WeightInfo for () { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - (45_011_000 as Weight) + (50_978_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -120,7 +120,7 @@ impl WeightInfo for () { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - (98_295_000 as Weight) + (106_990_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index 4ae82d3b230d2..f1667bea35480 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_treasury //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -57,29 +57,29 @@ impl WeightInfo for SubstrateWeight { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (22_397_000 as Weight) + (26_473_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (26_004_000 as Weight) + (29_955_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (7_415_000 as Weight) + (10_786_000 as Weight) // Standard Error: 0 - .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((110_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Treasury Approvals (r:1 w:1) fn remove_approval() -> Weight { - (3_827_000 as Weight) + (6_647_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -88,9 +88,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (25_129_000 as Weight) - // Standard Error: 16_000 - .saturating_add((28_612_000 as Weight).saturating_mul(p as Weight)) + (25_805_000 as Weight) + // Standard Error: 18_000 + .saturating_add((28_473_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -103,29 +103,29 @@ impl WeightInfo for () { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (22_397_000 as Weight) + (26_473_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (26_004_000 as Weight) + (29_955_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (7_415_000 as Weight) + (10_786_000 as Weight) // Standard Error: 0 - .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((110_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Treasury Approvals (r:1 w:1) fn remove_approval() -> Weight { - (3_827_000 as Weight) + (6_647_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -134,9 +134,9 @@ impl WeightInfo for () { // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (25_129_000 as Weight) - // Standard Error: 16_000 - .saturating_add((28_612_000 as Weight).saturating_mul(p as Weight)) + (25_805_000 as Weight) + // Standard Error: 18_000 + .saturating_add((28_473_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 127e5ccbb12a3..6e0ac358d3cdd 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -76,14 +76,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (23_990_000 as Weight) + (28_225_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (13_472_000 as Weight) + (16_513_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -96,12 +96,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 13_000 - .saturating_add((9_507_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 13_000 - .saturating_add((912_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 13_000 - .saturating_add((801_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 15_000 + .saturating_add((10_527_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 15_000 + .saturating_add((1_505_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 15_000 + .saturating_add((1_401_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -114,7 +114,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (32_519_000 as Weight) + (35_712_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -122,7 +122,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (32_024_000 as Weight) + (35_740_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -130,7 +130,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (23_948_000 as Weight) + (27_425_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -138,8 +138,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_000 - .saturating_add((11_911_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 13_000 + .saturating_add((12_499_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -148,26 +148,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (18_448_000 as Weight) + (21_787_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (18_704_000 as Weight) + (21_938_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (13_925_000 as Weight) + (17_122_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (13_902_000 as Weight) + (17_188_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -175,20 +175,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (20_949_000 as Weight) + (24_539_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (14_531_000 as Weight) + (17_808_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (16_623_000 as Weight) + (20_251_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -196,7 +196,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (37_593_000 as Weight) + (41_106_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -204,62 +204,62 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (35_304_000 as Weight) + (40_049_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (29_353_000 as Weight) + (33_701_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (29_323_000 as Weight) + (33_733_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (28_806_000 as Weight) + (32_848_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (26_744_000 as Weight) + (30_232_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (19_485_000 as Weight) + (22_890_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (19_494_000 as Weight) + (22_845_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (17_456_000 as Weight) + (21_490_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (16_780_000 as Weight) + (19_412_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -270,14 +270,14 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (23_990_000 as Weight) + (28_225_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (13_472_000 as Weight) + (16_513_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -290,12 +290,12 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:20) fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 13_000 - .saturating_add((9_507_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 13_000 - .saturating_add((912_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 13_000 - .saturating_add((801_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 15_000 + .saturating_add((10_527_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 15_000 + .saturating_add((1_505_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 15_000 + .saturating_add((1_401_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -308,7 +308,7 @@ impl WeightInfo for () { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (32_519_000 as Weight) + (35_712_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -316,7 +316,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (32_024_000 as Weight) + (35_740_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -324,7 +324,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (23_948_000 as Weight) + (27_425_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -332,8 +332,8 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:100 w:100) fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_000 - .saturating_add((11_911_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 13_000 + .saturating_add((12_499_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -342,26 +342,26 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (18_448_000 as Weight) + (21_787_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (18_704_000 as Weight) + (21_938_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (13_925_000 as Weight) + (17_122_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (13_902_000 as Weight) + (17_188_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -369,20 +369,20 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (20_949_000 as Weight) + (24_539_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (14_531_000 as Weight) + (17_808_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (16_623_000 as Weight) + (20_251_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -390,7 +390,7 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (37_593_000 as Weight) + (41_106_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -398,62 +398,62 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (35_304_000 as Weight) + (40_049_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (29_353_000 as Weight) + (33_701_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (29_323_000 as Weight) + (33_733_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (28_806_000 as Weight) + (32_848_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (26_744_000 as Weight) + (30_232_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (19_485_000 as Weight) + (22_890_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (19_494_000 as Weight) + (22_845_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (17_456_000 as Weight) + (21_490_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (16_780_000 as Weight) + (19_412_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 9a8384f836f8b..0aae2615702dd 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -60,7 +60,6 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::PostDispatchInfo, traits::{IsSubType, OriginTrait, UnfilteredDispatchable}, - transactional, weights::{extract_actual_weight, GetDispatchInfo}, }; use sp_core::TypeId; @@ -316,7 +315,6 @@ pub mod pallet { }; (dispatch_weight, dispatch_class) })] - #[transactional] pub fn batch_all( origin: OriginFor, calls: Vec<::Call>, diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index f53459a707b54..6368473ac8708 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -471,11 +471,11 @@ fn batch_all_revert() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); + let batch_all_calls = Call::Utility(crate::Call::::batch_all { + calls: vec![call_transfer(2, 5), call_transfer(2, 10), call_transfer(2, 5)], + }); assert_noop!( - Utility::batch_all( - Origin::signed(1), - vec![call_transfer(2, 5), call_transfer(2, 10), call_transfer(2, 5),] - ), + batch_all_calls.dispatch(Origin::signed(1)), DispatchErrorWithPostInfo { post_info: PostDispatchInfo { actual_weight: Some( diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index d3cd7530c2584..035831918b1dc 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_utility //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -55,49 +55,49 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn batch(c: u32, ) -> Weight { - (14_744_000 as Weight) + (20_307_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_549_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_701_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (1_412_000 as Weight) + (4_082_000 as Weight) } fn batch_all(c: u32, ) -> Weight { - (20_835_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_704_000 as Weight).saturating_mul(c as Weight)) + (3_087_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_842_000 as Weight).saturating_mul(c as Weight)) } fn dispatch_as() -> Weight { - (8_889_000 as Weight) + (11_832_000 as Weight) } fn force_batch(c: u32, ) -> Weight { - (13_155_000 as Weight) + (19_750_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_555_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_715_000 as Weight).saturating_mul(c as Weight)) } } // For backwards compatibility and tests impl WeightInfo for () { fn batch(c: u32, ) -> Weight { - (14_744_000 as Weight) + (20_307_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_549_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_701_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (1_412_000 as Weight) + (4_082_000 as Weight) } fn batch_all(c: u32, ) -> Weight { - (20_835_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_704_000 as Weight).saturating_mul(c as Weight)) + (3_087_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_842_000 as Weight).saturating_mul(c as Weight)) } fn dispatch_as() -> Weight { - (8_889_000 as Weight) + (11_832_000 as Weight) } fn force_batch(c: u32, ) -> Weight { - (13_155_000 as Weight) + (19_750_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_555_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((2_715_000 as Weight).saturating_mul(c as Weight)) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index 356cd003d8848..4596157e63b7b 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_vesting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -60,22 +60,22 @@ impl WeightInfo for SubstrateWeight { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - (27_818_000 as Weight) + (32_978_000 as Weight) // Standard Error: 1_000 - .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((82_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((74_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((88_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - (27_708_000 as Weight) + (32_856_000 as Weight) // Standard Error: 1_000 .saturating_add((79_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -83,11 +83,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - (27_854_000 as Weight) + (33_522_000 as Weight) // Standard Error: 1_000 - .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((74_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((73_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((72_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -95,11 +95,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - (27_738_000 as Weight) + (32_558_000 as Weight) // Standard Error: 1_000 - .saturating_add((71_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((78_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((42_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((61_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -107,11 +107,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - (43_640_000 as Weight) + (49_260_000 as Weight) // Standard Error: 1_000 - .saturating_add((71_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((80_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 3_000 - .saturating_add((45_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -119,11 +119,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - (42_850_000 as Weight) - // Standard Error: 1_000 - .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 3_000 - .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + (49_166_000 as Weight) + // Standard Error: 2_000 + .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 4_000 + .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -131,11 +131,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (28_683_000 as Weight) + (34_042_000 as Weight) // Standard Error: 1_000 - .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((83_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((63_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((80_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -143,11 +143,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (28_510_000 as Weight) + (33_937_000 as Weight) // Standard Error: 1_000 - .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((78_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((65_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((73_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -158,22 +158,22 @@ impl WeightInfo for () { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - (27_818_000 as Weight) + (32_978_000 as Weight) // Standard Error: 1_000 - .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((82_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((74_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((88_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - (27_708_000 as Weight) + (32_856_000 as Weight) // Standard Error: 1_000 .saturating_add((79_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -181,11 +181,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - (27_854_000 as Weight) + (33_522_000 as Weight) // Standard Error: 1_000 - .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((74_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((73_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((72_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -193,11 +193,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - (27_738_000 as Weight) + (32_558_000 as Weight) // Standard Error: 1_000 - .saturating_add((71_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((78_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((42_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((61_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -205,11 +205,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - (43_640_000 as Weight) + (49_260_000 as Weight) // Standard Error: 1_000 - .saturating_add((71_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((80_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 3_000 - .saturating_add((45_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -217,11 +217,11 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - (42_850_000 as Weight) - // Standard Error: 1_000 - .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) - // Standard Error: 3_000 - .saturating_add((48_000 as Weight).saturating_mul(s as Weight)) + (49_166_000 as Weight) + // Standard Error: 2_000 + .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 4_000 + .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -229,11 +229,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (28_683_000 as Weight) + (34_042_000 as Weight) // Standard Error: 1_000 - .saturating_add((81_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((83_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((63_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((80_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -241,11 +241,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (28_510_000 as Weight) + (33_937_000 as Weight) // Standard Error: 1_000 - .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((78_000 as Weight).saturating_mul(l as Weight)) // Standard Error: 2_000 - .saturating_add((65_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((73_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index b074cbf00d40d..81482c35e3de8 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_whitelist //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -56,7 +56,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - (16_953_000 as Weight) + (20_938_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -64,7 +64,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn remove_whitelisted_call() -> Weight { - (18_515_000 as Weight) + (22_332_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -72,7 +72,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn dispatch_whitelisted_call() -> Weight { - (5_870_296_000 as Weight) + (5_989_917_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -80,7 +80,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - (21_179_000 as Weight) + (25_325_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) @@ -93,7 +93,7 @@ impl WeightInfo for () { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - (16_953_000 as Weight) + (20_938_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -101,7 +101,7 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn remove_whitelisted_call() -> Weight { - (18_515_000 as Weight) + (22_332_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -109,7 +109,7 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn dispatch_whitelisted_call() -> Weight { - (5_870_296_000 as Weight) + (5_989_917_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -117,7 +117,7 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - (21_179_000 as Weight) + (25_325_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) From 34703673f1097b7d78b0ae0e3c82638f00dc157e Mon Sep 17 00:00:00 2001 From: Denis Pisarev Date: Fri, 27 May 2022 10:44:57 +0200 Subject: [PATCH 0850/1472] CI: github no longer checks whitelisted actions this way (#11507) * CI: github no longer checks whitelisted actions this way * CI: actually this one is needed and no one knows it's related to a Markdown Link Check --- .github/allowed-actions.js | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .github/allowed-actions.js diff --git a/.github/allowed-actions.js b/.github/allowed-actions.js deleted file mode 100644 index 4fb894758060d..0000000000000 --- a/.github/allowed-actions.js +++ /dev/null @@ -1,7 +0,0 @@ -// This is a whitelist of GitHub Actions that are approved for use in this project. -// If a new or existing workflow file is updated to use an action or action version -// not listed here, CI will fail. - -module.exports = [ - 'gaurav-nelson/github-action-markdown-link-check@7481451f70251762f149d69596e3e276ebf2b236', // gaurav-nelson/github-action-markdown-link-check@v1.0.8 -] From fe5bf49290d166b9552f65e751d46ec592173ebd Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 27 May 2022 13:29:31 +0200 Subject: [PATCH 0851/1472] Fork-Tree import requires post-order DFS traversal (#11531) * Fork-tree insert requires post-order dfs traversal * Add dedicated test for methods requireing post-order traversal --- utils/fork-tree/src/lib.rs | 80 +++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/utils/fork-tree/src/lib.rs b/utils/fork-tree/src/lib.rs index ab56ecb6360b3..76c28d910f943 100644 --- a/utils/fork-tree/src/lib.rs +++ b/utils/fork-tree/src/lib.rs @@ -126,6 +126,11 @@ where /// imported in order. /// /// Returns `true` if the imported node is a root. + // WARNING: some users of this method (i.e. consensus epoch changes tree) currently silently + // rely on a **post-order DFS** traversal. If we are using instead a top-down traversal method + // then the `is_descendent_of` closure, when used after a warp-sync, may end up querying the + // backend for a block (the one corresponding to the root) that is not present and thus will + // return a wrong result. pub fn import( &mut self, hash: H, @@ -143,29 +148,20 @@ where } } - let mut children = &mut self.roots; - let mut i = 0; - while i < children.len() { - let child = &children[i]; - if child.hash == hash { - return Err(Error::Duplicate) - } - if child.number < number && is_descendent_of(&child.hash, &hash)? { - children = &mut children[i].children; - i = 0; - } else { - i += 1; - } + let (children, is_root) = + match self.find_node_where_mut(&hash, &number, is_descendent_of, &|_| true)? { + Some(parent) => (&mut parent.children, false), + None => (&mut self.roots, true), + }; + + if children.iter().any(|elem| elem.hash == hash) { + return Err(Error::Duplicate) } - let is_first = children.is_empty(); children.push(Node { data, hash, number, children: Default::default() }); - // Quick way to check if the pushed node is a root - let is_root = children.as_ptr() == self.roots.as_ptr(); - - if is_first { - // Rebalance is required only if we've extended the branch depth. + if children.len() == 1 { + // Rebalance may be required only if we've extended the branch depth. self.rebalance(); } @@ -293,7 +289,7 @@ where // rely on a **post-order DFS** traversal. If we are using instead a top-down traversal method // then the `is_descendent_of` closure, when used after a warp-sync, will end up querying the // backend for a block (the one corresponding to the root) that is not present and thus will - // return a wrong result. Here we are implementing a post-order DFS. + // return a wrong result. pub fn find_node_index_where( &self, hash: &H, @@ -1441,22 +1437,6 @@ mod test { .unwrap() .unwrap(); assert_eq!(path, [0, 1, 0, 0, 0]); - - // Test for the post-order DFS requirement as specified by the `find_node_index_where` - // comment. Once (and if) post-order traversal requirement is removed, then this test - // can be removed as well. In practice this test should fail with a pre-order DFS. - let is_descendent_of_for_post_order = |parent: &&str, child: &&str| { - if *parent == "A" { - Err(TestError) - } else { - is_descendent_of(parent, child) - } - }; - let path = tree - .find_node_index_where(&"N", &6, &is_descendent_of_for_post_order, &|_| true) - .unwrap() - .unwrap(); - assert_eq!(path, [0, 1, 0, 0, 0]); } #[test] @@ -1521,4 +1501,32 @@ mod test { let node = tree.find_node_where(&"N", &6, &is_descendent_of, &|_| true).unwrap().unwrap(); assert_eq!((node.hash, node.number), ("M", 5)); } + + #[test] + fn post_order_traversal_requirement() { + let (mut tree, is_descendent_of) = test_fork_tree(); + + // Test for the post-order DFS traversal requirement as specified by the + // `find_node_index_where` and `import` comments. + let is_descendent_of_for_post_order = |parent: &&str, child: &&str| match *parent { + "A" => Err(TestError), + "K" if *child == "Z" => Ok(true), + _ => is_descendent_of(parent, child), + }; + + // Post order traversal requirement for `find_node_index_where` + let path = tree + .find_node_index_where(&"N", &6, &is_descendent_of_for_post_order, &|_| true) + .unwrap() + .unwrap(); + assert_eq!(path, [0, 1, 0, 0, 0]); + + // Post order traversal requirement for `import` + let res = tree.import(&"Z", 100, (), &is_descendent_of_for_post_order); + assert_eq!(res, Ok(false)); + assert_eq!( + tree.iter().map(|node| *node.0).collect::>(), + vec!["A", "B", "C", "D", "E", "F", "H", "L", "M", "O", "I", "G", "J", "K", "Z"], + ); + } } From 92517913b239a6e20f8b26bad9ce2238e9b978e8 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Sat, 28 May 2022 11:55:51 +0200 Subject: [PATCH 0852/1472] Fixed pruning docs (#11519) --- client/cli/src/params/pruning_params.rs | 6 +++--- client/state-db/src/lib.rs | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index 0f3d1013381e6..fa30aa53b8a04 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -25,9 +25,9 @@ use sc_service::{KeepBlocks, PruningMode}; pub struct PruningParams { /// Specify the state pruning mode, a number of blocks to keep or 'archive'. /// - /// Default is to keep all block states if the node is running as a - /// validator (i.e. 'archive'), otherwise state is only kept for the last - /// 256 blocks. + /// Default is to keep only the last 256 blocks, + /// otherwise, the state can be kept for all of the blocks (i.e 'archive'), + /// or for all of the canonical blocks (i.e 'archive-canonical'). #[clap(long, value_name = "PRUNING_MODE")] pub pruning: Option, /// Specify the number of finalized blocks to keep in the database. diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 794dec3b954b7..d5cca9a342187 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -239,7 +239,7 @@ impl PruningMode { } } - /// Is this an archive (either ArchiveAll or ArchiveCanonical) pruning mode? + /// Returns the pruning mode pub fn id(&self) -> &[u8] { match self { PruningMode::ArchiveAll => PRUNING_MODE_ARCHIVE, @@ -247,6 +247,7 @@ impl PruningMode { PruningMode::Constrained(_) => PRUNING_MODE_CONSTRAINED, } } + pub fn from_id(id: &[u8]) -> Option { match id { PRUNING_MODE_ARCHIVE => Some(Self::ArchiveAll), From b508b25f080236b8622506a435a78605f48ddb5b Mon Sep 17 00:00:00 2001 From: Alexander Gryaznov Date: Sun, 29 May 2022 11:28:03 +0300 Subject: [PATCH 0853/1472] fix broken links (#11536) --- frame/contracts/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frame/contracts/README.md b/frame/contracts/README.md index 8a8e4918f2e41..bd5e58d89d1ce 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -2,10 +2,10 @@ The Contract module provides functionality for the runtime to deploy and execute WebAssembly smart-contracts. -- [`Call`](https://docs.rs/pallet-contracts/latest/pallet_contracts/enum.Call.html) -- [`Config`](https://docs.rs/pallet-contracts/latest/pallet_contracts/trait.Config.html) -- [`Error`](https://docs.rs/pallet-contracts/latest/pallet_contracts/enum.Error.html) -- [`Event`](https://docs.rs/pallet-contracts/latest/pallet_contracts/enum.Event.html) +- [`Call`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/enum.Call.html) +- [`Config`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/trait.Config.html) +- [`Error`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/enum.Error.html) +- [`Event`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/enum.Error.html) ## Overview @@ -47,7 +47,7 @@ fails, A can decide how to handle that failure, either proceeding or reverting A ### Dispatchable functions -Those are documented in the [reference documentation](https://docs.rs/pallet-contracts/latest/pallet_contracts/#dispatchable-functions). +Those are documented in the [reference documentation](https://paritytech.github.io/substrate/master/pallet_contracts/index.html#dispatchable-functions). ### Interface exposed to contracts @@ -89,7 +89,7 @@ writing WebAssembly based smart contracts in the Rust programming language. Contracts can emit messages to the client when called as RPC through the `seal_debug_message` API. This is exposed in ink! via -[`ink_env::debug_println()`](https://docs.rs/ink_env/latest/ink_env/fn.debug_println.html). +[`ink_env::debug_message()`](https://paritytech.github.io/ink/ink_env/fn.debug_message.html). Those messages are gathered into an internal buffer and send to the RPC client. It is up the the individual client if and how those messages are presented to the user. From c8653447fc8ef8d95a92fe164c96dffb37919e85 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sun, 29 May 2022 12:56:26 +0100 Subject: [PATCH 0854/1472] Safe and sane multi-item storage removal (#11490) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix overlay prefix removal result * Second part of the overlay prefix removal fix. * Report only items deleted from storage in clear_prefix * Fix kill_prefix * Formatting * Remove unused code * Fixes * Fixes * Introduce clear_prefix host function v3 * Formatting * Use v2 for now * Fixes * Formatting * Docs * Child prefix removal should also hide v3 for now * Fixes * Fixes * Formatting * Fixes * apply_to_keys_whle takes start_at * apply_to_keys_whle takes start_at * apply_to_keys_whle takes start_at * Cursor API; force limits * Use unsafe deprecated functions * Formatting * Fixes * Grumbles * Fixes * Docs * Some nitpicks :see_no_evil: * Update primitives/externalities/src/lib.rs Co-authored-by: Bastian Köcher * Formatting * Fixes * cargo fmt * Fixes * Update primitives/io/src/lib.rs Co-authored-by: Keith Yeung * Formatting * Fixes Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher Co-authored-by: Keith Yeung --- Cargo.lock | 1 + client/db/src/bench.rs | 3 +- client/db/src/lib.rs | 3 +- client/db/src/storage_cache.rs | 6 +- frame/bags-list/src/list/mod.rs | 2 + frame/contracts/src/migration.rs | 1 + frame/contracts/src/storage.rs | 14 +- frame/elections-phragmen/src/benchmarking.rs | 1 + frame/im-online/src/lib.rs | 2 + frame/scheduler/src/lib.rs | 2 + frame/society/src/lib.rs | 3 + frame/staking/src/pallet/impls.rs | 9 ++ frame/staking/src/slashing.rs | 2 + frame/staking/src/testing_utils.rs | 2 + frame/support/src/lib.rs | 8 +- frame/support/src/storage/child.rs | 55 ++++++- .../src/storage/generator/double_map.rs | 21 ++- frame/support/src/storage/generator/nmap.rs | 17 +- frame/support/src/storage/migration.rs | 33 +++- frame/support/src/storage/mod.rs | 92 ++++++++++- .../support/src/storage/types/counted_map.rs | 46 +++++- frame/support/src/storage/types/double_map.rs | 75 ++++++++- frame/support/src/storage/types/map.rs | 33 +++- frame/support/src/storage/types/nmap.rs | 152 ++++++++++++++---- frame/support/src/storage/unhashed.rs | 53 ++++++ frame/system/src/lib.rs | 4 +- frame/uniques/src/functions.rs | 2 + primitives/externalities/src/lib.rs | 61 +++++-- primitives/io/Cargo.toml | 4 +- primitives/io/src/lib.rs | 152 +++++++++++++++--- primitives/runtime-interface/Cargo.toml | 4 +- primitives/runtime-interface/src/impls.rs | 4 + primitives/state-machine/Cargo.toml | 1 + primitives/state-machine/src/backend.rs | 1 + primitives/state-machine/src/basic.rs | 46 ++++-- primitives/state-machine/src/ext.rs | 113 +++++++------ primitives/state-machine/src/lib.rs | 52 ++++-- .../src/overlayed_changes/changeset.rs | 7 +- .../src/overlayed_changes/mod.rs | 12 +- .../state-machine/src/proving_backend.rs | 3 +- primitives/state-machine/src/read_only.rs | 20 ++- primitives/state-machine/src/testing.rs | 5 +- primitives/state-machine/src/trie_backend.rs | 3 +- .../state-machine/src/trie_backend_essence.rs | 23 +-- primitives/tasks/src/async_externalities.rs | 21 ++- 45 files changed, 968 insertions(+), 206 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b1a05b7067e2..29d15b9e015cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10070,6 +10070,7 @@ dependencies = [ name = "sp-state-machine" version = "0.12.0" dependencies = [ + "assert_matches", "hash-db", "hex-literal", "log", diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index 8bc4a0f4893c7..d3d43e742d026 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -393,10 +393,11 @@ impl StateBackend> for BenchmarkingState { &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, + start_at: Option<&[u8]>, f: F, ) { if let Some(ref state) = *self.state.borrow() { - state.apply_to_keys_while(child_info, prefix, f) + state.apply_to_keys_while(child_info, prefix, start_at, f) } } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index a32a666c3c980..5f15b2d6fe969 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -226,9 +226,10 @@ impl StateBackend> for RefTrackingState { &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, + start_at: Option<&[u8]>, f: F, ) { - self.state.apply_to_keys_while(child_info, prefix, f) + self.state.apply_to_keys_while(child_info, prefix, start_at, f) } fn for_child_keys_with_prefix( diff --git a/client/db/src/storage_cache.rs b/client/db/src/storage_cache.rs index 9dada92b066ea..8326946999946 100644 --- a/client/db/src/storage_cache.rs +++ b/client/db/src/storage_cache.rs @@ -639,9 +639,10 @@ impl>, B: BlockT> StateBackend> for Cachin &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, + start_at: Option<&[u8]>, f: F, ) { - self.state.apply_to_keys_while(child_info, prefix, f) + self.state.apply_to_keys_while(child_info, prefix, start_at, f) } fn next_storage_key(&self, key: &[u8]) -> Result>, Self::Error> { @@ -839,9 +840,10 @@ impl>, B: BlockT> StateBackend> &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, + start_at: Option<&[u8]>, f: F, ) { - self.caching_state().apply_to_keys_while(child_info, prefix, f) + self.caching_state().apply_to_keys_while(child_info, prefix, start_at, f) } fn next_storage_key(&self, key: &[u8]) -> Result>, Self::Error> { diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index d95c5de8132ea..b4f852685842d 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -94,7 +94,9 @@ impl, I: 'static> List { /// this function should generally not be used in production as it could lead to a very large /// number of storage accesses. pub(crate) fn unsafe_clear() { + #[allow(deprecated)] crate::ListBags::::remove_all(None); + #[allow(deprecated)] crate::ListNodes::::remove_all(); } diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 0832ebadac9c6..19e699a855461 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -56,6 +56,7 @@ mod v4 { use super::*; pub fn migrate() -> Weight { + #[allow(deprecated)] migration::remove_storage_prefix(>::name().as_bytes(), b"CurrentSchedule", b""); T::DbWeight::get().writes(1) } diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index af6dbe3c62bfc..e73eb8d3bd55e 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -27,12 +27,12 @@ use crate::{ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::{DispatchError, DispatchResult}, - storage::child::{self, ChildInfo, KillStorageResult}, + storage::child::{self, ChildInfo}, weights::Weight, }; use scale_info::TypeInfo; use sp_core::crypto::UncheckedFrom; -use sp_io::hashing::blake2_256; +use sp_io::{hashing::blake2_256, KillStorageResult}; use sp_runtime::{ traits::{Hash, Zero}, RuntimeDebug, @@ -266,16 +266,16 @@ where while !queue.is_empty() && remaining_key_budget > 0 { // Cannot panic due to loop condition let trie = &mut queue[0]; - let outcome = - child::kill_storage(&child_trie_info(&trie.trie_id), Some(remaining_key_budget)); + #[allow(deprecated)] + let outcome = child::kill_storage(&child_trie_info(&trie.trie_id), Some(remaining_key_budget)); let keys_removed = match outcome { // This happens when our budget wasn't large enough to remove all keys. - KillStorageResult::SomeRemaining(count) => count, - KillStorageResult::AllRemoved(count) => { + KillStorageResult::SomeRemaining(c) => c, + KillStorageResult::AllRemoved(c) => { // We do not care to preserve order. The contract is deleted already and // no one waits for the trie to be deleted. queue.swap_remove(0); - count + c }, }; remaining_key_budget = remaining_key_budget.saturating_sub(keys_removed); diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 493f20924203c..44dd6aff09f0c 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -148,6 +148,7 @@ fn clean() { >::kill(); >::kill(); >::kill(); + #[allow(deprecated)] >::remove_all(None); } diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 05b7618b286a6..f190f6672f309 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -900,7 +900,9 @@ impl OneSessionHandler for Pallet { // Remove all received heartbeats and number of authored blocks from the // current session, they have already been processed and won't be needed // anymore. + #[allow(deprecated)] ReceivedHeartbeats::::remove_prefix(&T::ValidatorSet::session_index(), None); + #[allow(deprecated)] AuthoredBlocks::::remove_prefix(&T::ValidatorSet::session_index(), None); if offenders.is_empty() { diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 9b0fc87587e3a..a005c051a1abc 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -565,6 +565,7 @@ impl Pallet { }, ); + #[allow(deprecated)] frame_support::storage::migration::remove_storage_prefix( Self::name().as_bytes(), b"StorageVersion", @@ -601,6 +602,7 @@ impl Pallet { ) }); + #[allow(deprecated)] frame_support::storage::migration::remove_storage_prefix( Self::name().as_bytes(), b"StorageVersion", diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 2973ecd68092e..5a993f72f32d2 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -1067,6 +1067,7 @@ pub mod pallet { Founder::::kill(); Rules::::kill(); Candidates::::kill(); + #[allow(deprecated)] SuspendedCandidates::::remove_all(None); Self::deposit_event(Event::::Unfounded { founder }); Ok(()) @@ -1511,6 +1512,7 @@ impl, I: 'static> Pallet { .collect::>(); // Clean up all votes. + #[allow(deprecated)] >::remove_all(None); // Reward one of the voters who voted the right way. @@ -1695,6 +1697,7 @@ impl, I: 'static> Pallet { } // Clean up all votes. + #[allow(deprecated)] >::remove_all(None); } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 4de1ea36cb591..66265ab1f135e 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -585,8 +585,11 @@ impl Pallet { /// Clear all era information for given era. pub(crate) fn clear_era_information(era_index: EraIndex) { + #[allow(deprecated)] >::remove_prefix(era_index, None); + #[allow(deprecated)] >::remove_prefix(era_index, None); + #[allow(deprecated)] >::remove_prefix(era_index, None); >::remove(era_index); >::remove(era_index); @@ -984,9 +987,13 @@ impl ElectionDataProvider for Pallet { #[cfg(feature = "runtime-benchmarks")] fn clear() { + #[allow(deprecated)] >::remove_all(None); + #[allow(deprecated)] >::remove_all(None); + #[allow(deprecated)] >::remove_all(); + #[allow(deprecated)] >::remove_all(); T::VoterList::unsafe_clear(); @@ -1368,7 +1375,9 @@ impl SortedListProvider for UseNominatorsAndValidatorsM fn unsafe_clear() { // NOTE: Caller must ensure this doesn't lead to too many storage accesses. This is a // condition of SortedListProvider::unsafe_clear. + #[allow(deprecated)] Nominators::::remove_all(); + #[allow(deprecated)] Validators::::remove_all(); } } diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 25954a3699b31..7372c4390f816 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -557,7 +557,9 @@ impl<'a, T: 'a + Config> Drop for InspectingSpans<'a, T> { /// Clear slashing metadata for an obsolete era. pub(crate) fn clear_era_metadata(obsolete_era: EraIndex) { + #[allow(deprecated)] as Store>::ValidatorSlashInEra::remove_prefix(&obsolete_era, None); + #[allow(deprecated)] as Store>::NominatorSlashInEra::remove_prefix(&obsolete_era, None); } diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index f30020597db45..ba67292ddc434 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -36,9 +36,11 @@ const SEED: u32 = 0; /// This function removes all validators and nominators from storage. pub fn clear_validators_and_nominators() { + #[allow(deprecated)] Validators::::remove_all(); // whenever we touch nominators counter we should update `T::VoterList` as well. + #[allow(deprecated)] Nominators::::remove_all(); // NOTE: safe to call outside block production diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 03f1553293a47..178fddb61b0a2 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1097,8 +1097,12 @@ pub mod tests { DoubleMap::insert(&(key1 + 1), &key2, &4u64); DoubleMap::insert(&(key1 + 1), &(key2 + 1), &4u64); assert!(matches!( - DoubleMap::remove_prefix(&key1, None), - sp_io::KillStorageResult::AllRemoved(0), // all in overlay + DoubleMap::clear_prefix(&key1, u32::max_value(), None), + // Note this is the incorrect answer (for now), since we are using v2 of + // `clear_prefix`. + // When we switch to v3, then this will become: + // sp_io::MultiRemovalResults::NoneLeft { db: 0, total: 2 }, + sp_io::MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 }, )); assert_eq!(DoubleMap::get(&key1, &key2), 0u64); assert_eq!(DoubleMap::get(&key1, &(key2 + 1)), 0u64); diff --git a/frame/support/src/storage/child.rs b/frame/support/src/storage/child.rs index e20d4fe0cd4d3..397daaa82a677 100644 --- a/frame/support/src/storage/child.rs +++ b/frame/support/src/storage/child.rs @@ -21,7 +21,7 @@ // NOTE: could replace unhashed by having only one kind of storage (top trie being the child info // of null length parent storage key). -pub use crate::sp_io::KillStorageResult; +pub use crate::sp_io::{KillStorageResult, MultiRemovalResults}; use crate::sp_std::prelude::*; use codec::{Codec, Decode, Encode}; pub use sp_core::storage::{ChildInfo, ChildType, StateVersion}; @@ -136,6 +136,7 @@ pub fn exists(child_info: &ChildInfo, key: &[u8]) -> bool { /// not make much sense because it is not cumulative when called inside the same block. /// Use this function to distribute the deletion of a single child trie across multiple /// blocks. +#[deprecated = "Use `clear_storage` instead"] pub fn kill_storage(child_info: &ChildInfo, limit: Option) -> KillStorageResult { match child_info.child_type() { ChildType::ParentKeyId => @@ -143,6 +144,58 @@ pub fn kill_storage(child_info: &ChildInfo, limit: Option) -> KillStorageRe } } +/// Partially clear the child storage of each key-value pair. +/// +/// # Limit +/// +/// A *limit* should always be provided through `maybe_limit`. This is one fewer than the +/// maximum number of backend iterations which may be done by this operation and as such +/// represents the maximum number of backend deletions which may happen. A *limit* of zero +/// implies that no keys will be deleted, though there may be a single iteration done. +/// +/// The limit can be used to partially delete storage items in case it is too large or costly +/// to delete all in a single operation. +/// +/// # Cursor +/// +/// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be +/// passed once (in the initial call) for any attempt to clear storage. In general, subsequent calls +/// operating on the same prefix should pass `Some` and this value should be equal to the +/// previous call result's `maybe_cursor` field. The only exception to this is when you can +/// guarantee that the subsequent call is in a new block; in this case the previous call's result +/// cursor need not be passed in an a `None` may be passed instead. This exception may be useful +/// then making this call solely from a block-hook such as `on_initialize`. +/// +/// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once the +/// resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. +/// +/// NOTE: After the initial call for any given child storage, it is important that no keys further +/// keys are inserted. If so, then they may or may not be deleted by subsequent calls. +/// +/// # Note +/// +/// Please note that keys which are residing in the overlay for the child are deleted without +/// counting towards the `limit`. +pub fn clear_storage( + child_info: &ChildInfo, + maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, +) -> MultiRemovalResults { + // TODO: Once the network has upgraded to include the new host functions, this code can be + // enabled. + // sp_io::default_child_storage::storage_kill(prefix, maybe_limit, maybe_cursor) + let r = match child_info.child_type() { + ChildType::ParentKeyId => + sp_io::default_child_storage::storage_kill(child_info.storage_key(), maybe_limit), + }; + use sp_io::KillStorageResult::*; + let (maybe_cursor, backend) = match r { + AllRemoved(db) => (None, db), + SomeRemaining(db) => (Some(child_info.storage_key().to_vec()), db), + }; + MultiRemovalResults { maybe_cursor, backend, unique: backend, loops: backend } +} + /// Ensure `key` has no explicit entry in storage. pub fn kill(child_info: &ChildInfo, key: &[u8]) { match child_info.child_type() { diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index 1c308bc351902..90ec92c622b1f 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -202,11 +202,28 @@ where unhashed::kill(&Self::storage_double_map_final_key(k1, k2)) } - fn remove_prefix(k1: KArg1, limit: Option) -> sp_io::KillStorageResult + fn remove_prefix(k1: KArg1, maybe_limit: Option) -> sp_io::KillStorageResult where KArg1: EncodeLike, { - unhashed::kill_prefix(Self::storage_double_map_final_key1(k1).as_ref(), limit) + unhashed::clear_prefix(Self::storage_double_map_final_key1(k1).as_ref(), maybe_limit, None) + .into() + } + + fn clear_prefix( + k1: KArg1, + limit: u32, + maybe_cursor: Option<&[u8]>, + ) -> sp_io::MultiRemovalResults + where + KArg1: EncodeLike, + { + unhashed::clear_prefix( + Self::storage_double_map_final_key1(k1).as_ref(), + Some(limit), + maybe_cursor, + ) + .into() } fn iter_prefix_values(k1: KArg1) -> storage::PrefixIterator diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 18c912cf294ef..0175d681df1d4 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -183,7 +183,22 @@ where where K: HasKeyPrefix, { - unhashed::kill_prefix(&Self::storage_n_map_partial_key(partial_key), limit) + unhashed::clear_prefix(&Self::storage_n_map_partial_key(partial_key), limit, None).into() + } + + fn clear_prefix( + partial_key: KP, + limit: u32, + maybe_cursor: Option<&[u8]>, + ) -> sp_io::MultiRemovalResults + where + K: HasKeyPrefix, + { + unhashed::clear_prefix( + &Self::storage_n_map_partial_key(partial_key), + Some(limit), + maybe_cursor, + ) } fn iter_prefix_values(partial_key: KP) -> PrefixIterator diff --git a/frame/support/src/storage/migration.rs b/frame/support/src/storage/migration.rs index 713c2b0f3fe01..67001fc4e1f42 100644 --- a/frame/support/src/storage/migration.rs +++ b/frame/support/src/storage/migration.rs @@ -256,12 +256,43 @@ pub fn put_storage_value(module: &[u8], item: &[u8], hash: &[u8], val /// Remove all items under a storage prefix by the `module`, the map's `item` name and the key /// `hash`. +#[deprecated = "Use `clear_storage_prefix` instead"] pub fn remove_storage_prefix(module: &[u8], item: &[u8], hash: &[u8]) { let mut key = vec![0u8; 32 + hash.len()]; let storage_prefix = storage_prefix(module, item); key[0..32].copy_from_slice(&storage_prefix); key[32..].copy_from_slice(hash); - frame_support::storage::unhashed::kill_prefix(&key, None); + let _ = frame_support::storage::unhashed::clear_prefix(&key, None, None); +} + +/// Attempt to remove all values under a storage prefix by the `module`, the map's `item` name and +/// the key `hash`. +/// +/// All values in the client overlay will be deleted, if `maybe_limit` is `Some` then up to +/// that number of values are deleted from the client backend by seeking and reading that number of +/// storage values plus one. If `maybe_limit` is `None` then all values in the client backend are +/// deleted. This is potentially unsafe since it's an unbounded operation. +/// +/// ## Cursors +/// +/// The `maybe_cursor` parameter should be `None` for the first call to initial removal. +/// If the resultant `maybe_cursor` is `Some`, then another call is required to complete the +/// removal operation. This value must be passed in as the subsequent call's `maybe_cursor` +/// parameter. If the resultant `maybe_cursor` is `None`, then the operation is complete and no +/// items remain in storage provided that no items were added between the first calls and the +/// final call. +pub fn clear_storage_prefix( + module: &[u8], + item: &[u8], + hash: &[u8], + maybe_limit: Option, + maybe_cursor: Option<&[u8]>, +) -> sp_io::MultiRemovalResults { + let mut key = vec![0u8; 32 + hash.len()]; + let storage_prefix = storage_prefix(module, item); + key[0..32].copy_from_slice(&storage_prefix); + key[32..].copy_from_slice(hash); + frame_support::storage::unhashed::clear_prefix(&key, maybe_limit, maybe_cursor) } /// Take a particular item in storage by the `module`, the map's `item` name and the key `hash`. diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 7a960776fc755..8b6f198b03f96 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -516,10 +516,34 @@ pub trait StorageDoubleMap { /// Calling this multiple times per block with a `limit` set leads always to the same keys being /// removed and the same result being returned. This happens because the keys to delete in the /// overlay are not taken into account when deleting keys in the backend. + #[deprecated = "Use `clear_prefix` instead"] fn remove_prefix(k1: KArg1, limit: Option) -> sp_io::KillStorageResult where KArg1: ?Sized + EncodeLike; + /// Remove all values under the first key `k1` in the overlay and up to `maybe_limit` in the + /// backend. + /// + /// All values in the client overlay will be deleted, if `maybe_limit` is `Some` then up to + /// that number of values are deleted from the client backend, otherwise all values in the + /// client backend are deleted. + /// + /// ## Cursors + /// + /// The `maybe_cursor` parameter should be `None` for the first call to initial removal. + /// If the resultant `maybe_cursor` is `Some`, then another call is required to complete the + /// removal operation. This value must be passed in as the subsequent call's `maybe_cursor` + /// parameter. If the resultant `maybe_cursor` is `None`, then the operation is complete and no + /// items remain in storage provided that no items were added between the first calls and the + /// final call. + fn clear_prefix( + k1: KArg1, + limit: u32, + maybe_cursor: Option<&[u8]>, + ) -> sp_io::MultiRemovalResults + where + KArg1: ?Sized + EncodeLike; + /// Iterate over values that share the first key. fn iter_prefix_values(k1: KArg1) -> PrefixIterator where @@ -657,10 +681,42 @@ pub trait StorageNMap { /// Calling this multiple times per block with a `limit` set leads always to the same keys being /// removed and the same result being returned. This happens because the keys to delete in the /// overlay are not taken into account when deleting keys in the backend. + #[deprecated = "Use `clear_prefix` instead"] fn remove_prefix(partial_key: KP, limit: Option) -> sp_io::KillStorageResult where K: HasKeyPrefix; + /// Attempt to remove items from the map matching a `partial_key` prefix. + /// + /// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once + /// the resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + /// + /// NOTE: After the initial call for any given map, it is important that no further items + /// are inserted into the map which match the `partial key`. If so, then the map may not be + /// empty when the resultant `maybe_cursor` is `None`. + /// + /// # Limit + /// + /// A `limit` must be provided in order to cap the maximum + /// amount of deletions done in a single call. This is one fewer than the + /// maximum number of backend iterations which may be done by this operation and as such + /// represents the maximum number of backend deletions which may happen. A `limit` of zero + /// implies that no keys will be deleted, though there may be a single iteration done. + /// + /// # Cursor + /// + /// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be + /// passed once (in the initial call) for any given storage map and `partial_key`. Subsequent + /// calls operating on the same map/`partial_key` should always pass `Some`, and this should be + /// equal to the previous call result's `maybe_cursor` field. + fn clear_prefix( + partial_key: KP, + limit: u32, + maybe_cursor: Option<&[u8]>, + ) -> sp_io::MultiRemovalResults + where + K: HasKeyPrefix; + /// Iterate over values that share the partial prefix key. fn iter_prefix_values(partial_key: KP) -> PrefixIterator where @@ -1111,8 +1167,36 @@ pub trait StoragePrefixedMap { /// Calling this multiple times per block with a `limit` set leads always to the same keys being /// removed and the same result being returned. This happens because the keys to delete in the /// overlay are not taken into account when deleting keys in the backend. + #[deprecated = "Use `clear` instead"] fn remove_all(limit: Option) -> sp_io::KillStorageResult { - sp_io::storage::clear_prefix(&Self::final_prefix(), limit) + unhashed::clear_prefix(&Self::final_prefix(), limit, None).into() + } + + /// Attempt to remove all items from the map. + /// + /// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once + /// the resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + /// + /// NOTE: After the initial call for any given map, it is important that no further items + /// are inserted into the map. If so, then the map may not be empty when the resultant + /// `maybe_cursor` is `None`. + /// + /// # Limit + /// + /// A `limit` must always be provided through in order to cap the maximum + /// amount of deletions done in a single call. This is one fewer than the + /// maximum number of backend iterations which may be done by this operation and as such + /// represents the maximum number of backend deletions which may happen. A `limit` of zero + /// implies that no keys will be deleted, though there may be a single iteration done. + /// + /// # Cursor + /// + /// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be + /// passed once (in the initial call) for any given storage map. Subsequent calls + /// operating on the same map should always pass `Some`, and this should be equal to the + /// previous call result's `maybe_cursor` field. + fn clear(limit: u32, maybe_cursor: Option<&[u8]>) -> sp_io::MultiRemovalResults { + unhashed::clear_prefix(&Self::final_prefix(), Some(limit), maybe_cursor) } /// Iter over all value of the storage. @@ -1427,7 +1511,7 @@ mod test { assert_eq!(MyStorage::iter_values().collect::>(), vec![1, 2, 3, 4]); // test removal - MyStorage::remove_all(None); + let _ = MyStorage::clear(u32::max_value(), None); assert!(MyStorage::iter_values().collect::>().is_empty()); // test migration @@ -1437,7 +1521,7 @@ mod test { assert!(MyStorage::iter_values().collect::>().is_empty()); MyStorage::translate_values(|v: u32| Some(v as u64)); assert_eq!(MyStorage::iter_values().collect::>(), vec![1, 2]); - MyStorage::remove_all(None); + let _ = MyStorage::clear(u32::max_value(), None); // test migration 2 unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u128); @@ -1449,7 +1533,7 @@ mod test { assert_eq!(MyStorage::iter_values().collect::>(), vec![1, 2, 3]); MyStorage::translate_values(|v: u128| Some(v as u64)); assert_eq!(MyStorage::iter_values().collect::>(), vec![1, 2, 3]); - MyStorage::remove_all(None); + let _ = MyStorage::clear(u32::max_value(), None); // test that other values are not modified. assert_eq!(unhashed::get(&key_before[..]), Some(32u64)); diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index a2160ede52fe9..44fcbf607935f 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -31,6 +31,7 @@ use crate::{ Never, }; use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen, Ref}; +use sp_io::MultiRemovalResults; use sp_runtime::traits::Saturating; use sp_std::prelude::*; @@ -273,13 +274,44 @@ where ::Map::migrate_key::(key) } - /// Remove all value of the storage. + /// Remove all values in the map. + #[deprecated = "Use `clear` instead"] pub fn remove_all() { - // NOTE: it is not possible to remove up to some limit because - // `sp_io::storage::clear_prefix` and `StorageMap::remove_all` don't give the number of - // value removed from the overlay. - CounterFor::::set(0u32); + #[allow(deprecated)] ::Map::remove_all(None); + CounterFor::::kill(); + } + + /// Attempt to remove all items from the map. + /// + /// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once + /// the resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + /// + /// NOTE: After the initial call for any given map, it is important that no further items + /// are inserted into the map. If so, then the map may not be empty when the resultant + /// `maybe_cursor` is `None`. + /// + /// # Limit + /// + /// A `limit` must always be provided through in order to cap the maximum + /// amount of deletions done in a single call. This is one fewer than the + /// maximum number of backend iterations which may be done by this operation and as such + /// represents the maximum number of backend deletions which may happen. A `limit` of zero + /// implies that no keys will be deleted, though there may be a single iteration done. + /// + /// # Cursor + /// + /// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be + /// passed once (in the initial call) for any given storage map. Subsequent calls + /// operating on the same map should always pass `Some`, and this should be equal to the + /// previous call result's `maybe_cursor` field. + pub fn clear(limit: u32, maybe_cursor: Option<&[u8]>) -> MultiRemovalResults { + let result = ::Map::clear(limit, maybe_cursor); + match result.maybe_cursor { + None => CounterFor::::kill(), + Some(_) => CounterFor::::mutate(|x| x.saturating_reduce(result.unique)), + } + result } /// Iter over all value of the storage. @@ -691,7 +723,7 @@ mod test { assert_eq!(A::count(), 2); // Remove all. - A::remove_all(); + let _ = A::clear(u32::max_value(), None); assert_eq!(A::count(), 0); assert_eq!(A::initialize_counter(), 0); @@ -922,7 +954,7 @@ mod test { assert_eq!(B::count(), 2); // Remove all. - B::remove_all(); + let _ = B::clear(u32::max_value(), None); assert_eq!(B::count(), 0); assert_eq!(B::initialize_counter(), 0); diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 42b903128934d..5662087cc896f 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -229,13 +229,53 @@ where /// Calling this multiple times per block with a `limit` set leads always to the same keys being /// removed and the same result being returned. This happens because the keys to delete in the /// overlay are not taken into account when deleting keys in the backend. + #[deprecated = "Use `clear_prefix` instead"] pub fn remove_prefix(k1: KArg1, limit: Option) -> sp_io::KillStorageResult where KArg1: ?Sized + EncodeLike, { + #[allow(deprecated)] >::remove_prefix(k1, limit) } + /// Attempt to remove items from the map matching a `first_key` prefix. + /// + /// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once + /// the resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + /// + /// NOTE: After the initial call for any given map, it is important that no further items + /// are inserted into the map which match the `first_key`. If so, then the map may not be + /// empty when the resultant `maybe_cursor` is `None`. + /// + /// # Limit + /// + /// A `limit` must always be provided through in order to cap the maximum + /// amount of deletions done in a single call. This is one fewer than the + /// maximum number of backend iterations which may be done by this operation and as such + /// represents the maximum number of backend deletions which may happen. A `limit` of zero + /// implies that no keys will be deleted, though there may be a single iteration done. + /// + /// # Cursor + /// + /// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be + /// passed once (in the initial call) for any given storage map and `first_key`. Subsequent + /// calls operating on the same map/`first_key` should always pass `Some`, and this should be + /// equal to the previous call result's `maybe_cursor` field. + pub fn clear_prefix( + first_key: KArg1, + limit: u32, + maybe_cursor: Option<&[u8]>, + ) -> sp_io::MultiRemovalResults + where + KArg1: ?Sized + EncodeLike, + { + >::clear_prefix( + first_key, + limit, + maybe_cursor, + ) + } + /// Iterate over values that share the first key. pub fn iter_prefix_values(k1: KArg1) -> crate::storage::PrefixIterator where @@ -359,10 +399,39 @@ where /// Calling this multiple times per block with a `limit` set leads always to the same keys being /// removed and the same result being returned. This happens because the keys to delete in the /// overlay are not taken into account when deleting keys in the backend. + #[deprecated = "Use `clear` instead"] pub fn remove_all(limit: Option) -> sp_io::KillStorageResult { + #[allow(deprecated)] >::remove_all(limit) } + /// Attempt to remove all items from the map. + /// + /// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once + /// the resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + /// + /// NOTE: After the initial call for any given map, it is important that no further items + /// are inserted into the map. If so, then the map may not be empty when the resultant + /// `maybe_cursor` is `None`. + /// + /// # Limit + /// + /// A `limit` must always be provided through in order to cap the maximum + /// amount of deletions done in a single call. This is one fewer than the + /// maximum number of backend iterations which may be done by this operation and as such + /// represents the maximum number of backend deletions which may happen.A `limit` of zero + /// implies that no keys will be deleted, though there may be a single iteration done. + /// + /// # Cursor + /// + /// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be + /// passed once (in the initial call) for any given storage map. Subsequent calls + /// operating on the same map should always pass `Some`, and this should be equal to the + /// previous call result's `maybe_cursor` field. + pub fn clear(limit: u32, maybe_cursor: Option<&[u8]>) -> sp_io::MultiRemovalResults { + >::clear(limit, maybe_cursor) + } + /// Iter over all value of the storage. /// /// NOTE: If a value failed to decode because storage is corrupted then it is skipped. @@ -768,7 +837,7 @@ mod test { A::insert(3, 30, 10); A::insert(4, 40, 10); - A::remove_all(None); + let _ = A::clear(u32::max_value(), None); assert_eq!(A::contains_key(3, 30), false); assert_eq!(A::contains_key(4, 40), false); @@ -829,7 +898,7 @@ mod test { ] ); - WithLen::remove_all(None); + let _ = WithLen::clear(u32::max_value(), None); assert_eq!(WithLen::decode_len(3, 30), None); WithLen::append(0, 100, 10); assert_eq!(WithLen::decode_len(0, 100), Some(1)); @@ -843,7 +912,7 @@ mod test { assert_eq!(A::iter_prefix_values(4).collect::>(), vec![13, 14]); assert_eq!(A::iter_prefix(4).collect::>(), vec![(40, 13), (41, 14)]); - A::remove_prefix(3, None); + let _ = A::clear_prefix(3, u32::max_value(), None); assert_eq!(A::iter_prefix(3).collect::>(), vec![]); assert_eq!(A::iter_prefix(4).collect::>(), vec![(40, 13), (41, 14)]); diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index bc32c58da8db6..6dac5b3756598 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -247,10 +247,39 @@ where /// Calling this multiple times per block with a `limit` set leads always to the same keys being /// removed and the same result being returned. This happens because the keys to delete in the /// overlay are not taken into account when deleting keys in the backend. + #[deprecated = "Use `clear` instead"] pub fn remove_all(limit: Option) -> sp_io::KillStorageResult { + #[allow(deprecated)] >::remove_all(limit) } + /// Attempt to remove all items from the map. + /// + /// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once + /// the resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + /// + /// NOTE: After the initial call for any given map, it is important that no further items + /// are inserted into the map. If so, then the map may not be empty when the resultant + /// `maybe_cursor` is `None`. + /// + /// # Limit + /// + /// A `limit` must always be provided through in order to cap the maximum + /// amount of deletions done in a single call. This is one fewer than the + /// maximum number of backend iterations which may be done by this operation and as such + /// represents the maximum number of backend deletions which may happen. A `limit` of zero + /// implies that no keys will be deleted, though there may be a single iteration done. + /// + /// # Cursor + /// + /// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be + /// passed once (in the initial call) for any given storage map. Subsequent calls + /// operating on the same map should always pass `Some`, and this should be equal to the + /// previous call result's `maybe_cursor` field. + pub fn clear(limit: u32, maybe_cursor: Option<&[u8]>) -> sp_io::MultiRemovalResults { + >::clear(limit, maybe_cursor) + } + /// Iter over all value of the storage. /// /// NOTE: If a value failed to decode because storage is corrupted then it is skipped. @@ -563,7 +592,7 @@ mod test { A::insert(3, 10); A::insert(4, 10); - A::remove_all(None); + let _ = A::clear(u32::max_value(), None); assert_eq!(A::contains_key(3), false); assert_eq!(A::contains_key(4), false); @@ -618,7 +647,7 @@ mod test { ] ); - WithLen::remove_all(None); + let _ = WithLen::clear(u32::max_value(), None); assert_eq!(WithLen::decode_len(3), None); WithLen::append(0, 10); assert_eq!(WithLen::decode_len(0), Some(1)); diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index a15c7482105e9..1f303525b7476 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -185,13 +185,53 @@ where /// Calling this multiple times per block with a `limit` set leads always to the same keys being /// removed and the same result being returned. This happens because the keys to delete in the /// overlay are not taken into account when deleting keys in the backend. + #[deprecated = "Use `clear_prefix` instead"] pub fn remove_prefix(partial_key: KP, limit: Option) -> sp_io::KillStorageResult where Key: HasKeyPrefix, { + #[allow(deprecated)] >::remove_prefix(partial_key, limit) } + /// Attempt to remove items from the map matching a `partial_key` prefix. + /// + /// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once + /// the resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + /// + /// NOTE: After the initial call for any given map, it is important that no further items + /// are inserted into the map which match the `partial key`. If so, then the map may not be + /// empty when the resultant `maybe_cursor` is `None`. + /// + /// # Limit + /// + /// A `limit` must be provided in order to cap the maximum + /// amount of deletions done in a single call. This is one fewer than the + /// maximum number of backend iterations which may be done by this operation and as such + /// represents the maximum number of backend deletions which may happen. A `limit` of zero + /// implies that no keys will be deleted, though there may be a single iteration done. + /// + /// # Cursor + /// + /// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be + /// passed once (in the initial call) for any given storage map and `partial_key`. Subsequent + /// calls operating on the same map/`partial_key` should always pass `Some`, and this should be + /// equal to the previous call result's `maybe_cursor` field. + pub fn clear_prefix( + partial_key: KP, + limit: u32, + maybe_cursor: Option<&[u8]>, + ) -> sp_io::MultiRemovalResults + where + Key: HasKeyPrefix, + { + >::clear_prefix( + partial_key, + limit, + maybe_cursor, + ) + } + /// Iterate over values that share the first key. pub fn iter_prefix_values(partial_key: KP) -> PrefixIterator where @@ -299,8 +339,37 @@ where /// Calling this multiple times per block with a `limit` set leads always to the same keys being /// removed and the same result being returned. This happens because the keys to delete in the /// overlay are not taken into account when deleting keys in the backend. + #[deprecated = "Use `clear` instead"] pub fn remove_all(limit: Option) -> sp_io::KillStorageResult { - >::remove_all(limit) + #[allow(deprecated)] + >::remove_all(limit).into() + } + + /// Attempt to remove all items from the map. + /// + /// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once + /// the resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + /// + /// NOTE: After the initial call for any given map, it is important that no further items + /// are inserted into the map. If so, then the map may not be empty when the resultant + /// `maybe_cursor` is `None`. + /// + /// # Limit + /// + /// A `limit` must always be provided through in order to cap the maximum + /// amount of deletions done in a single call. This is one fewer than the + /// maximum number of backend iterations which may be done by this operation and as such + /// represents the maximum number of backend deletions which may happen. A `limit` of zero + /// implies that no keys will be deleted, though there may be a single iteration done. + /// + /// # Cursor + /// + /// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be + /// passed once (in the initial call) for any given storage map. Subsequent calls + /// operating on the same map should always pass `Some`, and this should be equal to the + /// previous call result's `maybe_cursor` field. + pub fn clear(limit: u32, maybe_cursor: Option<&[u8]>) -> sp_io::MultiRemovalResults { + >::clear(limit, maybe_cursor) } /// Iter over all value of the storage. @@ -544,7 +613,7 @@ mod test { use crate::{ hash::{StorageHasher as _, *}, metadata::{StorageEntryModifier, StorageHasher}, - storage::types::{Key, ValueQuery}, + storage::types::{Key as NMapKey, ValueQuery}, }; use sp_io::{hashing::twox_128, TestExternalities}; @@ -565,12 +634,12 @@ mod test { #[test] fn test_1_key() { - type A = StorageNMap, u32, OptionQuery>; + type A = StorageNMap, u32, OptionQuery>; type AValueQueryWithAnOnEmpty = - StorageNMap, u32, ValueQuery, ADefault>; - type B = StorageNMap, u32, ValueQuery>; - type C = StorageNMap, u8, ValueQuery>; - type WithLen = StorageNMap, Vec>; + StorageNMap, u32, ValueQuery, ADefault>; + type B = StorageNMap, u32, ValueQuery>; + type C = StorageNMap, u8, ValueQuery>; + type WithLen = StorageNMap, Vec>; TestExternalities::default().execute_with(|| { let mut k: Vec = vec![]; @@ -590,13 +659,13 @@ mod test { { #[crate::storage_alias] - type Foo = StorageNMap), u32>; + type Foo = StorageNMap), u32>; assert_eq!(Foo::contains_key((3,)), true); assert_eq!(Foo::get((3,)), Some(10)); } - A::swap::, _, _>((3,), (2,)); + A::swap::, _, _>((3,), (2,)); assert_eq!(A::contains_key((3,)), false); assert_eq!(A::contains_key((2,)), true); assert_eq!(A::get((3,)), None); @@ -684,7 +753,7 @@ mod test { A::insert((3,), 10); A::insert((4,), 10); - A::remove_all(None); + let _ = A::clear(u32::max_value(), None); assert_eq!(A::contains_key((3,)), false); assert_eq!(A::contains_key((4,)), false); @@ -739,7 +808,7 @@ mod test { ] ); - WithLen::remove_all(None); + let _ = WithLen::clear(u32::max_value(), None); assert_eq!(WithLen::decode_len((3,)), None); WithLen::append((0,), 10); assert_eq!(WithLen::decode_len((0,)), Some(1)); @@ -750,26 +819,30 @@ mod test { fn test_2_keys() { type A = StorageNMap< Prefix, - (Key, Key), + (NMapKey, NMapKey), u32, OptionQuery, >; type AValueQueryWithAnOnEmpty = StorageNMap< Prefix, - (Key, Key), + (NMapKey, NMapKey), u32, ValueQuery, ADefault, >; - type B = StorageNMap, Key), u32, ValueQuery>; + type B = + StorageNMap, NMapKey), u32, ValueQuery>; type C = StorageNMap< Prefix, - (Key, Key), + (NMapKey, NMapKey), u8, ValueQuery, >; - type WithLen = - StorageNMap, Key), Vec>; + type WithLen = StorageNMap< + Prefix, + (NMapKey, NMapKey), + Vec, + >; TestExternalities::default().execute_with(|| { let mut k: Vec = vec![]; @@ -788,7 +861,10 @@ mod test { assert_eq!(A::get((3, 30)), Some(10)); assert_eq!(AValueQueryWithAnOnEmpty::get((3, 30)), 10); - A::swap::<(Key, Key), _, _>((3, 30), (2, 20)); + A::swap::<(NMapKey, NMapKey), _, _>( + (3, 30), + (2, 20), + ); assert_eq!(A::contains_key((3, 30)), false); assert_eq!(A::contains_key((2, 20)), true); assert_eq!(A::get((3, 30)), None); @@ -877,7 +953,7 @@ mod test { A::insert((3, 30), 10); A::insert((4, 40), 10); - A::remove_all(None); + let _ = A::clear(u32::max_value(), None); assert_eq!(A::contains_key((3, 30)), false); assert_eq!(A::contains_key((4, 40)), false); @@ -938,7 +1014,7 @@ mod test { ] ); - WithLen::remove_all(None); + let _ = WithLen::clear(u32::max_value(), None); assert_eq!(WithLen::decode_len((3, 30)), None); WithLen::append((0, 100), 10); assert_eq!(WithLen::decode_len((0, 100)), Some(1)); @@ -956,32 +1032,48 @@ mod test { fn test_3_keys() { type A = StorageNMap< Prefix, - (Key, Key, Key), + ( + NMapKey, + NMapKey, + NMapKey, + ), u32, OptionQuery, >; type AValueQueryWithAnOnEmpty = StorageNMap< Prefix, - (Key, Key, Key), + ( + NMapKey, + NMapKey, + NMapKey, + ), u32, ValueQuery, ADefault, >; type B = StorageNMap< Prefix, - (Key, Key, Key), + (NMapKey, NMapKey, NMapKey), u32, ValueQuery, >; type C = StorageNMap< Prefix, - (Key, Key, Key), + ( + NMapKey, + NMapKey, + NMapKey, + ), u8, ValueQuery, >; type WithLen = StorageNMap< Prefix, - (Key, Key, Key), + ( + NMapKey, + NMapKey, + NMapKey, + ), Vec, >; @@ -1004,7 +1096,11 @@ mod test { assert_eq!(AValueQueryWithAnOnEmpty::get((1, 10, 100)), 30); A::swap::< - (Key, Key, Key), + ( + NMapKey, + NMapKey, + NMapKey, + ), _, _, >((1, 10, 100), (2, 20, 200)); @@ -1093,7 +1189,7 @@ mod test { A::insert((3, 30, 300), 10); A::insert((4, 40, 400), 10); - A::remove_all(None); + let _ = A::clear(u32::max_value(), None); assert_eq!(A::contains_key((3, 30, 300)), false); assert_eq!(A::contains_key((4, 40, 400)), false); @@ -1161,7 +1257,7 @@ mod test { ] ); - WithLen::remove_all(None); + let _ = WithLen::clear(u32::max_value(), None); assert_eq!(WithLen::decode_len((3, 30, 300)), None); WithLen::append((0, 100, 1000), 10); assert_eq!(WithLen::decode_len((0, 100, 1000)), Some(1)); diff --git a/frame/support/src/storage/unhashed.rs b/frame/support/src/storage/unhashed.rs index adabc9c14a3d5..fc6d8ae79c57d 100644 --- a/frame/support/src/storage/unhashed.rs +++ b/frame/support/src/storage/unhashed.rs @@ -96,10 +96,63 @@ pub fn kill(key: &[u8]) { } /// Ensure keys with the given `prefix` have no entries in storage. +#[deprecated = "Use `clear_prefix` instead"] pub fn kill_prefix(prefix: &[u8], limit: Option) -> sp_io::KillStorageResult { + // TODO: Once the network has upgraded to include the new host functions, this code can be + // enabled. + // clear_prefix(prefix, limit).into() sp_io::storage::clear_prefix(prefix, limit) } +/// Partially clear the storage of all keys under a common `prefix`. +/// +/// # Limit +/// +/// A *limit* should always be provided through `maybe_limit`. This is one fewer than the +/// maximum number of backend iterations which may be done by this operation and as such +/// represents the maximum number of backend deletions which may happen. A *limit* of zero +/// implies that no keys will be deleted, though there may be a single iteration done. +/// +/// The limit can be used to partially delete storage items in case it is too large or costly +/// to delete all in a single operation. +/// +/// # Cursor +/// +/// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be +/// passed once (in the initial call) for any attempt to clear storage. In general, subsequent calls +/// operating on the same prefix should pass `Some` and this value should be equal to the +/// previous call result's `maybe_cursor` field. The only exception to this is when you can +/// guarantee that the subsequent call is in a new block; in this case the previous call's result +/// cursor need not be passed in an a `None` may be passed instead. This exception may be useful +/// then making this call solely from a block-hook such as `on_initialize`. +/// +/// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once the +/// resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. +/// +/// NOTE: After the initial call for any given child storage, it is important that no keys further +/// keys are inserted. If so, then they may or may not be deleted by subsequent calls. +/// +/// # Note +/// +/// Please note that keys which are residing in the overlay for the child are deleted without +/// counting towards the `limit`. +pub fn clear_prefix( + prefix: &[u8], + maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, +) -> sp_io::MultiRemovalResults { + // TODO: Once the network has upgraded to include the new host functions, this code can be + // enabled. + // sp_io::storage::clear_prefix(prefix, maybe_limit, maybe_cursor) + use sp_io::{KillStorageResult::*, MultiRemovalResults}; + #[allow(deprecated)] + let (maybe_cursor, i) = match kill_prefix(prefix, maybe_limit) { + AllRemoved(i) => (None, i), + SomeRemaining(i) => (Some(prefix.to_vec()), i), + }; + MultiRemovalResults { maybe_cursor, backend: i, unique: i, loops: i } +} + /// Get a Vec of bytes from storage. pub fn get_raw(key: &[u8]) -> Option> { sp_io::storage::get(key) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index ba494dfbd9f8c..f2999f945c5c2 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -475,7 +475,7 @@ pub mod pallet { _subkeys: u32, ) -> DispatchResultWithPostInfo { ensure_root(origin)?; - storage::unhashed::kill_prefix(&prefix, None); + let _ = storage::unhashed::clear_prefix(&prefix, None, None); Ok(().into()) } @@ -1427,7 +1427,7 @@ impl Pallet { pub fn reset_events() { >::kill(); EventCount::::kill(); - >::remove_all(None); + let _ = >::clear(u32::max_value(), None); } /// Assert the given `event` exists. diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index cdaa31d4e1c8a..c5220b562b172 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -110,8 +110,10 @@ impl, I: 'static> Pallet { for (item, details) in Item::::drain_prefix(&collection) { Account::::remove((&details.owner, &collection, &item)); } + #[allow(deprecated)] ItemMetadataOf::::remove_prefix(&collection, None); CollectionMetadataOf::::remove(&collection); + #[allow(deprecated)] Attribute::::remove_prefix((&collection,), None); CollectionAccount::::remove(&collection_details.owner, &collection); T::Currency::unreserve(&collection_details.owner, collection_details.total_deposit); diff --git a/primitives/externalities/src/lib.rs b/primitives/externalities/src/lib.rs index 49b190b4ae260..b343b8c393e00 100644 --- a/primitives/externalities/src/lib.rs +++ b/primitives/externalities/src/lib.rs @@ -52,6 +52,30 @@ pub enum Error { StorageUpdateFailed(&'static str), } +/// Results concerning an operation to remove many keys. +#[derive(codec::Encode, codec::Decode)] +#[must_use] +pub struct MultiRemovalResults { + /// A continuation cursor which, if `Some` must be provided to the subsequent removal call. + /// If `None` then all removals are complete and no further calls are needed. + pub maybe_cursor: Option>, + /// The number of items removed from the backend database. + pub backend: u32, + /// The number of unique keys removed, taking into account both the backend and the overlay. + pub unique: u32, + /// The number of iterations (each requiring a storage seek/read) which were done. + pub loops: u32, +} + +impl MultiRemovalResults { + /// Deconstruct into the internal components. + /// + /// Returns `(maybe_cursor, backend, unique, loops)`. + pub fn deconstruct(self) -> (Option>, u32, u32, u32) { + (self.maybe_cursor, self.backend, self.unique, self.loops) + } +} + /// The Substrate externalities. /// /// Provides access to the storage and to other registered extensions. @@ -118,32 +142,47 @@ pub trait Externalities: ExtensionStore { /// Clear an entire child storage. /// - /// Deletes all keys from the overlay and up to `limit` keys from the backend. No - /// limit is applied if `limit` is `None`. Returned boolean is `true` if the child trie was - /// removed completely and `false` if there are remaining keys after the function - /// returns. Returned `u32` is the number of keys that was removed at the end of the - /// operation. + /// Deletes all keys from the overlay and up to `maybe_limit` keys from the backend. No + /// limit is applied if `maybe_limit` is `None`. Returns the cursor for the next call as `Some` + /// if the child trie deletion operation is incomplete. In this case, it should be passed into + /// the next call to avoid unaccounted iterations on the backend. Returns also the the number + /// of keys that were removed from the backend, the number of unique keys removed in total + /// (including from the overlay) and the number of backend iterations done. + /// + /// As long as `maybe_cursor` is passed from the result of the previous call, then the number of + /// iterations done will only ever be one more than the number of keys removed. /// /// # Note /// /// An implementation is free to delete more keys than the specified limit as long as /// it is able to do that in constant time. - fn kill_child_storage(&mut self, child_info: &ChildInfo, limit: Option) -> (bool, u32); + fn kill_child_storage( + &mut self, + child_info: &ChildInfo, + maybe_limit: Option, + maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults; /// Clear storage entries which keys are start with the given prefix. /// - /// `limit` and result works as for `kill_child_storage`. - fn clear_prefix(&mut self, prefix: &[u8], limit: Option) -> (bool, u32); + /// `maybe_limit`, `maybe_cursor` and result works as for `kill_child_storage`. + fn clear_prefix( + &mut self, + prefix: &[u8], + maybe_limit: Option, + maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults; /// Clear child storage entries which keys are start with the given prefix. /// - /// `limit` and result works as for `kill_child_storage`. + /// `maybe_limit`, `maybe_cursor` and result works as for `kill_child_storage`. fn clear_child_prefix( &mut self, child_info: &ChildInfo, prefix: &[u8], - limit: Option, - ) -> (bool, u32); + maybe_limit: Option, + maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults; /// Set or clear a storage entry (`key`) of current contract being called (effective /// immediately). diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index bd288dd896d1b..09a087d509416 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -25,7 +25,7 @@ sp-state-machine = { version = "0.12.0", optional = true, path = "../state-machi sp-wasm-interface = { version = "6.0.0", path = "../wasm-interface", default-features = false } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } sp-trie = { version = "6.0.0", optional = true, path = "../trie" } -sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } +sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.17", optional = true } futures = { version = "0.3.21", features = ["thread-pool"], optional = true } @@ -37,6 +37,7 @@ tracing-core = { version = "0.1.26", default-features = false} [features] default = ["std"] std = [ + "sp-externalities/std", "sp-core/std", "sp-keystore", "codec/std", @@ -47,7 +48,6 @@ std = [ "libsecp256k1", "secp256k1", "sp-runtime-interface/std", - "sp-externalities", "sp-wasm-interface/std", "sp-tracing/std", "tracing/std", diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 8f62b03b62ea9..0a931919437af 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -81,6 +81,8 @@ mod batch_verifier; #[cfg(feature = "std")] use batch_verifier::BatchVerifier; +pub use sp_externalities::MultiRemovalResults; + #[cfg(feature = "std")] const LOG_TARGET: &str = "runtime::io"; @@ -99,12 +101,24 @@ pub enum EcdsaVerifyError { /// removed from the backend from making the `storage_kill` call. #[derive(PassByCodec, Encode, Decode)] pub enum KillStorageResult { - /// All key to remove were removed, return number of key removed from backend. + /// All keys to remove were removed, return number of iterations performed during the + /// operation. AllRemoved(u32), - /// Not all key to remove were removed, return number of key removed from backend. + /// Not all key to remove were removed, return number of iterations performed during the + /// operation. SomeRemaining(u32), } +impl From for KillStorageResult { + fn from(r: MultiRemovalResults) -> Self { + match r { + MultiRemovalResults { maybe_cursor: None, backend, .. } => Self::AllRemoved(backend), + MultiRemovalResults { maybe_cursor: Some(..), backend, .. } => + Self::SomeRemaining(backend), + } + } +} + /// Interface for accessing the storage from within the runtime. #[runtime_interface] pub trait Storage { @@ -145,7 +159,7 @@ pub trait Storage { /// Clear the storage of each key-value pair where the key starts with the given `prefix`. fn clear_prefix(&mut self, prefix: &[u8]) { - let _ = Externalities::clear_prefix(*self, prefix, None); + let _ = Externalities::clear_prefix(*self, prefix, None, None); } /// Clear the storage of each key-value pair where the key starts with the given `prefix`. @@ -175,13 +189,60 @@ pub trait Storage { /// backend. #[version(2)] fn clear_prefix(&mut self, prefix: &[u8], limit: Option) -> KillStorageResult { - let (all_removed, num_removed) = Externalities::clear_prefix(*self, prefix, limit); - match all_removed { - true => KillStorageResult::AllRemoved(num_removed), - false => KillStorageResult::SomeRemaining(num_removed), + let r = Externalities::clear_prefix(*self, prefix, limit, None); + match r.maybe_cursor { + None => KillStorageResult::AllRemoved(r.loops), + Some(_) => KillStorageResult::SomeRemaining(r.loops), } } + /// Partially clear the storage of each key-value pair where the key starts with the given + /// prefix. + /// + /// # Limit + /// + /// A *limit* should always be provided through `maybe_limit`. This is one fewer than the + /// maximum number of backend iterations which may be done by this operation and as such + /// represents the maximum number of backend deletions which may happen. A *limit* of zero + /// implies that no keys will be deleted, though there may be a single iteration done. + /// + /// The limit can be used to partially delete a prefix storage in case it is too large or costly + /// to delete in a single operation. + /// + /// # Cursor + /// + /// A *cursor* may be passed in to this operation with `maybe_cursor`. `None` should only be + /// passed once (in the initial call) for any given `maybe_prefix` value. Subsequent calls + /// operating on the same prefix should always pass `Some`, and this should be equal to the + /// previous call result's `maybe_cursor` field. + /// + /// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once + /// the resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + /// + /// NOTE: After the initial call for any given prefix, it is important that no keys further + /// keys under the same prefix are inserted. If so, then they may or may not be deleted by + /// subsequent calls. + /// + /// # Note + /// + /// Please note that keys which are residing in the overlay for that prefix when + /// issuing this call are deleted without counting towards the `limit`. + #[version(3, register_only)] + fn clear_prefix( + &mut self, + maybe_prefix: &[u8], + maybe_limit: Option, + maybe_cursor: Option>, //< TODO Make work or just Option>? + ) -> MultiRemovalResults { + Externalities::clear_prefix( + *self, + maybe_prefix, + maybe_limit, + maybe_cursor.as_ref().map(|x| &x[..]), + ) + .into() + } + /// Append the encoded `value` to the storage item at `key`. /// /// The storage item needs to implement [`EncodeAppend`](codec::EncodeAppend). @@ -323,7 +384,7 @@ pub trait DefaultChildStorage { /// is removed. fn storage_kill(&mut self, storage_key: &[u8]) { let child_info = ChildInfo::new_default(storage_key); - self.kill_child_storage(&child_info, None); + let _ = self.kill_child_storage(&child_info, None, None); } /// Clear a child storage key. @@ -332,8 +393,8 @@ pub trait DefaultChildStorage { #[version(2)] fn storage_kill(&mut self, storage_key: &[u8], limit: Option) -> bool { let child_info = ChildInfo::new_default(storage_key); - let (all_removed, _num_removed) = self.kill_child_storage(&child_info, limit); - all_removed + let r = self.kill_child_storage(&child_info, limit, None); + r.maybe_cursor.is_none() } /// Clear a child storage key. @@ -342,13 +403,28 @@ pub trait DefaultChildStorage { #[version(3)] fn storage_kill(&mut self, storage_key: &[u8], limit: Option) -> KillStorageResult { let child_info = ChildInfo::new_default(storage_key); - let (all_removed, num_removed) = self.kill_child_storage(&child_info, limit); - match all_removed { - true => KillStorageResult::AllRemoved(num_removed), - false => KillStorageResult::SomeRemaining(num_removed), + let r = self.kill_child_storage(&child_info, limit, None); + match r.maybe_cursor { + None => KillStorageResult::AllRemoved(r.loops), + Some(..) => KillStorageResult::SomeRemaining(r.loops), } } + /// Clear a child storage key. + /// + /// See `Storage` module `clear_prefix` documentation for `limit` usage. + #[version(4, register_only)] + fn storage_kill( + &mut self, + storage_key: &[u8], + maybe_limit: Option, + maybe_cursor: Option>, + ) -> MultiRemovalResults { + let child_info = ChildInfo::new_default(storage_key); + self.kill_child_storage(&child_info, maybe_limit, maybe_cursor.as_ref().map(|x| &x[..])) + .into() + } + /// Check a child storage key. /// /// Check whether the given `key` exists in default child defined at `storage_key`. @@ -362,7 +438,7 @@ pub trait DefaultChildStorage { /// Clear the child storage of each key-value pair where the key starts with the given `prefix`. fn clear_prefix(&mut self, storage_key: &[u8], prefix: &[u8]) { let child_info = ChildInfo::new_default(storage_key); - let _ = self.clear_child_prefix(&child_info, prefix, None); + let _ = self.clear_child_prefix(&child_info, prefix, None, None); } /// Clear the child storage of each key-value pair where the key starts with the given `prefix`. @@ -376,13 +452,34 @@ pub trait DefaultChildStorage { limit: Option, ) -> KillStorageResult { let child_info = ChildInfo::new_default(storage_key); - let (all_removed, num_removed) = self.clear_child_prefix(&child_info, prefix, limit); - match all_removed { - true => KillStorageResult::AllRemoved(num_removed), - false => KillStorageResult::SomeRemaining(num_removed), + let r = self.clear_child_prefix(&child_info, prefix, limit, None); + match r.maybe_cursor { + None => KillStorageResult::AllRemoved(r.loops), + Some(..) => KillStorageResult::SomeRemaining(r.loops), } } + /// Clear the child storage of each key-value pair where the key starts with the given `prefix`. + /// + /// See `Storage` module `clear_prefix` documentation for `limit` usage. + #[version(3, register_only)] + fn clear_prefix( + &mut self, + storage_key: &[u8], + prefix: &[u8], + maybe_limit: Option, + maybe_cursor: Option>, + ) -> MultiRemovalResults { + let child_info = ChildInfo::new_default(storage_key); + self.clear_child_prefix( + &child_info, + prefix, + maybe_limit, + maybe_cursor.as_ref().map(|x| &x[..]), + ) + .into() + } + /// Default child root calculation. /// /// "Commit" all existing operations and compute the resulting child storage root. @@ -1757,15 +1854,30 @@ mod tests { }); t.execute_with(|| { + // We can switch to this once we enable v3 of the `clear_prefix`. + //assert!(matches!( + // storage::clear_prefix(b":abc", None), + // MultiRemovalResults::NoneLeft { db: 2, total: 2 } + //)); assert!(matches!( storage::clear_prefix(b":abc", None), - KillStorageResult::AllRemoved(2) + KillStorageResult::AllRemoved(2), )); assert!(storage::get(b":a").is_some()); assert!(storage::get(b":abdd").is_some()); assert!(storage::get(b":abcd").is_none()); assert!(storage::get(b":abc").is_none()); + + // We can switch to this once we enable v3 of the `clear_prefix`. + //assert!(matches!( + // storage::clear_prefix(b":abc", None), + // MultiRemovalResults::NoneLeft { db: 0, total: 0 } + //)); + assert!(matches!( + storage::clear_prefix(b":abc", None), + KillStorageResult::AllRemoved(0), + )); }); } diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index c9419f73722c6..8cd31bab559ea 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -18,7 +18,7 @@ sp-wasm-interface = { version = "6.0.0", path = "../wasm-interface", default-fea sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } sp-runtime-interface-proc-macro = { version = "5.0.0", path = "proc-macro" } -sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } +sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } static_assertions = "1.0.0" primitive-types = { version = "0.11.1", default-features = false } @@ -40,7 +40,7 @@ std = [ "sp-std/std", "sp-tracing/std", "codec/std", - "sp-externalities", + "sp-externalities/std", "primitive-types/std", ] diff --git a/primitives/runtime-interface/src/impls.rs b/primitives/runtime-interface/src/impls.rs index 3c1927d6b361a..e801931c306cf 100644 --- a/primitives/runtime-interface/src/impls.rs +++ b/primitives/runtime-interface/src/impls.rs @@ -548,3 +548,7 @@ impl PassBy for sp_storage::TrackedStorageKey { impl PassBy for sp_storage::StateVersion { type PassBy = Enum; } + +impl PassBy for sp_externalities::MultiRemovalResults { + type PassBy = Codec; +} diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index e472b66c5d9ee..1c652966180a7 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -35,6 +35,7 @@ hex-literal = "0.3.4" pretty_assertions = "1.2.1" rand = "0.7.2" sp-runtime = { version = "6.0.0", path = "../runtime" } +assert_matches = "1.5" [features] default = ["std"] diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index e9d4ac0fb8224..505b53c800f9e 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -112,6 +112,7 @@ pub trait Backend: sp_std::fmt::Debug { &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, + start_at: Option<&[u8]>, f: F, ); diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index bb387e6406243..6efc847bfbdb7 100644 --- a/primitives/state-machine/src/basic.rs +++ b/primitives/state-machine/src/basic.rs @@ -29,7 +29,7 @@ use sp_core::{ traits::Externalities, Blake2Hasher, }; -use sp_externalities::{Extension, Extensions}; +use sp_externalities::{Extension, Extensions, MultiRemovalResults}; use sp_trie::{empty_child_trie_root, HashKey, LayoutV0, LayoutV1, TrieConfiguration}; use std::{ any::{Any, TypeId}, @@ -209,23 +209,34 @@ impl Externalities for BasicExternalities { } } - fn kill_child_storage(&mut self, child_info: &ChildInfo, _limit: Option) -> (bool, u32) { - let num_removed = self + fn kill_child_storage( + &mut self, + child_info: &ChildInfo, + _maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { + let count = self .inner .children_default .remove(child_info.storage_key()) .map(|c| c.data.len()) - .unwrap_or(0); - (true, num_removed as u32) + .unwrap_or(0) as u32; + MultiRemovalResults { maybe_cursor: None, backend: count, unique: count, loops: count } } - fn clear_prefix(&mut self, prefix: &[u8], _limit: Option) -> (bool, u32) { + fn clear_prefix( + &mut self, + prefix: &[u8], + _maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { if is_child_storage_key(prefix) { warn!( target: "trie", "Refuse to clear prefix that is part of child storage key via main storage" ); - return (false, 0) + let maybe_cursor = Some(prefix.to_vec()); + return MultiRemovalResults { maybe_cursor, backend: 0, unique: 0, loops: 0 } } let to_remove = self @@ -237,19 +248,20 @@ impl Externalities for BasicExternalities { .cloned() .collect::>(); - let num_removed = to_remove.len(); + let count = to_remove.len() as u32; for key in to_remove { self.inner.top.remove(&key); } - (true, num_removed as u32) + MultiRemovalResults { maybe_cursor: None, backend: count, unique: count, loops: count } } fn clear_child_prefix( &mut self, child_info: &ChildInfo, prefix: &[u8], - _limit: Option, - ) -> (bool, u32) { + _maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { if let Some(child) = self.inner.children_default.get_mut(child_info.storage_key()) { let to_remove = child .data @@ -259,13 +271,13 @@ impl Externalities for BasicExternalities { .cloned() .collect::>(); - let num_removed = to_remove.len(); + let count = to_remove.len() as u32; for key in to_remove { child.data.remove(&key); } - (true, num_removed as u32) + MultiRemovalResults { maybe_cursor: None, backend: count, unique: count, loops: count } } else { - (true, 0) + MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 } } } @@ -434,7 +446,7 @@ mod tests { ext.clear_child_storage(child_info, b"dog"); assert_eq!(ext.child_storage(child_info, b"dog"), None); - ext.kill_child_storage(child_info, None); + let _ = ext.kill_child_storage(child_info, None, None); assert_eq!(ext.child_storage(child_info, b"doe"), None); } @@ -456,8 +468,8 @@ mod tests { ], }); - let res = ext.kill_child_storage(child_info, None); - assert_eq!(res, (true, 3)); + let res = ext.kill_child_storage(child_info, None, None); + assert_eq!(res.deconstruct(), (None, 3, 3, 3)); } #[test] diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index e33569e2a1f67..1db0ec517015b 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -27,7 +27,7 @@ use sp_core::hexdisplay::HexDisplay; use sp_core::storage::{ well_known_keys::is_child_storage_key, ChildInfo, StateVersion, TrackedStorageKey, }; -use sp_externalities::{Extension, ExtensionStore, Externalities}; +use sp_externalities::{Extension, ExtensionStore, Externalities, MultiRemovalResults}; use sp_trie::{empty_child_trie_root, LayoutV1}; use crate::{log_error, trace, warn, StorageTransactionCache}; @@ -433,7 +433,12 @@ where self.overlay.set_child_storage(child_info, key, value); } - fn kill_child_storage(&mut self, child_info: &ChildInfo, limit: Option) -> (bool, u32) { + fn kill_child_storage( + &mut self, + child_info: &ChildInfo, + maybe_limit: Option, + maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { trace!( target: "state", method = "ChildKill", @@ -442,11 +447,18 @@ where ); let _guard = guard(); self.mark_dirty(); - self.overlay.clear_child_storage(child_info); - self.limit_remove_from_backend(Some(child_info), None, limit) + let overlay = self.overlay.clear_child_storage(child_info); + let (maybe_cursor, backend, loops) = + self.limit_remove_from_backend(Some(child_info), None, maybe_limit, maybe_cursor); + MultiRemovalResults { maybe_cursor, backend, unique: overlay + backend, loops } } - fn clear_prefix(&mut self, prefix: &[u8], limit: Option) -> (bool, u32) { + fn clear_prefix( + &mut self, + prefix: &[u8], + maybe_limit: Option, + maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { trace!( target: "state", method = "ClearPrefix", @@ -460,20 +472,23 @@ where target: "trie", "Refuse to directly clear prefix that is part or contains of child storage key", ); - return (false, 0) + return MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 } } self.mark_dirty(); - self.overlay.clear_prefix(prefix); - self.limit_remove_from_backend(None, Some(prefix), limit) + let overlay = self.overlay.clear_prefix(prefix); + let (maybe_cursor, backend, loops) = + self.limit_remove_from_backend(None, Some(prefix), maybe_limit, maybe_cursor); + MultiRemovalResults { maybe_cursor, backend, unique: overlay + backend, loops } } fn clear_child_prefix( &mut self, child_info: &ChildInfo, prefix: &[u8], - limit: Option, - ) -> (bool, u32) { + maybe_limit: Option, + maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { trace!( target: "state", method = "ChildClearPrefix", @@ -484,8 +499,14 @@ where let _guard = guard(); self.mark_dirty(); - self.overlay.clear_child_prefix(child_info, prefix); - self.limit_remove_from_backend(Some(child_info), Some(prefix), limit) + let overlay = self.overlay.clear_child_prefix(child_info, prefix); + let (maybe_cursor, backend, loops) = self.limit_remove_from_backend( + Some(child_info), + Some(prefix), + maybe_limit, + maybe_cursor, + ); + MultiRemovalResults { maybe_cursor, backend, unique: overlay + backend, loops } } fn storage_append(&mut self, key: Vec, value: Vec) { @@ -728,45 +749,37 @@ where { fn limit_remove_from_backend( &mut self, - child_info: Option<&ChildInfo>, - prefix: Option<&[u8]>, - limit: Option, - ) -> (bool, u32) { - let mut num_deleted: u32 = 0; - - if let Some(limit) = limit { - let mut all_deleted = true; - self.backend.apply_to_keys_while(child_info, prefix, |key| { - if num_deleted == limit { - all_deleted = false; - return false - } - if let Some(num) = num_deleted.checked_add(1) { - num_deleted = num; - } else { - all_deleted = false; + maybe_child: Option<&ChildInfo>, + maybe_prefix: Option<&[u8]>, + maybe_limit: Option, + maybe_cursor: Option<&[u8]>, + ) -> (Option>, u32, u32) { + let mut delete_count: u32 = 0; + let mut loop_count: u32 = 0; + let mut maybe_next_key = None; + self.backend + .apply_to_keys_while(maybe_child, maybe_prefix, maybe_cursor, |key| { + if maybe_limit.map_or(false, |limit| loop_count == limit) { + maybe_next_key = Some(key.to_vec()); return false } - if let Some(child_info) = child_info { - self.overlay.set_child_storage(child_info, key.to_vec(), None); - } else { - self.overlay.set_storage(key.to_vec(), None); - } - true - }); - (all_deleted, num_deleted) - } else { - self.backend.apply_to_keys_while(child_info, prefix, |key| { - num_deleted = num_deleted.saturating_add(1); - if let Some(child_info) = child_info { - self.overlay.set_child_storage(child_info, key.to_vec(), None); - } else { - self.overlay.set_storage(key.to_vec(), None); + let overlay = match maybe_child { + Some(child_info) => self.overlay.child_storage(child_info, key), + None => self.overlay.storage(key), + }; + if !matches!(overlay, Some(None)) { + // not pending deletion from the backend - delete it. + if let Some(child_info) = maybe_child { + self.overlay.set_child_storage(child_info, key.to_vec(), None); + } else { + self.overlay.set_storage(key.to_vec(), None); + } + delete_count = delete_count.saturating_add(1); } + loop_count = loop_count.saturating_add(1); true }); - (true, num_deleted) - } + (maybe_next_key, delete_count, loop_count) } } @@ -1085,14 +1098,14 @@ mod tests { not_under_prefix.extend(b"path"); ext.set_storage(not_under_prefix.clone(), vec![10]); - ext.clear_prefix(&[], None); - ext.clear_prefix(&well_known_keys::CHILD_STORAGE_KEY_PREFIX[..4], None); + let _ = ext.clear_prefix(&[], None, None); + let _ = ext.clear_prefix(&well_known_keys::CHILD_STORAGE_KEY_PREFIX[..4], None, None); let mut under_prefix = well_known_keys::CHILD_STORAGE_KEY_PREFIX.to_vec(); under_prefix.extend(b"path"); - ext.clear_prefix(&well_known_keys::CHILD_STORAGE_KEY_PREFIX[..4], None); + let _ = ext.clear_prefix(&well_known_keys::CHILD_STORAGE_KEY_PREFIX[..4], None, None); assert_eq!(ext.child_storage(child_info, &[30]), Some(vec![40])); assert_eq!(ext.storage(not_under_prefix.as_slice()), Some(vec![10])); - ext.clear_prefix(¬_under_prefix[..5], None); + let _ = ext.clear_prefix(¬_under_prefix[..5], None, None); assert_eq!(ext.storage(not_under_prefix.as_slice()), None); } diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index e5b521588aa79..edc3db7a60e36 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -1348,6 +1348,7 @@ mod execution { mod tests { use super::{ext::Ext, *}; use crate::{execution::CallResult, in_memory_backend::new_in_mem_hash_key}; + use assert_matches::assert_matches; use codec::{Decode, Encode}; use sp_core::{ map, @@ -1572,7 +1573,7 @@ mod tests { { let mut cache = StorageTransactionCache::default(); let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); - ext.clear_prefix(b"ab", None); + let _ = ext.clear_prefix(b"ab", None, None); } overlay.commit_transaction().unwrap(); @@ -1596,7 +1597,10 @@ mod tests { { let mut cache = StorageTransactionCache::default(); let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); - assert_eq!((false, 1), ext.clear_prefix(b"ab", Some(1))); + assert_matches!( + ext.clear_prefix(b"ab", Some(1), None).deconstruct(), + (Some(_), 1, 3, 1) + ); } overlay.commit_transaction().unwrap(); @@ -1638,7 +1642,8 @@ mod tests { { let mut cache = StorageTransactionCache::default(); let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); - assert_eq!(ext.kill_child_storage(&child_info, Some(2)), (false, 2)); + let r = ext.kill_child_storage(&child_info, Some(2), None); + assert_matches!(r.deconstruct(), (Some(_), 2, 6, 2)); } assert_eq!( @@ -1673,14 +1678,37 @@ mod tests { let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); - assert_eq!(ext.kill_child_storage(&child_info, Some(0)), (false, 0)); - assert_eq!(ext.kill_child_storage(&child_info, Some(1)), (false, 1)); - assert_eq!(ext.kill_child_storage(&child_info, Some(2)), (false, 2)); - assert_eq!(ext.kill_child_storage(&child_info, Some(3)), (false, 3)); - assert_eq!(ext.kill_child_storage(&child_info, Some(4)), (true, 4)); - // Only 4 items to remove - assert_eq!(ext.kill_child_storage(&child_info, Some(5)), (true, 4)); - assert_eq!(ext.kill_child_storage(&child_info, None), (true, 4)); + let r = ext.kill_child_storage(&child_info, Some(0), None).deconstruct(); + assert_matches!(r, (Some(_), 0, 0, 0)); + let r = ext + .kill_child_storage(&child_info, Some(1), r.0.as_ref().map(|x| &x[..])) + .deconstruct(); + assert_matches!(r, (Some(_), 1, 1, 1)); + let r = ext + .kill_child_storage(&child_info, Some(4), r.0.as_ref().map(|x| &x[..])) + .deconstruct(); + // Only 3 items remaining to remove + assert_matches!(r, (None, 3, 3, 3)); + let r = ext.kill_child_storage(&child_info, Some(1), None).deconstruct(); + assert_matches!(r, (Some(_), 0, 0, 1)); + } + + #[test] + fn limited_child_kill_off_by_one_works_without_limit() { + let child_info = ChildInfo::new_default(b"sub1"); + let initial: HashMap<_, BTreeMap<_, _>> = map![ + Some(child_info.clone()) => map![ + b"a".to_vec() => b"0".to_vec(), + b"b".to_vec() => b"1".to_vec(), + b"c".to_vec() => b"2".to_vec(), + b"d".to_vec() => b"3".to_vec() + ], + ]; + let backend = InMemoryBackend::::from((initial, StateVersion::default())); + let mut overlay = OverlayedChanges::default(); + let mut cache = StorageTransactionCache::default(); + let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); + assert_eq!(ext.kill_child_storage(&child_info, None, None).deconstruct(), (None, 4, 4, 4)); } #[test] @@ -1695,7 +1723,7 @@ mod tests { ext.set_child_storage(child_info, b"abc".to_vec(), b"def".to_vec()); assert_eq!(ext.child_storage(child_info, b"abc"), Some(b"def".to_vec())); - ext.kill_child_storage(child_info, None); + let _ = ext.kill_child_storage(child_info, None, None); assert_eq!(ext.child_storage(child_info, b"abc"), None); } diff --git a/primitives/state-machine/src/overlayed_changes/changeset.rs b/primitives/state-machine/src/overlayed_changes/changeset.rs index 9e7f6ffeddfd7..ae5d47f6bb943 100644 --- a/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -410,10 +410,15 @@ impl OverlayedChangeSet { &mut self, predicate: impl Fn(&[u8], &OverlayedValue) -> bool, at_extrinsic: Option, - ) { + ) -> u32 { + let mut count = 0; for (key, val) in self.changes.iter_mut().filter(|(k, v)| predicate(k, v)) { + if val.value_ref().is_some() { + count += 1; + } val.set(None, insert_dirty(&mut self.dirty_keys, key.clone()), at_extrinsic); } + count } /// Get the iterator over all changes that follow the supplied `key`. diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index 2161b343711c9..746599a6768e6 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -299,7 +299,7 @@ impl OverlayedChanges { /// Clear child storage of given storage key. /// /// Can be rolled back or committed when called inside a transaction. - pub(crate) fn clear_child_storage(&mut self, child_info: &ChildInfo) { + pub(crate) fn clear_child_storage(&mut self, child_info: &ChildInfo) -> u32 { let extrinsic_index = self.extrinsic_index(); let storage_key = child_info.storage_key().to_vec(); let top = &self.top; @@ -309,20 +309,20 @@ impl OverlayedChanges { .or_insert_with(|| (top.spawn_child(), child_info.clone())); let updatable = info.try_update(child_info); debug_assert!(updatable); - changeset.clear_where(|_, _| true, extrinsic_index); + changeset.clear_where(|_, _| true, extrinsic_index) } /// Removes all key-value pairs which keys share the given prefix. /// /// Can be rolled back or committed when called inside a transaction. - pub(crate) fn clear_prefix(&mut self, prefix: &[u8]) { - self.top.clear_where(|key, _| key.starts_with(prefix), self.extrinsic_index()); + pub(crate) fn clear_prefix(&mut self, prefix: &[u8]) -> u32 { + self.top.clear_where(|key, _| key.starts_with(prefix), self.extrinsic_index()) } /// Removes all key-value pairs which keys share the given prefix. /// /// Can be rolled back or committed when called inside a transaction - pub(crate) fn clear_child_prefix(&mut self, child_info: &ChildInfo, prefix: &[u8]) { + pub(crate) fn clear_child_prefix(&mut self, child_info: &ChildInfo, prefix: &[u8]) -> u32 { let extrinsic_index = self.extrinsic_index(); let storage_key = child_info.storage_key().to_vec(); let top = &self.top; @@ -332,7 +332,7 @@ impl OverlayedChanges { .or_insert_with(|| (top.spawn_child(), child_info.clone())); let updatable = info.try_update(child_info); debug_assert!(updatable); - changeset.clear_where(|key, _| key.starts_with(prefix), extrinsic_index); + changeset.clear_where(|key, _| key.starts_with(prefix), extrinsic_index) } /// Returns the current nesting depth of the transaction stack. diff --git a/primitives/state-machine/src/proving_backend.rs b/primitives/state-machine/src/proving_backend.rs index b47e6c693a3e8..f5cf542908b10 100644 --- a/primitives/state-machine/src/proving_backend.rs +++ b/primitives/state-machine/src/proving_backend.rs @@ -288,9 +288,10 @@ where &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, + start_at: Option<&[u8]>, f: F, ) { - self.0.apply_to_keys_while(child_info, prefix, f) + self.0.apply_to_keys_while(child_info, prefix, start_at, f) } fn next_storage_key(&self, key: &[u8]) -> Result>, Self::Error> { diff --git a/primitives/state-machine/src/read_only.rs b/primitives/state-machine/src/read_only.rs index 3c3e779c32f3a..622915a2d0525 100644 --- a/primitives/state-machine/src/read_only.rs +++ b/primitives/state-machine/src/read_only.rs @@ -25,6 +25,7 @@ use sp_core::{ traits::Externalities, Blake2Hasher, }; +use sp_externalities::MultiRemovalResults; use std::{ any::{Any, TypeId}, marker::PhantomData, @@ -124,11 +125,21 @@ impl<'a, H: Hasher, B: 'a + Backend> Externalities for ReadOnlyExternalities< unimplemented!("place_child_storage not supported in ReadOnlyExternalities") } - fn kill_child_storage(&mut self, _child_info: &ChildInfo, _limit: Option) -> (bool, u32) { + fn kill_child_storage( + &mut self, + _child_info: &ChildInfo, + _maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { unimplemented!("kill_child_storage is not supported in ReadOnlyExternalities") } - fn clear_prefix(&mut self, _prefix: &[u8], _limit: Option) -> (bool, u32) { + fn clear_prefix( + &mut self, + _prefix: &[u8], + _maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { unimplemented!("clear_prefix is not supported in ReadOnlyExternalities") } @@ -136,8 +147,9 @@ impl<'a, H: Hasher, B: 'a + Backend> Externalities for ReadOnlyExternalities< &mut self, _child_info: &ChildInfo, _prefix: &[u8], - _limit: Option, - ) -> (bool, u32) { + _maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { unimplemented!("clear_child_prefix is not supported in ReadOnlyExternalities") } diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index bc462ae01ab26..57d4f0b4898eb 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -381,7 +381,10 @@ mod tests { { let mut ext = ext.ext(); - assert!(!ext.kill_child_storage(&child_info, Some(2)).0, "Should not delete all keys"); + assert!( + ext.kill_child_storage(&child_info, Some(2), None).maybe_cursor.is_some(), + "Should not delete all keys" + ); assert!(ext.child_storage(&child_info, &b"doe"[..]).is_none()); assert!(ext.child_storage(&child_info, &b"dog"[..]).is_none()); diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index c0a620120bff2..130b4bf178202 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -123,9 +123,10 @@ where &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, + start_at: Option<&[u8]>, f: F, ) { - self.essence.apply_to_keys_while(child_info, prefix, f) + self.essence.apply_to_keys_while(child_info, prefix, start_at, f) } fn for_child_keys_with_prefix( diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 11cac92efd2f4..c55a6b7e80481 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -267,7 +267,8 @@ where &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, - mut f: F, + start_at: Option<&[u8]>, + f: F, ) { let root = if let Some(child_info) = child_info.as_ref() { match self.child_root(child_info) { @@ -283,7 +284,7 @@ where self.root }; - self.trie_iter_key_inner(&root, prefix, |k| f(k), child_info) + self.trie_iter_key_inner(&root, prefix, f, child_info, start_at) } /// Execute given closure for all keys starting with prefix. @@ -311,6 +312,7 @@ where true }, Some(child_info), + None, ) } @@ -324,28 +326,31 @@ where true }, None, + None, ) } fn trie_iter_key_inner bool>( &self, root: &H::Out, - prefix: Option<&[u8]>, + maybe_prefix: Option<&[u8]>, mut f: F, child_info: Option<&ChildInfo>, + maybe_start_at: Option<&[u8]>, ) { let mut iter = move |db| -> sp_std::result::Result<(), Box>> { let trie = TrieDB::::new(db, root)?; - let iter = if let Some(prefix) = prefix.as_ref() { - TrieDBKeyIterator::new_prefixed(&trie, prefix)? - } else { - TrieDBKeyIterator::new(&trie)? - }; + let prefix = maybe_prefix.unwrap_or(&[]); + let iter = match maybe_start_at { + Some(start_at) => + TrieDBKeyIterator::new_prefixed_then_seek(&trie, prefix, start_at), + None => TrieDBKeyIterator::new_prefixed(&trie, prefix), + }?; for x in iter { let key = x?; - debug_assert!(prefix + debug_assert!(maybe_prefix .as_ref() .map(|prefix| key.starts_with(prefix)) .unwrap_or(true)); diff --git a/primitives/tasks/src/async_externalities.rs b/primitives/tasks/src/async_externalities.rs index 70e3437538e8f..008955a714b21 100644 --- a/primitives/tasks/src/async_externalities.rs +++ b/primitives/tasks/src/async_externalities.rs @@ -22,7 +22,7 @@ use sp_core::{ storage::{ChildInfo, StateVersion, TrackedStorageKey}, traits::{Externalities, RuntimeSpawn, RuntimeSpawnExt, SpawnNamed, TaskExecutorExt}, }; -use sp_externalities::{Extensions, ExternalitiesExt as _}; +use sp_externalities::{Extensions, ExternalitiesExt as _, MultiRemovalResults}; use std::any::{Any, TypeId}; /// Simple state-less externalities for use in async context. @@ -105,11 +105,21 @@ impl Externalities for AsyncExternalities { panic!("`place_child_storage`: should not be used in async externalities!") } - fn kill_child_storage(&mut self, _child_info: &ChildInfo, _limit: Option) -> (bool, u32) { + fn kill_child_storage( + &mut self, + _child_info: &ChildInfo, + _maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { panic!("`kill_child_storage`: should not be used in async externalities!") } - fn clear_prefix(&mut self, _prefix: &[u8], _limit: Option) -> (bool, u32) { + fn clear_prefix( + &mut self, + _prefix: &[u8], + _maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { panic!("`clear_prefix`: should not be used in async externalities!") } @@ -117,8 +127,9 @@ impl Externalities for AsyncExternalities { &mut self, _child_info: &ChildInfo, _prefix: &[u8], - _limit: Option, - ) -> (bool, u32) { + _maybe_limit: Option, + _maybe_cursor: Option<&[u8]>, + ) -> MultiRemovalResults { panic!("`clear_child_prefix`: should not be used in async externalities!") } From 54a3ed42971fe1d922cb6f09f2013bfa3353cec2 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Mon, 30 May 2022 16:07:00 +0100 Subject: [PATCH 0855/1472] Use `loops` rather than `backend` for compatibility. (#11542) * Use `loops` rather than `backend` for compatibility. * Move over other converters --- primitives/io/src/lib.rs | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 0a931919437af..89b74dc3c6880 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -111,10 +111,12 @@ pub enum KillStorageResult { impl From for KillStorageResult { fn from(r: MultiRemovalResults) -> Self { - match r { - MultiRemovalResults { maybe_cursor: None, backend, .. } => Self::AllRemoved(backend), - MultiRemovalResults { maybe_cursor: Some(..), backend, .. } => - Self::SomeRemaining(backend), + // We use `loops` here rather than `backend` because that's the same as the original + // functionality pre-#11490. This won't matter once we switch to the new host function + // since we won't be using the `KillStorageResult` type in the runtime any more. + match r.maybe_cursor { + None => Self::AllRemoved(r.loops), + Some(..) => Self::SomeRemaining(r.loops), } } } @@ -189,11 +191,7 @@ pub trait Storage { /// backend. #[version(2)] fn clear_prefix(&mut self, prefix: &[u8], limit: Option) -> KillStorageResult { - let r = Externalities::clear_prefix(*self, prefix, limit, None); - match r.maybe_cursor { - None => KillStorageResult::AllRemoved(r.loops), - Some(_) => KillStorageResult::SomeRemaining(r.loops), - } + Externalities::clear_prefix(*self, prefix, limit, None).into() } /// Partially clear the storage of each key-value pair where the key starts with the given @@ -403,11 +401,7 @@ pub trait DefaultChildStorage { #[version(3)] fn storage_kill(&mut self, storage_key: &[u8], limit: Option) -> KillStorageResult { let child_info = ChildInfo::new_default(storage_key); - let r = self.kill_child_storage(&child_info, limit, None); - match r.maybe_cursor { - None => KillStorageResult::AllRemoved(r.loops), - Some(..) => KillStorageResult::SomeRemaining(r.loops), - } + self.kill_child_storage(&child_info, limit, None).into() } /// Clear a child storage key. @@ -452,11 +446,7 @@ pub trait DefaultChildStorage { limit: Option, ) -> KillStorageResult { let child_info = ChildInfo::new_default(storage_key); - let r = self.clear_child_prefix(&child_info, prefix, limit, None); - match r.maybe_cursor { - None => KillStorageResult::AllRemoved(r.loops), - Some(..) => KillStorageResult::SomeRemaining(r.loops), - } + self.clear_child_prefix(&child_info, prefix, limit, None).into() } /// Clear the child storage of each key-value pair where the key starts with the given `prefix`. From cbde83a8e2ab642285960efe9bb358e70c93e487 Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 31 May 2022 15:25:52 +0800 Subject: [PATCH 0856/1472] sp-core: impl serde for some offchain types (#11512) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * sp-core: impl serde for some offchain types * Update primitives/core/src/offchain/mod.rs Co-authored-by: Bastian Köcher * remove serde impls from OpaqueNetworkState/OpaqueMultiaddr * derive default Co-authored-by: Bastian Köcher --- primitives/core/src/offchain/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 4ffadc3e4031d..3f0eed87a3a64 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -208,12 +208,14 @@ impl OpaqueMultiaddr { #[derive( Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode, )] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct Timestamp(u64); /// Duration type #[derive( Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode, )] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct Duration(u64); impl Duration { From 54d6f2cbae12fa314f2bcaf6d57fba585162438f Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Tue, 31 May 2022 11:12:34 +0100 Subject: [PATCH 0857/1472] Several tweaks needed for Governance 2.0 (#11124) * Add stepped curve for referenda * Treasury SpendOrigin * Add tests * Better Origin Or-gating * Reciprocal curve * Tests for reciprical and rounding in PerThings * Tweaks and new quad curve * Const derivation of reciprocal curve parameters * Remove some unneeded code * Actually useful linear curve * Fixes * Provisional curves * Rejig 'turnout' as 'support' * Use TypedGet * Fixes * Enable curve's ceil to be configured * Formatting * Fixes * Fixes * Fixes * Remove EnsureOneOf * Fixes * Fixes * Fixes * Formatting * Fixes * Update frame/support/src/traits/dispatch.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Grumbles * Formatting * Fixes * APIs of VoteTally should include class * Fixes * Fix overlay prefix removal result * Second part of the overlay prefix removal fix. * Formatting * Fixes * Add some tests and make clear rounding algo * Fixes * Formatting * Revert questionable fix * Introduce test for kill_prefix * Fixes * Formatting * Fixes * Fix possible overflow * Docs * Add benchmark test * Formatting * Update frame/referenda/src/types.rs Co-authored-by: Keith Yeung * Docs * Fixes * Use latest API in tests * Formatting * Whitespace * Use latest API in tests Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Keith Yeung --- Cargo.lock | 2 + bin/node/runtime/src/lib.rs | 25 +- docs/Upgrading-2.0-to-3.0.md | 2 +- frame/bounties/src/tests.rs | 2 +- frame/child-bounties/src/tests.rs | 1 + frame/conviction-voting/src/tests.rs | 90 ++-- frame/conviction-voting/src/types.rs | 115 ++--- frame/identity/src/tests.rs | 6 +- frame/referenda/Cargo.toml | 3 + frame/referenda/src/benchmarking.rs | 15 +- frame/referenda/src/lib.rs | 48 ++- frame/referenda/src/mock.rs | 61 ++- frame/referenda/src/tests.rs | 10 +- frame/referenda/src/types.rs | 409 +++++++++++++++--- frame/scheduler/src/mock.rs | 4 +- frame/staking/src/benchmarking.rs | 4 +- frame/staking/src/tests.rs | 7 +- frame/support/src/lib.rs | 93 +++- frame/support/src/traits.rs | 8 +- frame/support/src/traits/dispatch.rs | 118 ++++- frame/support/src/traits/misc.rs | 16 + frame/support/src/traits/voting.rs | 16 +- frame/system/src/lib.rs | 25 +- frame/tips/src/tests.rs | 1 + frame/treasury/src/benchmarking.rs | 20 +- frame/treasury/src/lib.rs | 48 +++ frame/treasury/src/tests.rs | 70 ++- frame/treasury/src/weights.rs | 15 + primitives/arithmetic/Cargo.toml | 1 + primitives/arithmetic/src/fixed_point.rs | 431 +++++++++++++++++- primitives/arithmetic/src/helpers_128bit.rs | 255 ++++++++++- primitives/arithmetic/src/lib.rs | 5 +- primitives/arithmetic/src/per_things.rs | 455 +++++++++++++++++--- primitives/arithmetic/src/traits.rs | 2 + 34 files changed, 2047 insertions(+), 336 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29d15b9e015cb..09da4278f69f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6018,6 +6018,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", + "sp-arithmetic", "sp-core", "sp-io", "sp-runtime", @@ -9500,6 +9501,7 @@ dependencies = [ "rand 0.7.3", "scale-info", "serde", + "sp-core", "sp-debug-derive", "sp-std", "static_assertions", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index c98bb5cc13f85..9b5bc0273ab33 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -31,7 +31,7 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EnsureOneOf, + AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, }, @@ -550,7 +550,7 @@ impl pallet_staking::Config for Runtime { type BondingDuration = BondingDuration; type SlashDeferDuration = SlashDeferDuration; /// A super-majority of the council can cancel the slash. - type SlashCancelOrigin = EnsureOneOf< + type SlashCancelOrigin = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionAtLeast, >; @@ -794,12 +794,14 @@ impl pallet_referenda::TracksInfo for TracksInfo { confirm_period: 2, min_enactment_period: 4, min_approval: pallet_referenda::Curve::LinearDecreasing { - begin: Perbill::from_percent(100), - delta: Perbill::from_percent(50), + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), }, - min_turnout: pallet_referenda::Curve::LinearDecreasing { - begin: Perbill::from_percent(100), - delta: Perbill::from_percent(100), + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(0), + ceil: Perbill::from_percent(100), }, }, )]; @@ -882,7 +884,7 @@ impl pallet_democracy::Config for Runtime { pallet_collective::EnsureProportionAtLeast; // To cancel a proposal before it has been passed, the technical committee must be unanimous or // Root must agree. - type CancelProposalOrigin = EnsureOneOf< + type CancelProposalOrigin = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionAtLeast, >; @@ -972,7 +974,7 @@ impl pallet_collective::Config for Runtime { type WeightInfo = pallet_collective::weights::SubstrateWeight; } -type EnsureRootOrHalfCouncil = EnsureOneOf< +type EnsureRootOrHalfCouncil = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionMoreThan, >; @@ -1006,11 +1008,11 @@ parameter_types! { impl pallet_treasury::Config for Runtime { type PalletId = TreasuryPalletId; type Currency = Balances; - type ApproveOrigin = EnsureOneOf< + type ApproveOrigin = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionAtLeast, >; - type RejectOrigin = EnsureOneOf< + type RejectOrigin = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionMoreThan, >; @@ -1025,6 +1027,7 @@ impl pallet_treasury::Config for Runtime { type SpendFunds = Bounties; type WeightInfo = pallet_treasury::weights::SubstrateWeight; type MaxApprovals = MaxApprovals; + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; } parameter_types! { diff --git a/docs/Upgrading-2.0-to-3.0.md b/docs/Upgrading-2.0-to-3.0.md index 017467ede2d7e..f750c6dd5865b 100644 --- a/docs/Upgrading-2.0-to-3.0.md +++ b/docs/Upgrading-2.0-to-3.0.md @@ -290,7 +290,7 @@ Democracy brings three new settings with this release, all to allow for better i type CancellationOrigin = pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilCollective>; + // To cancel a proposal before it has been passed, the technical committee must be unanimous or + // Root must agree. -+ type CancelProposalOrigin = EnsureOneOf< ++ type CancelProposalOrigin = EitherOfDiverse< + AccountId, + EnsureRoot, + pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>, diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index 9a84bd687abc1..0904e3a2901bb 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -109,7 +109,6 @@ parameter_types! { pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); } -// impl pallet_treasury::Config for Test { impl pallet_treasury::Config for Test { type PalletId = TreasuryPalletId; type Currency = pallet_balances::Pallet; @@ -126,6 +125,7 @@ impl pallet_treasury::Config for Test { type WeightInfo = (); type SpendFunds = Bounties; type MaxApprovals = ConstU32<100>; + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; } parameter_types! { diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index 61545561a26c3..2584445071471 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -130,6 +130,7 @@ impl pallet_treasury::Config for Test { type WeightInfo = (); type SpendFunds = Bounties; type MaxApprovals = ConstU32<100>; + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; } parameter_types! { // This will be 50% of the bounty fee. diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index 6a8bad5d8944e..9eb7f679efca3 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -21,7 +21,7 @@ use std::collections::BTreeMap; use frame_support::{ assert_noop, assert_ok, parameter_types, - traits::{ConstU32, ConstU64, Contains, Polling}, + traits::{ConstU32, ConstU64, Contains, Polling, VoteTally}, }; use sp_core::H256; use sp_runtime::{ @@ -166,7 +166,7 @@ impl Polling> for TestPolls { fn create_ongoing(class: Self::Class) -> Result { let mut polls = Polls::get(); let i = polls.keys().rev().next().map_or(0, |x| x + 1); - polls.insert(i, Ongoing(Tally::default(), class)); + polls.insert(i, Ongoing(Tally::new(0), class)); Polls::set(polls); Ok(i) } @@ -271,19 +271,19 @@ fn basic_voting_works() { assert_ok!(Voting::vote(Origin::signed(1), 3, aye(2, 5))); assert_eq!(tally(3), Tally::from_parts(10, 0, 2)); assert_ok!(Voting::vote(Origin::signed(1), 3, nay(2, 5))); - assert_eq!(tally(3), Tally::from_parts(0, 10, 2)); + assert_eq!(tally(3), Tally::from_parts(0, 10, 0)); assert_eq!(Balances::usable_balance(1), 8); assert_ok!(Voting::vote(Origin::signed(1), 3, aye(5, 1))); assert_eq!(tally(3), Tally::from_parts(5, 0, 5)); assert_ok!(Voting::vote(Origin::signed(1), 3, nay(5, 1))); - assert_eq!(tally(3), Tally::from_parts(0, 5, 5)); + assert_eq!(tally(3), Tally::from_parts(0, 5, 0)); assert_eq!(Balances::usable_balance(1), 5); assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); assert_ok!(Voting::vote(Origin::signed(1), 3, nay(10, 0))); - assert_eq!(tally(3), Tally::from_parts(0, 1, 10)); + assert_eq!(tally(3), Tally::from_parts(0, 1, 0)); assert_eq!(Balances::usable_balance(1), 0); assert_ok!(Voting::remove_vote(Origin::signed(1), None, 3)); @@ -300,19 +300,19 @@ fn voting_balance_gets_locked() { assert_ok!(Voting::vote(Origin::signed(1), 3, aye(2, 5))); assert_eq!(tally(3), Tally::from_parts(10, 0, 2)); assert_ok!(Voting::vote(Origin::signed(1), 3, nay(2, 5))); - assert_eq!(tally(3), Tally::from_parts(0, 10, 2)); + assert_eq!(tally(3), Tally::from_parts(0, 10, 0)); assert_eq!(Balances::usable_balance(1), 8); assert_ok!(Voting::vote(Origin::signed(1), 3, aye(5, 1))); assert_eq!(tally(3), Tally::from_parts(5, 0, 5)); assert_ok!(Voting::vote(Origin::signed(1), 3, nay(5, 1))); - assert_eq!(tally(3), Tally::from_parts(0, 5, 5)); + assert_eq!(tally(3), Tally::from_parts(0, 5, 0)); assert_eq!(Balances::usable_balance(1), 5); assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); assert_ok!(Voting::vote(Origin::signed(1), 3, nay(10, 0))); - assert_eq!(tally(3), Tally::from_parts(0, 1, 10)); + assert_eq!(tally(3), Tally::from_parts(0, 1, 0)); assert_eq!(Balances::usable_balance(1), 0); assert_ok!(Voting::remove_vote(Origin::signed(1), None, 3)); @@ -376,10 +376,10 @@ fn classwise_delegation_works() { new_test_ext().execute_with(|| { Polls::set( vec![ - (0, Ongoing(Tally::default(), 0)), - (1, Ongoing(Tally::default(), 1)), - (2, Ongoing(Tally::default(), 2)), - (3, Ongoing(Tally::default(), 2)), + (0, Ongoing(Tally::new(0), 0)), + (1, Ongoing(Tally::new(0), 1)), + (2, Ongoing(Tally::new(0), 2)), + (3, Ongoing(Tally::new(0), 2)), ] .into_iter() .collect(), @@ -403,9 +403,9 @@ fn classwise_delegation_works() { assert_eq!( Polls::get(), vec![ - (0, Ongoing(Tally::from_parts(6, 2, 35), 0)), - (1, Ongoing(Tally::from_parts(6, 2, 35), 1)), - (2, Ongoing(Tally::from_parts(6, 2, 35), 2)), + (0, Ongoing(Tally::from_parts(6, 2, 15), 0)), + (1, Ongoing(Tally::from_parts(6, 2, 15), 1)), + (2, Ongoing(Tally::from_parts(6, 2, 15), 2)), (3, Ongoing(Tally::from_parts(0, 0, 0), 2)), ] .into_iter() @@ -417,10 +417,10 @@ fn classwise_delegation_works() { assert_eq!( Polls::get(), vec![ - (0, Ongoing(Tally::from_parts(6, 2, 35), 0)), - (1, Ongoing(Tally::from_parts(6, 2, 35), 1)), - (2, Ongoing(Tally::from_parts(6, 2, 35), 2)), - (3, Ongoing(Tally::from_parts(0, 6, 15), 2)), + (0, Ongoing(Tally::from_parts(6, 2, 15), 0)), + (1, Ongoing(Tally::from_parts(6, 2, 15), 1)), + (2, Ongoing(Tally::from_parts(6, 2, 15), 2)), + (3, Ongoing(Tally::from_parts(0, 6, 0), 2)), ] .into_iter() .collect() @@ -432,10 +432,10 @@ fn classwise_delegation_works() { assert_eq!( Polls::get(), vec![ - (0, Ongoing(Tally::from_parts(6, 2, 35), 0)), - (1, Ongoing(Tally::from_parts(6, 2, 35), 1)), - (2, Ongoing(Tally::from_parts(1, 7, 35), 2)), - (3, Ongoing(Tally::from_parts(0, 1, 10), 2)), + (0, Ongoing(Tally::from_parts(6, 2, 15), 0)), + (1, Ongoing(Tally::from_parts(6, 2, 15), 1)), + (2, Ongoing(Tally::from_parts(1, 7, 10), 2)), + (3, Ongoing(Tally::from_parts(0, 1, 0), 2)), ] .into_iter() .collect() @@ -451,10 +451,10 @@ fn classwise_delegation_works() { assert_eq!( Polls::get(), vec![ - (0, Ongoing(Tally::from_parts(4, 2, 33), 0)), - (1, Ongoing(Tally::from_parts(4, 2, 33), 1)), - (2, Ongoing(Tally::from_parts(4, 2, 33), 2)), - (3, Ongoing(Tally::from_parts(0, 4, 13), 2)), + (0, Ongoing(Tally::from_parts(4, 2, 13), 0)), + (1, Ongoing(Tally::from_parts(4, 2, 13), 1)), + (2, Ongoing(Tally::from_parts(4, 2, 13), 2)), + (3, Ongoing(Tally::from_parts(0, 4, 0), 2)), ] .into_iter() .collect() @@ -483,10 +483,10 @@ fn classwise_delegation_works() { assert_eq!( Polls::get(), vec![ - (0, Ongoing(Tally::from_parts(7, 2, 36), 0)), - (1, Ongoing(Tally::from_parts(8, 2, 37), 1)), - (2, Ongoing(Tally::from_parts(9, 2, 38), 2)), - (3, Ongoing(Tally::from_parts(0, 9, 18), 2)), + (0, Ongoing(Tally::from_parts(7, 2, 16), 0)), + (1, Ongoing(Tally::from_parts(8, 2, 17), 1)), + (2, Ongoing(Tally::from_parts(9, 2, 18), 2)), + (3, Ongoing(Tally::from_parts(0, 9, 0), 2)), ] .into_iter() .collect() @@ -497,7 +497,7 @@ fn classwise_delegation_works() { #[test] fn redelegation_after_vote_ending_should_keep_lock() { new_test_ext().execute_with(|| { - Polls::set(vec![(0, Ongoing(Tally::default(), 0))].into_iter().collect()); + Polls::set(vec![(0, Ongoing(Tally::new(0), 0))].into_iter().collect()); assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); assert_ok!(Voting::vote(Origin::signed(2), 0, aye(10, 1))); Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); @@ -515,9 +515,9 @@ fn lock_amalgamation_valid_with_multiple_removed_votes() { new_test_ext().execute_with(|| { Polls::set( vec![ - (0, Ongoing(Tally::default(), 0)), - (1, Ongoing(Tally::default(), 0)), - (2, Ongoing(Tally::default(), 0)), + (0, Ongoing(Tally::new(0), 0)), + (1, Ongoing(Tally::new(0), 0)), + (2, Ongoing(Tally::new(0), 0)), ] .into_iter() .collect(), @@ -587,7 +587,7 @@ fn lock_amalgamation_valid_with_multiple_delegations() { #[test] fn lock_amalgamation_valid_with_move_roundtrip_to_delegation() { new_test_ext().execute_with(|| { - Polls::set(vec![(0, Ongoing(Tally::default(), 0))].into_iter().collect()); + Polls::set(vec![(0, Ongoing(Tally::new(0), 0))].into_iter().collect()); assert_ok!(Voting::vote(Origin::signed(1), 0, aye(5, 1))); Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); @@ -599,7 +599,7 @@ fn lock_amalgamation_valid_with_move_roundtrip_to_delegation() { assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); - Polls::set(vec![(1, Ongoing(Tally::default(), 0))].into_iter().collect()); + Polls::set(vec![(1, Ongoing(Tally::new(0), 0))].into_iter().collect()); assert_ok!(Voting::vote(Origin::signed(1), 1, aye(5, 2))); Polls::set(vec![(1, Completed(1, true))].into_iter().collect()); assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 1)); @@ -627,7 +627,7 @@ fn lock_amalgamation_valid_with_move_roundtrip_to_casting() { assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 5); - Polls::set(vec![(0, Ongoing(Tally::default(), 0))].into_iter().collect()); + Polls::set(vec![(0, Ongoing(Tally::new(0), 0))].into_iter().collect()); assert_ok!(Voting::vote(Origin::signed(1), 0, aye(10, 1))); Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); @@ -688,9 +688,9 @@ fn lock_aggregation_over_different_classes_with_casting_works() { new_test_ext().execute_with(|| { Polls::set( vec![ - (0, Ongoing(Tally::default(), 0)), - (1, Ongoing(Tally::default(), 1)), - (2, Ongoing(Tally::default(), 2)), + (0, Ongoing(Tally::new(0), 0)), + (1, Ongoing(Tally::new(0), 1)), + (2, Ongoing(Tally::new(0), 2)), ] .into_iter() .collect(), @@ -747,10 +747,10 @@ fn errors_with_vote_work() { assert_ok!(Voting::undelegate(Origin::signed(1), 0)); Polls::set( vec![ - (0, Ongoing(Tally::default(), 0)), - (1, Ongoing(Tally::default(), 0)), - (2, Ongoing(Tally::default(), 0)), - (3, Ongoing(Tally::default(), 0)), + (0, Ongoing(Tally::new(0), 0)), + (1, Ongoing(Tally::new(0), 0)), + (2, Ongoing(Tally::new(0), 0)), + (3, Ongoing(Tally::new(0), 0)), ] .into_iter() .collect(), diff --git a/frame/conviction-voting/src/types.rs b/frame/conviction-voting/src/types.rs index e2b5844ddd5df..2469009855c5f 100644 --- a/frame/conviction-voting/src/types.rs +++ b/frame/conviction-voting/src/types.rs @@ -17,18 +17,16 @@ //! Miscellaneous additional datatypes. -use sp_std::marker::PhantomData; - use codec::{Codec, Decode, Encode, MaxEncodedLen}; use frame_support::{ - traits::VoteTally, CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, - RuntimeDebugNoBound, + traits::VoteTally, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use scale_info::TypeInfo; use sp_runtime::{ traits::{Saturating, Zero}, RuntimeDebug, }; +use sp_std::{fmt::Debug, marker::PhantomData}; use super::*; use crate::{AccountVote, Conviction, Vote}; @@ -36,7 +34,6 @@ use crate::{AccountVote, Conviction, Vote}; /// Info regarding an ongoing referendum. #[derive( CloneNoBound, - DefaultNoBound, PartialEqNoBound, EqNoBound, RuntimeDebugNoBound, @@ -46,84 +43,84 @@ use crate::{AccountVote, Conviction, Vote}; MaxEncodedLen, )] #[scale_info(skip_type_params(Total))] -pub struct Tally< - Votes: Clone + Default + PartialEq + Eq + sp_std::fmt::Debug + TypeInfo + Codec, - Total, -> { +pub struct Tally { /// The number of aye votes, expressed in terms of post-conviction lock-vote. pub ayes: Votes, /// The number of nay votes, expressed in terms of post-conviction lock-vote. pub nays: Votes, - /// The amount of funds currently expressing its opinion. Pre-conviction. - pub turnout: Votes, + /// The basic number of aye votes, expressed pre-conviction. + pub support: Votes, /// Dummy. dummy: PhantomData, } impl< - Votes: Clone - + Default - + PartialEq - + Eq - + sp_std::fmt::Debug - + Copy - + AtLeast32BitUnsigned - + TypeInfo - + Codec, + Votes: Clone + Default + PartialEq + Eq + Debug + Copy + AtLeast32BitUnsigned + TypeInfo + Codec, Total: Get, - > VoteTally for Tally + Class, + > VoteTally for Tally { - fn ayes(&self) -> Votes { + fn new(_: Class) -> Self { + Self { ayes: Zero::zero(), nays: Zero::zero(), support: Zero::zero(), dummy: PhantomData } + } + + fn ayes(&self, _: Class) -> Votes { self.ayes } - fn turnout(&self) -> Perbill { - Perbill::from_rational(self.turnout, Total::get()) + fn support(&self, _: Class) -> Perbill { + Perbill::from_rational(self.support, Total::get()) } - fn approval(&self) -> Perbill { + fn approval(&self, _: Class) -> Perbill { Perbill::from_rational(self.ayes, self.ayes.saturating_add(self.nays)) } #[cfg(feature = "runtime-benchmarks")] - fn unanimity() -> Self { - Self { ayes: Total::get(), nays: Zero::zero(), turnout: Total::get(), dummy: PhantomData } + fn unanimity(_: Class) -> Self { + Self { ayes: Total::get(), nays: Zero::zero(), support: Total::get(), dummy: PhantomData } + } + + #[cfg(feature = "runtime-benchmarks")] + fn rejection(_: Class) -> Self { + Self { ayes: Zero::zero(), nays: Total::get(), support: Total::get(), dummy: PhantomData } } #[cfg(feature = "runtime-benchmarks")] - fn from_requirements(turnout: Perbill, approval: Perbill) -> Self { - let turnout = turnout.mul_ceil(Total::get()); - let ayes = approval.mul_ceil(turnout); - Self { ayes, nays: turnout - ayes, turnout, dummy: PhantomData } + fn from_requirements(support: Perbill, approval: Perbill, _: Class) -> Self { + let support = support.mul_ceil(Total::get()); + let ayes = approval.mul_ceil(support); + Self { ayes, nays: support - ayes, support, dummy: PhantomData } } } impl< - Votes: Clone - + Default - + PartialEq - + Eq - + sp_std::fmt::Debug - + Copy - + AtLeast32BitUnsigned - + TypeInfo - + Codec, + Votes: Clone + Default + PartialEq + Eq + Debug + Copy + AtLeast32BitUnsigned + TypeInfo + Codec, Total: Get, > Tally { /// Create a new tally. - pub fn new(vote: Vote, balance: Votes) -> Self { + pub fn from_vote(vote: Vote, balance: Votes) -> Self { let Delegations { votes, capital } = vote.conviction.votes(balance); Self { ayes: if vote.aye { votes } else { Zero::zero() }, nays: if vote.aye { Zero::zero() } else { votes }, - turnout: capital, + support: capital, dummy: PhantomData, } } - pub fn from_parts(ayes: Votes, nays: Votes, turnout: Votes) -> Self { - Self { ayes, nays, turnout, dummy: PhantomData } + pub fn from_parts( + ayes_with_conviction: Votes, + nays_with_conviction: Votes, + ayes: Votes, + ) -> Self { + Self { + ayes: ayes_with_conviction, + nays: nays_with_conviction, + support: ayes, + dummy: PhantomData, + } } /// Add an account's vote into the tally. @@ -131,16 +128,18 @@ impl< match vote { AccountVote::Standard { vote, balance } => { let Delegations { votes, capital } = vote.conviction.votes(balance); - self.turnout = self.turnout.checked_add(&capital)?; match vote.aye { - true => self.ayes = self.ayes.checked_add(&votes)?, + true => { + self.support = self.support.checked_add(&capital)?; + self.ayes = self.ayes.checked_add(&votes)? + }, false => self.nays = self.nays.checked_add(&votes)?, } }, AccountVote::Split { aye, nay } => { let aye = Conviction::None.votes(aye); let nay = Conviction::None.votes(nay); - self.turnout = self.turnout.checked_add(&aye.capital)?.checked_add(&nay.capital)?; + self.support = self.support.checked_add(&aye.capital)?; self.ayes = self.ayes.checked_add(&aye.votes)?; self.nays = self.nays.checked_add(&nay.votes)?; }, @@ -153,16 +152,18 @@ impl< match vote { AccountVote::Standard { vote, balance } => { let Delegations { votes, capital } = vote.conviction.votes(balance); - self.turnout = self.turnout.checked_sub(&capital)?; match vote.aye { - true => self.ayes = self.ayes.checked_sub(&votes)?, + true => { + self.support = self.support.checked_sub(&capital)?; + self.ayes = self.ayes.checked_sub(&votes)? + }, false => self.nays = self.nays.checked_sub(&votes)?, } }, AccountVote::Split { aye, nay } => { let aye = Conviction::None.votes(aye); let nay = Conviction::None.votes(nay); - self.turnout = self.turnout.checked_sub(&aye.capital)?.checked_sub(&nay.capital)?; + self.support = self.support.checked_sub(&aye.capital)?; self.ayes = self.ayes.checked_sub(&aye.votes)?; self.nays = self.nays.checked_sub(&nay.votes)?; }, @@ -172,18 +173,22 @@ impl< /// Increment some amount of votes. pub fn increase(&mut self, approve: bool, delegations: Delegations) { - self.turnout = self.turnout.saturating_add(delegations.capital); match approve { - true => self.ayes = self.ayes.saturating_add(delegations.votes), + true => { + self.support = self.support.saturating_add(delegations.capital); + self.ayes = self.ayes.saturating_add(delegations.votes); + }, false => self.nays = self.nays.saturating_add(delegations.votes), } } /// Decrement some amount of votes. pub fn reduce(&mut self, approve: bool, delegations: Delegations) { - self.turnout = self.turnout.saturating_sub(delegations.capital); match approve { - true => self.ayes = self.ayes.saturating_sub(delegations.votes), + true => { + self.support = self.support.saturating_sub(delegations.capital); + self.ayes = self.ayes.saturating_sub(delegations.votes); + }, false => self.nays = self.nays.saturating_sub(delegations.votes), } } @@ -196,7 +201,7 @@ impl< pub struct Delegations { /// The number of votes (this is post-conviction). pub votes: Balance, - /// The amount of raw capital, used for the turnout. + /// The amount of raw capital, used for the support. pub capital: Balance, } diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 8cb0563ebeaa1..6066f176a6106 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -23,7 +23,7 @@ use crate as pallet_identity; use codec::{Decode, Encode}; use frame_support::{ assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{ConstU32, ConstU64, EnsureOneOf}, + traits::{ConstU32, ConstU64, EitherOfDiverse}, BoundedVec, }; use frame_system::{EnsureRoot, EnsureSignedBy}; @@ -100,8 +100,8 @@ ord_parameter_types! { pub const One: u64 = 1; pub const Two: u64 = 2; } -type EnsureOneOrRoot = EnsureOneOf, EnsureSignedBy>; -type EnsureTwoOrRoot = EnsureOneOf, EnsureSignedBy>; +type EnsureOneOrRoot = EitherOfDiverse, EnsureSignedBy>; +type EnsureTwoOrRoot = EitherOfDiverse, EnsureSignedBy>; impl pallet_identity::Config for Test { type Event = Event; type Currency = Balances; diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index 75888c6d14f3d..ef3d5fe5a8e06 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -19,6 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -39,6 +40,8 @@ std = [ "codec/std", "frame-benchmarking/std", "frame-support/std", + "sp-runtime/std", + "sp-arithmetic/std", "frame-system/std", "scale-info/std", "serde", diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 87b13868db9d9..e4cbf2ca52e7c 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -101,27 +101,27 @@ fn info(index: ReferendumIndex) -> &'static TrackInfoOf { } fn make_passing_after(index: ReferendumIndex, period_portion: Perbill) { - let turnout = info::(index).min_turnout.threshold(period_portion); + let support = info::(index).min_support.threshold(period_portion); let approval = info::(index).min_approval.threshold(period_portion); Referenda::::access_poll(index, |status| { - if let PollStatus::Ongoing(tally, ..) = status { - *tally = T::Tally::from_requirements(turnout, approval); + if let PollStatus::Ongoing(tally, class) = status { + *tally = T::Tally::from_requirements(support, approval, class); } }); } fn make_passing(index: ReferendumIndex) { Referenda::::access_poll(index, |status| { - if let PollStatus::Ongoing(tally, ..) = status { - *tally = T::Tally::unanimity(); + if let PollStatus::Ongoing(tally, class) = status { + *tally = T::Tally::unanimity(class); } }); } fn make_failing(index: ReferendumIndex) { Referenda::::access_poll(index, |status| { - if let PollStatus::Ongoing(tally, ..) = status { - *tally = T::Tally::default(); + if let PollStatus::Ongoing(tally, class) = status { + *tally = T::Tally::rejection(class); } }); } @@ -501,6 +501,7 @@ benchmarks! { let (_caller, index) = create_referendum::(); place_deposit::(index); skip_prepare_period::(index); + make_failing::(index); nudge::(index); skip_decision_period::(index); }: nudge_referendum(RawOrigin::Root, index) diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index b53be191d3525..e3f31bc411328 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -41,7 +41,7 @@ //! In order to become concluded, one of three things must happen: //! - The referendum should remain in an unbroken _Passing_ state for a period of time. This //! is known as the _Confirmation Period_ and is determined by the track. A referendum is considered -//! _Passing_ when there is a sufficiently high turnout and approval, given the amount of time it +//! _Passing_ when there is a sufficiently high support and approval, given the amount of time it //! has been being decided. Generally the threshold for what counts as being "sufficiently high" //! will reduce over time. The curves setting these thresholds are determined by the track. In this //! case, the referendum is considered _Approved_ and the proposal is scheduled for dispatch. @@ -54,6 +54,10 @@ //! //! Once a referendum is concluded, the decision deposit may be refunded. //! +//! ## Terms +//! - *Support*: The number of aye-votes, pre-conviction, as a proportion of the total number of +//! pre-conviction votes able to be cast in the population. +//! //! - [`Config`] //! - [`Call`] @@ -148,7 +152,12 @@ pub mod pallet { /// The counting type for votes. Usually just balance. type Votes: AtLeast32BitUnsigned + Copy + Parameter + Member; /// The tallying type. - type Tally: VoteTally + Default + Clone + Codec + Eq + Debug + TypeInfo; + type Tally: VoteTally> + + Clone + + Codec + + Eq + + Debug + + TypeInfo; // Constants /// The minimum amount to be used as a deposit for a public referendum proposal. @@ -369,7 +378,7 @@ pub mod pallet { submission_deposit, decision_deposit: None, deciding: None, - tally: Default::default(), + tally: TallyOf::::new(track), in_queue: false, alarm: Self::set_alarm(nudge_call, now.saturating_add(T::UndecidingTimeout::get())), }; @@ -613,7 +622,7 @@ impl, I: 'static> Polling for Pallet { submission_deposit: Deposit { who: dummy_account_id, amount: Zero::zero() }, decision_deposit: None, deciding: None, - tally: Default::default(), + tally: TallyOf::::new(class), in_queue: false, alarm: None, }; @@ -723,8 +732,9 @@ impl, I: 'static> Pallet { &status.tally, Zero::zero(), track.decision_period, - &track.min_turnout, + &track.min_support, &track.min_approval, + status.track, ); status.in_queue = false; Self::deposit_event(Event::::DecisionStarted { @@ -740,7 +750,7 @@ impl, I: 'static> Pallet { None }; let deciding_status = DecidingStatus { since: now, confirming }; - let alarm = Self::decision_time(&deciding_status, &status.tally, track); + let alarm = Self::decision_time(&deciding_status, &status.tally, status.track, track); status.deciding = Some(deciding_status); let branch = if is_passing { BeginDecidingBranch::Passing } else { BeginDecidingBranch::Failing }; @@ -765,7 +775,7 @@ impl, I: 'static> Pallet { (r.0, r.1.into()) } else { // Add to queue. - let item = (index, status.tally.ayes()); + let item = (index, status.tally.ayes(status.track)); status.in_queue = true; TrackQueue::::mutate(status.track, |q| q.insert_sorted_by_key(item, |x| x.1)); (None, ServiceBranch::Queued) @@ -872,7 +882,7 @@ impl, I: 'static> Pallet { // Are we already queued for deciding? if status.in_queue { // Does our position in the queue need updating? - let ayes = status.tally.ayes(); + let ayes = status.tally.ayes(status.track); let mut queue = TrackQueue::::get(status.track); let maybe_old_pos = queue.iter().position(|(x, _)| *x == index); let new_pos = queue.binary_search_by_key(&ayes, |x| x.1).unwrap_or_else(|x| x); @@ -930,8 +940,9 @@ impl, I: 'static> Pallet { &status.tally, now.saturating_sub(deciding.since), track.decision_period, - &track.min_turnout, + &track.min_support, &track.min_approval, + status.track, ); branch = if is_passing { match deciding.confirming { @@ -996,7 +1007,7 @@ impl, I: 'static> Pallet { ServiceBranch::ContinueNotConfirming } }; - alarm = Self::decision_time(deciding, &status.tally, track); + alarm = Self::decision_time(deciding, &status.tally, status.track, track); }, } @@ -1009,15 +1020,16 @@ impl, I: 'static> Pallet { fn decision_time( deciding: &DecidingStatusOf, tally: &T::Tally, + track_id: TrackIdOf, track: &TrackInfoOf, ) -> T::BlockNumber { deciding.confirming.unwrap_or_else(|| { // Set alarm to the point where the current voting would make it pass. - let approval = tally.approval(); - let turnout = tally.turnout(); + let approval = tally.approval(track_id); + let support = tally.support(track_id); let until_approval = track.min_approval.delay(approval); - let until_turnout = track.min_turnout.delay(turnout); - let offset = until_turnout.max(until_approval); + let until_support = track.min_support.delay(support); + let offset = until_support.max(until_approval); deciding.since.saturating_add(offset * track.decision_period) }) } @@ -1062,16 +1074,18 @@ impl, I: 'static> Pallet { } /// Determine whether the given `tally` would result in a referendum passing at `elapsed` blocks - /// into a total decision `period`, given the two curves for `turnout_needed` and + /// into a total decision `period`, given the two curves for `support_needed` and /// `approval_needed`. fn is_passing( tally: &T::Tally, elapsed: T::BlockNumber, period: T::BlockNumber, - turnout_needed: &Curve, + support_needed: &Curve, approval_needed: &Curve, + id: TrackIdOf, ) -> bool { let x = Perbill::from_rational(elapsed.min(period), period); - turnout_needed.passing(x, tally.turnout()) && approval_needed.passing(x, tally.approval()) + support_needed.passing(x, tally.support(id)) && + approval_needed.passing(x, tally.approval(id)) } } diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 1b0bbba24bbe6..a3026ce78e986 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -160,12 +160,14 @@ impl TracksInfo for TestTracksInfo { confirm_period: 2, min_enactment_period: 4, min_approval: Curve::LinearDecreasing { - begin: Perbill::from_percent(100), - delta: Perbill::from_percent(50), + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), }, - min_turnout: Curve::LinearDecreasing { - begin: Perbill::from_percent(100), - delta: Perbill::from_percent(100), + min_support: Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(0), + ceil: Perbill::from_percent(100), }, }, ), @@ -180,12 +182,14 @@ impl TracksInfo for TestTracksInfo { confirm_period: 1, min_enactment_period: 2, min_approval: Curve::LinearDecreasing { - begin: Perbill::from_percent(55), - delta: Perbill::from_percent(5), + length: Perbill::from_percent(100), + floor: Perbill::from_percent(95), + ceil: Perbill::from_percent(100), }, - min_turnout: Curve::LinearDecreasing { - begin: Perbill::from_percent(10), - delta: Perbill::from_percent(10), + min_support: Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(90), + ceil: Perbill::from_percent(100), }, }, ), @@ -241,35 +245,48 @@ pub fn new_test_ext_execute_with_cond(execute: impl FnOnce(bool) -> () + Clone) new_test_ext().execute_with(|| execute(true)); } -#[derive(Encode, Debug, Decode, TypeInfo, Eq, PartialEq, Clone, Default, MaxEncodedLen)] +#[derive(Encode, Debug, Decode, TypeInfo, Eq, PartialEq, Clone, MaxEncodedLen)] pub struct Tally { pub ayes: u32, pub nays: u32, } -impl VoteTally for Tally { - fn ayes(&self) -> u32 { +impl VoteTally for Tally { + fn new(_: Class) -> Self { + Self { ayes: 0, nays: 0 } + } + + fn ayes(&self, _: Class) -> u32 { self.ayes } - fn turnout(&self) -> Perbill { - Perbill::from_percent(self.ayes + self.nays) + fn support(&self, _: Class) -> Perbill { + Perbill::from_percent(self.ayes) } - fn approval(&self) -> Perbill { - Perbill::from_rational(self.ayes, self.ayes + self.nays) + fn approval(&self, _: Class) -> Perbill { + if self.ayes + self.nays > 0 { + Perbill::from_rational(self.ayes, self.ayes + self.nays) + } else { + Perbill::zero() + } } #[cfg(feature = "runtime-benchmarks")] - fn unanimity() -> Self { + fn unanimity(_: Class) -> Self { Self { ayes: 100, nays: 0 } } #[cfg(feature = "runtime-benchmarks")] - fn from_requirements(turnout: Perbill, approval: Perbill) -> Self { - let turnout = turnout.mul_ceil(100u32); - let ayes = approval.mul_ceil(turnout); - Self { ayes, nays: turnout - ayes } + fn rejection(_: Class) -> Self { + Self { ayes: 0, nays: 100 } + } + + #[cfg(feature = "runtime-benchmarks")] + fn from_requirements(support: Perbill, approval: Perbill, _: Class) -> Self { + let ayes = support.mul_ceil(100u32); + let nays = ((ayes as u64) * 1_000_000_000u64 / approval.deconstruct() as u64) as u32 - ayes; + Self { ayes, nays } } } diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index 96edd4ce879ce..8134e024dda39 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -504,12 +504,14 @@ fn set_balance_proposal_is_correctly_filtered_out() { #[test] fn curve_handles_all_inputs() { - let test_curve = Curve::LinearDecreasing { begin: Perbill::zero(), delta: Perbill::zero() }; + let test_curve = Curve::LinearDecreasing { + length: Perbill::one(), + floor: Perbill::zero(), + ceil: Perbill::from_percent(100), + }; let delay = test_curve.delay(Perbill::zero()); - assert_eq!(delay, Perbill::zero()); - - let test_curve = Curve::LinearDecreasing { begin: Perbill::zero(), delta: Perbill::one() }; + assert_eq!(delay, Perbill::one()); let threshold = test_curve.threshold(Perbill::one()); assert_eq!(threshold, Perbill::zero()); diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 5e0361c8fe160..27b3c6a5a9d59 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -21,7 +21,8 @@ use super::*; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use frame_support::{traits::schedule::Anon, Parameter}; use scale_info::TypeInfo; -use sp_runtime::RuntimeDebug; +use sp_arithmetic::{Rounding::*, SignedRounding::*}; +use sp_runtime::{FixedI64, PerThing, RuntimeDebug}; use sp_std::fmt::Debug; pub type BalanceOf = @@ -91,40 +92,6 @@ impl> InsertSorted for BoundedVec { } } -#[cfg(test)] -mod tests { - use super::*; - use frame_support::traits::ConstU32; - - #[test] - fn insert_sorted_works() { - let mut b: BoundedVec> = vec![20, 30, 40].try_into().unwrap(); - assert!(b.insert_sorted_by_key(10, |&x| x)); - assert_eq!(&b[..], &[10, 20, 30, 40][..]); - - assert!(b.insert_sorted_by_key(60, |&x| x)); - assert_eq!(&b[..], &[10, 20, 30, 40, 60][..]); - - assert!(b.insert_sorted_by_key(50, |&x| x)); - assert_eq!(&b[..], &[10, 20, 30, 40, 50, 60][..]); - - assert!(!b.insert_sorted_by_key(9, |&x| x)); - assert_eq!(&b[..], &[10, 20, 30, 40, 50, 60][..]); - - assert!(b.insert_sorted_by_key(11, |&x| x)); - assert_eq!(&b[..], &[11, 20, 30, 40, 50, 60][..]); - - assert!(b.insert_sorted_by_key(21, |&x| x)); - assert_eq!(&b[..], &[20, 21, 30, 40, 50, 60][..]); - - assert!(b.insert_sorted_by_key(61, |&x| x)); - assert_eq!(&b[..], &[21, 30, 40, 50, 60, 61][..]); - - assert!(b.insert_sorted_by_key(51, |&x| x)); - assert_eq!(&b[..], &[30, 40, 50, 51, 60, 61][..]); - } -} - #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct DecidingStatus { /// When this referendum began being "decided". If confirming, then the @@ -143,7 +110,7 @@ pub struct Deposit { #[derive(Clone, Encode, TypeInfo)] pub struct TrackInfo { - /// Name of this track. TODO was &'static str + /// Name of this track. pub name: &'static str, /// A limit for the number of referenda on this track that can be being decided at once. /// For Root origin this should generally be just one. @@ -161,9 +128,9 @@ pub struct TrackInfo { /// Minimum aye votes as percentage of overall conviction-weighted votes needed for /// approval as a function of time into decision period. pub min_approval: Curve, - /// Minimum turnout as percentage of overall population that is needed for - /// approval as a function of time into decision period. - pub min_turnout: Curve, + /// Minimum pre-conviction aye-votes ("support") as percentage of overall population that is + /// needed for approval as a function of time into decision period. + pub min_support: Curve, } /// Information on the voting tracks. @@ -282,21 +249,186 @@ impl< #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] #[cfg_attr(not(feature = "std"), derive(RuntimeDebug))] pub enum Curve { - /// Linear curve starting at `(0, begin)`, ending at `(period, begin - delta)`. - LinearDecreasing { begin: Perbill, delta: Perbill }, + /// Linear curve starting at `(0, ceil)`, proceeding linearly to `(length, floor)`, then + /// remaining at `floor` until the end of the period. + LinearDecreasing { length: Perbill, floor: Perbill, ceil: Perbill }, + /// Stepped curve, beginning at `(0, begin)`, then remaining constant for `period`, at which + /// point it steps down to `(period, begin - step)`. It then remains constant for another + /// `period` before stepping down to `(period * 2, begin - step * 2)`. This pattern continues + /// but the `y` component has a lower limit of `end`. + SteppedDecreasing { begin: Perbill, end: Perbill, step: Perbill, period: Perbill }, + /// A recipocal (`K/(x+S)-T`) curve: `factor` is `K` and `x_offset` is `S`, `y_offset` is `T`. + Reciprocal { factor: FixedI64, x_offset: FixedI64, y_offset: FixedI64 }, +} + +/// Calculate the quadratic solution for the given curve. +/// +/// WARNING: This is a `const` function designed for convenient use at build time and +/// will panic on overflow. Ensure that any inputs are sensible. +const fn pos_quad_solution(a: FixedI64, b: FixedI64, c: FixedI64) -> FixedI64 { + const TWO: FixedI64 = FixedI64::from_u32(2); + const FOUR: FixedI64 = FixedI64::from_u32(4); + b.neg().add(b.mul(b).sub(FOUR.mul(a).mul(c)).sqrt()).div(TWO.mul(a)) } impl Curve { + /// Create a `Curve::Linear` instance from a high-level description. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn make_linear(length: u128, period: u128, floor: FixedI64, ceil: FixedI64) -> Curve { + let length = FixedI64::from_rational(length, period).into_perbill(); + let floor = floor.into_perbill(); + let ceil = ceil.into_perbill(); + Curve::LinearDecreasing { length, floor, ceil } + } + + /// Create a `Curve::Reciprocal` instance from a high-level description. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn make_reciprocal( + delay: u128, + period: u128, + level: FixedI64, + floor: FixedI64, + ceil: FixedI64, + ) -> Curve { + let delay = FixedI64::from_rational(delay, period).into_perbill(); + let mut bounds = ( + ( + FixedI64::from_u32(0), + Self::reciprocal_from_parts(FixedI64::from_u32(0), floor, ceil), + FixedI64::from_inner(i64::max_value()), + ), + ( + FixedI64::from_u32(1), + Self::reciprocal_from_parts(FixedI64::from_u32(1), floor, ceil), + FixedI64::from_inner(i64::max_value()), + ), + ); + const TWO: FixedI64 = FixedI64::from_u32(2); + while (bounds.1).0.sub((bounds.0).0).into_inner() > 1 { + let factor = (bounds.0).0.add((bounds.1).0).div(TWO); + let curve = Self::reciprocal_from_parts(factor, floor, ceil); + let curve_level = FixedI64::from_perbill(curve.const_threshold(delay)); + if curve_level.into_inner() > level.into_inner() { + bounds = (bounds.0, (factor, curve, curve_level.sub(level))); + } else { + bounds = ((factor, curve, level.sub(curve_level)), bounds.1); + } + } + if (bounds.0).2.into_inner() < (bounds.1).2.into_inner() { + (bounds.0).1 + } else { + (bounds.1).1 + } + } + + /// Create a `Curve::Reciprocal` instance from basic parameters. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + const fn reciprocal_from_parts(factor: FixedI64, floor: FixedI64, ceil: FixedI64) -> Self { + let delta = ceil.sub(floor); + let x_offset = pos_quad_solution(delta, delta, factor.neg()); + let y_offset = floor.sub(factor.div(FixedI64::from_u32(1).add(x_offset))); + Curve::Reciprocal { factor, x_offset, y_offset } + } + + /// Print some info on the curve. + #[cfg(feature = "std")] + pub fn info(&self, days: u32, name: impl std::fmt::Display) { + let hours = days * 24; + println!("Curve {} := {:?}:", name, self); + println!(" t + 0h: {:?}", self.threshold(Perbill::zero())); + println!(" t + 1h: {:?}", self.threshold(Perbill::from_rational(1, hours))); + println!(" t + 2h: {:?}", self.threshold(Perbill::from_rational(2, hours))); + println!(" t + 3h: {:?}", self.threshold(Perbill::from_rational(3, hours))); + println!(" t + 6h: {:?}", self.threshold(Perbill::from_rational(6, hours))); + println!(" t + 12h: {:?}", self.threshold(Perbill::from_rational(12, hours))); + println!(" t + 24h: {:?}", self.threshold(Perbill::from_rational(24, hours))); + let mut l = 0; + for &(n, d) in [(1, 12), (1, 8), (1, 4), (1, 2), (3, 4), (1, 1)].iter() { + let t = days * n / d; + if t != l { + println!(" t + {}d: {:?}", t, self.threshold(Perbill::from_rational(t, days))); + l = t; + } + } + let t = |p: Perbill| -> std::string::String { + if p.is_one() { + "never".into() + } else { + let minutes = p * (hours * 60); + if minutes < 60 { + format!("{} minutes", minutes) + } else if minutes < 8 * 60 && minutes % 60 != 0 { + format!("{} hours {} minutes", minutes / 60, minutes % 60) + } else if minutes < 72 * 60 { + format!("{} hours", minutes / 60) + } else if minutes / 60 % 24 == 0 { + format!("{} days", minutes / 60 / 24) + } else { + format!("{} days {} hours", minutes / 60 / 24, minutes / 60 % 24) + } + } + }; + if self.delay(Perbill::from_percent(49)) < Perbill::one() { + println!(" 30% threshold: {}", t(self.delay(Perbill::from_percent(30)))); + println!(" 10% threshold: {}", t(self.delay(Perbill::from_percent(10)))); + println!(" 3% threshold: {}", t(self.delay(Perbill::from_percent(3)))); + println!(" 1% threshold: {}", t(self.delay(Perbill::from_percent(1)))); + println!(" 0.1% threshold: {}", t(self.delay(Perbill::from_rational(1u32, 1_000)))); + println!(" 0.01% threshold: {}", t(self.delay(Perbill::from_rational(1u32, 10_000)))); + } else { + println!( + " 99.9% threshold: {}", + t(self.delay(Perbill::from_rational(999u32, 1_000))) + ); + println!(" 99% threshold: {}", t(self.delay(Perbill::from_percent(99)))); + println!(" 95% threshold: {}", t(self.delay(Perbill::from_percent(95)))); + println!(" 90% threshold: {}", t(self.delay(Perbill::from_percent(90)))); + println!(" 75% threshold: {}", t(self.delay(Perbill::from_percent(75)))); + println!(" 60% threshold: {}", t(self.delay(Perbill::from_percent(60)))); + } + } + /// Determine the `y` value for the given `x` value. pub(crate) fn threshold(&self, x: Perbill) -> Perbill { match self { - Self::LinearDecreasing { begin, delta } => *begin - (*delta * x).min(*begin), + Self::LinearDecreasing { length, floor, ceil } => + *ceil - (x.min(*length).saturating_div(*length, Down) * (*ceil - *floor)), + Self::SteppedDecreasing { begin, end, step, period } => + (*begin - (step.int_mul(x.int_div(*period))).min(*begin)).max(*end), + Self::Reciprocal { factor, x_offset, y_offset } => factor + .checked_rounding_div(FixedI64::from(x) + *x_offset, Low) + .map(|yp| (yp + *y_offset).into_clamped_perthing()) + .unwrap_or_else(Perbill::one), + } + } + + /// Determine the `y` value for the given `x` value. + /// + /// This is a partial implementation designed only for use in const functions. + const fn const_threshold(&self, x: Perbill) -> Perbill { + match self { + Self::Reciprocal { factor, x_offset, y_offset } => { + match factor.checked_rounding_div(FixedI64::from_perbill(x).add(*x_offset), Low) { + Some(yp) => (yp.add(*y_offset)).into_perbill(), + None => Perbill::one(), + } + }, + _ => panic!("const_threshold cannot be used on this curve"), } } /// Determine the smallest `x` value such that `passing` returns `true` when passed along with /// the given `y` value. /// + /// If `passing` never returns `true` for any value of `x` when paired with `y`, then + /// `Perbill::one` may be returned. + /// /// ```nocompile /// let c = Curve::LinearDecreasing { begin: Perbill::one(), delta: Perbill::one() }; /// // ^^^ Can be any curve. @@ -307,12 +439,27 @@ impl Curve { /// ``` pub fn delay(&self, y: Perbill) -> Perbill { match self { - Self::LinearDecreasing { begin, delta } => - if delta.is_zero() { - *delta + Self::LinearDecreasing { length, floor, ceil } => + if y < *floor { + Perbill::one() + } else if y > *ceil { + Perbill::zero() + } else { + (*ceil - y).saturating_div(*ceil - *floor, Up).saturating_mul(*length) + }, + Self::SteppedDecreasing { begin, end, step, period } => + if y < *end { + Perbill::one() } else { - (*begin - y.min(*begin)).min(*delta) / *delta + period.int_mul((*begin - y.min(*begin) + step.less_epsilon()).int_div(*step)) }, + Self::Reciprocal { factor, x_offset, y_offset } => { + let y = FixedI64::from(y); + let maybe_term = factor.checked_rounding_div(y - *y_offset, High); + maybe_term + .and_then(|term| (term - *x_offset).try_into_perthing().ok()) + .unwrap_or_else(Perbill::one) + }, } } @@ -326,14 +473,176 @@ impl Curve { impl Debug for Curve { fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { match self { - Self::LinearDecreasing { begin, delta } => { + Self::LinearDecreasing { length, floor, ceil } => { + write!( + f, + "Linear[(0%, {:?}) -> ({:?}, {:?}) -> (100%, {:?})]", + ceil, length, floor, floor, + ) + }, + Self::SteppedDecreasing { begin, end, step, period } => { + write!( + f, + "Stepped[(0%, {:?}) -> (100%, {:?}) by ({:?}, {:?})]", + begin, end, period, step, + ) + }, + Self::Reciprocal { factor, x_offset, y_offset } => { write!( f, - "Linear[(0%, {}%) -> (100%, {}%)]", - *begin * 100u32, - (*begin - *delta) * 100u32, + "Reciprocal[factor of {:?}, x_offset of {:?}, y_offset of {:?}]", + factor, x_offset, y_offset, ) }, } } } + +#[cfg(test)] +mod tests { + use super::*; + use frame_support::traits::ConstU32; + use sp_runtime::PerThing; + + const fn percent(x: u128) -> FixedI64 { + FixedI64::from_rational(x, 100) + } + + const TIP_APP: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); + const TIP_SUP: Curve = Curve::make_reciprocal(1, 28, percent(4), percent(0), percent(50)); + const ROOT_APP: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); + const ROOT_SUP: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); + const WHITE_APP: Curve = + Curve::make_reciprocal(16, 28 * 24, percent(96), percent(50), percent(100)); + const WHITE_SUP: Curve = Curve::make_reciprocal(1, 28, percent(20), percent(10), percent(50)); + const SMALL_APP: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); + const SMALL_SUP: Curve = Curve::make_reciprocal(8, 28, percent(1), percent(0), percent(50)); + const MID_APP: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); + const MID_SUP: Curve = Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); + const BIG_APP: Curve = Curve::make_linear(23, 28, percent(50), percent(100)); + const BIG_SUP: Curve = Curve::make_reciprocal(16, 28, percent(1), percent(0), percent(50)); + const HUGE_APP: Curve = Curve::make_linear(28, 28, percent(50), percent(100)); + const HUGE_SUP: Curve = Curve::make_reciprocal(20, 28, percent(1), percent(0), percent(50)); + const PARAM_APP: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); + const PARAM_SUP: Curve = Curve::make_reciprocal(7, 28, percent(10), percent(0), percent(50)); + const ADMIN_APP: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); + const ADMIN_SUP: Curve = Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); + + // TODO: ceil for linear. + + #[test] + #[should_panic] + fn check_curves() { + TIP_APP.info(28u32, "Tip Approval"); + TIP_SUP.info(28u32, "Tip Support"); + ROOT_APP.info(28u32, "Root Approval"); + ROOT_SUP.info(28u32, "Root Support"); + WHITE_APP.info(28u32, "Whitelist Approval"); + WHITE_SUP.info(28u32, "Whitelist Support"); + SMALL_APP.info(28u32, "Small Spend Approval"); + SMALL_SUP.info(28u32, "Small Spend Support"); + MID_APP.info(28u32, "Mid Spend Approval"); + MID_SUP.info(28u32, "Mid Spend Support"); + BIG_APP.info(28u32, "Big Spend Approval"); + BIG_SUP.info(28u32, "Big Spend Support"); + HUGE_APP.info(28u32, "Huge Spend Approval"); + HUGE_SUP.info(28u32, "Huge Spend Support"); + PARAM_APP.info(28u32, "Mid-tier Parameter Change Approval"); + PARAM_SUP.info(28u32, "Mid-tier Parameter Change Support"); + ADMIN_APP.info(28u32, "Admin (e.g. Cancel Slash) Approval"); + ADMIN_SUP.info(28u32, "Admin (e.g. Cancel Slash) Support"); + assert!(false); + } + + #[test] + fn insert_sorted_works() { + let mut b: BoundedVec> = vec![20, 30, 40].try_into().unwrap(); + assert!(b.insert_sorted_by_key(10, |&x| x)); + assert_eq!(&b[..], &[10, 20, 30, 40][..]); + + assert!(b.insert_sorted_by_key(60, |&x| x)); + assert_eq!(&b[..], &[10, 20, 30, 40, 60][..]); + + assert!(b.insert_sorted_by_key(50, |&x| x)); + assert_eq!(&b[..], &[10, 20, 30, 40, 50, 60][..]); + + assert!(!b.insert_sorted_by_key(9, |&x| x)); + assert_eq!(&b[..], &[10, 20, 30, 40, 50, 60][..]); + + assert!(b.insert_sorted_by_key(11, |&x| x)); + assert_eq!(&b[..], &[11, 20, 30, 40, 50, 60][..]); + + assert!(b.insert_sorted_by_key(21, |&x| x)); + assert_eq!(&b[..], &[20, 21, 30, 40, 50, 60][..]); + + assert!(b.insert_sorted_by_key(61, |&x| x)); + assert_eq!(&b[..], &[21, 30, 40, 50, 60, 61][..]); + + assert!(b.insert_sorted_by_key(51, |&x| x)); + assert_eq!(&b[..], &[30, 40, 50, 51, 60, 61][..]); + } + + #[test] + fn translated_reciprocal_works() { + let c: Curve = Curve::Reciprocal { + factor: FixedI64::from_float(0.03125), + x_offset: FixedI64::from_float(0.0363306838226), + y_offset: FixedI64::from_float(0.139845532427), + }; + c.info(28u32, "Test"); + + for i in 0..9_696_969u32 { + let query = Perbill::from_rational(i, 9_696_969); + // Determine the nearest point in time when the query will be above threshold. + let delay_needed = c.delay(query); + // Ensure that it actually does pass at that time, or that it will never pass. + assert!(delay_needed.is_one() || c.passing(delay_needed, query)); + } + } + + #[test] + fn stepped_decreasing_works() { + fn pc(x: u32) -> Perbill { + Perbill::from_percent(x) + } + + let c = + Curve::SteppedDecreasing { begin: pc(80), end: pc(30), step: pc(10), period: pc(15) }; + + for i in 0..9_696_969u32 { + let query = Perbill::from_rational(i, 9_696_969); + // Determine the nearest point in time when the query will be above threshold. + let delay_needed = c.delay(query); + // Ensure that it actually does pass at that time, or that it will never pass. + assert!(delay_needed.is_one() || c.passing(delay_needed, query)); + } + + assert_eq!(c.threshold(pc(0)), pc(80)); + assert_eq!(c.threshold(pc(15).less_epsilon()), pc(80)); + assert_eq!(c.threshold(pc(15)), pc(70)); + assert_eq!(c.threshold(pc(30).less_epsilon()), pc(70)); + assert_eq!(c.threshold(pc(30)), pc(60)); + assert_eq!(c.threshold(pc(45).less_epsilon()), pc(60)); + assert_eq!(c.threshold(pc(45)), pc(50)); + assert_eq!(c.threshold(pc(60).less_epsilon()), pc(50)); + assert_eq!(c.threshold(pc(60)), pc(40)); + assert_eq!(c.threshold(pc(75).less_epsilon()), pc(40)); + assert_eq!(c.threshold(pc(75)), pc(30)); + assert_eq!(c.threshold(pc(100)), pc(30)); + + assert_eq!(c.delay(pc(100)), pc(0)); + assert_eq!(c.delay(pc(80)), pc(0)); + assert_eq!(c.delay(pc(80).less_epsilon()), pc(15)); + assert_eq!(c.delay(pc(70)), pc(15)); + assert_eq!(c.delay(pc(70).less_epsilon()), pc(30)); + assert_eq!(c.delay(pc(60)), pc(30)); + assert_eq!(c.delay(pc(60).less_epsilon()), pc(45)); + assert_eq!(c.delay(pc(50)), pc(45)); + assert_eq!(c.delay(pc(50).less_epsilon()), pc(60)); + assert_eq!(c.delay(pc(40)), pc(60)); + assert_eq!(c.delay(pc(40).less_epsilon()), pc(75)); + assert_eq!(c.delay(pc(30)), pc(75)); + assert_eq!(c.delay(pc(30).less_epsilon()), pc(100)); + assert_eq!(c.delay(pc(0)), pc(100)); + } +} diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index ecd04c3e48b52..008105dc737ea 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -23,7 +23,7 @@ use crate as scheduler; use frame_support::{ ord_parameter_types, parameter_types, traits::{ - ConstU32, ConstU64, Contains, EnsureOneOf, EqualPrivilegeOnly, OnFinalize, OnInitialize, + ConstU32, ConstU64, Contains, EitherOfDiverse, EqualPrivilegeOnly, OnFinalize, OnInitialize, }, weights::constants::RocksDbWeight, }; @@ -174,7 +174,7 @@ impl Config for Test { type PalletsOrigin = OriginCaller; type Call = Call; type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; + type ScheduleOrigin = EitherOfDiverse, EnsureSignedBy>; type MaxScheduledPerBlock = ConstU32<10>; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index eb9129ac4b436..12de0ff9cc665 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -990,7 +990,7 @@ mod tests { let (validator_stash, nominators) = create_validator_with_nominators::( n, - ::MaxNominatorRewardedPerValidator::get(), + <::MaxNominatorRewardedPerValidator as Get<_>>::get(), false, RewardDestination::Staked, ) @@ -1015,7 +1015,7 @@ mod tests { let (validator_stash, _nominators) = create_validator_with_nominators::( n, - ::MaxNominatorRewardedPerValidator::get(), + <::MaxNominatorRewardedPerValidator as Get<_>>::get(), false, RewardDestination::Staked, ) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index ccd9558c5c21d..d0ebef27b4ef6 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3388,7 +3388,7 @@ fn six_session_delay() { #[test] fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward() { ExtBuilder::default().build_and_execute(|| { - for i in 0..=::MaxNominatorRewardedPerValidator::get() { + for i in 0..=<::MaxNominatorRewardedPerValidator as Get<_>>::get() { let stash = 10_000 + i as AccountId; let controller = 20_000 + i as AccountId; let balance = 10_000 + i as Balance; @@ -3411,7 +3411,7 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( mock::make_all_reward_payment(1); // Assert only nominators from 1 to Max are rewarded - for i in 0..=::MaxNominatorRewardedPerValidator::get() { + for i in 0..=<::MaxNominatorRewardedPerValidator as Get<_>>::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; if stash == 10_000 { @@ -3649,7 +3649,8 @@ fn payout_stakers_handles_weight_refund() { // Note: this test relies on the assumption that `payout_stakers_alive_staked` is solely used by // `payout_stakers` to calculate the weight of each payout op. ExtBuilder::default().has_stakers(false).build_and_execute(|| { - let max_nom_rewarded = ::MaxNominatorRewardedPerValidator::get(); + let max_nom_rewarded = + <::MaxNominatorRewardedPerValidator as Get<_>>::get(); // Make sure the configured value is meaningful for our use. assert!(max_nom_rewarded >= 4); let half_max_nom_rewarded = max_nom_rewarded / 2; diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 178fddb61b0a2..fa37fa5cda22b 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -350,6 +350,13 @@ macro_rules! parameter_types { I::from(Self::get()) } } + + impl $crate::traits::TypedGet for $name { + type Type = $type; + fn get() -> $type { + Self::get() + } + } }; (IMPL $name:ident, $type:ty, $value:expr) => { impl $name { @@ -364,6 +371,13 @@ macro_rules! parameter_types { I::from(Self::get()) } } + + impl $crate::traits::TypedGet for $name { + type Type = $type; + fn get() -> $type { + Self::get() + } + } }; (IMPL_STORAGE $name:ident, $type:ty, $value:expr) => { impl $name { @@ -397,6 +411,13 @@ macro_rules! parameter_types { I::from(Self::get()) } } + + impl $crate::traits::TypedGet for $name { + type Type = $type; + fn get() -> $type { + Self::get() + } + } }; ( $( #[ $attr:meta ] )* @@ -805,7 +826,7 @@ pub mod tests { }; use codec::{Codec, EncodeLike}; use frame_support::traits::CrateVersion; - use sp_io::TestExternalities; + use sp_io::{MultiRemovalResults, TestExternalities}; use sp_std::result; /// A PalletInfo implementation which just panics. @@ -1065,16 +1086,61 @@ pub mod tests { }); } + #[test] + fn double_map_basic_insert_remove_remove_prefix_with_commit_should_work() { + let key1 = 17u32; + let key2 = 18u32; + type DoubleMap = DataDM; + let mut e = new_test_ext(); + e.execute_with(|| { + // initialized during genesis + assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64); + + // get / insert / take + assert_eq!(DoubleMap::get(&key1, &key2), 0u64); + DoubleMap::insert(&key1, &key2, &4u64); + assert_eq!(DoubleMap::get(&key1, &key2), 4u64); + assert_eq!(DoubleMap::take(&key1, &key2), 4u64); + assert_eq!(DoubleMap::get(&key1, &key2), 0u64); + + // mutate + DoubleMap::mutate(&key1, &key2, |val| *val = 15); + assert_eq!(DoubleMap::get(&key1, &key2), 15u64); + + // remove + DoubleMap::remove(&key1, &key2); + assert_eq!(DoubleMap::get(&key1, &key2), 0u64); + + // remove prefix + DoubleMap::insert(&key1, &key2, &4u64); + DoubleMap::insert(&key1, &(key2 + 1), &4u64); + DoubleMap::insert(&(key1 + 1), &key2, &4u64); + DoubleMap::insert(&(key1 + 1), &(key2 + 1), &4u64); + }); + e.commit_all().unwrap(); + e.execute_with(|| { + assert!(matches!( + DoubleMap::clear_prefix(&key1, u32::max_value(), None), + MultiRemovalResults { maybe_cursor: None, backend: 2, unique: 2, loops: 2 } + )); + assert_eq!(DoubleMap::get(&key1, &key2), 0u64); + assert_eq!(DoubleMap::get(&key1, &(key2 + 1)), 0u64); + assert_eq!(DoubleMap::get(&(key1 + 1), &key2), 4u64); + assert_eq!(DoubleMap::get(&(key1 + 1), &(key2 + 1)), 4u64); + }); + } + #[test] fn double_map_basic_insert_remove_remove_prefix_should_work() { new_test_ext().execute_with(|| { + let key1 = 17u32; + let key2 = 18u32; type DoubleMap = DataDM; + // initialized during genesis assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64); // get / insert / take - let key1 = 17u32; - let key2 = 18u32; assert_eq!(DoubleMap::get(&key1, &key2), 0u64); DoubleMap::insert(&key1, &key2, &4u64); assert_eq!(DoubleMap::get(&key1, &key2), 4u64); @@ -1082,9 +1148,7 @@ pub mod tests { assert_eq!(DoubleMap::get(&key1, &key2), 0u64); // mutate - DoubleMap::mutate(&key1, &key2, |val| { - *val = 15; - }); + DoubleMap::mutate(&key1, &key2, |val| *val = 15); assert_eq!(DoubleMap::get(&key1, &key2), 15u64); // remove @@ -1096,13 +1160,18 @@ pub mod tests { DoubleMap::insert(&key1, &(key2 + 1), &4u64); DoubleMap::insert(&(key1 + 1), &key2, &4u64); DoubleMap::insert(&(key1 + 1), &(key2 + 1), &4u64); + // all in overlay + assert!(matches!( + DoubleMap::clear_prefix(&key1, u32::max_value(), None), + MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 } + )); + // Note this is the incorrect answer (for now), since we are using v2 of + // `clear_prefix`. + // When we switch to v3, then this will become: + // MultiRemovalResults:: { maybe_cursor: None, backend: 0, unique: 2, loops: 2 }, assert!(matches!( DoubleMap::clear_prefix(&key1, u32::max_value(), None), - // Note this is the incorrect answer (for now), since we are using v2 of - // `clear_prefix`. - // When we switch to v3, then this will become: - // sp_io::MultiRemovalResults::NoneLeft { db: 0, total: 2 }, - sp_io::MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 }, + MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 } )); assert_eq!(DoubleMap::get(&key1, &key2), 0u64); assert_eq!(DoubleMap::get(&key1, &(key2 + 1)), 0u64); @@ -1321,7 +1390,7 @@ pub mod pallet_prelude { }, traits::{ ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, IsType, - PalletInfoAccess, StorageInfoTrait, StorageVersion, + PalletInfoAccess, StorageInfoTrait, StorageVersion, TypedGet, }, weights::{DispatchClass, Pays, Weight}, Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity, diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index a6fc88dfb5e76..d1872544e024d 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -59,7 +59,7 @@ pub use misc::{ ConstU32, ConstU64, ConstU8, DefensiveSaturating, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider, - PreimageRecipient, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, UnixTime, + PreimageRecipient, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime, WrapperKeepOpaque, WrapperOpaque, }; #[doc(hidden)] @@ -93,9 +93,11 @@ pub use storage::{ }; mod dispatch; +#[allow(deprecated)] +pub use dispatch::EnsureOneOf; pub use dispatch::{ - AsEnsureOriginWithArg, DispatchableWithStorageLayer, EnsureOneOf, EnsureOrigin, - EnsureOriginWithArg, OriginTrait, UnfilteredDispatchable, + AsEnsureOriginWithArg, DispatchableWithStorageLayer, EitherOf, EitherOfDiverse, EnsureOrigin, + EnsureOriginWithArg, NeverEnsureOrigin, OriginTrait, UnfilteredDispatchable, }; mod voting; diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 1cec6cf837aba..b1bd52ca960da 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -43,6 +43,19 @@ pub trait EnsureOrigin { fn successful_origin() -> OuterOrigin; } +/// `EnsureOrigin` implementation that always fails. +pub struct NeverEnsureOrigin(sp_std::marker::PhantomData); +impl EnsureOrigin for NeverEnsureOrigin { + type Success = Success; + fn try_origin(o: OO) -> Result { + Err(o) + } + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> OO { + panic!("No `successful_origin` possible for `NeverEnsureOrigin`") + } +} + /// Some sort of check on the origin is performed by this object. pub trait EnsureOriginWithArg { /// A return type. @@ -163,13 +176,16 @@ pub trait OriginTrait: Sized { fn signed(by: Self::AccountId) -> Self; } -/// The "OR gate" implementation of `EnsureOrigin`. +/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L` +/// and `R`, with them combined using an `Either` type. /// /// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. -pub struct EnsureOneOf(sp_std::marker::PhantomData<(L, R)>); +/// +/// Successful origin is derived from the left side. +pub struct EitherOfDiverse(sp_std::marker::PhantomData<(L, R)>); impl, R: EnsureOrigin> - EnsureOrigin for EnsureOneOf + EnsureOrigin for EitherOfDiverse { type Success = Either; fn try_origin(o: OuterOrigin) -> Result { @@ -183,17 +199,53 @@ impl, R: EnsureOrigin> } } +/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L` +/// and `R`, with them combined using an `Either` type. +/// +/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. +/// +/// Successful origin is derived from the left side. +#[deprecated = "Use `EitherOfDiverse` instead"] +pub type EnsureOneOf = EitherOfDiverse; + +/// "OR gate" implementation of `EnsureOrigin`, `Success` type for both `L` and `R` must +/// be equal. +/// +/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. +/// +/// Successful origin is derived from the left side. +pub struct EitherOf(sp_std::marker::PhantomData<(L, R)>); + +impl< + OuterOrigin, + L: EnsureOrigin, + R: EnsureOrigin, + > EnsureOrigin for EitherOf +{ + type Success = L::Success; + fn try_origin(o: OuterOrigin) -> Result { + L::try_origin(o).or_else(|o| R::try_origin(o)) + } + + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> OuterOrigin { + L::successful_origin() + } +} + #[cfg(test)] mod tests { use super::*; + use crate::traits::{ConstBool, ConstU8, TypedGet}; + use std::marker::PhantomData; - struct EnsureSuccess; - struct EnsureFail; + struct EnsureSuccess(PhantomData); + struct EnsureFail(PhantomData); - impl EnsureOrigin<()> for EnsureSuccess { - type Success = (); + impl EnsureOrigin<()> for EnsureSuccess { + type Success = V::Type; fn try_origin(_: ()) -> Result { - Ok(()) + Ok(V::get()) } #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> () { @@ -201,8 +253,8 @@ mod tests { } } - impl EnsureOrigin<()> for EnsureFail { - type Success = (); + impl EnsureOrigin<()> for EnsureFail { + type Success = T; fn try_origin(_: ()) -> Result { Err(()) } @@ -213,10 +265,46 @@ mod tests { } #[test] - fn ensure_one_of_test() { - assert!(>::try_origin(()).is_ok()); - assert!(>::try_origin(()).is_ok()); - assert!(>::try_origin(()).is_ok()); - assert!(>::try_origin(()).is_err()); + fn either_of_diverse_works() { + assert_eq!( + EitherOfDiverse::< + EnsureSuccess>, + EnsureSuccess>, + >::try_origin(()).unwrap().left(), + Some(true) + ); + assert_eq!( + EitherOfDiverse::>, EnsureFail>::try_origin(()) + .unwrap() + .left(), + Some(true) + ); + assert_eq!( + EitherOfDiverse::, EnsureSuccess>>::try_origin(()) + .unwrap() + .right(), + Some(0u8) + ); + assert!(EitherOfDiverse::, EnsureFail>::try_origin(()).is_err()); + } + + #[test] + fn either_of_works() { + assert_eq!( + EitherOf::< + EnsureSuccess>, + EnsureSuccess>, + >::try_origin(()).unwrap(), + true + ); + assert_eq!( + EitherOf::>, EnsureFail>::try_origin(()).unwrap(), + true + ); + assert_eq!( + EitherOf::, EnsureSuccess>>::try_origin(()).unwrap(), + false + ); + assert!(EitherOf::, EnsureFail>::try_origin(()).is_err()); } } diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 03420f64dd55b..bea4e2a394411 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -387,6 +387,16 @@ where } } +/// A trait for querying a single value from a type defined in the trait. +/// +/// It is not required that the value is constant. +pub trait TypedGet { + /// The type which is returned. + type Type; + /// Return the current value. + fn get() -> Self::Type; +} + /// A trait for querying a single value from a type. /// /// It is not required that the value is constant. @@ -423,6 +433,12 @@ macro_rules! impl_const_get { Some(T) } } + impl TypedGet for $name { + type Type = $t; + fn get() -> $t { + T + } + } }; } diff --git a/frame/support/src/traits/voting.rs b/frame/support/src/traits/voting.rs index 978c5ce4f6a01..6c802a6112246 100644 --- a/frame/support/src/traits/voting.rs +++ b/frame/support/src/traits/voting.rs @@ -95,16 +95,18 @@ impl + UniqueSaturatedFrom> CurrencyToVote } } -pub trait VoteTally { - fn ayes(&self) -> Votes; - fn turnout(&self) -> Perbill; - fn approval(&self) -> Perbill; +pub trait VoteTally { + fn new(_: Class) -> Self; + fn ayes(&self, class: Class) -> Votes; + fn support(&self, class: Class) -> Perbill; + fn approval(&self, class: Class) -> Perbill; #[cfg(feature = "runtime-benchmarks")] - fn unanimity() -> Self; + fn unanimity(class: Class) -> Self; #[cfg(feature = "runtime-benchmarks")] - fn from_requirements(turnout: Perbill, approval: Perbill) -> Self; + fn rejection(class: Class) -> Self; + #[cfg(feature = "runtime-benchmarks")] + fn from_requirements(support: Perbill, approval: Perbill, class: Class) -> Self; } - pub enum PollStatus { None, Ongoing(Tally, Class), diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index f2999f945c5c2..bc28cc7e8118e 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -86,7 +86,7 @@ use frame_support::{ storage, traits::{ ConstU32, Contains, EnsureOrigin, Get, HandleLifetime, OnKilledAccount, OnNewAccount, - OriginTrait, PalletInfo, SortedMembers, StoredMap, + OriginTrait, PalletInfo, SortedMembers, StoredMap, TypedGet, }, weights::{ extract_actual_weight, DispatchClass, DispatchInfo, PerDispatchClass, RuntimeDbWeight, @@ -787,6 +787,29 @@ impl, O>> + From>, Acco } } +pub struct EnsureRootWithSuccess( + sp_std::marker::PhantomData<(AccountId, Success)>, +); +impl< + O: Into, O>> + From>, + AccountId, + Success: TypedGet, + > EnsureOrigin for EnsureRootWithSuccess +{ + type Success = Success::Type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Root => Ok(Success::get()), + r => Err(O::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> O { + O::from(RawOrigin::Root) + } +} + pub struct EnsureSigned(sp_std::marker::PhantomData); impl, O>> + From>, AccountId: Decode> EnsureOrigin for EnsureSigned diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index 27cce5576a3b9..235952fd1092c 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -144,6 +144,7 @@ impl pallet_treasury::Config for Test { type WeightInfo = (); type SpendFunds = (); type MaxApprovals = ConstU32<100>; + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; } parameter_types! { pub const TipFindersFee: Percent = Percent::from_percent(20); diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index 47bc1b9ea99de..4f17189d79b39 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -22,7 +22,11 @@ use super::{Pallet as Treasury, *}; use frame_benchmarking::{account, benchmarks_instance_pallet}; -use frame_support::{ensure, traits::OnInitialize}; +use frame_support::{ + dispatch::UnfilteredDispatchable, + ensure, + traits::{EnsureOrigin, OnInitialize}, +}; use frame_system::RawOrigin; const SEED: u32 = 0; @@ -57,7 +61,21 @@ fn setup_pot_account, I: 'static>() { let _ = T::Currency::make_free_balance_be(&pot_account, value); } +fn assert_last_event, I: 'static>(generic_event: >::Event) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + benchmarks_instance_pallet! { + spend { + let (_, value, beneficiary_lookup) = setup_proposal::(SEED); + let origin = T::SpendOrigin::successful_origin(); + let beneficiary = T::Lookup::lookup(beneficiary_lookup.clone()).unwrap(); + let call = Call::::spend { amount: value, beneficiary: beneficiary_lookup }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_last_event::(Event::SpendApproved { proposal_index: 0, amount: value, beneficiary }.into()) + } + propose_spend { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); // Whitelist caller account from further DB operations. diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 419970ed18afa..6730f985b16e0 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -198,6 +198,11 @@ pub mod pallet { /// NOTE: This parameter is also used within the Bounties Pallet extension if enabled. #[pallet::constant] type MaxApprovals: Get; + + /// The origin required for approving spends from the treasury outside of the proposal + /// process. The `Success` value is the maximum amount that this origin is allowed to + /// spend at a time. + type SpendOrigin: EnsureOrigin>; } /// Number of proposals that have been made. @@ -275,6 +280,12 @@ pub mod pallet { Rollover { rollover_balance: BalanceOf }, /// Some funds have been deposited. Deposit { value: BalanceOf }, + /// A new spend proposal has been approved. + SpendApproved { + proposal_index: ProposalIndex, + amount: BalanceOf, + beneficiary: T::AccountId, + }, } /// Error for the treasury pallet. @@ -286,6 +297,9 @@ pub mod pallet { InvalidIndex, /// Too many approvals in the queue. TooManyApprovals, + /// The spend origin is valid but the amount it is allowed to spend is lower than the + /// amount to be spent. + InsufficientPermission, /// Proposal has not been approved. ProposalNotApproved, } @@ -393,6 +407,40 @@ pub mod pallet { Ok(()) } + /// Propose and approve a spend of treasury funds. + /// + /// - `origin`: Must be `SpendOrigin` with the `Success` value being at least `amount`. + /// - `amount`: The amount to be transferred from the treasury to the `beneficiary`. + /// - `beneficiary`: The destination account for the transfer. + /// + /// NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the + /// beneficiary. + #[pallet::weight(T::WeightInfo::spend())] + pub fn spend( + origin: OriginFor, + #[pallet::compact] amount: BalanceOf, + beneficiary: ::Source, + ) -> DispatchResult { + let max_amount = T::SpendOrigin::ensure_origin(origin)?; + let beneficiary = T::Lookup::lookup(beneficiary)?; + + ensure!(amount <= max_amount, Error::::InsufficientPermission); + let proposal_index = Self::proposal_count(); + Approvals::::try_append(proposal_index) + .map_err(|_| Error::::TooManyApprovals)?; + let proposal = Proposal { + proposer: beneficiary.clone(), + value: amount, + beneficiary: beneficiary.clone(), + bond: Default::default(), + }; + Proposals::::insert(proposal_index, proposal); + ProposalCount::::put(proposal_index + 1); + + Self::deposit_event(Event::SpendApproved { proposal_index, amount, beneficiary }); + Ok(()) + } + /// Force a previously approved proposal to be removed from the approval queue. /// The original deposit will no longer be returned. /// diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index b755db29682aa..a21296d1b39ec 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -24,7 +24,7 @@ use std::cell::RefCell; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BadOrigin, BlakeTwo256, IdentityLookup}, }; use frame_support::{ @@ -101,8 +101,26 @@ parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - pub const MaxApprovals: u32 = 100; } +pub struct TestSpendOrigin; +impl frame_support::traits::EnsureOrigin for TestSpendOrigin { + type Success = u64; + fn try_origin(o: Origin) -> Result { + Result::, Origin>::from(o).and_then(|o| match o { + frame_system::RawOrigin::Root => Ok(u64::max_value()), + frame_system::RawOrigin::Signed(10) => Ok(5), + frame_system::RawOrigin::Signed(11) => Ok(10), + frame_system::RawOrigin::Signed(12) => Ok(20), + frame_system::RawOrigin::Signed(13) => Ok(50), + r => Err(Origin::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> Origin { + Origin::root() + } +} + impl Config for Test { type PalletId = TreasuryPalletId; type Currency = pallet_balances::Pallet; @@ -119,6 +137,7 @@ impl Config for Test { type WeightInfo = (); type SpendFunds = (); type MaxApprovals = ConstU32<100>; + type SpendOrigin = TestSpendOrigin; } pub fn new_test_ext() -> sp_io::TestExternalities { @@ -141,6 +160,51 @@ fn genesis_config_works() { }); } +#[test] +fn spend_origin_permissioning_works() { + new_test_ext().execute_with(|| { + assert_noop!(Treasury::spend(Origin::signed(1), 1, 1), BadOrigin); + assert_noop!( + Treasury::spend(Origin::signed(10), 6, 1), + Error::::InsufficientPermission + ); + assert_noop!( + Treasury::spend(Origin::signed(11), 11, 1), + Error::::InsufficientPermission + ); + assert_noop!( + Treasury::spend(Origin::signed(12), 21, 1), + Error::::InsufficientPermission + ); + assert_noop!( + Treasury::spend(Origin::signed(13), 51, 1), + Error::::InsufficientPermission + ); + }); +} + +#[test] +fn spend_origin_works() { + new_test_ext().execute_with(|| { + // Check that accumulate works when we have Some value in Dummy already. + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(Origin::signed(11), 10, 6)); + assert_ok!(Treasury::spend(Origin::signed(12), 20, 6)); + assert_ok!(Treasury::spend(Origin::signed(13), 50, 6)); + + >::on_initialize(1); + assert_eq!(Balances::free_balance(6), 0); + + >::on_initialize(2); + assert_eq!(Balances::free_balance(6), 100); + assert_eq!(Treasury::pot(), 0); + }); +} + #[test] fn minting_works() { new_test_ext().execute_with(|| { @@ -372,7 +436,7 @@ fn max_approvals_limited() { Balances::make_free_balance_be(&Treasury::account_id(), u64::MAX); Balances::make_free_balance_be(&0, u64::MAX); - for _ in 0..MaxApprovals::get() { + for _ in 0..::MaxApprovals::get() { assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index f1667bea35480..f6b5414a05652 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -44,6 +44,7 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_treasury. pub trait WeightInfo { + fn spend() -> Weight; fn propose_spend() -> Weight; fn reject_proposal() -> Weight; fn approve_proposal(p: u32, ) -> Weight; @@ -54,6 +55,13 @@ pub trait WeightInfo { /// Weights for pallet_treasury using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { + // Storage: Treasury ProposalCount (r:1 w:1) + // Storage: Treasury Proposals (r:0 w:1) + fn spend() -> Weight { + (22_063_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { @@ -100,6 +108,13 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { + // Storage: Treasury ProposalCount (r:1 w:1) + // Storage: Treasury Proposals (r:0 w:1) + fn spend() -> Weight { + (22_063_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 4fdf983943c41..d7046b3254699 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -29,6 +29,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] criterion = "0.3" primitive-types = "0.11.1" +sp-core = { version = "6.0.0", features = ["full_crypto"], path = "../core" } rand = "0.7.2" [features] diff --git a/primitives/arithmetic/src/fixed_point.rs b/primitives/arithmetic/src/fixed_point.rs index 7ce17bb72611f..f4ed70ee8b5dc 100644 --- a/primitives/arithmetic/src/fixed_point.rs +++ b/primitives/arithmetic/src/fixed_point.rs @@ -18,12 +18,12 @@ //! Decimal Fixed Point implementations for Substrate runtime. use crate::{ - helpers_128bit::multiply_by_rational, + helpers_128bit::{multiply_by_rational, multiply_by_rational_with_rounding, sqrt}, traits::{ Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedSub, One, SaturatedConversion, Saturating, UniqueSaturatedInto, Zero, }, - PerThing, + PerThing, Perbill, Rounding, SignedRounding, }; use codec::{CompactAs, Decode, Encode}; use sp_std::{ @@ -406,20 +406,326 @@ macro_rules! implement_fixed { } impl $name { - /// const version of `FixedPointNumber::from_inner`. + /// Create a new instance from the given `inner` value. + /// + /// `const` version of `FixedPointNumber::from_inner`. pub const fn from_inner(inner: $inner_type) -> Self { Self(inner) } + /// Return the instance's inner value. + /// + /// `const` version of `FixedPointNumber::into_inner`. + pub const fn into_inner(self) -> $inner_type { + self.0 + } + + /// Creates self from a `u32`. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn from_u32(n: u32) -> Self { + Self::from_inner((n as $inner_type) * $div) + } + + /// Convert from a `float` value. #[cfg(any(feature = "std", test))] pub fn from_float(x: f64) -> Self { Self((x * (::DIV as f64)) as $inner_type) } + /// Convert from a `Perbill` value. + pub const fn from_perbill(n: Perbill) -> Self { + Self::from_rational(n.deconstruct() as u128, 1_000_000_000) + } + + /// Convert into a `Perbill` value. Will saturate if above one or below zero. + pub const fn into_perbill(self) -> Perbill { + if self.0 <= 0 { + Perbill::zero() + } else if self.0 >= $div { + Perbill::one() + } else { + match multiply_by_rational_with_rounding( + self.0 as u128, + 1_000_000_000, + Self::DIV as u128, + Rounding::NearestPrefDown, + ) { + Some(value) => { + if value > (u32::max_value() as u128) { + panic!( + "prior logic ensures 0 Perbill::zero(), + } + } + } + + /// Convert into a `float` value. #[cfg(any(feature = "std", test))] pub fn to_float(self) -> f64 { self.0 as f64 / ::DIV as f64 } + + /// Attempt to convert into a `PerThing`. This will succeed iff `self` is at least zero + /// and at most one. If it is out of bounds, it will result in an error returning the + /// clamped value. + pub fn try_into_perthing(self) -> Result { + if self < Self::zero() { + Err(P::zero()) + } else if self > Self::one() { + Err(P::one()) + } else { + Ok(P::from_rational(self.0 as u128, $div)) + } + } + + /// Attempt to convert into a `PerThing`. This will always succeed resulting in a + /// clamped value if `self` is less than zero or greater than one. + pub fn into_clamped_perthing(self) -> P { + if self < Self::zero() { + P::zero() + } else if self > Self::one() { + P::one() + } else { + P::from_rational(self.0 as u128, $div) + } + } + + /// Negate the value. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn neg(self) -> Self { + Self(0 - self.0) + } + + /// Take the square root of a positive value. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn sqrt(self) -> Self { + match self.try_sqrt() { + Some(v) => v, + None => panic!("sqrt overflow or negative input"), + } + } + + /// Compute the square root, rounding as desired. If it overflows or is negative, then + /// `None` is returned. + pub const fn try_sqrt(self) -> Option { + if self.0 == 0 { + return Some(Self(0)) + } + if self.0 < 1 { + return None + } + let v = self.0 as u128; + + // Want x' = sqrt(x) where x = n/D and x' = n'/D (D is fixed) + // Our prefered way is: + // sqrt(n/D) = sqrt(nD / D^2) = sqrt(nD)/sqrt(D^2) = sqrt(nD)/D + // ergo n' = sqrt(nD) + // but this requires nD to fit into our type. + // if nD doesn't fit then we can fall back on: + // sqrt(nD) = sqrt(n)*sqrt(D) + // computing them individually and taking the product at the end. we will lose some + // precision though. + let maybe_vd = u128::checked_mul(v, $div); + let r = if let Some(vd) = maybe_vd { sqrt(vd) } else { sqrt(v) * sqrt($div) }; + Some(Self(r as $inner_type)) + } + + /// Add a value and return the result. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) + } + + /// Subtract a value and return the result. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn sub(self, rhs: Self) -> Self { + Self(self.0 - rhs.0) + } + + /// Multiply by a value and return the result. + /// + /// Result will be rounded to the nearest representable value, rounding down if it is + /// equidistant between two neighbours. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn mul(self, rhs: Self) -> Self { + match $name::const_checked_mul(self, rhs) { + Some(v) => v, + None => panic!("attempt to multiply with overflow"), + } + } + + /// Divide by a value and return the result. + /// + /// Result will be rounded to the nearest representable value, rounding down if it is + /// equidistant between two neighbours. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn div(self, rhs: Self) -> Self { + match $name::const_checked_div(self, rhs) { + Some(v) => v, + None => panic!("attempt to divide with overflow or NaN"), + } + } + + /// Convert into an `I129` format value. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + const fn into_i129(self) -> I129 { + #[allow(unused_comparisons)] + if self.0 < 0 { + let value = match self.0.checked_neg() { + Some(n) => n as u128, + None => u128::saturating_add(<$inner_type>::max_value() as u128, 1), + }; + I129 { value, negative: true } + } else { + I129 { value: self.0 as u128, negative: false } + } + } + + /// Convert from an `I129` format value. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + const fn from_i129(n: I129) -> Option { + let max_plus_one = u128::saturating_add(<$inner_type>::max_value() as u128, 1); + #[allow(unused_comparisons)] + let inner = if n.negative && <$inner_type>::min_value() < 0 && n.value == max_plus_one { + <$inner_type>::min_value() + } else { + let unsigned_inner = n.value as $inner_type; + if unsigned_inner as u128 != n.value || (unsigned_inner > 0) != (n.value > 0) { + return None + }; + if n.negative { + match unsigned_inner.checked_neg() { + Some(v) => v, + None => return None, + } + } else { + unsigned_inner + } + }; + Some(Self(inner)) + } + + /// Calculate an approximation of a rational. + /// + /// Result will be rounded to the nearest representable value, rounding down if it is + /// equidistant between two neighbours. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn from_rational(a: u128, b: u128) -> Self { + Self::from_rational_with_rounding(a, b, Rounding::NearestPrefDown) + } + + /// Calculate an approximation of a rational with custom rounding. + /// + /// WARNING: This is a `const` function designed for convenient use at build time and + /// will panic on overflow. Ensure that any inputs are sensible. + pub const fn from_rational_with_rounding(a: u128, b: u128, rounding: Rounding) -> Self { + if b == 0 { + panic!("attempt to divide by zero in from_rational") + } + match multiply_by_rational_with_rounding(Self::DIV as u128, a, b, rounding) { + Some(value) => match Self::from_i129(I129 { value, negative: false }) { + Some(x) => x, + None => panic!("overflow in from_rational"), + }, + None => panic!("overflow in from_rational"), + } + } + + /// Multiply by another value, returning `None` in the case of an error. + /// + /// Result will be rounded to the nearest representable value, rounding down if it is + /// equidistant between two neighbours. + pub const fn const_checked_mul(self, other: Self) -> Option { + self.const_checked_mul_with_rounding(other, SignedRounding::NearestPrefLow) + } + + /// Multiply by another value with custom rounding, returning `None` in the case of an + /// error. + /// + /// Result will be rounded to the nearest representable value, rounding down if it is + /// equidistant between two neighbours. + pub const fn const_checked_mul_with_rounding( + self, + other: Self, + rounding: SignedRounding, + ) -> Option { + let lhs = self.into_i129(); + let rhs = other.into_i129(); + let negative = lhs.negative != rhs.negative; + + match multiply_by_rational_with_rounding( + lhs.value, + rhs.value, + Self::DIV as u128, + Rounding::from_signed(rounding, negative), + ) { + Some(value) => Self::from_i129(I129 { value, negative }), + None => None, + } + } + + /// Divide by another value, returning `None` in the case of an error. + /// + /// Result will be rounded to the nearest representable value, rounding down if it is + /// equidistant between two neighbours. + pub const fn const_checked_div(self, other: Self) -> Option { + self.checked_rounding_div(other, SignedRounding::NearestPrefLow) + } + + /// Divide by another value with custom rounding, returning `None` in the case of an + /// error. + /// + /// Result will be rounded to the nearest representable value, rounding down if it is + /// equidistant between two neighbours. + pub const fn checked_rounding_div( + self, + other: Self, + rounding: SignedRounding, + ) -> Option { + if other.0 == 0 { + return None + } + + let lhs = self.into_i129(); + let rhs = other.into_i129(); + let negative = lhs.negative != rhs.negative; + + match multiply_by_rational_with_rounding( + lhs.value, + Self::DIV as u128, + rhs.value, + Rounding::from_signed(rounding, negative), + ) { + Some(value) => Self::from_i129(I129 { value, negative }), + None => None, + } + } } impl Saturating for $name { @@ -522,6 +828,10 @@ macro_rules! implement_fixed { let rhs: I129 = other.0.into(); let negative = lhs.negative != rhs.negative; + // Note that this uses the old (well-tested) code with sign-ignorant rounding. This + // is equivalent to the `SignedRounding::NearestPrefMinor`. This means it is + // expected to give exactly the same result as `const_checked_div` when the result + // is positive and a result up to one epsilon greater when it is negative. multiply_by_rational(lhs.value, Self::DIV as u128, rhs.value) .ok() .and_then(|value| from_i129(I129 { value, negative })) @@ -851,6 +1161,16 @@ macro_rules! implement_fixed { } } + #[test] + fn op_sqrt_works() { + for i in 1..1_000i64 { + let x = $name::saturating_from_rational(i, 1_000i64); + assert_eq!((x * x).try_sqrt(), Some(x)); + let x = $name::saturating_from_rational(i, 1i64); + assert_eq!((x * x).try_sqrt(), Some(x)); + } + } + #[test] fn op_div_works() { let a = $name::saturating_from_integer(42); @@ -1133,6 +1453,41 @@ macro_rules! implement_fixed { assert_eq!(a.into_inner(), 0); } + #[test] + fn from_rational_works() { + let inner_max: u128 = <$name as FixedPointNumber>::Inner::max_value() as u128; + let inner_min: u128 = 0; + let accuracy: u128 = $name::accuracy() as u128; + + // Max - 1. + let a = $name::from_rational(inner_max - 1, accuracy); + assert_eq!(a.into_inner() as u128, inner_max - 1); + + // Min + 1. + let a = $name::from_rational(inner_min + 1, accuracy); + assert_eq!(a.into_inner() as u128, inner_min + 1); + + // Max. + let a = $name::from_rational(inner_max, accuracy); + assert_eq!(a.into_inner() as u128, inner_max); + + // Min. + let a = $name::from_rational(inner_min, accuracy); + assert_eq!(a.into_inner() as u128, inner_min); + + let a = $name::from_rational(inner_max, 3 * accuracy); + assert_eq!(a.into_inner() as u128, inner_max / 3); + + let a = $name::from_rational(1, accuracy); + assert_eq!(a.into_inner() as u128, 1); + + let a = $name::from_rational(1, accuracy + 1); + assert_eq!(a.into_inner() as u128, 1); + + let a = $name::from_rational_with_rounding(1, accuracy + 1, Rounding::Down); + assert_eq!(a.into_inner() as u128, 0); + } + #[test] fn checked_mul_int_works() { let a = $name::saturating_from_integer(2); @@ -1272,6 +1627,76 @@ macro_rules! implement_fixed { ); } + #[test] + fn const_checked_mul_works() { + let inner_max = <$name as FixedPointNumber>::Inner::max_value(); + let inner_min = <$name as FixedPointNumber>::Inner::min_value(); + + let a = $name::saturating_from_integer(2u32); + + // Max - 1. + let b = $name::from_inner(inner_max - 1); + assert_eq!(a.const_checked_mul((b / 2.into())), Some(b)); + + // Max. + let c = $name::from_inner(inner_max); + assert_eq!(a.const_checked_mul((c / 2.into())), Some(b)); + + // Max + 1 => None. + let e = $name::from_inner(1); + assert_eq!(a.const_checked_mul((c / 2.into() + e)), None); + + if $name::SIGNED { + // Min + 1. + let b = $name::from_inner(inner_min + 1) / 2.into(); + let c = $name::from_inner(inner_min + 2); + assert_eq!(a.const_checked_mul(b), Some(c)); + + // Min. + let b = $name::from_inner(inner_min) / 2.into(); + let c = $name::from_inner(inner_min); + assert_eq!(a.const_checked_mul(b), Some(c)); + + // Min - 1 => None. + let b = $name::from_inner(inner_min) / 2.into() - $name::from_inner(1); + assert_eq!(a.const_checked_mul(b), None); + + let b = $name::saturating_from_rational(1i32, -2i32); + let c = $name::saturating_from_integer(-21i32); + let d = $name::saturating_from_integer(42); + + assert_eq!(b.const_checked_mul(d), Some(c)); + + let minus_two = $name::saturating_from_integer(-2i32); + assert_eq!( + b.const_checked_mul($name::max_value()), + $name::max_value().const_checked_div(minus_two) + ); + assert_eq!( + b.const_checked_mul($name::min_value()), + $name::min_value().const_checked_div(minus_two) + ); + + let c = $name::saturating_from_integer(255u32); + assert_eq!(c.const_checked_mul($name::min_value()), None); + } + + let a = $name::saturating_from_rational(1i32, 2i32); + let c = $name::saturating_from_integer(255i32); + + assert_eq!(a.const_checked_mul(42.into()), Some(21.into())); + assert_eq!(c.const_checked_mul(2.into()), Some(510.into())); + assert_eq!(c.const_checked_mul($name::max_value()), None); + assert_eq!( + a.const_checked_mul($name::max_value()), + $name::max_value().checked_div(&2.into()) + ); + assert_eq!( + a.const_checked_mul($name::min_value()), + $name::min_value().const_checked_div($name::saturating_from_integer(2)) + ); + } + #[test] fn checked_div_int_works() { let inner_max = <$name as FixedPointNumber>::Inner::max_value(); diff --git a/primitives/arithmetic/src/helpers_128bit.rs b/primitives/arithmetic/src/helpers_128bit.rs index 735b11287cbe4..260f90ed60cd0 100644 --- a/primitives/arithmetic/src/helpers_128bit.rs +++ b/primitives/arithmetic/src/helpers_128bit.rs @@ -1,6 +1,7 @@ // This file is part of Substrate. // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Some code is based upon Derek Dreery's IntegerSquareRoot impl, used under license. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,10 +21,11 @@ //! assumptions of a bigger type (u128) being available, or simply create a per-thing and use the //! multiplication implementation provided there. -use crate::biguint; +use crate::{biguint, Rounding}; use num_traits::Zero; use sp_std::{ cmp::{max, min}, + convert::TryInto, mem, }; @@ -117,3 +119,254 @@ pub fn multiply_by_rational(mut a: u128, mut b: u128, mut c: u128) -> Result u128 { + a & ((1 << 64) - 1) + } + + /// Returns the most significant 64 bits of a + const fn high_64(a: u128) -> u128 { + a >> 64 + } + + /// Returns 2^128 - a (two's complement) + const fn neg128(a: u128) -> u128 { + (!a).wrapping_add(1) + } + + /// Returns 2^128 / a + const fn div128(a: u128) -> u128 { + (neg128(a) / a).wrapping_add(1) + } + + /// Returns 2^128 % a + const fn mod128(a: u128) -> u128 { + neg128(a) % a + } + + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Double128 { + high: u128, + low: u128, + } + + impl Double128 { + pub const fn try_into_u128(self) -> Result { + match self.high { + 0 => Ok(self.low), + _ => Err(()), + } + } + + pub const fn zero() -> Self { + Self { high: 0, low: 0 } + } + + /// Return a `Double128` value representing the `scaled_value << 64`. + /// + /// This means the lower half of the `high` component will be equal to the upper 64-bits of + /// `scaled_value` (in the lower positions) and the upper half of the `low` component will + /// be equal to the lower 64-bits of `scaled_value`. + pub const fn left_shift_64(scaled_value: u128) -> Self { + Self { high: scaled_value >> 64, low: scaled_value << 64 } + } + + /// Construct a value from the upper 128 bits only, with the lower being zeroed. + pub const fn from_low(low: u128) -> Self { + Self { high: 0, low } + } + + /// Returns the same value ignoring anything in the high 128-bits. + pub const fn low_part(self) -> Self { + Self { high: 0, ..self } + } + + /// Returns a*b (in 256 bits) + pub const fn product_of(a: u128, b: u128) -> Self { + // Split a and b into hi and lo 64-bit parts + let (a_low, a_high) = (low_64(a), high_64(a)); + let (b_low, b_high) = (low_64(b), high_64(b)); + // a = (a_low + a_high << 64); b = (b_low + b_high << 64); + // ergo a*b = (a_low + a_high << 64)(b_low + b_high << 64) + // = a_low * b_low + // + a_low * b_high << 64 + // + a_high << 64 * b_low + // + a_high << 64 * b_high << 64 + // assuming: + // f = a_low * b_low + // o = a_low * b_high + // i = a_high * b_low + // l = a_high * b_high + // then: + // a*b = (o+i) << 64 + f + l << 128 + let (f, o, i, l) = (a_low * b_low, a_low * b_high, a_high * b_low, a_high * b_high); + let fl = Self { high: l, low: f }; + let i = Self::left_shift_64(i); + let o = Self::left_shift_64(o); + fl.add(i).add(o) + } + + pub const fn add(self, b: Self) -> Self { + let (low, overflow) = self.low.overflowing_add(b.low); + let carry = overflow as u128; // 1 if true, 0 if false. + let high = self.high.wrapping_add(b.high).wrapping_add(carry as u128); + Double128 { high, low } + } + + pub const fn div(mut self, rhs: u128) -> (Self, u128) { + if rhs == 1 { + return (self, 0) + } + + // (self === a; rhs === b) + // Calculate a / b + // = (a_high << 128 + a_low) / b + // let (q, r) = (div128(b), mod128(b)); + // = (a_low * (q * b + r)) + a_high) / b + // = (a_low * q * b + a_low * r + a_high)/b + // = (a_low * r + a_high) / b + a_low * q + let (q, r) = (div128(rhs), mod128(rhs)); + + // x = current result + // a = next number + let mut x = Self::zero(); + while self.high != 0 { + // x += a.low * q + x = x.add(Self::product_of(self.high, q)); + // a = a.low * r + a.high + self = Self::product_of(self.high, r).add(self.low_part()); + } + + (x.add(Self::from_low(self.low / rhs)), self.low % rhs) + } + } +} + +/// Returns `a * b / c` and `(a * b) % c` (wrapping to 128 bits) or `None` in the case of +/// overflow. +pub const fn multiply_by_rational_with_rounding( + a: u128, + b: u128, + c: u128, + r: Rounding, +) -> Option { + use double128::Double128; + if c == 0 { + panic!("attempt to divide by zero") + } + let (result, remainder) = Double128::product_of(a, b).div(c); + let mut result: u128 = match result.try_into_u128() { + Ok(v) => v, + Err(_) => return None, + }; + if match r { + Rounding::Up => remainder > 0, + // cannot be `(c + 1) / 2` since `c` might be `max_value` and overflow. + Rounding::NearestPrefUp => remainder >= c / 2 + c % 2, + Rounding::NearestPrefDown => remainder > c / 2, + Rounding::Down => false, + } { + result = match result.checked_add(1) { + Some(v) => v, + None => return None, + }; + } + Some(result) +} + +pub const fn sqrt(mut n: u128) -> u128 { + // Modified from https://github.com/derekdreery/integer-sqrt-rs (Apache/MIT). + if n == 0 { + return 0 + } + + // Compute bit, the largest power of 4 <= n + let max_shift: u32 = 0u128.leading_zeros() - 1; + let shift: u32 = (max_shift - n.leading_zeros()) & !1; + let mut bit = 1u128 << shift; + + // Algorithm based on the implementation in: + // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2) + // Note that result/bit are logically unsigned (even if T is signed). + let mut result = 0u128; + while bit != 0 { + if n >= result + bit { + n -= result + bit; + result = (result >> 1) + bit; + } else { + result = result >> 1; + } + bit = bit >> 2; + } + result +} + +#[cfg(test)] +mod tests { + use super::*; + use codec::{Decode, Encode}; + use multiply_by_rational_with_rounding as mulrat; + use Rounding::*; + + const MAX: u128 = u128::max_value(); + + #[test] + fn rational_multiply_basic_rounding_works() { + assert_eq!(mulrat(1, 1, 1, Up), Some(1)); + assert_eq!(mulrat(3, 1, 3, Up), Some(1)); + assert_eq!(mulrat(1, 1, 3, Up), Some(1)); + assert_eq!(mulrat(1, 2, 3, Down), Some(0)); + assert_eq!(mulrat(1, 1, 3, NearestPrefDown), Some(0)); + assert_eq!(mulrat(1, 1, 2, NearestPrefDown), Some(0)); + assert_eq!(mulrat(1, 2, 3, NearestPrefDown), Some(1)); + assert_eq!(mulrat(1, 1, 3, NearestPrefUp), Some(0)); + assert_eq!(mulrat(1, 1, 2, NearestPrefUp), Some(1)); + assert_eq!(mulrat(1, 2, 3, NearestPrefUp), Some(1)); + } + + #[test] + fn rational_multiply_big_number_works() { + assert_eq!(mulrat(MAX, MAX - 1, MAX, Down), Some(MAX - 1)); + assert_eq!(mulrat(MAX, 1, MAX, Down), Some(1)); + assert_eq!(mulrat(MAX, MAX - 1, MAX, Up), Some(MAX - 1)); + assert_eq!(mulrat(MAX, 1, MAX, Up), Some(1)); + assert_eq!(mulrat(1, MAX - 1, MAX, Down), Some(0)); + assert_eq!(mulrat(1, 1, MAX, Up), Some(1)); + assert_eq!(mulrat(1, MAX / 2, MAX, NearestPrefDown), Some(0)); + assert_eq!(mulrat(1, MAX / 2 + 1, MAX, NearestPrefDown), Some(1)); + assert_eq!(mulrat(1, MAX / 2, MAX, NearestPrefUp), Some(0)); + assert_eq!(mulrat(1, MAX / 2 + 1, MAX, NearestPrefUp), Some(1)); + } + + #[test] + fn sqrt_works() { + for i in 0..100_000u32 { + let a = sqrt(random_u128(i)); + assert_eq!(sqrt(a * a), a); + } + } + + fn random_u128(seed: u32) -> u128 { + u128::decode(&mut &seed.using_encoded(sp_core::hashing::twox_128)[..]).unwrap_or(0) + } + + #[test] + fn op_checked_rounded_div_works() { + for i in 0..100_000u32 { + let a = random_u128(i); + let b = random_u128(i + 1 << 30); + let c = random_u128(i + 1 << 31); + let x = mulrat(a, b, c, NearestPrefDown); + let y = multiply_by_rational(a, b, c).ok(); + assert_eq!(x.is_some(), y.is_some()); + let x = x.unwrap_or(0); + let y = y.unwrap_or(0); + let d = x.max(y) - x.min(y); + assert_eq!(d, 0); + } + } +} diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index e43e42763575d..244242c0f7580 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -41,7 +41,10 @@ pub mod rational; pub mod traits; pub use fixed_point::{FixedI128, FixedI64, FixedPointNumber, FixedPointOperand, FixedU128}; -pub use per_things::{InnerOf, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, UpperOf}; +pub use per_things::{ + InnerOf, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, Rounding, SignedRounding, + UpperOf, +}; pub use rational::{Rational128, RationalInfinite}; use sp_std::{cmp::Ordering, fmt::Debug, prelude::*}; diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index 3851270b8d4db..7f39d35774190 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -26,7 +26,7 @@ use codec::{CompactAs, Encode}; use num_traits::{Pow, SaturatingAdd, SaturatingSub}; use sp_std::{ fmt, ops, - ops::{Add, Sub}, + ops::{Add, AddAssign, Div, Rem, Sub}, prelude::*, }; @@ -89,6 +89,40 @@ pub trait PerThing: self.deconstruct() == Self::ACCURACY } + /// Return the next lower value to `self` or `self` if it is already zero. + fn less_epsilon(self) -> Self { + if self.is_zero() { + return self + } + Self::from_parts(self.deconstruct() - One::one()) + } + + /// Return the next lower value to `self` or an error with the same value if `self` is already + /// zero. + fn try_less_epsilon(self) -> Result { + if self.is_zero() { + return Err(self) + } + Ok(Self::from_parts(self.deconstruct() - One::one())) + } + + /// Return the next higher value to `self` or `self` if it is already one. + fn plus_epsilon(self) -> Self { + if self.is_one() { + return self + } + Self::from_parts(self.deconstruct() + One::one()) + } + + /// Return the next higher value to `self` or an error with the same value if `self` is already + /// one. + fn try_plus_epsilon(self) -> Result { + if self.is_one() { + return Err(self) + } + Ok(Self::from_parts(self.deconstruct() + One::one())) + } + /// Build this type from a percent. Equivalent to `Self::from_parts(x * Self::ACCURACY / 100)` /// but more accurate and can cope with potential type overflows. fn from_percent(x: Self::Inner) -> Self { @@ -188,7 +222,7 @@ pub trait PerThing: + Unsigned, Self::Inner: Into, { - saturating_reciprocal_mul::(b, self.deconstruct(), Rounding::Nearest) + saturating_reciprocal_mul::(b, self.deconstruct(), Rounding::NearestPrefUp) } /// Saturating multiplication by the reciprocal of `self`. The result is rounded down to the @@ -275,9 +309,9 @@ pub trait PerThing: /// # fn main () { /// // 989/1000 is technically closer to 99%. /// assert_eq!( - /// Percent::from_rational(989u64, 1000), - /// Percent::from_parts(98), - /// ); + /// Percent::from_rational(989u64, 1000), + /// Percent::from_parts(98), + /// ); /// # } /// ``` fn from_rational(p: N, q: N) -> Self @@ -289,7 +323,82 @@ pub trait PerThing: + ops::Div + ops::Rem + ops::Add - + Unsigned, + + ops::AddAssign + + Unsigned + + Zero + + One, + Self::Inner: Into, + { + Self::from_rational_with_rounding(p, q, Rounding::Down).unwrap_or_else(|_| Self::one()) + } + + /// Approximate the fraction `p/q` into a per-thing fraction. + /// + /// The computation of this approximation is performed in the generic type `N`. Given + /// `M` as the data type that can hold the maximum value of this per-thing (e.g. `u32` for + /// `Perbill`), this can only work if `N == M` or `N: From + TryInto`. + /// + /// In the case of an overflow (or divide by zero), an `Err` is returned. + /// + /// Rounding is determined by the parameter `rounding`, i.e. + /// + /// ```rust + /// # use sp_arithmetic::{Percent, PerThing, Rounding::*}; + /// # fn main () { + /// // 989/100 is technically closer to 99%. + /// assert_eq!( + /// Percent::from_rational_with_rounding(989u64, 1000, Down).unwrap(), + /// Percent::from_parts(98), + /// ); + /// assert_eq!( + /// Percent::from_rational_with_rounding(984u64, 1000, NearestPrefUp).unwrap(), + /// Percent::from_parts(98), + /// ); + /// assert_eq!( + /// Percent::from_rational_with_rounding(985u64, 1000, NearestPrefDown).unwrap(), + /// Percent::from_parts(98), + /// ); + /// assert_eq!( + /// Percent::from_rational_with_rounding(985u64, 1000, NearestPrefUp).unwrap(), + /// Percent::from_parts(99), + /// ); + /// assert_eq!( + /// Percent::from_rational_with_rounding(986u64, 1000, NearestPrefDown).unwrap(), + /// Percent::from_parts(99), + /// ); + /// assert_eq!( + /// Percent::from_rational_with_rounding(981u64, 1000, Up).unwrap(), + /// Percent::from_parts(99), + /// ); + /// assert_eq!( + /// Percent::from_rational_with_rounding(1001u64, 1000, Up), + /// Err(()), + /// ); + /// # } + /// ``` + /// + /// ```rust + /// # use sp_arithmetic::{Percent, PerThing, Rounding::*}; + /// # fn main () { + /// assert_eq!( + /// Percent::from_rational_with_rounding(981u64, 1000, Up).unwrap(), + /// Percent::from_parts(99), + /// ); + /// # } + /// ``` + fn from_rational_with_rounding(p: N, q: N, rounding: Rounding) -> Result + where + N: Clone + + Ord + + TryInto + + TryInto + + ops::Div + + ops::Rem + + ops::Add + + ops::AddAssign + + Unsigned + + Zero + + One, Self::Inner: Into; /// Same as `Self::from_rational`. @@ -303,6 +412,7 @@ pub trait PerThing: + ops::Div + ops::Rem + ops::Add + + ops::AddAssign + Unsigned + Zero + One, @@ -312,14 +422,54 @@ pub trait PerThing: } } -/// The rounding method to use. -/// -/// `PerThing`s are unsigned so `Up` means towards infinity and `Down` means towards zero. -/// `Nearest` will round an exact half down. -enum Rounding { +/// The rounding method to use for unsigned quantities. +#[derive(Copy, Clone, sp_std::fmt::Debug)] +pub enum Rounding { + // Towards infinity. Up, + // Towards zero. Down, - Nearest, + // Nearest integer, rounding as `Up` when equidistant. + NearestPrefUp, + // Nearest integer, rounding as `Down` when equidistant. + NearestPrefDown, +} + +/// The rounding method to use. +#[derive(Copy, Clone, sp_std::fmt::Debug)] +pub enum SignedRounding { + // Towards positive infinity. + High, + // Towards negative infinity. + Low, + // Nearest integer, rounding as `High` when exactly equidistant. + NearestPrefHigh, + // Nearest integer, rounding as `Low` when exactly equidistant. + NearestPrefLow, + // Away from zero (up when positive, down when negative). When positive, equivalent to `High`. + Major, + // Towards zero (down when positive, up when negative). When positive, equivalent to `Low`. + Minor, + // Nearest integer, rounding as `Major` when exactly equidistant. + NearestPrefMajor, + // Nearest integer, rounding as `Minor` when exactly equidistant. + NearestPrefMinor, +} + +impl Rounding { + /// Returns the value for `Rounding` which would give the same result ignorant of the sign. + pub const fn from_signed(rounding: SignedRounding, negative: bool) -> Self { + use Rounding::*; + use SignedRounding::*; + match (rounding, negative) { + (Low, true) | (Major, _) | (High, false) => Up, + (High, true) | (Minor, _) | (Low, false) => Down, + (NearestPrefMajor, _) | (NearestPrefHigh, false) | (NearestPrefLow, true) => + NearestPrefUp, + (NearestPrefMinor, _) | (NearestPrefLow, false) | (NearestPrefHigh, true) => + NearestPrefDown, + } + } } /// Saturating reciprocal multiplication. Compute `x / self`, saturating at the numeric @@ -397,18 +547,53 @@ where rem_mul_div_inner += 1.into(); } }, - // Round up if the fractional part of the result is greater than a half. An exact half is - // rounded down. - Rounding::Nearest => { + Rounding::NearestPrefDown => if rem_mul_upper % denom_upper > denom_upper / 2.into() { // `rem * numer / denom` is less than `numer`, so this will not overflow. rem_mul_div_inner += 1.into(); - } - }, + }, + Rounding::NearestPrefUp => + if rem_mul_upper % denom_upper >= denom_upper / 2.into() + denom_upper % 2.into() { + // `rem * numer / denom` is less than `numer`, so this will not overflow. + rem_mul_div_inner += 1.into(); + }, } rem_mul_div_inner.into() } +/// Just a simple generic integer divide with custom rounding. +fn div_rounded(n: N, d: N, r: Rounding) -> N +where + N: Clone + + Eq + + Ord + + Zero + + One + + AddAssign + + Add + + Rem + + Div, +{ + let mut o = n.clone() / d.clone(); + use Rounding::*; + let two = || N::one() + N::one(); + if match r { + Up => !((n % d).is_zero()), + NearestPrefDown => { + let rem = n % d.clone(); + rem > d / two() + }, + NearestPrefUp => { + let rem = n % d.clone(); + rem >= d.clone() / two() + d % two() + }, + Down => false, + } { + o += N::one() + } + o +} + macro_rules! implement_per_thing { ( $name:ident, @@ -423,7 +608,7 @@ macro_rules! implement_per_thing { /// #[doc = $title] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] - #[derive(Encode, Copy, Clone, PartialEq, Eq, codec::MaxEncodedLen, PartialOrd, Ord, sp_std::fmt::Debug, scale_info::TypeInfo)] + #[derive(Encode, Copy, Clone, PartialEq, Eq, codec::MaxEncodedLen, PartialOrd, Ord, scale_info::TypeInfo)] pub struct $name($type); /// Implementation makes any compact encoding of `PerThing::Inner` valid, @@ -445,6 +630,55 @@ macro_rules! implement_per_thing { } } + #[cfg(feature = "std")] + impl sp_std::fmt::Debug for $name { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + if $max == <$type>::max_value() { + // Not a power of ten: show as N/D and approx % + let pc = (self.0 as f64) / (self.0 as f64) * 100f64; + write!(fmt, "{:.2}% ({}/{})", pc, self.0, $max) + } else { + // A power of ten: calculate exact percent + let units = self.0 / ($max / 100); + let rest = self.0 % ($max / 100); + write!(fmt, "{}", units)?; + if rest > 0 { + write!(fmt, ".")?; + let mut m = $max / 100; + while rest % m > 0 { + m /= 10; + write!(fmt, "{:01}", rest / m % 10)?; + } + } + write!(fmt, "%") + } + } + } + + #[cfg(not(feature = "std"))] + impl sp_std::fmt::Debug for $name { + fn fmt(&self, fmt: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + if $max == <$type>::max_value() { + // Not a power of ten: show as N/D and approx % + write!(fmt, "{}/{}", self.0, $max) + } else { + // A power of ten: calculate exact percent + let units = self.0 / ($max / 100); + let rest = self.0 % ($max / 100); + write!(fmt, "{}", units)?; + if rest > 0 { + write!(fmt, ".")?; + let mut m = $max / 100; + while rest % m > 0 { + m /= 10; + write!(fmt, "{:01}", rest / m % 10)?; + } + } + write!(fmt, "%") + } + } + } + impl PerThing for $name { type Inner = $type; type Upper = $upper_type; @@ -463,53 +697,50 @@ macro_rules! implement_per_thing { Self::from_parts((x.max(0.).min(1.) * $max as f64) as Self::Inner) } - fn from_rational(p: N, q: N) -> Self + fn from_rational_with_rounding(p: N, q: N, r: Rounding) -> Result where - N: Clone + Ord + TryInto + TryInto - + ops::Div + ops::Rem + ops::Add + Unsigned - + Zero + One, - Self::Inner: Into, + N: Clone + + Ord + + TryInto + + TryInto + + ops::Div + + ops::Rem + + ops::Add + + ops::AddAssign + + Unsigned + + Zero + + One, + Self::Inner: Into { - let div_ceil = |x: N, f: N| -> N { - let mut o = x.clone() / f.clone(); - let r = x.rem(f.clone()); - if r > N::zero() { - o = o + N::one(); - } - o - }; - // q cannot be zero. - let q: N = q.max((1 as Self::Inner).into()); + if q.is_zero() { return Err(()) } // p should not be bigger than q. - let p: N = p.min(q.clone()); + if p > q { return Err(()) } - let factor: N = div_ceil(q.clone(), $max.into()).max((1 as Self::Inner).into()); + let factor = div_rounded::(q.clone(), $max.into(), Rounding::Up).max(One::one()); // q cannot overflow: (q / (q/$max)) < $max. p < q hence p also cannot overflow. - let q_reduce: $type = (q.clone() / factor.clone()) + let q_reduce: $type = div_rounded(q, factor.clone(), r) .try_into() .map_err(|_| "Failed to convert") .expect( - "q / ceil(q/$max) < $max. Macro prevents any type being created that \ + "`q / ceil(q/$max) < $max`; macro prevents any type being created that \ does not satisfy this; qed" ); - let p_reduce: $type = (p / factor) + let p_reduce: $type = div_rounded(p, factor, r) .try_into() .map_err(|_| "Failed to convert") .expect( - "q / ceil(q/$max) < $max. Macro prevents any type being created that \ + "`p / ceil(p/$max) < $max`; macro prevents any type being created that \ does not satisfy this; qed" ); - // `p_reduced` and `q_reduced` are withing Self::Inner. Mul by another $max will - // always fit in $upper_type. This is guaranteed by the macro tests. - let part = - p_reduce as $upper_type - * <$upper_type>::from($max) - / q_reduce as $upper_type; - - $name(part as Self::Inner) + // `p_reduced` and `q_reduced` are within `Self::Inner`. Multiplication by another + // `$max` will always fit in `$upper_type`. This is guaranteed by the macro tests. + let n = p_reduce as $upper_type * <$upper_type>::from($max); + let d = q_reduce as $upper_type; + let part = div_rounded(n, d, r); + Ok($name(part as Self::Inner)) } } @@ -570,24 +801,52 @@ macro_rules! implement_per_thing { /// See [`PerThing::from_rational`]. #[deprecated = "Use `PerThing::from_rational` instead"] pub fn from_rational_approximation(p: N, q: N) -> Self - where N: Clone + Ord + TryInto<$type> + - TryInto<$upper_type> + ops::Div + ops::Rem + - ops::Add + Unsigned, - $type: Into, + where + N: Clone + + Ord + + TryInto<$type> + + TryInto<$upper_type> + + ops::Div + + ops::Rem + + ops::Add + + ops::AddAssign + + Unsigned + + Zero + + One, + $type: Into { ::from_rational(p, q) } /// See [`PerThing::from_rational`]. pub fn from_rational(p: N, q: N) -> Self - where N: Clone + Ord + TryInto<$type> + - TryInto<$upper_type> + ops::Div + ops::Rem + - ops::Add + Unsigned, - $type: Into, + where + N: Clone + + Ord + + TryInto<$type> + + TryInto<$upper_type> + + ops::Div + + ops::Rem + + ops::Add + + ops::AddAssign + + Unsigned + + Zero + + One, + $type: Into { ::from_rational(p, q) } + /// Integer multiplication with another value, saturating at 1. + pub fn int_mul(self, b: $type) -> Self { + PerThing::from_parts(self.0.saturating_mul(b)) + } + + /// Integer division with another value, rounding down. + pub fn int_div(self, b: Self) -> $type { + self.0 / b.0 + } + /// See [`PerThing::mul_floor`]. pub fn mul_floor(self, b: N) -> N where @@ -643,6 +902,38 @@ macro_rules! implement_per_thing { { PerThing::saturating_reciprocal_mul_ceil(self, b) } + + /// Saturating division. Compute `self / rhs`, saturating at one if `rhs < self`. + /// + /// The `rounding` method must be specified. e.g.: + /// + /// ```rust + /// # use sp_arithmetic::{Percent, PerThing, Rounding::*}; + /// # fn main () { + /// let pc = |x| Percent::from_percent(x); + /// assert_eq!( + /// pc(2).saturating_div(pc(3), Down), + /// pc(66), + /// ); + /// assert_eq!( + /// pc(1).saturating_div(pc(3), NearestPrefUp), + /// pc(33), + /// ); + /// assert_eq!( + /// pc(2).saturating_div(pc(3), NearestPrefDown), + /// pc(67), + /// ); + /// assert_eq!( + /// pc(1).saturating_div(pc(3), Up), + /// pc(34), + /// ); + /// # } + /// ``` + pub fn saturating_div(self, rhs: Self, r: Rounding) -> Self { + let p = self.0; + let q = rhs.0; + Self::from_rational_with_rounding(p, q, r).unwrap_or_else(|_| Self::one()) + } } impl Saturating for $name { @@ -756,7 +1047,7 @@ macro_rules! implement_per_thing { { type Output = N; fn mul(self, b: N) -> Self::Output { - overflow_prune_mul::(b, self.deconstruct(), Rounding::Nearest) + overflow_prune_mul::(b, self.deconstruct(), Rounding::NearestPrefDown) } } @@ -903,6 +1194,11 @@ macro_rules! implement_per_thing { } } + #[test] + fn from_parts_cannot_overflow() { + assert_eq!(<$name>::from_parts($max.saturating_add(1)), <$name>::one()); + } + #[test] fn has_max_encoded_len() { struct AsMaxEncodedLen { @@ -1040,10 +1336,10 @@ macro_rules! implement_per_thing { #[test] fn per_thing_mul_rounds_to_nearest_number() { - assert_eq!($name::from_float(0.33) * 10u64, 3); - assert_eq!($name::from_float(0.34) * 10u64, 3); - assert_eq!($name::from_float(0.35) * 10u64, 3); - assert_eq!($name::from_float(0.36) * 10u64, 4); + assert_eq!($name::from_percent(33) * 10u64, 3); + assert_eq!($name::from_percent(34) * 10u64, 3); + assert_eq!($name::from_percent(35) * 10u64, 3); + assert_eq!($name::from_percent(36) * 10u64, 4); } #[test] @@ -1351,7 +1647,7 @@ macro_rules! implement_per_thing { <$type>::max_value(), <$type>::max_value(), <$type>::max_value(), - super::Rounding::Nearest, + super::Rounding::NearestPrefDown, ), 0, ); @@ -1360,7 +1656,7 @@ macro_rules! implement_per_thing { <$type>::max_value() - 1, <$type>::max_value(), <$type>::max_value(), - super::Rounding::Nearest, + super::Rounding::NearestPrefDown, ), <$type>::max_value() - 1, ); @@ -1369,7 +1665,7 @@ macro_rules! implement_per_thing { ((<$type>::max_value() - 1) as $upper_type).pow(2), <$type>::max_value(), <$type>::max_value(), - super::Rounding::Nearest, + super::Rounding::NearestPrefDown, ), 1, ); @@ -1379,7 +1675,7 @@ macro_rules! implement_per_thing { (<$type>::max_value() as $upper_type).pow(2) - 1, <$type>::max_value(), <$type>::max_value(), - super::Rounding::Nearest, + super::Rounding::NearestPrefDown, ), <$upper_type>::from((<$type>::max_value() - 1)), ); @@ -1389,7 +1685,7 @@ macro_rules! implement_per_thing { (<$type>::max_value() as $upper_type).pow(2), <$type>::max_value(), 2 as $type, - super::Rounding::Nearest, + super::Rounding::NearestPrefDown, ), <$type>::max_value() as $upper_type / 2, ); @@ -1399,7 +1695,7 @@ macro_rules! implement_per_thing { (<$type>::max_value() as $upper_type).pow(2) - 1, 2 as $type, <$type>::max_value(), - super::Rounding::Nearest, + super::Rounding::NearestPrefDown, ), 2, ); @@ -1586,6 +1882,33 @@ macro_rules! implement_per_thing_with_perthousand { } } +#[test] +fn from_rational_with_rounding_works_in_extreme_case() { + use Rounding::*; + for &r in [Down, NearestPrefDown, NearestPrefUp, Up].iter() { + Percent::from_rational_with_rounding(1, u64::max_value(), r).unwrap(); + Percent::from_rational_with_rounding(1, u32::max_value(), r).unwrap(); + Percent::from_rational_with_rounding(1, u16::max_value(), r).unwrap(); + Percent::from_rational_with_rounding(u64::max_value() - 1, u64::max_value(), r).unwrap(); + Percent::from_rational_with_rounding(u32::max_value() - 1, u32::max_value(), r).unwrap(); + Percent::from_rational_with_rounding(u16::max_value() - 1, u16::max_value(), r).unwrap(); + PerU16::from_rational_with_rounding(1, u64::max_value(), r).unwrap(); + PerU16::from_rational_with_rounding(1, u32::max_value(), r).unwrap(); + PerU16::from_rational_with_rounding(1, u16::max_value(), r).unwrap(); + PerU16::from_rational_with_rounding(u64::max_value() - 1, u64::max_value(), r).unwrap(); + PerU16::from_rational_with_rounding(u32::max_value() - 1, u32::max_value(), r).unwrap(); + PerU16::from_rational_with_rounding(u16::max_value() - 1, u16::max_value(), r).unwrap(); + Permill::from_rational_with_rounding(1, u64::max_value(), r).unwrap(); + Permill::from_rational_with_rounding(1, u32::max_value(), r).unwrap(); + Permill::from_rational_with_rounding(u64::max_value() - 1, u64::max_value(), r).unwrap(); + Permill::from_rational_with_rounding(u32::max_value() - 1, u32::max_value(), r).unwrap(); + Perbill::from_rational_with_rounding(1, u64::max_value(), r).unwrap(); + Perbill::from_rational_with_rounding(1, u32::max_value(), r).unwrap(); + Perbill::from_rational_with_rounding(u64::max_value() - 1, u64::max_value(), r).unwrap(); + Perbill::from_rational_with_rounding(u32::max_value() - 1, u32::max_value(), r).unwrap(); + } +} + implement_per_thing!(Percent, test_per_cent, [u32, u64, u128], 100u8, u8, u16, "_Percent_",); implement_per_thing_with_perthousand!( PerU16, diff --git a/primitives/arithmetic/src/traits.rs b/primitives/arithmetic/src/traits.rs index 748aaed2a7cf5..466d5696c7136 100644 --- a/primitives/arithmetic/src/traits.rs +++ b/primitives/arithmetic/src/traits.rs @@ -58,6 +58,7 @@ pub trait BaseArithmetic: + Bounded + HasCompact + Sized + + Clone + TryFrom + TryInto + TryFrom @@ -113,6 +114,7 @@ impl< + Bounded + HasCompact + Sized + + Clone + TryFrom + TryInto + TryFrom From e5b6ca6fa22abdf6a07bead25cf5f52dd78391f1 Mon Sep 17 00:00:00 2001 From: mikolaichuk <45576473+mikolaichuk@users.noreply.github.com> Date: Tue, 31 May 2022 19:34:41 +0600 Subject: [PATCH 0858/1472] change impl FnOnce() to generic type + trait bound (#11534) * change impl FnOnce() to generic type + trait bound with_transaction() function can not be used with explicit generic arguments because of this issue: https://github.com/rust-lang/rust/issues/83701 * make the same changes elsewhere Co-authored-by: Shawn Tabrizi --- frame/support/src/storage/transactional.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/frame/support/src/storage/transactional.rs b/frame/support/src/storage/transactional.rs index b02552bdb0e14..d1bdb30af947b 100644 --- a/frame/support/src/storage/transactional.rs +++ b/frame/support/src/storage/transactional.rs @@ -101,9 +101,10 @@ pub fn is_transactional() -> bool { /// error. /// /// Commits happen to the parent transaction. -pub fn with_transaction(f: impl FnOnce() -> TransactionOutcome>) -> Result +pub fn with_transaction(f: F) -> Result where E: From, + F: FnOnce() -> TransactionOutcome>, { // This needs to happen before `start_transaction` below. // Otherwise we may rollback the increase, then decrease as the guard goes out of scope @@ -129,7 +130,10 @@ where /// This is mostly for backwards compatibility before there was a transactional layer limit. /// It is recommended to only use [`with_transaction`] to avoid users from generating too many /// transactional layers. -pub fn with_transaction_unchecked(f: impl FnOnce() -> TransactionOutcome) -> R { +pub fn with_transaction_unchecked(f: F) -> R +where + F: FnOnce() -> TransactionOutcome, +{ // This needs to happen before `start_transaction` below. // Otherwise we may rollback the increase, then decrease as the guard goes out of scope // and then end in some bad state. @@ -163,9 +167,10 @@ pub fn with_transaction_unchecked(f: impl FnOnce() -> TransactionOutcome) /// This is the same as `with_transaction`, but assuming that any function returning /// an `Err` should rollback, and any function returning `Ok` should commit. This /// provides a cleaner API to the developer who wants this behavior. -pub fn with_storage_layer(f: impl FnOnce() -> Result) -> Result +pub fn with_storage_layer(f: F) -> Result where E: From, + F: FnOnce() -> Result, { with_transaction(|| { let r = f(); @@ -181,9 +186,10 @@ where /// /// If we are already in a storage layer, we just execute the provided closure. /// If we are not, we execute the closure within a [`with_storage_layer`]. -pub fn in_storage_layer(f: impl FnOnce() -> Result) -> Result +pub fn in_storage_layer(f: F) -> Result where E: From, + F: FnOnce() -> Result, { if is_transactional() { f() From fb6bbb9d4983f9c2fa27eab5c4674cb74bb733ff Mon Sep 17 00:00:00 2001 From: Vlad Date: Tue, 31 May 2022 18:10:04 +0300 Subject: [PATCH 0859/1472] Introduce `rusty-cachier` (#11462) * Introduce `rusty-cachier` * Return LF at the end of file * Use `entrypoint` to `unshare(1)` into a new mount namespace * Use `rusty-cachier`-provided absolute path for `CARGO_TARGET_DIR` everywhere * Debug single `build-rustdoc` job * CI: debug * CI: debug * CI: debug * `unshare(1)` is no longer needed * CI: remove debug * Revert "Debug single `build-rustdoc` job" * Formatiing * Update scripts/ci/gitlab/pipeline/build.yml Co-authored-by: Denis Pisarev --- .gitlab-ci.yml | 14 ++++++++ scripts/ci/gitlab/pipeline/build.yml | 32 +++++++++++++++--- scripts/ci/gitlab/pipeline/test.yml | 49 +++++++++++++++++++++++++++- 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 87e7fa6fc61b0..fa3b51caefa14 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,6 +47,8 @@ variables: &default-vars DOCKER_OS: "debian:stretch" ARCH: "x86_64" CI_IMAGE: "paritytech/ci-linux:production" + RUSTY_CACHIER_SINGLE_BRANCH: master + RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" default: retry: @@ -86,10 +88,22 @@ default: - rustup +nightly show - cargo +nightly --version +.rusty-cachier: + before_script: + - curl -s https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.parity.io/parity/infrastructure/ci_cd/rusty-cachier/client/-/raw/release/util/install.sh | bash + - rusty-cachier environment check --gracefully + - $(rusty-cachier environment inject) + - rusty-cachier project mtime + after_script: + - rusty-cachier snapshot destroy + .docker-env: image: "${CI_IMAGE}" before_script: - !reference [.rust-info-script, script] + - !reference [.rusty-cachier, before_script] + after_script: + - !reference [.rusty-cachier, after_script] tags: - linux-docker diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index e896eac7238b1..a07fe8a4cfa07 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -55,9 +55,11 @@ build-linux-substrate: artifacts: false before_script: - mkdir -p ./artifacts/substrate/ + - !reference [.rusty-cachier, before_script] script: + - rusty-cachier snapshot create - WASM_BUILD_NO_COLOR=1 time cargo build --release --verbose - - mv ./target/release/substrate ./artifacts/substrate/. + - mv /cargo_target_dir/release/substrate ./artifacts/substrate/. - echo -n "Substrate version = " - if [ "${CI_COMMIT_TAG}" ]; then echo "${CI_COMMIT_TAG}" | tee ./artifacts/substrate/VERSION; @@ -69,6 +71,7 @@ build-linux-substrate: - cp -r ./scripts/ci/docker/substrate.Dockerfile ./artifacts/substrate/ - printf '\n# building node-template\n\n' - ./scripts/ci/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz + - rusty-cachier cache upload .build-subkey: stage: build @@ -81,23 +84,41 @@ build-linux-substrate: artifacts: false before_script: - mkdir -p ./artifacts/subkey + - !reference [.rusty-cachier, before_script] script: + - rusty-cachier snapshot create - cd ./bin/utils/subkey - SKIP_WASM_BUILD=1 time cargo build --release --verbose - cd - - - mv ./target/release/subkey ./artifacts/subkey/. + - mv /cargo_target_dir/release/subkey ./artifacts/subkey/. - echo -n "Subkey version = " - ./artifacts/subkey/subkey --version | sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | tee ./artifacts/subkey/VERSION; - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ + - rusty-cachier cache upload build-subkey-linux: extends: .build-subkey build-subkey-macos: extends: .build-subkey + # duplicating before_script & script sections from .build-subkey hidden job + # to overwrite rusty-cachier integration as it doesn't work on macos + before_script: + - mkdir -p ./artifacts/subkey + script: + - cd ./bin/utils/subkey + - SKIP_WASM_BUILD=1 time cargo build --release --verbose + - cd - + - mv ./target/release/subkey ./artifacts/subkey/. + - echo -n "Subkey version = " + - ./artifacts/subkey/subkey --version | + sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | + tee ./artifacts/subkey/VERSION; + - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 + - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ tags: - osx @@ -109,6 +130,7 @@ build-rustdoc: variables: SKIP_WASM_BUILD: 1 DOC_INDEX_PAGE: "sc_service/index.html" # default redirected page + RUSTY_CACHIER_TOOLCHAIN: nightly artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" when: on_success @@ -116,9 +138,11 @@ build-rustdoc: paths: - ./crate-docs/ script: + - rusty-cachier snapshot create - time cargo +nightly doc --workspace --all-features --verbose - - rm -f ./target/doc/.lock - - mv ./target/doc ./crate-docs + - rm -f /cargo_target_dir/doc/.lock + - mv /cargo_target_dir/doc ./crate-docs # FIXME: remove me after CI image gets nonroot - chown -R nonroot:nonroot ./crate-docs - echo "" > ./crate-docs/index.html + - rusty-cachier cache upload diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 769d1cd30d0d5..eab673a5ce13c 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -7,8 +7,11 @@ cargo-deny: - .docker-env - .nightly-pipeline script: + - rusty-cachier snapshot create - cargo deny check --hide-inclusion-graph -c ./scripts/ci/deny.toml + - rusty-cachier cache upload after_script: + - !reference [.rusty-cachier, after_script] - echo "___The complete log is in the artifacts___" - cargo deny check -c ./scripts/ci/deny.toml 2> deny.log artifacts: @@ -22,11 +25,15 @@ cargo-deny: cargo-fmt: stage: test + variables: + RUSTY_CACHIER_TOOLCHAIN: nightly extends: - .docker-env - .test-refs script: + - rusty-cachier snapshot create - cargo +nightly fmt --all -- --check + - rusty-cachier cache upload cargo-clippy: stage: test @@ -34,11 +41,15 @@ cargo-clippy: needs: - job: cargo-fmt artifacts: false + variables: + RUSTY_CACHIER_TOOLCHAIN: nightly extends: - .docker-env - .test-refs script: + - rusty-cachier snapshot create - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo +nightly clippy --all-targets + - rusty-cachier cache upload cargo-check-nixos: stage: test @@ -62,6 +73,8 @@ cargo-check-nixos: cargo-check-benches: stage: test + variables: + RUSTY_CACHIER_TOOLCHAIN: nightly extends: - .docker-env - .test-refs @@ -76,7 +89,9 @@ cargo-check-benches: git merge $CI_COMMIT_REF_NAME --verbose --no-edit; fi - !reference [.rust-info-script, script] + - !reference [.rusty-cachier, before_script] script: + - rusty-cachier snapshot create - mkdir -p ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA - SKIP_WASM_BUILD=1 time cargo +nightly check --benches --all - 'cargo run --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json @@ -84,6 +99,7 @@ cargo-check-benches: - 'cargo run --release -p node-bench -- ::trie::read::small --json | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json' - sccache -s + - rusty-cachier cache upload tags: - linux-docker-benches @@ -120,8 +136,10 @@ cargo-check-subkey: - .docker-env - .test-refs script: + - rusty-cachier snapshot create - cd ./bin/utils/subkey - SKIP_WASM_BUILD=1 time cargo check --release + - rusty-cachier cache upload cargo-check-try-runtime: stage: test @@ -133,7 +151,9 @@ cargo-check-try-runtime: - .docker-env - .test-refs script: + - rusty-cachier snapshot create - time cargo check --features try-runtime + - rusty-cachier cache upload cargo-check-wasmer-sandbox: stage: test @@ -145,7 +165,9 @@ cargo-check-wasmer-sandbox: - .docker-env - .test-refs script: + - rusty-cachier snapshot create - time cargo check --features wasmer-sandbox + - rusty-cachier cache upload test-deterministic-wasm: stage: test @@ -159,16 +181,18 @@ test-deterministic-wasm: variables: WASM_BUILD_NO_COLOR: 1 script: + - rusty-cachier snapshot create # build runtime - cargo build --verbose --release -p node-runtime # make checksum - - sha256sum ./target/release/wbuild/node-runtime/target/wasm32-unknown-unknown/release/node_runtime.wasm > checksum.sha256 + - sha256sum /cargo_target_dir/release/wbuild/node-runtime/target/wasm32-unknown-unknown/release/node_runtime.wasm > checksum.sha256 # clean up – FIXME: can we reuse some of the artifacts? - cargo clean # build again - cargo build --verbose --release -p node-runtime # confirm checksum - sha256sum -c ./checksum.sha256 + - rusty-cachier cache upload test-linux-stable: stage: test @@ -184,14 +208,18 @@ test-linux-stable: # Ensure we run the UI tests. RUN_UI_TESTS: 1 script: + - rusty-cachier snapshot create # this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests - time cargo test --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml - time cargo test -p frame-support-test --features=conditional-storage,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout + - rusty-cachier cache upload test-frame-examples-compile-to-wasm: # into one job stage: test + variables: + RUSTY_CACHIER_TOOLCHAIN: nightly extends: - .docker-env - .test-refs @@ -201,10 +229,12 @@ test-frame-examples-compile-to-wasm: RUSTFLAGS: "-Cdebug-assertions=y" RUST_BACKTRACE: 1 script: + - rusty-cachier snapshot create - cd ./frame/examples/offchain-worker/ - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features - cd ../basic - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features + - rusty-cachier cache upload test-linux-stable-int: stage: test @@ -220,13 +250,16 @@ test-linux-stable-int: # Ensure we run the UI tests. RUN_UI_TESTS: 1 script: + - rusty-cachier snapshot create - echo "___Logs will be partly shown at the end in case of failure.___" - echo "___Full log will be saved to the job artifacts only in case of failure.___" - WASM_BUILD_NO_COLOR=1 RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace time cargo test -p node-cli --release --verbose --locked -- --ignored &> ${CI_COMMIT_SHORT_SHA}_int_failure.log + - rusty-cachier cache upload after_script: + - !reference [.rusty-cachier, after_script] - awk '/FAILED|^error\[/,0' ${CI_COMMIT_SHORT_SHA}_int_failure.log artifacts: name: $CI_COMMIT_SHORT_SHA @@ -241,13 +274,17 @@ check-tracing: needs: - job: test-linux-stable-int artifacts: false + variables: + RUSTY_CACHIER_TOOLCHAIN: nightly extends: - .docker-env - .test-refs script: + - rusty-cachier snapshot create # with-tracing must be explicitly activated, we run a test to ensure this works as expected in both cases - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing + - rusty-cachier cache upload test-full-crypto-feature: stage: test @@ -255,6 +292,8 @@ test-full-crypto-feature: needs: - job: check-tracing artifacts: false + variables: + RUSTY_CACHIER_TOOLCHAIN: nightly extends: - .docker-env - .test-refs @@ -264,10 +303,12 @@ test-full-crypto-feature: RUSTFLAGS: "-Cdebug-assertions=y" RUST_BACKTRACE: 1 script: + - rusty-cachier snapshot create - cd primitives/core/ - time cargo +nightly build --verbose --no-default-features --features full_crypto - cd ../application-crypto - time cargo +nightly build --verbose --no-default-features --features full_crypto + - rusty-cachier cache upload test-wasmer-sandbox: stage: test @@ -275,7 +316,9 @@ test-wasmer-sandbox: - .docker-env - .test-refs-wasmer-sandbox script: + - rusty-cachier snapshot create - time cargo test --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests + - rusty-cachier cache upload cargo-check-macos: stage: test @@ -289,6 +332,8 @@ cargo-check-macos: check-rustdoc: stage: test + variables: + RUSTY_CACHIER_TOOLCHAIN: nightly extends: - .docker-env - .test-refs @@ -296,4 +341,6 @@ check-rustdoc: SKIP_WASM_BUILD: 1 RUSTDOCFLAGS: "-Dwarnings" script: + - rusty-cachier snapshot create - time cargo +nightly doc --workspace --all-features --verbose --no-deps + - rusty-cachier cache upload From 2b5f2a565383ebac210f361fbb0048a481cb58fe Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 31 May 2022 18:45:07 +0200 Subject: [PATCH 0860/1472] Clean up `#[transactional]` (#11546) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Deprecate #[transactional] attribute Signed-off-by: Oliver Tale-Yazdi * Remove #[transactional] from nomination pools Signed-off-by: Oliver Tale-Yazdi * Review fix Co-authored-by: Bastian Köcher * Fix NOOP test Signed-off-by: Oliver Tale-Yazdi * Suppress warnings Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher --- frame/nomination-pools/src/lib.rs | 9 +-------- frame/nomination-pools/src/tests.rs | 12 ++++++++---- frame/support/procedural/src/lib.rs | 1 + frame/support/src/dispatch.rs | 1 + frame/support/test/tests/storage_transaction.rs | 3 +++ 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index ff77949cf6952..c9d811fa4a22f 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1082,7 +1082,7 @@ impl Get for TotalUnbondingPools { #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{traits::StorageVersion, transactional}; + use frame_support::traits::StorageVersion; use frame_system::{ensure_signed, pallet_prelude::*}; /// The current storage version. @@ -1349,7 +1349,6 @@ pub mod pallet { /// `existential deposit + amount` in their account. /// * Only a pool with [`PoolState::Open`] can be joined #[pallet::weight(T::WeightInfo::join())] - #[transactional] pub fn join( origin: OriginFor, #[pallet::compact] amount: BalanceOf, @@ -1410,7 +1409,6 @@ pub mod pallet { T::WeightInfo::bond_extra_transfer() .max(T::WeightInfo::bond_extra_reward()) )] - #[transactional] pub fn bond_extra(origin: OriginFor, extra: BondExtra>) -> DispatchResult { let who = ensure_signed(origin)?; let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&who)?; @@ -1449,7 +1447,6 @@ pub mod pallet { /// The member will earn rewards pro rata based on the members stake vs the sum of the /// members in the pools stake. Rewards do not "expire". #[pallet::weight(T::WeightInfo::claim_payout())] - #[transactional] pub fn claim_payout(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&who)?; @@ -1489,7 +1486,6 @@ pub mod pallet { /// there are too many unlocking chunks, the result of this call will likely be the /// `NoMoreChunks` error from the staking system. #[pallet::weight(T::WeightInfo::unbond())] - #[transactional] pub fn unbond( origin: OriginFor, member_account: T::AccountId, @@ -1564,7 +1560,6 @@ pub mod pallet { /// would probably see an error like `NoMoreChunks` emitted from the staking system when /// they attempt to unbond. #[pallet::weight(T::WeightInfo::pool_withdraw_unbonded(*num_slashing_spans))] - #[transactional] pub fn pool_withdraw_unbonded( origin: OriginFor, pool_id: PoolId, @@ -1601,7 +1596,6 @@ pub mod pallet { #[pallet::weight( T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans) )] - #[transactional] pub fn withdraw_unbonded( origin: OriginFor, member_account: T::AccountId, @@ -1717,7 +1711,6 @@ pub mod pallet { /// In addition to `amount`, the caller will transfer the existential deposit; so the caller /// needs at have at least `amount + existential_deposit` transferrable. #[pallet::weight(T::WeightInfo::create())] - #[transactional] pub fn create( origin: OriginFor, #[pallet::compact] amount: BalanceOf, diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index c16c1c9da9e90..93218c78c83fc 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -21,6 +21,7 @@ use frame_support::{ assert_noop, assert_ok, assert_storage_noop, bounded_btree_map, storage::{with_transaction, TransactionOutcome}, }; +use sp_runtime::traits::Dispatchable; macro_rules! unbonding_pools_with_era { ($($k:expr => $v:expr),* $(,)?) => {{ @@ -3256,10 +3257,13 @@ mod create { Balances::make_free_balance_be(&11, 5 + 20); // Then - assert_noop!( - Pools::create(Origin::signed(11), 20, 11, 11, 11), - Error::::MaxPoolMembers - ); + let create = Call::Pools(crate::Call::::create { + amount: 20, + root: 11, + nominator: 11, + state_toggler: 11, + }); + assert_noop!(create.dispatch(Origin::signed(11)), Error::::MaxPoolMembers); }); } } diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 00204b7a4d906..418fad56b7674 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -429,6 +429,7 @@ pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream { /// } /// ``` #[proc_macro_attribute] +#[deprecated(note = "This is now the default behaviour for all extrinsics.")] pub fn transactional(attr: TokenStream, input: TokenStream) -> TokenStream { transactional::transactional(attr, input).unwrap_or_else(|e| e.to_compile_error().into()) } diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 51504c9c36e38..0a5092b411930 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -200,6 +200,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// /// Transactional function discards all changes to storage if it returns `Err`, or commits if /// `Ok`, via the #\[transactional\] attribute. Note the attribute must be after #\[weight\]. +/// The #\[transactional\] attribute is deprecated since it is the default behaviour. /// /// ``` /// # #[macro_use] diff --git a/frame/support/test/tests/storage_transaction.rs b/frame/support/test/tests/storage_transaction.rs index 848a91a7f5a86..9e597969d6c89 100644 --- a/frame/support/test/tests/storage_transaction.rs +++ b/frame/support/test/tests/storage_transaction.rs @@ -15,6 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Disable warnings for #\[transactional\] being deprecated. +#![allow(deprecated)] + use frame_support::{ assert_noop, assert_ok, assert_storage_noop, dispatch::{DispatchError, DispatchResult}, From 48d16264369e93b5de498a854164739f8ccd7662 Mon Sep 17 00:00:00 2001 From: Vlad Date: Tue, 31 May 2022 19:46:38 +0300 Subject: [PATCH 0861/1472] Add `rusty-cachier notify` job (#11554) * Add `rusty-cachier notify` job * Add comments --- .gitlab-ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fa3b51caefa14..935c5c1d40e86 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,6 +34,7 @@ stages: - build - publish - deploy + - notify workflow: rules: @@ -88,6 +89,8 @@ default: - rustup +nightly show - cargo +nightly --version +# rusty-cachier's hidden job. Parts of this job are used to instrument the pipeline's other real jobs with rusty-cachier +# Description of the commands is available here - https://gitlab.parity.io/parity/infrastructure/ci_cd/rusty-cachier/client#description .rusty-cachier: before_script: - curl -s https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.parity.io/parity/infrastructure/ci_cd/rusty-cachier/client/-/raw/release/util/install.sh | bash @@ -216,6 +219,16 @@ deploy-prometheus-alerting-rules: - .gitlab-ci.yml - ./scripts/ci/monitoring/**/* +#### stage: notify + +# This job notifies rusty-cachier about the latest commit with the cache. +# This info is later used for the cache distribution and an overlay creation. +rusty-cachier-notify: + stage: notify + <<: *docker-env + script: + - rusty-cachier cache notify + #### stage: .post # This job cancels the whole pipeline if any of provided jobs fail. From 108be5c3f2e390a2929f3ed945f1188de77b28dc Mon Sep 17 00:00:00 2001 From: Vlad Date: Tue, 31 May 2022 20:07:49 +0300 Subject: [PATCH 0862/1472] Fix CI after `rusty-cachier` introduction (#11556) * Fix CI after `rusty-cachier` introduction * Replace anchor with `extends` --- .gitlab-ci.yml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 935c5c1d40e86..e218a2c1f8d3a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -89,6 +89,16 @@ default: - rustup +nightly show - cargo +nightly --version +.docker-env: + image: "${CI_IMAGE}" + before_script: + - !reference [.rust-info-script, script] + - !reference [.rusty-cachier, before_script] + after_script: + - !reference [.rusty-cachier, after_script] + tags: + - linux-docker + # rusty-cachier's hidden job. Parts of this job are used to instrument the pipeline's other real jobs with rusty-cachier # Description of the commands is available here - https://gitlab.parity.io/parity/infrastructure/ci_cd/rusty-cachier/client#description .rusty-cachier: @@ -100,16 +110,6 @@ default: after_script: - rusty-cachier snapshot destroy -.docker-env: - image: "${CI_IMAGE}" - before_script: - - !reference [.rust-info-script, script] - - !reference [.rusty-cachier, before_script] - after_script: - - !reference [.rusty-cachier, after_script] - tags: - - linux-docker - .test-refs: rules: - if: $CI_PIPELINE_SOURCE == "web" @@ -225,7 +225,8 @@ deploy-prometheus-alerting-rules: # This info is later used for the cache distribution and an overlay creation. rusty-cachier-notify: stage: notify - <<: *docker-env + extends: + - .docker-env script: - rusty-cachier cache notify From 48de0a4a6393458f8330c4538fcd182b11a87a07 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Tue, 31 May 2022 19:12:07 +0100 Subject: [PATCH 0863/1472] Introduce `EnsureOrigin::try_successul_origin` (#11558) * Introduce `EnsureOrigin::try_successul_origin` * Formatting * Fixes * Add Morph * Fixes * Formatting --- frame/collective/src/lib.rs | 16 +- frame/society/src/lib.rs | 6 +- frame/support/src/traits/dispatch.rs | 224 +++++++++++++++++++-------- frame/system/src/lib.rs | 32 ++-- frame/treasury/src/tests.rs | 4 +- primitives/runtime/src/traits.rs | 36 +++++ 6 files changed, 221 insertions(+), 97 deletions(-) diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 9fce1762c6ea7..13d03562cce49 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -996,11 +996,11 @@ impl< } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { + fn try_successful_origin() -> Result { let zero_account_id = AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) .expect("infinite length input; no invalid inputs for type; qed"); - O::from(RawOrigin::Member(zero_account_id)) + Ok(O::from(RawOrigin::Member(zero_account_id))) } } @@ -1021,8 +1021,8 @@ impl< } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { - O::from(RawOrigin::Members(N, N)) + fn try_successful_origin() -> Result { + Ok(O::from(RawOrigin::Members(N, N))) } } @@ -1046,8 +1046,8 @@ impl< } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { - O::from(RawOrigin::Members(1u32, 0u32)) + fn try_successful_origin() -> Result { + Ok(O::from(RawOrigin::Members(1u32, 0u32))) } } @@ -1071,7 +1071,7 @@ impl< } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { - O::from(RawOrigin::Members(0u32, 0u32)) + fn try_successful_origin() -> Result { + Ok(O::from(RawOrigin::Members(0u32, 0u32))) } } diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 5a993f72f32d2..2a6428e754b9d 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -1272,9 +1272,9 @@ impl EnsureOrigin for EnsureFounder { } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::Origin { - let founder = Founder::::get().expect("society founder should exist"); - T::Origin::from(frame_system::RawOrigin::Signed(founder)) + fn try_successful_origin() -> Result { + let founder = Founder::::get().ok_or(())?; + Ok(T::Origin::from(frame_system::RawOrigin::Signed(founder))) } } diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index b1bd52ca960da..e06373348e499 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -18,10 +18,14 @@ //! Traits for dealing with dispatching calls and the origin from which they are dispatched. use crate::dispatch::{DispatchResultWithPostInfo, Parameter, RawOrigin}; +use sp_arithmetic::traits::{CheckedSub, Zero}; use sp_runtime::{ - traits::{BadOrigin, Member}, + traits::{BadOrigin, Member, Morph, TryMorph}, Either, }; +use sp_std::marker::PhantomData; + +use super::TypedGet; /// Some sort of check on the origin is performed by this object. pub trait EnsureOrigin { @@ -38,9 +42,23 @@ pub trait EnsureOrigin { /// Returns an outer origin capable of passing `try_origin` check. /// + /// NOTE: This should generally *NOT* be reimplemented. Instead implement + /// `try_successful_origin`. + /// /// ** Should be used for benchmarking only!!! ** #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> OuterOrigin; + fn successful_origin() -> OuterOrigin { + Self::try_successful_origin().expect("No origin exists which can satisfy the guard") + } + + /// Attept to get an outer origin capable of passing `try_origin` check. May return `Err` if it + /// is impossible. Default implementation just uses `successful_origin()`. + /// + /// ** Should be used for benchmarking only!!! ** + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(Self::successful_origin()) + } } /// `EnsureOrigin` implementation that always fails. @@ -51,8 +69,8 @@ impl EnsureOrigin for NeverEnsureOrigin { Err(o) } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> OO { - panic!("No `successful_origin` possible for `NeverEnsureOrigin`") + fn try_successful_origin() -> Result { + Err(()) } } @@ -71,9 +89,23 @@ pub trait EnsureOriginWithArg { /// Returns an outer origin capable of passing `try_origin` check. /// + /// NOTE: This should generally *NOT* be reimplemented. Instead implement + /// `try_successful_origin`. + /// /// ** Should be used for benchmarking only!!! ** #[cfg(feature = "runtime-benchmarks")] - fn successful_origin(a: &Argument) -> OuterOrigin; + fn successful_origin(a: &Argument) -> OuterOrigin { + Self::try_successful_origin(a).expect("No origin exists which can satisfy the guard") + } + + /// Attept to get an outer origin capable of passing `try_origin` check. May return `Err` if it + /// is impossible. Default implementation just uses `successful_origin()`. + /// + /// ** Should be used for benchmarking only!!! ** + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &Argument) -> Result { + Ok(Self::successful_origin(a)) + } } pub struct AsEnsureOriginWithArg(sp_std::marker::PhantomData); @@ -97,8 +129,121 @@ impl> /// /// ** Should be used for benchmarking only!!! ** #[cfg(feature = "runtime-benchmarks")] - fn successful_origin(_: &Argument) -> OuterOrigin { - EO::successful_origin() + fn try_successful_origin(_: &Argument) -> Result { + EO::try_successful_origin() + } +} + +/// A derivative `EnsureOrigin` implementation. It mutates the `Success` result of an `Original` +/// implementation with a given `Mutator`. +pub struct MapSuccess(PhantomData<(Original, Mutator)>); +impl, Mutator: Morph> EnsureOrigin + for MapSuccess +{ + type Success = Mutator::Outcome; + fn try_origin(o: O) -> Result { + Ok(Mutator::morph(Original::try_origin(o)?)) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Original::try_successful_origin() + } +} + +/// A derivative `EnsureOrigin` implementation. It mutates the `Success` result of an `Original` +/// implementation with a given `Mutator`, allowing the possibility of an error to be returned +/// from the mutator. +/// +/// NOTE: This is strictly worse performance than `MapSuccess` since it clones the original origin +/// value. If possible, use `MapSuccess` instead. +pub struct TryMapSuccess(PhantomData<(Orig, Mutator)>); +impl, Mutator: TryMorph> EnsureOrigin + for TryMapSuccess +{ + type Success = Mutator::Outcome; + fn try_origin(o: O) -> Result { + let orig = o.clone(); + Mutator::try_morph(Original::try_origin(o)?).map_err(|()| orig) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Original::try_successful_origin() + } +} + +/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L` +/// and `R`, with them combined using an `Either` type. +/// +/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. +/// +/// Successful origin is derived from the left side. +pub struct EitherOfDiverse(sp_std::marker::PhantomData<(L, R)>); +impl, R: EnsureOrigin> + EnsureOrigin for EitherOfDiverse +{ + type Success = Either; + fn try_origin(o: OuterOrigin) -> Result { + L::try_origin(o) + .map_or_else(|o| R::try_origin(o).map(Either::Right), |o| Ok(Either::Left(o))) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + L::try_successful_origin().or_else(|()| R::try_successful_origin()) + } +} + +/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L` +/// and `R`, with them combined using an `Either` type. +/// +/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. +/// +/// Successful origin is derived from the left side. +#[deprecated = "Use `EitherOfDiverse` instead"] +pub type EnsureOneOf = EitherOfDiverse; + +/// "OR gate" implementation of `EnsureOrigin`, `Success` type for both `L` and `R` must +/// be equal. +/// +/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. +/// +/// Successful origin is derived from the left side. +pub struct EitherOf(sp_std::marker::PhantomData<(L, R)>); +impl< + OuterOrigin, + L: EnsureOrigin, + R: EnsureOrigin, + > EnsureOrigin for EitherOf +{ + type Success = L::Success; + fn try_origin(o: OuterOrigin) -> Result { + L::try_origin(o).or_else(|o| R::try_origin(o)) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + L::try_successful_origin().or_else(|()| R::try_successful_origin()) + } +} + +/// Mutator which reduces a scalar by a particular amount. +pub struct ReduceBy(PhantomData); +impl TryMorph for ReduceBy +where + N::Type: CheckedSub, +{ + type Outcome = N::Type; + fn try_morph(r: N::Type) -> Result { + r.checked_sub(&N::get()).ok_or(()) + } +} +impl Morph for ReduceBy +where + N::Type: CheckedSub + Zero, +{ + type Outcome = N::Type; + fn morph(r: N::Type) -> N::Type { + r.checked_sub(&N::get()).unwrap_or(Zero::zero()) } } @@ -176,63 +321,6 @@ pub trait OriginTrait: Sized { fn signed(by: Self::AccountId) -> Self; } -/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L` -/// and `R`, with them combined using an `Either` type. -/// -/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. -/// -/// Successful origin is derived from the left side. -pub struct EitherOfDiverse(sp_std::marker::PhantomData<(L, R)>); - -impl, R: EnsureOrigin> - EnsureOrigin for EitherOfDiverse -{ - type Success = Either; - fn try_origin(o: OuterOrigin) -> Result { - L::try_origin(o) - .map_or_else(|o| R::try_origin(o).map(Either::Right), |o| Ok(Either::Left(o))) - } - - #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> OuterOrigin { - L::successful_origin() - } -} - -/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L` -/// and `R`, with them combined using an `Either` type. -/// -/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. -/// -/// Successful origin is derived from the left side. -#[deprecated = "Use `EitherOfDiverse` instead"] -pub type EnsureOneOf = EitherOfDiverse; - -/// "OR gate" implementation of `EnsureOrigin`, `Success` type for both `L` and `R` must -/// be equal. -/// -/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. -/// -/// Successful origin is derived from the left side. -pub struct EitherOf(sp_std::marker::PhantomData<(L, R)>); - -impl< - OuterOrigin, - L: EnsureOrigin, - R: EnsureOrigin, - > EnsureOrigin for EitherOf -{ - type Success = L::Success; - fn try_origin(o: OuterOrigin) -> Result { - L::try_origin(o).or_else(|o| R::try_origin(o)) - } - - #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> OuterOrigin { - L::successful_origin() - } -} - #[cfg(test)] mod tests { use super::*; @@ -248,8 +336,8 @@ mod tests { Ok(V::get()) } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> () { - () + fn try_successful_origin() -> Result<(), ()> { + Ok(()) } } @@ -259,8 +347,8 @@ mod tests { Err(()) } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> () { - () + fn try_successful_origin() -> Result<(), ()> { + Err(()) } } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index bc28cc7e8118e..370a802665918 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -66,6 +66,8 @@ #[cfg(feature = "std")] use serde::Serialize; +#[cfg(feature = "runtime-benchmarks")] +use sp_runtime::traits::TrailingZeroInput; use sp_runtime::{ generic, traits::{ @@ -782,8 +784,8 @@ impl, O>> + From>, Acco } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { - O::from(RawOrigin::Root) + fn try_successful_origin() -> Result { + Ok(O::from(RawOrigin::Root)) } } @@ -805,8 +807,8 @@ impl< } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { - O::from(RawOrigin::Root) + fn try_successful_origin() -> Result { + Ok(O::from(RawOrigin::Root)) } } @@ -823,11 +825,10 @@ impl, O>> + From>, Acco } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { + fn try_successful_origin() -> Result { let zero_account_id = - AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) - .expect("infinite length input; no invalid inputs for type; qed"); - O::from(RawOrigin::Signed(zero_account_id)) + AccountId::decode(&mut TrailingZeroInput::zeroes()).map_err(|_| ())?; + Ok(O::from(RawOrigin::Signed(zero_account_id))) } } @@ -847,16 +848,15 @@ impl< } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { + fn try_successful_origin() -> Result { let zero_account_id = - AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) - .expect("infinite length input; no invalid inputs for type; qed"); + AccountId::decode(&mut TrailingZeroInput::zeroes()).map_err(|_| ())?; let members = Who::sorted_members(); let first_member = match members.get(0) { Some(account) => account.clone(), None => zero_account_id, }; - O::from(RawOrigin::Signed(first_member)) + Ok(O::from(RawOrigin::Signed(first_member))) } } @@ -873,8 +873,8 @@ impl, O>> + From>, Acco } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { - O::from(RawOrigin::None) + fn try_successful_origin() -> Result { + Ok(O::from(RawOrigin::None)) } } @@ -886,8 +886,8 @@ impl EnsureOrigin for EnsureNever { } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> O { - unimplemented!() + fn try_successful_origin() -> Result { + Err(()) } } diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index a21296d1b39ec..61eafb652427b 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -116,8 +116,8 @@ impl frame_support::traits::EnsureOrigin for TestSpendOrigin { }) } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> Origin { - Origin::root() + fn try_successful_origin() -> Result { + Ok(Origin::root()) } } diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 1b21e7c65ddf7..ee6a526e95e1e 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -274,6 +274,42 @@ where } } +/// Extensible conversion trait. Generic over only source type, with destination type being +/// associated. +pub trait Morph { + /// The type into which `A` is mutated. + type Outcome; + + /// Make conversion. + fn morph(a: A) -> Self::Outcome; +} + +/// A structure that performs identity conversion. +impl Morph for Identity { + type Outcome = T; + fn morph(a: T) -> T { + a + } +} + +/// Extensible conversion trait. Generic over only source type, with destination type being +/// associated. +pub trait TryMorph { + /// The type into which `A` is mutated. + type Outcome; + + /// Make conversion. + fn try_morph(a: A) -> Result; +} + +/// A structure that performs identity conversion. +impl TryMorph for Identity { + type Outcome = T; + fn try_morph(a: T) -> Result { + Ok(a) + } +} + /// Extensible conversion trait. Generic over both source and destination types. pub trait Convert { /// Make conversion. From 24bea4c3cba7479e2cf2976a21e8111dfda6b1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 31 May 2022 20:29:00 +0200 Subject: [PATCH 0864/1472] Sync: Improve major sync detection (#11547) * Sync: Improve major sync detection When we still have a full import queue, we should still report that we are in major sync mode, otherwise validators may will already start producing blocks. * Use median * Review comments --- client/network/sync/src/lib.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index bc0ed46c3f068..b027d77827374 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -576,14 +576,28 @@ where .map(|p| PeerInfo { best_hash: p.best_hash, best_number: p.best_number }) } + /// Returns the best seen block. + fn best_seen(&self) -> Option> { + let mut best_seens = self.peers.values().map(|p| p.best_number).collect::>(); + + if best_seens.is_empty() { + None + } else { + let middle = best_seens.len() / 2; + + // Not the "perfect median" when we have an even number of peers. + Some(*best_seens.select_nth_unstable(middle).1) + } + } + /// Returns the current sync status. pub fn status(&self) -> Status { - let best_seen = self.peers.values().map(|p| p.best_number).max(); + let best_seen = self.best_seen(); let sync_state = if let Some(n) = best_seen { // A chain is classified as downloading if the provided best block is - // more than `MAJOR_SYNC_BLOCKS` behind the best queued block. - if n > self.best_queued_number && n - self.best_queued_number > MAJOR_SYNC_BLOCKS.into() - { + // more than `MAJOR_SYNC_BLOCKS` behind the best block. + let best_block = self.client.info().best_number; + if n > best_block && n - best_block > MAJOR_SYNC_BLOCKS.into() { SyncState::Downloading } else { SyncState::Idle From 0ebeac464ecacfb1b9cb36b63ed0040339807cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 31 May 2022 23:18:15 +0200 Subject: [PATCH 0865/1472] Fix clippy on master (#11559) --- primitives/arithmetic/src/helpers_128bit.rs | 4 ++-- primitives/arithmetic/src/per_things.rs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/primitives/arithmetic/src/helpers_128bit.rs b/primitives/arithmetic/src/helpers_128bit.rs index 260f90ed60cd0..11df8bd53153e 100644 --- a/primitives/arithmetic/src/helpers_128bit.rs +++ b/primitives/arithmetic/src/helpers_128bit.rs @@ -358,8 +358,8 @@ mod tests { fn op_checked_rounded_div_works() { for i in 0..100_000u32 { let a = random_u128(i); - let b = random_u128(i + 1 << 30); - let c = random_u128(i + 1 << 31); + let b = random_u128(i + (1 << 30)); + let c = random_u128(i + (1 << 31)); let x = mulrat(a, b, c, NearestPrefDown); let y = multiply_by_rational(a, b, c).ok(); assert_eq!(x.is_some(), y.is_some()); diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index 7f39d35774190..2932a742063db 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -639,8 +639,9 @@ macro_rules! implement_per_thing { write!(fmt, "{:.2}% ({}/{})", pc, self.0, $max) } else { // A power of ten: calculate exact percent - let units = self.0 / ($max / 100); - let rest = self.0 % ($max / 100); + let divisor = $max / 100; + let units = self.0 / divisor; + let rest = self.0 % divisor; write!(fmt, "{}", units)?; if rest > 0 { write!(fmt, ".")?; From 400e0751b3a9f165942566acc0a8815f22c32c91 Mon Sep 17 00:00:00 2001 From: koenw Date: Tue, 31 May 2022 23:23:30 +0200 Subject: [PATCH 0866/1472] Fix link in node-template README (#11529) The lorri repository has moved from https://github.com/target/lorri to https://github.com/nix-community/lorri. --- bin/node-template/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/node-template/README.md b/bin/node-template/README.md index 52b117b8a7826..8defb870fa1b0 100644 --- a/bin/node-template/README.md +++ b/bin/node-template/README.md @@ -13,8 +13,8 @@ the [Substrate Playground](https://docs.substrate.io/playground/) :hammer_and_wr ### Using Nix Install [nix](https://nixos.org/) and optionally [direnv](https://github.com/direnv/direnv) and -[lorri](https://github.com/target/lorri) for a fully plug and play experience for setting up the -development environment. To get all the correct dependencies activate direnv `direnv allow` and +[lorri](https://github.com/nix-community/lorri) for a fully plug and play experience for setting up +the development environment. To get all the correct dependencies activate direnv `direnv allow` and lorri `lorri shell`. ### Rust Setup From 3bfb4cc6a90d5aee98e634bada44225a187179d5 Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Wed, 1 Jun 2022 00:18:48 +0200 Subject: [PATCH 0867/1472] Fix minor typos (#11550) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix minor typos * FMT Co-authored-by: Bastian Köcher --- frame/contracts/src/lib.rs | 10 +++++----- frame/contracts/src/storage/meter.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index edb7fcf131de8..1011e264eb930 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -165,8 +165,8 @@ pub trait AddressGenerator { /// Default address generator. /// /// This is the default address generator used by contract instantiation. Its result -/// is only dependend on its inputs. It can therefore be used to reliably predict the -/// address of a contract. This is akin to the formular of eth's CREATE2 opcode. There +/// is only dependant on its inputs. It can therefore be used to reliably predict the +/// address of a contract. This is akin to the formula of eth's CREATE2 opcode. There /// is no CREATE equivalent because CREATE2 is strictly more powerful. /// /// Formula: `hash(deploying_address ++ code_hash ++ salt)` @@ -231,7 +231,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { - /// The time implementation used to supply timestamps to conntracts through `seal_now`. + /// The time implementation used to supply timestamps to contracts through `seal_now`. type Time: Time; /// The generator used to supply randomness to contracts through `seal_random`. @@ -339,7 +339,7 @@ pub mod pallet { /// /// For more information check out: /// - /// [`DefaultContractAccessWeight`] is a safe default to be used for polkadot or kusama + /// [`DefaultContractAccessWeight`] is a safe default to be used for Polkadot or Kusama /// parachains. /// /// # Note @@ -1044,7 +1044,7 @@ where })?; // The open deposit will be charged during execution when the // uploaded module does not already exist. This deposit is not part of the - // storage meter because it is not transfered to the contract but + // storage meter because it is not transferred to the contract but // reserved on the uploading account. (executable.open_deposit(), executable) }, diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index af51a5edc9472..b06f7ea4aedb5 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -35,10 +35,10 @@ pub type DepositOf = Deposit>; /// A production root storage meter that actually charges from its origin. pub type Meter = RawMeter; -/// A poduction nested storage meter that actually charges from its origin. +/// A production nested storage meter that actually charges from its origin. pub type NestedMeter = RawMeter; -/// A poduction storage meter that actually charges from its origin. +/// A production storage meter that actually charges from its origin. /// /// This can be used where we want to be generic over the state (Root vs. Nested). pub type GenericMeter = RawMeter; @@ -53,8 +53,8 @@ pub trait Ext { /// /// `origin`: The origin of the call stack from which is responsible for putting down a deposit. /// `limit`: The limit with which the meter was constructed. - /// `min_leftover`: How much `free_balance` in addition to the ed should be left inside the - /// `origin` account. + /// `min_leftover`: How much `free_balance` in addition to the existential deposit (ed) should + /// be left inside the `origin` account. /// /// Returns the limit that should be used by the meter. If origin can't afford the `limit` /// it returns `Err`. @@ -551,7 +551,7 @@ mod tests { let mut meter = TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); assert_eq!(meter.available(), 1_000); - // an empty charge foes not create a `Charge` entry + // an empty charge does not create a `Charge` entry let mut nested0 = meter.nested(); nested0.charge(&Default::default()).unwrap(); meter.absorb(nested0, &ALICE, &BOB, None); From 346471da930275ad61cbb33932a300062885dc21 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 1 Jun 2022 01:14:23 +0200 Subject: [PATCH 0868/1472] Short circuit Treasury::Spend benchmark for NeverEnsureOrigin (#11562) Signed-off-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- frame/treasury/src/benchmarking.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index 4f17189d79b39..ddb952383370d 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -66,14 +66,22 @@ fn assert_last_event, I: 'static>(generic_event: >:: } benchmarks_instance_pallet! { + // This benchmark is short-circuited if `SpendOrigin` cannot provide + // a successful origin, in which case `spend` is un-callable and can use weight=0. spend { let (_, value, beneficiary_lookup) = setup_proposal::(SEED); - let origin = T::SpendOrigin::successful_origin(); + let origin = T::SpendOrigin::try_successful_origin(); let beneficiary = T::Lookup::lookup(beneficiary_lookup.clone()).unwrap(); let call = Call::::spend { amount: value, beneficiary: beneficiary_lookup }; - }: { call.dispatch_bypass_filter(origin)? } + }: { + if let Ok(origin) = origin.clone() { + call.dispatch_bypass_filter(origin)?; + } + } verify { - assert_last_event::(Event::SpendApproved { proposal_index: 0, amount: value, beneficiary }.into()) + if origin.is_ok() { + assert_last_event::(Event::SpendApproved { proposal_index: 0, amount: value, beneficiary }.into()) + } } propose_spend { From 438f40dc262ac32a4afd600d8d76214897a0f1a6 Mon Sep 17 00:00:00 2001 From: MOZGIII Date: Wed, 1 Jun 2022 13:13:24 +0400 Subject: [PATCH 0869/1472] Do not require Ord for pallet_offences::Config::IdentificationTuple (#11563) --- frame/offences/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index a6d69e2a5e268..e4b75d9c3c015 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -59,7 +59,7 @@ pub mod pallet { /// The overarching event type. type Event: From + IsType<::Event>; /// Full identification of the validator. - type IdentificationTuple: Parameter + Ord; + type IdentificationTuple: Parameter; /// A handler called for every offence report. type OnOffenceHandler: OnOffenceHandler; } From 4aec7b4d0647c20f0e6b769b41bfec435dcfeced Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 1 Jun 2022 10:23:47 +0100 Subject: [PATCH 0870/1472] Ranked Collective pallet (#11548) * Ranked Collective pallet * Fixes * benchmarks * Weights * Allow class voting in rank Use bare ayes for calculating support. Allow only promotion/demotion by one rank only. Allow removal of member with rank zero only. Use new Tally API * Index by rank, still O(1). * Custom vote weights * Formatting * Update frame/ranked-collective/src/lib.rs * Broken :( * origin guard; cleanup uses new API * Formatting * Promote/demote by rank * Formatting * Use new API * Remove code in another PR * Remove code in another PR * Formatting * Remove code in another PR * Docs * Docs * Bump * Fixes * Formatting * Fixes --- Cargo.lock | 18 + Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 41 +- frame/ranked-collective/Cargo.toml | 49 ++ frame/ranked-collective/README.md | 22 + frame/ranked-collective/src/benchmarking.rs | 155 +++++ frame/ranked-collective/src/lib.rs | 630 ++++++++++++++++++ frame/ranked-collective/src/tests.rs | 457 +++++++++++++ frame/ranked-collective/src/weights.rs | 187 ++++++ frame/referenda/src/lib.rs | 2 +- frame/referenda/src/types.rs | 2 +- .../src/construct_runtime/expand/origin.rs | 9 +- frame/support/src/dispatch.rs | 3 + frame/support/src/storage/bounded_vec.rs | 6 + frame/support/src/storage/mod.rs | 6 +- frame/support/src/storage/types/double_map.rs | 31 +- frame/support/src/storage/types/map.rs | 16 +- frame/support/src/traits.rs | 3 +- frame/support/src/traits/dispatch.rs | 3 + frame/support/src/traits/voting.rs | 8 +- test-utils/runtime/src/lib.rs | 5 +- 22 files changed, 1641 insertions(+), 17 deletions(-) create mode 100644 frame/ranked-collective/Cargo.toml create mode 100644 frame/ranked-collective/README.md create mode 100644 frame/ranked-collective/src/benchmarking.rs create mode 100644 frame/ranked-collective/src/lib.rs create mode 100644 frame/ranked-collective/src/tests.rs create mode 100644 frame/ranked-collective/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 09da4278f69f4..17d2e82596526 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4764,6 +4764,7 @@ dependencies = [ "pallet-preimage", "pallet-proxy", "pallet-randomness-collective-flip", + "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", @@ -5988,6 +5989,23 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-ranked-collective" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-recovery" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 41739fe6f1ebc..74e7aae7949c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -115,6 +115,7 @@ members = [ "frame/nomination-pools", "frame/nomination-pools/benchmarking", "frame/randomness-collective-flip", + "frame/ranked-collective", "frame/recovery", "frame/referenda", "frame/remark", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 1b3e9083d1a1d..5ecd6ccedaf01 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -83,6 +83,7 @@ pallet-offences-benchmarking = { version = "4.0.0-dev", path = "../../../frame/o pallet-preimage = { version = "4.0.0-dev", default-features = false, path = "../../../frame/preimage" } pallet-proxy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/proxy" } pallet-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/randomness-collective-flip" } +pallet-ranked-collective = { version = "4.0.0-dev", default-features = false, path = "../../../frame/ranked-collective" } pallet-recovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/recovery" } pallet-referenda = { version = "4.0.0-dev", default-features = false, path = "../../../frame/referenda" } pallet-remark = { version = "4.0.0-dev", default-features = false, path = "../../../frame/remark" } @@ -176,6 +177,7 @@ std = [ "pallet-utility/std", "sp-version/std", "pallet-society/std", + "pallet-ranked-collective/std", "pallet-referenda/std", "pallet-remark/std", "pallet-recovery/std", @@ -218,6 +220,7 @@ runtime-benchmarks = [ "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-ranked-collective/runtime-benchmarks", "pallet-referenda/runtime-benchmarks", "pallet-recovery/runtime-benchmarks", "pallet-remark/runtime-benchmarks", @@ -265,6 +268,7 @@ try-runtime = [ "pallet-offences/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", + "pallet-ranked-collective/try-runtime", "pallet-randomness-collective-flip/try-runtime", "pallet-recovery/try-runtime", "pallet-referenda/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 9b5bc0273ab33..bfac30db6c66f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -20,7 +20,7 @@ #![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"] +#![recursion_limit = "512"] use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::{ @@ -43,7 +43,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureRoot, EnsureSigned, + EnsureRoot, EnsureRootWithSuccess, EnsureSigned, }; pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; @@ -780,11 +780,11 @@ parameter_types! { pub struct TracksInfo; impl pallet_referenda::TracksInfo for TracksInfo { - type Id = u8; + type Id = u16; type Origin = ::PalletsOrigin; fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { - static DATA: [(u8, pallet_referenda::TrackInfo); 1] = [( - 0u8, + static DATA: [(u16, pallet_referenda::TrackInfo); 1] = [( + 0u16, pallet_referenda::TrackInfo { name: "root", max_deciding: 1, @@ -837,6 +837,34 @@ impl pallet_referenda::Config for Runtime { type Tracks = TracksInfo; } +impl pallet_referenda::Config for Runtime { + type WeightInfo = pallet_referenda::weights::SubstrateWeight; + type Call = Call; + type Event = Event; + type Scheduler = Scheduler; + type Currency = pallet_balances::Pallet; + type CancelOrigin = EnsureRoot; + type KillOrigin = EnsureRoot; + type Slash = (); + type Votes = pallet_ranked_collective::Votes; + type Tally = pallet_ranked_collective::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; +} + +impl pallet_ranked_collective::Config for Runtime { + type WeightInfo = pallet_ranked_collective::weights::SubstrateWeight; + type Event = Event; + type PromoteOrigin = EnsureRootWithSuccess>; + type DemoteOrigin = EnsureRootWithSuccess>; + type Polls = RankedPolls; + type MinRankOfClass = traits::Identity; + type VoteWeight = pallet_ranked_collective::Geometric; +} + impl pallet_remark::Config for Runtime { type WeightInfo = pallet_remark::weights::SubstrateWeight; type Event = Event; @@ -1534,6 +1562,8 @@ construct_runtime!( ConvictionVoting: pallet_conviction_voting, Whitelist: pallet_whitelist, NominationPools: pallet_nomination_pools, + RankedPolls: pallet_referenda::, + RankedCollective: pallet_ranked_collective, } ); @@ -1622,6 +1652,7 @@ mod benches { [pallet_offences, OffencesBench::] [pallet_preimage, Preimage] [pallet_proxy, Proxy] + [pallet_ranked_collective, RankedCollective] [pallet_referenda, Referenda] [pallet_recovery, Recovery] [pallet_remark, Remark] diff --git a/frame/ranked-collective/Cargo.toml b/frame/ranked-collective/Cargo.toml new file mode 100644 index 0000000000000..cb43b9ea4c831 --- /dev/null +++ b/frame/ranked-collective/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "pallet-ranked-collective" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Ranked collective system: Members of a set of account IDs can make their collective feelings known through dispatched calls from one of two specialized origins." +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +log = { version = "0.4.16", default-features = false } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", + "sp-arithmetic/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/ranked-collective/README.md b/frame/ranked-collective/README.md new file mode 100644 index 0000000000000..b5fe65ef34920 --- /dev/null +++ b/frame/ranked-collective/README.md @@ -0,0 +1,22 @@ +# Ranked collective system. + +This is a membership pallet providing a `Tally` implementation ready for use with polling +systems such as the Referenda pallet. Members each have a rank, with zero being the lowest. +There is no complexity limitation on either the number of members at a rank or the number of +ranks in the system thus allowing potentially public membership. A member of at least a given +rank can be selected at random in O(1) time, allowing for various games to constructed using +this as a primitive. Members may only be promoted and demoted by one rank at a time, however +all operations (save one) are O(1) in complexity. The only operation which is not O(1) is the +`remove_member` since they must be removed from all ranks from the present down to zero. + +Different ranks have different voting power, and are able to vote in different polls. In general +rank privileges are cumulative. Higher ranks are able to vote in any polls open to lower ranks. +Similarly, higher ranks always have at least as much voting power in any given poll as lower +ranks. + +Two `Config` trait items control these "rank privileges": `MinRankOfClass` and `VoteWeight`. +The first controls which ranks are allowed to vote on a particular class of poll. The second +controls the weight of a vote given the voters rank compared to the minimum rank of the poll. + +An origin control, `EnsureRank`, ensures that the origin is a member of the collective of at +least a particular rank. diff --git a/frame/ranked-collective/src/benchmarking.rs b/frame/ranked-collective/src/benchmarking.rs new file mode 100644 index 0000000000000..ab1a5dc283ca5 --- /dev/null +++ b/frame/ranked-collective/src/benchmarking.rs @@ -0,0 +1,155 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Staking pallet benchmarking. + +use super::*; +#[allow(unused_imports)] +use crate::Pallet as RankedCollective; + +use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller}; +use frame_support::{assert_ok, dispatch::UnfilteredDispatchable}; +use frame_system::RawOrigin as SystemOrigin; + +const SEED: u32 = 0; + +fn assert_last_event, I: 'static>(generic_event: >::Event) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +fn make_member, I: 'static>(rank: Rank) -> T::AccountId { + let who = account::("member", MemberCount::::get(0), SEED); + assert_ok!(Pallet::::add_member(T::PromoteOrigin::successful_origin(), who.clone())); + for _ in 0..rank { + assert_ok!(Pallet::::promote_member( + T::PromoteOrigin::successful_origin(), + who.clone() + )); + } + who +} + +benchmarks_instance_pallet! { + add_member { + let who = account::("member", 0, SEED); + let origin = T::PromoteOrigin::successful_origin(); + let call = Call::::add_member { who: who.clone() }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_eq!(MemberCount::::get(0), 1); + assert_last_event::(Event::MemberAdded { who }.into()); + } + + remove_member { + let r in 0 .. 10; + let rank = r as u16; + let first = make_member::(rank); + let who = make_member::(rank); + let last = make_member::(rank); + let last_index = (0..=rank).map(|r| IdToIndex::::get(r, &last).unwrap()).collect::>(); + let origin = T::DemoteOrigin::successful_origin(); + let call = Call::::remove_member { who: who.clone(), min_rank: rank }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + for r in 0..=rank { + assert_eq!(MemberCount::::get(r), 2); + assert_ne!(last_index[r as usize], IdToIndex::::get(r, &last).unwrap()); + } + assert_last_event::(Event::MemberRemoved { who, rank }.into()); + } + + promote_member { + let r in 0 .. 10; + let rank = r as u16; + let who = make_member::(rank); + let origin = T::PromoteOrigin::successful_origin(); + let call = Call::::promote_member { who: who.clone() }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_eq!(Members::::get(&who).unwrap().rank, rank + 1); + assert_last_event::(Event::RankChanged { who, rank: rank + 1 }.into()); + } + + demote_member { + let r in 0 .. 10; + let rank = r as u16; + let first = make_member::(rank); + let who = make_member::(rank); + let last = make_member::(rank); + let last_index = IdToIndex::::get(rank, &last).unwrap(); + let origin = T::DemoteOrigin::successful_origin(); + let call = Call::::demote_member { who: who.clone() }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_eq!(Members::::get(&who).map(|x| x.rank), rank.checked_sub(1)); + assert_eq!(MemberCount::::get(rank), 2); + assert_ne!(last_index, IdToIndex::::get(rank, &last).unwrap()); + assert_last_event::(match rank { + 0 => Event::MemberRemoved { who, rank: 0 }, + r => Event::RankChanged { who, rank: r - 1 }, + }.into()); + } + + vote { + let caller: T::AccountId = whitelisted_caller(); + assert_ok!(Pallet::::add_member(T::PromoteOrigin::successful_origin(), caller.clone())); + // Create a poll + let class = T::Polls::classes().into_iter().next().unwrap(); + let rank = T::MinRankOfClass::convert(class.clone()); + for _ in 0..rank { + assert_ok!(Pallet::::promote_member( + T::PromoteOrigin::successful_origin(), + caller.clone() + )); + } + + let poll = T::Polls::create_ongoing(class).expect("Must always be able to create a poll for rank 0"); + + // Vote once. + assert_ok!(Pallet::::vote(SystemOrigin::Signed(caller.clone()).into(), poll, true)); + }: _(SystemOrigin::Signed(caller.clone()), poll, false) + verify { + let tally = Tally::from_parts(0, 0, 1); + let ev = Event::Voted { who: caller, poll, vote: VoteRecord::Nay(1), tally }; + assert_last_event::(ev.into()); + } + + cleanup_poll { + let n in 1 .. 100; + + // Create a poll + let class = T::Polls::classes().into_iter().next().unwrap(); + let rank = T::MinRankOfClass::convert(class.clone()); + let poll = T::Polls::create_ongoing(class).expect("Must always be able to create a poll"); + + // Vote in the poll by each of `n` members + for i in 0..n { + let who = make_member::(rank); + assert_ok!(Pallet::::vote(SystemOrigin::Signed(who).into(), poll, true)); + } + + // End the poll. + T::Polls::end_ongoing(poll, false).expect("Must always be able to end a poll"); + + assert_eq!(Voting::::iter_prefix(poll).count(), n as usize); + }: _(SystemOrigin::Signed(whitelisted_caller()), poll, n) + verify { + assert_eq!(Voting::::iter().count(), 0); + } + + impl_benchmark_test_suite!(RankedCollective, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs new file mode 100644 index 0000000000000..521dfb6aad4e3 --- /dev/null +++ b/frame/ranked-collective/src/lib.rs @@ -0,0 +1,630 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Ranked collective system. +//! +//! This is a membership pallet providing a `Tally` implementation ready for use with polling +//! systems such as the Referenda pallet. Members each have a rank, with zero being the lowest. +//! There is no complexity limitation on either the number of members at a rank or the number of +//! ranks in the system thus allowing potentially public membership. A member of at least a given +//! rank can be selected at random in O(1) time, allowing for various games to constructed using +//! this as a primitive. Members may only be promoted and demoted by one rank at a time, however +//! all operations (save one) are O(1) in complexity. The only operation which is not O(1) is the +//! `remove_member` since they must be removed from all ranks from the present down to zero. +//! +//! Different ranks have different voting power, and are able to vote in different polls. In general +//! rank privileges are cumulative. Higher ranks are able to vote in any polls open to lower ranks. +//! Similarly, higher ranks always have at least as much voting power in any given poll as lower +//! ranks. +//! +//! Two `Config` trait items control these "rank privileges": `MinRankOfClass` and `VoteWeight`. +//! The first controls which ranks are allowed to vote on a particular class of poll. The second +//! controls the weight of a vote given the voters rank compared to the minimum rank of the poll. +//! +//! An origin control, `EnsureRank`, ensures that the origin is a member of the collective of at +//! least a particular rank. + +#![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit = "128"] + +use scale_info::TypeInfo; +use sp_arithmetic::traits::Saturating; +use sp_runtime::{traits::Convert, ArithmeticError::Overflow, Perbill, RuntimeDebug}; +use sp_std::{marker::PhantomData, prelude::*}; + +use frame_support::{ + codec::{Decode, Encode, MaxEncodedLen}, + dispatch::{DispatchError, DispatchResultWithPostInfo}, + ensure, + traits::{EnsureOrigin, PollStatus, Polling, VoteTally}, + weights::PostDispatchInfo, + CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, +}; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +pub mod weights; + +pub use pallet::*; +pub use weights::WeightInfo; + +/// A number of members. +pub type MemberIndex = u32; + +/// Member rank. +pub type Rank = u16; + +/// Votes. +pub type Votes = u32; + +/// Aggregated votes for an ongoing poll by members of the ranked collective. +#[derive( + CloneNoBound, + PartialEqNoBound, + EqNoBound, + RuntimeDebugNoBound, + TypeInfo, + Encode, + Decode, + MaxEncodedLen, +)] +#[scale_info(skip_type_params(M))] +pub struct Tally { + bare_ayes: MemberIndex, + ayes: Votes, + nays: Votes, + dummy: PhantomData, +} + +impl Tally { + pub fn from_parts(bare_ayes: MemberIndex, ayes: Votes, nays: Votes) -> Self { + Tally { bare_ayes, ayes, nays, dummy: PhantomData } + } +} + +// Use (non-rank-weighted) ayes for calculating support. +// Allow only promotion/demotion by one rank only. +// Allow removal of member with rank zero only. +// This keeps everything O(1) while still allowing arbitrary number of ranks. + +// All functions of VoteTally now include the class as a param. + +pub type TallyOf = Tally>; +pub type PollIndexOf = <>::Polls as Polling>>::Index; + +impl VoteTally for Tally { + fn new(_: Rank) -> Self { + Self { bare_ayes: 0, ayes: 0, nays: 0, dummy: PhantomData } + } + fn ayes(&self, _: Rank) -> Votes { + self.bare_ayes + } + fn support(&self, class: Rank) -> Perbill { + Perbill::from_rational(self.bare_ayes, M::get_max_voters(class)) + } + fn approval(&self, _: Rank) -> Perbill { + Perbill::from_rational(self.ayes, 1.max(self.ayes + self.nays)) + } + #[cfg(feature = "runtime-benchmarks")] + fn unanimity(class: Rank) -> Self { + Self { + bare_ayes: M::get_max_voters(class), + ayes: M::get_max_voters(class), + nays: 0, + dummy: PhantomData, + } + } + #[cfg(feature = "runtime-benchmarks")] + fn rejection(class: Rank) -> Self { + Self { bare_ayes: 0, ayes: 0, nays: M::get_max_voters(class), dummy: PhantomData } + } + #[cfg(feature = "runtime-benchmarks")] + fn from_requirements(support: Perbill, approval: Perbill, class: Rank) -> Self { + let c = M::get_max_voters(class); + let ayes = support * c; + let nays = ((ayes as u64) * 1_000_000_000u64 / approval.deconstruct() as u64) as u32 - ayes; + Self { bare_ayes: ayes, ayes, nays, dummy: PhantomData } + } +} + +/// Record needed for every member. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct MemberRecord { + /// The rank of the member. + rank: Rank, +} + +/// Record needed for every vote. +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum VoteRecord { + /// Vote was an aye with given vote weight. + Aye(Votes), + /// Vote was a nay with given vote weight. + Nay(Votes), +} + +impl From<(bool, Votes)> for VoteRecord { + fn from((aye, votes): (bool, Votes)) -> Self { + match aye { + true => VoteRecord::Aye(votes), + false => VoteRecord::Nay(votes), + } + } +} + +/// Vote-weight scheme where all voters get one vote regardless of rank. +pub struct Unit; +impl Convert for Unit { + fn convert(_: Rank) -> Votes { + 1 + } +} + +/// Vote-weight scheme where all voters get one vote plus an additional vote for every excess rank +/// they have. I.e.: +/// +/// - Each member with no excess rank gets 1 vote; +/// - ...with an excess rank of 1 gets 2 votes; +/// - ...with an excess rank of 2 gets 2 votes; +/// - ...with an excess rank of 3 gets 3 votes; +/// - ...with an excess rank of 4 gets 4 votes. +pub struct Linear; +impl Convert for Linear { + fn convert(r: Rank) -> Votes { + (r + 1) as Votes + } +} + +/// Vote-weight scheme where all voters get one vote plus additional votes for every excess rank +/// they have incrementing by one vote for each excess rank. I.e.: +/// +/// - Each member with no excess rank gets 1 vote; +/// - ...with an excess rank of 1 gets 2 votes; +/// - ...with an excess rank of 2 gets 3 votes; +/// - ...with an excess rank of 3 gets 6 votes; +/// - ...with an excess rank of 4 gets 10 votes. +pub struct Geometric; +impl Convert for Geometric { + fn convert(r: Rank) -> Votes { + let v = (r + 1) as Votes; + v * (v + 1) / 2 + } +} + +/// Trait for getting the maximum number of voters for a given rank. +pub trait GetMaxVoters { + /// Return the maximum number of voters for the rank `r`. + fn get_max_voters(r: Rank) -> MemberIndex; +} +impl, I: 'static> GetMaxVoters for Pallet { + fn get_max_voters(r: Rank) -> MemberIndex { + MemberCount::::get(r) + } +} + +/// Guard to ensure that the given origin is a member of the collective. The rank of the member is +/// the `Success` value. +pub struct EnsureRanked(PhantomData<(T, I)>); +impl, I: 'static, const MIN_RANK: u16> EnsureOrigin + for EnsureRanked +{ + type Success = Rank; + + fn try_origin(o: T::Origin) -> Result { + let who = frame_system::EnsureSigned::try_origin(o)?; + match Members::::get(&who) { + Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok(rank), + _ => Err(frame_system::RawOrigin::Signed(who).into()), + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; + Ok(frame_system::RawOrigin::Signed(who).into()) + } +} + +/// Guard to ensure that the given origin is a member of the collective. The account ID of the +/// member is the `Success` value. +pub struct EnsureMember(PhantomData<(T, I)>); +impl, I: 'static, const MIN_RANK: u16> EnsureOrigin + for EnsureMember +{ + type Success = T::AccountId; + + fn try_origin(o: T::Origin) -> Result { + let who = frame_system::EnsureSigned::try_origin(o)?; + match Members::::get(&who) { + Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok(who), + _ => Err(frame_system::RawOrigin::Signed(who).into()), + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; + Ok(frame_system::RawOrigin::Signed(who).into()) + } +} + +/// Guard to ensure that the given origin is a member of the collective. The pair of including both +/// the account ID and the rank of the member is the `Success` value. +pub struct EnsureRankedMember(PhantomData<(T, I)>); +impl, I: 'static, const MIN_RANK: u16> EnsureOrigin + for EnsureRankedMember +{ + type Success = (T::AccountId, Rank); + + fn try_origin(o: T::Origin) -> Result { + let who = frame_system::EnsureSigned::try_origin(o)?; + match Members::::get(&who) { + Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok((who, rank)), + _ => Err(frame_system::RawOrigin::Signed(who).into()), + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; + Ok(frame_system::RawOrigin::Signed(who).into()) + } +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{pallet_prelude::*, storage::KeyLenOf}; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData<(T, I)>); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + /// The outer event type. + type Event: From> + IsType<::Event>; + + /// The origin required to add or promote a mmember. The success value indicates the + /// maximum rank *to which* the promotion may be. + type PromoteOrigin: EnsureOrigin; + + /// The origin required to demote or remove a member. The success value indicates the + /// maximum rank *from which* the demotion/removal may be. + type DemoteOrigin: EnsureOrigin; + + /// The polling system used for our voting. + type Polls: Polling, Votes = Votes, Moment = Self::BlockNumber>; + + /// Convert the tally class into the minimum rank required to vote on the poll. If + /// `Polls::Class` is the same type as `Rank`, then `Identity` can be used here to mean + /// "a rank of at least the poll class". + type MinRankOfClass: Convert<>>::Class, Rank>; + + /// Convert a rank_delta into a number of votes the rank gets. + /// + /// Rank_delta is defined as the number of ranks above the minimum required to take part + /// in the poll. + type VoteWeight: Convert; + } + + /// The number of members in the collective who have at least the rank according to the index + /// of the vec. + #[pallet::storage] + pub type MemberCount, I: 'static = ()> = + StorageMap<_, Twox64Concat, Rank, MemberIndex, ValueQuery>; + + /// The current members of the collective. + #[pallet::storage] + pub type Members, I: 'static = ()> = + StorageMap<_, Twox64Concat, T::AccountId, MemberRecord>; + + /// The index of each ranks's member into the group of members who have at least that rank. + #[pallet::storage] + pub type IdToIndex, I: 'static = ()> = + StorageDoubleMap<_, Twox64Concat, Rank, Twox64Concat, T::AccountId, MemberIndex>; + + /// The members in the collective by index. All indices in the range `0..MemberCount` will + /// return `Some`, however a member's index is not guaranteed to remain unchanged over time. + #[pallet::storage] + pub type IndexToId, I: 'static = ()> = + StorageDoubleMap<_, Twox64Concat, Rank, Twox64Concat, MemberIndex, T::AccountId>; + + /// Votes on a given proposal, if it is ongoing. + #[pallet::storage] + pub type Voting, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + PollIndexOf, + Twox64Concat, + T::AccountId, + VoteRecord, + >; + + #[pallet::storage] + pub type VotingCleanup, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, PollIndexOf, BoundedVec>>>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// A member `who` has been added. + MemberAdded { who: T::AccountId }, + /// The member `who`'s rank has been changed to the given `rank`. + RankChanged { who: T::AccountId, rank: Rank }, + /// The member `who` of given `rank` has been removed from the collective. + MemberRemoved { who: T::AccountId, rank: Rank }, + /// The member `who` has voted for the `poll` with the given `vote` leading to an updated + /// `tally`. + Voted { who: T::AccountId, poll: PollIndexOf, vote: VoteRecord, tally: TallyOf }, + } + + #[pallet::error] + pub enum Error { + /// Account is already a member. + AlreadyMember, + /// Account is not a member. + NotMember, + /// The given poll index is unknown or has closed. + NotPolling, + /// The given poll is still ongoing. + Ongoing, + /// There are no further records to be removed. + NoneRemaining, + /// Unexpected error in state. + Corruption, + /// The member's rank is too low to vote. + RankTooLow, + /// The information provided is incorrect. + InvalidWitness, + /// The origin is not sufficiently privileged to do the operation. + NoPermission, + } + + #[pallet::call] + impl, I: 'static> Pallet { + /// Introduce a new member. + /// + /// - `origin`: Must be the `AdminOrigin`. + /// - `who`: Account of non-member which will become a member. + /// - `rank`: The rank to give the new member. + /// + /// Weight: `O(1)` + #[pallet::weight(T::WeightInfo::add_member())] + pub fn add_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { + let _ = T::PromoteOrigin::ensure_origin(origin)?; + ensure!(!Members::::contains_key(&who), Error::::AlreadyMember); + let index = MemberCount::::get(0); + let count = index.checked_add(1).ok_or(Overflow)?; + + Members::::insert(&who, MemberRecord { rank: 0 }); + IdToIndex::::insert(0, &who, index); + IndexToId::::insert(0, index, &who); + MemberCount::::insert(0, count); + Self::deposit_event(Event::MemberAdded { who }); + + Ok(()) + } + + /// Increment the rank of an existing member by one. + /// + /// - `origin`: Must be the `AdminOrigin`. + /// - `who`: Account of existing member. + /// + /// Weight: `O(1)` + #[pallet::weight(T::WeightInfo::promote_member(0))] + pub fn promote_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { + let max_rank = T::PromoteOrigin::ensure_origin(origin)?; + let record = Self::ensure_member(&who)?; + let rank = record.rank.checked_add(1).ok_or(Overflow)?; + ensure!(max_rank >= rank, Error::::NoPermission); + let index = MemberCount::::get(rank); + MemberCount::::insert(rank, index.checked_add(1).ok_or(Overflow)?); + IdToIndex::::insert(rank, &who, index); + IndexToId::::insert(rank, index, &who); + Members::::insert(&who, MemberRecord { rank, ..record }); + Self::deposit_event(Event::RankChanged { who, rank }); + + Ok(()) + } + + /// Decrement the rank of an existing member by one. If the member is already at rank zero, + /// then they are removed entirely. + /// + /// - `origin`: Must be the `AdminOrigin`. + /// - `who`: Account of existing member of rank greater than zero. + /// + /// Weight: `O(1)`, less if the member's index is highest in its rank. + #[pallet::weight(T::WeightInfo::demote_member(0))] + pub fn demote_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { + let max_rank = T::DemoteOrigin::ensure_origin(origin)?; + let mut record = Self::ensure_member(&who)?; + let rank = record.rank; + ensure!(max_rank >= rank, Error::::NoPermission); + + Self::remove_from_rank(&who, rank)?; + let maybe_rank = rank.checked_sub(1); + match maybe_rank { + None => { + Members::::remove(&who); + Self::deposit_event(Event::MemberRemoved { who, rank: 0 }); + }, + Some(rank) => { + record.rank = rank; + Members::::insert(&who, &record); + Self::deposit_event(Event::RankChanged { who, rank }); + }, + } + Ok(()) + } + + /// Remove the member entirely. + /// + /// - `origin`: Must be the `AdminOrigin`. + /// - `who`: Account of existing member of rank greater than zero. + /// - `min_rank`: The rank of the member or greater. + /// + /// Weight: `O(min_rank)`. + #[pallet::weight(T::WeightInfo::remove_member(*min_rank as u32))] + pub fn remove_member( + origin: OriginFor, + who: T::AccountId, + min_rank: Rank, + ) -> DispatchResultWithPostInfo { + let max_rank = T::DemoteOrigin::ensure_origin(origin)?; + let MemberRecord { rank, .. } = Self::ensure_member(&who)?; + ensure!(min_rank >= rank, Error::::InvalidWitness); + ensure!(max_rank >= rank, Error::::NoPermission); + + for r in 0..=rank { + Self::remove_from_rank(&who, r)?; + } + Members::::remove(&who); + Self::deposit_event(Event::MemberRemoved { who, rank }); + Ok(PostDispatchInfo { + actual_weight: Some(T::WeightInfo::remove_member(rank as u32)), + pays_fee: Pays::Yes, + }) + } + + /// Add an aye or nay vote for the sender to the given proposal. + /// + /// - `origin`: Must be `Signed` by a member account. + /// - `poll`: Index of a poll which is ongoing. + /// - `aye`: `true` if the vote is to approve the proposal, `false` otherwise. + /// + /// Transaction fees are be waived if the member is voting on any particular proposal + /// for the first time and the call is successful. Subsequent vote changes will charge a + /// fee. + /// + /// Weight: `O(1)`, less if there was no previous vote on the poll by the member. + #[pallet::weight(T::WeightInfo::vote())] + pub fn vote( + origin: OriginFor, + poll: PollIndexOf, + aye: bool, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + let record = Self::ensure_member(&who)?; + use VoteRecord::*; + let mut pays = Pays::Yes; + + let (tally, vote) = T::Polls::try_access_poll( + poll, + |mut status| -> Result<(TallyOf, VoteRecord), DispatchError> { + match status { + PollStatus::None | PollStatus::Completed(..) => + Err(Error::::NotPolling)?, + PollStatus::Ongoing(ref mut tally, class) => { + match Voting::::get(&poll, &who) { + Some(Aye(votes)) => { + tally.bare_ayes.saturating_dec(); + tally.ayes.saturating_reduce(votes); + }, + Some(Nay(votes)) => tally.nays.saturating_reduce(votes), + None => pays = Pays::No, + } + let min_rank = T::MinRankOfClass::convert(class); + let votes = Self::rank_to_votes(record.rank, min_rank)?; + let vote = VoteRecord::from((aye, votes)); + match aye { + true => { + tally.bare_ayes.saturating_inc(); + tally.ayes.saturating_accrue(votes); + }, + false => tally.nays.saturating_accrue(votes), + } + Voting::::insert(&poll, &who, &vote); + Ok((tally.clone(), vote)) + }, + } + }, + )?; + Self::deposit_event(Event::Voted { who, poll, vote, tally }); + Ok(pays.into()) + } + + /// Remove votes from the given poll. It must have ended. + /// + /// - `origin`: Must be `Signed` by any account. + /// - `poll_index`: Index of a poll which is completed and for which votes continue to + /// exist. + /// - `max`: Maximum number of vote items from remove in this call. + /// + /// Transaction fees are waived if the operation is successful. + /// + /// Weight `O(max)` (less if there are fewer items to remove than `max`). + #[pallet::weight(T::WeightInfo::cleanup_poll(*max))] + pub fn cleanup_poll( + origin: OriginFor, + poll_index: PollIndexOf, + max: u32, + ) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + ensure!(T::Polls::as_ongoing(poll_index).is_none(), Error::::Ongoing); + + let r = Voting::::clear_prefix( + poll_index, + max, + VotingCleanup::::take(poll_index).as_ref().map(|c| &c[..]), + ); + if r.unique == 0 { + // return Err(Error::::NoneRemaining) + return Ok(Pays::Yes.into()) + } + if let Some(cursor) = r.maybe_cursor { + VotingCleanup::::insert(poll_index, BoundedVec::truncate_from(cursor)); + } + Ok(PostDispatchInfo { + actual_weight: Some(T::WeightInfo::cleanup_poll(r.unique)), + pays_fee: Pays::No, + }) + } + } + + impl, I: 'static> Pallet { + fn ensure_member(who: &T::AccountId) -> Result { + Members::::get(who).ok_or(Error::::NotMember.into()) + } + + fn rank_to_votes(rank: Rank, min: Rank) -> Result { + let excess = rank.checked_sub(min).ok_or(Error::::RankTooLow)?; + Ok(T::VoteWeight::convert(excess)) + } + + fn remove_from_rank(who: &T::AccountId, rank: Rank) -> DispatchResult { + let last_index = MemberCount::::get(rank).saturating_sub(1); + let index = IdToIndex::::get(rank, &who).ok_or(Error::::Corruption)?; + if index != last_index { + let last = + IndexToId::::get(rank, last_index).ok_or(Error::::Corruption)?; + IdToIndex::::insert(rank, &last, index); + IndexToId::::insert(rank, index, &last); + } + MemberCount::::mutate(rank, |r| r.saturating_dec()); + Ok(()) + } + } +} diff --git a/frame/ranked-collective/src/tests.rs b/frame/ranked-collective/src/tests.rs new file mode 100644 index 0000000000000..1426012b63cea --- /dev/null +++ b/frame/ranked-collective/src/tests.rs @@ -0,0 +1,457 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The crate's tests. + +use std::collections::BTreeMap; + +use frame_support::{ + assert_noop, assert_ok, + error::BadOrigin, + parameter_types, + traits::{ConstU16, ConstU32, ConstU64, EitherOf, Everything, MapSuccess, Polling, ReduceBy}, +}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, Identity, IdentityLookup}, +}; + +use super::*; +use crate as pallet_ranked_collective; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Club: pallet_ranked_collective::{Pallet, Call, Storage, Event}, + } +); + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(1_000_000); +} +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = Call; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TestPollState { + Ongoing(TallyOf, Rank), + Completed(u64, bool), +} +use TestPollState::*; + +parameter_types! { + pub static Polls: BTreeMap = vec![ + (1, Completed(1, true)), + (2, Completed(2, false)), + (3, Ongoing(Tally::from_parts(0, 0, 0), 1)), + ].into_iter().collect(); +} + +pub struct TestPolls; +impl Polling> for TestPolls { + type Index = u8; + type Votes = Votes; + type Moment = u64; + type Class = Rank; + fn classes() -> Vec { + vec![0, 1, 2] + } + fn as_ongoing(index: u8) -> Option<(TallyOf, Self::Class)> { + Polls::get().remove(&index).and_then(|x| { + if let TestPollState::Ongoing(t, c) = x { + Some((t, c)) + } else { + None + } + }) + } + fn access_poll( + index: Self::Index, + f: impl FnOnce(PollStatus<&mut TallyOf, Self::Moment, Self::Class>) -> R, + ) -> R { + let mut polls = Polls::get(); + let entry = polls.get_mut(&index); + let r = match entry { + Some(Ongoing(ref mut tally_mut_ref, class)) => + f(PollStatus::Ongoing(tally_mut_ref, *class)), + Some(Completed(when, succeeded)) => f(PollStatus::Completed(*when, *succeeded)), + None => f(PollStatus::None), + }; + Polls::set(polls); + r + } + fn try_access_poll( + index: Self::Index, + f: impl FnOnce( + PollStatus<&mut TallyOf, Self::Moment, Self::Class>, + ) -> Result, + ) -> Result { + let mut polls = Polls::get(); + let entry = polls.get_mut(&index); + let r = match entry { + Some(Ongoing(ref mut tally_mut_ref, class)) => + f(PollStatus::Ongoing(tally_mut_ref, *class)), + Some(Completed(when, succeeded)) => f(PollStatus::Completed(*when, *succeeded)), + None => f(PollStatus::None), + }?; + Polls::set(polls); + Ok(r) + } + + #[cfg(feature = "runtime-benchmarks")] + fn create_ongoing(class: Self::Class) -> Result { + let mut polls = Polls::get(); + let i = polls.keys().rev().next().map_or(0, |x| x + 1); + polls.insert(i, Ongoing(Tally::new(class), class)); + Polls::set(polls); + Ok(i) + } + + #[cfg(feature = "runtime-benchmarks")] + fn end_ongoing(index: Self::Index, approved: bool) -> Result<(), ()> { + let mut polls = Polls::get(); + match polls.get(&index) { + Some(Ongoing(..)) => {}, + _ => return Err(()), + } + let now = frame_system::Pallet::::block_number(); + polls.insert(index, Completed(now, approved)); + Polls::set(polls); + Ok(()) + } +} + +impl Config for Test { + type WeightInfo = (); + type Event = Event; + type PromoteOrigin = EitherOf< + // Root can promote arbitrarily. + frame_system::EnsureRootWithSuccess>, + // Members can promote up to the rank of 2 below them. + MapSuccess, ReduceBy>>, + >; + type DemoteOrigin = EitherOf< + // Root can demote arbitrarily. + frame_system::EnsureRootWithSuccess>, + // Members can demote up to the rank of 3 below them. + MapSuccess, ReduceBy>>, + >; + type Polls = TestPolls; + type MinRankOfClass = Identity; + type VoteWeight = Geometric; +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +fn next_block() { + System::set_block_number(System::block_number() + 1); +} + +fn member_count(r: Rank) -> MemberIndex { + MemberCount::::get(r) +} + +#[allow(dead_code)] +fn run_to(n: u64) { + while System::block_number() < n { + next_block(); + } +} + +fn tally(index: u8) -> TallyOf { + >>::as_ongoing(index).expect("No poll").0 +} + +#[test] +#[ignore] +#[should_panic(expected = "No poll")] +fn unknown_poll_should_panic() { + let _ = tally(0); +} + +#[test] +#[ignore] +#[should_panic(expected = "No poll")] +fn completed_poll_should_panic() { + let _ = tally(1); +} + +#[test] +fn basic_stuff() { + new_test_ext().execute_with(|| { + assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); + }); +} + +#[test] +fn member_lifecycle_works() { + new_test_ext().execute_with(|| { + assert_ok!(Club::add_member(Origin::root(), 1)); + assert_ok!(Club::promote_member(Origin::root(), 1)); + assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_eq!(member_count(0), 0); + assert_eq!(member_count(1), 0); + }); +} + +#[test] +fn add_remove_works() { + new_test_ext().execute_with(|| { + assert_noop!(Club::add_member(Origin::signed(1), 1), DispatchError::BadOrigin); + assert_ok!(Club::add_member(Origin::root(), 1)); + assert_eq!(member_count(0), 1); + + assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_eq!(member_count(0), 0); + + assert_ok!(Club::add_member(Origin::root(), 1)); + assert_eq!(member_count(0), 1); + + assert_ok!(Club::add_member(Origin::root(), 2)); + assert_eq!(member_count(0), 2); + + assert_ok!(Club::add_member(Origin::root(), 3)); + assert_eq!(member_count(0), 3); + + assert_ok!(Club::demote_member(Origin::root(), 3)); + assert_eq!(member_count(0), 2); + + assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_eq!(member_count(0), 1); + + assert_ok!(Club::demote_member(Origin::root(), 2)); + assert_eq!(member_count(0), 0); + }); +} + +#[test] +fn promote_demote_works() { + new_test_ext().execute_with(|| { + assert_noop!(Club::add_member(Origin::signed(1), 1), DispatchError::BadOrigin); + assert_ok!(Club::add_member(Origin::root(), 1)); + assert_eq!(member_count(0), 1); + assert_eq!(member_count(1), 0); + + assert_ok!(Club::add_member(Origin::root(), 2)); + assert_eq!(member_count(0), 2); + assert_eq!(member_count(1), 0); + + assert_ok!(Club::promote_member(Origin::root(), 1)); + assert_eq!(member_count(0), 2); + assert_eq!(member_count(1), 1); + + assert_ok!(Club::promote_member(Origin::root(), 2)); + assert_eq!(member_count(0), 2); + assert_eq!(member_count(1), 2); + + assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_eq!(member_count(0), 2); + assert_eq!(member_count(1), 1); + + assert_noop!(Club::demote_member(Origin::signed(1), 1), DispatchError::BadOrigin); + assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_eq!(member_count(0), 1); + assert_eq!(member_count(1), 1); + }); +} + +#[test] +fn promote_demote_by_rank_works() { + new_test_ext().execute_with(|| { + assert_ok!(Club::add_member(Origin::root(), 1)); + for _ in 0..7 { + assert_ok!(Club::promote_member(Origin::root(), 1)); + } + + // #1 can add #2 and promote to rank 1 + assert_ok!(Club::add_member(Origin::signed(1), 2)); + assert_ok!(Club::promote_member(Origin::signed(1), 2)); + // #2 as rank 1 cannot do anything privileged + assert_noop!(Club::add_member(Origin::signed(2), 3), BadOrigin); + + assert_ok!(Club::promote_member(Origin::signed(1), 2)); + // #2 as rank 2 can add #3. + assert_ok!(Club::add_member(Origin::signed(2), 3)); + + // #2 as rank 2 cannot promote #3 to rank 1 + assert_noop!(Club::promote_member(Origin::signed(2), 3), Error::::NoPermission); + + // #1 as rank 7 can promote #2 only up to rank 5 and once there cannot demote them. + assert_ok!(Club::promote_member(Origin::signed(1), 2)); + assert_ok!(Club::promote_member(Origin::signed(1), 2)); + assert_ok!(Club::promote_member(Origin::signed(1), 2)); + assert_noop!(Club::promote_member(Origin::signed(1), 2), Error::::NoPermission); + assert_noop!(Club::demote_member(Origin::signed(1), 2), Error::::NoPermission); + + // #2 as rank 5 can promote #3 only up to rank 3 and once there cannot demote them. + assert_ok!(Club::promote_member(Origin::signed(2), 3)); + assert_ok!(Club::promote_member(Origin::signed(2), 3)); + assert_ok!(Club::promote_member(Origin::signed(2), 3)); + assert_noop!(Club::promote_member(Origin::signed(2), 3), Error::::NoPermission); + assert_noop!(Club::demote_member(Origin::signed(2), 3), Error::::NoPermission); + + // #2 can add #4 & #5 as rank 0 and #6 & #7 as rank 1. + assert_ok!(Club::add_member(Origin::signed(2), 4)); + assert_ok!(Club::add_member(Origin::signed(2), 5)); + assert_ok!(Club::add_member(Origin::signed(2), 6)); + assert_ok!(Club::promote_member(Origin::signed(2), 6)); + assert_ok!(Club::add_member(Origin::signed(2), 7)); + assert_ok!(Club::promote_member(Origin::signed(2), 7)); + + // #3 as rank 3 can demote/remove #4 & #5 but not #6 & #7 + assert_ok!(Club::demote_member(Origin::signed(3), 4)); + assert_ok!(Club::remove_member(Origin::signed(3), 5, 0)); + assert_noop!(Club::demote_member(Origin::signed(3), 6), Error::::NoPermission); + assert_noop!(Club::remove_member(Origin::signed(3), 7, 1), Error::::NoPermission); + + // #2 as rank 5 can demote/remove #6 & #7 + assert_ok!(Club::demote_member(Origin::signed(2), 6)); + assert_ok!(Club::remove_member(Origin::signed(2), 7, 1)); + }); +} + +#[test] +fn voting_works() { + new_test_ext().execute_with(|| { + assert_ok!(Club::add_member(Origin::root(), 0)); + assert_ok!(Club::add_member(Origin::root(), 1)); + assert_ok!(Club::promote_member(Origin::root(), 1)); + assert_ok!(Club::add_member(Origin::root(), 2)); + assert_ok!(Club::promote_member(Origin::root(), 2)); + assert_ok!(Club::promote_member(Origin::root(), 2)); + assert_ok!(Club::add_member(Origin::root(), 3)); + assert_ok!(Club::promote_member(Origin::root(), 3)); + assert_ok!(Club::promote_member(Origin::root(), 3)); + assert_ok!(Club::promote_member(Origin::root(), 3)); + + assert_noop!(Club::vote(Origin::signed(0), 3, true), Error::::RankTooLow); + assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); + + assert_ok!(Club::vote(Origin::signed(1), 3, true)); + assert_eq!(tally(3), Tally::from_parts(1, 1, 0)); + assert_ok!(Club::vote(Origin::signed(1), 3, false)); + assert_eq!(tally(3), Tally::from_parts(0, 0, 1)); + + assert_ok!(Club::vote(Origin::signed(2), 3, true)); + assert_eq!(tally(3), Tally::from_parts(1, 3, 1)); + assert_ok!(Club::vote(Origin::signed(2), 3, false)); + assert_eq!(tally(3), Tally::from_parts(0, 0, 4)); + + assert_ok!(Club::vote(Origin::signed(3), 3, true)); + assert_eq!(tally(3), Tally::from_parts(1, 6, 4)); + assert_ok!(Club::vote(Origin::signed(3), 3, false)); + assert_eq!(tally(3), Tally::from_parts(0, 0, 10)); + }); +} + +#[test] +fn cleanup_works() { + new_test_ext().execute_with(|| { + assert_ok!(Club::add_member(Origin::root(), 1)); + assert_ok!(Club::promote_member(Origin::root(), 1)); + assert_ok!(Club::add_member(Origin::root(), 2)); + assert_ok!(Club::promote_member(Origin::root(), 2)); + assert_ok!(Club::add_member(Origin::root(), 3)); + assert_ok!(Club::promote_member(Origin::root(), 3)); + + assert_ok!(Club::vote(Origin::signed(1), 3, true)); + assert_ok!(Club::vote(Origin::signed(2), 3, false)); + assert_ok!(Club::vote(Origin::signed(3), 3, true)); + + assert_noop!(Club::cleanup_poll(Origin::signed(4), 3, 10), Error::::Ongoing); + Polls::set( + vec![(1, Completed(1, true)), (2, Completed(2, false)), (3, Completed(3, true))] + .into_iter() + .collect(), + ); + assert_ok!(Club::cleanup_poll(Origin::signed(4), 3, 10)); + // NOTE: This will fail until #10016 is merged. + // assert_noop!(Club::cleanup_poll(Origin::signed(4), 3, 10), Error::::NoneRemaining); + }); +} + +#[test] +fn ensure_ranked_works() { + new_test_ext().execute_with(|| { + assert_ok!(Club::add_member(Origin::root(), 1)); + assert_ok!(Club::promote_member(Origin::root(), 1)); + assert_ok!(Club::add_member(Origin::root(), 2)); + assert_ok!(Club::promote_member(Origin::root(), 2)); + assert_ok!(Club::promote_member(Origin::root(), 2)); + assert_ok!(Club::add_member(Origin::root(), 3)); + assert_ok!(Club::promote_member(Origin::root(), 3)); + assert_ok!(Club::promote_member(Origin::root(), 3)); + assert_ok!(Club::promote_member(Origin::root(), 3)); + + use frame_support::traits::OriginTrait; + type Rank1 = EnsureRanked; + type Rank2 = EnsureRanked; + type Rank3 = EnsureRanked; + type Rank4 = EnsureRanked; + assert_eq!(Rank1::try_origin(Origin::signed(1)).unwrap(), 1); + assert_eq!(Rank1::try_origin(Origin::signed(2)).unwrap(), 2); + assert_eq!(Rank1::try_origin(Origin::signed(3)).unwrap(), 3); + assert_eq!(Rank2::try_origin(Origin::signed(1)).unwrap_err().as_signed().unwrap(), 1); + assert_eq!(Rank2::try_origin(Origin::signed(2)).unwrap(), 2); + assert_eq!(Rank2::try_origin(Origin::signed(3)).unwrap(), 3); + assert_eq!(Rank3::try_origin(Origin::signed(1)).unwrap_err().as_signed().unwrap(), 1); + assert_eq!(Rank3::try_origin(Origin::signed(2)).unwrap_err().as_signed().unwrap(), 2); + assert_eq!(Rank3::try_origin(Origin::signed(3)).unwrap(), 3); + assert_eq!(Rank4::try_origin(Origin::signed(1)).unwrap_err().as_signed().unwrap(), 1); + assert_eq!(Rank4::try_origin(Origin::signed(2)).unwrap_err().as_signed().unwrap(), 2); + assert_eq!(Rank4::try_origin(Origin::signed(3)).unwrap_err().as_signed().unwrap(), 3); + }); +} diff --git a/frame/ranked-collective/src/weights.rs b/frame/ranked-collective/src/weights.rs new file mode 100644 index 0000000000000..3048dd804a5e2 --- /dev/null +++ b/frame/ranked-collective/src/weights.rs @@ -0,0 +1,187 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_ranked_collective +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-05-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// /Users/gav/Core/substrate/target/release/substrate +// benchmark +// pallet +// --pallet +// pallet-ranked-collective +// --extrinsic=* +// --chain=dev +// --steps=50 +// --repeat=20 +// --output=../../../frame/ranked-collective/src/weights.rs +// --template=../../../.maintain/frame-weight-template.hbs +// --header=../../../HEADER-APACHE2 +// --record-proof + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_ranked_collective. +pub trait WeightInfo { + fn add_member() -> Weight; + fn remove_member(r: u32, ) -> Weight; + fn promote_member(r: u32, ) -> Weight; + fn demote_member(r: u32, ) -> Weight; + fn vote() -> Weight; + fn cleanup_poll(n: u32, ) -> Weight; +} + +/// Weights for pallet_ranked_collective using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: RankedCollective Members (r:1 w:1) + // Storage: RankedCollective MemberCount (r:1 w:1) + // Storage: RankedCollective IndexToId (r:0 w:1) + // Storage: RankedCollective IdToIndex (r:0 w:1) + fn add_member() -> Weight { + (11_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: RankedCollective Members (r:1 w:1) + // Storage: RankedCollective MemberCount (r:1 w:1) + // Storage: RankedCollective IdToIndex (r:1 w:1) + // Storage: RankedCollective IndexToId (r:1 w:1) + fn remove_member(r: u32, ) -> Weight { + (16_855_000 as Weight) + // Standard Error: 27_000 + .saturating_add((8_107_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + } + // Storage: RankedCollective Members (r:1 w:1) + // Storage: RankedCollective MemberCount (r:1 w:1) + // Storage: RankedCollective IndexToId (r:0 w:1) + // Storage: RankedCollective IdToIndex (r:0 w:1) + fn promote_member(r: u32, ) -> Weight { + (11_936_000 as Weight) + // Standard Error: 3_000 + .saturating_add((9_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: RankedCollective Members (r:1 w:1) + // Storage: RankedCollective MemberCount (r:1 w:1) + // Storage: RankedCollective IdToIndex (r:1 w:1) + // Storage: RankedCollective IndexToId (r:1 w:1) + fn demote_member(r: u32, ) -> Weight { + (17_582_000 as Weight) + // Standard Error: 14_000 + .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: RankedCollective Members (r:1 w:0) + // Storage: RankedPolls ReferendumInfoFor (r:1 w:1) + // Storage: RankedCollective Voting (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn vote() -> Weight { + (22_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: RankedPolls ReferendumInfoFor (r:1 w:0) + // Storage: RankedCollective Voting (r:0 w:1) + fn cleanup_poll(n: u32, ) -> Weight { + (6_188_000 as Weight) + // Standard Error: 1_000 + .saturating_add((867_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(n as Weight))) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: RankedCollective Members (r:1 w:1) + // Storage: RankedCollective MemberCount (r:1 w:1) + // Storage: RankedCollective IndexToId (r:0 w:1) + // Storage: RankedCollective IdToIndex (r:0 w:1) + fn add_member() -> Weight { + (11_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: RankedCollective Members (r:1 w:1) + // Storage: RankedCollective MemberCount (r:1 w:1) + // Storage: RankedCollective IdToIndex (r:1 w:1) + // Storage: RankedCollective IndexToId (r:1 w:1) + fn remove_member(r: u32, ) -> Weight { + (16_855_000 as Weight) + // Standard Error: 27_000 + .saturating_add((8_107_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + } + // Storage: RankedCollective Members (r:1 w:1) + // Storage: RankedCollective MemberCount (r:1 w:1) + // Storage: RankedCollective IndexToId (r:0 w:1) + // Storage: RankedCollective IdToIndex (r:0 w:1) + fn promote_member(r: u32, ) -> Weight { + (11_936_000 as Weight) + // Standard Error: 3_000 + .saturating_add((9_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: RankedCollective Members (r:1 w:1) + // Storage: RankedCollective MemberCount (r:1 w:1) + // Storage: RankedCollective IdToIndex (r:1 w:1) + // Storage: RankedCollective IndexToId (r:1 w:1) + fn demote_member(r: u32, ) -> Weight { + (17_582_000 as Weight) + // Standard Error: 14_000 + .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: RankedCollective Members (r:1 w:0) + // Storage: RankedPolls ReferendumInfoFor (r:1 w:1) + // Storage: RankedCollective Voting (r:1 w:1) + // Storage: Scheduler Agenda (r:2 w:2) + fn vote() -> Weight { + (22_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: RankedPolls ReferendumInfoFor (r:1 w:0) + // Storage: RankedCollective Voting (r:0 w:1) + fn cleanup_poll(n: u32, ) -> Weight { + (6_188_000 as Weight) + // Standard Error: 1_000 + .saturating_add((867_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(n as Weight))) + } +} diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index e3f31bc411328..3fd54b54d331e 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -150,7 +150,7 @@ pub mod pallet { /// Handler for the unbalanced reduction when slashing a preimage deposit. type Slash: OnUnbalanced>; /// The counting type for votes. Usually just balance. - type Votes: AtLeast32BitUnsigned + Copy + Parameter + Member; + type Votes: AtLeast32BitUnsigned + Copy + Parameter + Member + MaxEncodedLen; /// The tallying type. type Tally: VoteTally> + Clone diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 27b3c6a5a9d59..3eba783246e10 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -136,7 +136,7 @@ pub struct TrackInfo { /// Information on the voting tracks. pub trait TracksInfo { /// The identifier for a track. - type Id: Copy + Parameter + Ord + PartialOrd + Send + Sync + 'static; + type Id: Copy + Parameter + Ord + PartialOrd + Send + Sync + 'static + MaxEncodedLen; /// The origin type from which a track is implied. type Origin; diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index 342a002b52b9d..d347818d65c38 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -186,9 +186,16 @@ pub fn expand_outer_origin( #system_path::RawOrigin::Root.into() } - fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self { + fn signed(by: Self::AccountId) -> Self { #system_path::RawOrigin::Signed(by).into() } + + fn as_signed(self) -> Option { + match self.caller { + OriginCaller::system(#system_path::RawOrigin::Signed(by)) => Some(by), + _ => None, + } + } } #[derive( diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 0a5092b411930..d399340f0470e 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -2748,6 +2748,9 @@ mod tests { fn signed(_by: ::AccountId) -> Self { unimplemented!("Not required in tests!") } + fn as_signed(self) -> Option { + unimplemented!("Not required in tests!") + } } impl system::Config for TraitImpl { diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index d3f9bfdd21d3b..f1f4330ab2960 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -286,6 +286,12 @@ impl> BoundedVec { Self::with_bounded_capacity(Self::bound()) } + /// Consume and truncate the vector `v` in order to create a new instance of `Self` from it. + pub fn truncate_from(mut v: Vec) -> Self { + v.truncate(Self::bound()); + Self::unchecked_from(v) + } + /// Get the bound of the type in `usize`. pub fn bound() -> usize { S::get() as usize diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 8b6f198b03f96..c878766643667 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -27,7 +27,7 @@ use crate::{ use codec::{Decode, Encode, EncodeLike, FullCodec, FullEncode}; use sp_core::storage::ChildInfo; use sp_runtime::generic::{Digest, DigestItem}; -use sp_std::prelude::*; +use sp_std::{marker::PhantomData, prelude::*}; pub use self::{ transactional::{ @@ -51,6 +51,10 @@ pub mod types; pub mod unhashed; pub mod weak_bounded_vec; +/// Utility type for converting a storage map into a `Get` impl which returns the maximum +/// key size. +pub struct KeyLenOf(PhantomData); + /// A trait for working with macro-generated storage values under the substrate storage API. /// /// Details on implementation can be found at [`generator::StorageValue`]. diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 5662087cc896f..bf957dc0ff928 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -22,7 +22,7 @@ use crate::{ metadata::{StorageEntryMetadata, StorageEntryType}, storage::{ types::{OptionQuery, QueryKindTrait, StorageEntryMetadataBuilder}, - StorageAppend, StorageDecodeLength, StoragePrefixedMap, StorageTryAppend, + KeyLenOf, StorageAppend, StorageDecodeLength, StoragePrefixedMap, StorageTryAppend, }, traits::{Get, GetDefault, StorageInfo, StorageInstance}, }; @@ -70,6 +70,35 @@ pub struct StorageDoubleMap< )>, ); +impl Get + for KeyLenOf< + StorageDoubleMap< + Prefix, + Hasher1, + Key1, + Hasher2, + Key2, + Value, + QueryKind, + OnEmpty, + MaxValues, + >, + > where + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: MaxEncodedLen, + Key2: MaxEncodedLen, +{ + fn get() -> u32 { + let z = Hasher1::max_len::() + + Hasher2::max_len::() + + Prefix::pallet_prefix().len() + + Prefix::STORAGE_PREFIX.len(); + z as u32 + } +} + impl crate::storage::generator::StorageDoubleMap for StorageDoubleMap diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 6dac5b3756598..1a5500e589d3a 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -22,7 +22,7 @@ use crate::{ metadata::{StorageEntryMetadata, StorageEntryType}, storage::{ types::{OptionQuery, QueryKindTrait, StorageEntryMetadataBuilder}, - StorageAppend, StorageDecodeLength, StoragePrefixedMap, StorageTryAppend, + KeyLenOf, StorageAppend, StorageDecodeLength, StoragePrefixedMap, StorageTryAppend, }, traits::{Get, GetDefault, StorageInfo, StorageInstance}, }; @@ -53,6 +53,20 @@ pub struct StorageMap< MaxValues = GetDefault, >(core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues)>); +impl Get + for KeyLenOf> +where + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec + MaxEncodedLen, +{ + fn get() -> u32 { + let z = + Hasher::max_len::() + Prefix::pallet_prefix().len() + Prefix::STORAGE_PREFIX.len(); + z as u32 + } +} + impl crate::storage::generator::StorageMap for StorageMap diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index d1872544e024d..fe983f5c292e3 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -97,7 +97,8 @@ mod dispatch; pub use dispatch::EnsureOneOf; pub use dispatch::{ AsEnsureOriginWithArg, DispatchableWithStorageLayer, EitherOf, EitherOfDiverse, EnsureOrigin, - EnsureOriginWithArg, NeverEnsureOrigin, OriginTrait, UnfilteredDispatchable, + EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, OriginTrait, ReduceBy, TryMapSuccess, + UnfilteredDispatchable, }; mod voting; diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index e06373348e499..720baf6c8a427 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -319,6 +319,9 @@ pub trait OriginTrait: Sized { /// Create with system signed origin and `frame_system::Config::BaseCallFilter`. fn signed(by: Self::AccountId) -> Self; + + /// Extract the signer from the message if it is a `Signed` origin. + fn as_signed(self) -> Option; } #[cfg(test)] diff --git a/frame/support/src/traits/voting.rs b/frame/support/src/traits/voting.rs index 6c802a6112246..7a3ff87e5940e 100644 --- a/frame/support/src/traits/voting.rs +++ b/frame/support/src/traits/voting.rs @@ -19,7 +19,7 @@ //! votes. use crate::dispatch::{DispatchError, Parameter}; -use codec::HasCompact; +use codec::{HasCompact, MaxEncodedLen}; use sp_arithmetic::{ traits::{SaturatedConversion, UniqueSaturatedFrom, UniqueSaturatedInto}, Perbill, @@ -123,9 +123,9 @@ impl PollStatus { } pub trait Polling { - type Index: Parameter + Member + Ord + PartialOrd + Copy + HasCompact; - type Votes: Parameter + Member + Ord + PartialOrd + Copy + HasCompact; - type Class: Parameter + Member + Ord + PartialOrd; + type Index: Parameter + Member + Ord + PartialOrd + Copy + HasCompact + MaxEncodedLen; + type Votes: Parameter + Member + Ord + PartialOrd + Copy + HasCompact + MaxEncodedLen; + type Class: Parameter + Member + Ord + PartialOrd + MaxEncodedLen; type Moment; /// Provides a vec of values that `T` may take. diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index aef061d952a96..97e060cb2a9bd 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -491,7 +491,10 @@ impl frame_support::traits::OriginTrait for Origin { fn root() -> Self { unimplemented!("Not required in tests!") } - fn signed(_by: ::AccountId) -> Self { + fn signed(_by: Self::AccountId) -> Self { + unimplemented!("Not required in tests!") + } + fn as_signed(self) -> Option { unimplemented!("Not required in tests!") } } From a3aa0e8f7bc8b10b981eb634f9e257f075e9aa15 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 1 Jun 2022 10:48:42 +0100 Subject: [PATCH 0871/1472] Introduce set function into storage maps (#11564) --- frame/support/src/storage/generator/double_map.rs | 7 +++++++ frame/support/src/storage/generator/map.rs | 7 +++++++ frame/support/src/storage/generator/nmap.rs | 7 +++++++ frame/support/src/storage/mod.rs | 9 +++++++++ frame/support/src/storage/types/counted_map.rs | 5 +++++ frame/support/src/storage/types/double_map.rs | 9 +++++++++ frame/support/src/storage/types/map.rs | 5 +++++ frame/support/src/storage/types/nmap.rs | 8 ++++++++ 8 files changed, 57 insertions(+) diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index 90ec92c622b1f..4ffe32651a9cc 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -151,6 +151,13 @@ where unhashed::get(&Self::storage_double_map_final_key(k1, k2)).ok_or(()) } + fn set, KArg2: EncodeLike>(k1: KArg1, k2: KArg2, q: Self::Query) { + match G::from_query_to_optional_value(q) { + Some(v) => Self::insert(k1, k2, v), + None => Self::remove(k1, k2), + } + } + fn take(k1: KArg1, k2: KArg2) -> Self::Query where KArg1: EncodeLike, diff --git a/frame/support/src/storage/generator/map.rs b/frame/support/src/storage/generator/map.rs index bd24e14e9e0d8..d190145ea4c00 100644 --- a/frame/support/src/storage/generator/map.rs +++ b/frame/support/src/storage/generator/map.rs @@ -245,6 +245,13 @@ impl> storage::StorageMap unhashed::get(Self::storage_map_final_key(key).as_ref()).ok_or(()) } + fn set>(key: KeyArg, q: Self::Query) { + match G::from_query_to_optional_value(q) { + Some(v) => Self::insert(key, v), + None => Self::remove(key), + } + } + fn insert, ValArg: EncodeLike>(key: KeyArg, val: ValArg) { unhashed::put(Self::storage_map_final_key(key).as_ref(), &val) } diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 0175d681df1d4..f1d0f9a5f0801 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -138,6 +138,13 @@ where unhashed::get(&Self::storage_n_map_final_key::(key)).ok_or(()) } + fn set + TupleToEncodedIter>(key: KArg, q: Self::Query) { + match G::from_query_to_optional_value(q) { + Some(v) => Self::insert(key, v), + None => Self::remove(key), + } + } + fn take + TupleToEncodedIter>(key: KArg) -> Self::Query { let final_key = Self::storage_n_map_final_key::(key); diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index c878766643667..6911da630cb34 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -167,6 +167,9 @@ pub trait StorageMap { /// Load the value associated with the given key from the map. fn get>(key: KeyArg) -> Self::Query; + /// Store or remove the value to be associated with `key` so that `get` returns the `query`. + fn set>(key: KeyArg, query: Self::Query); + /// Try to get the value for the given key from the map. /// /// Returns `Ok` if it exists, `Err` if not. @@ -481,6 +484,9 @@ pub trait StorageDoubleMap { KArg1: EncodeLike, KArg2: EncodeLike; + /// Store or remove the value to be associated with `key` so that `get` returns the `query`. + fn set, KArg2: EncodeLike>(k1: KArg1, k2: KArg2, query: Self::Query); + /// Take a value from storage, removing it afterwards. fn take(k1: KArg1, k2: KArg2) -> Self::Query where @@ -657,6 +663,9 @@ pub trait StorageNMap { /// Returns `Ok` if it exists, `Err` if not. fn try_get + TupleToEncodedIter>(key: KArg) -> Result; + /// Store or remove the value to be associated with `key` so that `get` returns the `query`. + fn set + TupleToEncodedIter>(key: KArg, query: Self::Query); + /// Swap the values of two keys. fn swap(key1: KArg1, key2: KArg2) where diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 44fcbf607935f..c4027acfe7232 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -132,6 +132,11 @@ where ::Map::try_get(key) } + /// Store or remove the value to be associated with `key` so that `get` returns the `query`. + pub fn set>(key: KeyArg, q: QueryKind::Query) { + ::Map::set(key, q) + } + /// Swap the values of two keys. pub fn swap, KeyArg2: EncodeLike>(key1: KeyArg1, key2: KeyArg2) { ::Map::swap(key1, key2) diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index bf957dc0ff928..2e090d30119aa 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -203,6 +203,15 @@ where >::try_get(k1, k2) } + /// Store or remove the value to be associated with `key` so that `get` returns the `query`. + pub fn set, KArg2: EncodeLike>( + k1: KArg1, + k2: KArg2, + q: QueryKind::Query, + ) { + >::set(k1, k2, q) + } + /// Take a value from storage, removing it afterwards. pub fn take(k1: KArg1, k2: KArg2) -> QueryKind::Query where diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 1a5500e589d3a..f4ac83c22663b 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -152,6 +152,11 @@ where >::swap(key1, key2) } + /// Store or remove the value to be associated with `key` so that `get` returns the `query`. + pub fn set>(key: KeyArg, q: QueryKind::Query) { + >::set(key, q) + } + /// Store a value to be associated with the given key from the map. pub fn insert, ValArg: EncodeLike>(key: KeyArg, val: ValArg) { >::insert(key, val) diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 1f303525b7476..dcbdac761fe15 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -142,6 +142,14 @@ where >::try_get(key) } + /// Store or remove the value to be associated with `key` so that `get` returns the `query`. + pub fn set + TupleToEncodedIter>( + key: KArg, + query: QueryKind::Query, + ) { + >::set(key, query) + } + /// Take a value from storage, removing it afterwards. pub fn take + TupleToEncodedIter>( key: KArg, From 9519124c4fe0f7b784114c500eeb04bd7d8f06c7 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 1 Jun 2022 11:46:06 +0100 Subject: [PATCH 0872/1472] Introduce `SubmitOrigin` to Referenda pallet config (#11567) --- bin/node/runtime/src/lib.rs | 2 ++ frame/referenda/src/lib.rs | 6 ++++-- frame/referenda/src/mock.rs | 1 + frame/referenda/src/tests.rs | 2 -- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index bfac30db6c66f..b421a4f05ed1a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -825,6 +825,7 @@ impl pallet_referenda::Config for Runtime { type Event = Event; type Scheduler = Scheduler; type Currency = pallet_balances::Pallet; + type SubmitOrigin = EnsureSigned; type CancelOrigin = EnsureRoot; type KillOrigin = EnsureRoot; type Slash = (); @@ -843,6 +844,7 @@ impl pallet_referenda::Config for Runtime { type Event = Event; type Scheduler = Scheduler; type Currency = pallet_balances::Pallet; + type SubmitOrigin = EnsureSigned; type CancelOrigin = EnsureRoot; type KillOrigin = EnsureRoot; type Slash = (); diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 3fd54b54d331e..f21a78bcb7863 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -143,6 +143,8 @@ pub mod pallet { /// Currency type for this pallet. type Currency: ReservableCurrency; // Origins and unbalances. + /// Origin from which proposals may be submitted. + type SubmitOrigin: EnsureOrigin; /// Origin from which any vote may be cancelled. type CancelOrigin: EnsureOrigin; /// Origin from which any vote may be killed. @@ -343,7 +345,7 @@ pub mod pallet { impl, I: 'static> Pallet { /// Propose a referendum on a privileged action. /// - /// - `origin`: must be `Signed` and the account must have `SubmissionDeposit` funds + /// - `origin`: must be `SubmitOrigin` and the account must have `SubmissionDeposit` funds /// available. /// - `proposal_origin`: The origin from which the proposal should be executed. /// - `proposal_hash`: The hash of the proposal preimage. @@ -357,7 +359,7 @@ pub mod pallet { proposal_hash: T::Hash, enactment_moment: DispatchTime, ) -> DispatchResult { - let who = ensure_signed(origin)?; + let who = T::SubmitOrigin::ensure_origin(origin)?; let track = T::Tracks::track_for(&proposal_origin).map_err(|_| Error::::NoTrack)?; diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index a3026ce78e986..8b06fb3205e6f 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -215,6 +215,7 @@ impl Config for Test { type Event = Event; type Scheduler = Scheduler; type Currency = pallet_balances::Pallet; + type SubmitOrigin = frame_system::EnsureSigned; type CancelOrigin = EnsureSignedBy; type KillOrigin = EnsureRoot; type Slash = (); diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index 8134e024dda39..db55fdb8c40cf 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -28,8 +28,6 @@ use frame_support::{ }; use pallet_balances::Error as BalancesError; -// TODO: Scheduler should re-use `None` items in its `Agenda`. - #[test] fn params_should_work() { new_test_ext().execute_with(|| { From 699375ef8dd0cb19f0b5d8917e4e2a02d50c92bf Mon Sep 17 00:00:00 2001 From: Vlad Date: Wed, 1 Jun 2022 14:28:24 +0300 Subject: [PATCH 0873/1472] Don't limit `test-linux-stable-int` job output (#11560) --- scripts/ci/gitlab/pipeline/test.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index eab673a5ce13c..419e9f0c7ead0 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -251,22 +251,10 @@ test-linux-stable-int: RUN_UI_TESTS: 1 script: - rusty-cachier snapshot create - - echo "___Logs will be partly shown at the end in case of failure.___" - - echo "___Full log will be saved to the job artifacts only in case of failure.___" - WASM_BUILD_NO_COLOR=1 RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace time cargo test -p node-cli --release --verbose --locked -- --ignored - &> ${CI_COMMIT_SHORT_SHA}_int_failure.log - rusty-cachier cache upload - after_script: - - !reference [.rusty-cachier, after_script] - - awk '/FAILED|^error\[/,0' ${CI_COMMIT_SHORT_SHA}_int_failure.log - artifacts: - name: $CI_COMMIT_SHORT_SHA - when: on_failure - expire_in: 3 days - paths: - - ${CI_COMMIT_SHORT_SHA}_int_failure.log check-tracing: stage: test From 1b3ddae9dec6e7653b5d6ef0179df1af831f46f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 1 Jun 2022 15:03:21 +0200 Subject: [PATCH 0874/1472] Fix all warnings when building for wasm (#11569) * Fix all warnings when building for wasm Besides that it also enables warnings as errors for wasm builds in the CI. * FMT * Make clippy happy --- frame/contracts/proc-macro/src/lib.rs | 6 ++++-- frame/nomination-pools/src/lib.rs | 4 ++-- frame/ranked-collective/src/lib.rs | 2 +- frame/try-runtime/src/lib.rs | 1 - primitives/block-builder/src/lib.rs | 9 ++++----- primitives/io/src/lib.rs | 6 +++--- primitives/state-machine/src/trie_backend_essence.rs | 5 ++--- primitives/version/src/lib.rs | 1 + scripts/ci/gitlab/pipeline/test.yml | 2 ++ 9 files changed, 19 insertions(+), 17 deletions(-) diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index 43b59debc4ad0..dca29c805cec4 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -24,7 +24,7 @@ extern crate alloc; use alloc::string::ToString; use proc_macro2::TokenStream; use quote::{quote, quote_spanned}; -use syn::{parse_macro_input, spanned::Spanned, Data, DataStruct, DeriveInput, Fields, Ident}; +use syn::{parse_macro_input, Data, DeriveInput, Ident}; /// This derives `Debug` for a struct where each field must be of some numeric type. /// It interprets each field as its represents some weight and formats it as times so that @@ -84,7 +84,9 @@ fn derive_debug( /// This is only used then the `full` feature is activated. #[cfg(feature = "full")] -fn iterate_fields(data: &DataStruct, fmt: impl Fn(&Ident) -> TokenStream) -> TokenStream { +fn iterate_fields(data: &syn::DataStruct, fmt: impl Fn(&Ident) -> TokenStream) -> TokenStream { + use syn::{spanned::Spanned, Fields}; + match &data.fields { Fields::Named(fields) => { let recurse = fields.named.iter().filter_map(|f| { diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index c9d811fa4a22f..fd8ae8ab76b08 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -316,7 +316,7 @@ use frame_support::{ Currency, Defensive, DefensiveOption, DefensiveResult, DefensiveSaturating, ExistenceRequirement, Get, }, - CloneNoBound, DefaultNoBound, PartialEqNoBound, RuntimeDebugNoBound, + CloneNoBound, DefaultNoBound, RuntimeDebugNoBound, }; use scale_info::TypeInfo; use sp_core::U256; @@ -398,7 +398,7 @@ enum AccountType { /// A member in a pool. #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound, CloneNoBound)] -#[cfg_attr(feature = "std", derive(PartialEqNoBound, DefaultNoBound))] +#[cfg_attr(feature = "std", derive(frame_support::PartialEqNoBound, DefaultNoBound))] #[codec(mel_bound(T: Config))] #[scale_info(skip_type_params(T))] pub struct PoolMember { diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 521dfb6aad4e3..61686f1efeb2f 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -444,7 +444,7 @@ pub mod pallet { MemberCount::::insert(rank, index.checked_add(1).ok_or(Overflow)?); IdToIndex::::insert(rank, &who, index); IndexToId::::insert(rank, index, &who); - Members::::insert(&who, MemberRecord { rank, ..record }); + Members::::insert(&who, MemberRecord { rank }); Self::deposit_event(Event::RankChanged { who, rank }); Ok(()) diff --git a/frame/try-runtime/src/lib.rs b/frame/try-runtime/src/lib.rs index bf08112bfc376..e4f01d40c9d42 100644 --- a/frame/try-runtime/src/lib.rs +++ b/frame/try-runtime/src/lib.rs @@ -20,7 +20,6 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::weights::Weight; -use sp_std::prelude::*; sp_api::decl_runtime_apis! { /// Runtime api for testing the execution of a runtime upgrade. diff --git a/primitives/block-builder/src/lib.rs b/primitives/block-builder/src/lib.rs index 1b74c27b7ae43..cf1bfa256084d 100644 --- a/primitives/block-builder/src/lib.rs +++ b/primitives/block-builder/src/lib.rs @@ -20,10 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_inherents::{CheckInherentsResult, InherentData}; -use sp_runtime::{ - legacy::byte_sized_error::ApplyExtrinsicResult as ApplyExtrinsicResultBeforeV6, - traits::Block as BlockT, ApplyExtrinsicResult, -}; +use sp_runtime::{traits::Block as BlockT, ApplyExtrinsicResult}; sp_api::decl_runtime_apis! { /// The `BlockBuilder` api trait that provides the required functionality for building a block. @@ -36,7 +33,9 @@ sp_api::decl_runtime_apis! { fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult; #[changed_in(6)] - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResultBeforeV6; + fn apply_extrinsic( + extrinsic: ::Extrinsic, + ) -> sp_runtime::legacy::byte_sized_error::ApplyExtrinsicResult; /// Finish the current block. #[renamed("finalise_block", 3)] diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 89b74dc3c6880..edffc37351147 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -1522,17 +1522,17 @@ mod tracing_setup { fn new_span(&self, attrs: &Attributes<'_>) -> Id { Id::from_u64(wasm_tracing::enter_span(Crossing(attrs.into()))) } - fn enter(&self, span: &Id) { + fn enter(&self, _: &Id) { // Do nothing, we already entered the span previously } /// Not implemented! We do not support recording values later /// Will panic when used. - fn record(&self, span: &Id, values: &Record<'_>) { + fn record(&self, _: &Id, _: &Record<'_>) { unimplemented! {} // this usage is not supported } /// Not implemented! We do not support recording values later /// Will panic when used. - fn record_follows_from(&self, span: &Id, follows: &Id) { + fn record_follows_from(&self, _: &Id, _: &Id) { unimplemented! {} // this usage is not supported } fn event(&self, event: &Event<'_>) { diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index c55a6b7e80481..7d910cc9602cc 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -29,8 +29,7 @@ use sp_trie::{ child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_value, read_trie_value, trie_types::{TrieDB, TrieError}, - DBValue, KeySpacedDB, LayoutV1 as Layout, PrefixedMemoryDB, Trie, TrieDBIterator, - TrieDBKeyIterator, + DBValue, KeySpacedDB, LayoutV1 as Layout, Trie, TrieDBIterator, TrieDBKeyIterator, }; #[cfg(feature = "std")] use std::collections::HashMap; @@ -619,7 +618,7 @@ pub trait TrieBackendStorage: Send + Sync { // This implementation is used by normal storage trie clients. #[cfg(feature = "std")] impl TrieBackendStorage for Arc> { - type Overlay = PrefixedMemoryDB; + type Overlay = sp_trie::PrefixedMemoryDB; fn get(&self, key: &H::Out, prefix: Prefix) -> Result> { Storage::::get(std::ops::Deref::deref(self), key, prefix) diff --git a/primitives/version/src/lib.rs b/primitives/version/src/lib.rs index 46f8af9e22c58..0bd62f0bac5aa 100644 --- a/primitives/version/src/lib.rs +++ b/primitives/version/src/lib.rs @@ -273,6 +273,7 @@ impl fmt::Display for RuntimeVersion { } } +#[cfg(feature = "std")] fn has_api_with bool>(apis: &ApisVec, id: &ApiId, predicate: P) -> bool { apis.iter().any(|(s, v)| s == id && predicate(*v)) } diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 419e9f0c7ead0..5d7572395d39c 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -205,6 +205,7 @@ test-linux-stable: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" RUST_BACKTRACE: 1 WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" # Ensure we run the UI tests. RUN_UI_TESTS: 1 script: @@ -247,6 +248,7 @@ test-linux-stable-int: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" RUST_BACKTRACE: 1 WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" # Ensure we run the UI tests. RUN_UI_TESTS: 1 script: From 06f8647b94de07eb9bc3fd75fe12220729e1bec4 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 1 Jun 2022 17:27:47 +0100 Subject: [PATCH 0875/1472] Helper macro for `Morph` impls (#11570) * Helper macro for Morph impls * No need to deprecate for now * Improved macro * Doc tests * Grumbles --- frame/ranked-collective/src/tests.rs | 4 +- frame/support/src/traits.rs | 2 +- frame/support/src/traits/dispatch.rs | 24 -- frame/support/src/traits/misc.rs | 72 +----- primitives/runtime/src/traits.rs | 369 ++++++++++++++++++++++++++- 5 files changed, 376 insertions(+), 95 deletions(-) diff --git a/frame/ranked-collective/src/tests.rs b/frame/ranked-collective/src/tests.rs index 1426012b63cea..4344a1be730fb 100644 --- a/frame/ranked-collective/src/tests.rs +++ b/frame/ranked-collective/src/tests.rs @@ -23,12 +23,12 @@ use frame_support::{ assert_noop, assert_ok, error::BadOrigin, parameter_types, - traits::{ConstU16, ConstU32, ConstU64, EitherOf, Everything, MapSuccess, Polling, ReduceBy}, + traits::{ConstU16, ConstU32, ConstU64, EitherOf, Everything, MapSuccess, Polling}, }; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, Identity, IdentityLookup}, + traits::{BlakeTwo256, Identity, IdentityLookup, ReduceBy}, }; use super::*; diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index fe983f5c292e3..53bdd219aa3ee 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -97,7 +97,7 @@ mod dispatch; pub use dispatch::EnsureOneOf; pub use dispatch::{ AsEnsureOriginWithArg, DispatchableWithStorageLayer, EitherOf, EitherOfDiverse, EnsureOrigin, - EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, OriginTrait, ReduceBy, TryMapSuccess, + EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess, UnfilteredDispatchable, }; diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 720baf6c8a427..9bfb0145009eb 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -18,15 +18,12 @@ //! Traits for dealing with dispatching calls and the origin from which they are dispatched. use crate::dispatch::{DispatchResultWithPostInfo, Parameter, RawOrigin}; -use sp_arithmetic::traits::{CheckedSub, Zero}; use sp_runtime::{ traits::{BadOrigin, Member, Morph, TryMorph}, Either, }; use sp_std::marker::PhantomData; -use super::TypedGet; - /// Some sort of check on the origin is performed by this object. pub trait EnsureOrigin { /// A return type. @@ -226,27 +223,6 @@ impl< } } -/// Mutator which reduces a scalar by a particular amount. -pub struct ReduceBy(PhantomData); -impl TryMorph for ReduceBy -where - N::Type: CheckedSub, -{ - type Outcome = N::Type; - fn try_morph(r: N::Type) -> Result { - r.checked_sub(&N::get()).ok_or(()) - } -} -impl Morph for ReduceBy -where - N::Type: CheckedSub + Zero, -{ - type Outcome = N::Type; - fn morph(r: N::Type) -> N::Type { - r.checked_sub(&N::get()).unwrap_or(Zero::zero()) - } -} - /// Type that can be dispatched with an origin but without checking the origin filter. /// /// Implemented for pallet dispatchable type by `decl_module` and for runtime dispatchable by diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index bea4e2a394411..ced6df8f971e8 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -21,6 +21,11 @@ use crate::dispatch::Parameter; use codec::{CompactLen, Decode, DecodeAll, Encode, EncodeLike, Input, MaxEncodedLen}; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; use sp_arithmetic::traits::{CheckedAdd, CheckedMul, CheckedSub, Saturating}; +#[doc(hidden)] +pub use sp_runtime::traits::{ + ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, ConstU32, + ConstU64, ConstU8, Get, GetDefault, TypedGet, +}; use sp_runtime::{traits::Block as BlockT, DispatchError}; use sp_std::{cmp::Ordering, prelude::*}; @@ -387,73 +392,6 @@ where } } -/// A trait for querying a single value from a type defined in the trait. -/// -/// It is not required that the value is constant. -pub trait TypedGet { - /// The type which is returned. - type Type; - /// Return the current value. - fn get() -> Self::Type; -} - -/// A trait for querying a single value from a type. -/// -/// It is not required that the value is constant. -pub trait Get { - /// Return the current value. - fn get() -> T; -} - -impl Get for () { - fn get() -> T { - T::default() - } -} - -/// Implement Get by returning Default for any type that implements Default. -pub struct GetDefault; -impl Get for GetDefault { - fn get() -> T { - T::default() - } -} - -macro_rules! impl_const_get { - ($name:ident, $t:ty) => { - #[derive($crate::RuntimeDebug)] - pub struct $name; - impl Get<$t> for $name { - fn get() -> $t { - T - } - } - impl Get> for $name { - fn get() -> Option<$t> { - Some(T) - } - } - impl TypedGet for $name { - type Type = $t; - fn get() -> $t { - T - } - } - }; -} - -impl_const_get!(ConstBool, bool); -impl_const_get!(ConstU8, u8); -impl_const_get!(ConstU16, u16); -impl_const_get!(ConstU32, u32); -impl_const_get!(ConstU64, u64); -impl_const_get!(ConstU128, u128); -impl_const_get!(ConstI8, i8); -impl_const_get!(ConstI16, i16); -impl_const_get!(ConstI32, i32); -impl_const_get!(ConstI64, i64); -impl_const_get!(ConstI128, i128); - /// A type for which some values make sense to be able to drop without further consideration. pub trait TryDrop: Sized { /// Drop an instance cleanly. Only works if its value represents "no-operation". diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index ee6a526e95e1e..aa5908526b819 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -37,7 +37,9 @@ pub use sp_arithmetic::traits::{ UniqueSaturatedFrom, UniqueSaturatedInto, Zero, }; use sp_core::{self, storage::StateVersion, Hasher, RuntimeDebug, TypeId}; -use sp_std::{self, fmt::Debug, marker::PhantomData, prelude::*}; +#[doc(hidden)] +pub use sp_std::marker::PhantomData; +use sp_std::{self, fmt::Debug, prelude::*}; #[cfg(feature = "std")] use std::fmt::Display; #[cfg(feature = "std")] @@ -274,6 +276,192 @@ where } } +/// A trait for querying a single value from a type defined in the trait. +/// +/// It is not required that the value is constant. +pub trait TypedGet { + /// The type which is returned. + type Type; + /// Return the current value. + fn get() -> Self::Type; +} + +/// A trait for querying a single value from a type. +/// +/// It is not required that the value is constant. +pub trait Get { + /// Return the current value. + fn get() -> T; +} + +impl Get for () { + fn get() -> T { + T::default() + } +} + +/// Implement Get by returning Default for any type that implements Default. +pub struct GetDefault; +impl Get for GetDefault { + fn get() -> T { + T::default() + } +} + +macro_rules! impl_const_get { + ($name:ident, $t:ty) => { + #[doc = "Const getter for a basic type."] + #[derive($crate::RuntimeDebug)] + pub struct $name; + impl Get<$t> for $name { + fn get() -> $t { + T + } + } + impl Get> for $name { + fn get() -> Option<$t> { + Some(T) + } + } + impl TypedGet for $name { + type Type = $t; + fn get() -> $t { + T + } + } + }; +} + +impl_const_get!(ConstBool, bool); +impl_const_get!(ConstU8, u8); +impl_const_get!(ConstU16, u16); +impl_const_get!(ConstU32, u32); +impl_const_get!(ConstU64, u64); +impl_const_get!(ConstU128, u128); +impl_const_get!(ConstI8, i8); +impl_const_get!(ConstI16, i16); +impl_const_get!(ConstI32, i32); +impl_const_get!(ConstI64, i64); +impl_const_get!(ConstI128, i128); + +/// Create new implementations of the [`Get`](crate::traits::Get) trait. +/// +/// The so-called parameter type can be created in four different ways: +/// +/// - Using `const` to create a parameter type that provides a `const` getter. It is required that +/// the `value` is const. +/// +/// - Declare the parameter type without `const` to have more freedom when creating the value. +/// +/// NOTE: A more substantial version of this macro is available in `frame_support` crate which +/// allows mutable and persistant variants. +/// +/// # Examples +/// +/// ``` +/// # use sp_runtime::traits::Get; +/// # use sp_runtime::parameter_types; +/// // This function cannot be used in a const context. +/// fn non_const_expression() -> u64 { 99 } +/// +/// const FIXED_VALUE: u64 = 10; +/// parameter_types! { +/// pub const Argument: u64 = 42 + FIXED_VALUE; +/// /// Visibility of the type is optional +/// OtherArgument: u64 = non_const_expression(); +/// } +/// +/// trait Config { +/// type Parameter: Get; +/// type OtherParameter: Get; +/// } +/// +/// struct Runtime; +/// impl Config for Runtime { +/// type Parameter = Argument; +/// type OtherParameter = OtherArgument; +/// } +/// ``` +/// +/// # Invalid example: +/// +/// ```compile_fail +/// # use sp_runtime::traits::Get; +/// # use sp_runtime::parameter_types; +/// // This function cannot be used in a const context. +/// fn non_const_expression() -> u64 { 99 } +/// +/// parameter_types! { +/// pub const Argument: u64 = non_const_expression(); +/// } +/// ``` +#[macro_export] +macro_rules! parameter_types { + ( + $( #[ $attr:meta ] )* + $vis:vis const $name:ident: $type:ty = $value:expr; + $( $rest:tt )* + ) => ( + $( #[ $attr ] )* + $vis struct $name; + $crate::parameter_types!(@IMPL_CONST $name , $type , $value); + $crate::parameter_types!( $( $rest )* ); + ); + ( + $( #[ $attr:meta ] )* + $vis:vis $name:ident: $type:ty = $value:expr; + $( $rest:tt )* + ) => ( + $( #[ $attr ] )* + $vis struct $name; + $crate::parameter_types!(@IMPL $name, $type, $value); + $crate::parameter_types!( $( $rest )* ); + ); + () => (); + (@IMPL_CONST $name:ident, $type:ty, $value:expr) => { + impl $name { + /// Returns the value of this parameter type. + pub const fn get() -> $type { + $value + } + } + + impl> $crate::traits::Get for $name { + fn get() -> I { + I::from(Self::get()) + } + } + + impl $crate::traits::TypedGet for $name { + type Type = $type; + fn get() -> $type { + Self::get() + } + } + }; + (@IMPL $name:ident, $type:ty, $value:expr) => { + impl $name { + /// Returns the value of this parameter type. + pub fn get() -> $type { + $value + } + } + + impl> $crate::traits::Get for $name { + fn get() -> I { + I::from(Self::get()) + } + } + + impl $crate::traits::TypedGet for $name { + type Type = $type; + fn get() -> $type { + Self::get() + } + } + }; +} + /// Extensible conversion trait. Generic over only source type, with destination type being /// associated. pub trait Morph { @@ -310,6 +498,185 @@ impl TryMorph for Identity { } } +/// Create a `Morph` and/or `TryMorph` impls with a simple closure-like expression. +/// +/// # Examples +/// +/// ``` +/// # use sp_runtime::{morph_types, traits::{Morph, TryMorph, TypedGet, ConstU32}}; +/// # use sp_arithmetic::traits::CheckedSub; +/// +/// morph_types! { +/// /// Replace by some other value; produce both `Morph` and `TryMorph` implementations +/// pub type Replace = |_| -> V::Type { V::get() }; +/// /// A private `Morph` implementation to reduce a `u32` by 10. +/// type ReduceU32ByTen: Morph = |r: u32| -> u32 { r - 10 }; +/// /// A `TryMorph` implementation to reduce a scalar by a particular amount, checking for +/// /// underflow. +/// pub type CheckedReduceBy: TryMorph = |r: N::Type| -> Result { +/// r.checked_sub(&N::get()).ok_or(()) +/// } where N::Type: CheckedSub; +/// } +/// +/// trait Config { +/// type TestMorph1: Morph; +/// type TestTryMorph1: TryMorph; +/// type TestMorph2: Morph; +/// type TestTryMorph2: TryMorph; +/// } +/// +/// struct Runtime; +/// impl Config for Runtime { +/// type TestMorph1 = Replace>; +/// type TestTryMorph1 = Replace>; +/// type TestMorph2 = ReduceU32ByTen; +/// type TestTryMorph2 = CheckedReduceBy>; +/// } +/// ``` +#[macro_export] +macro_rules! morph_types { + ( + @DECL $( #[doc = $doc:expr] )* $vq:vis $name:ident () + ) => { + $( #[doc = $doc] )* $vq struct $name; + }; + ( + @DECL $( #[doc = $doc:expr] )* $vq:vis $name:ident ( $( $bound_id:ident ),+ ) + ) => { + $( #[doc = $doc] )* + $vq struct $name < $($bound_id,)* > ( $crate::traits::PhantomData< ( $($bound_id,)* ) > ) ; + }; + ( + @IMPL $name:ty : ( $( $bounds:tt )* ) ( $( $where:tt )* ) + = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* } + ) => { + impl<$($bounds)*> $crate::traits::Morph<$var_type> for $name $( $where )? { + type Outcome = $outcome; + fn morph($var: $var_type) -> Self::Outcome { $( $ex )* } + } + }; + ( + @IMPL_TRY $name:ty : ( $( $bounds:tt )* ) ( $( $where:tt )* ) + = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* } + ) => { + impl<$($bounds)*> $crate::traits::TryMorph<$var_type> for $name $( $where )? { + type Outcome = $outcome; + fn try_morph($var: $var_type) -> Result { $( $ex )* } + } + }; + ( + @IMPL $name:ty : () ( $( $where:tt )* ) + = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* } + ) => { + impl $crate::traits::Morph<$var_type> for $name $( $where )? { + type Outcome = $outcome; + fn morph($var: $var_type) -> Self::Outcome { $( $ex )* } + } + }; + ( + @IMPL_TRY $name:ty : () ( $( $where:tt )* ) + = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* } + ) => { + impl $crate::traits::TryMorph<$var_type> for $name $( $where )? { + type Outcome = $outcome; + fn try_morph($var: $var_type) -> Result { $( $ex )* } + } + }; + ( + @IMPL_BOTH $name:ty : ( $( $bounds:tt )* ) ( $( $where:tt )* ) + = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* } + ) => { + morph_types! { + @IMPL $name : ($($bounds)*) ($($where)*) + = |$var: $var_type| -> $outcome { $( $ex )* } + } + morph_types! { + @IMPL_TRY $name : ($($bounds)*) ($($where)*) + = |$var: $var_type| -> $outcome { Ok({$( $ex )*}) } + } + }; + + ( + $( #[doc = $doc:expr] )* $vq:vis type $name:ident + $( < $( $bound_id:ident $( : $bound_head:path $( | $bound_tail:path )* )? ),+ > )? + $(: $type:tt)? + = |_| -> $outcome:ty { $( $ex:expr )* }; + $( $rest:tt )* + ) => { + morph_types! { + $( #[doc = $doc] )* $vq type $name + $( < $( $bound_id $( : $bound_head $( | $bound_tail )* )? ),+ > )? + EXTRA_GENERIC(X) + $(: $type)? + = |_x: X| -> $outcome { $( $ex )* }; + $( $rest )* + } + }; + ( + $( #[doc = $doc:expr] )* $vq:vis type $name:ident + $( < $( $bound_id:ident $( : $bound_head:path $( | $bound_tail:path )* )? ),+ > )? + $( EXTRA_GENERIC ($extra:ident) )? + = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* } + $( where $( $where_path:ty : $where_bound_head:path $( | $where_bound_tail:path )* ),* )?; + $( $rest:tt )* + ) => { + morph_types! { @DECL $( #[doc = $doc] )* $vq $name ( $( $( $bound_id ),+ )? ) } + morph_types! { + @IMPL_BOTH $name $( < $( $bound_id ),* > )? : + ( $( $( $bound_id $( : $bound_head $( + $bound_tail )* )? , )+ )? $( $extra )? ) + ( $( where $( $where_path : $where_bound_head $( + $where_bound_tail )* ),* )? ) + = |$var: $var_type| -> $outcome { $( $ex )* } + } + morph_types!{ $($rest)* } + }; + ( + $( #[doc = $doc:expr] )* $vq:vis type $name:ident + $( < $( $bound_id:ident $( : $bound_head:path $( | $bound_tail:path )* )? ),+ > )? + $( EXTRA_GENERIC ($extra:ident) )? + : Morph + = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* } + $( where $( $where_path:ty : $where_bound_head:path $( | $where_bound_tail:path )* ),* )?; + $( $rest:tt )* + ) => { + morph_types! { @DECL $( #[doc = $doc] )* $vq $name ( $( $( $bound_id ),+ )? ) } + morph_types! { + @IMPL $name $( < $( $bound_id ),* > )? : + ( $( $( $bound_id $( : $bound_head $( + $bound_tail )* )? , )+ )? $( $extra )? ) + ( $( where $( $where_path : $where_bound_head $( + $where_bound_tail )* ),* )? ) + = |$var: $var_type| -> $outcome { $( $ex )* } + } + morph_types!{ $($rest)* } + }; + ( + $( #[doc = $doc:expr] )* $vq:vis type $name:ident + $( < $( $bound_id:ident $( : $bound_head:path $( | $bound_tail:path )* )? ),+ > )? + $( EXTRA_GENERIC ($extra:ident) )? + : TryMorph + = |$var:ident: $var_type:ty| -> Result<$outcome:ty, ()> { $( $ex:expr )* } + $( where $( $where_path:ty : $where_bound_head:path $( | $where_bound_tail:path )* ),* )?; + $( $rest:tt )* + ) => { + morph_types! { @DECL $( #[doc = $doc] )* $vq $name ( $( $( $bound_id ),+ )? ) } + morph_types! { + @IMPL_TRY $name $( < $( $bound_id ),* > )? : + ( $( $( $bound_id $( : $bound_head $( + $bound_tail )* )? , )+ )? $( $extra )? ) + ( $( where $( $where_path : $where_bound_head $( + $where_bound_tail )* ),* )? ) + = |$var: $var_type| -> $outcome { $( $ex )* } + } + morph_types!{ $($rest)* } + }; + () => {} +} + +morph_types! { + /// Morpher to disregard the source value and replace with another. + pub type Replace = |_| -> V::Type { V::get() }; + /// Mutator which reduces a scalar by a particular amount. + pub type ReduceBy = |r: N::Type| -> N::Type { + r.checked_sub(&N::get()).unwrap_or(Zero::zero()) + } where N::Type: CheckedSub | Zero; +} + /// Extensible conversion trait. Generic over both source and destination types. pub trait Convert { /// Make conversion. From 3e04ae78cbb37ad9e607ded6c45e7724a3f00376 Mon Sep 17 00:00:00 2001 From: Vlad Date: Wed, 1 Jun 2022 19:48:53 +0300 Subject: [PATCH 0876/1472] `rusty-cachier` pipeline impovements and fixes (#11572) --- .gitlab-ci.yml | 5 ++--- scripts/ci/gitlab/pipeline/build.yml | 16 ++++++++++++---- scripts/ci/gitlab/pipeline/test.yml | 10 +++++++--- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e218a2c1f8d3a..b4933333b3418 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -108,7 +108,7 @@ default: - $(rusty-cachier environment inject) - rusty-cachier project mtime after_script: - - rusty-cachier snapshot destroy + - env RUSTY_CACHIER_SUPRESS_OUTPUT=true rusty-cachier snapshot destroy .test-refs: rules: @@ -225,8 +225,7 @@ deploy-prometheus-alerting-rules: # This info is later used for the cache distribution and an overlay creation. rusty-cachier-notify: stage: notify - extends: - - .docker-env + extends: .docker-env script: - rusty-cachier cache notify diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index a07fe8a4cfa07..47d8b2bc4c525 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -50,6 +50,9 @@ build-linux-substrate: - .collect-artifacts - .docker-env - .build-refs + variables: + # this variable gets overriden by "rusty-cachier environment inject", use the value as default + CARGO_TARGET_DIR: "./target" needs: - job: test-linux-stable artifacts: false @@ -59,7 +62,7 @@ build-linux-substrate: script: - rusty-cachier snapshot create - WASM_BUILD_NO_COLOR=1 time cargo build --release --verbose - - mv /cargo_target_dir/release/substrate ./artifacts/substrate/. + - mv $CARGO_TARGET_DIR/release/substrate ./artifacts/substrate/. - echo -n "Substrate version = " - if [ "${CI_COMMIT_TAG}" ]; then echo "${CI_COMMIT_TAG}" | tee ./artifacts/substrate/VERSION; @@ -79,6 +82,9 @@ build-linux-substrate: - .collect-artifacts - .docker-env - .build-refs + variables: + # this variable gets overriden by "rusty-cachier environment inject", use the value as default + CARGO_TARGET_DIR: "./target" needs: - job: cargo-check-subkey artifacts: false @@ -90,7 +96,7 @@ build-linux-substrate: - cd ./bin/utils/subkey - SKIP_WASM_BUILD=1 time cargo build --release --verbose - cd - - - mv /cargo_target_dir/release/subkey ./artifacts/subkey/. + - mv $CARGO_TARGET_DIR/release/subkey ./artifacts/subkey/. - echo -n "Subkey version = " - ./artifacts/subkey/subkey --version | sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | @@ -131,6 +137,8 @@ build-rustdoc: SKIP_WASM_BUILD: 1 DOC_INDEX_PAGE: "sc_service/index.html" # default redirected page RUSTY_CACHIER_TOOLCHAIN: nightly + # this variable gets overriden by "rusty-cachier environment inject", use the value as default + CARGO_TARGET_DIR: "./target" artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" when: on_success @@ -140,8 +148,8 @@ build-rustdoc: script: - rusty-cachier snapshot create - time cargo +nightly doc --workspace --all-features --verbose - - rm -f /cargo_target_dir/doc/.lock - - mv /cargo_target_dir/doc ./crate-docs + - rm -f $CARGO_TARGET_DIR/doc/.lock + - mv $CARGO_TARGET_DIR/doc ./crate-docs # FIXME: remove me after CI image gets nonroot - chown -R nonroot:nonroot ./crate-docs - echo "" > ./crate-docs/index.html diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 5d7572395d39c..36f920ba275bd 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -180,18 +180,22 @@ test-deterministic-wasm: - .test-refs variables: WASM_BUILD_NO_COLOR: 1 + # this variable gets overriden by "rusty-cachier environment inject", use the value as default + CARGO_TARGET_DIR: "./target" script: - rusty-cachier snapshot create # build runtime - cargo build --verbose --release -p node-runtime # make checksum - - sha256sum /cargo_target_dir/release/wbuild/node-runtime/target/wasm32-unknown-unknown/release/node_runtime.wasm > checksum.sha256 - # clean up – FIXME: can we reuse some of the artifacts? - - cargo clean + - sha256sum $CARGO_TARGET_DIR/release/wbuild/node-runtime/target/wasm32-unknown-unknown/release/node_runtime.wasm > checksum.sha256 + # clean up + - rm -rf $CARGO_TARGET_DIR/release/wbuild # build again - cargo build --verbose --release -p node-runtime # confirm checksum - sha256sum -c ./checksum.sha256 + # clean up again, don't put release binaries into the cache + - rm -rf $CARGO_TARGET_DIR/release/wbuild - rusty-cachier cache upload test-linux-stable: From 97f9aac7b9c222967a952579da429777af418977 Mon Sep 17 00:00:00 2001 From: Vlad Date: Thu, 2 Jun 2022 11:48:12 +0300 Subject: [PATCH 0877/1472] CI: fix `build-subkey-macos` build job (#11573) * CI: fix `build-subkey-macos` build job * CI: use full path for the `CARGO_TARGET_DIR` default value --- scripts/ci/gitlab/pipeline/build.yml | 7 ++++--- scripts/ci/gitlab/pipeline/test.yml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 47d8b2bc4c525..e6269c4e3949a 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -52,7 +52,7 @@ build-linux-substrate: - .build-refs variables: # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "./target" + CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" needs: - job: test-linux-stable artifacts: false @@ -84,7 +84,7 @@ build-linux-substrate: - .build-refs variables: # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "./target" + CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" needs: - job: cargo-check-subkey artifacts: false @@ -125,6 +125,7 @@ build-subkey-macos: tee ./artifacts/subkey/VERSION; - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ + after_script: [""] tags: - osx @@ -138,7 +139,7 @@ build-rustdoc: DOC_INDEX_PAGE: "sc_service/index.html" # default redirected page RUSTY_CACHIER_TOOLCHAIN: nightly # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "./target" + CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" when: on_success diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 36f920ba275bd..8ec16ab6839a5 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -181,7 +181,7 @@ test-deterministic-wasm: variables: WASM_BUILD_NO_COLOR: 1 # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "./target" + CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" script: - rusty-cachier snapshot create # build runtime From 86b1176d3ba2bd49b87e99e1b074bc0279849021 Mon Sep 17 00:00:00 2001 From: yjh Date: Thu, 2 Jun 2022 17:03:49 +0800 Subject: [PATCH 0878/1472] aura: export change_authorities and initialize_authorities (#11468) * aura: export change_authorities and initialize_authorities * add docs * fix docs --- frame/aura/src/lib.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 222360dc3a7d3..fd6882ca9f29f 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -146,7 +146,11 @@ pub mod pallet { } impl Pallet { - fn change_authorities(new: WeakBoundedVec) { + /// Change authorities. + /// + /// The storage will be applied immediately. + /// And aura consensus log will be appended to block's log. + pub fn change_authorities(new: WeakBoundedVec) { >::put(&new); let log = DigestItem::Consensus( @@ -156,7 +160,12 @@ impl Pallet { >::deposit_log(log); } - fn initialize_authorities(authorities: &[T::AuthorityId]) { + /// Initial authorities. + /// + /// The storage will be applied immediately. + /// + /// The authorities length must be equal or less than T::MaxAuthorities. + pub fn initialize_authorities(authorities: &[T::AuthorityId]) { if !authorities.is_empty() { assert!(>::get().is_empty(), "Authorities are already initialized!"); let bounded = >::try_from(authorities) From a75762d70c0f16190bb4eac51445212d1dedc269 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 2 Jun 2022 12:41:05 +0100 Subject: [PATCH 0879/1472] Reduce call size of Referenda pallet (#11578) * Reduce call size of Referenda pallet * Fixes * Fixes * Fixes * Docs --- frame/referenda/src/benchmarking.rs | 4 +-- frame/referenda/src/lib.rs | 4 +-- frame/referenda/src/mock.rs | 4 +-- frame/referenda/src/tests.rs | 33 +++++++++-------- .../src/construct_runtime/expand/call.rs | 36 +++++++++++++++++++ 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index e4cbf2ca52e7c..9abd3768f780c 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -46,7 +46,7 @@ fn create_referendum() -> (T::AccountId, ReferendumIndex) { whitelist_account!(caller); assert_ok!(Referenda::::submit( RawOrigin::Signed(caller.clone()).into(), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), T::Hashing::hash_of(&0), DispatchTime::After(0u32.into()) )); @@ -177,7 +177,7 @@ benchmarks! { whitelist_account!(caller); }: _( RawOrigin::Signed(caller), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), T::Hashing::hash_of(&0), DispatchTime::After(0u32.into()) ) verify { diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index f21a78bcb7863..ab8c3ad0efa6a 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -355,7 +355,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::submit())] pub fn submit( origin: OriginFor, - proposal_origin: PalletsOriginOf, + proposal_origin: Box>, proposal_hash: T::Hash, enactment_moment: DispatchTime, ) -> DispatchResult { @@ -373,7 +373,7 @@ pub mod pallet { let nudge_call = Call::nudge_referendum { index }; let status = ReferendumStatus { track, - origin: proposal_origin, + origin: *proposal_origin, proposal_hash, enactment: enactment_moment, submitted: now, diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 8b06fb3205e6f..1a24911603990 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -310,7 +310,7 @@ pub fn set_balance_proposal_hash(value: u64) -> H256 { pub fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult { Referenda::submit( Origin::signed(who), - frame_system::RawOrigin::Root.into(), + Box::new(frame_system::RawOrigin::Root.into()), set_balance_proposal_hash(value), DispatchTime::After(delay), ) @@ -438,7 +438,7 @@ impl RefState { pub fn create(self) -> ReferendumIndex { assert_ok!(Referenda::submit( Origin::signed(1), - frame_support::dispatch::RawOrigin::Root.into(), + Box::new(frame_support::dispatch::RawOrigin::Root.into()), set_balance_proposal_hash(1), DispatchTime::At(10), )); diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index db55fdb8c40cf..d5435daf185bd 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -43,7 +43,7 @@ fn basic_happy_path_works() { // #1: submit assert_ok!(Referenda::submit( Origin::signed(1), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), set_balance_proposal_hash(1), DispatchTime::At(10), )); @@ -174,7 +174,7 @@ fn queueing_works() { // Submit a proposal into a track with a queue len of 1. assert_ok!(Referenda::submit( Origin::signed(5), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), set_balance_proposal_hash(0), DispatchTime::After(0), )); @@ -186,7 +186,7 @@ fn queueing_works() { for i in 1..=4 { assert_ok!(Referenda::submit( Origin::signed(i), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), set_balance_proposal_hash(i), DispatchTime::After(0), )); @@ -271,7 +271,7 @@ fn auto_timeout_should_happen_with_nothing_but_submit() { // #1: submit assert_ok!(Referenda::submit( Origin::signed(1), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), set_balance_proposal_hash(1), DispatchTime::At(20), )); @@ -291,13 +291,13 @@ fn tracks_are_distinguished() { new_test_ext().execute_with(|| { assert_ok!(Referenda::submit( Origin::signed(1), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), set_balance_proposal_hash(1), DispatchTime::At(10), )); assert_ok!(Referenda::submit( Origin::signed(2), - RawOrigin::None.into(), + Box::new(RawOrigin::None.into()), set_balance_proposal_hash(2), DispatchTime::At(20), )); @@ -355,7 +355,7 @@ fn submit_errors_work() { assert_noop!( Referenda::submit( Origin::signed(1), - RawOrigin::Signed(2).into(), + Box::new(RawOrigin::Signed(2).into()), h, DispatchTime::At(10), ), @@ -364,7 +364,12 @@ fn submit_errors_work() { // No funds for deposit assert_noop!( - Referenda::submit(Origin::signed(10), RawOrigin::Root.into(), h, DispatchTime::At(10),), + Referenda::submit( + Origin::signed(10), + Box::new(RawOrigin::Root.into()), + h, + DispatchTime::At(10), + ), BalancesError::::InsufficientBalance ); }); @@ -379,7 +384,7 @@ fn decision_deposit_errors_work() { let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( Origin::signed(1), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); @@ -401,7 +406,7 @@ fn refund_deposit_works() { let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( Origin::signed(1), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); @@ -423,7 +428,7 @@ fn cancel_works() { let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( Origin::signed(1), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); @@ -442,7 +447,7 @@ fn cancel_errors_works() { let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( Origin::signed(1), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); @@ -460,7 +465,7 @@ fn kill_works() { let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( Origin::signed(1), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); @@ -480,7 +485,7 @@ fn kill_errors_works() { let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( Origin::signed(1), - RawOrigin::Root.into(), + Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index ad52ca48f68c9..c8c5d5ff0ee43 100644 --- a/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -62,6 +62,42 @@ pub fn expand_outer_dispatch( pub enum Call { #variant_defs } + #[cfg(test)] + impl Call { + /// Return a list of the module names together with their size in memory. + pub const fn sizes() -> &'static [( &'static str, usize )] { + use #scrate::dispatch::Callable; + use core::mem::size_of; + &[#( + ( + stringify!(#pallet_names), + size_of::< <#pallet_names as Callable<#runtime>>::Call >(), + ), + )*] + } + + /// Panics with diagnostic information if the size is greater than the given `limit`. + pub fn assert_size_under(limit: usize) { + let size = core::mem::size_of::(); + let call_oversize = size > limit; + if call_oversize { + println!("Size of `Call` is {} bytes (provided limit is {} bytes)", size, limit); + let mut sizes = Self::sizes().to_vec(); + sizes.sort_by_key(|x| -(x.1 as isize)); + for (i, &(name, size)) in sizes.iter().enumerate().take(5) { + println!("Offender #{}: {} at {} bytes", i + 1, name, size); + } + if let Some((_, next_size)) = sizes.get(5) { + println!("{} others of size {} bytes or less", sizes.len() - 5, next_size); + } + panic!( + "Size of `Call` is more than limit; use `Box` on complex parameter types to reduce the + size of `Call`. + If the limit is too strong, maybe consider providing a higher limit." + ); + } + } + } impl #scrate::dispatch::GetDispatchInfo for Call { fn get_dispatch_info(&self) -> #scrate::dispatch::DispatchInfo { match self { From bb71eab8b067b274f41e3a7190d3adb9023eda28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Thu, 2 Jun 2022 11:15:32 -0300 Subject: [PATCH 0880/1472] reactivate check-dependent-cumulus (#11506) * re-enable check-dependent-cumulus * temporary: use handle-extra-dependencies * temporary: trim CI * CI: include build stage * CI: include test stage * CI: include test stage * Revert "temporary: trim CI" This reverts commit dcf4ae8d842bc445a065c7ccdc3b6a603034faa4. * CI: fix weird revert * Revert "temporary: use handle-extra-dependencies" This reverts commit bc0dc0f21f10284a23f66fdd8509ca6df89f2586. * CI undebug Co-authored-by: TriplEight --- scripts/ci/gitlab/pipeline/build.yml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index e6269c4e3949a..da6391fb7c278 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -11,7 +11,7 @@ script: - git clone --depth=1 - "--branch=$PIPELINE_SCRIPTS_TAG" + --branch="$PIPELINE_SCRIPTS_TAG" https://github.com/paritytech/pipeline-scripts - ./pipeline-scripts/check_dependent_project.sh --org paritytech @@ -34,15 +34,14 @@ check-dependent-polkadot: rules: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ #PRs -# TODO: Re-enable after https://github.com/paritytech/pipeline-scripts/issues/44 -#check-dependent-cumulus: -# extends: .check-dependent-project -# variables: -# DEPENDENT_REPO: cumulus -# EXTRA_DEPENDENCIES: polkadot -# COMPANION_OVERRIDES: | -# substrate: polkadot-v* -# polkadot: release-v* +check-dependent-cumulus: + extends: .check-dependent-project + variables: + DEPENDENT_REPO: cumulus + EXTRA_DEPENDENCIES: polkadot + COMPANION_OVERRIDES: | + substrate: polkadot-v* + polkadot: release-v* build-linux-substrate: stage: build From 3c18d3765fe6e6a470be43e7829a2cf8f5c4eb0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 2 Jun 2022 18:48:48 +0200 Subject: [PATCH 0881/1472] wasm-builder: Rerun the build if the generated file changed (#11582) --- utils/wasm-builder/src/wasm_project.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 005b428a3ccac..4316f9041f11d 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -51,6 +51,11 @@ impl WasmBinaryBloaty { pub fn wasm_binary_bloaty_path_escaped(&self) -> String { self.0.display().to_string().escape_default().to_string() } + + /// Returns the path to the wasm binary. + pub fn wasm_binary_bloaty_path(&self) -> &Path { + &self.0 + } } /// Holds the path to the WASM binary. @@ -137,9 +142,17 @@ pub(crate) fn create_and_compile( copy_wasm_to_target_directory(project_cargo_toml, wasm_binary_compressed) }); - generate_rerun_if_changed_instructions(project_cargo_toml, &project, &wasm_workspace); + let final_wasm_binary = wasm_binary_compressed.or(wasm_binary); - (wasm_binary_compressed.or(wasm_binary), bloaty) + generate_rerun_if_changed_instructions( + project_cargo_toml, + &project, + &wasm_workspace, + final_wasm_binary.as_ref(), + &bloaty, + ); + + (final_wasm_binary, bloaty) } /// Find the `Cargo.lock` relative to the `OUT_DIR` environment variable. @@ -712,6 +725,8 @@ fn generate_rerun_if_changed_instructions( cargo_manifest: &Path, project_folder: &Path, wasm_workspace: &Path, + compressed_or_compact_wasm: Option<&WasmBinary>, + bloaty_wasm: &WasmBinaryBloaty, ) { // Rerun `build.rs` if the `Cargo.lock` changes if let Some(cargo_lock) = find_cargo_lock(cargo_manifest) { @@ -761,6 +776,9 @@ fn generate_rerun_if_changed_instructions( // Make sure that if any file/folder of a dependency change, we need to rerun the `build.rs` packages.iter().for_each(package_rerun_if_changed); + compressed_or_compact_wasm.map(|w| rerun_if_changed(w.wasm_binary_path())); + rerun_if_changed(bloaty_wasm.wasm_binary_bloaty_path()); + // Register our env variables println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV); println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TYPE_ENV); From 4132d047550178d194f3cd6b63933ccdb35c94e1 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 2 Jun 2022 21:18:59 +0200 Subject: [PATCH 0882/1472] [ci] use cargo nextest instead cargo test in test-linux-stable (#11576) * [DO NOT MERGE] Experimenting with nextest * enable jobs * enable stages * add comment * create test-frame-support job --- scripts/ci/gitlab/pipeline/test.yml | 48 ++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 8ec16ab6839a5..b2348c48355d0 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -214,12 +214,58 @@ test-linux-stable: RUN_UI_TESTS: 1 script: - rusty-cachier snapshot create + # TODO: add to paritytech/ci-linux image + - time cargo install cargo-nextest # this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests - - time cargo test --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml + # node-cli is excluded until https://github.com/paritytech/substrate/issues/11321 fixed + - time cargo nextest run --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml --exclude node-cli + - rusty-cachier cache upload + +test-frame-support: + stage: test + extends: + - .docker-env + - .test-refs + variables: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUST_BACKTRACE: 1 + WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + # Ensure we run the UI tests. + RUN_UI_TESTS: 1 + script: + - rusty-cachier snapshot create - time cargo test -p frame-support-test --features=conditional-storage,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout - rusty-cachier cache upload +# This job runs tests that don't work with cargo-nextest in test-linux-stable +test-linux-stable-extra: + stage: test + extends: + - .docker-env + - .test-refs + variables: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUST_BACKTRACE: 1 + WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + # Ensure we run the UI tests. + RUN_UI_TESTS: 1 + script: + - rusty-cachier snapshot create + # Run node-cli tests + # TODO: add to test-linux-stable-nextest after fix https://github.com/paritytech/substrate/issues/11321 + - time cargo test node-cli --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml + # Run doctests + # TODO: add to test-linux-stable-nextest after fix https://github.com/nextest-rs/nextest/issues/16 + - time cargo test --doc --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml + - rusty-cachier cache upload + test-frame-examples-compile-to-wasm: # into one job stage: test From 5f0aa1feb7250ac7b8c1b9928f87b2420b530e22 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 3 Jun 2022 20:33:59 +0800 Subject: [PATCH 0883/1472] Expose ValidatedTransaction from transaction pool (#11588) This is required to make a tx pool wrapper for some custom transaction validation, specificially required to make a wrapper around the `LocalTransactionPool` implementation (https://github.com/subspace/subspace/blob/f54881a9b5/crates/subspace-service/src/pool.rs#L232-L269). Related: https://github.com/paritytech/substrate/discussions/11520 --- client/transaction-pool/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index eb36d46538c1a..7b9ce9d6047c0 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -36,7 +36,9 @@ use futures::{ future::{self, ready}, prelude::*, }; -pub use graph::{base_pool::Limit as PoolLimit, ChainApi, Options, Pool, Transaction}; +pub use graph::{ + base_pool::Limit as PoolLimit, ChainApi, Options, Pool, Transaction, ValidatedTransaction, +}; use parking_lot::Mutex; use std::{ collections::{HashMap, HashSet}, @@ -407,7 +409,6 @@ where at: &BlockId, xt: sc_transaction_pool_api::LocalTransactionFor, ) -> Result { - use graph::ValidatedTransaction; use sp_runtime::{ traits::SaturatedConversion, transaction_validity::TransactionValidityError, }; From 227436365e2a75d6e0ab609c29acd737da21170b Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Fri, 3 Jun 2022 16:25:55 +0200 Subject: [PATCH 0884/1472] Tracable defensive errors (#11532) * Tracable defensive errors * small fixes * fix * refactored * switched to defensive_ok_or * Remove unnecessary type annotations and conversions * cargo fmt * Fixes Co-authored-by: Keith Yeung --- frame/nomination-pools/src/lib.rs | 36 ++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index fd8ae8ab76b08..dc40a6a7d41fd 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1329,13 +1329,31 @@ pub mod pallet { MetadataExceedsMaxLen, /// Some error occurred that should never happen. This should be reported to the /// maintainers. - DefensiveError, + Defensive(DefensiveError), /// Not enough points. Ty unbonding less. NotEnoughPointsToUnbond, /// Partial unbonding now allowed permissionlessly. PartialUnbondNotAllowedPermissionlessly, } + #[derive(Encode, Decode, PartialEq, TypeInfo, frame_support::PalletError)] + pub enum DefensiveError { + /// There isn't enough space in the unbond pool. + NotEnoughSpaceInUnbondPool, + /// A (bonded) pool id does not exist. + PoolNotFound, + /// A reward pool does not exist. In all cases this is a system logic error. + RewardPoolNotFound, + /// A sub pool does not exist. + SubPoolsNotFound, + } + + impl From for Error { + fn from(e: DefensiveError) -> Error { + Error::::Defensive(e) + } + } + #[pallet::call] impl Pallet { /// Stake funds with a pool. The amount to bond is transferred from the member to the @@ -1366,7 +1384,7 @@ pub mod pallet { // We just need its total earnings at this point in time, but we don't need to write it // because we are not adjusting its points (all other values can calculated virtual). let reward_pool = RewardPool::::get_and_update(pool_id) - .defensive_ok_or_else(|| Error::::RewardPoolNotFound)?; + .defensive_ok_or::>(DefensiveError::RewardPoolNotFound.into())?; bonded_pool.try_inc_members()?; let points_issued = bonded_pool.try_bond_funds(&who, amount, BondType::Later)?; @@ -1530,14 +1548,16 @@ pub mod pallet { .try_insert(unbond_era, UnbondPool::default()) // The above call to `maybe_merge_pools` should ensure there is // always enough space to insert. - .defensive_map_err(|_| Error::::DefensiveError)?; + .defensive_map_err::, _>(|_| { + DefensiveError::NotEnoughSpaceInUnbondPool.into() + })?; } sub_pools .with_era .get_mut(&unbond_era) // The above check ensures the pool exists. - .defensive_ok_or_else(|| Error::::DefensiveError)? + .defensive_ok_or::>(DefensiveError::PoolNotFound.into())? .issue(unbonding_balance); Self::deposit_event(Event::::Unbonded { @@ -1607,9 +1627,9 @@ pub mod pallet { let current_era = T::StakingInterface::current_era(); let bonded_pool = BondedPool::::get(member.pool_id) - .defensive_ok_or_else(|| Error::::PoolNotFound)?; + .defensive_ok_or::>(DefensiveError::PoolNotFound.into())?; let mut sub_pools = SubPoolsStorage::::get(member.pool_id) - .defensive_ok_or_else(|| Error::::SubPoolsNotFound)?; + .defensive_ok_or::>(DefensiveError::SubPoolsNotFound.into())?; bonded_pool.ok_to_withdraw_unbonded_with( &caller, @@ -2027,9 +2047,9 @@ impl Pallet { ) -> Result<(PoolMember, BondedPool, RewardPool), Error> { let member = PoolMembers::::get(&who).ok_or(Error::::PoolMemberNotFound)?; let bonded_pool = - BondedPool::::get(member.pool_id).defensive_ok_or(Error::::PoolNotFound)?; + BondedPool::::get(member.pool_id).defensive_ok_or(DefensiveError::PoolNotFound)?; let reward_pool = - RewardPools::::get(member.pool_id).defensive_ok_or(Error::::PoolNotFound)?; + RewardPools::::get(member.pool_id).defensive_ok_or(DefensiveError::PoolNotFound)?; Ok((member, bonded_pool, reward_pool)) } From 1785a87d7533895707be08b82367b73f56b6abc7 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 3 Jun 2022 18:30:12 +0100 Subject: [PATCH 0885/1472] Remove `#[pallet::without_storage_info]` for pallet-remark (#11590) --- frame/remark/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/remark/src/lib.rs b/frame/remark/src/lib.rs index 6803b2a60085f..c69f95907019f 100644 --- a/frame/remark/src/lib.rs +++ b/frame/remark/src/lib.rs @@ -57,7 +57,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::call] From 3abad95f067c5ef749edc28412ed60c59b13f129 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 3 Jun 2022 21:46:14 +0200 Subject: [PATCH 0886/1472] Add host info to weight templates (#11583) * Add host info to weight templates Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=frame_system --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/system/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- .maintain/frame-weight-template.hbs | 1 + Cargo.lock | 11 +++++ frame/system/src/weights.rs | 24 ++++++----- utils/frame/benchmarking-cli/Cargo.toml | 1 + .../benchmarking-cli/src/overhead/cmd.rs | 6 ++- .../benchmarking-cli/src/overhead/template.rs | 6 +++ .../benchmarking-cli/src/overhead/weights.hbs | 1 + .../frame/benchmarking-cli/src/pallet/mod.rs | 5 +++ .../benchmarking-cli/src/pallet/template.hbs | 1 + .../benchmarking-cli/src/pallet/writer.rs | 4 ++ .../frame/benchmarking-cli/src/shared/mod.rs | 43 +++++++++++++++++++ .../frame/benchmarking-cli/src/storage/cmd.rs | 6 ++- .../benchmarking-cli/src/storage/template.rs | 6 +++ .../benchmarking-cli/src/storage/weights.hbs | 1 + 14 files changed, 103 insertions(+), 13 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 34852daf7d47b..73608b372eb63 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -19,6 +19,7 @@ //! //! 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}}` +//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` //! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} // Executed Command: diff --git a/Cargo.lock b/Cargo.lock index 17d2e82596526..42accdb455cef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2112,6 +2112,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "gethostname", "handlebars", "hash-db", "hex", @@ -2596,6 +2597,16 @@ dependencies = [ "version_check", ] +[[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" diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index bdd2d64b2118b..a9126e4bf5bf4 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -18,11 +18,12 @@ //! Autogenerated weights for frame_system //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-06-02, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `ci3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet // --chain=dev @@ -32,8 +33,9 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/system/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -66,7 +68,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (5_453_000 as Weight) + (5_367_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -74,21 +76,21 @@ impl WeightInfo for SubstrateWeight { fn set_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 - .saturating_add((600_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((603_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 - .saturating_add((510_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((513_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_prefix(p: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 - .saturating_add((916_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_026_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } } @@ -106,7 +108,7 @@ impl WeightInfo for () { // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (5_453_000 as Weight) + (5_367_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -114,21 +116,21 @@ impl WeightInfo for () { fn set_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 - .saturating_add((600_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((603_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 - .saturating_add((510_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((513_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) fn kill_prefix(p: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 - .saturating_add((916_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_026_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) } } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 5f30e21b2986a..c4549f5c5439d 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -56,6 +56,7 @@ sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } +gethostname = "0.2.3" [features] default = ["db", "sc-client-db/runtime-benchmarks"] diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 3cf281986861f..357c89d97a5ac 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -35,7 +35,7 @@ use crate::{ bench::{Benchmark, BenchmarkParams, BenchmarkType}, template::TemplateData, }, - shared::WeightParams, + shared::{HostInfoParams, WeightParams}, }; /// Benchmark the execution overhead per-block and per-extrinsic. @@ -64,6 +64,10 @@ pub struct OverheadParams { #[allow(missing_docs)] #[clap(flatten)] pub bench: BenchmarkParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub hostinfo: HostInfoParams, } /// Used by the benchmark to build signed extrinsics. diff --git a/utils/frame/benchmarking-cli/src/overhead/template.rs b/utils/frame/benchmarking-cli/src/overhead/template.rs index 44e2c1f02e30f..33c2c7999039a 100644 --- a/utils/frame/benchmarking-cli/src/overhead/template.rs +++ b/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -47,6 +47,10 @@ pub(crate) struct TemplateData { version: String, /// Date that the template was filled out. date: String, + /// Hostname of the machine that executed the benchmarks. + hostname: String, + /// CPU name of the machine that executed the benchmarks. + cpuname: String, /// Command line arguments that were passed to the CLI. args: Vec, /// Params of the executed command. @@ -73,6 +77,8 @@ impl TemplateData { runtime_name: cfg.chain_spec.name().into(), version: VERSION.into(), date: chrono::Utc::now().format("%Y-%m-%d (Y/M/D)").to_string(), + hostname: params.hostinfo.hostname(), + cpuname: params.hostinfo.cpuname(), args: env::args().collect::>(), params: params.clone(), stats: stats.clone(), diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index 6d3ae471d1cf2..f8312b0052592 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -17,6 +17,7 @@ //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} //! DATE: {{date}} +//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` //! //! SHORT-NAME: `{{short_name}}`, LONG-NAME: `{{long_name}}`, RUNTIME: `{{runtime_name}}` //! WARMUPS: `{{params.bench.warmup}}`, REPEAT: `{{params.bench.repeat}}` diff --git a/utils/frame/benchmarking-cli/src/pallet/mod.rs b/utils/frame/benchmarking-cli/src/pallet/mod.rs index 227c9b2f8a7b6..7beaf321a2927 100644 --- a/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -18,6 +18,7 @@ mod command; mod writer; +use crate::shared::HostInfoParams; use sc_cli::{ ExecutionStrategy, WasmExecutionMethod, WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD, @@ -91,6 +92,10 @@ pub struct PalletCmd { #[clap(long)] pub template: Option, + #[allow(missing_docs)] + #[clap(flatten)] + pub hostinfo_params: HostInfoParams, + /// Which analysis function to use when outputting benchmarks: /// * min-squares (default) /// * median-slopes diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index ea734e165919a..a2f75c7b0a35b 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -3,6 +3,7 @@ //! //! 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}}` +//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` //! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} // Executed Command: diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index 515582d8c6db9..dc38fbcfc1756 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -43,6 +43,8 @@ const TEMPLATE: &str = include_str!("./template.hbs"); struct TemplateData { args: Vec, date: String, + hostname: String, + cpuname: String, version: String, pallet: String, instance: String, @@ -322,6 +324,8 @@ pub fn write_results( let hbs_data = TemplateData { args: args.clone(), date: date.clone(), + hostname: cmd.hostinfo_params.hostname(), + cpuname: cmd.hostinfo_params.cpuname(), version: VERSION.to_string(), pallet: pallet.to_string(), instance: instance.to_string(), diff --git a/utils/frame/benchmarking-cli/src/shared/mod.rs b/utils/frame/benchmarking-cli/src/shared/mod.rs index f959c285a346e..33189792c4008 100644 --- a/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -25,7 +25,10 @@ pub use record::BenchRecord; pub use stats::{StatSelect, Stats}; pub use weight_params::WeightParams; +use clap::Args; use rand::prelude::*; +use sc_sysinfo::gather_sysinfo; +use serde::Serialize; /// A Handlebars helper to add an underscore after every 3rd character, /// i.e. a separator for large numbers. @@ -89,3 +92,43 @@ pub fn check_build_profile() -> Result<(), String> { Ok(()) } } + +/// Parameters to configure how the host info will be determined. +#[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] +#[clap(rename_all = "kebab-case")] +pub struct HostInfoParams { + /// Manually override the hostname to use. + #[clap(long)] + pub hostname_override: Option, + + /// Specify a fallback hostname if no-one could be detected automatically. + /// + /// Note: This only exists to make the `hostname` function infallible. + #[clap(long, default_value = "")] + pub hostname_fallback: String, + + /// Specify a fallback CPU name if no-one could be detected automatically. + /// + /// Note: This only exists to make the `cpuname` function infallible. + #[clap(long, default_value = "")] + pub cpuname_fallback: String, +} + +impl HostInfoParams { + /// Returns the hostname of the machine. + /// + /// Can be used to track on which machine a benchmark was run. + pub fn hostname(&self) -> String { + self.hostname_override + .clone() + .or(gethostname::gethostname().into_string().ok()) + .unwrap_or(self.hostname_fallback.clone()) + } + + /// Returns the CPU name of the current machine. + /// + /// Can be used to track on which machine a benchmark was run. + pub fn cpuname(&self) -> String { + gather_sysinfo().cpu.unwrap_or(self.cpuname_fallback.clone()) + } +} diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index 23222dbd120ab..b8264dc009232 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -34,7 +34,7 @@ use sp_runtime::generic::BlockId; use std::{fmt::Debug, path::PathBuf, sync::Arc}; use super::template::TemplateData; -use crate::shared::{new_rng, WeightParams}; +use crate::shared::{new_rng, HostInfoParams, WeightParams}; /// Benchmark the storage speed of a chain snapshot. #[derive(Debug, Parser)] @@ -63,6 +63,10 @@ pub struct StorageParams { #[clap(flatten)] pub weight_params: WeightParams, + #[allow(missing_docs)] + #[clap(flatten)] + pub hostinfo: HostInfoParams, + /// Skip the `read` benchmark. #[clap(long)] pub skip_read: bool, diff --git a/utils/frame/benchmarking-cli/src/storage/template.rs b/utils/frame/benchmarking-cli/src/storage/template.rs index 8365c3841d422..20fbd58134f20 100644 --- a/utils/frame/benchmarking-cli/src/storage/template.rs +++ b/utils/frame/benchmarking-cli/src/storage/template.rs @@ -41,6 +41,10 @@ pub(crate) struct TemplateData { version: String, /// Date that the template was filled out. date: String, + /// Hostname of the machine that executed the benchmarks. + hostname: String, + /// CPU name of the machine that executed the benchmarks. + cpuname: String, /// Command line arguments that were passed to the CLI. args: Vec, /// Storage params of the executed command. @@ -65,6 +69,8 @@ impl TemplateData { runtime_name: cfg.chain_spec.name().into(), version: VERSION.into(), date: chrono::Utc::now().format("%Y-%m-%d (Y/M/D)").to_string(), + hostname: params.hostinfo.hostname(), + cpuname: params.hostinfo.cpuname(), args: env::args().collect::>(), params: params.clone(), ..Default::default() diff --git a/utils/frame/benchmarking-cli/src/storage/weights.hbs b/utils/frame/benchmarking-cli/src/storage/weights.hbs index 51878141d1449..8c19aaa0dff36 100644 --- a/utils/frame/benchmarking-cli/src/storage/weights.hbs +++ b/utils/frame/benchmarking-cli/src/storage/weights.hbs @@ -17,6 +17,7 @@ //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} //! DATE: {{date}} +//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` //! //! DATABASE: `{{db_name}}`, RUNTIME: `{{runtime_name}}` //! BLOCK-NUM: `{{block_number}}` From 50176e1b57bdf6168d9bf3764d1cce9ed8bcf611 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 3 Jun 2022 22:43:54 +0200 Subject: [PATCH 0887/1472] Expose Benchmarking Component Ranges (#11545) * Add component ranges to benchmarking Signed-off-by: Oliver Tale-Yazdi * Adding component ranges to templates Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=frame_system --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/system/src/weights.rs --template=./.maintain/frame-weight-template.hbs * tweak script to reduce diff * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_identity --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/identity/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot Co-authored-by: Shawn Tabrizi --- .maintain/frame-weight-template.hbs | 6 + frame/identity/src/weights.rs | 263 +++++++++++------- frame/system/src/weights.rs | 14 +- scripts/run_all_benchmarks.sh | 5 +- .../benchmarking-cli/src/pallet/command.rs | 24 +- .../benchmarking-cli/src/pallet/template.hbs | 3 + .../benchmarking-cli/src/pallet/writer.rs | 20 +- 7 files changed, 220 insertions(+), 115 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 73608b372eb63..593da06f4a7c0 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -56,6 +56,9 @@ impl WeightInfo for SubstrateWeight { {{#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| ~}} @@ -88,6 +91,9 @@ impl WeightInfo for () { {{#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| ~}} diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index d59611e2e1e82..7d3371c31b03b 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -18,11 +18,11 @@ //! Autogenerated weights for pallet_identity //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-06-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet // --chain=dev @@ -32,8 +32,9 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/identity/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -66,30 +67,34 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:1) + /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - (16_343_000 as Weight) + (16_649_000 as Weight) // Standard Error: 5_000 - .saturating_add((229_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((241_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) + /// The range of component `r` is `[1, 20]`. + /// The range of component `x` is `[1, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - (32_920_000 as Weight) - // Standard Error: 8_000 - .saturating_add((203_000 as Weight).saturating_mul(r as Weight)) + (31_322_000 as Weight) + // Standard Error: 10_000 + .saturating_add((252_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((300_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((312_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) + /// The range of component `s` is `[1, 100]`. fn set_subs_new(s: u32, ) -> Weight { - (31_009_000 as Weight) - // Standard Error: 1_000 - .saturating_add((3_053_000 as Weight).saturating_mul(s as Weight)) + (30_012_000 as Weight) + // Standard Error: 2_000 + .saturating_add((3_005_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -98,10 +103,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) + /// The range of component `p` is `[1, 100]`. fn set_subs_old(p: u32, ) -> Weight { - (29_712_000 as Weight) + (29_623_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_087_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_100_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -109,71 +115,83 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) + /// The range of component `r` is `[1, 20]`. + /// The range of component `s` is `[1, 100]`. + /// The range of component `x` is `[1, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (33_943_000 as Weight) - // Standard Error: 7_000 - .saturating_add((193_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 0 - .saturating_add((1_101_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 0 - .saturating_add((194_000 as Weight).saturating_mul(x as Weight)) + (34_370_000 as Weight) + // Standard Error: 10_000 + .saturating_add((186_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_000 + .saturating_add((1_114_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 1_000 + .saturating_add((189_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) + /// The range of component `r` is `[1, 20]`. + /// The range of component `x` is `[1, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - (34_861_000 as Weight) - // Standard Error: 3_000 - .saturating_add((249_000 as Weight).saturating_mul(r as Weight)) + (34_759_000 as Weight) + // Standard Error: 4_000 + .saturating_add((251_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((344_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((340_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) + /// The range of component `r` is `[1, 20]`. + /// The range of component `x` is `[1, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - (32_906_000 as Weight) - // Standard Error: 3_000 - .saturating_add((147_000 as Weight).saturating_mul(r as Weight)) + (32_254_000 as Weight) + // Standard Error: 7_000 + .saturating_add((159_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((347_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) + /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - (7_591_000 as Weight) + (7_858_000 as Weight) // Standard Error: 3_000 - .saturating_add((201_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((190_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) + /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - (7_919_000 as Weight) + (8_011_000 as Weight) // Standard Error: 3_000 - .saturating_add((183_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((187_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) + /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - (7_887_000 as Weight) - // Standard Error: 4_000 - .saturating_add((182_000 as Weight).saturating_mul(r as Weight)) + (7_970_000 as Weight) + // Standard Error: 3_000 + .saturating_add((175_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) + /// The range of component `r` is `[1, 19]`. + /// The range of component `x` is `[1, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - (24_623_000 as Weight) - // Standard Error: 3_000 - .saturating_add((230_000 as Weight).saturating_mul(r as Weight)) + (24_730_000 as Weight) + // Standard Error: 4_000 + .saturating_add((196_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((339_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -181,12 +199,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity IdentityOf (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) - fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (48_143_000 as Weight) - // Standard Error: 8_000 - .saturating_add((106_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 0 - .saturating_add((1_105_000 as Weight).saturating_mul(s as Weight)) + /// The range of component `r` is `[1, 20]`. + /// The range of component `s` is `[1, 100]`. + /// The range of component `x` is `[1, 100]`. + fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { + (44_988_000 as Weight) + // Standard Error: 10_000 + .saturating_add((201_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_000 + .saturating_add((1_126_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 1_000 + .saturating_add((2_000 as Weight).saturating_mul(x as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -194,38 +217,42 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) + /// The range of component `s` is `[1, 99]`. fn add_sub(s: u32, ) -> Weight { - (36_778_000 as Weight) + (36_768_000 as Weight) // Standard Error: 1_000 - .saturating_add((112_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((115_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) + /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - (13_895_000 as Weight) + (13_474_000 as Weight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) + /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - (37_707_000 as Weight) + (37_720_000 as Weight) // Standard Error: 1_000 - .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) + /// The range of component `s` is `[1, 99]`. fn quit_sub(s: u32, ) -> Weight { - (26_935_000 as Weight) + (26_848_000 as Weight) // Standard Error: 1_000 - .saturating_add((106_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((115_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -234,30 +261,34 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:1) + /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - (16_343_000 as Weight) + (16_649_000 as Weight) // Standard Error: 5_000 - .saturating_add((229_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((241_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) + /// The range of component `r` is `[1, 20]`. + /// The range of component `x` is `[1, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - (32_920_000 as Weight) - // Standard Error: 8_000 - .saturating_add((203_000 as Weight).saturating_mul(r as Weight)) + (31_322_000 as Weight) + // Standard Error: 10_000 + .saturating_add((252_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 1_000 - .saturating_add((300_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((312_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) + /// The range of component `s` is `[1, 100]`. fn set_subs_new(s: u32, ) -> Weight { - (31_009_000 as Weight) - // Standard Error: 1_000 - .saturating_add((3_053_000 as Weight).saturating_mul(s as Weight)) + (30_012_000 as Weight) + // Standard Error: 2_000 + .saturating_add((3_005_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -266,10 +297,11 @@ impl WeightInfo for () { // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) + /// The range of component `p` is `[1, 100]`. fn set_subs_old(p: u32, ) -> Weight { - (29_712_000 as Weight) + (29_623_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_087_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_100_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) @@ -277,71 +309,83 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) + /// The range of component `r` is `[1, 20]`. + /// The range of component `s` is `[1, 100]`. + /// The range of component `x` is `[1, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (33_943_000 as Weight) - // Standard Error: 7_000 - .saturating_add((193_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 0 - .saturating_add((1_101_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 0 - .saturating_add((194_000 as Weight).saturating_mul(x as Weight)) + (34_370_000 as Weight) + // Standard Error: 10_000 + .saturating_add((186_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_000 + .saturating_add((1_114_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 1_000 + .saturating_add((189_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) + /// The range of component `r` is `[1, 20]`. + /// The range of component `x` is `[1, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - (34_861_000 as Weight) - // Standard Error: 3_000 - .saturating_add((249_000 as Weight).saturating_mul(r as Weight)) + (34_759_000 as Weight) + // Standard Error: 4_000 + .saturating_add((251_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((344_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((340_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:1) + /// The range of component `r` is `[1, 20]`. + /// The range of component `x` is `[1, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - (32_906_000 as Weight) - // Standard Error: 3_000 - .saturating_add((147_000 as Weight).saturating_mul(r as Weight)) + (32_254_000 as Weight) + // Standard Error: 7_000 + .saturating_add((159_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((347_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) + /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - (7_591_000 as Weight) + (7_858_000 as Weight) // Standard Error: 3_000 - .saturating_add((201_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((190_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) + /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - (7_919_000 as Weight) + (8_011_000 as Weight) // Standard Error: 3_000 - .saturating_add((183_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((187_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:1) + /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - (7_887_000 as Weight) - // Standard Error: 4_000 - .saturating_add((182_000 as Weight).saturating_mul(r as Weight)) + (7_970_000 as Weight) + // Standard Error: 3_000 + .saturating_add((175_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) + /// The range of component `r` is `[1, 19]`. + /// The range of component `x` is `[1, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - (24_623_000 as Weight) - // Standard Error: 3_000 - .saturating_add((230_000 as Weight).saturating_mul(r as Weight)) + (24_730_000 as Weight) + // Standard Error: 4_000 + .saturating_add((196_000 as Weight).saturating_mul(r as Weight)) // Standard Error: 0 - .saturating_add((339_000 as Weight).saturating_mul(x as Weight)) + .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -349,12 +393,17 @@ impl WeightInfo for () { // Storage: Identity IdentityOf (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) - fn kill_identity(r: u32, s: u32, _x: u32, ) -> Weight { - (48_143_000 as Weight) - // Standard Error: 8_000 - .saturating_add((106_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 0 - .saturating_add((1_105_000 as Weight).saturating_mul(s as Weight)) + /// The range of component `r` is `[1, 20]`. + /// The range of component `s` is `[1, 100]`. + /// The range of component `x` is `[1, 100]`. + fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { + (44_988_000 as Weight) + // Standard Error: 10_000 + .saturating_add((201_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_000 + .saturating_add((1_126_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 1_000 + .saturating_add((2_000 as Weight).saturating_mul(x as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) @@ -362,38 +411,42 @@ impl WeightInfo for () { // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) + /// The range of component `s` is `[1, 99]`. fn add_sub(s: u32, ) -> Weight { - (36_778_000 as Weight) + (36_768_000 as Weight) // Standard Error: 1_000 - .saturating_add((112_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((115_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) + /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - (13_895_000 as Weight) + (13_474_000 as Weight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) + /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - (37_707_000 as Weight) + (37_720_000 as Weight) // Standard Error: 1_000 - .saturating_add((110_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) + /// The range of component `s` is `[1, 99]`. fn quit_sub(s: u32, ) -> Weight { - (26_935_000 as Weight) + (26_848_000 as Weight) // Standard Error: 1_000 - .saturating_add((106_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((115_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index a9126e4bf5bf4..19719032587ef 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -57,9 +57,11 @@ pub trait WeightInfo { /// Weights for frame_system using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { + /// The range of component `b` is `[0, 3932160]`. fn remark(_b: u32, ) -> Weight { - (0 as Weight) + (1_000_000 as Weight) } + /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 @@ -73,6 +75,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `i` is `[1, 1000]`. fn set_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 @@ -80,6 +83,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `i` is `[1, 1000]`. fn kill_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 @@ -87,6 +91,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `p` is `[1, 1000]`. fn kill_prefix(p: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 @@ -97,9 +102,11 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { + /// The range of component `b` is `[0, 3932160]`. fn remark(_b: u32, ) -> Weight { - (0 as Weight) + (1_000_000 as Weight) } + /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 @@ -113,6 +120,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `i` is `[1, 1000]`. fn set_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 @@ -120,6 +128,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `i` is `[1, 1000]`. fn kill_storage(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 @@ -127,6 +136,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `p` is `[1, 1000]`. fn kill_prefix(p: u32, ) -> Weight { (0 as Weight) // Standard Error: 1_000 diff --git a/scripts/run_all_benchmarks.sh b/scripts/run_all_benchmarks.sh index 8d0d3d5411ed9..9aac58be45029 100755 --- a/scripts/run_all_benchmarks.sh +++ b/scripts/run_all_benchmarks.sh @@ -119,8 +119,9 @@ for PALLET in "${PALLETS[@]}"; do --extrinsic="*" \ --execution=wasm \ --wasm-execution=compiled \ - --template=./.maintain/frame-weight-template.hbs \ - --output="$WEIGHT_FILE" 2>&1 + --heap-pages=4096 \ + --output="$WEIGHT_FILE" \ + --template=./.maintain/frame-weight-template.hbs 2>&1 ) if [ $? -ne 0 ]; then echo "$OUTPUT" >> "$ERR_FILE" diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index aa95223619b45..fae5a4494cdc4 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -29,6 +29,7 @@ use sc_cli::{ use sc_client_db::BenchmarkingState; use sc_executor::NativeElseWasmExecutor; use sc_service::{Configuration, NativeExecutionDispatch}; +use serde::Serialize; use sp_core::offchain::{ testing::{TestOffchainExt, TestTransactionPoolExt}, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, @@ -37,7 +38,18 @@ use sp_externalities::Extensions; use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStorePtr}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_state_machine::StateMachine; -use std::{fmt::Debug, fs, sync::Arc, time}; +use std::{collections::HashMap, fmt::Debug, fs, sync::Arc, time}; + +/// The inclusive range of a component. +#[derive(Serialize, Debug, Clone, Eq, PartialEq)] +pub(crate) struct ComponentRange { + /// Name of the component. + name: String, + /// Minimal valid value of the component. + min: u32, + /// Maximal valid value of the component. + max: u32, +} // This takes multiple benchmark batches and combines all the results where the pallet, instance, // and benchmark are the same. @@ -212,6 +224,9 @@ impl PalletCmd { let mut batches = Vec::new(); let mut batches_db = Vec::new(); let mut timer = time::SystemTime::now(); + // Maps (pallet, extrinsic) to its component ranges. + let mut component_ranges = HashMap::<(Vec, Vec), Vec>::new(); + for (pallet, extrinsic, components) in benchmarks_to_run { let all_components = if components.is_empty() { vec![Default::default()] @@ -244,6 +259,11 @@ impl PalletCmd { .collect(); all_components.push(c); } + + component_ranges + .entry((pallet.clone(), extrinsic.clone())) + .or_default() + .push(ComponentRange { name: name.to_string(), min: lowest, max: highest }); } all_components }; @@ -366,7 +386,7 @@ impl PalletCmd { // Create the weights.rs file. if let Some(output_path) = &self.output { - writer::write_results(&batches, &storage_info, output_path, self)?; + writer::write_results(&batches, &storage_info, &component_ranges, output_path, self)?; } // Jsonify the result and write it to a file or stdout if desired. diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index a2f75c7b0a35b..688ad4d3934f5 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -25,6 +25,9 @@ impl {{pallet}}::WeightInfo for WeightInfo { {{#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| ~}} diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index dc38fbcfc1756..42a237fcf3ce3 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -26,7 +26,7 @@ use std::{ use inflector::Inflector; use serde::Serialize; -use crate::{shared::UnderscoreHelper, PalletCmd}; +use crate::{pallet::command::ComponentRange, shared::UnderscoreHelper, PalletCmd}; use frame_benchmarking::{ Analysis, AnalysisChoice, BenchmarkBatchSplitResults, BenchmarkResult, BenchmarkSelector, RegressionModel, @@ -67,6 +67,7 @@ struct BenchmarkData { component_weight: Vec, component_reads: Vec, component_writes: Vec, + component_ranges: Vec, comments: Vec, } @@ -118,6 +119,7 @@ fn io_error(s: &str) -> std::io::Error { fn map_results( batches: &[BenchmarkBatchSplitResults], storage_info: &[StorageInfo], + component_ranges: &HashMap<(Vec, Vec), Vec>, analysis_choice: &AnalysisChoice, ) -> Result>, std::io::Error> { // Skip if batches is empty. @@ -135,7 +137,8 @@ fn map_results( let pallet_string = String::from_utf8(batch.pallet.clone()).unwrap(); let instance_string = String::from_utf8(batch.instance.clone()).unwrap(); - let benchmark_data = get_benchmark_data(batch, storage_info, analysis_choice); + let benchmark_data = + get_benchmark_data(batch, storage_info, &component_ranges, analysis_choice); let pallet_benchmarks = all_benchmarks.entry((pallet_string, instance_string)).or_default(); pallet_benchmarks.push(benchmark_data); } @@ -155,6 +158,8 @@ fn extract_errors(model: &Option) -> impl Iterator fn get_benchmark_data( batch: &BenchmarkBatchSplitResults, storage_info: &[StorageInfo], + // Per extrinsic component ranges. + component_ranges: &HashMap<(Vec, Vec), Vec>, analysis_choice: &AnalysisChoice, ) -> BenchmarkData { // You can use this to put any additional comments with the benchmarking output. @@ -238,6 +243,10 @@ fn get_benchmark_data( // We add additional comments showing which storage items were touched. add_storage_comments(&mut comments, &batch.db_results, storage_info); + let component_ranges = component_ranges + .get(&(batch.pallet.clone(), batch.benchmark.clone())) + .map(|c| c.clone()) + .unwrap_or_default(); BenchmarkData { name: String::from_utf8(batch.benchmark.clone()).unwrap(), @@ -248,14 +257,16 @@ fn get_benchmark_data( component_weight: used_extrinsic_time, component_reads: used_reads, component_writes: used_writes, + component_ranges, comments, } } // Create weight file from benchmark data and Handlebars template. -pub fn write_results( +pub(crate) fn write_results( batches: &[BenchmarkBatchSplitResults], storage_info: &[StorageInfo], + component_ranges: &HashMap<(Vec, Vec), Vec>, path: &PathBuf, cmd: &PalletCmd, ) -> Result<(), std::io::Error> { @@ -305,7 +316,7 @@ pub fn write_results( handlebars.register_escape_fn(|s| -> String { s.to_string() }); // Organize results by pallet into a JSON map - let all_results = map_results(batches, storage_info, &analysis_choice)?; + let all_results = map_results(batches, storage_info, component_ranges, &analysis_choice)?; for ((pallet, instance), results) in all_results.iter() { let mut file_path = path.clone(); // If a user only specified a directory... @@ -531,6 +542,7 @@ mod test { test_data(b"second", b"first", BenchmarkParameter::c, 3, 4), ], &[], + &Default::default(), &AnalysisChoice::default(), ) .unwrap(); From 45dbb797e1864897d4fcfbb8b3441fad7e91588d Mon Sep 17 00:00:00 2001 From: zqhxuyuan Date: Mon, 6 Jun 2022 21:38:31 +0800 Subject: [PATCH 0888/1472] make era public (#11575) --- frame/system/src/extensions/check_mortality.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index 2fb99c9f45e2b..5090093fe168f 100644 --- a/frame/system/src/extensions/check_mortality.rs +++ b/frame/system/src/extensions/check_mortality.rs @@ -33,7 +33,7 @@ use sp_runtime::{ /// The extension affects `longevity` of the transaction according to the [`Era`] definition. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] -pub struct CheckMortality(Era, sp_std::marker::PhantomData); +pub struct CheckMortality(pub Era, sp_std::marker::PhantomData); impl CheckMortality { /// utility constructor. Used only in client/factory code. From 3860bbb9c032ad3444ac408aa4b706b0a9f4b836 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Mon, 6 Jun 2022 15:47:37 +0100 Subject: [PATCH 0889/1472] MEL for Ranked Collective (#11602) --- frame/ranked-collective/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 61686f1efeb2f..60df32dcb3fa3 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -145,14 +145,14 @@ impl VoteTally for Tally { } /// Record needed for every member. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct MemberRecord { /// The rank of the member. rank: Rank, } /// Record needed for every vote. -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum VoteRecord { /// Vote was an aye with given vote weight. Aye(Votes), @@ -296,7 +296,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(PhantomData<(T, I)>); #[pallet::config] From a0a40adbf57b47b445012c6cbca940c991c94197 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 7 Jun 2022 01:17:41 +0900 Subject: [PATCH 0890/1472] Fix one-by-off in `BoundedSlice::try_from` (#11600) --- frame/support/src/storage/bounded_vec.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index f1f4330ab2960..232f9f97fc6f8 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -135,7 +135,7 @@ impl> Ord for BoundedVec { impl<'a, T, S: Get> TryFrom<&'a [T]> for BoundedSlice<'a, T, S> { type Error = (); fn try_from(t: &'a [T]) -> Result { - if t.len() < S::get() as usize { + if t.len() <= S::get() as usize { Ok(BoundedSlice(t, PhantomData)) } else { Err(()) @@ -1007,4 +1007,18 @@ pub mod test { _ => unreachable!("deserializer must raise error"), } } + + #[test] + fn bounded_vec_try_from_works() { + assert!(BoundedVec::>::try_from(vec![0]).is_ok()); + assert!(BoundedVec::>::try_from(vec![0, 1]).is_ok()); + assert!(BoundedVec::>::try_from(vec![0, 1, 2]).is_err()); + } + + #[test] + fn bounded_slice_try_from_works() { + assert!(BoundedSlice::>::try_from(&[0][..]).is_ok()); + assert!(BoundedSlice::>::try_from(&[0, 1][..]).is_ok()); + assert!(BoundedSlice::>::try_from(&[0, 1, 2][..]).is_err()); + } } From 3ca525dfa6307107ee65629146783025816f9a5e Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Tue, 7 Jun 2022 11:08:58 +0100 Subject: [PATCH 0891/1472] Remove a max supply record on collection's destruction (#11593) * Remove a max supply record on collection's destruction * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_utility --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/utility/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot --- frame/uniques/src/functions.rs | 1 + frame/uniques/src/tests.rs | 8 ++ frame/uniques/src/weights.rs | 142 ++++++++++++++++++--------------- frame/utility/src/weights.rs | 54 +++++++------ 4 files changed, 117 insertions(+), 88 deletions(-) diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index c5220b562b172..155fb35ef0999 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -117,6 +117,7 @@ impl, I: 'static> Pallet { Attribute::::remove_prefix((&collection,), None); CollectionAccount::::remove(&collection_details.owner, &collection); T::Currency::unreserve(&collection_details.owner, collection_details.total_deposit); + CollectionMaxSupply::::remove(&collection); Self::deposit_event(Event::Destroyed { collection }); diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 98e81863114e2..ef28a2143e84a 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -684,5 +684,13 @@ fn max_supply_should_work() { Uniques::mint(Origin::signed(user_id), collection_id, 2, user_id), Error::::MaxSupplyReached ); + + // validate we remove the CollectionMaxSupply record when we destroy the collection + assert_ok!(Uniques::destroy( + Origin::signed(user_id), + collection_id, + Collection::::get(collection_id).unwrap().destroy_witness() + )); + assert!(!CollectionMaxSupply::::contains_key(collection_id)); }); } diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 6e0ac358d3cdd..d885077a8dee9 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,11 +18,12 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-06-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet // --chain=dev @@ -32,8 +33,9 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/uniques/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -76,14 +78,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (28_225_000 as Weight) + (27_715_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (16_513_000 as Weight) + (16_929_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -93,18 +95,22 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Attribute (r:0 w:1000) // Storage: Uniques ClassMetadataOf (r:0 w:1) // Storage: Uniques InstanceMetadataOf (r:0 w:1000) + // Storage: Uniques CollectionMaxSupply (r:0 w:1) // Storage: Uniques Account (r:0 w:20) + /// The range of component `n` is `[0, 1000]`. + /// The range of component `m` is `[0, 1000]`. + /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 15_000 - .saturating_add((10_527_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 15_000 - .saturating_add((1_505_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 15_000 - .saturating_add((1_401_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 16_000 + .saturating_add((10_481_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 16_000 + .saturating_add((1_762_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 16_000 + .saturating_add((1_590_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(m as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) @@ -114,7 +120,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (35_712_000 as Weight) + (36_577_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -122,7 +128,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (35_740_000 as Weight) + (36_124_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -130,16 +136,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (27_425_000 as Weight) + (27_225_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:100 w:100) + /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 13_000 - .saturating_add((12_499_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 14_000 + .saturating_add((12_407_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -148,26 +155,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (21_787_000 as Weight) + (21_452_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (21_938_000 as Weight) + (22_155_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (17_122_000 as Weight) + (16_897_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (17_188_000 as Weight) + (16_657_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -175,20 +182,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (24_539_000 as Weight) + (25_057_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (17_808_000 as Weight) + (17_253_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (20_251_000 as Weight) + (20_010_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -196,7 +203,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (41_106_000 as Weight) + (41_159_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -204,62 +211,62 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (40_049_000 as Weight) + (39_598_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (33_701_000 as Weight) + (33_387_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (33_733_000 as Weight) + (33_208_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (32_848_000 as Weight) + (32_619_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (30_232_000 as Weight) + (31_028_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (22_890_000 as Weight) + (22_263_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (22_845_000 as Weight) + (22_910_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (21_490_000 as Weight) + (20_716_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (19_412_000 as Weight) + (19_380_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -270,14 +277,14 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (28_225_000 as Weight) + (27_715_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (16_513_000 as Weight) + (16_929_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -287,18 +294,22 @@ impl WeightInfo for () { // Storage: Uniques Attribute (r:0 w:1000) // Storage: Uniques ClassMetadataOf (r:0 w:1) // Storage: Uniques InstanceMetadataOf (r:0 w:1000) + // Storage: Uniques CollectionMaxSupply (r:0 w:1) // Storage: Uniques Account (r:0 w:20) + /// The range of component `n` is `[0, 1000]`. + /// The range of component `m` is `[0, 1000]`. + /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 15_000 - .saturating_add((10_527_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 15_000 - .saturating_add((1_505_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 15_000 - .saturating_add((1_401_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 16_000 + .saturating_add((10_481_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 16_000 + .saturating_add((1_762_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 16_000 + .saturating_add((1_590_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(m as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) @@ -308,7 +319,7 @@ impl WeightInfo for () { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (35_712_000 as Weight) + (36_577_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -316,7 +327,7 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (35_740_000 as Weight) + (36_124_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -324,16 +335,17 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (27_425_000 as Weight) + (27_225_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:100 w:100) + /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 13_000 - .saturating_add((12_499_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 14_000 + .saturating_add((12_407_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -342,26 +354,26 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (21_787_000 as Weight) + (21_452_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (21_938_000 as Weight) + (22_155_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (17_122_000 as Weight) + (16_897_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (17_188_000 as Weight) + (16_657_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -369,20 +381,20 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (24_539_000 as Weight) + (25_057_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (17_808_000 as Weight) + (17_253_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (20_251_000 as Weight) + (20_010_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -390,7 +402,7 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (41_106_000 as Weight) + (41_159_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -398,62 +410,62 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (40_049_000 as Weight) + (39_598_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (33_701_000 as Weight) + (33_387_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (33_733_000 as Weight) + (33_208_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (32_848_000 as Weight) + (32_619_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (30_232_000 as Weight) + (31_028_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (22_890_000 as Weight) + (22_263_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (22_845_000 as Weight) + (22_910_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (21_490_000 as Weight) + (20_716_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (19_412_000 as Weight) + (19_380_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 035831918b1dc..3660a54fb6a8f 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -18,11 +18,12 @@ //! Autogenerated weights for pallet_utility //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-06-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet // --chain=dev @@ -32,8 +33,9 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/utility/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,50 +56,56 @@ pub trait WeightInfo { /// Weights for pallet_utility using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { + /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - (20_307_000 as Weight) - // Standard Error: 1_000 + (23_113_000 as Weight) + // Standard Error: 2_000 .saturating_add((2_701_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (4_082_000 as Weight) + (4_182_000 as Weight) } + /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - (3_087_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_842_000 as Weight).saturating_mul(c as Weight)) + (18_682_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_794_000 as Weight).saturating_mul(c as Weight)) } fn dispatch_as() -> Weight { - (11_832_000 as Weight) + (12_049_000 as Weight) } + /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - (19_750_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_715_000 as Weight).saturating_mul(c as Weight)) + (19_136_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_697_000 as Weight).saturating_mul(c as Weight)) } } // For backwards compatibility and tests impl WeightInfo for () { + /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - (20_307_000 as Weight) - // Standard Error: 1_000 + (23_113_000 as Weight) + // Standard Error: 2_000 .saturating_add((2_701_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (4_082_000 as Weight) + (4_182_000 as Weight) } + /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - (3_087_000 as Weight) - // Standard Error: 2_000 - .saturating_add((2_842_000 as Weight).saturating_mul(c as Weight)) + (18_682_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_794_000 as Weight).saturating_mul(c as Weight)) } fn dispatch_as() -> Weight { - (11_832_000 as Weight) + (12_049_000 as Weight) } + /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - (19_750_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_715_000 as Weight).saturating_mul(c as Weight)) + (19_136_000 as Weight) + // Standard Error: 2_000 + .saturating_add((2_697_000 as Weight).saturating_mul(c as Weight)) } } From 4238528d40876615d0f2fb8cd9e70f747583d6a2 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Tue, 7 Jun 2022 15:32:30 +0100 Subject: [PATCH 0892/1472] Implement more IntoIter traits for bounded types (#11616) --- .../support/src/storage/bounded_btree_map.rs | 18 ++++++++++++++ .../support/src/storage/bounded_btree_set.rs | 9 +++++++ frame/support/src/storage/bounded_vec.rs | 24 +++++++++++++++++++ frame/support/src/storage/weak_bounded_vec.rs | 16 +++++++++++++ 4 files changed, 67 insertions(+) diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index 390330457b9b9..fd086f1fb23a1 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -252,6 +252,24 @@ impl IntoIterator for BoundedBTreeMap { } } +impl<'a, K, V, S> IntoIterator for &'a BoundedBTreeMap { + type Item = (&'a K, &'a V); + type IntoIter = sp_std::collections::btree_map::Iter<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl<'a, K, V, S> IntoIterator for &'a mut BoundedBTreeMap { + type Item = (&'a K, &'a mut V); + type IntoIter = sp_std::collections::btree_map::IterMut<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} + impl MaxEncodedLen for BoundedBTreeMap where K: MaxEncodedLen, diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index 275bb07c6275c..77e1c6f1c9625 100644 --- a/frame/support/src/storage/bounded_btree_set.rs +++ b/frame/support/src/storage/bounded_btree_set.rs @@ -230,6 +230,15 @@ impl IntoIterator for BoundedBTreeSet { } } +impl<'a, T, S> IntoIterator for &'a BoundedBTreeSet { + type Item = &'a T; + type IntoIter = sp_std::collections::btree_set::Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + impl MaxEncodedLen for BoundedBTreeSet where T: MaxEncodedLen, diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 232f9f97fc6f8..82ae36a82bf9f 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -149,6 +149,14 @@ impl<'a, T, S> From> for &'a [T] { } } +impl<'a, T, S> sp_std::iter::IntoIterator for BoundedSlice<'a, T, S> { + type Item = &'a T; + type IntoIter = sp_std::slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + impl> Decode for BoundedVec { fn decode(input: &mut I) -> Result { let inner = Vec::::decode(input)?; @@ -605,6 +613,22 @@ impl sp_std::iter::IntoIterator for BoundedVec { } } +impl<'a, T, S> sp_std::iter::IntoIterator for &'a BoundedVec { + type Item = &'a T; + type IntoIter = sp_std::slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl<'a, T, S> sp_std::iter::IntoIterator for &'a mut BoundedVec { + type Item = &'a mut T; + type IntoIter = sp_std::slice::IterMut<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} + impl codec::DecodeLength for BoundedVec { fn len(self_encoded: &[u8]) -> Result { // `BoundedVec` stored just a `Vec`, thus the length is at the beginning in diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 8d1d38374d8a7..bf9b9a1017221 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -262,6 +262,22 @@ impl sp_std::iter::IntoIterator for WeakBoundedVec { } } +impl<'a, T, S> sp_std::iter::IntoIterator for &'a WeakBoundedVec { + type Item = &'a T; + type IntoIter = sp_std::slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl<'a, T, S> sp_std::iter::IntoIterator for &'a mut WeakBoundedVec { + type Item = &'a mut T; + type IntoIter = sp_std::slice::IterMut<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} + impl codec::DecodeLength for WeakBoundedVec { fn len(self_encoded: &[u8]) -> Result { // `WeakBoundedVec` stored just a `Vec`, thus the length is at the beginning in From 5d8fc8596ee19028e4186d04e67a8bc12491b58f Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 7 Jun 2022 19:49:36 +0200 Subject: [PATCH 0893/1472] Remove `without_storage_info` for membership pallet (#11591) --- frame/membership/src/lib.rs | 70 +++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 8e7ea9eeec313..24ecfd5333c66 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -23,7 +23,10 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::traits::{ChangeMembers, Contains, Get, InitializeMembers, SortedMembers}; +use frame_support::{ + traits::{ChangeMembers, Contains, Get, InitializeMembers, SortedMembers}, + BoundedVec, +}; use sp_std::prelude::*; pub mod migrations; @@ -44,7 +47,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::without_storage_info] pub struct Pallet(PhantomData<(T, I)>); #[pallet::config] @@ -79,7 +81,7 @@ pub mod pallet { /// /// This is used for benchmarking. Re-run the benchmarks if this changes. /// - /// This is not enforced in the code; the membership size can exceed this limit. + /// This is enforced in the code; the membership size can not exceed this limit. type MaxMembers: Get; /// Weight information for extrinsics in this pallet. @@ -90,7 +92,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn members)] pub type Members, I: 'static = ()> = - StorageValue<_, Vec, ValueQuery>; + StorageValue<_, BoundedVec, ValueQuery>; /// The current prime member, if one exists. #[pallet::storage] @@ -99,14 +101,14 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig, I: 'static = ()> { - pub members: Vec, + pub members: BoundedVec, pub phantom: PhantomData, } #[cfg(feature = "std")] impl, I: 'static> Default for GenesisConfig { fn default() -> Self { - Self { members: Vec::new(), phantom: Default::default() } + Self { members: Default::default(), phantom: Default::default() } } } @@ -151,6 +153,8 @@ pub mod pallet { AlreadyMember, /// Not a member. NotMember, + /// Too many members. + TooManyMembers, } #[pallet::call] @@ -164,9 +168,10 @@ pub mod pallet { let mut members = >::get(); let location = members.binary_search(&who).err().ok_or(Error::::AlreadyMember)?; - members.insert(location, who.clone()); + members + .try_insert(location, who.clone()) + .map_err(|_| Error::::TooManyMembers)?; - Self::maybe_warn_max_members(&members); >::put(&members); T::MembershipChanged::change_members_sorted(&[who], &[], &members[..]); @@ -186,7 +191,6 @@ pub mod pallet { let location = members.binary_search(&who).ok().ok_or(Error::::NotMember)?; members.remove(location); - Self::maybe_warn_max_members(&members); >::put(&members); T::MembershipChanged::change_members_sorted(&[], &[who], &members[..]); @@ -219,7 +223,6 @@ pub mod pallet { members[location] = add.clone(); members.sort(); - Self::maybe_warn_max_members(&members); >::put(&members); T::MembershipChanged::change_members_sorted(&[add], &[remove], &members[..]); @@ -237,12 +240,12 @@ pub mod pallet { pub fn reset_members(origin: OriginFor, members: Vec) -> DispatchResult { T::ResetOrigin::ensure_origin(origin)?; - let mut members = members; + let mut members: BoundedVec = + BoundedVec::try_from(members).map_err(|_| Error::::TooManyMembers)?; members.sort(); >::mutate(|m| { T::MembershipChanged::set_members_sorted(&members[..], m); Self::rejig_prime(&members); - Self::maybe_warn_max_members(&members); *m = members; }); @@ -267,7 +270,6 @@ pub mod pallet { members[location] = new.clone(); members.sort(); - Self::maybe_warn_max_members(&members); >::put(&members); T::MembershipChanged::change_members_sorted( @@ -320,17 +322,6 @@ impl, I: 'static> Pallet { } } } - - fn maybe_warn_max_members(members: &[T::AccountId]) { - if members.len() as u32 > T::MaxMembers::get() { - log::error!( - target: "runtime::membership", - "maximum number of members used for weight is exceeded, weights can be underestimated [{} > {}].", - members.len(), - T::MaxMembers::get(), - ) - } - } } impl, I: 'static> Contains for Pallet { @@ -341,7 +332,7 @@ impl, I: 'static> Contains for Pallet { impl, I: 'static> SortedMembers for Pallet { fn sorted_members() -> Vec { - Self::members() + Self::members().to_vec() } fn count() -> usize { @@ -372,7 +363,7 @@ mod benchmark { benchmarks_instance_pallet! { add_member { - let m in 1 .. T::MaxMembers::get(); + let m in 1 .. (T::MaxMembers::get() - 1); let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); set_members::(members, None); @@ -504,7 +495,7 @@ mod tests { }; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, parameter_types, + assert_noop, assert_ok, bounded_vec, ord_parameter_types, parameter_types, traits::{ConstU32, ConstU64, GenesisBuild, StorageVersion}, }; use frame_system::EnsureSignedBy; @@ -609,7 +600,7 @@ mod tests { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); // We use default for brevity, but you can configure as desired if needed. pallet_membership::GenesisConfig:: { - members: vec![10, 20, 30], + members: bounded_vec![10, 20, 30], ..Default::default() } .assimilate_storage(&mut t) @@ -661,7 +652,7 @@ mod tests { ); assert_ok!(Membership::add_member(Origin::signed(1), 15)); assert_eq!(Membership::members(), vec![10, 15, 20, 30]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); }); } @@ -676,7 +667,7 @@ mod tests { assert_ok!(Membership::set_prime(Origin::signed(5), 20)); assert_ok!(Membership::remove_member(Origin::signed(2), 20)); assert_eq!(Membership::members(), vec![10, 30]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), None); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); }); @@ -704,7 +695,7 @@ mod tests { assert_ok!(Membership::set_prime(Origin::signed(5), 10)); assert_ok!(Membership::swap_member(Origin::signed(3), 10, 25)); assert_eq!(Membership::members(), vec![20, 25, 30]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), None); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); }); @@ -715,7 +706,7 @@ mod tests { new_test_ext().execute_with(|| { assert_ok!(Membership::swap_member(Origin::signed(3), 10, 5)); assert_eq!(Membership::members(), vec![5, 20, 30]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); }); } @@ -733,7 +724,7 @@ mod tests { ); assert_ok!(Membership::change_key(Origin::signed(10), 40)); assert_eq!(Membership::members(), vec![20, 30, 40]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), Some(40)); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); }); @@ -744,7 +735,7 @@ mod tests { new_test_ext().execute_with(|| { assert_ok!(Membership::change_key(Origin::signed(10), 5)); assert_eq!(Membership::members(), vec![5, 20, 30]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); }); } @@ -752,17 +743,20 @@ mod tests { fn reset_members_works() { new_test_ext().execute_with(|| { assert_ok!(Membership::set_prime(Origin::signed(5), 20)); - assert_noop!(Membership::reset_members(Origin::signed(1), vec![20, 40, 30]), BadOrigin); + assert_noop!( + Membership::reset_members(Origin::signed(1), bounded_vec![20, 40, 30]), + BadOrigin + ); assert_ok!(Membership::reset_members(Origin::signed(4), vec![20, 40, 30])); assert_eq!(Membership::members(), vec![20, 30, 40]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), Some(20)); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); assert_ok!(Membership::reset_members(Origin::signed(4), vec![10, 40, 30])); assert_eq!(Membership::members(), vec![10, 30, 40]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), None); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); }); @@ -772,7 +766,7 @@ mod tests { #[should_panic(expected = "Members cannot contain duplicate accounts.")] fn genesis_build_panics_with_duplicate_members() { pallet_membership::GenesisConfig:: { - members: vec![1, 2, 3, 1], + members: bounded_vec![1, 2, 3, 1], phantom: Default::default(), } .build_storage() From bc7a1e6c19aec92bfa247d8ca68ec63e07061032 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Wed, 8 Jun 2022 11:48:46 +0300 Subject: [PATCH 0894/1472] Improve docs on `--keep-blocks` CLI parameter and related data structures (#11611) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improve docs on `--keep-blocks` CLI parameter and related data structures * Update client/db/src/lib.rs Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- client/cli/src/params/pruning_params.rs | 2 ++ client/db/src/lib.rs | 2 ++ client/network/test/src/lib.rs | 2 ++ client/service/src/config.rs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index fa30aa53b8a04..9d471224cc59e 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -33,6 +33,8 @@ pub struct PruningParams { /// Specify the number of finalized blocks to keep in the database. /// /// Default is to keep all blocks. + /// + /// NOTE: only finalized blocks are subject for removal! #[clap(long, value_name = "COUNT")] pub keep_blocks: Option, } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 5f15b2d6fe969..ccdb434dfbd32 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -302,6 +302,8 @@ pub struct DatabaseSettings { /// Where to find the database. pub source: DatabaseSource, /// Block pruning mode. + /// + /// NOTE: only finalized blocks are subject for removal! pub keep_blocks: KeepBlocks, } diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 9e23a4cc678e9..9e752e81a3bbc 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -667,6 +667,8 @@ impl warp_request_handler::WarpSyncProvider for TestWarpSyncProvid #[derive(Default)] pub struct FullPeerConfig { /// Pruning window size. + /// + /// NOTE: only finalized blocks are subject for removal! pub keep_blocks: Option, /// Block announce validator. pub block_announce_validator: Option + Send + Sync>>, diff --git a/client/service/src/config.rs b/client/service/src/config.rs index c895300fea4d1..0eeb6e05cee16 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -77,6 +77,8 @@ pub struct Configuration { /// State pruning settings. pub state_pruning: Option, /// Number of blocks to keep in the db. + /// + /// NOTE: only finalized blocks are subject for removal! pub keep_blocks: KeepBlocks, /// Chain configuration. pub chain_spec: Box, From 81c3d9e594668a32935a5eb7ce546912251aced6 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 9 Jun 2022 18:55:02 +0100 Subject: [PATCH 0895/1472] Improve inspection and generation of node keys (#11525) * Improve inspection and generation of node keys * Lock stdout before write * Fix typo * Fix offset * Remove useless code * Set inspect-node-key 'network' option as obsolete --- bin/utils/subkey/src/lib.rs | 6 +-- client/cli/src/commands/generate_node_key.rs | 31 +++++++++---- client/cli/src/commands/inspect_node_key.rs | 49 +++++++++++++++----- client/cli/src/commands/key.rs | 6 +-- 4 files changed, 66 insertions(+), 26 deletions(-) diff --git a/bin/utils/subkey/src/lib.rs b/bin/utils/subkey/src/lib.rs index 3731d9f3ec75c..6773ba822340f 100644 --- a/bin/utils/subkey/src/lib.rs +++ b/bin/utils/subkey/src/lib.rs @@ -30,8 +30,8 @@ use sc_cli::{ version )] pub enum Subkey { - /// Generate a random node libp2p key, save it to file or print it to stdout - /// and print its peer ID to stderr. + /// Generate a random node key, write it to a file or stdout and write the + /// corresponding peer-id to stderr GenerateNodeKey(GenerateNodeKeyCmd), /// Generate a random account @@ -40,7 +40,7 @@ pub enum Subkey { /// Gets a public key and a SS58 address from the provided Secret URI Inspect(InspectKeyCmd), - /// Print the peer ID corresponding to the node key in the given file + /// Load a node key from a file or stdin and print the corresponding peer-id InspectNodeKey(InspectNodeKeyCmd), /// Sign a message, with a given (secret) key. diff --git a/client/cli/src/commands/generate_node_key.rs b/client/cli/src/commands/generate_node_key.rs index 8c634dca9acf2..6b2f12531458c 100644 --- a/client/cli/src/commands/generate_node_key.rs +++ b/client/cli/src/commands/generate_node_key.rs @@ -20,14 +20,18 @@ use crate::Error; use clap::Parser; use libp2p::identity::{ed25519 as libp2p_ed25519, PublicKey}; -use std::{fs, path::PathBuf}; +use std::{ + fs, + io::{self, Write}, + path::PathBuf, +}; /// The `generate-node-key` command #[derive(Debug, Parser)] #[clap( name = "generate-node-key", - about = "Generate a random node libp2p key, save it to \ - file or print it to stdout and print its peer ID to stderr" + about = "Generate a random node key, write it to a file or stdout \ + and write the corresponding peer-id to stderr" )] pub struct GenerateNodeKeyCmd { /// Name of file to save secret key to. @@ -35,22 +39,33 @@ pub struct GenerateNodeKeyCmd { /// If not given, the secret key is printed to stdout. #[clap(long)] file: Option, + + /// The output is in raw binary format. + /// + /// If not given, the output is written as an hex encoded string. + #[clap(long)] + bin: bool, } impl GenerateNodeKeyCmd { /// Run the command pub fn run(&self) -> Result<(), Error> { let keypair = libp2p_ed25519::Keypair::generate(); + let secret = keypair.secret(); - let peer_id = PublicKey::Ed25519(keypair.public()).to_peer_id(); - let secret_hex = hex::encode(secret.as_ref()); + + let file_data = if self.bin { + secret.as_ref().to_owned() + } else { + hex::encode(secret.as_ref()).into_bytes() + }; match &self.file { - Some(file) => fs::write(file, secret_hex)?, - None => print!("{}", secret_hex), + Some(file) => fs::write(file, file_data)?, + None => io::stdout().lock().write_all(&file_data)?, } - eprintln!("{}", peer_id); + eprintln!("{}", PublicKey::Ed25519(keypair.public()).to_peer_id()); Ok(()) } diff --git a/client/cli/src/commands/inspect_node_key.rs b/client/cli/src/commands/inspect_node_key.rs index 4c0798cc0635c..e1617c1d085df 100644 --- a/client/cli/src/commands/inspect_node_key.rs +++ b/client/cli/src/commands/inspect_node_key.rs @@ -17,39 +17,64 @@ //! Implementation of the `inspect-node-key` subcommand -use crate::{Error, NetworkSchemeFlag}; +use crate::Error; use clap::Parser; use libp2p::identity::{ed25519, PublicKey}; -use std::{fs, path::PathBuf}; +use std::{ + fs, + io::{self, Read}, + path::PathBuf, +}; /// The `inspect-node-key` command #[derive(Debug, Parser)] #[clap( name = "inspect-node-key", - about = "Print the peer ID corresponding to the node key in the given file." + about = "Load a node key from a file or stdin and print the corresponding peer-id." )] pub struct InspectNodeKeyCmd { /// Name of file to read the secret key from. + /// + /// If not given, the secret key is read from stdin (up to EOF). #[clap(long)] - file: PathBuf, + file: Option, - #[allow(missing_docs)] - #[clap(flatten)] - pub network_scheme: NetworkSchemeFlag, + /// The input is in raw binary format. + /// + /// If not given, the input is read as an hex encoded string. + #[clap(long)] + bin: bool, + + /// This argument is deprecated and has no effect for this command. + #[deprecated(note = "Network identifier is not used for node-key inspection")] + #[clap(short = 'n', long = "network", value_name = "NETWORK", ignore_case = true)] + pub network_scheme: Option, } impl InspectNodeKeyCmd { /// runs the command pub fn run(&self) -> Result<(), Error> { - let mut file_content = - hex::decode(fs::read(&self.file)?).map_err(|_| "failed to decode secret as hex")?; + let mut file_data = match &self.file { + Some(file) => fs::read(&file)?, + None => { + let mut buf = Vec::with_capacity(64); + io::stdin().lock().read_to_end(&mut buf)?; + buf + }, + }; + + if !self.bin { + // With hex input, give to the user a bit of tolerance about whitespaces + let keyhex = String::from_utf8_lossy(&file_data); + file_data = hex::decode(keyhex.trim()).map_err(|_| "failed to decode secret as hex")?; + } + let secret = - ed25519::SecretKey::from_bytes(&mut file_content).map_err(|_| "Bad node key file")?; + ed25519::SecretKey::from_bytes(&mut file_data).map_err(|_| "Bad node key file")?; let keypair = ed25519::Keypair::from(secret); - let peer_id = PublicKey::Ed25519(keypair.public()).to_peer_id(); - println!("{}", peer_id); + println!("{}", PublicKey::Ed25519(keypair.public()).to_peer_id()); Ok(()) } diff --git a/client/cli/src/commands/key.rs b/client/cli/src/commands/key.rs index e0f3524196e2c..59cca554bfa37 100644 --- a/client/cli/src/commands/key.rs +++ b/client/cli/src/commands/key.rs @@ -26,8 +26,8 @@ use crate::{Error, SubstrateCli}; /// Key utilities for the cli. #[derive(Debug, clap::Subcommand)] pub enum KeySubcommand { - /// Generate a random node libp2p key, save it to file or print it to stdout - /// and print its peer ID to stderr. + /// Generate a random node key, write it to a file or stdout and write the + /// corresponding peer-id to stderr GenerateNodeKey(GenerateNodeKeyCmd), /// Generate a random account @@ -36,7 +36,7 @@ pub enum KeySubcommand { /// Gets a public key and a SS58 address from the provided Secret URI Inspect(InspectKeyCmd), - /// Print the peer ID corresponding to the node key in the given file + /// Load a node key from a file or stdin and print the corresponding peer-id InspectNodeKey(InspectNodeKeyCmd), /// Insert a key to the keystore of a node. From cc4da0d2aed7736c4f88e89711831eafa9e3ee62 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 10 Jun 2022 11:58:55 +0300 Subject: [PATCH 0896/1472] Better transaction pool error (#11629) * Better transaction pool error * Do not use `Debug` when printing errors --- client/transaction-pool/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/transaction-pool/src/error.rs b/client/transaction-pool/src/error.rs index adc19d52c7e41..a4cf756481dc3 100644 --- a/client/transaction-pool/src/error.rs +++ b/client/transaction-pool/src/error.rs @@ -27,10 +27,10 @@ pub type Result = std::result::Result; #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { - #[error("Transaction pool error")] + #[error("Transaction pool error: {0}")] Pool(#[from] TxPoolError), - #[error("Blockchain error")] + #[error("Blockchain error: {0}")] Blockchain(#[from] sp_blockchain::Error), #[error("Block conversion error: {0}")] From 96596bcaac7d1fd60cf0e4f066ebf8ba3b810d84 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 10 Jun 2022 18:20:03 +0100 Subject: [PATCH 0897/1472] Use BoundedVec in aura pallet (#11617) * Use BoundedVec in aura pallet * cargo fmt --- frame/aura/src/lib.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index fd6882ca9f29f..ff2c5df04a453 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -40,8 +40,9 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ + log, traits::{DisabledValidators, FindAuthor, Get, OnTimestampSet, OneSessionHandler}, - BoundedSlice, ConsensusEngineId, Parameter, WeakBoundedVec, + BoundedSlice, BoundedVec, ConsensusEngineId, Parameter, }; use sp_consensus_aura::{AuthorityIndex, ConsensusLog, Slot, AURA_ENGINE_ID}; use sp_runtime::{ @@ -116,7 +117,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn authorities)] pub(super) type Authorities = - StorageValue<_, WeakBoundedVec, ValueQuery>; + StorageValue<_, BoundedVec, ValueQuery>; /// The current slot of this block. /// @@ -150,7 +151,7 @@ impl Pallet { /// /// The storage will be applied immediately. /// And aura consensus log will be appended to block's log. - pub fn change_authorities(new: WeakBoundedVec) { + pub fn change_authorities(new: BoundedVec) { >::put(&new); let log = DigestItem::Consensus( @@ -219,10 +220,14 @@ impl OneSessionHandler for Pallet { let next_authorities = validators.map(|(_, k)| k).collect::>(); let last_authorities = Self::authorities(); if last_authorities != next_authorities { - let bounded = >::force_from( - next_authorities, - Some("AuRa new session"), - ); + if next_authorities.len() as u32 > T::MaxAuthorities::get() { + log::warn!( + target: "runtime::aura", + "next authorities list larger than {}, truncating", + T::MaxAuthorities::get(), + ); + } + let bounded = >::truncate_from(next_authorities); Self::change_authorities(bounded); } } From bc310fdd1040af8a3d2901b5d6f4cf8d5250aeb7 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Sat, 11 Jun 2022 06:39:26 +1200 Subject: [PATCH 0898/1472] pallet alliance (#11112) * Add pallet-alliance Signed-off-by: koushiro * Update multihash/cid and format Signed-off-by: koushiro * Remove useless deps Signed-off-by: koushiro * Add pallet-alliance into node runtime Signed-off-by: koushiro * Fix has_identity Signed-off-by: koushiro * Add TooMantBlacklist Error Signed-off-by: koushiro * Add TooLongWebsiteUrlLength Error Signed-off-by: koushiro * Add remove_announcement Signed-off-by: koushiro * Derive pallet_identity::Config and Fix test/benchmarking Signed-off-by: koushiro * Add part weight for call of pallet-alliance Signed-off-by: koushiro * Remove pallet_identity Config trait Signed-off-by: koushiro * Fix propose arguments Signed-off-by: koushiro * Some nits Signed-off-by: koushiro * cargo fmt Signed-off-by: koushiro * Fix benchmarking of add_blacklist/remove_blacklist Signed-off-by: koushiro * Some nits Signed-off-by: koushiro * Add benchmarking for init_members Signed-off-by: koushiro * Add benchmarking for propose/vote/veto Signed-off-by: koushiro * Fix benchmarking Signed-off-by: koushiro * Remove some useless Signed-off-by: koushiro * fix some compile issue * more fix * all checks * refactor * refactor event * refactor * cleanup * cleanup * fix benchmarking * fix warning * fmt * fix benchmarks * with storage info * fmt * add new config * fix benchmarks * fix * fmt * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * improvements * fix * update docs * rename events, errors, and functions * make kicking events clearer * fix * fix tests * fix tests * fix runtime * fix build * remove unneeded change * remove Candidate role from Alliance * fmt grumbles * update lock * update recursion limit * benchmarks * convert-try * benchmark assertions * fmt , * cargo lock * Update frame/alliance/src/benchmarking.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * add docs to public interfaces * Apply suggestions from code review Co-authored-by: Squirrel * fix build (node) * review * use EitherOfDiverse * update cargo toml * make all dispatch class Normal * change blacklist to unscrupulous * formatting * fmt oops * rename benchmarking unscrupulous account creator Co-authored-by: koushiro Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: joepetrowski Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Squirrel --- Cargo.lock | 23 + Cargo.toml | 1 + bin/node/cli/src/chain_spec.rs | 2 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/impls.rs | 77 +- bin/node/runtime/src/lib.rs | 70 +- bin/node/testing/src/genesis.rs | 2 + frame/alliance/Cargo.toml | 68 ++ frame/alliance/README.md | 68 ++ frame/alliance/src/benchmarking.rs | 791 +++++++++++++++++++++ frame/alliance/src/lib.rs | 1053 ++++++++++++++++++++++++++++ frame/alliance/src/mock.rs | 324 +++++++++ frame/alliance/src/tests.rs | 483 +++++++++++++ frame/alliance/src/types.rs | 95 +++ frame/alliance/src/weights.rs | 485 +++++++++++++ frame/collective/src/lib.rs | 364 +++++----- 16 files changed, 3745 insertions(+), 165 deletions(-) create mode 100644 frame/alliance/Cargo.toml create mode 100644 frame/alliance/README.md create mode 100644 frame/alliance/src/benchmarking.rs create mode 100644 frame/alliance/src/lib.rs create mode 100644 frame/alliance/src/mock.rs create mode 100644 frame/alliance/src/tests.rs create mode 100644 frame/alliance/src/types.rs create mode 100644 frame/alliance/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 42accdb455cef..3b581bf9d0ff7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4741,6 +4741,7 @@ dependencies = [ "hex-literal", "log", "node-primitives", + "pallet-alliance", "pallet-asset-tx-payment", "pallet-assets", "pallet-authority-discovery", @@ -5132,6 +5133,28 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "pallet-alliance" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "hex-literal", + "log", + "pallet-balances", + "pallet-collective", + "pallet-identity", + "parity-scale-codec", + "scale-info", + "sha2 0.10.2", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 74e7aae7949c5..7f013c08a9144 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ members = [ "client/transaction-pool", "client/transaction-pool/api", "client/utils", + "frame/alliance", "frame/assets", "frame/atomic-swap", "frame/aura", diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 221c229876275..1c7794fd0cde6 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -363,6 +363,8 @@ pub fn testnet_genesis( gilt: Default::default(), transaction_storage: Default::default(), transaction_payment: Default::default(), + alliance: Default::default(), + alliance_motion: Default::default(), nomination_pools: Default::default(), } } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 5ecd6ccedaf01..ca971f29e93c9 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -50,6 +50,7 @@ frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, p frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-support" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system/rpc/runtime-api/" } frame-try-runtime = { version = "0.10.0-dev", default-features = false, path = "../../../frame/try-runtime", optional = true } +pallet-alliance = { version = "4.0.0-dev", default-features = false, path = "../../../frame/alliance" } pallet-assets = { version = "4.0.0-dev", default-features = false, path = "../../../frame/assets" } pallet-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/authority-discovery" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../../../frame/authorship" } @@ -187,12 +188,14 @@ std = [ "frame-try-runtime/std", "sp-io/std", "pallet-child-bounties/std", + "pallet-alliance/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "pallet-alliance/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", @@ -243,6 +246,7 @@ try-runtime = [ "frame-executive/try-runtime", "frame-try-runtime", "frame-system/try-runtime", + "pallet-alliance/try-runtime", "pallet-assets/try-runtime", "pallet-authority-discovery/try-runtime", "pallet-authorship/try-runtime", diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 4973aed4bd4fc..68c780094208f 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -17,12 +17,19 @@ //! Some configurable implementations as associated type for the substrate runtime. -use crate::{AccountId, Assets, Authorship, Balances, NegativeImbalance, Runtime}; -use frame_support::traits::{ - fungibles::{Balanced, CreditOf}, - Currency, OnUnbalanced, +use crate::{ + AccountId, AllianceMotion, Assets, Authorship, Balances, Call, Hash, NegativeImbalance, Runtime, }; +use frame_support::{ + pallet_prelude::*, + traits::{ + fungibles::{Balanced, CreditOf}, + Currency, OnUnbalanced, + }, +}; +use pallet_alliance::{IdentityVerifier, ProposalIndex, ProposalProvider}; use pallet_asset_tx_payment::HandleCredit; +use sp_std::prelude::*; pub struct Author; impl OnUnbalanced for Author { @@ -45,6 +52,68 @@ impl HandleCredit for CreditToBlockAuthor { } } +pub struct AllianceIdentityVerifier; +impl IdentityVerifier for AllianceIdentityVerifier { + fn has_identity(who: &AccountId, fields: u64) -> bool { + crate::Identity::has_identity(who, fields) + } + + fn has_good_judgement(who: &AccountId) -> bool { + use pallet_identity::Judgement; + if let Some(judgements) = + crate::Identity::identity(who).map(|registration| registration.judgements) + { + judgements + .iter() + .any(|(_, j)| matches!(j, Judgement::KnownGood | Judgement::Reasonable)) + } else { + false + } + } + + fn super_account_id(who: &AccountId) -> Option { + crate::Identity::super_of(who).map(|parent| parent.0) + } +} + +pub struct AllianceProposalProvider; +impl ProposalProvider for AllianceProposalProvider { + fn propose_proposal( + who: AccountId, + threshold: u32, + proposal: Box, + length_bound: u32, + ) -> Result<(u32, u32), DispatchError> { + AllianceMotion::do_propose_proposed(who, threshold, proposal, length_bound) + } + + fn vote_proposal( + who: AccountId, + proposal: Hash, + index: ProposalIndex, + approve: bool, + ) -> Result { + AllianceMotion::do_vote(who, proposal, index, approve) + } + + fn veto_proposal(proposal_hash: Hash) -> u32 { + AllianceMotion::do_disapprove_proposal(proposal_hash) + } + + fn close_proposal( + proposal_hash: Hash, + proposal_index: ProposalIndex, + proposal_weight_bound: Weight, + length_bound: u32, + ) -> DispatchResultWithPostInfo { + AllianceMotion::do_close(proposal_hash, proposal_index, proposal_weight_bound, length_bound) + } + + fn proposal_of(proposal_hash: Hash) -> Option { + AllianceMotion::proposal_of(proposal_hash) + } +} + #[cfg(test)] mod multiplier_tests { use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index b421a4f05ed1a..8e854b770a4ff 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -19,7 +19,7 @@ //! The Substrate 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. +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512. #![recursion_limit = "512"] use codec::{Decode, Encode, MaxEncodedLen}; @@ -90,7 +90,9 @@ pub use sp_runtime::BuildStorage; /// Implementations of some helper traits passed into runtime modules as associated types. pub mod impls; -use impls::{Author, CreditToBlockAuthor}; +#[cfg(not(feature = "runtime-benchmarks"))] +use impls::AllianceIdentityVerifier; +use impls::{AllianceProposalProvider, Author, CreditToBlockAuthor}; /// Constant values used within the runtime. pub mod constants; @@ -1506,6 +1508,67 @@ impl pallet_state_trie_migration::Config for Runtime { type WeightInfo = (); } +parameter_types! { + pub const AllianceMotionDuration: BlockNumber = 5 * DAYS; + pub const AllianceMaxProposals: u32 = 100; + pub const AllianceMaxMembers: u32 = 100; +} + +type AllianceCollective = pallet_collective::Instance3; +impl pallet_collective::Config for Runtime { + type Origin = Origin; + type Proposal = Call; + type Event = Event; + type MotionDuration = AllianceMotionDuration; + type MaxProposals = AllianceMaxProposals; + type MaxMembers = AllianceMaxMembers; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type WeightInfo = pallet_collective::weights::SubstrateWeight; +} + +parameter_types! { + pub const MaxFounders: u32 = 10; + pub const MaxFellows: u32 = AllianceMaxMembers::get() - MaxFounders::get(); + pub const MaxAllies: u32 = 100; + pub const AllyDeposit: Balance = 10 * DOLLARS; +} + +impl pallet_alliance::Config for Runtime { + type Event = Event; + type Proposal = Call; + type AdminOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, + >; + type MembershipManager = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, + >; + type AnnouncementOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, + >; + type Currency = Balances; + type Slashed = Treasury; + type InitializeMembers = AllianceMotion; + type MembershipChanged = AllianceMotion; + #[cfg(not(feature = "runtime-benchmarks"))] + type IdentityVerifier = AllianceIdentityVerifier; + #[cfg(feature = "runtime-benchmarks")] + type IdentityVerifier = (); + type ProposalProvider = AllianceProposalProvider; + type MaxProposals = AllianceMaxProposals; + type MaxFounders = MaxFounders; + type MaxFellows = MaxFellows; + type MaxAllies = MaxAllies; + type MaxUnscrupulousItems = ConstU32<100>; + type MaxWebsiteUrlLength = ConstU32<255>; + type MaxAnnouncementsCount = ConstU32<100>; + type MaxMembersCount = AllianceMaxMembers; + type AllyDeposit = AllyDeposit; + type WeightInfo = pallet_alliance::weights::SubstrateWeight; +} + construct_runtime!( pub enum Runtime where Block = Block, @@ -1563,6 +1626,8 @@ construct_runtime!( Remark: pallet_remark, ConvictionVoting: pallet_conviction_voting, Whitelist: pallet_whitelist, + AllianceMotion: pallet_collective::, + Alliance: pallet_alliance, NominationPools: pallet_nomination_pools, RankedPolls: pallet_referenda::, RankedCollective: pallet_ranked_collective, @@ -2049,7 +2114,6 @@ impl_runtime_apis! { let mut batches = Vec::::new(); let params = (&config, &whitelist); add_benchmarks!(params, batches); - Ok(batches) } } diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index 73e7ea50261d3..fbd28c5af0298 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -92,6 +92,8 @@ pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec) -> Gen gilt: Default::default(), transaction_storage: Default::default(), transaction_payment: Default::default(), + alliance: Default::default(), + alliance_motion: Default::default(), nomination_pools: Default::default(), } } diff --git a/frame/alliance/Cargo.toml b/frame/alliance/Cargo.toml new file mode 100644 index 0000000000000..706827708ce88 --- /dev/null +++ b/frame/alliance/Cargo.toml @@ -0,0 +1,68 @@ +[package] +name = "pallet-alliance" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://docs.substrate.io/" +repository = "https://github.com/paritytech/substrate/" +description = "The Alliance pallet provides a collective for standard-setting industry collaboration." +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +hex = { version = "0.4", default-features = false, features = ["alloc"], optional = true } +sha2 = { version = "0.10.1", default-features = false, optional = true } +log = { version = "0.4.14", default-features = false } + +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } + +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } + +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } + +pallet-identity = { version = "4.0.0-dev", path = "../identity", default-features = false } +pallet-collective = { version = "4.0.0-dev", path = "../collective", default-features = false, optional = true } + +[dev-dependencies] +hex-literal = "0.3.1" +sha2 = "0.10.1" +pallet-balances = { version = "4.0.0-dev", path = "../balances" } +pallet-collective = { version = "4.0.0-dev", path = "../collective" } + +[features] +default = ["std"] +std = [ + "log/std", + "codec/std", + "scale-info/std", + "sp-std/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", + "pallet-identity/std", +] +runtime-benchmarks = [ + "hex", + "sha2", + "frame-benchmarking", + "sp-runtime/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", + "pallet-identity/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/frame/alliance/README.md b/frame/alliance/README.md new file mode 100644 index 0000000000000..f0900c84cbd85 --- /dev/null +++ b/frame/alliance/README.md @@ -0,0 +1,68 @@ +# Alliance Pallet + +The Alliance Pallet provides a collective that curates a list of accounts and URLs, deemed by +the voting members to be unscrupulous actors. The alliance + +- provides a set of ethics against bad behavior, and +- provides recognition and influence for those teams that contribute something back to the + ecosystem. + +## Overview + +The network initializes the Alliance via a Root call. After that, anyone with an approved +identity and website can join as an Ally. The `MembershipManager` origin can elevate Allies to +Fellows, giving them voting rights within the Alliance. + +Voting members of the Alliance maintain a list of accounts and websites. Members can also vote +to update the Alliance's rule and make announcements. + +### Terminology + +- Rule: The IPFS CID (hash) of the Alliance rules for the community to read and the Alliance + members to enforce. Similar to a Code of Conduct. +- Announcement: An IPFS CID of some content that the Alliance want to announce. +- Member: An account that is already in the group of the Alliance, including three types: + Founder, Fellow, or Ally. A member can also be kicked by the `MembershipManager` origin or + retire by itself. +- Founder: An account who is initiated by Root with normal voting rights for basic motions and + special veto rights for rule change and Ally elevation motions. +- Fellow: An account who is elevated from Ally by Founders and other Fellows. +- Ally: An account who would like to join the alliance. To become a voting member, Fellow or + Founder, it will need approval from the `MembershipManager` origin. Any account can join as an + Ally either by placing a deposit or by nomination from a voting member. +- Unscrupulous List: A list of bad websites and addresses, items can be added or removed by + Founders and Fellows. + +## Interface + +### Dispatchable Functions + +#### For General Users + +- `join_alliance` - Join the Alliance as an Ally. This requires a slashable deposit. + +#### For Members (All) + +- `retire` - Retire from the Alliance and release the caller's deposit. + +#### For Members (Founders/Fellows) + +- `propose` - Propose a motion. +- `vote` - Vote on a motion. +- `close` - Close a motion with enough votes or that has expired. +- `set_rule` - Initialize or update the Alliance's rule by IPFS CID. +- `announce` - Make announcement by IPFS CID. +- `nominate_ally` - Nominate a non-member to become an Ally, without deposit. +- `elevate_ally` - Approve an ally to become a Fellow. +- `kick_member` - Kick a member and slash its deposit. +- `add_unscrupulous_items` - Add some items, either accounts or websites, to the list of + unscrupulous items. +- `remove_unscrupulous_items` - Remove some items from the list of unscrupulous items. + +#### For Members (Only Founders) + +- `veto` - Veto on a motion about `set_rule` and `elevate_ally`. + +#### Root Calls + +- `init_founders` - Initialize the founding members. diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs new file mode 100644 index 0000000000000..527c35b58a5d8 --- /dev/null +++ b/frame/alliance/src/benchmarking.rs @@ -0,0 +1,791 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Alliance pallet benchmarking. + +use sp_runtime::traits::{Bounded, Hash, StaticLookup}; +use sp_std::{ + convert::{TryFrom, TryInto}, + mem::size_of, + prelude::*, +}; + +use frame_benchmarking::{account, benchmarks_instance_pallet}; +use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; +use frame_system::{Pallet as System, RawOrigin as SystemOrigin}; + +use super::{Call as AllianceCall, Pallet as Alliance, *}; + +const SEED: u32 = 0; + +const MAX_BYTES: u32 = 1_024; + +fn assert_last_event, I: 'static>(generic_event: >::Event) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +fn cid(input: impl AsRef<[u8]>) -> Cid { + use sha2::{Digest, Sha256}; + let mut hasher = Sha256::new(); + hasher.update(input); + let result = hasher.finalize(); + Cid::new_v0(&*result) +} + +fn rule(input: impl AsRef<[u8]>) -> Cid { + cid(input) +} + +fn announcement(input: impl AsRef<[u8]>) -> Cid { + cid(input) +} + +fn funded_account, I: 'static>(name: &'static str, index: u32) -> T::AccountId { + let account: T::AccountId = account(name, index, SEED); + T::Currency::make_free_balance_be(&account, BalanceOf::::max_value() / 100u8.into()); + account +} + +fn founder, I: 'static>(index: u32) -> T::AccountId { + funded_account::("founder", index) +} + +fn fellow, I: 'static>(index: u32) -> T::AccountId { + funded_account::("fellow", index) +} + +fn ally, I: 'static>(index: u32) -> T::AccountId { + funded_account::("ally", index) +} + +fn outsider, I: 'static>(index: u32) -> T::AccountId { + funded_account::("outsider", index) +} + +fn generate_unscrupulous_account, I: 'static>(index: u32) -> T::AccountId { + funded_account::("unscrupulous", index) +} + +fn set_members, I: 'static>() { + let founders: BoundedVec<_, T::MaxMembersCount> = + BoundedVec::try_from(vec![founder::(1), founder::(2)]).unwrap(); + Members::::insert(MemberRole::Founder, founders.clone()); + + let fellows: BoundedVec<_, T::MaxMembersCount> = + BoundedVec::try_from(vec![fellow::(1), fellow::(2)]).unwrap(); + fellows.iter().for_each(|who| { + T::Currency::reserve(&who, T::AllyDeposit::get()).unwrap(); + >::insert(&who, T::AllyDeposit::get()); + }); + Members::::insert(MemberRole::Fellow, fellows.clone()); + + let allies: BoundedVec<_, T::MaxMembersCount> = + BoundedVec::try_from(vec![ally::(1)]).unwrap(); + allies.iter().for_each(|who| { + T::Currency::reserve(&who, T::AllyDeposit::get()).unwrap(); + >::insert(&who, T::AllyDeposit::get()); + }); + Members::::insert(MemberRole::Ally, allies); + + T::InitializeMembers::initialize_members(&[founders.as_slice(), fellows.as_slice()].concat()); +} + +benchmarks_instance_pallet! { + // This tests when proposal is created and queued as "proposed" + propose_proposed { + let b in 1 .. MAX_BYTES; + let x in 2 .. T::MaxFounders::get(); + let y in 0 .. T::MaxFellows::get(); + let p in 1 .. T::MaxProposals::get(); + + let m = x + y; + + let bytes_in_storage = b + size_of::() as u32 + 32; + + // Construct `members`. + let founders = (0 .. x).map(founder::).collect::>(); + let proposer = founders[0].clone(); + let fellows = (0 .. y).map(fellow::).collect::>(); + + Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + + let threshold = m; + // Add previous proposals. + for i in 0 .. p - 1 { + // Proposals should be different so that different proposal hashes are generated + let proposal: T::Proposal = AllianceCall::::set_rule { + rule: rule(vec![i as u8; b as usize]) + }.into(); + Alliance::::propose( + SystemOrigin::Signed(proposer.clone()).into(), + threshold, + Box::new(proposal), + bytes_in_storage, + )?; + } + + let proposal: T::Proposal = AllianceCall::::set_rule { rule: rule(vec![p as u8; b as usize]) }.into(); + + }: propose(SystemOrigin::Signed(proposer.clone()), threshold, Box::new(proposal.clone()), bytes_in_storage) + verify { + // New proposal is recorded + let proposal_hash = T::Hashing::hash_of(&proposal); + assert_eq!(T::ProposalProvider::proposal_of(proposal_hash), Some(proposal)); + } + + vote { + // We choose 5 (3 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) + let x in 3 .. T::MaxFounders::get(); + let y in 2 .. T::MaxFellows::get(); + + let m = x + y; + + let p = T::MaxProposals::get(); + let b = MAX_BYTES; + let bytes_in_storage = b + size_of::() as u32 + 32; + + // Construct `members`. + let founders = (0 .. x).map(founder::).collect::>(); + let proposer = founders[0].clone(); + let fellows = (0 .. y).map(fellow::).collect::>(); + + let mut members = Vec::with_capacity(founders.len() + fellows.len()); + members.extend(founders.clone()); + members.extend(fellows.clone()); + + Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + + // Threshold is 1 less than the number of members so that one person can vote nay + let threshold = m - 1; + + // Add previous proposals + let mut last_hash = T::Hash::default(); + for i in 0 .. p { + // Proposals should be different so that different proposal hashes are generated + let proposal: T::Proposal = AllianceCall::::set_rule { + rule: rule(vec![i as u8; b as usize]) + }.into(); + Alliance::::propose( + SystemOrigin::Signed(proposer.clone()).into(), + threshold, + Box::new(proposal.clone()), + b, + )?; + last_hash = T::Hashing::hash_of(&proposal); + } + + let index = p - 1; + // Have almost everyone vote aye on last proposal, while keeping it from passing. + for j in 0 .. m - 3 { + let voter = &members[j as usize]; + Alliance::::vote( + SystemOrigin::Signed(voter.clone()).into(), + last_hash.clone(), + index, + true, + )?; + } + + let voter = members[m as usize - 3].clone(); + // Voter votes aye without resolving the vote. + Alliance::::vote( + SystemOrigin::Signed(voter.clone()).into(), + last_hash.clone(), + index, + true, + )?; + + // Voter switches vote to nay, but does not kill the vote, just updates + inserts + let approve = false; + + // Whitelist voter account from further DB operations. + let voter_key = frame_system::Account::::hashed_key_for(&voter); + frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into()); + }: _(SystemOrigin::Signed(voter), last_hash.clone(), index, approve) + verify { + } + + veto { + let p in 1 .. T::MaxProposals::get(); + + let m = 3; + let b = MAX_BYTES; + let bytes_in_storage = b + size_of::() as u32 + 32; + + // Construct `members`. + let founders = (0 .. m).map(founder::).collect::>(); + let vetor = founders[0].clone(); + + Alliance::::init_members(SystemOrigin::Root.into(), founders, vec![], vec![])?; + + // Threshold is one less than total members so that two nays will disapprove the vote + let threshold = m - 1; + + // Add proposals + let mut last_hash = T::Hash::default(); + for i in 0 .. p { + // Proposals should be different so that different proposal hashes are generated + let proposal: T::Proposal = AllianceCall::::set_rule { + rule: rule(vec![i as u8; b as usize]) + }.into(); + Alliance::::propose( + SystemOrigin::Signed(vetor.clone()).into(), + threshold, + Box::new(proposal.clone()), + bytes_in_storage, + )?; + last_hash = T::Hashing::hash_of(&proposal); + } + + }: _(SystemOrigin::Signed(vetor), last_hash.clone()) + verify { + // The proposal is removed + assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); + } + + close_early_disapproved { + // We choose 4 (2 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) + let x in 2 .. T::MaxFounders::get(); + let y in 2 .. T::MaxFellows::get(); + let p in 1 .. T::MaxProposals::get(); + + let m = x + y; + + let bytes = 100; + let bytes_in_storage = bytes + size_of::() as u32 + 32; + + // Construct `members`. + let founders = (0 .. x).map(founder::).collect::>(); + let fellows = (0 .. y).map(fellow::).collect::>(); + + let mut members = Vec::with_capacity(founders.len() + fellows.len()); + members.extend(founders.clone()); + members.extend(fellows.clone()); + + Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + + let proposer = members[0].clone(); + let voter = members[1].clone(); + + // Threshold is total members so that one nay will disapprove the vote + let threshold = m; + + // Add previous proposals + let mut last_hash = T::Hash::default(); + for i in 0 .. p { + // Proposals should be different so that different proposal hashes are generated + let proposal: T::Proposal = AllianceCall::::set_rule { + rule: rule(vec![i as u8; bytes as usize]) + }.into(); + Alliance::::propose( + SystemOrigin::Signed(proposer.clone()).into(), + threshold, + Box::new(proposal.clone()), + bytes_in_storage, + )?; + last_hash = T::Hashing::hash_of(&proposal); + assert_eq!(T::ProposalProvider::proposal_of(last_hash), Some(proposal)); + } + + let index = p - 1; + // Have most everyone vote aye on last proposal, while keeping it from passing. + for j in 2 .. m - 1 { + let voter = &members[j as usize]; + Alliance::::vote( + SystemOrigin::Signed(voter.clone()).into(), + last_hash.clone(), + index, + true, + )?; + } + + // Voter votes aye without resolving the vote. + Alliance::::vote( + SystemOrigin::Signed(voter.clone()).into(), + last_hash.clone(), + index, + true, + )?; + + // Voter switches vote to nay, which kills the vote + Alliance::::vote( + SystemOrigin::Signed(voter.clone()).into(), + last_hash.clone(), + index, + false, + )?; + + // Whitelist voter account from further DB operations. + let voter_key = frame_system::Account::::hashed_key_for(&voter); + frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into()); + }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::max_value(), bytes_in_storage) + verify { + // The last proposal is removed. + assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); + } + + close_early_approved { + let b in 1 .. MAX_BYTES; + // We choose 4 (2 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) + let x in 2 .. T::MaxFounders::get(); + let y in 2 .. T::MaxFellows::get(); + let p in 1 .. T::MaxProposals::get(); + + let m = x + y; + let bytes_in_storage = b + size_of::() as u32 + 32; + + // Construct `members`. + let founders = (0 .. x).map(founder::).collect::>(); + let fellows = (0 .. y).map(fellow::).collect::>(); + + let mut members = Vec::with_capacity(founders.len() + fellows.len()); + members.extend(founders.clone()); + members.extend(fellows.clone()); + + Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + + let proposer = members[0].clone(); + let voter = members[1].clone(); + + // Threshold is 2 so any two ayes will approve the vote + let threshold = 2; + + // Add previous proposals + let mut last_hash = T::Hash::default(); + for i in 0 .. p { + // Proposals should be different so that different proposal hashes are generated + let proposal: T::Proposal = AllianceCall::::set_rule { + rule: rule(vec![i as u8; b as usize]) + }.into(); + Alliance::::propose( + SystemOrigin::Signed(proposer.clone()).into(), + threshold, + Box::new(proposal.clone()), + bytes_in_storage, + )?; + last_hash = T::Hashing::hash_of(&proposal); + assert_eq!(T::ProposalProvider::proposal_of(last_hash), Some(proposal)); + } + + let index = p - 1; + // Caller switches vote to nay on their own proposal, allowing them to be the deciding approval vote + Alliance::::vote( + SystemOrigin::Signed(proposer.clone()).into(), + last_hash.clone(), + index, + false, + )?; + + // Have almost everyone vote nay on last proposal, while keeping it from failing. + for j in 2 .. m - 1 { + let voter = &members[j as usize]; + Alliance::::vote( + SystemOrigin::Signed(voter.clone()).into(), + last_hash.clone(), + index, + false, + )?; + } + + // Member zero is the first aye + Alliance::::vote( + SystemOrigin::Signed(members[0].clone()).into(), + last_hash.clone(), + index, + true, + )?; + + let voter = members[1].clone(); + // Caller switches vote to aye, which passes the vote + Alliance::::vote( + SystemOrigin::Signed(voter.clone()).into(), + last_hash.clone(), + index, + true, + )?; + }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::max_value(), bytes_in_storage) + verify { + // The last proposal is removed. + assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); + } + + close_disapproved { + // We choose 2 (2 founders / 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) + let x in 2 .. T::MaxFounders::get(); + let y in 2 .. T::MaxFellows::get(); + let p in 1 .. T::MaxProposals::get(); + + let m = x + y; + + let bytes = 100; + let bytes_in_storage = bytes + size_of::() as u32 + 32; + + // Construct `members`. + let founders = (0 .. x).map(founder::).collect::>(); + let fellows = (0 .. y).map(fellow::).collect::>(); + + let mut members = Vec::with_capacity(founders.len() + fellows.len()); + members.extend(founders.clone()); + members.extend(fellows.clone()); + + Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + + let proposer = members[0].clone(); + let voter = members[1].clone(); + + // Threshold is one less than total members so that two nays will disapprove the vote + let threshold = m - 1; + + // Add proposals + let mut last_hash = T::Hash::default(); + for i in 0 .. p { + // Proposals should be different so that different proposal hashes are generated + let proposal: T::Proposal = AllianceCall::::set_rule { + rule: rule(vec![i as u8; bytes as usize]) + }.into(); + Alliance::::propose( + SystemOrigin::Signed(proposer.clone()).into(), + threshold, + Box::new(proposal.clone()), + bytes_in_storage, + )?; + last_hash = T::Hashing::hash_of(&proposal); + assert_eq!(T::ProposalProvider::proposal_of(last_hash), Some(proposal)); + } + + let index = p - 1; + // Have almost everyone vote aye on last proposal, while keeping it from passing. + // A few abstainers will be the nay votes needed to fail the vote. + for j in 2 .. m - 1 { + let voter = &members[j as usize]; + Alliance::::vote( + SystemOrigin::Signed(voter.clone()).into(), + last_hash.clone(), + index, + true, + )?; + } + + Alliance::::vote( + SystemOrigin::Signed(voter.clone()).into(), + last_hash.clone(), + index, + false, + )?; + + System::::set_block_number(T::BlockNumber::max_value()); + + }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::max_value(), bytes_in_storage) + verify { + // The last proposal is removed. + assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); + } + + close_approved { + let b in 1 .. MAX_BYTES; + // We choose 4 (2 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) + let x in 2 .. T::MaxFounders::get(); + let y in 2 .. T::MaxFellows::get(); + let p in 1 .. T::MaxProposals::get(); + + let m = x + y; + let bytes_in_storage = b + size_of::() as u32 + 32; + + // Construct `members`. + let founders = (0 .. x).map(founder::).collect::>(); + let fellows = (0 .. y).map(fellow::).collect::>(); + + let mut members = Vec::with_capacity(founders.len() + fellows.len()); + members.extend(founders.clone()); + members.extend(fellows.clone()); + + Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + + let proposer = members[0].clone(); + let voter = members[1].clone(); + + // Threshold is two, so any two ayes will pass the vote + let threshold = 2; + + // Add proposals + let mut last_hash = T::Hash::default(); + for i in 0 .. p { + // Proposals should be different so that different proposal hashes are generated + let proposal: T::Proposal = AllianceCall::::set_rule { + rule: rule(vec![i as u8; b as usize]) + }.into(); + Alliance::::propose( + SystemOrigin::Signed(proposer.clone()).into(), + threshold, + Box::new(proposal.clone()), + bytes_in_storage, + )?; + last_hash = T::Hashing::hash_of(&proposal); + assert_eq!(T::ProposalProvider::proposal_of(last_hash), Some(proposal)); + } + + // The prime member votes aye, so abstentions default to aye. + Alliance::::vote( + SystemOrigin::Signed(proposer.clone()).into(), + last_hash.clone(), + p - 1, + true // Vote aye. + )?; + + let index = p - 1; + // Have almost everyone vote nay on last proposal, while keeping it from failing. + // A few abstainers will be the aye votes needed to pass the vote. + for j in 2 .. m - 1 { + let voter = &members[j as usize]; + Alliance::::vote( + SystemOrigin::Signed(voter.clone()).into(), + last_hash.clone(), + index, + false + )?; + } + + // caller is prime, prime already votes aye by creating the proposal + System::::set_block_number(T::BlockNumber::max_value()); + + }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::max_value(), bytes_in_storage) + verify { + // The last proposal is removed. + assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); + } + + init_members { + // at least 2 founders + let x in 2 .. T::MaxFounders::get(); + let y in 0 .. T::MaxFellows::get(); + let z in 0 .. T::MaxAllies::get(); + + let mut founders = (2 .. x).map(founder::).collect::>(); + let mut fellows = (0 .. y).map(fellow::).collect::>(); + let mut allies = (0 .. z).map(ally::).collect::>(); + + }: _(SystemOrigin::Root, founders.clone(), fellows.clone(), allies.clone()) + verify { + founders.sort(); + fellows.sort(); + allies.sort(); + assert_last_event::(Event::MembersInitialized { + founders: founders.clone(), + fellows: fellows.clone(), + allies: allies.clone(), + }.into()); + assert_eq!(Alliance::::members(MemberRole::Founder), founders); + assert_eq!(Alliance::::members(MemberRole::Fellow), fellows); + assert_eq!(Alliance::::members(MemberRole::Ally), allies); + } + + set_rule { + set_members::(); + + let rule = rule(b"hello world"); + + let call = Call::::set_rule { rule: rule.clone() }; + let origin = T::AdminOrigin::successful_origin(); + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_eq!(Alliance::::rule(), Some(rule.clone())); + assert_last_event::(Event::NewRuleSet { rule }.into()); + } + + announce { + set_members::(); + + let announcement = announcement(b"hello world"); + + let call = Call::::announce { announcement: announcement.clone() }; + let origin = T::AnnouncementOrigin::successful_origin(); + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert!(Alliance::::announcements().contains(&announcement)); + assert_last_event::(Event::Announced { announcement }.into()); + } + + remove_announcement { + set_members::(); + + let announcement = announcement(b"hello world"); + let announcements: BoundedVec<_, T::MaxAnnouncementsCount> = BoundedVec::try_from(vec![announcement.clone()]).unwrap(); + Announcements::::put(announcements); + + let call = Call::::remove_announcement { announcement: announcement.clone() }; + let origin = T::AnnouncementOrigin::successful_origin(); + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert!(Alliance::::announcements().is_empty()); + assert_last_event::(Event::AnnouncementRemoved { announcement }.into()); + } + + join_alliance { + set_members::(); + + let outsider = outsider::(1); + assert!(!Alliance::::is_member(&outsider)); + assert_eq!(DepositOf::::get(&outsider), None); + }: _(SystemOrigin::Signed(outsider.clone())) + verify { + assert!(Alliance::::is_member_of(&outsider, MemberRole::Ally)); // outsider is now an ally + assert_eq!(DepositOf::::get(&outsider), Some(T::AllyDeposit::get())); // with a deposit + assert!(!Alliance::::has_voting_rights(&outsider)); // allies don't have voting rights + assert_last_event::(Event::NewAllyJoined { + ally: outsider, + nominator: None, + reserved: Some(T::AllyDeposit::get()) + }.into()); + } + + nominate_ally { + set_members::(); + + let founder1 = founder::(1); + assert!(Alliance::::is_member_of(&founder1, MemberRole::Founder)); + + let outsider = outsider::(1); + assert!(!Alliance::::is_member(&outsider)); + assert_eq!(DepositOf::::get(&outsider), None); + + let outsider_lookup: ::Source = T::Lookup::unlookup(outsider.clone()); + }: _(SystemOrigin::Signed(founder1.clone()), outsider_lookup) + verify { + assert!(Alliance::::is_member_of(&outsider, MemberRole::Ally)); // outsider is now an ally + assert_eq!(DepositOf::::get(&outsider), None); // without a deposit + assert!(!Alliance::::has_voting_rights(&outsider)); // allies don't have voting rights + assert_last_event::(Event::NewAllyJoined { + ally: outsider, + nominator: Some(founder1), + reserved: None + }.into()); + } + + elevate_ally { + set_members::(); + + let ally1 = ally::(1); + assert!(Alliance::::is_ally(&ally1)); + + let ally1_lookup: ::Source = T::Lookup::unlookup(ally1.clone()); + let call = Call::::elevate_ally { ally: ally1_lookup }; + let origin = T::MembershipManager::successful_origin(); + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert!(!Alliance::::is_ally(&ally1)); + assert!(Alliance::::is_fellow(&ally1)); + assert_last_event::(Event::AllyElevated { ally: ally1 }.into()); + } + + retire { + set_members::(); + + let fellow2 = fellow::(2); + assert!(Alliance::::is_fellow(&fellow2)); + assert!(!Alliance::::is_up_for_kicking(&fellow2)); + + assert_eq!(DepositOf::::get(&fellow2), Some(T::AllyDeposit::get())); + }: _(SystemOrigin::Signed(fellow2.clone())) + verify { + assert!(!Alliance::::is_member(&fellow2)); + assert_eq!(DepositOf::::get(&fellow2), None); + assert_last_event::(Event::MemberRetired { + member: fellow2, + unreserved: Some(T::AllyDeposit::get()) + }.into()); + } + + kick_member { + set_members::(); + + let fellow2 = fellow::(2); + UpForKicking::::insert(&fellow2, true); + + assert!(Alliance::::is_member_of(&fellow2, MemberRole::Fellow)); + assert!(Alliance::::is_up_for_kicking(&fellow2)); + + assert_eq!(DepositOf::::get(&fellow2), Some(T::AllyDeposit::get())); + + let fellow2_lookup: ::Source = T::Lookup::unlookup(fellow2.clone()); + let call = Call::::kick_member { who: fellow2_lookup }; + let origin = T::MembershipManager::successful_origin(); + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert!(!Alliance::::is_member(&fellow2)); + assert_eq!(DepositOf::::get(&fellow2), None); + assert_last_event::(Event::MemberKicked { + member: fellow2, + slashed: Some(T::AllyDeposit::get()) + }.into()); + } + + add_unscrupulous_items { + let n in 1 .. T::MaxUnscrupulousItems::get(); + let l in 1 .. T::MaxWebsiteUrlLength::get(); + + set_members::(); + + let accounts = (0 .. n) + .map(|i| generate_unscrupulous_account::(i)) + .collect::>(); + let websites = (0 .. n).map(|i| -> BoundedVec { + BoundedVec::try_from(vec![i as u8; l as usize]).unwrap() + }).collect::>(); + + let mut unscrupulous_list = Vec::with_capacity(accounts.len() + websites.len()); + unscrupulous_list.extend(accounts.into_iter().map(UnscrupulousItem::AccountId)); + unscrupulous_list.extend(websites.into_iter().map(UnscrupulousItem::Website)); + + let call = Call::::add_unscrupulous_items { items: unscrupulous_list.clone() }; + let origin = T::AnnouncementOrigin::successful_origin(); + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_last_event::(Event::UnscrupulousItemAdded { items: unscrupulous_list }.into()); + } + + remove_unscrupulous_items { + let n in 1 .. T::MaxUnscrupulousItems::get(); + let l in 1 .. T::MaxWebsiteUrlLength::get(); + + set_members::(); + + let mut accounts = (0 .. n) + .map(|i| generate_unscrupulous_account::(i)) + .collect::>(); + accounts.sort(); + let accounts: BoundedVec<_, T::MaxUnscrupulousItems> = accounts.try_into().unwrap(); + UnscrupulousAccounts::::put(accounts.clone()); + + let mut websites = (0 .. n).map(|i| -> BoundedVec<_, T::MaxWebsiteUrlLength> + { BoundedVec::try_from(vec![i as u8; l as usize]).unwrap() }).collect::>(); + websites.sort(); + let websites: BoundedVec<_, T::MaxUnscrupulousItems> = websites.try_into().unwrap(); + UnscrupulousWebsites::::put(websites.clone()); + + let mut unscrupulous_list = Vec::with_capacity(accounts.len() + websites.len()); + unscrupulous_list.extend(accounts.into_iter().map(UnscrupulousItem::AccountId)); + unscrupulous_list.extend(websites.into_iter().map(UnscrupulousItem::Website)); + + let call = Call::::remove_unscrupulous_items { items: unscrupulous_list.clone() }; + let origin = T::AnnouncementOrigin::successful_origin(); + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_last_event::(Event::UnscrupulousItemRemoved { items: unscrupulous_list }.into()); + } + + impl_benchmark_test_suite!(Alliance, crate::mock::new_bench_ext(), crate::mock::Test); +} diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs new file mode 100644 index 0000000000000..f9e85e270af16 --- /dev/null +++ b/frame/alliance/src/lib.rs @@ -0,0 +1,1053 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Alliance Pallet +//! +//! The Alliance Pallet provides a collective that curates a list of accounts and URLs, deemed by +//! the voting members to be unscrupulous actors. The alliance +//! +//! - provides a set of ethics against bad behavior, and +//! - provides recognition and influence for those teams that contribute something back to the +//! ecosystem. +//! +//! ## Overview +//! +//! The network initializes the Alliance via a Root call. After that, anyone with an approved +//! identity and website can join as an Ally. The `MembershipManager` origin can elevate Allies to +//! Fellows, giving them voting rights within the Alliance. +//! +//! Voting members of the Alliance maintain a list of accounts and websites. Members can also vote +//! to update the Alliance's rule and make announcements. +//! +//! ### Terminology +//! +//! - Rule: The IPFS CID (hash) of the Alliance rules for the community to read and the Alliance +//! members to enforce. Similar to a Code of Conduct. +//! - Announcement: An IPFS CID of some content that the Alliance want to announce. +//! - Member: An account that is already in the group of the Alliance, including three types: +//! Founder, Fellow, or Ally. A member can also be kicked by the `MembershipManager` origin or +//! retire by itself. +//! - Founder: An account who is initiated by Root with normal voting rights for basic motions and +//! special veto rights for rule change and Ally elevation motions. +//! - Fellow: An account who is elevated from Ally by Founders and other Fellows. +//! - Ally: An account who would like to join the alliance. To become a voting member, Fellow or +//! Founder, it will need approval from the `MembershipManager` origin. Any account can join as an +//! Ally either by placing a deposit or by nomination from a voting member. +//! - Unscrupulous List: A list of bad websites and addresses, items can be added or removed by +//! Founders and Fellows. +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! #### For General Users +//! +//! - `join_alliance` - Join the Alliance as an Ally. This requires a slashable deposit. +//! +//! #### For Members (All) +//! +//! - `retire` - Retire from the Alliance and release the caller's deposit. +//! +//! #### For Members (Founders/Fellows) +//! +//! - `propose` - Propose a motion. +//! - `vote` - Vote on a motion. +//! - `close` - Close a motion with enough votes or that has expired. +//! - `set_rule` - Initialize or update the Alliance's rule by IPFS CID. +//! - `announce` - Make announcement by IPFS CID. +//! - `nominate_ally` - Nominate a non-member to become an Ally, without deposit. +//! - `elevate_ally` - Approve an ally to become a Fellow. +//! - `kick_member` - Kick a member and slash its deposit. +//! - `add_unscrupulous_items` - Add some items, either accounts or websites, to the list of +//! unscrupulous items. +//! - `remove_unscrupulous_items` - Remove some items from the list of unscrupulous items. +//! +//! #### For Members (Only Founders) +//! +//! - `veto` - Veto on a motion about `set_rule` and `elevate_ally`. +//! +//! #### Root Calls +//! +//! - `init_founders` - Initialize the founding members. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +mod types; +pub mod weights; + +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; +use sp_runtime::{ + traits::{StaticLookup, Zero}, + RuntimeDebug, +}; +use sp_std::{convert::TryInto, prelude::*}; + +use frame_support::{ + codec::{Decode, Encode, MaxEncodedLen}, + dispatch::{ + DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, + PostDispatchInfo, + }, + ensure, + scale_info::TypeInfo, + traits::{ + ChangeMembers, Currency, Get, InitializeMembers, IsSubType, OnUnbalanced, + ReservableCurrency, + }, + weights::Weight, +}; +use pallet_identity::IdentityField; + +pub use pallet::*; +pub use types::*; +pub use weights::*; + +/// Simple index type for proposal counting. +pub type ProposalIndex = u32; + +type UrlOf = BoundedVec>::MaxWebsiteUrlLength>; + +type BalanceOf = + <>::Currency as Currency<::AccountId>>::Balance; +type NegativeImbalanceOf = <>::Currency as Currency< + ::AccountId, +>>::NegativeImbalance; + +/// Interface required for identity verification. +pub trait IdentityVerifier { + /// Function that returns whether an account has an identity registered with the identity + /// provider. + fn has_identity(who: &AccountId, fields: u64) -> bool; + + /// Whether an account has been deemed "good" by the provider. + fn has_good_judgement(who: &AccountId) -> bool; + + /// If the identity provider allows sub-accounts, provide the super of an account. Should + /// return `None` if the provider does not allow sub-accounts or if the account is not a sub. + fn super_account_id(who: &AccountId) -> Option; +} + +/// The non-provider. Imposes no restrictions on account identity. +impl IdentityVerifier for () { + fn has_identity(_who: &AccountId, _fields: u64) -> bool { + true + } + + fn has_good_judgement(_who: &AccountId) -> bool { + true + } + + fn super_account_id(_who: &AccountId) -> Option { + None + } +} + +/// The provider of a collective action interface, for example an instance of `pallet-collective`. +pub trait ProposalProvider { + fn propose_proposal( + who: AccountId, + threshold: u32, + proposal: Box, + length_bound: u32, + ) -> Result<(u32, u32), DispatchError>; + + fn vote_proposal( + who: AccountId, + proposal: Hash, + index: ProposalIndex, + approve: bool, + ) -> Result; + + fn veto_proposal(proposal_hash: Hash) -> u32; + + fn close_proposal( + proposal_hash: Hash, + index: ProposalIndex, + proposal_weight_bound: Weight, + length_bound: u32, + ) -> DispatchResultWithPostInfo; + + fn proposal_of(proposal_hash: Hash) -> Option; +} + +/// The various roles that a member can hold. +#[derive(Copy, Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub enum MemberRole { + Founder, + Fellow, + Ally, +} + +/// The type of item that may be deemed unscrupulous. +#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub enum UnscrupulousItem { + AccountId(AccountId), + Website(Url), +} + +type UnscrupulousItemOf = + UnscrupulousItem<::AccountId, UrlOf>; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + #[pallet::generate_store(pub (super) trait Store)] + pub struct Pallet(PhantomData<(T, I)>); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// The outer call dispatch type. + type Proposal: Parameter + + Dispatchable + + From> + + From> + + GetDispatchInfo + + IsSubType> + + IsType<::Call>; + + /// Origin for admin-level operations, like setting the Alliance's rules. + type AdminOrigin: EnsureOrigin; + + /// Origin that manages entry and forcible discharge from the Alliance. + type MembershipManager: EnsureOrigin; + + /// Origin for making announcements and adding/removing unscrupulous items. + type AnnouncementOrigin: EnsureOrigin; + + /// The currency used for deposits. + type Currency: ReservableCurrency; + + /// What to do with slashed funds. + type Slashed: OnUnbalanced>; + + /// What to do with initial voting members of the Alliance. + type InitializeMembers: InitializeMembers; + + /// What to do when a member has been added or removed. + type MembershipChanged: ChangeMembers; + + /// The identity verifier of an Alliance member. + type IdentityVerifier: IdentityVerifier; + + /// The provider of the proposal operation. + type ProposalProvider: ProposalProvider; + + /// Maximum number of proposals allowed to be active in parallel. + type MaxProposals: Get; + + /// The maximum number of founders supported by the pallet. Used for weight estimation. + /// + /// NOTE: + /// + Benchmarks will need to be re-run and weights adjusted if this changes. + /// + This pallet assumes that dependencies keep to the limit without enforcing it. + type MaxFounders: Get; + + /// The maximum number of fellows supported by the pallet. Used for weight estimation. + /// + /// NOTE: + /// + Benchmarks will need to be re-run and weights adjusted if this changes. + /// + This pallet assumes that dependencies keep to the limit without enforcing it. + type MaxFellows: Get; + + /// The maximum number of allies supported by the pallet. Used for weight estimation. + /// + /// NOTE: + /// + Benchmarks will need to be re-run and weights adjusted if this changes. + /// + This pallet assumes that dependencies keep to the limit without enforcing it. + type MaxAllies: Get; + + /// The maximum number of the unscrupulous items supported by the pallet. + #[pallet::constant] + type MaxUnscrupulousItems: Get; + + /// The maximum length of a website URL. + #[pallet::constant] + type MaxWebsiteUrlLength: Get; + + /// The deposit required for submitting candidacy. + #[pallet::constant] + type AllyDeposit: Get>; + + /// The maximum number of announcements. + #[pallet::constant] + type MaxAnnouncementsCount: Get; + + /// The maximum number of members per member role. Should not exceed the sum of + /// `MaxFounders` and `MaxFellows`. + #[pallet::constant] + type MaxMembersCount: Get; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::error] + pub enum Error { + /// The founders/fellows/allies have already been initialized. + MembersAlreadyInitialized, + /// Account is already a member. + AlreadyMember, + /// Account is not a member. + NotMember, + /// Account is not an ally. + NotAlly, + /// Account is not a founder. + NotFounder, + /// This member is up for being kicked from the Alliance and cannot perform this operation. + UpForKicking, + /// Account does not have voting rights. + NoVotingRights, + /// Account is already an elevated (fellow) member. + AlreadyElevated, + /// Item is already listed as unscrupulous. + AlreadyUnscrupulous, + /// Account has been deemed unscrupulous by the Alliance and is not welcome to join or be + /// nominated. + AccountNonGrata, + /// Item has not been deemed unscrupulous. + NotListedAsUnscrupulous, + /// The number of unscrupulous items exceeds `MaxUnscrupulousItems`. + TooManyUnscrupulousItems, + /// Length of website URL exceeds `MaxWebsiteUrlLength`. + TooLongWebsiteUrl, + /// Balance is insufficient for the required deposit. + InsufficientFunds, + /// The account's identity does not have display field and website field. + WithoutIdentityDisplayAndWebsite, + /// The account's identity has no good judgement. + WithoutGoodIdentityJudgement, + /// The proposal hash is not found. + MissingProposalHash, + /// The proposal is not vetoable. + NotVetoableProposal, + /// The announcement is not found. + MissingAnnouncement, + /// Number of members exceeds `MaxMembersCount`. + TooManyMembers, + /// Number of announcements exceeds `MaxAnnouncementsCount`. + TooManyAnnouncements, + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// A new rule has been set. + NewRuleSet { rule: Cid }, + /// A new announcement has been proposed. + Announced { announcement: Cid }, + /// An on-chain announcement has been removed. + AnnouncementRemoved { announcement: Cid }, + /// Some accounts have been initialized as members (founders/fellows/allies). + MembersInitialized { + founders: Vec, + fellows: Vec, + allies: Vec, + }, + /// An account has been added as an Ally and reserved its deposit. + NewAllyJoined { + ally: T::AccountId, + nominator: Option, + reserved: Option>, + }, + /// An ally has been elevated to Fellow. + AllyElevated { ally: T::AccountId }, + /// A member has retired with its deposit unreserved. + MemberRetired { member: T::AccountId, unreserved: Option> }, + /// A member has been kicked out with its deposit slashed. + MemberKicked { member: T::AccountId, slashed: Option> }, + /// Accounts or websites have been added into the list of unscrupulous items. + UnscrupulousItemAdded { items: Vec> }, + /// Accounts or websites have been removed from the list of unscrupulous items. + UnscrupulousItemRemoved { items: Vec> }, + } + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + pub founders: Vec, + pub fellows: Vec, + pub allies: Vec, + pub phantom: PhantomData<(T, I)>, + } + + #[cfg(feature = "std")] + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + Self { + founders: Vec::new(), + fellows: Vec::new(), + allies: Vec::new(), + phantom: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { + for m in self.founders.iter().chain(self.fellows.iter()).chain(self.allies.iter()) { + assert!(Pallet::::has_identity(m).is_ok(), "Member does not set identity!"); + } + + if !self.founders.is_empty() { + assert!( + !Pallet::::has_member(MemberRole::Founder), + "Founders are already initialized!" + ); + let members: BoundedVec = + self.founders.clone().try_into().expect("Too many genesis founders"); + Members::::insert(MemberRole::Founder, members); + } + if !self.fellows.is_empty() { + assert!( + !Pallet::::has_member(MemberRole::Fellow), + "Fellows are already initialized!" + ); + let members: BoundedVec = + self.fellows.clone().try_into().expect("Too many genesis fellows"); + Members::::insert(MemberRole::Fellow, members); + } + if !self.allies.is_empty() { + let members: BoundedVec = + self.allies.clone().try_into().expect("Too many genesis allies"); + Members::::insert(MemberRole::Ally, members); + } + + T::InitializeMembers::initialize_members( + &[self.founders.as_slice(), self.fellows.as_slice()].concat(), + ) + } + } + + /// The IPFS CID of the alliance rule. + /// Founders and fellows can propose a new rule with a super-majority. + /// + /// Any founder has a special one-vote veto right to the rule setting. + #[pallet::storage] + #[pallet::getter(fn rule)] + pub type Rule, I: 'static = ()> = StorageValue<_, Cid, OptionQuery>; + + /// The current IPFS CIDs of any announcements. + #[pallet::storage] + #[pallet::getter(fn announcements)] + pub type Announcements, I: 'static = ()> = + StorageValue<_, BoundedVec, ValueQuery>; + + /// Maps members to their candidacy deposit. + #[pallet::storage] + #[pallet::getter(fn deposit_of)] + pub type DepositOf, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, T::AccountId, BalanceOf, OptionQuery>; + + /// Maps member type to members of each type. + #[pallet::storage] + #[pallet::getter(fn members)] + pub type Members, I: 'static = ()> = StorageMap< + _, + Twox64Concat, + MemberRole, + BoundedVec, + ValueQuery, + >; + + /// A set of members that are (potentially) being kicked out. They cannot retire until the + /// motion is settled. + #[pallet::storage] + #[pallet::getter(fn up_for_kicking)] + pub type UpForKicking, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, T::AccountId, bool, ValueQuery>; + + /// The current list of accounts deemed unscrupulous. These accounts non grata cannot submit + /// candidacy. + #[pallet::storage] + #[pallet::getter(fn unscrupulous_accounts)] + pub type UnscrupulousAccounts, I: 'static = ()> = + StorageValue<_, BoundedVec, ValueQuery>; + + /// The current list of websites deemed unscrupulous. + #[pallet::storage] + #[pallet::getter(fn unscrupulous_websites)] + pub type UnscrupulousWebsites, I: 'static = ()> = + StorageValue<_, BoundedVec, T::MaxUnscrupulousItems>, ValueQuery>; + + #[pallet::call] + impl, I: 'static> Pallet { + /// Add a new proposal to be voted on. + /// + /// Requires the sender to be a founder or fellow. + #[pallet::weight(T::WeightInfo::propose_proposed( + *length_bound, // B + T::MaxFounders::get(), // X + T::MaxFellows::get(), // Y + T::MaxProposals::get(), // P2 + ))] + pub fn propose( + origin: OriginFor, + #[pallet::compact] threshold: u32, + proposal: Box<>::Proposal>, + #[pallet::compact] length_bound: u32, + ) -> DispatchResult { + let proposor = ensure_signed(origin)?; + ensure!(Self::has_voting_rights(&proposor), Error::::NoVotingRights); + + if let Some(Call::kick_member { who }) = proposal.is_sub_type() { + let strike = T::Lookup::lookup(who.clone())?; + >::insert(strike, true); + } + + T::ProposalProvider::propose_proposal(proposor, threshold, proposal, length_bound)?; + Ok(()) + } + + /// Add an aye or nay vote for the sender to the given proposal. + /// + /// Requires the sender to be a founder or fellow. + #[pallet::weight(T::WeightInfo::vote(T::MaxFounders::get(), T::MaxFellows::get()))] + pub fn vote( + origin: OriginFor, + proposal: T::Hash, + #[pallet::compact] index: ProposalIndex, + approve: bool, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + ensure!(Self::has_voting_rights(&who), Error::::NoVotingRights); + + T::ProposalProvider::vote_proposal(who, proposal, index, approve)?; + Ok(()) + } + + /// Veto a proposal about `set_rule` and `elevate_ally`, close, and remove it from the + /// system, regardless of its current state. + /// + /// Must be called by a founder. + #[pallet::weight(T::WeightInfo::veto(T::MaxProposals::get()))] + pub fn veto(origin: OriginFor, proposal_hash: T::Hash) -> DispatchResult { + let proposor = ensure_signed(origin)?; + ensure!(Self::is_founder(&proposor), Error::::NotFounder); + + let proposal = T::ProposalProvider::proposal_of(proposal_hash) + .ok_or(Error::::MissingProposalHash)?; + match proposal.is_sub_type() { + Some(Call::set_rule { .. }) | Some(Call::elevate_ally { .. }) => { + T::ProposalProvider::veto_proposal(proposal_hash); + Ok(()) + }, + _ => Err(Error::::NotVetoableProposal.into()), + } + } + + /// Close a vote that is either approved, disapproved, or whose voting period has ended. + /// + /// Requires the sender to be a founder or fellow. + #[pallet::weight({ + let b = *length_bound; + let x = T::MaxFounders::get(); + let y = T::MaxFellows::get(); + let p1 = *proposal_weight_bound; + let p2 = T::MaxProposals::get(); + T::WeightInfo::close_early_approved(b, x, y, p2) + .max(T::WeightInfo::close_early_disapproved(x, y, p2)) + .max(T::WeightInfo::close_approved(b, x, y, p2)) + .max(T::WeightInfo::close_disapproved(x, y, p2)) + .saturating_add(p1) + })] + pub fn close( + origin: OriginFor, + proposal_hash: T::Hash, + #[pallet::compact] index: ProposalIndex, + #[pallet::compact] proposal_weight_bound: Weight, + #[pallet::compact] length_bound: u32, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!(Self::has_voting_rights(&who), Error::::NoVotingRights); + + let info = T::ProposalProvider::close_proposal( + proposal_hash, + index, + proposal_weight_bound, + length_bound, + )?; + Ok(info.into()) + } + + /// Initialize the founders, fellows, and allies. + /// + /// This should only be called once, and must be called by the Root origin. + #[pallet::weight(T::WeightInfo::init_members( + T::MaxFounders::get(), + T::MaxFellows::get(), + T::MaxAllies::get() + ))] + pub fn init_members( + origin: OriginFor, + founders: Vec, + fellows: Vec, + allies: Vec, + ) -> DispatchResult { + ensure_root(origin)?; + + let mut founders: BoundedVec = + founders.try_into().map_err(|_| Error::::TooManyMembers)?; + let mut fellows: BoundedVec = + fellows.try_into().map_err(|_| Error::::TooManyMembers)?; + let mut allies: BoundedVec = + allies.try_into().map_err(|_| Error::::TooManyMembers)?; + + ensure!( + !Self::has_member(MemberRole::Founder) && + !Self::has_member(MemberRole::Fellow) && + !Self::has_member(MemberRole::Ally), + Error::::MembersAlreadyInitialized + ); + for member in founders.iter().chain(fellows.iter()).chain(allies.iter()) { + Self::has_identity(member)?; + } + + founders.sort(); + Members::::insert(&MemberRole::Founder, founders.clone()); + fellows.sort(); + Members::::insert(&MemberRole::Fellow, fellows.clone()); + allies.sort(); + Members::::insert(&MemberRole::Ally, allies.clone()); + + let mut voteable_members = Vec::with_capacity(founders.len() + fellows.len()); + voteable_members.extend(founders.clone()); + voteable_members.extend(fellows.clone()); + voteable_members.sort(); + + T::InitializeMembers::initialize_members(&voteable_members); + + log::debug!( + target: "runtime::alliance", + "Initialize alliance founders: {:?}, fellows: {:?}, allies: {:?}", + founders, fellows, allies + ); + + Self::deposit_event(Event::MembersInitialized { + founders: founders.into(), + fellows: fellows.into(), + allies: allies.into(), + }); + Ok(()) + } + + /// Set a new IPFS CID to the alliance rule. + #[pallet::weight(T::WeightInfo::set_rule())] + pub fn set_rule(origin: OriginFor, rule: Cid) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin)?; + + Rule::::put(&rule); + + Self::deposit_event(Event::NewRuleSet { rule }); + Ok(()) + } + + /// Make an announcement of a new IPFS CID about alliance issues. + #[pallet::weight(T::WeightInfo::announce())] + pub fn announce(origin: OriginFor, announcement: Cid) -> DispatchResult { + T::AnnouncementOrigin::ensure_origin(origin)?; + + let mut announcements = >::get(); + announcements + .try_push(announcement.clone()) + .map_err(|_| Error::::TooManyAnnouncements)?; + >::put(announcements); + + Self::deposit_event(Event::Announced { announcement }); + Ok(()) + } + + /// Remove an announcement. + #[pallet::weight(T::WeightInfo::remove_announcement())] + pub fn remove_announcement(origin: OriginFor, announcement: Cid) -> DispatchResult { + T::AnnouncementOrigin::ensure_origin(origin)?; + + let mut announcements = >::get(); + let pos = announcements + .binary_search(&announcement) + .ok() + .ok_or(Error::::MissingAnnouncement)?; + announcements.remove(pos); + >::put(announcements); + + Self::deposit_event(Event::AnnouncementRemoved { announcement }); + Ok(()) + } + + /// Submit oneself for candidacy. A fixed deposit is reserved. + #[pallet::weight(T::WeightInfo::join_alliance())] + pub fn join_alliance(origin: OriginFor) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Unscrupulous accounts are non grata. + ensure!(!Self::is_unscrupulous_account(&who), Error::::AccountNonGrata); + ensure!(!Self::is_member(&who), Error::::AlreadyMember); + // check user self or parent should has verified identity to reuse display name and + // website. + Self::has_identity(&who)?; + + let deposit = T::AllyDeposit::get(); + T::Currency::reserve(&who, deposit).map_err(|_| Error::::InsufficientFunds)?; + >::insert(&who, deposit); + + Self::add_member(&who, MemberRole::Ally)?; + + Self::deposit_event(Event::NewAllyJoined { + ally: who, + nominator: None, + reserved: Some(deposit), + }); + Ok(()) + } + + /// A founder or fellow can nominate someone to join the alliance as an Ally. + /// There is no deposit required to the nominator or nominee. + #[pallet::weight(T::WeightInfo::nominate_ally())] + pub fn nominate_ally( + origin: OriginFor, + who: ::Source, + ) -> DispatchResult { + let nominator = ensure_signed(origin)?; + ensure!(Self::has_voting_rights(&nominator), Error::::NoVotingRights); + let who = T::Lookup::lookup(who)?; + + // Individual voting members cannot nominate accounts non grata. + ensure!(!Self::is_unscrupulous_account(&who), Error::::AccountNonGrata); + ensure!(!Self::is_member(&who), Error::::AlreadyMember); + // check user self or parent should has verified identity to reuse display name and + // website. + Self::has_identity(&who)?; + + Self::add_member(&who, MemberRole::Ally)?; + + Self::deposit_event(Event::NewAllyJoined { + ally: who, + nominator: Some(nominator), + reserved: None, + }); + Ok(()) + } + + /// Elevate an ally to fellow. + #[pallet::weight(T::WeightInfo::elevate_ally())] + pub fn elevate_ally( + origin: OriginFor, + ally: ::Source, + ) -> DispatchResult { + T::MembershipManager::ensure_origin(origin)?; + let ally = T::Lookup::lookup(ally)?; + ensure!(Self::is_ally(&ally), Error::::NotAlly); + ensure!(!Self::has_voting_rights(&ally), Error::::AlreadyElevated); + + Self::remove_member(&ally, MemberRole::Ally)?; + Self::add_member(&ally, MemberRole::Fellow)?; + + Self::deposit_event(Event::AllyElevated { ally }); + Ok(()) + } + + /// As a member, retire from the alliance and unreserve the deposit. + #[pallet::weight(T::WeightInfo::retire())] + pub fn retire(origin: OriginFor) -> DispatchResult { + let who = ensure_signed(origin)?; + // A member up for kicking cannot retire. + ensure!(!Self::is_up_for_kicking(&who), Error::::UpForKicking); + + let role = Self::member_role_of(&who).ok_or(Error::::NotMember)?; + Self::remove_member(&who, role)?; + let deposit = DepositOf::::take(&who); + if let Some(deposit) = deposit { + let err_amount = T::Currency::unreserve(&who, deposit); + debug_assert!(err_amount.is_zero()); + } + Self::deposit_event(Event::MemberRetired { member: who, unreserved: deposit }); + Ok(()) + } + + /// Kick a member from the alliance and slash its deposit. + #[pallet::weight(T::WeightInfo::kick_member())] + pub fn kick_member( + origin: OriginFor, + who: ::Source, + ) -> DispatchResult { + T::MembershipManager::ensure_origin(origin)?; + let member = T::Lookup::lookup(who)?; + + let role = Self::member_role_of(&member).ok_or(Error::::NotMember)?; + Self::remove_member(&member, role)?; + let deposit = DepositOf::::take(member.clone()); + if let Some(deposit) = deposit { + T::Slashed::on_unbalanced(T::Currency::slash_reserved(&member, deposit).0); + } + + >::remove(&member); + + Self::deposit_event(Event::MemberKicked { member, slashed: deposit }); + Ok(()) + } + + /// Add accounts or websites to the list of unscrupulous items. + #[pallet::weight(T::WeightInfo::add_unscrupulous_items(items.len() as u32, T::MaxWebsiteUrlLength::get()))] + pub fn add_unscrupulous_items( + origin: OriginFor, + items: Vec>, + ) -> DispatchResult { + T::AnnouncementOrigin::ensure_origin(origin)?; + + let mut accounts = vec![]; + let mut webs = vec![]; + for info in items.iter() { + ensure!(!Self::is_unscrupulous(info), Error::::AlreadyUnscrupulous); + match info { + UnscrupulousItem::AccountId(who) => accounts.push(who.clone()), + UnscrupulousItem::Website(url) => { + ensure!( + url.len() as u32 <= T::MaxWebsiteUrlLength::get(), + Error::::TooLongWebsiteUrl + ); + webs.push(url.clone()); + }, + } + } + + Self::do_add_unscrupulous_items(&mut accounts, &mut webs)?; + Self::deposit_event(Event::UnscrupulousItemAdded { items }); + Ok(()) + } + + /// Deem an item no longer unscrupulous. + #[pallet::weight(>::WeightInfo::remove_unscrupulous_items( + items.len() as u32, T::MaxWebsiteUrlLength::get() + ))] + pub fn remove_unscrupulous_items( + origin: OriginFor, + items: Vec>, + ) -> DispatchResult { + T::AnnouncementOrigin::ensure_origin(origin)?; + let mut accounts = vec![]; + let mut webs = vec![]; + for info in items.iter() { + ensure!(Self::is_unscrupulous(info), Error::::NotListedAsUnscrupulous); + match info { + UnscrupulousItem::AccountId(who) => accounts.push(who.clone()), + UnscrupulousItem::Website(url) => webs.push(url.clone()), + } + } + Self::do_remove_unscrupulous_items(&mut accounts, &mut webs)?; + Self::deposit_event(Event::UnscrupulousItemRemoved { items }); + Ok(()) + } + } +} + +impl, I: 'static> Pallet { + /// Check if a given role has any members. + fn has_member(role: MemberRole) -> bool { + Members::::decode_len(role).unwrap_or_default() > 0 + } + + /// Look up the role, if any, of an account. + fn member_role_of(who: &T::AccountId) -> Option { + Members::::iter() + .find_map(|(r, members)| if members.contains(who) { Some(r) } else { None }) + } + + /// Check if a user is a alliance member. + pub fn is_member(who: &T::AccountId) -> bool { + Self::member_role_of(who).is_some() + } + + /// Check if an account has a given role. + pub fn is_member_of(who: &T::AccountId, role: MemberRole) -> bool { + Members::::get(role).contains(&who) + } + + /// Check if an account is a founder. + fn is_founder(who: &T::AccountId) -> bool { + Self::is_member_of(who, MemberRole::Founder) + } + + /// Check if an account is a fellow. + fn is_fellow(who: &T::AccountId) -> bool { + Self::is_member_of(who, MemberRole::Fellow) + } + + /// Check if an account is an ally. + fn is_ally(who: &T::AccountId) -> bool { + Self::is_member_of(who, MemberRole::Ally) + } + + /// Check if a member has voting rights. + fn has_voting_rights(who: &T::AccountId) -> bool { + Self::is_founder(who) || Self::is_fellow(who) + } + + /// Collect all members who have voting rights into one list. + fn votable_members_sorted() -> Vec { + let mut founders = Members::::get(MemberRole::Founder).into_inner(); + let mut fellows = Members::::get(MemberRole::Fellow).into_inner(); + founders.append(&mut fellows); + founders.sort(); + founders.into() + } + + /// Check if an account's forced removal is up for consideration. + fn is_up_for_kicking(who: &T::AccountId) -> bool { + >::contains_key(&who) + } + + /// Add a user to the sorted alliance member set. + fn add_member(who: &T::AccountId, role: MemberRole) -> DispatchResult { + >::try_mutate(role, |members| -> DispatchResult { + let pos = members.binary_search(who).err().ok_or(Error::::AlreadyMember)?; + members + .try_insert(pos, who.clone()) + .map_err(|_| Error::::TooManyMembers)?; + Ok(()) + })?; + + if role == MemberRole::Founder || role == MemberRole::Fellow { + let members = Self::votable_members_sorted(); + T::MembershipChanged::change_members_sorted(&[who.clone()], &[], &members[..]); + } + Ok(()) + } + + /// Remove a user from the alliance member set. + fn remove_member(who: &T::AccountId, role: MemberRole) -> DispatchResult { + >::try_mutate(role, |members| -> DispatchResult { + let pos = members.binary_search(who).ok().ok_or(Error::::NotMember)?; + members.remove(pos); + Ok(()) + })?; + + if matches!(role, MemberRole::Founder | MemberRole::Fellow) { + let members = Self::votable_members_sorted(); + T::MembershipChanged::change_members_sorted(&[], &[who.clone()], &members[..]); + } + Ok(()) + } + + /// Check if an item is listed as unscrupulous. + fn is_unscrupulous(info: &UnscrupulousItemOf) -> bool { + match info { + UnscrupulousItem::Website(url) => >::get().contains(url), + UnscrupulousItem::AccountId(who) => >::get().contains(who), + } + } + + /// Check if an account is listed as unscrupulous. + fn is_unscrupulous_account(who: &T::AccountId) -> bool { + >::get().contains(who) + } + + /// Add item to the unscrupulous list. + fn do_add_unscrupulous_items( + new_accounts: &mut Vec, + new_webs: &mut Vec>, + ) -> DispatchResult { + if !new_accounts.is_empty() { + >::try_mutate(|accounts| -> DispatchResult { + accounts + .try_append(new_accounts) + .map_err(|_| Error::::TooManyUnscrupulousItems)?; + accounts.sort(); + + Ok(()) + })?; + } + if !new_webs.is_empty() { + >::try_mutate(|webs| -> DispatchResult { + webs.try_append(new_webs).map_err(|_| Error::::TooManyUnscrupulousItems)?; + webs.sort(); + + Ok(()) + })?; + } + + Ok(()) + } + + /// Remove item from the unscrupulous list. + fn do_remove_unscrupulous_items( + out_accounts: &mut Vec, + out_webs: &mut Vec>, + ) -> DispatchResult { + if !out_accounts.is_empty() { + >::try_mutate(|accounts| -> DispatchResult { + for who in out_accounts.iter() { + let pos = accounts + .binary_search(who) + .ok() + .ok_or(Error::::NotListedAsUnscrupulous)?; + accounts.remove(pos); + } + Ok(()) + })?; + } + if !out_webs.is_empty() { + >::try_mutate(|webs| -> DispatchResult { + for web in out_webs.iter() { + let pos = webs + .binary_search(web) + .ok() + .ok_or(Error::::NotListedAsUnscrupulous)?; + webs.remove(pos); + } + Ok(()) + })?; + } + Ok(()) + } + + fn has_identity(who: &T::AccountId) -> DispatchResult { + const IDENTITY_FIELD_DISPLAY: u64 = IdentityField::Display as u64; + const IDENTITY_FIELD_WEB: u64 = IdentityField::Web as u64; + + let judgement = |who: &T::AccountId| -> DispatchResult { + ensure!( + T::IdentityVerifier::has_identity(who, IDENTITY_FIELD_DISPLAY | IDENTITY_FIELD_WEB), + Error::::WithoutIdentityDisplayAndWebsite + ); + ensure!( + T::IdentityVerifier::has_good_judgement(who), + Error::::WithoutGoodIdentityJudgement + ); + Ok(()) + }; + + let res = judgement(who); + if res.is_err() { + if let Some(parent) = T::IdentityVerifier::super_account_id(who) { + return judgement(&parent) + } + } + res + } +} diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs new file mode 100644 index 0000000000000..d6e9a92a10dec --- /dev/null +++ b/frame/alliance/src/mock.rs @@ -0,0 +1,324 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Test utilities + +pub use sp_core::H256; +pub use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; +use sp_std::convert::{TryFrom, TryInto}; + +pub use frame_support::{ + assert_ok, ord_parameter_types, parameter_types, + traits::{EitherOfDiverse, GenesisBuild, SortedMembers}, + BoundedVec, +}; +use frame_system::{EnsureRoot, EnsureSignedBy}; +use pallet_identity::{Data, IdentityInfo, Judgement}; + +pub use crate as pallet_alliance; + +use super::*; + +parameter_types! { + pub const BlockHashCount: u64 = 250; +} +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 10; +} +impl pallet_balances::Config for Test { + type Balance = u64; + type DustRemoval = (); + type Event = Event; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = MaxLocks; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; +} + +parameter_types! { + pub const MotionDuration: u64 = 3; + pub const MaxProposals: u32 = 100; + pub const MaxMembers: u32 = 100; +} +type AllianceCollective = pallet_collective::Instance1; +impl pallet_collective::Config for Test { + type Origin = Origin; + type Proposal = Call; + type Event = Event; + type MotionDuration = MotionDuration; + type MaxProposals = MaxProposals; + type MaxMembers = MaxMembers; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type WeightInfo = (); +} + +parameter_types! { + pub const BasicDeposit: u64 = 10; + pub const FieldDeposit: u64 = 10; + pub const SubAccountDeposit: u64 = 10; + pub const MaxSubAccounts: u32 = 2; + pub const MaxAdditionalFields: u32 = 2; + pub const MaxRegistrars: u32 = 20; +} +ord_parameter_types! { + pub const One: u64 = 1; + pub const Two: u64 = 2; + pub const Three: u64 = 3; + pub const Four: u64 = 4; + pub const Five: u64 = 5; +} +type EnsureOneOrRoot = EitherOfDiverse, EnsureSignedBy>; +type EnsureTwoOrRoot = EitherOfDiverse, EnsureSignedBy>; + +impl pallet_identity::Config for Test { + type Event = Event; + type Currency = Balances; + type BasicDeposit = BasicDeposit; + type FieldDeposit = FieldDeposit; + type SubAccountDeposit = SubAccountDeposit; + type MaxSubAccounts = MaxSubAccounts; + type MaxAdditionalFields = MaxAdditionalFields; + type MaxRegistrars = MaxRegistrars; + type Slashed = (); + type RegistrarOrigin = EnsureOneOrRoot; + type ForceOrigin = EnsureTwoOrRoot; + type WeightInfo = (); +} + +pub struct AllianceIdentityVerifier; +impl IdentityVerifier for AllianceIdentityVerifier { + fn has_identity(who: &u64, fields: u64) -> bool { + Identity::has_identity(who, fields) + } + + fn has_good_judgement(who: &u64) -> bool { + if let Some(judgements) = + Identity::identity(who).map(|registration| registration.judgements) + { + judgements + .iter() + .any(|(_, j)| matches!(j, Judgement::KnownGood | Judgement::Reasonable)) + } else { + false + } + } + + fn super_account_id(who: &u64) -> Option { + Identity::super_of(who).map(|parent| parent.0) + } +} + +pub struct AllianceProposalProvider; +impl ProposalProvider for AllianceProposalProvider { + fn propose_proposal( + who: u64, + threshold: u32, + proposal: Box, + length_bound: u32, + ) -> Result<(u32, u32), DispatchError> { + AllianceMotion::do_propose_proposed(who, threshold, proposal, length_bound) + } + + fn vote_proposal( + who: u64, + proposal: H256, + index: ProposalIndex, + approve: bool, + ) -> Result { + AllianceMotion::do_vote(who, proposal, index, approve) + } + + fn veto_proposal(proposal_hash: H256) -> u32 { + AllianceMotion::do_disapprove_proposal(proposal_hash) + } + + fn close_proposal( + proposal_hash: H256, + proposal_index: ProposalIndex, + proposal_weight_bound: Weight, + length_bound: u32, + ) -> DispatchResultWithPostInfo { + AllianceMotion::do_close(proposal_hash, proposal_index, proposal_weight_bound, length_bound) + } + + fn proposal_of(proposal_hash: H256) -> Option { + AllianceMotion::proposal_of(proposal_hash) + } +} + +parameter_types! { + pub const MaxFounders: u32 = 10; + pub const MaxFellows: u32 = MaxMembers::get() - MaxFounders::get(); + pub const MaxAllies: u32 = 100; + pub const AllyDeposit: u64 = 25; +} +impl Config for Test { + type Event = Event; + type Proposal = Call; + type AdminOrigin = EnsureSignedBy; + type MembershipManager = EnsureSignedBy; + type AnnouncementOrigin = EnsureSignedBy; + type Currency = Balances; + type Slashed = (); + type InitializeMembers = AllianceMotion; + type MembershipChanged = AllianceMotion; + #[cfg(not(feature = "runtime-benchmarks"))] + type IdentityVerifier = AllianceIdentityVerifier; + #[cfg(feature = "runtime-benchmarks")] + type IdentityVerifier = (); + type ProposalProvider = AllianceProposalProvider; + type MaxProposals = MaxProposals; + type MaxFounders = MaxFounders; + type MaxFellows = MaxFellows; + type MaxAllies = MaxAllies; + type MaxUnscrupulousItems = ConstU32<100>; + type MaxWebsiteUrlLength = ConstU32<255>; + type MaxAnnouncementsCount = ConstU32<100>; + type MaxMembersCount = MaxMembers; + type AllyDeposit = AllyDeposit; + type WeightInfo = (); +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Balances: pallet_balances, + Identity: pallet_identity, + AllianceMotion: pallet_collective::, + Alliance: pallet_alliance, + } +); + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(1, 50), (2, 50), (3, 50), (4, 50), (5, 30), (6, 50), (7, 50)], + } + .assimilate_storage(&mut t) + .unwrap(); + + GenesisBuild::::assimilate_storage( + &pallet_alliance::GenesisConfig { + founders: vec![], + fellows: vec![], + allies: vec![], + phantom: Default::default(), + }, + &mut t, + ) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + assert_ok!(Identity::add_registrar(Origin::signed(1), 1)); + + let info = IdentityInfo { + additional: BoundedVec::default(), + display: Data::Raw(b"name".to_vec().try_into().unwrap()), + legal: Data::default(), + web: Data::Raw(b"website".to_vec().try_into().unwrap()), + riot: Data::default(), + email: Data::default(), + pgp_fingerprint: None, + image: Data::default(), + twitter: Data::default(), + }; + assert_ok!(Identity::set_identity(Origin::signed(1), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 1, Judgement::KnownGood)); + assert_ok!(Identity::set_identity(Origin::signed(2), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 2, Judgement::KnownGood)); + assert_ok!(Identity::set_identity(Origin::signed(3), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 3, Judgement::KnownGood)); + assert_ok!(Identity::set_identity(Origin::signed(4), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 4, Judgement::KnownGood)); + assert_ok!(Identity::set_identity(Origin::signed(5), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 5, Judgement::KnownGood)); + assert_ok!(Identity::set_identity(Origin::signed(6), Box::new(info.clone()))); + + assert_ok!(Alliance::init_members(Origin::root(), vec![1, 2], vec![3], vec![])); + + System::set_block_number(1); + }); + ext +} + +#[cfg(feature = "runtime-benchmarks")] +pub fn new_bench_ext() -> sp_io::TestExternalities { + GenesisConfig::default().build_storage().unwrap().into() +} + +pub fn test_cid() -> Cid { + use sha2::{Digest, Sha256}; + let mut hasher = Sha256::new(); + hasher.update(b"hello world"); + let result = hasher.finalize(); + Cid::new_v0(&*result) +} + +pub fn make_proposal(value: u64) -> Call { + Call::System(frame_system::Call::remark { remark: value.encode() }) +} + +pub fn make_set_rule_proposal(rule: Cid) -> Call { + Call::Alliance(pallet_alliance::Call::set_rule { rule }) +} + +pub fn make_kick_member_proposal(who: u64) -> Call { + Call::Alliance(pallet_alliance::Call::kick_member { who }) +} diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs new file mode 100644 index 0000000000000..85c91b451d351 --- /dev/null +++ b/frame/alliance/src/tests.rs @@ -0,0 +1,483 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for the alliance pallet. + +use sp_runtime::traits::Hash; + +use frame_support::{assert_noop, assert_ok, Hashable}; +use frame_system::{EventRecord, Phase}; + +use super::*; +use crate::mock::*; + +type AllianceMotionEvent = pallet_collective::Event; + +#[test] +fn propose_works() { + new_test_ext().execute_with(|| { + let proposal = make_proposal(42); + let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); + let hash: H256 = proposal.blake2_256().into(); + + // only votable member can propose proposal, 4 is ally not have vote rights + assert_noop!( + Alliance::propose(Origin::signed(4), 3, Box::new(proposal.clone()), proposal_len), + Error::::NoVotingRights + ); + + assert_ok!(Alliance::propose( + Origin::signed(1), + 3, + Box::new(proposal.clone()), + proposal_len + )); + assert_eq!(*AllianceMotion::proposals(), vec![hash]); + assert_eq!(AllianceMotion::proposal_of(&hash), Some(proposal)); + assert_eq!( + System::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash, + threshold: 3, + }), + topics: vec![], + }] + ); + }); +} + +#[test] +fn vote_works() { + new_test_ext().execute_with(|| { + let proposal = make_proposal(42); + let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(Alliance::propose( + Origin::signed(1), + 3, + Box::new(proposal.clone()), + proposal_len + )); + assert_ok!(Alliance::vote(Origin::signed(2), hash.clone(), 0, true)); + + let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; + assert_eq!( + System::events(), + vec![ + record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash.clone(), + threshold: 3 + })), + record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + account: 2, + proposal_hash: hash.clone(), + voted: true, + yes: 1, + no: 0, + })), + ] + ); + }); +} + +#[test] +fn veto_works() { + new_test_ext().execute_with(|| { + let proposal = make_proposal(42); + let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(Alliance::propose( + Origin::signed(1), + 3, + Box::new(proposal.clone()), + proposal_len + )); + // only set_rule/elevate_ally can be veto + assert_noop!( + Alliance::veto(Origin::signed(1), hash.clone()), + Error::::NotVetoableProposal + ); + + let cid = test_cid(); + let vetoable_proposal = make_set_rule_proposal(cid); + let vetoable_proposal_len: u32 = vetoable_proposal.using_encoded(|p| p.len() as u32); + let vetoable_hash: H256 = vetoable_proposal.blake2_256().into(); + assert_ok!(Alliance::propose( + Origin::signed(1), + 3, + Box::new(vetoable_proposal.clone()), + vetoable_proposal_len + )); + + // only founder have veto rights, 3 is fellow + assert_noop!( + Alliance::veto(Origin::signed(3), vetoable_hash.clone()), + Error::::NotFounder + ); + + assert_ok!(Alliance::veto(Origin::signed(2), vetoable_hash.clone())); + let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; + assert_eq!( + System::events(), + vec![ + record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash.clone(), + threshold: 3 + })), + record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + account: 1, + proposal_index: 1, + proposal_hash: vetoable_hash.clone(), + threshold: 3 + })), + record(mock::Event::AllianceMotion(AllianceMotionEvent::Disapproved { + proposal_hash: vetoable_hash.clone() + })), + ] + ); + }) +} + +#[test] +fn close_works() { + new_test_ext().execute_with(|| { + let proposal = make_proposal(42); + let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); + let proposal_weight = proposal.get_dispatch_info().weight; + let hash = BlakeTwo256::hash_of(&proposal); + assert_ok!(Alliance::propose( + Origin::signed(1), + 3, + Box::new(proposal.clone()), + proposal_len + )); + assert_ok!(Alliance::vote(Origin::signed(1), hash.clone(), 0, true)); + assert_ok!(Alliance::vote(Origin::signed(2), hash.clone(), 0, true)); + assert_ok!(Alliance::vote(Origin::signed(3), hash.clone(), 0, true)); + assert_ok!(Alliance::close( + Origin::signed(1), + hash.clone(), + 0, + proposal_weight, + proposal_len + )); + + let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; + assert_eq!( + System::events(), + vec![ + record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + account: 1, + proposal_index: 0, + proposal_hash: hash.clone(), + threshold: 3 + })), + record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + account: 1, + proposal_hash: hash.clone(), + voted: true, + yes: 1, + no: 0, + })), + record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + account: 2, + proposal_hash: hash.clone(), + voted: true, + yes: 2, + no: 0, + })), + record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + account: 3, + proposal_hash: hash.clone(), + voted: true, + yes: 3, + no: 0, + })), + record(mock::Event::AllianceMotion(AllianceMotionEvent::Closed { + proposal_hash: hash.clone(), + yes: 3, + no: 0, + })), + record(mock::Event::AllianceMotion(AllianceMotionEvent::Approved { + proposal_hash: hash.clone() + })), + record(mock::Event::AllianceMotion(AllianceMotionEvent::Executed { + proposal_hash: hash.clone(), + result: Err(DispatchError::BadOrigin), + })) + ] + ); + }); +} + +#[test] +fn set_rule_works() { + new_test_ext().execute_with(|| { + let cid = test_cid(); + assert_ok!(Alliance::set_rule(Origin::signed(1), cid.clone())); + assert_eq!(Alliance::rule(), Some(cid.clone())); + + System::assert_last_event(mock::Event::Alliance(crate::Event::NewRuleSet { rule: cid })); + }); +} + +#[test] +fn announce_works() { + new_test_ext().execute_with(|| { + let cid = test_cid(); + assert_ok!(Alliance::announce(Origin::signed(3), cid.clone())); + assert_eq!(Alliance::announcements(), vec![cid.clone()]); + + System::assert_last_event(mock::Event::Alliance(crate::Event::Announced { + announcement: cid, + })); + }); +} + +#[test] +fn remove_announcement_works() { + new_test_ext().execute_with(|| { + let cid = test_cid(); + assert_ok!(Alliance::announce(Origin::signed(3), cid.clone())); + assert_eq!(Alliance::announcements(), vec![cid.clone()]); + System::assert_last_event(mock::Event::Alliance(crate::Event::Announced { + announcement: cid.clone(), + })); + + System::set_block_number(2); + + assert_ok!(Alliance::remove_announcement(Origin::signed(3), cid.clone())); + assert_eq!(Alliance::announcements(), vec![]); + System::assert_last_event(mock::Event::Alliance(crate::Event::AnnouncementRemoved { + announcement: cid, + })); + }); +} + +#[test] +fn join_alliance_works() { + new_test_ext().execute_with(|| { + // check already member + assert_noop!(Alliance::join_alliance(Origin::signed(1)), Error::::AlreadyMember); + + // check already listed as unscrupulous + assert_ok!(Alliance::add_unscrupulous_items( + Origin::signed(3), + vec![UnscrupulousItem::AccountId(4)] + )); + assert_noop!( + Alliance::join_alliance(Origin::signed(4)), + Error::::AccountNonGrata + ); + assert_ok!(Alliance::remove_unscrupulous_items( + Origin::signed(3), + vec![UnscrupulousItem::AccountId(4)] + )); + + // check deposit funds + assert_noop!( + Alliance::join_alliance(Origin::signed(5)), + Error::::InsufficientFunds + ); + + // success to submit + assert_ok!(Alliance::join_alliance(Origin::signed(4))); + assert_eq!(Alliance::deposit_of(4), Some(25)); + assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); + + // check already member + assert_noop!(Alliance::join_alliance(Origin::signed(4)), Error::::AlreadyMember); + + // check missing identity judgement + #[cfg(not(feature = "runtime-benchmarks"))] + assert_noop!( + Alliance::join_alliance(Origin::signed(6)), + Error::::WithoutGoodIdentityJudgement + ); + // check missing identity info + #[cfg(not(feature = "runtime-benchmarks"))] + assert_noop!( + Alliance::join_alliance(Origin::signed(7)), + Error::::WithoutIdentityDisplayAndWebsite + ); + }); +} + +#[test] +fn nominate_ally_works() { + new_test_ext().execute_with(|| { + // check already member + assert_noop!( + Alliance::nominate_ally(Origin::signed(1), 2), + Error::::AlreadyMember + ); + + // only votable member(founder/fellow) have nominate right + assert_noop!( + Alliance::nominate_ally(Origin::signed(5), 4), + Error::::NoVotingRights + ); + + // check already listed as unscrupulous + assert_ok!(Alliance::add_unscrupulous_items( + Origin::signed(3), + vec![UnscrupulousItem::AccountId(4)] + )); + assert_noop!( + Alliance::nominate_ally(Origin::signed(1), 4), + Error::::AccountNonGrata + ); + assert_ok!(Alliance::remove_unscrupulous_items( + Origin::signed(3), + vec![UnscrupulousItem::AccountId(4)] + )); + + // success to nominate + assert_ok!(Alliance::nominate_ally(Origin::signed(1), 4)); + assert_eq!(Alliance::deposit_of(4), None); + assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); + + // check already member + assert_noop!( + Alliance::nominate_ally(Origin::signed(1), 4), + Error::::AlreadyMember + ); + + // check missing identity judgement + #[cfg(not(feature = "runtime-benchmarks"))] + assert_noop!( + Alliance::join_alliance(Origin::signed(6)), + Error::::WithoutGoodIdentityJudgement + ); + // check missing identity info + #[cfg(not(feature = "runtime-benchmarks"))] + assert_noop!( + Alliance::join_alliance(Origin::signed(7)), + Error::::WithoutIdentityDisplayAndWebsite + ); + }); +} + +#[test] +fn elevate_ally_works() { + new_test_ext().execute_with(|| { + assert_noop!(Alliance::elevate_ally(Origin::signed(2), 4), Error::::NotAlly); + + assert_ok!(Alliance::join_alliance(Origin::signed(4))); + assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); + + assert_ok!(Alliance::elevate_ally(Origin::signed(2), 4)); + assert_eq!(Alliance::members(MemberRole::Ally), Vec::::new()); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![3, 4]); + }); +} + +#[test] +fn retire_works() { + new_test_ext().execute_with(|| { + let proposal = make_kick_member_proposal(2); + let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); + assert_ok!(Alliance::propose( + Origin::signed(1), + 3, + Box::new(proposal.clone()), + proposal_len + )); + assert_noop!(Alliance::retire(Origin::signed(2)), Error::::UpForKicking); + + assert_noop!(Alliance::retire(Origin::signed(4)), Error::::NotMember); + + assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); + assert_ok!(Alliance::retire(Origin::signed(3))); + assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); + }); +} + +#[test] +fn kick_member_works() { + new_test_ext().execute_with(|| { + let proposal = make_kick_member_proposal(2); + let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); + assert_ok!(Alliance::propose( + Origin::signed(1), + 3, + Box::new(proposal.clone()), + proposal_len + )); + assert_eq!(Alliance::up_for_kicking(2), true); + assert_eq!(Alliance::members(MemberRole::Founder), vec![1, 2]); + + assert_ok!(Alliance::kick_member(Origin::signed(2), 2)); + assert_eq!(Alliance::members(MemberRole::Founder), vec![1]); + }); +} + +#[test] +fn add_unscrupulous_items_works() { + new_test_ext().execute_with(|| { + assert_ok!(Alliance::add_unscrupulous_items( + Origin::signed(3), + vec![ + UnscrupulousItem::AccountId(3), + UnscrupulousItem::Website("abc".as_bytes().to_vec().try_into().unwrap()) + ] + )); + assert_eq!(Alliance::unscrupulous_accounts().into_inner(), vec![3]); + assert_eq!(Alliance::unscrupulous_websites().into_inner(), vec!["abc".as_bytes().to_vec()]); + + assert_noop!( + Alliance::add_unscrupulous_items( + Origin::signed(3), + vec![UnscrupulousItem::AccountId(3)] + ), + Error::::AlreadyUnscrupulous + ); + }); +} + +#[test] +fn remove_unscrupulous_items_works() { + new_test_ext().execute_with(|| { + assert_noop!( + Alliance::remove_unscrupulous_items( + Origin::signed(3), + vec![UnscrupulousItem::AccountId(3)] + ), + Error::::NotListedAsUnscrupulous + ); + + assert_ok!(Alliance::add_unscrupulous_items( + Origin::signed(3), + vec![UnscrupulousItem::AccountId(3)] + )); + assert_eq!(Alliance::unscrupulous_accounts(), vec![3]); + assert_ok!(Alliance::remove_unscrupulous_items( + Origin::signed(3), + vec![UnscrupulousItem::AccountId(3)] + )); + assert_eq!(Alliance::unscrupulous_accounts(), Vec::::new()); + }); +} diff --git a/frame/alliance/src/types.rs b/frame/alliance/src/types.rs new file mode 100644 index 0000000000000..8fb0ae96fd02d --- /dev/null +++ b/frame/alliance/src/types.rs @@ -0,0 +1,95 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{traits::ConstU32, BoundedVec}; +use scale_info::TypeInfo; +use sp_runtime::RuntimeDebug; +use sp_std::{convert::TryInto, prelude::*}; + +/// A Multihash instance that only supports the basic functionality and no hashing. +#[derive( + Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen, +)] +pub struct Multihash { + /// The code of the Multihash. + pub code: u64, + /// The digest. + pub digest: BoundedVec>, // 4 byte dig size + 64 bytes hash digest +} + +impl Multihash { + /// Returns the size of the digest. + pub fn size(&self) -> usize { + self.digest.len() + } +} + +/// The version of the CID. +#[derive( + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + RuntimeDebug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, +)] +pub enum Version { + /// CID version 0. + V0, + /// CID version 1. + V1, +} + +/// Representation of a CID. +/// +/// The generic is about the allocated size of the multihash. +#[derive( + Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen, +)] +pub struct Cid { + /// The version of CID. + pub version: Version, + /// The codec of CID. + pub codec: u64, + /// The multihash of CID. + pub hash: Multihash, +} + +impl Cid { + /// Creates a new CIDv0. + pub fn new_v0(sha2_256_digest: impl Into>) -> Self { + /// DAG-PB multicodec code + const DAG_PB: u64 = 0x70; + /// The SHA_256 multicodec code + const SHA2_256: u64 = 0x12; + + let digest = sha2_256_digest.into(); + assert_eq!(digest.len(), 32); + + Self { + version: Version::V0, + codec: DAG_PB, + hash: Multihash { code: SHA2_256, digest: digest.try_into().expect("msg") }, + } + } +} diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs new file mode 100644 index 0000000000000..495dd1b83df93 --- /dev/null +++ b/frame/alliance/src/weights.rs @@ -0,0 +1,485 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_alliance +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-11, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// ./target/release/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_alliance +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/alliance/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_alliance. +pub trait WeightInfo { + fn propose_proposed(b: u32, x: u32, y: u32, p: u32, ) -> Weight; + fn vote(x: u32, y: u32, ) -> Weight; + fn veto(p: u32, ) -> Weight; + fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight; + fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight; + fn close_disapproved(x: u32, y: u32, p: u32, ) -> Weight; + fn close_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight; + fn init_members(x: u32, y: u32, z: u32, ) -> Weight; + fn set_rule() -> Weight; + fn announce() -> Weight; + fn remove_announcement() -> Weight; + fn join_alliance() -> Weight; + fn nominate_ally() -> Weight; + fn elevate_ally() -> Weight; + fn retire() -> Weight; + fn kick_member() -> Weight; + fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight; + fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight; +} + +/// Weights for pallet_alliance using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Proposals (r:1 w:1) + // Storage: AllianceMotion ProposalCount (r:1 w:1) + // Storage: AllianceMotion Voting (r:0 w:1) + fn propose_proposed(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + (39_992_000 as Weight) + // Standard Error: 2_000 + .saturating_add((44_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 2_000 + .saturating_add((323_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: Alliance Members (r:2 w:0) + // Storage: AllianceMotion Voting (r:1 w:1) + fn vote(x: u32, y: u32, ) -> Weight { + (36_649_000 as Weight) + // Standard Error: 90_000 + .saturating_add((42_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 3_000 + .saturating_add((195_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Proposals (r:1 w:1) + // Storage: AllianceMotion Voting (r:0 w:1) + fn veto(p: u32, ) -> Weight { + (30_301_000 as Weight) + // Standard Error: 1_000 + .saturating_add((330_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Voting (r:1 w:1) + // Storage: AllianceMotion Members (r:1 w:0) + // Storage: AllianceMotion Proposals (r:1 w:1) + fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { + (40_472_000 as Weight) + // Standard Error: 69_000 + .saturating_add((485_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 2_000 + .saturating_add((192_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 2_000 + .saturating_add((330_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Voting (r:1 w:1) + // Storage: AllianceMotion Members (r:1 w:0) + // Storage: AllianceMotion Proposals (r:1 w:1) + fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { + (52_076_000 as Weight) + // Standard Error: 0 + .saturating_add((4_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 77_000 + .saturating_add((194_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 3_000 + .saturating_add((188_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 2_000 + .saturating_add((329_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Voting (r:1 w:1) + // Storage: AllianceMotion Members (r:1 w:0) + // Storage: AllianceMotion Prime (r:1 w:0) + // Storage: AllianceMotion Proposals (r:1 w:1) + fn close_disapproved(x: u32, y: u32, p: u32, ) -> Weight { + (47_009_000 as Weight) + // Standard Error: 66_000 + .saturating_add((256_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 2_000 + .saturating_add((176_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 2_000 + .saturating_add((327_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Voting (r:1 w:1) + // Storage: AllianceMotion Members (r:1 w:0) + // Storage: AllianceMotion Prime (r:1 w:0) + // Storage: AllianceMotion Proposals (r:1 w:1) + fn close_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { + (43_650_000 as Weight) + // Standard Error: 0 + .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 85_000 + .saturating_add((124_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 3_000 + .saturating_add((199_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 3_000 + .saturating_add((326_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:3 w:3) + // Storage: AllianceMotion Members (r:1 w:1) + fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { + (45_100_000 as Weight) + // Standard Error: 4_000 + .saturating_add((162_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 4_000 + .saturating_add((151_000 as Weight).saturating_mul(z as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: Alliance Rule (r:0 w:1) + fn set_rule() -> Weight { + (14_517_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Alliance Announcements (r:1 w:1) + fn announce() -> Weight { + (16_801_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Alliance Announcements (r:1 w:1) + fn remove_announcement() -> Weight { + (17_133_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Alliance UnscrupulousAccounts (r:1 w:0) + // Storage: Alliance Members (r:4 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Alliance DepositOf (r:0 w:1) + fn join_alliance() -> Weight { + (95_370_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:4 w:0) + // Storage: Alliance UnscrupulousAccounts (r:1 w:0) + fn nominate_ally() -> Weight { + (44_764_000 as Weight) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Alliance Members (r:3 w:2) + // Storage: AllianceMotion Proposals (r:1 w:0) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + fn elevate_ally() -> Weight { + (44_013_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: Alliance KickingMembers (r:1 w:0) + // Storage: Alliance Members (r:3 w:1) + // Storage: AllianceMotion Proposals (r:1 w:0) + // Storage: Alliance DepositOf (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + fn retire() -> Weight { + (60_183_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } + // Storage: Alliance KickingMembers (r:1 w:0) + // Storage: Alliance Members (r:3 w:1) + // Storage: AllianceMotion Proposals (r:1 w:0) + // Storage: Alliance DepositOf (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + fn kick_member() -> Weight { + (67_467_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } + // Storage: Alliance UnscrupulousAccounts (r:1 w:1) + // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 16_000 + .saturating_add((2_673_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 7_000 + .saturating_add((224_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Alliance UnscrupulousAccounts (r:1 w:1) + // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 343_000 + .saturating_add((59_025_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 153_000 + .saturating_add((6_725_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Proposals (r:1 w:1) + // Storage: AllianceMotion ProposalCount (r:1 w:1) + // Storage: AllianceMotion Voting (r:0 w:1) + fn propose_proposed(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + (39_992_000 as Weight) + // Standard Error: 2_000 + .saturating_add((44_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 2_000 + .saturating_add((323_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: Alliance Members (r:2 w:0) + // Storage: AllianceMotion Voting (r:1 w:1) + fn vote(x: u32, y: u32, ) -> Weight { + (36_649_000 as Weight) + // Standard Error: 90_000 + .saturating_add((42_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 3_000 + .saturating_add((195_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Proposals (r:1 w:1) + // Storage: AllianceMotion Voting (r:0 w:1) + fn veto(p: u32, ) -> Weight { + (30_301_000 as Weight) + // Standard Error: 1_000 + .saturating_add((330_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Voting (r:1 w:1) + // Storage: AllianceMotion Members (r:1 w:0) + // Storage: AllianceMotion Proposals (r:1 w:1) + fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { + (40_472_000 as Weight) + // Standard Error: 69_000 + .saturating_add((485_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 2_000 + .saturating_add((192_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 2_000 + .saturating_add((330_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Voting (r:1 w:1) + // Storage: AllianceMotion Members (r:1 w:0) + // Storage: AllianceMotion Proposals (r:1 w:1) + fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { + (52_076_000 as Weight) + // Standard Error: 0 + .saturating_add((4_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 77_000 + .saturating_add((194_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 3_000 + .saturating_add((188_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 2_000 + .saturating_add((329_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Voting (r:1 w:1) + // Storage: AllianceMotion Members (r:1 w:0) + // Storage: AllianceMotion Prime (r:1 w:0) + // Storage: AllianceMotion Proposals (r:1 w:1) + fn close_disapproved(x: u32, y: u32, p: u32, ) -> Weight { + (47_009_000 as Weight) + // Standard Error: 66_000 + .saturating_add((256_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 2_000 + .saturating_add((176_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 2_000 + .saturating_add((327_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) + // Storage: AllianceMotion Voting (r:1 w:1) + // Storage: AllianceMotion Members (r:1 w:0) + // Storage: AllianceMotion Prime (r:1 w:0) + // Storage: AllianceMotion Proposals (r:1 w:1) + fn close_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { + (43_650_000 as Weight) + // Standard Error: 0 + .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 85_000 + .saturating_add((124_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 3_000 + .saturating_add((199_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 3_000 + .saturating_add((326_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:3 w:3) + // Storage: AllianceMotion Members (r:1 w:1) + fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { + (45_100_000 as Weight) + // Standard Error: 4_000 + .saturating_add((162_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 4_000 + .saturating_add((151_000 as Weight).saturating_mul(z as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: Alliance Rule (r:0 w:1) + fn set_rule() -> Weight { + (14_517_000 as Weight) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Alliance Announcements (r:1 w:1) + fn announce() -> Weight { + (16_801_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Alliance Announcements (r:1 w:1) + fn remove_announcement() -> Weight { + (17_133_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Alliance UnscrupulousAccounts (r:1 w:0) + // Storage: Alliance Members (r:4 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Alliance DepositOf (r:0 w:1) + fn join_alliance() -> Weight { + (95_370_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Alliance Members (r:4 w:0) + // Storage: Alliance UnscrupulousAccounts (r:1 w:0) + fn nominate_ally() -> Weight { + (44_764_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Alliance Members (r:3 w:2) + // Storage: AllianceMotion Proposals (r:1 w:0) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + fn elevate_ally() -> Weight { + (44_013_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + // Storage: Alliance KickingMembers (r:1 w:0) + // Storage: Alliance Members (r:3 w:1) + // Storage: AllianceMotion Proposals (r:1 w:0) + // Storage: Alliance DepositOf (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + fn retire() -> Weight { + (60_183_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } + // Storage: Alliance KickingMembers (r:1 w:0) + // Storage: Alliance Members (r:3 w:1) + // Storage: AllianceMotion Proposals (r:1 w:0) + // Storage: Alliance DepositOf (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + fn kick_member() -> Weight { + (67_467_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } + // Storage: Alliance UnscrupulousAccounts (r:1 w:1) + // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 16_000 + .saturating_add((2_673_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 7_000 + .saturating_add((224_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Alliance UnscrupulousAccounts (r:1 w:1) + // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 343_000 + .saturating_add((59_025_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 153_000 + .saturating_add((6_725_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } +} diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 13d03562cce49..bc6d9ab3310e0 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -51,8 +51,10 @@ use frame_support::{ codec::{Decode, Encode}, dispatch::{DispatchError, DispatchResultWithPostInfo, Dispatchable, PostDispatchInfo}, ensure, - traits::{Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers}, - weights::{GetDispatchInfo, Weight}, + traits::{ + Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers, StorageVersion, + }, + weights::{GetDispatchInfo, Pays, Weight}, }; #[cfg(test)] @@ -435,7 +437,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let members = Self::members(); ensure!(members.contains(&who), Error::::NotMember); - let proposal_len = proposal.using_encoded(|x| x.len()); + let proposal_len = proposal.encoded_size(); ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); let proposal_hash = T::Hashing::hash_of(&proposal); @@ -508,21 +510,8 @@ pub mod pallet { let members = Self::members(); ensure!(members.contains(&who), Error::::NotMember); - let proposal_len = proposal.using_encoded(|x| x.len()); - ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); - let proposal_hash = T::Hashing::hash_of(&proposal); - ensure!( - !>::contains_key(proposal_hash), - Error::::DuplicateProposal - ); - if threshold < 2 { - let seats = Self::members().len() as MemberCount; - let result = proposal.dispatch(RawOrigin::Members(1, seats).into()); - Self::deposit_event(Event::Executed { - proposal_hash, - result: result.map(|_| ()).map_err(|e| e.error), - }); + let (proposal_len, result) = Self::do_propose_execute(proposal, length_bound)?; Ok(get_result_weight(result) .map(|w| { @@ -534,33 +523,13 @@ pub mod pallet { }) .into()) } else { - let active_proposals = - >::try_mutate(|proposals| -> Result { - proposals - .try_push(proposal_hash) - .map_err(|_| Error::::TooManyProposals)?; - Ok(proposals.len()) - })?; - let index = Self::proposal_count(); - >::mutate(|i| *i += 1); - >::insert(proposal_hash, *proposal); - let votes = { - let end = frame_system::Pallet::::block_number() + T::MotionDuration::get(); - Votes { index, threshold, ayes: vec![], nays: vec![], end } - }; - >::insert(proposal_hash, votes); - - Self::deposit_event(Event::Proposed { - account: who, - proposal_index: index, - proposal_hash, - threshold, - }); + let (proposal_len, active_proposals) = + Self::do_propose_proposed(who, threshold, proposal, length_bound)?; Ok(Some(T::WeightInfo::propose_proposed( - proposal_len as u32, // B - members.len() as u32, // M - active_proposals as u32, // P2 + proposal_len as u32, // B + members.len() as u32, // M + active_proposals, // P2 )) .into()) } @@ -592,46 +561,8 @@ pub mod pallet { let members = Self::members(); ensure!(members.contains(&who), Error::::NotMember); - let mut voting = Self::voting(&proposal).ok_or(Error::::ProposalMissing)?; - ensure!(voting.index == index, Error::::WrongIndex); - - let position_yes = voting.ayes.iter().position(|a| a == &who); - let position_no = voting.nays.iter().position(|a| a == &who); - // Detects first vote of the member in the motion - let is_account_voting_first_time = position_yes.is_none() && position_no.is_none(); - - if approve { - if position_yes.is_none() { - voting.ayes.push(who.clone()); - } else { - return Err(Error::::DuplicateVote.into()) - } - if let Some(pos) = position_no { - voting.nays.swap_remove(pos); - } - } else { - if position_no.is_none() { - voting.nays.push(who.clone()); - } else { - return Err(Error::::DuplicateVote.into()) - } - if let Some(pos) = position_yes { - voting.ayes.swap_remove(pos); - } - } - - let yes_votes = voting.ayes.len() as MemberCount; - let no_votes = voting.nays.len() as MemberCount; - Self::deposit_event(Event::Voted { - account: who, - proposal_hash: proposal, - voted: approve, - yes: yes_votes, - no: no_votes, - }); - - Voting::::insert(&proposal, voting); + let is_account_voting_first_time = Self::do_vote(who, proposal, index, approve)?; if is_account_voting_first_time { Ok((Some(T::WeightInfo::vote(members.len() as u32)), Pays::No).into()) @@ -695,82 +626,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - let voting = Self::voting(&proposal_hash).ok_or(Error::::ProposalMissing)?; - ensure!(voting.index == index, Error::::WrongIndex); - - let mut no_votes = voting.nays.len() as MemberCount; - let mut yes_votes = voting.ayes.len() as MemberCount; - let seats = Self::members().len() as MemberCount; - let approved = yes_votes >= voting.threshold; - let disapproved = seats.saturating_sub(no_votes) < voting.threshold; - // Allow (dis-)approving the proposal as soon as there are enough votes. - if approved { - let (proposal, len) = Self::validate_and_get_proposal( - &proposal_hash, - length_bound, - proposal_weight_bound, - )?; - Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); - let (proposal_weight, proposal_count) = - Self::do_approve_proposal(seats, yes_votes, proposal_hash, proposal); - return Ok(( - Some( - T::WeightInfo::close_early_approved(len as u32, seats, proposal_count) - .saturating_add(proposal_weight), - ), - Pays::Yes, - ) - .into()) - } else if disapproved { - Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); - let proposal_count = Self::do_disapprove_proposal(proposal_hash); - return Ok(( - Some(T::WeightInfo::close_early_disapproved(seats, proposal_count)), - Pays::No, - ) - .into()) - } - - // Only allow actual closing of the proposal after the voting period has ended. - ensure!( - frame_system::Pallet::::block_number() >= voting.end, - Error::::TooEarly - ); - - let prime_vote = Self::prime().map(|who| voting.ayes.iter().any(|a| a == &who)); - - // default voting strategy. - let default = T::DefaultVote::default_vote(prime_vote, yes_votes, no_votes, seats); - - let abstentions = seats - (yes_votes + no_votes); - match default { - true => yes_votes += abstentions, - false => no_votes += abstentions, - } - let approved = yes_votes >= voting.threshold; - - if approved { - let (proposal, len) = Self::validate_and_get_proposal( - &proposal_hash, - length_bound, - proposal_weight_bound, - )?; - Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); - let (proposal_weight, proposal_count) = - Self::do_approve_proposal(seats, yes_votes, proposal_hash, proposal); - Ok(( - Some( - T::WeightInfo::close_approved(len as u32, seats, proposal_count) - .saturating_add(proposal_weight), - ), - Pays::Yes, - ) - .into()) - } else { - Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); - let proposal_count = Self::do_disapprove_proposal(proposal_hash); - Ok((Some(T::WeightInfo::close_disapproved(seats, proposal_count)), Pays::No).into()) - } + Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) } /// Disapprove a proposal, close, and remove it from the system, regardless of its current @@ -817,6 +673,197 @@ impl, I: 'static> Pallet { Self::members().contains(who) } + /// Execute immediately when adding a new proposal. + pub fn do_propose_execute( + proposal: Box<>::Proposal>, + length_bound: MemberCount, + ) -> Result<(u32, DispatchResultWithPostInfo), DispatchError> { + let proposal_len = proposal.encoded_size(); + ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); + + let proposal_hash = T::Hashing::hash_of(&proposal); + ensure!(!>::contains_key(proposal_hash), Error::::DuplicateProposal); + + let seats = Self::members().len() as MemberCount; + let result = proposal.dispatch(RawOrigin::Members(1, seats).into()); + Self::deposit_event(Event::Executed { + proposal_hash, + result: result.map(|_| ()).map_err(|e| e.error), + }); + Ok((proposal_len as u32, result)) + } + + /// Add a new proposal to be voted. + pub fn do_propose_proposed( + who: T::AccountId, + threshold: MemberCount, + proposal: Box<>::Proposal>, + length_bound: MemberCount, + ) -> Result<(u32, u32), DispatchError> { + let proposal_len = proposal.encoded_size(); + ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); + + let proposal_hash = T::Hashing::hash_of(&proposal); + ensure!(!>::contains_key(proposal_hash), Error::::DuplicateProposal); + + let active_proposals = + >::try_mutate(|proposals| -> Result { + proposals.try_push(proposal_hash).map_err(|_| Error::::TooManyProposals)?; + Ok(proposals.len()) + })?; + + let index = Self::proposal_count(); + >::mutate(|i| *i += 1); + >::insert(proposal_hash, proposal); + let votes = { + let end = frame_system::Pallet::::block_number() + T::MotionDuration::get(); + Votes { index, threshold, ayes: vec![], nays: vec![], end } + }; + >::insert(proposal_hash, votes); + + Self::deposit_event(Event::Proposed { + account: who, + proposal_index: index, + proposal_hash, + threshold, + }); + Ok((proposal_len as u32, active_proposals as u32)) + } + + /// Add an aye or nay vote for the member to the given proposal, returns true if it's the first + /// vote of the member in the motion + pub fn do_vote( + who: T::AccountId, + proposal: T::Hash, + index: ProposalIndex, + approve: bool, + ) -> Result { + let mut voting = Self::voting(&proposal).ok_or(Error::::ProposalMissing)?; + ensure!(voting.index == index, Error::::WrongIndex); + + let position_yes = voting.ayes.iter().position(|a| a == &who); + let position_no = voting.nays.iter().position(|a| a == &who); + + // Detects first vote of the member in the motion + let is_account_voting_first_time = position_yes.is_none() && position_no.is_none(); + + if approve { + if position_yes.is_none() { + voting.ayes.push(who.clone()); + } else { + return Err(Error::::DuplicateVote.into()) + } + if let Some(pos) = position_no { + voting.nays.swap_remove(pos); + } + } else { + if position_no.is_none() { + voting.nays.push(who.clone()); + } else { + return Err(Error::::DuplicateVote.into()) + } + if let Some(pos) = position_yes { + voting.ayes.swap_remove(pos); + } + } + + let yes_votes = voting.ayes.len() as MemberCount; + let no_votes = voting.nays.len() as MemberCount; + Self::deposit_event(Event::Voted { + account: who, + proposal_hash: proposal, + voted: approve, + yes: yes_votes, + no: no_votes, + }); + + Voting::::insert(&proposal, voting); + + Ok(is_account_voting_first_time) + } + + /// Close a vote that is either approved, disapproved or whose voting period has ended. + pub fn do_close( + proposal_hash: T::Hash, + index: ProposalIndex, + proposal_weight_bound: Weight, + length_bound: u32, + ) -> DispatchResultWithPostInfo { + let voting = Self::voting(&proposal_hash).ok_or(Error::::ProposalMissing)?; + ensure!(voting.index == index, Error::::WrongIndex); + + let mut no_votes = voting.nays.len() as MemberCount; + let mut yes_votes = voting.ayes.len() as MemberCount; + let seats = Self::members().len() as MemberCount; + let approved = yes_votes >= voting.threshold; + let disapproved = seats.saturating_sub(no_votes) < voting.threshold; + // Allow (dis-)approving the proposal as soon as there are enough votes. + if approved { + let (proposal, len) = Self::validate_and_get_proposal( + &proposal_hash, + length_bound, + proposal_weight_bound, + )?; + Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); + let (proposal_weight, proposal_count) = + Self::do_approve_proposal(seats, yes_votes, proposal_hash, proposal); + return Ok(( + Some( + T::WeightInfo::close_early_approved(len as u32, seats, proposal_count) + .saturating_add(proposal_weight), + ), + Pays::Yes, + ) + .into()) + } else if disapproved { + Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); + let proposal_count = Self::do_disapprove_proposal(proposal_hash); + return Ok(( + Some(T::WeightInfo::close_early_disapproved(seats, proposal_count)), + Pays::No, + ) + .into()) + } + + // Only allow actual closing of the proposal after the voting period has ended. + ensure!(frame_system::Pallet::::block_number() >= voting.end, Error::::TooEarly); + + let prime_vote = Self::prime().map(|who| voting.ayes.iter().any(|a| a == &who)); + + // default voting strategy. + let default = T::DefaultVote::default_vote(prime_vote, yes_votes, no_votes, seats); + + let abstentions = seats - (yes_votes + no_votes); + match default { + true => yes_votes += abstentions, + false => no_votes += abstentions, + } + let approved = yes_votes >= voting.threshold; + + if approved { + let (proposal, len) = Self::validate_and_get_proposal( + &proposal_hash, + length_bound, + proposal_weight_bound, + )?; + Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); + let (proposal_weight, proposal_count) = + Self::do_approve_proposal(seats, yes_votes, proposal_hash, proposal); + Ok(( + Some( + T::WeightInfo::close_approved(len as u32, seats, proposal_count) + .saturating_add(proposal_weight), + ), + Pays::Yes, + ) + .into()) + } else { + Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); + let proposal_count = Self::do_disapprove_proposal(proposal_hash); + Ok((Some(T::WeightInfo::close_disapproved(seats, proposal_count)), Pays::No).into()) + } + } + /// Ensure that the right proposal bounds were passed and get the proposal from storage. /// /// Checks the length in storage via `storage::read` which adds an extra `size_of::() == 4` @@ -873,7 +920,8 @@ impl, I: 'static> Pallet { (proposal_weight, proposal_count) } - fn do_disapprove_proposal(proposal_hash: T::Hash) -> u32 { + /// Removes a proposal from the pallet, and deposit the `Disapproved` event. + pub fn do_disapprove_proposal(proposal_hash: T::Hash) -> u32 { // disapproved Self::deposit_event(Event::Disapproved { proposal_hash }); Self::remove_proposal(proposal_hash) From ac1fddccfbcbb9b2aa6bbbd81633e110ea0fd0a4 Mon Sep 17 00:00:00 2001 From: Tarek Mohamed Abdalla Date: Sat, 11 Jun 2022 19:24:42 +0200 Subject: [PATCH 0899/1472] Add fixed u64 (#11555) Co-authored-by: parity-processbot <> Co-authored-by: Oliver Tale-Yazdi --- primitives/arithmetic/src/fixed_point.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/primitives/arithmetic/src/fixed_point.rs b/primitives/arithmetic/src/fixed_point.rs index f4ed70ee8b5dc..2dfe717fe7e4f 100644 --- a/primitives/arithmetic/src/fixed_point.rs +++ b/primitives/arithmetic/src/fixed_point.rs @@ -2167,6 +2167,15 @@ implement_fixed!( "_Fixed Point 64 bits signed, range = [-9223372036.854775808, 9223372036.854775807]_", ); +implement_fixed!( + FixedU64, + test_fixed_u64, + u64, + false, + 1_000_000_000, + "_Fixed Point 64 bits unsigned, range = [0.000000000, 18446744073.709551615]_", +); + implement_fixed!( FixedI128, test_fixed_i128, From 3823ec4a3153a8b53a0effea3ad5a9191b46a153 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sat, 11 Jun 2022 18:50:16 +0100 Subject: [PATCH 0900/1472] Remove storage `MaxValues` limits (#11643) * Remove limits Signed-off-by: Oliver Tale-Yazdi * Remove more Signed-off-by: Oliver Tale-Yazdi --- frame/assets/src/lib.rs | 8 -------- frame/atomic-swap/src/lib.rs | 3 --- frame/balances/src/lib.rs | 13 ++----------- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index eb412de58fda6..3f9146c5d229b 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -262,9 +262,6 @@ pub mod pallet { Blake2_128Concat, T::AccountId, AssetAccountOf, - OptionQuery, - GetDefault, - ConstU32<300_000>, >; #[pallet::storage] @@ -279,9 +276,6 @@ pub mod pallet { NMapKey, // delegate ), Approval>, - OptionQuery, - GetDefault, - ConstU32<300_000>, >; #[pallet::storage] @@ -292,8 +286,6 @@ pub mod pallet { T::AssetId, AssetMetadata, BoundedVec>, ValueQuery, - GetDefault, - ConstU32<300_000>, >; #[pallet::genesis_config] diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index b999aefaaa907..1ddf3888d3c96 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -195,9 +195,6 @@ pub mod pallet { Blake2_128Concat, HashedProof, PendingSwap, - OptionQuery, - GetDefault, - ConstU32<300_000>, >; #[pallet::error] diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 7060486f8584d..298c2a6963880 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -516,15 +516,8 @@ pub mod pallet { /// `Balances` pallet, which uses a `StorageMap` to store balances data only. /// NOTE: This is only used in the case that this pallet is used to store balances. #[pallet::storage] - pub type Account, I: 'static = ()> = StorageMap< - _, - Blake2_128Concat, - T::AccountId, - AccountData, - ValueQuery, - GetDefault, - ConstU32<300_000>, - >; + pub type Account, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, T::AccountId, AccountData, ValueQuery>; /// Any liquidity locks on some account balances. /// NOTE: Should only be accessed when setting, changing and freeing a lock. @@ -536,8 +529,6 @@ pub mod pallet { T::AccountId, WeakBoundedVec, T::MaxLocks>, ValueQuery, - GetDefault, - ConstU32<300_000>, >; /// Named reserves on some account balances. From 3c99545cb062fbc56b84e2f3e44def3b933123cd Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Sun, 12 Jun 2022 18:40:29 +0200 Subject: [PATCH 0901/1472] Added an event for cancel_proposal (#11620) * Added an event for cancel_proposal * test --- frame/democracy/src/lib.rs | 3 +++ frame/democracy/src/tests/public_proposals.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 91362a0a3edf7..4e11c207657f0 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -537,6 +537,8 @@ pub mod pallet { Voted { voter: T::AccountId, ref_index: ReferendumIndex, vote: AccountVote> }, /// An account has secconded a proposal Seconded { seconder: T::AccountId, prop_index: PropIndex }, + /// A proposal got canceled. + ProposalCanceled { prop_index: PropIndex }, } #[pallet::error] @@ -1277,6 +1279,7 @@ pub mod pallet { } } + Self::deposit_event(Event::::ProposalCanceled { prop_index }); Ok(()) } } diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs index aadc92d24f41d..db06696ca5c95 100644 --- a/frame/democracy/src/tests/public_proposals.rs +++ b/frame/democracy/src/tests/public_proposals.rs @@ -96,11 +96,11 @@ fn invalid_seconds_upper_bound_should_not_work() { #[test] fn cancel_proposal_should_work() { new_test_ext().execute_with(|| { - System::set_block_number(0); assert_ok!(propose_set_balance_and_note(1, 2, 2)); assert_ok!(propose_set_balance_and_note(1, 4, 4)); assert_noop!(Democracy::cancel_proposal(Origin::signed(1), 0), BadOrigin); assert_ok!(Democracy::cancel_proposal(Origin::root(), 0)); + System::assert_last_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); assert_eq!(Democracy::backing_for(0), None); assert_eq!(Democracy::backing_for(1), Some(4)); }); From e47ef5d559bab08d6c897ce31fc8b55503ebed5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 13 Jun 2022 10:31:16 +0200 Subject: [PATCH 0902/1472] pallet-grandpa: Improve/Clarify docs of `note_stalled` (#11623) --- frame/grandpa/src/lib.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index be613e302b21e..1781f0a8e40a2 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -231,12 +231,17 @@ pub mod pallet { ) } - /// Note that the current authority set of the GRANDPA finality gadget has - /// stalled. This will trigger a forced authority set change at the beginning - /// of the next session, to be enacted `delay` blocks after that. The delay - /// should be high enough to safely assume that the block signalling the - /// forced change will not be re-orged (e.g. 1000 blocks). The GRANDPA voters - /// will start the new authority set using the given finalized block as base. + /// Note that the current authority set of the GRANDPA finality gadget has stalled. + /// + /// This will trigger a forced authority set change at the beginning of the next session, to + /// be enacted `delay` blocks after that. The `delay` should be high enough to safely assume + /// that the block signalling the forced change will not be re-orged e.g. 1000 blocks. + /// The block production rate (which may be slowed down because of finality lagging) should + /// be taken into account when choosing the `delay`. The GRANDPA voters based on the new + /// authority will start voting on top of `best_finalized_block_number` for new finalized + /// blocks. `best_finalized_block_number` should be the highest of the latest finalized + /// block of all validators of the new authority set. + /// /// Only callable by root. #[pallet::weight(T::WeightInfo::note_stalled())] pub fn note_stalled( From 87052efd6be1bb07061a14dbb63a13ed7a81cfb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 11:14:37 +0200 Subject: [PATCH 0903/1472] Bump crossbeam-utils from 0.8.5 to 0.8.8 (#11605) Bumps [crossbeam-utils](https://github.com/crossbeam-rs/crossbeam) from 0.8.5 to 0.8.8. - [Release notes](https://github.com/crossbeam-rs/crossbeam/releases) - [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md) - [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-utils-0.8.5...crossbeam-utils-0.8.8) --- updated-dependencies: - dependency-name: crossbeam-utils dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b581bf9d0ff7..a5e431c7a4aa0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1360,9 +1360,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if 1.0.0", "lazy_static", @@ -11205,7 +11205,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "digest 0.10.3", "rand 0.8.4", "static_assertions", From 8fe464b8636803dea45f5e6506d56eae309942ba Mon Sep 17 00:00:00 2001 From: Yongjin Huang <20609724+doutv@users.noreply.github.com> Date: Mon, 13 Jun 2022 19:44:50 +0800 Subject: [PATCH 0904/1472] fix pallet_uniques docs link (#11651) --- frame/uniques/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/uniques/README.md b/frame/uniques/README.md index 09f9d346895a6..8a91a558b5b5f 100644 --- a/frame/uniques/README.md +++ b/frame/uniques/README.md @@ -10,9 +10,9 @@ The Uniques module provides functionality for asset management of non-fungible a * Asset Transfer * Asset Destruction -To use it in your runtime, you need to implement the assets [`uniques::Config`](https://docs.rs/pallet-uniques/latest/pallet_uniques/pallet/trait.Config.html). +To use it in your runtime, you need to implement the assets [`uniques::Config`](https://paritytech.github.io/substrate/master/pallet_uniques/pallet/trait.Config.html). -The supported dispatchable functions are documented in the [`uniques::Call`](https://docs.rs/pallet-uniques/latest/pallet_uniques/pallet/enum.Call.html) enum. +The supported dispatchable functions are documented in the [`uniques::Call`](https://paritytech.github.io/substrate/master/pallet_uniques/pallet/enum.Call.html) enum. ### Terminology @@ -66,7 +66,7 @@ The Uniques pallet in Substrate is designed to make the following possible: * `force_create`: Create a new asset class. * `force_asset_status`: Alter the underlying characteristics of an asset class. -Please refer to the [`Call`](https://docs.rs/pallet-assets/latest/pallet_assets/enum.Call.html) enum +Please refer to the [`Call`](https://paritytech.github.io/substrate/master/pallet_uniques/pallet/enum.Call.html) enum and its associated variants for documentation on each function. ## Related Modules From 93cf073d7caac85f4f8f1fb894d1abf05362b917 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 13 Jun 2022 13:17:07 +0100 Subject: [PATCH 0905/1472] MEL bound `state-trie-migration` (#11639) * MEL bound state-trie-migration Signed-off-by: Oliver Tale-Yazdi * wip Signed-off-by: Oliver Tale-Yazdi * Add tests Signed-off-by: Oliver Tale-Yazdi * Use sp_std Co-authored-by: cheme * Add doc Signed-off-by: Oliver Tale-Yazdi * Set MaxKeyLen default to 512 Just to be sure that it will work. There is also no real penalty from over-estimating it. Signed-off-by: Oliver Tale-Yazdi * Add more doc Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Fix assert_err_with_weight macro Looks like I'm the only one using it anyway... Signed-off-by: Oliver Tale-Yazdi * Fix tests that use env macro Signed-off-by: Oliver Tale-Yazdi * Fix test Signed-off-by: Oliver Tale-Yazdi Co-authored-by: cheme --- bin/node/runtime/src/lib.rs | 2 + frame/state-trie-migration/src/lib.rs | 273 +++++++++++++++++++++----- frame/support/src/lib.rs | 2 +- 3 files changed, 223 insertions(+), 54 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8e854b770a4ff..6f3df7416681e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1492,12 +1492,14 @@ impl pallet_whitelist::Config for Runtime { parameter_types! { pub const MigrationSignedDepositPerItem: Balance = 1 * CENTS; pub const MigrationSignedDepositBase: Balance = 20 * DOLLARS; + pub const MigrationMaxKeyLen: u32 = 512; } impl pallet_state_trie_migration::Config for Runtime { type Event = Event; type ControlOrigin = EnsureRoot; type Currency = Balances; + type MaxKeyLen = MigrationMaxKeyLen; type SignedDepositPerItem = MigrationSignedDepositPerItem; type SignedDepositBase = MigrationSignedDepositBase; // Warning: this is not advised, as it might allow the chain to be temporarily DOS-ed. diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 899250cc3f3c3..9ac128a0e3108 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -78,12 +78,14 @@ pub mod pallet { traits::{Currency, Get}, }; use frame_system::{self, pallet_prelude::*}; - use sp_core::storage::well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX; + use sp_core::{ + hexdisplay::HexDisplay, storage::well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX, + }; use sp_runtime::{ self, traits::{Saturating, Zero}, }; - use sp_std::prelude::*; + use sp_std::{ops::Deref, prelude::*}; pub(crate) type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -124,30 +126,43 @@ pub mod pallet { } /// The progress of either the top or child keys. - #[derive(Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq)] - pub enum Progress { + #[derive( + CloneNoBound, + Encode, + Decode, + scale_info::TypeInfo, + PartialEqNoBound, + EqNoBound, + MaxEncodedLen, + )] + #[scale_info(skip_type_params(MaxKeyLen))] + #[codec(mel_bound())] + pub enum Progress> { /// Yet to begin. ToStart, /// Ongoing, with the last key given. - LastKey(Vec), + LastKey(BoundedVec), /// All done. Complete, } + /// Convenience type for easier usage of [`Progress`]. + pub type ProgressOf = Progress<::MaxKeyLen>; + /// A migration task stored in state. /// /// It tracks the last top and child keys read. - #[derive(Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq)] + #[derive(Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq, MaxEncodedLen)] #[codec(mel_bound(T: Config))] #[scale_info(skip_type_params(T))] pub struct MigrationTask { /// The current top trie migration progress. - pub(crate) progress_top: Progress, + pub(crate) progress_top: ProgressOf, /// The current child trie migration progress. /// /// If `ToStart`, no further top keys are processed until the child key migration is /// `Complete`. - pub(crate) progress_child: Progress, + pub(crate) progress_child: ProgressOf, /// Dynamic counter for the number of items that we have processed in this execution from /// the top trie. @@ -186,12 +201,11 @@ pub mod pallet { pub(crate) _ph: sp_std::marker::PhantomData, } - impl sp_std::fmt::Debug for Progress { + impl> sp_std::fmt::Debug for Progress { fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { match self { Progress::ToStart => f.write_str("To start"), - Progress::LastKey(key) => - write!(f, "Last: {:?}", sp_core::hexdisplay::HexDisplay::from(key)), + Progress::LastKey(key) => write!(f, "Last: {:?}", HexDisplay::from(key.deref())), Progress::Complete => f.write_str("Complete"), } } @@ -252,17 +266,20 @@ pub mod pallet { /// reading a key, we simply cannot know how many bytes it is. In other words, this should /// not be used in any environment where resources are strictly bounded (e.g. a parachain), /// but it is acceptable otherwise (relay chain, offchain workers). - pub fn migrate_until_exhaustion(&mut self, limits: MigrationLimits) { + pub fn migrate_until_exhaustion(&mut self, limits: MigrationLimits) -> DispatchResult { log!(debug, "running migrations on top of {:?} until {:?}", self, limits); if limits.item.is_zero() || limits.size.is_zero() { // handle this minor edge case, else we would call `migrate_tick` at least once. log!(warn, "limits are zero. stopping"); - return + return Ok(()) } while !self.exhausted(limits) && !self.finished() { - self.migrate_tick(); + if let Err(e) = self.migrate_tick() { + log!(error, "migrate_until_exhaustion failed: {:?}", e); + return Err(e) + } } // accumulate dynamic data into the storage items. @@ -270,19 +287,18 @@ pub mod pallet { self.child_items = self.child_items.saturating_add(self.dyn_child_items); self.top_items = self.top_items.saturating_add(self.dyn_top_items); log!(debug, "finished with {:?}", self); + Ok(()) } /// Migrate AT MOST ONE KEY. This can be either a top or a child key. /// /// This function is *the* core of this entire pallet. - fn migrate_tick(&mut self) { + fn migrate_tick(&mut self) -> DispatchResult { match (&self.progress_top, &self.progress_child) { - (Progress::ToStart, _) => { - self.migrate_top(); - }, + (Progress::ToStart, _) => self.migrate_top(), (Progress::LastKey(_), Progress::LastKey(_)) => { // we're in the middle of doing work on a child tree. - self.migrate_child(); + self.migrate_child() }, (Progress::LastKey(top_key), Progress::ToStart) => { // 3. this is the root of a child key, and we are finishing all child-keys (and @@ -293,20 +309,22 @@ pub mod pallet { if !top_key.starts_with(DEFAULT_CHILD_STORAGE_KEY_PREFIX) { // we continue the top key migrations. // continue the top key migration - self.migrate_top(); + self.migrate_top() } else { // this is the root of a child key, and we start processing child keys (and // should call `migrate_child`). - self.migrate_child(); + self.migrate_child() } }, (Progress::LastKey(_), Progress::Complete) => { // we're done with migrating a child-root. - self.migrate_top(); + self.migrate_top()?; self.progress_child = Progress::ToStart; + Ok(()) }, (Progress::Complete, _) => { // nada + Ok(()) }, } } @@ -314,24 +332,30 @@ pub mod pallet { /// Migrate the current child key, setting it to its new value, if one exists. /// /// It updates the dynamic counters. - fn migrate_child(&mut self) { + fn migrate_child(&mut self) -> DispatchResult { use sp_io::default_child_storage as child_io; let (maybe_current_child, child_root) = match (&self.progress_child, &self.progress_top) { (Progress::LastKey(last_child), Progress::LastKey(last_top)) => { let child_root = Pallet::::transform_child_key_or_halt(last_top); - let maybe_current_child = child_io::next_key(child_root, last_child); + let maybe_current_child: Option> = + if let Some(next) = child_io::next_key(child_root, last_child) { + Some(next.try_into().map_err(|_| Error::::KeyTooLong)?) + } else { + None + }; + (maybe_current_child, child_root) }, (Progress::ToStart, Progress::LastKey(last_top)) => { let child_root = Pallet::::transform_child_key_or_halt(last_top); // Start with the empty key as first key. - (Some(Vec::new()), child_root) + (Some(Default::default()), child_root) }, _ => { // defensive: there must be an ongoing top migration. frame_support::defensive!("cannot migrate child key."); - return + return Ok(()) }, }; @@ -350,21 +374,30 @@ pub mod pallet { self.progress_child = match maybe_current_child { Some(last_child) => Progress::LastKey(last_child), None => Progress::Complete, - } + }; + Ok(()) } /// Migrate the current top key, setting it to its new value, if one exists. /// /// It updates the dynamic counters. - fn migrate_top(&mut self) { + fn migrate_top(&mut self) -> DispatchResult { let maybe_current_top = match &self.progress_top { - Progress::LastKey(last_top) => sp_io::storage::next_key(last_top), + Progress::LastKey(last_top) => { + let maybe_top: Option> = + if let Some(next) = sp_io::storage::next_key(last_top) { + Some(next.try_into().map_err(|_| Error::::KeyTooLong)?) + } else { + None + }; + maybe_top + }, // Start with the empty key as first key. - Progress::ToStart => Some(Vec::new()), + Progress::ToStart => Some(Default::default()), Progress::Complete => { // defensive: there must be an ongoing top migration. frame_support::defensive!("cannot migrate top key."); - return + return Ok(()) }, }; @@ -383,12 +416,24 @@ pub mod pallet { self.progress_top = match maybe_current_top { Some(last_top) => Progress::LastKey(last_top), None => Progress::Complete, - } + }; + Ok(()) } } /// The limits of a migration. - #[derive(Clone, Copy, Encode, Decode, scale_info::TypeInfo, Default, Debug, PartialEq, Eq)] + #[derive( + Clone, + Copy, + Encode, + Decode, + scale_info::TypeInfo, + Default, + Debug, + PartialEq, + Eq, + MaxEncodedLen, + )] pub struct MigrationLimits { /// The byte size limit. pub size: u32, @@ -416,14 +461,13 @@ pub mod pallet { Slashed { who: T::AccountId, amount: BalanceOf }, /// The auto migration task finished. AutoMigrationFinished, - /// Migration got halted. + /// Migration got halted due to an error or miss-configuration. Halted, } /// The outer Pallet struct. #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); /// Configurations of this pallet. @@ -441,6 +485,31 @@ pub mod pallet { /// The currency provider type. type Currency: Currency; + /// Maximal number of bytes that a key can have. + /// + /// FRAME itself does not limit the key length. + /// The concrete value must therefore depend on your storage usage. + /// A [`frame_support::storage::StorageNMap`] for example can have an arbitrary number of + /// keys which are then hashed and concatenated, resulting in arbitrarily long keys. + /// + /// Use the *state migration RPC* to retrieve the length of the longest key in your + /// storage: + /// + /// The migration will halt with a `Halted` event if this value is too small. + /// Since there is no real penalty from over-estimating, it is advised to use a large + /// value. The default is 512 byte. + /// + /// Some key lengths for reference: + /// - [`frame_support::storage::StorageValue`]: 32 byte + /// - [`frame_support::storage::StorageMap`]: 64 byte + /// - [`frame_support::storage::StorageDoubleMap`]: 96 byte + /// + /// For more info see + /// + + #[pallet::constant] + type MaxKeyLen: Get; + /// The amount of deposit collected per item in advance, for signed migrations. /// /// This should reflect the average storage value size in the worse case. @@ -481,6 +550,14 @@ pub mod pallet { pub enum Error { /// max signed limits not respected. MaxSignedLimits, + /// A key was longer than the configured maximum. + /// + /// This means that the migration halted at the current [`Progress`] and + /// can be resumed with a larger [`crate::Config::MaxKeyLen`] value. + /// Retrying with the same [`crate::Config::MaxKeyLen`] value will not work. + /// The value should only be increased to avoid a storage migration for the currently + /// stored [`crate::Progress::LastKey`]. + KeyTooLong, /// submitter does not have enough funds. NotEnoughFunds, /// bad witness data provided. @@ -563,7 +640,7 @@ pub mod pallet { } } ); - task.migrate_until_exhaustion(limits); + let migration = task.migrate_until_exhaustion(limits); // ensure that the migration witness data was correct. if real_size_upper < task.dyn_size { @@ -587,7 +664,14 @@ pub mod pallet { ); MigrationProcess::::put(task); - Ok((actual_weight, Pays::No).into()) + let post_info = PostDispatchInfo { actual_weight, pays_fee: Pays::No }; + match migration { + Ok(_) => Ok(post_info), + Err(error) => { + Self::halt(&error); + Err(DispatchErrorWithPostInfo { post_info, error }) + }, + } } /// Migrate the list of top keys by iterating each of them one by one. @@ -735,8 +819,8 @@ pub mod pallet { #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] pub fn force_set_progress( origin: OriginFor, - progress_top: Progress, - progress_child: Progress, + progress_top: ProgressOf, + progress_child: ProgressOf, ) -> DispatchResult { let _ = T::ControlOrigin::ensure_origin(origin)?; MigrationProcess::::mutate(|task| { @@ -752,7 +836,9 @@ pub mod pallet { fn on_initialize(_: BlockNumberFor) -> Weight { if let Some(limits) = Self::auto_limits() { let mut task = Self::migration_process(); - task.migrate_until_exhaustion(limits); + if let Err(e) = task.migrate_until_exhaustion(limits) { + Self::halt(&e); + } let weight = Self::dynamic_weight(task.dyn_total_items(), task.dyn_size); log!( @@ -793,8 +879,9 @@ pub mod pallet { .saturating_add(T::WeightInfo::process_top_key(size)) } - /// Put a stop to all ongoing migrations. - fn halt() { + /// Put a stop to all ongoing migrations and logs an error. + fn halt(msg: &E) { + log!(error, "migration halted due to: {:?}", msg); AutoLimits::::kill(); Self::deposit_event(Event::::Halted); } @@ -815,7 +902,7 @@ pub mod pallet { fn transform_child_key_or_halt(root: &Vec) -> &[u8] { let key = Self::transform_child_key(root); if key.is_none() { - Self::halt(); + Self::halt("bad child root key"); } key.unwrap_or_default() } @@ -858,7 +945,7 @@ mod benchmarks { continue_migrate_wrong_witness { let null = MigrationLimits::default(); let caller = frame_benchmarking::whitelisted_caller(); - let bad_witness = MigrationTask { progress_top: Progress::LastKey(vec![1u8]), ..Default::default() }; + let bad_witness = MigrationTask { progress_top: Progress::LastKey(vec![1u8].try_into().unwrap()), ..Default::default() }; }: { assert!( StateTrieMigration::::continue_migrate( @@ -1046,6 +1133,7 @@ mod mock { parameter_types! { pub const SignedDepositPerItem: u64 = 1; pub const SignedDepositBase: u64 = 5; + pub const MigrationMaxKeyLen: u32 = 512; } impl pallet_balances::Config for Test { @@ -1064,6 +1152,7 @@ mod mock { type Event = Event; type ControlOrigin = EnsureRoot; type Currency = Balances; + type MaxKeyLen = MigrationMaxKeyLen; type SignedDepositPerItem = SignedDepositPerItem; type SignedDepositBase = SignedDepositBase; type SignedFilter = EnsureSigned; @@ -1171,6 +1260,7 @@ mod mock { #[cfg(test)] mod test { use super::{mock::*, *}; + use frame_support::{bounded_vec, dispatch::*}; use sp_runtime::{traits::Bounded, StateVersion}; #[test] @@ -1185,6 +1275,80 @@ mod test { assert_ne!(root1, root2); } + #[test] + fn halts_if_top_key_too_long() { + let bad_key = vec![1u8; MigrationMaxKeyLen::get() as usize + 1]; + let bad_top_keys = vec![(bad_key.clone(), vec![])]; + + new_test_ext(StateVersion::V0, true, Some(bad_top_keys), None).execute_with(|| { + System::set_block_number(1); + assert_eq!(MigrationProcess::::get(), Default::default()); + + // Allow signed migrations. + SignedMigrationMaxLimits::::put(MigrationLimits { size: 1 << 20, item: 50 }); + + // fails if the top key is too long. + frame_support::assert_err_with_weight!( + StateTrieMigration::continue_migrate( + Origin::signed(1), + MigrationLimits { item: 50, size: 1 << 20 }, + Bounded::max_value(), + MigrationProcess::::get() + ), + Error::::KeyTooLong, + Some(2000000), + ); + // The auto migration halted. + System::assert_last_event(crate::Event::Halted {}.into()); + // Limits are killed. + assert!(AutoLimits::::get().is_none()); + + // Calling `migrate_until_exhaustion` also fails. + let mut task = StateTrieMigration::migration_process(); + let result = task.migrate_until_exhaustion( + StateTrieMigration::signed_migration_max_limits().unwrap(), + ); + assert!(result.is_err()); + }); + } + + #[test] + fn halts_if_child_key_too_long() { + let bad_key = vec![1u8; MigrationMaxKeyLen::get() as usize + 1]; + let bad_child_keys = vec![(bad_key.clone(), vec![], vec![])]; + + new_test_ext(StateVersion::V0, true, None, Some(bad_child_keys)).execute_with(|| { + System::set_block_number(1); + assert_eq!(MigrationProcess::::get(), Default::default()); + + // Allow signed migrations. + SignedMigrationMaxLimits::::put(MigrationLimits { size: 1 << 20, item: 50 }); + + // fails if the top key is too long. + frame_support::assert_err_with_weight!( + StateTrieMigration::continue_migrate( + Origin::signed(1), + MigrationLimits { item: 50, size: 1 << 20 }, + Bounded::max_value(), + MigrationProcess::::get() + ), + Error::::KeyTooLong, + Some(2000000), + ); + // The auto migration halted. + System::assert_last_event(crate::Event::Halted {}.into()); + // Limits are killed. + assert!(AutoLimits::::get().is_none()); + + // Calling `migrate_until_exhaustion` also fails. + let mut task = StateTrieMigration::migration_process(); + let result = task.migrate_until_exhaustion( + StateTrieMigration::signed_migration_max_limits().unwrap(), + ); + assert!(result.is_err()); + }); + } + #[test] fn detects_value_in_empty_top_key() { let limit = MigrationLimits { item: 1, size: 1000 }; @@ -1319,7 +1483,7 @@ mod test { MigrationLimits { item: 5, size: 100 }, 100, MigrationTask { - progress_top: Progress::LastKey(vec![1u8]), + progress_top: Progress::LastKey(bounded_vec![1u8]), ..Default::default() } ), @@ -1330,9 +1494,10 @@ mod test { while !MigrationProcess::::get().finished() { // first we compute the task to get the accurate consumption. let mut task = StateTrieMigration::migration_process(); - task.migrate_until_exhaustion( + let result = task.migrate_until_exhaustion( StateTrieMigration::signed_migration_max_limits().unwrap(), ); + assert!(result.is_ok()); frame_support::assert_ok!(StateTrieMigration::continue_migrate( Origin::signed(1), @@ -1453,6 +1618,7 @@ pub(crate) mod remote_tests { use sp_runtime::traits::{Block as BlockT, HashFor, Header as _, One}; use thousands::Separable; + #[allow(dead_code)] fn run_to_block>( n: ::BlockNumber, ) -> (H256, u64) { @@ -1474,6 +1640,7 @@ pub(crate) mod remote_tests { /// Run the entire migration, against the given `Runtime`, until completion. /// /// This will print some very useful statistics, make sure [`crate::LOG_TARGET`] is enabled. + #[allow(dead_code)] pub(crate) async fn run_with_limits< Runtime: crate::Config, Block: BlockT + serde::de::DeserializeOwned, @@ -1571,8 +1738,9 @@ mod remote_tests_local { remote_tests::run_with_limits, *, }; - use remote_externalities::{Mode, OfflineConfig, OnlineConfig}; + use remote_externalities::{Mode, OfflineConfig, OnlineConfig, SnapshotConfig}; use sp_runtime::traits::Bounded; + use std::env::var as env_var; // we only use the hash type from this, so using the mock should be fine. type Extrinsic = sp_runtime::testing::TestXt; @@ -1580,14 +1748,13 @@ mod remote_tests_local { #[tokio::test] async fn on_initialize_migration() { + let snap: SnapshotConfig = env_var("SNAP").expect("Need SNAP env var").into(); + let ws_api = env_var("WS_API").expect("Need WS_API env var").into(); + sp_tracing::try_init_simple(); let mode = Mode::OfflineOrElseOnline( - OfflineConfig { state_snapshot: env!("SNAP").to_owned().into() }, - OnlineConfig { - transport: std::env!("WS_API").to_owned().into(), - state_snapshot: Some(env!("SNAP").to_owned().into()), - ..Default::default() - }, + OfflineConfig { state_snapshot: snap.clone() }, + OnlineConfig { transport: ws_api, state_snapshot: Some(snap), ..Default::default() }, ); // item being the bottleneck diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index fa37fa5cda22b..96bc1257c7598 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -762,7 +762,7 @@ macro_rules! assert_err_with_weight { ($call:expr, $err:expr, $weight:expr $(,)? ) => { if let Err(dispatch_err_with_post) = $call { $crate::assert_err!($call.map(|_| ()).map_err(|e| e.error), $err); - assert_eq!(dispatch_err_with_post.post_info.actual_weight, $weight.into()); + assert_eq!(dispatch_err_with_post.post_info.actual_weight, $weight); } else { panic!("expected Err(_), got Ok(_).") } From 26026d36a51c9f1c69b4f4e1503589b28e2019c6 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 13 Jun 2022 14:31:42 +0200 Subject: [PATCH 0906/1472] Move bounded type definitions to sp-runtime (#11645) * Move bounded type definitions to sp-runtime * cargo fmt * Fix compile error Signed-off-by: Oliver Tale-Yazdi * Move TryCollect to sp-runtime * Write some docs * Import missing types Co-authored-by: Oliver Tale-Yazdi --- frame/support/src/lib.rs | 43 +- .../support/src/storage/bounded_btree_map.rs | 489 +-------- .../support/src/storage/bounded_btree_set.rs | 451 +------- frame/support/src/storage/bounded_vec.rs | 976 +---------------- frame/support/src/storage/weak_bounded_vec.rs | 367 +------ frame/support/src/traits/misc.rs | 12 +- primitives/runtime/src/bounded.rs | 28 + .../runtime/src/bounded/bounded_btree_map.rs | 517 +++++++++ .../runtime/src/bounded/bounded_btree_set.rs | 479 +++++++++ primitives/runtime/src/bounded/bounded_vec.rs | 998 ++++++++++++++++++ .../runtime/src/bounded/weak_bounded_vec.rs | 393 +++++++ primitives/runtime/src/lib.rs | 43 + primitives/runtime/src/traits.rs | 11 + 13 files changed, 2484 insertions(+), 2323 deletions(-) create mode 100644 primitives/runtime/src/bounded.rs create mode 100644 primitives/runtime/src/bounded/bounded_btree_map.rs create mode 100644 primitives/runtime/src/bounded/bounded_btree_set.rs create mode 100644 primitives/runtime/src/bounded/bounded_vec.rs create mode 100644 primitives/runtime/src/bounded/weak_bounded_vec.rs diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 96bc1257c7598..f2cd7d1e165ec 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -45,6 +45,9 @@ pub use sp_core::Void; pub use sp_core_hashing_proc_macro; #[doc(hidden)] pub use sp_io::{self, storage::root as storage_root}; +#[cfg(feature = "std")] +#[doc(hidden)] +pub use sp_runtime::{bounded_btree_map, bounded_vec}; #[doc(hidden)] pub use sp_runtime::{RuntimeDebug, StateVersion}; #[cfg(feature = "std")] @@ -119,46 +122,6 @@ impl TypeId for PalletId { const TYPE_ID: [u8; 4] = *b"modl"; } -/// Build a bounded vec from the given literals. -/// -/// The type of the outcome must be known. -/// -/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding -/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. -#[macro_export] -#[cfg(feature = "std")] -macro_rules! bounded_vec { - ($ ($values:expr),* $(,)?) => { - { - $crate::sp_std::vec![$($values),*].try_into().unwrap() - } - }; - ( $value:expr ; $repetition:expr ) => { - { - $crate::sp_std::vec![$value ; $repetition].try_into().unwrap() - } - } -} - -/// Build a bounded btree-map from the given literals. -/// -/// The type of the outcome must be known. -/// -/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding -/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. -#[macro_export] -#[cfg(feature = "std")] -macro_rules! bounded_btree_map { - ($ ( $key:expr => $value:expr ),* $(,)?) => { - { - $crate::traits::TryCollect::<$crate::BoundedBTreeMap<_, _, _>>::try_collect( - $crate::sp_std::vec![$(($key, $value)),*].into_iter() - ).unwrap() - } - }; - -} - /// Generate a new type alias for [`storage::types::StorageValue`], /// [`storage::types::StorageMap`], [`storage::types::StorageDoubleMap`] /// and [`storage::types::StorageNMap`]. diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index fd086f1fb23a1..d567faa38fdc1 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -17,354 +17,18 @@ //! Traits, types and structs to support a bounded BTreeMap. -use crate::{ - storage::StorageDecodeLength, - traits::{Get, TryCollect}, -}; -use codec::{Decode, Encode, MaxEncodedLen}; -use sp_std::{borrow::Borrow, collections::btree_map::BTreeMap, marker::PhantomData, ops::Deref}; - -/// A bounded map based on a B-Tree. -/// -/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing -/// the amount of work performed in a search. See [`BTreeMap`] for more details. -/// -/// Unlike a standard `BTreeMap`, there is an enforced upper limit to the number of items in the -/// map. All internal operations ensure this bound is respected. -#[derive(Encode, scale_info::TypeInfo)] -#[scale_info(skip_type_params(S))] -pub struct BoundedBTreeMap(BTreeMap, PhantomData); - -impl Decode for BoundedBTreeMap -where - K: Decode + Ord, - V: Decode, - S: Get, -{ - fn decode(input: &mut I) -> Result { - let inner = BTreeMap::::decode(input)?; - if inner.len() > S::get() as usize { - return Err("BoundedBTreeMap exceeds its limit".into()) - } - Ok(Self(inner, PhantomData)) - } - - fn skip(input: &mut I) -> Result<(), codec::Error> { - BTreeMap::::skip(input) - } -} - -impl BoundedBTreeMap -where - S: Get, -{ - /// Get the bound of the type in `usize`. - pub fn bound() -> usize { - S::get() as usize - } -} - -impl BoundedBTreeMap -where - K: Ord, - S: Get, -{ - /// Create `Self` from `t` without any checks. - fn unchecked_from(t: BTreeMap) -> Self { - Self(t, Default::default()) - } - - /// Exactly the same semantics as `BTreeMap::retain`. - /// - /// The is a safe `&mut self` borrow because `retain` can only ever decrease the length of the - /// inner map. - pub fn retain bool>(&mut self, f: F) { - self.0.retain(f) - } - - /// Create a new `BoundedBTreeMap`. - /// - /// Does not allocate. - pub fn new() -> Self { - BoundedBTreeMap(BTreeMap::new(), PhantomData) - } - - /// Consume self, and return the inner `BTreeMap`. - /// - /// This is useful when a mutating API of the inner type is desired, and closure-based mutation - /// such as provided by [`try_mutate`][Self::try_mutate] is inconvenient. - pub fn into_inner(self) -> BTreeMap { - debug_assert!(self.0.len() <= Self::bound()); - self.0 - } - - /// Consumes self and mutates self via the given `mutate` function. - /// - /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is - /// returned. - /// - /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> - /// [`Self::try_from`]. - pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut BTreeMap)) -> Option { - mutate(&mut self.0); - (self.0.len() <= Self::bound()).then(move || self) - } - - // Clears the map, removing all elements. - pub fn clear(&mut self) { - self.0.clear() - } - - /// Return a mutable reference to the value corresponding to the key. - /// - /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed - /// form _must_ match the ordering on the key type. - pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Ord + ?Sized, - { - self.0.get_mut(key) - } - - /// Exactly the same semantics as [`BTreeMap::insert`], but returns an `Err` (and is a noop) if - /// the new length of the map exceeds `S`. - /// - /// In the `Err` case, returns the inserted pair so it can be further used without cloning. - pub fn try_insert(&mut self, key: K, value: V) -> Result, (K, V)> { - if self.len() < Self::bound() || self.0.contains_key(&key) { - Ok(self.0.insert(key, value)) - } else { - Err((key, value)) - } - } - - /// Remove a key from the map, returning the value at the key if the key was previously in the - /// map. - /// - /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed - /// form _must_ match the ordering on the key type. - pub fn remove(&mut self, key: &Q) -> Option - where - K: Borrow, - Q: Ord + ?Sized, - { - self.0.remove(key) - } - - /// Remove a key from the map, returning the value at the key if the key was previously in the - /// map. - /// - /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed - /// form _must_ match the ordering on the key type. - pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> - where - K: Borrow, - Q: Ord + ?Sized, - { - self.0.remove_entry(key) - } -} - -impl Default for BoundedBTreeMap -where - K: Ord, - S: Get, -{ - fn default() -> Self { - Self::new() - } -} - -impl Clone for BoundedBTreeMap -where - BTreeMap: Clone, -{ - fn clone(&self) -> Self { - BoundedBTreeMap(self.0.clone(), PhantomData) - } -} - -#[cfg(feature = "std")] -impl std::fmt::Debug for BoundedBTreeMap -where - BTreeMap: std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("BoundedBTreeMap").field(&self.0).field(&Self::bound()).finish() - } -} - -impl PartialEq> for BoundedBTreeMap -where - BTreeMap: PartialEq, - S1: Get, - S2: Get, -{ - fn eq(&self, other: &BoundedBTreeMap) -> bool { - S1::get() == S2::get() && self.0 == other.0 - } -} - -impl Eq for BoundedBTreeMap -where - BTreeMap: Eq, - S: Get, -{ -} - -impl PartialEq> for BoundedBTreeMap -where - BTreeMap: PartialEq, -{ - fn eq(&self, other: &BTreeMap) -> bool { - self.0 == *other - } -} - -impl PartialOrd for BoundedBTreeMap -where - BTreeMap: PartialOrd, - S: Get, -{ - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl Ord for BoundedBTreeMap -where - BTreeMap: Ord, - S: Get, -{ - fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl IntoIterator for BoundedBTreeMap { - type Item = (K, V); - type IntoIter = sp_std::collections::btree_map::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<'a, K, V, S> IntoIterator for &'a BoundedBTreeMap { - type Item = (&'a K, &'a V); - type IntoIter = sp_std::collections::btree_map::Iter<'a, K, V>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, K, V, S> IntoIterator for &'a mut BoundedBTreeMap { - type Item = (&'a K, &'a mut V); - type IntoIter = sp_std::collections::btree_map::IterMut<'a, K, V>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut() - } -} - -impl MaxEncodedLen for BoundedBTreeMap -where - K: MaxEncodedLen, - V: MaxEncodedLen, - S: Get, -{ - fn max_encoded_len() -> usize { - Self::bound() - .saturating_mul(K::max_encoded_len().saturating_add(V::max_encoded_len())) - .saturating_add(codec::Compact(S::get()).encoded_size()) - } -} - -impl Deref for BoundedBTreeMap -where - K: Ord, -{ - type Target = BTreeMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl AsRef> for BoundedBTreeMap -where - K: Ord, -{ - fn as_ref(&self) -> &BTreeMap { - &self.0 - } -} - -impl From> for BTreeMap -where - K: Ord, -{ - fn from(map: BoundedBTreeMap) -> Self { - map.0 - } -} - -impl TryFrom> for BoundedBTreeMap -where - K: Ord, - S: Get, -{ - type Error = (); - - fn try_from(value: BTreeMap) -> Result { - (value.len() <= Self::bound()) - .then(move || BoundedBTreeMap(value, PhantomData)) - .ok_or(()) - } -} - -impl codec::DecodeLength for BoundedBTreeMap { - fn len(self_encoded: &[u8]) -> Result { - // `BoundedBTreeMap` is stored just a `BTreeMap`, which is stored as a - // `Compact` with its length followed by an iteration of its items. We can just use - // the underlying implementation. - as codec::DecodeLength>::len(self_encoded) - } -} +use crate::storage::StorageDecodeLength; +pub use sp_runtime::BoundedBTreeMap; impl StorageDecodeLength for BoundedBTreeMap {} -impl codec::EncodeLike> for BoundedBTreeMap where - BTreeMap: Encode -{ -} - -impl TryCollect> for I -where - K: Ord, - I: ExactSizeIterator + Iterator, - Bound: Get, -{ - type Error = &'static str; - - fn try_collect(self) -> Result, Self::Error> { - if self.len() > Bound::get() as usize { - Err("iterator length too big") - } else { - Ok(BoundedBTreeMap::::unchecked_from(self.collect::>())) - } - } -} - #[cfg(test)] pub mod test { use super::*; use crate::Twox128; - use frame_support::traits::ConstU32; + use frame_support::traits::{ConstU32, Get}; use sp_io::TestExternalities; + use sp_std::collections::btree_map::BTreeMap; #[crate::storage_alias] type Foo = StorageValue>>; @@ -416,149 +80,4 @@ pub mod test { assert!(FooDoubleMap::decode_len(2, 2).is_none()); }); } - - #[test] - fn try_insert_works() { - let mut bounded = boundedmap_from_keys::>(&[1, 2, 3]); - bounded.try_insert(0, ()).unwrap(); - assert_eq!(*bounded, map_from_keys(&[1, 0, 2, 3])); - - assert!(bounded.try_insert(9, ()).is_err()); - assert_eq!(*bounded, map_from_keys(&[1, 0, 2, 3])); - } - - #[test] - fn deref_coercion_works() { - let bounded = boundedmap_from_keys::>(&[1, 2, 3]); - // these methods come from deref-ed vec. - assert_eq!(bounded.len(), 3); - assert!(bounded.iter().next().is_some()); - assert!(!bounded.is_empty()); - } - - #[test] - fn try_mutate_works() { - let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); - let bounded = bounded - .try_mutate(|v| { - v.insert(7, ()); - }) - .unwrap(); - assert_eq!(bounded.len(), 7); - assert!(bounded - .try_mutate(|v| { - v.insert(8, ()); - }) - .is_none()); - } - - #[test] - fn btree_map_eq_works() { - let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); - assert_eq!(bounded, map_from_keys(&[1, 2, 3, 4, 5, 6])); - } - - #[test] - fn too_big_fail_to_decode() { - let v: Vec<(u32, u32)> = vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]; - assert_eq!( - BoundedBTreeMap::>::decode(&mut &v.encode()[..]), - Err("BoundedBTreeMap exceeds its limit".into()), - ); - } - - #[test] - fn unequal_eq_impl_insert_works() { - // given a struct with a strange notion of equality - #[derive(Debug)] - struct Unequal(u32, bool); - - impl PartialEq for Unequal { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - impl Eq for Unequal {} - - impl Ord for Unequal { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.0.cmp(&other.0) - } - } - - impl PartialOrd for Unequal { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - let mut map = BoundedBTreeMap::>::new(); - - // when the set is full - - for i in 0..4 { - map.try_insert(Unequal(i, false), i).unwrap(); - } - - // can't insert a new distinct member - map.try_insert(Unequal(5, false), 5).unwrap_err(); - - // but _can_ insert a distinct member which compares equal, though per the documentation, - // neither the set length nor the actual member are changed, but the value is - map.try_insert(Unequal(0, true), 6).unwrap(); - assert_eq!(map.len(), 4); - let (zero_key, zero_value) = map.get_key_value(&Unequal(0, true)).unwrap(); - assert_eq!(zero_key.0, 0); - assert_eq!(zero_key.1, false); - assert_eq!(*zero_value, 6); - } - - #[test] - fn can_be_collected() { - let b1 = boundedmap_from_keys::>(&[1, 2, 3, 4]); - let b2: BoundedBTreeMap> = - b1.iter().map(|(k, v)| (k + 1, *v)).try_collect().unwrap(); - assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3, 4, 5]); - - // can also be collected into a collection of length 4. - let b2: BoundedBTreeMap> = - b1.iter().map(|(k, v)| (k + 1, *v)).try_collect().unwrap(); - assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3, 4, 5]); - - // can be mutated further into iterators that are `ExactSizedIterator`. - let b2: BoundedBTreeMap> = - b1.iter().map(|(k, v)| (k + 1, *v)).rev().skip(2).try_collect().unwrap(); - // note that the binary tree will re-sort this, so rev() is not really seen - assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3]); - - let b2: BoundedBTreeMap> = - b1.iter().map(|(k, v)| (k + 1, *v)).take(2).try_collect().unwrap(); - assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3]); - - // but these worn't work - let b2: Result>, _> = - b1.iter().map(|(k, v)| (k + 1, *v)).try_collect(); - assert!(b2.is_err()); - - let b2: Result>, _> = - b1.iter().map(|(k, v)| (k + 1, *v)).skip(2).try_collect(); - assert!(b2.is_err()); - } - - #[test] - fn eq_works() { - // of same type - let b1 = boundedmap_from_keys::>(&[1, 2]); - let b2 = boundedmap_from_keys::>(&[1, 2]); - assert_eq!(b1, b2); - - // of different type, but same value and bound. - crate::parameter_types! { - B1: u32 = 7; - B2: u32 = 7; - } - let b1 = boundedmap_from_keys::(&[1, 2]); - let b2 = boundedmap_from_keys::(&[1, 2]); - assert_eq!(b1, b2); - } } diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index 77e1c6f1c9625..9ed129e67c46c 100644 --- a/frame/support/src/storage/bounded_btree_set.rs +++ b/frame/support/src/storage/bounded_btree_set.rs @@ -17,319 +17,18 @@ //! Traits, types and structs to support a bounded `BTreeSet`. -use crate::{ - storage::StorageDecodeLength, - traits::{Get, TryCollect}, -}; -use codec::{Decode, Encode, MaxEncodedLen}; -use sp_std::{borrow::Borrow, collections::btree_set::BTreeSet, marker::PhantomData, ops::Deref}; - -/// A bounded set based on a B-Tree. -/// -/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing -/// the amount of work performed in a search. See [`BTreeSet`] for more details. -/// -/// Unlike a standard `BTreeSet`, there is an enforced upper limit to the number of items in the -/// set. All internal operations ensure this bound is respected. -#[derive(Encode, scale_info::TypeInfo)] -#[scale_info(skip_type_params(S))] -pub struct BoundedBTreeSet(BTreeSet, PhantomData); - -impl Decode for BoundedBTreeSet -where - T: Decode + Ord, - S: Get, -{ - fn decode(input: &mut I) -> Result { - let inner = BTreeSet::::decode(input)?; - if inner.len() > S::get() as usize { - return Err("BoundedBTreeSet exceeds its limit".into()) - } - Ok(Self(inner, PhantomData)) - } - - fn skip(input: &mut I) -> Result<(), codec::Error> { - BTreeSet::::skip(input) - } -} - -impl BoundedBTreeSet -where - S: Get, -{ - /// Get the bound of the type in `usize`. - pub fn bound() -> usize { - S::get() as usize - } -} - -impl BoundedBTreeSet -where - T: Ord, - S: Get, -{ - /// Create `Self` from `t` without any checks. - fn unchecked_from(t: BTreeSet) -> Self { - Self(t, Default::default()) - } - - /// Create a new `BoundedBTreeSet`. - /// - /// Does not allocate. - pub fn new() -> Self { - BoundedBTreeSet(BTreeSet::new(), PhantomData) - } - - /// Consume self, and return the inner `BTreeSet`. - /// - /// This is useful when a mutating API of the inner type is desired, and closure-based mutation - /// such as provided by [`try_mutate`][Self::try_mutate] is inconvenient. - pub fn into_inner(self) -> BTreeSet { - debug_assert!(self.0.len() <= Self::bound()); - self.0 - } - - /// Consumes self and mutates self via the given `mutate` function. - /// - /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is - /// returned. - /// - /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> - /// [`Self::try_from`]. - pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut BTreeSet)) -> Option { - mutate(&mut self.0); - (self.0.len() <= Self::bound()).then(move || self) - } - - // Clears the set, removing all elements. - pub fn clear(&mut self) { - self.0.clear() - } - - /// Exactly the same semantics as [`BTreeSet::insert`], but returns an `Err` (and is a noop) if - /// the new length of the set exceeds `S`. - /// - /// In the `Err` case, returns the inserted item so it can be further used without cloning. - pub fn try_insert(&mut self, item: T) -> Result { - if self.len() < Self::bound() || self.0.contains(&item) { - Ok(self.0.insert(item)) - } else { - Err(item) - } - } - - /// Remove an item from the set, returning whether it was previously in the set. - /// - /// The item may be any borrowed form of the set's item type, but the ordering on the borrowed - /// form _must_ match the ordering on the item type. - pub fn remove(&mut self, item: &Q) -> bool - where - T: Borrow, - Q: Ord + ?Sized, - { - self.0.remove(item) - } - - /// Removes and returns the value in the set, if any, that is equal to the given one. - /// - /// The value may be any borrowed form of the set's value type, but the ordering on the borrowed - /// form _must_ match the ordering on the value type. - pub fn take(&mut self, value: &Q) -> Option - where - T: Borrow + Ord, - Q: Ord + ?Sized, - { - self.0.take(value) - } -} - -impl Default for BoundedBTreeSet -where - T: Ord, - S: Get, -{ - fn default() -> Self { - Self::new() - } -} - -impl Clone for BoundedBTreeSet -where - BTreeSet: Clone, -{ - fn clone(&self) -> Self { - BoundedBTreeSet(self.0.clone(), PhantomData) - } -} - -#[cfg(feature = "std")] -impl std::fmt::Debug for BoundedBTreeSet -where - BTreeSet: std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("BoundedBTreeSet").field(&self.0).field(&Self::bound()).finish() - } -} - -impl PartialEq> for BoundedBTreeSet -where - BTreeSet: PartialEq, - S1: Get, - S2: Get, -{ - fn eq(&self, other: &BoundedBTreeSet) -> bool { - S1::get() == S2::get() && self.0 == other.0 - } -} - -impl Eq for BoundedBTreeSet -where - BTreeSet: Eq, - S: Get, -{ -} - -impl PartialEq> for BoundedBTreeSet -where - BTreeSet: PartialEq, - S: Get, -{ - fn eq(&self, other: &BTreeSet) -> bool { - self.0 == *other - } -} - -impl PartialOrd for BoundedBTreeSet -where - BTreeSet: PartialOrd, - S: Get, -{ - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl Ord for BoundedBTreeSet -where - BTreeSet: Ord, - S: Get, -{ - fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl IntoIterator for BoundedBTreeSet { - type Item = T; - type IntoIter = sp_std::collections::btree_set::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<'a, T, S> IntoIterator for &'a BoundedBTreeSet { - type Item = &'a T; - type IntoIter = sp_std::collections::btree_set::Iter<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl MaxEncodedLen for BoundedBTreeSet -where - T: MaxEncodedLen, - S: Get, -{ - fn max_encoded_len() -> usize { - Self::bound() - .saturating_mul(T::max_encoded_len()) - .saturating_add(codec::Compact(S::get()).encoded_size()) - } -} - -impl Deref for BoundedBTreeSet -where - T: Ord, -{ - type Target = BTreeSet; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl AsRef> for BoundedBTreeSet -where - T: Ord, -{ - fn as_ref(&self) -> &BTreeSet { - &self.0 - } -} - -impl From> for BTreeSet -where - T: Ord, -{ - fn from(set: BoundedBTreeSet) -> Self { - set.0 - } -} - -impl TryFrom> for BoundedBTreeSet -where - T: Ord, - S: Get, -{ - type Error = (); - - fn try_from(value: BTreeSet) -> Result { - (value.len() <= Self::bound()) - .then(move || BoundedBTreeSet(value, PhantomData)) - .ok_or(()) - } -} - -impl codec::DecodeLength for BoundedBTreeSet { - fn len(self_encoded: &[u8]) -> Result { - // `BoundedBTreeSet` is stored just a `BTreeSet`, which is stored as a - // `Compact` with its length followed by an iteration of its items. We can just use - // the underlying implementation. - as codec::DecodeLength>::len(self_encoded) - } -} +use crate::storage::StorageDecodeLength; +pub use sp_runtime::BoundedBTreeSet; impl StorageDecodeLength for BoundedBTreeSet {} -impl codec::EncodeLike> for BoundedBTreeSet where BTreeSet: Encode {} - -impl TryCollect> for I -where - T: Ord, - I: ExactSizeIterator + Iterator, - Bound: Get, -{ - type Error = &'static str; - - fn try_collect(self) -> Result, Self::Error> { - if self.len() > Bound::get() as usize { - Err("iterator length too big") - } else { - Ok(BoundedBTreeSet::::unchecked_from(self.collect::>())) - } - } -} - #[cfg(test)] pub mod test { use super::*; use crate::Twox128; - use frame_support::traits::ConstU32; + use frame_support::traits::{ConstU32, Get}; use sp_io::TestExternalities; + use sp_std::collections::btree_set::BTreeSet; #[crate::storage_alias] type Foo = StorageValue>>; @@ -381,146 +80,4 @@ pub mod test { assert!(FooDoubleMap::decode_len(2, 2).is_none()); }); } - - #[test] - fn try_insert_works() { - let mut bounded = boundedset_from_keys::>(&[1, 2, 3]); - bounded.try_insert(0).unwrap(); - assert_eq!(*bounded, set_from_keys(&[1, 0, 2, 3])); - - assert!(bounded.try_insert(9).is_err()); - assert_eq!(*bounded, set_from_keys(&[1, 0, 2, 3])); - } - - #[test] - fn deref_coercion_works() { - let bounded = boundedset_from_keys::>(&[1, 2, 3]); - // these methods come from deref-ed vec. - assert_eq!(bounded.len(), 3); - assert!(bounded.iter().next().is_some()); - assert!(!bounded.is_empty()); - } - - #[test] - fn try_mutate_works() { - let bounded = boundedset_from_keys::>(&[1, 2, 3, 4, 5, 6]); - let bounded = bounded - .try_mutate(|v| { - v.insert(7); - }) - .unwrap(); - assert_eq!(bounded.len(), 7); - assert!(bounded - .try_mutate(|v| { - v.insert(8); - }) - .is_none()); - } - - #[test] - fn btree_map_eq_works() { - let bounded = boundedset_from_keys::>(&[1, 2, 3, 4, 5, 6]); - assert_eq!(bounded, set_from_keys(&[1, 2, 3, 4, 5, 6])); - } - - #[test] - fn too_big_fail_to_decode() { - let v: Vec = vec![1, 2, 3, 4, 5]; - assert_eq!( - BoundedBTreeSet::>::decode(&mut &v.encode()[..]), - Err("BoundedBTreeSet exceeds its limit".into()), - ); - } - - #[test] - fn unequal_eq_impl_insert_works() { - // given a struct with a strange notion of equality - #[derive(Debug)] - struct Unequal(u32, bool); - - impl PartialEq for Unequal { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - impl Eq for Unequal {} - - impl Ord for Unequal { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.0.cmp(&other.0) - } - } - - impl PartialOrd for Unequal { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - let mut set = BoundedBTreeSet::>::new(); - - // when the set is full - - for i in 0..4 { - set.try_insert(Unequal(i, false)).unwrap(); - } - - // can't insert a new distinct member - set.try_insert(Unequal(5, false)).unwrap_err(); - - // but _can_ insert a distinct member which compares equal, though per the documentation, - // neither the set length nor the actual member are changed - set.try_insert(Unequal(0, true)).unwrap(); - assert_eq!(set.len(), 4); - let zero_item = set.get(&Unequal(0, true)).unwrap(); - assert_eq!(zero_item.0, 0); - assert_eq!(zero_item.1, false); - } - - #[test] - fn can_be_collected() { - let b1 = boundedset_from_keys::>(&[1, 2, 3, 4]); - let b2: BoundedBTreeSet> = b1.iter().map(|k| k + 1).try_collect().unwrap(); - assert_eq!(b2.into_iter().collect::>(), vec![2, 3, 4, 5]); - - // can also be collected into a collection of length 4. - let b2: BoundedBTreeSet> = b1.iter().map(|k| k + 1).try_collect().unwrap(); - assert_eq!(b2.into_iter().collect::>(), vec![2, 3, 4, 5]); - - // can be mutated further into iterators that are `ExactSizedIterator`. - let b2: BoundedBTreeSet> = - b1.iter().map(|k| k + 1).rev().skip(2).try_collect().unwrap(); - // note that the binary tree will re-sort this, so rev() is not really seen - assert_eq!(b2.into_iter().collect::>(), vec![2, 3]); - - let b2: BoundedBTreeSet> = - b1.iter().map(|k| k + 1).take(2).try_collect().unwrap(); - assert_eq!(b2.into_iter().collect::>(), vec![2, 3]); - - // but these worn't work - let b2: Result>, _> = - b1.iter().map(|k| k + 1).try_collect(); - assert!(b2.is_err()); - - let b2: Result>, _> = - b1.iter().map(|k| k + 1).skip(2).try_collect(); - assert!(b2.is_err()); - } - - #[test] - fn eq_works() { - // of same type - let b1 = boundedset_from_keys::>(&[1, 2]); - let b2 = boundedset_from_keys::>(&[1, 2]); - assert_eq!(b1, b2); - - // of different type, but same value and bound. - crate::parameter_types! { - B1: u32 = 7; - B2: u32 = 7; - } - let b1 = boundedset_from_keys::(&[1, 2]); - let b2 = boundedset_from_keys::(&[1, 2]); - assert_eq!(b1, b2); - } } diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 82ae36a82bf9f..1fa01b44ae6c4 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -20,641 +20,9 @@ use crate::{ storage::{StorageDecodeLength, StorageTryAppend}, - traits::{Get, TryCollect}, - WeakBoundedVec, + traits::Get, }; -use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; -use core::{ - ops::{Deref, Index, IndexMut, RangeBounds}, - slice::SliceIndex, -}; -#[cfg(feature = "std")] -use serde::{ - de::{Error, SeqAccess, Visitor}, - Deserialize, Deserializer, Serialize, -}; -use sp_std::{marker::PhantomData, prelude::*}; - -/// A bounded vector. -/// -/// It has implementations for efficient append and length decoding, as with a normal `Vec<_>`, once -/// put into storage as a raw value, map or double-map. -/// -/// As the name suggests, the length of the queue is always bounded. All internal operations ensure -/// this bound is respected. -#[cfg_attr(feature = "std", derive(Serialize), serde(transparent))] -#[derive(Encode, scale_info::TypeInfo)] -#[scale_info(skip_type_params(S))] -pub struct BoundedVec( - Vec, - #[cfg_attr(feature = "std", serde(skip_serializing))] PhantomData, -); - -#[cfg(feature = "std")] -impl<'de, T, S: Get> Deserialize<'de> for BoundedVec -where - T: Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct VecVisitor>(PhantomData<(T, S)>); - - impl<'de, T, S: Get> Visitor<'de> for VecVisitor - where - T: Deserialize<'de>, - { - type Value = Vec; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a sequence") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let size = seq.size_hint().unwrap_or(0); - let max = match usize::try_from(S::get()) { - Ok(n) => n, - Err(_) => return Err(A::Error::custom("can't convert to usize")), - }; - if size > max { - Err(A::Error::custom("out of bounds")) - } else { - let mut values = Vec::with_capacity(size); - - while let Some(value) = seq.next_element()? { - values.push(value); - if values.len() > max { - return Err(A::Error::custom("out of bounds")) - } - } - - Ok(values) - } - } - } - - let visitor: VecVisitor = VecVisitor(PhantomData); - deserializer - .deserialize_seq(visitor) - .map(|v| BoundedVec::::try_from(v).map_err(|_| Error::custom("out of bounds")))? - } -} - -/// A bounded slice. -/// -/// Similar to a `BoundedVec`, but not owned and cannot be decoded. -#[derive(Encode, scale_info::TypeInfo)] -#[scale_info(skip_type_params(S))] -pub struct BoundedSlice<'a, T, S>(&'a [T], PhantomData); - -// `BoundedSlice`s encode to something which will always decode into a `BoundedVec`, -// `WeakBoundedVec`, or a `Vec`. -impl<'a, T: Encode + Decode, S: Get> EncodeLike> for BoundedSlice<'a, T, S> {} -impl<'a, T: Encode + Decode, S: Get> EncodeLike> - for BoundedSlice<'a, T, S> -{ -} -impl<'a, T: Encode + Decode, S: Get> EncodeLike> for BoundedSlice<'a, T, S> {} - -impl> PartialOrd for BoundedVec { - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl> Ord for BoundedVec { - fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl<'a, T, S: Get> TryFrom<&'a [T]> for BoundedSlice<'a, T, S> { - type Error = (); - fn try_from(t: &'a [T]) -> Result { - if t.len() <= S::get() as usize { - Ok(BoundedSlice(t, PhantomData)) - } else { - Err(()) - } - } -} - -impl<'a, T, S> From> for &'a [T] { - fn from(t: BoundedSlice<'a, T, S>) -> Self { - t.0 - } -} - -impl<'a, T, S> sp_std::iter::IntoIterator for BoundedSlice<'a, T, S> { - type Item = &'a T; - type IntoIter = sp_std::slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl> Decode for BoundedVec { - fn decode(input: &mut I) -> Result { - let inner = Vec::::decode(input)?; - if inner.len() > S::get() as usize { - return Err("BoundedVec exceeds its limit".into()) - } - Ok(Self(inner, PhantomData)) - } - - fn skip(input: &mut I) -> Result<(), codec::Error> { - Vec::::skip(input) - } -} - -// `BoundedVec`s encode to something which will always decode as a `Vec`. -impl> EncodeLike> for BoundedVec {} - -impl BoundedVec { - /// Create `Self` from `t` without any checks. - fn unchecked_from(t: Vec) -> Self { - Self(t, Default::default()) - } - - /// Consume self, and return the inner `Vec`. Henceforth, the `Vec<_>` can be altered in an - /// arbitrary way. At some point, if the reverse conversion is required, `TryFrom>` can - /// be used. - /// - /// This is useful for cases if you need access to an internal API of the inner `Vec<_>` which - /// is not provided by the wrapper `BoundedVec`. - pub fn into_inner(self) -> Vec { - self.0 - } - - /// Exactly the same semantics as [`slice::sort_by`]. - /// - /// This is safe since sorting cannot change the number of elements in the vector. - pub fn sort_by(&mut self, compare: F) - where - F: FnMut(&T, &T) -> sp_std::cmp::Ordering, - { - self.0.sort_by(compare) - } - - /// Exactly the same semantics as [`slice::sort`]. - /// - /// This is safe since sorting cannot change the number of elements in the vector. - pub fn sort(&mut self) - where - T: sp_std::cmp::Ord, - { - self.0.sort() - } - - /// Exactly the same semantics as `Vec::remove`. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn remove(&mut self, index: usize) -> T { - self.0.remove(index) - } - - /// Exactly the same semantics as `slice::swap_remove`. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn swap_remove(&mut self, index: usize) -> T { - self.0.swap_remove(index) - } - - /// Exactly the same semantics as `Vec::retain`. - pub fn retain bool>(&mut self, f: F) { - self.0.retain(f) - } - - /// Exactly the same semantics as `slice::get_mut`. - pub fn get_mut>( - &mut self, - index: I, - ) -> Option<&mut >::Output> { - self.0.get_mut(index) - } - - /// Exactly the same semantics as `Vec::truncate`. - /// - /// This is safe because `truncate` can never increase the length of the internal vector. - pub fn truncate(&mut self, s: usize) { - self.0.truncate(s); - } - - /// Exactly the same semantics as `Vec::pop`. - /// - /// This is safe since popping can only shrink the inner vector. - pub fn pop(&mut self) -> Option { - self.0.pop() - } - - /// Exactly the same semantics as [`slice::iter_mut`]. - pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> { - self.0.iter_mut() - } - - /// Exactly the same semantics as [`slice::last_mut`]. - pub fn last_mut(&mut self) -> Option<&mut T> { - self.0.last_mut() - } - - /// Exact same semantics as [`Vec::drain`]. - pub fn drain(&mut self, range: R) -> sp_std::vec::Drain<'_, T> - where - R: RangeBounds, - { - self.0.drain(range) - } -} - -impl> From> for Vec { - fn from(x: BoundedVec) -> Vec { - x.0 - } -} - -impl> BoundedVec { - /// Pre-allocate `capacity` items in self. - /// - /// If `capacity` is greater than [`Self::bound`], then the minimum of the two is used. - pub fn with_bounded_capacity(capacity: usize) -> Self { - let capacity = capacity.min(Self::bound()); - Self(Vec::with_capacity(capacity), Default::default()) - } - - /// Allocate self with the maximum possible capacity. - pub fn with_max_capacity() -> Self { - Self::with_bounded_capacity(Self::bound()) - } - - /// Consume and truncate the vector `v` in order to create a new instance of `Self` from it. - pub fn truncate_from(mut v: Vec) -> Self { - v.truncate(Self::bound()); - Self::unchecked_from(v) - } - - /// Get the bound of the type in `usize`. - pub fn bound() -> usize { - S::get() as usize - } - - /// Returns true of this collection is full. - pub fn is_full(&self) -> bool { - self.len() >= Self::bound() - } - - /// Forces the insertion of `element` into `self` retaining all items with index at least - /// `index`. - /// - /// If `index == 0` and `self.len() == Self::bound()`, then this is a no-op. - /// - /// If `Self::bound() < index` or `self.len() < index`, then this is also a no-op. - /// - /// Returns `Ok(maybe_removed)` if the item was inserted, where `maybe_removed` is - /// `Some(removed)` if an item was removed to make room for the new one. Returns `Err(())` if - /// `element` cannot be inserted. - pub fn force_insert_keep_right( - &mut self, - index: usize, - mut element: T, - ) -> Result, ()> { - // Check against panics. - if Self::bound() < index || self.len() < index { - Err(()) - } else if self.len() < Self::bound() { - // Cannot panic since self.len() >= index; - self.0.insert(index, element); - Ok(None) - } else { - if index == 0 { - return Err(()) - } - sp_std::mem::swap(&mut self[0], &mut element); - // `[0..index] cannot panic since self.len() >= index. - // `rotate_left(1)` cannot panic because there is at least 1 element. - self[0..index].rotate_left(1); - Ok(Some(element)) - } - } - - /// Forces the insertion of `element` into `self` retaining all items with index at most - /// `index`. - /// - /// If `index == Self::bound()` and `self.len() == Self::bound()`, then this is a no-op. - /// - /// If `Self::bound() < index` or `self.len() < index`, then this is also a no-op. - /// - /// Returns `Ok(maybe_removed)` if the item was inserted, where `maybe_removed` is - /// `Some(removed)` if an item was removed to make room for the new one. Returns `Err(())` if - /// `element` cannot be inserted. - pub fn force_insert_keep_left(&mut self, index: usize, element: T) -> Result, ()> { - // Check against panics. - if Self::bound() < index || self.len() < index || Self::bound() == 0 { - return Err(()) - } - // Noop condition. - if Self::bound() == index && self.len() <= Self::bound() { - return Err(()) - } - let maybe_removed = if self.is_full() { - // defensive-only: since we are at capacity, this is a noop. - self.0.truncate(Self::bound()); - // if we truncate anything, it will be the last one. - self.0.pop() - } else { - None - }; - - // Cannot panic since `self.len() >= index`; - self.0.insert(index, element); - Ok(maybe_removed) - } - - /// Move the position of an item from one location to another in the slice. - /// - /// Except for the item being moved, the order of the slice remains the same. - /// - /// - `index` is the location of the item to be moved. - /// - `insert_position` is the index of the item in the slice which should *immediately follow* - /// the item which is being moved. - /// - /// Returns `true` of the operation was successful, otherwise `false` if a noop. - pub fn slide(&mut self, index: usize, insert_position: usize) -> bool { - // Check against panics. - if self.len() <= index || self.len() < insert_position || index == usize::MAX { - return false - } - // Noop conditions. - if index == insert_position || index + 1 == insert_position { - return false - } - if insert_position < index && index < self.len() { - // --- --- --- === === === === @@@ --- --- --- - // ^-- N ^O^ - // ... - // /-----<<<-----\ - // --- --- --- === === === === @@@ --- --- --- - // >>> >>> >>> >>> - // ... - // --- --- --- @@@ === === === === --- --- --- - // ^N^ - self[insert_position..index + 1].rotate_right(1); - return true - } else if insert_position > 0 && index + 1 < insert_position { - // Note that the apparent asymmetry of these two branches is due to the - // fact that the "new" position is the position to be inserted *before*. - // --- --- --- @@@ === === === === --- --- --- - // ^O^ ^-- N - // ... - // /----->>>-----\ - // --- --- --- @@@ === === === === --- --- --- - // <<< <<< <<< <<< - // ... - // --- --- --- === === === === @@@ --- --- --- - // ^N^ - self[index..insert_position].rotate_left(1); - return true - } - - debug_assert!(false, "all noop conditions should have been covered above"); - false - } - - /// Forces the insertion of `s` into `self` truncating first if necessary. - /// - /// Infallible, but if the bound is zero, then it's a no-op. - pub fn force_push(&mut self, element: T) { - if Self::bound() > 0 { - self.0.truncate(Self::bound() as usize - 1); - self.0.push(element); - } - } - - /// Same as `Vec::resize`, but if `size` is more than [`Self::bound`], then [`Self::bound`] is - /// used. - pub fn bounded_resize(&mut self, size: usize, value: T) - where - T: Clone, - { - let size = size.min(Self::bound()); - self.0.resize(size, value); - } - - /// Exactly the same semantics as [`Vec::extend`], but returns an error and does nothing if the - /// length of the outcome is larger than the bound. - pub fn try_extend( - &mut self, - with: impl IntoIterator + ExactSizeIterator, - ) -> Result<(), ()> { - if with.len().saturating_add(self.len()) <= Self::bound() { - self.0.extend(with); - Ok(()) - } else { - Err(()) - } - } - - /// Exactly the same semantics as [`Vec::append`], but returns an error and does nothing if the - /// length of the outcome is larger than the bound. - pub fn try_append(&mut self, other: &mut Vec) -> Result<(), ()> { - if other.len().saturating_add(self.len()) <= Self::bound() { - self.0.append(other); - Ok(()) - } else { - Err(()) - } - } - - /// Consumes self and mutates self via the given `mutate` function. - /// - /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is - /// returned. - /// - /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> - /// [`Self::try_from`]. - pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut Vec)) -> Option { - mutate(&mut self.0); - (self.0.len() <= Self::bound()).then(move || self) - } - - /// Exactly the same semantics as [`Vec::insert`], but returns an `Err` (and is a noop) if the - /// new length of the vector exceeds `S`. - /// - /// # Panics - /// - /// Panics if `index > len`. - pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), ()> { - if self.len() < Self::bound() { - self.0.insert(index, element); - Ok(()) - } else { - Err(()) - } - } - - /// Exactly the same semantics as [`Vec::push`], but returns an `Err` (and is a noop) if the - /// new length of the vector exceeds `S`. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds isize::MAX bytes. - pub fn try_push(&mut self, element: T) -> Result<(), ()> { - if self.len() < Self::bound() { - self.0.push(element); - Ok(()) - } else { - Err(()) - } - } -} - -impl Default for BoundedVec { - fn default() -> Self { - // the bound cannot be below 0, which is satisfied by an empty vector - Self::unchecked_from(Vec::default()) - } -} - -impl sp_std::fmt::Debug for BoundedVec -where - T: sp_std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - f.debug_tuple("BoundedVec").field(&self.0).field(&Self::bound()).finish() - } -} - -impl Clone for BoundedVec -where - T: Clone, -{ - fn clone(&self) -> Self { - // bound is retained - Self::unchecked_from(self.0.clone()) - } -} - -impl> TryFrom> for BoundedVec { - type Error = (); - fn try_from(t: Vec) -> Result { - if t.len() <= Self::bound() { - // explicit check just above - Ok(Self::unchecked_from(t)) - } else { - Err(()) - } - } -} - -// It is okay to give a non-mutable reference of the inner vec to anyone. -impl AsRef> for BoundedVec { - fn as_ref(&self) -> &Vec { - &self.0 - } -} - -impl AsRef<[T]> for BoundedVec { - fn as_ref(&self) -> &[T] { - &self.0 - } -} - -impl AsMut<[T]> for BoundedVec { - fn as_mut(&mut self) -> &mut [T] { - &mut self.0 - } -} - -// will allow for immutable all operations of `Vec` on `BoundedVec`. -impl Deref for BoundedVec { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// Allows for indexing similar to a normal `Vec`. Can panic if out of bound. -impl Index for BoundedVec -where - I: SliceIndex<[T]>, -{ - type Output = I::Output; - - #[inline] - fn index(&self, index: I) -> &Self::Output { - self.0.index(index) - } -} - -impl IndexMut for BoundedVec -where - I: SliceIndex<[T]>, -{ - #[inline] - fn index_mut(&mut self, index: I) -> &mut Self::Output { - self.0.index_mut(index) - } -} - -impl sp_std::iter::IntoIterator for BoundedVec { - type Item = T; - type IntoIter = sp_std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<'a, T, S> sp_std::iter::IntoIterator for &'a BoundedVec { - type Item = &'a T; - type IntoIter = sp_std::slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, T, S> sp_std::iter::IntoIterator for &'a mut BoundedVec { - type Item = &'a mut T; - type IntoIter = sp_std::slice::IterMut<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut() - } -} - -impl codec::DecodeLength for BoundedVec { - fn len(self_encoded: &[u8]) -> Result { - // `BoundedVec` stored just a `Vec`, thus the length is at the beginning in - // `Compact` form, and same implementation as `Vec` can be used. - as codec::DecodeLength>::len(self_encoded) - } -} - -impl PartialEq> for BoundedVec -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - fn eq(&self, rhs: &BoundedVec) -> bool { - BoundSelf::get() == BoundRhs::get() && self.0 == rhs.0 - } -} - -impl> PartialEq> for BoundedVec { - fn eq(&self, other: &Vec) -> bool { - &self.0 == other - } -} - -impl> Eq for BoundedVec where T: Eq {} +pub use sp_runtime::{BoundedSlice, BoundedVec}; impl StorageDecodeLength for BoundedVec {} @@ -664,38 +32,6 @@ impl> StorageTryAppend for BoundedVec { } } -impl MaxEncodedLen for BoundedVec -where - T: MaxEncodedLen, - S: Get, - BoundedVec: Encode, -{ - fn max_encoded_len() -> usize { - // BoundedVec encodes like Vec which encodes like [T], which is a compact u32 - // plus each item in the slice: - // https://docs.substrate.io/v3/advanced/scale-codec - codec::Compact(S::get()) - .encoded_size() - .saturating_add(Self::bound().saturating_mul(T::max_encoded_len())) - } -} - -impl TryCollect> for I -where - I: ExactSizeIterator + Iterator, - Bound: Get, -{ - type Error = &'static str; - - fn try_collect(self) -> Result, Self::Error> { - if self.len() > Bound::get() as usize { - Err("iterator length too big") - } else { - Ok(BoundedVec::::unchecked_from(self.collect::>())) - } - } -} - #[cfg(test)] pub mod test { use super::*; @@ -712,108 +48,6 @@ pub mod test { type FooDoubleMap = StorageDoubleMap>>; - #[test] - fn slide_works() { - let mut b: BoundedVec> = bounded_vec![0, 1, 2, 3, 4, 5]; - assert!(b.slide(1, 5)); - assert_eq!(*b, vec![0, 2, 3, 4, 1, 5]); - assert!(b.slide(4, 0)); - assert_eq!(*b, vec![1, 0, 2, 3, 4, 5]); - assert!(b.slide(0, 2)); - assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); - assert!(b.slide(1, 6)); - assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); - assert!(b.slide(0, 6)); - assert_eq!(*b, vec![2, 3, 4, 5, 1, 0]); - assert!(b.slide(5, 0)); - assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); - assert!(!b.slide(6, 0)); - assert!(!b.slide(7, 0)); - assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); - - let mut c: BoundedVec> = bounded_vec![0, 1, 2]; - assert!(!c.slide(1, 5)); - assert_eq!(*c, vec![0, 1, 2]); - assert!(!c.slide(4, 0)); - assert_eq!(*c, vec![0, 1, 2]); - assert!(!c.slide(3, 0)); - assert_eq!(*c, vec![0, 1, 2]); - assert!(c.slide(2, 0)); - assert_eq!(*c, vec![2, 0, 1]); - } - - #[test] - fn slide_noops_work() { - let mut b: BoundedVec> = bounded_vec![0, 1, 2, 3, 4, 5]; - assert!(!b.slide(3, 3)); - assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); - assert!(!b.slide(3, 4)); - assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); - } - - #[test] - fn force_insert_keep_left_works() { - let mut b: BoundedVec> = bounded_vec![]; - assert_eq!(b.force_insert_keep_left(1, 10), Err(())); - assert!(b.is_empty()); - - assert_eq!(b.force_insert_keep_left(0, 30), Ok(None)); - assert_eq!(b.force_insert_keep_left(0, 10), Ok(None)); - assert_eq!(b.force_insert_keep_left(1, 20), Ok(None)); - assert_eq!(b.force_insert_keep_left(3, 40), Ok(None)); - assert_eq!(*b, vec![10, 20, 30, 40]); - // at capacity. - assert_eq!(b.force_insert_keep_left(4, 41), Err(())); - assert_eq!(*b, vec![10, 20, 30, 40]); - assert_eq!(b.force_insert_keep_left(3, 31), Ok(Some(40))); - assert_eq!(*b, vec![10, 20, 30, 31]); - assert_eq!(b.force_insert_keep_left(1, 11), Ok(Some(31))); - assert_eq!(*b, vec![10, 11, 20, 30]); - assert_eq!(b.force_insert_keep_left(0, 1), Ok(Some(30))); - assert_eq!(*b, vec![1, 10, 11, 20]); - - let mut z: BoundedVec> = bounded_vec![]; - assert!(z.is_empty()); - assert_eq!(z.force_insert_keep_left(0, 10), Err(())); - assert!(z.is_empty()); - } - - #[test] - fn force_insert_keep_right_works() { - let mut b: BoundedVec> = bounded_vec![]; - assert_eq!(b.force_insert_keep_right(1, 10), Err(())); - assert!(b.is_empty()); - - assert_eq!(b.force_insert_keep_right(0, 30), Ok(None)); - assert_eq!(b.force_insert_keep_right(0, 10), Ok(None)); - assert_eq!(b.force_insert_keep_right(1, 20), Ok(None)); - assert_eq!(b.force_insert_keep_right(3, 40), Ok(None)); - assert_eq!(*b, vec![10, 20, 30, 40]); - - // at capacity. - assert_eq!(b.force_insert_keep_right(0, 0), Err(())); - assert_eq!(*b, vec![10, 20, 30, 40]); - assert_eq!(b.force_insert_keep_right(1, 11), Ok(Some(10))); - assert_eq!(*b, vec![11, 20, 30, 40]); - assert_eq!(b.force_insert_keep_right(3, 31), Ok(Some(11))); - assert_eq!(*b, vec![20, 30, 31, 40]); - assert_eq!(b.force_insert_keep_right(4, 41), Ok(Some(20))); - assert_eq!(*b, vec![30, 31, 40, 41]); - - assert_eq!(b.force_insert_keep_right(5, 69), Err(())); - assert_eq!(*b, vec![30, 31, 40, 41]); - - let mut z: BoundedVec> = bounded_vec![]; - assert!(z.is_empty()); - assert_eq!(z.force_insert_keep_right(0, 10), Err(())); - assert!(z.is_empty()); - } - - #[test] - fn bound_returns_correct_value() { - assert_eq!(BoundedVec::>::bound(), 7); - } - #[test] fn decode_len_works() { TestExternalities::default().execute_with(|| { @@ -839,210 +73,4 @@ pub mod test { assert!(FooDoubleMap::decode_len(2, 2).is_none()); }); } - - #[test] - fn try_insert_works() { - let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; - bounded.try_insert(1, 0).unwrap(); - assert_eq!(*bounded, vec![1, 0, 2, 3]); - - assert!(bounded.try_insert(0, 9).is_err()); - assert_eq!(*bounded, vec![1, 0, 2, 3]); - } - - #[test] - fn constructor_macro_works() { - use frame_support::bounded_vec; - - // With values. Use some brackets to make sure the macro doesn't expand. - let bv: BoundedVec<(u32, u32), ConstU32<3>> = bounded_vec![(1, 2), (1, 2), (1, 2)]; - assert_eq!(bv, vec![(1, 2), (1, 2), (1, 2)]); - - // With repetition. - let bv: BoundedVec<(u32, u32), ConstU32<3>> = bounded_vec![(1, 2); 3]; - assert_eq!(bv, vec![(1, 2), (1, 2), (1, 2)]); - } - - #[test] - #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] - fn try_inert_panics_if_oob() { - let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; - bounded.try_insert(9, 0).unwrap(); - } - - #[test] - fn try_push_works() { - let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; - bounded.try_push(0).unwrap(); - assert_eq!(*bounded, vec![1, 2, 3, 0]); - - assert!(bounded.try_push(9).is_err()); - } - - #[test] - fn deref_coercion_works() { - let bounded: BoundedVec> = bounded_vec![1, 2, 3]; - // these methods come from deref-ed vec. - assert_eq!(bounded.len(), 3); - assert!(bounded.iter().next().is_some()); - assert!(!bounded.is_empty()); - } - - #[test] - fn try_mutate_works() { - let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; - let bounded = bounded.try_mutate(|v| v.push(7)).unwrap(); - assert_eq!(bounded.len(), 7); - assert!(bounded.try_mutate(|v| v.push(8)).is_none()); - } - - #[test] - fn slice_indexing_works() { - let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; - assert_eq!(&bounded[0..=2], &[1, 2, 3]); - } - - #[test] - fn vec_eq_works() { - let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; - assert_eq!(bounded, vec![1, 2, 3, 4, 5, 6]); - } - - #[test] - fn too_big_vec_fail_to_decode() { - let v: Vec = vec![1, 2, 3, 4, 5]; - assert_eq!( - BoundedVec::>::decode(&mut &v.encode()[..]), - Err("BoundedVec exceeds its limit".into()), - ); - } - - #[test] - fn can_be_collected() { - let b1: BoundedVec> = bounded_vec![1, 2, 3, 4]; - let b2: BoundedVec> = b1.iter().map(|x| x + 1).try_collect().unwrap(); - assert_eq!(b2, vec![2, 3, 4, 5]); - - // can also be collected into a collection of length 4. - let b2: BoundedVec> = b1.iter().map(|x| x + 1).try_collect().unwrap(); - assert_eq!(b2, vec![2, 3, 4, 5]); - - // can be mutated further into iterators that are `ExactSizedIterator`. - let b2: BoundedVec> = - b1.iter().map(|x| x + 1).rev().try_collect().unwrap(); - assert_eq!(b2, vec![5, 4, 3, 2]); - - let b2: BoundedVec> = - b1.iter().map(|x| x + 1).rev().skip(2).try_collect().unwrap(); - assert_eq!(b2, vec![3, 2]); - let b2: BoundedVec> = - b1.iter().map(|x| x + 1).rev().skip(2).try_collect().unwrap(); - assert_eq!(b2, vec![3, 2]); - - let b2: BoundedVec> = - b1.iter().map(|x| x + 1).rev().take(2).try_collect().unwrap(); - assert_eq!(b2, vec![5, 4]); - let b2: BoundedVec> = - b1.iter().map(|x| x + 1).rev().take(2).try_collect().unwrap(); - assert_eq!(b2, vec![5, 4]); - - // but these worn't work - let b2: Result>, _> = b1.iter().map(|x| x + 1).try_collect(); - assert!(b2.is_err()); - - let b2: Result>, _> = - b1.iter().map(|x| x + 1).rev().take(2).try_collect(); - assert!(b2.is_err()); - } - - #[test] - fn eq_works() { - // of same type - let b1: BoundedVec> = bounded_vec![1, 2, 3]; - let b2: BoundedVec> = bounded_vec![1, 2, 3]; - assert_eq!(b1, b2); - - // of different type, but same value and bound. - crate::parameter_types! { - B1: u32 = 7; - B2: u32 = 7; - } - let b1: BoundedVec = bounded_vec![1, 2, 3]; - let b2: BoundedVec = bounded_vec![1, 2, 3]; - assert_eq!(b1, b2); - } - - #[test] - fn ord_works() { - use std::cmp::Ordering; - let b1: BoundedVec> = bounded_vec![1, 2, 3]; - let b2: BoundedVec> = bounded_vec![1, 3, 2]; - - // ordering for vec is lexicographic. - assert_eq!(b1.cmp(&b2), Ordering::Less); - assert_eq!(b1.cmp(&b2), b1.into_inner().cmp(&b2.into_inner())); - } - - #[test] - fn try_extend_works() { - let mut b: BoundedVec> = bounded_vec![1, 2, 3]; - - assert!(b.try_extend(vec![4].into_iter()).is_ok()); - assert_eq!(*b, vec![1, 2, 3, 4]); - - assert!(b.try_extend(vec![5].into_iter()).is_ok()); - assert_eq!(*b, vec![1, 2, 3, 4, 5]); - - assert!(b.try_extend(vec![6].into_iter()).is_err()); - assert_eq!(*b, vec![1, 2, 3, 4, 5]); - - let mut b: BoundedVec> = bounded_vec![1, 2, 3]; - assert!(b.try_extend(vec![4, 5].into_iter()).is_ok()); - assert_eq!(*b, vec![1, 2, 3, 4, 5]); - - let mut b: BoundedVec> = bounded_vec![1, 2, 3]; - assert!(b.try_extend(vec![4, 5, 6].into_iter()).is_err()); - assert_eq!(*b, vec![1, 2, 3]); - } - - #[test] - fn test_serializer() { - let c: BoundedVec> = bounded_vec![0, 1, 2]; - assert_eq!(serde_json::json!(&c).to_string(), r#"[0,1,2]"#); - } - - #[test] - fn test_deserializer() { - let c: BoundedVec> = serde_json::from_str(r#"[0,1,2]"#).unwrap(); - - assert_eq!(c.len(), 3); - assert_eq!(c[0], 0); - assert_eq!(c[1], 1); - assert_eq!(c[2], 2); - } - - #[test] - fn test_deserializer_failed() { - let c: Result>, serde_json::error::Error> = - serde_json::from_str(r#"[0,1,2,3,4,5]"#); - - match c { - Err(msg) => assert_eq!(msg.to_string(), "out of bounds at line 1 column 11"), - _ => unreachable!("deserializer must raise error"), - } - } - - #[test] - fn bounded_vec_try_from_works() { - assert!(BoundedVec::>::try_from(vec![0]).is_ok()); - assert!(BoundedVec::>::try_from(vec![0, 1]).is_ok()); - assert!(BoundedVec::>::try_from(vec![0, 1, 2]).is_err()); - } - - #[test] - fn bounded_slice_try_from_works() { - assert!(BoundedSlice::>::try_from(&[0][..]).is_ok()); - assert!(BoundedSlice::>::try_from(&[0, 1][..]).is_ok()); - assert!(BoundedSlice::>::try_from(&[0, 1, 2][..]).is_err()); - } } diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index bf9b9a1017221..72ba8d775a1d3 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -22,289 +22,7 @@ use crate::{ storage::{StorageDecodeLength, StorageTryAppend}, traits::Get, }; -use codec::{Decode, Encode, MaxEncodedLen}; -use core::{ - ops::{Deref, Index, IndexMut}, - slice::SliceIndex, -}; -use sp_std::{marker::PhantomData, prelude::*}; - -/// A weakly bounded vector. -/// -/// It has implementations for efficient append and length decoding, as with a normal `Vec<_>`, once -/// put into storage as a raw value, map or double-map. -/// -/// The length of the vec is not strictly bounded. Decoding a vec with more element that the bound -/// is accepted, and some method allow to bypass the restriction with warnings. -#[derive(Encode, scale_info::TypeInfo)] -#[scale_info(skip_type_params(S))] -pub struct WeakBoundedVec(Vec, PhantomData); - -impl> Decode for WeakBoundedVec { - fn decode(input: &mut I) -> Result { - let inner = Vec::::decode(input)?; - Ok(Self::force_from(inner, Some("decode"))) - } - - fn skip(input: &mut I) -> Result<(), codec::Error> { - Vec::::skip(input) - } -} - -impl WeakBoundedVec { - /// Create `Self` from `t` without any checks. - fn unchecked_from(t: Vec) -> Self { - Self(t, Default::default()) - } - - /// Consume self, and return the inner `Vec`. Henceforth, the `Vec<_>` can be altered in an - /// arbitrary way. At some point, if the reverse conversion is required, `TryFrom>` can - /// be used. - /// - /// This is useful for cases if you need access to an internal API of the inner `Vec<_>` which - /// is not provided by the wrapper `WeakBoundedVec`. - pub fn into_inner(self) -> Vec { - self.0 - } - - /// Exactly the same semantics as [`Vec::remove`]. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn remove(&mut self, index: usize) -> T { - self.0.remove(index) - } - - /// Exactly the same semantics as [`Vec::swap_remove`]. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn swap_remove(&mut self, index: usize) -> T { - self.0.swap_remove(index) - } - - /// Exactly the same semantics as [`Vec::retain`]. - pub fn retain bool>(&mut self, f: F) { - self.0.retain(f) - } - - /// Exactly the same semantics as [`slice::get_mut`]. - pub fn get_mut>( - &mut self, - index: I, - ) -> Option<&mut >::Output> { - self.0.get_mut(index) - } -} - -impl> WeakBoundedVec { - /// Get the bound of the type in `usize`. - pub fn bound() -> usize { - S::get() as usize - } - - /// Create `Self` from `t` without any checks. Logs warnings if the bound is not being - /// respected. The additional scope can be used to indicate where a potential overflow is - /// happening. - pub fn force_from(t: Vec, scope: Option<&'static str>) -> Self { - if t.len() > Self::bound() { - log::warn!( - target: crate::LOG_TARGET, - "length of a bounded vector in scope {} is not respected.", - scope.unwrap_or("UNKNOWN"), - ); - } - - Self::unchecked_from(t) - } - - /// Consumes self and mutates self via the given `mutate` function. - /// - /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is - /// returned. - /// - /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> - /// [`Self::try_from`]. - pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut Vec)) -> Option { - mutate(&mut self.0); - (self.0.len() <= Self::bound()).then(move || self) - } - - /// Exactly the same semantics as [`Vec::insert`], but returns an `Err` (and is a noop) if the - /// new length of the vector exceeds `S`. - /// - /// # Panics - /// - /// Panics if `index > len`. - pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), ()> { - if self.len() < Self::bound() { - self.0.insert(index, element); - Ok(()) - } else { - Err(()) - } - } - - /// Exactly the same semantics as [`Vec::push`], but returns an `Err` (and is a noop) if the - /// new length of the vector exceeds `S`. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds isize::MAX bytes. - pub fn try_push(&mut self, element: T) -> Result<(), ()> { - if self.len() < Self::bound() { - self.0.push(element); - Ok(()) - } else { - Err(()) - } - } -} - -impl Default for WeakBoundedVec { - fn default() -> Self { - // the bound cannot be below 0, which is satisfied by an empty vector - Self::unchecked_from(Vec::default()) - } -} - -#[cfg(feature = "std")] -impl std::fmt::Debug for WeakBoundedVec -where - T: std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("WeakBoundedVec").field(&self.0).field(&Self::bound()).finish() - } -} - -impl Clone for WeakBoundedVec -where - T: Clone, -{ - fn clone(&self) -> Self { - // bound is retained - Self::unchecked_from(self.0.clone()) - } -} - -impl> TryFrom> for WeakBoundedVec { - type Error = (); - fn try_from(t: Vec) -> Result { - if t.len() <= Self::bound() { - // explicit check just above - Ok(Self::unchecked_from(t)) - } else { - Err(()) - } - } -} - -// It is okay to give a non-mutable reference of the inner vec to anyone. -impl AsRef> for WeakBoundedVec { - fn as_ref(&self) -> &Vec { - &self.0 - } -} - -impl AsRef<[T]> for WeakBoundedVec { - fn as_ref(&self) -> &[T] { - &self.0 - } -} - -impl AsMut<[T]> for WeakBoundedVec { - fn as_mut(&mut self) -> &mut [T] { - &mut self.0 - } -} - -// will allow for immutable all operations of `Vec` on `WeakBoundedVec`. -impl Deref for WeakBoundedVec { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// Allows for indexing similar to a normal `Vec`. Can panic if out of bound. -impl Index for WeakBoundedVec -where - I: SliceIndex<[T]>, -{ - type Output = I::Output; - - #[inline] - fn index(&self, index: I) -> &Self::Output { - self.0.index(index) - } -} - -impl IndexMut for WeakBoundedVec -where - I: SliceIndex<[T]>, -{ - #[inline] - fn index_mut(&mut self, index: I) -> &mut Self::Output { - self.0.index_mut(index) - } -} - -impl sp_std::iter::IntoIterator for WeakBoundedVec { - type Item = T; - type IntoIter = sp_std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<'a, T, S> sp_std::iter::IntoIterator for &'a WeakBoundedVec { - type Item = &'a T; - type IntoIter = sp_std::slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, T, S> sp_std::iter::IntoIterator for &'a mut WeakBoundedVec { - type Item = &'a mut T; - type IntoIter = sp_std::slice::IterMut<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut() - } -} - -impl codec::DecodeLength for WeakBoundedVec { - fn len(self_encoded: &[u8]) -> Result { - // `WeakBoundedVec` stored just a `Vec`, thus the length is at the beginning in - // `Compact` form, and same implementation as `Vec` can be used. - as codec::DecodeLength>::len(self_encoded) - } -} - -// NOTE: we could also implement this as: -// impl, S2: Get> PartialEq> for WeakBoundedVec to allow comparison of bounded vectors with different bounds. -impl PartialEq for WeakBoundedVec -where - T: PartialEq, -{ - fn eq(&self, rhs: &Self) -> bool { - self.0 == rhs.0 - } -} - -impl> PartialEq> for WeakBoundedVec { - fn eq(&self, other: &Vec) -> bool { - &self.0 == other - } -} - -impl Eq for WeakBoundedVec where T: Eq {} +pub use sp_runtime::WeakBoundedVec; impl StorageDecodeLength for WeakBoundedVec {} @@ -314,22 +32,6 @@ impl> StorageTryAppend for WeakBoundedVec { } } -impl MaxEncodedLen for WeakBoundedVec -where - T: MaxEncodedLen, - S: Get, - WeakBoundedVec: Encode, -{ - fn max_encoded_len() -> usize { - // WeakBoundedVec encodes like Vec which encodes like [T], which is a compact u32 - // plus each item in the slice: - // https://docs.substrate.io/v3/advanced/scale-codec - codec::Compact(S::get()) - .encoded_size() - .saturating_add(Self::bound().saturating_mul(T::max_encoded_len())) - } -} - #[cfg(test)] pub mod test { use super::*; @@ -345,11 +47,6 @@ pub mod test { type FooDoubleMap = StorageDoubleMap>>; - #[test] - fn bound_returns_correct_value() { - assert_eq!(WeakBoundedVec::>::bound(), 7); - } - #[test] fn decode_len_works() { TestExternalities::default().execute_with(|| { @@ -375,66 +72,4 @@ pub mod test { assert!(FooDoubleMap::decode_len(2, 2).is_none()); }); } - - #[test] - fn try_insert_works() { - let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); - bounded.try_insert(1, 0).unwrap(); - assert_eq!(*bounded, vec![1, 0, 2, 3]); - - assert!(bounded.try_insert(0, 9).is_err()); - assert_eq!(*bounded, vec![1, 0, 2, 3]); - } - - #[test] - #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] - fn try_inert_panics_if_oob() { - let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); - bounded.try_insert(9, 0).unwrap(); - } - - #[test] - fn try_push_works() { - let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); - bounded.try_push(0).unwrap(); - assert_eq!(*bounded, vec![1, 2, 3, 0]); - - assert!(bounded.try_push(9).is_err()); - } - - #[test] - fn deref_coercion_works() { - let bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); - // these methods come from deref-ed vec. - assert_eq!(bounded.len(), 3); - assert!(bounded.iter().next().is_some()); - assert!(!bounded.is_empty()); - } - - #[test] - fn try_mutate_works() { - let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); - let bounded = bounded.try_mutate(|v| v.push(7)).unwrap(); - assert_eq!(bounded.len(), 7); - assert!(bounded.try_mutate(|v| v.push(8)).is_none()); - } - - #[test] - fn slice_indexing_works() { - let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); - assert_eq!(&bounded[0..=2], &[1, 2, 3]); - } - - #[test] - fn vec_eq_works() { - let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); - assert_eq!(bounded, vec![1, 2, 3, 4, 5, 6]); - } - - #[test] - fn too_big_succeed_to_decode() { - let v: Vec = vec![1, 2, 3, 4, 5]; - let w = WeakBoundedVec::>::decode(&mut &v.encode()[..]).unwrap(); - assert_eq!(v, *w); - } } diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index ced6df8f971e8..1f0ba1e769c24 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -24,7 +24,7 @@ use sp_arithmetic::traits::{CheckedAdd, CheckedMul, CheckedSub, Saturating}; #[doc(hidden)] pub use sp_runtime::traits::{ ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, ConstU32, - ConstU64, ConstU8, Get, GetDefault, TypedGet, + ConstU64, ConstU8, Get, GetDefault, TryCollect, TypedGet, }; use sp_runtime::{traits::Block as BlockT, DispatchError}; use sp_std::{cmp::Ordering, prelude::*}; @@ -367,16 +367,6 @@ impl DefensiveSaturating f } } -/// Try and collect into a collection `C`. -pub trait TryCollect { - type Error; - /// Consume self and try to collect the results into `C`. - /// - /// This is useful in preventing the undesirable `.collect().try_into()` call chain on - /// collections that need to be converted into a bounded type (e.g. `BoundedVec`). - fn try_collect(self) -> Result; -} - /// Anything that can have a `::len()` method. pub trait Len { /// Return the length of data type. diff --git a/primitives/runtime/src/bounded.rs b/primitives/runtime/src/bounded.rs new file mode 100644 index 0000000000000..45b4a9ca623d4 --- /dev/null +++ b/primitives/runtime/src/bounded.rs @@ -0,0 +1,28 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Bounded collection types. + +pub mod bounded_btree_map; +pub mod bounded_btree_set; +pub mod bounded_vec; +pub mod weak_bounded_vec; + +pub use bounded_btree_map::BoundedBTreeMap; +pub use bounded_btree_set::BoundedBTreeSet; +pub use bounded_vec::{BoundedSlice, BoundedVec}; +pub use weak_bounded_vec::WeakBoundedVec; diff --git a/primitives/runtime/src/bounded/bounded_btree_map.rs b/primitives/runtime/src/bounded/bounded_btree_map.rs new file mode 100644 index 0000000000000..f4fd4275beb2a --- /dev/null +++ b/primitives/runtime/src/bounded/bounded_btree_map.rs @@ -0,0 +1,517 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Traits, types and structs to support a bounded BTreeMap. + +use crate::traits::{Get, TryCollect}; +use codec::{Decode, Encode, MaxEncodedLen}; +use sp_std::{borrow::Borrow, collections::btree_map::BTreeMap, marker::PhantomData, ops::Deref}; + +/// A bounded map based on a B-Tree. +/// +/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing +/// the amount of work performed in a search. See [`BTreeMap`] for more details. +/// +/// Unlike a standard `BTreeMap`, there is an enforced upper limit to the number of items in the +/// map. All internal operations ensure this bound is respected. +#[derive(Encode, scale_info::TypeInfo)] +#[scale_info(skip_type_params(S))] +pub struct BoundedBTreeMap(BTreeMap, PhantomData); + +impl Decode for BoundedBTreeMap +where + K: Decode + Ord, + V: Decode, + S: Get, +{ + fn decode(input: &mut I) -> Result { + let inner = BTreeMap::::decode(input)?; + if inner.len() > S::get() as usize { + return Err("BoundedBTreeMap exceeds its limit".into()) + } + Ok(Self(inner, PhantomData)) + } + + fn skip(input: &mut I) -> Result<(), codec::Error> { + BTreeMap::::skip(input) + } +} + +impl BoundedBTreeMap +where + S: Get, +{ + /// Get the bound of the type in `usize`. + pub fn bound() -> usize { + S::get() as usize + } +} + +impl BoundedBTreeMap +where + K: Ord, + S: Get, +{ + /// Exactly the same semantics as `BTreeMap::retain`. + /// + /// The is a safe `&mut self` borrow because `retain` can only ever decrease the length of the + /// inner map. + pub fn retain bool>(&mut self, f: F) { + self.0.retain(f) + } + + /// Create a new `BoundedBTreeMap`. + /// + /// Does not allocate. + pub fn new() -> Self { + BoundedBTreeMap(BTreeMap::new(), PhantomData) + } + + /// Consume self, and return the inner `BTreeMap`. + /// + /// This is useful when a mutating API of the inner type is desired, and closure-based mutation + /// such as provided by [`try_mutate`][Self::try_mutate] is inconvenient. + pub fn into_inner(self) -> BTreeMap { + debug_assert!(self.0.len() <= Self::bound()); + self.0 + } + + /// Consumes self and mutates self via the given `mutate` function. + /// + /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is + /// returned. + /// + /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> + /// [`Self::try_from`]. + pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut BTreeMap)) -> Option { + mutate(&mut self.0); + (self.0.len() <= Self::bound()).then(move || self) + } + + /// Clears the map, removing all elements. + pub fn clear(&mut self) { + self.0.clear() + } + + /// Return a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed + /// form _must_ match the ordering on the key type. + pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Ord + ?Sized, + { + self.0.get_mut(key) + } + + /// Exactly the same semantics as [`BTreeMap::insert`], but returns an `Err` (and is a noop) if + /// the new length of the map exceeds `S`. + /// + /// In the `Err` case, returns the inserted pair so it can be further used without cloning. + pub fn try_insert(&mut self, key: K, value: V) -> Result, (K, V)> { + if self.len() < Self::bound() || self.0.contains_key(&key) { + Ok(self.0.insert(key, value)) + } else { + Err((key, value)) + } + } + + /// Remove a key from the map, returning the value at the key if the key was previously in the + /// map. + /// + /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed + /// form _must_ match the ordering on the key type. + pub fn remove(&mut self, key: &Q) -> Option + where + K: Borrow, + Q: Ord + ?Sized, + { + self.0.remove(key) + } + + /// Remove a key from the map, returning the value at the key if the key was previously in the + /// map. + /// + /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed + /// form _must_ match the ordering on the key type. + pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> + where + K: Borrow, + Q: Ord + ?Sized, + { + self.0.remove_entry(key) + } +} + +impl Default for BoundedBTreeMap +where + K: Ord, + S: Get, +{ + fn default() -> Self { + Self::new() + } +} + +impl Clone for BoundedBTreeMap +where + BTreeMap: Clone, +{ + fn clone(&self) -> Self { + BoundedBTreeMap(self.0.clone(), PhantomData) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Debug for BoundedBTreeMap +where + BTreeMap: std::fmt::Debug, + S: Get, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("BoundedBTreeMap").field(&self.0).field(&Self::bound()).finish() + } +} + +impl PartialEq> for BoundedBTreeMap +where + BTreeMap: PartialEq, + S1: Get, + S2: Get, +{ + fn eq(&self, other: &BoundedBTreeMap) -> bool { + S1::get() == S2::get() && self.0 == other.0 + } +} + +impl Eq for BoundedBTreeMap +where + BTreeMap: Eq, + S: Get, +{ +} + +impl PartialEq> for BoundedBTreeMap +where + BTreeMap: PartialEq, +{ + fn eq(&self, other: &BTreeMap) -> bool { + self.0 == *other + } +} + +impl PartialOrd for BoundedBTreeMap +where + BTreeMap: PartialOrd, + S: Get, +{ + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl Ord for BoundedBTreeMap +where + BTreeMap: Ord, + S: Get, +{ + fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl IntoIterator for BoundedBTreeMap { + type Item = (K, V); + type IntoIter = sp_std::collections::btree_map::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a, K, V, S> IntoIterator for &'a BoundedBTreeMap { + type Item = (&'a K, &'a V); + type IntoIter = sp_std::collections::btree_map::Iter<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl<'a, K, V, S> IntoIterator for &'a mut BoundedBTreeMap { + type Item = (&'a K, &'a mut V); + type IntoIter = sp_std::collections::btree_map::IterMut<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} + +impl MaxEncodedLen for BoundedBTreeMap +where + K: MaxEncodedLen, + V: MaxEncodedLen, + S: Get, +{ + fn max_encoded_len() -> usize { + Self::bound() + .saturating_mul(K::max_encoded_len().saturating_add(V::max_encoded_len())) + .saturating_add(codec::Compact(S::get()).encoded_size()) + } +} + +impl Deref for BoundedBTreeMap +where + K: Ord, +{ + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl AsRef> for BoundedBTreeMap +where + K: Ord, +{ + fn as_ref(&self) -> &BTreeMap { + &self.0 + } +} + +impl From> for BTreeMap +where + K: Ord, +{ + fn from(map: BoundedBTreeMap) -> Self { + map.0 + } +} + +impl TryFrom> for BoundedBTreeMap +where + K: Ord, + S: Get, +{ + type Error = (); + + fn try_from(value: BTreeMap) -> Result { + (value.len() <= Self::bound()) + .then(move || BoundedBTreeMap(value, PhantomData)) + .ok_or(()) + } +} + +impl codec::DecodeLength for BoundedBTreeMap { + fn len(self_encoded: &[u8]) -> Result { + // `BoundedBTreeMap` is stored just a `BTreeMap`, which is stored as a + // `Compact` with its length followed by an iteration of its items. We can just use + // the underlying implementation. + as codec::DecodeLength>::len(self_encoded) + } +} + +impl codec::EncodeLike> for BoundedBTreeMap where + BTreeMap: Encode +{ +} + +impl TryCollect> for I +where + K: Ord, + I: ExactSizeIterator + Iterator, + Bound: Get, +{ + type Error = &'static str; + + fn try_collect(self) -> Result, Self::Error> { + if self.len() > Bound::get() as usize { + Err("iterator length too big") + } else { + Ok(BoundedBTreeMap::::try_from(self.collect::>()) + .expect("length checked above; qed")) + } + } +} + +#[cfg(test)] +pub mod test { + use super::*; + use crate::traits::ConstU32; + + fn map_from_keys(keys: &[K]) -> BTreeMap + where + K: Ord + Copy, + { + keys.iter().copied().zip(std::iter::repeat(())).collect() + } + + fn boundedmap_from_keys(keys: &[K]) -> BoundedBTreeMap + where + K: Ord + Copy, + S: Get, + { + map_from_keys(keys).try_into().unwrap() + } + + #[test] + fn try_insert_works() { + let mut bounded = boundedmap_from_keys::>(&[1, 2, 3]); + bounded.try_insert(0, ()).unwrap(); + assert_eq!(*bounded, map_from_keys(&[1, 0, 2, 3])); + + assert!(bounded.try_insert(9, ()).is_err()); + assert_eq!(*bounded, map_from_keys(&[1, 0, 2, 3])); + } + + #[test] + fn deref_coercion_works() { + let bounded = boundedmap_from_keys::>(&[1, 2, 3]); + // these methods come from deref-ed vec. + assert_eq!(bounded.len(), 3); + assert!(bounded.iter().next().is_some()); + assert!(!bounded.is_empty()); + } + + #[test] + fn try_mutate_works() { + let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); + let bounded = bounded + .try_mutate(|v| { + v.insert(7, ()); + }) + .unwrap(); + assert_eq!(bounded.len(), 7); + assert!(bounded + .try_mutate(|v| { + v.insert(8, ()); + }) + .is_none()); + } + + #[test] + fn btree_map_eq_works() { + let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); + assert_eq!(bounded, map_from_keys(&[1, 2, 3, 4, 5, 6])); + } + + #[test] + fn too_big_fail_to_decode() { + let v: Vec<(u32, u32)> = vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]; + assert_eq!( + BoundedBTreeMap::>::decode(&mut &v.encode()[..]), + Err("BoundedBTreeMap exceeds its limit".into()), + ); + } + + #[test] + fn unequal_eq_impl_insert_works() { + // given a struct with a strange notion of equality + #[derive(Debug)] + struct Unequal(u32, bool); + + impl PartialEq for Unequal { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + impl Eq for Unequal {} + + impl Ord for Unequal { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0.cmp(&other.0) + } + } + + impl PartialOrd for Unequal { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + let mut map = BoundedBTreeMap::>::new(); + + // when the set is full + + for i in 0..4 { + map.try_insert(Unequal(i, false), i).unwrap(); + } + + // can't insert a new distinct member + map.try_insert(Unequal(5, false), 5).unwrap_err(); + + // but _can_ insert a distinct member which compares equal, though per the documentation, + // neither the set length nor the actual member are changed, but the value is + map.try_insert(Unequal(0, true), 6).unwrap(); + assert_eq!(map.len(), 4); + let (zero_key, zero_value) = map.get_key_value(&Unequal(0, true)).unwrap(); + assert_eq!(zero_key.0, 0); + assert_eq!(zero_key.1, false); + assert_eq!(*zero_value, 6); + } + + #[test] + fn eq_works() { + // of same type + let b1 = boundedmap_from_keys::>(&[1, 2]); + let b2 = boundedmap_from_keys::>(&[1, 2]); + assert_eq!(b1, b2); + + // of different type, but same value and bound. + crate::parameter_types! { + B1: u32 = 7; + B2: u32 = 7; + } + let b1 = boundedmap_from_keys::(&[1, 2]); + let b2 = boundedmap_from_keys::(&[1, 2]); + assert_eq!(b1, b2); + } + + #[test] + fn can_be_collected() { + let b1 = boundedmap_from_keys::>(&[1, 2, 3, 4]); + let b2: BoundedBTreeMap> = + b1.iter().map(|(k, v)| (k + 1, *v)).try_collect().unwrap(); + assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3, 4, 5]); + + // can also be collected into a collection of length 4. + let b2: BoundedBTreeMap> = + b1.iter().map(|(k, v)| (k + 1, *v)).try_collect().unwrap(); + assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3, 4, 5]); + + // can be mutated further into iterators that are `ExactSizedIterator`. + let b2: BoundedBTreeMap> = + b1.iter().map(|(k, v)| (k + 1, *v)).rev().skip(2).try_collect().unwrap(); + // note that the binary tree will re-sort this, so rev() is not really seen + assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3]); + + let b2: BoundedBTreeMap> = + b1.iter().map(|(k, v)| (k + 1, *v)).take(2).try_collect().unwrap(); + assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3]); + + // but these worn't work + let b2: Result>, _> = + b1.iter().map(|(k, v)| (k + 1, *v)).try_collect(); + assert!(b2.is_err()); + + let b2: Result>, _> = + b1.iter().map(|(k, v)| (k + 1, *v)).skip(2).try_collect(); + assert!(b2.is_err()); + } +} diff --git a/primitives/runtime/src/bounded/bounded_btree_set.rs b/primitives/runtime/src/bounded/bounded_btree_set.rs new file mode 100644 index 0000000000000..40b95165da1bd --- /dev/null +++ b/primitives/runtime/src/bounded/bounded_btree_set.rs @@ -0,0 +1,479 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Traits, types and structs to support a bounded `BTreeSet`. + +use crate::traits::{Get, TryCollect}; +use codec::{Decode, Encode, MaxEncodedLen}; +use sp_std::{borrow::Borrow, collections::btree_set::BTreeSet, marker::PhantomData, ops::Deref}; + +/// A bounded set based on a B-Tree. +/// +/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing +/// the amount of work performed in a search. See [`BTreeSet`] for more details. +/// +/// Unlike a standard `BTreeSet`, there is an enforced upper limit to the number of items in the +/// set. All internal operations ensure this bound is respected. +#[derive(Encode, scale_info::TypeInfo)] +#[scale_info(skip_type_params(S))] +pub struct BoundedBTreeSet(BTreeSet, PhantomData); + +impl Decode for BoundedBTreeSet +where + T: Decode + Ord, + S: Get, +{ + fn decode(input: &mut I) -> Result { + let inner = BTreeSet::::decode(input)?; + if inner.len() > S::get() as usize { + return Err("BoundedBTreeSet exceeds its limit".into()) + } + Ok(Self(inner, PhantomData)) + } + + fn skip(input: &mut I) -> Result<(), codec::Error> { + BTreeSet::::skip(input) + } +} + +impl BoundedBTreeSet +where + S: Get, +{ + /// Get the bound of the type in `usize`. + pub fn bound() -> usize { + S::get() as usize + } +} + +impl BoundedBTreeSet +where + T: Ord, + S: Get, +{ + /// Create a new `BoundedBTreeSet`. + /// + /// Does not allocate. + pub fn new() -> Self { + BoundedBTreeSet(BTreeSet::new(), PhantomData) + } + + /// Consume self, and return the inner `BTreeSet`. + /// + /// This is useful when a mutating API of the inner type is desired, and closure-based mutation + /// such as provided by [`try_mutate`][Self::try_mutate] is inconvenient. + pub fn into_inner(self) -> BTreeSet { + debug_assert!(self.0.len() <= Self::bound()); + self.0 + } + + /// Consumes self and mutates self via the given `mutate` function. + /// + /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is + /// returned. + /// + /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> + /// [`Self::try_from`]. + pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut BTreeSet)) -> Option { + mutate(&mut self.0); + (self.0.len() <= Self::bound()).then(move || self) + } + + /// Clears the set, removing all elements. + pub fn clear(&mut self) { + self.0.clear() + } + + /// Exactly the same semantics as [`BTreeSet::insert`], but returns an `Err` (and is a noop) if + /// the new length of the set exceeds `S`. + /// + /// In the `Err` case, returns the inserted item so it can be further used without cloning. + pub fn try_insert(&mut self, item: T) -> Result { + if self.len() < Self::bound() || self.0.contains(&item) { + Ok(self.0.insert(item)) + } else { + Err(item) + } + } + + /// Remove an item from the set, returning whether it was previously in the set. + /// + /// The item may be any borrowed form of the set's item type, but the ordering on the borrowed + /// form _must_ match the ordering on the item type. + pub fn remove(&mut self, item: &Q) -> bool + where + T: Borrow, + Q: Ord + ?Sized, + { + self.0.remove(item) + } + + /// Removes and returns the value in the set, if any, that is equal to the given one. + /// + /// The value may be any borrowed form of the set's value type, but the ordering on the borrowed + /// form _must_ match the ordering on the value type. + pub fn take(&mut self, value: &Q) -> Option + where + T: Borrow + Ord, + Q: Ord + ?Sized, + { + self.0.take(value) + } +} + +impl Default for BoundedBTreeSet +where + T: Ord, + S: Get, +{ + fn default() -> Self { + Self::new() + } +} + +impl Clone for BoundedBTreeSet +where + BTreeSet: Clone, +{ + fn clone(&self) -> Self { + BoundedBTreeSet(self.0.clone(), PhantomData) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Debug for BoundedBTreeSet +where + BTreeSet: std::fmt::Debug, + S: Get, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("BoundedBTreeSet").field(&self.0).field(&Self::bound()).finish() + } +} + +impl PartialEq> for BoundedBTreeSet +where + BTreeSet: PartialEq, + S1: Get, + S2: Get, +{ + fn eq(&self, other: &BoundedBTreeSet) -> bool { + S1::get() == S2::get() && self.0 == other.0 + } +} + +impl Eq for BoundedBTreeSet +where + BTreeSet: Eq, + S: Get, +{ +} + +impl PartialEq> for BoundedBTreeSet +where + BTreeSet: PartialEq, + S: Get, +{ + fn eq(&self, other: &BTreeSet) -> bool { + self.0 == *other + } +} + +impl PartialOrd for BoundedBTreeSet +where + BTreeSet: PartialOrd, + S: Get, +{ + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl Ord for BoundedBTreeSet +where + BTreeSet: Ord, + S: Get, +{ + fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl IntoIterator for BoundedBTreeSet { + type Item = T; + type IntoIter = sp_std::collections::btree_set::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a, T, S> IntoIterator for &'a BoundedBTreeSet { + type Item = &'a T; + type IntoIter = sp_std::collections::btree_set::Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl MaxEncodedLen for BoundedBTreeSet +where + T: MaxEncodedLen, + S: Get, +{ + fn max_encoded_len() -> usize { + Self::bound() + .saturating_mul(T::max_encoded_len()) + .saturating_add(codec::Compact(S::get()).encoded_size()) + } +} + +impl Deref for BoundedBTreeSet +where + T: Ord, +{ + type Target = BTreeSet; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl AsRef> for BoundedBTreeSet +where + T: Ord, +{ + fn as_ref(&self) -> &BTreeSet { + &self.0 + } +} + +impl From> for BTreeSet +where + T: Ord, +{ + fn from(set: BoundedBTreeSet) -> Self { + set.0 + } +} + +impl TryFrom> for BoundedBTreeSet +where + T: Ord, + S: Get, +{ + type Error = (); + + fn try_from(value: BTreeSet) -> Result { + (value.len() <= Self::bound()) + .then(move || BoundedBTreeSet(value, PhantomData)) + .ok_or(()) + } +} + +impl codec::DecodeLength for BoundedBTreeSet { + fn len(self_encoded: &[u8]) -> Result { + // `BoundedBTreeSet` is stored just a `BTreeSet`, which is stored as a + // `Compact` with its length followed by an iteration of its items. We can just use + // the underlying implementation. + as codec::DecodeLength>::len(self_encoded) + } +} + +impl codec::EncodeLike> for BoundedBTreeSet where BTreeSet: Encode {} + +impl TryCollect> for I +where + T: Ord, + I: ExactSizeIterator + Iterator, + Bound: Get, +{ + type Error = &'static str; + + fn try_collect(self) -> Result, Self::Error> { + if self.len() > Bound::get() as usize { + Err("iterator length too big") + } else { + Ok(BoundedBTreeSet::::try_from(self.collect::>()) + .expect("length is checked above; qed")) + } + } +} + +#[cfg(test)] +pub mod test { + use super::*; + use crate::traits::ConstU32; + + fn set_from_keys(keys: &[T]) -> BTreeSet + where + T: Ord + Copy, + { + keys.iter().copied().collect() + } + + fn boundedset_from_keys(keys: &[T]) -> BoundedBTreeSet + where + T: Ord + Copy, + S: Get, + { + set_from_keys(keys).try_into().unwrap() + } + + #[test] + fn try_insert_works() { + let mut bounded = boundedset_from_keys::>(&[1, 2, 3]); + bounded.try_insert(0).unwrap(); + assert_eq!(*bounded, set_from_keys(&[1, 0, 2, 3])); + + assert!(bounded.try_insert(9).is_err()); + assert_eq!(*bounded, set_from_keys(&[1, 0, 2, 3])); + } + + #[test] + fn deref_coercion_works() { + let bounded = boundedset_from_keys::>(&[1, 2, 3]); + // these methods come from deref-ed vec. + assert_eq!(bounded.len(), 3); + assert!(bounded.iter().next().is_some()); + assert!(!bounded.is_empty()); + } + + #[test] + fn try_mutate_works() { + let bounded = boundedset_from_keys::>(&[1, 2, 3, 4, 5, 6]); + let bounded = bounded + .try_mutate(|v| { + v.insert(7); + }) + .unwrap(); + assert_eq!(bounded.len(), 7); + assert!(bounded + .try_mutate(|v| { + v.insert(8); + }) + .is_none()); + } + + #[test] + fn btree_map_eq_works() { + let bounded = boundedset_from_keys::>(&[1, 2, 3, 4, 5, 6]); + assert_eq!(bounded, set_from_keys(&[1, 2, 3, 4, 5, 6])); + } + + #[test] + fn too_big_fail_to_decode() { + let v: Vec = vec![1, 2, 3, 4, 5]; + assert_eq!( + BoundedBTreeSet::>::decode(&mut &v.encode()[..]), + Err("BoundedBTreeSet exceeds its limit".into()), + ); + } + + #[test] + fn unequal_eq_impl_insert_works() { + // given a struct with a strange notion of equality + #[derive(Debug)] + struct Unequal(u32, bool); + + impl PartialEq for Unequal { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + impl Eq for Unequal {} + + impl Ord for Unequal { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0.cmp(&other.0) + } + } + + impl PartialOrd for Unequal { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + let mut set = BoundedBTreeSet::>::new(); + + // when the set is full + + for i in 0..4 { + set.try_insert(Unequal(i, false)).unwrap(); + } + + // can't insert a new distinct member + set.try_insert(Unequal(5, false)).unwrap_err(); + + // but _can_ insert a distinct member which compares equal, though per the documentation, + // neither the set length nor the actual member are changed + set.try_insert(Unequal(0, true)).unwrap(); + assert_eq!(set.len(), 4); + let zero_item = set.get(&Unequal(0, true)).unwrap(); + assert_eq!(zero_item.0, 0); + assert_eq!(zero_item.1, false); + } + + #[test] + fn eq_works() { + // of same type + let b1 = boundedset_from_keys::>(&[1, 2]); + let b2 = boundedset_from_keys::>(&[1, 2]); + assert_eq!(b1, b2); + + // of different type, but same value and bound. + crate::parameter_types! { + B1: u32 = 7; + B2: u32 = 7; + } + let b1 = boundedset_from_keys::(&[1, 2]); + let b2 = boundedset_from_keys::(&[1, 2]); + assert_eq!(b1, b2); + } + + #[test] + fn can_be_collected() { + let b1 = boundedset_from_keys::>(&[1, 2, 3, 4]); + let b2: BoundedBTreeSet> = b1.iter().map(|k| k + 1).try_collect().unwrap(); + assert_eq!(b2.into_iter().collect::>(), vec![2, 3, 4, 5]); + + // can also be collected into a collection of length 4. + let b2: BoundedBTreeSet> = b1.iter().map(|k| k + 1).try_collect().unwrap(); + assert_eq!(b2.into_iter().collect::>(), vec![2, 3, 4, 5]); + + // can be mutated further into iterators that are `ExactSizedIterator`. + let b2: BoundedBTreeSet> = + b1.iter().map(|k| k + 1).rev().skip(2).try_collect().unwrap(); + // note that the binary tree will re-sort this, so rev() is not really seen + assert_eq!(b2.into_iter().collect::>(), vec![2, 3]); + + let b2: BoundedBTreeSet> = + b1.iter().map(|k| k + 1).take(2).try_collect().unwrap(); + assert_eq!(b2.into_iter().collect::>(), vec![2, 3]); + + // but these worn't work + let b2: Result>, _> = + b1.iter().map(|k| k + 1).try_collect(); + assert!(b2.is_err()); + + let b2: Result>, _> = + b1.iter().map(|k| k + 1).skip(2).try_collect(); + assert!(b2.is_err()); + } +} diff --git a/primitives/runtime/src/bounded/bounded_vec.rs b/primitives/runtime/src/bounded/bounded_vec.rs new file mode 100644 index 0000000000000..4493d9f8b0198 --- /dev/null +++ b/primitives/runtime/src/bounded/bounded_vec.rs @@ -0,0 +1,998 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Traits, types and structs to support putting a bounded vector into storage, as a raw value, map +//! or a double map. + +use super::WeakBoundedVec; +use crate::traits::{Get, TryCollect}; +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use core::{ + ops::{Deref, Index, IndexMut, RangeBounds}, + slice::SliceIndex, +}; +#[cfg(feature = "std")] +use serde::{ + de::{Error, SeqAccess, Visitor}, + Deserialize, Deserializer, Serialize, +}; +use sp_std::{marker::PhantomData, prelude::*}; + +/// A bounded vector. +/// +/// It has implementations for efficient append and length decoding, as with a normal `Vec<_>`, once +/// put into storage as a raw value, map or double-map. +/// +/// As the name suggests, the length of the queue is always bounded. All internal operations ensure +/// this bound is respected. +#[cfg_attr(feature = "std", derive(Serialize), serde(transparent))] +#[derive(Encode, scale_info::TypeInfo)] +#[scale_info(skip_type_params(S))] +pub struct BoundedVec( + Vec, + #[cfg_attr(feature = "std", serde(skip_serializing))] PhantomData, +); + +#[cfg(feature = "std")] +impl<'de, T, S: Get> Deserialize<'de> for BoundedVec +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VecVisitor>(PhantomData<(T, S)>); + + impl<'de, T, S: Get> Visitor<'de> for VecVisitor + where + T: Deserialize<'de>, + { + type Value = Vec; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let size = seq.size_hint().unwrap_or(0); + let max = match usize::try_from(S::get()) { + Ok(n) => n, + Err(_) => return Err(A::Error::custom("can't convert to usize")), + }; + if size > max { + Err(A::Error::custom("out of bounds")) + } else { + let mut values = Vec::with_capacity(size); + + while let Some(value) = seq.next_element()? { + values.push(value); + if values.len() > max { + return Err(A::Error::custom("out of bounds")) + } + } + + Ok(values) + } + } + } + + let visitor: VecVisitor = VecVisitor(PhantomData); + deserializer + .deserialize_seq(visitor) + .map(|v| BoundedVec::::try_from(v).map_err(|_| Error::custom("out of bounds")))? + } +} + +/// A bounded slice. +/// +/// Similar to a `BoundedVec`, but not owned and cannot be decoded. +#[derive(Encode, scale_info::TypeInfo)] +#[scale_info(skip_type_params(S))] +pub struct BoundedSlice<'a, T, S>(&'a [T], PhantomData); + +// `BoundedSlice`s encode to something which will always decode into a `BoundedVec`, +// `WeakBoundedVec`, or a `Vec`. +impl<'a, T: Encode + Decode, S: Get> EncodeLike> for BoundedSlice<'a, T, S> {} +impl<'a, T: Encode + Decode, S: Get> EncodeLike> + for BoundedSlice<'a, T, S> +{ +} +impl<'a, T: Encode + Decode, S: Get> EncodeLike> for BoundedSlice<'a, T, S> {} + +impl> PartialOrd for BoundedVec { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl> Ord for BoundedVec { + fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl<'a, T, S: Get> TryFrom<&'a [T]> for BoundedSlice<'a, T, S> { + type Error = (); + fn try_from(t: &'a [T]) -> Result { + if t.len() <= S::get() as usize { + Ok(BoundedSlice(t, PhantomData)) + } else { + Err(()) + } + } +} + +impl<'a, T, S> From> for &'a [T] { + fn from(t: BoundedSlice<'a, T, S>) -> Self { + t.0 + } +} + +impl<'a, T, S> sp_std::iter::IntoIterator for BoundedSlice<'a, T, S> { + type Item = &'a T; + type IntoIter = sp_std::slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl> Decode for BoundedVec { + fn decode(input: &mut I) -> Result { + let inner = Vec::::decode(input)?; + if inner.len() > S::get() as usize { + return Err("BoundedVec exceeds its limit".into()) + } + Ok(Self(inner, PhantomData)) + } + + fn skip(input: &mut I) -> Result<(), codec::Error> { + Vec::::skip(input) + } +} + +// `BoundedVec`s encode to something which will always decode as a `Vec`. +impl> EncodeLike> for BoundedVec {} + +impl BoundedVec { + /// Create `Self` from `t` without any checks. + fn unchecked_from(t: Vec) -> Self { + Self(t, Default::default()) + } + + /// Consume self, and return the inner `Vec`. Henceforth, the `Vec<_>` can be altered in an + /// arbitrary way. At some point, if the reverse conversion is required, `TryFrom>` can + /// be used. + /// + /// This is useful for cases if you need access to an internal API of the inner `Vec<_>` which + /// is not provided by the wrapper `BoundedVec`. + pub fn into_inner(self) -> Vec { + self.0 + } + + /// Exactly the same semantics as [`slice::sort_by`]. + /// + /// This is safe since sorting cannot change the number of elements in the vector. + pub fn sort_by(&mut self, compare: F) + where + F: FnMut(&T, &T) -> sp_std::cmp::Ordering, + { + self.0.sort_by(compare) + } + + /// Exactly the same semantics as [`slice::sort`]. + /// + /// This is safe since sorting cannot change the number of elements in the vector. + pub fn sort(&mut self) + where + T: sp_std::cmp::Ord, + { + self.0.sort() + } + + /// Exactly the same semantics as `Vec::remove`. + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + pub fn remove(&mut self, index: usize) -> T { + self.0.remove(index) + } + + /// Exactly the same semantics as `slice::swap_remove`. + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + pub fn swap_remove(&mut self, index: usize) -> T { + self.0.swap_remove(index) + } + + /// Exactly the same semantics as `Vec::retain`. + pub fn retain bool>(&mut self, f: F) { + self.0.retain(f) + } + + /// Exactly the same semantics as `slice::get_mut`. + pub fn get_mut>( + &mut self, + index: I, + ) -> Option<&mut >::Output> { + self.0.get_mut(index) + } + + /// Exactly the same semantics as `Vec::truncate`. + /// + /// This is safe because `truncate` can never increase the length of the internal vector. + pub fn truncate(&mut self, s: usize) { + self.0.truncate(s); + } + + /// Exactly the same semantics as `Vec::pop`. + /// + /// This is safe since popping can only shrink the inner vector. + pub fn pop(&mut self) -> Option { + self.0.pop() + } + + /// Exactly the same semantics as [`slice::iter_mut`]. + pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> { + self.0.iter_mut() + } + + /// Exactly the same semantics as [`slice::last_mut`]. + pub fn last_mut(&mut self) -> Option<&mut T> { + self.0.last_mut() + } + + /// Exact same semantics as [`Vec::drain`]. + pub fn drain(&mut self, range: R) -> sp_std::vec::Drain<'_, T> + where + R: RangeBounds, + { + self.0.drain(range) + } +} + +impl> From> for Vec { + fn from(x: BoundedVec) -> Vec { + x.0 + } +} + +impl> BoundedVec { + /// Pre-allocate `capacity` items in self. + /// + /// If `capacity` is greater than [`Self::bound`], then the minimum of the two is used. + pub fn with_bounded_capacity(capacity: usize) -> Self { + let capacity = capacity.min(Self::bound()); + Self(Vec::with_capacity(capacity), Default::default()) + } + + /// Allocate self with the maximum possible capacity. + pub fn with_max_capacity() -> Self { + Self::with_bounded_capacity(Self::bound()) + } + + /// Consume and truncate the vector `v` in order to create a new instance of `Self` from it. + pub fn truncate_from(mut v: Vec) -> Self { + v.truncate(Self::bound()); + Self::unchecked_from(v) + } + + /// Get the bound of the type in `usize`. + pub fn bound() -> usize { + S::get() as usize + } + + /// Returns true of this collection is full. + pub fn is_full(&self) -> bool { + self.len() >= Self::bound() + } + + /// Forces the insertion of `element` into `self` retaining all items with index at least + /// `index`. + /// + /// If `index == 0` and `self.len() == Self::bound()`, then this is a no-op. + /// + /// If `Self::bound() < index` or `self.len() < index`, then this is also a no-op. + /// + /// Returns `Ok(maybe_removed)` if the item was inserted, where `maybe_removed` is + /// `Some(removed)` if an item was removed to make room for the new one. Returns `Err(())` if + /// `element` cannot be inserted. + pub fn force_insert_keep_right( + &mut self, + index: usize, + mut element: T, + ) -> Result, ()> { + // Check against panics. + if Self::bound() < index || self.len() < index { + Err(()) + } else if self.len() < Self::bound() { + // Cannot panic since self.len() >= index; + self.0.insert(index, element); + Ok(None) + } else { + if index == 0 { + return Err(()) + } + sp_std::mem::swap(&mut self[0], &mut element); + // `[0..index] cannot panic since self.len() >= index. + // `rotate_left(1)` cannot panic because there is at least 1 element. + self[0..index].rotate_left(1); + Ok(Some(element)) + } + } + + /// Forces the insertion of `element` into `self` retaining all items with index at most + /// `index`. + /// + /// If `index == Self::bound()` and `self.len() == Self::bound()`, then this is a no-op. + /// + /// If `Self::bound() < index` or `self.len() < index`, then this is also a no-op. + /// + /// Returns `Ok(maybe_removed)` if the item was inserted, where `maybe_removed` is + /// `Some(removed)` if an item was removed to make room for the new one. Returns `Err(())` if + /// `element` cannot be inserted. + pub fn force_insert_keep_left(&mut self, index: usize, element: T) -> Result, ()> { + // Check against panics. + if Self::bound() < index || self.len() < index || Self::bound() == 0 { + return Err(()) + } + // Noop condition. + if Self::bound() == index && self.len() <= Self::bound() { + return Err(()) + } + let maybe_removed = if self.is_full() { + // defensive-only: since we are at capacity, this is a noop. + self.0.truncate(Self::bound()); + // if we truncate anything, it will be the last one. + self.0.pop() + } else { + None + }; + + // Cannot panic since `self.len() >= index`; + self.0.insert(index, element); + Ok(maybe_removed) + } + + /// Move the position of an item from one location to another in the slice. + /// + /// Except for the item being moved, the order of the slice remains the same. + /// + /// - `index` is the location of the item to be moved. + /// - `insert_position` is the index of the item in the slice which should *immediately follow* + /// the item which is being moved. + /// + /// Returns `true` of the operation was successful, otherwise `false` if a noop. + pub fn slide(&mut self, index: usize, insert_position: usize) -> bool { + // Check against panics. + if self.len() <= index || self.len() < insert_position || index == usize::MAX { + return false + } + // Noop conditions. + if index == insert_position || index + 1 == insert_position { + return false + } + if insert_position < index && index < self.len() { + // --- --- --- === === === === @@@ --- --- --- + // ^-- N ^O^ + // ... + // /-----<<<-----\ + // --- --- --- === === === === @@@ --- --- --- + // >>> >>> >>> >>> + // ... + // --- --- --- @@@ === === === === --- --- --- + // ^N^ + self[insert_position..index + 1].rotate_right(1); + return true + } else if insert_position > 0 && index + 1 < insert_position { + // Note that the apparent asymmetry of these two branches is due to the + // fact that the "new" position is the position to be inserted *before*. + // --- --- --- @@@ === === === === --- --- --- + // ^O^ ^-- N + // ... + // /----->>>-----\ + // --- --- --- @@@ === === === === --- --- --- + // <<< <<< <<< <<< + // ... + // --- --- --- === === === === @@@ --- --- --- + // ^N^ + self[index..insert_position].rotate_left(1); + return true + } + + debug_assert!(false, "all noop conditions should have been covered above"); + false + } + + /// Forces the insertion of `s` into `self` truncating first if necessary. + /// + /// Infallible, but if the bound is zero, then it's a no-op. + pub fn force_push(&mut self, element: T) { + if Self::bound() > 0 { + self.0.truncate(Self::bound() as usize - 1); + self.0.push(element); + } + } + + /// Same as `Vec::resize`, but if `size` is more than [`Self::bound`], then [`Self::bound`] is + /// used. + pub fn bounded_resize(&mut self, size: usize, value: T) + where + T: Clone, + { + let size = size.min(Self::bound()); + self.0.resize(size, value); + } + + /// Exactly the same semantics as [`Vec::extend`], but returns an error and does nothing if the + /// length of the outcome is larger than the bound. + pub fn try_extend( + &mut self, + with: impl IntoIterator + ExactSizeIterator, + ) -> Result<(), ()> { + if with.len().saturating_add(self.len()) <= Self::bound() { + self.0.extend(with); + Ok(()) + } else { + Err(()) + } + } + + /// Exactly the same semantics as [`Vec::append`], but returns an error and does nothing if the + /// length of the outcome is larger than the bound. + pub fn try_append(&mut self, other: &mut Vec) -> Result<(), ()> { + if other.len().saturating_add(self.len()) <= Self::bound() { + self.0.append(other); + Ok(()) + } else { + Err(()) + } + } + + /// Consumes self and mutates self via the given `mutate` function. + /// + /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is + /// returned. + /// + /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> + /// [`Self::try_from`]. + pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut Vec)) -> Option { + mutate(&mut self.0); + (self.0.len() <= Self::bound()).then(move || self) + } + + /// Exactly the same semantics as [`Vec::insert`], but returns an `Err` (and is a noop) if the + /// new length of the vector exceeds `S`. + /// + /// # Panics + /// + /// Panics if `index > len`. + pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), ()> { + if self.len() < Self::bound() { + self.0.insert(index, element); + Ok(()) + } else { + Err(()) + } + } + + /// Exactly the same semantics as [`Vec::push`], but returns an `Err` (and is a noop) if the + /// new length of the vector exceeds `S`. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds isize::MAX bytes. + pub fn try_push(&mut self, element: T) -> Result<(), ()> { + if self.len() < Self::bound() { + self.0.push(element); + Ok(()) + } else { + Err(()) + } + } +} + +impl Default for BoundedVec { + fn default() -> Self { + // the bound cannot be below 0, which is satisfied by an empty vector + Self::unchecked_from(Vec::default()) + } +} + +impl sp_std::fmt::Debug for BoundedVec +where + T: sp_std::fmt::Debug, + S: Get, +{ + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + f.debug_tuple("BoundedVec").field(&self.0).field(&Self::bound()).finish() + } +} + +impl Clone for BoundedVec +where + T: Clone, +{ + fn clone(&self) -> Self { + // bound is retained + Self::unchecked_from(self.0.clone()) + } +} + +impl> TryFrom> for BoundedVec { + type Error = (); + fn try_from(t: Vec) -> Result { + if t.len() <= Self::bound() { + // explicit check just above + Ok(Self::unchecked_from(t)) + } else { + Err(()) + } + } +} + +// It is okay to give a non-mutable reference of the inner vec to anyone. +impl AsRef> for BoundedVec { + fn as_ref(&self) -> &Vec { + &self.0 + } +} + +impl AsRef<[T]> for BoundedVec { + fn as_ref(&self) -> &[T] { + &self.0 + } +} + +impl AsMut<[T]> for BoundedVec { + fn as_mut(&mut self) -> &mut [T] { + &mut self.0 + } +} + +// will allow for immutable all operations of `Vec` on `BoundedVec`. +impl Deref for BoundedVec { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +// Allows for indexing similar to a normal `Vec`. Can panic if out of bound. +impl Index for BoundedVec +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for BoundedVec +where + I: SliceIndex<[T]>, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl sp_std::iter::IntoIterator for BoundedVec { + type Item = T; + type IntoIter = sp_std::vec::IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a, T, S> sp_std::iter::IntoIterator for &'a BoundedVec { + type Item = &'a T; + type IntoIter = sp_std::slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl<'a, T, S> sp_std::iter::IntoIterator for &'a mut BoundedVec { + type Item = &'a mut T; + type IntoIter = sp_std::slice::IterMut<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} + +impl codec::DecodeLength for BoundedVec { + fn len(self_encoded: &[u8]) -> Result { + // `BoundedVec` stored just a `Vec`, thus the length is at the beginning in + // `Compact` form, and same implementation as `Vec` can be used. + as codec::DecodeLength>::len(self_encoded) + } +} + +impl PartialEq> for BoundedVec +where + T: PartialEq, + BoundSelf: Get, + BoundRhs: Get, +{ + fn eq(&self, rhs: &BoundedVec) -> bool { + BoundSelf::get() == BoundRhs::get() && self.0 == rhs.0 + } +} + +impl> PartialEq> for BoundedVec { + fn eq(&self, other: &Vec) -> bool { + &self.0 == other + } +} + +impl> Eq for BoundedVec where T: Eq {} + +impl MaxEncodedLen for BoundedVec +where + T: MaxEncodedLen, + S: Get, + BoundedVec: Encode, +{ + fn max_encoded_len() -> usize { + // BoundedVec encodes like Vec which encodes like [T], which is a compact u32 + // plus each item in the slice: + // https://docs.substrate.io/v3/advanced/scale-codec + codec::Compact(S::get()) + .encoded_size() + .saturating_add(Self::bound().saturating_mul(T::max_encoded_len())) + } +} + +impl TryCollect> for I +where + I: ExactSizeIterator + Iterator, + Bound: Get, +{ + type Error = &'static str; + + fn try_collect(self) -> Result, Self::Error> { + if self.len() > Bound::get() as usize { + Err("iterator length too big") + } else { + Ok(BoundedVec::::unchecked_from(self.collect::>())) + } + } +} + +#[cfg(test)] +pub mod test { + use super::*; + use crate::{bounded_vec, traits::ConstU32}; + + #[test] + fn slide_works() { + let mut b: BoundedVec> = bounded_vec![0, 1, 2, 3, 4, 5]; + assert!(b.slide(1, 5)); + assert_eq!(*b, vec![0, 2, 3, 4, 1, 5]); + assert!(b.slide(4, 0)); + assert_eq!(*b, vec![1, 0, 2, 3, 4, 5]); + assert!(b.slide(0, 2)); + assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); + assert!(b.slide(1, 6)); + assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); + assert!(b.slide(0, 6)); + assert_eq!(*b, vec![2, 3, 4, 5, 1, 0]); + assert!(b.slide(5, 0)); + assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); + assert!(!b.slide(6, 0)); + assert!(!b.slide(7, 0)); + assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); + + let mut c: BoundedVec> = bounded_vec![0, 1, 2]; + assert!(!c.slide(1, 5)); + assert_eq!(*c, vec![0, 1, 2]); + assert!(!c.slide(4, 0)); + assert_eq!(*c, vec![0, 1, 2]); + assert!(!c.slide(3, 0)); + assert_eq!(*c, vec![0, 1, 2]); + assert!(c.slide(2, 0)); + assert_eq!(*c, vec![2, 0, 1]); + } + + #[test] + fn slide_noops_work() { + let mut b: BoundedVec> = bounded_vec![0, 1, 2, 3, 4, 5]; + assert!(!b.slide(3, 3)); + assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); + assert!(!b.slide(3, 4)); + assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); + } + + #[test] + fn force_insert_keep_left_works() { + let mut b: BoundedVec> = bounded_vec![]; + assert_eq!(b.force_insert_keep_left(1, 10), Err(())); + assert!(b.is_empty()); + + assert_eq!(b.force_insert_keep_left(0, 30), Ok(None)); + assert_eq!(b.force_insert_keep_left(0, 10), Ok(None)); + assert_eq!(b.force_insert_keep_left(1, 20), Ok(None)); + assert_eq!(b.force_insert_keep_left(3, 40), Ok(None)); + assert_eq!(*b, vec![10, 20, 30, 40]); + // at capacity. + assert_eq!(b.force_insert_keep_left(4, 41), Err(())); + assert_eq!(*b, vec![10, 20, 30, 40]); + assert_eq!(b.force_insert_keep_left(3, 31), Ok(Some(40))); + assert_eq!(*b, vec![10, 20, 30, 31]); + assert_eq!(b.force_insert_keep_left(1, 11), Ok(Some(31))); + assert_eq!(*b, vec![10, 11, 20, 30]); + assert_eq!(b.force_insert_keep_left(0, 1), Ok(Some(30))); + assert_eq!(*b, vec![1, 10, 11, 20]); + + let mut z: BoundedVec> = bounded_vec![]; + assert!(z.is_empty()); + assert_eq!(z.force_insert_keep_left(0, 10), Err(())); + assert!(z.is_empty()); + } + + #[test] + fn force_insert_keep_right_works() { + let mut b: BoundedVec> = bounded_vec![]; + assert_eq!(b.force_insert_keep_right(1, 10), Err(())); + assert!(b.is_empty()); + + assert_eq!(b.force_insert_keep_right(0, 30), Ok(None)); + assert_eq!(b.force_insert_keep_right(0, 10), Ok(None)); + assert_eq!(b.force_insert_keep_right(1, 20), Ok(None)); + assert_eq!(b.force_insert_keep_right(3, 40), Ok(None)); + assert_eq!(*b, vec![10, 20, 30, 40]); + + // at capacity. + assert_eq!(b.force_insert_keep_right(0, 0), Err(())); + assert_eq!(*b, vec![10, 20, 30, 40]); + assert_eq!(b.force_insert_keep_right(1, 11), Ok(Some(10))); + assert_eq!(*b, vec![11, 20, 30, 40]); + assert_eq!(b.force_insert_keep_right(3, 31), Ok(Some(11))); + assert_eq!(*b, vec![20, 30, 31, 40]); + assert_eq!(b.force_insert_keep_right(4, 41), Ok(Some(20))); + assert_eq!(*b, vec![30, 31, 40, 41]); + + assert_eq!(b.force_insert_keep_right(5, 69), Err(())); + assert_eq!(*b, vec![30, 31, 40, 41]); + + let mut z: BoundedVec> = bounded_vec![]; + assert!(z.is_empty()); + assert_eq!(z.force_insert_keep_right(0, 10), Err(())); + assert!(z.is_empty()); + } + + #[test] + fn bound_returns_correct_value() { + assert_eq!(BoundedVec::>::bound(), 7); + } + + #[test] + fn try_insert_works() { + let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; + bounded.try_insert(1, 0).unwrap(); + assert_eq!(*bounded, vec![1, 0, 2, 3]); + + assert!(bounded.try_insert(0, 9).is_err()); + assert_eq!(*bounded, vec![1, 0, 2, 3]); + } + + #[test] + fn constructor_macro_works() { + // With values. Use some brackets to make sure the macro doesn't expand. + let bv: BoundedVec<(u32, u32), ConstU32<3>> = bounded_vec![(1, 2), (1, 2), (1, 2)]; + assert_eq!(bv, vec![(1, 2), (1, 2), (1, 2)]); + + // With repetition. + let bv: BoundedVec<(u32, u32), ConstU32<3>> = bounded_vec![(1, 2); 3]; + assert_eq!(bv, vec![(1, 2), (1, 2), (1, 2)]); + } + + #[test] + #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] + fn try_inert_panics_if_oob() { + let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; + bounded.try_insert(9, 0).unwrap(); + } + + #[test] + fn try_push_works() { + let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; + bounded.try_push(0).unwrap(); + assert_eq!(*bounded, vec![1, 2, 3, 0]); + + assert!(bounded.try_push(9).is_err()); + } + + #[test] + fn deref_coercion_works() { + let bounded: BoundedVec> = bounded_vec![1, 2, 3]; + // these methods come from deref-ed vec. + assert_eq!(bounded.len(), 3); + assert!(bounded.iter().next().is_some()); + assert!(!bounded.is_empty()); + } + + #[test] + fn try_mutate_works() { + let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; + let bounded = bounded.try_mutate(|v| v.push(7)).unwrap(); + assert_eq!(bounded.len(), 7); + assert!(bounded.try_mutate(|v| v.push(8)).is_none()); + } + + #[test] + fn slice_indexing_works() { + let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; + assert_eq!(&bounded[0..=2], &[1, 2, 3]); + } + + #[test] + fn vec_eq_works() { + let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; + assert_eq!(bounded, vec![1, 2, 3, 4, 5, 6]); + } + + #[test] + fn too_big_vec_fail_to_decode() { + let v: Vec = vec![1, 2, 3, 4, 5]; + assert_eq!( + BoundedVec::>::decode(&mut &v.encode()[..]), + Err("BoundedVec exceeds its limit".into()), + ); + } + + #[test] + fn eq_works() { + // of same type + let b1: BoundedVec> = bounded_vec![1, 2, 3]; + let b2: BoundedVec> = bounded_vec![1, 2, 3]; + assert_eq!(b1, b2); + + // of different type, but same value and bound. + crate::parameter_types! { + B1: u32 = 7; + B2: u32 = 7; + } + let b1: BoundedVec = bounded_vec![1, 2, 3]; + let b2: BoundedVec = bounded_vec![1, 2, 3]; + assert_eq!(b1, b2); + } + + #[test] + fn ord_works() { + use std::cmp::Ordering; + let b1: BoundedVec> = bounded_vec![1, 2, 3]; + let b2: BoundedVec> = bounded_vec![1, 3, 2]; + + // ordering for vec is lexicographic. + assert_eq!(b1.cmp(&b2), Ordering::Less); + assert_eq!(b1.cmp(&b2), b1.into_inner().cmp(&b2.into_inner())); + } + + #[test] + fn try_extend_works() { + let mut b: BoundedVec> = bounded_vec![1, 2, 3]; + + assert!(b.try_extend(vec![4].into_iter()).is_ok()); + assert_eq!(*b, vec![1, 2, 3, 4]); + + assert!(b.try_extend(vec![5].into_iter()).is_ok()); + assert_eq!(*b, vec![1, 2, 3, 4, 5]); + + assert!(b.try_extend(vec![6].into_iter()).is_err()); + assert_eq!(*b, vec![1, 2, 3, 4, 5]); + + let mut b: BoundedVec> = bounded_vec![1, 2, 3]; + assert!(b.try_extend(vec![4, 5].into_iter()).is_ok()); + assert_eq!(*b, vec![1, 2, 3, 4, 5]); + + let mut b: BoundedVec> = bounded_vec![1, 2, 3]; + assert!(b.try_extend(vec![4, 5, 6].into_iter()).is_err()); + assert_eq!(*b, vec![1, 2, 3]); + } + + #[test] + fn test_serializer() { + let c: BoundedVec> = bounded_vec![0, 1, 2]; + assert_eq!(serde_json::json!(&c).to_string(), r#"[0,1,2]"#); + } + + #[test] + fn test_deserializer() { + let c: BoundedVec> = serde_json::from_str(r#"[0,1,2]"#).unwrap(); + + assert_eq!(c.len(), 3); + assert_eq!(c[0], 0); + assert_eq!(c[1], 1); + assert_eq!(c[2], 2); + } + + #[test] + fn test_deserializer_failed() { + let c: Result>, serde_json::error::Error> = + serde_json::from_str(r#"[0,1,2,3,4,5]"#); + + match c { + Err(msg) => assert_eq!(msg.to_string(), "out of bounds at line 1 column 11"), + _ => unreachable!("deserializer must raise error"), + } + } + + #[test] + fn bounded_vec_try_from_works() { + assert!(BoundedVec::>::try_from(vec![0]).is_ok()); + assert!(BoundedVec::>::try_from(vec![0, 1]).is_ok()); + assert!(BoundedVec::>::try_from(vec![0, 1, 2]).is_err()); + } + + #[test] + fn bounded_slice_try_from_works() { + assert!(BoundedSlice::>::try_from(&[0][..]).is_ok()); + assert!(BoundedSlice::>::try_from(&[0, 1][..]).is_ok()); + assert!(BoundedSlice::>::try_from(&[0, 1, 2][..]).is_err()); + } + + #[test] + fn can_be_collected() { + let b1: BoundedVec> = bounded_vec![1, 2, 3, 4]; + let b2: BoundedVec> = b1.iter().map(|x| x + 1).try_collect().unwrap(); + assert_eq!(b2, vec![2, 3, 4, 5]); + + // can also be collected into a collection of length 4. + let b2: BoundedVec> = b1.iter().map(|x| x + 1).try_collect().unwrap(); + assert_eq!(b2, vec![2, 3, 4, 5]); + + // can be mutated further into iterators that are `ExactSizedIterator`. + let b2: BoundedVec> = + b1.iter().map(|x| x + 1).rev().try_collect().unwrap(); + assert_eq!(b2, vec![5, 4, 3, 2]); + + let b2: BoundedVec> = + b1.iter().map(|x| x + 1).rev().skip(2).try_collect().unwrap(); + assert_eq!(b2, vec![3, 2]); + let b2: BoundedVec> = + b1.iter().map(|x| x + 1).rev().skip(2).try_collect().unwrap(); + assert_eq!(b2, vec![3, 2]); + + let b2: BoundedVec> = + b1.iter().map(|x| x + 1).rev().take(2).try_collect().unwrap(); + assert_eq!(b2, vec![5, 4]); + let b2: BoundedVec> = + b1.iter().map(|x| x + 1).rev().take(2).try_collect().unwrap(); + assert_eq!(b2, vec![5, 4]); + + // but these worn't work + let b2: Result>, _> = b1.iter().map(|x| x + 1).try_collect(); + assert!(b2.is_err()); + + let b2: Result>, _> = + b1.iter().map(|x| x + 1).rev().take(2).try_collect(); + assert!(b2.is_err()); + } +} diff --git a/primitives/runtime/src/bounded/weak_bounded_vec.rs b/primitives/runtime/src/bounded/weak_bounded_vec.rs new file mode 100644 index 0000000000000..9b88ad27e4287 --- /dev/null +++ b/primitives/runtime/src/bounded/weak_bounded_vec.rs @@ -0,0 +1,393 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Traits, types and structs to support putting a bounded vector into storage, as a raw value, map +//! or a double map. + +use crate::traits::Get; +use codec::{Decode, Encode, MaxEncodedLen}; +use core::{ + ops::{Deref, Index, IndexMut}, + slice::SliceIndex, +}; +use sp_std::{marker::PhantomData, prelude::*}; + +/// A weakly bounded vector. +/// +/// It has implementations for efficient append and length decoding, as with a normal `Vec<_>`, once +/// put into storage as a raw value, map or double-map. +/// +/// The length of the vec is not strictly bounded. Decoding a vec with more element that the bound +/// is accepted, and some method allow to bypass the restriction with warnings. +#[derive(Encode, scale_info::TypeInfo)] +#[scale_info(skip_type_params(S))] +pub struct WeakBoundedVec(Vec, PhantomData); + +impl> Decode for WeakBoundedVec { + fn decode(input: &mut I) -> Result { + let inner = Vec::::decode(input)?; + Ok(Self::force_from(inner, Some("decode"))) + } + + fn skip(input: &mut I) -> Result<(), codec::Error> { + Vec::::skip(input) + } +} + +impl WeakBoundedVec { + /// Create `Self` from `t` without any checks. + fn unchecked_from(t: Vec) -> Self { + Self(t, Default::default()) + } + + /// Consume self, and return the inner `Vec`. Henceforth, the `Vec<_>` can be altered in an + /// arbitrary way. At some point, if the reverse conversion is required, `TryFrom>` can + /// be used. + /// + /// This is useful for cases if you need access to an internal API of the inner `Vec<_>` which + /// is not provided by the wrapper `WeakBoundedVec`. + pub fn into_inner(self) -> Vec { + self.0 + } + + /// Exactly the same semantics as [`Vec::remove`]. + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + pub fn remove(&mut self, index: usize) -> T { + self.0.remove(index) + } + + /// Exactly the same semantics as [`Vec::swap_remove`]. + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + pub fn swap_remove(&mut self, index: usize) -> T { + self.0.swap_remove(index) + } + + /// Exactly the same semantics as [`Vec::retain`]. + pub fn retain bool>(&mut self, f: F) { + self.0.retain(f) + } + + /// Exactly the same semantics as [`slice::get_mut`]. + pub fn get_mut>( + &mut self, + index: I, + ) -> Option<&mut >::Output> { + self.0.get_mut(index) + } +} + +impl> WeakBoundedVec { + /// Get the bound of the type in `usize`. + pub fn bound() -> usize { + S::get() as usize + } + + /// Create `Self` from `t` without any checks. Logs warnings if the bound is not being + /// respected. The additional scope can be used to indicate where a potential overflow is + /// happening. + pub fn force_from(t: Vec, scope: Option<&'static str>) -> Self { + if t.len() > Self::bound() { + log::warn!( + target: "runtime", + "length of a bounded vector in scope {} is not respected.", + scope.unwrap_or("UNKNOWN"), + ); + } + + Self::unchecked_from(t) + } + + /// Consumes self and mutates self via the given `mutate` function. + /// + /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is + /// returned. + /// + /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> + /// [`Self::try_from`]. + pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut Vec)) -> Option { + mutate(&mut self.0); + (self.0.len() <= Self::bound()).then(move || self) + } + + /// Exactly the same semantics as [`Vec::insert`], but returns an `Err` (and is a noop) if the + /// new length of the vector exceeds `S`. + /// + /// # Panics + /// + /// Panics if `index > len`. + pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), ()> { + if self.len() < Self::bound() { + self.0.insert(index, element); + Ok(()) + } else { + Err(()) + } + } + + /// Exactly the same semantics as [`Vec::push`], but returns an `Err` (and is a noop) if the + /// new length of the vector exceeds `S`. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds isize::MAX bytes. + pub fn try_push(&mut self, element: T) -> Result<(), ()> { + if self.len() < Self::bound() { + self.0.push(element); + Ok(()) + } else { + Err(()) + } + } +} + +impl Default for WeakBoundedVec { + fn default() -> Self { + // the bound cannot be below 0, which is satisfied by an empty vector + Self::unchecked_from(Vec::default()) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Debug for WeakBoundedVec +where + T: std::fmt::Debug, + S: Get, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("WeakBoundedVec").field(&self.0).field(&Self::bound()).finish() + } +} + +impl Clone for WeakBoundedVec +where + T: Clone, +{ + fn clone(&self) -> Self { + // bound is retained + Self::unchecked_from(self.0.clone()) + } +} + +impl> TryFrom> for WeakBoundedVec { + type Error = (); + fn try_from(t: Vec) -> Result { + if t.len() <= Self::bound() { + // explicit check just above + Ok(Self::unchecked_from(t)) + } else { + Err(()) + } + } +} + +// It is okay to give a non-mutable reference of the inner vec to anyone. +impl AsRef> for WeakBoundedVec { + fn as_ref(&self) -> &Vec { + &self.0 + } +} + +impl AsRef<[T]> for WeakBoundedVec { + fn as_ref(&self) -> &[T] { + &self.0 + } +} + +impl AsMut<[T]> for WeakBoundedVec { + fn as_mut(&mut self) -> &mut [T] { + &mut self.0 + } +} + +// will allow for immutable all operations of `Vec` on `WeakBoundedVec`. +impl Deref for WeakBoundedVec { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +// Allows for indexing similar to a normal `Vec`. Can panic if out of bound. +impl Index for WeakBoundedVec +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for WeakBoundedVec +where + I: SliceIndex<[T]>, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl sp_std::iter::IntoIterator for WeakBoundedVec { + type Item = T; + type IntoIter = sp_std::vec::IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a, T, S> sp_std::iter::IntoIterator for &'a WeakBoundedVec { + type Item = &'a T; + type IntoIter = sp_std::slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl<'a, T, S> sp_std::iter::IntoIterator for &'a mut WeakBoundedVec { + type Item = &'a mut T; + type IntoIter = sp_std::slice::IterMut<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} + +impl codec::DecodeLength for WeakBoundedVec { + fn len(self_encoded: &[u8]) -> Result { + // `WeakBoundedVec` stored just a `Vec`, thus the length is at the beginning in + // `Compact` form, and same implementation as `Vec` can be used. + as codec::DecodeLength>::len(self_encoded) + } +} + +// NOTE: we could also implement this as: +// impl, S2: Get> PartialEq> for WeakBoundedVec to allow comparison of bounded vectors with different bounds. +impl PartialEq for WeakBoundedVec +where + T: PartialEq, +{ + fn eq(&self, rhs: &Self) -> bool { + self.0 == rhs.0 + } +} + +impl> PartialEq> for WeakBoundedVec { + fn eq(&self, other: &Vec) -> bool { + &self.0 == other + } +} + +impl Eq for WeakBoundedVec where T: Eq {} + +impl MaxEncodedLen for WeakBoundedVec +where + T: MaxEncodedLen, + S: Get, + WeakBoundedVec: Encode, +{ + fn max_encoded_len() -> usize { + // WeakBoundedVec encodes like Vec which encodes like [T], which is a compact u32 + // plus each item in the slice: + // https://docs.substrate.io/v3/advanced/scale-codec + codec::Compact(S::get()) + .encoded_size() + .saturating_add(Self::bound().saturating_mul(T::max_encoded_len())) + } +} + +#[cfg(test)] +pub mod test { + use super::*; + use crate::traits::ConstU32; + + #[test] + fn bound_returns_correct_value() { + assert_eq!(WeakBoundedVec::>::bound(), 7); + } + + #[test] + fn try_insert_works() { + let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); + bounded.try_insert(1, 0).unwrap(); + assert_eq!(*bounded, vec![1, 0, 2, 3]); + + assert!(bounded.try_insert(0, 9).is_err()); + assert_eq!(*bounded, vec![1, 0, 2, 3]); + } + + #[test] + #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] + fn try_inert_panics_if_oob() { + let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); + bounded.try_insert(9, 0).unwrap(); + } + + #[test] + fn try_push_works() { + let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); + bounded.try_push(0).unwrap(); + assert_eq!(*bounded, vec![1, 2, 3, 0]); + + assert!(bounded.try_push(9).is_err()); + } + + #[test] + fn deref_coercion_works() { + let bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); + // these methods come from deref-ed vec. + assert_eq!(bounded.len(), 3); + assert!(bounded.iter().next().is_some()); + assert!(!bounded.is_empty()); + } + + #[test] + fn try_mutate_works() { + let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + let bounded = bounded.try_mutate(|v| v.push(7)).unwrap(); + assert_eq!(bounded.len(), 7); + assert!(bounded.try_mutate(|v| v.push(8)).is_none()); + } + + #[test] + fn slice_indexing_works() { + let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + assert_eq!(&bounded[0..=2], &[1, 2, 3]); + } + + #[test] + fn vec_eq_works() { + let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); + assert_eq!(bounded, vec![1, 2, 3, 4, 5, 6]); + } + + #[test] + fn too_big_succeed_to_decode() { + let v: Vec = vec![1, 2, 3, 4, 5]; + let w = WeakBoundedVec::>::decode(&mut &v.encode()[..]).unwrap(); + assert_eq!(v, *w); + } +} diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 39e606eb9b5f4..b41c605d8a3be 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -55,6 +55,7 @@ use sp_std::prelude::*; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +pub mod bounded; pub mod curve; pub mod generic; pub mod legacy; @@ -69,6 +70,9 @@ pub mod transaction_validity; pub use crate::runtime_string::*; +// Re-export bounded types +pub use bounded::{BoundedBTreeMap, BoundedBTreeSet, BoundedSlice, BoundedVec, WeakBoundedVec}; + // Re-export Multiaddress pub use multiaddress::MultiAddress; @@ -825,6 +829,45 @@ macro_rules! assert_eq_error_rate { }; } +/// Build a bounded vec from the given literals. +/// +/// The type of the outcome must be known. +/// +/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding +/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. +#[macro_export] +#[cfg(feature = "std")] +macro_rules! bounded_vec { + ($ ($values:expr),* $(,)?) => { + { + $crate::sp_std::vec![$($values),*].try_into().unwrap() + } + }; + ( $value:expr ; $repetition:expr ) => { + { + $crate::sp_std::vec![$value ; $repetition].try_into().unwrap() + } + } +} + +/// Build a bounded btree-map from the given literals. +/// +/// The type of the outcome must be known. +/// +/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding +/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. +#[macro_export] +#[cfg(feature = "std")] +macro_rules! bounded_btree_map { + ($ ( $key:expr => $value:expr ),* $(,)?) => { + { + $crate::traits::TryCollect::<$crate::BoundedBTreeMap<_, _, _>>::try_collect( + $crate::sp_std::vec![$(($key, $value)),*].into_iter() + ).unwrap() + } + }; +} + /// Simple blob to hold an extrinsic without committing to its format and ensure it is serialized /// correctly. #[derive(PartialEq, Eq, Clone, Default, Encode, Decode, TypeInfo)] diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index aa5908526b819..fba3117c41617 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -308,6 +308,17 @@ impl Get for GetDefault { } } +/// Try and collect into a collection `C`. +pub trait TryCollect { + /// The error type that gets returned when a collection can't be made from `self`. + type Error; + /// Consume self and try to collect the results into `C`. + /// + /// This is useful in preventing the undesirable `.collect().try_into()` call chain on + /// collections that need to be converted into a bounded type (e.g. `BoundedVec`). + fn try_collect(self) -> Result; +} + macro_rules! impl_const_get { ($name:ident, $t:ty) => { #[doc = "Const getter for a basic type."] From c8e2c4cea0485fea3b0d76099b5320730c3c8a9f Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 13 Jun 2022 19:53:07 +0200 Subject: [PATCH 0907/1472] Implement MaxEncodedLen on pallet-beefy (#11584) * Implement MaxEncodedLen on pallet-beefy * Return Result in intialize_authorities * Update docs * Log error when authorities list gets truncated * Update frame/beefy/src/lib.rs Co-authored-by: Adrian Catangiu * cargo fmt Co-authored-by: Adrian Catangiu --- frame/beefy-mmr/src/mock.rs | 1 + frame/beefy/src/lib.rs | 84 ++++++++++++++----- frame/beefy/src/mock.rs | 3 +- primitives/runtime/src/bounded/bounded_vec.rs | 9 ++ 4 files changed, 73 insertions(+), 24 deletions(-) diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index f6a35f68a4a1f..c9dbdb3b2e16a 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -124,6 +124,7 @@ impl pallet_mmr::Config for Test { impl pallet_beefy::Config for Test { type BeefyId = BeefyId; + type MaxAuthorities = ConstU32<100>; } parameter_types! { diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 14e7ac26cdb6e..a0cba2270b37d 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -17,9 +17,13 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::Encode; +use codec::{Encode, MaxEncodedLen}; -use frame_support::{traits::OneSessionHandler, Parameter}; +use frame_support::{ + log, + traits::{Get, OneSessionHandler}, + BoundedSlice, BoundedVec, Parameter, +}; use sp_runtime::{ generic::DigestItem, @@ -42,28 +46,28 @@ pub use pallet::*; pub mod pallet { use super::*; use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; #[pallet::config] pub trait Config: frame_system::Config { /// Authority identifier type - type BeefyId: Member + Parameter + RuntimeAppPublic + MaybeSerializeDeserialize; + type BeefyId: Member + + Parameter + + RuntimeAppPublic + + MaybeSerializeDeserialize + + MaxEncodedLen; + + /// The maximum number of authorities that can be added. + type MaxAuthorities: Get; } #[pallet::pallet] - #[pallet::without_storage_info] pub struct Pallet(PhantomData); - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet {} - /// The current authorities set #[pallet::storage] #[pallet::getter(fn authorities)] - pub(super) type Authorities = StorageValue<_, Vec, ValueQuery>; + pub(super) type Authorities = + StorageValue<_, BoundedVec, ValueQuery>; /// The current validator set id #[pallet::storage] @@ -74,7 +78,8 @@ pub mod pallet { /// Authorities set scheduled to be used with the next session #[pallet::storage] #[pallet::getter(fn next_authorities)] - pub(super) type NextAuthorities = StorageValue<_, Vec, ValueQuery>; + pub(super) type NextAuthorities = + StorageValue<_, BoundedVec, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig { @@ -91,7 +96,10 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - Pallet::::initialize_authorities(&self.authorities); + Pallet::::initialize_authorities(&self.authorities) + // we panic here as runtime maintainers can simply reconfigure genesis and restart + // the chain easily + .expect("Authorities vec too big"); } } } @@ -99,12 +107,15 @@ pub mod pallet { impl Pallet { /// Return the current active BEEFY validator set. pub fn validator_set() -> Option> { - let validators: Vec = Self::authorities(); + let validators: BoundedVec = Self::authorities(); let id: beefy_primitives::ValidatorSetId = Self::validator_set_id(); ValidatorSet::::new(validators, id) } - fn change_authorities(new: Vec, queued: Vec) { + fn change_authorities( + new: BoundedVec, + queued: BoundedVec, + ) { >::put(&new); let next_id = Self::validator_set_id() + 1u64; @@ -120,17 +131,23 @@ impl Pallet { >::put(&queued); } - fn initialize_authorities(authorities: &[T::BeefyId]) { + fn initialize_authorities(authorities: &[T::BeefyId]) -> Result<(), ()> { if authorities.is_empty() { - return + return Ok(()) + } + + if !>::get().is_empty() { + return Err(()) } - assert!(>::get().is_empty(), "Authorities are already initialized!"); + let bounded_authorities = + BoundedSlice::::try_from(authorities)?; - >::put(authorities); + >::put(bounded_authorities); >::put(0); // Like `pallet_session`, initialize the next validator set as well. - >::put(authorities); + >::put(bounded_authorities); + Ok(()) } } @@ -146,7 +163,9 @@ impl OneSessionHandler for Pallet { I: Iterator, { let authorities = validators.map(|(_, k)| k).collect::>(); - Self::initialize_authorities(&authorities); + // we panic here as runtime maintainers can simply reconfigure genesis and restart the + // chain easily + Self::initialize_authorities(&authorities).expect("Authorities vec too big"); } fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I) @@ -154,11 +173,30 @@ impl OneSessionHandler for Pallet { I: Iterator, { let next_authorities = validators.map(|(_, k)| k).collect::>(); + if next_authorities.len() as u32 > T::MaxAuthorities::get() { + log::error!( + target: "runtime::beefy", + "authorities list {:?} truncated to length {}", + next_authorities, T::MaxAuthorities::get(), + ); + } + let bounded_next_authorities = + BoundedVec::<_, T::MaxAuthorities>::truncate_from(next_authorities); + let next_queued_authorities = queued_validators.map(|(_, k)| k).collect::>(); + if next_queued_authorities.len() as u32 > T::MaxAuthorities::get() { + log::error!( + target: "runtime::beefy", + "queued authorities list {:?} truncated to length {}", + next_queued_authorities, T::MaxAuthorities::get(), + ); + } + let bounded_next_queued_authorities = + BoundedVec::<_, T::MaxAuthorities>::truncate_from(next_queued_authorities); // Always issue a change on each `session`, even if validator set hasn't changed. // We want to have at least one BEEFY mandatory block per session. - Self::change_authorities(next_authorities, next_queued_authorities); + Self::change_authorities(bounded_next_authorities, bounded_next_queued_authorities); } fn on_disabled(i: u32) { diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 7a8f15cd51d29..27796b5b2206c 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -52,7 +52,7 @@ construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - Beefy: pallet_beefy::{Pallet, Call, Config, Storage}, + Beefy: pallet_beefy::{Pallet, Config, Storage}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, } ); @@ -86,6 +86,7 @@ impl frame_system::Config for Test { impl pallet_beefy::Config for Test { type BeefyId = BeefyId; + type MaxAuthorities = ConstU32<100>; } parameter_types! { diff --git a/primitives/runtime/src/bounded/bounded_vec.rs b/primitives/runtime/src/bounded/bounded_vec.rs index 4493d9f8b0198..fe832b07f9588 100644 --- a/primitives/runtime/src/bounded/bounded_vec.rs +++ b/primitives/runtime/src/bounded/bounded_vec.rs @@ -146,6 +146,15 @@ impl<'a, T, S> From> for &'a [T] { } } +impl<'a, T, S> Clone for BoundedSlice<'a, T, S> { + fn clone(&self) -> Self { + BoundedSlice(self.0, PhantomData) + } +} + +// Since a reference `&T` is always `Copy`, so is `BoundedSlice<'a, T, S>`. +impl<'a, T, S> Copy for BoundedSlice<'a, T, S> {} + impl<'a, T, S> sp_std::iter::IntoIterator for BoundedSlice<'a, T, S> { type Item = &'a T; type IntoIter = sp_std::slice::Iter<'a, T>; From 4c41a7b0e9fc503648373e415235df97a7e10362 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 13 Jun 2022 22:55:48 +0200 Subject: [PATCH 0908/1472] Implement PartialOrd and Ord on BoundedSlice and WeakBoundedVec (#11655) * Implement PartialOrd and Ord on BoundedSlice and WeakBoundedVec * More implementations of PartialEq and PartialOrd * cargo fmt * Fixes --- .../runtime/src/bounded/bounded_btree_map.rs | 8 +- .../runtime/src/bounded/bounded_btree_set.rs | 8 +- primitives/runtime/src/bounded/bounded_vec.rs | 145 +++++++++++++++++- .../runtime/src/bounded/weak_bounded_vec.rs | 78 +++++++++- 4 files changed, 221 insertions(+), 18 deletions(-) diff --git a/primitives/runtime/src/bounded/bounded_btree_map.rs b/primitives/runtime/src/bounded/bounded_btree_map.rs index f4fd4275beb2a..b9abf77f175c6 100644 --- a/primitives/runtime/src/bounded/bounded_btree_map.rs +++ b/primitives/runtime/src/bounded/bounded_btree_map.rs @@ -66,6 +66,11 @@ where K: Ord, S: Get, { + /// Create `Self` from `t` without any checks. + fn unchecked_from(t: BTreeMap) -> Self { + Self(t, Default::default()) + } + /// Exactly the same semantics as `BTreeMap::retain`. /// /// The is a safe `&mut self` borrow because `retain` can only ever decrease the length of the @@ -344,8 +349,7 @@ where if self.len() > Bound::get() as usize { Err("iterator length too big") } else { - Ok(BoundedBTreeMap::::try_from(self.collect::>()) - .expect("length checked above; qed")) + Ok(BoundedBTreeMap::::unchecked_from(self.collect::>())) } } } diff --git a/primitives/runtime/src/bounded/bounded_btree_set.rs b/primitives/runtime/src/bounded/bounded_btree_set.rs index 40b95165da1bd..0f8cc769e47e3 100644 --- a/primitives/runtime/src/bounded/bounded_btree_set.rs +++ b/primitives/runtime/src/bounded/bounded_btree_set.rs @@ -65,6 +65,11 @@ where T: Ord, S: Get, { + /// Create `Self` from `t` without any checks. + fn unchecked_from(t: BTreeSet) -> Self { + Self(t, Default::default()) + } + /// Create a new `BoundedBTreeSet`. /// /// Does not allocate. @@ -309,8 +314,7 @@ where if self.len() > Bound::get() as usize { Err("iterator length too big") } else { - Ok(BoundedBTreeSet::::try_from(self.collect::>()) - .expect("length is checked above; qed")) + Ok(BoundedBTreeSet::::unchecked_from(self.collect::>())) } } } diff --git a/primitives/runtime/src/bounded/bounded_vec.rs b/primitives/runtime/src/bounded/bounded_vec.rs index fe832b07f9588..84acddea47cab 100644 --- a/primitives/runtime/src/bounded/bounded_vec.rs +++ b/primitives/runtime/src/bounded/bounded_vec.rs @@ -43,7 +43,7 @@ use sp_std::{marker::PhantomData, prelude::*}; #[derive(Encode, scale_info::TypeInfo)] #[scale_info(skip_type_params(S))] pub struct BoundedVec( - Vec, + pub(super) Vec, #[cfg_attr(feature = "std", serde(skip_serializing))] PhantomData, ); @@ -106,7 +106,7 @@ where /// Similar to a `BoundedVec`, but not owned and cannot be decoded. #[derive(Encode, scale_info::TypeInfo)] #[scale_info(skip_type_params(S))] -pub struct BoundedSlice<'a, T, S>(&'a [T], PhantomData); +pub struct BoundedSlice<'a, T, S>(pub(super) &'a [T], PhantomData); // `BoundedSlice`s encode to something which will always decode into a `BoundedVec`, // `WeakBoundedVec`, or a `Vec`. @@ -117,13 +117,81 @@ impl<'a, T: Encode + Decode, S: Get> EncodeLike> } impl<'a, T: Encode + Decode, S: Get> EncodeLike> for BoundedSlice<'a, T, S> {} -impl> PartialOrd for BoundedVec { - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) +impl<'a, T, BoundSelf, BoundRhs> PartialEq> + for BoundedSlice<'a, T, BoundSelf> +where + T: PartialEq, + BoundSelf: Get, + BoundRhs: Get, +{ + fn eq(&self, other: &BoundedSlice<'a, T, BoundRhs>) -> bool { + self.0 == other.0 } } -impl> Ord for BoundedVec { +impl<'a, T, BoundSelf, BoundRhs> PartialEq> + for BoundedSlice<'a, T, BoundSelf> +where + T: PartialEq, + BoundSelf: Get, + BoundRhs: Get, +{ + fn eq(&self, other: &BoundedVec) -> bool { + self.0 == other.0 + } +} + +impl<'a, T, BoundSelf, BoundRhs> PartialEq> + for BoundedSlice<'a, T, BoundSelf> +where + T: PartialEq, + BoundSelf: Get, + BoundRhs: Get, +{ + fn eq(&self, other: &WeakBoundedVec) -> bool { + self.0 == other.0 + } +} + +impl<'a, T, S: Get> Eq for BoundedSlice<'a, T, S> where T: Eq {} + +impl<'a, T, BoundSelf, BoundRhs> PartialOrd> + for BoundedSlice<'a, T, BoundSelf> +where + T: PartialOrd, + BoundSelf: Get, + BoundRhs: Get, +{ + fn partial_cmp(&self, other: &BoundedSlice<'a, T, BoundRhs>) -> Option { + self.0.partial_cmp(other.0) + } +} + +impl<'a, T, BoundSelf, BoundRhs> PartialOrd> + for BoundedSlice<'a, T, BoundSelf> +where + T: PartialOrd, + BoundSelf: Get, + BoundRhs: Get, +{ + fn partial_cmp(&self, other: &BoundedVec) -> Option { + self.0.partial_cmp(&*other.0) + } +} + +impl<'a, T, BoundSelf, BoundRhs> PartialOrd> + for BoundedSlice<'a, T, BoundSelf> +where + T: PartialOrd, + BoundSelf: Get, + BoundRhs: Get, +{ + fn partial_cmp(&self, other: &WeakBoundedVec) -> Option { + self.0.partial_cmp(&*other.0) + } +} + +impl<'a, T: Ord, Bound: Get> Ord for BoundedSlice<'a, T, Bound> { fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { self.0.cmp(&other.0) } @@ -650,7 +718,30 @@ where BoundRhs: Get, { fn eq(&self, rhs: &BoundedVec) -> bool { - BoundSelf::get() == BoundRhs::get() && self.0 == rhs.0 + self.0 == rhs.0 + } +} + +impl PartialEq> for BoundedVec +where + T: PartialEq, + BoundSelf: Get, + BoundRhs: Get, +{ + fn eq(&self, rhs: &WeakBoundedVec) -> bool { + self.0 == rhs.0 + } +} + +impl<'a, T, BoundSelf, BoundRhs> PartialEq> + for BoundedVec +where + T: PartialEq, + BoundSelf: Get, + BoundRhs: Get, +{ + fn eq(&self, rhs: &BoundedSlice<'a, T, BoundRhs>) -> bool { + self.0 == rhs.0 } } @@ -662,6 +753,46 @@ impl> PartialEq> for BoundedVec { impl> Eq for BoundedVec where T: Eq {} +impl PartialOrd> for BoundedVec +where + T: PartialOrd, + BoundSelf: Get, + BoundRhs: Get, +{ + fn partial_cmp(&self, other: &BoundedVec) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl PartialOrd> for BoundedVec +where + T: PartialOrd, + BoundSelf: Get, + BoundRhs: Get, +{ + fn partial_cmp(&self, other: &WeakBoundedVec) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl<'a, T, BoundSelf, BoundRhs> PartialOrd> + for BoundedVec +where + T: PartialOrd, + BoundSelf: Get, + BoundRhs: Get, +{ + fn partial_cmp(&self, other: &BoundedSlice<'a, T, BoundRhs>) -> Option { + (&*self.0).partial_cmp(other.0) + } +} + +impl> Ord for BoundedVec { + fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + impl MaxEncodedLen for BoundedVec where T: MaxEncodedLen, diff --git a/primitives/runtime/src/bounded/weak_bounded_vec.rs b/primitives/runtime/src/bounded/weak_bounded_vec.rs index 9b88ad27e4287..82bae4118f13e 100644 --- a/primitives/runtime/src/bounded/weak_bounded_vec.rs +++ b/primitives/runtime/src/bounded/weak_bounded_vec.rs @@ -18,6 +18,7 @@ //! Traits, types and structs to support putting a bounded vector into storage, as a raw value, map //! or a double map. +use super::{BoundedSlice, BoundedVec}; use crate::traits::Get; use codec::{Decode, Encode, MaxEncodedLen}; use core::{ @@ -35,7 +36,7 @@ use sp_std::{marker::PhantomData, prelude::*}; /// is accepted, and some method allow to bypass the restriction with warnings. #[derive(Encode, scale_info::TypeInfo)] #[scale_info(skip_type_params(S))] -pub struct WeakBoundedVec(Vec, PhantomData); +pub struct WeakBoundedVec(pub(super) Vec, PhantomData); impl> Decode for WeakBoundedVec { fn decode(input: &mut I) -> Result { @@ -283,14 +284,36 @@ impl codec::DecodeLength for WeakBoundedVec { } } -// NOTE: we could also implement this as: -// impl, S2: Get> PartialEq> for WeakBoundedVec to allow comparison of bounded vectors with different bounds. -impl PartialEq for WeakBoundedVec +impl PartialEq> for WeakBoundedVec where T: PartialEq, + BoundSelf: Get, + BoundRhs: Get, { - fn eq(&self, rhs: &Self) -> bool { + fn eq(&self, rhs: &WeakBoundedVec) -> bool { + self.0 == rhs.0 + } +} + +impl PartialEq> for WeakBoundedVec +where + T: PartialEq, + BoundSelf: Get, + BoundRhs: Get, +{ + fn eq(&self, rhs: &BoundedVec) -> bool { + self.0 == rhs.0 + } +} + +impl<'a, T, BoundSelf, BoundRhs> PartialEq> + for WeakBoundedVec +where + T: PartialEq, + BoundSelf: Get, + BoundRhs: Get, +{ + fn eq(&self, rhs: &BoundedSlice<'a, T, BoundRhs>) -> bool { self.0 == rhs.0 } } @@ -301,7 +324,48 @@ impl> PartialEq> for WeakBoundedVec { } } -impl Eq for WeakBoundedVec where T: Eq {} +impl> Eq for WeakBoundedVec where T: Eq {} + +impl PartialOrd> + for WeakBoundedVec +where + T: PartialOrd, + BoundSelf: Get, + BoundRhs: Get, +{ + fn partial_cmp(&self, other: &WeakBoundedVec) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl PartialOrd> for WeakBoundedVec +where + T: PartialOrd, + BoundSelf: Get, + BoundRhs: Get, +{ + fn partial_cmp(&self, other: &BoundedVec) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl<'a, T, BoundSelf, BoundRhs> PartialOrd> + for WeakBoundedVec +where + T: PartialOrd, + BoundSelf: Get, + BoundRhs: Get, +{ + fn partial_cmp(&self, other: &BoundedSlice<'a, T, BoundRhs>) -> Option { + (&*self.0).partial_cmp(other.0) + } +} + +impl> Ord for WeakBoundedVec { + fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + self.0.cmp(&other.0) + } +} impl MaxEncodedLen for WeakBoundedVec where From 323eecd2de38b9631d9c162997261e43c886828c Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 13 Jun 2022 22:07:36 +0100 Subject: [PATCH 0909/1472] Allow nomination pools to chill + fix dismantle scenario (#11426) * make pool roles optional * undo lock file changes? * add migration * add the ability for pools to chill themselves * boilerplate of tests * somewhat stable, but I think I found another bug as well * Fix it all * Add more more sophisticated test + capture one more bug. * Update frame/staking/src/lib.rs * reduce the diff a little bit * add some test for the slashing bug * cleanup * fix lock file? * Fix * fmt * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/mock.rs Co-authored-by: Oliver Tale-Yazdi * Fix build * fix some fishy tests.. * add one last integrity check for MinCreateBond * remove bad assertion -- needs to be dealt with later * nits * fix tests and add benchmarks for chill * remove stuff * fix benchmarks * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * remove defensive Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi Co-authored-by: Parity Bot --- Cargo.lock | 24 + Cargo.toml | 1 + bin/node/cli/src/chain_spec.rs | 11 +- frame/nomination-pools/Cargo.toml | 3 +- .../nomination-pools/benchmarking/src/lib.rs | 76 +- frame/nomination-pools/src/lib.rs | 153 +++- frame/nomination-pools/src/mock.rs | 64 +- frame/nomination-pools/src/tests.rs | 853 ++++++++---------- frame/nomination-pools/src/weights.rs | 133 ++- .../nomination-pools/test-staking/Cargo.toml | 36 + .../nomination-pools/test-staking/src/lib.rs | 373 ++++++++ .../nomination-pools/test-staking/src/mock.rs | 261 ++++++ frame/staking/src/lib.rs | 8 +- frame/staking/src/pallet/impls.rs | 21 +- frame/staking/src/tests.rs | 19 + frame/support/src/storage/mod.rs | 2 +- frame/support/src/storage/transactional.rs | 6 +- primitives/staking/src/lib.rs | 11 +- 18 files changed, 1427 insertions(+), 628 deletions(-) create mode 100644 frame/nomination-pools/test-staking/Cargo.toml create mode 100644 frame/nomination-pools/test-staking/src/lib.rs create mode 100644 frame/nomination-pools/test-staking/src/mock.rs diff --git a/Cargo.lock b/Cargo.lock index a5e431c7a4aa0..ae0a497867b51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5931,6 +5931,30 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-nomination-pools-test-staking" +version = "1.0.0" +dependencies = [ + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-bags-list", + "pallet-balances", + "pallet-nomination-pools", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", + "sp-tracing", +] + [[package]] name = "pallet-offences" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 7f013c08a9144..9909e6f893877 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -115,6 +115,7 @@ members = [ "frame/proxy", "frame/nomination-pools", "frame/nomination-pools/benchmarking", + "frame/nomination-pools/test-staking", "frame/randomness-collective-flip", "frame/ranked-collective", "frame/recovery", diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 1c7794fd0cde6..47c3634aa00df 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -23,8 +23,9 @@ use hex_literal::hex; use node_runtime::{ constants::currency::*, wasm_binary_unwrap, AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, Block, CouncilConfig, DemocracyConfig, ElectionsConfig, GrandpaConfig, - ImOnlineConfig, IndicesConfig, MaxNominations, SessionConfig, SessionKeys, SocietyConfig, - StakerStatus, StakingConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, + ImOnlineConfig, IndicesConfig, MaxNominations, NominationPoolsConfig, SessionConfig, + SessionKeys, SocietyConfig, StakerStatus, StakingConfig, SudoConfig, SystemConfig, + TechnicalCommitteeConfig, }; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use sc_chain_spec::ChainSpecExtension; @@ -365,7 +366,11 @@ pub fn testnet_genesis( transaction_payment: Default::default(), alliance: Default::default(), alliance_motion: Default::default(), - nomination_pools: Default::default(), + nomination_pools: NominationPoolsConfig { + min_create_bond: 10 * DOLLARS, + min_join_bond: 1 * DOLLARS, + ..Default::default() + }, } } diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index 0820125d77f44..be5c38d85552c 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -23,11 +23,11 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } log = { version = "0.4.0", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } [features] @@ -41,6 +41,7 @@ std = [ "frame-system/std", "sp-runtime/std", "sp-std/std", + "sp-io/std", "sp-staking/std", "sp-core/std", "log/std", diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 275b914cda297..4c2c902846a85 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -24,7 +24,7 @@ mod mock; use frame_benchmarking::{account, frame_support::traits::Currency, vec, whitelist_account, Vec}; use frame_election_provider_support::SortedListProvider; -use frame_support::{ensure, traits::Get}; +use frame_support::{assert_ok, ensure, traits::Get}; use frame_system::RawOrigin as Origin; use pallet_nomination_pools::{ BalanceOf, BondExtra, BondedPoolInner, BondedPools, ConfigOp, MaxPoolMembers, @@ -48,6 +48,12 @@ pub trait Config: pub struct Pallet(Pools); +fn min_create_bond() -> BalanceOf { + MinCreateBond::::get() + .max(T::StakingInterface::minimum_bond()) + .max(CurrencyOf::::minimum_balance()) +} + fn create_funded_user_with_balance( string: &'static str, n: u32, @@ -209,9 +215,7 @@ impl ListScenario { frame_benchmarking::benchmarks! { join { - let origin_weight = pallet_nomination_pools::MinCreateBond::::get() - .max(CurrencyOf::::minimum_balance()) - * 2u32.into(); + let origin_weight = min_create_bond::() * 2u32.into(); // setup the worst case list scenario. let scenario = ListScenario::::new(origin_weight, true)?; @@ -237,9 +241,7 @@ frame_benchmarking::benchmarks! { } bond_extra_transfer { - let origin_weight = pallet_nomination_pools::MinCreateBond::::get() - .max(CurrencyOf::::minimum_balance()) - * 2u32.into(); + let origin_weight = min_create_bond::() * 2u32.into(); let scenario = ListScenario::::new(origin_weight, true)?; let extra = scenario.dest_weight.clone() - origin_weight; @@ -254,9 +256,7 @@ frame_benchmarking::benchmarks! { } bond_extra_reward { - let origin_weight = pallet_nomination_pools::MinCreateBond::::get() - .max(CurrencyOf::::minimum_balance()) - * 2u32.into(); + let origin_weight = min_create_bond::() * 2u32.into(); let scenario = ListScenario::::new(origin_weight, true)?; let extra = (scenario.dest_weight.clone() - origin_weight).max(CurrencyOf::::minimum_balance()); @@ -274,7 +274,7 @@ frame_benchmarking::benchmarks! { } claim_payout { - let origin_weight = pallet_nomination_pools::MinCreateBond::::get().max(CurrencyOf::::minimum_balance()) * 2u32.into(); + let origin_weight = min_create_bond::() * 2u32.into(); let ed = CurrencyOf::::minimum_balance(); let (depositor, pool_account) = create_pool_account::(0, origin_weight); let reward_account = Pools::::create_reward_account(1); @@ -304,9 +304,7 @@ frame_benchmarking::benchmarks! { unbond { // The weight the nominator will start at. The value used here is expected to be // significantly higher than the first position in a list (e.g. the first bag threshold). - let origin_weight = BalanceOf::::try_from(952_994_955_240_703u128) - .map_err(|_| "balance expected to be a u128") - .unwrap(); + let origin_weight = min_create_bond::() * 200u32.into(); let scenario = ListScenario::::new(origin_weight, false)?; let amount = origin_weight - scenario.dest_weight.clone(); @@ -336,9 +334,7 @@ frame_benchmarking::benchmarks! { pool_withdraw_unbonded { let s in 0 .. MAX_SPANS; - let min_create_bond = MinCreateBond::::get() - .max(T::StakingInterface::minimum_bond()) - .max(CurrencyOf::::minimum_balance()); + let min_create_bond = min_create_bond::(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); // Add a new member @@ -380,9 +376,7 @@ frame_benchmarking::benchmarks! { withdraw_unbonded_update { let s in 0 .. MAX_SPANS; - let min_create_bond = MinCreateBond::::get() - .max(T::StakingInterface::minimum_bond()) - .max(CurrencyOf::::minimum_balance()); + let min_create_bond = min_create_bond::(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); // Add a new member @@ -427,10 +421,7 @@ frame_benchmarking::benchmarks! { withdraw_unbonded_kill { let s in 0 .. MAX_SPANS; - let min_create_bond = MinCreateBond::::get() - .max(T::StakingInterface::minimum_bond()) - .max(CurrencyOf::::minimum_balance()); - + let min_create_bond = min_create_bond::(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); // We set the pool to the destroying state so the depositor can leave @@ -494,9 +485,7 @@ frame_benchmarking::benchmarks! { } create { - let min_create_bond = MinCreateBond::::get() - .max(T::StakingInterface::minimum_bond()) - .max(CurrencyOf::::minimum_balance()); + let min_create_bond = min_create_bond::(); let depositor: T::AccountId = account("depositor", USER_SEED, 0); // Give the depositor some balance to bond @@ -542,9 +531,7 @@ frame_benchmarking::benchmarks! { let n in 1 .. T::MaxNominations::get(); // Create a pool - let min_create_bond = MinCreateBond::::get() - .max(T::StakingInterface::minimum_bond()) - .max(CurrencyOf::::minimum_balance()); + let min_create_bond = min_create_bond::() * 2u32.into(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); // Create some accounts to nominate. For the sake of benchmarking they don't need to be @@ -581,9 +568,7 @@ frame_benchmarking::benchmarks! { set_state { // Create a pool - let min_create_bond = MinCreateBond::::get() - .max(T::StakingInterface::minimum_bond()) - .max(CurrencyOf::::minimum_balance()); + let min_create_bond = min_create_bond::(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); BondedPools::::mutate(&1, |maybe_pool| { // Force the pool into an invalid state @@ -601,10 +586,7 @@ frame_benchmarking::benchmarks! { let n in 1 .. ::MaxMetadataLen::get(); // Create a pool - let min_create_bond = MinCreateBond::::get() - .max(T::StakingInterface::minimum_bond()) - .max(CurrencyOf::::minimum_balance()); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond::() * 2u32.into()); // Create metadata of the max possible size let metadata: Vec = (0..n).map(|_| 42).collect(); @@ -633,7 +615,7 @@ frame_benchmarking::benchmarks! { update_roles { let first_id = pallet_nomination_pools::LastPoolId::::get() + 1; - let (root, _) = create_pool_account::(0, CurrencyOf::::minimum_balance() * 2u32.into()); + let (root, _) = create_pool_account::(0, min_create_bond::() * 2u32.into()); let random: T::AccountId = account("but is anything really random in computers..?", 0, USER_SEED); }:_( Origin::Signed(root.clone()), @@ -653,6 +635,24 @@ frame_benchmarking::benchmarks! { ) } + chill { + // Create a pool + let (depositor, pool_account) = create_pool_account::(0, min_create_bond::() * 2u32.into()); + + // Nominate with the pool. + let validators: Vec<_> = (0..T::MaxNominations::get()) + .map(|i| account("stash", USER_SEED, i)) + .collect(); + + assert_ok!(Pools::::nominate(Origin::Signed(depositor.clone()).into(), 1, validators)); + assert!(T::StakingInterface::nominations(Pools::::create_bonded_account(1)).is_some()); + + whitelist_account!(depositor); + }:_(Origin::Signed(depositor.clone()), 1) + verify { + assert!(T::StakingInterface::nominations(Pools::::create_bonded_account(1)).is_none()); + } + impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext(), diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index dc40a6a7d41fd..19155a51405b0 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -447,21 +447,27 @@ impl PoolMember { .fold(BalanceOf::::zero(), |acc, (_, v)| acc.saturating_add(*v)) } - /// Try and unbond `points` from self, with the given target unbonding era. + /// Try and unbond `points_dissolved` from self, and in return mint `points_issued` into the + /// corresponding `era`'s unlock schedule. + /// + /// In the absence of slashing, these two points are always the same. In the presence of + /// slashing, the value of points in different pools varies. /// /// Returns `Ok(())` and updates `unbonding_eras` and `points` if success, `Err(_)` otherwise. fn try_unbond( &mut self, - points: BalanceOf, + points_dissolved: BalanceOf, + points_issued: BalanceOf, unbonding_era: EraIndex, ) -> Result<(), Error> { - if let Some(new_points) = self.points.checked_sub(&points) { + if let Some(new_points) = self.points.checked_sub(&points_dissolved) { match self.unbonding_eras.get_mut(&unbonding_era) { Some(already_unbonding_points) => - *already_unbonding_points = already_unbonding_points.saturating_add(points), + *already_unbonding_points = + already_unbonding_points.saturating_add(points_issued), None => self .unbonding_eras - .try_insert(unbonding_era, points) + .try_insert(unbonding_era, points_issued) .map(|old| { if old.is_some() { defensive!("value checked to not exist in the map; qed"); @@ -721,9 +727,13 @@ impl BondedPool { } fn is_destroying_and_only_depositor(&self, alleged_depositor_points: BalanceOf) -> bool { - // NOTE: if we add `&& self.member_counter == 1`, then this becomes even more strict and - // ensures that there are no unbonding members hanging around either. - self.is_destroying() && self.points == alleged_depositor_points + // we need to ensure that `self.member_counter == 1` as well, because the depositor's + // initial `MinCreateBond` (or more) is what guarantees that the ledger of the pool does not + // get killed in the staking system, and that it does not fall below `MinimumNominatorBond`, + // which could prevent other non-depositor members from fully leaving. Thus, all members + // must withdraw, then depositor can unbond, and finally withdraw after waiting another + // cycle. + self.is_destroying() && self.points == alleged_depositor_points && self.member_counter == 1 } /// Whether or not the pool is ok to be in `PoolSate::Open`. If this returns an `Err`, then the @@ -984,10 +994,14 @@ impl UnbondPool { Pallet::::point_to_balance(self.balance, self.points, points) } - /// Issue points and update the balance given `new_balance`. - fn issue(&mut self, new_funds: BalanceOf) { - self.points = self.points.saturating_add(self.balance_to_point(new_funds)); + /// Issue the equivalent points of `new_funds` into self. + /// + /// Returns the actual amounts of points issued. + fn issue(&mut self, new_funds: BalanceOf) -> BalanceOf { + let new_points = self.balance_to_point(new_funds); + self.points = self.points.saturating_add(new_points); self.balance = self.balance.saturating_add(new_funds); + new_points } /// Dissolve some points from the unbonding pool, reducing the balance of the pool @@ -1150,6 +1164,9 @@ pub mod pallet { /// /// This is the amount that the depositor must put as their initial stake in the pool, as an /// indication of "skin in the game". + /// + /// This is the value that will always exist in the staking ledger of the pool bonded account + /// while all other accounts leave. #[pallet::storage] pub type MinCreateBond = StorageValue<_, BalanceOf, ValueQuery>; @@ -1256,9 +1273,34 @@ pub mod pallet { /// A payout has been made to a member. PaidOut { member: T::AccountId, pool_id: PoolId, payout: BalanceOf }, /// A member has unbonded from their pool. - Unbonded { member: T::AccountId, pool_id: PoolId, amount: BalanceOf }, + /// + /// - `balance` is the corresponding balance of the number of points that has been + /// requested to be unbonded (the argument of the `unbond` transaction) from the bonded + /// pool. + /// - `points` is the number of points that are issued as a result of `balance` being + /// dissolved into the corresponding unbonding pool. + /// + /// In the absence of slashing, these values will match. In the presence of slashing, the + /// number of points that are issued in the unbonding pool will be less than the amount + /// requested to be unbonded. + Unbonded { + member: T::AccountId, + pool_id: PoolId, + balance: BalanceOf, + points: BalanceOf, + }, /// A member has withdrawn from their pool. - Withdrawn { member: T::AccountId, pool_id: PoolId, amount: BalanceOf }, + /// + /// The given number of `points` have been dissolved in return of `balance`. + /// + /// Similar to `Unbonded` event, in the absence of slashing, the ratio of point to balance + /// will be 1. + Withdrawn { + member: T::AccountId, + pool_id: PoolId, + balance: BalanceOf, + points: BalanceOf, + }, /// A pool has been destroyed. Destroyed { pool_id: PoolId }, /// The state of a pool has changed @@ -1274,6 +1316,10 @@ pub mod pallet { state_toggler: Option, nominator: Option, }, + /// The active balance of pool `pool_id` has been slashed to `balance`. + PoolSlashed { pool_id: PoolId, balance: BalanceOf }, + /// The unbond pool at `era` of pool `pool_id` has been slashed to `balance`. + UnbondingPoolSlashed { pool_id: PoolId, era: EraIndex, balance: BalanceOf }, } #[pallet::error] @@ -1290,10 +1336,6 @@ pub mod pallet { /// An account is already delegating in another pool. An account may only belong to one /// pool at a time. AccountBelongsToOtherPool, - /// The pool has insufficient balance to bond as a nominator. - InsufficientBond, - /// The member is already unbonding in this era. - AlreadyUnbonding, /// The member is fully unbonded (and thus cannot access the bonded and reward pool /// anymore to, for example, collect rewards). FullyUnbonding, @@ -1346,6 +1388,9 @@ pub mod pallet { RewardPoolNotFound, /// A sub pool does not exist. SubPoolsNotFound, + /// The bonded account should only be killed by the staking system when the depositor is + /// withdrawing + BondedStashKilledPrematurely, } impl From for Error { @@ -1477,7 +1522,7 @@ pub mod pallet { /// Unbond up to `unbonding_points` of the `member_account`'s funds from the pool. It /// implicitly collects the rewards one last time, since not doing so would mean some - /// rewards would go forfeited. + /// rewards would be forfeited. /// /// Under certain conditions, this call can be dispatched permissionlessly (i.e. by any /// account). @@ -1528,9 +1573,6 @@ pub mod pallet { let current_era = T::StakingInterface::current_era(); let unbond_era = T::StakingInterface::bonding_duration().saturating_add(current_era); - // Try and unbond in the member map. - member.try_unbond(unbonding_points, unbond_era)?; - // Unbond in the actual underlying nominator. let unbonding_balance = bonded_pool.dissolve(unbonding_points); T::StakingInterface::unbond(bonded_pool.bonded_account(), unbonding_balance)?; @@ -1553,17 +1595,21 @@ pub mod pallet { })?; } - sub_pools + let points_unbonded = sub_pools .with_era .get_mut(&unbond_era) // The above check ensures the pool exists. .defensive_ok_or::>(DefensiveError::PoolNotFound.into())? .issue(unbonding_balance); + // Try and unbond in the member map. + member.try_unbond(unbonding_points, points_unbonded, unbond_era)?; + Self::deposit_event(Event::::Unbonded { member: member_account.clone(), pool_id: member.pool_id, - amount: unbonding_balance, + points: points_unbonded, + balance: unbonding_balance, }); // Now that we know everything has worked write the items to storage. @@ -1644,14 +1690,23 @@ pub mod pallet { // Before calculate the `balance_to_unbond`, with call withdraw unbonded to ensure the // `transferrable_balance` is correct. - T::StakingInterface::withdraw_unbonded( + let stash_killed = T::StakingInterface::withdraw_unbonded( bonded_pool.bonded_account(), num_slashing_spans, )?; + // defensive-only: the depositor puts enough funds into the stash so that it will only + // be destroyed when they are leaving. + ensure!( + !stash_killed || caller == bonded_pool.roles.depositor, + Error::::Defensive(DefensiveError::BondedStashKilledPrematurely) + ); + + let mut sum_unlocked_points: BalanceOf = Zero::zero(); let balance_to_unbond = withdrawn_points .iter() .fold(BalanceOf::::zero(), |accumulator, (era, unlocked_points)| { + sum_unlocked_points = sum_unlocked_points.saturating_add(*unlocked_points); if let Some(era_pool) = sub_pools.with_era.get_mut(&era) { let balance_to_unbond = era_pool.dissolve(*unlocked_points); if era_pool.points.is_zero() { @@ -1684,7 +1739,8 @@ pub mod pallet { Self::deposit_event(Event::::Withdrawn { member: member_account.clone(), pool_id: member.pool_id, - amount: balance_to_unbond, + points: sum_unlocked_points, + balance: balance_to_unbond, }); let post_info_weight = if member.total_points().is_zero() { @@ -1811,6 +1867,13 @@ pub mod pallet { Ok(()) } + /// Nominate on behalf of the pool. + /// + /// The dispatch origin of this call must be signed by the pool nominator or the pool + /// root role. + /// + /// This directly forward the call to the staking pallet, on behalf of the pool bonded + /// account. #[pallet::weight(T::WeightInfo::nominate(validators.len() as u32))] pub fn nominate( origin: OriginFor, @@ -1820,10 +1883,13 @@ pub mod pallet { let who = ensure_signed(origin)?; let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); - T::StakingInterface::nominate(bonded_pool.bonded_account(), validators)?; - Ok(()) + T::StakingInterface::nominate(bonded_pool.bonded_account(), validators) } + /// Set a new state for the pool. + /// + /// The dispatch origin of this call must be signed by the state toggler, or the root role + /// of the pool. #[pallet::weight(T::WeightInfo::set_state())] pub fn set_state( origin: OriginFor, @@ -1850,6 +1916,10 @@ pub mod pallet { Ok(()) } + /// Set a new metadata for the pool. + /// + /// The dispatch origin of this call must be signed by the state toggler, or the root role + /// of the pool. #[pallet::weight(T::WeightInfo::set_metadata(metadata.len() as u32))] pub fn set_metadata( origin: OriginFor, @@ -1961,6 +2031,21 @@ pub mod pallet { bonded_pool.put(); Ok(()) } + + /// Chill on behalf of the pool. + /// + /// The dispatch origin of this call must be signed by the pool nominator or the pool + /// root role, same as [`Pallet::nominate`]. + /// + /// This directly forward the call to the staking pallet, on behalf of the pool bonded + /// account. + #[pallet::weight(T::WeightInfo::chill())] + pub fn chill(origin: OriginFor, pool_id: PoolId) -> DispatchResult { + let who = ensure_signed(origin)?; + let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); + T::StakingInterface::chill(bonded_pool.bonded_account()) + } } #[pallet::hooks] @@ -2175,6 +2260,7 @@ impl Pallet { if reward_pool.total_earnings == BalanceOf::::max_value() { bonded_pool.set_state(PoolState::Destroying); }; + member.reward_pool_total_earnings = reward_pool.total_earnings; reward_pool.points = current_points.saturating_sub(member_virtual_points); reward_pool.balance = reward_pool.balance.saturating_sub(member_payout); @@ -2355,19 +2441,26 @@ impl OnStakerSlash> for Pallet { pool_account: &T::AccountId, // Bonded balance is always read directly from staking, therefore we need not update // anything here. - _slashed_bonded: BalanceOf, + slashed_bonded: BalanceOf, slashed_unlocking: &BTreeMap>, ) { - if let Some(pool_id) = ReversePoolIdLookup::::get(pool_account).defensive() { + if let Some(pool_id) = ReversePoolIdLookup::::get(pool_account) { let mut sub_pools = match SubPoolsStorage::::get(pool_id).defensive() { Some(sub_pools) => sub_pools, None => return, }; for (era, slashed_balance) in slashed_unlocking.iter() { if let Some(pool) = sub_pools.with_era.get_mut(era) { - pool.balance = *slashed_balance + pool.balance = *slashed_balance; + Self::deposit_event(Event::::UnbondingPoolSlashed { + era: *era, + pool_id, + balance: *slashed_balance, + }); } } + + Self::deposit_event(Event::::PoolSlashed { pool_id, balance: slashed_bonded }); SubPoolsStorage::::insert(pool_id, sub_pools); } } diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 1dadd7e00c528..a3020e5add044 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -2,7 +2,6 @@ use super::*; use crate::{self as pools}; use frame_support::{assert_ok, parameter_types, PalletId}; use frame_system::RawOrigin; -use std::collections::HashMap; pub type AccountId = u128; pub type Balance = u128; @@ -20,17 +19,19 @@ pub fn default_reward_account() -> AccountId { parameter_types! { pub static CurrentEra: EraIndex = 0; pub static BondingDuration: EraIndex = 3; - static BondedBalanceMap: HashMap = Default::default(); - static UnbondingBalanceMap: HashMap = Default::default(); + pub storage BondedBalanceMap: BTreeMap = Default::default(); + pub storage UnbondingBalanceMap: BTreeMap = Default::default(); #[derive(Clone, PartialEq)] pub static MaxUnbonding: u32 = 8; - pub static Nominations: Vec = vec![]; + pub storage Nominations: Option> = None; } pub struct StakingMock; impl StakingMock { pub(crate) fn set_bonded_balance(who: AccountId, bonded: Balance) { - BONDED_BALANCE_MAP.with(|m| m.borrow_mut().insert(who, bonded)); + let mut x = BondedBalanceMap::get(); + x.insert(who, bonded); + BondedBalanceMap::set(&x) } } @@ -66,22 +67,33 @@ impl sp_staking::StakingInterface for StakingMock { } fn bond_extra(who: Self::AccountId, extra: Self::Balance) -> DispatchResult { - BONDED_BALANCE_MAP.with(|m| *m.borrow_mut().get_mut(&who).unwrap() += extra); + let mut x = BondedBalanceMap::get(); + x.get_mut(&who).map(|v| *v += extra); + BondedBalanceMap::set(&x); Ok(()) } fn unbond(who: Self::AccountId, amount: Self::Balance) -> DispatchResult { - BONDED_BALANCE_MAP.with(|m| *m.borrow_mut().get_mut(&who).unwrap() -= amount); - UNBONDING_BALANCE_MAP - .with(|m| *m.borrow_mut().entry(who).or_insert(Self::Balance::zero()) += amount); + let mut x = BondedBalanceMap::get(); + *x.get_mut(&who).unwrap() = x.get_mut(&who).unwrap().saturating_sub(amount); + BondedBalanceMap::set(&x); + let mut y = UnbondingBalanceMap::get(); + *y.entry(who).or_insert(Self::Balance::zero()) += amount; + UnbondingBalanceMap::set(&y); Ok(()) } - fn withdraw_unbonded(who: Self::AccountId, _: u32) -> Result { + fn chill(_: Self::AccountId) -> sp_runtime::DispatchResult { + Ok(()) + } + + fn withdraw_unbonded(who: Self::AccountId, _: u32) -> Result { // Simulates removing unlocking chunks and only having the bonded balance locked - let _maybe_new_free = UNBONDING_BALANCE_MAP.with(|m| m.borrow_mut().remove(&who)); + let mut x = UnbondingBalanceMap::get(); + x.remove(&who); + UnbondingBalanceMap::set(&x); - Ok(100) + Ok(UnbondingBalanceMap::get().is_empty() && BondedBalanceMap::get().is_empty()) } fn bond( @@ -95,9 +107,13 @@ impl sp_staking::StakingInterface for StakingMock { } fn nominate(_: Self::AccountId, nominations: Vec) -> DispatchResult { - Nominations::set(nominations); + Nominations::set(&Some(nominations)); Ok(()) } + + fn nominations(_: Self::AccountId) -> Option> { + Nominations::get() + } } impl frame_system::Config for Runtime { @@ -162,7 +178,6 @@ parameter_types! { pub static MaxMetadataLen: u32 = 2; pub static CheckLevel: u8 = 255; pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); - pub const MinPointsToBalance: u32 = 10; } impl pools::Config for Runtime { type Event = Event; @@ -175,7 +190,7 @@ impl pools::Config for Runtime { type PalletId = PoolsPalletId; type MaxMetadataLen = MaxMetadataLen; type MaxUnbonding = MaxUnbonding; - type MinPointsToBalance = MinPointsToBalance; + type MinPointsToBalance = frame_support::traits::ConstU32<10>; } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -265,7 +280,8 @@ pub(crate) fn unsafe_set_state(pool_id: PoolId, state: PoolState) -> Result<(), } parameter_types! { - static ObservedEvents: usize = 0; + static PoolsEvents: usize = 0; + static BalancesEvents: usize = 0; } /// All events of this pallet. @@ -275,8 +291,20 @@ pub(crate) fn pool_events_since_last_call() -> Vec> { .map(|r| r.event) .filter_map(|e| if let Event::Pools(inner) = e { Some(inner) } else { None }) .collect::>(); - let already_seen = ObservedEvents::get(); - ObservedEvents::set(events.len()); + let already_seen = PoolsEvents::get(); + PoolsEvents::set(events.len()); + events.into_iter().skip(already_seen).collect() +} + +/// All events of the `Balances` pallet. +pub(crate) fn balances_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let Event::Balances(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = BalancesEvents::get(); + BalancesEvents::set(events.len()); events.into_iter().skip(already_seen).collect() } diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 93218c78c83fc..97104423c5910 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -18,9 +18,10 @@ use super::*; use crate::{mock::*, Event}; use frame_support::{ - assert_noop, assert_ok, assert_storage_noop, bounded_btree_map, + assert_err, assert_noop, assert_ok, assert_storage_noop, bounded_btree_map, storage::{with_transaction, TransactionOutcome}, }; +use pallet_balances::Event as BEvent; use sp_runtime::traits::Dispatchable; macro_rules! unbonding_pools_with_era { @@ -65,7 +66,7 @@ fn test_setup_works() { ); assert_eq!( RewardPools::::get(last_pool).unwrap(), - RewardPool:: { balance: 0, points: 0.into(), total_earnings: 0 } + RewardPool:: { balance: 0, points: 0u32.into(), total_earnings: 0 } ); assert_eq!( PoolMembers::::get(10).unwrap(), @@ -80,7 +81,7 @@ fn test_setup_works() { assert_eq!(StakingMock::total_stake(&bonded_account).unwrap(), 10); // but not nominating yet. - assert!(Nominations::get().is_empty()); + assert!(Nominations::get().is_none()); // reward account should have an initial ED in it. assert_eq!(Balances::free_balance(&reward_account), Balances::minimum_balance()); @@ -90,101 +91,106 @@ fn test_setup_works() { mod bonded_pool { use super::*; #[test] - fn points_to_issue_works() { - let mut bonded_pool = BondedPool:: { - id: 123123, - inner: BondedPoolInner { - state: PoolState::Open, - points: 100, - member_counter: 1, - roles: DEFAULT_ROLES, - }, - }; + fn balance_to_point_works() { + ExtBuilder::default().build_and_execute(|| { + let mut bonded_pool = BondedPool:: { + id: 123123, + inner: BondedPoolInner { + state: PoolState::Open, + points: 100, + member_counter: 1, + roles: DEFAULT_ROLES, + }, + }; - // 1 points : 1 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); - assert_eq!(bonded_pool.balance_to_point(10), 10); - assert_eq!(bonded_pool.balance_to_point(0), 0); - - // 2 points : 1 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 50); - assert_eq!(bonded_pool.balance_to_point(10), 20); - - // 1 points : 2 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); - bonded_pool.points = 50; - assert_eq!(bonded_pool.balance_to_point(10), 5); - - // 100 points : 0 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); - bonded_pool.points = 100; - assert_eq!(bonded_pool.balance_to_point(10), 100 * 10); - - // 0 points : 100 balance - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); - bonded_pool.points = 100; - assert_eq!(bonded_pool.balance_to_point(10), 10); - - // 10 points : 3 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 30); - assert_eq!(bonded_pool.balance_to_point(10), 33); - - // 2 points : 3 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 300); - bonded_pool.points = 200; - assert_eq!(bonded_pool.balance_to_point(10), 6); - - // 4 points : 9 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 900); - bonded_pool.points = 400; - assert_eq!(bonded_pool.balance_to_point(90), 40); - } + // 1 points : 1 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + assert_eq!(bonded_pool.balance_to_point(10), 10); + assert_eq!(bonded_pool.balance_to_point(0), 0); - #[test] - fn balance_to_unbond_works() { - // 1 balance : 1 points ratio - let mut bonded_pool = BondedPool:: { - id: 123123, - inner: BondedPoolInner { - state: PoolState::Open, - points: 100, - member_counter: 1, - roles: DEFAULT_ROLES, - }, - }; + // 2 points : 1 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 50); + assert_eq!(bonded_pool.balance_to_point(10), 20); - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); - assert_eq!(bonded_pool.points_to_balance(10), 10); - assert_eq!(bonded_pool.points_to_balance(0), 0); + // 1 points : 2 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + bonded_pool.points = 50; + assert_eq!(bonded_pool.balance_to_point(10), 5); - // 2 balance : 1 points ratio - bonded_pool.points = 50; - assert_eq!(bonded_pool.points_to_balance(10), 20); + // 100 points : 0 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); + bonded_pool.points = 100; + assert_eq!(bonded_pool.balance_to_point(10), 100 * 10); - // 100 balance : 0 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); - bonded_pool.points = 0; - assert_eq!(bonded_pool.points_to_balance(10), 0); + // 0 points : 100 balance + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + bonded_pool.points = 0; + assert_eq!(bonded_pool.balance_to_point(10), 10); - // 0 balance : 100 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); - bonded_pool.points = 100; - assert_eq!(bonded_pool.points_to_balance(10), 0); + // 10 points : 3 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 30); + bonded_pool.points = 100; + assert_eq!(bonded_pool.balance_to_point(10), 33); - // 10 balance : 3 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); - bonded_pool.points = 30; - assert_eq!(bonded_pool.points_to_balance(10), 33); + // 2 points : 3 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 300); + bonded_pool.points = 200; + assert_eq!(bonded_pool.balance_to_point(10), 6); - // 2 balance : 3 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 200); - bonded_pool.points = 300; - assert_eq!(bonded_pool.points_to_balance(10), 6); + // 4 points : 9 balance ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 900); + bonded_pool.points = 400; + assert_eq!(bonded_pool.balance_to_point(90), 40); + }) + } - // 4 balance : 9 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 400); - bonded_pool.points = 900; - assert_eq!(bonded_pool.points_to_balance(90), 40); + #[test] + fn points_to_balance_works() { + ExtBuilder::default().build_and_execute(|| { + // 1 balance : 1 points ratio + let mut bonded_pool = BondedPool:: { + id: 123123, + inner: BondedPoolInner { + state: PoolState::Open, + points: 100, + member_counter: 1, + roles: DEFAULT_ROLES, + }, + }; + + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + assert_eq!(bonded_pool.points_to_balance(10), 10); + assert_eq!(bonded_pool.points_to_balance(0), 0); + + // 2 balance : 1 points ratio + bonded_pool.points = 50; + assert_eq!(bonded_pool.points_to_balance(10), 20); + + // 100 balance : 0 points ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + bonded_pool.points = 0; + assert_eq!(bonded_pool.points_to_balance(10), 0); + + // 0 balance : 100 points ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); + bonded_pool.points = 100; + assert_eq!(bonded_pool.points_to_balance(10), 0); + + // 10 balance : 3 points ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + bonded_pool.points = 30; + assert_eq!(bonded_pool.points_to_balance(10), 33); + + // 2 balance : 3 points ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 200); + bonded_pool.points = 300; + assert_eq!(bonded_pool.points_to_balance(10), 6); + + // 4 balance : 9 points ratio + StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 400); + bonded_pool.points = 900; + assert_eq!(bonded_pool.points_to_balance(90), 40); + }) } #[test] @@ -200,7 +206,8 @@ mod bonded_pool { }, }; - let min_points_to_balance: u128 = MinPointsToBalance::get().into(); + let min_points_to_balance: u128 = + <::MinPointsToBalance as Get>::get().into(); // Simulate a 100% slashed pool StakingMock::set_bonded_balance(pool.bonded_account(), 0); @@ -267,38 +274,40 @@ mod unbond_pool { #[test] fn points_to_issue_works() { - // 1 points : 1 balance ratio - let unbond_pool = UnbondPool:: { points: 100, balance: 100 }; - assert_eq!(unbond_pool.balance_to_point(10), 10); - assert_eq!(unbond_pool.balance_to_point(0), 0); - - // 2 points : 1 balance ratio - let unbond_pool = UnbondPool:: { points: 100, balance: 50 }; - assert_eq!(unbond_pool.balance_to_point(10), 20); - - // 1 points : 2 balance ratio - let unbond_pool = UnbondPool:: { points: 50, balance: 100 }; - assert_eq!(unbond_pool.balance_to_point(10), 5); - - // 100 points : 0 balance ratio - let unbond_pool = UnbondPool:: { points: 100, balance: 0 }; - assert_eq!(unbond_pool.balance_to_point(10), 100 * 10); - - // 0 points : 100 balance - let unbond_pool = UnbondPool:: { points: 0, balance: 100 }; - assert_eq!(unbond_pool.balance_to_point(10), 10); - - // 10 points : 3 balance ratio - let unbond_pool = UnbondPool:: { points: 100, balance: 30 }; - assert_eq!(unbond_pool.balance_to_point(10), 33); - - // 2 points : 3 balance ratio - let unbond_pool = UnbondPool:: { points: 200, balance: 300 }; - assert_eq!(unbond_pool.balance_to_point(10), 6); - - // 4 points : 9 balance ratio - let unbond_pool = UnbondPool:: { points: 400, balance: 900 }; - assert_eq!(unbond_pool.balance_to_point(90), 40); + ExtBuilder::default().build_and_execute(|| { + // 1 points : 1 balance ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 100 }; + assert_eq!(unbond_pool.balance_to_point(10), 10); + assert_eq!(unbond_pool.balance_to_point(0), 0); + + // 2 points : 1 balance ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 50 }; + assert_eq!(unbond_pool.balance_to_point(10), 20); + + // 1 points : 2 balance ratio + let unbond_pool = UnbondPool:: { points: 50, balance: 100 }; + assert_eq!(unbond_pool.balance_to_point(10), 5); + + // 100 points : 0 balance ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 0 }; + assert_eq!(unbond_pool.balance_to_point(10), 100 * 10); + + // 0 points : 100 balance + let unbond_pool = UnbondPool:: { points: 0, balance: 100 }; + assert_eq!(unbond_pool.balance_to_point(10), 10); + + // 10 points : 3 balance ratio + let unbond_pool = UnbondPool:: { points: 100, balance: 30 }; + assert_eq!(unbond_pool.balance_to_point(10), 33); + + // 2 points : 3 balance ratio + let unbond_pool = UnbondPool:: { points: 200, balance: 300 }; + assert_eq!(unbond_pool.balance_to_point(10), 6); + + // 4 points : 9 balance ratio + let unbond_pool = UnbondPool:: { points: 400, balance: 900 }; + assert_eq!(unbond_pool.balance_to_point(90), 40); + }) } #[test] @@ -516,7 +525,8 @@ mod join { ); // Force the points:balance ratio to `MinPointsToBalance` (100/10) - let min_points_to_balance: u128 = MinPointsToBalance::get().into(); + let min_points_to_balance: u128 = + <::MinPointsToBalance as Get>::get().into(); StakingMock::set_bonded_balance( Pools::create_bonded_account(123), @@ -972,7 +982,7 @@ mod claim_payout { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 11, pool_id: 1, bonded: 11, joined: true }, - Event::Unbonded { member: 11, pool_id: 1, amount: 11 } + Event::Unbonded { member: 11, pool_id: 1, points: 11, balance: 11 } ] ); }); @@ -1614,14 +1624,14 @@ mod unbond { Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, Event::PaidOut { member: 40, pool_id: 1, payout: 40 }, - Event::Unbonded { member: 40, pool_id: 1, amount: 6 } + Event::Unbonded { member: 40, pool_id: 1, points: 6, balance: 6 } ] ); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 94); assert_eq!( PoolMembers::::get(40).unwrap().unbonding_eras, - member_unbonding_eras!(0 + 3 => 40) + member_unbonding_eras!(0 + 3 => 6) ); assert_eq!(Balances::free_balance(&40), 40 + 40); // We claim rewards when unbonding @@ -1649,24 +1659,27 @@ mod unbond { assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 2); assert_eq!( PoolMembers::::get(550).unwrap().unbonding_eras, - member_unbonding_eras!(0 + 3 => 550) + member_unbonding_eras!(0 + 3 => 92) ); assert_eq!(Balances::free_balance(&550), 550 + 550); assert_eq!( pool_events_since_last_call(), vec![ Event::PaidOut { member: 550, pool_id: 1, payout: 550 }, - Event::Unbonded { member: 550, pool_id: 1, amount: 92 } + Event::Unbonded { member: 550, pool_id: 1, points: 92, balance: 92 } ] ); // When + CurrentEra::set(3); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 40, 0)); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 550, 0)); assert_ok!(fully_unbond_permissioned(10)); // Then assert_eq!( SubPoolsStorage::::get(1).unwrap().with_era, - unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 100, balance: 100 }} + unbonding_pools_with_era! { 6 => UnbondPool { points: 2, balance: 2 }} ); assert_eq!( BondedPool::::get(1).unwrap(), @@ -1675,22 +1688,23 @@ mod unbond { inner: BondedPoolInner { state: PoolState::Destroying, points: 0, - member_counter: 3, + member_counter: 1, roles: DEFAULT_ROLES } } ); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 0); - assert_eq!( - PoolMembers::::get(550).unwrap().unbonding_eras, - member_unbonding_eras!(0 + 3 => 550) - ); - assert_eq!(Balances::free_balance(&550), 550 + 550); + + assert_eq!(Balances::free_balance(&550), 550 + 550 + 92); assert_eq!( pool_events_since_last_call(), vec![ + Event::Withdrawn { member: 40, pool_id: 1, points: 6, balance: 6 }, + Event::MemberRemoved { pool_id: 1, member: 40 }, + Event::Withdrawn { member: 550, pool_id: 1, points: 92, balance: 92 }, + Event::MemberRemoved { pool_id: 1, member: 550 }, Event::PaidOut { member: 10, pool_id: 1, payout: 10 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 2 } + Event::Unbonded { member: 10, pool_id: 1, points: 2, balance: 2 } ] ); }); @@ -1736,7 +1750,7 @@ mod unbond { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, amount: 10 } + Event::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10 } ] ); }); @@ -1771,7 +1785,7 @@ mod unbond { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, Event::Bonded { member: 200, pool_id: 1, bonded: 200, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, amount: 100 }, + Event::Unbonded { member: 100, pool_id: 1, points: 100, balance: 100 }, ] ); @@ -1780,7 +1794,7 @@ mod unbond { assert_eq!( pool_events_since_last_call(), - vec![Event::Unbonded { member: 200, pool_id: 1, amount: 200 }] + vec![Event::Unbonded { member: 200, pool_id: 1, points: 200, balance: 200 }] ); assert_eq!( @@ -1806,8 +1820,7 @@ mod unbond { } ); assert_eq!( - UNBONDING_BALANCE_MAP - .with(|m| *m.borrow_mut().get(&default_bonded_account()).unwrap()), + *UnbondingBalanceMap::get().get(&default_bonded_account()).unwrap(), 100 + 200 ); }); @@ -1849,7 +1862,7 @@ mod unbond { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, amount: 100 } + Event::Unbonded { member: 100, pool_id: 1, points: 100, balance: 100 } ] ); @@ -1871,36 +1884,37 @@ mod unbond { // Given the pools is destroying unsafe_set_state(1, PoolState::Destroying).unwrap(); - // The depositor can be unbonded by anyone. - assert_ok!(Pools::fully_unbond(Origin::signed(420), 10)); - - assert_eq!( - pool_events_since_last_call(), - vec![Event::Unbonded { member: 10, pool_id: 1, amount: 10 }] + // The depositor cannot be unbonded yet. + assert_noop!( + Pools::fully_unbond(Origin::signed(420), 10), + Error::::DoesNotHavePermission, ); + // but when everyone is unbonded it can.. + CurrentEra::set(3); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 100, 0)); + // still permissionless unbond must be full. assert_noop!( Pools::unbond(Origin::signed(420), 10, 5), Error::::PartialUnbondNotAllowedPermissionlessly, ); + // but full unbond works. + assert_ok!(Pools::fully_unbond(Origin::signed(420), 10)); + assert_eq!(BondedPools::::get(1).unwrap().points, 0); assert_eq!( SubPoolsStorage::::get(1).unwrap(), SubPools { no_era: Default::default(), with_era: unbonding_pools_with_era! { - 0 + 3 => UnbondPool { points: 110, balance: 110 } + 3 + 3 => UnbondPool { points: 10, balance: 10 } } } ); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 0); - assert_eq!( - UNBONDING_BALANCE_MAP - .with(|m| *m.borrow_mut().get(&default_bonded_account()).unwrap()), - 110 - ); + assert_eq!(*UnbondingBalanceMap::get().get(&default_bonded_account()).unwrap(), 10); }); } @@ -1988,7 +2002,7 @@ mod unbond { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, amount: 1 } + Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1 } ] ); @@ -2014,7 +2028,7 @@ mod unbond { ); assert_eq!( pool_events_since_last_call(), - vec![Event::Unbonded { member: 10, pool_id: 1, amount: 5 }] + vec![Event::Unbonded { member: 10, pool_id: 1, points: 5, balance: 5 }] ); // when: casual further unbond, next era. @@ -2041,12 +2055,16 @@ mod unbond { ); assert_eq!( pool_events_since_last_call(), - vec![Event::Unbonded { member: 10, pool_id: 1, amount: 1 }] + vec![Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1 }] ); // when: unbonding more than our active: error - assert_noop!( - Pools::unbond(Origin::signed(10), 10, 5), + assert_err!( + frame_support::storage::in_storage_layer(|| Pools::unbond( + Origin::signed(10), + 10, + 5 + )), Error::::NotEnoughPointsToUnbond ); // instead: @@ -2072,7 +2090,7 @@ mod unbond { ); assert_eq!( pool_events_since_last_call(), - vec![Event::Unbonded { member: 10, pool_id: 1, amount: 3 }] + vec![Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3 }] ); }); } @@ -2095,8 +2113,12 @@ mod unbond { // when CurrentEra::set(2); - assert_noop!( - Pools::unbond(Origin::signed(10), 10, 4), + assert_err!( + frame_support::storage::in_storage_layer(|| Pools::unbond( + Origin::signed(10), + 10, + 4 + )), Error::::MaxUnbondingLimit ); @@ -2112,9 +2134,9 @@ mod unbond { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, amount: 2 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 3 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 1 } + Event::Unbonded { member: 10, pool_id: 1, points: 2, balance: 2 }, + Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3 }, + Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1 } ] ); }) @@ -2145,7 +2167,7 @@ mod unbond { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, amount: 3 } + Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3 } ] ); }); @@ -2201,7 +2223,7 @@ mod unbond { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, // exactly equal to ed, all that can be claimed. Event::PaidOut { member: 10, pool_id: 1, payout: 5 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 2 } + Event::Unbonded { member: 10, pool_id: 1, points: 2, balance: 2 } ] ); @@ -2217,7 +2239,7 @@ mod unbond { vec![ // exactly equal to ed, all that can be claimed. Event::PaidOut { member: 10, pool_id: 1, payout: 5 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 3 } + Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3 } ] ); @@ -2232,7 +2254,7 @@ mod unbond { pool_events_since_last_call(), vec![ Event::PaidOut { member: 10, pool_id: 1, payout: 5 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 5 } + Event::Unbonded { member: 10, pool_id: 1, points: 5, balance: 5 } ] ); @@ -2277,6 +2299,9 @@ mod withdraw_unbonded { ExtBuilder::default() .add_members(vec![(40, 40), (550, 550)]) .build_and_execute(|| { + // reduce the noise a bit. + let _ = balances_events_since_last_call(); + // Given assert_eq!(StakingMock::bonding_duration(), 3); assert_ok!(Pools::fully_unbond(Origin::signed(550), 550)); @@ -2285,23 +2310,30 @@ mod withdraw_unbonded { let mut current_era = 1; CurrentEra::set(current_era); - // In a new era, unbond the depositor - unsafe_set_state(1, PoolState::Destroying).unwrap(); - assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); let mut sub_pools = SubPoolsStorage::::get(1).unwrap(); - let unbond_pool = sub_pools.with_era.get_mut(&(current_era + 3)).unwrap(); + let unbond_pool = sub_pools.with_era.get_mut(&3).unwrap(); // Sanity check - assert_eq!(*unbond_pool, UnbondPool { points: 10, balance: 10 }); + assert_eq!(*unbond_pool, UnbondPool { points: 550 + 40, balance: 550 + 40 }); // Simulate a slash to the pool with_era(current_era), decreasing the balance by // half - unbond_pool.balance = 5; - SubPoolsStorage::::insert(1, sub_pools); - // Update the equivalent of the unbonding chunks for the `StakingMock` - UNBONDING_BALANCE_MAP - .with(|m| *m.borrow_mut().get_mut(&default_bonded_account()).unwrap() -= 5); - Balances::make_free_balance_be(&default_bonded_account(), 595); + { + unbond_pool.balance /= 2; // 295 + SubPoolsStorage::::insert(1, sub_pools); + // Update the equivalent of the unbonding chunks for the `StakingMock` + let mut x = UnbondingBalanceMap::get(); + *x.get_mut(&default_bonded_account()).unwrap() /= 5; + UnbondingBalanceMap::set(&x); + Balances::make_free_balance_be( + &default_bonded_account(), + Balances::free_balance(&default_bonded_account()) / 2, // 300 + ); + StakingMock::set_bonded_balance( + default_bonded_account(), + StakingMock::active_stake(&default_bonded_account()).unwrap() / 2, + ); + }; // Advance the current_era to ensure all `with_era` pools will be merged into // `no_era` pool @@ -2311,27 +2343,56 @@ mod withdraw_unbonded { // Simulate some other call to unbond that would merge `with_era` pools into // `no_era` let sub_pools = - SubPoolsStorage::::get(1).unwrap().maybe_merge_pools(current_era + 3); + SubPoolsStorage::::get(1).unwrap().maybe_merge_pools(current_era); SubPoolsStorage::::insert(1, sub_pools); + assert_eq!( SubPoolsStorage::::get(1).unwrap(), SubPools { - no_era: UnbondPool { points: 550 + 40 + 10, balance: 550 + 40 + 5 }, + no_era: UnbondPool { points: 550 + 40, balance: 275 + 20 }, with_era: Default::default() } ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, + Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, + Event::Unbonded { member: 550, pool_id: 1, points: 550, balance: 550 }, + Event::Unbonded { member: 40, pool_id: 1, points: 40, balance: 40 }, + ] + ); + assert_eq!( + balances_events_since_last_call(), + vec![BEvent::BalanceSet { + who: default_bonded_account(), + free: 300, + reserved: 0 + }] + ); + // When assert_ok!(Pools::withdraw_unbonded(Origin::signed(550), 550, 0)); // Then assert_eq!( SubPoolsStorage::::get(1).unwrap().no_era, - UnbondPool { points: 40 + 10, balance: 40 + 5 + 5 } + UnbondPool { points: 40, balance: 20 } + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Withdrawn { member: 550, pool_id: 1, balance: 275, points: 550 }, + Event::MemberRemoved { pool_id: 1, member: 550 } + ] + ); + assert_eq!( + balances_events_since_last_call(), + vec![BEvent::Transfer { from: default_bonded_account(), to: 550, amount: 275 }] ); - assert_eq!(Balances::free_balance(&550), 550 + 545); - assert_eq!(Balances::free_balance(&default_bonded_account()), 50); - assert!(!PoolMembers::::contains_key(550)); // When assert_ok!(Pools::withdraw_unbonded(Origin::signed(40), 40, 0)); @@ -2339,128 +2400,167 @@ mod withdraw_unbonded { // Then assert_eq!( SubPoolsStorage::::get(1).unwrap().no_era, - UnbondPool { points: 10, balance: 10 } + UnbondPool { points: 0, balance: 0 } ); - assert_eq!(Balances::free_balance(&40), 40 + 40); - assert_eq!(Balances::free_balance(&default_bonded_account()), 50 - 40); assert!(!PoolMembers::::contains_key(40)); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Withdrawn { member: 40, pool_id: 1, balance: 20, points: 40 }, + Event::MemberRemoved { pool_id: 1, member: 40 } + ] + ); + assert_eq!( + balances_events_since_last_call(), + vec![BEvent::Transfer { from: default_bonded_account(), to: 40, amount: 20 }] + ); - // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + // now, finally, the depositor can take out its share. + unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(fully_unbond_permissioned(10)); - // Then - assert_eq!(Balances::free_balance(&10), 10 + 10); - assert_eq!(Balances::free_balance(&default_bonded_account()), 0); - assert!(!PoolMembers::::contains_key(10)); - // Pools are removed from storage because the depositor left - assert!(!SubPoolsStorage::::contains_key(1),); - assert!(!RewardPools::::contains_key(1),); - assert!(!BondedPools::::contains_key(1),); + current_era += 3; + CurrentEra::set(current_era); + // when + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); assert_eq!( pool_events_since_last_call(), vec![ - Event::Created { depositor: 10, pool_id: 1 }, - Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, - Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, - Event::Unbonded { member: 550, pool_id: 1, amount: 550 }, - Event::Unbonded { member: 40, pool_id: 1, amount: 40 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 10 }, - Event::Withdrawn { member: 550, pool_id: 1, amount: 545 }, - Event::MemberRemoved { pool_id: 1, member: 550 }, - Event::Withdrawn { member: 40, pool_id: 1, amount: 40 }, - Event::MemberRemoved { pool_id: 1, member: 40 }, - Event::Withdrawn { member: 10, pool_id: 1, amount: 10 }, + Event::Unbonded { member: 10, pool_id: 1, balance: 5, points: 5 }, + Event::Withdrawn { member: 10, pool_id: 1, balance: 5, points: 5 }, Event::MemberRemoved { pool_id: 1, member: 10 }, Event::Destroyed { pool_id: 1 } ] ); + assert_eq!( + balances_events_since_last_call(), + vec![ + BEvent::Transfer { from: default_bonded_account(), to: 10, amount: 5 }, + BEvent::Transfer { from: default_reward_account(), to: 10, amount: 5 } + ] + ); }); } - // This test also documents the case when the pools free balance goes below ED before all - // members have unbonded. #[test] fn withdraw_unbonded_works_against_slashed_with_era_sub_pools() { ExtBuilder::default() .add_members(vec![(40, 40), (550, 550)]) .build_and_execute(|| { + let _ = balances_events_since_last_call(); + // Given - StakingMock::set_bonded_balance(default_bonded_account(), 100); // slash bonded balance - Balances::make_free_balance_be(&default_bonded_account(), 100); - assert_eq!(StakingMock::total_stake(&default_bonded_account()), Some(100)); + // current bond is 600, we slash it all to 300. + StakingMock::set_bonded_balance(default_bonded_account(), 300); + Balances::make_free_balance_be(&default_bonded_account(), 300); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Some(300)); - assert_ok!(Pools::fully_unbond(Origin::signed(40), 40)); - assert_ok!(Pools::fully_unbond(Origin::signed(550), 550)); - unsafe_set_state(1, PoolState::Destroying).unwrap(); - assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + assert_ok!(fully_unbond_permissioned(40)); + assert_ok!(fully_unbond_permissioned(550)); - SubPoolsStorage::::insert( - 1, - SubPools { - no_era: Default::default(), - with_era: unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 600, balance: 100 }}, - }, + assert_eq!( + SubPoolsStorage::::get(&1).unwrap().with_era, + unbonding_pools_with_era! { 3 => UnbondPool { points: 550 / 2 + 40 / 2, balance: 550 / 2 + 40 / 2 }} + ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, + Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, + Event::Unbonded { member: 40, pool_id: 1, balance: 20, points: 20 }, + Event::Unbonded { member: 550, pool_id: 1, balance: 275, points: 275 }, + ] + ); + assert_eq!( + balances_events_since_last_call(), + vec![BEvent::BalanceSet { + who: default_bonded_account(), + free: 300, + reserved: 0 + },] ); + CurrentEra::set(StakingMock::bonding_duration()); // When assert_ok!(Pools::withdraw_unbonded(Origin::signed(40), 40, 0)); // Then + assert_eq!( + balances_events_since_last_call(), + vec![BEvent::Transfer { from: default_bonded_account(), to: 40, amount: 20 },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Withdrawn { member: 40, pool_id: 1, balance: 20, points: 20 }, + Event::MemberRemoved { pool_id: 1, member: 40 } + ] + ); + assert_eq!( SubPoolsStorage::::get(&1).unwrap().with_era, - unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 560, balance: 94 }} + unbonding_pools_with_era! { 3 => UnbondPool { points: 550 / 2, balance: 550 / 2 }} ); - assert_eq!(Balances::free_balance(&40), 40 + 6); - assert_eq!(Balances::free_balance(&default_bonded_account()), 94); - assert!(!PoolMembers::::contains_key(40)); // When assert_ok!(Pools::withdraw_unbonded(Origin::signed(550), 550, 0)); // Then + assert_eq!( + balances_events_since_last_call(), + vec![BEvent::Transfer { from: default_bonded_account(), to: 550, amount: 275 },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Withdrawn { member: 550, pool_id: 1, balance: 275, points: 275 }, + Event::MemberRemoved { pool_id: 1, member: 550 } + ] + ); + assert!(SubPoolsStorage::::get(&1).unwrap().with_era.is_empty()); + + // now, finally, the depositor can take out its share. + unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(fully_unbond_permissioned(10)); + + // because everyone else has left, the points assert_eq!( SubPoolsStorage::::get(&1).unwrap().with_era, - unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 10, balance: 2 }} + unbonding_pools_with_era! { 6 => UnbondPool { points: 5, balance: 5 }} ); - assert_eq!(Balances::free_balance(&550), 550 + 92); - // The account was dusted because it went below ED(5) - assert_eq!(Balances::free_balance(&default_bonded_account()), 0); - assert!(!PoolMembers::::contains_key(550)); - // When + CurrentEra::set(CurrentEra::get() + 3); + + // when assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); - // Then - assert_eq!(Balances::free_balance(&10), 10 + 0); + // then + assert_eq!(Balances::free_balance(&10), 10 + 5); assert_eq!(Balances::free_balance(&default_bonded_account()), 0); - assert!(!PoolMembers::::contains_key(10)); - // Pools are removed from storage because the depositor left - assert!(!SubPoolsStorage::::contains_key(1)); - assert!(!RewardPools::::contains_key(1)); - assert!(!BondedPools::::contains_key(1)); + // in this test 10 also gets a fair share of the slash, because the slash was + // applied to the bonded account. assert_eq!( pool_events_since_last_call(), vec![ - Event::Created { depositor: 10, pool_id: 1 }, - Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, - Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, - Event::Unbonded { member: 40, pool_id: 1, amount: 6 }, - Event::Unbonded { member: 550, pool_id: 1, amount: 92 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 2 }, - Event::Withdrawn { member: 40, pool_id: 1, amount: 6 }, - Event::MemberRemoved { pool_id: 1, member: 40 }, - Event::Withdrawn { member: 550, pool_id: 1, amount: 92 }, - Event::MemberRemoved { pool_id: 1, member: 550 }, - Event::Withdrawn { member: 10, pool_id: 1, amount: 0 }, + Event::Unbonded { member: 10, pool_id: 1, points: 5, balance: 5 }, + Event::Withdrawn { member: 10, pool_id: 1, points: 5, balance: 5 }, Event::MemberRemoved { pool_id: 1, member: 10 }, Event::Destroyed { pool_id: 1 } ] ); + assert_eq!( + balances_events_since_last_call(), + vec![ + BEvent::Transfer { from: default_bonded_account(), to: 10, amount: 5 }, + BEvent::Transfer { from: default_reward_account(), to: 10, amount: 5 } + ] + ); }); } @@ -2562,8 +2662,8 @@ mod withdraw_unbonded { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, Event::Bonded { member: 200, pool_id: 1, bonded: 200, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, amount: 100 }, - Event::Unbonded { member: 200, pool_id: 1, amount: 200 } + Event::Unbonded { member: 100, pool_id: 1, points: 100, balance: 100 }, + Event::Unbonded { member: 200, pool_id: 1, points: 200, balance: 200 } ] ); @@ -2590,9 +2690,9 @@ mod withdraw_unbonded { assert_eq!( pool_events_since_last_call(), vec![ - Event::Withdrawn { member: 100, pool_id: 1, amount: 100 }, + Event::Withdrawn { member: 100, pool_id: 1, points: 100, balance: 100 }, Event::MemberRemoved { pool_id: 1, member: 100 }, - Event::Withdrawn { member: 200, pool_id: 1, amount: 200 }, + Event::Withdrawn { member: 200, pool_id: 1, points: 200, balance: 200 }, Event::MemberRemoved { pool_id: 1, member: 200 } ] ); @@ -2640,209 +2740,14 @@ mod withdraw_unbonded { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, amount: 100 }, - Event::Withdrawn { member: 100, pool_id: 1, amount: 100 }, + Event::Unbonded { member: 100, pool_id: 1, points: 100, balance: 100 }, + Event::Withdrawn { member: 100, pool_id: 1, points: 100, balance: 100 }, Event::MemberRemoved { pool_id: 1, member: 100 } ] ); }); } - #[test] - fn withdraw_unbonded_depositor_with_era_pool() { - ExtBuilder::default() - .add_members(vec![(100, 100), (200, 200)]) - .build_and_execute(|| { - // Given - assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); - - assert_eq!( - pool_events_since_last_call(), - vec![ - Event::Created { depositor: 10, pool_id: 1 }, - Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, - Event::Bonded { member: 200, pool_id: 1, bonded: 200, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, amount: 100 } - ] - ); - - let mut current_era = 1; - CurrentEra::set(current_era); - - assert_ok!(Pools::fully_unbond(Origin::signed(200), 200)); - - assert_eq!( - pool_events_since_last_call(), - vec![Event::Unbonded { member: 200, pool_id: 1, amount: 200 }] - ); - - unsafe_set_state(1, PoolState::Destroying).unwrap(); - assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); - - assert_eq!( - pool_events_since_last_call(), - vec![Event::Unbonded { member: 10, pool_id: 1, amount: 10 }] - ); - - assert_eq!( - SubPoolsStorage::::get(1).unwrap(), - SubPools { - no_era: Default::default(), - with_era: unbonding_pools_with_era! { - 0 + 3 => UnbondPool { points: 100, balance: 100}, - 1 + 3 => UnbondPool { points: 200 + 10, balance: 200 + 10 } - } - } - ); - - // Skip ahead eras to where its valid for the members to withdraw - current_era += StakingMock::bonding_duration(); - CurrentEra::set(current_era); - - // Cannot withdraw the depositor if their is a member in another `with_era` pool. - assert_noop!( - Pools::withdraw_unbonded(Origin::signed(420), 10, 0), - Error::::NotOnlyPoolMember - ); - - // Given - assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 100, 0)); - - assert_eq!( - pool_events_since_last_call(), - vec![ - Event::Withdrawn { member: 100, pool_id: 1, amount: 100 }, - Event::MemberRemoved { pool_id: 1, member: 100 } - ] - ); - - assert_eq!( - SubPoolsStorage::::get(1).unwrap(), - SubPools { - no_era: Default::default(), - with_era: unbonding_pools_with_era! { - // Note that era 0+3 unbond pool is destroyed because points went to 0 - 1 + 3 => UnbondPool { points: 200 + 10, balance: 200 + 10 } - } - } - ); - - // Cannot withdraw the depositor if their is a member in another `with_era` pool. - assert_noop!( - Pools::withdraw_unbonded(Origin::signed(420), 10, 0), - Error::::NotOnlyPoolMember - ); - - // Given - assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 200, 0)); - - assert_eq!( - pool_events_since_last_call(), - vec![ - Event::Withdrawn { member: 200, pool_id: 1, amount: 200 }, - Event::MemberRemoved { pool_id: 1, member: 200 } - ] - ); - - assert_eq!( - SubPoolsStorage::::get(1).unwrap(), - SubPools { - no_era: Default::default(), - with_era: unbonding_pools_with_era! { - 1 + 3 => UnbondPool { points: 10, balance: 10 } - } - } - ); - - // The depositor can withdraw - assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 10, 0)); - - assert_eq!( - pool_events_since_last_call(), - vec![ - Event::Withdrawn { member: 10, pool_id: 1, amount: 10 }, - Event::MemberRemoved { pool_id: 1, member: 10 }, - Event::Destroyed { pool_id: 1 } - ] - ); - - assert!(!PoolMembers::::contains_key(10)); - assert_eq!(Balances::free_balance(10), 10 + 10); - // Pools are removed from storage because the depositor left - assert!(!SubPoolsStorage::::contains_key(1)); - assert!(!RewardPools::::contains_key(1)); - assert!(!BondedPools::::contains_key(1)); - }); - } - - #[test] - fn withdraw_unbonded_depositor_no_era_pool() { - ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { - // Given - assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); - unsafe_set_state(1, PoolState::Destroying).unwrap(); - assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); - // Skip ahead to an era where the `with_era` pools can get merged into the `no_era` - // pool. - let current_era = TotalUnbondingPools::::get(); - CurrentEra::set(current_era); - - // Simulate some other withdraw that caused the pool to merge - let sub_pools = - SubPoolsStorage::::get(1).unwrap().maybe_merge_pools(current_era + 3); - SubPoolsStorage::::insert(1, sub_pools); - assert_eq!( - SubPoolsStorage::::get(1).unwrap(), - SubPools { - no_era: UnbondPool { points: 100 + 10, balance: 100 + 10 }, - with_era: Default::default(), - } - ); - - // Cannot withdraw depositor with another member in the `no_era` pool - assert_noop!( - Pools::withdraw_unbonded(Origin::signed(420), 10, 0), - Error::::NotOnlyPoolMember - ); - - // Given - assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 100, 0)); - assert_eq!( - SubPoolsStorage::::get(1).unwrap(), - SubPools { - no_era: UnbondPool { points: 10, balance: 10 }, - with_era: Default::default(), - } - ); - - // The depositor can withdraw - assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 10, 0)); - assert!(!PoolMembers::::contains_key(10)); - assert_eq!(Balances::free_balance(10), 10 + 10); - // Pools are removed from storage because the depositor left - assert!(!SubPoolsStorage::::contains_key(1)); - assert!(!RewardPools::::contains_key(1)); - assert!(!BondedPools::::contains_key(1)); - - assert_eq!( - pool_events_since_last_call(), - vec![ - Event::Created { depositor: 10, pool_id: 1 }, - Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, amount: 100 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 10 }, - Event::Withdrawn { member: 100, pool_id: 1, amount: 100 }, - Event::MemberRemoved { pool_id: 1, member: 100 }, - Event::Withdrawn { member: 10, pool_id: 1, amount: 10 }, - Event::MemberRemoved { pool_id: 1, member: 10 }, - Event::Destroyed { pool_id: 1 } - ] - ); - }); - } - #[test] fn partial_withdraw_unbonded_depositor() { ExtBuilder::default().ed(1).build_and_execute(|| { @@ -2874,8 +2779,8 @@ mod withdraw_unbonded { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, amount: 6 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 1 } + Event::Unbonded { member: 10, pool_id: 1, points: 6, balance: 6 }, + Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1 } ] ); @@ -2906,7 +2811,7 @@ mod withdraw_unbonded { ); assert_eq!( pool_events_since_last_call(), - vec![Event::Withdrawn { member: 10, pool_id: 1, amount: 6 }] + vec![Event::Withdrawn { member: 10, pool_id: 1, points: 6, balance: 6 }] ); // when @@ -2921,7 +2826,7 @@ mod withdraw_unbonded { assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default()); assert_eq!( pool_events_since_last_call(), - vec![Event::Withdrawn { member: 10, pool_id: 1, amount: 1 },] + vec![Event::Withdrawn { member: 10, pool_id: 1, points: 1, balance: 1 },] ); // when repeating: @@ -2961,8 +2866,8 @@ mod withdraw_unbonded { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 11, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 11, pool_id: 1, amount: 6 }, - Event::Unbonded { member: 11, pool_id: 1, amount: 1 } + Event::Unbonded { member: 11, pool_id: 1, points: 6, balance: 6 }, + Event::Unbonded { member: 11, pool_id: 1, points: 1, balance: 1 } ] ); @@ -2993,7 +2898,7 @@ mod withdraw_unbonded { ); assert_eq!( pool_events_since_last_call(), - vec![Event::Withdrawn { member: 11, pool_id: 1, amount: 6 }] + vec![Event::Withdrawn { member: 11, pool_id: 1, points: 6, balance: 6 }] ); // when @@ -3008,7 +2913,7 @@ mod withdraw_unbonded { assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default()); assert_eq!( pool_events_since_last_call(), - vec![Event::Withdrawn { member: 11, pool_id: 1, amount: 1 }] + vec![Event::Withdrawn { member: 11, pool_id: 1, points: 1, balance: 1 }] ); // when repeating: @@ -3051,9 +2956,9 @@ mod withdraw_unbonded { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, amount: 75 }, - Event::Unbonded { member: 100, pool_id: 1, amount: 25 }, - Event::Withdrawn { member: 100, pool_id: 1, amount: 75 }, + Event::Unbonded { member: 100, pool_id: 1, points: 75, balance: 75 }, + Event::Unbonded { member: 100, pool_id: 1, points: 25, balance: 25 }, + Event::Withdrawn { member: 100, pool_id: 1, points: 75, balance: 75 }, ] ); assert_eq!( @@ -3067,7 +2972,7 @@ mod withdraw_unbonded { assert_eq!( pool_events_since_last_call(), vec![ - Event::Withdrawn { member: 100, pool_id: 1, amount: 25 }, + Event::Withdrawn { member: 100, pool_id: 1, points: 25, balance: 25 }, Event::MemberRemoved { pool_id: 1, member: 100 } ] ); @@ -3102,9 +3007,9 @@ mod withdraw_unbonded { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, amount: 7 }, - Event::Unbonded { member: 10, pool_id: 1, amount: 3 }, - Event::Withdrawn { member: 10, pool_id: 1, amount: 7 } + Event::Unbonded { member: 10, pool_id: 1, points: 7, balance: 7 }, + Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3 }, + Event::Withdrawn { member: 10, pool_id: 1, points: 7, balance: 7 } ] ); assert_eq!( @@ -3118,7 +3023,7 @@ mod withdraw_unbonded { assert_eq!( pool_events_since_last_call(), vec![ - Event::Withdrawn { member: 10, pool_id: 1, amount: 3 }, + Event::Withdrawn { member: 10, pool_id: 1, points: 3, balance: 3 }, Event::MemberRemoved { pool_id: 1, member: 10 }, // the pool is also destroyed now. Event::Destroyed { pool_id: 1 }, @@ -3288,11 +3193,11 @@ mod nominate { // Root can nominate assert_ok!(Pools::nominate(Origin::signed(900), 1, vec![21])); - assert_eq!(Nominations::get(), vec![21]); + assert_eq!(Nominations::get().unwrap(), vec![21]); // Nominator can nominate assert_ok!(Pools::nominate(Origin::signed(901), 1, vec![31])); - assert_eq!(Nominations::get(), vec![31]); + assert_eq!(Nominations::get().unwrap(), vec![31]); // Can't nominate for a pool that doesn't exist assert_noop!( diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index ca89f982c60e3..8e3facfc5ec26 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -18,11 +18,12 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-06-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet // --chain=dev @@ -32,8 +33,9 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/nomination-pools/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -58,6 +60,7 @@ pub trait WeightInfo { fn set_metadata(n: u32, ) -> Weight; fn set_configs() -> Weight; fn update_roles() -> Weight; + fn chill() -> Weight; } /// Weights for pallet_nomination_pools using the Substrate node and recommended hardware. @@ -77,7 +80,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (129_124_000 as Weight) + (124_508_000 as Weight) .saturating_add(T::DbWeight::get().reads(17 as Weight)) .saturating_add(T::DbWeight::get().writes(11 as Weight)) } @@ -91,7 +94,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (118_193_000 as Weight) + (115_185_000 as Weight) .saturating_add(T::DbWeight::get().reads(13 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) } @@ -102,19 +105,19 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:0) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (132_390_000 as Weight) - .saturating_add(T::DbWeight::get().reads(13 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) + (132_723_000 as Weight) + .saturating_add(T::DbWeight::get().reads(14 as Weight)) + .saturating_add(T::DbWeight::get().writes(13 as Weight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (54_743_000 as Weight) + (52_498_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -133,7 +136,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (124_684_000 as Weight) + (121_645_000 as Weight) .saturating_add(T::DbWeight::get().reads(18 as Weight)) .saturating_add(T::DbWeight::get().writes(13 as Weight)) } @@ -141,10 +144,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) + /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (44_259_000 as Weight) + (43_320_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -156,10 +160,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - (84_854_000 as Weight) - // Standard Error: 0 - .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) + (83_195_000 as Weight) + // Standard Error: 5_000 + .saturating_add((57_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -182,8 +187,9 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) + /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (146_992_000 as Weight) + (143_495_000 as Weight) .saturating_add(T::DbWeight::get().reads(19 as Weight)) .saturating_add(T::DbWeight::get().writes(16 as Weight)) } @@ -210,7 +216,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (138_099_000 as Weight) + (127_998_000 as Weight) .saturating_add(T::DbWeight::get().reads(22 as Weight)) .saturating_add(T::DbWeight::get().writes(15 as Weight)) } @@ -226,10 +232,11 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) + /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - (50_964_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_333_000 as Weight).saturating_mul(n as Weight)) + (49_929_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_319_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(5 as Weight)) @@ -237,15 +244,16 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (27_196_000 as Weight) + (27_399_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) + /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - (15_056_000 as Weight) + (14_813_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -257,15 +265,28 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (6_294_000 as Weight) + (6_115_000 as Weight) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (22_444_000 as Weight) + (22_546_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:1 w:1) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) + fn chill() -> Weight { + (48_243_000 as Weight) + .saturating_add(T::DbWeight::get().reads(8 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + } } // For backwards compatibility and tests @@ -284,7 +305,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (129_124_000 as Weight) + (124_508_000 as Weight) .saturating_add(RocksDbWeight::get().reads(17 as Weight)) .saturating_add(RocksDbWeight::get().writes(11 as Weight)) } @@ -298,7 +319,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (118_193_000 as Weight) + (115_185_000 as Weight) .saturating_add(RocksDbWeight::get().reads(13 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) } @@ -309,19 +330,19 @@ impl WeightInfo for () { // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:0) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) + // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (132_390_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(13 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + (132_723_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(14 as Weight)) + .saturating_add(RocksDbWeight::get().writes(13 as Weight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (54_743_000 as Weight) + (52_498_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -340,7 +361,7 @@ impl WeightInfo for () { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (124_684_000 as Weight) + (121_645_000 as Weight) .saturating_add(RocksDbWeight::get().reads(18 as Weight)) .saturating_add(RocksDbWeight::get().writes(13 as Weight)) } @@ -348,10 +369,11 @@ impl WeightInfo for () { // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) + /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (44_259_000 as Weight) + (43_320_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -363,10 +385,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - (84_854_000 as Weight) - // Standard Error: 0 - .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) + (83_195_000 as Weight) + // Standard Error: 5_000 + .saturating_add((57_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } @@ -389,8 +412,9 @@ impl WeightInfo for () { // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) + /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (146_992_000 as Weight) + (143_495_000 as Weight) .saturating_add(RocksDbWeight::get().reads(19 as Weight)) .saturating_add(RocksDbWeight::get().writes(16 as Weight)) } @@ -417,7 +441,7 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (138_099_000 as Weight) + (127_998_000 as Weight) .saturating_add(RocksDbWeight::get().reads(22 as Weight)) .saturating_add(RocksDbWeight::get().writes(15 as Weight)) } @@ -433,10 +457,11 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) + /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - (50_964_000 as Weight) - // Standard Error: 11_000 - .saturating_add((2_333_000 as Weight).saturating_mul(n as Weight)) + (49_929_000 as Weight) + // Standard Error: 16_000 + .saturating_add((2_319_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) @@ -444,15 +469,16 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (27_196_000 as Weight) + (27_399_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) + /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - (15_056_000 as Weight) + (14_813_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -464,13 +490,26 @@ impl WeightInfo for () { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (6_294_000 as Weight) + (6_115_000 as Weight) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (22_444_000 as Weight) + (22_546_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:1 w:1) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) + fn chill() -> Weight { + (48_243_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(8 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + } } diff --git a/frame/nomination-pools/test-staking/Cargo.toml b/frame/nomination-pools/test-staking/Cargo.toml new file mode 100644 index 0000000000000..ad36e89e0d68a --- /dev/null +++ b/frame/nomination-pools/test-staking/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "pallet-nomination-pools-test-staking" +version = "1.0.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME nomination pools pallet tests with the staking pallet" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dev-dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +scale-info = { version = "2.0.1", features = ["derive"] } + +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-std = { version = "4.0.0", path = "../../../primitives/std" } +sp-staking = { version = "4.0.0-dev", path = "../../../primitives/staking" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } + +frame-system = { version = "4.0.0-dev", path = "../../system" } +frame-support = { version = "4.0.0-dev", path = "../../support" } +frame-election-provider-support = { version = "4.0.0-dev", path = "../../election-provider-support" } + +pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } +pallet-balances = { version = "4.0.0-dev", path = "../../balances" } +pallet-staking = { version = "4.0.0-dev", path = "../../staking" } +pallet-bags-list = { version = "4.0.0-dev", path = "../../bags-list" } +pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } +pallet-nomination-pools = { version = "1.0.0-dev", path = ".." } + +sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +log = { version = "0.4.0" } diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs new file mode 100644 index 0000000000000..2e40e8c6d917d --- /dev/null +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -0,0 +1,373 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(test)] + +mod mock; + +use frame_support::{assert_noop, assert_ok, bounded_btree_map, traits::Currency}; +use mock::*; +use pallet_nomination_pools::{ + Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, PoolMembers, PoolState, +}; +use pallet_staking::{CurrentEra, Event as StakingEvent, Payee, RewardDestination}; + +#[test] +fn pool_lifecycle_e2e() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::minimum_balance(), 5); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(Origin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // have the pool nominate. + assert_ok!(Pools::nominate(Origin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 50),]); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + // have two members join + assert_ok!(Pools::join(Origin::signed(20), 10, 1)); + assert_ok!(Pools::join(Origin::signed(21), 10, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded(POOL1_BONDED, 10), StakingEvent::Bonded(POOL1_BONDED, 10),] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, + ] + ); + + // pool goes into destroying + assert_ok!(Pools::set_state(Origin::signed(10), 1, PoolState::Destroying)); + + // depositor cannot unbond yet. + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 50), + PoolsError::::NotOnlyPoolMember, + ); + + // now the members want to unbond. + assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(Origin::signed(21), 21, 10)); + + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(20).unwrap().points, 0); + assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(21).unwrap().points, 0); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded(POOL1_BONDED, 10), + StakingEvent::Unbonded(POOL1_BONDED, 10), + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10 }, + PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10 }, + ] + ); + + // depositor cannot still unbond + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 50), + PoolsError::::NotOnlyPoolMember, + ); + + for e in 1..BondingDuration::get() { + CurrentEra::::set(Some(e)); + assert_noop!( + Pools::withdraw_unbonded(Origin::signed(20), 20, 0), + PoolsError::::CannotWithdrawAny + ); + } + + // members are now unlocked. + CurrentEra::::set(Some(BondingDuration::get())); + + // depositor cannot still unbond + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 50), + PoolsError::::NotOnlyPoolMember, + ); + + // but members can now withdraw. + assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(21), 21, 0)); + assert!(PoolMembers::::get(20).is_none()); + assert!(PoolMembers::::get(21).is_none()); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn(POOL1_BONDED, 20),] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 20, pool_id: 1, points: 10, balance: 10 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 20 }, + PoolsEvent::Withdrawn { member: 21, pool_id: 1, points: 10, balance: 10 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 21 }, + ] + ); + + // as soon as all members have left, the depositor can try to unbond, but since the + // min-nominator intention is set, they must chill first. + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 50), + pallet_staking::Error::::InsufficientBond + ); + + assert_ok!(Pools::chill(Origin::signed(10), 1)); + assert_ok!(Pools::unbond(Origin::signed(10), 10, 50)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Chilled(POOL1_BONDED), StakingEvent::Unbonded(POOL1_BONDED, 50),] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50 }] + ); + + // waiting another bonding duration: + CurrentEra::::set(Some(BondingDuration::get() * 2)); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 1)); + + // pools is fully destroyed now. + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn(POOL1_BONDED, 50),] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 10 }, + PoolsEvent::Destroyed { pool_id: 1 } + ] + ); + }) +} + +#[test] +fn pool_slash_e2e() { + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + assert_eq!(Payee::::get(POOL1_BONDED), RewardDestination::Account(POOL1_REWARD)); + + // have two members join + assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + assert_ok!(Pools::join(Origin::signed(21), 20, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded(POOL1_BONDED, 20), StakingEvent::Bonded(POOL1_BONDED, 20)] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 20, joined: true }, + ] + ); + + // now let's progress a bit. + CurrentEra::::set(Some(1)); + + // 20 / 80 of the total funds are unlocked, and safe from any further slash. + assert_ok!(Pools::unbond(Origin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded(POOL1_BONDED, 10), + StakingEvent::Unbonded(POOL1_BONDED, 10) + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10 }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10 } + ] + ); + + CurrentEra::::set(Some(2)); + + // note: depositor cannot fully unbond at this point. + // these funds will still get slashed. + assert_ok!(Pools::unbond(Origin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(Origin::signed(21), 21, 10)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded(POOL1_BONDED, 10), + StakingEvent::Unbonded(POOL1_BONDED, 10), + StakingEvent::Unbonded(POOL1_BONDED, 10), + ] + ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10 }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10 }, + PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10 }, + ] + ); + + // At this point, 20 are safe from slash, 30 are unlocking but vulnerable to slash, and and + // another 30 are active and vulnerable to slash. Let's slash half of them. + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 30, + &mut Default::default(), + &mut Default::default(), + 1, // slash era 1, affects chunks at era 5 onwards. + ); + + assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 30)]); + assert_eq!( + pool_events_since_last_call(), + vec![ + // 30 has been slashed to 15 (15 slash) + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 15 }, + // 30 has been slashed to 15 (15 slash) + PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } + ] + ); + + CurrentEra::::set(Some(3)); + assert_ok!(Pools::unbond(Origin::signed(21), 21, 10)); + + assert_eq!( + PoolMembers::::get(21).unwrap(), + PoolMember { + pool_id: 1, + points: 0, + reward_pool_total_earnings: 0, + // the 10 points unlocked just now correspond to 5 points in the unbond pool. + unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5) + } + ); + assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Unbonded(POOL1_BONDED, 5)]); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5 }] + ); + + // now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free. + CurrentEra::::set(Some(6)); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(21), 21, 0)); + + assert_eq!( + pool_events_since_last_call(), + vec![ + // 20 had unbonded 10 safely, and 10 got slashed by half. + PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 10 + 5, points: 20 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 20 }, + // 21 unbonded all of it after the slash + PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 5 + 5, points: 15 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 21 } + ] + ); + assert_eq!( + staking_events_since_last_call(), + // a 10 (un-slashed) + 10/2 (slashed) balance from 10 has also been unlocked + vec![StakingEvent::Withdrawn(POOL1_BONDED, 15 + 10 + 15)] + ); + + // now, finally, we can unbond the depositor further than their current limit. + assert_ok!(Pools::set_state(Origin::signed(10), 1, PoolState::Destroying)); + assert_ok!(Pools::unbond(Origin::signed(10), 10, 20)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded(POOL1_BONDED, 10)] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, + PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10 } + ] + ); + + CurrentEra::::set(Some(9)); + assert_eq!( + PoolMembers::::get(10).unwrap(), + PoolMember { + pool_id: 1, + points: 0, + reward_pool_total_earnings: 0, + unbonding_eras: bounded_btree_map!(4 => 10, 5 => 10, 9 => 10) + } + ); + // withdraw the depositor, they should lose 12 balance in total due to slash. + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn(POOL1_BONDED, 10)] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 10, pool_id: 1, balance: 10 + 15, points: 30 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 10 }, + PoolsEvent::Destroyed { pool_id: 1 } + ] + ); + }); +} diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs new file mode 100644 index 0000000000000..7b720c009b29b --- /dev/null +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -0,0 +1,261 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_election_provider_support::VoteWeight; +use frame_support::{assert_ok, pallet_prelude::*, parameter_types, traits::ConstU64, PalletId}; +use sp_runtime::traits::{Convert, IdentityLookup}; + +type AccountId = u128; +type AccountIndex = u32; +type BlockNumber = u64; +type Balance = u128; + +pub(crate) const POOL1_BONDED: AccountId = 20318131474730217858575332831085u128; +pub(crate) const POOL1_REWARD: AccountId = 20397359637244482196168876781421u128; + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = AccountIndex; + type BlockNumber = BlockNumber; + type Call = Call; + type Hash = sp_core::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = sp_runtime::testing::Header; + type Event = Event; + type BlockHashCount = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +parameter_types! { + pub static ExistentialDeposit: Balance = 5; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} + +pallet_staking_reward_curve::build! { + const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + +parameter_types! { + pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; + pub static BondingDuration: u32 = 3; +} + +impl pallet_staking::Config for Runtime { + type MaxNominations = ConstU32<16>; + type Currency = Balances; + type CurrencyBalance = Balance; + type UnixTime = pallet_timestamp::Pallet; + type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; + type RewardRemainder = (); + type Event = Event; + type Slash = (); + type Reward = (); + type SessionsPerEra = (); + type SlashDeferDuration = (); + type SlashCancelOrigin = frame_system::EnsureRoot; + type BondingDuration = BondingDuration; + type SessionInterface = (); + type EraPayout = pallet_staking::ConvertCurve; + type NextNewSession = (); + type MaxNominatorRewardedPerValidator = ConstU32<64>; + type OffendingValidatorsThreshold = (); + type ElectionProvider = + frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking)>; + type GenesisElectionProvider = Self::ElectionProvider; + type VoterList = pallet_bags_list::Pallet; + type MaxUnlockingChunks = ConstU32<32>; + type OnStakerSlash = Pools; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type WeightInfo = (); +} + +parameter_types! { + pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; +} + +impl pallet_bags_list::Config for Runtime { + type Event = Event; + type WeightInfo = (); + type BagThresholds = BagThresholds; + type ScoreProvider = Staking; + type Score = VoteWeight; +} + +pub struct BalanceToU256; +impl Convert for BalanceToU256 { + fn convert(n: Balance) -> sp_core::U256 { + n.into() + } +} + +pub struct U256ToBalance; +impl Convert for U256ToBalance { + fn convert(n: sp_core::U256) -> Balance { + n.try_into().unwrap() + } +} + +parameter_types! { + pub const PostUnbondingPoolsWindow: u32 = 10; + pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); +} + +impl pallet_nomination_pools::Config for Runtime { + type Event = Event; + type WeightInfo = (); + type Currency = Balances; + type BalanceToU256 = BalanceToU256; + type U256ToBalance = U256ToBalance; + type StakingInterface = Staking; + type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; + type MaxMetadataLen = ConstU32<256>; + type MaxUnbonding = ConstU32<8>; + type MinPointsToBalance = ConstU32<10>; + type PalletId = PoolsPalletId; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + Call: From, +{ + type OverarchingCall = Call; + type Extrinsic = UncheckedExtrinsic; +} + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system::{Pallet, Call, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, + BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, + Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event}, + } +); + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let _ = pallet_nomination_pools::GenesisConfig:: { + min_join_bond: 2, + min_create_bond: 2, + max_pools: Some(3), + max_members_per_pool: Some(3), + max_members: Some(3 * 3), + } + .assimilate_storage(&mut storage) + .unwrap(); + + let _ = pallet_balances::GenesisConfig:: { + balances: vec![(10, 100), (20, 100), (21, 100), (22, 100)], + } + .assimilate_storage(&mut storage) + .unwrap(); + + let mut ext = sp_io::TestExternalities::from(storage); + + ext.execute_with(|| { + // for events to be deposited. + frame_system::Pallet::::set_block_number(1); + + // set some limit for nominations. + assert_ok!(Staking::set_staking_configs( + Origin::root(), + pallet_staking::ConfigOp::Set(10), // minimum nominator bond + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + )); + }); + + ext +} + +parameter_types! { + static ObservedEventsPools: usize = 0; + static ObservedEventsStaking: usize = 0; + static ObservedEventsBalances: usize = 0; +} + +pub(crate) fn pool_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let Event::Pools(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = ObservedEventsPools::get(); + ObservedEventsPools::set(events.len()); + events.into_iter().skip(already_seen).collect() +} + +pub(crate) fn staking_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let Event::Staking(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = ObservedEventsStaking::get(); + ObservedEventsStaking::set(events.len()); + events.into_iter().skip(already_seen).collect() +} diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 331095774b741..360d5b5efb58f 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -438,7 +438,7 @@ pub struct UnlockChunk { } /// The ledger of a (bonded) stash. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct StakingLedger { /// The stash account whose balance is actually locked and at stake. @@ -607,12 +607,12 @@ impl StakingLedger { let mut slashed_unlocking = BTreeMap::<_, _>::new(); for i in slash_chunks_priority { if let Some(chunk) = self.unlocking.get_mut(i).defensive() { - slash_out_of(&mut chunk.value, &mut remaining_slash); - // write the new slashed value of this chunk to the map. - slashed_unlocking.insert(chunk.era, chunk.value); if remaining_slash.is_zero() { break } + slash_out_of(&mut chunk.value, &mut remaining_slash); + // write the new slashed value of this chunk to the map. + slashed_unlocking.insert(chunk.era, chunk.value); } else { break } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 66265ab1f135e..7656eec80a5ff 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1414,17 +1414,17 @@ impl StakingInterface for Pallet { Self::unbond(RawOrigin::Signed(controller).into(), value) } + fn chill(controller: Self::AccountId) -> DispatchResult { + Self::chill(RawOrigin::Signed(controller).into()) + } + fn withdraw_unbonded( controller: Self::AccountId, num_slashing_spans: u32, - ) -> Result { - Self::withdraw_unbonded(RawOrigin::Signed(controller).into(), num_slashing_spans) - .map(|post_info| { - post_info - .actual_weight - .unwrap_or(T::WeightInfo::withdraw_unbonded_kill(num_slashing_spans)) - }) - .map_err(|err_with_post_info| err_with_post_info.error) + ) -> Result { + Self::withdraw_unbonded(RawOrigin::Signed(controller.clone()).into(), num_slashing_spans) + .map(|_| !Ledger::::contains_key(&controller)) + .map_err(|with_post| with_post.error) } fn bond( @@ -1445,4 +1445,9 @@ impl StakingInterface for Pallet { let targets = targets.into_iter().map(T::Lookup::unlookup).collect::>(); Self::nominate(RawOrigin::Signed(controller).into(), targets) } + + #[cfg(feature = "runtime-benchmarks")] + fn nominations(who: Self::AccountId) -> Option> { + Nominators::::get(who).map(|n| n.targets.into_inner()) + } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index d0ebef27b4ef6..9a13a818f4b59 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4930,6 +4930,25 @@ fn force_apply_min_commission_works() { }); } +#[test] +fn proportional_slash_stop_slashing_if_remaining_zero() { + let c = |era, value| UnlockChunk:: { era, value }; + // Given + let mut ledger = StakingLedger:: { + stash: 123, + total: 40, + active: 20, + // we have some chunks, but they are not affected. + unlocking: bounded_vec![c(1, 10), c(2, 10)], + claimed_rewards: vec![], + }; + + assert_eq!(BondingDuration::get(), 3); + + // should not slash more than the amount requested, by accidentally slashing the first chunk. + assert_eq!(ledger.slash(18, 1, 0), 18); +} + #[test] fn proportional_ledger_slash_works() { let c = |era, value| UnlockChunk:: { era, value }; diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 6911da630cb34..d9e50a1e1345e 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -1267,7 +1267,7 @@ pub trait StoragePrefixedMap { pub trait StorageAppend: private::Sealed {} /// Marker trait that will be implemented for types that support to decode their length in an -/// effificent way. It is expected that the length is at the beginning of the encoded object +/// efficient way. It is expected that the length is at the beginning of the encoded object /// and that the length is a `Compact`. /// /// This trait is sealed. diff --git a/frame/support/src/storage/transactional.rs b/frame/support/src/storage/transactional.rs index d1bdb30af947b..909d5909ed8bd 100644 --- a/frame/support/src/storage/transactional.rs +++ b/frame/support/src/storage/transactional.rs @@ -164,9 +164,9 @@ where /// Execute the supplied function, adding a new storage layer. /// -/// This is the same as `with_transaction`, but assuming that any function returning -/// an `Err` should rollback, and any function returning `Ok` should commit. This -/// provides a cleaner API to the developer who wants this behavior. +/// This is the same as `with_transaction`, but assuming that any function returning an `Err` should +/// rollback, and any function returning `Ok` should commit. This provides a cleaner API to the +/// developer who wants this behavior. pub fn with_storage_layer(f: F) -> Result where E: From, diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index a2a6432485be8..5a3e97b4d5274 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -108,6 +108,9 @@ pub trait StakingInterface { validators: sp_std::vec::Vec, ) -> DispatchResult; + /// Chill `stash`. + fn chill(controller: Self::AccountId) -> DispatchResult; + /// Bond some extra amount in the _Stash_'s free balance against the active bonded balance of /// the account. The amount extra actually bonded will never be more than the _Stash_'s free /// balance. @@ -125,8 +128,14 @@ pub trait StakingInterface { fn unbond(stash: Self::AccountId, value: Self::Balance) -> DispatchResult; /// Unlock any funds schedule to unlock before or at the current era. + /// + /// Returns whether the stash was killed because of this withdraw or not. fn withdraw_unbonded( stash: Self::AccountId, num_slashing_spans: u32, - ) -> Result; + ) -> Result; + + /// Get the nominations of a stash, if they are a nominator, `None` otherwise. + #[cfg(feature = "runtime-benchmarks")] + fn nominations(who: Self::AccountId) -> Option>; } From 9a140a6190ae1527b89fe77bd426a38489526e44 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Tue, 14 Jun 2022 04:39:33 +0200 Subject: [PATCH 0910/1472] Properly implement Debug on bounded types (#11659) --- primitives/runtime/src/bounded/bounded_btree_map.rs | 7 +++---- primitives/runtime/src/bounded/bounded_btree_set.rs | 7 +++---- primitives/runtime/src/bounded/bounded_vec.rs | 2 +- primitives/runtime/src/bounded/weak_bounded_vec.rs | 7 +++---- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/primitives/runtime/src/bounded/bounded_btree_map.rs b/primitives/runtime/src/bounded/bounded_btree_map.rs index b9abf77f175c6..aefd168632a1e 100644 --- a/primitives/runtime/src/bounded/bounded_btree_map.rs +++ b/primitives/runtime/src/bounded/bounded_btree_map.rs @@ -182,13 +182,12 @@ where } } -#[cfg(feature = "std")] -impl std::fmt::Debug for BoundedBTreeMap +impl sp_std::fmt::Debug for BoundedBTreeMap where - BTreeMap: std::fmt::Debug, + BTreeMap: sp_std::fmt::Debug, S: Get, { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { f.debug_tuple("BoundedBTreeMap").field(&self.0).field(&Self::bound()).finish() } } diff --git a/primitives/runtime/src/bounded/bounded_btree_set.rs b/primitives/runtime/src/bounded/bounded_btree_set.rs index 0f8cc769e47e3..c19d176f11bef 100644 --- a/primitives/runtime/src/bounded/bounded_btree_set.rs +++ b/primitives/runtime/src/bounded/bounded_btree_set.rs @@ -159,13 +159,12 @@ where } } -#[cfg(feature = "std")] -impl std::fmt::Debug for BoundedBTreeSet +impl sp_std::fmt::Debug for BoundedBTreeSet where - BTreeSet: std::fmt::Debug, + BTreeSet: sp_std::fmt::Debug, S: Get, { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { f.debug_tuple("BoundedBTreeSet").field(&self.0).field(&Self::bound()).finish() } } diff --git a/primitives/runtime/src/bounded/bounded_vec.rs b/primitives/runtime/src/bounded/bounded_vec.rs index 84acddea47cab..555a34819a423 100644 --- a/primitives/runtime/src/bounded/bounded_vec.rs +++ b/primitives/runtime/src/bounded/bounded_vec.rs @@ -598,7 +598,7 @@ impl Default for BoundedVec { impl sp_std::fmt::Debug for BoundedVec where - T: sp_std::fmt::Debug, + Vec: sp_std::fmt::Debug, S: Get, { fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { diff --git a/primitives/runtime/src/bounded/weak_bounded_vec.rs b/primitives/runtime/src/bounded/weak_bounded_vec.rs index 82bae4118f13e..08460f7096357 100644 --- a/primitives/runtime/src/bounded/weak_bounded_vec.rs +++ b/primitives/runtime/src/bounded/weak_bounded_vec.rs @@ -168,13 +168,12 @@ impl Default for WeakBoundedVec { } } -#[cfg(feature = "std")] -impl std::fmt::Debug for WeakBoundedVec +impl sp_std::fmt::Debug for WeakBoundedVec where - T: std::fmt::Debug, + Vec: sp_std::fmt::Debug, S: Get, { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { f.debug_tuple("WeakBoundedVec").field(&self.0).field(&Self::bound()).finish() } } From abb80e54aa260514a4f12712a9ff8ef944e3b4ec Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 14 Jun 2022 10:17:58 +0200 Subject: [PATCH 0911/1472] remove flaky rpc subscription tests (#11653) --- client/beefy/rpc/src/lib.rs | 28 -------------------------- client/finality-grandpa/rpc/src/lib.rs | 27 ------------------------- 2 files changed, 55 deletions(-) diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index c248d33cb6c23..2c3ffda056c26 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -241,34 +241,6 @@ mod tests { ); } - #[tokio::test] - async fn subscribe_and_unsubscribe_to_justifications() { - let (rpc, _) = setup_io_handler(); - - // Subscribe call. - let sub = rpc - .subscribe("beefy_subscribeJustifications", EmptyParams::new()) - .await - .unwrap(); - - let ser_id = serde_json::to_string(sub.subscription_id()).unwrap(); - - // Unsubscribe - let unsub_req = format!( - "{{\"jsonrpc\":\"2.0\",\"method\":\"beefy_unsubscribeJustifications\",\"params\":[{}],\"id\":1}}", - ser_id - ); - let (response, _) = rpc.raw_json_request(&unsub_req).await.unwrap(); - - assert_eq!(response, r#"{"jsonrpc":"2.0","result":true,"id":1}"#); - - // Unsubscribe again and fail - let (response, _) = rpc.raw_json_request(&unsub_req).await.unwrap(); - let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; - - assert_eq!(response, expected); - } - #[tokio::test] async fn subscribe_and_unsubscribe_with_wrong_id() { let (rpc, _) = setup_io_handler(); diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index bdb86c125e20a..1cf23a18c794b 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -310,33 +310,6 @@ mod tests { assert_eq!(expected_response, result); } - #[tokio::test] - async fn subscribe_and_unsubscribe_to_justifications() { - let (rpc, _) = setup_io_handler(TestVoterState); - // Subscribe call. - let sub = rpc - .subscribe("grandpa_subscribeJustifications", EmptyParams::new()) - .await - .unwrap(); - - let ser_id = serde_json::to_string(sub.subscription_id()).unwrap(); - - // Unsubscribe - let unsub_req = format!( - "{{\"jsonrpc\":\"2.0\",\"method\":\"grandpa_unsubscribeJustifications\",\"params\":[{}],\"id\":1}}", - ser_id - ); - let (response, _) = rpc.raw_json_request(&unsub_req).await.unwrap(); - - assert_eq!(response, r#"{"jsonrpc":"2.0","result":true,"id":1}"#); - - // Unsubscribe again and fail - let (response, _) = rpc.raw_json_request(&unsub_req).await.unwrap(); - let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; - - assert_eq!(response, expected); - } - #[tokio::test] async fn subscribe_and_unsubscribe_with_wrong_id() { let (rpc, _) = setup_io_handler(TestVoterState); From 2951d340841523f6897e55e7a613b0fd0e1c7380 Mon Sep 17 00:00:00 2001 From: bear Date: Tue, 14 Jun 2022 16:48:49 +0800 Subject: [PATCH 0912/1472] Add `TypeInfo` (#11599) --- primitives/runtime/src/transaction_validity.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/primitives/runtime/src/transaction_validity.rs b/primitives/runtime/src/transaction_validity.rs index 29c8b542319b1..7cc8b70df9f96 100644 --- a/primitives/runtime/src/transaction_validity.rs +++ b/primitives/runtime/src/transaction_validity.rs @@ -21,6 +21,7 @@ use crate::{ codec::{Decode, Encode}, RuntimeDebug, }; +use scale_info::TypeInfo; use sp_std::prelude::*; /// Priority for a transaction. Additive. Higher is better. @@ -34,7 +35,7 @@ pub type TransactionLongevity = u64; pub type TransactionTag = Vec; /// An invalid transaction validity. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub enum InvalidTransaction { /// The call of the transaction is not expected. @@ -117,7 +118,7 @@ impl From for &'static str { } /// An unknown transaction validity. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub enum UnknownTransaction { /// Could not lookup some information that is required to validate the transaction. @@ -141,7 +142,7 @@ impl From for &'static str { } /// Errors that can occur while checking the validity of a transaction. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub enum TransactionValidityError { /// The transaction is invalid. From b511370572ac5689044779584a354a3d4ede1840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 14 Jun 2022 11:21:44 +0200 Subject: [PATCH 0913/1472] wasm-builder: Fix constant re-running of `build.rs` scripts. (#11624) Recently we added the wasm binaries to the `rerun-if-changed` list. The problem with that is that they have a later mtime than the `invoked.timestamp` file and this file's mtime is used to determine if the `build.rs` script needs to be re-run. The solution to this is that we copy the mtime of this `invoked.timestamp` file and add it to the wasm binaries. Then cargo/rustc doesn't constantly wants to rerun the `build.rs` script. --- Cargo.lock | 13 +++++++++++ utils/wasm-builder/Cargo.toml | 1 + utils/wasm-builder/src/wasm_project.rs | 32 ++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index ae0a497867b51..4f74660e67240 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2007,6 +2007,18 @@ dependencies = [ "log", ] +[[package]] +name = "filetime" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "winapi", +] + [[package]] name = "finality-grandpa" version = "0.15.0" @@ -10648,6 +10660,7 @@ dependencies = [ "ansi_term", "build-helper", "cargo_metadata", + "filetime", "sp-maybe-compressed-blob", "strum", "tempfile", diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index 0cd1249628f22..8f887e45ec176 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -22,3 +22,4 @@ toml = "0.5.4" walkdir = "2.3.2" wasm-gc-api = "0.1.11" sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } +filetime = "0.2.16" diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 4316f9041f11d..be84f2fecfb53 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -152,9 +152,41 @@ pub(crate) fn create_and_compile( &bloaty, ); + if let Err(err) = adjust_mtime(&bloaty, final_wasm_binary.as_ref()) { + build_helper::warning!("Error while adjusting the mtime of the wasm binaries: {}", err) + } + (final_wasm_binary, bloaty) } +/// Adjust the mtime of the bloaty and compressed/compact wasm files. +/// +/// We add the bloaty and the compressed/compact wasm file to the `rerun-if-changed` files. +/// Cargo/Rustc determines based on the timestamp of the `invoked.timestamp` file that can be found +/// in the `OUT_DIR/..`, if it needs to rerun a `build.rs` script. The problem is that this +/// `invoked.timestamp` is created when the `build.rs` is executed and the wasm binaries are created +/// later. This leads to them having a later mtime than the `invoked.timestamp` file and thus, +/// cargo/rustc always re-executes the `build.rs` script. To hack around this, we copy the mtime of +/// the `invoked.timestamp` to the wasm binaries. +fn adjust_mtime( + bloaty_wasm: &WasmBinaryBloaty, + compressed_or_compact_wasm: Option<&WasmBinary>, +) -> std::io::Result<()> { + let out_dir = build_helper::out_dir(); + let invoked_timestamp = out_dir.join("../invoked.timestamp"); + + // Get the mtime of the `invoked.timestamp` + let metadata = fs::metadata(invoked_timestamp)?; + let mtime = filetime::FileTime::from_last_modification_time(&metadata); + + filetime::set_file_mtime(bloaty_wasm.wasm_binary_bloaty_path(), mtime)?; + if let Some(binary) = compressed_or_compact_wasm.as_ref() { + filetime::set_file_mtime(binary.wasm_binary_path(), mtime)?; + } + + Ok(()) +} + /// Find the `Cargo.lock` relative to the `OUT_DIR` environment variable. /// /// If the `Cargo.lock` cannot be found, we emit a warning and return `None`. From 5325d59a5bc0af7c05cb1b9e08486c4d81a47f96 Mon Sep 17 00:00:00 2001 From: Leonardo <14614620+aardbol@users.noreply.github.com> Date: Tue, 14 Jun 2022 11:42:28 +0200 Subject: [PATCH 0914/1472] Increment subkey version to 2.0.2 (#11656) * Increment subkey version to 2.0.2 * Update Cargo.lock Co-authored-by: Davide Galassi --- Cargo.lock | 2 +- bin/utils/subkey/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f74660e67240..10d34da9cf888 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10406,7 +10406,7 @@ dependencies = [ [[package]] name = "subkey" -version = "2.0.1" +version = "2.0.2" dependencies = [ "clap 3.1.18", "sc-cli", diff --git a/bin/utils/subkey/Cargo.toml b/bin/utils/subkey/Cargo.toml index 26bc949b74ae7..4c4e47e702be6 100644 --- a/bin/utils/subkey/Cargo.toml +++ b/bin/utils/subkey/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subkey" -version = "2.0.1" +version = "2.0.2" authors = ["Parity Technologies "] edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" From 5abf6c8a015fac28d33967800da7c5c8d53002e3 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 14 Jun 2022 11:42:52 +0200 Subject: [PATCH 0915/1472] Implement `Deref` for `BoundedSlice` (#11660) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Impl Deref for BoundedSlice Signed-off-by: Oliver Tale-Yazdi * Update primitives/runtime/src/bounded/bounded_vec.rs Co-authored-by: Keith Yeung Co-authored-by: Bastian Köcher Co-authored-by: Keith Yeung --- primitives/runtime/src/bounded/bounded_vec.rs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/primitives/runtime/src/bounded/bounded_vec.rs b/primitives/runtime/src/bounded/bounded_vec.rs index 555a34819a423..c9c9f851d3249 100644 --- a/primitives/runtime/src/bounded/bounded_vec.rs +++ b/primitives/runtime/src/bounded/bounded_vec.rs @@ -223,6 +223,15 @@ impl<'a, T, S> Clone for BoundedSlice<'a, T, S> { // Since a reference `&T` is always `Copy`, so is `BoundedSlice<'a, T, S>`. impl<'a, T, S> Copy for BoundedSlice<'a, T, S> {} +// will allow for all immutable operations of `[T]` on `BoundedSlice`. +impl<'a, T, S> Deref for BoundedSlice<'a, T, S> { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + self.0 + } +} + impl<'a, T, S> sp_std::iter::IntoIterator for BoundedSlice<'a, T, S> { type Item = &'a T; type IntoIter = sp_std::slice::Iter<'a, T>; @@ -647,7 +656,7 @@ impl AsMut<[T]> for BoundedVec { } } -// will allow for immutable all operations of `Vec` on `BoundedVec`. +// will allow for all immutable operations of `Vec` on `BoundedVec`. impl Deref for BoundedVec { type Target = Vec; @@ -970,7 +979,7 @@ pub mod test { } #[test] - fn deref_coercion_works() { + fn deref_vec_coercion_works() { let bounded: BoundedVec> = bounded_vec![1, 2, 3]; // these methods come from deref-ed vec. assert_eq!(bounded.len(), 3); @@ -978,6 +987,15 @@ pub mod test { assert!(!bounded.is_empty()); } + #[test] + fn deref_slice_coercion_works() { + let bounded = BoundedSlice::>::try_from(&[1, 2, 3][..]).unwrap(); + // these methods come from deref-ed slice. + assert_eq!(bounded.len(), 3); + assert!(bounded.iter().next().is_some()); + assert!(!bounded.is_empty()); + } + #[test] fn try_mutate_works() { let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; From 42655d235dc0d6ad711bf45a3e7dfdbfd89d76e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 14 Jun 2022 11:41:11 +0100 Subject: [PATCH 0916/1472] grandpa: fix creation of justification with equivocating precommits in commit (#11302) * grandpa: fix creation of justification ancestry we would reject commits that have precommits targeting blocks lower than the commit target. when there is an equivocation (or if it the commit is not minimal) it is possible to have such precommits and we should assume that they are the round base. * grandpa: bump to 0.16.0 * grandpa: add test for justification with equivocation * grandpa: fix failing test --- Cargo.lock | 8 +-- client/finality-grandpa/Cargo.toml | 4 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/finality-grandpa/src/finality_proof.rs | 9 ++- client/finality-grandpa/src/justification.rs | 49 ++++++++++++-- client/finality-grandpa/src/observer.rs | 2 +- client/finality-grandpa/src/tests.rs | 67 +++++++++++++++++++ frame/grandpa/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- 9 files changed, 125 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10d34da9cf888..cf56bf0703246 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2021,9 +2021,9 @@ dependencies = [ [[package]] name = "finality-grandpa" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9def033d8505edf199f6a5d07aa7e6d2d6185b164293b77f0efd108f4f3e11d" +checksum = "b22349c6a11563a202d95772a68e0fcf56119e74ea8a2a19cf2301460fcd0df5" dependencies = [ "either", "futures", @@ -2031,7 +2031,7 @@ dependencies = [ "log", "num-traits", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "rand 0.8.4", "scale-info", ] @@ -11242,7 +11242,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "digest 0.10.3", "rand 0.8.4", "static_assertions", diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 2f7fcd4d052b1..77cd847d48169 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] ahash = "0.7.6" async-trait = "0.1.50" dyn-clone = "1.0" -finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } +finality-grandpa = { version = "0.16.0", features = ["derive-codec"] } futures = "0.3.21" futures-timer = "3.0.1" hex = "0.4.2" @@ -50,7 +50,7 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3.0" -finality-grandpa = { version = "0.15.0", features = [ +finality-grandpa = { version = "0.16.0", features = [ "derive-codec", "test-helpers", ] } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 0648c874f7dff..e8a3f24006e22 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" homepage = "https://substrate.io" [dependencies] -finality-grandpa = { version = "0.15.0", features = ["derive-codec"] } +finality-grandpa = { version = "0.16.0", features = ["derive-codec"] } futures = "0.3.16" jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } log = "0.4.8" diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index 03a4f2ff450a3..ac243a1633ee1 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -237,7 +237,7 @@ where } #[cfg(test)] -pub(crate) mod tests { +mod tests { use super::*; use crate::{authorities::AuthoritySetChanges, BlockNumberOps, ClientError, SetId}; use futures::executor::block_on; @@ -271,6 +271,7 @@ pub(crate) mod tests { let justification: GrandpaJustification = Decode::decode(&mut &proof.justification[..]) .map_err(|_| ClientError::JustificationDecode)?; + justification.verify(current_set_id, ¤t_authorities)?; Ok(proof) @@ -370,7 +371,7 @@ pub(crate) mod tests { #[test] fn finality_proof_check_fails_with_incomplete_justification() { - let (client, _, blocks) = test_blockchain(8, &[4, 5, 8]); + let (_, _, blocks) = test_blockchain(8, &[4, 5, 8]); // Create a commit without precommits let commit = finality_grandpa::Commit { @@ -378,7 +379,9 @@ pub(crate) mod tests { target_number: *blocks[7].header().number(), precommits: Vec::new(), }; - let grandpa_just = GrandpaJustification::from_commit(&client, 8, commit).unwrap(); + + let grandpa_just = + GrandpaJustification:: { round: 8, votes_ancestries: Vec::new(), commit }; let finality_proof = FinalityProof { block: header(2).hash(), diff --git a/client/finality-grandpa/src/justification.rs b/client/finality-grandpa/src/justification.rs index 39f24cb8ea57d..44abb4b95beba 100644 --- a/client/finality-grandpa/src/justification.rs +++ b/client/finality-grandpa/src/justification.rs @@ -42,9 +42,9 @@ use crate::{AuthorityList, Commit, Error}; /// nodes, and are used by syncing nodes to prove authority set handoffs. #[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)] pub struct GrandpaJustification { - round: u64, + pub(crate) round: u64, pub(crate) commit: Commit, - votes_ancestries: Vec, + pub(crate) votes_ancestries: Vec, } impl GrandpaJustification { @@ -66,16 +66,33 @@ impl GrandpaJustification { Err(Error::Client(ClientError::BadJustification(msg))) }; + // we pick the precommit for the lowest block as the base that + // should serve as the root block for populating ancestry (i.e. + // collect all headers from all precommit blocks to the base) + let (base_hash, base_number) = match commit + .precommits + .iter() + .map(|signed| &signed.precommit) + .min_by_key(|precommit| precommit.target_number) + .map(|precommit| (precommit.target_hash.clone(), precommit.target_number)) + { + None => return error(), + Some(base) => base, + }; + for signed in commit.precommits.iter() { let mut current_hash = signed.precommit.target_hash; loop { - if current_hash == commit.target_hash { + if current_hash == base_hash { break } match client.header(BlockId::Hash(current_hash))? { Some(current_header) => { - if *current_header.number() <= commit.target_number { + // NOTE: this should never happen as we pick the lowest block + // as base and only traverse backwards from the other blocks + // in the commit. but better be safe to avoid an unbound loop. + if *current_header.number() <= base_number { return error() } @@ -83,6 +100,7 @@ impl GrandpaJustification { if votes_ancestries_hashes.insert(current_hash) { votes_ancestries.push(current_header); } + current_hash = parent_hash; }, _ => return error(), @@ -142,13 +160,30 @@ impl GrandpaJustification { let ancestry_chain = AncestryChain::::new(&self.votes_ancestries); match finality_grandpa::validate_commit(&self.commit, voters, &ancestry_chain) { - Ok(ref result) if result.ghost().is_some() => {}, + Ok(ref result) if result.is_valid() => {}, _ => { let msg = "invalid commit in grandpa justification".to_string(); return Err(ClientError::BadJustification(msg)) }, } + // we pick the precommit for the lowest block as the base that + // should serve as the root block for populating ancestry (i.e. + // collect all headers from all precommit blocks to the base) + let base_hash = self + .commit + .precommits + .iter() + .map(|signed| &signed.precommit) + .min_by_key(|precommit| precommit.target_number) + .map(|precommit| precommit.target_hash.clone()) + .expect( + "can only fail if precommits is empty; \ + commit has been validated above; \ + valid commits must include precommits; \ + qed.", + ); + let mut buf = Vec::new(); let mut visited_hashes = HashSet::new(); for signed in self.commit.precommits.iter() { @@ -165,11 +200,11 @@ impl GrandpaJustification { )) } - if self.commit.target_hash == signed.precommit.target_hash { + if base_hash == signed.precommit.target_hash { continue } - match ancestry_chain.ancestry(self.commit.target_hash, signed.precommit.target_hash) { + match ancestry_chain.ancestry(base_hash, signed.precommit.target_hash) { Ok(route) => { // ancestry starts from parent hash but the precommit target hash has been // visited diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 7516fbb681c4b..85d80dcfe7cde 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -116,7 +116,7 @@ where Err(e) => return future::err(e.into()), }; - if validation_result.ghost().is_some() { + if validation_result.is_valid() { let finalized_hash = commit.target_hash; let finalized_number = commit.target_number; diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 5083cbfc21d1d..2d12232b04f15 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -1569,6 +1569,73 @@ fn grandpa_environment_never_overwrites_round_voter_state() { assert_matches!(get_current_round(2).unwrap(), HasVoted::Yes(_, _)); } +#[test] +fn justification_with_equivocation() { + use sp_application_crypto::Pair; + + // we have 100 authorities + let pairs = (0..100).map(|n| AuthorityPair::from_seed(&[n; 32])).collect::>(); + let voters = pairs.iter().map(AuthorityPair::public).map(|id| (id, 1)).collect::>(); + let api = TestApi::new(voters.clone()); + let mut net = GrandpaTestNet::new(api.clone(), 1, 0); + + // we create a basic chain with 3 blocks (no forks) + net.peer(0).push_blocks(3, false); + + let client = net.peer(0).client().clone(); + let block1 = client.header(&BlockId::Number(1)).ok().flatten().unwrap(); + let block2 = client.header(&BlockId::Number(2)).ok().flatten().unwrap(); + let block3 = client.header(&BlockId::Number(3)).ok().flatten().unwrap(); + + let set_id = 0; + let justification = { + let round = 1; + + let make_precommit = |target_hash, target_number, pair: &AuthorityPair| { + let precommit = finality_grandpa::Precommit { target_hash, target_number }; + + let msg = finality_grandpa::Message::Precommit(precommit.clone()); + let encoded = sp_finality_grandpa::localized_payload(round, set_id, &msg); + + let precommit = finality_grandpa::SignedPrecommit { + precommit: precommit.clone(), + signature: pair.sign(&encoded[..]), + id: pair.public(), + }; + + precommit + }; + + let mut precommits = Vec::new(); + + // we have 66/100 votes for block #3 and therefore do not have threshold to finalize + for pair in pairs.iter().take(66) { + let precommit = make_precommit(block3.hash(), *block3.number(), pair); + precommits.push(precommit); + } + + // we create an equivocation for the 67th validator targetting blocks #1 and #2. + // this should be accounted as "voting for all blocks" and therefore block #3 will + // have 67/100 votes, reaching finality threshold. + { + precommits.push(make_precommit(block1.hash(), *block1.number(), &pairs[66])); + precommits.push(make_precommit(block2.hash(), *block2.number(), &pairs[66])); + } + + let commit = finality_grandpa::Commit { + target_hash: block3.hash(), + target_number: *block3.number(), + precommits, + }; + + GrandpaJustification::from_commit(&client.as_client(), round, commit).unwrap() + }; + + // the justification should include the minimal necessary vote ancestry and + // the commit should be valid + assert!(justification.verify(set_id, &voters).is_ok()); +} + #[test] fn imports_justification_for_regular_blocks_on_import() { // NOTE: this is a regression test since initially we would only import diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index cb4233a26fb33..2090a4ea2e228 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -31,7 +31,7 @@ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../pr sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -grandpa = { package = "finality-grandpa", version = "0.15.0", features = ["derive-codec"] } +grandpa = { package = "finality-grandpa", version = "0.16.0", features = ["derive-codec"] } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index f86e2ab07e673..32945eacf0b93 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -grandpa = { package = "finality-grandpa", version = "0.15.0", default-features = false, features = ["derive-codec"] } +grandpa = { package = "finality-grandpa", version = "0.16.0", default-features = false, features = ["derive-codec"] } log = { version = "0.4.17", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } From 292c66c0ae3bfa057121b4fc61eb6afd9da04116 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Tue, 14 Jun 2022 19:55:56 +0300 Subject: [PATCH 0917/1472] Make it possible to disable RocksDB completely (#11537) * Make it possible to disable RocksDB completely * Make ParityDB non-optional * Address review comments --- bin/node/cli/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 11 ++++----- client/cli/Cargo.toml | 4 +++- client/cli/src/arg_enums.rs | 21 ++++++++++++----- client/cli/src/config.rs | 12 +++++++++- client/db/Cargo.toml | 5 ++-- client/db/src/lib.rs | 18 ++++++++------ client/db/src/utils.rs | 31 ++++--------------------- client/service/Cargo.toml | 4 ++-- test-utils/client/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 9 +++---- 11 files changed, 59 insertions(+), 60 deletions(-) diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index ab6644a379bb5..8f18aec891e9b 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -153,7 +153,7 @@ cli = [ "sc-cli", "frame-benchmarking-cli", "substrate-frame-cli", - "sc-service/db", + "sc-service/rocksdb", "clap", "clap_complete", "substrate-build-script-utils", diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index f7a78d10910b3..7caf10366b48c 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -22,21 +22,18 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } node-runtime = { version = "3.0.0-dev", path = "../runtime" } -pallet-asset-tx-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/asset-tx-payment/" } +pallet-asset-tx-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/asset-tx-payment" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } -sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } -sc-client-db = { version = "0.10.0-dev", features = [ - "kvdb-rocksdb", - "parity-db", -], path = "../../../client/db/" } +sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } +sc-client-db = { version = "0.10.0-dev", features = ["rocksdb"], path = "../../../client/db" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-executor = { version = "0.10.0-dev", features = [ "wasmtime", ], path = "../../../client/executor" } sc-service = { version = "0.10.0-dev", features = [ "test-helpers", - "db", + "rocksdb", ], path = "../../../client/service" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 456489e5f6639..4f0d777d137b9 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -31,7 +31,7 @@ thiserror = "1.0.30" tiny-bip39 = "0.8.2" tokio = { version = "1.17.0", features = ["signal", "rt-multi-thread", "parking_lot"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } -sc-client-db = { version = "0.10.0-dev", path = "../db" } +sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../db" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../service" } @@ -50,4 +50,6 @@ sp-version = { version = "5.0.0", path = "../../primitives/version" } tempfile = "3.1.0" [features] +default = ["rocksdb"] +rocksdb = ["sc-client-db/rocksdb"] wasmtime = ["sc-service/wasmtime"] diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index bc0989cf34659..283fef985dfb9 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -238,6 +238,7 @@ impl Into for RpcMethods { #[derive(Debug, Clone, PartialEq, Copy)] pub enum Database { /// Facebooks RocksDB + #[cfg(feature = "rocksdb")] RocksDb, /// ParityDb. ParityDb, @@ -252,12 +253,14 @@ impl std::str::FromStr for Database { type Err = String; fn from_str(s: &str) -> Result { + #[cfg(feature = "rocksdb")] if s.eq_ignore_ascii_case("rocksdb") { - Ok(Self::RocksDb) - } else if s.eq_ignore_ascii_case("paritydb-experimental") { - Ok(Self::ParityDbDeprecated) + return Ok(Self::RocksDb) + } + if s.eq_ignore_ascii_case("paritydb-experimental") { + return Ok(Self::ParityDbDeprecated) } else if s.eq_ignore_ascii_case("paritydb") { - Ok(Self::ParityDb) + return Ok(Self::ParityDb) } else if s.eq_ignore_ascii_case("auto") { Ok(Self::Auto) } else { @@ -268,8 +271,14 @@ impl std::str::FromStr for Database { impl Database { /// Returns all the variants of this enum to be shown in the cli. - pub fn variants() -> &'static [&'static str] { - &["rocksdb", "paritydb", "paritydb-experimental", "auto"] + pub const fn variants() -> &'static [&'static str] { + &[ + #[cfg(feature = "rocksdb")] + "rocksdb", + "paritydb", + "paritydb-experimental", + "auto", + ] } } diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 5e91cf6c74dae..6e1317c11fbc4 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -220,6 +220,7 @@ pub trait CliConfiguration: Sized { let rocksdb_path = base_path.join("db").join(role_dir); let paritydb_path = base_path.join("paritydb").join(role_dir); Ok(match database { + #[cfg(feature = "rocksdb")] Database::RocksDb => DatabaseSource::RocksDb { path: rocksdb_path, cache_size }, Database::ParityDb => DatabaseSource::ParityDb { path: paritydb_path }, Database::ParityDbDeprecated => { @@ -500,7 +501,16 @@ pub trait CliConfiguration: Sized { let net_config_dir = config_dir.join(DEFAULT_NETWORK_CONFIG_PATH); let client_id = C::client_id(); let database_cache_size = self.database_cache_size()?.unwrap_or(1024); - let database = self.database()?.unwrap_or(Database::RocksDb); + let database = self.database()?.unwrap_or( + #[cfg(feature = "rocksdb")] + { + Database::RocksDb + }, + #[cfg(not(feature = "rocksdb"))] + { + Database::ParityDb + }, + ); let node_key = self.node_key(&net_config_dir)?; let role = self.role(is_dev)?; let max_runtime_instances = self.max_runtime_instances()?.unwrap_or(8); diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index e1472bcbda01a..3b6402b3f6023 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -22,7 +22,7 @@ kvdb-memorydb = "0.11.0" kvdb-rocksdb = { version = "0.15.2", optional = true } linked-hash-map = "0.5.4" log = "0.4.17" -parity-db = { version = "0.3.13", optional = true } +parity-db = "0.3.13" parking_lot = "0.12.0" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } @@ -45,5 +45,4 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/ru default = [] test-helpers = [] runtime-benchmarks = [] -with-kvdb-rocksdb = ["kvdb-rocksdb"] -with-parity-db = ["parity-db"] +rocksdb = ["kvdb-rocksdb"] diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index ccdb434dfbd32..f1adbd3df1a0f 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -30,15 +30,13 @@ pub mod offchain; -#[cfg(any(feature = "with-kvdb-rocksdb", test))] pub mod bench; mod children; -#[cfg(feature = "with-parity-db")] mod parity_db; mod stats; mod storage_cache; -#[cfg(any(feature = "with-kvdb-rocksdb", test))] +#[cfg(any(feature = "rocksdb", test))] mod upgrade; mod utils; @@ -94,7 +92,6 @@ use sp_trie::{prefixed_key, MemoryDB, PrefixedMemoryDB}; pub use sc_state_db::PruningMode; pub use sp_database::Database; -#[cfg(any(feature = "with-kvdb-rocksdb", test))] pub use bench::BenchmarkingState; const CACHE_HEADERS: usize = 8; @@ -106,7 +103,6 @@ const DEFAULT_CHILD_RATIO: (usize, usize) = (1, 10); pub type DbState = sp_state_machine::TrieBackend>>, HashFor>; -#[cfg(feature = "with-parity-db")] /// Length of a [`DbHash`]. const DB_HASH_LEN: usize = 32; @@ -330,6 +326,7 @@ pub enum DatabaseSource { cache_size: usize, }, /// Load a RocksDB database from a given path. Recommended for most uses. + #[cfg(feature = "rocksdb")] RocksDb { /// Path to the database. path: PathBuf, @@ -362,7 +359,9 @@ impl DatabaseSource { // IIUC this is needed for polkadot to create its own dbs, so until it can use parity db // I would think rocksdb, but later parity-db. DatabaseSource::Auto { paritydb_path, .. } => Some(paritydb_path), - DatabaseSource::RocksDb { path, .. } | DatabaseSource::ParityDb { path } => Some(path), + #[cfg(feature = "rocksdb")] + DatabaseSource::RocksDb { path, .. } => Some(path), + DatabaseSource::ParityDb { path } => Some(path), DatabaseSource::Custom { .. } => None, } } @@ -374,7 +373,11 @@ impl DatabaseSource { *paritydb_path = p.into(); true }, - DatabaseSource::RocksDb { ref mut path, .. } | + #[cfg(feature = "rocksdb")] + DatabaseSource::RocksDb { ref mut path, .. } => { + *path = p.into(); + true + }, DatabaseSource::ParityDb { ref mut path } => { *path = p.into(); true @@ -388,6 +391,7 @@ impl std::fmt::Display for DatabaseSource { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name = match self { DatabaseSource::Auto { .. } => "Auto", + #[cfg(feature = "rocksdb")] DatabaseSource::RocksDb { .. } => "RocksDb", DatabaseSource::ParityDb { .. } => "ParityDb", DatabaseSource::Custom { .. } => "Custom", diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index 0227e4db8bcd0..567950d089e1b 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -34,12 +34,6 @@ use sp_trie::DBValue; /// Number of columns in the db. Must be the same for both full && light dbs. /// Otherwise RocksDb will fail to open database && check its type. -#[cfg(any( - feature = "with-kvdb-rocksdb", - feature = "with-parity-db", - feature = "test-helpers", - test -))] pub const NUM_COLUMNS: u32 = 13; /// Meta column. The set of keys in the column is shared by full && light storages. pub const COLUMN_META: u32 = 0; @@ -198,6 +192,7 @@ fn open_database_at( ) -> OpenDbResult { let db: Arc> = match &db_source { DatabaseSource::ParityDb { path } => open_parity_db::(path, db_type, create)?, + #[cfg(feature = "rocksdb")] DatabaseSource::RocksDb { path, cache_size } => open_kvdb_rocksdb::(path, db_type, create, *cache_size)?, DatabaseSource::Custom { db, require_create_flag } => { @@ -266,7 +261,6 @@ impl From for sp_blockchain::Error { } } -#[cfg(feature = "with-parity-db")] impl From for OpenDbError { fn from(err: parity_db::Error) -> Self { if matches!(err, parity_db::Error::DatabaseNotFound) { @@ -287,7 +281,6 @@ impl From for OpenDbError { } } -#[cfg(feature = "with-parity-db")] fn open_parity_db(path: &Path, db_type: DatabaseType, create: bool) -> OpenDbResult { match crate::parity_db::open(path, db_type, create, false) { Ok(db) => Ok(db), @@ -300,16 +293,7 @@ fn open_parity_db(path: &Path, db_type: DatabaseType, create: boo } } -#[cfg(not(feature = "with-parity-db"))] -fn open_parity_db( - _path: &Path, - _db_type: DatabaseType, - _create: bool, -) -> OpenDbResult { - Err(OpenDbError::NotEnabled("with-parity-db")) -} - -#[cfg(any(feature = "with-kvdb-rocksdb", test))] +#[cfg(any(feature = "rocksdb", test))] fn open_kvdb_rocksdb( path: &Path, db_type: DatabaseType, @@ -359,7 +343,7 @@ fn open_kvdb_rocksdb( Ok(sp_database::as_database(db)) } -#[cfg(not(any(feature = "with-kvdb-rocksdb", test)))] +#[cfg(not(any(feature = "rocksdb", test)))] fn open_kvdb_rocksdb( _path: &Path, _db_type: DatabaseType, @@ -602,7 +586,7 @@ mod tests { use std::path::PathBuf; type Block = RawBlock>; - #[cfg(any(feature = "with-kvdb-rocksdb", test))] + #[cfg(any(feature = "rocksdb", test))] #[test] fn database_type_subdir_migration() { type Block = RawBlock>; @@ -639,7 +623,6 @@ mod tests { "db_version", ); - #[cfg(feature = "with-parity-db")] check_dir_for_db_type( DatabaseType::Full, DatabaseSource::ParityDb { path: PathBuf::new() }, @@ -702,8 +685,6 @@ mod tests { assert_eq!(joined.remaining_len().unwrap(), Some(0)); } - #[cfg(feature = "with-parity-db")] - #[cfg(any(feature = "with-kvdb-rocksdb", test))] #[test] fn test_open_database_auto_new() { let db_dir = tempfile::TempDir::new().unwrap(); @@ -749,8 +730,6 @@ mod tests { } } - #[cfg(feature = "with-parity-db")] - #[cfg(any(feature = "with-kvdb-rocksdb", test))] #[test] fn test_open_database_rocksdb_new() { let db_dir = tempfile::TempDir::new().unwrap(); @@ -801,8 +780,6 @@ mod tests { } } - #[cfg(feature = "with-parity-db")] - #[cfg(any(feature = "with-kvdb-rocksdb", test))] #[test] fn test_open_database_paritydb_new() { let db_dir = tempfile::TempDir::new().unwrap(); diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 22bac652c30c4..c1cb9e459041b 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -13,10 +13,10 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [features] -default = ["db"] +default = ["rocksdb"] # The RocksDB feature activates the RocksDB database backend. If it is not activated, and you pass # a path to a database, an error will be produced at runtime. -db = ["sc-client-db/with-kvdb-rocksdb", "sc-client-db/with-parity-db"] +rocksdb = ["sc-client-db/rocksdb"] wasmtime = ["sc-executor/wasmtime"] # exposes the client type test-helpers = [] diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 1ff7d0de1d676..ce5ef2ffcc01a 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -19,7 +19,7 @@ hex = "0.4" serde = "1.0.136" serde_json = "1.0.79" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } -sc-client-db = { version = "0.10.0-dev", features = [ +sc-client-db = { version = "0.10.0-dev", default-features = false, features = [ "test-helpers", ], path = "../../client/db" } sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index c4549f5c5439d..ea26bf0c9261c 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -39,9 +39,9 @@ frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarkin frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } -sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } +sc-cli = { version = "0.10.0-dev", default-features = false, path = "../../../client/cli" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } -sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } +sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../../../client/db" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sc-sysinfo = { version = "6.0.0-dev", path = "../../../client/sysinfo" } @@ -59,5 +59,6 @@ sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } gethostname = "0.2.3" [features] -default = ["db", "sc-client-db/runtime-benchmarks"] -db = ["sc-client-db/with-kvdb-rocksdb", "sc-client-db/with-parity-db"] +default = ["rocksdb", "runtime-benchmarks"] +runtime-benchmarks = ["sc-client-db/runtime-benchmarks"] +rocksdb = ["sc-cli/rocksdb", "sc-client-db/rocksdb"] From 4037345b8c0491ae5b74fcb6d131b3ff304f0bed Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 14 Jun 2022 22:43:25 +0200 Subject: [PATCH 0918/1472] rpc servers: update jsonrpsee to fix host filtering + WS server-side pings (#11661) * bump jsonrpsee to fix #11480 In addition it adds WebSocket server-side pings which is configured to send out pings periodically every 30 seconds. * use released crates.io version * Update Cargo.toml --- Cargo.lock | 40 ++++++++++--------- bin/node-template/node/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/rpc/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc-servers/src/lib.rs | 22 +++++----- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- frame/contracts/rpc/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/transaction-payment/rpc/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 4 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 22 files changed, 55 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf56bf0703246..7027cfd44bcf4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3160,9 +3160,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae63f7fdeb51700b35e9b28bf92e8d233951590968c186ed79510b6c12fa3d9" +checksum = "11e017217fcd18da0a25296d3693153dd19c8a6aadab330b3595285d075385d1" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-server", @@ -3175,9 +3175,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32feb1f2f0b5ce37a03b96a988a6dadccc3f529a2f930356bac93f13c09cf385" +checksum = "ce395539a14d3ad4ec1256fde105abd36a2da25d578a291cabe98f45adfdb111" dependencies = [ "futures-util", "http", @@ -3196,9 +3196,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6b13067b615dd050ced7c19517a52cde490eee2c754d5447ce513f2275f7d" +checksum = "16efcd4477de857d4a2195a45769b2fe9ebb54f3ef5a4221d3b014a4fe33ec0b" dependencies = [ "anyhow", "arrayvec 0.7.1", @@ -3208,8 +3208,10 @@ dependencies = [ "futures-channel", "futures-timer", "futures-util", + "globset", "hyper", "jsonrpsee-types", + "lazy_static", "parking_lot 0.12.0", "rand 0.8.4", "rustc-hash", @@ -3219,32 +3221,31 @@ dependencies = [ "thiserror", "tokio", "tracing", + "unicase", ] [[package]] name = "jsonrpsee-http-server" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b34f1090bdc8f7f14ad8811fc84501867c23a9046ce79d49c0cd929a256c501e" +checksum = "bdd69efeb3ce2cba767f126872f4eeb4624038a29098e75d77608b2b4345ad03" dependencies = [ "futures-channel", "futures-util", - "globset", "hyper", "jsonrpsee-core", "jsonrpsee-types", - "lazy_static", + "serde", "serde_json", "tokio", "tracing", - "unicase", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8dc7a8b629e371cd5ca9d128883763ae00c5b63158ace4a6a61345726a21b7" +checksum = "874cf3f6a027cebf36cae767feca9aa2e8a8f799880e49eb5540819fcbd8eada" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3254,9 +3255,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f1835f131e77cd766b4dcb025873944cb1e479cd5debb639e2dc11f90df24a" +checksum = "3bcf76cd316f5d3ad48138085af1f45e2c58c98e02f0779783dbb034d43f7c86" dependencies = [ "anyhow", "beef", @@ -3268,9 +3269,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d75df866743c9733b3e2f5421e56df2f5b4630f7de39f82c44eaab350604926" +checksum = "ee043cb5dd0d51d3eb93432e998d5bae797691a7b10ec4a325e036bcdb48c48a" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -3279,9 +3280,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-server" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099971913436e7f6b1bc80180d4e5f014ec944660636da45d2f372c23d6308c3" +checksum = "2bd2e4d266774a671f8def3794255b28eddd09b18d76e0b913fa439f34588c0a" dependencies = [ "futures-channel", "futures-util", @@ -3290,6 +3291,7 @@ dependencies = [ "serde_json", "soketto", "tokio", + "tokio-stream", "tokio-util 0.7.1", "tracing", ] diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 8a6b041bbd518..c8e74ea9515ac 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -42,7 +42,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" } # These dependencies are used for the node template's RPCs -jsonrpsee = { version = "0.13.0", features = ["server"] } +jsonrpsee = { version = "0.14.0", features = ["server"] } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 8f18aec891e9b..b2e24f0b33189 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -37,7 +37,7 @@ crate-type = ["cdylib", "rlib"] clap = { version = "3.1.18", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } -jsonrpsee = { version = "0.13.0", features = ["server"] } +jsonrpsee = { version = "0.14.0", features = ["server"] } futures = "0.3.21" hex-literal = "0.3.4" log = "0.4.17" diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index ea6e8a5eb9c90..547d0df7a8372 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.13.0", features = ["server"] } +jsonrpsee = { version = "0.14.0", features = ["server"] } node-primitives = { version = "2.0.0", path = "../primitives" } pallet-contracts-rpc = { version = "4.0.0-dev", path = "../../../frame/contracts/rpc/" } pallet-mmr-rpc = { version = "3.0.0", path = "../../../frame/merkle-mountain-range/rpc/" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 98596c36f84d2..7d31aea3f6971 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://substrate.io" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" -jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } log = "0.4" parking_lot = "0.12.0" serde = { version = "1.0.136", features = ["derive"] } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 4fb45d3817036..4c9350735d529 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } futures = "0.3.21" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0" diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index dbc7c29c7f300..7aa2232178f22 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } assert_matches = "1.3.0" async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index e8a3f24006e22..f2d37da058f45 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" [dependencies] finality-grandpa = { version = "0.16.0", features = ["derive-codec"] } futures = "0.3.16" -jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } log = "0.4.8" parity-scale-codec = { version = "3.0.0", features = ["derive"] } serde = { version = "1.0.105", features = ["derive"] } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index f63f8ee65fbec..3425ba2b245df 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -28,4 +28,4 @@ sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-version = { version = "5.0.0", path = "../../primitives/version" } -jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index f5cd943b24e09..daaa955839045 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" -jsonrpsee = { version = "0.13.0", features = ["server"] } +jsonrpsee = { version = "0.14.0", features = ["server"] } log = "0.4.17" serde_json = "1.0.79" tokio = { version = "1.17.0", features = ["parking_lot"] } diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 78b8e16f8f13d..68b4aa6767348 100644 --- a/client/rpc-servers/src/lib.rs +++ b/client/rpc-servers/src/lib.rs @@ -103,7 +103,7 @@ pub async fn start_http( .max_request_body_size(max_payload_in as u32) .max_response_body_size(max_payload_out as u32) .set_access_control(acl.build()) - .health_api("/health", "system_health") + .health_api("/health", "system_health")? .custom_tokio_runtime(rt); let rpc_api = build_rpc_api(rpc_api); @@ -141,12 +141,23 @@ pub async fn start_ws( let (max_payload_in, max_payload_out, max_connections, max_subs_per_conn) = ws_config.deconstruct(); + let mut acl = AccessControlBuilder::new(); + + if let Some(cors) = cors { + // Whitelist listening address. + // NOTE: set_allowed_hosts will whitelist both ports but only one will used. + acl = acl.set_allowed_hosts(format_allowed_hosts(&addrs[..]))?; + acl = acl.set_allowed_origins(cors)?; + }; + let mut builder = WsServerBuilder::new() .max_request_body_size(max_payload_in) .max_response_body_size(max_payload_out) .max_connections(max_connections) .max_subscriptions_per_connection(max_subs_per_conn) - .custom_tokio_runtime(rt); + .ping_interval(std::time::Duration::from_secs(30)) + .custom_tokio_runtime(rt) + .set_access_control(acl.build()); if let Some(provider) = id_provider { builder = builder.set_id_provider(provider); @@ -154,13 +165,6 @@ pub async fn start_ws( builder = builder.set_id_provider(RandomStringIdProvider::new(16)); }; - if let Some(cors) = cors { - // Whitelist listening address. - // NOTE: set_allowed_hosts will whitelist both ports but only one will used. - builder = builder.set_allowed_hosts(format_allowed_hosts(&addrs[..]))?; - builder = builder.set_allowed_origins(cors)?; - } - let rpc_api = build_rpc_api(rpc_api); let (handle, addr) = if let Some(metrics) = metrics { let middleware = RpcMiddleware::new(metrics, "ws".into()); diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index f783ce8a94fb7..e8c657f1a2949 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } -jsonrpsee = { version = "0.13.0", features = ["server"] } +jsonrpsee = { version = "0.14.0", features = ["server"] } lazy_static = { version = "1.4.0", optional = true } log = "0.4.17" parking_lot = "0.12.0" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index c1cb9e459041b..ff11dd1344d01 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -22,7 +22,7 @@ wasmtime = ["sc-executor/wasmtime"] test-helpers = [] [dependencies] -jsonrpsee = { version = "0.13.0", features = ["server"] } +jsonrpsee = { version = "0.14.0", features = ["server"] } thiserror = "1.0.30" futures = "0.3.21" rand = "0.7.3" diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 3a2da48907a36..bd9194092fa3d 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" thiserror = "1.0.30" diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index c8777d50b90a1..a81abef9f37ca 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } serde = { version = "1", features = ["derive"] } # Substrate Dependencies diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 75238e5e329eb..45cb975df277b 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index f58049a0062ab..31e0972a0d5b5 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index a0adb8edb2d67..a77d090246421 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } env_logger = "0.9" -jsonrpsee = { version = "0.13.0", features = ["ws-client", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["ws-client", "macros"] } log = "0.4.17" serde = "1.0.136" serde_json = "1.0" diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index f4fbb1acbc0b1..6c6bc5cf327b5 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -25,7 +25,7 @@ sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } trie-db = { version = "0.23.1" } -jsonrpsee = { version = "0.13.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } # Substrate Dependencies sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index b19c3f235c7c7..7ea07534e1bdb 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -jsonrpsee = { version = "0.13.0", features = ["jsonrpsee-types"] } +jsonrpsee = { version = "0.14.0", features = ["jsonrpsee-types"] } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } @@ -25,6 +25,6 @@ sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } [dev-dependencies] scale-info = "2.1.1" -jsonrpsee = { version = "0.13.0", features = ["ws-client", "jsonrpsee-types"] } +jsonrpsee = { version = "0.14.0", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.17.0" frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 5f28c4e16231b..f76944a0fec40 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde_json = "1" codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.13.0", features = ["server"] } +jsonrpsee = { version = "0.14.0", features = ["server"] } futures = "0.3.21" log = "0.4.17" frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index a357378dc1903..a2d6eba3d8bfc 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -19,7 +19,7 @@ parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = { version = "0.10.0", default-features = false } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } -jsonrpsee = { version = "0.13.0", default-features = false, features = ["ws-client"] } +jsonrpsee = { version = "0.14.0", default-features = false, features = ["ws-client"] } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } From a9d055d55b310373b17076b9ed079a5a9b878bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 14 Jun 2022 23:22:16 +0200 Subject: [PATCH 0919/1472] Include the chain specs instead of trying to open them by path (#11625) This makes it possible to run the tests manually, without them expecting to be run in a special folder etc. --- client/beefy/src/tests.rs | 6 +++--- client/finality-grandpa/src/communication/tests.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 1d035a6a447c2..b5ff27c808908 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -75,9 +75,9 @@ impl BuildStorage for Genesis { #[test] fn beefy_protocol_name() { - let chain_spec = GenericChainSpec::::from_json_file(std::path::PathBuf::from( - "../chain-spec/res/chain_spec.json", - )) + let chain_spec = GenericChainSpec::::from_json_bytes( + &include_bytes!("../../chain-spec/res/chain_spec.json")[..], + ) .unwrap() .cloned_box(); diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index e41d21fc0684e..0ec5092a2a047 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -551,9 +551,9 @@ fn local_chain_spec() -> Box { Ok(()) } } - let chain_spec = GenericChainSpec::::from_json_file(std::path::PathBuf::from( - "../chain-spec/res/chain_spec.json", - )) + let chain_spec = GenericChainSpec::::from_json_bytes( + &include_bytes!("../../../chain-spec/res/chain_spec.json")[..], + ) .unwrap(); chain_spec.cloned_box() } From f589922b7ff081f07d7e89b80bbd35bebc33f5e9 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 15 Jun 2022 23:12:26 +0200 Subject: [PATCH 0920/1472] Remove `without_storage_info` from pallet `transaction-storage` (#11668) * Introduce BoundedVec * Fix typos * Add comments to the bounds * Remove migration * Improve bound value access syntax --- Cargo.lock | 1 + bin/node/runtime/src/lib.rs | 5 +- frame/transaction-storage/Cargo.toml | 1 + frame/transaction-storage/src/benchmarking.rs | 10 +-- frame/transaction-storage/src/lib.rs | 80 ++++++++++--------- frame/transaction-storage/src/mock.rs | 10 ++- 6 files changed, 59 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7027cfd44bcf4..fdcd450454629 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6413,6 +6413,7 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", + "log", "pallet-balances", "parity-scale-codec", "scale-info", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 6f3df7416681e..8987439db8e94 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1478,6 +1478,10 @@ impl pallet_transaction_storage::Config for Runtime { type Call = Call; type FeeDestination = (); type WeightInfo = pallet_transaction_storage::weights::SubstrateWeight; + type MaxBlockTransactions = + ConstU32<{ pallet_transaction_storage::DEFAULT_MAX_BLOCK_TRANSACTIONS }>; + type MaxTransactionSize = + ConstU32<{ pallet_transaction_storage::DEFAULT_MAX_TRANSACTION_SIZE }>; } impl pallet_whitelist::Config for Runtime { @@ -1674,7 +1678,6 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - (), >; /// MMR helper types. diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index a5195c4f75974..f001ef6acd468 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -26,6 +26,7 @@ sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-storage-proof" } +log = { version = "0.4.17", default-features = false } [dev-dependencies] sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs index 285b5cba7ad22..83dd37922a31f 100644 --- a/frame/transaction-storage/src/benchmarking.rs +++ b/frame/transaction-storage/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use frame_benchmarking::{benchmarks, whitelisted_caller}; -use frame_support::traits::{Currency, OnFinalize, OnInitialize}; +use frame_support::traits::{Currency, Get, OnFinalize, OnInitialize}; use frame_system::{EventRecord, Pallet as System, RawOrigin}; use sp_runtime::traits::{Bounded, One, Zero}; use sp_std::*; @@ -126,7 +126,7 @@ pub fn run_to_block(n: T::BlockNumber) { benchmarks! { store { - let l in 1 .. MaxTransactionSize::::get(); + let l in 1 .. T::MaxTransactionSize::get(); let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); }: _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize]) @@ -140,7 +140,7 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); TransactionStorage::::store( RawOrigin::Signed(caller.clone()).into(), - vec![0u8; MaxTransactionSize::::get() as usize], + vec![0u8; T::MaxTransactionSize::get() as usize], )?; run_to_block::(1u32.into()); }: _(RawOrigin::Signed(caller.clone()), T::BlockNumber::zero(), 0) @@ -152,10 +152,10 @@ benchmarks! { run_to_block::(1u32.into()); let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - for _ in 0 .. MaxBlockTransactions::::get() { + for _ in 0 .. T::MaxBlockTransactions::get() { TransactionStorage::::store( RawOrigin::Signed(caller.clone()).into(), - vec![0u8; MaxTransactionSize::::get() as usize], + vec![0u8; T::MaxTransactionSize::get() as usize], )?; } run_to_block::(StoragePeriod::::get() + T::BlockNumber::one()); diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index a63b31f2f1aac..f16b8f029662b 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -28,7 +28,7 @@ mod mock; #[cfg(test)] mod tests; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::{Dispatchable, GetDispatchInfo}, traits::{Currency, OnUnbalanced, ReservableCurrency}, @@ -57,7 +57,16 @@ pub const DEFAULT_MAX_TRANSACTION_SIZE: u32 = 8 * 1024 * 1024; pub const DEFAULT_MAX_BLOCK_TRANSACTIONS: u32 = 512; /// State data for a stored transaction. -#[derive(Encode, Decode, Clone, sp_runtime::RuntimeDebug, PartialEq, Eq, scale_info::TypeInfo)] +#[derive( + Encode, + Decode, + Clone, + sp_runtime::RuntimeDebug, + PartialEq, + Eq, + scale_info::TypeInfo, + MaxEncodedLen, +)] pub struct TransactionInfo { /// Chunk trie root. chunk_root: ::Output, @@ -95,6 +104,10 @@ pub mod pallet { type FeeDestination: OnUnbalanced>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + /// Maximum number of indexed transactions in the block. + type MaxBlockTransactions: Get; + /// Maximum data set in a single transaction in bytes. + type MaxTransactionSize: Get; } #[pallet::error] @@ -129,7 +142,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] @@ -180,7 +192,7 @@ pub mod pallet { pub fn store(origin: OriginFor, data: Vec) -> DispatchResult { ensure!(data.len() > 0, Error::::EmptyTransaction); ensure!( - data.len() <= MaxTransactionSize::::get() as usize, + data.len() <= T::MaxTransactionSize::get() as usize, Error::::TransactionTooLarge ); let sender = ensure_signed(origin)?; @@ -198,17 +210,19 @@ pub mod pallet { let mut index = 0; >::mutate(|transactions| { - if transactions.len() + 1 > MaxBlockTransactions::::get() as usize { + if transactions.len() + 1 > T::MaxBlockTransactions::get() as usize { return Err(Error::::TooManyTransactions) } let total_chunks = transactions.last().map_or(0, |t| t.block_chunks) + chunk_count; index = transactions.len() as u32; - transactions.push(TransactionInfo { - chunk_root: root, - size: data.len() as u32, - content_hash: content_hash.into(), - block_chunks: total_chunks, - }); + transactions + .try_push(TransactionInfo { + chunk_root: root, + size: data.len() as u32, + content_hash: content_hash.into(), + block_chunks: total_chunks, + }) + .map_err(|_| Error::::TooManyTransactions)?; Ok(()) })?; Self::deposit_event(Event::Stored { index }); @@ -238,19 +252,20 @@ pub mod pallet { let mut index = 0; >::mutate(|transactions| { - if transactions.len() + 1 > MaxBlockTransactions::::get() as usize { + if transactions.len() + 1 > T::MaxBlockTransactions::get() as usize { return Err(Error::::TooManyTransactions) } let chunks = num_chunks(info.size); let total_chunks = transactions.last().map_or(0, |t| t.block_chunks) + chunks; index = transactions.len() as u32; - transactions.push(TransactionInfo { - chunk_root: info.chunk_root, - size: info.size, - content_hash: info.content_hash, - block_chunks: total_chunks, - }); - Ok(()) + transactions + .try_push(TransactionInfo { + chunk_root: info.chunk_root, + size: info.size, + content_hash: info.content_hash, + block_chunks: total_chunks, + }) + .map_err(|_| Error::::TooManyTransactions) })?; Self::deposit_event(Event::Renewed { index }); Ok(().into()) @@ -324,8 +339,13 @@ pub mod pallet { /// Collection of transaction metadata by block number. #[pallet::storage] #[pallet::getter(fn transaction_roots)] - pub(super) type Transactions = - StorageMap<_, Blake2_128Concat, T::BlockNumber, Vec, OptionQuery>; + pub(super) type Transactions = StorageMap< + _, + Blake2_128Concat, + T::BlockNumber, + BoundedVec, + OptionQuery, + >; /// Count indexed chunks for each block. #[pallet::storage] @@ -342,16 +362,6 @@ pub mod pallet { /// Storage fee per transaction. pub(super) type EntryFee = StorageValue<_, BalanceOf>; - #[pallet::storage] - #[pallet::getter(fn max_transaction_size)] - /// Maximum data set in a single transaction in bytes. - pub(super) type MaxTransactionSize = StorageValue<_, u32, ValueQuery>; - - #[pallet::storage] - #[pallet::getter(fn max_block_transactions)] - /// Maximum number of indexed transactions in the block. - pub(super) type MaxBlockTransactions = StorageValue<_, u32, ValueQuery>; - /// Storage period for data in blocks. Should match `sp_storage_proof::DEFAULT_STORAGE_PERIOD` /// for block authoring. #[pallet::storage] @@ -360,7 +370,7 @@ pub mod pallet { // Intermediates #[pallet::storage] pub(super) type BlockTransactions = - StorageValue<_, Vec, ValueQuery>; + StorageValue<_, BoundedVec, ValueQuery>; /// Was the proof checked in this block? #[pallet::storage] @@ -371,8 +381,6 @@ pub mod pallet { pub byte_fee: BalanceOf, pub entry_fee: BalanceOf, pub storage_period: T::BlockNumber, - pub max_block_transactions: u32, - pub max_transaction_size: u32, } #[cfg(feature = "std")] @@ -382,8 +390,6 @@ pub mod pallet { byte_fee: 10u32.into(), entry_fee: 1000u32.into(), storage_period: sp_transaction_storage_proof::DEFAULT_STORAGE_PERIOD.into(), - max_block_transactions: DEFAULT_MAX_BLOCK_TRANSACTIONS, - max_transaction_size: DEFAULT_MAX_TRANSACTION_SIZE, } } } @@ -393,8 +399,6 @@ pub mod pallet { fn build(&self) { >::put(&self.byte_fee); >::put(&self.entry_fee); - >::put(&self.max_transaction_size); - >::put(&self.max_block_transactions); >::put(&self.storage_period); } } diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs index 753d4baaf00e2..771387ef705be 100644 --- a/frame/transaction-storage/src/mock.rs +++ b/frame/transaction-storage/src/mock.rs @@ -17,8 +17,10 @@ //! Test environment for transaction-storage pallet. -use crate as pallet_transaction_storage; -use crate::TransactionStorageProof; +use crate::{ + self as pallet_transaction_storage, TransactionStorageProof, DEFAULT_MAX_BLOCK_TRANSACTIONS, + DEFAULT_MAX_TRANSACTION_SIZE, +}; use frame_support::traits::{ConstU16, ConstU32, ConstU64, OnFinalize, OnInitialize}; use sp_core::H256; use sp_runtime::{ @@ -90,6 +92,8 @@ impl pallet_transaction_storage::Config for Test { type Currency = Balances; type FeeDestination = (); type WeightInfo = (); + type MaxBlockTransactions = ConstU32<{ DEFAULT_MAX_BLOCK_TRANSACTIONS }>; + type MaxTransactionSize = ConstU32<{ DEFAULT_MAX_TRANSACTION_SIZE }>; } pub fn new_test_ext() -> sp_io::TestExternalities { @@ -102,8 +106,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { storage_period: 10, byte_fee: 2, entry_fee: 200, - max_block_transactions: crate::DEFAULT_MAX_BLOCK_TRANSACTIONS, - max_transaction_size: crate::DEFAULT_MAX_TRANSACTION_SIZE, }, } .build_storage() From 5ab1a2790b65747ab7ec1d3a24dabad9282d42ae Mon Sep 17 00:00:00 2001 From: Georges Date: Thu, 16 Jun 2022 00:30:22 +0100 Subject: [PATCH 0921/1472] combine iteratons and tolerance in sp-npos-elections API (#11498) * Initial implementation of mms * Some more attempts at `mms` * Functioning `MMS` algorithm implementation. Adding some tests too * More tests and typos fixed. * Adding fuzzer for `mms` (but could not test it on Mac M1) * Missing imports * Fixing rustdoc * More accurate implementation of `mms` * Removing the fuzzer `mms` implementation * Implementing `NposSolver` for `MMS` had to add the `Clone` trait, maybe I could see if I can get rid of it. * Fixing rust docs by adding () to resolve ambiguity * Amending `unwrap` to `expect` removing unneeded `Clone` trait * Removing redundant `mms3.rs` * Implementing `BalancingConfig` and rustdoc changes * Implementing `weight` for `MMS` * Implementing `weight` for `MMS` * Fixing post merge * Initial implementation of mms * Some more attempts at `mms` * Functioning `MMS` algorithm implementation. Adding some tests too * More tests and typos fixed. * Adding fuzzer for `mms` (but could not test it on Mac M1) * Missing imports * Fixing rustdoc * More accurate implementation of `mms` * Removing the fuzzer `mms` implementation * Implementing `NposSolver` for `MMS` had to add the `Clone` trait, maybe I could see if I can get rid of it. * Amending `unwrap` to `expect` removing unneeded `Clone` trait * Fixing rust docs by adding () to resolve ambiguity * Removing redundant `mms3.rs` * Implementing `BalancingConfig` and rustdoc changes * Implementing `weight` for `MMS` * Implementing `weight` for `MMS` * Fixing post merge * Removing left over from rebase * Fixing tests * Removing unneeded import * Removing unneeded functions * Removing useless imports Co-authored-by: kianenigma --- bin/node/runtime/src/lib.rs | 11 ++++---- .../election-provider-multi-phase/src/lib.rs | 4 +-- .../election-provider-multi-phase/src/mock.rs | 6 ++--- frame/election-provider-support/src/lib.rs | 18 +++++-------- .../election-provider-support/src/weights.rs | 5 ++-- primitives/npos-elections/README.md | 4 +-- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- .../npos-elections/fuzzer/src/common.rs | 6 ++--- .../fuzzer/src/phragmen_balancing.rs | 7 ++--- .../fuzzer/src/phragmms_balancing.rs | 7 ++--- primitives/npos-elections/src/balancing.rs | 18 +++++++------ primitives/npos-elections/src/lib.rs | 11 ++++++-- primitives/npos-elections/src/phragmen.rs | 10 +++---- primitives/npos-elections/src/phragmms.rs | 26 +++++++++++-------- primitives/npos-elections/src/tests.rs | 8 +++--- 15 files changed, 78 insertions(+), 65 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8987439db8e94..bc889e002bf4f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -24,7 +24,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::{ - onchain, ElectionDataProvider, ExtendedBalance, SequentialPhragmen, VoteWeight, + onchain, BalancingConfig, ElectionDataProvider, SequentialPhragmen, VoteWeight, }; use frame_support::{ construct_runtime, @@ -630,10 +630,10 @@ pub const MINER_MAX_ITERATIONS: u32 = 10; /// A source of random balance for NposSolver, which is meant to be run by the OCW election miner. pub struct OffchainRandomBalancing; -impl Get> for OffchainRandomBalancing { - fn get() -> Option<(usize, ExtendedBalance)> { +impl Get> for OffchainRandomBalancing { + fn get() -> Option { use sp_runtime::traits::TrailingZeroInput; - let iters = match MINER_MAX_ITERATIONS { + let iterations = match MINER_MAX_ITERATIONS { 0 => 0, max => { let seed = sp_io::offchain::random_seed(); @@ -644,7 +644,8 @@ impl Get> for OffchainRandomBalancing { }, }; - Some((iters, 0)) + let config = BalancingConfig { iterations, tolerance: 0 }; + Some(config) } } diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 7d8559050f300..2f1f6463df719 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1808,7 +1808,7 @@ mod tests { }; use frame_election_provider_support::ElectionProvider; use frame_support::{assert_noop, assert_ok}; - use sp_npos_elections::Support; + use sp_npos_elections::{BalancingConfig, Support}; #[test] fn phase_rotation_works() { @@ -2163,7 +2163,7 @@ mod tests { assert_eq!(MultiPhase::current_phase(), Phase::Signed); // set the solution balancing to get the desired score. - crate::mock::Balancing::set(Some((2, 0))); + crate::mock::Balancing::set(Some(BalancingConfig { iterations: 2, tolerance: 0 })); let (solution, _) = MultiPhase::mine_solution().unwrap(); // Default solution's score. diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index bbc2d6d43beee..7eff70b47eba5 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -39,8 +39,8 @@ use sp_core::{ H256, }; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, ElectionResult, - EvaluateSupport, ExtendedBalance, + assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, BalancingConfig, + ElectionResult, EvaluateSupport, }; use sp_runtime::{ testing::Header, @@ -324,7 +324,7 @@ impl InstantElectionProvider for MockFallback { } parameter_types! { - pub static Balancing: Option<(usize, ExtendedBalance)> = Some((0, 0)); + pub static Balancing: Option = Some( BalancingConfig { iterations: 0, tolerance: 0 } ); } pub struct TestBenchmarkingConfig; diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 27bf7a37f9622..eee865d0b737b 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -177,8 +177,8 @@ pub use frame_support::{traits::Get, weights::Weight, BoundedVec, RuntimeDebug}; /// Re-export some type as they are used in the interface. pub use sp_arithmetic::PerThing; pub use sp_npos_elections::{ - Assignment, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128, Support, - Supports, VoteWeight, + Assignment, BalancingConfig, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128, + Support, Supports, VoteWeight, }; pub use traits::NposSolution; @@ -568,11 +568,8 @@ pub struct SequentialPhragmen( sp_std::marker::PhantomData<(AccountId, Accuracy, Balancing)>, ); -impl< - AccountId: IdentifierT, - Accuracy: PerThing128, - Balancing: Get>, - > NposSolver for SequentialPhragmen +impl>> + NposSolver for SequentialPhragmen { type AccountId = AccountId; type Accuracy = Accuracy; @@ -596,11 +593,8 @@ pub struct PhragMMS( sp_std::marker::PhantomData<(AccountId, Accuracy, Balancing)>, ); -impl< - AccountId: IdentifierT, - Accuracy: PerThing128, - Balancing: Get>, - > NposSolver for PhragMMS +impl>> + NposSolver for PhragMMS { type AccountId = AccountId; type Accuracy = Accuracy; diff --git a/frame/election-provider-support/src/weights.rs b/frame/election-provider-support/src/weights.rs index f288ae63bb5da..c603b196519b5 100644 --- a/frame/election-provider-support/src/weights.rs +++ b/frame/election-provider-support/src/weights.rs @@ -15,15 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_election_provider_support_onchain_benchmarking +//! Autogenerated weights for pallet_election_provider_support_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-04-04, STEPS: `1`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-04-23, STEPS: `1`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // target/release/substrate // benchmark +// pallet // --chain=dev // --steps=1 // --repeat=1 diff --git a/primitives/npos-elections/README.md b/primitives/npos-elections/README.md index b518e63615fa6..6881fc6418f3a 100644 --- a/primitives/npos-elections/README.md +++ b/primitives/npos-elections/README.md @@ -8,7 +8,7 @@ sub-system. Notable implementation include: it can achieve a constant factor approximation of the maximin problem, similar to that of the MMS algorithm. - [`balance_solution`]: Implements the star balancing algorithm. This iterative process can push - a solution toward being more `balances`, which in turn can increase its score. + a solution toward being more `balanced`, which in turn can increase its score. ### Terminology @@ -46,7 +46,7 @@ let election_result = ElectionResult { winners, assignments }; The `Assignment` field of the election result is voter-major, i.e. it is from the perspective of the voter. The struct that represents the opposite is called a `Support`. This struct is usually -accessed in a map-like manner, i.e. keyed vy voters, therefor it is stored as a mapping called +accessed in a map-like manner, i.e. keyed by voters, therefore it is stored as a mapping called `SupportMap`. Moreover, the support is built from absolute backing values, not ratios like the example above. diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 42a80296a4530..a200d5c41ee35 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -36,4 +36,4 @@ path = "src/phragmms_balancing.rs" [[bin]] name = "phragmen_pjr" -path = "src/phragmen_pjr.rs" +path = "src/phragmen_pjr.rs" \ No newline at end of file diff --git a/primitives/npos-elections/fuzzer/src/common.rs b/primitives/npos-elections/fuzzer/src/common.rs index 6b89983c16abe..e5853f28c4929 100644 --- a/primitives/npos-elections/fuzzer/src/common.rs +++ b/primitives/npos-elections/fuzzer/src/common.rs @@ -21,7 +21,7 @@ #![allow(dead_code)] use rand::{self, seq::SliceRandom, Rng, RngCore}; -use sp_npos_elections::{phragmms, seq_phragmen, ElectionResult, VoteWeight}; +use sp_npos_elections::{phragmms, seq_phragmen, BalancingConfig, ElectionResult, VoteWeight}; use sp_runtime::Perbill; use std::collections::{BTreeMap, HashSet}; @@ -38,8 +38,8 @@ pub fn to_range(x: usize, a: usize, b: usize) -> usize { } pub enum ElectionType { - Phragmen(Option<(usize, u128)>), - Phragmms(Option<(usize, u128)>), + Phragmen(Option), + Phragmms(Option), } pub type AccountId = u64; diff --git a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs index cacf64e81c8f7..e053f9aa0cddd 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs @@ -23,8 +23,8 @@ use common::*; use honggfuzz::fuzz; use rand::{self, SeedableRng}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, ElectionResult, - EvaluateSupport, VoteWeight, + assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, BalancingConfig, + ElectionResult, EvaluateSupport, VoteWeight, }; use sp_runtime::Perbill; @@ -66,8 +66,9 @@ fn main() { }; if iterations > 0 { + let config = BalancingConfig { iterations, tolerance: 0 }; let balanced: ElectionResult = - seq_phragmen(to_elect, candidates, voters, Some((iterations, 0))).unwrap(); + seq_phragmen(to_elect, candidates, voters, Some(config)).unwrap(); let balanced_score = { let staked = diff --git a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs index 988889428c9cf..3f114674e29d9 100644 --- a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs @@ -23,8 +23,8 @@ use common::*; use honggfuzz::fuzz; use rand::{self, SeedableRng}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, phragmms, to_supports, ElectionResult, EvaluateSupport, - VoteWeight, + assignment_ratio_to_staked_normalized, phragmms, to_supports, BalancingConfig, ElectionResult, + EvaluateSupport, VoteWeight, }; use sp_runtime::Perbill; @@ -65,8 +65,9 @@ fn main() { score }; + let config = BalancingConfig { iterations, tolerance: 0 }; let balanced: ElectionResult = - phragmms(to_elect, candidates, voters, Some((iterations, 0))).unwrap(); + phragmms(to_elect, candidates, voters, Some(config)).unwrap(); let balanced_score = { let staked = diff --git a/primitives/npos-elections/src/balancing.rs b/primitives/npos-elections/src/balancing.rs index 54b8ee4bf243e..4a713658ad38f 100644 --- a/primitives/npos-elections/src/balancing.rs +++ b/primitives/npos-elections/src/balancing.rs @@ -26,14 +26,15 @@ //! //! See [`balance`] for more information. -use crate::{Edge, ExtendedBalance, IdentifierT, Voter}; +use crate::{BalancingConfig, Edge, ExtendedBalance, IdentifierT, Voter}; use sp_arithmetic::traits::Zero; use sp_std::prelude::*; /// Balance the weight distribution of a given `voters` at most `iterations` times, or up until the /// point where the biggest difference created per iteration of all stakes is `tolerance`. If this /// is called with `tolerance = 0`, then exactly `iterations` rounds will be executed, except if no -/// change has been made (`difference = 0`). +/// change has been made (`difference = 0`). `tolerance` and `iterations` are part of the +/// [`BalancingConfig`] struct. /// /// In almost all cases, a balanced solution will have a better score than an unbalanced solution, /// yet this is not 100% guaranteed because the first element of a [`crate::ElectionScore`] does not @@ -52,12 +53,13 @@ use sp_std::prelude::*; /// - [A new approach to the maximum flow problem](https://dl.acm.org/doi/10.1145/48014.61051). /// - [Validator election in nominated proof-of-stake](https://arxiv.org/abs/2004.12990) (Appendix /// A.) +/// - [Computing a balanced solution](https://research.web3.foundation/en/latest/polkadot/NPoS/3.%20Balancing.html), +/// which contains the details of the algorithm implementation. pub fn balance( voters: &mut Vec>, - iterations: usize, - tolerance: ExtendedBalance, + config: &BalancingConfig, ) -> usize { - if iterations == 0 { + if config.iterations == 0 { return 0 } @@ -65,14 +67,14 @@ pub fn balance( loop { let mut max_diff = 0; for voter in voters.iter_mut() { - let diff = balance_voter(voter, tolerance); + let diff = balance_voter(voter, config.tolerance); if diff > max_diff { max_diff = diff; } } iter += 1; - if max_diff <= tolerance || iter >= iterations { + if max_diff <= config.tolerance || iter >= config.iterations { break iter } } @@ -158,7 +160,7 @@ pub(crate) fn balance_voter( .get(last_index) .expect( "length of elected_edges is greater than or equal 2; last_index index is at the \ - minimum elected_edges.len() - 1; index is within range; qed", + minimum elected_edges.len() - 1; index is within range; qed", ) .candidate .borrow() diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 63b9740b74639..dd2a9bf198f8d 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -62,7 +62,7 @@ //! //! The `Assignment` field of the election result is voter-major, i.e. it is from the perspective of //! the voter. The struct that represents the opposite is called a `Support`. This struct is usually -//! accessed in a map-like manner, i.e. keyed by voters, therefor it is stored as a mapping called +//! accessed in a map-like manner, i.e. keyed by voters, therefore it is stored as a mapping called //! `SupportMap`. //! //! Moreover, the support is built from absolute backing values, not ratios like the example above. @@ -217,6 +217,13 @@ impl sp_std::cmp::PartialOrd for ElectionScore { } } +/// Utility struct to group parameters for the balancing algorithm. +#[derive(Clone, Copy)] +pub struct BalancingConfig { + pub iterations: usize, + pub tolerance: ExtendedBalance, +} + /// A pointer to a candidate struct with interior mutability. pub type CandidatePtr = Rc>>; @@ -320,7 +327,7 @@ impl Voter { /// /// Note that this might create _un-normalized_ assignments, due to accuracy loss of `P`. Call /// site might compensate by calling `normalize()` on the returned `Assignment` as a - /// post-precessing. + /// post-processing. pub fn into_assignment(self) -> Option> { let who = self.who; let budget = self.budget; diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index 9b0bfa42215c3..9b50dc36e48fb 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -21,8 +21,8 @@ //! to the Maximin problem. use crate::{ - balancing, setup_inputs, CandidatePtr, ElectionResult, ExtendedBalance, IdentifierT, - PerThing128, VoteWeight, Voter, + balancing, setup_inputs, BalancingConfig, CandidatePtr, ElectionResult, ExtendedBalance, + IdentifierT, PerThing128, VoteWeight, Voter, }; use sp_arithmetic::{ helpers_128bit::multiply_by_rational, @@ -71,16 +71,16 @@ pub fn seq_phragmen( to_elect: usize, candidates: Vec, voters: Vec<(AccountId, VoteWeight, impl IntoIterator)>, - balancing: Option<(usize, ExtendedBalance)>, + balancing: Option, ) -> Result, crate::Error> { let (candidates, voters) = setup_inputs(candidates, voters); let (candidates, mut voters) = seq_phragmen_core::(to_elect, candidates, voters)?; - if let Some((iterations, tolerance)) = balancing { + if let Some(ref config) = balancing { // NOTE: might create zero-edges, but we will strip them again when we convert voter into // assignment. - let _iters = balancing::balance::(&mut voters, iterations, tolerance); + let _iters = balancing::balance::(&mut voters, config); } let mut winners = candidates diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index 5d63517c8e229..3fbbad75e2f8f 100644 --- a/primitives/npos-elections/src/phragmms.rs +++ b/primitives/npos-elections/src/phragmms.rs @@ -22,15 +22,15 @@ //! MMS algorithm. use crate::{ - balance, setup_inputs, CandidatePtr, ElectionResult, ExtendedBalance, IdentifierT, PerThing128, - VoteWeight, Voter, + balance, setup_inputs, BalancingConfig, CandidatePtr, ElectionResult, ExtendedBalance, + IdentifierT, PerThing128, VoteWeight, Voter, }; use sp_arithmetic::{traits::Bounded, PerThing, Rational128}; use sp_std::{prelude::*, rc::Rc}; /// Execute the phragmms method. /// -/// This can be used interchangeably with [`seq-phragmen`] and offers a similar API, namely: +/// This can be used interchangeably with `seq-phragmen` and offers a similar API, namely: /// /// - The resulting edge weight distribution is normalized (thus, safe to use for submission). /// - The accuracy can be configured via the generic type `P`. @@ -45,7 +45,7 @@ pub fn phragmms( to_elect: usize, candidates: Vec, voters: Vec<(AccountId, VoteWeight, impl IntoIterator)>, - balancing: Option<(usize, ExtendedBalance)>, + balancing: Option, ) -> Result, crate::Error> { let (candidates, mut voters) = setup_inputs(candidates, voters); @@ -58,8 +58,8 @@ pub fn phragmms( round_winner.borrow_mut().elected = true; winners.push(round_winner); - if let Some((iterations, tolerance)) = balancing { - balance(&mut voters, iterations, tolerance); + if let Some(ref config) = balancing { + balance(&mut voters, config); } } else { break @@ -275,7 +275,8 @@ mod tests { drop(winner); // balancing makes no difference here but anyhow. - balance(&mut voters, 10, 0); + let config = BalancingConfig { iterations: 10, tolerance: 0 }; + balance(&mut voters, &config); // round 2 let winner = @@ -315,7 +316,7 @@ mod tests { drop(winner); // balancing will improve stuff here. - balance(&mut voters, 10, 0); + balance(&mut voters, &config); assert_eq!( voters @@ -348,8 +349,9 @@ mod tests { let candidates = vec![1, 2, 3]; let voters = vec![(10, 10, vec![1, 2]), (20, 20, vec![1, 3]), (30, 30, vec![2, 3])]; + let config = BalancingConfig { iterations: 2, tolerance: 0 }; let ElectionResult::<_, Perbill> { winners, assignments } = - phragmms(2, candidates, voters, Some((2, 0))).unwrap(); + phragmms(2, candidates, voters, Some(config)).unwrap(); assert_eq!(winners, vec![(3, 30), (2, 30)]); assert_eq!( assignments, @@ -380,8 +382,9 @@ mod tests { (130, 1000, vec![61, 71]), ]; + let config = BalancingConfig { iterations: 2, tolerance: 0 }; let ElectionResult::<_, Perbill> { winners, assignments: _ } = - phragmms(4, candidates, voters, Some((2, 0))).unwrap(); + phragmms(4, candidates, voters, Some(config)).unwrap(); assert_eq!(winners, vec![(11, 3000), (31, 2000), (51, 1500), (61, 1500),]); } @@ -393,8 +396,9 @@ mod tests { // give a bit more to 1 and 3. voters.push((2, u64::MAX, vec![1, 3])); + let config = BalancingConfig { iterations: 2, tolerance: 0 }; let ElectionResult::<_, Perbill> { winners, assignments: _ } = - phragmms(2, candidates, voters, Some((2, 0))).unwrap(); + phragmms(2, candidates, voters, Some(config)).unwrap(); assert_eq!(winners.into_iter().map(|(w, _)| w).collect::>(), vec![1u32, 3]); } } diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index 1cf5ea8a24920..5b88889201b31 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -19,7 +19,7 @@ use crate::{ balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, to_support_map, - Assignment, ElectionResult, ExtendedBalance, StakedAssignment, Support, Voter, + Assignment, BalancingConfig, ElectionResult, ExtendedBalance, StakedAssignment, Support, Voter, }; use sp_arithmetic::{PerU16, Perbill, Percent, Permill}; use substrate_test_utils::assert_eq_uvec; @@ -142,7 +142,8 @@ fn balancing_core_works() { let (candidates, voters) = setup_inputs(candidates, voters); let (candidates, mut voters) = seq_phragmen_core(4, candidates, voters).unwrap(); - let iters = balancing::balance::(&mut voters, 4, 0); + let config = BalancingConfig { iterations: 4, tolerance: 0 }; + let iters = balancing::balance::(&mut voters, &config); assert!(iters > 0); @@ -282,6 +283,7 @@ fn phragmen_poc_works_with_balancing() { let voters = vec![(10, vec![1, 2]), (20, vec![1, 3]), (30, vec![2, 3])]; let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30)]); + let config = BalancingConfig { iterations: 4, tolerance: 0 }; let ElectionResult::<_, Perbill> { winners, assignments } = seq_phragmen( 2, candidates, @@ -289,7 +291,7 @@ fn phragmen_poc_works_with_balancing() { .iter() .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) .collect::>(), - Some((4, 0)), + Some(config), ) .unwrap(); From c950f18507d2b4a1d353c359ee3949f1b355bc60 Mon Sep 17 00:00:00 2001 From: ZhiYong Date: Thu, 16 Jun 2022 09:30:49 +0800 Subject: [PATCH 0922/1472] Add Event to Pallet Transaction Payment (#11618) * add Event to Pallet Transaction Payment * Fix tests in Pallet Balance * Fix tests in Pallet Balance/Executive/Asset-tx-payment. * Fix * fmt * Fix * Fix * Update Cargo.lock * Fix tests in executor * Update frame/transaction-payment/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * update the name of the event and fmt. Co-authored-by: Shawn Tabrizi Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- Cargo.lock | 1 + bin/node-template/runtime/src/lib.rs | 1 + bin/node/bench/src/import.rs | 7 ++-- bin/node/executor/Cargo.toml | 1 + bin/node/executor/tests/basic.rs | 33 +++++++++++++++++++ bin/node/runtime/src/lib.rs | 1 + client/db/src/parity_db.rs | 5 +-- frame/balances/src/lib.rs | 1 + frame/balances/src/tests_composite.rs | 3 +- frame/balances/src/tests_local.rs | 3 +- frame/balances/src/tests_reentrancy.rs | 14 ++------ frame/executive/src/lib.rs | 3 +- .../asset-tx-payment/src/tests.rs | 3 +- frame/transaction-payment/src/lib.rs | 25 ++++++++++++-- 14 files changed, 77 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdcd450454629..815254376e6cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4664,6 +4664,7 @@ dependencies = [ "pallet-contracts", "pallet-im-online", "pallet-timestamp", + "pallet-transaction-payment", "pallet-treasury", "parity-scale-codec", "sc-executor", diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 0145cacef8f7d..c514cdf6c25fd 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -249,6 +249,7 @@ impl pallet_balances::Config for Runtime { } impl pallet_transaction_payment::Config for Runtime { + type Event = Event; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; diff --git a/bin/node/bench/src/import.rs b/bin/node/bench/src/import.rs index faba85468b1fa..b9229fbd5331d 100644 --- a/bin/node/bench/src/import.rs +++ b/bin/node/bench/src/import.rs @@ -135,9 +135,10 @@ impl core::Benchmark for ImportBenchmark { .inspect_state(|| { match self.block_type { BlockType::RandomTransfersKeepAlive => { - // should be 7 per signed extrinsic + 1 per unsigned + // should be 8 per signed extrinsic + 1 per unsigned // we have 1 unsigned and the rest are signed in the block - // those 7 events per signed are: + // those 8 events per signed are: + // - transaction paid for the transaction payment // - withdraw (Balances::Withdraw) for charging the transaction fee // - new account (System::NewAccount) as we always transfer fund to // non-existent account @@ -148,7 +149,7 @@ impl core::Benchmark for ImportBenchmark { // - extrinsic success assert_eq!( node_runtime::System::events().len(), - (self.block.extrinsics.len() - 1) * 7 + 1, + (self.block.extrinsics.len() - 1) * 8 + 1, ); }, BlockType::Noop => { diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 6b6a1709d5aa0..5fbf59a74fdcd 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -36,6 +36,7 @@ pallet-contracts = { version = "4.0.0-dev", path = "../../../frame/contracts" } pallet-im-online = { version = "4.0.0-dev", path = "../../../frame/im-online" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } pallet-treasury = { version = "4.0.0-dev", path = "../../../frame/treasury" } +pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index da0f4e6afb319..de2aa6c18369d 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -417,6 +417,17 @@ fn full_native_block_import_works() { event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: Event::TransactionPayment( + pallet_transaction_payment::Event::TransactionFeePaid { + who: alice().into(), + actual_fee: fees, + tip: 0, + }, + ), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: Event::System(frame_system::Event::ExtrinsicSuccess { @@ -488,6 +499,17 @@ fn full_native_block_import_works() { event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: Event::TransactionPayment( + pallet_transaction_payment::Event::TransactionFeePaid { + who: bob().into(), + actual_fee: fees, + tip: 0, + }, + ), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: Event::System(frame_system::Event::ExtrinsicSuccess { @@ -525,6 +547,17 @@ fn full_native_block_import_works() { event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(2), + event: Event::TransactionPayment( + pallet_transaction_payment::Event::TransactionFeePaid { + who: alice().into(), + actual_fee: fees, + tip: 0, + }, + ), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(2), event: Event::System(frame_system::Event::ExtrinsicSuccess { diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index bc889e002bf4f..addcd0b35a9d9 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -447,6 +447,7 @@ parameter_types! { } impl pallet_transaction_payment::Config for Runtime { + type Event = Event; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; diff --git a/client/db/src/parity_db.rs b/client/db/src/parity_db.rs index 7ce1d6a683401..4adacbf6f041c 100644 --- a/client/db/src/parity_db.rs +++ b/client/db/src/parity_db.rs @@ -106,7 +106,7 @@ impl> Database for DbAdapter { } return None }, - Change::Reference(col, key) => + Change::Reference(col, key) => { if ref_counted_column(col) { // FIXME accessing value is not strictly needed, optimize this in parity-db. let value = >::get(self, col, key.as_ref()); @@ -116,7 +116,8 @@ impl> Database for DbAdapter { not_ref_counted_column.push(col); } return None - }, + } + }, Change::Release(col, key) => if ref_counted_column(col) { (col as u8, key.as_ref().to_vec(), None) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 298c2a6963880..683ebce2b1693 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -158,6 +158,7 @@ mod tests; mod benchmarking; mod tests_composite; mod tests_local; +#[cfg(test)] mod tests_reentrancy; pub mod weights; diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 4a2cc1d91936d..4ab913cf1411a 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -40,7 +40,7 @@ frame_support::construct_runtime!( { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, } ); @@ -77,6 +77,7 @@ impl frame_system::Config for Test { } impl pallet_transaction_payment::Config for Test { + type Event = Event; type OnChargeTransaction = CurrencyAdapter, ()>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index cfc7f84ab3a38..6f4c50d90153a 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -41,7 +41,7 @@ frame_support::construct_runtime!( { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, } ); @@ -78,6 +78,7 @@ impl frame_system::Config for Test { } impl pallet_transaction_payment::Config for Test { + type Event = Event; type OnChargeTransaction = CurrencyAdapter, ()>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 7037e9615afd8..4c028840d553c 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -19,13 +19,11 @@ #![cfg(test)] -use crate::{self as pallet_balances, Config, Pallet}; +use crate::{self as pallet_balances, Config}; use frame_support::{ parameter_types, - traits::{ConstU32, ConstU64, ConstU8, StorageMapShim}, - weights::IdentityFee, + traits::{ConstU32, ConstU64, StorageMapShim}, }; -use pallet_transaction_payment::CurrencyAdapter; use sp_core::H256; use sp_io; use sp_runtime::{testing::Header, traits::IdentityLookup}; @@ -83,14 +81,6 @@ impl frame_system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl pallet_transaction_payment::Config for Test { - type OnChargeTransaction = CurrencyAdapter, ()>; - type OperationalFeeMultiplier = ConstU8<5>; - type WeightToFee = IdentityFee; - type LengthToFee = IdentityFee; - type FeeMultiplierUpdate = (); -} - pub struct OnDustRemoval; impl OnUnbalanced> for OnDustRemoval { fn on_nonzero_unbalanced(amount: NegativeImbalance) { diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 55b7e926a0fad..60bf0a47ca120 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -722,7 +722,7 @@ mod tests { { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, Custom: custom::{Pallet, Call, ValidateUnsigned, Inherent}, } ); @@ -783,6 +783,7 @@ mod tests { pub const TransactionByteFee: Balance = 0; } impl pallet_transaction_payment::Config for Runtime { + type Event = Event; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index 5b1fa157c3f10..ad5bc3f22e57f 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -48,7 +48,7 @@ frame_support::construct_runtime!( { System: system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, Assets: pallet_assets::{Pallet, Call, Storage, Event}, Authorship: pallet_authorship::{Pallet, Call, Storage}, AssetTxPayment: pallet_asset_tx_payment::{Pallet}, @@ -143,6 +143,7 @@ impl WeightToFeeT for TransactionByteFee { } impl pallet_transaction_payment::Config for Runtime { + type Event = Event; type OnChargeTransaction = CurrencyAdapter; type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index d44f8b1b894e1..0f5c0321130be 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -249,6 +249,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + /// Handler for withdrawing, refunding and depositing the transaction fee. /// Transaction fees are withdrawn before the transaction is executed. /// After the transaction was executed the transaction weight can be @@ -321,6 +324,14 @@ pub mod pallet { } } + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A transaction fee `actual_fee`, of which `tip` was added to the minimum inclusion fee, + /// has been paid by `who`. + TransactionFeePaid { who: T::AccountId, actual_fee: BalanceOf, tip: BalanceOf }, + } + #[pallet::hooks] impl Hooks> for Pallet { fn on_finalize(_: T::BlockNumber) { @@ -734,6 +745,7 @@ where T::OnChargeTransaction::correct_and_deposit_fee( &who, info, post_info, actual_fee, tip, imbalance, )?; + Pallet::::deposit_event(Event::::TransactionFeePaid { who, actual_fee, tip }); } Ok(()) } @@ -790,7 +802,7 @@ mod tests { { System: system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, } ); @@ -899,6 +911,7 @@ mod tests { } impl Config for Runtime { + type Event = Event; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = WeightToFee; @@ -1407,8 +1420,14 @@ mod tests { &Ok(()) )); assert_eq!(Balances::total_balance(&user), 0); - // No events for such a scenario - assert_eq!(System::events().len(), 0); + // TransactionFeePaid Event + System::assert_has_event(Event::TransactionPayment( + pallet_transaction_payment::Event::TransactionFeePaid { + who: user, + actual_fee: 0, + tip: 0, + }, + )); }); } From 06ab196c201f93fb4560dc08ff8a94f3070a1dbe Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 16 Jun 2022 20:48:05 +0900 Subject: [PATCH 0923/1472] Remove `without_storage_info` for the authorship pallet (#11610) * Remove `without_storage_info` for the authorship pallet * Tweak impl bounds style * Use `defensive_proof` instead of `expect` --- frame/authorship/src/lib.rs | 92 ++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 11 deletions(-) diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 561db20849c2f..8ddccfd9cf939 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -21,17 +21,33 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch, - traits::{FindAuthor, Get, VerifySeal}, + traits::{Defensive, FindAuthor, Get, VerifySeal}, + BoundedSlice, BoundedVec, }; use sp_authorship::{InherentError, UnclesInherentData, INHERENT_IDENTIFIER}; -use sp_runtime::traits::{Header as HeaderT, One, Saturating}; +use sp_runtime::traits::{Header as HeaderT, One, Saturating, UniqueSaturatedInto}; use sp_std::{collections::btree_set::BTreeSet, prelude::*, result}; const MAX_UNCLES: usize = 10; +struct MaxUncleEntryItems(core::marker::PhantomData); +impl Get for MaxUncleEntryItems { + fn get() -> u32 { + // There can be at most `MAX_UNCLES` of `UncleEntryItem::Uncle` and + // one `UncleEntryItem::InclusionHeight` per one `UncleGenerations`, + // so this gives us `MAX_UNCLES + 1` entries per one generation. + // + // There can be one extra generation worth of uncles (e.g. even + // if `UncleGenerations` is zero the pallet will still hold + // one generation worth of uncles). + let max_generations: u32 = T::UncleGenerations::get().unique_saturated_into(); + (MAX_UNCLES as u32 + 1) * (max_generations + 1) + } +} + pub use pallet::*; /// An event handler for the authorship pallet. There is a dummy implementation @@ -115,7 +131,7 @@ where } } -#[derive(Encode, Decode, sp_runtime::RuntimeDebug, scale_info::TypeInfo)] +#[derive(Encode, Decode, sp_runtime::RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen)] #[cfg_attr(any(feature = "std", test), derive(PartialEq))] enum UncleEntryItem { InclusionHeight(BlockNumber), @@ -156,7 +172,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] @@ -187,8 +202,11 @@ pub mod pallet { #[pallet::storage] /// Uncles - pub(super) type Uncles = - StorageValue<_, Vec>, ValueQuery>; + pub(super) type Uncles = StorageValue< + _, + BoundedVec, MaxUncleEntryItems>, + ValueQuery, + >; #[pallet::storage] /// Author of current block. @@ -321,7 +339,10 @@ impl Pallet { let now = >::block_number(); let mut uncles = >::get(); - uncles.push(UncleEntryItem::InclusionHeight(now)); + uncles + .try_push(UncleEntryItem::InclusionHeight(now)) + .defensive_proof("the list of uncles accepted per generation is bounded, and the number of generations is bounded, so pushing a new element will always succeed") + .map_err(|_| Error::::TooManyUncles)?; let mut acc: >::Accumulator = Default::default(); @@ -336,7 +357,9 @@ impl Pallet { if let Some(author) = maybe_author.clone() { T::EventHandler::note_uncle(author, now - *uncle.number()); } - uncles.push(UncleEntryItem::Uncle(hash, maybe_author)); + uncles.try_push(UncleEntryItem::Uncle(hash, maybe_author)) + .defensive_proof("the list of uncles accepted per generation is bounded, and the number of generations is bounded, so pushing a new element will always succeed") + .map_err(|_| Error::::TooManyUncles)?; } >::put(&uncles); @@ -397,8 +420,11 @@ impl Pallet { UncleEntryItem::InclusionHeight(height) => height < &minimum_height, }); let prune_index = prune_entries.count(); + let pruned_uncles = + >>::try_from(&uncles[prune_index..]) + .expect("after pruning we can't end up with more uncles than we started with"); - >::put(&uncles[prune_index..]); + >::put(pruned_uncles); } } @@ -408,7 +434,7 @@ mod tests { use crate as pallet_authorship; use frame_support::{ parameter_types, - traits::{ConstU32, ConstU64}, + traits::{ConstU32, ConstU64, OnFinalize, OnInitialize}, ConsensusEngineId, }; use sp_core::H256; @@ -553,6 +579,7 @@ mod tests { InclusionHeight(3u64), Uncle(hash, None), ]; + let uncles = BoundedVec::try_from(uncles).unwrap(); ::Uncles::put(uncles); Authorship::prune_old_uncles(3); @@ -683,6 +710,49 @@ mod tests { }); } + #[test] + fn maximum_bound() { + new_test_ext().execute_with(|| { + let mut max_item_count = 0; + + let mut author_counter = 0; + let mut current_depth = 1; + let mut parent_hash: H256 = [1; 32].into(); + let mut uncles = vec![]; + + // We deliberately run this for more generations than the limit + // so that we can get the `Uncles` to hit its cap. + for _ in 0..<::UncleGenerations as Get>::get() + 3 { + let new_uncles: Vec<_> = (0..MAX_UNCLES) + .map(|_| { + System::reset_events(); + System::initialize(¤t_depth, &parent_hash, &Default::default()); + // Increment the author on every block to make sure the hash's always + // different. + author_counter += 1; + seal_header(System::finalize(), author_counter) + }) + .collect(); + + author_counter += 1; + System::reset_events(); + System::initialize(¤t_depth, &parent_hash, &Default::default()); + Authorship::on_initialize(current_depth); + Authorship::set_uncles(Origin::none(), uncles).unwrap(); + Authorship::on_finalize(current_depth); + max_item_count = + std::cmp::max(max_item_count, ::Uncles::get().len()); + + let new_parent = seal_header(System::finalize(), author_counter); + parent_hash = new_parent.hash(); + uncles = new_uncles; + current_depth += 1; + } + + assert_eq!(max_item_count, MaxUncleEntryItems::::get() as usize); + }); + } + #[test] fn sets_author_lazily() { new_test_ext().execute_with(|| { From 6a59cc341015fef7af028091345d9fb6a1040ac2 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 16 Jun 2022 17:13:17 +0100 Subject: [PATCH 0924/1472] MEL: Origin, Referenda, ConvictionVoting (#11631) * Referenda & CV pallets ready * Fix build * Add mel_bound for Voting and Casting types * Add mel_bound on Tally * Add mel_bound on another Tally * Add mel_bound for pallet_collective::RawOrigin Co-authored-by: Keith Yeung --- Cargo.lock | 8 +++---- frame/collective/src/lib.rs | 5 ++-- frame/conviction-voting/Cargo.toml | 3 ++- frame/conviction-voting/src/lib.rs | 23 +++++++++++++++---- frame/conviction-voting/src/types.rs | 1 + frame/conviction-voting/src/vote.rs | 5 ++++ frame/ranked-collective/src/lib.rs | 1 + frame/referenda/Cargo.toml | 2 +- frame/referenda/src/lib.rs | 4 ++-- .../src/construct_runtime/expand/origin.rs | 2 +- frame/support/src/dispatch.rs | 10 +++++--- frame/support/src/traits.rs | 3 ++- frame/support/src/traits/dispatch.rs | 7 +++++- frame/support/src/traits/schedule.rs | 8 +++---- frame/support/src/traits/voting.rs | 7 ++++++ frame/support/test/tests/construct_runtime.rs | 17 ++++++++++---- frame/support/test/tests/instance.rs | 10 +++++--- frame/support/test/tests/origin.rs | 10 ++++++-- frame/support/test/tests/pallet.rs | 9 +++++++- frame/support/test/tests/pallet_instance.rs | 2 ++ primitives/core/src/lib.rs | 4 ++-- test-utils/runtime/src/lib.rs | 4 ++-- 22 files changed, 106 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 815254376e6cf..84443396e0d06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6534,9 +6534,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.0.0" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a7f3fcf5e45fc28b84dcdab6b983e77f197ec01f325a33f404ba6855afd1070" +checksum = "04bc9583b5e01cc8c70d89acc9af14ef9b1c29ee3a0074b2a9eea8c0fa396690" dependencies = [ "arrayvec 0.7.1", "bitvec", @@ -6548,9 +6548,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.0.0" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6e626dc84025ff56bf1476ed0e30d10c84d7f89a475ef46ebabee1095a8fba" +checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index bc6d9ab3310e0..0323be1382392 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -48,7 +48,7 @@ use sp_runtime::{traits::Hash, RuntimeDebug}; use sp_std::{marker::PhantomData, prelude::*, result}; use frame_support::{ - codec::{Decode, Encode}, + codec::{Decode, Encode, MaxEncodedLen}, dispatch::{DispatchError, DispatchResultWithPostInfo, Dispatchable, PostDispatchInfo}, ensure, traits::{ @@ -124,8 +124,9 @@ impl DefaultVote for MoreThanMajorityThenPrimeDefaultVote { } /// Origin for the collective module. -#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo)] +#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(I))] +#[codec(mel_bound(AccountId: MaxEncodedLen))] pub enum RawOrigin { /// It has been condoned by a given number of members of the collective from a given total. Members(MemberCount, MemberCount), diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index ff6cfcc3efdee..ab6d04d199bc6 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -14,8 +14,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] assert_matches = "1.3.0" -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.3", default-features = false, features = [ "derive", + "max-encoded-len", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index 58ac76dac3a3e..54fc1156d1f47 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -87,12 +87,11 @@ type ClassOf = <>::Polls as Polling>>::C #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, traits::ClassCountOf}; use frame_system::pallet_prelude::*; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -154,7 +153,7 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - Vec<(ClassOf, BalanceOf)>, + BoundedVec<(ClassOf, BalanceOf), ClassCountOf>>, ValueQuery, >; @@ -616,7 +615,15 @@ impl, I: 'static> Pallet { ClassLocksFor::::mutate(who, |locks| { match locks.iter().position(|x| &x.0 == class) { Some(i) => locks[i].1 = locks[i].1.max(amount), - None => locks.push((class.clone(), amount)), + None => { + let ok = locks.try_push((class.clone(), amount)).is_ok(); + debug_assert!( + ok, + "Vec bounded by number of classes; \ + all items in Vec associated with a unique class; \ + qed" + ); + }, } }); T::Currency::extend_lock(CONVICTION_VOTING_ID, who, amount, WithdrawReasons::TRANSFER); @@ -632,7 +639,13 @@ impl, I: 'static> Pallet { let lock_needed = ClassLocksFor::::mutate(who, |locks| { locks.retain(|x| &x.0 != class); if !class_lock_needed.is_zero() { - locks.push((class.clone(), class_lock_needed)); + let ok = locks.try_push((class.clone(), class_lock_needed)).is_ok(); + debug_assert!( + ok, + "Vec bounded by number of classes; \ + all items in Vec associated with a unique class; \ + qed" + ); } locks.iter().map(|x| x.1).max().unwrap_or(Zero::zero()) }); diff --git a/frame/conviction-voting/src/types.rs b/frame/conviction-voting/src/types.rs index 2469009855c5f..8f4f3697e9766 100644 --- a/frame/conviction-voting/src/types.rs +++ b/frame/conviction-voting/src/types.rs @@ -43,6 +43,7 @@ use crate::{AccountVote, Conviction, Vote}; MaxEncodedLen, )] #[scale_info(skip_type_params(Total))] +#[codec(mel_bound(Votes: MaxEncodedLen))] pub struct Tally { /// The number of aye votes, expressed in terms of post-conviction lock-vote. pub ayes: Votes, diff --git a/frame/conviction-voting/src/vote.rs b/frame/conviction-voting/src/vote.rs index e608a6dcfd01b..a0b17ab4de39d 100644 --- a/frame/conviction-voting/src/vote.rs +++ b/frame/conviction-voting/src/vote.rs @@ -162,6 +162,7 @@ pub struct Delegating { /// Information concerning the direct vote-casting of some voting power. #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(MaxVotes))] +#[codec(mel_bound(Balance: MaxEncodedLen, BlockNumber: MaxEncodedLen, PollIndex: MaxEncodedLen))] pub struct Casting where MaxVotes: Get, @@ -177,6 +178,10 @@ where /// An indicator for what an account is doing; it can either be delegating or voting. #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(MaxVotes))] +#[codec(mel_bound( + Balance: MaxEncodedLen, AccountId: MaxEncodedLen, BlockNumber: MaxEncodedLen, + PollIndex: MaxEncodedLen, +))] pub enum Voting where MaxVotes: Get, diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 60df32dcb3fa3..7ea43a9017445 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -86,6 +86,7 @@ pub type Votes = u32; MaxEncodedLen, )] #[scale_info(skip_type_params(M))] +#[codec(mel_bound())] pub struct Tally { bare_ayes: MemberIndex, ayes: Votes, diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index ef3d5fe5a8e06..508f5a5ef8688 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] assert_matches = { version = "1.5", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.3", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index ab8c3ad0efa6a..15c5562d64c84 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -118,7 +118,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -159,7 +158,8 @@ pub mod pallet { + Codec + Eq + Debug - + TypeInfo; + + TypeInfo + + MaxEncodedLen; // Constants /// The minimum amount to be used as a deposit for a public referendum proposal. diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index d347818d65c38..46f08832f0bb4 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -200,7 +200,7 @@ pub fn expand_outer_origin( #[derive( Clone, PartialEq, Eq, #scrate::RuntimeDebug, #scrate::codec::Encode, - #scrate::codec::Decode, #scrate::scale_info::TypeInfo, + #scrate::codec::Decode, #scrate::scale_info::TypeInfo, #scrate::codec::MaxEncodedLen, )] #[allow(non_camel_case_types)] pub enum OriginCaller { diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index d399340f0470e..c175998956ff2 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -19,7 +19,9 @@ //! generating values representing lazy module function calls. pub use crate::{ - codec::{Codec, Decode, Encode, EncodeAsRef, EncodeLike, HasCompact, Input, Output}, + codec::{ + Codec, Decode, Encode, EncodeAsRef, EncodeLike, HasCompact, Input, MaxEncodedLen, Output, + }, scale_info::TypeInfo, sp_std::{ fmt, marker, @@ -63,7 +65,7 @@ pub trait Callable { pub type CallableCallFor = >::Call; /// Origin for the System pallet. -#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo)] +#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum RawOrigin { /// The system itself ordained this dispatch to happen: this is the highest privilege level. Root, @@ -2698,7 +2700,9 @@ mod tests { } } - #[derive(TypeInfo, crate::RuntimeDebug, Eq, PartialEq, Clone, Encode, Decode)] + #[derive( + TypeInfo, crate::RuntimeDebug, Eq, PartialEq, Clone, Encode, Decode, MaxEncodedLen, + )] pub struct OuterOrigin; impl From::AccountId>> for OuterOrigin { diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 53bdd219aa3ee..db8c8da4f869b 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -103,5 +103,6 @@ pub use dispatch::{ mod voting; pub use voting::{ - CurrencyToVote, PollStatus, Polling, SaturatingCurrencyToVote, U128CurrencyToVote, VoteTally, + ClassCountOf, CurrencyToVote, PollStatus, Polling, SaturatingCurrencyToVote, + U128CurrencyToVote, VoteTally, }; diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 9bfb0145009eb..7e97be12e449e 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -18,6 +18,7 @@ //! Traits for dealing with dispatching calls and the origin from which they are dispatched. use crate::dispatch::{DispatchResultWithPostInfo, Parameter, RawOrigin}; +use codec::MaxEncodedLen; use sp_runtime::{ traits::{BadOrigin, Member, Morph, TryMorph}, Either, @@ -258,7 +259,11 @@ pub trait OriginTrait: Sized { type Call; /// The caller origin, overarching type of all pallets origins. - type PalletsOrigin: Parameter + Member + Into + From>; + type PalletsOrigin: Parameter + + Member + + Into + + From> + + MaxEncodedLen; /// The AccountId used across the system. type AccountId; diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index c2d0d4bc3b81f..39ebbb78321d6 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -134,7 +134,7 @@ pub mod v1 { /// A type that can be used as a scheduler. pub trait Anon { /// An address which can be used for removing a scheduled task. - type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo; + type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo + MaxEncodedLen; /// Schedule a dispatch to happen at the beginning of some block in the future. /// @@ -179,7 +179,7 @@ pub mod v1 { /// A type that can be used as a scheduler. pub trait Named { /// An address which can be used for removing a scheduled task. - type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug; + type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug + MaxEncodedLen; /// Schedule a dispatch to happen at the beginning of some block in the future. /// @@ -289,7 +289,7 @@ pub mod v2 { /// A type that can be used as a scheduler. pub trait Anon { /// An address which can be used for removing a scheduled task. - type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo; + type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo + MaxEncodedLen; /// A means of expressing a call by the hash of its encoded data. type Hash; @@ -336,7 +336,7 @@ pub mod v2 { /// A type that can be used as a scheduler. pub trait Named { /// An address which can be used for removing a scheduled task. - type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug; + type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug + MaxEncodedLen; /// A means of expressing a call by the hash of its encoded data. type Hash; diff --git a/frame/support/src/traits/voting.rs b/frame/support/src/traits/voting.rs index 7a3ff87e5940e..b5e7d27073895 100644 --- a/frame/support/src/traits/voting.rs +++ b/frame/support/src/traits/voting.rs @@ -122,6 +122,13 @@ impl PollStatus { } } +pub struct ClassCountOf(sp_std::marker::PhantomData<(P, T)>); +impl> sp_runtime::traits::Get for ClassCountOf { + fn get() -> u32 { + P::classes().len() as u32 + } +} + pub trait Polling { type Index: Parameter + Member + Ord + PartialOrd + Copy + HasCompact + MaxEncodedLen; type Votes: Parameter + Member + Ord + PartialOrd + Copy + HasCompact + MaxEncodedLen; diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 804deb08919a4..63747a9d560dc 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -21,6 +21,7 @@ #![recursion_limit = "128"] +use codec::MaxEncodedLen; use frame_support::traits::{CrateVersion, PalletInfo as _}; use scale_info::TypeInfo; use sp_core::{sr25519, H256}; @@ -55,7 +56,9 @@ mod module1 { } } - #[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo)] + #[derive( + Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo, MaxEncodedLen, + )] pub struct Origin(pub core::marker::PhantomData<(T, I)>); frame_support::decl_event! { @@ -97,7 +100,9 @@ mod module2 { } } - #[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo)] + #[derive( + Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo, MaxEncodedLen, + )] pub struct Origin; frame_support::decl_event! { @@ -140,7 +145,9 @@ mod nested { } } - #[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo)] + #[derive( + Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo, MaxEncodedLen, + )] pub struct Origin; frame_support::decl_event! { @@ -196,7 +203,9 @@ pub mod module3 { } } - #[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo)] + #[derive( + Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo, MaxEncodedLen, + )] pub struct Origin(pub core::marker::PhantomData); frame_support::decl_event! { diff --git a/frame/support/test/tests/instance.rs b/frame/support/test/tests/instance.rs index 2fe8d0e0f22f5..75a96f628245a 100644 --- a/frame/support/test/tests/instance.rs +++ b/frame/support/test/tests/instance.rs @@ -17,7 +17,7 @@ #![recursion_limit = "128"] -use codec::{Codec, Decode, Encode, EncodeLike}; +use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; use frame_support::{ inherent::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent}, metadata::{ @@ -108,7 +108,9 @@ mod module1 { } } - #[derive(PartialEq, Eq, Clone, sp_runtime::RuntimeDebug, Encode, Decode, TypeInfo)] + #[derive( + PartialEq, Eq, Clone, sp_runtime::RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen, + )] pub enum Origin, I> where T::BlockNumber: From, @@ -181,7 +183,9 @@ mod module2 { } } - #[derive(PartialEq, Eq, Clone, sp_runtime::RuntimeDebug, Encode, Decode, TypeInfo)] + #[derive( + PartialEq, Eq, Clone, sp_runtime::RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen, + )] pub enum Origin, I = DefaultInstance> { Members(u32), _Phantom(std::marker::PhantomData<(T, I)>), diff --git a/frame/support/test/tests/origin.rs b/frame/support/test/tests/origin.rs index 1def44c15b48f..cff531ff2e529 100644 --- a/frame/support/test/tests/origin.rs +++ b/frame/support/test/tests/origin.rs @@ -19,6 +19,7 @@ #![recursion_limit = "128"] +use codec::MaxEncodedLen; use frame_support::traits::{Contains, OriginTrait}; use scale_info::TypeInfo; use sp_core::{sr25519, H256}; @@ -30,6 +31,7 @@ mod nested { use super::*; pub mod module { + use super::*; pub trait Config: system::Config {} @@ -45,7 +47,9 @@ mod nested { } } - #[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo)] + #[derive( + Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo, MaxEncodedLen, + )] pub struct Origin; frame_support::decl_event! { @@ -101,7 +105,9 @@ pub mod module { } } - #[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo)] + #[derive( + Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode, TypeInfo, MaxEncodedLen, + )] pub struct Origin(pub core::marker::PhantomData); frame_support::decl_event! { diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index b81941c45ff46..6b72327eb4989 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -359,7 +359,14 @@ pub mod pallet { #[pallet::origin] #[derive( - EqNoBound, RuntimeDebugNoBound, CloneNoBound, PartialEqNoBound, Encode, Decode, TypeInfo, + EqNoBound, + RuntimeDebugNoBound, + CloneNoBound, + PartialEqNoBound, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, )] pub struct Origin(PhantomData); diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index d716637f82895..360a73e5ea2a3 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -30,6 +30,7 @@ use sp_runtime::{DispatchError, ModuleError}; #[frame_support::pallet] pub mod pallet { + use codec::MaxEncodedLen; use frame_support::{pallet_prelude::*, scale_info}; use frame_system::pallet_prelude::*; use sp_std::any::TypeId; @@ -164,6 +165,7 @@ pub mod pallet { Encode, Decode, scale_info::TypeInfo, + MaxEncodedLen, )] #[scale_info(skip_type_params(T, I))] pub struct Origin(PhantomData<(T, I)>); diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 0709b615cf0d4..ab3334f9e4f5a 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -32,7 +32,7 @@ macro_rules! map { } #[doc(hidden)] -pub use codec::{Decode, Encode}; +pub use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] pub use serde; @@ -418,7 +418,7 @@ pub fn to_substrate_wasm_fn_return_value(value: &impl Encode) -> u64 { /// The void type - it cannot exist. // Oh rust, you crack me up... -#[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum Void {} /// Macro for creating `Maybe*` marker traits. diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 97e060cb2a9bd..555f29e5991f7 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -23,7 +23,7 @@ pub mod genesismap; pub mod system; -use codec::{Decode, Encode, Error, Input}; +use codec::{Decode, Encode, Error, Input, MaxEncodedLen}; use scale_info::TypeInfo; use sp_std::{marker::PhantomData, prelude::*}; @@ -439,7 +439,7 @@ impl GetRuntimeBlockType for Runtime { type RuntimeBlock = Block; } -#[derive(Clone, RuntimeDebug, Encode, Decode, PartialEq, Eq, TypeInfo)] +#[derive(Clone, RuntimeDebug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct Origin; impl From> for Origin { From 61f99d96f6c409b700d06d1f5de976fa6b9fe36e Mon Sep 17 00:00:00 2001 From: Boluwatife Bakre Date: Fri, 17 Jun 2022 04:57:29 +0100 Subject: [PATCH 0925/1472] Remove multiply_by_rational (#11598) * Removed multiply_by_rational Replaced with multiply_by_rational_with_rounding * fixes * Test Fixes * nightly fmt * Test Fix * Fixed fuzzer. --- primitives/arithmetic/fuzzer/Cargo.toml | 4 +- ... => multiply_by_rational_with_rounding.rs} | 16 +- primitives/arithmetic/src/fixed_point.rs | 48 ++++-- primitives/arithmetic/src/helpers_128bit.rs | 72 +-------- primitives/arithmetic/src/rational.rs | 151 ++++++++++++------ primitives/npos-elections/src/phragmen.rs | 18 ++- 6 files changed, 162 insertions(+), 147 deletions(-) rename primitives/arithmetic/fuzzer/src/{multiply_by_rational.rs => multiply_by_rational_with_rounding.rs} (77%) diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index 33bf313766545..990106f990323 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -32,8 +32,8 @@ name = "per_thing_rational" path = "src/per_thing_rational.rs" [[bin]] -name = "multiply_by_rational" -path = "src/multiply_by_rational.rs" +name = "multiply_by_rational_with_rounding" +path = "src/multiply_by_rational_with_rounding.rs" [[bin]] name = "fixed_point" diff --git a/primitives/arithmetic/fuzzer/src/multiply_by_rational.rs b/primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs similarity index 77% rename from primitives/arithmetic/fuzzer/src/multiply_by_rational.rs rename to primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs index 019cf0ec39b7d..474b2d363eccd 100644 --- a/primitives/arithmetic/fuzzer/src/multiply_by_rational.rs +++ b/primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs @@ -16,19 +16,21 @@ // limitations under the License. //! # Running -//! Running this fuzzer can be done with `cargo hfuzz run multiply_by_rational`. `honggfuzz` CLI -//! options can be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads. +//! Running this fuzzer can be done with `cargo hfuzz run multiply_by_rational_with_rounding`. +//! `honggfuzz` CLI options can be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 +//! threads. //! //! # Debugging a panic //! Once a panic is found, it can be debugged with -//! `cargo hfuzz run-debug multiply_by_rational hfuzz_workspace/multiply_by_rational/*.fuzz`. +//! `cargo hfuzz run-debug multiply_by_rational_with_rounding +//! hfuzz_workspace/multiply_by_rational_with_rounding/*.fuzz`. //! //! # More information //! More information about `honggfuzz` can be found //! [here](https://docs.rs/honggfuzz/). use honggfuzz::fuzz; -use sp_arithmetic::{helpers_128bit::multiply_by_rational, traits::Zero}; +use sp_arithmetic::{helpers_128bit::multiply_by_rational_with_rounding, traits::Zero, Rounding}; fn main() { loop { @@ -42,9 +44,9 @@ fn main() { println!("++ Equation: {} * {} / {}", a, b, c); - // The point of this fuzzing is to make sure that `multiply_by_rational` is 100% - // accurate as long as the value fits in a u128. - if let Ok(result) = multiply_by_rational(a, b, c) { + // The point of this fuzzing is to make sure that `multiply_by_rational_with_rounding` + // is 100% accurate as long as the value fits in a u128. + if let Some(result) = multiply_by_rational_with_rounding(a, b, c, Rounding::Down) { let truth = mul_div(a, b, c); if result != truth && result != truth + 1 { diff --git a/primitives/arithmetic/src/fixed_point.rs b/primitives/arithmetic/src/fixed_point.rs index 2dfe717fe7e4f..bf3c93cdad605 100644 --- a/primitives/arithmetic/src/fixed_point.rs +++ b/primitives/arithmetic/src/fixed_point.rs @@ -18,7 +18,7 @@ //! Decimal Fixed Point implementations for Substrate runtime. use crate::{ - helpers_128bit::{multiply_by_rational, multiply_by_rational_with_rounding, sqrt}, + helpers_128bit::{multiply_by_rational_with_rounding, sqrt}, traits::{ Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedSub, One, SaturatedConversion, Saturating, UniqueSaturatedInto, Zero, @@ -151,10 +151,14 @@ pub trait FixedPointNumber: let d: I129 = d.into(); let negative = n.negative != d.negative; - multiply_by_rational(n.value, Self::DIV.unique_saturated_into(), d.value) - .ok() - .and_then(|value| from_i129(I129 { value, negative })) - .map(Self::from_inner) + multiply_by_rational_with_rounding( + n.value, + Self::DIV.unique_saturated_into(), + d.value, + Rounding::from_signed(SignedRounding::Minor, negative), + ) + .and_then(|value| from_i129(I129 { value, negative })) + .map(Self::from_inner) } /// Checked multiplication for integer type `N`. Equal to `self * n`. @@ -165,9 +169,13 @@ pub trait FixedPointNumber: let rhs: I129 = n.into(); let negative = lhs.negative != rhs.negative; - multiply_by_rational(lhs.value, rhs.value, Self::DIV.unique_saturated_into()) - .ok() - .and_then(|value| from_i129(I129 { value, negative })) + multiply_by_rational_with_rounding( + lhs.value, + rhs.value, + Self::DIV.unique_saturated_into(), + Rounding::from_signed(SignedRounding::Minor, negative), + ) + .and_then(|value| from_i129(I129 { value, negative })) } /// Saturating multiplication for integer type `N`. Equal to `self * n`. @@ -832,10 +840,14 @@ macro_rules! implement_fixed { // is equivalent to the `SignedRounding::NearestPrefMinor`. This means it is // expected to give exactly the same result as `const_checked_div` when the result // is positive and a result up to one epsilon greater when it is negative. - multiply_by_rational(lhs.value, Self::DIV as u128, rhs.value) - .ok() - .and_then(|value| from_i129(I129 { value, negative })) - .map(Self) + multiply_by_rational_with_rounding( + lhs.value, + Self::DIV as u128, + rhs.value, + Rounding::from_signed(SignedRounding::Minor, negative), + ) + .and_then(|value| from_i129(I129 { value, negative })) + .map(Self) } } @@ -845,10 +857,14 @@ macro_rules! implement_fixed { let rhs: I129 = other.0.into(); let negative = lhs.negative != rhs.negative; - multiply_by_rational(lhs.value, rhs.value, Self::DIV as u128) - .ok() - .and_then(|value| from_i129(I129 { value, negative })) - .map(Self) + multiply_by_rational_with_rounding( + lhs.value, + rhs.value, + Self::DIV as u128, + Rounding::from_signed(SignedRounding::Minor, negative), + ) + .and_then(|value| from_i129(I129 { value, negative })) + .map(Self) } } diff --git a/primitives/arithmetic/src/helpers_128bit.rs b/primitives/arithmetic/src/helpers_128bit.rs index 11df8bd53153e..7938c31d1eaa6 100644 --- a/primitives/arithmetic/src/helpers_128bit.rs +++ b/primitives/arithmetic/src/helpers_128bit.rs @@ -22,12 +22,7 @@ //! multiplication implementation provided there. use crate::{biguint, Rounding}; -use num_traits::Zero; -use sp_std::{ - cmp::{max, min}, - convert::TryInto, - mem, -}; +use sp_std::cmp::{max, min}; /// Helper gcd function used in Rational128 implementation. pub fn gcd(a: u128, b: u128) -> u128 { @@ -61,65 +56,6 @@ pub fn to_big_uint(x: u128) -> biguint::BigUint { n } -/// Safely and accurately compute `a * b / c`. The approach is: -/// - Simply try `a * b / c`. -/// - Else, convert them both into big numbers and re-try. `Err` is returned if the result cannot -/// be safely casted back to u128. -/// -/// Invariant: c must be greater than or equal to 1. -pub fn multiply_by_rational(mut a: u128, mut b: u128, mut c: u128) -> Result { - if a.is_zero() || b.is_zero() { - return Ok(Zero::zero()) - } - c = c.max(1); - - // a and b are interchangeable by definition in this function. It always helps to assume the - // bigger of which is being multiplied by a `0 < b/c < 1`. Hence, a should be the bigger and - // b the smaller one. - if b > a { - mem::swap(&mut a, &mut b); - } - - // Attempt to perform the division first - if a % c == 0 { - a /= c; - c = 1; - } else if b % c == 0 { - b /= c; - c = 1; - } - - if let Some(x) = a.checked_mul(b) { - // This is the safest way to go. Try it. - Ok(x / c) - } else { - let a_num = to_big_uint(a); - let b_num = to_big_uint(b); - let c_num = to_big_uint(c); - - let mut ab = a_num * b_num; - ab.lstrip(); - let mut q = if c_num.len() == 1 { - // PROOF: if `c_num.len() == 1` then `c` fits in one limb. - ab.div_unit(c as biguint::Single) - } else { - // PROOF: both `ab` and `c` cannot have leading zero limbs; if length of `c` is 1, - // the previous branch would handle. Also, if ab for sure has a bigger size than - // c, because `a.checked_mul(b)` has failed, hence ab must be at least one limb - // bigger than c. In this case, returning zero is defensive-only and div should - // always return Some. - let (mut q, r) = ab.div(&c_num, true).unwrap_or((Zero::zero(), Zero::zero())); - let r: u128 = r.try_into().expect("reminder of div by c is always less than c; qed"); - if r > (c / 2) { - q = q.add(&to_big_uint(1)); - } - q - }; - q.lstrip(); - q.try_into().map_err(|_| "result cannot fit in u128") - } -} - mod double128 { // Inspired by: https://medium.com/wicketh/mathemagic-512-bit-division-in-solidity-afa55870a65 @@ -247,7 +183,7 @@ mod double128 { } /// Returns `a * b / c` and `(a * b) % c` (wrapping to 128 bits) or `None` in the case of -/// overflow. +/// overflow and c = 0. pub const fn multiply_by_rational_with_rounding( a: u128, b: u128, @@ -256,7 +192,7 @@ pub const fn multiply_by_rational_with_rounding( ) -> Option { use double128::Double128; if c == 0 { - panic!("attempt to divide by zero") + return None } let (result, remainder) = Double128::product_of(a, b).div(c); let mut result: u128 = match result.try_into_u128() { @@ -361,7 +297,7 @@ mod tests { let b = random_u128(i + (1 << 30)); let c = random_u128(i + (1 << 31)); let x = mulrat(a, b, c, NearestPrefDown); - let y = multiply_by_rational(a, b, c).ok(); + let y = multiply_by_rational_with_rounding(a, b, c, Rounding::NearestPrefDown); assert_eq!(x.is_some(), y.is_some()); let x = x.unwrap_or(0); let y = y.unwrap_or(0); diff --git a/primitives/arithmetic/src/rational.rs b/primitives/arithmetic/src/rational.rs index 1beafbe811614..54cabfc6214e8 100644 --- a/primitives/arithmetic/src/rational.rs +++ b/primitives/arithmetic/src/rational.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{biguint::BigUint, helpers_128bit}; +use crate::{biguint::BigUint, helpers_128bit, Rounding}; use num_traits::{Bounded, One, Zero}; use sp_std::{cmp::Ordering, prelude::*}; @@ -143,27 +143,38 @@ impl Rational128 { /// Convert `self` to a similar rational number where denominator is the given `den`. // - /// This only returns if the result is accurate. `Err` is returned if the result cannot be + /// This only returns if the result is accurate. `None` is returned if the result cannot be /// accurately calculated. - pub fn to_den(self, den: u128) -> Result { + pub fn to_den(self, den: u128) -> Option { if den == self.1 { - Ok(self) + Some(self) } else { - helpers_128bit::multiply_by_rational(self.0, den, self.1).map(|n| Self(n, den)) + helpers_128bit::multiply_by_rational_with_rounding( + self.0, + den, + self.1, + Rounding::NearestPrefDown, + ) + .map(|n| Self(n, den)) } } /// Get the least common divisor of `self` and `other`. /// - /// This only returns if the result is accurate. `Err` is returned if the result cannot be + /// This only returns if the result is accurate. `None` is returned if the result cannot be /// accurately calculated. - pub fn lcm(&self, other: &Self) -> Result { + pub fn lcm(&self, other: &Self) -> Option { // this should be tested better: two large numbers that are almost the same. if self.1 == other.1 { - return Ok(self.1) + return Some(self.1) } let g = helpers_128bit::gcd(self.1, other.1); - helpers_128bit::multiply_by_rational(self.1, other.1, g) + helpers_128bit::multiply_by_rational_with_rounding( + self.1, + other.1, + g, + Rounding::NearestPrefDown, + ) } /// A saturating add that assumes `self` and `other` have the same denominator. @@ -188,9 +199,11 @@ impl Rational128 { /// /// Overflow might happen during any of the steps. Error is returned in such cases. pub fn checked_add(self, other: Self) -> Result { - let lcm = self.lcm(&other).map_err(|_| "failed to scale to denominator")?; - let self_scaled = self.to_den(lcm).map_err(|_| "failed to scale to denominator")?; - let other_scaled = other.to_den(lcm).map_err(|_| "failed to scale to denominator")?; + let lcm = self.lcm(&other).ok_or(0).map_err(|_| "failed to scale to denominator")?; + let self_scaled = + self.to_den(lcm).ok_or(0).map_err(|_| "failed to scale to denominator")?; + let other_scaled = + other.to_den(lcm).ok_or(0).map_err(|_| "failed to scale to denominator")?; let n = self_scaled .0 .checked_add(other_scaled.0) @@ -202,9 +215,11 @@ impl Rational128 { /// /// Overflow might happen during any of the steps. None is returned in such cases. pub fn checked_sub(self, other: Self) -> Result { - let lcm = self.lcm(&other).map_err(|_| "failed to scale to denominator")?; - let self_scaled = self.to_den(lcm).map_err(|_| "failed to scale to denominator")?; - let other_scaled = other.to_den(lcm).map_err(|_| "failed to scale to denominator")?; + let lcm = self.lcm(&other).ok_or(0).map_err(|_| "failed to scale to denominator")?; + let self_scaled = + self.to_den(lcm).ok_or(0).map_err(|_| "failed to scale to denominator")?; + let other_scaled = + other.to_den(lcm).ok_or(0).map_err(|_| "failed to scale to denominator")?; let n = self_scaled .0 @@ -314,18 +329,18 @@ mod tests { #[test] fn to_denom_works() { // simple up and down - assert_eq!(r(1, 5).to_den(10), Ok(r(2, 10))); - assert_eq!(r(4, 10).to_den(5), Ok(r(2, 5))); + assert_eq!(r(1, 5).to_den(10), Some(r(2, 10))); + assert_eq!(r(4, 10).to_den(5), Some(r(2, 5))); // up and down with large numbers - assert_eq!(r(MAX128 - 10, MAX128).to_den(10), Ok(r(10, 10))); - assert_eq!(r(MAX128 / 2, MAX128).to_den(10), Ok(r(5, 10))); + assert_eq!(r(MAX128 - 10, MAX128).to_den(10), Some(r(10, 10))); + assert_eq!(r(MAX128 / 2, MAX128).to_den(10), Some(r(5, 10))); // large to perbill. This is very well needed for npos-elections. - assert_eq!(r(MAX128 / 2, MAX128).to_den(1000_000_000), Ok(r(500_000_000, 1000_000_000))); + assert_eq!(r(MAX128 / 2, MAX128).to_den(1000_000_000), Some(r(500_000_000, 1000_000_000))); // large to large - assert_eq!(r(MAX128 / 2, MAX128).to_den(MAX128 / 2), Ok(r(MAX128 / 4, MAX128 / 2))); + assert_eq!(r(MAX128 / 2, MAX128).to_den(MAX128 / 2), Some(r(MAX128 / 4, MAX128 / 2))); } #[test] @@ -342,13 +357,10 @@ mod tests { assert_eq!(r(5, 30).lcm(&r(1, 10)).unwrap(), 30); // large numbers - assert_eq!( - r(1_000_000_000, MAX128).lcm(&r(7_000_000_000, MAX128 - 1)), - Err("result cannot fit in u128"), - ); + assert_eq!(r(1_000_000_000, MAX128).lcm(&r(7_000_000_000, MAX128 - 1)), None,); assert_eq!( r(1_000_000_000, MAX64).lcm(&r(7_000_000_000, MAX64 - 1)), - Ok(340282366920938463408034375210639556610), + Some(340282366920938463408034375210639556610), ); const_assert!(340282366920938463408034375210639556610 < MAX128); const_assert!(340282366920938463408034375210639556610 == MAX64 * (MAX64 - 1)); @@ -408,55 +420,87 @@ mod tests { } #[test] - fn multiply_by_rational_works() { - assert_eq!(multiply_by_rational(7, 2, 3).unwrap(), 7 * 2 / 3); - assert_eq!(multiply_by_rational(7, 20, 30).unwrap(), 7 * 2 / 3); - assert_eq!(multiply_by_rational(20, 7, 30).unwrap(), 7 * 2 / 3); + fn multiply_by_rational_with_rounding_works() { + assert_eq!(multiply_by_rational_with_rounding(7, 2, 3, Rounding::Down).unwrap(), 7 * 2 / 3); + assert_eq!( + multiply_by_rational_with_rounding(7, 20, 30, Rounding::Down).unwrap(), + 7 * 2 / 3 + ); + assert_eq!( + multiply_by_rational_with_rounding(20, 7, 30, Rounding::Down).unwrap(), + 7 * 2 / 3 + ); assert_eq!( // MAX128 % 3 == 0 - multiply_by_rational(MAX128, 2, 3).unwrap(), + multiply_by_rational_with_rounding(MAX128, 2, 3, Rounding::Down).unwrap(), MAX128 / 3 * 2, ); assert_eq!( // MAX128 % 7 == 3 - multiply_by_rational(MAX128, 5, 7).unwrap(), + multiply_by_rational_with_rounding(MAX128, 5, 7, Rounding::Down).unwrap(), (MAX128 / 7 * 5) + (3 * 5 / 7), ); assert_eq!( // MAX128 % 7 == 3 - multiply_by_rational(MAX128, 11, 13).unwrap(), + multiply_by_rational_with_rounding(MAX128, 11, 13, Rounding::Down).unwrap(), (MAX128 / 13 * 11) + (8 * 11 / 13), ); assert_eq!( // MAX128 % 1000 == 455 - multiply_by_rational(MAX128, 555, 1000).unwrap(), + multiply_by_rational_with_rounding(MAX128, 555, 1000, Rounding::Down).unwrap(), (MAX128 / 1000 * 555) + (455 * 555 / 1000), ); - assert_eq!(multiply_by_rational(2 * MAX64 - 1, MAX64, MAX64).unwrap(), 2 * MAX64 - 1); - assert_eq!(multiply_by_rational(2 * MAX64 - 1, MAX64 - 1, MAX64).unwrap(), 2 * MAX64 - 3); + assert_eq!( + multiply_by_rational_with_rounding(2 * MAX64 - 1, MAX64, MAX64, Rounding::Down) + .unwrap(), + 2 * MAX64 - 1 + ); + assert_eq!( + multiply_by_rational_with_rounding(2 * MAX64 - 1, MAX64 - 1, MAX64, Rounding::Down) + .unwrap(), + 2 * MAX64 - 3 + ); assert_eq!( - multiply_by_rational(MAX64 + 100, MAX64_2, MAX64_2 / 2).unwrap(), + multiply_by_rational_with_rounding(MAX64 + 100, MAX64_2, MAX64_2 / 2, Rounding::Down) + .unwrap(), (MAX64 + 100) * 2, ); assert_eq!( - multiply_by_rational(MAX64 + 100, MAX64_2 / 100, MAX64_2 / 200).unwrap(), + multiply_by_rational_with_rounding( + MAX64 + 100, + MAX64_2 / 100, + MAX64_2 / 200, + Rounding::Down + ) + .unwrap(), (MAX64 + 100) * 2, ); assert_eq!( - multiply_by_rational(2u128.pow(66) - 1, 2u128.pow(65) - 1, 2u128.pow(65)).unwrap(), + multiply_by_rational_with_rounding( + 2u128.pow(66) - 1, + 2u128.pow(65) - 1, + 2u128.pow(65), + Rounding::Down + ) + .unwrap(), 73786976294838206461, ); - assert_eq!(multiply_by_rational(1_000_000_000, MAX128 / 8, MAX128 / 2).unwrap(), 250000000); + assert_eq!( + multiply_by_rational_with_rounding(1_000_000_000, MAX128 / 8, MAX128 / 2, Rounding::Up) + .unwrap(), + 250000000 + ); assert_eq!( - multiply_by_rational( + multiply_by_rational_with_rounding( 29459999999999999988000u128, 1000000000000000000u128, - 10000000000000000000u128 + 10000000000000000000u128, + Rounding::Down ) .unwrap(), 2945999999999999998800u128 @@ -464,17 +508,28 @@ mod tests { } #[test] - fn multiply_by_rational_a_b_are_interchangeable() { - assert_eq!(multiply_by_rational(10, MAX128, MAX128 / 2), Ok(20)); - assert_eq!(multiply_by_rational(MAX128, 10, MAX128 / 2), Ok(20)); + fn multiply_by_rational_with_rounding_a_b_are_interchangeable() { + assert_eq!( + multiply_by_rational_with_rounding(10, MAX128, MAX128 / 2, Rounding::NearestPrefDown), + Some(20) + ); + assert_eq!( + multiply_by_rational_with_rounding(MAX128, 10, MAX128 / 2, Rounding::NearestPrefDown), + Some(20) + ); } #[test] #[ignore] - fn multiply_by_rational_fuzzed_equation() { + fn multiply_by_rational_with_rounding_fuzzed_equation() { assert_eq!( - multiply_by_rational(154742576605164960401588224, 9223376310179529214, 549756068598), - Ok(2596149632101417846585204209223679) + multiply_by_rational_with_rounding( + 154742576605164960401588224, + 9223376310179529214, + 549756068598, + Rounding::NearestPrefDown + ), + Some(2596149632101417846585204209223679) ); } } diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index 9b50dc36e48fb..ca32780ed84b4 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -25,9 +25,9 @@ use crate::{ IdentifierT, PerThing128, VoteWeight, Voter, }; use sp_arithmetic::{ - helpers_128bit::multiply_by_rational, + helpers_128bit::multiply_by_rational_with_rounding, traits::{Bounded, Zero}, - Rational128, + Rational128, Rounding, }; use sp_std::prelude::*; @@ -143,10 +143,11 @@ pub fn seq_phragmen_core( for edge in &voter.edges { let mut candidate = edge.candidate.borrow_mut(); if !candidate.elected && !candidate.approval_stake.is_zero() { - let temp_n = multiply_by_rational( + let temp_n = multiply_by_rational_with_rounding( voter.load.n(), voter.budget, candidate.approval_stake, + Rounding::Down, ) .unwrap_or(Bounded::max_value()); let temp_d = voter.load.d(); @@ -184,9 +185,14 @@ pub fn seq_phragmen_core( for edge in &mut voter.edges { if edge.candidate.borrow().elected { // update internal state. - edge.weight = multiply_by_rational(voter.budget, edge.load.n(), voter.load.n()) - // If result cannot fit in u128. Not much we can do about it. - .unwrap_or(Bounded::max_value()); + edge.weight = multiply_by_rational_with_rounding( + voter.budget, + edge.load.n(), + voter.load.n(), + Rounding::Down, + ) + // If result cannot fit in u128. Not much we can do about it. + .unwrap_or(Bounded::max_value()); } else { edge.weight = 0 } From b195d0a5e20be4dfa5d29283bfb3a7417f94e4cd Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 17 Jun 2022 17:47:14 +0400 Subject: [PATCH 0926/1472] Upgrade to libp2p 0.45.1 (#11682) * Upgrade to libp2p 0.45.1 * Limit max_negotiating_inbound_streams to 512 * Upgrade prost-build to 0.10 * Set max_negotiating_inbound_streams to 2048 Co-authored-by: Pierre Krieger * Fix authority discovery protobuf * Fix comments in authority-discovery schema Co-authored-by: Pierre Krieger * Add a comment about transport initialization Co-authored-by: Pierre Krieger --- Cargo.lock | 327 +++++++++++------- client/authority-discovery/Cargo.toml | 4 +- .../src/worker/schema/dht-v2.proto | 4 +- client/cli/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 4 +- client/network/common/Cargo.toml | 4 +- client/network/light/Cargo.toml | 4 +- client/network/src/service.rs | 3 +- client/network/src/transport.rs | 9 +- client/network/sync/Cargo.toml | 4 +- client/network/test/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/telemetry/src/lib.rs | 36 +- client/telemetry/src/node.rs | 24 +- 17 files changed, 277 insertions(+), 158 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84443396e0d06..e33211911b47a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,9 +135,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "asn1_der" @@ -365,15 +365,6 @@ dependencies = [ "pin-project-lite 0.2.6", ] -[[package]] -name = "atomic" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3410529e8288c463bedb5930f82833bc0c90e5d2fe639a56582a4d09220b281" -dependencies = [ - "autocfg 1.0.1", -] - [[package]] name = "atomic-waker" version = "1.0.0" @@ -622,7 +613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" dependencies = [ "arrayref", - "arrayvec 0.7.1", + "arrayvec 0.7.2", "constant_time_eq", ] @@ -633,7 +624,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" dependencies = [ "arrayref", - "arrayvec 0.7.1", + "arrayvec 0.7.2", "constant_time_eq", ] @@ -644,7 +635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" dependencies = [ "arrayref", - "arrayvec 0.7.1", + "arrayvec 0.7.2", "cc", "cfg-if 1.0.0", "constant_time_eq", @@ -1037,6 +1028,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "cmake" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b858541263efe664aead4a5209a4ae5c5d2811167d4ed4ee0944503f8d2089" +dependencies = [ + "cc", +] + [[package]] name = "comfy-table" version = "5.0.1" @@ -3201,7 +3201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16efcd4477de857d4a2195a45769b2fe9ebb54f3ef5a4221d3b014a4fe33ec0b" dependencies = [ "anyhow", - "arrayvec 0.7.1", + "arrayvec 0.7.2", "async-lock", "async-trait", "beef", @@ -3437,11 +3437,10 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libp2p" -version = "0.44.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475ce2ac4a9727e53a519f6ee05b38abfcba8f0d39c4d24f103d184e36fd5b0f" +checksum = "41726ee8f662563fafba2d2d484b14037cc8ecb8c953fbfc8439d4ce3a0a9029" dependencies = [ - "atomic", "bytes", "futures", "futures-timer", @@ -3449,7 +3448,7 @@ dependencies = [ "instant", "lazy_static", "libp2p-autonat", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-deflate", "libp2p-dns", "libp2p-floodsub", @@ -3482,20 +3481,20 @@ dependencies = [ [[package]] name = "libp2p-autonat" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13b690e65046af6a09c0b27bd9508fa1cab0efce889de74b0b643b9d2a98f9a" +checksum = "50de7c1d5c3f040fccb469e8a2d189e068b7627d760dd74ef914071c16bbe905" dependencies = [ "async-trait", "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-request-response", "libp2p-swarm", "log", - "prost 0.9.0", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.8.4", ] @@ -3514,7 +3513,6 @@ dependencies = [ "futures-timer", "instant", "lazy_static", - "libsecp256k1", "log", "multiaddr", "multihash", @@ -3522,10 +3520,45 @@ dependencies = [ "parking_lot 0.12.0", "pin-project 1.0.10", "prost 0.9.0", - "prost-build", + "prost-build 0.9.0", + "rand 0.8.4", + "ring", + "rw-stream-sink 0.2.1", + "sha2 0.10.2", + "smallvec", + "thiserror", + "unsigned-varint", + "void", + "zeroize", +] + +[[package]] +name = "libp2p-core" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d46fca305dee6757022e2f5a4f6c023315084d0ed7441c3ab244e76666d979" +dependencies = [ + "asn1_der", + "bs58", + "ed25519-dalek", + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "lazy_static", + "libsecp256k1", + "log", + "multiaddr", + "multihash", + "multistream-select", + "parking_lot 0.12.0", + "pin-project 1.0.10", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.8.4", "ring", - "rw-stream-sink", + "rw-stream-sink 0.3.0", "sha2 0.10.2", "smallvec", "thiserror", @@ -3536,52 +3569,53 @@ dependencies = [ [[package]] name = "libp2p-deflate" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1d37f042f748e224f04785d0e987ae09a2aa518d6401d82d412dad83e360ed" +checksum = "86adefc55ea4ed8201149f052fb441210727481dff1fb0b8318460206a79f5fb" dependencies = [ "flate2", "futures", - "libp2p-core", + "libp2p-core 0.33.0", ] [[package]] name = "libp2p-dns" -version = "0.32.1" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "066e33e854e10b5c93fc650458bf2179c7e0d143db260b0963e44a94859817f1" +checksum = "fbb462ec3a51fab457b4b44ac295e8b0a4b04dc175127e615cf996b1f0f1a268" dependencies = [ "async-std-resolver", "futures", - "libp2p-core", + "libp2p-core 0.33.0", "log", + "parking_lot 0.12.0", "smallvec", "trust-dns-resolver", ] [[package]] name = "libp2p-floodsub" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733d3ea6ebe7a7a85df2bc86678b93f24b015fae5fe3b3acc4c400e795a55d2d" +checksum = "a505d0c6f851cbf2919535150198e530825def8bd3757477f13dc3a57f46cbcc" dependencies = [ "cuckoofilter", "fnv", "futures", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-swarm", "log", - "prost 0.9.0", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.7.3", "smallvec", ] [[package]] name = "libp2p-gossipsub" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90c989a7c0969c2ab63e898da9bc735e3be53fb4f376e9c045ce516bcc9f928" +checksum = "c9be947d8cea8e6b469201314619395826896d2c051053c3723910ba98e68e04" dependencies = [ "asynchronous-codec", "base64", @@ -3591,12 +3625,12 @@ dependencies = [ "futures", "hex_fmt", "instant", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-swarm", "log", "prometheus-client", - "prost 0.9.0", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.7.3", "regex", "sha2 0.10.2", @@ -3607,28 +3641,32 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.35.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ef5a5b57904c7c33d6713ef918d239dc6b7553458f3475d87f8a18e9c651c8" +checksum = "b84b53490442d086db1fa5375670c9666e79143dccadef3f7c74a4346899a984" dependencies = [ + "asynchronous-codec", "futures", "futures-timer", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-swarm", "log", "lru", - "prost 0.9.0", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", + "prost-codec", "smallvec", + "thiserror", + "void", ] [[package]] name = "libp2p-kad" -version = "0.36.0" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564e6bd64d177446399ed835b9451a8825b07929d6daa6a94e6405592974725e" +checksum = "5f6b5d4de90fcd35feb65ea6223fd78f3b747a64ca4b65e0813fbe66a27d56aa" dependencies = [ - "arrayvec 0.5.2", + "arrayvec 0.7.2", "asynchronous-codec", "bytes", "either", @@ -3636,11 +3674,11 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-swarm", "log", - "prost 0.9.0", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.7.3", "sha2 0.10.2", "smallvec", @@ -3652,9 +3690,9 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611ae873c8e280ccfab0d57c7a13cac5644f364529e233114ff07863946058b0" +checksum = "4783f8cf00c7b6c1ff0f1870b4fcf50b042b45533d2e13b6fb464caf447a6951" dependencies = [ "async-io", "data-encoding", @@ -3662,7 +3700,7 @@ dependencies = [ "futures", "if-watch", "lazy_static", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-swarm", "log", "rand 0.8.4", @@ -3673,11 +3711,11 @@ dependencies = [ [[package]] name = "libp2p-metrics" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985be799bb3796e0c136c768208c3c06604a38430571906a13dcfeda225a3b9d" +checksum = "adc4357140141ba9739eee71b20aa735351c0fc642635b2bffc7f57a6b5c1090" dependencies = [ - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-gossipsub", "libp2p-identify", "libp2p-kad", @@ -3689,14 +3727,14 @@ dependencies = [ [[package]] name = "libp2p-mplex" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "442eb0c9fff0bf22a34f015724b4143ce01877e079ed0963c722d94c07c72160" +checksum = "5ff9c893f2367631a711301d703c47432af898c9bb8253bea0e2c051a13f7640" dependencies = [ "asynchronous-codec", "bytes", "futures", - "libp2p-core", + "libp2p-core 0.33.0", "log", "nohash-hasher", "parking_lot 0.12.0", @@ -3707,18 +3745,18 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd7e0c94051cda67123be68cf6b65211ba3dde7277be9068412de3e7ffd63ef" +checksum = "cf2cee1dad1c83325bbd182a8e94555778699cec8a9da00086efb7522c4c15ad" dependencies = [ "bytes", "curve25519-dalek 3.0.2", "futures", "lazy_static", - "libp2p-core", + "libp2p-core 0.33.0", "log", - "prost 0.9.0", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.8.4", "sha2 0.10.2", "snow", @@ -3729,14 +3767,14 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf57a3c2e821331dda9fe612d4654d676ab6e33d18d9434a18cced72630df6ad" +checksum = "d41516c82fe8dd148ec925eead0c5ec08a0628f7913597e93e126e4dfb4e0787" dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-swarm", "log", "rand 0.7.3", @@ -3745,17 +3783,17 @@ dependencies = [ [[package]] name = "libp2p-plaintext" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "962c0fb0e7212fb96a69b87f2d09bcefd317935239bdc79cda900e7a8897a3fe" +checksum = "db007e737adc5d28b2e03223b0210164928ad742591127130796a72aa8eaf54f" dependencies = [ "asynchronous-codec", "bytes", "futures", - "libp2p-core", + "libp2p-core 0.33.0", "log", - "prost 0.9.0", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "unsigned-varint", "void", ] @@ -3776,9 +3814,9 @@ dependencies = [ [[package]] name = "libp2p-relay" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aa754cb7bccef51ebc3c458c6bbcef89d83b578a9925438389be841527d408f" +checksum = "624ead3406f64437a0d4567c31bd128a9a0b8226d5f16c074038f5d0fc32f650" dependencies = [ "asynchronous-codec", "bytes", @@ -3786,36 +3824,36 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-swarm", "log", "pin-project 1.0.10", - "prost 0.9.0", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", + "prost-codec", "rand 0.8.4", "smallvec", "static_assertions", "thiserror", - "unsigned-varint", "void", ] [[package]] name = "libp2p-rendezvous" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd0baab894c5b84da510b915d53264d566c3c35889f09931fe9edbd2a773bee" +checksum = "c59967ea2db2c7560f641aa58ac05982d42131863fcd3dd6dcf0dd1daf81c60c" dependencies = [ "asynchronous-codec", "bimap", "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-swarm", "log", - "prost 0.9.0", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.8.4", "sha2 0.10.2", "thiserror", @@ -3825,15 +3863,15 @@ dependencies = [ [[package]] name = "libp2p-request-response" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6a6fc6c9ad95661f46989473b34bd2993d14a4de497ff3b2668a910d4b869" +checksum = "b02e0acb725e5a757d77c96b95298fd73a7394fe82ba7b8bbeea510719cbe441" dependencies = [ "async-trait", "bytes", "futures", "instant", - "libp2p-core", + "libp2p-core 0.33.0", "libp2p-swarm", "log", "rand 0.7.3", @@ -3843,16 +3881,16 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.35.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f0c69ad9e8f7c5fc50ad5ad9c7c8b57f33716532a2b623197f69f93e374d14c" +checksum = "8f4bb21c5abadbf00360c734f16bf87f1712ed4f23cd46148f625d2ddb867346" dependencies = [ "either", "fnv", "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.33.0", "log", "pin-project 1.0.10", "rand 0.7.3", @@ -3873,9 +3911,9 @@ dependencies = [ [[package]] name = "libp2p-tcp" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193447aa729c85aac2376828df76d171c1a589c9e6b58fcc7f9d9a020734122c" +checksum = "4f4933e38ef21b50698aefc87799c24f2a365c9d3f6cf50471f3f6a0bc410892" dependencies = [ "async-io", "futures", @@ -3883,7 +3921,7 @@ dependencies = [ "if-watch", "ipnet", "libc", - "libp2p-core", + "libp2p-core 0.33.0", "log", "socket2 0.4.4", ] @@ -3896,19 +3934,19 @@ checksum = "24bdab114f7f2701757d6541266e1131b429bbae382008f207f2114ee4222dcb" dependencies = [ "async-std", "futures", - "libp2p-core", + "libp2p-core 0.32.1", "log", ] [[package]] name = "libp2p-wasm-ext" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f6ea0f84a967ef59a16083f222c18115ae2e91db69809dce275df62e101b279" +checksum = "f066f2b8b1a1d64793f05da2256e6842ecd0293d6735ca2e9bda89831a1bdc06" dependencies = [ "futures", "js-sys", - "libp2p-core", + "libp2p-core 0.33.0", "parity-send-wrapper", "wasm-bindgen", "wasm-bindgen-futures", @@ -3916,17 +3954,18 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.34.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c932834c3754501c368d1bf3d0fb458487a642b90fc25df082a3a2f3d3b32e37" +checksum = "39d398fbb29f432c4128fabdaac2ed155c3bcaf1b9bd40eeeb10a471eefacbf5" dependencies = [ "either", "futures", "futures-rustls", - "libp2p-core", + "libp2p-core 0.33.0", "log", + "parking_lot 0.12.0", "quicksink", - "rw-stream-sink", + "rw-stream-sink 0.3.0", "soketto", "url", "webpki-roots", @@ -3934,12 +3973,12 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be902ebd89193cd020e89e89107726a38cfc0d16d18f613f4a37d046e92c7517" +checksum = "8fe653639ad74877c759720febb0cbcbf4caa221adde4eed2d3126ce5c6f381f" dependencies = [ "futures", - "libp2p-core", + "libp2p-core 0.33.0", "parking_lot 0.12.0", "thiserror", "yamux", @@ -6538,7 +6577,7 @@ version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04bc9583b5e01cc8c70d89acc9af14ef9b1c29ee3a0074b2a9eea8c0fa396690" dependencies = [ - "arrayvec 0.7.1", + "arrayvec 0.7.2", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", @@ -7025,9 +7064,9 @@ dependencies = [ [[package]] name = "prometheus-client" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a896938cc6018c64f279888b8c7559d3725210d5db9a3a1ee6bc7188d51d34" +checksum = "ac1abe0255c04d15f571427a2d1e00099016506cf3297b53853acd2b7eb87825" dependencies = [ "dtoa", "itoa 1.0.1", @@ -7080,12 +7119,47 @@ dependencies = [ "multimap", "petgraph", "prost 0.9.0", - "prost-types", + "prost-types 0.9.0", + "regex", + "tempfile", + "which", +] + +[[package]] +name = "prost-build" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae5a4388762d5815a9fc0dea33c56b021cdc8dde0c55e0c9ca57197254b0cab" +dependencies = [ + "bytes", + "cfg-if 1.0.0", + "cmake", + "heck 0.4.0", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prost 0.10.3", + "prost-types 0.10.1", "regex", "tempfile", "which", ] +[[package]] +name = "prost-codec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00af1e92c33b4813cc79fda3f2dbf56af5169709be0202df730e9ebc3e4cd007" +dependencies = [ + "asynchronous-codec", + "bytes", + "prost 0.10.3", + "thiserror", + "unsigned-varint", +] + [[package]] name = "prost-derive" version = "0.9.0" @@ -7122,6 +7196,16 @@ dependencies = [ "prost 0.9.0", ] +[[package]] +name = "prost-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" +dependencies = [ + "bytes", + "prost 0.10.3", +] + [[package]] name = "psm" version = "0.1.12" @@ -7805,6 +7889,17 @@ dependencies = [ "static_assertions", ] +[[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 1.0.10", + "static_assertions", +] + [[package]] name = "ryu" version = "1.0.5" @@ -7860,7 +7955,7 @@ dependencies = [ "log", "parity-scale-codec", "prost 0.10.3", - "prost-build", + "prost-build 0.10.4", "quickcheck", "rand 0.7.3", "sc-client-api", @@ -8512,7 +8607,7 @@ dependencies = [ "parking_lot 0.12.0", "pin-project 1.0.10", "prost 0.10.3", - "prost-build", + "prost-build 0.10.4", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8550,7 +8645,7 @@ dependencies = [ "futures", "libp2p", "parity-scale-codec", - "prost-build", + "prost-build 0.10.4", "sc-peerset", "smallvec", ] @@ -8583,7 +8678,7 @@ dependencies = [ "log", "parity-scale-codec", "prost 0.10.3", - "prost-build", + "prost-build 0.10.4", "sc-client-api", "sc-network-common", "sc-peerset", @@ -8606,7 +8701,7 @@ dependencies = [ "lru", "parity-scale-codec", "prost 0.10.3", - "prost-build", + "prost-build 0.10.4", "quickcheck", "sc-block-builder", "sc-client-api", diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 136c2606a384e..32a5e23bd49d9 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.9" +prost-build = "0.10" [dependencies] async-trait = "0.1" @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" -libp2p = { version = "0.44.0", default-features = false, features = ["kad"] } +libp2p = { version = "0.45.1", default-features = false, features = ["kad"] } log = "0.4.17" prost = "0.10" rand = "0.7.2" diff --git a/client/authority-discovery/src/worker/schema/dht-v2.proto b/client/authority-discovery/src/worker/schema/dht-v2.proto index c63f6c1767351..fdbadb4266306 100644 --- a/client/authority-discovery/src/worker/schema/dht-v2.proto +++ b/client/authority-discovery/src/worker/schema/dht-v2.proto @@ -18,6 +18,6 @@ message SignedAuthorityRecord { bytes record = 1; bytes auth_signature = 2; // Even if there are multiple `record.addresses`, all of them have the same peer id. - // Old versions are missing this field, so `optional` will provide compatibility both ways. - optional PeerSignature peer_signature = 3; + // Old versions are missing this field. It is optional in order to provide compatibility both ways. + PeerSignature peer_signature = 3; } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 4f0d777d137b9..72b4efde077ff 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -18,7 +18,7 @@ clap = { version = "3.1.18", features = ["derive"] } fdlimit = "0.2.1" futures = "0.3.21" hex = "0.4.2" -libp2p = "0.44.0" +libp2p = "0.45.1" log = "0.4.17" names = { version = "0.13.0", default-features = false } parity-scale-codec = "3.0.0" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 1508dfa82a363..6d76eba0935ff 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.42" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" -libp2p = { version = "0.44.0", default-features = false } +libp2p = { version = "0.45.1", default-features = false } log = "0.4.17" parking_lot = "0.12.0" serde = { version = "1.0", features = ["derive"] } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 641574db288d7..0fac96b0fdde0 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] ahash = "0.7.6" futures = "0.3.21" futures-timer = "3.0.1" -libp2p = { version = "0.44.0", default-features = false } +libp2p = { version = "0.45.1", default-features = false } log = "0.4.17" lru = "0.7.5" tracing = "0.1.29" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 89a36bc483e6c..1b525844395b5 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.9" +prost-build = "0.10" [dependencies] async-trait = "0.1" @@ -29,7 +29,7 @@ futures = "0.3.21" futures-timer = "3.0.2" hex = "0.4.0" ip_network = "0.4.1" -libp2p = "0.44.0" +libp2p = "0.45.1" linked_hash_set = "0.1.3" linked-hash-map = "0.5.4" log = "0.4.17" diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index c41a7895888ae..553eb57958a5d 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -14,13 +14,13 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.9" +prost-build = "0.10" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -libp2p = "0.44.0" +libp2p = "0.45.1" smallvec = "1.8.0" sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index aa0b003e00763..924b8ed06ab0a 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -14,14 +14,14 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.9" +prost-build = "0.10" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -libp2p = "0.44.0" +libp2p = "0.45.1" log = "0.4.16" prost = "0.10" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index edd30e9c9dee4..1cc717a50d039 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -379,7 +379,8 @@ where ) .substream_upgrade_protocol_override(upgrade::Version::V1Lazy) .notify_handler_buffer_size(NonZeroUsize::new(32).expect("32 != 0; qed")) - .connection_event_buffer_size(1024); + .connection_event_buffer_size(1024) + .max_negotiating_inbound_streams(2048); if let Some(spawner) = params.executor { struct SpawnImpl(F); impl + Send>>)> Executor for SpawnImpl { diff --git a/client/network/src/transport.rs b/client/network/src/transport.rs index 64b199e9d769e..883f828e7db51 100644 --- a/client/network/src/transport.rs +++ b/client/network/src/transport.rs @@ -55,12 +55,15 @@ pub fn build_transport( // Build the base layer of the transport. let transport = if !memory_only { let desktop_trans = tcp::TcpConfig::new().nodelay(true); - let desktop_trans = - websocket::WsConfig::new(desktop_trans.clone()).or_transport(desktop_trans); - let dns_init = futures::executor::block_on(dns::DnsConfig::system(desktop_trans.clone())); + let desktop_trans = websocket::WsConfig::new(desktop_trans) + .or_transport(tcp::TcpConfig::new().nodelay(true)); + let dns_init = futures::executor::block_on(dns::DnsConfig::system(desktop_trans)); EitherTransport::Left(if let Ok(dns) = dns_init { EitherTransport::Left(dns) } else { + let desktop_trans = tcp::TcpConfig::new().nodelay(true); + let desktop_trans = websocket::WsConfig::new(desktop_trans) + .or_transport(tcp::TcpConfig::new().nodelay(true)); EitherTransport::Right(desktop_trans.map_err(dns::DnsErr::Transport)) }) } else { diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index f11cc753203ef..9185e812bc6cd 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.9" +prost-build = "0.10" [dependencies] bitflags = "1.3.2" @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ ] } either = "1.5.3" futures = "0.3.21" -libp2p = "0.44.0" +libp2p = "0.45.1" log = "0.4.17" lru = "0.7.5" prost = "0.10" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index fa34feb22df1d..2af1dd8cb9b54 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -17,7 +17,7 @@ async-std = "1.11.0" async-trait = "0.1.50" futures = "0.3.21" futures-timer = "3.0.1" -libp2p = { version = "0.44.0", default-features = false } +libp2p = { version = "0.45.1", default-features = false } log = "0.4.17" parking_lot = "0.12.0" rand = "0.7.2" diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index 29e67c73c18da..f150c728613ba 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" -libp2p = { version = "0.44.0", default-features = false } +libp2p = { version = "0.45.1", default-features = false } log = "0.4.17" serde_json = "1.0.79" wasm-timer = "0.2" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index e8abdfee44a2e..9682dc824f930 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = "0.4.19" futures = "0.3.21" -libp2p = { version = "0.44.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } +libp2p = { version = "0.45.1", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.17" parking_lot = "0.12.0" pin-project = "1.0.10" diff --git a/client/telemetry/src/lib.rs b/client/telemetry/src/lib.rs index fc40f999a6779..503a326f76c2b 100644 --- a/client/telemetry/src/lib.rs +++ b/client/telemetry/src/lib.rs @@ -42,7 +42,10 @@ use log::{error, warn}; use parking_lot::Mutex; use serde::Serialize; use std::{ - collections::HashMap, + collections::{ + hash_map::Entry::{Occupied, Vacant}, + HashMap, + }, sync::{atomic, Arc}, }; @@ -147,7 +150,6 @@ pub struct TelemetryWorker { register_receiver: mpsc::UnboundedReceiver, register_sender: mpsc::UnboundedSender, id_counter: Arc, - transport: WsTrans, } impl TelemetryWorker { @@ -155,7 +157,11 @@ impl TelemetryWorker { /// /// Only one is needed per process. pub fn new(buffer_size: usize) -> Result { - let transport = initialize_transport()?; + // Let's try to initialize a transport to get an early return. + // Later transport will be initialized multiple times in + // `::process_register`, so it's a convenient way to get an + // error as early as possible. + let _transport = initialize_transport()?; let (message_sender, message_receiver) = mpsc::channel(buffer_size); let (register_sender, register_receiver) = mpsc::unbounded(); @@ -165,7 +171,6 @@ impl TelemetryWorker { register_receiver, register_sender, id_counter: Arc::new(atomic::AtomicU64::new(1)), - transport, }) } @@ -200,7 +205,6 @@ impl TelemetryWorker { &mut node_pool, &mut node_map, &mut pending_connection_notifications, - self.transport.clone(), ).await, } } @@ -211,7 +215,6 @@ impl TelemetryWorker { node_pool: &mut HashMap>, node_map: &mut HashMap>, pending_connection_notifications: &mut Vec<(Multiaddr, ConnectionNotifierSender)>, - transport: WsTrans, ) { let input = input.expect("the stream is never closed; qed"); @@ -248,9 +251,24 @@ impl TelemetryWorker { ); node_map.entry(id).or_default().push((verbosity, addr.clone())); - let node = node_pool.entry(addr.clone()).or_insert_with(|| { - Node::new(transport.clone(), addr.clone(), Vec::new(), Vec::new()) - }); + let node = match node_pool.entry(addr.clone()) { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => { + let transport = initialize_transport(); + let transport = match transport { + Ok(t) => t, + Err(err) => { + log::error!( + target: "telemetry", + "Could not initialise transport: {}", + err, + ); + continue + }, + }; + entry.insert(Node::new(transport, addr.clone(), Vec::new(), Vec::new())) + }, + }; node.connection_messages.extend(connection_message.clone()); diff --git a/client/telemetry/src/node.rs b/client/telemetry/src/node.rs index aa0f5a3843d33..0d71a363a1b26 100644 --- a/client/telemetry/src/node.rs +++ b/client/telemetry/src/node.rs @@ -110,7 +110,6 @@ impl Node { impl Node where - TTrans: Clone + Unpin, TTrans::Dial: Unpin, TTrans::Output: Sink, Error = TSinkErr> + Stream, TSinkErr>> + Unpin, @@ -137,7 +136,7 @@ pub(crate) enum Infallible {} impl Sink for Node where - TTrans: Clone + Unpin, + TTrans: Unpin, TTrans::Dial: Unpin, TTrans::Output: Sink, Error = TSinkErr> + Stream, TSinkErr>> + Unpin, @@ -228,15 +227,18 @@ where socket = NodeSocket::wait_reconnect(); }, }, - NodeSocket::ReconnectNow => match self.transport.clone().dial(self.addr.clone()) { - Ok(d) => { - log::trace!(target: "telemetry", "Re-dialing {}", self.addr); - socket = NodeSocket::Dialing(d); - }, - Err(err) => { - log::warn!(target: "telemetry", "❌ Error while re-dialing {}: {:?}", self.addr, err); - socket = NodeSocket::wait_reconnect(); - }, + NodeSocket::ReconnectNow => { + let addr = self.addr.clone(); + match self.transport.dial(addr) { + Ok(d) => { + log::trace!(target: "telemetry", "Re-dialing {}", self.addr); + socket = NodeSocket::Dialing(d); + }, + Err(err) => { + log::warn!(target: "telemetry", "❌ Error while re-dialing {}: {:?}", self.addr, err); + socket = NodeSocket::wait_reconnect(); + }, + } }, NodeSocket::WaitingReconnect(mut s) => { if Future::poll(Pin::new(&mut s), cx).is_ready() { From e6f39a6a7f86c64193bcad5edc9545e0eb3632e2 Mon Sep 17 00:00:00 2001 From: yjh Date: Sat, 18 Jun 2022 06:14:50 +0800 Subject: [PATCH 0927/1472] chore: reducing codec times (#11688) --- client/basic-authorship/src/basic_authorship.rs | 6 +----- primitives/consensus/common/src/evaluation.rs | 15 ++++++++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 5a020ee81050e..b67008bc6f44b 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -20,7 +20,7 @@ // FIXME #1021 move this into sp-consensus -use codec::{Decode, Encode}; +use codec::Encode; use futures::{ channel::oneshot, future, @@ -536,10 +536,6 @@ where "hash" => ?::Hash::from(block.header().hash()), ); - if Decode::decode(&mut block.encode().as_slice()).as_ref() != Ok(&block) { - error!("Failed to verify block encoding/decoding"); - } - if let Err(err) = evaluation::evaluate_initial(&block, &self.parent_hash, self.parent_number) { diff --git a/primitives/consensus/common/src/evaluation.rs b/primitives/consensus/common/src/evaluation.rs index 6a6ca835f3153..d1ce8e9fc5109 100644 --- a/primitives/consensus/common/src/evaluation.rs +++ b/primitives/consensus/common/src/evaluation.rs @@ -30,6 +30,8 @@ pub type Result = std::result::Result; /// Error type. #[derive(Debug, thiserror::Error)] pub enum Error { + #[error("Failed to verify block encoding/decoding")] + BadBlockCodec, /// Proposal provided not a block. #[error("Proposal provided not a block: decoding error: {0}")] BadProposalFormat(#[from] codec::Error), @@ -49,19 +51,22 @@ pub fn evaluate_initial( parent_number: <::Header as HeaderT>::Number, ) -> Result<()> { let encoded = Encode::encode(proposal); - let proposal = Block::decode(&mut &encoded[..]).map_err(Error::BadProposalFormat)?; + let block = Block::decode(&mut &encoded[..]).map_err(Error::BadProposalFormat)?; + if &block != proposal { + return Err(Error::BadBlockCodec) + } - if *parent_hash != *proposal.header().parent_hash() { + if *parent_hash != *block.header().parent_hash() { return Err(Error::WrongParentHash { expected: format!("{:?}", *parent_hash), - got: format!("{:?}", proposal.header().parent_hash()), + got: format!("{:?}", block.header().parent_hash()), }) } - if parent_number + One::one() != *proposal.header().number() { + if parent_number + One::one() != *block.header().number() { return Err(Error::WrongNumber { expected: parent_number.checked_into::().map(|x| x + 1), - got: (*proposal.header().number()).checked_into::(), + got: (*block.header().number()).checked_into::(), }) } From 3a91ba68ac930ec4cd32b4ab6960e893a98503d1 Mon Sep 17 00:00:00 2001 From: yjh Date: Sun, 19 Jun 2022 06:43:11 +0800 Subject: [PATCH 0928/1472] chore: reduce uxt encode times (#11698) * chore: reduce uxt encode times * fmt --- frame/executive/src/lib.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 60bf0a47ca120..c40fdf94806aa 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -435,24 +435,15 @@ where sp_io::init_tracing(); let encoded = uxt.encode(); let encoded_len = encoded.len(); - Self::apply_extrinsic_with_len(uxt, encoded_len, encoded) - } - - /// Actually apply an extrinsic given its `encoded_len`; this doesn't note its hash. - fn apply_extrinsic_with_len( - uxt: Block::Extrinsic, - encoded_len: usize, - to_note: Vec, - ) -> ApplyExtrinsicResult { sp_tracing::enter_span!(sp_tracing::info_span!("apply_extrinsic", - ext=?sp_core::hexdisplay::HexDisplay::from(&uxt.encode()))); + ext=?sp_core::hexdisplay::HexDisplay::from(&encoded))); // Verify that the signature is good. let xt = uxt.check(&Default::default())?; // We don't need to make sure to `note_extrinsic` only after we know it's going to be // executed to prevent it from leaking in storage since at this point, it will either // execute or panic (and revert storage changes). - >::note_extrinsic(to_note); + >::note_extrinsic(encoded); // AUDIT: Under no circumstances may this function panic from here onwards. From c55e4a1ded4a73bbfb2923238386c48356065739 Mon Sep 17 00:00:00 2001 From: Zhenghao Lu <54395432+EmisonLu@users.noreply.github.com> Date: Sun, 19 Jun 2022 07:56:48 +0800 Subject: [PATCH 0929/1472] Simplified code using existing APIs (#11702) Signed-off-by: Emison Lu --- client/executor/wasmtime/src/host.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index 0cb64820fa8a3..b494795ae9dc1 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -145,11 +145,7 @@ impl<'a> sp_wasm_interface::FunctionContext for HostContext<'a> { } fn register_panic_error_message(&mut self, message: &str) { - self.caller - .data_mut() - .host_state_mut() - .expect("host state is not empty when calling a function in wasm; qed") - .panic_message = Some(message.to_owned()); + self.host_state_mut().panic_message = Some(message.to_owned()); } } From cde8e7d5e31bb6c2188a375d1a6e794e6c77cf80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 19 Jun 2022 19:56:36 +0200 Subject: [PATCH 0930/1472] `storage-alias`: Check that prefix is not an underscore (#11704) Besides that it also adds some UI tests. --- frame/support/procedural/src/storage_alias.rs | 4 +++ frame/support/test/tests/storage_alias_ui.rs | 32 +++++++++++++++++++ .../checks_for_valid_storage_type.rs | 4 +++ .../checks_for_valid_storage_type.stderr | 5 +++ .../forbid_underscore_as_prefix.rs | 4 +++ .../forbid_underscore_as_prefix.stderr | 5 +++ .../prefix_must_be_an_ident.rs | 4 +++ .../prefix_must_be_an_ident.stderr | 5 +++ 8 files changed, 63 insertions(+) create mode 100644 frame/support/test/tests/storage_alias_ui.rs create mode 100644 frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.rs create mode 100644 frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.stderr create mode 100644 frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.rs create mode 100644 frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.stderr create mode 100644 frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.rs create mode 100644 frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.stderr diff --git a/frame/support/procedural/src/storage_alias.rs b/frame/support/procedural/src/storage_alias.rs index adec995016653..e0df0123595b9 100644 --- a/frame/support/procedural/src/storage_alias.rs +++ b/frame/support/procedural/src/storage_alias.rs @@ -512,6 +512,10 @@ fn generate_storage_instance( prefix_generics: Option<&TypeGenerics>, visibility: &Visibility, ) -> Result { + if let Some(ident) = prefix.get_ident().filter(|i| *i == "_") { + return Err(Error::new(ident.span(), "`_` is not allowed as prefix by `storage_alias`.")) + } + let (pallet_prefix, impl_generics, type_generics) = if let Some((prefix_generics, storage_generics)) = prefix_generics.and_then(|p| storage_generics.map(|s| (p, s))) diff --git a/frame/support/test/tests/storage_alias_ui.rs b/frame/support/test/tests/storage_alias_ui.rs new file mode 100644 index 0000000000000..d45d071578dab --- /dev/null +++ b/frame/support/test/tests/storage_alias_ui.rs @@ -0,0 +1,32 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[rustversion::attr(not(stable), ignore)] +#[cfg(not(feature = "disable-ui-tests"))] +#[test] +fn storage_alias_ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if std::env::var("RUN_UI_TESTS").is_err() { + return + } + + // As trybuild is using `cargo check`, we don't need the real WASM binaries. + std::env::set_var("SKIP_WASM_BUILD", "1"); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/storage_alias_ui/*.rs"); +} diff --git a/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.rs b/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.rs new file mode 100644 index 0000000000000..4ed9d5adfec77 --- /dev/null +++ b/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.rs @@ -0,0 +1,4 @@ +#[frame_support::storage_alias] +type Ident = StorageValue; + +fn main() {} diff --git a/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.stderr b/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.stderr new file mode 100644 index 0000000000000..726efed400715 --- /dev/null +++ b/frame/support/test/tests/storage_alias_ui/checks_for_valid_storage_type.stderr @@ -0,0 +1,5 @@ +error: If there are no generics, the prefix is only allowed to be an identifier. + --> tests/storage_alias_ui/checks_for_valid_storage_type.rs:2:27 + | +2 | type Ident = StorageValue; + | ^^^^^^^^^^^^ diff --git a/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.rs b/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.rs new file mode 100644 index 0000000000000..59d8004bbe620 --- /dev/null +++ b/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.rs @@ -0,0 +1,4 @@ +#[frame_support::storage_alias] +type Ident = CustomStorage; + +fn main() {} diff --git a/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.stderr b/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.stderr new file mode 100644 index 0000000000000..3aa517ecfa314 --- /dev/null +++ b/frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.stderr @@ -0,0 +1,5 @@ +error: expected one of: `StorageValue`, `StorageMap`, `StorageDoubleMap`, `StorageNMap` + --> tests/storage_alias_ui/forbid_underscore_as_prefix.rs:2:14 + | +2 | type Ident = CustomStorage; + | ^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.rs b/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.rs new file mode 100644 index 0000000000000..79328268dc925 --- /dev/null +++ b/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.rs @@ -0,0 +1,4 @@ +#[frame_support::storage_alias] +type NoUnderscore = StorageValue<_, u32>; + +fn main() {} diff --git a/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.stderr b/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.stderr new file mode 100644 index 0000000000000..abb7bf2518f4f --- /dev/null +++ b/frame/support/test/tests/storage_alias_ui/prefix_must_be_an_ident.stderr @@ -0,0 +1,5 @@ +error: `_` is not allowed as prefix by `storage_alias`. + --> tests/storage_alias_ui/prefix_must_be_an_ident.rs:2:34 + | +2 | type NoUnderscore = StorageValue<_, u32>; + | ^ From 00c8081705122e04b87c659a0edf02c3946ce492 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Jun 2022 21:01:38 +0200 Subject: [PATCH 0931/1472] Bump twox-hash from 1.6.2 to 1.6.3 (#11423) Bumps [twox-hash](https://github.com/shepmaster/twox-hash) from 1.6.2 to 1.6.3. - [Release notes](https://github.com/shepmaster/twox-hash/releases) - [Commits](https://github.com/shepmaster/twox-hash/compare/v1.6.2...v1.6.3) --- updated-dependencies: - dependency-name: twox-hash 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 ++-- primitives/core/hashing/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e33211911b47a..9c76d25474679 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11337,9 +11337,9 @@ checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055" [[package]] name = "twox-hash" -version = "1.6.2" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if 1.0.0", "digest 0.10.3", diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index c83e48e563010..d85e28d1b2e56 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -18,7 +18,7 @@ byteorder = { version = "1.3.2", default-features = false } digest = { version = "0.10.3", default-features = false } sha2 = { version = "0.10.2", default-features = false } sha3 = { version = "0.10.0", default-features = false } -twox-hash = { version = "1.6.2", default-features = false, features = ["digest_0_10"] } +twox-hash = { version = "1.6.3", default-features = false, features = ["digest_0_10"] } sp-std = { version = "4.0.0", default-features = false, path = "../../std" } [features] From 4ea2ac87de6cd66ca1e6038d10212c7c4e07a86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 20 Jun 2022 11:53:41 +0200 Subject: [PATCH 0932/1472] Update syn and fix compilation (#11707) * Update syn and fix compilation * Bump pin-project --- Cargo.lock | 30 +++++++++++-------- client/chain-spec/derive/Cargo.toml | 2 +- client/tracing/proc-macro/Cargo.toml | 2 +- frame/contracts/proc-macro/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- frame/staking/reward-curve/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/tools/Cargo.toml | 2 +- .../procedural/tools/derive/Cargo.toml | 2 +- frame/support/procedural/tools/src/syn_ext.rs | 9 +++--- primitives/api/proc-macro/Cargo.toml | 2 +- primitives/core/hashing/proc-macro/Cargo.toml | 2 +- primitives/debug-derive/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- primitives/version/proc-macro/Cargo.toml | 2 +- test-utils/derive/Cargo.toml | 2 +- 16 files changed, 37 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c76d25474679..d7b1350c1f529 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6809,11 +6809,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" +checksum = "9615c18d31137579e9ff063499264ddc1278e7b1982757ebc111028c4d1dc909" dependencies = [ - "pin-project-internal 0.4.27", + "pin-project-internal 0.4.29", ] [[package]] @@ -6827,9 +6827,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" +checksum = "044964427019eed9d49d9d5bbce6047ef18f37100ea400912a9fa4a3523ab12a" dependencies = [ "proc-macro2", "quote", @@ -7041,11 +7041,11 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -7885,7 +7885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" dependencies = [ "futures", - "pin-project 0.4.27", + "pin-project 0.4.29", "static_assertions", ] @@ -10776,13 +10776,13 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.82" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -11389,6 +11389,12 @@ dependencies = [ "matches", ] +[[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.17" diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index 06f397e1e7b10..d733bda9b1692 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -18,4 +18,4 @@ proc-macro = true proc-macro-crate = "1.1.3" proc-macro2 = "1.0.37" quote = "1.0.10" -syn = "1.0.82" +syn = "1.0.98" diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index b55c3482be3f4..031f1fe49d970 100644 --- a/client/tracing/proc-macro/Cargo.toml +++ b/client/tracing/proc-macro/Cargo.toml @@ -18,4 +18,4 @@ proc-macro = true proc-macro-crate = "1.1.3" proc-macro2 = "1.0.37" quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.82", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "1.0.98", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/contracts/proc-macro/Cargo.toml b/frame/contracts/proc-macro/Cargo.toml index db3c620397771..aca1d86ac24a1 100644 --- a/frame/contracts/proc-macro/Cargo.toml +++ b/frame/contracts/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] proc-macro2 = "1" quote = "1" -syn = "1" +syn = "1.0.98" [dev-dependencies] diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index 8fd7ddbff434d..a7ce4fa662131 100644 --- a/frame/election-provider-support/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.82", features = ["full", "visit"] } +syn = { version = "1.0.98", features = ["full", "visit"] } quote = "1.0" proc-macro2 = "1.0.37" proc-macro-crate = "1.1.3" diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index 0307f61b1dce6..9e561fea4575b 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true proc-macro-crate = "1.1.3" proc-macro2 = "1.0.37" quote = "1.0.10" -syn = { version = "1.0.82", features = ["full", "visit"] } +syn = { version = "1.0.98", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index f8b325479c31d..7ddec39cad9fb 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true Inflector = "0.11.4" proc-macro2 = "1.0.37" quote = "1.0.10" -syn = { version = "1.0.82", features = ["full"] } +syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } [features] diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index f76b2480f9838..755483f7db9aa 100644 --- a/frame/support/procedural/tools/Cargo.toml +++ b/frame/support/procedural/tools/Cargo.toml @@ -15,5 +15,5 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro-crate = "1.1.3" proc-macro2 = "1.0.37" quote = "1.0.10" -syn = { version = "1.0.82", features = ["full", "visit", "extra-traits"] } +syn = { version = "1.0.98", features = ["full", "visit", "extra-traits"] } frame-support-procedural-tools-derive = { version = "3.0.0", path = "./derive" } diff --git a/frame/support/procedural/tools/derive/Cargo.toml b/frame/support/procedural/tools/derive/Cargo.toml index 6aface4ae0937..a688ee13a7d17 100644 --- a/frame/support/procedural/tools/derive/Cargo.toml +++ b/frame/support/procedural/tools/derive/Cargo.toml @@ -17,4 +17,4 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.37" quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.82", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "1.0.98", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/support/procedural/tools/src/syn_ext.rs b/frame/support/procedural/tools/src/syn_ext.rs index 25c98faaf388c..1a2d7c1d372ad 100644 --- a/frame/support/procedural/tools/src/syn_ext.rs +++ b/frame/support/procedural/tools/src/syn_ext.rs @@ -47,7 +47,8 @@ macro_rules! groups_impl { impl Parse for $name

{ fn parse(input: ParseStream) -> Result { - let syn::group::$name { token, content } = syn::group::$parse(input)?; + let content; + let token = syn::$parse!(content in input); let content = content.parse()?; Ok($name { token, content }) } @@ -71,9 +72,9 @@ macro_rules! groups_impl { }; } -groups_impl!(Braces, Brace, Brace, parse_braces); -groups_impl!(Brackets, Bracket, Bracket, parse_brackets); -groups_impl!(Parens, Paren, Parenthesis, parse_parens); +groups_impl!(Braces, Brace, Brace, braced); +groups_impl!(Brackets, Bracket, Bracket, bracketed); +groups_impl!(Parens, Paren, Parenthesis, parenthesized); #[derive(Debug)] pub struct PunctuatedInner { diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index 24ce1360c80f7..0a57be8d7a300 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "1.0.98", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.37" blake2 = { version = "0.10.2", default-features = false } proc-macro-crate = "1.1.3" diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index 0d8431facb874..8f4f4e0c873ef 100644 --- a/primitives/core/hashing/proc-macro/Cargo.toml +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -18,5 +18,5 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.37" quote = "1.0.6" -syn = { version = "1.0.82", features = ["full", "parsing"] } +syn = { version = "1.0.98", features = ["full", "parsing"] } sp-core-hashing = { version = "4.0.0", default-features = false, path = "../" } diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml index 5852bd428d3e7..50bb0ec65c0ac 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] quote = "1.0.10" -syn = "1.0.82" +syn = "1.0.98" proc-macro2 = "1.0" [features] diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index a3ae1fd48651c..6f6b71dc24658 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -20,4 +20,4 @@ Inflector = "0.11.4" proc-macro-crate = "1.1.3" proc-macro2 = "1.0.37" quote = "1.0.10" -syn = { version = "1.0.82", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "1.0.98", features = ["full", "visit", "fold", "extra-traits"] } diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index 5b544c7ddd07d..3d129d4753a15 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } proc-macro2 = "1.0.37" quote = "1.0.10" -syn = { version = "1.0.82", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "1.0.98", features = ["full", "fold", "extra-traits", "visit"] } [dev-dependencies] sp-version = { version = "5.0.0", path = ".." } diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index aa4f9bb5eab85..4494b55220ef2 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -12,7 +12,7 @@ description = "Substrate test utilities macros" proc-macro-crate = "1.1.3" proc-macro2 = "1.0.37" quote = "1.0.10" -syn = { version = "1.0.82", features = ["full"] } +syn = { version = "1.0.98", features = ["full"] } [lib] proc-macro = true From 6001b59f9f64a133d55fc13a495acc76eb4b532f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Mon, 20 Jun 2022 09:18:06 -0300 Subject: [PATCH 0933/1472] check-dependent-cumulus should only be executed for PRs (#11693) the script executed by check-dependent-cumulus only works for PRs, as shown in https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/1630771#L87, which comes from https://github.com/paritytech/pipeline-scripts/blob/3ad10ddc0d985ef5326974a1143229c6429befab/check_dependent_project.sh#L443 --- scripts/ci/gitlab/pipeline/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index da6391fb7c278..25ecad5bc5264 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -42,6 +42,8 @@ check-dependent-cumulus: COMPANION_OVERRIDES: | substrate: polkadot-v* polkadot: release-v* + rules: + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ #PRs build-linux-substrate: stage: build From b66c051f118898ef78e68e0ccf78b1cd8f00090b Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 21 Jun 2022 00:52:43 +0900 Subject: [PATCH 0934/1472] Pump the gossip engine while waiting for the BEEFY runtime pallet (memory leak fix) (#11694) * Pump the gossip engine while waiting for the BEEFY runtime pallet This fixes a memory leak when the BEEFY gadget is turned on, but the runtime doesn't actually use BEEFY. * Implement `FusedFuture` for `GossipEngine` * Fuse futures outside of loops --- client/beefy/src/worker.rs | 77 +++++++++++++++-------------- client/network-gossip/src/bridge.rs | 15 +++++- 2 files changed, 55 insertions(+), 37 deletions(-) diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index ae466a71abb57..735dea0170a62 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -25,11 +25,10 @@ use std::{ }; use codec::{Codec, Decode, Encode}; -use futures::{future, FutureExt, StreamExt}; +use futures::StreamExt; use log::{debug, error, info, log_enabled, trace, warn}; -use parking_lot::Mutex; -use sc_client_api::{Backend, FinalityNotification, FinalityNotifications}; +use sc_client_api::{Backend, FinalityNotification}; use sc_network_gossip::GossipEngine; use sp_api::{BlockId, ProvideRuntimeApi}; @@ -80,7 +79,7 @@ pub(crate) struct BeefyWorker { runtime: Arc, key_store: BeefyKeystore, signed_commitment_sender: BeefySignedCommitmentSender, - gossip_engine: Arc>>, + gossip_engine: GossipEngine, gossip_validator: Arc>, /// Min delta in block numbers between two blocks, BEEFY should vote on min_block_delta: u32, @@ -88,7 +87,6 @@ pub(crate) struct BeefyWorker { rounds: Option>, /// Buffer holding votes for blocks that the client hasn't seen finality for. pending_votes: BTreeMap, Vec, AuthorityId, Signature>>>, - finality_notifications: FinalityNotifications, /// Best block we received a GRANDPA notification for best_grandpa_block_header: ::Header, /// Best block a BEEFY voting round has been concluded for @@ -143,14 +141,13 @@ where runtime, key_store, signed_commitment_sender, - gossip_engine: Arc::new(Mutex::new(gossip_engine)), + gossip_engine, gossip_validator, // always target at least one block better than current best beefy min_block_delta: min_block_delta.max(1), metrics, rounds: None, pending_votes: BTreeMap::new(), - finality_notifications: client.finality_notification_stream(), best_grandpa_block_header: last_finalized_header, best_beefy_block: None, last_signed_id: 0, @@ -471,15 +468,21 @@ where true, ); - self.gossip_engine.lock().gossip_message(topic::(), encoded_message, false); + self.gossip_engine.gossip_message(topic::(), encoded_message, false); } /// Wait for BEEFY runtime pallet to be available. async fn wait_for_runtime_pallet(&mut self) { - self.client - .finality_notification_stream() - .take_while(|notif| { - let at = BlockId::hash(notif.header.hash()); + let mut gossip_engine = &mut self.gossip_engine; + let mut finality_stream = self.client.finality_notification_stream().fuse(); + loop { + futures::select! { + notif = finality_stream.next() => { + let notif = match notif { + Some(notif) => notif, + None => break + }; + let at = BlockId::hash(notif.header.hash()); if let Some(active) = self.runtime.runtime_api().validator_set(&at).ok().flatten() { if active.id() == GENESIS_AUTHORITY_SET_ID { // When starting from genesis, there is no session boundary digest. @@ -490,18 +493,18 @@ where // worker won't vote until it witnesses a session change. // Once we'll implement 'initial sync' (catch-up), the worker will be able to // start voting right away. - self.handle_finality_notification(notif); - future::ready(false) + self.handle_finality_notification(¬if); + break } else { trace!(target: "beefy", "🥩 Finality notification: {:?}", notif); debug!(target: "beefy", "🥩 Waiting for BEEFY pallet to become available..."); - future::ready(true) } - }) - .for_each(|_| future::ready(())) - .await; - // get a new stream that provides _new_ notifications (from here on out) - self.finality_notifications = self.client.finality_notification_stream(); + }, + _ = gossip_engine => { + break + } + } + } } /// Main loop for BEEFY worker. @@ -512,16 +515,20 @@ where info!(target: "beefy", "🥩 run BEEFY worker, best grandpa: #{:?}.", self.best_grandpa_block_header.number()); self.wait_for_runtime_pallet().await; - let mut votes = Box::pin(self.gossip_engine.lock().messages_for(topic::()).filter_map( - |notification| async move { - trace!(target: "beefy", "🥩 Got vote message: {:?}", notification); - - VoteMessage::, AuthorityId, Signature>::decode( - &mut ¬ification.message[..], - ) - .ok() - }, - )); + let mut finality_notifications = self.client.finality_notification_stream().fuse(); + let mut votes = Box::pin( + self.gossip_engine + .messages_for(topic::()) + .filter_map(|notification| async move { + trace!(target: "beefy", "🥩 Got vote message: {:?}", notification); + + VoteMessage::, AuthorityId, Signature>::decode( + &mut ¬ification.message[..], + ) + .ok() + }) + .fuse(), + ); loop { while self.sync_oracle.is_major_syncing() { @@ -529,18 +536,16 @@ where futures_timer::Delay::new(Duration::from_secs(5)).await; } - let engine = self.gossip_engine.clone(); - let gossip_engine = future::poll_fn(|cx| engine.lock().poll_unpin(cx)); - + let mut gossip_engine = &mut self.gossip_engine; futures::select! { - notification = self.finality_notifications.next().fuse() => { + notification = finality_notifications.next() => { if let Some(notification) = notification { self.handle_finality_notification(¬ification); } else { return; } }, - vote = votes.next().fuse() => { + vote = votes.next() => { if let Some(vote) = vote { let block_num = vote.commitment.block_number; if block_num > *self.best_grandpa_block_header.number() { @@ -563,7 +568,7 @@ where return; } }, - _ = gossip_engine.fuse() => { + _ = gossip_engine => { error!(target: "beefy", "🥩 Gossip engine has terminated."); return; } diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 2e09e7cc614a4..2d086e89b4a10 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -53,6 +53,8 @@ pub struct GossipEngine { message_sinks: HashMap>>, /// Buffered messages (see [`ForwardingState`]). forwarding_state: ForwardingState, + + is_terminated: bool, } /// A gossip engine receives messages from the network via the `network_event_stream` and forwards @@ -94,6 +96,8 @@ impl GossipEngine { network_event_stream, message_sinks: HashMap::new(), forwarding_state: ForwardingState::Idle, + + is_terminated: false, } } @@ -214,7 +218,10 @@ impl Future for GossipEngine { Event::Dht(_) => {}, }, // The network event stream closed. Do the same for [`GossipValidator`]. - Poll::Ready(None) => return Poll::Ready(()), + Poll::Ready(None) => { + self.is_terminated = true; + return Poll::Ready(()) + }, Poll::Pending => break, } }, @@ -288,6 +295,12 @@ impl Future for GossipEngine { } } +impl futures::future::FusedFuture for GossipEngine { + fn is_terminated(&self) -> bool { + self.is_terminated + } +} + #[cfg(test)] mod tests { use super::*; From 0fbf917676824cda9c3cf7e71e83b20c26b5f92e Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Tue, 21 Jun 2022 08:49:43 +0200 Subject: [PATCH 0935/1472] Implement Serialize/Deserialize on WeakBoundedVec (#11713) * Implement Serialize/Deserialize on WeakBoundedVec * cargo fmt * Warn when there are too many elements while deserializing WeakBoundedVec --- .../runtime/src/bounded/weak_bounded_vec.rs | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/primitives/runtime/src/bounded/weak_bounded_vec.rs b/primitives/runtime/src/bounded/weak_bounded_vec.rs index 08460f7096357..ed9f4bba62b55 100644 --- a/primitives/runtime/src/bounded/weak_bounded_vec.rs +++ b/primitives/runtime/src/bounded/weak_bounded_vec.rs @@ -25,6 +25,11 @@ use core::{ ops::{Deref, Index, IndexMut}, slice::SliceIndex, }; +#[cfg(feature = "std")] +use serde::{ + de::{Error, SeqAccess, Visitor}, + Deserialize, Deserializer, Serialize, +}; use sp_std::{marker::PhantomData, prelude::*}; /// A weakly bounded vector. @@ -34,9 +39,72 @@ use sp_std::{marker::PhantomData, prelude::*}; /// /// The length of the vec is not strictly bounded. Decoding a vec with more element that the bound /// is accepted, and some method allow to bypass the restriction with warnings. +#[cfg_attr(feature = "std", derive(Serialize), serde(transparent))] #[derive(Encode, scale_info::TypeInfo)] #[scale_info(skip_type_params(S))] -pub struct WeakBoundedVec(pub(super) Vec, PhantomData); +pub struct WeakBoundedVec( + pub(super) Vec, + #[cfg_attr(feature = "std", serde(skip_serializing))] PhantomData, +); + +#[cfg(feature = "std")] +impl<'de, T, S: Get> Deserialize<'de> for WeakBoundedVec +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VecVisitor>(PhantomData<(T, S)>); + + impl<'de, T, S: Get> Visitor<'de> for VecVisitor + where + T: Deserialize<'de>, + { + type Value = Vec; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let size = seq.size_hint().unwrap_or(0); + let max = match usize::try_from(S::get()) { + Ok(n) => n, + Err(_) => return Err(A::Error::custom("can't convert to usize")), + }; + if size > max { + log::warn!( + target: "runtime", + "length of a bounded vector while deserializing is not respected.", + ); + } + let mut values = Vec::with_capacity(size); + + while let Some(value) = seq.next_element()? { + values.push(value); + if values.len() > max { + log::warn!( + target: "runtime", + "length of a bounded vector while deserializing is not respected.", + ); + } + } + + Ok(values) + } + } + + let visitor: VecVisitor = VecVisitor(PhantomData); + deserializer.deserialize_seq(visitor).map(|v| { + WeakBoundedVec::::try_from(v).map_err(|_| Error::custom("out of bounds")) + })? + } +} impl> Decode for WeakBoundedVec { fn decode(input: &mut I) -> Result { From aacc3e99c0750c3e6c851a8270dc2c4eebca3290 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 21 Jun 2022 11:50:51 +0200 Subject: [PATCH 0936/1472] More robust grandpa revert procedure (#11719) * More robust revert procedure Return an error if revert is called in a node that is not actively running grandpa, i.e. grandpa genesis data has not been initialized. Previous implementation was just firing an `unreachable!` code exception. Furthermore we skip revert hassle if there is nothing to revert. * Nit --- client/consensus/babe/src/lib.rs | 4 ++++ client/finality-grandpa/src/lib.rs | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 84a3c618b3803..8478122375319 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1873,7 +1873,11 @@ where { let best_number = client.info().best_number; let finalized = client.info().finalized_number; + let revertible = blocks.min(best_number - finalized); + if revertible == Zero::zero() { + return Ok(()) + } let revert_up_to_number = best_number - revertible; let revert_up_to_hash = client.hash(revert_up_to_number)?.ok_or(ClientError::Backend( diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 17e04affa0f98..cb32957c0b0bf 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -1170,11 +1170,15 @@ fn local_authority_id( pub fn revert(client: Arc, blocks: NumberFor) -> ClientResult<()> where Block: BlockT, - Client: AuxStore + HeaderMetadata + HeaderBackend, + Client: AuxStore + HeaderMetadata + HeaderBackend, { let best_number = client.info().best_number; let finalized = client.info().finalized_number; + let revertible = blocks.min(best_number - finalized); + if revertible == Zero::zero() { + return Ok(()) + } let number = best_number - revertible; let hash = client @@ -1185,8 +1189,12 @@ where )))?; let info = client.info(); + let persistent_data: PersistentData = - aux_schema::load_persistent(&*client, info.genesis_hash, Zero::zero(), || unreachable!())?; + aux_schema::load_persistent(&*client, info.genesis_hash, Zero::zero(), || { + const MSG: &str = "Unexpected missing grandpa data during revert"; + Err(ClientError::Application(Box::from(MSG))) + })?; let shared_authority_set = persistent_data.authority_set; let mut authority_set = shared_authority_set.inner(); From b49d8ee54f4bd6e4b5b48f45d08f75705fad95b4 Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Wed, 22 Jun 2022 04:12:57 +0900 Subject: [PATCH 0937/1472] Fix typo in weights.rs (#11724) overriden -> overridden --- frame/support/src/weights.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index a3df199496922..24240c7cc4e6a 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -680,7 +680,7 @@ where /// Calculates the fee from the passed `weight` according to the `polynomial`. /// - /// This should not be overriden in most circumstances. Calculation is done in the + /// This should not be overridden in most circumstances. Calculation is done in the /// `Balance` type and never overflows. All evaluation is saturating. fn weight_to_fee(weight: &Weight) -> Self::Balance { Self::polynomial() From 90d08f77aaaebe8f7012216948e54b6684a175b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 22 Jun 2022 11:02:59 +0200 Subject: [PATCH 0938/1472] WrapperOpaque: Use `decode_all` to decode from the `Vec` (#11726) This ensures that there isn't any extra data attached that isn't used. --- frame/support/src/traits/misc.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 1f0ba1e769c24..ccbb47909d5f4 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -745,7 +745,7 @@ impl Encode for WrapperOpaque { impl Decode for WrapperOpaque { fn decode(input: &mut I) -> Result { - Ok(Self(T::decode(&mut &>::decode(input)?[..])?)) + Ok(Self(T::decode_all(&mut &>::decode(input)?[..])?)) } fn skip(input: &mut I) -> Result<(), codec::Error> { @@ -967,6 +967,10 @@ mod test { 2usize.pow(14) - 1 + 2 ); assert_eq!(>::max_encoded_len(), 2usize.pow(14) + 4); + + let data = 4u64; + // Ensure that we check that the `Vec` is consumed completly on decode. + assert!(WrapperOpaque::::decode(&mut &data.encode().encode()[..]).is_err()); } #[test] From 85cfb817d8392d8acb791d80fdef3f8e298f6c03 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 22 Jun 2022 17:27:46 +0200 Subject: [PATCH 0939/1472] Respect cargo offline env variable in wasm builder (#11735) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Support offline env variable in wasm builder * Clean up * Improve checks Co-authored-by: Bastian Köcher * Update crate docs * Add docs to `lib.rs` and introduce helper method `offline_build` Co-authored-by: Bastian Köcher --- utils/wasm-builder/README.md | 1 + utils/wasm-builder/src/lib.rs | 5 ++++ utils/wasm-builder/src/wasm_project.rs | 32 ++++++++++++++++++++------ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/utils/wasm-builder/README.md b/utils/wasm-builder/README.md index 3868faf1acab5..547468c7ca11d 100644 --- a/utils/wasm-builder/README.md +++ b/utils/wasm-builder/README.md @@ -64,6 +64,7 @@ By using environment variables, you can configure which Wasm binaries are built to be absolute. - `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the Wasm binaries. The format needs to be the same as used by cargo, e.g. `nightly-2020-02-20`. +- `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all processes launched to prevent network access. Useful in offline environments. Each project can be skipped individually by using the environment variable `SKIP_PROJECT_NAME_WASM_BUILD`. Where `PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `node-runtime` will diff --git a/utils/wasm-builder/src/lib.rs b/utils/wasm-builder/src/lib.rs index 6a7f0d7ca3cd5..919290655368b 100644 --- a/utils/wasm-builder/src/lib.rs +++ b/utils/wasm-builder/src/lib.rs @@ -87,6 +87,8 @@ //! required as we walk up from the target directory until we find a `Cargo.toml`. If the target //! directory is changed for the build, this environment variable can be used to point to the //! actual workspace. +//! - `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all processes launched to +//! prevent network access. Useful in offline environments. //! //! Each project can be skipped individually by using the environment variable //! `SKIP_PROJECT_NAME_WASM_BUILD`. Where `PROJECT_NAME` needs to be replaced by the name of the @@ -119,6 +121,9 @@ pub use builder::{WasmBuilder, WasmBuilderSelectProject}; /// Environment variable that tells us to skip building the wasm binary. const SKIP_BUILD_ENV: &str = "SKIP_WASM_BUILD"; +/// Environment variable that tells us whether we should avoid network requests +const OFFLINE: &str = "CARGO_NET_OFFLINE"; + /// Environment variable to force a certain build type when building the wasm binary. /// Expects "debug", "release" or "production" as value. /// diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index be84f2fecfb53..197c1d1b220bb 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{write_file_if_changed, CargoCommandVersioned}; +use crate::{write_file_if_changed, CargoCommandVersioned, OFFLINE}; use build_helper::rerun_if_changed; use cargo_metadata::{CargoOpt, Metadata, MetadataCommand}; @@ -88,12 +88,12 @@ fn crate_metadata(cargo_manifest: &Path) -> Metadata { cargo_manifest.to_path_buf() }; - let crate_metadata = MetadataCommand::new() - .manifest_path(cargo_manifest) - .features(CargoOpt::AllFeatures) + let mut crate_metadata_command = create_metadata_command(cargo_manifest); + crate_metadata_command.features(CargoOpt::AllFeatures); + + let crate_metadata = crate_metadata_command .exec() .expect("`cargo metadata` can not fail on project `Cargo.toml`; qed"); - // If the `Cargo.lock` didn't exist, we need to remove it after // calling `cargo metadata`. This is required to ensure that we don't change // the build directory outside of the `target` folder. Commands like @@ -593,6 +593,11 @@ impl Profile { } } +/// Check environment whether we should build without network +fn offline_build() -> bool { + env::var(OFFLINE).map_or(false, |v| v == "true") +} + /// Build the project to create the WASM binary. fn build_project( project: &Path, @@ -631,6 +636,10 @@ fn build_project( build_cmd.arg("--profile"); build_cmd.arg(profile.name()); + if offline_build() { + build_cmd.arg("--offline"); + } + println!("{}", colorize_info_message("Information that should be included in a bug report.")); println!("{} {:?}", colorize_info_message("Executing build command:"), build_cmd); println!("{} {}", colorize_info_message("Using rustc version:"), cargo_cmd.rustc_version()); @@ -751,6 +760,16 @@ impl<'a> Deref for DeduplicatePackage<'a> { } } +fn create_metadata_command(path: impl Into) -> MetadataCommand { + let mut metadata_command = MetadataCommand::new(); + metadata_command.manifest_path(path); + + if offline_build() { + metadata_command.other_options(vec!["--offline".to_owned()]); + } + metadata_command +} + /// Generate the `rerun-if-changed` instructions for cargo to make sure that the WASM binary is /// rebuilt when needed. fn generate_rerun_if_changed_instructions( @@ -765,8 +784,7 @@ fn generate_rerun_if_changed_instructions( rerun_if_changed(cargo_lock); } - let metadata = MetadataCommand::new() - .manifest_path(project_folder.join("Cargo.toml")) + let metadata = create_metadata_command(project_folder.join("Cargo.toml")) .exec() .expect("`cargo metadata` can not fail!"); From 0adc17e69fd1d66f2238adc2218b7728545fee53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 22 Jun 2022 17:54:57 +0200 Subject: [PATCH 0940/1472] contracts: Reduce size of deletion queue depth (#11696) * contracts: Reduce size of deletion queue depth * Remove unused import --- bin/node/runtime/src/lib.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index addcd0b35a9d9..54742cd91c430 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -47,7 +47,6 @@ use frame_system::{ }; pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; -use pallet_contracts::weights::WeightInfo; use pallet_election_provider_multi_phase::SolutionAccuracyOf; use pallet_grandpa::{ fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, @@ -1116,18 +1115,13 @@ parameter_types! { pub const DepositPerItem: Balance = deposit(1, 0); pub const DepositPerByte: Balance = deposit(0, 1); pub const MaxValueSize: u32 = 16 * 1024; + pub const DeletionQueueDepth: u32 = 128; // The lazy deletion runs inside on_initialize. pub DeletionWeightLimit: Weight = RuntimeBlockWeights::get() .per_class .get(DispatchClass::Normal) .max_total .unwrap_or(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() / ( - ::WeightInfo::on_initialize_per_queue_item(1) - - ::WeightInfo::on_initialize_per_queue_item(0) - )) / 5) as u32; pub Schedule: pallet_contracts::Schedule = Default::default(); } From b0f294b7976ddd5129e1245f8ddb2f1bc4fe9be2 Mon Sep 17 00:00:00 2001 From: Vlad Date: Wed, 22 Jun 2022 19:00:00 +0300 Subject: [PATCH 0941/1472] Put `rusty-cachier` before PR merge into `master` for `cargo-check-benches` job (#11737) --- scripts/ci/gitlab/pipeline/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index b2348c48355d0..0c3fd4d33798d 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -80,6 +80,8 @@ cargo-check-benches: - .test-refs - .collect-artifacts before_script: + - !reference [.rust-info-script, script] + - !reference [.rusty-cachier, before_script] # merges in the master branch on PRs - if [ $CI_COMMIT_REF_NAME != "master" ]; then git fetch origin +master:master; @@ -88,8 +90,6 @@ cargo-check-benches: git config user.email "ci@gitlab.parity.io"; git merge $CI_COMMIT_REF_NAME --verbose --no-edit; fi - - !reference [.rust-info-script, script] - - !reference [.rusty-cachier, before_script] script: - rusty-cachier snapshot create - mkdir -p ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA From 656c62fd6cbacc393f61b6749e6699e4f02e9d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Wed, 22 Jun 2022 17:03:03 +0100 Subject: [PATCH 0942/1472] epochs: don't use gap when there's at least one genesis epoch imported (#11725) * epochs: don't use gap when there's at least one genesis epoch imported * epochs: add test for genesis gap fix --- client/consensus/epochs/src/lib.rs | 115 ++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index 3a943e4851a4d..fee69613debf0 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -755,7 +755,10 @@ where Err(e) => PersistedEpoch::Regular(e), } } - } else if epoch.is_genesis() && !self.epochs.values().all(|e| e.is_genesis()) { + } else if epoch.is_genesis() && + !self.epochs.is_empty() && + !self.epochs.values().any(|e| e.is_genesis()) + { // There's a genesis epoch imported when we already have an active epoch. // This happens after the warp sync as the ancient blocks download start. // We need to start tracking gap epochs here. @@ -1170,15 +1173,17 @@ mod tests { epoch_changes.clear_gap(); // Check that both epochs are available. - epoch_changes + let epoch_a = epoch_changes .epoch_data_for_child_of(&is_descendent_of, b"A", 1, 101, &make_genesis) .unwrap() .unwrap(); - epoch_changes + let epoch_x = epoch_changes .epoch_data_for_child_of(&is_descendent_of, b"X", 1, 1001, &make_genesis) .unwrap() .unwrap(); + + assert!(epoch_a != epoch_x) } #[test] @@ -1288,4 +1293,108 @@ mod tests { epoch_changes.clear_gap(); assert!(epoch_changes.gap.is_none()); } + + /// Test that ensures that the gap is not enabled when there's still genesis + /// epochs imported, regardless of whether there are already other further + /// epochs imported descending from such genesis epochs. + #[test] + fn gap_is_not_enabled_when_at_least_one_genesis_epoch_is_still_imported() { + // A (#1) - B (#201) + // / + // 0 - C (#1) + // + // The epoch duration is 100 slots, each of these blocks represents + // an epoch change block. block B starts a new epoch at #201 since the + // genesis epoch spans two epochs. + + let is_descendent_of = |base: &Hash, block: &Hash| -> Result { + match (base, block) { + (b"0", _) => Ok(true), + (b"A", b"B") => Ok(true), + _ => Ok(false), + } + }; + + let duration = 100; + let make_genesis = |slot| Epoch { start_slot: slot, duration }; + let mut epoch_changes = EpochChanges::new(); + let next_descriptor = (); + + // insert genesis epoch for A at slot 1 + { + let genesis_epoch_a_descriptor = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 1) + .unwrap() + .unwrap(); + + let incremented_epoch = epoch_changes + .viable_epoch(&genesis_epoch_a_descriptor, &make_genesis) + .unwrap() + .increment(next_descriptor.clone()); + + epoch_changes + .import(&is_descendent_of, *b"A", 1, *b"0", incremented_epoch) + .unwrap(); + } + + // insert regular epoch for B at slot 201, descending from A + { + let epoch_b_descriptor = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, b"A", 1, 201) + .unwrap() + .unwrap(); + + let incremented_epoch = epoch_changes + .viable_epoch(&epoch_b_descriptor, &make_genesis) + .unwrap() + .increment(next_descriptor.clone()); + + epoch_changes + .import(&is_descendent_of, *b"B", 201, *b"A", incremented_epoch) + .unwrap(); + } + + // insert genesis epoch for C at slot 1000 + { + let genesis_epoch_x_descriptor = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 1000) + .unwrap() + .unwrap(); + + let incremented_epoch = epoch_changes + .viable_epoch(&genesis_epoch_x_descriptor, &make_genesis) + .unwrap() + .increment(next_descriptor.clone()); + + epoch_changes + .import(&is_descendent_of, *b"C", 1, *b"0", incremented_epoch) + .unwrap(); + } + + // Clearing the gap should be a no-op. + epoch_changes.clear_gap(); + + // Check that all three epochs are available. + let epoch_a = epoch_changes + .epoch_data_for_child_of(&is_descendent_of, b"A", 1, 10, &make_genesis) + .unwrap() + .unwrap(); + + let epoch_b = epoch_changes + .epoch_data_for_child_of(&is_descendent_of, b"B", 201, 201, &make_genesis) + .unwrap() + .unwrap(); + + assert!(epoch_a != epoch_b); + + // the genesis epoch A will span slots [1, 200] with epoch B starting at slot 201 + assert_eq!(epoch_b.start_slot(), 201); + + let epoch_c = epoch_changes + .epoch_data_for_child_of(&is_descendent_of, b"C", 1, 1001, &make_genesis) + .unwrap() + .unwrap(); + + assert!(epoch_a != epoch_c); + } } From 12b0503102480eb80fd2803b7475feabf8d6f6a2 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 22 Jun 2022 21:39:24 +0300 Subject: [PATCH 0943/1472] pallet-beefy-mmr: add API for BEEFY Authority Sets (#11406) * pallet-beefy: add Config::OnNewValidatorSet type Add a hook to pallet-beefy for doing specific work when BEEFY validator set changes. For example, this can be used by pallet-beefy-mmr to cache a lightweight MMR root over validators and make it available to light clients. * pallet-beefy-mmr: implement OnNewValidatorSet Implement pallet-beefy::OnNewValidatorSet to be notified of BEEFY validator set changes. Use the notifications to compute and cache a light weight 'BEEFY authority set' which is an MMR root over BEEFY validator set plus some extra info. Previously, pallet-beefy-mmr was interogating pallet-beefy about validator set id on every block to find out when it needs to recompute the authority set. By using the event-driven approach in this commit, we also save one extra state interogation per block. * pallet-beefy-mmr: add new authority_set() API Expose current and next BEEFY authority sets through runtime API. These can be directly used by light clients to avoid having them compute them themselves based on BEEFY validator sets. Signed-off-by: acatangiu * rename BeefyMmr exposed runtime api --- Cargo.lock | 3 ++ frame/beefy-mmr/primitives/Cargo.toml | 8 +++- frame/beefy-mmr/primitives/src/lib.rs | 17 +++++++ frame/beefy-mmr/src/lib.rs | 67 +++++++++++++++++++-------- frame/beefy-mmr/src/mock.rs | 1 + frame/beefy-mmr/src/tests.rs | 50 ++++++++++++++++++++ frame/beefy/src/lib.rs | 51 ++++++++++++++++---- frame/beefy/src/mock.rs | 1 + primitives/beefy/src/lib.rs | 14 ++++++ primitives/beefy/src/mmr.rs | 13 ++++-- test-utils/runtime/Cargo.toml | 2 + test-utils/runtime/src/lib.rs | 10 ++++ 12 files changed, 202 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7b1350c1f529..cfcf5573c0bff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -511,10 +511,12 @@ dependencies = [ name = "beefy-merkle-tree" version = "4.0.0-dev" dependencies = [ + "beefy-primitives", "env_logger 0.9.0", "hex", "hex-literal", "log", + "sp-api", "tiny-keccak", ] @@ -10646,6 +10648,7 @@ dependencies = [ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ + "beefy-merkle-tree", "beefy-primitives", "cfg-if 1.0.0", "frame-support", diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/frame/beefy-mmr/primitives/Cargo.toml index 7878dc3d22837..f30a418def042 100644 --- a/frame/beefy-mmr/primitives/Cargo.toml +++ b/frame/beefy-mmr/primitives/Cargo.toml @@ -13,6 +13,9 @@ hex = { version = "0.4", default-features = false, optional = true } log = { version = "0.4", default-features = false, optional = true } tiny-keccak = { version = "2.0.2", features = ["keccak"], optional = true } +beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/beefy" } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } + [dev-dependencies] env_logger = "0.9" hex = "0.4" @@ -22,4 +25,7 @@ hex-literal = "0.3" debug = ["hex", "hex/std", "log"] default = ["debug", "keccak", "std"] keccak = ["tiny-keccak"] -std = [] +std = [ + "beefy-primitives/std", + "sp-api/std" +] diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/frame/beefy-mmr/primitives/src/lib.rs index 04fa11760765b..664fd18199dd0 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/frame/beefy-mmr/primitives/src/lib.rs @@ -36,6 +36,8 @@ extern crate alloc; #[cfg(not(feature = "std"))] use alloc::vec::Vec; +use beefy_primitives::mmr::{BeefyAuthoritySet, BeefyNextAuthoritySet}; + /// Supported hashing output size. /// /// The size is restricted to 32 bytes to allow for a more optimised implementation. @@ -375,6 +377,21 @@ where } } +sp_api::decl_runtime_apis! { + /// API useful for BEEFY light clients. + pub trait BeefyMmrApi + where + H: From + Into, + BeefyAuthoritySet: sp_api::Decode, + { + /// Return the currently active BEEFY authority set proof. + fn authority_set_proof() -> BeefyAuthoritySet; + + /// Return the next/queued BEEFY authority set proof. + fn next_authority_set_proof() -> BeefyNextAuthoritySet; + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 8b904d6aefd5f..456d6e77aa8eb 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -36,7 +36,10 @@ use sp_runtime::traits::{Convert, Hash, Member}; use sp_std::prelude::*; -use beefy_primitives::mmr::{BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}; +use beefy_primitives::{ + mmr::{BeefyAuthoritySet, BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}, + ValidatorSet as BeefyValidatorSet, +}; use pallet_mmr::{LeafDataProvider, ParentNumberAndHash}; use frame_support::{crypto::ecdsa::ECDSAExt, traits::Get}; @@ -124,6 +127,12 @@ pub mod pallet { type BeefyDataProvider: BeefyDataProvider; } + /// Details of current BEEFY authority set. + #[pallet::storage] + #[pallet::getter(fn beefy_authorities)] + pub type BeefyAuthorities = + StorageValue<_, BeefyAuthoritySet>, ValueQuery>; + /// Details of next BEEFY authority set. /// /// This storage entry is used as cache for calls to `update_beefy_next_authority_set`. @@ -149,7 +158,7 @@ where version: T::LeafVersion::get(), parent_number_and_hash: ParentNumberAndHash::::leaf_data(), leaf_extra: T::BeefyDataProvider::extra_data(), - beefy_next_authority_set: Pallet::::update_beefy_next_authority_set(), + beefy_next_authority_set: Pallet::::beefy_next_authorities(), } } } @@ -163,35 +172,55 @@ where } } +impl beefy_primitives::OnNewValidatorSet<::BeefyId> for Pallet +where + T: pallet::Config, + MerkleRootOf: From + Into, +{ + /// Compute and cache BEEFY authority sets based on updated BEEFY validator sets. + fn on_new_validator_set( + current_set: &BeefyValidatorSet<::BeefyId>, + next_set: &BeefyValidatorSet<::BeefyId>, + ) { + let current = Pallet::::compute_authority_set(current_set); + let next = Pallet::::compute_authority_set(next_set); + // cache the result + BeefyAuthorities::::put(¤t); + BeefyNextAuthorities::::put(&next); + } +} + impl Pallet where MerkleRootOf: From + Into, { - /// Returns details of the next BEEFY authority set. + /// Return the currently active BEEFY authority set proof. + pub fn authority_set_proof() -> BeefyAuthoritySet> { + Pallet::::beefy_authorities() + } + + /// Return the next/queued BEEFY authority set proof. + pub fn next_authority_set_proof() -> BeefyNextAuthoritySet> { + Pallet::::beefy_next_authorities() + } + + /// Returns details of a BEEFY authority set. /// /// Details contain authority set id, authority set length and a merkle root, /// constructed from uncompressed secp256k1 public keys converted to Ethereum addresses /// of the next BEEFY authority set. - /// - /// This function will use a storage-cached entry in case the set didn't change, or compute and - /// cache new one in case it did. - fn update_beefy_next_authority_set() -> BeefyNextAuthoritySet> { - let id = pallet_beefy::Pallet::::validator_set_id() + 1; - let current_next = Self::beefy_next_authorities(); - // avoid computing the merkle tree if validator set id didn't change. - if id == current_next.id { - return current_next - } - - let beefy_addresses = pallet_beefy::Pallet::::next_authorities() + fn compute_authority_set( + validator_set: &BeefyValidatorSet<::BeefyId>, + ) -> BeefyAuthoritySet> { + let id = validator_set.id(); + let beefy_addresses = validator_set + .validators() .into_iter() + .cloned() .map(T::BeefyAuthorityToMerkleLeaf::convert) .collect::>(); let len = beefy_addresses.len() as u32; let root = beefy_merkle_tree::merkle_root::(beefy_addresses).into(); - let next_set = BeefyNextAuthoritySet { id, len, root }; - // cache the result - BeefyNextAuthorities::::put(&next_set); - next_set + BeefyAuthoritySet { id, len, root } } } diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index c9dbdb3b2e16a..8a673c9d4e914 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -125,6 +125,7 @@ impl pallet_mmr::Config for Test { impl pallet_beefy::Config for Test { type BeefyId = BeefyId; type MaxAuthorities = ConstU32<100>; + type OnNewValidatorSet = BeefyMmr; } parameter_types! { diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index fd3ecd5067155..d9cd8c8a5d8c8 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -149,3 +149,53 @@ fn should_contain_valid_leaf_data() { } ); } + +#[test] +fn should_update_authorities() { + new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { + let auth_set = BeefyMmr::authority_set_proof(); + let next_auth_set = BeefyMmr::next_authority_set_proof(); + + // check current authority set + assert_eq!(0, auth_set.id); + assert_eq!(2, auth_set.len); + let want: H256 = + hex!("176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96").into(); + assert_eq!(want, auth_set.root); + + // next authority set should have same validators but different id + assert_eq!(1, next_auth_set.id); + assert_eq!(auth_set.len, next_auth_set.len); + assert_eq!(auth_set.root, next_auth_set.root); + + let announced_set = next_auth_set; + init_block(1); + let auth_set = BeefyMmr::authority_set_proof(); + let next_auth_set = BeefyMmr::next_authority_set_proof(); + + // check new auth are expected ones + assert_eq!(announced_set, auth_set); + assert_eq!(1, auth_set.id); + // check next auth set + assert_eq!(2, next_auth_set.id); + let want: H256 = + hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5").into(); + assert_eq!(2, next_auth_set.len); + assert_eq!(want, next_auth_set.root); + + let announced_set = next_auth_set; + init_block(2); + let auth_set = BeefyMmr::authority_set_proof(); + let next_auth_set = BeefyMmr::next_authority_set_proof(); + + // check new auth are expected ones + assert_eq!(announced_set, auth_set); + assert_eq!(2, auth_set.id); + // check next auth set + assert_eq!(3, next_auth_set.id); + let want: H256 = + hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5").into(); + assert_eq!(2, next_auth_set.len); + assert_eq!(want, next_auth_set.root); + }); +} diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index a0cba2270b37d..fce531d3f5dd7 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -32,7 +32,9 @@ use sp_runtime::{ }; use sp_std::prelude::*; -use beefy_primitives::{AuthorityIndex, ConsensusLog, ValidatorSet, BEEFY_ENGINE_ID}; +use beefy_primitives::{ + AuthorityIndex, ConsensusLog, OnNewValidatorSet, ValidatorSet, BEEFY_ENGINE_ID, +}; #[cfg(test)] mod mock; @@ -58,6 +60,13 @@ pub mod pallet { /// The maximum number of authorities that can be added. type MaxAuthorities: Get; + + /// A hook to act on the new BEEFY validator set. + /// + /// For some applications it might be beneficial to make the BEEFY validator set available + /// externally apart from having it in the storage. For instance you might cache a light + /// weight MMR root over validators and make it available for Light Clients. + type OnNewValidatorSet: OnNewValidatorSet<::BeefyId>; } #[pallet::pallet] @@ -118,20 +127,29 @@ impl Pallet { ) { >::put(&new); - let next_id = Self::validator_set_id() + 1u64; - >::put(next_id); - if let Some(validator_set) = ValidatorSet::::new(new, next_id) { + let new_id = Self::validator_set_id() + 1u64; + >::put(new_id); + + >::put(&queued); + + if let Some(validator_set) = ValidatorSet::::new(new, new_id) { let log = DigestItem::Consensus( BEEFY_ENGINE_ID, - ConsensusLog::AuthoritiesChange(validator_set).encode(), + ConsensusLog::AuthoritiesChange(validator_set.clone()).encode(), ); >::deposit_log(log); - } - >::put(&queued); + let next_id = new_id + 1; + if let Some(next_validator_set) = ValidatorSet::::new(queued, next_id) { + >::on_new_validator_set( + &validator_set, + &next_validator_set, + ); + } + } } - fn initialize_authorities(authorities: &[T::BeefyId]) -> Result<(), ()> { + fn initialize_authorities(authorities: &Vec) -> Result<(), ()> { if authorities.is_empty() { return Ok(()) } @@ -141,12 +159,25 @@ impl Pallet { } let bounded_authorities = - BoundedSlice::::try_from(authorities)?; + BoundedSlice::::try_from(authorities.as_slice())?; + let id = 0; >::put(bounded_authorities); - >::put(0); + >::put(id); // Like `pallet_session`, initialize the next validator set as well. >::put(bounded_authorities); + + if let Some(validator_set) = ValidatorSet::::new(authorities.clone(), id) { + let next_id = id + 1; + if let Some(next_validator_set) = + ValidatorSet::::new(authorities.clone(), next_id) + { + >::on_new_validator_set( + &validator_set, + &next_validator_set, + ); + } + } Ok(()) } } diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 27796b5b2206c..3bb59c7c39485 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -87,6 +87,7 @@ impl frame_system::Config for Test { impl pallet_beefy::Config for Test { type BeefyId = BeefyId; type MaxAuthorities = ConstU32<100>; + type OnNewValidatorSet = (); } parameter_types! { diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index 8dbdd66f3559b..87f1b8756af65 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -154,6 +154,20 @@ pub struct VoteMessage { pub signature: Signature, } +/// New BEEFY validator set notification hook. +pub trait OnNewValidatorSet { + /// Function called by the pallet when BEEFY validator set changes. + fn on_new_validator_set( + validator_set: &ValidatorSet, + next_validator_set: &ValidatorSet, + ); +} + +/// No-op implementation of [OnNewValidatorSet]. +impl OnNewValidatorSet for () { + fn on_new_validator_set(_: &ValidatorSet, _: &ValidatorSet) {} +} + sp_api::decl_runtime_apis! { /// API necessary for BEEFY voters. pub trait BeefyApi diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 426a1ba5ff80b..761eee9f8ef85 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -95,10 +95,10 @@ impl MmrLeafVersion { } } -/// Details of the next BEEFY authority set. +/// Details of a BEEFY authority set. #[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct BeefyNextAuthoritySet { - /// Id of the next set. +pub struct BeefyAuthoritySet { + /// Id of the set. /// /// Id is required to correlate BEEFY signed commitments with the validator set. /// Light Client can easily verify that the commitment witness it is getting is @@ -106,11 +106,11 @@ pub struct BeefyNextAuthoritySet { pub id: crate::ValidatorSetId, /// Number of validators in the set. /// - /// Some BEEFY Light Clients may use an interactive protocol to verify only subset + /// Some BEEFY Light Clients may use an interactive protocol to verify only a subset /// of signatures. We put set length here, so that these clients can verify the minimal /// number of required signatures. pub len: u32, - /// Merkle Root Hash build from BEEFY AuthorityIds. + /// Merkle Root Hash built from BEEFY AuthorityIds. /// /// This is used by Light Clients to confirm that the commitments are signed by the correct /// validator set. Light Clients using interactive protocol, might verify only subset of @@ -118,6 +118,9 @@ pub struct BeefyNextAuthoritySet { pub root: MerkleRoot, } +/// Details of the next BEEFY authority set. +pub type BeefyNextAuthoritySet = BeefyAuthoritySet; + #[cfg(test)] mod tests { use super::*; diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 739be9ec8bdd8..1c2707b3719ad 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy" } +beefy-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "../../frame/beefy-mmr/primitives" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } @@ -67,6 +68,7 @@ default = [ ] std = [ "beefy-primitives/std", + "beefy-merkle-tree/std", "sp-application-crypto/std", "sp-consensus-aura/std", "sp-consensus-babe/std", diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 555f29e5991f7..ea62f2ac84f3d 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -947,6 +947,16 @@ cfg_if! { } } + impl beefy_merkle_tree::BeefyMmrApi for RuntimeApi { + fn authority_set_proof() -> beefy_primitives::mmr::BeefyAuthoritySet { + Default::default() + } + + fn next_authority_set_proof() -> beefy_primitives::mmr::BeefyNextAuthoritySet { + Default::default() + } + } + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { fn account_nonce(_account: AccountId) -> Index { 0 From ee3eb220974f55146cf238f28ec2b1ec61141999 Mon Sep 17 00:00:00 2001 From: Doordashcon Date: Thu, 23 Jun 2022 05:18:40 +0100 Subject: [PATCH 0944/1472] make pallet-tips & pallet-bounties instantiable (#11473) * make pallet-tips & pallet-bounties instantiable * update test * add default instance * update * cargo fmt * update * update * update * update * fix merge * fix tests * bounties benchmarking instantiable * fix benchmarks * make tips benchmarks instantible Co-authored-by: Shawn Tabrizi --- frame/bounties/src/benchmarking.rs | 156 ++++++++++++----------- frame/bounties/src/lib.rs | 193 +++++++++++++++-------------- frame/bounties/src/tests.rs | 89 +++++++++++-- frame/tips/src/benchmarking.rs | 58 +++++---- frame/tips/src/lib.rs | 105 ++++++++-------- frame/tips/src/tests.rs | 87 +++++++++++-- 6 files changed, 417 insertions(+), 271 deletions(-) diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 912e461501be5..7566c32f6e9a1 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -31,25 +31,25 @@ use pallet_treasury::Pallet as Treasury; const SEED: u32 = 0; // Create bounties that are approved for use in `on_initialize`. -fn create_approved_bounties(n: u32) -> Result<(), &'static str> { +fn create_approved_bounties, I: 'static>(n: u32) -> Result<(), &'static str> { for i in 0..n { let (caller, _curator, _fee, value, reason) = - setup_bounty::(i, T::MaximumReasonLength::get()); - Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::::get() - 1; - Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; + setup_bounty::(i, T::MaximumReasonLength::get()); + Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; + let bounty_id = BountyCount::::get() - 1; + Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; } - ensure!(BountyApprovals::::get().len() == n as usize, "Not all bounty approved"); + ensure!(BountyApprovals::::get().len() == n as usize, "Not all bounty approved"); Ok(()) } // Create the pre-requisite information needed to create a treasury `propose_bounty`. -fn setup_bounty( +fn setup_bounty, I: 'static>( u: u32, d: u32, -) -> (T::AccountId, T::AccountId, BalanceOf, BalanceOf, Vec) { +) -> (T::AccountId, T::AccountId, BalanceOf, BalanceOf, Vec) { let caller = account("caller", u, SEED); - let value: BalanceOf = T::BountyValueMinimum::get().saturating_mul(100u32.into()); + let value: BalanceOf = T::BountyValueMinimum::get().saturating_mul(100u32.into()); let fee = value / 2u32.into(); let deposit = T::BountyDepositBase::get() + T::DataDepositPerByte::get() * T::MaximumReasonLength::get().into(); @@ -60,97 +60,103 @@ fn setup_bounty( (caller, curator, fee, value, reason) } -fn create_bounty( +fn create_bounty, I: 'static>( ) -> Result<(::Source, BountyIndex), &'static str> { - let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); + let (caller, curator, fee, value, reason) = + setup_bounty::(0, T::MaximumReasonLength::get()); let curator_lookup = T::Lookup::unlookup(curator.clone()); - Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::::get() - 1; - Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; - Treasury::::on_initialize(T::BlockNumber::zero()); - Bounties::::propose_curator(RawOrigin::Root.into(), bounty_id, curator_lookup.clone(), fee)?; - Bounties::::accept_curator(RawOrigin::Signed(curator).into(), bounty_id)?; + Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; + let bounty_id = BountyCount::::get() - 1; + Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; + Treasury::::on_initialize(T::BlockNumber::zero()); + Bounties::::propose_curator( + RawOrigin::Root.into(), + bounty_id, + curator_lookup.clone(), + fee, + )?; + Bounties::::accept_curator(RawOrigin::Signed(curator).into(), bounty_id)?; Ok((curator_lookup, bounty_id)) } -fn setup_pot_account() { - let pot_account = Bounties::::account_id(); +fn setup_pot_account, I: 'static>() { + let pot_account = Bounties::::account_id(); let value = T::Currency::minimum_balance().saturating_mul(1_000_000_000u32.into()); let _ = T::Currency::make_free_balance_be(&pot_account, value); } -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event, I: 'static>(generic_event: >::Event) { frame_system::Pallet::::assert_last_event(generic_event.into()); } -benchmarks! { +benchmarks_instance_pallet! { propose_bounty { let d in 0 .. T::MaximumReasonLength::get(); - let (caller, curator, fee, value, description) = setup_bounty::(0, d); + let (caller, curator, fee, value, description) = setup_bounty::(0, d); }: _(RawOrigin::Signed(caller), value, description) approve_bounty { - let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); - Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::::get() - 1; + let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); + Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; + let bounty_id = BountyCount::::get() - 1; }: _(RawOrigin::Root, bounty_id) propose_curator { - setup_pot_account::(); - let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); + setup_pot_account::(); + let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); let curator_lookup = T::Lookup::unlookup(curator); - Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::::get() - 1; - Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; - Bounties::::on_initialize(T::BlockNumber::zero()); + Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; + let bounty_id = BountyCount::::get() - 1; + Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; + Treasury::::on_initialize(T::BlockNumber::zero()); }: _(RawOrigin::Root, bounty_id, curator_lookup, fee) // Worst case when curator is inactive and any sender unassigns the curator. unassign_curator { - setup_pot_account::(); - let (curator_lookup, bounty_id) = create_bounty::()?; - Bounties::::on_initialize(T::BlockNumber::zero()); - let bounty_id = BountyCount::::get() - 1; - frame_system::Pallet::::set_block_number(T::BountyUpdatePeriod::get() + 1u32.into()); + setup_pot_account::(); + let (curator_lookup, bounty_id) = create_bounty::()?; + Treasury::::on_initialize(T::BlockNumber::zero()); + let bounty_id = BountyCount::::get() - 1; + frame_system::Pallet::::set_block_number(T::BountyUpdatePeriod::get() + 2u32.into()); let caller = whitelisted_caller(); }: _(RawOrigin::Signed(caller), bounty_id) accept_curator { - setup_pot_account::(); - let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); + setup_pot_account::(); + let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); let curator_lookup = T::Lookup::unlookup(curator.clone()); - Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::::get() - 1; - Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; - Bounties::::on_initialize(T::BlockNumber::zero()); - Bounties::::propose_curator(RawOrigin::Root.into(), bounty_id, curator_lookup, fee)?; + Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; + let bounty_id = BountyCount::::get() - 1; + Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; + Treasury::::on_initialize(T::BlockNumber::zero()); + Bounties::::propose_curator(RawOrigin::Root.into(), bounty_id, curator_lookup, fee)?; }: _(RawOrigin::Signed(curator), bounty_id) award_bounty { - setup_pot_account::(); - let (curator_lookup, bounty_id) = create_bounty::()?; - Bounties::::on_initialize(T::BlockNumber::zero()); + setup_pot_account::(); + let (curator_lookup, bounty_id) = create_bounty::()?; + Treasury::::on_initialize(T::BlockNumber::zero()); - let bounty_id = BountyCount::::get() - 1; + let bounty_id = BountyCount::::get() - 1; let curator = T::Lookup::lookup(curator_lookup).map_err(<&str>::from)?; let beneficiary = T::Lookup::unlookup(account("beneficiary", 0, SEED)); }: _(RawOrigin::Signed(curator), bounty_id, beneficiary) claim_bounty { - setup_pot_account::(); - let (curator_lookup, bounty_id) = create_bounty::()?; - Bounties::::on_initialize(T::BlockNumber::zero()); + setup_pot_account::(); + let (curator_lookup, bounty_id) = create_bounty::()?; + Treasury::::on_initialize(T::BlockNumber::zero()); - let bounty_id = BountyCount::::get() - 1; + let bounty_id = BountyCount::::get() - 1; let curator = T::Lookup::lookup(curator_lookup).map_err(<&str>::from)?; let beneficiary_account: T::AccountId = account("beneficiary", 0, SEED); let beneficiary = T::Lookup::unlookup(beneficiary_account.clone()); - Bounties::::award_bounty(RawOrigin::Signed(curator.clone()).into(), bounty_id, beneficiary)?; + Bounties::::award_bounty(RawOrigin::Signed(curator.clone()).into(), bounty_id, beneficiary)?; - frame_system::Pallet::::set_block_number(T::BountyDepositPayoutDelay::get()); + frame_system::Pallet::::set_block_number(T::BountyDepositPayoutDelay::get() + 1u32.into()); ensure!(T::Currency::free_balance(&beneficiary_account).is_zero(), "Beneficiary already has balance"); }: _(RawOrigin::Signed(curator), bounty_id) @@ -159,45 +165,45 @@ benchmarks! { } close_bounty_proposed { - setup_pot_account::(); - let (caller, curator, fee, value, reason) = setup_bounty::(0, 0); - Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; - let bounty_id = BountyCount::::get() - 1; + setup_pot_account::(); + let (caller, curator, fee, value, reason) = setup_bounty::(0, 0); + Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; + let bounty_id = BountyCount::::get() - 1; }: close_bounty(RawOrigin::Root, bounty_id) close_bounty_active { - setup_pot_account::(); - let (curator_lookup, bounty_id) = create_bounty::()?; - Bounties::::on_initialize(T::BlockNumber::zero()); - let bounty_id = BountyCount::::get() - 1; + setup_pot_account::(); + let (curator_lookup, bounty_id) = create_bounty::()?; + Treasury::::on_initialize(T::BlockNumber::zero()); + let bounty_id = BountyCount::::get() - 1; }: close_bounty(RawOrigin::Root, bounty_id) verify { - assert_last_event::(Event::BountyCanceled { index: bounty_id }.into()) + assert_last_event::(Event::BountyCanceled { index: bounty_id }.into()) } extend_bounty_expiry { - setup_pot_account::(); - let (curator_lookup, bounty_id) = create_bounty::()?; - Bounties::::on_initialize(T::BlockNumber::zero()); + setup_pot_account::(); + let (curator_lookup, bounty_id) = create_bounty::()?; + Treasury::::on_initialize(T::BlockNumber::zero()); - let bounty_id = BountyCount::::get() - 1; + let bounty_id = BountyCount::::get() - 1; let curator = T::Lookup::lookup(curator_lookup).map_err(<&str>::from)?; }: _(RawOrigin::Signed(curator), bounty_id, Vec::new()) verify { - assert_last_event::(Event::BountyExtended { index: bounty_id }.into()) + assert_last_event::(Event::BountyExtended { index: bounty_id }.into()) } spend_funds { let b in 1 .. 100; - setup_pot_account::(); - create_approved_bounties::(b)?; + setup_pot_account::(); + create_approved_bounties::(b)?; - let mut budget_remaining = BalanceOf::::max_value(); - let mut imbalance = PositiveImbalanceOf::::zero(); + let mut budget_remaining = BalanceOf::::max_value(); + let mut imbalance = PositiveImbalanceOf::::zero(); let mut total_weight = Weight::zero(); let mut missed_any = false; }: { - as pallet_treasury::SpendFunds>::spend_funds( + as pallet_treasury::SpendFunds>::spend_funds( &mut budget_remaining, &mut imbalance, &mut total_weight, @@ -205,9 +211,9 @@ benchmarks! { ); } verify { - ensure!(budget_remaining < BalanceOf::::max_value(), "Budget not used"); + ensure!(budget_remaining < BalanceOf::::max_value(), "Budget not used"); ensure!(missed_any == false, "Missed some"); - assert_last_event::(Event::BountyBecameActive { index: b - 1 }.into()) + assert_last_event::(Event::BountyBecameActive { index: b - 1 }.into()) } impl_benchmark_test_suite!(Bounties, crate::tests::new_test_ext(), crate::tests::Test) diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index b01a36b430a4e..8e28cacb9d929 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -107,9 +107,9 @@ pub use weights::WeightInfo; pub use pallet::*; -type BalanceOf = pallet_treasury::BalanceOf; +type BalanceOf = pallet_treasury::BalanceOf; -type PositiveImbalanceOf = pallet_treasury::PositiveImbalanceOf; +type PositiveImbalanceOf = pallet_treasury::PositiveImbalanceOf; /// An index of a bounty. Just a `u32`. pub type BountyIndex = u32; @@ -188,13 +188,13 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); + pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + pallet_treasury::Config { + pub trait Config: frame_system::Config + pallet_treasury::Config { /// The amount held on deposit for placing a bounty proposal. #[pallet::constant] - type BountyDepositBase: Get>; + type BountyDepositBase: Get>; /// The delay period for which a bounty beneficiary need to wait before claim the payout. #[pallet::constant] @@ -213,22 +213,22 @@ pub mod pallet { /// Maximum amount of funds that should be placed in a deposit for making a proposal. #[pallet::constant] - type CuratorDepositMax: Get>>; + type CuratorDepositMax: Get>>; /// Minimum amount of funds that should be placed in a deposit for making a proposal. #[pallet::constant] - type CuratorDepositMin: Get>>; + type CuratorDepositMin: Get>>; /// Minimum value for a bounty. #[pallet::constant] - type BountyValueMinimum: Get>; + type BountyValueMinimum: Get>; /// The amount held on deposit per byte within the tip report reason or bounty description. #[pallet::constant] - type DataDepositPerByte: Get>; + type DataDepositPerByte: Get>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type Event: From> + IsType<::Event>; /// Maximum acceptable reason length. /// @@ -240,11 +240,11 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The child bounty manager. - type ChildBountyManager: ChildBountyManager>; + type ChildBountyManager: ChildBountyManager>; } #[pallet::error] - pub enum Error { + pub enum Error { /// Proposer's balance is too low. InsufficientProposersBalance, /// No proposal or bounty at that index. @@ -272,17 +272,17 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { + pub enum Event, I: 'static = ()> { /// New bounty proposal. BountyProposed { index: BountyIndex }, /// A bounty proposal was rejected; funds were slashed. - BountyRejected { index: BountyIndex, bond: BalanceOf }, + BountyRejected { index: BountyIndex, bond: BalanceOf }, /// A bounty proposal is funded and became active. BountyBecameActive { index: BountyIndex }, /// A bounty is awarded to a beneficiary. BountyAwarded { index: BountyIndex, beneficiary: T::AccountId }, /// A bounty is claimed by beneficiary. - BountyClaimed { index: BountyIndex, payout: BalanceOf, beneficiary: T::AccountId }, + BountyClaimed { index: BountyIndex, payout: BalanceOf, beneficiary: T::AccountId }, /// A bounty is cancelled. BountyCanceled { index: BountyIndex }, /// A bounty expiry is extended. @@ -292,32 +292,32 @@ pub mod pallet { /// Number of bounty proposals that have been made. #[pallet::storage] #[pallet::getter(fn bounty_count)] - pub type BountyCount = StorageValue<_, BountyIndex, ValueQuery>; + pub type BountyCount, I: 'static = ()> = StorageValue<_, BountyIndex, ValueQuery>; /// Bounties that have been made. #[pallet::storage] #[pallet::getter(fn bounties)] - pub type Bounties = StorageMap< + pub type Bounties, I: 'static = ()> = StorageMap< _, Twox64Concat, BountyIndex, - Bounty, T::BlockNumber>, + Bounty, T::BlockNumber>, >; /// The description of each bounty. #[pallet::storage] #[pallet::getter(fn bounty_descriptions)] - pub type BountyDescriptions = + pub type BountyDescriptions, I: 'static = ()> = StorageMap<_, Twox64Concat, BountyIndex, BoundedVec>; /// Bounty indices that have been approved but not yet funded. #[pallet::storage] #[pallet::getter(fn bounty_approvals)] - pub type BountyApprovals = + pub type BountyApprovals, I: 'static = ()> = StorageValue<_, BoundedVec, ValueQuery>; #[pallet::call] - impl Pallet { + impl, I: 'static> Pallet { /// Propose a new bounty. /// /// The dispatch origin for this call must be _Signed_. @@ -330,10 +330,10 @@ pub mod pallet { /// - `fee`: The curator fee. /// - `value`: The total payment amount of this bounty, curator fee included. /// - `description`: The description of this bounty. - #[pallet::weight(::WeightInfo::propose_bounty(description.len() as u32))] + #[pallet::weight(>::WeightInfo::propose_bounty(description.len() as u32))] pub fn propose_bounty( origin: OriginFor, - #[pallet::compact] value: BalanceOf, + #[pallet::compact] value: BalanceOf, description: Vec, ) -> DispatchResult { let proposer = ensure_signed(origin)?; @@ -349,21 +349,21 @@ pub mod pallet { /// # /// - O(1). /// # - #[pallet::weight(::WeightInfo::approve_bounty())] + #[pallet::weight(>::WeightInfo::approve_bounty())] pub fn approve_bounty( origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, ) -> DispatchResult { T::ApproveOrigin::ensure_origin(origin)?; - Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { - let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; - ensure!(bounty.status == BountyStatus::Proposed, Error::::UnexpectedStatus); + Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { + let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; + ensure!(bounty.status == BountyStatus::Proposed, Error::::UnexpectedStatus); bounty.status = BountyStatus::Approved; - BountyApprovals::::try_append(bounty_id) - .map_err(|()| Error::::TooManyQueued)?; + BountyApprovals::::try_append(bounty_id) + .map_err(|()| Error::::TooManyQueued)?; Ok(()) })?; @@ -377,24 +377,24 @@ pub mod pallet { /// # /// - O(1). /// # - #[pallet::weight(::WeightInfo::propose_curator())] + #[pallet::weight(>::WeightInfo::propose_curator())] pub fn propose_curator( origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, curator: ::Source, - #[pallet::compact] fee: BalanceOf, + #[pallet::compact] fee: BalanceOf, ) -> DispatchResult { T::ApproveOrigin::ensure_origin(origin)?; let curator = T::Lookup::lookup(curator)?; - Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { - let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; + Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { + let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; match bounty.status { BountyStatus::Proposed | BountyStatus::Approved | BountyStatus::Funded => {}, - _ => return Err(Error::::UnexpectedStatus.into()), + _ => return Err(Error::::UnexpectedStatus.into()), }; - ensure!(fee < bounty.value, Error::::InvalidFee); + ensure!(fee < bounty.value, Error::::InvalidFee); bounty.status = BountyStatus::CuratorProposed { curator }; bounty.fee = fee; @@ -422,7 +422,7 @@ pub mod pallet { /// # /// - O(1). /// # - #[pallet::weight(::WeightInfo::unassign_curator())] + #[pallet::weight(>::WeightInfo::unassign_curator())] pub fn unassign_curator( origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, @@ -431,10 +431,11 @@ pub mod pallet { .map(Some) .or_else(|_| T::RejectOrigin::ensure_origin(origin).map(|_| None))?; - Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { - let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; + Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { + let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; - let slash_curator = |curator: &T::AccountId, curator_deposit: &mut BalanceOf| { + let slash_curator = |curator: &T::AccountId, + curator_deposit: &mut BalanceOf| { let imbalance = T::Currency::slash_reserved(curator, *curator_deposit).0; T::OnSlash::on_unbalanced(imbalance); *curator_deposit = Zero::zero(); @@ -443,7 +444,7 @@ pub mod pallet { match bounty.status { BountyStatus::Proposed | BountyStatus::Approved | BountyStatus::Funded => { // No curator to unassign at this point. - return Err(Error::::UnexpectedStatus.into()) + return Err(Error::::UnexpectedStatus.into()) }, BountyStatus::CuratorProposed { ref curator } => { // A curator has been proposed, but not accepted yet. @@ -468,7 +469,7 @@ pub mod pallet { // Continue to change bounty status below... } else { // Curator has more time to give an update. - return Err(Error::::Premature.into()) + return Err(Error::::Premature.into()) } } else { // Else this is the curator, willingly giving up their role. @@ -506,19 +507,19 @@ pub mod pallet { /// # /// - O(1). /// # - #[pallet::weight(::WeightInfo::accept_curator())] + #[pallet::weight(>::WeightInfo::accept_curator())] pub fn accept_curator( origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, ) -> DispatchResult { let signer = ensure_signed(origin)?; - Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { - let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; + Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { + let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; match bounty.status { BountyStatus::CuratorProposed { ref curator } => { - ensure!(signer == *curator, Error::::RequireCurator); + ensure!(signer == *curator, Error::::RequireCurator); let deposit = Self::calculate_curator_deposit(&bounty.fee); T::Currency::reserve(curator, deposit)?; @@ -531,7 +532,7 @@ pub mod pallet { Ok(()) }, - _ => Err(Error::::UnexpectedStatus.into()), + _ => Err(Error::::UnexpectedStatus.into()), } })?; Ok(()) @@ -548,7 +549,7 @@ pub mod pallet { /// # /// - O(1). /// # - #[pallet::weight(::WeightInfo::award_bounty())] + #[pallet::weight(>::WeightInfo::award_bounty())] pub fn award_bounty( origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, @@ -557,20 +558,20 @@ pub mod pallet { let signer = ensure_signed(origin)?; let beneficiary = T::Lookup::lookup(beneficiary)?; - Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { - let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; + Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { + let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; // Ensure no active child bounties before processing the call. ensure!( T::ChildBountyManager::child_bounties_count(bounty_id) == 0, - Error::::HasActiveChildBounty + Error::::HasActiveChildBounty ); match &bounty.status { BountyStatus::Active { curator, .. } => { - ensure!(signer == *curator, Error::::RequireCurator); + ensure!(signer == *curator, Error::::RequireCurator); }, - _ => return Err(Error::::UnexpectedStatus.into()), + _ => return Err(Error::::UnexpectedStatus.into()), } bounty.status = BountyStatus::PendingPayout { curator: signer, @@ -582,7 +583,7 @@ pub mod pallet { Ok(()) })?; - Self::deposit_event(Event::::BountyAwarded { index: bounty_id, beneficiary }); + Self::deposit_event(Event::::BountyAwarded { index: bounty_id, beneficiary }); Ok(()) } @@ -595,21 +596,21 @@ pub mod pallet { /// # /// - O(1). /// # - #[pallet::weight(::WeightInfo::claim_bounty())] + #[pallet::weight(>::WeightInfo::claim_bounty())] pub fn claim_bounty( origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, ) -> DispatchResult { let _ = ensure_signed(origin)?; // anyone can trigger claim - Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { - let bounty = maybe_bounty.take().ok_or(Error::::InvalidIndex)?; + Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { + let bounty = maybe_bounty.take().ok_or(Error::::InvalidIndex)?; if let BountyStatus::PendingPayout { curator, beneficiary, unlock_at } = bounty.status { ensure!( frame_system::Pallet::::block_number() >= unlock_at, - Error::::Premature + Error::::Premature ); let bounty_account = Self::bounty_account_id(bounty_id); let balance = T::Currency::free_balance(&bounty_account); @@ -633,16 +634,16 @@ pub mod pallet { *maybe_bounty = None; - BountyDescriptions::::remove(bounty_id); + BountyDescriptions::::remove(bounty_id); - Self::deposit_event(Event::::BountyClaimed { + Self::deposit_event(Event::::BountyClaimed { index: bounty_id, payout, beneficiary, }); Ok(()) } else { - Err(Error::::UnexpectedStatus.into()) + Err(Error::::UnexpectedStatus.into()) } })?; Ok(()) @@ -658,47 +659,47 @@ pub mod pallet { /// # /// - O(1). /// # - #[pallet::weight(::WeightInfo::close_bounty_proposed() - .max(::WeightInfo::close_bounty_active()))] + #[pallet::weight(>::WeightInfo::close_bounty_proposed() + .max(>::WeightInfo::close_bounty_active()))] pub fn close_bounty( origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, ) -> DispatchResultWithPostInfo { T::RejectOrigin::ensure_origin(origin)?; - Bounties::::try_mutate_exists( + Bounties::::try_mutate_exists( bounty_id, |maybe_bounty| -> DispatchResultWithPostInfo { - let bounty = maybe_bounty.as_ref().ok_or(Error::::InvalidIndex)?; + let bounty = maybe_bounty.as_ref().ok_or(Error::::InvalidIndex)?; // Ensure no active child bounties before processing the call. ensure!( T::ChildBountyManager::child_bounties_count(bounty_id) == 0, - Error::::HasActiveChildBounty + Error::::HasActiveChildBounty ); match &bounty.status { BountyStatus::Proposed => { // The reject origin would like to cancel a proposed bounty. - BountyDescriptions::::remove(bounty_id); + BountyDescriptions::::remove(bounty_id); let value = bounty.bond; let imbalance = T::Currency::slash_reserved(&bounty.proposer, value).0; T::OnSlash::on_unbalanced(imbalance); *maybe_bounty = None; - Self::deposit_event(Event::::BountyRejected { + Self::deposit_event(Event::::BountyRejected { index: bounty_id, bond: value, }); // Return early, nothing else to do. return Ok( - Some(::WeightInfo::close_bounty_proposed()).into() + Some(>::WeightInfo::close_bounty_proposed()).into() ) }, BountyStatus::Approved => { // For weight reasons, we don't allow a council to cancel in this phase. // We ask for them to wait until it is funded before they can cancel. - return Err(Error::::UnexpectedStatus.into()) + return Err(Error::::UnexpectedStatus.into()) }, BountyStatus::Funded | BountyStatus::CuratorProposed { .. } => { // Nothing extra to do besides the removal of the bounty below. @@ -715,13 +716,13 @@ pub mod pallet { // this bounty, it should mean the curator was acting maliciously. // So the council should first unassign the curator, slashing their // deposit. - return Err(Error::::PendingPayout.into()) + return Err(Error::::PendingPayout.into()) }, } let bounty_account = Self::bounty_account_id(bounty_id); - BountyDescriptions::::remove(bounty_id); + BountyDescriptions::::remove(bounty_id); let balance = T::Currency::free_balance(&bounty_account); let res = T::Currency::transfer( @@ -733,8 +734,8 @@ pub mod pallet { debug_assert!(res.is_ok()); *maybe_bounty = None; - Self::deposit_event(Event::::BountyCanceled { index: bounty_id }); - Ok(Some(::WeightInfo::close_bounty_active()).into()) + Self::deposit_event(Event::::BountyCanceled { index: bounty_id }); + Ok(Some(>::WeightInfo::close_bounty_active()).into()) }, ) } @@ -749,7 +750,7 @@ pub mod pallet { /// # /// - O(1). /// # - #[pallet::weight(::WeightInfo::extend_bounty_expiry())] + #[pallet::weight(>::WeightInfo::extend_bounty_expiry())] pub fn extend_bounty_expiry( origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, @@ -757,30 +758,30 @@ pub mod pallet { ) -> DispatchResult { let signer = ensure_signed(origin)?; - Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { - let bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; + Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { + let bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; match bounty.status { BountyStatus::Active { ref curator, ref mut update_due } => { - ensure!(*curator == signer, Error::::RequireCurator); + ensure!(*curator == signer, Error::::RequireCurator); *update_due = (frame_system::Pallet::::block_number() + T::BountyUpdatePeriod::get()) .max(*update_due); }, - _ => return Err(Error::::UnexpectedStatus.into()), + _ => return Err(Error::::UnexpectedStatus.into()), } Ok(()) })?; - Self::deposit_event(Event::::BountyExtended { index: bounty_id }); + Self::deposit_event(Event::::BountyExtended { index: bounty_id }); Ok(()) } } } -impl Pallet { - pub fn calculate_curator_deposit(fee: &BalanceOf) -> BalanceOf { +impl, I: 'static> Pallet { + pub fn calculate_curator_deposit(fee: &BalanceOf) -> BalanceOf { let mut deposit = T::CuratorDepositMultiplier::get() * *fee; if let Some(max_deposit) = T::CuratorDepositMax::get() { @@ -812,11 +813,11 @@ impl Pallet { fn create_bounty( proposer: T::AccountId, description: Vec, - value: BalanceOf, + value: BalanceOf, ) -> DispatchResult { let bounded_description: BoundedVec<_, _> = - description.try_into().map_err(|()| Error::::ReasonTooBig)?; - ensure!(value >= T::BountyValueMinimum::get(), Error::::InvalidValue); + description.try_into().map_err(|()| Error::::ReasonTooBig)?; + ensure!(value >= T::BountyValueMinimum::get(), Error::::InvalidValue); let index = Self::bounty_count(); @@ -824,9 +825,9 @@ impl Pallet { let bond = T::BountyDepositBase::get() + T::DataDepositPerByte::get() * (bounded_description.len() as u32).into(); T::Currency::reserve(&proposer, bond) - .map_err(|_| Error::::InsufficientProposersBalance)?; + .map_err(|_| Error::::InsufficientProposersBalance)?; - BountyCount::::put(index + 1); + BountyCount::::put(index + 1); let bounty = Bounty { proposer, @@ -837,26 +838,26 @@ impl Pallet { status: BountyStatus::Proposed, }; - Bounties::::insert(index, &bounty); - BountyDescriptions::::insert(index, bounded_description); + Bounties::::insert(index, &bounty); + BountyDescriptions::::insert(index, bounded_description); - Self::deposit_event(Event::::BountyProposed { index }); + Self::deposit_event(Event::::BountyProposed { index }); Ok(()) } } -impl pallet_treasury::SpendFunds for Pallet { +impl, I: 'static> pallet_treasury::SpendFunds for Pallet { fn spend_funds( - budget_remaining: &mut BalanceOf, - imbalance: &mut PositiveImbalanceOf, + budget_remaining: &mut BalanceOf, + imbalance: &mut PositiveImbalanceOf, total_weight: &mut Weight, missed_any: &mut bool, ) { - let bounties_len = BountyApprovals::::mutate(|v| { + let bounties_len = BountyApprovals::::mutate(|v| { let bounties_approval_len = v.len() as u32; v.retain(|&index| { - Bounties::::mutate(index, |bounty| { + Bounties::::mutate(index, |bounty| { // Should always be true, but shouldn't panic if false or we're screwed. if let Some(bounty) = bounty { if bounty.value <= *budget_remaining { @@ -874,7 +875,7 @@ impl pallet_treasury::SpendFunds for Pallet { bounty.value, )); - Self::deposit_event(Event::::BountyBecameActive { index }); + Self::deposit_event(Event::::BountyBecameActive { index }); false } else { *missed_any = true; @@ -888,7 +889,7 @@ impl pallet_treasury::SpendFunds for Pallet { bounties_approval_len }); - *total_weight += ::WeightInfo::spend_funds(bounties_len); + *total_weight += >::WeightInfo::spend_funds(bounties_len); } } diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index 0904e3a2901bb..ff220600794d4 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -35,7 +35,7 @@ use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BadOrigin, BlakeTwo256, IdentityLookup}, - Perbill, Storage, + BuildStorage, Perbill, Storage, }; use super::Event as BountiesEvent; @@ -52,7 +52,9 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Bounties: pallet_bounties::{Pallet, Call, Storage, Event}, + Bounties1: pallet_bounties::::{Pallet, Call, Storage, Event}, Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event}, + Treasury1: pallet_treasury::::{Pallet, Call, Storage, Config, Event}, } ); @@ -105,8 +107,9 @@ thread_local! { } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); - pub const Burn: Permill = Permill::from_percent(50); + pub static Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub const TreasuryPalletId2: PalletId = PalletId(*b"py/trsr2"); } impl pallet_treasury::Config for Test { @@ -128,6 +131,25 @@ impl pallet_treasury::Config for Test { type SpendOrigin = frame_support::traits::NeverEnsureOrigin; } +impl pallet_treasury::Config for Test { + type PalletId = TreasuryPalletId2; + type Currency = pallet_balances::Pallet; + type ApproveOrigin = frame_system::EnsureRoot; + type RejectOrigin = frame_system::EnsureRoot; + type Event = Event; + type OnSlash = (); + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ConstU64<1>; + type ProposalBondMaximum = (); + type SpendPeriod = ConstU64<2>; + type Burn = Burn; + type BurnDestination = (); // Just gets burned. + type WeightInfo = (); + type SpendFunds = Bounties1; + type MaxApprovals = ConstU32<100>; + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; +} + parameter_types! { // This will be 50% of the bounty fee. pub const CuratorDepositMultiplier: Permill = Permill::from_percent(50); @@ -151,18 +173,35 @@ impl Config for Test { type ChildBountyManager = (); } +impl Config for Test { + type Event = Event; + type BountyDepositBase = ConstU64<80>; + type BountyDepositPayoutDelay = ConstU64<3>; + type BountyUpdatePeriod = ConstU64<20>; + type CuratorDepositMultiplier = CuratorDepositMultiplier; + type CuratorDepositMax = CuratorDepositMax; + type CuratorDepositMin = CuratorDepositMin; + type BountyValueMinimum = ConstU64<1>; + type DataDepositPerByte = ConstU64<1>; + type MaximumReasonLength = ConstU32<16384>; + type WeightInfo = (); + type ChildBountyManager = (); +} + type TreasuryError = pallet_treasury::Error; pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - // Total issuance will be 200 with treasury account initialized at ED. - balances: vec![(0, 100), (1, 98), (2, 1)], + let mut ext: sp_io::TestExternalities = GenesisConfig { + system: frame_system::GenesisConfig::default(), + balances: pallet_balances::GenesisConfig { balances: vec![(0, 100), (1, 98), (2, 1)] }, + treasury: Default::default(), + treasury_1: Default::default(), } - .assimilate_storage(&mut t) - .unwrap(); - GenesisBuild::::assimilate_storage(&pallet_treasury::GenesisConfig, &mut t).unwrap(); - t.into() + .build_storage() + .unwrap() + .into(); + ext.execute_with(|| System::set_block_number(1)); + ext } fn last_event() -> BountiesEvent { @@ -276,7 +315,7 @@ fn reject_non_existent_spend_proposal_fails() { new_test_ext().execute_with(|| { assert_noop!( Treasury::reject_proposal(Origin::root(), 0), - pallet_treasury::Error::::InvalidIndex + pallet_treasury::Error::::InvalidIndex ); }); } @@ -469,7 +508,7 @@ fn close_bounty_works() { assert_eq!(Balances::free_balance(0), 100 - deposit); assert_eq!(Bounties::bounties(0), None); - assert!(!pallet_treasury::Proposals::::contains_key(0)); + assert!(!pallet_treasury::Proposals::::contains_key(0)); assert_eq!(Bounties::bounty_descriptions(0), None); }); @@ -1122,3 +1161,29 @@ fn accept_curator_handles_different_deposit_calculations() { assert_eq!(Balances::reserved_balance(&user), expected_deposit); }); } + +#[test] +fn approve_bounty_works_second_instance() { + new_test_ext().execute_with(|| { + // Set burn to 0 to make tracking funds easier. + Burn::set(Permill::from_percent(0)); + + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + Balances::make_free_balance_be(&Treasury1::account_id(), 201); + assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); + assert_eq!(Balances::free_balance(&Treasury1::account_id()), 201); + + assert_ok!(Bounties1::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties1::approve_bounty(Origin::root(), 0)); + >::on_initialize(2); + >::on_initialize(2); + + // Bounties 1 is funded... but from where? + assert_eq!(Balances::free_balance(Bounties1::bounty_account_id(0)), 50); + // Treasury 1 unchanged + assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); + // Treasury 2 has funds removed + assert_eq!(Balances::free_balance(&Treasury1::account_id()), 201 - 50); + }); +} diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 190ef60f3b810..33e455bd3b9fd 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -19,7 +19,7 @@ #![cfg(feature = "runtime-benchmarks")] -use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller}; use frame_support::ensure; use frame_system::RawOrigin; use sp_runtime::traits::Saturating; @@ -30,7 +30,7 @@ use crate::Pallet as TipsMod; const SEED: u32 = 0; // Create the pre-requisite information needed to create a `report_awesome`. -fn setup_awesome(length: u32) -> (T::AccountId, Vec, T::AccountId) { +fn setup_awesome, I: 'static>(length: u32) -> (T::AccountId, Vec, T::AccountId) { let caller = whitelisted_caller(); let value = T::TipReportDepositBase::get() + T::DataDepositPerByte::get() * length.into() + @@ -42,10 +42,10 @@ fn setup_awesome(length: u32) -> (T::AccountId, Vec, T::AccountId } // Create the pre-requisite information needed to call `tip_new`. -fn setup_tip( +fn setup_tip, I: 'static>( r: u32, t: u32, -) -> Result<(T::AccountId, Vec, T::AccountId, BalanceOf), &'static str> { +) -> Result<(T::AccountId, Vec, T::AccountId, BalanceOf), &'static str> { let tippers_count = T::Tippers::count(); for i in 0..t { @@ -64,13 +64,17 @@ fn setup_tip( // Create `t` new tips for the tip proposal with `hash`. // This function automatically makes the tip able to close. -fn create_tips(t: u32, hash: T::Hash, value: BalanceOf) -> Result<(), &'static str> { +fn create_tips, I: 'static>( + t: u32, + hash: T::Hash, + value: BalanceOf, +) -> Result<(), &'static str> { for i in 0..t { let caller = account("member", i, SEED); ensure!(T::Tippers::contains(&caller), "caller is not a tipper"); - TipsMod::::tip(RawOrigin::Signed(caller).into(), hash, value)?; + TipsMod::::tip(RawOrigin::Signed(caller).into(), hash, value)?; } - Tips::::mutate(hash, |maybe_tip| { + Tips::::mutate(hash, |maybe_tip| { if let Some(open_tip) = maybe_tip { open_tip.closes = Some(T::BlockNumber::zero()); } @@ -78,16 +82,16 @@ fn create_tips(t: u32, hash: T::Hash, value: BalanceOf) -> Result< Ok(()) } -fn setup_pot_account() { - let pot_account = TipsMod::::account_id(); +fn setup_pot_account, I: 'static>() { + let pot_account = TipsMod::::account_id(); let value = T::Currency::minimum_balance().saturating_mul(1_000_000_000u32.into()); let _ = T::Currency::make_free_balance_be(&pot_account, value); } -benchmarks! { +benchmarks_instance_pallet! { report_awesome { let r in 0 .. T::MaximumReasonLength::get(); - let (caller, reason, awesome_person) = setup_awesome::(r); + let (caller, reason, awesome_person) = setup_awesome::(r); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); @@ -95,8 +99,8 @@ benchmarks! { retract_tip { let r = T::MaximumReasonLength::get(); - let (caller, reason, awesome_person) = setup_awesome::(r); - TipsMod::::report_awesome( + let (caller, reason, awesome_person) = setup_awesome::(r); + TipsMod::::report_awesome( RawOrigin::Signed(caller.clone()).into(), reason.clone(), awesome_person.clone() @@ -112,7 +116,7 @@ benchmarks! { let r in 0 .. T::MaximumReasonLength::get(); let t in 1 .. T::Tippers::max_len() as u32; - let (caller, reason, beneficiary, value) = setup_tip::(r, t)?; + let (caller, reason, beneficiary, value) = setup_tip::(r, t)?; // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); @@ -120,9 +124,9 @@ benchmarks! { tip { let t in 1 .. T::Tippers::max_len() as u32; - let (member, reason, beneficiary, value) = setup_tip::(0, t)?; + let (member, reason, beneficiary, value) = setup_tip::(0, t)?; let value = T::Currency::minimum_balance().saturating_mul(100u32.into()); - TipsMod::::tip_new( + TipsMod::::tip_new( RawOrigin::Signed(member).into(), reason.clone(), beneficiary.clone(), @@ -130,8 +134,8 @@ benchmarks! { )?; let reason_hash = T::Hashing::hash(&reason[..]); let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary)); - ensure!(Tips::::contains_key(hash), "tip does not exist"); - create_tips::(t - 1, hash, value)?; + ensure!(Tips::::contains_key(hash), "tip does not exist"); + create_tips::(t - 1, hash, value)?; let caller = account("member", t - 1, SEED); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); @@ -142,12 +146,12 @@ benchmarks! { let t in 1 .. T::Tippers::max_len() as u32; // Make sure pot is funded - setup_pot_account::(); + setup_pot_account::(); // Set up a new tip proposal - let (member, reason, beneficiary, value) = setup_tip::(0, t)?; + let (member, reason, beneficiary, value) = setup_tip::(0, t)?; let value = T::Currency::minimum_balance().saturating_mul(100u32.into()); - TipsMod::::tip_new( + TipsMod::::tip_new( RawOrigin::Signed(member).into(), reason.clone(), beneficiary.clone(), @@ -157,9 +161,9 @@ benchmarks! { // Create a bunch of tips let reason_hash = T::Hashing::hash(&reason[..]); let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary)); - ensure!(Tips::::contains_key(hash), "tip does not exist"); + ensure!(Tips::::contains_key(hash), "tip does not exist"); - create_tips::(t, hash, value)?; + create_tips::(t, hash, value)?; let caller = account("caller", t, SEED); // Whitelist caller account from further DB operations. @@ -171,12 +175,12 @@ benchmarks! { let t in 1 .. T::Tippers::max_len() as u32; // Make sure pot is funded - setup_pot_account::(); + setup_pot_account::(); // Set up a new tip proposal - let (member, reason, beneficiary, value) = setup_tip::(0, t)?; + let (member, reason, beneficiary, value) = setup_tip::(0, t)?; let value = T::Currency::minimum_balance().saturating_mul(100u32.into()); - TipsMod::::tip_new( + TipsMod::::tip_new( RawOrigin::Signed(member).into(), reason.clone(), beneficiary.clone(), @@ -185,7 +189,7 @@ benchmarks! { let reason_hash = T::Hashing::hash(&reason[..]); let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary)); - ensure!(Tips::::contains_key(hash), "tip does not exist"); + ensure!(Tips::::contains_key(hash), "tip does not exist"); }: _(RawOrigin::Root, hash) impl_benchmark_test_suite!(TipsMod, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index e1c7b5e77c062..71af87b42b55b 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -78,8 +78,8 @@ use frame_support::{ pub use pallet::*; pub use weights::WeightInfo; -pub type BalanceOf = pallet_treasury::BalanceOf; -pub type NegativeImbalanceOf = pallet_treasury::NegativeImbalanceOf; +pub type BalanceOf = pallet_treasury::BalanceOf; +pub type NegativeImbalanceOf = pallet_treasury::NegativeImbalanceOf; /// An open tipping "motion". Retains all details of a tip including information on the finder /// and the members who have voted. @@ -121,12 +121,12 @@ pub mod pallet { #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] #[pallet::without_storage_info] - pub struct Pallet(_); + pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + pallet_treasury::Config { + pub trait Config: frame_system::Config + pallet_treasury::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type Event: From> + IsType<::Event>; /// Maximum acceptable reason length. /// @@ -136,7 +136,7 @@ pub mod pallet { /// The amount held on deposit per byte within the tip report reason or bounty description. #[pallet::constant] - type DataDepositPerByte: Get>; + type DataDepositPerByte: Get>; /// The period for which a tip remains open after is has achieved threshold tippers. #[pallet::constant] @@ -148,7 +148,7 @@ pub mod pallet { /// The amount held on deposit for placing a tip report. #[pallet::constant] - type TipReportDepositBase: Get>; + type TipReportDepositBase: Get>; /// Origin from which tippers must come. /// @@ -166,11 +166,11 @@ pub mod pallet { /// guaranteed to be a secure hash. #[pallet::storage] #[pallet::getter(fn tips)] - pub type Tips = StorageMap< + pub type Tips, I: 'static = ()> = StorageMap< _, Twox64Concat, T::Hash, - OpenTip, T::BlockNumber, T::Hash>, + OpenTip, T::BlockNumber, T::Hash>, OptionQuery, >; @@ -178,25 +178,26 @@ pub mod pallet { /// insecure enumerable hash since the key is guaranteed to be the result of a secure hash. #[pallet::storage] #[pallet::getter(fn reasons)] - pub type Reasons = StorageMap<_, Identity, T::Hash, Vec, OptionQuery>; + pub type Reasons, I: 'static = ()> = + StorageMap<_, Identity, T::Hash, Vec, OptionQuery>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { + pub enum Event, I: 'static = ()> { /// A new tip suggestion has been opened. NewTip { tip_hash: T::Hash }, /// A tip suggestion has reached threshold and is closing. TipClosing { tip_hash: T::Hash }, /// A tip suggestion has been closed. - TipClosed { tip_hash: T::Hash, who: T::AccountId, payout: BalanceOf }, + TipClosed { tip_hash: T::Hash, who: T::AccountId, payout: BalanceOf }, /// A tip suggestion has been retracted. TipRetracted { tip_hash: T::Hash }, /// A tip suggestion has been slashed. - TipSlashed { tip_hash: T::Hash, finder: T::AccountId, deposit: BalanceOf }, + TipSlashed { tip_hash: T::Hash, finder: T::AccountId, deposit: BalanceOf }, } #[pallet::error] - pub enum Error { + pub enum Error { /// The reason given is just too big. ReasonTooBig, /// The tip was already found/started. @@ -212,7 +213,7 @@ pub mod pallet { } #[pallet::call] - impl Pallet { + impl, I: 'static> Pallet { /// Report something `reason` that deserves a tip and claim any eventual the finder's fee. /// /// The dispatch origin for this call must be _Signed_. @@ -232,7 +233,7 @@ pub mod pallet { /// - DbReads: `Reasons`, `Tips` /// - DbWrites: `Reasons`, `Tips` /// # - #[pallet::weight(::WeightInfo::report_awesome(reason.len() as u32))] + #[pallet::weight(>::WeightInfo::report_awesome(reason.len() as u32))] pub fn report_awesome( origin: OriginFor, reason: Vec, @@ -242,19 +243,19 @@ pub mod pallet { ensure!( reason.len() <= T::MaximumReasonLength::get() as usize, - Error::::ReasonTooBig + Error::::ReasonTooBig ); let reason_hash = T::Hashing::hash(&reason[..]); - ensure!(!Reasons::::contains_key(&reason_hash), Error::::AlreadyKnown); + ensure!(!Reasons::::contains_key(&reason_hash), Error::::AlreadyKnown); let hash = T::Hashing::hash_of(&(&reason_hash, &who)); - ensure!(!Tips::::contains_key(&hash), Error::::AlreadyKnown); + ensure!(!Tips::::contains_key(&hash), Error::::AlreadyKnown); let deposit = T::TipReportDepositBase::get() + T::DataDepositPerByte::get() * (reason.len() as u32).into(); T::Currency::reserve(&finder, deposit)?; - Reasons::::insert(&reason_hash, &reason); + Reasons::::insert(&reason_hash, &reason); let tip = OpenTip { reason: reason_hash, who, @@ -264,7 +265,7 @@ pub mod pallet { tips: vec![], finders_fee: true, }; - Tips::::insert(&hash, tip); + Tips::::insert(&hash, tip); Self::deposit_event(Event::NewTip { tip_hash: hash }); Ok(()) } @@ -288,14 +289,14 @@ pub mod pallet { /// - DbReads: `Tips`, `origin account` /// - DbWrites: `Reasons`, `Tips`, `origin account` /// # - #[pallet::weight(::WeightInfo::retract_tip())] + #[pallet::weight(>::WeightInfo::retract_tip())] pub fn retract_tip(origin: OriginFor, hash: T::Hash) -> DispatchResult { let who = ensure_signed(origin)?; - let tip = Tips::::get(&hash).ok_or(Error::::UnknownTip)?; - ensure!(tip.finder == who, Error::::NotFinder); + let tip = Tips::::get(&hash).ok_or(Error::::UnknownTip)?; + ensure!(tip.finder == who, Error::::NotFinder); - Reasons::::remove(&tip.reason); - Tips::::remove(&hash); + Reasons::::remove(&tip.reason); + Tips::::remove(&hash); if !tip.deposit.is_zero() { let err_amount = T::Currency::unreserve(&who, tip.deposit); debug_assert!(err_amount.is_zero()); @@ -326,20 +327,20 @@ pub mod pallet { /// - DbReads: `Tippers`, `Reasons` /// - DbWrites: `Reasons`, `Tips` /// # - #[pallet::weight(::WeightInfo::tip_new(reason.len() as u32, T::Tippers::max_len() as u32))] + #[pallet::weight(>::WeightInfo::tip_new(reason.len() as u32, T::Tippers::max_len() as u32))] pub fn tip_new( origin: OriginFor, reason: Vec, who: T::AccountId, - #[pallet::compact] tip_value: BalanceOf, + #[pallet::compact] tip_value: BalanceOf, ) -> DispatchResult { let tipper = ensure_signed(origin)?; ensure!(T::Tippers::contains(&tipper), BadOrigin); let reason_hash = T::Hashing::hash(&reason[..]); - ensure!(!Reasons::::contains_key(&reason_hash), Error::::AlreadyKnown); + ensure!(!Reasons::::contains_key(&reason_hash), Error::::AlreadyKnown); let hash = T::Hashing::hash_of(&(&reason_hash, &who)); - Reasons::::insert(&reason_hash, &reason); + Reasons::::insert(&reason_hash, &reason); Self::deposit_event(Event::NewTip { tip_hash: hash }); let tips = vec![(tipper.clone(), tip_value)]; let tip = OpenTip { @@ -351,7 +352,7 @@ pub mod pallet { tips, finders_fee: false, }; - Tips::::insert(&hash, tip); + Tips::::insert(&hash, tip); Ok(()) } @@ -379,20 +380,20 @@ pub mod pallet { /// - DbReads: `Tippers`, `Tips` /// - DbWrites: `Tips` /// # - #[pallet::weight(::WeightInfo::tip(T::Tippers::max_len() as u32))] + #[pallet::weight(>::WeightInfo::tip(T::Tippers::max_len() as u32))] pub fn tip( origin: OriginFor, hash: T::Hash, - #[pallet::compact] tip_value: BalanceOf, + #[pallet::compact] tip_value: BalanceOf, ) -> DispatchResult { let tipper = ensure_signed(origin)?; ensure!(T::Tippers::contains(&tipper), BadOrigin); - let mut tip = Tips::::get(hash).ok_or(Error::::UnknownTip)?; + let mut tip = Tips::::get(hash).ok_or(Error::::UnknownTip)?; if Self::insert_tip_and_check_closing(&mut tip, tipper, tip_value) { Self::deposit_event(Event::TipClosing { tip_hash: hash }); } - Tips::::insert(&hash, tip); + Tips::::insert(&hash, tip); Ok(()) } @@ -412,16 +413,16 @@ pub mod pallet { /// - DbReads: `Tips`, `Tippers`, `tip finder` /// - DbWrites: `Reasons`, `Tips`, `Tippers`, `tip finder` /// # - #[pallet::weight(::WeightInfo::close_tip(T::Tippers::max_len() as u32))] + #[pallet::weight(>::WeightInfo::close_tip(T::Tippers::max_len() as u32))] pub fn close_tip(origin: OriginFor, hash: T::Hash) -> DispatchResult { ensure_signed(origin)?; - let tip = Tips::::get(hash).ok_or(Error::::UnknownTip)?; - let n = tip.closes.as_ref().ok_or(Error::::StillOpen)?; - ensure!(frame_system::Pallet::::block_number() >= *n, Error::::Premature); + let tip = Tips::::get(hash).ok_or(Error::::UnknownTip)?; + let n = tip.closes.as_ref().ok_or(Error::::StillOpen)?; + ensure!(frame_system::Pallet::::block_number() >= *n, Error::::Premature); // closed. - Reasons::::remove(&tip.reason); - Tips::::remove(hash); + Reasons::::remove(&tip.reason); + Tips::::remove(hash); Self::payout_tip(hash, tip); Ok(()) } @@ -438,17 +439,17 @@ pub mod pallet { /// `T` is charged as upper bound given by `ContainsLengthBound`. /// The actual cost depends on the implementation of `T::Tippers`. /// # - #[pallet::weight(::WeightInfo::slash_tip(T::Tippers::max_len() as u32))] + #[pallet::weight(>::WeightInfo::slash_tip(T::Tippers::max_len() as u32))] pub fn slash_tip(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::RejectOrigin::ensure_origin(origin)?; - let tip = Tips::::take(hash).ok_or(Error::::UnknownTip)?; + let tip = Tips::::take(hash).ok_or(Error::::UnknownTip)?; if !tip.deposit.is_zero() { let imbalance = T::Currency::slash_reserved(&tip.finder, tip.deposit).0; T::OnSlash::on_unbalanced(imbalance); } - Reasons::::remove(&tip.reason); + Reasons::::remove(&tip.reason); Self::deposit_event(Event::TipSlashed { tip_hash: hash, finder: tip.finder, @@ -459,7 +460,7 @@ pub mod pallet { } } -impl Pallet { +impl, I: 'static> Pallet { // Add public immutables and private mutables. /// The account ID of the treasury pot. @@ -475,9 +476,9 @@ impl Pallet { /// /// `O(T)` and one storage access. fn insert_tip_and_check_closing( - tip: &mut OpenTip, T::BlockNumber, T::Hash>, + tip: &mut OpenTip, T::BlockNumber, T::Hash>, tipper: T::AccountId, - tip_value: BalanceOf, + tip_value: BalanceOf, ) -> bool { match tip.tips.binary_search_by_key(&&tipper, |x| &x.0) { Ok(pos) => tip.tips[pos] = (tipper, tip_value), @@ -494,7 +495,7 @@ impl Pallet { } /// Remove any non-members of `Tippers` from a `tips` vector. `O(T)`. - fn retain_active_tips(tips: &mut Vec<(T::AccountId, BalanceOf)>) { + fn retain_active_tips(tips: &mut Vec<(T::AccountId, BalanceOf)>) { let members = T::Tippers::sorted_members(); let mut members_iter = members.iter(); let mut member = members_iter.next(); @@ -520,14 +521,14 @@ impl Pallet { /// Plus `O(T)` (`T` is Tippers length). fn payout_tip( hash: T::Hash, - tip: OpenTip, T::BlockNumber, T::Hash>, + tip: OpenTip, T::BlockNumber, T::Hash>, ) { let mut tips = tip.tips; Self::retain_active_tips(&mut tips); tips.sort_by_key(|i| i.1); let treasury = Self::account_id(); - let max_payout = pallet_treasury::Pallet::::pot(); + let max_payout = pallet_treasury::Pallet::::pot(); let mut payout = tips[tips.len() / 2].1.min(max_payout); if !tip.deposit.is_zero() { @@ -582,7 +583,7 @@ impl Pallet { for (hash, old_tip) in storage_key_iter::< T::Hash, - OldOpenTip, T::BlockNumber, T::Hash>, + OldOpenTip, T::BlockNumber, T::Hash>, Twox64Concat, >(module, item) .drain() @@ -600,7 +601,7 @@ impl Pallet { tips: old_tip.tips, finders_fee, }; - Tips::::insert(hash, new_tip) + Tips::::insert(hash, new_tip) } } } diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index 235952fd1092c..194ecc60d9890 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -25,7 +25,7 @@ use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BadOrigin, BlakeTwo256, IdentityLookup}, - Perbill, Permill, + BuildStorage, Perbill, Permill, }; use sp_storage::Storage; @@ -53,7 +53,9 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event}, + Treasury1: pallet_treasury::::{Pallet, Call, Storage, Config, Event}, Tips: pallet_tips::{Pallet, Call, Storage, Event}, + Tips1: pallet_tips::::{Pallet, Call, Storage, Event}, } ); @@ -127,6 +129,7 @@ parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub const TreasuryPalletId2: PalletId = PalletId(*b"py/trsr2"); } impl pallet_treasury::Config for Test { type PalletId = TreasuryPalletId; @@ -146,6 +149,26 @@ impl pallet_treasury::Config for Test { type MaxApprovals = ConstU32<100>; type SpendOrigin = frame_support::traits::NeverEnsureOrigin; } + +impl pallet_treasury::Config for Test { + type PalletId = TreasuryPalletId2; + type Currency = pallet_balances::Pallet; + type ApproveOrigin = frame_system::EnsureRoot; + type RejectOrigin = frame_system::EnsureRoot; + type Event = Event; + type OnSlash = (); + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ConstU64<1>; + type ProposalBondMaximum = (); + type SpendPeriod = ConstU64<2>; + type Burn = Burn; + type BurnDestination = (); // Just gets burned. + type WeightInfo = (); + type SpendFunds = (); + type MaxApprovals = ConstU32<100>; + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; +} + parameter_types! { pub const TipFindersFee: Percent = Percent::from_percent(20); } @@ -160,16 +183,29 @@ impl Config for Test { type WeightInfo = (); } +impl Config for Test { + type MaximumReasonLength = ConstU32<16384>; + type Tippers = TenToFourteen; + type TipCountdown = ConstU64<1>; + type TipFindersFee = TipFindersFee; + type TipReportDepositBase = ConstU64<1>; + type DataDepositPerByte = ConstU64<1>; + type Event = Event; + type WeightInfo = (); +} + pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - // Total issuance will be 200 with treasury account initialized at ED. - balances: vec![(0, 100), (1, 98), (2, 1)], + let mut ext: sp_io::TestExternalities = GenesisConfig { + system: frame_system::GenesisConfig::default(), + balances: pallet_balances::GenesisConfig { balances: vec![(0, 100), (1, 98), (2, 1)] }, + treasury: Default::default(), + treasury_1: Default::default(), } - .assimilate_storage(&mut t) - .unwrap(); - GenesisBuild::::assimilate_storage(&pallet_treasury::GenesisConfig, &mut t).unwrap(); - t.into() + .build_storage() + .unwrap() + .into(); + ext.execute_with(|| System::set_block_number(1)); + ext } fn last_event() -> TipEvent { @@ -540,3 +576,36 @@ fn genesis_funding_works() { assert_eq!(Treasury::pot(), initial_funding - Balances::minimum_balance()); }); } + +#[test] +fn report_awesome_and_tip_works_second_instance() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&Treasury::account_id(), 101); + Balances::make_free_balance_be(&Treasury1::account_id(), 201); + assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); + assert_eq!(Balances::free_balance(&Treasury1::account_id()), 201); + + assert_ok!(Tips1::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + // duplicate report in tips1 reports don't count. + assert_noop!( + Tips1::report_awesome(Origin::signed(1), b"awesome.dot".to_vec(), 3), + Error::::AlreadyKnown + ); + // but tips is separate + assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + + let h = tip_hash(); + assert_ok!(Tips1::tip(Origin::signed(10), h.clone(), 10)); + assert_ok!(Tips1::tip(Origin::signed(11), h.clone(), 10)); + assert_ok!(Tips1::tip(Origin::signed(12), h.clone(), 10)); + assert_noop!(Tips1::tip(Origin::signed(9), h.clone(), 10), BadOrigin); + + System::set_block_number(2); + + assert_ok!(Tips1::close_tip(Origin::signed(100), h.into())); + // Treasury 1 unchanged + assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); + // Treasury 2 gave the funds + assert_eq!(Balances::free_balance(&Treasury1::account_id()), 191); + }); +} From 622f532e605270c9d4f932aea666073e409e02f9 Mon Sep 17 00:00:00 2001 From: Alexander Gryaznov Date: Thu, 23 Jun 2022 15:10:35 +0300 Subject: [PATCH 0945/1472] [contracts] Implement transparent hashing for contract storage (#11501) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * save * builds and old tests pass save: temporary value dropped while borrowed save: finally builds test updated but still fails * type names enhanced * VarSizedKey bounded to new Config param * improved wasm runtime updated funcs * unstable-interface tests fixed * benchmarks fixed * Apply suggestions from code review Co-authored-by: Alexander Theißen * fixes on feedback * fixes on feedback applied + make it build * benchmarks build but fail (old) * "Original code too large" * seal_clear_storage bench fixed (code size workaround hack removal tbd) * bench_seal_clear_storage pass * bench_seal_take_storage ... ok * added new seal_set_storage + updated benchmarks * added new seal_get_storage + updated benchmarks * added new seal_contains_storage + updated benchmarks * added tests for _transparent exec functions * wasm test for clear_storage * wasm test for take_storage * wasm test for new set_storage * wasm test for new get_storage * wasm test for new contains_storage * CI fix * ci fix * ci fix * ci fix * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * fixes according to the review feedback * tests & benchmarks fixed * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * refactoring * fix to runtime api * ci fix * ctx.get_storage() factored out * ctx.contains_storage() factored out * number of batches reduced for transparent hashing storage benchmarks * contracts RPC & pallet::get_storage to use transparent hashing * node and rpc updated to use get_storage with VarSizedKey * refactored (more concize) * refactored contains_storage (DRYed) * refactored contains_storage (DRYed) * fix rpc * fmt fix * more fixes in rpc * rollback `Pallet:get_storage` to Vec and rpc and node parts related to it * added `KeyDecodingFailed` error * Revert weird "fmt fix" This reverts commit c582cfff4b5cb2c9929fd5e3b45519bb24aeb657. * node-executor basic test update * fix node-executor basic test * benchmarks fix * more benchmarks fix * FixedSizedKey is hidden from pub, VarSizedKey is exported as StorageKey * ci fix * set_storage benchmark fix * ci fix * ci fix * comments improved * new error code to rpc: KEY_DECODING_FAILED * Put `rusty-cachier` before PR merge into `master` for `cargo-check-benches` job * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * minor optimization Co-authored-by: Alexander Theißen Co-authored-by: Parity Bot Co-authored-by: Vladimir Istyufeev Co-authored-by: command-bot <> --- bin/node/executor/tests/basic.rs | 6 +- bin/node/runtime/src/lib.rs | 3 +- frame/contracts/common/src/lib.rs | 2 + frame/contracts/rpc/runtime-api/src/lib.rs | 2 +- frame/contracts/rpc/src/lib.rs | 15 +- frame/contracts/src/benchmarking/mod.rs | 245 +-- frame/contracts/src/exec.rs | 408 ++++- frame/contracts/src/lib.rs | 21 +- frame/contracts/src/storage.rs | 16 +- frame/contracts/src/tests.rs | 23 +- frame/contracts/src/wasm/mod.rs | 433 +++++- frame/contracts/src/wasm/runtime.rs | 220 ++- frame/contracts/src/weights.rs | 1644 +++++++++++--------- 13 files changed, 2040 insertions(+), 998 deletions(-) diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index de2aa6c18369d..31a9bd0a90496 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -764,7 +764,11 @@ fn deploying_wasm_contract_should_work() { t.execute_with(|| { // Verify that the contract does exist by querying some of its storage items // It does not matter that the storage item itself does not exist. - assert!(&pallet_contracts::Pallet::::get_storage(addr, Default::default()).is_ok()); + assert!(&pallet_contracts::Pallet::::get_storage( + addr, + pallet_contracts::StorageKey::::default().to_vec() + ) + .is_ok()); }); } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 54742cd91c430..2d5981339fab3 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1151,6 +1151,7 @@ impl pallet_contracts::Config for Runtime { type ContractAccessWeight = pallet_contracts::DefaultContractAccessWeight; type MaxCodeLen = ConstU32<{ 128 * 1024 }>; type RelaxedMaxCodeLen = ConstU32<{ 256 * 1024 }>; + type MaxStorageKeyLen = ConstU32<128>; } impl pallet_sudo::Config for Runtime { @@ -1936,7 +1937,7 @@ impl_runtime_apis! { fn get_storage( address: AccountId, - key: [u8; 32], + key: Vec, ) -> pallet_contracts_primitives::GetStorageResult { Contracts::get_storage(address, key) } diff --git a/frame/contracts/common/src/lib.rs b/frame/contracts/common/src/lib.rs index 49f91f6769290..f810725afcd36 100644 --- a/frame/contracts/common/src/lib.rs +++ b/frame/contracts/common/src/lib.rs @@ -106,6 +106,8 @@ pub type GetStorageResult = Result>, ContractAccessError>; pub enum ContractAccessError { /// The given address doesn't point to a contract. DoesntExist, + /// Storage key cannot be decoded from the provided input data. + KeyDecodingFailed, } bitflags! { diff --git a/frame/contracts/rpc/runtime-api/src/lib.rs b/frame/contracts/rpc/runtime-api/src/lib.rs index 59622a21a6593..9765b37057c7b 100644 --- a/frame/contracts/rpc/runtime-api/src/lib.rs +++ b/frame/contracts/rpc/runtime-api/src/lib.rs @@ -79,7 +79,7 @@ sp_api::decl_runtime_apis! { /// doesn't exist, or doesn't have a contract then `Err` is returned. fn get_storage( address: AccountId, - key: [u8; 32], + key: Vec, ) -> GetStorageResult; } } diff --git a/frame/contracts/rpc/src/lib.rs b/frame/contracts/rpc/src/lib.rs index 77ae3f3ed35e3..0df8f90237ed3 100644 --- a/frame/contracts/rpc/src/lib.rs +++ b/frame/contracts/rpc/src/lib.rs @@ -33,7 +33,7 @@ use pallet_contracts_primitives::{ use serde::{Deserialize, Serialize}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; -use sp_core::{Bytes, H256}; +use sp_core::Bytes; use sp_rpc::number::NumberOrHex; use sp_runtime::{ generic::BlockId, @@ -44,6 +44,7 @@ pub use pallet_contracts_rpc_runtime_api::ContractsApi as ContractsRuntimeApi; const RUNTIME_ERROR: i32 = 1; const CONTRACT_DOESNT_EXIST: i32 = 2; +const KEY_DECODING_FAILED: i32 = 3; pub type Weight = u64; @@ -74,6 +75,12 @@ impl From for JsonRpseeError { None::<()>, )) .into(), + KeyDecodingFailed => CallError::Custom(ErrorObject::owned( + KEY_DECODING_FAILED, + "Failed to decode the specified storage key.", + None::<()>, + )) + .into(), } } } @@ -167,7 +174,7 @@ where fn get_storage( &self, address: AccountId, - key: H256, + key: Bytes, at: Option, ) -> RpcResult>; } @@ -292,13 +299,13 @@ where fn get_storage( &self, address: AccountId, - key: H256, + key: Bytes, at: Option<::Hash>, ) -> RpcResult> { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); let result = api - .get_storage(&at, address, key.into()) + .get_storage(&at, address, key.to_vec()) .map_err(runtime_error_into_rpc_err)? .map_err(ContractAccessError)? .map(Bytes); diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 8f17cacff328d..bea469bd0f5a9 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -30,7 +30,7 @@ use self::{ sandbox::Sandbox, }; use crate::{ - exec::{AccountIdOf, StorageKey}, + exec::{AccountIdOf, FixSizedKey, VarSizedKey}, schedule::{API_BENCHMARK_BATCH_SIZE, INSTR_BENCHMARK_BATCH_SIZE}, storage::Storage, wasm::CallFlags, @@ -132,11 +132,17 @@ where } /// Store the supplied storage items into this contracts storage. - fn store(&self, items: &Vec<(StorageKey, Vec)>) -> Result<(), &'static str> { + fn store(&self, items: &Vec<(FixSizedKey, Vec)>) -> Result<(), &'static str> { let info = self.info()?; for item in items { - Storage::::write(&info.trie_id, &item.0, Some(item.1.clone()), None, false) - .map_err(|_| "Failed to write storage to restoration dest")?; + Storage::::write( + &info.trie_id, + &item.0 as &FixSizedKey, + Some(item.1.clone()), + None, + false, + ) + .map_err(|_| "Failed to write storage to restoration dest")?; } >::insert(&self.account_id, info); Ok(()) @@ -896,33 +902,37 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. - // The contract is a bit more complex because I needs to use different keys in order + // The contract is a bit more complex because it needs to use different keys in order // to generate unique storage accesses. However, it is still dominated by the storage - // accesses. + // accesses. We store all the keys that we are about to write at beforehand + // because re-writing at an existing key is always more expensive than writing + // it at a virgin key. #[skip_meta] seal_set_storage { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_BATCHES/2; + let max_key_len = T::MaxStorageKeyLen::get(); let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); - let key_bytes = keys.iter().flatten().cloned().collect::>(); + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); + let keys_bytes = keys.iter().flatten().cloned().collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal1", + module: "__unstable__", name: "seal_set_storage", - params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ DataSegment { offset: 0, - value: key_bytes, + value: keys_bytes, }, ], call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), // key_ptr + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::I32Const(0)), // value_ptr Regular(Instruction::I32Const(0)), // value_len Regular(Instruction::Call(0)), @@ -935,7 +945,7 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -947,18 +957,19 @@ benchmarks! { #[skip_meta] seal_set_storage_per_new_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 1024; - let keys = (0 .. API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + let max_key_len = T::MaxStorageKeyLen::get(); + let keys = (0 .. n * API_BENCHMARK_BATCH_SIZE) + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal1", + module: "__unstable__", name: "seal_set_storage", - params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ @@ -968,9 +979,10 @@ benchmarks! { }, ], call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), // key_ptr + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::I32Const(0)), // value_ptr - Regular(Instruction::I32Const((n * 1024) as i32)), // value_len + Regular(Instruction::I32Const((n * 2048) as i32)), // value_len increments by 2kb up to max payload_len Regular(Instruction::Call(0)), Regular(Instruction::Drop), ])), @@ -981,7 +993,7 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -993,18 +1005,19 @@ benchmarks! { #[skip_meta] seal_set_storage_per_old_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 1024; - let keys = (0 .. API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + let max_key_len = T::MaxStorageKeyLen::get(); + let keys = (0 .. n * API_BENCHMARK_BATCH_SIZE) + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal1", + module: "__unstable__", name: "seal_set_storage", - params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ @@ -1014,9 +1027,10 @@ benchmarks! { }, ], call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), // key_ptr + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::I32Const(0)), // value_ptr - Regular(Instruction::I32Const(0)), // value_len + Regular(Instruction::I32Const(0)), // value_len is 0 as testing vs pre-existing value len Regular(Instruction::Call(0)), Regular(Instruction::Drop), ])), @@ -1027,8 +1041,8 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![42u8; (n * 1024) as usize]), + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + Some(vec![42u8; (n * 2048) as usize]), // value_len increments by 2kb up to max payload_len None, false, ) @@ -1037,23 +1051,25 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - // Similar to seal_set_storage. However, we store all the keys that we are about to + // Similar to seal_set_storage. We store all the keys that we are about to // delete beforehand in order to prevent any optimizations that could occur when - // deleting a non existing key. + // deleting a non existing key. We generate keys of a maximum length, and have to + // reduce batch size in order to make resulting contract code size less than MaxCodeLen. #[skip_meta] seal_clear_storage { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_BATCHES/2; + let max_key_len = T::MaxStorageKeyLen::get(); let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", name: "seal_clear_storage", - params: vec![ValueType::I32], + params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ @@ -1063,7 +1079,8 @@ benchmarks! { }, ], call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::Call(0)), Regular(Instruction::Drop), ])), @@ -1074,7 +1091,7 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -1087,18 +1104,19 @@ benchmarks! { #[skip_meta] seal_clear_storage_per_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 1024; - let keys = (0 .. API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + let max_key_len = T::MaxStorageKeyLen::get(); + let keys = (0 .. n * API_BENCHMARK_BATCH_SIZE) + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", name: "seal_clear_storage", - params: vec![ValueType::I32], + params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ @@ -1108,7 +1126,8 @@ benchmarks! { }, ], call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), // key_ptr + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::Call(0)), Regular(Instruction::Drop), ])), @@ -1119,8 +1138,8 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![42u8; (n * 1024) as usize]), + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + Some(vec![42u8; (n * 2048) as usize]), // value_len increments by 2kb up to max payload_len None, false, ) @@ -1132,19 +1151,20 @@ benchmarks! { // We make sure that all storage accesses are to unique keys. #[skip_meta] seal_get_storage { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_BATCHES/2; + let max_key_len = T::MaxStorageKeyLen::get(); let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", + module: "__unstable__", name: "seal_get_storage", - params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ @@ -1158,7 +1178,8 @@ benchmarks! { }, ], call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), // key_ptr + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr Regular(Instruction::Call(0)), @@ -1171,7 +1192,7 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -1184,19 +1205,20 @@ benchmarks! { #[skip_meta] seal_get_storage_per_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 1024; - let keys = (0 .. API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + let max_key_len = T::MaxStorageKeyLen::get(); + let keys = (0 .. n * API_BENCHMARK_BATCH_SIZE) + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", + module: "__unstable__", name: "seal_get_storage", - params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ @@ -1210,7 +1232,8 @@ benchmarks! { }, ], call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), // key_ptr + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr Regular(Instruction::Call(0)), @@ -1223,8 +1246,8 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![42u8; (n * 1024) as usize]), + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + Some(vec![42u8; (n * 2048) as usize]), // value_len increments by 2kb up to max payload_len None, false, ) @@ -1237,19 +1260,20 @@ benchmarks! { // We make sure that all storage accesses are to unique keys. #[skip_meta] seal_contains_storage { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_BATCHES/2; + let max_key_len = T::MaxStorageKeyLen::get(); let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", + module: "__unstable__", name: "seal_contains_storage", - params: vec![ValueType::I32], + params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ @@ -1259,7 +1283,8 @@ benchmarks! { }, ], call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), // key_ptr + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::Call(0)), Regular(Instruction::Drop), ])), @@ -1270,7 +1295,7 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -1283,18 +1308,19 @@ benchmarks! { #[skip_meta] seal_contains_storage_per_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 1024; - let keys = (0 .. API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + let max_key_len = T::MaxStorageKeyLen::get(); + let keys = (0 .. n * API_BENCHMARK_BATCH_SIZE) + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", + module: "__unstable__", name: "seal_contains_storage", - params: vec![ValueType::I32], + params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ @@ -1304,7 +1330,8 @@ benchmarks! { }, ], call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), // key_ptr + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::Call(0)), Regular(Instruction::Drop), ])), @@ -1315,8 +1342,8 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![42u8; (n * 1024) as usize]), + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + Some(vec![42u8; (n * 2048) as usize]), // value_len increments by 2kb up to max payload_len None, false, ) @@ -1328,11 +1355,12 @@ benchmarks! { #[skip_meta] seal_take_storage { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_BATCHES/2; + let max_key_len = T::MaxStorageKeyLen::get(); let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { @@ -1340,7 +1368,7 @@ benchmarks! { imported_functions: vec![ImportedFunction { module: "__unstable__", name: "seal_take_storage", - params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ @@ -1354,7 +1382,8 @@ benchmarks! { }, ], call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), // key_ptr + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr Regular(Instruction::Call(0)), @@ -1367,7 +1396,7 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -1380,11 +1409,12 @@ benchmarks! { #[skip_meta] seal_take_storage_per_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 1024; - let keys = (0 .. API_BENCHMARK_BATCH_SIZE) - .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec()) - .collect::>(); - let key_len = keys.get(0).map(|i| i.len() as u32).unwrap_or(0); + let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + let max_key_len = T::MaxStorageKeyLen::get(); + let keys = (0 .. n * API_BENCHMARK_BATCH_SIZE) + .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { @@ -1392,7 +1422,7 @@ benchmarks! { imported_functions: vec![ImportedFunction { module: "__unstable__", name: "seal_take_storage", - params: vec![ValueType::I32, ValueType::I32, ValueType::I32], + params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], data_segments: vec![ @@ -1406,7 +1436,8 @@ benchmarks! { }, ], call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, key_len as u32), // key_ptr + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr Regular(Instruction::Call(0)), @@ -1419,8 +1450,8 @@ benchmarks! { for key in keys { Storage::::write( &info.trie_id, - key.as_slice().try_into().map_err(|e| "Key has wrong length")?, - Some(vec![42u8; (n * 1024) as usize]), + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + Some(vec![42u8; (n * 2048) as usize]), // value_len increments by 2kb up to max payload_len None, false, ) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index e3ff4788791a5..ec7e1e9335182 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -27,12 +27,13 @@ use frame_support::{ storage::{with_transaction, TransactionOutcome}, traits::{Contains, Currency, ExistenceRequirement, OriginTrait, Randomness, Time}, weights::Weight, + Blake2_128Concat, BoundedVec, StorageHasher, }; use frame_system::RawOrigin; use pallet_contracts_primitives::ExecReturnValue; use smallvec::{Array, SmallVec}; use sp_core::{crypto::UncheckedFrom, ecdsa::Public as ECDSAPublic}; -use sp_io::crypto::secp256k1_ecdsa_recover_compressed; +use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; use sp_runtime::traits::Convert; use sp_std::{marker::PhantomData, mem, prelude::*}; @@ -40,12 +41,40 @@ pub type AccountIdOf = ::AccountId; pub type MomentOf = <::Time as Time>::Moment; pub type SeedOf = ::Hash; pub type BlockNumberOf = ::BlockNumber; -pub type StorageKey = [u8; 32]; pub type ExecResult = Result; /// A type that represents a topic of an event. At the moment a hash is used. pub type TopicOf = ::Hash; +/// Type for fix sized storage key. +pub type FixSizedKey = [u8; 32]; + +/// Type for variable sized storage key. Used for transparent hashing. +pub type VarSizedKey = BoundedVec::MaxStorageKeyLen>; + +/// Trait for hashing storage keys. +pub trait StorageKey +where + T: Config, +{ + fn hash(&self) -> Vec; +} + +impl StorageKey for FixSizedKey { + fn hash(&self) -> Vec { + blake2_256(self.as_slice()).to_vec() + } +} + +impl StorageKey for VarSizedKey +where + T: Config, +{ + fn hash(&self) -> Vec { + Blake2_128Concat::hash(self.as_slice()) + } +} + /// Origin of the error. /// /// Call or instantiate both called into other contracts and pass through errors happening @@ -140,19 +169,44 @@ pub trait Ext: sealing::Sealed { /// /// Returns `None` if the `key` wasn't previously set by `set_storage` or /// was deleted. - fn get_storage(&mut self, key: &StorageKey) -> Option>; + fn get_storage(&mut self, key: &FixSizedKey) -> Option>; + + /// This is a variation of `get_storage()` to be used with transparent hashing. + /// These two will be merged into a single function after some refactoring is done. + /// Returns the storage entry of the executing account by the given `key`. + /// + /// Returns `None` if the `key` wasn't previously set by `set_storage` or + /// was deleted. + fn get_storage_transparent(&mut self, key: &VarSizedKey) -> Option>; /// Returns `Some(len)` (in bytes) if a storage item exists at `key`. /// /// Returns `None` if the `key` wasn't previously set by `set_storage` or /// was deleted. - fn get_storage_size(&mut self, key: &StorageKey) -> Option; + fn get_storage_size(&mut self, key: &FixSizedKey) -> Option; + + /// This is the variation of `get_storage_size()` to be used with transparent hashing. + /// These two will be merged into a single function after some refactoring is done. + /// Returns `Some(len)` (in bytes) if a storage item exists at `key`. + /// + /// Returns `None` if the `key` wasn't previously set by `set_storage` or + /// was deleted. + fn get_storage_size_transparent(&mut self, key: &VarSizedKey) -> Option; /// Sets the storage entry by the given key to the specified value. If `value` is `None` then /// the storage entry is deleted. fn set_storage( &mut self, - key: StorageKey, + key: &FixSizedKey, + value: Option>, + take_old: bool, + ) -> Result; + + /// This is the variation of `set_storage()` to be used with transparent hashing. + /// These two will be merged into a single function after some refactoring is done. + fn set_storage_transparent( + &mut self, + key: &VarSizedKey, value: Option>, take_old: bool, ) -> Result; @@ -1085,24 +1139,48 @@ where Self::transfer(ExistenceRequirement::KeepAlive, &self.top_frame().account_id, to, value) } - fn get_storage(&mut self, key: &StorageKey) -> Option> { + fn get_storage(&mut self, key: &FixSizedKey) -> Option> { Storage::::read(&self.top_frame_mut().contract_info().trie_id, key) } - fn get_storage_size(&mut self, key: &StorageKey) -> Option { + fn get_storage_transparent(&mut self, key: &VarSizedKey) -> Option> { + Storage::::read(&self.top_frame_mut().contract_info().trie_id, key) + } + + fn get_storage_size(&mut self, key: &FixSizedKey) -> Option { + Storage::::size(&self.top_frame_mut().contract_info().trie_id, key) + } + + fn get_storage_size_transparent(&mut self, key: &VarSizedKey) -> Option { Storage::::size(&self.top_frame_mut().contract_info().trie_id, key) } fn set_storage( &mut self, - key: StorageKey, + key: &FixSizedKey, value: Option>, take_old: bool, ) -> Result { let frame = self.top_frame_mut(); Storage::::write( &frame.contract_info.get(&frame.account_id).trie_id, - &key, + key, + value, + Some(&mut frame.nested_storage), + take_old, + ) + } + + fn set_storage_transparent( + &mut self, + key: &VarSizedKey, + value: Option>, + take_old: bool, + ) -> Result { + let frame = self.top_frame_mut(); + Storage::::write( + &frame.contract_info.get(&frame.account_id).trie_id, + key, value, Some(&mut frame.nested_storage), take_old, @@ -2635,35 +2713,35 @@ mod tests { let code_hash = MockLoader::insert(Call, |ctx, _| { // Write assert_eq!( - ctx.ext.set_storage([1; 32], Some(vec![1, 2, 3]), false), + ctx.ext.set_storage(&[1; 32], Some(vec![1, 2, 3]), false), Ok(WriteOutcome::New) ); assert_eq!( - ctx.ext.set_storage([2; 32], Some(vec![4, 5, 6]), true), + ctx.ext.set_storage(&[2; 32], Some(vec![4, 5, 6]), true), Ok(WriteOutcome::New) ); - assert_eq!(ctx.ext.set_storage([3; 32], None, false), Ok(WriteOutcome::New)); - assert_eq!(ctx.ext.set_storage([4; 32], None, true), Ok(WriteOutcome::New)); - assert_eq!(ctx.ext.set_storage([5; 32], Some(vec![]), false), Ok(WriteOutcome::New)); - assert_eq!(ctx.ext.set_storage([6; 32], Some(vec![]), true), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage(&[3; 32], None, false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage(&[4; 32], None, true), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage(&[5; 32], Some(vec![]), false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage(&[6; 32], Some(vec![]), true), Ok(WriteOutcome::New)); // Overwrite assert_eq!( - ctx.ext.set_storage([1; 32], Some(vec![42]), false), + ctx.ext.set_storage(&[1; 32], Some(vec![42]), false), Ok(WriteOutcome::Overwritten(3)) ); assert_eq!( - ctx.ext.set_storage([2; 32], Some(vec![48]), true), + ctx.ext.set_storage(&[2; 32], Some(vec![48]), true), Ok(WriteOutcome::Taken(vec![4, 5, 6])) ); - assert_eq!(ctx.ext.set_storage([3; 32], None, false), Ok(WriteOutcome::New)); - assert_eq!(ctx.ext.set_storage([4; 32], None, true), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage(&[3; 32], None, false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage(&[4; 32], None, true), Ok(WriteOutcome::New)); assert_eq!( - ctx.ext.set_storage([5; 32], Some(vec![]), false), + ctx.ext.set_storage(&[5; 32], Some(vec![]), false), Ok(WriteOutcome::Overwritten(0)) ); assert_eq!( - ctx.ext.set_storage([6; 32], Some(vec![]), true), + ctx.ext.set_storage(&[6; 32], Some(vec![]), true), Ok(WriteOutcome::Taken(vec![])) ); @@ -2690,14 +2768,175 @@ mod tests { }); } + #[test] + fn set_storage_transparent_works() { + let code_hash = MockLoader::insert(Call, |ctx, _| { + // Write + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([1; 64].to_vec()).unwrap(), + Some(vec![1, 2, 3]), + false + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([2; 19].to_vec()).unwrap(), + Some(vec![4, 5, 6]), + true + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([3; 19].to_vec()).unwrap(), + None, + false + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([4; 64].to_vec()).unwrap(), + None, + true + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([5; 30].to_vec()).unwrap(), + Some(vec![]), + false + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([6; 128].to_vec()).unwrap(), + Some(vec![]), + true + ), + Ok(WriteOutcome::New) + ); + + // Overwrite + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([1; 64].to_vec()).unwrap(), + Some(vec![42, 43, 44]), + false + ), + Ok(WriteOutcome::Overwritten(3)) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([2; 19].to_vec()).unwrap(), + Some(vec![48]), + true + ), + Ok(WriteOutcome::Taken(vec![4, 5, 6])) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([3; 19].to_vec()).unwrap(), + None, + false + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([4; 64].to_vec()).unwrap(), + None, + true + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([5; 30].to_vec()).unwrap(), + Some(vec![]), + false + ), + Ok(WriteOutcome::Overwritten(0)) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([6; 128].to_vec()).unwrap(), + Some(vec![]), + true + ), + Ok(WriteOutcome::Taken(vec![])) + ); + + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); + let schedule = ::Schedule::get(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + set_balance(&ALICE, min_balance * 1000); + place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap(); + assert_ok!(MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + None, + )); + }); + } + + #[test] + fn get_storage_works() { + let code_hash = MockLoader::insert(Call, |ctx, _| { + assert_eq!( + ctx.ext.set_storage(&[1; 32], Some(vec![1, 2, 3]), false), + Ok(WriteOutcome::New) + ); + assert_eq!(ctx.ext.set_storage(&[2; 32], Some(vec![]), false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.get_storage(&[1; 32]), Some(vec![1, 2, 3])); + assert_eq!(ctx.ext.get_storage(&[2; 32]), Some(vec![])); + assert_eq!(ctx.ext.get_storage(&[3; 32]), None); + + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); + let schedule = ::Schedule::get(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + set_balance(&ALICE, min_balance * 1000); + place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap(); + assert_ok!(MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + None, + )); + }); + } + #[test] fn get_storage_size_works() { let code_hash = MockLoader::insert(Call, |ctx, _| { assert_eq!( - ctx.ext.set_storage([1; 32], Some(vec![1, 2, 3]), false), + ctx.ext.set_storage(&[1; 32], Some(vec![1, 2, 3]), false), Ok(WriteOutcome::New) ); - assert_eq!(ctx.ext.set_storage([2; 32], Some(vec![]), false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage(&[2; 32], Some(vec![]), false), Ok(WriteOutcome::New)); assert_eq!(ctx.ext.get_storage_size(&[1; 32]), Some(3)); assert_eq!(ctx.ext.get_storage_size(&[2; 32]), Some(0)); assert_eq!(ctx.ext.get_storage_size(&[3; 32]), None); @@ -2724,6 +2963,129 @@ mod tests { )); }); } + + #[test] + fn get_storage_transparent_works() { + let code_hash = MockLoader::insert(Call, |ctx, _| { + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([1; 19].to_vec()).unwrap(), + Some(vec![1, 2, 3]), + false + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([2; 16].to_vec()).unwrap(), + Some(vec![]), + false + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.get_storage_transparent( + &VarSizedKey::::try_from([1; 19].to_vec()).unwrap() + ), + Some(vec![1, 2, 3]) + ); + assert_eq!( + ctx.ext.get_storage_transparent( + &VarSizedKey::::try_from([2; 16].to_vec()).unwrap() + ), + Some(vec![]) + ); + assert_eq!( + ctx.ext.get_storage_transparent( + &VarSizedKey::::try_from([3; 8].to_vec()).unwrap() + ), + None + ); + + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); + let schedule = ::Schedule::get(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + set_balance(&ALICE, min_balance * 1000); + place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap(); + assert_ok!(MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + None, + )); + }); + } + + #[test] + fn get_storage_size_transparent_works() { + let code_hash = MockLoader::insert(Call, |ctx, _| { + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([1; 19].to_vec()).unwrap(), + Some(vec![1, 2, 3]), + false + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from([2; 16].to_vec()).unwrap(), + Some(vec![]), + false + ), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.get_storage_size_transparent( + &VarSizedKey::::try_from([1; 19].to_vec()).unwrap() + ), + Some(3) + ); + assert_eq!( + ctx.ext.get_storage_size_transparent( + &VarSizedKey::::try_from([2; 16].to_vec()).unwrap() + ), + Some(0) + ); + assert_eq!( + ctx.ext.get_storage_size_transparent( + &VarSizedKey::::try_from([3; 8].to_vec()).unwrap() + ), + None + ); + + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); + let schedule = ::Schedule::get(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + set_balance(&ALICE, min_balance * 1000); + place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap(); + assert_ok!(MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + None, + )); + }); + } + #[test] fn ecdsa_to_eth_address_returns_proper_value() { let bob_ch = MockLoader::insert(Call, |ctx, _| { diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 1011e264eb930..60b30ffa25005 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -98,11 +98,6 @@ pub mod weights; #[cfg(test)] mod tests; -pub use crate::{ - exec::Frame, - pallet::*, - schedule::{HostFnWeights, InstructionWeights, Limits, Schedule}, -}; use crate::{ exec::{AccountIdOf, ExecError, Executable, Stack as ExecStack}, gas::GasMeter, @@ -129,6 +124,12 @@ use sp_core::{crypto::UncheckedFrom, Bytes}; use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup}; use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; +pub use crate::{ + exec::{Frame, VarSizedKey as StorageKey}, + pallet::*, + schedule::{HostFnWeights, InstructionWeights, Limits, Schedule}, +}; + type CodeHash = ::Hash; type TrieId = BoundedVec>; type BalanceOf = @@ -372,6 +373,9 @@ pub mod pallet { /// new instrumentation increases the size beyond the limit it would make that contract /// inaccessible until rectified by another runtime upgrade. type RelaxedMaxCodeLen: Get; + + /// The maximum allowable length in bytes for storage keys. + type MaxStorageKeyLen: Get; } #[pallet::hooks] @@ -942,11 +946,14 @@ where } /// Query storage of a specified contract under a specified key. - pub fn get_storage(address: T::AccountId, key: [u8; 32]) -> GetStorageResult { + pub fn get_storage(address: T::AccountId, key: Vec) -> GetStorageResult { let contract_info = ContractInfoOf::::get(&address).ok_or(ContractAccessError::DoesntExist)?; - let maybe_value = Storage::::read(&contract_info.trie_id, &key); + let maybe_value = Storage::::read( + &contract_info.trie_id, + &StorageKey::::try_from(key).map_err(|_| ContractAccessError::KeyDecodingFailed)?, + ); Ok(maybe_value) } diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index e73eb8d3bd55e..01c809da8675e 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -32,7 +32,7 @@ use frame_support::{ }; use scale_info::TypeInfo; use sp_core::crypto::UncheckedFrom; -use sp_io::{hashing::blake2_256, KillStorageResult}; +use sp_io::KillStorageResult; use sp_runtime::{ traits::{Hash, Zero}, RuntimeDebug, @@ -124,16 +124,16 @@ where /// /// The read is performed from the `trie_id` only. The `address` is not necessary. If the /// contract doesn't store under the given `key` `None` is returned. - pub fn read(trie_id: &TrieId, key: &StorageKey) -> Option> { - child::get_raw(&child_trie_info(trie_id), &blake2_256(key)) + pub fn read>(trie_id: &TrieId, key: &K) -> Option> { + child::get_raw(&child_trie_info(trie_id), key.hash().as_slice()) } /// Returns `Some(len)` (in bytes) if a storage item exists at `key`. /// /// Returns `None` if the `key` wasn't previously set by `set_storage` or /// was deleted. - pub fn size(trie_id: &TrieId, key: &StorageKey) -> Option { - child::len(&child_trie_info(trie_id), &blake2_256(key)) + pub fn size>(trie_id: &TrieId, key: &K) -> Option { + child::len(&child_trie_info(trie_id), key.hash().as_slice()) } /// Update a storage entry into a contract's kv storage. @@ -143,15 +143,15 @@ where /// /// This function also records how much storage was created or removed if a `storage_meter` /// is supplied. It should only be absent for testing or benchmarking code. - pub fn write( + pub fn write>( trie_id: &TrieId, - key: &StorageKey, + key: &K, new_value: Option>, storage_meter: Option<&mut meter::NestedMeter>, take: bool, ) -> Result { - let hashed_key = blake2_256(key); let child_trie_info = &child_trie_info(trie_id); + let hashed_key = key.hash(); let (old_len, old_value) = if take { let val = child::get_raw(child_trie_info, &hashed_key); (val.as_ref().map(|v| v.len() as u32), val) diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index d4a5434cd5a46..bbac18142a658 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -20,7 +20,7 @@ use crate::{ ChainExtension, Environment, Ext, InitState, Result as ExtensionResult, RetVal, ReturnFlags, SysConfig, UncheckedFrom, }, - exec::Frame, + exec::{FixSizedKey, Frame}, storage::Storage, wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, @@ -291,6 +291,7 @@ impl Config for Test { type ContractAccessWeight = DefaultContractAccessWeight; type MaxCodeLen = ConstU32<{ 128 * 1024 }>; type RelaxedMaxCodeLen = ConstU32<{ 256 * 1024 }>; + type MaxStorageKeyLen = ConstU32<128>; } pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); @@ -1723,8 +1724,14 @@ fn lazy_removal_partial_remove_works() { // Put value into the contracts child trie for val in &vals { - Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None, false) - .unwrap(); + Storage::::write( + &info.trie_id, + &val.0 as &FixSizedKey, + Some(val.2.clone()), + None, + false, + ) + .unwrap(); } >::insert(&addr, info.clone()); @@ -1903,8 +1910,14 @@ fn lazy_removal_does_not_use_all_weight() { // Put value into the contracts child trie for val in &vals { - Storage::::write(&info.trie_id, &val.0, Some(val.2.clone()), None, false) - .unwrap(); + Storage::::write( + &info.trie_id, + &val.0 as &FixSizedKey, + Some(val.2.clone()), + None, + false, + ) + .unwrap(); } >::insert(&addr, info.clone()); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index c385b5d2f7cc2..3dd5da187b258 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -275,7 +275,8 @@ mod tests { use super::*; use crate::{ exec::{ - AccountIdOf, BlockNumberOf, ErrorOrigin, ExecError, Executable, Ext, SeedOf, StorageKey, + AccountIdOf, BlockNumberOf, ErrorOrigin, ExecError, Executable, Ext, FixSizedKey, + SeedOf, VarSizedKey, }, gas::GasMeter, storage::WriteOutcome, @@ -330,7 +331,7 @@ mod tests { } pub struct MockExt { - storage: HashMap>, + storage: HashMap, Vec>, instantiates: Vec, terminations: Vec, calls: Vec, @@ -425,19 +426,45 @@ mod tests { self.terminations.push(TerminationEntry { beneficiary: beneficiary.clone() }); Ok(()) } - fn get_storage(&mut self, key: &StorageKey) -> Option> { - self.storage.get(key).cloned() + fn get_storage(&mut self, key: &FixSizedKey) -> Option> { + self.storage.get(&key.to_vec()).cloned() } - fn get_storage_size(&mut self, key: &StorageKey) -> Option { - self.storage.get(key).map(|val| val.len() as u32) + fn get_storage_transparent(&mut self, key: &VarSizedKey) -> Option> { + self.storage.get(&key.to_vec()).cloned() + } + fn get_storage_size(&mut self, key: &FixSizedKey) -> Option { + self.storage.get(&key.to_vec()).map(|val| val.len() as u32) + } + fn get_storage_size_transparent(&mut self, key: &VarSizedKey) -> Option { + self.storage.get(&key.to_vec()).map(|val| val.len() as u32) } fn set_storage( &mut self, - key: StorageKey, + key: &FixSizedKey, value: Option>, take_old: bool, ) -> Result { - let entry = self.storage.entry(key); + let key = key.to_vec(); + let entry = self.storage.entry(key.clone()); + let result = match (entry, take_old) { + (Entry::Vacant(_), _) => WriteOutcome::New, + (Entry::Occupied(entry), false) => + WriteOutcome::Overwritten(entry.remove().len() as u32), + (Entry::Occupied(entry), true) => WriteOutcome::Taken(entry.remove()), + }; + if let Some(value) = value { + self.storage.insert(key, value); + } + Ok(result) + } + fn set_storage_transparent( + &mut self, + key: &VarSizedKey, + value: Option>, + take_old: bool, + ) -> Result { + let key = key.to_vec(); + let entry = self.storage.entry(key.clone()); let result = match (entry, take_old) { (Entry::Vacant(_), _) => WriteOutcome::New, (Entry::Occupied(entry), false) => @@ -836,6 +863,7 @@ mod tests { } #[test] + #[cfg(not(feature = "unstable-interface"))] fn contains_storage_works() { const CODE: &str = r#" (module @@ -844,11 +872,10 @@ mod tests { (import "seal0" "seal_contains_storage" (func $seal_contains_storage (param i32) (result i32))) (import "env" "memory" (memory 1 1)) - ;; [0, 4) size of input buffer (32 byte as we copy the key here) + ;; [0, 4) size of input buffer (32 bytes as we copy the key here) (data (i32.const 0) "\20") ;; [4, 36) input buffer - ;; [36, inf) output buffer (func (export "call") @@ -879,8 +906,8 @@ mod tests { let mut ext = MockExt::default(); - ext.storage.insert([1u8; 32], vec![42u8]); - ext.storage.insert([2u8; 32], vec![]); + ext.storage.insert(vec![1u8; 32], vec![42u8]); + ext.storage.insert(vec![2u8; 32], vec![]); // value does not exist -> sentinel value returned let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); @@ -895,6 +922,84 @@ mod tests { assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0,); } + #[test] + #[cfg(feature = "unstable-interface")] + fn contains_storage_works() { + const CODE: &str = r#" +(module + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "__unstable__" "seal_contains_storage" (func $seal_contains_storage (param i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + + ;; size of input buffer + ;; [0, 4) size of input buffer (128+32 = 160 bytes = 0xA0) + (data (i32.const 0) "\A0") + + ;; [4, 164) input buffer + + (func (export "call") + ;; Receive key + (call $seal_input + (i32.const 4) ;; Where we take input and store it + (i32.const 0) ;; Where we take and store the length of the data + ) + ;; Call seal_clear_storage and save what it returns at 0 + (i32.store (i32.const 0) + (call $seal_contains_storage + (i32.const 8) ;; key_ptr + (i32.load (i32.const 4)) ;; key_len + ) + ) + (call $seal_return + (i32.const 0) ;; flags + (i32.const 0) ;; returned value + (i32.const 4) ;; length of returned value + ) + ) + + (func (export "deploy")) +) +"#; + + let mut ext = MockExt::default(); + ext.set_storage_transparent( + &VarSizedKey::::try_from([1u8; 64].to_vec()).unwrap(), + Some(vec![42u8]), + false, + ) + .unwrap(); + ext.set_storage_transparent( + &VarSizedKey::::try_from([2u8; 19].to_vec()).unwrap(), + Some(vec![]), + false, + ) + .unwrap(); + + //value does not exist (wrong key length) + let input = (63, [1u8; 64]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + // sentinel returned + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + + // value exists + let input = (64, [1u8; 64]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + // true as u32 returned + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1); + // getter does not remove the value from storage + assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]); + + // value exists (test for 0 sized) + let input = (19, [2u8; 19]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + // true as u32 returned + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + // getter does not remove the value from storage + assert_eq!(ext.storage.get(&[2u8; 19].to_vec()).unwrap(), &([] as [u8; 0])); + } + const CODE_INSTANTIATE: &str = r#" (module ;; seal_instantiate( @@ -1204,7 +1309,7 @@ mod tests { #[test] fn get_storage_puts_data_into_buf() { let mut mock_ext = MockExt::default(); - mock_ext.storage.insert([0x11; 32], [0x22; 32].to_vec()); + mock_ext.storage.insert([0x11; 32].to_vec(), [0x22; 32].to_vec()); let output = execute(CODE_GET_STORAGE, vec![], mock_ext).unwrap(); @@ -2176,6 +2281,7 @@ mod tests { } #[test] + #[cfg(not(feature = "unstable-interface"))] fn set_storage_works() { const CODE: &str = r#" (module @@ -2199,7 +2305,7 @@ mod tests { (call $seal_set_storage (i32.const 4) ;; key_ptr (i32.const 36) ;; value_ptr - (i32.sub ;; value_len (input_size - key_size) + (i32.sub ;; value_len (input_size - key_size) (i32.load (i32.const 0)) (i32.const 32) ) @@ -2207,7 +2313,7 @@ mod tests { ) (call $seal_return (i32.const 0) ;; flags - (i32.const 0) ;; returned value + (i32.const 0) ;; pointer to returned value (i32.const 4) ;; length of returned value ) ) @@ -2222,45 +2328,213 @@ mod tests { let input = ([1u8; 32], [42u8, 48]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); - assert_eq!(ext.storage.get(&[1u8; 32]).unwrap(), &[42u8, 48]); + assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[42u8, 48]); // value do exist -> length of old value returned let input = ([1u8; 32], [0u8; 0]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 2); - assert_eq!(ext.storage.get(&[1u8; 32]).unwrap(), &[0u8; 0]); + assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[0u8; 0]); // value do exist -> length of old value returned (test for zero sized val) let input = ([1u8; 32], [99u8]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); - assert_eq!(ext.storage.get(&[1u8; 32]).unwrap(), &[99u8]); + assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[99u8]); } #[test] #[cfg(feature = "unstable-interface")] - fn clear_storage_works() { + fn set_storage_works() { const CODE: &str = r#" (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "__unstable__" "seal_clear_storage" (func $seal_clear_storage (param i32) (result i32))) + (import "__unstable__" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) - ;; 0x1000 = 4k in little endian - ;; size of input buffer + ;; [0, 4) size of input buffer + ;; 4k in little endian (data (i32.const 0) "\00\10") + ;; [4, 4100) input buffer + (func (export "call") - ;; Receive key + ;; Receive (key ++ value_to_write) (call $seal_input (i32.const 4) ;; Pointer to the input buffer - (i32.const 0) ;; Size of the length buffer + (i32.const 0) ;; Size of the input buffer ) ;; Store the passed value to the passed key and store result to memory + (i32.store (i32.const 168) + (call $seal_set_storage + (i32.const 8) ;; key_ptr + (i32.load (i32.const 4)) ;; key_len + (i32.add ;; value_ptr = 8 + key_len + (i32.const 8) + (i32.load (i32.const 4))) + (i32.sub ;; value_len (input_size - (key_len + key_len_len)) + (i32.load (i32.const 0)) + (i32.add + (i32.load (i32.const 4)) + (i32.const 4) + ) + ) + ) + ) + (call $seal_return + (i32.const 0) ;; flags + (i32.const 168) ;; ptr to returned value + (i32.const 4) ;; length of returned value + ) + ) + + (func (export "deploy")) +) +"#; + + let mut ext = MockExt::default(); + + // value did not exist before -> sentinel returned + let input = (32, [1u8; 32], [42u8, 48]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[42u8, 48]); + + // value do exist -> length of old value returned + let input = (32, [1u8; 32], [0u8; 0]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 2); + assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[0u8; 0]); + + // value do exist -> length of old value returned (test for zero sized val) + let input = (32, [1u8; 32], [99u8]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[99u8]); + } + + #[test] + #[cfg(feature = "unstable-interface")] + fn get_storage_works() { + const CODE: &str = r#" +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "__unstable__" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 4) size of input buffer (160 bytes as we copy the key+len here) + (data (i32.const 0) "\A0") + + ;; [4, 8) size of output buffer + ;; 4k in little endian + (data (i32.const 4) "\00\10") + + ;; [8, 168) input buffer + ;; [168, 4264) output buffer + + (func (export "call") + ;; Receive (key ++ value_to_write) + (call $seal_input + (i32.const 8) ;; Pointer to the input buffer + (i32.const 0) ;; Size of the input buffer + ) + ;; Load a storage value and result of this call into the output buffer + (i32.store (i32.const 168) + (call $seal_get_storage + (i32.const 12) ;; key_ptr + (i32.load (i32.const 8)) ;; key_len + (i32.const 172) ;; Pointer to the output buffer + (i32.const 4) ;; Pointer to the size of the buffer + ) + ) + (call $seal_return + (i32.const 0) ;; flags + (i32.const 168) ;; output buffer ptr + (i32.add ;; length: output size + 4 (retval) + (i32.load (i32.const 4)) + (i32.const 4) + ) + ) + ) + + (func (export "deploy")) +) +"#; + + let mut ext = MockExt::default(); + + ext.set_storage_transparent( + &VarSizedKey::::try_from([1u8; 64].to_vec()).unwrap(), + Some(vec![42u8]), + false, + ) + .unwrap(); + + ext.set_storage_transparent( + &VarSizedKey::::try_from([2u8; 19].to_vec()).unwrap(), + Some(vec![]), + false, + ) + .unwrap(); + + // value does not exist + let input = (63, [1u8; 64]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + assert_eq!( + u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + ReturnCode::KeyNotFound as u32 + ); + + // value exists + let input = (64, [1u8; 64]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + assert_eq!( + u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + ReturnCode::Success as u32 + ); + assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]); + assert_eq!(&result.data.0[4..], &[42u8]); + + // value exists (test for 0 sized) + let input = (19, [2u8; 19]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + assert_eq!( + u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + ReturnCode::Success as u32 + ); + assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), Some(&vec![])); + assert_eq!(&result.data.0[4..], &([] as [u8; 0])); + } + + #[test] + #[cfg(feature = "unstable-interface")] + fn clear_storage_works() { + const CODE: &str = r#" +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "__unstable__" "seal_clear_storage" (func $seal_clear_storage (param i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; size of input buffer + ;; [0, 4) size of input buffer (128+32 = 160 bytes = 0xA0) + (data (i32.const 0) "\A0") + + ;; [4, 164) input buffer + + (func (export "call") + ;; Receive key + (call $seal_input + (i32.const 4) ;; Where we take input and store it + (i32.const 0) ;; Where we take and store the length of thedata + ) + ;; Call seal_clear_storage and save what it returns at 0 (i32.store (i32.const 0) (call $seal_clear_storage - (i32.const 4) ;; key_ptr + (i32.const 8) ;; key_ptr + (i32.load (i32.const 4)) ;; key_len ) ) (call $seal_return @@ -2276,23 +2550,48 @@ mod tests { let mut ext = MockExt::default(); - ext.storage.insert([1u8; 32], vec![42u8]); - ext.storage.insert([2u8; 32], vec![]); + ext.set_storage_transparent( + &VarSizedKey::::try_from([1u8; 64].to_vec()).unwrap(), + Some(vec![42u8]), + false, + ) + .unwrap(); + ext.set_storage_transparent( + &VarSizedKey::::try_from([2u8; 19].to_vec()).unwrap(), + Some(vec![]), + false, + ) + .unwrap(); - // value does not exist -> sentinel returned - let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); + // value did not exist + let input = (32, [3u8; 32]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + // sentinel returned assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); - assert_eq!(ext.storage.get(&[3u8; 32]), None); + assert_eq!(ext.storage.get(&[3u8; 32].to_vec()), None); - // value did exist -> length returned - let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); + // value did exist + let input = (64, [1u8; 64]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + // length returned assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1); - assert_eq!(ext.storage.get(&[1u8; 32]), None); + // value cleared + assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None); - // value did exist -> length returned (test for 0 sized) - let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); + //value did not exist (wrong key length) + let input = (63, [1u8; 64]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + // sentinel returned + assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None); + + // value exists + let input = (19, [2u8; 19]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); + // length returned (test for 0 sized) assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); - assert_eq!(ext.storage.get(&[2u8; 32]), None); + // value cleared + assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None); } #[test] @@ -2302,42 +2601,42 @@ mod tests { (module (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "__unstable__" "seal_take_storage" (func $seal_take_storage (param i32 i32 i32) (result i32))) + (import "__unstable__" "seal_take_storage" (func $seal_take_storage (param i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) - ;; [0, 32) size of input buffer (32 byte as we copy the key here) - (data (i32.const 0) "\20") + ;; [0, 4) size of input buffer (160 bytes as we copy the key+len here) + (data (i32.const 0) "\A0") - ;; [32, 64) size of output buffer + ;; [4, 8) size of output buffer ;; 4k in little endian - (data (i32.const 32) "\00\10") - - ;; [64, 96) input buffer + (data (i32.const 4) "\00\10") - ;; [96, inf) output buffer + ;; [8, 168) input buffer + ;; [168, 4264) output buffer (func (export "call") ;; Receive key (call $seal_input - (i32.const 64) ;; Pointer to the input buffer + (i32.const 8) ;; Pointer to the input buffer (i32.const 0) ;; Size of the length buffer ) ;; Load a storage value and result of this call into the output buffer - (i32.store (i32.const 96) + (i32.store (i32.const 168) (call $seal_take_storage - (i32.const 64) ;; The pointer to the storage key to fetch - (i32.const 100) ;; Pointer to the output buffer - (i32.const 32) ;; Pointer to the size of the buffer + (i32.const 12) ;; key_ptr + (i32.load (i32.const 8)) ;; key_len + (i32.const 172) ;; Pointer to the output buffer + (i32.const 4) ;; Pointer to the size of the buffer ) ) ;; Return the contents of the buffer (call $seal_return - (i32.const 0) ;; flags - (i32.const 96) ;; output buffer ptr - (i32.add ;; length: storage size + 4 (retval) - (i32.load (i32.const 32)) + (i32.const 0) ;; flags + (i32.const 168) ;; output buffer ptr + (i32.add ;; length: storage size + 4 (retval) + (i32.load (i32.const 4)) (i32.const 4) ) ) @@ -2349,32 +2648,46 @@ mod tests { let mut ext = MockExt::default(); - ext.storage.insert([1u8; 32], vec![42u8]); - ext.storage.insert([2u8; 32], vec![]); + ext.set_storage_transparent( + &VarSizedKey::::try_from([1u8; 64].to_vec()).unwrap(), + Some(vec![42u8]), + false, + ) + .unwrap(); + + ext.set_storage_transparent( + &VarSizedKey::::try_from([2u8; 19].to_vec()).unwrap(), + Some(vec![]), + false, + ) + .unwrap(); // value does not exist -> error returned - let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); + let input = (63, [1u8; 64]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), ReturnCode::KeyNotFound as u32 ); // value did exist -> value returned - let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); + let input = (64, [1u8; 64]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), ReturnCode::Success as u32 ); - assert_eq!(ext.storage.get(&[1u8; 32]), None); + assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None); assert_eq!(&result.data.0[4..], &[42u8]); // value did exist -> length returned (test for 0 sized) - let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); + let input = (19, [2u8; 19]).encode(); + let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), ReturnCode::Success as u32 ); - assert_eq!(ext.storage.get(&[2u8; 32]), None); + assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None); assert_eq!(&result.data.0[4..], &[0u8; 0]); } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 850794fc9b09e..c1757ba06412a 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -18,15 +18,16 @@ //! Environment definition of the wasm smart-contract runtime. use crate::{ - exec::{ExecError, ExecResult, Ext, StorageKey, TopicOf}, + exec::{ExecError, ExecResult, Ext, FixSizedKey, TopicOf, VarSizedKey}, gas::{ChargedAmount, Token}, schedule::HostFnWeights, wasm::env_def::ConvertibleToWasm, BalanceOf, CodeHash, Config, Error, SENTINEL, }; + use bitflags::bitflags; use codec::{Decode, DecodeAll, Encode, MaxEncodedLen}; -use frame_support::{dispatch::DispatchError, ensure, weights::Weight}; +use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight}; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use sp_core::{crypto::UncheckedFrom, Bytes}; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; @@ -35,6 +36,28 @@ use sp_sandbox::SandboxMemory; use sp_std::prelude::*; use wasm_instrument::parity_wasm::elements::ValueType; +/// Type of a storage key. +#[allow(dead_code)] +enum KeyType { + /// Deprecated fix sized key [0;32]. + Fix, + /// Variable sized key used in transparent hashing, + /// cannot be larger than MaxStorageKeyLen. + Variable(u32), +} + +impl KeyType { + fn len(&self) -> Result { + match self { + KeyType::Fix => Ok(32u32), + KeyType::Variable(len) => { + ensure!(len <= &::MaxStorageKeyLen::get(), Error::::DecodingFailed); + Ok(*len) + }, + } + } +} + /// Every error that can be returned to a contract when it calls any of the host functions. /// /// # Note @@ -695,6 +718,7 @@ where fn set_storage( &mut self, + key_type: KeyType, key_ptr: u32, value_ptr: u32, value_len: u32, @@ -705,10 +729,21 @@ where if value_len > max_size { return Err(Error::::ValueTooLarge.into()) } - let mut key: StorageKey = [0; 32]; - self.read_sandbox_memory_into_buf(key_ptr, &mut key)?; + let key = self.read_sandbox_memory(key_ptr, key_type.len::()?)?; let value = Some(self.read_sandbox_memory(value_ptr, value_len)?); - let write_outcome = self.ext.set_storage(key, value, false)?; + let write_outcome = match key_type { + KeyType::Fix => self.ext.set_storage( + &FixSizedKey::try_from(key).map_err(|_| Error::::DecodingFailed)?, + value, + false, + )?, + KeyType::Variable(_) => self.ext.set_storage_transparent( + &VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, + value, + false, + )?, + }; + self.adjust_gas( charged, RuntimeCosts::SetStorage { new_bytes: value_len, old_bytes: write_outcome.old_len() }, @@ -716,15 +751,70 @@ where Ok(write_outcome.old_len_with_sentinel()) } - fn clear_storage(&mut self, key_ptr: u32) -> Result { + fn clear_storage(&mut self, key_type: KeyType, key_ptr: u32) -> Result { let charged = self.charge_gas(RuntimeCosts::ClearStorage(self.ext.max_value_size()))?; - let mut key: StorageKey = [0; 32]; - self.read_sandbox_memory_into_buf(key_ptr, &mut key)?; - let outcome = self.ext.set_storage(key, None, false)?; + let key = self.read_sandbox_memory(key_ptr, key_type.len::()?)?; + let outcome = match key_type { + KeyType::Fix => self.ext.set_storage( + &FixSizedKey::try_from(key).map_err(|_| Error::::DecodingFailed)?, + None, + false, + )?, + KeyType::Variable(_) => self.ext.set_storage_transparent( + &VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, + None, + false, + )?, + }; + self.adjust_gas(charged, RuntimeCosts::ClearStorage(outcome.old_len())); Ok(outcome.old_len_with_sentinel()) } + fn get_storage( + &mut self, + key_type: KeyType, + key_ptr: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result { + let charged = self.charge_gas(RuntimeCosts::GetStorage(self.ext.max_value_size()))?; + let key = self.read_sandbox_memory(key_ptr, key_type.len::()?)?; + let outcome = match key_type { + KeyType::Fix => self.ext.get_storage( + &FixSizedKey::try_from(key).map_err(|_| Error::::DecodingFailed)?, + ), + KeyType::Variable(_) => self.ext.get_storage_transparent( + &VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, + ), + }; + + if let Some(value) = outcome { + self.adjust_gas(charged, RuntimeCosts::GetStorage(value.len() as u32)); + self.write_sandbox_output(out_ptr, out_len_ptr, &value, false, already_charged)?; + Ok(ReturnCode::Success) + } else { + self.adjust_gas(charged, RuntimeCosts::GetStorage(0)); + Ok(ReturnCode::KeyNotFound) + } + } + + fn contains_storage(&mut self, key_type: KeyType, key_ptr: u32) -> Result { + let charged = self.charge_gas(RuntimeCosts::ContainsStorage(self.ext.max_value_size()))?; + let key = self.read_sandbox_memory(key_ptr, key_type.len::()?)?; + let outcome = match key_type { + KeyType::Fix => self.ext.get_storage_size( + &FixSizedKey::try_from(key).map_err(|_| Error::::DecodingFailed)?, + ), + KeyType::Variable(_) => self.ext.get_storage_size_transparent( + &VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, + ), + }; + + self.adjust_gas(charged, RuntimeCosts::ClearStorage(outcome.unwrap_or(0))); + Ok(outcome.unwrap_or(SENTINEL)) + } + fn call( &mut self, flags: CallFlags, @@ -863,11 +953,14 @@ define_env!(Env, , // Equivalent to the newer version of `seal_set_storage` with the exception of the return // type. Still a valid thing to call when not interested in the return value. [seal0] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) => { - ctx.set_storage(key_ptr, value_ptr, value_len).map(|_| ()) + ctx.set_storage(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) }, // Set the value at the given key in the contract storage. // + // This version is to be used with a fixed sized storage key. For runtimes supporting transparent + // hashing, please use the newer version of this function. + // // The value length must not exceed the maximum defined by the contracts module parameters. // Specifying a `value_len` of zero will store an empty value. // @@ -882,7 +975,27 @@ define_env!(Env, , // Returns the size of the pre-existing value at the specified key if any. Otherwise // `SENTINEL` is returned as a sentinel value. [seal1] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) -> u32 => { - ctx.set_storage(key_ptr, value_ptr, value_len) + ctx.set_storage(KeyType::Fix, key_ptr, value_ptr, value_len) + }, + + // Set the value at the given key in the contract storage. + // + // The key and value lengths must not exceed the maximums defined by the contracts module parameters. + // Specifying a `value_len` of zero will store an empty value. + // + // # Parameters + // + // - `key_ptr`: pointer into the linear memory where the location to store the value is placed. + // - `key_len`: the length of the key in bytes. + // - `value_ptr`: pointer into the linear memory where the value to set is placed. + // - `value_len`: the length of the value in bytes. + // + // # Return Value + // + // Returns the size of the pre-existing value at the specified key if any. Otherwise + // `SENTINEL` is returned as a sentinel value. + [__unstable__] seal_set_storage(ctx, key_ptr: u32, key_len: u32, value_ptr: u32, value_len: u32) -> u32 => { + ctx.set_storage(KeyType::Variable(key_len), key_ptr, value_ptr, value_len) }, // Clear the value at the given key in the contract storage. @@ -890,25 +1003,29 @@ define_env!(Env, , // Equivalent to the newer version of `seal_clear_storage` with the exception of the return // type. Still a valid thing to call when not interested in the return value. [seal0] seal_clear_storage(ctx, key_ptr: u32) => { - ctx.clear_storage(key_ptr).map(|_| ()).map_err(Into::into) + ctx.clear_storage(KeyType::Fix, key_ptr).map(|_| ()) }, // Clear the value at the given key in the contract storage. // // # Parameters // - // - `key_ptr`: pointer into the linear memory where the location to clear the value is placed. + // - `key_ptr`: pointer into the linear memory where the key is placed. + // - `key_len`: the length of the key in bytes. // // # Return Value // // Returns the size of the pre-existing value at the specified key if any. Otherwise // `SENTINEL` is returned as a sentinel value. - [__unstable__] seal_clear_storage(ctx, key_ptr: u32) -> u32 => { - ctx.clear_storage(key_ptr).map_err(Into::into) + [__unstable__] seal_clear_storage(ctx, key_ptr: u32, key_len: u32) -> u32 => { + ctx.clear_storage(KeyType::Variable(key_len), key_ptr) }, // Retrieve the value under the given key from storage. // + // This version is to be used with a fixed sized storage key. For runtimes supporting transparent + // hashing, please use the newer version of this function. + // // # Parameters // // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. @@ -920,21 +1037,36 @@ define_env!(Env, , // // `ReturnCode::KeyNotFound` [seal0] seal_get_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { - let charged = ctx.charge_gas(RuntimeCosts::GetStorage(ctx.ext.max_value_size()))?; - let mut key: StorageKey = [0; 32]; - ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; - if let Some(value) = ctx.ext.get_storage(&key) { - ctx.adjust_gas(charged, RuntimeCosts::GetStorage(value.len() as u32)); - ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, already_charged)?; - Ok(ReturnCode::Success) - } else { - ctx.adjust_gas(charged, RuntimeCosts::GetStorage(0)); - Ok(ReturnCode::KeyNotFound) - } + ctx.get_storage(KeyType::Fix, key_ptr, out_ptr, out_len_ptr) + }, + + // Retrieve the value under the given key from storage. + // + // This version is to be used with a fixed sized storage key. For runtimes supporting transparent + // hashing, please use the newer version of this function. + // + // The key length must not exceed the maximum defined by the contracts module parameter. + // + // # Parameters + // + // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. + // - `key_len`: the length of the key in bytes. + // - `out_ptr`: pointer to the linear memory where the value is written to. + // - `out_len_ptr`: in-out pointer into linear memory where the buffer length + // is read from and the value length is written to. + // + // # Errors + // + // `ReturnCode::KeyNotFound` + [__unstable__] seal_get_storage(ctx, key_ptr: u32, key_len: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { + ctx.get_storage(KeyType::Variable(key_len), key_ptr, out_ptr, out_len_ptr) }, // Checks whether there is a value stored under the given key. // + // This version is to be used with a fixed sized storage key. For runtimes supporting transparent + // hashing, please use the newer version of this function. + // // # Parameters // // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. @@ -944,16 +1076,24 @@ define_env!(Env, , // Returns the size of the pre-existing value at the specified key if any. Otherwise // `SENTINEL` is returned as a sentinel value. [seal0] seal_contains_storage(ctx, key_ptr: u32) -> u32 => { - let charged = ctx.charge_gas(RuntimeCosts::ContainsStorage(ctx.ext.max_value_size()))?; - let mut key: StorageKey = [0; 32]; - ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; - if let Some(len) = ctx.ext.get_storage_size(&key) { - ctx.adjust_gas(charged, RuntimeCosts::ContainsStorage(len)); - Ok(len) - } else { - ctx.adjust_gas(charged, RuntimeCosts::ContainsStorage(0)); - Ok(SENTINEL) - } + ctx.contains_storage(KeyType::Fix, key_ptr) + }, + + // Checks whether there is a value stored under the given key. + // + // The key length must not exceed the maximum defined by the contracts module parameter. + // + // # Parameters + // + // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. + // - `key_len`: the length of the key in bytes. + // + // # Return Value + // + // Returns the size of the pre-existing value at the specified key if any. Otherwise + // `SENTINEL` is returned as a sentinel value. + [__unstable__] seal_contains_storage(ctx, key_ptr: u32, key_len: u32) -> u32 => { + ctx.contains_storage(KeyType::Variable(key_len), key_ptr) }, // Retrieve and remove the value under the given key from storage. @@ -961,6 +1101,7 @@ define_env!(Env, , // # Parameters // // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. + // - `key_len`: the length of the key in bytes. // - `out_ptr`: pointer to the linear memory where the value is written to. // - `out_len_ptr`: in-out pointer into linear memory where the buffer length // is read from and the value length is written to. @@ -968,11 +1109,10 @@ define_env!(Env, , // # Errors // // `ReturnCode::KeyNotFound` - [__unstable__] seal_take_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { + [__unstable__] seal_take_storage(ctx, key_ptr: u32, key_len: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?; - let mut key: StorageKey = [0; 32]; - ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; - if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage(key, None, true)? { + let key = ctx.read_sandbox_memory(key_ptr, key_len)?; + if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage_transparent(&VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, None, true)? { ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(value.len() as u32)); ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, already_charged)?; Ok(ReturnCode::Success) diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index b18c259ebd433..3c90579e65d53 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,11 +18,12 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-04-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-06-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet // --chain=dev @@ -32,8 +33,9 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/contracts/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -164,44 +166,47 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - (1_664_000 as Weight) + (1_654_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (11_878_000 as Weight) + (8_564_000 as Weight) // Standard Error: 0 - .saturating_add((758_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((868_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) + /// The range of component `q` is `[0, 1024]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (10_240_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_899_000 as Weight).saturating_mul(q as Weight)) + (0 as Weight) + // Standard Error: 5_000 + .saturating_add((1_944_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) + /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - (18_012_000 as Weight) + (19_016_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - (206_036_000 as Weight) + (205_194_000 as Weight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -209,50 +214,51 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) + /// The range of component `c` is `[0, 64226]`. + /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (243_162_000 as Weight) + (288_487_000 as Weight) // Standard Error: 0 - .saturating_add((122_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((124_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(7 as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(6 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - (180_607_000 as Weight) + (186_136_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (146_032_000 as Weight) + (149_232_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) + /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - (45_113_000 as Weight) + (51_721_000 as Weight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -260,14 +266,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (25_722_000 as Weight) + (30_016_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) fn set_code() -> Weight { - (23_135_000 as Weight) + (27_192_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -275,11 +281,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - (205_061_000 as Weight) - // Standard Error: 76_000 - .saturating_add((40_732_000 as Weight).saturating_mul(r as Weight)) + (206_405_000 as Weight) + // Standard Error: 112_000 + .saturating_add((40_987_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -287,11 +293,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - (97_971_000 as Weight) - // Standard Error: 741_000 - .saturating_add((308_361_000 as Weight).saturating_mul(r as Weight)) + (106_220_000 as Weight) + // Standard Error: 710_000 + .saturating_add((307_648_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -300,11 +306,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - (109_052_000 as Weight) - // Standard Error: 716_000 - .saturating_add((366_257_000 as Weight).saturating_mul(r as Weight)) + (104_498_000 as Weight) + // Standard Error: 633_000 + .saturating_add((368_901_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -313,11 +319,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - (205_748_000 as Weight) - // Standard Error: 87_000 - .saturating_add((44_474_000 as Weight).saturating_mul(r as Weight)) + (208_696_000 as Weight) + // Standard Error: 101_000 + .saturating_add((44_445_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -325,11 +331,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - (201_898_000 as Weight) - // Standard Error: 55_000 - .saturating_add((16_703_000 as Weight).saturating_mul(r as Weight)) + (205_612_000 as Weight) + // Standard Error: 68_000 + .saturating_add((17_145_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -337,11 +343,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - (204_668_000 as Weight) - // Standard Error: 65_000 - .saturating_add((40_459_000 as Weight).saturating_mul(r as Weight)) + (206_947_000 as Weight) + // Standard Error: 107_000 + .saturating_add((40_789_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -349,11 +355,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - (203_240_000 as Weight) - // Standard Error: 68_000 - .saturating_add((40_270_000 as Weight).saturating_mul(r as Weight)) + (208_692_000 as Weight) + // Standard Error: 109_000 + .saturating_add((40_600_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -361,11 +367,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - (211_535_000 as Weight) - // Standard Error: 73_000 - .saturating_add((114_954_000 as Weight).saturating_mul(r as Weight)) + (209_811_000 as Weight) + // Standard Error: 208_000 + .saturating_add((116_831_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -373,11 +379,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - (204_653_000 as Weight) - // Standard Error: 71_000 - .saturating_add((40_188_000 as Weight).saturating_mul(r as Weight)) + (207_406_000 as Weight) + // Standard Error: 117_000 + .saturating_add((40_702_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -385,11 +391,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - (204_690_000 as Weight) - // Standard Error: 82_000 - .saturating_add((40_260_000 as Weight).saturating_mul(r as Weight)) + (209_260_000 as Weight) + // Standard Error: 130_000 + .saturating_add((40_479_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -397,11 +403,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - (205_004_000 as Weight) - // Standard Error: 62_000 - .saturating_add((40_018_000 as Weight).saturating_mul(r as Weight)) + (206_448_000 as Weight) + // Standard Error: 95_000 + .saturating_add((40_134_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -409,11 +415,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - (204_341_000 as Weight) - // Standard Error: 93_000 - .saturating_add((39_920_000 as Weight).saturating_mul(r as Weight)) + (206_969_000 as Weight) + // Standard Error: 116_000 + .saturating_add((40_251_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -421,12 +427,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - (208_702_000 as Weight) - // Standard Error: 115_000 - .saturating_add((101_441_000 as Weight).saturating_mul(r as Weight)) + (211_611_000 as Weight) + // Standard Error: 175_000 + .saturating_add((98_675_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -434,11 +440,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - (131_983_000 as Weight) - // Standard Error: 17_000 - .saturating_add((19_153_000 as Weight).saturating_mul(r as Weight)) + (134_484_000 as Weight) + // Standard Error: 57_000 + .saturating_add((19_329_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -446,11 +452,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - (203_768_000 as Weight) - // Standard Error: 57_000 - .saturating_add((39_316_000 as Weight).saturating_mul(r as Weight)) + (208_556_000 as Weight) + // Standard Error: 125_000 + .saturating_add((40_328_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -458,11 +464,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - (273_930_000 as Weight) - // Standard Error: 3_000 - .saturating_add((9_513_000 as Weight).saturating_mul(n as Weight)) + (268_886_000 as Weight) + // Standard Error: 4_000 + .saturating_add((9_627_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -470,10 +476,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(r: u32, ) -> Weight { - (199_311_000 as Weight) - // Standard Error: 601_000 - .saturating_add((2_181_000 as Weight).saturating_mul(r as Weight)) + /// The range of component `r` is `[0, 1]`. + fn seal_return(_r: u32, ) -> Weight { + (203_591_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -481,11 +486,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - (201_130_000 as Weight) + (204_258_000 as Weight) // Standard Error: 0 - .saturating_add((184_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((183_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -493,28 +498,28 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - (202_063_000 as Weight) - // Standard Error: 100_000 - .saturating_add((54_190_000 as Weight).saturating_mul(r as Weight)) + (206_625_000 as Weight) + // Standard Error: 672_000 + .saturating_add((59_377_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - (206_528_000 as Weight) - // Standard Error: 120_000 - .saturating_add((136_384_000 as Weight).saturating_mul(r as Weight)) + (208_866_000 as Weight) + // Standard Error: 164_000 + .saturating_add((133_438_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -522,11 +527,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - (210_309_000 as Weight) - // Standard Error: 138_000 - .saturating_add((236_583_000 as Weight).saturating_mul(r as Weight)) + (220_860_000 as Weight) + // Standard Error: 209_000 + .saturating_add((239_951_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -535,12 +540,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:80 w:80) + /// The range of component `t` is `[0, 4]`. + /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (434_046_000 as Weight) - // Standard Error: 1_678_000 - .saturating_add((242_928_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 330_000 - .saturating_add((66_716_000 as Weight).saturating_mul(n as Weight)) + (439_782_000 as Weight) + // Standard Error: 1_643_000 + .saturating_add((264_687_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 323_000 + .saturating_add((67_636_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -550,119 +557,140 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - (138_934_000 as Weight) - // Standard Error: 34_000 - .saturating_add((31_927_000 as Weight).saturating_mul(r as Weight)) + (140_280_000 as Weight) + // Standard Error: 82_000 + .saturating_add((32_717_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - (88_315_000 as Weight) - // Standard Error: 594_000 - .saturating_add((328_984_000 as Weight).saturating_mul(r as Weight)) + (161_247_000 as Weight) + // Standard Error: 883_000 + .saturating_add((423_997_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (529_349_000 as Weight) - // Standard Error: 223_000 - .saturating_add((21_065_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(85 as Weight)) - .saturating_add(T::DbWeight::get().writes(83 as Weight)) + (529_247_000 as Weight) + // Standard Error: 2_745_000 + .saturating_add((85_282_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(55 as Weight)) + .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(T::DbWeight::get().writes(53 as Weight)) + .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (546_447_000 as Weight) - // Standard Error: 261_000 - .saturating_add((8_709_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(85 as Weight)) - .saturating_add(T::DbWeight::get().writes(83 as Weight)) + (529_812_000 as Weight) + // Standard Error: 2_513_000 + .saturating_add((74_554_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(55 as Weight)) + .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(T::DbWeight::get().writes(53 as Weight)) + .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - (118_849_000 as Weight) - // Standard Error: 518_000 - .saturating_add((309_800_000 as Weight).saturating_mul(r as Weight)) + (184_803_000 as Weight) + // Standard Error: 733_000 + .saturating_add((404_933_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (537_039_000 as Weight) - // Standard Error: 235_000 - .saturating_add((8_071_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(85 as Weight)) - .saturating_add(T::DbWeight::get().writes(83 as Weight)) + (500_958_000 as Weight) + // Standard Error: 2_980_000 + .saturating_add((75_996_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(55 as Weight)) + .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(T::DbWeight::get().writes(52 as Weight)) + .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - (125_427_000 as Weight) - // Standard Error: 635_000 - .saturating_add((276_126_000 as Weight).saturating_mul(r as Weight)) + (177_682_000 as Weight) + // Standard Error: 743_000 + .saturating_add((338_172_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (500_356_000 as Weight) - // Standard Error: 279_000 - .saturating_add((49_746_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(84 as Weight)) + (465_285_000 as Weight) + // Standard Error: 2_599_000 + .saturating_add((155_106_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(55 as Weight)) + .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - (129_046_000 as Weight) - // Standard Error: 408_000 - .saturating_add((237_117_000 as Weight).saturating_mul(r as Weight)) + (179_118_000 as Weight) + // Standard Error: 572_000 + .saturating_add((311_083_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (451_122_000 as Weight) - // Standard Error: 200_000 - .saturating_add((7_750_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(84 as Weight)) + (423_056_000 as Weight) + // Standard Error: 2_037_000 + .saturating_add((69_665_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(54 as Weight)) + .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - (118_085_000 as Weight) - // Standard Error: 526_000 - .saturating_add((338_332_000 as Weight).saturating_mul(r as Weight)) + (188_884_000 as Weight) + // Standard Error: 761_000 + .saturating_add((432_781_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (569_270_000 as Weight) - // Standard Error: 294_000 - .saturating_add((51_071_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(85 as Weight)) - .saturating_add(T::DbWeight::get().writes(83 as Weight)) + (532_408_000 as Weight) + // Standard Error: 3_348_000 + .saturating_add((164_943_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(55 as Weight)) + .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(T::DbWeight::get().writes(53 as Weight)) + .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - (124_818_000 as Weight) - // Standard Error: 1_251_000 - .saturating_add((1_455_607_000 as Weight).saturating_mul(r as Weight)) + (127_181_000 as Weight) + // Standard Error: 1_495_000 + .saturating_add((1_500_589_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -672,11 +700,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_575_000 - .saturating_add((14_645_061_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 3_803_000 + .saturating_add((14_860_909_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -686,11 +714,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 5_742_000 - .saturating_add((14_623_917_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 6_045_000 + .saturating_add((14_797_140_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -698,13 +726,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `t` is `[0, 1]`. + /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (9_081_635_000 as Weight) - // Standard Error: 11_326_000 - .saturating_add((1_335_139_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 4_000 - .saturating_add((9_575_000 as Weight).saturating_mul(c as Weight)) + (9_196_444_000 as Weight) + // Standard Error: 20_486_000 + .saturating_add((1_458_153_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 8_000 + .saturating_add((9_718_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(85 as Weight)) .saturating_add(T::DbWeight::get().reads((81 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(81 as Weight)) @@ -714,13 +743,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:80 w:80) + /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 34_958_000 - .saturating_add((20_700_850_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 36_253_000 + .saturating_add((21_201_529_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((320 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(3 as Weight)) @@ -730,15 +759,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + /// The range of component `t` is `[0, 1]`. + /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (12_091_206_000 as Weight) - // Standard Error: 104_884_000 - .saturating_add((635_259_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 49_000 - .saturating_add((122_935_000 as Weight).saturating_mul(s as Weight)) + (12_282_498_000 as Weight) + // Standard Error: 48_112_000 + .saturating_add((720_795_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 22_000 + .saturating_add((124_274_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(167 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) .saturating_add(T::DbWeight::get().writes(165 as Weight)) @@ -748,11 +778,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - (203_315_000 as Weight) - // Standard Error: 74_000 - .saturating_add((60_223_000 as Weight).saturating_mul(r as Weight)) + (203_959_000 as Weight) + // Standard Error: 142_000 + .saturating_add((61_311_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -760,11 +790,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (355_672_000 as Weight) - // Standard Error: 25_000 - .saturating_add((319_519_000 as Weight).saturating_mul(n as Weight)) + (349_915_000 as Weight) + // Standard Error: 40_000 + .saturating_add((320_652_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -772,11 +802,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - (203_117_000 as Weight) - // Standard Error: 94_000 - .saturating_add((77_363_000 as Weight).saturating_mul(r as Weight)) + (209_219_000 as Weight) + // Standard Error: 157_000 + .saturating_add((73_728_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -784,11 +814,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (196_575_000 as Weight) - // Standard Error: 13_000 - .saturating_add((243_479_000 as Weight).saturating_mul(n as Weight)) + (208_860_000 as Weight) + // Standard Error: 25_000 + .saturating_add((245_718_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -796,11 +826,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - (203_938_000 as Weight) - // Standard Error: 97_000 - .saturating_add((50_708_000 as Weight).saturating_mul(r as Weight)) + (206_165_000 as Weight) + // Standard Error: 138_000 + .saturating_add((51_644_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -808,11 +838,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (247_065_000 as Weight) - // Standard Error: 8_000 - .saturating_add((94_160_000 as Weight).saturating_mul(n as Weight)) + (255_955_000 as Weight) + // Standard Error: 14_000 + .saturating_add((95_090_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -820,11 +850,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - (204_389_000 as Weight) - // Standard Error: 86_000 - .saturating_add((50_663_000 as Weight).saturating_mul(r as Weight)) + (208_153_000 as Weight) + // Standard Error: 140_000 + .saturating_add((51_264_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -832,11 +862,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (284_700_000 as Weight) - // Standard Error: 9_000 - .saturating_add((94_231_000 as Weight).saturating_mul(n as Weight)) + (278_368_000 as Weight) + // Standard Error: 14_000 + .saturating_add((95_006_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -844,11 +874,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - (235_813_000 as Weight) - // Standard Error: 521_000 - .saturating_add((3_044_204_000 as Weight).saturating_mul(r as Weight)) + (331_955_000 as Weight) + // Standard Error: 1_155_000 + .saturating_add((3_069_955_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -856,11 +886,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - (204_095_000 as Weight) - // Standard Error: 495_000 - .saturating_add((2_027_914_000 as Weight).saturating_mul(r as Weight)) + (207_838_000 as Weight) + // Standard Error: 783_000 + .saturating_add((2_058_503_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -869,267 +899,319 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts OwnerInfoOf (r:16 w:16) + /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_604_000 - .saturating_add((759_511_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_567_000 + .saturating_add((774_380_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes((79 as Weight).saturating_mul(r as Weight))) } + /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - (74_210_000 as Weight) + (73_955_000 as Weight) // Standard Error: 1_000 - .saturating_add((601_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((612_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - (74_123_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_315_000 as Weight).saturating_mul(r as Weight)) + (74_057_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - (74_145_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_388_000 as Weight).saturating_mul(r as Weight)) + (74_137_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_427_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - (73_931_000 as Weight) + (73_844_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_768_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_773_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - (73_829_000 as Weight) - // Standard Error: 0 - .saturating_add((1_957_000 as Weight).saturating_mul(r as Weight)) + (73_979_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_952_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - (73_760_000 as Weight) - // Standard Error: 0 - .saturating_add((932_000 as Weight).saturating_mul(r as Weight)) + (73_924_000 as Weight) + // Standard Error: 3_000 + .saturating_add((941_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - (73_714_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_420_000 as Weight).saturating_mul(r as Weight)) + (73_574_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_439_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - (73_496_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_575_000 as Weight).saturating_mul(r as Weight)) + (73_343_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_603_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_036_000 as Weight) + (76_267_000 as Weight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - (76_015_000 as Weight) - // Standard Error: 19_000 - .saturating_add((6_954_000 as Weight).saturating_mul(r as Weight)) + (74_877_000 as Weight) + // Standard Error: 12_000 + .saturating_add((7_144_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - (88_247_000 as Weight) - // Standard Error: 9_000 - .saturating_add((8_957_000 as Weight).saturating_mul(r as Weight)) + (88_665_000 as Weight) + // Standard Error: 20_000 + .saturating_add((9_142_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (98_336_000 as Weight) + (98_600_000 as Weight) // Standard Error: 2_000 - .saturating_add((474_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((469_000 as Weight).saturating_mul(p as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - (74_565_000 as Weight) - // Standard Error: 4_000 - .saturating_add((627_000 as Weight).saturating_mul(r as Weight)) + (74_555_000 as Weight) + // Standard Error: 1_000 + .saturating_add((624_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - (74_414_000 as Weight) + (74_329_000 as Weight) // Standard Error: 1_000 - .saturating_add((684_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((688_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - (74_346_000 as Weight) + (74_612_000 as Weight) // Standard Error: 1_000 - .saturating_add((911_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((909_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - (76_649_000 as Weight) - // Standard Error: 0 - .saturating_add((1_183_000 as Weight).saturating_mul(r as Weight)) + (76_906_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_192_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - (76_995_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + (76_979_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - (73_927_000 as Weight) - // Standard Error: 1_000 - .saturating_add((666_000 as Weight).saturating_mul(r as Weight)) + (74_370_000 as Weight) + // Standard Error: 3_000 + .saturating_add((661_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - (73_479_000 as Weight) - // Standard Error: 24_000 - .saturating_add((180_808_000 as Weight).saturating_mul(r as Weight)) + (73_584_000 as Weight) + // Standard Error: 353_000 + .saturating_add((187_114_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - (74_048_000 as Weight) + (74_206_000 as Weight) // Standard Error: 1_000 - .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - (73_894_000 as Weight) + (73_992_000 as Weight) // Standard Error: 1_000 - .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - (73_728_000 as Weight) - // Standard Error: 0 - .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) + (73_985_000 as Weight) + // Standard Error: 2_000 + .saturating_add((891_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - (74_049_000 as Weight) - // Standard Error: 1_000 - .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) + (74_117_000 as Weight) + // Standard Error: 4_000 + .saturating_add((901_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_118_000 as Weight) + (73_981_000 as Weight) // Standard Error: 1_000 - .saturating_add((863_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((866_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - (74_042_000 as Weight) - // Standard Error: 1_000 - .saturating_add((865_000 as Weight).saturating_mul(r as Weight)) + (74_104_000 as Weight) + // Standard Error: 3_000 + .saturating_add((868_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - (73_885_000 as Weight) - // Standard Error: 1_000 - .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) + (74_293_000 as Weight) + // Standard Error: 3_000 + .saturating_add((878_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - (73_788_000 as Weight) - // Standard Error: 0 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (74_055_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - (73_727_000 as Weight) - // Standard Error: 0 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (73_710_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - (73_825_000 as Weight) - // Standard Error: 0 - .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) + (73_917_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - (73_638_000 as Weight) - // Standard Error: 0 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (74_048_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - (73_688_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (74_029_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - (73_895_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) + (74_267_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - (73_860_000 as Weight) - // Standard Error: 0 + (73_952_000 as Weight) + // Standard Error: 1_000 .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - (73_864_000 as Weight) - // Standard Error: 0 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + (73_851_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - (72_730_000 as Weight) - // Standard Error: 7_000 - .saturating_add((1_432_000 as Weight).saturating_mul(r as Weight)) + (74_034_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - (73_998_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_346_000 as Weight).saturating_mul(r as Weight)) + (73_979_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - (73_708_000 as Weight) + (74_000_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_328_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - (74_312_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) + (73_883_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_331_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - (74_203_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_322_000 as Weight).saturating_mul(r as Weight)) + (74_216_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - (73_990_000 as Weight) + (73_989_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_010_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_998_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - (73_918_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_019_000 as Weight).saturating_mul(r as Weight)) + (73_857_000 as Weight) + // Standard Error: 4_000 + .saturating_add((2_073_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - (73_927_000 as Weight) + (73_801_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_001_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_027_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - (73_691_000 as Weight) - // Standard Error: 0 - .saturating_add((2_062_000 as Weight).saturating_mul(r as Weight)) + (74_130_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_064_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - (73_869_000 as Weight) - // Standard Error: 0 + (74_071_000 as Weight) + // Standard Error: 1_000 .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - (73_890_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) + (74_201_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_330_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - (73_866_000 as Weight) + (74_241_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_321_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - (73_793_000 as Weight) - // Standard Error: 0 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (74_331_000 as Weight) + // Standard Error: 6_000 + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - (73_695_000 as Weight) - // Standard Error: 0 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + (73_674_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - (73_743_000 as Weight) - // Standard Error: 0 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (73_807_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - (73_781_000 as Weight) - // Standard Error: 0 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (73_725_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - (73_941_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) + (73_755_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } } @@ -1137,44 +1219,47 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - (1_641_000 as Weight) + (1_654_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (11_878_000 as Weight) + (8_564_000 as Weight) // Standard Error: 0 - .saturating_add((758_000 as Weight).saturating_mul(k as Weight)) + .saturating_add((868_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } // Storage: Contracts DeletionQueue (r:1 w:0) + /// The range of component `q` is `[0, 1024]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (10_240_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_899_000 as Weight).saturating_mul(q as Weight)) + (0 as Weight) + // Standard Error: 5_000 + .saturating_add((1_944_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) + /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - (18_012_000 as Weight) + (19_016_000 as Weight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - (206_036_000 as Weight) + (205_194_000 as Weight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((53_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -1182,50 +1267,51 @@ impl WeightInfo for () { // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) + /// The range of component `c` is `[0, 64226]`. + /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (243_162_000 as Weight) + (288_487_000 as Weight) // Standard Error: 0 - .saturating_add((122_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((124_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(7 as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - (180_607_000 as Weight) + (186_136_000 as Weight) // Standard Error: 0 .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (146_032_000 as Weight) + (149_232_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) + /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - (45_113_000 as Weight) + (51_721_000 as Weight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1233,14 +1319,14 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (25_722_000 as Weight) + (30_016_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) fn set_code() -> Weight { - (23_135_000 as Weight) + (27_192_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -1248,11 +1334,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - (205_061_000 as Weight) - // Standard Error: 76_000 - .saturating_add((40_732_000 as Weight).saturating_mul(r as Weight)) + (206_405_000 as Weight) + // Standard Error: 112_000 + .saturating_add((40_987_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1260,11 +1346,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - (97_971_000 as Weight) - // Standard Error: 741_000 - .saturating_add((308_361_000 as Weight).saturating_mul(r as Weight)) + (106_220_000 as Weight) + // Standard Error: 710_000 + .saturating_add((307_648_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1273,11 +1359,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - (109_052_000 as Weight) - // Standard Error: 716_000 - .saturating_add((366_257_000 as Weight).saturating_mul(r as Weight)) + (104_498_000 as Weight) + // Standard Error: 633_000 + .saturating_add((368_901_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1286,11 +1372,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - (205_748_000 as Weight) - // Standard Error: 87_000 - .saturating_add((44_474_000 as Weight).saturating_mul(r as Weight)) + (208_696_000 as Weight) + // Standard Error: 101_000 + .saturating_add((44_445_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1298,11 +1384,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - (201_898_000 as Weight) - // Standard Error: 55_000 - .saturating_add((16_703_000 as Weight).saturating_mul(r as Weight)) + (205_612_000 as Weight) + // Standard Error: 68_000 + .saturating_add((17_145_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1310,11 +1396,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - (204_668_000 as Weight) - // Standard Error: 65_000 - .saturating_add((40_459_000 as Weight).saturating_mul(r as Weight)) + (206_947_000 as Weight) + // Standard Error: 107_000 + .saturating_add((40_789_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1322,11 +1408,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - (203_240_000 as Weight) - // Standard Error: 68_000 - .saturating_add((40_270_000 as Weight).saturating_mul(r as Weight)) + (208_692_000 as Weight) + // Standard Error: 109_000 + .saturating_add((40_600_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1334,11 +1420,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - (211_535_000 as Weight) - // Standard Error: 73_000 - .saturating_add((114_954_000 as Weight).saturating_mul(r as Weight)) + (209_811_000 as Weight) + // Standard Error: 208_000 + .saturating_add((116_831_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1346,11 +1432,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - (204_653_000 as Weight) - // Standard Error: 71_000 - .saturating_add((40_188_000 as Weight).saturating_mul(r as Weight)) + (207_406_000 as Weight) + // Standard Error: 117_000 + .saturating_add((40_702_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1358,11 +1444,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - (204_690_000 as Weight) - // Standard Error: 82_000 - .saturating_add((40_260_000 as Weight).saturating_mul(r as Weight)) + (209_260_000 as Weight) + // Standard Error: 130_000 + .saturating_add((40_479_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1370,11 +1456,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - (205_004_000 as Weight) - // Standard Error: 62_000 - .saturating_add((40_018_000 as Weight).saturating_mul(r as Weight)) + (206_448_000 as Weight) + // Standard Error: 95_000 + .saturating_add((40_134_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1382,11 +1468,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - (204_341_000 as Weight) - // Standard Error: 93_000 - .saturating_add((39_920_000 as Weight).saturating_mul(r as Weight)) + (206_969_000 as Weight) + // Standard Error: 116_000 + .saturating_add((40_251_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1394,12 +1480,12 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - (208_702_000 as Weight) - // Standard Error: 115_000 - .saturating_add((101_441_000 as Weight).saturating_mul(r as Weight)) + (211_611_000 as Weight) + // Standard Error: 175_000 + .saturating_add((98_675_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1407,11 +1493,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - (131_983_000 as Weight) - // Standard Error: 17_000 - .saturating_add((19_153_000 as Weight).saturating_mul(r as Weight)) + (134_484_000 as Weight) + // Standard Error: 57_000 + .saturating_add((19_329_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1419,11 +1505,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - (203_768_000 as Weight) - // Standard Error: 57_000 - .saturating_add((39_316_000 as Weight).saturating_mul(r as Weight)) + (208_556_000 as Weight) + // Standard Error: 125_000 + .saturating_add((40_328_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1431,11 +1517,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - (273_930_000 as Weight) - // Standard Error: 3_000 - .saturating_add((9_513_000 as Weight).saturating_mul(n as Weight)) + (268_886_000 as Weight) + // Standard Error: 4_000 + .saturating_add((9_627_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1443,10 +1529,9 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - fn seal_return(r: u32, ) -> Weight { - (199_311_000 as Weight) - // Standard Error: 601_000 - .saturating_add((2_181_000 as Weight).saturating_mul(r as Weight)) + /// The range of component `r` is `[0, 1]`. + fn seal_return(_r: u32, ) -> Weight { + (203_591_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1454,11 +1539,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - (201_130_000 as Weight) + (204_258_000 as Weight) // Standard Error: 0 - .saturating_add((184_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((183_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1466,28 +1551,28 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - (202_063_000 as Weight) - // Standard Error: 100_000 - .saturating_add((54_190_000 as Weight).saturating_mul(r as Weight)) + (206_625_000 as Weight) + // Standard Error: 672_000 + .saturating_add((59_377_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - (206_528_000 as Weight) - // Standard Error: 120_000 - .saturating_add((136_384_000 as Weight).saturating_mul(r as Weight)) + (208_866_000 as Weight) + // Standard Error: 164_000 + .saturating_add((133_438_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1495,11 +1580,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - (210_309_000 as Weight) - // Standard Error: 138_000 - .saturating_add((236_583_000 as Weight).saturating_mul(r as Weight)) + (220_860_000 as Weight) + // Standard Error: 209_000 + .saturating_add((239_951_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1508,12 +1593,14 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:80 w:80) + /// The range of component `t` is `[0, 4]`. + /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (434_046_000 as Weight) - // Standard Error: 1_678_000 - .saturating_add((242_928_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 330_000 - .saturating_add((66_716_000 as Weight).saturating_mul(n as Weight)) + (439_782_000 as Weight) + // Standard Error: 1_643_000 + .saturating_add((264_687_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 323_000 + .saturating_add((67_636_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1523,119 +1610,140 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - (138_934_000 as Weight) - // Standard Error: 34_000 - .saturating_add((31_927_000 as Weight).saturating_mul(r as Weight)) + (140_280_000 as Weight) + // Standard Error: 82_000 + .saturating_add((32_717_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - (88_315_000 as Weight) - // Standard Error: 594_000 - .saturating_add((328_984_000 as Weight).saturating_mul(r as Weight)) + (161_247_000 as Weight) + // Standard Error: 883_000 + .saturating_add((423_997_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (529_349_000 as Weight) - // Standard Error: 223_000 - .saturating_add((21_065_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(85 as Weight)) - .saturating_add(RocksDbWeight::get().writes(83 as Weight)) + (529_247_000 as Weight) + // Standard Error: 2_745_000 + .saturating_add((85_282_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(55 as Weight)) + .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(RocksDbWeight::get().writes(53 as Weight)) + .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (546_447_000 as Weight) - // Standard Error: 261_000 - .saturating_add((8_709_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(85 as Weight)) - .saturating_add(RocksDbWeight::get().writes(83 as Weight)) + (529_812_000 as Weight) + // Standard Error: 2_513_000 + .saturating_add((74_554_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(55 as Weight)) + .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(RocksDbWeight::get().writes(53 as Weight)) + .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - (118_849_000 as Weight) - // Standard Error: 518_000 - .saturating_add((309_800_000 as Weight).saturating_mul(r as Weight)) + (184_803_000 as Weight) + // Standard Error: 733_000 + .saturating_add((404_933_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (537_039_000 as Weight) - // Standard Error: 235_000 - .saturating_add((8_071_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(85 as Weight)) - .saturating_add(RocksDbWeight::get().writes(83 as Weight)) + (500_958_000 as Weight) + // Standard Error: 2_980_000 + .saturating_add((75_996_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(55 as Weight)) + .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(RocksDbWeight::get().writes(52 as Weight)) + .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - (125_427_000 as Weight) - // Standard Error: 635_000 - .saturating_add((276_126_000 as Weight).saturating_mul(r as Weight)) + (177_682_000 as Weight) + // Standard Error: 743_000 + .saturating_add((338_172_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (500_356_000 as Weight) - // Standard Error: 279_000 - .saturating_add((49_746_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(84 as Weight)) + (465_285_000 as Weight) + // Standard Error: 2_599_000 + .saturating_add((155_106_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(55 as Weight)) + .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - (129_046_000 as Weight) - // Standard Error: 408_000 - .saturating_add((237_117_000 as Weight).saturating_mul(r as Weight)) + (179_118_000 as Weight) + // Standard Error: 572_000 + .saturating_add((311_083_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (451_122_000 as Weight) - // Standard Error: 200_000 - .saturating_add((7_750_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(84 as Weight)) + (423_056_000 as Weight) + // Standard Error: 2_037_000 + .saturating_add((69_665_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(54 as Weight)) + .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - (118_085_000 as Weight) - // Standard Error: 526_000 - .saturating_add((338_332_000 as Weight).saturating_mul(r as Weight)) + (188_884_000 as Weight) + // Standard Error: 761_000 + .saturating_add((432_781_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (569_270_000 as Weight) - // Standard Error: 294_000 - .saturating_add((51_071_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(85 as Weight)) - .saturating_add(RocksDbWeight::get().writes(83 as Weight)) + (532_408_000 as Weight) + // Standard Error: 3_348_000 + .saturating_add((164_943_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(55 as Weight)) + .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(RocksDbWeight::get().writes(53 as Weight)) + .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - (124_818_000 as Weight) - // Standard Error: 1_251_000 - .saturating_add((1_455_607_000 as Weight).saturating_mul(r as Weight)) + (127_181_000 as Weight) + // Standard Error: 1_495_000 + .saturating_add((1_500_589_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -1645,11 +1753,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 4_575_000 - .saturating_add((14_645_061_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 3_803_000 + .saturating_add((14_860_909_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -1659,11 +1767,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 5_742_000 - .saturating_add((14_623_917_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 6_045_000 + .saturating_add((14_797_140_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1671,13 +1779,14 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `t` is `[0, 1]`. + /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (9_081_635_000 as Weight) - // Standard Error: 11_326_000 - .saturating_add((1_335_139_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 4_000 - .saturating_add((9_575_000 as Weight).saturating_mul(c as Weight)) + (9_196_444_000 as Weight) + // Standard Error: 20_486_000 + .saturating_add((1_458_153_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 8_000 + .saturating_add((9_718_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(85 as Weight)) .saturating_add(RocksDbWeight::get().reads((81 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(81 as Weight)) @@ -1687,13 +1796,13 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:80 w:80) + /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 34_958_000 - .saturating_add((20_700_850_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 36_253_000 + .saturating_add((21_201_529_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((320 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) @@ -1703,15 +1812,16 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:1) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + /// The range of component `t` is `[0, 1]`. + /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (12_091_206_000 as Weight) - // Standard Error: 104_884_000 - .saturating_add((635_259_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 49_000 - .saturating_add((122_935_000 as Weight).saturating_mul(s as Weight)) + (12_282_498_000 as Weight) + // Standard Error: 48_112_000 + .saturating_add((720_795_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 22_000 + .saturating_add((124_274_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(167 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) .saturating_add(RocksDbWeight::get().writes(165 as Weight)) @@ -1721,11 +1831,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - (203_315_000 as Weight) - // Standard Error: 74_000 - .saturating_add((60_223_000 as Weight).saturating_mul(r as Weight)) + (203_959_000 as Weight) + // Standard Error: 142_000 + .saturating_add((61_311_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1733,11 +1843,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (355_672_000 as Weight) - // Standard Error: 25_000 - .saturating_add((319_519_000 as Weight).saturating_mul(n as Weight)) + (349_915_000 as Weight) + // Standard Error: 40_000 + .saturating_add((320_652_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1745,11 +1855,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - (203_117_000 as Weight) - // Standard Error: 94_000 - .saturating_add((77_363_000 as Weight).saturating_mul(r as Weight)) + (209_219_000 as Weight) + // Standard Error: 157_000 + .saturating_add((73_728_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1757,11 +1867,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (196_575_000 as Weight) - // Standard Error: 13_000 - .saturating_add((243_479_000 as Weight).saturating_mul(n as Weight)) + (208_860_000 as Weight) + // Standard Error: 25_000 + .saturating_add((245_718_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1769,11 +1879,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - (203_938_000 as Weight) - // Standard Error: 97_000 - .saturating_add((50_708_000 as Weight).saturating_mul(r as Weight)) + (206_165_000 as Weight) + // Standard Error: 138_000 + .saturating_add((51_644_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1781,11 +1891,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (247_065_000 as Weight) - // Standard Error: 8_000 - .saturating_add((94_160_000 as Weight).saturating_mul(n as Weight)) + (255_955_000 as Weight) + // Standard Error: 14_000 + .saturating_add((95_090_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1793,11 +1903,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - (204_389_000 as Weight) - // Standard Error: 86_000 - .saturating_add((50_663_000 as Weight).saturating_mul(r as Weight)) + (208_153_000 as Weight) + // Standard Error: 140_000 + .saturating_add((51_264_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1805,11 +1915,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (284_700_000 as Weight) - // Standard Error: 9_000 - .saturating_add((94_231_000 as Weight).saturating_mul(n as Weight)) + (278_368_000 as Weight) + // Standard Error: 14_000 + .saturating_add((95_006_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1817,11 +1927,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - (235_813_000 as Weight) - // Standard Error: 521_000 - .saturating_add((3_044_204_000 as Weight).saturating_mul(r as Weight)) + (331_955_000 as Weight) + // Standard Error: 1_155_000 + .saturating_add((3_069_955_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1829,11 +1939,11 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1) + /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - (204_095_000 as Weight) - // Standard Error: 495_000 - .saturating_add((2_027_914_000 as Weight).saturating_mul(r as Weight)) + (207_838_000 as Weight) + // Standard Error: 783_000 + .saturating_add((2_058_503_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -1842,266 +1952,318 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts OwnerInfoOf (r:16 w:16) + /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_604_000 - .saturating_add((759_511_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_567_000 + .saturating_add((774_380_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes((79 as Weight).saturating_mul(r as Weight))) } + /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - (74_210_000 as Weight) + (73_955_000 as Weight) // Standard Error: 1_000 - .saturating_add((601_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((612_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - (74_123_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_315_000 as Weight).saturating_mul(r as Weight)) + (74_057_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - (74_145_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_388_000 as Weight).saturating_mul(r as Weight)) + (74_137_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_427_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - (73_931_000 as Weight) + (73_844_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_768_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_773_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - (73_829_000 as Weight) - // Standard Error: 0 - .saturating_add((1_957_000 as Weight).saturating_mul(r as Weight)) + (73_979_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_952_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - (73_760_000 as Weight) - // Standard Error: 0 - .saturating_add((932_000 as Weight).saturating_mul(r as Weight)) + (73_924_000 as Weight) + // Standard Error: 3_000 + .saturating_add((941_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - (73_714_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_420_000 as Weight).saturating_mul(r as Weight)) + (73_574_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_439_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - (73_496_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_575_000 as Weight).saturating_mul(r as Weight)) + (73_343_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_603_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_036_000 as Weight) + (76_267_000 as Weight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - (76_015_000 as Weight) - // Standard Error: 19_000 - .saturating_add((6_954_000 as Weight).saturating_mul(r as Weight)) + (74_877_000 as Weight) + // Standard Error: 12_000 + .saturating_add((7_144_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - (88_247_000 as Weight) - // Standard Error: 9_000 - .saturating_add((8_957_000 as Weight).saturating_mul(r as Weight)) + (88_665_000 as Weight) + // Standard Error: 20_000 + .saturating_add((9_142_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (98_336_000 as Weight) + (98_600_000 as Weight) // Standard Error: 2_000 - .saturating_add((474_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((469_000 as Weight).saturating_mul(p as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - (74_565_000 as Weight) - // Standard Error: 4_000 - .saturating_add((627_000 as Weight).saturating_mul(r as Weight)) + (74_555_000 as Weight) + // Standard Error: 1_000 + .saturating_add((624_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - (74_414_000 as Weight) + (74_329_000 as Weight) // Standard Error: 1_000 - .saturating_add((684_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((688_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - (74_346_000 as Weight) + (74_612_000 as Weight) // Standard Error: 1_000 - .saturating_add((911_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((909_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - (76_649_000 as Weight) - // Standard Error: 0 - .saturating_add((1_183_000 as Weight).saturating_mul(r as Weight)) + (76_906_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_192_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - (76_995_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_370_000 as Weight).saturating_mul(r as Weight)) + (76_979_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - (73_927_000 as Weight) - // Standard Error: 1_000 - .saturating_add((666_000 as Weight).saturating_mul(r as Weight)) + (74_370_000 as Weight) + // Standard Error: 3_000 + .saturating_add((661_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - (73_479_000 as Weight) - // Standard Error: 24_000 - .saturating_add((180_808_000 as Weight).saturating_mul(r as Weight)) + (73_584_000 as Weight) + // Standard Error: 353_000 + .saturating_add((187_114_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - (74_048_000 as Weight) + (74_206_000 as Weight) // Standard Error: 1_000 - .saturating_add((885_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - (73_894_000 as Weight) + (73_992_000 as Weight) // Standard Error: 1_000 - .saturating_add((889_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - (73_728_000 as Weight) - // Standard Error: 0 - .saturating_add((896_000 as Weight).saturating_mul(r as Weight)) + (73_985_000 as Weight) + // Standard Error: 2_000 + .saturating_add((891_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - (74_049_000 as Weight) - // Standard Error: 1_000 - .saturating_add((897_000 as Weight).saturating_mul(r as Weight)) + (74_117_000 as Weight) + // Standard Error: 4_000 + .saturating_add((901_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - (74_118_000 as Weight) + (73_981_000 as Weight) // Standard Error: 1_000 - .saturating_add((863_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((866_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - (74_042_000 as Weight) - // Standard Error: 1_000 - .saturating_add((865_000 as Weight).saturating_mul(r as Weight)) + (74_104_000 as Weight) + // Standard Error: 3_000 + .saturating_add((868_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - (73_885_000 as Weight) - // Standard Error: 1_000 - .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) + (74_293_000 as Weight) + // Standard Error: 3_000 + .saturating_add((878_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - (73_788_000 as Weight) - // Standard Error: 0 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (74_055_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - (73_727_000 as Weight) - // Standard Error: 0 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (73_710_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - (73_825_000 as Weight) - // Standard Error: 0 - .saturating_add((1_351_000 as Weight).saturating_mul(r as Weight)) + (73_917_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - (73_638_000 as Weight) - // Standard Error: 0 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + (74_048_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - (73_688_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_357_000 as Weight).saturating_mul(r as Weight)) + (74_029_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - (73_895_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) + (74_267_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - (73_860_000 as Weight) - // Standard Error: 0 + (73_952_000 as Weight) + // Standard Error: 1_000 .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - (73_864_000 as Weight) - // Standard Error: 0 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + (73_851_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - (72_730_000 as Weight) - // Standard Error: 7_000 - .saturating_add((1_432_000 as Weight).saturating_mul(r as Weight)) + (74_034_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - (73_998_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_346_000 as Weight).saturating_mul(r as Weight)) + (73_979_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - (73_708_000 as Weight) + (74_000_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_333_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_328_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - (74_312_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_339_000 as Weight).saturating_mul(r as Weight)) + (73_883_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_331_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - (74_203_000 as Weight) - // Standard Error: 2_000 - .saturating_add((1_322_000 as Weight).saturating_mul(r as Weight)) + (74_216_000 as Weight) + // Standard Error: 5_000 + .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - (73_990_000 as Weight) + (73_989_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_010_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_998_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - (73_918_000 as Weight) - // Standard Error: 1_000 - .saturating_add((2_019_000 as Weight).saturating_mul(r as Weight)) + (73_857_000 as Weight) + // Standard Error: 4_000 + .saturating_add((2_073_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - (73_927_000 as Weight) + (73_801_000 as Weight) // Standard Error: 1_000 - .saturating_add((2_001_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((2_027_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - (73_691_000 as Weight) - // Standard Error: 0 - .saturating_add((2_062_000 as Weight).saturating_mul(r as Weight)) + (74_130_000 as Weight) + // Standard Error: 1_000 + .saturating_add((2_064_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - (73_869_000 as Weight) - // Standard Error: 0 + (74_071_000 as Weight) + // Standard Error: 1_000 .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - (73_890_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) + (74_201_000 as Weight) + // Standard Error: 4_000 + .saturating_add((1_330_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - (73_866_000 as Weight) + (74_241_000 as Weight) // Standard Error: 1_000 - .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((1_321_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - (73_793_000 as Weight) - // Standard Error: 0 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (74_331_000 as Weight) + // Standard Error: 6_000 + .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - (73_695_000 as Weight) - // Standard Error: 0 - .saturating_add((1_354_000 as Weight).saturating_mul(r as Weight)) + (73_674_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - (73_743_000 as Weight) - // Standard Error: 0 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (73_807_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - (73_781_000 as Weight) - // Standard Error: 0 - .saturating_add((1_352_000 as Weight).saturating_mul(r as Weight)) + (73_725_000 as Weight) + // Standard Error: 1_000 + .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) } + /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - (73_941_000 as Weight) - // Standard Error: 1_000 - .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) + (73_755_000 as Weight) + // Standard Error: 3_000 + .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) } } From 16bae92b3f257f9c15525ae3d0a23d036bd59715 Mon Sep 17 00:00:00 2001 From: Vlad Date: Thu, 23 Jun 2022 17:54:15 +0300 Subject: [PATCH 0946/1472] Explain why `rusty-cachier` is put first (#11740) --- scripts/ci/gitlab/pipeline/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 0c3fd4d33798d..cc167410f94a4 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -80,6 +80,7 @@ cargo-check-benches: - .test-refs - .collect-artifacts before_script: + # perform rusty-cachier operations before any further modifications to the git repo to make cargo feel cheated not so much - !reference [.rust-info-script, script] - !reference [.rusty-cachier, before_script] # merges in the master branch on PRs From 60b945caca440fdf6a7be96b7dc0db54923f039d Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 24 Jun 2022 20:25:21 +0900 Subject: [PATCH 0947/1472] Bump `wasmtime` to 0.38.0 and `zstd` to 0.11.2 (#11720) * Bump `wasmtime` to 0.37.0 and `zstd` to 0.11.2 * Bump `wasmtime` to 0.38.0 --- Cargo.lock | 180 +++++++++++--------- client/executor/wasmtime/Cargo.toml | 2 +- client/executor/wasmtime/src/imports.rs | 12 +- client/executor/wasmtime/src/runtime.rs | 1 - frame/state-trie-migration/Cargo.toml | 2 +- primitives/maybe-compressed-blob/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 9 files changed, 109 insertions(+), 96 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cfcf5573c0bff..58604b47a87da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1141,11 +1141,11 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.82.3" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38faa2a16616c8e78a18d37b4726b98bfd2de192f2fdc8a39ddf568a408a0f75" +checksum = "899dc8d22f7771e7f887fb8bafa0c0d3ac1dea0c7f2c0ded6e20a855a7a1e890" dependencies = [ - "cranelift-entity 0.82.3", + "cranelift-entity 0.85.0", ] [[package]] @@ -1160,24 +1160,25 @@ dependencies = [ "cranelift-entity 0.76.0", "gimli 0.25.0", "log", - "regalloc 0.0.31", + "regalloc", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen" -version = "0.82.3" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f192472a3ba23860afd07d2b0217dc628f21fcc72617aa1336d98e1671f33b" +checksum = "8dbdc03f695cf67e7bc45da57155528274f47390b85060af8107eb304ef167c4" dependencies = [ - "cranelift-bforest 0.82.3", - "cranelift-codegen-meta 0.82.3", - "cranelift-codegen-shared 0.82.3", - "cranelift-entity 0.82.3", + "cranelift-bforest 0.85.0", + "cranelift-codegen-meta 0.85.0", + "cranelift-codegen-shared 0.85.0", + "cranelift-entity 0.85.0", + "cranelift-isle", "gimli 0.26.1", "log", - "regalloc 0.0.34", + "regalloc2", "smallvec", "target-lexicon", ] @@ -1194,11 +1195,11 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.82.3" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32ddb89e9b89d3d9b36a5b7d7ea3261c98235a76ac95ba46826b8ec40b1a24" +checksum = "9ea66cbba3eb7fcb3ec9f42839a6d381bd40cf97780397e7167daf9725d4ffa0" dependencies = [ - "cranelift-codegen-shared 0.82.3", + "cranelift-codegen-shared 0.85.0", ] [[package]] @@ -1209,9 +1210,9 @@ checksum = "9dabb5fe66e04d4652e434195b45ae65b5c8172d520247b8f66d8df42b2b45dc" [[package]] name = "cranelift-codegen-shared" -version = "0.82.3" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc" +checksum = "712fbebd119a476f59122b4ba51fdce893a66309b5c92bd5506bfb11a0587496" [[package]] name = "cranelift-entity" @@ -1221,9 +1222,9 @@ checksum = "3329733e4d4b8e91c809efcaa4faee80bf66f20164e3dd16d707346bd3494799" [[package]] name = "cranelift-entity" -version = "0.82.3" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf" +checksum = "4cb8b95859c4e14c9e860db78d596a904fdbe9261990233b62bd526346cb56cb" dependencies = [ "serde", ] @@ -1242,40 +1243,46 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.82.3" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" +checksum = "c7b91b19a7d1221a73f190c0e865c12be77a84f661cac89abfd4ab5820142886" dependencies = [ - "cranelift-codegen 0.82.3", + "cranelift-codegen 0.85.0", "log", "smallvec", "target-lexicon", ] +[[package]] +name = "cranelift-isle" +version = "0.85.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d4f53bc86fb458e59c695c6a95ce8346e6a8377ee7ffc058e3ac08b5f94cb1" + [[package]] name = "cranelift-native" -version = "0.82.3" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501241b0cdf903412ec9075385ac9f2b1eb18a89044d1538e97fab603231f70c" +checksum = "592f035d0ed41214dfeeb37abd536233536a27be6b4c2d39f380cd402f0cff4f" dependencies = [ - "cranelift-codegen 0.82.3", + "cranelift-codegen 0.85.0", "libc", "target-lexicon", ] [[package]] name = "cranelift-wasm" -version = "0.82.3" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d9e4211bbc3268042a96dd4de5bd979cda22434991d035f5f8eacba987fad2" +checksum = "295add6bf0b527a8bc50d02e31ff878585d2d2db53cb7e8754d6d82b84480086" dependencies = [ - "cranelift-codegen 0.82.3", - "cranelift-entity 0.82.3", - "cranelift-frontend 0.82.3", + "cranelift-codegen 0.85.0", + "cranelift-entity 0.85.0", + "cranelift-frontend 0.85.0", "itertools", "log", "smallvec", - "wasmparser 0.83.0", + "wasmparser 0.85.0", "wasmtime-types", ] @@ -2572,6 +2579,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "gcc" version = "0.3.55" @@ -5118,8 +5134,6 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" dependencies = [ - "crc32fast", - "indexmap", "memchr", ] @@ -5137,9 +5151,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "oorandom" @@ -7591,13 +7605,14 @@ dependencies = [ ] [[package]] -name = "regalloc" -version = "0.0.34" +name = "regalloc2" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" +checksum = "0d37148700dbb38f994cd99a1431613057f37ed934d7e4d799b7ab758c482461" dependencies = [ + "fxhash", "log", - "rustc-hash", + "slice-group-by", "smallvec", ] @@ -7829,9 +7844,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.33.5" +version = "0.33.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03627528abcc4a365554d32a9f3bbf67f7694c102cfeda792dc86a2d6057cc85" +checksum = "938a344304321a9da4973b9ff4f9f8db9caf4597dfd9dda6a60b523340a0fff0" dependencies = [ "bitflags", "errno", @@ -9539,6 +9554,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[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.8.0" @@ -11901,15 +11922,18 @@ checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" [[package]] name = "wasmparser" -version = "0.83.0" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" +checksum = "570460c58b21e9150d2df0eaaedbb7816c34bcec009ae0dcc976e40ba81463e7" +dependencies = [ + "indexmap", +] [[package]] name = "wasmtime" -version = "0.35.3" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21ffb4705016d5ca91e18a72ed6822dab50e6d5ddd7045461b17ef19071cdef1" +checksum = "c842f9c8e190fe01300fc8d715e9368c775670fb9856247c67abffdb5236d6db" dependencies = [ "anyhow", "backtrace", @@ -11919,7 +11943,7 @@ dependencies = [ "lazy_static", "libc", "log", - "object 0.27.1", + "object 0.28.3", "once_cell", "paste 1.0.6", "psm", @@ -11927,7 +11951,7 @@ dependencies = [ "region 2.2.0", "serde", "target-lexicon", - "wasmparser 0.83.0", + "wasmparser 0.85.0", "wasmtime-cache", "wasmtime-cranelift", "wasmtime-environ", @@ -11938,9 +11962,9 @@ dependencies = [ [[package]] name = "wasmtime-cache" -version = "0.35.3" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c6ab24291fa7cb3a181f5669f6c72599b7ef781669759b45c7828c5999d0c0" +checksum = "cce2aa752e864a33eef2a6629edc59554e75f0bc1719431dac5e49eed516af69" dependencies = [ "anyhow", "base64", @@ -11958,51 +11982,51 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "0.35.3" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04c810078a491b7bc4866ebe045f714d2b95e6b539e1f64009a4a7606be11de" +checksum = "922361eb8c03cea8909bc922471202f6c6bc2f0c682fac2fe473740441c86b3b" dependencies = [ "anyhow", - "cranelift-codegen 0.82.3", - "cranelift-entity 0.82.3", - "cranelift-frontend 0.82.3", + "cranelift-codegen 0.85.0", + "cranelift-entity 0.85.0", + "cranelift-frontend 0.85.0", "cranelift-native", "cranelift-wasm", "gimli 0.26.1", "log", "more-asserts", - "object 0.27.1", + "object 0.28.3", "target-lexicon", "thiserror", - "wasmparser 0.83.0", + "wasmparser 0.85.0", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.35.3" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61448266ea164b1ac406363cdcfac81c7c44db4d94c7a81c8620ac6c5c6cdf59" +checksum = "e602f1120fc40a3f016f1f69d08c86cfeff7b867bed1462901953e6871f85167" dependencies = [ "anyhow", - "cranelift-entity 0.82.3", + "cranelift-entity 0.85.0", "gimli 0.26.1", "indexmap", "log", "more-asserts", - "object 0.27.1", + "object 0.28.3", "serde", "target-lexicon", "thiserror", - "wasmparser 0.83.0", + "wasmparser 0.85.0", "wasmtime-types", ] [[package]] name = "wasmtime-jit" -version = "0.35.3" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "156b4623c6b0d4b8c24afb846c20525922f538ef464cc024abab7ea8de2109a2" +checksum = "49af1445759a8e797a92f27dd0983c155615648263052e0b80d69e7d223896b7" dependencies = [ "addr2line", "anyhow", @@ -12011,7 +12035,7 @@ dependencies = [ "cpp_demangle", "gimli 0.26.1", "log", - "object 0.27.1", + "object 0.28.3", "region 2.2.0", "rustc-demangle", "rustix", @@ -12026,20 +12050,20 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" -version = "0.35.3" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5dc31f811760a6c76b2672c404866fd19b75e5fb3b0075a3e377a6846490654" +checksum = "e6d5dd480cc6dc0a401653e45b79796a3317f8228990d84bc2271bdaf0810071" dependencies = [ "lazy_static", - "object 0.27.1", + "object 0.28.3", "rustix", ] [[package]] name = "wasmtime-runtime" -version = "0.35.3" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f907beaff69d4d920fa4688411ee4cc75c0f01859e424677f9e426e2ef749864" +checksum = "e875bcd02d1ecfc7d099dd58354d55d73467652eb2b103ff470fe3aecb7d0381" dependencies = [ "anyhow", "backtrace", @@ -12063,14 +12087,14 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "0.35.3" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514ef0e5fd197b9609dc9eb74beba0c84d5a12b2417cbae55534633329ba4852" +checksum = "8fd63a19ba61ac7448add4dc1fecb8d78304812af2a52dad04b89f887791b156" dependencies = [ - "cranelift-entity 0.82.3", + "cranelift-entity 0.85.0", "serde", "thiserror", - "wasmparser 0.83.0", + "wasmparser 0.85.0", ] [[package]] @@ -12328,18 +12352,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.10.0+zstd.1.5.2" +version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b1365becbe415f3f0fcd024e2f7b45bacfb5bdd055f0dc113571394114e7bdd" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.4+zstd.1.5.2" +version = "5.0.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7cd17c9af1a4d6c24beb1cc54b17e2ef7b593dc92f19e9d9acad8b182bbaee" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" dependencies = [ "libc", "zstd-sys", @@ -12347,9 +12371,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.3+zstd.1.5.2" +version = "2.0.1+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" +checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" dependencies = [ "cc", "libc", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 83859ee61be34..9d40fb53fd559 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } libc = "0.2.121" log = "0.4.17" parity-wasm = "0.42.0" -wasmtime = { version = "0.35.3", default-features = false, features = [ +wasmtime = { version = "0.38.0", default-features = false, features = [ "cache", "cranelift", "jitdump", diff --git a/client/executor/wasmtime/src/imports.rs b/client/executor/wasmtime/src/imports.rs index 4aad571029313..fae8d75854ef3 100644 --- a/client/executor/wasmtime/src/imports.rs +++ b/client/executor/wasmtime/src/imports.rs @@ -34,7 +34,7 @@ where { let mut pending_func_imports = HashMap::new(); for import_ty in module.imports() { - let name = import_name(&import_ty)?; + let name = import_ty.name(); if import_ty.module() != "env" { return Err(WasmError::Other(format!( @@ -121,13 +121,3 @@ impl<'a, 'b> sp_wasm_interface::HostFunctionRegistry for Registry<'a, 'b> { Ok(()) } } - -/// When the module linking proposal is supported the import's name can be `None`. -/// Because we are not using this proposal we could safely unwrap the name. -/// However, we opt for an error in order to avoid panics at all costs. -fn import_name<'a, 'b: 'a>(import: &'a ImportType<'b>) -> Result<&'a str, WasmError> { - let name = import.name().ok_or_else(|| { - WasmError::Other("The module linking proposal is not supported.".to_owned()) - })?; - Ok(name) -} diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 8f6826653f27d..2184dd7466a53 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -323,7 +323,6 @@ fn common_config(semantics: &Semantics) -> std::result::Result Date: Fri, 24 Jun 2022 18:21:07 -0400 Subject: [PATCH 0948/1472] Avoid a duplicate block request when syncing from a fork (#11094) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Separate queueing blocks for import from removal * Add regression tests * Remove unnecessary log * Clear queued blocks when processed * Move check out of match block * Track queued block ranges * Update client/network/sync/src/blocks.rs * Update client/network/sync/src/blocks.rs * Update client/network/sync/src/blocks.rs * Update client/network/sync/src/blocks.rs * FMT Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- client/consensus/common/src/import_queue.rs | 10 + client/network/sync/src/blocks.rs | 114 ++++++++--- client/network/sync/src/lib.rs | 200 ++++++++++++++++++-- 3 files changed, 281 insertions(+), 43 deletions(-) diff --git a/client/consensus/common/src/import_queue.rs b/client/consensus/common/src/import_queue.rs index a7b456191b000..c71e21ccd4b00 100644 --- a/client/consensus/common/src/import_queue.rs +++ b/client/consensus/common/src/import_queue.rs @@ -160,6 +160,16 @@ pub enum BlockImportStatus { ImportedUnknown(N, ImportedAux, Option), } +impl BlockImportStatus { + /// Returns the imported block number. + pub fn number(&self) -> &N { + match self { + BlockImportStatus::ImportedKnown(n, _) | + BlockImportStatus::ImportedUnknown(n, _, _) => n, + } + } +} + /// Block import error. #[derive(Debug, thiserror::Error)] pub enum BlockImportError { diff --git a/client/network/sync/src/blocks.rs b/client/network/sync/src/blocks.rs index b897184e7a44c..2cca13bfd7cc7 100644 --- a/client/network/sync/src/blocks.rs +++ b/client/network/sync/src/blocks.rs @@ -18,7 +18,7 @@ use crate::message; use libp2p::PeerId; -use log::trace; +use log::{debug, trace}; use sp_runtime::traits::{Block as BlockT, NumberFor, One}; use std::{ cmp, @@ -39,6 +39,7 @@ pub struct BlockData { enum BlockRangeState { Downloading { len: NumberFor, downloading: u32 }, Complete(Vec>), + Queued { len: NumberFor }, } impl BlockRangeState { @@ -46,6 +47,7 @@ impl BlockRangeState { match *self { Self::Downloading { len, .. } => len, Self::Complete(ref blocks) => (blocks.len() as u32).into(), + Self::Queued { len } => len, } } } @@ -56,12 +58,19 @@ pub struct BlockCollection { /// Downloaded blocks. blocks: BTreeMap, BlockRangeState>, peer_requests: HashMap>, + /// Block ranges downloaded and queued for import. + /// Maps start_hash => (start_num, end_num). + queued_blocks: HashMap, NumberFor)>, } impl BlockCollection { /// Create a new instance. pub fn new() -> Self { - Self { blocks: BTreeMap::new(), peer_requests: HashMap::new() } + Self { + blocks: BTreeMap::new(), + peer_requests: HashMap::new(), + queued_blocks: HashMap::new(), + } } /// Clear everything. @@ -170,29 +179,52 @@ impl BlockCollection { } /// Get a valid chain of blocks ordered in descending order and ready for importing into - /// blockchain. - pub fn drain(&mut self, from: NumberFor) -> Vec> { - let mut drained = Vec::new(); - let mut ranges = Vec::new(); + /// the blockchain. + pub fn ready_blocks(&mut self, from: NumberFor) -> Vec> { + let mut ready = Vec::new(); let mut prev = from; - for (start, range_data) in &mut self.blocks { - match range_data { - BlockRangeState::Complete(blocks) if *start <= prev => { - prev = *start + (blocks.len() as u32).into(); - // Remove all elements from `blocks` and add them to `drained` - drained.append(blocks); - ranges.push(*start); + for (&start, range_data) in &mut self.blocks { + if start > prev { + break + } + let len = match range_data { + BlockRangeState::Complete(blocks) => { + let len = (blocks.len() as u32).into(); + prev = start + len; + // Remove all elements from `blocks` and add them to `ready` + ready.append(blocks); + len }, + BlockRangeState::Queued { .. } => continue, _ => break, - } + }; + *range_data = BlockRangeState::Queued { len }; } - for r in ranges { - self.blocks.remove(&r); + if let Some(BlockData { block, .. }) = ready.first() { + self.queued_blocks + .insert(block.hash, (from, from + (ready.len() as u32).into())); + } + + trace!(target: "sync", "{} blocks ready for import", ready.len()); + ready + } + + pub fn clear_queued(&mut self, from_hash: &B::Hash) { + match self.queued_blocks.remove(from_hash) { + None => { + debug!(target: "sync", "Can't clear unknown queued blocks from {:?}", from_hash); + }, + Some((from, to)) => { + let mut block_num = from; + while block_num < to { + self.blocks.remove(&block_num); + block_num += One::one(); + } + trace!(target: "sync", "Cleared blocks from {:?} to {:?}", from, to); + }, } - trace!(target: "sync", "Drained {} blocks from {:?}", drained.len(), from); - drained } pub fn clear_peer_download(&mut self, who: &PeerId) { @@ -268,14 +300,14 @@ mod test { bc.clear_peer_download(&peer1); bc.insert(41, blocks[41..81].to_vec(), peer1.clone()); - assert_eq!(bc.drain(1), vec![]); + assert_eq!(bc.ready_blocks(1), vec![]); assert_eq!(bc.needed_blocks(peer1.clone(), 40, 150, 0, 1, 200), Some(121..151)); bc.clear_peer_download(&peer0); bc.insert(1, blocks[1..11].to_vec(), peer0.clone()); assert_eq!(bc.needed_blocks(peer0.clone(), 40, 150, 0, 1, 200), Some(11..41)); assert_eq!( - bc.drain(1), + bc.ready_blocks(1), blocks[1..11] .iter() .map(|b| BlockData { block: b.clone(), origin: Some(peer0.clone()) }) @@ -285,16 +317,16 @@ mod test { bc.clear_peer_download(&peer0); bc.insert(11, blocks[11..41].to_vec(), peer0.clone()); - let drained = bc.drain(12); + let ready = bc.ready_blocks(12); assert_eq!( - drained[..30], + ready[..30], blocks[11..41] .iter() .map(|b| BlockData { block: b.clone(), origin: Some(peer0.clone()) }) .collect::>()[..] ); assert_eq!( - drained[30..], + ready[30..], blocks[41..81] .iter() .map(|b| BlockData { block: b.clone(), origin: Some(peer1.clone()) }) @@ -308,17 +340,17 @@ mod test { bc.clear_peer_download(&peer1); bc.insert(121, blocks[121..150].to_vec(), peer1.clone()); - assert_eq!(bc.drain(80), vec![]); - let drained = bc.drain(81); + assert_eq!(bc.ready_blocks(80), vec![]); + let ready = bc.ready_blocks(81); assert_eq!( - drained[..40], + ready[..40], blocks[81..121] .iter() .map(|b| BlockData { block: b.clone(), origin: Some(peer2.clone()) }) .collect::>()[..] ); assert_eq!( - drained[40..], + ready[40..], blocks[121..150] .iter() .map(|b| BlockData { block: b.clone(), origin: Some(peer1.clone()) }) @@ -344,4 +376,32 @@ mod test { Some(100 + 128..100 + 128 + 128) ); } + + #[test] + fn no_duplicate_requests_on_fork() { + let mut bc = BlockCollection::new(); + assert!(is_empty(&bc)); + let peer = PeerId::random(); + + let blocks = generate_blocks(10); + + // count = 5, peer_best = 50, common = 39, max_parallel = 0, max_ahead = 200 + assert_eq!(bc.needed_blocks(peer.clone(), 5, 50, 39, 0, 200), Some(40..45)); + + // got a response on the request for `40..45` + bc.clear_peer_download(&peer); + bc.insert(40, blocks[..5].to_vec(), peer.clone()); + + // our "node" started on a fork, with its current best = 47, which is > common + let ready = bc.ready_blocks(48); + assert_eq!( + ready, + blocks[..5] + .iter() + .map(|b| BlockData { block: b.clone(), origin: Some(peer.clone()) }) + .collect::>() + ); + + assert_eq!(bc.needed_blocks(peer.clone(), 5, 50, 39, 0, 200), Some(45..50)); + } } diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index b027d77827374..4465e840c5ef5 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -1098,7 +1098,7 @@ where { self.blocks.insert(start_block, blocks, *who); } - self.drain_blocks() + self.ready_blocks() }, PeerSyncState::DownloadingGap(_) => { peer.state = PeerSyncState::Available; @@ -1112,7 +1112,7 @@ where gap = true; let blocks: Vec<_> = gap_sync .blocks - .drain(gap_sync.best_queued_number + One::one()) + .ready_blocks(gap_sync.best_queued_number + One::one()) .into_iter() .map(|block_data| { let justifications = @@ -1434,6 +1434,12 @@ where OnBlockData::Import(origin, new_blocks) } + fn update_peer_common_number(&mut self, peer_id: &PeerId, new_common: NumberFor) { + if let Some(peer) = self.peers.get_mut(peer_id) { + peer.update_common_number(new_common); + } + } + /// Handle a response from the remote to a justification request that we made. /// /// `request` must be the original request that triggered `response`. @@ -1515,9 +1521,12 @@ where for (_, hash) in &results { self.queue_blocks.remove(hash); } + if let Some(from_hash) = results.first().map(|(_, h)| h) { + self.blocks.clear_queued(from_hash); + } for (result, hash) in results { if has_error { - continue + break } if result.is_err() { @@ -1525,11 +1534,10 @@ where } match result { - Ok(BlockImportStatus::ImportedKnown(number, who)) => { - if let Some(peer) = who.and_then(|p| self.peers.get_mut(&p)) { - peer.update_common_number(number); - } - }, + Ok(BlockImportStatus::ImportedKnown(number, who)) => + if let Some(peer) = who { + self.update_peer_common_number(&peer, number); + }, Ok(BlockImportStatus::ImportedUnknown(number, aux, who)) => { if aux.clear_justification_requests { trace!( @@ -1558,8 +1566,8 @@ where } } - if let Some(peer) = who.and_then(|p| self.peers.get_mut(&p)) { - peer.update_common_number(number); + if let Some(peer) = who { + self.update_peer_common_number(&peer, number); } let state_sync_complete = self.state_sync.as_ref().map_or(false, |s| s.target() == hash); @@ -1993,11 +2001,11 @@ where // is either one further ahead or it's the one they just announced, if we know about it. if is_best { if known && self.best_queued_number >= number { - peer.update_common_number(number); + self.update_peer_common_number(&who, number); } else if announce.header.parent_hash() == &self.best_queued_hash || known_parent && self.best_queued_number >= number { - peer.update_common_number(number - One::one()); + self.update_peer_common_number(&who, number - One::one()); } } self.allowed_requests.add(&who); @@ -2071,7 +2079,7 @@ where target.peers.remove(who); !target.peers.is_empty() }); - let blocks = self.drain_blocks(); + let blocks = self.ready_blocks(); if !blocks.is_empty() { Some(self.validate_and_queue_blocks(blocks, false)) } else { @@ -2191,10 +2199,10 @@ where } } - /// Drain the downloaded block set up to the first gap. - fn drain_blocks(&mut self) -> Vec> { + /// Get the set of downloaded blocks that are ready to be queued for import. + fn ready_blocks(&mut self) -> Vec> { self.blocks - .drain(self.best_queued_number + One::one()) + .ready_blocks(self.best_queued_number + One::one()) .into_iter() .map(|block_data| { let justifications = block_data @@ -2981,6 +2989,25 @@ mod test { best_block_num += MAX_BLOCKS_TO_REQUEST as u32; + let _ = sync.on_blocks_processed( + MAX_BLOCKS_TO_REQUEST as usize, + MAX_BLOCKS_TO_REQUEST as usize, + resp_blocks + .iter() + .rev() + .map(|b| { + ( + Ok(BlockImportStatus::ImportedUnknown( + b.header().number().clone(), + Default::default(), + Some(peer_id1.clone()), + )), + b.hash(), + ) + }) + .collect(), + ); + resp_blocks .into_iter() .rev() @@ -3165,6 +3192,147 @@ mod test { ); } + #[test] + fn syncs_fork_without_duplicate_requests() { + sp_tracing::try_init_simple(); + + let mut client = Arc::new(TestClientBuilder::new().build()); + let blocks = (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 4) + .map(|_| build_block(&mut client, None, false)) + .collect::>(); + + let fork_blocks = { + let mut client = Arc::new(TestClientBuilder::new().build()); + let fork_blocks = blocks[..MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2] + .into_iter() + .inspect(|b| block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap()) + .cloned() + .collect::>(); + + fork_blocks + .into_iter() + .chain( + (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 2 + 1) + .map(|_| build_block(&mut client, None, true)), + ) + .collect::>() + }; + + let info = client.info(); + + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + Box::new(DefaultBlockAnnounceValidator), + 5, + None, + ) + .unwrap(); + + let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); + let just = (*b"TEST", Vec::new()); + client + .finalize_block(BlockId::Hash(finalized_block.hash()), Some(just)) + .unwrap(); + sync.update_chain_info(&info.best_hash, info.best_number); + + let peer_id1 = PeerId::random(); + + let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); + // Connect the node we will sync from + sync.new_peer(peer_id1.clone(), common_block.hash(), *common_block.header().number()) + .unwrap(); + + send_block_announce(fork_blocks.last().unwrap().header().clone(), &peer_id1, &mut sync); + + let mut request = + get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1); + + // Do the ancestor search + loop { + let block = &fork_blocks[unwrap_from_block_number(request.from.clone()) as usize - 1]; + let response = create_block_response(vec![block.clone()]); + + let on_block_data = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + request = match on_block_data.into_request() { + Some(req) => req.1, + // We found the ancenstor + None => break, + }; + + log::trace!(target: "sync", "Request: {:?}", request); + } + + // Now request and import the fork. + let mut best_block_num = finalized_block.header().number().clone() as u32; + let mut request = get_block_request( + &mut sync, + FromBlock::Number(MAX_BLOCKS_TO_REQUEST as u64 + best_block_num as u64), + MAX_BLOCKS_TO_REQUEST as u32, + &peer_id1, + ); + let last_block_num = *fork_blocks.last().unwrap().header().number() as u32 - 1; + while best_block_num < last_block_num { + let from = unwrap_from_block_number(request.from.clone()); + + let mut resp_blocks = fork_blocks[best_block_num as usize..from as usize].to_vec(); + resp_blocks.reverse(); + + let response = create_block_response(resp_blocks.clone()); + + let res = sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(_, blocks) if blocks.len() == MAX_BLOCKS_TO_REQUEST + ),); + + best_block_num += MAX_BLOCKS_TO_REQUEST as u32; + + if best_block_num < last_block_num { + // make sure we're not getting a duplicate request in the time before the blocks are + // processed + request = get_block_request( + &mut sync, + FromBlock::Number(MAX_BLOCKS_TO_REQUEST as u64 + best_block_num as u64), + MAX_BLOCKS_TO_REQUEST as u32, + &peer_id1, + ); + } + + let _ = sync.on_blocks_processed( + MAX_BLOCKS_TO_REQUEST as usize, + MAX_BLOCKS_TO_REQUEST as usize, + resp_blocks + .iter() + .rev() + .map(|b| { + ( + Ok(BlockImportStatus::ImportedUnknown( + b.header().number().clone(), + Default::default(), + Some(peer_id1.clone()), + )), + b.hash(), + ) + }) + .collect(), + ); + + resp_blocks + .into_iter() + .rev() + .for_each(|b| block_on(client.import(BlockOrigin::Own, b)).unwrap()); + } + + // Request the tip + get_block_request( + &mut sync, + FromBlock::Hash(fork_blocks.last().unwrap().hash()), + 1, + &peer_id1, + ); + } + #[test] fn removes_target_fork_on_disconnect() { sp_tracing::try_init_simple(); From c28702f3f2af48b3f04374d41d3f91add33e4e45 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Mon, 27 Jun 2022 16:33:58 +0200 Subject: [PATCH 0949/1472] Democracy.fast_track not allowed with zero voting period (#11666) * Democracy.fast_track not allowed with zero voting period * revert static parameter alter line * ensure voting period greater zero * update doc for fast_track * unit test: instant fast track to the next block referendum is backed * fix typos in comments --- frame/democracy/src/lib.rs | 9 ++-- frame/democracy/src/tests/fast_tracking.rs | 58 ++++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 4e11c207657f0..443b8579116d0 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -600,6 +600,8 @@ pub mod pallet { MaxVotesReached, /// Maximum number of proposals reached. TooManyProposals, + /// Voting period too low + VotingPeriodLow, } #[pallet::hooks] @@ -800,8 +802,9 @@ pub mod pallet { /// The dispatch of this call must be `FastTrackOrigin`. /// /// - `proposal_hash`: The hash of the current external proposal. - /// - `voting_period`: The period that is allowed for voting on this proposal. Increased to - /// `FastTrackVotingPeriod` if too low. + /// - `voting_period`: The period that is allowed for voting on this proposal. + /// Must be always greater than zero. + /// For `FastTrackOrigin` must be equal or greater than `FastTrackVotingPeriod`. /// - `delay`: The number of block after voting has ended in approval and this should be /// enacted. This doesn't have a minimum amount. /// @@ -830,7 +833,7 @@ pub mod pallet { T::InstantOrigin::ensure_origin(ensure_instant)?; ensure!(T::InstantAllowed::get(), Error::::InstantNotAllowed); } - + ensure!(voting_period > T::BlockNumber::zero(), Error::::VotingPeriodLow); let (e_proposal_hash, threshold) = >::get().ok_or(Error::::ProposalMissing)?; ensure!( diff --git a/frame/democracy/src/tests/fast_tracking.rs b/frame/democracy/src/tests/fast_tracking.rs index 7a15bb8de4dac..caf83c6d46120 100644 --- a/frame/democracy/src/tests/fast_tracking.rs +++ b/frame/democracy/src/tests/fast_tracking.rs @@ -67,6 +67,10 @@ fn instant_referendum_works() { Error::::InstantNotAllowed ); INSTANT_ALLOWED.with(|v| *v.borrow_mut() = true); + assert_noop!( + Democracy::fast_track(Origin::signed(6), h, 0, 0), + Error::::VotingPeriodLow + ); assert_ok!(Democracy::fast_track(Origin::signed(6), h, 1, 0)); assert_eq!( Democracy::referendum_status(0), @@ -81,6 +85,60 @@ fn instant_referendum_works() { }); } +#[test] +fn instant_next_block_referendum_backed() { + new_test_ext().execute_with(|| { + // arrange + let start_block_number = 10; + let majority_origin_id = 3; + let instant_origin_id = 6; + let voting_period = 1; + let proposal_hash = set_balance_proposal_hash_and_note(2); + let delay = 2; // has no effect on test + + // init + System::set_block_number(start_block_number); + InstantAllowed::set(true); + + // propose with majority origin + assert_ok!(Democracy::external_propose_majority( + Origin::signed(majority_origin_id), + proposal_hash + )); + + // fast track with instant origin and voting period pointing to the next block + assert_ok!(Democracy::fast_track( + Origin::signed(instant_origin_id), + proposal_hash, + voting_period, + delay + )); + + // fetch the status of the only referendum at index 0 + assert_eq!( + Democracy::referendum_status(0), + Ok(ReferendumStatus { + end: start_block_number + voting_period, + proposal_hash, + threshold: VoteThreshold::SimpleMajority, + delay, + tally: Tally { ayes: 0, nays: 0, turnout: 0 }, + }) + ); + + // referendum expected to be baked with the start of the next block + next_block(); + + // assert no active referendums + assert_noop!(Democracy::referendum_status(0), Error::::ReferendumInvalid); + // the only referendum in the storage is finished and not approved + assert_eq!( + ReferendumInfoOf::::get(0).unwrap(), + ReferendumInfo::Finished { approved: false, end: start_block_number + voting_period } + ); + }); +} + #[test] fn fast_track_referendum_fails_when_no_simple_majority() { new_test_ext().execute_with(|| { From ee3eb8f2448cc1bb978c5d1564febd351c128bb0 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 28 Jun 2022 15:54:56 +0900 Subject: [PATCH 0950/1472] Prevent unsoundness in environments with broken `madvise(MADV_DONTNEED)` (#11722) * Prevend unsoundness in environments with broken `madvise(MADV_DONTNEED)` * Add the `std` feature to `rustix` dependency Apparently not having this breaks compilation on non-nightly toolchains. * Autodetect the page size when checking whether `madvise` works * Only make sure that the madvice check doesn't return `Err` --- Cargo.lock | 89 ++++++++++++++++++++--- client/executor/wasmtime/Cargo.toml | 4 ++ client/executor/wasmtime/src/runtime.rs | 15 ++-- client/executor/wasmtime/src/util.rs | 93 ++++++++++++++++++++++++- 4 files changed, 187 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 58604b47a87da..1bf1034005284 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3113,6 +3113,12 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6" +[[package]] +name = "io-lifetimes" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24c3f4eff5495aee4c0399d7b6a0dc2b6e81be84242ffbfcf253ebacccc1d0cb" + [[package]] name = "ip_network" version = "0.4.1" @@ -3411,9 +3417,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libgit2-sys" @@ -4108,6 +4114,12 @@ version = "0.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5284f00d480e1c39af34e72f8ad60b94f47007e3481cd3b731c1d67190ddc7b7" +[[package]] +name = "linux-raw-sys" +version = "0.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" + [[package]] name = "lite-json" version = "0.1.3" @@ -6712,7 +6724,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.32.0", ] [[package]] @@ -7850,12 +7862,26 @@ checksum = "938a344304321a9da4973b9ff4f9f8db9caf4597dfd9dda6a60b523340a0fff0" dependencies = [ "bitflags", "errno", - "io-lifetimes", + "io-lifetimes 0.5.3", "libc", - "linux-raw-sys", + "linux-raw-sys 0.0.42", "winapi", ] +[[package]] +name = "rustix" +version = "0.35.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef258c11e17f5c01979a10543a30a4e12faef6aab217a74266e747eefa3aed88" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes 0.7.2", + "libc", + "linux-raw-sys 0.0.46", + "windows-sys 0.36.1", +] + [[package]] name = "rustls" version = "0.20.2" @@ -8479,9 +8505,11 @@ dependencies = [ "cfg-if 1.0.0", "libc", "log", + "once_cell", "parity-scale-codec", "parity-wasm 0.42.2", "paste 1.0.6", + "rustix 0.35.6", "sc-allocator", "sc-executor-common", "sc-runtime-test", @@ -11972,7 +12000,7 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix", + "rustix 0.33.7", "serde", "sha2 0.9.8", "toml", @@ -12038,7 +12066,7 @@ dependencies = [ "object 0.28.3", "region 2.2.0", "rustc-demangle", - "rustix", + "rustix 0.33.7", "serde", "target-lexicon", "thiserror", @@ -12056,7 +12084,7 @@ checksum = "e6d5dd480cc6dc0a401653e45b79796a3317f8228990d84bc2271bdaf0810071" dependencies = [ "lazy_static", "object 0.28.3", - "rustix", + "rustix 0.33.7", ] [[package]] @@ -12078,7 +12106,7 @@ dependencies = [ "more-asserts", "rand 0.8.4", "region 2.2.0", - "rustix", + "rustix 0.33.7", "thiserror", "wasmtime-environ", "wasmtime-jit-debug", @@ -12226,6 +12254,19 @@ dependencies = [ "windows_x86_64_msvc 0.32.0", ] +[[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_aarch64_msvc" version = "0.29.0" @@ -12238,6 +12279,12 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + [[package]] name = "windows_i686_gnu" version = "0.29.0" @@ -12250,6 +12297,12 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" +[[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_msvc" version = "0.29.0" @@ -12262,6 +12315,12 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + [[package]] name = "windows_x86_64_gnu" version = "0.29.0" @@ -12274,6 +12333,12 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" +[[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_msvc" version = "0.29.0" @@ -12286,6 +12351,12 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "winreg" version = "0.7.0" diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 9d40fb53fd559..2dcfde378bb87 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -32,6 +32,10 @@ sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime- sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-wasm-interface = { version = "6.0.0", features = ["wasmtime"], path = "../../../primitives/wasm-interface" } +[target.'cfg(target_os = "linux")'.dependencies] +rustix = { version = "0.35.6", default-features = false, features = ["std", "mm", "fs", "param"] } +once_cell = "1.12.0" + [dev-dependencies] wat = "1.0" sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 2184dd7466a53..c63a802df07cc 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -21,7 +21,7 @@ use crate::{ host::HostState, instance_wrapper::{EntryPoint, InstanceWrapper}, - util, + util::{self, replace_strategy_if_broken}, }; use sc_allocator::FreeingBumpHeapAllocator; @@ -411,6 +411,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result( code_supply_mode: CodeSupplyMode<'_>, - config: Config, + mut config: Config, ) -> std::result::Result where H: HostFunctions, { + replace_strategy_if_broken(&mut config.semantics.instantiation_strategy); + let mut wasmtime_config = common_config(&config.semantics)?; if let Some(ref cache_path) = config.cache_path { if let Err(reason) = setup_wasmtime_caching(cache_path, &mut wasmtime_config) { @@ -719,9 +723,12 @@ pub fn prepare_runtime_artifact( blob: RuntimeBlob, semantics: &Semantics, ) -> std::result::Result, WasmError> { - let blob = prepare_blob_for_compilation(blob, semantics)?; + let mut semantics = semantics.clone(); + replace_strategy_if_broken(&mut semantics.instantiation_strategy); + + let blob = prepare_blob_for_compilation(blob, &semantics)?; - let engine = Engine::new(&common_config(semantics)?) + let engine = Engine::new(&common_config(&semantics)?) .map_err(|e| WasmError::Other(format!("cannot create the engine: {}", e)))?; engine diff --git a/client/executor/wasmtime/src/util.rs b/client/executor/wasmtime/src/util.rs index 60ca598aee181..83745e21e86af 100644 --- a/client/executor/wasmtime/src/util.rs +++ b/client/executor/wasmtime/src/util.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::runtime::StoreData; +use crate::{runtime::StoreData, InstantiationStrategy}; use sc_executor_common::{ error::{Error, Result}, util::checked_range, @@ -98,3 +98,94 @@ pub(crate) fn write_memory_from( memory[range].copy_from_slice(data); Ok(()) } + +/// Checks whether the `madvise(MADV_DONTNEED)` works as expected. +/// +/// In certain environments (e.g. when running under the QEMU user-mode emulator) +/// this syscall is broken. +#[cfg(target_os = "linux")] +fn is_madvise_working() -> std::result::Result { + let page_size = rustix::param::page_size(); + + unsafe { + // Allocate two memory pages. + let pointer = rustix::mm::mmap_anonymous( + std::ptr::null_mut(), + 2 * page_size, + rustix::mm::ProtFlags::READ | rustix::mm::ProtFlags::WRITE, + rustix::mm::MapFlags::PRIVATE, + ) + .map_err(|error| format!("mmap failed: {}", error))?; + + // Dirty them both. + std::ptr::write_volatile(pointer.cast::(), b'A'); + std::ptr::write_volatile(pointer.cast::().add(page_size), b'B'); + + // Clear the first page. + let result_madvise = + rustix::mm::madvise(pointer, page_size, rustix::mm::Advice::LinuxDontNeed) + .map_err(|error| format!("madvise failed: {}", error)); + + // Fetch the values. + let value_1 = std::ptr::read_volatile(pointer.cast::()); + let value_2 = std::ptr::read_volatile(pointer.cast::().add(page_size)); + + let result_munmap = rustix::mm::munmap(pointer, 2 * page_size) + .map_err(|error| format!("munmap failed: {}", error)); + + result_madvise?; + result_munmap?; + + // Verify that the first page was cleared, while the second one was not. + Ok(value_1 == 0 && value_2 == b'B') + } +} + +#[cfg(test)] +#[cfg(target_os = "linux")] +#[test] +fn test_is_madvise_working_check_does_not_fail() { + assert!(is_madvise_working().is_ok()); +} + +/// Checks whether a given instantiation strategy can be safely used, and replaces +/// it with a slower (but sound) alternative if it isn't. +#[cfg(target_os = "linux")] +pub(crate) fn replace_strategy_if_broken(strategy: &mut InstantiationStrategy) { + let replacement_strategy = match *strategy { + // These strategies don't need working `madvise`. + InstantiationStrategy::Pooling | InstantiationStrategy::RecreateInstance => return, + + // These strategies require a working `madvise` to be sound. + InstantiationStrategy::PoolingCopyOnWrite => InstantiationStrategy::Pooling, + InstantiationStrategy::RecreateInstanceCopyOnWrite | + InstantiationStrategy::LegacyInstanceReuse => InstantiationStrategy::RecreateInstance, + }; + + use once_cell::sync::OnceCell; + static IS_OK: OnceCell = OnceCell::new(); + + let is_ok = IS_OK.get_or_init(|| { + let is_ok = match is_madvise_working() { + Ok(is_ok) => is_ok, + Err(error) => { + // This should never happen. + log::warn!("Failed to check whether `madvise(MADV_DONTNEED)` works: {}", error); + false + } + }; + + if !is_ok { + log::warn!("You're running on a system with a broken `madvise(MADV_DONTNEED)` implementation. This will result in lower performance."); + } + + is_ok + }); + + if !is_ok { + *strategy = replacement_strategy; + } +} + +#[cfg(not(target_os = "linux"))] +pub(crate) fn replace_strategy_if_broken(_: &mut InstantiationStrategy) {} From f39769740858bf480ef13adbfd46267afce92eb9 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 29 Jun 2022 17:39:56 +0100 Subject: [PATCH 0951/1472] Refund weight in `system::fillBlock` (#11754) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix * pushed * node: fix fee multiplier test Co-authored-by: André Silva --- Cargo.lock | 1 + bin/node/executor/Cargo.toml | 1 + bin/node/executor/tests/fees.rs | 6 ++++-- frame/system/src/lib.rs | 13 +++++++++++-- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1bf1034005284..d68330cfb15c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4732,6 +4732,7 @@ dependencies = [ "pallet-balances", "pallet-contracts", "pallet-im-online", + "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", "pallet-treasury", diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 5fbf59a74fdcd..6143ea3bd8c42 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -34,6 +34,7 @@ node-testing = { version = "3.0.0-dev", path = "../testing" } pallet-balances = { version = "4.0.0-dev", path = "../../../frame/balances" } pallet-contracts = { version = "4.0.0-dev", path = "../../../frame/contracts" } pallet-im-online = { version = "4.0.0-dev", path = "../../../frame/im-online" } +pallet-sudo = { version = "4.0.0-dev", path = "../../../frame/sudo" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } pallet-treasury = { version = "4.0.0-dev", path = "../../../frame/treasury" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index cf794bae1d307..e1550071d3006 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -58,8 +58,10 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(0, 0))), - function: Call::System(frame_system::Call::fill_block { - ratio: Perbill::from_percent(60), + function: Call::Sudo(pallet_sudo::Call::sudo { + call: Box::new(Call::System(frame_system::Call::fill_block { + ratio: Perbill::from_percent(60), + })), }), }, ], diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 370a802665918..3c6f514808b5d 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -197,6 +197,7 @@ impl, MaxOverflow: Get> ConsumerLimits for (MaxNormal, pub mod pallet { use crate::{self as frame_system, pallet_prelude::*, *}; use frame_support::pallet_prelude::*; + use sp_runtime::DispatchErrorWithPostInfo; /// System configuration trait. Implemented by runtime. #[pallet::config] @@ -371,8 +372,16 @@ pub mod pallet { // that's not possible at present (since it's within the pallet macro). #[pallet::weight(*_ratio * T::BlockWeights::get().max_block)] pub fn fill_block(origin: OriginFor, _ratio: Perbill) -> DispatchResultWithPostInfo { - ensure_root(origin)?; - Ok(().into()) + match ensure_root(origin) { + Ok(_) => Ok(().into()), + Err(_) => { + // roughly same as a 4 byte remark since perbill is u32. + Err(DispatchErrorWithPostInfo { + post_info: Some(T::SystemWeightInfo::remark(4u32)).into(), + error: DispatchError::BadOrigin, + }) + }, + } } /// Make some on-chain remark. From 279593d87f103fa5e10c9751a97b1584f3ad79d6 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Thu, 30 Jun 2022 12:02:57 +0200 Subject: [PATCH 0952/1472] nomination-pools fix (#11748) * Nomination pool fix * fmt --- frame/nomination-pools/src/lib.rs | 8 ++++---- frame/nomination-pools/src/mock.rs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 19155a51405b0..d43d43c806d61 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -43,7 +43,7 @@ //! //! ### Join //! -//! A account can stake funds with a nomination pool by calling [`Call::join`]. +//! An account can stake funds with a nomination pool by calling [`Call::join`]. //! //! ### Claim rewards //! @@ -87,7 +87,7 @@ //! [`Call::unbond`] and [`Call::withdraw_unbonded`]. Once a pool is in destroying state, it //! cannot be reverted to another state. //! -//! A pool has 3 administrative roles (see [`PoolRoles`]): +//! A pool has 4 administrative roles (see [`PoolRoles`]): //! //! * Depositor: creates the pool and is the initial member. They can only leave the pool once all //! other members have left. Once they fully leave the pool is destroyed. @@ -297,8 +297,8 @@ //! * PoolMembers cannot vote with their staked funds because they are transferred into the pools //! account. In the future this can be overcome by allowing the members to vote with their bonded //! funds via vote splitting. -//! * PoolMembers cannot quickly transfer to another pool if they do no like nominations, instead -//! they must wait for the unbonding duration. +//! * PoolMembers cannot quickly transfer to another pool if they do not like the nominations, +//! instead they must wait for the unbonding duration. //! //! # Runtime builder warnings //! diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index a3020e5add044..7d71efc3be04d 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -111,6 +111,7 @@ impl sp_staking::StakingInterface for StakingMock { Ok(()) } + #[cfg(feature = "runtime-benchmarks")] fn nominations(_: Self::AccountId) -> Option> { Nominations::get() } From 3080d3264c97cbe19843cfe708a7ac226309b7fa Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 5 Jul 2022 09:48:37 +0200 Subject: [PATCH 0953/1472] [ci] Remove polkadot-companion-labels GHA (#11774) --- .../workflows/polkadot-companion-labels.yml | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 .github/workflows/polkadot-companion-labels.yml diff --git a/.github/workflows/polkadot-companion-labels.yml b/.github/workflows/polkadot-companion-labels.yml deleted file mode 100644 index 0a5af09358524..0000000000000 --- a/.github/workflows/polkadot-companion-labels.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Check Polkadot Companion and Label - -on: - pull_request: - types: [opened, synchronize] - -jobs: - check_status: - runs-on: ubuntu-latest - steps: - - name: Monitor the status of the gitlab-check-companion-build job - uses: s3krit/await-status-action@v1.0.1 - id: 'check-companion-status' - with: - authToken: ${{ secrets.GITHUB_TOKEN }} - ref: ${{ github.event.pull_request.head.sha }} - contexts: 'continuous-integration/gitlab-check-dependent-polkadot' - timeout: 1800 - notPresentTimeout: 3600 # It can take quite a while before the job starts on Gitlab when the CI queue is large - failureStates: failure - interruptedStates: error # Error = job was probably cancelled. We don't want to label the PR in that case - pollInterval: 30 - - name: Label success - uses: andymckay/labeler@master - if: steps.check-companion-status.outputs.result == 'success' - with: - remove-labels: 'A7-needspolkadotpr' - - name: Label failure - uses: andymckay/labeler@master - if: steps.check-companion-status.outputs.result == 'failure' - with: - add-labels: 'A7-needspolkadotpr' From 6a946fc36d68b89599d7ca1ab03803d10c78468c Mon Sep 17 00:00:00 2001 From: GreenBaneling | Supercolony Date: Tue, 5 Jul 2022 11:12:16 +0100 Subject: [PATCH 0954/1472] [contracts] Fixed the bug with transfer value for delegate call (#11771) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed the bug with transfer value. * Apply suggestions from code review Co-authored-by: Alexander Theißen * Moved check into `initial_transfer` * Fmt Co-authored-by: Alexander Theißen --- frame/contracts/src/exec.rs | 86 ++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index ec7e1e9335182..d93c646872c6f 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -797,7 +797,7 @@ where )?; } - // Every call or instantiate also optionally transferres balance. + // Every non delegate call or instantiate also optionally transfers the balance. self.initial_transfer()?; // Call into the wasm blob. @@ -959,8 +959,14 @@ where // The transfer as performed by a call or instantiate. fn initial_transfer(&self) -> DispatchResult { let frame = self.top_frame(); - let value = frame.value_transferred; + // If it is a delegate call, then we've already transferred tokens in the + // last non-delegate frame. + if frame.delegate_caller.is_some() { + return Ok(()) + } + + let value = frame.value_transferred; Self::transfer(ExistenceRequirement::KeepAlive, self.caller(), &frame.account_id, value) } @@ -1560,6 +1566,82 @@ mod tests { }); } + #[test] + fn correct_transfer_on_call() { + let origin = ALICE; + let dest = BOB; + let value = 55; + + let success_ch = MockLoader::insert(Call, move |ctx, _| { + assert_eq!(ctx.ext.value_transferred(), value); + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + }); + + ExtBuilder::default().build().execute_with(|| { + let schedule = ::Schedule::get(); + place_contract(&dest, success_ch); + set_balance(&origin, 100); + let balance = get_balance(&dest); + let mut storage_meter = storage::meter::Meter::new(&origin, Some(0), 55).unwrap(); + + let _ = MockStack::run_call( + origin.clone(), + dest.clone(), + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + &schedule, + value, + vec![], + None, + ) + .unwrap(); + + assert_eq!(get_balance(&origin), 100 - value); + assert_eq!(get_balance(&dest), balance + value); + }); + } + + #[test] + fn correct_transfer_on_delegate_call() { + let origin = ALICE; + let dest = BOB; + let value = 35; + + let success_ch = MockLoader::insert(Call, move |ctx, _| { + assert_eq!(ctx.ext.value_transferred(), value); + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + }); + + let delegate_ch = MockLoader::insert(Call, move |ctx, _| { + assert_eq!(ctx.ext.value_transferred(), value); + let _ = ctx.ext.delegate_call(success_ch, Vec::new())?; + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + }); + + ExtBuilder::default().build().execute_with(|| { + let schedule = ::Schedule::get(); + place_contract(&dest, delegate_ch); + set_balance(&origin, 100); + let balance = get_balance(&dest); + let mut storage_meter = storage::meter::Meter::new(&origin, Some(0), 55).unwrap(); + + let _ = MockStack::run_call( + origin.clone(), + dest.clone(), + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + &schedule, + value, + vec![], + None, + ) + .unwrap(); + + assert_eq!(get_balance(&origin), 100 - value); + assert_eq!(get_balance(&dest), balance + value); + }); + } + #[test] fn changes_are_reverted_on_failing_call() { // This test verifies that changes are reverted on a call which fails (or equally, returns From 09154359f98e4ca5c121ad33685840b4dfd1f9de Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Thu, 7 Jul 2022 16:24:06 +0200 Subject: [PATCH 0955/1472] Fix clearing queued blocks in the sync module (#11763) --- client/network/sync/src/blocks.rs | 21 ++++++--------- client/network/sync/src/lib.rs | 43 +++++++++++++++++++------------ 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/client/network/sync/src/blocks.rs b/client/network/sync/src/blocks.rs index 2cca13bfd7cc7..8d9b039b14fba 100644 --- a/client/network/sync/src/blocks.rs +++ b/client/network/sync/src/blocks.rs @@ -18,7 +18,7 @@ use crate::message; use libp2p::PeerId; -use log::{debug, trace}; +use log::trace; use sp_runtime::traits::{Block as BlockT, NumberFor, One}; use std::{ cmp, @@ -212,18 +212,13 @@ impl BlockCollection { } pub fn clear_queued(&mut self, from_hash: &B::Hash) { - match self.queued_blocks.remove(from_hash) { - None => { - debug!(target: "sync", "Can't clear unknown queued blocks from {:?}", from_hash); - }, - Some((from, to)) => { - let mut block_num = from; - while block_num < to { - self.blocks.remove(&block_num); - block_num += One::one(); - } - trace!(target: "sync", "Cleared blocks from {:?} to {:?}", from, to); - }, + if let Some((from, to)) = self.queued_blocks.remove(from_hash) { + let mut block_num = from; + while block_num < to { + self.blocks.remove(&block_num); + block_num += One::one(); + } + trace!(target: "sync", "Cleared blocks from {:?} to {:?}", from, to); } } diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 4465e840c5ef5..5b5216c745c98 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -1520,9 +1520,7 @@ where let mut has_error = false; for (_, hash) in &results { self.queue_blocks.remove(hash); - } - if let Some(from_hash) = results.first().map(|(_, h)| h) { - self.blocks.clear_queued(from_hash); + self.blocks.clear_queued(hash); } for (result, hash) in results { if has_error { @@ -3299,23 +3297,34 @@ mod test { ); } + let mut notify_imported: Vec<_> = resp_blocks + .iter() + .rev() + .map(|b| { + ( + Ok(BlockImportStatus::ImportedUnknown( + b.header().number().clone(), + Default::default(), + Some(peer_id1.clone()), + )), + b.hash(), + ) + }) + .collect(); + + // The import queue may send notifications in batches of varying size. So we simulate + // this here by splitting the batch into 2 notifications. + let second_batch = notify_imported.split_off(notify_imported.len() / 2); let _ = sync.on_blocks_processed( MAX_BLOCKS_TO_REQUEST as usize, MAX_BLOCKS_TO_REQUEST as usize, - resp_blocks - .iter() - .rev() - .map(|b| { - ( - Ok(BlockImportStatus::ImportedUnknown( - b.header().number().clone(), - Default::default(), - Some(peer_id1.clone()), - )), - b.hash(), - ) - }) - .collect(), + notify_imported, + ); + + let _ = sync.on_blocks_processed( + MAX_BLOCKS_TO_REQUEST as usize, + MAX_BLOCKS_TO_REQUEST as usize, + second_batch, ); resp_blocks From 6c5ac3168d7ce4810648d667969c82b1db9950ac Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 7 Jul 2022 18:02:37 +0300 Subject: [PATCH 0956/1472] pallet-mmr: handle forks without collisions in offchain storage (#11594) * pallet-mmr: fix some typos * pallet-mmr: make the MMR resilient to chain forks * pallet-mmr: get hash for block that added node * beefy-mmr: add debug logging * add explanatory comment * account for block offset of pallet activation * add support for finding all nodes added by leaf * minor improvements * add helper to return all nodes added to mmr with a leaf append * simplify leaf_node_index_to_leaf_index summing the (shifted) differences in peak positions adds up to the (shifted) final position, so don't need to fold over positions. * dead fish: this also doesn't work The idea was to keep a rolling window of `(parent_hash, pos)` leaf entries in the offchain db, with the window matching the one that provides `block_num -> block_hash` mappings in `frame_system`. Once a leaf exits the window it would be "canonicalized" by switching its offchain db key from `(parent_hash, pos)` to simple `pos`. This doesn't work however because there's no way to get leaf contents from offchain db while in runtime context.. so no way to get+clear+set leaf to change its key in offchain db. Ideas: 1. move the "canonicalization" logic to offchain worker 2. enhance IndexingApi with "offchain::move(old_key, new_key)" This is weird, but correct, deterministic and safe AFAICT, so it could be exposed to runtime. * simplify rightmost_leaf_node_index_from_pos * minor fix * move leaf canonicalization to offchain worker * move storage related code to storage.rs * on offchain reads use canonic key for old leaves * fix offchain worker write using canon key * fix pallet-mmr tests * add documentation and fix logging * add offchain mmr canonicalization test * test canon + generate + verify * fix pallet-beefy-mmr tests * implement review suggestions * improve test * pallet-mmr: add offchain pruning of forks * pallet-mmr: improve offchain pruning Instead of keeping pruning map as single blob in offchain db, keep individual parent-hash lists with block-num identifier as part of the offchain key. Signed-off-by: acatangiu * pallet-mmr: improve MMRStore::get() Do the math and retrieve node using correct (canon or non-canon) offchain db key, instead of blindly looking in both canon and non-canon offchain db locations for each node. Still fallback on looking at both if for any reason it's not where expected. Signed-off-by: acatangiu * pallet-mmr: storage: improve logs * fix tests: correctly persist overlay runtime indexing API works on overlay, whereas offchain context bypasses overlay, so for loops > canon-window, canon would fail. * pallet-mmr: fix numeric typo in test * add comment around LeafData requirements Signed-off-by: acatangiu Co-authored-by: Robert Hambrock --- frame/beefy-mmr/src/tests.rs | 22 +- frame/merkle-mountain-range/src/lib.rs | 71 ++++- .../merkle-mountain-range/src/mmr/storage.rs | 228 +++++++++++++- frame/merkle-mountain-range/src/mmr/utils.rs | 68 +++++ frame/merkle-mountain-range/src/tests.rs | 287 ++++++++++++++++-- primitives/merkle-mountain-range/src/lib.rs | 12 +- 6 files changed, 635 insertions(+), 53 deletions(-) diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index d9cd8c8a5d8c8..eaa50004ae848 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -44,16 +44,12 @@ pub fn beefy_log(log: ConsensusLog) -> DigestItem { DigestItem::Consensus(BEEFY_ENGINE_ID, log.encode()) } -fn offchain_key(pos: usize) -> Vec { - (::INDEXING_PREFIX, pos as u64).encode() -} - -fn read_mmr_leaf(ext: &mut TestExternalities, index: usize) -> MmrLeaf { +fn read_mmr_leaf(ext: &mut TestExternalities, key: Vec) -> MmrLeaf { type Node = pallet_mmr::primitives::DataOrHash; ext.persist_offchain_overlay(); let offchain_db = ext.offchain_db(); offchain_db - .get(&offchain_key(index)) + .get(&key) .map(|d| Node::decode(&mut &*d).unwrap()) .map(|n| match n { Node::Data(d) => d, @@ -105,12 +101,17 @@ fn should_contain_mmr_digest() { #[test] fn should_contain_valid_leaf_data() { + fn node_offchain_key(parent_hash: H256, pos: usize) -> Vec { + (::INDEXING_PREFIX, parent_hash, pos as u64).encode() + } + let mut ext = new_test_ext(vec![1, 2, 3, 4]); - ext.execute_with(|| { + let parent_hash = ext.execute_with(|| { init_block(1); + >::parent_hash() }); - let mmr_leaf = read_mmr_leaf(&mut ext, 0); + let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(parent_hash, 0)); assert_eq!( mmr_leaf, MmrLeaf { @@ -128,11 +129,12 @@ fn should_contain_valid_leaf_data() { ); // build second block on top - ext.execute_with(|| { + let parent_hash = ext.execute_with(|| { init_block(2); + >::parent_hash() }); - let mmr_leaf = read_mmr_leaf(&mut ext, 1); + let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(parent_hash, 1)); assert_eq!( mmr_leaf, MmrLeaf { diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index d6cf3240692fc..9274e8e72c508 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -58,7 +58,10 @@ use codec::Encode; use frame_support::weights::Weight; -use sp_runtime::traits::{self, One, Saturating}; +use sp_runtime::{ + traits::{self, One, Saturating}, + SaturatedConversion, +}; #[cfg(any(feature = "runtime-benchmarks", test))] mod benchmarking; @@ -116,12 +119,12 @@ pub mod pallet { /// Prefix for elements stored in the Off-chain DB via Indexing API. /// /// Each node of the MMR is inserted both on-chain and off-chain via Indexing API. - /// The former does not store full leaf content, just it's compact version (hash), + /// The former does not store full leaf content, just its compact version (hash), /// and some of the inner mmr nodes might be pruned from on-chain storage. /// The latter will contain all the entries in their full form. /// /// Each node is stored in the Off-chain DB under key derived from the - /// [`Self::INDEXING_PREFIX`] and it's in-tree index (MMR position). + /// [`Self::INDEXING_PREFIX`] and its in-tree index (MMR position). const INDEXING_PREFIX: &'static [u8]; /// A hasher type for MMR. @@ -162,6 +165,12 @@ pub mod pallet { /// /// Note that the leaf at each block MUST be unique. You may want to include a block hash or /// block number as an easiest way to ensure that. + /// Also note that the leaf added by each block is expected to only reference data coming + /// from ancestor blocks (leaves are saved offchain using `(parent_hash, pos)` key to be + /// fork-resistant, as such conflicts could only happen on 1-block deep forks, which means + /// two forks with identical line of ancestors compete to write the same offchain key, but + /// that's fine as long as leaves only contain data coming from ancestors - conflicting + /// writes are identical). type LeafData: primitives::LeafDataProvider; /// A hook to act on the new MMR root. @@ -215,8 +224,31 @@ pub mod pallet { >::put(root); let peaks_after = mmr::utils::NodesUtils::new(leaves).number_of_peaks(); + T::WeightInfo::on_initialize(peaks_before.max(peaks_after)) } + + fn offchain_worker(n: T::BlockNumber) { + use mmr::storage::{OffchainStorage, Storage}; + // MMR pallet uses offchain storage to hold full MMR and leaves. + // The leaves are saved under fork-unique keys `(parent_hash, pos)`. + // MMR Runtime depends on `frame_system::block_hash(block_num)` mappings to find + // parent hashes for particular nodes or leaves. + // This MMR offchain worker function moves a rolling window of the same size + // as `frame_system::block_hash` map, where nodes/leaves added by blocks that are just + // about to exit the window are "canonicalized" so that their offchain key no longer + // depends on `parent_hash` therefore on access to `frame_system::block_hash`. + // + // This approach works to eliminate fork-induced leaf collisions in offchain db, + // under the assumption that no fork will be deeper than `frame_system::BlockHashCount` + // blocks (2400 blocks on Polkadot, Kusama, Rococo, etc): + // entries pertaining to block `N` where `N < current-2400` are moved to a key based + // solely on block number. The only way to have collisions is if two competing forks + // are deeper than 2400 blocks and they both "canonicalize" their view of block `N`. + // Once a block is canonicalized, all MMR entries pertaining to sibling blocks from + // other forks are pruned from offchain db. + Storage::>::canonicalize_and_prune(n); + } } } @@ -254,9 +286,38 @@ where } impl, I: 'static> Pallet { - fn offchain_key(pos: NodeIndex) -> sp_std::prelude::Vec { + /// Build offchain key from `parent_hash` of block that originally added node `pos` to MMR. + /// + /// This combination makes the offchain (key,value) entry resilient to chain forks. + fn node_offchain_key( + parent_hash: ::Hash, + pos: NodeIndex, + ) -> sp_std::prelude::Vec { + (T::INDEXING_PREFIX, parent_hash, pos).encode() + } + + /// Build canonical offchain key for node `pos` in MMR. + /// + /// Used for nodes added by now finalized blocks. + fn node_canon_offchain_key(pos: NodeIndex) -> sp_std::prelude::Vec { (T::INDEXING_PREFIX, pos).encode() } + + /// Provide the parent number for the block that added `leaf_index` to the MMR. + fn leaf_index_to_parent_block_num( + leaf_index: LeafIndex, + leaves_count: LeafIndex, + ) -> ::BlockNumber { + // leaves are zero-indexed and were added one per block since pallet activation, + // while block numbers are one-indexed, so block number that added `leaf_idx` is: + // `block_num = block_num_when_pallet_activated + leaf_idx + 1` + // `block_num = (current_block_num - leaves_count) + leaf_idx + 1` + // `parent_block_num = current_block_num - leaves_count + leaf_idx`. + >::block_number() + .saturating_sub(leaves_count.saturated_into()) + .saturating_add(leaf_index.saturated_into()) + } + /// Generate a MMR proof for the given `leaf_indices`. /// /// Note this method can only be used from an off-chain context @@ -264,7 +325,7 @@ impl, I: 'static> Pallet { /// all the leaves to be present. /// It may return an error or panic if used incorrectly. pub fn generate_batch_proof( - leaf_indices: Vec, + leaf_indices: Vec, ) -> Result< (Vec>, primitives::BatchProof<>::Hash>), primitives::Error, diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index 535057ca80da7..d31262d4d7f2f 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -18,8 +18,11 @@ //! A MMR storage implementations. use codec::Encode; +use frame_support::traits::Get; use mmr_lib::helper; -use sp_io::offchain_index; +use sp_core::offchain::StorageKind; +use sp_io::{offchain, offchain_index}; +use sp_runtime::traits::UniqueSaturatedInto; use sp_std::iter::Peekable; #[cfg(not(feature = "std"))] use sp_std::prelude::*; @@ -46,6 +49,51 @@ pub struct RuntimeStorage; /// DOES NOT support adding new items to the MMR. pub struct OffchainStorage; +/// Suffix of key for the 'pruning_map'. +/// +/// Nodes and leaves are initially saved under fork-specific keys in offchain db, +/// eventually they are "canonicalized" and this map is used to prune non-canon entries. +const OFFCHAIN_PRUNING_MAP_KEY_SUFFIX: &str = "pruning_map"; + +/// Used to store offchain mappings of `BlockNumber -> Vec[Hash]` to track all forks. +/// Size of this offchain map is at most `frame_system::BlockHashCount`, its entries are pruned +/// as part of the mechanism that prunes the forks this map tracks. +pub(crate) struct PruningMap(sp_std::marker::PhantomData<(T, I)>); +impl PruningMap +where + T: Config, + I: 'static, +{ + pub(crate) fn pruning_map_offchain_key(block: T::BlockNumber) -> sp_std::prelude::Vec { + (T::INDEXING_PREFIX, block, OFFCHAIN_PRUNING_MAP_KEY_SUFFIX).encode() + } + + /// Append `hash` to the list of parent hashes for `block` in offchain db. + pub fn append(block: T::BlockNumber, hash: ::Hash) { + let map_key = Self::pruning_map_offchain_key(block); + offchain::local_storage_get(StorageKind::PERSISTENT, &map_key) + .and_then(|v| codec::Decode::decode(&mut &*v).ok()) + .or_else(|| Some(Vec::<::Hash>::new())) + .map(|mut parents| { + parents.push(hash); + offchain::local_storage_set( + StorageKind::PERSISTENT, + &map_key, + &Encode::encode(&parents), + ); + }); + } + + /// Remove list of parent hashes for `block` from offchain db and return it. + pub fn remove(block: T::BlockNumber) -> Option::Hash>> { + let map_key = Self::pruning_map_offchain_key(block); + offchain::local_storage_get(StorageKind::PERSISTENT, &map_key).and_then(|v| { + offchain::local_storage_clear(StorageKind::PERSISTENT, &map_key); + codec::Decode::decode(&mut &*v).ok() + }) + } +} + /// A storage layer for MMR. /// /// There are two different implementations depending on the use case. @@ -58,6 +106,109 @@ impl Default for Storage { } } +impl Storage +where + T: Config, + I: 'static, + L: primitives::FullLeaf, +{ + /// Move nodes and leaves added by block `N` in offchain db from _fork-aware key_ to + /// _canonical key_, + /// where `N` is `frame_system::BlockHashCount` blocks behind current block number. + /// + /// This "canonicalization" process is required because the _fork-aware key_ value depends + /// on `frame_system::block_hash(block_num)` map which only holds the last + /// `frame_system::BlockHashCount` blocks. + /// + /// For the canonicalized block, prune all nodes pertaining to other forks from offchain db. + /// + /// Should only be called from offchain context, because it requires both read and write + /// access to offchain db. + pub(crate) fn canonicalize_and_prune(block: T::BlockNumber) { + // Add "block_num -> hash" mapping to offchain db, + // with all forks pushing hashes to same entry (same block number). + let parent_hash = >::parent_hash(); + PruningMap::::append(block, parent_hash); + + // Effectively move a rolling window of fork-unique leaves. Once out of the window, leaves + // are "canonicalized" in offchain by moving them under `Pallet::node_canon_offchain_key`. + let leaves = NumberOfLeaves::::get(); + let window_size = + ::BlockHashCount::get().unique_saturated_into(); + if leaves >= window_size { + // Move the rolling window towards the end of `block_num->hash` mappings available + // in the runtime: we "canonicalize" the leaf at the end, + let to_canon_leaf = leaves.saturating_sub(window_size); + // and all the nodes added by that leaf. + let to_canon_nodes = NodesUtils::right_branch_ending_in_leaf(to_canon_leaf); + frame_support::log::debug!( + target: "runtime::mmr::offchain", "Nodes to canon for leaf {}: {:?}", + to_canon_leaf, to_canon_nodes + ); + // For this block number there may be node entries saved from multiple forks. + let to_canon_block_num = + Pallet::::leaf_index_to_parent_block_num(to_canon_leaf, leaves); + // Only entries under this hash (retrieved from state on current canon fork) are to be + // persisted. All other entries added by same block number will be cleared. + let to_canon_hash = >::block_hash(to_canon_block_num); + + Self::canonicalize_nodes_for_hash(&to_canon_nodes, to_canon_hash); + // Get all the forks to prune, also remove them from the offchain pruning_map. + PruningMap::::remove(to_canon_block_num) + .map(|forks| { + Self::prune_nodes_for_forks(&to_canon_nodes, forks); + }) + .unwrap_or_else(|| { + frame_support::log::error!( + target: "runtime::mmr::offchain", + "Offchain: could not prune: no entry in pruning map for block {:?}", + to_canon_block_num + ); + }) + } + } + + fn prune_nodes_for_forks(nodes: &[NodeIndex], forks: Vec<::Hash>) { + for hash in forks { + for pos in nodes { + let key = Pallet::::node_offchain_key(hash, *pos); + frame_support::log::debug!( + target: "runtime::mmr::offchain", + "Clear elem at pos {} with key {:?}", + pos, key + ); + offchain::local_storage_clear(StorageKind::PERSISTENT, &key); + } + } + } + + fn canonicalize_nodes_for_hash( + to_canon_nodes: &[NodeIndex], + to_canon_hash: ::Hash, + ) { + for pos in to_canon_nodes { + let key = Pallet::::node_offchain_key(to_canon_hash, *pos); + // Retrieve the element from Off-chain DB under fork-aware key. + if let Some(elem) = offchain::local_storage_get(StorageKind::PERSISTENT, &key) { + let canon_key = Pallet::::node_canon_offchain_key(*pos); + // Add under new canon key. + offchain::local_storage_set(StorageKind::PERSISTENT, &canon_key, &elem); + frame_support::log::debug!( + target: "runtime::mmr::offchain", + "Moved elem at pos {} from key {:?} to canon key {:?}", + pos, key, canon_key + ); + } else { + frame_support::log::error!( + target: "runtime::mmr::offchain", + "Could not canonicalize elem at pos {} using key {:?}", + pos, key + ); + } + } + } +} + impl mmr_lib::MMRStore> for Storage where T: Config, @@ -65,9 +216,49 @@ where L: primitives::FullLeaf + codec::Decode, { fn get_elem(&self, pos: NodeIndex) -> mmr_lib::Result>> { - let key = Pallet::::offchain_key(pos); + let leaves = NumberOfLeaves::::get(); + // Find out which leaf added node `pos` in the MMR. + let ancestor_leaf_idx = NodesUtils::leaf_index_that_added_node(pos); + + let window_size = + ::BlockHashCount::get().unique_saturated_into(); + // Leaves older than this window should have been canonicalized. + if leaves.saturating_sub(ancestor_leaf_idx) > window_size { + let key = Pallet::::node_canon_offchain_key(pos); + frame_support::log::debug!( + target: "runtime::mmr::offchain", "offchain db get {}: leaf idx {:?}, key {:?}", + pos, ancestor_leaf_idx, key + ); + // Just for safety, to easily handle runtime upgrades where any of the window params + // change and maybe we mess up storage migration, + // return _if and only if_ node is found (in normal conditions it's always found), + if let Some(elem) = + sp_io::offchain::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) + { + return Ok(codec::Decode::decode(&mut &*elem).ok()) + } + // BUT if we DID MESS UP, fall through to searching node using fork-specific key. + } + + // Leaves still within the window will be found in offchain db under fork-aware keys. + let ancestor_parent_block_num = + Pallet::::leaf_index_to_parent_block_num(ancestor_leaf_idx, leaves); + let ancestor_parent_hash = >::block_hash(ancestor_parent_block_num); + let key = Pallet::::node_offchain_key(ancestor_parent_hash, pos); + frame_support::log::debug!( + target: "runtime::mmr::offchain", "offchain db get {}: leaf idx {:?}, hash {:?}, key {:?}", + pos, ancestor_leaf_idx, ancestor_parent_hash, key + ); // Retrieve the element from Off-chain DB. Ok(sp_io::offchain::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) + .or_else(|| { + // Again, this is just us being extra paranoid. + // We get here only if we mess up a storage migration for a runtime upgrades where + // say the window is increased, and for a little while following the upgrade there's + // leaves inside new 'window' that had been already canonicalized before upgrade. + let key = Pallet::::node_canon_offchain_key(pos); + sp_io::offchain::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) + }) .and_then(|v| codec::Decode::decode(&mut &*v).ok())) } @@ -91,9 +282,11 @@ where return Ok(()) } - sp_std::if_std! { - frame_support::log::trace!("elems: {:?}", elems.iter().map(|elem| elem.hash()).collect::>()); - } + frame_support::log::trace!( + target: "runtime::mmr", + "elems: {:?}", + elems.iter().map(|elem| elem.hash()).collect::>() + ); let leaves = NumberOfLeaves::::get(); let size = NodesUtils::new(leaves).size(); @@ -112,11 +305,24 @@ where let mut leaf_index = leaves; let mut node_index = size; + // Use parent hash of block adding new nodes (this block) as extra identifier + // in offchain DB to avoid DB collisions and overwrites in case of forks. + let parent_hash = >::parent_hash(); for elem in elems { + // For now we store this leaf offchain keyed by `(parent_hash, node_index)` + // to make it fork-resistant. + // Offchain worker task will "canonicalize" it `frame_system::BlockHashCount` blocks + // later when we are not worried about forks anymore (highly unlikely to have a fork + // in the chain that deep). + // "Canonicalization" in this case means moving this leaf under a new key based + // only on the leaf's `node_index`. + let key = Pallet::::node_offchain_key(parent_hash, node_index); + frame_support::log::debug!( + target: "runtime::mmr::offchain", "offchain db set: pos {} parent_hash {:?} key {:?}", + node_index, parent_hash, key + ); // Indexing API is used to store the full node content (both leaf and inner). - elem.using_encoded(|elem| { - offchain_index::set(&Pallet::::offchain_key(node_index), elem) - }); + elem.using_encoded(|elem| offchain_index::set(&key, elem)); // On-chain we are going to only store new peaks. if peaks_to_store.next_if_eq(&node_index).is_some() { @@ -150,10 +356,8 @@ fn peaks_to_prune_and_store( // both collections may share a common prefix. let peaks_before = if old_size == 0 { vec![] } else { helper::get_peaks(old_size) }; let peaks_after = helper::get_peaks(new_size); - sp_std::if_std! { - frame_support::log::trace!("peaks_before: {:?}", peaks_before); - frame_support::log::trace!("peaks_after: {:?}", peaks_after); - } + frame_support::log::trace!(target: "runtime::mmr", "peaks_before: {:?}", peaks_before); + frame_support::log::trace!(target: "runtime::mmr", "peaks_after: {:?}", peaks_after); let mut peaks_before = peaks_before.into_iter().peekable(); let mut peaks_after = peaks_after.into_iter().peekable(); diff --git a/frame/merkle-mountain-range/src/mmr/utils.rs b/frame/merkle-mountain-range/src/mmr/utils.rs index d9f7e3b671be3..3734ea514782d 100644 --- a/frame/merkle-mountain-range/src/mmr/utils.rs +++ b/frame/merkle-mountain-range/src/mmr/utils.rs @@ -18,6 +18,7 @@ //! Merkle Mountain Range utilities. use crate::primitives::{LeafIndex, NodeIndex}; +use mmr_lib::helper; /// MMR nodes & size -related utilities. pub struct NodesUtils { @@ -53,11 +54,78 @@ impl NodesUtils { 64 - self.no_of_leaves.next_power_of_two().leading_zeros() } + + /// Calculate `LeafIndex` for the leaf that added `node_index` to the MMR. + pub fn leaf_index_that_added_node(node_index: NodeIndex) -> LeafIndex { + let rightmost_leaf_pos = Self::rightmost_leaf_node_index_from_pos(node_index); + Self::leaf_node_index_to_leaf_index(rightmost_leaf_pos) + } + + // Translate a _leaf_ `NodeIndex` to its `LeafIndex`. + fn leaf_node_index_to_leaf_index(pos: NodeIndex) -> LeafIndex { + if pos == 0 { + return 0 + } + let peaks = helper::get_peaks(pos); + (pos + peaks.len() as u64) >> 1 + } + + // Starting from any node position get position of rightmost leaf; this is the leaf + // responsible for the addition of node `pos`. + fn rightmost_leaf_node_index_from_pos(pos: NodeIndex) -> NodeIndex { + pos - (helper::pos_height_in_tree(pos) as u64) + } + + /// Starting from any leaf index, get the sequence of positions of the nodes added + /// to the mmr when this leaf was added (inclusive of the leaf's position itself). + /// That is, all of these nodes are right children of their respective parents. + pub fn right_branch_ending_in_leaf(leaf_index: LeafIndex) -> crate::Vec { + let pos = helper::leaf_index_to_pos(leaf_index); + let num_parents = leaf_index.trailing_ones() as u64; + return (pos..=pos + num_parents).collect() + } } #[cfg(test)] mod tests { use super::*; + use mmr_lib::helper::leaf_index_to_pos; + + #[test] + fn should_calculate_node_index_from_leaf_index() { + for index in 0..100000 { + let pos = leaf_index_to_pos(index); + assert_eq!(NodesUtils::leaf_node_index_to_leaf_index(pos), index); + } + } + + #[test] + fn should_calculate_right_branch_correctly() { + fn left_jump_sequence(leaf_index: LeafIndex) -> Vec { + let pos = leaf_index_to_pos(leaf_index); + let mut right_branch_ending_in_leaf = vec![pos]; + let mut next_pos = pos + 1; + while mmr_lib::helper::pos_height_in_tree(next_pos) > 0 { + right_branch_ending_in_leaf.push(next_pos); + next_pos += 1; + } + right_branch_ending_in_leaf + } + + for leaf_index in 0..100000 { + let pos = mmr_lib::helper::leaf_index_to_pos(leaf_index); + assert_eq!(NodesUtils::right_branch_ending_in_leaf(pos), left_jump_sequence(pos)); + } + } + + #[test] + fn should_calculate_rightmost_leaf_node_index_from_pos() { + for pos in 0..100000 { + let leaf_pos = NodesUtils::rightmost_leaf_node_index_from_pos(pos); + let leaf_index = NodesUtils::leaf_node_index_to_leaf_index(leaf_pos); + assert!(NodesUtils::right_branch_ending_in_leaf(leaf_index).contains(&pos)); + } + } #[test] fn should_calculate_number_of_leaves_correctly() { diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index d025910a9ee5c..53226f8419988 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -15,9 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{mmr::utils, mock::*, *}; +use crate::{ + mmr::{storage::PruningMap, utils}, + mock::*, + *, +}; -use frame_support::traits::OnInitialize; +use frame_support::traits::{Get, OnInitialize}; use mmr_lib::helper; use sp_core::{ offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt}, @@ -47,7 +51,6 @@ fn new_block() -> u64 { fn peaks_from_leaves_count(leaves_count: NodeIndex) -> Vec { let size = utils::NodesUtils::new(leaves_count).size(); - helper::get_peaks(size) } @@ -73,7 +76,7 @@ fn decode_node( } } -fn init_chain(blocks: usize) { +fn add_blocks(blocks: usize) { // given for _ in 0..blocks { new_block(); @@ -115,9 +118,10 @@ fn should_start_empty() { fn should_append_to_mmr_when_on_initialize_is_called() { let _ = env_logger::try_init(); let mut ext = new_test_ext(); - ext.execute_with(|| { + let (parent_b1, parent_b2) = ext.execute_with(|| { // when new_block(); + let parent_b1 = >::parent_hash(); // then assert_eq!(crate::NumberOfLeaves::::get(), 1); @@ -136,6 +140,7 @@ fn should_append_to_mmr_when_on_initialize_is_called() { // when new_block(); + let parent_b2 = >::parent_hash(); // then assert_eq!(crate::NumberOfLeaves::::get(), 2); @@ -157,26 +162,33 @@ fn should_append_to_mmr_when_on_initialize_is_called() { hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854"), ) ); - }); + (parent_b1, parent_b2) + }); // make sure the leaves end up in the offchain DB ext.persist_offchain_overlay(); + let offchain_db = ext.offchain_db(); assert_eq!( - offchain_db.get(&MMR::offchain_key(0)).map(decode_node), + offchain_db.get(&MMR::node_offchain_key(parent_b1, 0)).map(decode_node), Some(mmr::Node::Data(((0, H256::repeat_byte(1)), LeafData::new(1),))) ); assert_eq!( - offchain_db.get(&MMR::offchain_key(1)).map(decode_node), + offchain_db.get(&MMR::node_offchain_key(parent_b2, 1)).map(decode_node), Some(mmr::Node::Data(((1, H256::repeat_byte(2)), LeafData::new(2),))) ); assert_eq!( - offchain_db.get(&MMR::offchain_key(2)).map(decode_node), + offchain_db.get(&MMR::node_offchain_key(parent_b2, 2)).map(decode_node), Some(mmr::Node::Hash(hex( "672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854" ))) ); - assert_eq!(offchain_db.get(&MMR::offchain_key(3)), None); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(parent_b2, 3)), None); + + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(0)), None); + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(1)), None); + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(2)), None); + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(3)), None); } #[test] @@ -184,7 +196,7 @@ fn should_construct_larger_mmr_correctly() { let _ = env_logger::try_init(); new_test_ext().execute_with(|| { // when - init_chain(7); + add_blocks(7); // then assert_eq!(crate::NumberOfLeaves::::get(), 7); @@ -215,7 +227,7 @@ fn should_generate_proofs_correctly() { let _ = env_logger::try_init(); let mut ext = new_test_ext(); // given - ext.execute_with(|| init_chain(7)); + ext.execute_with(|| add_blocks(7)); ext.persist_offchain_overlay(); // Try to generate proofs now. This requires the offchain extensions to be present @@ -283,7 +295,7 @@ fn should_generate_batch_proof_correctly() { let _ = env_logger::try_init(); let mut ext = new_test_ext(); // given - ext.execute_with(|| init_chain(7)); + ext.execute_with(|| add_blocks(7)); ext.persist_offchain_overlay(); // Try to generate proofs now. This requires the offchain extensions to be present @@ -316,7 +328,7 @@ fn should_verify() { // Start off with chain initialisation and storing indexing data off-chain // (MMR Leafs) let mut ext = new_test_ext(); - ext.execute_with(|| init_chain(7)); + ext.execute_with(|| add_blocks(7)); ext.persist_offchain_overlay(); // Try to generate proof now. This requires the offchain extensions to be present @@ -328,7 +340,7 @@ fn should_verify() { }); ext.execute_with(|| { - init_chain(7); + add_blocks(7); // then assert_eq!(crate::Pallet::::verify_leaves(leaves, proof5), Ok(())); }); @@ -341,7 +353,7 @@ fn should_verify_batch_proof() { // Start off with chain initialisation and storing indexing data off-chain // (MMR Leafs) let mut ext = new_test_ext(); - ext.execute_with(|| init_chain(7)); + ext.execute_with(|| add_blocks(7)); ext.persist_offchain_overlay(); // Try to generate proof now. This requires the offchain extensions to be present @@ -353,7 +365,7 @@ fn should_verify_batch_proof() { }); ext.execute_with(|| { - init_chain(7); + add_blocks(7); // then assert_eq!(crate::Pallet::::verify_leaves(leaves, proof), Ok(())); }); @@ -366,7 +378,7 @@ fn verification_should_be_stateless() { // Start off with chain initialisation and storing indexing data off-chain // (MMR Leafs) let mut ext = new_test_ext(); - ext.execute_with(|| init_chain(7)); + ext.execute_with(|| add_blocks(7)); ext.persist_offchain_overlay(); // Try to generate proof now. This requires the offchain extensions to be present @@ -393,7 +405,7 @@ fn should_verify_batch_proof_statelessly() { // Start off with chain initialisation and storing indexing data off-chain // (MMR Leafs) let mut ext = new_test_ext(); - ext.execute_with(|| init_chain(7)); + ext.execute_with(|| add_blocks(7)); ext.persist_offchain_overlay(); // Try to generate proof now. This requires the offchain extensions to be present @@ -424,7 +436,7 @@ fn should_verify_on_the_next_block_since_there_is_no_pruning_yet() { let _ = env_logger::try_init(); let mut ext = new_test_ext(); // given - ext.execute_with(|| init_chain(7)); + ext.execute_with(|| add_blocks(7)); ext.persist_offchain_overlay(); register_offchain_ext(&mut ext); @@ -438,3 +450,238 @@ fn should_verify_on_the_next_block_since_there_is_no_pruning_yet() { assert_eq!(crate::Pallet::::verify_leaves(leaves, proof5), Ok(())); }); } + +#[test] +fn should_verify_pruning_map() { + use sp_core::offchain::StorageKind; + use sp_io::offchain; + + let _ = env_logger::try_init(); + let mut ext = new_test_ext(); + register_offchain_ext(&mut ext); + + ext.execute_with(|| { + type TestPruningMap = PruningMap; + fn offchain_decoded(key: Vec) -> Option> { + offchain::local_storage_get(StorageKind::PERSISTENT, &key) + .and_then(|v| codec::Decode::decode(&mut &*v).ok()) + } + + // test append + { + TestPruningMap::append(1, H256::repeat_byte(1)); + + TestPruningMap::append(2, H256::repeat_byte(21)); + TestPruningMap::append(2, H256::repeat_byte(22)); + + TestPruningMap::append(3, H256::repeat_byte(31)); + TestPruningMap::append(3, H256::repeat_byte(32)); + TestPruningMap::append(3, H256::repeat_byte(33)); + + // `0` not present + let map_key = TestPruningMap::pruning_map_offchain_key(0); + assert_eq!(offchain::local_storage_get(StorageKind::PERSISTENT, &map_key), None); + + // verify `1` entries + let map_key = TestPruningMap::pruning_map_offchain_key(1); + let expected = vec![H256::repeat_byte(1)]; + assert_eq!(offchain_decoded(map_key), Some(expected)); + + // verify `2` entries + let map_key = TestPruningMap::pruning_map_offchain_key(2); + let expected = vec![H256::repeat_byte(21), H256::repeat_byte(22)]; + assert_eq!(offchain_decoded(map_key), Some(expected)); + + // verify `3` entries + let map_key = TestPruningMap::pruning_map_offchain_key(3); + let expected = + vec![H256::repeat_byte(31), H256::repeat_byte(32), H256::repeat_byte(33)]; + assert_eq!(offchain_decoded(map_key), Some(expected)); + + // `4` not present + let map_key = TestPruningMap::pruning_map_offchain_key(4); + assert_eq!(offchain::local_storage_get(StorageKind::PERSISTENT, &map_key), None); + } + + // test remove + { + // `0` doesn't return anything + assert_eq!(TestPruningMap::remove(0), None); + + // remove and verify `1` entries + let expected = vec![H256::repeat_byte(1)]; + assert_eq!(TestPruningMap::remove(1), Some(expected)); + + // remove and verify `2` entries + let expected = vec![H256::repeat_byte(21), H256::repeat_byte(22)]; + assert_eq!(TestPruningMap::remove(2), Some(expected)); + + // remove and verify `3` entries + let expected = + vec![H256::repeat_byte(31), H256::repeat_byte(32), H256::repeat_byte(33)]; + assert_eq!(TestPruningMap::remove(3), Some(expected)); + + // `4` doesn't return anything + assert_eq!(TestPruningMap::remove(4), None); + + // no entries left in offchain map + for block in 0..5 { + let map_key = TestPruningMap::pruning_map_offchain_key(block); + assert_eq!(offchain::local_storage_get(StorageKind::PERSISTENT, &map_key), None); + } + } + }) +} + +#[test] +fn should_canonicalize_offchain() { + use frame_support::traits::Hooks; + + let _ = env_logger::try_init(); + let mut ext = new_test_ext(); + register_offchain_ext(&mut ext); + + // adding 13 blocks that we'll later check have been canonicalized, + // (test assumes `13 < frame_system::BlockHashCount`). + let to_canon_count = 13u32; + + // add 13 blocks and verify leaves and nodes for them have been added to + // offchain MMR using fork-proof keys. + for blocknum in 0..to_canon_count { + ext.execute_with(|| { + new_block(); + as Hooks>::offchain_worker(blocknum.into()); + }); + ext.persist_offchain_overlay(); + } + let offchain_db = ext.offchain_db(); + ext.execute_with(|| { + // verify leaves added by blocks 1..=13 + for block_num in 1..=to_canon_count { + let parent_num: BlockNumber = (block_num - 1).into(); + let leaf_index = u64::from(block_num - 1); + let pos = helper::leaf_index_to_pos(leaf_index.into()); + // not canon, + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(pos)), None); + let parent_hash = >::block_hash(parent_num); + // but available in fork-proof storage. + assert_eq!( + offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)).map(decode_node), + Some(mmr::Node::Data(( + (leaf_index, H256::repeat_byte(u8::try_from(block_num).unwrap())), + LeafData::new(block_num.into()), + ))) + ); + } + + // verify a couple of nodes and peaks: + // `pos` is node to verify, + // `leaf_index` is leaf that added node `pos`, + // `expected` is expected value of node at `pos`. + let verify = |pos: NodeIndex, leaf_index: LeafIndex, expected: H256| { + let parent_num: BlockNumber = leaf_index.try_into().unwrap(); + let parent_hash = >::block_hash(parent_num); + // not canon, + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(pos)), None); + // but available in fork-proof storage. + assert_eq!( + offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)).map(decode_node), + Some(mmr::Node::Hash(expected)) + ); + }; + verify(2, 1, hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854")); + verify(13, 7, hex("441bf63abc7cf9b9e82eb57b8111c883d50ae468d9fd7f301e12269fc0fa1e75")); + verify(21, 11, hex("f323ac1a7f56de5f40ed8df3e97af74eec0ee9d72883679e49122ffad2ffd03b")); + }); + + // add another `frame_system::BlockHashCount` blocks and verify all nodes and leaves + // added by our original `to_canon_count` blocks have now been canonicalized in offchain db. + let block_hash_size: u64 = ::BlockHashCount::get(); + let base = to_canon_count; + for blocknum in base..(base + u32::try_from(block_hash_size).unwrap()) { + ext.execute_with(|| { + new_block(); + as Hooks>::offchain_worker(blocknum.into()); + }); + ext.persist_offchain_overlay(); + } + ext.execute_with(|| { + // verify leaves added by blocks 1..=13, should be in offchain under canon key. + for block_num in 1..=to_canon_count { + let leaf_index = u64::from(block_num - 1); + let pos = helper::leaf_index_to_pos(leaf_index.into()); + let parent_num: BlockNumber = (block_num - 1).into(); + let parent_hash = >::block_hash(parent_num); + // no longer available in fork-proof storage (was pruned), + assert_eq!(offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)), None); + // but available using canon key. + assert_eq!( + offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), + Some(mmr::Node::Data(( + (leaf_index, H256::repeat_byte(u8::try_from(block_num).unwrap())), + LeafData::new(block_num.into()), + ))) + ); + } + + // also check some nodes and peaks: + // `pos` is node to verify, + // `leaf_index` is leaf that added node `pos`, + // `expected` is expected value of node at `pos`. + let verify = |pos: NodeIndex, leaf_index: LeafIndex, expected: H256| { + let parent_num: BlockNumber = leaf_index.try_into().unwrap(); + let parent_hash = >::block_hash(parent_num); + // no longer available in fork-proof storage (was pruned), + assert_eq!(offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)), None); + // but available using canon key. + assert_eq!( + offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), + Some(mmr::Node::Hash(expected)) + ); + }; + verify(2, 1, hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854")); + verify(13, 7, hex("441bf63abc7cf9b9e82eb57b8111c883d50ae468d9fd7f301e12269fc0fa1e75")); + verify(21, 11, hex("f323ac1a7f56de5f40ed8df3e97af74eec0ee9d72883679e49122ffad2ffd03b")); + }); +} + +#[test] +fn should_verify_canonicalized() { + use frame_support::traits::Hooks; + let _ = env_logger::try_init(); + + // How deep is our fork-aware storage (in terms of blocks/leaves, nodes will be more). + let block_hash_size: u64 = ::BlockHashCount::get(); + + // Start off with chain initialisation and storing indexing data off-chain. + // Create twice as many leaf entries than our fork-aware capacity, + // resulting in ~half of MMR storage to use canonical keys and the other half fork-aware keys. + // Verify that proofs can be generated (using leaves and nodes from full set) and verified. + let mut ext = new_test_ext(); + register_offchain_ext(&mut ext); + for blocknum in 0u32..(2 * block_hash_size).try_into().unwrap() { + ext.execute_with(|| { + new_block(); + as Hooks>::offchain_worker(blocknum.into()); + }); + ext.persist_offchain_overlay(); + } + + // Generate proofs for some blocks. + let (leaves, proofs) = + ext.execute_with(|| crate::Pallet::::generate_batch_proof(vec![0, 4, 5, 7]).unwrap()); + // Verify all previously generated proofs. + ext.execute_with(|| { + assert_eq!(crate::Pallet::::verify_leaves(leaves, proofs), Ok(())); + }); + + // Generate proofs for some new blocks. + let (leaves, proofs) = ext.execute_with(|| { + crate::Pallet::::generate_batch_proof(vec![block_hash_size + 7]).unwrap() + }); + // Add some more blocks then verify all previously generated proofs. + ext.execute_with(|| { + add_blocks(7); + assert_eq!(crate::Pallet::::verify_leaves(leaves, proofs), Ok(())); + }); +} diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 5a339d069062c..8a2e901aefddf 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -81,7 +81,7 @@ pub struct Proof { /// A full leaf content stored in the offchain-db. pub trait FullLeaf: Clone + PartialEq + fmt::Debug { - /// Encode the leaf either in it's full or compact form. + /// Encode the leaf either in its full or compact form. /// /// NOTE the encoding returned here MUST be `Decode`able into `FullLeaf`. fn using_encoded R>(&self, f: F, compact: bool) -> R; @@ -167,18 +167,18 @@ impl EncodableOpaqueLeaf { } } -/// An element representing either full data or it's hash. +/// An element representing either full data or its hash. /// /// See [Compact] to see how it may be used in practice to reduce the size /// of proofs in case multiple [LeafDataProvider]s are composed together. /// This is also used internally by the MMR to differentiate leaf nodes (data) /// and inner nodes (hashes). /// -/// [DataOrHash::hash] method calculates the hash of this element in it's compact form, +/// [DataOrHash::hash] method calculates the hash of this element in its compact form, /// so should be used instead of hashing the encoded form (which will always be non-compact). #[derive(RuntimeDebug, Clone, PartialEq)] pub enum DataOrHash { - /// Arbitrary data in it's full form. + /// Arbitrary data in its full form. Data(L), /// A hash of some data. Hash(H::Output), @@ -339,7 +339,7 @@ where A: FullLeaf, B: FullLeaf, { - /// Retrieve a hash of this item in it's compact form. + /// Retrieve a hash of this item in its compact form. pub fn hash(&self) -> H::Output { self.using_encoded(::hash, true) } @@ -447,7 +447,7 @@ sp_api::decl_runtime_apis! { /// Note this function does not require any on-chain storage - the /// proof is verified against given MMR root hash. /// - /// The leaf data is expected to be encoded in it's compact form. + /// The leaf data is expected to be encoded in its compact form. fn verify_proof_stateless(root: Hash, leaf: EncodableOpaqueLeaf, proof: Proof) -> Result<(), Error>; From d871277f981d3e4d3105b9f7c4f7a5f6a1323cc5 Mon Sep 17 00:00:00 2001 From: Andronik Date: Fri, 8 Jul 2022 14:27:58 +0200 Subject: [PATCH 0957/1472] expose grandpa BeforeBestBlockBy voting rule (#11798) --- client/finality-grandpa/src/voting_rule.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/finality-grandpa/src/voting_rule.rs b/client/finality-grandpa/src/voting_rule.rs index 209b0f1b33ced..051c7f2c03658 100644 --- a/client/finality-grandpa/src/voting_rule.rs +++ b/client/finality-grandpa/src/voting_rule.rs @@ -89,7 +89,7 @@ where /// can prioritize shorter chains over longer ones, the vote may be /// closer to the best block than N. #[derive(Clone)] -pub struct BeforeBestBlockBy(N); +pub struct BeforeBestBlockBy(pub N); impl VotingRule for BeforeBestBlockBy> where Block: BlockT, From 8310936bd25519cee81abb01d2b164805f01bc25 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sat, 9 Jul 2022 14:39:26 +0100 Subject: [PATCH 0958/1472] Un-deprecate Transactional Macro (#11807) * un-deprecate transactional macro * add transactional back to nomination pools --- frame/nomination-pools/src/lib.rs | 15 ++++++++++++++- frame/support/procedural/src/lib.rs | 1 - 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index d43d43c806d61..f7ccac3e35411 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -316,7 +316,7 @@ use frame_support::{ Currency, Defensive, DefensiveOption, DefensiveResult, DefensiveSaturating, ExistenceRequirement, Get, }, - CloneNoBound, DefaultNoBound, RuntimeDebugNoBound, + transactional, CloneNoBound, DefaultNoBound, RuntimeDebugNoBound, }; use scale_info::TypeInfo; use sp_core::U256; @@ -1412,6 +1412,7 @@ pub mod pallet { /// `existential deposit + amount` in their account. /// * Only a pool with [`PoolState::Open`] can be joined #[pallet::weight(T::WeightInfo::join())] + #[transactional] pub fn join( origin: OriginFor, #[pallet::compact] amount: BalanceOf, @@ -1472,6 +1473,7 @@ pub mod pallet { T::WeightInfo::bond_extra_transfer() .max(T::WeightInfo::bond_extra_reward()) )] + #[transactional] pub fn bond_extra(origin: OriginFor, extra: BondExtra>) -> DispatchResult { let who = ensure_signed(origin)?; let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&who)?; @@ -1510,6 +1512,7 @@ pub mod pallet { /// The member will earn rewards pro rata based on the members stake vs the sum of the /// members in the pools stake. Rewards do not "expire". #[pallet::weight(T::WeightInfo::claim_payout())] + #[transactional] pub fn claim_payout(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&who)?; @@ -1549,6 +1552,7 @@ pub mod pallet { /// there are too many unlocking chunks, the result of this call will likely be the /// `NoMoreChunks` error from the staking system. #[pallet::weight(T::WeightInfo::unbond())] + #[transactional] pub fn unbond( origin: OriginFor, member_account: T::AccountId, @@ -1626,6 +1630,7 @@ pub mod pallet { /// would probably see an error like `NoMoreChunks` emitted from the staking system when /// they attempt to unbond. #[pallet::weight(T::WeightInfo::pool_withdraw_unbonded(*num_slashing_spans))] + #[transactional] pub fn pool_withdraw_unbonded( origin: OriginFor, pool_id: PoolId, @@ -1662,6 +1667,7 @@ pub mod pallet { #[pallet::weight( T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans) )] + #[transactional] pub fn withdraw_unbonded( origin: OriginFor, member_account: T::AccountId, @@ -1787,6 +1793,7 @@ pub mod pallet { /// In addition to `amount`, the caller will transfer the existential deposit; so the caller /// needs at have at least `amount + existential_deposit` transferrable. #[pallet::weight(T::WeightInfo::create())] + #[transactional] pub fn create( origin: OriginFor, #[pallet::compact] amount: BalanceOf, @@ -1875,6 +1882,7 @@ pub mod pallet { /// This directly forward the call to the staking pallet, on behalf of the pool bonded /// account. #[pallet::weight(T::WeightInfo::nominate(validators.len() as u32))] + #[transactional] pub fn nominate( origin: OriginFor, pool_id: PoolId, @@ -1891,6 +1899,7 @@ pub mod pallet { /// The dispatch origin of this call must be signed by the state toggler, or the root role /// of the pool. #[pallet::weight(T::WeightInfo::set_state())] + #[transactional] pub fn set_state( origin: OriginFor, pool_id: PoolId, @@ -1921,6 +1930,7 @@ pub mod pallet { /// The dispatch origin of this call must be signed by the state toggler, or the root role /// of the pool. #[pallet::weight(T::WeightInfo::set_metadata(metadata.len() as u32))] + #[transactional] pub fn set_metadata( origin: OriginFor, pool_id: PoolId, @@ -1952,6 +1962,7 @@ pub mod pallet { /// * `max_members` - Set [`MaxPoolMembers`]. /// * `max_members_per_pool` - Set [`MaxPoolMembersPerPool`]. #[pallet::weight(T::WeightInfo::set_configs())] + #[transactional] pub fn set_configs( origin: OriginFor, min_join_bond: ConfigOp>, @@ -1988,6 +1999,7 @@ pub mod pallet { /// It emits an event, notifying UIs of the role change. This event is quite relevant to /// most pool members and they should be informed of changes to pool roles. #[pallet::weight(T::WeightInfo::update_roles())] + #[transactional] pub fn update_roles( origin: OriginFor, pool_id: PoolId, @@ -2040,6 +2052,7 @@ pub mod pallet { /// This directly forward the call to the staking pallet, on behalf of the pool bonded /// account. #[pallet::weight(T::WeightInfo::chill())] + #[transactional] pub fn chill(origin: OriginFor, pool_id: PoolId) -> DispatchResult { let who = ensure_signed(origin)?; let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 418fad56b7674..00204b7a4d906 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -429,7 +429,6 @@ pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream { /// } /// ``` #[proc_macro_attribute] -#[deprecated(note = "This is now the default behaviour for all extrinsics.")] pub fn transactional(attr: TokenStream, input: TokenStream) -> TokenStream { transactional::transactional(attr, input).unwrap_or_else(|e| e.to_compile_error().into()) } From d513c8b9ad373432b671a46f28b1835c1f879923 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 12 Jul 2022 13:14:42 +0200 Subject: [PATCH 0959/1472] sync: Fixed clearing subsequent ranges (#11815) * sync: Fixed clearing subsequent ranges * Warp sync fix * Better documentation --- client/network/sync/src/blocks.rs | 48 +++++++++++++++++++++++++------ client/network/sync/src/lib.rs | 3 ++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/client/network/sync/src/blocks.rs b/client/network/sync/src/blocks.rs index 8d9b039b14fba..26753f120a170 100644 --- a/client/network/sync/src/blocks.rs +++ b/client/network/sync/src/blocks.rs @@ -180,6 +180,9 @@ impl BlockCollection { /// Get a valid chain of blocks ordered in descending order and ready for importing into /// the blockchain. + /// `from` is the maximum block number for the start of the range that we are interested in. + /// The function will return empty Vec if the first block ready is higher than `from`. + /// For each returned block hash `clear_queued` must be called at some later stage. pub fn ready_blocks(&mut self, from: NumberFor) -> Vec> { let mut ready = Vec::new(); @@ -192,6 +195,10 @@ impl BlockCollection { BlockRangeState::Complete(blocks) => { let len = (blocks.len() as u32).into(); prev = start + len; + if let Some(BlockData { block, .. }) = blocks.first() { + self.queued_blocks + .insert(block.hash, (start, start + (blocks.len() as u32).into())); + } // Remove all elements from `blocks` and add them to `ready` ready.append(blocks); len @@ -201,18 +208,12 @@ impl BlockCollection { }; *range_data = BlockRangeState::Queued { len }; } - - if let Some(BlockData { block, .. }) = ready.first() { - self.queued_blocks - .insert(block.hash, (from, from + (ready.len() as u32).into())); - } - trace!(target: "sync", "{} blocks ready for import", ready.len()); ready } - pub fn clear_queued(&mut self, from_hash: &B::Hash) { - if let Some((from, to)) = self.queued_blocks.remove(from_hash) { + pub fn clear_queued(&mut self, hash: &B::Hash) { + if let Some((from, to)) = self.queued_blocks.remove(hash) { let mut block_num = from; while block_num < to { self.blocks.remove(&block_num); @@ -399,4 +400,35 @@ mod test { assert_eq!(bc.needed_blocks(peer.clone(), 5, 50, 39, 0, 200), Some(45..50)); } + + #[test] + fn clear_queued_subsequent_ranges() { + let mut bc = BlockCollection::new(); + assert!(is_empty(&bc)); + let peer = PeerId::random(); + + let blocks = generate_blocks(10); + + // Request 2 ranges + assert_eq!(bc.needed_blocks(peer.clone(), 5, 50, 39, 0, 200), Some(40..45)); + assert_eq!(bc.needed_blocks(peer.clone(), 5, 50, 39, 0, 200), Some(45..50)); + + // got a response on the request for `40..50` + bc.clear_peer_download(&peer); + bc.insert(40, blocks.to_vec(), peer.clone()); + + // request any blocks starting from 1000 or lower. + let ready = bc.ready_blocks(1000); + assert_eq!( + ready, + blocks + .iter() + .map(|b| BlockData { block: b.clone(), origin: Some(peer.clone()) }) + .collect::>() + ); + + bc.clear_queued(&blocks[0].hash); + assert!(bc.blocks.is_empty()); + assert!(bc.queued_blocks.is_empty()); + } } diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 5b5216c745c98..1ce69b6dc816f 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -1521,6 +1521,9 @@ where for (_, hash) in &results { self.queue_blocks.remove(hash); self.blocks.clear_queued(hash); + if let Some(gap_sync) = &mut self.gap_sync { + gap_sync.blocks.clear_queued(hash); + } } for (result, hash) in results { if has_error { From 43fd9a9dc2ba2644f88531b52a196a4f0800c2bf Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Tue, 12 Jul 2022 23:19:13 +1200 Subject: [PATCH 0960/1472] CLI flag to configure tx ban duration (#11786) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add tx-ban-seconds * fix * trigger CI * trigger CI * remove test print * Update client/cli/src/params/transaction_pool_params.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- bin/node/cli/benches/transaction_pool.rs | 3 +++ client/cli/src/commands/run_cmd.rs | 4 ++-- client/cli/src/config.rs | 4 ++-- client/cli/src/params/transaction_pool_params.rs | 14 +++++++++++++- client/transaction-pool/src/graph/pool.rs | 5 ++++- client/transaction-pool/src/graph/rotator.rs | 5 +++++ .../transaction-pool/src/graph/validated_pool.rs | 3 ++- 7 files changed, 31 insertions(+), 7 deletions(-) diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index f1fce16d8c1b3..5b96355b9ca70 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -16,6 +16,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use std::time::Duration; + use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; use futures::{future, StreamExt}; use node_cli::service::{create_extrinsic, fetch_nonce, FullClient, TransactionPool}; @@ -58,6 +60,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { ready: PoolLimit { count: 100_000, total_bytes: 100 * 1024 * 1024 }, future: PoolLimit { count: 100_000, total_bytes: 100 * 1024 * 1024 }, reject_future_transactions: false, + ban_time: Duration::from_secs(30 * 60), }, network: network_config, keystore: KeystoreConfig::InMemory, diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index b4a3885e39906..12774eecc4174 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -480,8 +480,8 @@ impl CliConfiguration for RunCmd { Ok(self.ws_max_out_buffer_capacity) } - fn transaction_pool(&self) -> Result { - Ok(self.pool_config.transaction_pool()) + fn transaction_pool(&self, is_dev: bool) -> Result { + Ok(self.pool_config.transaction_pool(is_dev)) } fn max_runtime_instances(&self) -> Result> { diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 6e1317c11fbc4..01c541bf75255 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -145,7 +145,7 @@ pub trait CliConfiguration: Sized { /// Get the transaction pool options /// /// By default this is `TransactionPoolOptions::default()`. - fn transaction_pool(&self) -> Result { + fn transaction_pool(&self, _is_dev: bool) -> Result { Ok(Default::default()) } @@ -523,7 +523,7 @@ pub trait CliConfiguration: Sized { impl_name: C::impl_name(), impl_version: C::impl_version(), tokio_handle, - transaction_pool: self.transaction_pool()?, + transaction_pool: self.transaction_pool(is_dev)?, network: self.network_config( &chain_spec, is_dev, diff --git a/client/cli/src/params/transaction_pool_params.rs b/client/cli/src/params/transaction_pool_params.rs index efb78430ced55..6429dfec3f908 100644 --- a/client/cli/src/params/transaction_pool_params.rs +++ b/client/cli/src/params/transaction_pool_params.rs @@ -29,11 +29,15 @@ pub struct TransactionPoolParams { /// Maximum number of kilobytes of all transactions stored in the pool. #[clap(long, value_name = "COUNT", default_value = "20480")] pub pool_kbytes: usize, + + /// How long a transaction is banned for, if it is considered invalid. Defaults to 1800s. + #[clap(long, value_name = "SECONDS")] + pub tx_ban_seconds: Option, } impl TransactionPoolParams { /// Fill the given `PoolConfiguration` by looking at the cli parameters. - pub fn transaction_pool(&self) -> TransactionPoolOptions { + pub fn transaction_pool(&self, is_dev: bool) -> TransactionPoolOptions { let mut opts = TransactionPoolOptions::default(); // ready queue @@ -45,6 +49,14 @@ impl TransactionPoolParams { opts.future.count = self.pool_limit / factor; opts.future.total_bytes = self.pool_kbytes * 1024 / factor; + opts.ban_time = if let Some(ban_seconds) = self.tx_ban_seconds { + std::time::Duration::from_secs(ban_seconds) + } else if is_dev { + std::time::Duration::from_secs(0) + } else { + std::time::Duration::from_secs(30 * 60) + }; + opts } } diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 618ba8ccf24d5..4ce7954f8d479 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, sync::Arc, time::Duration}; use futures::{channel::mpsc::Receiver, Future}; use sc_transaction_pool_api::error; @@ -108,6 +108,8 @@ pub struct Options { pub future: base::Limit, /// Reject future transactions. pub reject_future_transactions: bool, + /// How long the extrinsic is banned for. + pub ban_time: Duration, } impl Default for Options { @@ -116,6 +118,7 @@ impl Default for Options { ready: base::Limit { count: 8192, total_bytes: 20 * 1024 * 1024 }, future: base::Limit { count: 512, total_bytes: 1 * 1024 * 1024 }, reject_future_transactions: false, + ban_time: Duration::from_secs(60 * 30), } } } diff --git a/client/transaction-pool/src/graph/rotator.rs b/client/transaction-pool/src/graph/rotator.rs index b897fe7885033..c91c8e407bc0f 100644 --- a/client/transaction-pool/src/graph/rotator.rs +++ b/client/transaction-pool/src/graph/rotator.rs @@ -51,6 +51,11 @@ impl Default for PoolRotator { } impl PoolRotator { + /// New rotator instance with specified ban time. + pub fn new(ban_time: Duration) -> Self { + Self { ban_time, banned_until: Default::default() } + } + /// Returns `true` if extrinsic hash is currently banned. pub fn is_banned(&self, hash: &Hash) -> bool { self.banned_until.read().contains_key(hash) diff --git a/client/transaction-pool/src/graph/validated_pool.rs b/client/transaction-pool/src/graph/validated_pool.rs index 084b04842ee90..e59c5afbdc512 100644 --- a/client/transaction-pool/src/graph/validated_pool.rs +++ b/client/transaction-pool/src/graph/validated_pool.rs @@ -125,6 +125,7 @@ impl ValidatedPool { /// Create a new transaction pool. pub fn new(options: Options, is_validator: IsValidator, api: Arc) -> Self { let base_pool = base::BasePool::new(options.reject_future_transactions); + let ban_time = options.ban_time; Self { is_validator, options, @@ -132,7 +133,7 @@ impl ValidatedPool { api, pool: RwLock::new(base_pool), import_notification_sinks: Default::default(), - rotator: Default::default(), + rotator: PoolRotator::new(ban_time), } } From 5677b91eb6ad8e280cf7dcbdb8990d31bd2d74b1 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 12 Jul 2022 21:00:00 +0400 Subject: [PATCH 0961/1472] Upgrade libp2p to 0.46.1 (#11787) * Update libp2p to 0.46.0 * Update libp2p to 0.46.1 * Fix telemetry initialization * Fix tests --- Cargo.lock | 362 ++++++------------ client/authority-discovery/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/common/Cargo.toml | 2 +- client/network/light/Cargo.toml | 2 +- client/network/src/discovery.rs | 6 +- client/network/src/peer_info.rs | 5 +- client/network/src/protocol.rs | 5 +- .../src/protocol/notifications/tests.rs | 6 +- client/network/src/request_responses.rs | 7 +- client/network/src/transport.rs | 9 +- client/network/sync/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/telemetry/src/transport.rs | 3 +- 19 files changed, 151 insertions(+), 274 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d68330cfb15c2..26f43fa4ae0ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3207,7 +3207,7 @@ dependencies = [ "http", "jsonrpsee-core", "jsonrpsee-types", - "pin-project 1.0.10", + "pin-project", "rustls-native-certs", "soketto", "thiserror", @@ -3461,9 +3461,9 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libp2p" -version = "0.45.1" +version = "0.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41726ee8f662563fafba2d2d484b14037cc8ecb8c953fbfc8439d4ce3a0a9029" +checksum = "81327106887e42d004fbdab1fef93675be2e2e07c1b95fce45e2cc813485611d" dependencies = [ "bytes", "futures", @@ -3472,7 +3472,7 @@ dependencies = [ "instant", "lazy_static", "libp2p-autonat", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-deflate", "libp2p-dns", "libp2p-floodsub", @@ -3498,69 +3498,35 @@ dependencies = [ "libp2p-yamux", "multiaddr", "parking_lot 0.12.0", - "pin-project 1.0.10", + "pin-project", "rand 0.7.3", "smallvec", ] [[package]] name = "libp2p-autonat" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50de7c1d5c3f040fccb469e8a2d189e068b7627d760dd74ef914071c16bbe905" +checksum = "4decc51f3573653a9f4ecacb31b1b922dd20c25a6322bb15318ec04287ec46f9" dependencies = [ "async-trait", "futures", "futures-timer", "instant", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-request-response", "libp2p-swarm", "log", - "prost 0.10.3", - "prost-build 0.10.4", - "rand 0.8.4", -] - -[[package]] -name = "libp2p-core" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b02602099fb75cb2d16f9ea860a320d6eb82ce41e95ab680912c454805cd5" -dependencies = [ - "asn1_der", - "bs58", - "ed25519-dalek", - "either", - "fnv", - "futures", - "futures-timer", - "instant", - "lazy_static", - "log", - "multiaddr", - "multihash", - "multistream-select", - "parking_lot 0.12.0", - "pin-project 1.0.10", - "prost 0.9.0", - "prost-build 0.9.0", + "prost", + "prost-build", "rand 0.8.4", - "ring", - "rw-stream-sink 0.2.1", - "sha2 0.10.2", - "smallvec", - "thiserror", - "unsigned-varint", - "void", - "zeroize", ] [[package]] name = "libp2p-core" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d46fca305dee6757022e2f5a4f6c023315084d0ed7441c3ab244e76666d979" +checksum = "fbf9b94cefab7599b2d3dff2f93bee218c6621d68590b23ede4485813cbcece6" dependencies = [ "asn1_der", "bs58", @@ -3577,12 +3543,12 @@ dependencies = [ "multihash", "multistream-select", "parking_lot 0.12.0", - "pin-project 1.0.10", - "prost 0.10.3", - "prost-build 0.10.4", + "pin-project", + "prost", + "prost-build", "rand 0.8.4", "ring", - "rw-stream-sink 0.3.0", + "rw-stream-sink", "sha2 0.10.2", "smallvec", "thiserror", @@ -3593,24 +3559,24 @@ dependencies = [ [[package]] name = "libp2p-deflate" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86adefc55ea4ed8201149f052fb441210727481dff1fb0b8318460206a79f5fb" +checksum = "d0183dc2a3da1fbbf85e5b6cf51217f55b14f5daea0c455a9536eef646bfec71" dependencies = [ "flate2", "futures", - "libp2p-core 0.33.0", + "libp2p-core", ] [[package]] name = "libp2p-dns" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbb462ec3a51fab457b4b44ac295e8b0a4b04dc175127e615cf996b1f0f1a268" +checksum = "6cbf54723250fa5d521383be789bf60efdabe6bacfb443f87da261019a49b4b5" dependencies = [ "async-std-resolver", "futures", - "libp2p-core 0.33.0", + "libp2p-core", "log", "parking_lot 0.12.0", "smallvec", @@ -3619,27 +3585,27 @@ dependencies = [ [[package]] name = "libp2p-floodsub" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a505d0c6f851cbf2919535150198e530825def8bd3757477f13dc3a57f46cbcc" +checksum = "98a4b6ffd53e355775d24b76f583fdda54b3284806f678499b57913adb94f231" dependencies = [ "cuckoofilter", "fnv", "futures", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-swarm", "log", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "rand 0.7.3", "smallvec", ] [[package]] name = "libp2p-gossipsub" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9be947d8cea8e6b469201314619395826896d2c051053c3723910ba98e68e04" +checksum = "74b4b888cfbeb1f5551acd3aa1366e01bf88ede26cc3c4645d0d2d004d5ca7b0" dependencies = [ "asynchronous-codec", "base64", @@ -3649,12 +3615,12 @@ dependencies = [ "futures", "hex_fmt", "instant", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-swarm", "log", "prometheus-client", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "rand 0.7.3", "regex", "sha2 0.10.2", @@ -3665,19 +3631,19 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.36.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84b53490442d086db1fa5375670c9666e79143dccadef3f7c74a4346899a984" +checksum = "c50b585518f8efd06f93ac2f976bd672e17cdac794644b3117edd078e96bda06" dependencies = [ "asynchronous-codec", "futures", "futures-timer", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-swarm", "log", "lru", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "prost-codec", "smallvec", "thiserror", @@ -3686,9 +3652,9 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.37.1" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6b5d4de90fcd35feb65ea6223fd78f3b747a64ca4b65e0813fbe66a27d56aa" +checksum = "740862893bb5f06ac24acc9d49bdeadc3a5e52e51818a30a25c1f3519da2c851" dependencies = [ "arrayvec 0.7.2", "asynchronous-codec", @@ -3698,11 +3664,11 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-swarm", "log", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "rand 0.7.3", "sha2 0.10.2", "smallvec", @@ -3714,9 +3680,9 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4783f8cf00c7b6c1ff0f1870b4fcf50b042b45533d2e13b6fb464caf447a6951" +checksum = "66e5e5919509603281033fd16306c61df7a4428ce274b67af5e14b07de5cdcb2" dependencies = [ "async-io", "data-encoding", @@ -3724,7 +3690,7 @@ dependencies = [ "futures", "if-watch", "lazy_static", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-swarm", "log", "rand 0.8.4", @@ -3735,11 +3701,11 @@ dependencies = [ [[package]] name = "libp2p-metrics" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4357140141ba9739eee71b20aa735351c0fc642635b2bffc7f57a6b5c1090" +checksum = "ef8aff4a1abef42328fbb30b17c853fff9be986dc39af17ee39f9c5f755c5e0c" dependencies = [ - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-gossipsub", "libp2p-identify", "libp2p-kad", @@ -3751,14 +3717,14 @@ dependencies = [ [[package]] name = "libp2p-mplex" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ff9c893f2367631a711301d703c47432af898c9bb8253bea0e2c051a13f7640" +checksum = "61fd1b20638ec209c5075dfb2e8ce6a7ea4ec3cd3ad7b77f7a477c06d53322e2" dependencies = [ "asynchronous-codec", "bytes", "futures", - "libp2p-core 0.33.0", + "libp2p-core", "log", "nohash-hasher", "parking_lot 0.12.0", @@ -3769,18 +3735,18 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2cee1dad1c83325bbd182a8e94555778699cec8a9da00086efb7522c4c15ad" +checksum = "762408cb5d84b49a600422d7f9a42c18012d8da6ebcd570f9a4a4290ba41fb6f" dependencies = [ "bytes", "curve25519-dalek 3.0.2", "futures", "lazy_static", - "libp2p-core 0.33.0", + "libp2p-core", "log", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "rand 0.8.4", "sha2 0.10.2", "snow", @@ -3791,14 +3757,14 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d41516c82fe8dd148ec925eead0c5ec08a0628f7913597e93e126e4dfb4e0787" +checksum = "100a6934ae1dbf8a693a4e7dd1d730fd60b774dafc45688ed63b554497c6c925" dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-swarm", "log", "rand 0.7.3", @@ -3807,17 +3773,17 @@ dependencies = [ [[package]] name = "libp2p-plaintext" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db007e737adc5d28b2e03223b0210164928ad742591127130796a72aa8eaf54f" +checksum = "be27bf0820a6238a4e06365b096d428271cce85a129cf16f2fe9eb1610c4df86" dependencies = [ "asynchronous-codec", "bytes", "futures", - "libp2p-core 0.33.0", + "libp2p-core", "log", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "unsigned-varint", "void", ] @@ -3830,7 +3796,7 @@ checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" dependencies = [ "futures", "log", - "pin-project 1.0.10", + "pin-project", "rand 0.7.3", "salsa20", "sha3 0.9.1", @@ -3838,9 +3804,9 @@ dependencies = [ [[package]] name = "libp2p-relay" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624ead3406f64437a0d4567c31bd128a9a0b8226d5f16c074038f5d0fc32f650" +checksum = "4931547ee0cce03971ccc1733ff05bb0c4349fd89120a39e9861e2bbe18843c3" dependencies = [ "asynchronous-codec", "bytes", @@ -3848,12 +3814,12 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-swarm", "log", - "pin-project 1.0.10", - "prost 0.10.3", - "prost-build 0.10.4", + "pin-project", + "prost", + "prost-build", "prost-codec", "rand 0.8.4", "smallvec", @@ -3864,20 +3830,20 @@ dependencies = [ [[package]] name = "libp2p-rendezvous" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59967ea2db2c7560f641aa58ac05982d42131863fcd3dd6dcf0dd1daf81c60c" +checksum = "9511c9672ba33284838e349623319c8cad2d18cfad243ae46c6b7e8a2982ea4e" dependencies = [ "asynchronous-codec", "bimap", "futures", "futures-timer", "instant", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-swarm", "log", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "rand 0.8.4", "sha2 0.10.2", "thiserror", @@ -3887,15 +3853,15 @@ dependencies = [ [[package]] name = "libp2p-request-response" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b02e0acb725e5a757d77c96b95298fd73a7394fe82ba7b8bbeea510719cbe441" +checksum = "508a189e2795d892c8f5c1fa1e9e0b1845d32d7b0b249dbf7b05b18811361843" dependencies = [ "async-trait", "bytes", "futures", "instant", - "libp2p-core 0.33.0", + "libp2p-core", "libp2p-swarm", "log", "rand 0.7.3", @@ -3905,18 +3871,18 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.36.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4bb21c5abadbf00360c734f16bf87f1712ed4f23cd46148f625d2ddb867346" +checksum = "95ac5be6c2de2d1ff3f7693fda6faf8a827b1f3e808202277783fea9f527d114" dependencies = [ "either", "fnv", "futures", "futures-timer", "instant", - "libp2p-core 0.33.0", + "libp2p-core", "log", - "pin-project 1.0.10", + "pin-project", "rand 0.7.3", "smallvec", "thiserror", @@ -3925,9 +3891,9 @@ dependencies = [ [[package]] name = "libp2p-swarm-derive" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf2fe8c80b43561355f4d51875273b5b6dfbac37952e8f64b1270769305c9d7" +checksum = "9f54a64b6957249e0ce782f8abf41d97f69330d02bf229f0672d864f0650cc76" dependencies = [ "quote", "syn", @@ -3935,9 +3901,9 @@ dependencies = [ [[package]] name = "libp2p-tcp" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4933e38ef21b50698aefc87799c24f2a365c9d3f6cf50471f3f6a0bc410892" +checksum = "8a6771dc19aa3c65d6af9a8c65222bfc8fcd446630ddca487acd161fa6096f3b" dependencies = [ "async-io", "futures", @@ -3945,32 +3911,32 @@ dependencies = [ "if-watch", "ipnet", "libc", - "libp2p-core 0.33.0", + "libp2p-core", "log", "socket2 0.4.4", ] [[package]] name = "libp2p-uds" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24bdab114f7f2701757d6541266e1131b429bbae382008f207f2114ee4222dcb" +checksum = "d125e3e5f0d58f3c6ac21815b20cf4b6a88b8db9dc26368ea821838f4161fd4d" dependencies = [ "async-std", "futures", - "libp2p-core 0.32.1", + "libp2p-core", "log", ] [[package]] name = "libp2p-wasm-ext" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f066f2b8b1a1d64793f05da2256e6842ecd0293d6735ca2e9bda89831a1bdc06" +checksum = "ec894790eec3c1608f8d1a8a0bdf0dbeb79ed4de2dce964222011c2896dfa05a" dependencies = [ "futures", "js-sys", - "libp2p-core 0.33.0", + "libp2p-core", "parity-send-wrapper", "wasm-bindgen", "wasm-bindgen-futures", @@ -3978,18 +3944,18 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39d398fbb29f432c4128fabdaac2ed155c3bcaf1b9bd40eeeb10a471eefacbf5" +checksum = "9808e57e81be76ff841c106b4c5974fb4d41a233a7bdd2afbf1687ac6def3818" dependencies = [ "either", "futures", "futures-rustls", - "libp2p-core 0.33.0", + "libp2p-core", "log", "parking_lot 0.12.0", "quicksink", - "rw-stream-sink 0.3.0", + "rw-stream-sink", "soketto", "url", "webpki-roots", @@ -3997,12 +3963,12 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe653639ad74877c759720febb0cbcbf4caa221adde4eed2d3126ce5c6f381f" +checksum = "c6dea686217a06072033dc025631932810e2f6ad784e4fafa42e27d311c7a81c" dependencies = [ "futures", - "libp2p-core 0.33.0", + "libp2p-core", "parking_lot 0.12.0", "thiserror", "yamux", @@ -4462,7 +4428,7 @@ dependencies = [ "bytes", "futures", "log", - "pin-project 1.0.10", + "pin-project", "smallvec", "unsigned-varint", ] @@ -6836,33 +6802,13 @@ dependencies = [ "indexmap", ] -[[package]] -name = "pin-project" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9615c18d31137579e9ff063499264ddc1278e7b1982757ebc111028c4d1dc909" -dependencies = [ - "pin-project-internal 0.4.29", -] - [[package]] name = "pin-project" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" dependencies = [ - "pin-project-internal 1.0.10", -] - -[[package]] -name = "pin-project-internal" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "044964427019eed9d49d9d5bbce6047ef18f37100ea400912a9fa4a3523ab12a" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "pin-project-internal", ] [[package]] @@ -7114,16 +7060,6 @@ dependencies = [ "syn", ] -[[package]] -name = "prost" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" -dependencies = [ - "bytes", - "prost-derive 0.9.0", -] - [[package]] name = "prost" version = "0.10.3" @@ -7131,27 +7067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc03e116981ff7d8da8e5c220e374587b98d294af7ba7dd7fda761158f00086f" dependencies = [ "bytes", - "prost-derive 0.10.1", -] - -[[package]] -name = "prost-build" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" -dependencies = [ - "bytes", - "heck 0.3.2", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prost 0.9.0", - "prost-types 0.9.0", - "regex", - "tempfile", - "which", + "prost-derive", ] [[package]] @@ -7169,8 +7085,8 @@ dependencies = [ "log", "multimap", "petgraph", - "prost 0.10.3", - "prost-types 0.10.1", + "prost", + "prost-types", "regex", "tempfile", "which", @@ -7184,24 +7100,11 @@ checksum = "00af1e92c33b4813cc79fda3f2dbf56af5169709be0202df730e9ebc3e4cd007" dependencies = [ "asynchronous-codec", "bytes", - "prost 0.10.3", + "prost", "thiserror", "unsigned-varint", ] -[[package]] -name = "prost-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "prost-derive" version = "0.10.1" @@ -7215,16 +7118,6 @@ dependencies = [ "syn", ] -[[package]] -name = "prost-types" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" -dependencies = [ - "bytes", - "prost 0.9.0", -] - [[package]] name = "prost-types" version = "0.10.1" @@ -7232,7 +7125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" dependencies = [ "bytes", - "prost 0.10.3", + "prost", ] [[package]] @@ -7922,17 +7815,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" -[[package]] -name = "rw-stream-sink" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" -dependencies = [ - "futures", - "pin-project 0.4.29", - "static_assertions", -] - [[package]] name = "rw-stream-sink" version = "0.3.0" @@ -7940,7 +7822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26338f5e09bb721b85b135ea05af7767c90b52f6de4f087d4f4a3a9d64e7dc04" dependencies = [ "futures", - "pin-project 1.0.10", + "pin-project", "static_assertions", ] @@ -7998,8 +7880,8 @@ dependencies = [ "libp2p", "log", "parity-scale-codec", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "quickcheck", "rand 0.7.3", "sc-client-api", @@ -8651,9 +8533,9 @@ dependencies = [ "lru", "parity-scale-codec", "parking_lot 0.12.0", - "pin-project 1.0.10", - "prost 0.10.3", - "prost-build 0.10.4", + "pin-project", + "prost", + "prost-build", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8691,7 +8573,7 @@ dependencies = [ "futures", "libp2p", "parity-scale-codec", - "prost-build 0.10.4", + "prost-build", "sc-peerset", "smallvec", ] @@ -8723,8 +8605,8 @@ dependencies = [ "libp2p", "log", "parity-scale-codec", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "sc-client-api", "sc-network-common", "sc-peerset", @@ -8746,8 +8628,8 @@ dependencies = [ "log", "lru", "parity-scale-codec", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "quickcheck", "sc-block-builder", "sc-client-api", @@ -8954,7 +8836,7 @@ dependencies = [ "parity-scale-codec", "parity-util-mem", "parking_lot 0.12.0", - "pin-project 1.0.10", + "pin-project", "rand 0.7.3", "sc-block-builder", "sc-chain-spec", @@ -9099,7 +8981,7 @@ dependencies = [ "libp2p", "log", "parking_lot 0.12.0", - "pin-project 1.0.10", + "pin-project", "rand 0.7.3", "serde", "serde_json", @@ -11189,7 +11071,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project 1.0.10", + "pin-project", "tracing", ] diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 32a5e23bd49d9..012e6096aab80 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" -libp2p = { version = "0.45.1", default-features = false, features = ["kad"] } +libp2p = { version = "0.46.1", default-features = false, features = ["kad"] } log = "0.4.17" prost = "0.10" rand = "0.7.2" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 72b4efde077ff..ea60e4c9f87e5 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -18,7 +18,7 @@ clap = { version = "3.1.18", features = ["derive"] } fdlimit = "0.2.1" futures = "0.3.21" hex = "0.4.2" -libp2p = "0.45.1" +libp2p = "0.46.1" log = "0.4.17" names = { version = "0.13.0", default-features = false } parity-scale-codec = "3.0.0" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 6d76eba0935ff..12b630f36b89b 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.42" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" -libp2p = { version = "0.45.1", default-features = false } +libp2p = { version = "0.46.1", default-features = false } log = "0.4.17" parking_lot = "0.12.0" serde = { version = "1.0", features = ["derive"] } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 0fac96b0fdde0..144c5ad168996 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] ahash = "0.7.6" futures = "0.3.21" futures-timer = "3.0.1" -libp2p = { version = "0.45.1", default-features = false } +libp2p = { version = "0.46.1", default-features = false } log = "0.4.17" lru = "0.7.5" tracing = "0.1.29" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 1b525844395b5..dfd2db2e6b844 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -29,7 +29,7 @@ futures = "0.3.21" futures-timer = "3.0.2" hex = "0.4.0" ip_network = "0.4.1" -libp2p = "0.45.1" +libp2p = "0.46.1" linked_hash_set = "0.1.3" linked-hash-map = "0.5.4" log = "0.4.17" diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 553eb57958a5d..e69787d7aff77 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -21,6 +21,6 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -libp2p = "0.45.1" +libp2p = "0.46.1" smallvec = "1.8.0" sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index 924b8ed06ab0a..0037177fb4046 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -libp2p = "0.45.1" +libp2p = "0.46.1" log = "0.4.16" prost = "0.10" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 2bae2fb807f7e..f3d1588c0280e 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -52,8 +52,8 @@ use futures_timer::Delay; use ip_network::IpNetwork; use libp2p::{ core::{ - connection::{ConnectionId, ListenerId}, - ConnectedPoint, Multiaddr, PeerId, PublicKey, + connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId, + PublicKey, }, kad::{ handler::KademliaHandlerProto, @@ -1030,7 +1030,7 @@ mod tests { let noise_keys = noise::Keypair::::new().into_authentic(&keypair).unwrap(); - let transport = MemoryTransport + let transport = MemoryTransport::new() .upgrade(upgrade::Version::V1) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) .multiplex(yamux::YamuxConfig::default()) diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index c3e79437bdd06..d668cb25ea455 100644 --- a/client/network/src/peer_info.rs +++ b/client/network/src/peer_info.rs @@ -21,9 +21,8 @@ use fnv::FnvHashMap; use futures::prelude::*; use libp2p::{ core::{ - connection::{ConnectionId, ListenerId}, - either::EitherOutput, - ConnectedPoint, PeerId, PublicKey, + connection::ConnectionId, either::EitherOutput, transport::ListenerId, ConnectedPoint, + PeerId, PublicKey, }, identify::{Identify, IdentifyConfig, IdentifyEvent, IdentifyInfo}, ping::{Ping, PingConfig, PingEvent, PingSuccess}, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 387a7b3fdde90..348d2d0bf8877 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -27,10 +27,7 @@ use bytes::Bytes; use codec::{Decode, DecodeAll, Encode}; use futures::{channel::oneshot, prelude::*}; use libp2p::{ - core::{ - connection::{ConnectionId, ListenerId}, - ConnectedPoint, - }, + core::{connection::ConnectionId, transport::ListenerId, ConnectedPoint}, request_response::OutboundFailure, swarm::{ ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, diff --git a/client/network/src/protocol/notifications/tests.rs b/client/network/src/protocol/notifications/tests.rs index da12dbf216c4c..fa79366d20283 100644 --- a/client/network/src/protocol/notifications/tests.rs +++ b/client/network/src/protocol/notifications/tests.rs @@ -23,8 +23,8 @@ use crate::protocol::notifications::{Notifications, NotificationsOut, ProtocolCo use futures::prelude::*; use libp2p::{ core::{ - connection::{ConnectionId, ListenerId}, - transport::MemoryTransport, + connection::ConnectionId, + transport::{ListenerId, MemoryTransport}, upgrade, ConnectedPoint, }, identity, noise, @@ -56,7 +56,7 @@ fn build_nodes() -> (Swarm, Swarm) { let noise_keys = noise::Keypair::::new().into_authentic(&keypair).unwrap(); - let transport = MemoryTransport + let transport = MemoryTransport::new() .upgrade(upgrade::Version::V1) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) .multiplex(yamux::YamuxConfig::default()) diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 6c7b0f3fcdfc8..cec4aa2a07fba 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -40,10 +40,7 @@ use futures::{ prelude::*, }; use libp2p::{ - core::{ - connection::{ConnectionId, ListenerId}, - ConnectedPoint, Multiaddr, PeerId, - }, + core::{connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId}, request_response::{ handler::RequestResponseHandler, ProtocolSupport, RequestResponse, RequestResponseCodec, RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, ResponseChannel, @@ -968,7 +965,7 @@ mod tests { let noise_keys = noise::Keypair::::new().into_authentic(&keypair).unwrap(); - let transport = MemoryTransport + let transport = MemoryTransport::new() .upgrade(upgrade::Version::V1) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) .multiplex(libp2p::yamux::YamuxConfig::default()) diff --git a/client/network/src/transport.rs b/client/network/src/transport.rs index 883f828e7db51..23645b11795c3 100644 --- a/client/network/src/transport.rs +++ b/client/network/src/transport.rs @@ -54,16 +54,17 @@ pub fn build_transport( ) -> (Boxed<(PeerId, StreamMuxerBox)>, Arc) { // Build the base layer of the transport. let transport = if !memory_only { - let desktop_trans = tcp::TcpConfig::new().nodelay(true); + let tcp_config = tcp::GenTcpConfig::new().nodelay(true); + let desktop_trans = tcp::TcpTransport::new(tcp_config.clone()); let desktop_trans = websocket::WsConfig::new(desktop_trans) - .or_transport(tcp::TcpConfig::new().nodelay(true)); + .or_transport(tcp::TcpTransport::new(tcp_config.clone())); let dns_init = futures::executor::block_on(dns::DnsConfig::system(desktop_trans)); EitherTransport::Left(if let Ok(dns) = dns_init { EitherTransport::Left(dns) } else { - let desktop_trans = tcp::TcpConfig::new().nodelay(true); + let desktop_trans = tcp::TcpTransport::new(tcp_config.clone()); let desktop_trans = websocket::WsConfig::new(desktop_trans) - .or_transport(tcp::TcpConfig::new().nodelay(true)); + .or_transport(tcp::TcpTransport::new(tcp_config)); EitherTransport::Right(desktop_trans.map_err(dns::DnsErr::Transport)) }) } else { diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 9185e812bc6cd..a61f780fd56ad 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ ] } either = "1.5.3" futures = "0.3.21" -libp2p = "0.45.1" +libp2p = "0.46.1" log = "0.4.17" lru = "0.7.5" prost = "0.10" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 2af1dd8cb9b54..fdb9befc41cb1 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -17,7 +17,7 @@ async-std = "1.11.0" async-trait = "0.1.50" futures = "0.3.21" futures-timer = "3.0.1" -libp2p = { version = "0.45.1", default-features = false } +libp2p = { version = "0.46.1", default-features = false } log = "0.4.17" parking_lot = "0.12.0" rand = "0.7.2" diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index f150c728613ba..510ebf7006155 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" -libp2p = { version = "0.45.1", default-features = false } +libp2p = { version = "0.46.1", default-features = false } log = "0.4.17" serde_json = "1.0.79" wasm-timer = "0.2" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 9682dc824f930..0d966dacfc2c8 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = "0.4.19" futures = "0.3.21" -libp2p = { version = "0.45.1", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } +libp2p = { version = "0.46.1", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.17" parking_lot = "0.12.0" pin-project = "1.0.10" diff --git a/client/telemetry/src/transport.rs b/client/telemetry/src/transport.rs index e21a2380be255..d64da44a83b6b 100644 --- a/client/telemetry/src/transport.rs +++ b/client/telemetry/src/transport.rs @@ -31,7 +31,8 @@ const CONNECT_TIMEOUT: Duration = Duration::from_secs(20); pub(crate) fn initialize_transport() -> Result { let transport = { - let inner = block_on(libp2p::dns::DnsConfig::system(libp2p::tcp::TcpConfig::new()))?; + let tcp_transport = libp2p::tcp::TcpTransport::new(libp2p::tcp::GenTcpConfig::new()); + let inner = block_on(libp2p::dns::DnsConfig::system(tcp_transport))?; libp2p::websocket::framed::WsConfig::new(inner).and_then(|connec, _| { let connec = connec .with(|item| { From 3c48c61ac6a088901668820a825e2d5823bdea82 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 12 Jul 2022 18:08:54 +0100 Subject: [PATCH 0962/1472] prep council election pallet for being dissolved (#11790) * prep council election pallet for being dissolved + make it temporarily bounded * fix tests * fix * Update frame/elections-phragmen/src/lib.rs * fix bench? --- Cargo.lock | 1 + frame/elections-phragmen/Cargo.toml | 1 + frame/elections-phragmen/src/benchmarking.rs | 86 ++----------- frame/elections-phragmen/src/lib.rs | 129 ++++++++----------- 4 files changed, 66 insertions(+), 151 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26f43fa4ae0ba..f98d98a3c571f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5673,6 +5673,7 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-std", + "sp-tracing", "substrate-test-utils", ] diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index 0f195f12cce3c..d71a74f76a114 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -30,6 +30,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-tracing = { path = "../../primitives/tracing" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 44dd6aff09f0c..9a9d448449eca 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -22,17 +22,12 @@ use super::*; use frame_benchmarking::{account, benchmarks, whitelist, BenchmarkError, BenchmarkResult}; -use frame_support::{ - dispatch::{DispatchResultWithPostInfo, UnfilteredDispatchable}, - traits::OnInitialize, -}; +use frame_support::{dispatch::DispatchResultWithPostInfo, traits::OnInitialize}; use frame_system::RawOrigin; use crate::Pallet as Elections; const BALANCE_FACTOR: u32 = 250; -const MAX_VOTERS: u32 = 500; -const MAX_CANDIDATES: u32 = 200; type Lookup = <::Lookup as StaticLookup>::Source; @@ -345,38 +340,6 @@ benchmarks! { ))?; } - // -- Root ones - #[extra] // this calls into phragmen and consumes a full block for now. - remove_member_without_replacement_extra { - // worse case is when we remove a member and we have no runner as a replacement. This - // triggers phragmen again. The only parameter is how many candidates will compete for the - // new slot. - let c in 1 .. MAX_CANDIDATES; - clean::(); - - // fill only desired members. no runners-up. - let all_members = fill_seats_up_to::(T::DesiredMembers::get())?; - assert_eq!(>::members().len() as u32, T::DesiredMembers::get()); - - // submit a new one to compensate, with self-vote. - let replacements = submit_candidates_with_self_vote::(c, "new_candidate")?; - - // create some voters for these replacements. - distribute_voters::(replacements, MAX_VOTERS, MAXIMUM_VOTE)?; - - let to_remove = as_lookup::(all_members[0].clone()); - }: remove_member(RawOrigin::Root, to_remove, false) - verify { - // must still have the desired number of members members. - assert_eq!(>::members().len() as u32, T::DesiredMembers::get()); - #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } - } - remove_member_with_replacement { // easy case. We have a runner up. Nothing will have that much of an impact. m will be // number of members and runners. There is always at least one runner. @@ -385,7 +348,7 @@ benchmarks! { let _ = fill_seats_up_to::(m)?; let removing = as_lookup::(>::members_ids()[0].clone()); - }: remove_member(RawOrigin::Root, removing, true) + }: remove_member(RawOrigin::Root, removing, true, false) verify { // must still have enough members. assert_eq!(>::members().len() as u32, T::DesiredMembers::get()); @@ -397,39 +360,6 @@ benchmarks! { } } - remove_member_wrong_refund { - // The root call by mistake indicated that this will have no replacement, while it has! - // this has now consumed a lot of weight and need to refund. - let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get(); - clean::(); - - let _ = fill_seats_up_to::(m)?; - let removing = as_lookup::(>::members_ids()[0].clone()); - let who = T::Lookup::lookup(removing.clone()).expect("member was added above"); - let call = Call::::remove_member { who: removing, has_replacement: false }.encode(); - }: { - assert_eq!( - as Decode>::decode(&mut &*call) - .expect("call is encoded above, encoding must be correct") - .dispatch_bypass_filter(RawOrigin::Root.into()) - .unwrap_err() - .error, - Error::::InvalidReplacement.into(), - ); - } - verify { - // must still have enough members. - assert_eq!(>::members().len() as u32, T::DesiredMembers::get()); - // on fail, `who` must still be a member - assert!(>::members_ids().contains(&who)); - #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } - } - clean_defunct_voters { // total number of voters. let v in (MAX_VOTERS / 2) .. MAX_VOTERS; @@ -439,7 +369,7 @@ benchmarks! { // remove any previous stuff. clean::(); - let all_candidates = submit_candidates::(v, "candidates")?; + let all_candidates = submit_candidates::(MAX_CANDIDATES, "candidates")?; distribute_voters::(all_candidates, v, MAXIMUM_VOTE)?; // all candidates leave. @@ -474,7 +404,7 @@ benchmarks! { let votes_per_voter = (e / v).min(MAXIMUM_VOTE as u32); let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; - let _ = distribute_voters::(all_candidates, v, votes_per_voter as usize)?; + let _ = distribute_voters::(all_candidates, v.saturating_sub(c), votes_per_voter as usize)?; }: { >::on_initialize(T::TermDuration::get()); } @@ -503,7 +433,11 @@ benchmarks! { let votes_per_voter = e / fixed_v; let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; - let _ = distribute_voters::(all_candidates, fixed_v, votes_per_voter as usize)?; + let _ = distribute_voters::( + all_candidates, + fixed_v - c, + votes_per_voter as usize, + )?; }: { >::on_initialize(T::TermDuration::get()); } @@ -525,7 +459,7 @@ benchmarks! { #[extra] election_phragmen_v { let v in 4 .. 16; - let fixed_c = MAX_CANDIDATES; + let fixed_c = MAX_CANDIDATES / 10; let fixed_e = 64; clean::(); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index ec2234cde5a6e..28fed28f18e5c 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -100,7 +100,6 @@ use codec::{Decode, Encode}; use frame_support::{ - dispatch::WithPostDispatchInfo, traits::{ defensive_prelude::*, ChangeMembers, Contains, ContainsLengthBound, Currency, CurrencyToVote, Get, InitializeMembers, LockIdentifier, LockableCurrency, OnUnbalanced, @@ -126,6 +125,17 @@ pub mod migrations; /// The maximum votes allowed per voter. pub const MAXIMUM_VOTE: usize = 16; +// Some safe temp values to make the wasm execution sane while we still use this pallet. +#[cfg(test)] +pub(crate) const MAX_CANDIDATES: u32 = 100; +#[cfg(not(test))] +pub(crate) const MAX_CANDIDATES: u32 = 1000; + +#[cfg(test)] +pub(crate) const MAX_VOTERS: u32 = 1000; +#[cfg(not(test))] +pub(crate) const MAX_VOTERS: u32 = 10 * 1000; + type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type NegativeImbalanceOf = <::Currency as Currency< @@ -385,8 +395,9 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let actual_count = >::decode_len().unwrap_or(0); - ensure!(actual_count as u32 <= candidate_count, Error::::InvalidWitnessData); + let actual_count = >::decode_len().unwrap_or(0) as u32; + ensure!(actual_count <= candidate_count, Error::::InvalidWitnessData); + ensure!(actual_count <= MAX_CANDIDATES, Error::::TooManyCandidates); let index = Self::is_candidate(&who).err().ok_or(Error::::DuplicatedCandidate)?; @@ -469,7 +480,11 @@ pub mod pallet { /// the outgoing member is slashed. /// /// If a runner-up is available, then the best runner-up will be removed and replaces the - /// outgoing member. Otherwise, a new phragmen election is started. + /// outgoing member. Otherwise, if `rerun_election` is `true`, a new phragmen election is + /// started, else, nothing happens. + /// + /// If `slash_bond` is set to true, the bond of the member being removed is slashed. Else, + /// it is returned. /// /// The dispatch origin of this call must be root. /// @@ -479,33 +494,24 @@ pub mod pallet { /// If we have a replacement, we use a small weight. Else, since this is a root call and /// will go into phragmen, we assume full block for now. /// # - #[pallet::weight(if *has_replacement { - T::WeightInfo::remove_member_with_replacement() - } else { + #[pallet::weight(if *rerun_election { T::WeightInfo::remove_member_without_replacement() + } else { + T::WeightInfo::remove_member_with_replacement() })] pub fn remove_member( origin: OriginFor, who: ::Source, - has_replacement: bool, + slash_bond: bool, + rerun_election: bool, ) -> DispatchResultWithPostInfo { ensure_root(origin)?; let who = T::Lookup::lookup(who)?; - let will_have_replacement = >::decode_len().map_or(false, |l| l > 0); - if will_have_replacement != has_replacement { - // In both cases, we will change more weight than need. Refund and abort. - return Err(Error::::InvalidReplacement.with_weight( - // refund. The weight value comes from a benchmark which is special to this. - T::WeightInfo::remove_member_wrong_refund(), - )) - } - - let had_replacement = Self::remove_and_replace_member(&who, true)?; - debug_assert_eq!(has_replacement, had_replacement); + let _ = Self::remove_and_replace_member(&who, slash_bond)?; Self::deposit_event(Event::MemberKicked { member: who }); - if !had_replacement { + if rerun_election { Self::do_phragmen(); } @@ -585,10 +591,10 @@ pub mod pallet { UnableToPayBond, /// Must be a voter. MustBeVoter, - /// Cannot report self. - ReportSelf, /// Duplicated candidate submission. DuplicatedCandidate, + /// Too many candidates have been created. + TooManyCandidates, /// Member cannot re-submit candidacy. MemberSubmit, /// Runner cannot re-submit candidacy. @@ -893,7 +899,7 @@ impl Pallet { if candidates_and_deposit.len().is_zero() { Self::deposit_event(Event::EmptyTerm); - return T::DbWeight::get().reads(5) + return T::DbWeight::get().reads(3) } // All of the new winners that come out of phragmen will thus have a deposit recorded. @@ -906,10 +912,28 @@ impl Pallet { let to_balance = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); let mut num_edges: u32 = 0; + // used for prime election. - let voters_and_stakes = Voting::::iter() - .map(|(voter, Voter { stake, votes, .. })| (voter, stake, votes)) - .collect::>(); + let mut voters_and_stakes = Vec::new(); + match Voting::::iter().try_for_each(|(voter, Voter { stake, votes, .. })| { + if voters_and_stakes.len() < MAX_VOTERS as usize { + voters_and_stakes.push((voter, stake, votes)); + Ok(()) + } else { + Err(()) + } + }) { + Ok(_) => (), + Err(_) => { + log::error!( + target: "runtime::elections-phragmen", + "Failed to run election. Number of voters exceeded", + ); + Self::deposit_event(Event::ElectionError); + return T::DbWeight::get().reads(3 + MAX_VOTERS as u64) + }, + } + // used for phragmen. let voters_and_votes = voters_and_stakes .iter() @@ -1137,7 +1161,7 @@ mod tests { use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, ModuleError, + BuildStorage, }; use substrate_test_utils::assert_eq_uvec; @@ -1321,6 +1345,7 @@ mod tests { self } pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + sp_tracing::try_init_simple(); MEMBERS.with(|m| { *m.borrow_mut() = self.genesis_members.iter().map(|(m, _)| m.clone()).collect::>() @@ -2494,7 +2519,7 @@ mod tests { assert_ok!(submit_candidacy(Origin::signed(3))); assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(Elections::remove_member(Origin::root(), 4, false)); + assert_ok!(Elections::remove_member(Origin::root(), 4, true, true)); assert_eq!(balances(&4), (35, 2)); // slashed assert_eq!(Elections::election_rounds(), 2); // new election round @@ -2502,52 +2527,6 @@ mod tests { }); } - #[test] - fn remove_member_should_indicate_replacement() { - ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - - System::set_block_number(5); - Elections::on_initialize(System::block_number()); - assert_eq!(members_ids(), vec![4, 5]); - - // no replacement yet. - let unwrapped_error = Elections::remove_member(Origin::root(), 4, true).unwrap_err(); - assert!(matches!( - unwrapped_error.error, - DispatchError::Module(ModuleError { message: Some("InvalidReplacement"), .. }) - )); - assert!(unwrapped_error.post_info.actual_weight.is_some()); - }); - - ExtBuilder::default().desired_runners_up(1).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - - System::set_block_number(5); - Elections::on_initialize(System::block_number()); - assert_eq!(members_ids(), vec![4, 5]); - assert_eq!(runners_up_ids(), vec![3]); - - // there is a replacement! and this one needs a weight refund. - let unwrapped_error = Elections::remove_member(Origin::root(), 4, false).unwrap_err(); - assert!(matches!( - unwrapped_error.error, - DispatchError::Module(ModuleError { message: Some("InvalidReplacement"), .. }) - )); - assert!(unwrapped_error.post_info.actual_weight.is_some()); - }); - } - #[test] fn seats_should_be_released_when_no_vote() { ExtBuilder::default().build_and_execute(|| { @@ -2684,7 +2663,7 @@ mod tests { Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![2, 4]); - assert_ok!(Elections::remove_member(Origin::root(), 2, true)); + assert_ok!(Elections::remove_member(Origin::root(), 2, true, false)); assert_eq!(members_ids(), vec![4, 5]); }); } From b0777b4c7f7d8d3c635319d0153953d0a22aa58e Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Tue, 12 Jul 2022 23:34:17 +0300 Subject: [PATCH 0963/1472] Network sync refactoring (part 4) (#11412) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove direct dependency of `sc-network` on `sc-network-light` * Move `WarpSyncProvider` trait and surrounding data structures into `sc-network-common` * Move `WarpSyncProvider` trait and surrounding data structures into `sc-network-common` * Create `sync` module in `sc-network-common`, create `ChainSync` trait there (not used yet), move a bunch of associated data structures from `sc-network-sync` * Switch from concrete implementation to `ChainSync` trait from `sc-network-common` * Introduce `OpaqueStateRequest`/`OpaqueStateResponse` to remove generics from `StateSync` trait * Introduce `OpaqueBlockRequest`/`OpaqueBlockResponse`, make `scheme` module of `sc-network-sync` private * Surface `sc-network-sync` into `sc-service` and make `sc-network` not depend on it anymore * Remove now unnecessary dependency from `sc-network` * Replace crate links with just text since dependencies are gone now * Remove `warp_sync` re-export from `sc-network-common` * Update copyright in network-related files * Address review comments about documentation * Apply review suggestion * Rename `extra_requests` module to `metrics` Co-authored-by: Bastian Köcher --- Cargo.lock | 13 +- client/beefy/src/tests.rs | 14 +- client/consensus/aura/src/lib.rs | 14 +- client/consensus/babe/src/tests.rs | 15 +- client/finality-grandpa/Cargo.toml | 1 + client/finality-grandpa/src/tests.rs | 20 +- client/finality-grandpa/src/warp_proof.rs | 2 +- client/network/Cargo.toml | 5 +- client/network/common/Cargo.toml | 5 + client/network/common/src/lib.rs | 1 + client/network/common/src/sync.rs | 394 ++++++ .../{sync/src => common/src/sync}/message.rs | 2 +- client/network/common/src/sync/metrics.rs | 25 + client/network/common/src/sync/warp.rs | 94 ++ client/network/src/behaviour.rs | 68 +- client/network/src/bitswap.rs | 5 +- client/network/src/config.rs | 33 +- client/network/src/lib.rs | 8 +- client/network/src/protocol.rs | 310 ++--- client/network/src/protocol/message.rs | 10 +- client/network/src/service.rs | 27 +- client/network/src/service/tests.rs | 24 +- client/network/sync/Cargo.toml | 2 - .../network/sync/src/block_request_handler.rs | 6 +- client/network/sync/src/blocks.rs | 4 +- client/network/sync/src/extra_requests.rs | 11 +- client/network/sync/src/lib.rs | 1112 ++++++++--------- client/network/sync/src/schema.rs | 2 +- client/network/sync/src/state.rs | 10 +- client/network/sync/src/warp.rs | 45 +- .../network/sync/src/warp_request_handler.rs | 47 +- client/network/test/Cargo.toml | 2 + client/network/test/src/lib.rs | 110 +- client/service/Cargo.toml | 4 +- client/service/src/builder.rs | 28 +- 35 files changed, 1359 insertions(+), 1114 deletions(-) create mode 100644 client/network/common/src/sync.rs rename client/network/{sync/src => common/src/sync}/message.rs (99%) create mode 100644 client/network/common/src/sync/metrics.rs create mode 100644 client/network/common/src/sync/warp.rs diff --git a/Cargo.lock b/Cargo.lock index f98d98a3c571f..3b7c315be4390 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8429,6 +8429,7 @@ dependencies = [ "sc-consensus", "sc-keystore", "sc-network", + "sc-network-common", "sc-network-gossip", "sc-network-test", "sc-telemetry", @@ -8553,7 +8554,6 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core", - "sp-finality-grandpa", "sp-runtime", "sp-test-primitives", "sp-tracing", @@ -8571,12 +8571,17 @@ dependencies = [ name = "sc-network-common" version = "0.10.0-dev" dependencies = [ + "bitflags", "futures", "libp2p", "parity-scale-codec", "prost-build", + "sc-consensus", "sc-peerset", "smallvec", + "sp-consensus", + "sp-finality-grandpa", + "sp-runtime", ] [[package]] @@ -8621,8 +8626,6 @@ dependencies = [ name = "sc-network-sync" version = "0.10.0-dev" dependencies = [ - "bitflags", - "either", "fork-tree", "futures", "libp2p", @@ -8667,6 +8670,8 @@ dependencies = [ "sc-consensus", "sc-network", "sc-network-common", + "sc-network-light", + "sc-network-sync", "sc-service", "sp-blockchain", "sp-consensus", @@ -8849,6 +8854,8 @@ dependencies = [ "sc-keystore", "sc-network", "sc-network-common", + "sc-network-light", + "sc-network-sync", "sc-offchain", "sc-rpc", "sc-rpc-server", diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index b5ff27c808908..8090c425e71db 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -28,7 +28,6 @@ use sc_chain_spec::{ChainSpec, GenericChainSpec}; use sc_client_api::HeaderBackend; use sc_consensus::BoxJustificationImport; use sc_keystore::LocalKeystore; -use sc_network::config::ProtocolConfig; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, TestNetFactory, @@ -111,6 +110,7 @@ pub(crate) struct PeerData { pub(crate) beefy_link_half: Mutex>, } +#[derive(Default)] pub(crate) struct BeefyTestNet { peers: Vec, } @@ -166,17 +166,7 @@ impl TestNetFactory for BeefyTestNet { type BlockImport = PeersClient; type PeerData = PeerData; - /// Create new test network with peers and given config. - fn from_config(_config: &ProtocolConfig) -> Self { - BeefyTestNet { peers: Vec::new() } - } - - fn make_verifier( - &self, - _client: PeersClient, - _cfg: &ProtocolConfig, - _: &PeerData, - ) -> Self::Verifier { + fn make_verifier(&self, _client: PeersClient, _: &PeerData) -> Self::Verifier { PassThroughVerifier::new(false) // use non-instant finality. } diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index ac3b89f2ff9a2..ee8be727dcdac 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -566,7 +566,6 @@ mod tests { use sc_consensus::BoxJustificationImport; use sc_consensus_slots::{BackoffAuthoringOnFinalizedHeadLagging, SimpleSlotWorker}; use sc_keystore::LocalKeystore; - use sc_network::config::ProtocolConfig; use sc_network_test::{Block as TestBlock, *}; use sp_application_crypto::key_types::AURA; use sp_consensus::{ @@ -645,6 +644,7 @@ mod tests { >; type AuraPeer = Peer<(), PeersClient>; + #[derive(Default)] pub struct AuraTestNet { peers: Vec, } @@ -654,17 +654,7 @@ mod tests { type PeerData = (); type BlockImport = PeersClient; - /// Create new test network with peers and given config. - fn from_config(_config: &ProtocolConfig) -> Self { - AuraTestNet { peers: Vec::new() } - } - - fn make_verifier( - &self, - client: PeersClient, - _cfg: &ProtocolConfig, - _peer_data: &(), - ) -> Self::Verifier { + fn make_verifier(&self, client: PeersClient, _peer_data: &()) -> Self::Verifier { let client = client.as_client(); let slot_duration = slot_duration(&*client).expect("slot duration available"); diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index e0590fc0cd86e..c0a7a8c6c013a 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -29,7 +29,6 @@ use sc_client_api::{backend::TransactionFor, BlockchainEvents, Finalizer}; use sc_consensus::{BoxBlockImport, BoxJustificationImport}; use sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging; use sc_keystore::LocalKeystore; -use sc_network::config::ProtocolConfig; use sc_network_test::{Block as TestBlock, *}; use sp_application_crypto::key_types::BABE; use sp_consensus::{AlwaysCanAuthor, DisableProofRecording, NoNetwork as DummyOracle, Proposal}; @@ -220,6 +219,7 @@ where type BabePeer = Peer, BabeBlockImport>; +#[derive(Default)] pub struct BabeTestNet { peers: Vec, } @@ -278,12 +278,6 @@ impl TestNetFactory for BabeTestNet { type PeerData = Option; type BlockImport = BabeBlockImport; - /// Create new test network with peers and given config. - fn from_config(_config: &ProtocolConfig) -> Self { - debug!(target: "babe", "Creating test network from config"); - BabeTestNet { peers: Vec::new() } - } - fn make_block_import( &self, client: PeersClient, @@ -309,12 +303,7 @@ impl TestNetFactory for BabeTestNet { ) } - fn make_verifier( - &self, - client: PeersClient, - _cfg: &ProtocolConfig, - maybe_link: &Option, - ) -> Self::Verifier { + fn make_verifier(&self, client: PeersClient, maybe_link: &Option) -> Self::Verifier { use substrate_test_runtime_client::DefaultTestClientBuilderExt; let client = client.as_client(); diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 77cd847d48169..a5f20b9f3261d 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -36,6 +36,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 2d12232b04f15..623ac577c5579 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -28,7 +28,7 @@ use sc_consensus::{ BlockImport, BlockImportParams, BoxJustificationImport, ForkChoiceStrategy, ImportResult, ImportedAux, }; -use sc_network::config::{ProtocolConfig, Role}; +use sc_network::config::Role; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, Hash, PassThroughVerifier, Peer, PeersClient, PeersFullClient, TestClient, TestNetFactory, @@ -73,6 +73,7 @@ type GrandpaBlockImport = crate::GrandpaBlockImport< LongestChain, >; +#[derive(Default)] struct GrandpaTestNet { peers: Vec, test_config: TestApi, @@ -110,16 +111,6 @@ impl TestNetFactory for GrandpaTestNet { type PeerData = PeerData; type BlockImport = GrandpaBlockImport; - /// Create new test network with peers and given config. - fn from_config(_config: &ProtocolConfig) -> Self { - GrandpaTestNet { peers: Vec::new(), test_config: Default::default() } - } - - fn default_config() -> ProtocolConfig { - // This is unused. - ProtocolConfig::default() - } - fn add_full_peer(&mut self) { self.add_full_peer_with_config(FullPeerConfig { notifications_protocols: vec![grandpa_protocol_name::NAME.into()], @@ -128,12 +119,7 @@ impl TestNetFactory for GrandpaTestNet { }) } - fn make_verifier( - &self, - _client: PeersClient, - _cfg: &ProtocolConfig, - _: &PeerData, - ) -> Self::Verifier { + fn make_verifier(&self, _client: PeersClient, _: &PeerData) -> Self::Verifier { PassThroughVerifier::new(false) // use non-instant finality. } diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index 90f6828a1105d..a31a0a8b91908 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -23,7 +23,7 @@ use crate::{ BlockNumberOps, GrandpaJustification, SharedAuthoritySet, }; use sc_client_api::Backend as ClientBackend; -use sc_network::warp_request_handler::{EncodedProof, VerificationResult, WarpSyncProvider}; +use sc_network_common::sync::warp::{EncodedProof, VerificationResult, WarpSyncProvider}; use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; use sp_finality_grandpa::{AuthorityList, SetId, GRANDPA_ENGINE_ID}; use sp_runtime::{ diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index dfd2db2e6b844..2742262b57e40 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -51,15 +51,12 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sc-network-common = { version = "0.10.0-dev", path = "./common" } -sc-network-light = { version = "0.10.0-dev", path = "./light" } -sc-network-sync = { version = "0.10.0-dev", path = "./sync" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] @@ -67,6 +64,8 @@ assert_matches = "1.3" async-std = "1.11.0" rand = "0.7.2" tempfile = "3.1.0" +sc-network-light = { version = "0.10.0-dev", path = "./light" } +sc-network-sync = { version = "0.10.0-dev", path = "./sync" } sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index e69787d7aff77..b0e3a8fe42a83 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -17,10 +17,15 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.10" [dependencies] +bitflags = "1.3.2" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" libp2p = "0.46.1" smallvec = "1.8.0" +sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/client/network/common/src/lib.rs b/client/network/common/src/lib.rs index 81769e23debbb..9fbedc542c123 100644 --- a/client/network/common/src/lib.rs +++ b/client/network/common/src/lib.rs @@ -21,3 +21,4 @@ pub mod config; pub mod message; pub mod request_responses; +pub mod sync; diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs new file mode 100644 index 0000000000000..2ee8f8c51814b --- /dev/null +++ b/client/network/common/src/sync.rs @@ -0,0 +1,394 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Abstract interfaces and data structures related to network sync. + +pub mod message; +pub mod metrics; +pub mod warp; + +use libp2p::PeerId; +use message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}; +use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; +use sp_consensus::BlockOrigin; +use sp_runtime::{ + traits::{Block as BlockT, NumberFor}, + Justifications, +}; +use std::{any::Any, fmt, fmt::Formatter, task::Poll}; +use warp::{EncodedProof, WarpProofRequest, WarpSyncProgress}; + +/// The sync status of a peer we are trying to sync with +#[derive(Debug)] +pub struct PeerInfo { + /// Their best block hash. + pub best_hash: Block::Hash, + /// Their best block number. + pub best_number: NumberFor, +} + +/// Reported sync state. +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum SyncState { + /// Initial sync is complete, keep-up sync is active. + Idle, + /// Actively catching up with the chain. + Downloading, +} + +/// Reported state download progress. +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct StateDownloadProgress { + /// Estimated download percentage. + pub percentage: u32, + /// Total state size in bytes downloaded so far. + pub size: u64, +} + +/// Syncing status and statistics. +#[derive(Clone)] +pub struct SyncStatus { + /// Current global sync state. + pub state: SyncState, + /// Target sync block number. + pub best_seen_block: Option>, + /// Number of peers participating in syncing. + pub num_peers: u32, + /// Number of blocks queued for import + pub queued_blocks: u32, + /// State sync status in progress, if any. + pub state_sync: Option, + /// Warp sync in progress, if any. + pub warp_sync: Option>, +} + +/// A peer did not behave as expected and should be reported. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BadPeer(pub PeerId, pub sc_peerset::ReputationChange); + +impl fmt::Display for BadPeer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Bad peer {}; Reputation change: {:?}", self.0, self.1) + } +} + +impl std::error::Error for BadPeer {} + +/// Result of [`ChainSync::on_block_data`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum OnBlockData { + /// The block should be imported. + Import(BlockOrigin, Vec>), + /// A new block request needs to be made to the given peer. + Request(PeerId, BlockRequest), +} + +/// Result of [`ChainSync::on_block_justification`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum OnBlockJustification { + /// The justification needs no further handling. + Nothing, + /// The justification should be imported. + Import { + peer: PeerId, + hash: Block::Hash, + number: NumberFor, + justifications: Justifications, + }, +} + +/// Result of [`ChainSync::on_state_data`]. +#[derive(Debug)] +pub enum OnStateData { + /// The block and state that should be imported. + Import(BlockOrigin, IncomingBlock), + /// A new state request needs to be made to the given peer. + Continue, +} + +/// Result of [`ChainSync::poll_block_announce_validation`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum PollBlockAnnounceValidation { + /// The announcement failed at validation. + /// + /// The peer reputation should be decreased. + Failure { + /// Who sent the processed block announcement? + who: PeerId, + /// Should the peer be disconnected? + disconnect: bool, + }, + /// The announcement does not require further handling. + Nothing { + /// Who sent the processed block announcement? + who: PeerId, + /// Was this their new best block? + is_best: bool, + /// The announcement. + announce: BlockAnnounce, + }, + /// The announcement header should be imported. + ImportHeader { + /// Who sent the processed block announcement? + who: PeerId, + /// Was this their new best block? + is_best: bool, + /// The announcement. + announce: BlockAnnounce, + }, + /// The block announcement should be skipped. + Skip, +} + +/// Operation mode. +#[derive(Debug, PartialEq, Eq)] +pub enum SyncMode { + // Sync headers only + Light, + // Sync headers and block bodies + Full, + // Sync headers and the last finalied state + LightState { storage_chain_mode: bool, skip_proofs: bool }, + // Warp sync mode. + Warp, +} + +#[derive(Debug)] +pub struct Metrics { + pub queued_blocks: u32, + pub fork_targets: u32, + pub justifications: metrics::Metrics, +} + +/// Wrapper for implementation-specific state request. +/// +/// NOTE: Implementation must be able to encode and decode it for network purposes. +pub struct OpaqueStateRequest(pub Box); + +impl fmt::Debug for OpaqueStateRequest { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("OpaqueStateRequest").finish() + } +} + +/// Wrapper for implementation-specific state response. +/// +/// NOTE: Implementation must be able to encode and decode it for network purposes. +pub struct OpaqueStateResponse(pub Box); + +impl fmt::Debug for OpaqueStateResponse { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("OpaqueStateResponse").finish() + } +} + +/// Wrapper for implementation-specific block request. +/// +/// NOTE: Implementation must be able to encode and decode it for network purposes. +pub struct OpaqueBlockRequest(pub Box); + +impl fmt::Debug for OpaqueBlockRequest { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("OpaqueBlockRequest").finish() + } +} + +/// Wrapper for implementation-specific block response. +/// +/// NOTE: Implementation must be able to encode and decode it for network purposes. +pub struct OpaqueBlockResponse(pub Box); + +impl fmt::Debug for OpaqueBlockResponse { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("OpaqueBlockResponse").finish() + } +} + +/// Something that represents the syncing strategy to download past and future blocks of the chain. +pub trait ChainSync: Send { + /// Returns the state of the sync of the given peer. + /// + /// Returns `None` if the peer is unknown. + fn peer_info(&self, who: &PeerId) -> Option>; + + /// Returns the current sync status. + fn status(&self) -> SyncStatus; + + /// Number of active forks requests. This includes + /// requests that are pending or could be issued right away. + fn num_sync_requests(&self) -> usize; + + /// Number of downloaded blocks. + fn num_downloaded_blocks(&self) -> usize; + + /// Returns the current number of peers stored within this state machine. + fn num_peers(&self) -> usize; + + /// Handle a new connected peer. + /// + /// Call this method whenever we connect to a new peer. + fn new_peer( + &mut self, + who: PeerId, + best_hash: Block::Hash, + best_number: NumberFor, + ) -> Result>, BadPeer>; + + /// Signal that a new best block has been imported. + fn update_chain_info(&mut self, best_hash: &Block::Hash, best_number: NumberFor); + + /// Schedule a justification request for the given block. + fn request_justification(&mut self, hash: &Block::Hash, number: NumberFor); + + /// Clear all pending justification requests. + fn clear_justification_requests(&mut self); + + /// Request syncing for the given block from given set of peers. + fn set_sync_fork_request( + &mut self, + peers: Vec, + hash: &Block::Hash, + number: NumberFor, + ); + + /// Get an iterator over all scheduled justification requests. + fn justification_requests( + &mut self, + ) -> Box)> + '_>; + + /// Get an iterator over all block requests of all peers. + fn block_requests(&mut self) -> Box)> + '_>; + + /// Get a state request, if any. + fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)>; + + /// Get a warp sync request, if any. + fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)>; + + /// Handle a response from the remote to a block request that we made. + /// + /// `request` must be the original request that triggered `response`. + /// or `None` if data comes from the block announcement. + /// + /// If this corresponds to a valid block, this outputs the block that + /// must be imported in the import queue. + fn on_block_data( + &mut self, + who: &PeerId, + request: Option>, + response: BlockResponse, + ) -> Result, BadPeer>; + + /// Handle a response from the remote to a state request that we made. + fn on_state_data( + &mut self, + who: &PeerId, + response: OpaqueStateResponse, + ) -> Result, BadPeer>; + + /// Handle a response from the remote to a warp proof request that we made. + fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer>; + + /// Handle a response from the remote to a justification request that we made. + /// + /// `request` must be the original request that triggered `response`. + fn on_block_justification( + &mut self, + who: PeerId, + response: BlockResponse, + ) -> Result, BadPeer>; + + /// A batch of blocks have been processed, with or without errors. + /// + /// Call this when a batch of blocks have been processed by the import + /// queue, with or without errors. + fn on_blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, Block::Hash)>, + ) -> Box), BadPeer>>>; + + /// Call this when a justification has been processed by the import queue, + /// with or without errors. + fn on_justification_import( + &mut self, + hash: Block::Hash, + number: NumberFor, + success: bool, + ); + + /// Notify about finalization of the given block. + fn on_block_finalized(&mut self, hash: &Block::Hash, number: NumberFor); + + /// Push a block announce validation. + /// + /// It is required that [`ChainSync::poll_block_announce_validation`] is called + /// to check for finished block announce validations. + fn push_block_announce_validation( + &mut self, + who: PeerId, + hash: Block::Hash, + announce: BlockAnnounce, + is_best: bool, + ); + + /// Poll block announce validation. + /// + /// Block announce validations can be pushed by using + /// [`ChainSync::push_block_announce_validation`]. + /// + /// This should be polled until it returns [`Poll::Pending`]. + /// + /// If [`PollBlockAnnounceValidation::ImportHeader`] is returned, then the caller MUST try to + /// import passed header (call `on_block_data`). The network request isn't sent in this case. + fn poll_block_announce_validation( + &mut self, + cx: &mut std::task::Context, + ) -> Poll>; + + /// Call when a peer has disconnected. + /// Canceled obsolete block request may result in some blocks being ready for + /// import, so this functions checks for such blocks and returns them. + fn peer_disconnected(&mut self, who: &PeerId) -> Option>; + + /// Return some key metrics. + fn metrics(&self) -> Metrics; + + /// Create implementation-specific block request. + fn create_opaque_block_request(&self, request: &BlockRequest) -> OpaqueBlockRequest; + + /// Encode implementation-specific block request. + fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String>; + + /// Decode implementation-specific block response. + fn decode_block_response(&self, response: &[u8]) -> Result; + + /// Access blocks from implementation-specific block response. + fn block_response_into_blocks( + &self, + request: &BlockRequest, + response: OpaqueBlockResponse, + ) -> Result>, String>; + + /// Encode implementation-specific state request. + fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String>; + + /// Decode implementation-specific state response. + fn decode_state_response(&self, response: &[u8]) -> Result; +} diff --git a/client/network/sync/src/message.rs b/client/network/common/src/sync/message.rs similarity index 99% rename from client/network/sync/src/message.rs rename to client/network/common/src/sync/message.rs index 996ee5231cf2e..27ab2704e6471 100644 --- a/client/network/sync/src/message.rs +++ b/client/network/common/src/sync/message.rs @@ -124,8 +124,8 @@ impl BlockAnnounce { /// Generic types. pub mod generic { use super::{BlockAttributes, BlockState, Direction}; + use crate::message::RequestId; use codec::{Decode, Encode, Input, Output}; - use sc_network_common::message::RequestId; use sp_runtime::{EncodedJustification, Justifications}; /// Block data sent in the response. diff --git a/client/network/common/src/sync/metrics.rs b/client/network/common/src/sync/metrics.rs new file mode 100644 index 0000000000000..15ff090a8ccac --- /dev/null +++ b/client/network/common/src/sync/metrics.rs @@ -0,0 +1,25 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#[derive(Debug)] +pub struct Metrics { + pub pending_requests: u32, + pub active_requests: u32, + pub importing_requests: u32, + pub failed_requests: u32, +} diff --git a/client/network/common/src/sync/warp.rs b/client/network/common/src/sync/warp.rs new file mode 100644 index 0000000000000..339a4c33a7eeb --- /dev/null +++ b/client/network/common/src/sync/warp.rs @@ -0,0 +1,94 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use codec::{Decode, Encode}; +pub use sp_finality_grandpa::{AuthorityList, SetId}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; +use std::fmt; + +/// Scale-encoded warp sync proof response. +pub struct EncodedProof(pub Vec); + +/// Warp sync request +#[derive(Encode, Decode, Debug)] +pub struct WarpProofRequest { + /// Start collecting proofs from this block. + pub begin: B::Hash, +} + +/// Proof verification result. +pub enum VerificationResult { + /// Proof is valid, but the target was not reached. + Partial(SetId, AuthorityList, Block::Hash), + /// Target finality is proved. + Complete(SetId, AuthorityList, Block::Header), +} + +/// Warp sync backend. Handles retrieveing and verifying warp sync proofs. +pub trait WarpSyncProvider: Send + Sync { + /// Generate proof starting at given block hash. The proof is accumulated until maximum proof + /// size is reached. + fn generate( + &self, + start: Block::Hash, + ) -> Result>; + /// Verify warp proof against current set of authorities. + fn verify( + &self, + proof: &EncodedProof, + set_id: SetId, + authorities: AuthorityList, + ) -> Result, Box>; + /// Get current list of authorities. This is supposed to be genesis authorities when starting + /// sync. + fn current_authorities(&self) -> AuthorityList; +} + +/// Reported warp sync phase. +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum WarpSyncPhase { + /// Waiting for peers to connect. + AwaitingPeers, + /// Downloading and verifying grandpa warp proofs. + DownloadingWarpProofs, + /// Downloading state data. + DownloadingState, + /// Importing state. + ImportingState, + /// Downloading block history. + DownloadingBlocks(NumberFor), +} + +impl fmt::Display for WarpSyncPhase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::AwaitingPeers => write!(f, "Waiting for peers"), + Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"), + Self::DownloadingState => write!(f, "Downloading state"), + Self::ImportingState => write!(f, "Importing state"), + Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n), + } + } +} + +/// Reported warp sync progress. +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct WarpSyncProgress { + /// Estimated download percentage. + pub phase: WarpSyncPhase, + /// Total bytes downloaded so far. + pub total_bytes: u64, +} diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 091dd116e4c9c..515608df13d0f 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -38,7 +38,7 @@ use libp2p::{ NetworkBehaviour, }; use log::debug; -use prost::Message; + use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::import_queue::{IncomingBlock, Origin}; use sc_network_common::{config::ProtocolId, request_responses::ProtocolConfig}; @@ -382,42 +382,44 @@ where .events .push_back(BehaviourOut::JustificationImport(origin, hash, nb, justification)), CustomMessageOutcome::BlockRequest { target, request, pending_response } => { - let mut buf = Vec::with_capacity(request.encoded_len()); - if let Err(err) = request.encode(&mut buf) { - log::warn!( - target: "sync", - "Failed to encode block request {:?}: {:?}", - request, err - ); - return + match self.substrate.encode_block_request(&request) { + Ok(data) => { + self.request_responses.send_request( + &target, + &self.block_request_protocol_name, + data, + pending_response, + IfDisconnected::ImmediateError, + ); + }, + Err(err) => { + log::warn!( + target: "sync", + "Failed to encode block request {:?}: {:?}", + request, err + ); + }, } - - self.request_responses.send_request( - &target, - &self.block_request_protocol_name, - buf, - pending_response, - IfDisconnected::ImmediateError, - ); }, CustomMessageOutcome::StateRequest { target, request, pending_response } => { - let mut buf = Vec::with_capacity(request.encoded_len()); - if let Err(err) = request.encode(&mut buf) { - log::warn!( - target: "sync", - "Failed to encode state request {:?}: {:?}", - request, err - ); - return + match self.substrate.encode_state_request(&request) { + Ok(data) => { + self.request_responses.send_request( + &target, + &self.state_request_protocol_name, + data, + pending_response, + IfDisconnected::ImmediateError, + ); + }, + Err(err) => { + log::warn!( + target: "sync", + "Failed to encode state request {:?}: {:?}", + request, err + ); + }, } - - self.request_responses.send_request( - &target, - &self.state_request_protocol_name, - buf, - pending_response, - IfDisconnected::ImmediateError, - ); }, CustomMessageOutcome::WarpSyncRequest { target, request, pending_response } => match &self.warp_sync_protocol_name { diff --git a/client/network/src/bitswap.rs b/client/network/src/bitswap.rs index d5039faaca113..2dab45adc5618 100644 --- a/client/network/src/bitswap.rs +++ b/client/network/src/bitswap.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright 2022 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -118,8 +118,7 @@ where fn upgrade_outbound(self, mut socket: TSocket, _info: Self::Info) -> Self::Future { Box::pin(async move { - let mut data = Vec::with_capacity(self.encoded_len()); - self.encode(&mut data)?; + let data = self.encode_to_vec(); upgrade::write_length_prefixed(&mut socket, data).await }) } diff --git a/client/network/src/config.rs b/client/network/src/config.rs index e44977e5be6b3..430efd697a18c 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -26,16 +26,11 @@ pub use sc_network_common::{ request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, + sync::warp::WarpSyncProvider, }; -pub use sc_network_sync::warp_request_handler::WarpSyncProvider; pub use libp2p::{build_multiaddr, core::PublicKey, identity}; -// Note: this re-export shouldn't be part of the public API of the crate and will be removed in -// the future. -#[doc(hidden)] -pub use crate::protocol::ProtocolConfig; - use crate::ExHashT; use core::{fmt, iter}; @@ -46,7 +41,7 @@ use libp2p::{ }; use prometheus_endpoint::Registry; use sc_consensus::ImportQueue; -use sp_consensus::block_validation::BlockAnnounceValidator; +use sc_network_common::sync::ChainSync; use sp_runtime::traits::Block as BlockT; use std::{ borrow::Cow, @@ -101,8 +96,14 @@ where /// valid. pub import_queue: Box>, - /// Type to check incoming block announcements. - pub block_announce_validator: Box + Send>, + /// Factory function that creates a new instance of chain sync. + pub create_chain_sync: Box< + dyn FnOnce( + sc_network_common::sync::SyncMode, + Arc, + Option>>, + ) -> crate::error::Result>>, + >, /// Registry for recording prometheus metrics to. pub metrics_registry: Option, @@ -114,26 +115,26 @@ where /// block requests, if enabled. /// /// Can be constructed either via - /// [`sc_network_sync::block_request_handler::generate_protocol_config`] allowing outgoing but - /// not incoming requests, or constructed via [`sc_network_sync::block_request_handler:: - /// BlockRequestHandler::new`] allowing both outgoing and incoming requests. + /// `sc_network_sync::block_request_handler::generate_protocol_config` allowing outgoing but + /// not incoming requests, or constructed via `sc_network_sync::block_request_handler:: + /// BlockRequestHandler::new` allowing both outgoing and incoming requests. pub block_request_protocol_config: RequestResponseConfig, /// Request response configuration for the light client request protocol. /// /// Can be constructed either via - /// [`sc_network_light::light_client_requests::generate_protocol_config`] allowing outgoing but + /// `sc_network_light::light_client_requests::generate_protocol_config` allowing outgoing but /// not incoming requests, or constructed via - /// [`sc_network_light::light_client_requests::handler::LightClientRequestHandler::new`] + /// `sc_network_light::light_client_requests::handler::LightClientRequestHandler::new` /// allowing both outgoing and incoming requests. pub light_client_request_protocol_config: RequestResponseConfig, /// Request response configuration for the state request protocol. /// /// Can be constructed either via - /// [`sc_network_sync::block_request_handler::generate_protocol_config`] allowing outgoing but + /// `sc_network_sync::state_request_handler::generate_protocol_config` allowing outgoing but /// not incoming requests, or constructed via - /// [`crate::state_request_handler::StateRequestHandler::new`] allowing + /// `sc_network_sync::state_request_handler::StateRequestHandler::new` allowing /// both outgoing and incoming requests. pub state_request_protocol_config: RequestResponseConfig, diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index fff30550eb8c9..83bc1075b8bad 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -266,13 +266,9 @@ pub use protocol::{ event::{DhtEvent, Event, ObservedRole}, PeerInfo, }; -pub use sc_network_light::light_client_requests; -pub use sc_network_sync::{ - block_request_handler, - state::StateDownloadProgress, - state_request_handler, +pub use sc_network_common::sync::{ warp::{WarpSyncPhase, WarpSyncProgress}, - warp_request_handler, SyncState, + StateDownloadProgress, SyncState, }; pub use service::{ DecodingError, IfDisconnected, KademliaKey, Keypair, NetworkService, NetworkWorker, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 348d2d0bf8877..3698a6b936ed5 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -20,7 +20,6 @@ use crate::{ config, error, request_responses::RequestFailure, utils::{interval, LruHashSet}, - warp_request_handler::{EncodedProof, WarpSyncProvider}, }; use bytes::Bytes; @@ -42,21 +41,23 @@ use message::{ }; use notifications::{Notifications, NotificationsOut}; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; -use prost::Message as _; use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; use sc_consensus::import_queue::{BlockImportError, BlockImportStatus, IncomingBlock, Origin}; -use sc_network_common::config::ProtocolId; -use sc_network_sync::{ - message::{ - BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, BlockState, - FromBlock, +use sc_network_common::{ + config::ProtocolId, + sync::{ + message::{ + BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, BlockState, + }, + warp::{EncodedProof, WarpProofRequest}, + BadPeer, ChainSync, OnBlockData, OnBlockJustification, OnStateData, OpaqueBlockRequest, + OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PollBlockAnnounceValidation, + SyncStatus, }, - schema::v1::StateResponse, - BadPeer, ChainSync, OnBlockData, OnBlockJustification, OnStateData, - PollBlockAnnounceValidation, Status as SyncStatus, }; use sp_arithmetic::traits::SaturatedConversion; -use sp_consensus::{block_validation::BlockAnnounceValidator, BlockOrigin}; +use sp_blockchain::HeaderMetadata; +use sp_consensus::BlockOrigin; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, CheckedSub, Header as HeaderT, NumberFor, Zero}, @@ -79,7 +80,6 @@ pub mod event; pub mod message; pub use notifications::{NotificationsSink, NotifsHandlerError, Ready}; -use sp_blockchain::HeaderMetadata; /// Interval at which we perform time based maintenance const TICK_TIMEOUT: time::Duration = time::Duration::from_millis(1100); @@ -167,11 +167,12 @@ pub struct Protocol { tick_timeout: Pin + Send>>, /// Pending list of messages to return from `poll` as a priority. pending_messages: VecDeque>, - config: ProtocolConfig, + /// Assigned roles. + roles: Roles, genesis_hash: B::Hash, /// State machine that handles the list of in-progress requests. Only full node peers are /// registered. - sync: ChainSync, + chain_sync: Box>, // All connected peers. Contains both full and light node peers. peers: HashMap>, chain: Arc, @@ -231,38 +232,6 @@ pub struct PeerInfo { pub best_number: ::Number, } -/// Configuration for the Substrate-specific part of the networking layer. -#[derive(Clone)] -pub struct ProtocolConfig { - /// Assigned roles. - pub roles: Roles, - /// Maximum number of peers to ask the same blocks in parallel. - pub max_parallel_downloads: u32, - /// Enable state sync. - pub sync_mode: config::SyncMode, -} - -impl ProtocolConfig { - fn sync_mode(&self) -> sc_network_sync::SyncMode { - if self.roles.is_light() { - sc_network_sync::SyncMode::Light - } else { - match self.sync_mode { - config::SyncMode::Full => sc_network_sync::SyncMode::Full, - config::SyncMode::Fast { skip_proofs, storage_chain_mode } => - sc_network_sync::SyncMode::LightState { skip_proofs, storage_chain_mode }, - config::SyncMode::Warp => sc_network_sync::SyncMode::Warp, - } - } - } -} - -impl Default for ProtocolConfig { - fn default() -> ProtocolConfig { - Self { roles: Roles::FULL, max_parallel_downloads: 5, sync_mode: config::SyncMode::Full } - } -} - /// Handshake sent when we open a block announces substream. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] struct BlockAnnouncesHandshake { @@ -278,12 +247,12 @@ struct BlockAnnouncesHandshake { impl BlockAnnouncesHandshake { fn build( - protocol_config: &ProtocolConfig, + roles: Roles, best_number: NumberFor, best_hash: B::Hash, genesis_hash: B::Hash, ) -> Self { - Self { genesis_hash, roles: protocol_config.roles, best_number, best_hash } + Self { genesis_hash, roles, best_number, best_hash } } } @@ -300,24 +269,15 @@ where { /// Create a new instance. pub fn new( - config: ProtocolConfig, + roles: Roles, chain: Arc, protocol_id: ProtocolId, network_config: &config::NetworkConfiguration, notifications_protocols_handshakes: Vec>, - block_announce_validator: Box + Send>, metrics_registry: Option<&Registry>, - warp_sync_provider: Option>>, - ) -> error::Result<(Protocol, sc_peerset::PeersetHandle, Vec<(PeerId, Multiaddr)>)> { + chain_sync: Box>, + ) -> error::Result<(Self, sc_peerset::PeersetHandle, Vec<(PeerId, Multiaddr)>)> { let info = chain.info(); - let sync = ChainSync::new( - config.sync_mode(), - chain.clone(), - block_announce_validator, - config.max_parallel_downloads, - warp_sync_provider, - ) - .map_err(Box::new)?; let boot_node_ids = { let mut list = HashSet::new(); @@ -405,7 +365,7 @@ where let genesis_hash = info.genesis_hash; let block_announces_handshake = - BlockAnnouncesHandshake::::build(&config, best_number, best_hash, genesis_hash) + BlockAnnouncesHandshake::::build(roles, best_number, best_hash, genesis_hash) .encode(); let sync_protocol_config = notifications::ProtocolConfig { @@ -438,11 +398,11 @@ where let protocol = Self { tick_timeout: Box::pin(interval(TICK_TIMEOUT)), pending_messages: VecDeque::new(), - config, + roles, peers: HashMap::new(), chain, genesis_hash: info.genesis_hash, - sync, + chain_sync, important_peers, default_peers_set_num_full: network_config.default_peers_set_num_full as usize, default_peers_set_num_light: { @@ -510,49 +470,49 @@ where /// Current global sync state. pub fn sync_state(&self) -> SyncStatus { - self.sync.status() + self.chain_sync.status() } /// Target sync block number. pub fn best_seen_block(&self) -> Option> { - self.sync.status().best_seen_block + self.chain_sync.status().best_seen_block } /// Number of peers participating in syncing. pub fn num_sync_peers(&self) -> u32 { - self.sync.status().num_peers + self.chain_sync.status().num_peers } /// Number of blocks in the import queue. pub fn num_queued_blocks(&self) -> u32 { - self.sync.status().queued_blocks + self.chain_sync.status().queued_blocks } /// Number of downloaded blocks. pub fn num_downloaded_blocks(&self) -> usize { - self.sync.num_downloaded_blocks() + self.chain_sync.num_downloaded_blocks() } /// Number of active sync requests. pub fn num_sync_requests(&self) -> usize { - self.sync.num_sync_requests() + self.chain_sync.num_sync_requests() } /// Inform sync about new best imported block. pub fn new_best_block_imported(&mut self, hash: B::Hash, number: NumberFor) { debug!(target: "sync", "New best block imported {:?}/#{}", hash, number); - self.sync.update_chain_info(&hash, number); + self.chain_sync.update_chain_info(&hash, number); self.behaviour.set_notif_protocol_handshake( HARDCODED_PEERSETS_SYNC, - BlockAnnouncesHandshake::::build(&self.config, number, hash, self.genesis_hash) + BlockAnnouncesHandshake::::build(self.roles, number, hash, self.genesis_hash) .encode(), ); } fn update_peer_info(&mut self, who: &PeerId) { - if let Some(info) = self.sync.peer_info(who) { + if let Some(info) = self.chain_sync.peer_info(who) { if let Some(ref mut peer) = self.peers.get_mut(who) { peer.info.best_hash = info.best_hash; peer.info.best_number = info.best_number; @@ -565,14 +525,6 @@ where self.peers.iter().map(|(id, peer)| (id, &peer.info)) } - fn prepare_block_request( - &mut self, - who: PeerId, - request: BlockRequest, - ) -> CustomMessageOutcome { - prepare_block_request::(&mut self.peers, who, request) - } - /// Called by peer when it is disconnecting. /// /// Returns a result if the handshake of this peer was indeed accepted. @@ -584,7 +536,9 @@ where } if let Some(_peer_data) = self.peers.remove(&peer) { - if let Some(OnBlockData::Import(origin, blocks)) = self.sync.peer_disconnected(&peer) { + if let Some(OnBlockData::Import(origin, blocks)) = + self.chain_sync.peer_disconnected(&peer) + { self.pending_messages .push_back(CustomMessageOutcome::BlockImport(origin, blocks)); } @@ -605,62 +559,9 @@ where &mut self, peer_id: PeerId, request: BlockRequest, - response: sc_network_sync::schema::v1::BlockResponse, + response: OpaqueBlockResponse, ) -> CustomMessageOutcome { - let blocks = response - .blocks - .into_iter() - .map(|block_data| { - Ok(BlockData:: { - hash: Decode::decode(&mut block_data.hash.as_ref())?, - header: if !block_data.header.is_empty() { - Some(Decode::decode(&mut block_data.header.as_ref())?) - } else { - None - }, - body: if request.fields.contains(BlockAttributes::BODY) { - Some( - block_data - .body - .iter() - .map(|body| Decode::decode(&mut body.as_ref())) - .collect::, _>>()?, - ) - } else { - None - }, - indexed_body: if request.fields.contains(BlockAttributes::INDEXED_BODY) { - Some(block_data.indexed_body) - } else { - None - }, - receipt: if !block_data.receipt.is_empty() { - Some(block_data.receipt) - } else { - None - }, - message_queue: if !block_data.message_queue.is_empty() { - Some(block_data.message_queue) - } else { - None - }, - justification: if !block_data.justification.is_empty() { - Some(block_data.justification) - } else if block_data.is_empty_justification { - Some(Vec::new()) - } else { - None - }, - justifications: if !block_data.justifications.is_empty() { - Some(DecodeAll::decode_all(&mut block_data.justifications.as_ref())?) - } else { - None - }, - }) - }) - .collect::, codec::Error>>(); - - let blocks = match blocks { + let blocks = match self.chain_sync.block_response_into_blocks(&request, response) { Ok(blocks) => blocks, Err(err) => { debug!(target: "sync", "Failed to decode block response from {}: {}", peer_id, err); @@ -690,7 +591,7 @@ where ); if request.fields == BlockAttributes::JUSTIFICATION { - match self.sync.on_block_justification(peer_id, block_response) { + match self.chain_sync.on_block_justification(peer_id, block_response) { Ok(OnBlockJustification::Nothing) => CustomMessageOutcome::None, Ok(OnBlockJustification::Import { peer, hash, number, justifications }) => CustomMessageOutcome::JustificationImport(peer, hash, number, justifications), @@ -701,10 +602,11 @@ where }, } } else { - match self.sync.on_block_data(&peer_id, Some(request), block_response) { + match self.chain_sync.on_block_data(&peer_id, Some(request), block_response) { Ok(OnBlockData::Import(origin, blocks)) => CustomMessageOutcome::BlockImport(origin, blocks), - Ok(OnBlockData::Request(peer, req)) => self.prepare_block_request(peer, req), + Ok(OnBlockData::Request(peer, req)) => + prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, peer, req), Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); @@ -719,9 +621,9 @@ where pub fn on_state_response( &mut self, peer_id: PeerId, - response: StateResponse, + response: OpaqueStateResponse, ) -> CustomMessageOutcome { - match self.sync.on_state_data(&peer_id, response) { + match self.chain_sync.on_state_data(&peer_id, response) { Ok(OnStateData::Import(origin, block)) => CustomMessageOutcome::BlockImport(origin, vec![block]), Ok(OnStateData::Continue) => CustomMessageOutcome::None, @@ -738,9 +640,9 @@ where pub fn on_warp_sync_response( &mut self, peer_id: PeerId, - response: crate::warp_request_handler::EncodedProof, + response: EncodedProof, ) -> CustomMessageOutcome { - match self.sync.on_warp_sync_data(&peer_id, response) { + match self.chain_sync.on_warp_sync_data(&peer_id, response) { Ok(()) => CustomMessageOutcome::None, Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); @@ -798,7 +700,7 @@ where return Err(()) } - if self.config.roles.is_light() { + if self.roles.is_light() { // we're not interested in light peers if status.roles.is_light() { debug!(target: "sync", "Peer {} is unable to serve light requests", who); @@ -821,14 +723,15 @@ where } } - if status.roles.is_full() && self.sync.num_peers() >= self.default_peers_set_num_full { + if status.roles.is_full() && self.chain_sync.num_peers() >= self.default_peers_set_num_full + { debug!(target: "sync", "Too many full nodes, rejecting {}", who); self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); return Err(()) } if status.roles.is_light() && - (self.peers.len() - self.sync.num_peers()) >= self.default_peers_set_num_light + (self.peers.len() - self.chain_sync.num_peers()) >= self.default_peers_set_num_light { // Make sure that not all slots are occupied by light clients. debug!(target: "sync", "Too many light nodes, rejecting {}", who); @@ -849,7 +752,7 @@ where }; let req = if peer.info.roles.is_full() { - match self.sync.new_peer(who, peer.info.best_hash, peer.info.best_number) { + match self.chain_sync.new_peer(who, peer.info.best_hash, peer.info.best_number) { Ok(req) => req, Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); @@ -868,8 +771,12 @@ where .push_back(CustomMessageOutcome::PeerNewBest(who, status.best_number)); if let Some(req) = req { - let event = self.prepare_block_request(who, req); - self.pending_messages.push_back(event); + self.pending_messages.push_back(prepare_block_request( + self.chain_sync.as_ref(), + &mut self.peers, + who, + req, + )); } Ok(()) @@ -953,7 +860,7 @@ where }; if peer.info.roles.is_full() { - self.sync.push_block_announce_validation(who, hash, announce, is_best); + self.chain_sync.push_block_announce_validation(who, hash, announce, is_best); } } @@ -1010,7 +917,7 @@ where // to import header from announced block let's construct response to request that normally // would have been sent over network (but it is not in our case) - let blocks_to_import = self.sync.on_block_data( + let blocks_to_import = self.chain_sync.on_block_data( &who, None, BlockResponse:: { @@ -1035,7 +942,8 @@ where match blocks_to_import { Ok(OnBlockData::Import(origin, blocks)) => CustomMessageOutcome::BlockImport(origin, blocks), - Ok(OnBlockData::Request(peer, req)) => self.prepare_block_request(peer, req), + Ok(OnBlockData::Request(peer, req)) => + prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, peer, req), Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); @@ -1047,7 +955,7 @@ where /// Call this when a block has been finalized. The sync layer may have some additional /// requesting to perform. pub fn on_block_finalized(&mut self, hash: B::Hash, header: &B::Header) { - self.sync.on_block_finalized(&hash, *header.number()) + self.chain_sync.on_block_finalized(&hash, *header.number()) } /// Request a justification for the given block. @@ -1055,12 +963,12 @@ where /// Uses `protocol` to queue a new justification request and tries to dispatch all pending /// requests. pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { - self.sync.request_justification(hash, number) + self.chain_sync.request_justification(hash, number) } /// Clear all pending justification requests. pub fn clear_justification_requests(&mut self) { - self.sync.clear_justification_requests(); + self.chain_sync.clear_justification_requests(); } /// Request syncing for the given block from given set of peers. @@ -1072,7 +980,7 @@ where hash: &B::Hash, number: NumberFor, ) { - self.sync.set_sync_fork_request(peers, hash, number) + self.chain_sync.set_sync_fork_request(peers, hash, number) } /// A batch of blocks have been processed, with or without errors. @@ -1084,11 +992,12 @@ where count: usize, results: Vec<(Result>, BlockImportError>, B::Hash)>, ) { - let results = self.sync.on_blocks_processed(imported, count, results); + let results = self.chain_sync.on_blocks_processed(imported, count, results); for result in results { match result { Ok((id, req)) => { self.pending_messages.push_back(prepare_block_request( + self.chain_sync.as_ref(), &mut self.peers, id, req, @@ -1111,7 +1020,7 @@ where number: NumberFor, success: bool, ) { - self.sync.on_justification_import(hash, number, success); + self.chain_sync.on_justification_import(hash, number, success); if !success { info!("💔 Invalid justification provided by {} for #{}", who, hash); self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); @@ -1228,12 +1137,22 @@ where } } + /// Encode implementation-specific block request. + pub fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String> { + self.chain_sync.encode_block_request(request) + } + + /// Encode implementation-specific state request. + pub fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String> { + self.chain_sync.encode_state_request(request) + } + fn report_metrics(&self) { if let Some(metrics) = &self.metrics { let n = u64::try_from(self.peers.len()).unwrap_or(std::u64::MAX); metrics.peers.set(n); - let m = self.sync.metrics(); + let m = self.chain_sync.metrics(); metrics.fork_targets.set(m.fork_targets.into()); metrics.queued_blocks.set(m.queued_blocks.into()); @@ -1259,6 +1178,7 @@ where } fn prepare_block_request( + chain_sync: &dyn ChainSync, peers: &mut HashMap>, who: PeerId, request: BlockRequest, @@ -1269,19 +1189,7 @@ fn prepare_block_request( peer.request = Some((PeerRequest::Block(request.clone()), rx)); } - let request = sc_network_sync::schema::v1::BlockRequest { - fields: request.fields.to_be_u32(), - from_block: match request.from { - FromBlock::Hash(h) => - Some(sc_network_sync::schema::v1::block_request::FromBlock::Hash(h.encode())), - FromBlock::Number(n) => - Some(sc_network_sync::schema::v1::block_request::FromBlock::Number(n.encode())), - }, - to_block: request.to.map(|h| h.encode()).unwrap_or_default(), - direction: request.direction as i32, - max_blocks: request.max.unwrap_or(0), - support_multiple_justifications: true, - }; + let request = chain_sync.create_opaque_block_request(&request); CustomMessageOutcome::BlockRequest { target: who, request, pending_response: tx } } @@ -1289,7 +1197,7 @@ fn prepare_block_request( fn prepare_state_request( peers: &mut HashMap>, who: PeerId, - request: sc_network_sync::schema::v1::StateRequest, + request: OpaqueStateRequest, ) -> CustomMessageOutcome { let (tx, rx) = oneshot::channel(); @@ -1302,7 +1210,7 @@ fn prepare_state_request( fn prepare_warp_sync_request( peers: &mut HashMap>, who: PeerId, - request: crate::warp_request_handler::Request, + request: WarpProofRequest, ) -> CustomMessageOutcome { let (tx, rx) = oneshot::channel(); @@ -1346,19 +1254,19 @@ pub enum CustomMessageOutcome { /// A new block request must be emitted. BlockRequest { target: PeerId, - request: sc_network_sync::schema::v1::BlockRequest, + request: OpaqueBlockRequest, pending_response: oneshot::Sender, RequestFailure>>, }, /// A new storage request must be emitted. StateRequest { target: PeerId, - request: sc_network_sync::schema::v1::StateRequest, + request: OpaqueStateRequest, pending_response: oneshot::Sender, RequestFailure>>, }, /// A new warp sync request must be emitted. WarpSyncRequest { target: PeerId, - request: crate::warp_request_handler::Request, + request: WarpProofRequest, pending_response: oneshot::Sender, RequestFailure>>, }, /// Peer has a reported a new head of chain. @@ -1455,10 +1363,8 @@ where let (req, _) = peer.request.take().unwrap(); match req { PeerRequest::Block(req) => { - let protobuf_response = - match sc_network_sync::schema::v1::BlockResponse::decode( - &resp[..], - ) { + let response = + match self.chain_sync.decode_block_response(&resp[..]) { Ok(proto) => proto, Err(e) => { debug!( @@ -1474,13 +1380,11 @@ where }, }; - finished_block_requests.push((*id, req, protobuf_response)); + finished_block_requests.push((*id, req, response)); }, PeerRequest::State => { - let protobuf_response = - match sc_network_sync::schema::v1::StateResponse::decode( - &resp[..], - ) { + let response = + match self.chain_sync.decode_state_response(&resp[..]) { Ok(proto) => proto, Err(e) => { debug!( @@ -1496,7 +1400,7 @@ where }, }; - finished_state_requests.push((*id, protobuf_response)); + finished_state_requests.push((*id, response)); }, PeerRequest::WarpProof => { finished_warp_sync_requests.push((*id, resp)); @@ -1555,12 +1459,12 @@ where } } } - for (id, req, protobuf_response) in finished_block_requests { - let ev = self.on_block_response(id, req, protobuf_response); + for (id, req, response) in finished_block_requests { + let ev = self.on_block_response(id, req, response); self.pending_messages.push_back(ev); } - for (id, protobuf_response) in finished_state_requests { - let ev = self.on_state_response(id, protobuf_response); + for (id, response) in finished_state_requests { + let ev = self.on_state_response(id, response); self.pending_messages.push_back(ev); } for (id, response) in finished_warp_sync_requests { @@ -1572,25 +1476,32 @@ where self.tick(); } - for (id, request) in self.sync.block_requests() { - let event = prepare_block_request(&mut self.peers, *id, request); + for (id, request) in self + .chain_sync + .block_requests() + .map(|(peer_id, request)| (*peer_id, request)) + .collect::>() + { + let event = + prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, id, request); self.pending_messages.push_back(event); } - if let Some((id, request)) = self.sync.state_request() { + if let Some((id, request)) = self.chain_sync.state_request() { let event = prepare_state_request(&mut self.peers, id, request); self.pending_messages.push_back(event); } - for (id, request) in self.sync.justification_requests() { - let event = prepare_block_request(&mut self.peers, id, request); + for (id, request) in self.chain_sync.justification_requests().collect::>() { + let event = + prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, id, request); self.pending_messages.push_back(event); } - if let Some((id, request)) = self.sync.warp_sync_request() { + if let Some((id, request)) = self.chain_sync.warp_sync_request() { let event = prepare_warp_sync_request(&mut self.peers, id, request); self.pending_messages.push_back(event); } // Check if there is any block announcement validation finished. - while let Poll::Ready(result) = self.sync.poll_block_announce_validation(cx) { + while let Poll::Ready(result) = self.chain_sync.poll_block_announce_validation(cx) { match self.process_block_announce_validation_result(result) { CustomMessageOutcome::None => {}, outcome => self.pending_messages.push_back(outcome), @@ -1771,7 +1682,8 @@ where // Make sure that the newly added block announce validation future was // polled once to be registered in the task. - if let Poll::Ready(res) = self.sync.poll_block_announce_validation(cx) { + if let Poll::Ready(res) = self.chain_sync.poll_block_announce_validation(cx) + { self.process_block_announce_validation_result(res) } else { CustomMessageOutcome::None diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index a57740ec2746b..c9512f82e23bb 100644 --- a/client/network/src/protocol/message.rs +++ b/client/network/src/protocol/message.rs @@ -63,10 +63,12 @@ pub mod generic { use bitflags::bitflags; use codec::{Decode, Encode, Input, Output}; use sc_client_api::StorageProof; - use sc_network_common::message::RequestId; - use sc_network_sync::message::{ - generic::{BlockRequest, BlockResponse}, - BlockAnnounce, + use sc_network_common::{ + message::RequestId, + sync::message::{ + generic::{BlockRequest, BlockResponse}, + BlockAnnounce, + }, }; use sp_runtime::ConsensusEngineId; diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 1cc717a50d039..ef7ef2f5a2deb 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -30,7 +30,7 @@ use crate::{ behaviour::{self, Behaviour, BehaviourOut}, bitswap::Bitswap, - config::{parse_str_addr, Params, TransportConfig}, + config::{self, parse_str_addr, Params, TransportConfig}, discovery::DiscoveryConfig, error::Error, network_state::{ @@ -60,7 +60,7 @@ use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; -use sc_network_sync::{Status as SyncStatus, SyncState}; +use sc_network_common::sync::{SyncMode, SyncState, SyncStatus}; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::{HeaderBackend, HeaderMetadata}; @@ -207,13 +207,23 @@ where None => (None, None), }; - let (protocol, peerset_handle, mut known_addresses) = Protocol::new( - protocol::ProtocolConfig { - roles: From::from(¶ms.role), - max_parallel_downloads: params.network_config.max_parallel_downloads, - sync_mode: params.network_config.sync_mode.clone(), + let chain_sync = (params.create_chain_sync)( + if params.role.is_light() { + SyncMode::Light + } else { + match params.network_config.sync_mode { + config::SyncMode::Full => SyncMode::Full, + config::SyncMode::Fast { skip_proofs, storage_chain_mode } => + SyncMode::LightState { skip_proofs, storage_chain_mode }, + config::SyncMode::Warp => SyncMode::Warp, + } }, params.chain.clone(), + warp_sync_provider, + )?; + let (protocol, peerset_handle, mut known_addresses) = Protocol::new( + From::from(¶ms.role), + params.chain.clone(), params.protocol_id.clone(), ¶ms.network_config, iter::once(Vec::new()) @@ -222,9 +232,8 @@ where .map(|_| default_notif_handshake_message.clone()), ) .collect(), - params.block_announce_validator, params.metrics_registry.as_ref(), - warp_sync_provider, + chain_sync, )?; // List of multiaddresses that we know in the network. diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 808546d67fc7c..181d58130aa6b 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -16,15 +16,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{ - config, state_request_handler::StateRequestHandler, Event, NetworkService, NetworkWorker, -}; +use crate::{config, Event, NetworkService, NetworkWorker}; use futures::prelude::*; use libp2p::PeerId; use sc_network_common::config::ProtocolId; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; -use sc_network_sync::block_request_handler::BlockRequestHandler; +use sc_network_sync::{ + block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler, + ChainSync, +}; +use sp_consensus::block_validation::DefaultBlockAnnounceValidator; use sp_runtime::traits::{Block as BlockT, Header as _}; use std::{borrow::Cow, sync::Arc, time::Duration}; use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; @@ -109,6 +111,7 @@ fn build_test_full_node( protocol_config }; + let max_parallel_downloads = config.max_parallel_downloads; let worker = NetworkWorker::new(config::Params { role: config::Role::Full, executor: None, @@ -120,8 +123,17 @@ fn build_test_full_node( transaction_pool: Arc::new(crate::config::EmptyTransactionPool), protocol_id, import_queue, - block_announce_validator: Box::new( - sp_consensus::block_validation::DefaultBlockAnnounceValidator, + create_chain_sync: Box::new( + move |sync_mode, chain, warp_sync_provider| match ChainSync::new( + sync_mode, + chain, + Box::new(DefaultBlockAnnounceValidator), + max_parallel_downloads, + warp_sync_provider, + ) { + Ok(chain_sync) => Ok(Box::new(chain_sync)), + Err(error) => Err(Box::new(error).into()), + }, ), metrics_registry: None, block_request_protocol_config, diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index a61f780fd56ad..3e3526146400a 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -17,11 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.10" [dependencies] -bitflags = "1.3.2" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } -either = "1.5.3" futures = "0.3.21" libp2p = "0.46.1" log = "0.4.17" diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index 4cd69d1fac4f5..2a847a8bf36ec 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -17,10 +17,7 @@ //! Helper for handling (i.e. answering) block requests from a remote peer via the //! `crate::request_responses::RequestResponsesBehaviour`. -use crate::{ - message::BlockAttributes, - schema::v1::{block_request::FromBlock, BlockResponse, Direction}, -}; +use crate::schema::v1::{block_request::FromBlock, BlockResponse, Direction}; use codec::{Decode, Encode}; use futures::{ channel::{mpsc, oneshot}, @@ -34,6 +31,7 @@ use sc_client_api::BlockBackend; use sc_network_common::{ config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, + sync::message::BlockAttributes, }; use sp_blockchain::HeaderBackend; use sp_runtime::{ diff --git a/client/network/sync/src/blocks.rs b/client/network/sync/src/blocks.rs index 26753f120a170..5fb1484675071 100644 --- a/client/network/sync/src/blocks.rs +++ b/client/network/sync/src/blocks.rs @@ -16,9 +16,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::message; use libp2p::PeerId; use log::trace; +use sc_network_common::sync::message; use sp_runtime::traits::{Block as BlockT, NumberFor, One}; use std::{ cmp, @@ -245,8 +245,8 @@ impl BlockCollection { #[cfg(test)] mod test { use super::{BlockCollection, BlockData, BlockRangeState}; - use crate::message; use libp2p::PeerId; + use sc_network_common::sync::message; use sp_core::H256; use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; diff --git a/client/network/sync/src/extra_requests.rs b/client/network/sync/src/extra_requests.rs index c684d8e72783e..6206f8a61bcf4 100644 --- a/client/network/sync/src/extra_requests.rs +++ b/client/network/sync/src/extra_requests.rs @@ -20,6 +20,7 @@ use crate::{PeerSync, PeerSyncState}; use fork_tree::ForkTree; use libp2p::PeerId; use log::{debug, trace, warn}; +use sc_network_common::sync::metrics::Metrics; use sp_blockchain::Error as ClientError; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; use std::{ @@ -56,15 +57,6 @@ pub(crate) struct ExtraRequests { request_type_name: &'static str, } -#[derive(Debug)] -pub struct Metrics { - pub pending_requests: u32, - pub active_requests: u32, - pub importing_requests: u32, - pub failed_requests: u32, - _priv: (), -} - impl ExtraRequests { pub(crate) fn new(request_type_name: &'static str) -> Self { Self { @@ -258,7 +250,6 @@ impl ExtraRequests { active_requests: self.active_requests.len().try_into().unwrap_or(std::u32::MAX), failed_requests: self.failed_requests.len().try_into().unwrap_or(std::u32::MAX), importing_requests: self.importing_requests.len().try_into().unwrap_or(std::u32::MAX), - _priv: (), } } } diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 1ce69b6dc816f..aff773bd12ed6 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -30,8 +30,7 @@ pub mod block_request_handler; pub mod blocks; -pub mod message; -pub mod schema; +mod schema; pub mod state; pub mod state_request_handler; pub mod warp; @@ -39,22 +38,28 @@ pub mod warp_request_handler; use crate::{ blocks::BlockCollection, - message::{BlockAnnounce, BlockAttributes, BlockRequest, BlockResponse}, schema::v1::{StateRequest, StateResponse}, - state::{StateDownloadProgress, StateSync}, - warp::{ - EncodedProof, WarpProofImportResult, WarpProofRequest, WarpSync, WarpSyncPhase, - WarpSyncProgress, WarpSyncProvider, - }, + state::StateSync, + warp::{WarpProofImportResult, WarpSync}, }; -use codec::Encode; -use either::Either; +use codec::{Decode, DecodeAll, Encode}; use extra_requests::ExtraRequests; use futures::{stream::FuturesUnordered, task::Poll, Future, FutureExt, StreamExt}; use libp2p::PeerId; use log::{debug, error, info, trace, warn}; +use prost::Message; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; +use sc_network_common::sync::{ + message::{ + BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, + FromBlock, + }, + warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, WarpSyncProvider}, + BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, OnStateData, + OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, + PollBlockAnnounceValidation, SyncMode, SyncState, SyncStatus, +}; use sp_arithmetic::traits::Saturating; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; use sp_consensus::{ @@ -71,7 +76,6 @@ use sp_runtime::{ }; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, - fmt, ops::Range, pin::Pin, sync::Arc, @@ -283,15 +287,6 @@ impl PeerSync { } } -/// The sync status of a peer we are trying to sync with -#[derive(Debug)] -pub struct PeerInfo { - /// Their best block hash. - pub best_hash: B::Hash, - /// Their best block number. - pub best_number: NumberFor, -} - struct ForkTarget { number: NumberFor, parent_hash: Option, @@ -330,108 +325,6 @@ impl PeerSyncState { } } -/// Reported sync state. -#[derive(Clone, Eq, PartialEq, Debug)] -pub enum SyncState { - /// Initial sync is complete, keep-up sync is active. - Idle, - /// Actively catching up with the chain. - Downloading, -} - -/// Syncing status and statistics. -#[derive(Clone)] -pub struct Status { - /// Current global sync state. - pub state: SyncState, - /// Target sync block number. - pub best_seen_block: Option>, - /// Number of peers participating in syncing. - pub num_peers: u32, - /// Number of blocks queued for import - pub queued_blocks: u32, - /// State sync status in progress, if any. - pub state_sync: Option, - /// Warp sync in progress, if any. - pub warp_sync: Option>, -} - -/// A peer did not behave as expected and should be reported. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BadPeer(pub PeerId, pub sc_peerset::ReputationChange); - -impl fmt::Display for BadPeer { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Bad peer {}; Reputation change: {:?}", self.0, self.1) - } -} - -impl std::error::Error for BadPeer {} - -/// Result of [`ChainSync::on_block_data`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum OnBlockData { - /// The block should be imported. - Import(BlockOrigin, Vec>), - /// A new block request needs to be made to the given peer. - Request(PeerId, BlockRequest), -} - -impl OnBlockData { - /// Returns `self` as request. - #[cfg(test)] - fn into_request(self) -> Option<(PeerId, BlockRequest)> { - if let Self::Request(peer, req) = self { - Some((peer, req)) - } else { - None - } - } -} - -/// Result of [`ChainSync::on_state_data`]. -#[derive(Debug)] -pub enum OnStateData { - /// The block and state that should be imported. - Import(BlockOrigin, IncomingBlock), - /// A new state request needs to be made to the given peer. - Continue, -} - -/// Result of [`ChainSync::poll_block_announce_validation`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PollBlockAnnounceValidation { - /// The announcement failed at validation. - /// - /// The peer reputation should be decreased. - Failure { - /// Who sent the processed block announcement? - who: PeerId, - /// Should the peer be disconnected? - disconnect: bool, - }, - /// The announcement does not require further handling. - Nothing { - /// Who sent the processed block announcement? - who: PeerId, - /// Was this their new best block? - is_best: bool, - /// The announcement. - announce: BlockAnnounce, - }, - /// The announcement header should be imported. - ImportHeader { - /// Who sent the processed block announcement? - who: PeerId, - /// Was this their new best block? - is_best: bool, - /// The announcement. - announce: BlockAnnounce, - }, - /// The block announcement should be skipped. - Skip, -} - /// Result of [`ChainSync::block_announce_validation`]. #[derive(Debug, Clone, PartialEq, Eq)] enum PreValidateBlockAnnounce { @@ -467,28 +360,6 @@ enum PreValidateBlockAnnounce { Skip, } -/// Result of [`ChainSync::on_block_justification`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum OnBlockJustification { - /// The justification needs no further handling. - Nothing, - /// The justification should be imported. - Import { peer: PeerId, hash: B::Hash, number: NumberFor, justifications: Justifications }, -} - -/// Operation mode. -#[derive(Debug, PartialEq, Eq)] -pub enum SyncMode { - // Sync headers only - Light, - // Sync headers and block bodies - Full, - // Sync headers and the last finalied state - LightState { storage_chain_mode: bool, skip_proofs: bool }, - // Warp sync mode. - Warp, -} - /// Result of [`ChainSync::has_slot_for_block_announce_validation`]. enum HasSlotForBlockAnnounceValidation { /// Yes, there is a slot for the block announce validation. @@ -499,7 +370,7 @@ enum HasSlotForBlockAnnounceValidation { MaximumPeerSlotsReached, } -impl ChainSync +impl ChainSyncT for ChainSync where B: BlockT, Client: HeaderBackend @@ -510,88 +381,14 @@ where + Sync + 'static, { - /// Create a new instance. - pub fn new( - mode: SyncMode, - client: Arc, - block_announce_validator: Box + Send>, - max_parallel_downloads: u32, - warp_sync_provider: Option>>, - ) -> Result { - let mut sync = Self { - client, - peers: HashMap::new(), - blocks: BlockCollection::new(), - best_queued_hash: Default::default(), - best_queued_number: Zero::zero(), - extra_justifications: ExtraRequests::new("justification"), - mode, - queue_blocks: Default::default(), - fork_targets: Default::default(), - allowed_requests: Default::default(), - block_announce_validator, - max_parallel_downloads, - downloaded_blocks: 0, - block_announce_validation: Default::default(), - block_announce_validation_per_peer_stats: Default::default(), - state_sync: None, - warp_sync: None, - warp_sync_provider, - import_existing: false, - gap_sync: None, - }; - sync.reset_sync_start_point()?; - Ok(sync) - } - - fn required_block_attributes(&self) -> BlockAttributes { - match self.mode { - SyncMode::Full => - BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION | BlockAttributes::BODY, - SyncMode::Light => BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION, - SyncMode::LightState { storage_chain_mode: false, .. } | SyncMode::Warp => - BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION | BlockAttributes::BODY, - SyncMode::LightState { storage_chain_mode: true, .. } => - BlockAttributes::HEADER | - BlockAttributes::JUSTIFICATION | - BlockAttributes::INDEXED_BODY, - } - } - - fn skip_execution(&self) -> bool { - match self.mode { - SyncMode::Full => false, - SyncMode::Light => true, - SyncMode::LightState { .. } => true, - SyncMode::Warp => true, - } - } - - /// Returns the state of the sync of the given peer. - /// - /// Returns `None` if the peer is unknown. - pub fn peer_info(&self, who: &PeerId) -> Option> { + fn peer_info(&self, who: &PeerId) -> Option> { self.peers .get(who) .map(|p| PeerInfo { best_hash: p.best_hash, best_number: p.best_number }) } - /// Returns the best seen block. - fn best_seen(&self) -> Option> { - let mut best_seens = self.peers.values().map(|p| p.best_number).collect::>(); - - if best_seens.is_empty() { - None - } else { - let middle = best_seens.len() / 2; - - // Not the "perfect median" when we have an even number of peers. - Some(*best_seens.select_nth_unstable(middle).1) - } - } - /// Returns the current sync status. - pub fn status(&self) -> Status { + fn status(&self) -> SyncStatus { let best_seen = self.best_seen(); let sync_state = if let Some(n) = best_seen { // A chain is classified as downloading if the provided best block is @@ -617,7 +414,7 @@ where _ => None, }; - Status { + SyncStatus { state: sync_state, best_seen_block: best_seen, num_peers: self.peers.len() as u32, @@ -627,29 +424,22 @@ where } } - /// Number of active forks requests. This includes - /// requests that are pending or could be issued right away. - pub fn num_sync_requests(&self) -> usize { + fn num_sync_requests(&self) -> usize { self.fork_targets .values() .filter(|f| f.number <= self.best_queued_number) .count() } - /// Number of downloaded blocks. - pub fn num_downloaded_blocks(&self) -> usize { + fn num_downloaded_blocks(&self) -> usize { self.downloaded_blocks } - /// Returns the current number of peers stored within this state machine. - pub fn num_peers(&self) -> usize { + fn num_peers(&self) -> usize { self.peers.len() } - /// Handle a new connected peer. - /// - /// Call this method whenever we connect to a new peer. - pub fn new_peer( + fn new_peer( &mut self, who: PeerId, best_hash: B::Hash, @@ -773,27 +563,22 @@ where } } - /// Signal that a new best block has been imported. - /// `ChainSync` state with that information. - pub fn update_chain_info(&mut self, best_hash: &B::Hash, best_number: NumberFor) { + fn update_chain_info(&mut self, best_hash: &B::Hash, best_number: NumberFor) { self.on_block_queued(best_hash, best_number); } - /// Schedule a justification request for the given block. - pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { + fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { let client = &self.client; self.extra_justifications .schedule((*hash, number), |base, block| is_descendent_of(&**client, base, block)) } - /// Clear all pending justification requests. - pub fn clear_justification_requests(&mut self) { + fn clear_justification_requests(&mut self) { self.extra_justifications.reset(); } - /// Request syncing for the given block from given set of peers. // The implementation is similar to on_block_announce with unknown parent hash. - pub fn set_sync_fork_request( + fn set_sync_fork_request( &mut self, mut peers: Vec, hash: &B::Hash, @@ -845,13 +630,12 @@ where .extend(peers); } - /// Get an iterator over all scheduled justification requests. - pub fn justification_requests( + fn justification_requests( &mut self, - ) -> impl Iterator)> + '_ { + ) -> Box)> + '_> { let peers = &mut self.peers; let mut matcher = self.extra_justifications.matcher(); - std::iter::from_fn(move || { + Box::new(std::iter::from_fn(move || { if let Some((peer, request)) = matcher.next(peers) { peers .get_mut(&peer) @@ -859,33 +643,32 @@ where "`Matcher::next` guarantees the `PeerId` comes from the given peers; qed", ) .state = PeerSyncState::DownloadingJustification(request.0); - let req = message::generic::BlockRequest { + let req = BlockRequest:: { id: 0, fields: BlockAttributes::JUSTIFICATION, - from: message::FromBlock::Hash(request.0), + from: FromBlock::Hash(request.0), to: None, - direction: message::Direction::Ascending, + direction: Direction::Ascending, max: Some(1), }; Some((peer, req)) } else { None } - }) + })) } - /// Get an iterator over all block requests of all peers. - pub fn block_requests(&mut self) -> impl Iterator)> + '_ { + fn block_requests(&mut self) -> Box)> + '_> { if self.allowed_requests.is_empty() || self.state_sync.is_some() || self.mode == SyncMode::Warp { - return Either::Left(std::iter::empty()) + return Box::new(std::iter::empty()) } if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS { trace!(target: "sync", "Too many blocks in the queue."); - return Either::Left(std::iter::empty()) + return Box::new(std::iter::empty()) } let major_sync = self.status().state == SyncState::Downloading; let attrs = self.required_block_attributes(); @@ -982,11 +765,10 @@ where None } }); - Either::Right(iter) + Box::new(iter) } - /// Get a state request, if any. - pub fn state_request(&mut self) -> Option<(PeerId, StateRequest)> { + fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { if self.allowed_requests.is_empty() { return None } @@ -1007,7 +789,7 @@ where let request = sync.next_request(); trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); self.allowed_requests.clear(); - return Some((*id, request)) + return Some((*id, OpaqueStateRequest(Box::new(request)))) } } } @@ -1023,7 +805,7 @@ where trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); peer.state = PeerSyncState::DownloadingState; self.allowed_requests.clear(); - return Some((*id, request)) + return Some((*id, OpaqueStateRequest(Box::new(request)))) } } } @@ -1031,8 +813,7 @@ where None } - /// Get a warp sync request, if any. - pub fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)> { + fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)> { if let Some(sync) = &self.warp_sync { if self.allowed_requests.is_empty() || sync.is_complete() || @@ -1063,14 +844,7 @@ where None } - /// Handle a response from the remote to a block request that we made. - /// - /// `request` must be the original request that triggered `response`. - /// or `None` if data comes from the block announcement. - /// - /// If this corresponds to a valid block, this outputs the block that - /// must be imported in the import queue. - pub fn on_block_data( + fn on_block_data( &mut self, who: &PeerId, request: Option>, @@ -1080,10 +854,7 @@ where let mut gap = false; let new_blocks: Vec> = if let Some(peer) = self.peers.get_mut(who) { let mut blocks = response.blocks; - if request - .as_ref() - .map_or(false, |r| r.direction == message::Direction::Descending) - { + if request.as_ref().map_or(false, |r| r.direction == Direction::Descending) { trace!(target: "sync", "Reversing incoming block list"); blocks.reverse() } @@ -1297,14 +1068,20 @@ where Ok(self.validate_and_queue_blocks(new_blocks, gap)) } - /// Handle a response from the remote to a state request that we made. - /// - /// Returns next request if any. - pub fn on_state_data( + fn on_state_data( &mut self, who: &PeerId, - response: StateResponse, + response: OpaqueStateResponse, ) -> Result, BadPeer> { + let response: Box = response.0.downcast().map_err(|_error| { + error!( + target: "sync", + "Failed to downcast opaque state response, this is an implementation bug." + ); + + BadPeer(*who, rep::BAD_RESPONSE) + })?; + if let Some(peer) = self.peers.get_mut(who) { if let PeerSyncState::DownloadingState = peer.state { peer.state = PeerSyncState::Available; @@ -1319,7 +1096,7 @@ where response.entries.len(), response.proof.len(), ); - sync.import(response) + sync.import(*response) } else if let Some(sync) = &mut self.warp_sync { debug!( target: "sync", @@ -1328,7 +1105,7 @@ where response.entries.len(), response.proof.len(), ); - sync.import_state(response) + sync.import_state(*response) } else { debug!(target: "sync", "Ignored obsolete state response from {}", who); return Err(BadPeer(*who, rep::NOT_REQUESTED)) @@ -1360,14 +1137,7 @@ where } } - /// Handle a response from the remote to a warp proof request that we made. - /// - /// Returns next request. - pub fn on_warp_sync_data( - &mut self, - who: &PeerId, - response: EncodedProof, - ) -> Result<(), BadPeer> { + fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer> { if let Some(peer) = self.peers.get_mut(who) { if let PeerSyncState::DownloadingWarpProof = peer.state { peer.state = PeerSyncState::Available; @@ -1396,57 +1166,7 @@ where } } - fn validate_and_queue_blocks( - &mut self, - mut new_blocks: Vec>, - gap: bool, - ) -> OnBlockData { - let orig_len = new_blocks.len(); - new_blocks.retain(|b| !self.queue_blocks.contains(&b.hash)); - if new_blocks.len() != orig_len { - debug!( - target: "sync", - "Ignoring {} blocks that are already queued", - orig_len - new_blocks.len(), - ); - } - - let origin = if !gap && self.status().state != SyncState::Downloading { - BlockOrigin::NetworkBroadcast - } else { - BlockOrigin::NetworkInitialSync - }; - - if let Some((h, n)) = new_blocks - .last() - .and_then(|b| b.header.as_ref().map(|h| (&b.hash, *h.number()))) - { - trace!( - target:"sync", - "Accepted {} blocks ({:?}) with origin {:?}", - new_blocks.len(), - h, - origin, - ); - self.on_block_queued(h, n) - } - self.queue_blocks.extend(new_blocks.iter().map(|b| b.hash)); - OnBlockData::Import(origin, new_blocks) - } - - fn update_peer_common_number(&mut self, peer_id: &PeerId, new_common: NumberFor) { - if let Some(peer) = self.peers.get_mut(peer_id) { - peer.update_common_number(new_common); - } - } - - /// Handle a response from the remote to a justification request that we made. - /// - /// `request` must be the original request that triggered `response`. - /// - /// Returns `Some` if this produces a justification that must be imported - /// into the import queue. - pub fn on_block_justification( + fn on_block_justification( &mut self, who: PeerId, response: BlockResponse, @@ -1501,18 +1221,12 @@ where Ok(OnBlockJustification::Nothing) } - /// A batch of blocks have been processed, with or without errors. - /// - /// Call this when a batch of blocks have been processed by the import - /// queue, with or without errors. - /// - /// `peer_info` is passed in case of a restart. - pub fn on_blocks_processed( + fn on_blocks_processed( &mut self, imported: usize, count: usize, results: Vec<(Result>, BlockImportError>, B::Hash)>, - ) -> impl Iterator), BadPeer>> { + ) -> Box), BadPeer>>> { trace!(target: "sync", "Imported {} of {}", imported, count); let mut output = Vec::new(); @@ -1654,54 +1368,435 @@ where } self.allowed_requests.set_all(); - output.into_iter() + Box::new(output.into_iter()) + } + + fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor, success: bool) { + let finalization_result = if success { Ok((hash, number)) } else { Err(()) }; + self.extra_justifications + .try_finalize_root((hash, number), finalization_result, true); + self.allowed_requests.set_all(); + } + + fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor) { + let client = &self.client; + let r = self.extra_justifications.on_block_finalized(hash, number, |base, block| { + is_descendent_of(&**client, base, block) + }); + + if let SyncMode::LightState { skip_proofs, .. } = &self.mode { + if self.state_sync.is_none() && !self.peers.is_empty() && self.queue_blocks.is_empty() { + // Finalized a recent block. + let mut heads: Vec<_> = + self.peers.iter().map(|(_, peer)| peer.best_number).collect(); + heads.sort(); + let median = heads[heads.len() / 2]; + if number + STATE_SYNC_FINALITY_THRESHOLD.saturated_into() >= median { + if let Ok(Some(header)) = self.client.header(BlockId::hash(*hash)) { + log::debug!( + target: "sync", + "Starting state sync for #{} ({})", + number, + hash, + ); + self.state_sync = + Some(StateSync::new(self.client.clone(), header, *skip_proofs)); + self.allowed_requests.set_all(); + } + } + } + } + + if let Err(err) = r { + warn!( + target: "sync", + "💔 Error cleaning up pending extra justification data requests: {}", + err, + ); + } + } + + fn push_block_announce_validation( + &mut self, + who: PeerId, + hash: B::Hash, + announce: BlockAnnounce, + is_best: bool, + ) { + let header = &announce.header; + let number = *header.number(); + debug!( + target: "sync", + "Pre-validating received block announcement {:?} with number {:?} from {}", + hash, + number, + who, + ); + + if number.is_zero() { + self.block_announce_validation.push( + async move { + warn!( + target: "sync", + "💔 Ignored genesis block (#0) announcement from {}: {}", + who, + hash, + ); + PreValidateBlockAnnounce::Skip + } + .boxed(), + ); + return + } + + // Check if there is a slot for this block announce validation. + match self.has_slot_for_block_announce_validation(&who) { + HasSlotForBlockAnnounceValidation::Yes => {}, + HasSlotForBlockAnnounceValidation::TotalMaximumSlotsReached => { + self.block_announce_validation.push( + async move { + warn!( + target: "sync", + "💔 Ignored block (#{} -- {}) announcement from {} because all validation slots are occupied.", + number, + hash, + who, + ); + PreValidateBlockAnnounce::Skip + } + .boxed(), + ); + return + }, + HasSlotForBlockAnnounceValidation::MaximumPeerSlotsReached => { + self.block_announce_validation.push(async move { + warn!( + target: "sync", + "💔 Ignored block (#{} -- {}) announcement from {} because all validation slots for this peer are occupied.", + number, + hash, + who, + ); + PreValidateBlockAnnounce::Skip + }.boxed()); + return + }, + } + + // Let external validator check the block announcement. + let assoc_data = announce.data.as_ref().map_or(&[][..], |v| v.as_slice()); + let future = self.block_announce_validator.validate(header, assoc_data); + + self.block_announce_validation.push( + async move { + match future.await { + Ok(Validation::Success { is_new_best }) => PreValidateBlockAnnounce::Process { + is_new_best: is_new_best || is_best, + announce, + who, + }, + Ok(Validation::Failure { disconnect }) => { + debug!( + target: "sync", + "Block announcement validation of block {:?} from {} failed", + hash, + who, + ); + PreValidateBlockAnnounce::Failure { who, disconnect } + }, + Err(e) => { + debug!( + target: "sync", + "💔 Block announcement validation of block {:?} errored: {}", + hash, + e, + ); + PreValidateBlockAnnounce::Error { who } + }, + } + } + .boxed(), + ); + } + + fn poll_block_announce_validation( + &mut self, + cx: &mut std::task::Context, + ) -> Poll> { + match self.block_announce_validation.poll_next_unpin(cx) { + Poll::Ready(Some(res)) => { + self.peer_block_announce_validation_finished(&res); + Poll::Ready(self.finish_block_announce_validation(res)) + }, + _ => Poll::Pending, + } + } + + fn peer_disconnected(&mut self, who: &PeerId) -> Option> { + self.blocks.clear_peer_download(who); + if let Some(gap_sync) = &mut self.gap_sync { + gap_sync.blocks.clear_peer_download(who) + } + self.peers.remove(who); + self.extra_justifications.peer_disconnected(who); + self.allowed_requests.set_all(); + self.fork_targets.retain(|_, target| { + target.peers.remove(who); + !target.peers.is_empty() + }); + let blocks = self.ready_blocks(); + (!blocks.is_empty()).then(|| self.validate_and_queue_blocks(blocks, false)) + } + + fn metrics(&self) -> Metrics { + Metrics { + queued_blocks: self.queue_blocks.len().try_into().unwrap_or(std::u32::MAX), + fork_targets: self.fork_targets.len().try_into().unwrap_or(std::u32::MAX), + justifications: self.extra_justifications.metrics(), + } + } + + /// Create implementation-specific block request. + fn create_opaque_block_request(&self, request: &BlockRequest) -> OpaqueBlockRequest { + OpaqueBlockRequest(Box::new(schema::v1::BlockRequest { + fields: request.fields.to_be_u32(), + from_block: match request.from { + FromBlock::Hash(h) => Some(schema::v1::block_request::FromBlock::Hash(h.encode())), + FromBlock::Number(n) => + Some(schema::v1::block_request::FromBlock::Number(n.encode())), + }, + to_block: request.to.map(|h| h.encode()).unwrap_or_default(), + direction: request.direction as i32, + max_blocks: request.max.unwrap_or(0), + support_multiple_justifications: true, + })) + } + + fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String> { + let request: &schema::v1::BlockRequest = request.0.downcast_ref().ok_or_else(|| { + "Failed to downcast opaque block response during encoding, this is an \ + implementation bug." + .to_string() + })?; + + Ok(request.encode_to_vec()) + } + + fn decode_block_response(&self, response: &[u8]) -> Result { + let response = schema::v1::BlockResponse::decode(response) + .map_err(|error| format!("Failed to decode block response: {error}"))?; + + Ok(OpaqueBlockResponse(Box::new(response))) + } + + fn block_response_into_blocks( + &self, + request: &BlockRequest, + response: OpaqueBlockResponse, + ) -> Result>, String> { + let response: Box = response.0.downcast().map_err(|_error| { + "Failed to downcast opaque block response during encoding, this is an \ + implementation bug." + .to_string() + })?; + + response + .blocks + .into_iter() + .map(|block_data| { + Ok(BlockData:: { + hash: Decode::decode(&mut block_data.hash.as_ref())?, + header: if !block_data.header.is_empty() { + Some(Decode::decode(&mut block_data.header.as_ref())?) + } else { + None + }, + body: if request.fields.contains(BlockAttributes::BODY) { + Some( + block_data + .body + .iter() + .map(|body| Decode::decode(&mut body.as_ref())) + .collect::, _>>()?, + ) + } else { + None + }, + indexed_body: if request.fields.contains(BlockAttributes::INDEXED_BODY) { + Some(block_data.indexed_body) + } else { + None + }, + receipt: if !block_data.receipt.is_empty() { + Some(block_data.receipt) + } else { + None + }, + message_queue: if !block_data.message_queue.is_empty() { + Some(block_data.message_queue) + } else { + None + }, + justification: if !block_data.justification.is_empty() { + Some(block_data.justification) + } else if block_data.is_empty_justification { + Some(Vec::new()) + } else { + None + }, + justifications: if !block_data.justifications.is_empty() { + Some(DecodeAll::decode_all(&mut block_data.justifications.as_ref())?) + } else { + None + }, + }) + }) + .collect::>() + .map_err(|error: codec::Error| error.to_string()) + } + + fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String> { + let request: &StateRequest = request.0.downcast_ref().ok_or_else(|| { + "Failed to downcast opaque state response during encoding, this is an \ + implementation bug." + .to_string() + })?; + + Ok(request.encode_to_vec()) + } + + fn decode_state_response(&self, response: &[u8]) -> Result { + let response = StateResponse::decode(response) + .map_err(|error| format!("Failed to decode state response: {error}"))?; + + Ok(OpaqueStateResponse(Box::new(response))) + } +} + +impl ChainSync +where + Self: ChainSyncT, + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ + /// Create a new instance. + pub fn new( + mode: SyncMode, + client: Arc, + block_announce_validator: Box + Send>, + max_parallel_downloads: u32, + warp_sync_provider: Option>>, + ) -> Result { + let mut sync = Self { + client, + peers: HashMap::new(), + blocks: BlockCollection::new(), + best_queued_hash: Default::default(), + best_queued_number: Zero::zero(), + extra_justifications: ExtraRequests::new("justification"), + mode, + queue_blocks: Default::default(), + fork_targets: Default::default(), + allowed_requests: Default::default(), + block_announce_validator, + max_parallel_downloads, + downloaded_blocks: 0, + block_announce_validation: Default::default(), + block_announce_validation_per_peer_stats: Default::default(), + state_sync: None, + warp_sync: None, + warp_sync_provider, + import_existing: false, + gap_sync: None, + }; + sync.reset_sync_start_point()?; + Ok(sync) } - /// Call this when a justification has been processed by the import queue, - /// with or without errors. - pub fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor, success: bool) { - let finalization_result = if success { Ok((hash, number)) } else { Err(()) }; - self.extra_justifications - .try_finalize_root((hash, number), finalization_result, true); - self.allowed_requests.set_all(); + /// Returns the best seen block. + fn best_seen(&self) -> Option> { + let mut best_seens = self.peers.values().map(|p| p.best_number).collect::>(); + + if best_seens.is_empty() { + None + } else { + let middle = best_seens.len() / 2; + + // Not the "perfect median" when we have an even number of peers. + Some(*best_seens.select_nth_unstable(middle).1) + } } - /// Notify about finalization of the given block. - pub fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor) { - let client = &self.client; - let r = self.extra_justifications.on_block_finalized(hash, number, |base, block| { - is_descendent_of(&**client, base, block) - }); + fn required_block_attributes(&self) -> BlockAttributes { + match self.mode { + SyncMode::Full => + BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION | BlockAttributes::BODY, + SyncMode::Light => BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION, + SyncMode::LightState { storage_chain_mode: false, .. } | SyncMode::Warp => + BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION | BlockAttributes::BODY, + SyncMode::LightState { storage_chain_mode: true, .. } => + BlockAttributes::HEADER | + BlockAttributes::JUSTIFICATION | + BlockAttributes::INDEXED_BODY, + } + } - if let SyncMode::LightState { skip_proofs, .. } = &self.mode { - if self.state_sync.is_none() && !self.peers.is_empty() && self.queue_blocks.is_empty() { - // Finalized a recent block. - let mut heads: Vec<_> = - self.peers.iter().map(|(_, peer)| peer.best_number).collect(); - heads.sort(); - let median = heads[heads.len() / 2]; - if number + STATE_SYNC_FINALITY_THRESHOLD.saturated_into() >= median { - if let Ok(Some(header)) = self.client.header(BlockId::hash(*hash)) { - log::debug!( - target: "sync", - "Starting state sync for #{} ({})", - number, - hash, - ); - self.state_sync = - Some(StateSync::new(self.client.clone(), header, *skip_proofs)); - self.allowed_requests.set_all(); - } - } - } + fn skip_execution(&self) -> bool { + match self.mode { + SyncMode::Full => false, + SyncMode::Light => true, + SyncMode::LightState { .. } => true, + SyncMode::Warp => true, } + } - if let Err(err) = r { - warn!( + fn validate_and_queue_blocks( + &mut self, + mut new_blocks: Vec>, + gap: bool, + ) -> OnBlockData { + let orig_len = new_blocks.len(); + new_blocks.retain(|b| !self.queue_blocks.contains(&b.hash)); + if new_blocks.len() != orig_len { + debug!( target: "sync", - "💔 Error cleaning up pending extra justification data requests: {}", - err, + "Ignoring {} blocks that are already queued", + orig_len - new_blocks.len(), + ); + } + + let origin = if !gap && self.status().state != SyncState::Downloading { + BlockOrigin::NetworkBroadcast + } else { + BlockOrigin::NetworkInitialSync + }; + + if let Some((h, n)) = new_blocks + .last() + .and_then(|b| b.header.as_ref().map(|h| (&b.hash, *h.number()))) + { + trace!( + target:"sync", + "Accepted {} blocks ({:?}) with origin {:?}", + new_blocks.len(), + h, + origin, ); + self.on_block_queued(h, n) + } + self.queue_blocks.extend(new_blocks.iter().map(|b| b.hash)); + OnBlockData::Import(origin, new_blocks) + } + + fn update_peer_common_number(&mut self, peer_id: &PeerId, new_common: NumberFor) { + if let Some(peer) = self.peers.get_mut(peer_id) { + peer.update_common_number(new_common); } } @@ -1779,135 +1874,6 @@ where } } - /// Push a block announce validation. - /// - /// It is required that [`ChainSync::poll_block_announce_validation`] is called - /// to check for finished block announce validations. - pub fn push_block_announce_validation( - &mut self, - who: PeerId, - hash: B::Hash, - announce: BlockAnnounce, - is_best: bool, - ) { - let header = &announce.header; - let number = *header.number(); - debug!( - target: "sync", - "Pre-validating received block announcement {:?} with number {:?} from {}", - hash, - number, - who, - ); - - if number.is_zero() { - self.block_announce_validation.push( - async move { - warn!( - target: "sync", - "💔 Ignored genesis block (#0) announcement from {}: {}", - who, - hash, - ); - PreValidateBlockAnnounce::Skip - } - .boxed(), - ); - return - } - - // Check if there is a slot for this block announce validation. - match self.has_slot_for_block_announce_validation(&who) { - HasSlotForBlockAnnounceValidation::Yes => {}, - HasSlotForBlockAnnounceValidation::TotalMaximumSlotsReached => { - self.block_announce_validation.push( - async move { - warn!( - target: "sync", - "💔 Ignored block (#{} -- {}) announcement from {} because all validation slots are occupied.", - number, - hash, - who, - ); - PreValidateBlockAnnounce::Skip - } - .boxed(), - ); - return - }, - HasSlotForBlockAnnounceValidation::MaximumPeerSlotsReached => { - self.block_announce_validation.push(async move { - warn!( - target: "sync", - "💔 Ignored block (#{} -- {}) announcement from {} because all validation slots for this peer are occupied.", - number, - hash, - who, - ); - PreValidateBlockAnnounce::Skip - }.boxed()); - return - }, - } - - // Let external validator check the block announcement. - let assoc_data = announce.data.as_ref().map_or(&[][..], |v| v.as_slice()); - let future = self.block_announce_validator.validate(header, assoc_data); - - self.block_announce_validation.push( - async move { - match future.await { - Ok(Validation::Success { is_new_best }) => PreValidateBlockAnnounce::Process { - is_new_best: is_new_best || is_best, - announce, - who, - }, - Ok(Validation::Failure { disconnect }) => { - debug!( - target: "sync", - "Block announcement validation of block {:?} from {} failed", - hash, - who, - ); - PreValidateBlockAnnounce::Failure { who, disconnect } - }, - Err(e) => { - debug!( - target: "sync", - "💔 Block announcement validation of block {:?} errored: {}", - hash, - e, - ); - PreValidateBlockAnnounce::Error { who } - }, - } - } - .boxed(), - ); - } - - /// Poll block announce validation. - /// - /// Block announce validations can be pushed by using - /// [`ChainSync::push_block_announce_validation`]. - /// - /// This should be polled until it returns [`Poll::Pending`]. - /// - /// If [`PollBlockAnnounceValidation::ImportHeader`] is returned, then the caller MUST try to - /// import passed header (call `on_block_data`). The network request isn't sent in this case. - pub fn poll_block_announce_validation( - &mut self, - cx: &mut std::task::Context, - ) -> Poll> { - match self.block_announce_validation.poll_next_unpin(cx) { - Poll::Ready(Some(res)) => { - self.peer_block_announce_validation_finished(&res); - Poll::Ready(self.finish_block_announce_validation(res)) - }, - _ => Poll::Pending, - } - } - /// Should be called when a block announce validation is finished, to update the slots /// of the peer that send the block announce. fn peer_block_announce_validation_finished( @@ -2065,29 +2031,6 @@ where PollBlockAnnounceValidation::Nothing { is_best, who, announce } } - /// Call when a peer has disconnected. - /// Canceled obsolete block request may result in some blocks being ready for - /// import, so this functions checks for such blocks and returns them. - pub fn peer_disconnected(&mut self, who: &PeerId) -> Option> { - self.blocks.clear_peer_download(who); - if let Some(gap_sync) = &mut self.gap_sync { - gap_sync.blocks.clear_peer_download(who) - } - self.peers.remove(who); - self.extra_justifications.peer_disconnected(who); - self.allowed_requests.set_all(); - self.fork_targets.retain(|_, target| { - target.peers.remove(who); - !target.peers.is_empty() - }); - let blocks = self.ready_blocks(); - if !blocks.is_empty() { - Some(self.validate_and_queue_blocks(blocks, false)) - } else { - None - } - } - /// Restart the sync process. This will reset all pending block requests and return an iterator /// of new block requests to make to peers. Peers that were downloading finality data (i.e. /// their state was `DownloadingJustification`) are unaffected and will stay in the same state. @@ -2190,16 +2133,6 @@ where .any(|(_, p)| p.state == PeerSyncState::DownloadingStale(*hash)) } - /// Return some key metrics. - pub fn metrics(&self) -> Metrics { - Metrics { - queued_blocks: self.queue_blocks.len().try_into().unwrap_or(std::u32::MAX), - fork_targets: self.fork_targets.len().try_into().unwrap_or(std::u32::MAX), - justifications: self.extra_justifications.metrics(), - _priv: (), - } - } - /// Get the set of downloaded blocks that are ready to be queued for import. fn ready_blocks(&mut self) -> Vec> { self.blocks @@ -2237,23 +2170,15 @@ fn legacy_justification_mapping( justification.map(|just| (*b"FRNK", just).into()) } -#[derive(Debug)] -pub struct Metrics { - pub queued_blocks: u32, - pub fork_targets: u32, - pub justifications: extra_requests::Metrics, - _priv: (), -} - /// Request the ancestry for a block. Sends a request for header and justification for the given /// block number. Used during ancestry search. fn ancestry_request(block: NumberFor) -> BlockRequest { - message::generic::BlockRequest { + BlockRequest:: { id: 0, fields: BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION, - from: message::FromBlock::Number(block), + from: FromBlock::Number(block), to: None, - direction: message::Direction::Ascending, + direction: Direction::Ascending, max: Some(1), } } @@ -2331,7 +2256,7 @@ fn peer_block_request( id: &PeerId, peer: &PeerSync, blocks: &mut BlockCollection, - attrs: message::BlockAttributes, + attrs: BlockAttributes, max_parallel_downloads: u32, finalized: NumberFor, best_num: NumberFor, @@ -2359,17 +2284,17 @@ fn peer_block_request( let last = range.end.saturating_sub(One::one()); let from = if peer.best_number == last { - message::FromBlock::Hash(peer.best_hash) + FromBlock::Hash(peer.best_hash) } else { - message::FromBlock::Number(last) + FromBlock::Number(last) }; - let request = message::generic::BlockRequest { + let request = BlockRequest:: { id: 0, fields: attrs, from, to: None, - direction: message::Direction::Descending, + direction: Direction::Descending, max: Some((range.end - range.start).saturated_into::()), }; @@ -2381,7 +2306,7 @@ fn peer_gap_block_request( id: &PeerId, peer: &PeerSync, blocks: &mut BlockCollection, - attrs: message::BlockAttributes, + attrs: BlockAttributes, target: NumberFor, common_number: NumberFor, ) -> Option<(Range>, BlockRequest)> { @@ -2396,14 +2321,14 @@ fn peer_gap_block_request( // The end is not part of the range. let last = range.end.saturating_sub(One::one()); - let from = message::FromBlock::Number(last); + let from = FromBlock::Number(last); - let request = message::generic::BlockRequest { + let request = BlockRequest:: { id: 0, fields: attrs, from, to: None, - direction: message::Direction::Descending, + direction: Direction::Descending, max: Some((range.end - range.start).saturated_into::()), }; Some((range, request)) @@ -2415,7 +2340,7 @@ fn fork_sync_request( targets: &mut HashMap>, best_num: NumberFor, finalized: NumberFor, - attributes: message::BlockAttributes, + attributes: BlockAttributes, check_block: impl Fn(&B::Hash) -> BlockStatus, ) -> Option<(B::Hash, BlockRequest)> { targets.retain(|hash, r| { @@ -2448,12 +2373,12 @@ fn fork_sync_request( trace!(target: "sync", "Downloading requested fork {:?} from {}, {} blocks", hash, id, count); return Some(( *hash, - message::generic::BlockRequest { + BlockRequest:: { id: 0, fields: attributes, - from: message::FromBlock::Hash(*hash), + from: FromBlock::Hash(*hash), to: None, - direction: message::Direction::Descending, + direction: Direction::Descending, max: Some(count), }, )) @@ -2488,7 +2413,7 @@ where /// /// It is expected that `blocks` are in ascending order. fn validate_blocks( - blocks: &Vec>, + blocks: &Vec>, who: &PeerId, request: Option>, ) -> Result>, BadPeer> { @@ -2505,16 +2430,13 @@ fn validate_blocks( return Err(BadPeer(*who, rep::NOT_REQUESTED)) } - let block_header = if request.direction == message::Direction::Descending { - blocks.last() - } else { - blocks.first() - } - .and_then(|b| b.header.as_ref()); + let block_header = + if request.direction == Direction::Descending { blocks.last() } else { blocks.first() } + .and_then(|b| b.header.as_ref()); let expected_block = block_header.as_ref().map_or(false, |h| match request.from { - message::FromBlock::Hash(hash) => h.hash() == hash, - message::FromBlock::Number(n) => h.number() == &n, + FromBlock::Hash(hash) => h.hash() == hash, + FromBlock::Number(n) => h.number() == &n, }); if !expected_block { @@ -2528,7 +2450,7 @@ fn validate_blocks( return Err(BadPeer(*who, rep::NOT_REQUESTED)) } - if request.fields.contains(message::BlockAttributes::HEADER) && + if request.fields.contains(BlockAttributes::HEADER) && blocks.iter().any(|b| b.header.is_none()) { trace!( @@ -2540,8 +2462,7 @@ fn validate_blocks( return Err(BadPeer(*who, rep::BAD_RESPONSE)) } - if request.fields.contains(message::BlockAttributes::BODY) && - blocks.iter().any(|b| b.body.is_none()) + if request.fields.contains(BlockAttributes::BODY) && blocks.iter().any(|b| b.body.is_none()) { trace!( target: "sync", @@ -2592,13 +2513,10 @@ fn validate_blocks( #[cfg(test)] mod test { - use super::{ - message::{BlockState, FromBlock}, - *, - }; - use crate::message::BlockData; + use super::*; use futures::{executor::block_on, future::poll_fn}; use sc_block_builder::BlockBuilderProvider; + use sc_network_common::sync::message::{BlockData, BlockState, FromBlock}; use sp_blockchain::HeaderBackend; use sp_consensus::block_validation::DefaultBlockAnnounceValidator; use substrate_test_runtime_client::{ @@ -2709,7 +2627,7 @@ mod test { assert!(sync.justification_requests().any(|(p, r)| { p == peer_id3 && r.fields == BlockAttributes::JUSTIFICATION && - r.from == message::FromBlock::Hash(b1_hash) && + r.from == FromBlock::Hash(b1_hash) && r.to == None })); @@ -3125,10 +3043,11 @@ mod test { let response = create_block_response(vec![block.clone()]); let on_block_data = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); - request = match on_block_data.into_request() { - Some(req) => req.1, + request = if let OnBlockData::Request(_peer, request) = on_block_data { + request + } else { // We found the ancenstor - None => break, + break }; log::trace!(target: "sync", "Request: {:?}", request); @@ -3255,10 +3174,11 @@ mod test { let response = create_block_response(vec![block.clone()]); let on_block_data = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); - request = match on_block_data.into_request() { - Some(req) => req.1, + request = if let OnBlockData::Request(_peer, request) = on_block_data { + request + } else { // We found the ancenstor - None => break, + break }; log::trace!(target: "sync", "Request: {:?}", request); diff --git a/client/network/sync/src/schema.rs b/client/network/sync/src/schema.rs index aa3eb84621d8f..b31005360d023 100644 --- a/client/network/sync/src/schema.rs +++ b/client/network/sync/src/schema.rs @@ -18,6 +18,6 @@ //! Include sources generated from protobuf definitions. -pub mod v1 { +pub(crate) mod v1 { include!(concat!(env!("OUT_DIR"), "/api.v1.rs")); } diff --git a/client/network/sync/src/state.rs b/client/network/sync/src/state.rs index 4041c28af0eba..e70d3b6b33a28 100644 --- a/client/network/sync/src/state.rs +++ b/client/network/sync/src/state.rs @@ -23,6 +23,7 @@ use codec::{Decode, Encode}; use log::debug; use sc_client_api::{CompactProof, ProofProvider}; use sc_consensus::ImportedState; +use sc_network_common::sync::StateDownloadProgress; use smallvec::SmallVec; use sp_core::storage::well_known_keys; use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; @@ -42,15 +43,6 @@ pub struct StateSync { skip_proof: bool, } -/// Reported state download progress. -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct StateDownloadProgress { - /// Estimated download percentage. - pub percentage: u32, - /// Total state size in bytes downloaded so far. - pub size: u64, -} - /// Import state chunk result. pub enum ImportResult { /// State is complete and ready for import. diff --git a/client/network/sync/src/warp.rs b/client/network/sync/src/warp.rs index d3d9d7d244153..f3fad6c1b7fdb 100644 --- a/client/network/sync/src/warp.rs +++ b/client/network/sync/src/warp.rs @@ -18,60 +18,25 @@ //! Warp sync support. -pub use crate::warp_request_handler::{ - EncodedProof, Request as WarpProofRequest, VerificationResult, WarpSyncProvider, -}; use crate::{ schema::v1::{StateRequest, StateResponse}, state::{ImportResult, StateSync}, }; use sc_client_api::ProofProvider; +use sc_network_common::sync::warp::{ + EncodedProof, VerificationResult, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, + WarpSyncProvider, +}; use sp_blockchain::HeaderBackend; use sp_finality_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; -use std::{fmt, sync::Arc}; +use std::sync::Arc; enum Phase { WarpProof { set_id: SetId, authorities: AuthorityList, last_hash: B::Hash }, State(StateSync), } -/// Reported warp sync phase. -#[derive(Clone, Eq, PartialEq, Debug)] -pub enum WarpSyncPhase { - /// Waiting for peers to connect. - AwaitingPeers, - /// Downloading and verifying grandpa warp proofs. - DownloadingWarpProofs, - /// Downloading state data. - DownloadingState, - /// Importing state. - ImportingState, - /// Downloading block history. - DownloadingBlocks(NumberFor), -} - -impl fmt::Display for WarpSyncPhase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::AwaitingPeers => write!(f, "Waiting for peers"), - Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"), - Self::DownloadingState => write!(f, "Downloading state"), - Self::ImportingState => write!(f, "Importing state"), - Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n), - } - } -} - -/// Reported warp sync progress. -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct WarpSyncProgress { - /// Estimated download percentage. - pub phase: WarpSyncPhase, - /// Total bytes downloaded so far. - pub total_bytes: u64, -} - /// Import warp proof result. pub enum WarpProofImportResult { /// Import was successful. diff --git a/client/network/sync/src/warp_request_handler.rs b/client/network/sync/src/warp_request_handler.rs index 4f66e0a6daf17..53ec216a1e668 100644 --- a/client/network/sync/src/warp_request_handler.rs +++ b/client/network/sync/src/warp_request_handler.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright 2022 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ //! Helper for handling (i.e. answering) grandpa warp sync requests from a remote peer. -use codec::{Decode, Encode}; +use codec::Decode; use futures::{ channel::{mpsc, oneshot}, stream::StreamExt, @@ -27,52 +27,13 @@ use sc_network_common::{ request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, + sync::warp::{EncodedProof, WarpProofRequest, WarpSyncProvider}, }; use sp_runtime::traits::Block as BlockT; use std::{sync::Arc, time::Duration}; -pub use sp_finality_grandpa::{AuthorityList, SetId}; - -/// Scale-encoded warp sync proof response. -pub struct EncodedProof(pub Vec); - -/// Warp sync request -#[derive(Encode, Decode, Debug)] -pub struct Request { - /// Start collecting proofs from this block. - pub begin: B::Hash, -} - const MAX_RESPONSE_SIZE: u64 = 16 * 1024 * 1024; -/// Proof verification result. -pub enum VerificationResult { - /// Proof is valid, but the target was not reached. - Partial(SetId, AuthorityList, Block::Hash), - /// Target finality is proved. - Complete(SetId, AuthorityList, Block::Header), -} - -/// Warp sync backend. Handles retrieveing and verifying warp sync proofs. -pub trait WarpSyncProvider: Send + Sync { - /// Generate proof starting at given block hash. The proof is accumulated until maximum proof - /// size is reached. - fn generate( - &self, - start: B::Hash, - ) -> Result>; - /// Verify warp proof against current set of authorities. - fn verify( - &self, - proof: &EncodedProof, - set_id: SetId, - authorities: AuthorityList, - ) -> Result, Box>; - /// Get current list of authorities. This is supposed to be genesis authorities when starting - /// sync. - fn current_authorities(&self) -> AuthorityList; -} - /// Generates a [`RequestResponseConfig`] for the grandpa warp sync request protocol, refusing /// incoming requests. pub fn generate_request_response_config(protocol_id: ProtocolId) -> RequestResponseConfig { @@ -115,7 +76,7 @@ impl RequestHandler { payload: Vec, pending_response: oneshot::Sender, ) -> Result<(), HandleRequestError> { - let request = Request::::decode(&mut &payload[..])?; + let request = WarpProofRequest::::decode(&mut &payload[..])?; let EncodedProof(proof) = self .backend diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index fdb9befc41cb1..1aa6ebd8bf357 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -26,6 +26,8 @@ sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-network = { version = "0.10.0-dev", path = "../" } sc-network-common = { version = "0.10.0-dev", path = "../common" } +sc-network-light = { version = "0.10.0-dev", path = "../light" } +sc-network-sync = { version = "0.10.0-dev", path = "../sync" } sc-service = { version = "0.10.0-dev", default-features = false, features = ["test-helpers"], path = "../../service" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 9e752e81a3bbc..d7c83810d521d 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -48,16 +48,21 @@ use sc_consensus::{ }; pub use sc_network::config::EmptyTransactionPool; use sc_network::{ - block_request_handler::BlockRequestHandler, config::{ - MultiaddrWithPeerId, NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, - ProtocolConfig, Role, SyncMode, TransportConfig, + MultiaddrWithPeerId, NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, Role, + SyncMode, TransportConfig, }, - light_client_requests::handler::LightClientRequestHandler, - state_request_handler::StateRequestHandler, - warp_request_handler, Multiaddr, NetworkService, NetworkWorker, + Multiaddr, NetworkService, NetworkWorker, }; pub use sc_network_common::config::ProtocolId; +use sc_network_common::sync::warp::{ + AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider, +}; +use sc_network_light::light_client_requests::handler::LightClientRequestHandler; +use sc_network_sync::{ + block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler, + warp_request_handler, ChainSync, +}; use sc_service::client::Client; use sp_blockchain::{ well_known_cache_keys::{self, Id as CacheKeyId}, @@ -638,27 +643,26 @@ impl VerifierAdapter { struct TestWarpSyncProvider(Arc>); -impl warp_request_handler::WarpSyncProvider for TestWarpSyncProvider { +impl WarpSyncProvider for TestWarpSyncProvider { fn generate( &self, _start: B::Hash, - ) -> Result> { + ) -> Result> { let info = self.0.info(); let best_header = self.0.header(BlockId::hash(info.best_hash)).unwrap().unwrap(); - Ok(warp_request_handler::EncodedProof(best_header.encode())) + Ok(EncodedProof(best_header.encode())) } fn verify( &self, - proof: &warp_request_handler::EncodedProof, - _set_id: warp_request_handler::SetId, - _authorities: warp_request_handler::AuthorityList, - ) -> Result, Box> - { - let warp_request_handler::EncodedProof(encoded) = proof; + proof: &EncodedProof, + _set_id: SetId, + _authorities: AuthorityList, + ) -> Result, Box> { + let EncodedProof(encoded) = proof; let header = B::Header::decode(&mut encoded.as_slice()).unwrap(); - Ok(warp_request_handler::VerificationResult::Complete(0, Default::default(), header)) + Ok(VerificationResult::Complete(0, Default::default(), header)) } - fn current_authorities(&self) -> warp_request_handler::AuthorityList { + fn current_authorities(&self) -> AuthorityList { Default::default() } } @@ -688,7 +692,7 @@ pub struct FullPeerConfig { pub storage_chain: bool, } -pub trait TestNetFactory: Sized +pub trait TestNetFactory: Default + Sized where >::Transaction: Send, { @@ -696,14 +700,8 @@ where type BlockImport: BlockImport + Clone + Send + Sync + 'static; type PeerData: Default; - /// These two need to be implemented! - fn from_config(config: &ProtocolConfig) -> Self; - fn make_verifier( - &self, - client: PeersClient, - config: &ProtocolConfig, - peer_data: &Self::PeerData, - ) -> Self::Verifier; + /// This one needs to be implemented! + fn make_verifier(&self, client: PeersClient, peer_data: &Self::PeerData) -> Self::Verifier; /// Get reference to peer. fn peer(&mut self, i: usize) -> &mut Peer; @@ -723,15 +721,10 @@ where Self::PeerData, ); - fn default_config() -> ProtocolConfig { - ProtocolConfig::default() - } - /// Create new test network with this many peers. fn new(n: usize) -> Self { trace!(target: "test_network", "Creating test network"); - let config = Self::default_config(); - let mut net = Self::from_config(&config); + let mut net = Self::default(); for i in 0..n { trace!(target: "test_network", "Adding peer {}", i); @@ -767,11 +760,8 @@ where let (block_import, justification_import, data) = self .make_block_import(PeersClient { client: client.clone(), backend: backend.clone() }); - let verifier = self.make_verifier( - PeersClient { client: client.clone(), backend: backend.clone() }, - &Default::default(), - &data, - ); + let verifier = self + .make_verifier(PeersClient { client: client.clone(), backend: backend.clone() }, &data); let verifier = VerifierAdapter::new(verifier); let import_queue = Box::new(BasicQueue::new( @@ -845,6 +835,10 @@ where protocol_config }; + let max_parallel_downloads = network_config.max_parallel_downloads; + let block_announce_validator = config + .block_announce_validator + .unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)); let network = NetworkWorker::new(sc_network::config::Params { role: if config.is_authority { Role::Authority } else { Role::Full }, executor: None, @@ -856,9 +850,18 @@ where transaction_pool: Arc::new(EmptyTransactionPool), protocol_id, import_queue, - block_announce_validator: config - .block_announce_validator - .unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)), + create_chain_sync: Box::new(move |sync_mode, chain, warp_sync_provider| { + match ChainSync::new( + sync_mode, + chain, + block_announce_validator, + max_parallel_downloads, + warp_sync_provider, + ) { + Ok(chain_sync) => Ok(Box::new(chain_sync)), + Err(error) => Err(Box::new(error).into()), + } + }), metrics_registry: None, block_request_protocol_config, state_request_protocol_config, @@ -1012,6 +1015,7 @@ where } } +#[derive(Default)] pub struct TestNet { peers: Vec>, } @@ -1021,17 +1025,7 @@ impl TestNetFactory for TestNet { type PeerData = (); type BlockImport = PeersClient; - /// Create new test network with peers and given config. - fn from_config(_config: &ProtocolConfig) -> Self { - TestNet { peers: Vec::new() } - } - - fn make_verifier( - &self, - _client: PeersClient, - _config: &ProtocolConfig, - _peer_data: &(), - ) -> Self::Verifier { + fn make_verifier(&self, _client: PeersClient, _peer_data: &()) -> Self::Verifier { PassThroughVerifier::new(false) } @@ -1081,6 +1075,7 @@ impl JustificationImport for ForceFinalized { } } +#[derive(Default)] pub struct JustificationTestNet(TestNet); impl TestNetFactory for JustificationTestNet { @@ -1088,17 +1083,8 @@ impl TestNetFactory for JustificationTestNet { type PeerData = (); type BlockImport = PeersClient; - fn from_config(config: &ProtocolConfig) -> Self { - JustificationTestNet(TestNet::from_config(config)) - } - - fn make_verifier( - &self, - client: PeersClient, - config: &ProtocolConfig, - peer_data: &(), - ) -> Self::Verifier { - self.0.make_verifier(client, config, peer_data) + fn make_verifier(&self, client: PeersClient, peer_data: &()) -> Self::Verifier { + self.0.make_verifier(client, peer_data) } fn peer(&mut self, i: usize) -> &mut Peer { diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index ff11dd1344d01..31b0c860cf190 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -50,8 +50,10 @@ sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/comm sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sp-storage = { version = "6.0.0", path = "../../primitives/storage" } -sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } +sc-network-light = { version = "0.10.0-dev", path = "../network/light" } +sc-network-sync = { version = "0.10.0-dev", path = "../network/sync" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 5319bf24d5e72..fe0ae5db53e70 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -38,13 +38,17 @@ use sc_consensus::import_queue::ImportQueue; use sc_executor::RuntimeVersionOf; use sc_keystore::LocalKeystore; use sc_network::{ - block_request_handler::{self, BlockRequestHandler}, config::{Role, SyncMode}, - light_client_requests::{self, handler::LightClientRequestHandler}, - state_request_handler::{self, StateRequestHandler}, - warp_request_handler::{self, RequestHandler as WarpSyncRequestHandler, WarpSyncProvider}, NetworkService, }; +use sc_network_common::sync::warp::WarpSyncProvider; +use sc_network_light::light_client_requests::{self, handler::LightClientRequestHandler}; +use sc_network_sync::{ + block_request_handler::{self, BlockRequestHandler}, + state_request_handler::{self, StateRequestHandler}, + warp_request_handler::{self, RequestHandler as WarpSyncRequestHandler}, + ChainSync, +}; use sc_rpc::{ author::AuthorApiServer, chain::ChainApiServer, @@ -801,6 +805,7 @@ where } }; + let max_parallel_downloads = config.network.max_parallel_downloads; let network_params = sc_network::config::Params { role: config.role.clone(), executor: { @@ -818,9 +823,20 @@ where network_config: config.network.clone(), chain: client.clone(), transaction_pool: transaction_pool_adapter as _, - import_queue: Box::new(import_queue), protocol_id, - block_announce_validator, + import_queue: Box::new(import_queue), + create_chain_sync: Box::new( + move |sync_mode, chain, warp_sync_provider| match ChainSync::new( + sync_mode, + chain, + block_announce_validator, + max_parallel_downloads, + warp_sync_provider, + ) { + Ok(chain_sync) => Ok(Box::new(chain_sync)), + Err(error) => Err(Box::new(error).into()), + }, + ), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_request_protocol_config, state_request_protocol_config, From 42044053b5895991d06ddc776e45da61c6462c78 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 13 Jul 2022 11:09:28 +0100 Subject: [PATCH 0964/1472] Fix off by one error in proportional slashing (#11782) * Fix proportional slashing logic * Update frame/nomination-pools/test-staking/src/lib.rs Co-authored-by: David * Update frame/staking/src/lib.rs Co-authored-by: David * Update frame/staking/src/lib.rs Co-authored-by: David * Update frame/staking/src/lib.rs Co-authored-by: David * fmt * Update frame/nomination-pools/test-staking/src/lib.rs * clean * fix * last fixes * doc Co-authored-by: David --- .../nomination-pools/test-staking/src/lib.rs | 256 +++++++++++++++++- .../nomination-pools/test-staking/src/mock.rs | 7 +- frame/staking/src/lib.rs | 95 +++++-- frame/staking/src/tests.rs | 30 +- 4 files changed, 342 insertions(+), 46 deletions(-) diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs index 2e40e8c6d917d..be7752ce113b4 100644 --- a/frame/nomination-pools/test-staking/src/lib.rs +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -22,7 +22,8 @@ mod mock; use frame_support::{assert_noop, assert_ok, bounded_btree_map, traits::Currency}; use mock::*; use pallet_nomination_pools::{ - Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, PoolMembers, PoolState, + BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, PoolMembers, + PoolState, }; use pallet_staking::{CurrentEra, Event as StakingEvent, Payee, RewardDestination}; @@ -273,7 +274,7 @@ fn pool_slash_e2e() { 30, &mut Default::default(), &mut Default::default(), - 1, // slash era 1, affects chunks at era 5 onwards. + 2, // slash era 2, affects chunks at era 5 onwards. ); assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 30)]); @@ -371,3 +372,254 @@ fn pool_slash_e2e() { ); }); } + +#[test] +fn pool_slash_proportional() { + // a typical example where 3 pool members unbond in era 99, 100, and 101, and a slash that + // happened in era 100 should only affect the latter two. + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + BondingDuration::set(28); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + // have two members join + let bond = 20; + assert_ok!(Pools::join(Origin::signed(20), bond, 1)); + assert_ok!(Pools::join(Origin::signed(21), bond, 1)); + assert_ok!(Pools::join(Origin::signed(22), bond, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded(POOL1_BONDED, bond), + StakingEvent::Bonded(POOL1_BONDED, bond), + StakingEvent::Bonded(POOL1_BONDED, bond), + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: bond, joined: true }, + PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: bond, joined: true }, + ] + ); + + // now let's progress a lot. + CurrentEra::::set(Some(99)); + + // and unbond + assert_ok!(Pools::unbond(Origin::signed(20), 20, bond)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: bond, points: bond }] + ); + + CurrentEra::::set(Some(100)); + assert_ok!(Pools::unbond(Origin::signed(21), 21, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: bond, points: bond }] + ); + + CurrentEra::::set(Some(101)); + assert_ok!(Pools::unbond(Origin::signed(22), 22, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 22, pool_id: 1, balance: bond, points: bond }] + ); + + // Apply a slash that happened in era 100. This is typically applied with a delay. + // Of the total 100, 50 is slashed. + assert_eq!(BondedPools::::get(1).unwrap().points, 40); + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 50, + &mut Default::default(), + &mut Default::default(), + 100, + ); + + assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 50)]); + assert_eq!( + pool_events_since_last_call(), + vec![ + // This last pool got slashed only the leftover dust. Otherwise in principle, this + // chunk/pool should have not been affected. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 19 }, + // This pool got slashed 12.5, which rounded down to 12. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 8 }, + // This pool got slashed 12.5, which rounded down to 12. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 129, balance: 8 }, + // Bonded pool got slashed for 25, remaining 15 in it. + PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } + ] + ); + }); +} + +#[test] +fn pool_slash_non_proportional_only_bonded_pool() { + // A typical example where a pool member unbonds in era 99, and he can get away with a slash + // that happened in era 100, as long as the pool has enough active bond to cover the slash. If + // everything else in the slashing/staking system works, this should always be the case. + // Nonetheless, `ledger.slash` has been written such that it will slash greedily from any chunk + // if it runs out of chunks that it thinks should be affected by the slash. + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + BondingDuration::set(28); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); + assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + // have two members join + let bond = 20; + assert_ok!(Pools::join(Origin::signed(20), bond, 1)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded(POOL1_BONDED, bond)] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] + ); + + // progress and unbond. + CurrentEra::::set(Some(99)); + assert_ok!(Pools::unbond(Origin::signed(20), 20, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded(POOL1_BONDED, bond)] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: bond, points: bond }] + ); + + // slash for 30. This will be deducted only from the bonded pool. + CurrentEra::::set(Some(100)); + assert_eq!(BondedPools::::get(1).unwrap().points, 40); + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 30, + &mut Default::default(), + &mut Default::default(), + 100, + ); + + assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 30)]); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::PoolSlashed { pool_id: 1, balance: 10 }] + ); + }); +} + +#[test] +fn pool_slash_non_proportional_bonded_pool_and_chunks() { + // An uncommon example where even though some funds are unlocked such that they should not be + // affected by a slash, we still slash out of them. This should not happen at all. If a + // nomination has unbonded, from the next era onwards, their exposure will drop, so if an era + // happens in that era, then their share of that slash should naturally be less, such that only + // their active ledger stake is enough to compensate it. + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + BondingDuration::set(28); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); + assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + // have two members join + let bond = 20; + assert_ok!(Pools::join(Origin::signed(20), bond, 1)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded(POOL1_BONDED, bond)] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] + ); + + // progress and unbond. + CurrentEra::::set(Some(99)); + assert_ok!(Pools::unbond(Origin::signed(20), 20, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded(POOL1_BONDED, bond)] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: bond, points: bond }] + ); + + // slash 50. This will be deducted only from the bonded pool and one of the unbonding pools. + CurrentEra::::set(Some(100)); + assert_eq!(BondedPools::::get(1).unwrap().points, 40); + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 50, + &mut Default::default(), + &mut Default::default(), + 100, + ); + + assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 50)]); + assert_eq!( + pool_events_since_last_call(), + vec![ + // out of 20, 10 was taken. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 10 }, + // out of 40, all was taken. + PoolsEvent::PoolSlashed { pool_id: 1, balance: 0 } + ] + ); + }); +} diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 7b720c009b29b..d13d8aa341c12 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -24,6 +24,8 @@ type AccountIndex = u32; type BlockNumber = u64; type Balance = u128; +pub(crate) type T = Runtime; + pub(crate) const POOL1_BONDED: AccountId = 20318131474730217858575332831085u128; pub(crate) const POOL1_REWARD: AccountId = 20397359637244482196168876781421u128; @@ -194,13 +196,14 @@ frame_support::construct_runtime!( ); pub fn new_test_ext() -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); let _ = pallet_nomination_pools::GenesisConfig:: { min_join_bond: 2, min_create_bond: 2, max_pools: Some(3), - max_members_per_pool: Some(3), - max_members: Some(3 * 3), + max_members_per_pool: Some(5), + max_members: Some(3 * 5), } .assimilate_storage(&mut storage) .unwrap(); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 360d5b5efb58f..50c033bdc7e28 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -529,13 +529,26 @@ impl StakingLedger { (self, unlocking_balance) } - /// Slash the staker for a given amount of balance. This can grow the value of the slash in the - /// case that either the active bonded or some unlocking chunks become dust after slashing. - /// Returns the amount of funds actually slashed. + /// Slash the staker for a given amount of balance. /// - /// `slash_era` is the era in which the slash (which is being enacted now) actually happened. + /// This implements a proportional slashing system, whereby we set our preference to slash as + /// such: + /// + /// - If any unlocking chunks exist that are scheduled to be unlocked at `slash_era + + /// bonding_duration` and onwards, the slash is divided equally between the active ledger and + /// the unlocking chunks. + /// - If no such chunks exist, then only the active balance is slashed. + /// + /// Note that the above is only a *preference*. If for any reason the active ledger, with or + /// without some portion of the unlocking chunks that are more justified to be slashed are not + /// enough, then the slashing will continue and will consume as much of the active and unlocking + /// chunks as needed. /// - /// # Note + /// This will never slash more than the given amount. If any of the chunks become dusted, the + /// last chunk is slashed slightly less to compensate. Returns the amount of funds actually + /// slashed. + /// + /// `slash_era` is the era in which the slash (which is being enacted now) actually happened. /// /// This calls `Config::OnStakerSlash::on_slash` with information as to how the slash was /// applied. @@ -545,54 +558,81 @@ impl StakingLedger { minimum_balance: BalanceOf, slash_era: EraIndex, ) -> BalanceOf { - use sp_staking::OnStakerSlash as _; - if slash_amount.is_zero() { return Zero::zero() } + use sp_staking::OnStakerSlash as _; let mut remaining_slash = slash_amount; let pre_slash_total = self.total; - let era_after_slash = slash_era + 1; - let chunk_unlock_era_after_slash = era_after_slash + T::BondingDuration::get(); + // for a `slash_era = x`, any chunk that is scheduled to be unlocked at era `x + 28` + // (assuming 28 is the bonding duration) onwards should be slashed. + let slashable_chunks_start = slash_era + T::BondingDuration::get(); - // Calculate the total balance of active funds and unlocking funds in the affected range. - let (affected_balance, slash_chunks_priority): (_, Box>) = { - if let Some(start_index) = - self.unlocking.iter().position(|c| c.era >= chunk_unlock_era_after_slash) + // `Some(ratio)` if this is proportional, with `ratio`, `None` otherwise. In both cases, we + // slash first the active chunk, and then `slash_chunks_priority`. + let (maybe_proportional, slash_chunks_priority) = { + if let Some(first_slashable_index) = + self.unlocking.iter().position(|c| c.era >= slashable_chunks_start) { + // If there exists a chunk who's after the first_slashable_start, then this is a + // proportional slash, because we want to slash active and these chunks + // proportionally. + // The indices of the first chunk after the slash up through the most recent chunk. // (The most recent chunk is at greatest from this era) - let affected_indices = start_index..self.unlocking.len(); + let affected_indices = first_slashable_index..self.unlocking.len(); let unbonding_affected_balance = affected_indices.clone().fold(BalanceOf::::zero(), |sum, i| { - if let Some(chunk) = self.unlocking.get_mut(i).defensive() { + if let Some(chunk) = self.unlocking.get(i).defensive() { sum.saturating_add(chunk.value) } else { sum } }); + let affected_balance = self.active.saturating_add(unbonding_affected_balance); + let ratio = Perquintill::from_rational(slash_amount, affected_balance); ( - self.active.saturating_add(unbonding_affected_balance), - Box::new(affected_indices.chain((0..start_index).rev())), + Some(ratio), + affected_indices.chain((0..first_slashable_index).rev()).collect::>(), ) } else { - (self.active, Box::new((0..self.unlocking.len()).rev())) + // We just slash from the last chunk to the most recent one, if need be. + (None, (0..self.unlocking.len()).rev().collect::>()) } }; // Helper to update `target` and the ledgers total after accounting for slashing `target`. - let ratio = Perquintill::from_rational(slash_amount, affected_balance); + log!( + debug, + "slashing {:?} for era {:?} out of {:?}, priority: {:?}, proportional = {:?}", + slash_amount, + slash_era, + self, + slash_chunks_priority, + maybe_proportional, + ); + let mut slash_out_of = |target: &mut BalanceOf, slash_remaining: &mut BalanceOf| { - let mut slash_from_target = - if slash_amount < affected_balance { ratio * (*target) } else { *slash_remaining } - .min(*target); + let mut slash_from_target = if let Some(ratio) = maybe_proportional { + ratio * (*target) + } else { + *slash_remaining + } + // this is the total that that the slash target has. We can't slash more than + // this anyhow! + .min(*target) + // this is the total amount that we would have wanted to slash + // non-proportionally, a proportional slash should never exceed this either! + .min(*slash_remaining); // slash out from *target exactly `slash_from_target`. *target = *target - slash_from_target; if *target < minimum_balance { - // Slash the rest of the target if its dust + // Slash the rest of the target if it's dust. This might cause the last chunk to be + // slightly under-slashed, by at most `MaxUnlockingChunks * ED`, which is not a big + // deal. slash_from_target = sp_std::mem::replace(target, Zero::zero()).saturating_add(slash_from_target) } @@ -606,10 +646,11 @@ impl StakingLedger { let mut slashed_unlocking = BTreeMap::<_, _>::new(); for i in slash_chunks_priority { + if remaining_slash.is_zero() { + break + } + if let Some(chunk) = self.unlocking.get_mut(i).defensive() { - if remaining_slash.is_zero() { - break - } slash_out_of(&mut chunk.value, &mut remaining_slash); // write the new slashed value of this chunk to the map. slashed_unlocking.insert(chunk.era, chunk.value); @@ -618,7 +659,9 @@ impl StakingLedger { } } + // clean unlocking chunks that are set to zero. self.unlocking.retain(|c| !c.value.is_zero()); + T::OnStakerSlash::on_slash(&self.stash, self.active, &slashed_unlocking); pre_slash_total.saturating_sub(self.total) } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 9a13a818f4b59..b76126f0c5d04 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2081,8 +2081,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { let _ = Balances::make_free_balance_be(&11, stake); let _ = Balances::make_free_balance_be(&2, stake); - // only slashes out of bonded stake are applied. without this line, - // it is 0. + // only slashes out of bonded stake are applied. without this line, it is 0. Staking::bond(Origin::signed(2), 20000, stake - 1, RewardDestination::default()).unwrap(); // Override exposure of 11 ErasStakers::::insert( @@ -2104,7 +2103,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { &[Perbill::from_percent(100)], ); - assert_eq!(Balances::total_balance(&11), stake); + assert_eq!(Balances::total_balance(&11), stake - 1); assert_eq!(Balances::total_balance(&2), 1); }) } @@ -4960,7 +4959,6 @@ fn proportional_ledger_slash_works() { unlocking: bounded_vec![], claimed_rewards: vec![], }; - assert_eq!(BondingDuration::get(), 3); // When we slash a ledger with no unlocking chunks @@ -4997,7 +4995,7 @@ fn proportional_ledger_slash_works() { ledger.total = 4 * 100; ledger.active = 0; // When the first 2 chunks don't overlap with the affected range of unlock eras. - assert_eq!(ledger.slash(140, 0, 2), 140); + assert_eq!(ledger.slash(140, 0, 3), 140); // Then assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]); assert_eq!(ledger.total, 4 * 100 - 140); @@ -5039,7 +5037,7 @@ fn proportional_ledger_slash_works() { ledger.active = 500; ledger.total = 40 + 10 + 100 + 250 + 500; // 900 assert_eq!(ledger.total, 900); - // When we have a higher min balance + // When we have a higher min balance assert_eq!( ledger.slash( 900 / 2, @@ -5047,16 +5045,17 @@ fn proportional_ledger_slash_works() { * get swept */ 0 ), - 475 + 450 ); - let dust = (10 / 2) + (40 / 2); assert_eq!(ledger.active, 500 / 2); - assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 250 / 2)]); - assert_eq!(ledger.total, 900 / 2 - dust); + // the last chunk was not slashed 50% like all the rest, because some other earlier chunks got + // dusted. + assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 150)]); + assert_eq!(ledger.total, 900 / 2); assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); assert_eq!( LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 250 / 2)]) + BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 150)]) ); // Given @@ -5068,7 +5067,7 @@ fn proportional_ledger_slash_works() { ledger.slash( 500 + 10 + 250 + 100 / 2, // active + era 6 + era 7 + era 5 / 2 0, - 2 /* slash era 2+4 first, so the affected parts are era 2+4, era 3+4 and + 3 /* slash era 6 first, so the affected parts are era 6, era 7 and * ledge.active. This will cause the affected to go to zero, and then we will * start slashing older chunks */ ), @@ -5091,7 +5090,7 @@ fn proportional_ledger_slash_works() { ledger.slash( 351, // active + era 6 + era 7 + era 5 / 2 + 1 50, // min balance - everything slashed below 50 will get dusted - 2 /* slash era 2+4 first, so the affected parts are era 2+4, era 3+4 and + 3 /* slash era 3+3 first, so the affected parts are era 6, era 7 and * ledge.active. This will cause the affected to go to zero, and then we will * start slashing older chunks */ ), @@ -5108,9 +5107,8 @@ fn proportional_ledger_slash_works() { // Given let slash = u64::MAX as Balance * 2; - let value = slash - - (9 * 4) // The value of the other parts of ledger that will get slashed - + 1; + // The value of the other parts of ledger that will get slashed + let value = slash - (10 * 4); ledger.active = 10; ledger.unlocking = bounded_vec![c(4, 10), c(5, 10), c(6, 10), c(7, value)]; From 9dad17f77b8a56ccf0d289ae410ee1e61d9b12a1 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Wed, 13 Jul 2022 13:41:20 +0100 Subject: [PATCH 0965/1472] Buy&Sell methods for Uniques (#11398) * Allow to set item's price * Clean the state when we transfer/burn an item or destroy a collection * Allow to buy an item * Remove redundant checks * Improve events * Cover with tests * Add comments * Apply suggestions * Fmt * Improvements for price validation * Improve validation * Update to use the new terminology * Remove multi-assets support * Chore * Weights + benchmarking * Shield against human error * Test when we pass the higher item's price * fmt fix * Chore * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Remove is_frozen check when setting the price * Try to fix benchmarking * Fix benchmarking * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Add transactional * Add 'allow deprecated' flag for transactional * Remove #[allow(deprecated)] * ".git/.scripts/bench-bot.sh" pallet dev pallet_uniques Co-authored-by: Parity Bot Co-authored-by: command-bot <> --- frame/uniques/src/benchmarking.rs | 36 ++++++ frame/uniques/src/functions.rs | 79 ++++++++++++- frame/uniques/src/lib.rs | 88 ++++++++++++++- frame/uniques/src/tests.rs | 178 +++++++++++++++++++++++++++++- frame/uniques/src/types.rs | 2 + frame/uniques/src/weights.rs | 174 +++++++++++++++++------------ 6 files changed, 485 insertions(+), 72 deletions(-) diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 14a3e2c61809a..713393048f7e9 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -408,5 +408,41 @@ benchmarks_instance_pallet! { }.into()); } + set_price { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + let delegate: T::AccountId = account("delegate", 0, SEED); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); + let price = ItemPrice::::from(100u32); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, Some(price), Some(delegate_lookup)) + verify { + assert_last_event::(Event::ItemPriceSet { + collection, + item, + price, + whitelisted_buyer: Some(delegate), + }.into()); + } + + buy_item { + let (collection, seller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + let buyer: T::AccountId = account("buyer", 0, SEED); + let buyer_lookup = T::Lookup::unlookup(buyer.clone()); + let price = ItemPrice::::from(0u32); + let origin = SystemOrigin::Signed(seller.clone()).into(); + Uniques::::set_price(origin, collection, item, Some(price.clone()), Some(buyer_lookup))?; + T::Currency::make_free_balance_be(&buyer, DepositBalanceOf::::max_value()); + }: _(SystemOrigin::Signed(buyer.clone()), collection, item, price.clone()) + verify { + assert_last_event::(Event::ItemBought { + collection, + item, + price, + seller, + buyer, + }.into()); + } + impl_benchmark_test_suite!(Uniques, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 155fb35ef0999..9e8d3301616df 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -18,7 +18,10 @@ //! Various pieces of common functionality. use super::*; -use frame_support::{ensure, traits::Get}; +use frame_support::{ + ensure, + traits::{ExistenceRequirement, Get}, +}; use sp_runtime::{DispatchError, DispatchResult}; impl, I: 'static> Pallet { @@ -46,6 +49,7 @@ impl, I: 'static> Pallet { let origin = details.owner; details.owner = dest; Item::::insert(&collection, &item, &details); + ItemPriceOf::::remove(&collection, &item); Self::deposit_event(Event::Transferred { collection, @@ -112,6 +116,8 @@ impl, I: 'static> Pallet { } #[allow(deprecated)] ItemMetadataOf::::remove_prefix(&collection, None); + #[allow(deprecated)] + ItemPriceOf::::remove_prefix(&collection, None); CollectionMetadataOf::::remove(&collection); #[allow(deprecated)] Attribute::::remove_prefix((&collection,), None); @@ -196,8 +202,79 @@ impl, I: 'static> Pallet { Item::::remove(&collection, &item); Account::::remove((&owner, &collection, &item)); + ItemPriceOf::::remove(&collection, &item); Self::deposit_event(Event::Burned { collection, item, owner }); Ok(()) } + + pub fn do_set_price( + collection: T::CollectionId, + item: T::ItemId, + sender: T::AccountId, + price: Option>, + whitelisted_buyer: Option, + ) -> DispatchResult { + let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(details.owner == sender, Error::::NoPermission); + + if let Some(ref price) = price { + ItemPriceOf::::insert( + &collection, + &item, + (price.clone(), whitelisted_buyer.clone()), + ); + Self::deposit_event(Event::ItemPriceSet { + collection, + item, + price: price.clone(), + whitelisted_buyer, + }); + } else { + ItemPriceOf::::remove(&collection, &item); + Self::deposit_event(Event::ItemPriceRemoved { collection, item }); + } + + Ok(()) + } + + pub fn do_buy_item( + collection: T::CollectionId, + item: T::ItemId, + buyer: T::AccountId, + bid_price: ItemPrice, + ) -> DispatchResult { + let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(details.owner != buyer, Error::::NoPermission); + + let price_info = + ItemPriceOf::::get(&collection, &item).ok_or(Error::::NotForSale)?; + + ensure!(bid_price >= price_info.0, Error::::BidTooLow); + + if let Some(only_buyer) = price_info.1 { + ensure!(only_buyer == buyer, Error::::NoPermission); + } + + T::Currency::transfer( + &buyer, + &details.owner, + price_info.0, + ExistenceRequirement::KeepAlive, + )?; + + let old_owner = details.owner.clone(); + + Self::do_transfer(collection, item, buyer.clone(), |_, _| Ok(()))?; + + Self::deposit_event(Event::ItemBought { + collection, + item, + price: price_info.0, + seller: old_owner, + buyer, + }); + + Ok(()) + } } diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 5c7adeac0eff2..53f83605da90e 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -24,6 +24,7 @@ //! * [`System`](../frame_system/index.html) //! * [`Support`](../frame_support/index.html) +#![recursion_limit = "256"] // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] @@ -42,8 +43,11 @@ pub mod migration; pub mod weights; use codec::{Decode, Encode}; -use frame_support::traits::{ - tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, ReservableCurrency, +use frame_support::{ + traits::{ + tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, ReservableCurrency, + }, + transactional, }; use frame_system::Config as SystemConfig; use sp_runtime::{ @@ -245,6 +249,18 @@ pub mod pallet { OptionQuery, >; + #[pallet::storage] + /// Price of an asset instance. + pub(super) type ItemPriceOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + (ItemPrice, Option), + OptionQuery, + >; + #[pallet::storage] /// Keeps track of the number of items a collection might have. pub(super) type CollectionMaxSupply, I: 'static = ()> = @@ -341,6 +357,23 @@ pub mod pallet { OwnershipAcceptanceChanged { who: T::AccountId, maybe_collection: Option }, /// Max supply has been set for a collection. CollectionMaxSupplySet { collection: T::CollectionId, max_supply: u32 }, + /// The price was set for the instance. + ItemPriceSet { + collection: T::CollectionId, + item: T::ItemId, + price: ItemPrice, + whitelisted_buyer: Option, + }, + /// The price for the instance was removed. + ItemPriceRemoved { collection: T::CollectionId, item: T::ItemId }, + /// An item was bought. + ItemBought { + collection: T::CollectionId, + item: T::ItemId, + price: ItemPrice, + seller: T::AccountId, + buyer: T::AccountId, + }, } #[pallet::error] @@ -375,6 +408,12 @@ pub mod pallet { MaxSupplyAlreadySet, /// The provided max supply is less to the amount of items a collection already has. MaxSupplyTooSmall, + /// The given item ID is unknown. + UnknownItem, + /// Item is not for sale. + NotForSale, + /// The provided bid is too low. + BidTooLow, } impl, I: 'static> Pallet { @@ -1408,5 +1447,50 @@ pub mod pallet { Self::deposit_event(Event::CollectionMaxSupplySet { collection, max_supply }); Ok(()) } + + /// Set (or reset) the price for an item. + /// + /// Origin must be Signed and must be the owner of the asset `item`. + /// + /// - `collection`: The collection of the item. + /// - `item`: The item to set the price for. + /// - `price`: The price for the item. Pass `None`, to reset the price. + /// - `buyer`: Restricts the buy operation to a specific account. + /// + /// Emits `ItemPriceSet` on success if the price is not `None`. + /// Emits `ItemPriceRemoved` on success if the price is `None`. + #[pallet::weight(T::WeightInfo::set_price())] + pub fn set_price( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + price: Option>, + whitelisted_buyer: Option<::Source>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let whitelisted_buyer = whitelisted_buyer.map(T::Lookup::lookup).transpose()?; + Self::do_set_price(collection, item, origin, price, whitelisted_buyer) + } + + /// Allows to buy an item if it's up for sale. + /// + /// Origin must be Signed and must not be the owner of the `item`. + /// + /// - `collection`: The collection of the item. + /// - `item`: The item the sender wants to buy. + /// - `bid_price`: The price the sender is willing to pay. + /// + /// Emits `ItemBought` on success. + #[pallet::weight(T::WeightInfo::buy_item())] + #[transactional] + pub fn buy_item( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + bid_price: ItemPrice, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_buy_item(collection, item, origin, bid_price) + } } } diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index ef28a2143e84a..8b1d00d7ba0c7 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for Uniques pallet. use crate::{mock::*, Event, *}; -use frame_support::{assert_noop, assert_ok, traits::Currency}; +use frame_support::{assert_noop, assert_ok, dispatch::Dispatchable, traits::Currency}; use pallet_balances::Error as BalancesError; use sp_std::prelude::*; @@ -694,3 +694,179 @@ fn max_supply_should_work() { assert!(!CollectionMaxSupply::::contains_key(collection_id)); }); } + +#[test] +fn set_price_should_work() { + new_test_ext().execute_with(|| { + let user_id = 1; + let collection_id = 0; + let item_1 = 1; + let item_2 = 2; + + assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true)); + + assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_1, user_id)); + assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_2, user_id)); + + assert_ok!(Uniques::set_price( + Origin::signed(user_id), + collection_id, + item_1, + Some(1), + None, + )); + + assert_ok!(Uniques::set_price( + Origin::signed(user_id), + collection_id, + item_2, + Some(2), + Some(3) + )); + + let item = ItemPriceOf::::get(collection_id, item_1).unwrap(); + assert_eq!(item.0, 1); + assert_eq!(item.1, None); + + let item = ItemPriceOf::::get(collection_id, item_2).unwrap(); + assert_eq!(item.0, 2); + assert_eq!(item.1, Some(3)); + + assert!(events().contains(&Event::::ItemPriceSet { + collection: collection_id, + item: item_1, + price: 1, + whitelisted_buyer: None, + })); + + // validate we can unset the price + assert_ok!(Uniques::set_price(Origin::signed(user_id), collection_id, item_2, None, None)); + assert!(events().contains(&Event::::ItemPriceRemoved { + collection: collection_id, + item: item_2 + })); + assert!(!ItemPriceOf::::contains_key(collection_id, item_2)); + }); +} + +#[test] +fn buy_item_should_work() { + new_test_ext().execute_with(|| { + let user_1 = 1; + let user_2 = 2; + let user_3 = 3; + let collection_id = 0; + let item_1 = 1; + let item_2 = 2; + let item_3 = 3; + let price_1 = 20; + let price_2 = 30; + let initial_balance = 100; + + Balances::make_free_balance_be(&user_1, initial_balance); + Balances::make_free_balance_be(&user_2, initial_balance); + Balances::make_free_balance_be(&user_3, initial_balance); + + assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_1, true)); + + assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_1, user_1)); + assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_2, user_1)); + assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_3, user_1)); + + assert_ok!(Uniques::set_price( + Origin::signed(user_1), + collection_id, + item_1, + Some(price_1), + None, + )); + + assert_ok!(Uniques::set_price( + Origin::signed(user_1), + collection_id, + item_2, + Some(price_2), + Some(user_3), + )); + + // can't buy for less + assert_noop!( + Uniques::buy_item(Origin::signed(user_2), collection_id, item_1, 1), + Error::::BidTooLow + ); + + // pass the higher price to validate it will still deduct correctly + assert_ok!(Uniques::buy_item(Origin::signed(user_2), collection_id, item_1, price_1 + 1,)); + + // validate the new owner & balances + let item = Item::::get(collection_id, item_1).unwrap(); + assert_eq!(item.owner, user_2); + assert_eq!(Balances::total_balance(&user_1), initial_balance + price_1); + assert_eq!(Balances::total_balance(&user_2), initial_balance - price_1); + + // can't buy from yourself + assert_noop!( + Uniques::buy_item(Origin::signed(user_1), collection_id, item_2, price_2), + Error::::NoPermission + ); + + // can't buy when the item is listed for a specific buyer + assert_noop!( + Uniques::buy_item(Origin::signed(user_2), collection_id, item_2, price_2), + Error::::NoPermission + ); + + // can buy when I'm a whitelisted buyer + assert_ok!(Uniques::buy_item(Origin::signed(user_3), collection_id, item_2, price_2,)); + + assert!(events().contains(&Event::::ItemBought { + collection: collection_id, + item: item_2, + price: price_2, + seller: user_1, + buyer: user_3, + })); + + // ensure we reset the buyer field + assert!(!ItemPriceOf::::contains_key(collection_id, item_2)); + + // can't buy when item is not for sale + assert_noop!( + Uniques::buy_item(Origin::signed(user_2), collection_id, item_3, price_2), + Error::::NotForSale + ); + + // ensure we can't buy an item when the collection or an item is frozen + { + assert_ok!(Uniques::set_price( + Origin::signed(user_1), + collection_id, + item_3, + Some(price_1), + None, + )); + + // freeze collection + assert_ok!(Uniques::freeze_collection(Origin::signed(user_1), collection_id)); + + let buy_item_call = mock::Call::Uniques(crate::Call::::buy_item { + collection: collection_id, + item: item_3, + bid_price: price_1, + }); + assert_noop!(buy_item_call.dispatch(Origin::signed(user_2)), Error::::Frozen); + + assert_ok!(Uniques::thaw_collection(Origin::signed(user_1), collection_id)); + + // freeze item + assert_ok!(Uniques::freeze(Origin::signed(user_1), collection_id, item_3)); + + let buy_item_call = mock::Call::Uniques(crate::Call::::buy_item { + collection: collection_id, + item: item_3, + bid_price: price_1, + }); + assert_noop!(buy_item_call.dispatch(Origin::signed(user_2)), Error::::Frozen); + } + }); +} diff --git a/frame/uniques/src/types.rs b/frame/uniques/src/types.rs index d7706fd7e3a58..98e056163d28d 100644 --- a/frame/uniques/src/types.rs +++ b/frame/uniques/src/types.rs @@ -30,6 +30,8 @@ pub(super) type CollectionDetailsFor = CollectionDetails<::AccountId, DepositBalanceOf>; pub(super) type ItemDetailsFor = ItemDetails<::AccountId, DepositBalanceOf>; +pub(super) type ItemPrice = + <>::Currency as Currency<::AccountId>>::Balance; #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct CollectionDetails { diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index d885077a8dee9..7c8cb170b1b1d 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,22 +18,22 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-06-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-07-13, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `test-bench-bot`, CPU: `Intel(R) Xeon(R) CPU @ 3.10GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_uniques // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 +// --pallet=pallet_uniques +// --chain=dev // --output=./frame/uniques/src/weights.rs // --template=./.maintain/frame-weight-template.hbs @@ -70,6 +70,8 @@ pub trait WeightInfo { fn cancel_approval() -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; + fn set_price() -> Weight; + fn buy_item() -> Weight; } /// Weights for pallet_uniques using the Substrate node and recommended hardware. @@ -78,14 +80,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (27_715_000 as Weight) + (33_075_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (16_929_000 as Weight) + (19_528_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -102,12 +104,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((10_481_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 16_000 - .saturating_add((1_762_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 16_000 - .saturating_add((1_590_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 25_000 + .saturating_add((13_639_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 25_000 + .saturating_add((2_393_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 25_000 + .saturating_add((2_217_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(4 as Weight)) @@ -120,33 +122,35 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (36_577_000 as Weight) + (42_146_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) + // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - (36_124_000 as Weight) + (42_960_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) + // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - (27_225_000 as Weight) + (33_025_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:100 w:100) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 14_000 - .saturating_add((12_407_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 24_000 + .saturating_add((15_540_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -155,26 +159,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (21_452_000 as Weight) + (25_194_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (22_155_000 as Weight) + (25_397_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (16_897_000 as Weight) + (19_278_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (16_657_000 as Weight) + (19_304_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -182,20 +186,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (25_057_000 as Weight) + (28_615_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (17_253_000 as Weight) + (19_943_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (20_010_000 as Weight) + (22_583_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -203,7 +207,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (41_159_000 as Weight) + (47_520_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -211,65 +215,81 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (39_598_000 as Weight) + (45_316_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (33_387_000 as Weight) + (38_391_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (33_208_000 as Weight) + (38_023_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (32_619_000 as Weight) + (37_398_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (31_028_000 as Weight) + (35_621_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (22_263_000 as Weight) + (25_856_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (22_910_000 as Weight) + (26_098_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (20_716_000 as Weight) + (24_076_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (19_380_000 as Weight) + (22_035_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Asset (r:1 w:0) + // Storage: Uniques ItemPriceOf (r:0 w:1) + fn set_price() -> Weight { + (22_534_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques ItemPriceOf (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Account (r:0 w:2) + fn buy_item() -> Weight { + (45_272_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } } // For backwards compatibility and tests @@ -277,14 +297,14 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (27_715_000 as Weight) + (33_075_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (16_929_000 as Weight) + (19_528_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -301,12 +321,12 @@ impl WeightInfo for () { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((10_481_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 16_000 - .saturating_add((1_762_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 16_000 - .saturating_add((1_590_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 25_000 + .saturating_add((13_639_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 25_000 + .saturating_add((2_393_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 25_000 + .saturating_add((2_217_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) @@ -319,33 +339,35 @@ impl WeightInfo for () { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (36_577_000 as Weight) + (42_146_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) + // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - (36_124_000 as Weight) + (42_960_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) + // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - (27_225_000 as Weight) + (33_025_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:100 w:100) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 14_000 - .saturating_add((12_407_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 24_000 + .saturating_add((15_540_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -354,26 +376,26 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (21_452_000 as Weight) + (25_194_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (22_155_000 as Weight) + (25_397_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (16_897_000 as Weight) + (19_278_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (16_657_000 as Weight) + (19_304_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -381,20 +403,20 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (25_057_000 as Weight) + (28_615_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (17_253_000 as Weight) + (19_943_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (20_010_000 as Weight) + (22_583_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -402,7 +424,7 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (41_159_000 as Weight) + (47_520_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -410,63 +432,79 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (39_598_000 as Weight) + (45_316_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (33_387_000 as Weight) + (38_391_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (33_208_000 as Weight) + (38_023_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (32_619_000 as Weight) + (37_398_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (31_028_000 as Weight) + (35_621_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (22_263_000 as Weight) + (25_856_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (22_910_000 as Weight) + (26_098_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (20_716_000 as Weight) + (24_076_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (19_380_000 as Weight) + (22_035_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Asset (r:1 w:0) + // Storage: Uniques ItemPriceOf (r:0 w:1) + fn set_price() -> Weight { + (22_534_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques ItemPriceOf (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Account (r:0 w:2) + fn buy_item() -> Weight { + (45_272_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } } From 367dab0d4bd7fd7b6c222dd15c753169c057dd42 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 13 Jul 2022 13:49:20 +0100 Subject: [PATCH 0966/1472] Revamp nomination pool reward scheme (#11669) * make pool roles optional * undo lock file changes? * add migration * add the ability for pools to chill themselves * boilerplate of tests * somewhat stable, but I think I found another bug as well * Fix it all * Add more more sophisticated test + capture one more bug. * Update frame/staking/src/lib.rs * reduce the diff a little bit * add some test for the slashing bug * cleanup * fix lock file? * Fix * fmt * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/mock.rs Co-authored-by: Oliver Tale-Yazdi * Fix build * fix some fishy tests.. * add one last integrity check for MinCreateBond * remove bad assertion -- needs to be dealt with later * nits * fix tests and add benchmarks for chill * remove stuff * fix benchmarks * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * remove defensive * first working version * bring back all tests * ALL new tests work now * cleanup * make sure benchmarks and all work * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * round of self-review, make arithmetic safe * fix warn * add migration code * Fix doc * add precision notes * make arithmetic fallible * fix node runtime * a lot of precision tests and notes and stuff * document MaxPOintsToBalance better * :round of self-review * fmt * fix some comments * Fix proportional slashing logic * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * track poinst in migration * fix * fmt * fix migration * remove event read * Apply suggestions from code review * Update frame/staking/src/lib.rs Co-authored-by: Shawn Tabrizi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Shawn Tabrizi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Shawn Tabrizi * update * fmt * fmt * add one last test * fmt Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi Co-authored-by: Parity Bot --- bin/node/runtime/src/lib.rs | 9 +- .../nomination-pools/benchmarking/src/mock.rs | 11 +- frame/nomination-pools/src/lib.rs | 582 +++--- frame/nomination-pools/src/migration.rs | 284 ++- frame/nomination-pools/src/mock.rs | 52 +- frame/nomination-pools/src/tests.rs | 1805 ++++++++++++----- frame/nomination-pools/src/weights.rs | 98 +- .../nomination-pools/test-staking/src/lib.rs | 5 +- .../nomination-pools/test-staking/src/mock.rs | 17 +- utils/frame/try-runtime/cli/src/lib.rs | 9 +- 10 files changed, 1950 insertions(+), 922 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 2d5981339fab3..b2efcb196787d 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -68,7 +68,7 @@ use sp_runtime::{ SaturatedConversion, StaticLookup, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedPointNumber, Perbill, Percent, Permill, Perquintill, + ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perbill, Percent, Permill, Perquintill, }; use sp_std::prelude::*; #[cfg(any(feature = "std", test))] @@ -730,7 +730,7 @@ impl pallet_bags_list::Config for Runtime { parameter_types! { pub const PostUnbondPoolsWindow: u32 = 4; pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/nopls"); - pub const MinPointsToBalance: u32 = 10; + pub const MaxPointsToBalance: u8 = 10; } use sp_runtime::traits::Convert; @@ -751,6 +751,8 @@ impl pallet_nomination_pools::Config for Runtime { type WeightInfo = (); type Event = Event; type Currency = Balances; + type CurrencyBalance = Balance; + type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; type StakingInterface = pallet_staking::Pallet; @@ -758,7 +760,7 @@ impl pallet_nomination_pools::Config for Runtime { type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; type PalletId = NominationPoolsPalletId; - type MinPointsToBalance = MinPointsToBalance; + type MaxPointsToBalance = MaxPointsToBalance; } parameter_types! { @@ -1675,6 +1677,7 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, + pallet_nomination_pools::migration::v2::MigrateToV2, >; /// MMR helper types. diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index eb884869f6d32..1c74c301e562d 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -17,7 +17,10 @@ use frame_election_provider_support::VoteWeight; use frame_support::{pallet_prelude::*, parameter_types, traits::ConstU64, PalletId}; -use sp_runtime::traits::{Convert, IdentityLookup}; +use sp_runtime::{ + traits::{Convert, IdentityLookup}, + FixedU128, +}; type AccountId = u128; type AccountIndex = u32; @@ -144,13 +147,15 @@ impl Convert for U256ToBalance { parameter_types! { pub static PostUnbondingPoolsWindow: u32 = 10; pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); - pub const MinPointsToBalance: u32 = 10; + pub const MaxPointsToBalance: u8 = 10; } impl pallet_nomination_pools::Config for Runtime { type Event = Event; type WeightInfo = (); type Currency = Balances; + type CurrencyBalance = Balance; + type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; type StakingInterface = Staking; @@ -158,7 +163,7 @@ impl pallet_nomination_pools::Config for Runtime { type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; type PalletId = PoolsPalletId; - type MinPointsToBalance = MinPointsToBalance; + type MaxPointsToBalance = MaxPointsToBalance; } impl crate::Config for Runtime {} diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index f7ccac3e35411..53e1c48a5e39e 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -17,8 +17,8 @@ //! # Nomination Pools for Staking Delegation //! -//! A pallet that allows members to delegate their stake to nominating pools. A nomination pool -//! acts as nominator and nominates validators on the members behalf. +//! A pallet that allows members to delegate their stake to nominating pools. A nomination pool acts +//! as nominator and nominates validators on the members behalf. //! //! # Index //! @@ -28,16 +28,27 @@ //! //! ## Key terms //! +//! * pool id: A unique identifier of each pool. Set to u12 //! * bonded pool: Tracks the distribution of actively staked funds. See [`BondedPool`] and -//! [`BondedPoolInner`]. Bonded pools are identified via the pools bonded account. +//! [`BondedPoolInner`]. //! * reward pool: Tracks rewards earned by actively staked funds. See [`RewardPool`] and -//! [`RewardPools`]. Reward pools are identified via the pools bonded account. +//! [`RewardPools`]. //! * unbonding sub pools: Collection of pools at different phases of the unbonding lifecycle. See -//! [`SubPools`] and [`SubPoolsStorage`]. Sub pools are identified via the pools bonded account. -//! * members: Accounts that are members of pools. See [`PoolMember`] and [`PoolMembers`]. Pool -//! members are identified via their account. -//! * point: A unit of measure for a members portion of a pool's funds. +//! [`SubPools`] and [`SubPoolsStorage`]. +//! * members: Accounts that are members of pools. See [`PoolMember`] and [`PoolMembers`]. +//! * roles: Administrative roles of each pool, capable of controlling nomination, and the state of +//! the pool. +//! * point: A unit of measure for a members portion of a pool's funds. Points initially have a +//! ratio of 1 (as set by `POINTS_TO_BALANCE_INIT_RATIO`) to balance, but as slashing happens, +//! this can change. //! * kick: The act of a pool administrator forcibly ejecting a member. +//! * bonded account: A key-less account id derived from the pool id that acts as the bonded +//! account. This account registers itself as a nominator in the staking system, and follows +//! exactly the same rules and conditions as a normal staker. Its bond increases or decreases as +//! members join, it can `nominate` or `chill`, and might not even earn staking rewards if it is +//! not nominating proper validators. +//! * reward account: A similar key-less account, that is set as the `Payee` account fo the bonded +//! account for all staking rewards. //! //! ## Usage //! @@ -55,11 +66,13 @@ //! //! In order to leave, a member must take two steps. //! -//! First, they must call [`Call::unbond`]. The unbond other extrinsic will start the -//! unbonding process by unbonding all of the members funds. +//! First, they must call [`Call::unbond`]. The unbond extrinsic will start the unbonding process by +//! unbonding all or a portion of the members funds. //! -//! Second, once [`sp_staking::StakingInterface::bonding_duration`] eras have passed, the member -//! can call [`Call::withdraw_unbonded`] to withdraw all their funds. +//! > A member can have up to [`Config::MaxUnbonding`] distinct active unbonding requests. +//! +//! Second, once [`sp_staking::StakingInterface::bonding_duration`] eras have passed, the member can +//! call [`Call::withdraw_unbonded`] to withdraw any funds that are free. //! //! For design docs see the [bonded pool](#bonded-pool) and [unbonding sub //! pools](#unbonding-sub-pools) sections. @@ -67,9 +80,13 @@ //! ### Slashes //! //! Slashes are distributed evenly across the bonded pool and the unbonding pools from slash era+1 -//! through the slash apply era. Thus, any member who either a) unbonded or b) was actively -//! bonded in the aforementioned range of eras will be affected by the slash. A member is slashed -//! pro-rata based on its stake relative to the total slash amount. +//! through the slash apply era. Thus, any member who either +//! +//! 1. unbonded, or +//! 2. was actively bonded +// +//! in the aforementioned range of eras will be affected by the slash. A member is slashed pro-rata +//! based on its stake relative to the total slash amount. //! //! For design docs see the [slashing](#slashing) section. //! @@ -82,7 +99,9 @@ //! To help facilitate pool administration the pool has one of three states (see [`PoolState`]): //! //! * Open: Anyone can join the pool and no members can be permissionlessly removed. -//! * Blocked: No members can join and some admin roles can kick members. +//! * Blocked: No members can join and some admin roles can kick members. Kicking is not instant, +//! and follows the same process of `unbond` and then `withdraw_unbonded`. In other words, +//! administrators can permissionlessly unbond other members. //! * Destroying: No members can join and all members can be permissionlessly removed with //! [`Call::unbond`] and [`Call::withdraw_unbonded`]. Once a pool is in destroying state, it //! cannot be reverted to another state. @@ -90,12 +109,23 @@ //! A pool has 4 administrative roles (see [`PoolRoles`]): //! //! * Depositor: creates the pool and is the initial member. They can only leave the pool once all -//! other members have left. Once they fully leave the pool is destroyed. +//! other members have left. Once they fully withdraw their funds, the pool is destroyed. //! * Nominator: can select which validators the pool nominates. //! * State-Toggler: can change the pools state and kick members if the pool is blocked. //! * Root: can change the nominator, state-toggler, or itself and can perform any of the actions //! the nominator or state-toggler can. //! +//! ### Dismantling +//! +//! As noted, a pool is destroyed once +//! +//! 1. First, all members need to fully unbond and withdraw. If the pool state is set to +//! `Destroying`, this can happen permissionlessly. +//! 2. The depositor itself fully unbonds and withdraws. Note that at this point, based on the +//! requirements of the staking system, the pool's bonded account's stake might not be able to ge +//! below a certain threshold as a nominator. At this point, the pool should `chill` itself to +//! allow the depositor to leave. +//! //! ## Design //! //! _Notes_: this section uses pseudo code to explain general design and does not necessarily @@ -108,8 +138,8 @@ //! members that where in the pool while it was backing a validator that got slashed. //! * Maximize scalability in terms of member count. //! -//! In order to maintain scalability, all operations are independent of the number of members. To -//! do this, delegation specific information is stored local to the member while the pool data +//! In order to maintain scalability, all operations are independent of the number of members. To do +//! this, delegation specific information is stored local to the member while the pool data //! structures have bounded datum. //! //! ### Bonded pool @@ -118,9 +148,9 @@ //! unbonding. The total points of a bonded pool are always equal to the sum of points of the //! delegation members. A bonded pool tracks its points and reads its bonded balance. //! -//! When a member joins a pool, `amount_transferred` is transferred from the members account -//! to the bonded pools account. Then the pool calls `staking::bond_extra(amount_transferred)` and -//! issues new points which are tracked by the member and added to the bonded pool's points. +//! When a member joins a pool, `amount_transferred` is transferred from the members account to the +//! bonded pools account. Then the pool calls `staking::bond_extra(amount_transferred)` and issues +//! new points which are tracked by the member and added to the bonded pool's points. //! //! When the pool already has some balance, we want the value of a point before the transfer to //! equal the value of a point after the transfer. So, when a member joins a bonded pool with a @@ -148,77 +178,13 @@ //! ### Reward pool //! //! When a pool is first bonded it sets up an deterministic, inaccessible account as its reward -//! destination. To track staking rewards we track how the balance of this reward account changes. -//! -//! The reward pool needs to store: -//! -//! * The pool balance at the time of the last payout: `reward_pool.balance` -//! * The total earnings ever at the time of the last payout: `reward_pool.total_earnings` -//! * The total points in the pool at the time of the last payout: `reward_pool.points` -//! -//! And the member needs to store: -//! -//! * The total payouts at the time of the last payout by that member: -//! `member.reward_pool_total_earnings` -//! -//! Before the first reward claim is initiated for a pool, all the above variables are set to zero. -//! -//! When a member initiates a claim, the following happens: -//! -//! 1) Compute the reward pool's total points and the member's virtual points in the reward pool -//! * First `current_total_earnings` is computed (`current_balance` is the free balance of the -//! reward pool at the beginning of these operations.) -//! ```text -//! current_total_earnings = -//! current_balance - reward_pool.balance + pool.total_earnings; -//! ``` -//! * Then the `current_points` is computed. Every balance unit that was added to the reward -//! pool since last time recorded means that the `pool.points` is increased by -//! `bonding_pool.total_points`. In other words, for every unit of balance that has been -//! earned by the reward pool, the reward pool points are inflated by `bonded_pool.points`. In -//! effect this allows each, single unit of balance (e.g. planck) to be divvied up pro-rata -//! among members based on points. -//! ```text -//! new_earnings = current_total_earnings - reward_pool.total_earnings; -//! current_points = reward_pool.points + bonding_pool.points * new_earnings; -//! ``` -//! * Finally, the`member_virtual_points` are computed: the product of the member's points in -//! the bonding pool and the total inflow of balance units since the last time the member -//! claimed rewards -//! ```text -//! new_earnings_since_last_claim = current_total_earnings - member.reward_pool_total_earnings; -//! member_virtual_points = member.points * new_earnings_since_last_claim; -//! ``` -//! 2) Compute the `member_payout`: -//! ```text -//! member_pool_point_ratio = member_virtual_points / current_points; -//! member_payout = current_balance * member_pool_point_ratio; -//! ``` -//! 3) Transfer `member_payout` to the member -//! 4) For the member set: -//! ```text -//! member.reward_pool_total_earnings = current_total_earnings; -//! ``` -//! 5) For the pool set: -//! ```text -//! reward_pool.points = current_points - member_virtual_points; -//! reward_pool.balance = current_balance - member_payout; -//! reward_pool.total_earnings = current_total_earnings; -//! ``` -//! -//! _Note_: One short coming of this design is that new joiners can claim rewards for the era after -//! they join even though their funds did not contribute to the pools vote weight. When a -//! member joins, it's `reward_pool_total_earnings` field is set equal to the `total_earnings` -//! of the reward pool at that point in time. At best the reward pool has the rewards up through the -//! previous era. If a member joins prior to the election snapshot it will benefit from the -//! rewards for the active era despite not contributing to the pool's vote weight. If it joins -//! after the election snapshot is taken it will benefit from the rewards of the next _2_ eras -//! because it's vote weight will not be counted until the election snapshot in active era + 1. -//! Related: -// _Note to maintainers_: In order to ensure the reward account never falls below the existential -// deposit, at creation the reward account must be endowed with the existential deposit. All logic -// for calculating rewards then does not see that existential deposit as part of the free balance. -// See `RewardPool::current_balance`. +//! destination. +//! +//! The reward pool is not really a pool anymore, as it does not track points anymore. Instead, it +//! tracks, a virtual value called `reward_counter`, among a few other values. +//! +//! See [this link](https://hackmd.io/PFGn6wI5TbCmBYoEA_f2Uw) for an in-depth explanation of the +//! reward pool mechanism. //! //! **Relevant extrinsics:** //! @@ -297,13 +263,8 @@ //! * PoolMembers cannot vote with their staked funds because they are transferred into the pools //! account. In the future this can be overcome by allowing the members to vote with their bonded //! funds via vote splitting. -//! * PoolMembers cannot quickly transfer to another pool if they do not like the nominations, -//! instead they must wait for the unbonding duration. -//! -//! # Runtime builder warnings -//! -//! * Watch out for overflow of [`RewardPoints`] and [`BalanceOf`] types. Consider things like the -//! chains total issuance, staking reward rate, and burn rate. +//! * PoolMembers cannot quickly transfer to another pool if they do no like nominations, instead +//! they must wait for the unbonding duration. #![cfg_attr(not(feature = "std"), no_std)] @@ -320,7 +281,10 @@ use frame_support::{ }; use scale_info::TypeInfo; use sp_core::U256; -use sp_runtime::traits::{AccountIdConversion, Bounded, CheckedSub, Convert, Saturating, Zero}; +use sp_runtime::{ + traits::{AccountIdConversion, Bounded, CheckedAdd, CheckedSub, Convert, Saturating, Zero}, + FixedPointNumber, FixedPointOperand, +}; use sp_staking::{EraIndex, OnStakerSlash, StakingInterface}; use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec}; @@ -352,8 +316,6 @@ pub use weights::WeightInfo; /// The balance type used by the currency system. pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -/// Type used to track the points of a reward pool. -pub type RewardPoints = U256; /// Type used for unique identifier of each pool. pub type PoolId = u32; @@ -407,26 +369,50 @@ pub struct PoolMember { /// The quantity of points this member has in the bonded pool or in a sub pool if /// `Self::unbonding_era` is some. pub points: BalanceOf, - /// The reward pools total earnings _ever_ the last time this member claimed a payout. - /// Assuming no massive burning events, we expect this value to always be below total issuance. - /// This value lines up with the [`RewardPool::total_earnings`] after a member claims a - /// payout. - pub reward_pool_total_earnings: BalanceOf, + /// The reward counter at the time of this member's last payout claim. + pub last_recorded_reward_counter: T::RewardCounter, /// The eras in which this member is unbonding, mapped from era index to the number of /// points scheduled to unbond in the given era. pub unbonding_eras: BoundedBTreeMap, T::MaxUnbonding>, } impl PoolMember { - fn total_points(&self) -> BalanceOf { - self.active_points().saturating_add(self.unbonding_points()) + /// The pending rewards of this member. + fn pending_rewards( + &self, + current_reward_counter: T::RewardCounter, + ) -> Result, Error> { + // accuracy note: Reward counters are `FixedU128` with base of 10^18. This value is being + // multiplied by a point. The worse case of a point is 10x the granularity of the balance + // (10x is the common configuration of `MaxPointsToBalance`). + // + // Assuming roughly the current issuance of polkadot (12,047,781,394,999,601,455, which is + // 1.2 * 10^9 * 10^10 = 1.2 * 10^19), the worse case point value is around 10^20. + // + // The final multiplication is: + // + // rc * 10^20 / 10^18 = rc * 100 + // + // meaning that as long as reward_counter's value is less than 1/100th of its max capacity + // (u128::MAX_VALUE), `checked_mul_int` won't saturate. + // + // given the nature of reward counter being 'pending_rewards / pool_total_point', the only + // (unrealistic) way that super high values can be achieved is for a pool to suddenly + // receive massive rewards with a very very small amount of stake. In all normal pools, as + // the points increase, so does the rewards. Moreover, as long as rewards are not + // accumulated for astronomically large durations, + // `current_reward_counter.defensive_saturating_sub(self.last_recorded_reward_counter)` + // won't be extremely big. + (current_reward_counter.defensive_saturating_sub(self.last_recorded_reward_counter)) + .checked_mul_int(self.active_points()) + .ok_or(Error::::OverflowRisk) } /// Active balance of the member. /// /// This is derived from the ratio of points in the pool to which the member belongs to. /// Might return different values based on the pool state for the same member and points. - pub(crate) fn active_balance(&self) -> BalanceOf { + fn active_balance(&self) -> BalanceOf { if let Some(pool) = BondedPool::::get(self.pool_id).defensive() { pool.points_to_balance(self.points) } else { @@ -434,13 +420,18 @@ impl PoolMember { } } + /// Total points of this member, both active and unbonding. + fn total_points(&self) -> BalanceOf { + self.active_points().saturating_add(self.unbonding_points()) + } + /// Active points of the member. - pub(crate) fn active_points(&self) -> BalanceOf { + fn active_points(&self) -> BalanceOf { self.points } /// Inactive points of the member, waiting to be withdrawn. - pub(crate) fn unbonding_points(&self) -> BalanceOf { + fn unbonding_points(&self) -> BalanceOf { self.unbonding_eras .as_ref() .iter() @@ -673,7 +664,7 @@ impl BondedPool { MaxPoolMembers::::get().map_or(true, |max| PoolMembers::::count() < max), Error::::MaxPoolMembers ); - self.member_counter = self.member_counter.defensive_saturating_add(1); + self.member_counter = self.member_counter.checked_add(1).ok_or(Error::::OverflowRisk)?; Ok(()) } @@ -750,19 +741,19 @@ impl BondedPool { // We checked for zero above .div(bonded_balance); - let min_points_to_balance = T::MinPointsToBalance::get(); + let max_points_to_balance = T::MaxPointsToBalance::get(); // Pool points can inflate relative to balance, but only if the pool is slashed. // If we cap the ratio of points:balance so one cannot join a pool that has been slashed - // by `min_points_to_balance`%, if not zero. + // by `max_points_to_balance`%, if not zero. ensure!( - points_to_balance_ratio_floor < min_points_to_balance.into(), + points_to_balance_ratio_floor < max_points_to_balance.into(), Error::::OverflowRisk ); - // while restricting the balance to `min_points_to_balance` of max total issuance, + // while restricting the balance to `max_points_to_balance` of max total issuance, let next_bonded_balance = bonded_balance.saturating_add(new_funds); ensure!( - next_bonded_balance < BalanceOf::::max_value().div(min_points_to_balance.into()), + next_bonded_balance < BalanceOf::::max_value().div(max_points_to_balance.into()), Error::::OverflowRisk ); @@ -904,16 +895,6 @@ impl BondedPool { Ok(points_issued) } - /// If `n` saturates at it's upper bound, mark the pool as destroying. This is useful when a - /// number saturating indicates the pool can no longer correctly keep track of state. - fn bound_check(&mut self, n: U256) -> U256 { - if n == U256::max_value() { - self.set_state(PoolState::Destroying) - } - - n - } - // Set the state of `self`, and deposit an event if the state changed. State should never be set // directly in in order to ensure a state change event is always correctly deposited. fn set_state(&mut self, state: PoolState) { @@ -928,45 +909,104 @@ impl BondedPool { } /// A reward pool. +/// +/// A reward pool is not so much a pool anymore, since it does not contain any shares or points. +/// Rather, simply to fit nicely next to bonded pool and unbonding pools in terms of terminology. In +/// reality, a reward pool is just a container for a few pool-dependent data related to the rewards. #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound)] -#[cfg_attr(feature = "std", derive(Clone, PartialEq))] +#[cfg_attr(feature = "std", derive(Clone, PartialEq, DefaultNoBound))] #[codec(mel_bound(T: Config))] #[scale_info(skip_type_params(T))] pub struct RewardPool { - /// The balance of this reward pool after the last claimed payout. - pub balance: BalanceOf, - /// The total earnings _ever_ of this reward pool after the last claimed payout. I.E. the sum - /// of all incoming balance through the pools life. + /// The last recorded value of the reward counter. /// - /// NOTE: We assume this will always be less than total issuance and thus can use the runtimes - /// `Balance` type. However in a chain with a burn rate higher than the rate this increases, - /// this type should be bigger than `Balance`. - pub total_earnings: BalanceOf, - /// The total points of this reward pool after the last claimed payout. - pub points: RewardPoints, + /// This is updated ONLY when the points in the bonded pool change, which means `join`, + /// `bond_extra` and `unbond`, all of which is done through `update_recorded`. + last_recorded_reward_counter: T::RewardCounter, + /// The last recorded total payouts of the reward pool. + /// + /// Payouts is essentially income of the pool. + /// + /// Update criteria is same as that of `last_recorded_reward_counter`. + last_recorded_total_payouts: BalanceOf, + /// Total amount that this pool has paid out so far to the members. + total_rewards_claimed: BalanceOf, } impl RewardPool { - /// Mutate the reward pool by updating the total earnings and current free balance. - fn update_total_earnings_and_balance(&mut self, id: PoolId) { - let current_balance = Self::current_balance(id); - // The earnings since the last time it was updated - let new_earnings = current_balance.saturating_sub(self.balance); - // The lifetime earnings of the of the reward pool - self.total_earnings = new_earnings.saturating_add(self.total_earnings); - self.balance = current_balance; - } - - /// Get a reward pool and update its total earnings and balance - fn get_and_update(id: PoolId) -> Option { - RewardPools::::get(id).map(|mut r| { - r.update_total_earnings_and_balance(id); - r - }) - } - - /// The current balance of the reward pool. Never access the reward pools free balance directly. - /// The existential deposit was not received as a reward, so the reward pool can not use it. + /// Getter for [`RewardPool::last_recorded_reward_counter`]. + fn last_recorded_reward_counter(&self) -> T::RewardCounter { + self.last_recorded_reward_counter + } + + /// Register some rewards that are claimed from the pool by the members. + fn register_claimed_reward(&mut self, reward: BalanceOf) { + self.total_rewards_claimed = self.total_rewards_claimed.saturating_add(reward); + } + + /// Update the recorded values of the pool. + fn update_records(&mut self, id: PoolId, bonded_points: BalanceOf) -> Result<(), Error> { + let balance = Self::current_balance(id); + self.last_recorded_reward_counter = self.current_reward_counter(id, bonded_points)?; + self.last_recorded_total_payouts = balance + .checked_add(&self.total_rewards_claimed) + .ok_or(Error::::OverflowRisk)?; + Ok(()) + } + + /// Get the current reward counter, based on the given `bonded_points` being the state of the + /// bonded pool at this time. + fn current_reward_counter( + &self, + id: PoolId, + bonded_points: BalanceOf, + ) -> Result> { + let balance = Self::current_balance(id); + let payouts_since_last_record = balance + .saturating_add(self.total_rewards_claimed) + .saturating_sub(self.last_recorded_total_payouts); + + // * accuracy notes regarding the multiplication in `checked_from_rational`: + // `payouts_since_last_record` is a subset of the total_issuance at the very + // worse. `bonded_points` are similarly, in a non-slashed pool, have the same granularity as + // balance, and are thus below within the range of total_issuance. In the worse case + // scenario, for `saturating_from_rational`, we have: + // + // dot_total_issuance * 10^18 / `minJoinBond` + // + // assuming `MinJoinBond == ED` + // + // dot_total_issuance * 10^18 / 10^10 = dot_total_issuance * 10^8 + // + // which, with the current numbers, is a miniscule fraction of the u128 capacity. + // + // Thus, adding two values of type reward counter should be safe for ages in a chain like + // Polkadot. The important note here is that `reward_pool.last_recorded_reward_counter` only + // ever accumulates, but its semantics imply that it is less than total_issuance, when + // represented as `FixedU128`, which means it is less than `total_issuance * 10^18`. + // + // * accuracy notes regarding `checked_from_rational` collapsing to zero, meaning that no + // reward can be claimed: + // + // largest `bonded_points`, such that the reward counter is non-zero, with `FixedU128` + // will be when the payout is being computed. This essentially means `payout/bonded_points` + // needs to be more than 1/1^18. Thus, assuming that `bonded_points` will always be less + // than `10 * dot_total_issuance`, if the reward_counter is the smallest possible value, + // the value of the reward being calculated is: + // + // x / 10^20 = 1/ 10^18 + // + // x = 100 + // + // which is basically 10^-8 DOTs. See `smallest_claimable_reward` for an example of this. + T::RewardCounter::checked_from_rational(payouts_since_last_record, bonded_points) + .and_then(|ref r| self.last_recorded_reward_counter.checked_add(r)) + .ok_or(Error::::OverflowRisk) + } + + /// Current free balance of the reward pool. + /// + /// This is sum of all the rewards that are claimable by pool members. fn current_balance(id: PoolId) -> BalanceOf { T::Currency::free_balance(&Pallet::::create_reward_account(id)) .saturating_sub(T::Currency::minimum_balance()) @@ -1098,9 +1138,10 @@ pub mod pallet { use super::*; use frame_support::traits::StorageVersion; use frame_system::{ensure_signed, pallet_prelude::*}; + use sp_runtime::traits::CheckedAdd; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] @@ -1116,19 +1157,53 @@ pub mod pallet { type WeightInfo: weights::WeightInfo; /// The nominating balance. - type Currency: Currency; + type Currency: Currency; + + /// Sadly needed to bound it to `FixedPointOperand`. + // The only alternative is to sprinkle a `where BalanceOf: FixedPointOperand` in roughly + // a million places, so we prefer doing this. + type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned + + codec::FullCodec + + MaybeSerializeDeserialize + + sp_std::fmt::Debug + + Default + + FixedPointOperand + + CheckedAdd + + TypeInfo + + MaxEncodedLen; + + /// The type that is used for reward counter. + /// + /// The arithmetic of the reward counter might saturate based on the size of the + /// `Currency::Balance`. If this happens, operations fails. Nonetheless, this type should be + /// chosen such that this failure almost never happens, as if it happens, the pool basically + /// needs to be dismantled (or all pools migrated to a larger `RewardCounter` type, which is + /// a PITA to do). + /// + /// See the inline code docs of `Member::pending_rewards` and `RewardPool::update_recorded` + /// for example analysis. A [`sp_runtime::FixedU128`] should be fine for chains with balance + /// types similar to that of Polkadot and Kusama, in the absence of severe slashing (or + /// prevented via a reasonable `MaxPointsToBalance`), for many many years to come. + type RewardCounter: FixedPointNumber + MaxEncodedLen + TypeInfo + Default + codec::FullCodec; /// The nomination pool's pallet id. #[pallet::constant] type PalletId: Get; - /// The minimum pool points-to-balance ratio that must be maintained for it to be `open`. + /// The maximum pool points-to-balance ratio that an `open` pool can have. + /// /// This is important in the event slashing takes place and the pool's points-to-balance /// ratio becomes disproportional. + /// + /// Moreover, this relates to the `RewardCounter` type as well, as the arithmetic operations + /// are a function of number of points, and by setting this value to e.g. 10, you ensure + /// that the total number of points in the system are at most 10 times the total_issuance of + /// the chain, in the absolute worse case. + /// /// For a value of 10, the threshold would be a pool points-to-balance ratio of 10:1. /// Such a scenario would also be the equivalent of the pool being 90% slashed. #[pallet::constant] - type MinPointsToBalance: Get; + type MaxPointsToBalance: Get; /// Infallible method for converting `Currency::Balance` to `U256`. type BalanceToU256: Convert, U256>; @@ -1427,10 +1502,10 @@ pub mod pallet { let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; bonded_pool.ok_to_join(amount)?; - // We just need its total earnings at this point in time, but we don't need to write it - // because we are not adjusting its points (all other values can calculated virtual). - let reward_pool = RewardPool::::get_and_update(pool_id) + let mut reward_pool = RewardPools::::get(pool_id) .defensive_ok_or::>(DefensiveError::RewardPoolNotFound.into())?; + // IMPORTANT: reward pool records must be updated with the old points. + reward_pool.update_records(pool_id, bonded_pool.points)?; bonded_pool.try_inc_members()?; let points_issued = bonded_pool.try_bond_funds(&who, amount, BondType::Later)?; @@ -1440,13 +1515,9 @@ pub mod pallet { PoolMember:: { pool_id, points: points_issued, - // At best the reward pool has the rewards up through the previous era. If the - // member joins prior to the snapshot they will benefit from the rewards of - // the active era despite not contributing to the pool's vote weight. If they - // join after the snapshot is taken they will benefit from the rewards of the - // next 2 eras because their vote weight will not be counted until the - // snapshot in active era + 1. - reward_pool_total_earnings: reward_pool.total_earnings, + // we just updated `last_known_reward_counter` to the current one in + // `update_recorded`. + last_recorded_reward_counter: reward_pool.last_recorded_reward_counter(), unbonding_eras: Default::default(), }, ); @@ -1457,7 +1528,9 @@ pub mod pallet { bonded: amount, joined: true, }); + bonded_pool.put(); + RewardPools::::insert(pool_id, reward_pool); Ok(()) } @@ -1466,6 +1539,8 @@ pub mod pallet { /// /// Additional funds can come from either the free balance of the account, of from the /// accumulated rewards, see [`BondExtra`]. + /// + /// Bonding extra funds implies an automatic payout of all pending rewards as well. // NOTE: this transaction is implemented with the sole purpose of readability and // correctness, not optimization. We read/write several storage items multiple times instead // of just once, in the spirit reusing code. @@ -1478,19 +1553,23 @@ pub mod pallet { let who = ensure_signed(origin)?; let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&who)?; + // payout related stuff: we must claim the payouts, and updated recorded payout data + // before updating the bonded pool points, similar to that of `join` transaction. + reward_pool.update_records(bonded_pool.id, bonded_pool.points)?; + // TODO: optimize this to not touch the free balance of `who ` at all in benchmarks. + // Currently, bonding rewards is like a batch. In the same PR, also make this function + // take a boolean argument that make it either 100% pure (no storage update), or make it + // also emit event and do the transfer. #11671 + let claimed = + Self::do_reward_payout(&who, &mut member, &mut bonded_pool, &mut reward_pool)?; + let (points_issued, bonded) = match extra { BondExtra::FreeBalance(amount) => (bonded_pool.try_bond_funds(&who, amount, BondType::Later)?, amount), - BondExtra::Rewards => { - let claimed = Self::do_reward_payout( - &who, - &mut member, - &mut bonded_pool, - &mut reward_pool, - )?; - (bonded_pool.try_bond_funds(&who, claimed, BondType::Later)?, claimed) - }, + BondExtra::Rewards => + (bonded_pool.try_bond_funds(&who, claimed, BondType::Later)?, claimed), }; + bonded_pool.ok_to_be_open(bonded)?; member.points = member.points.saturating_add(points_issued); @@ -1558,21 +1637,17 @@ pub mod pallet { member_account: T::AccountId, #[pallet::compact] unbonding_points: BalanceOf, ) -> DispatchResult { - let caller = ensure_signed(origin)?; + let who = ensure_signed(origin)?; let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&member_account)?; - bonded_pool.ok_to_unbond_with(&caller, &member_account, &member, unbonding_points)?; + bonded_pool.ok_to_unbond_with(&who, &member_account, &member, unbonding_points)?; // Claim the the payout prior to unbonding. Once the user is unbonding their points no // longer exist in the bonded pool and thus they can no longer claim their payouts. It // is not strictly necessary to claim the rewards, but we do it here for UX. - Self::do_reward_payout( - &member_account, - &mut member, - &mut bonded_pool, - &mut reward_pool, - )?; + let _ = reward_pool.update_records(bonded_pool.id, bonded_pool.points)?; + let _ = Self::do_reward_payout(&who, &mut member, &mut bonded_pool, &mut reward_pool)?; let current_era = T::StakingInterface::current_era(); let unbond_era = T::StakingInterface::bonding_duration().saturating_add(current_era); @@ -1846,23 +1921,25 @@ pub mod pallet { PoolMember:: { pool_id, points, - reward_pool_total_earnings: Zero::zero(), + last_recorded_reward_counter: Zero::zero(), unbonding_eras: Default::default(), }, ); RewardPools::::insert( pool_id, RewardPool:: { - balance: Zero::zero(), - points: U256::zero(), - total_earnings: Zero::zero(), + last_recorded_reward_counter: Zero::zero(), + last_recorded_total_payouts: Zero::zero(), + total_rewards_claimed: Zero::zero(), }, ); ReversePoolIdLookup::::insert(bonded_pool.bonded_account(), pool_id); + Self::deposit_event(Event::::Created { depositor: who.clone(), pool_id: pool_id.clone(), }); + Self::deposit_event(Event::::Bonded { member: who, pool_id, @@ -1896,8 +1973,14 @@ pub mod pallet { /// Set a new state for the pool. /// - /// The dispatch origin of this call must be signed by the state toggler, or the root role - /// of the pool. + /// If a pool is already in the `Destroying` state, then under no condition can its state + /// change again. + /// + /// The dispatch origin of this call must be either: + /// + /// 1. signed by the state toggler, or the root role of the pool, + /// 2. if the pool conditions to be open are NOT met (as described by `ok_to_be_open`), and + /// then the state of the pool can be permissionlessly changed to `Destroying`. #[pallet::weight(T::WeightInfo::set_state())] #[transactional] pub fn set_state( @@ -2065,14 +2148,9 @@ pub mod pallet { impl Hooks> for Pallet { fn integrity_test() { assert!( - T::MinPointsToBalance::get() > 0, + T::MaxPointsToBalance::get() > 0, "Minimum points to balance ratio must be greater than 0" ); - assert!( - sp_std::mem::size_of::() >= - 2 * sp_std::mem::size_of::>(), - "bit-length of the reward points must be at least twice as much as balance" - ); assert!( T::StakingInterface::bonding_duration() < TotalUnbondingPools::::get(), "There must be more unbonding pools then the bonding duration / @@ -2119,7 +2197,7 @@ impl Pallet { ExistenceRequirement::AllowDeath, ); - // TODO: this is purely defensive. + // NOTE: this is purely defensive. T::Currency::make_free_balance_be(&reward_account, Zero::zero()); T::Currency::make_free_balance_be(&bonded_pool.bonded_account(), Zero::zero()); @@ -2212,75 +2290,6 @@ impl Pallet { .div(current_points) } - /// Calculate the rewards for `member`. - /// - /// Returns the payout amount. - fn calculate_member_payout( - member: &mut PoolMember, - bonded_pool: &mut BondedPool, - reward_pool: &mut RewardPool, - ) -> Result, DispatchError> { - let u256 = |x| T::BalanceToU256::convert(x); - let balance = |x| T::U256ToBalance::convert(x); - - let last_total_earnings = reward_pool.total_earnings; - reward_pool.update_total_earnings_and_balance(bonded_pool.id); - - // Notice there is an edge case where total_earnings have not increased and this is zero - let new_earnings = u256(reward_pool.total_earnings.saturating_sub(last_total_earnings)); - - // The new points that will be added to the pool. For every unit of balance that has been - // earned by the reward pool, we inflate the reward pool points by `bonded_pool.points`. In - // effect this allows each, single unit of balance (e.g. plank) to be divvied up pro rata - // among members based on points. - let new_points = u256(bonded_pool.points).saturating_mul(new_earnings); - - // The points of the reward pool after taking into account the new earnings. Notice that - // this only stays even or increases over time except for when we subtract member virtual - // shares. - let current_points = bonded_pool.bound_check(reward_pool.points.saturating_add(new_points)); - - // The rewards pool's earnings since the last time this member claimed a payout. - let new_earnings_since_last_claim = - reward_pool.total_earnings.saturating_sub(member.reward_pool_total_earnings); - - // The points of the reward pool that belong to the member. - let member_virtual_points = - // The members portion of the reward pool - u256(member.active_points()) - // times the amount the pool has earned since the member last claimed. - .saturating_mul(u256(new_earnings_since_last_claim)); - - let member_payout = if member_virtual_points.is_zero() || - current_points.is_zero() || - reward_pool.balance.is_zero() - { - Zero::zero() - } else { - // Equivalent to `(member_virtual_points / current_points) * reward_pool.balance` - let numerator = { - let numerator = member_virtual_points.saturating_mul(u256(reward_pool.balance)); - bonded_pool.bound_check(numerator) - }; - balance( - numerator - // We check for zero above - .div(current_points), - ) - }; - - // Record updates - if reward_pool.total_earnings == BalanceOf::::max_value() { - bonded_pool.set_state(PoolState::Destroying); - }; - - member.reward_pool_total_earnings = reward_pool.total_earnings; - reward_pool.points = current_points.saturating_sub(member_virtual_points); - reward_pool.balance = reward_pool.balance.saturating_sub(member_payout); - - Ok(member_payout) - } - /// If the member has some rewards, transfer a payout from the reward pool to the member. // Emits events and potentially modifies pool state if any arithmetic saturates, but does // not persist any of the mutable inputs to storage. @@ -2291,38 +2300,37 @@ impl Pallet { reward_pool: &mut RewardPool, ) -> Result, DispatchError> { debug_assert_eq!(member.pool_id, bonded_pool.id); + // a member who has no skin in the game anymore cannot claim any rewards. ensure!(!member.active_points().is_zero(), Error::::FullyUnbonding); - let was_destroying = bonded_pool.is_destroying(); - let member_payout = Self::calculate_member_payout(member, bonded_pool, reward_pool)?; + let current_reward_counter = + reward_pool.current_reward_counter(bonded_pool.id, bonded_pool.points)?; + let pending_rewards = member.pending_rewards(current_reward_counter)?; - if member_payout.is_zero() { - return Ok(member_payout) + if pending_rewards.is_zero() { + return Ok(pending_rewards) } + // IFF the reward is non-zero alter the member and reward pool info. + member.last_recorded_reward_counter = current_reward_counter; + reward_pool.register_claimed_reward(pending_rewards); + // Transfer payout to the member. T::Currency::transfer( &bonded_pool.reward_account(), &member_account, - member_payout, + pending_rewards, ExistenceRequirement::AllowDeath, )?; Self::deposit_event(Event::::PaidOut { member: member_account.clone(), pool_id: member.pool_id, - payout: member_payout, + payout: pending_rewards, }); - if bonded_pool.is_destroying() && !was_destroying { - Self::deposit_event(Event::::StateChanged { - pool_id: member.pool_id, - new_state: PoolState::Destroying, - }); - } - - Ok(member_payout) + Ok(pending_rewards) } /// Ensure the correctness of the state of this pallet. diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index e23a35fe85602..f2abfe29dfbf7 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -16,11 +16,12 @@ // limitations under the License. use super::*; +use crate::log; +use frame_support::traits::OnRuntimeUpgrade; +use sp_std::collections::btree_map::BTreeMap; pub mod v1 { use super::*; - use crate::log; - use frame_support::traits::OnRuntimeUpgrade; #[derive(Decode)] pub struct OldPoolRoles { @@ -103,3 +104,282 @@ pub mod v1 { } } } + +pub mod v2 { + use super::*; + use sp_runtime::Perbill; + + #[test] + fn migration_assumption_is_correct() { + // this migrations cleans all the reward accounts to contain exactly ed, and all members + // having no claimable rewards. In this state, all fields of the `RewardPool` and + // `member.last_recorded_reward_counter` are all zero. + use crate::mock::*; + ExtBuilder::default().build_and_execute(|| { + let join = |x| { + Balances::make_free_balance_be(&x, Balances::minimum_balance() + 10); + frame_support::assert_ok!(Pools::join(Origin::signed(x), 10, 1)); + }; + + assert_eq!(BondedPool::::get(1).unwrap().points, 10); + assert_eq!( + RewardPools::::get(1).unwrap(), + RewardPool { ..Default::default() } + ); + assert_eq!( + PoolMembers::::get(10).unwrap().last_recorded_reward_counter, + Zero::zero() + ); + + join(20); + assert_eq!(BondedPool::::get(1).unwrap().points, 20); + assert_eq!( + RewardPools::::get(1).unwrap(), + RewardPool { ..Default::default() } + ); + assert_eq!( + PoolMembers::::get(10).unwrap().last_recorded_reward_counter, + Zero::zero() + ); + assert_eq!( + PoolMembers::::get(20).unwrap().last_recorded_reward_counter, + Zero::zero() + ); + + join(30); + assert_eq!(BondedPool::::get(1).unwrap().points, 30); + assert_eq!( + RewardPools::::get(1).unwrap(), + RewardPool { ..Default::default() } + ); + assert_eq!( + PoolMembers::::get(10).unwrap().last_recorded_reward_counter, + Zero::zero() + ); + assert_eq!( + PoolMembers::::get(20).unwrap().last_recorded_reward_counter, + Zero::zero() + ); + assert_eq!( + PoolMembers::::get(30).unwrap().last_recorded_reward_counter, + Zero::zero() + ); + }); + } + + #[derive(Decode)] + pub struct OldRewardPool { + pub balance: B, + pub total_earnings: B, + pub points: U256, + } + + #[derive(Decode)] + pub struct OldPoolMember { + pub pool_id: PoolId, + pub points: BalanceOf, + pub reward_pool_total_earnings: BalanceOf, + pub unbonding_eras: BoundedBTreeMap, T::MaxUnbonding>, + } + + /// Migrate the pool reward scheme to the new version, as per + /// . + pub struct MigrateToV2(sp_std::marker::PhantomData); + impl MigrateToV2 { + fn run(current: StorageVersion) -> Weight { + let mut reward_pools_translated = 0u64; + let mut members_translated = 0u64; + // just for logging. + let mut total_value_locked = BalanceOf::::zero(); + let mut total_points_locked = BalanceOf::::zero(); + + // store each member of the pool, with their active points. In the process, migrate + // their data as well. + let mut temp_members = BTreeMap::)>>::new(); + PoolMembers::::translate::, _>(|key, old_member| { + let id = old_member.pool_id; + temp_members.entry(id).or_default().push((key, old_member.points)); + + total_points_locked += old_member.points; + members_translated += 1; + Some(PoolMember:: { + last_recorded_reward_counter: Zero::zero(), + pool_id: old_member.pool_id, + points: old_member.points, + unbonding_eras: old_member.unbonding_eras, + }) + }); + + // translate all reward pools. In the process, do the last payout as well. + RewardPools::::translate::>, _>( + |id, _old_reward_pool| { + // each pool should have at least one member. + let members = match temp_members.get(&id) { + Some(x) => x, + None => { + log!(error, "pool {} has no member! deleting it..", id); + return None + }, + }; + let bonded_pool = match BondedPools::::get(id) { + Some(x) => x, + None => { + log!(error, "pool {} has no bonded pool! deleting it..", id); + return None + }, + }; + + let accumulated_reward = RewardPool::::current_balance(id); + let reward_account = Pallet::::create_reward_account(id); + let mut sum_paid_out = BalanceOf::::zero(); + + members + .into_iter() + .filter_map(|(who, points)| { + let bonded_pool = match BondedPool::::get(id) { + Some(x) => x, + None => { + log!(error, "pool {} for member {:?} does not exist!", id, who); + return None + }, + }; + + total_value_locked += bonded_pool.points_to_balance(points.clone()); + let portion = Perbill::from_rational(*points, bonded_pool.points); + let last_claim = portion * accumulated_reward; + + log!( + debug, + "{:?} has {:?} ({:?}) of pool {} with total reward of {:?}", + who, + portion, + last_claim, + id, + accumulated_reward + ); + + if last_claim.is_zero() { + None + } else { + Some((who, last_claim)) + } + }) + .for_each(|(who, last_claim)| { + let outcome = T::Currency::transfer( + &reward_account, + &who, + last_claim, + ExistenceRequirement::KeepAlive, + ); + + if let Err(reason) = outcome { + log!(warn, "last reward claim failed due to {:?}", reason,); + } else { + sum_paid_out = sum_paid_out.saturating_add(last_claim); + } + + Pallet::::deposit_event(Event::::PaidOut { + member: who.clone(), + pool_id: id, + payout: last_claim, + }); + }); + + // this can only be because of rounding down, or because the person we + // wanted to pay their reward to could not accept it (dust). + let leftover = accumulated_reward.saturating_sub(sum_paid_out); + if !leftover.is_zero() { + // pay it all to depositor. + let o = T::Currency::transfer( + &reward_account, + &bonded_pool.roles.depositor, + leftover, + ExistenceRequirement::KeepAlive, + ); + log!(warn, "paying {:?} leftover to the depositor: {:?}", leftover, o); + } + + // finally, migrate the reward pool. + reward_pools_translated += 1; + + Some(RewardPool { + last_recorded_reward_counter: Zero::zero(), + last_recorded_total_payouts: Zero::zero(), + total_rewards_claimed: Zero::zero(), + }) + }, + ); + + log!( + info, + "Upgraded {} members, {} reward pools, TVL {:?} TPL {:?}, storage to version {:?}", + members_translated, + reward_pools_translated, + total_value_locked, + total_points_locked, + current + ); + current.put::>(); + T::DbWeight::get().reads_writes(members_translated + 1, reward_pools_translated + 1) + } + } + + impl OnRuntimeUpgrade for MigrateToV2 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); + + log!( + info, + "Running migration with current storage version {:?} / onchain {:?}", + current, + onchain + ); + + if current == 2 && onchain == 1 { + Self::run(current) + } else { + log!(info, "MigrateToV2 did not executed. This probably should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + // all reward accounts must have more than ED. + RewardPools::::iter().for_each(|(id, _)| { + assert!( + T::Currency::free_balance(&Pallet::::create_reward_account(id)) >= + T::Currency::minimum_balance() + ) + }); + + Ok(()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + // new version must be set. + assert_eq!(Pallet::::on_chain_storage_version(), 2); + + // no reward or bonded pool has been skipped. + assert_eq!(RewardPools::::iter().count() as u32, RewardPools::::count()); + assert_eq!(BondedPools::::iter().count() as u32, BondedPools::::count()); + + // all reward pools must have exactly ED in them. This means no reward can be claimed, + // and that setting reward counters all over the board to zero will work henceforth. + RewardPools::::iter().for_each(|(id, _)| { + assert_eq!( + RewardPool::::current_balance(id), + Zero::zero(), + "reward pool({}) balance is {:?}", + id, + RewardPool::::current_balance(id) + ); + }); + + log!(info, "post upgrade hook for MigrateToV2 executed."); + Ok(()) + } + } +} diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 7d71efc3be04d..042a0b666efb1 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -2,9 +2,14 @@ use super::*; use crate::{self as pools}; use frame_support::{assert_ok, parameter_types, PalletId}; use frame_system::RawOrigin; +use sp_runtime::FixedU128; pub type AccountId = u128; pub type Balance = u128; +pub type RewardCounter = FixedU128; +// This sneaky little hack allows us to write code exactly as we would do in the pallet in the tests +// as well, e.g. `StorageItem::::get()`. +pub type T = Runtime; // Ext builder creates a pool with id 1. pub fn default_bonded_account() -> AccountId { @@ -23,6 +28,7 @@ parameter_types! { pub storage UnbondingBalanceMap: BTreeMap = Default::default(); #[derive(Clone, PartialEq)] pub static MaxUnbonding: u32 = 8; + pub static StakingMinBond: Balance = 10; pub storage Nominations: Option> = None; } @@ -40,7 +46,7 @@ impl sp_staking::StakingInterface for StakingMock { type AccountId = AccountId; fn minimum_bond() -> Self::Balance { - 10 + StakingMinBond::get() } fn current_era() -> EraIndex { @@ -184,6 +190,8 @@ impl pools::Config for Runtime { type Event = Event; type WeightInfo = (); type Currency = Balances; + type CurrencyBalance = Balance; + type RewardCounter = RewardCounter; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; type StakingInterface = StakingMock; @@ -191,7 +199,7 @@ impl pools::Config for Runtime { type PalletId = PoolsPalletId; type MaxMetadataLen = MaxMetadataLen; type MaxUnbonding = MaxUnbonding; - type MinPointsToBalance = frame_support::traits::ConstU32<10>; + type MaxPointsToBalance = frame_support::traits::ConstU8<10>; } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -208,9 +216,16 @@ frame_support::construct_runtime!( } ); -#[derive(Default)] pub struct ExtBuilder { members: Vec<(AccountId, Balance)>, + max_members: Option, + max_members_per_pool: Option, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { members: Default::default(), max_members: Some(4), max_members_per_pool: Some(3) } + } } impl ExtBuilder { @@ -225,11 +240,26 @@ impl ExtBuilder { self } + pub(crate) fn min_bond(self, min: Balance) -> Self { + StakingMinBond::set(min); + self + } + pub(crate) fn with_check(self, level: u8) -> Self { CheckLevel::set(level); self } + pub(crate) fn max_members(mut self, max: Option) -> Self { + self.max_members = max; + self + } + + pub(crate) fn max_members_per_pool(mut self, max: Option) -> Self { + self.max_members_per_pool = max; + self + } + pub(crate) fn build(self) -> sp_io::TestExternalities { let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); @@ -238,8 +268,8 @@ impl ExtBuilder { min_join_bond: 2, min_create_bond: 2, max_pools: Some(2), - max_members_per_pool: Some(3), - max_members: Some(4), + max_members_per_pool: self.max_members_per_pool, + max_members: self.max_members, } .assimilate_storage(&mut storage); @@ -281,8 +311,8 @@ pub(crate) fn unsafe_set_state(pool_id: PoolId, state: PoolState) -> Result<(), } parameter_types! { - static PoolsEvents: usize = 0; - static BalancesEvents: usize = 0; + storage PoolsEvents: u32 = 0; + storage BalancesEvents: u32 = 0; } /// All events of this pallet. @@ -293,8 +323,8 @@ pub(crate) fn pool_events_since_last_call() -> Vec> { .filter_map(|e| if let Event::Pools(inner) = e { Some(inner) } else { None }) .collect::>(); let already_seen = PoolsEvents::get(); - PoolsEvents::set(events.len()); - events.into_iter().skip(already_seen).collect() + PoolsEvents::set(&(events.len() as u32)); + events.into_iter().skip(already_seen as usize).collect() } /// All events of the `Balances` pallet. @@ -305,8 +335,8 @@ pub(crate) fn balances_events_since_last_call() -> Vec>(); let already_seen = BalancesEvents::get(); - BalancesEvents::set(events.len()); - events.into_iter().skip(already_seen).collect() + BalancesEvents::set(&(events.len() as u32)); + events.into_iter().skip(already_seen as usize).collect() } /// Same as `fully_unbond`, in permissioned setting. diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 97104423c5910..9989893d86462 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -17,10 +17,7 @@ use super::*; use crate::{mock::*, Event}; -use frame_support::{ - assert_err, assert_noop, assert_ok, assert_storage_noop, bounded_btree_map, - storage::{with_transaction, TransactionOutcome}, -}; +use frame_support::{assert_err, assert_noop, assert_ok, assert_storage_noop, bounded_btree_map}; use pallet_balances::Event as BEvent; use sp_runtime::traits::Dispatchable; @@ -66,7 +63,11 @@ fn test_setup_works() { ); assert_eq!( RewardPools::::get(last_pool).unwrap(), - RewardPool:: { balance: 0, points: 0u32.into(), total_earnings: 0 } + RewardPool:: { + last_recorded_reward_counter: Zero::zero(), + last_recorded_total_payouts: 0, + total_rewards_claimed: 0 + } ); assert_eq!( PoolMembers::::get(10).unwrap(), @@ -206,34 +207,34 @@ mod bonded_pool { }, }; - let min_points_to_balance: u128 = - <::MinPointsToBalance as Get>::get().into(); + let max_points_to_balance: u128 = + <::MaxPointsToBalance as Get>::get().into(); // Simulate a 100% slashed pool StakingMock::set_bonded_balance(pool.bonded_account(), 0); assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); - // Simulate a slashed pool at `MinPointsToBalance` + 1 slashed pool + // Simulate a slashed pool at `MaxPointsToBalance` + 1 slashed pool StakingMock::set_bonded_balance( pool.bonded_account(), - min_points_to_balance.saturating_add(1).into(), + max_points_to_balance.saturating_add(1).into(), ); assert_ok!(pool.ok_to_join(0)); - // Simulate a slashed pool at `MinPointsToBalance` - StakingMock::set_bonded_balance(pool.bonded_account(), min_points_to_balance); + // Simulate a slashed pool at `MaxPointsToBalance` + StakingMock::set_bonded_balance(pool.bonded_account(), max_points_to_balance); assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); StakingMock::set_bonded_balance( pool.bonded_account(), - Balance::MAX / min_points_to_balance, + Balance::MAX / max_points_to_balance, ); // New bonded balance would be over threshold of Balance type assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); // and a sanity check StakingMock::set_bonded_balance( pool.bonded_account(), - Balance::MAX / min_points_to_balance - 1, + Balance::MAX / max_points_to_balance - 1, ); assert_ok!(pool.ok_to_join(0)); }); @@ -515,44 +516,37 @@ mod join { .put(); // and reward pool - RewardPools::::insert( - 123, - RewardPool:: { - balance: Zero::zero(), - total_earnings: Zero::zero(), - points: U256::from(0u32), - }, - ); + RewardPools::::insert(123, RewardPool:: { ..Default::default() }); - // Force the points:balance ratio to `MinPointsToBalance` (100/10) - let min_points_to_balance: u128 = - <::MinPointsToBalance as Get>::get().into(); + // Force the points:balance ratio to `MaxPointsToBalance` (100/10) + let max_points_to_balance: u128 = + <::MaxPointsToBalance as Get>::get().into(); StakingMock::set_bonded_balance( Pools::create_bonded_account(123), - min_points_to_balance, + max_points_to_balance, ); assert_noop!(Pools::join(Origin::signed(11), 420, 123), Error::::OverflowRisk); StakingMock::set_bonded_balance( Pools::create_bonded_account(123), - Balance::MAX / min_points_to_balance, + Balance::MAX / max_points_to_balance, ); - // Balance needs to be gt Balance::MAX / `MinPointsToBalance` + // Balance needs to be gt Balance::MAX / `MaxPointsToBalance` assert_noop!(Pools::join(Origin::signed(11), 5, 123), Error::::OverflowRisk); - StakingMock::set_bonded_balance(Pools::create_bonded_account(1), min_points_to_balance); + StakingMock::set_bonded_balance(Pools::create_bonded_account(1), max_points_to_balance); // Cannot join a pool that isn't open unsafe_set_state(123, PoolState::Blocked).unwrap(); assert_noop!( - Pools::join(Origin::signed(11), min_points_to_balance, 123), + Pools::join(Origin::signed(11), max_points_to_balance, 123), Error::::NotOpen ); unsafe_set_state(123, PoolState::Destroying).unwrap(); assert_noop!( - Pools::join(Origin::signed(11), min_points_to_balance, 123), + Pools::join(Origin::signed(11), max_points_to_balance, 123), Error::::NotOpen ); @@ -649,17 +643,34 @@ mod join { mod claim_payout { use super::*; - fn del(points: Balance, reward_pool_total_earnings: Balance) -> PoolMember { + fn del(points: Balance, last_recorded_reward_counter: u128) -> PoolMember { PoolMember { pool_id: 1, points, - reward_pool_total_earnings, + last_recorded_reward_counter: last_recorded_reward_counter.into(), unbonding_eras: Default::default(), } } - fn rew(balance: Balance, points: u32, total_earnings: Balance) -> RewardPool { - RewardPool { balance, points: points.into(), total_earnings } + fn del_float(points: Balance, last_recorded_reward_counter: f64) -> PoolMember { + PoolMember { + pool_id: 1, + points, + last_recorded_reward_counter: RewardCounter::from_float(last_recorded_reward_counter), + unbonding_eras: Default::default(), + } + } + + fn rew( + last_recorded_reward_counter: u128, + last_recorded_total_payouts: Balance, + total_rewards_claimed: Balance, + ) -> RewardPool { + RewardPool { + last_recorded_reward_counter: last_recorded_reward_counter.into(), + last_recorded_total_payouts, + total_rewards_claimed, + } } #[test] @@ -672,8 +683,12 @@ mod claim_payout { Balances::make_free_balance_be(&40, 0); Balances::make_free_balance_be(&50, 0); let ed = Balances::minimum_balance(); + // and the reward pool has earned 100 in rewards - Balances::make_free_balance_be(&default_reward_account(), ed + 100); + assert_eq!(Balances::free_balance(default_reward_account()), ed); + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + + let _ = pool_events_since_last_call(); // When assert_ok!(Pools::claim_payout(Origin::signed(10))); @@ -681,22 +696,13 @@ mod claim_payout { // Then assert_eq!( pool_events_since_last_call(), - vec![ - Event::Created { depositor: 10, pool_id: 1 }, - Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, - Event::Bonded { member: 50, pool_id: 1, bonded: 50, joined: true }, - Event::PaidOut { member: 10, pool_id: 1, payout: 10 }, - ] - ); - - // Expect a payout of 10: (10 del virtual points / 100 pool points) * 100 pool - // balance - assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 100)); - assert_eq!( - RewardPools::::get(&1).unwrap(), - rew(90, 100 * 100 - 100 * 10, 100) + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 10 },] ); + // last recorded reward counter at the time of this member's payout is 1 + assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 1)); + // pool's 'last_recorded_reward_counter' and 'last_recorded_total_payouts' don't + // really change unless if someone bonds/unbonds. + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 10)); assert_eq!(Balances::free_balance(&10), 10); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 90); @@ -708,13 +714,8 @@ mod claim_payout { pool_events_since_last_call(), vec![Event::PaidOut { member: 40, pool_id: 1, payout: 40 }] ); - - // Expect payout 40: (400 del virtual points / 900 pool points) * 90 pool balance - assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 100)); - assert_eq!( - RewardPools::::get(&1).unwrap(), - rew(50, 9_000 - 100 * 40, 100) - ); + assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 1)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 50)); assert_eq!(Balances::free_balance(&40), 40); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 50); @@ -726,15 +727,13 @@ mod claim_payout { pool_events_since_last_call(), vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] ); - - // Expect payout 50: (50 del virtual points / 50 pool points) * 50 pool balance - assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 100)); + assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 1)); assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 100)); assert_eq!(Balances::free_balance(&50), 50); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 0); // Given the reward pool has some new rewards - Balances::make_free_balance_be(&default_reward_account(), ed + 50); + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); // When assert_ok!(Pools::claim_payout(Origin::signed(10))); @@ -744,10 +743,8 @@ mod claim_payout { pool_events_since_last_call(), vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] ); - - // Expect payout 5: (500 del virtual points / 5,000 pool points) * 50 pool balance - assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 150)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(45, 5_000 - 50 * 10, 150)); + assert_eq!(PoolMembers::::get(10).unwrap(), del_float(10, 1.5)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 105)); assert_eq!(Balances::free_balance(&10), 10 + 5); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 45); @@ -759,11 +756,8 @@ mod claim_payout { pool_events_since_last_call(), vec![Event::PaidOut { member: 40, pool_id: 1, payout: 20 }] ); - - // Expect payout 20: (2,000 del virtual points / 4,500 pool points) * 45 pool - // balance - assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 150)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(25, 4_500 - 50 * 40, 150)); + assert_eq!(PoolMembers::::get(40).unwrap(), del_float(40, 1.5)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 125)); assert_eq!(Balances::free_balance(&40), 40 + 20); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); @@ -779,22 +773,8 @@ mod claim_payout { pool_events_since_last_call(), vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] ); - - // We expect a payout of 50: (5,000 del virtual points / 7,5000 pool points) * 75 - // pool balance - assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 200)); - assert_eq!( - RewardPools::::get(&1).unwrap(), - rew( - 25, - // old pool points + points from new earnings - del points. - // - // points from new earnings = new earnings(50) * bonded_pool.points(100) - // del points = member.points(50) * new_earnings_since_last_claim (100) - (2_500 + 50 * 100) - 50 * 100, - 200, - ) - ); + assert_eq!(PoolMembers::::get(50).unwrap(), del_float(50, 2.0)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 175)); assert_eq!(Balances::free_balance(&50), 50 + 50); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); @@ -806,10 +786,8 @@ mod claim_payout { pool_events_since_last_call(), vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] ); - - // We expect a payout of 5 - assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 200)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(20, 2_500 - 10 * 50, 200)); + assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 2)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 180)); assert_eq!(Balances::free_balance(&10), 15 + 5); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 20); @@ -827,19 +805,8 @@ mod claim_payout { ); // We expect a payout of 40 - assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 600)); - assert_eq!( - RewardPools::::get(&1).unwrap(), - rew( - 380, - // old pool points + points from new earnings - del points - // - // points from new earnings = new earnings(400) * bonded_pool.points(100) - // del points = member.points(10) * new_earnings_since_last_claim(400) - (2_000 + 400 * 100) - 10 * 400, - 600 - ) - ); + assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 6)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 220)); assert_eq!(Balances::free_balance(&10), 20 + 40); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 380); @@ -855,14 +822,8 @@ mod claim_payout { pool_events_since_last_call(), vec![Event::PaidOut { member: 10, pool_id: 1, payout: 2 }] ); - - // Expect a payout of 2: (200 del virtual points / 38,000 pool points) * 400 pool - // balance - assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 620)); - assert_eq!( - RewardPools::::get(&1).unwrap(), - rew(398, (38_000 + 20 * 100) - 10 * 20, 620) - ); + assert_eq!(PoolMembers::::get(10).unwrap(), del_float(10, 6.2)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 222)); assert_eq!(Balances::free_balance(&10), 60 + 2); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 398); @@ -874,14 +835,8 @@ mod claim_payout { pool_events_since_last_call(), vec![Event::PaidOut { member: 40, pool_id: 1, payout: 188 }] ); - - // Expect a payout of 188: (18,800 del virtual points / 39,800 pool points) * 399 - // pool balance - assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 620)); - assert_eq!( - RewardPools::::get(&1).unwrap(), - rew(210, 39_800 - 40 * 470, 620) - ); + assert_eq!(PoolMembers::::get(40).unwrap(), del_float(40, 6.2)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 410)); assert_eq!(Balances::free_balance(&40), 60 + 188); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 210); @@ -893,88 +848,20 @@ mod claim_payout { pool_events_since_last_call(), vec![Event::PaidOut { member: 50, pool_id: 1, payout: 210 }] ); - - // Expect payout of 210: (21,000 / 21,000) * 210 - assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 620)); - assert_eq!( - RewardPools::::get(&1).unwrap(), - rew(0, 21_000 - 50 * 420, 620) - ); + assert_eq!(PoolMembers::::get(50).unwrap(), del_float(50, 6.2)); + assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 620)); assert_eq!(Balances::free_balance(&50), 100 + 210); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 0); }); } - #[test] - fn do_reward_payout_correctly_sets_pool_state_to_destroying() { - ExtBuilder::default().build_and_execute(|| { - let _ = with_transaction(|| -> TransactionOutcome { - let mut bonded_pool = BondedPool::::get(1).unwrap(); - let mut reward_pool = RewardPools::::get(1).unwrap(); - let mut member = PoolMembers::::get(10).unwrap(); - - // -- reward_pool.total_earnings saturates - - // Given - Balances::make_free_balance_be(&default_reward_account(), Balance::MAX); - - // When - assert_ok!(Pools::do_reward_payout( - &10, - &mut member, - &mut bonded_pool, - &mut reward_pool - )); - - // Then - assert!(bonded_pool.is_destroying()); - - storage::TransactionOutcome::Rollback(Ok(())) - }); - - // -- current_points saturates (reward_pool.points + new_earnings * bonded_pool.points) - let _ = with_transaction(|| -> TransactionOutcome { - // Given - let mut bonded_pool = BondedPool::::get(1).unwrap(); - let mut reward_pool = RewardPools::::get(1).unwrap(); - let mut member = PoolMembers::::get(10).unwrap(); - // Force new_earnings * bonded_pool.points == 100 - Balances::make_free_balance_be(&default_reward_account(), 5 + 10); - assert_eq!(bonded_pool.points, 10); - // Force reward_pool.points == U256::MAX - new_earnings * bonded_pool.points - reward_pool.points = U256::MAX - U256::from(100u32); - RewardPools::::insert(1, reward_pool.clone()); - - // When - assert_ok!(Pools::do_reward_payout( - &10, - &mut member, - &mut bonded_pool, - &mut reward_pool - )); - - // Then - assert!(bonded_pool.is_destroying()); - - storage::TransactionOutcome::Rollback(Ok(())) - }); - }); - } - #[test] fn reward_payout_errors_if_a_member_is_fully_unbonding() { ExtBuilder::default().add_members(vec![(11, 11)]).build_and_execute(|| { // fully unbond the member. - assert_ok!(Pools::fully_unbond(Origin::signed(11), 11)); + assert_ok!(fully_unbond_permissioned(11)); - let mut bonded_pool = BondedPool::::get(1).unwrap(); - let mut reward_pool = RewardPools::::get(1).unwrap(); - let mut member = PoolMembers::::get(11).unwrap(); - - assert_noop!( - Pools::do_reward_payout(&11, &mut member, &mut bonded_pool, &mut reward_pool,), - Error::::FullyUnbonding - ); + assert_noop!(Pools::claim_payout(Origin::signed(11)), Error::::FullyUnbonding); assert_eq!( pool_events_since_last_call(), @@ -989,80 +876,87 @@ mod claim_payout { } #[test] - fn calculate_member_payout_works_with_a_pool_of_1() { - let del = |reward_pool_total_earnings| del(10, reward_pool_total_earnings); + fn do_reward_payout_works_with_a_pool_of_1() { + let del = |last_recorded_reward_counter| del_float(10, last_recorded_reward_counter); ExtBuilder::default().build_and_execute(|| { - let mut bonded_pool = BondedPool::::get(1).unwrap(); - let mut reward_pool = RewardPools::::get(1).unwrap(); - let mut member = PoolMembers::::get(10).unwrap(); + let (mut member, mut bonded_pool, mut reward_pool) = + Pools::get_member_with_pools(&10).unwrap(); let ed = Balances::minimum_balance(); - // Given no rewards have been earned - // When let payout = - Pools::calculate_member_payout(&mut member, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&10, &mut member, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then assert_eq!(payout, 0); - assert_eq!(member, del(0)); + assert_eq!(member, del(0.0)); assert_eq!(reward_pool, rew(0, 0, 0)); // Given the pool has earned some rewards for the first time - Balances::make_free_balance_be(&default_reward_account(), ed + 5); + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 5)); // When let payout = - Pools::calculate_member_payout(&mut member, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&10, &mut member, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 5); // (10 * 5 del virtual points / 10 * 5 pool points) * 5 pool balance + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 5 } + ] + ); + assert_eq!(payout, 5); assert_eq!(reward_pool, rew(0, 0, 5)); - assert_eq!(member, del(5)); + assert_eq!(member, del(0.5)); // Given the pool has earned rewards again - Balances::make_free_balance_be(&default_reward_account(), ed + 10); + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10)); // When let payout = - Pools::calculate_member_payout(&mut member, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&10, &mut member, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 10); // (10 * 10 del virtual points / 10 pool points) * 5 pool balance + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 10 }] + ); + assert_eq!(payout, 10); assert_eq!(reward_pool, rew(0, 0, 15)); - assert_eq!(member, del(15)); + assert_eq!(member, del(1.5)); // Given the pool has earned no new rewards Balances::make_free_balance_be(&default_reward_account(), ed + 0); // When let payout = - Pools::calculate_member_payout(&mut member, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&10, &mut member, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then + assert_eq!(pool_events_since_last_call(), vec![]); assert_eq!(payout, 0); assert_eq!(reward_pool, rew(0, 0, 15)); - assert_eq!(member, del(15)); + assert_eq!(member, del(1.5)); }); } #[test] - fn calculate_member_payout_works_with_a_pool_of_3() { + fn do_reward_payout_works_with_a_pool_of_3() { ExtBuilder::default() .add_members(vec![(40, 40), (50, 50)]) .build_and_execute(|| { let mut bonded_pool = BondedPool::::get(1).unwrap(); let mut reward_pool = RewardPools::::get(1).unwrap(); - let ed = Balances::minimum_balance(); - // PoolMember with 10 points + let mut del_10 = PoolMembers::::get(10).unwrap(); - // PoolMember with 40 points let mut del_40 = PoolMembers::::get(40).unwrap(); - // PoolMember with 50 points let mut del_50 = PoolMembers::::get(50).unwrap(); assert_eq!( @@ -1078,479 +972,970 @@ mod claim_payout { // Given we have a total of 100 points split among the members assert_eq!(del_50.points + del_40.points + del_10.points, 100); assert_eq!(bonded_pool.points, 100); + // and the reward pool has earned 100 in rewards - Balances::make_free_balance_be(&default_reward_account(), ed + 100); + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); // When let payout = - Pools::calculate_member_payout(&mut del_10, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&10, &mut del_10, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 10); // (10 del virtual points / 100 pool points) * 100 pool balance - assert_eq!(del_10, del(10, 100)); - assert_eq!(reward_pool, rew(90, 100 * 100 - 100 * 10, 100)); - // Mock the reward pool transferring the payout to del_10 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 10)); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 10 }] + ); + assert_eq!(payout, 10); + assert_eq!(del_10, del(10, 1)); + assert_eq!(reward_pool, rew(0, 0, 10)); // When let payout = - Pools::calculate_member_payout(&mut del_40, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&40, &mut del_40, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 40); // (400 del virtual points / 900 pool points) * 90 pool balance - assert_eq!(del_40, del(40, 100)); assert_eq!( - reward_pool, - rew( - 50, - // old pool points - member virtual points - 9_000 - 100 * 40, - 100 - ) + pool_events_since_last_call(), + vec![Event::PaidOut { member: 40, pool_id: 1, payout: 40 }] ); - // Mock the reward pool transferring the payout to del_40 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 40)); + assert_eq!(payout, 40); + assert_eq!(del_40, del(40, 1)); + assert_eq!(reward_pool, rew(0, 0, 50)); // When let payout = - Pools::calculate_member_payout(&mut del_50, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&50, &mut del_50, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 50); // (50 del virtual points / 50 pool points) * 50 pool balance - assert_eq!(del_50, del(50, 100)); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] + ); + assert_eq!(payout, 50); + assert_eq!(del_50, del(50, 1)); assert_eq!(reward_pool, rew(0, 0, 100)); - // Mock the reward pool transferring the payout to del_50 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 50)); // Given the reward pool has some new rewards - Balances::make_free_balance_be(&default_reward_account(), ed + 50); + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); // When let payout = - Pools::calculate_member_payout(&mut del_10, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&10, &mut del_10, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 5); // (500 del virtual points / 5,000 pool points) * 50 pool balance - assert_eq!(del_10, del(10, 150)); - assert_eq!(reward_pool, rew(45, 5_000 - 50 * 10, 150)); - // Mock the reward pool transferring the payout to del_10 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 5)); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] + ); + assert_eq!(payout, 5); + assert_eq!(del_10, del_float(10, 1.5)); + assert_eq!(reward_pool, rew(0, 0, 105)); // When let payout = - Pools::calculate_member_payout(&mut del_40, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&40, &mut del_40, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 20); // (2,000 del virtual points / 4,500 pool points) * 45 pool balance - assert_eq!(del_40, del(40, 150)); - assert_eq!(reward_pool, rew(25, 4_500 - 50 * 40, 150)); - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 20)); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 40, pool_id: 1, payout: 20 }] + ); + assert_eq!(payout, 20); + assert_eq!(del_40, del_float(40, 1.5)); + assert_eq!(reward_pool, rew(0, 0, 125)); // Given del_50 hasn't claimed and the reward pools has just earned 50 assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 75); // When let payout = - Pools::calculate_member_payout(&mut del_50, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&50, &mut del_50, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 50); // (5,000 del virtual points / 7,5000 pool points) * 75 pool balance - assert_eq!(del_50, del(50, 200)); - assert_eq!( - reward_pool, - rew( - 25, - // old pool points + points from new earnings - del points. - // - // points from new earnings = new earnings(50) * bonded_pool.points(100) - // del points = member.points(50) * new_earnings_since_last_claim (100) - (2_500 + 50 * 100) - 50 * 100, - 200, - ) - ); - // Mock the reward pool transferring the payout to del_50 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 50)); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] + ); + assert_eq!(payout, 50); + assert_eq!(del_50, del_float(50, 2.0)); + assert_eq!(reward_pool, rew(0, 0, 175)); // When let payout = - Pools::calculate_member_payout(&mut del_10, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&10, &mut del_10, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] + ); assert_eq!(payout, 5); - assert_eq!(del_10, del(10, 200)); - assert_eq!(reward_pool, rew(20, 2_500 - 10 * 50, 200)); - // Mock the reward pool transferring the payout to del_10 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 5)); + assert_eq!(del_10, del_float(10, 2.0)); + assert_eq!(reward_pool, rew(0, 0, 180)); // Given del_40 hasn't claimed and the reward pool has just earned 400 assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 400)); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 420); // When let payout = - Pools::calculate_member_payout(&mut del_10, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&10, &mut del_10, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 40 }] + ); assert_eq!(payout, 40); - assert_eq!(del_10, del(10, 600)); - assert_eq!( - reward_pool, - rew( - 380, - // old pool points + points from new earnings - del points - // - // points from new earnings = new earnings(400) * bonded_pool.points(100) - // del points = member.points(10) * new_earnings_since_last_claim(400) - (2_000 + 400 * 100) - 10 * 400, - 600 - ) - ); - // Mock the reward pool transferring the payout to del_10 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 40)); + assert_eq!(del_10, del_float(10, 6.0)); + assert_eq!(reward_pool, rew(0, 0, 220)); // Given del_40 + del_50 haven't claimed and the reward pool has earned 20 assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 20)); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 400); // When let payout = - Pools::calculate_member_payout(&mut del_10, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&10, &mut del_10, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 2); // (200 del virtual points / 38,000 pool points) * 400 pool balance - assert_eq!(del_10, del(10, 620)); - assert_eq!(reward_pool, rew(398, (38_000 + 20 * 100) - 10 * 20, 620)); - // Mock the reward pool transferring the payout to del_10 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 2)); + assert_eq!(payout, 2); + assert_eq!(del_10, del_float(10, 6.2)); + assert_eq!(reward_pool, rew(0, 0, 222)); // When let payout = - Pools::calculate_member_payout(&mut del_40, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&40, &mut del_40, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 188); // (18,800 del virtual points / 39,800 pool points) * 399 pool balance - assert_eq!(del_40, del(40, 620)); - assert_eq!(reward_pool, rew(210, 39_800 - 40 * 470, 620)); - // Mock the reward pool transferring the payout to del_10 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= 188)); + assert_eq!(payout, 188); // 20 (from the 50) + 160 (from the 400) + 8 (from the 20) + assert_eq!(del_40, del_float(40, 6.2)); + assert_eq!(reward_pool, rew(0, 0, 410)); // When let payout = - Pools::calculate_member_payout(&mut del_50, &mut bonded_pool, &mut reward_pool) + Pools::do_reward_payout(&50, &mut del_50, &mut bonded_pool, &mut reward_pool) .unwrap(); // Then - assert_eq!(payout, 210); // (21,000 / 21,000) * 210 - assert_eq!(del_50, del(50, 620)); - assert_eq!(reward_pool, rew(0, 21_000 - 50 * 420, 620)); + assert_eq!(payout, 210); // 200 (from the 400) + 10 (from the 20) + assert_eq!(del_50, del_float(50, 6.2)); + assert_eq!(reward_pool, rew(0, 0, 620)); }); } #[test] - fn do_reward_payout_works() { - ExtBuilder::default() - .add_members(vec![(40, 40), (50, 50)]) - .build_and_execute(|| { - let mut bonded_pool = BondedPool::::get(1).unwrap(); - let mut reward_pool = RewardPools::::get(1).unwrap(); - let ed = Balances::minimum_balance(); + fn rewards_distribution_is_fair_basic() { + ExtBuilder::default().build_and_execute(|| { + // reward pool by 10. + Balances::mutate_account(&default_reward_account(), |f| f.free += 10).unwrap(); - assert_eq!( - pool_events_since_last_call(), - vec![ - Event::Created { depositor: 10, pool_id: 1 }, - Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, - Event::Bonded { member: 50, pool_id: 1, bonded: 50, joined: true } - ] - ); + // 20 joins afterwards. + Balances::make_free_balance_be(&20, Balances::minimum_balance() + 10); + assert_ok!(Pools::join(Origin::signed(20), 10, 1)); - // Given the bonded pool has 100 points - assert_eq!(bonded_pool.points, 100); - // Each member currently has a free balance of - Balances::make_free_balance_be(&10, 0); - Balances::make_free_balance_be(&40, 0); - Balances::make_free_balance_be(&50, 0); - // and the reward pool has earned 100 in rewards - Balances::make_free_balance_be(&default_reward_account(), ed + 100); + // reward by another 20 + Balances::mutate_account(&default_reward_account(), |f| f.free += 20).unwrap(); - let mut del_10 = PoolMembers::get(10).unwrap(); - let mut del_40 = PoolMembers::get(40).unwrap(); - let mut del_50 = PoolMembers::get(50).unwrap(); + // 10 should claim 10 + 10, 20 should claim 20 / 2. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 20 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 10 }, + ] + ); - // When - assert_ok!(Pools::do_reward_payout( - &10, - &mut del_10, - &mut bonded_pool, - &mut reward_pool - )); + // any upcoming rewards are shared equally. + Balances::mutate_account(&default_reward_account(), |f| f.free += 20).unwrap(); - // Then - assert_eq!( - pool_events_since_last_call(), - vec![Event::PaidOut { member: 10, pool_id: 1, payout: 10 }] - ); + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); - // Expect a payout of 10: (10 del virtual points / 100 pool points) * 100 pool - // balance - assert_eq!(del_10, del(10, 100)); - assert_eq!(reward_pool, rew(90, 100 * 100 - 100 * 10, 100)); - assert_eq!(Balances::free_balance(&10), 10); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 90); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 10 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 10 }, + ] + ); + }); + } - // When - assert_ok!(Pools::do_reward_payout( - &40, - &mut del_40, - &mut bonded_pool, - &mut reward_pool - )); + #[test] + fn rewards_distribution_is_fair_basic_with_fractions() { + // basically checks the case where the amount of rewards is less than the pool shares. for + // this, we have to rely on fixed point arithmetic. + ExtBuilder::default().build_and_execute(|| { + Balances::mutate_account(&default_reward_account(), |f| f.free += 3).unwrap(); - // Then - assert_eq!( - pool_events_since_last_call(), - vec![Event::PaidOut { member: 40, pool_id: 1, payout: 40 }] - ); + Balances::make_free_balance_be(&20, Balances::minimum_balance() + 10); + assert_ok!(Pools::join(Origin::signed(20), 10, 1)); - // Expect payout 40: (400 del virtual points / 900 pool points) * 90 pool balance - assert_eq!(del_40, del(40, 100)); - assert_eq!(reward_pool, rew(50, 9_000 - 100 * 40, 100)); - assert_eq!(Balances::free_balance(&40), 40); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 50); + Balances::mutate_account(&default_reward_account(), |f| f.free += 6).unwrap(); - // When - assert_ok!(Pools::do_reward_payout( - &50, - &mut del_50, - &mut bonded_pool, - &mut reward_pool - )); + // 10 should claim 3, 20 should claim 3 + 3. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); - // Then - assert_eq!( - pool_events_since_last_call(), - vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] - ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 3 + 3 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 3 }, + ] + ); - // Expect payout 50: (50 del virtual points / 50 pool points) * 50 pool balance - assert_eq!(del_50, del(50, 100)); - assert_eq!(reward_pool, rew(0, 0, 100)); - assert_eq!(Balances::free_balance(&50), 50); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 0); + // any upcoming rewards are shared equally. + Balances::mutate_account(&default_reward_account(), |f| f.free += 8).unwrap(); - // Given the reward pool has some new rewards - Balances::make_free_balance_be(&default_reward_account(), ed + 50); + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); - // When - assert_ok!(Pools::do_reward_payout( - &10, - &mut del_10, - &mut bonded_pool, - &mut reward_pool - )); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 4 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 4 }, + ] + ); - // Then - assert_eq!( - pool_events_since_last_call(), - vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] - ); + // uneven upcoming rewards are shared equally, rounded down. + Balances::mutate_account(&default_reward_account(), |f| f.free += 7).unwrap(); - // Expect payout 5: (500 del virtual points / 5,000 pool points) * 50 pool balance - assert_eq!(del_10, del(10, 150)); - assert_eq!(reward_pool, rew(45, 5_000 - 50 * 10, 150)); - assert_eq!(Balances::free_balance(&10), 10 + 5); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 45); + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); - // When - assert_ok!(Pools::do_reward_payout( - &40, - &mut del_40, - &mut bonded_pool, - &mut reward_pool - )); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 3 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 3 }, + ] + ); + }); + } - // Then - assert_eq!( - pool_events_since_last_call(), - vec![Event::PaidOut { member: 40, pool_id: 1, payout: 20 }] - ); + #[test] + fn rewards_distribution_is_fair_3() { + ExtBuilder::default().build_and_execute(|| { + let ed = Balances::minimum_balance(); - // Expect payout 20: (2,000 del virtual points / 4,500 pool points) * 45 pool - // balance - assert_eq!(del_40, del(40, 150)); - assert_eq!(reward_pool, rew(25, 4_500 - 50 * 40, 150)); - assert_eq!(Balances::free_balance(&40), 40 + 20); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); + Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); - // Given del 50 hasn't claimed and the reward pools has just earned 50 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 75); + Balances::make_free_balance_be(&20, ed + 10); + assert_ok!(Pools::join(Origin::signed(20), 10, 1)); - // When - assert_ok!(Pools::do_reward_payout( - &50, - &mut del_50, - &mut bonded_pool, - &mut reward_pool - )); + Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); - // Then + Balances::make_free_balance_be(&30, ed + 10); + assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + + Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); + + // 10 should claim 10, 20 should claim nothing. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(Origin::signed(30))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 30, pool_id: 1, bonded: 10, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 30 + 100 / 2 + 60 / 3 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 100 / 2 + 60 / 3 }, + Event::PaidOut { member: 30, pool_id: 1, payout: 60 / 3 }, + ] + ); + + // any upcoming rewards are shared equally. + Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(Origin::signed(30))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 10 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 10 }, + Event::PaidOut { member: 30, pool_id: 1, payout: 10 }, + ] + ); + }); + } + + #[test] + fn rewards_distribution_is_fair_bond_extra() { + ExtBuilder::default().build_and_execute(|| { + let ed = Balances::minimum_balance(); + + Balances::make_free_balance_be(&20, ed + 20); + assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + Balances::make_free_balance_be(&30, ed + 20); + assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + + Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); + + // everyone claims. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(Origin::signed(30))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + Event::Bonded { member: 30, pool_id: 1, bonded: 10, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 10 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 20 }, + Event::PaidOut { member: 30, pool_id: 1, payout: 10 } + ] + ); + + // 30 now bumps itself to be like 20. + assert_ok!(Pools::bond_extra(Origin::signed(30), BondExtra::FreeBalance(10))); + + // more rewards come in. + Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); + + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(Origin::signed(30))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Bonded { member: 30, pool_id: 1, bonded: 10, joined: false }, + Event::PaidOut { member: 10, pool_id: 1, payout: 20 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 40 }, + Event::PaidOut { member: 30, pool_id: 1, payout: 40 } + ] + ); + }); + } + + #[test] + fn rewards_distribution_is_fair_unbond() { + ExtBuilder::default().build_and_execute(|| { + let ed = Balances::minimum_balance(); + + Balances::make_free_balance_be(&20, ed + 20); + assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + + Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + + // everyone claims. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 10 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 20 } + ] + ); + + // 20 unbonds to be equal to 10 (10 points each). + assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + + // more rewards come in. + Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); + + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10 }, + Event::PaidOut { member: 10, pool_id: 1, payout: 50 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 50 }, + ] + ); + }); + } + + #[test] + fn unclaimed_reward_is_safe() { + ExtBuilder::default().build_and_execute(|| { + let ed = Balances::minimum_balance(); + + Balances::make_free_balance_be(&20, ed + 20); + assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + Balances::make_free_balance_be(&30, ed + 20); + assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + + // 10 gets 10, 20 gets 20, 30 gets 10 + Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); + + // some claim. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + Event::Bonded { member: 30, pool_id: 1, bonded: 10, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 10 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 20 } + ] + ); + + // 10 gets 20, 20 gets 40, 30 gets 20 + Balances::mutate_account(&default_reward_account(), |f| f.free += 80).unwrap(); + + // some claim. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 20 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 40 } + ] + ); + + // 10 gets 20, 20 gets 40, 30 gets 20 + Balances::mutate_account(&default_reward_account(), |f| f.free += 80).unwrap(); + + // some claim. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 20 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 40 } + ] + ); + + // now 30 claims all at once + assert_ok!(Pools::claim_payout(Origin::signed(30))); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 30, pool_id: 1, payout: 10 + 20 + 20 }] + ); + }); + } + + #[test] + fn bond_extra_and_delayed_claim() { + ExtBuilder::default().build_and_execute(|| { + let ed = Balances::minimum_balance(); + + Balances::make_free_balance_be(&20, ed + 200); + assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + + // 10 gets 10, 20 gets 20, 30 gets 10 + Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + + // some claim. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 10 } + ] + ); + + // 20 has not claimed yet, more reward comes + Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); + + // and 20 bonds more -- they should not have more share of this reward. + assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::FreeBalance(10))); + + // everyone claim. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + // 20 + 40, which means the extra amount they bonded did not impact us. + Event::PaidOut { member: 20, pool_id: 1, payout: 60 }, + Event::Bonded { member: 20, pool_id: 1, bonded: 10, joined: false }, + Event::PaidOut { member: 10, pool_id: 1, payout: 20 } + ] + ); + + // but in the next round of rewards, the extra10 they bonded has an impact. + Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); + + // everyone claim. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 15 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 45 } + ] + ); + }); + } + + #[test] + fn create_sets_recorded_data() { + ExtBuilder::default().build_and_execute(|| { + MaxPools::::set(None); + // pool 10 has already been created. + let (member_10, _, reward_pool_10) = Pools::get_member_with_pools(&10).unwrap(); + + assert_eq!(reward_pool_10.last_recorded_total_payouts, 0); + assert_eq!(reward_pool_10.total_rewards_claimed, 0); + assert_eq!(reward_pool_10.last_recorded_reward_counter, 0.into()); + + assert_eq!(member_10.last_recorded_reward_counter, 0.into()); + + // transfer some reward to pool 1. + Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); + + // create pool 2 + Balances::make_free_balance_be(&20, 100); + assert_ok!(Pools::create(Origin::signed(20), 10, 20, 20, 20)); + + // has no impact -- initial + let (member_20, _, reward_pool_20) = Pools::get_member_with_pools(&20).unwrap(); + + assert_eq!(reward_pool_20.last_recorded_total_payouts, 0); + assert_eq!(reward_pool_20.total_rewards_claimed, 0); + assert_eq!(reward_pool_20.last_recorded_reward_counter, 0.into()); + + assert_eq!(member_20.last_recorded_reward_counter, 0.into()); + + // pre-fund the reward account of pool id 3 with some funds. + Balances::make_free_balance_be(&Pools::create_reward_account(3), 10); + + // create pool 3 + Balances::make_free_balance_be(&30, 100); + assert_ok!(Pools::create(Origin::signed(30), 10, 30, 30, 30)); + + // reward counter is still the same. + let (member_30, _, reward_pool_30) = Pools::get_member_with_pools(&30).unwrap(); + assert_eq!( + Balances::free_balance(&Pools::create_reward_account(3)), + 10 + Balances::minimum_balance() + ); + + assert_eq!(reward_pool_30.last_recorded_total_payouts, 0); + assert_eq!(reward_pool_30.total_rewards_claimed, 0); + assert_eq!(reward_pool_30.last_recorded_reward_counter, 0.into()); + + assert_eq!(member_30.last_recorded_reward_counter, 0.into()); + + // and 30 can claim the reward now. + assert_ok!(Pools::claim_payout(Origin::signed(30))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Created { depositor: 20, pool_id: 2 }, + Event::Bonded { member: 20, pool_id: 2, bonded: 10, joined: true }, + Event::Created { depositor: 30, pool_id: 3 }, + Event::Bonded { member: 30, pool_id: 3, bonded: 10, joined: true }, + Event::PaidOut { member: 30, pool_id: 3, payout: 10 } + ] + ); + }) + } + + #[test] + fn join_updates_recorded_data() { + ExtBuilder::default().build_and_execute(|| { + MaxPoolMembers::::set(None); + MaxPoolMembersPerPool::::set(None); + let join = |x, y| { + Balances::make_free_balance_be(&x, y + Balances::minimum_balance()); + assert_ok!(Pools::join(Origin::signed(x), y, 1)); + }; + + { + let (member_10, _, reward_pool_10) = Pools::get_member_with_pools(&10).unwrap(); + + assert_eq!(reward_pool_10.last_recorded_total_payouts, 0); + assert_eq!(reward_pool_10.total_rewards_claimed, 0); + assert_eq!(reward_pool_10.last_recorded_reward_counter, 0.into()); + + assert_eq!(member_10.last_recorded_reward_counter, 0.into()); + } + + // someone joins without any rewards being issued. + { + join(20, 10); + let (member, _, reward_pool) = Pools::get_member_with_pools(&20).unwrap(); + // reward counter is 0 both before.. + assert_eq!(member.last_recorded_reward_counter, 0.into()); + assert_eq!(reward_pool.last_recorded_total_payouts, 0); + assert_eq!(reward_pool.last_recorded_reward_counter, 0.into()); + } + + // transfer some reward to pool 1. + Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); + + { + join(30, 10); + let (member, _, reward_pool) = Pools::get_member_with_pools(&30).unwrap(); + assert_eq!(reward_pool.last_recorded_total_payouts, 60); + // explanation: we have a total of 20 points so far (excluding the 10 that just got + // bonded), and 60 unclaimed rewards. each share is then roughly worth of 3 units of + // rewards, thus reward counter is 3. member's reward counter is the same + assert_eq!(member.last_recorded_reward_counter, 3.into()); + assert_eq!(reward_pool.last_recorded_reward_counter, 3.into()); + } + + // someone else joins + { + join(40, 10); + let (member, _, reward_pool) = Pools::get_member_with_pools(&40).unwrap(); + // reward counter does not change since no rewards have came in. + assert_eq!(member.last_recorded_reward_counter, 3.into()); + assert_eq!(reward_pool.last_recorded_reward_counter, 3.into()); + assert_eq!(reward_pool.last_recorded_total_payouts, 60); + } + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 30, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 40, pool_id: 1, bonded: 10, joined: true } + ] + ); + }) + } + + #[test] + fn bond_extra_updates_recorded_data() { + ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { + MaxPoolMembers::::set(None); + MaxPoolMembersPerPool::::set(None); + + // initial state of pool 1. + { + let (member_10, _, reward_pool_10) = Pools::get_member_with_pools(&10).unwrap(); + + assert_eq!(reward_pool_10.last_recorded_total_payouts, 0); + assert_eq!(reward_pool_10.total_rewards_claimed, 0); + assert_eq!(reward_pool_10.last_recorded_reward_counter, 0.into()); + + assert_eq!(member_10.last_recorded_reward_counter, 0.into()); + } + + Balances::make_free_balance_be(&10, 100); + Balances::make_free_balance_be(&20, 100); + + // 10 bonds extra without any rewards. + { + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); + assert_eq!(member.last_recorded_reward_counter, 0.into()); + assert_eq!(reward_pool.last_recorded_total_payouts, 0); + assert_eq!(reward_pool.last_recorded_reward_counter, 0.into()); + } + + // 10 bonds extra again with some rewards. This reward should be split equally between + // 10 and 20, as they both have equal points now. + Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + + { + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); + // explanation: before bond_extra takes place, there is 40 points and 30 balance in + // the system, RewardCounter is therefore 7.5 + assert_eq!(member.last_recorded_reward_counter, RewardCounter::from_float(0.75)); assert_eq!( - pool_events_since_last_call(), - vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] + reward_pool.last_recorded_reward_counter, + RewardCounter::from_float(0.75) ); + assert_eq!(reward_pool.last_recorded_total_payouts, 30); + } - // We expect a payout of 50: (5,000 del virtual points / 7,5000 pool points) * 75 - // pool balance - assert_eq!(del_50, del(50, 200)); + // 20 bonds extra again, without further rewards. + { + assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::FreeBalance(10))); + let (member, _, reward_pool) = Pools::get_member_with_pools(&20).unwrap(); + assert_eq!(member.last_recorded_reward_counter, RewardCounter::from_float(0.75)); assert_eq!( - reward_pool, - rew( - 25, - // old pool points + points from new earnings - del points. - // - // points from new earnings = new earnings(50) * bonded_pool.points(100) - // del points = member.points(50) * new_earnings_since_last_claim (100) - (2_500 + 50 * 100) - 50 * 100, - 200, - ) + reward_pool.last_recorded_reward_counter, + RewardCounter::from_float(0.75) ); - assert_eq!(Balances::free_balance(&50), 50 + 50); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); + assert_eq!(reward_pool.last_recorded_total_payouts, 30); + } + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: false }, + Event::PaidOut { member: 10, pool_id: 1, payout: 15 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: false }, + Event::PaidOut { member: 20, pool_id: 1, payout: 15 }, + Event::Bonded { member: 20, pool_id: 1, bonded: 10, joined: false } + ] + ); + }) + } + + #[test] + fn unbond_updates_recorded_data() { + ExtBuilder::default() + .add_members(vec![(20, 20), (30, 20)]) + .build_and_execute(|| { + MaxPoolMembers::::set(None); + MaxPoolMembersPerPool::::set(None); + + // initial state of pool 1. + { + let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); + + assert_eq!(reward_pool.last_recorded_total_payouts, 0); + assert_eq!(reward_pool.total_rewards_claimed, 0); + assert_eq!(reward_pool.last_recorded_reward_counter, 0.into()); + + assert_eq!(member.last_recorded_reward_counter, 0.into()); + } + + // 20 unbonds without any rewards. + { + assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + let (member, _, reward_pool) = Pools::get_member_with_pools(&20).unwrap(); + assert_eq!(member.last_recorded_reward_counter, 0.into()); + assert_eq!(reward_pool.last_recorded_total_payouts, 0); + assert_eq!(reward_pool.last_recorded_reward_counter, 0.into()); + } - // When - assert_ok!(Pools::do_reward_payout( - &10, - &mut del_10, - &mut bonded_pool, - &mut reward_pool - )); + // some rewards come in. + Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); - // Then - assert_eq!( - pool_events_since_last_call(), - vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] - ); + // and 30 also unbonds half. + { + assert_ok!(Pools::unbond(Origin::signed(30), 30, 10)); + let (member, _, reward_pool) = Pools::get_member_with_pools(&30).unwrap(); + // 30 reward in the system, and 40 points before this unbond to collect it, + // RewardCounter is 3/4. + assert_eq!( + member.last_recorded_reward_counter, + RewardCounter::from_float(0.75) + ); + assert_eq!(reward_pool.last_recorded_total_payouts, 30); + assert_eq!( + reward_pool.last_recorded_reward_counter, + RewardCounter::from_float(0.75) + ); + } - // We expect a payout of 5 - assert_eq!(del_10, del(10, 200)); - assert_eq!(reward_pool, rew(20, 2_500 - 10 * 50, 200)); - assert_eq!(Balances::free_balance(&10), 15 + 5); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 20); + // 30 unbonds again, not change this time. + { + assert_ok!(Pools::unbond(Origin::signed(30), 30, 5)); + let (member, _, reward_pool) = Pools::get_member_with_pools(&30).unwrap(); + assert_eq!( + member.last_recorded_reward_counter, + RewardCounter::from_float(0.75) + ); + assert_eq!(reward_pool.last_recorded_total_payouts, 30); + assert_eq!( + reward_pool.last_recorded_reward_counter, + RewardCounter::from_float(0.75) + ); + } - // Given del 40 hasn't claimed and the reward pool has just earned 400 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 400)); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 420); + // 20 unbonds again, not change this time, just collecting their reward. + { + assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + let (member, _, reward_pool) = Pools::get_member_with_pools(&20).unwrap(); + assert_eq!( + member.last_recorded_reward_counter, + RewardCounter::from_float(0.75) + ); + assert_eq!(reward_pool.last_recorded_total_payouts, 30); + assert_eq!( + reward_pool.last_recorded_reward_counter, + RewardCounter::from_float(0.75) + ); + } - // When - assert_ok!(Pools::do_reward_payout( - &10, - &mut del_10, - &mut bonded_pool, - &mut reward_pool - )); + // trigger 10's reward as well to see all of the payouts. + assert_ok!(Pools::claim_payout(Origin::signed(10))); - // Then assert_eq!( pool_events_since_last_call(), - vec![Event::PaidOut { member: 10, pool_id: 1, payout: 40 }] + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + Event::Bonded { member: 30, pool_id: 1, bonded: 20, joined: true }, + Event::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10 }, + Event::PaidOut { member: 30, pool_id: 1, payout: 15 }, + Event::Unbonded { member: 30, pool_id: 1, balance: 10, points: 10 }, + Event::Unbonded { member: 30, pool_id: 1, balance: 5, points: 5 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 7 }, + Event::Unbonded { member: 20, pool_id: 1, balance: 5, points: 5 }, + Event::PaidOut { member: 10, pool_id: 1, payout: 7 } + ] ); + }) + } - // We expect a payout of 40 - assert_eq!(del_10, del(10, 600)); - assert_eq!( - reward_pool, - rew( - 380, - // old pool points + points from new earnings - del points - // - // points from new earnings = new earnings(400) * bonded_pool.points(100) - // del points = member.points(10) * new_earnings_since_last_claim(400) - (2_000 + 400 * 100) - 10 * 400, - 600 - ) - ); - assert_eq!(Balances::free_balance(&10), 20 + 40); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 380); + #[test] + fn rewards_are_rounded_down_depositor_collects_them() { + ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { + // initial balance of 10. + assert_eq!(Balances::free_balance(&10), 5); + assert_eq!( + Balances::free_balance(&default_reward_account()), + Balances::minimum_balance() + ); - // Given del 40 + del 50 haven't claimed and the reward pool has earned 20 - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 20)); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 400); + // some rewards come in. + Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); - // When - assert_ok!(Pools::do_reward_payout( - &10, - &mut del_10, - &mut bonded_pool, - &mut reward_pool - )); + // everyone claims + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); - // Then - assert_eq!( - pool_events_since_last_call(), - vec![Event::PaidOut { member: 10, pool_id: 1, payout: 2 }] - ); + // some dust (1) remains in the reward account. + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 13 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 26 } + ] + ); - // Expect a payout of 2: (200 del virtual points / 38,000 pool points) * 400 pool - // balance - assert_eq!(del_10, del(10, 620)); - assert_eq!(reward_pool, rew(398, (38_000 + 20 * 100) - 10 * 20, 620)); - assert_eq!(Balances::free_balance(&10), 60 + 2); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 398); + // start dismantling the pool. + assert_ok!(Pools::set_state(Origin::signed(902), 1, PoolState::Destroying)); + assert_ok!(fully_unbond_permissioned(20)); - // When - assert_ok!(Pools::do_reward_payout( - &40, - &mut del_40, - &mut bonded_pool, - &mut reward_pool - )); + CurrentEra::set(3); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); + assert_ok!(fully_unbond_permissioned(10)); - // Then - assert_eq!( - pool_events_since_last_call(), - vec![Event::PaidOut { member: 40, pool_id: 1, payout: 188 }] - ); + CurrentEra::set(6); + assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); - // Expect a payout of 188: (18,800 del virtual points / 39,800 pool points) * 399 - // pool balance - assert_eq!(del_40, del(40, 620)); - assert_eq!(reward_pool, rew(210, 39_800 - 40 * 470, 620)); - assert_eq!(Balances::free_balance(&40), 60 + 188); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 210); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, + Event::Unbonded { member: 20, pool_id: 1, balance: 20, points: 20 }, + Event::Withdrawn { member: 20, pool_id: 1, balance: 20, points: 20 }, + Event::MemberRemoved { pool_id: 1, member: 20 }, + Event::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10 }, + Event::Withdrawn { member: 10, pool_id: 1, balance: 10, points: 10 }, + Event::MemberRemoved { pool_id: 1, member: 10 }, + Event::Destroyed { pool_id: 1 } + ] + ); - // When - assert_ok!(Pools::do_reward_payout( - &50, - &mut del_50, - &mut bonded_pool, - &mut reward_pool - )); + // original ed + ed put into reward account + reward + bond + dust. + assert_eq!(Balances::free_balance(&10), 5 + 5 + 13 + 10 + 1); + }) + } + + #[test] + fn claim_payout_large_numbers() { + let unit = 10u128.pow(12); // akin to KSM + ExistentialDeposit::set(unit); + StakingMinBond::set(unit * 1000); + + ExtBuilder::default() + .max_members(Some(4)) + .max_members_per_pool(Some(4)) + .add_members(vec![(20, 1500 * unit), (21, 2500 * unit), (22, 5000 * unit)]) + .build_and_execute(|| { + // some rewards come in. + assert_eq!(Balances::free_balance(&default_reward_account()), unit); + Balances::mutate_account(&default_reward_account(), |f| f.free += unit / 1000) + .unwrap(); + + // everyone claims + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(Origin::signed(21))); + assert_ok!(Pools::claim_payout(Origin::signed(22))); - // Then assert_eq!( pool_events_since_last_call(), - vec![Event::PaidOut { member: 50, pool_id: 1, payout: 210 }] + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { + member: 10, + pool_id: 1, + bonded: 1000000000000000, + joined: true + }, + Event::Bonded { + member: 20, + pool_id: 1, + bonded: 1500000000000000, + joined: true + }, + Event::Bonded { + member: 21, + pool_id: 1, + bonded: 2500000000000000, + joined: true + }, + Event::Bonded { + member: 22, + pool_id: 1, + bonded: 5000000000000000, + joined: true + }, + Event::PaidOut { member: 10, pool_id: 1, payout: 100000000 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 150000000 }, + Event::PaidOut { member: 21, pool_id: 1, payout: 250000000 }, + Event::PaidOut { member: 22, pool_id: 1, payout: 500000000 } + ] ); - - // Expect payout of 210: (21,000 / 21,000) * 210 - assert_eq!(del_50, del(50, 620)); - assert_eq!(reward_pool, rew(0, 21_000 - 50 * 420, 620)); - assert_eq!(Balances::free_balance(&50), 100 + 210); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 0); - }); + }) } } @@ -2461,7 +2846,8 @@ mod withdraw_unbonded { assert_eq!( SubPoolsStorage::::get(&1).unwrap().with_era, - unbonding_pools_with_era! { 3 => UnbondPool { points: 550 / 2 + 40 / 2, balance: 550 / 2 + 40 / 2 }} + unbonding_pools_with_era! { 3 => UnbondPool { points: 550 / 2 + 40 / 2, balance: 550 / 2 + 40 / 2 + }} ); assert_eq!( @@ -3089,11 +3475,7 @@ mod create { ); assert_eq!( RewardPools::::get(2).unwrap(), - RewardPool { - balance: Zero::zero(), - points: U256::zero(), - total_earnings: Zero::zero(), - } + RewardPool { ..Default::default() } ); assert_eq!( @@ -3688,3 +4070,310 @@ mod update_roles { }) } } + +mod reward_counter_precision { + use sp_runtime::FixedU128; + + use super::*; + + const DOT: Balance = 10u128.pow(10u32); + const POLKADOT_TOTAL_ISSUANCE_GENESIS: Balance = DOT * 10u128.pow(9u32); + + const fn inflation(years: u128) -> u128 { + let mut i = 0; + let mut start = POLKADOT_TOTAL_ISSUANCE_GENESIS; + while i < years { + start = start + start / 10; + i += 1 + } + start + } + + fn default_pool_reward_counter() -> FixedU128 { + RewardPools::::get(1) + .unwrap() + .current_reward_counter(1, BondedPools::::get(1).unwrap().points) + .unwrap() + } + + fn pending_rewards(of: AccountId) -> Option> { + let member = PoolMembers::::get(of).unwrap(); + assert_eq!(member.pool_id, 1); + let rc = default_pool_reward_counter(); + member.pending_rewards(rc).ok() + } + + #[test] + fn smallest_claimable_reward() { + // create a pool that has all of the polkadot issuance in 50 years. + let pool_bond = inflation(50); + ExtBuilder::default().ed(DOT).min_bond(pool_bond).build_and_execute(|| { + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { + member: 10, + pool_id: 1, + bonded: 1173908528796953165005, + joined: true, + } + ] + ); + + // the smallest reward that this pool can handle is + let expected_smallest_reward = inflation(50) / 10u128.pow(18); + + // tad bit less. cannot be paid out. + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += + expected_smallest_reward - 1)); + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_eq!(pool_events_since_last_call(), vec![]); + // revert it. + + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free -= + expected_smallest_reward - 1)); + + // tad bit more. can be claimed. + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += + expected_smallest_reward + 1)); + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 1173 }] + ); + }) + } + + #[test] + fn reward_counter_calc_wont_fail_in_normal_polkadot_future() { + // create a pool that has roughly half of the polkadot issuance in 10 years. + let pool_bond = inflation(10) / 2; + ExtBuilder::default().ed(DOT).min_bond(pool_bond).build_and_execute(|| { + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { + member: 10, + pool_id: 1, + bonded: 12_968_712_300_500_000_000, + joined: true, + } + ] + ); + + // in 10 years, the total claimed rewards are large values as well. assuming that a pool + // is earning all of the inflation per year (which is really unrealistic, but worse + // case), that will be: + let pool_total_earnings_10_years = inflation(10) - POLKADOT_TOTAL_ISSUANCE_GENESIS; + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += + pool_total_earnings_10_years)); + + // some whale now joins with the other half ot the total issuance. This will bloat all + // the calculation regarding current reward counter. + Balances::make_free_balance_be(&20, pool_bond * 2); + assert_ok!(Pools::join(Origin::signed(20), pool_bond, 1)); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::Bonded { + member: 20, + pool_id: 1, + bonded: 12_968_712_300_500_000_000, + joined: true + }] + ); + + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 15937424600999999996 }] + ); + + // now let a small member join with 10 DOTs. + Balances::make_free_balance_be(&30, 20 * DOT); + assert_ok!(Pools::join(Origin::signed(30), 10 * DOT, 1)); + + // and give a reasonably small reward to the pool. + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += DOT)); + + assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Bonded { member: 30, pool_id: 1, bonded: 100000000000, joined: true }, + // quite small, but working fine. + Event::PaidOut { member: 30, pool_id: 1, payout: 38 } + ] + ); + }) + } + + #[test] + fn reward_counter_update_can_fail_if_pool_is_highly_slashed() { + // create a pool that has roughly half of the polkadot issuance in 10 years. + let pool_bond = inflation(10) / 2; + ExtBuilder::default().ed(DOT).min_bond(pool_bond).build_and_execute(|| { + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { + member: 10, + pool_id: 1, + bonded: 12_968_712_300_500_000_000, + joined: true, + } + ] + ); + + // slash this pool by 99% of that. + StakingMock::set_bonded_balance(default_bonded_account(), DOT + pool_bond / 100); + + // some whale now joins with the other half ot the total issuance. This will trigger an + // overflow. This test is actually a bit too lenient because all the reward counters are + // set to zero. In other tests that we want to assert a scenario won't fail, we should + // also set the reward counters to some large value. + Balances::make_free_balance_be(&20, pool_bond * 2); + assert_err!(Pools::join(Origin::signed(20), pool_bond, 1), Error::::OverflowRisk); + }) + } + + #[test] + fn if_small_member_waits_long_enough_they_will_earn_rewards() { + // create a pool that has a quarter of the current polkadot issuance + ExtBuilder::default() + .ed(DOT) + .min_bond(POLKADOT_TOTAL_ISSUANCE_GENESIS / 4) + .build_and_execute(|| { + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { + member: 10, + pool_id: 1, + bonded: 2500000000000000000, + joined: true, + } + ] + ); + + // and have a tiny fish join the pool as well.. + Balances::make_free_balance_be(&20, 20 * DOT); + assert_ok!(Pools::join(Origin::signed(20), 10 * DOT, 1)); + + // earn some small rewards + assert_ok!( + Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) + ); + + // no point in claiming for 20 (nonetheless, it should be harmless) + assert!(pending_rewards(20).unwrap().is_zero()); + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Bonded { + member: 20, + pool_id: 1, + bonded: 100000000000, + joined: true + }, + Event::PaidOut { member: 10, pool_id: 1, payout: 9999997 } + ] + ); + + // earn some small more, still nothing can be claimed for 20, but 10 claims their + // share. + assert_ok!( + Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) + ); + assert!(pending_rewards(20).unwrap().is_zero()); + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 10000000 }] + ); + + // earn some more rewards, this time 20 can also claim. + assert_ok!( + Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) + ); + assert_eq!(pending_rewards(20).unwrap(), 1); + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 10000000 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 1 } + ] + ); + }); + } + + #[test] + fn zero_reward_claim_does_not_update_reward_counter() { + // create a pool that has a quarter of the current polkadot issuance + ExtBuilder::default() + .ed(DOT) + .min_bond(POLKADOT_TOTAL_ISSUANCE_GENESIS / 4) + .build_and_execute(|| { + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { + member: 10, + pool_id: 1, + bonded: 2500000000000000000, + joined: true, + } + ] + ); + + // and have a tiny fish join the pool as well.. + Balances::make_free_balance_be(&20, 20 * DOT); + assert_ok!(Pools::join(Origin::signed(20), 10 * DOT, 1)); + + // earn some small rewards + assert_ok!( + Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) + ); + + // if 20 claims now, their reward counter should stay the same, so that they have a + // chance of claiming this if they let it accumulate. Also see + // `if_small_member_waits_long_enough_they_will_earn_rewards` + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Bonded { + member: 20, + pool_id: 1, + bonded: 100000000000, + joined: true + }, + Event::PaidOut { member: 10, pool_id: 1, payout: 9999997 } + ] + ); + + let current_reward_counter = default_pool_reward_counter(); + // has been updated, because they actually claimed something. + assert_eq!( + PoolMembers::::get(10).unwrap().last_recorded_reward_counter, + current_reward_counter + ); + // has not be updated, even though the claim transaction went through okay. + assert_eq!( + PoolMembers::::get(20).unwrap().last_recorded_reward_counter, + Default::default() + ); + }); + } +} diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index 8e3facfc5ec26..a9003ffd3fb4c 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-06-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-06-15, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -70,7 +70,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) - // Storage: NominationPools RewardPools (r:1 w:0) + // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:2 w:1) // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) // Storage: NominationPools MaxPoolMembers (r:1 w:0) @@ -80,22 +80,22 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (124_508_000 as Weight) + (123_947_000 as Weight) .saturating_add(T::DbWeight::get().reads(17 as Weight)) - .saturating_add(T::DbWeight::get().writes(11 as Weight)) + .saturating_add(T::DbWeight::get().writes(12 as Weight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) - // Storage: System Account (r:2 w:2) + // Storage: System Account (r:3 w:2) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (115_185_000 as Weight) - .saturating_add(T::DbWeight::get().reads(13 as Weight)) + (118_236_000 as Weight) + .saturating_add(T::DbWeight::get().reads(14 as Weight)) .saturating_add(T::DbWeight::get().writes(12 as Weight)) } // Storage: NominationPools PoolMembers (r:1 w:1) @@ -108,7 +108,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (132_723_000 as Weight) + (132_475_000 as Weight) .saturating_add(T::DbWeight::get().reads(14 as Weight)) .saturating_add(T::DbWeight::get().writes(13 as Weight)) } @@ -117,7 +117,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (52_498_000 as Weight) + (50_299_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -136,7 +136,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (121_645_000 as Weight) + (121_254_000 as Weight) .saturating_add(T::DbWeight::get().reads(18 as Weight)) .saturating_add(T::DbWeight::get().writes(13 as Weight)) } @@ -146,9 +146,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (43_320_000 as Weight) + (41_928_000 as Weight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -162,9 +162,9 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - (83_195_000 as Weight) - // Standard Error: 5_000 - .saturating_add((57_000 as Weight).saturating_mul(s as Weight)) + (81_611_000 as Weight) + // Standard Error: 1_000 + .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } @@ -189,7 +189,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (143_495_000 as Weight) + (139_849_000 as Weight) .saturating_add(T::DbWeight::get().reads(19 as Weight)) .saturating_add(T::DbWeight::get().writes(16 as Weight)) } @@ -216,7 +216,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (127_998_000 as Weight) + (126_246_000 as Weight) .saturating_add(T::DbWeight::get().reads(22 as Weight)) .saturating_add(T::DbWeight::get().writes(15 as Weight)) } @@ -234,9 +234,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - (49_929_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_319_000 as Weight).saturating_mul(n as Weight)) + (48_829_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_204_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(12 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(5 as Weight)) @@ -244,7 +244,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (27_399_000 as Weight) + (26_761_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -253,7 +253,7 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools CounterForMetadata (r:1 w:1) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - (14_813_000 as Weight) + (14_519_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) @@ -265,12 +265,12 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (6_115_000 as Weight) + (6_173_000 as Weight) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (22_546_000 as Weight) + (22_261_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -283,7 +283,7 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (48_243_000 as Weight) + (47_959_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -295,7 +295,7 @@ impl WeightInfo for () { // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) - // Storage: NominationPools RewardPools (r:1 w:0) + // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:2 w:1) // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) // Storage: NominationPools MaxPoolMembers (r:1 w:0) @@ -305,22 +305,22 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (124_508_000 as Weight) + (123_947_000 as Weight) .saturating_add(RocksDbWeight::get().reads(17 as Weight)) - .saturating_add(RocksDbWeight::get().writes(11 as Weight)) + .saturating_add(RocksDbWeight::get().writes(12 as Weight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) - // Storage: System Account (r:2 w:2) + // Storage: System Account (r:3 w:2) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (115_185_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(13 as Weight)) + (118_236_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(14 as Weight)) .saturating_add(RocksDbWeight::get().writes(12 as Weight)) } // Storage: NominationPools PoolMembers (r:1 w:1) @@ -333,7 +333,7 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (132_723_000 as Weight) + (132_475_000 as Weight) .saturating_add(RocksDbWeight::get().reads(14 as Weight)) .saturating_add(RocksDbWeight::get().writes(13 as Weight)) } @@ -342,7 +342,7 @@ impl WeightInfo for () { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (52_498_000 as Weight) + (50_299_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -361,7 +361,7 @@ impl WeightInfo for () { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (121_645_000 as Weight) + (121_254_000 as Weight) .saturating_add(RocksDbWeight::get().reads(18 as Weight)) .saturating_add(RocksDbWeight::get().writes(13 as Weight)) } @@ -371,9 +371,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (43_320_000 as Weight) + (41_928_000 as Weight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -387,9 +387,9 @@ impl WeightInfo for () { // Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - (83_195_000 as Weight) - // Standard Error: 5_000 - .saturating_add((57_000 as Weight).saturating_mul(s as Weight)) + (81_611_000 as Weight) + // Standard Error: 1_000 + .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } @@ -414,7 +414,7 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (143_495_000 as Weight) + (139_849_000 as Weight) .saturating_add(RocksDbWeight::get().reads(19 as Weight)) .saturating_add(RocksDbWeight::get().writes(16 as Weight)) } @@ -441,7 +441,7 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (127_998_000 as Weight) + (126_246_000 as Weight) .saturating_add(RocksDbWeight::get().reads(22 as Weight)) .saturating_add(RocksDbWeight::get().writes(15 as Weight)) } @@ -459,9 +459,9 @@ impl WeightInfo for () { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - (49_929_000 as Weight) - // Standard Error: 16_000 - .saturating_add((2_319_000 as Weight).saturating_mul(n as Weight)) + (48_829_000 as Weight) + // Standard Error: 10_000 + .saturating_add((2_204_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(12 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) @@ -469,7 +469,7 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (27_399_000 as Weight) + (26_761_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -478,7 +478,7 @@ impl WeightInfo for () { // Storage: NominationPools CounterForMetadata (r:1 w:1) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - (14_813_000 as Weight) + (14_519_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) @@ -490,12 +490,12 @@ impl WeightInfo for () { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (6_115_000 as Weight) + (6_173_000 as Weight) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (22_546_000 as Weight) + (22_261_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -508,7 +508,7 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (48_243_000 as Weight) + (47_959_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs index be7752ce113b4..3b9350f25040b 100644 --- a/frame/nomination-pools/test-staking/src/lib.rs +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -26,6 +26,7 @@ use pallet_nomination_pools::{ PoolState, }; use pallet_staking::{CurrentEra, Event as StakingEvent, Payee, RewardDestination}; +use sp_runtime::traits::Zero; #[test] fn pool_lifecycle_e2e() { @@ -296,7 +297,7 @@ fn pool_slash_e2e() { PoolMember { pool_id: 1, points: 0, - reward_pool_total_earnings: 0, + last_recorded_reward_counter: Zero::zero(), // the 10 points unlocked just now correspond to 5 points in the unbond pool. unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5) } @@ -351,7 +352,7 @@ fn pool_slash_e2e() { PoolMember { pool_id: 1, points: 0, - reward_pool_total_earnings: 0, + last_recorded_reward_counter: Zero::zero(), unbonding_eras: bounded_btree_map!(4 => 10, 5 => 10, 9 => 10) } ); diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index d13d8aa341c12..852b2c319f376 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -16,8 +16,17 @@ // limitations under the License. use frame_election_provider_support::VoteWeight; -use frame_support::{assert_ok, pallet_prelude::*, parameter_types, traits::ConstU64, PalletId}; -use sp_runtime::traits::{Convert, IdentityLookup}; +use frame_support::{ + assert_ok, + pallet_prelude::*, + parameter_types, + traits::{ConstU64, ConstU8}, + PalletId, +}; +use sp_runtime::{ + traits::{Convert, IdentityLookup}, + FixedU128, +}; type AccountId = u128; type AccountIndex = u32; @@ -159,13 +168,15 @@ impl pallet_nomination_pools::Config for Runtime { type Event = Event; type WeightInfo = (); type Currency = Balances; + type CurrencyBalance = Balance; + type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; type StakingInterface = Staking; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; - type MinPointsToBalance = ConstU32<10>; + type MaxPointsToBalance = ConstU8<10>; type PalletId = PoolsPalletId; } diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index c09a33cf3f16a..f77f92c625c9d 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -472,9 +472,10 @@ pub enum State { #[clap(short, long)] snapshot_path: Option, - /// The pallets to scrape. If empty, entire chain state will be scraped. + /// A pallet to scrape. Can be provided multiple times. If empty, entire chain state will + /// be scraped. #[clap(short, long, multiple_values = true)] - pallets: Vec, + pallet: Vec, /// Fetch the child-keys as well. /// @@ -498,7 +499,7 @@ impl State { Builder::::new().mode(Mode::Offline(OfflineConfig { state_snapshot: SnapshotConfig::new(snapshot_path), })), - State::Live { snapshot_path, pallets, uri, at, child_tree } => { + State::Live { snapshot_path, pallet, uri, at, child_tree } => { let at = match at { Some(at_str) => Some(hash_of::(at_str)?), None => None, @@ -507,7 +508,7 @@ impl State { .mode(Mode::Online(OnlineConfig { transport: uri.to_owned().into(), state_snapshot: snapshot_path.as_ref().map(SnapshotConfig::new), - pallets: pallets.clone(), + pallets: pallet.clone(), scrape_children: true, at, })) From 49b06901eb65f2c61ff0934d66987fd955d5b8f5 Mon Sep 17 00:00:00 2001 From: Emre Surmeli Date: Thu, 14 Jul 2022 04:21:21 -0400 Subject: [PATCH 0967/1472] Fix typo (#11832) --- frame/election-provider-multi-phase/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 2f1f6463df719..e1d3cb8ed5dee 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -51,7 +51,7 @@ //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution //! on-chain for a number of blocks, and the potential weight of the solution upon being checked. A -//! maximum of `pallet::Config::MaxSignedSubmissions` solutions are stored. The queue is always +//! maximum of `pallet::Config::SignedMaxSubmissions` solutions are stored. The queue is always //! sorted based on score (worse to best). //! //! Upon arrival of a new solution: From 1f0253c4c5fe70213fc2a53e78b5e9648e71d2c7 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 14 Jul 2022 10:57:59 +0100 Subject: [PATCH 0968/1472] Fix nomination pools unbonding logic (#11746) * make pool roles optional * undo lock file changes? * add migration * add the ability for pools to chill themselves * boilerplate of tests * somewhat stable, but I think I found another bug as well * Fix it all * Add more more sophisticated test + capture one more bug. * Update frame/staking/src/lib.rs * reduce the diff a little bit * add some test for the slashing bug * cleanup * fix lock file? * Fix * fmt * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/mock.rs Co-authored-by: Oliver Tale-Yazdi * Fix build * fix some fishy tests.. * add one last integrity check for MinCreateBond * remove bad assertion -- needs to be dealt with later * nits * fix tests and add benchmarks for chill * remove stuff * fix benchmarks * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * remove defensive * first working version * bring back all tests * ALL new tests work now * cleanup * make sure benchmarks and all work * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * round of self-review, make arithmetic safe * fix warn * add migration code * Fix doc * add precision notes * make arithmetic fallible * fix node runtime * a lot of precision tests and notes and stuff * document MaxPOintsToBalance better * :round of self-review * fmt * fix some comments * new logic, some broken tests * Check if after unbonding remaining balance is more or equal to MinJoinBond and is not zero * incorporate nikos' work * make it work again * merge * Fix all tests * fix all tests * some updates * Add tests * remove erroneoysly placed comment * Try to make lint pass * Try to make lint pass * revamp the tests for unbond * fix docs * Fix proportional slashing logic * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * track poinst in migration * fix * fmt * fix migration * remove event read * Apply suggestions from code review * Update frame/nomination-pools/src/lib.rs Co-authored-by: Shawn Tabrizi * remove log * Update frame/staking/src/lib.rs Co-authored-by: Shawn Tabrizi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Shawn Tabrizi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Shawn Tabrizi * update * fmt * fmt * add one last test * fmrt * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi Co-authored-by: Parity Bot Co-authored-by: wirednkod --- frame/nomination-pools/src/lib.rs | 135 +++-- frame/nomination-pools/src/mock.rs | 16 +- frame/nomination-pools/src/tests.rs | 480 ++++++++++++++---- .../nomination-pools/test-staking/src/lib.rs | 6 +- 4 files changed, 464 insertions(+), 173 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 53e1c48a5e39e..514267e8bf4af 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -469,7 +469,7 @@ impl PoolMember { self.points = new_points; Ok(()) } else { - Err(Error::::NotEnoughPointsToUnbond) + Err(Error::::MinimumBondNotMet) } } @@ -781,45 +781,60 @@ impl BondedPool { let is_depositor = *target_account == self.roles.depositor; let is_full_unbond = unbonding_points == target_member.active_points(); + let balance_after_unbond = { + let new_depositor_points = + target_member.active_points().saturating_sub(unbonding_points); + let mut target_member_after_unbond = (*target_member).clone(); + target_member_after_unbond.points = new_depositor_points; + target_member_after_unbond.active_balance() + }; + // any partial unbonding is only ever allowed if this unbond is permissioned. ensure!( is_permissioned || is_full_unbond, Error::::PartialUnbondNotAllowedPermissionlessly ); + // any unbond must comply with the balance condition: + ensure!( + is_full_unbond || + balance_after_unbond >= + if is_depositor { + Pallet::::depositor_min_bond() + } else { + MinJoinBond::::get() + }, + Error::::MinimumBondNotMet + ); + + // additional checks: match (is_permissioned, is_depositor) { - // If the pool is blocked, then an admin with kicking permissions can remove a - // member. If the pool is being destroyed, anyone can remove a member + (true, false) => (), + (true, true) => { + // permission depositor unbond: if destroying and pool is empty, always allowed, + // with no additional limits. + if self.is_destroying_and_only_depositor(target_member.active_points()) { + // everything good, let them unbond anything. + } else { + // depositor cannot fully unbond yet. + ensure!(!is_full_unbond, Error::::MinimumBondNotMet); + } + }, (false, false) => { + // If the pool is blocked, then an admin with kicking permissions can remove a + // member. If the pool is being destroyed, anyone can remove a member + debug_assert!(is_full_unbond); ensure!( self.can_kick(caller) || self.is_destroying(), Error::::NotKickerOrDestroying ) }, - // Any member who is not the depositor can always unbond themselves - (true, false) => (), - (_, true) => { - if self.is_destroying_and_only_depositor(target_member.active_points()) { - // if the pool is about to be destroyed, anyone can unbond the depositor, and - // they can fully unbond. - } else { - // only the depositor can partially unbond, and they can only unbond up to the - // threshold. - ensure!(is_permissioned, Error::::DoesNotHavePermission); - let balance_after_unbond = { - let new_depositor_points = - target_member.active_points().saturating_sub(unbonding_points); - let mut depositor_after_unbond = (*target_member).clone(); - depositor_after_unbond.points = new_depositor_points; - depositor_after_unbond.active_balance() - }; - ensure!( - balance_after_unbond >= MinCreateBond::::get(), - Error::::NotOnlyPoolMember - ); - } + (false, true) => { + // the depositor can simply not be unbonded permissionlessly, period. + return Err(Error::::DoesNotHavePermission.into()) }, }; + Ok(()) } @@ -830,25 +845,14 @@ impl BondedPool { &self, caller: &T::AccountId, target_account: &T::AccountId, - target_member: &PoolMember, - sub_pools: &SubPools, ) -> Result<(), DispatchError> { - if *target_account == self.roles.depositor { - ensure!( - sub_pools.sum_unbonding_points() == target_member.unbonding_points(), - Error::::NotOnlyPoolMember - ); - debug_assert_eq!(self.member_counter, 1, "only member must exist at this point"); - Ok(()) - } else { - // This isn't a depositor - let is_permissioned = caller == target_account; - ensure!( - is_permissioned || self.can_kick(caller) || self.is_destroying(), - Error::::NotKickerOrDestroying - ); - Ok(()) - } + // This isn't a depositor + let is_permissioned = caller == target_account; + ensure!( + is_permissioned || self.can_kick(caller) || self.is_destroying(), + Error::::NotKickerOrDestroying + ); + Ok(()) } /// Bond exactly `amount` from `who`'s funds into this pool. @@ -1100,15 +1104,6 @@ impl SubPools { self } - /// The sum of all unbonding points, regardless of whether they are actually unlocked or not. - fn sum_unbonding_points(&self) -> BalanceOf { - self.no_era.points.saturating_add( - self.with_era - .values() - .fold(BalanceOf::::zero(), |acc, pool| acc.saturating_add(pool.points)), - ) - } - /// The sum of all unbonding balance, regardless of whether they are actually unlocked or not. #[cfg(any(test, debug_assertions))] fn sum_unbonding_balance(&self) -> BalanceOf { @@ -1419,15 +1414,16 @@ pub mod pallet { /// None of the funds can be withdrawn yet because the bonding duration has not passed. CannotWithdrawAny, /// The amount does not meet the minimum bond to either join or create a pool. + /// + /// The depositor can never unbond to a value less than + /// `Pallet::depositor_min_bond`. The caller does not have nominating + /// permissions for the pool. Members can never unbond to a value below `MinJoinBond`. MinimumBondNotMet, /// The transaction could not be executed due to overflow risk for the pool. OverflowRisk, /// A pool must be in [`PoolState::Destroying`] in order for the depositor to unbond or for /// other members to be permissionlessly unbonded. NotDestroying, - /// The depositor must be the only member in the bonded pool in order to unbond. And the - /// depositor must be the only member in the sub pools in order to withdraw unbonded. - NotOnlyPoolMember, /// The caller does not have nominating permissions for the pool. NotNominator, /// Either a) the caller cannot make a valid kick or b) the pool is not destroying. @@ -1447,8 +1443,6 @@ pub mod pallet { /// Some error occurred that should never happen. This should be reported to the /// maintainers. Defensive(DefensiveError), - /// Not enough points. Ty unbonding less. - NotEnoughPointsToUnbond, /// Partial unbonding now allowed permissionlessly. PartialUnbondNotAllowedPermissionlessly, } @@ -1758,12 +1752,7 @@ pub mod pallet { let mut sub_pools = SubPoolsStorage::::get(member.pool_id) .defensive_ok_or::>(DefensiveError::SubPoolsNotFound.into())?; - bonded_pool.ok_to_withdraw_unbonded_with( - &caller, - &member_account, - &member, - &sub_pools, - )?; + bonded_pool.ok_to_withdraw_unbonded_with(&caller, &member_account)?; // NOTE: must do this after we have done the `ok_to_withdraw_unbonded_other_with` check. let withdrawn_points = member.withdraw_unlocked(current_era); @@ -1878,13 +1867,7 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; - ensure!( - amount >= - T::StakingInterface::minimum_bond() - .max(MinCreateBond::::get()) - .max(MinJoinBond::::get()), - Error::::MinimumBondNotMet - ); + ensure!(amount >= Pallet::::depositor_min_bond(), Error::::MinimumBondNotMet); ensure!( MaxPools::::get() .map_or(true, |max_pools| BondedPools::::count() < max_pools), @@ -2162,6 +2145,18 @@ pub mod pallet { } impl Pallet { + /// The amount of bond that MUST REMAIN IN BONDED in ALL POOLS. + /// + /// It is the responsibility of the depositor to put these funds into the pool initially. Upon + /// unbond, they can never unbond to a value below this amount. + /// + /// It is essentially `max { MinNominatorBond, MinCreateBond, MinJoinBond }`, where the former + /// is coming from the staking pallet and the latter two are configured in this pallet. + fn depositor_min_bond() -> BalanceOf { + T::StakingInterface::minimum_bond() + .max(MinCreateBond::::get()) + .max(MinJoinBond::::get()) + } /// Remove everything related to the given bonded pool. /// /// All sub-pools are also deleted. All accounts are dusted and the leftover of the reward diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 042a0b666efb1..5138c55afccac 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -22,6 +22,7 @@ pub fn default_reward_account() -> AccountId { } parameter_types! { + pub static MinJoinBondConfig: Balance = 2; pub static CurrentEra: EraIndex = 0; pub static BondingDuration: EraIndex = 3; pub storage BondedBalanceMap: BTreeMap = Default::default(); @@ -245,6 +246,11 @@ impl ExtBuilder { self } + pub(crate) fn min_join_bond(self, min: Balance) -> Self { + MinJoinBondConfig::set(min); + self + } + pub(crate) fn with_check(self, level: u8) -> Self { CheckLevel::set(level); self @@ -261,11 +267,12 @@ impl ExtBuilder { } pub(crate) fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); let _ = crate::GenesisConfig:: { - min_join_bond: 2, + min_join_bond: MinJoinBondConfig::get(), min_create_bond: 2, max_pools: Some(2), max_members_per_pool: self.max_members_per_pool, @@ -280,8 +287,8 @@ impl ExtBuilder { frame_system::Pallet::::set_block_number(1); // make a pool - let amount_to_bond = ::StakingInterface::minimum_bond(); - Balances::make_free_balance_be(&10, amount_to_bond * 2); + let amount_to_bond = Pools::depositor_min_bond(); + Balances::make_free_balance_be(&10, amount_to_bond * 5); assert_ok!(Pools::create(RawOrigin::Signed(10).into(), amount_to_bond, 900, 901, 902)); let last_pool = LastPoolId::::get(); @@ -302,12 +309,13 @@ impl ExtBuilder { } } -pub(crate) fn unsafe_set_state(pool_id: PoolId, state: PoolState) -> Result<(), ()> { +pub(crate) fn unsafe_set_state(pool_id: PoolId, state: PoolState) { BondedPools::::try_mutate(pool_id, |maybe_bonded_pool| { maybe_bonded_pool.as_mut().ok_or(()).map(|bonded_pool| { bonded_pool.state = state; }) }) + .unwrap() } parameter_types! { diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 9989893d86462..c971239bef507 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -538,13 +538,13 @@ mod join { StakingMock::set_bonded_balance(Pools::create_bonded_account(1), max_points_to_balance); // Cannot join a pool that isn't open - unsafe_set_state(123, PoolState::Blocked).unwrap(); + unsafe_set_state(123, PoolState::Blocked); assert_noop!( Pools::join(Origin::signed(11), max_points_to_balance, 123), Error::::NotOpen ); - unsafe_set_state(123, PoolState::Destroying).unwrap(); + unsafe_set_state(123, PoolState::Destroying); assert_noop!( Pools::join(Origin::signed(11), max_points_to_balance, 123), Error::::NotOpen @@ -1824,7 +1824,8 @@ mod claim_payout { fn rewards_are_rounded_down_depositor_collects_them() { ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { // initial balance of 10. - assert_eq!(Balances::free_balance(&10), 5); + + assert_eq!(Balances::free_balance(&10), 35); assert_eq!( Balances::free_balance(&default_reward_account()), Balances::minimum_balance() @@ -1875,7 +1876,7 @@ mod claim_payout { ); // original ed + ed put into reward account + reward + bond + dust. - assert_eq!(Balances::free_balance(&10), 5 + 5 + 13 + 10 + 1); + assert_eq!(Balances::free_balance(&10), 35 + 5 + 13 + 10 + 1); }) } @@ -1942,10 +1943,269 @@ mod claim_payout { mod unbond { use super::*; + #[test] + fn member_unbond_open() { + // depositor in pool, pool state open + // - member unbond above limit + // - member unbonds to 0 + // - member cannot unbond between within limit and 0 + ExtBuilder::default() + .min_join_bond(10) + .add_members(vec![(20, 20)]) + .build_and_execute(|| { + // can unbond to above limit + assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 15); + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 5); + + // cannot go to below 10: + assert_noop!( + Pools::unbond(Origin::signed(20), 20, 10), + Error::::MinimumBondNotMet + ); + + // but can go to 0 + assert_ok!(Pools::unbond(Origin::signed(20), 20, 15)); + assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 0); + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 20); + }) + } + + #[test] + fn member_kicked() { + // depositor in pool, pool state blocked + // - member cannot be kicked to above limit + // - member cannot be kicked between within limit and 0 + // - member kicked to 0 + ExtBuilder::default() + .min_join_bond(10) + .add_members(vec![(20, 20)]) + .build_and_execute(|| { + unsafe_set_state(1, PoolState::Blocked); + let kicker = DEFAULT_ROLES.state_toggler.unwrap(); + + // cannot be kicked to above the limit. + assert_noop!( + Pools::unbond(Origin::signed(kicker), 20, 5), + Error::::PartialUnbondNotAllowedPermissionlessly + ); + + // cannot go to below 10: + assert_noop!( + Pools::unbond(Origin::signed(kicker), 20, 15), + Error::::PartialUnbondNotAllowedPermissionlessly + ); + + // but they themselves can do an unbond + assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); + assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 18); + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 2); + + // can be kicked to 0. + assert_ok!(Pools::unbond(Origin::signed(kicker), 20, 18)); + assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 0); + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 20); + }) + } + + #[test] + fn member_unbond_destroying() { + // depositor in pool, pool state destroying + // - member cannot be permissionlessly unbonded to above limit + // - member cannot be permissionlessly unbonded between within limit and 0 + // - member permissionlessly unbonded to 0 + ExtBuilder::default() + .min_join_bond(10) + .add_members(vec![(20, 20)]) + .build_and_execute(|| { + unsafe_set_state(1, PoolState::Destroying); + let random = 123; + + // cannot be kicked to above the limit. + assert_noop!( + Pools::unbond(Origin::signed(random), 20, 5), + Error::::PartialUnbondNotAllowedPermissionlessly + ); + + // cannot go to below 10: + assert_noop!( + Pools::unbond(Origin::signed(random), 20, 15), + Error::::PartialUnbondNotAllowedPermissionlessly + ); + + // but they themselves can do an unbond + assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); + assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 18); + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 2); + + // but can go to 0 + assert_ok!(Pools::unbond(Origin::signed(random), 20, 18)); + assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 0); + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 20); + }) + } + + #[test] + fn depositor_unbond_open() { + // depositor in pool, pool state open + // - depositor unbonds to above limit + // - depositor cannot unbond to below limit or 0 + ExtBuilder::default().min_join_bond(10).build_and_execute(|| { + // give the depositor some extra funds. + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_eq!(PoolMembers::::get(10).unwrap().points, 20); + + // can unbond to above the limit. + assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 15); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 5); + + // cannot go to below 10: + assert_noop!(Pools::unbond(Origin::signed(10), 10, 10), Error::::MinimumBondNotMet); + + // cannot go to 0 either. + assert_noop!(Pools::unbond(Origin::signed(10), 10, 15), Error::::MinimumBondNotMet); + }) + } + + #[test] + fn depositor_kick() { + // depositor in pool, pool state blocked + // - depositor can never be kicked. + ExtBuilder::default().min_join_bond(10).build_and_execute(|| { + // give the depositor some extra funds. + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_eq!(PoolMembers::::get(10).unwrap().points, 20); + + // set the stage + unsafe_set_state(1, PoolState::Blocked); + let kicker = DEFAULT_ROLES.state_toggler.unwrap(); + + // cannot be kicked to above limit. + assert_noop!( + Pools::unbond(Origin::signed(kicker), 10, 5), + Error::::PartialUnbondNotAllowedPermissionlessly + ); + + // or below the limit + assert_noop!( + Pools::unbond(Origin::signed(kicker), 10, 15), + Error::::PartialUnbondNotAllowedPermissionlessly + ); + + // or 0. + assert_noop!( + Pools::unbond(Origin::signed(kicker), 10, 20), + Error::::DoesNotHavePermission + ); + + // they themselves cannot do it either + assert_noop!(Pools::unbond(Origin::signed(10), 10, 20), Error::::MinimumBondNotMet); + }) + } + + #[test] + fn depositor_unbond_destroying_permissionless() { + // depositor can never be permissionlessly unbonded. + ExtBuilder::default().min_join_bond(10).build_and_execute(|| { + // give the depositor some extra funds. + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_eq!(PoolMembers::::get(10).unwrap().points, 20); + + // set the stage + unsafe_set_state(1, PoolState::Destroying); + let random = 123; + + // cannot be kicked to above limit. + assert_noop!( + Pools::unbond(Origin::signed(random), 10, 5), + Error::::PartialUnbondNotAllowedPermissionlessly + ); + + // or below the limit + assert_noop!( + Pools::unbond(Origin::signed(random), 10, 15), + Error::::PartialUnbondNotAllowedPermissionlessly + ); + + // or 0. + assert_noop!( + Pools::unbond(Origin::signed(random), 10, 20), + Error::::DoesNotHavePermission + ); + + // they themselves can do it in this case though. + assert_ok!(Pools::unbond(Origin::signed(10), 10, 20)); + }) + } + + #[test] + fn depositor_unbond_destroying_not_last_member() { + // deposit in pool, pool state destroying + // - depositor can never leave if there is another member in the pool. + ExtBuilder::default() + .min_join_bond(10) + .add_members(vec![(20, 20)]) + .build_and_execute(|| { + // give the depositor some extra funds. + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_eq!(PoolMembers::::get(10).unwrap().points, 20); + + // set the stage + unsafe_set_state(1, PoolState::Destroying); + + // can go above the limit + assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 15); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 5); + + // but not below the limit + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 10), + Error::::MinimumBondNotMet + ); + + // and certainly not zero + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 15), + Error::::MinimumBondNotMet + ); + }) + } + + #[test] + fn depositor_unbond_destroying_last_member() { + // deposit in pool, pool state destroying + // - depositor can unbond to above limit always. + // - depositor cannot unbond to below limit if last. + // - depositor can unbond to 0 if last and destroying. + ExtBuilder::default().min_join_bond(10).build_and_execute(|| { + // give the depositor some extra funds. + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_eq!(PoolMembers::::get(10).unwrap().points, 20); + + // set the stage + unsafe_set_state(1, PoolState::Destroying); + + // can unbond to above the limit. + assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 15); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 5); + + // still cannot go to below limit + assert_noop!(Pools::unbond(Origin::signed(10), 10, 10), Error::::MinimumBondNotMet); + + // can go to 0 too. + assert_ok!(Pools::unbond(Origin::signed(10), 10, 15)); + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 0); + assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 20); + }) + } + #[test] fn unbond_of_1_works() { ExtBuilder::default().build_and_execute(|| { - unsafe_set_state(1, PoolState::Destroying).unwrap(); + unsafe_set_state(1, PoolState::Destroying); assert_ok!(fully_unbond_permissioned(10)); assert_eq!( @@ -2021,7 +2281,7 @@ mod unbond { assert_eq!(Balances::free_balance(&40), 40 + 40); // We claim rewards when unbonding // When - unsafe_set_state(1, PoolState::Destroying).unwrap(); + unsafe_set_state(1, PoolState::Destroying); assert_ok!(fully_unbond_permissioned(550)); // Then @@ -2111,7 +2371,7 @@ mod unbond { }, }, ); - unsafe_set_state(1, PoolState::Destroying).unwrap(); + unsafe_set_state(1, PoolState::Destroying); // When let current_era = 1 + TotalUnbondingPools::::get(); @@ -2148,7 +2408,7 @@ mod unbond { .add_members(vec![(100, 100), (200, 200)]) .build_and_execute(|| { // Given - unsafe_set_state(1, PoolState::Blocked).unwrap(); + unsafe_set_state(1, PoolState::Blocked); let bonded_pool = BondedPool::::get(1).unwrap(); assert_eq!(bonded_pool.roles.root.unwrap(), 900); assert_eq!(bonded_pool.roles.nominator.unwrap(), 901); @@ -2216,7 +2476,7 @@ mod unbond { // Scenarios where non-admin accounts can unbond others ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { // Given the pool is blocked - unsafe_set_state(1, PoolState::Blocked).unwrap(); + unsafe_set_state(1, PoolState::Blocked); // A permissionless unbond attempt errors assert_noop!( @@ -2231,16 +2491,17 @@ mod unbond { ); // Given the pool is destroying - unsafe_set_state(1, PoolState::Destroying).unwrap(); + unsafe_set_state(1, PoolState::Destroying); // The depositor cannot be fully unbonded until they are the last member assert_noop!( Pools::fully_unbond(Origin::signed(10), 10), - Error::::NotOnlyPoolMember + Error::::MinimumBondNotMet, ); // Any account can unbond a member that is not the depositor assert_ok!(Pools::fully_unbond(Origin::signed(420), 100)); + assert_eq!( pool_events_since_last_call(), vec![ @@ -2258,7 +2519,7 @@ mod unbond { ); // Given the pool is blocked - unsafe_set_state(1, PoolState::Blocked).unwrap(); + unsafe_set_state(1, PoolState::Blocked); // The depositor cannot be unbonded assert_noop!( @@ -2267,7 +2528,7 @@ mod unbond { ); // Given the pools is destroying - unsafe_set_state(1, PoolState::Destroying).unwrap(); + unsafe_set_state(1, PoolState::Destroying); // The depositor cannot be unbonded yet. assert_noop!( @@ -2285,8 +2546,13 @@ mod unbond { Error::::PartialUnbondNotAllowedPermissionlessly, ); - // but full unbond works. - assert_ok!(Pools::fully_unbond(Origin::signed(420), 10)); + // depositor can never be unbonded permissionlessly . + assert_noop!( + Pools::fully_unbond(Origin::signed(420), 10), + Error::::DoesNotHavePermission + ); + // but depositor itself can do it. + assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); assert_eq!(BondedPools::::get(1).unwrap().points, 0); assert_eq!( @@ -2346,6 +2612,12 @@ mod unbond { #[test] fn partial_unbond_era_tracking() { ExtBuilder::default().build_and_execute(|| { + // to make the depositor capable of withdrawing. + StakingMinBond::set(1); + MinCreateBond::::set(1); + MinJoinBond::::set(1); + assert_eq!(Pools::depositor_min_bond(), 1); + // given assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 10); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 0); @@ -2360,7 +2632,7 @@ mod unbond { assert_eq!(BondingDuration::get(), 3); // so the depositor can leave, just keeps the test simpler. - unsafe_set_state(1, PoolState::Destroying).unwrap(); + unsafe_set_state(1, PoolState::Destroying); // when: casual unbond assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); @@ -2444,13 +2716,13 @@ mod unbond { ); // when: unbonding more than our active: error - assert_err!( + assert_noop!( frame_support::storage::in_storage_layer(|| Pools::unbond( Origin::signed(10), 10, 5 )), - Error::::NotEnoughPointsToUnbond + Error::::MinimumBondNotMet ); // instead: assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); @@ -2482,26 +2754,24 @@ mod unbond { #[test] fn partial_unbond_max_chunks() { - ExtBuilder::default().ed(1).build_and_execute(|| { - // so the depositor can leave, just keeps the test simpler. - unsafe_set_state(1, PoolState::Destroying).unwrap(); + ExtBuilder::default().add_members(vec![(20, 20)]).ed(1).build_and_execute(|| { MaxUnbonding::set(2); // given - assert_ok!(Pools::unbond(Origin::signed(10), 10, 2)); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 3)); assert_eq!( - PoolMembers::::get(10).unwrap().unbonding_eras, + PoolMembers::::get(20).unwrap().unbonding_eras, member_unbonding_eras!(3 => 2, 4 => 3) ); // when CurrentEra::set(2); - assert_err!( + assert_noop!( frame_support::storage::in_storage_layer(|| Pools::unbond( - Origin::signed(10), - 10, + Origin::signed(20), + 20, 4 )), Error::::MaxUnbondingLimit @@ -2509,30 +2779,35 @@ mod unbond { // when MaxUnbonding::set(3); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 1)); + assert_eq!( - PoolMembers::::get(10).unwrap().unbonding_eras, + PoolMembers::::get(20).unwrap().unbonding_eras, member_unbonding_eras!(3 => 2, 4 => 3, 5 => 1) ); + assert_eq!( pool_events_since_last_call(), vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, points: 2, balance: 2 }, - Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3 }, - Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1 } + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + Event::Unbonded { member: 20, pool_id: 1, balance: 2, points: 2 }, + Event::Unbonded { member: 20, pool_id: 1, balance: 3, points: 3 }, + Event::Unbonded { member: 20, pool_id: 1, balance: 1, points: 1 } ] ); }) } - // depositor can unbond inly up to `MinCreateBond`. + // depositor can unbond only up to `MinCreateBond`. #[test] fn depositor_permissioned_partial_unbond() { ExtBuilder::default().ed(1).build_and_execute(|| { // given - assert_eq!(MinCreateBond::::get(), 2); + StakingMinBond::set(5); + assert_eq!(Pools::depositor_min_bond(), 5); + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 10); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 0); @@ -2544,7 +2819,7 @@ mod unbond { // but not less than 2 assert_noop!( Pools::unbond(Origin::signed(10), 10, 6), - Error::::NotOnlyPoolMember + Error::::MinimumBondNotMet ); assert_eq!( @@ -2558,7 +2833,6 @@ mod unbond { }); } - // same as above, but the pool is slashed and therefore the depositor cannot partially unbond. #[test] fn depositor_permissioned_partial_unbond_slashed() { ExtBuilder::default().ed(1).build_and_execute(|| { @@ -2573,78 +2847,69 @@ mod unbond { // cannot unbond even 7, because the value of shares is now less. assert_noop!( Pools::unbond(Origin::signed(10), 10, 7), - Error::::NotOnlyPoolMember - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - Event::Created { depositor: 10, pool_id: 1 }, - Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - ] + Error::::MinimumBondNotMet ); }); } #[test] fn every_unbonding_triggers_payout() { - ExtBuilder::default().build_and_execute(|| { - let initial_reward_account = Balances::free_balance(Pools::create_reward_account(1)); + ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { + let initial_reward_account = Balances::free_balance(default_reward_account()); assert_eq!(initial_reward_account, Balances::minimum_balance()); assert_eq!(initial_reward_account, 5); - // set the pool to destroying so that depositor can leave. - unsafe_set_state(1, PoolState::Destroying).unwrap(); - Balances::make_free_balance_be( - &Pools::create_reward_account(1), - 2 * Balances::minimum_balance(), + &default_reward_account(), + 4 * Balances::minimum_balance(), ); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 2)); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); assert_eq!( pool_events_since_last_call(), vec![ + // 2/3 of ed, which is 20's share. Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - // exactly equal to ed, all that can be claimed. - Event::PaidOut { member: 10, pool_id: 1, payout: 5 }, - Event::Unbonded { member: 10, pool_id: 1, points: 2, balance: 2 } + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + Event::PaidOut { member: 20, pool_id: 1, payout: 10 }, + Event::Unbonded { member: 20, pool_id: 1, balance: 2, points: 2 } ] ); CurrentEra::set(1); Balances::make_free_balance_be( - &Pools::create_reward_account(1), - 2 * Balances::minimum_balance(), + &default_reward_account(), + 4 * Balances::minimum_balance(), ); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 3)); assert_eq!( pool_events_since_last_call(), vec![ - // exactly equal to ed, all that can be claimed. - Event::PaidOut { member: 10, pool_id: 1, payout: 5 }, - Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3 } + // 2/3 of ed, which is 20's share. + Event::PaidOut { member: 20, pool_id: 1, payout: 6 }, + Event::Unbonded { member: 20, pool_id: 1, points: 3, balance: 3 } ] ); CurrentEra::set(2); Balances::make_free_balance_be( - &Pools::create_reward_account(1), - 2 * Balances::minimum_balance(), + &default_reward_account(), + 4 * Balances::minimum_balance(), ); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); assert_eq!( pool_events_since_last_call(), vec![ - Event::PaidOut { member: 10, pool_id: 1, payout: 5 }, - Event::Unbonded { member: 10, pool_id: 1, points: 5, balance: 5 } + Event::PaidOut { member: 20, pool_id: 1, payout: 3 }, + Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5 } ] ); assert_eq!( - PoolMembers::::get(10).unwrap().unbonding_eras, + PoolMembers::::get(20).unwrap().unbonding_eras, member_unbonding_eras!(3 => 2, 4 => 3, 5 => 5) ); }); @@ -2801,7 +3066,7 @@ mod withdraw_unbonded { ); // now, finally, the depositor can take out its share. - unsafe_set_state(1, PoolState::Destroying).unwrap(); + unsafe_set_state(1, PoolState::Destroying); assert_ok!(fully_unbond_permissioned(10)); current_era += 3; @@ -2911,7 +3176,7 @@ mod withdraw_unbonded { assert!(SubPoolsStorage::::get(&1).unwrap().with_era.is_empty()); // now, finally, the depositor can take out its share. - unsafe_set_state(1, PoolState::Destroying).unwrap(); + unsafe_set_state(1, PoolState::Destroying); assert_ok!(fully_unbond_permissioned(10)); // because everyone else has left, the points @@ -2926,7 +3191,7 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); // then - assert_eq!(Balances::free_balance(&10), 10 + 5); + assert_eq!(Balances::free_balance(&10), 10 + 35); assert_eq!(Balances::free_balance(&default_bonded_account()), 0); // in this test 10 also gets a fair share of the slash, because the slash was @@ -2955,9 +3220,9 @@ mod withdraw_unbonded { ExtBuilder::default().build_and_execute(|| { // Given assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(Balances::free_balance(&10), 5); + assert_eq!(Balances::free_balance(&10), 35); assert_eq!(Balances::free_balance(&default_bonded_account()), 10); - unsafe_set_state(1, PoolState::Destroying).unwrap(); + unsafe_set_state(1, PoolState::Destroying); assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); // Simulate a slash that is not accounted for in the sub pools. @@ -2974,7 +3239,7 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); // Then - assert_eq!(Balances::free_balance(10), 10 + 5); + assert_eq!(Balances::free_balance(10), 10 + 35); assert_eq!(Balances::free_balance(&default_bonded_account()), 0); }); } @@ -3054,7 +3319,7 @@ mod withdraw_unbonded { ); // Given - unsafe_set_state(1, PoolState::Blocked).unwrap(); + unsafe_set_state(1, PoolState::Blocked); // Cannot kick as a nominator assert_noop!( @@ -3112,7 +3377,7 @@ mod withdraw_unbonded { ); // Given - unsafe_set_state(1, PoolState::Destroying).unwrap(); + unsafe_set_state(1, PoolState::Destroying); // Can permissionlesly withdraw a member that is not the depositor assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 100, 0)); @@ -3137,8 +3402,8 @@ mod withdraw_unbonded { #[test] fn partial_withdraw_unbonded_depositor() { ExtBuilder::default().ed(1).build_and_execute(|| { - // so the depositor can leave, just keeps the test simpler. - unsafe_set_state(1, PoolState::Destroying).unwrap(); + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + unsafe_set_state(1, PoolState::Destroying); // given assert_ok!(Pools::unbond(Origin::signed(10), 10, 6)); @@ -3158,13 +3423,14 @@ mod withdraw_unbonded { } } ); - assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 3); + assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 13); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 7); assert_eq!( pool_events_since_last_call(), vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: false }, Event::Unbonded { member: 10, pool_id: 1, points: 6, balance: 6 }, Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1 } ] @@ -3368,50 +3634,72 @@ mod withdraw_unbonded { #[test] fn full_multi_step_withdrawing_depositor() { ExtBuilder::default().ed(1).build_and_execute(|| { - // given + // depositor now has 20, they can unbond to 10. + assert_eq!(Pools::depositor_min_bond(), 10); + assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + + // now they can. assert_ok!(Pools::unbond(Origin::signed(10), 10, 7)); // progress one era and unbond the leftover. CurrentEra::set(1); - unsafe_set_state(1, PoolState::Destroying).unwrap(); assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_eq!( PoolMembers::::get(10).unwrap().unbonding_eras, member_unbonding_eras!(3 => 7, 4 => 3) ); + // they can't unbond to a value below 10 other than 0.. assert_noop!( - Pools::withdraw_unbonded(Origin::signed(10), 10, 0), - Error::::CannotWithdrawAny + Pools::unbond(Origin::signed(10), 10, 5), + Error::::MinimumBondNotMet ); + // but not even full, because they pool is not yet destroying. + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 10), + Error::::MinimumBondNotMet + ); + + // but now they can. + unsafe_set_state(1, PoolState::Destroying); + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 5), + Error::::MinimumBondNotMet + ); + assert_ok!(Pools::unbond(Origin::signed(10), 10, 10)); + // now the 7 should be free. CurrentEra::set(3); assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_eq!( pool_events_since_last_call(), vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, points: 7, balance: 7 }, - Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3 }, - Event::Withdrawn { member: 10, pool_id: 1, points: 7, balance: 7 } + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: false }, + Event::Unbonded { member: 10, pool_id: 1, balance: 7, points: 7 }, + Event::Unbonded { member: 10, pool_id: 1, balance: 3, points: 3 }, + Event::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10 }, + Event::Withdrawn { member: 10, pool_id: 1, balance: 7, points: 7 } ] ); assert_eq!( PoolMembers::::get(10).unwrap().unbonding_eras, - member_unbonding_eras!(4 => 3) + member_unbonding_eras!(4 => 13) ); - // the 25 should be free now, and the member removed. + // the 13 should be free now, and the member removed. CurrentEra::set(4); assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_eq!( pool_events_since_last_call(), vec![ - Event::Withdrawn { member: 10, pool_id: 1, points: 3, balance: 3 }, + Event::Withdrawn { member: 10, pool_id: 1, points: 13, balance: 13 }, Event::MemberRemoved { pool_id: 1, member: 10 }, - // the pool is also destroyed now. Event::Destroyed { pool_id: 1 }, ] ); @@ -3640,7 +3928,7 @@ mod set_state { // If the pool is not ok to be open, then anyone can set it to destroying // Given - unsafe_set_state(1, PoolState::Open).unwrap(); + unsafe_set_state(1, PoolState::Open); let mut bonded_pool = BondedPool::::get(1).unwrap(); bonded_pool.points = 100; bonded_pool.put(); @@ -3651,7 +3939,7 @@ mod set_state { // Given Balances::make_free_balance_be(&default_bonded_account(), Balance::max_value() / 10); - unsafe_set_state(1, PoolState::Open).unwrap(); + unsafe_set_state(1, PoolState::Open); // When assert_ok!(Pools::set_state(Origin::signed(11), 1, PoolState::Destroying)); // Then @@ -3659,7 +3947,7 @@ mod set_state { // If the pool is not ok to be open, it cannot be permissionleslly set to a state that // isn't destroying - unsafe_set_state(1, PoolState::Open).unwrap(); + unsafe_set_state(1, PoolState::Open); assert_noop!( Pools::set_state(Origin::signed(11), 1, PoolState::Blocked), Error::::CanNotChangeState @@ -3820,13 +4108,13 @@ mod bond_extra { // given assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(BondedPools::::get(1).unwrap().points, 10); - assert_eq!(Balances::free_balance(10), 5); + assert_eq!(Balances::free_balance(10), 35); // when assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::Rewards)); // then - assert_eq!(Balances::free_balance(10), 5); + assert_eq!(Balances::free_balance(10), 35); assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + claimable_reward); assert_eq!(BondedPools::::get(1).unwrap().points, 10 + claimable_reward); @@ -3862,14 +4150,14 @@ mod bond_extra { assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(PoolMembers::::get(20).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 30); - assert_eq!(Balances::free_balance(10), 5); + assert_eq!(Balances::free_balance(10), 35); assert_eq!(Balances::free_balance(20), 20); // when assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::Rewards)); // then - assert_eq!(Balances::free_balance(10), 5); + assert_eq!(Balances::free_balance(10), 35); // 10's share of the reward is 1/3, since they gave 10/30 of the total shares. assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + 1); assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 1); diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs index 3b9350f25040b..eed8e5fd390cd 100644 --- a/frame/nomination-pools/test-staking/src/lib.rs +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -72,7 +72,7 @@ fn pool_lifecycle_e2e() { // depositor cannot unbond yet. assert_noop!( Pools::unbond(Origin::signed(10), 10, 50), - PoolsError::::NotOnlyPoolMember, + PoolsError::::MinimumBondNotMet, ); // now the members want to unbond. @@ -103,7 +103,7 @@ fn pool_lifecycle_e2e() { // depositor cannot still unbond assert_noop!( Pools::unbond(Origin::signed(10), 10, 50), - PoolsError::::NotOnlyPoolMember, + PoolsError::::MinimumBondNotMet, ); for e in 1..BondingDuration::get() { @@ -120,7 +120,7 @@ fn pool_lifecycle_e2e() { // depositor cannot still unbond assert_noop!( Pools::unbond(Origin::signed(10), 10, 50), - PoolsError::::NotOnlyPoolMember, + PoolsError::::MinimumBondNotMet, ); // but members can now withdraw. From 37cca710eed3dadd4ed5364c7686608f5175cce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 14 Jul 2022 20:14:28 +0200 Subject: [PATCH 0969/1472] contracts: Composable `ChainExtension` (#11816) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add `RegisteredChainExtension` * Add tests * Update frame/contracts/src/chain_extension.rs Co-authored-by: Michael Müller * Add more docs * Remove debugging leftover * Make ChainExtension-registry lowercase * Apply suggestions from code review Co-authored-by: Hernando Castano * Improve clarity of test inputs Co-authored-by: Michael Müller Co-authored-by: Hernando Castano --- Cargo.lock | 1 + frame/contracts/Cargo.toml | 1 + frame/contracts/fixtures/chain_extension.wat | 10 +- frame/contracts/src/chain_extension.rs | 59 ++++++- frame/contracts/src/tests.rs | 175 +++++++++++++++++-- 5 files changed, 216 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b7c315be4390..791d8037f3335 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5505,6 +5505,7 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", + "impl-trait-for-tuples", "log", "pallet-balances", "pallet-contracts-primitives", diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index d27801df33bda..ac85c469354fe 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -26,6 +26,7 @@ smallvec = { version = "1", default-features = false, features = [ "const_generics", ] } wasmi-validation = { version = "0.4", default-features = false } +impl-trait-for-tuples = "0.2" # Only used in benchmarking to generate random contract code rand = { version = "0.8", optional = true, default-features = false } diff --git a/frame/contracts/fixtures/chain_extension.wat b/frame/contracts/fixtures/chain_extension.wat index db7e83fd96b42..9b2534c540ab8 100644 --- a/frame/contracts/fixtures/chain_extension.wat +++ b/frame/contracts/fixtures/chain_extension.wat @@ -15,12 +15,12 @@ ) ;; [0, 4) len of input output - (data (i32.const 0) "\02") + (data (i32.const 0) "\08") ;; [4, 12) buffer for input - ;; [12, 16) len of output buffer - (data (i32.const 12) "\02") + ;; [12, 48) len of output buffer + (data (i32.const 12) "\20") ;; [16, inf) buffer for output @@ -31,7 +31,7 @@ ;; the chain extension passes through the input and returns it as output (call $seal_call_chain_extension - (i32.load8_u (i32.const 4)) ;; func_id + (i32.load (i32.const 4)) ;; func_id (i32.const 4) ;; input_ptr (i32.load (i32.const 0)) ;; input_len (i32.const 16) ;; output_ptr @@ -39,7 +39,7 @@ ) ;; the chain extension passes through the func_id - (call $assert (i32.eq (i32.load8_u (i32.const 4)))) + (call $assert (i32.eq (i32.load (i32.const 4)))) (call $seal_return (i32.const 0) (i32.const 16) (i32.load (i32.const 12))) ) diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index ed447719933be..536d58c94f68f 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -29,6 +29,22 @@ //! required for this endeavour are defined or re-exported in this module. There is an //! implementation on `()` which can be used to signal that no chain extension is available. //! +//! # Using multiple chain extensions +//! +//! Often there is a need for having multiple chain extensions. This is often the case when +//! some generally useful off-the-shelf extensions should be included. To have multiple chain +//! extensions they can be put into a tuple which is then passed to `[Config::ChainExtension]` like +//! this `type Extensions = (ExtensionA, ExtensionB)`. +//! +//! However, only extensions implementing [`RegisteredChainExtension`] can be put into a tuple. +//! This is because the [`RegisteredChainExtension::ID`] is used to decide which of those extensions +//! should should be used when the contract calls a chain extensions. Extensions which are generally +//! useful should claim their `ID` with [the registry](https://github.com/paritytech/chainextension-registry) +//! so that no collisions with other vendors will occur. +//! +//! **Chain specific extensions must use the reserved `ID = 0` so that they can't be registered with +//! the registry.** +//! //! # Security //! //! The chain author alone is responsible for the security of the chain extension. @@ -112,20 +128,51 @@ pub trait ChainExtension { } } -/// Implementation that indicates that no chain extension is available. -impl ChainExtension for () { - fn call(_func_id: u32, mut _env: Environment) -> Result +/// A [`ChainExtension`] that can be composed with other extensions using a tuple. +/// +/// An extension that implements this trait can be put in a tuple in order to have multiple +/// extensions available. The tuple implementation routes requests based on the first two +/// most significant bytes of the `func_id` passed to `call`. +/// +/// If this extensions is to be used by multiple runtimes consider +/// [registering it](https://github.com/paritytech/chainextension-registry) to ensure that there +/// are no collisions with other vendors. +/// +/// # Note +/// +/// Currently, we support tuples of up to ten registred chain extensions. If more chain extensions +/// are needed consider opening an issue. +pub trait RegisteredChainExtension: ChainExtension { + /// The extensions globally unique identifier. + const ID: u16; +} + +#[impl_trait_for_tuples::impl_for_tuples(10)] +#[tuple_types_custom_trait_bound(RegisteredChainExtension)] +impl ChainExtension for Tuple { + fn call(func_id: u32, mut env: Environment) -> Result where E: Ext, ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { - // Never called since [`Self::enabled()`] is set to `false`. Because we want to - // avoid panics at all costs we supply a sensible error value here instead - // of an `unimplemented!`. + for_tuples!( + #( + if (Tuple::ID == (func_id >> 16) as u16) && Tuple::enabled() { + return Tuple::call(func_id, env); + } + )* + ); Err(Error::::NoChainExtension.into()) } fn enabled() -> bool { + for_tuples!( + #( + if Tuple::enabled() { + return true; + } + )* + ); false } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index bbac18142a658..85a0e9977d2d7 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -17,8 +17,8 @@ use crate::{ chain_extension::{ - ChainExtension, Environment, Ext, InitState, Result as ExtensionResult, RetVal, - ReturnFlags, SysConfig, UncheckedFrom, + ChainExtension, Environment, Ext, InitState, RegisteredChainExtension, + Result as ExtensionResult, RetVal, ReturnFlags, SysConfig, UncheckedFrom, }, exec::{FixSizedKey, Frame}, storage::Storage, @@ -118,6 +118,10 @@ pub struct TestExtension { last_seen_inputs: (u32, u32, u32, u32), } +pub struct RevertingExtension; + +pub struct DisabledExtension; + impl TestExtension { fn disable() { TEST_EXTENSION.with(|e| e.borrow_mut().enabled = false) @@ -147,7 +151,7 @@ impl ChainExtension for TestExtension { match func_id { 0 => { let mut env = env.buf_in_buf_out(); - let input = env.read(2)?; + let input = env.read(8)?; env.write(&input, false, None)?; TEST_EXTENSION.with(|e| e.borrow_mut().last_seen_buffer = input); Ok(RetVal::Converging(func_id)) @@ -162,7 +166,7 @@ impl ChainExtension for TestExtension { }, 2 => { let mut env = env.buf_in_buf_out(); - let weight = env.read(2)?[1].into(); + let weight = env.read(5)?[4].into(); env.charge_weight(weight)?; Ok(RetVal::Converging(func_id)) }, @@ -178,6 +182,46 @@ impl ChainExtension for TestExtension { } } +impl RegisteredChainExtension for TestExtension { + const ID: u16 = 0; +} + +impl ChainExtension for RevertingExtension { + fn call(_func_id: u32, _env: Environment) -> ExtensionResult + where + E: Ext, + ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, + { + Ok(RetVal::Diverging { flags: ReturnFlags::REVERT, data: vec![0x4B, 0x1D] }) + } + + fn enabled() -> bool { + TEST_EXTENSION.with(|e| e.borrow().enabled) + } +} + +impl RegisteredChainExtension for RevertingExtension { + const ID: u16 = 1; +} + +impl ChainExtension for DisabledExtension { + fn call(_func_id: u32, _env: Environment) -> ExtensionResult + where + E: Ext, + ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, + { + panic!("Disabled chain extensions are never called") + } + + fn enabled() -> bool { + false + } +} + +impl RegisteredChainExtension for DisabledExtension { + const ID: u16 = 2; +} + parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND); @@ -281,7 +325,7 @@ impl Config for Test { type CallStack = [Frame; 31]; type WeightPrice = Self; type WeightInfo = (); - type ChainExtension = TestExtension; + type ChainExtension = (TestExtension, DisabledExtension, RevertingExtension); type DeletionQueueDepth = ConstU32<1024>; type DeletionWeightLimit = ConstU64<500_000_000_000>; type Schedule = MySchedule; @@ -1523,6 +1567,23 @@ fn disabled_chain_extension_errors_on_call() { #[test] fn chain_extension_works() { + struct Input<'a> { + extension_id: u16, + func_id: u16, + extra: &'a [u8], + } + + impl<'a> From> for Vec { + fn from(input: Input) -> Vec { + ((input.extension_id as u32) << 16 | (input.func_id as u32)) + .to_le_bytes() + .iter() + .chain(input.extra) + .cloned() + .collect() + } + } + let (code, hash) = compile_module::("chain_extension").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let min_balance = ::Currency::minimum_balance(); @@ -1543,31 +1604,107 @@ fn chain_extension_works() { // func_id. // 0 = read input buffer and pass it through as output + let input: Vec = Input { extension_id: 0, func_id: 0, extra: &[99] }.into(); let result = - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![0, 99], false); - let gas_consumed = result.gas_consumed; - assert_eq!(TestExtension::last_seen_buffer(), vec![0, 99]); - assert_eq!(result.result.unwrap().data, Bytes(vec![0, 99])); + Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false); + assert_eq!(TestExtension::last_seen_buffer(), input); + assert_eq!(result.result.unwrap().data, Bytes(input)); // 1 = treat inputs as integer primitives and store the supplied integers - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![1], false) - .result - .unwrap(); + Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + Input { extension_id: 0, func_id: 1, extra: &[] }.into(), + false, + ) + .result + .unwrap(); // those values passed in the fixture - assert_eq!(TestExtension::last_seen_inputs(), (4, 1, 16, 12)); + assert_eq!(TestExtension::last_seen_inputs(), (4, 4, 16, 12)); - // 2 = charge some extra weight (amount supplied in second byte) - let result = - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![2, 42], false); + // 2 = charge some extra weight (amount supplied in the fifth byte) + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + Input { extension_id: 0, func_id: 2, extra: &[0] }.into(), + false, + ); + assert_ok!(result.result); + let gas_consumed = result.gas_consumed; + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + Input { extension_id: 0, func_id: 2, extra: &[42] }.into(), + false, + ); assert_ok!(result.result); assert_eq!(result.gas_consumed, gas_consumed + 42); + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + Input { extension_id: 0, func_id: 2, extra: &[95] }.into(), + false, + ); + assert_ok!(result.result); + assert_eq!(result.gas_consumed, gas_consumed + 95); // 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer - let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![3], false) - .result - .unwrap(); + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + Input { extension_id: 0, func_id: 3, extra: &[] }.into(), + false, + ) + .result + .unwrap(); assert_eq!(result.flags, ReturnFlags::REVERT); assert_eq!(result.data, Bytes(vec![42, 99])); + + // diverging to second chain extension that sets flags to 0x1 and returns a fixed buffer + // We set the MSB part to 1 (instead of 0) which routes the request into the second + // extension + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + Input { extension_id: 1, func_id: 0, extra: &[] }.into(), + false, + ) + .result + .unwrap(); + assert_eq!(result.flags, ReturnFlags::REVERT); + assert_eq!(result.data, Bytes(vec![0x4B, 0x1D])); + + // Diverging to third chain extension that is disabled + // We set the MSB part to 2 (instead of 0) which routes the request into the third extension + assert_err_ignore_postinfo!( + Contracts::call( + Origin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + Input { extension_id: 2, func_id: 0, extra: &[] }.into(), + ), + Error::::NoChainExtension, + ); }); } From 4400af779a733417c5bba098e30fd2e809af465f Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Fri, 15 Jul 2022 09:42:40 +0200 Subject: [PATCH 0970/1472] [ci] fix job `cancel-pipeline` (#11844) * [ci] fix cancel-pipeline job * test fail * remove debug --- .gitlab-ci.yml | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b4933333b3418..fba7b7a9d393f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -234,23 +234,42 @@ rusty-cachier-notify: # This job cancels the whole pipeline if any of provided jobs fail. # In a DAG, every jobs chain is executed independently of others. The `fail_fast` principle suggests # to fail the pipeline as soon as possible to shorten the feedback loop. -cancel-pipeline: +.cancel-pipeline-template: stage: .post + rules: + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + when: on_failure + variables: + PROJECT_ID: "${CI_PROJECT_ID}" + PIPELINE_ID: "${CI_PIPELINE_ID}" + trigger: "parity/infrastructure/ci_cd/pipeline-stopper" + +cancel-pipeline-test-linux-stable: + extends: .cancel-pipeline-template needs: - job: test-linux-stable artifacts: false + +cancel-pipeline-test-linux-stable-int: + extends: .cancel-pipeline-template + needs: - job: test-linux-stable-int artifacts: false + +cancel-pipeline-cargo-check-subkey: + extends: .cancel-pipeline-template + needs: - job: cargo-check-subkey artifacts: false + +cancel-pipeline-cargo-check-benches: + extends: .cancel-pipeline-template + needs: - job: cargo-check-benches artifacts: false + +cancel-pipeline-check-tracing: + extends: .cancel-pipeline-template + needs: - job: check-tracing artifacts: false - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - when: on_failure - variables: - PROJECT_ID: "${CI_PROJECT_ID}" - PIPELINE_ID: "${CI_PIPELINE_ID}" - trigger: "parity/infrastructure/ci_cd/pipeline-stopper" From 6eca5272deb30ca1abe9782ce8918bfb9047728c Mon Sep 17 00:00:00 2001 From: Vlad Date: Fri, 15 Jul 2022 10:58:53 +0300 Subject: [PATCH 0971/1472] Speed up `rusty-cachier-notify` job (#11841) * Speed up `rusty-cachier-notify` job * Don't forget to setup `rusty-cachier` first --- .gitlab-ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fba7b7a9d393f..9e80277404549 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -223,10 +223,15 @@ deploy-prometheus-alerting-rules: # This job notifies rusty-cachier about the latest commit with the cache. # This info is later used for the cache distribution and an overlay creation. +# Note that we don't use any .rusty-cachier references as we assume that a pipeline has reached this stage with working rusty-cachier. rusty-cachier-notify: stage: notify - extends: .docker-env + extends: .kubernetes-env + variables: + CI_IMAGE: paritytech/rusty-cachier-env:latest + GIT_STRATEGY: none script: + - curl -s https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.parity.io/parity/infrastructure/ci_cd/rusty-cachier/client/-/raw/release/util/install.sh | bash - rusty-cachier cache notify #### stage: .post From 66d2023925e28d7bc880dad5d38b5a0b0ed03855 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Fri, 15 Jul 2022 10:44:46 +0200 Subject: [PATCH 0972/1472] [ci] improvments to make pipeline faster (#11829) * [DO NOT MERGE] test-linux-stable parallel on 3 ci nodes * add debug message * adjust rusty-cachier * empty commit * move test-linux-stable to test.yml * make cargo-check-benches and test-wasmer-sandbox parallel * fix comment * Update scripts/ci/gitlab/pipeline/test.yml Co-authored-by: Denis Pisarev * Update scripts/ci/gitlab/pipeline/test.yml Co-authored-by: Denis Pisarev * if to case * use case instead if in cargo-check-benches * format * add comments to output * add comment * add quotes * Update scripts/ci/gitlab/pipeline/test.yml Co-authored-by: Denis Pisarev Co-authored-by: parity-processbot <> Co-authored-by: Denis Pisarev --- .gitlab-ci.yml | 1 - scripts/ci/gitlab/pipeline/test.yml | 58 ++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9e80277404549..fff11e07326d8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -196,7 +196,6 @@ include: # publish jobs - scripts/ci/gitlab/pipeline/publish.yml - #### stage: deploy deploy-prometheus-alerting-rules: diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index cc167410f94a4..dcec896ddc18b 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -74,7 +74,9 @@ cargo-check-nixos: cargo-check-benches: stage: test variables: - RUSTY_CACHIER_TOOLCHAIN: nightly + # Override to use nightly toolchain + RUSTY_CACHIER_TOOLCHAIN: "nightly" + CI_JOB_NAME: "cargo-check-benches" extends: - .docker-env - .test-refs @@ -91,16 +93,25 @@ cargo-check-benches: git config user.email "ci@gitlab.parity.io"; git merge $CI_COMMIT_REF_NAME --verbose --no-edit; fi + parallel: 2 script: - rusty-cachier snapshot create - mkdir -p ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA - - SKIP_WASM_BUILD=1 time cargo +nightly check --benches --all - - 'cargo run --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json - | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::native::sr25519::transfer_keep_alive::paritydb::small.json' - - 'cargo run --release -p node-bench -- ::trie::read::small --json - | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json' - - sccache -s - - rusty-cachier cache upload + # this job is executed in parallel on two runners + - echo "___Running benchmarks___"; + - case ${CI_NODE_INDEX} in + 1) + SKIP_WASM_BUILD=1 time cargo +nightly check --benches --all; + cargo run --release -p node-bench -- ::trie::read::small --json + | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json; + echo "___Uploading cache for rusty-cachier___"; + rusty-cachier cache upload + ;; + 2) + cargo run --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json + | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::native::sr25519::transfer_keep_alive::paritydb::small.json + ;; + esac tags: - linux-docker-benches @@ -116,7 +127,7 @@ node-bench-regression-guard: # this is a DAG - job: cargo-check-benches artifacts: true - # this does not like a DAG, just polls the artifact + # polls artifact from master to compare with current result - project: $CI_PROJECT_PATH job: cargo-check-benches ref: master @@ -213,14 +224,27 @@ test-linux-stable: WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" # Ensure we run the UI tests. RUN_UI_TESTS: 1 + # needed for rusty-cachier to keep cache in test-linux-stable folder and not in test-linux-stable-1/3 + CI_JOB_NAME: "test-linux-stable" + parallel: 3 script: - rusty-cachier snapshot create - # TODO: add to paritytech/ci-linux image + # TODO: remove when current paritytech/ci-linux:staging (with rust stable 1.62) is switched to production - time cargo install cargo-nextest # this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests + # tests are partitioned by nextest and executed in parallel on $CI_NODE_TOTAL runners # node-cli is excluded until https://github.com/paritytech/substrate/issues/11321 fixed - - time cargo nextest run --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml --exclude node-cli - - rusty-cachier cache upload + - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" + - time cargo nextest run --workspace + --locked + --release + --verbose + --features runtime-benchmarks + --manifest-path ./bin/node/cli/Cargo.toml + --exclude node-cli + --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} + # we need to update cache only from one job + - if [ ${CI_NODE_INDEX} == 1 ]; then rusty-cachier cache upload; fi test-frame-support: stage: test @@ -356,10 +380,16 @@ test-wasmer-sandbox: extends: - .docker-env - .test-refs-wasmer-sandbox + variables: + CI_JOB_NAME: "test-wasmer-sandbox" + parallel: 3 script: - rusty-cachier snapshot create - - time cargo test --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests - - rusty-cachier cache upload + # TODO: remove when current paritytech/ci-linux:staging (with rust stable 1.62) is switched to production + - cargo install cargo-nextest + - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" + - time cargo nextest run --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} + - if [ ${CI_NODE_INDEX} == 1 ]; then rusty-cachier cache upload; fi cargo-check-macos: stage: test From 4a19d408095ebcb47840ad1f2f086f53a0020cb7 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 15 Jul 2022 13:55:18 +0200 Subject: [PATCH 0973/1472] Fixed sync target detection (#11817) * Fixed sync target detection * Always report sync_target metric * Clamp median across all peers --- client/network/sync/src/lib.rs | 9 +++++++-- client/service/src/metrics.rs | 7 ++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index aff773bd12ed6..2f837cd6c4f51 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -1719,7 +1719,7 @@ where Ok(sync) } - /// Returns the best seen block. + /// Returns the best seen block number if we don't have that block yet, `None` otherwise. fn best_seen(&self) -> Option> { let mut best_seens = self.peers.values().map(|p| p.best_number).collect::>(); @@ -1729,7 +1729,12 @@ where let middle = best_seens.len() / 2; // Not the "perfect median" when we have an even number of peers. - Some(*best_seens.select_nth_unstable(middle).1) + let median = *best_seens.select_nth_unstable(middle).1; + if median > self.best_queued_number { + Some(median) + } else { + None + } } } diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index 555023f894488..56b145ccdf7f7 100644 --- a/client/service/src/metrics.rs +++ b/client/service/src/metrics.rs @@ -298,9 +298,10 @@ impl MetricsService { UniqueSaturatedInto::::unique_saturated_into(num) }); - if let Some(best_seen_block) = best_seen_block { - metrics.block_height.with_label_values(&["sync_target"]).set(best_seen_block); - } + metrics + .block_height + .with_label_values(&["sync_target"]) + .set(best_seen_block.unwrap_or(best_number)); } } } From ddfd02ef2e71f3b80564ae8807aac5a46f6c7134 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sun, 17 Jul 2022 00:24:46 +0300 Subject: [PATCH 0974/1472] Ignore boot and reserved nodes with peer ID the same as in local node itself (#11851) --- client/network/src/service.rs | 45 +++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/client/network/src/service.rs b/client/network/src/service.rs index ef7ef2f5a2deb..0d28b50df1821 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -148,6 +148,47 @@ where /// for the network processing to advance. From it, you can extract a `NetworkService` using /// `worker.service()`. The `NetworkService` can be shared through the codebase. pub fn new(mut params: Params) -> Result { + // Private and public keys configuration. + let local_identity = params.network_config.node_key.clone().into_keypair()?; + let local_public = local_identity.public(); + let local_peer_id = local_public.to_peer_id(); + + params.network_config.boot_nodes = params + .network_config + .boot_nodes + .into_iter() + .filter(|boot_node| { + if boot_node.peer_id == local_peer_id { + warn!( + target: "sub-libp2p", + "Local peer ID used in bootnode, ignoring: {}", + boot_node, + ); + false + } else { + true + } + }) + .collect(); + params.network_config.default_peers_set.reserved_nodes = params + .network_config + .default_peers_set + .reserved_nodes + .into_iter() + .filter(|reserved_node| { + if reserved_node.peer_id == local_peer_id { + warn!( + target: "sub-libp2p", + "Local peer ID used in reserved node, ignoring: {}", + reserved_node, + ); + false + } else { + true + } + }) + .collect(); + // Ensure the listen addresses are consistent with the transport. ensure_addresses_consistent_with_transport( params.network_config.listen_addresses.iter(), @@ -190,10 +231,6 @@ where .extra_sets .insert(0, transactions_handler_proto.set_config()); - // Private and public keys configuration. - let local_identity = params.network_config.node_key.clone().into_keypair()?; - let local_public = local_identity.public(); - let local_peer_id = local_public.to_peer_id(); info!( target: "sub-libp2p", "🏷 Local node identity is: {}", From 6f652840cc78629ac149bf36d23ab34345c65331 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Sun, 17 Jul 2022 00:38:38 +0300 Subject: [PATCH 0975/1472] removed evaluation.rs (#11766) * removed evaluation.rs * no need for parent_hash * fix --- .../basic-authorship/src/basic_authorship.rs | 12 +-- primitives/consensus/common/src/evaluation.rs | 74 ------------------- primitives/consensus/common/src/lib.rs | 1 - 3 files changed, 1 insertion(+), 86 deletions(-) delete mode 100644 primitives/consensus/common/src/evaluation.rs diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index b67008bc6f44b..bc328c40edb3c 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -34,9 +34,7 @@ use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_INFO}; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed, HeaderBackend}; -use sp_consensus::{ - evaluation, DisableProofRecording, EnableProofRecording, ProofRecording, Proposal, -}; +use sp_consensus::{DisableProofRecording, EnableProofRecording, ProofRecording, Proposal}; use sp_core::traits::SpawnNamed; use sp_inherents::InherentData; use sp_runtime::{ @@ -205,7 +203,6 @@ where let proposer = Proposer::<_, _, _, _, PR> { spawn_handle: self.spawn_handle.clone(), client: self.client.clone(), - parent_hash, parent_id: id, parent_number: *parent_header.number(), transaction_pool: self.transaction_pool.clone(), @@ -250,7 +247,6 @@ where pub struct Proposer { spawn_handle: Box, client: Arc, - parent_hash: ::Hash, parent_id: BlockId, parent_number: <::Header as HeaderT>::Number, transaction_pool: Arc, @@ -536,12 +532,6 @@ where "hash" => ?::Hash::from(block.header().hash()), ); - if let Err(err) = - evaluation::evaluate_initial(&block, &self.parent_hash, self.parent_number) - { - error!("Failed to evaluate authored block: {:?}", err); - } - let proof = PR::into_proof(proof).map_err(|e| sp_blockchain::Error::Application(Box::new(e)))?; diff --git a/primitives/consensus/common/src/evaluation.rs b/primitives/consensus/common/src/evaluation.rs deleted file mode 100644 index d1ce8e9fc5109..0000000000000 --- a/primitives/consensus/common/src/evaluation.rs +++ /dev/null @@ -1,74 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Block evaluation and evaluation errors. - -use codec::Encode; -use sp_runtime::traits::{Block as BlockT, CheckedConversion, Header as HeaderT, One}; - -// This is just a best effort to encode the number. None indicated that it's too big to encode -// in a u128. -type BlockNumber = Option; - -/// Result type alias. -pub type Result = std::result::Result; - -/// Error type. -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("Failed to verify block encoding/decoding")] - BadBlockCodec, - /// Proposal provided not a block. - #[error("Proposal provided not a block: decoding error: {0}")] - BadProposalFormat(#[from] codec::Error), - /// Proposal had wrong parent hash. - #[error("Proposal had wrong parent hash. Expected {expected:?}, got {got:?}")] - WrongParentHash { expected: String, got: String }, - /// Proposal had wrong number. - #[error("Proposal had wrong number. Expected {expected:?}, got {got:?}")] - WrongNumber { expected: BlockNumber, got: BlockNumber }, -} - -/// Attempt to evaluate a substrate block as a node block, returning error -/// upon any initial validity checks failing. -pub fn evaluate_initial( - proposal: &Block, - parent_hash: &::Hash, - parent_number: <::Header as HeaderT>::Number, -) -> Result<()> { - let encoded = Encode::encode(proposal); - let block = Block::decode(&mut &encoded[..]).map_err(Error::BadProposalFormat)?; - if &block != proposal { - return Err(Error::BadBlockCodec) - } - - if *parent_hash != *block.header().parent_hash() { - return Err(Error::WrongParentHash { - expected: format!("{:?}", *parent_hash), - got: format!("{:?}", block.header().parent_hash()), - }) - } - - if parent_number + One::one() != *block.header().number() { - return Err(Error::WrongNumber { - expected: parent_number.checked_into::().map(|x| x + 1), - got: (*block.header().number()).checked_into::(), - }) - } - - Ok(()) -} diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index 2743f434c209b..4539cec2c8e0a 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -33,7 +33,6 @@ use sp_state_machine::StorageProof; pub mod block_validation; pub mod error; -pub mod evaluation; mod select_chain; pub use self::error::Error; From 62a7f2a7db20516673af63884fc83ced4f5d29cf Mon Sep 17 00:00:00 2001 From: lumir-mrkva Date: Sun, 17 Jul 2022 21:28:32 +0200 Subject: [PATCH 0976/1472] assert noop notifies that storage has been mutated (#11805) --- frame/support/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index f2cd7d1e165ec..8e43df82a284c 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -679,7 +679,7 @@ macro_rules! assert_noop { ) => { let h = $crate::storage_root($crate::StateVersion::V1); $crate::assert_err!($x, $y); - assert_eq!(h, $crate::storage_root($crate::StateVersion::V1)); + assert_eq!(h, $crate::storage_root($crate::StateVersion::V1), "storage has been mutated"); }; } @@ -826,6 +826,7 @@ pub mod tests { pub struct Module for enum Call where origin: T::Origin, system=self {} } } + use self::module::Module; decl_storage! { @@ -851,6 +852,7 @@ pub mod tests { } struct Test; + impl Config for Test { type BlockNumber = u32; type Origin = u32; @@ -867,6 +869,7 @@ pub mod tests { trait Sorted { fn sorted(self) -> Self; } + impl Sorted for Vec { fn sorted(mut self) -> Self { self.sort(); From d2c1c5f36faf0950bd0de467a2d38682eab1dc38 Mon Sep 17 00:00:00 2001 From: yjh Date: Mon, 18 Jul 2022 06:43:04 +0800 Subject: [PATCH 0977/1472] arrange node-template service (#11795) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * make template more clear * fmt check_equivocation Co-authored-by: Bastian Köcher --- bin/node-template/node/src/service.rs | 34 ++++++++++++------------ client/consensus/slots/src/aux_schema.rs | 6 ++--- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index f45f914d94f44..ffb2440caa0ed 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -296,24 +296,24 @@ pub fn new_full(mut config: Configuration) -> Result .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.sync_keystore()) } else { None }; - - let grandpa_config = sc_finality_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 { + // 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.sync_keystore()) } else { None }; + + let grandpa_config = sc_finality_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, + }; + // 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 diff --git a/client/consensus/slots/src/aux_schema.rs b/client/consensus/slots/src/aux_schema.rs index eeaec68d369d2..c1d01500ffe47 100644 --- a/client/consensus/slots/src/aux_schema.rs +++ b/client/consensus/slots/src/aux_schema.rs @@ -89,8 +89,8 @@ where // 1) signed by the same voter, if prev_signer == signer { // 2) with different hash - if header.hash() != prev_header.hash() { - return Ok(Some(EquivocationProof { + return if header.hash() != prev_header.hash() { + Ok(Some(EquivocationProof { slot, offender: signer.clone(), first_header: prev_header.clone(), @@ -100,7 +100,7 @@ where // We don't need to continue in case of duplicated header, // since it's already saved and a possible equivocation // would have been detected before. - return Ok(None) + Ok(None) } } } From 64b0daa64d983738229af08f130f20aafc371a17 Mon Sep 17 00:00:00 2001 From: cheme Date: Mon, 18 Jul 2022 00:57:13 +0200 Subject: [PATCH 0978/1472] Expose and link trie migration weights (#11775) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * expose and link trie migration weights * actually limit to one trait * Run test on dummy weights * fmt Co-authored-by: Bastian Köcher --- frame/state-trie-migration/src/lib.rs | 69 +++++++++++++-------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 9ac128a0e3108..94f6c1f223b9c 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -56,6 +56,7 @@ #![cfg_attr(not(feature = "std"), no_std)] pub use pallet::*; +pub mod weights; const LOG_TARGET: &str = "runtime::state-trie-migration"; @@ -71,6 +72,9 @@ macro_rules! log { #[frame_support::pallet] pub mod pallet { + + pub use crate::weights::WeightInfo; + use frame_support::{ dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, ensure, @@ -90,41 +94,6 @@ pub mod pallet { pub(crate) type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; - /// The weight information of this pallet. - pub trait WeightInfo { - fn process_top_key(x: u32) -> Weight; - fn continue_migrate() -> Weight; - fn continue_migrate_wrong_witness() -> Weight; - fn migrate_custom_top_fail() -> Weight; - fn migrate_custom_top_success() -> Weight; - fn migrate_custom_child_fail() -> Weight; - fn migrate_custom_child_success() -> Weight; - } - - impl WeightInfo for () { - fn process_top_key(_: u32) -> Weight { - 1000000 - } - fn continue_migrate() -> Weight { - 1000000 - } - fn continue_migrate_wrong_witness() -> Weight { - 1000000 - } - fn migrate_custom_top_fail() -> Weight { - 1000000 - } - fn migrate_custom_top_success() -> Weight { - 1000000 - } - fn migrate_custom_child_fail() -> Weight { - 1000000 - } - fn migrate_custom_child_success() -> Weight { - 1000000 - } - } - /// The progress of either the top or child keys. #[derive( CloneNoBound, @@ -1072,6 +1041,7 @@ mod mock { use frame_support::{ parameter_types, traits::{ConstU32, ConstU64, Hooks}, + weights::Weight, }; use frame_system::{EnsureRoot, EnsureSigned}; use sp_core::{ @@ -1148,6 +1118,33 @@ mod mock { type WeightInfo = (); } + /// Test only Weights for state migration. + pub struct StateMigrationTestWeight; + + impl WeightInfo for StateMigrationTestWeight { + fn process_top_key(_: u32) -> Weight { + 1000000 + } + fn continue_migrate() -> Weight { + 1000000 + } + fn continue_migrate_wrong_witness() -> Weight { + 1000000 + } + fn migrate_custom_top_fail() -> Weight { + 1000000 + } + fn migrate_custom_top_success() -> Weight { + 1000000 + } + fn migrate_custom_child_fail() -> Weight { + 1000000 + } + fn migrate_custom_child_success() -> Weight { + 1000000 + } + } + impl pallet_state_trie_migration::Config for Test { type Event = Event; type ControlOrigin = EnsureRoot; @@ -1156,7 +1153,7 @@ mod mock { type SignedDepositPerItem = SignedDepositPerItem; type SignedDepositBase = SignedDepositBase; type SignedFilter = EnsureSigned; - type WeightInfo = (); + type WeightInfo = StateMigrationTestWeight; } pub fn new_test_ext( From 8016da9ddf1c10a5a74cc5a273905cfeb60ed82c Mon Sep 17 00:00:00 2001 From: Koute Date: Mon, 18 Jul 2022 20:51:38 +0900 Subject: [PATCH 0979/1472] Improve `wasmtime` error reporting (#11856) * Improve `wasmtime` error reporting * cargo fmt --- client/executor/wasmtime/src/imports.rs | 2 +- .../executor/wasmtime/src/instance_wrapper.rs | 7 +++--- client/executor/wasmtime/src/runtime.rs | 24 +++++++++---------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/client/executor/wasmtime/src/imports.rs b/client/executor/wasmtime/src/imports.rs index fae8d75854ef3..c80952a2541ce 100644 --- a/client/executor/wasmtime/src/imports.rs +++ b/client/executor/wasmtime/src/imports.rs @@ -112,7 +112,7 @@ impl<'a, 'b> sp_wasm_interface::HostFunctionRegistry for Registry<'a, 'b> { if self.pending_func_imports.remove(fn_name).is_some() { self.linker.func_wrap("env", fn_name, func).map_err(|error| { WasmError::Other(format!( - "failed to register host function '{}' with the WASM linker: {}", + "failed to register host function '{}' with the WASM linker: {:#}", fn_name, error )) })?; diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index 6abcbca1bba6f..5d272accd3524 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -186,9 +186,10 @@ impl InstanceWrapper { ) -> Result { let mut store = create_store(engine, max_memory_size); let instance = instance_pre.instantiate(&mut store).map_err(|error| { - WasmError::Other( - format!("failed to instantiate a new WASM module instance: {}", error,), - ) + WasmError::Other(format!( + "failed to instantiate a new WASM module instance: {:#}", + error, + )) })?; let memory = get_linear_memory(&instance, &mut store)?; diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index c63a802df07cc..fb5c6cb16993a 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -257,12 +257,12 @@ fn setup_wasmtime_caching( let wasmtime_cache_root = cache_path.join("wasmtime"); fs::create_dir_all(&wasmtime_cache_root) - .map_err(|err| format!("cannot create the dirs to cache: {:?}", err))?; + .map_err(|err| format!("cannot create the dirs to cache: {}", err))?; // Canonicalize the path after creating the directories. let wasmtime_cache_root = wasmtime_cache_root .canonicalize() - .map_err(|err| format!("failed to canonicalize the path: {:?}", err))?; + .map_err(|err| format!("failed to canonicalize the path: {}", err))?; // Write the cache config file let cache_config_path = wasmtime_cache_root.join("cache-config.toml"); @@ -275,11 +275,11 @@ directory = \"{cache_dir}\" cache_dir = wasmtime_cache_root.display() ); fs::write(&cache_config_path, config_content) - .map_err(|err| format!("cannot write the cache config: {:?}", err))?; + .map_err(|err| format!("cannot write the cache config: {}", err))?; config .cache_config_load(cache_config_path) - .map_err(|err| format!("failed to parse the config: {:?}", err))?; + .map_err(|err| format!("failed to parse the config: {:#}", err))?; Ok(()) } @@ -304,14 +304,14 @@ fn common_config(semantics: &Semantics) -> std::result::Result { @@ -626,7 +626,7 @@ where let serialized_blob = blob.clone().serialize(); let module = wasmtime::Module::new(&engine, &serialized_blob) - .map_err(|e| WasmError::Other(format!("cannot create module: {}", e)))?; + .map_err(|e| WasmError::Other(format!("cannot create module: {:#}", e)))?; match config.semantics.instantiation_strategy { InstantiationStrategy::LegacyInstanceReuse => { @@ -664,7 +664,7 @@ where // // See [`create_runtime_from_artifact`] for more details. let module = wasmtime::Module::deserialize_file(&engine, compiled_artifact_path) - .map_err(|e| WasmError::Other(format!("cannot deserialize module: {}", e)))?; + .map_err(|e| WasmError::Other(format!("cannot deserialize module: {:#}", e)))?; (module, InternalInstantiationStrategy::Builtin) }, @@ -677,7 +677,7 @@ where crate::instance_wrapper::create_store(module.engine(), config.semantics.max_memory_size); let instance_pre = linker .instantiate_pre(&mut store, &module) - .map_err(|e| WasmError::Other(format!("cannot preinstantiate module: {}", e)))?; + .map_err(|e| WasmError::Other(format!("cannot preinstantiate module: {:#}", e)))?; Ok(WasmtimeRuntime { engine, @@ -729,11 +729,11 @@ pub fn prepare_runtime_artifact( let blob = prepare_blob_for_compilation(blob, &semantics)?; let engine = Engine::new(&common_config(&semantics)?) - .map_err(|e| WasmError::Other(format!("cannot create the engine: {}", e)))?; + .map_err(|e| WasmError::Other(format!("cannot create the engine: {:#}", e)))?; engine .precompile_module(&blob.serialize()) - .map_err(|e| WasmError::Other(format!("cannot precompile module: {}", e))) + .map_err(|e| WasmError::Other(format!("cannot precompile module: {:#}", e))) } fn perform_call( From 32bc42ba64f88a8ea65734ba9a404779fafbc0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20St=C3=BCber?= Date: Mon, 18 Jul 2022 14:56:22 +0200 Subject: [PATCH 0980/1472] Fix invalid state transitions in pallet-bounties (#11630) * Pallet-bounty: disallow invalid state transitions * Fix tests: funding only at even block numbers * Fix benchmarks: bounties need to be funded * fix on_initialize Co-authored-by: Shawn Tabrizi --- frame/bounties/src/lib.rs | 2 +- frame/bounties/src/tests.rs | 8 ++++---- frame/child-bounties/src/benchmarking.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 8e28cacb9d929..fca758fd96b8e 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -390,7 +390,7 @@ pub mod pallet { Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; match bounty.status { - BountyStatus::Proposed | BountyStatus::Approved | BountyStatus::Funded => {}, + BountyStatus::Funded => {}, _ => return Err(Error::::UnexpectedStatus.into()), }; diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index ff220600794d4..b4ce039b35fbc 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -1126,8 +1126,8 @@ fn accept_curator_handles_different_deposit_calculations() { assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); - System::set_block_number(3); - >::on_initialize(3); + System::set_block_number(4); + >::on_initialize(4); assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); @@ -1150,8 +1150,8 @@ fn accept_curator_handles_different_deposit_calculations() { assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); - System::set_block_number(3); - >::on_initialize(3); + System::set_block_number(6); + >::on_initialize(6); assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); diff --git a/frame/child-bounties/src/benchmarking.rs b/frame/child-bounties/src/benchmarking.rs index dcb54361fac89..ca5af50276b9d 100644 --- a/frame/child-bounties/src/benchmarking.rs +++ b/frame/child-bounties/src/benchmarking.rs @@ -221,7 +221,7 @@ benchmarks! { unassign_curator { setup_pot_account::(); let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; - Bounties::::on_initialize(T::BlockNumber::zero()); + Treasury::::on_initialize(T::BlockNumber::zero()); frame_system::Pallet::::set_block_number(T::BountyUpdatePeriod::get() + 1u32.into()); let caller = whitelisted_caller(); }: _(RawOrigin::Signed(caller), bounty_setup.bounty_id, @@ -295,7 +295,7 @@ benchmarks! { close_child_bounty_active { setup_pot_account::(); let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; - Bounties::::on_initialize(T::BlockNumber::zero()); + Treasury::::on_initialize(T::BlockNumber::zero()); }: close_child_bounty(RawOrigin::Root, bounty_setup.bounty_id, bounty_setup.child_bounty_id) verify { assert_last_event::(Event::Canceled { From a434d07ab18982eceff528c6e7f1e95a6f71bea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 18 Jul 2022 21:25:18 +0200 Subject: [PATCH 0981/1472] Disable the interest cache (#11854) * Disable the interest cache The feature is currently broken with the latest `tracing-core`. We will enable it again, when it is fixed upstream. * FMT --- Cargo.lock | 8 +++----- client/tracing/Cargo.toml | 2 +- client/tracing/src/logging/mod.rs | 5 +---- primitives/io/Cargo.toml | 2 +- primitives/runtime-interface/test/Cargo.toml | 2 +- primitives/tracing/Cargo.toml | 2 +- 6 files changed, 8 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 791d8037f3335..279864e056b0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11066,11 +11066,11 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.26" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" dependencies = [ - "lazy_static", + "once_cell", "valuable", ] @@ -11090,10 +11090,8 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ - "ahash", "lazy_static", "log", - "lru", "tracing-core", ] diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 3f0bbbe922d3f..476e03ee741f3 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -26,7 +26,7 @@ rustc-hash = "1.1.0" serde = "1.0.136" thiserror = "1.0.30" tracing = "0.1.29" -tracing-log = { version = "0.1.3", features = ["interest-cache"] } +tracing-log = "0.1.3" tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-rpc-server = { version = "4.0.0-dev", path = "../rpc-servers" } diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index 33c83dd87189e..58941617bfb6a 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -155,10 +155,7 @@ where let max_level_hint = Layer::::max_level_hint(&env_filter); let max_level = to_log_level_filter(max_level_hint); - tracing_log::LogTracer::builder() - .with_max_level(max_level) - .with_interest_cache(tracing_log::InterestCacheConfig::default()) - .init()?; + tracing_log::LogTracer::builder().with_max_level(max_level).init()?; // If we're only logging `INFO` entries then we'll use a simplified logging format. let detailed_output = match max_level_hint { diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 09a087d509416..03cd8535665ac 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -32,7 +32,7 @@ futures = { version = "0.3.21", features = ["thread-pool"], optional = true } parking_lot = { version = "0.12.0", optional = true } secp256k1 = { version = "0.21.2", features = ["recovery", "global-context"], optional = true } tracing = { version = "0.1.29", default-features = false } -tracing-core = { version = "0.1.26", default-features = false} +tracing-core = { version = "0.1.28", default-features = false} [features] default = ["std"] diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index e897fc0bab71c..880d03902b421 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] tracing = "0.1.29" -tracing-core = "0.1.26" +tracing-core = "0.1.28" sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-executor-common = { version = "0.10.0-dev", path = "../../../client/executor/common" } sp-io = { version = "6.0.0", path = "../../io" } diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index d305b756e2d68..c2ca57d2b5a43 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -23,7 +23,7 @@ codec = { version = "3.0.0", package = "parity-scale-codec", default-features = "derive", ] } tracing = { version = "0.1.29", default-features = false } -tracing-core = { version = "0.1.26", default-features = false } +tracing-core = { version = "0.1.28", default-features = false } tracing-subscriber = { version = "0.2.25", optional = true, features = [ "tracing-log", ] } From ced41695aafa648ebdb01305e563fa7ca89756bc Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 19 Jul 2022 08:10:15 +0200 Subject: [PATCH 0982/1472] Add `benchmark extrinsic` command (#11456) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Benchmark extrinsic Signed-off-by: Oliver Tale-Yazdi * Reduce warmup and repeat Running this 1000 times with a full block takes ~33 minutes 🙈. Reducing it to ~3 minutes per default. Signed-off-by: Oliver Tale-Yazdi * Make ExistentialDeposit public Signed-off-by: Oliver Tale-Yazdi * Add 'bechmark extrinsic' command Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Add --list and cleanup Signed-off-by: Oliver Tale-Yazdi * Unrelated Clippy Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * Fix tests and doc Signed-off-by: Oliver Tale-Yazdi * Move implementations up + fmt Signed-off-by: Oliver Tale-Yazdi * Dont use parameter_types macro Signed-off-by: Oliver Tale-Yazdi * Cache to_lowercase() call The .to_lowercase() on the builder is actually not needes since its already documented to only return lower case. Signed-off-by: Oliver Tale-Yazdi * Spelling Signed-off-by: Oliver Tale-Yazdi * Use correct nightly for fmt... Signed-off-by: Oliver Tale-Yazdi * Rename ED Signed-off-by: Oliver Tale-Yazdi * Fix compile Signed-off-by: Oliver Tale-Yazdi * Subtract block base weight Signed-off-by: Oliver Tale-Yazdi * Fixes Signed-off-by: Oliver Tale-Yazdi * Use tmp folder for test This should already be the case since --dev is passed but somehow not... Signed-off-by: Oliver Tale-Yazdi * Fix test Signed-off-by: Oliver Tale-Yazdi --- .../{command_helper.rs => benchmarking.rs} | 66 ++++++++- bin/node-template/node/src/command.rs | 26 +++- bin/node-template/node/src/main.rs | 2 +- bin/node-template/runtime/src/lib.rs | 5 +- .../{command_helper.rs => benchmarking.rs} | 70 +++++++-- bin/node/cli/src/command.rs | 23 ++- bin/node/cli/src/lib.rs | 4 +- .../cli/tests/benchmark_extrinsic_works.rs | 46 ++++++ .../src/{overhead => extrinsic}/bench.rs | 107 +++++++------- .../benchmarking-cli/src/extrinsic/cmd.rs | 134 ++++++++++++++++++ .../src/extrinsic/extrinsic_factory.rs | 70 +++++++++ .../benchmarking-cli/src/extrinsic/mod.rs | 27 ++++ utils/frame/benchmarking-cli/src/lib.rs | 7 +- .../benchmarking-cli/src/overhead/cmd.rs | 52 +++++-- .../benchmarking-cli/src/overhead/mod.rs | 5 +- .../benchmarking-cli/src/overhead/template.rs | 2 +- 16 files changed, 537 insertions(+), 109 deletions(-) rename bin/node-template/node/src/{command_helper.rs => benchmarking.rs} (71%) rename bin/node/cli/src/{command_helper.rs => benchmarking.rs} (52%) create mode 100644 bin/node/cli/tests/benchmark_extrinsic_works.rs rename utils/frame/benchmarking-cli/src/{overhead => extrinsic}/bench.rs (70%) create mode 100644 utils/frame/benchmarking-cli/src/extrinsic/cmd.rs create mode 100644 utils/frame/benchmarking-cli/src/extrinsic/extrinsic_factory.rs create mode 100644 utils/frame/benchmarking-cli/src/extrinsic/mod.rs diff --git a/bin/node-template/node/src/command_helper.rs b/bin/node-template/node/src/benchmarking.rs similarity index 71% rename from bin/node-template/node/src/command_helper.rs rename to bin/node-template/node/src/benchmarking.rs index 287e81b1e96bd..f0e32104cd3ee 100644 --- a/bin/node-template/node/src/command_helper.rs +++ b/bin/node-template/node/src/benchmarking.rs @@ -16,13 +16,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Contains code to setup the command invocations in [`super::command`] which would -//! otherwise bloat that module. +//! Setup code for [`super::command`] which would otherwise bloat that module. +//! +//! Should only be used for benchmarking as it may break in other contexts. use crate::service::FullClient; use node_template_runtime as runtime; -use runtime::SystemCall; +use runtime::{AccountId, Balance, BalancesCall, SystemCall}; use sc_cli::Result; use sc_client_api::BlockBackend; use sp_core::{Encode, Pair}; @@ -35,19 +36,27 @@ use std::{sync::Arc, time::Duration}; /// Generates extrinsics for the `benchmark overhead` command. /// /// Note: Should only be used for benchmarking. -pub struct BenchmarkExtrinsicBuilder { +pub struct RemarkBuilder { client: Arc, } -impl BenchmarkExtrinsicBuilder { +impl RemarkBuilder { /// Creates a new [`Self`] from the given client. pub fn new(client: Arc) -> Self { Self { client } } } -impl frame_benchmarking_cli::ExtrinsicBuilder for BenchmarkExtrinsicBuilder { - fn remark(&self, nonce: u32) -> std::result::Result { +impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { + fn pallet(&self) -> &str { + "system" + } + + fn extrinsic(&self) -> &str { + "remark" + } + + fn build(&self, nonce: u32) -> std::result::Result { let acc = Sr25519Keyring::Bob.pair(); let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic( self.client.as_ref(), @@ -61,6 +70,49 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for BenchmarkExtrinsicBuilder { } } +/// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks. +/// +/// Note: Should only be used for benchmarking. +pub struct TransferKeepAliveBuilder { + client: Arc, + dest: AccountId, + value: Balance, +} + +impl TransferKeepAliveBuilder { + /// Creates a new [`Self`] from the given client. + pub fn new(client: Arc, dest: AccountId, value: Balance) -> Self { + Self { client, dest, value } + } +} + +impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { + fn pallet(&self) -> &str { + "balances" + } + + fn extrinsic(&self) -> &str { + "transfer_keep_alive" + } + + fn build(&self, nonce: u32) -> std::result::Result { + let acc = Sr25519Keyring::Bob.pair(); + let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic( + self.client.as_ref(), + acc, + BalancesCall::transfer_keep_alive { + dest: self.dest.clone().into(), + value: self.value.into(), + } + .into(), + nonce, + ) + .into(); + + Ok(extrinsic) + } +} + /// Create a transaction using the given `call`. /// /// Note: Should only be used for benchmarking. diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index e3e10007929e6..142f0b40c325e 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -1,14 +1,14 @@ use crate::{ + benchmarking::{inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder}, chain_spec, cli::{Cli, Subcommand}, - command_helper::{inherent_benchmark_data, BenchmarkExtrinsicBuilder}, service, }; -use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; -use node_template_runtime::Block; +use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE}; +use node_template_runtime::{Block, EXISTENTIAL_DEPOSIT}; use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; -use std::sync::Arc; +use sp_keyring::Sr25519Keyring; impl SubstrateCli for Cli { fn impl_name() -> String { @@ -137,9 +137,23 @@ pub fn run() -> sc_cli::Result<()> { }, BenchmarkCmd::Overhead(cmd) => { let PartialComponents { client, .. } = service::new_partial(&config)?; - let ext_builder = BenchmarkExtrinsicBuilder::new(client.clone()); + let ext_builder = RemarkBuilder::new(client.clone()); - cmd.run(config, client, inherent_benchmark_data()?, Arc::new(ext_builder)) + cmd.run(config, client, inherent_benchmark_data()?, &ext_builder) + }, + BenchmarkCmd::Extrinsic(cmd) => { + let PartialComponents { client, .. } = service::new_partial(&config)?; + // Register the *Remark* and *TKA* builders. + let ext_factory = ExtrinsicFactory(vec![ + Box::new(RemarkBuilder::new(client.clone())), + Box::new(TransferKeepAliveBuilder::new( + client.clone(), + Sr25519Keyring::Alice.to_account_id(), + EXISTENTIAL_DEPOSIT, + )), + ]); + + cmd.run(client, inherent_benchmark_data()?, &ext_factory) }, BenchmarkCmd::Machine(cmd) => cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), diff --git a/bin/node-template/node/src/main.rs b/bin/node-template/node/src/main.rs index 0f2fbd5a909c6..426cbabb6fbf7 100644 --- a/bin/node-template/node/src/main.rs +++ b/bin/node-template/node/src/main.rs @@ -4,9 +4,9 @@ mod chain_spec; #[macro_use] mod service; +mod benchmarking; mod cli; mod command; -mod command_helper; mod rpc; fn main() -> sc_cli::Result<()> { diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index c514cdf6c25fd..a2f595f571a90 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -234,6 +234,9 @@ impl pallet_timestamp::Config for Runtime { type WeightInfo = (); } +/// Existential deposit. +pub const EXISTENTIAL_DEPOSIT: u128 = 500; + impl pallet_balances::Config for Runtime { type MaxLocks = ConstU32<50>; type MaxReserves = (); @@ -243,7 +246,7 @@ impl pallet_balances::Config for Runtime { /// The ubiquitous event type. type Event = Event; type DustRemoval = (); - type ExistentialDeposit = ConstU128<500>; + type ExistentialDeposit = ConstU128; type AccountStore = System; type WeightInfo = pallet_balances::weights::SubstrateWeight; } diff --git a/bin/node/cli/src/command_helper.rs b/bin/node/cli/src/benchmarking.rs similarity index 52% rename from bin/node/cli/src/command_helper.rs rename to bin/node/cli/src/benchmarking.rs index 84d85ee367cab..52657016c046a 100644 --- a/bin/node/cli/src/command_helper.rs +++ b/bin/node/cli/src/benchmarking.rs @@ -16,12 +16,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Contains code to setup the command invocations in [`super::command`] which would -//! otherwise bloat that module. +//! Setup code for [`super::command`] which would otherwise bloat that module. +//! +//! Should only be used for benchmarking as it may break in other contexts. use crate::service::{create_extrinsic, FullClient}; -use node_runtime::SystemCall; +use node_primitives::{AccountId, Balance}; +use node_runtime::{BalancesCall, SystemCall}; use sc_cli::Result; use sp_inherents::{InherentData, InherentDataProvider}; use sp_keyring::Sr25519Keyring; @@ -29,20 +31,30 @@ use sp_runtime::OpaqueExtrinsic; use std::{sync::Arc, time::Duration}; -/// Generates extrinsics for the `benchmark overhead` command. -pub struct BenchmarkExtrinsicBuilder { +/// Generates `System::Remark` extrinsics for the benchmarks. +/// +/// Note: Should only be used for benchmarking. +pub struct RemarkBuilder { client: Arc, } -impl BenchmarkExtrinsicBuilder { +impl RemarkBuilder { /// Creates a new [`Self`] from the given client. pub fn new(client: Arc) -> Self { Self { client } } } -impl frame_benchmarking_cli::ExtrinsicBuilder for BenchmarkExtrinsicBuilder { - fn remark(&self, nonce: u32) -> std::result::Result { +impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { + fn pallet(&self) -> &str { + "system" + } + + fn extrinsic(&self) -> &str { + "remark" + } + + fn build(&self, nonce: u32) -> std::result::Result { let acc = Sr25519Keyring::Bob.pair(); let extrinsic: OpaqueExtrinsic = create_extrinsic( self.client.as_ref(), @@ -56,6 +68,48 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for BenchmarkExtrinsicBuilder { } } +/// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks. +/// +/// Note: Should only be used for benchmarking. +pub struct TransferKeepAliveBuilder { + client: Arc, + dest: AccountId, + value: Balance, +} + +impl TransferKeepAliveBuilder { + /// Creates a new [`Self`] from the given client. + pub fn new(client: Arc, dest: AccountId, value: Balance) -> Self { + Self { client, dest, value } + } +} + +impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { + fn pallet(&self) -> &str { + "balances" + } + + fn extrinsic(&self) -> &str { + "transfer_keep_alive" + } + + fn build(&self, nonce: u32) -> std::result::Result { + let acc = Sr25519Keyring::Bob.pair(); + let extrinsic: OpaqueExtrinsic = create_extrinsic( + self.client.as_ref(), + acc, + BalancesCall::transfer_keep_alive { + dest: self.dest.clone().into(), + value: self.value.into(), + }, + Some(nonce), + ) + .into(); + + Ok(extrinsic) + } +} + /// Generates inherent data for the `benchmark overhead` command. pub fn inherent_benchmark_data() -> Result { let mut inherent_data = InherentData::new(); diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index b17a26fa02935..df3d5a891e2ab 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::command_helper::{inherent_benchmark_data, BenchmarkExtrinsicBuilder}; +use super::benchmarking::{inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder}; use crate::{ chain_spec, service, service::{new_partial, FullClient}, @@ -25,9 +25,10 @@ use crate::{ use frame_benchmarking_cli::*; use node_executor::ExecutorDispatch; use node_primitives::Block; -use node_runtime::RuntimeApi; +use node_runtime::{ExistentialDeposit, RuntimeApi}; use sc_cli::{ChainSpec, Result, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; +use sp_keyring::Sr25519Keyring; use std::sync::Arc; @@ -126,9 +127,23 @@ pub fn run() -> Result<()> { }, BenchmarkCmd::Overhead(cmd) => { let PartialComponents { client, .. } = new_partial(&config)?; - let ext_builder = BenchmarkExtrinsicBuilder::new(client.clone()); + let ext_builder = RemarkBuilder::new(client.clone()); - cmd.run(config, client, inherent_benchmark_data()?, Arc::new(ext_builder)) + cmd.run(config, client, inherent_benchmark_data()?, &ext_builder) + }, + BenchmarkCmd::Extrinsic(cmd) => { + let PartialComponents { client, .. } = service::new_partial(&config)?; + // Register the *Remark* and *TKA* builders. + let ext_factory = ExtrinsicFactory(vec![ + Box::new(RemarkBuilder::new(client.clone())), + Box::new(TransferKeepAliveBuilder::new( + client.clone(), + Sr25519Keyring::Alice.to_account_id(), + ExistentialDeposit::get(), + )), + ]); + + cmd.run(client, inherent_benchmark_data()?, &ext_factory) }, BenchmarkCmd::Machine(cmd) => cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), diff --git a/bin/node/cli/src/lib.rs b/bin/node/cli/src/lib.rs index 06c0bcccbc296..13c074268e50f 100644 --- a/bin/node/cli/src/lib.rs +++ b/bin/node/cli/src/lib.rs @@ -35,11 +35,11 @@ pub mod chain_spec; #[macro_use] pub mod service; #[cfg(feature = "cli")] +mod benchmarking; +#[cfg(feature = "cli")] mod cli; #[cfg(feature = "cli")] mod command; -#[cfg(feature = "cli")] -mod command_helper; #[cfg(feature = "cli")] pub use cli::*; diff --git a/bin/node/cli/tests/benchmark_extrinsic_works.rs b/bin/node/cli/tests/benchmark_extrinsic_works.rs new file mode 100644 index 0000000000000..69800ad3c6c13 --- /dev/null +++ b/bin/node/cli/tests/benchmark_extrinsic_works.rs @@ -0,0 +1,46 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use assert_cmd::cargo::cargo_bin; +use std::process::Command; +use tempfile::tempdir; + +/// Tests that the `benchmark extrinsic` command works for +/// remark and transfer_keep_alive within the substrate dev runtime. +#[test] +fn benchmark_extrinsic_works() { + benchmark_extrinsic("system", "remark"); + benchmark_extrinsic("balances", "transfer_keep_alive"); +} + +/// Checks that the `benchmark extrinsic` command works for the given pallet and extrinsic. +fn benchmark_extrinsic(pallet: &str, extrinsic: &str) { + let base_dir = tempdir().expect("could not create a temp dir"); + + let status = Command::new(cargo_bin("substrate")) + .args(&["benchmark", "extrinsic", "--dev"]) + .arg("-d") + .arg(base_dir.path()) + .args(&["--pallet", pallet, "--extrinsic", extrinsic]) + // Run with low repeats for faster execution. + .args(["--warmup=10", "--repeat=10", "--max-ext-per-block=10"]) + .status() + .unwrap(); + + assert!(status.success()); +} diff --git a/utils/frame/benchmarking-cli/src/overhead/bench.rs b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs similarity index 70% rename from utils/frame/benchmarking-cli/src/overhead/bench.rs rename to utils/frame/benchmarking-cli/src/extrinsic/bench.rs index be7dac24021cf..27fc40fb34774 100644 --- a/utils/frame/benchmarking-cli/src/overhead/bench.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -36,8 +36,8 @@ use log::info; use serde::Serialize; use std::{marker::PhantomData, sync::Arc, time::Instant}; -use super::cmd::ExtrinsicBuilder; -use crate::shared::Stats; +use super::ExtrinsicBuilder; +use crate::shared::{StatSelect, Stats}; /// Parameters to configure an *overhead* benchmark. #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] @@ -60,21 +60,11 @@ pub struct BenchmarkParams { /// The results of multiple runs in nano seconds. pub(crate) type BenchRecord = Vec; -/// Type of a benchmark. -#[derive(Serialize, Clone, PartialEq, Copy)] -pub(crate) enum BenchmarkType { - /// Measure the per-extrinsic execution overhead. - Extrinsic, - /// Measure the per-block execution overhead. - Block, -} - /// Holds all objects needed to run the *overhead* benchmarks. pub(crate) struct Benchmark { client: Arc, params: BenchmarkParams, inherent_data: sp_inherents::InherentData, - ext_builder: Arc, _p: PhantomData<(Block, BA)>, } @@ -90,23 +80,51 @@ where client: Arc, params: BenchmarkParams, inherent_data: sp_inherents::InherentData, - ext_builder: Arc, ) -> Self { - Self { client, params, inherent_data, ext_builder, _p: PhantomData } + Self { client, params, inherent_data, _p: PhantomData } } - /// Run the specified benchmark. - pub fn bench(&self, bench_type: BenchmarkType) -> Result { - let (block, num_ext) = self.build_block(bench_type)?; - let record = self.measure_block(&block, num_ext, bench_type)?; + /// Benchmark a block with only inherents. + pub fn bench_block(&self) -> Result { + let (block, _) = self.build_block(None)?; + let record = self.measure_block(&block)?; Stats::new(&record) } - /// Builds a block for the given benchmark type. + /// Benchmark the time of an extrinsic in a full block. + /// + /// First benchmarks an empty block, analogous to `bench_block` and use it as baseline. + /// Then benchmarks a full block built with the given `ext_builder` and subtracts the baseline + /// from the result. + /// This is necessary to account for the time the inherents use. + pub fn bench_extrinsic(&self, ext_builder: &dyn ExtrinsicBuilder) -> Result { + let (block, _) = self.build_block(None)?; + let base = self.measure_block(&block)?; + let base_time = Stats::new(&base)?.select(StatSelect::Average); + + let (block, num_ext) = self.build_block(Some(ext_builder))?; + let num_ext = num_ext.ok_or_else(|| Error::Input("Block was empty".into()))?; + let mut records = self.measure_block(&block)?; + + for r in &mut records { + // Subtract the base time. + *r = r.saturating_sub(base_time); + // Divide by the number of extrinsics in the block. + *r = ((*r as f64) / (num_ext as f64)).ceil() as u64; + } + + Stats::new(&records) + } + + /// Builds a block with some optional extrinsics. /// /// Returns the block and the number of extrinsics in the block /// that are not inherents. - fn build_block(&self, bench_type: BenchmarkType) -> Result<(Block, u64)> { + /// Returns a block with only inherents if `ext_builder` is `None`. + fn build_block( + &self, + ext_builder: Option<&dyn ExtrinsicBuilder>, + ) -> Result<(Block, Option)> { let mut builder = self.client.new_block(Default::default())?; // Create and insert the inherents. let inherents = builder.create_inherents(self.inherent_data.clone())?; @@ -114,16 +132,18 @@ where builder.push(inherent)?; } - // Return early if we just want a block with inherents and no additional extrinsics. - if bench_type == BenchmarkType::Block { - return Ok((builder.build()?.block, 0)) - } + // Return early if `ext_builder` is `None`. + let ext_builder = if let Some(ext_builder) = ext_builder { + ext_builder + } else { + return Ok((builder.build()?.block, None)) + }; // Put as many extrinsics into the block as possible and count them. info!("Building block, this takes some time..."); let mut num_ext = 0; for nonce in 0..self.max_ext_per_block() { - let ext = self.ext_builder.remark(nonce)?; + let ext = ext_builder.build(nonce)?; match builder.push(ext.clone()) { Ok(()) => {}, Err(ApplyExtrinsicFailed(Validity(TransactionValidityError::Invalid( @@ -139,20 +159,12 @@ where info!("Extrinsics per block: {}", num_ext); let block = builder.build()?.block; - Ok((block, num_ext)) + Ok((block, Some(num_ext))) } /// Measures the time that it take to execute a block or an extrinsic. - fn measure_block( - &self, - block: &Block, - num_ext: u64, - bench_type: BenchmarkType, - ) -> Result { + fn measure_block(&self, block: &Block) -> Result { let mut record = BenchRecord::new(); - if bench_type == BenchmarkType::Extrinsic && num_ext == 0 { - return Err("Cannot measure the extrinsic time of an empty block".into()) - } let genesis = BlockId::Number(Zero::zero()); info!("Running {} warmups...", self.params.warmup); @@ -176,12 +188,7 @@ where .map_err(|e| Error::Client(RuntimeApiError(e)))?; let elapsed = start.elapsed().as_nanos(); - if bench_type == BenchmarkType::Extrinsic { - // Checked for non-zero div above. - record.push((elapsed as f64 / num_ext as f64).ceil() as u64); - } else { - record.push(elapsed as u64); - } + record.push(elapsed as u64); } Ok(record) @@ -191,21 +198,3 @@ where self.params.max_ext_per_block.unwrap_or(u32::MAX) } } - -impl BenchmarkType { - /// Short name of the benchmark type. - pub(crate) fn short_name(&self) -> &'static str { - match self { - Self::Extrinsic => "extrinsic", - Self::Block => "block", - } - } - - /// Long name of the benchmark type. - pub(crate) fn long_name(&self) -> &'static str { - match self { - Self::Extrinsic => "ExtrinsicBase", - Self::Block => "BlockExecution", - } - } -} diff --git a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs new file mode 100644 index 0000000000000..6b4fd0fad6638 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs @@ -0,0 +1,134 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; +use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; +use sc_client_api::Backend as ClientBackend; +use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; + +use clap::{Args, Parser}; +use log::info; +use serde::Serialize; +use std::{fmt::Debug, sync::Arc}; + +use super::{ + bench::{Benchmark, BenchmarkParams}, + extrinsic_factory::ExtrinsicFactory, +}; + +/// Benchmark the execution time of different extrinsics. +/// +/// This is calculated by filling a block with a specific extrinsic and executing the block. +/// The result time is then divided by the number of extrinsics in that block. +/// +/// NOTE: The BlockExecutionWeight is ignored in this case since it +// is very small compared to the total block execution time. +#[derive(Debug, Parser)] +pub struct ExtrinsicCmd { + #[allow(missing_docs)] + #[clap(flatten)] + pub shared_params: SharedParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub import_params: ImportParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub params: ExtrinsicParams, +} + +/// The params for the [`ExtrinsicCmd`]. +#[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] +pub struct ExtrinsicParams { + #[clap(flatten)] + pub bench: BenchmarkParams, + + /// List all available pallets and extrinsics. + /// + /// The format is CSV with header `pallet, extrinsic`. + #[clap(long)] + pub list: bool, + + /// Pallet name of the extrinsic to benchmark. + #[clap(long, value_name = "PALLET", required_unless_present = "list")] + pub pallet: Option, + + /// Extrinsic to benchmark. + #[clap(long, value_name = "EXTRINSIC", required_unless_present = "list")] + pub extrinsic: Option, +} + +impl ExtrinsicCmd { + /// Benchmark the execution time of a specific type of extrinsic. + /// + /// The output will be printed to console. + pub fn run( + &self, + client: Arc, + inherent_data: sp_inherents::InherentData, + ext_factory: &ExtrinsicFactory, + ) -> Result<()> + where + Block: BlockT, + BA: ClientBackend, + C: BlockBuilderProvider + ProvideRuntimeApi, + C::Api: ApiExt + BlockBuilderApi, + { + // Short circuit if --list was specified. + if self.params.list { + let list: Vec = ext_factory.0.iter().map(|b| b.name()).collect(); + info!( + "Listing available extrinsics ({}):\npallet, extrinsic\n{}", + list.len(), + list.join("\n") + ); + return Ok(()) + } + + let pallet = self.params.pallet.clone().unwrap_or_default(); + let extrinsic = self.params.extrinsic.clone().unwrap_or_default(); + let ext_builder = match ext_factory.try_get(&pallet, &extrinsic) { + Some(ext_builder) => ext_builder, + None => + return Err("Unknown pallet or extrinsic. Use --list for a complete list.".into()), + }; + + let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data); + let stats = bench.bench_extrinsic(ext_builder)?; + info!( + "Executing a {}::{} extrinsic takes[ns]:\n{:?}", + ext_builder.pallet(), + ext_builder.extrinsic(), + stats + ); + + Ok(()) + } +} + +// Boilerplate +impl CliConfiguration for ExtrinsicCmd { + fn shared_params(&self) -> &SharedParams { + &self.shared_params + } + + fn import_params(&self) -> Option<&ImportParams> { + Some(&self.import_params) + } +} diff --git a/utils/frame/benchmarking-cli/src/extrinsic/extrinsic_factory.rs b/utils/frame/benchmarking-cli/src/extrinsic/extrinsic_factory.rs new file mode 100644 index 0000000000000..7e1a22ccd1419 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/extrinsic/extrinsic_factory.rs @@ -0,0 +1,70 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Provides the [`ExtrinsicFactory`] and the [`ExtrinsicBuilder`] types. +//! Is used by the *overhead* and *extrinsic* benchmarks to build extrinsics. + +use sp_runtime::OpaqueExtrinsic; + +/// Helper to manage [`ExtrinsicBuilder`] instances. +#[derive(Default)] +pub struct ExtrinsicFactory(pub Vec>); + +impl ExtrinsicFactory { + /// Returns a builder for a pallet and extrinsic name. + /// + /// Is case in-sensitive. + pub fn try_get(&self, pallet: &str, extrinsic: &str) -> Option<&dyn ExtrinsicBuilder> { + let pallet = pallet.to_lowercase(); + let extrinsic = extrinsic.to_lowercase(); + + self.0 + .iter() + .find(|b| b.pallet() == pallet && b.extrinsic() == extrinsic) + .map(|b| b.as_ref()) + } +} + +/// Used by the benchmark to build signed extrinsics. +/// +/// The built extrinsics only need to be valid in the first block +/// who's parent block is the genesis block. +/// This assumption simplifies the generation of the extrinsics. +/// The signer should be one of the pre-funded dev accounts. +pub trait ExtrinsicBuilder { + /// Name of the pallet this builder is for. + /// + /// Should be all lowercase. + fn pallet(&self) -> &str; + + /// Name of the extrinsic this builder is for. + /// + /// Should be all lowercase. + fn extrinsic(&self) -> &str; + + /// Builds an extrinsic. + /// + /// Will be called multiple times with increasing nonces. + fn build(&self, nonce: u32) -> std::result::Result; +} + +impl dyn ExtrinsicBuilder + '_ { + /// Name of this builder in CSV format: `pallet, extrinsic`. + pub fn name(&self) -> String { + format!("{}, {}", self.pallet(), self.extrinsic()) + } +} diff --git a/utils/frame/benchmarking-cli/src/extrinsic/mod.rs b/utils/frame/benchmarking-cli/src/extrinsic/mod.rs new file mode 100644 index 0000000000000..12a09c3b1af63 --- /dev/null +++ b/utils/frame/benchmarking-cli/src/extrinsic/mod.rs @@ -0,0 +1,27 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmark the time it takes to execute a specific extrinsic. +//! This is a generalization of the *overhead* benchmark which can only measure `System::Remark` +//! extrinsics. + +pub mod bench; +pub mod cmd; +pub mod extrinsic_factory; + +pub use cmd::ExtrinsicCmd; +pub use extrinsic_factory::{ExtrinsicBuilder, ExtrinsicFactory}; diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index d0eee3d2939fc..96c7a997895d4 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -18,6 +18,7 @@ //! Contains the root [`BenchmarkCmd`] command and exports its sub-commands. mod block; +mod extrinsic; mod machine; mod overhead; mod pallet; @@ -25,8 +26,9 @@ mod shared; mod storage; pub use block::BlockCmd; +pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, Requirements, SUBSTRATE_REFERENCE_HARDWARE}; -pub use overhead::{ExtrinsicBuilder, OverheadCmd}; +pub use overhead::OverheadCmd; pub use pallet::PalletCmd; pub use storage::StorageCmd; @@ -41,8 +43,8 @@ pub enum BenchmarkCmd { Storage(StorageCmd), Overhead(OverheadCmd), Block(BlockCmd), - #[clap(hide = true)] // Hidden until fully completed. Machine(MachineCmd), + Extrinsic(ExtrinsicCmd), } /// Unwraps a [`BenchmarkCmd`] into its concrete sub-command. @@ -58,6 +60,7 @@ macro_rules! unwrap_cmd { BenchmarkCmd::Overhead($cmd) => $code, BenchmarkCmd::Block($cmd) => $code, BenchmarkCmd::Machine($cmd) => $code, + BenchmarkCmd::Extrinsic($cmd) => $code, } } } diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 357c89d97a5ac..28ceea63f1572 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -31,10 +31,11 @@ use serde::Serialize; use std::{fmt::Debug, sync::Arc}; use crate::{ - overhead::{ - bench::{Benchmark, BenchmarkParams, BenchmarkType}, - template::TemplateData, + extrinsic::{ + bench::{Benchmark, BenchmarkParams as ExtrinsicBenchmarkParams}, + ExtrinsicBuilder, }, + overhead::template::TemplateData, shared::{HostInfoParams, WeightParams}, }; @@ -63,20 +64,20 @@ pub struct OverheadParams { #[allow(missing_docs)] #[clap(flatten)] - pub bench: BenchmarkParams, + pub bench: ExtrinsicBenchmarkParams, #[allow(missing_docs)] #[clap(flatten)] pub hostinfo: HostInfoParams, } -/// Used by the benchmark to build signed extrinsics. -/// -/// The built extrinsics only need to be valid in the first block -/// who's parent block is the genesis block. -pub trait ExtrinsicBuilder { - /// Build a `System::remark` extrinsic. - fn remark(&self, nonce: u32) -> std::result::Result; +/// Type of a benchmark. +#[derive(Serialize, Clone, PartialEq, Copy)] +pub(crate) enum BenchmarkType { + /// Measure the per-extrinsic execution overhead. + Extrinsic, + /// Measure the per-block execution overhead. + Block, } impl OverheadCmd { @@ -89,7 +90,7 @@ impl OverheadCmd { cfg: Configuration, client: Arc, inherent_data: sp_inherents::InherentData, - ext_builder: Arc, + ext_builder: &dyn ExtrinsicBuilder, ) -> Result<()> where Block: BlockT, @@ -97,18 +98,21 @@ impl OverheadCmd { C: BlockBuilderProvider + ProvideRuntimeApi, C::Api: ApiExt + BlockBuilderApi, { - let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data, ext_builder); + if ext_builder.pallet() != "system" || ext_builder.extrinsic() != "remark" { + return Err(format!("The extrinsic builder is required to build `System::Remark` extrinsics but builds `{}` extrinsics instead", ext_builder.name()).into()); + } + let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data); // per-block execution overhead { - let stats = bench.bench(BenchmarkType::Block)?; + let stats = bench.bench_block()?; info!("Per-block execution overhead [ns]:\n{:?}", stats); let template = TemplateData::new(BenchmarkType::Block, &cfg, &self.params, &stats)?; template.write(&self.params.weight.weight_path)?; } // per-extrinsic execution overhead { - let stats = bench.bench(BenchmarkType::Extrinsic)?; + let stats = bench.bench_extrinsic(ext_builder)?; info!("Per-extrinsic execution overhead [ns]:\n{:?}", stats); let template = TemplateData::new(BenchmarkType::Extrinsic, &cfg, &self.params, &stats)?; template.write(&self.params.weight.weight_path)?; @@ -118,6 +122,24 @@ impl OverheadCmd { } } +impl BenchmarkType { + /// Short name of the benchmark type. + pub(crate) fn short_name(&self) -> &'static str { + match self { + Self::Extrinsic => "extrinsic", + Self::Block => "block", + } + } + + /// Long name of the benchmark type. + pub(crate) fn long_name(&self) -> &'static str { + match self { + Self::Extrinsic => "ExtrinsicBase", + Self::Block => "BlockExecution", + } + } +} + // Boilerplate impl CliConfiguration for OverheadCmd { fn shared_params(&self) -> &SharedParams { diff --git a/utils/frame/benchmarking-cli/src/overhead/mod.rs b/utils/frame/benchmarking-cli/src/overhead/mod.rs index abdeac22b7898..fc3db912f7a30 100644 --- a/utils/frame/benchmarking-cli/src/overhead/mod.rs +++ b/utils/frame/benchmarking-cli/src/overhead/mod.rs @@ -15,8 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod bench; pub mod cmd; -mod template; +pub mod template; -pub use cmd::{ExtrinsicBuilder, OverheadCmd}; +pub use cmd::OverheadCmd; diff --git a/utils/frame/benchmarking-cli/src/overhead/template.rs b/utils/frame/benchmarking-cli/src/overhead/template.rs index 33c2c7999039a..aa82e45cf6db9 100644 --- a/utils/frame/benchmarking-cli/src/overhead/template.rs +++ b/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -27,7 +27,7 @@ use serde::Serialize; use std::{env, fs, path::PathBuf}; use crate::{ - overhead::{bench::BenchmarkType, cmd::OverheadParams}, + overhead::cmd::{BenchmarkType, OverheadParams}, shared::{Stats, UnderscoreHelper}, }; From 752980bf4a16488f0b37a4741bdefdd2f90e93bf Mon Sep 17 00:00:00 2001 From: Vlad Date: Tue, 19 Jul 2022 15:47:51 +0300 Subject: [PATCH 0983/1472] Don't download artifacts into the `rusty-cachier-notify` job (#11850) --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fff11e07326d8..9608d88e9554d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -229,6 +229,7 @@ rusty-cachier-notify: variables: CI_IMAGE: paritytech/rusty-cachier-env:latest GIT_STRATEGY: none + dependencies: [] script: - curl -s https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.parity.io/parity/infrastructure/ci_cd/rusty-cachier/client/-/raw/release/util/install.sh | bash - rusty-cachier cache notify From 7b81072843e584ef2bee449081aed5c963021ee9 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 20 Jul 2022 10:50:54 +0200 Subject: [PATCH 0984/1472] Bump wasmtime default-pages (#11864) Signed-off-by: Oliver Tale-Yazdi --- client/executor/wasmtime/src/runtime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index fb5c6cb16993a..dcf07c454e46d 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -366,7 +366,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result Date: Wed, 20 Jul 2022 18:04:31 -0400 Subject: [PATCH 0985/1472] Make reading json genesis file faster (#11868) * Make reading json genesis file faster * Formatting * fmt --- client/chain-spec/src/chain_spec.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index efb40d46f216a..5aafc28524dbf 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -61,7 +61,16 @@ impl GenesisSource { let file = File::open(path).map_err(|e| { format!("Error opening spec file at `{}`: {}", path.display(), e) })?; - let genesis: GenesisContainer = json::from_reader(file) + // SAFETY: `mmap` is fundamentally unsafe since technically the file can change + // underneath us while it is mapped; in practice it's unlikely to be a + // problem + let bytes = unsafe { + memmap2::Mmap::map(&file).map_err(|e| { + format!("Error mmaping spec file `{}`: {}", path.display(), e) + })? + }; + + let genesis: GenesisContainer = json::from_slice(&bytes) .map_err(|e| format!("Error parsing spec file: {}", e))?; Ok(genesis.genesis) }, From 58a80806f01bab8bcf9da9be8afdfd70ad50e7fe Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Thu, 21 Jul 2022 11:36:00 +0300 Subject: [PATCH 0986/1472] Cleanup light client leftovers (#11865) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove --light cli option * Cleanup light client leftovers * Remove commented-out code and clean-up more light client leftovers * Fix formatting with `cargo +nightly fmt` * Remove FIXME regarding db directory structure Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- client/cli/src/commands/run_cmd.rs | 17 +--- client/cli/src/config.rs | 8 +- .../src/communication/gossip.rs | 14 +-- client/network/src/config.rs | 8 -- client/network/src/protocol/message.rs | 1 - client/network/src/service.rs | 15 +-- client/network/src/transactions.rs | 13 --- client/rpc-api/src/system/helpers.rs | 2 - client/service/src/builder.rs | 93 +++++++------------ client/service/src/lib.rs | 7 -- client/service/src/metrics.rs | 2 +- 11 files changed, 44 insertions(+), 136 deletions(-) diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 12774eecc4174..99eaa4be1cd0f 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -50,10 +50,6 @@ pub struct RunCmd { #[clap(long)] pub no_grandpa: bool, - /// Experimental: Run in light client mode. - #[clap(long)] - pub light: bool, - /// Listen to all RPC interfaces. /// /// Default is local. Note: not all RPC methods are safe to be exposed publicly. Use an RPC @@ -337,7 +333,7 @@ impl CliConfiguration for RunCmd { fn dev_key_seed(&self, is_dev: bool) -> Result> { Ok(self.get_keyring().map(|a| format!("//{}", a)).or_else(|| { - if is_dev && !self.light { + if is_dev { Some("//Alice".into()) } else { None @@ -363,16 +359,9 @@ impl CliConfiguration for RunCmd { fn role(&self, is_dev: bool) -> Result { let keyring = self.get_keyring(); - let is_light = self.light; - let is_authority = (self.validator || is_dev || keyring.is_some()) && !is_light; + let is_authority = self.validator || is_dev || keyring.is_some(); - Ok(if is_light { - sc_service::Role::Light - } else if is_authority { - sc_service::Role::Authority - } else { - sc_service::Role::Full - }) + Ok(if is_authority { sc_service::Role::Authority } else { sc_service::Role::Full }) } fn force_authoring(&self) -> Result { diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 01c541bf75255..4ebbc8c72c19a 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -211,12 +211,8 @@ pub trait CliConfiguration: Sized { base_path: &PathBuf, cache_size: usize, database: Database, - role: &Role, ) -> Result { - let role_dir = match role { - Role::Light => "light", - Role::Full | Role::Authority => "full", - }; + let role_dir = "full"; let rocksdb_path = base_path.join("db").join(role_dir); let paritydb_path = base_path.join("paritydb").join(role_dir); Ok(match database { @@ -536,7 +532,7 @@ pub trait CliConfiguration: Sized { )?, keystore_remote, keystore, - database: self.database_config(&config_dir, database_cache_size, database, &role)?, + database: self.database_config(&config_dir, database_cache_size, database)?, state_cache_size: self.state_cache_size()?, state_cache_child_ratio: self.state_cache_child_ratio()?, state_pruning: self.state_pruning()?, diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 250e640cbf037..65d7dfb783aa3 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -728,11 +728,7 @@ type MaybeMessage = Option<(Vec, NeighborPacket> impl Inner { fn new(config: crate::Config) -> Self { - let catch_up_config = if config.local_role.is_light() { - // if we are a light client we shouldn't be issuing any catch-up requests - // as we don't participate in the full GRANDPA protocol - CatchUpConfig::disabled() - } else if config.observer_enabled { + let catch_up_config = if config.observer_enabled { if config.local_role.is_authority() { // since the observer protocol is enabled, we will only issue // catch-up requests if we are an authority (and only to other @@ -1231,10 +1227,6 @@ impl Inner { None => return false, }; - if self.config.local_role.is_light() { - return false - } - if round_elapsed < round_duration.mul_f32(PROPAGATION_SOME) { self.peers.first_stage_peers.contains(who) } else if round_elapsed < round_duration.mul_f32(PROPAGATION_ALL) { @@ -1266,10 +1258,6 @@ impl Inner { None => return false, }; - if self.config.local_role.is_light() { - return false - } - if round_elapsed < round_duration.mul_f32(PROPAGATION_ALL) { self.peers.first_stage_peers.contains(who) || self.peers.second_stage_peers.contains(who) || diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 430efd697a18c..58349fe973330 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -147,8 +147,6 @@ where pub enum Role { /// Regular full node. Full, - /// Regular light node. - Light, /// Actual authority. Authority, } @@ -158,18 +156,12 @@ impl Role { pub fn is_authority(&self) -> bool { matches!(self, Self::Authority { .. }) } - - /// True for [`Role::Light`]. - pub fn is_light(&self) -> bool { - matches!(self, Self::Light { .. }) - } } impl fmt::Display for Role { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Full => write!(f, "FULL"), - Self::Light => write!(f, "LIGHT"), Self::Authority { .. } => write!(f, "AUTHORITY"), } } diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index c9512f82e23bb..50c4a264a5f95 100644 --- a/client/network/src/protocol/message.rs +++ b/client/network/src/protocol/message.rs @@ -107,7 +107,6 @@ pub mod generic { fn from(roles: &'a crate::config::Role) -> Self { match roles { crate::config::Role::Full => Self::FULL, - crate::config::Role::Light => Self::LIGHT, crate::config::Role::Authority { .. } => Self::AUTHORITY, } } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 0d28b50df1821..bc6cfc73bec36 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -245,15 +245,11 @@ where }; let chain_sync = (params.create_chain_sync)( - if params.role.is_light() { - SyncMode::Light - } else { - match params.network_config.sync_mode { - config::SyncMode::Full => SyncMode::Full, - config::SyncMode::Fast { skip_proofs, storage_chain_mode } => - SyncMode::LightState { skip_proofs, storage_chain_mode }, - config::SyncMode::Warp => SyncMode::Warp, - } + match params.network_config.sync_mode { + config::SyncMode::Full => SyncMode::Full, + config::SyncMode::Fast { skip_proofs, storage_chain_mode } => + SyncMode::LightState { skip_proofs, storage_chain_mode }, + config::SyncMode::Warp => SyncMode::Warp, }, params.chain.clone(), warp_sync_provider, @@ -489,7 +485,6 @@ where let (tx_handler, tx_handler_controller) = transactions_handler_proto.build( service.clone(), - params.role, params.transaction_pool, params.metrics_registry.as_ref(), )?; diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 1f54f05d7446f..043bdeff7ebfc 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -83,8 +83,6 @@ mod rep { pub const GOOD_TRANSACTION: Rep = Rep::new(1 << 7, "Good transaction"); /// Reputation change when a peer sends us a bad transaction. pub const BAD_TRANSACTION: Rep = Rep::new(-(1 << 12), "Bad transaction"); - /// We received an unexpected transaction packet. - pub const UNEXPECTED_TRANSACTIONS: Rep = Rep::new_fatal("Unexpected transactions packet"); } struct Metrics { @@ -160,7 +158,6 @@ impl TransactionsHandlerPrototype { pub fn build( self, service: Arc>, - local_role: config::Role, transaction_pool: Arc>, metrics_registry: Option<&Registry>, ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { @@ -178,7 +175,6 @@ impl TransactionsHandlerPrototype { event_stream, peers: HashMap::new(), transaction_pool, - local_role, from_controller, metrics: if let Some(r) = metrics_registry { Some(Metrics::register(r)?) @@ -247,7 +243,6 @@ pub struct TransactionsHandler { peers: HashMap>, transaction_pool: Arc>, gossip_enabled: Arc, - local_role: config::Role, from_controller: mpsc::UnboundedReceiver>, /// Prometheus metrics. metrics: Option, @@ -360,14 +355,6 @@ impl TransactionsHandler { /// Called when peer sends us new transactions fn on_transactions(&mut self, who: PeerId, transactions: message::Transactions) { - // sending transaction to light node is considered a bad behavior - if matches!(self.local_role, config::Role::Light) { - debug!(target: "sync", "Peer {} is trying to send transactions to the light node", who); - self.service.disconnect_peer(who, self.protocol_name.clone()); - self.service.report_peer(who, rep::UNEXPECTED_TRANSACTIONS); - return - } - // Accept transactions only when enabled if !self.gossip_enabled.load(Ordering::Relaxed) { trace!(target: "sync", "{} Ignoring transactions while disabled", who); diff --git a/client/rpc-api/src/system/helpers.rs b/client/rpc-api/src/system/helpers.rs index e17e0f518c3e6..4561fccc1e81b 100644 --- a/client/rpc-api/src/system/helpers.rs +++ b/client/rpc-api/src/system/helpers.rs @@ -76,8 +76,6 @@ pub struct PeerInfo { pub enum NodeRole { /// The node is a full node Full, - /// The node is a light client - LightClient, /// The node is an authority Authority, } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index fe0ae5db53e70..0a18943f45006 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -37,17 +37,12 @@ use sc_client_db::{Backend, DatabaseSettings}; use sc_consensus::import_queue::ImportQueue; use sc_executor::RuntimeVersionOf; use sc_keystore::LocalKeystore; -use sc_network::{ - config::{Role, SyncMode}, - NetworkService, -}; +use sc_network::{config::SyncMode, NetworkService}; use sc_network_common::sync::warp::WarpSyncProvider; -use sc_network_light::light_client_requests::{self, handler::LightClientRequestHandler}; +use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ - block_request_handler::{self, BlockRequestHandler}, - state_request_handler::{self, StateRequestHandler}, - warp_request_handler::{self, RequestHandler as WarpSyncRequestHandler}, - ChainSync, + block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler, + warp_request_handler::RequestHandler as WarpSyncRequestHandler, ChainSync, }; use sc_rpc::{ author::AuthorApiServer, @@ -731,11 +726,8 @@ where } } - let transaction_pool_adapter = Arc::new(TransactionPoolAdapter { - imports_external_transactions: !matches!(config.role, Role::Light), - pool: transaction_pool, - client: client.clone(), - }); + let transaction_pool_adapter = + Arc::new(TransactionPoolAdapter { pool: transaction_pool, client: client.clone() }); let protocol_id = config.protocol_id(); @@ -746,63 +738,42 @@ where }; let block_request_protocol_config = { - if matches!(config.role, Role::Light) { - // Allow outgoing requests but deny incoming requests. - block_request_handler::generate_protocol_config(&protocol_id) - } else { - // Allow both outgoing and incoming requests. - let (handler, protocol_config) = BlockRequestHandler::new( - &protocol_id, - client.clone(), - config.network.default_peers_set.in_peers as usize + - config.network.default_peers_set.out_peers as usize, - ); - spawn_handle.spawn("block-request-handler", Some("networking"), handler.run()); - protocol_config - } + // Allow both outgoing and incoming requests. + let (handler, protocol_config) = BlockRequestHandler::new( + &protocol_id, + client.clone(), + config.network.default_peers_set.in_peers as usize + + config.network.default_peers_set.out_peers as usize, + ); + spawn_handle.spawn("block-request-handler", Some("networking"), handler.run()); + protocol_config }; let state_request_protocol_config = { - if matches!(config.role, Role::Light) { - // Allow outgoing requests but deny incoming requests. - state_request_handler::generate_protocol_config(&protocol_id) - } else { - // Allow both outgoing and incoming requests. - let (handler, protocol_config) = StateRequestHandler::new( - &protocol_id, - client.clone(), - config.network.default_peers_set_num_full as usize, - ); - spawn_handle.spawn("state-request-handler", Some("networking"), handler.run()); - protocol_config - } + // Allow both outgoing and incoming requests. + let (handler, protocol_config) = StateRequestHandler::new( + &protocol_id, + client.clone(), + config.network.default_peers_set_num_full as usize, + ); + spawn_handle.spawn("state-request-handler", Some("networking"), handler.run()); + protocol_config }; let warp_sync_params = warp_sync.map(|provider| { - let protocol_config = if matches!(config.role, Role::Light) { - // Allow outgoing requests but deny incoming requests. - warp_request_handler::generate_request_response_config(protocol_id.clone()) - } else { - // Allow both outgoing and incoming requests. - let (handler, protocol_config) = - WarpSyncRequestHandler::new(protocol_id.clone(), provider.clone()); - spawn_handle.spawn("warp-sync-request-handler", Some("networking"), handler.run()); - protocol_config - }; + // Allow both outgoing and incoming requests. + let (handler, protocol_config) = + WarpSyncRequestHandler::new(protocol_id.clone(), provider.clone()); + spawn_handle.spawn("warp-sync-request-handler", Some("networking"), handler.run()); (provider, protocol_config) }); let light_client_request_protocol_config = { - if matches!(config.role, Role::Light) { - // Allow outgoing requests but deny incoming requests. - light_client_requests::generate_protocol_config(&protocol_id) - } else { - // Allow both outgoing and incoming requests. - let (handler, protocol_config) = - LightClientRequestHandler::new(&protocol_id, client.clone()); - spawn_handle.spawn("light-client-request-handler", Some("networking"), handler.run()); - protocol_config - } + // Allow both outgoing and incoming requests. + let (handler, protocol_config) = + LightClientRequestHandler::new(&protocol_id, client.clone()); + spawn_handle.spawn("light-client-request-handler", Some("networking"), handler.run()); + protocol_config }; let max_parallel_downloads = config.network.max_parallel_downloads; diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 24ba670cfcd65..1b70227a70488 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -253,7 +253,6 @@ async fn build_network_future< let node_role = match role { Role::Authority { .. } => NodeRole::Authority, - Role::Light => NodeRole::LightClient, Role::Full => NodeRole::Full, }; @@ -377,7 +376,6 @@ where /// Transaction pool adapter. pub struct TransactionPoolAdapter { - imports_external_transactions: bool, pool: Arc

, client: Arc, } @@ -425,11 +423,6 @@ where } fn import(&self, transaction: B::Extrinsic) -> TransactionImportFuture { - if !self.imports_external_transactions { - debug!("Transaction rejected"); - return Box::pin(futures::future::ready(TransactionImport::None)) - } - let encoded = transaction.encode(); let uxt = match Decode::decode(&mut &encoded[..]) { Ok(uxt) => uxt, diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index 56b145ccdf7f7..ef3132f61ab99 100644 --- a/client/service/src/metrics.rs +++ b/client/service/src/metrics.rs @@ -160,7 +160,7 @@ impl MetricsService { ) -> Result { let role_bits = match config.role { Role::Full => 1u64, - Role::Light => 2u64, + // 2u64 used to represent light client role Role::Authority { .. } => 4u64, }; From cac91f59b9e3fb8fd59842c023f87b4206931993 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Thu, 21 Jul 2022 12:11:19 +0300 Subject: [PATCH 0987/1472] Stop RPC servers on drop (#11679) * Stop RPC servers on drop * Switch to existing wrappers that stop RPC servers * Apply formatting --- client/service/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 1b70227a70488..2e7b611ffb187 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -369,7 +369,8 @@ where match tokio::task::block_in_place(|| { config.tokio_handle.block_on(futures::future::try_join(http_fut, ws_fut)) }) { - Ok((http, ws)) => Ok(Box::new((http, ws))), + Ok((http, ws)) => + Ok(Box::new((waiting::HttpServer(Some(http)), waiting::WsServer(Some(ws))))), Err(e) => Err(Error::Application(e)), } } From b28bf15e5160f33e257e2cc6066bdd6c55a3eb42 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 21 Jul 2022 15:35:18 +0200 Subject: [PATCH 0988/1472] [ci] Generate rustdocs without dependencies (#11885) --- scripts/ci/gitlab/pipeline/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 25ecad5bc5264..eedd2ee0bb409 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -149,7 +149,7 @@ build-rustdoc: - ./crate-docs/ script: - rusty-cachier snapshot create - - time cargo +nightly doc --workspace --all-features --verbose + - time cargo +nightly doc --workspace --all-features --verbose --no-deps - rm -f $CARGO_TARGET_DIR/doc/.lock - mv $CARGO_TARGET_DIR/doc ./crate-docs # FIXME: remove me after CI image gets nonroot From 1399afdcd8ab4d7fad149c96f9cadcaf04b94f86 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Thu, 21 Jul 2022 17:09:21 +0200 Subject: [PATCH 0989/1472] pallet-mmr: fix batch proof failures (#11840) * pallet-mmr: extend batch proof verification test covers all possible 2-leaf combinations now, including current verification failures that batch proof item count limit is too low sometimes. * raise upper bound on proof item number as described in https://github.com/paritytech/substrate/issues/11753#issuecomment-1179838174 * test for powerset of leaves * refactor batch proof verification test * test all batch proofs for mmr sizes up to n=13 * limit mmr size to reduce batch proof test duration * use saturating integer addition for proof check * extract common chain building in batch proof tests note: right now, since not killing old chain, it keeps growing by 7 blocks for every leaf selection (added after proof generation), hence heavier to compute. * only add blocks after a proof generation once * increase batch proof testing range * register offchain extensions only once * fmt & remove unused util --- Cargo.lock | 1 + frame/merkle-mountain-range/Cargo.toml | 1 + frame/merkle-mountain-range/src/lib.rs | 2 +- .../merkle-mountain-range/src/mmr/storage.rs | 2 +- frame/merkle-mountain-range/src/mmr/utils.rs | 22 +----- frame/merkle-mountain-range/src/tests.rs | 70 ++++++++++++++----- 6 files changed, 58 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 279864e056b0b..3d5bfe5e51201 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5871,6 +5871,7 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", + "itertools", "parity-scale-codec", "scale-info", "sp-core", diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index f5f8bdee0855d..75301afed0094 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -27,6 +27,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives [dev-dependencies] env_logger = "0.9" hex-literal = "0.3" +itertools = "0.10.3" [features] default = ["std"] diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 9274e8e72c508..4644ebcb7da1c 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -351,7 +351,7 @@ impl, I: 'static> Pallet { ) -> Result<(), primitives::Error> { if proof.leaf_count > Self::mmr_leaves() || proof.leaf_count == 0 || - proof.items.len() as u32 > mmr::utils::NodesUtils::new(proof.leaf_count).depth() + (proof.items.len().saturating_add(leaves.len())) as u64 > proof.leaf_count { return Err(primitives::Error::Verify .log_debug("The proof has incorrect number of leaves or proof items.")) diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index d31262d4d7f2f..8b623edf56957 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -136,7 +136,7 @@ where let window_size = ::BlockHashCount::get().unique_saturated_into(); if leaves >= window_size { - // Move the rolling window towards the end of `block_num->hash` mappings available + // Move the rolling window towards the end of `block_num->hash` mappings available // in the runtime: we "canonicalize" the leaf at the end, let to_canon_leaf = leaves.saturating_sub(window_size); // and all the nodes added by that leaf. diff --git a/frame/merkle-mountain-range/src/mmr/utils.rs b/frame/merkle-mountain-range/src/mmr/utils.rs index 3734ea514782d..0b8e88a9283da 100644 --- a/frame/merkle-mountain-range/src/mmr/utils.rs +++ b/frame/merkle-mountain-range/src/mmr/utils.rs @@ -46,15 +46,6 @@ impl NodesUtils { 2 * self.no_of_leaves - self.number_of_peaks() } - /// Calculate maximal depth of the MMR. - pub fn depth(&self) -> u32 { - if self.no_of_leaves == 0 { - return 0 - } - - 64 - self.no_of_leaves.next_power_of_two().leading_zeros() - } - /// Calculate `LeafIndex` for the leaf that added `node_index` to the MMR. pub fn leaf_index_that_added_node(node_index: NodeIndex) -> LeafIndex { let rightmost_leaf_pos = Self::rightmost_leaf_node_index_from_pos(node_index); @@ -128,18 +119,7 @@ mod tests { } #[test] - fn should_calculate_number_of_leaves_correctly() { - assert_eq!( - vec![0, 1, 2, 3, 4, 9, 15, 21] - .into_iter() - .map(|n| NodesUtils::new(n).depth()) - .collect::>(), - vec![0, 1, 2, 3, 3, 5, 5, 6] - ); - } - - #[test] - fn should_calculate_depth_correclty() { + fn should_calculate_depth_correctly() { assert_eq!( vec![0, 1, 2, 3, 4, 9, 15, 21] .into_iter() diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 53226f8419988..566a051823d5e 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -347,28 +347,64 @@ fn should_verify() { } #[test] -fn should_verify_batch_proof() { +fn should_verify_batch_proofs() { + fn generate_and_verify_batch_proof( + ext: &mut sp_io::TestExternalities, + leaves: &Vec, + blocks_to_add: usize, + ) { + let (leaves, proof) = ext + .execute_with(|| crate::Pallet::::generate_batch_proof(leaves.to_vec()).unwrap()); + + ext.execute_with(|| { + add_blocks(blocks_to_add); + // then + assert_eq!(crate::Pallet::::verify_leaves(leaves, proof), Ok(())); + }) + } + let _ = env_logger::try_init(); - // Start off with chain initialisation and storing indexing data off-chain - // (MMR Leafs) - let mut ext = new_test_ext(); - ext.execute_with(|| add_blocks(7)); - ext.persist_offchain_overlay(); + use itertools::Itertools; - // Try to generate proof now. This requires the offchain extensions to be present - // to retrieve full leaf data. + let mut ext = new_test_ext(); + // require the offchain extensions to be present + // to retrieve full leaf data when generating proofs register_offchain_ext(&mut ext); - let (leaves, proof) = ext.execute_with(|| { - // when - crate::Pallet::::generate_batch_proof(vec![0, 4, 5]).unwrap() - }); - ext.execute_with(|| { - add_blocks(7); - // then - assert_eq!(crate::Pallet::::verify_leaves(leaves, proof), Ok(())); - }); + // verify that up to n=10, valid proofs are generated for all possible leaf combinations + for n in 0..10 { + ext.execute_with(|| new_block()); + ext.persist_offchain_overlay(); + + // generate powerset (skipping empty set) of all possible leaf combinations for mmr size n + let leaves_set: Vec> = (0..n).into_iter().powerset().skip(1).collect(); + + leaves_set.iter().for_each(|leaves_subset| { + generate_and_verify_batch_proof(&mut ext, leaves_subset, 0); + ext.persist_offchain_overlay(); + }); + } + + // verify that up to n=15, valid proofs are generated for all possible 2-leaf combinations + for n in 10..15 { + // (MMR Leafs) + ext.execute_with(|| new_block()); + ext.persist_offchain_overlay(); + + // generate all possible 2-leaf combinations for mmr size n + let leaves_set: Vec> = (0..n).into_iter().combinations(2).collect(); + + leaves_set.iter().for_each(|leaves_subset| { + generate_and_verify_batch_proof(&mut ext, leaves_subset, 0); + ext.persist_offchain_overlay(); + }); + } + + generate_and_verify_batch_proof(&mut ext, &vec![7, 11], 20); + ext.execute_with(|| add_blocks(1000)); + ext.persist_offchain_overlay(); + generate_and_verify_batch_proof(&mut ext, &vec![7, 11, 100, 800], 100); } #[test] From dbdbef95c84644328bee60bd170d79814c04e32b Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 22 Jul 2022 15:08:52 +0300 Subject: [PATCH 0990/1472] Clarify wrong bootnode peer ID error message (#11872) --- client/network/src/service.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/client/network/src/service.rs b/client/network/src/service.rs index bc6cfc73bec36..aeb5e25497bb3 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -2020,12 +2020,16 @@ where if this.boot_node_ids.contains(&peer_id) { if let DialError::WrongPeerId { obtained, endpoint } = &error { - error!( - "💔 The bootnode you want to connect provided a different peer ID than the one you expect: `{}` with `{}`:`{:?}`.", - peer_id, - obtained, - endpoint, - ); + if let ConnectedPoint::Dialer { address, role_override: _ } = + endpoint + { + error!( + "💔 The bootnode you want to connect to at `{}` provided a different peer ID `{}` than the one you expect `{}`.", + address, + obtained, + peer_id, + ); + } } } } From 7bb4936d788c84bfd9ed1bbde49336538459c5aa Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Sat, 23 Jul 2022 20:01:57 +0200 Subject: [PATCH 0991/1472] Fix for 'note_applied_extrinsic' - consider also 'extract_actual_pays_fee' (#11849) --- frame/support/src/weights.rs | 37 +++++++++++ frame/system/src/lib.rs | 5 +- frame/system/src/tests.rs | 119 ++++++++++++++++++++++++++++++++++- 3 files changed, 157 insertions(+), 4 deletions(-) diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index 24240c7cc4e6a..dd49409ccc912 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -358,6 +358,15 @@ pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &Dispatc .calc_actual_weight(info) } +/// Extract the actual pays_fee from a dispatch result if any or fall back to the default weight. +pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays { + match result { + Ok(post_info) => post_info, + Err(err) => &err.post_info, + } + .pays_fee(info) +} + impl From<(Option, Pays)> for PostDispatchInfo { fn from(post_weight_info: (Option, Pays)) -> Self { let (actual_weight, pays_fee) = post_weight_info; @@ -956,6 +965,34 @@ mod tests { ); } + #[test] + fn extract_actual_pays_fee_works() { + let pre = DispatchInfo { weight: 1000, ..Default::default() }; + assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::Yes); + assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::Yes); + assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::Yes); + assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::No).into()), &pre), Pays::No); + assert_eq!( + extract_actual_pays_fee(&Err(DispatchError::BadOrigin.with_weight(9)), &pre), + Pays::Yes + ); + assert_eq!( + extract_actual_pays_fee( + &Err(DispatchErrorWithPostInfo { + post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::No }, + error: DispatchError::BadOrigin, + }), + &pre + ), + Pays::No + ); + + let pre = DispatchInfo { weight: 1000, pays_fee: Pays::No, ..Default::default() }; + assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::No); + assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::No); + assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::No); + } + type Balance = u64; // 0.5x^3 + 2.333x^2 + 7x - 10_000 diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 3c6f514808b5d..94605c2da59bd 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -91,8 +91,8 @@ use frame_support::{ OriginTrait, PalletInfo, SortedMembers, StoredMap, TypedGet, }, weights::{ - extract_actual_weight, DispatchClass, DispatchInfo, PerDispatchClass, RuntimeDbWeight, - Weight, + extract_actual_pays_fee, extract_actual_weight, DispatchClass, DispatchInfo, + PerDispatchClass, RuntimeDbWeight, Weight, }, Parameter, }; @@ -1500,6 +1500,7 @@ impl Pallet { /// To be called immediately after an extrinsic has been applied. pub fn note_applied_extrinsic(r: &DispatchResultWithPostInfo, mut info: DispatchInfo) { info.weight = extract_actual_weight(r, &info); + info.pays_fee = extract_actual_pays_fee(r, &info); Self::deposit_event(match r { Ok(_) => Event::ExtrinsicSuccess { dispatch_info: info }, Err(err) => { diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index 0facd796b2a0c..417dca12045ee 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -17,7 +17,9 @@ use crate::*; use frame_support::{ - assert_noop, assert_ok, dispatch::PostDispatchInfo, weights::WithPostDispatchInfo, + assert_noop, assert_ok, + dispatch::PostDispatchInfo, + weights::{Pays, WithPostDispatchInfo}, }; use mock::{Origin, *}; use sp_core::H256; @@ -216,7 +218,7 @@ fn deposit_event_should_work() { } #[test] -fn deposit_event_uses_actual_weight() { +fn deposit_event_uses_actual_weight_and_pays_fee() { new_test_ext().execute_with(|| { System::reset_events(); System::initialize(&1, &[0u8; 32].into(), &Default::default()); @@ -230,8 +232,34 @@ fn deposit_event_uses_actual_weight() { &Ok(Some(1200).into()), pre_info, ); + System::note_applied_extrinsic(&Ok((Some(2_500_000), Pays::Yes).into()), pre_info); + System::note_applied_extrinsic(&Ok(Pays::No.into()), pre_info); + System::note_applied_extrinsic(&Ok((Some(2_500_000), Pays::No).into()), pre_info); + System::note_applied_extrinsic(&Ok((Some(500), Pays::No).into()), pre_info); System::note_applied_extrinsic(&Err(DispatchError::BadOrigin.with_weight(999)), pre_info); + System::note_applied_extrinsic( + &Err(DispatchErrorWithPostInfo { + post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }, + error: DispatchError::BadOrigin, + }), + pre_info, + ); + System::note_applied_extrinsic( + &Err(DispatchErrorWithPostInfo { + post_info: PostDispatchInfo { actual_weight: Some(800), pays_fee: Pays::Yes }, + error: DispatchError::BadOrigin, + }), + pre_info, + ); + System::note_applied_extrinsic( + &Err(DispatchErrorWithPostInfo { + post_info: PostDispatchInfo { actual_weight: Some(800), pays_fee: Pays::No }, + error: DispatchError::BadOrigin, + }), + pre_info, + ); + assert_eq!( System::events(), vec![ @@ -261,6 +289,54 @@ fn deposit_event_uses_actual_weight() { }, EventRecord { phase: Phase::ApplyExtrinsic(3), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: 1000, + pays_fee: Pays::Yes, + ..Default::default() + }, + } + .into(), + topics: vec![] + }, + EventRecord { + phase: Phase::ApplyExtrinsic(4), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: 1000, + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![] + }, + EventRecord { + phase: Phase::ApplyExtrinsic(5), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: 1000, + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![] + }, + EventRecord { + phase: Phase::ApplyExtrinsic(6), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: 500, + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![] + }, + EventRecord { + phase: Phase::ApplyExtrinsic(7), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { weight: 999, ..Default::default() }, @@ -268,6 +344,45 @@ fn deposit_event_uses_actual_weight() { .into(), topics: vec![] }, + EventRecord { + phase: Phase::ApplyExtrinsic(8), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: 1000, + pays_fee: Pays::Yes, + ..Default::default() + }, + } + .into(), + topics: vec![] + }, + EventRecord { + phase: Phase::ApplyExtrinsic(9), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: 800, + pays_fee: Pays::Yes, + ..Default::default() + }, + } + .into(), + topics: vec![] + }, + EventRecord { + phase: Phase::ApplyExtrinsic(10), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: 800, + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![] + }, ] ); }); From ca570cffee47d9fa4806715b0e8b284ec6db7e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 23 Jul 2022 21:28:25 +0200 Subject: [PATCH 0992/1472] pallet-assets: Update docs (#11877) --- frame/assets/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 3f9146c5d229b..e0b00c5642c81 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -79,8 +79,6 @@ //! * `create`: Creates a new asset class, taking the required deposit. //! * `transfer`: Transfer sender's assets to another account. //! * `transfer_keep_alive`: Transfer sender's assets to another account, keeping the sender alive. -//! * `set_metadata`: Set the metadata of an asset class. -//! * `clear_metadata`: Remove the metadata of an asset class. //! * `approve_transfer`: Create or increase an delegated transfer. //! * `cancel_approval`: Rescind a previous approval. //! * `transfer_approved`: Transfer third-party's assets to another account. @@ -103,6 +101,8 @@ //! * `transfer_ownership`: Changes an asset class's Owner; called by the asset class's Owner. //! * `set_team`: Changes an asset class's Admin, Freezer and Issuer; called by the asset class's //! Owner. +//! * `set_metadata`: Set the metadata of an asset class; called by the asset class's Owner. +//! * `clear_metadata`: Remove the metadata of an asset class; called by the asset class's Owner. //! //! Please refer to the [`Call`] enum and its associated variants for documentation on each //! function. From fe3437e7ffd3207199f140ca14558f303567c955 Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Mon, 25 Jul 2022 05:42:49 +0900 Subject: [PATCH 0993/1472] Fix typo in limits.rs (#11894) alway -> always --- frame/system/src/limits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index d3c108afb6f32..6076414ba6bcb 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -369,7 +369,7 @@ impl BlockWeightsBuilder { /// /// This is to make sure that extrinsics don't stay forever in the pool, /// because they could seamingly fit the block (since they are below `max_block`), - /// but the cost of calling `on_initialize` alway prevents them from being included. + /// but the cost of calling `on_initialize` always prevents them from being included. pub fn avg_block_initialization(mut self, init_cost: Perbill) -> Self { self.init_cost = Some(init_cost); self From 64d77551cb9ae0a9572a955d8a678d0de41af4bf Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 25 Jul 2022 11:15:47 +0200 Subject: [PATCH 0994/1472] [ci] fix node-bench-regression-guard job (#11901) * [Do not merge] [ci] debug node-bench-regression-guard * debug * fix artifacts path * add debug job * debug * debug * fix job, return pipeline --- scripts/ci/gitlab/pipeline/test.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index dcec896ddc18b..d900d425ad494 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -129,7 +129,11 @@ node-bench-regression-guard: artifacts: true # polls artifact from master to compare with current result - project: $CI_PROJECT_PATH - job: cargo-check-benches + job: "cargo-check-benches 1/2" + ref: master + artifacts: true + - project: $CI_PROJECT_PATH + job: "cargo-check-benches 2/2" ref: master artifacts: true variables: From 618f26bc9fe1a5ae8ee0a485e4e24da3e5979af6 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 25 Jul 2022 12:19:43 +0200 Subject: [PATCH 0995/1472] Remove unused leaves-set fields (#11895) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove unused leaves-set fields * Fix undo_import method Old leaf sould be inserted using the displaced number * Fix leaves count * Apply code review suggestions Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- client/api/src/leaves.rs | 81 +++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/client/api/src/leaves.rs b/client/api/src/leaves.rs index 5859290777433..2e5d4be3a5462 100644 --- a/client/api/src/leaves.rs +++ b/client/api/src/leaves.rs @@ -67,8 +67,6 @@ impl FinalizationDisplaced { #[derive(Debug, Clone, PartialEq, Eq)] pub struct LeafSet { storage: BTreeMap, Vec>, - pending_added: Vec<(H, N)>, - pending_removed: Vec, } impl LeafSet @@ -78,7 +76,7 @@ where { /// Construct a new, blank leaf set. pub fn new() -> Self { - Self { storage: BTreeMap::new(), pending_added: Vec::new(), pending_removed: Vec::new() } + Self { storage: BTreeMap::new() } } /// Read the leaf list from the DB, using given prefix for keys. @@ -97,21 +95,21 @@ where }, None => {}, } - Ok(Self { storage, pending_added: Vec::new(), pending_removed: Vec::new() }) + Ok(Self { storage }) } - /// update the leaf list on import. returns a displaced leaf if there was one. + /// Update the leaf list on import. + /// Returns a displaced leaf if there was one. pub fn import(&mut self, hash: H, number: N, parent_hash: H) -> Option> { // avoid underflow for genesis. let displaced = if number != N::zero() { - let new_number = Reverse(number.clone() - N::one()); - let was_displaced = self.remove_leaf(&new_number, &parent_hash); + let parent_number = Reverse(number.clone() - N::one()); + let was_displaced = self.remove_leaf(&parent_number, &parent_hash); if was_displaced { - self.pending_removed.push(parent_hash.clone()); Some(ImportDisplaced { new_hash: hash.clone(), - displaced: LeafSetItem { hash: parent_hash, number: new_number }, + displaced: LeafSetItem { hash: parent_hash, number: parent_number }, }) } else { None @@ -121,7 +119,6 @@ where }; self.insert_leaf(Reverse(number.clone()), hash.clone()); - self.pending_added.push((hash, number)); displaced } @@ -140,8 +137,6 @@ where }; let below_boundary = self.storage.split_off(&Reverse(boundary)); - self.pending_removed - .extend(below_boundary.values().flat_map(|h| h.iter()).cloned()); FinalizationDisplaced { leaves: below_boundary } } @@ -188,8 +183,6 @@ where self.remove_leaf(number, hash), "item comes from an iterator over storage; qed", ); - - self.pending_removed.push(hash.clone()); } } @@ -203,7 +196,6 @@ where // this is an invariant of regular block import. if !leaves_contains_best { self.insert_leaf(best_number.clone(), best_hash.clone()); - self.pending_added.push((best_hash, best_number.0)); } } @@ -213,9 +205,9 @@ where self.storage.iter().flat_map(|(_, hashes)| hashes.iter()).cloned().collect() } - /// Number of known leaves + /// Number of known leaves. pub fn count(&self) -> usize { - self.storage.len() + self.storage.values().map(|level| level.len()).sum() } /// Write the leaf list to the database transaction. @@ -227,8 +219,6 @@ where ) { let leaves: Vec<_> = self.storage.iter().map(|(n, h)| (n.0.clone(), h.clone())).collect(); tx.set_from_vec(column, prefix, leaves.encode()); - self.pending_added.clear(); - self.pending_removed.clear(); } /// Check if given block is a leaf. @@ -242,7 +232,7 @@ where self.storage.entry(number).or_insert_with(Vec::new).push(hash); } - // returns true if this leaf was contained, false otherwise. + // Returns true if this leaf was contained, false otherwise. fn remove_leaf(&mut self, number: &Reverse, hash: &H) -> bool { let mut empty = false; let removed = self.storage.get_mut(number).map_or(false, |leaves| { @@ -285,7 +275,7 @@ where pub fn undo_import(&mut self, displaced: ImportDisplaced) { let new_number = Reverse(displaced.displaced.number.0.clone() + N::one()); self.inner.remove_leaf(&new_number, &displaced.new_hash); - self.inner.insert_leaf(new_number, displaced.displaced.hash); + self.inner.insert_leaf(displaced.displaced.number, displaced.displaced.hash); } /// Undo a finalization operation by providing the displaced leaves. @@ -294,13 +284,6 @@ where } } -impl<'a, H: 'a, N: 'a> Drop for Undo<'a, H, N> { - fn drop(&mut self) { - self.inner.pending_added.clear(); - self.inner.pending_removed.clear(); - } -} - #[cfg(test)] mod tests { use super::*; @@ -315,15 +298,20 @@ mod tests { set.import(2_1, 2, 1_1); set.import(3_1, 3, 2_1); + assert_eq!(set.count(), 1); assert!(set.contains(3, 3_1)); assert!(!set.contains(2, 2_1)); assert!(!set.contains(1, 1_1)); assert!(!set.contains(0, 0)); set.import(2_2, 2, 1_1); + set.import(1_2, 1, 0); + set.import(2_3, 2, 1_2); + assert_eq!(set.count(), 3); assert!(set.contains(3, 3_1)); assert!(set.contains(2, 2_2)); + assert!(set.contains(2, 2_3)); } #[test] @@ -392,17 +380,42 @@ mod tests { } #[test] - fn undo_finalization() { + fn undo_import() { let mut set = LeafSet::new(); set.import(10_1u32, 10u32, 0u32); - set.import(11_1, 11, 10_2); - set.import(11_2, 11, 10_2); - set.import(12_1, 12, 11_123); + set.import(11_1, 11, 10_1); + set.import(11_2, 11, 10_1); + + let displaced = set.import(12_1, 12, 11_1).unwrap(); + assert_eq!(set.count(), 2); + assert!(set.contains(11, 11_2)); + assert!(set.contains(12, 12_1)); + + set.undo().undo_import(displaced); + assert_eq!(set.count(), 2); + assert!(set.contains(11, 11_1)); + assert!(set.contains(11, 11_2)); + } + + #[test] + fn undo_finalization() { + let mut set = LeafSet::new(); + set.import(9_1u32, 9u32, 0u32); + set.import(10_1, 10, 9_1); + set.import(10_2, 10, 9_1); + set.import(11_1, 11, 10_1); + set.import(11_2, 11, 10_1); + set.import(12_1, 12, 11_2); let displaced = set.finalize_height(11); - assert!(!set.contains(10, 10_1)); + assert_eq!(set.count(), 2); + assert!(set.contains(11, 11_1)); + assert!(set.contains(12, 12_1)); set.undo().undo_finalization(displaced); - assert!(set.contains(10, 10_1)); + assert_eq!(set.count(), 3); + assert!(set.contains(11, 11_1)); + assert!(set.contains(12, 12_1)); + assert!(set.contains(10, 10_2)); } } From c38d02bfa2e5cc11e905bc1bc1ded8529f445f61 Mon Sep 17 00:00:00 2001 From: Falco Hirschenberger Date: Mon, 25 Jul 2022 16:53:12 +0200 Subject: [PATCH 0996/1472] Add era to `Unbonded` event (#11770) * Add era to `Unbonded` event fixes #11749 * Fix missing tests * Add comment for `era` field in `Unbonded` struct. Co-authored-by: parity-processbot <> --- frame/nomination-pools/src/lib.rs | 4 +- frame/nomination-pools/src/tests.rs | 131 ++++++++++++------ .../nomination-pools/test-staking/src/lib.rs | 60 ++++++-- 3 files changed, 134 insertions(+), 61 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 514267e8bf4af..203c13f2f3496 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1349,7 +1349,7 @@ pub mod pallet { /// pool. /// - `points` is the number of points that are issued as a result of `balance` being /// dissolved into the corresponding unbonding pool. - /// + /// - `era` is the era in which the balance will be unbonded. /// In the absence of slashing, these values will match. In the presence of slashing, the /// number of points that are issued in the unbonding pool will be less than the amount /// requested to be unbonded. @@ -1358,6 +1358,7 @@ pub mod pallet { pool_id: PoolId, balance: BalanceOf, points: BalanceOf, + era: EraIndex, }, /// A member has withdrawn from their pool. /// @@ -1683,6 +1684,7 @@ pub mod pallet { pool_id: member.pool_id, points: points_unbonded, balance: unbonding_balance, + era: unbond_era, }); // Now that we know everything has worked write the items to storage. diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index c971239bef507..b59f18cca72a2 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -869,7 +869,7 @@ mod claim_payout { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 11, pool_id: 1, bonded: 11, joined: true }, - Event::Unbonded { member: 11, pool_id: 1, points: 11, balance: 11 } + Event::Unbonded { member: 11, pool_id: 1, points: 11, balance: 11, era: 3 } ] ); }); @@ -1374,7 +1374,7 @@ mod claim_payout { assert_eq!( pool_events_since_last_call(), vec![ - Event::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10 }, + Event::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 3 }, Event::PaidOut { member: 10, pool_id: 1, payout: 50 }, Event::PaidOut { member: 20, pool_id: 1, payout: 50 }, ] @@ -1808,12 +1808,12 @@ mod claim_payout { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, Event::Bonded { member: 30, pool_id: 1, bonded: 20, joined: true }, - Event::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10 }, + Event::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 3 }, Event::PaidOut { member: 30, pool_id: 1, payout: 15 }, - Event::Unbonded { member: 30, pool_id: 1, balance: 10, points: 10 }, - Event::Unbonded { member: 30, pool_id: 1, balance: 5, points: 5 }, + Event::Unbonded { member: 30, pool_id: 1, balance: 10, points: 10, era: 3 }, + Event::Unbonded { member: 30, pool_id: 1, balance: 5, points: 5, era: 3 }, Event::PaidOut { member: 20, pool_id: 1, payout: 7 }, - Event::Unbonded { member: 20, pool_id: 1, balance: 5, points: 5 }, + Event::Unbonded { member: 20, pool_id: 1, balance: 5, points: 5, era: 3 }, Event::PaidOut { member: 10, pool_id: 1, payout: 7 } ] ); @@ -1865,10 +1865,10 @@ mod claim_payout { pool_events_since_last_call(), vec![ Event::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, - Event::Unbonded { member: 20, pool_id: 1, balance: 20, points: 20 }, + Event::Unbonded { member: 20, pool_id: 1, balance: 20, points: 20, era: 3 }, Event::Withdrawn { member: 20, pool_id: 1, balance: 20, points: 20 }, Event::MemberRemoved { pool_id: 1, member: 20 }, - Event::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10 }, + Event::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 6 }, Event::Withdrawn { member: 10, pool_id: 1, balance: 10, points: 10 }, Event::MemberRemoved { pool_id: 1, member: 10 }, Event::Destroyed { pool_id: 1 } @@ -2269,7 +2269,7 @@ mod unbond { Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, Event::PaidOut { member: 40, pool_id: 1, payout: 40 }, - Event::Unbonded { member: 40, pool_id: 1, points: 6, balance: 6 } + Event::Unbonded { member: 40, pool_id: 1, points: 6, balance: 6, era: 3 } ] ); @@ -2311,7 +2311,13 @@ mod unbond { pool_events_since_last_call(), vec![ Event::PaidOut { member: 550, pool_id: 1, payout: 550 }, - Event::Unbonded { member: 550, pool_id: 1, points: 92, balance: 92 } + Event::Unbonded { + member: 550, + pool_id: 1, + points: 92, + balance: 92, + era: 3 + } ] ); @@ -2349,7 +2355,7 @@ mod unbond { Event::Withdrawn { member: 550, pool_id: 1, points: 92, balance: 92 }, Event::MemberRemoved { pool_id: 1, member: 550 }, Event::PaidOut { member: 10, pool_id: 1, payout: 10 }, - Event::Unbonded { member: 10, pool_id: 1, points: 2, balance: 2 } + Event::Unbonded { member: 10, pool_id: 1, points: 2, balance: 2, era: 6 } ] ); }); @@ -2395,7 +2401,7 @@ mod unbond { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10 } + Event::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10, era: 9 } ] ); }); @@ -2430,7 +2436,13 @@ mod unbond { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, Event::Bonded { member: 200, pool_id: 1, bonded: 200, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, points: 100, balance: 100 }, + Event::Unbonded { + member: 100, + pool_id: 1, + points: 100, + balance: 100, + era: 3 + }, ] ); @@ -2439,7 +2451,13 @@ mod unbond { assert_eq!( pool_events_since_last_call(), - vec![Event::Unbonded { member: 200, pool_id: 1, points: 200, balance: 200 }] + vec![Event::Unbonded { + member: 200, + pool_id: 1, + points: 200, + balance: 200, + era: 3 + }] ); assert_eq!( @@ -2508,7 +2526,7 @@ mod unbond { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, points: 100, balance: 100 } + Event::Unbonded { member: 100, pool_id: 1, points: 100, balance: 100, era: 3 } ] ); @@ -2659,7 +2677,7 @@ mod unbond { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1 } + Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1, era: 3 } ] ); @@ -2685,7 +2703,7 @@ mod unbond { ); assert_eq!( pool_events_since_last_call(), - vec![Event::Unbonded { member: 10, pool_id: 1, points: 5, balance: 5 }] + vec![Event::Unbonded { member: 10, pool_id: 1, points: 5, balance: 5, era: 3 }] ); // when: casual further unbond, next era. @@ -2712,7 +2730,7 @@ mod unbond { ); assert_eq!( pool_events_since_last_call(), - vec![Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1 }] + vec![Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1, era: 4 }] ); // when: unbonding more than our active: error @@ -2747,7 +2765,7 @@ mod unbond { ); assert_eq!( pool_events_since_last_call(), - vec![Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3 }] + vec![Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3, era: 4 }] ); }); } @@ -2792,9 +2810,9 @@ mod unbond { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, - Event::Unbonded { member: 20, pool_id: 1, balance: 2, points: 2 }, - Event::Unbonded { member: 20, pool_id: 1, balance: 3, points: 3 }, - Event::Unbonded { member: 20, pool_id: 1, balance: 1, points: 1 } + Event::Unbonded { member: 20, pool_id: 1, points: 2, balance: 2, era: 3 }, + Event::Unbonded { member: 20, pool_id: 1, points: 3, balance: 3, era: 4 }, + Event::Unbonded { member: 20, pool_id: 1, points: 1, balance: 1, era: 5 } ] ); }) @@ -2827,7 +2845,7 @@ mod unbond { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3 } + Event::Unbonded { member: 10, pool_id: 1, points: 3, balance: 3, era: 3 } ] ); }); @@ -2873,7 +2891,7 @@ mod unbond { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, Event::PaidOut { member: 20, pool_id: 1, payout: 10 }, - Event::Unbonded { member: 20, pool_id: 1, balance: 2, points: 2 } + Event::Unbonded { member: 20, pool_id: 1, balance: 2, points: 2, era: 3 } ] ); @@ -2889,7 +2907,7 @@ mod unbond { vec![ // 2/3 of ed, which is 20's share. Event::PaidOut { member: 20, pool_id: 1, payout: 6 }, - Event::Unbonded { member: 20, pool_id: 1, points: 3, balance: 3 } + Event::Unbonded { member: 20, pool_id: 1, points: 3, balance: 3, era: 4 } ] ); @@ -2904,7 +2922,7 @@ mod unbond { pool_events_since_last_call(), vec![ Event::PaidOut { member: 20, pool_id: 1, payout: 3 }, - Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5 } + Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5, era: 5 } ] ); @@ -3003,7 +3021,6 @@ mod withdraw_unbonded { with_era: Default::default() } ); - assert_eq!( pool_events_since_last_call(), vec![ @@ -3011,8 +3028,14 @@ mod withdraw_unbonded { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, - Event::Unbonded { member: 550, pool_id: 1, points: 550, balance: 550 }, - Event::Unbonded { member: 40, pool_id: 1, points: 40, balance: 40 }, + Event::Unbonded { + member: 550, + pool_id: 1, + points: 550, + balance: 550, + era: 3 + }, + Event::Unbonded { member: 40, pool_id: 1, points: 40, balance: 40, era: 3 }, ] ); assert_eq!( @@ -3077,7 +3100,7 @@ mod withdraw_unbonded { assert_eq!( pool_events_since_last_call(), vec![ - Event::Unbonded { member: 10, pool_id: 1, balance: 5, points: 5 }, + Event::Unbonded { member: 10, pool_id: 1, balance: 5, points: 5, era: 9 }, Event::Withdrawn { member: 10, pool_id: 1, balance: 5, points: 5 }, Event::MemberRemoved { pool_id: 1, member: 10 }, Event::Destroyed { pool_id: 1 } @@ -3122,8 +3145,14 @@ mod withdraw_unbonded { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, - Event::Unbonded { member: 40, pool_id: 1, balance: 20, points: 20 }, - Event::Unbonded { member: 550, pool_id: 1, balance: 275, points: 275 }, + Event::Unbonded { member: 40, pool_id: 1, balance: 20, points: 20, era: 3 }, + Event::Unbonded { + member: 550, + pool_id: 1, + balance: 275, + points: 275, + era: 3, + } ] ); assert_eq!( @@ -3199,7 +3228,7 @@ mod withdraw_unbonded { assert_eq!( pool_events_since_last_call(), vec![ - Event::Unbonded { member: 10, pool_id: 1, points: 5, balance: 5 }, + Event::Unbonded { member: 10, pool_id: 1, points: 5, balance: 5, era: 6 }, Event::Withdrawn { member: 10, pool_id: 1, points: 5, balance: 5 }, Event::MemberRemoved { pool_id: 1, member: 10 }, Event::Destroyed { pool_id: 1 } @@ -3313,8 +3342,20 @@ mod withdraw_unbonded { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, Event::Bonded { member: 200, pool_id: 1, bonded: 200, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, points: 100, balance: 100 }, - Event::Unbonded { member: 200, pool_id: 1, points: 200, balance: 200 } + Event::Unbonded { + member: 100, + pool_id: 1, + points: 100, + balance: 100, + era: 3 + }, + Event::Unbonded { + member: 200, + pool_id: 1, + points: 200, + balance: 200, + era: 3 + } ] ); @@ -3391,7 +3432,7 @@ mod withdraw_unbonded { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, points: 100, balance: 100 }, + Event::Unbonded { member: 100, pool_id: 1, points: 100, balance: 100, era: 3 }, Event::Withdrawn { member: 100, pool_id: 1, points: 100, balance: 100 }, Event::MemberRemoved { pool_id: 1, member: 100 } ] @@ -3431,8 +3472,8 @@ mod withdraw_unbonded { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: false }, - Event::Unbonded { member: 10, pool_id: 1, points: 6, balance: 6 }, - Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1 } + Event::Unbonded { member: 10, pool_id: 1, points: 6, balance: 6, era: 3 }, + Event::Unbonded { member: 10, pool_id: 1, points: 1, balance: 1, era: 4 } ] ); @@ -3518,8 +3559,8 @@ mod withdraw_unbonded { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 11, pool_id: 1, bonded: 10, joined: true }, - Event::Unbonded { member: 11, pool_id: 1, points: 6, balance: 6 }, - Event::Unbonded { member: 11, pool_id: 1, points: 1, balance: 1 } + Event::Unbonded { member: 11, pool_id: 1, points: 6, balance: 6, era: 3 }, + Event::Unbonded { member: 11, pool_id: 1, points: 1, balance: 1, era: 4 } ] ); @@ -3608,8 +3649,8 @@ mod withdraw_unbonded { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 100, pool_id: 1, bonded: 100, joined: true }, - Event::Unbonded { member: 100, pool_id: 1, points: 75, balance: 75 }, - Event::Unbonded { member: 100, pool_id: 1, points: 25, balance: 25 }, + Event::Unbonded { member: 100, pool_id: 1, points: 75, balance: 75, era: 3 }, + Event::Unbonded { member: 100, pool_id: 1, points: 25, balance: 25, era: 4 }, Event::Withdrawn { member: 100, pool_id: 1, points: 75, balance: 75 }, ] ); @@ -3680,9 +3721,9 @@ mod withdraw_unbonded { Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: false }, - Event::Unbonded { member: 10, pool_id: 1, balance: 7, points: 7 }, - Event::Unbonded { member: 10, pool_id: 1, balance: 3, points: 3 }, - Event::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10 }, + Event::Unbonded { member: 10, pool_id: 1, balance: 7, points: 7, era: 3 }, + Event::Unbonded { member: 10, pool_id: 1, balance: 3, points: 3, era: 4 }, + Event::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 4 }, Event::Withdrawn { member: 10, pool_id: 1, balance: 7, points: 7 } ] ); diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs index eed8e5fd390cd..5a7cd494362ca 100644 --- a/frame/nomination-pools/test-staking/src/lib.rs +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -95,8 +95,8 @@ fn pool_lifecycle_e2e() { pool_events_since_last_call(), vec![ PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10 }, - PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10 }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10, era: 3 }, + PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10, era: 3 }, ] ); @@ -159,7 +159,7 @@ fn pool_lifecycle_e2e() { ); assert_eq!( pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50 }] + vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50, era: 6 }] ); // waiting another bonding duration: @@ -237,8 +237,8 @@ fn pool_slash_e2e() { assert_eq!( pool_events_since_last_call(), vec![ - PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10 }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10 } + PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 4 }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 4 } ] ); @@ -262,9 +262,9 @@ fn pool_slash_e2e() { assert_eq!( pool_events_since_last_call(), vec![ - PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10 }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10 }, - PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10 }, + PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 5 }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 5 }, + PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 5 }, ] ); @@ -305,7 +305,7 @@ fn pool_slash_e2e() { assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Unbonded(POOL1_BONDED, 5)]); assert_eq!( pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5 }] + vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5, era: 6 }] ); // now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free. @@ -342,7 +342,7 @@ fn pool_slash_e2e() { pool_events_since_last_call(), vec![ PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, - PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10 } + PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10, era: 9 } ] ); @@ -432,7 +432,13 @@ fn pool_slash_proportional() { ); assert_eq!( pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: bond, points: bond }] + vec![PoolsEvent::Unbonded { + member: 20, + pool_id: 1, + balance: bond, + points: bond, + era: 127 + }] ); CurrentEra::::set(Some(100)); @@ -443,7 +449,13 @@ fn pool_slash_proportional() { ); assert_eq!( pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: bond, points: bond }] + vec![PoolsEvent::Unbonded { + member: 21, + pool_id: 1, + balance: bond, + points: bond, + era: 128 + }] ); CurrentEra::::set(Some(101)); @@ -454,7 +466,13 @@ fn pool_slash_proportional() { ); assert_eq!( pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 22, pool_id: 1, balance: bond, points: bond }] + vec![PoolsEvent::Unbonded { + member: 22, + pool_id: 1, + balance: bond, + points: bond, + era: 129 + }] ); // Apply a slash that happened in era 100. This is typically applied with a delay. @@ -531,7 +549,13 @@ fn pool_slash_non_proportional_only_bonded_pool() { ); assert_eq!( pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: bond, points: bond }] + vec![PoolsEvent::Unbonded { + member: 20, + pool_id: 1, + balance: bond, + points: bond, + era: 127 + }] ); // slash for 30. This will be deducted only from the bonded pool. @@ -598,7 +622,13 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { ); assert_eq!( pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: bond, points: bond }] + vec![PoolsEvent::Unbonded { + member: 20, + pool_id: 1, + balance: bond, + points: bond, + era: 127 + }] ); // slash 50. This will be deducted only from the bonded pool and one of the unbonding pools. From eefb4fad378181d8916c28f320a1ba383157c990 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:20:19 +0100 Subject: [PATCH 0997/1472] remove FunctionOf (#11897) * remove FunctionOf * fix docs Co-authored-by: parity-processbot <> --- frame/support/src/weights.rs | 89 +++--------------------------------- 1 file changed, 6 insertions(+), 83 deletions(-) diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index dd49409ccc912..c37a72536bddf 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -91,27 +91,19 @@ //! # fn main() {} //! ``` //! -//! ### 2. Define weights as a function of input arguments using `FunctionOf` tuple struct. +//! ### 2. Define weights as a function of input arguments. //! -//! This struct works in a similar manner as above. 3 items must be provided and each can be either -//! a fixed value or a function/closure with the same parameters list as the dispatchable function -//! itself, wrapper in a tuple. -//! -//! Using this only makes sense if you want to use a function for at least one of the elements. If -//! all 3 are static values, providing a raw tuple is easier. +//! The arguments of the dispatch are available in the weight expressions as a borrowed value. //! //! ``` //! # use frame_system::Config; -//! # use frame_support::weights::{DispatchClass, FunctionOf, Pays}; +//! # use frame_support::weights::{DispatchClass, Pays}; //! frame_support::decl_module! { //! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = FunctionOf( -//! // weight, function. -//! |args: (&u32, &u64)| *args.0 as u64 + args.1, -//! // class, fixed. +//! #[weight = ( +//! *a as u64 + *b, //! DispatchClass::Operational, -//! // pays fee, function. -//! |args: (&u32, &u64)| if *args.0 > 1000 { Pays::Yes } else { Pays::No }, +//! if *a > 1000 { Pays::Yes } else { Pays::No } //! )] //! fn dispatching(origin, a: u32, b: u64) { unimplemented!() } //! } @@ -508,75 +500,6 @@ impl PaysFee for (Weight, Pays) { } } -/// A struct to represent a weight which is a function of the input arguments. The given items have -/// the following types: -/// -/// - `WD`: a raw `Weight` value or a closure that returns a `Weight` with the same argument list as -/// the dispatched, wrapped in a tuple. -/// - `CD`: a raw `DispatchClass` value or a closure that returns a `DispatchClass` with the same -/// argument list as the dispatched, wrapped in a tuple. -/// - `PF`: a `Pays` variant for whether this dispatch pays fee or not or a closure that returns a -/// `Pays` variant with the same argument list as the dispatched, wrapped in a tuple. -#[deprecated = "Function arguments are available directly inside the annotation now."] -pub struct FunctionOf(pub WD, pub CD, pub PF); - -// `WeighData` as a raw value -#[allow(deprecated)] -impl WeighData for FunctionOf { - fn weigh_data(&self, _: Args) -> Weight { - self.0 - } -} - -// `WeighData` as a closure -#[allow(deprecated)] -impl WeighData for FunctionOf -where - WD: Fn(Args) -> Weight, -{ - fn weigh_data(&self, args: Args) -> Weight { - (self.0)(args) - } -} - -// `ClassifyDispatch` as a raw value -#[allow(deprecated)] -impl ClassifyDispatch for FunctionOf { - fn classify_dispatch(&self, _: Args) -> DispatchClass { - self.1 - } -} - -// `ClassifyDispatch` as a raw value -#[allow(deprecated)] -impl ClassifyDispatch for FunctionOf -where - CD: Fn(Args) -> DispatchClass, -{ - fn classify_dispatch(&self, args: Args) -> DispatchClass { - (self.1)(args) - } -} - -// `PaysFee` as a raw value -#[allow(deprecated)] -impl PaysFee for FunctionOf { - fn pays_fee(&self, _: Args) -> Pays { - self.2 - } -} - -// `PaysFee` as a closure -#[allow(deprecated)] -impl PaysFee for FunctionOf -where - PF: Fn(Args) -> Pays, -{ - fn pays_fee(&self, args: Args) -> Pays { - (self.2)(args) - } -} - /// Implementation for unchecked extrinsic. impl GetDispatchInfo for UncheckedExtrinsic From 720093428b90363cb909162ef7c05e5bd51ae626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 25 Jul 2022 17:48:01 +0200 Subject: [PATCH 0998/1472] contracts: Allow `ChainExtension::call()` to access `&mut self` (#11874) * Give chain extensions the ability to store some temporary values * Update frame/contracts/src/wasm/runtime.rs Co-authored-by: Hernando Castano * Rename func_id -> id * Replace `id` param by two functions on `env` Co-authored-by: Hernando Castano --- frame/contracts/fixtures/chain_extension.wat | 4 +- .../fixtures/chain_extension_temp_storage.wat | 85 ++++++++++ frame/contracts/src/chain_extension.rs | 41 +++-- frame/contracts/src/lib.rs | 2 +- frame/contracts/src/tests.rs | 150 +++++++++++++----- frame/contracts/src/wasm/runtime.rs | 28 +++- 6 files changed, 254 insertions(+), 56 deletions(-) create mode 100644 frame/contracts/fixtures/chain_extension_temp_storage.wat diff --git a/frame/contracts/fixtures/chain_extension.wat b/frame/contracts/fixtures/chain_extension.wat index 9b2534c540ab8..7cc7335052e90 100644 --- a/frame/contracts/fixtures/chain_extension.wat +++ b/frame/contracts/fixtures/chain_extension.wat @@ -31,14 +31,14 @@ ;; the chain extension passes through the input and returns it as output (call $seal_call_chain_extension - (i32.load (i32.const 4)) ;; func_id + (i32.load (i32.const 4)) ;; id (i32.const 4) ;; input_ptr (i32.load (i32.const 0)) ;; input_len (i32.const 16) ;; output_ptr (i32.const 12) ;; output_len_ptr ) - ;; the chain extension passes through the func_id + ;; the chain extension passes through the id (call $assert (i32.eq (i32.load (i32.const 4)))) (call $seal_return (i32.const 0) (i32.const 16) (i32.load (i32.const 12))) diff --git a/frame/contracts/fixtures/chain_extension_temp_storage.wat b/frame/contracts/fixtures/chain_extension_temp_storage.wat new file mode 100644 index 0000000000000..b481abb5bc7c9 --- /dev/null +++ b/frame/contracts/fixtures/chain_extension_temp_storage.wat @@ -0,0 +1,85 @@ +;; Call chain extension two times with the specified func_ids +;; It then calls itself once +(module + (import "seal0" "seal_call_chain_extension" + (func $seal_call_chain_extension (param i32 i32 i32 i32 i32) (result i32)) + ) + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_address" (func $seal_address (param i32 i32))) + (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 16 16)) + + (func $assert (param i32) + (block $ok + (br_if $ok (get_local 0)) + (unreachable) + ) + ) + + ;; [0, 4) len of input buffer: 8 byte (func_ids) + 1byte (stop_recurse) + (data (i32.const 0) "\09") + + ;; [4, 16) buffer for input + + ;; [16, 48] buffer for self address + + ;; [48, 52] len of self address buffer + (data (i32.const 48) "\20") + + (func (export "deploy")) + + (func (export "call") + ;; input: (func_id1: i32, func_id2: i32, stop_recurse: i8) + (call $seal_input (i32.const 4) (i32.const 0)) + + (call $seal_call_chain_extension + (i32.load (i32.const 4)) ;; id + (i32.const 0) ;; input_ptr + (i32.const 0) ;; input_len + (i32.const 0xffffffff) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; output_len_ptr + ) + drop + + (call $seal_call_chain_extension + (i32.load (i32.const 8)) ;; _id + (i32.const 0) ;; input_ptr + (i32.const 0) ;; input_len + (i32.const 0xffffffff) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; output_len_ptr + ) + drop + + (if (i32.eqz (i32.load8_u (i32.const 12))) + (then + ;; stop recursion + (i32.store8 (i32.const 12) (i32.const 1)) + + ;; load own address into buffer + (call $seal_address (i32.const 16) (i32.const 48)) + + ;; call function 2 + 3 of chainext 3 next time + ;; (3 << 16) | 2 + ;; (3 << 16) | 3 + (i32.store (i32.const 4) (i32.const 196610)) + (i32.store (i32.const 8) (i32.const 196611)) + + ;; call self + (call $seal_call + (i32.const 8) ;; Set ALLOW_REENTRY + (i32.const 16) ;; Pointer to "callee" address. + (i64.const 0) ;; How much gas to devote for the execution. 0 = all. + (i32.const 512) ;; Pointer to the buffer with value to transfer + (i32.const 4) ;; Pointer to input data buffer address + (i32.load (i32.const 0)) ;; Length of input data buffer + (i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + ) + + ;; check that call succeeded of call + (call $assert (i32.eqz)) + ) + (else) + ) + ) +) diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 536d58c94f68f..23242a2a542c1 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -33,7 +33,7 @@ //! //! Often there is a need for having multiple chain extensions. This is often the case when //! some generally useful off-the-shelf extensions should be included. To have multiple chain -//! extensions they can be put into a tuple which is then passed to `[Config::ChainExtension]` like +//! extensions they can be put into a tuple which is then passed to [`Config::ChainExtension`] like //! this `type Extensions = (ExtensionA, ExtensionB)`. //! //! However, only extensions implementing [`RegisteredChainExtension`] can be put into a tuple. @@ -94,6 +94,12 @@ pub type Result = sp_std::result::Result; /// In order to create a custom chain extension this trait must be implemented and supplied /// to the pallet contracts configuration trait as the associated type of the same name. /// Consult the [module documentation](self) for a general explanation of chain extensions. +/// +/// # Lifetime +/// +/// The extension will be [`Default`] initialized at the beginning of each call +/// (**not** per call stack) and dropped afterwards. Hence any value held inside the extension +/// can be used as a per-call scratch buffer. pub trait ChainExtension { /// Call the chain extension logic. /// @@ -102,8 +108,6 @@ pub trait ChainExtension { /// imported wasm function. /// /// # Parameters - /// - `func_id`: The first argument to `seal_call_chain_extension`. Usually used to determine - /// which function to realize. /// - `env`: Access to the remaining arguments and the execution environment. /// /// # Return @@ -111,7 +115,7 @@ pub trait ChainExtension { /// In case of `Err` the contract execution is immediately suspended and the passed error /// is returned to the caller. Otherwise the value of [`RetVal`] determines the exit /// behaviour. - fn call(func_id: u32, env: Environment) -> Result + fn call(&mut self, env: Environment) -> Result where E: Ext, ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>; @@ -132,7 +136,7 @@ pub trait ChainExtension { /// /// An extension that implements this trait can be put in a tuple in order to have multiple /// extensions available. The tuple implementation routes requests based on the first two -/// most significant bytes of the `func_id` passed to `call`. +/// most significant bytes of the `id` passed to `call`. /// /// If this extensions is to be used by multiple runtimes consider /// [registering it](https://github.com/paritytech/chainextension-registry) to ensure that there @@ -150,15 +154,15 @@ pub trait RegisteredChainExtension: ChainExtension { #[impl_trait_for_tuples::impl_for_tuples(10)] #[tuple_types_custom_trait_bound(RegisteredChainExtension)] impl ChainExtension for Tuple { - fn call(func_id: u32, mut env: Environment) -> Result + fn call(&mut self, mut env: Environment) -> Result where E: Ext, ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { for_tuples!( #( - if (Tuple::ID == (func_id >> 16) as u16) && Tuple::enabled() { - return Tuple::call(func_id, env); + if (Tuple::ID == env.ext_id()) && Tuple::enabled() { + return Tuple.call(env); } )* ); @@ -206,6 +210,22 @@ impl<'a, 'b, E: Ext, S: state::State> Environment<'a, 'b, E, S> where ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { + /// The function id within the `id` passed by a contract. + /// + /// It returns the two least significant bytes of the `id` passed by a contract as the other + /// two bytes represent the chain extension itself (the code which is calling this function). + pub fn func_id(&self) -> u16 { + (self.inner.id & 0x00FF) as u16 + } + + /// The chain extension id within the `id` passed by a contract. + /// + /// It returns the two most significant bytes of the `id` passed by a contract which represent + /// the chain extension itself (the code which is calling this function). + pub fn ext_id(&self) -> u16 { + (self.inner.id >> 16) as u16 + } + /// Charge the passed `amount` of weight from the overall limit. /// /// It returns `Ok` when there the remaining weight budget is larger than the passed @@ -251,13 +271,14 @@ impl<'a, 'b, E: Ext> Environment<'a, 'b, E, state::Init> { /// ever create this type. Chain extensions merely consume it. pub(crate) fn new( runtime: &'a mut Runtime<'b, E>, + id: u32, input_ptr: u32, input_len: u32, output_ptr: u32, output_len_ptr: u32, ) -> Self { Environment { - inner: Inner { runtime, input_ptr, input_len, output_ptr, output_len_ptr }, + inner: Inner { runtime, id, input_ptr, input_len, output_ptr, output_len_ptr }, phantom: PhantomData, } } @@ -406,6 +427,8 @@ struct Inner<'a, 'b, E: Ext> { /// The runtime contains all necessary functions to interact with the running contract. runtime: &'a mut Runtime<'b, E>, /// Verbatim argument passed to `seal_call_chain_extension`. + id: u32, + /// Verbatim argument passed to `seal_call_chain_extension`. input_ptr: u32, /// Verbatim argument passed to `seal_call_chain_extension`. input_len: u32, diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 60b30ffa25005..319bacaab7789 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -280,7 +280,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// Type that allows the runtime authors to add new host functions for a contract to call. - type ChainExtension: chain_extension::ChainExtension; + type ChainExtension: chain_extension::ChainExtension + Default; /// Cost schedule and limits. #[pallet::constant] diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 85a0e9977d2d7..0febfec929b6e 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -118,10 +118,17 @@ pub struct TestExtension { last_seen_inputs: (u32, u32, u32, u32), } +#[derive(Default)] pub struct RevertingExtension; +#[derive(Default)] pub struct DisabledExtension; +#[derive(Default)] +pub struct TempStorageExtension { + storage: u32, +} + impl TestExtension { fn disable() { TEST_EXTENSION.with(|e| e.borrow_mut().enabled = false) @@ -143,18 +150,20 @@ impl Default for TestExtension { } impl ChainExtension for TestExtension { - fn call(func_id: u32, env: Environment) -> ExtensionResult + fn call(&mut self, env: Environment) -> ExtensionResult where E: Ext, ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { + let func_id = env.func_id(); + let id = env.ext_id() as u32 | func_id as u32; match func_id { 0 => { let mut env = env.buf_in_buf_out(); let input = env.read(8)?; env.write(&input, false, None)?; TEST_EXTENSION.with(|e| e.borrow_mut().last_seen_buffer = input); - Ok(RetVal::Converging(func_id)) + Ok(RetVal::Converging(id)) }, 1 => { let env = env.only_in(); @@ -162,17 +171,17 @@ impl ChainExtension for TestExtension { e.borrow_mut().last_seen_inputs = (env.val0(), env.val1(), env.val2(), env.val3()) }); - Ok(RetVal::Converging(func_id)) + Ok(RetVal::Converging(id)) }, 2 => { let mut env = env.buf_in_buf_out(); let weight = env.read(5)?[4].into(); env.charge_weight(weight)?; - Ok(RetVal::Converging(func_id)) + Ok(RetVal::Converging(id)) }, 3 => Ok(RetVal::Diverging { flags: ReturnFlags::REVERT, data: vec![42, 99] }), _ => { - panic!("Passed unknown func_id to test chain extension: {}", func_id); + panic!("Passed unknown id to test chain extension: {}", func_id); }, } } @@ -187,7 +196,7 @@ impl RegisteredChainExtension for TestExtension { } impl ChainExtension for RevertingExtension { - fn call(_func_id: u32, _env: Environment) -> ExtensionResult + fn call(&mut self, _env: Environment) -> ExtensionResult where E: Ext, ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, @@ -205,7 +214,7 @@ impl RegisteredChainExtension for RevertingExtension { } impl ChainExtension for DisabledExtension { - fn call(_func_id: u32, _env: Environment) -> ExtensionResult + fn call(&mut self, _env: Environment) -> ExtensionResult where E: Ext, ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, @@ -222,6 +231,37 @@ impl RegisteredChainExtension for DisabledExtension { const ID: u16 = 2; } +impl ChainExtension for TempStorageExtension { + fn call(&mut self, env: Environment) -> ExtensionResult + where + E: Ext, + ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, + { + let func_id = env.func_id(); + match func_id { + 0 => self.storage = 42, + 1 => assert_eq!(self.storage, 42, "Storage is preserved inside the same call."), + 2 => { + assert_eq!(self.storage, 0, "Storage is different for different calls."); + self.storage = 99; + }, + 3 => assert_eq!(self.storage, 99, "Storage is preserved inside the same call."), + _ => { + panic!("Passed unknown id to test chain extension: {}", func_id); + }, + } + Ok(RetVal::Converging(0)) + } + + fn enabled() -> bool { + TEST_EXTENSION.with(|e| e.borrow().enabled) + } +} + +impl RegisteredChainExtension for TempStorageExtension { + const ID: u16 = 3; +} + parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND); @@ -325,7 +365,8 @@ impl Config for Test { type CallStack = [Frame; 31]; type WeightPrice = Self; type WeightInfo = (); - type ChainExtension = (TestExtension, DisabledExtension, RevertingExtension); + type ChainExtension = + (TestExtension, DisabledExtension, RevertingExtension, TempStorageExtension); type DeletionQueueDepth = ConstU32<1024>; type DeletionWeightLimit = ConstU64<500_000_000_000>; type Schedule = MySchedule; @@ -396,6 +437,29 @@ fn initialize_block(number: u64) { System::initialize(&number, &[0u8; 32].into(), &Default::default()); } +struct ExtensionInput<'a> { + extension_id: u16, + func_id: u16, + extra: &'a [u8], +} + +impl<'a> ExtensionInput<'a> { + fn to_vec(&self) -> Vec { + ((self.extension_id as u32) << 16 | (self.func_id as u32)) + .to_le_bytes() + .iter() + .chain(self.extra) + .cloned() + .collect() + } +} + +impl<'a> From> for Vec { + fn from(input: ExtensionInput) -> Vec { + input.to_vec() + } +} + // Perform a call to a plain account. // The actual transfer fails because we can only call contracts. // Then we check that at least the base costs where charged (no runtime gas costs.) @@ -1567,23 +1631,6 @@ fn disabled_chain_extension_errors_on_call() { #[test] fn chain_extension_works() { - struct Input<'a> { - extension_id: u16, - func_id: u16, - extra: &'a [u8], - } - - impl<'a> From> for Vec { - fn from(input: Input) -> Vec { - ((input.extension_id as u32) << 16 | (input.func_id as u32)) - .to_le_bytes() - .iter() - .chain(input.extra) - .cloned() - .collect() - } - } - let (code, hash) = compile_module::("chain_extension").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let min_balance = ::Currency::minimum_balance(); @@ -1599,12 +1646,8 @@ fn chain_extension_works() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - // The contract takes a up to 2 byte buffer where the first byte passed is used as - // as func_id to the chain extension which behaves differently based on the - // func_id. - // 0 = read input buffer and pass it through as output - let input: Vec = Input { extension_id: 0, func_id: 0, extra: &[99] }.into(); + let input: Vec = ExtensionInput { extension_id: 0, func_id: 0, extra: &[99] }.into(); let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false); assert_eq!(TestExtension::last_seen_buffer(), input); @@ -1617,7 +1660,7 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - Input { extension_id: 0, func_id: 1, extra: &[] }.into(), + ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into(), false, ) .result @@ -1632,7 +1675,7 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - Input { extension_id: 0, func_id: 2, extra: &[0] }.into(), + ExtensionInput { extension_id: 0, func_id: 2, extra: &[0] }.into(), false, ); assert_ok!(result.result); @@ -1643,7 +1686,7 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - Input { extension_id: 0, func_id: 2, extra: &[42] }.into(), + ExtensionInput { extension_id: 0, func_id: 2, extra: &[42] }.into(), false, ); assert_ok!(result.result); @@ -1654,7 +1697,7 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - Input { extension_id: 0, func_id: 2, extra: &[95] }.into(), + ExtensionInput { extension_id: 0, func_id: 2, extra: &[95] }.into(), false, ); assert_ok!(result.result); @@ -1667,7 +1710,7 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - Input { extension_id: 0, func_id: 3, extra: &[] }.into(), + ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into(), false, ) .result @@ -1684,7 +1727,7 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - Input { extension_id: 1, func_id: 0, extra: &[] }.into(), + ExtensionInput { extension_id: 1, func_id: 0, extra: &[] }.into(), false, ) .result @@ -1701,13 +1744,46 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - Input { extension_id: 2, func_id: 0, extra: &[] }.into(), + ExtensionInput { extension_id: 2, func_id: 0, extra: &[] }.into(), ), Error::::NoChainExtension, ); }); } +#[test] +fn chain_extension_temp_storage_works() { + let (code, hash) = compile_module::("chain_extension_temp_storage").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); + assert_ok!(Contracts::instantiate_with_code( + Origin::signed(ALICE), + min_balance * 100, + GAS_LIMIT, + None, + code, + vec![], + vec![], + ),); + let addr = Contracts::contract_address(&ALICE, &hash, &[]); + + // Call func 0 and func 1 back to back. + let stop_recursion = 0u8; + let mut input: Vec = ExtensionInput { extension_id: 3, func_id: 0, extra: &[] }.into(); + input.extend_from_slice( + ExtensionInput { extension_id: 3, func_id: 1, extra: &[stop_recursion] } + .to_vec() + .as_ref(), + ); + + assert_ok!( + Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false) + .result + ); + }) +} + #[test] fn lazy_removal_works() { let (code, hash) = compile_module::("self_destruct").unwrap(); diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index c1757ba06412a..3d5e62f2c1333 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -65,7 +65,7 @@ impl KeyType { /// This enum can be extended in the future: New codes can be added but existing codes /// will not be changed or removed. This means that any contract **must not** exhaustively /// match return codes. Instead, contracts should prepare for unknown variants and deal with -/// those errors gracefuly in order to be forward compatible. +/// those errors gracefully in order to be forward compatible. #[repr(u32)] pub enum ReturnCode { /// API call successful. @@ -101,8 +101,9 @@ pub enum ReturnCode { } impl ConvertibleToWasm for ReturnCode { - type NativeType = Self; const VALUE_TYPE: ValueType = ValueType::I32; + type NativeType = Self; + fn to_typed_value(self) -> sp_sandbox::Value { sp_sandbox::Value::I32(self as i32) } @@ -439,6 +440,7 @@ pub struct Runtime<'a, E: Ext + 'a> { input_data: Option>, memory: sp_sandbox::default_executor::Memory, trap_reason: Option, + chain_extension: Option::ChainExtension>>, } impl<'a, E> Runtime<'a, E> @@ -452,7 +454,13 @@ where input_data: Vec, memory: sp_sandbox::default_executor::Memory, ) -> Self { - Runtime { ext, input_data: Some(input_data), memory, trap_reason: None } + Runtime { + ext, + input_data: Some(input_data), + memory, + trap_reason: None, + chain_extension: Some(Box::new(Default::default())), + } } /// Converts the sandbox result and the runtime state into the execution outcome. @@ -2006,7 +2014,7 @@ define_env!(Env, , // module error. [seal0] seal_call_chain_extension( ctx, - func_id: u32, + id: u32, input_ptr: u32, input_len: u32, output_ptr: u32, @@ -2016,14 +2024,20 @@ define_env!(Env, , if !::ChainExtension::enabled() { return Err(Error::::NoChainExtension.into()); } - let env = Environment::new(ctx, input_ptr, input_len, output_ptr, output_len_ptr); - match ::ChainExtension::call(func_id, env)? { + let mut chain_extension = ctx.chain_extension.take().expect( + "Constructor initializes with `Some`. This is the only place where it is set to `None`.\ + It is always reset to `Some` afterwards. qed" + ); + let env = Environment::new(ctx, id, input_ptr, input_len, output_ptr, output_len_ptr); + let ret = match chain_extension.call(env)? { RetVal::Converging(val) => Ok(val), RetVal::Diverging{flags, data} => Err(TrapReason::Return(ReturnData { flags: flags.bits(), data, })), - } + }; + ctx.chain_extension = Some(chain_extension); + ret }, // Emit a custom debug message. From 9b139a5117081dc1d70890c02e5a09a46bc95fb6 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Tue, 26 Jul 2022 00:52:11 +0800 Subject: [PATCH 0999/1472] Pruned duplicated dependencies (#11900) * Update comfy-table v5.0.1 => v6.0.0 Signed-off-by: koushiro * Update strum v0.23.0 => v0.24.1 Signed-off-by: koushiro * Update h2 v0.3.9 => v0.3.13 Signed-off-by: koushiro * Update file-per-thread-logger v0.1.4 => v0.1.5 Signed-off-by: koushiro * Update mio v0.8.0 => v0.8.4 Signed-off-by: koushiro * revert twox-hash Signed-off-by: koushiro * Update secp256k1 v0.21.2 => v0.24.0 Signed-off-by: koushiro --- Cargo.lock | 324 +++--------------- client/beefy/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 9 +- primitives/core/Cargo.toml | 2 +- primitives/core/src/ecdsa.rs | 2 +- primitives/io/Cargo.toml | 2 +- primitives/keyring/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/wasm-builder/Cargo.toml | 2 +- 9 files changed, 65 insertions(+), 282 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d5bfe5e51201..8c19c80bde1a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -230,7 +230,7 @@ dependencies = [ "parking", "polling", "slab", - "socket2 0.4.4", + "socket2", "waker-fn", "winapi", ] @@ -310,7 +310,7 @@ dependencies = [ "futures-io", "futures-util", "pin-utils", - "socket2 0.4.4", + "socket2", "trust-dns-resolver", ] @@ -382,12 +382,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - [[package]] name = "autocfg" version = "1.0.1" @@ -512,7 +506,7 @@ name = "beefy-merkle-tree" version = "4.0.0-dev" dependencies = [ "beefy-primitives", - "env_logger 0.9.0", + "env_logger", "hex", "hex-literal", "log", @@ -1005,7 +999,7 @@ version = "3.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" dependencies = [ - "heck 0.4.0", + "heck", "proc-macro-error", "proc-macro2", "quote", @@ -1021,15 +1015,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - [[package]] name = "cmake" version = "0.1.46" @@ -1041,9 +1026,9 @@ dependencies = [ [[package]] name = "comfy-table" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b103d85ca6e209388771bfb7aa6b68a7aeec4afbf6f0a0264bfbf50360e5212e" +checksum = "121d8a5b0346092c18a4b2fd6f620d7a06f0eb7ac0a45860939a0884bc579c56" dependencies = [ "strum", "strum_macros", @@ -1831,7 +1816,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" dependencies = [ - "heck 0.4.0", + "heck", "proc-macro2", "quote", "syn", @@ -1898,19 +1883,6 @@ dependencies = [ "syn", ] -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime 1.3.0", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.9.0" @@ -1918,7 +1890,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", - "humantime 2.1.0", + "humantime", "log", "regex", "termcolor", @@ -2008,11 +1980,11 @@ dependencies = [ [[package]] name = "file-per-thread-logger" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdbe0d94371f9ce939b555dd342d0686cc4c0cadbcd4b61d70af5ff97eb4126" +checksum = "21e16290574b39ee41c71aeb90ae960c504ebaf1e2a1c87bd52aa56ed6e1a02f" dependencies = [ - "env_logger 0.7.1", + "env_logger", "log", ] @@ -2445,12 +2417,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - [[package]] name = "funty" version = "2.0.0" @@ -2751,9 +2717,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.9" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" dependencies = [ "bytes", "fnv", @@ -2764,7 +2730,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.6.7", + "tokio-util", "tracing", ] @@ -2821,15 +2787,6 @@ dependencies = [ "ahash", ] -[[package]] -name = "heck" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "heck" version = "0.4.0" @@ -2950,15 +2907,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error 1.2.3", -] - [[package]] name = "humantime" version = "2.1.0" @@ -2982,7 +2930,7 @@ dependencies = [ "httpdate", "itoa 0.4.8", "pin-project-lite 0.2.6", - "socket2 0.4.4", + "socket2", "tokio", "tower-service", "tracing", @@ -3084,7 +3032,7 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ - "autocfg 1.0.1", + "autocfg", "hashbrown 0.11.2", "serde", ] @@ -3131,7 +3079,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" dependencies = [ - "socket2 0.4.4", + "socket2", "widestring", "winapi", "winreg", @@ -3213,7 +3161,7 @@ dependencies = [ "thiserror", "tokio", "tokio-rustls", - "tokio-util 0.7.1", + "tokio-util", "tracing", "webpki-roots", ] @@ -3316,7 +3264,7 @@ dependencies = [ "soketto", "tokio", "tokio-stream", - "tokio-util 0.7.1", + "tokio-util", "tracing", ] @@ -3695,7 +3643,7 @@ dependencies = [ "log", "rand 0.8.4", "smallvec", - "socket2 0.4.4", + "socket2", "void", ] @@ -3913,7 +3861,7 @@ dependencies = [ "libc", "libp2p-core", "log", - "socket2 0.4.4", + "socket2", ] [[package]] @@ -4276,7 +4224,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" dependencies = [ - "autocfg 1.0.1", + "autocfg", ] [[package]] @@ -4321,30 +4269,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", - "autocfg 1.0.1", + "autocfg", ] [[package]] name = "mio" -version = "0.8.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" dependencies = [ "libc", "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" -dependencies = [ - "socket2 0.3.19", - "winapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.36.1", ] [[package]] @@ -5015,22 +4952,13 @@ dependencies = [ "version_check", ] -[[package]] -name = "ntapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi", -] - [[package]] name = "num-bigint" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ - "autocfg 1.0.1", + "autocfg", "num-integer", "num-traits", ] @@ -5060,7 +4988,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg 1.0.1", + "autocfg", "num-traits", ] @@ -5070,7 +4998,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ - "autocfg 1.0.1", + "autocfg", "num-bigint", "num-integer", "num-traits", @@ -5082,7 +5010,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" dependencies = [ - "autocfg 1.0.1", + "autocfg", "num-integer", "num-traits", ] @@ -5093,7 +5021,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.1", + "autocfg", "libm", ] @@ -5500,7 +5428,7 @@ version = "4.0.0-dev" dependencies = [ "assert_matches", "bitflags", - "env_logger 0.9.0", + "env_logger", "frame-benchmarking", "frame-support", "frame-system", @@ -5866,7 +5794,7 @@ name = "pallet-mmr" version = "4.0.0-dev" dependencies = [ "ckb-merkle-mountain-range", - "env_logger 0.9.0", + "env_logger", "frame-benchmarking", "frame-support", "frame-system", @@ -7082,7 +7010,7 @@ dependencies = [ "bytes", "cfg-if 1.0.0", "cmake", - "heck 0.4.0", + "heck", "itertools", "lazy_static", "log", @@ -7207,25 +7135,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.7", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc 0.1.0", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg 0.1.2", - "rand_xorshift", - "winapi", -] - [[package]] name = "rand" version = "0.7.3" @@ -7252,16 +7161,6 @@ dependencies = [ "rand_hc 0.3.0", ] -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.3.1", -] - [[package]] name = "rand_chacha" version = "0.2.2" @@ -7282,21 +7181,6 @@ dependencies = [ "rand_core 0.6.2", ] -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - [[package]] name = "rand_core" version = "0.5.1" @@ -7325,15 +7209,6 @@ dependencies = [ "rand 0.8.4", ] -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "rand_hc" version = "0.2.0" @@ -7352,50 +7227,6 @@ dependencies = [ "rand_core 0.6.2", ] -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.4.2", -] - [[package]] name = "rand_pcg" version = "0.2.1" @@ -7414,15 +7245,6 @@ dependencies = [ "rand_core 0.6.2", ] -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "rawpointer" version = "0.2.1" @@ -7435,7 +7257,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" dependencies = [ - "autocfg 1.0.1", + "autocfg", "crossbeam-deque", "either", "rayon-core", @@ -7454,15 +7276,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "redox_syscall" version = "0.2.10" @@ -7580,7 +7393,7 @@ dependencies = [ name = "remote-externalities" version = "0.10.0-dev" dependencies = [ - "env_logger 0.9.0", + "env_logger", "frame-support", "jsonrpsee", "log", @@ -8317,7 +8130,7 @@ name = "sc-executor" version = "0.10.0-dev" dependencies = [ "criterion", - "env_logger 0.9.0", + "env_logger", "hex-literal", "lazy_static", "lru", @@ -8747,7 +8560,7 @@ name = "sc-rpc" version = "4.0.0-dev" dependencies = [ "assert_matches", - "env_logger 0.9.0", + "env_logger", "futures", "hash-db", "jsonrpsee", @@ -9189,19 +9002,18 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.21.2" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab7883017d5b21f011ef8040ea9c6c7ac90834c0df26a69e4c0b06276151f125" +checksum = "b7649a0b3ffb32636e60c7ce0d70511eda9c52c658cd0634e194d5a19943aeff" dependencies = [ - "rand 0.6.5", "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.4.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" +checksum = "7058dc8eaf3f2810d7828680320acda0b25a288f6d288e19278e249bbf74226b" dependencies = [ "cc", ] @@ -9510,17 +9322,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "socket2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.4.4" @@ -10427,20 +10228,20 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.23.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38" +checksum = "4faebde00e8ff94316c01800f9054fd2ba77d30d9e922541913051d1d978918b" dependencies = [ - "heck 0.3.2", + "heck", "proc-macro2", "quote", "rustversion", @@ -10947,7 +10748,7 @@ dependencies = [ "parking_lot 0.12.0", "pin-project-lite 0.2.6", "signal-hook-registry", - "socket2 0.4.4", + "socket2", "tokio-macros", "winapi", ] @@ -10998,20 +10799,6 @@ dependencies = [ "tokio-stream", ] -[[package]] -name = "tokio-util" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite 0.2.6", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.1" @@ -11024,6 +10811,7 @@ dependencies = [ "futures-sink", "pin-project-lite 0.2.6", "tokio", + "tracing", ] [[package]] @@ -11347,12 +11135,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" - [[package]] name = "unicode-width" version = "0.1.8" @@ -11493,6 +11275,12 @@ 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.77" diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index bd25496f2dfea..b910f7ce307a5 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -39,7 +39,7 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] serde = "1.0.136" -strum = { version = "0.23", features = ["derive"] } +strum = { version = "0.24.1", features = ["derive"] } tempfile = "3.1.0" tokio = "1.17.0" sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 6c8e537a72c64..bbb0adf02e366 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -36,13 +36,8 @@ frame-election-provider-support = { version = "4.0.0-dev", default-features = fa # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } pallet-election-provider-support-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support/benchmarking", optional = true } -rand = { version = "0.7.3", default-features = false, optional = true, features = [ - "alloc", - "small_rng", -] } -strum = { optional = true, default-features = false, version = "0.23.0", features = [ - "derive", -] } +rand = { version = "0.7.3", default-features = false, features = ["alloc", "small_rng"], optional = true } +strum = { version = "0.24.1", default-features = false, features = ["derive"], optional = true } [dev-dependencies] parking_lot = "0.12.0" diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index cdc12c677e4f3..fced678293140 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -56,7 +56,7 @@ schnorrkel = { version = "0.9.1", features = [ hex = { version = "0.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } -secp256k1 = { version = "0.21.2", default-features = false, features = ["recovery", "alloc"], optional = true } +secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"], optional = true } ss58-registry = { version = "1.18.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 485e39d3a71db..d56f65fd289e7 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -499,7 +499,7 @@ impl TraitPair for Pair { impl Pair { /// Get the seed for this key. pub fn seed(&self) -> Seed { - self.secret.serialize_secret() + self.secret.secret_bytes() } /// Exactly as `from_string` except that if no matches are found then, the the first 32 diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 03cd8535665ac..77ba4be677f31 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -30,7 +30,7 @@ sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" log = { version = "0.4.17", optional = true } futures = { version = "0.3.21", features = ["thread-pool"], optional = true } parking_lot = { version = "0.12.0", optional = true } -secp256k1 = { version = "0.21.2", features = ["recovery", "global-context"], optional = true } +secp256k1 = { version = "0.24.0", features = ["recovery", "global-context"], optional = true } tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.28", default-features = false} diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 8f1adb6cf81f3..982abfd09a553 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -15,6 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] lazy_static = "1.4.0" -strum = { version = "0.23.0", features = ["derive"] } +strum = { version = "0.24.1", features = ["derive"] } sp-core = { version = "6.0.0", path = "../core" } sp-runtime = { version = "6.0.0", path = "../runtime" } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index ea26bf0c9261c..31b8f1332a653 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] chrono = "0.4" clap = { version = "3.1.18", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } -comfy-table = { version = "5.0.1", default-features = false } +comfy-table = { version = "6.0.0", default-features = false } handlebars = "4.2.2" hash-db = "0.15.2" hex = "0.4.3" diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index 8f887e45ec176..ac0ba5dbdb85a 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] ansi_term = "0.12.1" build-helper = "0.1.1" cargo_metadata = "0.14.2" -strum = { version = "0.23.0", features = ["derive"] } +strum = { version = "0.24.1", features = ["derive"] } tempfile = "3.1.0" toml = "0.5.4" walkdir = "2.3.2" From 134985fdf880e16de6ba5e8bf2bf9a7d8b768fb3 Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Mon, 25 Jul 2022 23:09:50 +0100 Subject: [PATCH 1000/1472] Fix typos (#11914) --- frame/transaction-payment/src/lib.rs | 2 +- test-utils/runtime/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 0f5c0321130be..fe37acb214452 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -609,7 +609,7 @@ where /// and user-included tip. /// /// The priority is based on the amount of `tip` the user is willing to pay per unit of either - /// `weight` or `length`, depending which one is more limitting. For `Operational` extrinsics + /// `weight` or `length`, depending which one is more limiting. For `Operational` extrinsics /// we add a "virtual tip" to the calculations. /// /// The formula should simply be `tip / bounded_{weight|length}`, but since we are using diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index ea62f2ac84f3d..e5cfae49da56d 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -237,7 +237,7 @@ impl sp_runtime::traits::Dispatchable for Extrinsic { type Info = (); type PostInfo = (); fn dispatch(self, _origin: Self::Origin) -> sp_runtime::DispatchResultWithInfo { - panic!("This implemention should not be used for actual dispatch."); + panic!("This implementation should not be used for actual dispatch."); } } From 5709dfa7095659d398323fb2c9515f66b2617b17 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Tue, 26 Jul 2022 11:06:48 +0200 Subject: [PATCH 1001/1472] Rpc for pending rewards (#11831) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * rpc pending rewards * commit * remove unused imports * fix * fix * fmt * fix * fmt * fix * docs * docs & formatting * better formatting * temporary fix * error handling * fix? * fmt * use to_string * fmt * fixed error handling * fix * rpc added to client * Update Cargo.toml * Update Cargo.toml * fix wrong reward counter * expose function * move implementation * docs * docs * docs * Update lib.rs * Update lib.rs * unexpose functions * unused dependency * update Cargo.lock * Update frame/nomination-pools/src/lib.rs * Update lib.rs * Update lib.rs * Update frame/nomination-pools/rpc/runtime-api/src/lib.rs Co-authored-by: Bastian Köcher * remove rpc * remove rpc directory * final fix Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Bastian Köcher --- Cargo.lock | 10 ++++++ Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 2 ++ bin/node/runtime/src/lib.rs | 6 ++++ frame/nomination-pools/runtime-api/Cargo.toml | 26 +++++++++++++++ frame/nomination-pools/runtime-api/README.md | 3 ++ frame/nomination-pools/runtime-api/src/lib.rs | 33 +++++++++++++++++++ frame/nomination-pools/src/lib.rs | 16 ++++++++- 8 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 frame/nomination-pools/runtime-api/Cargo.toml create mode 100644 frame/nomination-pools/runtime-api/README.md create mode 100644 frame/nomination-pools/runtime-api/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 8c19c80bde1a9..50603c6235a23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4759,6 +4759,7 @@ dependencies = [ "pallet-multisig", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", + "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-preimage", @@ -5911,6 +5912,15 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-nomination-pools-runtime-api" +version = "1.0.0-dev" +dependencies = [ + "parity-scale-codec", + "sp-api", + "sp-std", +] + [[package]] name = "pallet-nomination-pools-test-staking" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 9909e6f893877..1f22343c002a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -116,6 +116,7 @@ members = [ "frame/nomination-pools", "frame/nomination-pools/benchmarking", "frame/nomination-pools/test-staking", + "frame/nomination-pools/runtime-api", "frame/randomness-collective-flip", "frame/ranked-collective", "frame/recovery", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index ca971f29e93c9..d3138ce51de9c 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -79,6 +79,7 @@ pallet-mmr = { version = "4.0.0-dev", default-features = false, path = "../../.. pallet-multisig = { version = "4.0.0-dev", default-features = false, path = "../../../frame/multisig" } pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../../../frame/nomination-pools"} pallet-nomination-pools-benchmarking = { version = "1.0.0", default-features = false, optional = true, path = "../../../frame/nomination-pools/benchmarking" } +pallet-nomination-pools-runtime-api = { version = "1.0.0-dev", default-features = false, path = "../../../frame/nomination-pools/runtime-api" } pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../../frame/offences" } pallet-offences-benchmarking = { version = "4.0.0-dev", path = "../../../frame/offences/benchmarking", default-features = false, optional = true } pallet-preimage = { version = "4.0.0-dev", default-features = false, path = "../../../frame/preimage" } @@ -145,6 +146,7 @@ std = [ "pallet-mmr/std", "pallet-multisig/std", "pallet-nomination-pools/std", + "pallet-nomination-pools-runtime-api/std", "pallet-identity/std", "pallet-scheduler/std", "node-primitives/std", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index b2efcb196787d..037211155cf0e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1835,6 +1835,12 @@ impl_runtime_apis! { } } + impl pallet_nomination_pools_runtime_api::NominationPoolsApi for Runtime { + fn pending_rewards(member_account: AccountId) -> Balance { + NominationPools::pending_rewards(member_account) + } + } + impl sp_consensus_babe::BabeApi for Runtime { fn configuration() -> sp_consensus_babe::BabeGenesisConfiguration { // The choice of `c` parameter (where `1 - c` represents the diff --git a/frame/nomination-pools/runtime-api/Cargo.toml b/frame/nomination-pools/runtime-api/Cargo.toml new file mode 100644 index 0000000000000..dde925c62fe0d --- /dev/null +++ b/frame/nomination-pools/runtime-api/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "pallet-nomination-pools-runtime-api" +version = "1.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Runtime API for nomination-pools FRAME pallet" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-api/std", + "sp-std/std", +] diff --git a/frame/nomination-pools/runtime-api/README.md b/frame/nomination-pools/runtime-api/README.md new file mode 100644 index 0000000000000..af90b31733b0b --- /dev/null +++ b/frame/nomination-pools/runtime-api/README.md @@ -0,0 +1,3 @@ +Runtime API definition for nomination-pools pallet. + +License: Apache-2.0 \ No newline at end of file diff --git a/frame/nomination-pools/runtime-api/src/lib.rs b/frame/nomination-pools/runtime-api/src/lib.rs new file mode 100644 index 0000000000000..aa3ca57ca5b8b --- /dev/null +++ b/frame/nomination-pools/runtime-api/src/lib.rs @@ -0,0 +1,33 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Runtime API definition for nomination-pools pallet. +//! Currently supports only one rpc endpoint. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; + +sp_api::decl_runtime_apis! { + /// Runtime api for accessing information about nomination pools. + pub trait NominationPoolsApi + where AccountId: Codec, Balance: Codec + { + /// Returns the pending rewards for the member that the AccountId was given for. + fn pending_rewards(member: AccountId) -> Balance; + } +} diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 203c13f2f3496..09f1746b8e5ba 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -939,7 +939,7 @@ pub struct RewardPool { impl RewardPool { /// Getter for [`RewardPool::last_recorded_reward_counter`]. - fn last_recorded_reward_counter(&self) -> T::RewardCounter { + pub(crate) fn last_recorded_reward_counter(&self) -> T::RewardCounter { self.last_recorded_reward_counter } @@ -2147,6 +2147,20 @@ pub mod pallet { } impl Pallet { + /// Returns the pending rewards for the specified `member_account`. + /// + /// In the case of error the function returns balance of zero. + pub fn pending_rewards(member_account: T::AccountId) -> BalanceOf { + if let Some(pool_member) = PoolMembers::::get(member_account) { + if let Some(reward_pool) = RewardPools::::get(pool_member.pool_id) { + return pool_member + .pending_rewards(reward_pool.last_recorded_reward_counter()) + .unwrap_or_default() + } + } + BalanceOf::::default() + } + /// The amount of bond that MUST REMAIN IN BONDED in ALL POOLS. /// /// It is the responsibility of the depositor to put these funds into the pool initially. Upon From 531d7c3a5b26f5849aa6e23518c45a56d67faccb Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 26 Jul 2022 11:37:54 +0200 Subject: [PATCH 1002/1472] [ci] remove cargo-check-nixos job (#11873) * [ci] remove cargo-check-nixos job * remove shell.nix --- scripts/ci/gitlab/pipeline/test.yml | 24 ++++-------------------- shell.nix | 27 --------------------------- 2 files changed, 4 insertions(+), 47 deletions(-) delete mode 100644 shell.nix diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index d900d425ad494..b2daf5bada24f 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -51,26 +51,6 @@ cargo-clippy: - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo +nightly clippy --all-targets - rusty-cachier cache upload -cargo-check-nixos: - stage: test - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: cargo-clippy - artifacts: false - extends: - - .docker-env - - .test-refs - before_script: [] - # Don't use CI_IMAGE here because it breaks nightly checks of paritytech/ci-linux image - image: nixos/nix - variables: - SNAP: "DUMMY" - WS_API: "DUMMY" - script: - - nix-channel --update - - nix-shell shell.nix - - nix-shell --run "cargo check --workspace --all-targets --all-features" - cargo-check-benches: stage: test variables: @@ -337,6 +317,8 @@ test-linux-stable-int: time cargo test -p node-cli --release --verbose --locked -- --ignored - rusty-cachier cache upload +# more information about this job can be found here: +# https://github.com/paritytech/substrate/pull/6916 check-tracing: stage: test # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs @@ -355,6 +337,8 @@ check-tracing: - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing - rusty-cachier cache upload +# more information about this job can be found here: +# https://github.com/paritytech/substrate/pull/3778 test-full-crypto-feature: stage: test # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs diff --git a/shell.nix b/shell.nix deleted file mode 100644 index c318995605a38..0000000000000 --- a/shell.nix +++ /dev/null @@ -1,27 +0,0 @@ -let - mozillaOverlay = - import (builtins.fetchGit { - url = "https://github.com/mozilla/nixpkgs-mozilla.git"; - rev = "15b7a05f20aab51c4ffbefddb1b448e862dccb7d"; - }); - nixpkgs = import { overlays = [ mozillaOverlay ]; }; - rust-nightly = with nixpkgs; ((rustChannelOf { date = "2022-04-20"; channel = "nightly"; }).rust.override { - extensions = [ "rust-src" ]; - targets = [ "wasm32-unknown-unknown" ]; - }); -in -with nixpkgs; pkgs.mkShell { - buildInputs = [ - clang - openssl.dev - pkg-config - rust-nightly - ] ++ lib.optionals stdenv.isDarwin [ - darwin.apple_sdk.frameworks.Security - ]; - - RUST_SRC_PATH = "${rust-nightly}/lib/rustlib/src/rust/src"; - LIBCLANG_PATH = "${llvmPackages.libclang.lib}/lib"; - PROTOC = "${protobuf}/bin/protoc"; - ROCKSDB_LIB_DIR = "${rocksdb}/lib"; -} From 9428b0ea492d405f320753fcd93bc59ebb3bf33b Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 26 Jul 2022 14:37:05 +0200 Subject: [PATCH 1003/1472] Prepare for rust 1.62.1 (#11903) * Update UI test output for rust 1.62.1 * switch ci to staging image to check that everything works * fix artifacts node-bench-regression-guard * Imeplement `scale_info::TypeInfo` manually to silence aggressive rust warning * Fix more clippy lints * Make clippy happy by relying on auto-deref were possible * Add tracking issue to the comments * pin ci image Co-authored-by: alvicsam --- .gitlab-ci.yml | 3 +- bin/node/bench/src/simple_trie.rs | 2 +- bin/node/cli/benches/transaction_pool.rs | 8 +-- client/beefy/src/tests.rs | 14 ++--- client/beefy/src/worker.rs | 4 +- client/cli/src/commands/run_cmd.rs | 2 +- client/consensus/common/src/block_import.rs | 4 +- client/db/src/lib.rs | 2 +- .../finality-grandpa/src/communication/mod.rs | 6 +- client/finality-grandpa/src/import.rs | 2 +- client/finality-grandpa/src/observer.rs | 2 +- client/rpc/src/offchain/mod.rs | 4 +- client/rpc/src/state/state_full.rs | 2 +- client/service/src/client/client.rs | 4 +- client/tracing/src/logging/stderr_writer.rs | 2 +- client/transaction-pool/tests/pool.rs | 14 ++--- frame/contracts/src/exec.rs | 2 +- frame/executive/src/lib.rs | 4 +- frame/offences/src/mock.rs | 2 +- .../procedural/src/pallet/parse/call.rs | 2 +- .../no_std_genesis_config.stderr | 13 ++++ .../undefined_event_part.stderr | 26 ++++++++ .../undefined_genesis_config_part.stderr | 13 ++++ .../undefined_origin_part.stderr | 26 ++++++++ ...ed_keyword_two_times_integrity_test.stderr | 14 ++--- frame/support/test/tests/decl_storage.rs | 2 +- .../derive_no_bound_ui/partial_eq.stderr | 4 +- .../call_argument_invalid_bound.stderr | 5 -- .../call_argument_invalid_bound_2.stderr | 5 -- .../call_argument_invalid_bound_3.stderr | 4 ++ .../error_does_not_derive_pallet_error.stderr | 10 ++++ .../pallet_ui/event_field_not_member.stderr | 5 -- .../genesis_default_not_satisfied.stderr | 4 ++ ...age_ensure_span_are_ok_on_wrong_gen.stderr | 60 +++++++++++++++++++ ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 60 +++++++++++++++++++ .../pallet_ui/storage_info_unsatisfied.stderr | 10 ++++ .../storage_info_unsatisfied_nmap.stderr | 10 ++++ .../api/proc-macro/src/impl_runtime_apis.rs | 2 +- primitives/runtime/src/bounded/bounded_vec.rs | 40 ++++++++++++- primitives/runtime/src/curve.rs | 32 +++++++++- primitives/runtime/src/traits.rs | 2 +- primitives/trie/src/lib.rs | 12 ++-- .../proc-macro/src/decl_runtime_version.rs | 2 +- rustfmt.toml | 1 + utils/frame/remote-externalities/src/lib.rs | 2 +- 45 files changed, 365 insertions(+), 84 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9608d88e9554d..d1de666009bf1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,7 +47,8 @@ variables: &default-vars CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux:production" + # change to production when this image is published + CI_IMAGE: "paritytech/ci-linux:staging@sha256:2c90b67f1452ed2d7236c2cd13f6224053a833d521b3630650b679f00874e0a9" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" diff --git a/bin/node/bench/src/simple_trie.rs b/bin/node/bench/src/simple_trie.rs index c59389570e534..aa9c96a1cbd3f 100644 --- a/bin/node/bench/src/simple_trie.rs +++ b/bin/node/bench/src/simple_trie.rs @@ -33,7 +33,7 @@ pub struct SimpleTrie<'a> { impl<'a> AsHashDB for SimpleTrie<'a> { fn as_hash_db(&self) -> &dyn hash_db::HashDB { - &*self + self } fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn HashDB + 'b) { diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index 5b96355b9ca70..d88c3a65b6138 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -243,25 +243,25 @@ fn transaction_pool_benchmarks(c: &mut Criterion) { move |b| { b.iter_batched( || { - let prepare_extrinsics = create_account_extrinsics(&*node.client, &accounts); + let prepare_extrinsics = create_account_extrinsics(&node.client, &accounts); runtime.block_on(future::join_all(prepare_extrinsics.into_iter().map(|tx| { submit_tx_and_wait_for_inclusion( &node.transaction_pool, tx, - &*node.client, + &node.client, true, ) }))); - create_benchmark_extrinsics(&*node.client, &accounts, extrinsics_per_account) + create_benchmark_extrinsics(&node.client, &accounts, extrinsics_per_account) }, |extrinsics| { runtime.block_on(future::join_all(extrinsics.into_iter().map(|tx| { submit_tx_and_wait_for_inclusion( &node.transaction_pool, tx, - &*node.client, + &node.client, false, ) }))); diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 8090c425e71db..78e697a6ada81 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -467,7 +467,7 @@ fn finalize_block_and_wait_for_beefy( finalize_targets: &[u64], expected_beefy: &[u64], ) { - let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); + let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers); for block in finalize_targets { let finalize = BlockId::number(*block); @@ -555,7 +555,7 @@ fn lagging_validators() { // Alice finalizes #25, Bob lags behind let finalize = BlockId::number(25); - let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); + let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers); net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY let timeout = Some(Duration::from_millis(250)); @@ -563,7 +563,7 @@ fn lagging_validators() { streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); // Bob catches up and also finalizes #25 - let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); + let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers); net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); // expected beefy finalizes block #17 from diff-power-of-two wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[23, 24, 25]); @@ -577,7 +577,7 @@ fn lagging_validators() { // validator set). // Alice finalizes session-boundary mandatory block #60, Bob lags behind - let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); + let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers); let finalize = BlockId::number(60); net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY @@ -586,7 +586,7 @@ fn lagging_validators() { streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); // Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60) - let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers); + let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers); net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); // verify beefy skips intermediary votes, and successfully finalizes mandatory block #40 wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]); @@ -629,7 +629,7 @@ fn correct_beefy_payload() { finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[1, 9]); let (best_blocks, signed_commitments) = - get_beefy_streams(&mut *net.lock(), &[BeefyKeyring::Alice]); + get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]); // now 2 good validators and 1 bad one are voting net.lock() @@ -658,7 +658,7 @@ fn correct_beefy_payload() { // 3rd good validator catches up and votes as well let (best_blocks, signed_commitments) = - get_beefy_streams(&mut *net.lock(), &[BeefyKeyring::Alice]); + get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]); net.lock() .peer(2) .client() diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 735dea0170a62..dccf7ba7504dd 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -439,7 +439,7 @@ where let commitment = Commitment { payload, block_number: target_number, validator_set_id }; let encoded_commitment = commitment.encode(); - let signature = match self.key_store.sign(&authority_id, &*encoded_commitment) { + let signature = match self.key_store.sign(&authority_id, &encoded_commitment) { Ok(sig) => sig, Err(err) => { warn!(target: "beefy", "🥩 Error signing commitment: {:?}", err); @@ -451,7 +451,7 @@ where target: "beefy", "🥩 Produced signature using {:?}, is_valid: {:?}", authority_id, - BeefyKeystore::verify(&authority_id, &signature, &*encoded_commitment) + BeefyKeystore::verify(&authority_id, &signature, &encoded_commitment) ); let message = VoteMessage { commitment, id: authority_id, signature }; diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 99eaa4be1cd0f..3a74fdd9700f2 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -556,7 +556,7 @@ impl std::error::Error for TelemetryParsingError {} impl std::fmt::Display for TelemetryParsingError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &*self { + match self { TelemetryParsingError::MissingVerbosity => write!(f, "Verbosity level missing"), TelemetryParsingError::VerbosityParsingError(e) => write!(f, "{}", e), } diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index f81c8eb7e8dee..10739f63ef779 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -433,10 +433,10 @@ impl JustificationSyncLink for () { impl> JustificationSyncLink for Arc { fn request_justification(&self, hash: &B::Hash, number: NumberFor) { - L::request_justification(&*self, hash, number); + L::request_justification(self, hash, number); } fn clear_justification_requests(&self) { - L::clear_justification_requests(&*self); + L::clear_justification_requests(self); } } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index f1adbd3df1a0f..7dd49f9831f1c 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -2292,7 +2292,7 @@ impl sc_client_api::backend::Backend for Backend { } fn get_import_lock(&self) -> &RwLock<()> { - &*self.import_lock + &self.import_lock } fn requires_full_sync(&self) -> bool { diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 0555a03db149f..378501cffdd62 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -320,7 +320,7 @@ impl> NetworkBridge { voters: Arc>, has_voted: HasVoted, ) -> (impl Stream> + Unpin, OutgoingMessages) { - self.note_round(round, set_id, &*voters); + self.note_round(round, set_id, &voters); let keystore = keystore.and_then(|ks| { let id = ks.local_id(); @@ -637,9 +637,9 @@ fn incoming_global( .filter_map(move |(notification, msg)| { future::ready(match msg { GossipMessage::Commit(msg) => - process_commit(msg, notification, &gossip_engine, &gossip_validator, &*voters), + process_commit(msg, notification, &gossip_engine, &gossip_validator, &voters), GossipMessage::CatchUp(msg) => - process_catch_up(msg, notification, &gossip_engine, &gossip_validator, &*voters), + process_catch_up(msg, notification, &gossip_engine, &gossip_validator, &voters), _ => { debug!(target: "afg", "Skipping unknown message type"); None diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index eefb3d3f0aee4..b5a0d7be70f19 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -284,7 +284,7 @@ where impl<'a, H, N> InnerGuard<'a, H, N> { fn as_mut(&mut self) -> &mut AuthoritySet { - &mut **self.guard.as_mut().expect("only taken on deconstruction; qed") + self.guard.as_mut().expect("only taken on deconstruction; qed") } fn set_old(&mut self, old: AuthoritySet) { diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 85d80dcfe7cde..9bcb03c0555c2 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -289,7 +289,7 @@ where network.note_round( crate::communication::Round(round), crate::communication::SetId(set_id), - &*voters, + &voters, ) } }; diff --git a/client/rpc/src/offchain/mod.rs b/client/rpc/src/offchain/mod.rs index b66b78274a64e..6896b82619166 100644 --- a/client/rpc/src/offchain/mod.rs +++ b/client/rpc/src/offchain/mod.rs @@ -57,7 +57,7 @@ impl OffchainApiServer for Offchain { StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX, StorageKind::LOCAL => return Err(JsonRpseeError::from(Error::UnavailableStorageKind)), }; - self.storage.write().set(prefix, &*key, &*value); + self.storage.write().set(prefix, &key, &value); Ok(()) } @@ -69,6 +69,6 @@ impl OffchainApiServer for Offchain { StorageKind::LOCAL => return Err(JsonRpseeError::from(Error::UnavailableStorageKind)), }; - Ok(self.storage.read().get(prefix, &*key).map(Into::into)) + Ok(self.storage.read().get(prefix, &key).map(Into::into)) } } diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index c58638c870ab3..5a8a83cdd4851 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -199,7 +199,7 @@ where .call( &BlockId::Hash(block), &method, - &*call_data, + &call_data, self.client.execution_extensions().strategies().other, None, ) diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index fb73b4c34c040..d61d7f7fa3781 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1614,11 +1614,11 @@ where RA: Send + Sync, { fn header(&self, id: BlockId) -> sp_blockchain::Result> { - (**self).backend.blockchain().header(id) + self.backend.blockchain().header(id) } fn info(&self) -> blockchain::Info { - (**self).backend.blockchain().info() + self.backend.blockchain().info() } fn status(&self, id: BlockId) -> sp_blockchain::Result { diff --git a/client/tracing/src/logging/stderr_writer.rs b/client/tracing/src/logging/stderr_writer.rs index e62c5e82c1ac7..de78a61af41a2 100644 --- a/client/tracing/src/logging/stderr_writer.rs +++ b/client/tracing/src/logging/stderr_writer.rs @@ -89,7 +89,7 @@ fn flush_logs(mut buffer: parking_lot::lock_api::MutexGuard>(); assert_eq!(expected_ready, ready); - let event = block_event_with_retracted(f1_header, f0, &*pool.api()); + let event = block_event_with_retracted(f1_header, f0, pool.api()); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 3); diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index d93c646872c6f..5ca74e681e5dd 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1315,7 +1315,7 @@ where fn deposit_event(topics: Vec, event: Event) { >::deposit_event_indexed( - &*topics, + &topics, ::Event::from(event).into(), ) } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index c40fdf94806aa..cd3e1c500db26 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -573,7 +573,7 @@ mod tests { use pallet_balances::Call as BalancesCall; use pallet_transaction_payment::CurrencyAdapter; - const TEST_KEY: &[u8] = &*b":test:key:"; + const TEST_KEY: &[u8] = b":test:key:"; #[frame_support::pallet] mod custom { @@ -806,7 +806,7 @@ mod tests { type TestUncheckedExtrinsic = TestXt; // Will contain `true` when the custom runtime logic was called. - const CUSTOM_ON_RUNTIME_KEY: &[u8] = &*b":custom:on_runtime"; + const CUSTOM_ON_RUNTIME_KEY: &[u8] = b":custom:on_runtime"; struct CustomOnRuntimeUpgrade; impl OnRuntimeUpgrade for CustomOnRuntimeUpgrade { diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index b3dfbdd90b19d..6a69b54b3cca0 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -67,7 +67,7 @@ impl offence::OnOffenceHandler } pub fn with_on_offence_fractions) -> R>(f: F) -> R { - ON_OFFENCE_PERBILL.with(|fractions| f(&mut *fractions.borrow_mut())) + ON_OFFENCE_PERBILL.with(|fractions| f(&mut fractions.borrow_mut())) } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index 75c85474dcfe7..d8a81d699b8c2 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -188,7 +188,7 @@ impl CallDef { return Err(syn::Error::new(method.sig.span(), msg)) }, Some(syn::FnArg::Typed(arg)) => { - check_dispatchable_first_arg_type(&*arg.ty)?; + check_dispatchable_first_arg_type(&arg.ty)?; }, } diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr index 404c0c3627b7b..1f08ab87c1f79 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr @@ -29,6 +29,19 @@ help: consider importing this struct | 1 | use frame_system::GenesisConfig; | +help: if you import `GenesisConfig`, refer to it directly + | +40 - construct_runtime! { +41 - pub enum Runtime where +42 - Block = Block, +43 - NodeBlock = Block, +44 - UncheckedExtrinsic = UncheckedExtrinsic +45 - { +46 - System: frame_system::{Pallet, Call, Storage, Config, Event}, +47 - Pallet: test_pallet::{Pallet, Config}, +48 - } +49 - } + | error[E0283]: type annotations needed --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index 31229f8c93cb6..2af4d3fb15000 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -32,6 +32,19 @@ help: consider importing this enum | 1 | use frame_system::Event; | +help: if you import `Event`, refer to it directly + | +49 - construct_runtime! { +50 - pub enum Runtime where +51 - Block = Block, +52 - NodeBlock = Block, +53 - UncheckedExtrinsic = UncheckedExtrinsic +54 - { +55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, +56 - Pallet: pallet::{Pallet, Event}, +57 - } +58 - } + | error[E0412]: cannot find type `Event` in module `pallet` --> tests/construct_runtime_ui/undefined_event_part.rs:49:1 @@ -52,3 +65,16 @@ help: consider importing one of these items | 1 | use frame_system::Event; | +help: if you import `Event`, refer to it directly + | +49 - construct_runtime! { +50 - pub enum Runtime where +51 - Block = Block, +52 - NodeBlock = Block, +53 - UncheckedExtrinsic = UncheckedExtrinsic +54 - { +55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, +56 - Pallet: pallet::{Pallet, Event}, +57 - } +58 - } + | diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr index fa1cee1ac7e2f..1bc109a45ac57 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr @@ -32,6 +32,19 @@ help: consider importing this struct | 1 | use frame_system::GenesisConfig; | +help: if you import `GenesisConfig`, refer to it directly + | +49 - construct_runtime! { +50 - pub enum Runtime where +51 - Block = Block, +52 - NodeBlock = Block, +53 - UncheckedExtrinsic = UncheckedExtrinsic +54 - { +55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, +56 - Pallet: pallet::{Pallet, Config}, +57 - } +58 - } + | error[E0283]: type annotations needed --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr index 06e845618d44f..c692cd61bae8b 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr @@ -32,6 +32,19 @@ help: consider importing this type alias | 1 | use frame_system::Origin; | +help: if you import `Origin`, refer to it directly + | +49 - construct_runtime! { +50 - pub enum Runtime where +51 - Block = Block, +52 - NodeBlock = Block, +53 - UncheckedExtrinsic = UncheckedExtrinsic +54 - { +55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, +56 - Pallet: pallet::{Pallet, Origin}, +57 - } +58 - } + | error[E0412]: cannot find type `Origin` in module `pallet` --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 @@ -52,6 +65,19 @@ help: consider importing one of these items | 1 | use frame_system::Origin; | +help: if you import `Origin`, refer to it directly + | +49 - construct_runtime! { +50 - pub enum Runtime where +51 - Block = Block, +52 - NodeBlock = Block, +53 - UncheckedExtrinsic = UncheckedExtrinsic +54 - { +55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, +56 - Pallet: pallet::{Pallet, Origin}, +57 - } +58 - } + | error[E0282]: type annotations needed --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr index 86c427d8080be..880695d9b77e2 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr @@ -1,5 +1,5 @@ error: `integrity_test` can only be passed once as input. - --> $DIR/reserved_keyword_two_times_integrity_test.rs:1:1 + --> tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs:1:1 | 1 | / frame_support::decl_module! { 2 | | pub struct Module for enum Call where origin: T::Origin, system=self { @@ -13,13 +13,7 @@ error: `integrity_test` can only be passed once as input. = note: this error originates in the macro `$crate::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0601]: `main` function not found in crate `$CRATE` - --> $DIR/reserved_keyword_two_times_integrity_test.rs:1:1 + --> tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs:7:2 | -1 | / frame_support::decl_module! { -2 | | pub struct Module for enum Call where origin: T::Origin, system=self { -3 | | fn integrity_test() {} -4 | | -5 | | fn integrity_test() {} -6 | | } -7 | | } - | |_^ consider adding a `main` function to `$DIR/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs` +7 | } + | ^ consider adding a `main` function to `$DIR/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs` diff --git a/frame/support/test/tests/decl_storage.rs b/frame/support/test/tests/decl_storage.rs index be5d70be17f69..7ce43cd5d44d1 100644 --- a/frame/support/test/tests/decl_storage.rs +++ b/frame/support/test/tests/decl_storage.rs @@ -797,7 +797,7 @@ mod test_append_and_len { TestExternalities::default().execute_with(|| { let key = JustVec::hashed_key(); // Set it to some invalid value. - frame_support::storage::unhashed::put_raw(&key, &*b"1"); + frame_support::storage::unhashed::put_raw(&key, b"1"); assert!(JustVec::get().is_empty()); assert_eq!(frame_support::storage::unhashed::get_raw(&key), Some(b"1".to_vec())); diff --git a/frame/support/test/tests/derive_no_bound_ui/partial_eq.stderr b/frame/support/test/tests/derive_no_bound_ui/partial_eq.stderr index 64f844e547be0..1c230db376a49 100644 --- a/frame/support/test/tests/derive_no_bound_ui/partial_eq.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/partial_eq.stderr @@ -1,7 +1,5 @@ error[E0369]: binary operation `==` cannot be applied to type `::C` - --> $DIR/partial_eq.rs:7:2 + --> tests/derive_no_bound_ui/partial_eq.rs:7:2 | 7 | c: T::C, | ^ - | - = note: the trait `std::cmp::PartialEq` is not implemented for `::C` diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index 3a636d9f659c7..1d581ea7ed572 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -19,8 +19,3 @@ error[E0369]: binary operation `==` cannot be applied to type `&, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ - | -help: consider further restricting this bound - | -17 | #[pallet::call + std::cmp::PartialEq] - | +++++++++++++++++++++ diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index f182382d18f11..b1487776eac50 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -19,11 +19,6 @@ error[E0369]: binary operation `==` cannot be applied to type `&, bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^ - | -help: consider further restricting this bound - | -17 | #[pallet::call + std::cmp::PartialEq] - | +++++++++++++++++++++ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr index c196b28a31ce6..a0418760ba7e2 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr @@ -8,3 +8,7 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` = note: add `#[derive(Debug)]` to `Bar` or manually `impl std::fmt::Debug for Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Bar` = note: required for the cast to the object type `dyn std::fmt::Debug` +help: consider annotating `Bar` with `#[derive(Debug)]` + | +17 | #[derive(Debug)] + | diff --git a/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr b/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr index 0f2ea7e161c4e..7edb55a62d401 100644 --- a/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr +++ b/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr @@ -4,4 +4,14 @@ error[E0277]: the trait bound `MyError: PalletError` is not satisfied 1 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PalletError` is not implemented for `MyError` | + = help: the following other types implement trait `PalletError`: + () + (TupleElement0, TupleElement1) + (TupleElement0, TupleElement1, TupleElement2) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) + and 36 others = note: this error originates in the derive macro `frame_support::PalletError` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr index 3db258a819fcb..92623e0329fe3 100644 --- a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr +++ b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr @@ -9,11 +9,6 @@ error[E0369]: binary operation `==` cannot be applied to type `& { - | +++++++++++++++++++++ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` --> tests/pallet_ui/event_field_not_member.rs:23:7 diff --git a/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr b/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr index e01f66fa3d19d..80903928585b4 100644 --- a/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr +++ b/frame/support/test/tests/pallet_ui/genesis_default_not_satisfied.stderr @@ -9,3 +9,7 @@ note: required by a bound in `GenesisBuild` | | pub trait GenesisBuild: Default + sp_runtime::traits::MaybeSerializeDeserialize { | ^^^^^^^ required by this bound in `GenesisBuild` +help: consider annotating `pallet::GenesisConfig` with `#[derive(Default)]` + | +19 | #[derive(Default)] + | diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index 87528751a0a7a..e1c1b32d65c39 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied 10 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | + = help: the following other types implement trait `WrapperTypeDecode`: + Arc + Box + Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -14,6 +19,16 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied 10 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | + = help: the following other types implement trait `EncodeLike`: + <&&T as EncodeLike> + <&T as EncodeLike> + <&T as EncodeLike> + <&[(K, V)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[T] as EncodeLike>> + and 273 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -24,6 +39,16 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied 10 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | + = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc + Box + Cow<'a, T> + Rc + Vec + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + and 2 others = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` @@ -35,6 +60,16 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied 21 | #[pallet::storage] | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` | + = help: the following other types implement trait `TypeInfo`: + &T + &mut T + () + (A, B) + (A, B, C) + (A, B, C, D) + (A, B, C, D, E) + (A, B, C, D, E, F) + and 158 others = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -44,6 +79,11 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied 21 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | + = help: the following other types implement trait `WrapperTypeDecode`: + Arc + Box + Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -54,6 +94,16 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied 21 | #[pallet::storage] | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | + = help: the following other types implement trait `EncodeLike`: + <&&T as EncodeLike> + <&T as EncodeLike> + <&T as EncodeLike> + <&[(K, V)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[T] as EncodeLike>> + and 273 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -64,6 +114,16 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied 21 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | + = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc + Box + Cow<'a, T> + Rc + Vec + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + and 2 others = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 6c3f6dc662fbc..7d8c448f00193 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied 10 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | + = help: the following other types implement trait `WrapperTypeDecode`: + Arc + Box + Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -14,6 +19,16 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied 10 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | + = help: the following other types implement trait `EncodeLike`: + <&&T as EncodeLike> + <&T as EncodeLike> + <&T as EncodeLike> + <&[(K, V)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[T] as EncodeLike>> + and 273 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -24,6 +39,16 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied 10 | #[pallet::without_storage_info] | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | + = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc + Box + Cow<'a, T> + Rc + Vec + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + and 2 others = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` @@ -35,6 +60,16 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied 21 | #[pallet::storage] | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` | + = help: the following other types implement trait `TypeInfo`: + &T + &mut T + () + (A, B) + (A, B, C) + (A, B, C, D) + (A, B, C, D, E) + (A, B, C, D, E, F) + and 158 others = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -44,6 +79,11 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied 21 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | + = help: the following other types implement trait `WrapperTypeDecode`: + Arc + Box + Rc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes = note: required because of the requirements on the impl of `Decode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -54,6 +94,16 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied 21 | #[pallet::storage] | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | + = help: the following other types implement trait `EncodeLike`: + <&&T as EncodeLike> + <&T as EncodeLike> + <&T as EncodeLike> + <&[(K, V)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[(T,)] as EncodeLike>> + <&[T] as EncodeLike>> + and 273 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -64,6 +114,16 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied 21 | #[pallet::storage] | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | + = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc + Box + Cow<'a, T> + Rc + Vec + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + and 2 others = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index 68856f122c7ac..d87e6900197f5 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -4,4 +4,14 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied 9 | #[pallet::pallet] | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | + = help: the following other types implement trait `MaxEncodedLen`: + () + (TupleElement0, TupleElement1) + (TupleElement0, TupleElement1, TupleElement2) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) + and 70 others = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 226cb40f1d48b..bc8e99cd65006 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -4,5 +4,15 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied 12 | #[pallet::pallet] | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | + = help: the following other types implement trait `MaxEncodedLen`: + () + (TupleElement0, TupleElement1) + (TupleElement0, TupleElement1, TupleElement2) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) + and 70 others = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index 0ac3cfbe1244e..02ef37370ffeb 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -613,7 +613,7 @@ fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result let mut visitor = ApiRuntimeImplToApiRuntimeApiImpl { runtime_block, runtime_mod_path: &runtime_mod_path, - runtime_type: &*runtime_type, + runtime_type, trait_generic_arguments: &trait_generic_arguments, impl_trait: &impl_trait.ident, }; diff --git a/primitives/runtime/src/bounded/bounded_vec.rs b/primitives/runtime/src/bounded/bounded_vec.rs index c9c9f851d3249..10d9fc608c273 100644 --- a/primitives/runtime/src/bounded/bounded_vec.rs +++ b/primitives/runtime/src/bounded/bounded_vec.rs @@ -104,10 +104,46 @@ where /// A bounded slice. /// /// Similar to a `BoundedVec`, but not owned and cannot be decoded. -#[derive(Encode, scale_info::TypeInfo)] -#[scale_info(skip_type_params(S))] +#[derive(Encode)] pub struct BoundedSlice<'a, T, S>(pub(super) &'a [T], PhantomData); +// This can be replaced with +// #[derive(scale_info::TypeInfo)] +// #[scale_info(skip_type_params(S))] +// again once this issue is fixed in the rust compiler: https://github.com/rust-lang/rust/issues/96956 +// Tracking issues: https://github.com/paritytech/substrate/issues/11915 +impl<'a, T, S> scale_info::TypeInfo for BoundedSlice<'a, T, S> +where + &'a [T]: scale_info::TypeInfo + 'static, + PhantomData: scale_info::TypeInfo + 'static, + T: scale_info::TypeInfo + 'static, + S: 'static, +{ + type Identity = Self; + + fn type_info() -> ::scale_info::Type { + scale_info::Type::builder() + .path(scale_info::Path::new("BoundedSlice", "sp_runtime::bounded::bounded_vec")) + .type_params(<[_]>::into_vec(Box::new([ + scale_info::TypeParameter::new( + "T", + core::option::Option::Some(::scale_info::meta_type::()), + ), + scale_info::TypeParameter::new("S", ::core::option::Option::None), + ]))) + .docs(&[ + "A bounded slice.", + "", + "Similar to a `BoundedVec`, but not owned and cannot be decoded.", + ]) + .composite( + scale_info::build::Fields::unnamed() + .field(|f| f.ty::<&'static [T]>().type_name("&'static[T]").docs(&[])) + .field(|f| f.ty::>().type_name("PhantomData").docs(&[])), + ) + } +} + // `BoundedSlice`s encode to something which will always decode into a `BoundedVec`, // `WeakBoundedVec`, or a `Vec`. impl<'a, T: Encode + Decode, S: Get> EncodeLike> for BoundedSlice<'a, T, S> {} diff --git a/primitives/runtime/src/curve.rs b/primitives/runtime/src/curve.rs index c6bfa66017870..99733dbbe9a55 100644 --- a/primitives/runtime/src/curve.rs +++ b/primitives/runtime/src/curve.rs @@ -24,7 +24,7 @@ use crate::{ use core::ops::Sub; /// Piecewise Linear function in [0, 1] -> [0, 1]. -#[derive(PartialEq, Eq, sp_core::RuntimeDebug, scale_info::TypeInfo)] +#[derive(PartialEq, Eq, sp_core::RuntimeDebug)] pub struct PiecewiseLinear<'a> { /// Array of points. Must be in order from the lowest abscissas to the highest. pub points: &'a [(Perbill, Perbill)], @@ -32,6 +32,36 @@ pub struct PiecewiseLinear<'a> { pub maximum: Perbill, } +// This can be replaced with +// #[derive(scale_info::TypeInfo)] +// #[scale_info(skip_type_params(S))] +// again once this issue is fixed in the rust compiler: https://github.com/rust-lang/rust/issues/96956 +// Tracking issues: https://github.com/paritytech/substrate/issues/11915 +impl scale_info::TypeInfo for PiecewiseLinear<'static> { + type Identity = Self; + fn type_info() -> ::scale_info::Type { + scale_info::Type::builder() + .path(scale_info::Path::new("PiecewiseLinear", "sp_runtime::curve")) + .type_params(crate::Vec::new()) + .docs(&["Piecewise Linear function in [0, 1] -> [0, 1]."]) + .composite( + scale_info::build::Fields::named() + .field(|f| { + f.ty::<&'static[(Perbill, Perbill)]>() + .name("points") + .type_name("&'static[(Perbill, Perbill)]") + .docs(&["Array of points. Must be in order from the lowest abscissas to the highest."]) + }) + .field(|f| { + f.ty::() + .name("maximum") + .type_name("Perbill") + .docs(&["The maximum value that can be returned."]) + }), + ) + } +} + fn abs_sub + Clone>(a: N, b: N) -> N where { a.clone().max(b.clone()) - a.min(b) } diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index fba3117c41617..a82ae1d62f56a 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -55,7 +55,7 @@ pub trait Lazy { impl<'a> Lazy<[u8]> for &'a [u8] { fn get(&mut self) -> &[u8] { - &**self + self } } diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index 1dca617acf912..7a17d44aa5b69 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -280,7 +280,7 @@ where L: TrieConfiguration, DB: hash_db::HashDBRef, { - TrieDB::::new(&*db, root)?.get(key).map(|x| x.map(|val| val.to_vec())) + TrieDB::::new(db, root)?.get(key).map(|x| x.map(|val| val.to_vec())) } /// Read a value from the trie with given Query. @@ -295,7 +295,7 @@ where Q: Query, DB: hash_db::HashDBRef, { - TrieDB::::new(&*db, root)? + TrieDB::::new(db, root)? .get_with(key, query) .map(|x| x.map(|val| val.to_vec())) } @@ -354,7 +354,7 @@ pub fn record_all_keys( where DB: hash_db::HashDBRef, { - let trie = TrieDB::::new(&*db, root)?; + let trie = TrieDB::::new(db, root)?; let iter = trie.iter()?; for x in iter { @@ -379,7 +379,7 @@ pub fn read_child_trie_value( where DB: hash_db::HashDBRef, { - let db = KeySpacedDB::new(&*db, keyspace); + let db = KeySpacedDB::new(db, keyspace); TrieDB::::new(&db, root)?.get(key).map(|x| x.map(|val| val.to_vec())) } @@ -400,7 +400,7 @@ where // root is fetched from DB, not writable by runtime, so it's always valid. root.as_mut().copy_from_slice(root_slice); - let db = KeySpacedDB::new(&*db, keyspace); + let db = KeySpacedDB::new(db, keyspace); TrieDB::::new(&db, &root)? .get_with(key, query) .map(|x| x.map(|val| val.to_vec())) @@ -501,7 +501,7 @@ where T: Default + PartialEq + for<'b> From<&'b [u8]> + Clone + Send + Sync, { fn as_hash_db(&self) -> &dyn hash_db::HashDB { - &*self + self } fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn hash_db::HashDB + 'b) { diff --git a/primitives/version/proc-macro/src/decl_runtime_version.rs b/primitives/version/proc-macro/src/decl_runtime_version.rs index ee81940b53993..9a25adfa5fca2 100644 --- a/primitives/version/proc-macro/src/decl_runtime_version.rs +++ b/primitives/version/proc-macro/src/decl_runtime_version.rs @@ -37,7 +37,7 @@ pub fn decl_runtime_version_impl(input: proc_macro::TokenStream) -> proc_macro:: } fn decl_runtime_version_impl_inner(item: ItemConst) -> Result { - let runtime_version = ParseRuntimeVersion::parse_expr(&*item.expr)?.build(item.expr.span())?; + let runtime_version = ParseRuntimeVersion::parse_expr(&item.expr)?.build(item.expr.span())?; let link_section = generate_emit_link_section_decl(&runtime_version.encode(), "runtime_version"); diff --git a/rustfmt.toml b/rustfmt.toml index 441913f619cdc..f6fbe80064fce 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -21,3 +21,4 @@ match_block_trailing_comma = true trailing_comma = "Vertical" trailing_semicolon = false use_field_init_shorthand = true +edition = "2021" diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 1d9dc5dcd11da..202560f18cf84 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -130,7 +130,7 @@ pub enum Transport { impl Transport { fn as_client(&self) -> Option<&WsClient> { match self { - Self::RemoteClient(client) => Some(&*client), + Self::RemoteClient(client) => Some(client), _ => None, } } From fdfdc73f9e64dc47934b72eb9af3e1989e4ba699 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 26 Jul 2022 13:44:48 +0100 Subject: [PATCH 1004/1472] Properly defer slashes (#11823) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial draft of fixing slashing * fix test * Update frame/staking/src/tests.rs Co-authored-by: Piotr Mikołajczyk * last touches * add more detail about unbonding * add migration * fmt Co-authored-by: Piotr Mikołajczyk Co-authored-by: parity-processbot <> --- frame/staking/src/lib.rs | 11 +-- frame/staking/src/migrations.rs | 23 ++++++ frame/staking/src/mock.rs | 15 ++++ frame/staking/src/pallet/impls.rs | 47 ++++++------ frame/staking/src/pallet/mod.rs | 4 - frame/staking/src/tests.rs | 118 +++++++++++++++++++++++++++--- 6 files changed, 177 insertions(+), 41 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 50c033bdc7e28..3fff6312f333f 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -872,11 +872,12 @@ enum Releases { V2_0_0, V3_0_0, V4_0_0, - V5_0_0, // blockable validators. - V6_0_0, // removal of all storage associated with offchain phragmen. - V7_0_0, // keep track of number of nominators / validators in map - V8_0_0, // populate `VoterList`. - V9_0_0, // inject validators into `VoterList` as well. + V5_0_0, // blockable validators. + V6_0_0, // removal of all storage associated with offchain phragmen. + V7_0_0, // keep track of number of nominators / validators in map + V8_0_0, // populate `VoterList`. + V9_0_0, // inject validators into `VoterList` as well. + V10_0_0, // remove `EarliestUnappliedSlash`. } impl Default for Releases { diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 14846da8a5d54..101cac0a31348 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -20,6 +20,29 @@ use super::*; use frame_election_provider_support::SortedListProvider; use frame_support::traits::OnRuntimeUpgrade; +pub mod v10 { + use super::*; + use frame_support::storage_alias; + + #[storage_alias] + type EarliestUnappliedSlash = StorageValue, EraIndex>; + + pub struct MigrateToV10(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV10 { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + if StorageVersion::::get() == Releases::V9_0_0 { + EarliestUnappliedSlash::::kill(); + StorageVersion::::put(Releases::V10_0_0); + + T::DbWeight::get().reads_writes(1, 1) + } else { + log!(warn, "MigrateToV10 should be removed."); + T::DbWeight::get().reads(1) + } + } + } +} + pub mod v9 { use super::*; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index bd2d8cdc32ce9..70d00c2b648d8 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -549,6 +549,7 @@ impl ExtBuilder { ext } pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + sp_tracing::try_init_simple(); let mut ext = self.build(); ext.execute_with(test); ext.execute_with(post_conditions); @@ -884,6 +885,20 @@ pub(crate) fn staking_events() -> Vec> { .collect() } +parameter_types! { + static StakingEventsIndex: usize = 0; +} + +pub(crate) fn staking_events_since_last_call() -> Vec> { + let all: Vec<_> = System::events() + .into_iter() + .filter_map(|r| if let Event::Staking(inner) = r.event { Some(inner) } else { None }) + .collect(); + let seen = StakingEventsIndex::get(); + StakingEventsIndex::set(all.len()); + all.into_iter().skip(seen).collect() +} + pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { (Balances::free_balance(who), Balances::reserved_balance(who)) } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 7656eec80a5ff..68aa97db8a324 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -32,7 +32,7 @@ use frame_support::{ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ - traits::{Bounded, Convert, SaturatedConversion, Saturating, StaticLookup, Zero}, + traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero}, Perbill, }; use sp_staking::{ @@ -599,20 +599,17 @@ impl Pallet { /// Apply previously-unapplied slashes on the beginning of a new era, after a delay. fn apply_unapplied_slashes(active_era: EraIndex) { - let slash_defer_duration = T::SlashDeferDuration::get(); - ::EarliestUnappliedSlash::mutate(|earliest| { - if let Some(ref mut earliest) = earliest { - let keep_from = active_era.saturating_sub(slash_defer_duration); - for era in (*earliest)..keep_from { - let era_slashes = ::UnappliedSlashes::take(&era); - for slash in era_slashes { - slashing::apply_slash::(slash, era); - } - } - - *earliest = (*earliest).max(keep_from) - } - }) + let era_slashes = ::UnappliedSlashes::take(&active_era); + log!( + debug, + "found {} slashes scheduled to be executed in era {:?}", + era_slashes.len(), + active_era, + ); + for slash in era_slashes { + let slash_era = active_era.saturating_sub(T::SlashDeferDuration::get()); + slashing::apply_slash::(slash, slash_era); + } } /// Add reward points to validators using their stash account ID. @@ -1209,11 +1206,6 @@ where } }; - ::EarliestUnappliedSlash::mutate(|earliest| { - if earliest.is_none() { - *earliest = Some(active_era) - } - }); add_db_reads_writes(1, 1); let slash_defer_duration = T::SlashDeferDuration::get(); @@ -1263,9 +1255,18 @@ where } } else { // Defer to end of some `slash_defer_duration` from now. - ::UnappliedSlashes::mutate(active_era, move |for_later| { - for_later.push(unapplied) - }); + log!( + debug, + "deferring slash of {:?}% happened in {:?} (reported in {:?}) to {:?}", + slash_fraction, + slash_era, + active_era, + slash_era + slash_defer_duration + 1, + ); + ::UnappliedSlashes::mutate( + slash_era.saturating_add(slash_defer_duration).saturating_add(One::one()), + move |for_later| for_later.push(unapplied), + ); add_db_reads_writes(1, 1); } } else { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index e53464195de23..c999020c28167 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -477,10 +477,6 @@ pub mod pallet { ValueQuery, >; - /// The earliest era for which we have a pending, unapplied slash. - #[pallet::storage] - pub(crate) type EarliestUnappliedSlash = StorageValue<_, EraIndex>; - /// The last planned session scheduled by the session pallet. /// /// This is basically in sync with the call to [`pallet_session::SessionManager::new_session`]. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index b76126f0c5d04..d14d8c4a75f2e 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2777,12 +2777,103 @@ fn deferred_slashes_are_deferred() { assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); + System::reset_events(); + // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. mock::start_active_era(4); assert_eq!(Balances::free_balance(11), 900); assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid(3, 11075, 33225), + Event::Slashed(11, 100), + Event::Slashed(101, 12) + ] + ); + }) +} + +#[test] +fn retroactive_deferred_slashes_two_eras_before() { + ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { + assert_eq!(BondingDuration::get(), 3); + + mock::start_active_era(1); + let exposure_11_at_era1 = Staking::eras_stakers(active_era(), 11); + + mock::start_active_era(3); + on_offence_in_era( + &[OffenceDetails { offender: (11, exposure_11_at_era1), reporters: vec![] }], + &[Perbill::from_percent(10)], + 1, // should be deferred for two full eras, and applied at the beginning of era 4. + DisableStrategy::Never, + ); + System::reset_events(); + + mock::start_active_era(4); + + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid(3, 7100, 21300), + Event::Slashed(11, 100), + Event::Slashed(101, 12) + ] + ); + }) +} + +#[test] +fn retroactive_deferred_slashes_one_before() { + ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { + assert_eq!(BondingDuration::get(), 3); + + mock::start_active_era(1); + let exposure_11_at_era1 = Staking::eras_stakers(active_era(), 11); + + // unbond at slash era. + mock::start_active_era(2); + assert_ok!(Staking::chill(Origin::signed(10))); + assert_ok!(Staking::unbond(Origin::signed(10), 100)); + + mock::start_active_era(3); + on_offence_in_era( + &[OffenceDetails { offender: (11, exposure_11_at_era1), reporters: vec![] }], + &[Perbill::from_percent(10)], + 2, // should be deferred for two full eras, and applied at the beginning of era 5. + DisableStrategy::Never, + ); + System::reset_events(); + + mock::start_active_era(4); + assert_eq!( + staking_events_since_last_call(), + vec![Event::StakersElected, Event::EraPaid(3, 11075, 33225)] + ); + + assert_eq!(Staking::ledger(10).unwrap().total, 1000); + // slash happens after the next line. + mock::start_active_era(5); + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid(4, 11075, 33225), + Event::Slashed(11, 100), + Event::Slashed(101, 12) + ] + ); + + // their ledger has already been slashed. + assert_eq!(Staking::ledger(10).unwrap().total, 900); + assert_ok!(Staking::unbond(Origin::signed(10), 1000)); + assert_eq!(Staking::ledger(10).unwrap().total, 900); }) } @@ -2871,6 +2962,7 @@ fn remove_deferred() { assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; + // deferred to start of era 4. on_offence_now( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], &[Perbill::from_percent(10)], @@ -2881,6 +2973,7 @@ fn remove_deferred() { mock::start_active_era(2); + // reported later, but deferred to start of era 4 as well. on_offence_in_era( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], &[Perbill::from_percent(15)], @@ -2894,7 +2987,8 @@ fn remove_deferred() { Error::::EmptyTargets ); - assert_ok!(Staking::cancel_deferred_slash(Origin::root(), 1, vec![0])); + // cancel one of them. + assert_ok!(Staking::cancel_deferred_slash(Origin::root(), 4, vec![0])); assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); @@ -2906,13 +3000,19 @@ fn remove_deferred() { // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. + System::reset_events(); mock::start_active_era(4); - // the first slash for 10% was cancelled, so no effect. - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); - - mock::start_active_era(5); + // the first slash for 10% was cancelled, but the 15% one + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid(3, 11075, 33225), + Event::Slashed(11, 50), + Event::Slashed(101, 7) + ] + ); let slash_10 = Perbill::from_percent(10); let slash_15 = Perbill::from_percent(15); @@ -2965,7 +3065,7 @@ fn remove_multi_deferred() { &[Perbill::from_percent(25)], ); - assert_eq!(::UnappliedSlashes::get(&1).len(), 5); + assert_eq!(::UnappliedSlashes::get(&4).len(), 5); // fails if list is not sorted assert_noop!( @@ -2983,9 +3083,9 @@ fn remove_multi_deferred() { Error::::InvalidSlashIndex ); - assert_ok!(Staking::cancel_deferred_slash(Origin::root(), 1, vec![0, 2, 4])); + assert_ok!(Staking::cancel_deferred_slash(Origin::root(), 4, vec![0, 2, 4])); - let slashes = ::UnappliedSlashes::get(&1); + let slashes = ::UnappliedSlashes::get(&4); assert_eq!(slashes.len(), 2); assert_eq!(slashes[0].validator, 21); assert_eq!(slashes[1].validator, 42); From 7db3c4fc5221d1f3fde36f1a5ef3042725a0f616 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 26 Jul 2022 18:03:50 +0200 Subject: [PATCH 1005/1472] [ci] Return production image (#11920) --- .gitlab-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d1de666009bf1..9608d88e9554d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,8 +47,7 @@ variables: &default-vars CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - # change to production when this image is published - CI_IMAGE: "paritytech/ci-linux:staging@sha256:2c90b67f1452ed2d7236c2cd13f6224053a833d521b3630650b679f00874e0a9" + CI_IMAGE: "paritytech/ci-linux:production" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" From 9acfbc0e88f5a6df873d222a3e01c2b59868b2e3 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 26 Jul 2022 18:49:11 +0100 Subject: [PATCH 1006/1472] Make New Storage Layer Truly Default (#11918) * with storage layer truly default * fmt Co-authored-by: parity-processbot <> --- frame/nomination-pools/src/tests.rs | 4 ++-- .../src/construct_runtime/expand/call.rs | 13 ------------- .../procedural/src/pallet/expand/call.rs | 4 ++-- frame/support/src/dispatch.rs | 7 +++---- frame/support/src/traits.rs | 5 ++--- frame/support/src/traits/dispatch.rs | 17 ----------------- 6 files changed, 9 insertions(+), 41 deletions(-) diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index b59f18cca72a2..5aa8e97266e0d 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -2735,7 +2735,7 @@ mod unbond { // when: unbonding more than our active: error assert_noop!( - frame_support::storage::in_storage_layer(|| Pools::unbond( + frame_support::storage::with_storage_layer(|| Pools::unbond( Origin::signed(10), 10, 5 @@ -2787,7 +2787,7 @@ mod unbond { // when CurrentEra::set(2); assert_noop!( - frame_support::storage::in_storage_layer(|| Pools::unbond( + frame_support::storage::with_storage_layer(|| Pools::unbond( Origin::signed(20), 20, 4 diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index c8c5d5ff0ee43..801b69035121d 100644 --- a/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -163,19 +163,6 @@ pub fn expand_outer_dispatch( } } } - impl #scrate::traits::DispatchableWithStorageLayer for Call { - type Origin = Origin; - fn dispatch_with_storage_layer(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { - #scrate::storage::with_storage_layer(|| { - #scrate::dispatch::Dispatchable::dispatch(self, origin) - }) - } - fn dispatch_bypass_filter_with_storage_layer(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { - #scrate::storage::with_storage_layer(|| { - #scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(self, origin) - }) - } - } #( impl #scrate::traits::IsSubType<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for Call { diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index a5038ec399e2b..fe7589a8275d2 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -267,9 +267,9 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::sp_tracing::enter_span!( #frame_support::sp_tracing::trace_span!(stringify!(#fn_name)) ); - // We execute all dispatchable in at least one storage layer, allowing them + // We execute all dispatchable in a new storage layer, allowing them // to return an error at any point, and undoing any storage changes. - #frame_support::storage::in_storage_layer(|| { + #frame_support::storage::with_storage_layer(|| { <#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* ) .map(Into::into).map_err(Into::into) }) diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index c175998956ff2..ae4230efc63f8 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -29,8 +29,7 @@ pub use crate::{ result, }, traits::{ - CallMetadata, DispatchableWithStorageLayer, GetCallMetadata, GetCallName, - GetStorageVersion, UnfilteredDispatchable, + CallMetadata, GetCallMetadata, GetCallName, GetStorageVersion, UnfilteredDispatchable, }, weights::{ ClassifyDispatch, DispatchInfo, GetDispatchInfo, PaysFee, PostDispatchInfo, @@ -1473,9 +1472,9 @@ macro_rules! decl_module { $ignore:ident $mod_type:ident<$trait_instance:ident $(, $instance:ident)?> $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] ) => { - // We execute all dispatchable in at least one storage layer, allowing them + // We execute all dispatchable in a new storage layer, allowing them // to return an error at any point, and undoing any storage changes. - $crate::storage::in_storage_layer(|| { + $crate::storage::with_storage_layer(|| { <$mod_type<$trait_instance $(, $instance)?>>::$fn_name( $origin $(, $param_name )* ).map(Into::into).map_err(Into::into) }) }; diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index db8c8da4f869b..72d6d6682f14a 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -96,9 +96,8 @@ mod dispatch; #[allow(deprecated)] pub use dispatch::EnsureOneOf; pub use dispatch::{ - AsEnsureOriginWithArg, DispatchableWithStorageLayer, EitherOf, EitherOfDiverse, EnsureOrigin, - EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess, - UnfilteredDispatchable, + AsEnsureOriginWithArg, EitherOf, EitherOfDiverse, EnsureOrigin, EnsureOriginWithArg, + MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess, UnfilteredDispatchable, }; mod voting; diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 7e97be12e449e..afc819aa454e5 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -236,23 +236,6 @@ pub trait UnfilteredDispatchable { fn dispatch_bypass_filter(self, origin: Self::Origin) -> DispatchResultWithPostInfo; } -/// Type that can be dispatched with an additional storage layer which is used to execute the call. -pub trait DispatchableWithStorageLayer { - /// The origin type of the runtime, (i.e. `frame_system::Config::Origin`). - type Origin; - - /// Same as `dispatch` from the [`frame_support::dispatch::Dispatchable`] trait, but - /// specifically spawns a new storage layer to execute the call inside of. - fn dispatch_with_storage_layer(self, origin: Self::Origin) -> DispatchResultWithPostInfo; - - /// Same as `dispatch_bypass_filter` from the [`UnfilteredDispatchable`] trait, but specifically - /// spawns a new storage layer to execute the call inside of. - fn dispatch_bypass_filter_with_storage_layer( - self, - origin: Self::Origin, - ) -> DispatchResultWithPostInfo; -} - /// Methods available on `frame_system::Config::Origin`. pub trait OriginTrait: Sized { /// Runtime call type, as in `frame_system::Config::Call` From dddfed3d9260cf03244f15ba3db4edf9af7467e9 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 28 Jul 2022 00:35:33 +0200 Subject: [PATCH 1007/1472] Remove `retain_mut` crate (#11926) * Remove retain_mut crate * Remove reain_mut crate from babe-consensus --- Cargo.lock | 8 ----- client/consensus/babe/Cargo.toml | 1 - client/consensus/babe/src/lib.rs | 22 +++++++------- client/transaction-pool/Cargo.toml | 1 - .../src/graph/validated_pool.rs | 30 +++++++++---------- 5 files changed, 24 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50603c6235a23..3b0246168632c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7446,12 +7446,6 @@ dependencies = [ "quick-error 1.2.3", ] -[[package]] -name = "retain_mut" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "448296241d034b96c11173591deaa1302f2c17b56092106c1f92c1bc0183a8c9" - [[package]] name = "rfc6979" version = "0.1.0" @@ -7965,7 +7959,6 @@ dependencies = [ "parking_lot 0.12.0", "rand 0.7.3", "rand_chacha 0.2.2", - "retain_mut", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -8877,7 +8870,6 @@ dependencies = [ "parity-scale-codec", "parity-util-mem", "parking_lot 0.12.0", - "retain_mut", "sc-block-builder", "sc-client-api", "sc-transaction-pool-api", diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 765fc367f424f..59d7854619fc0 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -26,7 +26,6 @@ num-rational = "0.2.2" num-traits = "0.2.8" parking_lot = "0.12.0" rand = "0.7.2" -retain_mut = "0.1.4" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0" diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 8478122375319..f61ba23d920f3 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -87,7 +87,6 @@ use futures::{ use log::{debug, info, log, trace, warn}; use parking_lot::Mutex; use prometheus_endpoint::Registry; -use retain_mut::RetainMut; use schnorrkel::SignatureError; use sc_client_api::{ @@ -835,17 +834,16 @@ where slot: Slot, epoch_descriptor: &ViableEpochDescriptor, Epoch>, ) { - RetainMut::retain_mut(&mut *self.slot_notification_sinks.lock(), |sink| { - match sink.try_send((slot, epoch_descriptor.clone())) { - Ok(()) => true, - Err(e) => - if e.is_full() { - warn!(target: "babe", "Trying to notify a slot but the channel is full"); - true - } else { - false - }, - } + let sinks = &mut self.slot_notification_sinks.lock(); + sinks.retain_mut(|sink| match sink.try_send((slot, epoch_descriptor.clone())) { + Ok(()) => true, + Err(e) => + if e.is_full() { + warn!(target: "babe", "Trying to notify a slot but the channel is full"); + true + } else { + false + }, }); } diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index cabde4b6307ae..3fdcde48d9e22 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -20,7 +20,6 @@ linked-hash-map = "0.5.4" log = "0.4.17" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } parking_lot = "0.12.0" -retain_mut = "0.1.4" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/transaction-pool/src/graph/validated_pool.rs b/client/transaction-pool/src/graph/validated_pool.rs index e59c5afbdc512..dcb8195073733 100644 --- a/client/transaction-pool/src/graph/validated_pool.rs +++ b/client/transaction-pool/src/graph/validated_pool.rs @@ -24,7 +24,6 @@ use std::{ use futures::channel::mpsc::{channel, Sender}; use parking_lot::{Mutex, RwLock}; -use retain_mut::RetainMut; use sc_transaction_pool_api::{error, PoolStatus, ReadyTransactions}; use serde::Serialize; use sp_runtime::{ @@ -204,21 +203,20 @@ impl ValidatedPool { let imported = self.pool.write().import(tx)?; if let base::Imported::Ready { ref hash, .. } = imported { - RetainMut::retain_mut(&mut *self.import_notification_sinks.lock(), |sink| { - match sink.try_send(*hash) { - Ok(()) => true, - Err(e) => - if e.is_full() { - log::warn!( - target: "txpool", - "[{:?}] Trying to notify an import but the channel is full", - hash, - ); - true - } else { - false - }, - } + let sinks = &mut self.import_notification_sinks.lock(); + sinks.retain_mut(|sink| match sink.try_send(*hash) { + Ok(()) => true, + Err(e) => + if e.is_full() { + log::warn!( + target: "txpool", + "[{:?}] Trying to notify an import but the channel is full", + hash, + ); + true + } else { + false + }, }); } From 782e08ed36e3c3e5ffa3a48484267b02ec8b7b6d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 28 Jul 2022 11:44:02 +0100 Subject: [PATCH 1008/1472] Fix slashing migration to v10 (#11924) * Fix slashing migration to v10 * add some logs * Fix default version * fmt * Move doc to struct Co-authored-by: Wilfried Kopp --- frame/staking/src/lib.rs | 2 +- frame/staking/src/migrations.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 3fff6312f333f..ab0ab685e6911 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -882,7 +882,7 @@ enum Releases { impl Default for Releases { fn default() -> Self { - Releases::V8_0_0 + Releases::V10_0_0 } } diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 101cac0a31348..7e3bf6ccb93e1 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -27,13 +27,29 @@ pub mod v10 { #[storage_alias] type EarliestUnappliedSlash = StorageValue, EraIndex>; + /// Apply any pending slashes that where queued. + /// + /// That means we might slash someone a bit too early, but we will definitely + /// won't forget to slash them. The cap of 512 is somewhat randomly taken to + /// prevent us from iterating over an arbitrary large number of keys `on_runtime_upgrade`. pub struct MigrateToV10(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV10 { fn on_runtime_upgrade() -> frame_support::weights::Weight { if StorageVersion::::get() == Releases::V9_0_0 { + let pending_slashes = as Store>::UnappliedSlashes::iter().take(512); + for (era, slashes) in pending_slashes { + for slash in slashes { + // in the old slashing scheme, the slash era was the key at which we read + // from `UnappliedSlashes`. + log!(warn, "prematurely applying a slash ({:?}) for era {:?}", slash, era); + slashing::apply_slash::(slash, era); + } + } + EarliestUnappliedSlash::::kill(); StorageVersion::::put(Releases::V10_0_0); + log!(info, "MigrateToV10 executed successfully"); T::DbWeight::get().reads_writes(1, 1) } else { log!(warn, "MigrateToV10 should be removed."); From b8591d63c998a8a80376018c426a5b1fd75714db Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Thu, 28 Jul 2022 23:31:47 +0800 Subject: [PATCH 1009/1472] Enrich the sync log on handling the block request (#11747) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add more info to the log to help debug the issue like https://github.com/paritytech/substrate/issues/11732. Co-authored-by: Bastian Köcher --- .../network/sync/src/block_request_handler.rs | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index 2a847a8bf36ec..30cbb32289d66 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -226,16 +226,13 @@ where debug!( target: LOG_TARGET, - "Handling block request from {}: Starting at `{:?}` with maximum blocks \ - of `{}`, direction `{:?}` and attributes `{:?}`.", - peer, - from_block_id, - max_blocks, - direction, - attributes, + "Handling block request from {peer}: Starting at `{from_block_id:?}` with \ + maximum blocks of `{max_blocks}`, reputation_change: `{reputation_change:?}`, \ + small_request `{small_request:?}`, direction `{direction:?}` and \ + attributes `{attributes:?}`.", ); - let result = if reputation_change.is_none() || small_request { + let maybe_block_response = if reputation_change.is_none() || small_request { let block_response = self.get_block_response( attributes, from_block_id, @@ -259,9 +256,22 @@ where } } + Some(block_response) + } else { + None + }; + + debug!( + target: LOG_TARGET, + "Sending result of block request from {peer} starting at `{from_block_id:?}`: \ + blocks: {:?}, data: {:?}", + maybe_block_response.as_ref().map(|res| res.blocks.len()), + maybe_block_response.as_ref().map(|res| res.encoded_len()), + ); + + let result = if let Some(block_response) = maybe_block_response { let mut data = Vec::with_capacity(block_response.encoded_len()); block_response.encode(&mut data)?; - Ok(data) } else { Err(()) From 3ca8a42954e284bfb8771ed93d37cced3a7809b9 Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 29 Jul 2022 16:46:15 +0900 Subject: [PATCH 1010/1472] Prevent double allocation of the payload when calling `sp_io::storage::get` (#11523) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Expose allocation stats in `FreeingBumpHeapAllocator` * Return allocation stats when calling into the runtime * Bump `parity-scale-codec` to 3.1.3 (fork) * Prevent double allocation of the payload when calling `sp_io::storage::get` * Fix tests * Remove unnecessary `mut` * Enable the `bytes` feature for `parity-scale-codec` in `sp-runtime-interface` * Update client/allocator/src/freeing_bump.rs Co-authored-by: Bastian Köcher * Bump `parity-scale-codec` to 3.1.3 * Fix some of the UI tests Co-authored-by: Bastian Köcher --- Cargo.lock | 4 + client/allocator/src/freeing_bump.rs | 97 +++++++++++-------- client/allocator/src/lib.rs | 2 +- client/executor/common/src/wasm_runtime.rs | 17 +++- client/executor/src/native_executor.rs | 49 +++++++++- client/executor/wasmi/src/lib.rs | 26 ++++- client/executor/wasmtime/src/host.rs | 6 +- client/executor/wasmtime/src/runtime.rs | 34 +++++-- frame/support/src/storage/unhashed.rs | 2 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 12 +-- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 12 +-- primitives/io/Cargo.toml | 3 +- primitives/io/src/lib.rs | 10 +- primitives/runtime-interface/Cargo.toml | 3 +- primitives/runtime-interface/src/pass_by.rs | 6 +- .../runtime-interface/test-wasm/Cargo.toml | 1 + .../runtime-interface/test-wasm/src/lib.rs | 20 ++++ primitives/runtime-interface/test/src/lib.rs | 72 +++++++++++--- 18 files changed, 284 insertions(+), 92 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b0246168632c..926d6d4cdf19a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6516,6 +6516,7 @@ dependencies = [ "arrayvec 0.7.2", "bitvec", "byte-slice-cast", + "bytes", "impl-trait-for-tuples", "parity-scale-codec-derive", "serde", @@ -9731,6 +9732,7 @@ dependencies = [ name = "sp-io" version = "6.0.0" dependencies = [ + "bytes", "futures", "hash-db", "libsecp256k1", @@ -9889,6 +9891,7 @@ dependencies = [ name = "sp-runtime-interface" version = "6.0.0" dependencies = [ + "bytes", "impl-trait-for-tuples", "parity-scale-codec", "primitive-types", @@ -9938,6 +9941,7 @@ dependencies = [ name = "sp-runtime-interface-test-wasm" version = "2.0.0" dependencies = [ + "bytes", "sp-core", "sp-io", "sp-runtime-interface", diff --git a/client/allocator/src/freeing_bump.rs b/client/allocator/src/freeing_bump.rs index 79d6fca6f91b6..13dc6dca0dcd6 100644 --- a/client/allocator/src/freeing_bump.rs +++ b/client/allocator/src/freeing_bump.rs @@ -314,27 +314,50 @@ impl IndexMut for FreeLists { } } +/// Memory allocation stats gathered during the lifetime of the allocator. +#[derive(Clone, Debug, Default)] +#[non_exhaustive] +pub struct AllocationStats { + /// The current number of bytes allocated. + /// + /// This represents how many bytes are allocated *right now*. + pub bytes_allocated: u32, + + /// The peak number of bytes ever allocated. + /// + /// This is the maximum the `bytes_allocated` ever reached. + pub bytes_allocated_peak: u32, + + /// The sum of every allocation ever made. + /// + /// This increases every time a new allocation is made. + pub bytes_allocated_sum: u32, + + /// The amount of address space (in bytes) used by the allocator. + /// + /// This is calculated as the difference between the allocator's bumper + /// and the heap base. + /// + /// Currently the bumper's only ever incremented, so this is simultaneously + /// the current value as well as the peak value. + pub address_space_used: u32, +} + /// An implementation of freeing bump allocator. /// /// Refer to the module-level documentation for further details. pub struct FreeingBumpHeapAllocator { + original_heap_base: u32, bumper: u32, free_lists: FreeLists, - total_size: u32, poisoned: bool, - max_total_size: u32, - max_bumper: u32, last_observed_memory_size: u32, + stats: AllocationStats, } impl Drop for FreeingBumpHeapAllocator { fn drop(&mut self) { - log::debug!( - target: LOG_TARGET, - "allocator being destroyed, max_total_size {}, max_bumper {}", - self.max_total_size, - self.max_bumper, - ) + log::debug!(target: LOG_TARGET, "allocator dropped: {:?}", self.stats) } } @@ -348,13 +371,12 @@ impl FreeingBumpHeapAllocator { let aligned_heap_base = (heap_base + ALIGNMENT - 1) / ALIGNMENT * ALIGNMENT; FreeingBumpHeapAllocator { + original_heap_base: aligned_heap_base, bumper: aligned_heap_base, free_lists: FreeLists::new(), - total_size: 0, poisoned: false, - max_total_size: 0, - max_bumper: aligned_heap_base, last_observed_memory_size: 0, + stats: AllocationStats::default(), } } @@ -412,22 +434,13 @@ impl FreeingBumpHeapAllocator { // Write the order in the occupied header. Header::Occupied(order).write_into(mem, header_ptr)?; - self.total_size += order.size() + HEADER_SIZE; - - log::trace!( - target: LOG_TARGET, - "after allocation, total_size = {}, bumper = {}.", - self.total_size, - self.bumper, - ); + self.stats.bytes_allocated += order.size() + HEADER_SIZE; + self.stats.bytes_allocated_sum += order.size() + HEADER_SIZE; + self.stats.bytes_allocated_peak = + std::cmp::max(self.stats.bytes_allocated_peak, self.stats.bytes_allocated); + self.stats.address_space_used = self.bumper - self.original_heap_base; - // update trackers if needed. - if self.total_size > self.max_total_size { - self.max_total_size = self.total_size; - } - if self.bumper > self.max_bumper { - self.max_bumper = self.bumper; - } + log::trace!(target: LOG_TARGET, "after allocation: {:?}", self.stats); bomb.disarm(); Ok(Pointer::new(header_ptr + HEADER_SIZE)) @@ -469,21 +482,23 @@ impl FreeingBumpHeapAllocator { let prev_head = self.free_lists.replace(order, Link::Ptr(header_ptr)); Header::Free(prev_head).write_into(mem, header_ptr)?; - // Do the total_size book keeping. - self.total_size = self - .total_size + self.stats.bytes_allocated = self + .stats + .bytes_allocated .checked_sub(order.size() + HEADER_SIZE) - .ok_or_else(|| error("Unable to subtract from total heap size without overflow"))?; - log::trace!( - "after deallocation, total_size = {}, bumper = {}.", - self.total_size, - self.bumper, - ); + .ok_or_else(|| error("underflow of the currently allocated bytes count"))?; + + log::trace!("after deallocation: {:?}", self.stats); bomb.disarm(); Ok(()) } + /// Returns the allocation stats for this allocator. + pub fn stats(&self) -> AllocationStats { + self.stats.clone() + } + /// Increases the `bumper` by `size`. /// /// Returns the `bumper` from before the increase. Returns an `Error::AllocatorOutOfSpace` if @@ -791,13 +806,13 @@ mod tests { let ptr1 = heap.allocate(&mut mem[..], 32).unwrap(); assert_eq!(ptr1, to_pointer(HEADER_SIZE)); heap.deallocate(&mut mem[..], ptr1).expect("failed freeing ptr1"); - assert_eq!(heap.total_size, 0); + assert_eq!(heap.stats.bytes_allocated, 0); assert_eq!(heap.bumper, 40); let ptr2 = heap.allocate(&mut mem[..], 16).unwrap(); assert_eq!(ptr2, to_pointer(48)); heap.deallocate(&mut mem[..], ptr2).expect("failed freeing ptr2"); - assert_eq!(heap.total_size, 0); + assert_eq!(heap.stats.bytes_allocated, 0); assert_eq!(heap.bumper, 64); // when @@ -825,7 +840,7 @@ mod tests { heap.allocate(&mut mem[..], 9).unwrap(); // then - assert_eq!(heap.total_size, HEADER_SIZE + 16); + assert_eq!(heap.stats.bytes_allocated, HEADER_SIZE + 16); } #[test] @@ -840,7 +855,7 @@ mod tests { heap.deallocate(&mut mem[..], ptr).unwrap(); // then - assert_eq!(heap.total_size, 0); + assert_eq!(heap.stats.bytes_allocated, 0); } #[test] @@ -856,7 +871,7 @@ mod tests { } // then - assert_eq!(heap.total_size, 0); + assert_eq!(heap.stats.bytes_allocated, 0); } #[test] diff --git a/client/allocator/src/lib.rs b/client/allocator/src/lib.rs index 2c3e3b2ae841d..2fe63a1ec392c 100644 --- a/client/allocator/src/lib.rs +++ b/client/allocator/src/lib.rs @@ -26,4 +26,4 @@ mod error; mod freeing_bump; pub use error::Error; -pub use freeing_bump::FreeingBumpHeapAllocator; +pub use freeing_bump::{AllocationStats, FreeingBumpHeapAllocator}; diff --git a/client/executor/common/src/wasm_runtime.rs b/client/executor/common/src/wasm_runtime.rs index d43ad758b144c..d0cc8926144be 100644 --- a/client/executor/common/src/wasm_runtime.rs +++ b/client/executor/common/src/wasm_runtime.rs @@ -21,6 +21,8 @@ use crate::error::Error; use sp_wasm_interface::Value; +pub use sc_allocator::AllocationStats; + /// A method to be used to find the entrypoint when calling into the runtime /// /// Contains variants on how to resolve wasm function that will be invoked. @@ -78,7 +80,20 @@ pub trait WasmInstance: Send { /// Before execution, instance is reset. /// /// Returns the encoded result on success. - fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result, Error>; + fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result, Error> { + self.call_with_allocation_stats(method, data).0 + } + + /// Call a method on this WASM instance. + /// + /// Before execution, instance is reset. + /// + /// Returns the encoded result on success. + fn call_with_allocation_stats( + &mut self, + method: InvokeMethod, + data: &[u8], + ) -> (Result, Error>, Option); /// Call an exported method on this WASM instance. /// diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index ea060a89c13df..d805949d26fd9 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -37,7 +37,7 @@ use std::{ use codec::{Decode, Encode}; use sc_executor_common::{ runtime_blob::RuntimeBlob, - wasm_runtime::{InvokeMethod, WasmInstance, WasmModule}, + wasm_runtime::{AllocationStats, InvokeMethod, WasmInstance, WasmModule}, }; use sp_core::{ traits::{CodeExecutor, Externalities, RuntimeCode, RuntimeSpawn, RuntimeSpawnExt}, @@ -219,6 +219,47 @@ where allow_missing_host_functions: bool, export_name: &str, call_data: &[u8], + ) -> std::result::Result, Error> { + self.uncached_call_impl( + runtime_blob, + ext, + allow_missing_host_functions, + export_name, + call_data, + &mut None, + ) + } + + /// Same as `uncached_call`, except it also returns allocation statistics. + #[doc(hidden)] // We use this function in tests. + pub fn uncached_call_with_allocation_stats( + &self, + runtime_blob: RuntimeBlob, + ext: &mut dyn Externalities, + allow_missing_host_functions: bool, + export_name: &str, + call_data: &[u8], + ) -> (std::result::Result, Error>, Option) { + let mut allocation_stats = None; + let result = self.uncached_call_impl( + runtime_blob, + ext, + allow_missing_host_functions, + export_name, + call_data, + &mut allocation_stats, + ); + (result, allocation_stats) + } + + fn uncached_call_impl( + &self, + runtime_blob: RuntimeBlob, + ext: &mut dyn Externalities, + allow_missing_host_functions: bool, + export_name: &str, + call_data: &[u8], + allocation_stats_out: &mut Option, ) -> std::result::Result, Error> { let module = crate::wasm_runtime::create_wasm_runtime_with_code::( self.method, @@ -235,10 +276,14 @@ where let mut instance = AssertUnwindSafe(instance); let mut ext = AssertUnwindSafe(ext); let module = AssertUnwindSafe(module); + let mut allocation_stats_out = AssertUnwindSafe(allocation_stats_out); with_externalities_safe(&mut **ext, move || { preregister_builtin_ext(module.clone()); - instance.call_export(export_name, call_data) + let (result, allocation_stats) = + instance.call_with_allocation_stats(export_name.into(), call_data); + **allocation_stats_out = allocation_stats; + result }) .and_then(|r| r) } diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index 199fe431580ed..e17707e158321 100644 --- a/client/executor/wasmi/src/lib.rs +++ b/client/executor/wasmi/src/lib.rs @@ -29,6 +29,7 @@ use wasmi::{ }; use codec::{Decode, Encode}; +use sc_allocator::AllocationStats; use sc_executor_common::{ error::{Error, MessageWithBacktrace, WasmError}, runtime_blob::{DataSegmentsSnapshot, RuntimeBlob}, @@ -489,6 +490,7 @@ fn call_in_wasm_module( host_functions: Arc>, allow_missing_func_imports: bool, missing_functions: Arc>, + allocation_stats: &mut Option, ) -> Result, Error> { // Initialize FunctionExecutor. let table: Option = module_instance @@ -561,6 +563,8 @@ fn call_in_wasm_module( }, }; + *allocation_stats = Some(function_executor.heap.borrow().stats()); + match result { Ok(Some(I64(r))) => { let (ptr, length) = unpack_ptr_and_len(r as u64); @@ -761,8 +765,13 @@ pub struct WasmiInstance { // `self.instance` unsafe impl Send for WasmiInstance {} -impl WasmInstance for WasmiInstance { - fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result, Error> { +impl WasmiInstance { + fn call_impl( + &mut self, + method: InvokeMethod, + data: &[u8], + allocation_stats: &mut Option, + ) -> Result, Error> { // We reuse a single wasm instance for multiple calls and a previous call (if any) // altered the state. Therefore, we need to restore the instance to original state. @@ -790,8 +799,21 @@ impl WasmInstance for WasmiInstance { self.host_functions.clone(), self.allow_missing_func_imports, self.missing_functions.clone(), + allocation_stats, ) } +} + +impl WasmInstance for WasmiInstance { + fn call_with_allocation_stats( + &mut self, + method: InvokeMethod, + data: &[u8], + ) -> (Result, Error>, Option) { + let mut allocation_stats = None; + let result = self.call_impl(method, data, &mut allocation_stats); + (result, allocation_stats) + } fn get_global_const(&mut self, name: &str) -> Result, Error> { match self.instance.export_by_name(name) { diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index b494795ae9dc1..a54254810b68b 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -23,7 +23,7 @@ use log::trace; use wasmtime::{Caller, Func, Val}; use codec::{Decode, Encode}; -use sc_allocator::FreeingBumpHeapAllocator; +use sc_allocator::{AllocationStats, FreeingBumpHeapAllocator}; use sc_executor_common::{ error::Result, sandbox::{self, SupervisorFuncIndex}, @@ -66,6 +66,10 @@ impl HostState { pub fn take_panic_message(&mut self) -> Option { self.panic_message.take() } + + pub(crate) fn allocation_stats(&self) -> AllocationStats { + self.allocator.stats() + } } /// A `HostContext` implements `FunctionContext` for making host calls from a Wasmtime diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index dcf07c454e46d..2feb9d0eea502 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -24,7 +24,7 @@ use crate::{ util::{self, replace_strategy_if_broken}, }; -use sc_allocator::FreeingBumpHeapAllocator; +use sc_allocator::{AllocationStats, FreeingBumpHeapAllocator}; use sc_executor_common::{ error::{Result, WasmError}, runtime_blob::{ @@ -184,8 +184,13 @@ pub struct WasmtimeInstance { strategy: Strategy, } -impl WasmInstance for WasmtimeInstance { - fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result> { +impl WasmtimeInstance { + fn call_impl( + &mut self, + method: InvokeMethod, + data: &[u8], + allocation_stats: &mut Option, + ) -> Result> { match &mut self.strategy { Strategy::LegacyInstanceReuse { ref mut instance_wrapper, @@ -205,7 +210,8 @@ impl WasmInstance for WasmtimeInstance { globals_snapshot.apply(&mut InstanceGlobals { instance: instance_wrapper }); let allocator = FreeingBumpHeapAllocator::new(*heap_base); - let result = perform_call(data, instance_wrapper, entrypoint, allocator); + let result = + perform_call(data, instance_wrapper, entrypoint, allocator, allocation_stats); // Signal to the OS that we are done with the linear memory and that it can be // reclaimed. @@ -219,10 +225,22 @@ impl WasmInstance for WasmtimeInstance { let entrypoint = instance_wrapper.resolve_entrypoint(method)?; let allocator = FreeingBumpHeapAllocator::new(heap_base); - perform_call(data, &mut instance_wrapper, entrypoint, allocator) + perform_call(data, &mut instance_wrapper, entrypoint, allocator, allocation_stats) }, } } +} + +impl WasmInstance for WasmtimeInstance { + fn call_with_allocation_stats( + &mut self, + method: InvokeMethod, + data: &[u8], + ) -> (Result>, Option) { + let mut allocation_stats = None; + let result = self.call_impl(method, data, &mut allocation_stats); + (result, allocation_stats) + } fn get_global_const(&mut self, name: &str) -> Result> { match &mut self.strategy { @@ -741,6 +759,7 @@ fn perform_call( instance_wrapper: &mut InstanceWrapper, entrypoint: EntryPoint, mut allocator: FreeingBumpHeapAllocator, + allocation_stats: &mut Option, ) -> Result> { let (data_ptr, data_len) = inject_input_data(instance_wrapper, &mut allocator, data)?; @@ -754,7 +773,10 @@ fn perform_call( .map(unpack_ptr_and_len); // Reset the host state - instance_wrapper.store_mut().data_mut().host_state = None; + let host_state = instance_wrapper.store_mut().data_mut().host_state.take().expect( + "the host state is always set before calling into WASM so it can't be None here; qed", + ); + *allocation_stats = Some(host_state.allocation_stats()); let (output_ptr, output_len) = ret?; let output = extract_output_data(instance_wrapper, output_ptr, output_len)?; diff --git a/frame/support/src/storage/unhashed.rs b/frame/support/src/storage/unhashed.rs index fc6d8ae79c57d..089230bc9bfdf 100644 --- a/frame/support/src/storage/unhashed.rs +++ b/frame/support/src/storage/unhashed.rs @@ -155,7 +155,7 @@ pub fn clear_prefix( /// Get a Vec of bytes from storage. pub fn get_raw(key: &[u8]) -> Option> { - sp_io::storage::get(key) + sp_io::storage::get(key).map(|value| value.to_vec()) } /// Put a raw byte slice into storage. diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index e1c1b32d65c39..45cdfad67b8ae 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 273 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -47,8 +47,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Cow<'a, T> Rc Vec - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes - and 2 others + bytes::bytes::Bytes + and 3 others = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 273 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -122,8 +122,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Cow<'a, T> Rc Vec - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes - and 2 others + bytes::bytes::Bytes + and 3 others = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 7d8c448f00193..d7441e8b18562 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 273 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -47,8 +47,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Cow<'a, T> Rc Vec - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes - and 2 others + bytes::bytes::Bytes + and 3 others = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 273 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -122,8 +122,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Cow<'a, T> Rc Vec - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes - and 2 others + bytes::bytes::Bytes + and 3 others = note: required because of the requirements on the impl of `Encode` for `Bar` = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 77ba4be677f31..fda6b7fdd11dd 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -15,7 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +bytes = { version = "1.1.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.1.3", default-features = false, features = ["bytes"] } hash-db = { version = "0.15.2", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-keystore = { version = "0.12.0", default-features = false, optional = true, path = "../keystore" } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index edffc37351147..9bf9345e594c3 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -125,8 +125,8 @@ impl From for KillStorageResult { #[runtime_interface] pub trait Storage { /// Returns the data for `key` in the storage or `None` if the key can not be found. - fn get(&self, key: &[u8]) -> Option> { - self.storage(key).map(|s| s.to_vec()) + fn get(&self, key: &[u8]) -> Option { + self.storage(key).map(|s| bytes::Bytes::from(s.to_vec())) } /// Get `key` from storage, placing the value into `value_out` and return the number of @@ -1787,7 +1787,7 @@ mod tests { t.execute_with(|| { assert_eq!(storage::get(b"hello"), None); storage::set(b"hello", b"world"); - assert_eq!(storage::get(b"hello"), Some(b"world".to_vec())); + assert_eq!(storage::get(b"hello"), Some(b"world".to_vec().into())); assert_eq!(storage::get(b"foo"), None); storage::set(b"foo", &[1, 2, 3][..]); }); @@ -1799,7 +1799,7 @@ mod tests { t.execute_with(|| { assert_eq!(storage::get(b"hello"), None); - assert_eq!(storage::get(b"foo"), Some(b"bar".to_vec())); + assert_eq!(storage::get(b"foo"), Some(b"bar".to_vec().into())); }); let value = vec![7u8; 35]; @@ -1809,7 +1809,7 @@ mod tests { t.execute_with(|| { assert_eq!(storage::get(b"hello"), None); - assert_eq!(storage::get(b"foo00"), Some(value.clone())); + assert_eq!(storage::get(b"foo00"), Some(value.clone().into())); }); } diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 8cd31bab559ea..a657c98381c9a 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -14,12 +14,13 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +bytes = { version = "1.1.0", default-features = false } sp-wasm-interface = { version = "6.0.0", path = "../wasm-interface", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } sp-runtime-interface-proc-macro = { version = "5.0.0", path = "proc-macro" } sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["bytes"] } static_assertions = "1.0.0" primitive-types = { version = "0.11.1", default-features = false } sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } diff --git a/primitives/runtime-interface/src/pass_by.rs b/primitives/runtime-interface/src/pass_by.rs index 5d895ff5b3f82..ac6f0def9cad0 100644 --- a/primitives/runtime-interface/src/pass_by.rs +++ b/primitives/runtime-interface/src/pass_by.rs @@ -248,12 +248,12 @@ impl PassByImpl for Codec { let len = len as usize; let encoded = if len == 0 { - Vec::new() + bytes::Bytes::new() } else { - unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) } + bytes::Bytes::from(unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) }) }; - T::decode(&mut &encoded[..]).expect("Host to wasm values are encoded correctly; qed") + codec::decode_from_bytes(encoded).expect("Host to wasm values are encoded correctly; qed") } } diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index f0e78e0e536b9..e9b2937227db6 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -13,6 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] +bytes = { version = "1.1.0", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../../core" } sp-io = { version = "6.0.0", default-features = false, path = "../../io" } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../" } diff --git a/primitives/runtime-interface/test-wasm/src/lib.rs b/primitives/runtime-interface/test-wasm/src/lib.rs index f518a2e17498c..1305aef66cacc 100644 --- a/primitives/runtime-interface/test-wasm/src/lib.rs +++ b/primitives/runtime-interface/test-wasm/src/lib.rs @@ -60,6 +60,18 @@ pub trait TestApi { vec![0; 4 * 1024] } + fn return_option_vec() -> Option> { + let mut vec = Vec::new(); + vec.resize(16 * 1024, 0xAA); + Some(vec) + } + + fn return_option_bytes() -> Option { + let mut vec = Vec::new(); + vec.resize(16 * 1024, 0xAA); + Some(vec.into()) + } + /// Set the storage at key with value. fn set_storage(&mut self, key: &[u8], data: &[u8]) { self.place_storage(key.to_vec(), Some(data.to_vec())); @@ -300,4 +312,12 @@ wasm_export_functions! { assert_eq!(c, res.2); assert_eq!(d, res.3); } + + fn test_return_option_vec() { + test_api::return_option_vec(); + } + + fn test_return_option_bytes() { + test_api::return_option_bytes(); + } } diff --git a/primitives/runtime-interface/test/src/lib.rs b/primitives/runtime-interface/test/src/lib.rs index 1ab8dbfbbff22..d1db3e064295e 100644 --- a/primitives/runtime-interface/test/src/lib.rs +++ b/primitives/runtime-interface/test/src/lib.rs @@ -23,7 +23,7 @@ use sp_runtime_interface::*; use sp_runtime_interface_test_wasm::{test_api::HostFunctions, wasm_binary_unwrap}; use sp_runtime_interface_test_wasm_deprecated::wasm_binary_unwrap as wasm_binary_deprecated_unwrap; -use sc_executor_common::runtime_blob::RuntimeBlob; +use sc_executor_common::{runtime_blob::RuntimeBlob, wasm_runtime::AllocationStats}; use sp_wasm_interface::{ExtendedHostFunctions, HostFunctions as HostFunctionsT}; use std::{ @@ -36,7 +36,7 @@ type TestExternalities = sp_state_machine::TestExternalities( binary: &[u8], method: &str, -) -> Result { +) -> (Result, Option) { let mut ext = TestExternalities::default(); let mut ext_ext = ext.ext(); @@ -44,20 +44,21 @@ fn call_wasm_method_with_result( ExtendedHostFunctions, >::new(sc_executor::WasmExecutionMethod::Interpreted, Some(8), 8, None, 2); - executor - .uncached_call( - RuntimeBlob::uncompress_if_needed(binary).expect("Failed to parse binary"), - &mut ext_ext, - false, - method, - &[], - ) - .map_err(|e| format!("Failed to execute `{}`: {}", method, e))?; - Ok(ext) + let (result, allocation_stats) = executor.uncached_call_with_allocation_stats( + RuntimeBlob::uncompress_if_needed(binary).expect("Failed to parse binary"), + &mut ext_ext, + false, + method, + &[], + ); + let result = result + .map_err(|e| format!("Failed to execute `{}`: {}", method, e)) + .map(|_| ext); + (result, allocation_stats) } fn call_wasm_method(binary: &[u8], method: &str) -> TestExternalities { - call_wasm_method_with_result::(binary, method).unwrap() + call_wasm_method_with_result::(binary, method).0.unwrap() } #[test] @@ -103,8 +104,9 @@ fn test_return_input_public_key() { #[test] fn host_function_not_found() { - let err = - call_wasm_method_with_result::<()>(wasm_binary_unwrap(), "test_return_data").unwrap_err(); + let err = call_wasm_method_with_result::<()>(wasm_binary_unwrap(), "test_return_data") + .0 + .unwrap_err(); assert!(err.contains("Instantiation: Export ")); assert!(err.contains(" not found")); @@ -236,3 +238,43 @@ fn test_tracing() { fn test_return_input_as_tuple() { call_wasm_method::(wasm_binary_unwrap(), "test_return_input_as_tuple"); } + +#[test] +fn test_returning_option_bytes_from_a_host_function_is_efficient() { + let (result, stats_vec) = call_wasm_method_with_result::( + wasm_binary_unwrap(), + "test_return_option_vec", + ); + result.unwrap(); + let (result, stats_bytes) = call_wasm_method_with_result::( + wasm_binary_unwrap(), + "test_return_option_bytes", + ); + result.unwrap(); + + let stats_vec = stats_vec.unwrap(); + let stats_bytes = stats_bytes.unwrap(); + + // The way we currently implement marshaling of `Option>` through + // the WASM FFI boundary from the host to the runtime requires that it is + // marshaled through SCALE. This is quite inefficient as it requires two + // memory allocations inside of the runtime: + // + // 1) the first allocation to copy the SCALE-encoded blob into the runtime; + // 2) and another allocation for the resulting `Vec` when decoding that blob. + // + // Both of these allocations are are as big as the `Vec` which is being + // passed to the runtime. This is especially bad when fetching big values + // from storage, as it can lead to an out-of-memory situation. + // + // Our `Option` marshaling is better; it still must go through SCALE, + // and it still requires two allocations, however since `Bytes` is zero-copy + // only the first allocation is `Vec`-sized, and the second allocation + // which creates the deserialized `Bytes` is tiny, and is only necessary because + // the underlying `Bytes` buffer from which we're deserializing gets automatically + // turned into an `Arc`. + // + // So this assertion tests that deserializing `Option` allocates less than + // deserializing `Option>`. + assert_eq!(stats_bytes.bytes_allocated_sum + 16 * 1024 + 8, stats_vec.bytes_allocated_sum); +} From 479c84cacee0009eb5632754295c039bf96f706d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 29 Jul 2022 10:22:49 +0100 Subject: [PATCH 1011/1472] construct_runtime!: Support parsing `struct Runtime` (#11932) * construct_runtime!: Support parsing `struct Runtime` * FMT --- bin/node-template/runtime/src/lib.rs | 5 +++-- frame/balances/src/tests_local.rs | 2 +- frame/support/procedural/src/construct_runtime/parse.rs | 9 ++++++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index a2f595f571a90..a4382cc9038ce 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -272,10 +272,11 @@ impl pallet_template::Config for Runtime { // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( - pub enum Runtime where + pub struct Runtime + where Block = Block, NodeBlock = opaque::Block, - UncheckedExtrinsic = UncheckedExtrinsic + UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system, RandomnessCollectiveFlip: pallet_randomness_collective_flip, diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index 6f4c50d90153a..48c6574c3b39f 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -34,7 +34,7 @@ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( - pub enum Test where + pub struct Test where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index a2cda6a0777b8..711da85c10cfc 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -73,7 +73,14 @@ pub struct ExplicitRuntimeDeclaration { impl Parse for RuntimeDeclaration { fn parse(input: ParseStream) -> Result { input.parse::()?; - input.parse::()?; + + // Support either `enum` or `struct`. + if input.peek(Token![struct]) { + input.parse::()?; + } else { + input.parse::()?; + } + let name = input.parse::()?; let where_section = input.parse()?; let pallets = From 47c19a570d4703732541decf97e22e3b2b8881d9 Mon Sep 17 00:00:00 2001 From: yjh Date: Fri, 29 Jul 2022 17:32:31 +0800 Subject: [PATCH 1012/1472] feat: add propose method for SimpleSlotWorker (#11692) * feat: add propose method for SimpleSlotWorker * remove param slot * improve code * fmt --- client/consensus/slots/src/lib.rs | 117 ++++++++++++++++++------------ 1 file changed, 69 insertions(+), 48 deletions(-) diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index a6fbc4bebc796..7c3de13444c1a 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -38,7 +38,7 @@ use log::{debug, info, warn}; use sc_consensus::{BlockImport, JustificationSyncLink}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO, CONSENSUS_WARN}; use sp_arithmetic::traits::BaseArithmetic; -use sp_consensus::{CanAuthorWith, Proposer, SelectChain, SyncOracle}; +use sp_consensus::{CanAuthorWith, Proposal, Proposer, SelectChain, SyncOracle}; use sp_consensus_slots::{Slot, SlotDuration}; use sp_inherents::CreateInherentDataProviders; use sp_runtime::{ @@ -103,7 +103,7 @@ pub trait SimpleSlotWorker { type Proposer: Proposer + Send; /// Data associated with a slot claim. - type Claim: Send + 'static; + type Claim: Send + Sync + 'static; /// Epoch data necessary for authoring. type EpochData: Send + Sync + 'static; @@ -183,6 +183,70 @@ pub trait SimpleSlotWorker { /// Remaining duration for proposing. fn proposing_remaining_duration(&self, slot_info: &SlotInfo) -> Duration; + /// Propose a block by `Proposer`. + async fn propose( + &mut self, + proposer: Self::Proposer, + claim: &Self::Claim, + slot_info: SlotInfo, + proposing_remaining: Delay, + ) -> Option< + Proposal< + B, + >::Transaction, + >::Proof, + >, + > { + let slot = slot_info.slot; + let telemetry = self.telemetry(); + let logging_target = self.logging_target(); + let proposing_remaining_duration = self.proposing_remaining_duration(&slot_info); + let logs = self.pre_digest_data(slot, claim); + + // deadline our production to 98% of the total time left for proposing. As we deadline + // the proposing below to the same total time left, the 2% margin should be enough for + // the result to be returned. + let proposing = proposer + .propose( + slot_info.inherent_data, + sp_runtime::generic::Digest { logs }, + proposing_remaining_duration.mul_f32(0.98), + None, + ) + .map_err(|e| sp_consensus::Error::ClientImport(e.to_string())); + + let proposal = match futures::future::select(proposing, proposing_remaining).await { + Either::Left((Ok(p), _)) => p, + Either::Left((Err(err), _)) => { + warn!(target: logging_target, "Proposing failed: {}", err); + + return None + }, + Either::Right(_) => { + info!( + target: logging_target, + "⌛️ Discarding proposal for slot {}; block production took too long", slot, + ); + // If the node was compiled with debug, tell the user to use release optimizations. + #[cfg(build_type = "debug")] + info!( + target: logging_target, + "👉 Recompile your node in `--release` mode to mitigate this problem.", + ); + telemetry!( + telemetry; + CONSENSUS_INFO; + "slots.discarding_proposal_took_too_long"; + "slot" => *slot, + ); + + return None + }, + }; + + Some(proposal) + } + /// Implements [`SlotWorker::on_slot`]. async fn on_slot( &mut self, @@ -256,10 +320,8 @@ pub trait SimpleSlotWorker { } debug!( - target: self.logging_target(), - "Starting authorship at slot {}; timestamp = {}", - slot, - *timestamp, + target: logging_target, + "Starting authorship at slot {}; timestamp = {}", slot, *timestamp, ); telemetry!( @@ -287,48 +349,7 @@ pub trait SimpleSlotWorker { }, }; - let logs = self.pre_digest_data(slot, &claim); - - // deadline our production to 98% of the total time left for proposing. As we deadline - // the proposing below to the same total time left, the 2% margin should be enough for - // the result to be returned. - let proposing = proposer - .propose( - slot_info.inherent_data, - sp_runtime::generic::Digest { logs }, - proposing_remaining_duration.mul_f32(0.98), - None, - ) - .map_err(|e| sp_consensus::Error::ClientImport(e.to_string())); - - let proposal = match futures::future::select(proposing, proposing_remaining).await { - Either::Left((Ok(p), _)) => p, - Either::Left((Err(err), _)) => { - warn!(target: logging_target, "Proposing failed: {}", err); - - return None - }, - Either::Right(_) => { - info!( - target: logging_target, - "⌛️ Discarding proposal for slot {}; block production took too long", slot, - ); - // If the node was compiled with debug, tell the user to use release optimizations. - #[cfg(build_type = "debug")] - info!( - target: logging_target, - "👉 Recompile your node in `--release` mode to mitigate this problem.", - ); - telemetry!( - telemetry; - CONSENSUS_INFO; - "slots.discarding_proposal_took_too_long"; - "slot" => *slot, - ); - - return None - }, - }; + let proposal = self.propose(proposer, &claim, slot_info, proposing_remaining).await?; let (block, storage_proof) = (proposal.block, proposal.proof); let (header, body) = block.deconstruct(); From bafd81148ca71faf73abfdb124430de1c994abc7 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Fri, 29 Jul 2022 12:56:08 +0200 Subject: [PATCH 1013/1472] Require Alliance Initialisation Before Joining (#11917) * require alliance initialisation before joining * use noop * make one definition of initialization * rename event * add todo comment * update doc --- frame/alliance/src/lib.rs | 34 +++++++++++++++++++++++++++------- frame/alliance/src/mock.rs | 8 +++++++- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index f9e85e270af16..111ea5dc6e507 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -311,7 +311,9 @@ pub mod pallet { #[pallet::error] pub enum Error { /// The founders/fellows/allies have already been initialized. - MembersAlreadyInitialized, + AllianceAlreadyInitialized, + /// The Alliance has not been initialized yet, therefore accounts cannot join it. + AllianceNotYetInitialized, /// Account is already a member. AlreadyMember, /// Account is not a member. @@ -434,6 +436,11 @@ pub mod pallet { Members::::insert(MemberRole::Fellow, members); } if !self.allies.is_empty() { + // Only allow Allies if the Alliance is "initialized". + assert!( + Pallet::::is_initialized(), + "Alliance must have Founders or Fellows to have Allies" + ); let members: BoundedVec = self.allies.clone().try_into().expect("Too many genesis allies"); Members::::insert(MemberRole::Ally, members); @@ -612,6 +619,11 @@ pub mod pallet { ) -> DispatchResult { ensure_root(origin)?; + // Cannot be called if the Alliance already has Founders or Fellows. + // TODO: Remove check and allow Root to set members at any time. + // https://github.com/paritytech/substrate/issues/11928 + ensure!(!Self::is_initialized(), Error::::AllianceAlreadyInitialized); + let mut founders: BoundedVec = founders.try_into().map_err(|_| Error::::TooManyMembers)?; let mut fellows: BoundedVec = @@ -619,12 +631,6 @@ pub mod pallet { let mut allies: BoundedVec = allies.try_into().map_err(|_| Error::::TooManyMembers)?; - ensure!( - !Self::has_member(MemberRole::Founder) && - !Self::has_member(MemberRole::Fellow) && - !Self::has_member(MemberRole::Ally), - Error::::MembersAlreadyInitialized - ); for member in founders.iter().chain(fellows.iter()).chain(allies.iter()) { Self::has_identity(member)?; } @@ -705,6 +711,15 @@ pub mod pallet { pub fn join_alliance(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; + // We don't want anyone to join as an Ally before the Alliance has been initialized via + // Root call. The reasons are two-fold: + // + // 1. There is no `Rule` or admission criteria, so the joiner would be an ally to + // nought, and + // 2. It adds complexity to the initialization, namely deciding to overwrite accounts + // that already joined as an Ally. + ensure!(Self::is_initialized(), Error::::AllianceNotYetInitialized); + // Unscrupulous accounts are non grata. ensure!(!Self::is_unscrupulous_account(&who), Error::::AccountNonGrata); ensure!(!Self::is_member(&who), Error::::AlreadyMember); @@ -867,6 +882,11 @@ pub mod pallet { } impl, I: 'static> Pallet { + /// Check if the Alliance has been initialized. + fn is_initialized() -> bool { + Self::has_member(MemberRole::Founder) || Self::has_member(MemberRole::Fellow) + } + /// Check if a given role has any members. fn has_member(role: MemberRole) -> bool { Members::::decode_len(role).unwrap_or_default() > 0 diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index d6e9a92a10dec..91986300aa2e1 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -26,7 +26,7 @@ pub use sp_runtime::{ use sp_std::convert::{TryFrom, TryInto}; pub use frame_support::{ - assert_ok, ord_parameter_types, parameter_types, + assert_noop, assert_ok, ord_parameter_types, parameter_types, traits::{EitherOfDiverse, GenesisBuild, SortedMembers}, BoundedVec, }; @@ -291,6 +291,12 @@ pub fn new_test_ext() -> sp_io::TestExternalities { assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 5, Judgement::KnownGood)); assert_ok!(Identity::set_identity(Origin::signed(6), Box::new(info.clone()))); + // Joining before init should fail. + assert_noop!( + Alliance::join_alliance(Origin::signed(1)), + Error::::AllianceNotYetInitialized + ); + assert_ok!(Alliance::init_members(Origin::root(), vec![1, 2], vec![3], vec![])); System::set_block_number(1); From e0d7147c672afe45c47e82d1ad2ce3b8fc733984 Mon Sep 17 00:00:00 2001 From: Mak Date: Fri, 29 Jul 2022 15:16:30 +0300 Subject: [PATCH 1014/1472] Integrate automatic update of substrate-node-template (#11931) * Integrate automatic update of substrate-node-template * Update scripts/ci/gitlab/pipeline/publish.yml Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> --- scripts/ci/gitlab/pipeline/publish.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index c02b50e0cbc1d..8f7a619f8b196 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -147,3 +147,17 @@ publish-draft-release: script: - ./scripts/ci/gitlab/publish_draft_release.sh allow_failure: true + +# Ref: https://github.com/paritytech/opstooling/issues/111 +update-node-template: + stage: publish + extends: .kubernetes-env + rules: + - if: $CI_COMMIT_REF_NAME =~ /^polkadot-v[0-9]+\.[0-9]+.*$/ # i.e. polkadot-v1.0.99, polkadot-v2.1rc1 + script: + - git clone --depth=1 --branch="$PIPELINE_SCRIPTS_TAG" https://github.com/paritytech/pipeline-scripts + - ./pipeline-scripts/update_substrate_template.sh + --repo-name "substrate-node-template" + --template-path "bin/node-template" + --github-api-token "$GITHUB_TOKEN" + --polkadot-branch "$CI_COMMIT_REF_NAME" From 969a344684d9b79b6bb6bab591ac73df4017fea9 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 29 Jul 2022 15:36:48 +0300 Subject: [PATCH 1015/1472] Always allocate slots for reserved nodes (#11909) * Always allocate slots for reserved nodes * minor: replace no-slot peer counter with a set --- client/network/src/protocol.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 3698a6b936ed5..1c933fabcbb5d 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -179,6 +179,10 @@ pub struct Protocol { /// List of nodes for which we perform additional logging because they are important for the /// user. important_peers: HashSet, + /// List of nodes that should never occupy peer slots. + default_peers_set_no_slot_peers: HashSet, + /// Actual list of connected no-slot nodes. + default_peers_set_no_slot_connected_peers: HashSet, /// Value that was passed as part of the configuration. Used to cap the number of full nodes. default_peers_set_num_full: usize, /// Number of slots to allocate to light nodes. @@ -304,6 +308,17 @@ where imp_p }; + let default_peers_set_no_slot_peers = { + let mut no_slot_p: HashSet = network_config + .default_peers_set + .reserved_nodes + .iter() + .map(|reserved| reserved.peer_id) + .collect(); + no_slot_p.shrink_to_fit(); + no_slot_p + }; + let mut known_addresses = Vec::new(); let (peerset, peerset_handle) = { @@ -404,6 +419,8 @@ where genesis_hash: info.genesis_hash, chain_sync, important_peers, + default_peers_set_no_slot_peers, + default_peers_set_no_slot_connected_peers: HashSet::new(), default_peers_set_num_full: network_config.default_peers_set_num_full as usize, default_peers_set_num_light: { let total = network_config.default_peers_set.out_peers + @@ -542,6 +559,7 @@ where self.pending_messages .push_back(CustomMessageOutcome::BlockImport(origin, blocks)); } + self.default_peers_set_no_slot_connected_peers.remove(&peer); Ok(()) } else { Err(()) @@ -723,7 +741,14 @@ where } } - if status.roles.is_full() && self.chain_sync.num_peers() >= self.default_peers_set_num_full + let no_slot_peer = self.default_peers_set_no_slot_peers.contains(&who); + let this_peer_reserved_slot: usize = if no_slot_peer { 1 } else { 0 }; + + if status.roles.is_full() && + self.chain_sync.num_peers() >= + self.default_peers_set_num_full + + self.default_peers_set_no_slot_connected_peers.len() + + this_peer_reserved_slot { debug!(target: "sync", "Too many full nodes, rejecting {}", who); self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); @@ -767,6 +792,9 @@ where debug!(target: "sync", "Connected {}", who); self.peers.insert(who, peer); + if no_slot_peer { + self.default_peers_set_no_slot_connected_peers.insert(who); + } self.pending_messages .push_back(CustomMessageOutcome::PeerNewBest(who, status.best_number)); From 494a2883e14a389e1c090475077d0c745fefc6c3 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 29 Jul 2022 18:47:21 +0300 Subject: [PATCH 1016/1472] Lean BEEFY to Full BEEFY - don't skip (older) mandatory blocks and import justifications (#11821) * client/beefy: don't accept vote for older rounds * client/beefy: clean up and reorg the worker struct * client/beefy: first step towards Full BEEFY The first step from Lean->Full BEEFY is to have the worker enforce uninterrupted line of BEEFY finalized mandatory blocks. There is one mandatory block per session (the first block in the session). As such, votes processing and votes generation now enforces that all mandatory blocks are finalized in strict monotonically increasing sequence and no block 'N' will be worked on if there is any GRANDPA finalized but BEEFY non-final mandatory block 'M', where 'M < N'. Implementation details: - Introduced 'VoterOracle' to separate the voting decisions logic, and track new/pending sessions. - New sessions get queued up with the worker operating either: 1. up-to-date - all mandatory blocks leading up to current GRANDPA finalized: queue has ONE element, the 'current session' where `mandatory_done == true`, 2. lagging behind GRANDPA: queue has [1, N] elements, where all `mandatory_done == false`. In this state, everytime a session gets its mandatory block BEEFY finalized, the session is popped off the queue, eventually getting to operating mode `1. up-to-date`. - Votes get triaged and those that fall withing the `VoterOracle` allowed window get processed, the others get dropped if stale, or buffered for later processing (when they reach the window). - Worker general code was also updated to fall in one of two roles: 1. react to external events and change internal 'state', 2. generate events/votes based on internal 'state'. Signed-off-by: acatangiu * client/beefy: sketch idea for block import and sync Signed-off-by: acatangiu * client/beefy: add BEEFY block import * client/beefy: process justifications from block import * client/beefy: add TODOs for sync protocol * client/beefy: add more docs and comments * client/beefy-rpc: fix RPC error * client/beefy: verify justification validity on block import * client/beefy: more tests * client/beefy: small fixes - first handle and note the self vote before gossiping it, - don't shortcircuit on err when processing pending votes. * client/beefy: remove invalid justifications at block import * todo: beefy block import tests * RFC: ideas for multiple justifications per block * Revert "RFC: ideas for multiple justifications per block" This reverts commit 8256fb07d3124db69daf252720b3c0208202624d. * client/beefy: append justif to backend on block import * client/beefy: groundwork for block import test * client/beefy: groundwork2 for block import test * client/beefy: groundwork3 for block import test * client/beefy: add block import test * client/beefy: add required trait bounds to block import builder * remove client from beefy block import, backend gets the job done Signed-off-by: acatangiu --- Cargo.lock | 2 + client/beefy/Cargo.toml | 4 +- client/beefy/rpc/src/lib.rs | 5 +- client/beefy/rpc/src/notification.rs | 2 +- client/beefy/src/error.rs | 4 + client/beefy/src/import.rs | 205 ++++++ client/beefy/src/justification.rs | 177 +++++ client/beefy/src/lib.rs | 101 ++- client/beefy/src/metrics.rs | 10 +- client/beefy/src/notification.rs | 6 +- client/beefy/src/round.rs | 82 ++- client/beefy/src/tests.rs | 199 +++++- client/beefy/src/worker.rs | 932 +++++++++++++++++---------- client/network/test/src/lib.rs | 15 +- primitives/beefy/src/commitment.rs | 6 + primitives/runtime/src/lib.rs | 5 + 16 files changed, 1344 insertions(+), 411 deletions(-) create mode 100644 client/beefy/src/import.rs create mode 100644 client/beefy/src/justification.rs diff --git a/Cargo.lock b/Cargo.lock index 926d6d4cdf19a..34bf34c62c6fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -440,6 +440,7 @@ dependencies = [ name = "beefy-gadget" version = "4.0.0-dev" dependencies = [ + "async-trait", "beefy-primitives", "fnv", "futures", @@ -448,6 +449,7 @@ dependencies = [ "log", "parity-scale-codec", "parking_lot 0.12.0", + "sc-block-builder", "sc-chain-spec", "sc-client-api", "sc-consensus", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index b910f7ce307a5..e219420959c9f 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -9,6 +9,7 @@ description = "BEEFY Client gadget for substrate" homepage = "https://substrate.io" [dependencies] +async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } fnv = "1.0.6" futures = "0.3" @@ -22,6 +23,7 @@ beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } prometheus = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } +sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../../client/finality-grandpa" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } @@ -42,7 +44,7 @@ serde = "1.0.136" strum = { version = "0.24.1", features = ["derive"] } tempfile = "3.1.0" tokio = "1.17.0" -sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } +sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-network-test = { version = "0.8.0", path = "../network/test" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 2c3ffda056c26..13bca08d37429 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -164,8 +164,9 @@ where mod tests { use super::*; - use beefy_gadget::notification::{ - BeefyBestBlockStream, BeefySignedCommitment, BeefySignedCommitmentSender, + use beefy_gadget::{ + justification::BeefySignedCommitment, + notification::{BeefyBestBlockStream, BeefySignedCommitmentSender}, }; use beefy_primitives::{known_payload_ids, Payload}; use codec::{Decode, Encode}; diff --git a/client/beefy/rpc/src/notification.rs b/client/beefy/rpc/src/notification.rs index 2f58c7c6bb5dc..cdda667782dd5 100644 --- a/client/beefy/rpc/src/notification.rs +++ b/client/beefy/rpc/src/notification.rs @@ -29,7 +29,7 @@ pub struct EncodedSignedCommitment(sp_core::Bytes); impl EncodedSignedCommitment { pub fn new( - signed_commitment: beefy_gadget::notification::BeefySignedCommitment, + signed_commitment: beefy_gadget::justification::BeefySignedCommitment, ) -> Self where Block: BlockT, diff --git a/client/beefy/src/error.rs b/client/beefy/src/error.rs index eacadeb7613a5..dd5fd649d52ce 100644 --- a/client/beefy/src/error.rs +++ b/client/beefy/src/error.rs @@ -24,8 +24,12 @@ use std::fmt::Debug; #[derive(Debug, thiserror::Error, PartialEq)] pub enum Error { + #[error("Backend: {0}")] + Backend(String), #[error("Keystore error: {0}")] Keystore(String), #[error("Signature error: {0}")] Signature(String), + #[error("Session uninitialized")] + UninitSession, } diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs new file mode 100644 index 0000000000000..7caeb49db5e50 --- /dev/null +++ b/client/beefy/src/import.rs @@ -0,0 +1,205 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use beefy_primitives::{crypto::Signature, BeefyApi, VersionedFinalityProof, BEEFY_ENGINE_ID}; +use codec::Encode; +use log::error; +use std::{collections::HashMap, sync::Arc}; + +use sp_api::{ProvideRuntimeApi, TransactionFor}; +use sp_blockchain::{well_known_cache_keys, HeaderBackend}; +use sp_consensus::Error as ConsensusError; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Header as HeaderT, NumberFor}, + EncodedJustification, +}; + +use sc_client_api::backend::Backend; +use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResult}; + +use crate::{ + justification::decode_and_verify_commitment, notification::BeefySignedCommitmentSender, +}; + +/// A block-import handler for BEEFY. +/// +/// This scans each imported block for BEEFY justifications and verifies them. +/// Wraps a `inner: BlockImport` and ultimately defers to it. +/// +/// When using BEEFY, the block import worker should be using this block import object. +pub struct BeefyBlockImport { + backend: Arc, + runtime: Arc, + inner: I, + justification_sender: BeefySignedCommitmentSender, +} + +impl Clone for BeefyBlockImport { + fn clone(&self) -> Self { + BeefyBlockImport { + backend: self.backend.clone(), + runtime: self.runtime.clone(), + inner: self.inner.clone(), + justification_sender: self.justification_sender.clone(), + } + } +} + +impl BeefyBlockImport { + /// Create a new BeefyBlockImport. + pub fn new( + backend: Arc, + runtime: Arc, + inner: I, + justification_sender: BeefySignedCommitmentSender, + ) -> BeefyBlockImport { + BeefyBlockImport { backend, runtime, inner, justification_sender } + } +} + +impl BeefyBlockImport +where + Block: BlockT, + BE: Backend, + Runtime: ProvideRuntimeApi, + Runtime::Api: BeefyApi + Send + Sync, +{ + fn decode_and_verify( + &self, + encoded: &EncodedJustification, + number: NumberFor, + hash: ::Hash, + ) -> Result, Signature>, ConsensusError> { + let block_id = BlockId::hash(hash); + let validator_set = self + .runtime + .runtime_api() + .validator_set(&block_id) + .map_err(|e| ConsensusError::ClientImport(e.to_string()))? + .ok_or_else(|| ConsensusError::ClientImport("Unknown validator set".to_string()))?; + + decode_and_verify_commitment::(&encoded[..], number, &validator_set) + } + + /// Import BEEFY justification: Send it to worker for processing and also append it to backend. + /// + /// This function assumes: + /// - `justification` is verified and valid, + /// - the block referred by `justification` has been imported _and_ finalized. + fn import_beefy_justification_unchecked( + &self, + number: NumberFor, + justification: VersionedFinalityProof, Signature>, + ) { + // Append the justification to the block in the backend. + if let Err(e) = self.backend.append_justification( + BlockId::Number(number), + (BEEFY_ENGINE_ID, justification.encode()), + ) { + error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, justification); + } + // Send the justification to the BEEFY voter for processing. + match justification { + // TODO #11838: Should not unpack, these channels should also use + // `VersionedFinalityProof`. + VersionedFinalityProof::V1(signed_commitment) => self + .justification_sender + .notify(|| Ok::<_, ()>(signed_commitment)) + .expect("forwards closure result; the closure always returns Ok; qed."), + }; + } +} + +#[async_trait::async_trait] +impl BlockImport for BeefyBlockImport +where + Block: BlockT, + BE: Backend, + I: BlockImport< + Block, + Error = ConsensusError, + Transaction = sp_api::TransactionFor, + > + Send + + Sync, + Runtime: ProvideRuntimeApi + Send + Sync, + Runtime::Api: BeefyApi, +{ + type Error = ConsensusError; + type Transaction = TransactionFor; + + async fn import_block( + &mut self, + mut block: BlockImportParams, + new_cache: HashMap>, + ) -> Result { + let hash = block.post_hash(); + let number = *block.header.number(); + + let beefy_proof = block + .justifications + .as_mut() + .and_then(|just| { + let decoded = just + .get(BEEFY_ENGINE_ID) + .map(|encoded| self.decode_and_verify(encoded, number, hash)); + // Remove BEEFY justification from the list before giving to `inner`; + // we will append it to backend ourselves at the end if all goes well. + just.remove(BEEFY_ENGINE_ID); + decoded + }) + .transpose() + .unwrap_or(None); + + // Run inner block import. + let inner_import_result = self.inner.import_block(block, new_cache).await?; + + match (beefy_proof, &inner_import_result) { + (Some(proof), ImportResult::Imported(_)) => { + let status = self.backend.blockchain().info(); + if number <= status.finalized_number && + Some(hash) == + self.backend + .blockchain() + .hash(number) + .map_err(|e| ConsensusError::ClientImport(e.to_string()))? + { + // The proof is valid and the block is imported and final, we can import. + self.import_beefy_justification_unchecked(number, proof); + } else { + error!( + target: "beefy", + "🥩 Cannot import justification: {:?} for, not yet final, block number {:?}", + proof, + number, + ); + } + }, + _ => (), + } + + Ok(inner_import_result) + } + + async fn check_block( + &mut self, + block: BlockCheckParams, + ) -> Result { + self.inner.check_block(block).await + } +} diff --git a/client/beefy/src/justification.rs b/client/beefy/src/justification.rs new file mode 100644 index 0000000000000..2a5191daec4b5 --- /dev/null +++ b/client/beefy/src/justification.rs @@ -0,0 +1,177 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::keystore::BeefyKeystore; +use beefy_primitives::{ + crypto::{AuthorityId, Signature}, + ValidatorSet, VersionedFinalityProof, +}; +use codec::{Decode, Encode}; +use sp_consensus::Error as ConsensusError; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +/// A commitment with matching BEEFY authorities' signatures. +pub type BeefySignedCommitment = + beefy_primitives::SignedCommitment, beefy_primitives::crypto::Signature>; + +/// Decode and verify a Beefy SignedCommitment. +pub(crate) fn decode_and_verify_commitment( + encoded: &[u8], + target_number: NumberFor, + validator_set: &ValidatorSet, +) -> Result, Signature>, ConsensusError> { + let proof = , Signature>>::decode(&mut &*encoded) + .map_err(|_| ConsensusError::InvalidJustification)?; + verify_with_validator_set::(target_number, validator_set, &proof).map(|_| proof) +} + +/// Verify the Beefy finality proof against the validator set at the block it was generated. +fn verify_with_validator_set( + target_number: NumberFor, + validator_set: &ValidatorSet, + proof: &VersionedFinalityProof, Signature>, +) -> Result<(), ConsensusError> { + match proof { + VersionedFinalityProof::V1(signed_commitment) => { + if signed_commitment.signatures.len() != validator_set.len() || + signed_commitment.commitment.validator_set_id != validator_set.id() || + signed_commitment.commitment.block_number != target_number + { + return Err(ConsensusError::InvalidJustification) + } + + // Arrangement of signatures in the commitment should be in the same order + // as validators for that set. + let message = signed_commitment.commitment.encode(); + let valid_signatures = validator_set + .validators() + .into_iter() + .zip(signed_commitment.signatures.iter()) + .filter(|(id, signature)| { + signature + .as_ref() + .map(|sig| BeefyKeystore::verify(id, sig, &message[..])) + .unwrap_or(false) + }) + .count(); + if valid_signatures >= crate::round::threshold(validator_set.len()) { + Ok(()) + } else { + Err(ConsensusError::InvalidJustification) + } + }, + } +} + +#[cfg(test)] +pub(crate) mod tests { + use beefy_primitives::{known_payload_ids, Commitment, Payload, SignedCommitment}; + use substrate_test_runtime_client::runtime::Block; + + use super::*; + use crate::{keystore::tests::Keyring, tests::make_beefy_ids}; + + pub(crate) fn new_signed_commitment( + block_num: NumberFor, + validator_set: &ValidatorSet, + keys: &[Keyring], + ) -> BeefySignedCommitment { + let commitment = Commitment { + payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + block_number: block_num, + validator_set_id: validator_set.id(), + }; + let message = commitment.encode(); + let signatures = keys.iter().map(|key| Some(key.sign(&message))).collect(); + SignedCommitment { commitment, signatures } + } + + #[test] + fn should_verify_with_validator_set() { + let keys = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + + // build valid justification + let block_num = 42; + let proof = new_signed_commitment(block_num, &validator_set, keys); + + let good_proof = proof.clone().into(); + // should verify successfully + verify_with_validator_set::(block_num, &validator_set, &good_proof).unwrap(); + + // wrong block number -> should fail verification + let good_proof = proof.clone().into(); + match verify_with_validator_set::(block_num + 1, &validator_set, &good_proof) { + Err(ConsensusError::InvalidJustification) => (), + _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), + }; + + // wrong validator set id -> should fail verification + let good_proof = proof.clone().into(); + let other = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); + match verify_with_validator_set::(block_num, &other, &good_proof) { + Err(ConsensusError::InvalidJustification) => (), + _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), + }; + + // wrong signatures length -> should fail verification + let mut bad_proof = proof.clone(); + // change length of signatures + bad_proof.signatures.pop().flatten().unwrap(); + match verify_with_validator_set::(block_num + 1, &validator_set, &bad_proof.into()) { + Err(ConsensusError::InvalidJustification) => (), + _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), + }; + + // not enough signatures -> should fail verification + let mut bad_proof = proof.clone(); + // remove a signature (but same length) + *bad_proof.signatures.first_mut().unwrap() = None; + match verify_with_validator_set::(block_num + 1, &validator_set, &bad_proof.into()) { + Err(ConsensusError::InvalidJustification) => (), + _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), + }; + + // not enough _correct_ signatures -> should fail verification + let mut bad_proof = proof.clone(); + // change a signature to a different key + *bad_proof.signatures.first_mut().unwrap() = + Some(Keyring::Dave.sign(&proof.commitment.encode())); + match verify_with_validator_set::(block_num + 1, &validator_set, &bad_proof.into()) { + Err(ConsensusError::InvalidJustification) => (), + _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), + }; + } + + #[test] + fn should_decode_and_verify_commitment() { + let keys = &[Keyring::Alice, Keyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let block_num = 1; + + // build valid justification + let proof = new_signed_commitment(block_num, &validator_set, keys); + let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); + let encoded = versioned_proof.encode(); + + // should successfully decode and verify + let verified = + decode_and_verify_commitment::(&encoded, block_num, &validator_set).unwrap(); + assert_eq!(verified, versioned_proof); + } +} diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index c025ec5686ad2..81c72dec8cd08 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -16,23 +16,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::sync::Arc; - +use beefy_primitives::{BeefyApi, MmrRootHash}; use prometheus::Registry; - use sc_client_api::{Backend, BlockchainEvents, Finalizer}; +use sc_consensus::BlockImport; use sc_network_gossip::Network as GossipNetwork; - use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; -use sp_consensus::SyncOracle; +use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_keystore::SyncCryptoStorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::Block; - -use beefy_primitives::{BeefyApi, MmrRootHash}; - -use crate::notification::{BeefyBestBlockSender, BeefySignedCommitmentSender}; +use std::sync::Arc; mod error; mod gossip; @@ -41,11 +36,21 @@ mod metrics; mod round; mod worker; +pub mod import; +pub mod justification; pub mod notification; #[cfg(test)] mod tests; +use crate::{ + import::BeefyBlockImport, + notification::{ + BeefyBestBlockSender, BeefyBestBlockStream, BeefySignedCommitmentSender, + BeefySignedCommitmentStream, + }, +}; + pub use beefy_protocol_name::standard_name as protocol_standard_name; pub(crate) mod beefy_protocol_name { @@ -110,6 +115,68 @@ where // empty } +/// Links between the block importer, the background voter and the RPC layer, +/// to be used by the voter. +#[derive(Clone)] +pub struct BeefyVoterLinks { + // BlockImport -> Voter links + /// Stream of BEEFY signed commitments from block import to voter. + pub from_block_import_justif_stream: BeefySignedCommitmentStream, + + // Voter -> RPC links + /// Sends BEEFY signed commitments from voter to RPC. + pub to_rpc_justif_sender: BeefySignedCommitmentSender, + /// Sends BEEFY best block hashes from voter to RPC. + pub to_rpc_best_block_sender: BeefyBestBlockSender, +} + +/// Links used by the BEEFY RPC layer, from the BEEFY background voter. +#[derive(Clone)] +pub struct BeefyRPCLinks { + /// Stream of signed commitments coming from the voter. + pub from_voter_justif_stream: BeefySignedCommitmentStream, + /// Stream of BEEFY best block hashes coming from the voter. + pub from_voter_best_beefy_stream: BeefyBestBlockStream, +} + +/// Make block importer and link half necessary to tie the background voter to it. +pub fn beefy_block_import_and_links( + wrapped_block_import: I, + backend: Arc, + runtime: Arc, +) -> (BeefyBlockImport, BeefyVoterLinks, BeefyRPCLinks) +where + B: Block, + BE: Backend, + I: BlockImport> + + Send + + Sync, + RuntimeApi: ProvideRuntimeApi + Send + Sync, + RuntimeApi::Api: BeefyApi, +{ + // Voter -> RPC links + let (to_rpc_justif_sender, from_voter_justif_stream) = + notification::BeefySignedCommitmentStream::::channel(); + let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = + notification::BeefyBestBlockStream::::channel(); + + // BlockImport -> Voter links + let (to_voter_justif_sender, from_block_import_justif_stream) = + notification::BeefySignedCommitmentStream::::channel(); + + // BlockImport + let import = + BeefyBlockImport::new(backend, runtime, wrapped_block_import, to_voter_justif_sender); + let voter_links = BeefyVoterLinks { + from_block_import_justif_stream, + to_rpc_justif_sender, + to_rpc_best_block_sender, + }; + let rpc_links = BeefyRPCLinks { from_voter_best_beefy_stream, from_voter_justif_stream }; + + (import, voter_links, rpc_links) +} + /// BEEFY gadget initialization parameters. pub struct BeefyParams where @@ -130,16 +197,14 @@ where pub key_store: Option, /// Gossip network pub network: N, - /// BEEFY signed commitment sender - pub signed_commitment_sender: BeefySignedCommitmentSender, - /// BEEFY best block sender - pub beefy_best_block_sender: BeefyBestBlockSender, /// Minimal delta between blocks, BEEFY should vote for pub min_block_delta: u32, /// Prometheus metric registry pub prometheus_registry: Option, /// Chain specific GRANDPA protocol name. See [`beefy_protocol_name::standard_name`]. pub protocol_name: std::borrow::Cow<'static, str>, + /// Links between the block importer, the background voter and the RPC layer. + pub links: BeefyVoterLinks, } /// Start the BEEFY gadget. @@ -160,11 +225,10 @@ where runtime, key_store, network, - signed_commitment_sender, - beefy_best_block_sender, min_block_delta, prometheus_registry, protocol_name, + links, } = beefy_params; let sync_oracle = network.clone(); @@ -194,14 +258,13 @@ where client, backend, runtime, + sync_oracle, key_store: key_store.into(), - signed_commitment_sender, - beefy_best_block_sender, gossip_engine, gossip_validator, - min_block_delta, + links, metrics, - sync_oracle, + min_block_delta, }; let worker = worker::BeefyWorker::<_, _, _, _, _>::new(worker_params); diff --git a/client/beefy/src/metrics.rs b/client/beefy/src/metrics.rs index a6d29dbf88abb..71e34e24c4fa0 100644 --- a/client/beefy/src/metrics.rs +++ b/client/beefy/src/metrics.rs @@ -32,8 +32,8 @@ pub(crate) struct Metrics { pub beefy_best_block: Gauge, /// Next block BEEFY should vote on pub beefy_should_vote_on: Gauge, - /// Number of sessions without a signed commitment - pub beefy_skipped_sessions: Counter, + /// Number of sessions with lagging signed commitment on mandatory block + pub beefy_lagging_sessions: Counter, } impl Metrics { @@ -65,10 +65,10 @@ impl Metrics { Gauge::new("substrate_beefy_should_vote_on", "Next block, BEEFY should vote on")?, registry, )?, - beefy_skipped_sessions: register( + beefy_lagging_sessions: register( Counter::new( - "substrate_beefy_skipped_sessions", - "Number of sessions without a signed commitment", + "substrate_beefy_lagging_sessions", + "Number of sessions with lagging signed commitment on mandatory block", )?, registry, )?, diff --git a/client/beefy/src/notification.rs b/client/beefy/src/notification.rs index 7c18d809f6efb..9479891714234 100644 --- a/client/beefy/src/notification.rs +++ b/client/beefy/src/notification.rs @@ -17,11 +17,9 @@ // along with this program. If not, see . use sc_utils::notification::{NotificationSender, NotificationStream, TracingKeyStr}; -use sp_runtime::traits::{Block as BlockT, NumberFor}; +use sp_runtime::traits::Block as BlockT; -/// A commitment with matching BEEFY authorities' signatures. -pub type BeefySignedCommitment = - beefy_primitives::SignedCommitment, beefy_primitives::crypto::Signature>; +use crate::justification::BeefySignedCommitment; /// The sending half of the notifications channel(s) used to send /// notifications about best BEEFY block from the gadget side. diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index fecb9557df6ea..ebd85c8dea05d 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -59,7 +59,8 @@ impl RoundTracker { } } -fn threshold(authorities: usize) -> usize { +/// Minimum size of `authorities` subset that produced valid signatures for a block to finalize. +pub fn threshold(authorities: usize) -> usize { let faulty = authorities.saturating_sub(1) / 3; authorities - faulty } @@ -70,9 +71,10 @@ fn threshold(authorities: usize) -> usize { /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). pub(crate) struct Rounds { rounds: BTreeMap<(Payload, NumberFor), RoundTracker>, - best_done: Option>, session_start: NumberFor, validator_set: ValidatorSet, + mandatory_done: bool, + best_done: Option>, } impl Rounds @@ -81,15 +83,15 @@ where B: Block, { pub(crate) fn new(session_start: NumberFor, validator_set: ValidatorSet) -> Self { - Rounds { rounds: BTreeMap::new(), best_done: None, session_start, validator_set } + Rounds { + rounds: BTreeMap::new(), + session_start, + validator_set, + mandatory_done: false, + best_done: None, + } } -} -impl Rounds -where - P: Ord + Hash + Clone, - B: Block, -{ pub(crate) fn validator_set_id(&self) -> ValidatorSetId { self.validator_set.id() } @@ -98,8 +100,12 @@ where self.validator_set.validators() } - pub(crate) fn session_start(&self) -> &NumberFor { - &self.session_start + pub(crate) fn session_start(&self) -> NumberFor { + self.session_start + } + + pub(crate) fn mandatory_done(&self) -> bool { + self.mandatory_done } pub(crate) fn should_self_vote(&self, round: &(P, NumberFor)) -> bool { @@ -113,12 +119,9 @@ where vote: (Public, Signature), self_vote: bool, ) -> bool { - if Some(round.1.clone()) <= self.best_done { - debug!( - target: "beefy", - "🥩 received vote for old stale round {:?}, ignoring", - round.1 - ); + let num = round.1; + if num < self.session_start || Some(num) <= self.best_done { + debug!(target: "beefy", "🥩 received vote for old stale round {:?}, ignoring", num); false } else if !self.validators().iter().any(|id| vote.0 == *id) { debug!( @@ -147,6 +150,7 @@ where // remove this and older (now stale) rounds let signatures = self.rounds.remove(round)?.votes; self.rounds.retain(|&(_, number), _| number > round.1); + self.mandatory_done = self.mandatory_done || round.1 == self.session_start; self.best_done = self.best_done.max(Some(round.1)); debug!(target: "beefy", "🥩 Concluded round #{}", round.1); @@ -160,6 +164,11 @@ where None } } + + #[cfg(test)] + pub(crate) fn test_set_mandatory_done(&mut self, done: bool) { + self.mandatory_done = done; + } } #[cfg(test)] @@ -226,7 +235,7 @@ mod tests { let rounds = Rounds::::new(session_start, validators); assert_eq!(42, rounds.validator_set_id()); - assert_eq!(1, *rounds.session_start()); + assert_eq!(1, rounds.session_start()); assert_eq!( &vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], rounds.validators() @@ -307,6 +316,43 @@ mod tests { )); } + #[test] + fn old_rounds_not_accepted() { + sp_tracing::try_init_simple(); + + let validators = ValidatorSet::::new( + vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + 42, + ) + .unwrap(); + let alice = (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")); + + let session_start = 10u64.into(); + let mut rounds = Rounds::::new(session_start, validators); + + let mut vote = (H256::from_low_u64_le(1), 9); + // add vote for previous session, should fail + assert!(!rounds.add_vote(&vote, alice.clone(), true)); + // no votes present + assert!(rounds.rounds.is_empty()); + + // simulate 11 was concluded + rounds.best_done = Some(11); + // add votes for current session, but already concluded rounds, should fail + vote.1 = 10; + assert!(!rounds.add_vote(&vote, alice.clone(), true)); + vote.1 = 11; + assert!(!rounds.add_vote(&vote, alice.clone(), true)); + // no votes present + assert!(rounds.rounds.is_empty()); + + // add good vote + vote.1 = 12; + assert!(rounds.add_vote(&vote, alice, true)); + // good vote present + assert_eq!(rounds.rounds.len(), 1); + } + #[test] fn multiple_rounds() { sp_tracing::try_init_simple(); diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 78e697a6ada81..9c8f443dd1f7e 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -21,12 +21,15 @@ use futures::{future, stream::FuturesUnordered, Future, StreamExt}; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; -use std::{sync::Arc, task::Poll}; +use std::{collections::HashMap, sync::Arc, task::Poll}; use tokio::{runtime::Runtime, time::Duration}; use sc_chain_spec::{ChainSpec, GenericChainSpec}; use sc_client_api::HeaderBackend; -use sc_consensus::BoxJustificationImport; +use sc_consensus::{ + BlockImport, BlockImportParams, BoxJustificationImport, ForkChoiceStrategy, ImportResult, + ImportedAux, +}; use sc_keystore::LocalKeystore; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, @@ -35,7 +38,8 @@ use sc_network_test::{ use sc_utils::notification::NotificationReceiver; use beefy_primitives::{ - crypto::AuthorityId, BeefyApi, ConsensusLog, MmrRootHash, ValidatorSet, BEEFY_ENGINE_ID, + crypto::{AuthorityId, Signature}, + BeefyApi, ConsensusLog, MmrRootHash, ValidatorSet, VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, }; use sp_mmr_primitives::{ @@ -47,19 +51,32 @@ use sp_consensus::BlockOrigin; use sp_core::H256; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ - codec::Encode, generic::BlockId, traits::Header as HeaderT, BuildStorage, DigestItem, Storage, + codec::Encode, + generic::BlockId, + traits::{Header as HeaderT, NumberFor}, + BuildStorage, DigestItem, Justifications, Storage, }; use substrate_test_runtime_client::{runtime::Header, ClientExt}; -use crate::{beefy_protocol_name, keystore::tests::Keyring as BeefyKeyring, notification::*}; +use crate::{ + beefy_block_import_and_links, beefy_protocol_name, justification::*, + keystore::tests::Keyring as BeefyKeyring, BeefyRPCLinks, BeefyVoterLinks, +}; pub(crate) const BEEFY_PROTOCOL_NAME: &'static str = "/beefy/1"; const GOOD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0xbf); const BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x42); +type BeefyBlockImport = crate::BeefyBlockImport< + Block, + substrate_test_runtime_client::Backend, + two_validators::TestApi, + BlockImportAdapter>, +>; + pub(crate) type BeefyValidatorSet = ValidatorSet; -pub(crate) type BeefyPeer = Peer; +pub(crate) type BeefyPeer = Peer; #[derive(Debug, Serialize, Deserialize)] struct Genesis(std::collections::BTreeMap); @@ -97,17 +114,10 @@ fn beefy_protocol_name() { assert_eq!(proto_name.to_string(), expected); } -// TODO: compiler warns us about unused `signed_commitment_stream`, will use in later tests -#[allow(dead_code)] -#[derive(Clone)] -pub(crate) struct BeefyLinkHalf { - pub signed_commitment_stream: BeefySignedCommitmentStream, - pub beefy_best_block_stream: BeefyBestBlockStream, -} - #[derive(Default)] pub(crate) struct PeerData { - pub(crate) beefy_link_half: Mutex>, + pub(crate) beefy_rpc_links: Mutex>>, + pub(crate) beefy_voter_links: Mutex>>, } #[derive(Default)] @@ -163,7 +173,7 @@ impl BeefyTestNet { impl TestNetFactory for BeefyTestNet { type Verifier = PassThroughVerifier; - type BlockImport = PeersClient; + type BlockImport = BeefyBlockImport; type PeerData = PeerData; fn make_verifier(&self, _client: PeersClient, _: &PeerData) -> Self::Verifier { @@ -178,7 +188,17 @@ impl TestNetFactory for BeefyTestNet { Option>, Self::PeerData, ) { - (client.as_block_import(), None, PeerData::default()) + let inner = BlockImportAdapter::new(client.clone()); + let (block_import, voter_links, rpc_links) = beefy_block_import_and_links( + inner, + client.as_backend(), + Arc::new(two_validators::TestApi {}), + ); + let peer_data = PeerData { + beefy_rpc_links: Mutex::new(Some(rpc_links)), + beefy_voter_links: Mutex::new(Some(voter_links)), + }; + (BlockImportAdapter::new(block_import), None, peer_data) } fn peer(&mut self, i: usize) -> &mut BeefyPeer { @@ -333,12 +353,12 @@ where let keystore = create_beefy_keystore(*key); - let (signed_commitment_sender, signed_commitment_stream) = - BeefySignedCommitmentStream::::channel(); - let (beefy_best_block_sender, beefy_best_block_stream) = - BeefyBestBlockStream::::channel(); - let beefy_link_half = BeefyLinkHalf { signed_commitment_stream, beefy_best_block_stream }; - *peer.data.beefy_link_half.lock() = Some(beefy_link_half); + let (_, _, peer_data) = net.make_block_import(peer.client().clone()); + let PeerData { beefy_rpc_links, beefy_voter_links } = peer_data; + + let beefy_voter_links = beefy_voter_links.lock().take(); + *peer.data.beefy_rpc_links.lock() = beefy_rpc_links.lock().take(); + *peer.data.beefy_voter_links.lock() = beefy_voter_links.clone(); let beefy_params = crate::BeefyParams { client: peer.client().as_client(), @@ -346,8 +366,7 @@ where runtime: api.clone(), key_store: Some(keystore), network: peer.network_service().clone(), - signed_commitment_sender, - beefy_best_block_sender, + links: beefy_voter_links.unwrap(), min_block_delta, prometheus_registry: None, protocol_name: BEEFY_PROTOCOL_NAME.into(), @@ -382,11 +401,11 @@ pub(crate) fn get_beefy_streams( let mut best_block_streams = Vec::new(); let mut signed_commitment_streams = Vec::new(); for peer_id in 0..peers.len() { - let beefy_link_half = - net.peer(peer_id).data.beefy_link_half.lock().as_ref().unwrap().clone(); - let BeefyLinkHalf { signed_commitment_stream, beefy_best_block_stream } = beefy_link_half; - best_block_streams.push(beefy_best_block_stream.subscribe()); - signed_commitment_streams.push(signed_commitment_stream.subscribe()); + let beefy_rpc_links = net.peer(peer_id).data.beefy_rpc_links.lock().clone().unwrap(); + let BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream } = + beefy_rpc_links; + best_block_streams.push(from_voter_best_beefy_stream.subscribe()); + signed_commitment_streams.push(from_voter_justif_stream.subscribe()); } (best_block_streams, signed_commitment_streams) } @@ -670,3 +689,123 @@ fn correct_beefy_payload() { wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[11]); wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[11]); } + +#[test] +fn beefy_importing_blocks() { + use futures::{executor::block_on, future::poll_fn, task::Poll}; + use sc_block_builder::BlockBuilderProvider; + use sc_client_api::BlockBackend; + + sp_tracing::try_init_simple(); + + let mut net = BeefyTestNet::new(2, 0); + + let client = net.peer(0).client().clone(); + let (mut block_import, _, peer_data) = net.make_block_import(client.clone()); + let PeerData { beefy_rpc_links: _, beefy_voter_links } = peer_data; + let justif_stream = beefy_voter_links.lock().take().unwrap().from_block_import_justif_stream; + + let params = |block: Block, justifications: Option| { + let mut import = BlockImportParams::new(BlockOrigin::File, block.header); + import.justifications = justifications; + import.body = Some(block.extrinsics); + import.finalized = true; + import.fork_choice = Some(ForkChoiceStrategy::LongestChain); + import + }; + + let full_client = client.as_client(); + let parent_id = BlockId::Number(0); + let block_id = BlockId::Number(1); + let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); + let block = builder.build().unwrap().block; + + // Import without justifications. + let mut justif_recv = justif_stream.subscribe(); + assert_eq!( + block_on(block_import.import_block(params(block.clone(), None), HashMap::new())).unwrap(), + ImportResult::Imported(ImportedAux { is_new_best: true, ..Default::default() }), + ); + assert_eq!( + block_on(block_import.import_block(params(block, None), HashMap::new())).unwrap(), + ImportResult::AlreadyInChain + ); + // Verify no justifications present: + { + // none in backend, + assert!(full_client.justifications(&block_id).unwrap().is_none()); + // and none sent to BEEFY worker. + block_on(poll_fn(move |cx| { + assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); + Poll::Ready(()) + })); + } + + // Import with valid justification. + let parent_id = BlockId::Number(1); + let block_num = 2; + let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let proof = crate::justification::tests::new_signed_commitment(block_num, &validator_set, keys); + let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); + let encoded = versioned_proof.encode(); + let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); + + let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); + let block = builder.build().unwrap().block; + let mut justif_recv = justif_stream.subscribe(); + assert_eq!( + block_on(block_import.import_block(params(block, justif), HashMap::new())).unwrap(), + ImportResult::Imported(ImportedAux { + bad_justification: false, + is_new_best: true, + ..Default::default() + }), + ); + // Verify justification successfully imported: + { + // available in backend, + assert!(full_client.justifications(&BlockId::Number(block_num)).unwrap().is_some()); + // and also sent to BEEFY worker. + block_on(poll_fn(move |cx| { + match justif_recv.poll_next_unpin(cx) { + Poll::Ready(Some(_justification)) => (), + v => panic!("unexpected value: {:?}", v), + } + Poll::Ready(()) + })); + } + + // Import with invalid justification (incorrect validator set). + let parent_id = BlockId::Number(2); + let block_num = 3; + let keys = &[BeefyKeyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); + let proof = crate::justification::tests::new_signed_commitment(block_num, &validator_set, keys); + let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); + let encoded = versioned_proof.encode(); + let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); + + let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); + let block = builder.build().unwrap().block; + let mut justif_recv = justif_stream.subscribe(); + assert_eq!( + block_on(block_import.import_block(params(block, justif), HashMap::new())).unwrap(), + ImportResult::Imported(ImportedAux { + // Still `false` because we don't want to fail import on bad BEEFY justifications. + bad_justification: false, + is_new_best: true, + ..Default::default() + }), + ); + // Verify bad justifications was not imported: + { + // none in backend, + assert!(full_client.justifications(&block_id).unwrap().is_none()); + // and none sent to BEEFY worker. + block_on(poll_fn(move |cx| { + assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); + Poll::Ready(()) + })); + } +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index dccf7ba7504dd..3bff0822ebdb4 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -17,11 +17,10 @@ // along with this program. If not, see . use std::{ - collections::{BTreeMap, BTreeSet}, + collections::{BTreeMap, BTreeSet, VecDeque}, fmt::Debug, marker::PhantomData, sync::Arc, - time::Duration, }; use codec::{Codec, Decode, Encode}; @@ -48,57 +47,174 @@ use beefy_primitives::{ }; use crate::{ - error, + error::Error, gossip::{topic, GossipValidator}, + justification::BeefySignedCommitment, keystore::BeefyKeystore, metric_inc, metric_set, metrics::Metrics, - notification::{BeefyBestBlockSender, BeefySignedCommitmentSender}, round::Rounds, - Client, + BeefyVoterLinks, Client, }; +enum RoundAction { + Drop, + Process, + Enqueue, +} + +/// Responsible for the voting strategy. +/// It chooses which incoming votes to accept and which votes to generate. +struct VoterOracle { + /// Queue of known sessions. Keeps track of voting rounds (block numbers) within each session. + /// + /// There are three voter states coresponding to three queue states: + /// 1. voter uninitialized: queue empty, + /// 2. up-to-date - all mandatory blocks leading up to current GRANDPA finalized: + /// queue has ONE element, the 'current session' where `mandatory_done == true`, + /// 3. lagging behind GRANDPA: queue has [1, N] elements, where all `mandatory_done == false`. + /// In this state, everytime a session gets its mandatory block BEEFY finalized, it's + /// popped off the queue, eventually getting to state `2. up-to-date`. + sessions: VecDeque>, + /// Min delta in block numbers between two blocks, BEEFY should vote on. + min_block_delta: u32, +} + +impl VoterOracle { + pub fn new(min_block_delta: u32) -> Self { + Self { + sessions: VecDeque::new(), + // Always target at least one block better than current best beefy. + min_block_delta: min_block_delta.max(1), + } + } + + /// Return mutable reference to rounds pertaining to first session in the queue. + /// Voting will always happen at the head of the queue. + pub fn rounds_mut(&mut self) -> Option<&mut Rounds> { + self.sessions.front_mut() + } + + /// Add new observed session to the Oracle. + pub fn add_session(&mut self, rounds: Rounds) { + self.sessions.push_back(rounds); + self.try_prune(); + } + + /// Prune the queue to keep the Oracle in one of the expected three states. + /// + /// Call this function on each BEEFY finality, + /// or at the very least on each BEEFY mandatory block finality. + pub fn try_prune(&mut self) { + if self.sessions.len() > 1 { + // when there's multiple sessions, only keep the `!mandatory_done()` ones. + self.sessions.retain(|s| !s.mandatory_done()) + } + } + + /// Return `(A, B)` tuple representing inclusive [A, B] interval of votes to accept. + pub fn accepted_interval( + &self, + best_grandpa: NumberFor, + ) -> Result<(NumberFor, NumberFor), Error> { + let rounds = self.sessions.front().ok_or(Error::UninitSession)?; + + if rounds.mandatory_done() { + // There's only one session active and its mandatory is done. + // Accept any GRANDPA finalized vote. + Ok((rounds.session_start(), best_grandpa.into())) + } else { + // There's at least one session with mandatory not done. + // Only accept votes for the mandatory block in the front of queue. + Ok((rounds.session_start(), rounds.session_start())) + } + } + + /// Utility function to quickly decide what to do for each round. + pub fn triage_round( + &self, + round: NumberFor, + best_grandpa: NumberFor, + ) -> Result { + let (start, end) = self.accepted_interval(best_grandpa)?; + if start <= round && round <= end { + Ok(RoundAction::Process) + } else if round > end { + Ok(RoundAction::Enqueue) + } else { + Ok(RoundAction::Drop) + } + } + + /// Return `Some(number)` if we should be voting on block `number`, + /// return `None` if there is no block we should vote on. + pub fn voting_target( + &self, + best_beefy: Option>, + best_grandpa: NumberFor, + ) -> Option> { + let rounds = if let Some(r) = self.sessions.front() { + r + } else { + debug!(target: "beefy", "🥩 No voting round started"); + return None + }; + + // `target` is guaranteed > `best_beefy` since `min_block_delta` is at least `1`. + let target = + vote_target(best_grandpa, best_beefy, rounds.session_start(), self.min_block_delta); + trace!( + target: "beefy", + "🥩 best beefy: #{:?}, best finalized: #{:?}, current_vote_target: {:?}", + best_beefy, + best_grandpa, + target + ); + target + } +} + pub(crate) struct WorkerParams { pub client: Arc, pub backend: Arc, pub runtime: Arc, + pub sync_oracle: SO, pub key_store: BeefyKeystore, - pub signed_commitment_sender: BeefySignedCommitmentSender, - pub beefy_best_block_sender: BeefyBestBlockSender, pub gossip_engine: GossipEngine, pub gossip_validator: Arc>, - pub min_block_delta: u32, + pub links: BeefyVoterLinks, pub metrics: Option, - pub sync_oracle: SO, + pub min_block_delta: u32, } /// A BEEFY worker plays the BEEFY protocol pub(crate) struct BeefyWorker { + // utilities client: Arc, backend: Arc, runtime: Arc, + sync_oracle: SO, key_store: BeefyKeystore, - signed_commitment_sender: BeefySignedCommitmentSender, gossip_engine: GossipEngine, gossip_validator: Arc>, - /// Min delta in block numbers between two blocks, BEEFY should vote on - min_block_delta: u32, + + // channels + /// Links between the block importer, the background voter and the RPC layer. + links: BeefyVoterLinks, + + // voter state + /// BEEFY client metrics. metrics: Option, - rounds: Option>, - /// Buffer holding votes for blocks that the client hasn't seen finality for. - pending_votes: BTreeMap, Vec, AuthorityId, Signature>>>, - /// Best block we received a GRANDPA notification for + /// Best block we received a GRANDPA finality for. best_grandpa_block_header: ::Header, - /// Best block a BEEFY voting round has been concluded for + /// Best block a BEEFY voting round has been concluded for. best_beefy_block: Option>, - /// Used to keep RPC worker up to date on latest/best beefy - beefy_best_block_sender: BeefyBestBlockSender, - /// Validator set id for the last signed commitment - last_signed_id: u64, - /// Handle to the sync oracle - sync_oracle: SO, - // keep rustc happy - _backend: PhantomData, + /// Buffer holding votes for future processing. + pending_votes: BTreeMap, Vec, AuthorityId, Signature>>>, + /// Buffer holding justifications for future processing. + pending_justifications: BTreeMap, Vec>>, + /// Chooses which incoming votes to accept and which votes to generate. + voting_oracle: VoterOracle, } impl BeefyWorker @@ -122,13 +238,12 @@ where backend, runtime, key_store, - signed_commitment_sender, - beefy_best_block_sender, + sync_oracle, gossip_engine, gossip_validator, - min_block_delta, + links, metrics, - sync_oracle, + min_block_delta, } = worker_params; let last_finalized_header = client @@ -139,53 +254,29 @@ where client: client.clone(), backend, runtime, + sync_oracle, key_store, - signed_commitment_sender, gossip_engine, gossip_validator, - // always target at least one block better than current best beefy - min_block_delta: min_block_delta.max(1), + links, metrics, - rounds: None, - pending_votes: BTreeMap::new(), best_grandpa_block_header: last_finalized_header, best_beefy_block: None, - last_signed_id: 0, - beefy_best_block_sender, - sync_oracle, - _backend: PhantomData, + pending_votes: BTreeMap::new(), + pending_justifications: BTreeMap::new(), + voting_oracle: VoterOracle::new(min_block_delta), } } - /// Return `Some(number)` if we should be voting on block `number` now, - /// return `None` if there is no block we should vote on now. - fn current_vote_target(&self) -> Option> { - let rounds = if let Some(r) = &self.rounds { - r - } else { - debug!(target: "beefy", "🥩 No voting round started"); - return None - }; - - let best_finalized = *self.best_grandpa_block_header.number(); - // `target` is guaranteed > `best_beefy` since `min_block_delta` is at least `1`. - let target = vote_target( - best_finalized, - self.best_beefy_block, - *rounds.session_start(), - self.min_block_delta, - ); - trace!( - target: "beefy", - "🥩 best beefy: #{:?}, best finalized: #{:?}, current_vote_target: {:?}", - self.best_beefy_block, - best_finalized, - target - ); - if let Some(target) = &target { - metric_set!(self, beefy_should_vote_on, target); - } - target + /// Simple wrapper that gets MMR root from header digests or from client state. + fn get_mmr_root_digest(&self, header: &B::Header) -> Option { + find_mmr_root_digest::(header).or_else(|| { + self.runtime + .runtime_api() + .mmr_root(&BlockId::hash(header.hash())) + .ok() + .and_then(|r| r.ok()) + }) } /// Verify `active` validator set for `block` against the key store @@ -200,7 +291,7 @@ where &self, block: &NumberFor, active: &ValidatorSet, - ) -> Result<(), error::Error> { + ) -> Result<(), Error> { let active: BTreeSet<&AuthorityId> = active.validators().iter().collect(); let public_keys = self.key_store.public_keys()?; @@ -209,121 +300,100 @@ where if store.intersection(&active).count() == 0 { let msg = "no authority public key found in store".to_string(); debug!(target: "beefy", "🥩 for block {:?} {}", block, msg); - Err(error::Error::Keystore(msg)) + Err(Error::Keystore(msg)) } else { Ok(()) } } - /// Set best BEEFY block to `block_num`. - /// - /// Also sends/updates the best BEEFY block hash to the RPC worker. - fn set_best_beefy_block(&mut self, block_num: NumberFor) { - if Some(block_num) > self.best_beefy_block { - // Try to get block hash ourselves. - let block_hash = match self.client.hash(block_num) { - Ok(h) => h, - Err(e) => { - error!(target: "beefy", "🥩 Failed to get hash for block number {}: {}", - block_num, e); - None - }, - }; - // Update RPC worker with new best BEEFY block hash. - block_hash.map(|hash| { - self.beefy_best_block_sender - .notify(|| Ok::<_, ()>(hash)) - .expect("forwards closure result; the closure always returns Ok; qed.") - }); - // Set new best BEEFY block number. - self.best_beefy_block = Some(block_num); - metric_set!(self, beefy_best_block, block_num); - } else { - debug!(target: "beefy", "🥩 Can't set best beefy to older: {}", block_num); - } - } - /// Handle session changes by starting new voting round for mandatory blocks. fn init_session_at( &mut self, - active: ValidatorSet, + validator_set: ValidatorSet, new_session_start: NumberFor, ) { - debug!(target: "beefy", "🥩 New active validator set: {:?}", active); - metric_set!(self, beefy_validator_set_id, active.id()); - // BEEFY should produce a signed commitment for each session - if active.id() != self.last_signed_id + 1 && - active.id() != GENESIS_AUTHORITY_SET_ID && - self.last_signed_id != 0 - { - debug!( - target: "beefy", "🥩 Detected skipped session: active-id {:?}, last-signed-id {:?}", - active.id(), - self.last_signed_id, - ); - metric_inc!(self, beefy_skipped_sessions); + debug!(target: "beefy", "🥩 New active validator set: {:?}", validator_set); + metric_set!(self, beefy_validator_set_id, validator_set.id()); + + // BEEFY should produce the mandatory block of each session. + if let Some(active_session) = self.voting_oracle.rounds_mut() { + if !active_session.mandatory_done() { + debug!( + target: "beefy", "🥩 New session {} while active session {} is still lagging.", + validator_set.id(), + active_session.validator_set_id(), + ); + metric_inc!(self, beefy_lagging_sessions); + } } if log_enabled!(target: "beefy", log::Level::Debug) { // verify the new validator set - only do it if we're also logging the warning - let _ = self.verify_validator_set(&new_session_start, &active); + let _ = self.verify_validator_set(&new_session_start, &validator_set); } - let id = active.id(); - self.rounds = Some(Rounds::new(new_session_start, active)); + let id = validator_set.id(); + self.voting_oracle.add_session(Rounds::new(new_session_start, validator_set)); info!(target: "beefy", "🥩 New Rounds for validator set id: {:?} with session_start {:?}", id, new_session_start); } fn handle_finality_notification(&mut self, notification: &FinalityNotification) { debug!(target: "beefy", "🥩 Finality notification: {:?}", notification); - let number = *notification.header.number(); - - // On start-up ignore old finality notifications that we're not interested in. - if number <= *self.best_grandpa_block_header.number() { - debug!(target: "beefy", "🥩 Got unexpected finality for old block #{:?}", number); - return - } + let header = ¬ification.header; - // update best GRANDPA finalized block we have seen - self.best_grandpa_block_header = notification.header.clone(); + if *header.number() > *self.best_grandpa_block_header.number() { + // update best GRANDPA finalized block we have seen + self.best_grandpa_block_header = header.clone(); - self.handle_finality(¬ification.header); - } - - fn handle_finality(&mut self, header: &B::Header) { - // Check for and handle potential new session. - if let Some(new_validator_set) = find_authorities_change::(header) { - self.init_session_at(new_validator_set, *header.number()); + // Check for and enqueue potential new session. + if let Some(new_validator_set) = find_authorities_change::(header) { + self.init_session_at(new_validator_set, *header.number()); + // TODO: when adding SYNC protocol, fire up a request for justification for this + // mandatory block here. + } } + } - // Handle any pending votes for now finalized blocks. - self.check_pending_votes(); - - // Vote if there's now a new vote target. - if let Some(target_number) = self.current_vote_target() { - self.do_vote(target_number); - } + /// Based on [VoterOracle] this vote is either processed here or enqueued for later. + fn triage_incoming_vote( + &mut self, + vote: VoteMessage, AuthorityId, Signature>, + ) -> Result<(), Error> { + let block_num = vote.commitment.block_number; + let best_grandpa = *self.best_grandpa_block_header.number(); + match self.voting_oracle.triage_round(block_num, best_grandpa)? { + RoundAction::Process => self.handle_vote( + (vote.commitment.payload, vote.commitment.block_number), + (vote.id, vote.signature), + false, + )?, + RoundAction::Enqueue => { + debug!(target: "beefy", "🥩 Buffer vote for round: {:?}.", block_num); + self.pending_votes.entry(block_num).or_default().push(vote) + }, + RoundAction::Drop => (), + }; + Ok(()) } - // Handles all buffered votes for now finalized blocks. - fn check_pending_votes(&mut self) { - let not_finalized = self.best_grandpa_block_header.number().saturating_add(1u32.into()); - let still_pending = self.pending_votes.split_off(¬_finalized); - let votes_to_handle = std::mem::replace(&mut self.pending_votes, still_pending); - for (num, votes) in votes_to_handle.into_iter() { - if Some(num) > self.best_beefy_block { - debug!(target: "beefy", "🥩 Handling buffered votes for now GRANDPA finalized block: {:?}.", num); - for v in votes.into_iter() { - self.handle_vote( - (v.commitment.payload, v.commitment.block_number), - (v.id, v.signature), - false, - ); - } - } else { - debug!(target: "beefy", "🥩 Dropping outdated buffered votes for now BEEFY finalized block: {:?}.", num); - } - } + /// Based on [VoterOracle] this justification is either processed here or enqueued for later. + /// + /// Expects `justification` to be valid. + fn triage_incoming_justif( + &mut self, + justification: BeefySignedCommitment, + ) -> Result<(), Error> { + let block_num = justification.commitment.block_number; + let best_grandpa = *self.best_grandpa_block_header.number(); + match self.voting_oracle.triage_round(block_num, best_grandpa)? { + RoundAction::Process => self.finalize(justification), + RoundAction::Enqueue => { + debug!(target: "beefy", "🥩 Buffer justification for round: {:?}.", block_num); + self.pending_justifications.entry(block_num).or_default().push(justification) + }, + RoundAction::Drop => (), + }; + Ok(()) } fn handle_vote( @@ -331,28 +401,20 @@ where round: (Payload, NumberFor), vote: (AuthorityId, Signature), self_vote: bool, - ) { + ) -> Result<(), Error> { self.gossip_validator.note_round(round.1); - let rounds = if let Some(rounds) = self.rounds.as_mut() { - rounds - } else { - debug!(target: "beefy", "🥩 Missing validator set - can't handle vote {:?}", vote); - return - }; + let rounds = self.voting_oracle.rounds_mut().ok_or(Error::UninitSession)?; if rounds.add_vote(&round, vote, self_vote) { if let Some(signatures) = rounds.try_conclude(&round) { self.gossip_validator.conclude_round(round.1); - // id is stored for skipped session metric calculation - self.last_signed_id = rounds.validator_set_id(); - let block_num = round.1; let commitment = Commitment { payload: round.0, block_number: block_num, - validator_set_id: self.last_signed_id, + validator_set_id: rounds.validator_set_id(), }; let signed_commitment = SignedCommitment { commitment, signatures }; @@ -370,24 +432,115 @@ where ) { debug!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, signed_commitment); } - self.signed_commitment_sender - .notify(|| Ok::<_, ()>(signed_commitment)) - .expect("forwards closure result; the closure always returns Ok; qed."); - self.set_best_beefy_block(block_num); + // We created the `signed_commitment` and know to be valid. + self.finalize(signed_commitment); + } + } + Ok(()) + } + + /// Provide BEEFY finality for block based on `signed_commitment`: + /// 1. Prune irrelevant past sessions from the oracle, + /// 2. Set BEEFY best block, + /// 3. Send best block hash and `signed_commitment` to RPC worker. + /// + /// Expects `signed commitment` to be valid. + fn finalize(&mut self, signed_commitment: BeefySignedCommitment) { + // Prune any now "finalized" sessions from queue. + self.voting_oracle.try_prune(); - // Vote if there's now a new vote target. - if let Some(target_number) = self.current_vote_target() { - self.do_vote(target_number); + let block_num = signed_commitment.commitment.block_number; + if Some(block_num) > self.best_beefy_block { + // Set new best BEEFY block number. + self.best_beefy_block = Some(block_num); + metric_set!(self, beefy_best_block, block_num); + + self.client.hash(block_num).ok().flatten().map(|hash| { + self.links + .to_rpc_best_block_sender + .notify(|| Ok::<_, ()>(hash)) + .expect("forwards closure result; the closure always returns Ok; qed.") + }); + + self.links + .to_rpc_justif_sender + .notify(|| Ok::<_, ()>(signed_commitment)) + .expect("forwards closure result; the closure always returns Ok; qed."); + } else { + debug!(target: "beefy", "🥩 Can't set best beefy to older: {}", block_num); + } + } + + /// Handle previously buffered justifications and votes that now land in the voting interval. + fn try_pending_justif_and_votes(&mut self) -> Result<(), Error> { + let best_grandpa = *self.best_grandpa_block_header.number(); + let _ph = PhantomData::::default(); + + fn to_process_for( + pending: &mut BTreeMap, Vec>, + (start, end): (NumberFor, NumberFor), + _: PhantomData, + ) -> BTreeMap, Vec> { + // These are still pending. + let still_pending = pending.split_off(&end.saturating_add(1u32.into())); + // These can be processed. + let to_handle = pending.split_off(&start); + // The rest can be dropped. + *pending = still_pending; + // Return ones to process. + to_handle + } + + // Process pending justifications. + let interval = self.voting_oracle.accepted_interval(best_grandpa)?; + if !self.pending_justifications.is_empty() { + let justifs_to_handle = to_process_for(&mut self.pending_justifications, interval, _ph); + for (num, justifications) in justifs_to_handle.into_iter() { + debug!(target: "beefy", "🥩 Handle buffered justifications for: {:?}.", num); + for justif in justifications.into_iter() { + self.finalize(justif); } } } + + // Process pending votes. + let interval = self.voting_oracle.accepted_interval(best_grandpa)?; + if !self.pending_votes.is_empty() { + let votes_to_handle = to_process_for(&mut self.pending_votes, interval, _ph); + for (num, votes) in votes_to_handle.into_iter() { + debug!(target: "beefy", "🥩 Handle buffered votes for: {:?}.", num); + for v in votes.into_iter() { + if let Err(err) = self.handle_vote( + (v.commitment.payload, v.commitment.block_number), + (v.id, v.signature), + false, + ) { + error!(target: "beefy", "🥩 Error handling buffered vote: {}", err); + }; + } + } + } + Ok(()) + } + + /// Decide if should vote, then vote.. or don't.. + fn try_to_vote(&mut self) -> Result<(), Error> { + // Vote if there's now a new vote target. + if let Some(target) = self + .voting_oracle + .voting_target(self.best_beefy_block, *self.best_grandpa_block_header.number()) + { + metric_set!(self, beefy_should_vote_on, target); + self.do_vote(target)?; + } + Ok(()) } /// Create and gossip Signed Commitment for block number `target_number`. /// /// Also handle this self vote by calling `self.handle_vote()` for it. - fn do_vote(&mut self, target_number: NumberFor) { + fn do_vote(&mut self, target_number: NumberFor) -> Result<(), Error> { debug!(target: "beefy", "🥩 Try voting on {}", target_number); // Most of the time we get here, `target` is actually `best_grandpa`, @@ -395,18 +548,13 @@ where let target_header = if target_number == *self.best_grandpa_block_header.number() { self.best_grandpa_block_header.clone() } else { - match self.client.expect_header(BlockId::Number(target_number)) { - Ok(h) => h, - Err(err) => { - debug!( - target: "beefy", - "🥩 Could not get header for block #{:?} (error: {:?}), skipping vote..", - target_number, - err - ); - return - }, - } + self.client.expect_header(BlockId::Number(target_number)).map_err(|err| { + let err_msg = format!( + "Couldn't get header for block #{:?} (error: {:?}), skipping vote..", + target_number, err + ); + Error::Backend(err_msg) + })? }; let target_hash = target_header.hash(); @@ -414,26 +562,23 @@ where hash } else { warn!(target: "beefy", "🥩 No MMR root digest found for: {:?}", target_hash); - return + return Ok(()) }; let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, mmr_root.encode()); - let (validators, validator_set_id) = if let Some(rounds) = &self.rounds { - if !rounds.should_self_vote(&(payload.clone(), target_number)) { - debug!(target: "beefy", "🥩 Don't double vote for block number: {:?}", target_number); - return - } - (rounds.validators(), rounds.validator_set_id()) - } else { - debug!(target: "beefy", "🥩 Missing validator set - can't vote for: {:?}", target_hash); - return - }; + let rounds = self.voting_oracle.rounds_mut().ok_or(Error::UninitSession)?; + if !rounds.should_self_vote(&(payload.clone(), target_number)) { + debug!(target: "beefy", "🥩 Don't double vote for block number: {:?}", target_number); + return Ok(()) + } + let (validators, validator_set_id) = (rounds.validators(), rounds.validator_set_id()); + let authority_id = if let Some(id) = self.key_store.authority_id(validators) { debug!(target: "beefy", "🥩 Local authority id: {:?}", id); id } else { debug!(target: "beefy", "🥩 Missing validator id - can't vote for: {:?}", target_hash); - return + return Ok(()) }; let commitment = Commitment { payload, block_number: target_number, validator_set_id }; @@ -443,7 +588,7 @@ where Ok(sig) => sig, Err(err) => { warn!(target: "beefy", "🥩 Error signing commitment: {:?}", err); - return + return Ok(()) }, }; @@ -462,13 +607,17 @@ where debug!(target: "beefy", "🥩 Sent vote message: {:?}", message); - self.handle_vote( + if let Err(err) = self.handle_vote( (message.commitment.payload, message.commitment.block_number), (message.id, message.signature), true, - ); + ) { + error!(target: "beefy", "🥩 Error handling self vote: {}", err); + } self.gossip_engine.gossip_message(topic::(), encoded_message, false); + + Ok(()) } /// Wait for BEEFY runtime pallet to be available. @@ -494,6 +643,9 @@ where // Once we'll implement 'initial sync' (catch-up), the worker will be able to // start voting right away. self.handle_finality_notification(¬if); + if let Err(err) = self.try_to_vote() { + debug!(target: "beefy", "🥩 {}", err); + } break } else { trace!(target: "beefy", "🥩 Finality notification: {:?}", notif); @@ -529,15 +681,14 @@ where }) .fuse(), ); + let mut block_import_justif = self.links.from_block_import_justif_stream.subscribe().fuse(); loop { - while self.sync_oracle.is_major_syncing() { - debug!(target: "beefy", "Waiting for major sync to complete..."); - futures_timer::Delay::new(Duration::from_secs(5)).await; - } - let mut gossip_engine = &mut self.gossip_engine; - futures::select! { + // Wait for, and handle external events. + // The branches below only change 'state', actual voting happen afterwards, + // based on the new resulting 'state'. + futures::select_biased! { notification = finality_notifications.next() => { if let Some(notification) = notification { self.handle_finality_notification(¬ification); @@ -545,24 +696,24 @@ where return; } }, + // TODO: when adding SYNC protocol, join the on-demand justifications stream to + // this one, and handle them both here. + justif = block_import_justif.next() => { + if let Some(justif) = justif { + // Block import justifications have already been verified to be valid + // by `BeefyBlockImport`. + if let Err(err) = self.triage_incoming_justif(justif) { + debug!(target: "beefy", "🥩 {}", err); + } + } else { + return; + } + }, vote = votes.next() => { if let Some(vote) = vote { - let block_num = vote.commitment.block_number; - if block_num > *self.best_grandpa_block_header.number() { - // Only handle votes for blocks we _know_ have been finalized. - // Buffer vote to be handled later. - debug!( - target: "beefy", - "🥩 Buffering vote for not (yet) finalized block: {:?}.", - block_num - ); - self.pending_votes.entry(block_num).or_default().push(vote); - } else { - self.handle_vote( - (vote.commitment.payload, vote.commitment.block_number), - (vote.id, vote.signature), - false - ); + // Votes have already been verified to be valid by the gossip validator. + if let Err(err) = self.triage_incoming_vote(vote) { + debug!(target: "beefy", "🥩 {}", err); } } else { return; @@ -573,18 +724,20 @@ where return; } } - } - } - /// Simple wrapper that gets MMR root from header digests or from client state. - fn get_mmr_root_digest(&self, header: &B::Header) -> Option { - find_mmr_root_digest::(header).or_else(|| { - self.runtime - .runtime_api() - .mmr_root(&BlockId::hash(header.hash())) - .ok() - .and_then(|r| r.ok()) - }) + // Don't bother acting on 'state' changes during major sync. + if !self.sync_oracle.is_major_syncing() { + // Handle pending justifications and/or votes for now GRANDPA finalized blocks. + if let Err(err) = self.try_pending_justif_and_votes() { + debug!(target: "beefy", "🥩 {}", err); + } + + // There were external events, 'state' is changed, author a vote if needed/possible. + if let Err(err) = self.try_to_vote() { + debug!(target: "beefy", "🥩 {}", err); + } + } + } } } @@ -684,11 +837,11 @@ pub(crate) mod tests { create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi, BeefyPeer, BeefyTestNet, BEEFY_PROTOCOL_NAME, }, + BeefyRPCLinks, }; use futures::{executor::block_on, future::poll_fn, task::Poll}; - use crate::tests::BeefyLinkHalf; use sc_client_api::HeaderBackend; use sc_network::NetworkService; use sc_network_test::{PeersFullClient, TestNetFactory}; @@ -705,12 +858,21 @@ pub(crate) mod tests { ) -> BeefyWorker>> { let keystore = create_beefy_keystore(*key); - let (signed_commitment_sender, signed_commitment_stream) = + let (to_rpc_justif_sender, from_voter_justif_stream) = BeefySignedCommitmentStream::::channel(); - let (beefy_best_block_sender, beefy_best_block_stream) = + let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = BeefyBestBlockStream::::channel(); - let beefy_link_half = BeefyLinkHalf { signed_commitment_stream, beefy_best_block_stream }; - *peer.data.beefy_link_half.lock() = Some(beefy_link_half); + let (_, from_block_import_justif_stream) = BeefySignedCommitmentStream::::channel(); + + let beefy_rpc_links = + BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream }; + *peer.data.beefy_rpc_links.lock() = Some(beefy_rpc_links); + + let links = BeefyVoterLinks { + from_block_import_justif_stream, + to_rpc_justif_sender, + to_rpc_best_block_sender, + }; let api = Arc::new(TestApi {}); let network = peer.network_service().clone(); @@ -723,8 +885,7 @@ pub(crate) mod tests { backend: peer.client().as_backend(), runtime: api, key_store: Some(keystore).into(), - signed_commitment_sender, - beefy_best_block_sender, + links, gossip_engine, gossip_validator, min_block_delta, @@ -826,6 +987,107 @@ pub(crate) mod tests { assert_eq!(Some(1072), t); } + #[test] + fn should_vote_target() { + let mut oracle = VoterOracle::::new(1); + + // rounds not initialized -> should vote: `None` + assert_eq!(oracle.voting_target(None, 1), None); + + let keys = &[Keyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + + oracle.add_session(Rounds::new(1, validator_set.clone())); + + // under min delta + oracle.min_block_delta = 4; + assert_eq!(oracle.voting_target(Some(1), 1), None); + assert_eq!(oracle.voting_target(Some(2), 5), None); + + // vote on min delta + assert_eq!(oracle.voting_target(Some(4), 9), Some(8)); + oracle.min_block_delta = 8; + assert_eq!(oracle.voting_target(Some(10), 18), Some(18)); + + // vote on power of two + oracle.min_block_delta = 1; + assert_eq!(oracle.voting_target(Some(1000), 1008), Some(1004)); + assert_eq!(oracle.voting_target(Some(1000), 1016), Some(1008)); + + // nothing new to vote on + assert_eq!(oracle.voting_target(Some(1000), 1000), None); + + // vote on mandatory + oracle.sessions.clear(); + oracle.add_session(Rounds::new(1000, validator_set.clone())); + assert_eq!(oracle.voting_target(None, 1008), Some(1000)); + oracle.sessions.clear(); + oracle.add_session(Rounds::new(1001, validator_set.clone())); + assert_eq!(oracle.voting_target(Some(1000), 1008), Some(1001)); + } + + #[test] + fn test_oracle_accepted_interval() { + let keys = &[Keyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + + let mut oracle = VoterOracle::::new(1); + + // rounds not initialized -> should accept votes: `None` + assert!(oracle.accepted_interval(1).is_err()); + + let session_one = 1; + oracle.add_session(Rounds::new(session_one, validator_set.clone())); + // mandatory not done, only accept mandatory + for i in 0..15 { + assert_eq!(oracle.accepted_interval(i), Ok((session_one, session_one))); + } + + // add more sessions, nothing changes + let session_two = 11; + let session_three = 21; + oracle.add_session(Rounds::new(session_two, validator_set.clone())); + oracle.add_session(Rounds::new(session_three, validator_set.clone())); + // mandatory not done, should accept mandatory for session_one + for i in session_three..session_three + 15 { + assert_eq!(oracle.accepted_interval(i), Ok((session_one, session_one))); + } + + // simulate finish mandatory for session one, prune oracle + oracle.sessions.front_mut().unwrap().test_set_mandatory_done(true); + oracle.try_prune(); + // session_one pruned, should accept mandatory for session_two + for i in session_three..session_three + 15 { + assert_eq!(oracle.accepted_interval(i), Ok((session_two, session_two))); + } + + // simulate finish mandatory for session two, prune oracle + oracle.sessions.front_mut().unwrap().test_set_mandatory_done(true); + oracle.try_prune(); + // session_two pruned, should accept mandatory for session_three + for i in session_three..session_three + 15 { + assert_eq!(oracle.accepted_interval(i), Ok((session_three, session_three))); + } + + // simulate finish mandatory for session three + oracle.sessions.front_mut().unwrap().test_set_mandatory_done(true); + // verify all other blocks in this session are now open to voting + for i in session_three..session_three + 15 { + assert_eq!(oracle.accepted_interval(i), Ok((session_three, i))); + } + // pruning does nothing in this case + oracle.try_prune(); + for i in session_three..session_three + 15 { + assert_eq!(oracle.accepted_interval(i), Ok((session_three, i))); + } + + // adding new session automatically prunes "finalized" previous session + let session_four = 31; + oracle.add_session(Rounds::new(session_four, validator_set.clone())); + assert_eq!(oracle.sessions.front().unwrap().session_start(), session_four); + assert_eq!(oracle.accepted_interval(session_four + 10), Ok((session_four, session_four))); + } + #[test] fn extract_authorities_change_digest() { let mut header = Header::new( @@ -876,69 +1138,6 @@ pub(crate) mod tests { assert_eq!(extracted, Some(mmr_root_hash)); } - #[test] - fn should_vote_target() { - let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1, 0); - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); - - // rounds not initialized -> should vote: `None` - assert_eq!(worker.current_vote_target(), None); - - let set_up = |worker: &mut BeefyWorker< - Block, - Backend, - PeersFullClient, - TestApi, - Arc>, - >, - best_grandpa: u64, - best_beefy: Option, - session_start: u64, - min_delta: u32| { - let grandpa_header = Header::new( - best_grandpa, - Default::default(), - Default::default(), - Default::default(), - Default::default(), - ); - worker.best_grandpa_block_header = grandpa_header; - worker.best_beefy_block = best_beefy; - worker.min_block_delta = min_delta; - worker.rounds = Some(Rounds::new(session_start, validator_set.clone())); - }; - - // under min delta - set_up(&mut worker, 1, Some(1), 1, 4); - assert_eq!(worker.current_vote_target(), None); - set_up(&mut worker, 5, Some(2), 1, 4); - assert_eq!(worker.current_vote_target(), None); - - // vote on min delta - set_up(&mut worker, 9, Some(4), 1, 4); - assert_eq!(worker.current_vote_target(), Some(8)); - set_up(&mut worker, 18, Some(10), 1, 8); - assert_eq!(worker.current_vote_target(), Some(18)); - - // vote on power of two - set_up(&mut worker, 1008, Some(1000), 1, 1); - assert_eq!(worker.current_vote_target(), Some(1004)); - set_up(&mut worker, 1016, Some(1000), 1, 2); - assert_eq!(worker.current_vote_target(), Some(1008)); - - // nothing new to vote on - set_up(&mut worker, 1000, Some(1000), 1, 1); - assert_eq!(worker.current_vote_target(), None); - - // vote on mandatory - set_up(&mut worker, 1008, None, 1000, 8); - assert_eq!(worker.current_vote_target(), Some(1000)); - set_up(&mut worker, 1008, Some(1000), 1001, 8); - assert_eq!(worker.current_vote_target(), Some(1001)); - } - #[test] fn keystore_vs_validator_set() { let keys = &[Keyring::Alice]; @@ -953,39 +1152,57 @@ pub(crate) mod tests { let keys = &[Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let err_msg = "no authority public key found in store".to_string(); - let expected = Err(error::Error::Keystore(err_msg)); + let expected = Err(Error::Keystore(err_msg)); assert_eq!(worker.verify_validator_set(&1, &validator_set), expected); // worker has no keystore worker.key_store = None.into(); - let expected_err = Err(error::Error::Keystore("no Keystore".into())); + let expected_err = Err(Error::Keystore("no Keystore".into())); assert_eq!(worker.verify_validator_set(&1, &validator_set), expected_err); } #[test] - fn setting_best_beefy_block() { + fn test_finalize() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1, 0); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); - let (mut best_block_streams, _) = get_beefy_streams(&mut net, keys); + let (mut best_block_streams, mut signed_commitments) = get_beefy_streams(&mut net, keys); let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); + let mut signed_commitments = signed_commitments.drain(..).next().unwrap(); - // no 'best beefy block' + let create_signed_commitment = |block_num: NumberFor| { + let commitment = Commitment { + payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + block_number: block_num, + validator_set_id: validator_set.id(), + }; + SignedCommitment { commitment, signatures: vec![None] } + }; + + // no 'best beefy block' or signed commitments assert_eq!(worker.best_beefy_block, None); block_on(poll_fn(move |cx| { assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); + assert_eq!(signed_commitments.poll_next_unpin(cx), Poll::Pending); Poll::Ready(()) })); // unknown hash for block #1 - let (mut best_block_streams, _) = get_beefy_streams(&mut net, keys); + let (mut best_block_streams, mut signed_commitments) = get_beefy_streams(&mut net, keys); let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); - worker.set_best_beefy_block(1); + let mut signed_commitments = signed_commitments.drain(..).next().unwrap(); + let justif = create_signed_commitment(1); + worker.finalize(justif.clone()); assert_eq!(worker.best_beefy_block, Some(1)); block_on(poll_fn(move |cx| { assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); + match signed_commitments.poll_next_unpin(cx) { + // expect justification + Poll::Ready(Some(received)) => assert_eq!(received, justif), + v => panic!("unexpected value: {:?}", v), + } Poll::Ready(()) })); @@ -994,7 +1211,8 @@ pub(crate) mod tests { let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); net.generate_blocks(2, 10, &validator_set, false); - worker.set_best_beefy_block(2); + let justif = create_signed_commitment(2); + worker.finalize(justif); assert_eq!(worker.best_beefy_block, Some(2)); block_on(poll_fn(move |cx| { match best_block_stream.poll_next_unpin(cx) { @@ -1010,20 +1228,17 @@ pub(crate) mod tests { } #[test] - fn setting_initial_session() { + fn should_init_session() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1, 0); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); - assert!(worker.rounds.is_none()); + assert!(worker.voting_oracle.sessions.is_empty()); - // verify setting the correct validator sets and boundary for genesis session worker.init_session_at(validator_set.clone(), 1); - - let worker_rounds = worker.rounds.as_ref().unwrap(); - assert_eq!(worker_rounds.session_start(), &1); - // in genesis case both current and prev validator sets are the same + let worker_rounds = worker.voting_oracle.rounds_mut().unwrap(); + assert_eq!(worker_rounds.session_start(), 1); assert_eq!(worker_rounds.validators(), validator_set.validators()); assert_eq!(worker_rounds.validator_set_id(), validator_set.id()); @@ -1031,12 +1246,79 @@ pub(crate) mod tests { let keys = &[Keyring::Bob]; let new_validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); - // verify setting the correct validator sets and boundary for non-genesis session worker.init_session_at(new_validator_set.clone(), 11); + // Since mandatory is not done for old rounds, we still get those. + let rounds = worker.voting_oracle.rounds_mut().unwrap(); + assert_eq!(rounds.validator_set_id(), validator_set.id()); + // Let's finalize mandatory. + rounds.test_set_mandatory_done(true); + worker.voting_oracle.try_prune(); + // Now we should get the next round. + let rounds = worker.voting_oracle.rounds_mut().unwrap(); + // Expect new values. + assert_eq!(rounds.session_start(), 11); + assert_eq!(rounds.validators(), new_validator_set.validators()); + assert_eq!(rounds.validator_set_id(), new_validator_set.id()); + } + + #[test] + fn should_triage_votes_and_process_later() { + let keys = &[Keyring::Alice, Keyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1, 0); + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + + fn new_vote( + block_number: NumberFor, + ) -> VoteMessage, AuthorityId, Signature> { + let commitment = Commitment { + payload: Payload::new(*b"BF", vec![]), + block_number, + validator_set_id: 0, + }; + VoteMessage { + commitment, + id: Keyring::Alice.public(), + signature: Keyring::Alice.sign(b"I am committed"), + } + } + + // best grandpa is 20 + let best_grandpa_header = Header::new( + 20u32.into(), + Default::default(), + Default::default(), + Default::default(), + Digest::default(), + ); - let worker_rounds = worker.rounds.as_ref().unwrap(); - assert_eq!(worker_rounds.session_start(), &11); - assert_eq!(worker_rounds.validators(), new_validator_set.validators()); - assert_eq!(worker_rounds.validator_set_id(), new_validator_set.id()); + worker.voting_oracle.add_session(Rounds::new(10, validator_set.clone())); + worker.best_grandpa_block_header = best_grandpa_header; + + // triage votes for blocks 10..13 + worker.triage_incoming_vote(new_vote(10)).unwrap(); + worker.triage_incoming_vote(new_vote(11)).unwrap(); + worker.triage_incoming_vote(new_vote(12)).unwrap(); + // triage votes for blocks 20..23 + worker.triage_incoming_vote(new_vote(20)).unwrap(); + worker.triage_incoming_vote(new_vote(21)).unwrap(); + worker.triage_incoming_vote(new_vote(22)).unwrap(); + + // vote for 10 should have been handled, while the rest buffered for later processing + let mut votes = worker.pending_votes.values(); + assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 11); + assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 12); + assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 20); + assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 21); + assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 22); + assert!(votes.next().is_none()); + + // simulate mandatory done, and retry buffered votes + worker.voting_oracle.rounds_mut().unwrap().test_set_mandatory_done(true); + worker.try_pending_justif_and_votes().unwrap(); + // all blocks <= grandpa finalized should have been handled, rest still buffered + let mut votes = worker.pending_votes.values(); + assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 21); + assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 22); } } diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index d7c83810d521d..c0e1e9f0e944f 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -25,6 +25,7 @@ mod sync; use std::{ borrow::Cow, collections::HashMap, + marker::PhantomData, pin::Pin, sync::Arc, task::{Context as FutureContext, Poll}, @@ -567,25 +568,27 @@ impl BlockImportAdapterFull for T where /// This is required as the `TestNetFactory` trait does not distinguish between /// full and light nodes. #[derive(Clone)] -pub struct BlockImportAdapter { +pub struct BlockImportAdapter { inner: I, + _phantom: PhantomData, } -impl BlockImportAdapter { +impl BlockImportAdapter { /// Create a new instance of `Self::Full`. pub fn new(inner: I) -> Self { - Self { inner } + Self { inner, _phantom: PhantomData } } } #[async_trait::async_trait] -impl BlockImport for BlockImportAdapter +impl BlockImport for BlockImportAdapter where I: BlockImport + Send + Sync, I::Transaction: Send, + Transaction: Send + 'static, { type Error = ConsensusError; - type Transaction = (); + type Transaction = Transaction; async fn check_block( &mut self, @@ -596,7 +599,7 @@ where async fn import_block( &mut self, - block: BlockImportParams, + block: BlockImportParams, cache: HashMap>, ) -> Result { self.inner.import_block(block.clear_storage_changes_and_mutate(), cache).await diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index ed392139de13f..ddf58474e77a0 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -293,6 +293,12 @@ pub enum VersionedFinalityProof { V1(SignedCommitment), } +impl From> for VersionedFinalityProof { + fn from(commitment: SignedCommitment) -> Self { + VersionedFinalityProof::V1(commitment) + } +} + #[cfg(test)] mod tests { diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index b41c605d8a3be..bf77c08b76906 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -151,6 +151,11 @@ impl Justifications { self.iter().find(|j| j.0 == engine_id).map(|j| &j.1) } + /// Remove the encoded justification for the given consensus engine, if it exists. + pub fn remove(&mut self, engine_id: ConsensusEngineId) { + self.0.retain(|j| j.0 != engine_id) + } + /// Return a copy of the encoded justification for the given consensus /// engine, if it exists. pub fn into_justification(self, engine_id: ConsensusEngineId) -> Option { From 3e0554a94193c1221c6bf12c7efabc25e2d63404 Mon Sep 17 00:00:00 2001 From: ZhiYong Date: Sat, 30 Jul 2022 01:59:03 +0800 Subject: [PATCH 1017/1472] Add Event to Pallet Asset-Tx-Payment (#11690) * Add Event to Pallet Asset-Tx-Payment * add asset_id into the Event Co-authored-by: parity-processbot <> --- bin/node/runtime/src/lib.rs | 1 + .../asset-tx-payment/src/lib.rs | 27 +++++++++++++++++-- .../asset-tx-payment/src/tests.rs | 5 ++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 037211155cf0e..2ac1e6444f119 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -456,6 +456,7 @@ impl pallet_transaction_payment::Config for Runtime { } impl pallet_asset_tx_payment::Config for Runtime { + type Event = Event; type Fungibles = Assets; type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< pallet_assets::BalanceToAssetBalance, diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index 83801c44d3578..08561375247ae 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -113,6 +113,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + pallet_transaction_payment::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; /// The fungibles instance used to pay for transactions in assets. type Fungibles: Balanced; /// The actual transaction charging logic that charges the fees. @@ -122,6 +124,19 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A transaction fee `actual_fee`, of which `tip` was added to the minimum inclusion fee, + /// has been paid by `who` in an asset `asset_id`. + AssetTxFeePaid { + who: T::AccountId, + actual_fee: BalanceOf, + tip: BalanceOf, + asset_id: Option>, + }, + } } /// Require the transactor pay for themselves and maybe include a tip to gain additional priority @@ -213,6 +228,8 @@ where Self::AccountId, // imbalance resulting from withdrawing the fee InitialPayment, + // asset_id for the transaction payment + Option>, ); fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { @@ -240,7 +257,7 @@ where len: usize, ) -> Result { let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?; - Ok((self.tip, who.clone(), initial_payment)) + Ok((self.tip, who.clone(), initial_payment, self.asset_id)) } fn post_dispatch( @@ -250,7 +267,7 @@ where len: usize, result: &DispatchResult, ) -> Result<(), TransactionValidityError> { - if let Some((tip, who, initial_payment)) = pre { + if let Some((tip, who, initial_payment, asset_id)) = pre { match initial_payment { InitialPayment::Native(already_withdrawn) => { pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( @@ -273,6 +290,12 @@ where tip.into(), already_withdrawn.into(), )?; + Pallet::::deposit_event(Event::::AssetTxFeePaid { + who, + actual_fee, + tip, + asset_id, + }); }, InitialPayment::Nothing => { // `actual_fee` should be zero here for any signed extrinsic. It would be diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index ad5bc3f22e57f..08b17a6bf459c 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -51,7 +51,7 @@ frame_support::construct_runtime!( TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, Assets: pallet_assets::{Pallet, Call, Storage, Event}, Authorship: pallet_authorship::{Pallet, Call, Storage}, - AssetTxPayment: pallet_asset_tx_payment::{Pallet}, + AssetTxPayment: pallet_asset_tx_payment::{Pallet, Event}, } ); @@ -198,6 +198,7 @@ impl HandleCredit for CreditToBlockAuthor { } impl Config for Runtime { + type Event = Event; type Fungibles = Assets; type OnChargeAssetTransaction = FungiblesAdapter< pallet_assets::BalanceToAssetBalance, @@ -663,7 +664,7 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { .unwrap(); // `Pays::No` implies no pre-dispatch fees assert_eq!(Assets::balance(asset_id, caller), balance); - let (_tip, _who, initial_payment) = ⪯ + let (_tip, _who, initial_payment, _asset_id) = ⪯ let not_paying = match initial_payment { &InitialPayment::Nothing => true, _ => false, From 8f4d1b31163aa53f72d0fcb438ebe7d417093fae Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 29 Jul 2022 23:17:49 +0300 Subject: [PATCH 1018/1472] Network sync refactoring (part 5) (#11825) * Make `chain_sync` an explicit networking parameter instead of offering factory method * Derive `Copy` on `SyncMode` and remove cloning --- client/network/src/config.rs | 16 ++++------- client/network/src/service.rs | 26 ++++------------- client/network/src/service/tests.rs | 35 ++++++++++++----------- client/network/test/src/lib.rs | 32 ++++++++++++--------- client/service/src/builder.rs | 44 +++++++++++++++-------------- 5 files changed, 69 insertions(+), 84 deletions(-) diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 58349fe973330..2622762da5fc9 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -96,14 +96,8 @@ where /// valid. pub import_queue: Box>, - /// Factory function that creates a new instance of chain sync. - pub create_chain_sync: Box< - dyn FnOnce( - sc_network_common::sync::SyncMode, - Arc, - Option>>, - ) -> crate::error::Result>>, - >, + /// Instance of chain sync implementation. + pub chain_sync: Box>, /// Registry for recording prometheus metrics to. pub metrics_registry: Option, @@ -138,8 +132,8 @@ where /// both outgoing and incoming requests. pub state_request_protocol_config: RequestResponseConfig, - /// Optional warp sync protocol support. Include protocol config and sync provider. - pub warp_sync: Option<(Arc>, RequestResponseConfig)>, + /// Optional warp sync protocol config. + pub warp_sync_protocol_config: Option, } /// Role of the local node. @@ -352,7 +346,7 @@ impl From for ParseErr { } /// Sync operation mode. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum SyncMode { /// Full block download and verification. Full, diff --git a/client/network/src/service.rs b/client/network/src/service.rs index aeb5e25497bb3..409ed88c75c00 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -30,7 +30,7 @@ use crate::{ behaviour::{self, Behaviour, BehaviourOut}, bitswap::Bitswap, - config::{self, parse_str_addr, Params, TransportConfig}, + config::{parse_str_addr, Params, TransportConfig}, discovery::DiscoveryConfig, error::Error, network_state::{ @@ -60,7 +60,7 @@ use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; -use sc_network_common::sync::{SyncMode, SyncState, SyncStatus}; +use sc_network_common::sync::{SyncState, SyncStatus}; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::{HeaderBackend, HeaderMetadata}; @@ -239,21 +239,6 @@ where let default_notif_handshake_message = Roles::from(¶ms.role).encode(); - let (warp_sync_provider, warp_sync_protocol_config) = match params.warp_sync { - Some((p, c)) => (Some(p), Some(c)), - None => (None, None), - }; - - let chain_sync = (params.create_chain_sync)( - match params.network_config.sync_mode { - config::SyncMode::Full => SyncMode::Full, - config::SyncMode::Fast { skip_proofs, storage_chain_mode } => - SyncMode::LightState { skip_proofs, storage_chain_mode }, - config::SyncMode::Warp => SyncMode::Warp, - }, - params.chain.clone(), - warp_sync_provider, - )?; let (protocol, peerset_handle, mut known_addresses) = Protocol::new( From::from(¶ms.role), params.chain.clone(), @@ -266,7 +251,7 @@ where ) .collect(), params.metrics_registry.as_ref(), - chain_sync, + params.chain_sync, )?; // List of multiaddresses that we know in the network. @@ -303,7 +288,6 @@ where let is_major_syncing = Arc::new(AtomicBool::new(false)); // Build the swarm. - let client = params.chain.clone(); let (mut swarm, bandwidth): (Swarm>, _) = { let user_agent = format!( "{} ({})", @@ -389,7 +373,7 @@ where }; let behaviour = { - let bitswap = params.network_config.ipfs_server.then(|| Bitswap::new(client)); + let bitswap = params.network_config.ipfs_server.then(|| Bitswap::new(params.chain)); let result = Behaviour::new( protocol, user_agent, @@ -397,7 +381,7 @@ where discovery_config, params.block_request_protocol_config, params.state_request_protocol_config, - warp_sync_protocol_config, + params.warp_sync_protocol_config, bitswap, params.light_client_request_protocol_config, params.network_config.request_response_protocols, diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 181d58130aa6b..de474ee8fe4d0 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -42,7 +42,7 @@ type TestNetworkService = NetworkService< /// > **Note**: We return the events stream in order to not possibly lose events between the /// > construction of the service and the moment the events stream is grabbed. fn build_test_full_node( - config: config::NetworkConfiguration, + network_config: config::NetworkConfiguration, ) -> (Arc, impl Stream) { let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); @@ -111,35 +111,36 @@ fn build_test_full_node( protocol_config }; - let max_parallel_downloads = config.max_parallel_downloads; + let chain_sync = ChainSync::new( + match network_config.sync_mode { + config::SyncMode::Full => sc_network_common::sync::SyncMode::Full, + config::SyncMode::Fast { skip_proofs, storage_chain_mode } => + sc_network_common::sync::SyncMode::LightState { skip_proofs, storage_chain_mode }, + config::SyncMode::Warp => sc_network_common::sync::SyncMode::Warp, + }, + client.clone(), + Box::new(DefaultBlockAnnounceValidator), + network_config.max_parallel_downloads, + None, + ) + .unwrap(); let worker = NetworkWorker::new(config::Params { role: config::Role::Full, executor: None, transactions_handler_executor: Box::new(|task| { async_std::task::spawn(task); }), - network_config: config, + network_config, chain: client.clone(), - transaction_pool: Arc::new(crate::config::EmptyTransactionPool), + transaction_pool: Arc::new(config::EmptyTransactionPool), protocol_id, import_queue, - create_chain_sync: Box::new( - move |sync_mode, chain, warp_sync_provider| match ChainSync::new( - sync_mode, - chain, - Box::new(DefaultBlockAnnounceValidator), - max_parallel_downloads, - warp_sync_provider, - ) { - Ok(chain_sync) => Ok(Box::new(chain_sync)), - Err(error) => Err(Box::new(error).into()), - }, - ), + chain_sync: Box::new(chain_sync), metrics_registry: None, block_request_protocol_config, state_request_protocol_config, light_client_request_protocol_config, - warp_sync: None, + warp_sync_protocol_config: None, }) .unwrap(); diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index c0e1e9f0e944f..4659684987f77 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -838,10 +838,25 @@ where protocol_config }; - let max_parallel_downloads = network_config.max_parallel_downloads; let block_announce_validator = config .block_announce_validator .unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)); + let chain_sync = ChainSync::new( + match network_config.sync_mode { + SyncMode::Full => sc_network_common::sync::SyncMode::Full, + SyncMode::Fast { skip_proofs, storage_chain_mode } => + sc_network_common::sync::SyncMode::LightState { + skip_proofs, + storage_chain_mode, + }, + SyncMode::Warp => sc_network_common::sync::SyncMode::Warp, + }, + client.clone(), + block_announce_validator, + network_config.max_parallel_downloads, + Some(warp_sync), + ) + .unwrap(); let network = NetworkWorker::new(sc_network::config::Params { role: if config.is_authority { Role::Authority } else { Role::Full }, executor: None, @@ -853,23 +868,12 @@ where transaction_pool: Arc::new(EmptyTransactionPool), protocol_id, import_queue, - create_chain_sync: Box::new(move |sync_mode, chain, warp_sync_provider| { - match ChainSync::new( - sync_mode, - chain, - block_announce_validator, - max_parallel_downloads, - warp_sync_provider, - ) { - Ok(chain_sync) => Ok(Box::new(chain_sync)), - Err(error) => Err(Box::new(error).into()), - } - }), + chain_sync: Box::new(chain_sync), metrics_registry: None, block_request_protocol_config, state_request_protocol_config, light_client_request_protocol_config, - warp_sync: Some((warp_sync, warp_protocol_config)), + warp_sync_protocol_config: Some(warp_protocol_config), }) .unwrap(); diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 0a18943f45006..ec537a33b72d5 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -760,13 +760,15 @@ where protocol_config }; - let warp_sync_params = warp_sync.map(|provider| { - // Allow both outgoing and incoming requests. - let (handler, protocol_config) = - WarpSyncRequestHandler::new(protocol_id.clone(), provider.clone()); - spawn_handle.spawn("warp-sync-request-handler", Some("networking"), handler.run()); - (provider, protocol_config) - }); + let (warp_sync_provider, warp_sync_protocol_config) = warp_sync + .map(|provider| { + // Allow both outgoing and incoming requests. + let (handler, protocol_config) = + WarpSyncRequestHandler::new(protocol_id.clone(), provider.clone()); + spawn_handle.spawn("warp-sync-request-handler", Some("networking"), handler.run()); + (Some(provider), Some(protocol_config)) + }) + .unwrap_or_default(); let light_client_request_protocol_config = { // Allow both outgoing and incoming requests. @@ -776,7 +778,18 @@ where protocol_config }; - let max_parallel_downloads = config.network.max_parallel_downloads; + let chain_sync = ChainSync::new( + match config.network.sync_mode { + SyncMode::Full => sc_network_common::sync::SyncMode::Full, + SyncMode::Fast { skip_proofs, storage_chain_mode } => + sc_network_common::sync::SyncMode::LightState { skip_proofs, storage_chain_mode }, + SyncMode::Warp => sc_network_common::sync::SyncMode::Warp, + }, + client.clone(), + block_announce_validator, + config.network.max_parallel_downloads, + warp_sync_provider, + )?; let network_params = sc_network::config::Params { role: config.role.clone(), executor: { @@ -796,22 +809,11 @@ where transaction_pool: transaction_pool_adapter as _, protocol_id, import_queue: Box::new(import_queue), - create_chain_sync: Box::new( - move |sync_mode, chain, warp_sync_provider| match ChainSync::new( - sync_mode, - chain, - block_announce_validator, - max_parallel_downloads, - warp_sync_provider, - ) { - Ok(chain_sync) => Ok(Box::new(chain_sync)), - Err(error) => Err(Box::new(error).into()), - }, - ), + chain_sync: Box::new(chain_sync), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_request_protocol_config, state_request_protocol_config, - warp_sync: warp_sync_params, + warp_sync_protocol_config, light_client_request_protocol_config, }; From 986fab5ab303e566f637bb57e3c9c9b7df1d369e Mon Sep 17 00:00:00 2001 From: yjh Date: Sat, 30 Jul 2022 06:07:34 +0800 Subject: [PATCH 1019/1472] feat: generalize ConsensusDataProvider for manual-seal (#11827) * feat: generalize ConsensusDataProvider for manual-seal * rename all generic type param `proof`/`PROOF` to `P` * rename a missing thing * Update client/consensus/manual-seal/src/consensus.rs Co-authored-by: Davide Galassi * Update client/consensus/manual-seal/src/consensus/babe.rs Co-authored-by: Davide Galassi * Update client/consensus/manual-seal/src/consensus/aura.rs Co-authored-by: Davide Galassi Co-authored-by: Davide Galassi --- client/consensus/manual-seal/src/consensus.rs | 4 ++++ .../manual-seal/src/consensus/aura.rs | 11 +++++---- .../manual-seal/src/consensus/babe.rs | 21 ++++++++++++---- client/consensus/manual-seal/src/lib.rs | 24 +++++++++++-------- .../consensus/manual-seal/src/seal_block.rs | 14 ++++++----- 5 files changed, 49 insertions(+), 25 deletions(-) diff --git a/client/consensus/manual-seal/src/consensus.rs b/client/consensus/manual-seal/src/consensus.rs index dfd3730fd3427..b5dfc3d809c13 100644 --- a/client/consensus/manual-seal/src/consensus.rs +++ b/client/consensus/manual-seal/src/consensus.rs @@ -33,6 +33,9 @@ pub trait ConsensusDataProvider: Send + Sync { /// Block import transaction type type Transaction; + /// The proof type. + type Proof; + /// Attempt to create a consensus digest. fn create_digest(&self, parent: &B::Header, inherents: &InherentData) -> Result; @@ -42,5 +45,6 @@ pub trait ConsensusDataProvider: Send + Sync { parent: &B::Header, params: &mut BlockImportParams, inherents: &InherentData, + proof: Self::Proof, ) -> Result<(), Error>; } diff --git a/client/consensus/manual-seal/src/consensus/aura.rs b/client/consensus/manual-seal/src/consensus/aura.rs index 7b5d6720562be..065b78732cdc3 100644 --- a/client/consensus/manual-seal/src/consensus/aura.rs +++ b/client/consensus/manual-seal/src/consensus/aura.rs @@ -35,14 +35,14 @@ use sp_timestamp::TimestampInherentData; use std::{marker::PhantomData, sync::Arc}; /// Consensus data provider for Aura. -pub struct AuraConsensusDataProvider { +pub struct AuraConsensusDataProvider { // slot duration slot_duration: SlotDuration, // phantom data for required generics - _phantom: PhantomData<(B, C)>, + _phantom: PhantomData<(B, C, P)>, } -impl AuraConsensusDataProvider +impl AuraConsensusDataProvider where B: BlockT, C: AuxStore + ProvideRuntimeApi + UsageProvider, @@ -58,7 +58,7 @@ where } } -impl ConsensusDataProvider for AuraConsensusDataProvider +impl ConsensusDataProvider for AuraConsensusDataProvider where B: BlockT, C: AuxStore @@ -67,8 +67,10 @@ where + UsageProvider + ProvideRuntimeApi, C::Api: AuraApi, + P: Send + Sync, { type Transaction = TransactionFor; + type Proof = P; fn create_digest( &self, @@ -92,6 +94,7 @@ where _parent: &B::Header, _params: &mut BlockImportParams, _inherents: &InherentData, + _proof: Self::Proof, ) -> Result<(), Error> { Ok(()) } diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 3e7770cd982d2..cc73a3fa961ce 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -31,7 +31,7 @@ use sc_consensus_epochs::{ descendent_query, EpochHeader, SharedEpochChanges, ViableEpochDescriptor, }; use sp_keystore::SyncCryptoStorePtr; -use std::{borrow::Cow, sync::Arc}; +use std::{borrow::Cow, marker::PhantomData, sync::Arc}; use sc_consensus::{BlockImportParams, ForkChoiceStrategy, Verifier}; use sp_api::{ProvideRuntimeApi, TransactionFor}; @@ -53,7 +53,7 @@ use sp_timestamp::TimestampInherentData; /// Provides BABE-compatible predigests and BlockImportParams. /// Intended for use with BABE runtimes. -pub struct BabeConsensusDataProvider { +pub struct BabeConsensusDataProvider { /// shared reference to keystore keystore: SyncCryptoStorePtr, @@ -68,6 +68,7 @@ pub struct BabeConsensusDataProvider { /// Authorities to be used for this babe chain. authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, + _phantom: PhantomData

, } /// Verifier to be used for babe chains @@ -131,7 +132,7 @@ where } } -impl BabeConsensusDataProvider +impl BabeConsensusDataProvider where B: BlockT, C: AuxStore @@ -153,7 +154,14 @@ where let config = Config::get(&*client)?; - Ok(Self { config, client, keystore, epoch_changes, authorities }) + Ok(Self { + config, + client, + keystore, + epoch_changes, + authorities, + _phantom: Default::default(), + }) } fn epoch(&self, parent: &B::Header, slot: Slot) -> Result { @@ -181,7 +189,7 @@ where } } -impl ConsensusDataProvider for BabeConsensusDataProvider +impl ConsensusDataProvider for BabeConsensusDataProvider where B: BlockT, C: AuxStore @@ -190,8 +198,10 @@ where + UsageProvider + ProvideRuntimeApi, C::Api: BabeApi, + P: Send + Sync, { type Transaction = TransactionFor; + type Proof = P; fn create_digest(&self, parent: &B::Header, inherents: &InherentData) -> Result { let slot = inherents @@ -259,6 +269,7 @@ where parent: &B::Header, params: &mut BlockImportParams, inherents: &InherentData, + _proof: Self::Proof, ) -> Result<(), Error> { let slot = inherents .babe_inherent_data()? diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index a8d2634ade560..ba63666f3e46c 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -81,7 +81,7 @@ where } /// Params required to start the instant sealing authorship task. -pub struct ManualSealParams, TP, SC, CS, CIDP> { +pub struct ManualSealParams, TP, SC, CS, CIDP, P> { /// Block import instance for well. importing blocks. pub block_import: BI, @@ -103,14 +103,14 @@ pub struct ManualSealParams, TP, SC, C /// Digest provider for inclusion in blocks. pub consensus_data_provider: - Option>>>, + Option>>>, /// Something that can create the inherent data providers. pub create_inherent_data_providers: CIDP, } /// Params required to start the manual sealing authorship task. -pub struct InstantSealParams, TP, SC, CIDP> { +pub struct InstantSealParams, TP, SC, CIDP, P> { /// Block import instance for well. importing blocks. pub block_import: BI, @@ -128,14 +128,14 @@ pub struct InstantSealParams, TP, SC, /// Digest provider for inclusion in blocks. pub consensus_data_provider: - Option>>>, + Option>>>, /// Something that can create the inherent data providers. pub create_inherent_data_providers: CIDP, } /// Creates the background authorship task for the manual seal engine. -pub async fn run_manual_seal( +pub async fn run_manual_seal( ManualSealParams { mut block_import, mut env, @@ -145,7 +145,7 @@ pub async fn run_manual_seal( select_chain, consensus_data_provider, create_inherent_data_providers, - }: ManualSealParams, + }: ManualSealParams, ) where B: BlockT + 'static, BI: BlockImport> @@ -155,12 +155,13 @@ pub async fn run_manual_seal( C: HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, CB: ClientBackend + 'static, E: Environment + 'static, - E::Proposer: Proposer>, + E::Proposer: Proposer>, CS: Stream::Hash>> + Unpin + 'static, SC: SelectChain + 'static, TransactionFor: 'static, TP: TransactionPool, CIDP: CreateInherentDataProviders, + P: Send + Sync + 'static, { while let Some(command) = commands_stream.next().await { match command { @@ -198,7 +199,7 @@ pub async fn run_manual_seal( /// runs the background authorship task for the instant seal engine. /// instant-seal creates a new block for every transaction imported into /// the transaction pool. -pub async fn run_instant_seal( +pub async fn run_instant_seal( InstantSealParams { block_import, env, @@ -207,7 +208,7 @@ pub async fn run_instant_seal( select_chain, consensus_data_provider, create_inherent_data_providers, - }: InstantSealParams, + }: InstantSealParams, ) where B: BlockT + 'static, BI: BlockImport> @@ -217,11 +218,12 @@ pub async fn run_instant_seal( C: HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, CB: ClientBackend + 'static, E: Environment + 'static, - E::Proposer: Proposer>, + E::Proposer: Proposer>, SC: SelectChain + 'static, TransactionFor: 'static, TP: TransactionPool, CIDP: CreateInherentDataProviders, + P: Send + Sync + 'static, { // instant-seal creates blocks as soon as transactions are imported // into the transaction pool. @@ -275,6 +277,7 @@ mod tests { C: ProvideRuntimeApi + Send + Sync, { type Transaction = TransactionFor; + type Proof = (); fn create_digest( &self, @@ -289,6 +292,7 @@ mod tests { _parent: &B::Header, params: &mut BlockImportParams, _inherents: &InherentData, + _proof: Self::Proof, ) -> Result<(), Error> { params.post_digests.push(DigestItem::Other(vec![1])); Ok(()) diff --git a/client/consensus/manual-seal/src/seal_block.rs b/client/consensus/manual-seal/src/seal_block.rs index 202b54fe5d0c5..32e3acf68506e 100644 --- a/client/consensus/manual-seal/src/seal_block.rs +++ b/client/consensus/manual-seal/src/seal_block.rs @@ -36,7 +36,7 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; pub const MAX_PROPOSAL_DURATION: u64 = 10; /// params for sealing a new block -pub struct SealBlockParams<'a, B: BlockT, BI, SC, C: ProvideRuntimeApi, E, TP, CIDP> { +pub struct SealBlockParams<'a, B: BlockT, BI, SC, C: ProvideRuntimeApi, E, TP, CIDP, P> { /// if true, empty blocks(without extrinsics) will be created. /// otherwise, will return Error::EmptyTransactionPool. pub create_empty: bool, @@ -56,7 +56,7 @@ pub struct SealBlockParams<'a, B: BlockT, BI, SC, C: ProvideRuntimeApi, E, TP pub select_chain: &'a SC, /// Digest provider for inclusion in blocks. pub consensus_data_provider: - Option<&'a dyn ConsensusDataProvider>>, + Option<&'a dyn ConsensusDataProvider>>, /// block import object pub block_import: &'a mut BI, /// Something that can create the inherent data providers. @@ -64,7 +64,7 @@ pub struct SealBlockParams<'a, B: BlockT, BI, SC, C: ProvideRuntimeApi, E, TP } /// seals a new block with the given params -pub async fn seal_block( +pub async fn seal_block( SealBlockParams { create_empty, finalize, @@ -77,7 +77,7 @@ pub async fn seal_block( create_inherent_data_providers, consensus_data_provider: digest_provider, mut sender, - }: SealBlockParams<'_, B, BI, SC, C, E, TP, CIDP>, + }: SealBlockParams<'_, B, BI, SC, C, E, TP, CIDP, P>, ) where B: BlockT, BI: BlockImport> @@ -86,11 +86,12 @@ pub async fn seal_block( + 'static, C: HeaderBackend + ProvideRuntimeApi, E: Environment, - E::Proposer: Proposer>, + E::Proposer: Proposer>, TP: TransactionPool, SC: SelectChain, TransactionFor: 'static, CIDP: CreateInherentDataProviders, + P: Send + Sync + 'static, { let future = async { if pool.status().ready == 0 && !create_empty { @@ -138,6 +139,7 @@ pub async fn seal_block( } let (header, body) = proposal.block.deconstruct(); + let proof = proposal.proof; let mut params = BlockImportParams::new(BlockOrigin::Own, header.clone()); params.body = Some(body); params.finalized = finalize; @@ -147,7 +149,7 @@ pub async fn seal_block( )); if let Some(digest_provider) = digest_provider { - digest_provider.append_block_import(&parent, &mut params, &inherent_data)?; + digest_provider.append_block_import(&parent, &mut params, &inherent_data, proof)?; } // Make sure we return the same post-hash that will be calculated when importing the block From 7d8e5a1e3979cb0fc61123d5cfeec974dfa25334 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Sat, 30 Jul 2022 16:09:25 +0200 Subject: [PATCH 1020/1472] Auto-incremental CollectionId (#11796) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * autoincrementing CollectionId * fix * benchmarking fix * fmt * fix * update before checking * fmt * fix * fmt * commit * tests & fix * fix * commit * docs * safe math * unexpose function * benchmark * fmt * better naming * fix? * merge fixes * fmt * ".git/.scripts/bench-bot.sh" pallet dev pallet_uniques * wrong weight * Update frame/uniques/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/uniques/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * using substrate trait instead of num-traits * remove unnecessary trait * emit NextCollectionIdIncremented in do_create_collection * fix in benchmarks * check for event & group import * docs Co-authored-by: Sergej Sakač Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi --- Cargo.lock | 4 +- frame/uniques/src/benchmarking.rs | 25 +++-- frame/uniques/src/functions.rs | 15 +++ frame/uniques/src/lib.rs | 54 ++++++++-- frame/uniques/src/tests.rs | 83 ++++++++++----- frame/uniques/src/weights.rs | 169 +++++++++++++++++------------- 6 files changed, 233 insertions(+), 117 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34bf34c62c6fd..2b76f61df7912 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5020,9 +5020,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", "libm", diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 713393048f7e9..86247fb964ff5 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -42,13 +42,10 @@ fn create_collection, I: 'static>( let caller_lookup = T::Lookup::unlookup(caller.clone()); let collection = T::Helper::collection(0); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - assert!(Uniques::::force_create( - SystemOrigin::Root.into(), - collection, - caller_lookup.clone(), - false, - ) - .is_ok()); + assert!( + Uniques::::force_create(SystemOrigin::Root.into(), caller_lookup.clone(), false,) + .is_ok() + ); (collection, caller, caller_lookup) } @@ -143,7 +140,7 @@ benchmarks_instance_pallet! { whitelist_account!(caller); let admin = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - let call = Call::::create { collection, admin }; + let call = Call::::create { admin }; }: { call.dispatch_bypass_filter(origin)? } verify { assert_last_event::(Event::Created { collection: T::Helper::collection(0), creator: caller.clone(), owner: caller }.into()); @@ -152,7 +149,7 @@ benchmarks_instance_pallet! { force_create { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - }: _(SystemOrigin::Root, T::Helper::collection(0), caller_lookup, true) + }: _(SystemOrigin::Root, caller_lookup, true) verify { assert_last_event::(Event::ForceCreated { collection: T::Helper::collection(0), owner: caller }.into()); } @@ -408,6 +405,16 @@ benchmarks_instance_pallet! { }.into()); } + try_increment_id { + let (_, caller, _) = create_collection::(); + Uniques::::set_next_id(0); + }: _(SystemOrigin::Signed(caller.clone())) + verify { + assert_last_event::(Event::NextCollectionIdIncremented { + next_id: 1u32.into() + }.into()); + } + set_price { let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 9e8d3301616df..dcbb1f27973d7 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -88,7 +88,12 @@ impl, I: 'static> Pallet { }, ); + let next_id = collection.saturating_add(1u32.into()); + CollectionAccount::::insert(&owner, &collection, ()); + NextCollectionId::::set(next_id); + + Self::deposit_event(Event::NextCollectionIdIncremented { next_id }); Self::deposit_event(event); Ok(()) } @@ -208,6 +213,16 @@ impl, I: 'static> Pallet { Ok(()) } + #[cfg(any(test, feature = "runtime-benchmarks"))] + pub fn set_next_id(count: u32) { + NextCollectionId::::set(count.into()); + } + + #[cfg(test)] + pub fn get_next_id() -> T::CollectionId { + NextCollectionId::::get() + } + pub fn do_set_price( collection: T::CollectionId, item: T::ItemId, diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 53f83605da90e..b25fb2f87ea97 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -51,7 +51,7 @@ use frame_support::{ }; use frame_system::Config as SystemConfig; use sp_runtime::{ - traits::{Saturating, StaticLookup, Zero}, + traits::{AtLeast32BitUnsigned, Saturating, StaticLookup, Zero}, ArithmeticError, RuntimeDebug, }; use sp_std::prelude::*; @@ -92,7 +92,12 @@ pub mod pallet { type Event: From> + IsType<::Event>; /// Identifier for the collection of item. - type CollectionId: Member + Parameter + MaxEncodedLen + Copy; + type CollectionId: Member + + Parameter + + MaxEncodedLen + + Copy + + Default + + AtLeast32BitUnsigned; /// The type used to identify a unique item within a collection. type ItemId: Member + Parameter + MaxEncodedLen + Copy; @@ -266,6 +271,12 @@ pub mod pallet { pub(super) type CollectionMaxSupply, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::CollectionId, u32, OptionQuery>; + #[pallet::storage] + /// Stores the `CollectionId` that is going to be used for the next collection. + /// This gets incremented by 1 whenever a new collection is created. + pub(super) type NextCollectionId, I: 'static = ()> = + StorageValue<_, T::CollectionId, ValueQuery>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { @@ -357,6 +368,8 @@ pub mod pallet { OwnershipAcceptanceChanged { who: T::AccountId, maybe_collection: Option }, /// Max supply has been set for a collection. CollectionMaxSupplySet { collection: T::CollectionId, max_supply: u32 }, + /// Event gets emmited when the `NextCollectionId` gets incremented. + NextCollectionIdIncremented { next_id: T::CollectionId }, /// The price was set for the instance. ItemPriceSet { collection: T::CollectionId, @@ -408,6 +421,10 @@ pub mod pallet { MaxSupplyAlreadySet, /// The provided max supply is less to the amount of items a collection already has. MaxSupplyTooSmall, + /// The `CollectionId` in `NextCollectionId` is not being used. + /// + /// This means that you can directly proceed to call `create`. + NextIdNotUsed, /// The given item ID is unknown. UnknownItem, /// Item is not for sale. @@ -439,7 +456,6 @@ pub mod pallet { /// `ItemDeposit` funds of sender are reserved. /// /// Parameters: - /// - `collection`: The identifier of the new collection. This must not be currently in use. /// - `admin`: The admin of this collection. The admin is the initial address of each /// member of the collection's admin team. /// @@ -449,9 +465,10 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::create())] pub fn create( origin: OriginFor, - collection: T::CollectionId, admin: ::Source, ) -> DispatchResult { + let collection = NextCollectionId::::get(); + let owner = T::CreateOrigin::ensure_origin(origin, &collection)?; let admin = T::Lookup::lookup(admin)?; @@ -473,7 +490,6 @@ pub mod pallet { /// /// Unlike `create`, no funds are reserved. /// - /// - `collection`: The identifier of the new item. This must not be currently in use. /// - `owner`: The owner of this collection of items. The owner has full superuser /// permissions /// over this item, but may later change and configure the permissions using @@ -485,13 +501,14 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_create())] pub fn force_create( origin: OriginFor, - collection: T::CollectionId, owner: ::Source, free_holding: bool, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; + let collection = NextCollectionId::::get(); + Self::do_create_collection( collection, owner.clone(), @@ -502,6 +519,31 @@ pub mod pallet { ) } + /// Increments the `CollectionId` stored in `NextCollectionId`. + /// + /// This is only callable when the next `CollectionId` is already being + /// used for some other collection. + /// + /// The origin must be Signed and the sender must have sufficient funds + /// free. + /// + /// Emits `NextCollectionIdIncremented` event when successful. + /// + /// Weight: `O(1)` + #[pallet::weight(T::WeightInfo::try_increment_id())] + pub fn try_increment_id(origin: OriginFor) -> DispatchResult { + ensure_signed(origin)?; + ensure!( + Collection::::contains_key(NextCollectionId::::get()), + Error::::NextIdNotUsed + ); + + let next_id = NextCollectionId::::get().saturating_add(1u32.into()); + NextCollectionId::::set(next_id); + Self::deposit_event(Event::NextCollectionIdIncremented { next_id }); + Ok(()) + } + /// Destroy a collection of fungible items. /// /// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 8b1d00d7ba0c7..bd3a2b032945e 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -92,12 +92,12 @@ fn basic_setup_works() { #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); assert_eq!(collections(), vec![(1, 0)]); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_eq!(items(), vec![(1, 0, 42)]); - assert_ok!(Uniques::force_create(Origin::root(), 1, 2, true)); + assert_ok!(Uniques::force_create(Origin::root(), 2, true)); assert_eq!(collections(), vec![(1, 0), (2, 1)]); assert_ok!(Uniques::mint(Origin::signed(2), 1, 69, 1)); assert_eq!(items(), vec![(1, 0, 42), (1, 1, 69)]); @@ -108,7 +108,7 @@ fn basic_minting_should_work() { fn lifecycle_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); + assert_ok!(Uniques::create(Origin::signed(1), 1)); assert_eq!(Balances::reserved_balance(&1), 2); assert_eq!(collections(), vec![(1, 0)]); assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0, 0], false)); @@ -151,7 +151,7 @@ fn lifecycle_should_work() { fn destroy_with_bad_witness_should_not_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); + assert_ok!(Uniques::create(Origin::signed(1), 1)); let w = Collection::::get(0).unwrap().destroy_witness(); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); @@ -162,7 +162,7 @@ fn destroy_with_bad_witness_should_not_work() { #[test] fn mint_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_eq!(Uniques::owner(0, 42).unwrap(), 1); assert_eq!(collections(), vec![(1, 0)]); @@ -173,7 +173,7 @@ fn mint_should_work() { #[test] fn transfer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 3)); @@ -188,7 +188,7 @@ fn transfer_should_work() { #[test] fn freezing_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_ok!(Uniques::freeze(Origin::signed(1), 0, 42)); assert_noop!(Uniques::transfer(Origin::signed(1), 0, 42, 2), Error::::Frozen); @@ -205,7 +205,7 @@ fn freezing_should_work() { #[test] fn origin_guards_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); Balances::make_free_balance_be(&2, 100); @@ -230,7 +230,7 @@ fn transfer_owner_should_work() { Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); Balances::make_free_balance_be(&3, 100); - assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); + assert_ok!(Uniques::create(Origin::signed(1), 1)); assert_eq!(collections(), vec![(1, 0)]); assert_noop!( Uniques::transfer_ownership(Origin::signed(1), 0, 2), @@ -275,7 +275,7 @@ fn transfer_owner_should_work() { #[test] fn set_team_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4)); assert_ok!(Uniques::mint(Origin::signed(2), 0, 42, 2)); @@ -294,7 +294,7 @@ fn set_collection_metadata_should_work() { Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 20], false), Error::::UnknownCollection, ); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 1, false)); // Cannot add metadata to unowned item assert_noop!( Uniques::set_collection_metadata(Origin::signed(2), 0, bvec![0u8; 20], false), @@ -354,7 +354,7 @@ fn set_item_metadata_should_work() { Balances::make_free_balance_be(&1, 30); // Cannot add metadata to unknown item - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 1, false)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); // Cannot add metadata to unowned item assert_noop!( @@ -410,7 +410,7 @@ fn set_attribute_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 1, false)); assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0])); assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![0])); @@ -455,7 +455,7 @@ fn set_attribute_should_respect_freeze() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 1, false)); assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0])); assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![0])); @@ -487,7 +487,7 @@ fn force_item_status_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 1, false)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 69, 2)); assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0; 20], false)); @@ -521,7 +521,7 @@ fn force_item_status_should_work() { fn burn_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 1, false)); assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4)); assert_noop!( @@ -545,7 +545,7 @@ fn burn_works() { #[test] fn approval_lifecycle_works() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); assert_ok!(Uniques::transfer(Origin::signed(3), 0, 42, 4)); @@ -560,7 +560,7 @@ fn approval_lifecycle_works() { #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); @@ -592,7 +592,7 @@ fn cancel_approval_works() { #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); @@ -620,7 +620,7 @@ fn cancel_approval_works_with_admin() { #[test] fn cancel_approval_works_with_force() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); @@ -653,7 +653,7 @@ fn max_supply_should_work() { let max_supply = 2; // validate set_collection_max_supply - assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true)); + assert_ok!(Uniques::force_create(Origin::root(), user_id, true)); assert!(!CollectionMaxSupply::::contains_key(collection_id)); assert_ok!(Uniques::set_collection_max_supply( @@ -695,15 +695,48 @@ fn max_supply_should_work() { }); } +#[test] +fn try_increment_id_works() { + new_test_ext().execute_with(|| { + // should fail because the next `CollectionId` is not being used. + assert_noop!(Uniques::try_increment_id(Origin::signed(2)), Error::::NextIdNotUsed); + + // create two collections & check for events. + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert!(events().contains(&Event::::NextCollectionIdIncremented { next_id: 1 })); + assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert!(events().contains(&Event::::NextCollectionIdIncremented { next_id: 2 })); + + // there are now two collections. + assert_eq!(Uniques::get_next_id(), 2); + + // reset the collections counter to test if the `try_increment_id` + // works. + Uniques::set_next_id(0); + assert_ok!(Uniques::try_increment_id(Origin::signed(2))); + + // `try_increment_id` should emit an event when successful. + assert!(events().contains(&Event::::NextCollectionIdIncremented { next_id: 1 })); + + // because reset, the collections count should be now 1 + assert_eq!(Uniques::get_next_id(), 1); + + // increment the collections count again. + assert_ok!(Uniques::try_increment_id(Origin::signed(2))); + // should fail because the next `CollectionId` is not being used. + assert_noop!(Uniques::try_increment_id(Origin::signed(2)), Error::::NextIdNotUsed); + }); +} + #[test] fn set_price_should_work() { new_test_ext().execute_with(|| { let user_id = 1; - let collection_id = 0; + let collection_id: u32 = 0; let item_1 = 1; let item_2 = 2; - assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true)); + assert_ok!(Uniques::force_create(Origin::root(), user_id, true)); assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_1, user_id)); assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_2, user_id)); @@ -755,7 +788,7 @@ fn buy_item_should_work() { let user_1 = 1; let user_2 = 2; let user_3 = 3; - let collection_id = 0; + let collection_id: u32 = 0; let item_1 = 1; let item_2 = 2; let item_3 = 3; @@ -767,7 +800,7 @@ fn buy_item_should_work() { Balances::make_free_balance_be(&user_2, initial_balance); Balances::make_free_balance_be(&user_3, initial_balance); - assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_1, true)); + assert_ok!(Uniques::force_create(Origin::root(), user_1, true)); assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_1, user_1)); assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_2, user_1)); diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 7c8cb170b1b1d..75bb89f26b428 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,12 +18,12 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-07-13, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `test-bench-bot`, CPU: `Intel(R) Xeon(R) CPU @ 3.10GHz` +//! DATE: 2022-07-15, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet // --steps=50 @@ -70,6 +70,7 @@ pub trait WeightInfo { fn cancel_approval() -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; + fn try_increment_id() -> Weight; fn set_price() -> Weight; fn buy_item() -> Weight; } @@ -77,19 +78,21 @@ pub trait WeightInfo { /// Weights for pallet_uniques using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { + // Storage: Uniques NextCollectionId (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (33_075_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + (30_481_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) } + // Storage: Uniques NextCollectionId (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (19_528_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + (19_811_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:0) @@ -104,12 +107,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 25_000 - .saturating_add((13_639_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 25_000 - .saturating_add((2_393_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 25_000 - .saturating_add((2_217_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 17_000 + .saturating_add((10_950_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 17_000 + .saturating_add((1_657_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 17_000 + .saturating_add((1_512_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(4 as Weight)) @@ -122,7 +125,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (42_146_000 as Weight) + (36_980_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -131,7 +134,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - (42_960_000 as Weight) + (38_771_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -140,7 +143,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - (33_025_000 as Weight) + (29_914_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -149,8 +152,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 24_000 - .saturating_add((15_540_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 16_000 + .saturating_add((12_759_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -159,26 +162,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (25_194_000 as Weight) + (22_425_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (25_397_000 as Weight) + (23_011_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (19_278_000 as Weight) + (17_718_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (19_304_000 as Weight) + (17_619_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -186,20 +189,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (28_615_000 as Weight) + (25_869_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (19_943_000 as Weight) + (18_058_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (22_583_000 as Weight) + (20_720_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -207,7 +210,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (47_520_000 as Weight) + (41_808_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -215,69 +218,76 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (45_316_000 as Weight) + (39_866_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (38_391_000 as Weight) + (34_767_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (38_023_000 as Weight) + (33_910_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (37_398_000 as Weight) + (33_827_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (35_621_000 as Weight) + (31_998_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (25_856_000 as Weight) + (23_607_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (26_098_000 as Weight) + (23_341_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (24_076_000 as Weight) + (21_969_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (22_035_000 as Weight) + (20_355_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Uniques NextCollectionId (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) + fn try_increment_id() -> Weight { + (19_233_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - (22_534_000 as Weight) + (20_733_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -286,7 +296,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - (45_272_000 as Weight) + (40_798_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -294,19 +304,21 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { + // Storage: Uniques NextCollectionId (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (33_075_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + (30_481_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } + // Storage: Uniques NextCollectionId (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (19_528_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + (19_811_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:0) @@ -321,12 +333,12 @@ impl WeightInfo for () { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 25_000 - .saturating_add((13_639_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 25_000 - .saturating_add((2_393_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 25_000 - .saturating_add((2_217_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 17_000 + .saturating_add((10_950_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 17_000 + .saturating_add((1_657_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 17_000 + .saturating_add((1_512_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) @@ -339,7 +351,7 @@ impl WeightInfo for () { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (42_146_000 as Weight) + (36_980_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -348,7 +360,7 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - (42_960_000 as Weight) + (38_771_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -357,7 +369,7 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - (33_025_000 as Weight) + (29_914_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -366,8 +378,8 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 24_000 - .saturating_add((15_540_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 16_000 + .saturating_add((12_759_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -376,26 +388,26 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (25_194_000 as Weight) + (22_425_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (25_397_000 as Weight) + (23_011_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (19_278_000 as Weight) + (17_718_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (19_304_000 as Weight) + (17_619_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -403,20 +415,20 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (28_615_000 as Weight) + (25_869_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (19_943_000 as Weight) + (18_058_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (22_583_000 as Weight) + (20_720_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -424,7 +436,7 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (47_520_000 as Weight) + (41_808_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -432,69 +444,76 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (45_316_000 as Weight) + (39_866_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (38_391_000 as Weight) + (34_767_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (38_023_000 as Weight) + (33_910_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (37_398_000 as Weight) + (33_827_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (35_621_000 as Weight) + (31_998_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (25_856_000 as Weight) + (23_607_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (26_098_000 as Weight) + (23_341_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (24_076_000 as Weight) + (21_969_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (22_035_000 as Weight) + (20_355_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Uniques NextCollectionId (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) + fn try_increment_id() -> Weight { + (19_233_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - (22_534_000 as Weight) + (20_733_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -503,7 +522,7 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - (45_272_000 as Weight) + (40_798_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } From 4d598040e0369b02cd24e8e67eaf317d09f74f85 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 1 Aug 2022 11:44:56 +0100 Subject: [PATCH 1021/1472] remove unused staking trait bound (#11942) --- frame/nomination-pools/benchmarking/src/mock.rs | 8 -------- frame/nomination-pools/test-staking/src/mock.rs | 8 -------- frame/session/benchmarking/src/mock.rs | 10 ---------- frame/staking/src/mock.rs | 11 +---------- frame/staking/src/pallet/mod.rs | 4 ++-- 5 files changed, 3 insertions(+), 38 deletions(-) diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 1c74c301e562d..d239d4f072b80 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -168,14 +168,6 @@ impl pallet_nomination_pools::Config for Runtime { impl crate::Config for Runtime {} -impl frame_system::offchain::SendTransactionTypes for Runtime -where - Call: From, -{ - type OverarchingCall = Call; - type Extrinsic = UncheckedExtrinsic; -} - type Block = frame_system::mocking::MockBlock; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; frame_support::construct_runtime!( diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 852b2c319f376..055ba7b4b3c06 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -180,14 +180,6 @@ impl pallet_nomination_pools::Config for Runtime { type PalletId = PoolsPalletId; } -impl frame_system::offchain::SendTransactionTypes for Runtime -where - Call: From, -{ - type OverarchingCall = Call; - type Extrinsic = UncheckedExtrinsic; -} - type Block = frame_system::mocking::MockBlock; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index c777f2c56de3a..2181493f72947 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -144,16 +144,6 @@ parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; } -pub type Extrinsic = sp_runtime::testing::TestXt; - -impl frame_system::offchain::SendTransactionTypes for Test -where - Call: From, -{ - type OverarchingCall = Call; - type Extrinsic = Extrinsic; -} - pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { type System = Test; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 70d00c2b648d8..d9dc97f9c1127 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -33,7 +33,7 @@ use sp_core::H256; use sp_io; use sp_runtime::{ curve::PiecewiseLinear, - testing::{Header, TestXt, UintAuthorityId}, + testing::{Header, UintAuthorityId}, traits::{IdentityLookup, Zero}, }; use sp_staking::offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}; @@ -304,15 +304,6 @@ impl crate::pallet::pallet::Config for Test { type WeightInfo = (); } -impl frame_system::offchain::SendTransactionTypes for Test -where - Call: From, -{ - type OverarchingCall = Call; - type Extrinsic = Extrinsic; -} - -pub type Extrinsic = TestXt; pub(crate) type StakingCall = crate::Call; pub(crate) type TestRuntimeCall = ::Call; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index c999020c28167..4ce96ab68b11a 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -27,7 +27,7 @@ use frame_support::{ }, weights::Weight, }; -use frame_system::{ensure_root, ensure_signed, offchain::SendTransactionTypes, pallet_prelude::*}; +use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; use sp_runtime::{ traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero}, Perbill, Percent, @@ -73,7 +73,7 @@ pub mod pallet { } #[pallet::config] - pub trait Config: frame_system::Config + SendTransactionTypes> { + pub trait Config: frame_system::Config { /// The staking balance. type Currency: LockableCurrency< Self::AccountId, From 6401300a2ff7ce013385f2c61fc9a3798bd4272d Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 1 Aug 2022 22:24:22 +0800 Subject: [PATCH 1022/1472] Add and implement MaxEncodedLen to token traits (#11945) * Add and implement MaxEncodedLen bounds to token traits * cargo fmt * Update UI test expectations --- frame/support/src/traits/tokens/misc.rs | 31 ++++++++++++++----- .../pallet_ui/storage_info_unsatisfied.stderr | 2 +- .../storage_info_unsatisfied_nmap.stderr | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index fbbef6c31822f..294d0e89c8b9e 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -17,7 +17,7 @@ //! Miscellaneous types. -use codec::{Decode, Encode, FullCodec}; +use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero}; use sp_core::RuntimeDebug; use sp_runtime::{ArithmeticError, DispatchError, TokenError}; @@ -116,7 +116,9 @@ pub enum ExistenceRequirement { } /// Status of funds. -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] +#[derive( + PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen, +)] pub enum BalanceStatus { /// Funds are free, as corresponding to `free` item in Balances. Free, @@ -126,7 +128,7 @@ pub enum BalanceStatus { bitflags::bitflags! { /// Reasons for moving funds out of an account. - #[derive(Encode, Decode)] + #[derive(Encode, Decode, MaxEncodedLen)] pub struct WithdrawReasons: u8 { /// In order to pay for (system) transaction costs. const TRANSACTION_PAYMENT = 0b00000001; @@ -161,16 +163,29 @@ impl WithdrawReasons { } /// Simple amalgamation trait to collect together properties for an AssetId under one roof. -pub trait AssetId: FullCodec + Copy + Eq + PartialEq + Debug + scale_info::TypeInfo {} -impl AssetId for T {} +pub trait AssetId: + FullCodec + Copy + Eq + PartialEq + Debug + scale_info::TypeInfo + MaxEncodedLen +{ +} +impl AssetId + for T +{ +} /// Simple amalgamation trait to collect together properties for a Balance under one roof. pub trait Balance: - AtLeast32BitUnsigned + FullCodec + Copy + Default + Debug + scale_info::TypeInfo + AtLeast32BitUnsigned + FullCodec + Copy + Default + Debug + scale_info::TypeInfo + MaxEncodedLen { } -impl Balance - for T +impl< + T: AtLeast32BitUnsigned + + FullCodec + + Copy + + Default + + Debug + + scale_info::TypeInfo + + MaxEncodedLen, + > Balance for T { } diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index d87e6900197f5..c2ec8cf7f4d05 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -13,5 +13,5 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 70 others + and 72 others = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index bc8e99cd65006..dbbc426de2906 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -13,6 +13,6 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 70 others + and 72 others = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` From 457de070e4a847dc66bba6c20e03c14346fb5619 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 1 Aug 2022 20:56:19 +0200 Subject: [PATCH 1023/1472] Remove `remove_member_wrong_refund` from `phragmen` WeightInfo (#11952) * Remove 'remove_member_wrong_refund' from WeightInfo Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/bench-bot.sh" pallet dev pallet_elections_phragmen Co-authored-by: command-bot <> --- frame/elections-phragmen/src/weights.rs | 181 ++++++++++++------------ 1 file changed, 93 insertions(+), 88 deletions(-) diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 5ad986bf142a3..07ee7aa2012ad 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -18,22 +18,24 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-08-01, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_elections_phragmen // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --pallet=pallet_elections_phragmen +// --chain=dev // --output=./frame/elections-phragmen/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,7 +56,6 @@ pub trait WeightInfo { fn renounce_candidacy_runners_up() -> Weight; fn remove_member_without_replacement() -> Weight; fn remove_member_with_replacement() -> Weight; - fn remove_member_wrong_refund() -> Weight; fn clean_defunct_voters(v: u32, d: u32, ) -> Weight; fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight; } @@ -67,10 +68,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections RunnersUp (r:1 w:0) // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - (27_798_000 as Weight) - // Standard Error: 5_000 - .saturating_add((238_000 as Weight).saturating_mul(v as Weight)) + (26_143_000 as Weight) + // Standard Error: 23_000 + .saturating_add((297_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -79,10 +81,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections RunnersUp (r:1 w:0) // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - (41_241_000 as Weight) - // Standard Error: 8_000 - .saturating_add((259_000 as Weight).saturating_mul(v as Weight)) + (40_431_000 as Weight) + // Standard Error: 6_000 + .saturating_add((205_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -91,35 +94,38 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections RunnersUp (r:1 w:0) // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - (41_313_000 as Weight) - // Standard Error: 8_000 - .saturating_add((255_000 as Weight).saturating_mul(v as Weight)) + (40_188_000 as Weight) + // Standard Error: 6_000 + .saturating_add((225_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (39_218_000 as Weight) + (38_031_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) + /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - (41_348_000 as Weight) - // Standard Error: 1_000 - .saturating_add((112_000 as Weight).saturating_mul(c as Weight)) + (43_715_000 as Weight) + // Standard Error: 0 + .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) + /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (35_522_000 as Weight) + (47_882_000 as Weight) // Standard Error: 1_000 - .saturating_add((92_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((25_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -129,13 +135,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (47_887_000 as Weight) + (45_600_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (36_271_000 as Weight) + (34_959_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -143,34 +149,29 @@ impl WeightInfo for SubstrateWeight { fn remove_member_without_replacement() -> Weight { (2_000_000_000_000 as Weight) } - // Storage: Elections RunnersUp (r:1 w:1) // Storage: Elections Members (r:1 w:1) // Storage: System Account (r:1 w:1) + // Storage: Elections RunnersUp (r:1 w:1) // Storage: Council Prime (r:1 w:1) // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (55_024_000 as Weight) + (52_684_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } - // Storage: Elections RunnersUp (r:1 w:0) - fn remove_member_wrong_refund() -> Weight { - (13_089_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - } - // Storage: Elections Voting (r:251 w:250) + // Storage: Elections Voting (r:5001 w:5000) // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) // Storage: Elections Candidates (r:1 w:0) - // Storage: Balances Locks (r:250 w:250) - // Storage: System Account (r:250 w:250) - fn clean_defunct_voters(v: u32, d: u32, ) -> Weight { + // Storage: Balances Locks (r:5000 w:5000) + // Storage: System Account (r:5000 w:5000) + /// The range of component `v` is `[5000, 10000]`. + /// The range of component `d` is `[1, 5000]`. + fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 40_000 - .saturating_add((51_848_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 38_000 - .saturating_add((537_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 65_000 + .saturating_add((64_009_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -178,21 +179,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:1) // Storage: Elections RunnersUp (r:1 w:1) - // Storage: Elections Voting (r:502 w:0) + // Storage: Elections Voting (r:10001 w:0) // Storage: Council Proposals (r:1 w:0) // Storage: Elections ElectionRounds (r:1 w:1) // Storage: Council Members (r:0 w:1) // Storage: Council Prime (r:0 w:1) - // Storage: System Account (r:2 w:2) + // Storage: System Account (r:19 w:19) + /// The range of component `c` is `[1, 1000]`. + /// The range of component `v` is `[1, 10000]`. + /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_664_000 - .saturating_add((30_736_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 692_000 - .saturating_add((49_739_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 47_000 - .saturating_add((3_363_000 as Weight).saturating_mul(e as Weight)) - .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) + // Standard Error: 778_000 + .saturating_add((81_049_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 51_000 + .saturating_add((4_420_000 as Weight).saturating_mul(e as Weight)) + .saturating_add(T::DbWeight::get().reads(279 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } @@ -205,10 +208,11 @@ impl WeightInfo for () { // Storage: Elections RunnersUp (r:1 w:0) // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - (27_798_000 as Weight) - // Standard Error: 5_000 - .saturating_add((238_000 as Weight).saturating_mul(v as Weight)) + (26_143_000 as Weight) + // Standard Error: 23_000 + .saturating_add((297_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -217,10 +221,11 @@ impl WeightInfo for () { // Storage: Elections RunnersUp (r:1 w:0) // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - (41_241_000 as Weight) - // Standard Error: 8_000 - .saturating_add((259_000 as Weight).saturating_mul(v as Weight)) + (40_431_000 as Weight) + // Standard Error: 6_000 + .saturating_add((205_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -229,35 +234,38 @@ impl WeightInfo for () { // Storage: Elections RunnersUp (r:1 w:0) // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - (41_313_000 as Weight) - // Standard Error: 8_000 - .saturating_add((255_000 as Weight).saturating_mul(v as Weight)) + (40_188_000 as Weight) + // Standard Error: 6_000 + .saturating_add((225_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (39_218_000 as Weight) + (38_031_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) + /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - (41_348_000 as Weight) - // Standard Error: 1_000 - .saturating_add((112_000 as Weight).saturating_mul(c as Weight)) + (43_715_000 as Weight) + // Standard Error: 0 + .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) + /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (35_522_000 as Weight) + (47_882_000 as Weight) // Standard Error: 1_000 - .saturating_add((92_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((25_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -267,13 +275,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (47_887_000 as Weight) + (45_600_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (36_271_000 as Weight) + (34_959_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -281,34 +289,29 @@ impl WeightInfo for () { fn remove_member_without_replacement() -> Weight { (2_000_000_000_000 as Weight) } - // Storage: Elections RunnersUp (r:1 w:1) // Storage: Elections Members (r:1 w:1) // Storage: System Account (r:1 w:1) + // Storage: Elections RunnersUp (r:1 w:1) // Storage: Council Prime (r:1 w:1) // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (55_024_000 as Weight) + (52_684_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } - // Storage: Elections RunnersUp (r:1 w:0) - fn remove_member_wrong_refund() -> Weight { - (13_089_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - } - // Storage: Elections Voting (r:251 w:250) + // Storage: Elections Voting (r:5001 w:5000) // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) // Storage: Elections Candidates (r:1 w:0) - // Storage: Balances Locks (r:250 w:250) - // Storage: System Account (r:250 w:250) - fn clean_defunct_voters(v: u32, d: u32, ) -> Weight { + // Storage: Balances Locks (r:5000 w:5000) + // Storage: System Account (r:5000 w:5000) + /// The range of component `v` is `[5000, 10000]`. + /// The range of component `d` is `[1, 5000]`. + fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 40_000 - .saturating_add((51_848_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 38_000 - .saturating_add((537_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 65_000 + .saturating_add((64_009_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -316,21 +319,23 @@ impl WeightInfo for () { // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:1) // Storage: Elections RunnersUp (r:1 w:1) - // Storage: Elections Voting (r:502 w:0) + // Storage: Elections Voting (r:10001 w:0) // Storage: Council Proposals (r:1 w:0) // Storage: Elections ElectionRounds (r:1 w:1) // Storage: Council Members (r:0 w:1) // Storage: Council Prime (r:0 w:1) - // Storage: System Account (r:2 w:2) + // Storage: System Account (r:19 w:19) + /// The range of component `c` is `[1, 1000]`. + /// The range of component `v` is `[1, 10000]`. + /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_664_000 - .saturating_add((30_736_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 692_000 - .saturating_add((49_739_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 47_000 - .saturating_add((3_363_000 as Weight).saturating_mul(e as Weight)) - .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) + // Standard Error: 778_000 + .saturating_add((81_049_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 51_000 + .saturating_add((4_420_000 as Weight).saturating_mul(e as Weight)) + .saturating_add(RocksDbWeight::get().reads(279 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } From a5fe1dc09fb047c267d476c8bbe058594325aae3 Mon Sep 17 00:00:00 2001 From: lisa-parity <92225469+lisa-parity@users.noreply.github.com> Date: Mon, 1 Aug 2022 11:58:42 -0700 Subject: [PATCH 1024/1472] Update the link to the runtime versioning topic (#11957) --- bin/node-template/runtime/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index a4382cc9038ce..88fc86db02ef9 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -89,8 +89,8 @@ pub mod opaque { } } -// To learn more about runtime versioning and what each of the following value means: -// https://docs.substrate.io/v3/runtime/upgrades#runtime-versioning +// To learn more about runtime versioning, see: +// https://docs.substrate.io/main-docs/build/upgrade#runtime-versioning #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node-template"), From 84cc128a6edc1c87b68954e6d64407ee36be45c1 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 2 Aug 2022 09:06:36 +0200 Subject: [PATCH 1025/1472] fix(rpc middleware): fix `is_error` bug (#11951) * fix(rpc middleware): fix `is_error` bug * Update client/rpc-servers/src/middleware.rs --- client/rpc-servers/src/middleware.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/rpc-servers/src/middleware.rs b/client/rpc-servers/src/middleware.rs index 5b2ee4bedb7dd..cb9918268f4de 100644 --- a/client/rpc-servers/src/middleware.rs +++ b/client/rpc-servers/src/middleware.rs @@ -176,7 +176,9 @@ impl Middleware for RpcMiddleware { .with_label_values(&[ self.transport_label, name, - if success { "true" } else { "false" }, + // the label "is_error", so `success` should be regarded as false + // and vice-versa to be registrered correctly. + if success { "false" } else { "true" }, ]) .inc(); } From 938c0d9363131d862bcc04d2cf913ce9cb9dd5fe Mon Sep 17 00:00:00 2001 From: bernardo Date: Tue, 2 Aug 2022 13:43:57 +0100 Subject: [PATCH 1026/1472] benchmarking f32 step calculation (#11890) * benchmark steps with f32 * divide by self.steps - 1 * avoid steps <= 1 * Fix step size Signed-off-by: Oliver Tale-Yazdi * Fix 'steps' print and print number of args Signed-off-by: Oliver Tale-Yazdi * Add Test Signed-off-by: Oliver Tale-Yazdi * fix comments * Remove unneeded comment Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- bin/node/cli/tests/benchmark_pallet_works.rs | 49 +++++++++++++++++++ .../benchmarking-cli/src/pallet/command.rs | 27 ++++++---- 2 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 bin/node/cli/tests/benchmark_pallet_works.rs diff --git a/bin/node/cli/tests/benchmark_pallet_works.rs b/bin/node/cli/tests/benchmark_pallet_works.rs new file mode 100644 index 0000000000000..bf29c0e308bcb --- /dev/null +++ b/bin/node/cli/tests/benchmark_pallet_works.rs @@ -0,0 +1,49 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use assert_cmd::cargo::cargo_bin; +use std::process::Command; + +pub mod common; + +/// `benchmark pallet` works for the different combinations of `steps` and `repeat`. +#[test] +fn benchmark_pallet_works() { + // Some invalid combinations: + benchmark_pallet(0, 10, false); + benchmark_pallet(1, 10, false); + // ... and some valid: + benchmark_pallet(2, 1, true); + benchmark_pallet(50, 20, true); + benchmark_pallet(20, 50, true); +} + +fn benchmark_pallet(steps: u32, repeat: u32, should_work: bool) { + let output = Command::new(cargo_bin("substrate")) + .args(["benchmark", "pallet", "--dev"]) + // Use the `addition` benchmark since is the fastest. + .args(["--pallet", "frame-benchmarking", "--extrinsic", "addition"]) + .args(["--steps", &format!("{}", steps), "--repeat", &format!("{}", repeat)]) + .output() + .unwrap(); + + if output.status.success() != should_work { + let log = String::from_utf8_lossy(&output.stderr).to_string(); + panic!("Test failed:\n{}", log); + } +} diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index fae5a4494cdc4..fb6f1393650ad 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -236,14 +236,22 @@ impl PalletCmd { let lowest = self.lowest_range_values.get(idx).cloned().unwrap_or(*low); let highest = self.highest_range_values.get(idx).cloned().unwrap_or(*high); - let diff = highest - lowest; + let diff = + highest.checked_sub(lowest).ok_or("`low` cannot be higher than `high`")?; - // Create up to `STEPS` steps for that component between high and low. - let step_size = (diff / self.steps).max(1); - let num_of_steps = diff / step_size + 1; - for s in 0..num_of_steps { + // The slope logic needs at least two points + // to compute a slope. + if self.steps < 2 { + return Err("`steps` must be at least 2.".into()) + } + + let step_size = (diff as f32 / (self.steps - 1) as f32).max(0.0); + + for s in 0..self.steps { // This is the value we will be testing for component `name` - let component_value = lowest + step_size * s; + let component_value = ((lowest as f32 + step_size * s as f32) as u32) + .min(highest) + .max(lowest); // Select the max value for all the other components. let c: Vec<(BenchmarkParameter, u32)> = components @@ -364,13 +372,14 @@ impl PalletCmd { if elapsed >= time::Duration::from_secs(5) { timer = time::SystemTime::now(); log::info!( - "Running Benchmark: {}.{} {}/{} {}/{}", + "Running Benchmark: {}.{}({} args) {}/{} {}/{}", String::from_utf8(pallet.clone()) .expect("Encoded from String; qed"), String::from_utf8(extrinsic.clone()) .expect("Encoded from String; qed"), - s + 1, // s starts at 0. todo show step - self.steps, + components.len(), + s + 1, // s starts at 0. + all_components.len(), r + 1, self.external_repeat, ); From 028ee356720d9b8de9995acae93de68af4ef8ece Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 2 Aug 2022 15:01:15 +0200 Subject: [PATCH 1027/1472] [ci] chores: remove cargo install nextest (#11961) --- scripts/ci/gitlab/pipeline/test.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index b2daf5bada24f..7a9f57e9a7734 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -213,8 +213,6 @@ test-linux-stable: parallel: 3 script: - rusty-cachier snapshot create - # TODO: remove when current paritytech/ci-linux:staging (with rust stable 1.62) is switched to production - - time cargo install cargo-nextest # this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests # tests are partitioned by nextest and executed in parallel on $CI_NODE_TOTAL runners # node-cli is excluded until https://github.com/paritytech/substrate/issues/11321 fixed @@ -373,8 +371,6 @@ test-wasmer-sandbox: parallel: 3 script: - rusty-cachier snapshot create - # TODO: remove when current paritytech/ci-linux:staging (with rust stable 1.62) is switched to production - - cargo install cargo-nextest - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" - time cargo nextest run --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} - if [ ${CI_NODE_INDEX} == 1 ]; then rusty-cachier cache upload; fi From 43427bd3dd9b04e1830c497df47042a7f5a7aa6e Mon Sep 17 00:00:00 2001 From: Nikos Kontakis Date: Tue, 2 Aug 2022 17:25:52 +0200 Subject: [PATCH 1028/1472] Rename `node-runtime` to `node-kitchensink-runtime` (#11930) * Rename node=runtime to kithensink-runtime * Undo md formatting --- Cargo.lock | 198 +++++++++--------- bin/node/bench/Cargo.toml | 2 +- bin/node/bench/src/import.rs | 4 +- bin/node/cli/Cargo.toml | 6 +- bin/node/cli/benches/block_production.rs | 6 +- bin/node/cli/benches/transaction_pool.rs | 2 +- bin/node/cli/src/benchmarking.rs | 2 +- bin/node/cli/src/chain_spec.rs | 6 +- bin/node/cli/src/command.rs | 4 +- bin/node/cli/src/service.rs | 42 ++-- bin/node/executor/Cargo.toml | 2 +- bin/node/executor/benches/bench.rs | 12 +- bin/node/executor/src/lib.rs | 4 +- bin/node/executor/tests/basic.rs | 6 +- bin/node/executor/tests/common.rs | 12 +- bin/node/executor/tests/fees.rs | 4 +- bin/node/executor/tests/submit_transaction.rs | 2 +- bin/node/runtime/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- bin/node/testing/src/bench.rs | 15 +- bin/node/testing/src/client.rs | 8 +- bin/node/testing/src/genesis.rs | 2 +- bin/node/testing/src/keyring.rs | 2 +- bin/utils/subkey/src/main.rs | 2 +- docs/README.adoc | 2 +- scripts/ci/gitlab/pipeline/test.yml | 6 +- .../generate-bags/node-runtime/Cargo.toml | 4 +- .../generate-bags/node-runtime/src/main.rs | 7 +- utils/wasm-builder/src/lib.rs | 2 +- 29 files changed, 188 insertions(+), 180 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b76f61df7912..733c6d73d2709 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3299,6 +3299,100 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "kitchensink-runtime" +version = "3.0.0-dev" +dependencies = [ + "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", + "log", + "node-primitives", + "pallet-alliance", + "pallet-asset-tx-payment", + "pallet-assets", + "pallet-authority-discovery", + "pallet-authorship", + "pallet-babe", + "pallet-bags-list", + "pallet-balances", + "pallet-bounties", + "pallet-child-bounties", + "pallet-collective", + "pallet-contracts", + "pallet-contracts-primitives", + "pallet-contracts-rpc-runtime-api", + "pallet-conviction-voting", + "pallet-democracy", + "pallet-election-provider-multi-phase", + "pallet-election-provider-support-benchmarking", + "pallet-elections-phragmen", + "pallet-gilt", + "pallet-grandpa", + "pallet-identity", + "pallet-im-online", + "pallet-indices", + "pallet-lottery", + "pallet-membership", + "pallet-mmr", + "pallet-multisig", + "pallet-nomination-pools", + "pallet-nomination-pools-benchmarking", + "pallet-nomination-pools-runtime-api", + "pallet-offences", + "pallet-offences-benchmarking", + "pallet-preimage", + "pallet-proxy", + "pallet-randomness-collective-flip", + "pallet-ranked-collective", + "pallet-recovery", + "pallet-referenda", + "pallet-remark", + "pallet-scheduler", + "pallet-session", + "pallet-session-benchmarking", + "pallet-society", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-state-trie-migration", + "pallet-sudo", + "pallet-timestamp", + "pallet-tips", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-transaction-storage", + "pallet-treasury", + "pallet-uniques", + "pallet-utility", + "pallet-vesting", + "pallet-whitelist", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-authority-discovery", + "sp-block-builder", + "sp-consensus-babe", + "sp-core", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-sandbox", + "sp-session", + "sp-staking", + "sp-std", + "sp-transaction-pool", + "sp-version", + "static_assertions", + "substrate-wasm-builder", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -4511,12 +4605,12 @@ dependencies = [ "futures", "hash-db", "hex", + "kitchensink-runtime", "kvdb", "kvdb-rocksdb", "lazy_static", "log", "node-primitives", - "node-runtime", "node-testing", "parity-db", "parity-util-mem", @@ -4553,13 +4647,13 @@ dependencies = [ "futures", "hex-literal", "jsonrpsee", + "kitchensink-runtime", "log", "nix 0.23.1", "node-executor", "node-inspect", "node-primitives", "node-rpc", - "node-runtime", "pallet-asset-tx-payment", "pallet-balances", "pallet-im-online", @@ -4631,8 +4725,8 @@ dependencies = [ "frame-support", "frame-system", "futures", + "kitchensink-runtime", "node-primitives", - "node-runtime", "node-testing", "pallet-balances", "pallet-contracts", @@ -4716,107 +4810,13 @@ dependencies = [ "substrate-state-trie-migration-rpc", ] -[[package]] -name = "node-runtime" -version = "3.0.0-dev" -dependencies = [ - "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", - "log", - "node-primitives", - "pallet-alliance", - "pallet-asset-tx-payment", - "pallet-assets", - "pallet-authority-discovery", - "pallet-authorship", - "pallet-babe", - "pallet-bags-list", - "pallet-balances", - "pallet-bounties", - "pallet-child-bounties", - "pallet-collective", - "pallet-contracts", - "pallet-contracts-primitives", - "pallet-contracts-rpc-runtime-api", - "pallet-conviction-voting", - "pallet-democracy", - "pallet-election-provider-multi-phase", - "pallet-election-provider-support-benchmarking", - "pallet-elections-phragmen", - "pallet-gilt", - "pallet-grandpa", - "pallet-identity", - "pallet-im-online", - "pallet-indices", - "pallet-lottery", - "pallet-membership", - "pallet-mmr", - "pallet-multisig", - "pallet-nomination-pools", - "pallet-nomination-pools-benchmarking", - "pallet-nomination-pools-runtime-api", - "pallet-offences", - "pallet-offences-benchmarking", - "pallet-preimage", - "pallet-proxy", - "pallet-randomness-collective-flip", - "pallet-ranked-collective", - "pallet-recovery", - "pallet-referenda", - "pallet-remark", - "pallet-scheduler", - "pallet-session", - "pallet-session-benchmarking", - "pallet-society", - "pallet-staking", - "pallet-staking-reward-curve", - "pallet-state-trie-migration", - "pallet-sudo", - "pallet-timestamp", - "pallet-tips", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-transaction-storage", - "pallet-treasury", - "pallet-uniques", - "pallet-utility", - "pallet-vesting", - "pallet-whitelist", - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-authority-discovery", - "sp-block-builder", - "sp-consensus-babe", - "sp-core", - "sp-inherents", - "sp-io", - "sp-offchain", - "sp-runtime", - "sp-sandbox", - "sp-session", - "sp-staking", - "sp-std", - "sp-transaction-pool", - "sp-version", - "static_assertions", - "substrate-wasm-builder", -] - [[package]] name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ "clap 3.1.18", "generate-bags", - "node-runtime", + "kitchensink-runtime", ] [[package]] @@ -4905,10 +4905,10 @@ dependencies = [ "frame-system", "fs_extra", "futures", + "kitchensink-runtime", "log", "node-executor", "node-primitives", - "node-runtime", "pallet-asset-tx-payment", "pallet-transaction-payment", "parity-scale-codec", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 90c325b8e5b32..4d090c71a72e9 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -13,7 +13,7 @@ clap = { version = "3.1.18", features = ["derive"] } log = "0.4.17" node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } -node-runtime = { version = "3.0.0-dev", path = "../runtime" } +kitchensink-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } diff --git a/bin/node/bench/src/import.rs b/bin/node/bench/src/import.rs index b9229fbd5331d..47f630eb68700 100644 --- a/bin/node/bench/src/import.rs +++ b/bin/node/bench/src/import.rs @@ -148,13 +148,13 @@ impl core::Benchmark for ImportBenchmark { // the transaction fee into the treasury // - extrinsic success assert_eq!( - node_runtime::System::events().len(), + kitchensink_runtime::System::events().len(), (self.block.extrinsics.len() - 1) * 8 + 1, ); }, BlockType::Noop => { assert_eq!( - node_runtime::System::events().len(), + kitchensink_runtime::System::events().len(), // should be 2 per signed extrinsic + 1 per unsigned // we have 1 unsigned and the rest are signed in the block // those 2 events per signed are: diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index b2e24f0b33189..9dde225c0d6fb 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -87,7 +87,7 @@ pallet-asset-tx-payment = { version = "4.0.0-dev", path = "../../../frame/transa pallet-im-online = { version = "4.0.0-dev", default-features = false, path = "../../../frame/im-online" } # node-specific dependencies -node-runtime = { version = "3.0.0-dev", path = "../runtime" } +kitchensink-runtime = { version = "3.0.0-dev", path = "../runtime" } node-rpc = { version = "3.0.0-dev", path = "../rpc" } node-primitives = { version = "2.0.0", path = "../primitives" } node-executor = { version = "3.0.0-dev", path = "../executor" } @@ -159,10 +159,10 @@ cli = [ "substrate-build-script-utils", "try-runtime-cli", ] -runtime-benchmarks = ["node-runtime/runtime-benchmarks", "frame-benchmarking-cli"] +runtime-benchmarks = ["kitchensink-runtime/runtime-benchmarks", "frame-benchmarking-cli"] # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. -try-runtime = ["node-runtime/try-runtime", "try-runtime-cli"] +try-runtime = ["kitchensink-runtime/try-runtime", "try-runtime-cli"] [[bench]] name = "transaction_pool" diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index ad16ba8e4072b..6d269ccaac271 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -18,8 +18,8 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; +use kitchensink_runtime::{constants::currency::*, BalancesCall}; use node_cli::service::{create_extrinsic, FullClient}; -use node_runtime::{constants::currency::*, BalancesCall}; use sc_block_builder::{BlockBuilderProvider, BuiltBlock, RecordProof}; use sc_client_api::execution_extensions::ExecutionStrategies; use sc_consensus::{ @@ -121,9 +121,9 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { } fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { - node_runtime::UncheckedExtrinsic { + kitchensink_runtime::UncheckedExtrinsic { signature: None, - function: node_runtime::Call::Timestamp(pallet_timestamp::Call::set { now }), + function: kitchensink_runtime::Call::Timestamp(pallet_timestamp::Call::set { now }), } .into() } diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index d88c3a65b6138..580a10d6a6678 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -20,9 +20,9 @@ use std::time::Duration; use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; use futures::{future, StreamExt}; +use kitchensink_runtime::{constants::currency::*, BalancesCall, SudoCall}; use node_cli::service::{create_extrinsic, fetch_nonce, FullClient, TransactionPool}; use node_primitives::AccountId; -use node_runtime::{constants::currency::*, BalancesCall, SudoCall}; use sc_client_api::execution_extensions::ExecutionStrategies; use sc_service::{ config::{ diff --git a/bin/node/cli/src/benchmarking.rs b/bin/node/cli/src/benchmarking.rs index 52657016c046a..19bd1660a4dd9 100644 --- a/bin/node/cli/src/benchmarking.rs +++ b/bin/node/cli/src/benchmarking.rs @@ -22,8 +22,8 @@ use crate::service::{create_extrinsic, FullClient}; +use kitchensink_runtime::{BalancesCall, SystemCall}; use node_primitives::{AccountId, Balance}; -use node_runtime::{BalancesCall, SystemCall}; use sc_cli::Result; use sp_inherents::{InherentData, InherentDataProvider}; use sp_keyring::Sr25519Keyring; diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 47c3634aa00df..77e2f73dd6e18 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -20,7 +20,7 @@ use grandpa_primitives::AuthorityId as GrandpaId; use hex_literal::hex; -use node_runtime::{ +use kitchensink_runtime::{ constants::currency::*, wasm_binary_unwrap, AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, Block, CouncilConfig, DemocracyConfig, ElectionsConfig, GrandpaConfig, ImOnlineConfig, IndicesConfig, MaxNominations, NominationPoolsConfig, SessionConfig, @@ -40,8 +40,8 @@ use sp_runtime::{ Perbill, }; +pub use kitchensink_runtime::GenesisConfig; pub use node_primitives::{AccountId, Balance, Signature}; -pub use node_runtime::GenesisConfig; type AccountPublic = ::Signer; @@ -343,7 +343,7 @@ pub fn testnet_genesis( sudo: SudoConfig { key: Some(root_key) }, babe: BabeConfig { authorities: vec![], - epoch_config: Some(node_runtime::BABE_GENESIS_EPOCH_CONFIG), + epoch_config: Some(kitchensink_runtime::BABE_GENESIS_EPOCH_CONFIG), }, im_online: ImOnlineConfig { keys: vec![] }, authority_discovery: AuthorityDiscoveryConfig { keys: vec![] }, diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index df3d5a891e2ab..85e5415dbe139 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -23,9 +23,9 @@ use crate::{ Cli, Subcommand, }; use frame_benchmarking_cli::*; +use kitchensink_runtime::{ExistentialDeposit, RuntimeApi}; use node_executor::ExecutorDispatch; use node_primitives::Block; -use node_runtime::{ExistentialDeposit, RuntimeApi}; use sc_cli::{ChainSpec, Result, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; use sp_keyring::Sr25519Keyring; @@ -75,7 +75,7 @@ impl SubstrateCli for Cli { } fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { - &node_runtime::VERSION + &kitchensink_runtime::VERSION } } diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index bff4be88002fb..e0644f462cf20 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -23,9 +23,9 @@ use codec::Encode; use frame_system_rpc_runtime_api::AccountNonceApi; use futures::prelude::*; +use kitchensink_runtime::RuntimeApi; use node_executor::ExecutorDispatch; use node_primitives::Block; -use node_runtime::RuntimeApi; use sc_client_api::{BlockBackend, ExecutorProvider}; use sc_consensus_babe::{self, SlotProportion}; use sc_executor::NativeElseWasmExecutor; @@ -68,41 +68,43 @@ pub fn fetch_nonce(client: &FullClient, account: sp_core::sr25519::Pair) -> u32 pub fn create_extrinsic( client: &FullClient, sender: sp_core::sr25519::Pair, - function: impl Into, + function: impl Into, nonce: Option, -) -> node_runtime::UncheckedExtrinsic { +) -> kitchensink_runtime::UncheckedExtrinsic { let function = function.into(); let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); let best_hash = client.chain_info().best_hash; let best_block = client.chain_info().best_number; let nonce = nonce.unwrap_or_else(|| fetch_nonce(client, sender.clone())); - let period = node_runtime::BlockHashCount::get() + let period = kitchensink_runtime::BlockHashCount::get() .checked_next_power_of_two() .map(|c| c / 2) .unwrap_or(2) as u64; let tip = 0; - let extra: node_runtime::SignedExtra = ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(generic::Era::mortal( + let extra: kitchensink_runtime::SignedExtra = ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(generic::Era::mortal( period, best_block.saturated_into(), )), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_asset_tx_payment::ChargeAssetTxPayment::::from(tip, None), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + pallet_asset_tx_payment::ChargeAssetTxPayment::::from( + tip, None, + ), ); - let raw_payload = node_runtime::SignedPayload::from_raw( + let raw_payload = kitchensink_runtime::SignedPayload::from_raw( function.clone(), extra.clone(), ( (), - node_runtime::VERSION.spec_version, - node_runtime::VERSION.transaction_version, + kitchensink_runtime::VERSION.spec_version, + kitchensink_runtime::VERSION.transaction_version, genesis_hash, best_hash, (), @@ -112,10 +114,10 @@ pub fn create_extrinsic( ); let signature = raw_payload.using_encoded(|e| sender.sign(e)); - node_runtime::UncheckedExtrinsic::new_signed( + kitchensink_runtime::UncheckedExtrinsic::new_signed( function, sp_runtime::AccountId32::from(sender.public()).into(), - node_runtime::Signature::Sr25519(signature), + kitchensink_runtime::Signature::Sr25519(signature), extra, ) } @@ -565,11 +567,11 @@ pub fn new_full( mod tests { use crate::service::{new_full_base, NewFullBase}; use codec::Encode; - use node_primitives::{Block, DigestItem, Signature}; - use node_runtime::{ + use kitchensink_runtime::{ constants::{currency::CENTS, time::SLOT_DURATION}, Address, BalancesCall, Call, UncheckedExtrinsic, }; + use node_primitives::{Block, DigestItem, Signature}; use sc_client_api::BlockBackend; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy}; use sc_consensus_babe::{BabeIntermediate, CompatibleDigestItem, INTERMEDIATE_KEY}; diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 6143ea3bd8c42..71865783da8ac 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } scale-info = { version = "2.1.1", features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } node-primitives = { version = "2.0.0", path = "../primitives" } -node-runtime = { version = "3.0.0-dev", path = "../runtime" } +kitchensink-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index 61e2d1b053012..a1d31a5a966db 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -18,12 +18,12 @@ use codec::{Decode, Encode}; use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; use frame_support::Hashable; -use node_executor::ExecutorDispatch; -use node_primitives::{BlockNumber, Hash}; -use node_runtime::{ +use kitchensink_runtime::{ constants::currency::*, Block, BuildStorage, Call, CheckedExtrinsic, GenesisConfig, Header, UncheckedExtrinsic, }; +use node_executor::ExecutorDispatch; +use node_primitives::{BlockNumber, Hash}; use node_testing::keyring::*; #[cfg(feature = "wasmtime")] use sc_executor::WasmtimeInstantiationStrategy; @@ -41,7 +41,7 @@ criterion_main!(benches); /// The wasm runtime code. pub fn compact_code_unwrap() -> &'static [u8] { - node_runtime::WASM_BINARY.expect( + kitchensink_runtime::WASM_BINARY.expect( "Development wasm binary is not available. Testing is only supported with the flag \ disabled.", ) @@ -49,9 +49,9 @@ pub fn compact_code_unwrap() -> &'static [u8] { const GENESIS_HASH: [u8; 32] = [69u8; 32]; -const TRANSACTION_VERSION: u32 = node_runtime::VERSION.transaction_version; +const TRANSACTION_VERSION: u32 = kitchensink_runtime::VERSION.transaction_version; -const SPEC_VERSION: u32 = node_runtime::VERSION.spec_version; +const SPEC_VERSION: u32 = kitchensink_runtime::VERSION.spec_version; const HEAP_PAGES: u64 = 20; diff --git a/bin/node/executor/src/lib.rs b/bin/node/executor/src/lib.rs index 9f87c7d12623c..c4edf5ad22f47 100644 --- a/bin/node/executor/src/lib.rs +++ b/bin/node/executor/src/lib.rs @@ -28,10 +28,10 @@ impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; fn dispatch(method: &str, data: &[u8]) -> Option> { - node_runtime::api::dispatch(method, data) + kitchensink_runtime::api::dispatch(method, data) } fn native_version() -> sc_executor::NativeVersion { - node_runtime::native_version() + kitchensink_runtime::native_version() } } diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 31a9bd0a90496..27e848a281097 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -26,12 +26,12 @@ use sp_runtime::{ traits::Hash as HashT, transaction_validity::InvalidTransaction, ApplyExtrinsicResult, }; -use node_primitives::{Balance, Hash}; -use node_runtime::{ +use kitchensink_runtime::{ constants::{currency::*, time::SLOT_DURATION}, Balances, Call, CheckedExtrinsic, Event, Header, Runtime, System, TransactionPayment, UncheckedExtrinsic, }; +use node_primitives::{Balance, Hash}; use node_testing::keyring::*; use wat; @@ -44,7 +44,7 @@ use self::common::{sign, *}; /// have to execute provided wasm code instead of the native equivalent. This trick is used to /// test code paths that differ between native and wasm versions. pub fn bloaty_code_unwrap() -> &'static [u8] { - node_runtime::WASM_BINARY_BLOATY.expect( + kitchensink_runtime::WASM_BINARY_BLOATY.expect( "Development wasm binary is not available. \ Testing is only supported with the flag disabled.", ) diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index a2bb91056f474..407a1e09f8efb 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -35,12 +35,12 @@ use sp_runtime::{ }; use sp_state_machine::TestExternalities as CoreTestExternalities; -use node_executor::ExecutorDispatch; -use node_primitives::{BlockNumber, Hash}; -use node_runtime::{ +use kitchensink_runtime::{ constants::currency::*, Block, BuildStorage, CheckedExtrinsic, Header, Runtime, UncheckedExtrinsic, }; +use node_executor::ExecutorDispatch; +use node_primitives::{BlockNumber, Hash}; use node_testing::keyring::*; use sp_externalities::Externalities; @@ -69,7 +69,7 @@ impl AppCrypto for TestAuthorityId { /// making the binary slimmer. There is a convention to use compact version of the runtime /// as canonical. pub fn compact_code_unwrap() -> &'static [u8] { - node_runtime::WASM_BINARY.expect( + kitchensink_runtime::WASM_BINARY.expect( "Development wasm binary is not available. Testing is only supported with the flag \ disabled.", ) @@ -77,9 +77,9 @@ pub fn compact_code_unwrap() -> &'static [u8] { pub const GENESIS_HASH: [u8; 32] = [69u8; 32]; -pub const SPEC_VERSION: u32 = node_runtime::VERSION.spec_version; +pub const SPEC_VERSION: u32 = kitchensink_runtime::VERSION.spec_version; -pub const TRANSACTION_VERSION: u32 = node_runtime::VERSION.transaction_version; +pub const TRANSACTION_VERSION: u32 = kitchensink_runtime::VERSION.transaction_version; pub type TestExternalities = CoreTestExternalities; diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index e1550071d3006..008ed5f53927b 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -20,11 +20,11 @@ use frame_support::{ traits::Currency, weights::{constants::ExtrinsicBaseWeight, GetDispatchInfo, IdentityFee, WeightToFee}, }; -use node_primitives::Balance; -use node_runtime::{ +use kitchensink_runtime::{ constants::{currency::*, time::SLOT_DURATION}, Balances, Call, CheckedExtrinsic, Multiplier, Runtime, TransactionByteFee, TransactionPayment, }; +use node_primitives::Balance; use node_testing::keyring::*; use sp_core::NeverNativeValue; use sp_runtime::{traits::One, Perbill}; diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs index 7df13a577006e..be43f3c78674f 100644 --- a/bin/node/executor/tests/submit_transaction.rs +++ b/bin/node/executor/tests/submit_transaction.rs @@ -17,7 +17,7 @@ use codec::Decode; use frame_system::offchain::{SendSignedTransaction, Signer, SubmitTransaction}; -use node_runtime::{Executive, Indices, Runtime, UncheckedExtrinsic}; +use kitchensink_runtime::{Executive, Indices, Runtime, UncheckedExtrinsic}; use sp_application_crypto::AppKey; use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt}; use sp_keyring::sr25519::Keyring::Alice; diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index d3138ce51de9c..10b15b6ec554d 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "node-runtime" +name = "kitchensink-runtime" version = "3.0.0-dev" authors = ["Parity Technologies "] edition = "2021" diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 7caf10366b48c..ed81301e45189 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -21,7 +21,7 @@ tempfile = "3.1.0" frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } -node-runtime = { version = "3.0.0-dev", path = "../runtime" } +kitchensink-runtime = { version = "3.0.0-dev", path = "../runtime" } pallet-asset-tx-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/asset-tx-payment" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 00ce7f64bc3f0..18e979b95737f 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -34,11 +34,11 @@ use crate::{ }; use codec::{Decode, Encode}; use futures::executor; -use node_primitives::Block; -use node_runtime::{ +use kitchensink_runtime::{ constants::currency::DOLLARS, AccountId, BalancesCall, Call, CheckedExtrinsic, MinimumPeriod, Signature, SystemCall, UncheckedExtrinsic, }; +use node_primitives::Block; use sc_block_builder::BlockBuilderProvider; use sc_client_api::{ execution_extensions::{ExecutionExtensions, ExecutionStrategies}, @@ -304,20 +304,21 @@ impl<'a> Iterator for BlockContentIterator<'a> { CheckedExtrinsic { signed: Some(( sender, - signed_extra(0, node_runtime::ExistentialDeposit::get() + 1), + signed_extra(0, kitchensink_runtime::ExistentialDeposit::get() + 1), )), function: match self.content.block_type { BlockType::RandomTransfersKeepAlive => Call::Balances(BalancesCall::transfer_keep_alive { dest: sp_runtime::MultiAddress::Id(receiver), - value: node_runtime::ExistentialDeposit::get() + 1, + value: kitchensink_runtime::ExistentialDeposit::get() + 1, }), BlockType::RandomTransfersReaping => { Call::Balances(BalancesCall::transfer { dest: sp_runtime::MultiAddress::Id(receiver), // Transfer so that ending balance would be 1 less than existential // deposit so that we kill the sender account. - value: 100 * DOLLARS - (node_runtime::ExistentialDeposit::get() - 1), + value: 100 * DOLLARS - + (kitchensink_runtime::ExistentialDeposit::get() - 1), }) }, BlockType::Noop => Call::System(SystemCall::remark { remark: Vec::new() }), @@ -592,9 +593,9 @@ impl BenchKeyring { } /// Generate genesis with accounts from this keyring endowed with some balance. - pub fn generate_genesis(&self) -> node_runtime::GenesisConfig { + pub fn generate_genesis(&self) -> kitchensink_runtime::GenesisConfig { crate::genesis::config_endowed( - Some(node_runtime::wasm_binary_unwrap()), + Some(kitchensink_runtime::wasm_binary_unwrap()), self.collect_account_ids(), ) } diff --git a/bin/node/testing/src/client.rs b/bin/node/testing/src/client.rs index 8cb98511098f1..590304bdd52a5 100644 --- a/bin/node/testing/src/client.rs +++ b/bin/node/testing/src/client.rs @@ -16,14 +16,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Utilities to build a `TestClient` for `node-runtime`. +//! Utilities to build a `TestClient` for `kitchensink-runtime`. use sc_service::client; use sp_runtime::BuildStorage; /// Re-export test-client utilities. pub use substrate_test_client::*; -/// Call executor for `node-runtime` `TestClient`. +/// Call executor for `kitchensink-runtime` `TestClient`. pub type ExecutorDispatch = sc_executor::NativeElseWasmExecutor; /// Default backend type. @@ -34,10 +34,10 @@ pub type Client = client::Client< Backend, client::LocalCallExecutor, node_primitives::Block, - node_runtime::RuntimeApi, + kitchensink_runtime::RuntimeApi, >; -/// Transaction for node-runtime. +/// Transaction for kitchensink-runtime. pub type Transaction = sc_client_api::backend::TransactionFor; /// Genesis configuration parameters for `TestClient`. diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index fbd28c5af0298..1eb7318db52da 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -19,7 +19,7 @@ //! Genesis Configuration. use crate::keyring::*; -use node_runtime::{ +use kitchensink_runtime::{ constants::currency::*, wasm_binary_unwrap, AccountId, BabeConfig, BalancesConfig, GenesisConfig, GrandpaConfig, IndicesConfig, SessionConfig, SocietyConfig, StakerStatus, StakingConfig, SystemConfig, BABE_GENESIS_EPOCH_CONFIG, diff --git a/bin/node/testing/src/keyring.rs b/bin/node/testing/src/keyring.rs index 41dd28bb89988..88d9dc56b0532 100644 --- a/bin/node/testing/src/keyring.rs +++ b/bin/node/testing/src/keyring.rs @@ -19,8 +19,8 @@ //! Test accounts. use codec::Encode; +use kitchensink_runtime::{CheckedExtrinsic, SessionKeys, SignedExtra, UncheckedExtrinsic}; use node_primitives::{AccountId, Balance, Index}; -use node_runtime::{CheckedExtrinsic, SessionKeys, SignedExtra, UncheckedExtrinsic}; use sp_keyring::{AccountKeyring, Ed25519Keyring, Sr25519Keyring}; use sp_runtime::generic::Era; diff --git a/bin/utils/subkey/src/main.rs b/bin/utils/subkey/src/main.rs index d85c6dbe9d048..271388549bcf9 100644 --- a/bin/utils/subkey/src/main.rs +++ b/bin/utils/subkey/src/main.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Subkey utility, based on node_runtime. +//! Subkey utility, based on kitchensink_runtime. fn main() -> Result<(), sc_cli::Error> { subkey::run() diff --git a/docs/README.adoc b/docs/README.adoc index 0b82f0ed82a13..5d7b0b52c5250 100644 --- a/docs/README.adoc +++ b/docs/README.adoc @@ -445,7 +445,7 @@ pallet-assets, pallet-balances, pallet-consensus, pallet-contracts, pallet-counc frame-executive, pallet-session, pallet-staking, pallet-timestamp, pallet-treasury * Node [source, shell] -node-cli, node-consensus, node-executor, node-network, node-primitives, node-runtime +node-cli, node-consensus, node-executor, node-network, node-primitives, kitchensink-runtime * Subkey [source, shell] subkey diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 7a9f57e9a7734..ccf8338236d0a 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -181,13 +181,13 @@ test-deterministic-wasm: script: - rusty-cachier snapshot create # build runtime - - cargo build --verbose --release -p node-runtime + - cargo build --verbose --release -p kitchensink-runtime # make checksum - - sha256sum $CARGO_TARGET_DIR/release/wbuild/node-runtime/target/wasm32-unknown-unknown/release/node_runtime.wasm > checksum.sha256 + - sha256sum $CARGO_TARGET_DIR/release/wbuild/kitchensink-runtime/target/wasm32-unknown-unknown/release/kitchensink_runtime.wasm > checksum.sha256 # clean up - rm -rf $CARGO_TARGET_DIR/release/wbuild # build again - - cargo build --verbose --release -p node-runtime + - cargo build --verbose --release -p kitchensink-runtime # confirm checksum - sha256sum -c ./checksum.sha256 # clean up again, don't put release binaries into the cache diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml index c5f3b1998fa97..5af7dd78a08e8 100644 --- a/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -6,11 +6,11 @@ edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" -description = "Bag threshold generation script for pallet-bag-list and node-runtime." +description = "Bag threshold generation script for pallet-bag-list and kitchensink-runtime." readme = "README.md" [dependencies] -node-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runtime" } +kitchensink-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runtime" } generate-bags = { version = "4.0.0-dev", path = "../" } # third-party diff --git a/utils/frame/generate-bags/node-runtime/src/main.rs b/utils/frame/generate-bags/node-runtime/src/main.rs index 12bcf8d28cf2b..5ea1262d95d34 100644 --- a/utils/frame/generate-bags/node-runtime/src/main.rs +++ b/utils/frame/generate-bags/node-runtime/src/main.rs @@ -43,5 +43,10 @@ struct Opt { fn main() -> Result<(), std::io::Error> { let Opt { n_bags, output, total_issuance, minimum_balance } = Opt::parse(); - generate_thresholds::(n_bags, &output, total_issuance, minimum_balance) + generate_thresholds::( + n_bags, + &output, + total_issuance, + minimum_balance, + ) } diff --git a/utils/wasm-builder/src/lib.rs b/utils/wasm-builder/src/lib.rs index 919290655368b..fc86a06170a50 100644 --- a/utils/wasm-builder/src/lib.rs +++ b/utils/wasm-builder/src/lib.rs @@ -92,7 +92,7 @@ //! //! Each project can be skipped individually by using the environment variable //! `SKIP_PROJECT_NAME_WASM_BUILD`. Where `PROJECT_NAME` needs to be replaced by the name of the -//! cargo project, e.g. `node-runtime` will be `NODE_RUNTIME`. +//! cargo project, e.g. `kitchensink-runtime` will be `NODE_RUNTIME`. //! //! ## Prerequisites: //! From 9b0156931330532ff5d5284c6f84ffbad1af8010 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 2 Aug 2022 20:00:18 +0300 Subject: [PATCH 1029/1472] rpc: Update jsonrpsee v0.15.1 (#11939) * Bump jsonrpsee to v0.15.1 Signed-off-by: Alexandru Vasile * Update cargo.lock Signed-off-by: Alexandru Vasile * rpc-servers: Adjust RpcMiddleware to WS and HTTP traits Signed-off-by: Alexandru Vasile * rpc/author: Use `SubscriptionSink` Signed-off-by: Alexandru Vasile * rpc/chain: Use `SubscriptionSink` Signed-off-by: Alexandru Vasile * rpc/state: Use `SubscriptionSink` Signed-off-by: Alexandru Vasile * rpc/finality-grandpa: Use `SubscriptionSink` Signed-off-by: Alexandru Vasile * rpc/beefy: Use `SubscriptionSink` Signed-off-by: Alexandru Vasile * client: Extract RPC string result from queries Signed-off-by: Alexandru Vasile * Apply rust-fmt Signed-off-by: Alexandru Vasile * Fix warnings Signed-off-by: Alexandru Vasile * Fix testing Signed-off-by: Alexandru Vasile * rpc/tests: Remove trailing comma Signed-off-by: Alexandru Vasile * rpc: Use `SubscriptionResult` for implementations Signed-off-by: Alexandru Vasile * rpc: Remove comment Signed-off-by: Alexandru Vasile * rpc: Delegate middleware calls to `RpcMiddleware` Signed-off-by: Alexandru Vasile * rpc: Remove comment Signed-off-by: Alexandru Vasile * Revert Cargo.lock Signed-off-by: Alexandru Vasile * Update Cargo.lock with minimal changes Signed-off-by: Alexandru Vasile * rpc: Update imports for `SubscriptionResult` Signed-off-by: Alexandru Vasile * Apply cargo fmt Signed-off-by: Alexandru Vasile * rpc/tests: Submit raw json requests to validate DenyUnsafe Signed-off-by: Alexandru Vasile --- Cargo.lock | 52 ++++++------ bin/node-template/node/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/rpc/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/beefy/rpc/src/lib.rs | 21 +++-- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/babe/rpc/src/lib.rs | 4 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/finality-grandpa/rpc/src/lib.rs | 20 ++--- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc-servers/src/middleware.rs | 79 +++++++++++++++---- client/rpc/Cargo.toml | 2 +- client/rpc/src/author/mod.rs | 17 ++-- client/rpc/src/chain/chain_full.rs | 14 ++-- client/rpc/src/chain/mod.rs | 23 +++--- client/rpc/src/dev/tests.rs | 19 +++-- client/rpc/src/state/mod.rs | 23 ++++-- client/rpc/src/state/state_full.rs | 18 ++--- client/service/Cargo.toml | 2 +- client/service/src/lib.rs | 5 +- client/sync-state-rpc/Cargo.toml | 2 +- frame/contracts/rpc/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/transaction-payment/rpc/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 4 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 32 files changed, 201 insertions(+), 136 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 733c6d73d2709..ec5c5267142a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2877,13 +2877,13 @@ dependencies = [ [[package]] name = "http" -version = "0.2.3" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 0.4.8", + "itoa 1.0.1", ] [[package]] @@ -3134,9 +3134,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11e017217fcd18da0a25296d3693153dd19c8a6aadab330b3595285d075385d1" +checksum = "8bd0d559d5e679b1ab2f869b486a11182923863b1b3ee8b421763cdd707b783a" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-server", @@ -3149,9 +3149,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce395539a14d3ad4ec1256fde105abd36a2da25d578a291cabe98f45adfdb111" +checksum = "8752740ecd374bcbf8b69f3e80b0327942df76f793f8d4e60d3355650c31fb74" dependencies = [ "futures-util", "http", @@ -3170,9 +3170,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16efcd4477de857d4a2195a45769b2fe9ebb54f3ef5a4221d3b014a4fe33ec0b" +checksum = "f3dc3e9cf2ba50b7b1d7d76a667619f82846caa39e8e8daa8a4962d74acaddca" dependencies = [ "anyhow", "arrayvec 0.7.2", @@ -3183,6 +3183,7 @@ dependencies = [ "futures-timer", "futures-util", "globset", + "http", "hyper", "jsonrpsee-types", "lazy_static", @@ -3195,14 +3196,15 @@ dependencies = [ "thiserror", "tokio", "tracing", + "tracing-futures", "unicase", ] [[package]] name = "jsonrpsee-http-server" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdd69efeb3ce2cba767f126872f4eeb4624038a29098e75d77608b2b4345ad03" +checksum = "03802f0373a38c2420c70b5144742d800b509e2937edc4afb116434f07120117" dependencies = [ "futures-channel", "futures-util", @@ -3213,13 +3215,14 @@ dependencies = [ "serde_json", "tokio", "tracing", + "tracing-futures", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874cf3f6a027cebf36cae767feca9aa2e8a8f799880e49eb5540819fcbd8eada" +checksum = "bd67957d4280217247588ac86614ead007b301ca2fa9f19c19f880a536f029e3" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3229,9 +3232,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcf76cd316f5d3ad48138085af1f45e2c58c98e02f0779783dbb034d43f7c86" +checksum = "e290bba767401b646812f608c099b922d8142603c9e73a50fb192d3ac86f4a0d" dependencies = [ "anyhow", "beef", @@ -3243,10 +3246,11 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee043cb5dd0d51d3eb93432e998d5bae797691a7b10ec4a325e036bcdb48c48a" +checksum = "6ee5feddd5188e62ac08fcf0e56478138e581509d4730f3f7be9b57dd402a4ff" dependencies = [ + "http", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", @@ -3254,12 +3258,13 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-server" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2e4d266774a671f8def3794255b28eddd09b18d76e0b913fa439f34588c0a" +checksum = "d488ba74fb369e5ab68926feb75a483458b88e768d44319f37e4ecad283c7325" dependencies = [ "futures-channel", "futures-util", + "http", "jsonrpsee-core", "jsonrpsee-types", "serde_json", @@ -3268,6 +3273,7 @@ dependencies = [ "tokio-stream", "tokio-util", "tracing", + "tracing-futures", ] [[package]] @@ -10839,9 +10845,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ "cfg-if 1.0.0", "log", @@ -10852,9 +10858,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index c8e74ea9515ac..eeba198da8212 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -42,7 +42,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" } # These dependencies are used for the node template's RPCs -jsonrpsee = { version = "0.14.0", features = ["server"] } +jsonrpsee = { version = "0.15.1", features = ["server"] } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 9dde225c0d6fb..fe7c5332e2b45 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -37,7 +37,7 @@ crate-type = ["cdylib", "rlib"] clap = { version = "3.1.18", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } -jsonrpsee = { version = "0.14.0", features = ["server"] } +jsonrpsee = { version = "0.15.1", features = ["server"] } futures = "0.3.21" hex-literal = "0.3.4" log = "0.4.17" diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 547d0df7a8372..07b25085b9d10 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.14.0", features = ["server"] } +jsonrpsee = { version = "0.15.1", features = ["server"] } node-primitives = { version = "2.0.0", path = "../primitives" } pallet-contracts-rpc = { version = "4.0.0-dev", path = "../../../frame/contracts/rpc/" } pallet-mmr-rpc = { version = "3.0.0", path = "../../../frame/merkle-mountain-range/rpc/" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 7d31aea3f6971..46ee7640d710a 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://substrate.io" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" -jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } log = "0.4" parking_lot = "0.12.0" serde = { version = "1.0.136", features = ["derive"] } diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 13bca08d37429..91ff59324bd95 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -30,8 +30,8 @@ use futures::{task::SpawnError, FutureExt, StreamExt}; use jsonrpsee::{ core::{async_trait, Error as JsonRpseeError, RpcResult}, proc_macros::rpc, - types::{error::CallError, ErrorObject}, - PendingSubscription, + types::{error::CallError, ErrorObject, SubscriptionResult}, + SubscriptionSink, }; use log::warn; @@ -135,19 +135,18 @@ impl BeefyApiServer f where Block: BlockT, { - fn subscribe_justifications(&self, pending: PendingSubscription) { + fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult { let stream = self .signed_commitment_stream .subscribe() .map(|sc| notification::EncodedSignedCommitment::new::(sc)); let fut = async move { - if let Some(mut sink) = pending.accept() { - sink.pipe_from_stream(stream).await; - } + sink.pipe_from_stream(stream).await; }; self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + Ok(()) } async fn latest_finalized(&self) -> RpcResult { @@ -197,9 +196,9 @@ mod tests { let (rpc, _) = setup_io_handler(); let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"BEEFY RPC endpoint not ready"},"id":1}"#.to_string(); - let (result, _) = rpc.raw_json_request(&request).await.unwrap(); + let (response, _) = rpc.raw_json_request(&request).await.unwrap(); - assert_eq!(expected_response, result,); + assert_eq!(expected_response, response.result); } #[tokio::test] @@ -229,8 +228,8 @@ mod tests { let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2); while std::time::Instant::now() < deadline { let (response, _) = io.raw_json_request(request).await.expect("RPC requests work"); - if response != not_ready { - assert_eq!(response, expected); + if response.result != not_ready { + assert_eq!(response.result, expected); // Success return } @@ -260,7 +259,7 @@ mod tests { .unwrap(); let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; - assert_eq!(response, expected); + assert_eq!(response.result, expected); } fn create_commitment() -> BeefySignedCommitment { diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 4c9350735d529..488036277d7b6 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } futures = "0.3.21" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0" diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index af19d410346e3..b000d38a44f02 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -262,7 +262,7 @@ mod tests { let (response, _) = api.raw_json_request(request).await.unwrap(); let expected = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[1,2,4],"secondary_vrf":[]}},"id":1}"#; - assert_eq!(&response, expected); + assert_eq!(&response.result, expected); } #[tokio::test] @@ -274,6 +274,6 @@ mod tests { let (response, _) = api.raw_json_request(request).await.unwrap(); let expected = r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"RPC call is unsafe to be called externally"},"id":1}"#; - assert_eq!(&response, expected); + assert_eq!(&response.result, expected); } } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 7aa2232178f22..83c156ef5667f 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } assert_matches = "1.3.0" async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index f2d37da058f45..075179d3ceaf7 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" [dependencies] finality-grandpa = { version = "0.16.0", features = ["derive-codec"] } futures = "0.3.16" -jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } log = "0.4.8" parity-scale-codec = { version = "3.0.0", features = ["derive"] } serde = { version = "1.0.105", features = ["derive"] } diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index 1cf23a18c794b..85df72de77b54 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -26,7 +26,8 @@ use std::sync::Arc; use jsonrpsee::{ core::{async_trait, RpcResult}, proc_macros::rpc, - PendingSubscription, + types::SubscriptionResult, + SubscriptionSink, }; mod error; @@ -102,7 +103,7 @@ where ReportedRoundStates::from(&self.authority_set, &self.voter_state).map_err(Into::into) } - fn subscribe_justifications(&self, pending: PendingSubscription) { + fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult { let stream = self.justification_stream.subscribe().map( |x: sc_finality_grandpa::GrandpaJustification| { JustificationNotification::from(x) @@ -110,12 +111,11 @@ where ); let fut = async move { - if let Some(mut sink) = pending.accept() { - sink.pipe_from_stream(stream).await; - } + sink.pipe_from_stream(stream).await; }; self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + Ok(()) } async fn prove_finality( @@ -283,9 +283,9 @@ mod tests { let (rpc, _) = setup_io_handler(EmptyVoterState); let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"GRANDPA RPC endpoint not ready"},"id":0}"#.to_string(); let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; - let (result, _) = rpc.raw_json_request(&request).await.unwrap(); + let (response, _) = rpc.raw_json_request(&request).await.unwrap(); - assert_eq!(expected_response, result,); + assert_eq!(expected_response, response.result); } #[tokio::test] @@ -306,8 +306,8 @@ mod tests { },\"id\":0}".to_string(); let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; - let (result, _) = rpc.raw_json_request(&request).await.unwrap(); - assert_eq!(expected_response, result); + let (response, _) = rpc.raw_json_request(&request).await.unwrap(); + assert_eq!(expected_response, response.result); } #[tokio::test] @@ -328,7 +328,7 @@ mod tests { .unwrap(); let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; - assert_eq!(response, expected); + assert_eq!(response.result, expected); } fn create_justification() -> GrandpaJustification { diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 3425ba2b245df..101d558663f9f 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -28,4 +28,4 @@ sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-version = { version = "5.0.0", path = "../../primitives/version" } -jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index daaa955839045..8b40972527be8 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" -jsonrpsee = { version = "0.14.0", features = ["server"] } +jsonrpsee = { version = "0.15.1", features = ["server"] } log = "0.4.17" serde_json = "1.0.79" tokio = { version = "1.17.0", features = ["parking_lot"] } diff --git a/client/rpc-servers/src/middleware.rs b/client/rpc-servers/src/middleware.rs index cb9918268f4de..1c0660fc3528d 100644 --- a/client/rpc-servers/src/middleware.rs +++ b/client/rpc-servers/src/middleware.rs @@ -18,11 +18,12 @@ //! RPC middlware to collect prometheus metrics on RPC calls. -use jsonrpsee::core::middleware::Middleware; +use jsonrpsee::core::middleware::{Headers, HttpMiddleware, MethodKind, Params, WsMiddleware}; use prometheus_endpoint::{ register, Counter, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry, U64, }; +use std::net::SocketAddr; /// Metrics for RPC middleware storing information about the number of requests started/completed, /// calls started/completed and their timings. @@ -134,30 +135,33 @@ impl RpcMiddleware { pub fn new(metrics: RpcMetrics, transport_label: &'static str) -> Self { Self { metrics, transport_label } } -} - -impl Middleware for RpcMiddleware { - type Instant = std::time::Instant; - - fn on_connect(&self) { - self.metrics.ws_sessions_opened.as_ref().map(|counter| counter.inc()); - } - fn on_request(&self) -> Self::Instant { + /// Called when a new JSON-RPC request comes to the server. + fn on_request(&self) -> std::time::Instant { let now = std::time::Instant::now(); self.metrics.requests_started.with_label_values(&[self.transport_label]).inc(); now } - fn on_call(&self, name: &str) { - log::trace!(target: "rpc_metrics", "[{}] on_call name={}", self.transport_label, name); + /// Called on each JSON-RPC method call, batch requests will trigger `on_call` multiple times. + fn on_call(&self, name: &str, params: Params, kind: MethodKind) { + log::trace!( + target: "rpc_metrics", + "[{}] on_call name={} params={:?} kind={}", + self.transport_label, + name, + params, + kind, + ); self.metrics .calls_started .with_label_values(&[self.transport_label, name]) .inc(); } - fn on_result(&self, name: &str, success: bool, started_at: Self::Instant) { + /// Called on each JSON-RPC method completion, batch requests will trigger `on_result` multiple + /// times. + fn on_result(&self, name: &str, success: bool, started_at: std::time::Instant) { let micros = started_at.elapsed().as_micros(); log::debug!( target: "rpc_metrics", @@ -183,12 +187,57 @@ impl Middleware for RpcMiddleware { .inc(); } - fn on_response(&self, started_at: Self::Instant) { + /// Called once the JSON-RPC request is finished and response is sent to the output buffer. + fn on_response(&self, _result: &str, started_at: std::time::Instant) { log::trace!(target: "rpc_metrics", "[{}] on_response started_at={:?}", self.transport_label, started_at); self.metrics.requests_finished.with_label_values(&[self.transport_label]).inc(); } +} + +impl WsMiddleware for RpcMiddleware { + type Instant = std::time::Instant; + + fn on_connect(&self, _remote_addr: SocketAddr, _headers: &Headers) { + self.metrics.ws_sessions_opened.as_ref().map(|counter| counter.inc()); + } + + fn on_request(&self) -> Self::Instant { + self.on_request() + } + + fn on_call(&self, name: &str, params: Params, kind: MethodKind) { + self.on_call(name, params, kind) + } + + fn on_result(&self, name: &str, success: bool, started_at: Self::Instant) { + self.on_result(name, success, started_at) + } + + fn on_response(&self, _result: &str, started_at: Self::Instant) { + self.on_response(_result, started_at) + } - fn on_disconnect(&self) { + fn on_disconnect(&self, _remote_addr: SocketAddr) { self.metrics.ws_sessions_closed.as_ref().map(|counter| counter.inc()); } } + +impl HttpMiddleware for RpcMiddleware { + type Instant = std::time::Instant; + + fn on_request(&self, _remote_addr: SocketAddr, _headers: &Headers) -> Self::Instant { + self.on_request() + } + + fn on_call(&self, name: &str, params: Params, kind: MethodKind) { + self.on_call(name, params, kind) + } + + fn on_result(&self, name: &str, success: bool, started_at: Self::Instant) { + self.on_result(name, success, started_at) + } + + fn on_response(&self, _result: &str, started_at: Self::Instant) { + self.on_response(_result, started_at) + } +} diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index e8c657f1a2949..5a05ae6e29df1 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } -jsonrpsee = { version = "0.14.0", features = ["server"] } +jsonrpsee = { version = "0.15.1", features = ["server"] } lazy_static = { version = "1.4.0", optional = true } log = "0.4.17" parking_lot = "0.12.0" diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index b8c4f5d582808..7d0ffdc62e080 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -29,7 +29,8 @@ use codec::{Decode, Encode}; use futures::{FutureExt, TryFutureExt}; use jsonrpsee::{ core::{async_trait, Error as JsonRpseeError, RpcResult}, - PendingSubscription, + types::SubscriptionResult, + SubscriptionSink, }; use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::{ @@ -176,13 +177,13 @@ where .collect()) } - fn watch_extrinsic(&self, pending: PendingSubscription, xt: Bytes) { + fn watch_extrinsic(&self, mut sink: SubscriptionSink, xt: Bytes) -> SubscriptionResult { let best_block_hash = self.client.info().best_hash; let dxt = match TransactionFor::

::decode(&mut &xt[..]).map_err(|e| Error::from(e)) { Ok(dxt) => dxt, Err(e) => { - pending.reject(JsonRpseeError::from(e)); - return + let _ = sink.reject(JsonRpseeError::from(e)); + return Ok(()) }, }; @@ -199,19 +200,15 @@ where let stream = match submit.await { Ok(stream) => stream, Err(err) => { - pending.reject(JsonRpseeError::from(err)); + let _ = sink.reject(JsonRpseeError::from(err)); return }, }; - let mut sink = match pending.accept() { - Some(sink) => sink, - _ => return, - }; - sink.pipe_from_stream(stream).await; }; self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + Ok(()) } } diff --git a/client/rpc/src/chain/chain_full.rs b/client/rpc/src/chain/chain_full.rs index c00c6e5875d94..375e724a33d69 100644 --- a/client/rpc/src/chain/chain_full.rs +++ b/client/rpc/src/chain/chain_full.rs @@ -26,7 +26,7 @@ use futures::{ future::{self, FutureExt}, stream::{self, Stream, StreamExt}, }; -use jsonrpsee::PendingSubscription; +use jsonrpsee::SubscriptionSink; use sc_client_api::{BlockBackend, BlockchainEvents}; use sp_blockchain::HeaderBackend; use sp_runtime::{ @@ -69,7 +69,7 @@ where self.client.block(&BlockId::Hash(self.unwrap_or_best(hash))).map_err(client_err) } - fn subscribe_all_heads(&self, sink: PendingSubscription) { + fn subscribe_all_heads(&self, sink: SubscriptionSink) { subscribe_headers( &self.client, &self.executor, @@ -83,7 +83,7 @@ where ) } - fn subscribe_new_heads(&self, sink: PendingSubscription) { + fn subscribe_new_heads(&self, sink: SubscriptionSink) { subscribe_headers( &self.client, &self.executor, @@ -98,7 +98,7 @@ where ) } - fn subscribe_finalized_heads(&self, sink: PendingSubscription) { + fn subscribe_finalized_heads(&self, sink: SubscriptionSink) { subscribe_headers( &self.client, &self.executor, @@ -117,7 +117,7 @@ where fn subscribe_headers( client: &Arc, executor: &SubscriptionTaskExecutor, - pending: PendingSubscription, + mut sink: SubscriptionSink, best_block_hash: G, stream: F, ) where @@ -143,9 +143,7 @@ fn subscribe_headers( let stream = stream::iter(maybe_header).chain(stream()); let fut = async move { - if let Some(mut sink) = pending.accept() { - sink.pipe_from_stream(stream).await; - } + sink.pipe_from_stream(stream).await; }; executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index a300c80271fd1..be06b91ca747f 100644 --- a/client/rpc/src/chain/mod.rs +++ b/client/rpc/src/chain/mod.rs @@ -27,7 +27,7 @@ use std::sync::Arc; use crate::SubscriptionTaskExecutor; -use jsonrpsee::{core::RpcResult, PendingSubscription}; +use jsonrpsee::{core::RpcResult, types::SubscriptionResult, SubscriptionSink}; use sc_client_api::BlockchainEvents; use sp_rpc::{list::ListOrValue, number::NumberOrHex}; use sp_runtime::{ @@ -95,13 +95,13 @@ where } /// All new head subscription - fn subscribe_all_heads(&self, sink: PendingSubscription); + fn subscribe_all_heads(&self, sink: SubscriptionSink); /// New best head subscription - fn subscribe_new_heads(&self, sink: PendingSubscription); + fn subscribe_new_heads(&self, sink: SubscriptionSink); /// Finalized head subscription - fn subscribe_finalized_heads(&self, sink: PendingSubscription); + fn subscribe_finalized_heads(&self, sink: SubscriptionSink); } /// Create new state API that works on full node. @@ -160,16 +160,19 @@ where self.backend.finalized_head().map_err(Into::into) } - fn subscribe_all_heads(&self, sink: PendingSubscription) { - self.backend.subscribe_all_heads(sink) + fn subscribe_all_heads(&self, sink: SubscriptionSink) -> SubscriptionResult { + self.backend.subscribe_all_heads(sink); + Ok(()) } - fn subscribe_new_heads(&self, sink: PendingSubscription) { - self.backend.subscribe_new_heads(sink) + fn subscribe_new_heads(&self, sink: SubscriptionSink) -> SubscriptionResult { + self.backend.subscribe_new_heads(sink); + Ok(()) } - fn subscribe_finalized_heads(&self, sink: PendingSubscription) { - self.backend.subscribe_finalized_heads(sink) + fn subscribe_finalized_heads(&self, sink: SubscriptionSink) -> SubscriptionResult { + self.backend.subscribe_finalized_heads(sink); + Ok(()) } } diff --git a/client/rpc/src/dev/tests.rs b/client/rpc/src/dev/tests.rs index b7a0de8f5ae0b..f3b18690d0972 100644 --- a/client/rpc/src/dev/tests.rs +++ b/client/rpc/src/dev/tests.rs @@ -17,8 +17,6 @@ // along with this program. If not, see . use super::*; -use assert_matches::assert_matches; -use jsonrpsee::{core::Error as JsonRpseeError, types::error::CallError}; use sc_block_builder::BlockBuilderProvider; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; @@ -61,9 +59,18 @@ async fn deny_unsafe_works() { let block = client.new_block(Default::default()).unwrap().build().unwrap().block; client.import(BlockOrigin::Own, block).await.unwrap(); - assert_matches!( - api.call::<_, Option>("dev_getBlockStats", [client.info().best_hash]) - .await, - Err(JsonRpseeError::Call(CallError::Custom(err))) if err.message().contains("RPC call is unsafe to be called externally") + let best_hash = client.info().best_hash; + let best_hash_param = + serde_json::to_string(&best_hash).expect("To string must always succeed for block hashes"); + + let request = format!( + "{{\"jsonrpc\":\"2.0\",\"method\":\"dev_getBlockStats\",\"params\":[{}],\"id\":1}}", + best_hash_param + ); + let (resp, _) = api.raw_json_request(&request).await.expect("Raw calls should succeed"); + + assert_eq!( + resp.result, + r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"RPC call is unsafe to be called externally"},"id":1}"# ); } diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index 232be4edc8aab..7213e4360ae2b 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -29,7 +29,8 @@ use crate::SubscriptionTaskExecutor; use jsonrpsee::{ core::{Error as JsonRpseeError, RpcResult}, - ws_server::PendingSubscription, + types::SubscriptionResult, + ws_server::SubscriptionSink, }; use sc_rpc_api::{state::ReadProof, DenyUnsafe}; @@ -155,10 +156,10 @@ where ) -> Result; /// New runtime version subscription - fn subscribe_runtime_version(&self, sink: PendingSubscription); + fn subscribe_runtime_version(&self, sink: SubscriptionSink); /// New storage subscription - fn subscribe_storage(&self, sink: PendingSubscription, keys: Option>); + fn subscribe_storage(&self, sink: SubscriptionSink, keys: Option>); } /// Create new state API that works on full node. @@ -318,19 +319,25 @@ where .map_err(Into::into) } - fn subscribe_runtime_version(&self, sink: PendingSubscription) { - self.backend.subscribe_runtime_version(sink) + fn subscribe_runtime_version(&self, sink: SubscriptionSink) -> SubscriptionResult { + self.backend.subscribe_runtime_version(sink); + Ok(()) } - fn subscribe_storage(&self, sink: PendingSubscription, keys: Option>) { + fn subscribe_storage( + &self, + mut sink: SubscriptionSink, + keys: Option>, + ) -> SubscriptionResult { if keys.is_none() { if let Err(err) = self.deny_unsafe.check_if_safe() { let _ = sink.reject(JsonRpseeError::from(err)); - return + return Ok(()) } } - self.backend.subscribe_storage(sink, keys) + self.backend.subscribe_storage(sink, keys); + Ok(()) } } diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 5a8a83cdd4851..42ba70b0af7e7 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -28,7 +28,7 @@ use super::{ use crate::SubscriptionTaskExecutor; use futures::{future, stream, FutureExt, StreamExt}; -use jsonrpsee::{core::Error as JsonRpseeError, PendingSubscription}; +use jsonrpsee::{core::Error as JsonRpseeError, SubscriptionSink}; use sc_client_api::{ Backend, BlockBackend, BlockchainEvents, CallExecutor, ExecutorProvider, ProofProvider, StorageProvider, @@ -357,7 +357,7 @@ where .map_err(client_err) } - fn subscribe_runtime_version(&self, pending: PendingSubscription) { + fn subscribe_runtime_version(&self, mut sink: SubscriptionSink) { let client = self.client.clone(); let initial = match self @@ -369,7 +369,7 @@ where { Ok(initial) => initial, Err(e) => { - pending.reject(JsonRpseeError::from(e)); + let _ = sink.reject(JsonRpseeError::from(e)); return }, }; @@ -397,19 +397,17 @@ where let stream = futures::stream::once(future::ready(initial)).chain(version_stream); let fut = async move { - if let Some(mut sink) = pending.accept() { - sink.pipe_from_stream(stream).await; - } + sink.pipe_from_stream(stream).await; }; self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } - fn subscribe_storage(&self, pending: PendingSubscription, keys: Option>) { + fn subscribe_storage(&self, mut sink: SubscriptionSink, keys: Option>) { let stream = match self.client.storage_changes_notification_stream(keys.as_deref(), None) { Ok(stream) => stream, Err(blockchain_err) => { - pending.reject(JsonRpseeError::from(Error::Client(Box::new(blockchain_err)))); + let _ = sink.reject(JsonRpseeError::from(Error::Client(Box::new(blockchain_err)))); return }, }; @@ -442,9 +440,7 @@ where .filter(|storage| future::ready(!storage.changes.is_empty())); let fut = async move { - if let Some(mut sink) = pending.accept() { - sink.pipe_from_stream(stream).await; - } + sink.pipe_from_stream(stream).await; }; self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 31b0c860cf190..e8ddf40a0ae03 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -22,7 +22,7 @@ wasmtime = ["sc-executor/wasmtime"] test-helpers = [] [dependencies] -jsonrpsee = { version = "0.14.0", features = ["server"] } +jsonrpsee = { version = "0.15.1", features = ["server"] } thiserror = "1.0.30" futures = "0.3.21" rand = "0.7.3" diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 2e7b611ffb187..98bcb17174157 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -101,7 +101,10 @@ impl RpcHandlers { &self, json_query: &str, ) -> Result<(String, mpsc::UnboundedReceiver), JsonRpseeError> { - self.0.raw_json_request(json_query).await + self.0 + .raw_json_request(json_query) + .await + .map(|(method_res, recv)| (method_res.result, recv)) } /// Provides access to the underlying `RpcModule` diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index bd9194092fa3d..d02637fcf884b 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" thiserror = "1.0.30" diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml index a81abef9f37ca..7876c7cba40d0 100644 --- a/frame/contracts/rpc/Cargo.toml +++ b/frame/contracts/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } serde = { version = "1", features = ["derive"] } # Substrate Dependencies diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 45cb975df277b..c7d9662904747 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 31e0972a0d5b5..16c2cc55efefb 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index a77d090246421..3121157df68d8 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } env_logger = "0.9" -jsonrpsee = { version = "0.14.0", features = ["ws-client", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["ws-client", "macros"] } log = "0.4.17" serde = "1.0.136" serde_json = "1.0" diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 6c6bc5cf327b5..00fdc87a506e8 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -25,7 +25,7 @@ sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } trie-db = { version = "0.23.1" } -jsonrpsee = { version = "0.14.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } # Substrate Dependencies sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 7ea07534e1bdb..2104774bd2605 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -jsonrpsee = { version = "0.14.0", features = ["jsonrpsee-types"] } +jsonrpsee = { version = "0.15.1", features = ["jsonrpsee-types"] } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } @@ -25,6 +25,6 @@ sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } [dev-dependencies] scale-info = "2.1.1" -jsonrpsee = { version = "0.14.0", features = ["ws-client", "jsonrpsee-types"] } +jsonrpsee = { version = "0.15.1", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.17.0" frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index f76944a0fec40..5d8984e8d399b 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde_json = "1" codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.14.0", features = ["server"] } +jsonrpsee = { version = "0.15.1", features = ["server"] } futures = "0.3.21" log = "0.4.17" frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index b82da0f1222a7..4b4f9bdb2809a 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -19,7 +19,7 @@ parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = { version = "0.11.2", default-features = false } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } -jsonrpsee = { version = "0.14.0", default-features = false, features = ["ws-client"] } +jsonrpsee = { version = "0.15.1", default-features = false, features = ["ws-client"] } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } From 862dbbc1c16a17b33e0e619b0e996b608a1c5069 Mon Sep 17 00:00:00 2001 From: Andronik Date: Tue, 2 Aug 2022 20:49:03 +0200 Subject: [PATCH 1030/1472] offences: make fn slash_fraction non-static (#11956) * offences: make fn slash_fraction non-static * Bastifmt (inline variable) --- frame/babe/src/equivocation.rs | 4 ++-- frame/grandpa/src/equivocation.rs | 4 ++-- frame/im-online/src/lib.rs | 6 +++--- frame/im-online/src/tests.rs | 10 ++++++---- frame/offences/benchmarking/src/lib.rs | 6 ++---- frame/offences/src/lib.rs | 3 +-- frame/offences/src/mock.rs | 4 ++-- primitives/staking/src/offence.rs | 7 +++---- 8 files changed, 21 insertions(+), 23 deletions(-) diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index df46f3544b389..f55bda751887d 100644 --- a/frame/babe/src/equivocation.rs +++ b/frame/babe/src/equivocation.rs @@ -284,9 +284,9 @@ impl Offence self.slot } - fn slash_fraction(offenders_count: u32, validator_set_count: u32) -> Perbill { + fn slash_fraction(&self, offenders_count: u32) -> Perbill { // the formula is min((3k / n)^2, 1) - let x = Perbill::from_rational(3 * offenders_count, validator_set_count); + let x = Perbill::from_rational(3 * offenders_count, self.validator_set_count); // _ ^ 2 x.square() } diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 804272c20480f..181d22fba545c 100644 --- a/frame/grandpa/src/equivocation.rs +++ b/frame/grandpa/src/equivocation.rs @@ -353,9 +353,9 @@ impl Offence self.time_slot } - fn slash_fraction(offenders_count: u32, validator_set_count: u32) -> Perbill { + fn slash_fraction(&self, offenders_count: u32) -> Perbill { // the formula is min((3k / n)^2, 1) - let x = Perbill::from_rational(3 * offenders_count, validator_set_count); + let x = Perbill::from_rational(3 * offenders_count, self.validator_set_count); // _ ^ 2 x.square() } diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index f190f6672f309..34c1c70d79f75 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -958,12 +958,12 @@ impl Offence for UnresponsivenessOffence { self.session_index } - fn slash_fraction(offenders: u32, validator_set_count: u32) -> Perbill { + fn slash_fraction(&self, offenders: u32) -> Perbill { // the formula is min((3 * (k - (n / 10 + 1))) / n, 1) * 0.07 // basically, 10% can be offline with no slash, but after that, it linearly climbs up to 7% // when 13/30 are offline (around 5% when 1/3 are offline). - if let Some(threshold) = offenders.checked_sub(validator_set_count / 10 + 1) { - let x = Perbill::from_rational(3 * threshold, validator_set_count); + if let Some(threshold) = offenders.checked_sub(self.validator_set_count / 10 + 1) { + let x = Perbill::from_rational(3 * threshold, self.validator_set_count); x.saturating_mul(Perbill::from_percent(7)) } else { Perbill::default() diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index 288081556a085..05e1af169dba9 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -36,22 +36,24 @@ use sp_runtime::{ #[test] fn test_unresponsiveness_slash_fraction() { + let dummy_offence = + UnresponsivenessOffence { session_index: 0, validator_set_count: 50, offenders: vec![()] }; // A single case of unresponsiveness is not slashed. - assert_eq!(UnresponsivenessOffence::<()>::slash_fraction(1, 50), Perbill::zero()); + assert_eq!(dummy_offence.slash_fraction(1), Perbill::zero()); assert_eq!( - UnresponsivenessOffence::<()>::slash_fraction(5, 50), + dummy_offence.slash_fraction(5), Perbill::zero(), // 0% ); assert_eq!( - UnresponsivenessOffence::<()>::slash_fraction(7, 50), + dummy_offence.slash_fraction(7), Perbill::from_parts(4200000), // 0.42% ); // One third offline should be punished around 5%. assert_eq!( - UnresponsivenessOffence::<()>::slash_fraction(17, 50), + dummy_offence.slash_fraction(17), Perbill::from_parts(46200000), // 4.62% ); } diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 98c6390964d82..b793bd8d2699a 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -288,15 +288,13 @@ benchmarks! { let (offenders, raw_offenders) = make_offenders_im_online::(o, n)?; let keys = ImOnline::::keys(); let validator_set_count = keys.len() as u32; - - let slash_fraction = UnresponsivenessOffence::::slash_fraction( - offenders.len() as u32, validator_set_count, - ); + let offenders_count = offenders.len() as u32; let offence = UnresponsivenessOffence { session_index: 0, validator_set_count, offenders, }; + let slash_fraction = offence.slash_fraction(offenders_count); assert_eq!(System::::event_count(), 0); }: { let _ = ::ReportUnresponsiveness::report_offence( diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index e4b75d9c3c015..ae454d6b06740 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -120,7 +120,6 @@ where fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { let offenders = offence.offenders(); let time_slot = offence.time_slot(); - let validator_set_count = offence.validator_set_count(); // Go through all offenders in the offence report and find all offenders that were spotted // in unique reports. @@ -134,7 +133,7 @@ where let offenders_count = concurrent_offenders.len() as u32; // The amount new offenders are slashed - let new_fraction = O::slash_fraction(offenders_count, validator_set_count); + let new_fraction = offence.slash_fraction(offenders_count); let slash_perbill: Vec<_> = (0..concurrent_offenders.len()).map(|_| new_fraction).collect(); diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 6a69b54b3cca0..d9ecf44ad8734 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -168,8 +168,8 @@ impl offence::Offence for Offence { 1 } - fn slash_fraction(offenders_count: u32, validator_set_count: u32) -> Perbill { - Perbill::from_percent(5 + offenders_count * 100 / validator_set_count) + fn slash_fraction(&self, offenders_count: u32) -> Perbill { + Perbill::from_percent(5 + offenders_count * 100 / self.validator_set_count) } } diff --git a/primitives/staking/src/offence.rs b/primitives/staking/src/offence.rs index 4261063993a52..f6517b9e9028b 100644 --- a/primitives/staking/src/offence.rs +++ b/primitives/staking/src/offence.rs @@ -108,11 +108,10 @@ pub trait Offence { } /// A slash fraction of the total exposure that should be slashed for this - /// particular offence kind for the given parameters that happened at a singular `TimeSlot`. + /// particular offence for the `offenders_count` that happened at a singular `TimeSlot`. /// - /// `offenders_count` - the count of unique offending authorities. It is >0. - /// `validator_set_count` - the cardinality of the validator set at the time of offence. - fn slash_fraction(offenders_count: u32, validator_set_count: u32) -> Perbill; + /// `offenders_count` - the count of unique offending authorities for this `TimeSlot`. It is >0. + fn slash_fraction(&self, offenders_count: u32) -> Perbill; } /// Errors that may happen on offence reports. From b27c470eaff379f512d1dec052aff5d551ed3b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 3 Aug 2022 10:46:10 +0200 Subject: [PATCH 1031/1472] Revert non-best block (#11716) * Revert non-best block This makes `revert` also revert non-best blocks. * Update client/db/src/lib.rs * Do not count leaves against the maximum number to revert * Add some explanation * Fix bug * Apply suggestions from code review Co-authored-by: Davide Galassi Co-authored-by: Davide Galassi --- client/api/src/backend.rs | 3 +- client/api/src/leaves.rs | 5 + client/db/src/lib.rs | 149 +++++++++++++++---- client/service/src/chain_ops/revert_chain.rs | 7 + 4 files changed, 135 insertions(+), 29 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index af8552886b72e..54784a2f27b64 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -507,7 +507,8 @@ pub trait Backend: AuxStore + Send + Sync { /// Attempts to revert the chain by `n` blocks. If `revert_finalized` is set it will attempt to /// revert past any finalized block, this is unsafe and can potentially leave the node in an - /// inconsistent state. + /// inconsistent state. All blocks higher than the best block are also reverted and not counting + /// towards `n`. /// /// Returns the number of blocks that were successfully reverted and the list of finalized /// blocks that has been reverted. diff --git a/client/api/src/leaves.rs b/client/api/src/leaves.rs index 2e5d4be3a5462..26eda46e6f76f 100644 --- a/client/api/src/leaves.rs +++ b/client/api/src/leaves.rs @@ -259,6 +259,11 @@ where removed } + + /// Returns the highest leaf and all hashes associated to it. + pub fn highest_leaf(&self) -> Option<(N, &[H])> { + self.storage.iter().next().map(|(k, v)| (k.0.clone(), &v[..])) + } } /// Helper for undoing operations. diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 7dd49f9831f1c..e14d3a26aa557 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -2057,36 +2057,46 @@ impl sc_client_api::backend::Backend for Backend { ) -> ClientResult<(NumberFor, HashSet)> { let mut reverted_finalized = HashSet::new(); - let mut best_number = self.blockchain.info().best_number; - let mut best_hash = self.blockchain.info().best_hash; + let info = self.blockchain.info(); - let finalized = self.blockchain.info().finalized_number; + let highest_leaf = self + .blockchain + .leaves + .read() + .highest_leaf() + .and_then(|(n, h)| h.last().map(|h| (n, *h))); + + let best_number = info.best_number; + let best_hash = info.best_hash; + + let finalized = info.finalized_number; let revertible = best_number - finalized; let n = if !revert_finalized && revertible < n { revertible } else { n }; + let (n, mut number_to_revert, mut hash_to_revert) = match highest_leaf { + Some((l_n, l_h)) => (n + (l_n - best_number), l_n, l_h), + None => (n, best_number, best_hash), + }; + let mut revert_blocks = || -> ClientResult> { for c in 0..n.saturated_into::() { - if best_number.is_zero() { + if number_to_revert.is_zero() { return Ok(c.saturated_into::>()) } let mut transaction = Transaction::new(); let removed = - self.blockchain.header(BlockId::Number(best_number))?.ok_or_else(|| { + self.blockchain.header(BlockId::Hash(hash_to_revert))?.ok_or_else(|| { sp_blockchain::Error::UnknownBlock(format!( - "Error reverting to {}. Block hash not found.", - best_number + "Error reverting to {}. Block header not found.", + hash_to_revert, )) })?; let removed_hash = removed.hash(); - let prev_number = best_number.saturating_sub(One::one()); - let prev_hash = self.blockchain.hash(prev_number)?.ok_or_else(|| { - sp_blockchain::Error::UnknownBlock(format!( - "Error reverting to {}. Block hash not found.", - best_number - )) - })?; + let prev_number = number_to_revert.saturating_sub(One::one()); + let prev_hash = + if prev_number == best_number { best_hash } else { *removed.parent_hash() }; if !self.have_state_at(&prev_hash, prev_number) { return Ok(c.saturated_into::>()) @@ -2096,12 +2106,15 @@ impl sc_client_api::backend::Backend for Backend { Some(commit) => { apply_state_commit(&mut transaction, commit); - best_number = prev_number; - best_hash = prev_hash; + number_to_revert = prev_number; + hash_to_revert = prev_hash; - let update_finalized = best_number < finalized; + let update_finalized = number_to_revert < finalized; - let key = utils::number_and_hash_to_lookup_key(best_number, &best_hash)?; + let key = utils::number_and_hash_to_lookup_key( + number_to_revert, + &hash_to_revert, + )?; if update_finalized { transaction.set_from_vec( columns::META, @@ -2111,12 +2124,14 @@ impl sc_client_api::backend::Backend for Backend { reverted_finalized.insert(removed_hash); if let Some((hash, _)) = self.blockchain.info().finalized_state { - if hash == best_hash { - if !best_number.is_zero() && - self.have_state_at(&prev_hash, best_number - One::one()) - { + if hash == hash_to_revert { + if !number_to_revert.is_zero() && + self.have_state_at( + &prev_hash, + number_to_revert - One::one(), + ) { let lookup_key = utils::number_and_hash_to_lookup_key( - best_number - One::one(), + number_to_revert - One::one(), prev_hash, )?; transaction.set_from_vec( @@ -2137,13 +2152,16 @@ impl sc_client_api::backend::Backend for Backend { &mut transaction, columns::META, meta_keys::CHILDREN_PREFIX, - best_hash, + hash_to_revert, ); self.storage.db.commit(transaction)?; + + let is_best = number_to_revert < best_number; + self.blockchain.update_meta(MetaUpdate { - hash: best_hash, - number: best_number, - is_best: true, + hash: hash_to_revert, + number: number_to_revert, + is_best, is_finalized: update_finalized, with_state: false, }); @@ -2161,7 +2179,7 @@ impl sc_client_api::backend::Backend for Backend { let mut transaction = Transaction::new(); let mut leaves = self.blockchain.leaves.write(); - leaves.revert(best_hash, best_number); + leaves.revert(hash_to_revert, number_to_revert); leaves.prepare_transaction(&mut transaction, columns::META, meta_keys::LEAF_PREFIX); self.storage.db.commit(transaction)?; @@ -3463,4 +3481,79 @@ pub(crate) mod tests { insert_header_no_head(&backend, 1, block0, [1; 32].into()); assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a]); } + + #[test] + fn revert_non_best_blocks() { + let backend = Backend::::new_test(10, 10); + + let genesis = + insert_block(&backend, 0, Default::default(), None, Default::default(), vec![], None) + .unwrap(); + + let block1 = + insert_block(&backend, 1, genesis, None, Default::default(), vec![], None).unwrap(); + + let block2 = + insert_block(&backend, 2, block1, None, Default::default(), vec![], None).unwrap(); + + let block3 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Number(1)).unwrap(); + let header = Header { + number: 3, + parent_hash: block2, + state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), + digest: Default::default(), + extrinsics_root: Default::default(), + }; + + op.set_block_data(header.clone(), Some(Vec::new()), None, None, NewBlockState::Normal) + .unwrap(); + + backend.commit_operation(op).unwrap(); + + header.hash() + }; + + let block4 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Hash(block2)).unwrap(); + let header = Header { + number: 4, + parent_hash: block3, + state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), + digest: Default::default(), + extrinsics_root: Default::default(), + }; + + op.set_block_data(header.clone(), Some(Vec::new()), None, None, NewBlockState::Normal) + .unwrap(); + + backend.commit_operation(op).unwrap(); + + header.hash() + }; + + let block3_fork = insert_header_no_head(&backend, 3, block2, Default::default()); + + assert!(backend.have_state_at(&block1, 1)); + assert!(backend.have_state_at(&block2, 2)); + assert!(backend.have_state_at(&block3, 3)); + assert!(backend.have_state_at(&block4, 4)); + assert!(backend.have_state_at(&block3_fork, 3)); + + assert_eq!(backend.blockchain.leaves().unwrap(), vec![block4, block3_fork]); + assert_eq!(4, backend.blockchain.leaves.read().highest_leaf().unwrap().0); + + assert_eq!(3, backend.revert(1, false).unwrap().0); + + assert!(backend.have_state_at(&block1, 1)); + assert!(!backend.have_state_at(&block2, 2)); + assert!(!backend.have_state_at(&block3, 3)); + assert!(!backend.have_state_at(&block4, 4)); + assert!(!backend.have_state_at(&block3_fork, 3)); + + assert_eq!(backend.blockchain.leaves().unwrap(), vec![block1]); + assert_eq!(1, backend.blockchain.leaves.read().highest_leaf().unwrap().0); + } } diff --git a/client/service/src/chain_ops/revert_chain.rs b/client/service/src/chain_ops/revert_chain.rs index 9a3ce6024ed92..3ee4399d063b3 100644 --- a/client/service/src/chain_ops/revert_chain.rs +++ b/client/service/src/chain_ops/revert_chain.rs @@ -40,6 +40,13 @@ where info!("There aren't any non-finalized blocks to revert."); } else { info!("Reverted {} blocks. Best: #{} ({})", reverted.0, info.best_number, info.best_hash); + + if reverted.0 > blocks { + info!( + "Number of reverted blocks is higher than requested \ + because of reverted leaves higher than the best block." + ) + } } Ok(()) } From 28ac0a8591c3b9765206cada54980e9ea3416ea0 Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Wed, 3 Aug 2022 12:34:33 +0100 Subject: [PATCH 1032/1472] Fix docs urls (#11966) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix docs urls * Update bin/node-template/README.md * Update frame/aura/src/lib.rs * Run cargo +nightly fmt Co-authored-by: Bastian Köcher --- README.md | 2 +- bin/node-template/README.md | 32 ++++++++----------- bin/node-template/docs/rust-setup.md | 6 ++-- bin/node-template/pallets/template/src/lib.rs | 10 +++--- client/rpc-api/src/state/mod.rs | 2 +- frame/examples/basic/src/benchmarking.rs | 2 +- frame/examples/basic/src/lib.rs | 2 +- frame/remark/src/tests.rs | 3 ++ frame/sudo/README.md | 2 +- frame/sudo/src/lib.rs | 2 +- .../procedural/src/pallet/expand/error.rs | 2 +- .../procedural/src/pallet/expand/event.rs | 2 +- .../procedural/src/pallet/expand/mod.rs | 2 +- .../src/pallet/expand/pallet_struct.rs | 2 +- frame/support/src/dispatch.rs | 2 +- frame/support/src/traits/misc.rs | 2 +- primitives/runtime/src/bounded/bounded_vec.rs | 2 +- .../runtime/src/bounded/weak_bounded_vec.rs | 2 +- 18 files changed, 39 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index b716794428a00..c609641af7ce2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Substrate is a next-generation framework for blockchain innovation 🚀. ## Trying it out Simply go to [docs.substrate.io](https://docs.substrate.io) and follow the -[installation](https://docs.substrate.io/v3/getting-started/overview) instructions. You can +[installation](https://docs.substrate.io/main-docs/install/) instructions. You can also try out one of the [tutorials](https://docs.substrate.io/tutorials/). ## Contributions & Code of Conduct diff --git a/bin/node-template/README.md b/bin/node-template/README.md index 8defb870fa1b0..0f6fd9450aeee 100644 --- a/bin/node-template/README.md +++ b/bin/node-template/README.md @@ -114,7 +114,7 @@ local node template. ### Multi-Node Local Testnet If you want to see the multi-node consensus algorithm in action, refer to our -[Start a Private Network tutorial](https://docs.substrate.io/tutorials/v3/private-network). +[Simulate a network tutorial](https://docs.substrate.io/tutorials/get-started/simulate-network/). ## Template Structure @@ -129,7 +129,7 @@ Substrate-based blockchain nodes expose a number of capabilities: - Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking stack to allow the nodes in the network to communicate with one another. - Consensus: Blockchains must have a way to come to - [consensus](https://docs.substrate.io/v3/advanced/consensus) on the state of the + [consensus](https://docs.substrate.io/main-docs/fundamentals/consensus/) on the state of the network. Substrate makes it possible to supply custom consensus engines and also ships with several consensus mechanisms that have been built on top of [Web3 Foundation research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html). @@ -138,22 +138,20 @@ Substrate-based blockchain nodes expose a number of capabilities: There are several files in the `node` directory - take special note of the following: - [`chain_spec.rs`](./node/src/chain_spec.rs): A - [chain specification](https://docs.substrate.io/v3/runtime/chain-specs) is a + [chain specification](https://docs.substrate.io/main-docs/build/chain-spec/) is a source code file that defines a Substrate chain's initial (genesis) state. Chain specifications are useful for development and testing, and critical when architecting the launch of a production chain. Take note of the `development_config` and `testnet_genesis` functions, which are used to define the genesis state for the local development chain configuration. These functions identify some - [well-known accounts](https://docs.substrate.io/v3/tools/subkey#well-known-keys) + [well-known accounts](https://docs.substrate.io/reference/command-line-tools/subkey/) and use them to configure the blockchain's initial state. - [`service.rs`](./node/src/service.rs): This file defines the node implementation. Take note of the libraries that this file imports and the names of the functions it invokes. In particular, there are references to consensus-related topics, such as the - [longest chain rule](https://docs.substrate.io/v3/advanced/consensus#longest-chain-rule), - the [Aura](https://docs.substrate.io/v3/advanced/consensus#aura) block authoring - mechanism and the - [GRANDPA](https://docs.substrate.io/v3/advanced/consensus#grandpa) finality - gadget. + [block finalization and forks](https://docs.substrate.io/main-docs/fundamentals/consensus/#finalization-and-forks) + and other [consensus mechanisms](https://docs.substrate.io/main-docs/fundamentals/consensus/#default-consensus-models) + such as Aura for block authoring and GRANDPA for finality. After the node has been [built](#build), refer to the embedded documentation to learn more about the capabilities and configuration parameters that it exposes: @@ -165,16 +163,15 @@ capabilities and configuration parameters that it exposes: ### Runtime In Substrate, the terms -"[runtime](https://docs.substrate.io/v3/getting-started/glossary#runtime)" and -"[state transition function](https://docs.substrate.io/v3/getting-started/glossary#state-transition-function-stf)" +"runtime" and "state transition function" are analogous - they refer to the core logic of the blockchain that is responsible for validating blocks and executing the state changes they define. The Substrate project in this repository uses -the [FRAME](https://docs.substrate.io/v3/runtime/frame) framework to construct a +[FRAME](https://docs.substrate.io/main-docs/fundamentals/runtime-intro/#frame) to construct a blockchain runtime. FRAME allows runtime developers to declare domain-specific logic in modules called "pallets". At the heart of FRAME is a helpful -[macro language](https://docs.substrate.io/v3/runtime/macros) that makes it easy to +[macro language](https://docs.substrate.io/reference/frame-macros/) that makes it easy to create pallets and flexibly compose them to create blockchains that can address -[a variety of needs](https://www.substrate.io/substrate-users/). +[a variety of needs](https://substrate.io/ecosystem/projects/). Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this template and note the following: @@ -184,8 +181,7 @@ the following: - The pallets are composed into a single runtime by way of the [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html) macro, which is part of the core - [FRAME Support](https://docs.substrate.io/v3/runtime/frame#support-crate) - library. + FRAME Support [system](https://docs.substrate.io/reference/frame-pallets/#system-pallets) library. ### Pallets @@ -196,12 +192,12 @@ template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs A FRAME pallet is compromised of a number of blockchain primitives: - Storage: FRAME defines a rich set of powerful - [storage abstractions](https://docs.substrate.io/v3/runtime/storage) that makes + [storage abstractions](https://docs.substrate.io/main-docs/build/runtime-storage/) that makes it easy to use Substrate's efficient key-value database to manage the evolving state of a blockchain. - Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched) from outside of the runtime in order to update its state. -- Events: Substrate uses [events and errors](https://docs.substrate.io/v3/runtime/events-and-errors) +- Events: Substrate uses [events and errors](https://docs.substrate.io/main-docs/build/events-errors/) to notify users of important changes in the runtime. - Errors: When a dispatchable fails, it returns an error. - Config: The `Config` configuration interface is used to define the types and parameters upon diff --git a/bin/node-template/docs/rust-setup.md b/bin/node-template/docs/rust-setup.md index ea133ca847af7..2755966e3ae0f 100644 --- a/bin/node-template/docs/rust-setup.md +++ b/bin/node-template/docs/rust-setup.md @@ -3,7 +3,7 @@ title: Installation --- This guide is for reference only, please check the latest information on getting starting with Substrate -[here](https://docs.substrate.io/v3/getting-started/installation/). +[here](https://docs.substrate.io/main-docs/install/). This page will guide you through the **2 steps** needed to prepare a computer for **Substrate** development. Since Substrate is built with [the Rust programming language](https://www.rust-lang.org/), the first @@ -73,11 +73,11 @@ brew install openssl ### Windows -**_PLEASE NOTE:_** Native development of Substrate is _not_ very well supported! It is _highly_ +**_PLEASE NOTE:_** Native Windows development of Substrate is _not_ very well supported! It is _highly_ recommend to use [Windows Subsystem Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) (WSL) and follow the instructions for [Ubuntu/Debian](#ubuntudebian). Please refer to the separate -[guide for native Windows development](https://docs.substrate.io/v3/getting-started/windows-users/). +[guide for native Windows development](https://docs.substrate.io/main-docs/install/windows/). ## Rust developer environment diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index 067c7ce2575a0..2c337146859ef 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -2,7 +2,7 @@ /// Edit this file to define custom logic or remove it if it is not needed. /// Learn more about FRAME and the core library of Substrate FRAME pallets: -/// +/// pub use pallet::*; #[cfg(test)] @@ -31,15 +31,15 @@ pub mod pallet { pub struct Pallet(_); // The pallet's runtime storage items. - // https://docs.substrate.io/v3/runtime/storage + // https://docs.substrate.io/main-docs/build/runtime-storage/ #[pallet::storage] #[pallet::getter(fn something)] // Learn more about declaring storage items: - // https://docs.substrate.io/v3/runtime/storage#declaring-storage-items + // https://docs.substrate.io/main-docs/build/runtime-storage/#declaring-storage-items pub type Something = StorageValue<_, u32>; // Pallets use events to inform users when important changes are made. - // https://docs.substrate.io/v3/runtime/events-and-errors + // https://docs.substrate.io/main-docs/build/events-errors/ #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -68,7 +68,7 @@ pub mod pallet { pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { // Check that the extrinsic was signed and get the signer. // This function will return an error if the extrinsic is not signed. - // https://docs.substrate.io/v3/runtime/origins + // https://docs.substrate.io/main-docs/build/origins/ let who = ensure_signed(origin)?; // Update storage. diff --git a/client/rpc-api/src/state/mod.rs b/client/rpc-api/src/state/mod.rs index 54bf21674a8bd..40e208c2eba8d 100644 --- a/client/rpc-api/src/state/mod.rs +++ b/client/rpc-api/src/state/mod.rs @@ -265,7 +265,7 @@ pub trait StateApi { /// [substrate storage][1], [transparent keys in substrate][2], /// [querying substrate storage via rpc][3]. /// - /// [1]: https://docs.substrate.io/v3/advanced/storage#storage-map-keys + /// [1]: https://docs.substrate.io/main-docs/fundamentals/state-transitions-and-storage/ /// [2]: https://www.shawntabrizi.com/substrate/transparent-keys-in-substrate/ /// [3]: https://www.shawntabrizi.com/substrate/querying-substrate-storage-via-rpc/ /// diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index d7b933577ead5..93e14f358208e 100644 --- a/frame/examples/basic/src/benchmarking.rs +++ b/frame/examples/basic/src/benchmarking.rs @@ -26,7 +26,7 @@ use frame_system::RawOrigin; // To actually run this benchmark on pallet-example-basic, we need to put this pallet into the // runtime and compile it with `runtime-benchmarks` feature. The detail procedures are // documented at: -// https://docs.substrate.io/v3/runtime/benchmarking#how-to-benchmark +// https://docs.substrate.io/reference/how-to-guides/weights/add-benchmarks/ // // The auto-generated weight estimate of this pallet is copied over to the `weights.rs` file. // The exact command of how the estimate generated is printed at the top of the file. diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index f8acc1962388f..03dc2c613c01e 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -318,7 +318,7 @@ const MILLICENTS: u32 = 1_000_000_000; // - assigns a dispatch class `operational` if the argument of the call is more than 1000. // // More information can be read at: -// - https://docs.substrate.io/v3/runtime/weights-and-fees +// - https://docs.substrate.io/main-docs/build/tx-weights-fees/ // // Manually configuring weight is an advanced operation and what you really need may well be // fulfilled by running the benchmarking toolchain. Refer to `benchmarking.rs` file. diff --git a/frame/remark/src/tests.rs b/frame/remark/src/tests.rs index 60a376c5afca5..eac006054c1d5 100644 --- a/frame/remark/src/tests.rs +++ b/frame/remark/src/tests.rs @@ -30,11 +30,14 @@ fn generates_event() { System::set_block_number(System::block_number() + 1); //otherwise event won't be registered. assert_ok!(Remark::::store(RawOrigin::Signed(caller.clone()).into(), data.clone(),)); let events = System::events(); + // this one we create as we expect it let system_event: ::Event = Event::Stored { content_hash: sp_io::hashing::blake2_256(&data).into(), sender: caller, } .into(); + // this one we actually go into the system pallet and get the last event + // because we know its there from block +1 let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; assert_eq!(event, &system_event); }); diff --git a/frame/sudo/README.md b/frame/sudo/README.md index e8f688091e326..7342832d2d7a7 100644 --- a/frame/sudo/README.md +++ b/frame/sudo/README.md @@ -72,6 +72,6 @@ You need to set an initial superuser account as the sudo `key`. [`Call`]: ./enum.Call.html [`Config`]: ./trait.Config.html -[`Origin`]: https://docs.substrate.io/v3/runtime/origins +[`Origin`]: https://docs.substrate.io/main-docs/build/origins/ License: Apache-2.0 diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index d9e72b37f2970..a47b5a79bd017 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -88,7 +88,7 @@ //! //! * [Democracy](../pallet_democracy/index.html) //! -//! [`Origin`]: https://docs.substrate.io/v3/runtime/origins +//! [`Origin`]: https://docs.substrate.io/main-docs/build/origins/ #![cfg_attr(not(feature = "std"), no_std)] diff --git a/frame/support/procedural/src/pallet/expand/error.rs b/frame/support/procedural/src/pallet/expand/error.rs index 124e8b312ce39..5a8487b09de5c 100644 --- a/frame/support/procedural/src/pallet/expand/error.rs +++ b/frame/support/procedural/src/pallet/expand/error.rs @@ -111,7 +111,7 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { if get_doc_literals(&error_item.attrs).is_empty() { error_item.attrs.push(syn::parse_quote!( #[doc = r" - Custom [dispatch errors](https://docs.substrate.io/v3/runtime/events-and-errors) + Custom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/) of this pallet. "] )); diff --git a/frame/support/procedural/src/pallet/expand/event.rs b/frame/support/procedural/src/pallet/expand/event.rs index acd60ab959c61..791f930302207 100644 --- a/frame/support/procedural/src/pallet/expand/event.rs +++ b/frame/support/procedural/src/pallet/expand/event.rs @@ -98,7 +98,7 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { if get_doc_literals(&event_item.attrs).is_empty() { event_item.attrs.push(syn::parse_quote!( #[doc = r" - The [event](https://docs.substrate.io/v3/runtime/events-and-errors) emitted + The [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted by this pallet. "] )); diff --git a/frame/support/procedural/src/pallet/expand/mod.rs b/frame/support/procedural/src/pallet/expand/mod.rs index 83bef7a97af1f..c33d2386700b2 100644 --- a/frame/support/procedural/src/pallet/expand/mod.rs +++ b/frame/support/procedural/src/pallet/expand/mod.rs @@ -74,7 +74,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { def.item.attrs.push(syn::parse_quote!( #[doc = r" The module that hosts all the - [FRAME](https://docs.substrate.io/v3/runtime/frame) + [FRAME](https://docs.substrate.io/main-docs/build/events-errors/) types needed to add this pallet to a runtime. "] diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 52586a70a521a..a4a8acc10f799 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -62,7 +62,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { if get_doc_literals(&pallet_item.attrs).is_empty() { pallet_item.attrs.push(syn::parse_quote!( #[doc = r" - The [pallet](https://docs.substrate.io/v3/runtime/frame#pallets) implementing + The [pallet](https://docs.substrate.io/reference/frame-pallets/#pallets) implementing the on-chain logic. "] )); diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index ae4230efc63f8..2b05478e0b02a 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -306,7 +306,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// /// The following are reserved function signatures: /// -/// * `deposit_event`: Helper function for depositing an [event](https://docs.substrate.io/v3/runtime/events-and-errors). +/// * `deposit_event`: Helper function for depositing an [event](https://docs.substrate.io/main-docs/build/events-errors/). /// The default behavior is to call `deposit_event` from the [System /// module](../frame_system/index.html). However, you can write your own implementation for events /// in your runtime. To use the default behavior, add `fn deposit_event() = default;` to your diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index ccbb47909d5f4..ddb7f6f41b378 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -763,7 +763,7 @@ impl MaxEncodedLen for WrapperOpaque { fn max_encoded_len() -> usize { let t_max_len = T::max_encoded_len(); - // See scale encoding https://docs.substrate.io/v3/advanced/scale-codec + // See scale encoding: https://docs.substrate.io/reference/scale-codec/ if t_max_len < 64 { t_max_len + 1 } else if t_max_len < 2usize.pow(14) { diff --git a/primitives/runtime/src/bounded/bounded_vec.rs b/primitives/runtime/src/bounded/bounded_vec.rs index 10d9fc608c273..d5f3f2da0d615 100644 --- a/primitives/runtime/src/bounded/bounded_vec.rs +++ b/primitives/runtime/src/bounded/bounded_vec.rs @@ -847,7 +847,7 @@ where fn max_encoded_len() -> usize { // BoundedVec encodes like Vec which encodes like [T], which is a compact u32 // plus each item in the slice: - // https://docs.substrate.io/v3/advanced/scale-codec + // See: https://docs.substrate.io/reference/scale-codec/ codec::Compact(S::get()) .encoded_size() .saturating_add(Self::bound().saturating_mul(T::max_encoded_len())) diff --git a/primitives/runtime/src/bounded/weak_bounded_vec.rs b/primitives/runtime/src/bounded/weak_bounded_vec.rs index ed9f4bba62b55..a447e7285f906 100644 --- a/primitives/runtime/src/bounded/weak_bounded_vec.rs +++ b/primitives/runtime/src/bounded/weak_bounded_vec.rs @@ -443,7 +443,7 @@ where fn max_encoded_len() -> usize { // WeakBoundedVec encodes like Vec which encodes like [T], which is a compact u32 // plus each item in the slice: - // https://docs.substrate.io/v3/advanced/scale-codec + // See: https://docs.substrate.io/reference/scale-codec/ codec::Compact(S::get()) .encoded_size() .saturating_add(Self::bound().saturating_mul(T::max_encoded_len())) From 744eda47f545e31083ee722abb3a286f91a7f98d Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 3 Aug 2022 12:35:47 +0100 Subject: [PATCH 1033/1472] nit improvements to pallet template (#11968) --- bin/node-template/pallets/template/src/lib.rs | 8 ++++---- bin/node-template/pallets/template/src/mock.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index 2c337146859ef..f1519efe062bd 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -19,6 +19,10 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + /// Configure the pallet by specifying the parameters and types on which it depends. #[pallet::config] pub trait Config: frame_system::Config { @@ -26,10 +30,6 @@ pub mod pallet { type Event: From> + IsType<::Event>; } - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - // The pallet's runtime storage items. // https://docs.substrate.io/main-docs/build/runtime-storage/ #[pallet::storage] diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index 8721fe6c78851..e03f37b2eea69 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -17,8 +17,8 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - TemplateModule: pallet_template::{Pallet, Call, Storage, Event}, + System: frame_system, + TemplateModule: pallet_template, } ); From 614126401211afc95f43b62a80f83f45d38f9279 Mon Sep 17 00:00:00 2001 From: lucasvanmol Date: Thu, 4 Aug 2022 00:16:24 -0700 Subject: [PATCH 1034/1472] Update node-template's docker-compose.yml (#11802) * Update docker-compose.yml * Use production image Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: parity-processbot <> --- bin/node-template/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/node-template/docker-compose.yml b/bin/node-template/docker-compose.yml index cfc4437bbae41..bc1922f47d963 100644 --- a/bin/node-template/docker-compose.yml +++ b/bin/node-template/docker-compose.yml @@ -3,7 +3,7 @@ version: "3.2" services: dev: container_name: node-template - image: paritytech/ci-linux:974ba3ac-20201006 + image: paritytech/ci-linux:production working_dir: /var/www/node-template ports: - "9944:9944" From 317808ab8920e261840013cc0e522b47a6c0d57d Mon Sep 17 00:00:00 2001 From: ZhiYong Date: Thu, 4 Aug 2022 15:47:52 +0800 Subject: [PATCH 1035/1472] Beefy: use VersionedFinalityProof instead of SignedCommitment (#11962) * beefy: use VersionedFinalityProof instead of SignedCommitment. * Change the exposed RPC API to support versioned proofs. Co-authored-by: Adrian Catangiu --- client/beefy/rpc/src/lib.rs | 51 ++++++++++---------- client/beefy/rpc/src/notification.rs | 12 ++--- client/beefy/src/import.rs | 26 +++++------ client/beefy/src/justification.rs | 53 ++++++++++++--------- client/beefy/src/lib.rs | 14 +++--- client/beefy/src/notification.rs | 21 +++++---- client/beefy/src/tests.rs | 50 +++++++++++--------- client/beefy/src/worker.rs | 70 +++++++++++++++------------- 8 files changed, 157 insertions(+), 140 deletions(-) diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 91ff59324bd95..3be182ceb8f39 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -35,7 +35,7 @@ use jsonrpsee::{ }; use log::warn; -use beefy_gadget::notification::{BeefyBestBlockStream, BeefySignedCommitmentStream}; +use beefy_gadget::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}; mod notification; @@ -101,7 +101,7 @@ pub trait BeefyApi { /// Implements the BeefyApi RPC trait for interacting with BEEFY. pub struct Beefy { - signed_commitment_stream: BeefySignedCommitmentStream, + finality_proof_stream: BeefyVersionedFinalityProofStream, beefy_best_block: Arc>>, executor: SubscriptionTaskExecutor, } @@ -112,7 +112,7 @@ where { /// Creates a new Beefy Rpc handler instance. pub fn new( - signed_commitment_stream: BeefySignedCommitmentStream, + finality_proof_stream: BeefyVersionedFinalityProofStream, best_block_stream: BeefyBestBlockStream, executor: SubscriptionTaskExecutor, ) -> Result { @@ -126,20 +126,21 @@ where }); executor.spawn("substrate-rpc-subscription", Some("rpc"), future.map(drop).boxed()); - Ok(Self { signed_commitment_stream, beefy_best_block, executor }) + Ok(Self { finality_proof_stream, beefy_best_block, executor }) } } #[async_trait] -impl BeefyApiServer for Beefy +impl BeefyApiServer + for Beefy where Block: BlockT, { fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult { let stream = self - .signed_commitment_stream + .finality_proof_stream .subscribe() - .map(|sc| notification::EncodedSignedCommitment::new::(sc)); + .map(|vfp| notification::EncodedVersionedFinalityProof::new::(vfp)); let fut = async move { sink.pipe_from_stream(stream).await; @@ -164,31 +165,31 @@ mod tests { use super::*; use beefy_gadget::{ - justification::BeefySignedCommitment, - notification::{BeefyBestBlockStream, BeefySignedCommitmentSender}, + justification::BeefyVersionedFinalityProof, + notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofSender}, }; - use beefy_primitives::{known_payload_ids, Payload}; + use beefy_primitives::{known_payload_ids, Payload, SignedCommitment}; use codec::{Decode, Encode}; use jsonrpsee::{types::EmptyParams, RpcModule}; use sp_runtime::traits::{BlakeTwo256, Hash}; use substrate_test_runtime_client::runtime::Block; - fn setup_io_handler() -> (RpcModule>, BeefySignedCommitmentSender) { + fn setup_io_handler() -> (RpcModule>, BeefyVersionedFinalityProofSender) { let (_, stream) = BeefyBestBlockStream::::channel(); setup_io_handler_with_best_block_stream(stream) } fn setup_io_handler_with_best_block_stream( best_block_stream: BeefyBestBlockStream, - ) -> (RpcModule>, BeefySignedCommitmentSender) { - let (commitment_sender, commitment_stream) = - BeefySignedCommitmentStream::::channel(); + ) -> (RpcModule>, BeefyVersionedFinalityProofSender) { + let (finality_proof_sender, finality_proof_stream) = + BeefyVersionedFinalityProofStream::::channel(); let handler = - Beefy::new(commitment_stream, best_block_stream, sc_rpc::testing::test_executor()) + Beefy::new(finality_proof_stream, best_block_stream, sc_rpc::testing::test_executor()) .expect("Setting up the BEEFY RPC handler works"); - (handler.into_rpc(), commitment_sender) + (handler.into_rpc(), finality_proof_sender) } #[tokio::test] @@ -262,21 +263,21 @@ mod tests { assert_eq!(response.result, expected); } - fn create_commitment() -> BeefySignedCommitment { + fn create_finality_proof() -> BeefyVersionedFinalityProof { let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); - BeefySignedCommitment:: { + BeefyVersionedFinalityProof::::V1(SignedCommitment { commitment: beefy_primitives::Commitment { payload, block_number: 5, validator_set_id: 0, }, signatures: vec![], - } + }) } #[tokio::test] async fn subscribe_and_listen_to_one_justification() { - let (rpc, commitment_sender) = setup_io_handler(); + let (rpc, finality_proof_sender) = setup_io_handler(); // Subscribe let mut sub = rpc @@ -284,16 +285,16 @@ mod tests { .await .unwrap(); - // Notify with commitment - let commitment = create_commitment(); - let r: Result<(), ()> = commitment_sender.notify(|| Ok(commitment.clone())); + // Notify with finality_proof + let finality_proof = create_finality_proof(); + let r: Result<(), ()> = finality_proof_sender.notify(|| Ok(finality_proof.clone())); r.unwrap(); // Inspect what we received let (bytes, recv_sub_id) = sub.next::().await.unwrap().unwrap(); - let recv_commitment: BeefySignedCommitment = + let recv_finality_proof: BeefyVersionedFinalityProof = Decode::decode(&mut &bytes[..]).unwrap(); assert_eq!(&recv_sub_id, sub.subscription_id()); - assert_eq!(recv_commitment, commitment); + assert_eq!(recv_finality_proof, finality_proof); } } diff --git a/client/beefy/rpc/src/notification.rs b/client/beefy/rpc/src/notification.rs index cdda667782dd5..a815425644d52 100644 --- a/client/beefy/rpc/src/notification.rs +++ b/client/beefy/rpc/src/notification.rs @@ -21,19 +21,19 @@ use serde::{Deserialize, Serialize}; use sp_runtime::traits::Block as BlockT; -/// An encoded signed commitment proving that the given header has been finalized. +/// An encoded finality proof proving that the given header has been finalized. /// The given bytes should be the SCALE-encoded representation of a -/// `beefy_primitives::SignedCommitment`. +/// `beefy_primitives::VersionedFinalityProof`. #[derive(Clone, Serialize, Deserialize)] -pub struct EncodedSignedCommitment(sp_core::Bytes); +pub struct EncodedVersionedFinalityProof(sp_core::Bytes); -impl EncodedSignedCommitment { +impl EncodedVersionedFinalityProof { pub fn new( - signed_commitment: beefy_gadget::justification::BeefySignedCommitment, + finality_proof: beefy_gadget::justification::BeefyVersionedFinalityProof, ) -> Self where Block: BlockT, { - EncodedSignedCommitment(signed_commitment.encode().into()) + EncodedVersionedFinalityProof(finality_proof.encode().into()) } } diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index 7caeb49db5e50..129484199de89 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use beefy_primitives::{crypto::Signature, BeefyApi, VersionedFinalityProof, BEEFY_ENGINE_ID}; +use beefy_primitives::{BeefyApi, BEEFY_ENGINE_ID}; use codec::Encode; use log::error; use std::{collections::HashMap, sync::Arc}; @@ -34,7 +34,8 @@ use sc_client_api::backend::Backend; use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResult}; use crate::{ - justification::decode_and_verify_commitment, notification::BeefySignedCommitmentSender, + justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, + notification::BeefyVersionedFinalityProofSender, }; /// A block-import handler for BEEFY. @@ -47,7 +48,7 @@ pub struct BeefyBlockImport { backend: Arc, runtime: Arc, inner: I, - justification_sender: BeefySignedCommitmentSender, + justification_sender: BeefyVersionedFinalityProofSender, } impl Clone for BeefyBlockImport { @@ -67,7 +68,7 @@ impl BeefyBlockImport { backend: Arc, runtime: Arc, inner: I, - justification_sender: BeefySignedCommitmentSender, + justification_sender: BeefyVersionedFinalityProofSender, ) -> BeefyBlockImport { BeefyBlockImport { backend, runtime, inner, justification_sender } } @@ -85,7 +86,7 @@ where encoded: &EncodedJustification, number: NumberFor, hash: ::Hash, - ) -> Result, Signature>, ConsensusError> { + ) -> Result, ConsensusError> { let block_id = BlockId::hash(hash); let validator_set = self .runtime @@ -94,7 +95,7 @@ where .map_err(|e| ConsensusError::ClientImport(e.to_string()))? .ok_or_else(|| ConsensusError::ClientImport("Unknown validator set".to_string()))?; - decode_and_verify_commitment::(&encoded[..], number, &validator_set) + decode_and_verify_finality_proof::(&encoded[..], number, &validator_set) } /// Import BEEFY justification: Send it to worker for processing and also append it to backend. @@ -105,7 +106,7 @@ where fn import_beefy_justification_unchecked( &self, number: NumberFor, - justification: VersionedFinalityProof, Signature>, + justification: BeefyVersionedFinalityProof, ) { // Append the justification to the block in the backend. if let Err(e) = self.backend.append_justification( @@ -115,14 +116,9 @@ where error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, justification); } // Send the justification to the BEEFY voter for processing. - match justification { - // TODO #11838: Should not unpack, these channels should also use - // `VersionedFinalityProof`. - VersionedFinalityProof::V1(signed_commitment) => self - .justification_sender - .notify(|| Ok::<_, ()>(signed_commitment)) - .expect("forwards closure result; the closure always returns Ok; qed."), - }; + self.justification_sender + .notify(|| Ok::<_, ()>(justification)) + .expect("forwards closure result; the closure always returns Ok; qed."); } } diff --git a/client/beefy/src/justification.rs b/client/beefy/src/justification.rs index 2a5191daec4b5..d9be18593dac7 100644 --- a/client/beefy/src/justification.rs +++ b/client/beefy/src/justification.rs @@ -25,17 +25,17 @@ use codec::{Decode, Encode}; use sp_consensus::Error as ConsensusError; use sp_runtime::traits::{Block as BlockT, NumberFor}; -/// A commitment with matching BEEFY authorities' signatures. -pub type BeefySignedCommitment = - beefy_primitives::SignedCommitment, beefy_primitives::crypto::Signature>; +/// A finality proof with matching BEEFY authorities' signatures. +pub type BeefyVersionedFinalityProof = + beefy_primitives::VersionedFinalityProof, Signature>; -/// Decode and verify a Beefy SignedCommitment. -pub(crate) fn decode_and_verify_commitment( +/// Decode and verify a Beefy FinalityProof. +pub(crate) fn decode_and_verify_finality_proof( encoded: &[u8], target_number: NumberFor, validator_set: &ValidatorSet, -) -> Result, Signature>, ConsensusError> { - let proof = , Signature>>::decode(&mut &*encoded) +) -> Result, ConsensusError> { + let proof = >::decode(&mut &*encoded) .map_err(|_| ConsensusError::InvalidJustification)?; verify_with_validator_set::(target_number, validator_set, &proof).map(|_| proof) } @@ -44,7 +44,7 @@ pub(crate) fn decode_and_verify_commitment( fn verify_with_validator_set( target_number: NumberFor, validator_set: &ValidatorSet, - proof: &VersionedFinalityProof, Signature>, + proof: &BeefyVersionedFinalityProof, ) -> Result<(), ConsensusError> { match proof { VersionedFinalityProof::V1(signed_commitment) => { @@ -80,17 +80,19 @@ fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { - use beefy_primitives::{known_payload_ids, Commitment, Payload, SignedCommitment}; + use beefy_primitives::{ + known_payload_ids, Commitment, Payload, SignedCommitment, VersionedFinalityProof, + }; use substrate_test_runtime_client::runtime::Block; use super::*; use crate::{keystore::tests::Keyring, tests::make_beefy_ids}; - pub(crate) fn new_signed_commitment( + pub(crate) fn new_finality_proof( block_num: NumberFor, validator_set: &ValidatorSet, keys: &[Keyring], - ) -> BeefySignedCommitment { + ) -> BeefyVersionedFinalityProof { let commitment = Commitment { payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), block_number: block_num, @@ -98,7 +100,7 @@ pub(crate) mod tests { }; let message = commitment.encode(); let signatures = keys.iter().map(|key| Some(key.sign(&message))).collect(); - SignedCommitment { commitment, signatures } + VersionedFinalityProof::V1(SignedCommitment { commitment, signatures }) } #[test] @@ -108,7 +110,7 @@ pub(crate) mod tests { // build valid justification let block_num = 42; - let proof = new_signed_commitment(block_num, &validator_set, keys); + let proof = new_finality_proof(block_num, &validator_set, keys); let good_proof = proof.clone().into(); // should verify successfully @@ -132,7 +134,10 @@ pub(crate) mod tests { // wrong signatures length -> should fail verification let mut bad_proof = proof.clone(); // change length of signatures - bad_proof.signatures.pop().flatten().unwrap(); + let bad_signed_commitment = match bad_proof { + VersionedFinalityProof::V1(ref mut sc) => sc, + }; + bad_signed_commitment.signatures.pop().flatten().unwrap(); match verify_with_validator_set::(block_num + 1, &validator_set, &bad_proof.into()) { Err(ConsensusError::InvalidJustification) => (), _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), @@ -140,8 +145,11 @@ pub(crate) mod tests { // not enough signatures -> should fail verification let mut bad_proof = proof.clone(); + let bad_signed_commitment = match bad_proof { + VersionedFinalityProof::V1(ref mut sc) => sc, + }; // remove a signature (but same length) - *bad_proof.signatures.first_mut().unwrap() = None; + *bad_signed_commitment.signatures.first_mut().unwrap() = None; match verify_with_validator_set::(block_num + 1, &validator_set, &bad_proof.into()) { Err(ConsensusError::InvalidJustification) => (), _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), @@ -149,9 +157,12 @@ pub(crate) mod tests { // not enough _correct_ signatures -> should fail verification let mut bad_proof = proof.clone(); + let bad_signed_commitment = match bad_proof { + VersionedFinalityProof::V1(ref mut sc) => sc, + }; // change a signature to a different key - *bad_proof.signatures.first_mut().unwrap() = - Some(Keyring::Dave.sign(&proof.commitment.encode())); + *bad_signed_commitment.signatures.first_mut().unwrap() = + Some(Keyring::Dave.sign(&bad_signed_commitment.commitment.encode())); match verify_with_validator_set::(block_num + 1, &validator_set, &bad_proof.into()) { Err(ConsensusError::InvalidJustification) => (), _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), @@ -159,19 +170,19 @@ pub(crate) mod tests { } #[test] - fn should_decode_and_verify_commitment() { + fn should_decode_and_verify_finality_proof() { let keys = &[Keyring::Alice, Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let block_num = 1; // build valid justification - let proof = new_signed_commitment(block_num, &validator_set, keys); - let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); + let proof = new_finality_proof(block_num, &validator_set, keys); + let versioned_proof: BeefyVersionedFinalityProof = proof.into(); let encoded = versioned_proof.encode(); // should successfully decode and verify let verified = - decode_and_verify_commitment::(&encoded, block_num, &validator_set).unwrap(); + decode_and_verify_finality_proof::(&encoded, block_num, &validator_set).unwrap(); assert_eq!(verified, versioned_proof); } } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 81c72dec8cd08..bdf44e056786c 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -46,8 +46,8 @@ mod tests; use crate::{ import::BeefyBlockImport, notification::{ - BeefyBestBlockSender, BeefyBestBlockStream, BeefySignedCommitmentSender, - BeefySignedCommitmentStream, + BeefyBestBlockSender, BeefyBestBlockStream, BeefyVersionedFinalityProofSender, + BeefyVersionedFinalityProofStream, }, }; @@ -121,11 +121,11 @@ where pub struct BeefyVoterLinks { // BlockImport -> Voter links /// Stream of BEEFY signed commitments from block import to voter. - pub from_block_import_justif_stream: BeefySignedCommitmentStream, + pub from_block_import_justif_stream: BeefyVersionedFinalityProofStream, // Voter -> RPC links /// Sends BEEFY signed commitments from voter to RPC. - pub to_rpc_justif_sender: BeefySignedCommitmentSender, + pub to_rpc_justif_sender: BeefyVersionedFinalityProofSender, /// Sends BEEFY best block hashes from voter to RPC. pub to_rpc_best_block_sender: BeefyBestBlockSender, } @@ -134,7 +134,7 @@ pub struct BeefyVoterLinks { #[derive(Clone)] pub struct BeefyRPCLinks { /// Stream of signed commitments coming from the voter. - pub from_voter_justif_stream: BeefySignedCommitmentStream, + pub from_voter_justif_stream: BeefyVersionedFinalityProofStream, /// Stream of BEEFY best block hashes coming from the voter. pub from_voter_best_beefy_stream: BeefyBestBlockStream, } @@ -156,13 +156,13 @@ where { // Voter -> RPC links let (to_rpc_justif_sender, from_voter_justif_stream) = - notification::BeefySignedCommitmentStream::::channel(); + notification::BeefyVersionedFinalityProofStream::::channel(); let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = notification::BeefyBestBlockStream::::channel(); // BlockImport -> Voter links let (to_voter_justif_sender, from_block_import_justif_stream) = - notification::BeefySignedCommitmentStream::::channel(); + notification::BeefyVersionedFinalityProofStream::::channel(); // BlockImport let import = diff --git a/client/beefy/src/notification.rs b/client/beefy/src/notification.rs index 9479891714234..c673115e487f3 100644 --- a/client/beefy/src/notification.rs +++ b/client/beefy/src/notification.rs @@ -19,7 +19,7 @@ use sc_utils::notification::{NotificationSender, NotificationStream, TracingKeyStr}; use sp_runtime::traits::Block as BlockT; -use crate::justification::BeefySignedCommitment; +use crate::justification::BeefyVersionedFinalityProof; /// The sending half of the notifications channel(s) used to send /// notifications about best BEEFY block from the gadget side. @@ -31,13 +31,14 @@ pub type BeefyBestBlockStream = NotificationStream<::Hash, BeefyBestBlockTracingKey>; /// The sending half of the notifications channel(s) used to send notifications -/// about signed commitments generated at the end of a BEEFY round. -pub type BeefySignedCommitmentSender = NotificationSender>; +/// about versioned finality proof generated at the end of a BEEFY round. +pub type BeefyVersionedFinalityProofSender = + NotificationSender>; /// The receiving half of a notifications channel used to receive notifications -/// about signed commitments generated at the end of a BEEFY round. -pub type BeefySignedCommitmentStream = - NotificationStream, BeefySignedCommitmentTracingKey>; +/// about versioned finality proof generated at the end of a BEEFY round. +pub type BeefyVersionedFinalityProofStream = + NotificationStream, BeefyVersionedFinalityProofTracingKey>; /// Provides tracing key for BEEFY best block stream. #[derive(Clone)] @@ -46,9 +47,9 @@ impl TracingKeyStr for BeefyBestBlockTracingKey { const TRACING_KEY: &'static str = "mpsc_beefy_best_block_notification_stream"; } -/// Provides tracing key for BEEFY signed commitments stream. +/// Provides tracing key for BEEFY versioned finality proof stream. #[derive(Clone)] -pub struct BeefySignedCommitmentTracingKey; -impl TracingKeyStr for BeefySignedCommitmentTracingKey { - const TRACING_KEY: &'static str = "mpsc_beefy_signed_commitments_notification_stream"; +pub struct BeefyVersionedFinalityProofTracingKey; +impl TracingKeyStr for BeefyVersionedFinalityProofTracingKey { + const TRACING_KEY: &'static str = "mpsc_beefy_versioned_finality_proof_notification_stream"; } diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 9c8f443dd1f7e..134339009302b 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -397,17 +397,18 @@ fn run_for(duration: Duration, net: &Arc>, runtime: &mut Run pub(crate) fn get_beefy_streams( net: &mut BeefyTestNet, peers: &[BeefyKeyring], -) -> (Vec>, Vec>>) { +) -> (Vec>, Vec>>) +{ let mut best_block_streams = Vec::new(); - let mut signed_commitment_streams = Vec::new(); + let mut versioned_finality_proof_streams = Vec::new(); for peer_id in 0..peers.len() { let beefy_rpc_links = net.peer(peer_id).data.beefy_rpc_links.lock().clone().unwrap(); let BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream } = beefy_rpc_links; best_block_streams.push(from_voter_best_beefy_stream.subscribe()); - signed_commitment_streams.push(from_voter_justif_stream.subscribe()); + versioned_finality_proof_streams.push(from_voter_justif_stream.subscribe()); } - (best_block_streams, signed_commitment_streams) + (best_block_streams, versioned_finality_proof_streams) } fn wait_for_best_beefy_blocks( @@ -437,7 +438,7 @@ fn wait_for_best_beefy_blocks( } fn wait_for_beefy_signed_commitments( - streams: Vec>>, + streams: Vec>>, net: &Arc>, runtime: &mut Runtime, expected_commitment_block_nums: &[u64], @@ -446,9 +447,12 @@ fn wait_for_beefy_signed_commitments( let len = expected_commitment_block_nums.len(); streams.into_iter().for_each(|stream| { let mut expected = expected_commitment_block_nums.iter(); - wait_for.push(Box::pin(stream.take(len).for_each(move |signed_commitment| { + wait_for.push(Box::pin(stream.take(len).for_each(move |versioned_finality_proof| { let expected = expected.next(); async move { + let signed_commitment = match versioned_finality_proof { + beefy_primitives::VersionedFinalityProof::V1(sc) => sc, + }; let commitment_block_num = signed_commitment.commitment.block_number; assert_eq!(expected, Some(commitment_block_num).as_ref()); // TODO: also verify commitment payload, validator set id, and signatures. @@ -486,7 +490,7 @@ fn finalize_block_and_wait_for_beefy( finalize_targets: &[u64], expected_beefy: &[u64], ) { - let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); for block in finalize_targets { let finalize = BlockId::number(*block); @@ -499,11 +503,11 @@ fn finalize_block_and_wait_for_beefy( // run for quarter second then verify no new best beefy block available let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, runtime, timeout); - streams_empty_after_timeout(signed_commitments, &net, runtime, None); + streams_empty_after_timeout(versioned_finality_proof, &net, runtime, None); } else { // run until expected beefy blocks are received wait_for_best_beefy_blocks(best_blocks, &net, runtime, expected_beefy); - wait_for_beefy_signed_commitments(signed_commitments, &net, runtime, expected_beefy); + wait_for_beefy_signed_commitments(versioned_finality_proof, &net, runtime, expected_beefy); } } @@ -574,19 +578,19 @@ fn lagging_validators() { // Alice finalizes #25, Bob lags behind let finalize = BlockId::number(25); - let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); - streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); + streams_empty_after_timeout(versioned_finality_proof, &net, &mut runtime, None); // Bob catches up and also finalizes #25 - let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); // expected beefy finalizes block #17 from diff-power-of-two wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[23, 24, 25]); - wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[23, 24, 25]); + wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[23, 24, 25]); // Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32 finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[30, 32], &[30, 31, 32]); @@ -596,20 +600,20 @@ fn lagging_validators() { // validator set). // Alice finalizes session-boundary mandatory block #60, Bob lags behind - let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); let finalize = BlockId::number(60); net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); - streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); + streams_empty_after_timeout(versioned_finality_proof, &net, &mut runtime, None); // Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60) - let (best_blocks, signed_commitments) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); // verify beefy skips intermediary votes, and successfully finalizes mandatory block #40 wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]); - wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[60]); + wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[60]); } #[test] @@ -647,7 +651,7 @@ fn correct_beefy_payload() { // with 3 good voters and 1 bad one, consensus should happen and best blocks produced. finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[1, 9]); - let (best_blocks, signed_commitments) = + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]); // now 2 good validators and 1 bad one are voting @@ -673,10 +677,10 @@ fn correct_beefy_payload() { // verify consensus is _not_ reached let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); - streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None); + streams_empty_after_timeout(versioned_finality_proof, &net, &mut runtime, None); // 3rd good validator catches up and votes as well - let (best_blocks, signed_commitments) = + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]); net.lock() .peer(2) @@ -687,7 +691,7 @@ fn correct_beefy_payload() { // verify consensus is reached wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[11]); - wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[11]); + wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[11]); } #[test] @@ -746,7 +750,7 @@ fn beefy_importing_blocks() { let block_num = 2; let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let proof = crate::justification::tests::new_signed_commitment(block_num, &validator_set, keys); + let proof = crate::justification::tests::new_finality_proof(block_num, &validator_set, keys); let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); let encoded = versioned_proof.encode(); let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); @@ -781,7 +785,7 @@ fn beefy_importing_blocks() { let block_num = 3; let keys = &[BeefyKeyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); - let proof = crate::justification::tests::new_signed_commitment(block_num, &validator_set, keys); + let proof = crate::justification::tests::new_finality_proof(block_num, &validator_set, keys); let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); let encoded = versioned_proof.encode(); let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 3bff0822ebdb4..2c4985c0e6966 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -49,7 +49,7 @@ use beefy_primitives::{ use crate::{ error::Error, gossip::{topic, GossipValidator}, - justification::BeefySignedCommitment, + justification::BeefyVersionedFinalityProof, keystore::BeefyKeystore, metric_inc, metric_set, metrics::Metrics, @@ -212,7 +212,7 @@ pub(crate) struct BeefyWorker { /// Buffer holding votes for future processing. pending_votes: BTreeMap, Vec, AuthorityId, Signature>>>, /// Buffer holding justifications for future processing. - pending_justifications: BTreeMap, Vec>>, + pending_justifications: BTreeMap, Vec>>, /// Chooses which incoming votes to accept and which votes to generate. voting_oracle: VoterOracle, } @@ -381,9 +381,12 @@ where /// Expects `justification` to be valid. fn triage_incoming_justif( &mut self, - justification: BeefySignedCommitment, + justification: BeefyVersionedFinalityProof, ) -> Result<(), Error> { - let block_num = justification.commitment.block_number; + let signed_commitment = match justification { + VersionedFinalityProof::V1(ref sc) => sc, + }; + let block_num = signed_commitment.commitment.block_number; let best_grandpa = *self.best_grandpa_block_header.number(); match self.voting_oracle.triage_round(block_num, best_grandpa)? { RoundAction::Process => self.finalize(justification), @@ -417,39 +420,39 @@ where validator_set_id: rounds.validator_set_id(), }; - let signed_commitment = SignedCommitment { commitment, signatures }; + let finality_proof = + VersionedFinalityProof::V1(SignedCommitment { commitment, signatures }); metric_set!(self, beefy_round_concluded, block_num); - info!(target: "beefy", "🥩 Round #{} concluded, committed: {:?}.", round.1, signed_commitment); + info!(target: "beefy", "🥩 Round #{} concluded, finality_proof: {:?}.", round.1, finality_proof); if let Err(e) = self.backend.append_justification( BlockId::Number(block_num), - ( - BEEFY_ENGINE_ID, - VersionedFinalityProof::V1(signed_commitment.clone()).encode(), - ), + (BEEFY_ENGINE_ID, finality_proof.clone().encode()), ) { - debug!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, signed_commitment); + debug!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, finality_proof); } - // We created the `signed_commitment` and know to be valid. - self.finalize(signed_commitment); + // We created the `finality_proof` and know to be valid. + self.finalize(finality_proof); } } Ok(()) } - /// Provide BEEFY finality for block based on `signed_commitment`: + /// Provide BEEFY finality for block based on `finality_proof`: /// 1. Prune irrelevant past sessions from the oracle, /// 2. Set BEEFY best block, - /// 3. Send best block hash and `signed_commitment` to RPC worker. + /// 3. Send best block hash and `finality_proof` to RPC worker. /// - /// Expects `signed commitment` to be valid. - fn finalize(&mut self, signed_commitment: BeefySignedCommitment) { + /// Expects `finality proof` to be valid. + fn finalize(&mut self, finality_proof: BeefyVersionedFinalityProof) { // Prune any now "finalized" sessions from queue. self.voting_oracle.try_prune(); - + let signed_commitment = match finality_proof { + VersionedFinalityProof::V1(ref sc) => sc, + }; let block_num = signed_commitment.commitment.block_number; if Some(block_num) > self.best_beefy_block { // Set new best BEEFY block number. @@ -465,7 +468,7 @@ where self.links .to_rpc_justif_sender - .notify(|| Ok::<_, ()>(signed_commitment)) + .notify(|| Ok::<_, ()>(finality_proof)) .expect("forwards closure result; the closure always returns Ok; qed."); } else { debug!(target: "beefy", "🥩 Can't set best beefy to older: {}", block_num); @@ -832,7 +835,7 @@ pub(crate) mod tests { use super::*; use crate::{ keystore::tests::Keyring, - notification::{BeefyBestBlockStream, BeefySignedCommitmentStream}, + notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, tests::{ create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi, BeefyPeer, BeefyTestNet, BEEFY_PROTOCOL_NAME, @@ -859,10 +862,11 @@ pub(crate) mod tests { let keystore = create_beefy_keystore(*key); let (to_rpc_justif_sender, from_voter_justif_stream) = - BeefySignedCommitmentStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = BeefyBestBlockStream::::channel(); - let (_, from_block_import_justif_stream) = BeefySignedCommitmentStream::::channel(); + let (_, from_block_import_justif_stream) = + BeefyVersionedFinalityProofStream::::channel(); let beefy_rpc_links = BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream }; @@ -1168,37 +1172,37 @@ pub(crate) mod tests { let mut net = BeefyTestNet::new(1, 0); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); - let (mut best_block_streams, mut signed_commitments) = get_beefy_streams(&mut net, keys); + let (mut best_block_streams, mut finality_proofs) = get_beefy_streams(&mut net, keys); let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); - let mut signed_commitments = signed_commitments.drain(..).next().unwrap(); + let mut finality_proof = finality_proofs.drain(..).next().unwrap(); - let create_signed_commitment = |block_num: NumberFor| { + let create_finality_proof = |block_num: NumberFor| { let commitment = Commitment { payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), block_number: block_num, validator_set_id: validator_set.id(), }; - SignedCommitment { commitment, signatures: vec![None] } + VersionedFinalityProof::V1(SignedCommitment { commitment, signatures: vec![None] }) }; - // no 'best beefy block' or signed commitments + // no 'best beefy block' or finality proofs assert_eq!(worker.best_beefy_block, None); block_on(poll_fn(move |cx| { assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); - assert_eq!(signed_commitments.poll_next_unpin(cx), Poll::Pending); + assert_eq!(finality_proof.poll_next_unpin(cx), Poll::Pending); Poll::Ready(()) })); // unknown hash for block #1 - let (mut best_block_streams, mut signed_commitments) = get_beefy_streams(&mut net, keys); + let (mut best_block_streams, mut finality_proofs) = get_beefy_streams(&mut net, keys); let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); - let mut signed_commitments = signed_commitments.drain(..).next().unwrap(); - let justif = create_signed_commitment(1); + let mut finality_proof = finality_proofs.drain(..).next().unwrap(); + let justif = create_finality_proof(1); worker.finalize(justif.clone()); assert_eq!(worker.best_beefy_block, Some(1)); block_on(poll_fn(move |cx| { assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); - match signed_commitments.poll_next_unpin(cx) { + match finality_proof.poll_next_unpin(cx) { // expect justification Poll::Ready(Some(received)) => assert_eq!(received, justif), v => panic!("unexpected value: {:?}", v), @@ -1211,7 +1215,7 @@ pub(crate) mod tests { let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); net.generate_blocks(2, 10, &validator_set, false); - let justif = create_signed_commitment(2); + let justif = create_finality_proof(2); worker.finalize(justif); assert_eq!(worker.best_beefy_block, Some(2)); block_on(poll_fn(move |cx| { From 9ece574bd1472275eed212acf8c69ae49c38f57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 4 Aug 2022 11:34:19 +0200 Subject: [PATCH 1036/1472] Timestamp: `set_timestamp` sets `DidUpdate` (#11960) * Timestamp: `set_timestamp` sets `DidUpdate` There exists the `set_timestamp` in the Timestamp pallet for setting the current timestamp. The problem is that it doesn't set `DidUpdate`. This results in `on_finalize` panicking. There is no real reason why the function doesn't also set `DidUpdate`. * Update frame/timestamp/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Fix Babe tests Co-authored-by: Oliver Tale-Yazdi --- frame/babe/src/mock.rs | 2 +- frame/babe/src/tests.rs | 2 +- frame/timestamp/src/lib.rs | 2 ++ frame/timestamp/src/tests.rs | 5 ++--- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 5677eb7e28e49..c2ba3c2be06d8 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -429,7 +429,7 @@ pub fn generate_equivocation_proof( System::reset_events(); System::initialize(¤t_block, &parent_hash, &pre_digest); System::set_block_number(current_block); - Timestamp::set_timestamp(current_block); + Timestamp::set_timestamp(*current_slot * Babe::slot_duration()); System::finalize() }; diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 0859bb7a40849..ece0883387709 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -659,7 +659,7 @@ fn report_equivocation_invalid_equivocation_proof() { equivocation_proof.second_header = equivocation_proof.first_header.clone(); assert_invalid_equivocation(equivocation_proof); - // missing preruntime digest from one header + // missing pre-runtime digest from one header let mut equivocation_proof = generate_equivocation_proof( offending_validator_index as u32, &offending_authority_pair, diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index 81ed67913c2e6..6a7f849d1329a 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -282,6 +282,8 @@ impl Pallet { #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] pub fn set_timestamp(now: T::Moment) { Now::::put(now); + DidUpdate::::put(true); + >::on_timestamp_set(now); } } diff --git a/frame/timestamp/src/tests.rs b/frame/timestamp/src/tests.rs index f52ba7849c951..ef9fd6e39d4b5 100644 --- a/frame/timestamp/src/tests.rs +++ b/frame/timestamp/src/tests.rs @@ -23,7 +23,7 @@ use frame_support::assert_ok; #[test] fn timestamp_works() { new_test_ext().execute_with(|| { - Timestamp::set_timestamp(42); + crate::Now::::put(46); assert_ok!(Timestamp::set(Origin::none(), 69)); assert_eq!(Timestamp::now(), 69); assert_eq!(Some(69), get_captured_moment()); @@ -36,7 +36,6 @@ fn double_timestamp_should_fail() { new_test_ext().execute_with(|| { Timestamp::set_timestamp(42); assert_ok!(Timestamp::set(Origin::none(), 69)); - let _ = Timestamp::set(Origin::none(), 70); }); } @@ -46,7 +45,7 @@ fn double_timestamp_should_fail() { )] fn block_period_minimum_enforced() { new_test_ext().execute_with(|| { - Timestamp::set_timestamp(42); + crate::Now::::put(44); let _ = Timestamp::set(Origin::none(), 46); }); } From d09f5d92677c460bbb8b9b3e084bd9f3c1ffaf4c Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 4 Aug 2022 22:57:05 +0200 Subject: [PATCH 1037/1472] Prevent duplicated leaves in the backend (#11941) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Prevent duplicated leaves in the backend * Comments... * Use highest known heaf as a shortcut for not existing header detection * Apply code review suggestion Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- client/db/src/lib.rs | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index e14d3a26aa557..0ce408a39b004 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1345,8 +1345,15 @@ impl Backend { let parent_hash = *pending_block.header.parent_hash(); let number = *pending_block.header.number(); + let highest_leaf = self + .blockchain + .leaves + .read() + .highest_leaf() + .map(|(n, _)| n) + .unwrap_or(Zero::zero()); let existing_header = - number <= best_num && self.blockchain.header(BlockId::hash(hash))?.is_some(); + number <= highest_leaf && self.blockchain.header(BlockId::hash(hash))?.is_some(); // blocks are keyed by number + hash. let lookup_key = utils::number_and_hash_to_lookup_key(number, hash)?; @@ -3534,7 +3541,24 @@ pub(crate) mod tests { header.hash() }; - let block3_fork = insert_header_no_head(&backend, 3, block2, Default::default()); + let block3_fork = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Hash(block2)).unwrap(); + let header = Header { + number: 3, + parent_hash: block2, + state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), + digest: Default::default(), + extrinsics_root: H256::from_low_u64_le(42), + }; + + op.set_block_data(header.clone(), Some(Vec::new()), None, None, NewBlockState::Normal) + .unwrap(); + + backend.commit_operation(op).unwrap(); + + header.hash() + }; assert!(backend.have_state_at(&block1, 1)); assert!(backend.have_state_at(&block2, 2)); @@ -3556,4 +3580,20 @@ pub(crate) mod tests { assert_eq!(backend.blockchain.leaves().unwrap(), vec![block1]); assert_eq!(1, backend.blockchain.leaves.read().highest_leaf().unwrap().0); } + + #[test] + fn test_no_duplicated_leaves_allowed() { + let backend: Backend = Backend::new_test(10, 10); + let block0 = insert_header(&backend, 0, Default::default(), None, Default::default()); + let block1 = insert_header(&backend, 1, block0, None, Default::default()); + // Add block 2 not as the best block + let block2 = insert_header_no_head(&backend, 2, block1, Default::default()); + assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2]); + assert_eq!(backend.blockchain().info().best_hash, block1); + + // Add block 2 as the best block + let block2 = insert_header(&backend, 2, block1, None, Default::default()); + assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2]); + assert_eq!(backend.blockchain().info().best_hash, block2); + } } From 6527f0cc6e14f750d83a37f468e65a17d4088854 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 5 Aug 2022 09:50:57 +0300 Subject: [PATCH 1038/1472] Change on-the-wire protocol names to include genesis hash & fork id (#11938) * Rename transactions protocol to include genesis hash * Add protocol name generation to sc_network::utils * Use utils functions for transactions protocol name generation * Extract protocol name generation into public module * Use sc_network::protocol_name::standard_protocol_name() for BEEFY and GRANDPA * minor: add missing newline at EOF * Change block-announces protocol name to include genesis_hash & fork_id * Change protocol names to include genesis hash and fork id Protocols changed: - sync - state - light - sync/warp * Revert "Use sc_network::protocol_name::standard_protocol_name() for BEEFY and GRANDPA" This reverts commit 29aa556ef947e2cfd48264db2a9fc8bc528d7ddb. * Get rid of `protocol_name` module --- Cargo.lock | 2 + .../network/common/src/request_responses.rs | 3 ++ client/network/light/Cargo.toml | 1 + .../light/src/light_client_requests.rs | 23 +++++++++-- .../src/light_client_requests/handler.rs | 20 ++++++++-- client/network/src/config.rs | 6 ++- client/network/src/protocol.rs | 18 +++++++-- client/network/src/request_responses.rs | 10 ++++- client/network/src/service.rs | 13 +++++- client/network/src/service/tests.rs | 11 +++-- client/network/src/transactions.rs | 21 ++++++++-- client/network/sync/Cargo.toml | 1 + .../network/sync/src/block_request_handler.rs | 34 +++++++++++++--- .../network/sync/src/state_request_handler.rs | 40 +++++++++++++++---- .../network/sync/src/warp_request_handler.rs | 30 +++++++++++--- client/network/test/src/lib.rs | 21 +++++++--- client/service/src/builder.rs | 22 ++++++++-- 17 files changed, 226 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec5c5267142a9..703eeffce54a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8435,6 +8435,7 @@ name = "sc-network-light" version = "0.10.0-dev" dependencies = [ "futures", + "hex", "libp2p", "log", "parity-scale-codec", @@ -8455,6 +8456,7 @@ version = "0.10.0-dev" dependencies = [ "fork-tree", "futures", + "hex", "libp2p", "log", "lru", diff --git a/client/network/common/src/request_responses.rs b/client/network/common/src/request_responses.rs index 71570e6beb864..f409d1ac16d61 100644 --- a/client/network/common/src/request_responses.rs +++ b/client/network/common/src/request_responses.rs @@ -29,6 +29,9 @@ pub struct ProtocolConfig { /// Name of the protocol on the wire. Should be something like `/foo/bar`. pub name: Cow<'static, str>, + /// Fallback on the wire protocol names to support. + pub fallback_names: Vec>, + /// Maximum allowed size, in bytes, of a request. /// /// Any request larger than this value will be declined as a way to avoid allocating too diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index 0037177fb4046..c1a0fb4759320 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -21,6 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" +hex = "0.4.0" libp2p = "0.46.1" log = "0.4.16" prost = "0.10" diff --git a/client/network/light/src/light_client_requests.rs b/client/network/light/src/light_client_requests.rs index 9eccef41e833d..b58426cf15992 100644 --- a/client/network/light/src/light_client_requests.rs +++ b/client/network/light/src/light_client_requests.rs @@ -25,16 +25,31 @@ use sc_network_common::{config::ProtocolId, request_responses::ProtocolConfig}; use std::time::Duration; -/// Generate the light client protocol name from chain specific protocol identifier. -fn generate_protocol_name(protocol_id: &ProtocolId) -> String { +/// Generate the light client protocol name from the genesis hash and fork id. +fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + if let Some(fork_id) = fork_id { + format!("/{}/{}/light/2", hex::encode(genesis_hash), fork_id) + } else { + format!("/{}/light/2", hex::encode(genesis_hash)) + } +} + +/// Generate the legacy light client protocol name from chain specific protocol identifier. +fn generate_legacy_protocol_name(protocol_id: &ProtocolId) -> String { format!("/{}/light/2", protocol_id.as_ref()) } /// Generates a [`ProtocolConfig`] for the light client request protocol, refusing incoming /// requests. -pub fn generate_protocol_config(protocol_id: &ProtocolId) -> ProtocolConfig { +pub fn generate_protocol_config>( + protocol_id: &ProtocolId, + genesis_hash: Hash, + fork_id: Option<&str>, +) -> ProtocolConfig { ProtocolConfig { - name: generate_protocol_name(protocol_id).into(), + name: generate_protocol_name(genesis_hash, fork_id).into(), + fallback_names: std::iter::once(generate_legacy_protocol_name(protocol_id).into()) + .collect(), max_request_size: 1 * 1024 * 1024, max_response_size: 16 * 1024 * 1024, request_timeout: Duration::from_secs(15), diff --git a/client/network/light/src/light_client_requests/handler.rs b/client/network/light/src/light_client_requests/handler.rs index 3c87ccfd6ed9f..727a9b0d7e820 100644 --- a/client/network/light/src/light_client_requests/handler.rs +++ b/client/network/light/src/light_client_requests/handler.rs @@ -28,7 +28,7 @@ use futures::{channel::mpsc, prelude::*}; use libp2p::PeerId; use log::{debug, trace}; use prost::Message; -use sc_client_api::{ProofProvider, StorageProof}; +use sc_client_api::{BlockBackend, ProofProvider, StorageProof}; use sc_network_common::{ config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, @@ -54,15 +54,27 @@ pub struct LightClientRequestHandler { impl LightClientRequestHandler where B: Block, - Client: ProofProvider + Send + Sync + 'static, + Client: BlockBackend + ProofProvider + Send + Sync + 'static, { /// Create a new [`LightClientRequestHandler`]. - pub fn new(protocol_id: &ProtocolId, client: Arc) -> (Self, ProtocolConfig) { + pub fn new( + protocol_id: &ProtocolId, + fork_id: Option<&str>, + client: Arc, + ) -> (Self, ProtocolConfig) { // For now due to lack of data on light client request handling in production systems, this // value is chosen to match the block request limit. let (tx, request_receiver) = mpsc::channel(20); - let mut protocol_config = super::generate_protocol_config(protocol_id); + let mut protocol_config = super::generate_protocol_config( + protocol_id, + client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + fork_id, + ); protocol_config.inbound_queue = Some(tx); (Self { client, request_receiver, _block: PhantomData::default() }, protocol_config) diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 2622762da5fc9..afd61cae6c83b 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -87,9 +87,13 @@ where /// the network. pub transaction_pool: Arc>, - /// Name of the protocol to use on the wire. Should be different for each chain. + /// Legacy name of the protocol to use on the wire. Should be different for each chain. pub protocol_id: ProtocolId, + /// Fork ID to distinguish protocols of different hard forks. Part of the standard protocol + /// name on the wire. + pub fork_id: Option, + /// Import queue to use. /// /// The import queue is the component that verifies that blocks received from other nodes are diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 1c933fabcbb5d..a06fff2322ce6 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -276,6 +276,7 @@ where roles: Roles, chain: Arc, protocol_id: ProtocolId, + fork_id: &Option, network_config: &config::NetworkConfiguration, notifications_protocols_handshakes: Vec>, metrics_registry: Option<&Registry>, @@ -371,8 +372,17 @@ where sc_peerset::Peerset::from_config(sc_peerset::PeersetConfig { sets }) }; - let block_announces_protocol: Cow<'static, str> = - format!("/{}/block-announces/1", protocol_id.as_ref()).into(); + let block_announces_protocol = { + let genesis_hash = + chain.block_hash(0u32.into()).ok().flatten().expect("Genesis block exists; qed"); + if let Some(fork_id) = fork_id { + format!("/{}/{}/block-announces/1", hex::encode(genesis_hash), fork_id) + } else { + format!("/{}/block-announces/1", hex::encode(genesis_hash)) + } + }; + + let legacy_ba_protocol_name = format!("/{}/block-announces/1", protocol_id.as_ref()); let behaviour = { let best_number = info.best_number; @@ -384,8 +394,8 @@ where .encode(); let sync_protocol_config = notifications::ProtocolConfig { - name: block_announces_protocol, - fallback_names: Vec::new(), + name: block_announces_protocol.into(), + fallback_names: iter::once(legacy_ba_protocol_name.into()).collect(), handshake: block_announces_handshake, max_notification_size: MAX_BLOCK_ANNOUNCE_SIZE, }; diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index cec4aa2a07fba..0d8c6c33b1c95 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -220,7 +220,9 @@ impl RequestResponsesBehaviour { max_request_size: protocol.max_request_size, max_response_size: protocol.max_response_size, }, - iter::once((protocol.name.as_bytes().to_vec(), protocol_support)), + iter::once(protocol.name.as_bytes().to_vec()) + .chain(protocol.fallback_names.iter().map(|name| name.as_bytes().to_vec())) + .zip(iter::repeat(protocol_support)), cfg, ); @@ -1027,6 +1029,7 @@ mod tests { let protocol_config = ProtocolConfig { name: From::from(protocol_name), + fallback_names: Vec::new(), max_request_size: 1024, max_response_size: 1024 * 1024, request_timeout: Duration::from_secs(30), @@ -1127,6 +1130,7 @@ mod tests { let protocol_config = ProtocolConfig { name: From::from(protocol_name), + fallback_names: Vec::new(), max_request_size: 1024, max_response_size: 8, // <-- important for the test request_timeout: Duration::from_secs(30), @@ -1223,6 +1227,7 @@ mod tests { let protocol_configs = vec![ ProtocolConfig { name: From::from(protocol_name_1), + fallback_names: Vec::new(), max_request_size: 1024, max_response_size: 1024 * 1024, request_timeout: Duration::from_secs(30), @@ -1230,6 +1235,7 @@ mod tests { }, ProtocolConfig { name: From::from(protocol_name_2), + fallback_names: Vec::new(), max_request_size: 1024, max_response_size: 1024 * 1024, request_timeout: Duration::from_secs(30), @@ -1247,6 +1253,7 @@ mod tests { let protocol_configs = vec![ ProtocolConfig { name: From::from(protocol_name_1), + fallback_names: Vec::new(), max_request_size: 1024, max_response_size: 1024 * 1024, request_timeout: Duration::from_secs(30), @@ -1254,6 +1261,7 @@ mod tests { }, ProtocolConfig { name: From::from(protocol_name_2), + fallback_names: Vec::new(), max_request_size: 1024, max_response_size: 1024 * 1024, request_timeout: Duration::from_secs(30), diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 409ed88c75c00..1210b0ca64224 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -224,8 +224,16 @@ where fs::create_dir_all(path)?; } - let transactions_handler_proto = - transactions::TransactionsHandlerPrototype::new(params.protocol_id.clone()); + let transactions_handler_proto = transactions::TransactionsHandlerPrototype::new( + params.protocol_id.clone(), + params + .chain + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + params.fork_id.clone(), + ); params .network_config .extra_sets @@ -243,6 +251,7 @@ where From::from(¶ms.role), params.chain.clone(), params.protocol_id.clone(), + ¶ms.fork_id, ¶ms.network_config, iter::once(Vec::new()) .chain( diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index de474ee8fe4d0..f757bf4891fbc 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -92,21 +92,25 @@ fn build_test_full_node( let protocol_id = ProtocolId::from("/test-protocol-name"); + let fork_id = Some(String::from("test-fork-id")); + let block_request_protocol_config = { - let (handler, protocol_config) = BlockRequestHandler::new(&protocol_id, client.clone(), 50); + let (handler, protocol_config) = + BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); async_std::task::spawn(handler.run().boxed()); protocol_config }; let state_request_protocol_config = { - let (handler, protocol_config) = StateRequestHandler::new(&protocol_id, client.clone(), 50); + let (handler, protocol_config) = + StateRequestHandler::new(&protocol_id, None, client.clone(), 50); async_std::task::spawn(handler.run().boxed()); protocol_config }; let light_client_request_protocol_config = { let (handler, protocol_config) = - LightClientRequestHandler::new(&protocol_id, client.clone()); + LightClientRequestHandler::new(&protocol_id, None, client.clone()); async_std::task::spawn(handler.run().boxed()); protocol_config }; @@ -134,6 +138,7 @@ fn build_test_full_node( chain: client.clone(), transaction_pool: Arc::new(config::EmptyTransactionPool), protocol_id, + fork_id, import_queue, chain_sync: Box::new(chain_sync), metrics_registry: None, diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 043bdeff7ebfc..342b6a0430272 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -127,19 +127,34 @@ impl Future for PendingTransaction { /// Prototype for a [`TransactionsHandler`]. pub struct TransactionsHandlerPrototype { protocol_name: Cow<'static, str>, + fallback_protocol_names: Vec>, } impl TransactionsHandlerPrototype { /// Create a new instance. - pub fn new(protocol_id: ProtocolId) -> Self { - Self { protocol_name: format!("/{}/transactions/1", protocol_id.as_ref()).into() } + pub fn new>( + protocol_id: ProtocolId, + genesis_hash: Hash, + fork_id: Option, + ) -> Self { + let protocol_name = if let Some(fork_id) = fork_id { + format!("/{}/{}/transactions/1", hex::encode(genesis_hash), fork_id) + } else { + format!("/{}/transactions/1", hex::encode(genesis_hash)) + }; + let legacy_protocol_name = format!("/{}/transactions/1", protocol_id.as_ref()); + + Self { + protocol_name: protocol_name.into(), + fallback_protocol_names: iter::once(legacy_protocol_name.into()).collect(), + } } /// Returns the configuration of the set to put in the network configuration. pub fn set_config(&self) -> config::NonDefaultSetConfig { config::NonDefaultSetConfig { notifications_protocol: self.protocol_name.clone(), - fallback_names: Vec::new(), + fallback_names: self.fallback_protocol_names.clone(), max_notification_size: MAX_TRANSACTIONS_SIZE, set_config: config::SetConfig { in_peers: 0, diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 3e3526146400a..7c8f8adafd214 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -21,6 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" +hex = "0.4.0" libp2p = "0.46.1" log = "0.4.17" lru = "0.7.5" diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index 30cbb32289d66..f4f10ac73c8d9 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -62,9 +62,15 @@ mod rep { } /// Generates a [`ProtocolConfig`] for the block request protocol, refusing incoming requests. -pub fn generate_protocol_config(protocol_id: &ProtocolId) -> ProtocolConfig { +pub fn generate_protocol_config>( + protocol_id: &ProtocolId, + genesis_hash: Hash, + fork_id: Option<&str>, +) -> ProtocolConfig { ProtocolConfig { - name: generate_protocol_name(protocol_id).into(), + name: generate_protocol_name(genesis_hash, fork_id).into(), + fallback_names: std::iter::once(generate_legacy_protocol_name(protocol_id).into()) + .collect(), max_request_size: 1024 * 1024, max_response_size: 16 * 1024 * 1024, request_timeout: Duration::from_secs(20), @@ -72,8 +78,17 @@ pub fn generate_protocol_config(protocol_id: &ProtocolId) -> ProtocolConfig { } } -/// Generate the block protocol name from chain specific protocol identifier. -fn generate_protocol_name(protocol_id: &ProtocolId) -> String { +/// Generate the block protocol name from the genesis hash and fork id. +fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + if let Some(fork_id) = fork_id { + format!("/{}/{}/sync/2", hex::encode(genesis_hash), fork_id) + } else { + format!("/{}/sync/2", hex::encode(genesis_hash)) + } +} + +/// Generate the legacy block protocol name from chain specific protocol identifier. +fn generate_legacy_protocol_name(protocol_id: &ProtocolId) -> String { format!("/{}/sync/2", protocol_id.as_ref()) } @@ -129,6 +144,7 @@ where /// Create a new [`BlockRequestHandler`]. pub fn new( protocol_id: &ProtocolId, + fork_id: Option<&str>, client: Arc, num_peer_hint: usize, ) -> (Self, ProtocolConfig) { @@ -136,7 +152,15 @@ where // number of peers. let (tx, request_receiver) = mpsc::channel(num_peer_hint); - let mut protocol_config = generate_protocol_config(protocol_id); + let mut protocol_config = generate_protocol_config( + protocol_id, + client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + fork_id, + ); protocol_config.inbound_queue = Some(tx); let seen_requests = LruCache::new(num_peer_hint * 2); diff --git a/client/network/sync/src/state_request_handler.rs b/client/network/sync/src/state_request_handler.rs index 8e0bae14046da..6cf6482a44f8b 100644 --- a/client/network/sync/src/state_request_handler.rs +++ b/client/network/sync/src/state_request_handler.rs @@ -27,7 +27,7 @@ use libp2p::PeerId; use log::{debug, trace}; use lru::LruCache; use prost::Message; -use sc_client_api::ProofProvider; +use sc_client_api::{BlockBackend, ProofProvider}; use sc_network_common::{ config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, @@ -50,10 +50,16 @@ mod rep { pub const SAME_REQUEST: Rep = Rep::new(i32::MIN, "Same state request multiple times"); } -/// Generates a [`ProtocolConfig`] for the block request protocol, refusing incoming requests. -pub fn generate_protocol_config(protocol_id: &ProtocolId) -> ProtocolConfig { +/// Generates a [`ProtocolConfig`] for the state request protocol, refusing incoming requests. +pub fn generate_protocol_config>( + protocol_id: &ProtocolId, + genesis_hash: Hash, + fork_id: Option<&str>, +) -> ProtocolConfig { ProtocolConfig { - name: generate_protocol_name(protocol_id).into(), + name: generate_protocol_name(genesis_hash, fork_id).into(), + fallback_names: std::iter::once(generate_legacy_protocol_name(protocol_id).into()) + .collect(), max_request_size: 1024 * 1024, max_response_size: 16 * 1024 * 1024, request_timeout: Duration::from_secs(40), @@ -61,8 +67,17 @@ pub fn generate_protocol_config(protocol_id: &ProtocolId) -> ProtocolConfig { } } -/// Generate the state protocol name from chain specific protocol identifier. -fn generate_protocol_name(protocol_id: &ProtocolId) -> String { +/// Generate the state protocol name from the genesis hash and fork id. +fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + if let Some(fork_id) = fork_id { + format!("/{}/{}/state/2", hex::encode(genesis_hash), fork_id) + } else { + format!("/{}/state/2", hex::encode(genesis_hash)) + } +} + +/// Generate the legacy state protocol name from chain specific protocol identifier. +fn generate_legacy_protocol_name(protocol_id: &ProtocolId) -> String { format!("/{}/state/2", protocol_id.as_ref()) } @@ -104,11 +119,12 @@ pub struct StateRequestHandler { impl StateRequestHandler where B: BlockT, - Client: ProofProvider + Send + Sync + 'static, + Client: BlockBackend + ProofProvider + Send + Sync + 'static, { /// Create a new [`StateRequestHandler`]. pub fn new( protocol_id: &ProtocolId, + fork_id: Option<&str>, client: Arc, num_peer_hint: usize, ) -> (Self, ProtocolConfig) { @@ -116,7 +132,15 @@ where // number of peers. let (tx, request_receiver) = mpsc::channel(num_peer_hint); - let mut protocol_config = generate_protocol_config(protocol_id); + let mut protocol_config = generate_protocol_config( + protocol_id, + client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + fork_id, + ); protocol_config.inbound_queue = Some(tx); let seen_requests = LruCache::new(num_peer_hint * 2); diff --git a/client/network/sync/src/warp_request_handler.rs b/client/network/sync/src/warp_request_handler.rs index 53ec216a1e668..394bc68449099 100644 --- a/client/network/sync/src/warp_request_handler.rs +++ b/client/network/sync/src/warp_request_handler.rs @@ -36,9 +36,15 @@ const MAX_RESPONSE_SIZE: u64 = 16 * 1024 * 1024; /// Generates a [`RequestResponseConfig`] for the grandpa warp sync request protocol, refusing /// incoming requests. -pub fn generate_request_response_config(protocol_id: ProtocolId) -> RequestResponseConfig { +pub fn generate_request_response_config>( + protocol_id: ProtocolId, + genesis_hash: Hash, + fork_id: Option<&str>, +) -> RequestResponseConfig { RequestResponseConfig { - name: generate_protocol_name(protocol_id).into(), + name: generate_protocol_name(genesis_hash, fork_id).into(), + fallback_names: std::iter::once(generate_legacy_protocol_name(protocol_id).into()) + .collect(), max_request_size: 32, max_response_size: MAX_RESPONSE_SIZE, request_timeout: Duration::from_secs(10), @@ -46,8 +52,17 @@ pub fn generate_request_response_config(protocol_id: ProtocolId) -> RequestRespo } } -/// Generate the grandpa warp sync protocol name from chain specific protocol identifier. -fn generate_protocol_name(protocol_id: ProtocolId) -> String { +/// Generate the grandpa warp sync protocol name from the genesi hash and fork id. +fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + if let Some(fork_id) = fork_id { + format!("/{}/{}/sync/warp", hex::encode(genesis_hash), fork_id) + } else { + format!("/{}/sync/warp", hex::encode(genesis_hash)) + } +} + +/// Generate the legacy grandpa warp sync protocol name from chain specific protocol identifier. +fn generate_legacy_protocol_name(protocol_id: ProtocolId) -> String { format!("/{}/sync/warp", protocol_id.as_ref()) } @@ -59,13 +74,16 @@ pub struct RequestHandler { impl RequestHandler { /// Create a new [`RequestHandler`]. - pub fn new( + pub fn new>( protocol_id: ProtocolId, + genesis_hash: Hash, + fork_id: Option<&str>, backend: Arc>, ) -> (Self, RequestResponseConfig) { let (tx, request_receiver) = mpsc::channel(20); - let mut request_response_config = generate_request_response_config(protocol_id); + let mut request_response_config = + generate_request_response_config(protocol_id, genesis_hash, fork_id); request_response_config.inbound_queue = Some(tx); (Self { backend, request_receiver }, request_response_config) diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 4659684987f77..494ff2048f6c4 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -808,23 +808,25 @@ where let protocol_id = ProtocolId::from("test-protocol-name"); + let fork_id = Some(String::from("test-fork-id")); + let block_request_protocol_config = { let (handler, protocol_config) = - BlockRequestHandler::new(&protocol_id, client.clone(), 50); + BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); self.spawn_task(handler.run().boxed()); protocol_config }; let state_request_protocol_config = { let (handler, protocol_config) = - StateRequestHandler::new(&protocol_id, client.clone(), 50); + StateRequestHandler::new(&protocol_id, None, client.clone(), 50); self.spawn_task(handler.run().boxed()); protocol_config }; let light_client_request_protocol_config = { let (handler, protocol_config) = - LightClientRequestHandler::new(&protocol_id, client.clone()); + LightClientRequestHandler::new(&protocol_id, None, client.clone()); self.spawn_task(handler.run().boxed()); protocol_config }; @@ -832,8 +834,16 @@ where let warp_sync = Arc::new(TestWarpSyncProvider(client.clone())); let warp_protocol_config = { - let (handler, protocol_config) = - warp_request_handler::RequestHandler::new(protocol_id.clone(), warp_sync.clone()); + let (handler, protocol_config) = warp_request_handler::RequestHandler::new( + protocol_id.clone(), + client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + None, + warp_sync.clone(), + ); self.spawn_task(handler.run().boxed()); protocol_config }; @@ -867,6 +877,7 @@ where chain: client.clone(), transaction_pool: Arc::new(EmptyTransactionPool), protocol_id, + fork_id, import_queue, chain_sync: Box::new(chain_sync), metrics_registry: None, diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index ec537a33b72d5..998ec12c1d05b 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -741,6 +741,7 @@ where // Allow both outgoing and incoming requests. let (handler, protocol_config) = BlockRequestHandler::new( &protocol_id, + config.chain_spec.fork_id(), client.clone(), config.network.default_peers_set.in_peers as usize + config.network.default_peers_set.out_peers as usize, @@ -753,6 +754,7 @@ where // Allow both outgoing and incoming requests. let (handler, protocol_config) = StateRequestHandler::new( &protocol_id, + config.chain_spec.fork_id(), client.clone(), config.network.default_peers_set_num_full as usize, ); @@ -763,8 +765,16 @@ where let (warp_sync_provider, warp_sync_protocol_config) = warp_sync .map(|provider| { // Allow both outgoing and incoming requests. - let (handler, protocol_config) = - WarpSyncRequestHandler::new(protocol_id.clone(), provider.clone()); + let (handler, protocol_config) = WarpSyncRequestHandler::new( + protocol_id.clone(), + client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + config.chain_spec.fork_id(), + provider.clone(), + ); spawn_handle.spawn("warp-sync-request-handler", Some("networking"), handler.run()); (Some(provider), Some(protocol_config)) }) @@ -772,8 +782,11 @@ where let light_client_request_protocol_config = { // Allow both outgoing and incoming requests. - let (handler, protocol_config) = - LightClientRequestHandler::new(&protocol_id, client.clone()); + let (handler, protocol_config) = LightClientRequestHandler::new( + &protocol_id, + config.chain_spec.fork_id(), + client.clone(), + ); spawn_handle.spawn("light-client-request-handler", Some("networking"), handler.run()); protocol_config }; @@ -808,6 +821,7 @@ where chain: client.clone(), transaction_pool: transaction_pool_adapter as _, protocol_id, + fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), import_queue: Box::new(import_queue), chain_sync: Box::new(chain_sync), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), From f64cd4fa987473ad1d05f409afe886d4a620782b Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 5 Aug 2022 12:48:05 +0300 Subject: [PATCH 1039/1472] `sync` protocol now can have negotiated fallback name (#11982) --- client/network/src/protocol.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index a06fff2322ce6..c51667017d15c 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -1577,8 +1577,6 @@ where } => { // Set number 0 is hardcoded the default set of peers we sync from. if set_id == HARDCODED_PEERSETS_SYNC { - debug_assert!(negotiated_fallback.is_none()); - // `received_handshake` can be either a `Status` message if received from the // legacy substream ,or a `BlockAnnouncesHandshake` if received from the block // announces substream. From c172d0f683fab3792b90d876fd6ca27056af9fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 5 Aug 2022 19:53:56 +0200 Subject: [PATCH 1040/1472] system_syncState: Always return highest block (#11979) Before `highestBlock` was an optional that was omitted when it was `None`. We recently changed the way the `highestBlock` is determined, this resulted in having this value in 99.99% of the time being `None` when the node is syncing blocks at the tip. Now we always return a block for `highestBlock`. If sync doesn't return us any best seen block, we return our own local best block as `highestBlock`. This should mainly reflect the same behavior to before we changed the way the best seen block is determined. --- client/rpc-api/src/system/helpers.rs | 12 ++++++------ client/rpc/src/system/tests.rs | 7 ++----- client/service/src/lib.rs | 6 ++++-- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/client/rpc-api/src/system/helpers.rs b/client/rpc-api/src/system/helpers.rs index 4561fccc1e81b..7ddb3f813c249 100644 --- a/client/rpc-api/src/system/helpers.rs +++ b/client/rpc-api/src/system/helpers.rs @@ -88,10 +88,10 @@ pub struct SyncState { pub starting_block: Number, /// Height of the current best block of the node. pub current_block: Number, - /// Height of the highest block learned from the network. Missing if no block is known yet. - #[serde(default = "Default::default", skip_serializing_if = "Option::is_none")] - pub highest_block: Option, + /// Height of the highest block in the network. + pub highest_block: Number, } + #[cfg(test)] mod tests { use super::*; @@ -129,7 +129,7 @@ mod tests { ::serde_json::to_string(&SyncState { starting_block: 12u32, current_block: 50u32, - highest_block: Some(128u32), + highest_block: 128u32, }) .unwrap(), r#"{"startingBlock":12,"currentBlock":50,"highestBlock":128}"#, @@ -139,10 +139,10 @@ mod tests { ::serde_json::to_string(&SyncState { starting_block: 12u32, current_block: 50u32, - highest_block: None, + highest_block: 50u32, }) .unwrap(), - r#"{"startingBlock":12,"currentBlock":50}"#, + r#"{"startingBlock":12,"currentBlock":50,"highestBlock":50}"#, ); } } diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index 77acdf8418ccc..facad7a0b347a 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -123,7 +123,7 @@ fn api>>(sync: T) -> RpcModule> { let _ = sender.send(SyncState { starting_block: 1, current_block: 2, - highest_block: Some(3), + highest_block: 3, }); }, }; @@ -297,10 +297,7 @@ async fn system_node_roles() { async fn system_sync_state() { let sync_state: SyncState = api(None).call("system_syncState", EmptyParams::new()).await.unwrap(); - assert_eq!( - sync_state, - SyncState { starting_block: 1, current_block: 2, highest_block: Some(3) } - ); + assert_eq!(sync_state, SyncState { starting_block: 1, current_block: 2, highest_block: 3 }); } #[tokio::test] diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 98bcb17174157..1de45e5527eec 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -264,10 +264,12 @@ async fn build_network_future< sc_rpc::system::Request::SyncState(sender) => { use sc_rpc::system::SyncState; + let best_number = client.info().best_number; + let _ = sender.send(SyncState { starting_block, - current_block: client.info().best_number, - highest_block: network.best_seen_block(), + current_block: best_number, + highest_block: network.best_seen_block().unwrap_or(best_number), }); } } From 8574647f2a3df620ef32eddb050bfe2adb34aeab Mon Sep 17 00:00:00 2001 From: Nikos Kontakis Date: Mon, 8 Aug 2022 11:31:26 +0200 Subject: [PATCH 1041/1472] Rename --pruning and --keep-blocks to be more similar to one another (#11934) * rename prunning and keep-blocks flags * Add aliases in keep-blocks and pruning for backward compatibility * Rename in code variables from and to and --- bin/node/cli/benches/block_production.rs | 4 +- bin/node/cli/benches/transaction_pool.rs | 4 +- bin/node/testing/src/bench.rs | 2 +- client/cli/src/commands/chain_info_cmd.rs | 2 +- client/cli/src/config.rs | 12 +++--- client/cli/src/params/pruning_params.rs | 22 +++++------ client/db/src/lib.rs | 26 ++++++------- client/network/test/src/lib.rs | 8 ++-- client/network/test/src/sync.rs | 2 +- client/service/src/builder.rs | 2 +- client/service/src/config.rs | 4 +- client/service/src/lib.rs | 2 +- client/service/test/src/client/mod.rs | 8 ++-- client/service/test/src/lib.rs | 6 +-- client/state-db/src/lib.rs | 46 +++++++++++------------ test-utils/client/src/lib.rs | 8 ++-- 16 files changed, 79 insertions(+), 79 deletions(-) diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 6d269ccaac271..8420a65f8cb80 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -28,7 +28,7 @@ use sc_consensus::{ }; use sc_service::{ config::{ - DatabaseSource, KeepBlocks, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, + BlocksPruning, DatabaseSource, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, PruningMode, WasmExecutionMethod, WasmtimeInstantiationStrategy, }, BasePath, Configuration, Role, @@ -75,7 +75,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { state_cache_size: 67108864, state_cache_child_ratio: None, state_pruning: Some(PruningMode::ArchiveAll), - keep_blocks: KeepBlocks::All, + blocks_pruning: BlocksPruning::All, chain_spec: spec, wasm_method: WasmExecutionMethod::Compiled { instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index 580a10d6a6678..f031f9dae3d21 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -26,7 +26,7 @@ use node_primitives::AccountId; use sc_client_api::execution_extensions::ExecutionStrategies; use sc_service::{ config::{ - DatabaseSource, KeepBlocks, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, + BlocksPruning, DatabaseSource, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, PruningMode, TransactionPoolOptions, WasmExecutionMethod, }, BasePath, Configuration, Role, @@ -69,7 +69,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { state_cache_size: 67108864, state_cache_child_ratio: None, state_pruning: Some(PruningMode::ArchiveAll), - keep_blocks: KeepBlocks::All, + blocks_pruning: BlocksPruning::All, chain_spec: spec, wasm_method: WasmExecutionMethod::Interpreted, // NOTE: we enforce the use of the native runtime to make the errors more debuggable diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 18e979b95737f..de64910125b86 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -392,7 +392,7 @@ impl BenchDb { state_cache_child_ratio: Some((0, 100)), state_pruning: Some(PruningMode::ArchiveAll), source: database_type.into_settings(dir.into()), - keep_blocks: sc_client_db::KeepBlocks::All, + blocks_pruning: sc_client_db::BlocksPruning::All, }; let task_executor = TaskExecutor::new(); diff --git a/client/cli/src/commands/chain_info_cmd.rs b/client/cli/src/commands/chain_info_cmd.rs index 0e57d1677efbb..c65092290cf2d 100644 --- a/client/cli/src/commands/chain_info_cmd.rs +++ b/client/cli/src/commands/chain_info_cmd.rs @@ -77,7 +77,7 @@ impl ChainInfoCmd { state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), state_pruning: config.state_pruning.clone(), source: config.database.clone(), - keep_blocks: config.keep_blocks.clone(), + blocks_pruning: config.blocks_pruning.clone(), }; let backend = sc_service::new_db_backend::(db_config)?; let info: ChainInfo = backend.blockchain().info().into(); diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 4ebbc8c72c19a..f513008b17adc 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -31,7 +31,7 @@ use sc_service::{ NodeKeyConfig, OffchainWorkerConfig, PrometheusConfig, PruningMode, Role, RpcMethods, TelemetryEndpoints, TransactionPoolOptions, WasmExecutionMethod, }, - ChainSpec, KeepBlocks, TracingReceiver, + BlocksPruning, ChainSpec, TracingReceiver, }; use sc_tracing::logging::LoggerBuilder; use std::{net::SocketAddr, path::PathBuf}; @@ -257,11 +257,11 @@ pub trait CliConfiguration: Sized { /// Get the block pruning mode. /// /// By default this is retrieved from `block_pruning` if it is available. Otherwise its - /// `KeepBlocks::All`. - fn keep_blocks(&self) -> Result { + /// `BlocksPruning::All`. + fn blocks_pruning(&self) -> Result { self.pruning_params() - .map(|x| x.keep_blocks()) - .unwrap_or_else(|| Ok(KeepBlocks::All)) + .map(|x| x.blocks_pruning()) + .unwrap_or_else(|| Ok(BlocksPruning::All)) } /// Get the chain ID (string). @@ -536,7 +536,7 @@ pub trait CliConfiguration: Sized { state_cache_size: self.state_cache_size()?, state_cache_child_ratio: self.state_cache_child_ratio()?, state_pruning: self.state_pruning()?, - keep_blocks: self.keep_blocks()?, + blocks_pruning: self.blocks_pruning()?, wasm_method: self.wasm_method()?, wasm_runtime_overrides: self.wasm_runtime_overrides(), execution_strategies: self.execution_strategies(is_dev, is_validator)?, diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index 9d471224cc59e..34a0982e63d95 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -18,7 +18,7 @@ use crate::error; use clap::Args; -use sc_service::{KeepBlocks, PruningMode}; +use sc_service::{BlocksPruning, PruningMode}; /// Parameters to define the pruning mode #[derive(Debug, Clone, PartialEq, Args)] @@ -28,37 +28,37 @@ pub struct PruningParams { /// Default is to keep only the last 256 blocks, /// otherwise, the state can be kept for all of the blocks (i.e 'archive'), /// or for all of the canonical blocks (i.e 'archive-canonical'). - #[clap(long, value_name = "PRUNING_MODE")] - pub pruning: Option, + #[clap(alias = "pruning", long, value_name = "PRUNING_MODE")] + pub state_pruning: Option, /// Specify the number of finalized blocks to keep in the database. /// /// Default is to keep all blocks. /// /// NOTE: only finalized blocks are subject for removal! - #[clap(long, value_name = "COUNT")] - pub keep_blocks: Option, + #[clap(alias = "keep-blocks", long, value_name = "COUNT")] + pub blocks_pruning: Option, } impl PruningParams { /// Get the pruning value from the parameters pub fn state_pruning(&self) -> error::Result> { - self.pruning + self.state_pruning .as_ref() .map(|s| match s.as_str() { "archive" => Ok(PruningMode::ArchiveAll), bc => bc .parse() .map_err(|_| error::Error::Input("Invalid pruning mode specified".to_string())) - .map(PruningMode::keep_blocks), + .map(PruningMode::blocks_pruning), }) .transpose() } /// Get the block pruning value from the parameters - pub fn keep_blocks(&self) -> error::Result { - Ok(match self.keep_blocks { - Some(n) => KeepBlocks::Some(n), - None => KeepBlocks::All, + pub fn blocks_pruning(&self) -> error::Result { + Ok(match self.blocks_pruning { + Some(n) => BlocksPruning::Some(n), + None => BlocksPruning::All, }) } } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 0ce408a39b004..3214ee8f0d738 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -300,12 +300,12 @@ pub struct DatabaseSettings { /// Block pruning mode. /// /// NOTE: only finalized blocks are subject for removal! - pub keep_blocks: KeepBlocks, + pub blocks_pruning: BlocksPruning, } /// Block pruning settings. #[derive(Debug, Clone, Copy)] -pub enum KeepBlocks { +pub enum BlocksPruning { /// Keep full block history. All, /// Keep N recent finalized blocks. @@ -1012,7 +1012,7 @@ pub struct Backend { shared_cache: SharedCache, import_lock: Arc>, is_archive: bool, - keep_blocks: KeepBlocks, + blocks_pruning: BlocksPruning, io_stats: FrozenForDuration<(kvdb::IoStats, StateUsageInfo)>, state_usage: Arc, genesis_state: RwLock>>>, @@ -1043,21 +1043,21 @@ impl Backend { /// Create new memory-backed client backend for tests. #[cfg(any(test, feature = "test-helpers"))] - pub fn new_test(keep_blocks: u32, canonicalization_delay: u64) -> Self { - Self::new_test_with_tx_storage(keep_blocks, canonicalization_delay) + pub fn new_test(blocks_pruning: u32, canonicalization_delay: u64) -> Self { + Self::new_test_with_tx_storage(blocks_pruning, canonicalization_delay) } /// Create new memory-backed client backend for tests. #[cfg(any(test, feature = "test-helpers"))] - pub fn new_test_with_tx_storage(keep_blocks: u32, canonicalization_delay: u64) -> Self { + pub fn new_test_with_tx_storage(blocks_pruning: u32, canonicalization_delay: u64) -> Self { let db = kvdb_memorydb::create(crate::utils::NUM_COLUMNS); let db = sp_database::as_database(db); let db_setting = DatabaseSettings { state_cache_size: 16777216, state_cache_child_ratio: Some((50, 100)), - state_pruning: Some(PruningMode::keep_blocks(keep_blocks)), + state_pruning: Some(PruningMode::blocks_pruning(blocks_pruning)), source: DatabaseSource::Custom { db, require_create_flag: true }, - keep_blocks: KeepBlocks::Some(keep_blocks), + blocks_pruning: BlocksPruning::Some(blocks_pruning), }; Self::new(db_setting, canonicalization_delay).expect("failed to create test-db") @@ -1124,7 +1124,7 @@ impl Backend { is_archive: is_archive_pruning, io_stats: FrozenForDuration::new(std::time::Duration::from_secs(1)), state_usage: Arc::new(StateUsageStats::new()), - keep_blocks: config.keep_blocks, + blocks_pruning: config.blocks_pruning, genesis_state: RwLock::new(None), }; @@ -1698,9 +1698,9 @@ impl Backend { finalized: NumberFor, displaced: &FinalizationDisplaced>, ) -> ClientResult<()> { - if let KeepBlocks::Some(keep_blocks) = self.keep_blocks { + if let BlocksPruning::Some(blocks_pruning) = self.blocks_pruning { // Always keep the last finalized block - let keep = std::cmp::max(keep_blocks, 1); + let keep = std::cmp::max(blocks_pruning, 1); if finalized >= keep.into() { let number = finalized.saturating_sub(keep.into()); self.prune_block(transaction, BlockId::::number(number))?; @@ -2465,9 +2465,9 @@ pub(crate) mod tests { DatabaseSettings { state_cache_size: 16777216, state_cache_child_ratio: Some((50, 100)), - state_pruning: Some(PruningMode::keep_blocks(1)), + state_pruning: Some(PruningMode::blocks_pruning(1)), source: DatabaseSource::Custom { db: backing, require_create_flag: false }, - keep_blocks: KeepBlocks::All, + blocks_pruning: BlocksPruning::All, }, 0, ) diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 494ff2048f6c4..09b4139c213a6 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -676,7 +676,7 @@ pub struct FullPeerConfig { /// Pruning window size. /// /// NOTE: only finalized blocks are subject for removal! - pub keep_blocks: Option, + pub blocks_pruning: Option, /// Block announce validator. pub block_announce_validator: Option + Send + Sync>>, /// List of notification protocols that the network must support. @@ -742,10 +742,10 @@ where /// Add a full peer. fn add_full_peer_with_config(&mut self, config: FullPeerConfig) { - let mut test_client_builder = match (config.keep_blocks, config.storage_chain) { - (Some(keep_blocks), true) => TestClientBuilder::with_tx_storage(keep_blocks), + let mut test_client_builder = match (config.blocks_pruning, config.storage_chain) { + (Some(blocks_pruning), true) => TestClientBuilder::with_tx_storage(blocks_pruning), (None, true) => TestClientBuilder::with_tx_storage(u32::MAX), - (Some(keep_blocks), false) => TestClientBuilder::with_pruning_window(keep_blocks), + (Some(blocks_pruning), false) => TestClientBuilder::with_pruning_window(blocks_pruning), (None, false) => TestClientBuilder::with_default_backend(), }; if let Some(storage) = config.extra_storage { diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index 84a5c2ca13fa5..c0778767b75af 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -544,7 +544,7 @@ fn syncs_header_only_forks() { sp_tracing::try_init_simple(); let mut net = TestNet::new(0); net.add_full_peer_with_config(Default::default()); - net.add_full_peer_with_config(FullPeerConfig { keep_blocks: Some(3), ..Default::default() }); + net.add_full_peer_with_config(FullPeerConfig { blocks_pruning: Some(3), ..Default::default() }); net.peer(0).push_blocks(2, false); net.peer(1).push_blocks(2, false); diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 998ec12c1d05b..55c0006de33fb 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -207,7 +207,7 @@ where state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), state_pruning: config.state_pruning.clone(), source: config.database.clone(), - keep_blocks: config.keep_blocks, + blocks_pruning: config.blocks_pruning, }; let backend = new_db_backend(db_config)?; diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 0eeb6e05cee16..7860ff2281fe4 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -19,7 +19,7 @@ //! Service configuration. pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStrategy}; -pub use sc_client_db::{Database, DatabaseSource, KeepBlocks, PruningMode}; +pub use sc_client_db::{BlocksPruning, Database, DatabaseSource, PruningMode}; pub use sc_executor::WasmExecutionMethod; #[cfg(feature = "wasmtime")] pub use sc_executor::WasmtimeInstantiationStrategy; @@ -79,7 +79,7 @@ pub struct Configuration { /// Number of blocks to keep in the db. /// /// NOTE: only finalized blocks are subject for removal! - pub keep_blocks: KeepBlocks, + pub blocks_pruning: BlocksPruning, /// Chain configuration. pub chain_spec: Box, /// Wasm execution method. diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 1de45e5527eec..5291d219e8102 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -60,7 +60,7 @@ pub use self::{ error::Error, }; pub use config::{ - BasePath, Configuration, DatabaseSource, KeepBlocks, PruningMode, Role, RpcMethods, TaskType, + BasePath, BlocksPruning, Configuration, DatabaseSource, PruningMode, Role, RpcMethods, TaskType, }; pub use sc_chain_spec::{ ChainSpec, ChainType, Extension as ChainSpecExtension, GenericChainSpec, NoExtension, diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 136efad088fae..f363b621d5bcd 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -23,7 +23,7 @@ use sc_block_builder::BlockBuilderProvider; use sc_client_api::{ in_mem, BlockBackend, BlockchainEvents, FinalityNotifications, StorageProvider, }; -use sc_client_db::{Backend, DatabaseSettings, DatabaseSource, KeepBlocks, PruningMode}; +use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, DatabaseSource, PruningMode}; use sc_consensus::{ BlockCheckParams, BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, }; @@ -1200,7 +1200,7 @@ fn doesnt_import_blocks_that_revert_finality() { state_cache_size: 1 << 20, state_cache_child_ratio: None, state_pruning: Some(PruningMode::ArchiveAll), - keep_blocks: KeepBlocks::All, + blocks_pruning: BlocksPruning::All, source: DatabaseSource::RocksDb { path: tmp.path().into(), cache_size: 1024 }, }, u64::MAX, @@ -1426,8 +1426,8 @@ fn returns_status_for_pruned_blocks() { DatabaseSettings { state_cache_size: 1 << 20, state_cache_child_ratio: None, - state_pruning: Some(PruningMode::keep_blocks(1)), - keep_blocks: KeepBlocks::All, + state_pruning: Some(PruningMode::blocks_pruning(1)), + blocks_pruning: BlocksPruning::All, source: DatabaseSource::RocksDb { path: tmp.path().into(), cache_size: 1024 }, }, u64::MAX, diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 749c83c6eeac7..2d63362daffba 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -29,8 +29,8 @@ use sc_network::{ use sc_service::{ client::Client, config::{BasePath, DatabaseSource, KeystoreConfig}, - ChainSpecExtension, Configuration, Error, GenericChainSpec, KeepBlocks, Role, RuntimeGenesis, - SpawnTaskHandle, TaskManager, + BlocksPruning, ChainSpecExtension, Configuration, Error, GenericChainSpec, Role, + RuntimeGenesis, SpawnTaskHandle, TaskManager, }; use sc_transaction_pool_api::TransactionPool; use sp_api::BlockId; @@ -234,7 +234,7 @@ fn node_config< state_cache_size: 16777216, state_cache_child_ratio: None, state_pruning: Default::default(), - keep_blocks: KeepBlocks::All, + blocks_pruning: BlocksPruning::All, chain_spec: Box::new((*spec).clone()), wasm_method: sc_service::config::WasmExecutionMethod::Interpreted, wasm_runtime_overrides: Default::default(), diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index d5cca9a342187..1c7140777e16e 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -227,7 +227,7 @@ pub enum PruningMode { impl PruningMode { /// Create a mode that keeps given number of blocks. - pub fn keep_blocks(n: u32) -> PruningMode { + pub fn blocks_pruning(n: u32) -> PruningMode { PruningMode::Constrained(Constraints { max_blocks: Some(n), max_mem: None }) } @@ -835,34 +835,34 @@ mod tests { #[test] fn pruning_mode_compatibility() { for (created, reopened, expected) in [ - (None, None, Ok(PruningMode::keep_blocks(256))), - (None, Some(PruningMode::keep_blocks(256)), Ok(PruningMode::keep_blocks(256))), - (None, Some(PruningMode::keep_blocks(128)), Ok(PruningMode::keep_blocks(128))), - (None, Some(PruningMode::keep_blocks(512)), Ok(PruningMode::keep_blocks(512))), + (None, None, Ok(PruningMode::blocks_pruning(256))), + (None, Some(PruningMode::blocks_pruning(256)), Ok(PruningMode::blocks_pruning(256))), + (None, Some(PruningMode::blocks_pruning(128)), Ok(PruningMode::blocks_pruning(128))), + (None, Some(PruningMode::blocks_pruning(512)), Ok(PruningMode::blocks_pruning(512))), (None, Some(PruningMode::ArchiveAll), Err(())), (None, Some(PruningMode::ArchiveCanonical), Err(())), - (Some(PruningMode::keep_blocks(256)), None, Ok(PruningMode::keep_blocks(256))), + (Some(PruningMode::blocks_pruning(256)), None, Ok(PruningMode::blocks_pruning(256))), ( - Some(PruningMode::keep_blocks(256)), - Some(PruningMode::keep_blocks(256)), - Ok(PruningMode::keep_blocks(256)), + Some(PruningMode::blocks_pruning(256)), + Some(PruningMode::blocks_pruning(256)), + Ok(PruningMode::blocks_pruning(256)), ), ( - Some(PruningMode::keep_blocks(256)), - Some(PruningMode::keep_blocks(128)), - Ok(PruningMode::keep_blocks(128)), + Some(PruningMode::blocks_pruning(256)), + Some(PruningMode::blocks_pruning(128)), + Ok(PruningMode::blocks_pruning(128)), ), ( - Some(PruningMode::keep_blocks(256)), - Some(PruningMode::keep_blocks(512)), - Ok(PruningMode::keep_blocks(512)), + Some(PruningMode::blocks_pruning(256)), + Some(PruningMode::blocks_pruning(512)), + Ok(PruningMode::blocks_pruning(512)), ), - (Some(PruningMode::keep_blocks(256)), Some(PruningMode::ArchiveAll), Err(())), - (Some(PruningMode::keep_blocks(256)), Some(PruningMode::ArchiveCanonical), Err(())), + (Some(PruningMode::blocks_pruning(256)), Some(PruningMode::ArchiveAll), Err(())), + (Some(PruningMode::blocks_pruning(256)), Some(PruningMode::ArchiveCanonical), Err(())), (Some(PruningMode::ArchiveAll), None, Ok(PruningMode::ArchiveAll)), - (Some(PruningMode::ArchiveAll), Some(PruningMode::keep_blocks(256)), Err(())), - (Some(PruningMode::ArchiveAll), Some(PruningMode::keep_blocks(128)), Err(())), - (Some(PruningMode::ArchiveAll), Some(PruningMode::keep_blocks(512)), Err(())), + (Some(PruningMode::ArchiveAll), Some(PruningMode::blocks_pruning(256)), Err(())), + (Some(PruningMode::ArchiveAll), Some(PruningMode::blocks_pruning(128)), Err(())), + (Some(PruningMode::ArchiveAll), Some(PruningMode::blocks_pruning(512)), Err(())), ( Some(PruningMode::ArchiveAll), Some(PruningMode::ArchiveAll), @@ -870,9 +870,9 @@ mod tests { ), (Some(PruningMode::ArchiveAll), Some(PruningMode::ArchiveCanonical), Err(())), (Some(PruningMode::ArchiveCanonical), None, Ok(PruningMode::ArchiveCanonical)), - (Some(PruningMode::ArchiveCanonical), Some(PruningMode::keep_blocks(256)), Err(())), - (Some(PruningMode::ArchiveCanonical), Some(PruningMode::keep_blocks(128)), Err(())), - (Some(PruningMode::ArchiveCanonical), Some(PruningMode::keep_blocks(512)), Err(())), + (Some(PruningMode::ArchiveCanonical), Some(PruningMode::blocks_pruning(256)), Err(())), + (Some(PruningMode::ArchiveCanonical), Some(PruningMode::blocks_pruning(128)), Err(())), + (Some(PruningMode::ArchiveCanonical), Some(PruningMode::blocks_pruning(512)), Err(())), (Some(PruningMode::ArchiveCanonical), Some(PruningMode::ArchiveAll), Err(())), ( Some(PruningMode::ArchiveCanonical), diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 148f34246044d..3115be58425e6 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -95,14 +95,14 @@ impl } /// Create new `TestClientBuilder` with default backend and pruning window size - pub fn with_pruning_window(keep_blocks: u32) -> Self { - let backend = Arc::new(Backend::new_test(keep_blocks, 0)); + pub fn with_pruning_window(blocks_pruning: u32) -> Self { + let backend = Arc::new(Backend::new_test(blocks_pruning, 0)); Self::with_backend(backend) } /// Create new `TestClientBuilder` with default backend and storage chain mode - pub fn with_tx_storage(keep_blocks: u32) -> Self { - let backend = Arc::new(Backend::new_test_with_tx_storage(keep_blocks, 0)); + pub fn with_tx_storage(blocks_pruning: u32) -> Self { + let backend = Arc::new(Backend::new_test_with_tx_storage(blocks_pruning, 0)); Self::with_backend(backend) } } From 4ad36db74762629c65d5c1af1084f7e7683bc7a8 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 8 Aug 2022 17:46:57 +0800 Subject: [PATCH 1042/1472] Fix 16bit func_id (#11985) --- frame/contracts/src/chain_extension.rs | 4 ++-- frame/contracts/src/tests.rs | 29 +++++++++++++------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 23242a2a542c1..57101668f794d 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -38,7 +38,7 @@ //! //! However, only extensions implementing [`RegisteredChainExtension`] can be put into a tuple. //! This is because the [`RegisteredChainExtension::ID`] is used to decide which of those extensions -//! should should be used when the contract calls a chain extensions. Extensions which are generally +//! should be used when the contract calls a chain extensions. Extensions which are generally //! useful should claim their `ID` with [the registry](https://github.com/paritytech/chainextension-registry) //! so that no collisions with other vendors will occur. //! @@ -215,7 +215,7 @@ where /// It returns the two least significant bytes of the `id` passed by a contract as the other /// two bytes represent the chain extension itself (the code which is calling this function). pub fn func_id(&self) -> u16 { - (self.inner.id & 0x00FF) as u16 + (self.inner.id & 0x0000FFFF) as u16 } /// The chain extension id within the `id` passed by a contract. diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 0febfec929b6e..30417d8544489 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -158,14 +158,14 @@ impl ChainExtension for TestExtension { let func_id = env.func_id(); let id = env.ext_id() as u32 | func_id as u32; match func_id { - 0 => { + 0x8000 => { let mut env = env.buf_in_buf_out(); let input = env.read(8)?; env.write(&input, false, None)?; TEST_EXTENSION.with(|e| e.borrow_mut().last_seen_buffer = input); Ok(RetVal::Converging(id)) }, - 1 => { + 0x8001 => { let env = env.only_in(); TEST_EXTENSION.with(|e| { e.borrow_mut().last_seen_inputs = @@ -173,13 +173,13 @@ impl ChainExtension for TestExtension { }); Ok(RetVal::Converging(id)) }, - 2 => { + 0x8002 => { let mut env = env.buf_in_buf_out(); let weight = env.read(5)?[4].into(); env.charge_weight(weight)?; Ok(RetVal::Converging(id)) }, - 3 => Ok(RetVal::Diverging { flags: ReturnFlags::REVERT, data: vec![42, 99] }), + 0x8003 => Ok(RetVal::Diverging { flags: ReturnFlags::REVERT, data: vec![42, 99] }), _ => { panic!("Passed unknown id to test chain extension: {}", func_id); }, @@ -1646,21 +1646,22 @@ fn chain_extension_works() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - // 0 = read input buffer and pass it through as output - let input: Vec = ExtensionInput { extension_id: 0, func_id: 0, extra: &[99] }.into(); + // 0x8000 = read input buffer and pass it through as output + let input: Vec = + ExtensionInput { extension_id: 0, func_id: 0x8000, extra: &[99] }.into(); let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false); assert_eq!(TestExtension::last_seen_buffer(), input); assert_eq!(result.result.unwrap().data, Bytes(input)); - // 1 = treat inputs as integer primitives and store the supplied integers + // 0x8001 = treat inputs as integer primitives and store the supplied integers Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into(), + ExtensionInput { extension_id: 0, func_id: 0x8001, extra: &[] }.into(), false, ) .result @@ -1668,14 +1669,14 @@ fn chain_extension_works() { // those values passed in the fixture assert_eq!(TestExtension::last_seen_inputs(), (4, 4, 16, 12)); - // 2 = charge some extra weight (amount supplied in the fifth byte) + // 0x8002 = charge some extra weight (amount supplied in the fifth byte) let result = Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 2, extra: &[0] }.into(), + ExtensionInput { extension_id: 0, func_id: 0x8002, extra: &[0] }.into(), false, ); assert_ok!(result.result); @@ -1686,7 +1687,7 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 2, extra: &[42] }.into(), + ExtensionInput { extension_id: 0, func_id: 0x8002, extra: &[42] }.into(), false, ); assert_ok!(result.result); @@ -1697,20 +1698,20 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 2, extra: &[95] }.into(), + ExtensionInput { extension_id: 0, func_id: 0x8002, extra: &[95] }.into(), false, ); assert_ok!(result.result); assert_eq!(result.gas_consumed, gas_consumed + 95); - // 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer + // 0x8003 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer let result = Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into(), + ExtensionInput { extension_id: 0, func_id: 0x8003, extra: &[] }.into(), false, ) .result From ef890f5598e0d3fd1b6a5fcc8c3322f7570089d1 Mon Sep 17 00:00:00 2001 From: yjh Date: Mon, 8 Aug 2022 17:49:00 +0800 Subject: [PATCH 1043/1472] chore: fix typos and sort trait impls (#11989) --- frame/contracts/src/wasm/code_cache.rs | 6 +++--- frame/contracts/src/wasm/env_def/mod.rs | 6 +++--- frame/contracts/src/wasm/prepare.rs | 2 +- frame/contracts/src/wasm/runtime.rs | 18 +++++++++--------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 10de436bfb155..61826c7c323aa 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -215,7 +215,7 @@ impl Token for CodeToken { use self::CodeToken::*; // In case of `Load` we already covered the general costs of // calling the storage but still need to account for the actual size of the - // contract code. This is why we substract `T::*::(0)`. We need to do this at this + // contract code. This is why we subtract `T::*::(0)`. We need to do this at this // point because when charging the general weight for calling the contract we not know the // size of the contract. match *self { @@ -223,8 +223,8 @@ impl Token for CodeToken { Load(len) => { let computation = T::WeightInfo::call_with_code_per_byte(len) .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)); - let bandwith = T::ContractAccessWeight::get().saturating_mul(len.into()); - computation.max(bandwith) + let bandwidth = T::ContractAccessWeight::get().saturating_mul(len.into()); + computation.max(bandwidth) }, } } diff --git a/frame/contracts/src/wasm/env_def/mod.rs b/frame/contracts/src/wasm/env_def/mod.rs index b4c5ffe81e7c1..c904445f8aea8 100644 --- a/frame/contracts/src/wasm/env_def/mod.rs +++ b/frame/contracts/src/wasm/env_def/mod.rs @@ -31,8 +31,8 @@ pub trait ConvertibleToWasm: Sized { fn from_typed_value(_: Value) -> Option; } impl ConvertibleToWasm for i32 { - type NativeType = i32; const VALUE_TYPE: ValueType = ValueType::I32; + type NativeType = i32; fn to_typed_value(self) -> Value { Value::I32(self) } @@ -41,8 +41,8 @@ impl ConvertibleToWasm for i32 { } } impl ConvertibleToWasm for u32 { - type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; + type NativeType = u32; fn to_typed_value(self) -> Value { Value::I32(self as i32) } @@ -54,8 +54,8 @@ impl ConvertibleToWasm for u32 { } } impl ConvertibleToWasm for u64 { - type NativeType = u64; const VALUE_TYPE: ValueType = ValueType::I64; + type NativeType = u64; fn to_typed_value(self) -> Value { Value::I64(self as i64) } diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index f6fff20de6b1a..aec5dc2db611d 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -540,7 +540,7 @@ mod tests { [seal0] nop(_ctx, _unused: u64) => { unreachable!(); }, - // new version of nop with other data type for argumebt + // new version of nop with other data type for argument [seal1] nop(_ctx, _unused: i32) => { unreachable!(); }, ); } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 3d5e62f2c1333..562b29fbaeb1b 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -1209,7 +1209,7 @@ define_env!(Env, , // // # Parameters // - // - flags: See [`CallFlags`] for a documenation of the supported flags. + // - flags: See [`CallFlags`] for a documentation of the supported flags. // - callee_ptr: a pointer to the address of the callee contract. // Should be decodable as an `T::AccountId`. Traps otherwise. // - gas: how much gas to devote to the execution. @@ -1753,7 +1753,7 @@ define_env!(Env, , // # Note // // The state rent functionality was removed. This is stub only exists for - // backwards compatiblity + // backwards compatibility [seal0] seal_restore_to( ctx, _dest_ptr: u32, @@ -1774,7 +1774,7 @@ define_env!(Env, , // # Note // // The state rent functionality was removed. This is stub only exists for - // backwards compatiblity + // backwards compatibility [seal1] seal_restore_to( ctx, _dest_ptr: u32, @@ -1857,7 +1857,7 @@ define_env!(Env, , // # Note // // The state rent functionality was removed. This is stub only exists for - // backwards compatiblity. + // backwards compatibility. [seal0] seal_set_rent_allowance(ctx, _value_ptr: u32, _value_len: u32) => { ctx.charge_gas(RuntimeCosts::DebugMessage)?; Ok(()) @@ -1868,7 +1868,7 @@ define_env!(Env, , // # Note // // The state rent functionality was removed. This is stub only exists for - // backwards compatiblity. + // backwards compatibility. [seal1] seal_set_rent_allowance(ctx, _value_ptr: u32) => { ctx.charge_gas(RuntimeCosts::DebugMessage)?; Ok(()) @@ -1879,7 +1879,7 @@ define_env!(Env, , // # Note // // The state rent functionality was removed. This is stub only exists for - // backwards compatiblity. + // backwards compatibility. [seal0] seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => { ctx.charge_gas(RuntimeCosts::Balance)?; let rent_allowance = >::max_value().encode(); @@ -2085,15 +2085,15 @@ define_env!(Env, , // // # Return Value // - // Returns `ReturnCode::Success` when the dispatchable was succesfully executed and - // returned `Ok`. When the dispatchable was exeuted but returned an error + // Returns `ReturnCode::Success` when the dispatchable was successfully executed and + // returned `Ok`. When the dispatchable was executed but returned an error // `ReturnCode::CallRuntimeReturnedError` is returned. The full error is not // provided because it is not guaranteed to be stable. // // # Comparison with `ChainExtension` // // Just as a chain extension this API allows the runtime to extend the functionality - // of contracts. While making use of this function is generelly easier it cannot be + // of contracts. While making use of this function is generally easier it cannot be // used in call cases. Consider writing a chain extension if you need to do perform // one of the following tasks: // From 74a6370e805ebaf88b7939e496818531f762cadf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 8 Aug 2022 15:32:00 +0100 Subject: [PATCH 1044/1472] contracts: Apply depth limit when decoding (#11991) --- frame/contracts/src/wasm/runtime.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 562b29fbaeb1b..f21dc7c76e44c 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -26,7 +26,7 @@ use crate::{ }; use bitflags::bitflags; -use codec::{Decode, DecodeAll, Encode, MaxEncodedLen}; +use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight}; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use sp_core::{crypto::UncheckedFrom, Bytes}; @@ -36,6 +36,9 @@ use sp_sandbox::SandboxMemory; use sp_std::prelude::*; use wasm_instrument::parity_wasm::elements::ValueType; +/// The maximum nesting depth a contract can use when encoding types. +const MAX_DECODE_NESTING: u32 = 256; + /// Type of a storage key. #[allow(dead_code)] enum KeyType { @@ -575,7 +578,7 @@ where ptr: u32, ) -> Result { let buf = self.read_sandbox_memory(ptr, D::max_encoded_len() as u32)?; - let decoded = D::decode_all(&mut &buf[..]) + let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut &buf[..]) .map_err(|_| DispatchError::from(Error::::DecodingFailed))?; Ok(decoded) } @@ -597,7 +600,7 @@ where len: u32, ) -> Result { let buf = self.read_sandbox_memory(ptr, len)?; - let decoded = D::decode_all(&mut &buf[..]) + let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut &buf[..]) .map_err(|_| DispatchError::from(Error::::DecodingFailed))?; Ok(decoded) } From 8e600ee0515122667cd091d632104708d343ca34 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 9 Aug 2022 20:04:28 +0900 Subject: [PATCH 1045/1472] Restore `wasmtime`'s default stack size limit to 1MB (#11993) * Restore `wasmtime`'s default stack size limit to 1MB * Add extra comments * Enforce different maximum call depth in release mode * Split the call depth limit in two --- client/executor/wasmtime/src/runtime.rs | 20 ++++--- client/executor/wasmtime/src/tests.rs | 79 +++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 7 deletions(-) diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 2feb9d0eea502..871de4e2300d2 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -324,13 +324,19 @@ fn common_config(semantics: &Semantics) -> std::result::Result native_stack_max, + + // In `wasmtime` 0.35 the default stack size limit was changed from 1MB to 512KB. + // + // This broke at least one parachain which depended on the original 1MB limit, + // so here we restore it to what it was originally. + None => 1024 * 1024, + }; + + config + .max_wasm_stack(native_stack_max as usize) + .map_err(|e| WasmError::Other(format!("cannot set max wasm stack: {:#}", e)))?; config.parallel_compilation(semantics.parallel_compilation); diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index e0fd9fbce0c57..1ca5dde4c2b93 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -174,6 +174,85 @@ impl RuntimeBuilder { } } +fn deep_call_stack_wat(depth: usize) -> String { + format!( + r#" + (module + (memory $0 32) + (export "memory" (memory $0)) + (global (export "__heap_base") i32 (i32.const 0)) + (func (export "overflow") call 0) + + (func $overflow (param $0 i32) + (block $label$1 + (br_if $label$1 + (i32.ge_u + (local.get $0) + (i32.const {depth}) + ) + ) + (call $overflow + (i32.add + (local.get $0) + (i32.const 1) + ) + ) + ) + ) + + (func (export "main") + (param i32 i32) (result i64) + (call $overflow (i32.const 0)) + (i64.const 0) + ) + ) + "# + ) +} + +// These two tests ensure that the `wasmtime`'s stack size limit and the amount of +// stack space used by a single stack frame doesn't suddenly change without us noticing. +// +// If they do (e.g. because we've pulled in a new version of `wasmtime`) we want to know +// that it did, regardless of how small the change was. +// +// If these tests starting failing it doesn't necessarily mean that something is broken; +// what it means is that one (or multiple) of the following has to be done: +// a) the tests may need to be updated for the new call depth, +// b) the stack limit may need to be changed to maintain backwards compatibility, +// c) the root cause of the new call depth limit determined, and potentially fixed, +// d) the new call depth limit may need to be validated to ensure it doesn't prevent any +// existing chain from syncing (if it was effectively decreased) + +// We need two limits here since depending on whether the code is compiled in debug +// or in release mode the maximum call depth is slightly different. +const CALL_DEPTH_LOWER_LIMIT: usize = 65478; +const CALL_DEPTH_UPPER_LIMIT: usize = 65514; + +test_wasm_execution!(test_consume_under_1mb_of_stack_does_not_trap); +fn test_consume_under_1mb_of_stack_does_not_trap(instantiation_strategy: InstantiationStrategy) { + let wat = deep_call_stack_wat(CALL_DEPTH_LOWER_LIMIT); + let mut builder = RuntimeBuilder::new(instantiation_strategy).use_wat(wat); + let runtime = builder.build(); + let mut instance = runtime.new_instance().expect("failed to instantiate a runtime"); + instance.call_export("main", &[]).unwrap(); +} + +test_wasm_execution!(test_consume_over_1mb_of_stack_does_trap); +fn test_consume_over_1mb_of_stack_does_trap(instantiation_strategy: InstantiationStrategy) { + let wat = deep_call_stack_wat(CALL_DEPTH_UPPER_LIMIT + 1); + let mut builder = RuntimeBuilder::new(instantiation_strategy).use_wat(wat); + let runtime = builder.build(); + let mut instance = runtime.new_instance().expect("failed to instantiate a runtime"); + match instance.call_export("main", &[]).unwrap_err() { + Error::AbortedDueToTrap(error) => { + let expected = "wasm trap: call stack exhausted"; + assert_eq!(error.message, expected); + }, + error => panic!("unexpected error: {:?}", error), + } +} + test_wasm_execution!(test_nan_canonicalization); fn test_nan_canonicalization(instantiation_strategy: InstantiationStrategy) { let mut builder = RuntimeBuilder::new(instantiation_strategy).canonicalize_nans(true); From fece0657f20e15df94be5833b164dfacd44823eb Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Tue, 9 Aug 2022 21:28:32 +0300 Subject: [PATCH 1046/1472] Network sync refactoring (part 6) (#11940) * Extract `NetworkKVProvider` trait in `sc-authority-discovery` and remove unnecessary dependency * Extract `NetworkSyncForkRequest` trait in `sc-finality-grandpa` * Relax requirements on `SyncOracle` trait, remove extra native methods from `NetworkService` that are already provided by trait impls * Move `NetworkSigner` trait from `sc-authority-discovery` into `sc-network-common` and de-duplicate methods on `NetworkService` * Move `NetworkKVProvider` trait from `sc-authority-discovery` into `sc-network-common` and de-duplicate methods on `NetworkService` * Minimize `sc-authority-discovery` dependency on `sc-network` * Move `NetworkSyncForkRequest` trait from `sc-finality-grandpa` to `sc-network-common` and de-duplicate methods in `NetworkService` * Extract `NetworkStatusProvider` trait and de-duplicate methods on `NetworkService` * Extract `NetworkPeers` trait and de-duplicate methods on `NetworkService` * Extract `NetworkEventStream` trait and de-duplicate methods on `NetworkService` * Move more methods from `NetworkService` into `NetworkPeers` trait * Move `NetworkStateInfo` trait into `sc-network-common` * Extract `NetworkNotification` trait and de-duplicate methods on `NetworkService` * Extract `NetworkRequest` trait and de-duplicate methods on `NetworkService` * Remove `NetworkService::local_peer_id()`, it is already provided by `NetworkStateInfo` impl * Extract `NetworkTransaction` trait and de-duplicate methods on `NetworkService` * Extract `NetworkBlock` trait and de-duplicate methods on `NetworkService` * Remove dependencies on `NetworkService` from most of the methods of `sc-service` * Address simple review comments --- Cargo.lock | 11 +- bin/node/cli/Cargo.toml | 1 + bin/node/cli/src/service.rs | 3 +- client/authority-discovery/Cargo.toml | 2 +- client/authority-discovery/src/lib.rs | 3 +- client/authority-discovery/src/service.rs | 2 +- client/authority-discovery/src/tests.rs | 4 +- client/authority-discovery/src/worker.rs | 76 +- .../src/worker/addr_cache.rs | 7 +- .../src/worker/schema/tests.rs | 5 +- .../authority-discovery/src/worker/tests.rs | 63 +- client/consensus/pow/src/lib.rs | 2 +- client/consensus/slots/src/lib.rs | 2 +- .../src/communication/gossip.rs | 3 +- .../finality-grandpa/src/communication/mod.rs | 45 +- .../src/communication/tests.rs | 143 +++- client/informant/Cargo.toml | 2 +- client/informant/src/display.rs | 8 +- client/informant/src/lib.rs | 7 +- client/network-gossip/Cargo.toml | 1 + client/network-gossip/src/bridge.rs | 138 ++- client/network-gossip/src/lib.rs | 79 +- client/network-gossip/src/state_machine.rs | 126 ++- client/network-gossip/src/validator.rs | 3 +- client/network/common/Cargo.toml | 3 + client/network/common/src/lib.rs | 2 + client/network/common/src/protocol.rs | 19 + .../{ => common}/src/protocol/event.rs | 4 +- .../network/common/src/request_responses.rs | 39 +- client/network/common/src/service.rs | 660 +++++++++++++++ .../{ => common}/src/service/signature.rs | 5 +- client/network/src/behaviour.rs | 12 +- client/network/src/lib.rs | 58 +- client/network/src/protocol.rs | 3 +- client/network/src/request_responses.rs | 41 +- client/network/src/service.rs | 794 +++++++----------- client/network/src/service/out_events.rs | 3 +- client/network/src/service/tests.rs | 59 +- client/network/src/transactions.rs | 10 +- client/network/test/src/lib.rs | 16 +- client/offchain/Cargo.toml | 1 + client/offchain/src/api.rs | 79 +- client/offchain/src/lib.rs | 104 ++- client/service/src/builder.rs | 58 +- client/service/src/lib.rs | 2 + client/service/src/metrics.rs | 8 +- client/service/test/Cargo.toml | 1 + client/service/test/src/lib.rs | 9 +- primitives/consensus/common/src/lib.rs | 18 +- 49 files changed, 1802 insertions(+), 942 deletions(-) create mode 100644 client/network/common/src/protocol.rs rename client/network/{ => common}/src/protocol/event.rs (96%) create mode 100644 client/network/common/src/service.rs rename client/network/{ => common}/src/service/signature.rs (96%) diff --git a/Cargo.lock b/Cargo.lock index 703eeffce54a1..38063e8060835 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4686,6 +4686,7 @@ dependencies = [ "sc-finality-grandpa", "sc-keystore", "sc-network", + "sc-network-common", "sc-rpc", "sc-service", "sc-service-test", @@ -7702,7 +7703,6 @@ dependencies = [ name = "sc-authority-discovery" version = "0.10.0-dev" dependencies = [ - "async-trait", "futures", "futures-timer", "ip_network", @@ -7715,6 +7715,7 @@ dependencies = [ "rand 0.7.3", "sc-client-api", "sc-network", + "sc-network-common", "sp-api", "sp-authority-discovery", "sp-blockchain", @@ -8316,7 +8317,7 @@ dependencies = [ "log", "parity-util-mem", "sc-client-api", - "sc-network", + "sc-network-common", "sc-transaction-pool-api", "sp-blockchain", "sp-runtime", @@ -8398,7 +8399,9 @@ dependencies = [ name = "sc-network-common" version = "0.10.0-dev" dependencies = [ + "async-trait", "bitflags", + "bytes", "futures", "libp2p", "parity-scale-codec", @@ -8409,6 +8412,7 @@ dependencies = [ "sp-consensus", "sp-finality-grandpa", "sp-runtime", + "thiserror", ] [[package]] @@ -8424,6 +8428,7 @@ dependencies = [ "lru", "quickcheck", "sc-network", + "sc-network-common", "sp-runtime", "substrate-prometheus-endpoint", "substrate-test-runtime-client", @@ -8533,6 +8538,7 @@ dependencies = [ "sc-client-api", "sc-client-db", "sc-network", + "sc-network-common", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", @@ -8741,6 +8747,7 @@ dependencies = [ "sc-consensus", "sc-executor", "sc-network", + "sc-network-common", "sc-service", "sc-transaction-pool-api", "sp-api", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index fe7c5332e2b45..89ca3ebb45576 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -66,6 +66,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } sc-network = { version = "0.10.0-dev", path = "../../../client/network" } +sc-network-common = { version = "0.10.0-dev", path = "../../../client/network/common" } sc-consensus-slots = { version = "0.10.0-dev", path = "../../../client/consensus/slots" } sc-consensus-babe = { version = "0.10.0-dev", path = "../../../client/consensus/babe" } sc-consensus-uncles = { version = "0.10.0-dev", path = "../../../client/consensus/uncles" } diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index e0644f462cf20..b20a3ac59a96a 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -29,7 +29,8 @@ use node_primitives::Block; use sc_client_api::{BlockBackend, ExecutorProvider}; use sc_consensus_babe::{self, SlotProportion}; use sc_executor::NativeElseWasmExecutor; -use sc_network::{Event, NetworkService}; +use sc_network::NetworkService; +use sc_network_common::{protocol::event::Event, service::NetworkEventStream}; use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sp_api::ProvideRuntimeApi; diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 012e6096aab80..544df4c8d4812 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -17,7 +17,6 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.10" [dependencies] -async-trait = "0.1" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } futures = "0.3.21" futures-timer = "3.0.1" @@ -29,6 +28,7 @@ rand = "0.7.2" thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-client-api = { version = "4.0.0-dev", path = "../api" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-network = { version = "0.10.0-dev", path = "../network" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-authority-discovery = { version = "4.0.0-dev", path = "../../primitives/authority-discovery" } diff --git a/client/authority-discovery/src/lib.rs b/client/authority-discovery/src/lib.rs index 8522da9984a6f..f0ef374551617 100644 --- a/client/authority-discovery/src/lib.rs +++ b/client/authority-discovery/src/lib.rs @@ -39,8 +39,9 @@ use futures::{ Stream, }; +use libp2p::{Multiaddr, PeerId}; use sc_client_api::blockchain::HeaderBackend; -use sc_network::{DhtEvent, Multiaddr, PeerId}; +use sc_network_common::protocol::event::DhtEvent; use sp_api::ProvideRuntimeApi; use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId}; use sp_runtime::traits::Block as BlockT; diff --git a/client/authority-discovery/src/service.rs b/client/authority-discovery/src/service.rs index c240e5d0c2287..df09b6ea43216 100644 --- a/client/authority-discovery/src/service.rs +++ b/client/authority-discovery/src/service.rs @@ -25,7 +25,7 @@ use futures::{ SinkExt, }; -use sc_network::{Multiaddr, PeerId}; +use libp2p::{Multiaddr, PeerId}; use sp_authority_discovery::AuthorityId; /// Service to interact with the [`crate::Worker`]. diff --git a/client/authority-discovery/src/tests.rs b/client/authority-discovery/src/tests.rs index e9f94b6a186db..334b2638ca58c 100644 --- a/client/authority-discovery/src/tests.rs +++ b/client/authority-discovery/src/tests.rs @@ -87,12 +87,12 @@ fn get_addresses_and_authority_id() { fn cryptos_are_compatible() { use sp_core::crypto::Pair; - let libp2p_secret = sc_network::Keypair::generate_ed25519(); + let libp2p_secret = libp2p::identity::Keypair::generate_ed25519(); let libp2p_public = libp2p_secret.public(); let sp_core_secret = { let libp2p_ed_secret = match libp2p_secret.clone() { - sc_network::Keypair::Ed25519(x) => x, + libp2p::identity::Keypair::Ed25519(x) => x, _ => panic!("generate_ed25519 should have generated an Ed25519 key ¯\\_(ツ)_/¯"), }; sp_core::ed25519::Pair::from_seed_slice(&libp2p_ed_secret.secret().as_ref()).unwrap() diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index 87cc72ba7a69c..f13a1cf33581b 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -32,19 +32,22 @@ use std::{ use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt}; use addr_cache::AddrCache; -use async_trait::async_trait; use codec::Decode; use ip_network::IpNetwork; use libp2p::{ core::multiaddr, multihash::{Multihash, MultihashDigest}, + Multiaddr, PeerId, }; use log::{debug, error, log_enabled}; use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64}; use prost::Message; use rand::{seq::SliceRandom, thread_rng}; use sc_client_api::blockchain::HeaderBackend; -use sc_network::{DhtEvent, ExHashT, Multiaddr, NetworkStateInfo, PeerId}; +use sc_network_common::{ + protocol::event::DhtEvent, + service::{KademliaKey, NetworkDHTProvider, NetworkSigner, NetworkStateInfo, Signature}, +}; use sp_api::ProvideRuntimeApi; use sp_authority_discovery::{ AuthorityDiscoveryApi, AuthorityId, AuthorityPair, AuthoritySignature, @@ -136,7 +139,7 @@ pub struct Worker { /// Queue of throttled lookups pending to be passed to the network. pending_lookups: Vec, /// Set of in-flight lookups. - in_flight_lookups: HashMap, + in_flight_lookups: HashMap, addr_cache: addr_cache::AddrCache, @@ -464,10 +467,7 @@ where } } - fn handle_dht_value_found_event( - &mut self, - values: Vec<(sc_network::KademliaKey, Vec)>, - ) -> Result<()> { + fn handle_dht_value_found_event(&mut self, values: Vec<(KademliaKey, Vec)>) -> Result<()> { // Ensure `values` is not empty and all its keys equal. let remote_key = single(values.iter().map(|(key, _)| key.clone())) .map_err(|_| Error::ReceivingDhtValueFoundEventWithDifferentKeys)? @@ -523,11 +523,11 @@ where // properly signed by the owner of the PeerId if let Some(peer_signature) = peer_signature { - let public_key = - sc_network::PublicKey::from_protobuf_encoding(&peer_signature.public_key) - .map_err(Error::ParsingLibp2pIdentity)?; - let signature = - sc_network::Signature { public_key, bytes: peer_signature.signature }; + let public_key = libp2p::identity::PublicKey::from_protobuf_encoding( + &peer_signature.public_key, + ) + .map_err(Error::ParsingLibp2pIdentity)?; + let signature = Signature { public_key, bytes: peer_signature.signature }; if !signature.verify(record, &remote_peer_id) { return Err(Error::VerifyingDhtPayload) @@ -590,55 +590,15 @@ where } } -pub trait NetworkSigner { - /// Sign a message in the name of `self.local_peer_id()` - fn sign_with_local_identity( - &self, - msg: impl AsRef<[u8]>, - ) -> std::result::Result; -} - /// NetworkProvider provides [`Worker`] with all necessary hooks into the /// underlying Substrate networking. Using this trait abstraction instead of -/// [`sc_network::NetworkService`] directly is necessary to unit test [`Worker`]. -#[async_trait] -pub trait NetworkProvider: NetworkStateInfo + NetworkSigner { - /// Start putting a value in the Dht. - fn put_value(&self, key: sc_network::KademliaKey, value: Vec); - - /// Start getting a value from the Dht. - fn get_value(&self, key: &sc_network::KademliaKey); -} +/// `sc_network::NetworkService` directly is necessary to unit test [`Worker`]. +pub trait NetworkProvider: NetworkDHTProvider + NetworkStateInfo + NetworkSigner {} -impl NetworkSigner for sc_network::NetworkService -where - B: BlockT + 'static, - H: ExHashT, -{ - fn sign_with_local_identity( - &self, - msg: impl AsRef<[u8]>, - ) -> std::result::Result { - self.sign_with_local_identity(msg) - } -} - -#[async_trait::async_trait] -impl NetworkProvider for sc_network::NetworkService -where - B: BlockT + 'static, - H: ExHashT, -{ - fn put_value(&self, key: sc_network::KademliaKey, value: Vec) { - self.put_value(key, value) - } - fn get_value(&self, key: &sc_network::KademliaKey) { - self.get_value(key) - } -} +impl NetworkProvider for T where T: NetworkDHTProvider + NetworkStateInfo + NetworkSigner {} -fn hash_authority_id(id: &[u8]) -> sc_network::KademliaKey { - sc_network::KademliaKey::new(&libp2p::multihash::Code::Sha2_256.digest(id).digest()) +fn hash_authority_id(id: &[u8]) -> KademliaKey { + KademliaKey::new(&libp2p::multihash::Code::Sha2_256.digest(id).digest()) } // Makes sure all values are the same and returns it @@ -685,7 +645,7 @@ async fn sign_record_with_authority_ids( peer_signature: Option, key_store: &dyn CryptoStore, keys: Vec, -) -> Result)>> { +) -> Result)>> { let signatures = key_store .sign_with_all(key_types::AUTHORITY_DISCOVERY, keys.clone(), &serialized_record) .await diff --git a/client/authority-discovery/src/worker/addr_cache.rs b/client/authority-discovery/src/worker/addr_cache.rs index f768b9c4e66a7..19bbbf0b62e7e 100644 --- a/client/authority-discovery/src/worker/addr_cache.rs +++ b/client/authority-discovery/src/worker/addr_cache.rs @@ -16,9 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use libp2p::core::multiaddr::{Multiaddr, Protocol}; - -use sc_network::PeerId; +use libp2p::{ + core::multiaddr::{Multiaddr, Protocol}, + PeerId, +}; use sp_authority_discovery::AuthorityId; use std::collections::{hash_map::Entry, HashMap, HashSet}; diff --git a/client/authority-discovery/src/worker/schema/tests.rs b/client/authority-discovery/src/worker/schema/tests.rs index b85a4ce37447d..60147d6762e50 100644 --- a/client/authority-discovery/src/worker/schema/tests.rs +++ b/client/authority-discovery/src/worker/schema/tests.rs @@ -21,9 +21,8 @@ mod schema_v1 { } use super::*; -use libp2p::multiaddr::Multiaddr; +use libp2p::{multiaddr::Multiaddr, PeerId}; use prost::Message; -use sc_network::PeerId; #[test] fn v2_decodes_v1() { @@ -56,7 +55,7 @@ fn v2_decodes_v1() { #[test] fn v1_decodes_v2() { - let peer_secret = sc_network::Keypair::generate_ed25519(); + let peer_secret = libp2p::identity::Keypair::generate_ed25519(); let peer_public = peer_secret.public(); let peer_id = peer_public.to_peer_id(); let multiaddress: Multiaddr = diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index a1a699bc30dd2..5a60d3353db52 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -22,7 +22,6 @@ use std::{ task::Poll, }; -use async_trait::async_trait; use futures::{ channel::mpsc::{self, channel}, executor::{block_on, LocalPool}, @@ -30,9 +29,10 @@ use futures::{ sink::SinkExt, task::LocalSpawn, }; -use libp2p::{core::multiaddr, PeerId}; +use libp2p::{core::multiaddr, identity::Keypair, PeerId}; use prometheus_endpoint::prometheus::default_registry; +use sc_network_common::service::{KademliaKey, Signature, SigningError}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_keystore::{testing::KeyStore, CryptoStore}; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; @@ -111,18 +111,18 @@ sp_api::mock_impl_runtime_apis! { #[derive(Debug)] pub enum TestNetworkEvent { - GetCalled(sc_network::KademliaKey), - PutCalled(sc_network::KademliaKey, Vec), + GetCalled(KademliaKey), + PutCalled(KademliaKey, Vec), } pub struct TestNetwork { peer_id: PeerId, - identity: sc_network::Keypair, + identity: Keypair, external_addresses: Vec, // Whenever functions on `TestNetwork` are called, the function arguments are added to the // vectors below. - pub put_value_call: Arc)>>>, - pub get_value_call: Arc>>, + pub put_value_call: Arc)>>>, + pub get_value_call: Arc>>, event_sender: mpsc::UnboundedSender, event_receiver: Option>, } @@ -136,7 +136,7 @@ impl TestNetwork { impl Default for TestNetwork { fn default() -> Self { let (tx, rx) = mpsc::unbounded(); - let identity = sc_network::Keypair::generate_ed25519(); + let identity = Keypair::generate_ed25519(); TestNetwork { peer_id: identity.public().to_peer_id(), identity, @@ -153,21 +153,20 @@ impl NetworkSigner for TestNetwork { fn sign_with_local_identity( &self, msg: impl AsRef<[u8]>, - ) -> std::result::Result { - sc_network::Signature::sign_message(msg, &self.identity) + ) -> std::result::Result { + Signature::sign_message(msg, &self.identity) } } -#[async_trait] -impl NetworkProvider for TestNetwork { - fn put_value(&self, key: sc_network::KademliaKey, value: Vec) { +impl NetworkDHTProvider for TestNetwork { + fn put_value(&self, key: KademliaKey, value: Vec) { self.put_value_call.lock().unwrap().push((key.clone(), value.clone())); self.event_sender .clone() .unbounded_send(TestNetworkEvent::PutCalled(key, value)) .unwrap(); } - fn get_value(&self, key: &sc_network::KademliaKey) { + fn get_value(&self, key: &KademliaKey) { self.get_value_call.lock().unwrap().push(key.clone()); self.event_sender .clone() @@ -186,12 +185,16 @@ impl NetworkStateInfo for TestNetwork { } } -impl NetworkSigner for sc_network::Keypair { +struct TestSigner<'a> { + keypair: &'a Keypair, +} + +impl<'a> NetworkSigner for TestSigner<'a> { fn sign_with_local_identity( &self, msg: impl AsRef<[u8]>, - ) -> std::result::Result { - sc_network::Signature::sign_message(msg, self) + ) -> std::result::Result { + Signature::sign_message(msg, self.keypair) } } @@ -200,7 +203,7 @@ async fn build_dht_event( public_key: AuthorityId, key_store: &dyn CryptoStore, network: Option<&Signer>, -) -> Vec<(sc_network::KademliaKey, Vec)> { +) -> Vec<(KademliaKey, Vec)> { let serialized_record = serialize_authority_record(serialize_addresses(addresses.into_iter())).unwrap(); @@ -313,7 +316,7 @@ fn publish_discover_cycle() { let dht_event = { let (key, value) = network.put_value_call.lock().unwrap().pop().unwrap(); - sc_network::DhtEvent::ValueFound(vec![(key, value)]) + DhtEvent::ValueFound(vec![(key, value)]) }; // Node B discovering node A's address. @@ -469,7 +472,7 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { None, ) .await; - sc_network::DhtEvent::ValueFound(kv_pairs) + DhtEvent::ValueFound(kv_pairs) }; dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); @@ -487,7 +490,7 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { struct DhtValueFoundTester { pub remote_key_store: KeyStore, pub remote_authority_public: sp_core::sr25519::Public, - pub remote_node_key: sc_network::Keypair, + pub remote_node_key: Keypair, pub local_worker: Option< Worker< TestApi, @@ -496,7 +499,7 @@ struct DhtValueFoundTester { sp_runtime::generic::Header, substrate_test_runtime_client::runtime::Extrinsic, >, - std::pin::Pin>>, + std::pin::Pin>>, >, >, } @@ -508,7 +511,7 @@ impl DhtValueFoundTester { block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)) .unwrap(); - let remote_node_key = sc_network::Keypair::generate_ed25519(); + let remote_node_key = Keypair::generate_ed25519(); Self { remote_key_store, remote_authority_public, remote_node_key, local_worker: None } } @@ -523,7 +526,7 @@ impl DhtValueFoundTester { fn process_value_found( &mut self, strict_record_validation: bool, - values: Vec<(sc_network::KademliaKey, Vec)>, + values: Vec<(KademliaKey, Vec)>, ) -> Option<&HashSet> { let (_dht_event_tx, dht_event_rx) = channel(1); let local_test_api = @@ -583,7 +586,7 @@ fn strict_accept_address_with_peer_signature() { vec![addr.clone()], tester.remote_authority_public.clone().into(), &tester.remote_key_store, - Some(&tester.remote_node_key), + Some(&TestSigner { keypair: &tester.remote_node_key }), )); let cached_remote_addresses = tester.process_value_found(true, kv_pairs); @@ -598,12 +601,12 @@ fn strict_accept_address_with_peer_signature() { #[test] fn reject_address_with_rogue_peer_signature() { let mut tester = DhtValueFoundTester::new(); - let rogue_remote_node_key = sc_network::Keypair::generate_ed25519(); + let rogue_remote_node_key = Keypair::generate_ed25519(); let kv_pairs = block_on(build_dht_event( vec![tester.multiaddr_with_peer_id(1)], tester.remote_authority_public.clone().into(), &tester.remote_key_store, - Some(&rogue_remote_node_key), + Some(&TestSigner { keypair: &rogue_remote_node_key }), )); let cached_remote_addresses = tester.process_value_found(false, kv_pairs); @@ -621,7 +624,7 @@ fn reject_address_with_invalid_peer_signature() { vec![tester.multiaddr_with_peer_id(1)], tester.remote_authority_public.clone().into(), &tester.remote_key_store, - Some(&tester.remote_node_key), + Some(&TestSigner { keypair: &tester.remote_node_key }), )); // tamper with the signature let mut record = schema::SignedAuthorityRecord::decode(kv_pairs[0].1.as_slice()).unwrap(); @@ -808,7 +811,7 @@ fn lookup_throttling() { None, ) .await; - sc_network::DhtEvent::ValueFound(kv_pairs) + DhtEvent::ValueFound(kv_pairs) }; dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); @@ -822,7 +825,7 @@ fn lookup_throttling() { // Make second one fail. let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap(); - let dht_event = sc_network::DhtEvent::ValueNotFound(remote_hash); + let dht_event = DhtEvent::ValueNotFound(remote_hash); dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); // Assert worker to trigger another lookup. diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 6f9ee6f864ad8..f63e453a48026 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -518,7 +518,7 @@ pub fn start_mining_worker( select_chain: S, algorithm: Algorithm, mut env: E, - mut sync_oracle: SO, + sync_oracle: SO, justification_sync_link: L, pre_runtime: Option>, create_inherent_data_providers: CIDP, diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 7c3de13444c1a..39b40a32f18ca 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -490,7 +490,7 @@ pub async fn start_slot_worker( slot_duration: SlotDuration, client: C, mut worker: W, - mut sync_oracle: SO, + sync_oracle: SO, create_inherent_data_providers: CIDP, can_author_with: CAW, ) where diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 65d7dfb783aa3..9e9f2fb98b0d1 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -89,7 +89,8 @@ use log::{debug, trace}; use parity_scale_codec::{Decode, Encode}; use prometheus_endpoint::{register, CounterVec, Opts, PrometheusError, Registry, U64}; use rand::seq::SliceRandom; -use sc_network::{ObservedRole, PeerId, ReputationChange}; +use sc_network::{PeerId, ReputationChange}; +use sc_network_common::protocol::event::ObservedRole; use sc_network_gossip::{MessageIntent, ValidatorContext}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 378501cffdd62..7a47ebe214950 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -45,7 +45,7 @@ use finality_grandpa::{ Message::{Precommit, Prevote, PrimaryPropose}, }; use parity_scale_codec::{Decode, Encode}; -use sc_network::{NetworkService, ReputationChange}; +use sc_network::ReputationChange; use sc_network_gossip::{GossipEngine, Network as GossipNetwork}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sp_keystore::SyncCryptoStorePtr; @@ -58,6 +58,7 @@ use crate::{ use gossip::{ FullCatchUpMessage, FullCommitMessage, GossipMessage, GossipValidator, PeerReport, VoteMessage, }; +use sc_network_common::service::{NetworkBlock, NetworkSyncForkRequest}; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_finality_grandpa::{AuthorityId, AuthoritySignature, RoundNumber, SetId as SetIdNumber}; @@ -156,34 +157,26 @@ const TELEMETRY_VOTERS_LIMIT: usize = 10; /// /// Something that provides both the capabilities needed for the `gossip_network::Network` trait as /// well as the ability to set a fork sync request for a particular block. -pub trait Network: GossipNetwork + Clone + Send + 'static { - /// Notifies the sync service to try and sync the given block from the given - /// peers. - /// - /// If the given vector of peers is empty then the underlying implementation - /// should make a best effort to fetch the block from any peers it is - /// connected to (NOTE: this assumption will change in the future #3629). - fn set_sync_fork_request( - &self, - peers: Vec, - hash: Block::Hash, - number: NumberFor, - ); +pub trait Network: + NetworkSyncForkRequest> + + NetworkBlock> + + GossipNetwork + + Clone + + Send + + 'static +{ } -impl Network for Arc> +impl Network for T where - B: BlockT, - H: sc_network::ExHashT, + Block: BlockT, + T: NetworkSyncForkRequest> + + NetworkBlock> + + GossipNetwork + + Clone + + Send + + 'static, { - fn set_sync_fork_request( - &self, - peers: Vec, - hash: B::Hash, - number: NumberFor, - ) { - NetworkService::set_sync_fork_request(self, peers, hash, number) - } } /// Create a unique topic for a round and set-id combo. @@ -467,7 +460,7 @@ impl> NetworkBridge { hash: B::Hash, number: NumberFor, ) { - Network::set_sync_fork_request(&self.service, peers, hash, number) + self.service.set_sync_fork_request(peers, hash, number) } } diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index 0ec5092a2a047..59935cef6a095 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -25,7 +25,14 @@ use super::{ use crate::{communication::grandpa_protocol_name, environment::SharedVoterSetState}; use futures::prelude::*; use parity_scale_codec::Encode; -use sc_network::{config::Role, Event as NetworkEvent, ObservedRole, PeerId}; +use sc_network::{config::Role, Multiaddr, PeerId, ReputationChange}; +use sc_network_common::{ + protocol::event::{Event as NetworkEvent, ObservedRole}, + service::{ + NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, + NetworkSyncForkRequest, NotificationSender, NotificationSenderError, + }, +}; use sc_network_gossip::Validator; use sc_network_test::{Block, Hash}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; @@ -34,6 +41,7 @@ use sp_keyring::Ed25519Keyring; use sp_runtime::traits::NumberFor; use std::{ borrow::Cow, + collections::HashSet, pin::Pin, sync::Arc, task::{Context, Poll}, @@ -42,8 +50,8 @@ use std::{ #[derive(Debug)] pub(crate) enum Event { EventStream(TracingUnboundedSender), - WriteNotification(sc_network::PeerId, Vec), - Report(sc_network::PeerId, sc_network::ReputationChange), + WriteNotification(PeerId, Vec), + Report(PeerId, ReputationChange), Announce(Hash), } @@ -52,49 +60,122 @@ pub(crate) struct TestNetwork { sender: TracingUnboundedSender, } -impl sc_network_gossip::Network for TestNetwork { - fn event_stream(&self) -> Pin + Send>> { - let (tx, rx) = tracing_unbounded("test"); - let _ = self.sender.unbounded_send(Event::EventStream(tx)); - Box::pin(rx) +impl NetworkPeers for TestNetwork { + fn set_authorized_peers(&self, _peers: HashSet) { + unimplemented!(); + } + + fn set_authorized_only(&self, _reserved_only: bool) { + unimplemented!(); + } + + fn add_known_address(&self, _peer_id: PeerId, _addr: Multiaddr) { + unimplemented!(); } - fn report_peer(&self, who: sc_network::PeerId, cost_benefit: sc_network::ReputationChange) { + fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { let _ = self.sender.unbounded_send(Event::Report(who, cost_benefit)); } - fn add_set_reserved(&self, _: PeerId, _: Cow<'static, str>) {} + fn disconnect_peer(&self, _who: PeerId, _protocol: Cow<'static, str>) {} + + fn accept_unreserved_peers(&self) { + unimplemented!(); + } + + fn deny_unreserved_peers(&self) { + unimplemented!(); + } + + fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { + unimplemented!(); + } + + fn remove_reserved_peer(&self, _peer_id: PeerId) { + unimplemented!(); + } + + fn set_reserved_peers( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn add_peers_to_reserved_set( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn remove_peers_from_reserved_set(&self, _protocol: Cow<'static, str>, _peers: Vec) {} - fn remove_set_reserved(&self, _: PeerId, _: Cow<'static, str>) {} + fn add_to_peers_set( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } - fn disconnect_peer(&self, _: PeerId, _: Cow<'static, str>) {} + fn remove_from_peers_set(&self, _protocol: Cow<'static, str>, _peers: Vec) { + unimplemented!(); + } - fn write_notification(&self, who: PeerId, _: Cow<'static, str>, message: Vec) { - let _ = self.sender.unbounded_send(Event::WriteNotification(who, message)); + fn sync_num_connected(&self) -> usize { + unimplemented!(); } +} - fn announce(&self, block: Hash, _associated_data: Option>) { - let _ = self.sender.unbounded_send(Event::Announce(block)); +impl NetworkEventStream for TestNetwork { + fn event_stream( + &self, + _name: &'static str, + ) -> Pin + Send>> { + let (tx, rx) = tracing_unbounded("test"); + let _ = self.sender.unbounded_send(Event::EventStream(tx)); + Box::pin(rx) } } -impl super::Network for TestNetwork { - fn set_sync_fork_request( +impl NetworkNotification for TestNetwork { + fn write_notification(&self, target: PeerId, _protocol: Cow<'static, str>, message: Vec) { + let _ = self.sender.unbounded_send(Event::WriteNotification(target, message)); + } + + fn notification_sender( &self, - _peers: Vec, - _hash: Hash, - _number: NumberFor, - ) { + _target: PeerId, + _protocol: Cow<'static, str>, + ) -> Result, NotificationSenderError> { + unimplemented!(); + } +} + +impl NetworkBlock> for TestNetwork { + fn announce_block(&self, hash: Hash, _data: Option>) { + let _ = self.sender.unbounded_send(Event::Announce(hash)); + } + + fn new_best_block_imported(&self, _hash: Hash, _number: NumberFor) { + unimplemented!(); } } +impl NetworkSyncForkRequest> for TestNetwork { + fn set_sync_fork_request(&self, _peers: Vec, _hash: Hash, _number: NumberFor) {} +} + impl sc_network_gossip::ValidatorContext for TestNetwork { fn broadcast_topic(&mut self, _: Hash, _: bool) {} fn broadcast_message(&mut self, _: Hash, _: Vec, _: bool) {} - fn send_message(&mut self, who: &sc_network::PeerId, data: Vec) { - >::write_notification( + fn send_message(&mut self, who: &PeerId, data: Vec) { + ::write_notification( self, who.clone(), grandpa_protocol_name::NAME.into(), @@ -102,7 +183,7 @@ impl sc_network_gossip::ValidatorContext for TestNetwork { ); } - fn send_topic(&mut self, _: &sc_network::PeerId, _: Hash, _: bool) {} + fn send_topic(&mut self, _: &PeerId, _: Hash, _: bool) {} } pub(crate) struct Tester { @@ -207,8 +288,8 @@ struct NoopContext; impl sc_network_gossip::ValidatorContext for NoopContext { fn broadcast_topic(&mut self, _: Hash, _: bool) {} fn broadcast_message(&mut self, _: Hash, _: Vec, _: bool) {} - fn send_message(&mut self, _: &sc_network::PeerId, _: Vec) {} - fn send_topic(&mut self, _: &sc_network::PeerId, _: Hash, _: bool) {} + fn send_message(&mut self, _: &PeerId, _: Vec) {} + fn send_topic(&mut self, _: &PeerId, _: Hash, _: bool) {} } #[test] @@ -252,7 +333,7 @@ fn good_commit_leads_to_relay() { }) .encode(); - let id = sc_network::PeerId::random(); + let id = PeerId::random(); let global_topic = super::global_topic::(set_id); let test = make_test_network() @@ -301,7 +382,7 @@ fn good_commit_leads_to_relay() { }); // Add a random peer which will be the recipient of this message - let receiver_id = sc_network::PeerId::random(); + let receiver_id = PeerId::random(); let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { remote: receiver_id.clone(), protocol: grandpa_protocol_name::NAME.into(), @@ -403,7 +484,7 @@ fn bad_commit_leads_to_report() { }) .encode(); - let id = sc_network::PeerId::random(); + let id = PeerId::random(); let global_topic = super::global_topic::(set_id); let test = make_test_network() @@ -484,7 +565,7 @@ fn bad_commit_leads_to_report() { #[test] fn peer_with_higher_view_leads_to_catch_up_request() { - let id = sc_network::PeerId::random(); + let id = PeerId::random(); let (tester, mut net) = make_test_network(); let test = tester diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index 528365d62c18b..b3ac5d892fd58 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -19,7 +19,7 @@ futures-timer = "3.0.1" log = "0.4.17" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } -sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } diff --git a/client/informant/src/display.rs b/client/informant/src/display.rs index 446ddf47b4cab..0441011b0ec42 100644 --- a/client/informant/src/display.rs +++ b/client/informant/src/display.rs @@ -20,7 +20,13 @@ use crate::OutputFormat; use ansi_term::Colour; use log::info; use sc_client_api::ClientInfo; -use sc_network::{NetworkStatus, SyncState, WarpSyncPhase, WarpSyncProgress}; +use sc_network_common::{ + service::NetworkStatus, + sync::{ + warp::{WarpSyncPhase, WarpSyncProgress}, + SyncState, + }, +}; use sp_runtime::traits::{Block as BlockT, CheckedDiv, NumberFor, Saturating, Zero}; use std::{fmt, time::Instant}; diff --git a/client/informant/src/lib.rs b/client/informant/src/lib.rs index 5dca77f1a7433..52f1c95fe0198 100644 --- a/client/informant/src/lib.rs +++ b/client/informant/src/lib.rs @@ -24,7 +24,7 @@ use futures_timer::Delay; use log::{debug, info, trace}; use parity_util_mem::MallocSizeOf; use sc_client_api::{BlockchainEvents, UsageProvider}; -use sc_network::NetworkService; +use sc_network_common::service::NetworkStatusProvider; use sc_transaction_pool_api::TransactionPool; use sp_blockchain::HeaderMetadata; use sp_runtime::traits::{Block as BlockT, Header}; @@ -53,12 +53,13 @@ impl Default for OutputFormat { } /// Builds the informant and returns a `Future` that drives the informant. -pub async fn build( +pub async fn build( client: Arc, - network: Arc::Hash>>, + network: N, pool: Arc

, format: OutputFormat, ) where + N: NetworkStatusProvider, C: UsageProvider + HeaderMetadata + BlockchainEvents, >::Error: Display, P: TransactionPool + MallocSizeOf, diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 144c5ad168996..185c37985b585 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -23,6 +23,7 @@ lru = "0.7.5" tracing = "0.1.29" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 2d086e89b4a10..8a6c3358e4409 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -21,7 +21,8 @@ use crate::{ Network, Validator, }; -use sc_network::{Event, ReputationChange}; +use sc_network::ReputationChange; +use sc_network_common::protocol::event::Event; use futures::{ channel::mpsc::{channel, Receiver, Sender}, @@ -85,7 +86,7 @@ impl GossipEngine { B: 'static, { let protocol = protocol.into(); - let network_event_stream = network.event_stream(); + let network_event_stream = network.event_stream("network-gossip"); GossipEngine { state_machine: ConsensusGossip::new(validator, protocol.clone(), metrics_registry), @@ -162,7 +163,7 @@ impl GossipEngine { /// Note: this method isn't strictly related to gossiping and should eventually be moved /// somewhere else. pub fn announce(&self, block: B::Hash, associated_data: Option>) { - self.network.announce(block, associated_data); + self.network.announce_block(block, associated_data); } } @@ -181,7 +182,10 @@ impl Future for GossipEngine { this.network.add_set_reserved(remote, this.protocol.clone()); }, Event::SyncDisconnected { remote } => { - this.network.remove_set_reserved(remote, this.protocol.clone()); + this.network.remove_peers_from_reserved_set( + this.protocol.clone(), + vec![remote], + ); }, Event::NotificationStreamOpened { remote, protocol, role, .. } => { if protocol != this.protocol { @@ -304,7 +308,7 @@ impl futures::future::FusedFuture for GossipEngine { #[cfg(test)] mod tests { use super::*; - use crate::{ValidationResult, ValidatorContext}; + use crate::{multiaddr::Multiaddr, ValidationResult, ValidatorContext}; use async_std::task::spawn; use futures::{ channel::mpsc::{unbounded, UnboundedSender}, @@ -312,10 +316,20 @@ mod tests { future::poll_fn, }; use quickcheck::{Arbitrary, Gen, QuickCheck}; - use sc_network::ObservedRole; - use sp_runtime::{testing::H256, traits::Block as BlockT}; + use sc_network_common::{ + protocol::event::ObservedRole, + service::{ + NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, + NotificationSender, NotificationSenderError, + }, + }; + use sp_runtime::{ + testing::H256, + traits::{Block as BlockT, NumberFor}, + }; use std::{ borrow::Cow, + collections::HashSet, sync::{Arc, Mutex}, }; use substrate_test_runtime_client::runtime::Block; @@ -330,29 +344,119 @@ mod tests { event_senders: Vec>, } - impl Network for TestNetwork { - fn event_stream(&self) -> Pin + Send>> { + impl NetworkPeers for TestNetwork { + fn set_authorized_peers(&self, _peers: HashSet) { + unimplemented!(); + } + + fn set_authorized_only(&self, _reserved_only: bool) { + unimplemented!(); + } + + fn add_known_address(&self, _peer_id: PeerId, _addr: Multiaddr) { + unimplemented!(); + } + + fn report_peer(&self, _who: PeerId, _cost_benefit: ReputationChange) {} + + fn disconnect_peer(&self, _who: PeerId, _protocol: Cow<'static, str>) { + unimplemented!(); + } + + fn accept_unreserved_peers(&self) { + unimplemented!(); + } + + fn deny_unreserved_peers(&self) { + unimplemented!(); + } + + fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { + unimplemented!(); + } + + fn remove_reserved_peer(&self, _peer_id: PeerId) { + unimplemented!(); + } + + fn set_reserved_peers( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn add_peers_to_reserved_set( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn remove_peers_from_reserved_set( + &self, + _protocol: Cow<'static, str>, + _peers: Vec, + ) { + } + + fn add_to_peers_set( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn remove_from_peers_set(&self, _protocol: Cow<'static, str>, _peers: Vec) { + unimplemented!(); + } + + fn sync_num_connected(&self) -> usize { + unimplemented!(); + } + } + + impl NetworkEventStream for TestNetwork { + fn event_stream(&self, _name: &'static str) -> Pin + Send>> { let (tx, rx) = unbounded(); self.inner.lock().unwrap().event_senders.push(tx); Box::pin(rx) } + } - fn report_peer(&self, _: PeerId, _: ReputationChange) {} - - fn disconnect_peer(&self, _: PeerId, _: Cow<'static, str>) { + impl NetworkNotification for TestNetwork { + fn write_notification( + &self, + _target: PeerId, + _protocol: Cow<'static, str>, + _message: Vec, + ) { unimplemented!(); } - fn add_set_reserved(&self, _: PeerId, _: Cow<'static, str>) {} - - fn remove_set_reserved(&self, _: PeerId, _: Cow<'static, str>) {} + fn notification_sender( + &self, + _target: PeerId, + _protocol: Cow<'static, str>, + ) -> Result, NotificationSenderError> { + unimplemented!(); + } + } - fn write_notification(&self, _: PeerId, _: Cow<'static, str>, _: Vec) { + impl NetworkBlock<::Hash, NumberFor> for TestNetwork { + fn announce_block(&self, _hash: ::Hash, _data: Option>) { unimplemented!(); } - fn announce(&self, _: B::Hash, _: Option>) { + fn new_best_block_imported( + &self, + _hash: ::Hash, + _number: NumberFor, + ) { unimplemented!(); } } diff --git a/client/network-gossip/src/lib.rs b/client/network-gossip/src/lib.rs index 4b83708702466..b9dff0bcd4d00 100644 --- a/client/network-gossip/src/lib.rs +++ b/client/network-gossip/src/lib.rs @@ -41,9 +41,9 @@ //! messages. //! //! The [`GossipEngine`] will automatically use [`Network::add_set_reserved`] and -//! [`Network::remove_set_reserved`] to maintain a set of peers equal to the set of peers the -//! node is syncing from. See the documentation of `sc-network` for more explanations about the -//! concepts of peer sets. +//! [`NetworkPeers::remove_peers_from_reserved_set`] to maintain a set of peers equal to the set of +//! peers the node is syncing from. See the documentation of `sc-network` for more explanations +//! about the concepts of peer sets. //! //! # What is a validator? //! @@ -67,74 +67,35 @@ pub use self::{ validator::{DiscardAll, MessageIntent, ValidationResult, Validator, ValidatorContext}, }; -use futures::prelude::*; -use sc_network::{multiaddr, Event, ExHashT, NetworkService, PeerId, ReputationChange}; -use sp_runtime::traits::Block as BlockT; -use std::{borrow::Cow, iter, pin::Pin, sync::Arc}; +use sc_network::{multiaddr, PeerId}; +use sc_network_common::service::{ + NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, +}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; +use std::{borrow::Cow, iter}; mod bridge; mod state_machine; mod validator; /// Abstraction over a network. -pub trait Network { - /// Returns a stream of events representing what happens on the network. - fn event_stream(&self) -> Pin + Send>>; - - /// Adjust the reputation of a node. - fn report_peer(&self, peer_id: PeerId, reputation: ReputationChange); - - /// Adds the peer to the set of peers to be connected to with this protocol. - fn add_set_reserved(&self, who: PeerId, protocol: Cow<'static, str>); - - /// Removes the peer from the set of peers to be connected to with this protocol. - fn remove_set_reserved(&self, who: PeerId, protocol: Cow<'static, str>); - - /// Force-disconnect a peer. - fn disconnect_peer(&self, who: PeerId, protocol: Cow<'static, str>); - - /// Send a notification to a peer. - fn write_notification(&self, who: PeerId, protocol: Cow<'static, str>, message: Vec); - - /// Notify everyone we're connected to that we have the given block. - /// - /// Note: this method isn't strictly related to gossiping and should eventually be moved - /// somewhere else. - fn announce(&self, block: B::Hash, associated_data: Option>); -} - -impl Network for Arc> { - fn event_stream(&self) -> Pin + Send>> { - Box::pin(NetworkService::event_stream(self, "network-gossip")) - } - - fn report_peer(&self, peer_id: PeerId, reputation: ReputationChange) { - NetworkService::report_peer(self, peer_id, reputation); - } - +pub trait Network: + NetworkPeers + NetworkEventStream + NetworkNotification + NetworkBlock> +{ fn add_set_reserved(&self, who: PeerId, protocol: Cow<'static, str>) { let addr = iter::once(multiaddr::Protocol::P2p(who.into())).collect::(); - let result = - NetworkService::add_peers_to_reserved_set(self, protocol, iter::once(addr).collect()); + let result = self.add_peers_to_reserved_set(protocol, iter::once(addr).collect()); if let Err(err) = result { log::error!(target: "gossip", "add_set_reserved failed: {}", err); } } +} - fn remove_set_reserved(&self, who: PeerId, protocol: Cow<'static, str>) { - NetworkService::remove_peers_from_reserved_set(self, protocol, iter::once(who).collect()); - } - - fn disconnect_peer(&self, who: PeerId, protocol: Cow<'static, str>) { - NetworkService::disconnect_peer(self, who, protocol) - } - - fn write_notification(&self, who: PeerId, protocol: Cow<'static, str>, message: Vec) { - NetworkService::write_notification(self, who, protocol, message) - } - - fn announce(&self, block: B::Hash, associated_data: Option>) { - NetworkService::announce_block(self, block, associated_data) - } +impl Network for T where + T: NetworkPeers + + NetworkEventStream + + NetworkNotification + + NetworkBlock> +{ } diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 8a016cbaab3da..4cc4e25529af4 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -22,7 +22,7 @@ use ahash::AHashSet; use libp2p::PeerId; use lru::LruCache; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; -use sc_network::ObservedRole; +use sc_network_common::protocol::event::ObservedRole; use sp_runtime::traits::{Block as BlockT, Hash, HashFor}; use std::{borrow::Cow, collections::HashMap, iter, sync::Arc, time, time::Instant}; @@ -511,11 +511,23 @@ impl Metrics { #[cfg(test)] mod tests { use super::*; + use crate::multiaddr::Multiaddr; use futures::prelude::*; - use sc_network::{Event, ReputationChange}; - use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256}; + use sc_network::ReputationChange; + use sc_network_common::{ + protocol::event::Event, + service::{ + NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, + NotificationSender, NotificationSenderError, + }, + }; + use sp_runtime::{ + testing::{Block as RawBlock, ExtrinsicWrapper, H256}, + traits::NumberFor, + }; use std::{ borrow::Cow, + collections::HashSet, pin::Pin, sync::{Arc, Mutex}, }; @@ -569,28 +581,118 @@ mod tests { peer_reports: Vec<(PeerId, ReputationChange)>, } - impl Network for NoOpNetwork { - fn event_stream(&self) -> Pin + Send>> { + impl NetworkPeers for NoOpNetwork { + fn set_authorized_peers(&self, _peers: HashSet) { + unimplemented!(); + } + + fn set_authorized_only(&self, _reserved_only: bool) { + unimplemented!(); + } + + fn add_known_address(&self, _peer_id: PeerId, _addr: Multiaddr) { + unimplemented!(); + } + + fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { + self.inner.lock().unwrap().peer_reports.push((who, cost_benefit)); + } + + fn disconnect_peer(&self, _who: PeerId, _protocol: Cow<'static, str>) { + unimplemented!(); + } + + fn accept_unreserved_peers(&self) { + unimplemented!(); + } + + fn deny_unreserved_peers(&self) { + unimplemented!(); + } + + fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { + unimplemented!(); + } + + fn remove_reserved_peer(&self, _peer_id: PeerId) { + unimplemented!(); + } + + fn set_reserved_peers( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { unimplemented!(); } - fn report_peer(&self, peer_id: PeerId, reputation_change: ReputationChange) { - self.inner.lock().unwrap().peer_reports.push((peer_id, reputation_change)); + fn add_peers_to_reserved_set( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn remove_peers_from_reserved_set( + &self, + _protocol: Cow<'static, str>, + _peers: Vec, + ) { } - fn disconnect_peer(&self, _: PeerId, _: Cow<'static, str>) { + fn add_to_peers_set( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { unimplemented!(); } - fn add_set_reserved(&self, _: PeerId, _: Cow<'static, str>) {} + fn remove_from_peers_set(&self, _protocol: Cow<'static, str>, _peers: Vec) { + unimplemented!(); + } - fn remove_set_reserved(&self, _: PeerId, _: Cow<'static, str>) {} + fn sync_num_connected(&self) -> usize { + unimplemented!(); + } + } - fn write_notification(&self, _: PeerId, _: Cow<'static, str>, _: Vec) { + impl NetworkEventStream for NoOpNetwork { + fn event_stream(&self, _name: &'static str) -> Pin + Send>> { unimplemented!(); } + } - fn announce(&self, _: B::Hash, _: Option>) { + impl NetworkNotification for NoOpNetwork { + fn write_notification( + &self, + _target: PeerId, + _protocol: Cow<'static, str>, + _message: Vec, + ) { + unimplemented!(); + } + + fn notification_sender( + &self, + _target: PeerId, + _protocol: Cow<'static, str>, + ) -> Result, NotificationSenderError> { + unimplemented!(); + } + } + + impl NetworkBlock<::Hash, NumberFor> for NoOpNetwork { + fn announce_block(&self, _hash: ::Hash, _data: Option>) { + unimplemented!(); + } + + fn new_best_block_imported( + &self, + _hash: ::Hash, + _number: NumberFor, + ) { unimplemented!(); } } diff --git a/client/network-gossip/src/validator.rs b/client/network-gossip/src/validator.rs index 7d60f7b31397f..a98c62ab5a9eb 100644 --- a/client/network-gossip/src/validator.rs +++ b/client/network-gossip/src/validator.rs @@ -16,7 +16,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use sc_network::{ObservedRole, PeerId}; +use sc_network::PeerId; +use sc_network_common::protocol::event::ObservedRole; use sp_runtime::traits::Block as BlockT; /// Validates consensus messages. diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index b0e3a8fe42a83..1b10bd248292c 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -17,7 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.10" [dependencies] +async-trait = "0.1.50" bitflags = "1.3.2" +bytes = "1" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } @@ -29,3 +31,4 @@ sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +thiserror = "1.0" diff --git a/client/network/common/src/lib.rs b/client/network/common/src/lib.rs index 9fbedc542c123..3a30d24900199 100644 --- a/client/network/common/src/lib.rs +++ b/client/network/common/src/lib.rs @@ -20,5 +20,7 @@ pub mod config; pub mod message; +pub mod protocol; pub mod request_responses; +pub mod service; pub mod sync; diff --git a/client/network/common/src/protocol.rs b/client/network/common/src/protocol.rs new file mode 100644 index 0000000000000..0fd36cb511112 --- /dev/null +++ b/client/network/common/src/protocol.rs @@ -0,0 +1,19 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pub mod event; diff --git a/client/network/src/protocol/event.rs b/client/network/common/src/protocol/event.rs similarity index 96% rename from client/network/src/protocol/event.rs rename to client/network/common/src/protocol/event.rs index 26c9544960605..c6fb4a2faf9f9 100644 --- a/client/network/src/protocol/event.rs +++ b/client/network/common/src/protocol/event.rs @@ -67,14 +67,14 @@ pub enum Event { remote: PeerId, /// The concerned protocol. Each protocol uses a different substream. /// This is always equal to the value of - /// [`crate::config::NonDefaultSetConfig::notifications_protocol`] of one of the + /// `sc_network::config::NonDefaultSetConfig::notifications_protocol` of one of the /// configured sets. protocol: Cow<'static, str>, /// If the negotiation didn't use the main name of the protocol (the one in /// `notifications_protocol`), then this field contains which name has actually been /// used. /// Always contains a value equal to the value in - /// [`crate::config::NonDefaultSetConfig::fallback_names`]. + /// `sc_network::config::NonDefaultSetConfig::fallback_names`. negotiated_fallback: Option>, /// Role of the remote. role: ObservedRole, diff --git a/client/network/common/src/request_responses.rs b/client/network/common/src/request_responses.rs index f409d1ac16d61..a216c9c2d254d 100644 --- a/client/network/common/src/request_responses.rs +++ b/client/network/common/src/request_responses.rs @@ -19,7 +19,7 @@ //! Collection of generic data structures for request-response protocols. use futures::channel::{mpsc, oneshot}; -use libp2p::PeerId; +use libp2p::{request_response::OutboundFailure, PeerId}; use sc_peerset::ReputationChange; use std::{borrow::Cow, time::Duration}; @@ -115,3 +115,40 @@ pub struct OutgoingResponse { /// > written to the buffer managed by the operating system. pub sent_feedback: Option>, } + +/// When sending a request, what to do on a disconnected recipient. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum IfDisconnected { + /// Try to connect to the peer. + TryConnect, + /// Just fail if the destination is not yet connected. + ImmediateError, +} + +/// Convenience functions for `IfDisconnected`. +impl IfDisconnected { + /// Shall we connect to a disconnected peer? + pub fn should_connect(self) -> bool { + match self { + Self::TryConnect => true, + Self::ImmediateError => false, + } + } +} + +/// Error in a request. +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum RequestFailure { + #[error("We are not currently connected to the requested peer.")] + NotConnected, + #[error("Given protocol hasn't been registered.")] + UnknownProtocol, + #[error("Remote has closed the substream before answering, thereby signaling that it considers the request as valid, but refused to answer it.")] + Refused, + #[error("The remote replied, but the local node is no longer interested in the response.")] + Obsolete, + /// Problem on the network. + #[error("Problem on the network: {0}")] + Network(OutboundFailure), +} diff --git a/client/network/common/src/service.rs b/client/network/common/src/service.rs new file mode 100644 index 0000000000000..0fff32b12d66c --- /dev/null +++ b/client/network/common/src/service.rs @@ -0,0 +1,660 @@ +// This file is part of Substrate. +// +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// If you read this, you are very thorough, congratulations. + +use crate::{ + protocol::event::Event, + request_responses::{IfDisconnected, RequestFailure}, + sync::{warp::WarpSyncProgress, StateDownloadProgress, SyncState}, +}; +use futures::{channel::oneshot, Stream}; +pub use libp2p::{identity::error::SigningError, kad::record::Key as KademliaKey}; +use libp2p::{Multiaddr, PeerId}; +use sc_peerset::ReputationChange; +pub use signature::Signature; +use sp_runtime::traits::{Block as BlockT, NumberFor}; +use std::{borrow::Cow, collections::HashSet, future::Future, pin::Pin, sync::Arc}; + +mod signature; + +/// Signer with network identity +pub trait NetworkSigner { + /// Signs the message with the `KeyPair` that defines the local [`PeerId`]. + fn sign_with_local_identity(&self, msg: impl AsRef<[u8]>) -> Result; +} + +impl NetworkSigner for Arc +where + T: ?Sized, + T: NetworkSigner, +{ + fn sign_with_local_identity(&self, msg: impl AsRef<[u8]>) -> Result { + T::sign_with_local_identity(self, msg) + } +} + +/// Provides access to the networking DHT. +pub trait NetworkDHTProvider { + /// Start getting a value from the DHT. + fn get_value(&self, key: &KademliaKey); + + /// Start putting a value in the DHT. + fn put_value(&self, key: KademliaKey, value: Vec); +} + +impl NetworkDHTProvider for Arc +where + T: ?Sized, + T: NetworkDHTProvider, +{ + fn get_value(&self, key: &KademliaKey) { + T::get_value(self, key) + } + + fn put_value(&self, key: KademliaKey, value: Vec) { + T::put_value(self, key, value) + } +} + +/// Provides an ability to set a fork sync request for a particular block. +pub trait NetworkSyncForkRequest { + /// Notifies the sync service to try and sync the given block from the given + /// peers. + /// + /// If the given vector of peers is empty then the underlying implementation + /// should make a best effort to fetch the block from any peers it is + /// connected to (NOTE: this assumption will change in the future #3629). + fn set_sync_fork_request(&self, peers: Vec, hash: BlockHash, number: BlockNumber); +} + +impl NetworkSyncForkRequest for Arc +where + T: ?Sized, + T: NetworkSyncForkRequest, +{ + fn set_sync_fork_request(&self, peers: Vec, hash: BlockHash, number: BlockNumber) { + T::set_sync_fork_request(self, peers, hash, number) + } +} + +/// Overview status of the network. +#[derive(Clone)] +pub struct NetworkStatus { + /// Current global sync state. + pub sync_state: SyncState, + /// Target sync block number. + pub best_seen_block: Option>, + /// Number of peers participating in syncing. + pub num_sync_peers: u32, + /// Total number of connected peers + pub num_connected_peers: usize, + /// Total number of active peers. + pub num_active_peers: usize, + /// The total number of bytes received. + pub total_bytes_inbound: u64, + /// The total number of bytes sent. + pub total_bytes_outbound: u64, + /// State sync in progress. + pub state_sync: Option, + /// Warp sync in progress. + pub warp_sync: Option>, +} + +/// Provides high-level status information about network. +#[async_trait::async_trait] +pub trait NetworkStatusProvider { + /// High-level network status information. + /// + /// Returns an error if the `NetworkWorker` is no longer running. + async fn status(&self) -> Result, ()>; +} + +// Manual implementation to avoid extra boxing here +impl NetworkStatusProvider for Arc +where + T: ?Sized, + T: NetworkStatusProvider, +{ + fn status<'life0, 'async_trait>( + &'life0 self, + ) -> Pin, ()>> + Send + 'async_trait>> + where + 'life0: 'async_trait, + Self: 'async_trait, + { + T::status(self) + } +} + +/// Provides low-level API for manipulating network peers. +pub trait NetworkPeers { + /// Set authorized peers. + /// + /// Need a better solution to manage authorized peers, but now just use reserved peers for + /// prototyping. + fn set_authorized_peers(&self, peers: HashSet); + + /// Set authorized_only flag. + /// + /// Need a better solution to decide authorized_only, but now just use reserved_only flag for + /// prototyping. + fn set_authorized_only(&self, reserved_only: bool); + + /// Adds an address known to a node. + fn add_known_address(&self, peer_id: PeerId, addr: Multiaddr); + + /// Report a given peer as either beneficial (+) or costly (-) according to the + /// given scalar. + fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange); + + /// Disconnect from a node as soon as possible. + /// + /// This triggers the same effects as if the connection had closed itself spontaneously. + /// + /// See also [`NetworkPeers::remove_from_peers_set`], which has the same effect but also + /// prevents the local node from re-establishing an outgoing substream to this peer until it + /// is added again. + fn disconnect_peer(&self, who: PeerId, protocol: Cow<'static, str>); + + /// Connect to unreserved peers and allow unreserved peers to connect for syncing purposes. + fn accept_unreserved_peers(&self); + + /// Disconnect from unreserved peers and deny new unreserved peers to connect for syncing + /// purposes. + fn deny_unreserved_peers(&self); + + /// Adds a `PeerId` and its address as reserved. The string should encode the address + /// and peer ID of the remote node. + /// + /// Returns an `Err` if the given string is not a valid multiaddress + /// or contains an invalid peer ID (which includes the local peer ID). + fn add_reserved_peer(&self, peer: String) -> Result<(), String>; + + /// Removes a `PeerId` from the list of reserved peers. + fn remove_reserved_peer(&self, peer_id: PeerId); + + /// Sets the reserved set of a protocol to the given set of peers. + /// + /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also + /// consist of only `/p2p/`. + /// + /// The node will start establishing/accepting connections and substreams to/from peers in this + /// set, if it doesn't have any substream open with them yet. + /// + /// Note however, if a call to this function results in less peers on the reserved set, they + /// will not necessarily get disconnected (depending on available free slots in the peer set). + /// If you want to also disconnect those removed peers, you will have to call + /// `remove_from_peers_set` on those in addition to updating the reserved set. You can omit + /// this step if the peer set is in reserved only mode. + /// + /// Returns an `Err` if one of the given addresses is invalid or contains an + /// invalid peer ID (which includes the local peer ID). + fn set_reserved_peers( + &self, + protocol: Cow<'static, str>, + peers: HashSet, + ) -> Result<(), String>; + + /// Add peers to a peer set. + /// + /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also + /// consist of only `/p2p/`. + /// + /// Returns an `Err` if one of the given addresses is invalid or contains an + /// invalid peer ID (which includes the local peer ID). + fn add_peers_to_reserved_set( + &self, + protocol: Cow<'static, str>, + peers: HashSet, + ) -> Result<(), String>; + + /// Remove peers from a peer set. + fn remove_peers_from_reserved_set(&self, protocol: Cow<'static, str>, peers: Vec); + + /// Add a peer to a set of peers. + /// + /// If the set has slots available, it will try to open a substream with this peer. + /// + /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also + /// consist of only `/p2p/`. + /// + /// Returns an `Err` if one of the given addresses is invalid or contains an + /// invalid peer ID (which includes the local peer ID). + fn add_to_peers_set( + &self, + protocol: Cow<'static, str>, + peers: HashSet, + ) -> Result<(), String>; + + /// Remove peers from a peer set. + /// + /// If we currently have an open substream with this peer, it will soon be closed. + fn remove_from_peers_set(&self, protocol: Cow<'static, str>, peers: Vec); + + /// Returns the number of peers in the sync peer set we're connected to. + fn sync_num_connected(&self) -> usize; +} + +// Manual implementation to avoid extra boxing here +impl NetworkPeers for Arc +where + T: ?Sized, + T: NetworkPeers, +{ + fn set_authorized_peers(&self, peers: HashSet) { + T::set_authorized_peers(self, peers) + } + + fn set_authorized_only(&self, reserved_only: bool) { + T::set_authorized_only(self, reserved_only) + } + + fn add_known_address(&self, peer_id: PeerId, addr: Multiaddr) { + T::add_known_address(self, peer_id, addr) + } + + fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { + T::report_peer(self, who, cost_benefit) + } + + fn disconnect_peer(&self, who: PeerId, protocol: Cow<'static, str>) { + T::disconnect_peer(self, who, protocol) + } + + fn accept_unreserved_peers(&self) { + T::accept_unreserved_peers(self) + } + + fn deny_unreserved_peers(&self) { + T::deny_unreserved_peers(self) + } + + fn add_reserved_peer(&self, peer: String) -> Result<(), String> { + T::add_reserved_peer(self, peer) + } + + fn remove_reserved_peer(&self, peer_id: PeerId) { + T::remove_reserved_peer(self, peer_id) + } + + fn set_reserved_peers( + &self, + protocol: Cow<'static, str>, + peers: HashSet, + ) -> Result<(), String> { + T::set_reserved_peers(self, protocol, peers) + } + + fn add_peers_to_reserved_set( + &self, + protocol: Cow<'static, str>, + peers: HashSet, + ) -> Result<(), String> { + T::add_peers_to_reserved_set(self, protocol, peers) + } + + fn remove_peers_from_reserved_set(&self, protocol: Cow<'static, str>, peers: Vec) { + T::remove_peers_from_reserved_set(self, protocol, peers) + } + + fn add_to_peers_set( + &self, + protocol: Cow<'static, str>, + peers: HashSet, + ) -> Result<(), String> { + T::add_to_peers_set(self, protocol, peers) + } + + fn remove_from_peers_set(&self, protocol: Cow<'static, str>, peers: Vec) { + T::remove_from_peers_set(self, protocol, peers) + } + + fn sync_num_connected(&self) -> usize { + T::sync_num_connected(self) + } +} + +/// Provides access to network-level event stream. +pub trait NetworkEventStream { + /// Returns a stream containing the events that happen on the network. + /// + /// If this method is called multiple times, the events are duplicated. + /// + /// The stream never ends (unless the `NetworkWorker` gets shut down). + /// + /// The name passed is used to identify the channel in the Prometheus metrics. Note that the + /// parameter is a `&'static str`, and not a `String`, in order to avoid accidentally having + /// an unbounded set of Prometheus metrics, which would be quite bad in terms of memory + fn event_stream(&self, name: &'static str) -> Pin + Send>>; +} + +impl NetworkEventStream for Arc +where + T: ?Sized, + T: NetworkEventStream, +{ + fn event_stream(&self, name: &'static str) -> Pin + Send>> { + T::event_stream(self, name) + } +} + +/// Trait for providing information about the local network state +pub trait NetworkStateInfo { + /// Returns the local external addresses. + fn external_addresses(&self) -> Vec; + + /// Returns the local Peer ID. + fn local_peer_id(&self) -> PeerId; +} + +impl NetworkStateInfo for Arc +where + T: ?Sized, + T: NetworkStateInfo, +{ + fn external_addresses(&self) -> Vec { + T::external_addresses(self) + } + + fn local_peer_id(&self) -> PeerId { + T::local_peer_id(self) + } +} + +/// Reserved slot in the notifications buffer, ready to accept data. +pub trait NotificationSenderReady { + /// Consumes this slots reservation and actually queues the notification. + /// + /// NOTE: Traits can't consume itself, but calling this method second time will return an error. + fn send(&mut self, notification: Vec) -> Result<(), NotificationSenderError>; +} + +/// A `NotificationSender` allows for sending notifications to a peer with a chosen protocol. +#[async_trait::async_trait] +pub trait NotificationSender { + /// Returns a future that resolves when the `NotificationSender` is ready to send a + /// notification. + async fn ready(&self) + -> Result, NotificationSenderError>; +} + +/// Error returned by [`NetworkNotification::notification_sender`]. +#[derive(Debug, thiserror::Error)] +pub enum NotificationSenderError { + /// The notification receiver has been closed, usually because the underlying connection + /// closed. + /// + /// Some of the notifications most recently sent may not have been received. However, + /// the peer may still be connected and a new `NotificationSender` for the same + /// protocol obtained from [`NetworkNotification::notification_sender`]. + #[error("The notification receiver has been closed")] + Closed, + /// Protocol name hasn't been registered. + #[error("Protocol name hasn't been registered")] + BadProtocol, +} + +/// Provides ability to send network notifications. +pub trait NetworkNotification { + /// Appends a notification to the buffer of pending outgoing notifications with the given peer. + /// Has no effect if the notifications channel with this protocol name is not open. + /// + /// If the buffer of pending outgoing notifications with that peer is full, the notification + /// is silently dropped and the connection to the remote will start being shut down. This + /// happens if you call this method at a higher rate than the rate at which the peer processes + /// these notifications, or if the available network bandwidth is too low. + /// + /// For this reason, this method is considered soft-deprecated. You are encouraged to use + /// [`NetworkNotification::notification_sender`] instead. + /// + /// > **Note**: The reason why this is a no-op in the situation where we have no channel is + /// > that we don't guarantee message delivery anyway. Networking issues can cause + /// > connections to drop at any time, and higher-level logic shouldn't differentiate + /// > between the remote voluntarily closing a substream or a network error + /// > preventing the message from being delivered. + /// + /// The protocol must have been registered with + /// `crate::config::NetworkConfiguration::notifications_protocols`. + fn write_notification(&self, target: PeerId, protocol: Cow<'static, str>, message: Vec); + + /// Obtains a [`NotificationSender`] for a connected peer, if it exists. + /// + /// A `NotificationSender` is scoped to a particular connection to the peer that holds + /// a receiver. With a `NotificationSender` at hand, sending a notification is done in two + /// steps: + /// + /// 1. [`NotificationSender::ready`] is used to wait for the sender to become ready + /// for another notification, yielding a [`NotificationSenderReady`] token. + /// 2. [`NotificationSenderReady::send`] enqueues the notification for sending. This operation + /// can only fail if the underlying notification substream or connection has suddenly closed. + /// + /// An error is returned by [`NotificationSenderReady::send`] if there exists no open + /// notifications substream with that combination of peer and protocol, or if the remote + /// has asked to close the notifications substream. If that happens, it is guaranteed that an + /// [`Event::NotificationStreamClosed`] has been generated on the stream returned by + /// [`NetworkEventStream::event_stream`]. + /// + /// If the remote requests to close the notifications substream, all notifications successfully + /// enqueued using [`NotificationSenderReady::send`] will finish being sent out before the + /// substream actually gets closed, but attempting to enqueue more notifications will now + /// return an error. It is however possible for the entire connection to be abruptly closed, + /// in which case enqueued notifications will be lost. + /// + /// The protocol must have been registered with + /// `crate::config::NetworkConfiguration::notifications_protocols`. + /// + /// # Usage + /// + /// This method returns a struct that allows waiting until there is space available in the + /// buffer of messages towards the given peer. If the peer processes notifications at a slower + /// rate than we send them, this buffer will quickly fill up. + /// + /// As such, you should never do something like this: + /// + /// ```ignore + /// // Do NOT do this + /// for peer in peers { + /// if let Ok(n) = network.notification_sender(peer, ...) { + /// if let Ok(s) = n.ready().await { + /// let _ = s.send(...); + /// } + /// } + /// } + /// ``` + /// + /// Doing so would slow down all peers to the rate of the slowest one. A malicious or + /// malfunctioning peer could intentionally process notifications at a very slow rate. + /// + /// Instead, you are encouraged to maintain your own buffer of notifications on top of the one + /// maintained by `sc-network`, and use `notification_sender` to progressively send out + /// elements from your buffer. If this additional buffer is full (which will happen at some + /// point if the peer is too slow to process notifications), appropriate measures can be taken, + /// such as removing non-critical notifications from the buffer or disconnecting the peer + /// using [`NetworkPeers::disconnect_peer`]. + /// + /// + /// Notifications Per-peer buffer + /// broadcast +-------> of notifications +--> `notification_sender` +--> Internet + /// ^ (not covered by + /// | sc-network) + /// + + /// Notifications should be dropped + /// if buffer is full + /// + /// + /// See also the `sc-network-gossip` crate for a higher-level way to send notifications. + fn notification_sender( + &self, + target: PeerId, + protocol: Cow<'static, str>, + ) -> Result, NotificationSenderError>; +} + +impl NetworkNotification for Arc +where + T: ?Sized, + T: NetworkNotification, +{ + fn write_notification(&self, target: PeerId, protocol: Cow<'static, str>, message: Vec) { + T::write_notification(self, target, protocol, message) + } + + fn notification_sender( + &self, + target: PeerId, + protocol: Cow<'static, str>, + ) -> Result, NotificationSenderError> { + T::notification_sender(self, target, protocol) + } +} + +/// Provides ability to send network requests. +#[async_trait::async_trait] +pub trait NetworkRequest { + /// Sends a single targeted request to a specific peer. On success, returns the response of + /// the peer. + /// + /// Request-response protocols are a way to complement notifications protocols, but + /// notifications should remain the default ways of communicating information. For example, a + /// peer can announce something through a notification, after which the recipient can obtain + /// more information by performing a request. + /// As such, call this function with `IfDisconnected::ImmediateError` for `connect`. This way + /// you will get an error immediately for disconnected peers, instead of waiting for a + /// potentially very long connection attempt, which would suggest that something is wrong + /// anyway, as you are supposed to be connected because of the notification protocol. + /// + /// No limit or throttling of concurrent outbound requests per peer and protocol are enforced. + /// Such restrictions, if desired, need to be enforced at the call site(s). + /// + /// The protocol must have been registered through + /// `NetworkConfiguration::request_response_protocols`. + async fn request( + &self, + target: PeerId, + protocol: Cow<'static, str>, + request: Vec, + connect: IfDisconnected, + ) -> Result, RequestFailure>; + + /// Variation of `request` which starts a request whose response is delivered on a provided + /// channel. + /// + /// Instead of blocking and waiting for a reply, this function returns immediately, sending + /// responses via the passed in sender. This alternative API exists to make it easier to + /// integrate with message passing APIs. + /// + /// Keep in mind that the connected receiver might receive a `Canceled` event in case of a + /// closing connection. This is expected behaviour. With `request` you would get a + /// `RequestFailure::Network(OutboundFailure::ConnectionClosed)` in that case. + fn start_request( + &self, + target: PeerId, + protocol: Cow<'static, str>, + request: Vec, + tx: oneshot::Sender, RequestFailure>>, + connect: IfDisconnected, + ); +} + +// Manual implementation to avoid extra boxing here +impl NetworkRequest for Arc +where + T: ?Sized, + T: NetworkRequest, +{ + fn request<'life0, 'async_trait>( + &'life0 self, + target: PeerId, + protocol: Cow<'static, str>, + request: Vec, + connect: IfDisconnected, + ) -> Pin, RequestFailure>> + Send + 'async_trait>> + where + 'life0: 'async_trait, + Self: 'async_trait, + { + T::request(self, target, protocol, request, connect) + } + + fn start_request( + &self, + target: PeerId, + protocol: Cow<'static, str>, + request: Vec, + tx: oneshot::Sender, RequestFailure>>, + connect: IfDisconnected, + ) { + T::start_request(self, target, protocol, request, tx, connect) + } +} + +/// Provides ability to propagate transactions over the network. +pub trait NetworkTransaction { + /// You may call this when new transactions are imported by the transaction pool. + /// + /// All transactions will be fetched from the `TransactionPool` that was passed at + /// initialization as part of the configuration and propagated to peers. + fn trigger_repropagate(&self); + + /// You must call when new transaction is imported by the transaction pool. + /// + /// This transaction will be fetched from the `TransactionPool` that was passed at + /// initialization as part of the configuration and propagated to peers. + fn propagate_transaction(&self, hash: H); +} + +impl NetworkTransaction for Arc +where + T: ?Sized, + T: NetworkTransaction, +{ + fn trigger_repropagate(&self) { + T::trigger_repropagate(self) + } + + fn propagate_transaction(&self, hash: H) { + T::propagate_transaction(self, hash) + } +} + +/// Provides ability to announce blocks to the network. +pub trait NetworkBlock { + /// Make sure an important block is propagated to peers. + /// + /// In chain-based consensus, we often need to make sure non-best forks are + /// at least temporarily synced. This function forces such an announcement. + fn announce_block(&self, hash: BlockHash, data: Option>); + + /// Inform the network service about new best imported block. + fn new_best_block_imported(&self, hash: BlockHash, number: BlockNumber); +} + +impl NetworkBlock for Arc +where + T: ?Sized, + T: NetworkBlock, +{ + fn announce_block(&self, hash: BlockHash, data: Option>) { + T::announce_block(self, hash, data) + } + + fn new_best_block_imported(&self, hash: BlockHash, number: BlockNumber) { + T::new_best_block_imported(self, hash, number) + } +} diff --git a/client/network/src/service/signature.rs b/client/network/common/src/service/signature.rs similarity index 96% rename from client/network/src/service/signature.rs rename to client/network/common/src/service/signature.rs index d21d28a3007b5..602ef3d82979a 100644 --- a/client/network/src/service/signature.rs +++ b/client/network/common/src/service/signature.rs @@ -18,7 +18,10 @@ // // If you read this, you are very thorough, congratulations. -use super::*; +use libp2p::{ + identity::{error::SigningError, Keypair, PublicKey}, + PeerId, +}; /// A result of signing a message with a network identity. Since `PeerId` is potentially a hash of a /// `PublicKey`, you need to reveal the `PublicKey` next to the signature, so the verifier can check diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 515608df13d0f..4ff415788f4ea 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -21,7 +21,7 @@ use crate::{ discovery::{DiscoveryBehaviour, DiscoveryConfig, DiscoveryOut}, peer_info, protocol::{message::Roles, CustomMessageOutcome, NotificationsSink, Protocol}, - request_responses, DhtEvent, ObservedRole, + request_responses, }; use bytes::Bytes; @@ -41,7 +41,11 @@ use log::debug; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::import_queue::{IncomingBlock, Origin}; -use sc_network_common::{config::ProtocolId, request_responses::ProtocolConfig}; +use sc_network_common::{ + config::ProtocolId, + protocol::event::{DhtEvent, ObservedRole}, + request_responses::{IfDisconnected, ProtocolConfig, RequestFailure}, +}; use sc_peerset::PeersetHandle; use sp_blockchain::{HeaderBackend, HeaderMetadata}; use sp_consensus::BlockOrigin; @@ -57,9 +61,7 @@ use std::{ time::Duration, }; -pub use crate::request_responses::{ - IfDisconnected, InboundFailure, OutboundFailure, RequestFailure, RequestId, ResponseFailure, -}; +pub use crate::request_responses::{InboundFailure, OutboundFailure, RequestId, ResponseFailure}; /// General behaviour of the network. Combines all protocols together. #[derive(NetworkBehaviour)] diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 83bc1075b8bad..b1d70c28289bd 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -262,22 +262,26 @@ pub mod transactions; #[doc(inline)] pub use libp2p::{multiaddr, Multiaddr, PeerId}; -pub use protocol::{ - event::{DhtEvent, Event, ObservedRole}, - PeerInfo, -}; -pub use sc_network_common::sync::{ - warp::{WarpSyncPhase, WarpSyncProgress}, - StateDownloadProgress, SyncState, +pub use protocol::PeerInfo; +pub use sc_network_common::{ + protocol::event::{DhtEvent, Event, ObservedRole}, + request_responses::{IfDisconnected, RequestFailure}, + service::{ + KademliaKey, NetworkBlock, NetworkDHTProvider, NetworkRequest, NetworkSigner, + NetworkStateInfo, NetworkStatus, NetworkStatusProvider, NetworkSyncForkRequest, + NetworkTransaction, Signature, SigningError, + }, + sync::{ + warp::{WarpSyncPhase, WarpSyncProgress}, + StateDownloadProgress, SyncState, + }, }; pub use service::{ - DecodingError, IfDisconnected, KademliaKey, Keypair, NetworkService, NetworkWorker, - NotificationSender, NotificationSenderReady, OutboundFailure, PublicKey, RequestFailure, - Signature, SigningError, + DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, + NotificationSenderReady, OutboundFailure, PublicKey, }; pub use sc_peerset::ReputationChange; -use sp_runtime::traits::{Block as BlockT, NumberFor}; /// The maximum allowed number of established connections per peer. /// @@ -296,35 +300,3 @@ pub trait ExHashT: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync impl ExHashT for T where T: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static {} - -/// Trait for providing information about the local network state -pub trait NetworkStateInfo { - /// Returns the local external addresses. - fn external_addresses(&self) -> Vec; - - /// Returns the local Peer ID. - fn local_peer_id(&self) -> PeerId; -} - -/// Overview status of the network. -#[derive(Clone)] -pub struct NetworkStatus { - /// Current global sync state. - pub sync_state: SyncState, - /// Target sync block number. - pub best_seen_block: Option>, - /// Number of peers participating in syncing. - pub num_sync_peers: u32, - /// Total number of connected peers - pub num_connected_peers: usize, - /// Total number of active peers. - pub num_active_peers: usize, - /// The total number of bytes received. - pub total_bytes_inbound: u64, - /// The total number of bytes sent. - pub total_bytes_outbound: u64, - /// State sync in progress. - pub state_sync: Option, - /// Warp sync in progress. - pub warp_sync: Option>, -} diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index c51667017d15c..351e7d207ad1e 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -18,7 +18,6 @@ use crate::{ config, error, - request_responses::RequestFailure, utils::{interval, LruHashSet}, }; @@ -45,6 +44,7 @@ use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; use sc_consensus::import_queue::{BlockImportError, BlockImportStatus, IncomingBlock, Origin}; use sc_network_common::{ config::ProtocolId, + request_responses::RequestFailure, sync::{ message::{ BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, BlockState, @@ -76,7 +76,6 @@ use std::{ mod notifications; -pub mod event; pub mod message; pub use notifications::{NotificationsSink, NotifsHandlerError, Ready}; diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 0d8c6c33b1c95..9eab85a4c1ce1 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -50,7 +50,9 @@ use libp2p::{ NetworkBehaviourAction, PollParameters, }, }; -use sc_network_common::request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}; +use sc_network_common::request_responses::{ + IfDisconnected, IncomingRequest, OutgoingResponse, ProtocolConfig, RequestFailure, +}; use std::{ borrow::Cow, collections::{hash_map::Entry, HashMap}, @@ -118,26 +120,6 @@ impl From<(Cow<'static, str>, RequestId)> for ProtocolRequestId { } } -/// When sending a request, what to do on a disconnected recipient. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum IfDisconnected { - /// Try to connect to the peer. - TryConnect, - /// Just fail if the destination is not yet connected. - ImmediateError, -} - -/// Convenience functions for `IfDisconnected`. -impl IfDisconnected { - /// Shall we connect to a disconnected peer? - pub fn should_connect(self) -> bool { - match self { - Self::TryConnect => true, - Self::ImmediateError => false, - } - } -} - /// Implementation of `NetworkBehaviour` that provides support for request-response protocols. pub struct RequestResponsesBehaviour { /// The multiple sub-protocols, by name. @@ -787,23 +769,6 @@ pub enum RegisterError { DuplicateProtocol(Cow<'static, str>), } -/// Error in a request. -#[derive(Debug, thiserror::Error)] -#[allow(missing_docs)] -pub enum RequestFailure { - #[error("We are not currently connected to the requested peer.")] - NotConnected, - #[error("Given protocol hasn't been registered.")] - UnknownProtocol, - #[error("Remote has closed the substream before answering, thereby signaling that it considers the request as valid, but refused to answer it.")] - Refused, - #[error("The remote replied, but the local node is no longer interested in the response.")] - Obsolete, - /// Problem on the network. - #[error("Problem on the network: {0}")] - Network(OutboundFailure), -} - /// Error when processing a request sent by a remote. #[derive(Debug, thiserror::Error)] pub enum ResponseFailure { diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 1210b0ca64224..bf15a9250d82c 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -37,16 +37,17 @@ use crate::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, protocol::{ - self, event::Event, message::generic::Roles, NotificationsSink, NotifsHandlerError, - PeerInfo, Protocol, Ready, + self, message::generic::Roles, NotificationsSink, NotifsHandlerError, PeerInfo, Protocol, + Ready, }, - transactions, transport, DhtEvent, ExHashT, NetworkStateInfo, NetworkStatus, ReputationChange, + transactions, transport, ExHashT, ReputationChange, }; use codec::Encode as _; use futures::{channel::oneshot, prelude::*}; use libp2p::{ core::{either::EitherError, upgrade, ConnectedPoint, Executor}, + kad::record::Key as KademliaKey, multiaddr, ping::Failure as PingFailure, swarm::{ @@ -60,7 +61,17 @@ use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; -use sc_network_common::sync::{SyncState, SyncStatus}; +use sc_network_common::{ + protocol::event::{DhtEvent, Event}, + request_responses::{IfDisconnected, RequestFailure}, + service::{ + NetworkDHTProvider, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkSigner, + NetworkStateInfo, NetworkStatus, NetworkStatusProvider, NetworkSyncForkRequest, + NotificationSender as NotificationSenderT, NotificationSenderError, + NotificationSenderReady as NotificationSenderReadyT, Signature, SigningError, + }, + sync::{SyncState, SyncStatus}, +}; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::{HeaderBackend, HeaderMetadata}; @@ -81,24 +92,15 @@ use std::{ task::Poll, }; -pub use behaviour::{ - IfDisconnected, InboundFailure, OutboundFailure, RequestFailure, ResponseFailure, -}; +pub use behaviour::{InboundFailure, OutboundFailure, ResponseFailure}; mod metrics; mod out_events; -mod signature; #[cfg(test)] mod tests; -pub use libp2p::{ - identity::{ - error::{DecodingError, SigningError}, - Keypair, PublicKey, - }, - kad::record::Key as KademliaKey, -}; -pub use signature::Signature; +pub use libp2p::identity::{error::DecodingError, Keypair, PublicKey}; +use sc_network_common::service::{NetworkBlock, NetworkRequest, NetworkTransaction}; /// Substrate network service. Handles network IO and manages connectivity. pub struct NetworkService { @@ -723,289 +725,6 @@ where } impl NetworkService { - /// Returns the local `PeerId`. - pub fn local_peer_id(&self) -> &PeerId { - &self.local_peer_id - } - - /// Signs the message with the `KeyPair` that defined the local `PeerId`. - pub fn sign_with_local_identity( - &self, - msg: impl AsRef<[u8]>, - ) -> Result { - Signature::sign_message(msg.as_ref(), &self.local_identity) - } - - /// Set authorized peers. - /// - /// Need a better solution to manage authorized peers, but now just use reserved peers for - /// prototyping. - pub fn set_authorized_peers(&self, peers: HashSet) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::SetReserved(peers)); - } - - /// Set authorized_only flag. - /// - /// Need a better solution to decide authorized_only, but now just use reserved_only flag for - /// prototyping. - pub fn set_authorized_only(&self, reserved_only: bool) { - let _ = self - .to_worker - .unbounded_send(ServiceToWorkerMsg::SetReservedOnly(reserved_only)); - } - - /// Adds an address known to a node. - pub fn add_known_address(&self, peer_id: PeerId, addr: Multiaddr) { - let _ = self - .to_worker - .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id, addr)); - } - - /// Appends a notification to the buffer of pending outgoing notifications with the given peer. - /// Has no effect if the notifications channel with this protocol name is not open. - /// - /// If the buffer of pending outgoing notifications with that peer is full, the notification - /// is silently dropped and the connection to the remote will start being shut down. This - /// happens if you call this method at a higher rate than the rate at which the peer processes - /// these notifications, or if the available network bandwidth is too low. - /// - /// For this reason, this method is considered soft-deprecated. You are encouraged to use - /// [`NetworkService::notification_sender`] instead. - /// - /// > **Note**: The reason why this is a no-op in the situation where we have no channel is - /// > that we don't guarantee message delivery anyway. Networking issues can cause - /// > connections to drop at any time, and higher-level logic shouldn't differentiate - /// > between the remote voluntarily closing a substream or a network error - /// > preventing the message from being delivered. - /// - /// The protocol must have been registered with - /// `crate::config::NetworkConfiguration::notifications_protocols`. - pub fn write_notification( - &self, - target: PeerId, - protocol: Cow<'static, str>, - message: Vec, - ) { - // We clone the `NotificationsSink` in order to be able to unlock the network-wide - // `peers_notifications_sinks` mutex as soon as possible. - let sink = { - let peers_notifications_sinks = self.peers_notifications_sinks.lock(); - if let Some(sink) = peers_notifications_sinks.get(&(target, protocol.clone())) { - sink.clone() - } else { - // Notification silently discarded, as documented. - debug!( - target: "sub-libp2p", - "Attempted to send notification on missing or closed substream: {}, {:?}", - target, protocol, - ); - return - } - }; - - if let Some(notifications_sizes_metric) = self.notifications_sizes_metric.as_ref() { - notifications_sizes_metric - .with_label_values(&["out", &protocol]) - .observe(message.len() as f64); - } - - // Sending is communicated to the `NotificationsSink`. - trace!( - target: "sub-libp2p", - "External API => Notification({:?}, {:?}, {} bytes)", - target, protocol, message.len() - ); - trace!(target: "sub-libp2p", "Handler({:?}) <= Sync notification", target); - sink.send_sync_notification(message); - } - - /// Obtains a [`NotificationSender`] for a connected peer, if it exists. - /// - /// A `NotificationSender` is scoped to a particular connection to the peer that holds - /// a receiver. With a `NotificationSender` at hand, sending a notification is done in two - /// steps: - /// - /// 1. [`NotificationSender::ready`] is used to wait for the sender to become ready - /// for another notification, yielding a [`NotificationSenderReady`] token. - /// 2. [`NotificationSenderReady::send`] enqueues the notification for sending. This operation - /// can only fail if the underlying notification substream or connection has suddenly closed. - /// - /// An error is returned by [`NotificationSenderReady::send`] if there exists no open - /// notifications substream with that combination of peer and protocol, or if the remote - /// has asked to close the notifications substream. If that happens, it is guaranteed that an - /// [`Event::NotificationStreamClosed`] has been generated on the stream returned by - /// [`NetworkService::event_stream`]. - /// - /// If the remote requests to close the notifications substream, all notifications successfully - /// enqueued using [`NotificationSenderReady::send`] will finish being sent out before the - /// substream actually gets closed, but attempting to enqueue more notifications will now - /// return an error. It is however possible for the entire connection to be abruptly closed, - /// in which case enqueued notifications will be lost. - /// - /// The protocol must have been registered with - /// `crate::config::NetworkConfiguration::notifications_protocols`. - /// - /// # Usage - /// - /// This method returns a struct that allows waiting until there is space available in the - /// buffer of messages towards the given peer. If the peer processes notifications at a slower - /// rate than we send them, this buffer will quickly fill up. - /// - /// As such, you should never do something like this: - /// - /// ```ignore - /// // Do NOT do this - /// for peer in peers { - /// if let Ok(n) = network.notification_sender(peer, ...) { - /// if let Ok(s) = n.ready().await { - /// let _ = s.send(...); - /// } - /// } - /// } - /// ``` - /// - /// Doing so would slow down all peers to the rate of the slowest one. A malicious or - /// malfunctioning peer could intentionally process notifications at a very slow rate. - /// - /// Instead, you are encouraged to maintain your own buffer of notifications on top of the one - /// maintained by `sc-network`, and use `notification_sender` to progressively send out - /// elements from your buffer. If this additional buffer is full (which will happen at some - /// point if the peer is too slow to process notifications), appropriate measures can be taken, - /// such as removing non-critical notifications from the buffer or disconnecting the peer - /// using [`NetworkService::disconnect_peer`]. - /// - /// - /// Notifications Per-peer buffer - /// broadcast +-------> of notifications +--> `notification_sender` +--> Internet - /// ^ (not covered by - /// | sc-network) - /// + - /// Notifications should be dropped - /// if buffer is full - /// - /// - /// See also the `sc-network-gossip` crate for a higher-level way to send notifications. - pub fn notification_sender( - &self, - target: PeerId, - protocol: Cow<'static, str>, - ) -> Result { - // We clone the `NotificationsSink` in order to be able to unlock the network-wide - // `peers_notifications_sinks` mutex as soon as possible. - let sink = { - let peers_notifications_sinks = self.peers_notifications_sinks.lock(); - if let Some(sink) = peers_notifications_sinks.get(&(target, protocol.clone())) { - sink.clone() - } else { - return Err(NotificationSenderError::Closed) - } - }; - - let notification_size_metric = self - .notifications_sizes_metric - .as_ref() - .map(|histogram| histogram.with_label_values(&["out", &protocol])); - - Ok(NotificationSender { sink, protocol_name: protocol, notification_size_metric }) - } - - /// Returns a stream containing the events that happen on the network. - /// - /// If this method is called multiple times, the events are duplicated. - /// - /// The stream never ends (unless the `NetworkWorker` gets shut down). - /// - /// The name passed is used to identify the channel in the Prometheus metrics. Note that the - /// parameter is a `&'static str`, and not a `String`, in order to avoid accidentally having - /// an unbounded set of Prometheus metrics, which would be quite bad in terms of memory - pub fn event_stream(&self, name: &'static str) -> impl Stream { - let (tx, rx) = out_events::channel(name); - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::EventStream(tx)); - rx - } - - /// Sends a single targeted request to a specific peer. On success, returns the response of - /// the peer. - /// - /// Request-response protocols are a way to complement notifications protocols, but - /// notifications should remain the default ways of communicating information. For example, a - /// peer can announce something through a notification, after which the recipient can obtain - /// more information by performing a request. - /// As such, call this function with `IfDisconnected::ImmediateError` for `connect`. This way - /// you will get an error immediately for disconnected peers, instead of waiting for a - /// potentially very long connection attempt, which would suggest that something is wrong - /// anyway, as you are supposed to be connected because of the notification protocol. - /// - /// No limit or throttling of concurrent outbound requests per peer and protocol are enforced. - /// Such restrictions, if desired, need to be enforced at the call site(s). - /// - /// The protocol must have been registered through - /// [`NetworkConfiguration::request_response_protocols`]( - /// crate::config::NetworkConfiguration::request_response_protocols). - pub async fn request( - &self, - target: PeerId, - protocol: impl Into>, - request: Vec, - connect: IfDisconnected, - ) -> Result, RequestFailure> { - let (tx, rx) = oneshot::channel(); - - self.start_request(target, protocol, request, tx, connect); - - match rx.await { - Ok(v) => v, - // The channel can only be closed if the network worker no longer exists. If the - // network worker no longer exists, then all connections to `target` are necessarily - // closed, and we legitimately report this situation as a "ConnectionClosed". - Err(_) => Err(RequestFailure::Network(OutboundFailure::ConnectionClosed)), - } - } - - /// Variation of `request` which starts a request whose response is delivered on a provided - /// channel. - /// - /// Instead of blocking and waiting for a reply, this function returns immediately, sending - /// responses via the passed in sender. This alternative API exists to make it easier to - /// integrate with message passing APIs. - /// - /// Keep in mind that the connected receiver might receive a `Canceled` event in case of a - /// closing connection. This is expected behaviour. With `request` you would get a - /// `RequestFailure::Network(OutboundFailure::ConnectionClosed)` in that case. - pub fn start_request( - &self, - target: PeerId, - protocol: impl Into>, - request: Vec, - tx: oneshot::Sender, RequestFailure>>, - connect: IfDisconnected, - ) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::Request { - target, - protocol: protocol.into(), - request, - pending_response: tx, - connect, - }); - } - - /// High-level network status information. - /// - /// Returns an error if the `NetworkWorker` is no longer running. - pub async fn status(&self) -> Result, ()> { - let (tx, rx) = oneshot::channel(); - - let _ = self - .to_worker - .unbounded_send(ServiceToWorkerMsg::NetworkStatus { pending_response: tx }); - - match rx.await { - Ok(v) => v.map_err(|_| ()), - // The channel can only be closed if the network worker no longer exists. - Err(_) => Err(()), - } - } - /// Get network state. /// /// **Note**: Use this only for debugging. This API is unstable. There are warnings literally @@ -1026,74 +745,97 @@ impl NetworkService { } } - /// You may call this when new transactions are imported by the transaction pool. - /// - /// All transactions will be fetched from the `TransactionPool` that was passed at - /// initialization as part of the configuration and propagated to peers. - pub fn trigger_repropagate(&self) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::PropagateTransactions); - } - - /// You must call when new transaction is imported by the transaction pool. + /// Utility function to extract `PeerId` from each `Multiaddr` for peer set updates. /// - /// This transaction will be fetched from the `TransactionPool` that was passed at - /// initialization as part of the configuration and propagated to peers. - pub fn propagate_transaction(&self, hash: H) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::PropagateTransaction(hash)); - } + /// Returns an `Err` if one of the given addresses is invalid or contains an + /// invalid peer ID (which includes the local peer ID). + fn split_multiaddr_and_peer_id( + &self, + peers: HashSet, + ) -> Result, String> { + peers + .into_iter() + .map(|mut addr| { + let peer = match addr.pop() { + Some(multiaddr::Protocol::P2p(key)) => PeerId::from_multihash(key) + .map_err(|_| "Invalid PeerId format".to_string())?, + _ => return Err("Missing PeerId from address".to_string()), + }; - /// Make sure an important block is propagated to peers. - /// - /// In chain-based consensus, we often need to make sure non-best forks are - /// at least temporarily synced. This function forces such an announcement. - pub fn announce_block(&self, hash: B::Hash, data: Option>) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::AnnounceBlock(hash, data)); + // Make sure the local peer ID is never added to the PSM + // or added as a "known address", even if given. + if peer == self.local_peer_id { + Err("Local peer ID in peer set.".to_string()) + } else { + Ok((peer, addr)) + } + }) + .collect::, String>>() } +} - /// Report a given peer as either beneficial (+) or costly (-) according to the - /// given scalar. - pub fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { - self.peerset.report_peer(who, cost_benefit); +impl sp_consensus::SyncOracle for NetworkService { + fn is_major_syncing(&self) -> bool { + self.is_major_syncing.load(Ordering::Relaxed) } - /// Disconnect from a node as soon as possible. - /// - /// This triggers the same effects as if the connection had closed itself spontaneously. - /// - /// See also [`NetworkService::remove_from_peers_set`], which has the same effect but also - /// prevents the local node from re-establishing an outgoing substream to this peer until it - /// is added again. - pub fn disconnect_peer(&self, who: PeerId, protocol: impl Into>) { - let _ = self - .to_worker - .unbounded_send(ServiceToWorkerMsg::DisconnectPeer(who, protocol.into())); + fn is_offline(&self) -> bool { + self.num_connected.load(Ordering::Relaxed) == 0 } +} +impl sc_consensus::JustificationSyncLink for NetworkService { /// Request a justification for the given block from the network. /// /// On success, the justification will be passed to the import queue that was part at /// initialization as part of the configuration. - pub fn request_justification(&self, hash: &B::Hash, number: NumberFor) { + fn request_justification(&self, hash: &B::Hash, number: NumberFor) { let _ = self .to_worker .unbounded_send(ServiceToWorkerMsg::RequestJustification(*hash, number)); } - /// Clear all pending justification requests. - pub fn clear_justification_requests(&self) { + fn clear_justification_requests(&self) { let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::ClearJustificationRequests); } +} - /// Are we in the process of downloading the chain? - pub fn is_major_syncing(&self) -> bool { - self.is_major_syncing.load(Ordering::Relaxed) +impl NetworkStateInfo for NetworkService +where + B: sp_runtime::traits::Block, + H: ExHashT, +{ + /// Returns the local external addresses. + fn external_addresses(&self) -> Vec { + self.external_addresses.lock().clone() + } + + /// Returns the local Peer ID. + fn local_peer_id(&self) -> PeerId { + self.local_peer_id } +} +impl NetworkSigner for NetworkService +where + B: sp_runtime::traits::Block, + H: ExHashT, +{ + fn sign_with_local_identity(&self, msg: impl AsRef<[u8]>) -> Result { + Signature::sign_message(msg.as_ref(), &self.local_identity) + } +} + +impl NetworkDHTProvider for NetworkService +where + B: BlockT + 'static, + H: ExHashT, +{ /// Start getting a value from the DHT. /// /// This will generate either a `ValueFound` or a `ValueNotFound` event and pass it as an /// item on the [`NetworkWorker`] stream. - pub fn get_value(&self, key: &KademliaKey) { + fn get_value(&self, key: &KademliaKey) { let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::GetValue(key.clone())); } @@ -1101,27 +843,86 @@ impl NetworkService { /// /// This will generate either a `ValuePut` or a `ValuePutFailed` event and pass it as an /// item on the [`NetworkWorker`] stream. - pub fn put_value(&self, key: KademliaKey, value: Vec) { + fn put_value(&self, key: KademliaKey, value: Vec) { let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::PutValue(key, value)); } +} + +impl NetworkSyncForkRequest> for NetworkService +where + B: BlockT + 'static, + H: ExHashT, +{ + /// Configure an explicit fork sync request. + /// Note that this function should not be used for recent blocks. + /// Sync should be able to download all the recent forks normally. + /// `set_sync_fork_request` should only be used if external code detects that there's + /// a stale fork missing. + /// Passing empty `peers` set effectively removes the sync request. + fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor) { + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::SyncFork(peers, hash, number)); + } +} - /// Connect to unreserved peers and allow unreserved peers to connect for syncing purposes. - pub fn accept_unreserved_peers(&self) { +#[async_trait::async_trait] +impl NetworkStatusProvider for NetworkService +where + B: BlockT + 'static, + H: ExHashT, +{ + async fn status(&self) -> Result, ()> { + let (tx, rx) = oneshot::channel(); + + let _ = self + .to_worker + .unbounded_send(ServiceToWorkerMsg::NetworkStatus { pending_response: tx }); + + match rx.await { + Ok(v) => v.map_err(|_| ()), + // The channel can only be closed if the network worker no longer exists. + Err(_) => Err(()), + } + } +} + +impl NetworkPeers for NetworkService +where + B: BlockT + 'static, + H: ExHashT, +{ + fn set_authorized_peers(&self, peers: HashSet) { + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::SetReserved(peers)); + } + + fn set_authorized_only(&self, reserved_only: bool) { + let _ = self + .to_worker + .unbounded_send(ServiceToWorkerMsg::SetReservedOnly(reserved_only)); + } + + fn add_known_address(&self, peer_id: PeerId, addr: Multiaddr) { + let _ = self + .to_worker + .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id, addr)); + } + + fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { + self.peerset.report_peer(who, cost_benefit); + } + + fn disconnect_peer(&self, who: PeerId, protocol: Cow<'static, str>) { + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::DisconnectPeer(who, protocol)); + } + + fn accept_unreserved_peers(&self) { let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::SetReservedOnly(false)); } - /// Disconnect from unreserved peers and deny new unreserved peers to connect for syncing - /// purposes. - pub fn deny_unreserved_peers(&self) { + fn deny_unreserved_peers(&self) { let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::SetReservedOnly(true)); } - /// Adds a `PeerId` and its address as reserved. The string should encode the address - /// and peer ID of the remote node. - /// - /// Returns an `Err` if the given string is not a valid multiaddress - /// or contains an invalid peer ID (which includes the local peer ID). - pub fn add_reserved_peer(&self, peer: String) -> Result<(), String> { + fn add_reserved_peer(&self, peer: String) -> Result<(), String> { let (peer_id, addr) = parse_str_addr(&peer).map_err(|e| format!("{:?}", e))?; // Make sure the local peer ID is never added to the PSM. if peer_id == self.local_peer_id { @@ -1135,28 +936,11 @@ impl NetworkService { Ok(()) } - /// Removes a `PeerId` from the list of reserved peers. - pub fn remove_reserved_peer(&self, peer_id: PeerId) { + fn remove_reserved_peer(&self, peer_id: PeerId) { let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::RemoveReserved(peer_id)); } - /// Sets the reserved set of a protocol to the given set of peers. - /// - /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also - /// consist of only `/p2p/`. - /// - /// The node will start establishing/accepting connections and substreams to/from peers in this - /// set, if it doesn't have any substream open with them yet. - /// - /// Note however, if a call to this function results in less peers on the reserved set, they - /// will not necessarily get disconnected (depending on available free slots in the peer set). - /// If you want to also disconnect those removed peers, you will have to call - /// `remove_from_peers_set` on those in addition to updating the reserved set. You can omit - /// this step if the peer set is in reserved only mode. - /// - /// Returns an `Err` if one of the given addresses is invalid or contains an - /// invalid peer ID (which includes the local peer ID). - pub fn set_reserved_peers( + fn set_reserved_peers( &self, protocol: Cow<'static, str>, peers: HashSet, @@ -1187,14 +971,7 @@ impl NetworkService { Ok(()) } - /// Add peers to a peer set. - /// - /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also - /// consist of only `/p2p/`. - /// - /// Returns an `Err` if one of the given addresses is invalid or contains an - /// invalid peer ID (which includes the local peer ID). - pub fn add_peers_to_reserved_set( + fn add_peers_to_reserved_set( &self, protocol: Cow<'static, str>, peers: HashSet, @@ -1220,8 +997,7 @@ impl NetworkService { Ok(()) } - /// Remove peers from a peer set. - pub fn remove_peers_from_reserved_set(&self, protocol: Cow<'static, str>, peers: Vec) { + fn remove_peers_from_reserved_set(&self, protocol: Cow<'static, str>, peers: Vec) { for peer_id in peers.into_iter() { let _ = self .to_worker @@ -1229,26 +1005,7 @@ impl NetworkService { } } - /// Configure an explicit fork sync request. - /// Note that this function should not be used for recent blocks. - /// Sync should be able to download all the recent forks normally. - /// `set_sync_fork_request` should only be used if external code detects that there's - /// a stale fork missing. - /// Passing empty `peers` set effectively removes the sync request. - pub fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::SyncFork(peers, hash, number)); - } - - /// Add a peer to a set of peers. - /// - /// If the set has slots available, it will try to open a substream with this peer. - /// - /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also - /// consist of only `/p2p/`. - /// - /// Returns an `Err` if one of the given addresses is invalid or contains an - /// invalid peer ID (which includes the local peer ID). - pub fn add_to_peers_set( + fn add_to_peers_set( &self, protocol: Cow<'static, str>, peers: HashSet, @@ -1274,10 +1031,7 @@ impl NetworkService { Ok(()) } - /// Remove peers from a peer set. - /// - /// If we currently have an open substream with this peer, it will soon be closed. - pub fn remove_from_peers_set(&self, protocol: Cow<'static, str>, peers: Vec) { + fn remove_from_peers_set(&self, protocol: Cow<'static, str>, peers: Vec) { for peer_id in peers.into_iter() { let _ = self .to_worker @@ -1285,90 +1039,158 @@ impl NetworkService { } } - /// Returns the number of peers we're connected to. - pub fn num_connected(&self) -> usize { + fn sync_num_connected(&self) -> usize { self.num_connected.load(Ordering::Relaxed) } +} - /// Inform the network service about new best imported block. - pub fn new_best_block_imported(&self, hash: B::Hash, number: NumberFor) { - let _ = self - .to_worker - .unbounded_send(ServiceToWorkerMsg::NewBestBlockImported(hash, number)); +impl NetworkEventStream for NetworkService +where + B: BlockT + 'static, + H: ExHashT, +{ + fn event_stream(&self, name: &'static str) -> Pin + Send>> { + let (tx, rx) = out_events::channel(name); + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::EventStream(tx)); + Box::pin(rx) } +} - /// Utility function to extract `PeerId` from each `Multiaddr` for peer set updates. - /// - /// Returns an `Err` if one of the given addresses is invalid or contains an - /// invalid peer ID (which includes the local peer ID). - fn split_multiaddr_and_peer_id( - &self, - peers: HashSet, - ) -> Result, String> { - peers - .into_iter() - .map(|mut addr| { - let peer = match addr.pop() { - Some(multiaddr::Protocol::P2p(key)) => PeerId::from_multihash(key) - .map_err(|_| "Invalid PeerId format".to_string())?, - _ => return Err("Missing PeerId from address".to_string()), - }; +impl NetworkNotification for NetworkService +where + B: BlockT + 'static, + H: ExHashT, +{ + fn write_notification(&self, target: PeerId, protocol: Cow<'static, str>, message: Vec) { + // We clone the `NotificationsSink` in order to be able to unlock the network-wide + // `peers_notifications_sinks` mutex as soon as possible. + let sink = { + let peers_notifications_sinks = self.peers_notifications_sinks.lock(); + if let Some(sink) = peers_notifications_sinks.get(&(target, protocol.clone())) { + sink.clone() + } else { + // Notification silently discarded, as documented. + debug!( + target: "sub-libp2p", + "Attempted to send notification on missing or closed substream: {}, {:?}", + target, protocol, + ); + return + } + }; - // Make sure the local peer ID is never added to the PSM - // or added as a "known address", even if given. - if peer == self.local_peer_id { - Err("Local peer ID in peer set.".to_string()) - } else { - Ok((peer, addr)) - } - }) - .collect::, String>>() - } -} + if let Some(notifications_sizes_metric) = self.notifications_sizes_metric.as_ref() { + notifications_sizes_metric + .with_label_values(&["out", &protocol]) + .observe(message.len() as f64); + } -impl sp_consensus::SyncOracle for NetworkService { - fn is_major_syncing(&mut self) -> bool { - Self::is_major_syncing(self) + // Sending is communicated to the `NotificationsSink`. + trace!( + target: "sub-libp2p", + "External API => Notification({:?}, {:?}, {} bytes)", + target, protocol, message.len() + ); + trace!(target: "sub-libp2p", "Handler({:?}) <= Sync notification", target); + sink.send_sync_notification(message); } - fn is_offline(&mut self) -> bool { - self.num_connected.load(Ordering::Relaxed) == 0 + fn notification_sender( + &self, + target: PeerId, + protocol: Cow<'static, str>, + ) -> Result, NotificationSenderError> { + // We clone the `NotificationsSink` in order to be able to unlock the network-wide + // `peers_notifications_sinks` mutex as soon as possible. + let sink = { + let peers_notifications_sinks = self.peers_notifications_sinks.lock(); + if let Some(sink) = peers_notifications_sinks.get(&(target, protocol.clone())) { + sink.clone() + } else { + return Err(NotificationSenderError::Closed) + } + }; + + let notification_size_metric = self + .notifications_sizes_metric + .as_ref() + .map(|histogram| histogram.with_label_values(&["out", &protocol])); + + Ok(Box::new(NotificationSender { sink, protocol_name: protocol, notification_size_metric })) } } -impl<'a, B: BlockT + 'static, H: ExHashT> sp_consensus::SyncOracle for &'a NetworkService { - fn is_major_syncing(&mut self) -> bool { - NetworkService::is_major_syncing(self) +#[async_trait::async_trait] +impl NetworkRequest for NetworkService +where + B: BlockT + 'static, + H: ExHashT, +{ + async fn request( + &self, + target: PeerId, + protocol: Cow<'static, str>, + request: Vec, + connect: IfDisconnected, + ) -> Result, RequestFailure> { + let (tx, rx) = oneshot::channel(); + + self.start_request(target, protocol, request, tx, connect); + + match rx.await { + Ok(v) => v, + // The channel can only be closed if the network worker no longer exists. If the + // network worker no longer exists, then all connections to `target` are necessarily + // closed, and we legitimately report this situation as a "ConnectionClosed". + Err(_) => Err(RequestFailure::Network(OutboundFailure::ConnectionClosed)), + } } - fn is_offline(&mut self) -> bool { - self.num_connected.load(Ordering::Relaxed) == 0 + fn start_request( + &self, + target: PeerId, + protocol: Cow<'static, str>, + request: Vec, + tx: oneshot::Sender, RequestFailure>>, + connect: IfDisconnected, + ) { + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::Request { + target, + protocol: protocol.into(), + request, + pending_response: tx, + connect, + }); } } -impl sc_consensus::JustificationSyncLink for NetworkService { - fn request_justification(&self, hash: &B::Hash, number: NumberFor) { - Self::request_justification(self, hash, number); +impl NetworkTransaction for NetworkService +where + B: BlockT + 'static, + H: ExHashT, +{ + fn trigger_repropagate(&self) { + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::PropagateTransactions); } - fn clear_justification_requests(&self) { - Self::clear_justification_requests(self); + fn propagate_transaction(&self, hash: H) { + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::PropagateTransaction(hash)); } } -impl NetworkStateInfo for NetworkService +impl NetworkBlock> for NetworkService where - B: sp_runtime::traits::Block, + B: BlockT + 'static, H: ExHashT, { - /// Returns the local external addresses. - fn external_addresses(&self) -> Vec { - self.external_addresses.lock().clone() + fn announce_block(&self, hash: B::Hash, data: Option>) { + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::AnnounceBlock(hash, data)); } - /// Returns the local Peer ID. - fn local_peer_id(&self) -> PeerId { - self.local_peer_id + fn new_best_block_imported(&self, hash: B::Hash, number: NumberFor) { + let _ = self + .to_worker + .unbounded_send(ServiceToWorkerMsg::NewBestBlockImported(hash, number)); } } @@ -1385,26 +1207,27 @@ pub struct NotificationSender { notification_size_metric: Option, } -impl NotificationSender { - /// Returns a future that resolves when the `NotificationSender` is ready to send a - /// notification. - pub async fn ready(&self) -> Result, NotificationSenderError> { - Ok(NotificationSenderReady { +#[async_trait::async_trait] +impl NotificationSenderT for NotificationSender { + async fn ready( + &self, + ) -> Result, NotificationSenderError> { + Ok(Box::new(NotificationSenderReady { ready: match self.sink.reserve_notification().await { - Ok(r) => r, + Ok(r) => Some(r), Err(()) => return Err(NotificationSenderError::Closed), }, peer_id: self.sink.peer_id(), protocol_name: &self.protocol_name, notification_size_metric: self.notification_size_metric.clone(), - }) + })) } } /// Reserved slot in the notifications buffer, ready to accept data. #[must_use] pub struct NotificationSenderReady<'a> { - ready: Ready<'a>, + ready: Option>, /// Target of the notification. peer_id: &'a PeerId, @@ -1417,11 +1240,8 @@ pub struct NotificationSenderReady<'a> { notification_size_metric: Option, } -impl<'a> NotificationSenderReady<'a> { - /// Consumes this slots reservation and actually queues the notification. - pub fn send(self, notification: impl Into>) -> Result<(), NotificationSenderError> { - let notification = notification.into(); - +impl<'a> NotificationSenderReadyT for NotificationSenderReady<'a> { + fn send(&mut self, notification: Vec) -> Result<(), NotificationSenderError> { if let Some(notification_size_metric) = &self.notification_size_metric { notification_size_metric.observe(notification.len() as f64); } @@ -1433,26 +1253,14 @@ impl<'a> NotificationSenderReady<'a> { ); trace!(target: "sub-libp2p", "Handler({:?}) <= Async notification", self.peer_id); - self.ready.send(notification).map_err(|()| NotificationSenderError::Closed) + self.ready + .take() + .ok_or(NotificationSenderError::Closed)? + .send(notification) + .map_err(|()| NotificationSenderError::Closed) } } -/// Error returned by [`NetworkService::send_notification`]. -#[derive(Debug, thiserror::Error)] -pub enum NotificationSenderError { - /// The notification receiver has been closed, usually because the underlying connection - /// closed. - /// - /// Some of the notifications most recently sent may not have been received. However, - /// the peer may still be connected and a new `NotificationSender` for the same - /// protocol obtained from [`NetworkService::notification_sender`]. - #[error("The notification receiver has been closed")] - Closed, - /// Protocol name hasn't been registered. - #[error("Protocol name hasn't been registered")] - BadProtocol, -} - /// Messages sent from the `NetworkService` to the `NetworkWorker`. /// /// Each entry corresponds to a method of `NetworkService`. diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index c95b46af4cefa..4144d7f19551e 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -31,11 +31,10 @@ //! - Send events by calling [`OutChannels::send`]. Events are cloned for each sender in the //! collection. -use crate::Event; - use futures::{channel::mpsc, prelude::*, ready, stream::FusedStream}; use parking_lot::Mutex; use prometheus_endpoint::{register, CounterVec, GaugeVec, Opts, PrometheusError, Registry, U64}; +use sc_network_common::protocol::event::Event; use std::{ cell::RefCell, fmt, diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index f757bf4891fbc..6ccca17650b67 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -16,11 +16,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{config, Event, NetworkService, NetworkWorker}; +use crate::{config, NetworkService, NetworkWorker}; use futures::prelude::*; use libp2p::PeerId; -use sc_network_common::config::ProtocolId; +use sc_network_common::{ + config::ProtocolId, + protocol::event::Event, + service::{NetworkEventStream, NetworkNotification, NetworkPeers, NetworkStateInfo}, +}; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler, @@ -192,7 +196,7 @@ fn build_nodes_one_proto() -> ( set_config: config::SetConfig { reserved_nodes: vec![config::MultiaddrWithPeerId { multiaddr: listen_addr, - peer_id: node1.local_peer_id().clone(), + peer_id: node1.local_peer_id(), }], ..Default::default() }, @@ -214,18 +218,10 @@ fn notifications_state_consistent() { // Write some initial notifications that shouldn't get through. for _ in 0..(rand::random::() % 5) { - node1.write_notification( - node2.local_peer_id().clone(), - PROTOCOL_NAME, - b"hello world".to_vec(), - ); + node1.write_notification(node2.local_peer_id(), PROTOCOL_NAME, b"hello world".to_vec()); } for _ in 0..(rand::random::() % 5) { - node2.write_notification( - node1.local_peer_id().clone(), - PROTOCOL_NAME, - b"hello world".to_vec(), - ); + node2.write_notification(node1.local_peer_id(), PROTOCOL_NAME, b"hello world".to_vec()); } async_std::task::block_on(async move { @@ -249,14 +245,14 @@ fn notifications_state_consistent() { // test consists in ensuring that notifications get ignored if the stream isn't open. if rand::random::() % 5 >= 3 { node1.write_notification( - node2.local_peer_id().clone(), + node2.local_peer_id(), PROTOCOL_NAME, b"hello world".to_vec(), ); } if rand::random::() % 5 >= 3 { node2.write_notification( - node1.local_peer_id().clone(), + node1.local_peer_id(), PROTOCOL_NAME, b"hello world".to_vec(), ); @@ -264,10 +260,10 @@ fn notifications_state_consistent() { // Also randomly disconnect the two nodes from time to time. if rand::random::() % 20 == 0 { - node1.disconnect_peer(node2.local_peer_id().clone(), PROTOCOL_NAME); + node1.disconnect_peer(node2.local_peer_id(), PROTOCOL_NAME); } if rand::random::() % 20 == 0 { - node2.disconnect_peer(node1.local_peer_id().clone(), PROTOCOL_NAME); + node2.disconnect_peer(node1.local_peer_id(), PROTOCOL_NAME); } // Grab next event from either `events_stream1` or `events_stream2`. @@ -295,7 +291,7 @@ fn notifications_state_consistent() { something_happened = true; assert!(!node1_to_node2_open); node1_to_node2_open = true; - assert_eq!(remote, *node2.local_peer_id()); + assert_eq!(remote, node2.local_peer_id()); }, future::Either::Right(Event::NotificationStreamOpened { remote, protocol, .. @@ -304,7 +300,7 @@ fn notifications_state_consistent() { something_happened = true; assert!(!node2_to_node1_open); node2_to_node1_open = true; - assert_eq!(remote, *node1.local_peer_id()); + assert_eq!(remote, node1.local_peer_id()); }, future::Either::Left(Event::NotificationStreamClosed { remote, protocol, .. @@ -312,7 +308,7 @@ fn notifications_state_consistent() { if protocol == PROTOCOL_NAME { assert!(node1_to_node2_open); node1_to_node2_open = false; - assert_eq!(remote, *node2.local_peer_id()); + assert_eq!(remote, node2.local_peer_id()); }, future::Either::Right(Event::NotificationStreamClosed { remote, protocol, .. @@ -320,14 +316,14 @@ fn notifications_state_consistent() { if protocol == PROTOCOL_NAME { assert!(node2_to_node1_open); node2_to_node1_open = false; - assert_eq!(remote, *node1.local_peer_id()); + assert_eq!(remote, node1.local_peer_id()); }, future::Either::Left(Event::NotificationsReceived { remote, .. }) => { assert!(node1_to_node2_open); - assert_eq!(remote, *node2.local_peer_id()); + assert_eq!(remote, node2.local_peer_id()); if rand::random::() % 5 >= 4 { node1.write_notification( - node2.local_peer_id().clone(), + node2.local_peer_id(), PROTOCOL_NAME, b"hello world".to_vec(), ); @@ -335,10 +331,10 @@ fn notifications_state_consistent() { }, future::Either::Right(Event::NotificationsReceived { remote, .. }) => { assert!(node2_to_node1_open); - assert_eq!(remote, *node1.local_peer_id()); + assert_eq!(remote, node1.local_peer_id()); if rand::random::() % 5 >= 4 { node2.write_notification( - node1.local_peer_id().clone(), + node1.local_peer_id(), PROTOCOL_NAME, b"hello world".to_vec(), ); @@ -373,7 +369,7 @@ fn lots_of_incoming_peers_works() { ..config::NetworkConfiguration::new_local() }); - let main_node_peer_id = *main_node.local_peer_id(); + let main_node_peer_id = main_node.local_peer_id(); // We spawn background tasks and push them in this `Vec`. They will all be waited upon before // this test ends. @@ -476,8 +472,13 @@ fn notifications_back_pressure() { // Sending! for num in 0..TOTAL_NOTIFS { - let notif = node1.notification_sender(node2_id.clone(), PROTOCOL_NAME).unwrap(); - notif.ready().await.unwrap().send(format!("hello #{}", num)).unwrap(); + let notif = node1.notification_sender(node2_id, PROTOCOL_NAME).unwrap(); + notif + .ready() + .await + .unwrap() + .send(format!("hello #{}", num).into_bytes()) + .unwrap(); } receiver.await; @@ -514,7 +515,7 @@ fn fallback_name_working() { set_config: config::SetConfig { reserved_nodes: vec![config::MultiaddrWithPeerId { multiaddr: listen_addr, - peer_id: node1.local_peer_id().clone(), + peer_id: node1.local_peer_id(), }], ..Default::default() }, diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 342b6a0430272..f7e4d774ca812 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -32,7 +32,7 @@ use crate::{ protocol::message, service::NetworkService, utils::{interval, LruHashSet}, - Event, ExHashT, ObservedRole, + ExHashT, }; use codec::{Decode, Encode}; @@ -40,7 +40,11 @@ use futures::{channel::mpsc, prelude::*, stream::FuturesUnordered}; use libp2p::{multiaddr, PeerId}; use log::{debug, trace, warn}; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; -use sc_network_common::config::ProtocolId; +use sc_network_common::{ + config::ProtocolId, + protocol::event::{Event, ObservedRole}, + service::{NetworkEventStream, NetworkNotification, NetworkPeers}, +}; use sp_runtime::traits::Block as BlockT; use std::{ borrow::Cow, @@ -176,7 +180,7 @@ impl TransactionsHandlerPrototype { transaction_pool: Arc>, metrics_registry: Option<&Registry>, ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { - let event_stream = service.event_stream("transactions-handler").boxed(); + let event_stream = service.event_stream("transactions-handler"); let (to_handler, from_controller) = mpsc::unbounded(); let gossip_enabled = Arc::new(AtomicBool::new(false)); diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 09b4139c213a6..3ba663aba2267 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -45,7 +45,8 @@ use sc_client_api::{ }; use sc_consensus::{ BasicQueue, BlockCheckParams, BlockImport, BlockImportParams, BoxJustificationImport, - ForkChoiceStrategy, ImportResult, JustificationImport, LongestChain, Verifier, + ForkChoiceStrategy, ImportResult, JustificationImport, JustificationSyncLink, LongestChain, + Verifier, }; pub use sc_network::config::EmptyTransactionPool; use sc_network::{ @@ -56,8 +57,9 @@ use sc_network::{ Multiaddr, NetworkService, NetworkWorker, }; pub use sc_network_common::config::ProtocolId; -use sc_network_common::sync::warp::{ - AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider, +use sc_network_common::{ + service::{NetworkBlock, NetworkStateInfo, NetworkSyncForkRequest}, + sync::warp::{AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider}, }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ @@ -71,7 +73,7 @@ use sp_blockchain::{ }; use sp_consensus::{ block_validation::{BlockAnnounceValidator, DefaultBlockAnnounceValidator}, - BlockOrigin, Error as ConsensusError, + BlockOrigin, Error as ConsensusError, SyncOracle, }; use sp_core::H256; use sp_runtime::{ @@ -243,7 +245,7 @@ where { /// Get this peer ID. pub fn id(&self) -> PeerId { - *self.network.service().local_peer_id() + self.network.service().local_peer_id() } /// Returns true if we're major syncing. @@ -797,7 +799,7 @@ where let addrs = connect_to .iter() .map(|v| { - let peer_id = *self.peer(*v).network_service().local_peer_id(); + let peer_id = self.peer(*v).network_service().local_peer_id(); let multiaddr = self.peer(*v).listen_addr.clone(); MultiaddrWithPeerId { peer_id, multiaddr } }) @@ -893,7 +895,7 @@ where self.mut_peers(move |peers| { for peer in peers.iter_mut() { peer.network - .add_known_address(*network.service().local_peer_id(), listen_addr.clone()); + .add_known_address(network.service().local_peer_id(), listen_addr.clone()); } let imported_blocks_stream = Box::pin(client.import_notification_stream().fuse()); diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 8da2d4be3adde..ab26c0c38596c 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -29,6 +29,7 @@ threadpool = "1.7" tracing = "0.1.29" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "6.0.0", path = "../../primitives/core" } diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index c80b511c84d17..f379ebad17bbf 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -325,19 +325,88 @@ impl AsyncApi { mod tests { use super::*; use sc_client_db::offchain::LocalStorage; - use sc_network::{NetworkStateInfo, PeerId}; + use sc_network::{PeerId, ReputationChange}; + use sc_network_common::service::{NetworkPeers, NetworkStateInfo}; use sp_core::offchain::{DbExternalities, Externalities}; - use std::time::SystemTime; + use std::{borrow::Cow, time::SystemTime}; pub(super) struct TestNetwork(); - impl NetworkProvider for TestNetwork { + impl NetworkPeers for TestNetwork { fn set_authorized_peers(&self, _peers: HashSet) { - unimplemented!() + unimplemented!(); } fn set_authorized_only(&self, _reserved_only: bool) { - unimplemented!() + unimplemented!(); + } + + fn add_known_address(&self, _peer_id: PeerId, _addr: Multiaddr) { + unimplemented!(); + } + + fn report_peer(&self, _who: PeerId, _cost_benefit: ReputationChange) { + unimplemented!(); + } + + fn disconnect_peer(&self, _who: PeerId, _protocol: Cow<'static, str>) { + unimplemented!(); + } + + fn accept_unreserved_peers(&self) { + unimplemented!(); + } + + fn deny_unreserved_peers(&self) { + unimplemented!(); + } + + fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { + unimplemented!(); + } + + fn remove_reserved_peer(&self, _peer_id: PeerId) { + unimplemented!(); + } + + fn set_reserved_peers( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn add_peers_to_reserved_set( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn remove_peers_from_reserved_set( + &self, + _protocol: Cow<'static, str>, + _peers: Vec, + ) { + unimplemented!(); + } + + fn add_to_peers_set( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn remove_from_peers_set(&self, _protocol: Cow<'static, str>, _peers: Vec) { + unimplemented!(); + } + + fn sync_num_connected(&self) -> usize { + unimplemented!(); } } diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index d54d491b04c43..14a2408e61a70 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -35,14 +35,14 @@ #![warn(missing_docs)] -use std::{collections::HashSet, fmt, marker::PhantomData, sync::Arc}; +use std::{fmt, marker::PhantomData, sync::Arc}; use futures::{ future::{ready, Future}, prelude::*, }; use parking_lot::Mutex; -use sc_network::{ExHashT, NetworkService, NetworkStateInfo, PeerId}; +use sc_network_common::service::{NetworkPeers, NetworkStateInfo}; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_core::{offchain, traits::SpawnNamed, ExecutionContext}; use sp_runtime::{ @@ -60,27 +60,9 @@ const LOG_TARGET: &str = "offchain-worker"; /// NetworkProvider provides [`OffchainWorkers`] with all necessary hooks into the /// underlying Substrate networking. -pub trait NetworkProvider: NetworkStateInfo { - /// Set the authorized peers. - fn set_authorized_peers(&self, peers: HashSet); +pub trait NetworkProvider: NetworkStateInfo + NetworkPeers {} - /// Set the authorized only flag. - fn set_authorized_only(&self, reserved_only: bool); -} - -impl NetworkProvider for NetworkService -where - B: traits::Block + 'static, - H: ExHashT, -{ - fn set_authorized_peers(&self, peers: HashSet) { - NetworkService::set_authorized_peers(self, peers) - } - - fn set_authorized_only(&self, reserved_only: bool) { - NetworkService::set_authorized_only(self, reserved_only) - } -} +impl NetworkProvider for T where T: NetworkStateInfo + NetworkPeers {} /// Options for [`OffchainWorkers`] pub struct OffchainWorkerOptions { @@ -266,11 +248,11 @@ mod tests { use futures::executor::block_on; use sc_block_builder::BlockBuilderProvider as _; use sc_client_api::Backend as _; - use sc_network::{Multiaddr, PeerId}; + use sc_network::{Multiaddr, PeerId, ReputationChange}; use sc_transaction_pool::{BasicPool, FullChainApi}; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_consensus::BlockOrigin; - use std::sync::Arc; + use std::{borrow::Cow, collections::HashSet, sync::Arc}; use substrate_test_runtime_client::{ runtime::Block, ClientBlockImportExt, DefaultTestClientBuilderExt, TestClient, TestClientBuilderExt, @@ -288,13 +270,81 @@ mod tests { } } - impl NetworkProvider for TestNetwork { + impl NetworkPeers for TestNetwork { fn set_authorized_peers(&self, _peers: HashSet) { - unimplemented!() + unimplemented!(); } fn set_authorized_only(&self, _reserved_only: bool) { - unimplemented!() + unimplemented!(); + } + + fn add_known_address(&self, _peer_id: PeerId, _addr: Multiaddr) { + unimplemented!(); + } + + fn report_peer(&self, _who: PeerId, _cost_benefit: ReputationChange) { + unimplemented!(); + } + + fn disconnect_peer(&self, _who: PeerId, _protocol: Cow<'static, str>) { + unimplemented!(); + } + + fn accept_unreserved_peers(&self) { + unimplemented!(); + } + + fn deny_unreserved_peers(&self) { + unimplemented!(); + } + + fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { + unimplemented!(); + } + + fn remove_reserved_peer(&self, _peer_id: PeerId) { + unimplemented!(); + } + + fn set_reserved_peers( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn add_peers_to_reserved_set( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn remove_peers_from_reserved_set( + &self, + _protocol: Cow<'static, str>, + _peers: Vec, + ) { + unimplemented!(); + } + + fn add_to_peers_set( + &self, + _protocol: Cow<'static, str>, + _peers: HashSet, + ) -> Result<(), String> { + unimplemented!(); + } + + fn remove_from_peers_set(&self, _protocol: Cow<'static, str>, _peers: Vec) { + unimplemented!(); + } + + fn sync_num_connected(&self) -> usize { + unimplemented!(); } } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 55c0006de33fb..f81143583eacf 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -38,7 +38,10 @@ use sc_consensus::import_queue::ImportQueue; use sc_executor::RuntimeVersionOf; use sc_keystore::LocalKeystore; use sc_network::{config::SyncMode, NetworkService}; -use sc_network_common::sync::warp::WarpSyncProvider; +use sc_network_common::{ + service::{NetworkStateInfo, NetworkStatusProvider, NetworkTransaction}, + sync::warp::WarpSyncProvider, +}; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler, @@ -319,6 +322,31 @@ where ) } +/// Shared network instance implementing a set of mandatory traits. +pub trait SpawnTaskNetwork: + sc_offchain::NetworkProvider + + NetworkStateInfo + + NetworkTransaction + + NetworkStatusProvider + + Send + + Sync + + 'static +{ +} + +impl SpawnTaskNetwork for T +where + Block: BlockT, + T: sc_offchain::NetworkProvider + + NetworkStateInfo + + NetworkTransaction + + NetworkStatusProvider + + Send + + Sync + + 'static, +{ +} + /// Parameters to pass into `build`. pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> { /// The service configuration. @@ -337,7 +365,7 @@ pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> { pub rpc_builder: Box Result, Error>>, /// A shared network instance. - pub network: Arc::Hash>>, + pub network: Arc>, /// A Sender for RPC requests. pub system_rpc_tx: TracingUnboundedSender>, /// Telemetry instance for this node. @@ -349,7 +377,7 @@ pub fn build_offchain_workers( config: &Configuration, spawn_handle: SpawnTaskHandle, client: Arc, - network: Arc::Hash>>, + network: Arc, ) -> Option>> where TBl: BlockT, @@ -516,13 +544,14 @@ where Ok(rpc_handlers) } -async fn transaction_notifications( - transaction_pool: Arc, - network: Arc::Hash>>, +async fn transaction_notifications( + transaction_pool: Arc, + network: Network, telemetry: Option, ) where - TBl: BlockT, - TExPool: MaintainedTransactionPool::Hash>, + Block: BlockT, + ExPool: MaintainedTransactionPool::Hash>, + Network: NetworkTransaction<::Hash> + Send + Sync, { // transaction notifications transaction_pool @@ -542,13 +571,18 @@ async fn transaction_notifications( .await; } -fn init_telemetry>( +fn init_telemetry( config: &mut Configuration, - network: Arc::Hash>>, - client: Arc, + network: Network, + client: Arc, telemetry: &mut Telemetry, sysinfo: Option, -) -> sc_telemetry::Result { +) -> sc_telemetry::Result +where + Block: BlockT, + Client: BlockBackend, + Network: NetworkStateInfo, +{ let genesis_hash = client.block_hash(Zero::zero()).ok().flatten().unwrap_or_default(); let connection_message = ConnectionMessage { name: config.network.node_name.to_owned(), diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 5291d219e8102..2f35a04451e79 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -42,9 +42,11 @@ use jsonrpsee::{core::Error as JsonRpseeError, RpcModule}; use log::{debug, error, warn}; use sc_client_api::{blockchain::HeaderBackend, BlockBackend, BlockchainEvents, ProofProvider}; use sc_network::PeerId; +use sc_network_common::service::NetworkBlock; use sc_rpc_server::WsConfig; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; +use sp_consensus::SyncOracle; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header as HeaderT}, diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index ef3132f61ab99..13b249a7b9563 100644 --- a/client/service/src/metrics.rs +++ b/client/service/src/metrics.rs @@ -22,7 +22,8 @@ use crate::config::Configuration; use futures_timer::Delay; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; use sc_client_api::{ClientInfo, UsageProvider}; -use sc_network::{config::Role, NetworkService, NetworkStatus}; +use sc_network::config::Role; +use sc_network_common::service::{NetworkStatus, NetworkStatusProvider}; use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sc_transaction_pool_api::{MaintainedTransactionPool, PoolStatus}; use sc_utils::metrics::register_globals; @@ -182,15 +183,16 @@ impl MetricsService { /// Returns a never-ending `Future` that performs the /// metric and telemetry updates with information from /// the given sources. - pub async fn run( + pub async fn run( mut self, client: Arc, transactions: Arc, - network: Arc::Hash>>, + network: TNet, ) where TBl: Block, TCl: ProvideRuntimeApi + UsageProvider, TExPool: MaintainedTransactionPool::Hash>, + TNet: NetworkStatusProvider, { let mut timer = Delay::new(Duration::from_secs(0)); let timer_interval = Duration::from_secs(5); diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index d003db57eb7ac..01c3ee2348ef5 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -27,6 +27,7 @@ sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../.. sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-executor = { version = "0.10.0-dev", path = "../../executor" } sc-network = { version = "0.10.0-dev", path = "../../network" } +sc-network-common = { version = "0.10.0-dev", path = "../../network/common" } sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../../service" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 2d63362daffba..9c720c6fedea0 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -26,6 +26,7 @@ use sc_network::{ config::{NetworkConfiguration, TransportConfig}, multiaddr, Multiaddr, }; +use sc_network_common::service::{NetworkBlock, NetworkPeers, NetworkStateInfo}; use sc_service::{ client::Client, config::{BasePath, DatabaseSource, KeystoreConfig}, @@ -320,7 +321,7 @@ where handle.spawn(service.clone().map_err(|_| ())); let addr = - addr.with(multiaddr::Protocol::P2p((*service.network().local_peer_id()).into())); + addr.with(multiaddr::Protocol::P2p((service.network().local_peer_id()).into())); self.authority_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; } @@ -340,7 +341,7 @@ where handle.spawn(service.clone().map_err(|_| ())); let addr = - addr.with(multiaddr::Protocol::P2p((*service.network().local_peer_id()).into())); + addr.with(multiaddr::Protocol::P2p((service.network().local_peer_id()).into())); self.full_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; } @@ -387,7 +388,7 @@ where } network.run_until_all_full(move |_index, service| { - let connected = service.network().num_connected(); + let connected = service.network().sync_num_connected(); debug!("Got {}/{} full connections...", connected, expected_full_connections); connected == expected_full_connections }); @@ -422,7 +423,7 @@ where } network.run_until_all_full(move |_index, service| { - let connected = service.network().num_connected(); + let connected = service.network().sync_num_connected(); debug!("Got {}/{} full connections...", connected, expected_full_connections); connected == expected_full_connections }); diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index 4539cec2c8e0a..043533cbf2258 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -236,10 +236,10 @@ pub trait Proposer { pub trait SyncOracle { /// Whether the synchronization service is undergoing major sync. /// Returns true if so. - fn is_major_syncing(&mut self) -> bool; + fn is_major_syncing(&self) -> bool; /// Whether the synchronization service is offline. /// Returns true if so. - fn is_offline(&mut self) -> bool; + fn is_offline(&self) -> bool; } /// A synchronization oracle for when there is no network. @@ -247,10 +247,10 @@ pub trait SyncOracle { pub struct NoNetwork; impl SyncOracle for NoNetwork { - fn is_major_syncing(&mut self) -> bool { + fn is_major_syncing(&self) -> bool { false } - fn is_offline(&mut self) -> bool { + fn is_offline(&self) -> bool { false } } @@ -258,14 +258,14 @@ impl SyncOracle for NoNetwork { impl SyncOracle for Arc where T: ?Sized, - for<'r> &'r T: SyncOracle, + T: SyncOracle, { - fn is_major_syncing(&mut self) -> bool { - <&T>::is_major_syncing(&mut &**self) + fn is_major_syncing(&self) -> bool { + T::is_major_syncing(self) } - fn is_offline(&mut self) -> bool { - <&T>::is_offline(&mut &**self) + fn is_offline(&self) -> bool { + T::is_offline(self) } } From ef433a8c31947c73e9bad212a9672d1f841a9c0d Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 10 Aug 2022 10:39:24 +0200 Subject: [PATCH 1047/1472] Add BoundedVec::sort_by_key (#11998) Signed-off-by: Oliver Tale-Yazdi --- primitives/runtime/src/bounded/bounded_vec.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/primitives/runtime/src/bounded/bounded_vec.rs b/primitives/runtime/src/bounded/bounded_vec.rs index d5f3f2da0d615..aed1a156ad699 100644 --- a/primitives/runtime/src/bounded/bounded_vec.rs +++ b/primitives/runtime/src/bounded/bounded_vec.rs @@ -319,6 +319,17 @@ impl BoundedVec { self.0.sort_by(compare) } + /// Exactly the same semantics as [`slice::sort_by_key`]. + /// + /// This is safe since sorting cannot change the number of elements in the vector. + pub fn sort_by_key(&mut self, f: F) + where + F: FnMut(&T) -> K, + K: sp_std::cmp::Ord, + { + self.0.sort_by_key(f) + } + /// Exactly the same semantics as [`slice::sort`]. /// /// This is safe since sorting cannot change the number of elements in the vector. @@ -1189,4 +1200,12 @@ pub mod test { b1.iter().map(|x| x + 1).rev().take(2).try_collect(); assert!(b2.is_err()); } + + #[test] + fn bounded_vec_sort_by_key_works() { + let mut v: BoundedVec> = bounded_vec![-5, 4, 1, -3, 2]; + // Sort by absolute value. + v.sort_by_key(|k| k.abs()); + assert_eq!(v, vec![1, 2, -3, 4, -5]); + } } From edeba3f760fe54600ea38c8765a0d099e58d4799 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Wed, 10 Aug 2022 12:36:16 +0200 Subject: [PATCH 1048/1472] Transaction payment runtime api: query call info and fee details (#11819) * Transaction payment RPC calls: query call info * transaction payment pallet - runtime api - add query_call info and fee_details * remove unused deps * separate call runtime api * undo fmt for unchanged code * system config call bounded to GetDispatchInfo, drop Call generic for query call info/fee * impl GetDispatchInfo for Extrinsics within runtime test-utils * introduced runtime api methods accept encoded Call instead of Call type * replace Bytes by Vec, docs for for new api, drop len argument, drop GetDispatchInfo bound from system_Config::Call * clean up toml and extra impl for dropped bound * panic if Call can not be decoded * revert to 6d0ca79 * fmt and docs * rustfmt --- bin/node-template/runtime/src/lib.rs | 17 +++++ bin/node/runtime/src/lib.rs | 11 ++++ .../rpc/runtime-api/src/lib.rs | 12 ++++ frame/transaction-payment/src/lib.rs | 63 +++++++++++++++++++ 4 files changed, 103 insertions(+) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 88fc86db02ef9..b43fbde52dcdc 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -467,6 +467,23 @@ impl_runtime_apis! { } } + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + for Runtime + { + fn query_call_info( + call: Call, + len: u32, + ) -> pallet_transaction_payment::RuntimeDispatchInfo { + TransactionPayment::query_call_info(call, len) + } + fn query_call_fee_details( + call: Call, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_call_fee_details(call, len) + } + } + #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn benchmark_metadata(extra: bool) -> ( diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 2ac1e6444f119..6bfbe3413058a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1965,6 +1965,17 @@ impl_runtime_apis! { } } + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + for Runtime + { + fn query_call_info(call: Call, len: u32) -> RuntimeDispatchInfo { + TransactionPayment::query_call_info(call, len) + } + fn query_call_fee_details(call: Call, len: u32) -> FeeDetails { + TransactionPayment::query_call_fee_details(call, len) + } + } + impl pallet_mmr::primitives::MmrApi< Block, mmr::Hash, diff --git a/frame/transaction-payment/rpc/runtime-api/src/lib.rs b/frame/transaction-payment/rpc/runtime-api/src/lib.rs index 5a0c70138db24..6944593daa57a 100644 --- a/frame/transaction-payment/rpc/runtime-api/src/lib.rs +++ b/frame/transaction-payment/rpc/runtime-api/src/lib.rs @@ -31,4 +31,16 @@ sp_api::decl_runtime_apis! { fn query_info(uxt: Block::Extrinsic, len: u32) -> RuntimeDispatchInfo; fn query_fee_details(uxt: Block::Extrinsic, len: u32) -> FeeDetails; } + + pub trait TransactionPaymentCallApi + where + Balance: Codec + MaybeDisplay, + Call: Codec, + { + /// Query information of a dispatch class, weight, and fee of a given encoded `Call`. + fn query_call_info(call: Call, len: u32) -> RuntimeDispatchInfo; + + /// Query fee details of a given encoded `Call`. + fn query_call_fee_details(call: Call, len: u32) -> FeeDetails; + } } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index fe37acb214452..ff65c0d2735fd 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -445,6 +445,32 @@ where } } + /// Query information of a dispatch class, weight, and fee of a given encoded `Call`. + pub fn query_call_info(call: T::Call, len: u32) -> RuntimeDispatchInfo> + where + T::Call: Dispatchable + GetDispatchInfo, + { + let dispatch_info = ::get_dispatch_info(&call); + let DispatchInfo { weight, class, .. } = dispatch_info; + + RuntimeDispatchInfo { + weight, + class, + partial_fee: Self::compute_fee(len, &dispatch_info, 0u32.into()), + } + } + + /// Query fee details of a given encoded `Call`. + pub fn query_call_fee_details(call: T::Call, len: u32) -> FeeDetails> + where + T::Call: Dispatchable + GetDispatchInfo, + { + let dispatch_info = ::get_dispatch_info(&call); + let tip = 0u32.into(); + + Self::compute_fee_details(len, &dispatch_info, tip) + } + /// Compute the final fee value for a particular transaction. pub fn compute_fee(len: u32, info: &DispatchInfoOf, tip: BalanceOf) -> BalanceOf where @@ -1206,6 +1232,43 @@ mod tests { }); } + #[test] + fn query_call_info_and_fee_details_works() { + let call = Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + let info = call.get_dispatch_info(); + let encoded_call = call.encode(); + let len = encoded_call.len() as u32; + + ExtBuilder::default().base_weight(5).weight_fee(2).build().execute_with(|| { + // all fees should be x1.5 + >::put(Multiplier::saturating_from_rational(3, 2)); + + assert_eq!( + TransactionPayment::query_call_info(call.clone(), len), + RuntimeDispatchInfo { + weight: info.weight, + class: info.class, + partial_fee: 5 * 2 /* base * weight_fee */ + + len as u64 /* len * 1 */ + + info.weight.min(BlockWeights::get().max_block) as u64 * 2 * 3 / 2 /* weight */ + }, + ); + + assert_eq!( + TransactionPayment::query_call_fee_details(call, len), + FeeDetails { + inclusion_fee: Some(InclusionFee { + base_fee: 5 * 2, /* base * weight_fee */ + len_fee: len as u64, /* len * 1 */ + adjusted_weight_fee: info.weight.min(BlockWeights::get().max_block) as u64 * + 2 * 3 / 2 /* weight * weight_fee * multipler */ + }), + tip: 0, + }, + ); + }); + } + #[test] fn compute_fee_works_without_multiplier() { ExtBuilder::default() From 1fd71c7845d6c28c532795ec79106d959dd1fe30 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 10 Aug 2022 14:58:52 +0100 Subject: [PATCH 1049/1472] Use `#[pallet::unbounded]` tag in FRAME System (#11946) * use unbounded in system * update ui tests --- frame/sudo/src/mock.rs | 12 ++++++------ frame/support/src/weights.rs | 4 ++-- .../pallet_ui/storage_info_unsatisfied.stderr | 2 +- .../storage_info_unsatisfied_nmap.stderr | 2 +- frame/system/src/lib.rs | 15 ++++++++++----- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index 2e2a4abafcd98..71f0f26b1a1d5 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -44,7 +44,6 @@ pub mod logger { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::call] @@ -57,7 +56,7 @@ pub mod logger { ) -> DispatchResultWithPostInfo { // Ensure that the `origin` is `Root`. ensure_root(origin)?; - >::append(i); + >::try_append(i).map_err(|_| "could not append")?; Self::deposit_event(Event::AppendI32 { value: i, weight }); Ok(().into()) } @@ -70,8 +69,8 @@ pub mod logger { ) -> DispatchResultWithPostInfo { // Ensure that the `origin` is some signed account. let sender = ensure_signed(origin)?; - >::append(i); - >::append(sender.clone()); + >::try_append(i).map_err(|_| "could not append")?; + >::try_append(sender.clone()).map_err(|_| "could not append")?; Self::deposit_event(Event::AppendI32AndAccount { sender, value: i, weight }); Ok(().into()) } @@ -86,11 +85,12 @@ pub mod logger { #[pallet::storage] #[pallet::getter(fn account_log)] - pub(super) type AccountLog = StorageValue<_, Vec, ValueQuery>; + pub(super) type AccountLog = + StorageValue<_, BoundedVec>, ValueQuery>; #[pallet::storage] #[pallet::getter(fn i32_log)] - pub(super) type I32Log = StorageValue<_, Vec, ValueQuery>; + pub(super) type I32Log = StorageValue<_, BoundedVec>, ValueQuery>; } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index c37a72536bddf..fb34484416063 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -128,7 +128,7 @@ use crate::{ dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo}, traits::Get, }; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -676,7 +676,7 @@ where } /// A struct holding value for each `DispatchClass`. -#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] +#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct PerDispatchClass { /// Value for `Normal` extrinsics. normal: T, diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index c2ec8cf7f4d05..6c49e1220a3a5 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -13,5 +13,5 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 72 others + and 75 others = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index dbbc426de2906..9a0731683a953 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -13,6 +13,6 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 72 others + and 75 others = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 94605c2da59bd..12d415e4e2b42 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -233,7 +233,8 @@ pub mod pallet { + Default + MaybeDisplay + AtLeast32Bit - + Copy; + + Copy + + MaxEncodedLen; /// The block number type used by the runtime. type BlockNumber: Parameter @@ -320,7 +321,7 @@ pub mod pallet { /// Data to be associated with an account (other than nonce/transaction counter, which this /// pallet does regardless). - type AccountData: Member + FullCodec + Clone + Default + TypeInfo; + type AccountData: Member + FullCodec + Clone + Default + TypeInfo + MaxEncodedLen; /// Handler for when a new account has just been created. type OnNewAccount: OnNewAccount; @@ -355,7 +356,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] @@ -578,6 +578,7 @@ pub mod pallet { /// Extrinsics data for the current block (maps an extrinsic's index to its data). #[pallet::storage] #[pallet::getter(fn extrinsic_data)] + #[pallet::unbounded] pub(super) type ExtrinsicData = StorageMap<_, Twox64Concat, u32, Vec, ValueQuery>; @@ -593,6 +594,7 @@ pub mod pallet { /// Digest of the current block, also part of the block header. #[pallet::storage] + #[pallet::unbounded] #[pallet::getter(fn digest)] pub(super) type Digest = StorageValue<_, generic::Digest, ValueQuery>; @@ -604,6 +606,7 @@ pub mod pallet { /// Events have a large in-memory size. Box the events to not go out-of-memory /// just in case someone still reads them from within the runtime. #[pallet::storage] + #[pallet::unbounded] pub(super) type Events = StorageValue<_, Vec>>, ValueQuery>; @@ -623,12 +626,14 @@ pub mod pallet { /// the `EventIndex` then in case if the topic has the same contents on the next block /// no notification will be triggered thus the event might be lost. #[pallet::storage] + #[pallet::unbounded] #[pallet::getter(fn event_topics)] pub(super) type EventTopics = StorageMap<_, Blake2_128Concat, T::Hash, Vec<(T::BlockNumber, EventIndex)>, ValueQuery>; /// Stores the `spec_version` and `spec_name` of when the last runtime upgrade happened. #[pallet::storage] + #[pallet::unbounded] pub type LastRuntimeUpgrade = StorageValue<_, LastRuntimeUpgradeInfo>; /// True if we have upgraded so that `type RefCount` is `u32`. False (default) if not. @@ -690,7 +695,7 @@ pub type Key = Vec; pub type KeyValue = (Vec, Vec); /// A phase of a block's execution. -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, PartialEq, Eq, Clone))] pub enum Phase { /// Applying an extrinsic. @@ -738,7 +743,7 @@ type EventIndex = u32; pub type RefCount = u32; /// Information of an account. -#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] +#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct AccountInfo { /// The number of transactions this account has sent. pub nonce: Index, From a1a9b475c354d873f91135ed5fa028ac9ef6a2c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 10 Aug 2022 22:27:01 +0200 Subject: [PATCH 1050/1472] transactional: Wrap `pallet::calls` directly in storage layers (#11927) * transactional: Wrap `pallet::calls` directly in storage layers Before this pr we only wrapped `pallet::calls` into storage layers when executing the calls with `dispatch`. This pr is solving that by wrapping each call function inside a storage layer. * Teach `BasicExternalities` transactions support * Fix crates * FMT * Fix benchmarking tests * Use correct span * Support old decl macros * Fix test * Apply suggestions from code review Co-authored-by: Oliver Tale-Yazdi * Update frame/state-trie-migration/src/lib.rs * Update frame/state-trie-migration/src/lib.rs * Update frame/state-trie-migration/src/lib.rs * Feedback * Apply suggestions from code review Co-authored-by: cheme Co-authored-by: Oliver Tale-Yazdi Co-authored-by: cheme --- frame/state-trie-migration/src/lib.rs | 128 ++++++------ .../procedural/src/pallet/expand/call.rs | 26 ++- .../procedural/src/pallet/parse/call.rs | 20 +- frame/support/src/dispatch.rs | 14 +- frame/support/test/tests/construct_runtime.rs | 178 ++++++++-------- frame/support/test/tests/storage_layers.rs | 2 + frame/transaction-storage/src/lib.rs | 4 +- primitives/state-machine/src/basic.rs | 192 +++++++----------- .../src/overlayed_changes/changeset.rs | 31 ++- .../src/overlayed_changes/mod.rs | 15 ++ 10 files changed, 316 insertions(+), 294 deletions(-) diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 94f6c1f223b9c..353bc93e5ab94 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -235,7 +235,10 @@ pub mod pallet { /// reading a key, we simply cannot know how many bytes it is. In other words, this should /// not be used in any environment where resources are strictly bounded (e.g. a parachain), /// but it is acceptable otherwise (relay chain, offchain workers). - pub fn migrate_until_exhaustion(&mut self, limits: MigrationLimits) -> DispatchResult { + pub fn migrate_until_exhaustion( + &mut self, + limits: MigrationLimits, + ) -> Result<(), Error> { log!(debug, "running migrations on top of {:?} until {:?}", self, limits); if limits.item.is_zero() || limits.size.is_zero() { @@ -262,7 +265,7 @@ pub mod pallet { /// Migrate AT MOST ONE KEY. This can be either a top or a child key. /// /// This function is *the* core of this entire pallet. - fn migrate_tick(&mut self) -> DispatchResult { + fn migrate_tick(&mut self) -> Result<(), Error> { match (&self.progress_top, &self.progress_child) { (Progress::ToStart, _) => self.migrate_top(), (Progress::LastKey(_), Progress::LastKey(_)) => { @@ -301,7 +304,7 @@ pub mod pallet { /// Migrate the current child key, setting it to its new value, if one exists. /// /// It updates the dynamic counters. - fn migrate_child(&mut self) -> DispatchResult { + fn migrate_child(&mut self) -> Result<(), Error> { use sp_io::default_child_storage as child_io; let (maybe_current_child, child_root) = match (&self.progress_child, &self.progress_top) { @@ -350,7 +353,7 @@ pub mod pallet { /// Migrate the current top key, setting it to its new value, if one exists. /// /// It updates the dynamic counters. - fn migrate_top(&mut self) -> DispatchResult { + fn migrate_top(&mut self) -> Result<(), Error> { let maybe_current_top = match &self.progress_top { Progress::LastKey(last_top) => { let maybe_top: Option> = @@ -431,7 +434,7 @@ pub mod pallet { /// The auto migration task finished. AutoMigrationFinished, /// Migration got halted due to an error or miss-configuration. - Halted, + Halted { error: Error }, } /// The outer Pallet struct. @@ -516,8 +519,9 @@ pub mod pallet { pub type SignedMigrationMaxLimits = StorageValue<_, MigrationLimits, OptionQuery>; #[pallet::error] + #[derive(Clone, PartialEq)] pub enum Error { - /// max signed limits not respected. + /// Max signed limits not respected. MaxSignedLimits, /// A key was longer than the configured maximum. /// @@ -529,12 +533,12 @@ pub mod pallet { KeyTooLong, /// submitter does not have enough funds. NotEnoughFunds, - /// bad witness data provided. + /// Bad witness data provided. BadWitness, - /// upper bound of size is exceeded, - SizeUpperBoundExceeded, /// Signed migration is not allowed because the maximum limit is not set yet. SignedMigrationNotAllowed, + /// Bad child root provided. + BadChildRoot, } #[pallet::call] @@ -617,7 +621,7 @@ pub mod pallet { let (_imbalance, _remainder) = T::Currency::slash(&who, deposit); Self::deposit_event(Event::::Slashed { who, amount: deposit }); debug_assert!(_remainder.is_zero()); - return Err(Error::::SizeUpperBoundExceeded.into()) + return Ok(().into()) } Self::deposit_event(Event::::Migrated { @@ -634,13 +638,10 @@ pub mod pallet { MigrationProcess::::put(task); let post_info = PostDispatchInfo { actual_weight, pays_fee: Pays::No }; - match migration { - Ok(_) => Ok(post_info), - Err(error) => { - Self::halt(&error); - Err(DispatchErrorWithPostInfo { post_info, error }) - }, + if let Err(error) = migration { + Self::halt(error); } + Ok(post_info) } /// Migrate the list of top keys by iterating each of them one by one. @@ -679,7 +680,7 @@ pub mod pallet { let (_imbalance, _remainder) = T::Currency::slash(&who, deposit); Self::deposit_event(Event::::Slashed { who, amount: deposit }); debug_assert!(_remainder.is_zero()); - Err("wrong witness data".into()) + Ok(().into()) } else { Self::deposit_event(Event::::Migrated { top: keys.len() as u32, @@ -741,12 +742,9 @@ pub mod pallet { let (_imbalance, _remainder) = T::Currency::slash(&who, deposit); debug_assert!(_remainder.is_zero()); Self::deposit_event(Event::::Slashed { who, amount: deposit }); - Err(DispatchErrorWithPostInfo { - error: "bad witness".into(), - post_info: PostDispatchInfo { - actual_weight: Some(T::WeightInfo::migrate_custom_child_fail()), - pays_fee: Pays::Yes, - }, + Ok(PostDispatchInfo { + actual_weight: Some(T::WeightInfo::migrate_custom_child_fail()), + pays_fee: Pays::Yes, }) } else { Self::deposit_event(Event::::Migrated { @@ -806,7 +804,7 @@ pub mod pallet { if let Some(limits) = Self::auto_limits() { let mut task = Self::migration_process(); if let Err(e) = task.migrate_until_exhaustion(limits) { - Self::halt(&e); + Self::halt(e); } let weight = Self::dynamic_weight(task.dyn_total_items(), task.dyn_size); @@ -849,10 +847,10 @@ pub mod pallet { } /// Put a stop to all ongoing migrations and logs an error. - fn halt(msg: &E) { - log!(error, "migration halted due to: {:?}", msg); + fn halt(error: Error) { + log!(error, "migration halted due to: {:?}", error); AutoLimits::::kill(); - Self::deposit_event(Event::::Halted); + Self::deposit_event(Event::::Halted { error }); } /// Convert a child root key, aka. "Child-bearing top key" into the proper format. @@ -871,7 +869,7 @@ pub mod pallet { fn transform_child_key_or_halt(root: &Vec) -> &[u8] { let key = Self::transform_child_key(root); if key.is_none() { - Self::halt("bad child root key"); + Self::halt(Error::::BadChildRoot); } key.unwrap_or_default() } @@ -961,8 +959,16 @@ mod benchmarks { frame_system::RawOrigin::Signed(caller.clone()).into(), vec![b"foo".to_vec()], 1, - ).is_err() - ) + ).is_ok() + ); + + frame_system::Pallet::::assert_last_event( + ::Event::from(crate::Event::Slashed { + who: caller.clone(), + amount: T::SignedDepositBase::get() + .saturating_add(T::SignedDepositPerItem::get().saturating_mul(1u32.into())), + }).into(), + ); } verify { assert_eq!(StateTrieMigration::::migration_process(), Default::default()); @@ -1005,7 +1011,7 @@ mod benchmarks { StateTrieMigration::::childify("top"), vec![b"foo".to_vec()], 1, - ).is_err() + ).is_ok() ) } verify { @@ -1285,18 +1291,16 @@ mod test { SignedMigrationMaxLimits::::put(MigrationLimits { size: 1 << 20, item: 50 }); // fails if the top key is too long. - frame_support::assert_err_with_weight!( - StateTrieMigration::continue_migrate( - Origin::signed(1), - MigrationLimits { item: 50, size: 1 << 20 }, - Bounded::max_value(), - MigrationProcess::::get() - ), - Error::::KeyTooLong, - Some(2000000), - ); + frame_support::assert_ok!(StateTrieMigration::continue_migrate( + Origin::signed(1), + MigrationLimits { item: 50, size: 1 << 20 }, + Bounded::max_value(), + MigrationProcess::::get() + ),); // The auto migration halted. - System::assert_last_event(crate::Event::Halted {}.into()); + System::assert_last_event( + crate::Event::Halted { error: Error::::KeyTooLong }.into(), + ); // Limits are killed. assert!(AutoLimits::::get().is_none()); @@ -1322,18 +1326,16 @@ mod test { SignedMigrationMaxLimits::::put(MigrationLimits { size: 1 << 20, item: 50 }); // fails if the top key is too long. - frame_support::assert_err_with_weight!( - StateTrieMigration::continue_migrate( - Origin::signed(1), - MigrationLimits { item: 50, size: 1 << 20 }, - Bounded::max_value(), - MigrationProcess::::get() - ), - Error::::KeyTooLong, - Some(2000000), - ); + frame_support::assert_ok!(StateTrieMigration::continue_migrate( + Origin::signed(1), + MigrationLimits { item: 50, size: 1 << 20 }, + Bounded::max_value(), + MigrationProcess::::get() + )); // The auto migration halted. - System::assert_last_event(crate::Event::Halted {}.into()); + System::assert_last_event( + crate::Event::Halted { error: Error::::KeyTooLong }.into(), + ); // Limits are killed. assert!(AutoLimits::::get().is_none()); @@ -1484,7 +1486,7 @@ mod test { ..Default::default() } ), - Error::::BadWitness + Error::::BadWitness, ); // migrate all keys in a series of submissions @@ -1547,14 +1549,11 @@ mod test { assert_eq!(Balances::free_balance(&1), 1000); // note that we don't expect this to be a noop -- we do slash. - frame_support::assert_err!( - StateTrieMigration::migrate_custom_top( - Origin::signed(1), - vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], - correct_witness - 1, - ), - "wrong witness data" - ); + frame_support::assert_ok!(StateTrieMigration::migrate_custom_top( + Origin::signed(1), + vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], + correct_witness - 1, + ),); // no funds should remain reserved. assert_eq!(Balances::reserved_balance(&1), 0); @@ -1584,13 +1583,12 @@ mod test { assert_eq!(Balances::free_balance(&1), 1000); // note that we don't expect this to be a noop -- we do slash. - assert!(StateTrieMigration::migrate_custom_child( + frame_support::assert_ok!(StateTrieMigration::migrate_custom_child( Origin::signed(1), StateTrieMigration::childify("chk1"), vec![b"key1".to_vec(), b"key2".to_vec()], 999999, // wrong witness - ) - .is_err()); + )); // no funds should remain reserved. assert_eq!(Balances::reserved_balance(&1), 0); diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index fe7589a8275d2..a9468451ad1d4 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -140,6 +140,24 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" }; + // Wrap all calls inside of storage layers + if let Some(syn::Item::Impl(item_impl)) = def + .call + .as_ref() + .map(|c| &mut def.item.content.as_mut().expect("Checked by def parser").1[c.index]) + { + item_impl.items.iter_mut().for_each(|i| { + if let syn::ImplItem::Method(method) = i { + let block = &method.block; + method.block = syn::parse_quote! {{ + // We execute all dispatchable in a new storage layer, allowing them + // to return an error at any point, and undoing any storage changes. + #frame_support::storage::with_storage_layer(|| #block) + }}; + } + }); + } + quote::quote_spanned!(span => #[doc(hidden)] pub mod __substrate_call_check { @@ -267,12 +285,8 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::sp_tracing::enter_span!( #frame_support::sp_tracing::trace_span!(stringify!(#fn_name)) ); - // We execute all dispatchable in a new storage layer, allowing them - // to return an error at any point, and undoing any storage changes. - #frame_support::storage::with_storage_layer(|| { - <#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* ) - .map(Into::into).map_err(Into::into) - }) + <#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* ) + .map(Into::into).map_err(Into::into) }, )* Self::__Ignore(_, _) => { diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index d8a81d699b8c2..336e08c3d39b7 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -48,8 +48,8 @@ pub struct CallDef { pub docs: Vec, } -#[derive(Clone)] /// Definition of dispatchable typically: `#[weight...] fn foo(origin .., param1: ...) -> ..` +#[derive(Clone)] pub struct CallVariantDef { /// Function name. pub name: syn::Ident, @@ -143,18 +143,18 @@ impl CallDef { index: usize, item: &mut syn::Item, ) -> syn::Result { - let item = if let syn::Item::Impl(item) = item { + let item_impl = if let syn::Item::Impl(item) = item { item } else { return Err(syn::Error::new(item.span(), "Invalid pallet::call, expected item impl")) }; let instances = vec![ - helper::check_impl_gen(&item.generics, item.impl_token.span())?, - helper::check_pallet_struct_usage(&item.self_ty)?, + helper::check_impl_gen(&item_impl.generics, item_impl.impl_token.span())?, + helper::check_pallet_struct_usage(&item_impl.self_ty)?, ]; - if let Some((_, _, for_)) = item.trait_ { + if let Some((_, _, for_)) = item_impl.trait_ { let msg = "Invalid pallet::call, expected no trait ident as in \ `impl<..> Pallet<..> { .. }`"; return Err(syn::Error::new(for_.span(), msg)) @@ -163,8 +163,8 @@ impl CallDef { let mut methods = vec![]; let mut indices = HashMap::new(); let mut last_index: Option = None; - for impl_item in &mut item.items { - if let syn::ImplItem::Method(method) = impl_item { + for item in &mut item_impl.items { + if let syn::ImplItem::Method(method) = item { if !matches!(method.vis, syn::Visibility::Public(_)) { let msg = "Invalid pallet::call, dispatchable function must be public: \ `pub fn`"; @@ -290,7 +290,7 @@ impl CallDef { }); } else { let msg = "Invalid pallet::call, only method accepted"; - return Err(syn::Error::new(impl_item.span(), msg)) + return Err(syn::Error::new(item.span(), msg)) } } @@ -299,8 +299,8 @@ impl CallDef { attr_span, instances, methods, - where_clause: item.generics.where_clause.clone(), - docs: get_doc_literals(&item.attrs), + where_clause: item_impl.generics.where_clause.clone(), + docs: get_doc_literals(&item_impl.attrs), }) } } diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 2b05478e0b02a..fb0b658cd9303 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -1787,9 +1787,11 @@ macro_rules! decl_module { $vis fn $name( $origin: $origin_ty $(, $param: $param_ty )* ) -> $crate::dispatch::DispatchResult { - $crate::sp_tracing::enter_span!($crate::sp_tracing::trace_span!(stringify!($name))); - { $( $impl )* } - Ok(()) + $crate::storage::with_storage_layer(|| { + $crate::sp_tracing::enter_span!($crate::sp_tracing::trace_span!(stringify!($name))); + { $( $impl )* } + Ok(()) + }) } }; @@ -1805,8 +1807,10 @@ macro_rules! decl_module { ) => { $(#[$fn_attr])* $vis fn $name($origin: $origin_ty $(, $param: $param_ty )* ) -> $result { - $crate::sp_tracing::enter_span!($crate::sp_tracing::trace_span!(stringify!($name))); - $( $impl )* + $crate::storage::with_storage_layer(|| { + $crate::sp_tracing::enter_span!($crate::sp_tracing::trace_span!(stringify!($name))); + $( $impl )* + }) } }; diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 63747a9d560dc..d388127f29abd 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -282,94 +282,96 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 31, - error: [0; 4], - message: Some("Something") - })), - ); - assert_eq!( - Module2::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 32, - error: [0; 4], - message: Some("Something") - })), - ); - assert_eq!( - Module1_2::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 33, - error: [0; 4], - message: Some("Something") - })), - ); - assert_eq!( - NestedModule3::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 34, - error: [0; 4], - message: Some("Something") - })), - ); - assert_eq!( - Module1_3::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 6, - error: [0; 4], - message: Some("Something") - })), - ); - assert_eq!( - Module1_4::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 3, - error: [0; 4], - message: Some("Something") - })), - ); - assert_eq!( - Module1_5::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 4, - error: [0; 4], - message: Some("Something") - })), - ); - assert_eq!( - Module1_6::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 1, - error: [0; 4], - message: Some("Something") - })), - ); - assert_eq!( - Module1_7::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 2, - error: [0; 4], - message: Some("Something") - })), - ); - assert_eq!( - Module1_8::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 12, - error: [0; 4], - message: Some("Something") - })), - ); - assert_eq!( - Module1_9::fail(system::Origin::::Root.into()), - Err(DispatchError::Module(ModuleError { - index: 13, - error: [0; 4], - message: Some("Something") - })), - ); + sp_io::TestExternalities::default().execute_with(|| { + assert_eq!( + Module1_1::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 31, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module2::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 32, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_2::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 33, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + NestedModule3::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 34, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_3::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 6, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_4::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 3, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_5::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 4, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_6::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 1, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_7::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 2, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_8::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 12, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_9::fail(system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 13, + error: [0; 4], + message: Some("Something") + })), + ); + }); } #[test] diff --git a/frame/support/test/tests/storage_layers.rs b/frame/support/test/tests/storage_layers.rs index 05ed60fe90196..7404ccace2c09 100644 --- a/frame/support/test/tests/storage_layers.rs +++ b/frame/support/test/tests/storage_layers.rs @@ -276,5 +276,7 @@ fn storage_layer_in_decl_pallet_call() { let call2 = Call::DeclPallet(decl_pallet::Call::set_value { value: 1 }); assert_noop!(call2.dispatch(Origin::signed(0)), "Revert!"); + // Calling the function directly also works with storage layers. + assert_noop!(decl_pallet::Module::::set_value(Origin::signed(1), 1), "Revert!"); }); } diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index f16b8f029662b..681cd29af8222 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -245,9 +245,11 @@ pub mod pallet { let sender = ensure_signed(origin)?; let transactions = >::get(block).ok_or(Error::::RenewedNotFound)?; let info = transactions.get(index as usize).ok_or(Error::::RenewedNotFound)?; + let extrinsic_index = + >::extrinsic_index().ok_or(Error::::BadContext)?; + Self::apply_fee(sender, info.size)?; - let extrinsic_index = >::extrinsic_index().unwrap(); sp_io::transaction_index::renew(extrinsic_index, info.content_hash.into()); let mut index = 0; diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index 6efc847bfbdb7..236a515a2412d 100644 --- a/primitives/state-machine/src/basic.rs +++ b/primitives/state-machine/src/basic.rs @@ -17,14 +17,13 @@ //! Basic implementation for Externalities. -use crate::{Backend, StorageKey, StorageValue}; +use crate::{Backend, OverlayedChanges, StorageKey, StorageValue}; use codec::Encode; use hash_db::Hasher; use log::warn; use sp_core::{ storage::{ - well_known_keys::is_child_storage_key, ChildInfo, StateVersion, Storage, StorageChild, - TrackedStorageKey, + well_known_keys::is_child_storage_key, ChildInfo, StateVersion, Storage, TrackedStorageKey, }, traits::Externalities, Blake2Hasher, @@ -35,20 +34,19 @@ use std::{ any::{Any, TypeId}, collections::BTreeMap, iter::FromIterator, - ops::Bound, }; /// Simple Map-based Externalities impl. #[derive(Debug)] pub struct BasicExternalities { - inner: Storage, + overlay: OverlayedChanges, extensions: Extensions, } impl BasicExternalities { /// Create a new instance of `BasicExternalities` pub fn new(inner: Storage) -> Self { - BasicExternalities { inner, extensions: Default::default() } + BasicExternalities { overlay: inner.into(), extensions: Default::default() } } /// New basic externalities with empty storage. @@ -57,13 +55,34 @@ impl BasicExternalities { } /// Insert key/value - pub fn insert(&mut self, k: StorageKey, v: StorageValue) -> Option { - self.inner.top.insert(k, v) + pub fn insert(&mut self, k: StorageKey, v: StorageValue) { + self.overlay.set_storage(k, Some(v)); } /// Consume self and returns inner storages pub fn into_storages(self) -> Storage { - self.inner + Storage { + top: self + .overlay + .changes() + .filter_map(|(k, v)| v.value().map(|v| (k.to_vec(), v.to_vec()))) + .collect(), + children_default: self + .overlay + .children() + .map(|(iter, i)| { + ( + i.storage_key().to_vec(), + sp_core::storage::StorageChild { + data: iter + .filter_map(|(k, v)| v.value().map(|v| (k.to_vec(), v.to_vec()))) + .collect(), + child_info: i.clone(), + }, + ) + }) + .collect(), + } } /// Execute the given closure `f` with the externalities set and initialized with `storage`. @@ -73,13 +92,7 @@ impl BasicExternalities { storage: &mut sp_core::storage::Storage, f: impl FnOnce() -> R, ) -> R { - let mut ext = Self { - inner: Storage { - top: std::mem::take(&mut storage.top), - children_default: std::mem::take(&mut storage.children_default), - }, - extensions: Default::default(), - }; + let mut ext = Self::new(std::mem::take(storage)); let r = ext.execute_with(f); @@ -108,15 +121,26 @@ impl BasicExternalities { impl PartialEq for BasicExternalities { fn eq(&self, other: &BasicExternalities) -> bool { - self.inner.top.eq(&other.inner.top) && - self.inner.children_default.eq(&other.inner.children_default) + self.overlay.changes().map(|(k, v)| (k, v.value())).collect::>() == + other.overlay.changes().map(|(k, v)| (k, v.value())).collect::>() && + self.overlay + .children() + .map(|(iter, i)| (i, iter.map(|(k, v)| (k, v.value())).collect::>())) + .collect::>() == + other + .overlay + .children() + .map(|(iter, i)| { + (i, iter.map(|(k, v)| (k, v.value())).collect::>()) + }) + .collect::>() } } impl FromIterator<(StorageKey, StorageValue)> for BasicExternalities { fn from_iter>(iter: I) -> Self { let mut t = Self::default(); - t.inner.top.extend(iter); + iter.into_iter().for_each(|(k, v)| t.insert(k, v)); t } } @@ -128,11 +152,8 @@ impl Default for BasicExternalities { } impl From> for BasicExternalities { - fn from(hashmap: BTreeMap) -> Self { - BasicExternalities { - inner: Storage { top: hashmap, children_default: Default::default() }, - extensions: Default::default(), - } + fn from(map: BTreeMap) -> Self { + Self::from_iter(map.into_iter()) } } @@ -140,7 +161,7 @@ impl Externalities for BasicExternalities { fn set_offchain_storage(&mut self, _key: &[u8], _value: Option<&[u8]>) {} fn storage(&self, key: &[u8]) -> Option { - self.inner.top.get(key).cloned() + self.overlay.storage(key).and_then(|v| v.map(|v| v.to_vec())) } fn storage_hash(&self, key: &[u8]) -> Option> { @@ -148,11 +169,7 @@ impl Externalities for BasicExternalities { } fn child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> Option { - self.inner - .children_default - .get(child_info.storage_key()) - .and_then(|child| child.data.get(key)) - .cloned() + self.overlay.child_storage(child_info, key).and_then(|v| v.map(|v| v.to_vec())) } fn child_storage_hash(&self, child_info: &ChildInfo, key: &[u8]) -> Option> { @@ -160,16 +177,13 @@ impl Externalities for BasicExternalities { } fn next_storage_key(&self, key: &[u8]) -> Option { - let range = (Bound::Excluded(key), Bound::Unbounded); - self.inner.top.range::<[u8], _>(range).next().map(|(k, _)| k).cloned() + self.overlay.iter_after(key).find_map(|(k, v)| v.value().map(|_| k.to_vec())) } fn next_child_storage_key(&self, child_info: &ChildInfo, key: &[u8]) -> Option { - let range = (Bound::Excluded(key), Bound::Unbounded); - self.inner - .children_default - .get(child_info.storage_key()) - .and_then(|child| child.data.range::<[u8], _>(range).next().map(|(k, _)| k).cloned()) + self.overlay + .child_iter_after(child_info.storage_key(), key) + .find_map(|(k, v)| v.value().map(|_| k.to_vec())) } fn place_storage(&mut self, key: StorageKey, maybe_value: Option) { @@ -178,14 +192,7 @@ impl Externalities for BasicExternalities { return } - match maybe_value { - Some(value) => { - self.inner.top.insert(key, value); - }, - None => { - self.inner.top.remove(&key); - }, - } + self.overlay.set_storage(key, maybe_value) } fn place_child_storage( @@ -194,19 +201,7 @@ impl Externalities for BasicExternalities { key: StorageKey, value: Option, ) { - let child_map = self - .inner - .children_default - .entry(child_info.storage_key().to_vec()) - .or_insert_with(|| StorageChild { - data: Default::default(), - child_info: child_info.to_owned(), - }); - if let Some(value) = value { - child_map.data.insert(key, value); - } else { - child_map.data.remove(&key); - } + self.overlay.set_child_storage(child_info, key, value); } fn kill_child_storage( @@ -215,12 +210,7 @@ impl Externalities for BasicExternalities { _maybe_limit: Option, _maybe_cursor: Option<&[u8]>, ) -> MultiRemovalResults { - let count = self - .inner - .children_default - .remove(child_info.storage_key()) - .map(|c| c.data.len()) - .unwrap_or(0) as u32; + let count = self.overlay.clear_child_storage(child_info); MultiRemovalResults { maybe_cursor: None, backend: count, unique: count, loops: count } } @@ -239,19 +229,7 @@ impl Externalities for BasicExternalities { return MultiRemovalResults { maybe_cursor, backend: 0, unique: 0, loops: 0 } } - let to_remove = self - .inner - .top - .range::<[u8], _>((Bound::Included(prefix), Bound::Unbounded)) - .map(|(k, _)| k) - .take_while(|k| k.starts_with(prefix)) - .cloned() - .collect::>(); - - let count = to_remove.len() as u32; - for key in to_remove { - self.inner.top.remove(&key); - } + let count = self.overlay.clear_prefix(prefix); MultiRemovalResults { maybe_cursor: None, backend: count, unique: count, loops: count } } @@ -262,56 +240,37 @@ impl Externalities for BasicExternalities { _maybe_limit: Option, _maybe_cursor: Option<&[u8]>, ) -> MultiRemovalResults { - if let Some(child) = self.inner.children_default.get_mut(child_info.storage_key()) { - let to_remove = child - .data - .range::<[u8], _>((Bound::Included(prefix), Bound::Unbounded)) - .map(|(k, _)| k) - .take_while(|k| k.starts_with(prefix)) - .cloned() - .collect::>(); - - let count = to_remove.len() as u32; - for key in to_remove { - child.data.remove(&key); - } - MultiRemovalResults { maybe_cursor: None, backend: count, unique: count, loops: count } - } else { - MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 } - } + let count = self.overlay.clear_child_prefix(child_info, prefix); + MultiRemovalResults { maybe_cursor: None, backend: count, unique: count, loops: count } } fn storage_append(&mut self, key: Vec, value: Vec) { - let current = self.inner.top.entry(key).or_default(); - crate::ext::StorageAppend::new(current).append(value); + let current_value = self.overlay.value_mut_or_insert_with(&key, || Default::default()); + crate::ext::StorageAppend::new(current_value).append(value); } fn storage_root(&mut self, state_version: StateVersion) -> Vec { - let mut top = self.inner.top.clone(); - let prefixed_keys: Vec<_> = self - .inner - .children_default - .iter() - .map(|(_k, v)| (v.child_info.prefixed_storage_key(), v.child_info.clone())) - .collect(); + let mut top = self + .overlay + .changes() + .filter_map(|(k, v)| v.value().map(|v| (k.clone(), v.clone()))) + .collect::>(); // Single child trie implementation currently allows using the same child // empty root for all child trie. Using null storage key until multiple // type of child trie support. let empty_hash = empty_child_trie_root::>(); - for (prefixed_storage_key, child_info) in prefixed_keys { + for child_info in self.overlay.children().map(|d| d.1.clone()).collect::>() { let child_root = self.child_storage_root(&child_info, state_version); if empty_hash[..] == child_root[..] { - top.remove(prefixed_storage_key.as_slice()); + top.remove(child_info.prefixed_storage_key().as_slice()); } else { - top.insert(prefixed_storage_key.into_inner(), child_root); + top.insert(child_info.prefixed_storage_key().into_inner(), child_root); } } match state_version { - StateVersion::V0 => - LayoutV0::::trie_root(self.inner.top.clone()).as_ref().into(), - StateVersion::V1 => - LayoutV1::::trie_root(self.inner.top.clone()).as_ref().into(), + StateVersion::V0 => LayoutV0::::trie_root(top).as_ref().into(), + StateVersion::V1 => LayoutV1::::trie_root(top).as_ref().into(), } } @@ -320,10 +279,11 @@ impl Externalities for BasicExternalities { child_info: &ChildInfo, state_version: StateVersion, ) -> Vec { - if let Some(child) = self.inner.children_default.get(child_info.storage_key()) { - let delta = child.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))); + if let Some((data, child_info)) = self.overlay.child_changes(child_info.storage_key()) { + let delta = + data.into_iter().map(|(k, v)| (k.as_ref(), v.value().map(|v| v.as_slice()))); crate::in_memory_backend::new_in_mem::>() - .child_storage_root(&child.child_info, delta, state_version) + .child_storage_root(&child_info, delta, state_version) .0 } else { empty_child_trie_root::>() @@ -332,15 +292,15 @@ impl Externalities for BasicExternalities { } fn storage_start_transaction(&mut self) { - unimplemented!("Transactions are not supported by BasicExternalities"); + self.overlay.start_transaction() } fn storage_rollback_transaction(&mut self) -> Result<(), ()> { - unimplemented!("Transactions are not supported by BasicExternalities"); + self.overlay.rollback_transaction().map_err(drop) } fn storage_commit_transaction(&mut self) -> Result<(), ()> { - unimplemented!("Transactions are not supported by BasicExternalities"); + self.overlay.commit_transaction().map_err(drop) } fn wipe(&mut self) {} diff --git a/primitives/state-machine/src/overlayed_changes/changeset.rs b/primitives/state-machine/src/overlayed_changes/changeset.rs index ae5d47f6bb943..e5dad7157c731 100644 --- a/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -57,7 +57,7 @@ pub struct NotInRuntime; /// Describes in which mode the node is currently executing. #[derive(Debug, Clone, Copy)] pub enum ExecutionMode { - /// Exeuting in client mode: Removal of all transactions possible. + /// Executing in client mode: Removal of all transactions possible. Client, /// Executing in runtime mode: Transactions started by the client are protected. Runtime, @@ -95,7 +95,7 @@ pub type OverlayedChangeSet = OverlayedMap>; /// Holds a set of changes with the ability modify them using nested transactions. #[derive(Debug, Clone)] -pub struct OverlayedMap { +pub struct OverlayedMap { /// Stores the changes that this overlay constitutes. changes: BTreeMap>, /// Stores which keys are dirty per transaction. Needed in order to determine which @@ -110,7 +110,7 @@ pub struct OverlayedMap { execution_mode: ExecutionMode, } -impl Default for OverlayedMap { +impl Default for OverlayedMap { fn default() -> Self { Self { changes: BTreeMap::new(), @@ -121,6 +121,31 @@ impl Default for OverlayedMap { } } +#[cfg(feature = "std")] +impl From for OverlayedMap> { + fn from(storage: sp_core::storage::StorageMap) -> Self { + Self { + changes: storage + .into_iter() + .map(|(k, v)| { + ( + k, + OverlayedEntry { + transactions: SmallVec::from_iter([InnerValue { + value: Some(v), + extrinsics: Default::default(), + }]), + }, + ) + }) + .collect(), + dirty_keys: Default::default(), + num_client_transactions: 0, + execution_mode: ExecutionMode::Client, + } + } +} + impl Default for ExecutionMode { fn default() -> Self { Self::Client diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index 746599a6768e6..001b4b656c34e 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -638,6 +638,21 @@ impl OverlayedChanges { } } +#[cfg(feature = "std")] +impl From for OverlayedChanges { + fn from(storage: sp_core::storage::Storage) -> Self { + Self { + top: storage.top.into(), + children: storage + .children_default + .into_iter() + .map(|(k, v)| (k, (v.data.into(), v.child_info))) + .collect(), + ..Default::default() + } + } +} + #[cfg(feature = "std")] fn retain_map(map: &mut Map, f: F) where From 389cc11d8d836a28cd4462bf8f63a36ff794a976 Mon Sep 17 00:00:00 2001 From: yjh Date: Thu, 11 Aug 2022 17:59:38 +0800 Subject: [PATCH 1051/1472] chore: improve runtime docs and remove unused error (#12000) --- Cargo.lock | 1 - client/executor/common/Cargo.toml | 1 - client/executor/common/src/error.rs | 4 ---- client/executor/src/native_executor.rs | 11 +++++++---- primitives/runtime-interface/src/lib.rs | 4 ++-- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38063e8060835..a5cd455e6029b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8188,7 +8188,6 @@ dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", "sp-sandbox", - "sp-serializer", "sp-wasm-interface", "thiserror", "wasm-instrument", diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 9ffdfb788474d..b16ed7e8552ce 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -23,7 +23,6 @@ wasmi = "0.9.1" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } -sp-serializer = { version = "4.0.0-dev", path = "../../../primitives/serializer" } sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface" } [features] diff --git a/client/executor/common/src/error.rs b/client/executor/common/src/error.rs index 09e070bb3bae5..376ac190bd7b7 100644 --- a/client/executor/common/src/error.rs +++ b/client/executor/common/src/error.rs @@ -18,7 +18,6 @@ //! Rust executor possible errors. -use sp_serializer; use wasmi; /// Result type alias. @@ -28,9 +27,6 @@ pub type Result = std::result::Result; #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { - #[error("Unserializable data encountered")] - InvalidData(#[from] sp_serializer::Error), - #[error(transparent)] Wasmi(#[from] wasmi::Error), diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index d805949d26fd9..4d8f559d700b5 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -130,14 +130,13 @@ where /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. /// Defaults to `DEFAULT_HEAP_PAGES` if `None` is provided. /// - /// `host_functions` - The set of host functions to be available for import provided by this - /// executor. - /// /// `max_runtime_instances` - The number of runtime instances to keep in memory ready for reuse. /// /// `cache_path` - A path to a directory where the executor can place its files for purposes of /// caching. This may be important in cases when there are many different modules with the /// compiled execution method is used. + /// + /// `runtime_cache_size` - The capacity of runtime cache. pub fn new( method: WasmExecutionMethod, default_heap_pages: Option, @@ -209,7 +208,7 @@ where /// The runtime is passed as a [`RuntimeBlob`]. The runtime will be instantiated with the /// parameters this `WasmExecutor` was initialized with. /// - /// In case of problems with during creation of the runtime or instantation, a `Err` is + /// In case of problems with during creation of the runtime or instantiation, a `Err` is /// returned. that describes the message. #[doc(hidden)] // We use this function for tests across multiple crates. pub fn uncached_call( @@ -405,6 +404,10 @@ impl NativeElseWasmExecutor { /// /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. /// Defaults to `DEFAULT_HEAP_PAGES` if `None` is provided. + /// + /// `max_runtime_instances` - The number of runtime instances to keep in memory ready for reuse. + /// + /// `runtime_cache_size` - The capacity of runtime cache. pub fn new( fallback_method: WasmExecutionMethod, default_heap_pages: Option, diff --git a/primitives/runtime-interface/src/lib.rs b/primitives/runtime-interface/src/lib.rs index f9bf8825f9486..6ebcb7482a779 100644 --- a/primitives/runtime-interface/src/lib.rs +++ b/primitives/runtime-interface/src/lib.rs @@ -308,10 +308,10 @@ pub use sp_std; /// /// 1. The generated functions are not callable from the native side. /// 2. The trait as shown above is not implemented for [`Externalities`] and is instead -/// implemented for `FunctionExecutor` (from `sp-wasm-interface`). +/// implemented for `FunctionContext` (from `sp-wasm-interface`). /// /// # Disable tracing -/// By addding `no_tracing` to the list of options you can prevent the wasm-side interface from +/// By adding `no_tracing` to the list of options you can prevent the wasm-side interface from /// generating the default `sp-tracing`-calls. Note that this is rarely needed but only meant /// for the case when that would create a circular dependency. You usually _do not_ want to add /// this flag, as tracing doesn't cost you anything by default anyways (it is added as a no-op) From 6cd7ac7bd1e9da914adb7c8066d759f0a2d3849f Mon Sep 17 00:00:00 2001 From: lucasvanmol Date: Thu, 11 Aug 2022 06:13:49 -0700 Subject: [PATCH 1052/1472] Fix broken links in `polkadot --help` (#12010) https://docs.substrate.io/v3/runtime/custom-rpcs/#public-rpcs > https://docs.substrate.io/main-docs/build/custom-rpc/#public-rpcs --- client/cli/src/commands/run_cmd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 3a74fdd9700f2..fd236aa0211dd 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -54,7 +54,7 @@ pub struct RunCmd { /// /// Default is local. Note: not all RPC methods are safe to be exposed publicly. Use an RPC /// proxy server to filter out dangerous methods. More details: - /// . + /// . /// Use `--unsafe-rpc-external` to suppress the warning if you understand the risks. #[clap(long)] pub rpc_external: bool, @@ -85,7 +85,7 @@ pub struct RunCmd { /// /// Default is local. Note: not all RPC methods are safe to be exposed publicly. Use an RPC /// proxy server to filter out dangerous methods. More details: - /// . + /// . /// Use `--unsafe-ws-external` to suppress the warning if you understand the risks. #[clap(long)] pub ws_external: bool, From e3512480d5e6ff527b1f82c2b47618aaa824c9bb Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 11 Aug 2022 15:39:56 +0100 Subject: [PATCH 1053/1472] add decode with depth limit to opaque types (#11947) Co-authored-by: parity-processbot <> --- Cargo.lock | 1 + frame/support/Cargo.toml | 2 ++ frame/support/src/traits/misc.rs | 33 +++++++++++++++++++++++++++++--- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5cd455e6029b..2db192dcbf1a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2250,6 +2250,7 @@ dependencies = [ "serde", "serde_json", "smallvec", + "sp-api", "sp-arithmetic", "sp-core", "sp-core-hashing-proc-macro", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index ca26d3a5e32f2..a69133961e970 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -17,6 +17,7 @@ serde = { version = "1.0.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-metadata = { version = "15.0.0", default-features = false, features = ["v14"] } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } @@ -49,6 +50,7 @@ default = ["std"] std = [ "once_cell", "serde", + "sp-api/std", "sp-io/std", "codec/std", "scale-info/std", diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index ddb7f6f41b378..fa59fa92f920d 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -18,7 +18,7 @@ //! Smaller traits used in FRAME which don't need their own file. use crate::dispatch::Parameter; -use codec::{CompactLen, Decode, DecodeAll, Encode, EncodeLike, Input, MaxEncodedLen}; +use codec::{CompactLen, Decode, DecodeLimit, Encode, EncodeLike, Input, MaxEncodedLen}; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; use sp_arithmetic::traits::{CheckedAdd, CheckedMul, CheckedSub, Saturating}; #[doc(hidden)] @@ -745,7 +745,10 @@ impl Encode for WrapperOpaque { impl Decode for WrapperOpaque { fn decode(input: &mut I) -> Result { - Ok(Self(T::decode_all(&mut &>::decode(input)?[..])?)) + Ok(Self(T::decode_all_with_depth_limit( + sp_api::MAX_EXTRINSIC_DEPTH, + &mut &>::decode(input)?[..], + )?)) } fn skip(input: &mut I) -> Result<(), codec::Error> { @@ -807,7 +810,7 @@ impl WrapperKeepOpaque { /// /// Returns `None` if the decoding failed. pub fn try_decode(&self) -> Option { - T::decode_all(&mut &self.data[..]).ok() + T::decode_all_with_depth_limit(sp_api::MAX_EXTRINSIC_DEPTH, &mut &self.data[..]).ok() } /// Returns the length of the encoded `T`. @@ -939,6 +942,30 @@ impl PreimageRecipient for () { #[cfg(test)] mod test { use super::*; + use sp_std::marker::PhantomData; + + #[derive(Encode, Decode)] + enum NestedType { + Nested(Box), + Done, + } + + #[test] + fn test_opaque_wrapper_decode_limit() { + let limit = sp_api::MAX_EXTRINSIC_DEPTH as usize; + let mut ok_bytes = vec![0u8; limit]; + ok_bytes.push(1u8); + let mut err_bytes = vec![0u8; limit + 1]; + err_bytes.push(1u8); + assert!(>::decode(&mut &ok_bytes.encode()[..]).is_ok()); + assert!(>::decode(&mut &err_bytes.encode()[..]).is_err()); + + let ok_keep_opaque = WrapperKeepOpaque { data: ok_bytes, _phantom: PhantomData }; + let err_keep_opaque = WrapperKeepOpaque { data: err_bytes, _phantom: PhantomData }; + + assert!(>::try_decode(&ok_keep_opaque).is_some()); + assert!(>::try_decode(&err_keep_opaque).is_none()); + } #[test] fn test_opaque_wrapper() { From dc45cc29167ee6358b527f3a0bcc0617dc9e4c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 11 Aug 2022 16:53:40 +0200 Subject: [PATCH 1054/1472] Use correct length for Pallet and Storage prefix when calculating `KeyLenOf` (#11994) * Use correct length for Pallet and Storage prefix when calculating `KeyLenOf` * Add tests Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/support/src/storage/types/double_map.rs | 19 ++++++++++--- frame/support/src/storage/types/map.rs | 27 +++++++++++++++++-- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 2e090d30119aa..9ba4cf052e82a 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -25,6 +25,7 @@ use crate::{ KeyLenOf, StorageAppend, StorageDecodeLength, StoragePrefixedMap, StorageTryAppend, }, traits::{Get, GetDefault, StorageInfo, StorageInstance}, + StorageHasher, Twox128, }; use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::SaturatedConversion; @@ -91,10 +92,10 @@ impl Key2: MaxEncodedLen, { fn get() -> u32 { - let z = Hasher1::max_len::() + - Hasher2::max_len::() + - Prefix::pallet_prefix().len() + - Prefix::STORAGE_PREFIX.len(); + // The `max_len` of both key hashes plus the pallet prefix and storage prefix (which both + // are hashed with `Twox128`). + let z = + Hasher1::max_len::() + Hasher2::max_len::() + Twox128::max_len::<()>() * 2; z as u32 } } @@ -755,6 +756,16 @@ mod test { } } + #[test] + fn keylenof_works() { + // Works with Blake2_128Concat and Twox64Concat. + type A = StorageDoubleMap; + let size = 16 * 2 // Two Twox128 + + 16 + 8 // Blake2_128Concat = hash + key + + 8 + 4; // Twox64Concat = hash + key + assert_eq!(KeyLenOf::::get(), size); + } + #[test] fn test() { type A = diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index f4ac83c22663b..0f89e2378a55d 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -25,6 +25,7 @@ use crate::{ KeyLenOf, StorageAppend, StorageDecodeLength, StoragePrefixedMap, StorageTryAppend, }, traits::{Get, GetDefault, StorageInfo, StorageInstance}, + StorageHasher, Twox128, }; use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::SaturatedConversion; @@ -61,8 +62,9 @@ where Key: FullCodec + MaxEncodedLen, { fn get() -> u32 { - let z = - Hasher::max_len::() + Prefix::pallet_prefix().len() + Prefix::STORAGE_PREFIX.len(); + // The `max_len` of the key hash plus the pallet prefix and storage prefix (which both are + // hashed with `Twox128`). + let z = Hasher::max_len::() + Twox128::max_len::<()>() * 2; z as u32 } } @@ -501,6 +503,27 @@ mod test { } } + #[test] + fn keylenof_works() { + // Works with Blake2_128Concat. + type A = StorageMap; + let size = 16 * 2 // Two Twox128 + + 16 + 4; // Blake2_128Concat = hash + key + assert_eq!(KeyLenOf::::get(), size); + + // Works with Blake2_256. + type B = StorageMap; + let size = 16 * 2 // Two Twox128 + + 32; // Blake2_256 + assert_eq!(KeyLenOf::::get(), size); + + // Works with Twox64Concat. + type C = StorageMap; + let size = 16 * 2 // Two Twox128 + + 8 + 4; // Twox64Concat = hash + key + assert_eq!(KeyLenOf::::get(), size); + } + #[test] fn test() { type A = StorageMap; From 469189bfe16b61b238f7786c5d2cff82060ec8f8 Mon Sep 17 00:00:00 2001 From: benluelo <57334811+benluelo@users.noreply.github.com> Date: Thu, 11 Aug 2022 14:55:30 -0400 Subject: [PATCH 1055/1472] Add map and try_map methods to BoundedBTreeMap (#11869) * Add map and try_map methods to BoundedBTreeMap * Undo changes to basic_authorship.rs * Remove unwrap and use unchecked_from instead * Add iter_mut() method * Remove map functions and add docs to iter_mut * fmt Co-authored-by: Shawn Tabrizi --- .../runtime/src/bounded/bounded_btree_map.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/primitives/runtime/src/bounded/bounded_btree_map.rs b/primitives/runtime/src/bounded/bounded_btree_map.rs index aefd168632a1e..725864b462694 100644 --- a/primitives/runtime/src/bounded/bounded_btree_map.rs +++ b/primitives/runtime/src/bounded/bounded_btree_map.rs @@ -161,6 +161,13 @@ where { self.0.remove_entry(key) } + + /// Gets a mutable iterator over the entries of the map, sorted by key. + /// + /// See [`BTreeMap::iter_mut`] for more information. + pub fn iter_mut(&mut self) -> sp_std::collections::btree_map::IterMut { + self.0.iter_mut() + } } impl Default for BoundedBTreeMap @@ -508,7 +515,7 @@ pub mod test { b1.iter().map(|(k, v)| (k + 1, *v)).take(2).try_collect().unwrap(); assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3]); - // but these worn't work + // but these won't work let b2: Result>, _> = b1.iter().map(|(k, v)| (k + 1, *v)).try_collect(); assert!(b2.is_err()); @@ -517,4 +524,17 @@ pub mod test { b1.iter().map(|(k, v)| (k + 1, *v)).skip(2).try_collect(); assert!(b2.is_err()); } + + #[test] + fn test_iter_mut() { + let mut b1: BoundedBTreeMap> = + [1, 2, 3, 4].into_iter().map(|k| (k, k)).try_collect().unwrap(); + + let b2: BoundedBTreeMap> = + [1, 2, 3, 4].into_iter().map(|k| (k, k * 2)).try_collect().unwrap(); + + b1.iter_mut().for_each(|(_, v)| *v *= 2); + + assert_eq!(b1, b2); + } } From 6b8553511112afd5ae7e8e6877dc2f467850f155 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Fri, 12 Aug 2022 11:03:27 +0200 Subject: [PATCH 1056/1472] [ci] Improve cancel-pipeline job (#12008) * [WIP][ci] Improve cancel-pipeline job * fix job name * test that fail works * debug cancel-pipeline * remove artifacts-false from cancel-pipeline jobs * split cancel pipeline jobs * fail test-linux-stable 2/3 * fail test-linux-stable 3/3 * fail cargo-check-benches 1/2 * fail cargo-check-benches 2/2 * fail test-linux-stable-int * fail cargo-check-subkey * fail check-tracing * fail check-tracing * fix pipeline --- .gitlab-ci.yml | 60 ++++++++++++++++++++++------- scripts/ci/gitlab/pipeline/test.yml | 6 +++ 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9608d88e9554d..765112bfa9e62 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -82,18 +82,31 @@ default: tags: - kubernetes-parity-build -.rust-info-script: &rust-info-script +.rust-info-script: script: - rustup show - cargo --version - rustup +nightly show - cargo +nightly --version +.pipeline-stopper-vars: + script: + - echo "Collecting env variables for the cancel-pipeline job" + - echo "FAILED_JOB_URL=${CI_JOB_URL}" > pipeline-stopper.env + - echo "FAILED_JOB_NAME=${CI_JOB_NAME}" >> pipeline-stopper.env + - echo "PR_NUM=${CI_COMMIT_REF_NAME}" >> pipeline-stopper.env + +.pipeline-stopper-artifacts: + artifacts: + reports: + dotenv: pipeline-stopper.env + .docker-env: image: "${CI_IMAGE}" before_script: - !reference [.rust-info-script, script] - !reference [.rusty-cachier, before_script] + - !reference [.pipeline-stopper-vars, script] after_script: - !reference [.rusty-cachier, after_script] tags: @@ -246,35 +259,54 @@ rusty-cachier-notify: when: on_failure variables: PROJECT_ID: "${CI_PROJECT_ID}" + PROJECT_NAME: "${CI_PROJECT_NAME}" PIPELINE_ID: "${CI_PIPELINE_ID}" - trigger: "parity/infrastructure/ci_cd/pipeline-stopper" + FAILED_JOB_URL: "${FAILED_JOB_URL}" + FAILED_JOB_NAME: "${FAILED_JOB_NAME}" + PR_NUM: "${PR_NUM}" + trigger: + project: "parity/infrastructure/ci_cd/pipeline-stopper" + # remove branch, when pipeline-stopper for polakdot is updated to the same branch + branch: "as-improve" -cancel-pipeline-test-linux-stable: +# need to copy jobs this way because otherwise gitlab will wait +# for all 3 jobs to finish instead of cancelling if one fails +cancel-pipeline-test-linux-stable1: extends: .cancel-pipeline-template needs: - - job: test-linux-stable - artifacts: false + - job: "test-linux-stable 1/3" + +cancel-pipeline-test-linux-stable2: + extends: .cancel-pipeline-template + needs: + - job: "test-linux-stable 2/3" + +cancel-pipeline-test-linux-stable3: + extends: .cancel-pipeline-template + needs: + - job: "test-linux-stable 3/3" + +cancel-pipeline-cargo-check-benches1: + extends: .cancel-pipeline-template + needs: + - job: "cargo-check-benches 1/2" + +cancel-pipeline-cargo-check-benches2: + extends: .cancel-pipeline-template + needs: + - job: "cargo-check-benches 2/2" cancel-pipeline-test-linux-stable-int: extends: .cancel-pipeline-template needs: - job: test-linux-stable-int - artifacts: false cancel-pipeline-cargo-check-subkey: extends: .cancel-pipeline-template needs: - job: cargo-check-subkey - artifacts: false - -cancel-pipeline-cargo-check-benches: - extends: .cancel-pipeline-template - needs: - - job: cargo-check-benches - artifacts: false cancel-pipeline-check-tracing: extends: .cancel-pipeline-template needs: - job: check-tracing - artifacts: false diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index ccf8338236d0a..a58015c6e22d6 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -61,10 +61,12 @@ cargo-check-benches: - .docker-env - .test-refs - .collect-artifacts + - .pipeline-stopper-artifacts before_script: # perform rusty-cachier operations before any further modifications to the git repo to make cargo feel cheated not so much - !reference [.rust-info-script, script] - !reference [.rusty-cachier, before_script] + - !reference [.pipeline-stopper-vars, script] # merges in the master branch on PRs - if [ $CI_COMMIT_REF_NAME != "master" ]; then git fetch origin +master:master; @@ -131,6 +133,7 @@ cargo-check-subkey: extends: - .docker-env - .test-refs + - .pipeline-stopper-artifacts script: - rusty-cachier snapshot create - cd ./bin/utils/subkey @@ -199,6 +202,7 @@ test-linux-stable: extends: - .docker-env - .test-refs + - .pipeline-stopper-artifacts variables: # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. @@ -299,6 +303,7 @@ test-linux-stable-int: extends: - .docker-env - .test-refs + - .pipeline-stopper-artifacts variables: # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. @@ -328,6 +333,7 @@ check-tracing: extends: - .docker-env - .test-refs + - .pipeline-stopper-artifacts script: - rusty-cachier snapshot create # with-tracing must be explicitly activated, we run a test to ensure this works as expected in both cases From 241fc1f8a7e367420ee8c697a9a85b7ceb78713d Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Fri, 12 Aug 2022 16:34:00 +0100 Subject: [PATCH 1057/1472] better benchmark log (#12016) * better benchmark log * Update lib.rs --- frame/benchmarking/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index afd53915cc397..a1399dc388b09 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -1054,7 +1054,9 @@ macro_rules! impl_benchmark { // Time the extrinsic logic. $crate::log::trace!( target: "benchmark", - "Start Benchmark: {:?}", c + "Start Benchmark: {} ({:?})", + extrinsic, + c ); let start_pov = $crate::benchmarking::proof_size(); From bfbbf4c7fb1be8d2304b8da102c89fe286e70804 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 12 Aug 2022 17:39:05 +0200 Subject: [PATCH 1058/1472] feat(rpc middleware): use custom time buckets (#11950) * feat(rpc middleware): use custom time buckets * cargo fmt * make it compile again * fix bad comment --- client/rpc-servers/src/middleware.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/client/rpc-servers/src/middleware.rs b/client/rpc-servers/src/middleware.rs index 1c0660fc3528d..0d77442323241 100644 --- a/client/rpc-servers/src/middleware.rs +++ b/client/rpc-servers/src/middleware.rs @@ -25,6 +25,21 @@ use prometheus_endpoint::{ }; use std::net::SocketAddr; +/// Histogram time buckets in microseconds. +const HISTOGRAM_BUCKETS: [f64; 11] = [ + 5.0, + 25.0, + 100.0, + 500.0, + 1_000.0, + 2_500.0, + 10_000.0, + 25_000.0, + 100_000.0, + 1_000_000.0, + 10_000_000.0, +]; + /// Metrics for RPC middleware storing information about the number of requests started/completed, /// calls started/completed and their timings. #[derive(Debug, Clone)] @@ -75,7 +90,8 @@ impl RpcMetrics { HistogramOpts::new( "substrate_rpc_calls_time", "Total time [μs] of processed RPC calls", - ), + ) + .buckets(HISTOGRAM_BUCKETS.to_vec()), &["protocol", "method"], )?, metrics_registry, From 95a0c6a9d41628c3cc37f59dc42f5f45ca3f3977 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 12 Aug 2022 19:18:27 +0200 Subject: [PATCH 1059/1472] Add `defer` (#12013) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add defer Signed-off-by: Oliver Tale-Yazdi * Convert to macro + review fixes Signed-off-by: Oliver Tale-Yazdi * Apply suggestions from code review Co-authored-by: Bastian Köcher * Move into new file and add panic unwind tests Signed-off-by: Oliver Tale-Yazdi * Fix doc and Clippy Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher --- primitives/core/src/defer.rs | 140 +++++++++++++++++++++++++++++++++++ primitives/core/src/lib.rs | 1 + 2 files changed, 141 insertions(+) create mode 100644 primitives/core/src/defer.rs diff --git a/primitives/core/src/defer.rs b/primitives/core/src/defer.rs new file mode 100644 index 0000000000000..d14b26d59e4dd --- /dev/null +++ b/primitives/core/src/defer.rs @@ -0,0 +1,140 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains the [`crate::defer!`] macro for *deferring* the execution +//! of code until the current scope is dropped. +//! This helps with *always* executing cleanup code. + +/// Executes the wrapped closure on drop. +/// +/// Should be used together with the [`crate::defer!`] macro. +#[must_use] +pub struct DeferGuard(pub Option); + +impl Drop for DeferGuard { + fn drop(&mut self) { + self.0.take().map(|f| f()); + } +} + +/// Executes the given code when the current scope is dropped. +/// +/// Multiple calls to [`crate::defer!`] will execute the passed codes in reverse order. +/// This also applies to panic stack unwinding. +/// +/// # Example +/// +/// ```rust +/// use sp_core::defer; +/// +/// let message = std::cell::RefCell::new("".to_string()); +/// { +/// defer!( +/// message.borrow_mut().push_str("world!"); +/// ); +/// defer!( +/// message.borrow_mut().push_str("Hello "); +/// ); +/// } +/// assert_eq!(*message.borrow(), "Hello world!"); +/// ``` +#[macro_export] +macro_rules! defer( + ( $( $code:tt )* ) => { + let _guard = $crate::defer::DeferGuard(Some(|| { $( $code )* })); + }; +); + +#[cfg(test)] +mod test { + #[test] + fn defer_guard_works() { + let mut called = false; + { + defer!( + called = true; + ); + } + assert!(called, "DeferGuard should have executed the closure"); + } + + #[test] + /// `defer` executes the code in reverse order of being called. + fn defer_guard_order_works() { + let called = std::cell::RefCell::new(1); + + defer!( + assert_eq!(*called.borrow(), 3); + ); + defer!( + assert_eq!(*called.borrow(), 2); + *called.borrow_mut() = 3; + ); + defer!({ + assert_eq!(*called.borrow(), 1); + *called.borrow_mut() = 2; + }); + } + + #[test] + #[allow(unused_braces)] + #[allow(clippy::unnecessary_operation)] + fn defer_guard_syntax_works() { + let called = std::cell::RefCell::new(0); + { + defer!(*called.borrow_mut() += 1); + defer!(*called.borrow_mut() += 1;); // With ; + defer!({ *called.borrow_mut() += 1 }); + defer!({ *called.borrow_mut() += 1 };); // With ; + } + assert_eq!(*called.borrow(), 4); + } + + #[test] + /// `defer` executes the code even in case of a panic. + fn defer_guard_panic_unwind_works() { + use std::panic::{catch_unwind, AssertUnwindSafe}; + let mut called = false; + + let should_panic = catch_unwind(AssertUnwindSafe(|| { + defer!(called = true); + panic!(); + })); + + assert!(should_panic.is_err(), "DeferGuard should have panicked"); + assert!(called, "DeferGuard should have executed the closure"); + } + + #[test] + /// `defer` executes the code even in case another `defer` panics. + fn defer_guard_defer_panics_unwind_works() { + use std::panic::{catch_unwind, AssertUnwindSafe}; + let counter = std::cell::RefCell::new(0); + + let should_panic = catch_unwind(AssertUnwindSafe(|| { + defer!(*counter.borrow_mut() += 1); + defer!( + *counter.borrow_mut() += 1; + panic!(); + ); + defer!(*counter.borrow_mut() += 1); + })); + + assert!(should_panic.is_err(), "DeferGuard should have panicked"); + assert_eq!(*counter.borrow(), 3, "DeferGuard should have executed the closure"); + } +} diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index ab3334f9e4f5a..f48adc274f524 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -56,6 +56,7 @@ pub use hashing::{blake2_128, blake2_256, keccak_256, twox_128, twox_256, twox_6 pub mod crypto; pub mod hexdisplay; +pub mod defer; pub mod ecdsa; pub mod ed25519; pub mod hash; From c1293d4adec3aac82de9620842ae7f3cc0c97915 Mon Sep 17 00:00:00 2001 From: Tsvetomir Dimitrov Date: Sat, 13 Aug 2022 14:56:40 +0300 Subject: [PATCH 1060/1472] Runtime API versioning (#11779) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Runtime API versioning Related to issue #11577 Add support for multiple versions of a Runtime API. The purpose is to have one main version of the API, which is considered stable and multiple unstable (aka staging) ones. How it works =========== Some methods of the API trait can be tagged with `#[api_version(N)]` attribute where N is version number bigger than the main one. Let's call them **staging methods** for brevity. The implementor of the API decides which version to implement. Example (from https://github.com/paritytech/substrate/issues/11577#issuecomment-1145347025): ``` decl_runtime_apis! { #{api_version(10)] trait Test { fn something() -> Vec; #[api_version(11)] fn new_cool_function() -> u32; } } ``` ``` impl_runtime_apis! { #[api_version(11)] impl Test for Runtime { fn something() -> Vec { vec![1, 2, 3] } fn new_cool_function() -> u32 { 10 } } } ``` Version safety checks (currently not implemented) ================================================= By default in the API trait all staging methods has got default implementation calling `unimplemented!()`. This is a problem because if the developer wants to implement version 11 in the example above and forgets to add `fn new_cool_function()` in `impl_runtime_apis!` the runtime will crash when the function is executed. Ideally a compilation error should be generated in such cases. TODOs ===== Things not working well at the moment: [ ] Version safety check [ ] Integration tests of `primitives/api` are messed up a bit. More specifically `primitives/api/test/tests/decl_and_impl.rs` [ ] Integration test covering the new functionality. [ ] Some duplicated code * Update primitives/api/proc-macro/src/impl_runtime_apis.rs Code review feedback and formatting Co-authored-by: asynchronous rob * Code review feedback Applying suggestions from @bkchr * fmt * Apply suggestions from code review Co-authored-by: Bastian Köcher * Code review feedback * dummy trait -> versioned trait * Implement only versioned traits (not compiling) * Remove native API calls (still not compiling) * fmt * Fix compilation * Comments * Remove unused code * Remove native runtime tests * Remove unused code * Fix UI tests * Code review feedback * Code review feedback * attribute_names -> common * Rework `append_api_version` * Code review feedback * Apply suggestions from code review Co-authored-by: Bastian Köcher * Code review feedback * Code review feedback * Code review feedback * Use type alias for the default trait - doesn't compile * Fixes * Better error for `method_api_ver < trait_api_version` * fmt * Rework how we call runtime functions * Update UI tests * Fix warnings * Fix doctests * Apply suggestions from code review Co-authored-by: Bastian Köcher * Apply suggestions from code review Co-authored-by: Bastian Köcher * Fix formatting and small compilation errors * Update primitives/api/proc-macro/src/impl_runtime_apis.rs Co-authored-by: Bastian Köcher Co-authored-by: asynchronous rob Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- primitives/api/proc-macro/src/common.rs | 41 + .../api/proc-macro/src/decl_runtime_apis.rs | 699 +++++++----------- .../api/proc-macro/src/impl_runtime_apis.rs | 319 ++++---- primitives/api/proc-macro/src/lib.rs | 1 + .../proc-macro/src/mock_impl_runtime_apis.rs | 134 +++- primitives/api/proc-macro/src/utils.rs | 43 +- primitives/api/src/lib.rs | 82 +- primitives/api/test/tests/decl_and_impl.rs | 39 +- primitives/api/test/tests/runtime_calls.rs | 24 +- primitives/api/test/tests/trybuild.rs | 1 + .../ui/impl_incorrect_method_signature.stderr | 43 -- .../api/test/tests/ui/impl_missing_version.rs | 40 + .../test/tests/ui/impl_missing_version.stderr | 14 + ...pi_version.rs => invalid_api_version_1.rs} | 0 ...on.stderr => invalid_api_version_1.stderr} | 4 +- .../tests/ui/invalid_api_version_2.stderr | 4 +- .../tests/ui/invalid_api_version_3.stderr | 4 +- .../test/tests/ui/invalid_api_version_4.rs | 8 + .../tests/ui/invalid_api_version_4.stderr | 5 + .../ui/method_ver_lower_than_trait_ver.rs | 9 + .../ui/method_ver_lower_than_trait_ver.stderr | 11 + .../test/tests/ui/missing_versioned_method.rs | 39 + .../tests/ui/missing_versioned_method.stderr | 8 + .../missing_versioned_method_multiple_vers.rs | 42 ++ ...sing_versioned_method_multiple_vers.stderr | 8 + .../ui/mock_advanced_block_id_by_value.rs | 2 +- .../ui/mock_advanced_block_id_by_value.stderr | 4 +- .../tests/ui/mock_advanced_missing_blockid.rs | 2 +- .../ui/mock_advanced_missing_blockid.stderr | 4 +- .../tests/ui/mock_only_self_reference.stderr | 74 +- .../tests/ui/positive_cases/default_impls.rs | 41 + ...reference_in_impl_runtime_apis_call.stderr | 43 -- 32 files changed, 937 insertions(+), 855 deletions(-) create mode 100644 primitives/api/proc-macro/src/common.rs create mode 100644 primitives/api/test/tests/ui/impl_missing_version.rs create mode 100644 primitives/api/test/tests/ui/impl_missing_version.stderr rename primitives/api/test/tests/ui/{invalid_api_version.rs => invalid_api_version_1.rs} (100%) rename primitives/api/test/tests/ui/{invalid_api_version.stderr => invalid_api_version_1.stderr} (65%) create mode 100644 primitives/api/test/tests/ui/invalid_api_version_4.rs create mode 100644 primitives/api/test/tests/ui/invalid_api_version_4.stderr create mode 100644 primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.rs create mode 100644 primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.stderr create mode 100644 primitives/api/test/tests/ui/missing_versioned_method.rs create mode 100644 primitives/api/test/tests/ui/missing_versioned_method.stderr create mode 100644 primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs create mode 100644 primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.stderr create mode 100644 primitives/api/test/tests/ui/positive_cases/default_impls.rs diff --git a/primitives/api/proc-macro/src/common.rs b/primitives/api/proc-macro/src/common.rs new file mode 100644 index 0000000000000..10887be613278 --- /dev/null +++ b/primitives/api/proc-macro/src/common.rs @@ -0,0 +1,41 @@ +// This file is part of Substrate. + +// Copyright (C) 2018-2024 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// The ident used for the block generic parameter. +pub const BLOCK_GENERIC_IDENT: &str = "Block"; + +/// Unique identifier used to make the hidden includes unique for this macro. +pub const HIDDEN_INCLUDES_ID: &str = "DECL_RUNTIME_APIS"; + +/// The `core_trait` attribute. +pub const CORE_TRAIT_ATTRIBUTE: &str = "core_trait"; +/// The `api_version` attribute. +/// +/// Is used to set the current version of the trait. +pub const API_VERSION_ATTRIBUTE: &str = "api_version"; +/// The `changed_in` attribute. +/// +/// Is used when the function signature changed between different versions of a trait. +/// This attribute should be placed on the old signature of the function. +pub const CHANGED_IN_ATTRIBUTE: &str = "changed_in"; +/// The `renamed` attribute. +/// +/// Is used when a trait method was renamed. +pub const RENAMED_ATTRIBUTE: &str = "renamed"; +/// All attributes that we support in the declaration of a runtime api trait. +pub const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = + &[CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE, RENAMED_ATTRIBUTE]; diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index b031c0f8bb1cc..aac4491720c34 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -16,11 +16,15 @@ // limitations under the License. use crate::utils::{ - extract_parameter_names_types_and_borrows, fold_fn_decl_for_client_side, - generate_call_api_at_fn_name, generate_crate_access, generate_hidden_includes, - generate_method_runtime_api_impl_name, generate_native_call_generator_fn_name, - generate_runtime_mod_name_for_trait, prefix_function_with_trait, - replace_wild_card_parameter_names, return_type_extract_type, AllowSelfRefInParameters, + extract_parameter_names_types_and_borrows, fold_fn_decl_for_client_side, generate_crate_access, + generate_hidden_includes, generate_runtime_mod_name_for_trait, parse_runtime_api_version, + prefix_function_with_trait, replace_wild_card_parameter_names, return_type_extract_type, + versioned_trait_name, AllowSelfRefInParameters, +}; + +use crate::common::{ + API_VERSION_ATTRIBUTE, BLOCK_GENERIC_IDENT, CHANGED_IN_ATTRIBUTE, CORE_TRAIT_ATTRIBUTE, + HIDDEN_INCLUDES_ID, RENAMED_ATTRIBUTE, SUPPORTED_ATTRIBUTE_NAMES, }; use proc_macro2::{Span, TokenStream}; @@ -33,36 +37,11 @@ use syn::{ parse_macro_input, parse_quote, spanned::Spanned, visit::{self, Visit}, - Attribute, FnArg, GenericParam, Generics, Ident, ItemTrait, Lit, Meta, NestedMeta, ReturnType, - TraitBound, TraitItem, TraitItemMethod, Type, + Attribute, FnArg, GenericParam, Generics, Ident, ItemTrait, Lit, Meta, NestedMeta, TraitBound, + TraitItem, TraitItemMethod, }; -use std::collections::HashMap; - -/// The ident used for the block generic parameter. -const BLOCK_GENERIC_IDENT: &str = "Block"; - -/// Unique identifier used to make the hidden includes unique for this macro. -const HIDDEN_INCLUDES_ID: &str = "DECL_RUNTIME_APIS"; - -/// The `core_trait` attribute. -const CORE_TRAIT_ATTRIBUTE: &str = "core_trait"; -/// The `api_version` attribute. -/// -/// Is used to set the current version of the trait. -const API_VERSION_ATTRIBUTE: &str = "api_version"; -/// The `changed_in` attribute. -/// -/// Is used when the function signature changed between different versions of a trait. -/// This attribute should be placed on the old signature of the function. -const CHANGED_IN_ATTRIBUTE: &str = "changed_in"; -/// The `renamed` attribute. -/// -/// Is used when a trait method was renamed. -const RENAMED_ATTRIBUTE: &str = "renamed"; -/// All attributes that we support in the declaration of a runtime api trait. -const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = - &[CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE, RENAMED_ATTRIBUTE]; +use std::collections::{BTreeMap, HashMap}; /// The structure used for parsing the runtime api declarations. struct RuntimeApiDecls { @@ -119,20 +98,6 @@ impl<'ast> Visit<'ast> for IsUsingBlock { } } -/// Visits the ast and checks if `Block` ident is used somewhere. -fn type_is_using_block(ty: &Type) -> bool { - let mut visitor = IsUsingBlock { result: false }; - visitor.visit_type(ty); - visitor.result -} - -/// Visits the ast and checks if `Block` ident is used somewhere. -fn return_type_is_using_block(ty: &ReturnType) -> bool { - let mut visitor = IsUsingBlock { result: false }; - visitor.visit_return_type(ty); - visitor.result -} - /// Replace all occurrences of `Block` with `NodeBlock` struct ReplaceBlockWithNodeBlock {} @@ -146,146 +111,69 @@ impl Fold for ReplaceBlockWithNodeBlock { } } -/// Replace all occurrences of `Block` with `NodeBlock` -fn fn_arg_replace_block_with_node_block(fn_arg: FnArg) -> FnArg { - let mut replace = ReplaceBlockWithNodeBlock {}; - fold::fold_fn_arg(&mut replace, fn_arg) -} - -/// Replace all occurrences of `Block` with `NodeBlock` -fn return_type_replace_block_with_node_block(return_type: ReturnType) -> ReturnType { - let mut replace = ReplaceBlockWithNodeBlock {}; - fold::fold_return_type(&mut replace, return_type) -} - -/// Generate the functions that generate the native call closure for each trait method. -fn generate_native_call_generators(decl: &ItemTrait) -> Result { - let fns = decl.items.iter().filter_map(|i| match i { - TraitItem::Method(ref m) => Some(&m.sig), - _ => None, - }); - - let mut result = Vec::new(); - let trait_ = &decl.ident; - let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); - - // Auxiliary function that is used to convert between types that use different block types. - // The function expects that both are convertible by encoding the one and decoding the other. - result.push(quote!( - #[cfg(any(feature = "std", test))] - fn convert_between_block_types - #crate_::ApiError>( - input: &I, - map_error: F, - ) -> std::result::Result - { - ::decode_with_depth_limit( - #crate_::MAX_EXTRINSIC_DEPTH, - &mut &#crate_::Encode::encode(input)[..], - ).map_err(map_error) +/// Versioned API traits are used to catch missing methods when implementing a specific version of a +/// versioned API. They contain all non-versioned methods (aka stable methods) from the main trait +/// and all versioned methods for the specific version. This means that there is one trait for each +/// version mentioned in the trait definition. For example: +/// ```ignore +/// // The trait version implicitly is 1 +/// decl_runtime_apis!( +/// trait SomeApi { +/// fn method1(); // this is a 'stable method' +/// +/// #[api_version(2)] +/// fn method2(); +/// +/// #[api_version(2)] +/// fn method3(); +/// +/// #[api_version(3)] +/// fn method4(); +/// } +/// ); +/// ``` +/// This trait has got three different versions. The function below will generate the following +/// code: +/// ``` +/// trait SomeApiV1 { +/// // in V1 only the stable methods are required. The rest has got default implementations. +/// fn method1(); +/// } +/// +/// trait SomeApiV2 { +/// // V2 contains all methods from V1 and V2. V3 not required so they are skipped. +/// fn method1(); +/// fn method2(); +/// fn method3(); +/// } +/// +/// trait SomeApiV3 { +/// // And V3 contains all methods from the trait. +/// fn method1(); +/// fn method2(); +/// fn method3(); +/// fn method4(); +/// } +/// ``` +fn generate_versioned_api_traits( + api: ItemTrait, + methods: BTreeMap>, +) -> Vec { + let mut result = Vec::::new(); + for (version, _) in &methods { + let mut versioned_trait = api.clone(); + versioned_trait.ident = versioned_trait_name(&versioned_trait.ident, *version); + versioned_trait.items = Vec::new(); + // Add the methods from the current version and all previous one. Versions are sorted so + // it's safe to stop early. + for (_, m) in methods.iter().take_while(|(v, _)| v <= &version) { + versioned_trait.items.extend(m.iter().cloned().map(|m| TraitItem::Method(m))); } - )); - - // Generate a native call generator for each function of the given trait. - for fn_ in fns { - let params = extract_parameter_names_types_and_borrows(fn_, AllowSelfRefInParameters::No)?; - let trait_fn_name = &fn_.ident; - let function_name_str = fn_.ident.to_string(); - let fn_name = generate_native_call_generator_fn_name(&fn_.ident); - let output = return_type_replace_block_with_node_block(fn_.output.clone()); - let output_ty = return_type_extract_type(&output); - let output = quote!( std::result::Result<#output_ty, #crate_::ApiError> ); - - // Every type that is using the `Block` generic parameter, we need to encode/decode, - // to make it compatible between the runtime/node. - let conversions = params.iter().filter(|v| type_is_using_block(&v.1)).map(|(n, t, _)| { - let param_name = quote!(#n).to_string(); - - quote!( - let #n: #t = convert_between_block_types( - &#n, - |e| #crate_::ApiError::FailedToConvertParameter { - function: #function_name_str, - parameter: #param_name, - error: e, - }, - )?; - ) - }); - // Same as for the input types, we need to check if we also need to convert the output, - // before returning it. - let output_conversion = if return_type_is_using_block(&fn_.output) { - quote!( - convert_between_block_types( - &res, - |e| #crate_::ApiError::FailedToConvertReturnValue { - function: #function_name_str, - error: e, - }, - ) - ) - } else { - quote!(Ok(res)) - }; - - let input_names = params.iter().map(|v| &v.0); - // If the type is using the block generic type, we will encode/decode it to make it - // compatible. To ensure that we forward it by ref/value, we use the value given by the - // the user. Otherwise if it is not using the block, we don't need to add anything. - let input_borrows = - params.iter().map(|v| if type_is_using_block(&v.1) { v.2 } else { None }); - - // Replace all `Block` with `NodeBlock`, add `'a` lifetime to references and collect - // all the function inputs. - let fn_inputs = fn_ - .inputs - .iter() - .map(|v| fn_arg_replace_block_with_node_block(v.clone())) - .map(|v| match v { - FnArg::Typed(ref arg) => { - let mut arg = arg.clone(); - if let Type::Reference(ref mut r) = *arg.ty { - r.lifetime = Some(parse_quote!( 'a )); - } - FnArg::Typed(arg) - }, - r => r, - }); - - let (impl_generics, ty_generics, where_clause) = decl.generics.split_for_impl(); - // We need to parse them again, to get an easy access to the actual parameters. - let impl_generics: Generics = parse_quote!( #impl_generics ); - let impl_generics_params = impl_generics.params.iter().map(|p| { - match p { - GenericParam::Type(ref ty) => { - let mut ty = ty.clone(); - ty.bounds.push(parse_quote!( 'a )); - GenericParam::Type(ty) - }, - // We should not see anything different than type params here. - r => r.clone(), - } - }); - // Generate the generator function - result.push(quote!( - #[cfg(any(feature = "std", test))] - pub fn #fn_name< - 'a, ApiImpl: #trait_ #ty_generics, NodeBlock: #crate_::BlockT - #(, #impl_generics_params)* - >( - #( #fn_inputs ),* - ) -> impl FnOnce() -> #output + 'a #where_clause { - move || { - #( #conversions )* - let res = ApiImpl::#trait_fn_name(#( #input_borrows #input_names ),*); - #output_conversion - } - } - )); + result.push(versioned_trait); } - Ok(quote!( #( #result )* )) + result } /// Try to parse the given `Attribute` as `renamed` attribute. @@ -323,126 +211,13 @@ fn parse_renamed_attribute(renamed: &Attribute) -> Result<(String, u32)> { } } -/// Generate the functions that call the api at a given block for a given trait method. -fn generate_call_api_at_calls(decl: &ItemTrait) -> Result { - let fns = decl.items.iter().filter_map(|i| match i { - TraitItem::Method(ref m) => Some((&m.attrs, &m.sig)), - _ => None, - }); - - let mut result = Vec::new(); - let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); - - // Generate a native call generator for each function of the given trait. - for (attrs, fn_) in fns { - let trait_name = &decl.ident; - let trait_fn_name = prefix_function_with_trait(trait_name, &fn_.ident); - let fn_name = generate_call_api_at_fn_name(&fn_.ident); - - let attrs = remove_supported_attributes(&mut attrs.clone()); - - if attrs.contains_key(RENAMED_ATTRIBUTE) && attrs.contains_key(CHANGED_IN_ATTRIBUTE) { - return Err(Error::new( - fn_.span(), - format!( - "`{}` and `{}` are not supported at once.", - RENAMED_ATTRIBUTE, CHANGED_IN_ATTRIBUTE - ), - )) - } - - // We do not need to generate this function for a method that signature was changed. - if attrs.contains_key(CHANGED_IN_ATTRIBUTE) { - continue - } - - // Parse the renamed attributes. - let mut renames = Vec::new(); - if let Some((_, a)) = attrs.iter().find(|a| a.0 == &RENAMED_ATTRIBUTE) { - let (old_name, version) = parse_renamed_attribute(a)?; - renames.push((version, prefix_function_with_trait(trait_name, &old_name))); - } - - renames.sort_by(|l, r| r.cmp(l)); - let (versions, old_names) = renames.into_iter().fold( - (Vec::new(), Vec::new()), - |(mut versions, mut old_names), (version, old_name)| { - versions.push(version); - old_names.push(old_name); - (versions, old_names) - }, - ); - - // Generate the generator function - result.push(quote!( - #[cfg(any(feature = "std", test))] - #[allow(clippy::too_many_arguments)] - pub fn #fn_name< - R: #crate_::Encode + #crate_::Decode + std::cmp::PartialEq, - NC: FnOnce() -> std::result::Result + std::panic::UnwindSafe, - Block: #crate_::BlockT, - T: #crate_::CallApiAt, - >( - call_runtime_at: &T, - at: &#crate_::BlockId, - args: std::vec::Vec, - changes: &std::cell::RefCell<#crate_::OverlayedChanges>, - storage_transaction_cache: &std::cell::RefCell< - #crate_::StorageTransactionCache - >, - native_call: std::option::Option, - context: #crate_::ExecutionContext, - recorder: &std::option::Option<#crate_::ProofRecorder>, - ) -> std::result::Result<#crate_::NativeOrEncoded, #crate_::ApiError> { - let version = call_runtime_at.runtime_version_at(at)?; - - #( - // Check if we need to call the function by an old name. - if version.apis.iter().any(|(s, v)| { - s == &ID && *v < #versions - }) { - let params = #crate_::CallApiAtParams::<_, fn() -> _, _> { - at, - function: #old_names, - native_call: None, - arguments: args, - overlayed_changes: changes, - storage_transaction_cache, - context, - recorder, - }; - - let ret = #crate_::CallApiAt::::call_api_at(call_runtime_at, params)?; - - return Ok(ret) - } - )* - - let params = #crate_::CallApiAtParams { - at, - function: #trait_fn_name, - native_call, - arguments: args, - overlayed_changes: changes, - storage_transaction_cache, - context, - recorder, - }; - - #crate_::CallApiAt::::call_api_at(call_runtime_at, params) - } - )); - } - - Ok(quote!( #( #result )* )) -} - /// Generate the declaration of the trait for the runtime. fn generate_runtime_decls(decls: &[ItemTrait]) -> Result { let mut result = Vec::new(); for decl in decls { let mut decl = decl.clone(); + let decl_span = decl.span(); extend_generics_with_block(&mut decl.generics); let mod_name = generate_runtime_mod_name_for_trait(&decl.ident); let found_attributes = remove_supported_attributes(&mut decl.attrs); @@ -450,30 +225,73 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result { get_api_version(&found_attributes).map(|v| generate_runtime_api_version(v as u32))?; let id = generate_runtime_api_id(&decl.ident.to_string()); - let call_api_at_calls = generate_call_api_at_calls(&decl)?; - - // Remove methods that have the `changed_in` attribute as they are not required for the - // runtime anymore. - decl.items = decl - .items - .iter_mut() - .filter_map(|i| match i { - TraitItem::Method(ref mut method) => { - if remove_supported_attributes(&mut method.attrs) - .contains_key(CHANGED_IN_ATTRIBUTE) - { - None - } else { - // Make sure we replace all the wild card parameter names. - replace_wild_card_parameter_names(&mut method.sig); - Some(TraitItem::Method(method.clone())) - } - }, - r => Some(r.clone()), - }) - .collect(); + let trait_api_version = get_api_version(&found_attributes)?; + + let mut methods_by_version: BTreeMap> = BTreeMap::new(); + + // Process the items in the declaration. The filter_map function below does a lot of stuff + // because the method attributes are stripped at this point + decl.items.iter_mut().for_each(|i| match i { + TraitItem::Method(ref mut method) => { + let method_attrs = remove_supported_attributes(&mut method.attrs); + let mut method_version = trait_api_version; + // validate the api version for the method (if any) and generate default + // implementation for versioned methods + if let Some(version_attribute) = method_attrs.get(API_VERSION_ATTRIBUTE) { + method_version = match parse_runtime_api_version(version_attribute) { + Ok(method_api_ver) if method_api_ver < trait_api_version => { + let method_ver = method_api_ver.to_string(); + let trait_ver = trait_api_version.to_string(); + let mut err1 = Error::new( + version_attribute.span(), + format!( + "Method version `{}` is older than (or equal to) trait version `{}`.\ + Methods can't define versions older than the trait version.", + method_ver, + trait_ver, + ), + ); + + let err2 = match found_attributes.get(&API_VERSION_ATTRIBUTE) { + Some(attr) => Error::new(attr.span(), "Trait version is set here."), + None => Error::new( + decl_span, + "Trait version is not set so it is implicitly equal to 1.", + ), + }; + err1.combine(err2); + result.push(err1.to_compile_error()); + + trait_api_version + }, + Ok(method_api_ver) => method_api_ver, + Err(e) => { + result.push(e.to_compile_error()); + trait_api_version + }, + }; + } - let native_call_generators = generate_native_call_generators(&decl)?; + // Any method with the `changed_in` attribute isn't required for the runtime + // anymore. + if !method_attrs.contains_key(CHANGED_IN_ATTRIBUTE) { + // Make sure we replace all the wild card parameter names. + replace_wild_card_parameter_names(&mut method.sig); + + // partition methods by api version + methods_by_version.entry(method_version).or_default().push(method.clone()); + } + }, + _ => (), + }); + + let versioned_api_traits = generate_versioned_api_traits(decl.clone(), methods_by_version); + + let main_api_ident = decl.ident.clone(); + let versioned_ident = &versioned_api_traits + .first() + .expect("There should always be at least one version.") + .ident; result.push(quote!( #[doc(hidden)] @@ -482,15 +300,13 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result { pub mod #mod_name { use super::*; - #decl + #( #versioned_api_traits )* + + pub use #versioned_ident as #main_api_ident; pub #api_version pub #id - - #native_call_generators - - #call_api_at_calls } )); } @@ -509,18 +325,45 @@ struct ToClientSideDecl<'a> { } impl<'a> ToClientSideDecl<'a> { - fn fold_item_trait_items(&mut self, items: Vec) -> Vec { + /// Process the given [`ItemTrait`]. + fn process(mut self, decl: ItemTrait) -> ItemTrait { + let mut decl = self.fold_item_trait(decl); + + let block_id = self.block_id; + let crate_ = self.crate_; + + // Add the special method that will be implemented by the `impl_runtime_apis!` macro + // to enable functions to call into the runtime. + decl.items.push(parse_quote! { + /// !!INTERNAL USE ONLY!! + #[doc(hidden)] + fn __runtime_api_internal_call_api_at( + &self, + at: &#block_id, + context: #crate_::ExecutionContext, + params: std::vec::Vec, + fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str, + ) -> std::result::Result, #crate_::ApiError>; + }); + + decl + } +} + +impl<'a> ToClientSideDecl<'a> { + fn fold_item_trait_items( + &mut self, + items: Vec, + trait_generics_num: usize, + ) -> Vec { let mut result = Vec::new(); items.into_iter().for_each(|i| match i { TraitItem::Method(method) => { - let (fn_decl, fn_impl, fn_decl_ctx) = self.fold_trait_item_method(method); + let (fn_decl, fn_decl_ctx) = + self.fold_trait_item_method(method, trait_generics_num); result.push(fn_decl.into()); result.push(fn_decl_ctx.into()); - - if let Some(fn_impl) = fn_impl { - result.push(fn_impl.into()); - } }, r => result.push(r), }); @@ -531,20 +374,24 @@ impl<'a> ToClientSideDecl<'a> { fn fold_trait_item_method( &mut self, method: TraitItemMethod, - ) -> (TraitItemMethod, Option, TraitItemMethod) { + trait_generics_num: usize, + ) -> (TraitItemMethod, TraitItemMethod) { let crate_ = self.crate_; let context = quote!( #crate_::ExecutionContext::OffchainCall(None) ); - let fn_impl = self.create_method_runtime_api_impl(method.clone()); - let fn_decl = self.create_method_decl(method.clone(), context); - let fn_decl_ctx = self.create_method_decl_with_context(method); + let fn_decl = self.create_method_decl(method.clone(), context, trait_generics_num); + let fn_decl_ctx = self.create_method_decl_with_context(method, trait_generics_num); - (fn_decl, fn_impl, fn_decl_ctx) + (fn_decl, fn_decl_ctx) } - fn create_method_decl_with_context(&mut self, method: TraitItemMethod) -> TraitItemMethod { + fn create_method_decl_with_context( + &mut self, + method: TraitItemMethod, + trait_generics_num: usize, + ) -> TraitItemMethod { let crate_ = self.crate_; let context_arg: syn::FnArg = parse_quote!( context: #crate_::ExecutionContext ); - let mut fn_decl_ctx = self.create_method_decl(method, quote!(context)); + let mut fn_decl_ctx = self.create_method_decl(method, quote!(context), trait_generics_num); fn_decl_ctx.sig.ident = Ident::new(&format!("{}_with_context", &fn_decl_ctx.sig.ident), Span::call_site()); fn_decl_ctx.sig.inputs.insert(2, context_arg); @@ -552,52 +399,6 @@ impl<'a> ToClientSideDecl<'a> { fn_decl_ctx } - /// Takes the given method and creates a `method_runtime_api_impl` method that will be - /// implemented in the runtime for the client side. - fn create_method_runtime_api_impl( - &mut self, - mut method: TraitItemMethod, - ) -> Option { - if remove_supported_attributes(&mut method.attrs).contains_key(CHANGED_IN_ATTRIBUTE) { - return None - } - - let fn_sig = &method.sig; - let ret_type = return_type_extract_type(&fn_sig.output); - - // Get types and if the value is borrowed from all parameters. - // If there is an error, we push it as the block to the user. - let param_types = - match extract_parameter_names_types_and_borrows(fn_sig, AllowSelfRefInParameters::No) { - Ok(res) => res - .into_iter() - .map(|v| { - let ty = v.1; - let borrow = v.2; - quote!( #borrow #ty ) - }) - .collect::>(), - Err(e) => { - self.errors.push(e.to_compile_error()); - Vec::new() - }, - }; - let name = generate_method_runtime_api_impl_name(self.trait_, &method.sig.ident); - let block_id = self.block_id; - let crate_ = self.crate_; - - Some(parse_quote! { - #[doc(hidden)] - fn #name( - &self, - at: &#block_id, - context: #crate_::ExecutionContext, - params: Option<( #( #param_types ),* )>, - params_encoded: Vec, - ) -> std::result::Result<#crate_::NativeOrEncoded<#ret_type>, #crate_::ApiError>; - }) - } - /// Takes the method declared by the user and creates the declaration we require for the runtime /// api client side. This method will call by default the `method_runtime_api_impl` for doing /// the actual call into the runtime. @@ -605,6 +406,7 @@ impl<'a> ToClientSideDecl<'a> { &mut self, mut method: TraitItemMethod, context: TokenStream, + trait_generics_num: usize, ) -> TraitItemMethod { let params = match extract_parameter_names_types_and_borrows( &method.sig, @@ -616,18 +418,42 @@ impl<'a> ToClientSideDecl<'a> { Vec::new() }, }; - let params2 = params.clone(); let ret_type = return_type_extract_type(&method.sig.output); fold_fn_decl_for_client_side(&mut method.sig, self.block_id, self.crate_); - let name_impl = generate_method_runtime_api_impl_name(self.trait_, &method.sig.ident); let crate_ = self.crate_; let found_attributes = remove_supported_attributes(&mut method.attrs); + + // Parse the renamed attributes. + let mut renames = Vec::new(); + for (_, a) in found_attributes.iter().filter(|a| a.0 == &RENAMED_ATTRIBUTE) { + match parse_renamed_attribute(a) { + Ok((old_name, version)) => { + renames.push((version, prefix_function_with_trait(&self.trait_, &old_name))); + }, + Err(e) => self.errors.push(e.to_compile_error()), + } + } + + renames.sort_by(|l, r| r.cmp(l)); + let (versions, old_names) = renames.into_iter().fold( + (Vec::new(), Vec::new()), + |(mut versions, mut old_names), (version, old_name)| { + versions.push(version); + old_names.push(old_name); + (versions, old_names) + }, + ); + + // Generate the function name before we may rename it below to + // `function_name_before_version_{}`. + let function_name = prefix_function_with_trait(&self.trait_, &method.sig.ident); + // If the method has a `changed_in` attribute, we need to alter the method name to // `method_before_version_VERSION`. - let (native_handling, param_tuple) = match get_changed_in(&found_attributes) { + match get_changed_in(&found_attributes) { Ok(Some(version)) => { // Make sure that the `changed_in` version is at least the current `api_version`. if get_api_version(self.found_attributes).ok() < Some(version) { @@ -646,47 +472,51 @@ impl<'a> ToClientSideDecl<'a> { ); method.sig.ident = ident; method.attrs.push(parse_quote!( #[deprecated] )); - - let panic = - format!("Calling `{}` should not return a native value!", method.sig.ident); - (quote!(panic!(#panic)), quote!(None)) }, - Ok(None) => (quote!(Ok(n)), quote!( Some(( #( #params2 ),* )) )), + Ok(None) => {}, Err(e) => { self.errors.push(e.to_compile_error()); - (quote!(unimplemented!()), quote!(None)) }, }; - let function_name = method.sig.ident.to_string(); + // The module where the runtime relevant stuff is declared. + let trait_name = &self.trait_; + let runtime_mod = generate_runtime_mod_name_for_trait(trait_name); + let underscores = (0..trait_generics_num).map(|_| quote!(_)); // Generate the default implementation that calls the `method_runtime_api_impl` method. method.default = Some(parse_quote! { { - let runtime_api_impl_params_encoded = + let __runtime_api_impl_params_encoded__ = #crate_::Encode::encode(&( #( &#params ),* )); - self.#name_impl( + >::__runtime_api_internal_call_api_at( + self, __runtime_api_at_param__, #context, - #param_tuple, - runtime_api_impl_params_encoded, - ).and_then(|r| - match r { - #crate_::NativeOrEncoded::Native(n) => { - #native_handling - }, - #crate_::NativeOrEncoded::Encoded(r) => { - std::result::Result::map_err( - <#ret_type as #crate_::Decode>::decode(&mut &r[..]), - |err| #crate_::ApiError::FailedToDecodeReturnValue { - function: #function_name, - error: err, - } - ) - } + __runtime_api_impl_params_encoded__, + &|version| { + #( + // Check if we need to call the function by an old name. + if version.apis.iter().any(|(s, v)| { + s == &#runtime_mod::ID && *v < #versions + }) { + return #old_names + } + )* + + #function_name } ) + .and_then(|r| + std::result::Result::map_err( + <#ret_type as #crate_::Decode>::decode(&mut &r[..]), + |err| #crate_::ApiError::FailedToDecodeReturnValue { + function: #function_name, + error: err, + } + ) + ) } }); @@ -714,37 +544,12 @@ impl<'a> Fold for ToClientSideDecl<'a> { // The client side trait is only required when compiling with the feature `std` or `test`. input.attrs.push(parse_quote!( #[cfg(any(feature = "std", test))] )); - input.items = self.fold_item_trait_items(input.items); + input.items = self.fold_item_trait_items(input.items, input.generics.params.len()); fold::fold_item_trait(self, input) } } -/// Parse the given attribute as `API_VERSION_ATTRIBUTE`. -fn parse_runtime_api_version(version: &Attribute) -> Result { - let meta = version.parse_meta()?; - - let err = Err(Error::new( - meta.span(), - &format!( - "Unexpected `{api_version}` attribute. The supported format is `{api_version}(1)`", - api_version = API_VERSION_ATTRIBUTE - ), - )); - - match meta { - Meta::List(list) => - if list.nested.len() != 1 { - err - } else if let Some(NestedMeta::Lit(Lit::Int(i))) = list.nested.first() { - i.base10_parse() - } else { - err - }, - _ => err, - } -} - /// Generates the identifier as const variable for the given `trait_name` /// by hashing the `trait_name`. fn generate_runtime_api_id(trait_name: &str) -> TokenStream { @@ -821,16 +626,14 @@ fn generate_client_side_decls(decls: &[ItemTrait]) -> Result { let mut errors = Vec::new(); let trait_ = decl.ident.clone(); - let decl = { - let mut to_client_side = ToClientSideDecl { - crate_: &crate_, - block_id: &block_id, - found_attributes: &mut found_attributes, - errors: &mut errors, - trait_: &trait_, - }; - to_client_side.fold_item_trait(decl) - }; + let decl = ToClientSideDecl { + crate_: &crate_, + block_id: &block_id, + found_attributes: &mut found_attributes, + errors: &mut errors, + trait_: &trait_, + } + .process(decl); let api_version = get_api_version(&found_attributes); diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index 02ef37370ffeb..0087a1ad37ab9 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -17,13 +17,13 @@ use crate::utils::{ extract_all_signature_types, extract_block_type_from_trait_path, extract_impl_trait, - extract_parameter_names_types_and_borrows, generate_call_api_at_fn_name, generate_crate_access, - generate_hidden_includes, generate_method_runtime_api_impl_name, - generate_native_call_generator_fn_name, generate_runtime_mod_name_for_trait, - prefix_function_with_trait, return_type_extract_type, AllowSelfRefInParameters, - RequireQualifiedTraitPath, + extract_parameter_names_types_and_borrows, generate_crate_access, generate_hidden_includes, + generate_runtime_mod_name_for_trait, parse_runtime_api_version, prefix_function_with_trait, + versioned_trait_name, AllowSelfRefInParameters, RequireQualifiedTraitPath, }; +use crate::common::API_VERSION_ATTRIBUTE; + use proc_macro2::{Span, TokenStream}; use quote::quote; @@ -33,8 +33,7 @@ use syn::{ parse::{Error, Parse, ParseStream, Result}, parse_macro_input, parse_quote, spanned::Spanned, - Attribute, GenericArgument, Ident, ImplItem, ItemImpl, Path, PathArguments, Signature, Type, - TypePath, + Attribute, Ident, ImplItem, ItemImpl, Path, Signature, Type, TypePath, }; use std::collections::HashSet; @@ -105,8 +104,10 @@ fn generate_impl_calls( let mut impl_calls = Vec::new(); for impl_ in impls { + let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?; let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?; let impl_trait = extend_with_runtime_decl_path(impl_trait_path.clone()); + let impl_trait = extend_with_api_version(impl_trait, trait_api_ver); let impl_trait_ident = &impl_trait_path .segments .last() @@ -326,35 +327,6 @@ fn generate_runtime_api_base_structures() -> Result { #[cfg(any(feature = "std", test))] impl> RuntimeApiImpl { - fn call_api_at< - R: #crate_::Encode + #crate_::Decode + std::cmp::PartialEq, - F: FnOnce( - &C, - &std::cell::RefCell<#crate_::OverlayedChanges>, - &std::cell::RefCell<#crate_::StorageTransactionCache>, - &std::option::Option<#crate_::ProofRecorder>, - ) -> std::result::Result<#crate_::NativeOrEncoded, E>, - E, - >( - &self, - call_api_at: F, - ) -> std::result::Result<#crate_::NativeOrEncoded, E> { - if *std::cell::RefCell::borrow(&self.commit_on_success) { - #crate_::OverlayedChanges::start_transaction( - &mut std::cell::RefCell::borrow_mut(&self.changes) - ); - } - let res = call_api_at( - &self.call, - &self.changes, - &self.storage_transaction_cache, - &self.recorder, - ); - - self.commit_or_rollback(std::result::Result::is_ok(&res)); - res - } - fn commit_or_rollback(&self, commit: bool) { let proof = "\ We only close a transaction when we opened one ourself. @@ -398,6 +370,24 @@ fn extend_with_runtime_decl_path(mut trait_: Path) -> Path { trait_ } +fn extend_with_api_version(mut trait_: Path, version: Option) -> Path { + let version = if let Some(v) = version { + v + } else { + // nothing to do + return trait_ + }; + + let trait_name = &mut trait_ + .segments + .last_mut() + .expect("Trait path should always contain at least one item; qed") + .ident; + *trait_name = versioned_trait_name(trait_name, version); + + trait_ +} + /// Generates the implementations of the apis for the runtime. fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result { let mut impls_prepared = Vec::new(); @@ -405,9 +395,12 @@ fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result { // We put `runtime` before each trait to get the trait that is intended for the runtime and // we put the `RuntimeBlock` as first argument for the trait generics. for impl_ in impls.iter() { + let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?; + let mut impl_ = impl_.clone(); let trait_ = extract_impl_trait(&impl_, RequireQualifiedTraitPath::Yes)?.clone(); let trait_ = extend_with_runtime_decl_path(trait_); + let trait_ = extend_with_api_version(trait_, trait_api_ver); impl_.trait_.as_mut().unwrap().1 = trait_; impl_.attrs = filter_cfg_attrs(&impl_.attrs); @@ -424,121 +417,70 @@ fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result { /// with code that calls into the runtime. struct ApiRuntimeImplToApiRuntimeApiImpl<'a> { runtime_block: &'a TypePath, - runtime_mod_path: &'a Path, - runtime_type: &'a Type, - trait_generic_arguments: &'a [GenericArgument], - impl_trait: &'a Ident, } -impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { - fn fold_type_path(&mut self, input: TypePath) -> TypePath { - let new_ty_path = - if input == *self.runtime_block { parse_quote!(__SR_API_BLOCK__) } else { input }; - - fold::fold_type_path(self, new_ty_path) - } +impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { + /// Process the given item implementation. + fn process(mut self, input: ItemImpl) -> ItemImpl { + let mut input = self.fold_item_impl(input); - fn fold_impl_item_method(&mut self, mut input: syn::ImplItemMethod) -> syn::ImplItemMethod { - let block = { - let runtime_mod_path = self.runtime_mod_path; - let runtime = self.runtime_type; - let native_call_generator_ident = - generate_native_call_generator_fn_name(&input.sig.ident); - let call_api_at_call = generate_call_api_at_fn_name(&input.sig.ident); - let trait_generic_arguments = self.trait_generic_arguments; - let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); - - // Generate the access to the native parameters - let param_tuple_access = if input.sig.inputs.len() == 1 { - vec![quote!(p)] - } else { - input - .sig - .inputs - .iter() - .enumerate() - .map(|(i, _)| { - let i = syn::Index::from(i); - quote!( p.#i ) - }) - .collect::>() - }; - - let (param_types, error) = match extract_parameter_names_types_and_borrows( - &input.sig, - AllowSelfRefInParameters::No, - ) { - Ok(res) => ( - res.into_iter() - .map(|v| { - let ty = v.1; - let borrow = v.2; - quote!( #borrow #ty ) - }) - .collect::>(), - None, - ), - Err(e) => (Vec::new(), Some(e.to_compile_error())), - }; + let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); - // Rewrite the input parameters. - input.sig.inputs = parse_quote! { + // Delete all functions, because all of them are default implemented by + // `decl_runtime_apis!`. We only need to implement the `__runtime_api_internal_call_api_at` + // function. + input.items.clear(); + input.items.push(parse_quote! { + fn __runtime_api_internal_call_api_at( &self, at: &#crate_::BlockId<__SR_API_BLOCK__>, context: #crate_::ExecutionContext, - params: Option<( #( #param_types ),* )>, - params_encoded: Vec, - }; - - input.sig.ident = - generate_method_runtime_api_impl_name(self.impl_trait, &input.sig.ident); - let ret_type = return_type_extract_type(&input.sig.output); - - // Generate the correct return type. - input.sig.output = parse_quote!( - -> std::result::Result<#crate_::NativeOrEncoded<#ret_type>, #crate_::ApiError> - ); - - // Generate the new method implementation that calls into the runtime. - parse_quote!( - { - // Get the error to the user (if we have one). - #error - - self.call_api_at( - | - call_runtime_at, - changes, - storage_transaction_cache, - recorder - | { - #runtime_mod_path #call_api_at_call( - call_runtime_at, - at, - params_encoded, - changes, - storage_transaction_cache, - params.map(|p| { - #runtime_mod_path #native_call_generator_ident :: - <#runtime, __SR_API_BLOCK__ #(, #trait_generic_arguments )*> ( - #( #param_tuple_access ),* - ) - }), - context, - recorder, - ) - } - ) + params: std::vec::Vec, + fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str, + ) -> std::result::Result, #crate_::ApiError> { + if *std::cell::RefCell::borrow(&self.commit_on_success) { + #crate_::OverlayedChanges::start_transaction( + &mut std::cell::RefCell::borrow_mut(&self.changes) + ); } - ) - }; - let mut input = fold::fold_impl_item_method(self, input); - // We need to set the block, after we modified the rest of the ast, otherwise we would - // modify our generated block as well. - input.block = block; + let res = (|| { + let version = #crate_::CallApiAt::<__SR_API_BLOCK__>::runtime_version_at(self.call, at)?; + + let params = #crate_::CallApiAtParams::<_, fn() -> _, _> { + at, + function: (*fn_name)(version), + native_call: None, + arguments: params, + overlayed_changes: &self.changes, + storage_transaction_cache: &self.storage_transaction_cache, + context, + recorder: &self.recorder, + }; + + #crate_::CallApiAt::<__SR_API_BLOCK__>::call_api_at::<#crate_::NeverNativeValue, _>( + self.call, + params, + ) + })(); + + self.commit_or_rollback(std::result::Result::is_ok(&res)); + + res.map(#crate_::NativeOrEncoded::into_encoded) + } + }); + input } +} + +impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { + fn fold_type_path(&mut self, input: TypePath) -> TypePath { + let new_ty_path = + if input == *self.runtime_block { parse_quote!(__SR_API_BLOCK__) } else { input }; + + fold::fold_type_path(self, new_ty_path) + } fn fold_item_impl(&mut self, mut input: ItemImpl) -> ItemImpl { // All this `UnwindSafe` magic below here is required for this rust bug: @@ -594,45 +536,55 @@ fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result for impl_ in impls { let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?; - let impl_trait = &impl_trait_path - .segments - .last() - .ok_or_else(|| Error::new(impl_trait_path.span(), "Empty trait path not possible!"))? - .clone(); let runtime_block = extract_block_type_from_trait_path(impl_trait_path)?; - let runtime_type = &impl_.self_ty; let mut runtime_mod_path = extend_with_runtime_decl_path(impl_trait_path.clone()); // remove the trait to get just the module path runtime_mod_path.segments.pop(); - let trait_generic_arguments = match impl_trait.arguments { - PathArguments::Parenthesized(_) | PathArguments::None => vec![], - PathArguments::AngleBracketed(ref b) => b.args.iter().cloned().collect(), - }; - - let mut visitor = ApiRuntimeImplToApiRuntimeApiImpl { - runtime_block, - runtime_mod_path: &runtime_mod_path, - runtime_type, - trait_generic_arguments: &trait_generic_arguments, - impl_trait: &impl_trait.ident, - }; + let processed_impl = + ApiRuntimeImplToApiRuntimeApiImpl { runtime_block }.process(impl_.clone()); - result.push(visitor.fold_item_impl(impl_.clone())); + result.push(processed_impl); } Ok(quote!( #( #result )* )) } +fn populate_runtime_api_versions( + result: &mut Vec, + sections: &mut Vec, + attrs: Vec, + id: Path, + version: TokenStream, + crate_access: &TokenStream, +) { + result.push(quote!( + #( #attrs )* + (#id, #version) + )); + + sections.push(quote!( + #( #attrs )* + const _: () = { + // All sections with the same name are going to be merged by concatenation. + #[cfg(not(feature = "std"))] + #[link_section = "runtime_apis"] + static SECTION_CONTENTS: [u8; 12] = #crate_access::serialize_runtime_api_info(#id, #version); + }; + )); +} + /// Generates `RUNTIME_API_VERSIONS` that holds all version information about the implemented /// runtime apis. fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { - let mut result = Vec::with_capacity(impls.len()); - let mut sections = Vec::with_capacity(impls.len()); + let mut result = Vec::::with_capacity(impls.len()); + let mut sections = Vec::::with_capacity(impls.len()); let mut processed_traits = HashSet::new(); let c = generate_crate_access(HIDDEN_INCLUDES_ID); for impl_ in impls { + let api_ver = extract_api_version(&impl_.attrs, impl_.span())?.map(|a| a as u32); + let mut path = extend_with_runtime_decl_path( extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?.clone(), ); @@ -655,23 +607,11 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { } let id: Path = parse_quote!( #path ID ); - let version: Path = parse_quote!( #path VERSION ); + let version = quote!( #path VERSION ); let attrs = filter_cfg_attrs(&impl_.attrs); - result.push(quote!( - #( #attrs )* - (#id, #version) - )); - - sections.push(quote!( - #( #attrs )* - const _: () = { - // All sections with the same name are going to be merged by concatenation. - #[cfg(not(feature = "std"))] - #[link_section = "runtime_apis"] - static SECTION_CONTENTS: [u8; 12] = #c::serialize_runtime_api_info(#id, #version); - }; - )); + let api_ver = api_ver.map(|a| quote!( #a )).unwrap_or_else(|| version); + populate_runtime_api_versions(&mut result, &mut sections, attrs, id, api_ver, &c) } Ok(quote!( @@ -726,6 +666,33 @@ fn filter_cfg_attrs(attrs: &[Attribute]) -> Vec { attrs.iter().filter(|a| a.path.is_ident("cfg")).cloned().collect() } +// Extracts the value of `API_VERSION_ATTRIBUTE` and handles errors. +// Returns: +// - Err if the version is malformed +// - Some(u64) if the version is set +// - None if the version is not set (this is valid). +fn extract_api_version(attrs: &Vec, span: Span) -> Result> { + // First fetch all `API_VERSION_ATTRIBUTE` values (should be only one) + let api_ver = attrs + .iter() + .filter(|a| a.path.is_ident(API_VERSION_ATTRIBUTE)) + .collect::>(); + + if api_ver.len() > 1 { + return Err(Error::new( + span, + format!( + "Found multiple #[{}] attributes for an API implementation. \ + Each runtime API can have only one version.", + API_VERSION_ATTRIBUTE + ), + )) + } + + // Parse the runtime version if there exists one. + api_ver.first().map(|v| parse_runtime_api_version(v)).transpose() +} + #[cfg(test)] mod tests { use super::*; diff --git a/primitives/api/proc-macro/src/lib.rs b/primitives/api/proc-macro/src/lib.rs index 20a2f76f2c83d..31636b8e2d545 100644 --- a/primitives/api/proc-macro/src/lib.rs +++ b/primitives/api/proc-macro/src/lib.rs @@ -21,6 +21,7 @@ use proc_macro::TokenStream; +mod common; mod decl_runtime_apis; mod impl_runtime_apis; mod mock_impl_runtime_apis; diff --git a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs index 6098f8d6bd741..4de0f6b9e571b 100644 --- a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs @@ -18,8 +18,7 @@ use crate::utils::{ extract_block_type_from_trait_path, extract_impl_trait, extract_parameter_names_types_and_borrows, generate_crate_access, generate_hidden_includes, - generate_method_runtime_api_impl_name, return_type_extract_type, AllowSelfRefInParameters, - RequireQualifiedTraitPath, + return_type_extract_type, AllowSelfRefInParameters, RequireQualifiedTraitPath, }; use proc_macro2::{Span, TokenStream}; @@ -31,7 +30,7 @@ use syn::{ parse::{Error, Parse, ParseStream, Result}, parse_macro_input, parse_quote, spanned::Spanned, - Attribute, Ident, ItemImpl, Pat, Type, TypePath, + Attribute, ItemImpl, Pat, Type, TypePath, }; /// Unique identifier used to make the hidden includes unique for this macro. @@ -40,7 +39,7 @@ const HIDDEN_INCLUDES_ID: &str = "MOCK_IMPL_RUNTIME_APIS"; /// The `advanced` attribute. /// /// If this attribute is given to a function, the function gets access to the `BlockId` as first -/// parameter and needs to return a `Result` with the appropiate error type. +/// parameter and needs to return a `Result` with the appropriate error type. const ADVANCED_ATTRIBUTE: &str = "advanced"; /// The structure used for parsing the runtime api implementations. @@ -126,34 +125,63 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result for #self_ty { - fn Core_version_runtime_api_impl( + fn __runtime_api_internal_call_api_at( &self, _: &#crate_::BlockId<#block_type>, _: #crate_::ExecutionContext, - _: Option<()>, - _: Vec, - ) -> std::result::Result<#crate_::NativeOrEncoded<#crate_::RuntimeVersion>, #crate_::ApiError> { - unimplemented!("Not required for testing!") + _: std::vec::Vec, + _: &dyn Fn(#crate_::RuntimeVersion) -> &'static str, + ) -> std::result::Result, #crate_::ApiError> { + unimplemented!("`__runtime_api_internal_call_api_at` not implemented for runtime api mocks") } - fn Core_execute_block_runtime_api_impl( + fn version( + &self, + _: &#crate_::BlockId<#block_type>, + ) -> std::result::Result<#crate_::RuntimeVersion, #crate_::ApiError> { + unimplemented!("`Core::version` not implemented for runtime api mocks") + } + + fn version_with_context( + &self, + _: &#crate_::BlockId<#block_type>, + _: #crate_::ExecutionContext, + ) -> std::result::Result<#crate_::RuntimeVersion, #crate_::ApiError> { + unimplemented!("`Core::version` not implemented for runtime api mocks") + } + + fn execute_block( + &self, + _: &#crate_::BlockId<#block_type>, + _: #block_type, + ) -> std::result::Result<(), #crate_::ApiError> { + unimplemented!("`Core::execute_block` not implemented for runtime api mocks") + } + + fn execute_block_with_context( &self, _: &#crate_::BlockId<#block_type>, _: #crate_::ExecutionContext, - _: Option<#block_type>, - _: Vec, - ) -> std::result::Result<#crate_::NativeOrEncoded<()>, #crate_::ApiError> { - unimplemented!("Not required for testing!") + _: #block_type, + ) -> std::result::Result<(), #crate_::ApiError> { + unimplemented!("`Core::execute_block` not implemented for runtime api mocks") } - fn Core_initialize_block_runtime_api_impl( + fn initialize_block( + &self, + _: &#crate_::BlockId<#block_type>, + _: &<#block_type as #crate_::BlockT>::Header, + ) -> std::result::Result<(), #crate_::ApiError> { + unimplemented!("`Core::initialize_block` not implemented for runtime api mocks") + } + + fn initialize_block_with_context( &self, _: &#crate_::BlockId<#block_type>, _: #crate_::ExecutionContext, - _: Option<&<#block_type as #crate_::BlockT>::Header>, - _: Vec, - ) -> std::result::Result<#crate_::NativeOrEncoded<()>, #crate_::ApiError> { - unimplemented!("Not required for testing!") + _: &<#block_type as #crate_::BlockT>::Header, + ) -> std::result::Result<(), #crate_::ApiError> { + unimplemented!("`Core::initialize_block` not implemented for runtime api mocks") } } )) @@ -216,14 +244,53 @@ fn get_at_param_name( } } -/// Auxialiry structure to fold a runtime api trait implementation into the expected format. +/// Auxiliary structure to fold a runtime api trait implementation into the expected format. /// /// This renames the methods, changes the method parameters and extracts the error type. struct FoldRuntimeApiImpl<'a> { /// The block type that is being used. block_type: &'a TypePath, - /// The identifier of the trait being implemented. - impl_trait: &'a Ident, +} + +impl<'a> FoldRuntimeApiImpl<'a> { + /// Process the given [`syn::ItemImpl`]. + fn process(mut self, impl_item: syn::ItemImpl) -> syn::ItemImpl { + let mut impl_item = self.fold_item_impl(impl_item); + + let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + + // We also need to overwrite all the `_with_context` methods. To do this, + // we clone all methods and add them again with the new name plus one more argument. + impl_item.items.extend(impl_item.items.clone().into_iter().filter_map(|i| { + if let syn::ImplItem::Method(mut m) = i { + m.sig.ident = quote::format_ident!("{}_with_context", m.sig.ident); + m.sig.inputs.insert(2, parse_quote!( _: #crate_::ExecutionContext )); + + Some(m.into()) + } else { + None + } + })); + + let block_type = self.block_type; + + impl_item.items.push(parse_quote! { + fn __runtime_api_internal_call_api_at( + &self, + _: &#crate_::BlockId<#block_type>, + _: #crate_::ExecutionContext, + _: std::vec::Vec, + _: &dyn Fn(#crate_::RuntimeVersion) -> &'static str, + ) -> std::result::Result, #crate_::ApiError> { + unimplemented!( + "`__runtime_api_internal_call_api_at` not implemented for runtime api mocks. \ + Calling deprecated methods is not supported by mocked runtime api." + ) + } + }); + + impl_item + } } impl<'a> Fold for FoldRuntimeApiImpl<'a> { @@ -277,14 +344,9 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> { input.sig.inputs = parse_quote! { &self, #at_param_name: #block_id_type, - _: #crate_::ExecutionContext, - ___params___sp___api___: Option<( #( #param_types ),* )>, - _: Vec, + #( #param_names: #param_types ),* }; - input.sig.ident = - generate_method_runtime_api_impl_name(self.impl_trait, &input.sig.ident); - // When using advanced, the user needs to declare the correct return type on its own, // otherwise do it for the user. if !is_advanced { @@ -292,7 +354,7 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> { // Generate the correct return type. input.sig.output = parse_quote!( - -> std::result::Result<#crate_::NativeOrEncoded<#ret_type>, #crate_::ApiError> + -> std::result::Result<#ret_type, #crate_::ApiError> ); } @@ -304,7 +366,7 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> { quote! { let __fn_implementation__ = move || #orig_block; - Ok(#crate_::NativeOrEncoded::Native(__fn_implementation__())) + Ok(__fn_implementation__()) } }; @@ -314,9 +376,6 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> { // Get the error to the user (if we have one). #( #errors )* - let (#( #param_names ),*) = ___params___sp___api___ - .expect("Mocked runtime apis don't support calling deprecated api versions"); - #construct_return_value } ) @@ -351,11 +410,6 @@ fn generate_runtime_api_impls(impls: &[ItemImpl]) -> Result Result Some(block_type.clone()), }; - let mut visitor = FoldRuntimeApiImpl { block_type, impl_trait: &impl_trait.ident }; - - result.push(visitor.fold_item_impl(impl_.clone())); + result.push(FoldRuntimeApiImpl { block_type }.process(impl_.clone())); } Ok(GeneratedRuntimeApiImpls { diff --git a/primitives/api/proc-macro/src/utils.rs b/primitives/api/proc-macro/src/utils.rs index 97b456b62dfa6..2ccd050cfb151 100644 --- a/primitives/api/proc-macro/src/utils.rs +++ b/primitives/api/proc-macro/src/utils.rs @@ -18,16 +18,18 @@ use proc_macro2::{Span, TokenStream}; use syn::{ - parse_quote, spanned::Spanned, token::And, Error, FnArg, GenericArgument, Ident, ImplItem, - ItemImpl, Pat, Path, PathArguments, Result, ReturnType, Signature, Type, TypePath, + parse_quote, spanned::Spanned, token::And, Attribute, Error, FnArg, GenericArgument, Ident, + ImplItem, ItemImpl, Pat, Path, PathArguments, Result, ReturnType, Signature, Type, TypePath, }; -use quote::quote; +use quote::{format_ident, quote}; use std::env; use proc_macro_crate::{crate_name, FoundCrate}; +use crate::common::API_VERSION_ATTRIBUTE; + fn generate_hidden_includes_mod_name(unique_id: &'static str) -> Ident { Ident::new(&format!("sp_api_hidden_includes_{}", unique_id), Span::call_site()) } @@ -68,11 +70,6 @@ pub fn generate_runtime_mod_name_for_trait(trait_: &Ident) -> Ident { Ident::new(&format!("runtime_decl_for_{}", trait_), Span::call_site()) } -/// Generates a name for a method that needs to be implemented in the runtime for the client side. -pub fn generate_method_runtime_api_impl_name(trait_: &Ident, method: &Ident) -> Ident { - Ident::new(&format!("{}_{}_runtime_api_impl", trait_, method), Span::call_site()) -} - /// Get the type of a `syn::ReturnType`. pub fn return_type_extract_type(rt: &ReturnType) -> Type { match rt { @@ -166,16 +163,6 @@ pub fn extract_parameter_names_types_and_borrows( Ok(result) } -/// Generates the name for the native call generator function. -pub fn generate_native_call_generator_fn_name(fn_name: &Ident) -> Ident { - Ident::new(&format!("{}_native_call_generator", fn_name), Span::call_site()) -} - -/// Generates the name for the call api at function. -pub fn generate_call_api_at_fn_name(fn_name: &Ident) -> Ident { - Ident::new(&format!("{}_call_api_at", fn_name), Span::call_site()) -} - /// Prefix the given function with the trait name. pub fn prefix_function_with_trait(trait_: &Ident, function: &F) -> String { format!("{}_{}", trait_, function.to_string()) @@ -267,3 +254,23 @@ pub fn extract_impl_trait(impl_: &ItemImpl, require: RequireQualifiedTraitPath) } }) } + +/// Parse the given attribute as `API_VERSION_ATTRIBUTE`. +pub fn parse_runtime_api_version(version: &Attribute) -> Result { + let version = version.parse_args::().map_err(|_| { + Error::new( + version.span(), + &format!( + "Unexpected `{api_version}` attribute. The supported format is `{api_version}(1)`", + api_version = API_VERSION_ATTRIBUTE + ), + ) + })?; + + version.base10_parse() +} + +// Each versioned trait is named 'ApiNameVN' where N is the specific version. E.g. ParachainHostV2 +pub fn versioned_trait_name(trait_ident: &Ident, version: u64) -> Ident { + format_ident!("{}V{}", trait_ident, version) +} diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index 2635c81948ff3..a5230cfc5f116 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -78,12 +78,12 @@ pub use hash_db::Hasher; #[doc(hidden)] #[cfg(not(feature = "std"))] pub use sp_core::to_substrate_wasm_fn_return_value; -#[doc(hidden)] -#[cfg(feature = "std")] -pub use sp_core::NativeOrEncoded; use sp_core::OpaqueMetadata; #[doc(hidden)] pub use sp_core::{offchain, ExecutionContext}; +#[doc(hidden)] +#[cfg(feature = "std")] +pub use sp_core::{NativeOrEncoded, NeverNativeValue}; #[cfg(feature = "std")] pub use sp_runtime::StateVersion; #[doc(hidden)] @@ -187,6 +187,56 @@ pub const MAX_EXTRINSIC_DEPTH: u32 = 256; /// To check if a given runtime implements a runtime api trait, the `RuntimeVersion` has the /// function `has_api()`. Also the `ApiExt` provides a function `has_api(at: &BlockId)` /// to check if the runtime at the given block id implements the requested runtime api trait. +/// +/// # Declaring multiple api versions +/// +/// Optionally multiple versions of the same api can be declared. This is useful for +/// development purposes. For example you want to have a testing version of the api which is +/// available only on a testnet. You can define one stable and one development version. This +/// can be done like this: +/// ```rust +/// sp_api::decl_runtime_apis! { +/// /// Declare the api trait. +/// #[api_version(2)] +/// pub trait Balance { +/// /// Get the balance. +/// fn get_balance() -> u64; +/// /// Set the balance. +/// fn set_balance(val: u64); +/// /// Transfer the balance to another user id +/// #[api_version(3)] +/// fn transfer_balance(uid: u64); +/// } +/// } +/// +/// # fn main() {} +/// ``` +/// The example above defines two api versions - 2 and 3. Version 2 contains `get_balance` and +/// `set_balance`. Version 3 additionally contains `transfer_balance`, which is not available +/// in version 2. Version 2 in this case is considered the default/base version of the api. +/// More than two versions can be defined this way. For example: +/// ```rust +/// sp_api::decl_runtime_apis! { +/// /// Declare the api trait. +/// #[api_version(2)] +/// pub trait Balance { +/// /// Get the balance. +/// fn get_balance() -> u64; +/// /// Set the balance. +/// fn set_balance(val: u64); +/// /// Transfer the balance to another user id +/// #[api_version(3)] +/// fn transfer_balance(uid: u64); +/// /// Clears the balance +/// #[api_version(4)] +/// fn clear_balance(); +/// } +/// } +/// +/// # fn main() {} +/// ``` +/// Note that the latest version (4 in our example above) always contains all methods from all +/// the versions before. pub use sp_api_proc_macro::decl_runtime_apis; /// Tags given trait implementations as runtime apis. @@ -276,6 +326,22 @@ pub use sp_api_proc_macro::decl_runtime_apis; /// /// # fn main() {} /// ``` +/// +/// # Implementing specific api version +/// +/// If `decl_runtime_apis!` declares multiple versions for an api `impl_runtime_apis!` +/// should specify which version it implements by adding `api_version` attribute to the +/// `impl` block. If omitted - the base/default version is implemented. Here is an example: +/// ```ignore +/// sp_api::impl_runtime_apis! { +/// #[api_version(3)] +/// impl self::Balance for Runtime { +/// // implementation +/// } +/// } +/// ``` +/// In this case `Balance` api version 3 is being implemented for `Runtime`. The `impl` block +/// must contain all methods declared in version 3 and below. pub use sp_api_proc_macro::impl_runtime_apis; /// Mocks given trait implementations as runtime apis. @@ -341,15 +407,13 @@ pub use sp_api_proc_macro::impl_runtime_apis; /// using the `advanced` attribute, the macro expects that the first parameter of the function /// is this `at` parameter. Besides that the macro also doesn't do the automatic return value /// rewrite, which means that full return value must be specified. The full return value is -/// constructed like [`Result`]`<`[`NativeOrEncoded`](sp_api::NativeOrEncoded)`, -/// Error>` while `ReturnValue` being the return value that is specified in the trait -/// declaration. +/// constructed like [`Result`]`<, Error>` while `ReturnValue` being the return +/// value that is specified in the trait declaration. /// /// ## Example /// ```rust /// # use sp_runtime::{traits::Block as BlockT, generic::BlockId}; /// # use sp_test_primitives::Block; -/// # use sp_core::NativeOrEncoded; /// # use codec; /// # /// # sp_api::decl_runtime_apis! { @@ -368,13 +432,13 @@ pub use sp_api_proc_macro::impl_runtime_apis; /// sp_api::mock_impl_runtime_apis! { /// impl Balance for MockApi { /// #[advanced] -/// fn get_balance(&self, at: &BlockId) -> Result, sp_api::ApiError> { +/// fn get_balance(&self, at: &BlockId) -> Result { /// println!("Being called at: {}", at); /// /// Ok(self.balance.into()) /// } /// #[advanced] -/// fn set_balance(at: &BlockId, val: u64) -> Result, sp_api::ApiError> { +/// fn set_balance(at: &BlockId, val: u64) -> Result<(), sp_api::ApiError> { /// if let BlockId::Number(1) = at { /// println!("Being called to set balance to: {}", val); /// } diff --git a/primitives/api/test/tests/decl_and_impl.rs b/primitives/api/test/tests/decl_and_impl.rs index 1db416a1d3db6..42628830cc7fa 100644 --- a/primitives/api/test/tests/decl_and_impl.rs +++ b/primitives/api/test/tests/decl_and_impl.rs @@ -18,7 +18,6 @@ use sp_api::{ decl_runtime_apis, impl_runtime_apis, mock_impl_runtime_apis, ApiError, ApiExt, RuntimeApiInfo, }; -use sp_core::NativeOrEncoded; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, GetNodeBlockType}, @@ -47,6 +46,15 @@ decl_runtime_apis! { #[changed_in(2)] fn same_name() -> String; } + + #[api_version(2)] + pub trait ApiWithMultipleVersions { + fn stable_one(data: u64); + #[api_version(3)] + fn new_one(); + #[api_version(4)] + fn glory_one(); + } } impl_runtime_apis! { @@ -72,6 +80,13 @@ impl_runtime_apis! { fn same_name() {} } + #[api_version(3)] + impl self::ApiWithMultipleVersions for Runtime { + fn stable_one(_: u64) {} + + fn new_one() {} + } + impl sp_api::Core for Runtime { fn version() -> sp_version::RuntimeVersion { unimplemented!() @@ -104,22 +119,12 @@ mock_impl_runtime_apis! { } #[advanced] - fn same_name(_: &BlockId) -> - Result< - NativeOrEncoded<()>, - ApiError - > - { + fn same_name(_: &BlockId) -> Result<(), ApiError> { Ok(().into()) } #[advanced] - fn wild_card(at: &BlockId, _: u32) -> - Result< - NativeOrEncoded<()>, - ApiError - > - { + fn wild_card(at: &BlockId, _: u32) -> Result<(), ApiError> { if let BlockId::Number(1337) = at { // yeah Ok(().into()) @@ -176,6 +181,9 @@ fn check_runtime_api_info() { &runtime_decl_for_ApiWithCustomVersion::ID, ); assert_eq!(>::VERSION, 2); + + // The stable version of the API + assert_eq!(>::VERSION, 2); } fn check_runtime_api_versions_contains() { @@ -186,6 +194,9 @@ fn check_runtime_api_versions_contains() { fn check_runtime_api_versions() { check_runtime_api_versions_contains::>(); check_runtime_api_versions_contains::>(); + assert!(RUNTIME_API_VERSIONS + .iter() + .any(|v| v == &(>::ID, 3))); check_runtime_api_versions_contains::>(); } @@ -198,7 +209,7 @@ fn mock_runtime_api_has_api() { } #[test] -#[should_panic(expected = "Mocked runtime apis don't support calling deprecated api versions")] +#[should_panic(expected = "Calling deprecated methods is not supported by mocked runtime api.")] fn mock_runtime_api_panics_on_calling_old_version() { let mock = MockApi { block: None }; diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index ba42b342377c7..968bda6885d0d 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -25,7 +25,7 @@ use sp_state_machine::{ }; use substrate_test_runtime_client::{ prelude::*, - runtime::{Block, DecodeFails, Header, TestAPI, Transfer}, + runtime::{Block, Header, TestAPI, Transfer}, DefaultTestClientBuilderExt, TestClientBuilder, }; @@ -51,28 +51,6 @@ fn calling_wasm_runtime_function() { calling_function_with_strat(ExecutionStrategy::AlwaysWasm); } -#[test] -#[should_panic(expected = "FailedToConvertParameter { function: \"fail_convert_parameter\"")] -fn calling_native_runtime_function_with_non_decodable_parameter() { - let client = TestClientBuilder::new() - .set_execution_strategy(ExecutionStrategy::NativeWhenPossible) - .build(); - let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); - runtime_api.fail_convert_parameter(&block_id, DecodeFails::default()).unwrap(); -} - -#[test] -#[should_panic(expected = "FailedToConvertReturnValue { function: \"fail_convert_return_value\"")] -fn calling_native_runtime_function_with_non_decodable_return_value() { - let client = TestClientBuilder::new() - .set_execution_strategy(ExecutionStrategy::NativeWhenPossible) - .build(); - let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); - runtime_api.fail_convert_return_value(&block_id).unwrap(); -} - #[test] fn calling_native_runtime_signature_changed_function() { let client = TestClientBuilder::new() diff --git a/primitives/api/test/tests/trybuild.rs b/primitives/api/test/tests/trybuild.rs index f3d6aa59a0336..13af1ded7dc6b 100644 --- a/primitives/api/test/tests/trybuild.rs +++ b/primitives/api/test/tests/trybuild.rs @@ -30,4 +30,5 @@ fn ui() { let t = trybuild::TestCases::new(); t.compile_fail("tests/ui/*.rs"); + t.pass("tests/ui/positive_cases/*.rs"); } diff --git a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr index b1478e2f53344..2c47c2f480add 100644 --- a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr +++ b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr @@ -15,49 +15,6 @@ note: type in trait = note: expected fn pointer `fn(u64)` found fn pointer `fn(std::string::String)` -error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait - --> tests/ui/impl_incorrect_method_signature.rs:17:1 - | -17 | sp_api::impl_runtime_apis! { - | -^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | _expected `u64`, found struct `std::string::String` - | | -18 | | impl self::Api for Runtime { -19 | | fn test(data: String) {} -20 | | } -... | -32 | | } -33 | | } - | |_- help: change the parameter type to match the trait: `std::option::Option` - | -note: type in trait - --> tests/ui/impl_incorrect_method_signature.rs:11:1 - | -11 | / sp_api::decl_runtime_apis! { -12 | | pub trait Api { -13 | | fn test(data: u64); -14 | | } -15 | | } - | |_^ - = note: expected fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option, Vec<_>) -> Result<_, _>` - found fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option, Vec<_>) -> Result<_, _>` - = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0308]: mismatched types - --> tests/ui/impl_incorrect_method_signature.rs:17:1 - | -17 | / sp_api::impl_runtime_apis! { -18 | | impl self::Api for Runtime { -19 | | fn test(data: String) {} -20 | | } -... | -32 | | } -33 | | } - | |_^ expected `u64`, found struct `std::string::String` - | - = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0308]: mismatched types --> tests/ui/impl_incorrect_method_signature.rs:19:11 | diff --git a/primitives/api/test/tests/ui/impl_missing_version.rs b/primitives/api/test/tests/ui/impl_missing_version.rs new file mode 100644 index 0000000000000..63e0599622ac9 --- /dev/null +++ b/primitives/api/test/tests/ui/impl_missing_version.rs @@ -0,0 +1,40 @@ +use sp_runtime::traits::{Block as BlockT, GetNodeBlockType}; +use substrate_test_runtime_client::runtime::Block; + +struct Runtime {} +impl GetNodeBlockType for Runtime { + type NodeBlock = Block; +} + +sp_api::decl_runtime_apis! { + #[api_version(2)] + pub trait Api { + fn test1(); + fn test2(); + #[api_version(3)] + fn test3(); + } +} + +sp_api::impl_runtime_apis! { + #[api_version(4)] + impl self::Api for Runtime { + fn test1() {} + fn test2() {} + fn test3() {} + } + + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) { + unimplemented!() + } + } +} + +fn main() {} diff --git a/primitives/api/test/tests/ui/impl_missing_version.stderr b/primitives/api/test/tests/ui/impl_missing_version.stderr new file mode 100644 index 0000000000000..c0abeffe0cccf --- /dev/null +++ b/primitives/api/test/tests/ui/impl_missing_version.stderr @@ -0,0 +1,14 @@ +error[E0433]: failed to resolve: could not find `ApiV4` in `runtime_decl_for_Api` + --> tests/ui/impl_missing_version.rs:21:13 + | +21 | impl self::Api for Runtime { + | ^^^ could not find `ApiV4` in `runtime_decl_for_Api` + +error[E0405]: cannot find trait `ApiV4` in module `self::runtime_decl_for_Api` + --> tests/ui/impl_missing_version.rs:21:13 + | +11 | pub trait Api { + | ------------- similarly named trait `ApiV2` defined here +... +21 | impl self::Api for Runtime { + | ^^^ help: a trait with a similar name exists: `ApiV2` diff --git a/primitives/api/test/tests/ui/invalid_api_version.rs b/primitives/api/test/tests/ui/invalid_api_version_1.rs similarity index 100% rename from primitives/api/test/tests/ui/invalid_api_version.rs rename to primitives/api/test/tests/ui/invalid_api_version_1.rs diff --git a/primitives/api/test/tests/ui/invalid_api_version.stderr b/primitives/api/test/tests/ui/invalid_api_version_1.stderr similarity index 65% rename from primitives/api/test/tests/ui/invalid_api_version.stderr rename to primitives/api/test/tests/ui/invalid_api_version_1.stderr index 7770bc70e72d6..53ffce959bb66 100644 --- a/primitives/api/test/tests/ui/invalid_api_version.stderr +++ b/primitives/api/test/tests/ui/invalid_api_version_1.stderr @@ -1,5 +1,5 @@ error: Unexpected `api_version` attribute. The supported format is `api_version(1)` - --> $DIR/invalid_api_version.rs:2:4 + --> tests/ui/invalid_api_version_1.rs:2:2 | 2 | #[api_version] - | ^^^^^^^^^^^ + | ^ diff --git a/primitives/api/test/tests/ui/invalid_api_version_2.stderr b/primitives/api/test/tests/ui/invalid_api_version_2.stderr index 7ca6a7eebe49c..0c5274d4680ff 100644 --- a/primitives/api/test/tests/ui/invalid_api_version_2.stderr +++ b/primitives/api/test/tests/ui/invalid_api_version_2.stderr @@ -1,5 +1,5 @@ error: Unexpected `api_version` attribute. The supported format is `api_version(1)` - --> $DIR/invalid_api_version_2.rs:2:4 + --> tests/ui/invalid_api_version_2.rs:2:2 | 2 | #[api_version("1")] - | ^^^^^^^^^^^ + | ^ diff --git a/primitives/api/test/tests/ui/invalid_api_version_3.stderr b/primitives/api/test/tests/ui/invalid_api_version_3.stderr index cef4763a6de96..4a34a7aa9b47a 100644 --- a/primitives/api/test/tests/ui/invalid_api_version_3.stderr +++ b/primitives/api/test/tests/ui/invalid_api_version_3.stderr @@ -1,5 +1,5 @@ error: Unexpected `api_version` attribute. The supported format is `api_version(1)` - --> $DIR/invalid_api_version_3.rs:2:4 + --> tests/ui/invalid_api_version_3.rs:2:2 | 2 | #[api_version()] - | ^^^^^^^^^^^ + | ^ diff --git a/primitives/api/test/tests/ui/invalid_api_version_4.rs b/primitives/api/test/tests/ui/invalid_api_version_4.rs new file mode 100644 index 0000000000000..37b5b6ffa25d1 --- /dev/null +++ b/primitives/api/test/tests/ui/invalid_api_version_4.rs @@ -0,0 +1,8 @@ +sp_api::decl_runtime_apis! { + pub trait Api { + #[api_version("1")] + fn test(data: u64); + } +} + +fn main() {} diff --git a/primitives/api/test/tests/ui/invalid_api_version_4.stderr b/primitives/api/test/tests/ui/invalid_api_version_4.stderr new file mode 100644 index 0000000000000..57541a97f6c91 --- /dev/null +++ b/primitives/api/test/tests/ui/invalid_api_version_4.stderr @@ -0,0 +1,5 @@ +error: Unexpected `api_version` attribute. The supported format is `api_version(1)` + --> tests/ui/invalid_api_version_4.rs:3:3 + | +3 | #[api_version("1")] + | ^ diff --git a/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.rs b/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.rs new file mode 100644 index 0000000000000..b4f43cd401bba --- /dev/null +++ b/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.rs @@ -0,0 +1,9 @@ +sp_api::decl_runtime_apis! { + #[api_version(2)] + pub trait Api { + #[api_version(1)] + fn test(data: u64); + } +} + +fn main() {} \ No newline at end of file diff --git a/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.stderr b/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.stderr new file mode 100644 index 0000000000000..ec4b594023a05 --- /dev/null +++ b/primitives/api/test/tests/ui/method_ver_lower_than_trait_ver.stderr @@ -0,0 +1,11 @@ +error: Method version `1` is older than (or equal to) trait version `2`.Methods can't define versions older than the trait version. + --> tests/ui/method_ver_lower_than_trait_ver.rs:4:3 + | +4 | #[api_version(1)] + | ^ + +error: Trait version is set here. + --> tests/ui/method_ver_lower_than_trait_ver.rs:2:2 + | +2 | #[api_version(2)] + | ^ diff --git a/primitives/api/test/tests/ui/missing_versioned_method.rs b/primitives/api/test/tests/ui/missing_versioned_method.rs new file mode 100644 index 0000000000000..d973a94c2101d --- /dev/null +++ b/primitives/api/test/tests/ui/missing_versioned_method.rs @@ -0,0 +1,39 @@ +use sp_runtime::traits::{Block as BlockT, GetNodeBlockType}; +use substrate_test_runtime_client::runtime::Block; + +struct Runtime {} +impl GetNodeBlockType for Runtime { + type NodeBlock = Block; +} + +sp_api::decl_runtime_apis! { + #[api_version(2)] + pub trait Api { + fn test1(); + fn test2(); + #[api_version(3)] + fn test3(); + } +} + +sp_api::impl_runtime_apis! { + #[api_version(3)] + impl self::Api for Runtime { + fn test1() {} + fn test2() {} + } + + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) { + unimplemented!() + } + } +} + +fn main() {} diff --git a/primitives/api/test/tests/ui/missing_versioned_method.stderr b/primitives/api/test/tests/ui/missing_versioned_method.stderr new file mode 100644 index 0000000000000..e3ace7979c27e --- /dev/null +++ b/primitives/api/test/tests/ui/missing_versioned_method.stderr @@ -0,0 +1,8 @@ +error[E0046]: not all trait items implemented, missing: `test3` + --> tests/ui/missing_versioned_method.rs:21:2 + | +15 | fn test3(); + | ----------- `test3` from trait +... +21 | impl self::Api for Runtime { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `test3` in implementation diff --git a/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs b/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs new file mode 100644 index 0000000000000..72358b99164d5 --- /dev/null +++ b/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs @@ -0,0 +1,42 @@ +use sp_runtime::traits::{Block as BlockT, GetNodeBlockType}; +use substrate_test_runtime_client::runtime::Block; + +struct Runtime {} +impl GetNodeBlockType for Runtime { + type NodeBlock = Block; +} + +sp_api::decl_runtime_apis! { + #[api_version(2)] + pub trait Api { + fn test1(); + fn test2(); + #[api_version(3)] + fn test3(); + #[api_version(4)] + fn test4(); + } +} + +sp_api::impl_runtime_apis! { + #[api_version(4)] + impl self::Api for Runtime { + fn test1() {} + fn test2() {} + fn test4() {} + } + + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) { + unimplemented!() + } + } +} + +fn main() {} diff --git a/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.stderr b/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.stderr new file mode 100644 index 0000000000000..7354fbd537fd7 --- /dev/null +++ b/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.stderr @@ -0,0 +1,8 @@ +error[E0046]: not all trait items implemented, missing: `test3` + --> tests/ui/missing_versioned_method_multiple_vers.rs:23:2 + | +15 | fn test3(); + | ----------- `test3` from trait +... +23 | impl self::Api for Runtime { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `test3` in implementation diff --git a/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.rs b/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.rs index fd654ffdc63d6..aeef40f4c77d6 100644 --- a/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.rs +++ b/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.rs @@ -12,7 +12,7 @@ struct MockApi; sp_api::mock_impl_runtime_apis! { impl Api for MockApi { #[advanced] - fn test(&self, _: BlockId) -> Result, ApiError> { + fn test(&self, _: BlockId) -> Result<(), ApiError> { Ok(().into()) } } diff --git a/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.stderr b/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.stderr index befe67c1d0b4a..3b3c4e94c3121 100644 --- a/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.stderr +++ b/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.stderr @@ -1,10 +1,10 @@ error: `BlockId` needs to be taken by reference and not by value! - --> $DIR/mock_advanced_block_id_by_value.rs:12:1 + --> tests/ui/mock_advanced_block_id_by_value.rs:12:1 | 12 | / sp_api::mock_impl_runtime_apis! { 13 | | impl Api for MockApi { 14 | | #[advanced] -15 | | fn test(&self, _: BlockId) -> Result, ApiError> { +15 | | fn test(&self, _: BlockId) -> Result<(), ApiError> { ... | 18 | | } 19 | | } diff --git a/primitives/api/test/tests/ui/mock_advanced_missing_blockid.rs b/primitives/api/test/tests/ui/mock_advanced_missing_blockid.rs index a15ef133fa6c4..76bf5f1aa7459 100644 --- a/primitives/api/test/tests/ui/mock_advanced_missing_blockid.rs +++ b/primitives/api/test/tests/ui/mock_advanced_missing_blockid.rs @@ -12,7 +12,7 @@ struct MockApi; sp_api::mock_impl_runtime_apis! { impl Api for MockApi { #[advanced] - fn test(&self) -> Result, ApiError> { + fn test(&self) -> Result<(), ApiError> { Ok(().into()) } } diff --git a/primitives/api/test/tests/ui/mock_advanced_missing_blockid.stderr b/primitives/api/test/tests/ui/mock_advanced_missing_blockid.stderr index 87d3660316b1e..b9ce7324b5caa 100644 --- a/primitives/api/test/tests/ui/mock_advanced_missing_blockid.stderr +++ b/primitives/api/test/tests/ui/mock_advanced_missing_blockid.stderr @@ -1,5 +1,5 @@ error: If using the `advanced` attribute, it is required that the function takes at least one argument, the `BlockId`. - --> $DIR/mock_advanced_missing_blockid.rs:15:3 + --> tests/ui/mock_advanced_missing_blockid.rs:15:3 | -15 | fn test(&self) -> Result, ApiError> { +15 | fn test(&self) -> Result<(), ApiError> { | ^^ diff --git a/primitives/api/test/tests/ui/mock_only_self_reference.stderr b/primitives/api/test/tests/ui/mock_only_self_reference.stderr index c67de70b9c140..430f63eee1660 100644 --- a/primitives/api/test/tests/ui/mock_only_self_reference.stderr +++ b/primitives/api/test/tests/ui/mock_only_self_reference.stderr @@ -10,62 +10,80 @@ error: Only `&self` is supported! 16 | fn test2(&mut self, data: u64) {} | ^ -error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait +error[E0050]: method `test` has 2 parameters but the declaration in trait `Api::test` has 3 --> tests/ui/mock_only_self_reference.rs:12:1 | -12 | sp_api::mock_impl_runtime_apis! { - | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | _expected `u64`, found `()` - | | +3 | / sp_api::decl_runtime_apis! { +4 | | pub trait Api { +5 | | fn test(data: u64); + | |_________________________- trait requires 3 parameters +... +12 | / sp_api::mock_impl_runtime_apis! { 13 | | impl Api for MockApi { 14 | | fn test(self, data: u64) {} 15 | | 16 | | fn test2(&mut self, data: u64) {} 17 | | } 18 | | } - | |_- help: change the parameter type to match the trait: `Option` + | |_^ expected 3 parameters, found 2 | -note: type in trait - --> tests/ui/mock_only_self_reference.rs:3:1 + = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0050]: method `test2` has 2 parameters but the declaration in trait `Api::test2` has 3 + --> tests/ui/mock_only_self_reference.rs:12:1 | 3 | / sp_api::decl_runtime_apis! { 4 | | pub trait Api { 5 | | fn test(data: u64); 6 | | fn test2(data: u64); -7 | | } -8 | | } - | |_^ - = note: expected fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option, Vec<_>) -> Result<_, _>` - found fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option<()>, Vec<_>) -> Result<_, _>` + | |__________________________- trait requires 3 parameters +... +12 | / sp_api::mock_impl_runtime_apis! { +13 | | impl Api for MockApi { +14 | | fn test(self, data: u64) {} +15 | | +16 | | fn test2(&mut self, data: u64) {} +17 | | } +18 | | } + | |_^ expected 3 parameters, found 2 + | = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0053]: method `Api_test2_runtime_api_impl` has an incompatible type for trait +error[E0050]: method `test_with_context` has 3 parameters but the declaration in trait `Api::test_with_context` has 4 --> tests/ui/mock_only_self_reference.rs:12:1 | -12 | sp_api::mock_impl_runtime_apis! { - | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | _expected `u64`, found `()` - | | +3 | / sp_api::decl_runtime_apis! { +4 | | pub trait Api { +5 | | fn test(data: u64); + | |_________________________- trait requires 4 parameters +... +12 | / sp_api::mock_impl_runtime_apis! { 13 | | impl Api for MockApi { 14 | | fn test(self, data: u64) {} 15 | | 16 | | fn test2(&mut self, data: u64) {} 17 | | } 18 | | } - | |_- help: change the parameter type to match the trait: `Option` + | |_^ expected 4 parameters, found 3 | -note: type in trait - --> tests/ui/mock_only_self_reference.rs:3:1 + = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0050]: method `test2_with_context` has 3 parameters but the declaration in trait `Api::test2_with_context` has 4 + --> tests/ui/mock_only_self_reference.rs:12:1 | 3 | / sp_api::decl_runtime_apis! { 4 | | pub trait Api { 5 | | fn test(data: u64); 6 | | fn test2(data: u64); -7 | | } -8 | | } - | |_^ - = note: expected fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option, Vec<_>) -> Result<_, _>` - found fn pointer `fn(&MockApi, &BlockId, Extrinsic>>, ExecutionContext, Option<()>, Vec<_>) -> Result<_, _>` + | |__________________________- trait requires 4 parameters +... +12 | / sp_api::mock_impl_runtime_apis! { +13 | | impl Api for MockApi { +14 | | fn test(self, data: u64) {} +15 | | +16 | | fn test2(&mut self, data: u64) {} +17 | | } +18 | | } + | |_^ expected 4 parameters, found 3 + | = note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/primitives/api/test/tests/ui/positive_cases/default_impls.rs b/primitives/api/test/tests/ui/positive_cases/default_impls.rs new file mode 100644 index 0000000000000..3434db1089f05 --- /dev/null +++ b/primitives/api/test/tests/ui/positive_cases/default_impls.rs @@ -0,0 +1,41 @@ +use sp_runtime::traits::{Block as BlockT, GetNodeBlockType}; +use substrate_test_runtime_client::runtime::Block; + +struct Runtime {} +impl GetNodeBlockType for Runtime { + type NodeBlock = Block; +} + +sp_api::decl_runtime_apis! { + #[api_version(2)] + pub trait Api { + fn test1(); + fn test2(); + #[api_version(3)] + fn test3(); + #[api_version(4)] + fn test4(); + } +} + +sp_api::impl_runtime_apis! { + #[api_version(2)] + impl self::Api for Runtime { + fn test1() {} + fn test2() {} + } + + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) { + unimplemented!() + } + } +} + +fn main() {} diff --git a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index dbc0f6def3aa5..479e1cf05a9d1 100644 --- a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -15,49 +15,6 @@ note: type in trait = note: expected fn pointer `fn(u64)` found fn pointer `fn(&u64)` -error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait - --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:17:1 - | -17 | sp_api::impl_runtime_apis! { - | -^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | _expected `u64`, found `&u64` - | | -18 | | impl self::Api for Runtime { -19 | | fn test(data: &u64) { -20 | | unimplemented!() -... | -34 | | } -35 | | } - | |_- help: change the parameter type to match the trait: `std::option::Option` - | -note: type in trait - --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:11:1 - | -11 | / sp_api::decl_runtime_apis! { -12 | | pub trait Api { -13 | | fn test(data: u64); -14 | | } -15 | | } - | |_^ - = note: expected fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option, Vec<_>) -> Result<_, _>` - found fn pointer `fn(&RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall>, &BlockId<__SR_API_BLOCK__>, ExecutionContext, std::option::Option<&u64>, Vec<_>) -> Result<_, _>` - = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0308]: mismatched types - --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:17:1 - | -17 | / sp_api::impl_runtime_apis! { -18 | | impl self::Api for Runtime { -19 | | fn test(data: &u64) { -20 | | unimplemented!() -... | -34 | | } -35 | | } - | |_^ expected `u64`, found `&u64` - | - = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0308]: mismatched types --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:19:11 | From d558a21dda1a6f9df919c442527b84975bcfee47 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sat, 13 Aug 2022 13:05:39 +0100 Subject: [PATCH 1061/1472] Fix Gov V2 Benchmarks (#12022) * better benchmark log * Update lib.rs * fix gov2 benchmarks * saturating math + fmt * add comment --- frame/referenda/src/benchmarking.rs | 12 ++++++++++-- frame/referenda/src/lib.rs | 6 ++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 9abd3768f780c..dfca7cdf465dd 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -101,8 +101,16 @@ fn info(index: ReferendumIndex) -> &'static TrackInfoOf { } fn make_passing_after(index: ReferendumIndex, period_portion: Perbill) { - let support = info::(index).min_support.threshold(period_portion); - let approval = info::(index).min_approval.threshold(period_portion); + // We add an extra 1 percent to handle any perbill rounding errors which may cause + // a proposal to not actually pass. + let support = info::(index) + .min_support + .threshold(period_portion) + .saturating_add(Perbill::from_percent(1)); + let approval = info::(index) + .min_approval + .threshold(period_portion) + .saturating_add(Perbill::from_percent(1)); Referenda::::access_poll(index, |status| { if let PollStatus::Ongoing(tally, class) = status { *tally = T::Tally::from_requirements(support, approval, class); diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 15c5562d64c84..e9e14e1d4a96a 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -699,7 +699,8 @@ impl, I: 'static> Pallet { when: T::BlockNumber, ) -> Option<(T::BlockNumber, ScheduleAddressOf)> { let alarm_interval = T::AlarmInterval::get().max(One::one()); - let when = (when + alarm_interval - One::one()) / alarm_interval * alarm_interval; + let when = when.saturating_add(alarm_interval).saturating_sub(One::one()) / + (alarm_interval.saturating_mul(alarm_interval)).max(One::one()); let maybe_result = T::Scheduler::schedule( DispatchTime::At(when), None, @@ -752,7 +753,8 @@ impl, I: 'static> Pallet { None }; let deciding_status = DecidingStatus { since: now, confirming }; - let alarm = Self::decision_time(&deciding_status, &status.tally, status.track, track); + let alarm = Self::decision_time(&deciding_status, &status.tally, status.track, track) + .max(now.saturating_add(One::one())); status.deciding = Some(deciding_status); let branch = if is_passing { BeginDecidingBranch::Passing } else { BeginDecidingBranch::Failing }; From 055453ebdf00db9e59ef5af0c59c1b4e39267813 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sat, 13 Aug 2022 16:07:10 +0100 Subject: [PATCH 1062/1472] Add Benchmarking Instance to Pallets (#12026) * benchmark instance * add benchmark instance to conviction voting * instance on bags list * fmt --- frame/bags-list/src/benchmarks.rs | 6 +- frame/conviction-voting/src/benchmarking.rs | 117 +++--- frame/referenda/src/benchmarking.rs | 408 ++++++++++---------- 3 files changed, 266 insertions(+), 265 deletions(-) diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index dba0c9ee1e623..bb45da076f751 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -25,7 +25,7 @@ use frame_support::{assert_ok, traits::Get}; use frame_system::RawOrigin as SystemOrigin; use sp_runtime::traits::One; -frame_benchmarking::benchmarks! { +frame_benchmarking::benchmarks_instance_pallet! { rebag_non_terminal { // An expensive case for rebag-ing (rebag a non-terminal node): // @@ -97,7 +97,7 @@ frame_benchmarking::benchmarks! { // clear any pre-existing storage. // NOTE: safe to call outside block production - List::::unsafe_clear(); + List::::unsafe_clear(); // define our origin and destination thresholds. let origin_bag_thresh = T::BagThresholds::get()[0]; @@ -146,7 +146,7 @@ frame_benchmarking::benchmarks! { // clear any pre-existing storage. // NOTE: safe to call outside block production - List::::unsafe_clear(); + List::::unsafe_clear(); let bag_thresh = T::BagThresholds::get()[0]; diff --git a/frame/conviction-voting/src/benchmarking.rs b/frame/conviction-voting/src/benchmarking.rs index 53ac7a07302f9..d472770832497 100644 --- a/frame/conviction-voting/src/benchmarking.rs +++ b/frame/conviction-voting/src/benchmarking.rs @@ -20,7 +20,7 @@ use super::*; use assert_matches::assert_matches; -use frame_benchmarking::{account, benchmarks, whitelist_account}; +use frame_benchmarking::{account, benchmarks_instance_pallet, whitelist_account}; use frame_support::{ dispatch::RawOrigin, traits::{fungible, Currency, Get}, @@ -34,8 +34,9 @@ const SEED: u32 = 0; /// Fill all classes as much as possible up to `MaxVotes` and return the Class with the most votes /// ongoing. -fn fill_voting() -> (ClassOf, BTreeMap, Vec>>) { - let mut r = BTreeMap::, Vec>>::new(); +fn fill_voting, I: 'static>( +) -> (ClassOf, BTreeMap, Vec>>) { + let mut r = BTreeMap::, Vec>>::new(); for class in T::Polls::classes().into_iter() { for _ in 0..T::MaxVotes::get() { match T::Polls::create_ongoing(class.clone()) { @@ -48,34 +49,34 @@ fn fill_voting() -> (ClassOf, BTreeMap, Vec> (c, r) } -fn funded_account(name: &'static str, index: u32) -> T::AccountId { +fn funded_account, I: 'static>(name: &'static str, index: u32) -> T::AccountId { let caller: T::AccountId = account(name, index, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); caller } -fn account_vote(b: BalanceOf) -> AccountVote> { +fn account_vote, I: 'static>(b: BalanceOf) -> AccountVote> { let v = Vote { aye: true, conviction: Conviction::Locked1x }; AccountVote::Standard { vote: v, balance: b } } -benchmarks! { +benchmarks_instance_pallet! { where_clause { where T::MaxVotes: core::fmt::Debug } vote_new { - let caller = funded_account::("caller", 0); + let caller = funded_account::("caller", 0); whitelist_account!(caller); - let account_vote = account_vote::(100u32.into()); + let account_vote = account_vote::(100u32.into()); - let (class, all_polls) = fill_voting::(); + let (class, all_polls) = fill_voting::(); let polls = &all_polls[&class]; let r = polls.len() - 1; // We need to create existing votes for i in polls.iter().skip(1) { - ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, account_vote)?; + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, account_vote)?; } - let votes = match VotingFor::::get(&caller, &class) { + let votes = match VotingFor::::get(&caller, &class) { Voting::Casting(Casting { votes, .. }) => votes, _ => return Err("Votes are not direct".into()), }; @@ -85,52 +86,52 @@ benchmarks! { }: vote(RawOrigin::Signed(caller.clone()), index, account_vote) verify { assert_matches!( - VotingFor::::get(&caller, &class), + VotingFor::::get(&caller, &class), Voting::Casting(Casting { votes, .. }) if votes.len() == (r + 1) as usize ); } vote_existing { - let caller = funded_account::("caller", 0); + let caller = funded_account::("caller", 0); whitelist_account!(caller); - let old_account_vote = account_vote::(100u32.into()); + let old_account_vote = account_vote::(100u32.into()); - let (class, all_polls) = fill_voting::(); + let (class, all_polls) = fill_voting::(); let polls = &all_polls[&class]; let r = polls.len(); // We need to create existing votes for i in polls.iter() { - ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote)?; + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote)?; } - let votes = match VotingFor::::get(&caller, &class) { + let votes = match VotingFor::::get(&caller, &class) { Voting::Casting(Casting { votes, .. }) => votes, _ => return Err("Votes are not direct".into()), }; assert_eq!(votes.len(), r, "Votes were not recorded."); - let new_account_vote = account_vote::(200u32.into()); + let new_account_vote = account_vote::(200u32.into()); let index = polls[0]; }: vote(RawOrigin::Signed(caller.clone()), index, new_account_vote) verify { assert_matches!( - VotingFor::::get(&caller, &class), + VotingFor::::get(&caller, &class), Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize ); } remove_vote { - let caller = funded_account::("caller", 0); + let caller = funded_account::("caller", 0); whitelist_account!(caller); - let old_account_vote = account_vote::(100u32.into()); + let old_account_vote = account_vote::(100u32.into()); - let (class, all_polls) = fill_voting::(); + let (class, all_polls) = fill_voting::(); let polls = &all_polls[&class]; let r = polls.len(); // We need to create existing votes for i in polls.iter() { - ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote)?; + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote)?; } - let votes = match VotingFor::::get(&caller, &class) { + let votes = match VotingFor::::get(&caller, &class) { Voting::Casting(Casting { votes, .. }) => votes, _ => return Err("Votes are not direct".into()), }; @@ -140,25 +141,25 @@ benchmarks! { }: _(RawOrigin::Signed(caller.clone()), Some(class.clone()), index) verify { assert_matches!( - VotingFor::::get(&caller, &class), + VotingFor::::get(&caller, &class), Voting::Casting(Casting { votes, .. }) if votes.len() == (r - 1) as usize ); } remove_other_vote { - let caller = funded_account::("caller", 0); - let voter = funded_account::("caller", 0); + let caller = funded_account::("caller", 0); + let voter = funded_account::("caller", 0); whitelist_account!(caller); - let old_account_vote = account_vote::(100u32.into()); + let old_account_vote = account_vote::(100u32.into()); - let (class, all_polls) = fill_voting::(); + let (class, all_polls) = fill_voting::(); let polls = &all_polls[&class]; let r = polls.len(); // We need to create existing votes for i in polls.iter() { - ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, old_account_vote)?; + ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, old_account_vote)?; } - let votes = match VotingFor::::get(&caller, &class) { + let votes = match VotingFor::::get(&caller, &class) { Voting::Casting(Casting { votes, .. }) => votes, _ => return Err("Votes are not direct".into()), }; @@ -169,7 +170,7 @@ benchmarks! { }: _(RawOrigin::Signed(caller.clone()), voter.clone(), class.clone(), index) verify { assert_matches!( - VotingFor::::get(&voter, &class), + VotingFor::::get(&voter, &class), Voting::Casting(Casting { votes, .. }) if votes.len() == (r - 1) as usize ); } @@ -177,44 +178,44 @@ benchmarks! { delegate { let r in 0 .. T::MaxVotes::get().min(T::Polls::max_ongoing().1); - let all_polls = fill_voting::().1; + let all_polls = fill_voting::().1; let class = T::Polls::max_ongoing().0; let polls = &all_polls[&class]; - let voter = funded_account::("voter", 0); - let caller = funded_account::("caller", 0); + let voter = funded_account::("voter", 0); + let caller = funded_account::("caller", 0); whitelist_account!(caller); - let delegated_balance: BalanceOf = 1000u32.into(); - let delegate_vote = account_vote::(delegated_balance); + let delegated_balance: BalanceOf = 1000u32.into(); + let delegate_vote = account_vote::(delegated_balance); // We need to create existing delegations for i in polls.iter().take(r as usize) { - ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote)?; + ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote)?; } assert_matches!( - VotingFor::::get(&voter, &class), + VotingFor::::get(&voter, &class), Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize ); }: _(RawOrigin::Signed(caller.clone()), class.clone(), voter, Conviction::Locked1x, delegated_balance) verify { - assert_matches!(VotingFor::::get(&caller, &class), Voting::Delegating(_)); + assert_matches!(VotingFor::::get(&caller, &class), Voting::Delegating(_)); } undelegate { let r in 0 .. T::MaxVotes::get().min(T::Polls::max_ongoing().1); - let all_polls = fill_voting::().1; + let all_polls = fill_voting::().1; let class = T::Polls::max_ongoing().0; let polls = &all_polls[&class]; - let voter = funded_account::("voter", 0); - let caller = funded_account::("caller", 0); + let voter = funded_account::("voter", 0); + let caller = funded_account::("caller", 0); whitelist_account!(caller); - let delegated_balance: BalanceOf = 1000u32.into(); - let delegate_vote = account_vote::(delegated_balance); + let delegated_balance: BalanceOf = 1000u32.into(); + let delegate_vote = account_vote::(delegated_balance); - ConvictionVoting::::delegate( + ConvictionVoting::::delegate( RawOrigin::Signed(caller.clone()).into(), class.clone(), voter.clone(), @@ -224,31 +225,31 @@ benchmarks! { // We need to create delegations for i in polls.iter().take(r as usize) { - ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote)?; + ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote)?; } assert_matches!( - VotingFor::::get(&voter, &class), + VotingFor::::get(&voter, &class), Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize ); - assert_matches!(VotingFor::::get(&caller, &class), Voting::Delegating(_)); + assert_matches!(VotingFor::::get(&caller, &class), Voting::Delegating(_)); }: _(RawOrigin::Signed(caller.clone()), class.clone()) verify { - assert_matches!(VotingFor::::get(&caller, &class), Voting::Casting(_)); + assert_matches!(VotingFor::::get(&caller, &class), Voting::Casting(_)); } unlock { - let caller = funded_account::("caller", 0); + let caller = funded_account::("caller", 0); whitelist_account!(caller); - let normal_account_vote = account_vote::(T::Currency::free_balance(&caller) - 100u32.into()); - let big_account_vote = account_vote::(T::Currency::free_balance(&caller)); + let normal_account_vote = account_vote::(T::Currency::free_balance(&caller) - 100u32.into()); + let big_account_vote = account_vote::(T::Currency::free_balance(&caller)); // Fill everything up to the max by filling all classes with votes and voting on them all. - let (class, all_polls) = fill_voting::(); + let (class, all_polls) = fill_voting::(); assert!(all_polls.len() > 0); for (class, polls) in all_polls.iter() { assert!(polls.len() > 0); for i in polls.iter() { - ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, normal_account_vote)?; + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, normal_account_vote)?; } } @@ -257,12 +258,12 @@ benchmarks! { // Vote big on the class with the most ongoing votes of them to bump the lock and make it // hard to recompute when removed. - ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), polls[0], big_account_vote)?; + ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), polls[0], big_account_vote)?; let now_usable = >::reducible_balance(&caller, false); assert_eq!(orig_usable - now_usable, 100u32.into()); // Remove the vote - ConvictionVoting::::remove_vote(RawOrigin::Signed(caller.clone()).into(), Some(class.clone()), polls[0])?; + ConvictionVoting::::remove_vote(RawOrigin::Signed(caller.clone()).into(), Some(class.clone()), polls[0])?; // We can now unlock on `class` from 200 to 100... }: _(RawOrigin::Signed(caller.clone()), class, caller.clone()) diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index dfca7cdf465dd..b9c64a61f510d 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -20,7 +20,7 @@ use super::*; use crate::Pallet as Referenda; use assert_matches::assert_matches; -use frame_benchmarking::{account, benchmarks, whitelist_account}; +use frame_benchmarking::{account, benchmarks_instance_pallet, whitelist_account}; use frame_support::{ assert_ok, traits::{Currency, EnsureOrigin}, @@ -31,157 +31,157 @@ use sp_runtime::traits::{Bounded, Hash}; const SEED: u32 = 0; #[allow(dead_code)] -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event, I: 'static>(generic_event: >::Event) { frame_system::Pallet::::assert_last_event(generic_event.into()); } -fn funded_account(name: &'static str, index: u32) -> T::AccountId { +fn funded_account, I: 'static>(name: &'static str, index: u32) -> T::AccountId { let caller: T::AccountId = account(name, index, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); caller } -fn create_referendum() -> (T::AccountId, ReferendumIndex) { - let caller = funded_account::("caller", 0); +fn create_referendum, I: 'static>() -> (T::AccountId, ReferendumIndex) { + let caller = funded_account::("caller", 0); whitelist_account!(caller); - assert_ok!(Referenda::::submit( + assert_ok!(Referenda::::submit( RawOrigin::Signed(caller.clone()).into(), Box::new(RawOrigin::Root.into()), T::Hashing::hash_of(&0), DispatchTime::After(0u32.into()) )); - let index = ReferendumCount::::get() - 1; + let index = ReferendumCount::::get() - 1; (caller, index) } -fn place_deposit(index: ReferendumIndex) { - let caller = funded_account::("caller", 0); +fn place_deposit, I: 'static>(index: ReferendumIndex) { + let caller = funded_account::("caller", 0); whitelist_account!(caller); - assert_ok!(Referenda::::place_decision_deposit(RawOrigin::Signed(caller).into(), index)); + assert_ok!(Referenda::::place_decision_deposit(RawOrigin::Signed(caller).into(), index)); } -fn nudge(index: ReferendumIndex) { - assert_ok!(Referenda::::nudge_referendum(RawOrigin::Root.into(), index)); +fn nudge, I: 'static>(index: ReferendumIndex) { + assert_ok!(Referenda::::nudge_referendum(RawOrigin::Root.into(), index)); } -fn fill_queue( +fn fill_queue, I: 'static>( index: ReferendumIndex, spaces: u32, pass_after: u32, ) -> Vec { // First, create enough other referendums to fill the track. let mut others = vec![]; - for _ in 0..info::(index).max_deciding { - let (_caller, index) = create_referendum::(); - place_deposit::(index); + for _ in 0..info::(index).max_deciding { + let (_caller, index) = create_referendum::(); + place_deposit::(index); others.push(index); } // We will also need enough referenda which are queued and passing, we want `MaxQueued - 1` // in order to force the maximum amount of work to insert ours into the queue. for _ in spaces..T::MaxQueued::get() { - let (_caller, index) = create_referendum::(); - place_deposit::(index); - make_passing_after::(index, Perbill::from_percent(pass_after)); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + make_passing_after::(index, Perbill::from_percent(pass_after)); others.push(index); } // Skip to when they can start being decided. - skip_prepare_period::(index); + skip_prepare_period::(index); // Manually nudge the other referenda first to ensure that they begin. - others.iter().for_each(|&i| nudge::(i)); + others.iter().for_each(|&i| nudge::(i)); others } -fn info(index: ReferendumIndex) -> &'static TrackInfoOf { - let status = Referenda::::ensure_ongoing(index).unwrap(); +fn info, I: 'static>(index: ReferendumIndex) -> &'static TrackInfoOf { + let status = Referenda::::ensure_ongoing(index).unwrap(); T::Tracks::info(status.track).expect("Id value returned from T::Tracks") } -fn make_passing_after(index: ReferendumIndex, period_portion: Perbill) { +fn make_passing_after, I: 'static>(index: ReferendumIndex, period_portion: Perbill) { // We add an extra 1 percent to handle any perbill rounding errors which may cause // a proposal to not actually pass. - let support = info::(index) + let support = info::(index) .min_support .threshold(period_portion) .saturating_add(Perbill::from_percent(1)); - let approval = info::(index) + let approval = info::(index) .min_approval .threshold(period_portion) .saturating_add(Perbill::from_percent(1)); - Referenda::::access_poll(index, |status| { + Referenda::::access_poll(index, |status| { if let PollStatus::Ongoing(tally, class) = status { *tally = T::Tally::from_requirements(support, approval, class); } }); } -fn make_passing(index: ReferendumIndex) { - Referenda::::access_poll(index, |status| { +fn make_passing, I: 'static>(index: ReferendumIndex) { + Referenda::::access_poll(index, |status| { if let PollStatus::Ongoing(tally, class) = status { *tally = T::Tally::unanimity(class); } }); } -fn make_failing(index: ReferendumIndex) { - Referenda::::access_poll(index, |status| { +fn make_failing, I: 'static>(index: ReferendumIndex) { + Referenda::::access_poll(index, |status| { if let PollStatus::Ongoing(tally, class) = status { *tally = T::Tally::rejection(class); } }); } -fn skip_prepare_period(index: ReferendumIndex) { - let status = Referenda::::ensure_ongoing(index).unwrap(); - let prepare_period_over = status.submitted + info::(index).prepare_period; +fn skip_prepare_period, I: 'static>(index: ReferendumIndex) { + let status = Referenda::::ensure_ongoing(index).unwrap(); + let prepare_period_over = status.submitted + info::(index).prepare_period; frame_system::Pallet::::set_block_number(prepare_period_over); } -fn skip_decision_period(index: ReferendumIndex) { - let status = Referenda::::ensure_ongoing(index).unwrap(); - let decision_period_over = status.deciding.unwrap().since + info::(index).decision_period; +fn skip_decision_period, I: 'static>(index: ReferendumIndex) { + let status = Referenda::::ensure_ongoing(index).unwrap(); + let decision_period_over = status.deciding.unwrap().since + info::(index).decision_period; frame_system::Pallet::::set_block_number(decision_period_over); } -fn skip_confirm_period(index: ReferendumIndex) { - let status = Referenda::::ensure_ongoing(index).unwrap(); +fn skip_confirm_period, I: 'static>(index: ReferendumIndex) { + let status = Referenda::::ensure_ongoing(index).unwrap(); let confirm_period_over = status.deciding.unwrap().confirming.unwrap(); frame_system::Pallet::::set_block_number(confirm_period_over); } -fn skip_timeout_period(index: ReferendumIndex) { - let status = Referenda::::ensure_ongoing(index).unwrap(); +fn skip_timeout_period, I: 'static>(index: ReferendumIndex) { + let status = Referenda::::ensure_ongoing(index).unwrap(); let timeout_period_over = status.submitted + T::UndecidingTimeout::get(); frame_system::Pallet::::set_block_number(timeout_period_over); } -fn alarm_time(index: ReferendumIndex) -> T::BlockNumber { - let status = Referenda::::ensure_ongoing(index).unwrap(); +fn alarm_time, I: 'static>(index: ReferendumIndex) -> T::BlockNumber { + let status = Referenda::::ensure_ongoing(index).unwrap(); status.alarm.unwrap().0 } -fn is_confirming(index: ReferendumIndex) -> bool { - let status = Referenda::::ensure_ongoing(index).unwrap(); +fn is_confirming, I: 'static>(index: ReferendumIndex) -> bool { + let status = Referenda::::ensure_ongoing(index).unwrap(); matches!( status, ReferendumStatus { deciding: Some(DecidingStatus { confirming: Some(_), .. }), .. } ) } -fn is_not_confirming(index: ReferendumIndex) -> bool { - let status = Referenda::::ensure_ongoing(index).unwrap(); +fn is_not_confirming, I: 'static>(index: ReferendumIndex) -> bool { + let status = Referenda::::ensure_ongoing(index).unwrap(); matches!( status, ReferendumStatus { deciding: Some(DecidingStatus { confirming: None, .. }), .. } ) } -benchmarks! { +benchmarks_instance_pallet! { submit { - let caller = funded_account::("caller", 0); + let caller = funded_account::("caller", 0); whitelist_account!(caller); }: _( RawOrigin::Signed(caller), @@ -189,105 +189,105 @@ benchmarks! { T::Hashing::hash_of(&0), DispatchTime::After(0u32.into()) ) verify { - let index = ReferendumCount::::get().checked_sub(1).unwrap(); - assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Ongoing(_))); + let index = ReferendumCount::::get().checked_sub(1).unwrap(); + assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Ongoing(_))); } place_decision_deposit_preparing { - let (caller, index) = create_referendum::(); + let (caller, index) = create_referendum::(); }: place_decision_deposit(RawOrigin::Signed(caller), index) verify { - assert!(Referenda::::ensure_ongoing(index).unwrap().decision_deposit.is_some()); + assert!(Referenda::::ensure_ongoing(index).unwrap().decision_deposit.is_some()); } place_decision_deposit_queued { - let (caller, index) = create_referendum::(); - fill_queue::(index, 1, 90); + let (caller, index) = create_referendum::(); + fill_queue::(index, 1, 90); }: place_decision_deposit(RawOrigin::Signed(caller), index) verify { - let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); - assert_eq!(TrackQueue::::get(&track)[0], (index, 0u32.into())); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert_eq!(TrackQueue::::get(&track)[0], (index, 0u32.into())); } place_decision_deposit_not_queued { - let (caller, index) = create_referendum::(); - fill_queue::(index, 0, 90); + let (caller, index) = create_referendum::(); + fill_queue::(index, 0, 90); }: place_decision_deposit(RawOrigin::Signed(caller), index) verify { - let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); - assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); } place_decision_deposit_passing { - let (caller, index) = create_referendum::(); - skip_prepare_period::(index); - make_passing::(index); + let (caller, index) = create_referendum::(); + skip_prepare_period::(index); + make_passing::(index); }: place_decision_deposit(RawOrigin::Signed(caller), index) verify { - assert!(is_confirming::(index)); + assert!(is_confirming::(index)); } place_decision_deposit_failing { - let (caller, index) = create_referendum::(); - skip_prepare_period::(index); + let (caller, index) = create_referendum::(); + skip_prepare_period::(index); }: place_decision_deposit(RawOrigin::Signed(caller), index) verify { - assert!(is_not_confirming::(index)); + assert!(is_not_confirming::(index)); } refund_decision_deposit { - let (caller, index) = create_referendum::(); - place_deposit::(index); - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); + let (caller, index) = create_referendum::(); + place_deposit::(index); + assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); }: _(RawOrigin::Signed(caller), index) verify { - assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, _, None))); + assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, _, None))); } cancel { - let (_caller, index) = create_referendum::(); - place_deposit::(index); + let (_caller, index) = create_referendum::(); + place_deposit::(index); }: _(T::CancelOrigin::successful_origin(), index) verify { - assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(..))); + assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(..))); } kill { - let (_caller, index) = create_referendum::(); - place_deposit::(index); + let (_caller, index) = create_referendum::(); + place_deposit::(index); }: _(T::KillOrigin::successful_origin(), index) verify { - assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Killed(..))); + assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Killed(..))); } one_fewer_deciding_queue_empty { - let (_caller, index) = create_referendum::(); - place_deposit::(index); - skip_prepare_period::(index); - nudge::(index); - let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); - assert_eq!(DecidingCount::::get(&track), 1); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + nudge::(index); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); + assert_eq!(DecidingCount::::get(&track), 1); }: one_fewer_deciding(RawOrigin::Root, track) verify { - assert_eq!(DecidingCount::::get(&track), 0); + assert_eq!(DecidingCount::::get(&track), 0); } one_fewer_deciding_failing { - let (_caller, index) = create_referendum::(); + let (_caller, index) = create_referendum::(); // No spaces free in the queue. - let queued = fill_queue::(index, 0, 90); - let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); - let deciding_count = DecidingCount::::get(&track); + let queued = fill_queue::(index, 0, 90); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + let deciding_count = DecidingCount::::get(&track); }: one_fewer_deciding(RawOrigin::Root, track) verify { - assert_eq!(DecidingCount::::get(&track), deciding_count); - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); - assert!(queued.into_iter().skip(1).all(|i| Referenda::::ensure_ongoing(i) + assert_eq!(DecidingCount::::get(&track), deciding_count); + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); + assert!(queued.into_iter().skip(1).all(|i| Referenda::::ensure_ongoing(i) .unwrap() .deciding .map_or(true, |d| d.confirming.is_none()) @@ -295,18 +295,18 @@ benchmarks! { } one_fewer_deciding_passing { - let (_caller, index) = create_referendum::(); + let (_caller, index) = create_referendum::(); // No spaces free in the queue. - let queued = fill_queue::(index, 0, 0); - let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); - let deciding_count = DecidingCount::::get(&track); + let queued = fill_queue::(index, 0, 0); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + let deciding_count = DecidingCount::::get(&track); }: one_fewer_deciding(RawOrigin::Root, track) verify { - assert_eq!(DecidingCount::::get(&track), deciding_count); - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); - assert!(queued.into_iter().skip(1).all(|i| Referenda::::ensure_ongoing(i) + assert_eq!(DecidingCount::::get(&track), deciding_count); + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); + assert!(queued.into_iter().skip(1).all(|i| Referenda::::ensure_ongoing(i) .unwrap() .deciding .map_or(true, |d| d.confirming.is_some()) @@ -315,43 +315,43 @@ benchmarks! { nudge_referendum_requeued_insertion { // First create our referendum and place the deposit. It will be failing. - let (_caller, index) = create_referendum::(); - place_deposit::(index); - fill_queue::(index, 0, 90); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + fill_queue::(index, 0, 90); // Now nudge ours, with the track now full and the queue full of referenda with votes, // ours will not be in the queue. - nudge::(index); - let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); + nudge::(index); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); // Now alter the voting, so that ours goes into pole-position and shifts others down. - make_passing::(index); + make_passing::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - let t = TrackQueue::::get(&track); + let t = TrackQueue::::get(&track); assert_eq!(t.len() as u32, T::MaxQueued::get()); assert_eq!(t[t.len() - 1].0, index); } nudge_referendum_requeued_slide { // First create our referendum and place the deposit. It will be failing. - let (_caller, index) = create_referendum::(); - place_deposit::(index); - fill_queue::(index, 1, 90); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + fill_queue::(index, 1, 90); // Now nudge ours, with the track now full, ours will be queued, but with no votes, it // will have the worst position. - nudge::(index); - let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); - assert_eq!(TrackQueue::::get(&track)[0], (index, 0u32.into())); + nudge::(index); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert_eq!(TrackQueue::::get(&track)[0], (index, 0u32.into())); // Now alter the voting, so that ours leap-frogs all into the best position. - make_passing::(index); + make_passing::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - let t = TrackQueue::::get(&track); + let t = TrackQueue::::get(&track); assert_eq!(t.len() as u32, T::MaxQueued::get()); assert_eq!(t[t.len() - 1].0, index); } @@ -362,159 +362,159 @@ benchmarks! { // insertion at the beginning. // First create our referendum and place the deposit. It will be failing. - let (_caller, index) = create_referendum::(); - place_deposit::(index); - fill_queue::(index, 1, 0); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + fill_queue::(index, 1, 0); - let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); - assert!(TrackQueue::::get(&track).into_iter().all(|(_, v)| v > 0u32.into())); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); + assert!(TrackQueue::::get(&track).into_iter().all(|(_, v)| v > 0u32.into())); // Then nudge ours, with the track now full, ours will be queued. }: nudge_referendum(RawOrigin::Root, index) verify { - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); - assert_eq!(TrackQueue::::get(&track)[0], (index, 0u32.into())); + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert_eq!(TrackQueue::::get(&track)[0], (index, 0u32.into())); } nudge_referendum_not_queued { // First create our referendum and place the deposit. It will be failing. - let (_caller, index) = create_referendum::(); - place_deposit::(index); - fill_queue::(index, 0, 0); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + fill_queue::(index, 0, 0); - let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); - assert!(TrackQueue::::get(&track).into_iter().all(|(_, v)| v > 0u32.into())); + let track = Referenda::::ensure_ongoing(index).unwrap().track; + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert!(TrackQueue::::get(&track).into_iter().all(|(_, v)| v > 0u32.into())); // Then nudge ours, with the track now full, ours will be queued. }: nudge_referendum(RawOrigin::Root, index) verify { - assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); - assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); } nudge_referendum_no_deposit { - let (_caller, index) = create_referendum::(); - skip_prepare_period::(index); + let (_caller, index) = create_referendum::(); + skip_prepare_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - let status = Referenda::::ensure_ongoing(index).unwrap(); + let status = Referenda::::ensure_ongoing(index).unwrap(); assert_matches!(status, ReferendumStatus { deciding: None, .. }); } nudge_referendum_preparing { - let (_caller, index) = create_referendum::(); - place_deposit::(index); + let (_caller, index) = create_referendum::(); + place_deposit::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - let status = Referenda::::ensure_ongoing(index).unwrap(); + let status = Referenda::::ensure_ongoing(index).unwrap(); assert_matches!(status, ReferendumStatus { deciding: None, .. }); } nudge_referendum_timed_out { - let (_caller, index) = create_referendum::(); - skip_timeout_period::(index); + let (_caller, index) = create_referendum::(); + skip_timeout_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - let info = ReferendumInfoFor::::get(index).unwrap(); + let info = ReferendumInfoFor::::get(index).unwrap(); assert_matches!(info, ReferendumInfo::TimedOut(..)); } nudge_referendum_begin_deciding_failing { - let (_caller, index) = create_referendum::(); - place_deposit::(index); - skip_prepare_period::(index); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - assert!(is_not_confirming::(index)); + assert!(is_not_confirming::(index)); } nudge_referendum_begin_deciding_passing { - let (_caller, index) = create_referendum::(); - place_deposit::(index); - make_passing::(index); - skip_prepare_period::(index); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + make_passing::(index); + skip_prepare_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - assert!(is_confirming::(index)); + assert!(is_confirming::(index)); } nudge_referendum_begin_confirming { - let (_caller, index) = create_referendum::(); - place_deposit::(index); - skip_prepare_period::(index); - nudge::(index); - assert!(!is_confirming::(index)); - make_passing::(index); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + nudge::(index); + assert!(!is_confirming::(index)); + make_passing::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - assert!(is_confirming::(index)); + assert!(is_confirming::(index)); } nudge_referendum_end_confirming { - let (_caller, index) = create_referendum::(); - place_deposit::(index); - skip_prepare_period::(index); - make_passing::(index); - nudge::(index); - assert!(is_confirming::(index)); - make_failing::(index); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + make_passing::(index); + nudge::(index); + assert!(is_confirming::(index)); + make_failing::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - assert!(!is_confirming::(index)); + assert!(!is_confirming::(index)); } nudge_referendum_continue_not_confirming { - let (_caller, index) = create_referendum::(); - place_deposit::(index); - skip_prepare_period::(index); - nudge::(index); - assert!(!is_confirming::(index)); - let old_alarm = alarm_time::(index); - make_passing_after::(index, Perbill::from_percent(50)); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + nudge::(index); + assert!(!is_confirming::(index)); + let old_alarm = alarm_time::(index); + make_passing_after::(index, Perbill::from_percent(50)); }: nudge_referendum(RawOrigin::Root, index) verify { - assert_ne!(old_alarm, alarm_time::(index)); - assert!(!is_confirming::(index)); + assert_ne!(old_alarm, alarm_time::(index)); + assert!(!is_confirming::(index)); } nudge_referendum_continue_confirming { - let (_caller, index) = create_referendum::(); - place_deposit::(index); - make_passing::(index); - skip_prepare_period::(index); - nudge::(index); - assert!(is_confirming::(index)); - let old_alarm = alarm_time::(index); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + make_passing::(index); + skip_prepare_period::(index); + nudge::(index); + assert!(is_confirming::(index)); + let old_alarm = alarm_time::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - assert!(is_confirming::(index)); + assert!(is_confirming::(index)); } nudge_referendum_approved { - let (_caller, index) = create_referendum::(); - place_deposit::(index); - skip_prepare_period::(index); - make_passing::(index); - nudge::(index); - skip_confirm_period::(index); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + make_passing::(index); + nudge::(index); + skip_confirm_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - let info = ReferendumInfoFor::::get(index).unwrap(); + let info = ReferendumInfoFor::::get(index).unwrap(); assert_matches!(info, ReferendumInfo::Approved(..)); } nudge_referendum_rejected { - let (_caller, index) = create_referendum::(); - place_deposit::(index); - skip_prepare_period::(index); - make_failing::(index); - nudge::(index); - skip_decision_period::(index); + let (_caller, index) = create_referendum::(); + place_deposit::(index); + skip_prepare_period::(index); + make_failing::(index); + nudge::(index); + skip_decision_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { - let info = ReferendumInfoFor::::get(index).unwrap(); + let info = ReferendumInfoFor::::get(index).unwrap(); assert_matches!(info, ReferendumInfo::Rejected(..)); } From 34a0621761c4a333cb2074ff720f7acbfb92dbb8 Mon Sep 17 00:00:00 2001 From: Sudip Ghimire <39845901+sudipghimire533@users.noreply.github.com> Date: Sun, 14 Aug 2022 23:50:06 +0545 Subject: [PATCH 1063/1472] make MAX_VOTERS and MAX_CANDIDATES in elections-phragmen configurable. Fix: #11092 (#11908) * make MAX_VOTERS and MAX_CANDIDATES in elections-phragmen configurable * Configure election-phragmen in node bin configuring max candidates & voters * Add document comment for added Config parameter * Incorporate suggestion * fix benchmarks * Update frame/elections-phragmen/src/lib.rs * Update frame/elections-phragmen/src/lib.rs * fix wrong values * fix typo * docs * more detailed docs * fmt * ".git/.scripts/bench-bot.sh" pallet dev pallet_elections_phragmen Co-authored-by: Szegoo Co-authored-by: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Co-authored-by: command-bot <> --- bin/node/runtime/src/lib.rs | 4 + frame/elections-phragmen/src/benchmarking.rs | 26 ++--- frame/elections-phragmen/src/lib.rs | 40 +++++--- frame/elections-phragmen/src/weights.rs | 102 +++++++++---------- 4 files changed, 94 insertions(+), 78 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 6bfbe3413058a..ff793a49b5ce6 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -966,6 +966,8 @@ parameter_types! { pub const TermDuration: BlockNumber = 7 * DAYS; pub const DesiredMembers: u32 = 13; pub const DesiredRunnersUp: u32 = 7; + pub const MaxVoters: u32 = 10 * 1000; + pub const MaxCandidates: u32 = 1000; pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; } @@ -989,6 +991,8 @@ impl pallet_elections_phragmen::Config for Runtime { type DesiredMembers = DesiredMembers; type DesiredRunnersUp = DesiredRunnersUp; type TermDuration = TermDuration; + type MaxVoters = MaxVoters; + type MaxCandidates = MaxCandidates; type WeightInfo = pallet_elections_phragmen::weights::SubstrateWeight; } diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 9a9d448449eca..2d1b698940a9d 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -36,7 +36,7 @@ fn endowed_account(name: &'static str, index: u32) -> T::AccountId { let account: T::AccountId = account(name, index, 0); // Fund each account with at-least his stake but still a sane amount as to not mess up // the vote calculation. - let amount = default_stake::(MAX_VOTERS) * BalanceOf::::from(BALANCE_FACTOR); + let amount = default_stake::(T::MaxVoters::get()) * BalanceOf::::from(BALANCE_FACTOR); let _ = T::Currency::make_free_balance_be(&account, amount); // important to increase the total issuance since T::CurrencyToVote will need it to be sane for // phragmen to work. @@ -230,7 +230,7 @@ benchmarks! { submit_candidacy { // number of already existing candidates. - let c in 1 .. MAX_CANDIDATES; + let c in 1 .. T::MaxCandidates::get(); // we fix the number of members to the number of desired members and runners-up. We'll be in // this state almost always. let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get(); @@ -261,7 +261,7 @@ benchmarks! { // this will check members, runners-up and candidate for removal. Members and runners-up are // limited by the runtime bound, nonetheless we fill them by `m`. // number of already existing candidates. - let c in 1 .. MAX_CANDIDATES; + let c in 1 .. T::MaxCandidates::get(); // we fix the number of members to the number of desired members and runners-up. We'll be in // this state almost always. let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get(); @@ -362,14 +362,14 @@ benchmarks! { clean_defunct_voters { // total number of voters. - let v in (MAX_VOTERS / 2) .. MAX_VOTERS; + let v in (T::MaxVoters::get() / 2) .. T::MaxVoters::get(); // those that are defunct and need removal. - let d in 1 .. (MAX_VOTERS / 2); + let d in 1 .. (T::MaxVoters::get() / 2); // remove any previous stuff. clean::(); - let all_candidates = submit_candidates::(MAX_CANDIDATES, "candidates")?; + let all_candidates = submit_candidates::(T::MaxCandidates::get(), "candidates")?; distribute_voters::(all_candidates, v, MAXIMUM_VOTE)?; // all candidates leave. @@ -389,9 +389,9 @@ benchmarks! { // members, this is hard-coded in the runtime and cannot be trivially changed at this stage. // Yet, change the number of voters, candidates and edge per voter to see the impact. Note // that we give all candidates a self vote to make sure they are all considered. - let c in 1 .. MAX_CANDIDATES; - let v in 1 .. MAX_VOTERS; - let e in MAX_VOTERS .. MAX_VOTERS * MAXIMUM_VOTE as u32; + let c in 1 .. T::MaxCandidates::get(); + let v in 1 .. T::MaxVoters::get(); + let e in (T::MaxVoters::get()) .. T::MaxVoters::get() as u32 * MAXIMUM_VOTE as u32; clean::(); // so we have a situation with v and e. we want e to basically always be in the range of `e @@ -425,9 +425,9 @@ benchmarks! { #[extra] election_phragmen_c_e { - let c in 1 .. MAX_CANDIDATES; - let e in MAX_VOTERS .. MAX_VOTERS * MAXIMUM_VOTE as u32; - let fixed_v = MAX_VOTERS; + let c in 1 .. T::MaxCandidates::get(); + let e in (T::MaxVoters::get()) .. T::MaxVoters::get() * MAXIMUM_VOTE as u32; + let fixed_v = T::MaxVoters::get(); clean::(); let votes_per_voter = e / fixed_v; @@ -459,7 +459,7 @@ benchmarks! { #[extra] election_phragmen_v { let v in 4 .. 16; - let fixed_c = MAX_CANDIDATES / 10; + let fixed_c = T::MaxCandidates::get() / 10; let fixed_e = 64; clean::(); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 28fed28f18e5c..ffd1c6ab4de9c 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -125,17 +125,6 @@ pub mod migrations; /// The maximum votes allowed per voter. pub const MAXIMUM_VOTE: usize = 16; -// Some safe temp values to make the wasm execution sane while we still use this pallet. -#[cfg(test)] -pub(crate) const MAX_CANDIDATES: u32 = 100; -#[cfg(not(test))] -pub(crate) const MAX_CANDIDATES: u32 = 1000; - -#[cfg(test)] -pub(crate) const MAX_VOTERS: u32 = 1000; -#[cfg(not(test))] -pub(crate) const MAX_VOTERS: u32 = 10 * 1000; - type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type NegativeImbalanceOf = <::Currency as Currency< @@ -259,6 +248,21 @@ pub mod pallet { #[pallet::constant] type TermDuration: Get; + /// The maximum number of candidates in a phragmen election. + /// + /// Warning: The election happens onchain, and this value will determine + /// the size of the election. When this limit is reached no more + /// candidates are accepted in the election. + #[pallet::constant] + type MaxCandidates: Get; + + /// The maximum number of voters to allow in a phragmen election. + /// + /// Warning: This impacts the size of the election which is run onchain. + /// When the limit is reached the new voters are ignored. + #[pallet::constant] + type MaxVoters: Get; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -397,7 +401,10 @@ pub mod pallet { let actual_count = >::decode_len().unwrap_or(0) as u32; ensure!(actual_count <= candidate_count, Error::::InvalidWitnessData); - ensure!(actual_count <= MAX_CANDIDATES, Error::::TooManyCandidates); + ensure!( + actual_count <= ::MaxCandidates::get(), + Error::::TooManyCandidates + ); let index = Self::is_candidate(&who).err().ok_or(Error::::DuplicatedCandidate)?; @@ -913,10 +920,11 @@ impl Pallet { let mut num_edges: u32 = 0; + let max_voters = ::MaxVoters::get() as usize; // used for prime election. let mut voters_and_stakes = Vec::new(); match Voting::::iter().try_for_each(|(voter, Voter { stake, votes, .. })| { - if voters_and_stakes.len() < MAX_VOTERS as usize { + if voters_and_stakes.len() < max_voters { voters_and_stakes.push((voter, stake, votes)); Ok(()) } else { @@ -930,7 +938,7 @@ impl Pallet { "Failed to run election. Number of voters exceeded", ); Self::deposit_event(Event::ElectionError); - return T::DbWeight::get().reads(3 + MAX_VOTERS as u64) + return T::DbWeight::get().reads(3 + max_voters as u64) }, } @@ -1266,6 +1274,8 @@ mod tests { parameter_types! { pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; + pub const PhragmenMaxVoters: u32 = 1000; + pub const PhragmenMaxCandidates: u32 = 100; } impl Config for Test { @@ -1284,6 +1294,8 @@ mod tests { type LoserCandidate = (); type KickedMember = (); type WeightInfo = (); + type MaxVoters = PhragmenMaxVoters; + type MaxCandidates = PhragmenMaxCandidates; } pub type Block = sp_runtime::generic::Block; diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 07ee7aa2012ad..0e067699e5fac 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-08-01, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-08-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -70,9 +70,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - (26_143_000 as Weight) - // Standard Error: 23_000 - .saturating_add((297_000 as Weight).saturating_mul(v as Weight)) + (27_011_000 as Weight) + // Standard Error: 3_000 + .saturating_add((214_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -83,9 +83,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - (40_431_000 as Weight) - // Standard Error: 6_000 - .saturating_add((205_000 as Weight).saturating_mul(v as Weight)) + (40_240_000 as Weight) + // Standard Error: 5_000 + .saturating_add((244_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -96,16 +96,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - (40_188_000 as Weight) - // Standard Error: 6_000 - .saturating_add((225_000 as Weight).saturating_mul(v as Weight)) + (40_394_000 as Weight) + // Standard Error: 5_000 + .saturating_add((217_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (38_031_000 as Weight) + (37_651_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -114,18 +114,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections RunnersUp (r:1 w:0) /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - (43_715_000 as Weight) + (42_217_000 as Weight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((50_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (47_882_000 as Weight) - // Standard Error: 1_000 - .saturating_add((25_000 as Weight).saturating_mul(c as Weight)) + (46_459_000 as Weight) + // Standard Error: 0 + .saturating_add((26_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -135,13 +135,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (45_600_000 as Weight) + (45_189_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (34_959_000 as Weight) + (34_516_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -156,7 +156,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (52_684_000 as Weight) + (51_838_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } @@ -170,8 +170,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `d` is `[1, 5000]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 65_000 - .saturating_add((64_009_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 76_000 + .saturating_add((63_721_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -184,17 +184,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections ElectionRounds (r:1 w:1) // Storage: Council Members (r:0 w:1) // Storage: Council Prime (r:0 w:1) - // Storage: System Account (r:19 w:19) + // Storage: System Account (r:1 w:1) /// The range of component `c` is `[1, 1000]`. /// The range of component `v` is `[1, 10000]`. /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 778_000 - .saturating_add((81_049_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 773_000 + .saturating_add((81_534_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 51_000 - .saturating_add((4_420_000 as Weight).saturating_mul(e as Weight)) - .saturating_add(T::DbWeight::get().reads(279 as Weight)) + .saturating_add((4_453_000 as Weight).saturating_mul(e as Weight)) + .saturating_add(T::DbWeight::get().reads(280 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) @@ -210,9 +210,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - (26_143_000 as Weight) - // Standard Error: 23_000 - .saturating_add((297_000 as Weight).saturating_mul(v as Weight)) + (27_011_000 as Weight) + // Standard Error: 3_000 + .saturating_add((214_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -223,9 +223,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - (40_431_000 as Weight) - // Standard Error: 6_000 - .saturating_add((205_000 as Weight).saturating_mul(v as Weight)) + (40_240_000 as Weight) + // Standard Error: 5_000 + .saturating_add((244_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -236,16 +236,16 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - (40_188_000 as Weight) - // Standard Error: 6_000 - .saturating_add((225_000 as Weight).saturating_mul(v as Weight)) + (40_394_000 as Weight) + // Standard Error: 5_000 + .saturating_add((217_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (38_031_000 as Weight) + (37_651_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -254,18 +254,18 @@ impl WeightInfo for () { // Storage: Elections RunnersUp (r:1 w:0) /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - (43_715_000 as Weight) + (42_217_000 as Weight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((50_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Elections Candidates (r:1 w:1) /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (47_882_000 as Weight) - // Standard Error: 1_000 - .saturating_add((25_000 as Weight).saturating_mul(c as Weight)) + (46_459_000 as Weight) + // Standard Error: 0 + .saturating_add((26_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -275,13 +275,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (45_600_000 as Weight) + (45_189_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (34_959_000 as Weight) + (34_516_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -296,7 +296,7 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (52_684_000 as Weight) + (51_838_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } @@ -310,8 +310,8 @@ impl WeightInfo for () { /// The range of component `d` is `[1, 5000]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 65_000 - .saturating_add((64_009_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 76_000 + .saturating_add((63_721_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) @@ -324,17 +324,17 @@ impl WeightInfo for () { // Storage: Elections ElectionRounds (r:1 w:1) // Storage: Council Members (r:0 w:1) // Storage: Council Prime (r:0 w:1) - // Storage: System Account (r:19 w:19) + // Storage: System Account (r:1 w:1) /// The range of component `c` is `[1, 1000]`. /// The range of component `v` is `[1, 10000]`. /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { (0 as Weight) - // Standard Error: 778_000 - .saturating_add((81_049_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 773_000 + .saturating_add((81_534_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 51_000 - .saturating_add((4_420_000 as Weight).saturating_mul(e as Weight)) - .saturating_add(RocksDbWeight::get().reads(279 as Weight)) + .saturating_add((4_453_000 as Weight).saturating_mul(e as Weight)) + .saturating_add(RocksDbWeight::get().reads(280 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) From bfc2d085f392ccfb369251709bccb4bfa0edebe7 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sun, 14 Aug 2022 19:36:19 +0100 Subject: [PATCH 1064/1472] Further Improve Gov V2 Stuff (#12028) * refactor and improve successful origin * use appropriate origin for creating referendum * fmt * add setup tally feature for benchmarks * feedback updates * fmt * Update frame/referenda/src/benchmarking.rs Co-authored-by: Gavin Wood * feedback on `setup` trait * fix Co-authored-by: Gavin Wood --- frame/conviction-voting/src/types.rs | 3 + frame/ranked-collective/src/lib.rs | 137 +++++++++++++++++++++------ frame/ranked-collective/src/tests.rs | 17 ++++ frame/referenda/src/benchmarking.rs | 118 ++++++++++++----------- frame/referenda/src/mock.rs | 3 + frame/support/src/traits/voting.rs | 13 +++ 6 files changed, 210 insertions(+), 81 deletions(-) diff --git a/frame/conviction-voting/src/types.rs b/frame/conviction-voting/src/types.rs index 8f4f3697e9766..d6051dff62569 100644 --- a/frame/conviction-voting/src/types.rs +++ b/frame/conviction-voting/src/types.rs @@ -93,6 +93,9 @@ impl< let ayes = approval.mul_ceil(support); Self { ayes, nays: support - ayes, support, dummy: PhantomData } } + + #[cfg(feature = "runtime-benchmarks")] + fn setup(_: Class, _: Perbill) {} } impl< diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 7ea43a9017445..79910c259a7cd 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -85,16 +85,16 @@ pub type Votes = u32; Decode, MaxEncodedLen, )] -#[scale_info(skip_type_params(M))] +#[scale_info(skip_type_params(T, I, M))] #[codec(mel_bound())] -pub struct Tally { +pub struct Tally { bare_ayes: MemberIndex, ayes: Votes, nays: Votes, - dummy: PhantomData, + dummy: PhantomData<(T, I, M)>, } -impl Tally { +impl, I: 'static, M: GetMaxVoters> Tally { pub fn from_parts(bare_ayes: MemberIndex, ayes: Votes, nays: Votes) -> Self { Tally { bare_ayes, ayes, nays, dummy: PhantomData } } @@ -107,10 +107,10 @@ impl Tally { // All functions of VoteTally now include the class as a param. -pub type TallyOf = Tally>; +pub type TallyOf = Tally>; pub type PollIndexOf = <>::Polls as Polling>>::Index; -impl VoteTally for Tally { +impl, I: 'static, M: GetMaxVoters> VoteTally for Tally { fn new(_: Rank) -> Self { Self { bare_ayes: 0, ayes: 0, nays: 0, dummy: PhantomData } } @@ -143,6 +143,20 @@ impl VoteTally for Tally { let nays = ((ayes as u64) * 1_000_000_000u64 / approval.deconstruct() as u64) as u32 - ayes; Self { bare_ayes: ayes, ayes, nays, dummy: PhantomData } } + + #[cfg(feature = "runtime-benchmarks")] + fn setup(class: Rank, granularity: Perbill) { + if M::get_max_voters(class) == 0 { + let max_voters = granularity.saturating_reciprocal_mul(1u32); + for i in 0..max_voters { + let who: T::AccountId = + frame_benchmarking::account("ranked_collective_benchmarking", i, 0); + crate::Pallet::::do_add_member_to_rank(who, class) + .expect("could not add members for benchmarks"); + } + assert_eq!(M::get_max_voters(class), max_voters); + } + } } /// Record needed for every member. @@ -241,6 +255,19 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } + + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> T::Origin { + match Self::try_successful_origin() { + Ok(o) => o, + Err(()) => { + let who: T::AccountId = frame_benchmarking::whitelisted_caller(); + crate::Pallet::::do_add_member_to_rank(who.clone(), MIN_RANK) + .expect("failed to add ranked member"); + frame_system::RawOrigin::Signed(who).into() + }, + } + } } /// Guard to ensure that the given origin is a member of the collective. The account ID of the @@ -264,6 +291,19 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } + + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> T::Origin { + match Self::try_successful_origin() { + Ok(o) => o, + Err(()) => { + let who: T::AccountId = frame_benchmarking::whitelisted_caller(); + crate::Pallet::::do_add_member_to_rank(who.clone(), MIN_RANK) + .expect("failed to add ranked member"); + frame_system::RawOrigin::Signed(who).into() + }, + } + } } /// Guard to ensure that the given origin is a member of the collective. The pair of including both @@ -287,6 +327,19 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } + + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> T::Origin { + match Self::try_successful_origin() { + Ok(o) => o, + Err(()) => { + let who: T::AccountId = frame_benchmarking::whitelisted_caller(); + crate::Pallet::::do_add_member_to_rank(who.clone(), MIN_RANK) + .expect("failed to add ranked member"); + frame_system::RawOrigin::Signed(who).into() + }, + } + } } #[frame_support::pallet] @@ -415,17 +468,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::add_member())] pub fn add_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { let _ = T::PromoteOrigin::ensure_origin(origin)?; - ensure!(!Members::::contains_key(&who), Error::::AlreadyMember); - let index = MemberCount::::get(0); - let count = index.checked_add(1).ok_or(Overflow)?; - - Members::::insert(&who, MemberRecord { rank: 0 }); - IdToIndex::::insert(0, &who, index); - IndexToId::::insert(0, index, &who); - MemberCount::::insert(0, count); - Self::deposit_event(Event::MemberAdded { who }); - - Ok(()) + Self::do_add_member(who) } /// Increment the rank of an existing member by one. @@ -437,17 +480,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::promote_member(0))] pub fn promote_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { let max_rank = T::PromoteOrigin::ensure_origin(origin)?; - let record = Self::ensure_member(&who)?; - let rank = record.rank.checked_add(1).ok_or(Overflow)?; - ensure!(max_rank >= rank, Error::::NoPermission); - let index = MemberCount::::get(rank); - MemberCount::::insert(rank, index.checked_add(1).ok_or(Overflow)?); - IdToIndex::::insert(rank, &who, index); - IndexToId::::insert(rank, index, &who); - Members::::insert(&who, MemberRecord { rank }); - Self::deposit_event(Event::RankChanged { who, rank }); - - Ok(()) + Self::do_promote_member(who, Some(max_rank)) } /// Decrement the rank of an existing member by one. If the member is already at rank zero, @@ -626,5 +659,53 @@ pub mod pallet { MemberCount::::mutate(rank, |r| r.saturating_dec()); Ok(()) } + + /// Adds a member into the ranked collective at level 0. + /// + /// No origin checks are executed. + pub fn do_add_member(who: T::AccountId) -> DispatchResult { + ensure!(!Members::::contains_key(&who), Error::::AlreadyMember); + let index = MemberCount::::get(0); + let count = index.checked_add(1).ok_or(Overflow)?; + + Members::::insert(&who, MemberRecord { rank: 0 }); + IdToIndex::::insert(0, &who, index); + IndexToId::::insert(0, index, &who); + MemberCount::::insert(0, count); + Self::deposit_event(Event::MemberAdded { who }); + Ok(()) + } + + /// Promotes a member in the ranked collective into the next role. + /// + /// A `maybe_max_rank` may be provided to check that the member does not get promoted beyond + /// a certain rank. Is `None` is provided, then the rank will be incremented without checks. + pub fn do_promote_member( + who: T::AccountId, + maybe_max_rank: Option, + ) -> DispatchResult { + let record = Self::ensure_member(&who)?; + let rank = record.rank.checked_add(1).ok_or(Overflow)?; + if let Some(max_rank) = maybe_max_rank { + ensure!(max_rank >= rank, Error::::NoPermission); + } + let index = MemberCount::::get(rank); + MemberCount::::insert(rank, index.checked_add(1).ok_or(Overflow)?); + IdToIndex::::insert(rank, &who, index); + IndexToId::::insert(rank, index, &who); + Members::::insert(&who, MemberRecord { rank }); + Self::deposit_event(Event::RankChanged { who, rank }); + Ok(()) + } + + /// Add a member to the rank collective, and continue to promote them until a certain rank + /// is reached. + pub fn do_add_member_to_rank(who: T::AccountId, rank: Rank) -> DispatchResult { + Self::do_add_member(who.clone())?; + for _ in 0..rank { + Self::do_promote_member(who.clone(), None)?; + } + Ok(()) + } } } diff --git a/frame/ranked-collective/src/tests.rs b/frame/ranked-collective/src/tests.rs index 4344a1be730fb..530388d83f3c4 100644 --- a/frame/ranked-collective/src/tests.rs +++ b/frame/ranked-collective/src/tests.rs @@ -455,3 +455,20 @@ fn ensure_ranked_works() { assert_eq!(Rank4::try_origin(Origin::signed(3)).unwrap_err().as_signed().unwrap(), 3); }); } + +#[test] +fn do_add_member_to_rank_works() { + new_test_ext().execute_with(|| { + let max_rank = 9u16; + assert_ok!(Club::do_add_member_to_rank(69, max_rank / 2)); + assert_ok!(Club::do_add_member_to_rank(1337, max_rank)); + for i in 0..=max_rank { + if i <= max_rank / 2 { + assert_eq!(member_count(i), 2); + } else { + assert_eq!(member_count(i), 1); + } + } + assert_eq!(member_count(max_rank + 1), 0); + }) +} diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index b9c64a61f510d..4a64a9aa03b77 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -23,6 +23,7 @@ use assert_matches::assert_matches; use frame_benchmarking::{account, benchmarks_instance_pallet, whitelist_account}; use frame_support::{ assert_ok, + dispatch::UnfilteredDispatchable, traits::{Currency, EnsureOrigin}, }; use frame_system::RawOrigin; @@ -41,17 +42,20 @@ fn funded_account, I: 'static>(name: &'static str, index: u32) -> T caller } -fn create_referendum, I: 'static>() -> (T::AccountId, ReferendumIndex) { - let caller = funded_account::("caller", 0); - whitelist_account!(caller); - assert_ok!(Referenda::::submit( - RawOrigin::Signed(caller.clone()).into(), - Box::new(RawOrigin::Root.into()), - T::Hashing::hash_of(&0), - DispatchTime::After(0u32.into()) - )); +fn create_referendum, I: 'static>() -> (T::Origin, ReferendumIndex) { + let origin: T::Origin = T::SubmitOrigin::successful_origin(); + if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + whitelist_account!(caller); + } + + let proposal_origin = Box::new(RawOrigin::Root.into()); + let proposal_hash = T::Hashing::hash_of(&0); + let enactment_moment = DispatchTime::After(0u32.into()); + let call = Call::::submit { proposal_origin, proposal_hash, enactment_moment }; + assert_ok!(call.dispatch_bypass_filter(origin.clone())); let index = ReferendumCount::::get() - 1; - (caller, index) + (origin, index) } fn place_deposit, I: 'static>(index: ReferendumIndex) { @@ -72,7 +76,7 @@ fn fill_queue, I: 'static>( // First, create enough other referendums to fill the track. let mut others = vec![]; for _ in 0..info::(index).max_deciding { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); others.push(index); } @@ -80,7 +84,7 @@ fn fill_queue, I: 'static>( // We will also need enough referenda which are queued and passing, we want `MaxQueued - 1` // in order to force the maximum amount of work to insert ours into the queue. for _ in spaces..T::MaxQueued::get() { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); make_passing_after::(index, Perbill::from_percent(pass_after)); others.push(index); @@ -113,6 +117,7 @@ fn make_passing_after, I: 'static>(index: ReferendumIndex, period_p .saturating_add(Perbill::from_percent(1)); Referenda::::access_poll(index, |status| { if let PollStatus::Ongoing(tally, class) = status { + T::Tally::setup(class, Perbill::from_rational(1u32, 1000u32)); *tally = T::Tally::from_requirements(support, approval, class); } }); @@ -121,6 +126,7 @@ fn make_passing_after, I: 'static>(index: ReferendumIndex, period_p fn make_passing, I: 'static>(index: ReferendumIndex) { Referenda::::access_poll(index, |status| { if let PollStatus::Ongoing(tally, class) = status { + T::Tally::setup(class, Perbill::from_rational(1u32, 1000u32)); *tally = T::Tally::unanimity(class); } }); @@ -129,6 +135,7 @@ fn make_passing, I: 'static>(index: ReferendumIndex) { fn make_failing, I: 'static>(index: ReferendumIndex) { Referenda::::access_poll(index, |status| { if let PollStatus::Ongoing(tally, class) = status { + T::Tally::setup(class, Perbill::from_rational(1u32, 1000u32)); *tally = T::Tally::rejection(class); } }); @@ -181,10 +188,13 @@ fn is_not_confirming, I: 'static>(index: ReferendumIndex) -> bool { benchmarks_instance_pallet! { submit { - let caller = funded_account::("caller", 0); - whitelist_account!(caller); - }: _( - RawOrigin::Signed(caller), + let origin: T::Origin = T::SubmitOrigin::successful_origin(); + if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + whitelist_account!(caller); + } + }: _( + origin, Box::new(RawOrigin::Root.into()), T::Hashing::hash_of(&0), DispatchTime::After(0u32.into()) @@ -194,60 +204,62 @@ benchmarks_instance_pallet! { } place_decision_deposit_preparing { - let (caller, index) = create_referendum::(); - }: place_decision_deposit(RawOrigin::Signed(caller), index) + let (origin, index) = create_referendum::(); + }: place_decision_deposit(origin, index) verify { assert!(Referenda::::ensure_ongoing(index).unwrap().decision_deposit.is_some()); } place_decision_deposit_queued { - let (caller, index) = create_referendum::(); + let (origin, index) = create_referendum::(); fill_queue::(index, 1, 90); - }: place_decision_deposit(RawOrigin::Signed(caller), index) + }: place_decision_deposit(origin, index) verify { let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); - assert_eq!(TrackQueue::::get(&track)[0], (index, 0u32.into())); + assert!(TrackQueue::::get(&track).contains(&(index, 0u32.into()))); } place_decision_deposit_not_queued { - let (caller, index) = create_referendum::(); + let (origin, index) = create_referendum::(); fill_queue::(index, 0, 90); - }: place_decision_deposit(RawOrigin::Signed(caller), index) - verify { let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); + }: place_decision_deposit(origin, index) + verify { + assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); + assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); } place_decision_deposit_passing { - let (caller, index) = create_referendum::(); + let (origin, index) = create_referendum::(); skip_prepare_period::(index); make_passing::(index); - }: place_decision_deposit(RawOrigin::Signed(caller), index) + }: place_decision_deposit(origin, index) verify { assert!(is_confirming::(index)); } place_decision_deposit_failing { - let (caller, index) = create_referendum::(); + let (origin, index) = create_referendum::(); skip_prepare_period::(index); - }: place_decision_deposit(RawOrigin::Signed(caller), index) + }: place_decision_deposit(origin, index) verify { assert!(is_not_confirming::(index)); } refund_decision_deposit { - let (caller, index) = create_referendum::(); + let (origin, index) = create_referendum::(); place_deposit::(index); assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); - }: _(RawOrigin::Signed(caller), index) + }: _(origin, index) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, _, None))); } cancel { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); }: _(T::CancelOrigin::successful_origin(), index) verify { @@ -255,7 +267,7 @@ benchmarks_instance_pallet! { } kill { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); }: _(T::KillOrigin::successful_origin(), index) verify { @@ -263,7 +275,7 @@ benchmarks_instance_pallet! { } one_fewer_deciding_queue_empty { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); skip_prepare_period::(index); nudge::(index); @@ -276,7 +288,7 @@ benchmarks_instance_pallet! { } one_fewer_deciding_failing { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); // No spaces free in the queue. let queued = fill_queue::(index, 0, 90); let track = Referenda::::ensure_ongoing(index).unwrap().track; @@ -295,7 +307,7 @@ benchmarks_instance_pallet! { } one_fewer_deciding_passing { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); // No spaces free in the queue. let queued = fill_queue::(index, 0, 0); let track = Referenda::::ensure_ongoing(index).unwrap().track; @@ -306,16 +318,16 @@ benchmarks_instance_pallet! { verify { assert_eq!(DecidingCount::::get(&track), deciding_count); assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); - assert!(queued.into_iter().skip(1).all(|i| Referenda::::ensure_ongoing(i) + assert!(queued.into_iter().skip(1).filter(|i| Referenda::::ensure_ongoing(*i) .unwrap() .deciding - .map_or(true, |d| d.confirming.is_some()) - )); + .map_or(false, |d| d.confirming.is_some()) + ).count() == 1); } nudge_referendum_requeued_insertion { // First create our referendum and place the deposit. It will be failing. - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); fill_queue::(index, 0, 90); @@ -336,7 +348,7 @@ benchmarks_instance_pallet! { nudge_referendum_requeued_slide { // First create our referendum and place the deposit. It will be failing. - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); fill_queue::(index, 1, 90); @@ -362,7 +374,7 @@ benchmarks_instance_pallet! { // insertion at the beginning. // First create our referendum and place the deposit. It will be failing. - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); fill_queue::(index, 1, 0); @@ -379,7 +391,7 @@ benchmarks_instance_pallet! { nudge_referendum_not_queued { // First create our referendum and place the deposit. It will be failing. - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); fill_queue::(index, 0, 0); @@ -395,7 +407,7 @@ benchmarks_instance_pallet! { } nudge_referendum_no_deposit { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); skip_prepare_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { @@ -404,7 +416,7 @@ benchmarks_instance_pallet! { } nudge_referendum_preparing { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); }: nudge_referendum(RawOrigin::Root, index) verify { @@ -413,7 +425,7 @@ benchmarks_instance_pallet! { } nudge_referendum_timed_out { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); skip_timeout_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { @@ -422,7 +434,7 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_deciding_failing { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); skip_prepare_period::(index); }: nudge_referendum(RawOrigin::Root, index) @@ -431,7 +443,7 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_deciding_passing { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); make_passing::(index); skip_prepare_period::(index); @@ -441,7 +453,7 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_confirming { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); skip_prepare_period::(index); nudge::(index); @@ -453,7 +465,7 @@ benchmarks_instance_pallet! { } nudge_referendum_end_confirming { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); skip_prepare_period::(index); make_passing::(index); @@ -466,7 +478,7 @@ benchmarks_instance_pallet! { } nudge_referendum_continue_not_confirming { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); skip_prepare_period::(index); nudge::(index); @@ -480,7 +492,7 @@ benchmarks_instance_pallet! { } nudge_referendum_continue_confirming { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); make_passing::(index); skip_prepare_period::(index); @@ -493,7 +505,7 @@ benchmarks_instance_pallet! { } nudge_referendum_approved { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); skip_prepare_period::(index); make_passing::(index); @@ -506,7 +518,7 @@ benchmarks_instance_pallet! { } nudge_referendum_rejected { - let (_caller, index) = create_referendum::(); + let (_origin, index) = create_referendum::(); place_deposit::(index); skip_prepare_period::(index); make_failing::(index); diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 1a24911603990..dbe22cd562349 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -289,6 +289,9 @@ impl VoteTally for Tally { let nays = ((ayes as u64) * 1_000_000_000u64 / approval.deconstruct() as u64) as u32 - ayes; Self { ayes, nays } } + + #[cfg(feature = "runtime-benchmarks")] + fn setup(_: Class, _: Perbill) {} } pub fn set_balance_proposal(value: u64) -> Vec { diff --git a/frame/support/src/traits/voting.rs b/frame/support/src/traits/voting.rs index b5e7d27073895..49ae3163d0cd1 100644 --- a/frame/support/src/traits/voting.rs +++ b/frame/support/src/traits/voting.rs @@ -106,6 +106,19 @@ pub trait VoteTally { fn rejection(class: Class) -> Self; #[cfg(feature = "runtime-benchmarks")] fn from_requirements(support: Perbill, approval: Perbill, class: Class) -> Self; + #[cfg(feature = "runtime-benchmarks")] + /// A function that should be called before any use of the `runtime-benchmarks` gated functions + /// of the `VoteTally` trait. + /// + /// Should be used to set up any needed state in a Pallet which implements `VoteTally` so that + /// benchmarks that execute will complete successfully. `class` can be used to set up a + /// particular class of voters, and `granularity` is used to determine the weight of one vote + /// relative to total unanimity. + /// + /// For example, in the case where there are a number of unique voters, and each voter has equal + /// voting weight, a granularity of `Perbill::from_rational(1, 1000)` should create `1_000` + /// users. + fn setup(class: Class, granularity: Perbill); } pub enum PollStatus { None, From 669ed362f922c679ab1416fc8b9e9f4f68a21483 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sun, 14 Aug 2022 20:06:02 +0100 Subject: [PATCH 1065/1472] Proposal: Flatten `AllPallets` and similar types (#11813) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * flratten AllPallets types * feature flag it * fix * fix * fmt * remove todo * Update frame/support/src/traits/metadata.rs Co-authored-by: Bastian Köcher * Update frame/support/src/migrations.rs Co-authored-by: Bastian Köcher * fix * mark as deprecated * add docs * fix ui test? * fmt Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher --- frame/support/Cargo.toml | 4 ++ .../procedural/src/construct_runtime/mod.rs | 60 +++++++------------ .../src/pallet/expand/pallet_struct.rs | 6 +- frame/support/src/dispatch.rs | 4 +- frame/support/src/lib.rs | 10 ++++ frame/support/src/migrations.rs | 5 +- frame/support/src/traits.rs | 5 +- frame/support/src/traits/filter.rs | 11 ---- frame/support/src/traits/hooks.rs | 37 ++++++++++-- frame/support/src/traits/members.rs | 9 ++- frame/support/src/traits/metadata.rs | 41 ++++--------- frame/support/src/traits/misc.rs | 13 +++- frame/support/src/traits/storage.rs | 5 +- frame/support/test/tests/pallet.rs | 13 ++-- .../tests/pallet_ui/hooks_invalid_item.stderr | 6 +- 15 files changed, 121 insertions(+), 108 deletions(-) diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index a69133961e970..1b6488bbd4712 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -73,3 +73,7 @@ no-metadata-docs = ["frame-support-procedural/no-metadata-docs"] # By default some types have documentation, `full-metadata-docs` allows to add documentation to # more types in the metadata. full-metadata-docs = ["scale-info/docs"] +# Generate impl-trait for tuples with the given number of tuples. Will be needed as the number of +# pallets in a runtime grows. Does increase the compile time! +tuples-96 = [] +tuples-128 = [] diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 7b4156a94db58..042af31be6bf4 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -308,47 +308,26 @@ fn decl_all_pallets<'a>( names.push(&pallet_declaration.name); } - // Make nested tuple structure like: - // `((FirstPallet, (SecondPallet, ( ... , LastPallet) ... ))))` - // But ignore the system pallet. - let all_pallets_without_system = names - .iter() - .filter(|n| **n != SYSTEM_PALLET_NAME) - .rev() - .fold(TokenStream2::default(), |combined, name| quote!((#name, #combined))); - - // Make nested tuple structure like: - // `((FirstPallet, (SecondPallet, ( ... , LastPallet) ... ))))` - let all_pallets_with_system = names - .iter() - .rev() - .fold(TokenStream2::default(), |combined, name| quote!((#name, #combined))); - - // Make nested tuple structure like: - // `((LastPallet, (SecondLastPallet, ( ... , FirstPallet) ... ))))` - // But ignore the system pallet. - let all_pallets_without_system_reversed = names - .iter() - .filter(|n| **n != SYSTEM_PALLET_NAME) - .fold(TokenStream2::default(), |combined, name| quote!((#name, #combined))); - - // Make nested tuple structure like: - // `((LastPallet, (SecondLastPallet, ( ... , FirstPallet) ... ))))` - let all_pallets_with_system_reversed = names - .iter() - .fold(TokenStream2::default(), |combined, name| quote!((#name, #combined))); - let system_pallet = match names.iter().find(|n| **n == SYSTEM_PALLET_NAME) { Some(name) => name, None => return syn::Error::new( proc_macro2::Span::call_site(), "`System` pallet declaration is missing. \ - Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},`", + Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},`", ) .into_compile_error(), }; + let names_without_system = + names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).collect::>(); + let names_reversed = names.clone().into_iter().rev().collect::>(); + let names_without_system_reverse = + names_without_system.clone().into_iter().rev().collect::>(); + let names_reversed_with_system_first = std::iter::once(system_pallet) + .chain(names_without_system_reverse.clone().into_iter()) + .collect::>(); + quote!( #types @@ -364,25 +343,28 @@ fn decl_all_pallets<'a>( pub type AllPallets = AllPalletsWithSystem; /// All pallets included in the runtime as a nested tuple of types. - pub type AllPalletsWithSystem = ( #all_pallets_with_system ); + pub type AllPalletsWithSystem = ( #(#names),* ); /// All pallets included in the runtime as a nested tuple of types. /// Excludes the System pallet. - pub type AllPalletsWithoutSystem = ( #all_pallets_without_system ); + pub type AllPalletsWithoutSystem = ( #(#names_without_system),* ); /// All pallets included in the runtime as a nested tuple of types in reversed order. /// Excludes the System pallet. - pub type AllPalletsWithoutSystemReversed = ( #all_pallets_without_system_reversed ); + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsWithoutSystemReversed =( #(#names_without_system_reverse),* ); /// All pallets included in the runtime as a nested tuple of types in reversed order. - pub type AllPalletsWithSystemReversed = ( #all_pallets_with_system_reversed ); + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsWithSystemReversed = ( #(#names_reversed),* ); /// All pallets included in the runtime as a nested tuple of types in reversed order. /// With the system pallet first. - pub type AllPalletsReversedWithSystemFirst = ( - #system_pallet, - AllPalletsWithoutSystemReversed - ); + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsReversedWithSystemFirst = ( #(#names_reversed_with_system_first),* ); ) } diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index a4a8acc10f799..f0fb6bacedffb 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -240,9 +240,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { #config_where_clause { fn count() -> usize { 1 } - fn accumulate( - acc: &mut #frame_support::sp_std::vec::Vec<#frame_support::traits::PalletInfoData> - ) { + fn infos() -> #frame_support::sp_std::vec::Vec<#frame_support::traits::PalletInfoData> { use #frame_support::traits::PalletInfoAccess; let item = #frame_support::traits::PalletInfoData { index: Self::index(), @@ -250,7 +248,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { module_name: Self::module_name(), crate_version: Self::crate_version(), }; - acc.push(item); + #frame_support::sp_std::vec![item] } } diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index fb0b658cd9303..a658f01fa6854 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -2207,7 +2207,7 @@ macro_rules! decl_module { for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { fn count() -> usize { 1 } - fn accumulate(acc: &mut $crate::sp_std::vec::Vec<$crate::traits::PalletInfoData>) { + fn infos() -> $crate::sp_std::vec::Vec<$crate::traits::PalletInfoData> { use $crate::traits::PalletInfoAccess; let item = $crate::traits::PalletInfoData { index: Self::index(), @@ -2215,7 +2215,7 @@ macro_rules! decl_module { module_name: Self::module_name(), crate_version: Self::crate_version(), }; - acc.push(item); + vec![item] } } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 8e43df82a284c..7e4c944330fe3 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -16,6 +16,16 @@ // limitations under the License. //! Support code for the runtime. +//! +//! ## Note on Tuple Traits +//! +//! Many of the traits defined in [`traits`] have auto-implementations on tuples as well. Usually, +//! the tuple is a function of number of pallets in the runtime. By default, the traits are +//! implemented for tuples of up to 64 items. +// +// If you have more pallets in your runtime, or for any other reason need more, enabled `tuples-96` +// or the `tuples-128` complication flag. Note that these features *will increase* the compilation +// of this crate. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/frame/support/src/migrations.rs b/frame/support/src/migrations.rs index 05833e0515c07..f594b98ede4ff 100644 --- a/frame/support/src/migrations.rs +++ b/frame/support/src/migrations.rs @@ -19,6 +19,7 @@ use crate::{ traits::{GetStorageVersion, PalletInfoAccess}, weights::{RuntimeDbWeight, Weight}, }; +use impl_trait_for_tuples::impl_for_tuples; /// Trait used by [`migrate_from_pallet_version_to_storage_version`] to do the actual migration. pub trait PalletVersionToStorageVersionHelper { @@ -42,7 +43,9 @@ impl PalletVersionToStorageVersionHelpe } } -#[impl_trait_for_tuples::impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl PalletVersionToStorageVersionHelper for T { fn migrate(db_weight: &RuntimeDbWeight) -> Weight { let mut weight: Weight = 0; diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 72d6d6682f14a..16504beb16907 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -50,7 +50,7 @@ mod error; pub use error::PalletError; mod filter; -pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter, IntegrityTest}; +pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter}; mod misc; pub use misc::{ @@ -81,7 +81,8 @@ mod hooks; #[cfg(feature = "std")] pub use hooks::GenesisBuild; pub use hooks::{ - Hooks, OnFinalize, OnGenesis, OnIdle, OnInitialize, OnRuntimeUpgrade, OnTimestampSet, + Hooks, IntegrityTest, OnFinalize, OnGenesis, OnIdle, OnInitialize, OnRuntimeUpgrade, + OnTimestampSet, }; #[cfg(feature = "try-runtime")] pub use hooks::{OnRuntimeUpgradeHelpersExt, ON_RUNTIME_UPGRADE_PREFIX}; diff --git a/frame/support/src/traits/filter.rs b/frame/support/src/traits/filter.rs index 95e5954184b4b..cdd82a3124e63 100644 --- a/frame/support/src/traits/filter.rs +++ b/frame/support/src/traits/filter.rs @@ -180,17 +180,6 @@ macro_rules! impl_filter_stack { } } -/// Type that provide some integrity tests. -/// -/// This implemented for modules by `decl_module`. -#[impl_trait_for_tuples::impl_for_tuples(30)] -pub trait IntegrityTest { - /// Run integrity test. - /// - /// The test is not executed in a externalities provided environment. - fn integrity_test() {} -} - #[cfg(test)] pub mod test_impl_filter_stack { use super::*; diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index 385db4e4d1ad9..2b7234006e0ff 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -38,7 +38,9 @@ pub trait OnInitialize { } } -#[impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnInitialize for Tuple { fn on_initialize(n: BlockNumber) -> crate::weights::Weight { let mut weight = 0; @@ -50,7 +52,9 @@ impl OnInitialize for Tuple { /// The block finalization trait. /// /// Implementing this lets you express what should happen for your pallet when the block is ending. -#[impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] pub trait OnFinalize { /// The block is being finalized. Implement to have something happen. /// @@ -79,7 +83,9 @@ pub trait OnIdle { } } -#[impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnIdle for Tuple { fn on_idle(n: BlockNumber, remaining_weight: crate::weights::Weight) -> crate::weights::Weight { let on_idle_functions: &[fn( @@ -105,7 +111,9 @@ impl OnIdle for Tuple { /// Implementing this trait for a pallet let's you express operations that should /// happen at genesis. It will be called in an externalities provided environment and /// will see the genesis state after all pallets have written their genesis state. -#[impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] pub trait OnGenesis { /// Something that should happen at genesis. fn on_genesis() {} @@ -187,7 +195,9 @@ pub trait OnRuntimeUpgrade { } } -#[impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnRuntimeUpgrade for Tuple { fn on_runtime_upgrade() -> crate::weights::Weight { let mut weight = 0; @@ -210,6 +220,19 @@ impl OnRuntimeUpgrade for Tuple { } } +/// Type that provide some integrity tests. +/// +/// This implemented for modules by `decl_module`. +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] +pub trait IntegrityTest { + /// Run integrity test. + /// + /// The test is not executed in a externalities provided environment. + fn integrity_test() {} +} + /// The pallet hooks trait. Implementing this lets you express some logic to execute. pub trait Hooks { /// The block is being finalized. Implement to have something happen. @@ -321,7 +344,9 @@ pub trait GenesisBuild: Default + sp_runtime::traits::MaybeSerializeD } /// A trait which is called when the timestamp is set in the runtime. -#[impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] pub trait OnTimestampSet { /// Called when the timestamp is set. fn on_timestamp_set(moment: Moment); diff --git a/frame/support/src/traits/members.rs b/frame/support/src/traits/members.rs index 8c69a2aaccb33..daf2d3aa6517d 100644 --- a/frame/support/src/traits/members.rs +++ b/frame/support/src/traits/members.rs @@ -17,6 +17,7 @@ //! Traits for dealing with the idea of membership. +use impl_trait_for_tuples::impl_for_tuples; use sp_std::{marker::PhantomData, prelude::*}; /// A trait for querying whether a type can be said to "contain" a value. @@ -25,7 +26,9 @@ pub trait Contains { fn contains(t: &T) -> bool; } -#[impl_trait_for_tuples::impl_for_tuples(1, 30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl Contains for Tuple { fn contains(t: &T) -> bool { for_tuples!( #( @@ -41,7 +44,9 @@ pub trait ContainsPair { fn contains(a: &A, b: &B) -> bool; } -#[impl_trait_for_tuples::impl_for_tuples(0, 30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl ContainsPair for Tuple { fn contains(a: &A, b: &B) -> bool { for_tuples!( #( diff --git a/frame/support/src/traits/metadata.rs b/frame/support/src/traits/metadata.rs index d3dc57e1ee52d..b0dd5bd5160b4 100644 --- a/frame/support/src/traits/metadata.rs +++ b/frame/support/src/traits/metadata.rs @@ -18,6 +18,7 @@ //! Traits for managing information attached to pallets and their constituents. use codec::{Decode, Encode}; +use impl_trait_for_tuples::impl_for_tuples; use sp_runtime::RuntimeDebug; use sp_std::prelude::*; @@ -70,40 +71,22 @@ pub trait PalletsInfoAccess { /// /// You probably don't want this function but `infos()` instead. fn count() -> usize { - 0 + // for backwards compatibility with XCM-3, Mark is deprecated. + Self::infos().len() } - /// Extend the given vector by all of the pallets' information that this type represents. - /// - /// You probably don't want this function but `infos()` instead. - fn accumulate(_accumulator: &mut Vec) {} - /// All of the pallets' information that this type represents. - fn infos() -> Vec { - let mut result = Vec::with_capacity(Self::count()); - Self::accumulate(&mut result); - result - } + fn infos() -> Vec; } -impl PalletsInfoAccess for () {} -impl PalletsInfoAccess for (T,) { - fn count() -> usize { - T::count() - } - fn accumulate(acc: &mut Vec) { - T::accumulate(acc) - } -} - -impl PalletsInfoAccess for (T1, T2) { - fn count() -> usize { - T1::count() + T2::count() - } - fn accumulate(acc: &mut Vec) { - // The AllPallets type tuplises the pallets in reverse order, so we unreverse them here. - T2::accumulate(acc); - T1::accumulate(acc); +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] +impl PalletsInfoAccess for Tuple { + fn infos() -> Vec { + let mut res = vec![]; + for_tuples!( #( res.extend(Tuple::infos()); )* ); + res } } diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index fa59fa92f920d..0f781d0bbd4cf 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -19,6 +19,7 @@ use crate::dispatch::Parameter; use codec::{CompactLen, Decode, DecodeLimit, Encode, EncodeLike, Input, MaxEncodedLen}; +use impl_trait_for_tuples::impl_for_tuples; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; use sp_arithmetic::traits::{CheckedAdd, CheckedMul, CheckedSub, Saturating}; #[doc(hidden)] @@ -467,14 +468,18 @@ impl SameOrOther { } /// Handler for when a new account has been created. -#[impl_trait_for_tuples::impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] pub trait OnNewAccount { /// A new account `who` has been registered. fn on_new_account(who: &AccountId); } /// The account with the given id was reaped. -#[impl_trait_for_tuples::impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] pub trait OnKilledAccount { /// The account with the given id was reaped. fn on_killed_account(who: &AccountId); @@ -632,7 +637,9 @@ impl PrivilegeCmp for EqualPrivilegeOnly { /// but cannot preform any alterations. More specifically alterations are /// not forbidden, but they are not persisted in any way after the worker /// has finished. -#[impl_trait_for_tuples::impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] pub trait OffchainWorker { /// This function is being called after every block import (when fully synced). /// diff --git a/frame/support/src/traits/storage.rs b/frame/support/src/traits/storage.rs index e484140cc2fd9..d40d82c28e87e 100644 --- a/frame/support/src/traits/storage.rs +++ b/frame/support/src/traits/storage.rs @@ -17,6 +17,7 @@ //! Traits for encoding data related to pallet's storage items. +use impl_trait_for_tuples::impl_for_tuples; use sp_std::prelude::*; /// An instance of a pallet in the storage. @@ -71,7 +72,9 @@ pub trait StorageInfoTrait { fn storage_info() -> Vec; } -#[impl_trait_for_tuples::impl_for_tuples(30)] +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl StorageInfoTrait for Tuple { fn storage_info() -> Vec { let mut res = vec![]; diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 6b72327eb4989..c4bbc59c70373 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -1597,8 +1597,9 @@ fn test_storage_info() { #[test] fn assert_type_all_pallets_reversed_with_system_first_is_correct() { // Just ensure the 2 types are same. + #[allow(deprecated)] fn _a(_t: AllPalletsReversedWithSystemFirst) {} - fn _b(t: (System, (Example4, (Example2, (Example,))))) { + fn _b(t: (System, Example4, Example2, Example)) { _a(t) } } @@ -1607,7 +1608,7 @@ fn assert_type_all_pallets_reversed_with_system_first_is_correct() { fn assert_type_all_pallets_with_system_is_correct() { // Just ensure the 2 types are same. fn _a(_t: AllPalletsWithSystem) {} - fn _b(t: (System, (Example, (Example2, (Example4,))))) { + fn _b(t: (System, Example, Example2, Example4)) { _a(t) } } @@ -1616,7 +1617,7 @@ fn assert_type_all_pallets_with_system_is_correct() { fn assert_type_all_pallets_without_system_is_correct() { // Just ensure the 2 types are same. fn _a(_t: AllPalletsWithoutSystem) {} - fn _b(t: (Example, (Example2, (Example4,)))) { + fn _b(t: (Example, Example2, Example4)) { _a(t) } } @@ -1624,8 +1625,9 @@ fn assert_type_all_pallets_without_system_is_correct() { #[test] fn assert_type_all_pallets_with_system_reversed_is_correct() { // Just ensure the 2 types are same. + #[allow(deprecated)] fn _a(_t: AllPalletsWithSystemReversed) {} - fn _b(t: (Example4, (Example2, (Example, (System,))))) { + fn _b(t: (Example4, Example2, Example, System)) { _a(t) } } @@ -1633,8 +1635,9 @@ fn assert_type_all_pallets_with_system_reversed_is_correct() { #[test] fn assert_type_all_pallets_without_system_reversed_is_correct() { // Just ensure the 2 types are same. + #[allow(deprecated)] fn _a(_t: AllPalletsWithoutSystemReversed) {} - fn _b(t: (Example4, (Example2, (Example,)))) { + fn _b(t: (Example4, Example2, Example)) { _a(t) } } diff --git a/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr b/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr index d1a89fbb850e9..ff52a094d6f8d 100644 --- a/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr +++ b/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr @@ -1,13 +1,13 @@ error[E0107]: missing generics for trait `Hooks` - --> $DIR/hooks_invalid_item.rs:12:18 + --> tests/pallet_ui/hooks_invalid_item.rs:12:18 | 12 | impl Hooks for Pallet {} | ^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `BlockNumber` - --> $DIR/hooks.rs:214:11 + --> $WORKSPACE/frame/support/src/traits/hooks.rs | -214 | pub trait Hooks { + | pub trait Hooks { | ^^^^^ ----------- help: add missing generic argument | From cf36d2f7eaaee27516c601141a2ea0acd3db641c Mon Sep 17 00:00:00 2001 From: Jake Hemmerle Date: Mon, 15 Aug 2022 03:53:39 -0400 Subject: [PATCH 1066/1472] swap ed25519-dalek for ed25519-zebra (#11781) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * swap ed25519-dalek for ed25519-zebra; no batch verificaiton fixed batch verificaiton tests removed additional zero verificaiton tests removed comments, fixed test bug, added #[derive(Clone)] Update primitives/core/src/ed25519.rs Co-authored-by: Squirrel * modified assertion to allow default ed25519-zebra zero key behavior * cargo clippy * Update primitives/core/Cargo.toml Co-authored-by: Bastian Köcher * Update primitives/core/src/ed25519.rs Co-authored-by: Davide Galassi * Update primitives/core/src/ed25519.rs Co-authored-by: Davide Galassi * Update primitives/core/src/ed25519.rs Co-authored-by: Davide Galassi * Update primitives/core/src/ed25519.rs Co-authored-by: Davide Galassi * updated Cargo.lock for sp-core * fix inaccurate comment Co-authored-by: Squirrel Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher Co-authored-by: Davide Galassi --- Cargo.lock | 16 ++++++++++- Cargo.toml | 2 +- primitives/core/Cargo.toml | 6 ++-- primitives/core/src/ed25519.rs | 51 ++++++++++++++-------------------- primitives/io/src/lib.rs | 27 +++++++++++------- 5 files changed, 57 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2db192dcbf1a1..b5506b1259436 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1788,6 +1788,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed25519-zebra" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +dependencies = [ + "curve25519-dalek 3.0.2", + "hex", + "rand_core 0.6.2", + "sha2 0.9.8", + "thiserror", + "zeroize", +] + [[package]] name = "either" version = "1.6.1" @@ -9624,7 +9638,7 @@ dependencies = [ "byteorder", "criterion", "dyn-clonable", - "ed25519-dalek", + "ed25519-zebra", "futures", "hash-db", "hash256-std-hasher", diff --git a/Cargo.toml b/Cargo.toml index 1f22343c002a8..e2907716ca9f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -258,7 +258,7 @@ crc32fast = { opt-level = 3 } crossbeam-deque = { opt-level = 3 } crypto-mac = { opt-level = 3 } curve25519-dalek = { opt-level = 3 } -ed25519-dalek = { opt-level = 3 } +ed25519-zebra = { opt-level = 3 } flate2 = { opt-level = 3 } futures-channel = { opt-level = 3 } hashbrown = { opt-level = 3 } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index fced678293140..2cdfd04e942d7 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -47,7 +47,7 @@ thiserror = { version = "1.0.30", optional = true } bitflags = "1.3" # full crypto -ed25519-dalek = { version = "1.0.1", default-features = false, features = ["u64_backend", "alloc"], optional = true } +ed25519-zebra = { version = "3.0.0", default-features = false, optional = true} blake2-rfc = { version = "0.2.18", default-features = false, optional = true } schnorrkel = { version = "0.9.1", features = [ "preaudit_deprecated", @@ -97,7 +97,7 @@ std = [ "sp-std/std", "serde", "blake2-rfc/std", - "ed25519-dalek/std", + "ed25519-zebra", "hex/std", "base58", "substrate-bip39", @@ -127,7 +127,7 @@ std = [ # or Intel SGX. # For the regular wasm runtime builds this should not be used. full_crypto = [ - "ed25519-dalek", + "ed25519-zebra", "blake2-rfc", "schnorrkel", "hex", diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 177af0651c0ef..0553cf4843df5 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -39,7 +39,9 @@ use crate::crypto::{DeriveJunction, Pair as TraitPair, SecretStringError}; #[cfg(feature = "std")] use bip39::{Language, Mnemonic, MnemonicType}; #[cfg(feature = "full_crypto")] -use ed25519_dalek::{Signer as _, Verifier as _}; +use core::convert::TryFrom; +#[cfg(feature = "full_crypto")] +use ed25519_zebra::{SigningKey, VerificationKey}; #[cfg(feature = "std")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_runtime_interface::pass_by::PassByInner; @@ -75,17 +77,10 @@ pub struct Public(pub [u8; 32]); /// A key pair. #[cfg(feature = "full_crypto")] -pub struct Pair(ed25519_dalek::Keypair); - -#[cfg(feature = "full_crypto")] -impl Clone for Pair { - fn clone(&self) -> Self { - Pair(ed25519_dalek::Keypair { - public: self.0.public, - secret: ed25519_dalek::SecretKey::from_bytes(self.0.secret.as_bytes()) - .expect("key is always the correct size; qed"), - }) - } +#[derive(Copy, Clone)] +pub struct Pair { + public: VerificationKey, + secret: SigningKey, } impl AsRef<[u8; 32]> for Public { @@ -456,10 +451,10 @@ impl TraitPair for Pair { /// /// You should never need to use this; generate(), generate_with_phrase fn from_seed_slice(seed_slice: &[u8]) -> Result { - let secret = ed25519_dalek::SecretKey::from_bytes(seed_slice) - .map_err(|_| SecretStringError::InvalidSeedLength)?; - let public = ed25519_dalek::PublicKey::from(&secret); - Ok(Pair(ed25519_dalek::Keypair { secret, public })) + let secret = + SigningKey::try_from(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?; + let public = VerificationKey::from(&secret); + Ok(Pair { secret, public }) } /// Derive a child key from a series of given junctions. @@ -468,7 +463,7 @@ impl TraitPair for Pair { path: Iter, _seed: Option, ) -> Result<(Pair, Option), DeriveError> { - let mut acc = self.0.secret.to_bytes(); + let mut acc = self.secret.into(); for j in path { match j { DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), @@ -480,16 +475,12 @@ impl TraitPair for Pair { /// Get the public key. fn public(&self) -> Public { - let mut r = [0u8; 32]; - let pk = self.0.public.as_bytes(); - r.copy_from_slice(pk); - Public(r) + Public(self.public.into()) } /// Sign a message. fn sign(&self, message: &[u8]) -> Signature { - let r = self.0.sign(message).to_bytes(); - Signature::from_raw(r) + Signature::from_raw(self.secret.sign(message).into()) } /// Verify a signature on a message. Returns true if the signature is good. @@ -502,17 +493,17 @@ impl TraitPair for Pair { /// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct /// size. Use it only if you're coming from byte buffers and need the speed. fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { - let public_key = match ed25519_dalek::PublicKey::from_bytes(pubkey.as_ref()) { + let public_key = match VerificationKey::try_from(pubkey.as_ref()) { Ok(pk) => pk, Err(_) => return false, }; - let sig = match ed25519_dalek::Signature::try_from(sig) { + let sig = match ed25519_zebra::Signature::try_from(sig) { Ok(s) => s, Err(_) => return false, }; - public_key.verify(message.as_ref(), &sig).is_ok() + public_key.verify(&sig, message.as_ref()).is_ok() } /// Return a vec filled with raw data. @@ -524,8 +515,8 @@ impl TraitPair for Pair { #[cfg(feature = "full_crypto")] impl Pair { /// Get the seed for this key. - pub fn seed(&self) -> &Seed { - self.0.secret.as_bytes() + pub fn seed(&self) -> Seed { + self.secret.into() } /// Exactly as `from_string` except that if no matches are found then, the the first 32 @@ -577,12 +568,12 @@ mod test { fn seed_and_derive_should_work() { let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); let pair = Pair::from_seed(&seed); - assert_eq!(pair.seed(), &seed); + assert_eq!(pair.seed(), seed); let path = vec![DeriveJunction::Hard([0u8; 32])]; let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; assert_eq!( derived.seed(), - &hex!("ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c") + hex!("ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c") ); } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 9bf9345e594c3..7942bafcc2a1b 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -1895,6 +1895,7 @@ mod tests { ext.register_extension(TaskExecutorExt::new(TaskExecutor::new())); ext.execute_with(|| { let pair = sr25519::Pair::generate_with_phrase(None).0; + let pair_unused = sr25519::Pair::generate_with_phrase(None).0; crypto::start_batch_verify(); for it in 0..70 { let msg = format!("Schnorrkel {}!", it); @@ -1902,8 +1903,10 @@ mod tests { crypto::sr25519_batch_verify(&signature, msg.as_bytes(), &pair.public()); } - // push invlaid - crypto::sr25519_batch_verify(&zero_sr_sig(), &Vec::new(), &zero_sr_pub()); + // push invalid + let msg = b"asdf!"; + let signature = pair.sign(msg); + crypto::sr25519_batch_verify(&signature, msg, &pair_unused.public()); assert!(!crypto::finish_batch_verify()); crypto::start_batch_verify(); @@ -1938,10 +1941,10 @@ mod tests { ext.register_extension(TaskExecutorExt::new(TaskExecutor::new())); ext.execute_with(|| { - // invalid ed25519 signature + // valid ed25519 signature crypto::start_batch_verify(); crypto::ed25519_batch_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub()); - assert!(!crypto::finish_batch_verify()); + assert!(crypto::finish_batch_verify()); // 2 valid ed25519 signatures crypto::start_batch_verify(); @@ -1961,12 +1964,14 @@ mod tests { // 1 valid, 1 invalid ed25519 signature crypto::start_batch_verify(); - let pair = ed25519::Pair::generate_with_phrase(None).0; + let pair1 = ed25519::Pair::generate_with_phrase(None).0; + let pair2 = ed25519::Pair::generate_with_phrase(None).0; let msg = b"Important message"; - let signature = pair.sign(msg); - crypto::ed25519_batch_verify(&signature, msg, &pair.public()); + let signature = pair1.sign(msg); crypto::ed25519_batch_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub()); + crypto::ed25519_batch_verify(&signature, msg, &pair1.public()); + crypto::ed25519_batch_verify(&signature, msg, &pair2.public()); assert!(!crypto::finish_batch_verify()); @@ -1993,11 +1998,13 @@ mod tests { // 1 valid sr25519, 1 invalid sr25519 crypto::start_batch_verify(); - let pair = sr25519::Pair::generate_with_phrase(None).0; + let pair1 = sr25519::Pair::generate_with_phrase(None).0; + let pair2 = sr25519::Pair::generate_with_phrase(None).0; let msg = b"Schnorrkcel!"; - let signature = pair.sign(msg); - crypto::sr25519_batch_verify(&signature, msg, &pair.public()); + let signature = pair1.sign(msg); + crypto::sr25519_batch_verify(&signature, msg, &pair1.public()); + crypto::sr25519_batch_verify(&signature, msg, &pair2.public()); crypto::sr25519_batch_verify(&zero_sr_sig(), &Vec::new(), &zero_sr_pub()); assert!(!crypto::finish_batch_verify()); From 90c8ac3410966ef538fb1444412b60077d073a05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 07:57:15 +0000 Subject: [PATCH 1067/1472] Bump rpassword from 5.0.1 to 7.0.0 (#11826) * Bump rpassword from 5.0.1 to 7.0.0 Bumps [rpassword](https://github.com/conradkleinespel/rpassword) from 5.0.1 to 7.0.0. - [Release notes](https://github.com/conradkleinespel/rpassword/releases) - [Commits](https://github.com/conradkleinespel/rpassword/compare/v5.0.1...v7.0.0) --- updated-dependencies: - dependency-name: rpassword dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Use new API Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi Signed-off-by: dependabot[bot] Signed-off-by: Oliver Tale-Yazdi Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi --- Cargo.lock | 4 ++-- client/cli/Cargo.toml | 2 +- client/cli/src/commands/utils.rs | 2 +- client/cli/src/params/keystore_params.rs | 5 ++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5506b1259436..da047d4cba6d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7534,9 +7534,9 @@ dependencies = [ [[package]] name = "rpassword" -version = "5.0.1" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +checksum = "26b763cb66df1c928432cc35053f8bd4cec3335d8559fc16010017d16b3c1680" dependencies = [ "libc", "winapi", diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index ea60e4c9f87e5..5f4c00d06aea3 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -24,7 +24,7 @@ names = { version = "0.13.0", default-features = false } parity-scale-codec = "3.0.0" rand = "0.7.3" regex = "1.5.5" -rpassword = "5.0.0" +rpassword = "7.0.0" serde = "1.0.136" serde_json = "1.0.79" thiserror = "1.0.30" diff --git a/client/cli/src/commands/utils.rs b/client/cli/src/commands/utils.rs index 32556f0ea728d..95849065471b4 100644 --- a/client/cli/src/commands/utils.rs +++ b/client/cli/src/commands/utils.rs @@ -48,7 +48,7 @@ pub fn read_uri(uri: Option<&String>) -> error::Result { uri.into() } } else { - rpassword::read_password_from_tty(Some("URI: "))? + rpassword::prompt_password("URI: ")? }; Ok(uri) diff --git a/client/cli/src/params/keystore_params.rs b/client/cli/src/params/keystore_params.rs index 46403f95fbc4b..386d1791dd805 100644 --- a/client/cli/src/params/keystore_params.rs +++ b/client/cli/src/params/keystore_params.rs @@ -94,7 +94,7 @@ impl KeystoreParams { let (password_interactive, password) = (self.password_interactive, self.password.clone()); let pass = if password_interactive { - let password = rpassword::read_password_from_tty(Some("Key password: "))?; + let password = rpassword::prompt_password("Key password: ")?; Some(SecretString::new(password)) } else { password @@ -105,6 +105,5 @@ impl KeystoreParams { } fn input_keystore_password() -> Result { - rpassword::read_password_from_tty(Some("Keystore password: ")) - .map_err(|e| format!("{:?}", e).into()) + rpassword::prompt_password("Keystore password: ").map_err(|e| format!("{:?}", e).into()) } From 20b5aac7e09e8b25abaa48c6781e653b36ba3ca0 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Mon, 15 Aug 2022 20:38:36 +0100 Subject: [PATCH 1068/1472] declone and close the door (#12035) * declone and close the door * cargo fmt * remove brackets --- .cargo/config.toml | 2 - bin/node/executor/tests/basic.rs | 2 +- bin/node/executor/tests/fees.rs | 2 +- bin/node/runtime/src/impls.rs | 12 +- client/api/src/in_mem.rs | 2 +- .../authority-discovery/src/worker/tests.rs | 19 ++- client/beefy/src/round.rs | 2 +- client/beefy/src/tests.rs | 2 +- client/beefy/src/worker.rs | 2 +- client/cli/src/commands/chain_info_cmd.rs | 2 +- client/consensus/aura/src/lib.rs | 4 +- client/consensus/babe/src/authorship.rs | 2 +- client/consensus/babe/src/tests.rs | 2 +- .../common/src/import_queue/basic_queue.rs | 2 +- client/consensus/epochs/src/lib.rs | 16 +-- client/consensus/manual-seal/src/lib.rs | 6 +- client/db/src/lib.rs | 2 +- client/db/src/storage_cache.rs | 6 +- client/executor/wasmtime/src/host.rs | 3 +- .../executor/wasmtime/src/instance_wrapper.rs | 26 ++-- client/executor/wasmtime/src/tests.rs | 2 +- .../src/communication/gossip.rs | 36 ++--- .../src/communication/tests.rs | 24 ++-- client/finality-grandpa/src/justification.rs | 4 +- client/finality-grandpa/src/tests.rs | 6 +- client/finality-grandpa/src/until_imported.rs | 4 +- client/finality-grandpa/src/voting_rule.rs | 2 +- client/network-gossip/src/bridge.rs | 18 +-- client/network-gossip/src/state_machine.rs | 2 +- client/network/src/discovery.rs | 2 +- client/network/sync/src/blocks.rs | 54 +++---- client/network/sync/src/extra_requests.rs | 8 +- client/network/sync/src/lib.rs | 40 +++--- client/rpc/src/chain/tests.rs | 8 +- client/service/test/src/client/mod.rs | 36 ++--- client/transaction-pool/benches/basics.rs | 4 +- client/transaction-pool/src/graph/pool.rs | 10 +- client/transaction-pool/src/graph/rotator.rs | 2 +- client/transaction-pool/tests/pool.rs | 32 ++--- frame/alliance/src/tests.rs | 46 +++--- frame/assets/src/mock.rs | 4 +- frame/atomic-swap/src/lib.rs | 2 +- frame/atomic-swap/src/tests.rs | 4 +- frame/contracts/src/exec.rs | 9 +- frame/contracts/src/tests.rs | 6 +- frame/contracts/src/wasm/mod.rs | 4 +- .../democracy/src/tests/external_proposing.rs | 9 +- frame/democracy/src/tests/public_proposals.rs | 2 +- frame/elections-phragmen/src/lib.rs | 7 +- frame/examples/offchain-worker/src/tests.rs | 10 +- frame/multisig/src/tests.rs | 134 +++--------------- .../nomination-pools/benchmarking/src/lib.rs | 10 +- frame/nomination-pools/src/lib.rs | 7 +- frame/nomination-pools/src/migration.rs | 2 +- frame/proxy/src/tests.rs | 2 +- frame/remark/src/tests.rs | 4 +- frame/scheduler/src/tests.rs | 4 +- frame/staking/src/mock.rs | 2 +- frame/staking/src/tests.rs | 5 +- frame/state-trie-migration/src/lib.rs | 2 +- frame/timestamp/src/mock.rs | 2 +- frame/tips/src/tests.rs | 66 ++++----- frame/transaction-payment/src/lib.rs | 8 +- frame/transaction-storage/src/tests.rs | 12 +- frame/uniques/src/functions.rs | 8 +- primitives/api/test/tests/runtime_calls.rs | 6 +- .../npos-elections/fuzzer/src/reduce.rs | 2 +- primitives/npos-elections/src/mock.rs | 16 +-- primitives/npos-elections/src/pjr.rs | 2 +- primitives/npos-elections/src/tests.rs | 45 ++---- primitives/runtime/src/curve.rs | 2 +- primitives/runtime/src/lib.rs | 2 +- 72 files changed, 344 insertions(+), 512 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index de299a90971e4..5355758f7a4fa 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -12,8 +12,6 @@ rustflags = [ "-Aclippy::if-same-then-else", "-Aclippy::clone-double-ref", "-Dclippy::complexity", - "-Aclippy::clone_on_copy", # Too common - "-Aclippy::needless_lifetimes", # Backward compat? "-Aclippy::zero-prefixed-literal", # 00_1000_000 "-Aclippy::type_complexity", # raison d'etre "-Aclippy::nonminimal-bool", # maybe diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 27e848a281097..468b9c8ac4c1b 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -127,7 +127,7 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { let block2 = construct_block( &mut t, 2, - block1.1.clone(), + block1.1, vec![ CheckedExtrinsic { signed: None, diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index 008ed5f53927b..296d1d8e28798 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -73,7 +73,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { let block2 = construct_block( &mut tt, 2, - block1.1.clone(), + block1.1, vec![ CheckedExtrinsic { signed: None, diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 68c780094208f..eaf872d6f3fec 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -197,12 +197,12 @@ mod multiplier_tests { fn truth_value_update_poc_works() { let fm = Multiplier::saturating_from_rational(1, 2); let test_set = vec![ - (0, fm.clone()), - (100, fm.clone()), - (1000, fm.clone()), - (target(), fm.clone()), - (max_normal() / 2, fm.clone()), - (max_normal(), fm.clone()), + (0, fm), + (100, fm), + (1000, fm), + (target(), fm), + (max_normal() / 2, fm), + (max_normal(), fm), ]; test_set.into_iter().for_each(|(w, fm)| { run_with_system_weight(w, || { diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index a8a7442a8ef9f..9000f62aa6cc3 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -173,7 +173,7 @@ impl Blockchain { { let mut storage = self.storage.write(); - storage.leaves.import(hash, number, header.parent_hash().clone()); + storage.leaves.import(hash, number, *header.parent_hash()); storage.blocks.insert(hash, StoredBlock::new(header, body, justifications)); if let NewBlockState::Final = new_state { diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index 5a60d3353db52..7b0ee45833e19 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -48,7 +48,7 @@ pub(crate) struct TestApi { impl ProvideRuntimeApi for TestApi { type Api = RuntimeApi; - fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { + fn runtime_api(&self) -> ApiRef<'_, Self::Api> { RuntimeApi { authorities: self.authorities.clone() }.into() } } @@ -530,7 +530,7 @@ impl DhtValueFoundTester { ) -> Option<&HashSet> { let (_dht_event_tx, dht_event_rx) = channel(1); let local_test_api = - Arc::new(TestApi { authorities: vec![self.remote_authority_public.clone().into()] }); + Arc::new(TestApi { authorities: vec![self.remote_authority_public.into()] }); let local_network: Arc = Arc::new(Default::default()); let local_key_store = KeyStore::new(); @@ -555,8 +555,7 @@ impl DhtValueFoundTester { self.local_worker .as_ref() .map(|w| { - w.addr_cache - .get_addresses_by_authority_id(&self.remote_authority_public.clone().into()) + w.addr_cache.get_addresses_by_authority_id(&self.remote_authority_public.into()) }) .unwrap() } @@ -569,7 +568,7 @@ fn limit_number_of_addresses_added_to_cache_per_authority() { let addresses = (1..100).map(|i| tester.multiaddr_with_peer_id(i)).collect(); let kv_pairs = block_on(build_dht_event::( addresses, - tester.remote_authority_public.clone().into(), + tester.remote_authority_public.into(), &tester.remote_key_store, None, )); @@ -584,7 +583,7 @@ fn strict_accept_address_with_peer_signature() { let addr = tester.multiaddr_with_peer_id(1); let kv_pairs = block_on(build_dht_event( vec![addr.clone()], - tester.remote_authority_public.clone().into(), + tester.remote_authority_public.into(), &tester.remote_key_store, Some(&TestSigner { keypair: &tester.remote_node_key }), )); @@ -604,7 +603,7 @@ fn reject_address_with_rogue_peer_signature() { let rogue_remote_node_key = Keypair::generate_ed25519(); let kv_pairs = block_on(build_dht_event( vec![tester.multiaddr_with_peer_id(1)], - tester.remote_authority_public.clone().into(), + tester.remote_authority_public.into(), &tester.remote_key_store, Some(&TestSigner { keypair: &rogue_remote_node_key }), )); @@ -622,7 +621,7 @@ fn reject_address_with_invalid_peer_signature() { let mut tester = DhtValueFoundTester::new(); let mut kv_pairs = block_on(build_dht_event( vec![tester.multiaddr_with_peer_id(1)], - tester.remote_authority_public.clone().into(), + tester.remote_authority_public.into(), &tester.remote_key_store, Some(&TestSigner { keypair: &tester.remote_node_key }), )); @@ -644,7 +643,7 @@ fn reject_address_without_peer_signature() { let mut tester = DhtValueFoundTester::new(); let kv_pairs = block_on(build_dht_event::( vec![tester.multiaddr_with_peer_id(1)], - tester.remote_authority_public.clone().into(), + tester.remote_authority_public.into(), &tester.remote_key_store, None, )); @@ -662,7 +661,7 @@ fn do_not_cache_addresses_without_peer_id() { "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333".parse().unwrap(); let kv_pairs = block_on(build_dht_event::( vec![multiaddr_with_peer_id.clone(), multiaddr_without_peer_id], - tester.remote_authority_public.clone().into(), + tester.remote_authority_public.into(), &tester.remote_key_store, None, )); diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index ebd85c8dea05d..762a8f7e5d544 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -109,7 +109,7 @@ where } pub(crate) fn should_self_vote(&self, round: &(P, NumberFor)) -> bool { - Some(round.1.clone()) > self.best_done && + Some(round.1) > self.best_done && self.rounds.get(round).map(|tracker| !tracker.has_self_vote()).unwrap_or(true) } diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 134339009302b..f0257d179cb33 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -326,7 +326,7 @@ fn add_auth_change_digest(header: &mut Header, new_auth_set: BeefyValidatorSet) } pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { - keys.iter().map(|key| key.clone().public().into()).collect() + keys.iter().map(|&key| key.public().into()).collect() } pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> SyncCryptoStorePtr { diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 2c4985c0e6966..9f1938fa91c33 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -1134,7 +1134,7 @@ pub(crate) mod tests { let mmr_root_hash = H256::random(); header.digest_mut().push(DigestItem::Consensus( BEEFY_ENGINE_ID, - ConsensusLog::::MmrRoot(mmr_root_hash.clone()).encode(), + ConsensusLog::::MmrRoot(mmr_root_hash).encode(), )); // verify validator set is correctly extracted from digest diff --git a/client/cli/src/commands/chain_info_cmd.rs b/client/cli/src/commands/chain_info_cmd.rs index c65092290cf2d..8fea0d7058e50 100644 --- a/client/cli/src/commands/chain_info_cmd.rs +++ b/client/cli/src/commands/chain_info_cmd.rs @@ -77,7 +77,7 @@ impl ChainInfoCmd { state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), state_pruning: config.state_pruning.clone(), source: config.database.clone(), - blocks_pruning: config.blocks_pruning.clone(), + blocks_pruning: config.blocks_pruning, }; let backend = sc_service::new_db_backend::(db_config)?; let info: ChainInfo = backend.blockchain().info().into(); diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index ee8be727dcdac..92fe1fa3cf29d 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -821,7 +821,7 @@ mod tests { block_import: client, env: environ, keystore: keystore.into(), - sync_oracle: DummyOracle.clone(), + sync_oracle: DummyOracle, justification_sync_link: (), force_authoring: false, backoff_authoring_blocks: Some(BackoffAuthoringOnFinalizedHeadLagging::default()), @@ -873,7 +873,7 @@ mod tests { block_import: client.clone(), env: environ, keystore: keystore.into(), - sync_oracle: DummyOracle.clone(), + sync_oracle: DummyOracle, justification_sync_link: (), force_authoring: false, backoff_authoring_blocks: Option::<()>::None, diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 43df26a9a29ae..896bfaeda1dc9 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -310,7 +310,7 @@ mod tests { assert!(claim_slot(10.into(), &epoch, &keystore).is_none()); - epoch.authorities.push((valid_public_key.clone().into(), 10)); + epoch.authorities.push((valid_public_key.into(), 10)); assert_eq!(claim_slot(10.into(), &epoch, &keystore).unwrap().1, valid_public_key.into()); } } diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index c0a7a8c6c013a..5ecdb42f7f177 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -152,7 +152,7 @@ impl DummyProposer { // that will re-check the randomness logic off-chain. let digest_data = ConsensusLog::NextEpochData(NextEpochDescriptor { authorities: epoch.authorities.clone(), - randomness: epoch.randomness.clone(), + randomness: epoch.randomness, }) .encode(); let digest = DigestItem::Consensus(BABE_ENGINE_ID, digest_data); diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index 9fe293142050b..84ccba990e599 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -535,7 +535,7 @@ mod tests { _number: BlockNumber, _success: bool, ) { - self.events.push(Event::JustificationImported(hash.clone())) + self.events.push(Event::JustificationImported(*hash)) } } diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index fee69613debf0..2e0186495db5e 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -1063,7 +1063,7 @@ mod tests { let incremented_epoch = epoch_changes .viable_epoch(&genesis_epoch_a_descriptor, &make_genesis) .unwrap() - .increment(next_descriptor.clone()); + .increment(next_descriptor); epoch_changes .import(&is_descendent_of, *b"A", 1, *b"0", incremented_epoch) @@ -1080,7 +1080,7 @@ mod tests { let incremented_epoch = epoch_changes .viable_epoch(&genesis_epoch_x_descriptor, &make_genesis) .unwrap() - .increment(next_descriptor.clone()); + .increment(next_descriptor); epoch_changes .import(&is_descendent_of, *b"X", 1, *b"0", incremented_epoch) @@ -1145,7 +1145,7 @@ mod tests { let incremented_epoch = epoch_changes .viable_epoch(&genesis_epoch_a_descriptor, &make_genesis) .unwrap() - .increment(next_descriptor.clone()); + .increment(next_descriptor); epoch_changes .import(&is_descendent_of, *b"A", 1, *b"0", incremented_epoch) @@ -1162,7 +1162,7 @@ mod tests { let incremented_epoch = epoch_changes .viable_epoch(&genesis_epoch_x_descriptor, &make_genesis) .unwrap() - .increment(next_descriptor.clone()); + .increment(next_descriptor); epoch_changes .import(&is_descendent_of, *b"X", 1, *b"0", incremented_epoch) @@ -1220,7 +1220,7 @@ mod tests { let incremented_epoch = epoch_changes .viable_epoch(&genesis_epoch_a_descriptor, &make_genesis) .unwrap() - .increment(next_descriptor.clone()); + .increment(next_descriptor); epoch_changes .import(&is_descendent_of, *b"1", 1, *b"0", incremented_epoch) @@ -1330,7 +1330,7 @@ mod tests { let incremented_epoch = epoch_changes .viable_epoch(&genesis_epoch_a_descriptor, &make_genesis) .unwrap() - .increment(next_descriptor.clone()); + .increment(next_descriptor); epoch_changes .import(&is_descendent_of, *b"A", 1, *b"0", incremented_epoch) @@ -1347,7 +1347,7 @@ mod tests { let incremented_epoch = epoch_changes .viable_epoch(&epoch_b_descriptor, &make_genesis) .unwrap() - .increment(next_descriptor.clone()); + .increment(next_descriptor); epoch_changes .import(&is_descendent_of, *b"B", 201, *b"A", incremented_epoch) @@ -1364,7 +1364,7 @@ mod tests { let incremented_epoch = epoch_changes .viable_epoch(&genesis_epoch_x_descriptor, &make_genesis) .unwrap() - .increment(next_descriptor.clone()); + .increment(next_descriptor); epoch_changes .import(&is_descendent_of, *b"C", 1, *b"0", incremented_epoch) diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index ba63666f3e46c..c5dd169e281f2 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -355,7 +355,7 @@ mod tests { assert_eq!( created_block, CreatedBlock { - hash: created_block.hash.clone(), + hash: created_block.hash, aux: ImportedAux { header_only: false, clear_justification_requests: false, @@ -422,7 +422,7 @@ mod tests { assert_eq!( created_block, CreatedBlock { - hash: created_block.hash.clone(), + hash: created_block.hash, aux: ImportedAux { header_only: false, clear_justification_requests: false, @@ -502,7 +502,7 @@ mod tests { assert_eq!( created_block, CreatedBlock { - hash: created_block.hash.clone(), + hash: created_block.hash, aux: ImportedAux { header_only: false, clear_justification_requests: false, diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 3214ee8f0d738..6b644ad53d52b 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -3390,7 +3390,7 @@ pub(crate) mod tests { assert!(backend.remove_leaf_block(&best_hash).is_err()); assert!(backend.have_state_at(&prev_hash, 1)); backend.remove_leaf_block(&prev_hash).unwrap(); - assert_eq!(None, backend.blockchain().header(BlockId::hash(prev_hash.clone())).unwrap()); + assert_eq!(None, backend.blockchain().header(BlockId::hash(prev_hash)).unwrap()); assert!(!backend.have_state_at(&prev_hash, 1)); } diff --git a/client/db/src/storage_cache.rs b/client/db/src/storage_cache.rs index 8326946999946..d9253fe09eb50 100644 --- a/client/db/src/storage_cache.rs +++ b/client/db/src/storage_cache.rs @@ -1223,7 +1223,7 @@ mod tests { let mut s = CachingState::new( InMemoryBackend::::default(), shared.clone(), - Some(root_parent.clone()), + Some(root_parent), ); let key = H256::random()[..].to_vec(); @@ -1307,14 +1307,14 @@ mod tests { let mut s = CachingState::new( InMemoryBackend::::default(), shared.clone(), - Some(root_parent.clone()), + Some(root_parent), ); s.cache.sync_cache( &[], &[], vec![(key.clone(), Some(vec![2]))], vec![], - Some(h0.clone()), + Some(h0), Some(0), true, ); diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index a54254810b68b..768a6e36e2390 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -276,12 +276,11 @@ impl<'a> Sandbox for HostContext<'a> { .ok_or("Runtime doesn't have a table; sandbox is unavailable")?; let table_item = table.get(&mut self.caller, dispatch_thunk_id); - table_item + *table_item .ok_or("dispatch_thunk_id is out of bounds")? .funcref() .ok_or("dispatch_thunk_idx should be a funcref")? .ok_or("dispatch_thunk_idx should point to actual func")? - .clone() }; let guest_env = match sandbox::GuestEnvironment::decode(self.sandbox_store(), raw_env_def) { diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index 5d272accd3524..feded4008068d 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -107,8 +107,7 @@ impl EntryPoint { ) -> std::result::Result { let entrypoint = func .typed::<(u32, u32), u64, _>(ctx) - .map_err(|_| "Invalid signature for direct entry point")? - .clone(); + .map_err(|_| "Invalid signature for direct entry point")?; Ok(Self { call_type: EntryPointType::Direct { entrypoint } }) } @@ -119,8 +118,7 @@ impl EntryPoint { ) -> std::result::Result { let dispatcher = dispatcher .typed::<(u32, u32, u32), u64, _>(ctx) - .map_err(|_| "Invalid signature for wrapped entry point")? - .clone(); + .map_err(|_| "Invalid signature for wrapped entry point")?; Ok(Self { call_type: EntryPointType::Wrapped { func, dispatcher } }) } } @@ -214,9 +212,8 @@ impl InstanceWrapper { Error::from(format!("Exported method {} is not found", method)) })?; let func = extern_func(&export) - .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))? - .clone(); - EntryPoint::direct(func, &self.store).map_err(|_| { + .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))?; + EntryPoint::direct(*func, &self.store).map_err(|_| { Error::from(format!("Exported function '{}' has invalid signature.", method)) })? }, @@ -231,10 +228,9 @@ impl InstanceWrapper { let func = val .funcref() .ok_or(Error::TableElementIsNotAFunction(func_ref))? - .ok_or(Error::FunctionRefIsNull(func_ref))? - .clone(); + .ok_or(Error::FunctionRefIsNull(func_ref))?; - EntryPoint::direct(func, &self.store).map_err(|_| { + EntryPoint::direct(*func, &self.store).map_err(|_| { Error::from(format!( "Function @{} in exported table has invalid signature for direct call.", func_ref, @@ -252,10 +248,9 @@ impl InstanceWrapper { let dispatcher = val .funcref() .ok_or(Error::TableElementIsNotAFunction(dispatcher_ref))? - .ok_or(Error::FunctionRefIsNull(dispatcher_ref))? - .clone(); + .ok_or(Error::FunctionRefIsNull(dispatcher_ref))?; - EntryPoint::wrapped(dispatcher, func, &self.store).map_err(|_| { + EntryPoint::wrapped(*dispatcher, func, &self.store).map_err(|_| { Error::from(format!( "Function @{} in exported table has invalid signature for wrapped call.", dispatcher_ref, @@ -315,9 +310,8 @@ fn get_linear_memory(instance: &Instance, ctx: impl AsContextMut) -> Result(&'a mut self) -> impl WasmModule + 'a { + fn build(&mut self) -> impl WasmModule + '_ { let blob = { let wasm: Vec; diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 9e9f2fb98b0d1..5f94a4d1b65be 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -1729,7 +1729,7 @@ mod tests { assert!(res.unwrap().is_none()); // connect & disconnect. - peers.new_peer(id.clone(), ObservedRole::Authority); + peers.new_peer(id, ObservedRole::Authority); peers.peer_disconnected(&id); let res = peers.update_peer_state(&id, update.clone()); @@ -1753,7 +1753,7 @@ mod tests { let mut peers = Peers::default(); let id = PeerId::random(); - peers.new_peer(id.clone(), ObservedRole::Authority); + peers.new_peer(id, ObservedRole::Authority); let mut check_update = move |update: NeighborPacket<_>| { let view = peers.update_peer_state(&id, update.clone()).unwrap().unwrap(); @@ -1773,7 +1773,7 @@ mod tests { let mut peers = Peers::default(); let id = PeerId::random(); - peers.new_peer(id.clone(), ObservedRole::Authority); + peers.new_peer(id, ObservedRole::Authority); peers .update_peer_state( @@ -1964,7 +1964,7 @@ mod tests { // add the peer making the request to the validator, // otherwise it is discarded let mut inner = val.inner.write(); - inner.peers.new_peer(peer.clone(), ObservedRole::Authority); + inner.peers.new_peer(peer, ObservedRole::Authority); let res = inner.handle_catch_up_request( &peer, @@ -2005,7 +2005,7 @@ mod tests { // add the peer making the request to the validator, // otherwise it is discarded let peer = PeerId::random(); - val.inner.write().peers.new_peer(peer.clone(), ObservedRole::Authority); + val.inner.write().peers.new_peer(peer, ObservedRole::Authority); let send_request = |set_id, round| { let mut inner = val.inner.write(); @@ -2060,7 +2060,7 @@ mod tests { // add the peer making the request to the validator, // otherwise it is discarded. let peer = PeerId::random(); - val.inner.write().peers.new_peer(peer.clone(), ObservedRole::Authority); + val.inner.write().peers.new_peer(peer, ObservedRole::Authority); let import_neighbor_message = |set_id, round| { let (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message( @@ -2130,7 +2130,7 @@ mod tests { // add the peer making the request to the validator, // otherwise it is discarded. let peer = PeerId::random(); - val.inner.write().peers.new_peer(peer.clone(), ObservedRole::Authority); + val.inner.write().peers.new_peer(peer, ObservedRole::Authority); // importing a neighbor message from a peer in the same set in a later // round should lead to a catch up request but since they're disabled @@ -2158,11 +2158,8 @@ mod tests { let peer_authority = PeerId::random(); let peer_full = PeerId::random(); - val.inner - .write() - .peers - .new_peer(peer_authority.clone(), ObservedRole::Authority); - val.inner.write().peers.new_peer(peer_full.clone(), ObservedRole::Full); + val.inner.write().peers.new_peer(peer_authority, ObservedRole::Authority); + val.inner.write().peers.new_peer(peer_full, ObservedRole::Full); let import_neighbor_message = |peer| { let (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message( @@ -2211,7 +2208,7 @@ mod tests { // add the peer making the requests to the validator, otherwise it is // discarded. let peer_full = PeerId::random(); - val.inner.write().peers.new_peer(peer_full.clone(), ObservedRole::Full); + val.inner.write().peers.new_peer(peer_full, ObservedRole::Full); let (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message( &peer_full, @@ -2271,12 +2268,9 @@ mod tests { full_nodes.resize_with(30, || PeerId::random()); for i in 0..30 { - val.inner - .write() - .peers - .new_peer(authorities[i].clone(), ObservedRole::Authority); + val.inner.write().peers.new_peer(authorities[i], ObservedRole::Authority); - val.inner.write().peers.new_peer(full_nodes[i].clone(), ObservedRole::Full); + val.inner.write().peers.new_peer(full_nodes[i], ObservedRole::Full); } let test = |rounds_elapsed, peers| { @@ -2355,7 +2349,7 @@ mod tests { // add a new light client as peer let light_peer = PeerId::random(); - val.inner.write().peers.new_peer(light_peer.clone(), ObservedRole::Light); + val.inner.write().peers.new_peer(light_peer, ObservedRole::Light); assert!(!val.message_allowed()( &light_peer, @@ -2427,7 +2421,7 @@ mod tests { // add a new peer at set id 1 let peer1 = PeerId::random(); - val.inner.write().peers.new_peer(peer1.clone(), ObservedRole::Authority); + val.inner.write().peers.new_peer(peer1, ObservedRole::Authority); val.inner .write() @@ -2440,7 +2434,7 @@ mod tests { // peer2 will default to set id 0 let peer2 = PeerId::random(); - val.inner.write().peers.new_peer(peer2.clone(), ObservedRole::Authority); + val.inner.write().peers.new_peer(peer2, ObservedRole::Authority); // create a commit for round 1 of set id 1 // targeting a block at height 2 diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index 59935cef6a095..5b2436b23351e 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -177,7 +177,7 @@ impl sc_network_gossip::ValidatorContext for TestNetwork { fn send_message(&mut self, who: &PeerId, data: Vec) { ::write_notification( self, - who.clone(), + *who, grandpa_protocol_name::NAME.into(), data, ); @@ -280,7 +280,7 @@ pub(crate) fn make_test_network() -> (impl Future, TestNetwork) } fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { - keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect() + keys.iter().map(|&key| key.public().into()).map(|id| (id, 1)).collect() } struct NoopContext; @@ -305,8 +305,7 @@ fn good_commit_leads_to_relay() { let target_hash: Hash = [1; 32].into(); let target_number = 500; - let precommit = - finality_grandpa::Precommit { target_hash: target_hash.clone(), target_number }; + let precommit = finality_grandpa::Precommit { target_hash, target_number }; let payload = sp_finality_grandpa::localized_payload( round, set_id, @@ -362,19 +361,19 @@ fn good_commit_leads_to_relay() { // asking for global communication will cause the test network // to send us an event asking us for a stream. use it to // send a message. - let sender_id = id.clone(); + let sender_id = id; let send_message = tester.filter_network_events(move |event| match event { Event::EventStream(sender) => { // Add the sending peer and send the commit let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { - remote: sender_id.clone(), + remote: sender_id, protocol: grandpa_protocol_name::NAME.into(), negotiated_fallback: None, role: ObservedRole::Full, }); let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { - remote: sender_id.clone(), + remote: sender_id, messages: vec![( grandpa_protocol_name::NAME.into(), commit_to_send.clone().into(), @@ -384,7 +383,7 @@ fn good_commit_leads_to_relay() { // Add a random peer which will be the recipient of this message let receiver_id = PeerId::random(); let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { - remote: receiver_id.clone(), + remote: receiver_id, protocol: grandpa_protocol_name::NAME.into(), negotiated_fallback: None, role: ObservedRole::Full, @@ -456,8 +455,7 @@ fn bad_commit_leads_to_report() { let target_hash: Hash = [1; 32].into(); let target_number = 500; - let precommit = - finality_grandpa::Precommit { target_hash: target_hash.clone(), target_number }; + let precommit = finality_grandpa::Precommit { target_hash, target_number }; let payload = sp_finality_grandpa::localized_payload( round, set_id, @@ -513,17 +511,17 @@ fn bad_commit_leads_to_report() { // asking for global communication will cause the test network // to send us an event asking us for a stream. use it to // send a message. - let sender_id = id.clone(); + let sender_id = id; let send_message = tester.filter_network_events(move |event| match event { Event::EventStream(sender) => { let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { - remote: sender_id.clone(), + remote: sender_id, protocol: grandpa_protocol_name::NAME.into(), negotiated_fallback: None, role: ObservedRole::Full, }); let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { - remote: sender_id.clone(), + remote: sender_id, messages: vec![( grandpa_protocol_name::NAME.into(), commit_to_send.clone().into(), diff --git a/client/finality-grandpa/src/justification.rs b/client/finality-grandpa/src/justification.rs index 44abb4b95beba..6c3b6aa826ded 100644 --- a/client/finality-grandpa/src/justification.rs +++ b/client/finality-grandpa/src/justification.rs @@ -74,7 +74,7 @@ impl GrandpaJustification { .iter() .map(|signed| &signed.precommit) .min_by_key(|precommit| precommit.target_number) - .map(|precommit| (precommit.target_hash.clone(), precommit.target_number)) + .map(|precommit| (precommit.target_hash, precommit.target_number)) { None => return error(), Some(base) => base, @@ -176,7 +176,7 @@ impl GrandpaJustification { .iter() .map(|signed| &signed.precommit) .min_by_key(|precommit| precommit.target_number) - .map(|precommit| precommit.target_hash.clone()) + .map(|precommit| precommit.target_hash) .expect( "can only fail if precommits is empty; \ commit has been validated above; \ diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 623ac577c5579..3dd21d51b6a2d 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -170,7 +170,7 @@ pub(crate) struct RuntimeApi { impl ProvideRuntimeApi for TestApi { type Api = RuntimeApi; - fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { + fn runtime_api(&self) -> ApiRef<'_, Self::Api> { RuntimeApi { inner: self.clone() }.into() } } @@ -210,7 +210,7 @@ impl GenesisAuthoritySetProvider for TestApi { const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500); fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { - keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect() + keys.iter().map(|&key| key.public().into()).map(|id| (id, 1)).collect() } fn create_keystore(authority: Ed25519Keyring) -> (SyncCryptoStorePtr, tempfile::TempDir) { @@ -533,7 +533,7 @@ fn transition_3_voters_twice_1_full_observer() { { let net = net.clone(); let client = net.lock().peers[0].client().clone(); - let peers_c = peers_c.clone(); + let peers_c = *peers_c; // wait for blocks to be finalized before generating new ones let block_production = client diff --git a/client/finality-grandpa/src/until_imported.rs b/client/finality-grandpa/src/until_imported.rs index 6adce0d920209..fe7caf74422db 100644 --- a/client/finality-grandpa/src/until_imported.rs +++ b/client/finality-grandpa/src/until_imported.rs @@ -587,7 +587,7 @@ mod tests { fn import_header(&self, header: Header) { let hash = header.hash(); - let number = header.number().clone(); + let number = *header.number(); self.known_blocks.lock().insert(hash, number); self.sender @@ -608,7 +608,7 @@ mod tests { impl BlockStatusT for TestBlockStatus { fn block_number(&self, hash: Hash) -> Result, Error> { - Ok(self.inner.lock().get(&hash).map(|x| x.clone())) + Ok(self.inner.lock().get(&hash).map(|x| *x)) } } diff --git a/client/finality-grandpa/src/voting_rule.rs b/client/finality-grandpa/src/voting_rule.rs index 051c7f2c03658..fb7754fc0169a 100644 --- a/client/finality-grandpa/src/voting_rule.rs +++ b/client/finality-grandpa/src/voting_rule.rs @@ -419,7 +419,7 @@ mod tests { } let best = client.header(&BlockId::Hash(client.info().best_hash)).unwrap().unwrap(); - let best_number = best.number().clone(); + let best_number = *best.number(); for i in 0u32..5 { let base = client.header(&BlockId::Number(i.into())).unwrap().unwrap(); diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 8a6c3358e4409..b5c957024701d 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -520,7 +520,7 @@ mod tests { // Register the remote peer. event_sender .start_send(Event::NotificationStreamOpened { - remote: remote_peer.clone(), + remote: remote_peer, protocol: protocol.clone(), negotiated_fallback: None, role: ObservedRole::Authority, @@ -532,7 +532,7 @@ mod tests { .iter() .cloned() .map(|m| Event::NotificationsReceived { - remote: remote_peer.clone(), + remote: remote_peer, messages: vec![(protocol.clone(), m.into())], }) .collect::>(); @@ -562,10 +562,7 @@ mod tests { for subscriber in subscribers.iter_mut() { assert_eq!( subscriber.next(), - Some(TopicNotification { - message: message.clone(), - sender: Some(remote_peer.clone()), - }), + Some(TopicNotification { message: message.clone(), sender: Some(remote_peer) }), ); } } @@ -661,7 +658,7 @@ mod tests { // Create channels. let (txs, mut rxs) = channels .iter() - .map(|ChannelLengthAndTopic { length, topic }| (topic.clone(), channel(*length))) + .map(|ChannelLengthAndTopic { length, topic }| (*topic, channel(*length))) .fold((vec![], vec![]), |mut acc, (topic, (tx, rx))| { acc.0.push((topic, tx)); acc.1.push((topic, rx)); @@ -683,7 +680,7 @@ mod tests { // Register the remote peer. event_sender .start_send(Event::NotificationStreamOpened { - remote: remote_peer.clone(), + remote: remote_peer, protocol: protocol.clone(), negotiated_fallback: None, role: ObservedRole::Authority, @@ -710,10 +707,7 @@ mod tests { .collect(); event_sender - .start_send(Event::NotificationsReceived { - remote: remote_peer.clone(), - messages, - }) + .start_send(Event::NotificationsReceived { remote: remote_peer, messages }) .expect("Event stream is unbounded; qed."); } diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 4cc4e25529af4..3cb8d5bd9bab9 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -810,7 +810,7 @@ mod tests { .on_incoming( &mut network, // Unregistered peer. - remote.clone(), + remote, vec![vec![1, 2, 3]], ); diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index f3d1588c0280e..ab93662968dc2 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -1069,7 +1069,7 @@ mod tests { // Skip the first swarm as all other swarms already know it. .skip(1) .filter(|p| *p != n) - .map(|p| Swarm::local_peer_id(&swarms[p].0).clone()) + .map(|p| *Swarm::local_peer_id(&swarms[p].0)) .collect::>() }) .collect::>(); diff --git a/client/network/sync/src/blocks.rs b/client/network/sync/src/blocks.rs index 5fb1484675071..b8acd61a2009f 100644 --- a/client/network/sync/src/blocks.rs +++ b/client/network/sync/src/blocks.rs @@ -290,51 +290,51 @@ mod test { let peer2 = PeerId::random(); let blocks = generate_blocks(150); - assert_eq!(bc.needed_blocks(peer0.clone(), 40, 150, 0, 1, 200), Some(1..41)); - assert_eq!(bc.needed_blocks(peer1.clone(), 40, 150, 0, 1, 200), Some(41..81)); - assert_eq!(bc.needed_blocks(peer2.clone(), 40, 150, 0, 1, 200), Some(81..121)); + assert_eq!(bc.needed_blocks(peer0, 40, 150, 0, 1, 200), Some(1..41)); + assert_eq!(bc.needed_blocks(peer1, 40, 150, 0, 1, 200), Some(41..81)); + assert_eq!(bc.needed_blocks(peer2, 40, 150, 0, 1, 200), Some(81..121)); bc.clear_peer_download(&peer1); - bc.insert(41, blocks[41..81].to_vec(), peer1.clone()); + bc.insert(41, blocks[41..81].to_vec(), peer1); assert_eq!(bc.ready_blocks(1), vec![]); - assert_eq!(bc.needed_blocks(peer1.clone(), 40, 150, 0, 1, 200), Some(121..151)); + assert_eq!(bc.needed_blocks(peer1, 40, 150, 0, 1, 200), Some(121..151)); bc.clear_peer_download(&peer0); - bc.insert(1, blocks[1..11].to_vec(), peer0.clone()); + bc.insert(1, blocks[1..11].to_vec(), peer0); - assert_eq!(bc.needed_blocks(peer0.clone(), 40, 150, 0, 1, 200), Some(11..41)); + assert_eq!(bc.needed_blocks(peer0, 40, 150, 0, 1, 200), Some(11..41)); assert_eq!( bc.ready_blocks(1), blocks[1..11] .iter() - .map(|b| BlockData { block: b.clone(), origin: Some(peer0.clone()) }) + .map(|b| BlockData { block: b.clone(), origin: Some(peer0) }) .collect::>() ); bc.clear_peer_download(&peer0); - bc.insert(11, blocks[11..41].to_vec(), peer0.clone()); + bc.insert(11, blocks[11..41].to_vec(), peer0); let ready = bc.ready_blocks(12); assert_eq!( ready[..30], blocks[11..41] .iter() - .map(|b| BlockData { block: b.clone(), origin: Some(peer0.clone()) }) + .map(|b| BlockData { block: b.clone(), origin: Some(peer0) }) .collect::>()[..] ); assert_eq!( ready[30..], blocks[41..81] .iter() - .map(|b| BlockData { block: b.clone(), origin: Some(peer1.clone()) }) + .map(|b| BlockData { block: b.clone(), origin: Some(peer1) }) .collect::>()[..] ); bc.clear_peer_download(&peer2); - assert_eq!(bc.needed_blocks(peer2.clone(), 40, 150, 80, 1, 200), Some(81..121)); + assert_eq!(bc.needed_blocks(peer2, 40, 150, 80, 1, 200), Some(81..121)); bc.clear_peer_download(&peer2); - bc.insert(81, blocks[81..121].to_vec(), peer2.clone()); + bc.insert(81, blocks[81..121].to_vec(), peer2); bc.clear_peer_download(&peer1); - bc.insert(121, blocks[121..150].to_vec(), peer1.clone()); + bc.insert(121, blocks[121..150].to_vec(), peer1); assert_eq!(bc.ready_blocks(80), vec![]); let ready = bc.ready_blocks(81); @@ -342,14 +342,14 @@ mod test { ready[..40], blocks[81..121] .iter() - .map(|b| BlockData { block: b.clone(), origin: Some(peer2.clone()) }) + .map(|b| BlockData { block: b.clone(), origin: Some(peer2) }) .collect::>()[..] ); assert_eq!( ready[40..], blocks[121..150] .iter() - .map(|b| BlockData { block: b.clone(), origin: Some(peer1.clone()) }) + .map(|b| BlockData { block: b.clone(), origin: Some(peer1) }) .collect::>()[..] ); } @@ -365,10 +365,10 @@ mod test { bc.blocks.insert(114305, BlockRangeState::Complete(blocks)); let peer0 = PeerId::random(); - assert_eq!(bc.needed_blocks(peer0.clone(), 128, 10000, 000, 1, 200), Some(1..100)); - assert_eq!(bc.needed_blocks(peer0.clone(), 128, 10000, 600, 1, 200), None); // too far ahead + assert_eq!(bc.needed_blocks(peer0, 128, 10000, 000, 1, 200), Some(1..100)); + assert_eq!(bc.needed_blocks(peer0, 128, 10000, 600, 1, 200), None); // too far ahead assert_eq!( - bc.needed_blocks(peer0.clone(), 128, 10000, 600, 1, 200000), + bc.needed_blocks(peer0, 128, 10000, 600, 1, 200000), Some(100 + 128..100 + 128 + 128) ); } @@ -382,11 +382,11 @@ mod test { let blocks = generate_blocks(10); // count = 5, peer_best = 50, common = 39, max_parallel = 0, max_ahead = 200 - assert_eq!(bc.needed_blocks(peer.clone(), 5, 50, 39, 0, 200), Some(40..45)); + assert_eq!(bc.needed_blocks(peer, 5, 50, 39, 0, 200), Some(40..45)); // got a response on the request for `40..45` bc.clear_peer_download(&peer); - bc.insert(40, blocks[..5].to_vec(), peer.clone()); + bc.insert(40, blocks[..5].to_vec(), peer); // our "node" started on a fork, with its current best = 47, which is > common let ready = bc.ready_blocks(48); @@ -394,11 +394,11 @@ mod test { ready, blocks[..5] .iter() - .map(|b| BlockData { block: b.clone(), origin: Some(peer.clone()) }) + .map(|b| BlockData { block: b.clone(), origin: Some(peer) }) .collect::>() ); - assert_eq!(bc.needed_blocks(peer.clone(), 5, 50, 39, 0, 200), Some(45..50)); + assert_eq!(bc.needed_blocks(peer, 5, 50, 39, 0, 200), Some(45..50)); } #[test] @@ -410,12 +410,12 @@ mod test { let blocks = generate_blocks(10); // Request 2 ranges - assert_eq!(bc.needed_blocks(peer.clone(), 5, 50, 39, 0, 200), Some(40..45)); - assert_eq!(bc.needed_blocks(peer.clone(), 5, 50, 39, 0, 200), Some(45..50)); + assert_eq!(bc.needed_blocks(peer, 5, 50, 39, 0, 200), Some(40..45)); + assert_eq!(bc.needed_blocks(peer, 5, 50, 39, 0, 200), Some(45..50)); // got a response on the request for `40..50` bc.clear_peer_download(&peer); - bc.insert(40, blocks.to_vec(), peer.clone()); + bc.insert(40, blocks.to_vec(), peer); // request any blocks starting from 1000 or lower. let ready = bc.ready_blocks(1000); @@ -423,7 +423,7 @@ mod test { ready, blocks .iter() - .map(|b| BlockData { block: b.clone(), origin: Some(peer.clone()) }) + .map(|b| BlockData { block: b.clone(), origin: Some(peer) }) .collect::>() ); diff --git a/client/network/sync/src/extra_requests.rs b/client/network/sync/src/extra_requests.rs index 6206f8a61bcf4..0506bd542ff3b 100644 --- a/client/network/sync/src/extra_requests.rs +++ b/client/network/sync/src/extra_requests.rs @@ -446,16 +446,12 @@ mod tests { PeerSyncState::DownloadingJustification(r.0); } - let active = requests - .active_requests - .iter() - .map(|(p, &r)| (p.clone(), r)) - .collect::>(); + let active = requests.active_requests.iter().map(|(&p, &r)| (p, r)).collect::>(); for (peer, req) in &active { assert!(requests.failed_requests.get(req).is_none()); assert!(!requests.pending_requests.contains(req)); - assert!(requests.on_response::<()>(peer.clone(), None).is_none()); + assert!(requests.on_response::<()>(*peer, None).is_none()); assert!(requests.pending_requests.contains(req)); assert_eq!( 1, diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 2f837cd6c4f51..aae5f4de353fe 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -2614,15 +2614,15 @@ mod test { let (b1_hash, b1_number) = new_blocks(50); // add 2 peers at blocks that we don't have locally - sync.new_peer(peer_id1.clone(), Hash::random(), 42).unwrap(); - sync.new_peer(peer_id2.clone(), Hash::random(), 10).unwrap(); + sync.new_peer(peer_id1, Hash::random(), 42).unwrap(); + sync.new_peer(peer_id2, Hash::random(), 10).unwrap(); // we wil send block requests to these peers // for these blocks we don't know about assert!(sync.block_requests().all(|(p, _)| { *p == peer_id1 || *p == peer_id2 })); // add a new peer at a known block - sync.new_peer(peer_id3.clone(), b1_hash, b1_number).unwrap(); + sync.new_peer(peer_id3, b1_hash, b1_number).unwrap(); // we request a justification for a block we have locally sync.request_justification(&b1_hash, b1_number); @@ -2673,7 +2673,7 @@ mod test { data: Some(Vec::new()), }; - sync.push_block_announce_validation(peer_id.clone(), header.hash(), block_annnounce, true); + sync.push_block_announce_validation(*peer_id, header.hash(), block_annnounce, true); // Poll until we have procssed the block announcement block_on(poll_fn(|cx| loop { @@ -2790,8 +2790,8 @@ mod test { let block3_fork = build_block_at(block2.hash(), false); // Add two peers which are on block 1. - sync.new_peer(peer_id1.clone(), block1.hash(), 1).unwrap(); - sync.new_peer(peer_id2.clone(), block1.hash(), 1).unwrap(); + sync.new_peer(peer_id1, block1.hash(), 1).unwrap(); + sync.new_peer(peer_id2, block1.hash(), 1).unwrap(); // Tell sync that our best block is 3. sync.update_chain_info(&block3.hash(), 3); @@ -2885,9 +2885,9 @@ mod test { let best_block = blocks.last().unwrap().clone(); // Connect the node we will sync from - sync.new_peer(peer_id1.clone(), best_block.hash(), *best_block.header().number()) + sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()) .unwrap(); - sync.new_peer(peer_id2.clone(), info.best_hash, 0).unwrap(); + sync.new_peer(peer_id2, info.best_hash, 0).unwrap(); let mut best_block_num = 0; while best_block_num < MAX_DOWNLOAD_AHEAD { @@ -2922,9 +2922,9 @@ mod test { .map(|b| { ( Ok(BlockImportStatus::ImportedUnknown( - b.header().number().clone(), + *b.header().number(), Default::default(), - Some(peer_id1.clone()), + Some(peer_id1), )), b.hash(), ) @@ -3034,7 +3034,7 @@ mod test { let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); // Connect the node we will sync from - sync.new_peer(peer_id1.clone(), common_block.hash(), *common_block.header().number()) + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) .unwrap(); send_block_announce(fork_blocks.last().unwrap().header().clone(), &peer_id1, &mut sync); @@ -3059,7 +3059,7 @@ mod test { } // Now request and import the fork. - let mut best_block_num = finalized_block.header().number().clone() as u32; + let mut best_block_num = *finalized_block.header().number() as u32; while best_block_num < *fork_blocks.last().unwrap().header().number() as u32 - 1 { let request = get_block_request( &mut sync, @@ -3092,9 +3092,9 @@ mod test { .map(|b| { ( Ok(BlockImportStatus::ImportedUnknown( - b.header().number().clone(), + *b.header().number(), Default::default(), - Some(peer_id1.clone()), + Some(peer_id1), )), b.hash(), ) @@ -3165,7 +3165,7 @@ mod test { let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); // Connect the node we will sync from - sync.new_peer(peer_id1.clone(), common_block.hash(), *common_block.header().number()) + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) .unwrap(); send_block_announce(fork_blocks.last().unwrap().header().clone(), &peer_id1, &mut sync); @@ -3190,7 +3190,7 @@ mod test { } // Now request and import the fork. - let mut best_block_num = finalized_block.header().number().clone() as u32; + let mut best_block_num = *finalized_block.header().number() as u32; let mut request = get_block_request( &mut sync, FromBlock::Number(MAX_BLOCKS_TO_REQUEST as u64 + best_block_num as u64), @@ -3231,9 +3231,9 @@ mod test { .map(|b| { ( Ok(BlockImportStatus::ImportedUnknown( - b.header().number().clone(), + *b.header().number(), Default::default(), - Some(peer_id1.clone()), + Some(peer_id1), )), b.hash(), ) @@ -3288,7 +3288,7 @@ mod test { let peer_id1 = PeerId::random(); let common_block = blocks[1].clone(); // Connect the node we will sync from - sync.new_peer(peer_id1.clone(), common_block.hash(), *common_block.header().number()) + sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number()) .unwrap(); // Create a "new" header and announce it @@ -3320,7 +3320,7 @@ mod test { let peer_id1 = PeerId::random(); let best_block = blocks[3].clone(); - sync.new_peer(peer_id1.clone(), best_block.hash(), *best_block.header().number()) + sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()) .unwrap(); sync.peers.get_mut(&peer_id1).unwrap().state = PeerSyncState::Available; diff --git a/client/rpc/src/chain/tests.rs b/client/rpc/src/chain/tests.rs index f09da200ff587..7d12458511cfd 100644 --- a/client/rpc/src/chain/tests.rs +++ b/client/rpc/src/chain/tests.rs @@ -40,7 +40,7 @@ async fn should_return_header() { Header { parent_hash: H256::from_low_u64_be(0), number: 0, - state_root: res.state_root.clone(), + state_root: res.state_root, extrinsics_root: "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" .parse() .unwrap(), @@ -54,7 +54,7 @@ async fn should_return_header() { Header { parent_hash: H256::from_low_u64_be(0), number: 0, - state_root: res.state_root.clone(), + state_root: res.state_root, extrinsics_root: "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" .parse() .unwrap(), @@ -93,7 +93,7 @@ async fn should_return_a_block() { header: Header { parent_hash: client.genesis_hash(), number: 1, - state_root: res.block.header.state_root.clone(), + state_root: res.block.header.state_root, extrinsics_root: "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" .parse() .unwrap(), @@ -110,7 +110,7 @@ async fn should_return_a_block() { header: Header { parent_hash: client.genesis_hash(), number: 1, - state_root: res.block.header.state_root.clone(), + state_root: res.block.header.state_root, extrinsics_root: "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" .parse() .unwrap(), diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index f363b621d5bcd..9c4fa84c144c7 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -410,7 +410,7 @@ fn best_containing_with_genesis_block() { assert_eq!( genesis_hash.clone(), - block_on(longest_chain_select.finality_target(genesis_hash.clone(), None)).unwrap(), + block_on(longest_chain_select.finality_target(genesis_hash, None)).unwrap(), ); } @@ -1333,9 +1333,9 @@ fn respects_block_rules() { .block; let params = BlockCheckParams { - hash: block_ok.hash().clone(), + hash: block_ok.hash(), number: 0, - parent_hash: block_ok.header().parent_hash().clone(), + parent_hash: *block_ok.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, import_existing: false, @@ -1349,9 +1349,9 @@ fn respects_block_rules() { let block_not_ok = block_not_ok.build().unwrap().block; let params = BlockCheckParams { - hash: block_not_ok.hash().clone(), + hash: block_not_ok.hash(), number: 0, - parent_hash: block_not_ok.header().parent_hash().clone(), + parent_hash: *block_not_ok.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, import_existing: false, @@ -1372,15 +1372,15 @@ fn respects_block_rules() { let block_ok = block_ok.build().unwrap().block; let params = BlockCheckParams { - hash: block_ok.hash().clone(), + hash: block_ok.hash(), number: 1, - parent_hash: block_ok.header().parent_hash().clone(), + parent_hash: *block_ok.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, import_existing: false, }; if record_only { - fork_rules.push((1, block_ok.hash().clone())); + fork_rules.push((1, block_ok.hash())); } assert_eq!(block_on(client.check_block(params)).unwrap(), ImportResult::imported(false)); @@ -1391,9 +1391,9 @@ fn respects_block_rules() { let block_not_ok = block_not_ok.build().unwrap().block; let params = BlockCheckParams { - hash: block_not_ok.hash().clone(), + hash: block_not_ok.hash(), number: 1, - parent_hash: block_not_ok.header().parent_hash().clone(), + parent_hash: *block_not_ok.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, import_existing: false, @@ -1457,9 +1457,9 @@ fn returns_status_for_pruned_blocks() { let b1 = b1.build().unwrap().block; let check_block_a1 = BlockCheckParams { - hash: a1.hash().clone(), + hash: a1.hash(), number: 0, - parent_hash: a1.header().parent_hash().clone(), + parent_hash: *a1.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, import_existing: false, @@ -1494,9 +1494,9 @@ fn returns_status_for_pruned_blocks() { block_on(client.import_as_final(BlockOrigin::Own, a2.clone())).unwrap(); let check_block_a2 = BlockCheckParams { - hash: a2.hash().clone(), + hash: a2.hash(), number: 1, - parent_hash: a1.header().parent_hash().clone(), + parent_hash: *a1.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, import_existing: false, @@ -1528,9 +1528,9 @@ fn returns_status_for_pruned_blocks() { block_on(client.import_as_final(BlockOrigin::Own, a3.clone())).unwrap(); let check_block_a3 = BlockCheckParams { - hash: a3.hash().clone(), + hash: a3.hash(), number: 2, - parent_hash: a2.header().parent_hash().clone(), + parent_hash: *a2.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, import_existing: false, @@ -1563,9 +1563,9 @@ fn returns_status_for_pruned_blocks() { ); let mut check_block_b1 = BlockCheckParams { - hash: b1.hash().clone(), + hash: b1.hash(), number: 0, - parent_hash: b1.header().parent_hash().clone(), + parent_hash: *b1.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, import_existing: false, diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index c3577a45faf07..a7991269439ce 100644 --- a/client/transaction-pool/benches/basics.rs +++ b/client/transaction-pool/benches/basics.rs @@ -66,7 +66,7 @@ impl ChainApi for TestApi { uxt: ::Extrinsic, ) -> Self::ValidationFuture { let nonce = uxt.transfer().nonce; - let from = uxt.transfer().from.clone(); + let from = uxt.transfer().from; match self.block_id_to_number(at) { Ok(Some(num)) if num > 5 => return ready(Ok(Err(InvalidTransaction::Stale.into()))), @@ -76,7 +76,7 @@ impl ChainApi for TestApi { ready(Ok(Ok(ValidTransaction { priority: 4, requires: if nonce > 1 && self.nonce_dependant { - vec![to_tag(nonce - 1, from.clone())] + vec![to_tag(nonce - 1, from)] } else { vec![] }, diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 4ce7954f8d479..19acbddbe7843 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -641,7 +641,7 @@ mod tests { .unwrap(); // when - block_on(pool.prune_tags(&BlockId::Number(1), vec![vec![0]], vec![hash1.clone()])).unwrap(); + block_on(pool.prune_tags(&BlockId::Number(1), vec![vec![0]], vec![hash1])).unwrap(); // then assert!(pool.validated_pool.is_banned(&hash1)); @@ -793,12 +793,8 @@ mod tests { assert_eq!(pool.validated_pool().status().future, 0); // when - block_on(pool.prune_tags( - &BlockId::Number(2), - vec![vec![0u8]], - vec![watcher.hash().clone()], - )) - .unwrap(); + block_on(pool.prune_tags(&BlockId::Number(2), vec![vec![0u8]], vec![*watcher.hash()])) + .unwrap(); assert_eq!(pool.validated_pool().status().ready, 0); assert_eq!(pool.validated_pool().status().future, 0); diff --git a/client/transaction-pool/src/graph/rotator.rs b/client/transaction-pool/src/graph/rotator.rs index c91c8e407bc0f..47e00a1292155 100644 --- a/client/transaction-pool/src/graph/rotator.rs +++ b/client/transaction-pool/src/graph/rotator.rs @@ -120,7 +120,7 @@ mod tests { let tx = Transaction { data: (), bytes: 1, - hash: hash.clone(), + hash, priority: 5, valid_till: 1, requires: vec![], diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index d6ea5ab8c0625..17c2cfa8a1e06 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -387,7 +387,7 @@ fn should_push_watchers_during_maintenance() { let header_hash = header.hash(); block_on(pool.maintain(block_event(header))); - let event = ChainEvent::Finalized { hash: header_hash.clone(), tree_route: Arc::from(vec![]) }; + let event = ChainEvent::Finalized { hash: header_hash, tree_route: Arc::from(vec![]) }; block_on(pool.maintain(event)); // then @@ -398,24 +398,24 @@ fn should_push_watchers_during_maintenance() { futures::executor::block_on_stream(watcher0).collect::>(), vec![ TransactionStatus::Ready, - TransactionStatus::InBlock(header_hash.clone()), - TransactionStatus::Finalized(header_hash.clone()) + TransactionStatus::InBlock(header_hash), + TransactionStatus::Finalized(header_hash) ], ); assert_eq!( futures::executor::block_on_stream(watcher1).collect::>(), vec![ TransactionStatus::Ready, - TransactionStatus::InBlock(header_hash.clone()), - TransactionStatus::Finalized(header_hash.clone()) + TransactionStatus::InBlock(header_hash), + TransactionStatus::Finalized(header_hash) ], ); assert_eq!( futures::executor::block_on_stream(watcher2).collect::>(), vec![ TransactionStatus::Ready, - TransactionStatus::InBlock(header_hash.clone()), - TransactionStatus::Finalized(header_hash.clone()) + TransactionStatus::InBlock(header_hash), + TransactionStatus::Finalized(header_hash) ], ); } @@ -573,7 +573,7 @@ fn fork_aware_finalization() { for (canon_watcher, h) in canon_watchers { let mut stream = futures::executor::block_on_stream(canon_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(h.clone()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(h))); assert_eq!(stream.next(), Some(TransactionStatus::Finalized(h))); assert_eq!(stream.next(), None); } @@ -581,22 +581,22 @@ fn fork_aware_finalization() { { let mut stream = futures::executor::block_on_stream(from_dave_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(c2.clone()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(c2))); assert_eq!(stream.next(), Some(TransactionStatus::Retracted(c2))); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); assert_eq!(stream.next(), Some(TransactionStatus::InBlock(e1))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(e1.clone()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(e1))); assert_eq!(stream.next(), None); } { let mut stream = futures::executor::block_on_stream(from_bob_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(d2.clone()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(d2))); assert_eq!(stream.next(), Some(TransactionStatus::Retracted(d2))); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); assert_eq!(stream.next(), Some(TransactionStatus::InBlock(e1))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(e1.clone()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(e1))); assert_eq!(stream.next(), None); } } @@ -646,9 +646,9 @@ fn prune_and_retract_tx_at_same_time() { { let mut stream = futures::executor::block_on_stream(watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1.clone()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1))); assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1))); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2.clone()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2))); assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2))); assert_eq!(stream.next(), None); } @@ -781,7 +781,7 @@ fn resubmit_from_retracted_fork() { let e1 = { let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx4.clone())) .expect("1. Imported"); - let header = pool.api().push_block_with_parent(d1.clone(), vec![tx4.clone()], true); + let header = pool.api().push_block_with_parent(d1, vec![tx4.clone()], true); assert_eq!(pool.status().ready, 2); header.hash() }; @@ -790,7 +790,7 @@ fn resubmit_from_retracted_fork() { let f1_header = { let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx5.clone())) .expect("1. Imported"); - let header = pool.api().push_block_with_parent(e1.clone(), vec![tx5.clone()], true); + let header = pool.api().push_block_with_parent(e1, vec![tx5.clone()], true); // Don't announce the block event to the pool directly, because we will // re-org to this block. assert_eq!(pool.status().ready, 3); diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index 85c91b451d351..14265cad5aa76 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -76,7 +76,7 @@ fn vote_works() { Box::new(proposal.clone()), proposal_len )); - assert_ok!(Alliance::vote(Origin::signed(2), hash.clone(), 0, true)); + assert_ok!(Alliance::vote(Origin::signed(2), hash, 0, true)); let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; assert_eq!( @@ -85,12 +85,12 @@ fn vote_works() { record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, - proposal_hash: hash.clone(), + proposal_hash: hash, threshold: 3 })), record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { account: 2, - proposal_hash: hash.clone(), + proposal_hash: hash, voted: true, yes: 1, no: 0, @@ -114,7 +114,7 @@ fn veto_works() { )); // only set_rule/elevate_ally can be veto assert_noop!( - Alliance::veto(Origin::signed(1), hash.clone()), + Alliance::veto(Origin::signed(1), hash), Error::::NotVetoableProposal ); @@ -131,11 +131,11 @@ fn veto_works() { // only founder have veto rights, 3 is fellow assert_noop!( - Alliance::veto(Origin::signed(3), vetoable_hash.clone()), + Alliance::veto(Origin::signed(3), vetoable_hash), Error::::NotFounder ); - assert_ok!(Alliance::veto(Origin::signed(2), vetoable_hash.clone())); + assert_ok!(Alliance::veto(Origin::signed(2), vetoable_hash)); let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; assert_eq!( System::events(), @@ -143,17 +143,17 @@ fn veto_works() { record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, - proposal_hash: hash.clone(), + proposal_hash: hash, threshold: 3 })), record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 1, - proposal_hash: vetoable_hash.clone(), + proposal_hash: vetoable_hash, threshold: 3 })), record(mock::Event::AllianceMotion(AllianceMotionEvent::Disapproved { - proposal_hash: vetoable_hash.clone() + proposal_hash: vetoable_hash })), ] ); @@ -173,16 +173,10 @@ fn close_works() { Box::new(proposal.clone()), proposal_len )); - assert_ok!(Alliance::vote(Origin::signed(1), hash.clone(), 0, true)); - assert_ok!(Alliance::vote(Origin::signed(2), hash.clone(), 0, true)); - assert_ok!(Alliance::vote(Origin::signed(3), hash.clone(), 0, true)); - assert_ok!(Alliance::close( - Origin::signed(1), - hash.clone(), - 0, - proposal_weight, - proposal_len - )); + assert_ok!(Alliance::vote(Origin::signed(1), hash, 0, true)); + assert_ok!(Alliance::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Alliance::vote(Origin::signed(3), hash, 0, true)); + assert_ok!(Alliance::close(Origin::signed(1), hash, 0, proposal_weight, proposal_len)); let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; assert_eq!( @@ -191,40 +185,40 @@ fn close_works() { record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, - proposal_hash: hash.clone(), + proposal_hash: hash, threshold: 3 })), record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { account: 1, - proposal_hash: hash.clone(), + proposal_hash: hash, voted: true, yes: 1, no: 0, })), record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { account: 2, - proposal_hash: hash.clone(), + proposal_hash: hash, voted: true, yes: 2, no: 0, })), record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { account: 3, - proposal_hash: hash.clone(), + proposal_hash: hash, voted: true, yes: 3, no: 0, })), record(mock::Event::AllianceMotion(AllianceMotionEvent::Closed { - proposal_hash: hash.clone(), + proposal_hash: hash, yes: 3, no: 0, })), record(mock::Event::AllianceMotion(AllianceMotionEvent::Approved { - proposal_hash: hash.clone() + proposal_hash: hash })), record(mock::Event::AllianceMotion(AllianceMotionEvent::Executed { - proposal_hash: hash.clone(), + proposal_hash: hash, result: Err(DispatchError::BadOrigin), })) ] diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 67690e2b28ec1..0fd4dd3281516 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -115,11 +115,11 @@ thread_local! { pub struct TestFreezer; impl FrozenBalance for TestFreezer { fn frozen_balance(asset: u32, who: &u64) -> Option { - FROZEN.with(|f| f.borrow().get(&(asset, who.clone())).cloned()) + FROZEN.with(|f| f.borrow().get(&(asset, *who)).cloned()) } fn died(asset: u32, who: &u64) { - HOOKS.with(|h| h.borrow_mut().push(Hook::Died(asset, who.clone()))); + HOOKS.with(|h| h.borrow_mut().push(Hook::Died(asset, *who))); // Sanity check: dead accounts have no balance. assert!(Assets::balance(asset, *who).is_zero()); } diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 1ddf3888d3c96..54643001ad6fc 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -333,7 +333,7 @@ pub mod pallet { ); swap.action.cancel(&swap.source); - PendingSwaps::::remove(&target, hashed_proof.clone()); + PendingSwaps::::remove(&target, hashed_proof); Self::deposit_event(Event::SwapCancelled { account: target, proof: hashed_proof }); diff --git a/frame/atomic-swap/src/tests.rs b/frame/atomic-swap/src/tests.rs index 2352e7852d090..688d3ff17f786 100644 --- a/frame/atomic-swap/src/tests.rs +++ b/frame/atomic-swap/src/tests.rs @@ -102,7 +102,7 @@ fn two_party_successful_swap() { AtomicSwap::create_swap( Origin::signed(A), B, - hashed_proof.clone(), + hashed_proof, BalanceSwapAction::new(50), 1000, ) @@ -117,7 +117,7 @@ fn two_party_successful_swap() { AtomicSwap::create_swap( Origin::signed(B), A, - hashed_proof.clone(), + hashed_proof, BalanceSwapAction::new(75), 1000, ) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 5ca74e681e5dd..3b186236dd0fa 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1416,12 +1416,7 @@ mod tests { loader.counter += 1; loader.map.insert( hash, - MockExecutable { - func: Rc::new(f), - func_type, - code_hash: hash.clone(), - refcount: 1, - }, + MockExecutable { func: Rc::new(f), func_type, code_hash: hash, refcount: 1 }, ); hash }) @@ -2189,7 +2184,6 @@ mod tests { let dummy_ch = MockLoader::insert(Call, |_, _| exec_success()); let instantiated_contract_address = Rc::new(RefCell::new(None::>)); let instantiator_ch = MockLoader::insert(Call, { - let dummy_ch = dummy_ch.clone(); let instantiated_contract_address = Rc::clone(&instantiated_contract_address); move |ctx, _| { // Instantiate a contract and save it's address in `instantiated_contract_address`. @@ -2252,7 +2246,6 @@ mod tests { fn instantiation_traps() { let dummy_ch = MockLoader::insert(Constructor, |_, _| Err("It's a trap!".into())); let instantiator_ch = MockLoader::insert(Call, { - let dummy_ch = dummy_ch.clone(); move |ctx, _| { // Instantiate a contract and save it's address in `instantiated_contract_address`. assert_matches!( diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 30417d8544489..204908cc4a989 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -139,7 +139,7 @@ impl TestExtension { } fn last_seen_inputs() -> (u32, u32, u32, u32) { - TEST_EXTENSION.with(|e| e.borrow().last_seen_inputs.clone()) + TEST_EXTENSION.with(|e| e.borrow().last_seen_inputs) } } @@ -3478,8 +3478,8 @@ fn set_code_hash() { phase: Phase::Initialization, event: Event::Contracts(crate::Event::ContractCodeUpdated { contract: contract_addr.clone(), - new_code_hash: new_code_hash.clone(), - old_code_hash: code_hash.clone(), + new_code_hash, + old_code_hash: code_hash, }), topics: vec![], }, diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 3dd5da187b258..02a360fe86b45 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -403,7 +403,7 @@ mod tests { salt: &[u8], ) -> Result<(AccountIdOf, ExecReturnValue), ExecError> { self.instantiates.push(InstantiateEntry { - code_hash: code_hash.clone(), + code_hash, value, data: data.to_vec(), gas_left: gas_limit, @@ -541,7 +541,7 @@ mod tests { signature: &[u8; 65], message_hash: &[u8; 32], ) -> Result<[u8; 33], ()> { - self.ecdsa_recover.borrow_mut().push((signature.clone(), message_hash.clone())); + self.ecdsa_recover.borrow_mut().push((*signature, *message_hash)); Ok([3; 33]) } fn contract_info(&mut self) -> &mut crate::ContractInfo { diff --git a/frame/democracy/src/tests/external_proposing.rs b/frame/democracy/src/tests/external_proposing.rs index 5d4a9f2a7cbfc..6ac34a38723ce 100644 --- a/frame/democracy/src/tests/external_proposing.rs +++ b/frame/democracy/src/tests/external_proposing.rs @@ -30,7 +30,7 @@ fn veto_external_works() { assert!(>::exists()); let h = set_balance_proposal_hash_and_note(2); - assert_ok!(Democracy::veto_external(Origin::signed(3), h.clone())); + assert_ok!(Democracy::veto_external(Origin::signed(3), h)); // cancelled. assert!(!>::exists()); // fails - same proposal can't be resubmitted. @@ -55,13 +55,10 @@ fn veto_external_works() { assert!(>::exists()); // 3 can't veto the same thing twice. - assert_noop!( - Democracy::veto_external(Origin::signed(3), h.clone()), - Error::::AlreadyVetoed - ); + assert_noop!(Democracy::veto_external(Origin::signed(3), h), Error::::AlreadyVetoed); // 4 vetoes. - assert_ok!(Democracy::veto_external(Origin::signed(4), h.clone())); + assert_ok!(Democracy::veto_external(Origin::signed(4), h)); // cancelled again. assert!(!>::exists()); diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs index db06696ca5c95..65e5466857dc1 100644 --- a/frame/democracy/src/tests/public_proposals.rs +++ b/frame/democracy/src/tests/public_proposals.rs @@ -115,7 +115,7 @@ fn blacklisting_should_work() { assert_ok!(propose_set_balance_and_note(1, 2, 2)); assert_ok!(propose_set_balance_and_note(1, 4, 4)); - assert_noop!(Democracy::blacklist(Origin::signed(1), hash.clone(), None), BadOrigin); + assert_noop!(Democracy::blacklist(Origin::signed(1), hash, None), BadOrigin); assert_ok!(Democracy::blacklist(Origin::root(), hash, None)); assert_eq!(Democracy::backing_for(0), None); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index ffd1c6ab4de9c..03d41fa2af40f 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1342,9 +1342,7 @@ mod tests { self } pub fn genesis_members(mut self, members: Vec<(u64, u64)>) -> Self { - MEMBERS.with(|m| { - *m.borrow_mut() = members.iter().map(|(m, _)| m.clone()).collect::>() - }); + MEMBERS.with(|m| *m.borrow_mut() = members.iter().map(|(m, _)| *m).collect::>()); self.genesis_members = members; self } @@ -1359,8 +1357,7 @@ mod tests { pub fn build_and_execute(self, test: impl FnOnce() -> ()) { sp_tracing::try_init_simple(); MEMBERS.with(|m| { - *m.borrow_mut() = - self.genesis_members.iter().map(|(m, _)| m.clone()).collect::>() + *m.borrow_mut() = self.genesis_members.iter().map(|(m, _)| *m).collect::>() }); let mut ext: sp_io::TestExternalities = GenesisConfig { balances: pallet_balances::GenesisConfig:: { diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index e5bd9fabc629b..703220e64fa8a 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -253,10 +253,9 @@ fn should_submit_unsigned_transaction_on_chain_for_any_account() { ) .unwrap(); - let public_key = SyncCryptoStore::sr25519_public_keys(&keystore, crate::crypto::Public::ID) + let public_key = *SyncCryptoStore::sr25519_public_keys(&keystore, crate::crypto::Public::ID) .get(0) - .unwrap() - .clone(); + .unwrap(); let mut t = sp_io::TestExternalities::default(); t.register_extension(OffchainWorkerExt::new(offchain)); @@ -313,10 +312,9 @@ fn should_submit_unsigned_transaction_on_chain_for_all_accounts() { ) .unwrap(); - let public_key = SyncCryptoStore::sr25519_public_keys(&keystore, crate::crypto::Public::ID) + let public_key = *SyncCryptoStore::sr25519_public_keys(&keystore, crate::crypto::Public::ID) .get(0) - .unwrap() - .clone(); + .unwrap(); let mut t = sp_io::TestExternalities::default(); t.register_extension(OffchainWorkerExt::new(offchain)); diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index d67d06e1bce05..5d37e32e4d8a4 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -221,14 +221,7 @@ fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() { let data = call.encode(); let hash = blake2_256(&data); - assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - None, - hash.clone(), - 0 - )); + assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); assert_eq!(Balances::free_balance(1), 1); assert_eq!(Balances::reserved_balance(1), 4); @@ -266,31 +259,18 @@ fn cancel_multisig_returns_deposit() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); - assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - None, - hash.clone(), - 0 - )); + assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); assert_ok!(Multisig::approve_as_multi( Origin::signed(2), 3, vec![1, 3], Some(now()), - hash.clone(), + hash, 0 )); assert_eq!(Balances::free_balance(1), 6); assert_eq!(Balances::reserved_balance(1), 4); - assert_ok!(Multisig::cancel_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - now(), - hash.clone() - ),); + assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash),); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::reserved_balance(1), 0); }); @@ -308,14 +288,7 @@ fn timepoint_checking_works() { let hash = blake2_256(&call); assert_noop!( - Multisig::approve_as_multi( - Origin::signed(2), - 2, - vec![1, 3], - Some(now()), - hash.clone(), - 0 - ), + Multisig::approve_as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), hash, 0), Error::::UnexpectedTimepoint, ); @@ -424,20 +397,13 @@ fn multisig_3_of_3_works() { let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); - assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - None, - hash.clone(), - 0 - )); + assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); assert_ok!(Multisig::approve_as_multi( Origin::signed(2), 3, vec![1, 3], Some(now()), - hash.clone(), + hash, 0 )); assert_eq!(Balances::free_balance(6), 0); @@ -460,33 +426,20 @@ fn cancel_multisig_works() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); - assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - None, - hash.clone(), - 0 - )); + assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); assert_ok!(Multisig::approve_as_multi( Origin::signed(2), 3, vec![1, 3], Some(now()), - hash.clone(), + hash, 0 )); assert_noop!( - Multisig::cancel_as_multi(Origin::signed(2), 3, vec![1, 3], now(), hash.clone()), + Multisig::cancel_as_multi(Origin::signed(2), 3, vec![1, 3], now(), hash), Error::::NotOwner, ); - assert_ok!(Multisig::cancel_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - now(), - hash.clone() - ),); + assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash),); }); } @@ -510,20 +463,14 @@ fn cancel_multisig_with_call_storage_works() { 3, vec![1, 3], Some(now()), - hash.clone(), + hash, 0 )); assert_noop!( - Multisig::cancel_as_multi(Origin::signed(2), 3, vec![1, 3], now(), hash.clone()), + Multisig::cancel_as_multi(Origin::signed(2), 3, vec![1, 3], now(), hash), Error::::NotOwner, ); - assert_ok!(Multisig::cancel_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - now(), - hash.clone() - ),); + assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash),); assert_eq!(Balances::free_balance(1), 10); }); } @@ -533,14 +480,7 @@ fn cancel_multisig_with_alt_call_storage_works() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); - assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - None, - hash.clone(), - 0 - )); + assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); assert_eq!(Balances::free_balance(1), 6); assert_ok!(Multisig::as_multi( Origin::signed(2), @@ -770,23 +710,9 @@ fn duplicate_approvals_are_ignored() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); - assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), - 2, - vec![2, 3], - None, - hash.clone(), - 0 - )); + assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 2, vec![2, 3], None, hash, 0)); assert_noop!( - Multisig::approve_as_multi( - Origin::signed(1), - 2, - vec![2, 3], - Some(now()), - hash.clone(), - 0 - ), + Multisig::approve_as_multi(Origin::signed(1), 2, vec![2, 3], Some(now()), hash, 0), Error::::AlreadyApproved, ); assert_ok!(Multisig::approve_as_multi( @@ -794,18 +720,11 @@ fn duplicate_approvals_are_ignored() { 2, vec![1, 3], Some(now()), - hash.clone(), + hash, 0 )); assert_noop!( - Multisig::approve_as_multi( - Origin::signed(3), - 2, - vec![1, 2], - Some(now()), - hash.clone(), - 0 - ), + Multisig::approve_as_multi(Origin::signed(3), 2, vec![1, 2], Some(now()), hash, 0), Error::::AlreadyApproved, ); }); @@ -822,7 +741,7 @@ fn multisig_1_of_3_works() { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_noop!( - Multisig::approve_as_multi(Origin::signed(1), 1, vec![2, 3], None, hash.clone(), 0), + Multisig::approve_as_multi(Origin::signed(1), 1, vec![2, 3], None, hash, 0), Error::::MinimumThreshold, ); assert_noop!( @@ -906,20 +825,13 @@ fn multisig_handles_no_preimage_after_all_approve() { let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); - assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - None, - hash.clone(), - 0 - )); + assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); assert_ok!(Multisig::approve_as_multi( Origin::signed(2), 3, vec![1, 3], Some(now()), - hash.clone(), + hash, 0 )); assert_ok!(Multisig::approve_as_multi( @@ -927,7 +839,7 @@ fn multisig_handles_no_preimage_after_all_approve() { 3, vec![1, 2], Some(now()), - hash.clone(), + hash, 0 )); assert_eq!(Balances::free_balance(6), 0); diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 4c2c902846a85..6cc589ceb08bd 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -224,7 +224,7 @@ frame_benchmarking::benchmarks! { origin_weight ); - let max_additional = scenario.dest_weight.clone() - origin_weight; + let max_additional = scenario.dest_weight - origin_weight; let joiner_free = CurrencyOf::::minimum_balance() + max_additional; let joiner: T::AccountId @@ -243,7 +243,7 @@ frame_benchmarking::benchmarks! { bond_extra_transfer { let origin_weight = min_create_bond::() * 2u32.into(); let scenario = ListScenario::::new(origin_weight, true)?; - let extra = scenario.dest_weight.clone() - origin_weight; + let extra = scenario.dest_weight - origin_weight; // creator of the src pool will bond-extra, bumping itself to dest bag. @@ -258,7 +258,7 @@ frame_benchmarking::benchmarks! { bond_extra_reward { let origin_weight = min_create_bond::() * 2u32.into(); let scenario = ListScenario::::new(origin_weight, true)?; - let extra = (scenario.dest_weight.clone() - origin_weight).max(CurrencyOf::::minimum_balance()); + let extra = (scenario.dest_weight - origin_weight).max(CurrencyOf::::minimum_balance()); // transfer exactly `extra` to the depositor of the src pool (1), let reward_account1 = Pools::::create_reward_account(1); @@ -306,7 +306,7 @@ frame_benchmarking::benchmarks! { // significantly higher than the first position in a list (e.g. the first bag threshold). let origin_weight = min_create_bond::() * 200u32.into(); let scenario = ListScenario::::new(origin_weight, false)?; - let amount = origin_weight - scenario.dest_weight.clone(); + let amount = origin_weight - scenario.dest_weight; let scenario = scenario.add_joiner(amount); let member_id = scenario.origin1_member.unwrap().clone(); @@ -316,7 +316,7 @@ frame_benchmarking::benchmarks! { verify { let bonded_after = T::StakingInterface::active_stake(&scenario.origin1).unwrap(); // We at least went down to the destination bag - assert!(bonded_after <= scenario.dest_weight.clone()); + assert!(bonded_after <= scenario.dest_weight); let member = PoolMembers::::get( &member_id ) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 09f1746b8e5ba..4a31048fb8d8b 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -491,7 +491,7 @@ impl PoolMember { true } else { removed_points - .try_insert(*e, p.clone()) + .try_insert(*e, *p) .expect("source map is bounded, this is a subset, will be bounded; qed"); false } @@ -1920,10 +1920,7 @@ pub mod pallet { ); ReversePoolIdLookup::::insert(bonded_pool.bonded_account(), pool_id); - Self::deposit_event(Event::::Created { - depositor: who.clone(), - pool_id: pool_id.clone(), - }); + Self::deposit_event(Event::::Created { depositor: who.clone(), pool_id }); Self::deposit_event(Event::::Bonded { member: who, diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index f2abfe29dfbf7..243e5489b5445 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -244,7 +244,7 @@ pub mod v2 { }, }; - total_value_locked += bonded_pool.points_to_balance(points.clone()); + total_value_locked += bonded_pool.points_to_balance(*points); let portion = Perbill::from_rational(*points, bonded_pool.points); let last_claim = portion * accumulated_reward; diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index a0807f1d3d0b6..72acee1e0347e 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -543,7 +543,7 @@ fn anonymous_works() { let anon = Proxy::anonymous_account(&1, &ProxyType::Any, 0, None); System::assert_last_event( ProxyEvent::AnonymousCreated { - anonymous: anon.clone(), + anonymous: anon, who: 1, proxy_type: ProxyType::Any, disambiguation_index: 0, diff --git a/frame/remark/src/tests.rs b/frame/remark/src/tests.rs index eac006054c1d5..580b64cc64997 100644 --- a/frame/remark/src/tests.rs +++ b/frame/remark/src/tests.rs @@ -28,7 +28,7 @@ fn generates_event() { let caller = 1; let data = vec![0u8; 100]; System::set_block_number(System::block_number() + 1); //otherwise event won't be registered. - assert_ok!(Remark::::store(RawOrigin::Signed(caller.clone()).into(), data.clone(),)); + assert_ok!(Remark::::store(RawOrigin::Signed(caller).into(), data.clone(),)); let events = System::events(); // this one we create as we expect it let system_event: ::Event = Event::Stored { @@ -50,7 +50,7 @@ fn does_not_store_empty() { let data = vec![]; System::set_block_number(System::block_number() + 1); //otherwise event won't be registered. assert_noop!( - Remark::::store(RawOrigin::Signed(caller.clone()).into(), data.clone(),), + Remark::::store(RawOrigin::Signed(caller).into(), data.clone(),), Error::::Empty ); assert!(System::events().is_empty()); diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index d2a795cb19fa4..d03e13da4747a 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -47,7 +47,7 @@ fn scheduling_with_preimages_works() { new_test_ext().execute_with(|| { let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); let hash = ::Hashing::hash_of(&call); - let hashed = MaybeHashed::Hash(hash.clone()); + let hashed = MaybeHashed::Hash(hash); assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); assert!(Preimage::preimage_requested(&hash)); @@ -67,7 +67,7 @@ fn scheduling_with_preimage_postpones_correctly() { new_test_ext().execute_with(|| { let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); let hash = ::Hashing::hash_of(&call); - let hashed = MaybeHashed::Hash(hash.clone()); + let hashed = MaybeHashed::Hash(hash); assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); assert!(Preimage::preimage_requested(&hash)); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index d9dc97f9c1127..7911428b3337c 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -826,7 +826,7 @@ pub(crate) fn on_offence_now( pub(crate) fn add_slash(who: &AccountId) { on_offence_now( &[OffenceDetails { - offender: (who.clone(), Staking::eras_stakers(active_era(), who.clone())), + offender: (*who, Staking::eras_stakers(active_era(), *who)), reporters: vec![], }], &[Perbill::from_percent(10)], diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index d14d8c4a75f2e..485a9dc3ae66a 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1082,10 +1082,7 @@ fn validator_payment_prefs_work() { // This test will focus on validator payment. ExtBuilder::default().build_and_execute(|| { let commission = Perbill::from_percent(40); - >::insert( - &11, - ValidatorPrefs { commission: commission.clone(), ..Default::default() }, - ); + >::insert(&11, ValidatorPrefs { commission, ..Default::default() }); // Reward controller so staked ratio doesn't change. >::insert(&11, RewardDestination::Controller); diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 353bc93e5ab94..9b0172bf97aa2 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -1253,7 +1253,7 @@ mod mock { weight_sum += StateTrieMigration::on_initialize(System::block_number()); - root = System::finalize().state_root().clone(); + root = *System::finalize().state_root(); System::on_finalize(System::block_number()); } (root, weight_sum) diff --git a/frame/timestamp/src/mock.rs b/frame/timestamp/src/mock.rs index 9536414c54db6..0da94deb7112a 100644 --- a/frame/timestamp/src/mock.rs +++ b/frame/timestamp/src/mock.rs @@ -101,7 +101,7 @@ pub(crate) fn clear_captured_moment() { } pub(crate) fn get_captured_moment() -> Option { - CAPTURED_MOMENT.with(|x| x.borrow().clone()) + CAPTURED_MOMENT.with(|x| *x.borrow()) } pub(crate) fn new_test_ext() -> TestExternalities { diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index 194ecc60d9890..bcaa99285d2e7 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -256,10 +256,10 @@ fn report_awesome_and_tip_works() { ); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(10), h.clone(), 10)); - assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10)); - assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10)); - assert_noop!(Tips::tip(Origin::signed(9), h.clone(), 10), BadOrigin); + assert_ok!(Tips::tip(Origin::signed(10), h, 10)); + assert_ok!(Tips::tip(Origin::signed(11), h, 10)); + assert_ok!(Tips::tip(Origin::signed(12), h, 10)); + assert_noop!(Tips::tip(Origin::signed(9), h, 10), BadOrigin); System::set_block_number(2); assert_ok!(Tips::close_tip(Origin::signed(100), h.into())); assert_eq!(Balances::reserved_balance(0), 0); @@ -276,9 +276,9 @@ fn report_awesome_from_beneficiary_and_tip_works() { assert_eq!(Balances::reserved_balance(0), 12); assert_eq!(Balances::free_balance(0), 88); let h = BlakeTwo256::hash_of(&(BlakeTwo256::hash(b"awesome.dot"), 0u128)); - assert_ok!(Tips::tip(Origin::signed(10), h.clone(), 10)); - assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10)); - assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10)); + assert_ok!(Tips::tip(Origin::signed(10), h, 10)); + assert_ok!(Tips::tip(Origin::signed(11), h, 10)); + assert_ok!(Tips::tip(Origin::signed(12), h, 10)); System::set_block_number(2); assert_ok!(Tips::close_tip(Origin::signed(100), h.into())); assert_eq!(Balances::reserved_balance(0), 0); @@ -300,11 +300,11 @@ fn close_tip_works() { assert_eq!(last_event(), TipEvent::NewTip { tip_hash: h }); - assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10)); + assert_ok!(Tips::tip(Origin::signed(11), h, 10)); assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::::StillOpen); - assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10)); + assert_ok!(Tips::tip(Origin::signed(12), h, 10)); assert_eq!(last_event(), TipEvent::TipClosing { tip_hash: h }); @@ -340,10 +340,10 @@ fn slash_tip_works() { assert_eq!(last_event(), TipEvent::NewTip { tip_hash: h }); // can't remove from any origin - assert_noop!(Tips::slash_tip(Origin::signed(0), h.clone()), BadOrigin); + assert_noop!(Tips::slash_tip(Origin::signed(0), h), BadOrigin); // can remove from root. - assert_ok!(Tips::slash_tip(Origin::root(), h.clone())); + assert_ok!(Tips::slash_tip(Origin::root(), h)); assert_eq!(last_event(), TipEvent::TipSlashed { tip_hash: h, finder: 0, deposit: 12 }); // tipper slashed @@ -359,11 +359,11 @@ fn retract_tip_works() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(10), h.clone(), 10)); - assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10)); - assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10)); - assert_noop!(Tips::retract_tip(Origin::signed(10), h.clone()), Error::::NotFinder); - assert_ok!(Tips::retract_tip(Origin::signed(0), h.clone())); + assert_ok!(Tips::tip(Origin::signed(10), h, 10)); + assert_ok!(Tips::tip(Origin::signed(11), h, 10)); + assert_ok!(Tips::tip(Origin::signed(12), h, 10)); + assert_noop!(Tips::retract_tip(Origin::signed(10), h), Error::::NotFinder); + assert_ok!(Tips::retract_tip(Origin::signed(0), h)); System::set_block_number(2); assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::::UnknownTip); @@ -371,10 +371,10 @@ fn retract_tip_works() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10)); - assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10)); - assert_noop!(Tips::retract_tip(Origin::signed(0), h.clone()), Error::::NotFinder); - assert_ok!(Tips::retract_tip(Origin::signed(10), h.clone())); + assert_ok!(Tips::tip(Origin::signed(11), h, 10)); + assert_ok!(Tips::tip(Origin::signed(12), h, 10)); + assert_noop!(Tips::retract_tip(Origin::signed(0), h), Error::::NotFinder); + assert_ok!(Tips::retract_tip(Origin::signed(10), h)); System::set_block_number(2); assert_noop!(Tips::close_tip(Origin::signed(10), h.into()), Error::::UnknownTip); }); @@ -386,8 +386,8 @@ fn tip_median_calculation_works() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 0)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10)); - assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 1000000)); + assert_ok!(Tips::tip(Origin::signed(11), h, 10)); + assert_ok!(Tips::tip(Origin::signed(12), h, 1000000)); System::set_block_number(2); assert_ok!(Tips::close_tip(Origin::signed(0), h.into())); assert_eq!(Balances::free_balance(3), 10); @@ -400,13 +400,13 @@ fn tip_changing_works() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10000)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 10000)); - assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 10000)); - assert_ok!(Tips::tip(Origin::signed(13), h.clone(), 0)); - assert_ok!(Tips::tip(Origin::signed(14), h.clone(), 0)); - assert_ok!(Tips::tip(Origin::signed(12), h.clone(), 1000)); - assert_ok!(Tips::tip(Origin::signed(11), h.clone(), 100)); - assert_ok!(Tips::tip(Origin::signed(10), h.clone(), 10)); + assert_ok!(Tips::tip(Origin::signed(11), h, 10000)); + assert_ok!(Tips::tip(Origin::signed(12), h, 10000)); + assert_ok!(Tips::tip(Origin::signed(13), h, 0)); + assert_ok!(Tips::tip(Origin::signed(14), h, 0)); + assert_ok!(Tips::tip(Origin::signed(12), h, 1000)); + assert_ok!(Tips::tip(Origin::signed(11), h, 100)); + assert_ok!(Tips::tip(Origin::signed(10), h, 10)); System::set_block_number(2); assert_ok!(Tips::close_tip(Origin::signed(0), h.into())); assert_eq!(Balances::free_balance(3), 10); @@ -595,10 +595,10 @@ fn report_awesome_and_tip_works_second_instance() { assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); let h = tip_hash(); - assert_ok!(Tips1::tip(Origin::signed(10), h.clone(), 10)); - assert_ok!(Tips1::tip(Origin::signed(11), h.clone(), 10)); - assert_ok!(Tips1::tip(Origin::signed(12), h.clone(), 10)); - assert_noop!(Tips1::tip(Origin::signed(9), h.clone(), 10), BadOrigin); + assert_ok!(Tips1::tip(Origin::signed(10), h, 10)); + assert_ok!(Tips1::tip(Origin::signed(11), h, 10)); + assert_ok!(Tips1::tip(Origin::signed(12), h, 10)); + assert_noop!(Tips1::tip(Origin::signed(9), h, 10), BadOrigin); System::set_block_number(2); diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index ff65c0d2735fd..707f7d8a22065 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -1042,8 +1042,8 @@ mod tests { &Ok(()) )); assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); - assert_eq!(FEE_UNBALANCED_AMOUNT.with(|a| a.borrow().clone()), 5 + 5 + 10); - assert_eq!(TIP_UNBALANCED_AMOUNT.with(|a| a.borrow().clone()), 0); + assert_eq!(FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 5 + 5 + 10); + assert_eq!(TIP_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 0); FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() = 0); @@ -1060,8 +1060,8 @@ mod tests { &Ok(()) )); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 50 - 5); - assert_eq!(FEE_UNBALANCED_AMOUNT.with(|a| a.borrow().clone()), 5 + 10 + 50); - assert_eq!(TIP_UNBALANCED_AMOUNT.with(|a| a.borrow().clone()), 5); + assert_eq!(FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 5 + 10 + 50); + assert_eq!(TIP_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 5); }); } diff --git a/frame/transaction-storage/src/tests.rs b/frame/transaction-storage/src/tests.rs index 8825890ae67a2..4f5ce1c4b654d 100644 --- a/frame/transaction-storage/src/tests.rs +++ b/frame/transaction-storage/src/tests.rs @@ -31,11 +31,11 @@ fn discards_data() { run_to_block(1, || None); let caller = 1; assert_ok!(TransactionStorage::::store( - RawOrigin::Signed(caller.clone()).into(), + RawOrigin::Signed(caller).into(), vec![0u8; 2000 as usize] )); assert_ok!(TransactionStorage::::store( - RawOrigin::Signed(caller.clone()).into(), + RawOrigin::Signed(caller).into(), vec![0u8; 2000 as usize] )); let proof_provider = || { @@ -74,7 +74,7 @@ fn burns_fee() { Error::::InsufficientFunds, ); assert_ok!(TransactionStorage::::store( - RawOrigin::Signed(caller.clone()).into(), + RawOrigin::Signed(caller).into(), vec![0u8; 2000 as usize] )); assert_eq!(Balances::free_balance(1), 1_000_000_000 - 2000 * 2 - 200); @@ -87,7 +87,7 @@ fn checks_proof() { run_to_block(1, || None); let caller = 1; assert_ok!(TransactionStorage::::store( - RawOrigin::Signed(caller.clone()).into(), + RawOrigin::Signed(caller).into(), vec![0u8; MAX_DATA_SIZE as usize] )); run_to_block(10, || None); @@ -119,13 +119,13 @@ fn renews_data() { run_to_block(1, || None); let caller = 1; assert_ok!(TransactionStorage::::store( - RawOrigin::Signed(caller.clone()).into(), + RawOrigin::Signed(caller).into(), vec![0u8; 2000] )); let info = BlockTransactions::::get().last().unwrap().clone(); run_to_block(6, || None); assert_ok!(TransactionStorage::::renew( - RawOrigin::Signed(caller.clone()).into(), + RawOrigin::Signed(caller).into(), 1, // block 0, // transaction )); diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index dcbb1f27973d7..e9169bdd963b4 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -234,15 +234,11 @@ impl, I: 'static> Pallet { ensure!(details.owner == sender, Error::::NoPermission); if let Some(ref price) = price { - ItemPriceOf::::insert( - &collection, - &item, - (price.clone(), whitelisted_buyer.clone()), - ); + ItemPriceOf::::insert(&collection, &item, (price, whitelisted_buyer.clone())); Self::deposit_event(Event::ItemPriceSet { collection, item, - price: price.clone(), + price: *price, whitelisted_buyer, }); } else { diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 968bda6885d0d..2ac88c7e6c04f 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -148,10 +148,8 @@ fn record_proof_works() { .build_with_longest_chain(); let block_id = BlockId::Number(client.chain_info().best_number); - let storage_root = futures::executor::block_on(longest_chain.best_chain()) - .unwrap() - .state_root() - .clone(); + let storage_root = + *futures::executor::block_on(longest_chain.best_chain()).unwrap().state_root(); let runtime_code = sp_core::traits::RuntimeCode { code_fetcher: &sp_core::traits::WrappedRuntimeCode( diff --git a/primitives/npos-elections/fuzzer/src/reduce.rs b/primitives/npos-elections/fuzzer/src/reduce.rs index 605f2d6081a6f..602467a343884 100644 --- a/primitives/npos-elections/fuzzer/src/reduce.rs +++ b/primitives/npos-elections/fuzzer/src/reduce.rs @@ -90,7 +90,7 @@ fn generate_random_phragmen_assignment( let target = targets_to_chose_from.remove(rng.gen_range(0..targets_to_chose_from.len())); if winners.iter().all(|w| *w != target) { - winners.push(target.clone()); + winners.push(target); } (target, rng.gen_range(1 * KSM..100 * KSM)) }) diff --git a/primitives/npos-elections/src/mock.rs b/primitives/npos-elections/src/mock.rs index dd85ce9b6dfae..5a06e3f3c88ca 100644 --- a/primitives/npos-elections/src/mock.rs +++ b/primitives/npos-elections/src/mock.rs @@ -92,7 +92,7 @@ where .into_iter() .enumerate() .map(|(idx, who)| { - c_idx_cache.insert(who.clone(), idx); + c_idx_cache.insert(who, idx); _Candidate { who, ..Default::default() } }) .collect::>>(); @@ -103,7 +103,7 @@ where for v in votes { if let Some(idx) = c_idx_cache.get(&v) { candidates[*idx].approval_stake = candidates[*idx].approval_stake + voter_stake; - edges.push(_Edge { who: v.clone(), candidate_index: *idx, ..Default::default() }); + edges.push(_Edge { who: v, candidate_index: *idx, ..Default::default() }); } } _Voter { who, edges, budget: voter_stake, load: 0f64 } @@ -143,21 +143,21 @@ where } } - elected_candidates.push((winner.who.clone(), winner.approval_stake as ExtendedBalance)); + elected_candidates.push((winner.who, winner.approval_stake as ExtendedBalance)); } else { break } } for n in &mut voters { - let mut assignment = (n.who.clone(), vec![]); + let mut assignment = (n.who, vec![]); for e in &mut n.edges { if let Some(c) = elected_candidates.iter().cloned().map(|(c, _)| c).find(|c| *c == e.who) { if c != n.who { let ratio = e.load / n.load; - assignment.1.push((e.who.clone(), ratio)); + assignment.1.push((e.who, ratio)); } } } @@ -321,7 +321,7 @@ pub(crate) fn run_and_compare( candidates.clone(), voters .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, ) @@ -368,7 +368,7 @@ pub(crate) fn build_support_map_float( let mut supports = <_SupportMap>::new(); result.winners.iter().map(|(e, _)| (e, stake_of(e) as f64)).for_each(|(e, s)| { let item = _Support { own: s, total: s, ..Default::default() }; - supports.insert(e.clone(), item); + supports.insert(*e, item); }); for (n, assignment) in result.assignments.iter_mut() { @@ -377,7 +377,7 @@ pub(crate) fn build_support_map_float( let other_stake = nominator_stake * *r; if let Some(support) = supports.get_mut(c) { support.total = support.total + other_stake; - support.others.push((n.clone(), other_stake)); + support.others.push((*n, other_stake)); } *r = other_stake; } diff --git a/primitives/npos-elections/src/pjr.rs b/primitives/npos-elections/src/pjr.rs index 914834fbb2aef..fd7c8ef539241 100644 --- a/primitives/npos-elections/src/pjr.rs +++ b/primitives/npos-elections/src/pjr.rs @@ -481,7 +481,7 @@ mod tests { assert_eq!( candidates .iter() - .map(|c| (c.borrow().who.clone(), c.borrow().elected, c.borrow().backed_stake)) + .map(|c| (c.borrow().who, c.borrow().elected, c.borrow().backed_stake)) .collect::>(), vec![(10, false, 0), (20, true, 15), (30, false, 0), (40, true, 15)], ); diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index 5b88889201b31..6f2e4fca77115 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -233,7 +233,7 @@ fn phragmen_poc_works() { candidates, voters .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, ) @@ -289,7 +289,7 @@ fn phragmen_poc_works_with_balancing() { candidates, voters .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), Some(config), ) @@ -376,7 +376,7 @@ fn phragmen_accuracy_on_large_scale_only_candidates() { candidates.clone(), auto_generate_self_voters(&candidates) .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, ) @@ -407,7 +407,7 @@ fn phragmen_accuracy_on_large_scale_voters_and_candidates() { candidates, voters .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, ) @@ -439,7 +439,7 @@ fn phragmen_accuracy_on_small_scale_self_vote() { candidates, voters .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, ) @@ -469,7 +469,7 @@ fn phragmen_accuracy_on_small_scale_no_self_vote() { candidates, voters .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, ) @@ -505,7 +505,7 @@ fn phragmen_large_scale_test() { candidates, voters .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, ) @@ -532,7 +532,7 @@ fn phragmen_large_scale_test_2() { candidates, voters .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, ) @@ -601,7 +601,7 @@ fn elect_has_no_entry_barrier() { candidates, voters .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, ) @@ -622,7 +622,7 @@ fn phragmen_self_votes_should_be_kept() { candidates, voters .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, ) @@ -872,30 +872,15 @@ mod score { let claim = [12488167277027543u128, 5559266368032409496, 118700736389524721358337889258988054]; - assert_eq!( - is_score_better(claim.clone(), initial.clone(), Perbill::from_rational(1u32, 10_000),), - true, - ); + assert_eq!(is_score_better(claim, initial, Perbill::from_rational(1u32, 10_000),), true,); - assert_eq!( - is_score_better(claim.clone(), initial.clone(), Perbill::from_rational(2u32, 10_000),), - true, - ); + assert_eq!(is_score_better(claim, initial, Perbill::from_rational(2u32, 10_000),), true,); - assert_eq!( - is_score_better(claim.clone(), initial.clone(), Perbill::from_rational(3u32, 10_000),), - true, - ); + assert_eq!(is_score_better(claim, initial, Perbill::from_rational(3u32, 10_000),), true,); - assert_eq!( - is_score_better(claim.clone(), initial.clone(), Perbill::from_rational(4u32, 10_000),), - true, - ); + assert_eq!(is_score_better(claim, initial, Perbill::from_rational(4u32, 10_000),), true,); - assert_eq!( - is_score_better(claim.clone(), initial.clone(), Perbill::from_rational(5u32, 10_000),), - false, - ); + assert_eq!(is_score_better(claim, initial, Perbill::from_rational(5u32, 10_000),), false,); } #[test] diff --git a/primitives/runtime/src/curve.rs b/primitives/runtime/src/curve.rs index 99733dbbe9a55..c040b7cf517e0 100644 --- a/primitives/runtime/src/curve.rs +++ b/primitives/runtime/src/curve.rs @@ -170,7 +170,7 @@ fn test_calculate_for_fraction_times_denominator() { }; pub fn formal_calculate_for_fraction_times_denominator(n: u64, d: u64) -> u64 { - if n <= Perbill::from_parts(0_500_000_000) * d.clone() { + if n <= Perbill::from_parts(0_500_000_000) * d { n + d / 2 } else { (d as u128 * 2 - n as u128 * 2).try_into().unwrap() diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index bf77c08b76906..cd43038522914 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -1118,7 +1118,7 @@ mod tests { ext.insert(b"c".to_vec(), vec![3u8; 33]); ext.insert(b"d".to_vec(), vec![4u8; 33]); - let pre_root = ext.backend.root().clone(); + let pre_root = *ext.backend.root(); let (_, proof) = ext.execute_and_prove(|| { sp_io::storage::get(b"a"); sp_io::storage::get(b"b"); From e7ae42bcc1e5bfac971d7bfd73307cb738623e85 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 16 Aug 2022 00:31:28 +0200 Subject: [PATCH 1069/1472] Always wipe DB state after benchmark (#12025) * Add test Signed-off-by: Oliver Tale-Yazdi * Always wipe the DB state Signed-off-by: Oliver Tale-Yazdi * Silence Clippy Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 1 + frame/benchmarking/Cargo.toml | 2 ++ frame/benchmarking/src/lib.rs | 18 +++++++------- frame/benchmarking/src/tests.rs | 44 +++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da047d4cba6d8..6a114065ee56c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2102,6 +2102,7 @@ dependencies = [ "serde", "sp-api", "sp-application-crypto", + "sp-core", "sp-io", "sp-keystore", "sp-runtime", diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 4205274b5dbc3..d3a2704724f12 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -23,6 +23,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../../primitives/runtime-interface" } @@ -45,6 +46,7 @@ std = [ "serde", "sp-api/std", "sp-application-crypto/std", + "sp-core/std", "sp-io/std", "sp-runtime-interface/std", "sp-runtime/std", diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index a1399dc388b09..926d7985e8ba7 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -38,6 +38,8 @@ pub use log; #[doc(hidden)] pub use paste; #[doc(hidden)] +pub use sp_core::defer; +#[doc(hidden)] pub use sp_io::storage::root as storage_root; #[doc(hidden)] pub use sp_runtime::traits::Zero; @@ -1033,6 +1035,9 @@ macro_rules! impl_benchmark { // Always do at least one internal repeat... for _ in 0 .. internal_repeats.max(1) { + // Always reset the state after the benchmark. + $crate::defer!($crate::benchmarking::wipe_db()); + // Set up the externalities environment for the setup we want to // benchmark. let closure_to_benchmark = < @@ -1110,9 +1115,6 @@ macro_rules! impl_benchmark { proof_size: diff_pov, keys: read_and_written_keys, }); - - // Wipe the DB back to the genesis state. - $crate::benchmarking::wipe_db(); } return Ok(results); @@ -1175,6 +1177,9 @@ macro_rules! impl_benchmark_test { let execute_benchmark = | c: $crate::Vec<($crate::BenchmarkParameter, u32)> | -> Result<(), $crate::BenchmarkError> { + // Always reset the state after the benchmark. + $crate::defer!($crate::benchmarking::wipe_db()); + // Set up the benchmark, return execution + verification function. let closure_to_verify = < SelectedBenchmark as $crate::BenchmarkingSetup @@ -1186,12 +1191,7 @@ macro_rules! impl_benchmark_test { } // Run execution + verification - closure_to_verify()?; - - // Reset the state - $crate::benchmarking::wipe_db(); - - Ok(()) + closure_to_verify() }; if components.is_empty() { diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index 06f2b5bdc4916..9a97250aeb965 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -125,6 +125,8 @@ fn new_test_ext() -> sp_io::TestExternalities { GenesisConfig::default().build_storage().unwrap().into() } +// NOTE: This attribute is only needed for the `modify_in_` functions. +#[allow(unreachable_code)] mod benchmarks { use super::{new_test_ext, pallet_test::Value, Test}; use crate::{account, BenchmarkError, BenchmarkParameter, BenchmarkResult, BenchmarkingSetup}; @@ -227,6 +229,24 @@ mod benchmarks { // This should never be reached. assert!(value > 100); } + + modify_in_setup_then_error { + Value::::set(Some(123)); + return Err(BenchmarkError::Stop("Should error")); + }: { } + + modify_in_call_then_error { + }: { + Value::::set(Some(123)); + return Err(BenchmarkError::Stop("Should error")); + } + + modify_in_verify_then_error { + }: { + } verify { + Value::::set(Some(123)); + return Err(BenchmarkError::Stop("Should error")); + } } #[test] @@ -350,4 +370,28 @@ mod benchmarks { assert_eq!(Pallet::::test_benchmark_skip_benchmark(), Err(BenchmarkError::Skip),); }); } + + /// An error return of a benchmark test function still causes the db to be wiped. + #[test] + fn benchmark_error_wipes_storage() { + new_test_ext().execute_with(|| { + // It resets when the error happens in the setup: + assert_err!( + Pallet::::test_benchmark_modify_in_setup_then_error(), + "Should error" + ); + assert_eq!(Value::::get(), None); + + // It resets when the error happens in the call: + assert_err!(Pallet::::test_benchmark_modify_in_call_then_error(), "Should error"); + assert_eq!(Value::::get(), None); + + // It resets when the error happens in the verify: + assert_err!( + Pallet::::test_benchmark_modify_in_verify_then_error(), + "Should error" + ); + assert_eq!(Value::::get(), None); + }); + } } From 97ae6be11b0132224a05634c508417f048894670 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 16 Aug 2022 11:36:34 +0100 Subject: [PATCH 1070/1472] Fix Origins Used in Runtime Benchmarks (#12037) * fix identity benchmark origin * fix benchmarking macro * bounties * democracy * scheduler * tips and treasury * unused * dunno, this is causing issues --- frame/benchmarking/src/lib.rs | 14 ++++++------ frame/bounties/src/benchmarking.rs | 33 ++++++++++++++++------------- frame/democracy/src/benchmarking.rs | 4 +++- frame/identity/src/benchmarking.rs | 26 ++++++++++++++++------- frame/scheduler/src/benchmarking.rs | 15 ++++++++----- frame/staking/Cargo.toml | 2 +- frame/tips/src/benchmarking.rs | 3 ++- frame/treasury/src/benchmarking.rs | 9 +++++--- 8 files changed, 65 insertions(+), 41 deletions(-) diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 926d7985e8ba7..0a0f8eecdcc3d 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -547,7 +547,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) - $name:ident { $( $code:tt )* }: _ ( $origin:expr $( , $arg:expr )* ) + $name:ident { $( $code:tt )* }: _ $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) $( $rest:tt )* ) => { $crate::benchmarks_iter! { @@ -557,7 +557,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) - $name { $( $code )* }: _ ( $origin $( , $arg )* ) + $name { $( $code )* }: _ $(<$origin_type>)? ( $origin $( , $arg )* ) verify { } $( $rest )* } @@ -570,7 +570,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) - $name:ident { $( $code:tt )* }: $dispatch:ident ( $origin:expr $( , $arg:expr )* ) + $name:ident { $( $code:tt )* }: $dispatch:ident $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) $( $rest:tt )* ) => { $crate::benchmarks_iter! { @@ -580,7 +580,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) - $name { $( $code )* }: $dispatch ( $origin $( , $arg )* ) + $name { $( $code )* }: $dispatch $(<$origin_type>)? ( $origin $( , $arg )* ) verify { } $( $rest )* } @@ -593,7 +593,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) - $name:ident { $( $code:tt )* }: $eval:block + $name:ident { $( $code:tt )* }: $(<$origin_type:ty>)? $eval:block $( $rest:tt )* ) => { $crate::benchmarks_iter!( @@ -603,7 +603,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) - $name { $( $code )* }: $eval + $name { $( $code )* }: $(<$origin_type>)? $eval verify { } $( $rest )* ); @@ -617,7 +617,7 @@ macro_rules! to_origin { $origin.into() }; ($origin:expr, $origin_type:ty) => { - >::from($origin) + <::Origin as From<$origin_type>>::from($origin) }; } diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 7566c32f6e9a1..bc559e1e8b358 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -37,7 +37,8 @@ fn create_approved_bounties, I: 'static>(n: u32) -> Result<(), &'st setup_bounty::(i, T::MaximumReasonLength::get()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; + let approve_origin = T::ApproveOrigin::successful_origin(); + Bounties::::approve_bounty(approve_origin, bounty_id)?; } ensure!(BountyApprovals::::get().len() == n as usize, "Not all bounty approved"); Ok(()) @@ -67,14 +68,10 @@ fn create_bounty, I: 'static>( let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; + let approve_origin = T::ApproveOrigin::successful_origin(); + Bounties::::approve_bounty(approve_origin.clone(), bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); - Bounties::::propose_curator( - RawOrigin::Root.into(), - bounty_id, - curator_lookup.clone(), - fee, - )?; + Bounties::::propose_curator(approve_origin, bounty_id, curator_lookup.clone(), fee)?; Bounties::::accept_curator(RawOrigin::Signed(curator).into(), bounty_id)?; Ok((curator_lookup, bounty_id)) } @@ -100,7 +97,8 @@ benchmarks_instance_pallet! { let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - }: _(RawOrigin::Root, bounty_id) + let approve_origin = T::ApproveOrigin::successful_origin(); + }: _(approve_origin, bounty_id) propose_curator { setup_pot_account::(); @@ -108,9 +106,11 @@ benchmarks_instance_pallet! { let curator_lookup = T::Lookup::unlookup(curator); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; + let approve_origin = T::ApproveOrigin::successful_origin(); + Bounties::::approve_bounty(approve_origin, bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); - }: _(RawOrigin::Root, bounty_id, curator_lookup, fee) + let approve_origin = T::ApproveOrigin::successful_origin(); + }: _(approve_origin, bounty_id, curator_lookup, fee) // Worst case when curator is inactive and any sender unassigns the curator. unassign_curator { @@ -128,9 +128,10 @@ benchmarks_instance_pallet! { let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - Bounties::::approve_bounty(RawOrigin::Root.into(), bounty_id)?; + let approve_origin = T::ApproveOrigin::successful_origin(); + Bounties::::approve_bounty(approve_origin.clone(), bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); - Bounties::::propose_curator(RawOrigin::Root.into(), bounty_id, curator_lookup, fee)?; + Bounties::::propose_curator(approve_origin, bounty_id, curator_lookup, fee)?; }: _(RawOrigin::Signed(curator), bounty_id) award_bounty { @@ -169,14 +170,16 @@ benchmarks_instance_pallet! { let (caller, curator, fee, value, reason) = setup_bounty::(0, 0); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - }: close_bounty(RawOrigin::Root, bounty_id) + let approve_origin = T::ApproveOrigin::successful_origin(); + }: close_bounty(approve_origin, bounty_id) close_bounty_active { setup_pot_account::(); let (curator_lookup, bounty_id) = create_bounty::()?; Treasury::::on_initialize(T::BlockNumber::zero()); let bounty_id = BountyCount::::get() - 1; - }: close_bounty(RawOrigin::Root, bounty_id) + let approve_origin = T::ApproveOrigin::successful_origin(); + }: close_bounty(approve_origin, bounty_id) verify { assert_last_event::(Event::BountyCanceled { index: bounty_id }.into()) } diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index c51fde8a3de8b..0544ee1731484 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -318,7 +318,9 @@ benchmarks! { for i in 0 .. p { add_proposal::(i)?; } - }: _(RawOrigin::Root, 0) + + let cancel_origin = T::CancelProposalOrigin::successful_origin(); + }: _(cancel_origin, 0) cancel_referendum { let referendum_index = add_referendum::(0)?; diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index b225db4edfa91..4891302695186 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -23,7 +23,10 @@ use super::*; use crate::Pallet as Identity; use frame_benchmarking::{account, benchmarks, whitelisted_caller}; -use frame_support::{ensure, traits::Get}; +use frame_support::{ + ensure, + traits::{EnsureOrigin, Get}, +}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -38,7 +41,8 @@ fn add_registrars(r: u32) -> Result<(), &'static str> { for i in 0..r { let registrar: T::AccountId = account("registrar", i, SEED); let _ = T::Currency::make_free_balance_be(®istrar, BalanceOf::::max_value()); - Identity::::add_registrar(RawOrigin::Root.into(), registrar.clone())?; + let registrar_origin = T::RegistrarOrigin::successful_origin(); + Identity::::add_registrar(registrar_origin, registrar.clone())?; Identity::::set_fee(RawOrigin::Signed(registrar.clone()).into(), i, 10u32.into())?; let fields = IdentityFields( @@ -114,7 +118,8 @@ benchmarks! { add_registrar { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; ensure!(Registrars::::get().len() as u32 == r, "Registrars not set up correctly."); - }: _(RawOrigin::Root, account("registrar", r + 1, SEED)) + let origin = T::RegistrarOrigin::successful_origin(); + }: _(origin, account("registrar", r + 1, SEED)) verify { ensure!(Registrars::::get().len() as u32 == r + 1, "Registrars not added."); } @@ -259,7 +264,8 @@ benchmarks! { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - Identity::::add_registrar(RawOrigin::Root.into(), caller.clone())?; + let registrar_origin = T::RegistrarOrigin::successful_origin(); + Identity::::add_registrar(registrar_origin, caller.clone())?; let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().fee == 0u32.into(), "Fee already set."); }: _(RawOrigin::Signed(caller), r, 100u32.into()) @@ -274,7 +280,8 @@ benchmarks! { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - Identity::::add_registrar(RawOrigin::Root.into(), caller.clone())?; + let registrar_origin = T::RegistrarOrigin::successful_origin(); + Identity::::add_registrar(registrar_origin, caller.clone())?; let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().account == caller, "id not set."); }: _(RawOrigin::Signed(caller), r, account("new", 0, SEED)) @@ -289,7 +296,8 @@ benchmarks! { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - Identity::::add_registrar(RawOrigin::Root.into(), caller.clone())?; + let registrar_origin = T::RegistrarOrigin::successful_origin(); + Identity::::add_registrar(registrar_origin, caller.clone())?; let fields = IdentityFields( IdentityField::Display | IdentityField::Legal | IdentityField::Web | IdentityField::Riot | IdentityField::Email | IdentityField::PgpFingerprint | IdentityField::Image | IdentityField::Twitter @@ -318,7 +326,8 @@ benchmarks! { Identity::::set_identity(user_origin.clone(), Box::new(info))?; }; - Identity::::add_registrar(RawOrigin::Root.into(), caller.clone())?; + let registrar_origin = T::RegistrarOrigin::successful_origin(); + Identity::::add_registrar(registrar_origin, caller.clone())?; Identity::::request_judgement(user_origin, r, 10u32.into())?; }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable) verify { @@ -350,7 +359,8 @@ benchmarks! { )?; } ensure!(IdentityOf::::contains_key(&target), "Identity not set"); - }: _(RawOrigin::Root, target_lookup) + let origin = T::ForceOrigin::successful_origin(); + }: _(origin, target_lookup) verify { ensure!(!IdentityOf::::contains_key(&target), "Identity not removed"); } diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 9c97bc5973384..a8e36b72814b7 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -23,7 +23,6 @@ use frame_support::{ ensure, traits::{OnInitialize, PreimageProvider, PreimageRecipient}, }; -use frame_system::RawOrigin; use sp_runtime::traits::Hash; use sp_std::{prelude::*, vec}; @@ -32,6 +31,8 @@ use frame_system::Pallet as System; const BLOCK_NUMBER: u32 = 2; +type SystemOrigin = ::Origin; + /// Add `n` named items to the schedule. /// /// For `resolved`: @@ -210,7 +211,8 @@ benchmarks! { let call = Box::new(CallOrHashOf::::Value(inner_call)); fill_schedule::(when, s, true, true, Some(false))?; - }: _(RawOrigin::Root, when, periodic, priority, call) + let schedule_origin = T::ScheduleOrigin::successful_origin(); + }: _>(schedule_origin, when, periodic, priority, call) verify { ensure!( Agenda::::get(when).len() == (s + 1) as usize, @@ -224,7 +226,8 @@ benchmarks! { fill_schedule::(when, s, true, true, Some(false))?; assert_eq!(Agenda::::get(when).len(), s as usize); - }: _(RawOrigin::Root, when, 0) + let schedule_origin = T::ScheduleOrigin::successful_origin(); + }: _>(schedule_origin, when, 0) verify { ensure!( Lookup::::get(0.encode()).is_none(), @@ -248,7 +251,8 @@ benchmarks! { let call = Box::new(CallOrHashOf::::Value(inner_call)); fill_schedule::(when, s, true, true, Some(false))?; - }: _(RawOrigin::Root, id, when, periodic, priority, call) + let schedule_origin = T::ScheduleOrigin::successful_origin(); + }: _>(schedule_origin, id, when, periodic, priority, call) verify { ensure!( Agenda::::get(when).len() == (s + 1) as usize, @@ -261,7 +265,8 @@ benchmarks! { let when = BLOCK_NUMBER.into(); fill_schedule::(when, s, true, true, Some(false))?; - }: _(RawOrigin::Root, 0.encode()) + let schedule_origin = T::ScheduleOrigin::successful_origin(); + }: _>(schedule_origin, 0.encode()) verify { ensure!( Lookup::::get(0.encode()).is_none(), diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 0950478fba089..37d13a54ba5ed 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -71,6 +71,6 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-election-provider-support/runtime-benchmarks", "rand_chacha", - "sp-staking/runtime-benchmarks" + "sp-staking/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 33e455bd3b9fd..4c14cb4de94e1 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -190,7 +190,8 @@ benchmarks_instance_pallet! { let reason_hash = T::Hashing::hash(&reason[..]); let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary)); ensure!(Tips::::contains_key(hash), "tip does not exist"); - }: _(RawOrigin::Root, hash) + let reject_origin = T::RejectOrigin::successful_origin(); + }: _(reject_origin, hash) impl_benchmark_test_suite!(TipsMod, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index ddb952383370d..ed30b2f7358e5 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -99,7 +99,8 @@ benchmarks_instance_pallet! { beneficiary_lookup )?; let proposal_id = Treasury::::proposal_count() - 1; - }: _(RawOrigin::Root, proposal_id) + let reject_origin = T::RejectOrigin::successful_origin(); + }: _(reject_origin, proposal_id) approve_proposal { let p in 0 .. T::MaxApprovals::get() - 1; @@ -111,7 +112,8 @@ benchmarks_instance_pallet! { beneficiary_lookup )?; let proposal_id = Treasury::::proposal_count() - 1; - }: _(RawOrigin::Root, proposal_id) + let approve_origin = T::ApproveOrigin::successful_origin(); + }: _(approve_origin, proposal_id) remove_approval { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); @@ -122,7 +124,8 @@ benchmarks_instance_pallet! { )?; let proposal_id = Treasury::::proposal_count() - 1; Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; - }: _(RawOrigin::Root, proposal_id) + let reject_origin = T::RejectOrigin::successful_origin(); + }: _(reject_origin, proposal_id) on_initialize_proposals { let p in 0 .. T::MaxApprovals::get(); From 0fd19982a6a94288c81e31bb6f75f499d4d71b46 Mon Sep 17 00:00:00 2001 From: Aramik Date: Wed, 17 Aug 2022 05:35:56 -0700 Subject: [PATCH 1071/1472] benchmark-cli: add child tree support (#12021) * benchmark-cli: add child tree support * removed extra comments * addressed pr comments * clean up * addressed pr comments --- bin/node/cli/tests/benchmark_storage_works.rs | 1 + .../frame/benchmarking-cli/src/storage/cmd.rs | 18 +- .../benchmarking-cli/src/storage/read.rs | 41 +++- .../benchmarking-cli/src/storage/write.rs | 189 ++++++++++++++---- 4 files changed, 201 insertions(+), 48 deletions(-) diff --git a/bin/node/cli/tests/benchmark_storage_works.rs b/bin/node/cli/tests/benchmark_storage_works.rs index 30f860e48459f..82d1c943ae7aa 100644 --- a/bin/node/cli/tests/benchmark_storage_works.rs +++ b/bin/node/cli/tests/benchmark_storage_works.rs @@ -47,6 +47,7 @@ fn benchmark_storage(db: &str, base_path: &Path) -> ExitStatus { .args(["--state-version", "1"]) .args(["--warmups", "0"]) .args(["--add", "100", "--mul", "1.2", "--metric", "p75"]) + .arg("--include-child-trees") .status() .unwrap() } diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index b8264dc009232..0a92636b151a2 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -24,7 +24,7 @@ use sp_core::storage::StorageKey; use sp_database::{ColumnId, Database}; use sp_runtime::traits::{Block as BlockT, HashFor}; use sp_state_machine::Storage; -use sp_storage::StateVersion; +use sp_storage::{ChildInfo, ChildType, PrefixedStorageKey, StateVersion}; use clap::{Args, Parser}; use log::info; @@ -99,6 +99,10 @@ pub struct StorageParams { /// State cache size. #[clap(long, default_value = "0")] pub state_cache_size: usize, + + /// Include child trees in benchmark. + #[clap(long)] + pub include_child_trees: bool, } impl StorageCmd { @@ -155,6 +159,16 @@ impl StorageCmd { } } + /// Returns Some if child node and None if regular + pub(crate) fn is_child_key(&self, key: Vec) -> Option { + if let Some((ChildType::ParentKeyId, storage_key)) = + ChildType::from_prefixed_key(&PrefixedStorageKey::new(key)) + { + return Some(ChildInfo::new_default(storage_key)) + } + None + } + /// Run some rounds of the (read) benchmark as warmup. /// See `frame_benchmarking_cli::storage::read::bench_read` for detailed comments. fn bench_warmup(&self, client: &Arc) -> Result<()> @@ -171,7 +185,7 @@ impl StorageCmd { for i in 0..self.params.warmups { info!("Warmup round {}/{}", i + 1, self.params.warmups); - for key in keys.clone() { + for key in keys.as_slice() { let _ = client .storage(&block, &key) .expect("Checked above to exist") diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs index c1dc6daba0953..cba318f87ea98 100644 --- a/utils/frame/benchmarking-cli/src/storage/read.rs +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -50,16 +50,43 @@ impl StorageCmd { let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); + let mut child_nodes = Vec::new(); // Interesting part here: // Read all the keys in the database and measure the time it takes to access each. info!("Reading {} keys", keys.len()); - for key in keys.clone() { - let start = Instant::now(); - let v = client - .storage(&block, &key) - .expect("Checked above to exist") - .ok_or("Value unexpectedly empty")?; - record.append(v.0.len(), start.elapsed())?; + for key in keys.as_slice() { + match (self.params.include_child_trees, self.is_child_key(key.clone().0)) { + (true, Some(info)) => { + // child tree key + let child_keys = client.child_storage_keys(&block, &info, &empty_prefix)?; + for ck in child_keys { + child_nodes.push((ck.clone(), info.clone())); + } + }, + _ => { + // regular key + let start = Instant::now(); + let v = client + .storage(&block, &key) + .expect("Checked above to exist") + .ok_or("Value unexpectedly empty")?; + record.append(v.0.len(), start.elapsed())?; + }, + } + } + + if self.params.include_child_trees { + child_nodes.shuffle(&mut rng); + + info!("Reading {} child keys", child_nodes.len()); + for (key, info) in child_nodes.as_slice() { + let start = Instant::now(); + let v = client + .child_storage(&block, info, key) + .expect("Checked above to exist") + .ok_or("Value unexpectedly empty")?; + record.append(v.0.len(), start.elapsed())?; + } } Ok(record) } diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index ab25109a35d49..0d10ef1b7414d 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -16,7 +16,7 @@ // limitations under the License. use sc_cli::Result; -use sc_client_api::UsageProvider; +use sc_client_api::{Backend as ClientBackend, StorageProvider, UsageProvider}; use sc_client_db::{DbHash, DbState}; use sp_api::StateBackend; use sp_blockchain::HeaderBackend; @@ -29,7 +29,12 @@ use sp_trie::PrefixedMemoryDB; use log::{info, trace}; use rand::prelude::*; -use std::{fmt::Debug, sync::Arc, time::Instant}; +use sp_storage::{ChildInfo, StateVersion}; +use std::{ + fmt::Debug, + sync::Arc, + time::{Duration, Instant}, +}; use super::cmd::StorageCmd; use crate::shared::{new_rng, BenchRecord}; @@ -37,7 +42,7 @@ use crate::shared::{new_rng, BenchRecord}; impl StorageCmd { /// Benchmarks the time it takes to write a single Storage item. /// Uses the latest state that is available for the given client. - pub(crate) fn bench_write( + pub(crate) fn bench_write( &self, client: Arc, (db, state_col): (Arc>, ColumnId), @@ -46,7 +51,8 @@ impl StorageCmd { where Block: BlockT

+ Debug, H: HeaderT, - C: UsageProvider + HeaderBackend, + BA: ClientBackend, + C: UsageProvider + HeaderBackend + StorageProvider, { // Store the time that it took to write each value. let mut record = BenchRecord::default(); @@ -61,50 +67,96 @@ impl StorageCmd { let mut kvs = trie.pairs(); let (mut rng, _) = new_rng(None); kvs.shuffle(&mut rng); + info!("Writing {} keys", kvs.len()); + + let mut child_nodes = Vec::new(); // Generate all random values first; Make sure there are no collisions with existing // db entries, so we can rollback all additions without corrupting existing entries. - for (k, original_v) in kvs.iter_mut() { - 'retry: loop { - let mut new_v = vec![0; original_v.len()]; - // Create a random value to overwrite with. - // NOTE: We use a possibly higher entropy than the original value, - // could be improved but acts as an over-estimation which is fine for now. - rng.fill_bytes(&mut new_v[..]); - let new_kv = vec![(k.as_ref(), Some(new_v.as_ref()))]; - let (_, mut stx) = trie.storage_root(new_kv.iter().cloned(), self.state_version()); - for (mut k, (_, rc)) in stx.drain().into_iter() { - if rc > 0 { - db.sanitize_key(&mut k); - if db.get(state_col, &k).is_some() { - trace!("Benchmark-store key creation: Key collision detected, retry"); - continue 'retry + for (k, original_v) in kvs { + match (self.params.include_child_trees, self.is_child_key(k.to_vec())) { + (true, Some(info)) => { + let child_keys = + client.child_storage_keys_iter(&block, info.clone(), None, None)?; + for ck in child_keys { + child_nodes.push((ck.clone(), info.clone())); + } + }, + _ => { + // regular key + let mut new_v = vec![0; original_v.len()]; + loop { + // Create a random value to overwrite with. + // NOTE: We use a possibly higher entropy than the original value, + // could be improved but acts as an over-estimation which is fine for now. + rng.fill_bytes(&mut new_v[..]); + if check_new_value::( + db.clone(), + &trie, + &k.to_vec(), + &new_v, + self.state_version(), + state_col, + None, + ) { + break } } - } - *original_v = new_v; - break + + // Write each value in one commit. + let (size, duration) = measure_write::( + db.clone(), + &trie, + k.to_vec(), + new_v.to_vec(), + self.state_version(), + state_col, + None, + )?; + record.append(size, duration)?; + }, } } - info!("Writing {} keys", kvs.len()); - // Write each value in one commit. - for (k, new_v) in kvs.iter() { - // Interesting part here: - let start = Instant::now(); - // Create a TX that will modify the Trie in the DB and - // calculate the root hash of the Trie after the modification. - let replace = vec![(k.as_ref(), Some(new_v.as_ref()))]; - let (_, stx) = trie.storage_root(replace.iter().cloned(), self.state_version()); - // Only the keep the insertions, since we do not want to benchmark pruning. - let tx = convert_tx::(db.clone(), stx.clone(), false, state_col); - db.commit(tx).map_err(|e| format!("Writing to the Database: {}", e))?; - record.append(new_v.len(), start.elapsed())?; - - // Now undo the changes by removing what was added. - let tx = convert_tx::(db.clone(), stx.clone(), true, state_col); - db.commit(tx).map_err(|e| format!("Writing to the Database: {}", e))?; + if self.params.include_child_trees { + child_nodes.shuffle(&mut rng); + info!("Writing {} child keys", child_nodes.len()); + + for (key, info) in child_nodes { + if let Some(original_v) = client + .child_storage(&block, &info.clone(), &key) + .expect("Checked above to exist") + { + let mut new_v = vec![0; original_v.0.len()]; + loop { + rng.fill_bytes(&mut new_v[..]); + if check_new_value::( + db.clone(), + &trie, + &key.0, + &new_v, + self.state_version(), + state_col, + Some(&info), + ) { + break + } + } + + let (size, duration) = measure_write::( + db.clone(), + &trie, + key.0, + new_v.to_vec(), + self.state_version(), + state_col, + Some(&info), + )?; + record.append(size, duration)?; + } + } } + Ok(record) } } @@ -134,3 +186,62 @@ fn convert_tx( } ret } + +/// Measures write benchmark +/// if `child_info` exist then it means this is a child tree key +fn measure_write( + db: Arc>, + trie: &DbState, + key: Vec, + new_v: Vec, + version: StateVersion, + col: ColumnId, + child_info: Option<&ChildInfo>, +) -> Result<(usize, Duration)> { + let start = Instant::now(); + // Create a TX that will modify the Trie in the DB and + // calculate the root hash of the Trie after the modification. + let replace = vec![(key.as_ref(), Some(new_v.as_ref()))]; + let stx = match child_info { + Some(info) => trie.child_storage_root(info, replace.iter().cloned(), version).2, + None => trie.storage_root(replace.iter().cloned(), version).1, + }; + // Only the keep the insertions, since we do not want to benchmark pruning. + let tx = convert_tx::(db.clone(), stx.clone(), false, col); + db.commit(tx).map_err(|e| format!("Writing to the Database: {}", e))?; + let result = (new_v.len(), start.elapsed()); + + // Now undo the changes by removing what was added. + let tx = convert_tx::(db.clone(), stx.clone(), true, col); + db.commit(tx).map_err(|e| format!("Writing to the Database: {}", e))?; + Ok(result) +} + +/// Checks if a new value causes any collision in tree updates +/// returns true if there is no collision +/// if `child_info` exist then it means this is a child tree key +fn check_new_value( + db: Arc>, + trie: &DbState, + key: &Vec, + new_v: &Vec, + version: StateVersion, + col: ColumnId, + child_info: Option<&ChildInfo>, +) -> bool { + let new_kv = vec![(key.as_ref(), Some(new_v.as_ref()))]; + let mut stx = match child_info { + Some(info) => trie.child_storage_root(info, new_kv.iter().cloned(), version).2, + None => trie.storage_root(new_kv.iter().cloned(), version).1, + }; + for (mut k, (_, rc)) in stx.drain().into_iter() { + if rc > 0 { + db.sanitize_key(&mut k); + if db.get(col, &k).is_some() { + trace!("Benchmark-store key creation: Key collision detected, retry"); + return false + } + } + } + true +} From 2cb89be0a20a119e4bc1a7b255a9dd75b1fc8925 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 17 Aug 2022 17:36:18 +0200 Subject: [PATCH 1072/1472] Fix leaf block removal in the backend (#12005) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix leaf block removal in the backend The fix introduced the new 'removal' method for the backend leaves set and the improvement of the undo features. * Update docs * Apply suggestions from code review Co-authored-by: Bastian Köcher * Fix docs typo * On block block removal the new children list should be persisted. * Align leaves set removal tests to the new interface Co-authored-by: Bastian Köcher --- client/api/src/leaves.rs | 255 ++++++++++++++++++++++++++------------- client/db/src/lib.rs | 92 ++++++++++++-- 2 files changed, 252 insertions(+), 95 deletions(-) diff --git a/client/api/src/leaves.rs b/client/api/src/leaves.rs index 26eda46e6f76f..cdcb80a110b74 100644 --- a/client/api/src/leaves.rs +++ b/client/api/src/leaves.rs @@ -32,32 +32,36 @@ struct LeafSetItem { number: Reverse, } -/// A displaced leaf after import. -#[must_use = "Displaced items from the leaf set must be handled."] -pub struct ImportDisplaced { - new_hash: H, - displaced: LeafSetItem, +/// Inserted and removed leaves after an import action. +pub struct ImportOutcome { + inserted: LeafSetItem, + removed: Option, } -/// Displaced leaves after finalization. -#[must_use = "Displaced items from the leaf set must be handled."] -pub struct FinalizationDisplaced { - leaves: BTreeMap, Vec>, +/// Inserted and removed leaves after a remove action. +pub struct RemoveOutcome { + inserted: Option, + removed: LeafSetItem, } -impl FinalizationDisplaced { +/// Removed leaves after a finalization action. +pub struct FinalizationOutcome { + removed: BTreeMap, Vec>, +} + +impl FinalizationOutcome { /// Merge with another. This should only be used for displaced items that /// are produced within one transaction of each other. pub fn merge(&mut self, mut other: Self) { // this will ignore keys that are in duplicate, however // if these are actually produced correctly via the leaf-set within // one transaction, then there will be no overlap in the keys. - self.leaves.append(&mut other.leaves); + self.removed.append(&mut other.removed); } /// Iterate over all displaced leaves. pub fn leaves(&self) -> impl Iterator { - self.leaves.values().flatten() + self.removed.values().flatten() } } @@ -99,27 +103,52 @@ where } /// Update the leaf list on import. - /// Returns a displaced leaf if there was one. - pub fn import(&mut self, hash: H, number: N, parent_hash: H) -> Option> { - // avoid underflow for genesis. - let displaced = if number != N::zero() { - let parent_number = Reverse(number.clone() - N::one()); - let was_displaced = self.remove_leaf(&parent_number, &parent_hash); - - if was_displaced { - Some(ImportDisplaced { - new_hash: hash.clone(), - displaced: LeafSetItem { hash: parent_hash, number: parent_number }, - }) - } else { - None - } + pub fn import(&mut self, hash: H, number: N, parent_hash: H) -> ImportOutcome { + let number = Reverse(number); + + let removed = if number.0 != N::zero() { + let parent_number = Reverse(number.0.clone() - N::one()); + self.remove_leaf(&parent_number, &parent_hash).then(|| parent_hash) } else { None }; - self.insert_leaf(Reverse(number.clone()), hash.clone()); - displaced + self.insert_leaf(number.clone(), hash.clone()); + + ImportOutcome { inserted: LeafSetItem { hash, number }, removed } + } + + /// Update the leaf list on removal. + /// + /// Note that the leaves set structure doesn't have the information to decide if the + /// leaf we're removing is the last children of the parent. Follows that this method requires + /// the caller to check this condition and optionally pass the `parent_hash` if `hash` is + /// its last child. + /// + /// Returns `None` if no modifications are applied. + pub fn remove( + &mut self, + hash: H, + number: N, + parent_hash: Option, + ) -> Option> { + let number = Reverse(number); + + if !self.remove_leaf(&number, &hash) { + return None + } + + let inserted = parent_hash.and_then(|parent_hash| { + if number.0 != N::zero() { + let parent_number = Reverse(number.0.clone() - N::one()); + self.insert_leaf(parent_number, parent_hash.clone()); + Some(parent_hash) + } else { + None + } + }); + + Some(RemoveOutcome { inserted, removed: LeafSetItem { hash, number } }) } /// Note a block height finalized, displacing all leaves with number less than the finalized @@ -129,15 +158,15 @@ where /// same number as the finalized block, but with different hashes, the current behavior /// is simpler and our assumptions about how finalization works means that those leaves /// will be pruned soon afterwards anyway. - pub fn finalize_height(&mut self, number: N) -> FinalizationDisplaced { + pub fn finalize_height(&mut self, number: N) -> FinalizationOutcome { let boundary = if number == N::zero() { - return FinalizationDisplaced { leaves: BTreeMap::new() } + return FinalizationOutcome { removed: BTreeMap::new() } } else { number - N::one() }; let below_boundary = self.storage.split_off(&Reverse(boundary)); - FinalizationDisplaced { leaves: below_boundary } + FinalizationOutcome { removed: below_boundary } } /// The same as [`Self::finalize_height`], but it only simulates the operation. @@ -145,16 +174,16 @@ where /// This means that no changes are done. /// /// Returns the leaves that would be displaced by finalizing the given block. - pub fn displaced_by_finalize_height(&self, number: N) -> FinalizationDisplaced { + pub fn displaced_by_finalize_height(&self, number: N) -> FinalizationOutcome { let boundary = if number == N::zero() { - return FinalizationDisplaced { leaves: BTreeMap::new() } + return FinalizationOutcome { removed: BTreeMap::new() } } else { number - N::one() }; let below_boundary = self.storage.range(&Reverse(boundary)..); - FinalizationDisplaced { - leaves: below_boundary.map(|(k, v)| (k.clone(), v.clone())).collect(), + FinalizationOutcome { + removed: below_boundary.map(|(k, v)| (k.clone(), v.clone())).collect(), } } @@ -276,16 +305,30 @@ where H: Clone + PartialEq + Decode + Encode, N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode, { - /// Undo an imported block by providing the displaced leaf. - pub fn undo_import(&mut self, displaced: ImportDisplaced) { - let new_number = Reverse(displaced.displaced.number.0.clone() + N::one()); - self.inner.remove_leaf(&new_number, &displaced.new_hash); - self.inner.insert_leaf(displaced.displaced.number, displaced.displaced.hash); + /// Undo an imported block by providing the import operation outcome. + /// No additional operations should be performed between import and undo. + pub fn undo_import(&mut self, outcome: ImportOutcome) { + if let Some(removed_hash) = outcome.removed { + let removed_number = Reverse(outcome.inserted.number.0.clone() - N::one()); + self.inner.insert_leaf(removed_number, removed_hash); + } + self.inner.remove_leaf(&outcome.inserted.number, &outcome.inserted.hash); + } + + /// Undo a removed block by providing the displaced leaf. + /// No additional operations should be performed between remove and undo. + pub fn undo_remove(&mut self, outcome: RemoveOutcome) { + if let Some(inserted_hash) = outcome.inserted { + let inserted_number = Reverse(outcome.removed.number.0.clone() - N::one()); + self.inner.remove_leaf(&inserted_number, &inserted_hash); + } + self.inner.insert_leaf(outcome.removed.number, outcome.removed.hash); } /// Undo a finalization operation by providing the displaced leaves. - pub fn undo_finalization(&mut self, mut displaced: FinalizationDisplaced) { - self.inner.storage.append(&mut displaced.leaves); + /// No additional operations should be performed between finalization and undo. + pub fn undo_finalization(&mut self, mut outcome: FinalizationOutcome) { + self.inner.storage.append(&mut outcome.removed); } } @@ -295,7 +338,7 @@ mod tests { use std::sync::Arc; #[test] - fn it_works() { + fn import_works() { let mut set = LeafSet::new(); set.import(0u32, 0u32, 0u32); @@ -317,6 +360,90 @@ mod tests { assert!(set.contains(3, 3_1)); assert!(set.contains(2, 2_2)); assert!(set.contains(2, 2_3)); + + // Finally test the undo feature + + let outcome = set.import(2_4, 2, 1_1); + assert_eq!(outcome.inserted.hash, 2_4); + assert_eq!(outcome.removed, None); + assert_eq!(set.count(), 4); + assert!(set.contains(2, 2_4)); + + set.undo().undo_import(outcome); + assert_eq!(set.count(), 3); + assert!(set.contains(3, 3_1)); + assert!(set.contains(2, 2_2)); + assert!(set.contains(2, 2_3)); + + let outcome = set.import(3_2, 3, 2_3); + assert_eq!(outcome.inserted.hash, 3_2); + assert_eq!(outcome.removed, Some(2_3)); + assert_eq!(set.count(), 3); + assert!(set.contains(3, 3_2)); + + set.undo().undo_import(outcome); + assert_eq!(set.count(), 3); + assert!(set.contains(3, 3_1)); + assert!(set.contains(2, 2_2)); + assert!(set.contains(2, 2_3)); + } + + #[test] + fn removal_works() { + let mut set = LeafSet::new(); + set.import(10_1u32, 10u32, 0u32); + set.import(11_1, 11, 10_1); + set.import(11_2, 11, 10_1); + set.import(12_1, 12, 11_1); + + let outcome = set.remove(12_1, 12, Some(11_1)).unwrap(); + assert_eq!(outcome.removed.hash, 12_1); + assert_eq!(outcome.inserted, Some(11_1)); + assert_eq!(set.count(), 2); + assert!(set.contains(11, 11_1)); + assert!(set.contains(11, 11_2)); + + let outcome = set.remove(11_1, 11, None).unwrap(); + assert_eq!(outcome.removed.hash, 11_1); + assert_eq!(outcome.inserted, None); + assert_eq!(set.count(), 1); + assert!(set.contains(11, 11_2)); + + let outcome = set.remove(11_2, 11, Some(10_1)).unwrap(); + assert_eq!(outcome.removed.hash, 11_2); + assert_eq!(outcome.inserted, Some(10_1)); + assert_eq!(set.count(), 1); + assert!(set.contains(10, 10_1)); + + set.undo().undo_remove(outcome); + assert_eq!(set.count(), 1); + assert!(set.contains(11, 11_2)); + } + + #[test] + fn finalization_works() { + let mut set = LeafSet::new(); + set.import(9_1u32, 9u32, 0u32); + set.import(10_1, 10, 9_1); + set.import(10_2, 10, 9_1); + set.import(11_1, 11, 10_1); + set.import(11_2, 11, 10_1); + set.import(12_1, 12, 11_2); + + let outcome = set.finalize_height(11); + assert_eq!(set.count(), 2); + assert!(set.contains(11, 11_1)); + assert!(set.contains(12, 12_1)); + assert_eq!( + outcome.removed, + [(Reverse(10), vec![10_2])].into_iter().collect::>(), + ); + + set.undo().undo_finalization(outcome); + assert_eq!(set.count(), 3); + assert!(set.contains(11, 11_1)); + assert!(set.contains(12, 12_1)); + assert!(set.contains(10, 10_2)); } #[test] @@ -383,44 +510,4 @@ mod tests { let set2 = LeafSet::read_from_db(&*db, 0, PREFIX).unwrap(); assert_eq!(set, set2); } - - #[test] - fn undo_import() { - let mut set = LeafSet::new(); - set.import(10_1u32, 10u32, 0u32); - set.import(11_1, 11, 10_1); - set.import(11_2, 11, 10_1); - - let displaced = set.import(12_1, 12, 11_1).unwrap(); - assert_eq!(set.count(), 2); - assert!(set.contains(11, 11_2)); - assert!(set.contains(12, 12_1)); - - set.undo().undo_import(displaced); - assert_eq!(set.count(), 2); - assert!(set.contains(11, 11_1)); - assert!(set.contains(11, 11_2)); - } - - #[test] - fn undo_finalization() { - let mut set = LeafSet::new(); - set.import(9_1u32, 9u32, 0u32); - set.import(10_1, 10, 9_1); - set.import(10_2, 10, 9_1); - set.import(11_1, 11, 10_1); - set.import(11_2, 11, 10_1); - set.import(12_1, 12, 11_2); - - let displaced = set.finalize_height(11); - assert_eq!(set.count(), 2); - assert!(set.contains(11, 11_1)); - assert!(set.contains(12, 12_1)); - - set.undo().undo_finalization(displaced); - assert_eq!(set.count(), 3); - assert!(set.contains(11, 11_1)); - assert!(set.contains(12, 12_1)); - assert!(set.contains(10, 10_2)); - } } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 6b644ad53d52b..71f291e66e793 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -59,7 +59,7 @@ use codec::{Decode, Encode}; use hash_db::Prefix; use sc_client_api::{ backend::NewBlockState, - leaves::{FinalizationDisplaced, LeafSet}, + leaves::{FinalizationOutcome, LeafSet}, utils::is_descendent_of, IoInfo, MemoryInfo, MemorySize, UsageInfo, }; @@ -1251,7 +1251,7 @@ impl Backend { header: &Block::Header, last_finalized: Option, justification: Option, - finalization_displaced: &mut Option>>, + finalization_displaced: &mut Option>>, ) -> ClientResult> { // TODO: ensure best chain contains this block. let number = *header.number(); @@ -1657,7 +1657,7 @@ impl Backend { transaction: &mut Transaction, f_header: &Block::Header, f_hash: Block::Hash, - displaced: &mut Option>>, + displaced: &mut Option>>, with_state: bool, ) -> ClientResult<()> { let f_num = *f_header.number(); @@ -1696,7 +1696,7 @@ impl Backend { &self, transaction: &mut Transaction, finalized: NumberFor, - displaced: &FinalizationDisplaced>, + displaced: &FinalizationOutcome>, ) -> ClientResult<()> { if let BlocksPruning::Some(blocks_pruning) = self.blocks_pruning { // Always keep the last finalized block @@ -2226,9 +2226,40 @@ impl sc_client_api::backend::Backend for Backend { apply_state_commit(&mut transaction, commit); } transaction.remove(columns::KEY_LOOKUP, hash.as_ref()); - leaves.revert(*hash, hdr.number); + + let children: Vec<_> = self + .blockchain() + .children(hdr.parent)? + .into_iter() + .filter(|child_hash| child_hash != hash) + .collect(); + let parent_leaf = if children.is_empty() { + children::remove_children( + &mut transaction, + columns::META, + meta_keys::CHILDREN_PREFIX, + hdr.parent, + ); + Some(hdr.parent) + } else { + children::write_children( + &mut transaction, + columns::META, + meta_keys::CHILDREN_PREFIX, + hdr.parent, + children, + ); + None + }; + + let remove_outcome = leaves.remove(*hash, hdr.number, parent_leaf); leaves.prepare_transaction(&mut transaction, columns::META, meta_keys::LEAF_PREFIX); - self.storage.db.commit(transaction)?; + if let Err(e) = self.storage.db.commit(transaction) { + if let Some(outcome) = remove_outcome { + leaves.undo().undo_remove(outcome); + } + return Err(e.into()) + } self.blockchain().remove_header_metadata(*hash); Ok(()) } @@ -3376,7 +3407,21 @@ pub(crate) mod tests { prev_hash = hash; } - // insert a fork at block 2, which becomes best block + for i in 0..2 { + let hash = insert_block( + &backend, + 2, + blocks[1], + None, + sp_core::H256::random(), + vec![i.into()], + None, + ) + .unwrap(); + blocks.push(hash); + } + + // insert a fork at block 1, which becomes best block let best_hash = insert_block( &backend, 1, @@ -3387,11 +3432,36 @@ pub(crate) mod tests { None, ) .unwrap(); + + assert_eq!(backend.blockchain().info().best_hash, best_hash); assert!(backend.remove_leaf_block(&best_hash).is_err()); - assert!(backend.have_state_at(&prev_hash, 1)); - backend.remove_leaf_block(&prev_hash).unwrap(); - assert_eq!(None, backend.blockchain().header(BlockId::hash(prev_hash)).unwrap()); - assert!(!backend.have_state_at(&prev_hash, 1)); + + assert_eq!(backend.blockchain().leaves().unwrap(), vec![blocks[2], blocks[3], best_hash]); + assert_eq!(backend.blockchain().children(blocks[1]).unwrap(), vec![blocks[2], blocks[3]]); + + assert!(backend.have_state_at(&blocks[3], 2)); + assert!(backend.blockchain().header(BlockId::hash(blocks[3])).unwrap().is_some()); + backend.remove_leaf_block(&blocks[3]).unwrap(); + assert!(!backend.have_state_at(&blocks[3], 2)); + assert!(backend.blockchain().header(BlockId::hash(blocks[3])).unwrap().is_none()); + assert_eq!(backend.blockchain().leaves().unwrap(), vec![blocks[2], best_hash]); + assert_eq!(backend.blockchain().children(blocks[1]).unwrap(), vec![blocks[2]]); + + assert!(backend.have_state_at(&blocks[2], 2)); + assert!(backend.blockchain().header(BlockId::hash(blocks[2])).unwrap().is_some()); + backend.remove_leaf_block(&blocks[2]).unwrap(); + assert!(!backend.have_state_at(&blocks[2], 2)); + assert!(backend.blockchain().header(BlockId::hash(blocks[2])).unwrap().is_none()); + assert_eq!(backend.blockchain().leaves().unwrap(), vec![best_hash, blocks[1]]); + assert_eq!(backend.blockchain().children(blocks[1]).unwrap(), vec![]); + + assert!(backend.have_state_at(&blocks[1], 1)); + assert!(backend.blockchain().header(BlockId::hash(blocks[1])).unwrap().is_some()); + backend.remove_leaf_block(&blocks[1]).unwrap(); + assert!(!backend.have_state_at(&blocks[1], 1)); + assert!(backend.blockchain().header(BlockId::hash(blocks[1])).unwrap().is_none()); + assert_eq!(backend.blockchain().leaves().unwrap(), vec![best_hash]); + assert_eq!(backend.blockchain().children(blocks[0]).unwrap(), vec![best_hash]); } #[test] From e7aa858767c2f19a1f084b98f7a43db52b53b969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 17 Aug 2022 20:19:32 +0200 Subject: [PATCH 1073/1472] Make state types public (#12032) --- frame/contracts/src/chain_extension.rs | 98 ++++++++++++++++---------- 1 file changed, 60 insertions(+), 38 deletions(-) diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 57101668f794d..29f8ad44a56ac 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -84,7 +84,6 @@ pub use crate::{exec::Ext, Config}; pub use frame_system::Config as SysConfig; pub use pallet_contracts_primitives::ReturnFlags; pub use sp_core::crypto::UncheckedFrom; -pub use state::Init as InitState; /// Result that returns a [`DispatchError`] on error. pub type Result = sp_std::result::Result; @@ -198,7 +197,7 @@ pub enum RetVal { /// /// It uses [typestate programming](https://docs.rust-embedded.org/book/static-guarantees/typestate-programming.html) /// to enforce the correct usage of the parameters passed to the chain extension. -pub struct Environment<'a, 'b, E: Ext, S: state::State> { +pub struct Environment<'a, 'b, E: Ext, S: State> { /// The actual data of this type. inner: Inner<'a, 'b, E>, /// `S` is only used in the type system but never as value. @@ -206,7 +205,7 @@ pub struct Environment<'a, 'b, E: Ext, S: state::State> { } /// Functions that are available in every state of this type. -impl<'a, 'b, E: Ext, S: state::State> Environment<'a, 'b, E, S> +impl<'a, 'b, E: Ext, S: State> Environment<'a, 'b, E, S> where ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { @@ -264,7 +263,7 @@ where /// /// Those are the functions that determine how the arguments to the chain extensions /// should be consumed. -impl<'a, 'b, E: Ext> Environment<'a, 'b, E, state::Init> { +impl<'a, 'b, E: Ext> Environment<'a, 'b, E, InitState> { /// Creates a new environment for consumption by a chain extension. /// /// It is only available to this crate because only the wasm runtime module needs to @@ -284,23 +283,23 @@ impl<'a, 'b, E: Ext> Environment<'a, 'b, E, state::Init> { } /// Use all arguments as integer values. - pub fn only_in(self) -> Environment<'a, 'b, E, state::OnlyIn> { + pub fn only_in(self) -> Environment<'a, 'b, E, OnlyInState> { Environment { inner: self.inner, phantom: PhantomData } } /// Use input arguments as integer and output arguments as pointer to a buffer. - pub fn prim_in_buf_out(self) -> Environment<'a, 'b, E, state::PrimInBufOut> { + pub fn prim_in_buf_out(self) -> Environment<'a, 'b, E, PrimInBufOutState> { Environment { inner: self.inner, phantom: PhantomData } } /// Use input and output arguments as pointers to a buffer. - pub fn buf_in_buf_out(self) -> Environment<'a, 'b, E, state::BufInBufOut> { + pub fn buf_in_buf_out(self) -> Environment<'a, 'b, E, BufInBufOutState> { Environment { inner: self.inner, phantom: PhantomData } } } /// Functions to use the input arguments as integers. -impl<'a, 'b, E: Ext, S: state::PrimIn> Environment<'a, 'b, E, S> { +impl<'a, 'b, E: Ext, S: PrimIn> Environment<'a, 'b, E, S> { /// The `input_ptr` argument. pub fn val0(&self) -> u32 { self.inner.input_ptr @@ -313,7 +312,7 @@ impl<'a, 'b, E: Ext, S: state::PrimIn> Environment<'a, 'b, E, S> { } /// Functions to use the output arguments as integers. -impl<'a, 'b, E: Ext, S: state::PrimOut> Environment<'a, 'b, E, S> { +impl<'a, 'b, E: Ext, S: PrimOut> Environment<'a, 'b, E, S> { /// The `output_ptr` argument. pub fn val2(&self) -> u32 { self.inner.output_ptr @@ -326,7 +325,7 @@ impl<'a, 'b, E: Ext, S: state::PrimOut> Environment<'a, 'b, E, S> { } /// Functions to use the input arguments as pointer to a buffer. -impl<'a, 'b, E: Ext, S: state::BufIn> Environment<'a, 'b, E, S> +impl<'a, 'b, E: Ext, S: BufIn> Environment<'a, 'b, E, S> where ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { @@ -389,7 +388,7 @@ where } /// Functions to use the output arguments as pointer to a buffer. -impl<'a, 'b, E: Ext, S: state::BufOut> Environment<'a, 'b, E, S> +impl<'a, 'b, E: Ext, S: BufOut> Environment<'a, 'b, E, S> where ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { @@ -438,31 +437,54 @@ struct Inner<'a, 'b, E: Ext> { output_len_ptr: u32, } -/// Private submodule with public types to prevent other modules from naming them. -mod state { - pub trait State {} - - pub trait PrimIn: State {} - pub trait PrimOut: State {} - pub trait BufIn: State {} - pub trait BufOut: State {} - - /// The initial state of an [`Environment`](`super::Environment`). - /// See [typestate programming](https://docs.rust-embedded.org/book/static-guarantees/typestate-programming.html). - pub enum Init {} - pub enum OnlyIn {} - pub enum PrimInBufOut {} - pub enum BufInBufOut {} - - impl State for Init {} - impl State for OnlyIn {} - impl State for PrimInBufOut {} - impl State for BufInBufOut {} - - impl PrimIn for OnlyIn {} - impl PrimOut for OnlyIn {} - impl PrimIn for PrimInBufOut {} - impl BufOut for PrimInBufOut {} - impl BufIn for BufInBufOut {} - impl BufOut for BufInBufOut {} +/// Any state of an [`Environment`] implements this trait. +/// See [typestate programming](https://docs.rust-embedded.org/book/static-guarantees/typestate-programming.html). +pub trait State: sealed::Sealed {} + +/// A state that uses primitive inputs. +pub trait PrimIn: State {} + +/// A state that uses primitive outputs. +pub trait PrimOut: State {} + +/// A state that uses a buffer as input. +pub trait BufIn: State {} + +/// A state that uses a buffer as output. +pub trait BufOut: State {} + +/// The initial state of an [`Environment`]. +pub enum InitState {} + +/// A state that uses all arguments as primitive inputs. +pub enum OnlyInState {} + +/// A state that uses two arguments as primitive inputs and the other two as buffer output. +pub enum PrimInBufOutState {} + +/// Uses a buffer for input and a buffer for output. +pub enum BufInBufOutState {} + +mod sealed { + use super::*; + + /// Trait to prevent users from implementing `State` for anything else. + pub trait Sealed {} + + impl Sealed for InitState {} + impl Sealed for OnlyInState {} + impl Sealed for PrimInBufOutState {} + impl Sealed for BufInBufOutState {} + + impl State for InitState {} + impl State for OnlyInState {} + impl State for PrimInBufOutState {} + impl State for BufInBufOutState {} + + impl PrimIn for OnlyInState {} + impl PrimOut for OnlyInState {} + impl PrimIn for PrimInBufOutState {} + impl BufOut for PrimInBufOutState {} + impl BufIn for BufInBufOutState {} + impl BufOut for BufInBufOutState {} } From 22b678f7284537b28c0983d6301faea3c607278c Mon Sep 17 00:00:00 2001 From: Doordashcon Date: Thu, 18 Aug 2022 10:30:46 +0100 Subject: [PATCH 1074/1472] Replace `T::AccountId` with `::Source` (#11670) * initial * update * update * update * cargo fmt * update * update benchmarks * AccountIdLookupOf * cargo fmt * fix conflits * cargo fmt * update Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/alliance/src/benchmarking.rs | 6 +-- frame/alliance/src/lib.rs | 17 ++----- frame/assets/src/benchmarking.rs | 4 +- frame/assets/src/lib.rs | 50 ++++++++++--------- frame/bags-list/src/benchmarks.rs | 12 +++-- frame/bags-list/src/lib.rs | 13 +++-- frame/balances/src/benchmarking.rs | 20 ++++---- frame/balances/src/lib.rs | 16 +++--- frame/bounties/src/benchmarking.rs | 2 +- frame/bounties/src/lib.rs | 6 ++- frame/child-bounties/src/lib.rs | 5 +- frame/contracts/src/benchmarking/mod.rs | 2 +- frame/contracts/src/lib.rs | 5 +- frame/conviction-voting/src/benchmarking.rs | 12 +++-- frame/conviction-voting/src/lib.rs | 12 +++-- frame/democracy/src/benchmarking.rs | 18 ++++--- frame/democracy/src/lib.rs | 12 +++-- frame/elections-phragmen/src/benchmarking.rs | 4 +- frame/elections-phragmen/src/lib.rs | 4 +- frame/identity/src/benchmarking.rs | 19 ++++--- frame/identity/src/lib.rs | 20 ++++---- frame/indices/src/benchmarking.rs | 6 ++- frame/indices/src/lib.rs | 7 ++- frame/indices/src/tests.rs | 13 ++--- frame/membership/src/lib.rs | 42 +++++++++++----- frame/nicks/src/lib.rs | 8 ++- frame/node-authorization/src/lib.rs | 9 +++- .../nomination-pools/benchmarking/src/lib.rs | 25 ++++++---- frame/nomination-pools/src/lib.rs | 25 +++++++--- frame/proxy/src/benchmarking.rs | 32 ++++++++---- frame/proxy/src/lib.rs | 31 ++++++++---- frame/ranked-collective/src/benchmarking.rs | 25 +++++++--- frame/ranked-collective/src/lib.rs | 19 +++++-- frame/recovery/src/benchmarking.rs | 28 +++++++---- frame/recovery/src/lib.rs | 42 ++++++++++++---- frame/scored-pool/src/lib.rs | 5 +- frame/society/src/lib.rs | 15 ++++-- frame/staking/src/benchmarking.rs | 7 ++- frame/staking/src/lib.rs | 4 +- frame/staking/src/pallet/mod.rs | 19 +++---- frame/staking/src/testing_utils.rs | 27 ++++------ frame/sudo/src/lib.rs | 6 ++- frame/tips/src/benchmarking.rs | 18 ++++--- frame/tips/src/lib.rs | 9 ++-- frame/treasury/src/benchmarking.rs | 2 +- frame/treasury/src/lib.rs | 5 +- frame/uniques/src/benchmarking.rs | 11 ++-- frame/uniques/src/lib.rs | 37 +++++++------- frame/vesting/src/benchmarking.rs | 22 ++++---- frame/vesting/src/lib.rs | 16 +++--- 50 files changed, 465 insertions(+), 309 deletions(-) diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index 527c35b58a5d8..c23ded1640b58 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -662,7 +662,7 @@ benchmarks_instance_pallet! { assert!(!Alliance::::is_member(&outsider)); assert_eq!(DepositOf::::get(&outsider), None); - let outsider_lookup: ::Source = T::Lookup::unlookup(outsider.clone()); + let outsider_lookup = T::Lookup::unlookup(outsider.clone()); }: _(SystemOrigin::Signed(founder1.clone()), outsider_lookup) verify { assert!(Alliance::::is_member_of(&outsider, MemberRole::Ally)); // outsider is now an ally @@ -681,7 +681,7 @@ benchmarks_instance_pallet! { let ally1 = ally::(1); assert!(Alliance::::is_ally(&ally1)); - let ally1_lookup: ::Source = T::Lookup::unlookup(ally1.clone()); + let ally1_lookup = T::Lookup::unlookup(ally1.clone()); let call = Call::::elevate_ally { ally: ally1_lookup }; let origin = T::MembershipManager::successful_origin(); }: { call.dispatch_bypass_filter(origin)? } @@ -720,7 +720,7 @@ benchmarks_instance_pallet! { assert_eq!(DepositOf::::get(&fellow2), Some(T::AllyDeposit::get())); - let fellow2_lookup: ::Source = T::Lookup::unlookup(fellow2.clone()); + let fellow2_lookup = T::Lookup::unlookup(fellow2.clone()); let call = Call::::kick_member { who: fellow2_lookup }; let origin = T::MembershipManager::successful_origin(); }: { call.dispatch_bypass_filter(origin)? } diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 111ea5dc6e507..0f4d43505e3f9 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -210,6 +210,8 @@ pub enum UnscrupulousItem { type UnscrupulousItemOf = UnscrupulousItem<::AccountId, UrlOf>; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -744,10 +746,7 @@ pub mod pallet { /// A founder or fellow can nominate someone to join the alliance as an Ally. /// There is no deposit required to the nominator or nominee. #[pallet::weight(T::WeightInfo::nominate_ally())] - pub fn nominate_ally( - origin: OriginFor, - who: ::Source, - ) -> DispatchResult { + pub fn nominate_ally(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { let nominator = ensure_signed(origin)?; ensure!(Self::has_voting_rights(&nominator), Error::::NoVotingRights); let who = T::Lookup::lookup(who)?; @@ -771,10 +770,7 @@ pub mod pallet { /// Elevate an ally to fellow. #[pallet::weight(T::WeightInfo::elevate_ally())] - pub fn elevate_ally( - origin: OriginFor, - ally: ::Source, - ) -> DispatchResult { + pub fn elevate_ally(origin: OriginFor, ally: AccountIdLookupOf) -> DispatchResult { T::MembershipManager::ensure_origin(origin)?; let ally = T::Lookup::lookup(ally)?; ensure!(Self::is_ally(&ally), Error::::NotAlly); @@ -807,10 +803,7 @@ pub mod pallet { /// Kick a member from the alliance and slash its deposit. #[pallet::weight(T::WeightInfo::kick_member())] - pub fn kick_member( - origin: OriginFor, - who: ::Source, - ) -> DispatchResult { + pub fn kick_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::MembershipManager::ensure_origin(origin)?; let member = T::Lookup::lookup(who)?; diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index ca88899edf842..043d3f1a1aef4 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -37,7 +37,7 @@ const SEED: u32 = 0; fn create_default_asset, I: 'static>( is_sufficient: bool, -) -> (T::AccountId, ::Source) { +) -> (T::AccountId, AccountIdLookupOf) { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); let root = SystemOrigin::Root.into(); @@ -55,7 +55,7 @@ fn create_default_asset, I: 'static>( fn create_default_minted_asset, I: 'static>( is_sufficient: bool, amount: T::Balance, -) -> (T::AccountId, ::Source) { +) -> (T::AccountId, AccountIdLookupOf) { let (caller, caller_lookup) = create_default_asset::(is_sufficient); if !is_sufficient { T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index e0b00c5642c81..d7ca83c8a84e3 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -164,6 +164,8 @@ use frame_system::Config as SystemConfig; pub use pallet::*; pub use weights::WeightInfo; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -501,7 +503,7 @@ pub mod pallet { pub fn create( origin: OriginFor, #[pallet::compact] id: T::AssetId, - admin: ::Source, + admin: AccountIdLookupOf, min_balance: T::Balance, ) -> DispatchResult { let owner = ensure_signed(origin)?; @@ -557,7 +559,7 @@ pub mod pallet { pub fn force_create( origin: OriginFor, #[pallet::compact] id: T::AssetId, - owner: ::Source, + owner: AccountIdLookupOf, is_sufficient: bool, #[pallet::compact] min_balance: T::Balance, ) -> DispatchResult { @@ -623,7 +625,7 @@ pub mod pallet { pub fn mint( origin: OriginFor, #[pallet::compact] id: T::AssetId, - beneficiary: ::Source, + beneficiary: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -651,7 +653,7 @@ pub mod pallet { pub fn burn( origin: OriginFor, #[pallet::compact] id: T::AssetId, - who: ::Source, + who: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -684,7 +686,7 @@ pub mod pallet { pub fn transfer( origin: OriginFor, #[pallet::compact] id: T::AssetId, - target: ::Source, + target: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -716,7 +718,7 @@ pub mod pallet { pub fn transfer_keep_alive( origin: OriginFor, #[pallet::compact] id: T::AssetId, - target: ::Source, + target: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let source = ensure_signed(origin)?; @@ -749,8 +751,8 @@ pub mod pallet { pub fn force_transfer( origin: OriginFor, #[pallet::compact] id: T::AssetId, - source: ::Source, - dest: ::Source, + source: AccountIdLookupOf, + dest: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -775,7 +777,7 @@ pub mod pallet { pub fn freeze( origin: OriginFor, #[pallet::compact] id: T::AssetId, - who: ::Source, + who: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -806,7 +808,7 @@ pub mod pallet { pub fn thaw( origin: OriginFor, #[pallet::compact] id: T::AssetId, - who: ::Source, + who: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -891,7 +893,7 @@ pub mod pallet { pub fn transfer_ownership( origin: OriginFor, #[pallet::compact] id: T::AssetId, - owner: ::Source, + owner: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; let owner = T::Lookup::lookup(owner)?; @@ -932,9 +934,9 @@ pub mod pallet { pub fn set_team( origin: OriginFor, #[pallet::compact] id: T::AssetId, - issuer: ::Source, - admin: ::Source, - freezer: ::Source, + issuer: AccountIdLookupOf, + admin: AccountIdLookupOf, + freezer: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; let issuer = T::Lookup::lookup(issuer)?; @@ -1117,10 +1119,10 @@ pub mod pallet { pub fn force_asset_status( origin: OriginFor, #[pallet::compact] id: T::AssetId, - owner: ::Source, - issuer: ::Source, - admin: ::Source, - freezer: ::Source, + owner: AccountIdLookupOf, + issuer: AccountIdLookupOf, + admin: AccountIdLookupOf, + freezer: AccountIdLookupOf, #[pallet::compact] min_balance: T::Balance, is_sufficient: bool, is_frozen: bool, @@ -1167,7 +1169,7 @@ pub mod pallet { pub fn approve_transfer( origin: OriginFor, #[pallet::compact] id: T::AssetId, - delegate: ::Source, + delegate: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let owner = ensure_signed(origin)?; @@ -1192,7 +1194,7 @@ pub mod pallet { pub fn cancel_approval( origin: OriginFor, #[pallet::compact] id: T::AssetId, - delegate: ::Source, + delegate: AccountIdLookupOf, ) -> DispatchResult { let owner = ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; @@ -1225,8 +1227,8 @@ pub mod pallet { pub fn force_cancel_approval( origin: OriginFor, #[pallet::compact] id: T::AssetId, - owner: ::Source, - delegate: ::Source, + owner: AccountIdLookupOf, + delegate: AccountIdLookupOf, ) -> DispatchResult { let mut d = Asset::::get(id).ok_or(Error::::Unknown)?; T::ForceOrigin::try_origin(origin) @@ -1272,8 +1274,8 @@ pub mod pallet { pub fn transfer_approved( origin: OriginFor, #[pallet::compact] id: T::AssetId, - owner: ::Source, - destination: ::Source, + owner: AccountIdLookupOf, + destination: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let delegate = ensure_signed(origin)?; diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index bb45da076f751..1f66697cb6765 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -57,6 +57,8 @@ frame_benchmarking::benchmarks_instance_pallet! { let dest_head: T::AccountId = account("dest_head", 0, 0); assert_ok!(List::::insert(dest_head.clone(), dest_bag_thresh)); + let origin_middle_lookup = T::Lookup::unlookup(origin_middle.clone()); + // the bags are in the expected state after initial setup. assert_eq!( List::::get_bags(), @@ -69,7 +71,7 @@ frame_benchmarking::benchmarks_instance_pallet! { let caller = whitelisted_caller(); // update the weight of `origin_middle` to guarantee it will be rebagged into the destination. T::ScoreProvider::set_score_of(&origin_middle, dest_bag_thresh); - }: rebag(SystemOrigin::Signed(caller), origin_middle.clone()) + }: rebag(SystemOrigin::Signed(caller), origin_middle_lookup.clone()) verify { // check the bags have updated as expected. assert_eq!( @@ -114,6 +116,8 @@ frame_benchmarking::benchmarks_instance_pallet! { let dest_head: T::AccountId = account("dest_head", 0, 0); assert_ok!(List::::insert(dest_head.clone(), dest_bag_thresh)); + let origin_tail_lookup = T::Lookup::unlookup(origin_tail.clone()); + // the bags are in the expected state after initial setup. assert_eq!( List::::get_bags(), @@ -126,7 +130,7 @@ frame_benchmarking::benchmarks_instance_pallet! { let caller = whitelisted_caller(); // update the weight of `origin_tail` to guarantee it will be rebagged into the destination. T::ScoreProvider::set_score_of(&origin_tail, dest_bag_thresh); - }: rebag(SystemOrigin::Signed(caller), origin_tail.clone()) + }: rebag(SystemOrigin::Signed(caller), origin_tail_lookup.clone()) verify { // check the bags have updated as expected. assert_eq!( @@ -166,13 +170,15 @@ frame_benchmarking::benchmarks_instance_pallet! { T::ScoreProvider::set_score_of(&lighter, bag_thresh - One::one()); T::ScoreProvider::set_score_of(&heavier, bag_thresh); + let lighter_lookup = T::Lookup::unlookup(lighter.clone()); + assert_eq!( List::::iter().map(|n| n.id().clone()).collect::>(), vec![lighter.clone(), heavier_prev.clone(), heavier.clone(), heavier_next.clone()] ); whitelist_account!(heavier); - }: _(SystemOrigin::Signed(heavier.clone()), lighter.clone()) + }: _(SystemOrigin::Signed(heavier.clone()), lighter_lookup.clone()) verify { assert_eq!( List::::iter().map(|n| n.id().clone()).collect::>(), diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 7eee8fdfa23d8..5163a579c6f43 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -56,7 +56,7 @@ use codec::FullCodec; use frame_election_provider_support::{ScoreProvider, SortedListProvider}; use frame_system::ensure_signed; -use sp_runtime::traits::{AtLeast32BitUnsigned, Bounded}; +use sp_runtime::traits::{AtLeast32BitUnsigned, Bounded, StaticLookup}; use sp_std::prelude::*; #[cfg(any(feature = "runtime-benchmarks", test))] @@ -90,6 +90,8 @@ macro_rules! log { }; } +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -222,8 +224,9 @@ pub mod pallet { /// /// If `dislocated` does not exists, it returns an error. #[pallet::weight(T::WeightInfo::rebag_non_terminal().max(T::WeightInfo::rebag_terminal()))] - pub fn rebag(origin: OriginFor, dislocated: T::AccountId) -> DispatchResult { + pub fn rebag(origin: OriginFor, dislocated: AccountIdLookupOf) -> DispatchResult { ensure_signed(origin)?; + let dislocated = T::Lookup::lookup(dislocated)?; let current_score = T::ScoreProvider::score(&dislocated); let _ = Pallet::::do_rebag(&dislocated, current_score) .map_err::, _>(Into::into)?; @@ -239,8 +242,12 @@ pub mod pallet { /// - both nodes are within the same bag, /// - and `origin` has a greater `Score` than `lighter`. #[pallet::weight(T::WeightInfo::put_in_front_of())] - pub fn put_in_front_of(origin: OriginFor, lighter: T::AccountId) -> DispatchResult { + pub fn put_in_front_of( + origin: OriginFor, + lighter: AccountIdLookupOf, + ) -> DispatchResult { let heavier = ensure_signed(origin)?; + let lighter = T::Lookup::lookup(lighter)?; List::::put_in_front_of(&lighter, &heavier) .map_err::, _>(Into::into) .map_err::(Into::into) diff --git a/frame/balances/src/benchmarking.rs b/frame/balances/src/benchmarking.rs index 4a874e4ffa1d5..206adba0f044b 100644 --- a/frame/balances/src/benchmarking.rs +++ b/frame/balances/src/benchmarking.rs @@ -46,7 +46,7 @@ benchmarks_instance_pallet! { // Transfer `e - 1` existential deposits + 1 unit, which guarantees to create one account, // and reap this user. let recipient: T::AccountId = account("recipient", 0, SEED); - let recipient_lookup: ::Source = T::Lookup::unlookup(recipient.clone()); + let recipient_lookup = T::Lookup::unlookup(recipient.clone()); let transfer_amount = existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into(); }: transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount) verify { @@ -60,7 +60,7 @@ benchmarks_instance_pallet! { transfer_best_case { let caller = whitelisted_caller(); let recipient: T::AccountId = account("recipient", 0, SEED); - let recipient_lookup: ::Source = T::Lookup::unlookup(recipient.clone()); + let recipient_lookup = T::Lookup::unlookup(recipient.clone()); // Give the sender account max funds for transfer (their account will never reasonably be killed). let _ = as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value()); @@ -80,7 +80,7 @@ benchmarks_instance_pallet! { transfer_keep_alive { let caller = whitelisted_caller(); let recipient: T::AccountId = account("recipient", 0, SEED); - let recipient_lookup: ::Source = T::Lookup::unlookup(recipient.clone()); + let recipient_lookup = T::Lookup::unlookup(recipient.clone()); // Give the sender account max funds, thus a transfer will not kill account. let _ = as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value()); @@ -95,7 +95,7 @@ benchmarks_instance_pallet! { // Benchmark `set_balance` coming from ROOT account. This always creates an account. set_balance_creating { let user: T::AccountId = account("user", 0, SEED); - let user_lookup: ::Source = T::Lookup::unlookup(user.clone()); + let user_lookup = T::Lookup::unlookup(user.clone()); // Give the user some initial balance. let existential_deposit = T::ExistentialDeposit::get(); @@ -110,7 +110,7 @@ benchmarks_instance_pallet! { // Benchmark `set_balance` coming from ROOT account. This always kills an account. set_balance_killing { let user: T::AccountId = account("user", 0, SEED); - let user_lookup: ::Source = T::Lookup::unlookup(user.clone()); + let user_lookup = T::Lookup::unlookup(user.clone()); // Give the user some initial balance. let existential_deposit = T::ExistentialDeposit::get(); @@ -127,7 +127,7 @@ benchmarks_instance_pallet! { force_transfer { let existential_deposit = T::ExistentialDeposit::get(); let source: T::AccountId = account("source", 0, SEED); - let source_lookup: ::Source = T::Lookup::unlookup(source.clone()); + let source_lookup = T::Lookup::unlookup(source.clone()); // Give some multiple of the existential deposit let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); @@ -135,7 +135,7 @@ benchmarks_instance_pallet! { // Transfer `e - 1` existential deposits + 1 unit, which guarantees to create one account, and reap this user. let recipient: T::AccountId = account("recipient", 0, SEED); - let recipient_lookup: ::Source = T::Lookup::unlookup(recipient.clone()); + let recipient_lookup = T::Lookup::unlookup(recipient.clone()); let transfer_amount = existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into(); }: force_transfer(RawOrigin::Root, source_lookup, recipient_lookup, transfer_amount) verify { @@ -160,7 +160,7 @@ benchmarks_instance_pallet! { // Transfer `e - 1` existential deposits + 1 unit, which guarantees to create one account, // and reap this user. let recipient: T::AccountId = account("recipient", 0, SEED); - let recipient_lookup: ::Source = T::Lookup::unlookup(recipient.clone()); + let recipient_lookup = T::Lookup::unlookup(recipient.clone()); let transfer_amount = existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into(); // Create a bunch of users in storage. @@ -182,7 +182,7 @@ benchmarks_instance_pallet! { transfer_all { let caller = whitelisted_caller(); let recipient: T::AccountId = account("recipient", 0, SEED); - let recipient_lookup: ::Source = T::Lookup::unlookup(recipient.clone()); + let recipient_lookup = T::Lookup::unlookup(recipient.clone()); // Give some multiple of the existential deposit let existential_deposit = T::ExistentialDeposit::get(); @@ -196,7 +196,7 @@ benchmarks_instance_pallet! { force_unreserve { let user: T::AccountId = account("user", 0, SEED); - let user_lookup: ::Source = T::Lookup::unlookup(user.clone()); + let user_lookup = T::Lookup::unlookup(user.clone()); // Give some multiple of the existential deposit let existential_deposit = T::ExistentialDeposit::get(); diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 683ebce2b1693..0cb32a4e3ecd6 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -192,6 +192,8 @@ pub use weights::WeightInfo; pub use pallet::*; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -275,7 +277,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( origin: OriginFor, - dest: ::Source, + dest: AccountIdLookupOf, #[pallet::compact] value: T::Balance, ) -> DispatchResultWithPostInfo { let transactor = ensure_signed(origin)?; @@ -303,7 +305,7 @@ pub mod pallet { )] pub fn set_balance( origin: OriginFor, - who: ::Source, + who: AccountIdLookupOf, #[pallet::compact] new_free: T::Balance, #[pallet::compact] new_reserved: T::Balance, ) -> DispatchResultWithPostInfo { @@ -353,8 +355,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_transfer())] pub fn force_transfer( origin: OriginFor, - source: ::Source, - dest: ::Source, + source: AccountIdLookupOf, + dest: AccountIdLookupOf, #[pallet::compact] value: T::Balance, ) -> DispatchResultWithPostInfo { ensure_root(origin)?; @@ -378,7 +380,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer_keep_alive())] pub fn transfer_keep_alive( origin: OriginFor, - dest: ::Source, + dest: AccountIdLookupOf, #[pallet::compact] value: T::Balance, ) -> DispatchResultWithPostInfo { let transactor = ensure_signed(origin)?; @@ -407,7 +409,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer_all())] pub fn transfer_all( origin: OriginFor, - dest: ::Source, + dest: AccountIdLookupOf, keep_alive: bool, ) -> DispatchResult { use fungible::Inspect; @@ -425,7 +427,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_unreserve())] pub fn force_unreserve( origin: OriginFor, - who: ::Source, + who: AccountIdLookupOf, amount: T::Balance, ) -> DispatchResult { ensure_root(origin)?; diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index bc559e1e8b358..0c8c875dc611c 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -62,7 +62,7 @@ fn setup_bounty, I: 'static>( } fn create_bounty, I: 'static>( -) -> Result<(::Source, BountyIndex), &'static str> { +) -> Result<(AccountIdLookupOf, BountyIndex), &'static str> { let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); let curator_lookup = T::Lookup::unlookup(curator.clone()); diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index fca758fd96b8e..74e67b7ea5b92 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -114,6 +114,8 @@ type PositiveImbalanceOf = pallet_treasury::PositiveImbalanceOf /// An index of a bounty. Just a `u32`. pub type BountyIndex = u32; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + /// A bounty proposal. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Bounty { @@ -381,7 +383,7 @@ pub mod pallet { pub fn propose_curator( origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, - curator: ::Source, + curator: AccountIdLookupOf, #[pallet::compact] fee: BalanceOf, ) -> DispatchResult { T::ApproveOrigin::ensure_origin(origin)?; @@ -553,7 +555,7 @@ pub mod pallet { pub fn award_bounty( origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, - beneficiary: ::Source, + beneficiary: AccountIdLookupOf, ) -> DispatchResult { let signer = ensure_signed(origin)?; let beneficiary = T::Lookup::lookup(beneficiary)?; diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 4f25fdcf8903a..5f396cd2d4567 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -80,6 +80,7 @@ pub use pallet::*; type BalanceOf = pallet_treasury::BalanceOf; type BountiesError = pallet_bounties::Error; type BountyIndex = pallet_bounties::BountyIndex; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// A child bounty proposal. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] @@ -315,7 +316,7 @@ pub mod pallet { origin: OriginFor, #[pallet::compact] parent_bounty_id: BountyIndex, #[pallet::compact] child_bounty_id: BountyIndex, - curator: ::Source, + curator: AccountIdLookupOf, #[pallet::compact] fee: BalanceOf, ) -> DispatchResult { let signer = ensure_signed(origin)?; @@ -574,7 +575,7 @@ pub mod pallet { origin: OriginFor, #[pallet::compact] parent_bounty_id: BountyIndex, #[pallet::compact] child_bounty_id: BountyIndex, - beneficiary: ::Source, + beneficiary: AccountIdLookupOf, ) -> DispatchResult { let signer = ensure_signed(origin)?; let beneficiary = T::Lookup::lookup(beneficiary)?; diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index bea469bd0f5a9..1a0b735ac76ce 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -57,7 +57,7 @@ const INSTR_BENCHMARK_BATCHES: u32 = 50; struct Contract { caller: T::AccountId, account_id: T::AccountId, - addr: ::Source, + addr: AccountIdLookupOf, value: BalanceOf, } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 319bacaab7789..06fd419d88bf3 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -136,6 +136,7 @@ type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type CodeVec = BoundedVec::MaxCodeLen>; type RelaxedCodeVec = BoundedVec::RelaxedMaxCodeLen>; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// Used as a sentinel value when reading and writing contract memory. /// @@ -435,7 +436,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::call().saturating_add(*gas_limit))] pub fn call( origin: OriginFor, - dest: ::Source, + dest: AccountIdLookupOf, #[pallet::compact] value: BalanceOf, #[pallet::compact] gas_limit: Weight, storage_deposit_limit: Option< as codec::HasCompact>::Type>, @@ -617,7 +618,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_code())] pub fn set_code( origin: OriginFor, - dest: ::Source, + dest: AccountIdLookupOf, code_hash: CodeHash, ) -> DispatchResult { ensure_root(origin)?; diff --git a/frame/conviction-voting/src/benchmarking.rs b/frame/conviction-voting/src/benchmarking.rs index d472770832497..117bb7fe22989 100644 --- a/frame/conviction-voting/src/benchmarking.rs +++ b/frame/conviction-voting/src/benchmarking.rs @@ -149,6 +149,7 @@ benchmarks_instance_pallet! { remove_other_vote { let caller = funded_account::("caller", 0); let voter = funded_account::("caller", 0); + let voter_lookup = T::Lookup::unlookup(voter.clone()); whitelist_account!(caller); let old_account_vote = account_vote::(100u32.into()); @@ -167,7 +168,7 @@ benchmarks_instance_pallet! { let index = polls[0]; assert!(T::Polls::end_ongoing(index, false).is_ok()); - }: _(RawOrigin::Signed(caller.clone()), voter.clone(), class.clone(), index) + }: _(RawOrigin::Signed(caller.clone()), voter_lookup, class.clone(), index) verify { assert_matches!( VotingFor::::get(&voter, &class), @@ -182,6 +183,7 @@ benchmarks_instance_pallet! { let class = T::Polls::max_ongoing().0; let polls = &all_polls[&class]; let voter = funded_account::("voter", 0); + let voter_lookup = T::Lookup::unlookup(voter.clone()); let caller = funded_account::("caller", 0); whitelist_account!(caller); @@ -197,7 +199,7 @@ benchmarks_instance_pallet! { Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize ); - }: _(RawOrigin::Signed(caller.clone()), class.clone(), voter, Conviction::Locked1x, delegated_balance) + }: _(RawOrigin::Signed(caller.clone()), class.clone(), voter_lookup, Conviction::Locked1x, delegated_balance) verify { assert_matches!(VotingFor::::get(&caller, &class), Voting::Delegating(_)); } @@ -209,6 +211,7 @@ benchmarks_instance_pallet! { let class = T::Polls::max_ongoing().0; let polls = &all_polls[&class]; let voter = funded_account::("voter", 0); + let voter_lookup = T::Lookup::unlookup(voter.clone()); let caller = funded_account::("caller", 0); whitelist_account!(caller); @@ -218,7 +221,7 @@ benchmarks_instance_pallet! { ConvictionVoting::::delegate( RawOrigin::Signed(caller.clone()).into(), class.clone(), - voter.clone(), + voter_lookup, Conviction::Locked1x, delegated_balance, )?; @@ -239,6 +242,7 @@ benchmarks_instance_pallet! { unlock { let caller = funded_account::("caller", 0); + let caller_lookup = T::Lookup::unlookup(caller.clone()); whitelist_account!(caller); let normal_account_vote = account_vote::(T::Currency::free_balance(&caller) - 100u32.into()); let big_account_vote = account_vote::(T::Currency::free_balance(&caller)); @@ -266,7 +270,7 @@ benchmarks_instance_pallet! { ConvictionVoting::::remove_vote(RawOrigin::Signed(caller.clone()).into(), Some(class.clone()), polls[0])?; // We can now unlock on `class` from 200 to 100... - }: _(RawOrigin::Signed(caller.clone()), class, caller.clone()) + }: _(RawOrigin::Signed(caller.clone()), class, caller_lookup) verify { assert_eq!(orig_usable, >::reducible_balance(&caller, false)); } diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index 54fc1156d1f47..cd16fccd6661d 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -36,7 +36,7 @@ use frame_support::{ }, }; use sp_runtime::{ - traits::{AtLeast32BitUnsigned, Saturating, Zero}, + traits::{AtLeast32BitUnsigned, Saturating, StaticLookup, Zero}, ArithmeticError, Perbill, }; use sp_std::prelude::*; @@ -62,6 +62,7 @@ pub mod benchmarking; const CONVICTION_VOTING_ID: LockIdentifier = *b"pyconvot"; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; type BalanceOf = <>::Currency as Currency<::AccountId>>::Balance; type VotingOf = Voting< @@ -245,11 +246,12 @@ pub mod pallet { pub fn delegate( origin: OriginFor, class: ClassOf, - to: T::AccountId, + to: AccountIdLookupOf, conviction: Conviction, balance: BalanceOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; + let to = T::Lookup::lookup(to)?; let votes = Self::try_delegate(who, class, to, conviction, balance)?; Ok(Some(T::WeightInfo::delegate(votes)).into()) @@ -294,9 +296,10 @@ pub mod pallet { pub fn unlock( origin: OriginFor, class: ClassOf, - target: T::AccountId, + target: AccountIdLookupOf, ) -> DispatchResult { ensure_signed(origin)?; + let target = T::Lookup::lookup(target)?; Self::update_lock(&class, &target); Ok(()) } @@ -359,11 +362,12 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_other_vote())] pub fn remove_other_vote( origin: OriginFor, - target: T::AccountId, + target: AccountIdLookupOf, class: ClassOf, index: PollIndexOf, ) -> DispatchResult { let who = ensure_signed(origin)?; + let target = T::Lookup::lookup(target)?; let scope = if target == who { UnvoteScope::Any } else { UnvoteScope::OnlyExpired }; Self::try_remove_vote(&target, index, Some(class), scope)?; Ok(()) diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index 0544ee1731484..9b275043df43e 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -483,9 +483,10 @@ benchmarks! { let caller = funded_account::("caller", 0); // Caller will initially delegate to `old_delegate` let old_delegate: T::AccountId = funded_account::("old_delegate", r); + let old_delegate_lookup = T::Lookup::unlookup(old_delegate.clone()); Democracy::::delegate( RawOrigin::Signed(caller.clone()).into(), - old_delegate.clone(), + old_delegate_lookup, Conviction::Locked1x, delegated_balance, )?; @@ -497,6 +498,7 @@ benchmarks! { assert_eq!(balance, delegated_balance, "delegation balance didn't work"); // Caller will now switch to `new_delegate` let new_delegate: T::AccountId = funded_account::("new_delegate", r); + let new_delegate_lookup = T::Lookup::unlookup(new_delegate.clone()); let account_vote = account_vote::(initial_balance); // We need to create existing direct votes for the `new_delegate` for i in 0..r { @@ -509,7 +511,7 @@ benchmarks! { }; assert_eq!(votes.len(), r as usize, "Votes were not recorded."); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller.clone()), new_delegate.clone(), Conviction::Locked1x, delegated_balance) + }: _(RawOrigin::Signed(caller.clone()), new_delegate_lookup, Conviction::Locked1x, delegated_balance) verify { let (target, balance) = match VotingOf::::get(&caller) { Voting::Delegating { target, balance, .. } => (target, balance), @@ -533,9 +535,10 @@ benchmarks! { let caller = funded_account::("caller", 0); // Caller will delegate let the_delegate: T::AccountId = funded_account::("delegate", r); + let the_delegate_lookup = T::Lookup::unlookup(the_delegate.clone()); Democracy::::delegate( RawOrigin::Signed(caller.clone()).into(), - the_delegate.clone(), + the_delegate_lookup, Conviction::Locked1x, delegated_balance, )?; @@ -642,6 +645,7 @@ benchmarks! { let r in 1 .. MAX_REFERENDUMS; let locker = funded_account::("locker", 0); + let locker_lookup = T::Lookup::unlookup(locker.clone()); // Populate votes so things are locked let base_balance: BalanceOf = 100u32.into(); let small_vote = account_vote::(base_balance); @@ -654,7 +658,7 @@ benchmarks! { let caller = funded_account::("caller", 0); whitelist_account!(caller); - }: unlock(RawOrigin::Signed(caller), locker.clone()) + }: unlock(RawOrigin::Signed(caller), locker_lookup) verify { // Note that we may want to add a `get_lock` api to actually verify let voting = VotingOf::::get(&locker); @@ -666,6 +670,7 @@ benchmarks! { let r in 1 .. MAX_REFERENDUMS; let locker = funded_account::("locker", 0); + let locker_lookup = T::Lookup::unlookup(locker.clone()); // Populate votes so things are locked let base_balance: BalanceOf = 100u32.into(); let small_vote = account_vote::(base_balance); @@ -692,7 +697,7 @@ benchmarks! { let caller = funded_account::("caller", 0); whitelist_account!(caller); - }: unlock(RawOrigin::Signed(caller), locker.clone()) + }: unlock(RawOrigin::Signed(caller), locker_lookup) verify { let votes = match VotingOf::::get(&locker) { Voting::Direct { votes, .. } => votes, @@ -738,6 +743,7 @@ benchmarks! { let r in 1 .. MAX_REFERENDUMS; let caller = funded_account::("caller", r); + let caller_lookup = T::Lookup::unlookup(caller.clone()); let account_vote = account_vote::(100u32.into()); for i in 0 .. r { @@ -753,7 +759,7 @@ benchmarks! { let referendum_index = r - 1; whitelist_account!(caller); - }: _(RawOrigin::Signed(caller.clone()), caller.clone(), referendum_index) + }: _(RawOrigin::Signed(caller.clone()), caller_lookup, referendum_index) verify { let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 443b8579116d0..a347f47efe121 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -165,7 +165,7 @@ use frame_support::{ }; use scale_info::TypeInfo; use sp_runtime::{ - traits::{Bounded, Dispatchable, Hash, Saturating, Zero}, + traits::{Bounded, Dispatchable, Hash, Saturating, StaticLookup, Zero}, ArithmeticError, DispatchError, DispatchResult, RuntimeDebug, }; use sp_std::prelude::*; @@ -206,6 +206,7 @@ type BalanceOf = type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum PreimageStatus { @@ -944,11 +945,12 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::delegate(T::MaxVotes::get()))] pub fn delegate( origin: OriginFor, - to: T::AccountId, + to: AccountIdLookupOf, conviction: Conviction, balance: BalanceOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; + let to = T::Lookup::lookup(to)?; let votes = Self::try_delegate(who, to, conviction, balance)?; Ok(Some(T::WeightInfo::delegate(votes)).into()) @@ -1127,8 +1129,9 @@ pub mod pallet { T::WeightInfo::unlock_set(T::MaxVotes::get()) .max(T::WeightInfo::unlock_remove(T::MaxVotes::get())) )] - pub fn unlock(origin: OriginFor, target: T::AccountId) -> DispatchResult { + pub fn unlock(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { ensure_signed(origin)?; + let target = T::Lookup::lookup(target)?; Self::update_lock(&target); Ok(()) } @@ -1184,10 +1187,11 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_other_vote(T::MaxVotes::get()))] pub fn remove_other_vote( origin: OriginFor, - target: T::AccountId, + target: AccountIdLookupOf, index: ReferendumIndex, ) -> DispatchResult { let who = ensure_signed(origin)?; + let target = T::Lookup::lookup(target)?; let scope = if target == who { UnvoteScope::Any } else { UnvoteScope::OnlyExpired }; Self::try_remove_vote(&target, index, scope)?; Ok(()) diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 2d1b698940a9d..22d00a912a4f7 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -29,8 +29,6 @@ use crate::Pallet as Elections; const BALANCE_FACTOR: u32 = 250; -type Lookup = <::Lookup as StaticLookup>::Source; - /// grab new account with infinite balance. fn endowed_account(name: &'static str, index: u32) -> T::AccountId { let account: T::AccountId = account(name, index, 0); @@ -46,7 +44,7 @@ fn endowed_account(name: &'static str, index: u32) -> T::AccountId { } /// Account to lookup type of system trait. -fn as_lookup(account: T::AccountId) -> Lookup { +fn as_lookup(account: T::AccountId) -> AccountIdLookupOf { T::Lookup::unlookup(account) } diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 03d41fa2af40f..1076ae77fbdda 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -176,6 +176,8 @@ pub struct SeatHolder { pub use pallet::*; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -508,7 +510,7 @@ pub mod pallet { })] pub fn remove_member( origin: OriginFor, - who: ::Source, + who: AccountIdLookupOf, slash_bond: bool, rerun_election: bool, ) -> DispatchResultWithPostInfo { diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 4891302695186..20af41d392089 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -40,9 +40,10 @@ fn assert_last_event(generic_event: ::Event) { fn add_registrars(r: u32) -> Result<(), &'static str> { for i in 0..r { let registrar: T::AccountId = account("registrar", i, SEED); + let registrar_lookup = T::Lookup::unlookup(registrar.clone()); let _ = T::Currency::make_free_balance_be(®istrar, BalanceOf::::max_value()); let registrar_origin = T::RegistrarOrigin::successful_origin(); - Identity::::add_registrar(registrar_origin, registrar.clone())?; + Identity::::add_registrar(registrar_origin, registrar_lookup)?; Identity::::set_fee(RawOrigin::Signed(registrar.clone()).into(), i, 10u32.into())?; let fields = IdentityFields( @@ -130,7 +131,7 @@ benchmarks! { let caller = { // The target user let caller: T::AccountId = whitelisted_caller(); - let caller_lookup: ::Source = T::Lookup::unlookup(caller.clone()); + let caller_lookup = T::Lookup::unlookup(caller.clone()); let caller_origin: ::Origin = RawOrigin::Signed(caller.clone()).into(); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -261,11 +262,12 @@ benchmarks! { set_fee { let caller: T::AccountId = whitelisted_caller(); + let caller_lookup = T::Lookup::unlookup(caller.clone()); let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; let registrar_origin = T::RegistrarOrigin::successful_origin(); - Identity::::add_registrar(registrar_origin, caller.clone())?; + Identity::::add_registrar(registrar_origin, caller_lookup)?; let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().fee == 0u32.into(), "Fee already set."); }: _(RawOrigin::Signed(caller), r, 100u32.into()) @@ -276,12 +278,13 @@ benchmarks! { set_account_id { let caller: T::AccountId = whitelisted_caller(); + let caller_lookup = T::Lookup::unlookup(caller.clone()); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; let registrar_origin = T::RegistrarOrigin::successful_origin(); - Identity::::add_registrar(registrar_origin, caller.clone())?; + Identity::::add_registrar(registrar_origin, caller_lookup)?; let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().account == caller, "id not set."); }: _(RawOrigin::Signed(caller), r, account("new", 0, SEED)) @@ -292,12 +295,13 @@ benchmarks! { set_fields { let caller: T::AccountId = whitelisted_caller(); + let caller_lookup = T::Lookup::unlookup(caller.clone()); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; let registrar_origin = T::RegistrarOrigin::successful_origin(); - Identity::::add_registrar(registrar_origin, caller.clone())?; + Identity::::add_registrar(registrar_origin, caller_lookup)?; let fields = IdentityFields( IdentityField::Display | IdentityField::Legal | IdentityField::Web | IdentityField::Riot | IdentityField::Email | IdentityField::PgpFingerprint | IdentityField::Image | IdentityField::Twitter @@ -318,6 +322,7 @@ benchmarks! { let _ = T::Currency::make_free_balance_be(&user, BalanceOf::::max_value()); let caller: T::AccountId = whitelisted_caller(); + let caller_lookup = T::Lookup::unlookup(caller.clone()); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; @@ -327,7 +332,7 @@ benchmarks! { }; let registrar_origin = T::RegistrarOrigin::successful_origin(); - Identity::::add_registrar(registrar_origin, caller.clone())?; + Identity::::add_registrar(registrar_origin, caller_lookup)?; Identity::::request_judgement(user_origin, r, 10u32.into())?; }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable) verify { @@ -341,7 +346,7 @@ benchmarks! { let target: T::AccountId = account("target", 0, SEED); let target_origin: ::Origin = RawOrigin::Signed(target.clone()).into(); - let target_lookup: ::Source = T::Lookup::unlookup(target.clone()); + let target_lookup = T::Lookup::unlookup(target.clone()); let _ = T::Currency::make_free_balance_be(&target, BalanceOf::::max_value()); let info = create_identity_info::(x); diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 46f847606903d..0f80acceb949c 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -94,6 +94,7 @@ type BalanceOf = type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; #[frame_support::pallet] pub mod pallet { @@ -282,9 +283,10 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::add_registrar(T::MaxRegistrars::get()))] pub fn add_registrar( origin: OriginFor, - account: T::AccountId, + account: AccountIdLookupOf, ) -> DispatchResultWithPostInfo { T::RegistrarOrigin::ensure_origin(origin)?; + let account = T::Lookup::lookup(account)?; let (i, registrar_count) = >::try_mutate( |registrars| -> Result<(RegistrarIndex, usize), DispatchError> { @@ -672,9 +674,10 @@ pub mod pallet { pub fn set_account_id( origin: OriginFor, #[pallet::compact] index: RegistrarIndex, - new: T::AccountId, + new: AccountIdLookupOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; + let new = T::Lookup::lookup(new)?; let registrars = >::mutate(|rs| -> Result { rs.get_mut(index as usize) @@ -760,7 +763,7 @@ pub mod pallet { pub fn provide_judgement( origin: OriginFor, #[pallet::compact] reg_index: RegistrarIndex, - target: ::Source, + target: AccountIdLookupOf, judgement: Judgement>, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; @@ -827,7 +830,7 @@ pub mod pallet { ))] pub fn kill_identity( origin: OriginFor, - target: ::Source, + target: AccountIdLookupOf, ) -> DispatchResultWithPostInfo { T::ForceOrigin::ensure_origin(origin)?; @@ -863,7 +866,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::add_sub(T::MaxSubAccounts::get()))] pub fn add_sub( origin: OriginFor, - sub: ::Source, + sub: AccountIdLookupOf, data: Data, ) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -898,7 +901,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::rename_sub(T::MaxSubAccounts::get()))] pub fn rename_sub( origin: OriginFor, - sub: ::Source, + sub: AccountIdLookupOf, data: Data, ) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -917,10 +920,7 @@ pub mod pallet { /// The dispatch origin for this call must be _Signed_ and the sender must have a registered /// sub identity of `sub`. #[pallet::weight(T::WeightInfo::remove_sub(T::MaxSubAccounts::get()))] - pub fn remove_sub( - origin: OriginFor, - sub: ::Source, - ) -> DispatchResult { + pub fn remove_sub(origin: OriginFor, sub: AccountIdLookupOf) -> DispatchResult { let sender = ensure_signed(origin)?; ensure!(IdentityOf::::contains_key(&sender), Error::::NoIdentity); let sub = T::Lookup::lookup(sub)?; diff --git a/frame/indices/src/benchmarking.rs b/frame/indices/src/benchmarking.rs index cb06cd809f542..f462f22284d40 100644 --- a/frame/indices/src/benchmarking.rs +++ b/frame/indices/src/benchmarking.rs @@ -44,10 +44,11 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let recipient: T::AccountId = account("recipient", 0, SEED); + let recipient_lookup = T::Lookup::unlookup(recipient.clone()); T::Currency::make_free_balance_be(&recipient, BalanceOf::::max_value()); // Claim the index Indices::::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?; - }: _(RawOrigin::Signed(caller.clone()), recipient.clone(), account_index) + }: _(RawOrigin::Signed(caller.clone()), recipient_lookup, account_index) verify { assert_eq!(Accounts::::get(account_index).unwrap().0, recipient); } @@ -70,10 +71,11 @@ benchmarks! { let original: T::AccountId = account("original", 0, SEED); T::Currency::make_free_balance_be(&original, BalanceOf::::max_value()); let recipient: T::AccountId = account("recipient", 0, SEED); + let recipient_lookup = T::Lookup::unlookup(recipient.clone()); T::Currency::make_free_balance_be(&recipient, BalanceOf::::max_value()); // Claim the index Indices::::claim(RawOrigin::Signed(original).into(), account_index)?; - }: _(RawOrigin::Root, recipient.clone(), account_index, false) + }: _(RawOrigin::Root, recipient_lookup, account_index, false) verify { assert_eq!(Accounts::::get(account_index).unwrap().0, recipient); } diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index ddc03c94b1233..49380f18e24db 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -36,6 +36,7 @@ pub use weights::WeightInfo; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; pub use pallet::*; @@ -133,10 +134,11 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( origin: OriginFor, - new: T::AccountId, + new: AccountIdLookupOf, index: T::AccountIndex, ) -> DispatchResult { let who = ensure_signed(origin)?; + let new = T::Lookup::lookup(new)?; ensure!(who != new, Error::::NotTransfer); Accounts::::try_mutate(index, |maybe_value| -> DispatchResult { @@ -208,11 +210,12 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_transfer())] pub fn force_transfer( origin: OriginFor, - new: T::AccountId, + new: AccountIdLookupOf, index: T::AccountIndex, freeze: bool, ) -> DispatchResult { ensure_root(origin)?; + let new = T::Lookup::lookup(new)?; Accounts::::mutate(index, |maybe_value| { if let Some((account, amount, _)) = maybe_value.take() { diff --git a/frame/indices/src/tests.rs b/frame/indices/src/tests.rs index 73d591c38bb2f..4e6c59703ca36 100644 --- a/frame/indices/src/tests.rs +++ b/frame/indices/src/tests.rs @@ -22,6 +22,7 @@ use super::{mock::*, *}; use frame_support::{assert_noop, assert_ok}; use pallet_balances::Error as BalancesError; +use sp_runtime::MultiAddress::Id; #[test] fn claiming_should_work() { @@ -60,7 +61,7 @@ fn freezing_should_work() { assert_noop!(Indices::freeze(Some(1).into(), 0), Error::::Permanent); assert_noop!(Indices::free(Some(1).into(), 0), Error::::Permanent); - assert_noop!(Indices::transfer(Some(1).into(), 2, 0), Error::::Permanent); + assert_noop!(Indices::transfer(Some(1).into(), Id(2), 0), Error::::Permanent); }); } @@ -90,9 +91,9 @@ fn reclaim_index_on_accounts_should_work() { fn transfer_index_on_accounts_should_work() { new_test_ext().execute_with(|| { assert_ok!(Indices::claim(Some(1).into(), 0)); - assert_noop!(Indices::transfer(Some(1).into(), 2, 1), Error::::NotAssigned); - assert_noop!(Indices::transfer(Some(2).into(), 3, 0), Error::::NotOwner); - assert_ok!(Indices::transfer(Some(1).into(), 3, 0)); + assert_noop!(Indices::transfer(Some(1).into(), Id(2), 1), Error::::NotAssigned); + assert_noop!(Indices::transfer(Some(2).into(), Id(3), 0), Error::::NotOwner); + assert_ok!(Indices::transfer(Some(1).into(), Id(3), 0)); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::reserved_balance(3), 1); assert_eq!(Indices::lookup_index(0), Some(3)); @@ -103,7 +104,7 @@ fn transfer_index_on_accounts_should_work() { fn force_transfer_index_on_preowned_should_work() { new_test_ext().execute_with(|| { assert_ok!(Indices::claim(Some(1).into(), 0)); - assert_ok!(Indices::force_transfer(Origin::root(), 3, 0, false)); + assert_ok!(Indices::force_transfer(Origin::root(), Id(3), 0, false)); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::reserved_balance(3), 0); assert_eq!(Indices::lookup_index(0), Some(3)); @@ -113,7 +114,7 @@ fn force_transfer_index_on_preowned_should_work() { #[test] fn force_transfer_index_on_free_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Indices::force_transfer(Origin::root(), 3, 0, false)); + assert_ok!(Indices::force_transfer(Origin::root(), Id(3), 0, false)); assert_eq!(Balances::reserved_balance(3), 0); assert_eq!(Indices::lookup_index(0), Some(3)); }); diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 24ecfd5333c66..32e1130f3d944 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -27,6 +27,7 @@ use frame_support::{ traits::{ChangeMembers, Contains, Get, InitializeMembers, SortedMembers}, BoundedVec, }; +use sp_runtime::traits::StaticLookup; use sp_std::prelude::*; pub mod migrations; @@ -35,6 +36,8 @@ pub mod weights; pub use pallet::*; pub use weights::WeightInfo; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -163,8 +166,9 @@ pub mod pallet { /// /// May only be called from `T::AddOrigin`. #[pallet::weight(50_000_000)] - pub fn add_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { + pub fn add_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::AddOrigin::ensure_origin(origin)?; + let who = T::Lookup::lookup(who)?; let mut members = >::get(); let location = members.binary_search(&who).err().ok_or(Error::::AlreadyMember)?; @@ -184,8 +188,9 @@ pub mod pallet { /// /// May only be called from `T::RemoveOrigin`. #[pallet::weight(50_000_000)] - pub fn remove_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { + pub fn remove_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::RemoveOrigin::ensure_origin(origin)?; + let who = T::Lookup::lookup(who)?; let mut members = >::get(); let location = members.binary_search(&who).ok().ok_or(Error::::NotMember)?; @@ -208,10 +213,12 @@ pub mod pallet { #[pallet::weight(50_000_000)] pub fn swap_member( origin: OriginFor, - remove: T::AccountId, - add: T::AccountId, + remove: AccountIdLookupOf, + add: AccountIdLookupOf, ) -> DispatchResult { T::SwapOrigin::ensure_origin(origin)?; + let remove = T::Lookup::lookup(remove)?; + let add = T::Lookup::lookup(add)?; if remove == add { return Ok(()) @@ -259,8 +266,9 @@ pub mod pallet { /// /// Prime membership is passed from the origin account to `new`, if extant. #[pallet::weight(50_000_000)] - pub fn change_key(origin: OriginFor, new: T::AccountId) -> DispatchResult { + pub fn change_key(origin: OriginFor, new: AccountIdLookupOf) -> DispatchResult { let remove = ensure_signed(origin)?; + let new = T::Lookup::lookup(new)?; if remove != new { let mut members = >::get(); @@ -292,8 +300,9 @@ pub mod pallet { /// /// May only be called from `T::PrimeOrigin`. #[pallet::weight(50_000_000)] - pub fn set_prime(origin: OriginFor, who: T::AccountId) -> DispatchResult { + pub fn set_prime(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::PrimeOrigin::ensure_origin(origin)?; + let who = T::Lookup::lookup(who)?; Self::members().binary_search(&who).ok().ok_or(Error::::NotMember)?; Prime::::put(&who); T::MembershipChanged::set_prime(Some(who)); @@ -355,7 +364,8 @@ mod benchmark { assert_ok!(>::reset_members(reset_origin, members.clone())); if let Some(prime) = prime.map(|i| members[i].clone()) { - assert_ok!(>::set_prime(prime_origin, prime)); + let prime_lookup = T::Lookup::unlookup(prime); + assert_ok!(>::set_prime(prime_origin, prime_lookup)); } else { assert_ok!(>::clear_prime(prime_origin)); } @@ -368,8 +378,9 @@ mod benchmark { let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); set_members::(members, None); let new_member = account::("add", m, SEED); + let new_member_lookup = T::Lookup::unlookup(new_member.clone()); }: { - assert_ok!(>::add_member(T::AddOrigin::successful_origin(), new_member.clone())); + assert_ok!(>::add_member(T::AddOrigin::successful_origin(), new_member_lookup)); } verify { assert!(>::get().contains(&new_member)); @@ -385,8 +396,9 @@ mod benchmark { set_members::(members.clone(), Some(members.len() - 1)); let to_remove = members.first().cloned().unwrap(); + let to_remove_lookup = T::Lookup::unlookup(to_remove.clone()); }: { - assert_ok!(>::remove_member(T::RemoveOrigin::successful_origin(), to_remove.clone())); + assert_ok!(>::remove_member(T::RemoveOrigin::successful_origin(), to_remove_lookup)); } verify { assert!(!>::get().contains(&to_remove)); // prime is rejigged @@ -401,12 +413,14 @@ mod benchmark { let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); set_members::(members.clone(), Some(members.len() - 1)); let add = account::("member", m, SEED); + let add_lookup = T::Lookup::unlookup(add.clone()); let remove = members.first().cloned().unwrap(); + let remove_lookup = T::Lookup::unlookup(remove.clone()); }: { assert_ok!(>::swap_member( T::SwapOrigin::successful_origin(), - remove.clone(), - add.clone(), + remove_lookup, + add_lookup, )); } verify { assert!(!>::get().contains(&remove)); @@ -442,9 +456,10 @@ mod benchmark { set_members::(members.clone(), Some(members.len() - 1)); let add = account::("member", m, SEED); + let add_lookup = T::Lookup::unlookup(add.clone()); whitelist!(prime); }: { - assert_ok!(>::change_key(RawOrigin::Signed(prime.clone()).into(), add.clone())); + assert_ok!(>::change_key(RawOrigin::Signed(prime.clone()).into(), add_lookup)); } verify { assert!(!>::get().contains(&prime)); assert!(>::get().contains(&add)); @@ -457,9 +472,10 @@ mod benchmark { let m in 1 .. T::MaxMembers::get(); let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); let prime = members.last().cloned().unwrap(); + let prime_lookup = T::Lookup::unlookup(prime.clone()); set_members::(members, None); }: { - assert_ok!(>::set_prime(T::PrimeOrigin::successful_origin(), prime)); + assert_ok!(>::set_prime(T::PrimeOrigin::successful_origin(), prime_lookup)); } verify { assert!(>::get().is_some()); assert!(::get_prime().is_some()); diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 5da06a24df3e5..8eb6936ec0450 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -47,6 +47,7 @@ type AccountIdOf = ::AccountId; type BalanceOf = <::Currency as Currency>>::Balance; type NegativeImbalanceOf = <::Currency as Currency>>::NegativeImbalance; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; #[frame_support::pallet] pub mod pallet { @@ -193,10 +194,7 @@ pub mod pallet { /// - One event. /// # #[pallet::weight(70_000_000)] - pub fn kill_name( - origin: OriginFor, - target: ::Source, - ) -> DispatchResult { + pub fn kill_name(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; // Figure out who we're meant to be clearing. @@ -225,7 +223,7 @@ pub mod pallet { #[pallet::weight(70_000_000)] pub fn force_name( origin: OriginFor, - target: ::Source, + target: AccountIdLookupOf, name: Vec, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 07f2e9de37dde..427e71af6e8c4 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -46,9 +46,12 @@ pub mod weights; pub use pallet::*; use sp_core::OpaquePeerId as PeerId; +use sp_runtime::traits::StaticLookup; use sp_std::{collections::btree_set::BTreeSet, iter::FromIterator, prelude::*}; pub use weights::WeightInfo; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -211,9 +214,10 @@ pub mod pallet { pub fn add_well_known_node( origin: OriginFor, node: PeerId, - owner: T::AccountId, + owner: AccountIdLookupOf, ) -> DispatchResult { T::AddOrigin::ensure_origin(origin)?; + let owner = T::Lookup::lookup(owner)?; ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); let mut nodes = WellKnownNodes::::get(); @@ -355,9 +359,10 @@ pub mod pallet { pub fn transfer_node( origin: OriginFor, node: PeerId, - owner: T::AccountId, + owner: AccountIdLookupOf, ) -> DispatchResult { let sender = ensure_signed(origin)?; + let owner = T::Lookup::lookup(owner)?; ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); let pre_owner = Owners::::get(&node).ok_or(Error::::NotClaimed)?; diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 6cc589ceb08bd..f4ecb4a9b0ff1 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -31,7 +31,7 @@ use pallet_nomination_pools::{ MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, Pallet as Pools, PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, }; -use sp_runtime::traits::{Bounded, Zero}; +use sp_runtime::traits::{Bounded, StaticLookup, Zero}; use sp_staking::{EraIndex, StakingInterface}; // `frame_benchmarking::benchmarks!` macro needs this use pallet_nomination_pools::Call; @@ -73,13 +73,14 @@ fn create_pool_account( let ed = CurrencyOf::::minimum_balance(); let pool_creator: T::AccountId = create_funded_user_with_balance::("pool_creator", n, ed + balance * 2u32.into()); + let pool_creator_lookup = T::Lookup::unlookup(pool_creator.clone()); Pools::::create( Origin::Signed(pool_creator.clone()).into(), balance, - pool_creator.clone(), - pool_creator.clone(), - pool_creator.clone(), + pool_creator_lookup.clone(), + pool_creator_lookup.clone(), + pool_creator_lookup, ) .unwrap(); @@ -310,9 +311,10 @@ frame_benchmarking::benchmarks! { let scenario = scenario.add_joiner(amount); let member_id = scenario.origin1_member.unwrap().clone(); + let member_id_lookup = T::Lookup::unlookup(member_id.clone()); let all_points = PoolMembers::::get(&member_id).unwrap().points; whitelist_account!(member_id); - }: _(Origin::Signed(member_id.clone()), member_id.clone(), all_points) + }: _(Origin::Signed(member_id.clone()), member_id_lookup, all_points) verify { let bonded_after = T::StakingInterface::active_stake(&scenario.origin1).unwrap(); // We at least went down to the destination bag @@ -382,6 +384,7 @@ frame_benchmarking::benchmarks! { // Add a new member let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); + let joiner_lookup = T::Lookup::unlookup(joiner.clone()); Pools::::join(Origin::Signed(joiner.clone()).into(), min_join_bond, 1) .unwrap(); @@ -408,7 +411,7 @@ frame_benchmarking::benchmarks! { pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); whitelist_account!(joiner); - }: withdraw_unbonded(Origin::Signed(joiner.clone()), joiner.clone(), s) + }: withdraw_unbonded(Origin::Signed(joiner.clone()), joiner_lookup, s) verify { assert_eq!( CurrencyOf::::free_balance(&joiner), @@ -423,6 +426,7 @@ frame_benchmarking::benchmarks! { let min_create_bond = min_create_bond::(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + let depositor_lookup = T::Lookup::unlookup(depositor.clone()); // We set the pool to the destroying state so the depositor can leave BondedPools::::try_mutate(&1, |maybe_bonded_pool| { @@ -465,7 +469,7 @@ frame_benchmarking::benchmarks! { assert!(frame_system::Account::::contains_key(&reward_account)); whitelist_account!(depositor); - }: withdraw_unbonded(Origin::Signed(depositor.clone()), depositor.clone(), s) + }: withdraw_unbonded(Origin::Signed(depositor.clone()), depositor_lookup, s) verify { // Pool removal worked assert!(!pallet_staking::Ledger::::contains_key(&pool_account)); @@ -487,6 +491,7 @@ frame_benchmarking::benchmarks! { create { let min_create_bond = min_create_bond::(); let depositor: T::AccountId = account("depositor", USER_SEED, 0); + let depositor_lookup = T::Lookup::unlookup(depositor.clone()); // Give the depositor some balance to bond CurrencyOf::::make_free_balance_be(&depositor, min_create_bond * 2u32.into()); @@ -499,9 +504,9 @@ frame_benchmarking::benchmarks! { }: _( Origin::Signed(depositor.clone()), min_create_bond, - depositor.clone(), - depositor.clone(), - depositor.clone() + depositor_lookup.clone(), + depositor_lookup.clone(), + depositor_lookup ) verify { assert_eq!(RewardPools::::count(), 1); diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 4a31048fb8d8b..62d0b3ddd55cb 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -282,7 +282,10 @@ use frame_support::{ use scale_info::TypeInfo; use sp_core::U256; use sp_runtime::{ - traits::{AccountIdConversion, Bounded, CheckedAdd, CheckedSub, Convert, Saturating, Zero}, + traits::{ + AccountIdConversion, Bounded, CheckedAdd, CheckedSub, Convert, Saturating, StaticLookup, + Zero, + }, FixedPointNumber, FixedPointOperand, }; use sp_staking::{EraIndex, OnStakerSlash, StakingInterface}; @@ -321,6 +324,8 @@ pub type PoolId = u32; type UnbondingPoolsWithEra = BoundedBTreeMap, TotalUnbondingPools>; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + pub const POINTS_TO_BALANCE_INIT_RATIO: u32 = 1; /// Possible operations on the configuration values of this pallet. @@ -1629,10 +1634,11 @@ pub mod pallet { #[transactional] pub fn unbond( origin: OriginFor, - member_account: T::AccountId, + member_account: AccountIdLookupOf, #[pallet::compact] unbonding_points: BalanceOf, ) -> DispatchResult { let who = ensure_signed(origin)?; + let member_account = T::Lookup::lookup(member_account)?; let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&member_account)?; @@ -1741,10 +1747,11 @@ pub mod pallet { #[transactional] pub fn withdraw_unbonded( origin: OriginFor, - member_account: T::AccountId, + member_account: AccountIdLookupOf, num_slashing_spans: u32, ) -> DispatchResultWithPostInfo { let caller = ensure_signed(origin)?; + let member_account = T::Lookup::lookup(member_account)?; let mut member = PoolMembers::::get(&member_account).ok_or(Error::::PoolMemberNotFound)?; let current_era = T::StakingInterface::current_era(); @@ -1863,11 +1870,14 @@ pub mod pallet { pub fn create( origin: OriginFor, #[pallet::compact] amount: BalanceOf, - root: T::AccountId, - nominator: T::AccountId, - state_toggler: T::AccountId, + root: AccountIdLookupOf, + nominator: AccountIdLookupOf, + state_toggler: AccountIdLookupOf, ) -> DispatchResult { let who = ensure_signed(origin)?; + let root = T::Lookup::lookup(root)?; + let nominator = T::Lookup::lookup(nominator)?; + let state_toggler = T::Lookup::lookup(state_toggler)?; ensure!(amount >= Pallet::::depositor_min_bond(), Error::::MinimumBondNotMet); ensure!( @@ -2461,7 +2471,8 @@ impl Pallet { member: T::AccountId, ) -> DispatchResult { let points = PoolMembers::::get(&member).map(|d| d.active_points()).unwrap_or_default(); - Self::unbond(origin, member, points) + let member_lookup = T::Lookup::unlookup(member); + Self::unbond(origin, member_lookup, points) } } diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index 87017290a3ab9..adaaebb0adc98 100644 --- a/frame/proxy/src/benchmarking.rs +++ b/frame/proxy/src/benchmarking.rs @@ -51,6 +51,7 @@ fn add_announcements( maybe_real: Option, ) -> Result<(), &'static str> { let caller = maybe_who.unwrap_or_else(|| account("caller", 0, SEED)); + let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); let real = if let Some(real) = maybe_real { real @@ -59,16 +60,17 @@ fn add_announcements( T::Currency::make_free_balance_be(&real, BalanceOf::::max_value() / 2u32.into()); Proxy::::add_proxy( RawOrigin::Signed(real.clone()).into(), - caller.clone(), + caller_lookup, T::ProxyType::default(), T::BlockNumber::zero(), )?; real }; + let real_lookup = T::Lookup::unlookup(real); for _ in 0..n { Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), - real.clone(), + real_lookup.clone(), T::CallHasher::hash_of(&("add_announcement", n)), )?; } @@ -83,8 +85,9 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); + let real_lookup = T::Lookup::unlookup(real); let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); - }: _(RawOrigin::Signed(caller), real, Some(T::ProxyType::default()), Box::new(call)) + }: _(RawOrigin::Signed(caller), real_lookup, Some(T::ProxyType::default()), Box::new(call)) verify { assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) } @@ -95,17 +98,19 @@ benchmarks! { // In this case the caller is the "target" proxy let caller: T::AccountId = account("anonymous", 0, SEED); let delegate: T::AccountId = account("target", p - 1, SEED); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); T::Currency::make_free_balance_be(&delegate, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); + let real_lookup = T::Lookup::unlookup(real); let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(delegate.clone()).into(), - real.clone(), + real_lookup.clone(), T::CallHasher::hash_of(&call), )?; add_announcements::(a, Some(delegate.clone()), None)?; - }: _(RawOrigin::Signed(caller), delegate, real, Some(T::ProxyType::default()), Box::new(call)) + }: _(RawOrigin::Signed(caller), delegate_lookup, real_lookup, Some(T::ProxyType::default()), Box::new(call)) verify { assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) } @@ -118,14 +123,15 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); + let real_lookup = T::Lookup::unlookup(real); let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), - real.clone(), + real_lookup.clone(), T::CallHasher::hash_of(&call), )?; add_announcements::(a, Some(caller.clone()), None)?; - }: _(RawOrigin::Signed(caller.clone()), real, T::CallHasher::hash_of(&call)) + }: _(RawOrigin::Signed(caller.clone()), real_lookup, T::CallHasher::hash_of(&call)) verify { let (announcements, _) = Announcements::::get(&caller); assert_eq!(announcements.len() as u32, a); @@ -136,17 +142,19 @@ benchmarks! { let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); + let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); + let real_lookup = T::Lookup::unlookup(real.clone()); let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), - real.clone(), + real_lookup, T::CallHasher::hash_of(&call), )?; add_announcements::(a, Some(caller.clone()), None)?; - }: _(RawOrigin::Signed(real), caller.clone(), T::CallHasher::hash_of(&call)) + }: _(RawOrigin::Signed(real), caller_lookup, T::CallHasher::hash_of(&call)) verify { let (announcements, _) = Announcements::::get(&caller); assert_eq!(announcements.len() as u32, a); @@ -160,10 +168,11 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); + let real_lookup = T::Lookup::unlookup(real.clone()); add_announcements::(a, Some(caller.clone()), None)?; let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); let call_hash = T::CallHasher::hash_of(&call); - }: _(RawOrigin::Signed(caller.clone()), real.clone(), call_hash) + }: _(RawOrigin::Signed(caller.clone()), real_lookup, call_hash) verify { assert_last_event::(Event::Announced { real, proxy: caller, call_hash }.into()); } @@ -228,6 +237,7 @@ benchmarks! { let p in 0 .. (T::MaxProxies::get() - 2); let caller: T::AccountId = whitelisted_caller(); + let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); Pallet::::anonymous( RawOrigin::Signed(whitelisted_caller()).into(), @@ -241,7 +251,7 @@ benchmarks! { add_proxies::(p, Some(anon.clone()))?; ensure!(Proxies::::contains_key(&anon), "anon proxy not created"); - }: _(RawOrigin::Signed(anon.clone()), caller.clone(), T::ProxyType::default(), 0, height, ext_index) + }: _(RawOrigin::Signed(anon.clone()), caller_lookup, T::ProxyType::default(), 0, height, ext_index) verify { assert!(!Proxies::::contains_key(&anon)); } diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 9945626efbeb1..761d530954100 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -45,7 +45,7 @@ use frame_system::{self as system}; use scale_info::TypeInfo; use sp_io::hashing::blake2_256; use sp_runtime::{ - traits::{Dispatchable, Hash, Saturating, TrailingZeroInput, Zero}, + traits::{Dispatchable, Hash, Saturating, StaticLookup, TrailingZeroInput, Zero}, DispatchResult, }; use sp_std::prelude::*; @@ -58,6 +58,8 @@ type CallHashOf = <::CallHasher as Hash>::Output; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + /// The parameters under which a particular account has a proxy relationship with some other /// account. #[derive( @@ -204,11 +206,12 @@ pub mod pallet { })] pub fn proxy( origin: OriginFor, - real: T::AccountId, + real: AccountIdLookupOf, force_proxy_type: Option, call: Box<::Call>, ) -> DispatchResult { let who = ensure_signed(origin)?; + let real = T::Lookup::lookup(real)?; let def = Self::find_proxy(&real, &who, force_proxy_type)?; ensure!(def.delay.is_zero(), Error::::Unannounced); @@ -233,11 +236,12 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::add_proxy(T::MaxProxies::get()))] pub fn add_proxy( origin: OriginFor, - delegate: T::AccountId, + delegate: AccountIdLookupOf, proxy_type: T::ProxyType, delay: T::BlockNumber, ) -> DispatchResult { let who = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; Self::add_proxy_delegate(&who, delegate, proxy_type, delay) } @@ -255,11 +259,12 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_proxy(T::MaxProxies::get()))] pub fn remove_proxy( origin: OriginFor, - delegate: T::AccountId, + delegate: AccountIdLookupOf, proxy_type: T::ProxyType, delay: T::BlockNumber, ) -> DispatchResult { let who = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; Self::remove_proxy_delegate(&who, delegate, proxy_type, delay) } @@ -359,13 +364,14 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::kill_anonymous(T::MaxProxies::get()))] pub fn kill_anonymous( origin: OriginFor, - spawner: T::AccountId, + spawner: AccountIdLookupOf, proxy_type: T::ProxyType, index: u16, #[pallet::compact] height: T::BlockNumber, #[pallet::compact] ext_index: u32, ) -> DispatchResult { let who = ensure_signed(origin)?; + let spawner = T::Lookup::lookup(spawner)?; let when = (height, ext_index); let proxy = Self::anonymous_account(&spawner, &proxy_type, index, Some(when)); @@ -401,10 +407,11 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::announce(T::MaxPending::get(), T::MaxProxies::get()))] pub fn announce( origin: OriginFor, - real: T::AccountId, + real: AccountIdLookupOf, call_hash: CallHashOf, ) -> DispatchResult { let who = ensure_signed(origin)?; + let real = T::Lookup::lookup(real)?; Proxies::::get(&real) .0 .into_iter() @@ -458,10 +465,11 @@ pub mod pallet { ))] pub fn remove_announcement( origin: OriginFor, - real: T::AccountId, + real: AccountIdLookupOf, call_hash: CallHashOf, ) -> DispatchResult { let who = ensure_signed(origin)?; + let real = T::Lookup::lookup(real)?; Self::edit_announcements(&who, |ann| ann.real != real || ann.call_hash != call_hash)?; Ok(()) @@ -489,10 +497,11 @@ pub mod pallet { ))] pub fn reject_announcement( origin: OriginFor, - delegate: T::AccountId, + delegate: AccountIdLookupOf, call_hash: CallHashOf, ) -> DispatchResult { let who = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; Self::edit_announcements(&delegate, |ann| { ann.real != who || ann.call_hash != call_hash })?; @@ -527,12 +536,14 @@ pub mod pallet { })] pub fn proxy_announced( origin: OriginFor, - delegate: T::AccountId, - real: T::AccountId, + delegate: AccountIdLookupOf, + real: AccountIdLookupOf, force_proxy_type: Option, call: Box<::Call>, ) -> DispatchResult { ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + let real = T::Lookup::lookup(real)?; let def = Self::find_proxy(&real, &delegate, force_proxy_type)?; let call_hash = T::CallHasher::hash_of(&call); diff --git a/frame/ranked-collective/src/benchmarking.rs b/frame/ranked-collective/src/benchmarking.rs index ab1a5dc283ca5..611a4ce7334a9 100644 --- a/frame/ranked-collective/src/benchmarking.rs +++ b/frame/ranked-collective/src/benchmarking.rs @@ -33,11 +33,15 @@ fn assert_last_event, I: 'static>(generic_event: >:: fn make_member, I: 'static>(rank: Rank) -> T::AccountId { let who = account::("member", MemberCount::::get(0), SEED); - assert_ok!(Pallet::::add_member(T::PromoteOrigin::successful_origin(), who.clone())); + let who_lookup = T::Lookup::unlookup(who.clone()); + assert_ok!(Pallet::::add_member( + T::PromoteOrigin::successful_origin(), + who_lookup.clone() + )); for _ in 0..rank { assert_ok!(Pallet::::promote_member( T::PromoteOrigin::successful_origin(), - who.clone() + who_lookup.clone() )); } who @@ -46,8 +50,9 @@ fn make_member, I: 'static>(rank: Rank) -> T::AccountId { benchmarks_instance_pallet! { add_member { let who = account::("member", 0, SEED); + let who_lookup = T::Lookup::unlookup(who.clone()); let origin = T::PromoteOrigin::successful_origin(); - let call = Call::::add_member { who: who.clone() }; + let call = Call::::add_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { assert_eq!(MemberCount::::get(0), 1); @@ -59,10 +64,11 @@ benchmarks_instance_pallet! { let rank = r as u16; let first = make_member::(rank); let who = make_member::(rank); + let who_lookup = T::Lookup::unlookup(who.clone()); let last = make_member::(rank); let last_index = (0..=rank).map(|r| IdToIndex::::get(r, &last).unwrap()).collect::>(); let origin = T::DemoteOrigin::successful_origin(); - let call = Call::::remove_member { who: who.clone(), min_rank: rank }; + let call = Call::::remove_member { who: who_lookup, min_rank: rank }; }: { call.dispatch_bypass_filter(origin)? } verify { for r in 0..=rank { @@ -76,8 +82,9 @@ benchmarks_instance_pallet! { let r in 0 .. 10; let rank = r as u16; let who = make_member::(rank); + let who_lookup = T::Lookup::unlookup(who.clone()); let origin = T::PromoteOrigin::successful_origin(); - let call = Call::::promote_member { who: who.clone() }; + let call = Call::::promote_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { assert_eq!(Members::::get(&who).unwrap().rank, rank + 1); @@ -89,10 +96,11 @@ benchmarks_instance_pallet! { let rank = r as u16; let first = make_member::(rank); let who = make_member::(rank); + let who_lookup = T::Lookup::unlookup(who.clone()); let last = make_member::(rank); let last_index = IdToIndex::::get(rank, &last).unwrap(); let origin = T::DemoteOrigin::successful_origin(); - let call = Call::::demote_member { who: who.clone() }; + let call = Call::::demote_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { assert_eq!(Members::::get(&who).map(|x| x.rank), rank.checked_sub(1)); @@ -106,14 +114,15 @@ benchmarks_instance_pallet! { vote { let caller: T::AccountId = whitelisted_caller(); - assert_ok!(Pallet::::add_member(T::PromoteOrigin::successful_origin(), caller.clone())); + let caller_lookup = T::Lookup::unlookup(caller.clone()); + assert_ok!(Pallet::::add_member(T::PromoteOrigin::successful_origin(), caller_lookup.clone())); // Create a poll let class = T::Polls::classes().into_iter().next().unwrap(); let rank = T::MinRankOfClass::convert(class.clone()); for _ in 0..rank { assert_ok!(Pallet::::promote_member( T::PromoteOrigin::successful_origin(), - caller.clone() + caller_lookup.clone() )); } diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 79910c259a7cd..b8eaac9823634 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -43,7 +43,11 @@ use scale_info::TypeInfo; use sp_arithmetic::traits::Saturating; -use sp_runtime::{traits::Convert, ArithmeticError::Overflow, Perbill, RuntimeDebug}; +use sp_runtime::{ + traits::{Convert, StaticLookup}, + ArithmeticError::Overflow, + Perbill, RuntimeDebug, +}; use sp_std::{marker::PhantomData, prelude::*}; use frame_support::{ @@ -109,6 +113,7 @@ impl, I: 'static, M: GetMaxVoters> Tally { pub type TallyOf = Tally>; pub type PollIndexOf = <>::Polls as Polling>>::Index; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; impl, I: 'static, M: GetMaxVoters> VoteTally for Tally { fn new(_: Rank) -> Self { @@ -466,8 +471,9 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::add_member())] - pub fn add_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { + pub fn add_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { let _ = T::PromoteOrigin::ensure_origin(origin)?; + let who = T::Lookup::lookup(who)?; Self::do_add_member(who) } @@ -478,8 +484,9 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::promote_member(0))] - pub fn promote_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { + pub fn promote_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { let max_rank = T::PromoteOrigin::ensure_origin(origin)?; + let who = T::Lookup::lookup(who)?; Self::do_promote_member(who, Some(max_rank)) } @@ -491,8 +498,9 @@ pub mod pallet { /// /// Weight: `O(1)`, less if the member's index is highest in its rank. #[pallet::weight(T::WeightInfo::demote_member(0))] - pub fn demote_member(origin: OriginFor, who: T::AccountId) -> DispatchResult { + pub fn demote_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { let max_rank = T::DemoteOrigin::ensure_origin(origin)?; + let who = T::Lookup::lookup(who)?; let mut record = Self::ensure_member(&who)?; let rank = record.rank; ensure!(max_rank >= rank, Error::::NoPermission); @@ -523,10 +531,11 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_member(*min_rank as u32))] pub fn remove_member( origin: OriginFor, - who: T::AccountId, + who: AccountIdLookupOf, min_rank: Rank, ) -> DispatchResultWithPostInfo { let max_rank = T::DemoteOrigin::ensure_origin(origin)?; + let who = T::Lookup::lookup(who)?; let MemberRecord { rank, .. } = Self::ensure_member(&who)?; ensure!(min_rank >= rank, Error::::InvalidWitness); ensure!(max_rank >= rank, Error::::NoPermission); diff --git a/frame/recovery/src/benchmarking.rs b/frame/recovery/src/benchmarking.rs index 5354de6d10b51..56d5df22d49c5 100644 --- a/frame/recovery/src/benchmarking.rs +++ b/frame/recovery/src/benchmarking.rs @@ -106,22 +106,25 @@ benchmarks! { as_recovered { let caller: T::AccountId = whitelisted_caller(); let recovered_account: T::AccountId = account("recovered_account", 0, SEED); + let recovered_account_lookup = T::Lookup::unlookup(recovered_account.clone()); let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::insert(&caller, &recovered_account); }: _( RawOrigin::Signed(caller), - recovered_account, + recovered_account_lookup, Box::new(call) ) set_recovered { let lost: T::AccountId = whitelisted_caller(); + let lost_lookup = T::Lookup::unlookup(lost.clone()); let rescuer: T::AccountId = whitelisted_caller(); + let rescuer_lookup = T::Lookup::unlookup(rescuer.clone()); }: _( RawOrigin::Root, - lost.clone(), - rescuer.clone() + lost_lookup, + rescuer_lookup ) verify { assert_last_event::( Event::AccountRecovered { @@ -153,11 +156,12 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let lost_account: T::AccountId = account("lost_account", 0, SEED); + let lost_account_lookup = T::Lookup::unlookup(lost_account.clone()); insert_recovery_account::(&caller, &lost_account); }: _( RawOrigin::Signed(caller.clone()), - lost_account.clone() + lost_account_lookup ) verify { assert_last_event::( Event::RecoveryInitiated { @@ -172,7 +176,10 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); let lost_account: T::AccountId = account("lost_account", 0, SEED); + let lost_account_lookup = T::Lookup::unlookup(lost_account.clone()); let rescuer_account: T::AccountId = account("rescuer_account", 0, SEED); + let rescuer_account_lookup = T::Lookup::unlookup(rescuer_account.clone()); + // Create friends let friends = add_caller_and_generate_friends::(caller.clone(), n); @@ -206,8 +213,8 @@ benchmarks! { }: _( RawOrigin::Signed(caller.clone()), - lost_account.clone(), - rescuer_account.clone() + lost_account_lookup, + rescuer_account_lookup ) verify { assert_last_event::( Event::RecoveryVouched { @@ -223,6 +230,7 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); let lost_account: T::AccountId = account("lost_account", 0, SEED); + let lost_account_lookup = T::Lookup::unlookup(lost_account.clone()); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -257,7 +265,7 @@ benchmarks! { >::insert(&lost_account, &caller, recovery_status); }: _( RawOrigin::Signed(caller.clone()), - lost_account.clone() + lost_account_lookup ) verify { assert_last_event::( Event::AccountRecovered { @@ -270,6 +278,7 @@ benchmarks! { close_recovery { let caller: T::AccountId = whitelisted_caller(); let rescuer_account: T::AccountId = account("rescuer_account", 0, SEED); + let rescuer_account_lookup = T::Lookup::unlookup(rescuer_account.clone()); let n in 1 .. T::MaxFriends::get(); @@ -307,7 +316,7 @@ benchmarks! { >::insert(&caller, &rescuer_account, recovery_status); }: _( RawOrigin::Signed(caller.clone()), - rescuer_account.clone() + rescuer_account_lookup ) verify { assert_last_event::( Event::RecoveryClosed { @@ -356,6 +365,7 @@ benchmarks! { cancel_recovered { let caller: T::AccountId = whitelisted_caller(); let account: T::AccountId = account("account", 0, SEED); + let account_lookup = T::Lookup::unlookup(account.clone()); frame_system::Pallet::::inc_providers(&caller); @@ -364,7 +374,7 @@ benchmarks! { Proxy::::insert(&caller, &account); }: _( RawOrigin::Signed(caller), - account + account_lookup ) impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index b839d25e32b47..45260b577f700 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -156,7 +156,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime::traits::{CheckedAdd, CheckedMul, Dispatchable, SaturatedConversion}; +use sp_runtime::traits::{CheckedAdd, CheckedMul, Dispatchable, SaturatedConversion, StaticLookup}; use sp_std::prelude::*; use frame_support::{ @@ -182,6 +182,7 @@ type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type FriendsOf = BoundedVec<::AccountId, ::MaxFriends>; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// An active recovery process. #[derive(Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen)] @@ -382,10 +383,11 @@ pub mod pallet { )})] pub fn as_recovered( origin: OriginFor, - account: T::AccountId, + account: AccountIdLookupOf, call: Box<::Call>, ) -> DispatchResult { let who = ensure_signed(origin)?; + let account = T::Lookup::lookup(account)?; // Check `who` is allowed to make a call on behalf of `account` let target = Self::proxy(&who).ok_or(Error::::NotAllowed)?; ensure!(target == account, Error::::NotAllowed); @@ -405,10 +407,12 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_recovered())] pub fn set_recovered( origin: OriginFor, - lost: T::AccountId, - rescuer: T::AccountId, + lost: AccountIdLookupOf, + rescuer: AccountIdLookupOf, ) -> DispatchResult { ensure_root(origin)?; + let lost = T::Lookup::lookup(lost)?; + let rescuer = T::Lookup::lookup(rescuer)?; // Create the recovery storage item. >::insert(&rescuer, &lost); Self::deposit_event(Event::::AccountRecovered { @@ -486,8 +490,12 @@ pub mod pallet { /// - `account`: The lost account that you want to recover. This account needs to be /// recoverable (i.e. have a recovery configuration). #[pallet::weight(T::WeightInfo::initiate_recovery())] - pub fn initiate_recovery(origin: OriginFor, account: T::AccountId) -> DispatchResult { + pub fn initiate_recovery( + origin: OriginFor, + account: AccountIdLookupOf, + ) -> DispatchResult { let who = ensure_signed(origin)?; + let account = T::Lookup::lookup(account)?; // Check that the account is recoverable ensure!(>::contains_key(&account), Error::::NotRecoverable); // Check that the recovery process has not already been started @@ -528,10 +536,12 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::vouch_recovery(T::MaxFriends::get()))] pub fn vouch_recovery( origin: OriginFor, - lost: T::AccountId, - rescuer: T::AccountId, + lost: AccountIdLookupOf, + rescuer: AccountIdLookupOf, ) -> DispatchResult { let who = ensure_signed(origin)?; + let lost = T::Lookup::lookup(lost)?; + let rescuer = T::Lookup::lookup(rescuer)?; // Get the recovery configuration for the lost account. let recovery_config = Self::recovery_config(&lost).ok_or(Error::::NotRecoverable)?; // Get the active recovery process for the rescuer. @@ -567,8 +577,12 @@ pub mod pallet { /// - `account`: The lost account that you want to claim has been successfully recovered by /// you. #[pallet::weight(T::WeightInfo::claim_recovery(T::MaxFriends::get()))] - pub fn claim_recovery(origin: OriginFor, account: T::AccountId) -> DispatchResult { + pub fn claim_recovery( + origin: OriginFor, + account: AccountIdLookupOf, + ) -> DispatchResult { let who = ensure_signed(origin)?; + let account = T::Lookup::lookup(account)?; // Get the recovery configuration for the lost account let recovery_config = Self::recovery_config(&account).ok_or(Error::::NotRecoverable)?; @@ -610,8 +624,12 @@ pub mod pallet { /// Parameters: /// - `rescuer`: The account trying to rescue this recoverable account. #[pallet::weight(T::WeightInfo::close_recovery(T::MaxFriends::get()))] - pub fn close_recovery(origin: OriginFor, rescuer: T::AccountId) -> DispatchResult { + pub fn close_recovery( + origin: OriginFor, + rescuer: AccountIdLookupOf, + ) -> DispatchResult { let who = ensure_signed(origin)?; + let rescuer = T::Lookup::lookup(rescuer)?; // Take the active recovery process started by the rescuer for this account. let active_recovery = >::take(&who, &rescuer).ok_or(Error::::NotStarted)?; @@ -665,8 +683,12 @@ pub mod pallet { /// Parameters: /// - `account`: The recovered account you are able to call on-behalf-of. #[pallet::weight(T::WeightInfo::cancel_recovered())] - pub fn cancel_recovered(origin: OriginFor, account: T::AccountId) -> DispatchResult { + pub fn cancel_recovered( + origin: OriginFor, + account: AccountIdLookupOf, + ) -> DispatchResult { let who = ensure_signed(origin)?; + let account = T::Lookup::lookup(account)?; // Check `who` is allowed to make a call on behalf of `account` ensure!(Self::proxy(&who) == Some(account), Error::::NotAllowed); Proxy::::remove(&who); diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index abdb9b2acc9b5..aa4f75255b120 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -110,6 +110,7 @@ use sp_std::{fmt::Debug, prelude::*}; type BalanceOf = <>::Currency as Currency<::AccountId>>::Balance; type PoolT = Vec<(::AccountId, Option<>::Score>)>; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// The enum is supplied when refreshing the members set. /// Depending on the enum variant the corresponding associated @@ -346,7 +347,7 @@ pub mod pallet { #[pallet::weight(0)] pub fn kick( origin: OriginFor, - dest: ::Source, + dest: AccountIdLookupOf, index: u32, ) -> DispatchResult { T::KickOrigin::ensure_origin(origin)?; @@ -370,7 +371,7 @@ pub mod pallet { #[pallet::weight(0)] pub fn score( origin: OriginFor, - dest: ::Source, + dest: AccountIdLookupOf, index: u32, score: T::Score, ) -> DispatchResult { diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 2a6428e754b9d..ec4cca1813ec6 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -281,6 +281,7 @@ type BalanceOf = type NegativeImbalanceOf = <>::Currency as Currency< ::AccountId, >>::NegativeImbalance; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// A vote by a member on a candidate application. #[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] @@ -823,11 +824,12 @@ pub mod pallet { #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn vouch( origin: OriginFor, - who: T::AccountId, + who: AccountIdLookupOf, value: BalanceOf, tip: BalanceOf, ) -> DispatchResult { let voucher = ensure_signed(origin)?; + let who = T::Lookup::lookup(who)?; // Check user is not suspended. ensure!(!>::contains_key(&who), Error::::Suspended); ensure!(!>::contains_key(&who), Error::::Suspended); @@ -914,7 +916,7 @@ pub mod pallet { #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn vote( origin: OriginFor, - candidate: ::Source, + candidate: AccountIdLookupOf, approve: bool, ) -> DispatchResult { let voter = ensure_signed(origin)?; @@ -1026,11 +1028,12 @@ pub mod pallet { #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn found( origin: OriginFor, - founder: T::AccountId, + founder: AccountIdLookupOf, max_members: u32, rules: Vec, ) -> DispatchResult { T::FounderSetOrigin::ensure_origin(origin)?; + let founder = T::Lookup::lookup(founder)?; ensure!(!>::exists(), Error::::AlreadyFounded); ensure!(max_members > 1, Error::::MaxMembers); // This should never fail in the context of this function... @@ -1104,10 +1107,11 @@ pub mod pallet { #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn judge_suspended_member( origin: OriginFor, - who: T::AccountId, + who: AccountIdLookupOf, forgive: bool, ) -> DispatchResult { T::SuspensionJudgementOrigin::ensure_origin(origin)?; + let who = T::Lookup::lookup(who)?; ensure!(>::contains_key(&who), Error::::NotSuspended); if forgive { @@ -1180,10 +1184,11 @@ pub mod pallet { #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn judge_suspended_candidate( origin: OriginFor, - who: T::AccountId, + who: AccountIdLookupOf, judgement: Judgement, ) -> DispatchResult { T::SuspensionJudgementOrigin::ensure_origin(origin)?; + let who = T::Lookup::lookup(who)?; if let Some((value, kind)) = >::get(&who) { match judgement { Judgement::Approve => { diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 12de0ff9cc665..2d5943b51758d 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -83,7 +83,7 @@ pub fn create_validator_with_nominators( let validator_prefs = ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }; Staking::::validate(RawOrigin::Signed(v_controller).into(), validator_prefs)?; - let stash_lookup: ::Source = T::Lookup::unlookup(v_stash.clone()); + let stash_lookup = T::Lookup::unlookup(v_stash.clone()); points_total += 10; points_individual.push((v_stash.clone(), 10)); @@ -217,8 +217,7 @@ benchmarks! { bond { let stash = create_funded_user::("stash", USER_SEED, 100); let controller = create_funded_user::("controller", USER_SEED, 100); - let controller_lookup: ::Source - = T::Lookup::unlookup(controller.clone()); + let controller_lookup = T::Lookup::unlookup(controller.clone()); let reward_destination = RewardDestination::Staked; let amount = T::Currency::minimum_balance() * 10u32.into(); whitelist_account!(stash); @@ -365,7 +364,7 @@ benchmarks! { 100, Default::default(), )?; - let stash_lookup: ::Source = T::Lookup::unlookup(stash.clone()); + let stash_lookup = T::Lookup::unlookup(stash.clone()); // they start validating. Staking::::validate(RawOrigin::Signed(controller.clone()).into(), Default::default())?; diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index ab0ab685e6911..38466c8cb1d62 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -309,7 +309,7 @@ use frame_support::{ use scale_info::TypeInfo; use sp_runtime::{ curve::PiecewiseLinear, - traits::{AtLeast32BitUnsigned, Convert, Saturating, Zero}, + traits::{AtLeast32BitUnsigned, Convert, Saturating, StaticLookup, Zero}, Perbill, Perquintill, RuntimeDebug, }; use sp_staking::{ @@ -347,6 +347,8 @@ type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + parameter_types! { pub MaxUnlockingChunks: u32 = 32; } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 4ce96ab68b11a..1f11f0ff00ac1 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -40,10 +40,10 @@ mod impls; pub use impls::*; use crate::{ - slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints, Exposure, - Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, Releases, - RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, - ValidatorPrefs, + slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout, + EraRewardPoints, Exposure, Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, + PositiveImbalanceOf, Releases, RewardDestination, SessionInterface, StakingLedger, + UnappliedSlash, UnlockChunk, ValidatorPrefs, }; const STAKING_ID: LockIdentifier = *b"staking "; @@ -768,7 +768,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::bond())] pub fn bond( origin: OriginFor, - controller: ::Source, + controller: AccountIdLookupOf, #[pallet::compact] value: BalanceOf, payee: RewardDestination, ) -> DispatchResult { @@ -1055,7 +1055,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::nominate(targets.len() as u32))] pub fn nominate( origin: OriginFor, - targets: Vec<::Source>, + targets: Vec>, ) -> DispatchResult { let controller = ensure_signed(origin)?; @@ -1175,7 +1175,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_controller())] pub fn set_controller( origin: OriginFor, - controller: ::Source, + controller: AccountIdLookupOf, ) -> DispatchResult { let stash = ensure_signed(origin)?; let old_controller = Self::bonded(&stash).ok_or(Error::::NotStash)?; @@ -1521,10 +1521,7 @@ pub mod pallet { /// Note: Making this call only makes sense if you first set the validator preferences to /// block any further nominations. #[pallet::weight(T::WeightInfo::kick(who.len() as u32))] - pub fn kick( - origin: OriginFor, - who: Vec<::Source>, - ) -> DispatchResult { + pub fn kick(origin: OriginFor, who: Vec>) -> DispatchResult { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let stash = &ledger.stash; diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index ba67292ddc434..0e0ac76523471 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -78,8 +78,7 @@ pub fn create_stash_controller( ) -> Result<(T::AccountId, T::AccountId), &'static str> { let stash = create_funded_user::("stash", n, balance_factor); let controller = create_funded_user::("controller", n, balance_factor); - let controller_lookup: ::Source = - T::Lookup::unlookup(controller.clone()); + let controller_lookup = T::Lookup::unlookup(controller.clone()); let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into(); Staking::::bond( RawOrigin::Signed(stash.clone()).into(), @@ -98,8 +97,7 @@ pub fn create_stash_controller_with_balance( ) -> Result<(T::AccountId, T::AccountId), &'static str> { let stash = create_funded_user_with_balance::("stash", n, balance); let controller = create_funded_user_with_balance::("controller", n, balance); - let controller_lookup: ::Source = - T::Lookup::unlookup(controller.clone()); + let controller_lookup = T::Lookup::unlookup(controller.clone()); Staking::::bond( RawOrigin::Signed(stash.clone()).into(), @@ -120,8 +118,7 @@ pub fn create_stash_and_dead_controller( let stash = create_funded_user::("stash", n, balance_factor); // controller has no funds let controller = create_funded_user::("controller", n, 0); - let controller_lookup: ::Source = - T::Lookup::unlookup(controller.clone()); + let controller_lookup = T::Lookup::unlookup(controller.clone()); let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into(); Staking::::bond( RawOrigin::Signed(stash.clone()).into(), @@ -136,7 +133,7 @@ pub fn create_stash_and_dead_controller( pub fn create_validators( max: u32, balance_factor: u32, -) -> Result::Source>, &'static str> { +) -> Result>, &'static str> { create_validators_with_seed::(max, balance_factor, 0) } @@ -145,15 +142,15 @@ pub fn create_validators_with_seed( max: u32, balance_factor: u32, seed: u32, -) -> Result::Source>, &'static str> { - let mut validators: Vec<::Source> = Vec::with_capacity(max as usize); +) -> Result>, &'static str> { + let mut validators: Vec> = Vec::with_capacity(max as usize); for i in 0..max { let (stash, controller) = create_stash_controller::(i + seed, balance_factor, RewardDestination::Staked)?; let validator_prefs = ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }; Staking::::validate(RawOrigin::Signed(controller).into(), validator_prefs)?; - let stash_lookup: ::Source = T::Lookup::unlookup(stash); + let stash_lookup = T::Lookup::unlookup(stash); validators.push(stash_lookup); } Ok(validators) @@ -180,11 +177,10 @@ pub fn create_validators_with_nominators_for_era( edge_per_nominator: usize, randomize_stake: bool, to_nominate: Option, -) -> Result::Source>, &'static str> { +) -> Result>, &'static str> { clear_validators_and_nominators::(); - let mut validators_stash: Vec<::Source> = - Vec::with_capacity(validators as usize); + let mut validators_stash: Vec> = Vec::with_capacity(validators as usize); let mut rng = ChaChaRng::from_seed(SEED.using_encoded(blake2_256)); // Create validators @@ -195,8 +191,7 @@ pub fn create_validators_with_nominators_for_era( let validator_prefs = ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }; Staking::::validate(RawOrigin::Signed(v_controller.clone()).into(), validator_prefs)?; - let stash_lookup: ::Source = - T::Lookup::unlookup(v_stash.clone()); + let stash_lookup = T::Lookup::unlookup(v_stash.clone()); validators_stash.push(stash_lookup.clone()); } @@ -211,7 +206,7 @@ pub fn create_validators_with_nominators_for_era( // Have them randomly validate let mut available_validators = validator_chosen.clone(); - let mut selected_validators: Vec<::Source> = + let mut selected_validators: Vec> = Vec::with_capacity(edge_per_nominator); for _ in 0..validators.min(edge_per_nominator as u32) { diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index a47b5a79bd017..07fdc56e82da6 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -104,6 +104,8 @@ mod tests; pub use pallet::*; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + #[frame_support::pallet] pub mod pallet { use super::{DispatchResult, *}; @@ -192,7 +194,7 @@ pub mod pallet { #[pallet::weight(0)] pub fn set_key( origin: OriginFor, - new: ::Source, + new: AccountIdLookupOf, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; @@ -228,7 +230,7 @@ pub mod pallet { })] pub fn sudo_as( origin: OriginFor, - who: ::Source, + who: AccountIdLookupOf, call: Box<::Call>, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 4c14cb4de94e1..4956e2a095688 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -92,18 +92,20 @@ benchmarks_instance_pallet! { report_awesome { let r in 0 .. T::MaximumReasonLength::get(); let (caller, reason, awesome_person) = setup_awesome::(r); + let awesome_person_lookup = T::Lookup::unlookup(awesome_person); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: _(RawOrigin::Signed(caller), reason, awesome_person) + }: _(RawOrigin::Signed(caller), reason, awesome_person_lookup) retract_tip { let r = T::MaximumReasonLength::get(); let (caller, reason, awesome_person) = setup_awesome::(r); + let awesome_person_lookup = T::Lookup::unlookup(awesome_person.clone()); TipsMod::::report_awesome( RawOrigin::Signed(caller.clone()).into(), reason.clone(), - awesome_person.clone() + awesome_person_lookup )?; let reason_hash = T::Hashing::hash(&reason[..]); let hash = T::Hashing::hash_of(&(&reason_hash, &awesome_person)); @@ -117,19 +119,21 @@ benchmarks_instance_pallet! { let t in 1 .. T::Tippers::max_len() as u32; let (caller, reason, beneficiary, value) = setup_tip::(r, t)?; + let beneficiary_lookup = T::Lookup::unlookup(beneficiary); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: _(RawOrigin::Signed(caller), reason, beneficiary, value) + }: _(RawOrigin::Signed(caller), reason, beneficiary_lookup, value) tip { let t in 1 .. T::Tippers::max_len() as u32; let (member, reason, beneficiary, value) = setup_tip::(0, t)?; + let beneficiary_lookup = T::Lookup::unlookup(beneficiary.clone()); let value = T::Currency::minimum_balance().saturating_mul(100u32.into()); TipsMod::::tip_new( RawOrigin::Signed(member).into(), reason.clone(), - beneficiary.clone(), + beneficiary_lookup, value )?; let reason_hash = T::Hashing::hash(&reason[..]); @@ -150,11 +154,12 @@ benchmarks_instance_pallet! { // Set up a new tip proposal let (member, reason, beneficiary, value) = setup_tip::(0, t)?; + let beneficiary_lookup = T::Lookup::unlookup(beneficiary.clone()); let value = T::Currency::minimum_balance().saturating_mul(100u32.into()); TipsMod::::tip_new( RawOrigin::Signed(member).into(), reason.clone(), - beneficiary.clone(), + beneficiary_lookup, value )?; @@ -179,11 +184,12 @@ benchmarks_instance_pallet! { // Set up a new tip proposal let (member, reason, beneficiary, value) = setup_tip::(0, t)?; + let beneficiary_lookup = T::Lookup::unlookup(beneficiary.clone()); let value = T::Currency::minimum_balance().saturating_mul(100u32.into()); TipsMod::::tip_new( RawOrigin::Signed(member).into(), reason.clone(), - beneficiary.clone(), + beneficiary_lookup, value )?; diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index 71af87b42b55b..a4697284e38a0 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -61,7 +61,7 @@ pub mod migrations; pub mod weights; use sp_runtime::{ - traits::{AccountIdConversion, BadOrigin, Hash, TrailingZeroInput, Zero}, + traits::{AccountIdConversion, BadOrigin, Hash, StaticLookup, TrailingZeroInput, Zero}, Percent, RuntimeDebug, }; use sp_std::prelude::*; @@ -80,6 +80,7 @@ pub use weights::WeightInfo; pub type BalanceOf = pallet_treasury::BalanceOf; pub type NegativeImbalanceOf = pallet_treasury::NegativeImbalanceOf; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// An open tipping "motion". Retains all details of a tip including information on the finder /// and the members who have voted. @@ -237,9 +238,10 @@ pub mod pallet { pub fn report_awesome( origin: OriginFor, reason: Vec, - who: T::AccountId, + who: AccountIdLookupOf, ) -> DispatchResult { let finder = ensure_signed(origin)?; + let who = T::Lookup::lookup(who)?; ensure!( reason.len() <= T::MaximumReasonLength::get() as usize, @@ -331,10 +333,11 @@ pub mod pallet { pub fn tip_new( origin: OriginFor, reason: Vec, - who: T::AccountId, + who: AccountIdLookupOf, #[pallet::compact] tip_value: BalanceOf, ) -> DispatchResult { let tipper = ensure_signed(origin)?; + let who = T::Lookup::lookup(who)?; ensure!(T::Tippers::contains(&tipper), BadOrigin); let reason_hash = T::Hashing::hash(&reason[..]); ensure!(!Reasons::::contains_key(&reason_hash), Error::::AlreadyKnown); diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index ed30b2f7358e5..b2b670d86f07c 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -34,7 +34,7 @@ const SEED: u32 = 0; // Create the pre-requisite information needed to create a treasury `propose_spend`. fn setup_proposal, I: 'static>( u: u32, -) -> (T::AccountId, BalanceOf, ::Source) { +) -> (T::AccountId, BalanceOf, AccountIdLookupOf) { let caller = account("caller", u, SEED); let value: BalanceOf = T::ProposalBondMinimum::get().saturating_mul(100u32.into()); let _ = T::Currency::make_free_balance_be(&caller, value); diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 6730f985b16e0..ed38177e1c499 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -93,6 +93,7 @@ pub type PositiveImbalanceOf = <>::Currency as Currenc pub type NegativeImbalanceOf = <>::Currency as Currency< ::AccountId, >>::NegativeImbalance; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// A trait to allow the Treasury Pallet to spend it's funds for other purposes. /// There is an expectation that the implementer of this trait will correctly manage @@ -338,7 +339,7 @@ pub mod pallet { pub fn propose_spend( origin: OriginFor, #[pallet::compact] value: BalanceOf, - beneficiary: ::Source, + beneficiary: AccountIdLookupOf, ) -> DispatchResult { let proposer = ensure_signed(origin)?; let beneficiary = T::Lookup::lookup(beneficiary)?; @@ -419,7 +420,7 @@ pub mod pallet { pub fn spend( origin: OriginFor, #[pallet::compact] amount: BalanceOf, - beneficiary: ::Source, + beneficiary: AccountIdLookupOf, ) -> DispatchResult { let max_amount = T::SpendOrigin::ensure_origin(origin)?; let beneficiary = T::Lookup::lookup(beneficiary)?; diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 86247fb964ff5..8aa1512883448 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -37,7 +37,7 @@ use crate::Pallet as Uniques; const SEED: u32 = 0; fn create_collection, I: 'static>( -) -> (T::CollectionId, T::AccountId, ::Source) { +) -> (T::CollectionId, T::AccountId, AccountIdLookupOf) { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); let collection = T::Helper::collection(0); @@ -49,8 +49,7 @@ fn create_collection, I: 'static>( (collection, caller, caller_lookup) } -fn add_collection_metadata, I: 'static>( -) -> (T::AccountId, ::Source) { +fn add_collection_metadata, I: 'static>() -> (T::AccountId, AccountIdLookupOf) { let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; if caller != whitelisted_caller() { whitelist_account!(caller); @@ -68,7 +67,7 @@ fn add_collection_metadata, I: 'static>( fn mint_item, I: 'static>( index: u16, -) -> (T::ItemId, T::AccountId, ::Source) { +) -> (T::ItemId, T::AccountId, AccountIdLookupOf) { let caller = Collection::::get(T::Helper::collection(0)).unwrap().admin; if caller != whitelisted_caller() { whitelist_account!(caller); @@ -87,7 +86,7 @@ fn mint_item, I: 'static>( fn add_item_metadata, I: 'static>( item: T::ItemId, -) -> (T::AccountId, ::Source) { +) -> (T::AccountId, AccountIdLookupOf) { let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; if caller != whitelisted_caller() { whitelist_account!(caller); @@ -106,7 +105,7 @@ fn add_item_metadata, I: 'static>( fn add_item_attribute, I: 'static>( item: T::ItemId, -) -> (BoundedVec, T::AccountId, ::Source) { +) -> (BoundedVec, T::AccountId, AccountIdLookupOf) { let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; if caller != whitelisted_caller() { whitelist_account!(caller); diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index b25fb2f87ea97..de5a774d16061 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -60,6 +60,8 @@ pub use pallet::*; pub use types::*; pub use weights::WeightInfo; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -463,10 +465,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::create())] - pub fn create( - origin: OriginFor, - admin: ::Source, - ) -> DispatchResult { + pub fn create(origin: OriginFor, admin: AccountIdLookupOf) -> DispatchResult { let collection = NextCollectionId::::get(); let owner = T::CreateOrigin::ensure_origin(origin, &collection)?; @@ -501,7 +500,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_create())] pub fn force_create( origin: OriginFor, - owner: ::Source, + owner: AccountIdLookupOf, free_holding: bool, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; @@ -599,7 +598,7 @@ pub mod pallet { origin: OriginFor, collection: T::CollectionId, item: T::ItemId, - owner: ::Source, + owner: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; let owner = T::Lookup::lookup(owner)?; @@ -628,7 +627,7 @@ pub mod pallet { origin: OriginFor, collection: T::CollectionId, item: T::ItemId, - check_owner: Option<::Source>, + check_owner: Option>, ) -> DispatchResult { let origin = ensure_signed(origin)?; let check_owner = check_owner.map(T::Lookup::lookup).transpose()?; @@ -664,7 +663,7 @@ pub mod pallet { origin: OriginFor, collection: T::CollectionId, item: T::ItemId, - dest: ::Source, + dest: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; @@ -876,7 +875,7 @@ pub mod pallet { pub fn transfer_ownership( origin: OriginFor, collection: T::CollectionId, - owner: ::Source, + owner: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; let owner = T::Lookup::lookup(owner)?; @@ -924,9 +923,9 @@ pub mod pallet { pub fn set_team( origin: OriginFor, collection: T::CollectionId, - issuer: ::Source, - admin: ::Source, - freezer: ::Source, + issuer: AccountIdLookupOf, + admin: AccountIdLookupOf, + freezer: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; let issuer = T::Lookup::lookup(issuer)?; @@ -962,7 +961,7 @@ pub mod pallet { origin: OriginFor, collection: T::CollectionId, item: T::ItemId, - delegate: ::Source, + delegate: AccountIdLookupOf, ) -> DispatchResult { let maybe_check: Option = T::ForceOrigin::try_origin(origin) .map(|_| None) @@ -1015,7 +1014,7 @@ pub mod pallet { origin: OriginFor, collection: T::CollectionId, item: T::ItemId, - maybe_check_delegate: Option<::Source>, + maybe_check_delegate: Option>, ) -> DispatchResult { let maybe_check: Option = T::ForceOrigin::try_origin(origin) .map(|_| None) @@ -1066,10 +1065,10 @@ pub mod pallet { pub fn force_item_status( origin: OriginFor, collection: T::CollectionId, - owner: ::Source, - issuer: ::Source, - admin: ::Source, - freezer: ::Source, + owner: AccountIdLookupOf, + issuer: AccountIdLookupOf, + admin: AccountIdLookupOf, + freezer: AccountIdLookupOf, free_holding: bool, is_frozen: bool, ) -> DispatchResult { @@ -1507,7 +1506,7 @@ pub mod pallet { collection: T::CollectionId, item: T::ItemId, price: Option>, - whitelisted_buyer: Option<::Source>, + whitelisted_buyer: Option>, ) -> DispatchResult { let origin = ensure_signed(origin)?; let whitelisted_buyer = whitelisted_buyer.map(T::Lookup::lookup).transpose()?; diff --git a/frame/vesting/src/benchmarking.rs b/frame/vesting/src/benchmarking.rs index 2b8150e995240..dde5fe3ac7561 100644 --- a/frame/vesting/src/benchmarking.rs +++ b/frame/vesting/src/benchmarking.rs @@ -42,7 +42,7 @@ fn add_locks(who: &T::AccountId, n: u8) { } fn add_vesting_schedules( - target: ::Source, + target: AccountIdLookupOf, n: u32, ) -> Result, &'static str> { let min_transfer = T::MinVestedTransfer::get(); @@ -52,7 +52,7 @@ fn add_vesting_schedules( let starting_block = 1u32; let source: T::AccountId = account("source", 0, SEED); - let source_lookup: ::Source = T::Lookup::unlookup(source.clone()); + let source_lookup = T::Lookup::unlookup(source.clone()); T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); System::::set_block_number(T::BlockNumber::zero()); @@ -81,7 +81,7 @@ benchmarks! { let s in 1 .. T::MAX_VESTING_SCHEDULES; let caller: T::AccountId = whitelisted_caller(); - let caller_lookup: ::Source = T::Lookup::unlookup(caller.clone()); + let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); @@ -109,7 +109,7 @@ benchmarks! { let s in 1 .. T::MAX_VESTING_SCHEDULES; let caller: T::AccountId = whitelisted_caller(); - let caller_lookup: ::Source = T::Lookup::unlookup(caller.clone()); + let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); @@ -137,7 +137,7 @@ benchmarks! { let s in 1 .. T::MAX_VESTING_SCHEDULES; let other: T::AccountId = account("other", 0, SEED); - let other_lookup: ::Source = T::Lookup::unlookup(other.clone()); + let other_lookup = T::Lookup::unlookup(other.clone()); add_locks::(&other, l as u8); let expected_balance = add_vesting_schedules::(other_lookup.clone(), s)?; @@ -166,7 +166,7 @@ benchmarks! { let s in 1 .. T::MAX_VESTING_SCHEDULES; let other: T::AccountId = account("other", 0, SEED); - let other_lookup: ::Source = T::Lookup::unlookup(other.clone()); + let other_lookup = T::Lookup::unlookup(other.clone()); add_locks::(&other, l as u8); add_vesting_schedules::(other_lookup.clone(), s)?; @@ -198,7 +198,7 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let target: T::AccountId = account("target", 0, SEED); - let target_lookup: ::Source = T::Lookup::unlookup(target.clone()); + let target_lookup = T::Lookup::unlookup(target.clone()); // Give target existing locks add_locks::(&target, l as u8); // Add one vesting schedules. @@ -232,11 +232,11 @@ benchmarks! { let s in 0 .. T::MAX_VESTING_SCHEDULES - 1; let source: T::AccountId = account("source", 0, SEED); - let source_lookup: ::Source = T::Lookup::unlookup(source.clone()); + let source_lookup = T::Lookup::unlookup(source.clone()); T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); let target: T::AccountId = account("target", 0, SEED); - let target_lookup: ::Source = T::Lookup::unlookup(target.clone()); + let target_lookup = T::Lookup::unlookup(target.clone()); // Give target existing locks add_locks::(&target, l as u8); // Add one less than max vesting schedules @@ -270,7 +270,7 @@ benchmarks! { let s in 2 .. T::MAX_VESTING_SCHEDULES; let caller: T::AccountId = account("caller", 0, SEED); - let caller_lookup: ::Source = T::Lookup::unlookup(caller.clone()); + let caller_lookup = T::Lookup::unlookup(caller.clone()); // Give target existing locks. add_locks::(&caller, l as u8); // Add max vesting schedules. @@ -320,7 +320,7 @@ benchmarks! { let test_dest: T::AccountId = account("test_dest", 0, SEED); let caller: T::AccountId = account("caller", 0, SEED); - let caller_lookup: ::Source = T::Lookup::unlookup(caller.clone()); + let caller_lookup = T::Lookup::unlookup(caller.clone()); // Give target other locks. add_locks::(&caller, l as u8); // Add max vesting schedules. diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 9fb7eb8037916..8ac625e775e4f 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -84,6 +84,7 @@ type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type MaxLocksOf = <::Currency as LockableCurrency<::AccountId>>::MaxLocks; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; const VESTING_ID: LockIdentifier = *b"vesting "; @@ -321,10 +322,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::vest_other_locked(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) .max(T::WeightInfo::vest_other_unlocked(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES)) )] - pub fn vest_other( - origin: OriginFor, - target: ::Source, - ) -> DispatchResult { + pub fn vest_other(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { ensure_signed(origin)?; let who = T::Lookup::lookup(target)?; Self::do_vest(who) @@ -352,7 +350,7 @@ pub mod pallet { )] pub fn vested_transfer( origin: OriginFor, - target: ::Source, + target: AccountIdLookupOf, schedule: VestingInfo, T::BlockNumber>, ) -> DispatchResult { let transactor = ensure_signed(origin)?; @@ -383,8 +381,8 @@ pub mod pallet { )] pub fn force_vested_transfer( origin: OriginFor, - source: ::Source, - target: ::Source, + source: AccountIdLookupOf, + target: AccountIdLookupOf, schedule: VestingInfo, T::BlockNumber>, ) -> DispatchResult { ensure_root(origin)?; @@ -494,8 +492,8 @@ impl Pallet { // Execute a vested transfer from `source` to `target` with the given `schedule`. fn do_vested_transfer( - source: ::Source, - target: ::Source, + source: AccountIdLookupOf, + target: AccountIdLookupOf, schedule: VestingInfo, T::BlockNumber>, ) -> DispatchResult { // Validate user inputs. From 00cc5f104176fac6f5a624bced22a2192c7c0470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 18 Aug 2022 20:59:22 +0200 Subject: [PATCH 1075/1472] Introduce trie level cache and remove state cache (#11407) * trie state cache * Also cache missing access on read. * fix comp * bis * fix * use has_lru * remove local storage cache on size 0. * No cache. * local cache only * trie cache and local cache * storage cache (with local) * trie cache no local cache * Add state access benchmark * Remove warnings etc * Add trie cache benchmark * No extra "clone" required * Change benchmark to use multiple blocks * Use patches * Integrate shitty implementation * More stuff * Revert "Merge branch 'master' into trie_state_cache" This reverts commit 2c1886d2410f3351a1eb5d2d7e930a05fe0ad796, reversing changes made to 540b4fd0f6bf8157f5402f0095f78f0ed893c57b. * Improve benchmark * Adapt to latest changes * Adapt to changes in trie * Add a test that uses iterator * Start fixing it * Remove obsolete file * Make it compile * Start rewriting the trie node cache * More work on the cache * More docs and code etc * Make data cache an optional * Tests * Remove debug stuff * Recorder * Some docs and a simple test for the recorder * Compile fixes * Make it compile * More fixes * More fixes * Fix fix fix * Make sure cache and recorder work together for basic stuff * Test that data caching and recording works * Test `TrieDBMut` with caching * Try something * Fixes, fixes, fixes * Forward the recorder * Make it compile * Use recorder in more places * Switch to new `with_optional_recorder` fn * Refactor and cleanups * Move `ProvingBackend` tests * Simplify * Move over all functionality to the essence * Fix compilation * Implement estimate encoded size for StorageProof * Start using the `cache` everywhere * Use the cache everywhere * Fix compilation * Fix tests * Adds `TrieBackendBuilder` and enhances the tests * Ensure that recorder drain checks that values are found as expected * Switch over to `TrieBackendBuilder` * Start fixing the problem with child tries and recording * Fix recording of child tries * Make it compile * Overwrite `storage_hash` in `TrieBackend` * Add `storage_cache` to the benchmarks * Fix `no_std` build * Speed up cache lookup * Extend the state access benchmark to also hash a runtime * Fix build * Fix compilation * Rewrite value cache * Add lru cache * Ensure that the cache lru works * Value cache should not be optional * Add support for keeping the shared node cache in its bounds * Make the cache configurable * Check that the cache respects the bounds * Adds a new test * Fixes * Docs and some renamings * More docs * Start using the new recorder * Fix more code * Take `self` argument * Remove warnings * Fix benchmark * Fix accounting * Rip off the state cache * Start fixing fallout after removing the state cache * Make it compile after trie changes * Fix test * Add some logging * Some docs * Some fixups and clean ups * Fix benchmark * Remove unneeded file * Use git for patching * Make CI happy * Update primitives/trie/Cargo.toml Co-authored-by: Koute * Update primitives/state-machine/src/trie_backend.rs Co-authored-by: cheme * Introduce new `AsTrieBackend` trait * Make the LocalTrieCache not clonable * Make it work in no_std and add docs * Remove duplicate dependency * Switch to ahash for better performance * Speedup value cache merge * Output errors on underflow * Ensure the internal LRU map doesn't grow too much * Use const fn to calculate the value cache element size * Remove cache configuration * Fix * Clear the cache in between for more testing * Try to come up with a failing test case * Make the test fail * Fix the child trie recording * Make everything compile after the changes to trie * Adapt to latest trie-db changes * Fix on stable * Update primitives/trie/src/cache.rs Co-authored-by: cheme * Fix wrong merge * Docs * Fix warnings * Cargo.lock * Bump pin-project * Fix warnings * Switch to released crate version * More fixes * Make clippy and rustdocs happy * More clippy * Print error when using deprecated `--state-cache-size` * :facepalm: * Fixes * Fix storage_hash linkings * Update client/rpc/src/dev/mod.rs Co-authored-by: Arkadiy Paronyan * Review feedback * encode bound * Rework the shared value cache Instead of using a `u64` to represent the key we now use an `Arc<[u8]>`. This arc is also stored in some extra `HashSet`. We store the key are in an extra `HashSet` to de-duplicate the keys accross different storage roots. When the latest key usage is dropped in the lru, we also remove the key from the `HashSet`. * Improve of the cache by merging the old and new solution * FMT * Please stop coming back all the time :crying: * Update primitives/trie/src/cache/shared_cache.rs Co-authored-by: Arkadiy Paronyan * Fixes * Make clippy happy * Ensure we don't deadlock * Only use one lock to simplify the code * Do not depend on `Hasher` * Fix tests * FMT * Clippy :facepalm: Co-authored-by: cheme Co-authored-by: Koute Co-authored-by: Arkadiy Paronyan --- Cargo.lock | 32 +- bin/node/bench/src/generator.rs | 5 +- bin/node/bench/src/trie.rs | 7 +- bin/node/cli/benches/block_production.rs | 3 +- bin/node/cli/benches/transaction_pool.rs | 3 +- bin/node/testing/src/bench.rs | 3 +- client/api/src/backend.rs | 10 +- .../basic-authorship/src/basic_authorship.rs | 21 +- client/cli/src/commands/chain_info_cmd.rs | 3 +- client/cli/src/config.rs | 17 +- client/cli/src/params/import_params.rs | 24 +- client/db/Cargo.toml | 12 +- client/db/benches/state_access.rs | 312 ++++++ client/db/src/bench.rs | 107 ++- client/db/src/lib.rs | 181 ++-- client/db/src/record_stats_state.rs | 230 +++++ client/rpc-api/src/dev/error.rs | 5 + client/service/src/builder.rs | 3 +- client/service/src/client/call_executor.rs | 21 +- client/service/src/client/client.rs | 6 +- client/service/src/config.rs | 8 +- client/service/test/src/client/mod.rs | 6 +- client/service/test/src/lib.rs | 3 +- frame/session/src/historical/mod.rs | 35 +- primitives/api/Cargo.toml | 2 + .../api/proc-macro/src/impl_runtime_apis.rs | 10 +- .../proc-macro/src/mock_impl_runtime_apis.rs | 4 +- primitives/api/src/lib.rs | 12 +- primitives/state-machine/Cargo.toml | 1 + primitives/state-machine/src/backend.rs | 32 +- .../state-machine/src/in_memory_backend.rs | 13 +- primitives/state-machine/src/lib.rs | 192 ++-- .../state-machine/src/proving_backend.rs | 611 ------------ primitives/state-machine/src/read_only.rs | 26 +- primitives/state-machine/src/testing.rs | 14 +- primitives/state-machine/src/trie_backend.rs | 891 ++++++++++++++++-- .../state-machine/src/trie_backend_essence.rs | 455 ++++++--- .../transaction-storage-proof/src/lib.rs | 3 +- primitives/trie/Cargo.toml | 18 +- primitives/trie/src/cache/mod.rs | 686 ++++++++++++++ primitives/trie/src/cache/shared_cache.rs | 677 +++++++++++++ primitives/trie/src/error.rs | 21 +- primitives/trie/src/lib.rs | 168 ++-- primitives/trie/src/node_codec.rs | 41 +- primitives/trie/src/recorder.rs | 284 ++++++ primitives/trie/src/storage_proof.rs | 7 +- primitives/trie/src/trie_codec.rs | 6 +- test-utils/runtime/Cargo.toml | 2 +- test-utils/runtime/src/lib.rs | 35 +- utils/frame/benchmarking-cli/src/lib.rs | 4 +- .../frame/benchmarking-cli/src/storage/cmd.rs | 16 +- .../benchmarking-cli/src/storage/write.rs | 4 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- .../rpc/state-trie-migration-rpc/src/lib.rs | 19 +- utils/frame/try-runtime/cli/src/lib.rs | 12 +- 55 files changed, 3979 insertions(+), 1346 deletions(-) create mode 100644 client/db/benches/state_access.rs create mode 100644 client/db/src/record_stats_state.rs delete mode 100644 primitives/state-machine/src/proving_backend.rs create mode 100644 primitives/trie/src/cache/mod.rs create mode 100644 primitives/trie/src/cache/shared_cache.rs create mode 100644 primitives/trie/src/recorder.rs diff --git a/Cargo.lock b/Cargo.lock index 6a114065ee56c..1579c887b8fed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2798,9 +2798,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", ] @@ -4352,7 +4352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6566c70c1016f525ced45d7b7f97730a2bafb037c788211d0c186ef5b2189f0a" dependencies = [ "hash-db", - "hashbrown 0.12.0", + "hashbrown 0.12.3", "parity-util-mem", ] @@ -6572,7 +6572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c32561d248d352148124f036cac253a644685a21dc9fea383eb4907d7bd35a8f" dependencies = [ "cfg-if 1.0.0", - "hashbrown 0.12.0", + "hashbrown 0.12.3", "impl-trait-for-tuples", "parity-util-mem-derive", "parking_lot 0.12.0", @@ -7505,7 +7505,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f08c8062c1fe1253064043b8fc07bfea1b9702b71b4a86c11ea3588183b12e1" dependencies = [ "bytecheck", - "hashbrown 0.12.0", + "hashbrown 0.12.3", "ptr_meta", "rend", "rkyv_derive", @@ -7884,7 +7884,9 @@ dependencies = [ name = "sc-client-db" version = "0.10.0-dev" dependencies = [ + "criterion", "hash-db", + "kitchensink-runtime", "kvdb", "kvdb-memorydb", "kvdb-rocksdb", @@ -7894,6 +7896,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.0", "quickcheck", + "rand 0.8.4", "sc-client-api", "sc-state-db", "sp-arithmetic", @@ -9396,6 +9399,7 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-test-primitives", + "sp-trie", "sp-version", "thiserror", ] @@ -10060,6 +10064,7 @@ dependencies = [ "sp-trie", "thiserror", "tracing", + "trie-db", "trie-root", ] @@ -10157,16 +10162,23 @@ dependencies = [ name = "sp-trie" version = "6.0.0" dependencies = [ + "ahash", "criterion", "hash-db", + "hashbrown 0.12.3", "hex-literal", + "lazy_static", + "lru", "memory-db", + "nohash-hasher", "parity-scale-codec", + "parking_lot 0.12.0", "scale-info", "sp-core", "sp-runtime", "sp-std", "thiserror", + "tracing", "trie-bench", "trie-db", "trie-root", @@ -10963,9 +10975,9 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" [[package]] name = "trie-bench" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ecec5d10427b35e9ae374b059dccc0801d02d832617c04c78afc7a8c5c4a34" +checksum = "c5704f0d6130bd83608e4370c19e20c8a6ec03e80363e493d0234efca005265a" dependencies = [ "criterion", "hash-db", @@ -10979,12 +10991,12 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.23.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32d034c0d3db64b43c31de38e945f15b40cd4ca6d2dcfc26d4798ce8de4ab83" +checksum = "004e1e8f92535694b4cb1444dc5a8073ecf0815e3357f729638b9f8fc4062908" dependencies = [ "hash-db", - "hashbrown 0.12.0", + "hashbrown 0.12.3", "log", "rustc-hex", "smallvec", diff --git a/bin/node/bench/src/generator.rs b/bin/node/bench/src/generator.rs index 2b26ed9089a51..863928c719429 100644 --- a/bin/node/bench/src/generator.rs +++ b/bin/node/bench/src/generator.rs @@ -20,7 +20,7 @@ use std::{collections::HashMap, sync::Arc}; use kvdb::KeyValueDB; use node_primitives::Hash; -use sp_trie::{trie_types::TrieDBMutV1, TrieMut}; +use sp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut}; use crate::simple_trie::SimpleTrie; @@ -43,7 +43,8 @@ pub fn generate_trie( ); let mut trie = SimpleTrie { db, overlay: &mut overlay }; { - let mut trie_db = TrieDBMutV1::::new(&mut trie, &mut root); + let mut trie_db = + TrieDBMutBuilderV1::::new(&mut trie, &mut root).build(); for (key, value) in key_values { trie_db.insert(&key, &value).expect("trie insertion failed"); } diff --git a/bin/node/bench/src/trie.rs b/bin/node/bench/src/trie.rs index d508dc712e1c3..de49a6fe7b6da 100644 --- a/bin/node/bench/src/trie.rs +++ b/bin/node/bench/src/trie.rs @@ -23,7 +23,7 @@ use kvdb::KeyValueDB; use lazy_static::lazy_static; use rand::Rng; use sp_state_machine::Backend as _; -use sp_trie::{trie_types::TrieDBMutV1, TrieMut as _}; +use sp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut as _}; use std::{borrow::Cow, collections::HashMap, sync::Arc}; use node_primitives::Hash; @@ -180,7 +180,7 @@ impl core::Benchmark for TrieReadBenchmark { let storage: Arc> = Arc::new(Storage(db.open(self.database_type))); - let trie_backend = sp_state_machine::TrieBackend::new(storage, self.root); + let trie_backend = sp_state_machine::TrieBackendBuilder::new(storage, self.root).build(); for (warmup_key, warmup_value) in self.warmup_keys.iter() { let value = trie_backend .storage(&warmup_key[..]) @@ -286,8 +286,7 @@ impl core::Benchmark for TrieWriteBenchmark { let mut overlay = HashMap::new(); let mut trie = SimpleTrie { db: kvdb.clone(), overlay: &mut overlay }; - let mut trie_db_mut = TrieDBMutV1::from_existing(&mut trie, &mut new_root) - .expect("Failed to create TrieDBMut"); + let mut trie_db_mut = TrieDBMutBuilderV1::from_existing(&mut trie, &mut new_root).build(); for (warmup_key, warmup_value) in self.warmup_keys.iter() { let value = trie_db_mut diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 8420a65f8cb80..c0f3b96e093cb 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -72,8 +72,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { keystore: KeystoreConfig::InMemory, keystore_remote: Default::default(), database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, - state_cache_size: 67108864, - state_cache_child_ratio: None, + trie_cache_maximum_size: Some(64 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), blocks_pruning: BlocksPruning::All, chain_spec: spec, diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index f031f9dae3d21..e6084fba8242a 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -66,8 +66,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { keystore: KeystoreConfig::InMemory, keystore_remote: Default::default(), database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, - state_cache_size: 67108864, - state_cache_child_ratio: None, + trie_cache_maximum_size: Some(64 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), blocks_pruning: BlocksPruning::All, chain_spec: spec, diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index de64910125b86..534f0a4f09732 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -388,8 +388,7 @@ impl BenchDb { keyring: &BenchKeyring, ) -> (Client, std::sync::Arc, TaskExecutor) { let db_config = sc_client_db::DatabaseSettings { - state_cache_size: 16 * 1024 * 1024, - state_cache_child_ratio: Some((0, 100)), + trie_cache_maximum_size: Some(16 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), source: database_type.into_settings(dir.into()), blocks_pruning: sc_client_db::BlocksPruning::All, diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 54784a2f27b64..bcc7a9bff3b2d 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -32,7 +32,8 @@ use sp_runtime::{ Justification, Justifications, StateVersion, Storage, }; use sp_state_machine::{ - ChildStorageCollection, IndexOperation, OffchainChangesCollection, StorageCollection, + backend::AsTrieBackend, ChildStorageCollection, IndexOperation, OffchainChangesCollection, + StorageCollection, }; use sp_storage::{ChildInfo, StorageData, StorageKey}; use std::collections::{HashMap, HashSet}; @@ -448,7 +449,12 @@ pub trait Backend: AuxStore + Send + Sync { /// Associated blockchain backend type. type Blockchain: BlockchainBackend; /// Associated state backend type. - type State: StateBackend> + Send; + type State: StateBackend> + + Send + + AsTrieBackend< + HashFor, + TrieBackendStorage = >>::TrieBackendStorage, + >; /// Offchain workers local storage. type OffchainStorage: OffchainStorage; diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index bc328c40edb3c..f5ccd9023a3db 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -855,10 +855,18 @@ mod tests { .expect("header get error") .expect("there should be header"); - let extrinsics_num = 4; - let extrinsics = (0..extrinsics_num) - .map(|v| Extrinsic::IncludeData(vec![v as u8; 10])) - .collect::>(); + let extrinsics_num = 5; + let extrinsics = std::iter::once( + Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Bob.into(), + amount: 100, + nonce: 0, + } + .into_signed_tx(), + ) + .chain((0..extrinsics_num - 1).map(|v| Extrinsic::IncludeData(vec![v as u8; 10]))) + .collect::>(); let block_limit = genesis_header.encoded_size() + extrinsics @@ -922,8 +930,9 @@ mod tests { .unwrap(); // The block limit didn't changed, but we now include the proof in the estimation of the - // block size and thus, one less transaction should fit into the limit. - assert_eq!(block.extrinsics().len(), extrinsics_num - 2); + // block size and thus, only the `Transfer` will fit into the block. It reads more data + // than we have reserved in the block limit. + assert_eq!(block.extrinsics().len(), 1); } #[test] diff --git a/client/cli/src/commands/chain_info_cmd.rs b/client/cli/src/commands/chain_info_cmd.rs index 8fea0d7058e50..cbc22cc4d52d9 100644 --- a/client/cli/src/commands/chain_info_cmd.rs +++ b/client/cli/src/commands/chain_info_cmd.rs @@ -73,8 +73,7 @@ impl ChainInfoCmd { B: BlockT, { let db_config = sc_client_db::DatabaseSettings { - state_cache_size: config.state_cache_size, - state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), + trie_cache_maximum_size: config.trie_cache_maximum_size, state_pruning: config.state_pruning.clone(), source: config.database.clone(), blocks_pruning: config.blocks_pruning, diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index f513008b17adc..92091ea118ff1 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -230,18 +230,12 @@ pub trait CliConfiguration: Sized { }) } - /// Get the state cache size. + /// Get the trie cache maximum size. /// /// By default this is retrieved from `ImportParams` if it is available. Otherwise its `0`. - fn state_cache_size(&self) -> Result { - Ok(self.import_params().map(|x| x.state_cache_size()).unwrap_or_default()) - } - - /// Get the state cache child ratio (if any). - /// - /// By default this is `None`. - fn state_cache_child_ratio(&self) -> Result> { - Ok(Default::default()) + /// If `None` is returned the trie cache is disabled. + fn trie_cache_maximum_size(&self) -> Result> { + Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) } /// Get the state pruning mode. @@ -533,8 +527,7 @@ pub trait CliConfiguration: Sized { keystore_remote, keystore, database: self.database_config(&config_dir, database_cache_size, database)?, - state_cache_size: self.state_cache_size()?, - state_cache_child_ratio: self.state_cache_child_ratio()?, + trie_cache_maximum_size: self.trie_cache_maximum_size()?, state_pruning: self.state_pruning()?, blocks_pruning: self.blocks_pruning()?, wasm_method: self.wasm_method()?, diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index aef7511ffc371..c851050838965 100644 --- a/client/cli/src/params/import_params.rs +++ b/client/cli/src/params/import_params.rs @@ -95,14 +95,30 @@ pub struct ImportParams { pub execution_strategies: ExecutionStrategiesParams, /// Specify the state cache size. + /// + /// Providing `0` will disable the cache. #[clap(long, value_name = "Bytes", default_value = "67108864")] - pub state_cache_size: usize, + pub trie_cache_size: usize, + + /// DEPRECATED + /// + /// Switch to `--trie-cache-size`. + #[clap(long)] + state_cache_size: Option, } impl ImportParams { - /// Specify the state cache size. - pub fn state_cache_size(&self) -> usize { - self.state_cache_size + /// Specify the trie cache maximum size. + pub fn trie_cache_maximum_size(&self) -> Option { + if self.state_cache_size.is_some() { + eprintln!("`--state-cache-size` was deprecated. Please switch to `--trie-cache-size`."); + } + + if self.trie_cache_size == 0 { + None + } else { + Some(self.trie_cache_size) + } } /// Get the WASM execution method from the parameters diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 3b6402b3f6023..7bfba997767f2 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -35,9 +35,12 @@ sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" sp-trie = { version = "6.0.0", path = "../../primitives/trie" } [dev-dependencies] +criterion = "0.3.3" kvdb-rocksdb = "0.15.1" +rand = "0.8.4" +tempfile = "3.1.0" quickcheck = { version = "1.0.3", default-features = false } -tempfile = "3" +kitchensink-runtime = { path = "../../bin/node/runtime" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } @@ -46,3 +49,10 @@ default = [] test-helpers = [] runtime-benchmarks = [] rocksdb = ["kvdb-rocksdb"] + +[[bench]] +name = "state_access" +harness = false + +[lib] +bench = false diff --git a/client/db/benches/state_access.rs b/client/db/benches/state_access.rs new file mode 100644 index 0000000000000..78aed7858e342 --- /dev/null +++ b/client/db/benches/state_access.rs @@ -0,0 +1,312 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; +use rand::{distributions::Uniform, rngs::StdRng, Rng, SeedableRng}; +use sc_client_api::{Backend as _, BlockImportOperation, NewBlockState, StateBackend}; +use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, DatabaseSource, PruningMode}; +use sp_core::H256; +use sp_runtime::{ + generic::BlockId, + testing::{Block as RawBlock, ExtrinsicWrapper, Header}, + StateVersion, Storage, +}; +use tempfile::TempDir; + +pub(crate) type Block = RawBlock>; + +fn insert_blocks(db: &Backend, storage: Vec<(Vec, Vec)>) -> H256 { + let mut op = db.begin_operation().unwrap(); + let mut header = Header { + number: 0, + parent_hash: Default::default(), + state_root: Default::default(), + digest: Default::default(), + extrinsics_root: Default::default(), + }; + + header.state_root = op + .set_genesis_state( + Storage { + top: vec![( + sp_core::storage::well_known_keys::CODE.to_vec(), + kitchensink_runtime::wasm_binary_unwrap().to_vec(), + )] + .into_iter() + .collect(), + children_default: Default::default(), + }, + true, + StateVersion::V1, + ) + .unwrap(); + + op.set_block_data(header.clone(), Some(vec![]), None, None, NewBlockState::Best) + .unwrap(); + + db.commit_operation(op).unwrap(); + + let mut number = 1; + let mut parent_hash = header.hash(); + + for i in 0..10 { + let mut op = db.begin_operation().unwrap(); + + db.begin_state_operation(&mut op, BlockId::Hash(parent_hash)).unwrap(); + + let mut header = Header { + number, + parent_hash, + state_root: Default::default(), + digest: Default::default(), + extrinsics_root: Default::default(), + }; + + let changes = storage + .iter() + .skip(i * 100_000) + .take(100_000) + .map(|(k, v)| (k.clone(), Some(v.clone()))) + .collect::>(); + + let (state_root, tx) = db.state_at(BlockId::Number(number - 1)).unwrap().storage_root( + changes.iter().map(|(k, v)| (k.as_slice(), v.as_deref())), + StateVersion::V1, + ); + header.state_root = state_root; + + op.update_db_storage(tx).unwrap(); + op.update_storage(changes.clone(), Default::default()).unwrap(); + + op.set_block_data(header.clone(), Some(vec![]), None, None, NewBlockState::Best) + .unwrap(); + + db.commit_operation(op).unwrap(); + + number += 1; + parent_hash = header.hash(); + } + + parent_hash +} + +enum BenchmarkConfig { + NoCache, + TrieNodeCache, +} + +fn create_backend(config: BenchmarkConfig, temp_dir: &TempDir) -> Backend { + let path = temp_dir.path().to_owned(); + + let trie_cache_maximum_size = match config { + BenchmarkConfig::NoCache => None, + BenchmarkConfig::TrieNodeCache => Some(2 * 1024 * 1024 * 1024), + }; + + let settings = DatabaseSettings { + trie_cache_maximum_size, + state_pruning: Some(PruningMode::ArchiveAll), + source: DatabaseSource::ParityDb { path }, + blocks_pruning: BlocksPruning::All, + }; + + Backend::new(settings, 100).expect("Creates backend") +} + +/// Generate the storage that will be used for the benchmark +/// +/// Returns the `Vec` and the `Vec<(key, value)>` +fn generate_storage() -> (Vec>, Vec<(Vec, Vec)>) { + let mut rng = StdRng::seed_from_u64(353893213); + + let mut storage = Vec::new(); + let mut keys = Vec::new(); + + for _ in 0..1_000_000 { + let key_len: usize = rng.gen_range(32..128); + let key = (&mut rng) + .sample_iter(Uniform::new_inclusive(0, 255)) + .take(key_len) + .collect::>(); + + let value_len: usize = rng.gen_range(20..60); + let value = (&mut rng) + .sample_iter(Uniform::new_inclusive(0, 255)) + .take(value_len) + .collect::>(); + + keys.push(key.clone()); + storage.push((key, value)); + } + + (keys, storage) +} + +fn state_access_benchmarks(c: &mut Criterion) { + sp_tracing::try_init_simple(); + + let (keys, storage) = generate_storage(); + let path = TempDir::new().expect("Creates temporary directory"); + + let block_hash = { + let backend = create_backend(BenchmarkConfig::NoCache, &path); + insert_blocks(&backend, storage.clone()) + }; + + let mut group = c.benchmark_group("Reading entire state"); + group.sample_size(20); + + let mut bench_multiple_values = |config, desc, multiplier| { + let backend = create_backend(config, &path); + + group.bench_function(desc, |b| { + b.iter_batched( + || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + |state| { + for key in keys.iter().cycle().take(keys.len() * multiplier) { + let _ = state.storage(&key).expect("Doesn't fail").unwrap(); + } + }, + BatchSize::SmallInput, + ) + }); + }; + + bench_multiple_values( + BenchmarkConfig::TrieNodeCache, + "with trie node cache and reading each key once", + 1, + ); + bench_multiple_values(BenchmarkConfig::NoCache, "no cache and reading each key once", 1); + + bench_multiple_values( + BenchmarkConfig::TrieNodeCache, + "with trie node cache and reading 4 times each key in a row", + 4, + ); + bench_multiple_values( + BenchmarkConfig::NoCache, + "no cache and reading 4 times each key in a row", + 4, + ); + + group.finish(); + + let mut group = c.benchmark_group("Reading a single value"); + + let mut bench_single_value = |config, desc, multiplier| { + let backend = create_backend(config, &path); + + group.bench_function(desc, |b| { + b.iter_batched( + || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + |state| { + for key in keys.iter().take(1).cycle().take(multiplier) { + let _ = state.storage(&key).expect("Doesn't fail").unwrap(); + } + }, + BatchSize::SmallInput, + ) + }); + }; + + bench_single_value( + BenchmarkConfig::TrieNodeCache, + "with trie node cache and reading the key once", + 1, + ); + bench_single_value(BenchmarkConfig::NoCache, "no cache and reading the key once", 1); + + bench_single_value( + BenchmarkConfig::TrieNodeCache, + "with trie node cache and reading 4 times each key in a row", + 4, + ); + bench_single_value( + BenchmarkConfig::NoCache, + "no cache and reading 4 times each key in a row", + 4, + ); + + group.finish(); + + let mut group = c.benchmark_group("Hashing a value"); + + let mut bench_single_value = |config, desc, multiplier| { + let backend = create_backend(config, &path); + + group.bench_function(desc, |b| { + b.iter_batched( + || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + |state| { + for key in keys.iter().take(1).cycle().take(multiplier) { + let _ = state.storage_hash(&key).expect("Doesn't fail").unwrap(); + } + }, + BatchSize::SmallInput, + ) + }); + }; + + bench_single_value( + BenchmarkConfig::TrieNodeCache, + "with trie node cache and hashing the key once", + 1, + ); + bench_single_value(BenchmarkConfig::NoCache, "no cache and hashing the key once", 1); + + bench_single_value( + BenchmarkConfig::TrieNodeCache, + "with trie node cache and hashing 4 times each key in a row", + 4, + ); + bench_single_value( + BenchmarkConfig::NoCache, + "no cache and hashing 4 times each key in a row", + 4, + ); + + group.finish(); + + let mut group = c.benchmark_group("Hashing `:code`"); + + let mut bench_single_value = |config, desc| { + let backend = create_backend(config, &path); + + group.bench_function(desc, |b| { + b.iter_batched( + || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + |state| { + let _ = state + .storage_hash(sp_core::storage::well_known_keys::CODE) + .expect("Doesn't fail") + .unwrap(); + }, + BatchSize::SmallInput, + ) + }); + }; + + bench_single_value(BenchmarkConfig::TrieNodeCache, "with trie node cache"); + bench_single_value(BenchmarkConfig::NoCache, "no cache"); + + group.finish(); +} + +criterion_group!(benches, state_access_benchmarks); +criterion_main!(benches); diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index d3d43e742d026..b1f4e3b6c0af5 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -18,13 +18,7 @@ //! State backend that's useful for benchmarking -use std::{ - cell::{Cell, RefCell}, - collections::HashMap, - sync::Arc, -}; - -use crate::storage_cache::{new_shared_cache, CachingState, SharedCache}; +use crate::{DbState, DbStateBuilder}; use hash_db::{Hasher, Prefix}; use kvdb::{DBTransaction, KeyValueDB}; use linked_hash_map::LinkedHashMap; @@ -37,40 +31,31 @@ use sp_runtime::{ StateVersion, Storage, }; use sp_state_machine::{ - backend::Backend as StateBackend, ChildStorageCollection, DBValue, ProofRecorder, - StorageCollection, + backend::Backend as StateBackend, ChildStorageCollection, DBValue, StorageCollection, +}; +use sp_trie::{ + cache::{CacheSize, SharedTrieCache}, + prefixed_key, MemoryDB, +}; +use std::{ + cell::{Cell, RefCell}, + collections::HashMap, + sync::Arc, }; -use sp_trie::{prefixed_key, MemoryDB}; - -type DbState = - sp_state_machine::TrieBackend>>, HashFor>; -type State = CachingState, B>; +type State = DbState; struct StorageDb { db: Arc, - proof_recorder: Option>, _block: std::marker::PhantomData, } impl sp_state_machine::Storage> for StorageDb { fn get(&self, key: &Block::Hash, prefix: Prefix) -> Result, String> { let prefixed_key = prefixed_key::>(key, prefix); - if let Some(recorder) = &self.proof_recorder { - if let Some(v) = recorder.get(key) { - return Ok(v) - } - let backend_value = self - .db - .get(0, &prefixed_key) - .map_err(|e| format!("Database backend error: {:?}", e))?; - recorder.record(*key, backend_value.clone()); - Ok(backend_value) - } else { - self.db - .get(0, &prefixed_key) - .map_err(|e| format!("Database backend error: {:?}", e)) - } + self.db + .get(0, &prefixed_key) + .map_err(|e| format!("Database backend error: {:?}", e)) } } @@ -82,7 +67,6 @@ pub struct BenchmarkingState { db: Cell>>, genesis: HashMap, (Vec, i32)>, record: Cell>>, - shared_cache: SharedCache, // shared cache is always empty /// Key tracker for keys in the main trie. /// We track the total number of reads and writes to these keys, /// not de-duplicated for repeats. @@ -93,9 +77,10 @@ pub struct BenchmarkingState { /// not de-duplicated for repeats. child_key_tracker: RefCell, LinkedHashMap, TrackedStorageKey>>>, whitelist: RefCell>, - proof_recorder: Option>, + proof_recorder: Option>>, proof_recorder_root: Cell, enable_tracking: bool, + shared_trie_cache: SharedTrieCache>, } impl BenchmarkingState { @@ -109,7 +94,7 @@ impl BenchmarkingState { let state_version = sp_runtime::StateVersion::default(); let mut root = B::Hash::default(); let mut mdb = MemoryDB::>::default(); - sp_state_machine::TrieDBMutV1::>::new(&mut mdb, &mut root); + sp_trie::trie_types::TrieDBMutBuilderV1::>::new(&mut mdb, &mut root).build(); let mut state = BenchmarkingState { state: RefCell::new(None), @@ -118,13 +103,14 @@ impl BenchmarkingState { genesis: Default::default(), genesis_root: Default::default(), record: Default::default(), - shared_cache: new_shared_cache(0, (1, 10)), main_key_tracker: Default::default(), child_key_tracker: Default::default(), whitelist: Default::default(), proof_recorder: record_proof.then(Default::default), proof_recorder_root: Cell::new(root), enable_tracking, + // Enable the cache, but do not sync anything to the shared state. + shared_trie_cache: SharedTrieCache::new(CacheSize::Maximum(0)), }; state.add_whitelist_to_tracker(); @@ -160,16 +146,13 @@ impl BenchmarkingState { recorder.reset(); self.proof_recorder_root.set(self.root.get()); } - let storage_db = Arc::new(StorageDb:: { - db, - proof_recorder: self.proof_recorder.clone(), - _block: Default::default(), - }); - *self.state.borrow_mut() = Some(State::new( - DbState::::new(storage_db, self.root.get()), - self.shared_cache.clone(), - None, - )); + let storage_db = Arc::new(StorageDb:: { db, _block: Default::default() }); + *self.state.borrow_mut() = Some( + DbStateBuilder::::new(storage_db, self.root.get()) + .with_optional_recorder(self.proof_recorder.clone()) + .with_cache(self.shared_trie_cache.local_cache()) + .build(), + ); Ok(()) } @@ -324,6 +307,19 @@ impl StateBackend> for BenchmarkingState { .child_storage(child_info, key) } + fn child_storage_hash( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result, Self::Error> { + self.add_read_key(Some(child_info.storage_key()), key); + self.state + .borrow() + .as_ref() + .ok_or_else(state_err)? + .child_storage_hash(child_info, key) + } + fn exists_storage(&self, key: &[u8]) -> Result { self.add_read_key(None, key); self.state.borrow().as_ref().ok_or_else(state_err)?.exists_storage(key) @@ -604,22 +600,25 @@ impl StateBackend> for BenchmarkingState { fn proof_size(&self) -> Option { self.proof_recorder.as_ref().map(|recorder| { let proof_size = recorder.estimate_encoded_size() as u32; + let proof = recorder.to_storage_proof(); + let proof_recorder_root = self.proof_recorder_root.get(); if proof_recorder_root == Default::default() || proof_size == 1 { // empty trie proof_size - } else if let Some(size) = proof.encoded_compact_size::>(proof_recorder_root) - { - size as u32 } else { - panic!( - "proof rec root {:?}, root {:?}, genesis {:?}, rec_len {:?}", - self.proof_recorder_root.get(), - self.root.get(), - self.genesis_root, - proof_size, - ); + if let Some(size) = proof.encoded_compact_size::>(proof_recorder_root) { + size as u32 + } else { + panic!( + "proof rec root {:?}, root {:?}, genesis {:?}, rec_len {:?}", + self.proof_recorder_root.get(), + self.root.get(), + self.genesis_root, + proof_size, + ); + } } }) } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 71f291e66e793..465db08fe3afc 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -34,8 +34,8 @@ pub mod bench; mod children; mod parity_db; +mod record_stats_state; mod stats; -mod storage_cache; #[cfg(any(feature = "rocksdb", test))] mod upgrade; mod utils; @@ -51,8 +51,8 @@ use std::{ }; use crate::{ + record_stats_state::RecordStatsState, stats::StateUsageStats, - storage_cache::{new_shared_cache, CachingState, SharedCache, SyncingCachingState}, utils::{meta_keys, read_db, read_meta, DatabaseType, Meta}, }; use codec::{Decode, Encode}; @@ -83,10 +83,11 @@ use sp_runtime::{ Justification, Justifications, StateVersion, Storage, }; use sp_state_machine::{ - backend::Backend as StateBackend, ChildStorageCollection, DBValue, IndexOperation, - OffchainChangesCollection, StateMachineStats, StorageCollection, UsageInfo as StateUsageInfo, + backend::{AsTrieBackend, Backend as StateBackend}, + ChildStorageCollection, DBValue, IndexOperation, OffchainChangesCollection, StateMachineStats, + StorageCollection, UsageInfo as StateUsageInfo, }; -use sp_trie::{prefixed_key, MemoryDB, PrefixedMemoryDB}; +use sp_trie::{cache::SharedTrieCache, prefixed_key, MemoryDB, PrefixedMemoryDB}; // Re-export the Database trait so that one can pass an implementation of it. pub use sc_state_db::PruningMode; @@ -96,13 +97,16 @@ pub use bench::BenchmarkingState; const CACHE_HEADERS: usize = 8; -/// Default value for storage cache child ratio. -const DEFAULT_CHILD_RATIO: (usize, usize) = (1, 10); - /// DB-backed patricia trie state, transaction type is an overlay of changes to commit. pub type DbState = sp_state_machine::TrieBackend>>, HashFor>; +/// Builder for [`DbState`]. +pub type DbStateBuilder = sp_state_machine::TrieBackendBuilder< + Arc>>, + HashFor, +>; + /// Length of a [`DbHash`]. const DB_HASH_LEN: usize = 32; @@ -174,6 +178,14 @@ impl StateBackend> for RefTrackingState { self.state.child_storage(child_info, key) } + fn child_storage_hash( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result, Self::Error> { + self.state.child_storage_hash(child_info, key) + } + fn exists_storage(&self, key: &[u8]) -> Result { self.state.exists_storage(key) } @@ -272,12 +284,6 @@ impl StateBackend> for RefTrackingState { self.state.child_keys(child_info, prefix) } - fn as_trie_backend( - &self, - ) -> Option<&sp_state_machine::TrieBackend>> { - self.state.as_trie_backend() - } - fn register_overlay_stats(&self, stats: &StateMachineStats) { self.state.register_overlay_stats(stats); } @@ -287,12 +293,22 @@ impl StateBackend> for RefTrackingState { } } +impl AsTrieBackend> for RefTrackingState { + type TrieBackendStorage = as StateBackend>>::TrieBackendStorage; + + fn as_trie_backend( + &self, + ) -> &sp_state_machine::TrieBackend> { + &self.state.as_trie_backend() + } +} + /// Database settings. pub struct DatabaseSettings { - /// State cache size. - pub state_cache_size: usize, - /// Ratio of cache size dedicated to child tries. - pub state_cache_child_ratio: Option<(usize, usize)>, + /// The maximum trie cache size in bytes. + /// + /// If `None` is given, the cache is disabled. + pub trie_cache_maximum_size: Option, /// Requested state pruning mode. pub state_pruning: Option, /// Where to find the database. @@ -730,7 +746,7 @@ impl HeaderMetadata for BlockchainDb { /// Database transaction pub struct BlockImportOperation { - old_state: SyncingCachingState, Block>, + old_state: RecordStatsState, Block>, db_updates: PrefixedMemoryDB>, storage_updates: StorageCollection, child_storage_updates: ChildStorageCollection, @@ -800,7 +816,7 @@ impl BlockImportOperation { impl sc_client_api::backend::BlockImportOperation for BlockImportOperation { - type State = SyncingCachingState, Block>; + type State = RecordStatsState, Block>; fn state(&self) -> ClientResult> { Ok(Some(&self.old_state)) @@ -949,7 +965,7 @@ impl EmptyStorage { let mut root = Block::Hash::default(); let mut mdb = MemoryDB::>::default(); // both triedbmut are the same on empty storage. - sp_state_machine::TrieDBMutV1::>::new(&mut mdb, &mut root); + sp_trie::trie_types::TrieDBMutBuilderV1::>::new(&mut mdb, &mut root).build(); EmptyStorage(root) } } @@ -1009,13 +1025,13 @@ pub struct Backend { offchain_storage: offchain::LocalStorage, blockchain: BlockchainDb, canonicalization_delay: u64, - shared_cache: SharedCache, import_lock: Arc>, is_archive: bool, blocks_pruning: BlocksPruning, io_stats: FrozenForDuration<(kvdb::IoStats, StateUsageInfo)>, state_usage: Arc, genesis_state: RwLock>>>, + shared_trie_cache: Option>>, } impl Backend { @@ -1053,8 +1069,7 @@ impl Backend { let db = kvdb_memorydb::create(crate::utils::NUM_COLUMNS); let db = sp_database::as_database(db); let db_setting = DatabaseSettings { - state_cache_size: 16777216, - state_cache_child_ratio: Some((50, 100)), + trie_cache_maximum_size: Some(16 * 1024 * 1024), state_pruning: Some(PruningMode::blocks_pruning(blocks_pruning)), source: DatabaseSource::Custom { db, require_create_flag: true }, blocks_pruning: BlocksPruning::Some(blocks_pruning), @@ -1116,16 +1131,15 @@ impl Backend { offchain_storage, blockchain, canonicalization_delay, - shared_cache: new_shared_cache( - config.state_cache_size, - config.state_cache_child_ratio.unwrap_or(DEFAULT_CHILD_RATIO), - ), import_lock: Default::default(), is_archive: is_archive_pruning, io_stats: FrozenForDuration::new(std::time::Duration::from_secs(1)), state_usage: Arc::new(StateUsageStats::new()), blocks_pruning: config.blocks_pruning, genesis_state: RwLock::new(None), + shared_trie_cache: config.trie_cache_maximum_size.map(|maximum_size| { + SharedTrieCache::new(sp_trie::cache::CacheSize::Maximum(maximum_size)) + }), }; // Older DB versions have no last state key. Check if the state is available and set it. @@ -1194,7 +1208,7 @@ impl Backend { (&r.number, &r.hash) ); - return Err(::sp_blockchain::Error::NotInFinalizedChain) + return Err(sp_blockchain::Error::NotInFinalizedChain) } retracted.push(r.hash); @@ -1358,10 +1372,8 @@ impl Backend { // blocks are keyed by number + hash. let lookup_key = utils::number_and_hash_to_lookup_key(number, hash)?; - let (enacted, retracted) = if pending_block.leaf_state.is_best() { - self.set_head_with_transaction(&mut transaction, parent_hash, (number, hash))? - } else { - (Default::default(), Default::default()) + if pending_block.leaf_state.is_best() { + self.set_head_with_transaction(&mut transaction, parent_hash, (number, hash))?; }; utils::insert_hash_to_key_mapping(&mut transaction, columns::KEY_LOOKUP, number, hash)?; @@ -1488,14 +1500,22 @@ impl Backend { let header = &pending_block.header; let is_best = pending_block.leaf_state.is_best(); - debug!(target: "db", + debug!( + target: "db", "DB Commit {:?} ({}), best={}, state={}, existing={}, finalized={}", - hash, number, is_best, operation.commit_state, existing_header, finalized, + hash, + number, + is_best, + operation.commit_state, + existing_header, + finalized, ); self.state_usage.merge_sm(operation.old_state.usage_info()); + // release state reference so that it can be finalized - let cache = operation.old_state.into_cache_changes(); + // VERY IMPORTANT + drop(operation.old_state); if finalized { // TODO: ensure best chain contains this block. @@ -1584,20 +1604,20 @@ impl Backend { is_finalized: finalized, with_state: operation.commit_state, }); - Some((pending_block.header, number, hash, enacted, retracted, is_best, cache)) + Some((pending_block.header, hash)) } else { None }; - let cache_update = if let Some(set_head) = operation.set_head { + if let Some(set_head) = operation.set_head { if let Some(header) = sc_client_api::blockchain::HeaderBackend::header(&self.blockchain, set_head)? { let number = header.number(); let hash = header.hash(); - let (enacted, retracted) = - self.set_head_with_transaction(&mut transaction, hash, (*number, hash))?; + self.set_head_with_transaction(&mut transaction, hash, (*number, hash))?; + meta_updates.push(MetaUpdate { hash, number: *number, @@ -1605,40 +1625,24 @@ impl Backend { is_finalized: false, with_state: false, }); - Some((enacted, retracted)) } else { return Err(sp_blockchain::Error::UnknownBlock(format!( "Cannot set head {:?}", set_head ))) } - } else { - None - }; + } self.storage.db.commit(transaction)?; // Apply all in-memory state changes. // Code beyond this point can't fail. - if let Some((header, number, hash, enacted, retracted, is_best, mut cache)) = imported { + if let Some((header, hash)) = imported { trace!(target: "db", "DB Commit done {:?}", hash); let header_metadata = CachedHeaderMetadata::from(&header); self.blockchain.insert_header_metadata(header_metadata.hash, header_metadata); cache_header(&mut self.blockchain.header_cache.lock(), hash, Some(header)); - cache.sync_cache( - &enacted, - &retracted, - operation.storage_updates, - operation.child_storage_updates, - Some(hash), - Some(number), - is_best, - ); - } - - if let Some((enacted, retracted)) = cache_update { - self.shared_cache.write().sync(&enacted, &retracted); } for m in meta_updates { @@ -1770,17 +1774,13 @@ impl Backend { Ok(()) } - fn empty_state(&self) -> ClientResult, Block>> { + fn empty_state(&self) -> ClientResult, Block>> { let root = EmptyStorage::::new().0; // Empty trie - let db_state = DbState::::new(self.storage.clone(), root); + let db_state = DbStateBuilder::::new(self.storage.clone(), root) + .with_optional_cache(self.shared_trie_cache.as_ref().map(|c| c.local_cache())) + .build(); let state = RefTrackingState::new(db_state, self.storage.clone(), None); - let caching_state = CachingState::new(state, self.shared_cache.clone(), None); - Ok(SyncingCachingState::new( - caching_state, - self.state_usage.clone(), - self.blockchain.meta.clone(), - self.import_lock.clone(), - )) + Ok(RecordStatsState::new(state, None, self.state_usage.clone())) } } @@ -1902,16 +1902,13 @@ where impl sc_client_api::backend::Backend for Backend { type BlockImportOperation = BlockImportOperation; type Blockchain = BlockchainDb; - type State = SyncingCachingState, Block>; + type State = RecordStatsState, Block>; type OffchainStorage = offchain::LocalStorage; fn begin_operation(&self) -> ClientResult { - let mut old_state = self.empty_state()?; - old_state.disable_syncing(); - Ok(BlockImportOperation { pending_block: None, - old_state, + old_state: self.empty_state()?, db_updates: PrefixedMemoryDB::default(), storage_updates: Default::default(), child_storage_updates: Default::default(), @@ -1934,7 +1931,6 @@ impl sc_client_api::backend::Backend for Backend { } else { operation.old_state = self.state_at(block)?; } - operation.old_state.disable_syncing(); operation.commit_state = true; Ok(()) @@ -2035,8 +2031,9 @@ impl sc_client_api::backend::Backend for Backend { ) }); let database_cache = MemorySize::from_bytes(0); - let state_cache = - MemorySize::from_bytes(self.shared_cache.read().used_storage_cache_size()); + let state_cache = MemorySize::from_bytes( + self.shared_trie_cache.as_ref().map_or(0, |c| c.used_memory_size()), + ); let state_db = self.storage.state_db.memory_info(); Some(UsageInfo { @@ -2278,17 +2275,13 @@ impl sc_client_api::backend::Backend for Backend { }; if is_genesis { if let Some(genesis_state) = &*self.genesis_state.read() { - let db_state = DbState::::new(genesis_state.clone(), genesis_state.root); + let root = genesis_state.root; + let db_state = DbStateBuilder::::new(genesis_state.clone(), root) + .with_optional_cache(self.shared_trie_cache.as_ref().map(|c| c.local_cache())) + .build(); + let state = RefTrackingState::new(db_state, self.storage.clone(), None); - let caching_state = CachingState::new(state, self.shared_cache.clone(), None); - let mut state = SyncingCachingState::new( - caching_state, - self.state_usage.clone(), - self.blockchain.meta.clone(), - self.import_lock.clone(), - ); - state.disable_syncing(); - return Ok(state) + return Ok(RecordStatsState::new(state, None, self.state_usage.clone())) } } @@ -2309,16 +2302,13 @@ impl sc_client_api::backend::Backend for Backend { } if let Ok(()) = self.storage.state_db.pin(&hash) { let root = hdr.state_root; - let db_state = DbState::::new(self.storage.clone(), root); + let db_state = DbStateBuilder::::new(self.storage.clone(), root) + .with_optional_cache( + self.shared_trie_cache.as_ref().map(|c| c.local_cache()), + ) + .build(); let state = RefTrackingState::new(db_state, self.storage.clone(), Some(hash)); - let caching_state = - CachingState::new(state, self.shared_cache.clone(), Some(hash)); - Ok(SyncingCachingState::new( - caching_state, - self.state_usage.clone(), - self.blockchain.meta.clone(), - self.import_lock.clone(), - )) + Ok(RecordStatsState::new(state, Some(hash), self.state_usage.clone())) } else { Err(sp_blockchain::Error::UnknownBlock(format!( "State already discarded for {:?}", @@ -2494,8 +2484,7 @@ pub(crate) mod tests { let backend = Backend::::new( DatabaseSettings { - state_cache_size: 16777216, - state_cache_child_ratio: Some((50, 100)), + trie_cache_maximum_size: Some(16 * 1024 * 1024), state_pruning: Some(PruningMode::blocks_pruning(1)), source: DatabaseSource::Custom { db: backing, require_create_flag: false }, blocks_pruning: BlocksPruning::All, diff --git a/client/db/src/record_stats_state.rs b/client/db/src/record_stats_state.rs new file mode 100644 index 0000000000000..0b51d3fef2127 --- /dev/null +++ b/client/db/src/record_stats_state.rs @@ -0,0 +1,230 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Provides [`RecordStatsState`] for recording stats about state access. + +use crate::stats::StateUsageStats; +use sp_core::storage::ChildInfo; +use sp_runtime::{ + traits::{Block as BlockT, HashFor}, + StateVersion, +}; +use sp_state_machine::{ + backend::{AsTrieBackend, Backend as StateBackend}, + TrieBackend, +}; +use std::sync::Arc; + +/// State abstraction for recording stats about state access. +pub struct RecordStatsState { + /// Usage statistics + usage: StateUsageStats, + /// State machine registered stats + overlay_stats: sp_state_machine::StateMachineStats, + /// Backing state. + state: S, + /// The hash of the block is state belongs to. + block_hash: Option, + /// The usage statistics of the backend. These will be updated on drop. + state_usage: Arc, +} + +impl std::fmt::Debug for RecordStatsState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Block {:?}", self.block_hash) + } +} + +impl Drop for RecordStatsState { + fn drop(&mut self) { + self.state_usage.merge_sm(self.usage.take()); + } +} + +impl>, B: BlockT> RecordStatsState { + /// Create a new instance wrapping generic State and shared cache. + pub(crate) fn new( + state: S, + block_hash: Option, + state_usage: Arc, + ) -> Self { + RecordStatsState { + usage: StateUsageStats::new(), + overlay_stats: sp_state_machine::StateMachineStats::default(), + state, + block_hash, + state_usage, + } + } +} + +impl>, B: BlockT> StateBackend> for RecordStatsState { + type Error = S::Error; + type Transaction = S::Transaction; + type TrieBackendStorage = S::TrieBackendStorage; + + fn storage(&self, key: &[u8]) -> Result>, Self::Error> { + let value = self.state.storage(key)?; + self.usage.tally_key_read(key, value.as_ref(), false); + Ok(value) + } + + fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { + self.state.storage_hash(key) + } + + fn child_storage( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result>, Self::Error> { + let key = (child_info.storage_key().to_vec(), key.to_vec()); + let value = self.state.child_storage(child_info, &key.1)?; + + // just pass it through the usage counter + let value = self.usage.tally_child_key_read(&key, value, false); + + Ok(value) + } + + fn child_storage_hash( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result, Self::Error> { + self.state.child_storage_hash(child_info, key) + } + + fn exists_storage(&self, key: &[u8]) -> Result { + self.state.exists_storage(key) + } + + fn exists_child_storage( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result { + self.state.exists_child_storage(child_info, key) + } + + fn apply_to_key_values_while, Vec) -> bool>( + &self, + child_info: Option<&ChildInfo>, + prefix: Option<&[u8]>, + start_at: Option<&[u8]>, + f: F, + allow_missing: bool, + ) -> Result { + self.state + .apply_to_key_values_while(child_info, prefix, start_at, f, allow_missing) + } + + fn apply_to_keys_while bool>( + &self, + child_info: Option<&ChildInfo>, + prefix: Option<&[u8]>, + start_at: Option<&[u8]>, + f: F, + ) { + self.state.apply_to_keys_while(child_info, prefix, start_at, f) + } + + fn next_storage_key(&self, key: &[u8]) -> Result>, Self::Error> { + self.state.next_storage_key(key) + } + + fn next_child_storage_key( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result>, Self::Error> { + self.state.next_child_storage_key(child_info, key) + } + + fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { + self.state.for_keys_with_prefix(prefix, f) + } + + fn for_key_values_with_prefix(&self, prefix: &[u8], f: F) { + self.state.for_key_values_with_prefix(prefix, f) + } + + fn for_child_keys_with_prefix( + &self, + child_info: &ChildInfo, + prefix: &[u8], + f: F, + ) { + self.state.for_child_keys_with_prefix(child_info, prefix, f) + } + + fn storage_root<'a>( + &self, + delta: impl Iterator)>, + state_version: StateVersion, + ) -> (B::Hash, Self::Transaction) + where + B::Hash: Ord, + { + self.state.storage_root(delta, state_version) + } + + fn child_storage_root<'a>( + &self, + child_info: &ChildInfo, + delta: impl Iterator)>, + state_version: StateVersion, + ) -> (B::Hash, bool, Self::Transaction) + where + B::Hash: Ord, + { + self.state.child_storage_root(child_info, delta, state_version) + } + + fn pairs(&self) -> Vec<(Vec, Vec)> { + self.state.pairs() + } + + fn keys(&self, prefix: &[u8]) -> Vec> { + self.state.keys(prefix) + } + + fn child_keys(&self, child_info: &ChildInfo, prefix: &[u8]) -> Vec> { + self.state.child_keys(child_info, prefix) + } + + fn register_overlay_stats(&self, stats: &sp_state_machine::StateMachineStats) { + self.overlay_stats.add(stats); + } + + fn usage_info(&self) -> sp_state_machine::UsageInfo { + let mut info = self.usage.take(); + info.include_state_machine_states(&self.overlay_stats); + info + } +} + +impl> + AsTrieBackend>, B: BlockT> AsTrieBackend> + for RecordStatsState +{ + type TrieBackendStorage = >>::TrieBackendStorage; + + fn as_trie_backend(&self) -> &TrieBackend> { + self.state.as_trie_backend() + } +} diff --git a/client/rpc-api/src/dev/error.rs b/client/rpc-api/src/dev/error.rs index fe74dea256376..43fd3325fa598 100644 --- a/client/rpc-api/src/dev/error.rs +++ b/client/rpc-api/src/dev/error.rs @@ -32,6 +32,9 @@ pub enum Error { /// The re-execution of the specified block failed. #[error("Failed to re-execute the specified block")] BlockExecutionFailed, + /// Failed to extract the proof. + #[error("Failed to extract the proof")] + ProofExtractionFailed, /// The witness compaction failed. #[error("Failed to create to compact the witness")] WitnessCompactionFailed, @@ -54,6 +57,8 @@ impl From for JsonRpseeError { CallError::Custom(ErrorObject::owned(BASE_ERROR + 3, msg, None::<()>)), Error::WitnessCompactionFailed => CallError::Custom(ErrorObject::owned(BASE_ERROR + 4, msg, None::<()>)), + Error::ProofExtractionFailed => + CallError::Custom(ErrorObject::owned(BASE_ERROR + 5, msg, None::<()>)), Error::UnsafeRpcCalled(e) => e.into(), } .into() diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index f81143583eacf..de04af259600b 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -206,8 +206,7 @@ where let (client, backend) = { let db_config = sc_client_db::DatabaseSettings { - state_cache_size: config.state_cache_size, - state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), + trie_cache_maximum_size: config.trie_cache_maximum_size, state_pruning: config.state_pruning.clone(), source: config.database.clone(), blocks_pruning: config.blocks_pruning, diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 1e8114df13339..de851ac848919 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -28,7 +28,7 @@ use sp_core::{ use sp_externalities::Extensions; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_state_machine::{ - self, backend::Backend as _, ExecutionManager, ExecutionStrategy, Ext, OverlayedChanges, + backend::AsTrieBackend, ExecutionManager, ExecutionStrategy, Ext, OverlayedChanges, StateMachine, StorageProof, }; use std::{cell::RefCell, panic::UnwindSafe, result, sync::Arc}; @@ -224,15 +224,11 @@ where match recorder { Some(recorder) => { - let trie_state = state.as_trie_backend().ok_or_else(|| { - Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) - as Box - })?; - - let backend = sp_state_machine::ProvingBackend::new_with_recorder( - trie_state, - recorder.clone(), - ); + let trie_state = state.as_trie_backend(); + + let backend = sp_state_machine::TrieBackendBuilder::wrap(&trie_state) + .with_recorder(recorder.clone()) + .build(); let mut state_machine = StateMachine::new( &backend, @@ -294,10 +290,7 @@ where ) -> sp_blockchain::Result<(Vec, StorageProof)> { let state = self.backend.state_at(*at)?; - let trie_backend = state.as_trie_backend().ok_or_else(|| { - Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) - as Box - })?; + let trie_backend = state.as_trie_backend(); let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend); let runtime_code = diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index d61d7f7fa3781..9d6a2e0457a84 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1327,7 +1327,7 @@ where Some(&root), ) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?; - let proving_backend = sp_state_machine::TrieBackend::new(db, root); + let proving_backend = sp_state_machine::TrieBackendBuilder::new(db, root).build(); let state = read_range_proof_check_with_child_on_proving_backend::>( &proving_backend, start_key, @@ -1689,6 +1689,10 @@ where fn runtime_version_at(&self, at: &BlockId) -> Result { CallExecutor::runtime_version(&self.executor, at).map_err(Into::into) } + + fn state_at(&self, at: &BlockId) -> Result { + self.state_at(at).map_err(Into::into) + } } /// NOTE: only use this implementation when you are sure there are NO consensus-level BlockImport diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 7860ff2281fe4..6f5650df5648c 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -70,10 +70,10 @@ pub struct Configuration { pub keystore_remote: Option, /// Configuration for the database. pub database: DatabaseSource, - /// Size of internal state cache in Bytes - pub state_cache_size: usize, - /// Size in percent of cache size dedicated to child tries - pub state_cache_child_ratio: Option, + /// Maximum size of internal trie cache in bytes. + /// + /// If `None` is given the cache is disabled. + pub trie_cache_maximum_size: Option, /// State pruning settings. pub state_pruning: Option, /// Number of blocks to keep in the db. diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 9c4fa84c144c7..f02b1321d2922 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1197,8 +1197,7 @@ fn doesnt_import_blocks_that_revert_finality() { let backend = Arc::new( Backend::new( DatabaseSettings { - state_cache_size: 1 << 20, - state_cache_child_ratio: None, + trie_cache_maximum_size: Some(1 << 20), state_pruning: Some(PruningMode::ArchiveAll), blocks_pruning: BlocksPruning::All, source: DatabaseSource::RocksDb { path: tmp.path().into(), cache_size: 1024 }, @@ -1424,8 +1423,7 @@ fn returns_status_for_pruned_blocks() { let backend = Arc::new( Backend::new( DatabaseSettings { - state_cache_size: 1 << 20, - state_cache_child_ratio: None, + trie_cache_maximum_size: Some(1 << 20), state_pruning: Some(PruningMode::blocks_pruning(1)), blocks_pruning: BlocksPruning::All, source: DatabaseSource::RocksDb { path: tmp.path().into(), cache_size: 1024 }, diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 9c720c6fedea0..919c90400e94c 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -232,8 +232,7 @@ fn node_config< keystore_remote: Default::default(), keystore: KeystoreConfig::Path { path: root.join("key"), password: None }, database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, - state_cache_size: 16777216, - state_cache_child_ratio: None, + trie_cache_maximum_size: Some(16 * 1024 * 1024), state_pruning: Default::default(), blocks_pruning: BlocksPruning::All, chain_spec: Box::new((*spec).clone()), diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index 2a749f2aae9dd..c72ab8c210d69 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -39,8 +39,8 @@ use sp_session::{MembershipProof, ValidatorCount}; use sp_staking::SessionIndex; use sp_std::prelude::*; use sp_trie::{ - trie_types::{TrieDB, TrieDBMutV0}, - MemoryDB, Recorder, Trie, TrieMut, EMPTY_PREFIX, + trie_types::{TrieDBBuilder, TrieDBMutBuilderV0}, + LayoutV0, MemoryDB, Recorder, Trie, TrieMut, EMPTY_PREFIX, }; use frame_support::{ @@ -236,7 +236,7 @@ impl ProvingTrie { let mut root = Default::default(); { - let mut trie = TrieDBMutV0::new(&mut db, &mut root); + let mut trie = TrieDBMutBuilderV0::new(&mut db, &mut root).build(); for (i, (validator, full_id)) in validators.into_iter().enumerate() { let i = i as u32; let keys = match >::load_keys(&validator) { @@ -278,19 +278,20 @@ impl ProvingTrie { /// Prove the full verification data for a given key and key ID. pub fn prove(&self, key_id: KeyTypeId, key_data: &[u8]) -> Option>> { - let trie = TrieDB::new(&self.db, &self.root).ok()?; - let mut recorder = Recorder::new(); - let val_idx = (key_id, key_data).using_encoded(|s| { - trie.get_with(s, &mut recorder) - .ok()? - .and_then(|raw| u32::decode(&mut &*raw).ok()) - })?; - - val_idx.using_encoded(|s| { - trie.get_with(s, &mut recorder) - .ok()? - .and_then(|raw| >::decode(&mut &*raw).ok()) - })?; + let mut recorder = Recorder::>::new(); + { + let trie = + TrieDBBuilder::new(&self.db, &self.root).with_recorder(&mut recorder).build(); + let val_idx = (key_id, key_data).using_encoded(|s| { + trie.get(s).ok()?.and_then(|raw| u32::decode(&mut &*raw).ok()) + })?; + + val_idx.using_encoded(|s| { + trie.get(s) + .ok()? + .and_then(|raw| >::decode(&mut &*raw).ok()) + })?; + } Some(recorder.drain().into_iter().map(|r| r.data).collect()) } @@ -303,7 +304,7 @@ impl ProvingTrie { // Check a proof contained within the current memory-db. Returns `None` if the // nodes within the current `MemoryDB` are insufficient to query the item. fn query(&self, key_id: KeyTypeId, key_data: &[u8]) -> Option> { - let trie = TrieDB::new(&self.db, &self.root).ok()?; + let trie = TrieDBBuilder::new(&self.db, &self.root).build(); let val_idx = (key_id, key_data) .using_encoded(|s| trie.get(s)) .ok()? diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index f3d091266d5d4..75c935bf844bd 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -20,6 +20,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-version = { version = "5.0.0", default-features = false, path = "../version" } sp-state-machine = { version = "0.12.0", optional = true, path = "../state-machine" } +sp-trie = { version = "6.0.0", optional = true, path = "../trie" } hash-db = { version = "0.15.2", optional = true } thiserror = { version = "1.0.30", optional = true } @@ -36,6 +37,7 @@ std = [ "sp-std/std", "sp-runtime/std", "sp-state-machine", + "sp-trie", "sp-version/std", "hash-db", "thiserror", diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index 0087a1ad37ab9..5ab8fa0521699 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -277,9 +277,13 @@ fn generate_runtime_api_base_structures() -> Result { std::clone::Clone::clone(&self.recorder) } - fn extract_proof(&mut self) -> std::option::Option<#crate_::StorageProof> { - std::option::Option::take(&mut self.recorder) - .map(|recorder| #crate_::ProofRecorder::::to_storage_proof(&recorder)) + fn extract_proof( + &mut self, + ) -> std::option::Option<#crate_::StorageProof> { + let recorder = std::option::Option::take(&mut self.recorder); + std::option::Option::map(recorder, |recorder| { + #crate_::ProofRecorder::::drain_storage_proof(recorder) + }) } fn into_storage_changes( diff --git a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs index 4de0f6b9e571b..e43a302e18923 100644 --- a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs @@ -104,7 +104,9 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result Option<#crate_::StorageProof> { + fn extract_proof( + &mut self, + ) -> Option<#crate_::StorageProof> { unimplemented!("`extract_proof` not implemented for runtime api mocks") } diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index a5230cfc5f116..353ebd91cf5df 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -99,7 +99,8 @@ pub use sp_runtime::{ #[doc(hidden)] #[cfg(feature = "std")] pub use sp_state_machine::{ - Backend as StateBackend, InMemoryBackend, OverlayedChanges, StorageProof, + backend::AsTrieBackend, Backend as StateBackend, InMemoryBackend, OverlayedChanges, + StorageProof, TrieBackend, TrieBackendBuilder, }; #[cfg(feature = "std")] use sp_std::result; @@ -454,7 +455,7 @@ pub use sp_api_proc_macro::mock_impl_runtime_apis; /// A type that records all accessed trie nodes and generates a proof out of it. #[cfg(feature = "std")] -pub type ProofRecorder = sp_state_machine::ProofRecorder<::Hash>; +pub type ProofRecorder = sp_trie::recorder::Recorder>; /// A type that is used as cache for the storage transactions. #[cfg(feature = "std")] @@ -518,6 +519,8 @@ pub enum ApiError { #[source] error: codec::Error, }, + #[error("The given `StateBackend` isn't a `TrieBackend`.")] + StateBackendIsNotTrie, #[error(transparent)] Application(#[from] Box), } @@ -613,7 +616,7 @@ pub struct CallApiAtParams<'a, Block: BlockT, NC, Backend: StateBackend { /// The state backend that is used to store the block states. - type StateBackend: StateBackend>; + type StateBackend: StateBackend> + AsTrieBackend>; /// Calls the given api function with the given encoded arguments at the given block and returns /// the encoded result. @@ -627,6 +630,9 @@ pub trait CallApiAt { /// Returns the runtime version at the given block. fn runtime_version_at(&self, at: &BlockId) -> Result; + + /// Get the state `at` the given block. + fn state_at(&self, at: &BlockId) -> Result; } /// Auxiliary wrapper that holds an api instance and binds it to the given lifetime. diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 1c652966180a7..00acca7e86788 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -35,6 +35,7 @@ hex-literal = "0.3.4" pretty_assertions = "1.2.1" rand = "0.7.2" sp-runtime = { version = "6.0.0", path = "../runtime" } +trie-db = "0.24.0" assert_matches = "1.5" [features] diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index 505b53c800f9e..791183c4d7e4d 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -17,9 +17,11 @@ //! State machine backends. These manage the code and storage of contracts. +#[cfg(feature = "std")] +use crate::trie_backend::TrieBackend; use crate::{ - trie_backend::TrieBackend, trie_backend_essence::TrieBackendStorage, ChildStorageCollection, - StorageCollection, StorageKey, StorageValue, UsageInfo, + trie_backend_essence::TrieBackendStorage, ChildStorageCollection, StorageCollection, + StorageKey, StorageValue, UsageInfo, }; use codec::Encode; use hash_db::Hasher; @@ -46,9 +48,7 @@ pub trait Backend: sp_std::fmt::Debug { fn storage(&self, key: &[u8]) -> Result, Self::Error>; /// Get keyed storage value hash or None if there is nothing associated. - fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { - self.storage(key).map(|v| v.map(|v| H::hash(&v))) - } + fn storage_hash(&self, key: &[u8]) -> Result, Self::Error>; /// Get keyed child storage or None if there is nothing associated. fn child_storage( @@ -62,13 +62,11 @@ pub trait Backend: sp_std::fmt::Debug { &self, child_info: &ChildInfo, key: &[u8], - ) -> Result, Self::Error> { - self.child_storage(child_info, key).map(|v| v.map(|v| H::hash(&v))) - } + ) -> Result, Self::Error>; /// true if a key exists in storage. fn exists_storage(&self, key: &[u8]) -> Result { - Ok(self.storage(key)?.is_some()) + Ok(self.storage_hash(key)?.is_some()) } /// true if a key exists in child storage. @@ -77,7 +75,7 @@ pub trait Backend: sp_std::fmt::Debug { child_info: &ChildInfo, key: &[u8], ) -> Result { - Ok(self.child_storage(child_info, key)?.is_some()) + Ok(self.child_storage_hash(child_info, key)?.is_some()) } /// Return the next key in storage in lexicographic order or `None` if there is no value. @@ -175,10 +173,6 @@ pub trait Backend: sp_std::fmt::Debug { all } - /// Try convert into trie backend. - fn as_trie_backend(&self) -> Option<&TrieBackend> { - None - } /// Calculate the storage root, with given delta over what is already stored /// in the backend, and produce a "transaction" that can be used to commit. /// Does include child storage updates. @@ -273,6 +267,16 @@ pub trait Backend: sp_std::fmt::Debug { } } +/// Something that can be converted into a [`TrieBackend`]. +#[cfg(feature = "std")] +pub trait AsTrieBackend> { + /// Type of trie backend storage. + type TrieBackendStorage: TrieBackendStorage; + + /// Return the type as [`TrieBackend`]. + fn as_trie_backend(&self) -> &TrieBackend; +} + /// Trait that allows consolidate two transactions together. pub trait Consolidate { /// Consolidate two transactions into one. diff --git a/primitives/state-machine/src/in_memory_backend.rs b/primitives/state-machine/src/in_memory_backend.rs index 6df23cdb7096e..e205e83e85572 100644 --- a/primitives/state-machine/src/in_memory_backend.rs +++ b/primitives/state-machine/src/in_memory_backend.rs @@ -19,6 +19,7 @@ use crate::{ backend::Backend, trie_backend::TrieBackend, StorageCollection, StorageKey, StorageValue, + TrieBackendBuilder, }; use codec::Codec; use hash_db::Hasher; @@ -46,7 +47,7 @@ where { let db = GenericMemoryDB::default(); // V1 is same as V0 for an empty trie. - TrieBackend::new(db, empty_trie_root::>()) + TrieBackendBuilder::new(db, empty_trie_root::>()).build() } impl TrieBackend, H> @@ -87,14 +88,14 @@ where pub fn update_backend(&self, root: H::Out, changes: GenericMemoryDB) -> Self { let mut clone = self.backend_storage().clone(); clone.consolidate(changes); - Self::new(clone, root) + TrieBackendBuilder::new(clone, root).build() } /// Apply the given transaction to this backend and set the root to the given value. pub fn apply_transaction(&mut self, root: H::Out, transaction: GenericMemoryDB) { let mut storage = sp_std::mem::take(self).into_storage(); storage.consolidate(transaction); - *self = TrieBackend::new(storage, root); + *self = TrieBackendBuilder::new(storage, root).build(); } /// Compare with another in-memory backend. @@ -109,7 +110,7 @@ where KF: KeyFunction + Send + Sync, { fn clone(&self) -> Self { - TrieBackend::new(self.backend_storage().clone(), *self.root()) + TrieBackendBuilder::new(self.backend_storage().clone(), *self.root()).build() } } @@ -203,7 +204,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::backend::Backend; + use crate::backend::{AsTrieBackend, Backend}; use sp_core::storage::StateVersion; use sp_runtime::traits::BlakeTwo256; @@ -218,7 +219,7 @@ mod tests { vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])], state_version, ); - let trie_backend = storage.as_trie_backend().unwrap(); + let trie_backend = storage.as_trie_backend(); assert_eq!(trie_backend.child_storage(child_info, b"2").unwrap(), Some(b"3".to_vec())); let storage_key = child_info.prefixed_storage_key(); assert!(trie_backend.storage(storage_key.as_slice()).unwrap().is_some()); diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index edc3db7a60e36..59488599883e9 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -29,8 +29,6 @@ mod ext; mod in_memory_backend; pub(crate) mod overlayed_changes; #[cfg(feature = "std")] -mod proving_backend; -#[cfg(feature = "std")] mod read_only; mod stats; #[cfg(feature = "std")] @@ -134,7 +132,7 @@ pub use crate::{ StorageTransactionCache, StorageValue, }, stats::{StateMachineStats, UsageInfo, UsageUnit}, - trie_backend::TrieBackend, + trie_backend::{TrieBackend, TrieBackendBuilder}, trie_backend_essence::{Storage, TrieBackendStorage}, }; @@ -144,11 +142,9 @@ mod std_reexport { basic::BasicExternalities, error::{Error, ExecutionError}, in_memory_backend::{new_in_mem, new_in_mem_hash_key}, - proving_backend::{ - create_proof_check_backend, ProofRecorder, ProvingBackend, ProvingBackendRecorder, - }, read_only::{InspectState, ReadOnlyExternalities}, testing::TestExternalities, + trie_backend::create_proof_check_backend, }; pub use sp_trie::{ trie_types::{TrieDBMutV0, TrieDBMutV1}, @@ -158,6 +154,8 @@ mod std_reexport { #[cfg(feature = "std")] mod execution { + use crate::backend::AsTrieBackend; + use super::*; use codec::{Codec, Decode, Encode}; use hash_db::Hasher; @@ -188,9 +186,6 @@ mod execution { /// Trie backend with in-memory storage. pub type InMemoryBackend = TrieBackend, H>; - /// Proving Trie backend with in-memory storage. - pub type InMemoryProvingBackend<'a, H> = ProvingBackend<'a, MemoryDB, H>; - /// Strategy for executing a call into the runtime. #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum ExecutionStrategy { @@ -562,15 +557,13 @@ mod execution { runtime_code: &RuntimeCode, ) -> Result<(Vec, StorageProof), Box> where - B: Backend, + B: AsTrieBackend, H: Hasher, H::Out: Ord + 'static + codec::Codec, Exec: CodeExecutor + Clone + 'static, Spawn: SpawnNamed + Send + 'static, { - let trie_backend = backend - .as_trie_backend() - .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; + let trie_backend = backend.as_trie_backend(); prove_execution_on_trie_backend::<_, _, _, _>( trie_backend, overlay, @@ -607,23 +600,31 @@ mod execution { Exec: CodeExecutor + 'static + Clone, Spawn: SpawnNamed + Send + 'static, { - let proving_backend = proving_backend::ProvingBackend::new(trie_backend); - let mut sm = StateMachine::<_, H, Exec>::new( - &proving_backend, - overlay, - exec, - method, - call_data, - Extensions::default(), - runtime_code, - spawn_handle, - ); + let proving_backend = + TrieBackendBuilder::wrap(trie_backend).with_recorder(Default::default()).build(); + + let result = { + let mut sm = StateMachine::<_, H, Exec>::new( + &proving_backend, + overlay, + exec, + method, + call_data, + Extensions::default(), + runtime_code, + spawn_handle, + ); + + sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( + always_wasm(), + None, + )? + }; + + let proof = proving_backend + .extract_proof() + .expect("A recorder was set and thus, a storage proof can be extracted; qed"); - let result = sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - always_wasm(), - None, - )?; - let proof = sm.backend.extract_proof(); Ok((result.into_encoded(), proof)) } @@ -639,7 +640,7 @@ mod execution { runtime_code: &RuntimeCode, ) -> Result, Box> where - H: Hasher, + H: Hasher + 'static, Exec: CodeExecutor + Clone + 'static, H::Out: Ord + 'static + codec::Codec, Spawn: SpawnNamed + Send + 'static, @@ -693,15 +694,13 @@ mod execution { /// Generate storage read proof. pub fn prove_read(backend: B, keys: I) -> Result> where - B: Backend, + B: AsTrieBackend, H: Hasher, H::Out: Ord + Codec, I: IntoIterator, I::Item: AsRef<[u8]>, { - let trie_backend = backend - .as_trie_backend() - .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; + let trie_backend = backend.as_trie_backend(); prove_read_on_trie_backend(trie_backend, keys) } @@ -829,13 +828,11 @@ mod execution { start_at: &[Vec], ) -> Result<(StorageProof, u32), Box> where - B: Backend, + B: AsTrieBackend, H: Hasher, H::Out: Ord + Codec, { - let trie_backend = backend - .as_trie_backend() - .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; + let trie_backend = backend.as_trie_backend(); prove_range_read_with_child_with_size_on_trie_backend(trie_backend, size_limit, start_at) } @@ -856,7 +853,9 @@ mod execution { return Err(Box::new("Invalid start of range.")) } - let proving_backend = proving_backend::ProvingBackend::::new(trie_backend); + let recorder = sp_trie::recorder::Recorder::default(); + let proving_backend = + TrieBackendBuilder::wrap(trie_backend).with_recorder(recorder.clone()).build(); let mut count = 0; let mut child_roots = HashSet::new(); @@ -924,7 +923,7 @@ mod execution { // do not add two child trie with same root true } - } else if proving_backend.estimate_encoded_size() <= size_limit { + } else if recorder.estimate_encoded_size() <= size_limit { count += 1; true } else { @@ -948,7 +947,11 @@ mod execution { start_at = None; } } - Ok((proving_backend.extract_proof(), count)) + + let proof = proving_backend + .extract_proof() + .expect("A recorder was set and thus, a storage proof can be extracted; qed"); + Ok((proof, count)) } /// Generate range storage read proof. @@ -960,13 +963,11 @@ mod execution { start_at: Option<&[u8]>, ) -> Result<(StorageProof, u32), Box> where - B: Backend, + B: AsTrieBackend, H: Hasher, H::Out: Ord + Codec, { - let trie_backend = backend - .as_trie_backend() - .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; + let trie_backend = backend.as_trie_backend(); prove_range_read_with_size_on_trie_backend( trie_backend, child_info, @@ -989,7 +990,9 @@ mod execution { H: Hasher, H::Out: Ord + Codec, { - let proving_backend = proving_backend::ProvingBackend::::new(trie_backend); + let recorder = sp_trie::recorder::Recorder::default(); + let proving_backend = + TrieBackendBuilder::wrap(trie_backend).with_recorder(recorder.clone()).build(); let mut count = 0; proving_backend .apply_to_key_values_while( @@ -997,7 +1000,7 @@ mod execution { prefix, start_at, |_key, _value| { - if count == 0 || proving_backend.estimate_encoded_size() <= size_limit { + if count == 0 || recorder.estimate_encoded_size() <= size_limit { count += 1; true } else { @@ -1007,7 +1010,11 @@ mod execution { false, ) .map_err(|e| Box::new(e) as Box)?; - Ok((proving_backend.extract_proof(), count)) + + let proof = proving_backend + .extract_proof() + .expect("A recorder was set and thus, a storage proof can be extracted; qed"); + Ok((proof, count)) } /// Generate child storage read proof. @@ -1017,15 +1024,13 @@ mod execution { keys: I, ) -> Result> where - B: Backend, + B: AsTrieBackend, H: Hasher, H::Out: Ord + Codec, I: IntoIterator, I::Item: AsRef<[u8]>, { - let trie_backend = backend - .as_trie_backend() - .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; + let trie_backend = backend.as_trie_backend(); prove_child_read_on_trie_backend(trie_backend, child_info, keys) } @@ -1041,13 +1046,17 @@ mod execution { I: IntoIterator, I::Item: AsRef<[u8]>, { - let proving_backend = proving_backend::ProvingBackend::<_, H>::new(trie_backend); + let proving_backend = + TrieBackendBuilder::wrap(trie_backend).with_recorder(Default::default()).build(); for key in keys.into_iter() { proving_backend .storage(key.as_ref()) .map_err(|e| Box::new(e) as Box)?; } - Ok(proving_backend.extract_proof()) + + Ok(proving_backend + .extract_proof() + .expect("A recorder was set and thus, a storage proof can be extracted; qed")) } /// Generate storage read proof on pre-created trie backend. @@ -1063,13 +1072,17 @@ mod execution { I: IntoIterator, I::Item: AsRef<[u8]>, { - let proving_backend = proving_backend::ProvingBackend::<_, H>::new(trie_backend); + let proving_backend = + TrieBackendBuilder::wrap(trie_backend).with_recorder(Default::default()).build(); for key in keys.into_iter() { proving_backend .child_storage(child_info, key.as_ref()) .map_err(|e| Box::new(e) as Box)?; } - Ok(proving_backend.extract_proof()) + + Ok(proving_backend + .extract_proof() + .expect("A recorder was set and thus, a storage proof can be extracted; qed")) } /// Check storage read proof, generated by `prove_read` call. @@ -1079,7 +1092,7 @@ mod execution { keys: I, ) -> Result, Option>>, Box> where - H: Hasher, + H: Hasher + 'static, H::Out: Ord + Codec, I: IntoIterator, I::Item: AsRef<[u8]>, @@ -1104,7 +1117,7 @@ mod execution { start_at: &[Vec], ) -> Result<(KeyValueStates, usize), Box> where - H: Hasher, + H: Hasher + 'static, H::Out: Ord + Codec, { let proving_backend = create_proof_check_backend::(root, proof)?; @@ -1121,7 +1134,7 @@ mod execution { start_at: Option<&[u8]>, ) -> Result<(Vec<(Vec, Vec)>, bool), Box> where - H: Hasher, + H: Hasher + 'static, H::Out: Ord + Codec, { let proving_backend = create_proof_check_backend::(root, proof)?; @@ -1142,7 +1155,7 @@ mod execution { keys: I, ) -> Result, Option>>, Box> where - H: Hasher, + H: Hasher + 'static, H::Out: Ord + Codec, I: IntoIterator, I::Item: AsRef<[u8]>, @@ -1346,7 +1359,7 @@ mod execution { #[cfg(test)] mod tests { - use super::{ext::Ext, *}; + use super::{backend::AsTrieBackend, ext::Ext, *}; use crate::{execution::CallResult, in_memory_backend::new_in_mem_hash_key}; use assert_matches::assert_matches; use codec::{Decode, Encode}; @@ -1358,6 +1371,7 @@ mod tests { NativeOrEncoded, NeverNativeValue, }; use sp_runtime::traits::BlakeTwo256; + use sp_trie::trie_types::{TrieDBMutBuilderV0, TrieDBMutBuilderV1}; use std::{ collections::{BTreeMap, HashMap}, panic::UnwindSafe, @@ -1419,7 +1433,7 @@ mod tests { execute_works_inner(StateVersion::V1); } fn execute_works_inner(state_version: StateVersion) { - let backend = trie_backend::tests::test_trie(state_version); + let backend = trie_backend::tests::test_trie(state_version, None, None); let mut overlayed_changes = Default::default(); let wasm_code = RuntimeCode::empty(); @@ -1447,7 +1461,7 @@ mod tests { execute_works_with_native_else_wasm_inner(StateVersion::V1); } fn execute_works_with_native_else_wasm_inner(state_version: StateVersion) { - let backend = trie_backend::tests::test_trie(state_version); + let backend = trie_backend::tests::test_trie(state_version, None, None); let mut overlayed_changes = Default::default(); let wasm_code = RuntimeCode::empty(); @@ -1476,7 +1490,7 @@ mod tests { } fn dual_execution_strategy_detects_consensus_failure_inner(state_version: StateVersion) { let mut consensus_failed = false; - let backend = trie_backend::tests::test_trie(state_version); + let backend = trie_backend::tests::test_trie(state_version, None, None); let mut overlayed_changes = Default::default(); let wasm_code = RuntimeCode::empty(); @@ -1520,7 +1534,7 @@ mod tests { }; // fetch execution proof from 'remote' full node - let mut remote_backend = trie_backend::tests::test_trie(state_version); + let mut remote_backend = trie_backend::tests::test_trie(state_version, None, None); let remote_root = remote_backend.storage_root(std::iter::empty(), state_version).0; let (remote_result, remote_proof) = prove_execution( &mut remote_backend, @@ -1560,7 +1574,7 @@ mod tests { b"bbb".to_vec() => b"3".to_vec() ]; let state = InMemoryBackend::::from((initial, StateVersion::default())); - let backend = state.as_trie_backend().unwrap(); + let backend = state.as_trie_backend(); let mut overlay = OverlayedChanges::default(); overlay.set_storage(b"aba".to_vec(), Some(b"1312".to_vec())); @@ -1716,7 +1730,7 @@ mod tests { let child_info = ChildInfo::new_default(b"sub1"); let child_info = &child_info; let state = new_in_mem_hash_key::(); - let backend = state.as_trie_backend().unwrap(); + let backend = state.as_trie_backend(); let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); @@ -1732,7 +1746,7 @@ mod tests { let reference_data = vec![b"data1".to_vec(), b"2".to_vec(), b"D3".to_vec(), b"d4".to_vec()]; let key = b"key".to_vec(); let state = new_in_mem_hash_key::(); - let backend = state.as_trie_backend().unwrap(); + let backend = state.as_trie_backend(); let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); { @@ -1769,7 +1783,7 @@ mod tests { let key = b"events".to_vec(); let mut cache = StorageTransactionCache::default(); let state = new_in_mem_hash_key::(); - let backend = state.as_trie_backend().unwrap(); + let backend = state.as_trie_backend(); let mut overlay = OverlayedChanges::default(); // For example, block initialization with event. @@ -1840,7 +1854,7 @@ mod tests { let child_info = &child_info; let missing_child_info = &missing_child_info; // fetch read proof from 'remote' full node - let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_backend = trie_backend::tests::test_trie(state_version, None, None); let remote_root = remote_backend.storage_root(std::iter::empty(), state_version).0; let remote_proof = prove_read(remote_backend, &[b"value2"]).unwrap(); let remote_proof = test_compact(remote_proof, &remote_root); @@ -1857,7 +1871,7 @@ mod tests { ); assert_eq!(local_result2, false); // on child trie - let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_backend = trie_backend::tests::test_trie(state_version, None, None); let remote_root = remote_backend.storage_root(std::iter::empty(), state_version).0; let remote_proof = prove_child_read(remote_backend, child_info, &[b"value3"]).unwrap(); let remote_proof = test_compact(remote_proof, &remote_root); @@ -1924,8 +1938,8 @@ mod tests { let trie: InMemoryBackend = (storage.clone(), StateVersion::default()).into(); - let trie_root = trie.root(); - let backend = crate::ProvingBackend::new(&trie); + let trie_root = *trie.root(); + let backend = TrieBackendBuilder::wrap(&trie).with_recorder(Default::default()).build(); let mut queries = Vec::new(); for c in 0..(5 + nb_child_trie / 2) { // random existing query @@ -1970,10 +1984,10 @@ mod tests { } } - let storage_proof = backend.extract_proof(); + let storage_proof = backend.extract_proof().expect("Failed to extract proof"); let remote_proof = test_compact(storage_proof, &trie_root); let proof_check = - create_proof_check_backend::(*trie_root, remote_proof).unwrap(); + create_proof_check_backend::(trie_root, remote_proof).unwrap(); for (child_info, key, expected) in queries { assert_eq!( @@ -1987,7 +2001,7 @@ mod tests { #[test] fn prove_read_with_size_limit_works() { let state_version = StateVersion::V0; - let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_backend = trie_backend::tests::test_trie(state_version, None, None); let remote_root = remote_backend.storage_root(::std::iter::empty(), state_version).0; let (proof, count) = prove_range_read_with_size(remote_backend, None, None, 0, None).unwrap(); @@ -1995,7 +2009,7 @@ mod tests { assert_eq!(proof.into_memory_db::().drain().len(), 3); assert_eq!(count, 1); - let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_backend = trie_backend::tests::test_trie(state_version, None, None); let (proof, count) = prove_range_read_with_size(remote_backend, None, None, 800, Some(&[])).unwrap(); assert_eq!(proof.clone().into_memory_db::().drain().len(), 9); @@ -2018,7 +2032,7 @@ mod tests { assert_eq!(results.len() as u32, 101); assert_eq!(completed, false); - let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_backend = trie_backend::tests::test_trie(state_version, None, None); let (proof, count) = prove_range_read_with_size(remote_backend, None, None, 50000, Some(&[])).unwrap(); assert_eq!(proof.clone().into_memory_db::().drain().len(), 11); @@ -2035,7 +2049,7 @@ mod tests { let mut state_version = StateVersion::V0; let (mut mdb, mut root) = trie_backend::tests::test_db(state_version); { - let mut trie = TrieDBMutV0::from_existing(&mut mdb, &mut root).unwrap(); + let mut trie = TrieDBMutBuilderV0::from_existing(&mut mdb, &mut root).build(); trie.insert(b"foo", vec![1u8; 1_000].as_slice()) // big inner hash .expect("insert failed"); trie.insert(b"foo2", vec![3u8; 16].as_slice()) // no inner hash @@ -2045,7 +2059,7 @@ mod tests { } let check_proof = |mdb, root, state_version| -> StorageProof { - let remote_backend = TrieBackend::new(mdb, root); + let remote_backend = TrieBackendBuilder::new(mdb, root).build(); let remote_root = remote_backend.storage_root(std::iter::empty(), state_version).0; let remote_proof = prove_read(remote_backend, &[b"foo222"]).unwrap(); // check proof locally @@ -2069,7 +2083,7 @@ mod tests { // do switch state_version = StateVersion::V1; { - let mut trie = TrieDBMutV1::from_existing(&mut mdb, &mut root).unwrap(); + let mut trie = TrieDBMutBuilderV1::from_existing(&mut mdb, &mut root).build(); trie.insert(b"foo222", vec![5u8; 100].as_slice()) // inner hash .expect("insert failed"); // update with same value do change @@ -2088,10 +2102,10 @@ mod tests { #[test] fn prove_range_with_child_works() { let state_version = StateVersion::V0; - let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_backend = trie_backend::tests::test_trie(state_version, None, None); let remote_root = remote_backend.storage_root(std::iter::empty(), state_version).0; let mut start_at = smallvec::SmallVec::<[Vec; 2]>::new(); - let trie_backend = remote_backend.as_trie_backend().unwrap(); + let trie_backend = remote_backend.as_trie_backend(); let max_iter = 1000; let mut nb_loop = 0; loop { @@ -2138,7 +2152,7 @@ mod tests { let child_info2 = ChildInfo::new_default(b"sub2"); // this root will be include in proof let child_info3 = ChildInfo::new_default(b"sub"); - let remote_backend = trie_backend::tests::test_trie(state_version); + let remote_backend = trie_backend::tests::test_trie(state_version, None, None); let long_vec: Vec = (0..1024usize).map(|_| 8u8).collect(); let (remote_root, transaction) = remote_backend.full_storage_root( std::iter::empty(), @@ -2170,9 +2184,9 @@ mod tests { .into_iter(), state_version, ); - let mut remote_storage = remote_backend.into_storage(); + let mut remote_storage = remote_backend.backend_storage().clone(); remote_storage.consolidate(transaction); - let remote_backend = TrieBackend::new(remote_storage, remote_root); + let remote_backend = TrieBackendBuilder::new(remote_storage, remote_root).build(); let remote_proof = prove_child_read(remote_backend, &child_info1, &[b"key1"]).unwrap(); let size = remote_proof.encoded_size(); let remote_proof = test_compact(remote_proof, &remote_root); @@ -2198,7 +2212,7 @@ mod tests { let mut overlay = OverlayedChanges::default(); let mut transaction = { - let backend = test_trie(state_version); + let backend = test_trie(state_version, None, None); let mut cache = StorageTransactionCache::default(); let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); ext.set_child_storage(&child_info_1, b"abc".to_vec(), b"def".to_vec()); @@ -2224,7 +2238,7 @@ mod tests { b"bbb".to_vec() => b"".to_vec() ]; let state = InMemoryBackend::::from((initial, StateVersion::default())); - let backend = state.as_trie_backend().unwrap(); + let backend = state.as_trie_backend(); let mut overlay = OverlayedChanges::default(); overlay.start_transaction(); @@ -2255,7 +2269,7 @@ mod tests { struct DummyExt(u32); } - let backend = trie_backend::tests::test_trie(state_version); + let backend = trie_backend::tests::test_trie(state_version, None, None); let mut overlayed_changes = Default::default(); let wasm_code = RuntimeCode::empty(); diff --git a/primitives/state-machine/src/proving_backend.rs b/primitives/state-machine/src/proving_backend.rs deleted file mode 100644 index f5cf542908b10..0000000000000 --- a/primitives/state-machine/src/proving_backend.rs +++ /dev/null @@ -1,611 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Proving state machine backend. - -use crate::{ - trie_backend::TrieBackend, - trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage}, - Backend, DBValue, Error, ExecutionError, -}; -use codec::{Codec, Decode, Encode}; -use hash_db::{HashDB, Hasher, Prefix, EMPTY_PREFIX}; -use log::debug; -use parking_lot::RwLock; -use sp_core::storage::{ChildInfo, StateVersion}; -pub use sp_trie::trie_types::TrieError; -use sp_trie::{ - empty_child_trie_root, read_child_trie_value_with, read_trie_value_with, record_all_keys, - LayoutV1, MemoryDB, Recorder, StorageProof, -}; -use std::{ - collections::{hash_map::Entry, HashMap}, - sync::Arc, -}; - -/// Patricia trie-based backend specialized in get value proofs. -pub struct ProvingBackendRecorder<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> { - pub(crate) backend: &'a TrieBackendEssence, - pub(crate) proof_recorder: &'a mut Recorder, -} - -impl<'a, S, H> ProvingBackendRecorder<'a, S, H> -where - S: TrieBackendStorage, - H: Hasher, - H::Out: Codec, -{ - /// Produce proof for a key query. - pub fn storage(&mut self, key: &[u8]) -> Result>, String> { - let mut read_overlay = S::Overlay::default(); - let eph = Ephemeral::new(self.backend.backend_storage(), &mut read_overlay); - - let map_e = |e| format!("Trie lookup error: {}", e); - - // V1 is equivalent to V0 on read. - read_trie_value_with::, _, Ephemeral>( - &eph, - self.backend.root(), - key, - &mut *self.proof_recorder, - ) - .map_err(map_e) - } - - /// Produce proof for a child key query. - pub fn child_storage( - &mut self, - child_info: &ChildInfo, - key: &[u8], - ) -> Result>, String> { - let storage_key = child_info.storage_key(); - let root = self - .storage(storage_key)? - .and_then(|r| Decode::decode(&mut &r[..]).ok()) - // V1 is equivalent to V0 on empty trie - .unwrap_or_else(empty_child_trie_root::>); - - let mut read_overlay = S::Overlay::default(); - let eph = Ephemeral::new(self.backend.backend_storage(), &mut read_overlay); - - let map_e = |e| format!("Trie lookup error: {}", e); - - // V1 is equivalent to V0 on read - read_child_trie_value_with::, _, _>( - child_info.keyspace(), - &eph, - root.as_ref(), - key, - &mut *self.proof_recorder, - ) - .map_err(map_e) - } - - /// Produce proof for the whole backend. - pub fn record_all_keys(&mut self) { - let mut read_overlay = S::Overlay::default(); - let eph = Ephemeral::new(self.backend.backend_storage(), &mut read_overlay); - - let mut iter = move || -> Result<(), Box>> { - let root = self.backend.root(); - // V1 and V is equivalent to V0 on read and recorder is key read. - record_all_keys::, _>(&eph, root, &mut *self.proof_recorder) - }; - - if let Err(e) = iter() { - debug!(target: "trie", "Error while recording all keys: {}", e); - } - } -} - -#[derive(Default)] -struct ProofRecorderInner { - /// All the records that we have stored so far. - records: HashMap>, - /// The encoded size of all recorded values. - encoded_size: usize, -} - -/// Global proof recorder, act as a layer over a hash db for recording queried data. -#[derive(Clone, Default)] -pub struct ProofRecorder { - inner: Arc>>, -} - -impl ProofRecorder { - /// Record the given `key` => `val` combination. - pub fn record(&self, key: Hash, val: Option) { - let mut inner = self.inner.write(); - let encoded_size = if let Entry::Vacant(entry) = inner.records.entry(key) { - let encoded_size = val.as_ref().map(Encode::encoded_size).unwrap_or(0); - - entry.insert(val); - encoded_size - } else { - 0 - }; - - inner.encoded_size += encoded_size; - } - - /// Returns the value at the given `key`. - pub fn get(&self, key: &Hash) -> Option> { - self.inner.read().records.get(key).cloned() - } - - /// Returns the estimated encoded size of the proof. - /// - /// The estimation is maybe bigger (by in maximum 4 bytes), but never smaller than the actual - /// encoded proof. - pub fn estimate_encoded_size(&self) -> usize { - let inner = self.inner.read(); - inner.encoded_size + codec::Compact(inner.records.len() as u32).encoded_size() - } - - /// Convert into a [`StorageProof`]. - pub fn to_storage_proof(&self) -> StorageProof { - StorageProof::new( - self.inner - .read() - .records - .iter() - .filter_map(|(_k, v)| v.as_ref().map(|v| v.to_vec())), - ) - } - - /// Reset the internal state. - pub fn reset(&self) { - let mut inner = self.inner.write(); - inner.records.clear(); - inner.encoded_size = 0; - } -} - -/// Patricia trie-based backend which also tracks all touched storage trie values. -/// These can be sent to remote node and used as a proof of execution. -pub struct ProvingBackend<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher>( - TrieBackend, H>, -); - -/// Trie backend storage with its proof recorder. -pub struct ProofRecorderBackend<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> { - backend: &'a S, - proof_recorder: ProofRecorder, -} - -impl<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> ProvingBackend<'a, S, H> -where - H::Out: Codec, -{ - /// Create new proving backend. - pub fn new(backend: &'a TrieBackend) -> Self { - let proof_recorder = Default::default(); - Self::new_with_recorder(backend, proof_recorder) - } - - /// Create new proving backend with the given recorder. - pub fn new_with_recorder( - backend: &'a TrieBackend, - proof_recorder: ProofRecorder, - ) -> Self { - let essence = backend.essence(); - let root = *essence.root(); - let recorder = ProofRecorderBackend { backend: essence.backend_storage(), proof_recorder }; - ProvingBackend(TrieBackend::new(recorder, root)) - } - - /// Extracting the gathered unordered proof. - pub fn extract_proof(&self) -> StorageProof { - self.0.essence().backend_storage().proof_recorder.to_storage_proof() - } - - /// Returns the estimated encoded size of the proof. - /// - /// The estimation is maybe bigger (by in maximum 4 bytes), but never smaller than the actual - /// encoded proof. - pub fn estimate_encoded_size(&self) -> usize { - self.0.essence().backend_storage().proof_recorder.estimate_encoded_size() - } - - /// Clear the proof recorded data. - pub fn clear_recorder(&self) { - self.0.essence().backend_storage().proof_recorder.reset() - } -} - -impl<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> TrieBackendStorage - for ProofRecorderBackend<'a, S, H> -{ - type Overlay = S::Overlay; - - fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String> { - if let Some(v) = self.proof_recorder.get(key) { - return Ok(v) - } - - let backend_value = self.backend.get(key, prefix)?; - self.proof_recorder.record(*key, backend_value.clone()); - Ok(backend_value) - } -} - -impl<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> std::fmt::Debug - for ProvingBackend<'a, S, H> -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "ProvingBackend") - } -} - -impl<'a, S, H> Backend for ProvingBackend<'a, S, H> -where - S: 'a + TrieBackendStorage, - H: 'a + Hasher, - H::Out: Ord + Codec, -{ - type Error = String; - type Transaction = S::Overlay; - type TrieBackendStorage = S; - - fn storage(&self, key: &[u8]) -> Result>, Self::Error> { - self.0.storage(key) - } - - fn child_storage( - &self, - child_info: &ChildInfo, - key: &[u8], - ) -> Result>, Self::Error> { - self.0.child_storage(child_info, key) - } - - fn apply_to_key_values_while, Vec) -> bool>( - &self, - child_info: Option<&ChildInfo>, - prefix: Option<&[u8]>, - start_at: Option<&[u8]>, - f: F, - allow_missing: bool, - ) -> Result { - self.0.apply_to_key_values_while(child_info, prefix, start_at, f, allow_missing) - } - - fn apply_to_keys_while bool>( - &self, - child_info: Option<&ChildInfo>, - prefix: Option<&[u8]>, - start_at: Option<&[u8]>, - f: F, - ) { - self.0.apply_to_keys_while(child_info, prefix, start_at, f) - } - - fn next_storage_key(&self, key: &[u8]) -> Result>, Self::Error> { - self.0.next_storage_key(key) - } - - fn next_child_storage_key( - &self, - child_info: &ChildInfo, - key: &[u8], - ) -> Result>, Self::Error> { - self.0.next_child_storage_key(child_info, key) - } - - fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { - self.0.for_keys_with_prefix(prefix, f) - } - - fn for_key_values_with_prefix(&self, prefix: &[u8], f: F) { - self.0.for_key_values_with_prefix(prefix, f) - } - - fn for_child_keys_with_prefix( - &self, - child_info: &ChildInfo, - prefix: &[u8], - f: F, - ) { - self.0.for_child_keys_with_prefix(child_info, prefix, f) - } - - fn pairs(&self) -> Vec<(Vec, Vec)> { - self.0.pairs() - } - - fn keys(&self, prefix: &[u8]) -> Vec> { - self.0.keys(prefix) - } - - fn child_keys(&self, child_info: &ChildInfo, prefix: &[u8]) -> Vec> { - self.0.child_keys(child_info, prefix) - } - - fn storage_root<'b>( - &self, - delta: impl Iterator)>, - state_version: StateVersion, - ) -> (H::Out, Self::Transaction) - where - H::Out: Ord, - { - self.0.storage_root(delta, state_version) - } - - fn child_storage_root<'b>( - &self, - child_info: &ChildInfo, - delta: impl Iterator)>, - state_version: StateVersion, - ) -> (H::Out, bool, Self::Transaction) - where - H::Out: Ord, - { - self.0.child_storage_root(child_info, delta, state_version) - } - - fn register_overlay_stats(&self, _stats: &crate::stats::StateMachineStats) {} - - fn usage_info(&self) -> crate::stats::UsageInfo { - self.0.usage_info() - } -} - -/// Create a backend used for checking the proof., using `H` as hasher. -/// -/// `proof` and `root` must match, i.e. `root` must be the correct root of `proof` nodes. -pub fn create_proof_check_backend( - root: H::Out, - proof: StorageProof, -) -> Result, H>, Box> -where - H: Hasher, - H::Out: Codec, -{ - let db = proof.into_memory_db(); - - if db.contains(&root, EMPTY_PREFIX) { - Ok(TrieBackend::new(db, root)) - } else { - Err(Box::new(ExecutionError::InvalidProof)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - proving_backend::create_proof_check_backend, trie_backend::tests::test_trie, - InMemoryBackend, - }; - use sp_core::H256; - use sp_runtime::traits::BlakeTwo256; - use sp_trie::PrefixedMemoryDB; - - fn test_proving( - trie_backend: &TrieBackend, BlakeTwo256>, - ) -> ProvingBackend, BlakeTwo256> { - ProvingBackend::new(trie_backend) - } - - #[test] - fn proof_is_empty_until_value_is_read() { - proof_is_empty_until_value_is_read_inner(StateVersion::V0); - proof_is_empty_until_value_is_read_inner(StateVersion::V1); - } - fn proof_is_empty_until_value_is_read_inner(test_hash: StateVersion) { - let trie_backend = test_trie(test_hash); - assert!(test_proving(&trie_backend).extract_proof().is_empty()); - } - - #[test] - fn proof_is_non_empty_after_value_is_read() { - proof_is_non_empty_after_value_is_read_inner(StateVersion::V0); - proof_is_non_empty_after_value_is_read_inner(StateVersion::V1); - } - fn proof_is_non_empty_after_value_is_read_inner(test_hash: StateVersion) { - let trie_backend = test_trie(test_hash); - let backend = test_proving(&trie_backend); - assert_eq!(backend.storage(b"key").unwrap(), Some(b"value".to_vec())); - assert!(!backend.extract_proof().is_empty()); - } - - #[test] - fn proof_is_invalid_when_does_not_contains_root() { - let result = create_proof_check_backend::( - H256::from_low_u64_be(1), - StorageProof::empty(), - ); - assert!(result.is_err()); - } - - #[test] - fn passes_through_backend_calls() { - passes_through_backend_calls_inner(StateVersion::V0); - passes_through_backend_calls_inner(StateVersion::V1); - } - fn passes_through_backend_calls_inner(state_version: StateVersion) { - let trie_backend = test_trie(state_version); - let proving_backend = test_proving(&trie_backend); - assert_eq!(trie_backend.storage(b"key").unwrap(), proving_backend.storage(b"key").unwrap()); - assert_eq!(trie_backend.pairs(), proving_backend.pairs()); - - let (trie_root, mut trie_mdb) = - trie_backend.storage_root(std::iter::empty(), state_version); - let (proving_root, mut proving_mdb) = - proving_backend.storage_root(std::iter::empty(), state_version); - assert_eq!(trie_root, proving_root); - assert_eq!(trie_mdb.drain(), proving_mdb.drain()); - } - - #[test] - fn proof_recorded_and_checked_top() { - proof_recorded_and_checked_inner(StateVersion::V0); - proof_recorded_and_checked_inner(StateVersion::V1); - } - fn proof_recorded_and_checked_inner(state_version: StateVersion) { - let size_content = 34; // above hashable value treshold. - let value_range = 0..64; - let contents = value_range - .clone() - .map(|i| (vec![i], Some(vec![i; size_content]))) - .collect::>(); - let in_memory = InMemoryBackend::::default(); - let in_memory = in_memory.update(vec![(None, contents)], state_version); - let in_memory_root = in_memory.storage_root(std::iter::empty(), state_version).0; - value_range.clone().for_each(|i| { - assert_eq!(in_memory.storage(&[i]).unwrap().unwrap(), vec![i; size_content]) - }); - - let trie = in_memory.as_trie_backend().unwrap(); - let trie_root = trie.storage_root(std::iter::empty(), state_version).0; - assert_eq!(in_memory_root, trie_root); - value_range - .for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i; size_content])); - - let proving = ProvingBackend::new(trie); - assert_eq!(proving.storage(&[42]).unwrap().unwrap(), vec![42; size_content]); - - let proof = proving.extract_proof(); - - let proof_check = create_proof_check_backend::(in_memory_root, proof).unwrap(); - assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42; size_content]); - } - - #[test] - fn proof_recorded_and_checked_with_child() { - proof_recorded_and_checked_with_child_inner(StateVersion::V0); - proof_recorded_and_checked_with_child_inner(StateVersion::V1); - } - fn proof_recorded_and_checked_with_child_inner(state_version: StateVersion) { - let child_info_1 = ChildInfo::new_default(b"sub1"); - let child_info_2 = ChildInfo::new_default(b"sub2"); - let child_info_1 = &child_info_1; - let child_info_2 = &child_info_2; - let contents = vec![ - (None, (0..64).map(|i| (vec![i], Some(vec![i]))).collect::>()), - (Some(child_info_1.clone()), (28..65).map(|i| (vec![i], Some(vec![i]))).collect()), - (Some(child_info_2.clone()), (10..15).map(|i| (vec![i], Some(vec![i]))).collect()), - ]; - let in_memory = InMemoryBackend::::default(); - let in_memory = in_memory.update(contents, state_version); - let child_storage_keys = vec![child_info_1.to_owned(), child_info_2.to_owned()]; - let in_memory_root = in_memory - .full_storage_root( - std::iter::empty(), - child_storage_keys.iter().map(|k| (k, std::iter::empty())), - state_version, - ) - .0; - (0..64).for_each(|i| assert_eq!(in_memory.storage(&[i]).unwrap().unwrap(), vec![i])); - (28..65).for_each(|i| { - assert_eq!(in_memory.child_storage(child_info_1, &[i]).unwrap().unwrap(), vec![i]) - }); - (10..15).for_each(|i| { - assert_eq!(in_memory.child_storage(child_info_2, &[i]).unwrap().unwrap(), vec![i]) - }); - - let trie = in_memory.as_trie_backend().unwrap(); - let trie_root = trie.storage_root(std::iter::empty(), state_version).0; - assert_eq!(in_memory_root, trie_root); - (0..64).for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i])); - - let proving = ProvingBackend::new(trie); - assert_eq!(proving.storage(&[42]).unwrap().unwrap(), vec![42]); - - let proof = proving.extract_proof(); - - let proof_check = create_proof_check_backend::(in_memory_root, proof).unwrap(); - assert!(proof_check.storage(&[0]).is_err()); - assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42]); - // note that it is include in root because proof close - assert_eq!(proof_check.storage(&[41]).unwrap().unwrap(), vec![41]); - assert_eq!(proof_check.storage(&[64]).unwrap(), None); - - let proving = ProvingBackend::new(trie); - assert_eq!(proving.child_storage(child_info_1, &[64]), Ok(Some(vec![64]))); - - let proof = proving.extract_proof(); - let proof_check = create_proof_check_backend::(in_memory_root, proof).unwrap(); - assert_eq!(proof_check.child_storage(child_info_1, &[64]).unwrap().unwrap(), vec![64]); - } - - #[test] - fn storage_proof_encoded_size_estimation_works() { - storage_proof_encoded_size_estimation_works_inner(StateVersion::V0); - storage_proof_encoded_size_estimation_works_inner(StateVersion::V1); - } - fn storage_proof_encoded_size_estimation_works_inner(state_version: StateVersion) { - let trie_backend = test_trie(state_version); - let backend = test_proving(&trie_backend); - - let check_estimation = - |backend: &ProvingBackend<'_, PrefixedMemoryDB, BlakeTwo256>| { - let storage_proof = backend.extract_proof(); - let estimation = - backend.0.essence().backend_storage().proof_recorder.estimate_encoded_size(); - - assert_eq!(storage_proof.encoded_size(), estimation); - }; - - assert_eq!(backend.storage(b"key").unwrap(), Some(b"value".to_vec())); - check_estimation(&backend); - - assert_eq!(backend.storage(b"value1").unwrap(), Some(vec![42])); - check_estimation(&backend); - - assert_eq!(backend.storage(b"value2").unwrap(), Some(vec![24])); - check_estimation(&backend); - - assert!(backend.storage(b"doesnotexist").unwrap().is_none()); - check_estimation(&backend); - - assert!(backend.storage(b"doesnotexist2").unwrap().is_none()); - check_estimation(&backend); - } - - #[test] - fn proof_recorded_for_same_execution_should_be_deterministic() { - let storage_changes = vec![ - (H256::random(), Some(b"value1".to_vec())), - (H256::random(), Some(b"value2".to_vec())), - (H256::random(), Some(b"value3".to_vec())), - (H256::random(), Some(b"value4".to_vec())), - (H256::random(), Some(b"value5".to_vec())), - (H256::random(), Some(b"value6".to_vec())), - (H256::random(), Some(b"value7".to_vec())), - (H256::random(), Some(b"value8".to_vec())), - ]; - - let proof_recorder = - ProofRecorder:: { inner: Arc::new(RwLock::new(ProofRecorderInner::default())) }; - storage_changes - .clone() - .into_iter() - .for_each(|(key, val)| proof_recorder.record(key, val)); - let proof1 = proof_recorder.to_storage_proof(); - - let proof_recorder = - ProofRecorder:: { inner: Arc::new(RwLock::new(ProofRecorderInner::default())) }; - storage_changes - .into_iter() - .for_each(|(key, val)| proof_recorder.record(key, val)); - let proof2 = proof_recorder.to_storage_proof(); - - assert_eq!(proof1, proof2); - } -} diff --git a/primitives/state-machine/src/read_only.rs b/primitives/state-machine/src/read_only.rs index 622915a2d0525..e58fb760f4d7e 100644 --- a/primitives/state-machine/src/read_only.rs +++ b/primitives/state-machine/src/read_only.rs @@ -23,7 +23,6 @@ use hash_db::Hasher; use sp_core::{ storage::{ChildInfo, StateVersion, TrackedStorageKey}, traits::Externalities, - Blake2Hasher, }; use sp_externalities::MultiRemovalResults; use std::{ @@ -44,7 +43,10 @@ pub trait InspectState> { fn inspect_state R, R>(&self, f: F) -> R; } -impl> InspectState for B { +impl> InspectState for B +where + H::Out: Encode, +{ fn inspect_state R, R>(&self, f: F) -> R { ReadOnlyExternalities::from(self).execute_with(f) } @@ -66,7 +68,10 @@ impl<'a, H: Hasher, B: 'a + Backend> From<&'a B> for ReadOnlyExternalities<'a } } -impl<'a, H: Hasher, B: 'a + Backend> ReadOnlyExternalities<'a, H, B> { +impl<'a, H: Hasher, B: 'a + Backend> ReadOnlyExternalities<'a, H, B> +where + H::Out: Encode, +{ /// Execute the given closure while `self` is set as externalities. /// /// Returns the result of the given closure. @@ -75,7 +80,10 @@ impl<'a, H: Hasher, B: 'a + Backend> ReadOnlyExternalities<'a, H, B> { } } -impl<'a, H: Hasher, B: 'a + Backend> Externalities for ReadOnlyExternalities<'a, H, B> { +impl<'a, H: Hasher, B: 'a + Backend> Externalities for ReadOnlyExternalities<'a, H, B> +where + H::Out: Encode, +{ fn set_offchain_storage(&mut self, _key: &[u8], _value: Option<&[u8]>) { panic!("Should not be used in read-only externalities!") } @@ -87,7 +95,10 @@ impl<'a, H: Hasher, B: 'a + Backend> Externalities for ReadOnlyExternalities< } fn storage_hash(&self, key: &[u8]) -> Option> { - self.storage(key).map(|v| Blake2Hasher::hash(&v).encode()) + self.backend + .storage_hash(key) + .expect("Backed failed for storage_hash in ReadOnlyExternalities") + .map(|h| h.encode()) } fn child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> Option { @@ -97,7 +108,10 @@ impl<'a, H: Hasher, B: 'a + Backend> Externalities for ReadOnlyExternalities< } fn child_storage_hash(&self, child_info: &ChildInfo, key: &[u8]) -> Option> { - self.child_storage(child_info, key).map(|v| Blake2Hasher::hash(&v).encode()) + self.backend + .child_storage_hash(child_info, key) + .expect("Backed failed for child_storage_hash in ReadOnlyExternalities") + .map(|h| h.encode()) } fn next_storage_key(&self, key: &[u8]) -> Option { diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index 57d4f0b4898eb..46b7573d9d1a6 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -24,7 +24,7 @@ use std::{ use crate::{ backend::Backend, ext::Ext, InMemoryBackend, OverlayedChanges, StorageKey, - StorageTransactionCache, StorageValue, + StorageTransactionCache, StorageValue, TrieBackendBuilder, }; use hash_db::Hasher; @@ -41,8 +41,9 @@ use sp_externalities::{Extension, ExtensionStore, Extensions}; use sp_trie::StorageProof; /// Simple HashMap-based Externalities impl. -pub struct TestExternalities +pub struct TestExternalities where + H: Hasher + 'static, H::Out: codec::Codec + Ord, { /// The overlay changed storage. @@ -58,8 +59,9 @@ where pub state_version: StateVersion, } -impl TestExternalities +impl TestExternalities where + H: Hasher + 'static, H::Out: Ord + 'static + codec::Codec, { /// Get externalities implementation. @@ -202,7 +204,9 @@ where /// This implementation will wipe the proof recorded in between calls. Consecutive calls will /// get their own proof from scratch. pub fn execute_and_prove(&mut self, execute: impl FnOnce() -> R) -> (R, StorageProof) { - let proving_backend = crate::InMemoryProvingBackend::new(&self.backend); + let proving_backend = TrieBackendBuilder::wrap(&self.backend) + .with_recorder(Default::default()) + .build(); let mut proving_ext = Ext::new( &mut self.overlay, &mut self.storage_transaction_cache, @@ -211,7 +215,7 @@ where ); let outcome = sp_externalities::set_and_run_with_externalities(&mut proving_ext, execute); - let proof = proving_backend.extract_proof(); + let proof = proving_backend.extract_proof().expect("Failed to extract storage proof"); (outcome, proof) } diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index 130b4bf178202..447c276a6049c 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -17,31 +17,182 @@ //! Trie-based state machine backend. +#[cfg(feature = "std")] +use crate::backend::AsTrieBackend; use crate::{ trie_backend_essence::{TrieBackendEssence, TrieBackendStorage}, Backend, StorageKey, StorageValue, }; use codec::Codec; +#[cfg(feature = "std")] +use hash_db::HashDB; use hash_db::Hasher; use sp_core::storage::{ChildInfo, StateVersion}; use sp_std::vec::Vec; +#[cfg(feature = "std")] +use sp_trie::{cache::LocalTrieCache, recorder::Recorder}; +#[cfg(feature = "std")] +use sp_trie::{MemoryDB, StorageProof}; -/// Patricia trie-based backend. Transaction type is an overlay of changes to commit. -pub struct TrieBackend, H: Hasher> { - pub(crate) essence: TrieBackendEssence, +/// Dummy type to be used in `no_std`. +/// +/// This is required to have the type available for [`TrieBackendBuilder`] and [`TrieBackend`]. +#[cfg(not(feature = "std"))] +pub struct LocalTrieCache(sp_std::marker::PhantomData); + +/// Special trait to support taking the [`LocalTrieCache`] by value or by reference. +/// +/// This trait is internal use only and to emphasize this, the trait is sealed. +pub trait AsLocalTrieCache: sealed::Sealed { + /// Returns `self` as [`LocalTrieCache`]. + #[cfg(feature = "std")] + fn as_local_trie_cache(&self) -> &LocalTrieCache; +} + +impl AsLocalTrieCache for LocalTrieCache { + #[cfg(feature = "std")] + fn as_local_trie_cache(&self) -> &LocalTrieCache { + self + } +} + +#[cfg(feature = "std")] +impl AsLocalTrieCache for &LocalTrieCache { + fn as_local_trie_cache(&self) -> &LocalTrieCache { + self + } +} + +/// Special module that contains the `Sealed` trait. +mod sealed { + use super::*; + + /// A special trait which prevents externals to implement the [`AsLocalTrieCache`] outside + /// of this crate. + pub trait Sealed {} + + impl Sealed for LocalTrieCache {} + impl Sealed for &LocalTrieCache {} +} + +/// Builder for creating a [`TrieBackend`]. +pub struct TrieBackendBuilder, H: Hasher, C = LocalTrieCache> { + storage: S, + root: H::Out, + #[cfg(feature = "std")] + recorder: Option>, + cache: Option, } -impl, H: Hasher> TrieBackend +impl TrieBackendBuilder> where - H::Out: Codec, + S: TrieBackendStorage, + H: Hasher, { - /// Create new trie-based backend. + /// Create a new builder instance. pub fn new(storage: S, root: H::Out) -> Self { - TrieBackend { essence: TrieBackendEssence::new(storage, root) } + Self { + storage, + root, + #[cfg(feature = "std")] + recorder: None, + cache: None, + } + } +} + +impl TrieBackendBuilder +where + S: TrieBackendStorage, + H: Hasher, +{ + /// Wrap the given [`TrieBackend`]. + /// + /// This can be used for example if all accesses to the trie should + /// be recorded while some other functionality still uses the non-recording + /// backend. + /// + /// The backend storage and the cache will be taken from `other`. + pub fn wrap(other: &TrieBackend) -> TrieBackendBuilder<&S, H, &C> { + TrieBackendBuilder { + storage: other.essence.backend_storage(), + root: *other.essence.root(), + #[cfg(feature = "std")] + recorder: None, + #[cfg(feature = "std")] + cache: other.essence.trie_node_cache.as_ref(), + #[cfg(not(feature = "std"))] + cache: None, + } + } + + /// Use the given optional `recorder` for the to be configured [`TrieBackend`]. + #[cfg(feature = "std")] + pub fn with_optional_recorder(self, recorder: Option>) -> Self { + Self { recorder, ..self } } + /// Use the given `recorder` for the to be configured [`TrieBackend`]. + #[cfg(feature = "std")] + pub fn with_recorder(self, recorder: Recorder) -> Self { + Self { recorder: Some(recorder), ..self } + } + + /// Use the given optional `cache` for the to be configured [`TrieBackend`]. + #[cfg(feature = "std")] + pub fn with_optional_cache(self, cache: Option) -> TrieBackendBuilder { + TrieBackendBuilder { + cache, + root: self.root, + storage: self.storage, + recorder: self.recorder, + } + } + + /// Use the given `cache` for the to be configured [`TrieBackend`]. + #[cfg(feature = "std")] + pub fn with_cache(self, cache: LC) -> TrieBackendBuilder { + TrieBackendBuilder { + cache: Some(cache), + root: self.root, + storage: self.storage, + recorder: self.recorder, + } + } + + /// Build the configured [`TrieBackend`]. + #[cfg(feature = "std")] + pub fn build(self) -> TrieBackend { + TrieBackend { + essence: TrieBackendEssence::new_with_cache_and_recorder( + self.storage, + self.root, + self.cache, + self.recorder, + ), + } + } + + /// Build the configured [`TrieBackend`]. + #[cfg(not(feature = "std"))] + pub fn build(self) -> TrieBackend { + let _ = self.cache; + + TrieBackend { essence: TrieBackendEssence::new(self.storage, self.root) } + } +} + +/// Patricia trie-based backend. Transaction type is an overlay of changes to commit. +pub struct TrieBackend, H: Hasher, C = LocalTrieCache> { + pub(crate) essence: TrieBackendEssence, +} + +impl, H: Hasher, C: AsLocalTrieCache + Send + Sync> TrieBackend +where + H::Out: Codec, +{ /// Get backend essence reference. - pub fn essence(&self) -> &TrieBackendEssence { + pub fn essence(&self) -> &TrieBackendEssence { &self.essence } @@ -59,15 +210,26 @@ where pub fn into_storage(self) -> S { self.essence.into_storage() } + + /// Extract the [`StorageProof`]. + /// + /// This only returns `Some` when there was a recorder set. + #[cfg(feature = "std")] + pub fn extract_proof(mut self) -> Option { + self.essence.recorder.take().map(|r| r.drain_storage_proof()) + } } -impl, H: Hasher> sp_std::fmt::Debug for TrieBackend { +impl, H: Hasher, C: AsLocalTrieCache> sp_std::fmt::Debug + for TrieBackend +{ fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { write!(f, "TrieBackend") } } -impl, H: Hasher> Backend for TrieBackend +impl, H: Hasher, C: AsLocalTrieCache + Send + Sync> Backend + for TrieBackend where H::Out: Ord + Codec, { @@ -75,10 +237,22 @@ where type Transaction = S::Overlay; type TrieBackendStorage = S; + fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { + self.essence.storage_hash(key) + } + fn storage(&self, key: &[u8]) -> Result, Self::Error> { self.essence.storage(key) } + fn child_storage_hash( + &self, + child_info: &ChildInfo, + key: &[u8], + ) -> Result, Self::Error> { + self.essence.child_storage_hash(child_info, key) + } + fn child_storage( &self, child_info: &ChildInfo, @@ -169,10 +343,6 @@ where self.essence.child_storage_root(child_info, delta, state_version) } - fn as_trie_backend(&self) -> Option<&TrieBackend> { - Some(self) - } - fn register_overlay_stats(&self, _stats: &crate::stats::StateMachineStats) {} fn usage_info(&self) -> crate::UsageInfo { @@ -184,20 +354,97 @@ where } } +#[cfg(feature = "std")] +impl, H: Hasher, C> AsTrieBackend for TrieBackend { + type TrieBackendStorage = S; + + fn as_trie_backend(&self) -> &TrieBackend { + self + } +} + +/// Create a backend used for checking the proof, using `H` as hasher. +/// +/// `proof` and `root` must match, i.e. `root` must be the correct root of `proof` nodes. +#[cfg(feature = "std")] +pub fn create_proof_check_backend( + root: H::Out, + proof: StorageProof, +) -> Result, H>, Box> +where + H: Hasher, + H::Out: Codec, +{ + let db = proof.into_memory_db(); + + if db.contains(&root, hash_db::EMPTY_PREFIX) { + Ok(TrieBackendBuilder::new(db, root).build()) + } else { + Err(Box::new(crate::ExecutionError::InvalidProof)) + } +} + #[cfg(test)] pub mod tests { + use crate::{new_in_mem, InMemoryBackend}; + use super::*; use codec::Encode; use sp_core::H256; use sp_runtime::traits::BlakeTwo256; use sp_trie::{ - trie_types::{TrieDB, TrieDBMutV0, TrieDBMutV1}, - KeySpacedDBMut, PrefixedMemoryDB, Trie, TrieMut, + cache::{CacheSize, SharedTrieCache}, + trie_types::{TrieDBBuilder, TrieDBMutBuilderV0, TrieDBMutBuilderV1}, + KeySpacedDBMut, PrefixedKey, PrefixedMemoryDB, Trie, TrieCache, TrieMut, }; use std::{collections::HashSet, iter}; + use trie_db::NodeCodec; const CHILD_KEY_1: &[u8] = b"sub1"; + type Recorder = sp_trie::recorder::Recorder; + type Cache = LocalTrieCache; + type SharedCache = SharedTrieCache; + + macro_rules! parameterized_test { + ($name:ident, $internal_name:ident) => { + #[test] + fn $name() { + let parameters = vec![ + (StateVersion::V0, None, None), + (StateVersion::V0, Some(SharedCache::new(CacheSize::Unlimited)), None), + (StateVersion::V0, None, Some(Recorder::default())), + ( + StateVersion::V0, + Some(SharedCache::new(CacheSize::Unlimited)), + Some(Recorder::default()), + ), + (StateVersion::V1, None, None), + (StateVersion::V1, Some(SharedCache::new(CacheSize::Unlimited)), None), + (StateVersion::V1, None, Some(Recorder::default())), + ( + StateVersion::V1, + Some(SharedCache::new(CacheSize::Unlimited)), + Some(Recorder::default()), + ), + ]; + + for (version, cache, recorder) in parameters { + eprintln!( + "Running with version {:?}, cache enabled {} and recorder enabled {}", + version, + cache.is_some(), + recorder.is_some() + ); + + let cache = cache.as_ref().map(|c| c.local_cache()); + + $internal_name(version, cache, recorder.clone()); + } + } + }; + } + pub(crate) fn test_db(state_version: StateVersion) -> (PrefixedMemoryDB, H256) { let child_info = ChildInfo::new_default(CHILD_KEY_1); let mut root = H256::default(); @@ -206,12 +453,12 @@ pub mod tests { let mut mdb = KeySpacedDBMut::new(&mut mdb, child_info.keyspace()); match state_version { StateVersion::V0 => { - let mut trie = TrieDBMutV0::new(&mut mdb, &mut root); + let mut trie = TrieDBMutBuilderV0::new(&mut mdb, &mut root).build(); trie.insert(b"value3", &[142; 33]).expect("insert failed"); trie.insert(b"value4", &[124; 33]).expect("insert failed"); }, StateVersion::V1 => { - let mut trie = TrieDBMutV1::new(&mut mdb, &mut root); + let mut trie = TrieDBMutBuilderV1::new(&mut mdb, &mut root).build(); trie.insert(b"value3", &[142; 33]).expect("insert failed"); trie.insert(b"value4", &[124; 33]).expect("insert failed"); }, @@ -240,11 +487,11 @@ pub mod tests { match state_version { StateVersion::V0 => { - let trie = TrieDBMutV0::new(&mut mdb, &mut root); + let trie = TrieDBMutBuilderV0::new(&mut mdb, &mut root).build(); build(trie, &child_info, &sub_root[..]) }, StateVersion::V1 => { - let trie = TrieDBMutV1::new(&mut mdb, &mut root); + let trie = TrieDBMutBuilderV1::new(&mut mdb, &mut root).build(); build(trie, &child_info, &sub_root[..]) }, }; @@ -254,27 +501,39 @@ pub mod tests { pub(crate) fn test_trie( hashed_value: StateVersion, + cache: Option, + recorder: Option, ) -> TrieBackend, BlakeTwo256> { let (mdb, root) = test_db(hashed_value); - TrieBackend::new(mdb, root) - } - #[test] - fn read_from_storage_returns_some() { - read_from_storage_returns_some_inner(StateVersion::V0); - read_from_storage_returns_some_inner(StateVersion::V1); - } - fn read_from_storage_returns_some_inner(state_version: StateVersion) { - assert_eq!(test_trie(state_version).storage(b"key").unwrap(), Some(b"value".to_vec())); + TrieBackendBuilder::new(mdb, root) + .with_optional_cache(cache) + .with_optional_recorder(recorder) + .build() } - #[test] - fn read_from_child_storage_returns_some() { - read_from_child_storage_returns_some_inner(StateVersion::V0); - read_from_child_storage_returns_some_inner(StateVersion::V1); + parameterized_test!(read_from_storage_returns_some, read_from_storage_returns_some_inner); + fn read_from_storage_returns_some_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + assert_eq!( + test_trie(state_version, cache, recorder).storage(b"key").unwrap(), + Some(b"value".to_vec()) + ); } - fn read_from_child_storage_returns_some_inner(state_version: StateVersion) { - let test_trie = test_trie(state_version); + + parameterized_test!( + read_from_child_storage_returns_some, + read_from_child_storage_returns_some_inner + ); + fn read_from_child_storage_returns_some_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + let test_trie = test_trie(state_version, cache, recorder); assert_eq!( test_trie .child_storage(&ChildInfo::new_default(CHILD_KEY_1), b"value3") @@ -299,65 +558,81 @@ pub mod tests { ); } - #[test] - fn read_from_storage_returns_none() { - read_from_storage_returns_none_inner(StateVersion::V0); - read_from_storage_returns_none_inner(StateVersion::V1); - } - fn read_from_storage_returns_none_inner(state_version: StateVersion) { - assert_eq!(test_trie(state_version).storage(b"non-existing-key").unwrap(), None); + parameterized_test!(read_from_storage_returns_none, read_from_storage_returns_none_inner); + fn read_from_storage_returns_none_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + assert_eq!( + test_trie(state_version, cache, recorder).storage(b"non-existing-key").unwrap(), + None + ); } - #[test] - fn pairs_are_not_empty_on_non_empty_storage() { - pairs_are_not_empty_on_non_empty_storage_inner(StateVersion::V0); - pairs_are_not_empty_on_non_empty_storage_inner(StateVersion::V1); - } - fn pairs_are_not_empty_on_non_empty_storage_inner(state_version: StateVersion) { - assert!(!test_trie(state_version).pairs().is_empty()); + parameterized_test!( + pairs_are_not_empty_on_non_empty_storage, + pairs_are_not_empty_on_non_empty_storage_inner + ); + fn pairs_are_not_empty_on_non_empty_storage_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + assert!(!test_trie(state_version, cache, recorder).pairs().is_empty()); } #[test] fn pairs_are_empty_on_empty_storage() { - assert!(TrieBackend::, BlakeTwo256>::new( + assert!(TrieBackendBuilder::, BlakeTwo256>::new( PrefixedMemoryDB::default(), Default::default(), ) + .build() .pairs() .is_empty()); } - #[test] - fn storage_root_is_non_default() { - storage_root_is_non_default_inner(StateVersion::V0); - storage_root_is_non_default_inner(StateVersion::V1); - } - fn storage_root_is_non_default_inner(state_version: StateVersion) { + parameterized_test!(storage_root_is_non_default, storage_root_is_non_default_inner); + fn storage_root_is_non_default_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { assert!( - test_trie(state_version).storage_root(iter::empty(), state_version).0 != - H256::repeat_byte(0) + test_trie(state_version, cache, recorder) + .storage_root(iter::empty(), state_version) + .0 != H256::repeat_byte(0) ); } - #[test] - fn storage_root_transaction_is_non_empty() { - storage_root_transaction_is_non_empty_inner(StateVersion::V0); - storage_root_transaction_is_non_empty_inner(StateVersion::V1); - } - fn storage_root_transaction_is_non_empty_inner(state_version: StateVersion) { - let (new_root, mut tx) = test_trie(state_version) + parameterized_test!( + storage_root_transaction_is_non_empty, + storage_root_transaction_is_non_empty_inner + ); + fn storage_root_transaction_is_non_empty_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + let (new_root, mut tx) = test_trie(state_version, cache, recorder) .storage_root(iter::once((&b"new-key"[..], Some(&b"new-value"[..]))), state_version); assert!(!tx.drain().is_empty()); - assert!(new_root != test_trie(state_version).storage_root(iter::empty(), state_version).0); + assert!( + new_root != + test_trie(state_version, None, None) + .storage_root(iter::empty(), state_version) + .0 + ); } - #[test] - fn prefix_walking_works() { - prefix_walking_works_inner(StateVersion::V0); - prefix_walking_works_inner(StateVersion::V1); - } - fn prefix_walking_works_inner(state_version: StateVersion) { - let trie = test_trie(state_version); + parameterized_test!(prefix_walking_works, prefix_walking_works_inner); + fn prefix_walking_works_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + let trie = test_trie(state_version, cache, recorder); let mut seen = HashSet::new(); trie.for_keys_with_prefix(b"value", |key| { @@ -371,23 +646,475 @@ pub mod tests { assert_eq!(seen, expected); } - #[test] - fn keys_with_empty_prefix_returns_all_keys() { - keys_with_empty_prefix_returns_all_keys_inner(StateVersion::V0); - keys_with_empty_prefix_returns_all_keys_inner(StateVersion::V1); - } - fn keys_with_empty_prefix_returns_all_keys_inner(state_version: StateVersion) { + parameterized_test!( + keys_with_empty_prefix_returns_all_keys, + keys_with_empty_prefix_returns_all_keys_inner + ); + fn keys_with_empty_prefix_returns_all_keys_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { let (test_db, test_root) = test_db(state_version); - let expected = TrieDB::new(&test_db, &test_root) - .unwrap() + let expected = TrieDBBuilder::new(&test_db, &test_root) + .build() .iter() .unwrap() .map(|d| d.unwrap().0.to_vec()) .collect::>(); - let trie = test_trie(state_version); + let trie = test_trie(state_version, cache, recorder); let keys = trie.keys(&[]); assert_eq!(expected, keys); } + + parameterized_test!( + proof_is_empty_until_value_is_read, + proof_is_empty_until_value_is_read_inner + ); + fn proof_is_empty_until_value_is_read_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + let trie_backend = test_trie(state_version, cache, recorder); + assert!(TrieBackendBuilder::wrap(&trie_backend) + .with_recorder(Recorder::default()) + .build() + .extract_proof() + .unwrap() + .is_empty()); + } + + parameterized_test!( + proof_is_non_empty_after_value_is_read, + proof_is_non_empty_after_value_is_read_inner + ); + fn proof_is_non_empty_after_value_is_read_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + let trie_backend = test_trie(state_version, cache, recorder); + let backend = TrieBackendBuilder::wrap(&trie_backend) + .with_recorder(Recorder::default()) + .build(); + assert_eq!(backend.storage(b"key").unwrap(), Some(b"value".to_vec())); + assert!(!backend.extract_proof().unwrap().is_empty()); + } + + #[test] + fn proof_is_invalid_when_does_not_contains_root() { + let result = create_proof_check_backend::( + H256::from_low_u64_be(1), + StorageProof::empty(), + ); + assert!(result.is_err()); + } + + parameterized_test!(passes_through_backend_calls, passes_through_backend_calls_inner); + fn passes_through_backend_calls_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + let trie_backend = test_trie(state_version, cache, recorder); + let proving_backend = TrieBackendBuilder::wrap(&trie_backend) + .with_recorder(Recorder::default()) + .build(); + assert_eq!(trie_backend.storage(b"key").unwrap(), proving_backend.storage(b"key").unwrap()); + assert_eq!(trie_backend.pairs(), proving_backend.pairs()); + + let (trie_root, mut trie_mdb) = + trie_backend.storage_root(std::iter::empty(), state_version); + let (proving_root, mut proving_mdb) = + proving_backend.storage_root(std::iter::empty(), state_version); + assert_eq!(trie_root, proving_root); + assert_eq!(trie_mdb.drain(), proving_mdb.drain()); + } + + #[test] + fn proof_recorded_and_checked_top() { + proof_recorded_and_checked_inner(StateVersion::V0); + proof_recorded_and_checked_inner(StateVersion::V1); + } + fn proof_recorded_and_checked_inner(state_version: StateVersion) { + let size_content = 34; // above hashable value threshold. + let value_range = 0..64; + let contents = value_range + .clone() + .map(|i| (vec![i], Some(vec![i; size_content]))) + .collect::>(); + let in_memory = InMemoryBackend::::default(); + let in_memory = in_memory.update(vec![(None, contents)], state_version); + let in_memory_root = in_memory.storage_root(std::iter::empty(), state_version).0; + value_range.clone().for_each(|i| { + assert_eq!(in_memory.storage(&[i]).unwrap().unwrap(), vec![i; size_content]) + }); + + let trie = in_memory.as_trie_backend(); + let trie_root = trie.storage_root(std::iter::empty(), state_version).0; + assert_eq!(in_memory_root, trie_root); + value_range + .clone() + .for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i; size_content])); + + for cache in [Some(SharedTrieCache::new(CacheSize::Unlimited)), None] { + // Run multiple times to have a different cache conditions. + for i in 0..5 { + if let Some(cache) = &cache { + if i == 2 { + cache.reset_node_cache(); + } else if i == 3 { + cache.reset_value_cache(); + } + } + + let proving = TrieBackendBuilder::wrap(&trie) + .with_recorder(Recorder::default()) + .with_optional_cache(cache.as_ref().map(|c| c.local_cache())) + .build(); + assert_eq!(proving.storage(&[42]).unwrap().unwrap(), vec![42; size_content]); + + let proof = proving.extract_proof().unwrap(); + + let proof_check = + create_proof_check_backend::(in_memory_root.into(), proof) + .unwrap(); + assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42; size_content]); + } + } + } + + #[test] + fn proof_record_works_with_iter() { + proof_record_works_with_iter_inner(StateVersion::V0); + proof_record_works_with_iter_inner(StateVersion::V1); + } + fn proof_record_works_with_iter_inner(state_version: StateVersion) { + for cache in [Some(SharedTrieCache::new(CacheSize::Unlimited)), None] { + // Run multiple times to have a different cache conditions. + for i in 0..5 { + if let Some(cache) = &cache { + if i == 2 { + cache.reset_node_cache(); + } else if i == 3 { + cache.reset_value_cache(); + } + } + + let contents = (0..64).map(|i| (vec![i], Some(vec![i]))).collect::>(); + let in_memory = InMemoryBackend::::default(); + let in_memory = in_memory.update(vec![(None, contents)], state_version); + let in_memory_root = in_memory.storage_root(std::iter::empty(), state_version).0; + (0..64) + .for_each(|i| assert_eq!(in_memory.storage(&[i]).unwrap().unwrap(), vec![i])); + + let trie = in_memory.as_trie_backend(); + let trie_root = trie.storage_root(std::iter::empty(), state_version).0; + assert_eq!(in_memory_root, trie_root); + (0..64).for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i])); + + let proving = TrieBackendBuilder::wrap(&trie) + .with_recorder(Recorder::default()) + .with_optional_cache(cache.as_ref().map(|c| c.local_cache())) + .build(); + + (0..63).for_each(|i| { + assert_eq!(proving.next_storage_key(&[i]).unwrap(), Some(vec![i + 1])) + }); + + let proof = proving.extract_proof().unwrap(); + + let proof_check = + create_proof_check_backend::(in_memory_root.into(), proof) + .unwrap(); + (0..63).for_each(|i| { + assert_eq!(proof_check.next_storage_key(&[i]).unwrap(), Some(vec![i + 1])) + }); + } + } + } + + #[test] + fn proof_recorded_and_checked_with_child() { + proof_recorded_and_checked_with_child_inner(StateVersion::V0); + proof_recorded_and_checked_with_child_inner(StateVersion::V1); + } + fn proof_recorded_and_checked_with_child_inner(state_version: StateVersion) { + let child_info_1 = ChildInfo::new_default(b"sub1"); + let child_info_2 = ChildInfo::new_default(b"sub2"); + let child_info_1 = &child_info_1; + let child_info_2 = &child_info_2; + let contents = vec![ + (None, (0..64).map(|i| (vec![i], Some(vec![i]))).collect::>()), + (Some(child_info_1.clone()), (28..65).map(|i| (vec![i], Some(vec![i]))).collect()), + (Some(child_info_2.clone()), (10..15).map(|i| (vec![i], Some(vec![i]))).collect()), + ]; + let in_memory = new_in_mem::>(); + let in_memory = in_memory.update(contents, state_version); + let child_storage_keys = vec![child_info_1.to_owned(), child_info_2.to_owned()]; + let in_memory_root = in_memory + .full_storage_root( + std::iter::empty(), + child_storage_keys.iter().map(|k| (k, std::iter::empty())), + state_version, + ) + .0; + (0..64).for_each(|i| assert_eq!(in_memory.storage(&[i]).unwrap().unwrap(), vec![i])); + (28..65).for_each(|i| { + assert_eq!(in_memory.child_storage(child_info_1, &[i]).unwrap().unwrap(), vec![i]) + }); + (10..15).for_each(|i| { + assert_eq!(in_memory.child_storage(child_info_2, &[i]).unwrap().unwrap(), vec![i]) + }); + + for cache in [Some(SharedTrieCache::new(CacheSize::Unlimited)), None] { + // Run multiple times to have a different cache conditions. + for i in 0..5 { + eprintln!("Running with cache {}, iteration {}", cache.is_some(), i); + + if let Some(cache) = &cache { + if i == 2 { + cache.reset_node_cache(); + } else if i == 3 { + cache.reset_value_cache(); + } + } + + let trie = in_memory.as_trie_backend(); + let trie_root = trie.storage_root(std::iter::empty(), state_version).0; + assert_eq!(in_memory_root, trie_root); + (0..64).for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i])); + + let proving = TrieBackendBuilder::wrap(&trie) + .with_recorder(Recorder::default()) + .with_optional_cache(cache.as_ref().map(|c| c.local_cache())) + .build(); + assert_eq!(proving.storage(&[42]).unwrap().unwrap(), vec![42]); + + let proof = proving.extract_proof().unwrap(); + + let proof_check = + create_proof_check_backend::(in_memory_root.into(), proof) + .unwrap(); + assert!(proof_check.storage(&[0]).is_err()); + assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42]); + // note that it is include in root because proof close + assert_eq!(proof_check.storage(&[41]).unwrap().unwrap(), vec![41]); + assert_eq!(proof_check.storage(&[64]).unwrap(), None); + + let proving = TrieBackendBuilder::wrap(&trie) + .with_recorder(Recorder::default()) + .with_optional_cache(cache.as_ref().map(|c| c.local_cache())) + .build(); + assert_eq!(proving.child_storage(child_info_1, &[64]), Ok(Some(vec![64]))); + assert_eq!(proving.child_storage(child_info_1, &[25]), Ok(None)); + assert_eq!(proving.child_storage(child_info_2, &[14]), Ok(Some(vec![14]))); + assert_eq!(proving.child_storage(child_info_2, &[25]), Ok(None)); + + let proof = proving.extract_proof().unwrap(); + let proof_check = + create_proof_check_backend::(in_memory_root.into(), proof) + .unwrap(); + assert_eq!( + proof_check.child_storage(child_info_1, &[64]).unwrap().unwrap(), + vec![64] + ); + assert_eq!(proof_check.child_storage(child_info_1, &[25]).unwrap(), None); + + assert_eq!( + proof_check.child_storage(child_info_2, &[14]).unwrap().unwrap(), + vec![14] + ); + assert_eq!(proof_check.child_storage(child_info_2, &[25]).unwrap(), None); + } + } + } + + /// This tests an edge case when recording a child trie access with a cache. + /// + /// The accessed value/node is in the cache, but not the nodes to get to this value. So, + /// the recorder will need to traverse the trie to access these nodes from the backend when the + /// storage proof is generated. + #[test] + fn child_proof_recording_with_edge_cases_works() { + child_proof_recording_with_edge_cases_works_inner(StateVersion::V0); + child_proof_recording_with_edge_cases_works_inner(StateVersion::V1); + } + fn child_proof_recording_with_edge_cases_works_inner(state_version: StateVersion) { + let child_info_1 = ChildInfo::new_default(b"sub1"); + let child_info_1 = &child_info_1; + let contents = vec![ + (None, (0..64).map(|i| (vec![i], Some(vec![i]))).collect::>()), + ( + Some(child_info_1.clone()), + (28..65) + .map(|i| (vec![i], Some(vec![i]))) + // Some big value to ensure we get a new node + .chain(std::iter::once((vec![65], Some(vec![65; 128])))) + .collect(), + ), + ]; + let in_memory = new_in_mem::>(); + let in_memory = in_memory.update(contents, state_version); + let child_storage_keys = vec![child_info_1.to_owned()]; + let in_memory_root = in_memory + .full_storage_root( + std::iter::empty(), + child_storage_keys.iter().map(|k| (k, std::iter::empty())), + state_version, + ) + .0; + + let child_1_root = + in_memory.child_storage_root(child_info_1, std::iter::empty(), state_version).0; + let trie = in_memory.as_trie_backend(); + let nodes = { + let backend = TrieBackendBuilder::wrap(trie).with_recorder(Default::default()).build(); + let value = backend.child_storage(child_info_1, &[65]).unwrap().unwrap(); + let value_hash = BlakeTwo256::hash(&value); + assert_eq!(value, vec![65; 128]); + + let proof = backend.extract_proof().unwrap(); + + let mut nodes = Vec::new(); + for node in proof.iter_nodes() { + let hash = BlakeTwo256::hash(&node); + // Only insert the node/value that contains the important data. + if hash != value_hash { + let node = sp_trie::NodeCodec::::decode(&node) + .unwrap() + .to_owned_node::>() + .unwrap(); + + if let Some(data) = node.data() { + if data == &vec![65; 128] { + nodes.push((hash, node)); + } + } + } else if hash == value_hash { + nodes.push((hash, trie_db::node::NodeOwned::Value(node.into(), hash))); + } + } + + nodes + }; + + let cache = SharedTrieCache::::new(CacheSize::Unlimited); + { + let local_cache = cache.local_cache(); + let mut trie_cache = local_cache.as_trie_db_cache(child_1_root); + + // Put the value/node into the cache. + for (hash, node) in nodes { + trie_cache.get_or_insert_node(hash, &mut || Ok(node.clone())).unwrap(); + + if let Some(data) = node.data() { + trie_cache.cache_value_for_key(&[65], (data.clone(), hash).into()); + } + } + } + + { + // Record the access + let proving = TrieBackendBuilder::wrap(&trie) + .with_recorder(Recorder::default()) + .with_cache(cache.local_cache()) + .build(); + assert_eq!(proving.child_storage(child_info_1, &[65]), Ok(Some(vec![65; 128]))); + + let proof = proving.extract_proof().unwrap(); + // And check that we have a correct proof. + let proof_check = + create_proof_check_backend::(in_memory_root.into(), proof).unwrap(); + assert_eq!( + proof_check.child_storage(child_info_1, &[65]).unwrap().unwrap(), + vec![65; 128] + ); + } + } + + parameterized_test!( + storage_proof_encoded_size_estimation_works, + storage_proof_encoded_size_estimation_works_inner + ); + fn storage_proof_encoded_size_estimation_works_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + let has_cache = cache.is_some(); + let trie_backend = test_trie(state_version, cache, recorder); + let keys = &[ + &b"key"[..], + &b"value1"[..], + &b"value2"[..], + &b"doesnotexist"[..], + &b"doesnotexist2"[..], + ]; + + fn check_estimation( + backend: TrieBackend< + impl TrieBackendStorage, + BlakeTwo256, + &'_ LocalTrieCache, + >, + has_cache: bool, + ) { + let estimation = backend.essence.recorder.as_ref().unwrap().estimate_encoded_size(); + let storage_proof = backend.extract_proof().unwrap(); + let storage_proof_size = + storage_proof.into_nodes().into_iter().map(|n| n.encoded_size()).sum::(); + + if has_cache { + // Estimation is not entirely correct when we have values already cached. + assert!(estimation >= storage_proof_size) + } else { + assert_eq!(storage_proof_size, estimation); + } + } + + for n in 0..keys.len() { + let backend = TrieBackendBuilder::wrap(&trie_backend) + .with_recorder(Recorder::default()) + .build(); + + // Read n keys + (0..n).for_each(|i| { + backend.storage(keys[i]).unwrap(); + }); + + // Check the estimation + check_estimation(backend, has_cache); + } + } + + #[test] + fn new_data_is_added_to_the_cache() { + let shared_cache = SharedTrieCache::new(CacheSize::Unlimited); + let new_data = vec![ + (&b"new_data0"[..], Some(&b"0"[..])), + (&b"new_data1"[..], Some(&b"1"[..])), + (&b"new_data2"[..], Some(&b"2"[..])), + (&b"new_data3"[..], Some(&b"3"[..])), + (&b"new_data4"[..], Some(&b"4"[..])), + ]; + + let new_root = { + let trie = test_trie(StateVersion::V1, Some(shared_cache.local_cache()), None); + trie.storage_root(new_data.clone().into_iter(), StateVersion::V1).0 + }; + + let local_cache = shared_cache.local_cache(); + let mut cache = local_cache.as_trie_db_cache(new_root); + // All the data should be cached now + for (key, value) in new_data { + assert_eq!( + value.unwrap(), + cache.lookup_value_for_key(key).unwrap().data().flatten().unwrap().as_ref() + ); + } + } } diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 7d910cc9602cc..dda7b51ab08c6 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -18,23 +18,32 @@ //! Trie-based state machine backend essence used to read values //! from storage. -use crate::{backend::Consolidate, debug, warn, StorageKey, StorageValue}; -use codec::Encode; +use crate::{ + backend::Consolidate, debug, trie_backend::AsLocalTrieCache, warn, StorageKey, StorageValue, +}; +use codec::Codec; use hash_db::{self, AsHashDB, HashDB, HashDBRef, Hasher, Prefix}; #[cfg(feature = "std")] use parking_lot::RwLock; use sp_core::storage::{ChildInfo, ChildType, StateVersion}; +#[cfg(not(feature = "std"))] +use sp_std::marker::PhantomData; use sp_std::{boxed::Box, vec::Vec}; +#[cfg(feature = "std")] +use sp_trie::recorder::Recorder; use sp_trie::{ - child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_value, - read_trie_value, - trie_types::{TrieDB, TrieError}, - DBValue, KeySpacedDB, LayoutV1 as Layout, Trie, TrieDBIterator, TrieDBKeyIterator, + child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_hash, + read_child_trie_value, read_trie_value, + trie_types::{TrieDBBuilder, TrieError}, + DBValue, KeySpacedDB, NodeCodec, Trie, TrieCache, TrieDBIterator, TrieDBKeyIterator, + TrieRecorder, }; #[cfg(feature = "std")] -use std::collections::HashMap; -#[cfg(feature = "std")] -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; + +// In this module, we only use layout for read operation and empty root, +// where V1 and V0 are equivalent. +use sp_trie::LayoutV1 as Layout; #[cfg(not(feature = "std"))] macro_rules! format { @@ -68,18 +77,21 @@ impl Cache { } /// Patricia trie-based pairs storage essence. -pub struct TrieBackendEssence, H: Hasher> { +pub struct TrieBackendEssence, H: Hasher, C> { storage: S, root: H::Out, empty: H::Out, #[cfg(feature = "std")] pub(crate) cache: Arc>>, + #[cfg(feature = "std")] + pub(crate) trie_node_cache: Option, + #[cfg(feature = "std")] + pub(crate) recorder: Option>, + #[cfg(not(feature = "std"))] + _phantom: PhantomData, } -impl, H: Hasher> TrieBackendEssence -where - H::Out: Encode, -{ +impl, H: Hasher, C> TrieBackendEssence { /// Create new trie-based backend. pub fn new(storage: S, root: H::Out) -> Self { TrieBackendEssence { @@ -88,6 +100,30 @@ where empty: H::hash(&[0u8]), #[cfg(feature = "std")] cache: Arc::new(RwLock::new(Cache::new())), + #[cfg(feature = "std")] + trie_node_cache: None, + #[cfg(feature = "std")] + recorder: None, + #[cfg(not(feature = "std"))] + _phantom: PhantomData, + } + } + + /// Create new trie-based backend. + #[cfg(feature = "std")] + pub fn new_with_cache_and_recorder( + storage: S, + root: H::Out, + cache: Option, + recorder: Option>, + ) -> Self { + TrieBackendEssence { + storage, + root, + empty: H::hash(&[0u8]), + cache: Arc::new(RwLock::new(Cache::new())), + trie_node_cache: cache, + recorder, } } @@ -96,6 +132,11 @@ where &self.storage } + /// Get backend storage mutable reference. + pub fn backend_storage_mut(&mut self) -> &mut S { + &mut self.storage + } + /// Get trie root. pub fn root(&self) -> &H::Out { &self.root @@ -120,7 +161,97 @@ where pub fn into_storage(self) -> S { self.storage } +} + +impl, H: Hasher, C: AsLocalTrieCache> TrieBackendEssence { + /// Call the given closure passing it the recorder and the cache. + /// + /// If the given `storage_root` is `None`, `self.root` will be used. + #[cfg(feature = "std")] + fn with_recorder_and_cache( + &self, + storage_root: Option, + callback: impl FnOnce( + Option<&mut dyn TrieRecorder>, + Option<&mut dyn TrieCache>>, + ) -> R, + ) -> R { + let storage_root = storage_root.unwrap_or_else(|| self.root); + let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder()); + let recorder = recorder.as_mut().map(|r| r as _); + let mut cache = self + .trie_node_cache + .as_ref() + .map(|c| c.as_local_trie_cache().as_trie_db_cache(storage_root)); + let cache = cache.as_mut().map(|c| c as _); + + callback(recorder, cache) + } + + #[cfg(not(feature = "std"))] + fn with_recorder_and_cache( + &self, + _: Option, + callback: impl FnOnce( + Option<&mut dyn TrieRecorder>, + Option<&mut dyn TrieCache>>, + ) -> R, + ) -> R { + callback(None, None) + } + + /// Call the given closure passing it the recorder and the cache. + /// + /// This function must only be used when the operation in `callback` is + /// calculating a `storage_root`. It is expected that `callback` returns + /// the new storage root. This is required to register the changes in the cache + /// for the correct storage root. + #[cfg(feature = "std")] + fn with_recorder_and_cache_for_storage_root( + &self, + callback: impl FnOnce( + Option<&mut dyn TrieRecorder>, + Option<&mut dyn TrieCache>>, + ) -> (Option, R), + ) -> R { + let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder()); + let recorder = recorder.as_mut().map(|r| r as _); + + let result = if let Some(local_cache) = self.trie_node_cache.as_ref() { + let mut cache = local_cache.as_local_trie_cache().as_trie_db_mut_cache(); + + let (new_root, r) = callback(recorder, Some(&mut cache)); + + if let Some(new_root) = new_root { + cache.merge_into(local_cache.as_local_trie_cache(), new_root); + } + + r + } else { + callback(recorder, None).1 + }; + + result + } + + #[cfg(not(feature = "std"))] + fn with_recorder_and_cache_for_storage_root( + &self, + callback: impl FnOnce( + Option<&mut dyn TrieRecorder>, + Option<&mut dyn TrieCache>>, + ) -> (Option, R), + ) -> R { + callback(None, None).1 + } +} + +impl, H: Hasher, C: AsLocalTrieCache + Send + Sync> + TrieBackendEssence +where + H::Out: Codec + Ord, +{ /// Return the next key in the trie i.e. the minimum key that is strictly superior to `key` in /// lexicographic order. pub fn next_storage_key(&self, key: &[u8]) -> Result> { @@ -184,39 +315,82 @@ where dyn_eph = self; } - let trie = - TrieDB::::new(dyn_eph, root).map_err(|e| format!("TrieDB creation error: {}", e))?; - let mut iter = trie.key_iter().map_err(|e| format!("TrieDB iteration error: {}", e))?; + self.with_recorder_and_cache(Some(*root), |recorder, cache| { + let trie = TrieDBBuilder::::new(dyn_eph, root) + .with_optional_recorder(recorder) + .with_optional_cache(cache) + .build(); - // The key just after the one given in input, basically `key++0`. - // Note: We are sure this is the next key if: - // * size of key has no limit (i.e. we can always add 0 to the path), - // * and no keys can be inserted between `key` and `key++0` (this is ensured by sp-io). - let mut potential_next_key = Vec::with_capacity(key.len() + 1); - potential_next_key.extend_from_slice(key); - potential_next_key.push(0); + let mut iter = trie.key_iter().map_err(|e| format!("TrieDB iteration error: {}", e))?; - iter.seek(&potential_next_key) - .map_err(|e| format!("TrieDB iterator seek error: {}", e))?; + // The key just after the one given in input, basically `key++0`. + // Note: We are sure this is the next key if: + // * size of key has no limit (i.e. we can always add 0 to the path), + // * and no keys can be inserted between `key` and `key++0` (this is ensured by sp-io). + let mut potential_next_key = Vec::with_capacity(key.len() + 1); + potential_next_key.extend_from_slice(key); + potential_next_key.push(0); - let next_element = iter.next(); + iter.seek(&potential_next_key) + .map_err(|e| format!("TrieDB iterator seek error: {}", e))?; - let next_key = if let Some(next_element) = next_element { - let next_key = - next_element.map_err(|e| format!("TrieDB iterator next error: {}", e))?; - Some(next_key) - } else { - None - }; + let next_element = iter.next(); + + let next_key = if let Some(next_element) = next_element { + let next_key = + next_element.map_err(|e| format!("TrieDB iterator next error: {}", e))?; + Some(next_key) + } else { + None + }; - Ok(next_key) + Ok(next_key) + }) + } + + /// Returns the hash value + pub fn storage_hash(&self, key: &[u8]) -> Result> { + let map_e = |e| format!("Trie lookup error: {}", e); + + self.with_recorder_and_cache(None, |recorder, cache| { + TrieDBBuilder::new(self, &self.root) + .with_optional_cache(cache) + .with_optional_recorder(recorder) + .build() + .get_hash(key) + .map_err(map_e) + }) } /// Get the value of storage at given key. pub fn storage(&self, key: &[u8]) -> Result> { let map_e = |e| format!("Trie lookup error: {}", e); - read_trie_value::, _>(self, &self.root, key).map_err(map_e) + self.with_recorder_and_cache(None, |recorder, cache| { + read_trie_value::, _>(self, &self.root, key, recorder, cache).map_err(map_e) + }) + } + + /// Returns the hash value + pub fn child_storage_hash(&self, child_info: &ChildInfo, key: &[u8]) -> Result> { + let child_root = match self.child_root(child_info)? { + Some(root) => root, + None => return Ok(None), + }; + + let map_e = |e| format!("Trie lookup error: {}", e); + + self.with_recorder_and_cache(Some(child_root), |recorder, cache| { + read_child_trie_hash::, _>( + child_info.keyspace(), + self, + &child_root, + key, + recorder, + cache, + ) + .map_err(map_e) + }) } /// Get the value of child storage at given key. @@ -225,15 +399,24 @@ where child_info: &ChildInfo, key: &[u8], ) -> Result> { - let root = match self.child_root(child_info)? { + let child_root = match self.child_root(child_info)? { Some(root) => root, None => return Ok(None), }; let map_e = |e| format!("Trie lookup error: {}", e); - read_child_trie_value::, _>(child_info.keyspace(), self, &root, key) + self.with_recorder_and_cache(Some(child_root), |recorder, cache| { + read_child_trie_value::, _>( + child_info.keyspace(), + self, + &child_root, + key, + recorder, + cache, + ) .map_err(map_e) + }) } /// Retrieve all entries keys of storage and call `f` for each of those keys. @@ -338,28 +521,33 @@ where maybe_start_at: Option<&[u8]>, ) { let mut iter = move |db| -> sp_std::result::Result<(), Box>> { - let trie = TrieDB::::new(db, root)?; - let prefix = maybe_prefix.unwrap_or(&[]); - let iter = match maybe_start_at { - Some(start_at) => - TrieDBKeyIterator::new_prefixed_then_seek(&trie, prefix, start_at), - None => TrieDBKeyIterator::new_prefixed(&trie, prefix), - }?; - - for x in iter { - let key = x?; - - debug_assert!(maybe_prefix - .as_ref() - .map(|prefix| key.starts_with(prefix)) - .unwrap_or(true)); - - if !f(&key) { - break + self.with_recorder_and_cache(Some(*root), |recorder, cache| { + let trie = TrieDBBuilder::::new(db, root) + .with_optional_recorder(recorder) + .with_optional_cache(cache) + .build(); + let prefix = maybe_prefix.unwrap_or(&[]); + let iter = match maybe_start_at { + Some(start_at) => + TrieDBKeyIterator::new_prefixed_then_seek(&trie, prefix, start_at), + None => TrieDBKeyIterator::new_prefixed(&trie, prefix), + }?; + + for x in iter { + let key = x?; + + debug_assert!(maybe_prefix + .as_ref() + .map(|prefix| key.starts_with(prefix)) + .unwrap_or(true)); + + if !f(&key) { + break + } } - } - Ok(()) + Ok(()) + }) }; let result = if let Some(child_info) = child_info { @@ -383,25 +571,30 @@ where allow_missing_nodes: bool, ) -> Result { let mut iter = move |db| -> sp_std::result::Result>> { - let trie = TrieDB::::new(db, root)?; - - let prefix = prefix.unwrap_or(&[]); - let iterator = if let Some(start_at) = start_at { - TrieDBIterator::new_prefixed_then_seek(&trie, prefix, start_at)? - } else { - TrieDBIterator::new_prefixed(&trie, prefix)? - }; - for x in iterator { - let (key, value) = x?; - - debug_assert!(key.starts_with(prefix)); - - if !f(key, value) { - return Ok(false) + self.with_recorder_and_cache(Some(*root), |recorder, cache| { + let trie = TrieDBBuilder::::new(db, root) + .with_optional_recorder(recorder) + .with_optional_cache(cache) + .build(); + + let prefix = prefix.unwrap_or(&[]); + let iterator = if let Some(start_at) = start_at { + TrieDBIterator::new_prefixed_then_seek(&trie, prefix, start_at)? + } else { + TrieDBIterator::new_prefixed(&trie, prefix)? + }; + for x in iterator { + let (key, value) = x?; + + debug_assert!(key.starts_with(prefix)); + + if !f(key, value) { + return Ok(false) + } } - } - Ok(true) + Ok(true) + }) }; let result = if let Some(child_info) = child_info { @@ -436,14 +629,20 @@ where /// Returns all `(key, value)` pairs in the trie. pub fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { let collect_all = || -> sp_std::result::Result<_, Box>> { - let trie = TrieDB::::new(self, &self.root)?; - let mut v = Vec::new(); - for x in trie.iter()? { - let (key, value) = x?; - v.push((key.to_vec(), value.to_vec())); - } + self.with_recorder_and_cache(None, |recorder, cache| { + let trie = TrieDBBuilder::::new(self, self.root()) + .with_optional_cache(cache) + .with_optional_recorder(recorder) + .build(); + + let mut v = Vec::new(); + for x in trie.iter()? { + let (key, value) = x?; + v.push((key.to_vec(), value.to_vec())); + } - Ok(v) + Ok(v) + }) }; match collect_all() { @@ -467,27 +666,28 @@ where &self, delta: impl Iterator)>, state_version: StateVersion, - ) -> (H::Out, S::Overlay) - where - H::Out: Ord, - { + ) -> (H::Out, S::Overlay) { let mut write_overlay = S::Overlay::default(); - let mut root = self.root; - { + let root = self.with_recorder_and_cache_for_storage_root(|recorder, cache| { let mut eph = Ephemeral::new(self.backend_storage(), &mut write_overlay); let res = match state_version { - StateVersion::V0 => - delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), - StateVersion::V1 => - delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), + StateVersion::V0 => delta_trie_root::, _, _, _, _, _>( + &mut eph, self.root, delta, recorder, cache, + ), + StateVersion::V1 => delta_trie_root::, _, _, _, _, _>( + &mut eph, self.root, delta, recorder, cache, + ), }; match res { - Ok(ret) => root = ret, - Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), + Ok(ret) => (Some(ret), ret), + Err(e) => { + warn!(target: "trie", "Failed to write to trie: {}", e); + (None, self.root) + }, } - } + }); (root, write_overlay) } @@ -499,15 +699,12 @@ where child_info: &ChildInfo, delta: impl Iterator)>, state_version: StateVersion, - ) -> (H::Out, bool, S::Overlay) - where - H::Out: Ord, - { + ) -> (H::Out, bool, S::Overlay) { let default_root = match child_info.child_type() { ChildType::ParentKeyId => empty_child_trie_root::>(), }; let mut write_overlay = S::Overlay::default(); - let mut root = match self.child_root(child_info) { + let child_root = match self.child_root(child_info) { Ok(Some(hash)) => hash, Ok(None) => default_root, Err(e) => { @@ -516,32 +713,39 @@ where }, }; - { + let new_child_root = self.with_recorder_and_cache_for_storage_root(|recorder, cache| { let mut eph = Ephemeral::new(self.backend_storage(), &mut write_overlay); match match state_version { StateVersion::V0 => child_delta_trie_root::, _, _, _, _, _, _>( child_info.keyspace(), &mut eph, - root, + child_root, delta, + recorder, + cache, ), StateVersion::V1 => child_delta_trie_root::, _, _, _, _, _, _>( child_info.keyspace(), &mut eph, - root, + child_root, delta, + recorder, + cache, ), } { - Ok(ret) => root = ret, - Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), + Ok(ret) => (Some(ret), ret), + Err(e) => { + warn!(target: "trie", "Failed to write to trie: {}", e); + (None, child_root) + }, } - } + }); - let is_default = root == default_root; + let is_default = new_child_root == default_root; - (root, is_default, write_overlay) + (new_child_root, is_default, write_overlay) } } @@ -615,6 +819,14 @@ pub trait TrieBackendStorage: Send + Sync { fn get(&self, key: &H::Out, prefix: Prefix) -> Result>; } +impl, H: Hasher> TrieBackendStorage for &T { + type Overlay = T::Overlay; + + fn get(&self, key: &H::Out, prefix: Prefix) -> Result> { + (*self).get(key, prefix) + } +} + // This implementation is used by normal storage trie clients. #[cfg(feature = "std")] impl TrieBackendStorage for Arc> { @@ -637,7 +849,9 @@ where } } -impl, H: Hasher> AsHashDB for TrieBackendEssence { +impl, H: Hasher, C: AsLocalTrieCache + Send + Sync> AsHashDB + for TrieBackendEssence +{ fn as_hash_db<'b>(&'b self) -> &'b (dyn HashDB + 'b) { self } @@ -646,7 +860,9 @@ impl, H: Hasher> AsHashDB for TrieBackendEs } } -impl, H: Hasher> HashDB for TrieBackendEssence { +impl, H: Hasher, C: AsLocalTrieCache + Send + Sync> HashDB + for TrieBackendEssence +{ fn get(&self, key: &H::Out, prefix: Prefix) -> Option { if *key == self.empty { return Some([0u8].to_vec()) @@ -677,7 +893,9 @@ impl, H: Hasher> HashDB for TrieBackendEsse } } -impl, H: Hasher> HashDBRef for TrieBackendEssence { +impl, H: Hasher, C: AsLocalTrieCache + Send + Sync> + HashDBRef for TrieBackendEssence +{ fn get(&self, key: &H::Out, prefix: Prefix) -> Option { HashDB::get(self, key, prefix) } @@ -692,7 +910,8 @@ mod test { use super::*; use sp_core::{Blake2Hasher, H256}; use sp_trie::{ - trie_types::TrieDBMutV1 as TrieDBMut, KeySpacedDBMut, PrefixedMemoryDB, TrieMut, + cache::LocalTrieCache, trie_types::TrieDBMutBuilderV1 as TrieDBMutBuilder, KeySpacedDBMut, + PrefixedMemoryDB, TrieMut, }; #[test] @@ -706,7 +925,7 @@ mod test { let mut mdb = PrefixedMemoryDB::::default(); { - let mut trie = TrieDBMut::new(&mut mdb, &mut root_1); + let mut trie = TrieDBMutBuilder::new(&mut mdb, &mut root_1).build(); trie.insert(b"3", &[1]).expect("insert failed"); trie.insert(b"4", &[1]).expect("insert failed"); trie.insert(b"6", &[1]).expect("insert failed"); @@ -715,18 +934,18 @@ mod test { let mut mdb = KeySpacedDBMut::new(&mut mdb, child_info.keyspace()); // reuse of root_1 implicitly assert child trie root is same // as top trie (contents must remain the same). - let mut trie = TrieDBMut::new(&mut mdb, &mut root_1); + let mut trie = TrieDBMutBuilder::new(&mut mdb, &mut root_1).build(); trie.insert(b"3", &[1]).expect("insert failed"); trie.insert(b"4", &[1]).expect("insert failed"); trie.insert(b"6", &[1]).expect("insert failed"); } { - let mut trie = TrieDBMut::new(&mut mdb, &mut root_2); + let mut trie = TrieDBMutBuilder::new(&mut mdb, &mut root_2).build(); trie.insert(child_info.prefixed_storage_key().as_slice(), root_1.as_ref()) .expect("insert failed"); }; - let essence_1 = TrieBackendEssence::new(mdb, root_1); + let essence_1 = TrieBackendEssence::<_, _, LocalTrieCache<_>>::new(mdb, root_1); assert_eq!(essence_1.next_storage_key(b"2"), Ok(Some(b"3".to_vec()))); assert_eq!(essence_1.next_storage_key(b"3"), Ok(Some(b"4".to_vec()))); @@ -734,8 +953,8 @@ mod test { assert_eq!(essence_1.next_storage_key(b"5"), Ok(Some(b"6".to_vec()))); assert_eq!(essence_1.next_storage_key(b"6"), Ok(None)); - let mdb = essence_1.into_storage(); - let essence_2 = TrieBackendEssence::new(mdb, root_2); + let mdb = essence_1.backend_storage().clone(); + let essence_2 = TrieBackendEssence::<_, _, LocalTrieCache<_>>::new(mdb, root_2); assert_eq!(essence_2.next_child_storage_key(child_info, b"2"), Ok(Some(b"3".to_vec()))); assert_eq!(essence_2.next_child_storage_key(child_info, b"3"), Ok(Some(b"4".to_vec()))); diff --git a/primitives/transaction-storage-proof/src/lib.rs b/primitives/transaction-storage-proof/src/lib.rs index ee0c8e4ec8e29..fde84c1c58b1a 100644 --- a/primitives/transaction-storage-proof/src/lib.rs +++ b/primitives/transaction-storage-proof/src/lib.rs @@ -200,7 +200,8 @@ pub mod registration { let mut transaction_root = sp_trie::empty_trie_root::(); { let mut trie = - sp_trie::TrieDBMut::::new(&mut db, &mut transaction_root); + sp_trie::TrieDBMutBuilder::::new(&mut db, &mut transaction_root) + .build(); let chunks = transaction.chunks(CHUNK_SIZE).map(|c| c.to_vec()); for (index, chunk) in chunks.enumerate() { let index = encode_index(index as u32); diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index a3754461f890e..84b97a9f88da8 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -18,12 +18,19 @@ name = "bench" harness = false [dependencies] +ahash = { version = "0.7.6", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +hashbrown = { version = "0.12.3", optional = true } hash-db = { version = "0.15.2", default-features = false } +lazy_static = { version = "1.4.0", optional = true } +lru = { version = "0.7.5", optional = true } memory-db = { version = "0.29.0", default-features = false } +nohash-hasher = { version = "0.2.0", optional = true } +parking_lot = { version = "0.12.0", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } -trie-db = { version = "0.23.1", default-features = false } +tracing = { version = "0.1.29", optional = true } +trie-db = { version = "0.24.0", default-features = false } trie-root = { version = "0.17.0", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } @@ -31,20 +38,27 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] criterion = "0.3.3" hex-literal = "0.3.4" -trie-bench = "0.30.0" +trie-bench = "0.31.0" trie-standardmap = "0.15.2" sp-runtime = { version = "6.0.0", path = "../runtime" } [features] default = ["std"] std = [ + "ahash", "codec/std", + "hashbrown", "hash-db/std", + "lazy_static", + "lru", "memory-db/std", + "nohash-hasher", + "parking_lot", "scale-info/std", "sp-core/std", "sp-std/std", "thiserror", + "tracing", "trie-db/std", "trie-root/std", ] diff --git a/primitives/trie/src/cache/mod.rs b/primitives/trie/src/cache/mod.rs new file mode 100644 index 0000000000000..a588f20bdb7b4 --- /dev/null +++ b/primitives/trie/src/cache/mod.rs @@ -0,0 +1,686 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Trie Cache +//! +//! Provides an implementation of the [`TrieCache`](trie_db::TrieCache) trait. +//! The implementation is split into three types [`SharedTrieCache`], [`LocalTrieCache`] and +//! [`TrieCache`]. The [`SharedTrieCache`] is the instance that should be kept around for the entire +//! lifetime of the node. It will store all cached trie nodes and values on a global level. Then +//! there is the [`LocalTrieCache`] that should be kept around per state instance requested from the +//! backend. As there are very likely multiple accesses to the state per instance, this +//! [`LocalTrieCache`] is used to cache the nodes and the values before they are merged back to the +//! shared instance. Last but not least there is the [`TrieCache`] that is being used per access to +//! the state. It will use the [`SharedTrieCache`] and the [`LocalTrieCache`] to fulfill cache +//! requests. If both of them don't provide the requested data it will be inserted into the +//! [`LocalTrieCache`] and then later into the [`SharedTrieCache`]. +//! +//! The [`SharedTrieCache`] is bound to some maximum number of bytes. It is ensured that it never +//! runs above this limit. However as long as data is cached inside a [`LocalTrieCache`] it isn't +//! taken into account when limiting the [`SharedTrieCache`]. This means that for the lifetime of a +//! [`LocalTrieCache`] the actual memory usage could be above the allowed maximum. + +use crate::{Error, NodeCodec}; +use hash_db::Hasher; +use hashbrown::HashSet; +use nohash_hasher::BuildNoHashHasher; +use parking_lot::{Mutex, MutexGuard, RwLockReadGuard}; +use shared_cache::{SharedValueCache, ValueCacheKey}; +use std::{ + collections::{hash_map::Entry as MapEntry, HashMap}, + sync::Arc, +}; +use trie_db::{node::NodeOwned, CachedValue}; + +mod shared_cache; + +pub use shared_cache::SharedTrieCache; + +use self::shared_cache::{SharedTrieCacheInner, ValueCacheKeyHash}; + +const LOG_TARGET: &str = "trie-cache"; + +/// The size of the cache. +#[derive(Debug, Clone, Copy)] +pub enum CacheSize { + /// Do not limit the cache size. + Unlimited, + /// Let the cache in maximum use the given amount of bytes. + Maximum(usize), +} + +impl CacheSize { + /// Returns `true` if the `current_size` exceeds the allowed size. + fn exceeds(&self, current_size: usize) -> bool { + match self { + Self::Unlimited => false, + Self::Maximum(max) => *max < current_size, + } + } +} + +/// The local trie cache. +/// +/// This cache should be used per state instance created by the backend. One state instance is +/// referring to the state of one block. It will cache all the accesses that are done to the state +/// which could not be fullfilled by the [`SharedTrieCache`]. These locally cached items are merged +/// back to the shared trie cache when this instance is dropped. +/// +/// When using [`Self::as_trie_db_cache`] or [`Self::as_trie_db_mut_cache`], it will lock Mutexes. +/// So, it is important that these methods are not called multiple times, because they otherwise +/// deadlock. +pub struct LocalTrieCache { + /// The shared trie cache that created this instance. + shared: SharedTrieCache, + /// The local cache for the trie nodes. + node_cache: Mutex>>, + /// Keeps track of all the trie nodes accessed in the shared cache. + /// + /// This will be used to ensure that these nodes are brought to the front of the lru when this + /// local instance is merged back to the shared cache. + shared_node_cache_access: Mutex>, + /// The local cache for the values. + value_cache: Mutex< + HashMap< + ValueCacheKey<'static, H::Out>, + CachedValue, + BuildNoHashHasher>, + >, + >, + /// Keeps track of all values accessed in the shared cache. + /// + /// This will be used to ensure that these nodes are brought to the front of the lru when this + /// local instance is merged back to the shared cache. This can actually lead to collision when + /// two [`ValueCacheKey`]s with different storage roots and keys map to the same hash. However, + /// as we only use this set to update the lru position it is fine, even if we bring the wrong + /// value to the top. The important part is that we always get the correct value from the value + /// cache for a given key. + shared_value_cache_access: + Mutex>>, +} + +impl LocalTrieCache { + /// Return self as a [`TrieDB`](trie_db::TrieDB) compatible cache. + /// + /// The given `storage_root` needs to be the storage root of the trie this cache is used for. + pub fn as_trie_db_cache(&self, storage_root: H::Out) -> TrieCache<'_, H> { + let shared_inner = self.shared.read_lock_inner(); + + let value_cache = ValueCache::ForStorageRoot { + storage_root, + local_value_cache: self.value_cache.lock(), + shared_value_cache_access: self.shared_value_cache_access.lock(), + }; + + TrieCache { + shared_inner, + local_cache: self.node_cache.lock(), + value_cache, + shared_node_cache_access: self.shared_node_cache_access.lock(), + } + } + + /// Return self as [`TrieDBMut`](trie_db::TrieDBMut) compatible cache. + /// + /// After finishing all operations with [`TrieDBMut`](trie_db::TrieDBMut) and having obtained + /// the new storage root, [`TrieCache::merge_into`] should be called to update this local + /// cache instance. If the function is not called, cached data is just thrown away and not + /// propagated to the shared cache. So, accessing these new items will be slower, but nothing + /// would break because of this. + pub fn as_trie_db_mut_cache(&self) -> TrieCache<'_, H> { + TrieCache { + shared_inner: self.shared.read_lock_inner(), + local_cache: self.node_cache.lock(), + value_cache: ValueCache::Fresh(Default::default()), + shared_node_cache_access: self.shared_node_cache_access.lock(), + } + } +} + +impl Drop for LocalTrieCache { + fn drop(&mut self) { + let mut shared_inner = self.shared.write_lock_inner(); + + shared_inner + .node_cache_mut() + .update(self.node_cache.lock().drain(), self.shared_node_cache_access.lock().drain()); + + shared_inner + .value_cache_mut() + .update(self.value_cache.lock().drain(), self.shared_value_cache_access.lock().drain()); + } +} + +/// The abstraction of the value cache for the [`TrieCache`]. +enum ValueCache<'a, H> { + /// The value cache is fresh, aka not yet associated to any storage root. + /// This is used for example when a new trie is being build, to cache new values. + Fresh(HashMap, CachedValue>), + /// The value cache is already bound to a specific storage root. + ForStorageRoot { + shared_value_cache_access: MutexGuard< + 'a, + HashSet>, + >, + local_value_cache: MutexGuard< + 'a, + HashMap< + ValueCacheKey<'static, H>, + CachedValue, + nohash_hasher::BuildNoHashHasher>, + >, + >, + storage_root: H, + }, +} + +impl + std::hash::Hash + Eq + Clone + Copy> ValueCache<'_, H> { + /// Get the value for the given `key`. + fn get<'a>( + &'a mut self, + key: &[u8], + shared_value_cache: &'a SharedValueCache, + ) -> Option<&CachedValue> { + match self { + Self::Fresh(map) => map.get(key), + Self::ForStorageRoot { local_value_cache, shared_value_cache_access, storage_root } => { + let key = ValueCacheKey::new_ref(key, *storage_root); + + // We first need to look up in the local cache and then the shared cache. + // It can happen that some value is cached in the shared cache, but the + // weak reference of the data can not be upgraded anymore. This for example + // happens when the node is dropped that contains the strong reference to the data. + // + // So, the logic of the trie would lookup the data and the node and store both + // in our local caches. + local_value_cache + .get(unsafe { + // SAFETY + // + // We need to convert the lifetime to make the compiler happy. However, as + // we only use the `key` to looking up the value this lifetime conversion is + // safe. + std::mem::transmute::<&ValueCacheKey<'_, H>, &ValueCacheKey<'static, H>>( + &key, + ) + }) + .or_else(|| { + shared_value_cache.get(&key).map(|v| { + shared_value_cache_access.insert(key.get_hash()); + v + }) + }) + }, + } + } + + /// Insert some new `value` under the given `key`. + fn insert(&mut self, key: &[u8], value: CachedValue) { + match self { + Self::Fresh(map) => { + map.insert(key.into(), value); + }, + Self::ForStorageRoot { local_value_cache, storage_root, .. } => { + local_value_cache.insert(ValueCacheKey::new_value(key, *storage_root), value); + }, + } + } +} + +/// The actual [`TrieCache`](trie_db::TrieCache) implementation. +/// +/// If this instance was created for using it with a [`TrieDBMut`](trie_db::TrieDBMut), it needs to +/// be merged back into the [`LocalTrieCache`] with [`Self::merge_into`] after all operations are +/// done. +pub struct TrieCache<'a, H: Hasher> { + shared_inner: RwLockReadGuard<'a, SharedTrieCacheInner>, + shared_node_cache_access: MutexGuard<'a, HashSet>, + local_cache: MutexGuard<'a, HashMap>>, + value_cache: ValueCache<'a, H::Out>, +} + +impl<'a, H: Hasher> TrieCache<'a, H> { + /// Merge this cache into the given [`LocalTrieCache`]. + /// + /// This function is only required to be called when this instance was created through + /// [`LocalTrieCache::as_trie_db_mut_cache`], otherwise this method is a no-op. The given + /// `storage_root` is the new storage root that was obtained after finishing all operations + /// using the [`TrieDBMut`](trie_db::TrieDBMut). + pub fn merge_into(self, local: &LocalTrieCache, storage_root: H::Out) { + let cache = if let ValueCache::Fresh(cache) = self.value_cache { cache } else { return }; + + if !cache.is_empty() { + let mut value_cache = local.value_cache.lock(); + let partial_hash = ValueCacheKey::hash_partial_data(&storage_root); + + cache + .into_iter() + .map(|(k, v)| { + let hash = + ValueCacheKeyHash::from_hasher_and_storage_key(partial_hash.clone(), &k); + (ValueCacheKey::Value { storage_key: k, storage_root, hash }, v) + }) + .for_each(|(k, v)| { + value_cache.insert(k, v); + }); + } + } +} + +impl<'a, H: Hasher> trie_db::TrieCache> for TrieCache<'a, H> { + fn get_or_insert_node( + &mut self, + hash: H::Out, + fetch_node: &mut dyn FnMut() -> trie_db::Result, H::Out, Error>, + ) -> trie_db::Result<&NodeOwned, H::Out, Error> { + if let Some(res) = self.shared_inner.node_cache().get(&hash) { + tracing::trace!(target: LOG_TARGET, ?hash, "Serving node from shared cache"); + self.shared_node_cache_access.insert(hash); + return Ok(res) + } + + match self.local_cache.entry(hash) { + MapEntry::Occupied(res) => { + tracing::trace!(target: LOG_TARGET, ?hash, "Serving node from local cache"); + Ok(res.into_mut()) + }, + MapEntry::Vacant(vacant) => { + let node = (*fetch_node)(); + + tracing::trace!( + target: LOG_TARGET, + ?hash, + fetch_successful = node.is_ok(), + "Node not found, needed to fetch it." + ); + + Ok(vacant.insert(node?)) + }, + } + } + + fn get_node(&mut self, hash: &H::Out) -> Option<&NodeOwned> { + if let Some(node) = self.shared_inner.node_cache().get(hash) { + tracing::trace!(target: LOG_TARGET, ?hash, "Getting node from shared cache"); + self.shared_node_cache_access.insert(*hash); + return Some(node) + } + + let res = self.local_cache.get(hash); + + tracing::trace!( + target: LOG_TARGET, + ?hash, + found = res.is_some(), + "Getting node from local cache" + ); + + res + } + + fn lookup_value_for_key(&mut self, key: &[u8]) -> Option<&CachedValue> { + let res = self.value_cache.get(key, self.shared_inner.value_cache()); + + tracing::trace!( + target: LOG_TARGET, + key = ?sp_core::hexdisplay::HexDisplay::from(&key), + found = res.is_some(), + "Looked up value for key", + ); + + res + } + + fn cache_value_for_key(&mut self, key: &[u8], data: CachedValue) { + tracing::trace!( + target: LOG_TARGET, + key = ?sp_core::hexdisplay::HexDisplay::from(&key), + "Caching value for key", + ); + + self.value_cache.insert(key.into(), data); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use trie_db::{Bytes, Trie, TrieDBBuilder, TrieDBMutBuilder, TrieHash, TrieMut}; + + type MemoryDB = crate::MemoryDB; + type Layout = crate::LayoutV1; + type Cache = super::SharedTrieCache; + type Recorder = crate::recorder::Recorder; + + const TEST_DATA: &[(&[u8], &[u8])] = + &[(b"key1", b"val1"), (b"key2", &[2; 64]), (b"key3", b"val3"), (b"key4", &[4; 64])]; + const CACHE_SIZE_RAW: usize = 1024 * 10; + const CACHE_SIZE: CacheSize = CacheSize::Maximum(CACHE_SIZE_RAW); + + fn create_trie() -> (MemoryDB, TrieHash) { + let mut db = MemoryDB::default(); + let mut root = Default::default(); + + { + let mut trie = TrieDBMutBuilder::::new(&mut db, &mut root).build(); + for (k, v) in TEST_DATA { + trie.insert(k, v).expect("Inserts data"); + } + } + + (db, root) + } + + #[test] + fn basic_cache_works() { + let (db, root) = create_trie(); + + let shared_cache = Cache::new(CACHE_SIZE); + let local_cache = shared_cache.local_cache(); + + { + let mut cache = local_cache.as_trie_db_cache(root); + let trie = TrieDBBuilder::::new(&db, &root).with_cache(&mut cache).build(); + assert_eq!(TEST_DATA[0].1.to_vec(), trie.get(TEST_DATA[0].0).unwrap().unwrap()); + } + + // Local cache wasn't dropped yet, so there should nothing in the shared caches. + assert!(shared_cache.read_lock_inner().value_cache().lru.is_empty()); + assert!(shared_cache.read_lock_inner().node_cache().lru.is_empty()); + + drop(local_cache); + + // Now we should have the cached items in the shared cache. + assert!(shared_cache.read_lock_inner().node_cache().lru.len() >= 1); + let cached_data = shared_cache + .read_lock_inner() + .value_cache() + .lru + .peek(&ValueCacheKey::new_value(TEST_DATA[0].0, root)) + .unwrap() + .clone(); + assert_eq!(Bytes::from(TEST_DATA[0].1.to_vec()), cached_data.data().flatten().unwrap()); + + let fake_data = Bytes::from(&b"fake_data"[..]); + + let local_cache = shared_cache.local_cache(); + shared_cache.write_lock_inner().value_cache_mut().lru.put( + ValueCacheKey::new_value(TEST_DATA[1].0, root), + (fake_data.clone(), Default::default()).into(), + ); + + { + let mut cache = local_cache.as_trie_db_cache(root); + let trie = TrieDBBuilder::::new(&db, &root).with_cache(&mut cache).build(); + + // We should now get the "fake_data", because we inserted this manually to the cache. + assert_eq!(b"fake_data".to_vec(), trie.get(TEST_DATA[1].0).unwrap().unwrap()); + } + } + + #[test] + fn trie_db_mut_cache_works() { + let (mut db, root) = create_trie(); + + let new_key = b"new_key".to_vec(); + // Use some long value to not have it inlined + let new_value = vec![23; 64]; + + let shared_cache = Cache::new(CACHE_SIZE); + let mut new_root = root; + + { + let local_cache = shared_cache.local_cache(); + + let mut cache = local_cache.as_trie_db_mut_cache(); + + { + let mut trie = TrieDBMutBuilder::::from_existing(&mut db, &mut new_root) + .with_cache(&mut cache) + .build(); + + trie.insert(&new_key, &new_value).unwrap(); + } + + cache.merge_into(&local_cache, new_root); + } + + // After the local cache is dropped, all changes should have been merged back to the shared + // cache. + let cached_data = shared_cache + .read_lock_inner() + .value_cache() + .lru + .peek(&ValueCacheKey::new_value(new_key, new_root)) + .unwrap() + .clone(); + assert_eq!(Bytes::from(new_value), cached_data.data().flatten().unwrap()); + } + + #[test] + fn trie_db_cache_and_recorder_work_together() { + let (db, root) = create_trie(); + + let shared_cache = Cache::new(CACHE_SIZE); + + for i in 0..5 { + // Clear some of the caches. + if i == 2 { + shared_cache.reset_node_cache(); + } else if i == 3 { + shared_cache.reset_value_cache(); + } + + let local_cache = shared_cache.local_cache(); + let recorder = Recorder::default(); + + { + let mut cache = local_cache.as_trie_db_cache(root); + let mut recorder = recorder.as_trie_recorder(); + let trie = TrieDBBuilder::::new(&db, &root) + .with_cache(&mut cache) + .with_recorder(&mut recorder) + .build(); + + for (key, value) in TEST_DATA { + assert_eq!(*value, trie.get(&key).unwrap().unwrap()); + } + } + + let storage_proof = recorder.drain_storage_proof(); + let memory_db: MemoryDB = storage_proof.into_memory_db(); + + { + let trie = TrieDBBuilder::::new(&memory_db, &root).build(); + + for (key, value) in TEST_DATA { + assert_eq!(*value, trie.get(&key).unwrap().unwrap()); + } + } + } + } + + #[test] + fn trie_db_mut_cache_and_recorder_work_together() { + const DATA_TO_ADD: &[(&[u8], &[u8])] = &[(b"key11", &[45; 78]), (b"key33", &[78; 89])]; + + let (db, root) = create_trie(); + + let shared_cache = Cache::new(CACHE_SIZE); + + // Run this twice so that we use the data cache in the second run. + for i in 0..5 { + // Clear some of the caches. + if i == 2 { + shared_cache.reset_node_cache(); + } else if i == 3 { + shared_cache.reset_value_cache(); + } + + let recorder = Recorder::default(); + let local_cache = shared_cache.local_cache(); + let mut new_root = root; + + { + let mut db = db.clone(); + let mut cache = local_cache.as_trie_db_cache(root); + let mut recorder = recorder.as_trie_recorder(); + let mut trie = TrieDBMutBuilder::::from_existing(&mut db, &mut new_root) + .with_cache(&mut cache) + .with_recorder(&mut recorder) + .build(); + + for (key, value) in DATA_TO_ADD { + trie.insert(key, value).unwrap(); + } + } + + let storage_proof = recorder.drain_storage_proof(); + let mut memory_db: MemoryDB = storage_proof.into_memory_db(); + let mut proof_root = root; + + { + let mut trie = + TrieDBMutBuilder::::from_existing(&mut memory_db, &mut proof_root) + .build(); + + for (key, value) in DATA_TO_ADD { + trie.insert(key, value).unwrap(); + } + } + + assert_eq!(new_root, proof_root) + } + } + + #[test] + fn cache_lru_works() { + let (db, root) = create_trie(); + + let shared_cache = Cache::new(CACHE_SIZE); + + { + let local_cache = shared_cache.local_cache(); + + let mut cache = local_cache.as_trie_db_cache(root); + let trie = TrieDBBuilder::::new(&db, &root).with_cache(&mut cache).build(); + + for (k, _) in TEST_DATA { + trie.get(k).unwrap().unwrap(); + } + } + + // Check that all items are there. + assert!(shared_cache + .read_lock_inner() + .value_cache() + .lru + .iter() + .map(|d| d.0) + .all(|l| TEST_DATA.iter().any(|d| l.storage_key().unwrap() == d.0))); + + { + let local_cache = shared_cache.local_cache(); + + let mut cache = local_cache.as_trie_db_cache(root); + let trie = TrieDBBuilder::::new(&db, &root).with_cache(&mut cache).build(); + + for (k, _) in TEST_DATA.iter().take(2) { + trie.get(k).unwrap().unwrap(); + } + } + + // Ensure that the accessed items are most recently used items of the shared value cache. + assert!(shared_cache + .read_lock_inner() + .value_cache() + .lru + .iter() + .take(2) + .map(|d| d.0) + .all(|l| { TEST_DATA.iter().take(2).any(|d| l.storage_key().unwrap() == d.0) })); + + let most_recently_used_nodes = shared_cache + .read_lock_inner() + .node_cache() + .lru + .iter() + .map(|d| *d.0) + .collect::>(); + + // Delete the value cache, so that we access the nodes. + shared_cache.reset_value_cache(); + + { + let local_cache = shared_cache.local_cache(); + + let mut cache = local_cache.as_trie_db_cache(root); + let trie = TrieDBBuilder::::new(&db, &root).with_cache(&mut cache).build(); + + for (k, _) in TEST_DATA.iter().take(2) { + trie.get(k).unwrap().unwrap(); + } + } + + // Ensure that the most recently used nodes changed as well. + assert_ne!( + most_recently_used_nodes, + shared_cache + .read_lock_inner() + .node_cache() + .lru + .iter() + .map(|d| *d.0) + .collect::>() + ); + } + + #[test] + fn cache_respects_bounds() { + let (mut db, root) = create_trie(); + + let shared_cache = Cache::new(CACHE_SIZE); + { + let local_cache = shared_cache.local_cache(); + + let mut new_root = root; + + { + let mut cache = local_cache.as_trie_db_cache(root); + { + let mut trie = + TrieDBMutBuilder::::from_existing(&mut db, &mut new_root) + .with_cache(&mut cache) + .build(); + + let value = vec![10u8; 100]; + // Ensure we add enough data that would overflow the cache. + for i in 0..CACHE_SIZE_RAW / 100 * 2 { + trie.insert(format!("key{}", i).as_bytes(), &value).unwrap(); + } + } + + cache.merge_into(&local_cache, new_root); + } + } + + let node_cache_size = shared_cache.read_lock_inner().node_cache().size_in_bytes; + let value_cache_size = shared_cache.read_lock_inner().value_cache().size_in_bytes; + + assert!(node_cache_size + value_cache_size < CACHE_SIZE_RAW); + } +} diff --git a/primitives/trie/src/cache/shared_cache.rs b/primitives/trie/src/cache/shared_cache.rs new file mode 100644 index 0000000000000..abac8c9f946ca --- /dev/null +++ b/primitives/trie/src/cache/shared_cache.rs @@ -0,0 +1,677 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +///! Provides the [`SharedNodeCache`], the [`SharedValueCache`] and the [`SharedTrieCache`] +///! that combines both caches and is exported to the outside. +use super::{CacheSize, LOG_TARGET}; +use hash_db::Hasher; +use hashbrown::{hash_set::Entry as SetEntry, HashSet}; +use lru::LruCache; +use nohash_hasher::BuildNoHashHasher; +use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use std::{ + hash::{BuildHasher, Hasher as _}, + mem, + sync::Arc, +}; +use trie_db::{node::NodeOwned, CachedValue}; + +lazy_static::lazy_static! { + static ref RANDOM_STATE: ahash::RandomState = ahash::RandomState::default(); +} + +/// No hashing [`LruCache`]. +type NoHashingLruCache = lru::LruCache>; + +/// The shared node cache. +/// +/// Internally this stores all cached nodes in a [`LruCache`]. It ensures that when updating the +/// cache, that the cache stays within its allowed bounds. +pub(super) struct SharedNodeCache { + /// The cached nodes, ordered by least recently used. + pub(super) lru: LruCache>, + /// The size of [`Self::lru`] in bytes. + pub(super) size_in_bytes: usize, + /// The maximum cache size of [`Self::lru`]. + maximum_cache_size: CacheSize, +} + +impl + Eq + std::hash::Hash> SharedNodeCache { + /// Create a new instance. + fn new(cache_size: CacheSize) -> Self { + Self { lru: LruCache::unbounded(), size_in_bytes: 0, maximum_cache_size: cache_size } + } + + /// Get the node for `key`. + /// + /// This doesn't change the least recently order in the internal [`LruCache`]. + pub fn get(&self, key: &H) -> Option<&NodeOwned> { + self.lru.peek(key) + } + + /// Update the cache with the `added` nodes and the `accessed` nodes. + /// + /// The `added` nodes are the ones that have been collected by doing operations on the trie and + /// now should be stored in the shared cache. The `accessed` nodes are only referenced by hash + /// and represent the nodes that were retrieved from this shared cache through [`Self::get`]. + /// These `accessed` nodes are being put to the front of the internal [`LruCache`] like the + /// `added` ones. + /// + /// After the internal [`LruCache`] was updated, it is ensured that the internal [`LruCache`] is + /// inside its bounds ([`Self::maximum_size_in_bytes`]). + pub fn update( + &mut self, + added: impl IntoIterator)>, + accessed: impl IntoIterator, + ) { + let update_size_in_bytes = |size_in_bytes: &mut usize, key: &H, node: &NodeOwned| { + if let Some(new_size_in_bytes) = + size_in_bytes.checked_sub(key.as_ref().len() + node.size_in_bytes()) + { + *size_in_bytes = new_size_in_bytes; + } else { + *size_in_bytes = 0; + tracing::error!(target: LOG_TARGET, "`SharedNodeCache` underflow detected!",); + } + }; + + accessed.into_iter().for_each(|key| { + // Access every node in the lru to put it to the front. + self.lru.get(&key); + }); + added.into_iter().for_each(|(key, node)| { + self.size_in_bytes += key.as_ref().len() + node.size_in_bytes(); + + if let Some((r_key, r_node)) = self.lru.push(key, node) { + update_size_in_bytes(&mut self.size_in_bytes, &r_key, &r_node); + } + + // Directly ensure that we respect the maximum size. By doing it directly here we ensure + // that the internal map of the [`LruCache`] doesn't grow too much. + while self.maximum_cache_size.exceeds(self.size_in_bytes) { + // This should always be `Some(_)`, otherwise something is wrong! + if let Some((key, node)) = self.lru.pop_lru() { + update_size_in_bytes(&mut self.size_in_bytes, &key, &node); + } + } + }); + } + + /// Reset the cache. + fn reset(&mut self) { + self.size_in_bytes = 0; + self.lru.clear(); + } +} + +/// The hash of [`ValueCacheKey`]. +#[derive(Eq, Clone, Copy)] +pub struct ValueCacheKeyHash(u64); + +impl ValueCacheKeyHash { + pub fn from_hasher_and_storage_key( + mut hasher: impl std::hash::Hasher, + storage_key: &[u8], + ) -> Self { + hasher.write(storage_key); + + Self(hasher.finish()) + } +} + +impl PartialEq for ValueCacheKeyHash { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl std::hash::Hash for ValueCacheKeyHash { + fn hash(&self, state: &mut Hasher) { + state.write_u64(self.0); + } +} + +impl nohash_hasher::IsEnabled for ValueCacheKeyHash {} + +/// A type that can only be constructed inside of this file. +/// +/// It "requires" that the user has read the docs to prevent fuck ups. +#[derive(Eq, PartialEq)] +pub(super) struct IReadTheDocumentation(()); + +/// The key type that is being used to address a [`CachedValue`]. +/// +/// This type is implemented as `enum` to improve the performance when accessing the value cache. +/// The problem being that we need to calculate the `hash` of [`Self`] in worst case three times +/// when trying to find a value in the value cache. First to lookup the local cache, then the shared +/// cache and if we found it in the shared cache a third time to insert it into the list of accessed +/// values. To work around each variant stores the `hash` to identify a unique combination of +/// `storage_key` and `storage_root`. However, be aware that this `hash` can lead to collisions when +/// there are two different `storage_key` and `storage_root` pairs that map to the same `hash`. This +/// type also has the `Hash` variant. This variant should only be used for the use case of updating +/// the lru for a key. Because when using only the `Hash` variant to getting a value from a hash map +/// it could happen that a wrong value is returned when there is another key in the same hash map +/// that maps to the same `hash`. The [`PartialEq`] implementation is written in a way that when one +/// of the two compared instances is the `Hash` variant, we will only compare the hashes. This +/// ensures that we can use the `Hash` variant to bring values up in the lru. +#[derive(Eq)] +pub(super) enum ValueCacheKey<'a, H> { + /// Variant that stores the `storage_key` by value. + Value { + /// The storage root of the trie this key belongs to. + storage_root: H, + /// The key to access the value in the storage. + storage_key: Arc<[u8]>, + /// The hash that identifying this instance of `storage_root` and `storage_key`. + hash: ValueCacheKeyHash, + }, + /// Variant that only references the `storage_key`. + Ref { + /// The storage root of the trie this key belongs to. + storage_root: H, + /// The key to access the value in the storage. + storage_key: &'a [u8], + /// The hash that identifying this instance of `storage_root` and `storage_key`. + hash: ValueCacheKeyHash, + }, + /// Variant that only stores the hash that represents the `storage_root` and `storage_key`. + /// + /// This should be used by caution, because it can lead to accessing the wrong value in a + /// hash map/set when there exists two different `storage_root`s and `storage_key`s that + /// map to the same `hash`. + Hash { hash: ValueCacheKeyHash, _i_read_the_documentation: IReadTheDocumentation }, +} + +impl<'a, H> ValueCacheKey<'a, H> { + /// Constructs [`Self::Value`]. + pub fn new_value(storage_key: impl Into>, storage_root: H) -> Self + where + H: AsRef<[u8]>, + { + let storage_key = storage_key.into(); + let hash = Self::hash_data(&storage_key, &storage_root); + Self::Value { storage_root, storage_key, hash } + } + + /// Constructs [`Self::Ref`]. + pub fn new_ref(storage_key: &'a [u8], storage_root: H) -> Self + where + H: AsRef<[u8]>, + { + let storage_key = storage_key.into(); + let hash = Self::hash_data(storage_key, &storage_root); + Self::Ref { storage_root, storage_key, hash } + } + + /// Returns a hasher prepared to build the final hash to identify [`Self`]. + /// + /// See [`Self::hash_data`] for building the hash directly. + pub fn hash_partial_data(storage_root: &H) -> impl std::hash::Hasher + Clone + where + H: AsRef<[u8]>, + { + let mut hasher = RANDOM_STATE.build_hasher(); + hasher.write(storage_root.as_ref()); + hasher + } + + /// Hash the `key` and `storage_root` that identify [`Self`]. + /// + /// Returns a `u64` which represents the unique hash for the given inputs. + pub fn hash_data(key: &[u8], storage_root: &H) -> ValueCacheKeyHash + where + H: AsRef<[u8]>, + { + let hasher = Self::hash_partial_data(storage_root); + + ValueCacheKeyHash::from_hasher_and_storage_key(hasher, key) + } + + /// Returns the `hash` that identifies the current instance. + pub fn get_hash(&self) -> ValueCacheKeyHash { + match self { + Self::Value { hash, .. } | Self::Ref { hash, .. } | Self::Hash { hash, .. } => *hash, + } + } + + /// Returns the stored storage root. + pub fn storage_root(&self) -> Option<&H> { + match self { + Self::Value { storage_root, .. } | Self::Ref { storage_root, .. } => Some(storage_root), + Self::Hash { .. } => None, + } + } + + /// Returns the stored storage key. + pub fn storage_key(&self) -> Option<&[u8]> { + match self { + Self::Ref { storage_key, .. } => Some(&storage_key), + Self::Value { storage_key, .. } => Some(storage_key), + Self::Hash { .. } => None, + } + } +} + +// Implement manually to ensure that the `Value` and `Hash` are treated equally. +impl std::hash::Hash for ValueCacheKey<'_, H> { + fn hash(&self, state: &mut Hasher) { + self.get_hash().hash(state) + } +} + +impl nohash_hasher::IsEnabled for ValueCacheKey<'_, H> {} + +// Implement manually to ensure that the `Value` and `Hash` are treated equally. +impl PartialEq for ValueCacheKey<'_, H> { + fn eq(&self, other: &Self) -> bool { + // First check if `self` or `other` is only the `Hash`. + // Then we only compare the `hash`. So, there could actually be some collision + // if two different storage roots and keys are mapping to the same key. See the + // [`ValueCacheKey`] docs for more information. + match (self, other) { + (Self::Hash { hash, .. }, Self::Hash { hash: other_hash, .. }) => hash == other_hash, + (Self::Hash { hash, .. }, _) => *hash == other.get_hash(), + (_, Self::Hash { hash: other_hash, .. }) => self.get_hash() == *other_hash, + // If both are not the `Hash` variant, we compare all the values. + _ => + self.get_hash() == other.get_hash() && + self.storage_root() == other.storage_root() && + self.storage_key() == other.storage_key(), + } + } +} + +/// The shared value cache. +/// +/// The cache ensures that it stays in the configured size bounds. +pub(super) struct SharedValueCache { + /// The cached nodes, ordered by least recently used. + pub(super) lru: NoHashingLruCache, CachedValue>, + /// The size of [`Self::lru`] in bytes. + pub(super) size_in_bytes: usize, + /// The maximum cache size of [`Self::lru`]. + maximum_cache_size: CacheSize, + /// All known storage keys that are stored in [`Self::lru`]. + /// + /// This is used to de-duplicate keys in memory that use the + /// same [`SharedValueCache::storage_key`], but have a different + /// [`SharedValueCache::storage_root`]. + known_storage_keys: HashSet>, +} + +impl> SharedValueCache { + /// Create a new instance. + fn new(cache_size: CacheSize) -> Self { + Self { + lru: NoHashingLruCache::unbounded_with_hasher(Default::default()), + size_in_bytes: 0, + maximum_cache_size: cache_size, + known_storage_keys: Default::default(), + } + } + + /// Get the [`CachedValue`] for `key`. + /// + /// This doesn't change the least recently order in the internal [`LruCache`]. + pub fn get<'a>(&'a self, key: &ValueCacheKey) -> Option<&'a CachedValue> { + debug_assert!( + !matches!(key, ValueCacheKey::Hash { .. }), + "`get` can not be called with `Hash` variant as this may returns the wrong value." + ); + + self.lru.peek(unsafe { + // SAFETY + // + // We need to convert the lifetime to make the compiler happy. However, as + // we only use the `key` to looking up the value this lifetime conversion is + // safe. + mem::transmute::<&ValueCacheKey<'_, H>, &ValueCacheKey<'static, H>>(key) + }) + } + + /// Update the cache with the `added` values and the `accessed` values. + /// + /// The `added` values are the ones that have been collected by doing operations on the trie and + /// now should be stored in the shared cache. The `accessed` values are only referenced by the + /// [`ValueCacheKeyHash`] and represent the values that were retrieved from this shared cache + /// through [`Self::get`]. These `accessed` values are being put to the front of the internal + /// [`LruCache`] like the `added` ones. + /// + /// After the internal [`LruCache`] was updated, it is ensured that the internal [`LruCache`] is + /// inside its bounds ([`Self::maximum_size_in_bytes`]). + pub fn update( + &mut self, + added: impl IntoIterator, CachedValue)>, + accessed: impl IntoIterator, + ) { + // The base size in memory per ([`ValueCacheKey`], [`CachedValue`]). + let base_size = mem::size_of::>() + mem::size_of::>(); + let known_keys_entry_size = mem::size_of::>(); + + let update_size_in_bytes = + |size_in_bytes: &mut usize, r_key: Arc<[u8]>, known_keys: &mut HashSet>| { + // If the `strong_count == 2`, it means this is the last instance of the key. + // One being `r_key` and the other being stored in `known_storage_keys`. + let last_instance = Arc::strong_count(&r_key) == 2; + + let key_len = if last_instance { + known_keys.remove(&r_key); + r_key.len() + known_keys_entry_size + } else { + // The key is still in `keys`, because it is still used by another + // `ValueCacheKey`. + 0 + }; + + if let Some(new_size_in_bytes) = size_in_bytes.checked_sub(key_len + base_size) { + *size_in_bytes = new_size_in_bytes; + } else { + *size_in_bytes = 0; + tracing::error!(target: LOG_TARGET, "`SharedValueCache` underflow detected!",); + } + }; + + accessed.into_iter().for_each(|key| { + // Access every node in the lru to put it to the front. + // As we are using the `Hash` variant here, it may leads to putting the wrong value to + // the top. However, the only consequence of this is that we may prune a recently used + // value to early. + self.lru.get(&ValueCacheKey::Hash { + hash: key, + _i_read_the_documentation: IReadTheDocumentation(()), + }); + }); + + added.into_iter().for_each(|(key, value)| { + let (storage_root, storage_key, key_hash) = match key { + ValueCacheKey::Hash { .. } => { + // Ignore the hash variant and try the next. + tracing::error!( + target: LOG_TARGET, + "`SharedValueCached::update` was called with a key to add \ + that uses the `Hash` variant. This would lead to potential hash collision!", + ); + return + }, + ValueCacheKey::Ref { storage_key, storage_root, hash } => + (storage_root, storage_key.into(), hash), + ValueCacheKey::Value { storage_root, storage_key, hash } => + (storage_root, storage_key, hash), + }; + + let (size_update, storage_key) = + match self.known_storage_keys.entry(storage_key.clone()) { + SetEntry::Vacant(v) => { + let len = v.get().len(); + v.insert(); + + // If the key was unknown, we need to also take its length and the size of + // the entry of `known_keys` into account. + (len + base_size + known_keys_entry_size, storage_key) + }, + SetEntry::Occupied(o) => { + // Key is known + (base_size, o.get().clone()) + }, + }; + + self.size_in_bytes += size_update; + + if let Some((r_key, _)) = self + .lru + .push(ValueCacheKey::Value { storage_key, storage_root, hash: key_hash }, value) + { + if let ValueCacheKey::Value { storage_key, .. } = r_key { + update_size_in_bytes( + &mut self.size_in_bytes, + storage_key, + &mut self.known_storage_keys, + ); + } + } + + // Directly ensure that we respect the maximum size. By doing it directly here we + // ensure that the internal map of the [`LruCache`] doesn't grow too much. + while self.maximum_cache_size.exceeds(self.size_in_bytes) { + // This should always be `Some(_)`, otherwise something is wrong! + if let Some((r_key, _)) = self.lru.pop_lru() { + if let ValueCacheKey::Value { storage_key, .. } = r_key { + update_size_in_bytes( + &mut self.size_in_bytes, + storage_key, + &mut self.known_storage_keys, + ); + } + } + } + }); + } + + /// Reset the cache. + fn reset(&mut self) { + self.size_in_bytes = 0; + self.lru.clear(); + self.known_storage_keys.clear(); + } +} + +/// The inner of [`SharedTrieCache`]. +pub(super) struct SharedTrieCacheInner { + node_cache: SharedNodeCache, + value_cache: SharedValueCache, +} + +impl SharedTrieCacheInner { + /// Returns a reference to the [`SharedValueCache`]. + pub(super) fn value_cache(&self) -> &SharedValueCache { + &self.value_cache + } + + /// Returns a mutable reference to the [`SharedValueCache`]. + pub(super) fn value_cache_mut(&mut self) -> &mut SharedValueCache { + &mut self.value_cache + } + + /// Returns a reference to the [`SharedNodeCache`]. + pub(super) fn node_cache(&self) -> &SharedNodeCache { + &self.node_cache + } + + /// Returns a mutable reference to the [`SharedNodeCache`]. + pub(super) fn node_cache_mut(&mut self) -> &mut SharedNodeCache { + &mut self.node_cache + } +} + +/// The shared trie cache. +/// +/// It should be instantiated once per node. It will hold the trie nodes and values of all +/// operations to the state. To not use all available memory it will ensure to stay in the +/// bounds given via the [`CacheSize`] at startup. +/// +/// The instance of this object can be shared between multiple threads. +pub struct SharedTrieCache { + inner: Arc>>, +} + +impl Clone for SharedTrieCache { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +impl SharedTrieCache { + /// Create a new [`SharedTrieCache`]. + pub fn new(cache_size: CacheSize) -> Self { + let (node_cache_size, value_cache_size) = match cache_size { + CacheSize::Maximum(max) => { + // Allocate 20% for the value cache. + let value_cache_size_in_bytes = (max as f32 * 0.20) as usize; + + ( + CacheSize::Maximum(max - value_cache_size_in_bytes), + CacheSize::Maximum(value_cache_size_in_bytes), + ) + }, + CacheSize::Unlimited => (CacheSize::Unlimited, CacheSize::Unlimited), + }; + + Self { + inner: Arc::new(RwLock::new(SharedTrieCacheInner { + node_cache: SharedNodeCache::new(node_cache_size), + value_cache: SharedValueCache::new(value_cache_size), + })), + } + } + + /// Create a new [`LocalTrieCache`](super::LocalTrieCache) instance from this shared cache. + pub fn local_cache(&self) -> super::LocalTrieCache { + super::LocalTrieCache { + shared: self.clone(), + node_cache: Default::default(), + value_cache: Default::default(), + shared_node_cache_access: Default::default(), + shared_value_cache_access: Default::default(), + } + } + + /// Returns the used memory size of this cache in bytes. + pub fn used_memory_size(&self) -> usize { + let inner = self.inner.read(); + let value_cache_size = inner.value_cache.size_in_bytes; + let node_cache_size = inner.node_cache.size_in_bytes; + + node_cache_size + value_cache_size + } + + /// Reset the node cache. + pub fn reset_node_cache(&self) { + self.inner.write().node_cache.reset(); + } + + /// Reset the value cache. + pub fn reset_value_cache(&self) { + self.inner.write().value_cache.reset(); + } + + /// Reset the entire cache. + pub fn reset(&self) { + self.reset_node_cache(); + self.reset_value_cache(); + } + + /// Returns the read locked inner. + pub(super) fn read_lock_inner(&self) -> RwLockReadGuard<'_, SharedTrieCacheInner> { + self.inner.read() + } + + /// Returns the write locked inner. + pub(super) fn write_lock_inner(&self) -> RwLockWriteGuard<'_, SharedTrieCacheInner> { + self.inner.write() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::H256 as Hash; + + #[test] + fn shared_value_cache_works() { + let base_size = mem::size_of::>() + mem::size_of::>(); + let arc_size = mem::size_of::>(); + + let mut cache = SharedValueCache::::new(CacheSize::Maximum( + (base_size + arc_size + 10) * 10, + )); + + let key = vec![0; 10]; + + let root0 = Hash::repeat_byte(1); + let root1 = Hash::repeat_byte(2); + + cache.update( + vec![ + (ValueCacheKey::new_value(&key[..], root0), CachedValue::NonExisting), + (ValueCacheKey::new_value(&key[..], root1), CachedValue::NonExisting), + ], + vec![], + ); + + // Ensure that the basics are working + assert_eq!(1, cache.known_storage_keys.len()); + assert_eq!(3, Arc::strong_count(cache.known_storage_keys.get(&key[..]).unwrap())); + assert_eq!(base_size * 2 + key.len() + arc_size, cache.size_in_bytes); + + // Just accessing a key should not change anything on the size and number of entries. + cache.update(vec![], vec![ValueCacheKey::hash_data(&key[..], &root0)]); + assert_eq!(1, cache.known_storage_keys.len()); + assert_eq!(3, Arc::strong_count(cache.known_storage_keys.get(&key[..]).unwrap())); + assert_eq!(base_size * 2 + key.len() + arc_size, cache.size_in_bytes); + + // Add 9 other entries and this should move out the key for `root1`. + cache.update( + (1..10) + .map(|i| vec![i; 10]) + .map(|key| (ValueCacheKey::new_value(&key[..], root0), CachedValue::NonExisting)), + vec![], + ); + + assert_eq!(10, cache.known_storage_keys.len()); + assert_eq!(2, Arc::strong_count(cache.known_storage_keys.get(&key[..]).unwrap())); + assert_eq!((base_size + key.len() + arc_size) * 10, cache.size_in_bytes); + assert!(matches!( + cache.get(&ValueCacheKey::new_ref(&key, root0)).unwrap(), + CachedValue::::NonExisting + )); + assert!(cache.get(&ValueCacheKey::new_ref(&key, root1)).is_none()); + + cache.update( + vec![(ValueCacheKey::new_value(vec![10; 10], root0), CachedValue::NonExisting)], + vec![], + ); + + assert!(cache.known_storage_keys.get(&key[..]).is_none()); + } + + #[test] + fn value_cache_key_eq_works() { + let storage_key = &b"something"[..]; + let storage_key2 = &b"something2"[..]; + let storage_root = Hash::random(); + + let value = ValueCacheKey::new_value(storage_key, storage_root); + // Ref gets the same hash, but a different storage key + let ref_ = + ValueCacheKey::Ref { storage_root, storage_key: storage_key2, hash: value.get_hash() }; + let hash = ValueCacheKey::Hash { + hash: value.get_hash(), + _i_read_the_documentation: IReadTheDocumentation(()), + }; + + // Ensure that the hash variants is equal to `value`, `ref_` and itself. + assert!(hash == value); + assert!(value == hash); + assert!(hash == ref_); + assert!(ref_ == hash); + assert!(hash == hash); + + // But when we compare `value` and `ref_` the different storage key is detected. + assert!(value != ref_); + assert!(ref_ != value); + } +} diff --git a/primitives/trie/src/error.rs b/primitives/trie/src/error.rs index e0b3642b6db76..a781d408e994f 100644 --- a/primitives/trie/src/error.rs +++ b/primitives/trie/src/error.rs @@ -15,18 +15,33 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Error for trie node decoding. +use sp_std::{boxed::Box, vec::Vec}; + +/// Error type used for trie related errors. #[derive(Debug, PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(thiserror::Error))] -pub enum Error { +pub enum Error { #[cfg_attr(feature = "std", error("Bad format"))] BadFormat, #[cfg_attr(feature = "std", error("Decoding failed: {0}"))] Decode(#[cfg_attr(feature = "std", source)] codec::Error), + #[cfg_attr( + feature = "std", + error("Recorded key ({0:x?}) access with value as found={1}, but could not confirm with trie.") + )] + InvalidRecording(Vec, bool), + #[cfg_attr(feature = "std", error("Trie error: {0:?}"))] + TrieError(Box>), } -impl From for Error { +impl From for Error { fn from(x: codec::Error) -> Self { Error::Decode(x) } } + +impl From>> for Error { + fn from(x: Box>) -> Self { + Error::TrieError(x) + } +} diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index 7a17d44aa5b69..fafa2a2891ce4 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -19,9 +19,13 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "std")] +pub mod cache; mod error; mod node_codec; mod node_header; +#[cfg(feature = "std")] +pub mod recorder; mod storage_proof; mod trie_codec; mod trie_stream; @@ -46,8 +50,8 @@ use trie_db::proof::{generate_proof, verify_proof}; pub use trie_db::{ nibble_ops, node::{NodePlan, ValuePlan}, - CError, DBValue, Query, Recorder, Trie, TrieConfiguration, TrieDBIterator, TrieDBKeyIterator, - TrieLayout, TrieMut, + CError, DBValue, Query, Recorder, Trie, TrieCache, TrieConfiguration, TrieDBIterator, + TrieDBKeyIterator, TrieLayout, TrieMut, TrieRecorder, }; /// The Substrate format implementation of `TrieStream`. pub use trie_stream::TrieStream; @@ -167,11 +171,15 @@ pub type MemoryDB = memory_db::MemoryDB, trie_db::DB pub type GenericMemoryDB = memory_db::MemoryDB; /// Persistent trie database read-access interface for the a given hasher. -pub type TrieDB<'a, L> = trie_db::TrieDB<'a, L>; +pub type TrieDB<'a, 'cache, L> = trie_db::TrieDB<'a, 'cache, L>; +/// Builder for creating a [`TrieDB`]. +pub type TrieDBBuilder<'a, 'cache, L> = trie_db::TrieDBBuilder<'a, 'cache, L>; /// Persistent trie database write-access interface for the a given hasher. pub type TrieDBMut<'a, L> = trie_db::TrieDBMut<'a, L>; +/// Builder for creating a [`TrieDBMut`]. +pub type TrieDBMutBuilder<'a, L> = trie_db::TrieDBMutBuilder<'a, L>; /// Querying interface, as in `trie_db` but less generic. -pub type Lookup<'a, L, Q> = trie_db::Lookup<'a, L, Q>; +pub type Lookup<'a, 'cache, L, Q> = trie_db::Lookup<'a, 'cache, L, Q>; /// Hash type for a trie layout. pub type TrieHash = <::Hash as Hasher>::Out; /// This module is for non generic definition of trie type. @@ -180,18 +188,23 @@ pub mod trie_types { use super::*; /// Persistent trie database read-access interface for the a given hasher. + /// /// Read only V1 and V0 are compatible, thus we always use V1. - pub type TrieDB<'a, H> = super::TrieDB<'a, LayoutV1>; + pub type TrieDB<'a, 'cache, H> = super::TrieDB<'a, 'cache, LayoutV1>; + /// Builder for creating a [`TrieDB`]. + pub type TrieDBBuilder<'a, 'cache, H> = super::TrieDBBuilder<'a, 'cache, LayoutV1>; /// Persistent trie database write-access interface for the a given hasher. pub type TrieDBMutV0<'a, H> = super::TrieDBMut<'a, LayoutV0>; + /// Builder for creating a [`TrieDBMutV0`]. + pub type TrieDBMutBuilderV0<'a, H> = super::TrieDBMutBuilder<'a, LayoutV0>; /// Persistent trie database write-access interface for the a given hasher. pub type TrieDBMutV1<'a, H> = super::TrieDBMut<'a, LayoutV1>; + /// Builder for creating a [`TrieDBMutV1`]. + pub type TrieDBMutBuilderV1<'a, H> = super::TrieDBMutBuilder<'a, LayoutV1>; /// Querying interface, as in `trie_db` but less generic. - pub type LookupV0<'a, H, Q> = trie_db::Lookup<'a, LayoutV0, Q>; - /// Querying interface, as in `trie_db` but less generic. - pub type LookupV1<'a, H, Q> = trie_db::Lookup<'a, LayoutV1, Q>; + pub type Lookup<'a, 'cache, H, Q> = trie_db::Lookup<'a, 'cache, LayoutV1, Q>; /// As in `trie_db`, but less generic, error type for the crate. - pub type TrieError = trie_db::TrieError; + pub type TrieError = trie_db::TrieError>; } /// Create a proof for a subset of keys in a trie. @@ -213,9 +226,7 @@ where K: 'a + AsRef<[u8]>, DB: hash_db::HashDBRef, { - // Can use default layout (read only). - let trie = TrieDB::::new(db, &root)?; - generate_proof(&trie, keys) + generate_proof::<_, L, _, _>(db, &root, keys) } /// Verify a set of key-value pairs against a trie root and a proof. @@ -245,6 +256,8 @@ pub fn delta_trie_root( db: &mut DB, mut root: TrieHash, delta: I, + recorder: Option<&mut dyn trie_db::TrieRecorder>>, + cache: Option<&mut dyn TrieCache>, ) -> Result, Box>> where I: IntoIterator, @@ -254,7 +267,10 @@ where DB: hash_db::HashDB, { { - let mut trie = TrieDBMut::::from_existing(db, &mut root)?; + let mut trie = TrieDBMutBuilder::::from_existing(db, &mut root) + .with_optional_cache(cache) + .with_optional_recorder(recorder) + .build(); let mut delta = delta.into_iter().collect::>(); delta.sort_by(|l, r| l.0.borrow().cmp(r.0.borrow())); @@ -271,33 +287,32 @@ where } /// Read a value from the trie. -pub fn read_trie_value( +pub fn read_trie_value>( db: &DB, root: &TrieHash, key: &[u8], -) -> Result>, Box>> -where - L: TrieConfiguration, - DB: hash_db::HashDBRef, -{ - TrieDB::::new(db, root)?.get(key).map(|x| x.map(|val| val.to_vec())) + recorder: Option<&mut dyn TrieRecorder>>, + cache: Option<&mut dyn TrieCache>, +) -> Result>, Box>> { + TrieDBBuilder::::new(db, root) + .with_optional_cache(cache) + .with_optional_recorder(recorder) + .build() + .get(key) } /// Read a value from the trie with given Query. -pub fn read_trie_value_with( +pub fn read_trie_value_with< + L: TrieLayout, + Q: Query>, + DB: hash_db::HashDBRef, +>( db: &DB, root: &TrieHash, key: &[u8], query: Q, -) -> Result>, Box>> -where - L: TrieConfiguration, - Q: Query, - DB: hash_db::HashDBRef, -{ - TrieDB::::new(db, root)? - .get_with(key, query) - .map(|x| x.map(|val| val.to_vec())) +) -> Result>, Box>> { + TrieDBBuilder::::new(db, root).build().get_with(key, query) } /// Determine the empty trie root. @@ -328,6 +343,8 @@ pub fn child_delta_trie_root( db: &mut DB, root_data: RD, delta: I, + recorder: Option<&mut dyn TrieRecorder>>, + cache: Option<&mut dyn TrieCache>, ) -> Result<::Out, Box>> where I: IntoIterator, @@ -341,46 +358,49 @@ where // root is fetched from DB, not writable by runtime, so it's always valid. root.as_mut().copy_from_slice(root_data.as_ref()); - let mut db = KeySpacedDBMut::new(&mut *db, keyspace); - delta_trie_root::(&mut db, root, delta) + let mut db = KeySpacedDBMut::new(db, keyspace); + delta_trie_root::(&mut db, root, delta, recorder, cache) } -/// Record all keys for a given root. -pub fn record_all_keys( +/// Read a value from the child trie. +pub fn read_child_trie_value( + keyspace: &[u8], db: &DB, root: &TrieHash, - recorder: &mut Recorder>, -) -> Result<(), Box>> + key: &[u8], + recorder: Option<&mut dyn TrieRecorder>>, + cache: Option<&mut dyn TrieCache>, +) -> Result>, Box>> where DB: hash_db::HashDBRef, { - let trie = TrieDB::::new(db, root)?; - let iter = trie.iter()?; - - for x in iter { - let (key, _) = x?; - - // there's currently no API like iter_with() - // => use iter to enumerate all keys AND lookup each - // key using get_with - trie.get_with(&key, &mut *recorder)?; - } - - Ok(()) + let db = KeySpacedDB::new(db, keyspace); + TrieDBBuilder::::new(&db, &root) + .with_optional_recorder(recorder) + .with_optional_cache(cache) + .build() + .get(key) + .map(|x| x.map(|val| val.to_vec())) } -/// Read a value from the child trie. -pub fn read_child_trie_value( +/// Read a hash from the child trie. +pub fn read_child_trie_hash( keyspace: &[u8], db: &DB, root: &TrieHash, key: &[u8], -) -> Result>, Box>> + recorder: Option<&mut dyn TrieRecorder>>, + cache: Option<&mut dyn TrieCache>, +) -> Result>, Box>> where DB: hash_db::HashDBRef, { let db = KeySpacedDB::new(db, keyspace); - TrieDB::::new(&db, root)?.get(key).map(|x| x.map(|val| val.to_vec())) + TrieDBBuilder::::new(&db, &root) + .with_optional_recorder(recorder) + .with_optional_cache(cache) + .build() + .get_hash(key) } /// Read a value from the child trie with given query. @@ -401,20 +421,21 @@ where root.as_mut().copy_from_slice(root_slice); let db = KeySpacedDB::new(db, keyspace); - TrieDB::::new(&db, &root)? + TrieDBBuilder::::new(&db, &root) + .build() .get_with(key, query) .map(|x| x.map(|val| val.to_vec())) } /// `HashDB` implementation that append a encoded prefix (unique id bytes) in addition to the /// prefix of every key value. -pub struct KeySpacedDB<'a, DB, H>(&'a DB, &'a [u8], PhantomData); +pub struct KeySpacedDB<'a, DB: ?Sized, H>(&'a DB, &'a [u8], PhantomData); /// `HashDBMut` implementation that append a encoded prefix (unique id bytes) in addition to the /// prefix of every key value. /// /// Mutable variant of `KeySpacedDB`, see [`KeySpacedDB`]. -pub struct KeySpacedDBMut<'a, DB, H>(&'a mut DB, &'a [u8], PhantomData); +pub struct KeySpacedDBMut<'a, DB: ?Sized, H>(&'a mut DB, &'a [u8], PhantomData); /// Utility function used to merge some byte data (keyspace) and `prefix` data /// before calling key value database primitives. @@ -425,20 +446,14 @@ fn keyspace_as_prefix_alloc(ks: &[u8], prefix: Prefix) -> (Vec, Option) (result, prefix.1) } -impl<'a, DB, H> KeySpacedDB<'a, DB, H> -where - H: Hasher, -{ +impl<'a, DB: ?Sized, H> KeySpacedDB<'a, DB, H> { /// instantiate new keyspaced db pub fn new(db: &'a DB, ks: &'a [u8]) -> Self { KeySpacedDB(db, ks, PhantomData) } } -impl<'a, DB, H> KeySpacedDBMut<'a, DB, H> -where - H: Hasher, -{ +impl<'a, DB: ?Sized, H> KeySpacedDBMut<'a, DB, H> { /// instantiate new keyspaced db pub fn new(db: &'a mut DB, ks: &'a [u8]) -> Self { KeySpacedDBMut(db, ks, PhantomData) @@ -447,7 +462,7 @@ where impl<'a, DB, H, T> hash_db::HashDBRef for KeySpacedDB<'a, DB, H> where - DB: hash_db::HashDBRef, + DB: hash_db::HashDBRef + ?Sized, H: Hasher, T: From<&'static [u8]>, { @@ -550,7 +565,7 @@ mod tests { let persistent = { let mut memdb = MemoryDBMeta::default(); let mut root = Default::default(); - let mut t = TrieDBMut::::new(&mut memdb, &mut root); + let mut t = TrieDBMutBuilder::::new(&mut memdb, &mut root).build(); for (x, y) in input.iter().rev() { t.insert(x, y).unwrap(); } @@ -564,13 +579,13 @@ mod tests { let mut memdb = MemoryDBMeta::default(); let mut root = Default::default(); { - let mut t = TrieDBMut::::new(&mut memdb, &mut root); + let mut t = TrieDBMutBuilder::::new(&mut memdb, &mut root).build(); for (x, y) in input.clone() { t.insert(x, y).unwrap(); } } { - let t = TrieDB::::new(&memdb, &root).unwrap(); + let t = TrieDBBuilder::::new(&memdb, &root).build(); assert_eq!( input.iter().map(|(i, j)| (i.to_vec(), j.to_vec())).collect::>(), t.iter() @@ -592,7 +607,7 @@ mod tests { fn default_trie_root() { let mut db = MemoryDB::default(); let mut root = TrieHash::::default(); - let mut empty = TrieDBMut::::new(&mut db, &mut root); + let mut empty = TrieDBMutBuilder::::new(&mut db, &mut root).build(); empty.commit(); let root1 = empty.root().as_ref().to_vec(); let root2: Vec = LayoutV1::trie_root::<_, Vec, Vec>(std::iter::empty()) @@ -695,15 +710,12 @@ mod tests { check_input(&input); } - fn populate_trie<'db, T>( + fn populate_trie<'db, T: TrieConfiguration>( db: &'db mut dyn HashDB, root: &'db mut TrieHash, v: &[(Vec, Vec)], - ) -> TrieDBMut<'db, T> - where - T: TrieConfiguration, - { - let mut t = TrieDBMut::::new(db, root); + ) -> TrieDBMut<'db, T> { + let mut t = TrieDBMutBuilder::::new(db, root).build(); for i in 0..v.len() { let key: &[u8] = &v[i].0; let val: &[u8] = &v[i].1; @@ -841,7 +853,7 @@ mod tests { let mut root = Default::default(); let _ = populate_trie::(&mut mdb, &mut root, &pairs); - let trie = TrieDB::::new(&mdb, &root).unwrap(); + let trie = TrieDBBuilder::::new(&mdb, &root).build(); let iter = trie.iter().unwrap(); let mut iter_pairs = Vec::new(); @@ -954,12 +966,16 @@ mod tests { &mut proof_db.clone(), storage_root, valid_delta, + None, + None, ) .unwrap(); let second_storage_root = delta_trie_root::( &mut proof_db.clone(), storage_root, invalid_delta, + None, + None, ) .unwrap(); diff --git a/primitives/trie/src/node_codec.rs b/primitives/trie/src/node_codec.rs index bd0ba27483e66..4b3e69adb7041 100644 --- a/primitives/trie/src/node_codec.rs +++ b/primitives/trie/src/node_codec.rs @@ -25,7 +25,7 @@ use sp_std::{borrow::Borrow, marker::PhantomData, ops::Range, vec::Vec}; use trie_db::{ nibble_ops, node::{NibbleSlicePlan, NodeHandlePlan, NodePlan, Value, ValuePlan}, - ChildReference, NodeCodec as NodeCodecT, Partial, + ChildReference, NodeCodec as NodeCodecT, }; /// Helper struct for trie node decoder. This implements `codec::Input` on a byte slice, while @@ -85,7 +85,7 @@ where H: Hasher, { const ESCAPE_HEADER: Option = Some(trie_constants::ESCAPE_COMPACT_HEADER); - type Error = Error; + type Error = Error; type HashOut = H::Out; fn hashed_null_node() -> ::Out { @@ -185,19 +185,19 @@ where &[trie_constants::EMPTY_TRIE] } - fn leaf_node(partial: Partial, value: Value) -> Vec { + fn leaf_node(partial: impl Iterator, number_nibble: usize, value: Value) -> Vec { let contains_hash = matches!(&value, Value::Node(..)); let mut output = if contains_hash { - partial_encode(partial, NodeKind::HashedValueLeaf) + partial_from_iterator_encode(partial, number_nibble, NodeKind::HashedValueLeaf) } else { - partial_encode(partial, NodeKind::Leaf) + partial_from_iterator_encode(partial, number_nibble, NodeKind::Leaf) }; match value { Value::Inline(value) => { Compact(value.len() as u32).encode_to(&mut output); output.extend_from_slice(value); }, - Value::Node(hash, _) => { + Value::Node(hash) => { debug_assert!(hash.len() == H::LENGTH); output.extend_from_slice(hash); }, @@ -244,7 +244,7 @@ where Compact(value.len() as u32).encode_to(&mut output); output.extend_from_slice(value); }, - Some(Value::Node(hash, _)) => { + Some(Value::Node(hash)) => { debug_assert!(hash.len() == H::LENGTH); output.extend_from_slice(hash); }, @@ -295,31 +295,6 @@ fn partial_from_iterator_encode>( output } -/// Encode and allocate node type header (type and size), and partial value. -/// Same as `partial_from_iterator_encode` but uses non encoded `Partial` as input. -fn partial_encode(partial: Partial, node_kind: NodeKind) -> Vec { - let number_nibble_encoded = (partial.0).0 as usize; - let nibble_count = partial.1.len() * nibble_ops::NIBBLE_PER_BYTE + number_nibble_encoded; - - let nibble_count = sp_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibble_count); - - let mut output = Vec::with_capacity(4 + partial.1.len()); - match node_kind { - NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output), - NodeKind::BranchWithValue => NodeHeader::Branch(true, nibble_count).encode_to(&mut output), - NodeKind::BranchNoValue => NodeHeader::Branch(false, nibble_count).encode_to(&mut output), - NodeKind::HashedValueLeaf => - NodeHeader::HashedValueLeaf(nibble_count).encode_to(&mut output), - NodeKind::HashedValueBranch => - NodeHeader::HashedValueBranch(nibble_count).encode_to(&mut output), - }; - if number_nibble_encoded > 0 { - output.push(nibble_ops::pad_right((partial.0).1)); - } - output.extend_from_slice(partial.1); - output -} - const BITMAP_LENGTH: usize = 2; /// Radix 16 trie, bitmap encoding implementation, @@ -329,7 +304,7 @@ const BITMAP_LENGTH: usize = 2; pub(crate) struct Bitmap(u16); impl Bitmap { - pub fn decode(mut data: &[u8]) -> Result { + pub fn decode(mut data: &[u8]) -> Result { Ok(Bitmap(u16::decode(&mut data)?)) } diff --git a/primitives/trie/src/recorder.rs b/primitives/trie/src/recorder.rs new file mode 100644 index 0000000000000..5599ad1c36904 --- /dev/null +++ b/primitives/trie/src/recorder.rs @@ -0,0 +1,284 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Trie recorder +//! +//! Provides an implementation of the [`TrieRecorder`](trie_db::TrieRecorder) trait. It can be used +//! to record storage accesses to the state to generate a [`StorageProof`]. + +use crate::{NodeCodec, StorageProof}; +use codec::Encode; +use hash_db::Hasher; +use parking_lot::Mutex; +use std::{ + collections::HashMap, + marker::PhantomData, + mem, + ops::DerefMut, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }, +}; +use trie_db::{RecordedForKey, TrieAccess}; + +const LOG_TARGET: &str = "trie-recorder"; + +/// The internals of [`Recorder`]. +struct RecorderInner { + /// The keys for that we have recorded the trie nodes and if we have recorded up to the value. + recorded_keys: HashMap, RecordedForKey>, + /// The encoded nodes we accessed while recording. + accessed_nodes: HashMap>, +} + +impl Default for RecorderInner { + fn default() -> Self { + Self { recorded_keys: Default::default(), accessed_nodes: Default::default() } + } +} + +/// The trie recorder. +/// +/// It can be used to record accesses to the trie and then to convert them into a [`StorageProof`]. +pub struct Recorder { + inner: Arc>>, + /// The estimated encoded size of the storage proof this recorder will produce. + /// + /// We store this in an atomic to be able to fetch the value while the `inner` is may locked. + encoded_size_estimation: Arc, +} + +impl Default for Recorder { + fn default() -> Self { + Self { inner: Default::default(), encoded_size_estimation: Arc::new(0.into()) } + } +} + +impl Clone for Recorder { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + encoded_size_estimation: self.encoded_size_estimation.clone(), + } + } +} + +impl Recorder { + /// Returns the recorder as [`TrieRecorder`](trie_db::TrieRecorder) compatible type. + pub fn as_trie_recorder(&self) -> impl trie_db::TrieRecorder + '_ { + TrieRecorder:: { + inner: self.inner.lock(), + encoded_size_estimation: self.encoded_size_estimation.clone(), + _phantom: PhantomData, + } + } + + /// Drain the recording into a [`StorageProof`]. + /// + /// While a recorder can be cloned, all share the same internal state. After calling this + /// function, all other instances will have their internal state reset as well. + /// + /// If you don't want to drain the recorded state, use [`Self::to_storage_proof`]. + /// + /// Returns the [`StorageProof`]. + pub fn drain_storage_proof(self) -> StorageProof { + let mut recorder = mem::take(&mut *self.inner.lock()); + StorageProof::new(recorder.accessed_nodes.drain().map(|(_, v)| v)) + } + + /// Convert the recording to a [`StorageProof`]. + /// + /// In contrast to [`Self::drain_storage_proof`] this doesn't consumes and doesn't clears the + /// recordings. + /// + /// Returns the [`StorageProof`]. + pub fn to_storage_proof(&self) -> StorageProof { + let recorder = self.inner.lock(); + StorageProof::new(recorder.accessed_nodes.iter().map(|(_, v)| v.clone())) + } + + /// Returns the estimated encoded size of the proof. + /// + /// The estimation is based on all the nodes that were accessed until now while + /// accessing the trie. + pub fn estimate_encoded_size(&self) -> usize { + self.encoded_size_estimation.load(Ordering::Relaxed) + } + + /// Reset the state. + /// + /// This discards all recorded data. + pub fn reset(&self) { + mem::take(&mut *self.inner.lock()); + self.encoded_size_estimation.store(0, Ordering::Relaxed); + } +} + +/// The [`TrieRecorder`](trie_db::TrieRecorder) implementation. +struct TrieRecorder { + inner: I, + encoded_size_estimation: Arc, + _phantom: PhantomData, +} + +impl>> trie_db::TrieRecorder + for TrieRecorder +{ + fn record<'b>(&mut self, access: TrieAccess<'b, H::Out>) { + let mut encoded_size_update = 0; + + match access { + TrieAccess::NodeOwned { hash, node_owned } => { + tracing::trace!( + target: LOG_TARGET, + hash = ?hash, + "Recording node", + ); + + self.inner.accessed_nodes.entry(hash).or_insert_with(|| { + let node = node_owned.to_encoded::>(); + + encoded_size_update += node.encoded_size(); + + node + }); + }, + TrieAccess::EncodedNode { hash, encoded_node } => { + tracing::trace!( + target: LOG_TARGET, + hash = ?hash, + "Recording node", + ); + + self.inner.accessed_nodes.entry(hash).or_insert_with(|| { + let node = encoded_node.into_owned(); + + encoded_size_update += node.encoded_size(); + + node + }); + }, + TrieAccess::Value { hash, value, full_key } => { + tracing::trace!( + target: LOG_TARGET, + hash = ?hash, + key = ?sp_core::hexdisplay::HexDisplay::from(&full_key), + "Recording value", + ); + + self.inner.accessed_nodes.entry(hash).or_insert_with(|| { + let value = value.into_owned(); + + encoded_size_update += value.encoded_size(); + + value + }); + + self.inner + .recorded_keys + .entry(full_key.to_vec()) + .and_modify(|e| *e = RecordedForKey::Value) + .or_insert(RecordedForKey::Value); + }, + TrieAccess::Hash { full_key } => { + tracing::trace!( + target: LOG_TARGET, + key = ?sp_core::hexdisplay::HexDisplay::from(&full_key), + "Recorded hash access for key", + ); + + // We don't need to update the `encoded_size_update` as the hash was already + // accounted for by the recorded node that holds the hash. + self.inner + .recorded_keys + .entry(full_key.to_vec()) + .or_insert(RecordedForKey::Hash); + }, + TrieAccess::NonExisting { full_key } => { + tracing::trace!( + target: LOG_TARGET, + key = ?sp_core::hexdisplay::HexDisplay::from(&full_key), + "Recorded non-existing value access for key", + ); + + // Non-existing access means we recorded all trie nodes up to the value. + // Not the actual value, as it doesn't exist, but all trie nodes to know + // that the value doesn't exist in the trie. + self.inner + .recorded_keys + .entry(full_key.to_vec()) + .and_modify(|e| *e = RecordedForKey::Value) + .or_insert(RecordedForKey::Value); + }, + }; + + self.encoded_size_estimation.fetch_add(encoded_size_update, Ordering::Relaxed); + } + + fn trie_nodes_recorded_for_key(&self, key: &[u8]) -> RecordedForKey { + self.inner.recorded_keys.get(key).copied().unwrap_or(RecordedForKey::None) + } +} + +#[cfg(test)] +mod tests { + use trie_db::{Trie, TrieDBBuilder, TrieDBMutBuilder, TrieHash, TrieMut}; + + type MemoryDB = crate::MemoryDB; + type Layout = crate::LayoutV1; + type Recorder = super::Recorder; + + const TEST_DATA: &[(&[u8], &[u8])] = + &[(b"key1", b"val1"), (b"key2", b"val2"), (b"key3", b"val3"), (b"key4", b"val4")]; + + fn create_trie() -> (MemoryDB, TrieHash) { + let mut db = MemoryDB::default(); + let mut root = Default::default(); + + { + let mut trie = TrieDBMutBuilder::::new(&mut db, &mut root).build(); + for (k, v) in TEST_DATA { + trie.insert(k, v).expect("Inserts data"); + } + } + + (db, root) + } + + #[test] + fn recorder_works() { + let (db, root) = create_trie(); + + let recorder = Recorder::default(); + + { + let mut trie_recorder = recorder.as_trie_recorder(); + let trie = TrieDBBuilder::::new(&db, &root) + .with_recorder(&mut trie_recorder) + .build(); + assert_eq!(TEST_DATA[0].1.to_vec(), trie.get(TEST_DATA[0].0).unwrap().unwrap()); + } + + let storage_proof = recorder.drain_storage_proof(); + let memory_db: MemoryDB = storage_proof.into_memory_db(); + + // Check that we recorded the required data + let trie = TrieDBBuilder::::new(&memory_db, &root).build(); + assert_eq!(TEST_DATA[0].1.to_vec(), trie.get(TEST_DATA[0].0).unwrap().unwrap()); + } +} diff --git a/primitives/trie/src/storage_proof.rs b/primitives/trie/src/storage_proof.rs index f6139584dbbad..8fdb04ee20ed0 100644 --- a/primitives/trie/src/storage_proof.rs +++ b/primitives/trie/src/storage_proof.rs @@ -88,7 +88,7 @@ impl StorageProof { pub fn into_compact_proof( self, root: H::Out, - ) -> Result> { + ) -> Result>> { crate::encode_compact::>(self, root) } @@ -130,7 +130,7 @@ impl CompactProof { pub fn to_storage_proof( &self, expected_root: Option<&H::Out>, - ) -> Result<(StorageProof, H::Out), crate::CompactProofError> { + ) -> Result<(StorageProof, H::Out), crate::CompactProofError>> { let mut db = crate::MemoryDB::::new(&[]); let root = crate::decode_compact::, _, _>( &mut db, @@ -157,7 +157,8 @@ impl CompactProof { pub fn to_memory_db( &self, expected_root: Option<&H::Out>, - ) -> Result<(crate::MemoryDB, H::Out), crate::CompactProofError> { + ) -> Result<(crate::MemoryDB, H::Out), crate::CompactProofError>> + { let mut db = crate::MemoryDB::::new(&[]); let root = crate::decode_compact::, _, _>( &mut db, diff --git a/primitives/trie/src/trie_codec.rs b/primitives/trie/src/trie_codec.rs index d29f5a98f31b9..949f9a6e284eb 100644 --- a/primitives/trie/src/trie_codec.rs +++ b/primitives/trie/src/trie_codec.rs @@ -78,7 +78,7 @@ where let mut child_tries = Vec::new(); { // fetch child trie roots - let trie = crate::TrieDB::::new(db, &top_root)?; + let trie = crate::TrieDBBuilder::::new(db, &top_root).build(); let mut iter = trie.iter()?; @@ -159,7 +159,7 @@ where let mut child_tries = Vec::new(); let partial_db = proof.into_memory_db(); let mut compact_proof = { - let trie = crate::TrieDB::::new(&partial_db, &root)?; + let trie = crate::TrieDBBuilder::::new(&partial_db, &root).build(); let mut iter = trie.iter()?; @@ -197,7 +197,7 @@ where continue } - let trie = crate::TrieDB::::new(&partial_db, &child_root)?; + let trie = crate::TrieDBBuilder::::new(&partial_db, &child_root).build(); let child_proof = trie_db::encode_compact::(&trie)?; compact_proof.extend(child_proof); diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 1c2707b3719ad..6cea6282f5bd8 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -41,7 +41,7 @@ pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = ".. sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } sp-trie = { version = "6.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } -trie-db = { version = "0.23.1", default-features = false } +trie-db = { version = "0.24.0", default-features = false } parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } sp-state-machine = { version = "0.12.0", default-features = false, path = "../../primitives/state-machine" } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index e5cfae49da56d..aa436f1ad2a91 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -29,7 +29,10 @@ use sp_std::{marker::PhantomData, prelude::*}; use sp_application_crypto::{ecdsa, ed25519, sr25519, RuntimeAppPublic}; use sp_core::{offchain::KeyTypeId, OpaqueMetadata, RuntimeDebug}; -use sp_trie::{trie_types::TrieDB, PrefixedMemoryDB, StorageProof}; +use sp_trie::{ + trie_types::{TrieDBBuilder, TrieDBMutBuilderV1}, + PrefixedMemoryDB, StorageProof, +}; use trie_db::{Trie, TrieMut}; use cfg_if::cfg_if; @@ -59,8 +62,6 @@ use sp_runtime::{ #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -// bench on latest state. -use sp_trie::trie_types::TrieDBMutV1 as TrieDBMut; // Ensure Babe and Aura use the same crypto to simplify things a bit. pub use sp_consensus_babe::{AllowedSlots, AuthorityId, Slot}; @@ -663,25 +664,19 @@ fn code_using_trie() -> u64 { let mut mdb = PrefixedMemoryDB::default(); let mut root = sp_std::default::Default::default(); - let _ = { - let mut t = TrieDBMut::::new(&mut mdb, &mut root); + { + let mut t = TrieDBMutBuilderV1::::new(&mut mdb, &mut root).build(); for (key, value) in &pairs { if t.insert(key, value).is_err() { return 101 } } - t - }; - - if let Ok(trie) = TrieDB::::new(&mdb, &root) { - if let Ok(iter) = trie.iter() { - iter.flatten().count() as u64 - } else { - 102 - } - } else { - 103 } + + let trie = TrieDBBuilder::::new(&mdb, &root).build(); + let res = if let Ok(iter) = trie.iter() { iter.flatten().count() as u64 } else { 102 }; + + res } impl_opaque_keys! { @@ -1277,7 +1272,7 @@ fn test_read_child_storage() { fn test_witness(proof: StorageProof, root: crate::Hash) { use sp_externalities::Externalities; let db: sp_trie::MemoryDB = proof.into_memory_db(); - let backend = sp_state_machine::TrieBackend::<_, crate::Hashing>::new(db, root); + let backend = sp_state_machine::TrieBackendBuilder::<_, crate::Hashing>::new(db, root).build(); let mut overlay = sp_state_machine::OverlayedChanges::default(); let mut cache = sp_state_machine::StorageTransactionCache::<_, _>::default(); let mut ext = sp_state_machine::Ext::new( @@ -1354,7 +1349,8 @@ mod tests { let mut root = crate::Hash::default(); let mut mdb = sp_trie::MemoryDB::::default(); { - let mut trie = sp_trie::trie_types::TrieDBMutV1::new(&mut mdb, &mut root); + let mut trie = + sp_trie::trie_types::TrieDBMutBuilderV1::new(&mut mdb, &mut root).build(); trie.insert(b"value3", &[142]).expect("insert failed"); trie.insert(b"value4", &[124]).expect("insert failed"); }; @@ -1364,7 +1360,8 @@ mod tests { #[test] fn witness_backend_works() { let (db, root) = witness_backend(); - let backend = sp_state_machine::TrieBackend::<_, crate::Hashing>::new(db, root); + let backend = + sp_state_machine::TrieBackendBuilder::<_, crate::Hashing>::new(db, root).build(); let proof = sp_state_machine::prove_read(backend, vec![b"value3"]).unwrap(); let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build(); diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 96c7a997895d4..6e4f092084ef5 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -93,9 +93,9 @@ impl CliConfiguration for BenchmarkCmd { } } - fn state_cache_size(&self) -> Result { + fn trie_cache_maximum_size(&self) -> Result> { unwrap_cmd! { - self, cmd, cmd.state_cache_size() + self, cmd, cmd.trie_cache_maximum_size() } } diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index 0a92636b151a2..de5e189b40db0 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -96,9 +96,11 @@ pub struct StorageParams { #[clap(long, possible_values = ["0", "1"])] pub state_version: u8, - /// State cache size. - #[clap(long, default_value = "0")] - pub state_cache_size: usize, + /// Trie cache size in bytes. + /// + /// Providing `0` will disable the cache. + #[clap(long, default_value = "1024")] + pub trie_cache_size: usize, /// Include child trees in benchmark. #[clap(long)] @@ -211,7 +213,11 @@ impl CliConfiguration for StorageCmd { Some(&self.pruning_params) } - fn state_cache_size(&self) -> Result { - Ok(self.params.state_cache_size) + fn trie_cache_maximum_size(&self) -> Result> { + if self.params.trie_cache_size == 0 { + Ok(None) + } else { + Ok(Some(self.params.trie_cache_size)) + } } } diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index 0d10ef1b7414d..9a3821a7095f8 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -17,7 +17,7 @@ use sc_cli::Result; use sc_client_api::{Backend as ClientBackend, StorageProvider, UsageProvider}; -use sc_client_db::{DbHash, DbState}; +use sc_client_db::{DbHash, DbState, DbStateBuilder}; use sp_api::StateBackend; use sp_blockchain::HeaderBackend; use sp_database::{ColumnId, Transaction}; @@ -60,7 +60,7 @@ impl StorageCmd { let block = BlockId::Number(client.usage_info().chain.best_number); let header = client.header(block)?.ok_or("Header not found")?; let original_root = *header.state_root(); - let trie = DbState::::new(storage.clone(), original_root); + let trie = DbStateBuilder::::new(storage.clone(), original_root).build(); info!("Preparing keys from block {}", block); // Load all KV pairs and randomly shuffle them. diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 00fdc87a506e8..d45e502df276c 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -23,7 +23,7 @@ sp-io = { path = "../../../../primitives/io" } sp-core = { path = "../../../../primitives/core" } sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } -trie-db = { version = "0.23.1" } +trie-db = "0.24.0" jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } diff --git a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index b6d403ff2fcfd..f9a57206ece4d 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -31,8 +31,11 @@ use sp_core::{ storage::{ChildInfo, ChildType, PrefixedStorageKey}, Hasher, }; -use sp_state_machine::Backend; -use sp_trie::{trie_types::TrieDB, KeySpacedDB, Trie}; +use sp_state_machine::backend::AsTrieBackend; +use sp_trie::{ + trie_types::{TrieDB, TrieDBBuilder}, + KeySpacedDB, Trie, +}; use trie_db::{ node::{NodePlan, ValuePlan}, TrieDBNodeIterator, @@ -41,9 +44,9 @@ use trie_db::{ fn count_migrate<'a, H: Hasher>( storage: &'a dyn trie_db::HashDBRef>, root: &'a H::Out, -) -> std::result::Result<(u64, TrieDB<'a, H>), String> { +) -> std::result::Result<(u64, TrieDB<'a, 'a, H>), String> { let mut nb = 0u64; - let trie = TrieDB::new(storage, root).map_err(|e| format!("TrieDB creation error: {}", e))?; + let trie = TrieDBBuilder::new(storage, root).build(); let iter_node = TrieDBNodeIterator::new(&trie).map_err(|e| format!("TrieDB node iterator error: {}", e))?; for node in iter_node { @@ -68,13 +71,9 @@ pub fn migration_status(backend: &B) -> std::result::Result<(u64, u64), St where H: Hasher, H::Out: codec::Codec, - B: Backend, + B: AsTrieBackend, { - let trie_backend = if let Some(backend) = backend.as_trie_backend() { - backend - } else { - return Err("No access to trie from backend.".to_string()) - }; + let trie_backend = backend.as_trie_backend(); let essence = trie_backend.essence(); let (nb_to_migrate, trie) = count_migrate(essence, essence.root())?; diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index f77f92c625c9d..be7ec923a55bc 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -293,7 +293,7 @@ use sp_runtime::{ traits::{Block as BlockT, NumberFor}, DeserializeOwned, }; -use sp_state_machine::{InMemoryProvingBackend, OverlayedChanges, StateMachine}; +use sp_state_machine::{OverlayedChanges, StateMachine, TrieBackendBuilder}; use std::{fmt::Debug, path::PathBuf, str::FromStr}; mod commands; @@ -746,9 +746,11 @@ pub(crate) fn state_machine_call_with_proof(Into::into)?; - let proof = proving_backend.extract_proof(); + let proof = proving_backend + .extract_proof() + .expect("A recorder was set and thus, a storage proof can be extracted; qed"); let proof_size = proof.encoded_size(); let compact_proof = proof .clone() From a357c29ebabb075235977edd5e3901c66575f995 Mon Sep 17 00:00:00 2001 From: Jake Edwards Date: Fri, 19 Aug 2022 03:03:48 -0500 Subject: [PATCH 1076/1472] Fix broken link to web3 foundation research (#12066) --- frame/staking/reward-curve/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/reward-curve/src/lib.rs b/frame/staking/reward-curve/src/lib.rs index e66f6fde37599..e1ea8aa7b15d5 100644 --- a/frame/staking/reward-curve/src/lib.rs +++ b/frame/staking/reward-curve/src/lib.rs @@ -28,7 +28,7 @@ use syn::parse::{Parse, ParseStream}; /// Accepts a number of expressions to create a instance of PiecewiseLinear which represents the /// NPoS curve (as detailed -/// [here](https://research.web3.foundation/en/latest/polkadot/Token%20Economics.html#inflation-model)) +/// [here](https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html#inflation-model)) /// for those parameters. Parameters are: /// - `min_inflation`: the minimal amount to be rewarded between validators, expressed as a fraction /// of total issuance. Known as `I_0` in the literature. Expressed in millionth, must be between 0 From 90d0247012bfb801b52eafb5c1e592b65ad972bf Mon Sep 17 00:00:00 2001 From: yjh Date: Fri, 19 Aug 2022 16:50:12 +0800 Subject: [PATCH 1077/1472] chore(executor): make allow_missing_host_functions could be configurable (#12015) * make `with_instance` pub * make `allow_missing_host_functions` could be configurable * add method `allow_missing_host_functions` * update usage * update usage * fix comments * fix `with_instance` --- .../manual-seal/src/consensus/timestamp.rs | 4 +- client/executor/src/native_executor.rs | 37 ++++++++++++------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/client/consensus/manual-seal/src/consensus/timestamp.rs b/client/consensus/manual-seal/src/consensus/timestamp.rs index e7f4e709ab996..70b5e5de4ec6c 100644 --- a/client/consensus/manual-seal/src/consensus/timestamp.rs +++ b/client/consensus/manual-seal/src/consensus/timestamp.rs @@ -46,10 +46,10 @@ use std::{ /// This works by either fetching the `slot_number` from the most recent header and dividing /// that value by `slot_duration` in order to fork chains that expect this inherent. /// -/// It produces timestamp inherents that are increaed by `slot_duraation` whenever +/// It produces timestamp inherents that are increased by `slot_duration` whenever /// `provide_inherent_data` is called. pub struct SlotTimestampProvider { - // holds the unix millisecnd timestamp for the most recent block + // holds the unix millisecond timestamp for the most recent block unix_millis: atomic::AtomicU64, // configured slot_duration in the runtime slot_duration: SlotDuration, diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 4d8f559d700b5..7610c4c8f32e0 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -101,7 +101,8 @@ pub struct WasmExecutor { /// The path to a directory which the executor can leverage for a file cache, e.g. put there /// compiled artifacts. cache_path: Option, - + /// Ignore missing function imports. + allow_missing_host_functions: bool, phantom: PhantomData, } @@ -112,6 +113,7 @@ impl Clone for WasmExecutor { default_heap_pages: self.default_heap_pages, cache: self.cache.clone(), cache_path: self.cache_path.clone(), + allow_missing_host_functions: self.allow_missing_host_functions, phantom: self.phantom, } } @@ -153,10 +155,16 @@ where runtime_cache_size, )), cache_path, + allow_missing_host_functions: false, phantom: PhantomData, } } + /// Ignore missing function imports if set true. + pub fn allow_missing_host_functions(&mut self, allow_missing_host_functions: bool) { + self.allow_missing_host_functions = allow_missing_host_functions + } + /// Execute the given closure `f` with the latest runtime (based on `runtime_code`). /// /// The closure `f` is expected to return `Err(_)` when there happened a `panic!` in native code @@ -170,11 +178,10 @@ where /// runtime is invalidated on any `panic!` to prevent a poisoned state. `ext` is already /// implicitly handled as unwind safe, as we store it in a global variable while executing the /// native runtime. - fn with_instance( + pub fn with_instance( &self, runtime_code: &RuntimeCode, ext: &mut dyn Externalities, - allow_missing_host_functions: bool, f: F, ) -> Result where @@ -190,7 +197,7 @@ where ext, self.method, self.default_heap_pages, - allow_missing_host_functions, + self.allow_missing_host_functions, |module, instance, version, ext| { let module = AssertUnwindSafe(module); let instance = AssertUnwindSafe(instance); @@ -353,7 +360,6 @@ where let result = self.with_instance( runtime_code, ext, - false, |module, mut instance, _onchain_version, mut ext| { with_externalities_safe(&mut **ext, move || { preregister_builtin_ext(module.clone()); @@ -374,7 +380,7 @@ where ext: &mut dyn Externalities, runtime_code: &RuntimeCode, ) -> Result { - self.with_instance(runtime_code, ext, false, |_module, _instance, version, _ext| { + self.with_instance(runtime_code, ext, |_module, _instance, version, _ext| { Ok(version.cloned().ok_or_else(|| Error::ApiError("Unknown version".into()))) }) } @@ -387,7 +393,7 @@ where D: NativeExecutionDispatch, { /// Dummy field to avoid the compiler complaining about us not using `D`. - _dummy: std::marker::PhantomData, + _dummy: PhantomData, /// Native runtime version info. native_version: NativeVersion, /// Fallback wasm executor. @@ -414,7 +420,7 @@ impl NativeElseWasmExecutor { max_runtime_instances: usize, runtime_cache_size: u8, ) -> Self { - let wasm_executor = WasmExecutor::new( + let wasm = WasmExecutor::new( fallback_method, default_heap_pages, max_runtime_instances, @@ -425,9 +431,14 @@ impl NativeElseWasmExecutor { NativeElseWasmExecutor { _dummy: Default::default(), native_version: D::native_version(), - wasm: wasm_executor, + wasm, } } + + /// Ignore missing function imports if set true. + pub fn allow_missing_host_functions(&mut self, allow_missing_host_functions: bool) { + self.wasm.allow_missing_host_functions = allow_missing_host_functions + } } impl RuntimeVersionOf for NativeElseWasmExecutor { @@ -436,10 +447,9 @@ impl RuntimeVersionOf for NativeElseWasmExecutor ext: &mut dyn Externalities, runtime_code: &RuntimeCode, ) -> Result { - self.wasm - .with_instance(runtime_code, ext, false, |_module, _instance, version, _ext| { - Ok(version.cloned().ok_or_else(|| Error::ApiError("Unknown version".into()))) - }) + self.wasm.with_instance(runtime_code, ext, |_module, _instance, version, _ext| { + Ok(version.cloned().ok_or_else(|| Error::ApiError("Unknown version".into()))) + }) } } @@ -606,7 +616,6 @@ impl CodeExecutor for NativeElseWasmExecut let result = self.wasm.with_instance( runtime_code, ext, - false, |module, mut instance, onchain_version, mut ext| { let onchain_version = onchain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?; From c76c40ac94c1e66c38af6fcf2dba18e401b125b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 19 Aug 2022 13:07:14 +0200 Subject: [PATCH 1078/1472] Fix benchmarks and adds CI to test them (#12068) * Fix benchmarks and adds CI to test them Instead of waiting for benchmarks failing in Polkadot CI, we also can just test them in Substrate :P * Do not overflow --- client/allocator/src/freeing_bump.rs | 4 ++-- frame/democracy/src/benchmarking.rs | 4 +++- frame/identity/src/benchmarking.rs | 6 ++++-- frame/offences/benchmarking/src/lib.rs | 2 +- frame/proxy/src/benchmarking.rs | 10 +++++++--- scripts/ci/gitlab/pipeline/test.yml | 18 ++++++++++++++++++ .../benchmarking-cli/src/pallet/command.rs | 5 +++++ 7 files changed, 40 insertions(+), 9 deletions(-) diff --git a/client/allocator/src/freeing_bump.rs b/client/allocator/src/freeing_bump.rs index 13dc6dca0dcd6..e81d1b79e74ed 100644 --- a/client/allocator/src/freeing_bump.rs +++ b/client/allocator/src/freeing_bump.rs @@ -331,7 +331,7 @@ pub struct AllocationStats { /// The sum of every allocation ever made. /// /// This increases every time a new allocation is made. - pub bytes_allocated_sum: u32, + pub bytes_allocated_sum: u128, /// The amount of address space (in bytes) used by the allocator. /// @@ -435,7 +435,7 @@ impl FreeingBumpHeapAllocator { Header::Occupied(order).write_into(mem, header_ptr)?; self.stats.bytes_allocated += order.size() + HEADER_SIZE; - self.stats.bytes_allocated_sum += order.size() + HEADER_SIZE; + self.stats.bytes_allocated_sum += u128::from(order.size() + HEADER_SIZE); self.stats.bytes_allocated_peak = std::cmp::max(self.stats.bytes_allocated_peak, self.stats.bytes_allocated); self.stats.address_space_used = self.bumper - self.original_heap_base; diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index 9b275043df43e..d5db82de3840d 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -43,7 +43,9 @@ fn assert_last_event(generic_event: ::Event) { fn funded_account(name: &'static str, index: u32) -> T::AccountId { let caller: T::AccountId = account(name, index, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + // Give the account half of the maximum value of the `Balance` type. + // Otherwise some transfers will fail with an overflow error. + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); caller } diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 20af41d392089..5d409f48bf567 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -120,7 +120,8 @@ benchmarks! { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; ensure!(Registrars::::get().len() as u32 == r, "Registrars not set up correctly."); let origin = T::RegistrarOrigin::successful_origin(); - }: _(origin, account("registrar", r + 1, SEED)) + let account = T::Lookup::unlookup(account("registrar", r + 1, SEED)); + }: _(origin, account) verify { ensure!(Registrars::::get().len() as u32 == r + 1, "Registrars not added."); } @@ -287,7 +288,8 @@ benchmarks! { Identity::::add_registrar(registrar_origin, caller_lookup)?; let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().account == caller, "id not set."); - }: _(RawOrigin::Signed(caller), r, account("new", 0, SEED)) + let new_account = T::Lookup::unlookup(account("new", 0, SEED)); + }: _(RawOrigin::Signed(caller), r, new_account) verify { let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().account == account("new", 0, SEED), "id not changed."); diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index b793bd8d2699a..5d81a71d4c47c 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -305,7 +305,7 @@ benchmarks! { verify { let bond_amount: u32 = UniqueSaturatedInto::::unique_saturated_into(bond_amount::()); let slash_amount = slash_fraction * bond_amount; - let reward_amount = slash_amount * (1 + n) / 2; + let reward_amount = slash_amount.saturating_mul(1 + n) / 2; let reward = reward_amount / r; let slash = |id| core::iter::once( ::Event::from(StakingEvent::::Slashed(id, BalanceOf::::from(slash_amount))) diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index adaaebb0adc98..c01a8da000c09 100644 --- a/frame/proxy/src/benchmarking.rs +++ b/frame/proxy/src/benchmarking.rs @@ -35,9 +35,11 @@ fn add_proxies(n: u32, maybe_who: Option) -> Result<(), let caller = maybe_who.unwrap_or_else(whitelisted_caller); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); for i in 0..n { + let real = T::Lookup::unlookup(account("target", i, SEED)); + Proxy::::add_proxy( RawOrigin::Signed(caller.clone()).into(), - account("target", i, SEED), + real, T::ProxyType::default(), T::BlockNumber::zero(), )?; @@ -180,9 +182,10 @@ benchmarks! { add_proxy { let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); + let real = T::Lookup::unlookup(account("target", T::MaxProxies::get(), SEED)); }: _( RawOrigin::Signed(caller.clone()), - account("target", T::MaxProxies::get(), SEED), + real, T::ProxyType::default(), T::BlockNumber::zero() ) @@ -194,9 +197,10 @@ benchmarks! { remove_proxy { let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); + let delegate = T::Lookup::unlookup(account("target", 0, SEED)); }: _( RawOrigin::Signed(caller.clone()), - account("target", 0, SEED), + delegate, T::ProxyType::default(), T::BlockNumber::zero() ) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index a58015c6e22d6..acd2cb1fa7855 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -277,6 +277,24 @@ test-linux-stable-extra: - time cargo test --doc --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path ./bin/node/cli/Cargo.toml - rusty-cachier cache upload +# This job runs all benchmarks defined in the `/bin/node/runtime` once to check that there are no errors. +quick-benchmarks: + stage: test + extends: + - .docker-env + - .test-refs + variables: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUST_BACKTRACE: "full" + WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + script: + - rusty-cachier snapshot create + - time cargo run --release --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 + - rusty-cachier cache upload + test-frame-examples-compile-to-wasm: # into one job stage: test diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index fb6f1393650ad..0fc7cc4d783f7 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -228,6 +228,11 @@ impl PalletCmd { let mut component_ranges = HashMap::<(Vec, Vec), Vec>::new(); for (pallet, extrinsic, components) in benchmarks_to_run { + log::info!( + "Starting benchmark: {}::{}", + String::from_utf8(pallet.clone()).expect("Encoded from String; qed"), + String::from_utf8(extrinsic.clone()).expect("Encoded from String; qed"), + ); let all_components = if components.is_empty() { vec![Default::default()] } else { From b7d2cb5c2dbfbc49cb3c06f6198daa60b04f16c0 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 19 Aug 2022 15:15:57 +0200 Subject: [PATCH 1079/1472] Revert "Auto-incremental CollectionId (#11796)" (#12059) This reverts commit 7d8e5a1e3979cb0fc61123d5cfeec974dfa25334. Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 4 +- frame/uniques/src/benchmarking.rs | 25 ++--- frame/uniques/src/functions.rs | 15 --- frame/uniques/src/lib.rs | 59 ++--------- frame/uniques/src/tests.rs | 83 +++++---------- frame/uniques/src/weights.rs | 169 +++++++++++++----------------- 6 files changed, 121 insertions(+), 234 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1579c887b8fed..060cd960ee985 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5043,9 +5043,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg", "libm", diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 8aa1512883448..3e3148b5b5fc2 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -42,10 +42,13 @@ fn create_collection, I: 'static>( let caller_lookup = T::Lookup::unlookup(caller.clone()); let collection = T::Helper::collection(0); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - assert!( - Uniques::::force_create(SystemOrigin::Root.into(), caller_lookup.clone(), false,) - .is_ok() - ); + assert!(Uniques::::force_create( + SystemOrigin::Root.into(), + collection, + caller_lookup.clone(), + false, + ) + .is_ok()); (collection, caller, caller_lookup) } @@ -139,7 +142,7 @@ benchmarks_instance_pallet! { whitelist_account!(caller); let admin = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - let call = Call::::create { admin }; + let call = Call::::create { collection, admin }; }: { call.dispatch_bypass_filter(origin)? } verify { assert_last_event::(Event::Created { collection: T::Helper::collection(0), creator: caller.clone(), owner: caller }.into()); @@ -148,7 +151,7 @@ benchmarks_instance_pallet! { force_create { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - }: _(SystemOrigin::Root, caller_lookup, true) + }: _(SystemOrigin::Root, T::Helper::collection(0), caller_lookup, true) verify { assert_last_event::(Event::ForceCreated { collection: T::Helper::collection(0), owner: caller }.into()); } @@ -404,16 +407,6 @@ benchmarks_instance_pallet! { }.into()); } - try_increment_id { - let (_, caller, _) = create_collection::(); - Uniques::::set_next_id(0); - }: _(SystemOrigin::Signed(caller.clone())) - verify { - assert_last_event::(Event::NextCollectionIdIncremented { - next_id: 1u32.into() - }.into()); - } - set_price { let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index e9169bdd963b4..107214558307f 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -88,12 +88,7 @@ impl, I: 'static> Pallet { }, ); - let next_id = collection.saturating_add(1u32.into()); - CollectionAccount::::insert(&owner, &collection, ()); - NextCollectionId::::set(next_id); - - Self::deposit_event(Event::NextCollectionIdIncremented { next_id }); Self::deposit_event(event); Ok(()) } @@ -213,16 +208,6 @@ impl, I: 'static> Pallet { Ok(()) } - #[cfg(any(test, feature = "runtime-benchmarks"))] - pub fn set_next_id(count: u32) { - NextCollectionId::::set(count.into()); - } - - #[cfg(test)] - pub fn get_next_id() -> T::CollectionId { - NextCollectionId::::get() - } - pub fn do_set_price( collection: T::CollectionId, item: T::ItemId, diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index de5a774d16061..70f10ca4f8b39 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -51,7 +51,7 @@ use frame_support::{ }; use frame_system::Config as SystemConfig; use sp_runtime::{ - traits::{AtLeast32BitUnsigned, Saturating, StaticLookup, Zero}, + traits::{Saturating, StaticLookup, Zero}, ArithmeticError, RuntimeDebug, }; use sp_std::prelude::*; @@ -94,12 +94,7 @@ pub mod pallet { type Event: From> + IsType<::Event>; /// Identifier for the collection of item. - type CollectionId: Member - + Parameter - + MaxEncodedLen - + Copy - + Default - + AtLeast32BitUnsigned; + type CollectionId: Member + Parameter + MaxEncodedLen + Copy; /// The type used to identify a unique item within a collection. type ItemId: Member + Parameter + MaxEncodedLen + Copy; @@ -273,12 +268,6 @@ pub mod pallet { pub(super) type CollectionMaxSupply, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::CollectionId, u32, OptionQuery>; - #[pallet::storage] - /// Stores the `CollectionId` that is going to be used for the next collection. - /// This gets incremented by 1 whenever a new collection is created. - pub(super) type NextCollectionId, I: 'static = ()> = - StorageValue<_, T::CollectionId, ValueQuery>; - #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { @@ -370,8 +359,6 @@ pub mod pallet { OwnershipAcceptanceChanged { who: T::AccountId, maybe_collection: Option }, /// Max supply has been set for a collection. CollectionMaxSupplySet { collection: T::CollectionId, max_supply: u32 }, - /// Event gets emmited when the `NextCollectionId` gets incremented. - NextCollectionIdIncremented { next_id: T::CollectionId }, /// The price was set for the instance. ItemPriceSet { collection: T::CollectionId, @@ -423,10 +410,6 @@ pub mod pallet { MaxSupplyAlreadySet, /// The provided max supply is less to the amount of items a collection already has. MaxSupplyTooSmall, - /// The `CollectionId` in `NextCollectionId` is not being used. - /// - /// This means that you can directly proceed to call `create`. - NextIdNotUsed, /// The given item ID is unknown. UnknownItem, /// Item is not for sale. @@ -458,6 +441,7 @@ pub mod pallet { /// `ItemDeposit` funds of sender are reserved. /// /// Parameters: + /// - `collection`: The identifier of the new collection. This must not be currently in use. /// - `admin`: The admin of this collection. The admin is the initial address of each /// member of the collection's admin team. /// @@ -465,9 +449,11 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::create())] - pub fn create(origin: OriginFor, admin: AccountIdLookupOf) -> DispatchResult { - let collection = NextCollectionId::::get(); - + pub fn create( + origin: OriginFor, + collection: T::CollectionId, + admin: AccountIdLookupOf, + ) -> DispatchResult { let owner = T::CreateOrigin::ensure_origin(origin, &collection)?; let admin = T::Lookup::lookup(admin)?; @@ -489,6 +475,7 @@ pub mod pallet { /// /// Unlike `create`, no funds are reserved. /// + /// - `collection`: The identifier of the new item. This must not be currently in use. /// - `owner`: The owner of this collection of items. The owner has full superuser /// permissions /// over this item, but may later change and configure the permissions using @@ -500,14 +487,13 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_create())] pub fn force_create( origin: OriginFor, + collection: T::CollectionId, owner: AccountIdLookupOf, free_holding: bool, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; - let collection = NextCollectionId::::get(); - Self::do_create_collection( collection, owner.clone(), @@ -518,31 +504,6 @@ pub mod pallet { ) } - /// Increments the `CollectionId` stored in `NextCollectionId`. - /// - /// This is only callable when the next `CollectionId` is already being - /// used for some other collection. - /// - /// The origin must be Signed and the sender must have sufficient funds - /// free. - /// - /// Emits `NextCollectionIdIncremented` event when successful. - /// - /// Weight: `O(1)` - #[pallet::weight(T::WeightInfo::try_increment_id())] - pub fn try_increment_id(origin: OriginFor) -> DispatchResult { - ensure_signed(origin)?; - ensure!( - Collection::::contains_key(NextCollectionId::::get()), - Error::::NextIdNotUsed - ); - - let next_id = NextCollectionId::::get().saturating_add(1u32.into()); - NextCollectionId::::set(next_id); - Self::deposit_event(Event::NextCollectionIdIncremented { next_id }); - Ok(()) - } - /// Destroy a collection of fungible items. /// /// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index bd3a2b032945e..8b1d00d7ba0c7 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -92,12 +92,12 @@ fn basic_setup_works() { #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_eq!(collections(), vec![(1, 0)]); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_eq!(items(), vec![(1, 0, 42)]); - assert_ok!(Uniques::force_create(Origin::root(), 2, true)); + assert_ok!(Uniques::force_create(Origin::root(), 1, 2, true)); assert_eq!(collections(), vec![(1, 0), (2, 1)]); assert_ok!(Uniques::mint(Origin::signed(2), 1, 69, 1)); assert_eq!(items(), vec![(1, 0, 42), (1, 1, 69)]); @@ -108,7 +108,7 @@ fn basic_minting_should_work() { fn lifecycle_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::create(Origin::signed(1), 1)); + assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); assert_eq!(Balances::reserved_balance(&1), 2); assert_eq!(collections(), vec![(1, 0)]); assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0, 0], false)); @@ -151,7 +151,7 @@ fn lifecycle_should_work() { fn destroy_with_bad_witness_should_not_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::create(Origin::signed(1), 1)); + assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); let w = Collection::::get(0).unwrap().destroy_witness(); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); @@ -162,7 +162,7 @@ fn destroy_with_bad_witness_should_not_work() { #[test] fn mint_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_eq!(Uniques::owner(0, 42).unwrap(), 1); assert_eq!(collections(), vec![(1, 0)]); @@ -173,7 +173,7 @@ fn mint_should_work() { #[test] fn transfer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 3)); @@ -188,7 +188,7 @@ fn transfer_should_work() { #[test] fn freezing_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_ok!(Uniques::freeze(Origin::signed(1), 0, 42)); assert_noop!(Uniques::transfer(Origin::signed(1), 0, 42, 2), Error::::Frozen); @@ -205,7 +205,7 @@ fn freezing_should_work() { #[test] fn origin_guards_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); Balances::make_free_balance_be(&2, 100); @@ -230,7 +230,7 @@ fn transfer_owner_should_work() { Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); Balances::make_free_balance_be(&3, 100); - assert_ok!(Uniques::create(Origin::signed(1), 1)); + assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); assert_eq!(collections(), vec![(1, 0)]); assert_noop!( Uniques::transfer_ownership(Origin::signed(1), 0, 2), @@ -275,7 +275,7 @@ fn transfer_owner_should_work() { #[test] fn set_team_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4)); assert_ok!(Uniques::mint(Origin::signed(2), 0, 42, 2)); @@ -294,7 +294,7 @@ fn set_collection_metadata_should_work() { Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 20], false), Error::::UnknownCollection, ); - assert_ok!(Uniques::force_create(Origin::root(), 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); // Cannot add metadata to unowned item assert_noop!( Uniques::set_collection_metadata(Origin::signed(2), 0, bvec![0u8; 20], false), @@ -354,7 +354,7 @@ fn set_item_metadata_should_work() { Balances::make_free_balance_be(&1, 30); // Cannot add metadata to unknown item - assert_ok!(Uniques::force_create(Origin::root(), 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); // Cannot add metadata to unowned item assert_noop!( @@ -410,7 +410,7 @@ fn set_attribute_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0])); assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![0])); @@ -455,7 +455,7 @@ fn set_attribute_should_respect_freeze() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0])); assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![0])); @@ -487,7 +487,7 @@ fn force_item_status_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 69, 2)); assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0; 20], false)); @@ -521,7 +521,7 @@ fn force_item_status_should_work() { fn burn_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 1, false)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4)); assert_noop!( @@ -545,7 +545,7 @@ fn burn_works() { #[test] fn approval_lifecycle_works() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); assert_ok!(Uniques::transfer(Origin::signed(3), 0, 42, 4)); @@ -560,7 +560,7 @@ fn approval_lifecycle_works() { #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); @@ -592,7 +592,7 @@ fn cancel_approval_works() { #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); @@ -620,7 +620,7 @@ fn cancel_approval_works_with_admin() { #[test] fn cancel_approval_works_with_force() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); @@ -653,7 +653,7 @@ fn max_supply_should_work() { let max_supply = 2; // validate set_collection_max_supply - assert_ok!(Uniques::force_create(Origin::root(), user_id, true)); + assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true)); assert!(!CollectionMaxSupply::::contains_key(collection_id)); assert_ok!(Uniques::set_collection_max_supply( @@ -695,48 +695,15 @@ fn max_supply_should_work() { }); } -#[test] -fn try_increment_id_works() { - new_test_ext().execute_with(|| { - // should fail because the next `CollectionId` is not being used. - assert_noop!(Uniques::try_increment_id(Origin::signed(2)), Error::::NextIdNotUsed); - - // create two collections & check for events. - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); - assert!(events().contains(&Event::::NextCollectionIdIncremented { next_id: 1 })); - assert_ok!(Uniques::force_create(Origin::root(), 1, true)); - assert!(events().contains(&Event::::NextCollectionIdIncremented { next_id: 2 })); - - // there are now two collections. - assert_eq!(Uniques::get_next_id(), 2); - - // reset the collections counter to test if the `try_increment_id` - // works. - Uniques::set_next_id(0); - assert_ok!(Uniques::try_increment_id(Origin::signed(2))); - - // `try_increment_id` should emit an event when successful. - assert!(events().contains(&Event::::NextCollectionIdIncremented { next_id: 1 })); - - // because reset, the collections count should be now 1 - assert_eq!(Uniques::get_next_id(), 1); - - // increment the collections count again. - assert_ok!(Uniques::try_increment_id(Origin::signed(2))); - // should fail because the next `CollectionId` is not being used. - assert_noop!(Uniques::try_increment_id(Origin::signed(2)), Error::::NextIdNotUsed); - }); -} - #[test] fn set_price_should_work() { new_test_ext().execute_with(|| { let user_id = 1; - let collection_id: u32 = 0; + let collection_id = 0; let item_1 = 1; let item_2 = 2; - assert_ok!(Uniques::force_create(Origin::root(), user_id, true)); + assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true)); assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_1, user_id)); assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_2, user_id)); @@ -788,7 +755,7 @@ fn buy_item_should_work() { let user_1 = 1; let user_2 = 2; let user_3 = 3; - let collection_id: u32 = 0; + let collection_id = 0; let item_1 = 1; let item_2 = 2; let item_3 = 3; @@ -800,7 +767,7 @@ fn buy_item_should_work() { Balances::make_free_balance_be(&user_2, initial_balance); Balances::make_free_balance_be(&user_3, initial_balance); - assert_ok!(Uniques::force_create(Origin::root(), user_1, true)); + assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_1, true)); assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_1, user_1)); assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_2, user_1)); diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 75bb89f26b428..7c8cb170b1b1d 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,12 +18,12 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-07-15, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-07-13, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `test-bench-bot`, CPU: `Intel(R) Xeon(R) CPU @ 3.10GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// target/production/substrate // benchmark // pallet // --steps=50 @@ -70,7 +70,6 @@ pub trait WeightInfo { fn cancel_approval() -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; - fn try_increment_id() -> Weight; fn set_price() -> Weight; fn buy_item() -> Weight; } @@ -78,21 +77,19 @@ pub trait WeightInfo { /// Weights for pallet_uniques using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Uniques NextCollectionId (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (30_481_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (33_075_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - // Storage: Uniques NextCollectionId (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (19_811_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (19_528_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:0) @@ -107,12 +104,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 17_000 - .saturating_add((10_950_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 17_000 - .saturating_add((1_657_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 17_000 - .saturating_add((1_512_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 25_000 + .saturating_add((13_639_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 25_000 + .saturating_add((2_393_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 25_000 + .saturating_add((2_217_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(4 as Weight)) @@ -125,7 +122,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (36_980_000 as Weight) + (42_146_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } @@ -134,7 +131,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - (38_771_000 as Weight) + (42_960_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -143,7 +140,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - (29_914_000 as Weight) + (33_025_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -152,8 +149,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((12_759_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 24_000 + .saturating_add((15_540_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -162,26 +159,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (22_425_000 as Weight) + (25_194_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (23_011_000 as Weight) + (25_397_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (17_718_000 as Weight) + (19_278_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (17_619_000 as Weight) + (19_304_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -189,20 +186,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (25_869_000 as Weight) + (28_615_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (18_058_000 as Weight) + (19_943_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (20_720_000 as Weight) + (22_583_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -210,7 +207,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (41_808_000 as Weight) + (47_520_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -218,76 +215,69 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (39_866_000 as Weight) + (45_316_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (34_767_000 as Weight) + (38_391_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (33_910_000 as Weight) + (38_023_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (33_827_000 as Weight) + (37_398_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (31_998_000 as Weight) + (35_621_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (23_607_000 as Weight) + (25_856_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (23_341_000 as Weight) + (26_098_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (21_969_000 as Weight) + (24_076_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (20_355_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - // Storage: Uniques NextCollectionId (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) - fn try_increment_id() -> Weight { - (19_233_000 as Weight) + (22_035_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - (20_733_000 as Weight) + (22_534_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -296,7 +286,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - (40_798_000 as Weight) + (45_272_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } @@ -304,21 +294,19 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Uniques NextCollectionId (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (30_481_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (33_075_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } - // Storage: Uniques NextCollectionId (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (19_811_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (19_528_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:0) @@ -333,12 +321,12 @@ impl WeightInfo for () { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 17_000 - .saturating_add((10_950_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 17_000 - .saturating_add((1_657_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 17_000 - .saturating_add((1_512_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 25_000 + .saturating_add((13_639_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 25_000 + .saturating_add((2_393_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 25_000 + .saturating_add((2_217_000 as Weight).saturating_mul(a as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) @@ -351,7 +339,7 @@ impl WeightInfo for () { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (36_980_000 as Weight) + (42_146_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } @@ -360,7 +348,7 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - (38_771_000 as Weight) + (42_960_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -369,7 +357,7 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - (29_914_000 as Weight) + (33_025_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } @@ -378,8 +366,8 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((12_759_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 24_000 + .saturating_add((15_540_000 as Weight).saturating_mul(i as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -388,26 +376,26 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (22_425_000 as Weight) + (25_194_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (23_011_000 as Weight) + (25_397_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (17_718_000 as Weight) + (19_278_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (17_619_000 as Weight) + (19_304_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -415,20 +403,20 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (25_869_000 as Weight) + (28_615_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (18_058_000 as Weight) + (19_943_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (20_720_000 as Weight) + (22_583_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -436,7 +424,7 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (41_808_000 as Weight) + (47_520_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } @@ -444,76 +432,69 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (39_866_000 as Weight) + (45_316_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (34_767_000 as Weight) + (38_391_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (33_910_000 as Weight) + (38_023_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (33_827_000 as Weight) + (37_398_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (31_998_000 as Weight) + (35_621_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (23_607_000 as Weight) + (25_856_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (23_341_000 as Weight) + (26_098_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (21_969_000 as Weight) + (24_076_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (20_355_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - } - // Storage: Uniques NextCollectionId (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) - fn try_increment_id() -> Weight { - (19_233_000 as Weight) + (22_035_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - (20_733_000 as Weight) + (22_534_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -522,7 +503,7 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - (40_798_000 as Weight) + (45_272_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } From bd2a876e4c0e79b6e2ab6b0a92c038304a64b20f Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Fri, 19 Aug 2022 18:08:31 +0100 Subject: [PATCH 1080/1472] make weightinfo pub (#12074) --- frame/whitelist/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index 239f0fd280160..5fb4e3aeb9ba6 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -38,6 +38,7 @@ mod mock; #[cfg(test)] mod tests; pub mod weights; +pub use weights::WeightInfo; use codec::{DecodeLimit, Encode, FullCodec}; use frame_support::{ @@ -54,7 +55,6 @@ pub use pallet::*; #[frame_support::pallet] pub mod pallet { use super::*; - use crate::weights::WeightInfo; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; From 28f0cb18c96fb82f810f1d9be69fb609fbb7217e Mon Sep 17 00:00:00 2001 From: Quentin McGaw Date: Sat, 20 Aug 2022 15:40:43 -0400 Subject: [PATCH 1081/1472] Fix comment typo `SS85` -> `SS58` (#12076) --- frame/system/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 12d415e4e2b42..990e3cdd14de1 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -333,7 +333,7 @@ pub mod pallet { type SystemWeightInfo: WeightInfo; - /// The designated SS85 prefix of this chain. + /// The designated SS58 prefix of this chain. /// /// This replaces the "ss58Format" property declared in the chain spec. Reason is /// that the runtime should know about the prefix in order to make use of it as From 1498d867ffc4182d7d82298171d9831e9bbc1d25 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Mon, 22 Aug 2022 16:06:43 +0300 Subject: [PATCH 1082/1472] [contracts] `define_env!` re-write as a proc macro (#11888) * define_env proc macro basics + can_satisfy part ready * expand_impls part done * fix of the &FunctionType bug * pallet is compiled * updated host fn definition syntax * docs comments allowed to host fn definitions * all 53 host funcs re-defined by the new macro * unstable feat fix * cleanup * legacy mbe macros cleaned up * Added Env ident to macro attribute; all tests pass! * \#[v(..)] -> \#[version(..)] * some tiny corrections * save * builds with non-magic rt; tests fail * tests pass * refactored errors + added docs * merge err fixed * fixes on @ascjones review, all except moving away from `pub mod env` syntax * debug printing cleared * clippy fix --- frame/contracts/proc-macro/src/lib.rs | 406 +++- frame/contracts/src/wasm/env_def/macros.rs | 396 ---- frame/contracts/src/wasm/env_def/mod.rs | 3 - frame/contracts/src/wasm/prepare.rs | 27 +- frame/contracts/src/wasm/runtime.rs | 2006 +++++++++++--------- 5 files changed, 1523 insertions(+), 1315 deletions(-) delete mode 100644 frame/contracts/src/wasm/env_def/macros.rs diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index dca29c805cec4..65c13bb1fc607 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -15,16 +15,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Proc macros used in the contracts module. +//! Procedural macroses used in the contracts module. +//! +//! Most likely you should use the [`#[define_env]`][`macro@define_env`] attribute macro which hides +//! boilerplate of defining external environment for a wasm module. #![no_std] extern crate alloc; -use alloc::string::ToString; +use alloc::{ + format, + string::{String, ToString}, + vec::Vec, +}; use proc_macro2::TokenStream; -use quote::{quote, quote_spanned}; -use syn::{parse_macro_input, Data, DeriveInput, Ident}; +use quote::{quote, quote_spanned, ToTokens}; +use syn::{parse_macro_input, spanned::Spanned, Data, DeriveInput, Ident}; /// This derives `Debug` for a struct where each field must be of some numeric type. /// It interprets each field as its represents some weight and formats it as times so that @@ -85,7 +92,7 @@ fn derive_debug( /// This is only used then the `full` feature is activated. #[cfg(feature = "full")] fn iterate_fields(data: &syn::DataStruct, fmt: impl Fn(&Ident) -> TokenStream) -> TokenStream { - use syn::{spanned::Spanned, Fields}; + use syn::Fields; match &data.fields { Fields::Named(fields) => { @@ -140,3 +147,392 @@ fn format_default(field: &Ident) -> TokenStream { &self.#field } } + +/// Parsed environment definition. +struct EnvDef { + host_funcs: Vec, +} + +/// Parsed host function definition. +struct HostFn { + item: syn::ItemFn, + module: String, + name: String, + returns: HostFnReturn, +} + +enum HostFnReturn { + Unit, + U32, + ReturnCode, +} + +impl ToTokens for HostFn { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.item.to_tokens(tokens); + } +} + +impl HostFn { + pub fn try_from(item: syn::Item) -> syn::Result { + let err = |span, msg| { + let msg = format!("Invalid host function definition. {}", msg); + syn::Error::new(span, msg) + }; + let msg = "only #[version()] or #[unstable] attribute is allowed."; + let span = item.span(); + let item = match item { + syn::Item::Fn(i_fn) => Ok(i_fn), + _ => Err(err(span, msg)), + }?; + + let name = item.sig.ident.to_string(); + let attrs: Vec<&syn::Attribute> = + item.attrs.iter().filter(|m| !m.path.is_ident("doc")).collect(); + + let module = match attrs.len() { + 0 => Ok("seal0".to_string()), + 1 => { + let attr = &attrs[0]; + let ident = attr.path.get_ident().ok_or(err(span, msg))?.to_string(); + match ident.as_str() { + "version" => { + let ver: syn::LitInt = attr.parse_args()?; + Ok(format!("seal{}", ver.base10_parse::().map_err(|_| err(span, msg))?)) + }, + "unstable" => Ok("__unstable__".to_string()), + _ => Err(err(span, msg)), + } + }, + _ => Err(err(span, msg)), + }?; + + let msg = r#"Should return one of the following: + - Result<(), TrapReason>, + - Result, + - Result"#; + + let ret_ty = match item.clone().sig.output { + syn::ReturnType::Type(_, ty) => Ok(ty.clone()), + _ => Err(err(span, &msg)), + }?; + + match *ret_ty { + syn::Type::Path(tp) => { + let result = &tp.path.segments.last().ok_or(err(span, &msg))?; + let (id, span) = (result.ident.to_string(), result.ident.span()); + id.eq(&"Result".to_string()).then_some(()).ok_or(err(span, &msg))?; + + match &result.arguments { + syn::PathArguments::AngleBracketed(group) => { + if group.args.len() != 2 { + return Err(err(span, &msg)) + }; + + let arg2 = group.args.last().ok_or(err(span, &msg))?; + + let err_ty = match arg2 { + syn::GenericArgument::Type(ty) => Ok(ty.clone()), + _ => Err(err(arg2.span(), &msg)), + }?; + + match err_ty { + syn::Type::Path(tp) => Ok(tp + .path + .segments + .first() + .ok_or(err(arg2.span(), &msg))? + .ident + .to_string()), + _ => Err(err(tp.span(), &msg)), + }? + .eq("TrapReason") + .then_some(()) + .ok_or(err(span, &msg))?; + + let arg1 = group.args.first().ok_or(err(span, &msg))?; + let ok_ty = match arg1 { + syn::GenericArgument::Type(ty) => Ok(ty.clone()), + _ => Err(err(arg1.span(), &msg)), + }?; + let ok_ty_str = match ok_ty { + syn::Type::Path(tp) => Ok(tp + .path + .segments + .first() + .ok_or(err(arg1.span(), &msg))? + .ident + .to_string()), + syn::Type::Tuple(tt) => { + if !tt.elems.is_empty() { + return Err(err(arg1.span(), &msg)) + }; + Ok("()".to_string()) + }, + _ => Err(err(ok_ty.span(), &msg)), + }?; + + let returns = match ok_ty_str.as_str() { + "()" => Ok(HostFnReturn::Unit), + "u32" => Ok(HostFnReturn::U32), + "ReturnCode" => Ok(HostFnReturn::ReturnCode), + _ => Err(err(arg1.span(), &msg)), + }?; + Ok(Self { item, module, name, returns }) + }, + _ => Err(err(span, &msg)), + } + }, + _ => Err(err(span, &msg)), + } + } + + fn to_wasm_sig(&self) -> TokenStream { + let args = self.item.sig.inputs.iter().skip(1).filter_map(|a| match a { + syn::FnArg::Typed(pt) => Some(&pt.ty), + _ => None, + }); + let returns = match &self.returns { + HostFnReturn::U32 => quote! { vec![ ::VALUE_TYPE ] }, + HostFnReturn::ReturnCode => quote! { vec![ ::VALUE_TYPE ] }, + HostFnReturn::Unit => quote! { vec![] }, + }; + + quote! { + wasm_instrument::parity_wasm::elements::FunctionType::new( + vec! [ #(<#args>::VALUE_TYPE),* ], + #returns, + ) + } + } +} +impl EnvDef { + pub fn try_from(item: syn::ItemMod) -> syn::Result { + let span = item.span(); + let err = |msg| syn::Error::new(span, msg); + let items = &item + .content + .as_ref() + .ok_or(err("Invalid environment definition, expected `mod` to be inlined."))? + .1; + + let host_funcs = items + .iter() + .map(|i| HostFn::try_from(i.clone())) + .collect::, _>>()?; + + Ok(Self { host_funcs }) + } +} + +/// Expands environment definiton. +/// Should generate source code for: +/// - wasm import satisfy checks (see `expand_can_satisfy()`); +/// - implementations of the host functions to be added to the wasm runtime environment (see +/// `expand_impls()`). +fn expand_env(def: &mut EnvDef) -> proc_macro2::TokenStream { + let can_satisfy = expand_can_satisfy(def); + let impls = expand_impls(def); + + quote! { + pub struct Env; + #can_satisfy + #impls + } +} + +/// Generates `can_satisfy()` method for every host function, to be used to check +/// these functions versus expected module, name and signatures when imporing them from a wasm +/// module. +fn expand_can_satisfy(def: &mut EnvDef) -> proc_macro2::TokenStream { + let checks = def.host_funcs.iter().map(|f| { + let (module, name, signature) = (&f.module, &f.name, &f.to_wasm_sig()); + quote! { + if module == #module.as_bytes() + && name == #name.as_bytes() + && signature == &#signature + { + return true; + } + } + }); + let satisfy_checks = quote! { + #( #checks )* + }; + + quote! { + impl crate::wasm::env_def::ImportSatisfyCheck for Env { + fn can_satisfy( + module: &[u8], + name: &[u8], + signature: &wasm_instrument::parity_wasm::elements::FunctionType, + ) -> bool { + use crate::wasm::env_def::ConvertibleToWasm; + #[cfg(not(feature = "unstable-interface"))] + if module == b"__unstable__" { + return false; + } + #satisfy_checks + return false; + } + } + } +} + +/// Generates implementation for every host function, to register it in the contract execution +/// environment. +fn expand_impls(def: &mut EnvDef) -> proc_macro2::TokenStream { + let impls = def.host_funcs.iter().map(|f| { + let params = &f.item.sig.inputs.iter().skip(1).map(|arg| { + match arg { + syn::FnArg::Typed(pt) => { + if let syn::Pat::Ident(ident) = &*pt.pat { + let p_type = &pt.ty; + let p_name = ident.ident.clone(); + quote! { + let #p_name : <#p_type as crate::wasm::env_def::ConvertibleToWasm>::NativeType = + args.next() + .and_then(|v| <#p_type as crate::wasm::env_def::ConvertibleToWasm>::from_typed_value(v.clone())) + .expect( + "precondition: all imports should be checked against the signatures of corresponding + functions defined by `#[define_env]` proc macro by the user of the macro; + thus this can never be `None`; + qed;" + ); + } + } else { quote! { } } + }, + _ => quote! { }, + } + }); + + let outline = match &f.returns { + HostFnReturn::Unit => quote! { + body().map_err(|reason| { + ctx.set_trap_reason(reason); + sp_sandbox::HostError + })?; + return Ok(sp_sandbox::ReturnValue::Unit); + }, + _ => quote! { + let r = body().map_err(|reason| { + ctx.set_trap_reason(reason); + sp_sandbox::HostError + })?; + return Ok(sp_sandbox::ReturnValue::Value({ + r.to_typed_value() + })); + }, + }; + let params = params.clone(); + let (module, name, ident, body) = (&f.module, &f.name, &f.item.sig.ident, &f.item.block); + let unstable_feat = match module.as_str() { + "__unstable__" => quote! { #[cfg(feature = "unstable-interface")] }, + _ => quote! { }, + }; + quote! { + #unstable_feat + f(#module.as_bytes(), #name.as_bytes(), { + fn #ident( + ctx: &mut crate::wasm::Runtime, + args: &[sp_sandbox::Value], + ) -> Result + where + ::AccountId: sp_core::crypto::UncheckedFrom<::Hash> + + AsRef<[u8]>, + { + #[allow(unused)] + let mut args = args.iter(); + let mut body = || { + #( #params )* + #body + }; + #outline + } + #ident:: + }); + } + }); + + let packed_impls = quote! { + #( #impls )* + }; + + quote! { + impl crate::wasm::env_def::FunctionImplProvider for Env + where + ::AccountId: + sp_core::crypto::UncheckedFrom<::Hash> + AsRef<[u8]>, + { + fn impls)>(f: &mut F) { + #packed_impls + } + } + } +} + +/// Defines a host functions set that can be imported by contract wasm code. +/// +/// **NB**: Be advised that all functions defined by this macro +/// will panic if called with unexpected arguments. +/// +/// It's up to you as the user of this macro to check signatures of wasm code to be executed +/// and reject the code if any imported function has a mismatched signature. +/// +/// ## Example +/// +/// ```nocompile +/// #[define_env] +/// pub mod some_env { +/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<(), TrapReason> { +/// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) +/// } +/// } +/// ``` +/// This example will expand to the `some_host_fn()` defined in the wasm module named `seal0`. +/// To define a host function in `seal1` and `__unstable__` modules, it should be annotated with the +/// appropriate attribute as follows: +/// +/// ## Example +/// +/// ```nocompile +/// #[define_env] +/// pub mod some_env { +/// #[version(1)] +/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) +/// } +/// +/// #[unstable] +/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) +/// } +/// } +/// ``` +/// +/// Only following return types are allowed for the host functions defined with the macro: +/// - `Result<(), TrapReason>`, +/// - `Result`, +/// - `Result`. +/// +/// The macro expands to `pub struct Env` declaration, with the following traits implementations: +/// - `pallet_contracts::wasm::env_def::ImportSatisfyCheck` +/// - `pallet_contracts::wasm::env_def::FunctionImplProvider` +#[proc_macro_attribute] +pub fn define_env( + attr: proc_macro::TokenStream, + item: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + if !attr.is_empty() { + let msg = "Invalid `define_env` attribute macro: expected no attributes: `#[define_env]`."; + let span = proc_macro2::TokenStream::from(attr).span(); + return syn::Error::new(span, msg).to_compile_error().into() + } + + let item = syn::parse_macro_input!(item as syn::ItemMod); + + match EnvDef::try_from(item) { + Ok(mut def) => expand_env(&mut def).into(), + Err(e) => e.to_compile_error().into(), + } +} diff --git a/frame/contracts/src/wasm/env_def/macros.rs b/frame/contracts/src/wasm/env_def/macros.rs deleted file mode 100644 index aa5a1626681f4..0000000000000 --- a/frame/contracts/src/wasm/env_def/macros.rs +++ /dev/null @@ -1,396 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Definition of macros that hides boilerplate of defining external environment -//! for a wasm module. -//! -//! Most likely you should use `define_env` macro. - -macro_rules! convert_args { - () => (vec![]); - ( $( $t:ty ),* ) => ( vec![ $( { use $crate::wasm::env_def::ConvertibleToWasm; <$t>::VALUE_TYPE }, )* ] ); -} - -macro_rules! gen_signature { - ( ( $( $params: ty ),* ) ) => ( - { - wasm_instrument::parity_wasm::elements::FunctionType::new( - convert_args!($($params),*), vec![], - ) - } - ); - - ( ( $( $params: ty ),* ) -> $returns: ty ) => ( - { - wasm_instrument::parity_wasm::elements::FunctionType::new( - convert_args!($($params),*), - vec![{use $crate::wasm::env_def::ConvertibleToWasm; <$returns>::VALUE_TYPE}], - ) - } - ); -} - -macro_rules! gen_signature_dispatch { - ( - $needle_module:ident, - $needle_name:ident, - $needle_sig:ident ; - $module:ident, - $name:ident - ( $ctx:ident $( , $names:ident : $params:ty )* ) $( -> $returns:ty )* , $($rest:tt)* - ) => { - let module = stringify!($module).as_bytes(); - if module == $needle_module && stringify!($name).as_bytes() == $needle_name { - let signature = gen_signature!( ( $( $params ),* ) $( -> $returns )* ); - if $needle_sig == &signature { - return true; - } - } else { - gen_signature_dispatch!($needle_module, $needle_name, $needle_sig ; $($rest)*); - } - }; - ( $needle_module:ident, $needle_name:ident, $needle_sig:ident ; ) => {}; -} - -/// Unmarshall arguments and then execute `body` expression and return its result. -macro_rules! unmarshall_then_body { - ( $body:tt, $ctx:ident, $args_iter:ident, $( $names:ident : $params:ty ),* ) => ({ - $( - let $names : <$params as $crate::wasm::env_def::ConvertibleToWasm>::NativeType = - $args_iter.next() - .and_then(|v| <$params as $crate::wasm::env_def::ConvertibleToWasm> - ::from_typed_value(v.clone())) - .expect( - "precondition: all imports should be checked against the signatures of corresponding - functions defined by `define_env!` macro by the user of the macro; - signatures of these functions defined by `$params`; - calls always made with arguments types of which are defined by the corresponding imports; - thus types of arguments should be equal to type list in `$params` and - length of argument list and $params should be equal; - thus this can never be `None`; - qed; - " - ); - )* - $body - }) -} - -/// Since we can't specify the type of closure directly at binding site: -/// -/// ```nocompile -/// let f: FnOnce() -> Result<::NativeType, _> = || { /* ... */ }; -/// ``` -/// -/// we use this function to constrain the type of the closure. -#[inline(always)] -pub fn constrain_closure(f: F) -> F -where - F: FnOnce() -> Result, -{ - f -} - -macro_rules! unmarshall_then_body_then_marshall { - ( $args_iter:ident, $ctx:ident, ( $( $names:ident : $params:ty ),* ) -> $returns:ty => $body:tt ) => ({ - let body = $crate::wasm::env_def::macros::constrain_closure::< - <$returns as $crate::wasm::env_def::ConvertibleToWasm>::NativeType, _ - >(|| { - unmarshall_then_body!($body, $ctx, $args_iter, $( $names : $params ),*) - }); - let r = body().map_err(|reason| { - $ctx.set_trap_reason(reason); - sp_sandbox::HostError - })?; - return Ok(sp_sandbox::ReturnValue::Value({ use $crate::wasm::env_def::ConvertibleToWasm; r.to_typed_value() })) - }); - ( $args_iter:ident, $ctx:ident, ( $( $names:ident : $params:ty ),* ) => $body:tt ) => ({ - let body = $crate::wasm::env_def::macros::constrain_closure::<(), _>(|| { - unmarshall_then_body!($body, $ctx, $args_iter, $( $names : $params ),*) - }); - body().map_err(|reason| { - $ctx.set_trap_reason(reason); - sp_sandbox::HostError - })?; - return Ok(sp_sandbox::ReturnValue::Unit) - }) -} - -macro_rules! define_func { - ( $trait:tt $name:ident ( $ctx: ident $(, $names:ident : $params:ty)*) $(-> $returns:ty)* => $body:tt ) => { - fn $name< E: $trait >( - $ctx: &mut $crate::wasm::Runtime, - args: &[sp_sandbox::Value], - ) -> Result - where - ::AccountId: - sp_core::crypto::UncheckedFrom<::Hash> + - AsRef<[u8]> - { - #[allow(unused)] - let mut args = args.iter(); - - unmarshall_then_body_then_marshall!( - args, - $ctx, - ( $( $names : $params ),* ) $( -> $returns )* => $body - ) - } - }; -} - -macro_rules! register_body { - ( $reg_cb:ident, $trait:tt; - $module:ident $name:ident ( $ctx:ident $( , $names:ident : $params:ty )* ) - $( -> $returns:ty )* => $body:tt - ) => { - $reg_cb( - stringify!($module).as_bytes(), - stringify!($name).as_bytes(), - { - define_func!( - $trait $name ( $ctx $(, $names : $params )* ) $( -> $returns )* => $body - ); - $name:: - } - ); - } -} - -macro_rules! register_func { - ( $reg_cb:ident, $trait:tt; ) => {}; - - ( $reg_cb:ident, $trait:tt; - __unstable__ $name:ident ( $ctx:ident $( , $names:ident : $params:ty )* ) - $( -> $returns:ty )* => $body:tt $($rest:tt)* - ) => { - #[cfg(feature = "unstable-interface")] - register_body!( - $reg_cb, $trait; - __unstable__ $name - ( $ctx $( , $names : $params )* ) - $( -> $returns )* => $body - ); - register_func!( $reg_cb, $trait; $($rest)* ); - }; - - ( $reg_cb:ident, $trait:tt; - $module:ident $name:ident ( $ctx:ident $( , $names:ident : $params:ty )* ) - $( -> $returns:ty )* => $body:tt $($rest:tt)* - ) => { - register_body!( - $reg_cb, $trait; - $module $name - ( $ctx $( , $names : $params )* ) - $( -> $returns )* => $body - ); - register_func!( $reg_cb, $trait; $($rest)* ); - }; -} - -/// Define a function set that can be imported by executing wasm code. -/// -/// **NB**: Be advised that all functions defined by this macro -/// will panic if called with unexpected arguments. -/// -/// It's up to the user of this macro to check signatures of wasm code to be executed -/// and reject the code if any imported function has a mismatched signature. -macro_rules! define_env { - ( $init_name:ident , < E: $trait:tt > , - $( [$module:ident] $name:ident ( $ctx:ident $( , $names:ident : $params:ty )* ) - $( -> $returns:ty )* => $body:tt , )* - ) => { - pub struct $init_name; - - impl $crate::wasm::env_def::ImportSatisfyCheck for $init_name { - fn can_satisfy( - module: &[u8], - name: &[u8], - func_type: &wasm_instrument::parity_wasm::elements::FunctionType, - ) -> bool - { - #[cfg(not(feature = "unstable-interface"))] - if module == b"__unstable__" { - return false; - } - gen_signature_dispatch!( - module, name, func_type ; - $( $module, $name ( $ctx $(, $names : $params )* ) $( -> $returns )* , )* - ); - - return false; - } - } - - impl $crate::wasm::env_def::FunctionImplProvider for $init_name - where - ::AccountId: - sp_core::crypto::UncheckedFrom<::Hash> + - AsRef<[u8]> - { - fn impls)>(f: &mut F) { - register_func!( - f, - $trait; - $( $module $name ( $ctx $( , $names : $params )* ) $( -> $returns)* => $body )* - ); - } - } - }; -} - -#[cfg(test)] -mod tests { - use crate::{ - exec::Ext, - wasm::{runtime::TrapReason, tests::MockExt, Runtime}, - Weight, - }; - use sp_runtime::traits::Zero; - use sp_sandbox::{ReturnValue, Value}; - use wasm_instrument::parity_wasm::elements::{FunctionType, ValueType}; - - struct TestRuntime { - value: u32, - } - - impl TestRuntime { - fn set_trap_reason(&mut self, _reason: TrapReason) {} - } - - #[test] - fn macro_unmarshall_then_body_then_marshall_value_or_trap() { - fn test_value( - _ctx: &mut TestRuntime, - args: &[sp_sandbox::Value], - ) -> Result { - let mut args = args.iter(); - unmarshall_then_body_then_marshall!( - args, - _ctx, - (a: u32, b: u32) -> u32 => { - if b == 0 { - Err(crate::wasm::runtime::TrapReason::Termination) - } else { - Ok(a / b) - } - } - ) - } - - let ctx = &mut TestRuntime { value: 0 }; - assert_eq!( - test_value(ctx, &[Value::I32(15), Value::I32(3)]).unwrap(), - ReturnValue::Value(Value::I32(5)), - ); - assert!(test_value(ctx, &[Value::I32(15), Value::I32(0)]).is_err()); - } - - #[test] - fn macro_unmarshall_then_body_then_marshall_unit() { - fn test_unit( - ctx: &mut TestRuntime, - args: &[sp_sandbox::Value], - ) -> Result { - let mut args = args.iter(); - unmarshall_then_body_then_marshall!( - args, - ctx, - (a: u32, b: u32) => { - ctx.value = a + b; - Ok(()) - } - ) - } - - let ctx = &mut TestRuntime { value: 0 }; - let result = test_unit(ctx, &[Value::I32(2), Value::I32(3)]).unwrap(); - assert_eq!(result, ReturnValue::Unit); - assert_eq!(ctx.value, 5); - } - - #[test] - fn macro_define_func() { - define_func!( Ext seal_gas (_ctx, amount: u32) => { - let amount = Weight::from(amount); - if !amount.is_zero() { - Ok(()) - } else { - Err(TrapReason::Termination) - } - }); - let _f: fn( - &mut Runtime, - &[sp_sandbox::Value], - ) -> Result = seal_gas::; - } - - #[test] - fn macro_gen_signature() { - assert_eq!(gen_signature!((i32)), FunctionType::new(vec![ValueType::I32], vec![])); - - assert_eq!( - gen_signature!( (i32, u32) -> u32 ), - FunctionType::new(vec![ValueType::I32, ValueType::I32], vec![ValueType::I32]), - ); - } - - #[test] - fn macro_unmarshall_then_body() { - let args = vec![Value::I32(5), Value::I32(3)]; - let mut args = args.iter(); - - let ctx: &mut u32 = &mut 0; - - let r = unmarshall_then_body!( - { - *ctx = a + b; - a * b - }, - ctx, - args, - a: u32, - b: u32 - ); - - assert_eq!(*ctx, 8); - assert_eq!(r, 15); - } - - #[test] - fn macro_define_env() { - use crate::wasm::env_def::ImportSatisfyCheck; - - define_env!(Env, , - [seal0] seal_gas( _ctx, amount: u32 ) => { - let amount = Weight::from(amount); - if !amount.is_zero() { - Ok(()) - } else { - Err(crate::wasm::runtime::TrapReason::Termination) - } - }, - ); - - assert!(Env::can_satisfy( - b"seal0", - b"seal_gas", - &FunctionType::new(vec![ValueType::I32], vec![]) - )); - assert!(!Env::can_satisfy(b"seal0", b"not_exists", &FunctionType::new(vec![], vec![]))); - } -} diff --git a/frame/contracts/src/wasm/env_def/mod.rs b/frame/contracts/src/wasm/env_def/mod.rs index c904445f8aea8..be6e688c97868 100644 --- a/frame/contracts/src/wasm/env_def/mod.rs +++ b/frame/contracts/src/wasm/env_def/mod.rs @@ -21,9 +21,6 @@ use crate::exec::Ext; use sp_sandbox::Value; use wasm_instrument::parity_wasm::elements::{FunctionType, ValueType}; -#[macro_use] -pub mod macros; - pub trait ConvertibleToWasm: Sized { const VALUE_TYPE: ValueType; type NativeType; diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index aec5dc2db611d..7b81c1c55b3bd 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -517,6 +517,7 @@ mod tests { schedule::Limits, tests::{Test, ALICE}, }; + use pallet_contracts_proc_macro::define_env; use std::fmt; impl fmt::Debug for PrefabWasmModule { @@ -532,17 +533,27 @@ mod tests { // Define test environment for tests. We need ImportSatisfyCheck // implementation from it. So actual implementations doesn't matter. - define_env!(Test, , - [seal0] panic(_ctx) => { unreachable!(); }, + #[define_env] + pub mod test_env { + fn panic(_ctx: crate::wasm::Runtime) -> Result<(), TrapReason> { + Ok(()) + } // gas is an implementation defined function and a contract can't import it. - [seal0] gas(_ctx, _amount: u32) => { unreachable!(); }, + fn gas(_ctx: crate::wasm::Runtime, _amount: u32) -> Result<(), TrapReason> { + Ok(()) + } - [seal0] nop(_ctx, _unused: u64) => { unreachable!(); }, + fn nop(_ctx: crate::wasm::Runtime, _unused: u64) -> Result<(), TrapReason> { + Ok(()) + } - // new version of nop with other data type for argument - [seal1] nop(_ctx, _unused: i32) => { unreachable!(); }, - ); + // new version of nop with other data type for argumebt + #[version(1)] + fn nop(_ctx: crate::wasm::Runtime, _unused: i32) -> Result<(), TrapReason> { + Ok(()) + } + } } macro_rules! prepare_test { @@ -561,7 +572,7 @@ mod tests { }, .. Default::default() }; - let r = do_preparation::(wasm, &schedule, ALICE); + let r = do_preparation::(wasm, &schedule, ALICE); assert_matches::assert_matches!(r.map_err(|(_, msg)| msg), $($expected)*); } }; diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index f21dc7c76e44c..1d5478a5277cd 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -29,6 +29,7 @@ use bitflags::bitflags; use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight}; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; +use pallet_contracts_proc_macro::define_env; use sp_core::{crypto::UncheckedFrom, Bytes}; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; use sp_runtime::traits::{Bounded, Zero}; @@ -947,183 +948,235 @@ where // Any input that leads to a out of bound error (reading or writing) or failing to decode // data passed to the supervisor will lead to a trap. This is not documented explicitly // for every function. -define_env!(Env, , - // Account for used gas. Traps if gas used is greater than gas limit. - // - // NOTE: This is a implementation defined call and is NOT a part of the public API. - // This call is supposed to be called only by instrumentation injected code. - // - // - amount: How much gas is used. - [seal0] gas(ctx, amount: u32) => { +#[define_env] +pub mod env { + /// Account for used gas. Traps if gas used is greater than gas limit. + /// + /// NOTE: This is a implementation defined call and is NOT a part of the public API. + /// This call is supposed to be called only by instrumentation injected code. + /// + /// - amount: How much gas is used. + fn gas(ctx: Runtime, amount: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::MeteringBlock(amount))?; Ok(()) - }, + } - // Set the value at the given key in the contract storage. - // - // Equivalent to the newer version of `seal_set_storage` with the exception of the return - // type. Still a valid thing to call when not interested in the return value. - [seal0] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) => { + /// Set the value at the given key in the contract storage. + /// + /// Equivalent to the newer version of `seal_set_storage` with the exception of the return + /// type. Still a valid thing to call when not interested in the return value. + fn seal_set_storage( + ctx: Runtime, + key_ptr: u32, + value_ptr: u32, + value_len: u32, + ) -> Result<(), TrapReason> { ctx.set_storage(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) - }, + } - // Set the value at the given key in the contract storage. - // - // This version is to be used with a fixed sized storage key. For runtimes supporting transparent - // hashing, please use the newer version of this function. - // - // The value length must not exceed the maximum defined by the contracts module parameters. - // Specifying a `value_len` of zero will store an empty value. - // - // # Parameters - // - // - `key_ptr`: pointer into the linear memory where the location to store the value is placed. - // - `value_ptr`: pointer into the linear memory where the value to set is placed. - // - `value_len`: the length of the value in bytes. - // - // # Return Value - // - // Returns the size of the pre-existing value at the specified key if any. Otherwise - // `SENTINEL` is returned as a sentinel value. - [seal1] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) -> u32 => { + /// Set the value at the given key in the contract storage. + /// + /// This version is to be used with a fixed sized storage key. For runtimes supporting + /// transparent hashing, please use the newer version of this function. + /// + /// The value length must not exceed the maximum defined by the contracts module parameters. + /// Specifying a `value_len` of zero will store an empty value. + /// + /// # Parameters + /// + /// - `key_ptr`: pointer into the linear memory where the location to store the value is placed. + /// - `value_ptr`: pointer into the linear memory where the value to set is placed. + /// - `value_len`: the length of the value in bytes. + /// + /// # Return Value + /// + /// Returns the size of the pre-existing value at the specified key if any. Otherwise + /// `SENTINEL` is returned as a sentinel value. + #[version(1)] + fn seal_set_storage( + ctx: Runtime, + key_ptr: u32, + value_ptr: u32, + value_len: u32, + ) -> Result { ctx.set_storage(KeyType::Fix, key_ptr, value_ptr, value_len) - }, + } - // Set the value at the given key in the contract storage. - // - // The key and value lengths must not exceed the maximums defined by the contracts module parameters. - // Specifying a `value_len` of zero will store an empty value. - // - // # Parameters - // - // - `key_ptr`: pointer into the linear memory where the location to store the value is placed. - // - `key_len`: the length of the key in bytes. - // - `value_ptr`: pointer into the linear memory where the value to set is placed. - // - `value_len`: the length of the value in bytes. - // - // # Return Value - // - // Returns the size of the pre-existing value at the specified key if any. Otherwise - // `SENTINEL` is returned as a sentinel value. - [__unstable__] seal_set_storage(ctx, key_ptr: u32, key_len: u32, value_ptr: u32, value_len: u32) -> u32 => { + /// Set the value at the given key in the contract storage. + /// + /// The key and value lengths must not exceed the maximums defined by the contracts module + /// parameters. Specifying a `value_len` of zero will store an empty value. + /// + /// # Parameters + /// + /// - `key_ptr`: pointer into the linear memory where the location to store the value is placed. + /// - `key_len`: the length of the key in bytes. + /// - `value_ptr`: pointer into the linear memory where the value to set is placed. + /// - `value_len`: the length of the value in bytes. + /// + /// # Return Value + /// + /// Returns the size of the pre-existing value at the specified key if any. Otherwise + /// `SENTINEL` is returned as a sentinel value. + #[unstable] + fn seal_set_storage( + ctx: Runtime, + key_ptr: u32, + key_len: u32, + value_ptr: u32, + value_len: u32, + ) -> Result { ctx.set_storage(KeyType::Variable(key_len), key_ptr, value_ptr, value_len) - }, + } - // Clear the value at the given key in the contract storage. - // - // Equivalent to the newer version of `seal_clear_storage` with the exception of the return - // type. Still a valid thing to call when not interested in the return value. - [seal0] seal_clear_storage(ctx, key_ptr: u32) => { + /// Clear the value at the given key in the contract storage. + /// + /// Equivalent to the newer version of `seal_clear_storage` with the exception of the return + /// type. Still a valid thing to call when not interested in the return value. + fn seal_clear_storage(ctx: Runtime, key_ptr: u32) -> Result<(), TrapReason> { ctx.clear_storage(KeyType::Fix, key_ptr).map(|_| ()) - }, + } - // Clear the value at the given key in the contract storage. - // - // # Parameters - // - // - `key_ptr`: pointer into the linear memory where the key is placed. - // - `key_len`: the length of the key in bytes. - // - // # Return Value - // - // Returns the size of the pre-existing value at the specified key if any. Otherwise - // `SENTINEL` is returned as a sentinel value. - [__unstable__] seal_clear_storage(ctx, key_ptr: u32, key_len: u32) -> u32 => { + /// Clear the value at the given key in the contract storage. + /// + /// # Parameters + /// + /// - `key_ptr`: pointer into the linear memory where the key is placed. + /// - `key_len`: the length of the key in bytes. + /// + /// # Return Value + /// + /// Returns the size of the pre-existing value at the specified key if any. Otherwise + /// `SENTINEL` is returned as a sentinel value. + #[unstable] + fn seal_clear_storage( + ctx: Runtime, + key_ptr: u32, + key_len: u32, + ) -> Result { ctx.clear_storage(KeyType::Variable(key_len), key_ptr) - }, + } - // Retrieve the value under the given key from storage. - // - // This version is to be used with a fixed sized storage key. For runtimes supporting transparent - // hashing, please use the newer version of this function. - // - // # Parameters - // - // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. - // - `out_ptr`: pointer to the linear memory where the value is written to. - // - `out_len_ptr`: in-out pointer into linear memory where the buffer length - // is read from and the value length is written to. - // - // # Errors - // - // `ReturnCode::KeyNotFound` - [seal0] seal_get_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { + /// Retrieve the value under the given key from storage. + /// + /// This version is to be used with a fixed sized storage key. For runtimes supporting + /// transparent hashing, please use the newer version of this function. + /// + /// # Parameters + /// + /// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. + /// - `out_ptr`: pointer to the linear memory where the value is written to. + /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and + /// the value length is written to. + /// + /// # Errors + /// + /// `ReturnCode::KeyNotFound` + fn seal_get_storage( + ctx: Runtime, + key_ptr: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result { ctx.get_storage(KeyType::Fix, key_ptr, out_ptr, out_len_ptr) - }, + } - // Retrieve the value under the given key from storage. - // - // This version is to be used with a fixed sized storage key. For runtimes supporting transparent - // hashing, please use the newer version of this function. - // - // The key length must not exceed the maximum defined by the contracts module parameter. - // - // # Parameters - // - // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. - // - `key_len`: the length of the key in bytes. - // - `out_ptr`: pointer to the linear memory where the value is written to. - // - `out_len_ptr`: in-out pointer into linear memory where the buffer length - // is read from and the value length is written to. - // - // # Errors - // - // `ReturnCode::KeyNotFound` - [__unstable__] seal_get_storage(ctx, key_ptr: u32, key_len: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { + /// Retrieve the value under the given key from storage. + /// + /// This version is to be used with a fixed sized storage key. For runtimes supporting + /// transparent hashing, please use the newer version of this function. + /// + /// The key length must not exceed the maximum defined by the contracts module parameter. + /// + /// # Parameters + /// + /// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. + /// - `key_len`: the length of the key in bytes. + /// - `out_ptr`: pointer to the linear memory where the value is written to. + /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and + /// the value length is written to. + /// + /// # Errors + /// + /// `ReturnCode::KeyNotFound` + #[unstable] + fn seal_get_storage( + ctx: Runtime, + key_ptr: u32, + key_len: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result { ctx.get_storage(KeyType::Variable(key_len), key_ptr, out_ptr, out_len_ptr) - }, + } - // Checks whether there is a value stored under the given key. - // - // This version is to be used with a fixed sized storage key. For runtimes supporting transparent - // hashing, please use the newer version of this function. - // - // # Parameters - // - // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. - // - // # Return Value - // - // Returns the size of the pre-existing value at the specified key if any. Otherwise - // `SENTINEL` is returned as a sentinel value. - [seal0] seal_contains_storage(ctx, key_ptr: u32) -> u32 => { + /// Checks whether there is a value stored under the given key. + /// + /// This version is to be used with a fixed sized storage key. For runtimes supporting + /// transparent hashing, please use the newer version of this function. + /// + /// # Parameters + /// + /// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. + /// + /// # Return Value + /// + /// Returns the size of the pre-existing value at the specified key if any. Otherwise + /// `SENTINEL` is returned as a sentinel value. + fn seal_contains_storage(ctx: Runtime, key_ptr: u32) -> Result { ctx.contains_storage(KeyType::Fix, key_ptr) - }, + } - // Checks whether there is a value stored under the given key. - // - // The key length must not exceed the maximum defined by the contracts module parameter. - // - // # Parameters - // - // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. - // - `key_len`: the length of the key in bytes. - // - // # Return Value - // - // Returns the size of the pre-existing value at the specified key if any. Otherwise - // `SENTINEL` is returned as a sentinel value. - [__unstable__] seal_contains_storage(ctx, key_ptr: u32, key_len: u32) -> u32 => { + /// Checks whether there is a value stored under the given key. + /// + /// The key length must not exceed the maximum defined by the contracts module parameter. + /// + /// # Parameters + /// + /// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. + /// - `key_len`: the length of the key in bytes. + /// + /// # Return Value + /// + /// Returns the size of the pre-existing value at the specified key if any. Otherwise + /// `SENTINEL` is returned as a sentinel value. + #[unstable] + fn seal_contains_storage( + ctx: Runtime, + key_ptr: u32, + key_len: u32, + ) -> Result { ctx.contains_storage(KeyType::Variable(key_len), key_ptr) - }, + } - // Retrieve and remove the value under the given key from storage. - // - // # Parameters - // - // - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. - // - `key_len`: the length of the key in bytes. - // - `out_ptr`: pointer to the linear memory where the value is written to. - // - `out_len_ptr`: in-out pointer into linear memory where the buffer length - // is read from and the value length is written to. - // - // # Errors - // - // `ReturnCode::KeyNotFound` - [__unstable__] seal_take_storage(ctx, key_ptr: u32, key_len: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { + /// Retrieve and remove the value under the given key from storage. + /// + /// # Parameters + /// + /// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed. + /// - `key_len`: the length of the key in bytes. + /// - `out_ptr`: pointer to the linear memory where the value is written to. + /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and + /// the value length is written to. + /// + /// # Errors + /// + /// `ReturnCode::KeyNotFound` + #[unstable] + fn seal_take_storage( + ctx: Runtime, + key_ptr: u32, + key_len: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result { let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?; let key = ctx.read_sandbox_memory(key_ptr, key_len)?; - if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage_transparent(&VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, None, true)? { + if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage_transparent( + &VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, + None, + true, + )? { ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(value.len() as u32)); ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, already_charged)?; Ok(ReturnCode::Success) @@ -1131,59 +1184,56 @@ define_env!(Env, , ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(0)); Ok(ReturnCode::KeyNotFound) } - }, - - // Transfer some value to another account. - // - // # Parameters - // - // - account_ptr: a pointer to the address of the beneficiary account - // Should be decodable as an `T::AccountId`. Traps otherwise. - // - account_len: length of the address buffer. - // - value_ptr: a pointer to the buffer with value, how much value to send. - // Should be decodable as a `T::Balance`. Traps otherwise. - // - value_len: length of the value buffer. - // - // # Errors - // - // `ReturnCode::TransferFailed` - [seal0] seal_transfer( - ctx, + } + /// Transfer some value to another account. + /// + /// # Parameters + /// + /// - account_ptr: a pointer to the address of the beneficiary account Should be decodable as an + /// `T::AccountId`. Traps otherwise. + /// - account_len: length of the address buffer. + /// - value_ptr: a pointer to the buffer with value, how much value to send. Should be decodable + /// as a `T::Balance`. Traps otherwise. + /// - value_len: length of the value buffer. + /// + /// # Errors + /// + /// `ReturnCode::TransferFailed` + fn seal_transfer( + ctx: Runtime, account_ptr: u32, _account_len: u32, value_ptr: u32, - _value_len: u32 - ) -> ReturnCode => { + _value_len: u32, + ) -> Result { ctx.charge_gas(RuntimeCosts::Transfer)?; let callee: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(account_ptr)?; - let value: BalanceOf<::T> = - ctx.read_sandbox_memory_as(value_ptr)?; - + let value: BalanceOf<::T> = ctx.read_sandbox_memory_as(value_ptr)?; let result = ctx.ext.transfer(&callee, value); match result { Ok(()) => Ok(ReturnCode::Success), Err(err) => { let code = Runtime::::err_into_return_code(err)?; Ok(code) - } + }, } - }, + } - // Make a call to another contract. - // - // # Deprecation - // - // This is equivalent to calling the newer version of this function with - // `flags` set to `ALLOW_REENTRY`. See the newer version for documentation. - // - // # Note - // - // The values `_callee_len` and `_value_len` are ignored because the encoded sizes - // of those types are fixed through `[`MaxEncodedLen`]. The fields exist for backwards - // compatibility. Consider switching to the newest version of this function. - [seal0] seal_call( - ctx, + /// Make a call to another contract. + /// + /// # Deprecation + /// + /// This is equivalent to calling the newer version of this function with + /// `flags` set to `ALLOW_REENTRY`. See the newer version for documentation. + /// + /// # Note + /// + /// The values `_callee_len` and `_value_len` are ignored because the encoded sizes + /// of those types are fixed through `[`MaxEncodedLen`]. The fields exist for backwards + /// compatibility. Consider switching to the newest version of this function. + fn seal_call( + ctx: Runtime, callee_ptr: u32, _callee_len: u32, gas: u64, @@ -1192,49 +1242,50 @@ define_env!(Env, , input_data_ptr: u32, input_data_len: u32, output_ptr: u32, - output_len_ptr: u32 - ) -> ReturnCode => { + output_len_ptr: u32, + ) -> Result { ctx.call( CallFlags::ALLOW_REENTRY, - CallType::Call{callee_ptr, value_ptr, gas}, + CallType::Call { callee_ptr, value_ptr, gas }, input_data_ptr, input_data_len, output_ptr, output_len_ptr, ) - }, + } - // Make a call to another contract. - // - // The callees output buffer is copied to `output_ptr` and its length to `output_len_ptr`. - // The copy of the output buffer can be skipped by supplying the sentinel value - // of `SENTINEL` to `output_ptr`. - // - // # Parameters - // - // - flags: See [`CallFlags`] for a documentation of the supported flags. - // - callee_ptr: a pointer to the address of the callee contract. - // Should be decodable as an `T::AccountId`. Traps otherwise. - // - gas: how much gas to devote to the execution. - // - value_ptr: a pointer to the buffer with value, how much value to send. - // Should be decodable as a `T::Balance`. Traps otherwise. - // - input_data_ptr: a pointer to a buffer to be used as input data to the callee. - // - input_data_len: length of the input data buffer. - // - output_ptr: a pointer where the output buffer is copied to. - // - output_len_ptr: in-out pointer to where the length of the buffer is read from - // and the actual length is written to. - // - // # Errors - // - // An error means that the call wasn't successful output buffer is returned unless - // stated otherwise. - // - // `ReturnCode::CalleeReverted`: Output buffer is returned. - // `ReturnCode::CalleeTrapped` - // `ReturnCode::TransferFailed` - // `ReturnCode::NotCallable` - [seal1] seal_call( - ctx, + /// Make a call to another contract. + /// + /// The callees output buffer is copied to `output_ptr` and its length to `output_len_ptr`. + /// The copy of the output buffer can be skipped by supplying the sentinel value + /// of `SENTINEL` to `output_ptr`. + /// + /// # Parameters + /// + /// - flags: See [`CallFlags`] for a documenation of the supported flags. + /// - callee_ptr: a pointer to the address of the callee contract. Should be decodable as an + /// `T::AccountId`. Traps otherwise. + /// - gas: how much gas to devote to the execution. + /// - value_ptr: a pointer to the buffer with value, how much value to send. Should be decodable + /// as a `T::Balance`. Traps otherwise. + /// - input_data_ptr: a pointer to a buffer to be used as input data to the callee. + /// - input_data_len: length of the input data buffer. + /// - output_ptr: a pointer where the output buffer is copied to. + /// - output_len_ptr: in-out pointer to where the length of the buffer is read from and the + /// actual length is written to. + /// + /// # Errors + /// + /// An error means that the call wasn't successful output buffer is returned unless + /// stated otherwise. + /// + /// `ReturnCode::CalleeReverted`: Output buffer is returned. + /// `ReturnCode::CalleeTrapped` + /// `ReturnCode::TransferFailed` + /// `ReturnCode::NotCallable` + #[version(1)] + fn seal_call( + ctx: Runtime, flags: u32, callee_ptr: u32, gas: u64, @@ -1242,75 +1293,74 @@ define_env!(Env, , input_data_ptr: u32, input_data_len: u32, output_ptr: u32, - output_len_ptr: u32 - ) -> ReturnCode => { + output_len_ptr: u32, + ) -> Result { ctx.call( CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, - CallType::Call{callee_ptr, value_ptr, gas}, + CallType::Call { callee_ptr, value_ptr, gas }, input_data_ptr, input_data_len, output_ptr, output_len_ptr, ) - }, + } - // Execute code in the context (storage, caller, value) of the current contract. - // - // Reentrancy protection is always disabled since the callee is allowed - // to modify the callers storage. This makes going through a reentrancy attack - // unnecessary for the callee when it wants to exploit the caller. - // - // # Parameters - // - // - flags: See [`CallFlags`] for a documentation of the supported flags. - // - code_hash: a pointer to the hash of the code to be called. - // - input_data_ptr: a pointer to a buffer to be used as input data to the callee. - // - input_data_len: length of the input data buffer. - // - output_ptr: a pointer where the output buffer is copied to. - // - output_len_ptr: in-out pointer to where the length of the buffer is read from - // and the actual length is written to. - // - // # Errors - // - // An error means that the call wasn't successful and no output buffer is returned unless - // stated otherwise. - // - // `ReturnCode::CalleeReverted`: Output buffer is returned. - // `ReturnCode::CalleeTrapped` - // `ReturnCode::CodeNotFound` - [seal0] seal_delegate_call( - ctx, + /// Execute code in the context (storage, caller, value) of the current contract. + /// + /// Reentrancy protection is always disabled since the callee is allowed + /// to modify the callers storage. This makes going through a reentrancy attack + /// unnecessary for the callee when it wants to exploit the caller. + /// + /// # Parameters + /// + /// - flags: See [`CallFlags`] for a documentation of the supported flags. + /// - code_hash: a pointer to the hash of the code to be called. + /// - input_data_ptr: a pointer to a buffer to be used as input data to the callee. + /// - input_data_len: length of the input data buffer. + /// - output_ptr: a pointer where the output buffer is copied to. + /// - output_len_ptr: in-out pointer to where the length of the buffer is read from and the + /// actual length is written to. + /// + /// # Errors + /// + /// An error means that the call wasn't successful and no output buffer is returned unless + /// stated otherwise. + /// + /// `ReturnCode::CalleeReverted`: Output buffer is returned. + /// `ReturnCode::CalleeTrapped` + /// `ReturnCode::CodeNotFound` + fn seal_delegate_call( + ctx: Runtime, flags: u32, code_hash_ptr: u32, input_data_ptr: u32, input_data_len: u32, output_ptr: u32, - output_len_ptr: u32 - ) -> ReturnCode => { + output_len_ptr: u32, + ) -> Result { ctx.call( CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, - CallType::DelegateCall{code_hash_ptr}, + CallType::DelegateCall { code_hash_ptr }, input_data_ptr, input_data_len, output_ptr, output_len_ptr, ) - }, - - // Instantiate a contract with the specified code hash. - // - // # Deprecation - // - // This is equivalent to calling the newer version of this function. The newer version - // drops the now unnecessary length fields. - // - // # Note - // - // The values `_code_hash_len` and `_value_len` are ignored because the encoded sizes - // of those types are fixed through `[`MaxEncodedLen`]. The fields exist for backwards - // compatibility. Consider switching to the newest version of this function. - [seal0] seal_instantiate( - ctx, + } + /// Instantiate a contract with the specified code hash. + /// + /// # Deprecation + /// + /// This is equivalent to calling the newer version of this function. The newer version + /// drops the now unnecessary length fields. + /// + /// # Note + /// + /// The values `_code_hash_len` and `_value_len` are ignored because the encoded sizes + /// of those types are fixed through `[`MaxEncodedLen`]. The fields exist for backwards + /// compatibility. Consider switching to the newest version of this function. + fn seal_instantiate( + ctx: Runtime, code_hash_ptr: u32, _code_hash_len: u32, gas: u64, @@ -1323,9 +1373,9 @@ define_env!(Env, , output_ptr: u32, output_len_ptr: u32, salt_ptr: u32, - salt_len: u32 - ) -> ReturnCode => { - ctx.instantiate ( + salt_len: u32, + ) -> Result { + ctx.instantiate( code_hash_ptr, gas, value_ptr, @@ -1338,50 +1388,51 @@ define_env!(Env, , salt_ptr, salt_len, ) - }, + } - // Instantiate a contract with the specified code hash. - // - // This function creates an account and executes the constructor defined in the code specified - // by the code hash. The address of this new account is copied to `address_ptr` and its length - // to `address_len_ptr`. The constructors output buffer is copied to `output_ptr` and its - // length to `output_len_ptr`. The copy of the output buffer and address can be skipped by - // supplying the sentinel value of `SENTINEL` to `output_ptr` or `address_ptr`. - // - // `value` must be at least the minimum balance. Otherwise the instantiation fails and the - // contract is not created. - // - // # Parameters - // - // - code_hash_ptr: a pointer to the buffer that contains the initializer code. - // - gas: how much gas to devote to the execution of the initializer code. - // - value_ptr: a pointer to the buffer with value, how much value to send. - // Should be decodable as a `T::Balance`. Traps otherwise. - // - input_data_ptr: a pointer to a buffer to be used as input data to the initializer code. - // - input_data_len: length of the input data buffer. - // - address_ptr: a pointer where the new account's address is copied to. - // - address_len_ptr: in-out pointer to where the length of the buffer is read from - // and the actual length is written to. - // - output_ptr: a pointer where the output buffer is copied to. - // - output_len_ptr: in-out pointer to where the length of the buffer is read from - // and the actual length is written to. - // - salt_ptr: Pointer to raw bytes used for address derivation. See `fn contract_address`. - // - salt_len: length in bytes of the supplied salt. - // - // # Errors - // - // Please consult the `ReturnCode` enum declaration for more information on those - // errors. Here we only note things specific to this function. - // - // An error means that the account wasn't created and no address or output buffer - // is returned unless stated otherwise. - // - // `ReturnCode::CalleeReverted`: Output buffer is returned. - // `ReturnCode::CalleeTrapped` - // `ReturnCode::TransferFailed` - // `ReturnCode::CodeNotFound` - [seal1] seal_instantiate( - ctx, + /// Instantiate a contract with the specified code hash. + /// + /// This function creates an account and executes the constructor defined in the code specified + /// by the code hash. The address of this new account is copied to `address_ptr` and its length + /// to `address_len_ptr`. The constructors output buffer is copied to `output_ptr` and its + /// length to `output_len_ptr`. The copy of the output buffer and address can be skipped by + /// supplying the sentinel value of `SENTINEL` to `output_ptr` or `address_ptr`. + /// + /// `value` must be at least the minimum balance. Otherwise the instantiation fails and the + /// contract is not created. + /// + /// # Parameters + /// + /// - code_hash_ptr: a pointer to the buffer that contains the initializer code. + /// - gas: how much gas to devote to the execution of the initializer code. + /// - value_ptr: a pointer to the buffer with value, how much value to send. Should be decodable + /// as a `T::Balance`. Traps otherwise. + /// - input_data_ptr: a pointer to a buffer to be used as input data to the initializer code. + /// - input_data_len: length of the input data buffer. + /// - address_ptr: a pointer where the new account's address is copied to. + /// - address_len_ptr: in-out pointer to where the length of the buffer is read from and the + /// actual length is written to. + /// - output_ptr: a pointer where the output buffer is copied to. + /// - output_len_ptr: in-out pointer to where the length of the buffer is read from and the + /// actual length is written to. + /// - salt_ptr: Pointer to raw bytes used for address derivation. See `fn contract_address`. + /// - salt_len: length in bytes of the supplied salt. + /// + /// # Errors + /// + /// Please consult the `ReturnCode` enum declaration for more information on those + /// errors. Here we only note things specific to this function. + /// + /// An error means that the account wasn't created and no address or output buffer + /// is returned unless stated otherwise. + /// + /// `ReturnCode::CalleeReverted`: Output buffer is returned. + /// `ReturnCode::CalleeTrapped` + /// `ReturnCode::TransferFailed` + /// `ReturnCode::CodeNotFound` + #[version(1)] + fn seal_instantiate( + ctx: Runtime, code_hash_ptr: u32, gas: u64, value_ptr: u32, @@ -1392,8 +1443,8 @@ define_env!(Env, , output_ptr: u32, output_len_ptr: u32, salt_ptr: u32, - salt_len: u32 - ) -> ReturnCode => { + salt_len: u32, + ) -> Result { ctx.instantiate( code_hash_ptr, gas, @@ -1407,54 +1458,59 @@ define_env!(Env, , salt_ptr, salt_len, ) - }, + } - // Remove the calling account and transfer remaining balance. - // - // # Deprecation - // - // This is equivalent to calling the newer version of this function. The newer version - // drops the now unnecessary length fields. - // - // # Note - // - // The value `_beneficiary_len` is ignored because the encoded sizes - // this type is fixed through `[`MaxEncodedLen`]. The field exist for backwards - // compatibility. Consider switching to the newest version of this function. - [seal0] seal_terminate(ctx, beneficiary_ptr: u32, _beneficiary_len: u32) => { + /// Remove the calling account and transfer remaining balance. + /// + /// # Deprecation + /// + /// This is equivalent to calling the newer version of this function. The newer version + /// drops the now unnecessary length fields. + /// + /// # Note + /// + /// The value `_beneficiary_len` is ignored because the encoded sizes + /// this type is fixed through `[`MaxEncodedLen`]. The field exist for backwards + /// compatibility. Consider switching to the newest version of this function. + fn seal_terminate( + ctx: Runtime, + beneficiary_ptr: u32, + _beneficiary_len: u32, + ) -> Result<(), TrapReason> { ctx.terminate(beneficiary_ptr) - }, + } - // Remove the calling account and transfer remaining **free** balance. - // - // This function never returns. Either the termination was successful and the - // execution of the destroyed contract is halted. Or it failed during the termination - // which is considered fatal and results in a trap + rollback. - // - // - beneficiary_ptr: a pointer to the address of the beneficiary account where all - // where all remaining funds of the caller are transferred. - // Should be decodable as an `T::AccountId`. Traps otherwise. - // - // # Traps - // - // - The contract is live i.e is already on the call stack. - // - Failed to send the balance to the beneficiary. - // - The deletion queue is full. - [seal1] seal_terminate(ctx, beneficiary_ptr: u32) => { + /// Remove the calling account and transfer remaining **free** balance. + /// + /// This function never returns. Either the termination was successful and the + /// execution of the destroyed contract is halted. Or it failed during the termination + /// which is considered fatal and results in a trap + rollback. + /// + /// - beneficiary_ptr: a pointer to the address of the beneficiary account where all where all + /// remaining funds of the caller are transferred. Should be decodable as an `T::AccountId`. + /// Traps otherwise. + /// + /// # Traps + /// + /// - The contract is live i.e is already on the call stack. + /// - Failed to send the balance to the beneficiary. + /// - The deletion queue is full. + #[version(1)] + fn seal_terminate(ctx: Runtime, beneficiary_ptr: u32) -> Result<(), TrapReason> { ctx.terminate(beneficiary_ptr) - }, + } - // Stores the input passed by the caller into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - // - // # Note - // - // This function traps if the input was previously forwarded by a `seal_call`. - [seal0] seal_input(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Stores the input passed by the caller into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// + /// # Note + /// + /// This function traps if the input was previously forwarded by a `seal_call`. + fn seal_input(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::InputBase)?; if let Some(input) = ctx.input_data.take() { ctx.write_sandbox_output(out_ptr, out_len_ptr, &input, false, |len| { @@ -1465,300 +1521,402 @@ define_env!(Env, , } else { Err(Error::::InputForwarded.into()) } - }, + } - // Cease contract execution and save a data buffer as a result of the execution. - // - // This function never returns as it stops execution of the caller. - // This is the only way to return a data buffer to the caller. Returning from - // execution without calling this function is equivalent to calling: - // ``` - // seal_return(0, 0, 0); - // ``` - // - // The flags argument is a bitfield that can be used to signal special return - // conditions to the supervisor: - // --- lsb --- - // bit 0 : REVERT - Revert all storage changes made by the caller. - // bit [1, 31]: Reserved for future use. - // --- msb --- - // - // Using a reserved bit triggers a trap. - [seal0] seal_return(ctx, flags: u32, data_ptr: u32, data_len: u32) => { + /// Cease contract execution and save a data buffer as a result of the execution. + /// + /// This function never returns as it stops execution of the caller. + /// This is the only way to return a data buffer to the caller. Returning from + /// execution without calling this function is equivalent to calling: + /// ``` + /// seal_return(0, 0, 0); + /// ``` + /// + /// The flags argument is a bitfield that can be used to signal special return + /// conditions to the supervisor: + /// --- lsb --- + /// bit 0 : REVERT - Revert all storage changes made by the caller. + /// bit [1, 31]: Reserved for future use. + /// --- msb --- + /// + /// Using a reserved bit triggers a trap. + fn seal_return( + ctx: Runtime, + flags: u32, + data_ptr: u32, + data_len: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Return(data_len))?; Err(TrapReason::Return(ReturnData { flags, data: ctx.read_sandbox_memory(data_ptr, data_len)?, })) - }, + } - // Stores the address of the caller into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - // - // If this is a top-level call (i.e. initiated by an extrinsic) the origin address of the - // extrinsic will be returned. Otherwise, if this call is initiated by another contract then the - // address of the contract will be returned. The value is encoded as T::AccountId. - [seal0] seal_caller(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Stores the address of the caller into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// + /// If this is a top-level call (i.e. initiated by an extrinsic) the origin address of the + /// extrinsic will be returned. Otherwise, if this call is initiated by another contract then + /// the address of the contract will be returned. The value is encoded as T::AccountId. + fn seal_caller(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Caller)?; Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.caller().encode(), false, already_charged + out_ptr, + out_len_ptr, + &ctx.ext.caller().encode(), + false, + already_charged, )?) - }, + } - // Checks whether a specified address belongs to a contract. - // - // # Parameters - // - // - account_ptr: a pointer to the address of the beneficiary account - // Should be decodable as an `T::AccountId`. Traps otherwise. - // - // Returned value is a u32-encoded boolean: (0 = false, 1 = true). - [seal0] seal_is_contract(ctx, account_ptr: u32) -> u32 => { + /// Checks whether a specified address belongs to a contract. + /// + /// # Parameters + /// + /// - account_ptr: a pointer to the address of the beneficiary account Should be decodable as an + /// `T::AccountId`. Traps otherwise. + /// + /// Returned value is a u32-encoded boolean: (0 = false, 1 = true). + fn seal_is_contract(ctx: Runtime, account_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::IsContract)?; let address: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(account_ptr)?; Ok(ctx.ext.is_contract(&address) as u32) - }, + } - // Retrieve the code hash for a specified contract address. - // - // # Parameters - // - // - `account_ptr`: a pointer to the address in question. - // Should be decodable as an `T::AccountId`. Traps otherwise. - // - `out_ptr`: pointer to the linear memory where the returning value is written to. - // - `out_len_ptr`: in-out pointer into linear memory where the buffer length - // is read from and the value length is written to. - // - // # Errors - // - // `ReturnCode::KeyNotFound` - [seal0] seal_code_hash(ctx, account_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { + /// Retrieve the code hash for a specified contract address. + /// + /// # Parameters + /// + /// - `account_ptr`: a pointer to the address in question. Should be decodable as an + /// `T::AccountId`. Traps otherwise. + /// - `out_ptr`: pointer to the linear memory where the returning value is written to. + /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and + /// the value length is written to. + /// + /// # Errors + /// + /// `ReturnCode::KeyNotFound` + fn seal_code_hash( + ctx: Runtime, + account_ptr: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result { ctx.charge_gas(RuntimeCosts::CodeHash)?; let address: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(account_ptr)?; if let Some(value) = ctx.ext.code_hash(&address) { - ctx.write_sandbox_output(out_ptr, out_len_ptr, &value.encode(), false, already_charged)?; + ctx.write_sandbox_output( + out_ptr, + out_len_ptr, + &value.encode(), + false, + already_charged, + )?; Ok(ReturnCode::Success) } else { Ok(ReturnCode::KeyNotFound) } - }, + } - // Retrieve the code hash of the currently executing contract. - // - // # Parameters - // - // - `out_ptr`: pointer to the linear memory where the returning value is written to. - // - `out_len_ptr`: in-out pointer into linear memory where the buffer length - // is read from and the value length is written to. - [seal0] seal_own_code_hash(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Retrieve the code hash of the currently executing contract. + /// + /// # Parameters + /// + /// - `out_ptr`: pointer to the linear memory where the returning value is written to. + /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and + /// the value length is written to. + fn seal_own_code_hash( + ctx: Runtime, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::OwnCodeHash)?; let code_hash_encoded = &ctx.ext.own_code_hash().encode(); - Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, code_hash_encoded, false, already_charged)?) - }, + Ok(ctx.write_sandbox_output( + out_ptr, + out_len_ptr, + code_hash_encoded, + false, + already_charged, + )?) + } - // Checks whether the caller of the current contract is the origin of the whole call stack. - // - // Prefer this over `seal_is_contract` when checking whether your contract is being called by a contract - // or a plain account. The reason is that it performs better since it does not need to - // do any storage lookups. - // - // A return value of`true` indicates that this contract is being called by a plain account - // and `false` indicates that the caller is another contract. - // - // Returned value is a u32-encoded boolean: (0 = false, 1 = true). - [seal0] seal_caller_is_origin(ctx) -> u32 => { + /// Checks whether the caller of the current contract is the origin of the whole call stack. + /// + /// Prefer this over `seal_is_contract` when checking whether your contract is being called by a + /// contract or a plain account. The reason is that it performs better since it does not need to + /// do any storage lookups. + /// + /// A return value of`true` indicates that this contract is being called by a plain account + /// and `false` indicates that the caller is another contract. + /// + /// Returned value is a u32-encoded boolean: (0 = false, 1 = true). + fn seal_caller_is_origin(ctx: Runtime) -> Result { ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?; Ok(ctx.ext.caller_is_origin() as u32) - }, + } - // Stores the address of the current contract into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - [seal0] seal_address(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Stores the address of the current contract into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + fn seal_address( + ctx: Runtime, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Address)?; Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.address().encode(), false, already_charged + out_ptr, + out_len_ptr, + &ctx.ext.address().encode(), + false, + already_charged, )?) - }, + } - // Stores the price for the specified amount of gas into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - // - // The data is encoded as T::Balance. - // - // # Note - // - // It is recommended to avoid specifying very small values for `gas` as the prices for a single - // gas can be smaller than one. - [seal0] seal_weight_to_fee(ctx, gas: u64, out_ptr: u32, out_len_ptr: u32) => { + /// Stores the price for the specified amount of gas into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// + /// The data is encoded as T::Balance. + /// + /// # Note + /// + /// It is recommended to avoid specifying very small values for `gas` as the prices for a single + /// gas can be smaller than one. + fn seal_weight_to_fee( + ctx: Runtime, + gas: u64, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::WeightToFee)?; Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.get_weight_price(gas).encode(), false, already_charged + out_ptr, + out_len_ptr, + &ctx.ext.get_weight_price(gas).encode(), + false, + already_charged, )?) - }, + } - // Stores the amount of gas left into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - // - // The data is encoded as Gas. - [seal0] seal_gas_left(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Stores the amount of gas left into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// + /// The data is encoded as Gas. + fn seal_gas_left( + ctx: Runtime, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::GasLeft)?; let gas_left = &ctx.ext.gas_meter().gas_left().encode(); - Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, gas_left, false, already_charged, - )?) - }, - - // Stores the **free* balance of the current account into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - // - // The data is encoded as T::Balance. - [seal0] seal_balance(ctx, out_ptr: u32, out_len_ptr: u32) => { + Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, gas_left, false, already_charged)?) + } + + /// Stores the **free* balance of the current account into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// + /// The data is encoded as T::Balance. + fn seal_balance( + ctx: Runtime, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Balance)?; Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.balance().encode(), false, already_charged + out_ptr, + out_len_ptr, + &ctx.ext.balance().encode(), + false, + already_charged, )?) - }, + } - // Stores the value transferred along with this call/instantiate into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - // - // The data is encoded as T::Balance. - [seal0] seal_value_transferred(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Stores the value transferred along with this call/instantiate into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// + /// The data is encoded as T::Balance. + fn seal_value_transferred( + ctx: Runtime, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::ValueTransferred)?; Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.value_transferred().encode(), false, already_charged + out_ptr, + out_len_ptr, + &ctx.ext.value_transferred().encode(), + false, + already_charged, )?) - }, + } - // Stores a random number for the current block and the given subject into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - // - // The data is encoded as T::Hash. - // - // # Deprecation - // - // This function is deprecated. Users should migrate to the version in the "seal1" module. - [seal0] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => { + /// Stores a random number for the current block and the given subject into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// + /// The data is encoded as T::Hash. + /// + /// # Deprecation + /// + /// This function is deprecated. Users should migrate to the version in the "seal1" module. + fn seal_random( + ctx: Runtime, + subject_ptr: u32, + subject_len: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Random)?; if subject_len > ctx.ext.schedule().limits.subject_len { - return Err(Error::::RandomSubjectTooLong.into()); + return Err(Error::::RandomSubjectTooLong.into()) } let subject_buf = ctx.read_sandbox_memory(subject_ptr, subject_len)?; Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.random(&subject_buf).0.encode(), false, already_charged + out_ptr, + out_len_ptr, + &ctx.ext.random(&subject_buf).0.encode(), + false, + already_charged, )?) - }, + } - // Stores a random number for the current block and the given subject into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - // - // The data is encoded as (T::Hash, T::BlockNumber). - // - // # Changes from v0 - // - // In addition to the seed it returns the block number since which it was determinable - // by chain observers. - // - // # Note - // - // The returned seed should only be used to distinguish commitments made before - // the returned block number. If the block number is too early (i.e. commitments were - // made afterwards), then ensure no further commitments may be made and repeatedly - // call this on later blocks until the block number returned is later than the latest - // commitment. - [seal1] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => { + /// Stores a random number for the current block and the given subject into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// + /// The data is encoded as (T::Hash, T::BlockNumber). + /// + /// # Changes from v0 + /// + /// In addition to the seed it returns the block number since which it was determinable + /// by chain observers. + /// + /// # Note + /// + /// The returned seed should only be used to distinguish commitments made before + /// the returned block number. If the block number is too early (i.e. commitments were + /// made afterwards), then ensure no further commitments may be made and repeatedly + /// call this on later blocks until the block number returned is later than the latest + /// commitment. + #[version(1)] + fn seal_random( + ctx: Runtime, + subject_ptr: u32, + subject_len: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Random)?; if subject_len > ctx.ext.schedule().limits.subject_len { - return Err(Error::::RandomSubjectTooLong.into()); + return Err(Error::::RandomSubjectTooLong.into()) } let subject_buf = ctx.read_sandbox_memory(subject_ptr, subject_len)?; Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.random(&subject_buf).encode(), false, already_charged + out_ptr, + out_len_ptr, + &ctx.ext.random(&subject_buf).encode(), + false, + already_charged, )?) - }, + } - // Load the latest block timestamp into the supplied buffer - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - [seal0] seal_now(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Load the latest block timestamp into the supplied buffer + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + fn seal_now(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Now)?; Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.now().encode(), false, already_charged + out_ptr, + out_len_ptr, + &ctx.ext.now().encode(), + false, + already_charged, )?) - }, + } - // Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. - // - // The data is encoded as T::Balance. - [seal0] seal_minimum_balance(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. + /// + /// The data is encoded as T::Balance. + fn seal_minimum_balance( + ctx: Runtime, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::MinimumBalance)?; Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.minimum_balance().encode(), false, already_charged + out_ptr, + out_len_ptr, + &ctx.ext.minimum_balance().encode(), + false, + already_charged, )?) - }, + } - // Stores the tombstone deposit into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - // - // # Deprecation - // - // There is no longer a tombstone deposit. This function always returns 0. - [seal0] seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Stores the tombstone deposit into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + /// + /// # Deprecation + /// + /// There is no longer a tombstone deposit. This function always returns 0. + fn seal_tombstone_deposit( + ctx: Runtime, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Balance)?; let deposit = >::zero().encode(); Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, &deposit, false, already_charged)?) - }, + } - // Was used to restore the given destination contract sacrificing the caller. - // - // # Note - // - // The state rent functionality was removed. This is stub only exists for - // backwards compatibility - [seal0] seal_restore_to( - ctx, + /// Was used to restore the given destination contract sacrificing the caller. + /// + /// # Note + /// + /// The state rent functionality was removed. This is stub only exists for + /// backwards compatiblity + fn seal_restore_to( + ctx: Runtime, _dest_ptr: u32, _dest_len: u32, _code_hash_ptr: u32, @@ -1766,45 +1924,46 @@ define_env!(Env, , _rent_allowance_ptr: u32, _rent_allowance_len: u32, _delta_ptr: u32, - _delta_count: u32 - ) => { + _delta_count: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::DebugMessage)?; Ok(()) - }, + } - // Was used to restore the given destination contract sacrificing the caller. - // - // # Note - // - // The state rent functionality was removed. This is stub only exists for - // backwards compatibility - [seal1] seal_restore_to( - ctx, + /// Was used to restore the given destination contract sacrificing the caller. + /// + /// # Note + /// + /// The state rent functionality was removed. This is stub only exists for + /// backwards compatiblity + #[version(1)] + fn seal_restore_to( + ctx: Runtime, _dest_ptr: u32, _code_hash_ptr: u32, _rent_allowance_ptr: u32, _delta_ptr: u32, - _delta_count: u32 - ) => { + _delta_count: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::DebugMessage)?; Ok(()) - }, + } - // Deposit a contract event with the data buffer and optional list of topics. There is a limit - // on the maximum number of topics specified by `event_topics`. - // - // - topics_ptr - a pointer to the buffer of topics encoded as `Vec`. The value of this - // is ignored if `topics_len` is set to 0. The topics list can't contain duplicates. - // - topics_len - the length of the topics buffer. Pass 0 if you want to pass an empty vector. - // - data_ptr - a pointer to a raw data buffer which will saved along the event. - // - data_len - the length of the data buffer. - [seal0] seal_deposit_event( - ctx, + /// Deposit a contract event with the data buffer and optional list of topics. There is a limit + /// on the maximum number of topics specified by `event_topics`. + /// + /// - topics_ptr - a pointer to the buffer of topics encoded as `Vec`. The value of + /// this is ignored if `topics_len` is set to 0. The topics list can't contain duplicates. + /// - topics_len - the length of the topics buffer. Pass 0 if you want to pass an empty vector. + /// - data_ptr - a pointer to a raw data buffer which will saved along the event. + /// - data_len - the length of the data buffer. + fn seal_deposit_event( + ctx: Runtime, topics_ptr: u32, topics_len: u32, data_ptr: u32, - data_len: u32 - ) => { + data_len: u32, + ) -> Result<(), TrapReason> { fn has_duplicates(items: &mut Vec) -> bool { // # Warning // @@ -1812,40 +1971,35 @@ define_env!(Env, , // because we are rejecting duplicates which removes the non determinism. items.sort_unstable(); // Find any two consecutive equal elements. - items.windows(2).any(|w| { - match &w { - &[a, b] => a == b, - _ => false, - } + items.windows(2).any(|w| match &w { + &[a, b] => a == b, + _ => false, }) } let num_topic = topics_len .checked_div(sp_std::mem::size_of::>() as u32) .ok_or("Zero sized topics are not allowed")?; - ctx.charge_gas(RuntimeCosts::DepositEvent { - num_topic, - len: data_len, - })?; + ctx.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?; if data_len > ctx.ext.max_value_size() { - return Err(Error::::ValueTooLarge.into()); + return Err(Error::::ValueTooLarge.into()) } - let mut topics: Vec::::T>> = match topics_len { + let mut topics: Vec::T>> = match topics_len { 0 => Vec::new(), _ => ctx.read_sandbox_memory_as_unbounded(topics_ptr, topics_len)?, }; // If there are more than `event_topics`, then trap. if topics.len() > ctx.ext.schedule().limits.event_topics as usize { - return Err(Error::::TooManyTopics.into()); + return Err(Error::::TooManyTopics.into()) } // Check for duplicate topics. If there are any, then trap. // Complexity O(n * log(n)) and no additional allocations. // This also sorts the topics. if has_duplicates(&mut topics) { - return Err(Error::::DuplicateTopics.into()); + return Err(Error::::DuplicateTopics.into()) } let event_data = ctx.read_sandbox_memory(data_ptr, data_len)?; @@ -1853,179 +2007,208 @@ define_env!(Env, , ctx.ext.deposit_event(topics, event_data); Ok(()) - }, + } - // Was used to set rent allowance of the contract. - // - // # Note - // - // The state rent functionality was removed. This is stub only exists for - // backwards compatibility. - [seal0] seal_set_rent_allowance(ctx, _value_ptr: u32, _value_len: u32) => { + /// Was used to set rent allowance of the contract. + /// + /// # Note + /// + /// The state rent functionality was removed. This is stub only exists for + /// backwards compatiblity. + fn seal_set_rent_allowance( + ctx: Runtime, + _value_ptr: u32, + _value_len: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::DebugMessage)?; Ok(()) - }, + } - // Was used to set rent allowance of the contract. - // - // # Note - // - // The state rent functionality was removed. This is stub only exists for - // backwards compatibility. - [seal1] seal_set_rent_allowance(ctx, _value_ptr: u32) => { + /// Was used to set rent allowance of the contract. + /// + /// # Note + /// + /// The state rent functionality was removed. This is stub only exists for + /// backwards compatiblity. + #[version(1)] + fn seal_set_rent_allowance(ctx: Runtime, _value_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::DebugMessage)?; Ok(()) - }, + } - // Was used to store the rent allowance into the supplied buffer. - // - // # Note - // - // The state rent functionality was removed. This is stub only exists for - // backwards compatibility. - [seal0] seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Was used to store the rent allowance into the supplied buffer. + /// + /// # Note + /// + /// The state rent functionality was removed. This is stub only exists for + /// backwards compatiblity. + fn seal_rent_allowance( + ctx: Runtime, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Balance)?; let rent_allowance = >::max_value().encode(); Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &rent_allowance, false, already_charged + out_ptr, + out_len_ptr, + &rent_allowance, + false, + already_charged, )?) - }, + } - // Stores the current block number of the current contract into the supplied buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // `out_len_ptr` must point to a u32 value that describes the available space at - // `out_ptr`. This call overwrites it with the size of the value. If the available - // space at `out_ptr` is less than the size of the value a trap is triggered. - [seal0] seal_block_number(ctx, out_ptr: u32, out_len_ptr: u32) => { + /// Stores the current block number of the current contract into the supplied buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_ptr`. This call overwrites it with the size of the value. If the available + /// space at `out_ptr` is less than the size of the value a trap is triggered. + fn seal_block_number( + ctx: Runtime, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::BlockNumber)?; Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.block_number().encode(), false, already_charged + out_ptr, + out_len_ptr, + &ctx.ext.block_number().encode(), + false, + already_charged, )?) - }, + } - // Computes the SHA2 256-bit hash on the given input buffer. - // - // Returns the result directly into the given output buffer. - // - // # Note - // - // - The `input` and `output` buffer may overlap. - // - The output buffer is expected to hold at least 32 bytes (256 bits). - // - It is the callers responsibility to provide an output buffer that - // is large enough to hold the expected amount of bytes returned by the - // chosen hash function. - // - // # Parameters - // - // - `input_ptr`: the pointer into the linear memory where the input - // data is placed. - // - `input_len`: the length of the input data in bytes. - // - `output_ptr`: the pointer into the linear memory where the output - // data is placed. The function will write the result - // directly into this buffer. - [seal0] seal_hash_sha2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { + /// Computes the SHA2 256-bit hash on the given input buffer. + /// + /// Returns the result directly into the given output buffer. + /// + /// # Note + /// + /// - The `input` and `output` buffer may overlap. + /// - The output buffer is expected to hold at least 32 bytes (256 bits). + /// - It is the callers responsibility to provide an output buffer that is large enough to hold + /// the expected amount of bytes returned by the chosen hash function. + /// + /// # Parameters + /// + /// - `input_ptr`: the pointer into the linear memory where the input data is placed. + /// - `input_len`: the length of the input data in bytes. + /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The + /// function will write the result directly into this buffer. + fn seal_hash_sha2_256( + ctx: Runtime, + input_ptr: u32, + input_len: u32, + output_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::HashSha256(input_len))?; Ok(ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr)?) - }, + } - // Computes the KECCAK 256-bit hash on the given input buffer. - // - // Returns the result directly into the given output buffer. - // - // # Note - // - // - The `input` and `output` buffer may overlap. - // - The output buffer is expected to hold at least 32 bytes (256 bits). - // - It is the callers responsibility to provide an output buffer that - // is large enough to hold the expected amount of bytes returned by the - // chosen hash function. - // - // # Parameters - // - // - `input_ptr`: the pointer into the linear memory where the input - // data is placed. - // - `input_len`: the length of the input data in bytes. - // - `output_ptr`: the pointer into the linear memory where the output - // data is placed. The function will write the result - // directly into this buffer. - [seal0] seal_hash_keccak_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { + /// Computes the KECCAK 256-bit hash on the given input buffer. + /// + /// Returns the result directly into the given output buffer. + /// + /// # Note + /// + /// - The `input` and `output` buffer may overlap. + /// - The output buffer is expected to hold at least 32 bytes (256 bits). + /// - It is the callers responsibility to provide an output buffer that is large enough to hold + /// the expected amount of bytes returned by the chosen hash function. + /// + /// # Parameters + /// + /// - `input_ptr`: the pointer into the linear memory where the input data is placed. + /// - `input_len`: the length of the input data in bytes. + /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The + /// function will write the result directly into this buffer. + fn seal_hash_keccak_256( + ctx: Runtime, + input_ptr: u32, + input_len: u32, + output_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::HashKeccak256(input_len))?; Ok(ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr)?) - }, + } - // Computes the BLAKE2 256-bit hash on the given input buffer. - // - // Returns the result directly into the given output buffer. - // - // # Note - // - // - The `input` and `output` buffer may overlap. - // - The output buffer is expected to hold at least 32 bytes (256 bits). - // - It is the callers responsibility to provide an output buffer that - // is large enough to hold the expected amount of bytes returned by the - // chosen hash function. - // - // # Parameters - // - // - `input_ptr`: the pointer into the linear memory where the input - // data is placed. - // - `input_len`: the length of the input data in bytes. - // - `output_ptr`: the pointer into the linear memory where the output - // data is placed. The function will write the result - // directly into this buffer. - [seal0] seal_hash_blake2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { + /// Computes the BLAKE2 256-bit hash on the given input buffer. + /// + /// Returns the result directly into the given output buffer. + /// + /// # Note + /// + /// - The `input` and `output` buffer may overlap. + /// - The output buffer is expected to hold at least 32 bytes (256 bits). + /// - It is the callers responsibility to provide an output buffer that is large enough to hold + /// the expected amount of bytes returned by the chosen hash function. + /// + /// # Parameters + /// + /// - `input_ptr`: the pointer into the linear memory where the input data is placed. + /// - `input_len`: the length of the input data in bytes. + /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The + /// function will write the result directly into this buffer. + fn seal_hash_blake2_256( + ctx: Runtime, + input_ptr: u32, + input_len: u32, + output_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::HashBlake256(input_len))?; Ok(ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr)?) - }, + } - // Computes the BLAKE2 128-bit hash on the given input buffer. - // - // Returns the result directly into the given output buffer. - // - // # Note - // - // - The `input` and `output` buffer may overlap. - // - The output buffer is expected to hold at least 16 bytes (128 bits). - // - It is the callers responsibility to provide an output buffer that - // is large enough to hold the expected amount of bytes returned by the - // chosen hash function. - // - // # Parameters - // - // - `input_ptr`: the pointer into the linear memory where the input - // data is placed. - // - `input_len`: the length of the input data in bytes. - // - `output_ptr`: the pointer into the linear memory where the output - // data is placed. The function will write the result - // directly into this buffer. - [seal0] seal_hash_blake2_128(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { + /// Computes the BLAKE2 128-bit hash on the given input buffer. + /// + /// Returns the result directly into the given output buffer. + /// + /// # Note + /// + /// - The `input` and `output` buffer may overlap. + /// - The output buffer is expected to hold at least 16 bytes (128 bits). + /// - It is the callers responsibility to provide an output buffer that is large enough to hold + /// the expected amount of bytes returned by the chosen hash function. + /// + /// # Parameters + /// + /// - `input_ptr`: the pointer into the linear memory where the input data is placed. + /// - `input_len`: the length of the input data in bytes. + /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The + /// function will write the result directly into this buffer. + fn seal_hash_blake2_128( + ctx: Runtime, + input_ptr: u32, + input_len: u32, + output_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::HashBlake128(input_len))?; Ok(ctx.compute_hash_on_intermediate_buffer(blake2_128, input_ptr, input_len, output_ptr)?) - }, + } - // Call into the chain extension provided by the chain if any. - // - // Handling of the input values is up to the specific chain extension and so is the - // return value. The extension can decide to use the inputs as primitive inputs or as - // in/out arguments by interpreting them as pointers. Any caller of this function - // must therefore coordinate with the chain that it targets. - // - // # Note - // - // If no chain extension exists the contract will trap with the `NoChainExtension` - // module error. - [seal0] seal_call_chain_extension( - ctx, + /// Call into the chain extension provided by the chain if any. + /// + /// Handling of the input values is up to the specific chain extension and so is the + /// return value. The extension can decide to use the inputs as primitive inputs or as + /// in/out arguments by interpreting them as pointers. Any caller of this function + /// must therefore coordinate with the chain that it targets. + /// + /// # Note + /// + /// If no chain extension exists the contract will trap with the `NoChainExtension` + /// module error. + fn seal_call_chain_extension( + ctx: Runtime, id: u32, input_ptr: u32, input_len: u32, output_ptr: u32, - output_len_ptr: u32 - ) -> u32 => { + output_len_ptr: u32, + ) -> Result { use crate::chain_extension::{ChainExtension, Environment, RetVal}; if !::ChainExtension::enabled() { - return Err(Error::::NoChainExtension.into()); + return Err(Error::::NoChainExtension.into()) } let mut chain_extension = ctx.chain_extension.take().expect( "Constructor initializes with `Some`. This is the only place where it is set to `None`.\ @@ -2034,87 +2217,93 @@ define_env!(Env, , let env = Environment::new(ctx, id, input_ptr, input_len, output_ptr, output_len_ptr); let ret = match chain_extension.call(env)? { RetVal::Converging(val) => Ok(val), - RetVal::Diverging{flags, data} => Err(TrapReason::Return(ReturnData { - flags: flags.bits(), - data, - })), + RetVal::Diverging { flags, data } => + Err(TrapReason::Return(ReturnData { flags: flags.bits(), data })), }; ctx.chain_extension = Some(chain_extension); ret - }, + } - // Emit a custom debug message. - // - // No newlines are added to the supplied message. - // Specifying invalid UTF-8 triggers a trap. - // - // This is a no-op if debug message recording is disabled which is always the case - // when the code is executing on-chain. The message is interpreted as UTF-8 and - // appended to the debug buffer which is then supplied to the calling RPC client. - // - // # Note - // - // Even though no action is taken when debug message recording is disabled there is still - // a non trivial overhead (and weight cost) associated with calling this function. Contract - // languages should remove calls to this function (either at runtime or compile time) when - // not being executed as an RPC. For example, they could allow users to disable logging - // through compile time flags (cargo features) for on-chain deployment. Additionally, the - // return value of this function can be cached in order to prevent further calls at runtime. - [seal0] seal_debug_message(ctx, str_ptr: u32, str_len: u32) -> ReturnCode => { + /// Emit a custom debug message. + /// + /// No newlines are added to the supplied message. + /// Specifying invalid UTF-8 triggers a trap. + /// + /// This is a no-op if debug message recording is disabled which is always the case + /// when the code is executing on-chain. The message is interpreted as UTF-8 and + /// appended to the debug buffer which is then supplied to the calling RPC client. + /// + /// # Note + /// + /// Even though no action is taken when debug message recording is disabled there is still + /// a non trivial overhead (and weight cost) associated with calling this function. Contract + /// languages should remove calls to this function (either at runtime or compile time) when + /// not being executed as an RPC. For example, they could allow users to disable logging + /// through compile time flags (cargo features) for on-chain deployment. Additionally, the + /// return value of this function can be cached in order to prevent further calls at runtime. + fn seal_debug_message( + ctx: Runtime, + str_ptr: u32, + str_len: u32, + ) -> Result { ctx.charge_gas(RuntimeCosts::DebugMessage)?; if ctx.ext.append_debug_buffer("") { let data = ctx.read_sandbox_memory(str_ptr, str_len)?; - let msg = core::str::from_utf8(&data) - .map_err(|_| >::DebugMessageInvalidUTF8)?; + let msg = + core::str::from_utf8(&data).map_err(|_| >::DebugMessageInvalidUTF8)?; ctx.ext.append_debug_buffer(msg); - return Ok(ReturnCode::Success); + return Ok(ReturnCode::Success) } Ok(ReturnCode::LoggingDisabled) - }, + } - // Call some dispatchable of the runtime. - // - // This function decodes the passed in data as the overarching `Call` type of the - // runtime and dispatches it. The weight as specified in the runtime is charged - // from the gas meter. Any weight refunds made by the dispatchable are considered. - // - // The filter specified by `Config::CallFilter` is attached to the origin of - // the dispatched call. - // - // # Parameters - // - // - `input_ptr`: the pointer into the linear memory where the input data is placed. - // - `input_len`: the length of the input data in bytes. - // - // # Return Value - // - // Returns `ReturnCode::Success` when the dispatchable was successfully executed and - // returned `Ok`. When the dispatchable was executed but returned an error - // `ReturnCode::CallRuntimeReturnedError` is returned. The full error is not - // provided because it is not guaranteed to be stable. - // - // # Comparison with `ChainExtension` - // - // Just as a chain extension this API allows the runtime to extend the functionality - // of contracts. While making use of this function is generally easier it cannot be - // used in call cases. Consider writing a chain extension if you need to do perform - // one of the following tasks: - // - // - Return data. - // - Provide functionality **exclusively** to contracts. - // - Provide custom weights. - // - Avoid the need to keep the `Call` data structure stable. - // - // # Unstable - // - // This function is unstable and subject to change (or removal) in the future. Do not - // deploy a contract using it to a production chain. - [__unstable__] seal_call_runtime(ctx, call_ptr: u32, call_len: u32) -> ReturnCode => { + /// Call some dispatchable of the runtime. + /// + /// This function decodes the passed in data as the overarching `Call` type of the + /// runtime and dispatches it. The weight as specified in the runtime is charged + /// from the gas meter. Any weight refunds made by the dispatchable are considered. + /// + /// The filter specified by `Config::CallFilter` is attached to the origin of + /// the dispatched call. + /// + /// # Parameters + /// + /// - `input_ptr`: the pointer into the linear memory where the input data is placed. + /// - `input_len`: the length of the input data in bytes. + /// + /// # Return Value + /// + /// Returns `ReturnCode::Success` when the dispatchable was succesfully executed and + /// returned `Ok`. When the dispatchable was exeuted but returned an error + /// `ReturnCode::CallRuntimeReturnedError` is returned. The full error is not + /// provided because it is not guaranteed to be stable. + /// + /// # Comparison with `ChainExtension` + /// + /// Just as a chain extension this API allows the runtime to extend the functionality + /// of contracts. While making use of this function is generelly easier it cannot be + /// used in call cases. Consider writing a chain extension if you need to do perform + /// one of the following tasks: + /// + /// - Return data. + /// - Provide functionality **exclusively** to contracts. + /// - Provide custom weights. + /// - Avoid the need to keep the `Call` data structure stable. + /// + /// # Unstable + /// + /// This function is unstable and subject to change (or removal) in the future. Do not + /// deploy a contract using it to a production chain. + #[unstable] + fn seal_call_runtime( + ctx: Runtime, + call_ptr: u32, + call_len: u32, + ) -> Result { use frame_support::{dispatch::GetDispatchInfo, weights::extract_actual_weight}; ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?; - let call: ::Call = ctx.read_sandbox_memory_as_unbounded( - call_ptr, call_len - )?; + let call: ::Call = + ctx.read_sandbox_memory_as_unbounded(call_ptr, call_len)?; let dispatch_info = call.get_dispatch_info(); let charged = ctx.charge_gas(RuntimeCosts::CallRuntime(dispatch_info.weight))?; let result = ctx.ext.call_runtime(call); @@ -2124,27 +2313,31 @@ define_env!(Env, , Ok(_) => Ok(ReturnCode::Success), Err(_) => Ok(ReturnCode::CallRuntimeReturnedError), } - }, + } - // Recovers the ECDSA public key from the given message hash and signature. - // - // Writes the public key into the given output buffer. - // Assumes the secp256k1 curve. - // - // # Parameters - // - // - `signature_ptr`: the pointer into the linear memory where the signature - // is placed. Should be decodable as a 65 bytes. Traps otherwise. - // - `message_hash_ptr`: the pointer into the linear memory where the message - // hash is placed. Should be decodable as a 32 bytes. Traps otherwise. - // - `output_ptr`: the pointer into the linear memory where the output - // data is placed. The buffer should be 33 bytes. The function - // will write the result directly into this buffer. - // - // # Errors - // - // `ReturnCode::EcdsaRecoverFailed` - [seal0] seal_ecdsa_recover(ctx, signature_ptr: u32, message_hash_ptr: u32, output_ptr: u32) -> ReturnCode => { + /// Recovers the ECDSA public key from the given message hash and signature. + /// + /// Writes the public key into the given output buffer. + /// Assumes the secp256k1 curve. + /// + /// # Parameters + /// + /// - `signature_ptr`: the pointer into the linear memory where the signature is placed. Should + /// be decodable as a 65 bytes. Traps otherwise. + /// - `message_hash_ptr`: the pointer into the linear memory where the message hash is placed. + /// Should be decodable as a 32 bytes. Traps otherwise. + /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The + /// buffer should be 33 bytes. The function will write the result directly into this buffer. + /// + /// # Errors + /// + /// `ReturnCode::EcdsaRecoverFailed` + fn seal_ecdsa_recover( + ctx: Runtime, + signature_ptr: u32, + message_hash_ptr: u32, + output_ptr: u32, + ) -> Result { ctx.charge_gas(RuntimeCosts::EcdsaRecovery)?; let mut signature: [u8; 65] = [0; 65]; @@ -2164,65 +2357,72 @@ define_env!(Env, , }, Err(_) => Ok(ReturnCode::EcdsaRecoverFailed), } - }, + } - // Replace the contract code at the specified address with new code. - // - // # Note - // - // There are a couple of important considerations which must be taken into account when - // using this API: - // - // 1. The storage at the code address will remain untouched. This means that contract developers - // must ensure that the storage layout of the new code is compatible with that of the old code. - // - // 2. Contracts using this API can't be assumed as having deterministic addresses. Said another way, - // when using this API you lose the guarantee that an address always identifies a specific code hash. - // - // 3. If a contract calls into itself after changing its code the new call would use - // the new code. However, if the original caller panics after returning from the sub call it - // would revert the changes made by `seal_set_code_hash` and the next caller would use - // the old code. - // - // # Parameters - // - // - `code_hash_ptr`: A pointer to the buffer that contains the new code hash. - // - // # Errors - // - // `ReturnCode::CodeNotFound` - [seal0] seal_set_code_hash(ctx, code_hash_ptr: u32) -> ReturnCode => { + /// Replace the contract code at the specified address with new code. + /// + /// # Note + /// + /// There are a couple of important considerations which must be taken into account when + /// using this API: + /// + /// 1. The storage at the code address will remain untouched. This means that contract + /// developers must ensure that the storage layout of the new code is compatible with that of + /// the old code. + /// + /// 2. Contracts using this API can't be assumed as having deterministic addresses. Said another + /// way, when using this API you lose the guarantee that an address always identifies a specific + /// code hash. + /// 3. If a contract calls into itself after changing its code the new call would use + /// the new code. However, if the original caller panics after returning from the sub call it + /// would revert the changes made by `seal_set_code_hash` and the next caller would use + /// the old code. + /// + /// # Parameters + /// + /// - `code_hash_ptr`: A pointer to the buffer that contains the new code hash. + /// + /// # Errors + /// + /// `ReturnCode::CodeNotFound` + fn seal_set_code_hash( + ctx: Runtime, + code_hash_ptr: u32, + ) -> Result { ctx.charge_gas(RuntimeCosts::SetCodeHash)?; let code_hash: CodeHash<::T> = ctx.read_sandbox_memory_as(code_hash_ptr)?; match ctx.ext.set_code_hash(code_hash) { - Err(err) => { + Err(err) => { let code = Runtime::::err_into_return_code(err)?; Ok(code) }, - Ok(()) => Ok(ReturnCode::Success) + Ok(()) => Ok(ReturnCode::Success), } - }, + } - // Calculates Ethereum address from the ECDSA compressed public key and stores - // it into the supplied buffer. - // - // # Parameters - // - // - `key_ptr`: a pointer to the ECDSA compressed public key. Should be decodable as a 33 bytes value. - // Traps otherwise. - // - `out_ptr`: the pointer into the linear memory where the output - // data is placed. The function will write the result - // directly into this buffer. - // - // The value is stored to linear memory at the address pointed to by `out_ptr`. - // If the available space at `out_ptr` is less than the size of the value a trap is triggered. - // - // # Errors - // - // `ReturnCode::EcdsaRecoverFailed` - [seal0] seal_ecdsa_to_eth_address(ctx, key_ptr: u32, out_ptr: u32) -> ReturnCode => { + /// Calculates Ethereum address from the ECDSA compressed public key and stores + /// it into the supplied buffer. + /// + /// # Parameters + /// + /// - `key_ptr`: a pointer to the ECDSA compressed public key. Should be decodable as a 33 bytes + /// value. Traps otherwise. + /// - `out_ptr`: the pointer into the linear memory where the output data is placed. The + /// function will write the result directly into this buffer. + /// + /// The value is stored to linear memory at the address pointed to by `out_ptr`. + /// If the available space at `out_ptr` is less than the size of the value a trap is triggered. + /// + /// # Errors + /// + /// `ReturnCode::EcdsaRecoverFailed` + fn seal_ecdsa_to_eth_address( + ctx: Runtime, + key_ptr: u32, + out_ptr: u32, + ) -> Result { ctx.charge_gas(RuntimeCosts::EcdsaToEthAddress)?; - let mut compressed_key: [u8; 33] = [0;33]; + let mut compressed_key: [u8; 33] = [0; 33]; ctx.read_sandbox_memory_into_buf(key_ptr, &mut compressed_key)?; let result = ctx.ext.ecdsa_to_eth_address(&compressed_key); match result { @@ -2232,5 +2432,5 @@ define_env!(Env, , }, Err(_) => Ok(ReturnCode::EcdsaRecoverFailed), } - }, -); + } +} From 57e3486d9c7bb4deaef33cf9ba2da083b4e40314 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Mon, 22 Aug 2022 18:53:14 +0300 Subject: [PATCH 1083/1472] Network sync refactoring (part 7) (#12006) * Move `MultiaddrWithPeerId` and related parsing functions into `sc-network-common`, remove dependency on `sc-network` from `sc-chain-spec` * Remove dependency on `sc-network` from `sc-offchain` * Remove dependency on `sc-network` from `sc-network-gossip` --- Cargo.lock | 10 +- client/authority-discovery/Cargo.toml | 1 - client/authority-discovery/src/error.rs | 2 +- client/chain-spec/Cargo.toml | 2 +- client/chain-spec/src/chain_spec.rs | 2 +- client/chain-spec/src/lib.rs | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network-gossip/src/bridge.rs | 4 +- client/network-gossip/src/lib.rs | 2 +- client/network-gossip/src/state_machine.rs | 6 +- client/network-gossip/src/validator.rs | 2 +- client/network/common/Cargo.toml | 1 + client/network/common/src/config.rs | 129 ++++++++++++++++++++- client/network/src/config.rs | 129 +-------------------- client/network/src/service.rs | 3 +- client/network/src/service/tests.rs | 16 +-- client/network/test/src/lib.rs | 6 +- client/offchain/Cargo.toml | 3 +- client/offchain/src/api.rs | 5 +- client/offchain/src/lib.rs | 3 +- client/rpc/Cargo.toml | 1 + client/rpc/src/system/tests.rs | 2 +- client/service/src/config.rs | 5 +- 23 files changed, 173 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 060cd960ee985..1c453da9d3045 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7730,7 +7730,6 @@ dependencies = [ "quickcheck", "rand 0.7.3", "sc-client-api", - "sc-network", "sc-network-common", "sp-api", "sp-authority-discovery", @@ -7793,7 +7792,7 @@ dependencies = [ "memmap2 0.5.0", "parity-scale-codec", "sc-chain-spec-derive", - "sc-network", + "sc-network-common", "sc-telemetry", "serde", "serde_json", @@ -8426,6 +8425,7 @@ dependencies = [ "prost-build", "sc-consensus", "sc-peerset", + "serde", "smallvec", "sp-consensus", "sp-finality-grandpa", @@ -8445,8 +8445,8 @@ dependencies = [ "log", "lru", "quickcheck", - "sc-network", "sc-network-common", + "sc-peerset", "sp-runtime", "substrate-prometheus-endpoint", "substrate-test-runtime-client", @@ -8547,6 +8547,7 @@ dependencies = [ "hyper", "hyper-rustls", "lazy_static", + "libp2p", "num_cpus", "once_cell", "parity-scale-codec", @@ -8555,8 +8556,8 @@ dependencies = [ "sc-block-builder", "sc-client-api", "sc-client-db", - "sc-network", "sc-network-common", + "sc-peerset", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", @@ -8610,6 +8611,7 @@ dependencies = [ "sc-chain-spec", "sc-client-api", "sc-network", + "sc-network-common", "sc-rpc-api", "sc-tracing", "sc-transaction-pool", diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 544df4c8d4812..b7a140f24a111 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -29,7 +29,6 @@ thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } -sc-network = { version = "0.10.0-dev", path = "../network" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-authority-discovery = { version = "4.0.0-dev", path = "../../primitives/authority-discovery" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } diff --git a/client/authority-discovery/src/error.rs b/client/authority-discovery/src/error.rs index bce39069ef7c7..285a2714b81f5 100644 --- a/client/authority-discovery/src/error.rs +++ b/client/authority-discovery/src/error.rs @@ -57,7 +57,7 @@ pub enum Error { ParsingMultiaddress(#[from] libp2p::core::multiaddr::Error), #[error("Failed to parse a libp2p key.")] - ParsingLibp2pIdentity(#[from] sc_network::DecodingError), + ParsingLibp2pIdentity(#[from] libp2p::identity::error::DecodingError), #[error("Failed to sign using a specific public key.")] MissingSignature(CryptoTypePublicPair), diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 6ab559dea46fd..bd4ee548e296b 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -19,7 +19,7 @@ memmap2 = "0.5.0" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } -sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 5aafc28524dbf..2cc9f356e4df7 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -20,7 +20,7 @@ #![warn(missing_docs)] use crate::{extension::GetExtension, ChainType, Properties, RuntimeGenesis}; -use sc_network::config::MultiaddrWithPeerId; +use sc_network_common::config::MultiaddrWithPeerId; use sc_telemetry::TelemetryEndpoints; use serde::{Deserialize, Serialize}; use serde_json as json; diff --git a/client/chain-spec/src/lib.rs b/client/chain-spec/src/lib.rs index 73d3e1af15492..9d2cc728b8288 100644 --- a/client/chain-spec/src/lib.rs +++ b/client/chain-spec/src/lib.rs @@ -184,7 +184,7 @@ pub use extension::{ }; pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup}; -use sc_network::config::MultiaddrWithPeerId; +use sc_network_common::config::MultiaddrWithPeerId; use sc_telemetry::TelemetryEndpoints; use serde::{de::DeserializeOwned, Serialize}; use sp_core::storage::Storage; diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 185c37985b585..8ecf2b9cec787 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -22,8 +22,8 @@ log = "0.4.17" lru = "0.7.5" tracing = "0.1.29" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } -sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } +sc-peerset = { version = "4.0.0-dev", path = "../peerset" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index b5c957024701d..b63e3f64a1256 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -21,8 +21,8 @@ use crate::{ Network, Validator, }; -use sc_network::ReputationChange; use sc_network_common::protocol::event::Event; +use sc_peerset::ReputationChange; use futures::{ channel::mpsc::{channel, Receiver, Sender}, @@ -152,7 +152,7 @@ impl GossipEngine { /// Send addressed message to the given peers. The message is not kept or multicast /// later on. - pub fn send_message(&mut self, who: Vec, data: Vec) { + pub fn send_message(&mut self, who: Vec, data: Vec) { for who in &who { self.state_machine.send_message(&mut *self.network, who, data.clone()); } diff --git a/client/network-gossip/src/lib.rs b/client/network-gossip/src/lib.rs index b9dff0bcd4d00..0fdde1feac6c6 100644 --- a/client/network-gossip/src/lib.rs +++ b/client/network-gossip/src/lib.rs @@ -67,7 +67,7 @@ pub use self::{ validator::{DiscardAll, MessageIntent, ValidationResult, Validator, ValidatorContext}, }; -use sc_network::{multiaddr, PeerId}; +use libp2p::{multiaddr, PeerId}; use sc_network_common::service::{ NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, }; diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 3cb8d5bd9bab9..a870ca6a3acdf 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -42,9 +42,9 @@ const REBROADCAST_INTERVAL: time::Duration = time::Duration::from_millis(750); pub(crate) const PERIODIC_MAINTENANCE_INTERVAL: time::Duration = time::Duration::from_millis(1100); mod rep { - use sc_network::ReputationChange as Rep; + use sc_peerset::ReputationChange as Rep; /// Reputation change when a peer sends us a gossip message that we didn't know about. - pub const GOSSIP_SUCCESS: Rep = Rep::new(1 << 4, "Successfull gossip"); + pub const GOSSIP_SUCCESS: Rep = Rep::new(1 << 4, "Successful gossip"); /// Reputation change when a peer sends us a gossip message that we already knew about. pub const DUPLICATE_GOSSIP: Rep = Rep::new(-(1 << 2), "Duplicate gossip"); } @@ -513,7 +513,6 @@ mod tests { use super::*; use crate::multiaddr::Multiaddr; use futures::prelude::*; - use sc_network::ReputationChange; use sc_network_common::{ protocol::event::Event, service::{ @@ -521,6 +520,7 @@ mod tests { NotificationSender, NotificationSenderError, }, }; + use sc_peerset::ReputationChange; use sp_runtime::{ testing::{Block as RawBlock, ExtrinsicWrapper, H256}, traits::NumberFor, diff --git a/client/network-gossip/src/validator.rs b/client/network-gossip/src/validator.rs index a98c62ab5a9eb..185c2cfeed2c7 100644 --- a/client/network-gossip/src/validator.rs +++ b/client/network-gossip/src/validator.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use sc_network::PeerId; +use libp2p::PeerId; use sc_network_common::protocol::event::ObservedRole; use sp_runtime::traits::Block as BlockT; diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 1b10bd248292c..8f0702e05cac5 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -28,6 +28,7 @@ libp2p = "0.46.1" smallvec = "1.8.0" sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } +serde = { version = "1.0.136", features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/client/network/common/src/config.rs b/client/network/common/src/config.rs index 92f8df5cd380f..c2e61424c88e0 100644 --- a/client/network/common/src/config.rs +++ b/client/network/common/src/config.rs @@ -18,7 +18,8 @@ //! Configuration of the networking layer. -use std::{fmt, str}; +use libp2p::{multiaddr, Multiaddr, PeerId}; +use std::{fmt, str, str::FromStr}; /// Name of a protocol, transmitted on the wire. Should be unique for each chain. Always UTF-8. #[derive(Clone, PartialEq, Eq, Hash)] @@ -42,3 +43,129 @@ impl fmt::Debug for ProtocolId { fmt::Debug::fmt(self.as_ref(), f) } } + +/// Parses a string address and splits it into Multiaddress and PeerId, if +/// valid. +/// +/// # Example +/// +/// ``` +/// # use libp2p::{Multiaddr, PeerId}; +/// # use sc_network_common::config::parse_str_addr; +/// let (peer_id, addr) = parse_str_addr( +/// "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV" +/// ).unwrap(); +/// assert_eq!(peer_id, "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".parse::().unwrap()); +/// assert_eq!(addr, "/ip4/198.51.100.19/tcp/30333".parse::().unwrap()); +/// ``` +pub fn parse_str_addr(addr_str: &str) -> Result<(PeerId, Multiaddr), ParseErr> { + let addr: Multiaddr = addr_str.parse()?; + parse_addr(addr) +} + +/// Splits a Multiaddress into a Multiaddress and PeerId. +pub fn parse_addr(mut addr: Multiaddr) -> Result<(PeerId, Multiaddr), ParseErr> { + let who = match addr.pop() { + Some(multiaddr::Protocol::P2p(key)) => + PeerId::from_multihash(key).map_err(|_| ParseErr::InvalidPeerId)?, + _ => return Err(ParseErr::PeerIdMissing), + }; + + Ok((who, addr)) +} + +/// Address of a node, including its identity. +/// +/// This struct represents a decoded version of a multiaddress that ends with `/p2p/`. +/// +/// # Example +/// +/// ``` +/// # use libp2p::{Multiaddr, PeerId}; +/// # use sc_network_common::config::MultiaddrWithPeerId; +/// let addr: MultiaddrWithPeerId = +/// "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".parse().unwrap(); +/// assert_eq!(addr.peer_id.to_base58(), "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"); +/// assert_eq!(addr.multiaddr.to_string(), "/ip4/198.51.100.19/tcp/30333"); +/// ``` +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)] +#[serde(try_from = "String", into = "String")] +pub struct MultiaddrWithPeerId { + /// Address of the node. + pub multiaddr: Multiaddr, + /// Its identity. + pub peer_id: PeerId, +} + +impl MultiaddrWithPeerId { + /// Concatenates the multiaddress and peer ID into one multiaddress containing both. + pub fn concat(&self) -> Multiaddr { + let proto = multiaddr::Protocol::P2p(From::from(self.peer_id)); + self.multiaddr.clone().with(proto) + } +} + +impl fmt::Display for MultiaddrWithPeerId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.concat(), f) + } +} + +impl FromStr for MultiaddrWithPeerId { + type Err = ParseErr; + + fn from_str(s: &str) -> Result { + let (peer_id, multiaddr) = parse_str_addr(s)?; + Ok(Self { peer_id, multiaddr }) + } +} + +impl From for String { + fn from(ma: MultiaddrWithPeerId) -> String { + format!("{}", ma) + } +} + +impl TryFrom for MultiaddrWithPeerId { + type Error = ParseErr; + fn try_from(string: String) -> Result { + string.parse() + } +} + +/// Error that can be generated by `parse_str_addr`. +#[derive(Debug)] +pub enum ParseErr { + /// Error while parsing the multiaddress. + MultiaddrParse(multiaddr::Error), + /// Multihash of the peer ID is invalid. + InvalidPeerId, + /// The peer ID is missing from the address. + PeerIdMissing, +} + +impl fmt::Display for ParseErr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::MultiaddrParse(err) => write!(f, "{}", err), + Self::InvalidPeerId => write!(f, "Peer id at the end of the address is invalid"), + Self::PeerIdMissing => write!(f, "Peer id is missing from the address"), + } + } +} + +impl std::error::Error for ParseErr { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::MultiaddrParse(err) => Some(err), + Self::InvalidPeerId => None, + Self::PeerIdMissing => None, + } + } +} + +impl From for ParseErr { + fn from(err: multiaddr::Error) -> ParseErr { + Self::MultiaddrParse(err) + } +} diff --git a/client/network/src/config.rs b/client/network/src/config.rs index afd61cae6c83b..52fa28e76e207 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -37,11 +37,11 @@ use core::{fmt, iter}; use futures::future; use libp2p::{ identity::{ed25519, Keypair}, - multiaddr, Multiaddr, PeerId, + multiaddr, Multiaddr, }; use prometheus_endpoint::Registry; use sc_consensus::ImportQueue; -use sc_network_common::sync::ChainSync; +use sc_network_common::{config::MultiaddrWithPeerId, sync::ChainSync}; use sp_runtime::traits::Block as BlockT; use std::{ borrow::Cow, @@ -54,7 +54,6 @@ use std::{ path::{Path, PathBuf}, pin::Pin, str, - str::FromStr, sync::Arc, }; use zeroize::Zeroize; @@ -225,130 +224,6 @@ impl TransactionPool for EmptyTransaction } } -/// Parses a string address and splits it into Multiaddress and PeerId, if -/// valid. -/// -/// # Example -/// -/// ``` -/// # use sc_network::{Multiaddr, PeerId, config::parse_str_addr}; -/// let (peer_id, addr) = parse_str_addr( -/// "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV" -/// ).unwrap(); -/// assert_eq!(peer_id, "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".parse::().unwrap()); -/// assert_eq!(addr, "/ip4/198.51.100.19/tcp/30333".parse::().unwrap()); -/// ``` -pub fn parse_str_addr(addr_str: &str) -> Result<(PeerId, Multiaddr), ParseErr> { - let addr: Multiaddr = addr_str.parse()?; - parse_addr(addr) -} - -/// Splits a Multiaddress into a Multiaddress and PeerId. -pub fn parse_addr(mut addr: Multiaddr) -> Result<(PeerId, Multiaddr), ParseErr> { - let who = match addr.pop() { - Some(multiaddr::Protocol::P2p(key)) => - PeerId::from_multihash(key).map_err(|_| ParseErr::InvalidPeerId)?, - _ => return Err(ParseErr::PeerIdMissing), - }; - - Ok((who, addr)) -} - -/// Address of a node, including its identity. -/// -/// This struct represents a decoded version of a multiaddress that ends with `/p2p/`. -/// -/// # Example -/// -/// ``` -/// # use sc_network::{Multiaddr, PeerId, config::MultiaddrWithPeerId}; -/// let addr: MultiaddrWithPeerId = -/// "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".parse().unwrap(); -/// assert_eq!(addr.peer_id.to_base58(), "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"); -/// assert_eq!(addr.multiaddr.to_string(), "/ip4/198.51.100.19/tcp/30333"); -/// ``` -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)] -#[serde(try_from = "String", into = "String")] -pub struct MultiaddrWithPeerId { - /// Address of the node. - pub multiaddr: Multiaddr, - /// Its identity. - pub peer_id: PeerId, -} - -impl MultiaddrWithPeerId { - /// Concatenates the multiaddress and peer ID into one multiaddress containing both. - pub fn concat(&self) -> Multiaddr { - let proto = multiaddr::Protocol::P2p(From::from(self.peer_id)); - self.multiaddr.clone().with(proto) - } -} - -impl fmt::Display for MultiaddrWithPeerId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.concat(), f) - } -} - -impl FromStr for MultiaddrWithPeerId { - type Err = ParseErr; - - fn from_str(s: &str) -> Result { - let (peer_id, multiaddr) = parse_str_addr(s)?; - Ok(Self { peer_id, multiaddr }) - } -} - -impl From for String { - fn from(ma: MultiaddrWithPeerId) -> String { - format!("{}", ma) - } -} - -impl TryFrom for MultiaddrWithPeerId { - type Error = ParseErr; - fn try_from(string: String) -> Result { - string.parse() - } -} - -/// Error that can be generated by `parse_str_addr`. -#[derive(Debug)] -pub enum ParseErr { - /// Error while parsing the multiaddress. - MultiaddrParse(multiaddr::Error), - /// Multihash of the peer ID is invalid. - InvalidPeerId, - /// The peer ID is missing from the address. - PeerIdMissing, -} - -impl fmt::Display for ParseErr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::MultiaddrParse(err) => write!(f, "{}", err), - Self::InvalidPeerId => write!(f, "Peer id at the end of the address is invalid"), - Self::PeerIdMissing => write!(f, "Peer id is missing from the address"), - } - } -} - -impl std::error::Error for ParseErr { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::MultiaddrParse(err) => Some(err), - Self::InvalidPeerId => None, - Self::PeerIdMissing => None, - } - } -} - -impl From for ParseErr { - fn from(err: multiaddr::Error) -> ParseErr { - Self::MultiaddrParse(err) - } -} - /// Sync operation mode. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum SyncMode { diff --git a/client/network/src/service.rs b/client/network/src/service.rs index bf15a9250d82c..d36e310795818 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -30,7 +30,7 @@ use crate::{ behaviour::{self, Behaviour, BehaviourOut}, bitswap::Bitswap, - config::{parse_str_addr, Params, TransportConfig}, + config::{Params, TransportConfig}, discovery::DiscoveryConfig, error::Error, network_state::{ @@ -62,6 +62,7 @@ use parking_lot::Mutex; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; use sc_network_common::{ + config::parse_str_addr, protocol::event::{DhtEvent, Event}, request_responses::{IfDisconnected, RequestFailure}, service::{ diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 6ccca17650b67..e2fe58423abfe 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -21,7 +21,7 @@ use crate::{config, NetworkService, NetworkWorker}; use futures::prelude::*; use libp2p::PeerId; use sc_network_common::{ - config::ProtocolId, + config::{MultiaddrWithPeerId, ProtocolId}, protocol::event::Event, service::{NetworkEventStream, NetworkNotification, NetworkPeers, NetworkStateInfo}, }; @@ -194,7 +194,7 @@ fn build_nodes_one_proto() -> ( fallback_names: Vec::new(), max_notification_size: 1024 * 1024, set_config: config::SetConfig { - reserved_nodes: vec![config::MultiaddrWithPeerId { + reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, peer_id: node1.local_peer_id(), }], @@ -383,7 +383,7 @@ fn lots_of_incoming_peers_works() { fallback_names: Vec::new(), max_notification_size: 1024 * 1024, set_config: config::SetConfig { - reserved_nodes: vec![config::MultiaddrWithPeerId { + reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr.clone(), peer_id: main_node_peer_id, }], @@ -513,7 +513,7 @@ fn fallback_name_working() { fallback_names: Vec::new(), max_notification_size: 1024 * 1024, set_config: config::SetConfig { - reserved_nodes: vec![config::MultiaddrWithPeerId { + reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, peer_id: node1.local_peer_id(), }], @@ -584,7 +584,7 @@ fn ensure_listen_addresses_consistent_with_transport_not_memory() { #[should_panic(expected = "don't match the transport")] fn ensure_boot_node_addresses_consistent_with_transport_memory() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let boot_node = config::MultiaddrWithPeerId { + let boot_node = MultiaddrWithPeerId { multiaddr: config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)], peer_id: PeerId::random(), }; @@ -601,7 +601,7 @@ fn ensure_boot_node_addresses_consistent_with_transport_memory() { #[should_panic(expected = "don't match the transport")] fn ensure_boot_node_addresses_consistent_with_transport_not_memory() { let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)]; - let boot_node = config::MultiaddrWithPeerId { + let boot_node = MultiaddrWithPeerId { multiaddr: config::build_multiaddr![Memory(rand::random::())], peer_id: PeerId::random(), }; @@ -617,7 +617,7 @@ fn ensure_boot_node_addresses_consistent_with_transport_not_memory() { #[should_panic(expected = "don't match the transport")] fn ensure_reserved_node_addresses_consistent_with_transport_memory() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let reserved_node = config::MultiaddrWithPeerId { + let reserved_node = MultiaddrWithPeerId { multiaddr: config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)], peer_id: PeerId::random(), }; @@ -637,7 +637,7 @@ fn ensure_reserved_node_addresses_consistent_with_transport_memory() { #[should_panic(expected = "don't match the transport")] fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)]; - let reserved_node = config::MultiaddrWithPeerId { + let reserved_node = MultiaddrWithPeerId { multiaddr: config::build_multiaddr![Memory(rand::random::())], peer_id: PeerId::random(), }; diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 3ba663aba2267..fbe56f463d0f3 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -51,13 +51,13 @@ use sc_consensus::{ pub use sc_network::config::EmptyTransactionPool; use sc_network::{ config::{ - MultiaddrWithPeerId, NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, Role, - SyncMode, TransportConfig, + NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, Role, SyncMode, + TransportConfig, }, Multiaddr, NetworkService, NetworkWorker, }; -pub use sc_network_common::config::ProtocolId; use sc_network_common::{ + config::{MultiaddrWithPeerId, ProtocolId}, service::{NetworkBlock, NetworkStateInfo, NetworkSyncForkRequest}, sync::warp::{AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider}, }; diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index ab26c0c38596c..89b77dbb5fea7 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -21,6 +21,7 @@ futures-timer = "3.0.2" hex = "0.4" hyper = { version = "0.14.16", features = ["stream", "http2"] } hyper-rustls = { version = "0.23.0", features = ["http2"] } +libp2p = { version = "0.46.1", default-features = false } num_cpus = "1.13" once_cell = "1.8" parking_lot = "0.12.0" @@ -28,8 +29,8 @@ rand = "0.7.2" threadpool = "1.7" tracing = "0.1.29" sc-client-api = { version = "4.0.0-dev", path = "../api" } -sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } +sc-peerset = { version = "4.0.0-dev", path = "../peerset" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "6.0.0", path = "../../primitives/core" } diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index f379ebad17bbf..5c8139d4505e7 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -22,7 +22,7 @@ use crate::NetworkProvider; use codec::{Decode, Encode}; use futures::Future; pub use http::SharedClient; -use sc_network::{Multiaddr, PeerId}; +use libp2p::{Multiaddr, PeerId}; use sp_core::{ offchain::{ self, HttpError, HttpRequestId, HttpRequestStatus, OffchainStorage, OpaqueMultiaddr, @@ -324,9 +324,10 @@ impl AsyncApi { #[cfg(test)] mod tests { use super::*; + use libp2p::PeerId; use sc_client_db::offchain::LocalStorage; - use sc_network::{PeerId, ReputationChange}; use sc_network_common::service::{NetworkPeers, NetworkStateInfo}; + use sc_peerset::ReputationChange; use sp_core::offchain::{DbExternalities, Externalities}; use std::{borrow::Cow, time::SystemTime}; diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 14a2408e61a70..5eed142ff3871 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -246,9 +246,10 @@ pub async fn notification_future( mod tests { use super::*; use futures::executor::block_on; + use libp2p::{Multiaddr, PeerId}; use sc_block_builder::BlockBuilderProvider as _; use sc_client_api::Backend as _; - use sc_network::{Multiaddr, PeerId, ReputationChange}; + use sc_peerset::ReputationChange; use sc_transaction_pool::{BasicPool, FullChainApi}; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_consensus::BlockOrigin; diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 5a05ae6e29df1..2381323d25a24 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -46,6 +46,7 @@ assert_matches = "1.3.0" lazy_static = "1.4.0" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } tokio = "1.17.0" diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index facad7a0b347a..2f91648008ff7 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -99,7 +99,7 @@ fn api>>(sync: T) -> RpcModule> { ); }, Request::NetworkAddReservedPeer(peer, sender) => { - let _ = match sc_network::config::parse_str_addr(&peer) { + let _ = match sc_network_common::config::parse_str_addr(&peer) { Ok(_) => sender.send(Ok(())), Err(s) => sender.send(Err(error::Error::MalformattedPeerArg(s.to_string()))), diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 6f5650df5648c..2fb3f820ebf15 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -25,13 +25,12 @@ pub use sc_executor::WasmExecutionMethod; pub use sc_executor::WasmtimeInstantiationStrategy; pub use sc_network::{ config::{ - MultiaddrWithPeerId, NetworkConfiguration, NodeKeyConfig, NonDefaultSetConfig, Role, - SetConfig, TransportConfig, + NetworkConfiguration, NodeKeyConfig, NonDefaultSetConfig, Role, SetConfig, TransportConfig, }, Multiaddr, }; pub use sc_network_common::{ - config::ProtocolId, + config::{MultiaddrWithPeerId, ProtocolId}, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, From 7266eb7d794d74a7860fe193d7a3074200765ea1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Aug 2022 13:19:54 +0200 Subject: [PATCH 1084/1472] Bump parity-db from 0.3.13 to 0.3.16 (#12091) Bumps [parity-db](https://github.com/paritytech/parity-db) from 0.3.13 to 0.3.16. - [Release notes](https://github.com/paritytech/parity-db/releases) - [Commits](https://github.com/paritytech/parity-db/commits) --- updated-dependencies: - dependency-name: parity-db dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- client/db/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c453da9d3045..c99212ba06ba8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6515,9 +6515,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.13" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a7901b85874402471e131de3332dde0e51f38432c69a3853627c8e25433048" +checksum = "2bb474d0ed0836e185cb998a6b140ed1073d1fbf27d690ecf9ede8030289382c" dependencies = [ "blake2-rfc", "crc32fast", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 7bfba997767f2..144791fda5c3c 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -22,7 +22,7 @@ kvdb-memorydb = "0.11.0" kvdb-rocksdb = { version = "0.15.2", optional = true } linked-hash-map = "0.5.4" log = "0.4.17" -parity-db = "0.3.13" +parity-db = "0.3.16" parking_lot = "0.12.0" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } From 40703f41167c718e13b491228efeafb4a6194448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 23 Aug 2022 22:22:58 +0200 Subject: [PATCH 1085/1472] Print bootnode mismatch message as `warning` (#12075) * Print bootnode mismatch message as `warning` * Fix test :thinking_face: * Remove wrong warning --- client/network/src/service.rs | 15 ++------------- primitives/trie/src/cache/mod.rs | 2 +- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/client/network/src/service.rs b/client/network/src/service.rs index d36e310795818..162b9c6a30491 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -160,18 +160,7 @@ where .network_config .boot_nodes .into_iter() - .filter(|boot_node| { - if boot_node.peer_id == local_peer_id { - warn!( - target: "sub-libp2p", - "Local peer ID used in bootnode, ignoring: {}", - boot_node, - ); - false - } else { - true - } - }) + .filter(|boot_node| boot_node.peer_id != local_peer_id) .collect(); params.network_config.default_peers_set.reserved_nodes = params .network_config @@ -1825,7 +1814,7 @@ where if let ConnectedPoint::Dialer { address, role_override: _ } = endpoint { - error!( + warn!( "💔 The bootnode you want to connect to at `{}` provided a different peer ID `{}` than the one you expect `{}`.", address, obtained, diff --git a/primitives/trie/src/cache/mod.rs b/primitives/trie/src/cache/mod.rs index a588f20bdb7b4..67348919250cd 100644 --- a/primitives/trie/src/cache/mod.rs +++ b/primitives/trie/src/cache/mod.rs @@ -631,7 +631,7 @@ mod tests { let mut cache = local_cache.as_trie_db_cache(root); let trie = TrieDBBuilder::::new(&db, &root).with_cache(&mut cache).build(); - for (k, _) in TEST_DATA.iter().take(2) { + for (k, _) in TEST_DATA.iter().skip(2) { trie.get(k).unwrap().unwrap(); } } From b7d8a3a3bd70f281d50352c48634cc96f6232d57 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 24 Aug 2022 17:55:48 +0200 Subject: [PATCH 1086/1472] Test bench components with more values (#11963) * Test values besides low and high. Signed-off-by: Oliver Tale-Yazdi * Only add highest if different and remove check Signed-off-by: Oliver Tale-Yazdi * Add env var Signed-off-by: Oliver Tale-Yazdi * Update README Signed-off-by: Oliver Tale-Yazdi * Add tests Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/benchmarking/README.md | 2 ++ frame/benchmarking/src/lib.rs | 40 +++++++++++++++++++++---- frame/benchmarking/src/tests.rs | 53 ++++++++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/frame/benchmarking/README.md b/frame/benchmarking/README.md index f0fe05cc140f2..6316cd5903c8b 100644 --- a/frame/benchmarking/README.md +++ b/frame/benchmarking/README.md @@ -125,6 +125,8 @@ cargo test -p pallet-balances --features runtime-benchmarks > ``` > To solve this, navigate to the folder of the node (`cd bin/node/cli`) or pallet (`cd frame/pallet`) and run the command there. +This will instance each linear component with different values. The number of values per component is set to six and can be changed with the `VALUES_PER_COMPONENT` environment variable. + ## Adding Benchmarks The benchmarks included with each pallet are not automatically added to your node. To actually diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 0a0f8eecdcc3d..18472595f15b9 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -1153,6 +1153,8 @@ macro_rules! impl_benchmark { // This creates a unit test for one benchmark of the main benchmark macro. // It runs the benchmark using the `high` and `low` value for each component // and ensure that everything completes successfully. +// Instances each component with six values which can be controlled with the +// env variable `VALUES_PER_COMPONENT`. #[macro_export] #[doc(hidden)] macro_rules! impl_benchmark_test { @@ -1197,16 +1199,42 @@ macro_rules! impl_benchmark_test { if components.is_empty() { execute_benchmark(Default::default())?; } else { - for (name, low, high) in components.iter() { - // Test only the low and high value, assuming values in the middle - // won't break - for component_value in $crate::vec![low, high] { + let num_values: u32 = if let Ok(ev) = std::env::var("VALUES_PER_COMPONENT") { + ev.parse().map_err(|_| { + $crate::BenchmarkError::Stop( + "Could not parse env var `VALUES_PER_COMPONENT` as u32." + ) + })? + } else { + 6 + }; + + if num_values < 2 { + return Err("`VALUES_PER_COMPONENT` must be at least 2".into()); + } + + for (name, low, high) in components.clone().into_iter() { + // Test the lowest, highest (if its different from the lowest) + // and up to num_values-2 more equidistant values in between. + // For 0..10 and num_values=6 this would mean: [0, 2, 4, 6, 8, 10] + + let mut values = $crate::vec![low]; + let diff = (high - low).min(num_values - 1); + let slope = (high - low) as f32 / diff as f32; + + for i in 1..=diff { + let value = ((low as f32 + slope * i as f32) as u32) + .clamp(low, high); + values.push(value); + } + + for component_value in values { // Select the max value for all the other components. let c: $crate::Vec<($crate::BenchmarkParameter, u32)> = components .iter() .map(|(n, _, h)| - if n == name { - (*n, *component_value) + if *n == name { + (*n, component_value) } else { (*n, *h) } diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index 9a97250aeb965..be5c23fff17f6 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -27,6 +27,7 @@ use sp_runtime::{ BuildStorage, }; use sp_std::prelude::*; +use std::cell::RefCell; #[frame_support::pallet] mod pallet_test { @@ -125,10 +126,16 @@ fn new_test_ext() -> sp_io::TestExternalities { GenesisConfig::default().build_storage().unwrap().into() } +thread_local! { + /// Tracks the used components per value. Needs to be a thread local since the + /// benchmarking clears the storage after each run. + static VALUES_PER_COMPONENT: RefCell> = RefCell::new(vec![]); +} + // NOTE: This attribute is only needed for the `modify_in_` functions. #[allow(unreachable_code)] mod benchmarks { - use super::{new_test_ext, pallet_test::Value, Test}; + use super::{new_test_ext, pallet_test::Value, Test, VALUES_PER_COMPONENT}; use crate::{account, BenchmarkError, BenchmarkParameter, BenchmarkResult, BenchmarkingSetup}; use frame_support::{assert_err, assert_ok, ensure, traits::Get}; use frame_system::RawOrigin; @@ -247,6 +254,13 @@ mod benchmarks { Value::::set(Some(123)); return Err(BenchmarkError::Stop("Should error")); } + + // Stores all component values in the thread-local storage. + values_per_component { + let n in 0 .. 10; + }: { + VALUES_PER_COMPONENT.with(|v| v.borrow_mut().push(n)); + } } #[test] @@ -394,4 +408,41 @@ mod benchmarks { assert_eq!(Value::::get(), None); }); } + + /// Test that the benchmarking uses the correct values for each component and + /// that the number of components can be controlled with `VALUES_PER_COMPONENT`. + #[test] + fn test_values_per_component() { + let tests = vec![ + (Some("1"), Err("`VALUES_PER_COMPONENT` must be at least 2".into())), + (Some("asdf"), Err("Could not parse env var `VALUES_PER_COMPONENT` as u32.".into())), + (None, Ok(vec![0, 2, 4, 6, 8, 10])), + (Some("2"), Ok(vec![0, 10])), + (Some("4"), Ok(vec![0, 3, 6, 10])), + (Some("6"), Ok(vec![0, 2, 4, 6, 8, 10])), + (Some("10"), Ok(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 10])), + (Some("11"), Ok(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), + (Some("99"), Ok(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), + ]; + + for (num, expected) in tests { + run_test_values_per_component(num, expected); + } + } + + /// Helper for [`test_values_per_component`]. + fn run_test_values_per_component(num: Option<&str>, output: Result, BenchmarkError>) { + VALUES_PER_COMPONENT.with(|v| v.borrow_mut().clear()); + match num { + Some(n) => std::env::set_var("VALUES_PER_COMPONENT", n), + None => std::env::remove_var("VALUES_PER_COMPONENT"), + } + + new_test_ext().execute_with(|| { + let got = Pallet::::test_benchmark_values_per_component() + .map(|_| VALUES_PER_COMPONENT.with(|v| v.borrow().clone())); + + assert_eq!(got, output); + }); + } } From bf7729208a6c5c67d0ac2f91004ba180a169be6f Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 25 Aug 2022 01:47:08 +0800 Subject: [PATCH 1087/1472] Implement ResultQuery (#11257) * Implement ResultQuery * Fix test expectations * Add more tests * Fix test expectations * Clean up some names * Silence warnings * Specify error type when supplying error type to ResultQuery * cargo fmt * Add support for type parameters in parameter_types macro * Reduce deeply indented code * Fixes * Update test expectation * Rewrite and document formula for calculating max storage size * More docs * cargo fmt * formatting Co-authored-by: parity-processbot <> --- .../procedural/src/pallet/expand/storage.rs | 217 ++++++++++++++++-- .../procedural/src/pallet/parse/storage.rs | 110 ++++++++- frame/support/src/lib.rs | 81 ++++--- frame/support/src/storage/types/mod.rs | 32 ++- frame/support/test/tests/pallet.rs | 139 ++++++++++- frame/support/test/tests/pallet_instance.rs | 129 ++++++++++- .../storage_result_query_missing_generics.rs | 21 ++ ...orage_result_query_missing_generics.stderr | 15 ++ ...storage_result_query_multiple_type_args.rs | 23 ++ ...age_result_query_multiple_type_args.stderr | 5 + ...ge_result_query_no_defined_pallet_error.rs | 16 ++ ...esult_query_no_defined_pallet_error.stderr | 5 + ...age_result_query_parenthesized_generics.rs | 22 ++ ...result_query_parenthesized_generics.stderr | 5 + ...storage_result_query_wrong_generic_kind.rs | 22 ++ ...age_result_query_wrong_generic_kind.stderr | 5 + 16 files changed, 770 insertions(+), 77 deletions(-) create mode 100644 frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.rs create mode 100644 frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.stderr create mode 100644 frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.rs create mode 100644 frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.stderr create mode 100644 frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs create mode 100644 frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.stderr create mode 100644 frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.rs create mode 100644 frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.stderr create mode 100644 frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.rs create mode 100644 frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.stderr diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 657968e17a80c..181f35b545496 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -19,7 +19,9 @@ use crate::pallet::{ parse::storage::{Metadata, QueryKind, StorageDef, StorageGenerics}, Def, }; -use std::collections::HashMap; +use quote::ToTokens; +use std::{collections::HashMap, ops::IndexMut}; +use syn::spanned::Spanned; /// Generate the prefix_ident related to the storage. /// prefix_ident is used for the prefix struct to be given to storage as first generic param. @@ -84,12 +86,28 @@ fn check_prefix_duplicates( Ok(()) } +pub struct ResultOnEmptyStructMetadata { + /// The Rust ident that is going to be used as the name of the OnEmpty struct. + pub name: syn::Ident, + /// The path to the error type being returned by the ResultQuery. + pub error_path: syn::Path, + /// The visibility of the OnEmpty struct. + pub visibility: syn::Visibility, + /// The type of the storage item. + pub value_ty: syn::Type, + /// The name of the pallet error enum variant that is going to be returned. + pub variant_name: syn::Ident, + /// The span used to report compilation errors about the OnEmpty struct. + pub span: proc_macro2::Span, +} + /// /// * if generics are unnamed: replace the first generic `_` by the generated prefix structure /// * if generics are named: reorder the generic, remove their name, and add the missing ones. /// * Add `#[allow(type_alias_bounds)]` -pub fn process_generics(def: &mut Def) -> syn::Result<()> { +pub fn process_generics(def: &mut Def) -> syn::Result> { let frame_support = &def.frame_support; + let mut on_empty_struct_metadata = Vec::new(); for storage_def in def.storages.iter_mut() { let item = &mut def.item.content.as_mut().expect("Checked by def").1[storage_def.index]; @@ -120,27 +138,72 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> { let default_query_kind: syn::Type = syn::parse_quote!(#frame_support::storage::types::OptionQuery); - let default_on_empty: syn::Type = syn::parse_quote!(#frame_support::traits::GetDefault); + let mut default_on_empty = |value_ty: syn::Type| -> syn::Type { + if let Some(QueryKind::ResultQuery(error_path, variant_name)) = + storage_def.query_kind.as_ref() + { + let on_empty_ident = + quote::format_ident!("__Frame_Internal_Get{}Result", storage_def.ident); + on_empty_struct_metadata.push(ResultOnEmptyStructMetadata { + name: on_empty_ident.clone(), + visibility: storage_def.vis.clone(), + value_ty, + error_path: error_path.clone(), + variant_name: variant_name.clone(), + span: storage_def.attr_span, + }); + return syn::parse_quote!(#on_empty_ident) + } + syn::parse_quote!(#frame_support::traits::GetDefault) + }; let default_max_values: syn::Type = syn::parse_quote!(#frame_support::traits::GetDefault); + let set_result_query_type_parameter = |query_type: &mut syn::Type| -> syn::Result<()> { + if let Some(QueryKind::ResultQuery(error_path, _)) = storage_def.query_kind.as_ref() { + if let syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) = + query_type + { + if let Some(seg) = segments.last_mut() { + if let syn::PathArguments::AngleBracketed( + syn::AngleBracketedGenericArguments { args, .. }, + ) = &mut seg.arguments + { + args.clear(); + args.push(syn::GenericArgument::Type(syn::parse_quote!(#error_path))); + } + } + } else { + let msg = format!( + "Invalid pallet::storage, unexpected type for query, expected ResultQuery \ + with 1 type parameter, found `{}`", + query_type.to_token_stream().to_string() + ); + return Err(syn::Error::new(query_type.span(), msg)) + } + } + Ok(()) + }; + if let Some(named_generics) = storage_def.named_generics.clone() { args.args.clear(); args.args.push(syn::parse_quote!( #prefix_ident<#type_use_gen> )); match named_generics { StorageGenerics::Value { value, query_kind, on_empty } => { - args.args.push(syn::GenericArgument::Type(value)); - let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); + args.args.push(syn::GenericArgument::Type(value.clone())); + let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); + set_result_query_type_parameter(&mut query_kind)?; args.args.push(syn::GenericArgument::Type(query_kind)); - let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone()); + let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value)); args.args.push(syn::GenericArgument::Type(on_empty)); }, StorageGenerics::Map { hasher, key, value, query_kind, on_empty, max_values } => { args.args.push(syn::GenericArgument::Type(hasher)); args.args.push(syn::GenericArgument::Type(key)); - args.args.push(syn::GenericArgument::Type(value)); - let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); + args.args.push(syn::GenericArgument::Type(value.clone())); + let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); + set_result_query_type_parameter(&mut query_kind)?; args.args.push(syn::GenericArgument::Type(query_kind)); - let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone()); + let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value)); args.args.push(syn::GenericArgument::Type(on_empty)); let max_values = max_values.unwrap_or_else(|| default_max_values.clone()); args.args.push(syn::GenericArgument::Type(max_values)); @@ -155,10 +218,11 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> { } => { args.args.push(syn::GenericArgument::Type(hasher)); args.args.push(syn::GenericArgument::Type(key)); - args.args.push(syn::GenericArgument::Type(value)); - let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); + args.args.push(syn::GenericArgument::Type(value.clone())); + let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); + set_result_query_type_parameter(&mut query_kind)?; args.args.push(syn::GenericArgument::Type(query_kind)); - let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone()); + let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value)); args.args.push(syn::GenericArgument::Type(on_empty)); let max_values = max_values.unwrap_or_else(|| default_max_values.clone()); args.args.push(syn::GenericArgument::Type(max_values)); @@ -177,20 +241,22 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> { args.args.push(syn::GenericArgument::Type(key1)); args.args.push(syn::GenericArgument::Type(hasher2)); args.args.push(syn::GenericArgument::Type(key2)); - args.args.push(syn::GenericArgument::Type(value)); - let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); + args.args.push(syn::GenericArgument::Type(value.clone())); + let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); + set_result_query_type_parameter(&mut query_kind)?; args.args.push(syn::GenericArgument::Type(query_kind)); - let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone()); + let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value)); args.args.push(syn::GenericArgument::Type(on_empty)); let max_values = max_values.unwrap_or_else(|| default_max_values.clone()); args.args.push(syn::GenericArgument::Type(max_values)); }, StorageGenerics::NMap { keygen, value, query_kind, on_empty, max_values } => { args.args.push(syn::GenericArgument::Type(keygen)); - args.args.push(syn::GenericArgument::Type(value)); - let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); + args.args.push(syn::GenericArgument::Type(value.clone())); + let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); + set_result_query_type_parameter(&mut query_kind)?; args.args.push(syn::GenericArgument::Type(query_kind)); - let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone()); + let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value)); args.args.push(syn::GenericArgument::Type(on_empty)); let max_values = max_values.unwrap_or_else(|| default_max_values.clone()); args.args.push(syn::GenericArgument::Type(max_values)); @@ -198,10 +264,40 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> { } } else { args.args[0] = syn::parse_quote!( #prefix_ident<#type_use_gen> ); + + let (value_idx, query_idx, on_empty_idx) = match storage_def.metadata { + Metadata::Value { .. } => (1, 2, 3), + Metadata::NMap { .. } => (2, 3, 4), + Metadata::Map { .. } | Metadata::CountedMap { .. } => (3, 4, 5), + Metadata::DoubleMap { .. } => (5, 6, 7), + }; + + if query_idx < args.args.len() { + if let syn::GenericArgument::Type(query_kind) = args.args.index_mut(query_idx) { + set_result_query_type_parameter(query_kind)?; + } + } else if let Some(QueryKind::ResultQuery(error_path, _)) = + storage_def.query_kind.as_ref() + { + args.args.push(syn::GenericArgument::Type(syn::parse_quote!(#error_path))) + } + + // Here, we only need to check if OnEmpty is *not* specified, and if so, then we have to + // generate a default OnEmpty struct for it. + if on_empty_idx >= args.args.len() && + matches!(storage_def.query_kind.as_ref(), Some(QueryKind::ResultQuery(_, _))) + { + let value_ty = match args.args[value_idx].clone() { + syn::GenericArgument::Type(ty) => ty, + _ => unreachable!(), + }; + let on_empty = default_on_empty(value_ty); + args.args.push(syn::GenericArgument::Type(on_empty)); + } } } - Ok(()) + Ok(on_empty_struct_metadata) } /// @@ -212,9 +308,10 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> { /// * Add `#[allow(type_alias_bounds)]` on storages type alias /// * generate metadatas pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { - if let Err(e) = process_generics(def) { - return e.into_compile_error() - } + let on_empty_struct_metadata = match process_generics(def) { + Ok(idents) => idents, + Err(e) => return e.into_compile_error(), + }; // Check for duplicate prefixes let mut prefix_set = HashMap::new(); @@ -277,6 +374,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), + QueryKind::ResultQuery(error_path, _) => + quote::quote_spanned!(storage.attr_span => + Result<#value, #error_path> + ), QueryKind::ValueQuery => quote::quote!(#value), }; quote::quote_spanned!(storage.attr_span => @@ -296,6 +397,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), + QueryKind::ResultQuery(error_path, _) => + quote::quote_spanned!(storage.attr_span => + Result<#value, #error_path> + ), QueryKind::ValueQuery => quote::quote!(#value), }; quote::quote_spanned!(storage.attr_span => @@ -317,6 +422,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), + QueryKind::ResultQuery(error_path, _) => + quote::quote_spanned!(storage.attr_span => + Result<#value, #error_path> + ), QueryKind::ValueQuery => quote::quote!(#value), }; quote::quote_spanned!(storage.attr_span => @@ -338,6 +447,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), + QueryKind::ResultQuery(error_path, _) => + quote::quote_spanned!(storage.attr_span => + Result<#value, #error_path> + ), QueryKind::ValueQuery => quote::quote!(#value), }; quote::quote_spanned!(storage.attr_span => @@ -361,6 +474,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), + QueryKind::ResultQuery(error_path, _) => + quote::quote_spanned!(storage.attr_span => + Result<#value, #error_path> + ), QueryKind::ValueQuery => quote::quote!(#value), }; quote::quote_spanned!(storage.attr_span => @@ -459,6 +576,61 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { ) }); + let on_empty_structs = on_empty_struct_metadata.into_iter().map(|metadata| { + use crate::pallet::parse::GenericKind; + use syn::{GenericArgument, Path, PathArguments, PathSegment, Type, TypePath}; + + let ResultOnEmptyStructMetadata { + name, + visibility, + value_ty, + error_path, + variant_name, + span, + } = metadata; + + let generic_kind = match error_path.segments.last() { + Some(PathSegment { arguments: PathArguments::AngleBracketed(args), .. }) => { + let (has_config, has_instance) = + args.args.iter().fold((false, false), |(has_config, has_instance), arg| { + match arg { + GenericArgument::Type(Type::Path(TypePath { + path: Path { segments, .. }, + .. + })) => { + let maybe_config = + segments.first().map_or(false, |seg| seg.ident == "T"); + let maybe_instance = + segments.first().map_or(false, |seg| seg.ident == "I"); + + (has_config || maybe_config, has_instance || maybe_instance) + }, + _ => (has_config, has_instance), + } + }); + GenericKind::from_gens(has_config, has_instance).unwrap_or(GenericKind::None) + }, + _ => GenericKind::None, + }; + let type_impl_gen = generic_kind.type_impl_gen(proc_macro2::Span::call_site()); + let config_where_clause = &def.config.where_clause; + + quote::quote_spanned!(span => + #[doc(hidden)] + #[allow(non_camel_case_types)] + #visibility struct #name; + + impl<#type_impl_gen> #frame_support::traits::Get> + for #name + #config_where_clause + { + fn get() -> Result<#value_ty, #error_path> { + Err(<#error_path>::#variant_name) + } + } + ) + }); + let mut where_clauses = vec![&def.config.where_clause]; where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause)); let completed_where_clause = super::merge_where_clauses(&where_clauses); @@ -489,5 +661,6 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { #( #getters )* #( #prefix_structs )* + #( #on_empty_structs )* ) } diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 1f1bb5b2f26ad..97abdd3ad0977 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -29,6 +29,7 @@ mod keyword { syn::custom_keyword!(storage_prefix); syn::custom_keyword!(unbounded); syn::custom_keyword!(OptionQuery); + syn::custom_keyword!(ResultQuery); syn::custom_keyword!(ValueQuery); } @@ -129,6 +130,7 @@ pub enum Metadata { pub enum QueryKind { OptionQuery, + ResultQuery(syn::Path, syn::Ident), ValueQuery, } @@ -153,7 +155,7 @@ pub struct StorageDef { /// Optional expression that evaluates to a type that can be used as StoragePrefix instead of /// ident. pub rename_as: Option, - /// Whereas the querytype of the storage is OptionQuery or ValueQuery. + /// Whereas the querytype of the storage is OptionQuery, ResultQuery or ValueQuery. /// Note that this is best effort as it can't be determined when QueryKind is generic, and /// result can be false if user do some unexpected type alias. pub query_kind: Option, @@ -695,21 +697,105 @@ impl StorageDef { let (named_generics, metadata, query_kind) = process_generics(&typ.path.segments[0])?; let query_kind = query_kind - .map(|query_kind| match query_kind { - syn::Type::Path(path) - if path.path.segments.last().map_or(false, |s| s.ident == "OptionQuery") => - Some(QueryKind::OptionQuery), - syn::Type::Path(path) - if path.path.segments.last().map_or(false, |s| s.ident == "ValueQuery") => - Some(QueryKind::ValueQuery), - _ => None, + .map(|query_kind| { + use syn::{ + AngleBracketedGenericArguments, GenericArgument, Path, PathArguments, Type, + TypePath, + }; + + let result_query = match query_kind { + Type::Path(path) + if path + .path + .segments + .last() + .map_or(false, |s| s.ident == "OptionQuery") => + return Ok(Some(QueryKind::OptionQuery)), + Type::Path(TypePath { path: Path { segments, .. }, .. }) + if segments.last().map_or(false, |s| s.ident == "ResultQuery") => + segments + .last() + .expect("segments is checked to have the last value; qed") + .clone(), + Type::Path(path) + if path.path.segments.last().map_or(false, |s| s.ident == "ValueQuery") => + return Ok(Some(QueryKind::ValueQuery)), + _ => return Ok(None), + }; + + let error_type = match result_query.arguments { + PathArguments::AngleBracketed(AngleBracketedGenericArguments { + args, .. + }) => { + if args.len() != 1 { + let msg = format!( + "Invalid pallet::storage, unexpected number of generic arguments \ + for ResultQuery, expected 1 type argument, found {}", + args.len(), + ); + return Err(syn::Error::new(args.span(), msg)) + } + + args[0].clone() + }, + args => { + let msg = format!( + "Invalid pallet::storage, unexpected generic args for ResultQuery, \ + expected angle-bracketed arguments, found `{}`", + args.to_token_stream().to_string() + ); + return Err(syn::Error::new(args.span(), msg)) + }, + }; + + match error_type { + GenericArgument::Type(Type::Path(TypePath { + path: Path { segments: err_variant, leading_colon }, + .. + })) => { + if err_variant.len() < 2 { + let msg = format!( + "Invalid pallet::storage, unexpected number of path segments for \ + the generics in ResultQuery, expected a path with at least 2 \ + segments, found {}", + err_variant.len(), + ); + return Err(syn::Error::new(err_variant.span(), msg)) + } + let mut error = err_variant.clone(); + let err_variant = error + .pop() + .expect("Checked to have at least 2; qed") + .into_value() + .ident; + + // Necessary here to eliminate the last double colon + let last = + error.pop().expect("Checked to have at least 2; qed").into_value(); + error.push_value(last); + + Ok(Some(QueryKind::ResultQuery( + syn::Path { leading_colon: leading_colon.clone(), segments: error }, + err_variant, + ))) + }, + gen_arg => { + let msg = format!( + "Invalid pallet::storage, unexpected generic argument kind, expected a \ + type path to a `PalletError` enum variant, found `{}`", + gen_arg.to_token_stream().to_string(), + ); + Err(syn::Error::new(gen_arg.span(), msg)) + }, + } }) - .unwrap_or(Some(QueryKind::OptionQuery)); // This value must match the default generic. + .transpose()? + .unwrap_or(Some(QueryKind::OptionQuery)); if let (None, Some(getter)) = (query_kind.as_ref(), getter.as_ref()) { let msg = "Invalid pallet::storage, cannot generate getter because QueryKind is not \ - identifiable. QueryKind must be `OptionQuery`, `ValueQuery`, or default one to be \ - identifiable."; + identifiable. QueryKind must be `OptionQuery`, `ResultQuery`, `ValueQuery`, or default \ + one to be identifiable."; return Err(syn::Error::new(getter.span(), msg)) } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 7e4c944330fe3..72551980bc7e9 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -281,79 +281,85 @@ pub use frame_support_procedural::storage_alias; macro_rules! parameter_types { ( $( #[ $attr:meta ] )* - $vis:vis const $name:ident: $type:ty = $value:expr; + $vis:vis const $name:ident $(< $($ty_params:ident),* >)?: $type:ty = $value:expr; $( $rest:tt )* ) => ( $( #[ $attr ] )* - $vis struct $name; - $crate::parameter_types!(IMPL_CONST $name , $type , $value); + $vis struct $name $( + < $($ty_params),* >( $($crate::sp_std::marker::PhantomData<$ty_params>),* ) + )?; + $crate::parameter_types!(IMPL_CONST $name , $type , $value $( $(, $ty_params)* )?); $crate::parameter_types!( $( $rest )* ); ); ( $( #[ $attr:meta ] )* - $vis:vis $name:ident: $type:ty = $value:expr; + $vis:vis $name:ident $(< $($ty_params:ident),* >)?: $type:ty = $value:expr; $( $rest:tt )* ) => ( $( #[ $attr ] )* - $vis struct $name; - $crate::parameter_types!(IMPL $name, $type, $value); + $vis struct $name $( + < $($ty_params),* >( $($crate::sp_std::marker::PhantomData<$ty_params>),* ) + )?; + $crate::parameter_types!(IMPL $name, $type, $value $( $(, $ty_params)* )?); $crate::parameter_types!( $( $rest )* ); ); ( $( #[ $attr:meta ] )* - $vis:vis storage $name:ident: $type:ty = $value:expr; + $vis:vis storage $name:ident $(< $($ty_params:ident),* >)?: $type:ty = $value:expr; $( $rest:tt )* ) => ( $( #[ $attr ] )* - $vis struct $name; - $crate::parameter_types!(IMPL_STORAGE $name, $type, $value); + $vis struct $name $( + < $($ty_params),* >( $($crate::sp_std::marker::PhantomData<$ty_params>),* ) + )?; + $crate::parameter_types!(IMPL_STORAGE $name, $type, $value $( $(, $ty_params)* )?); $crate::parameter_types!( $( $rest )* ); ); () => (); - (IMPL_CONST $name:ident, $type:ty, $value:expr) => { - impl $name { + (IMPL_CONST $name:ident, $type:ty, $value:expr $(, $ty_params:ident)*) => { + impl< $($ty_params),* > $name< $($ty_params),* > { /// Returns the value of this parameter type. pub const fn get() -> $type { $value } } - impl> $crate::traits::Get for $name { - fn get() -> I { - I::from(Self::get()) + impl<_I: From<$type> $(, $ty_params)*> $crate::traits::Get<_I> for $name< $($ty_params),* > { + fn get() -> _I { + _I::from(Self::get()) } } - impl $crate::traits::TypedGet for $name { + impl< $($ty_params),* > $crate::traits::TypedGet for $name< $($ty_params),* > { type Type = $type; fn get() -> $type { Self::get() } } }; - (IMPL $name:ident, $type:ty, $value:expr) => { - impl $name { + (IMPL $name:ident, $type:ty, $value:expr $(, $ty_params:ident)*) => { + impl< $($ty_params),* > $name< $($ty_params),* > { /// Returns the value of this parameter type. pub fn get() -> $type { $value } } - impl> $crate::traits::Get for $name { - fn get() -> I { - I::from(Self::get()) + impl<_I: From<$type>, $(, $ty_params)*> $crate::traits::Get<_I> for $name< $($ty_params),* > { + fn get() -> _I { + _I::from(Self::get()) } } - impl $crate::traits::TypedGet for $name { + impl< $($ty_params),* > $crate::traits::TypedGet for $name< $($ty_params),* > { type Type = $type; fn get() -> $type { Self::get() } } }; - (IMPL_STORAGE $name:ident, $type:ty, $value:expr) => { - impl $name { + (IMPL_STORAGE $name:ident, $type:ty, $value:expr $(, $ty_params:ident)*) => { + impl< $($ty_params),* > $name< $($ty_params),* > { /// Returns the key for this parameter type. #[allow(unused)] pub fn key() -> [u8; 16] { @@ -379,13 +385,13 @@ macro_rules! parameter_types { } } - impl> $crate::traits::Get for $name { - fn get() -> I { - I::from(Self::get()) + impl<_I: From<$type> $(, $ty_params)*> $crate::traits::Get<_I> for $name< $($ty_params),* > { + fn get() -> _I { + _I::from(Self::get()) } } - impl $crate::traits::TypedGet for $name { + impl< $($ty_params),* > $crate::traits::TypedGet for $name< $($ty_params),* > { type Type = $type; fn get() -> $type { Self::get() @@ -1360,8 +1366,8 @@ pub mod pallet_prelude { storage::{ bounded_vec::BoundedVec, types::{ - CountedStorageMap, Key as NMapKey, OptionQuery, StorageDoubleMap, StorageMap, - StorageNMap, StorageValue, ValueQuery, + CountedStorageMap, Key as NMapKey, OptionQuery, ResultQuery, StorageDoubleMap, + StorageMap, StorageNMap, StorageValue, ValueQuery, }, }, traits::{ @@ -1835,6 +1841,23 @@ pub mod pallet_prelude { /// All the `cfg` attributes are automatically copied to the items generated for the storage, /// i.e. the getter, storage prefix, and the metadata element etc. /// +/// Any type placed as the `QueryKind` parameter must implement +/// [`frame_support::storage::types::QueryKindTrait`]. There are 3 implementations of this +/// trait by default: +/// 1. [`frame_support::storage::types::OptionQuery`], the default `QueryKind` used when this +/// type parameter is omitted. Specifying this as the `QueryKind` would cause storage map +/// APIs that return a `QueryKind` to instead return an `Option`, returning `Some` when a +/// value does exist under a specified storage key, and `None` otherwise. +/// 2. [`frame_support::storage::types::ValueQuery`] causes storage map APIs that return a +/// `QueryKind` to instead return the value type. In cases where a value does not exist +/// under a specified storage key, the `OnEmpty` type parameter on `QueryKindTrait` is used +/// to return an appropriate value. +/// 3. [`frame_support::storage::types::ResultQuery`] causes storage map APIs that return a +/// `QueryKind` to instead return a `Result`, with `T` being the value type and `E` +/// being the pallet error type specified by the `#[pallet::error]` attribute. In cases +/// where a value does not exist under a specified storage key, an `Err` with the specified +/// pallet error variant is returned. +/// /// NOTE: If the `QueryKind` generic parameter is still generic at this stage or is using some /// type alias then the generation of the getter might fail. In this case the getter can be /// implemented manually. diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index 0706e9fb377e2..f87da5de12274 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -42,9 +42,11 @@ pub use value::StorageValue; /// Trait implementing how the storage optional value is converted into the queried type. /// /// It is implemented by: -/// * `OptionQuery` which convert an optional value to an optional value, user when querying storage -/// will get an optional value. -/// * `ValueQuery` which convert an optional value to a value, user when querying storage will get a +/// * `OptionQuery` which converts an optional value to an optional value, used when querying +/// storage returns an optional value. +/// * `ResultQuery` which converts an optional value to a result value, used when querying storage +/// returns a result value. +/// * `ValueQuery` which converts an optional value to a value, used when querying storage returns a /// value. pub trait QueryKindTrait { /// Metadata for the storage kind. @@ -85,6 +87,30 @@ where } } +/// Implement QueryKindTrait with query being `Result` +pub struct ResultQuery(sp_std::marker::PhantomData); +impl QueryKindTrait for ResultQuery +where + Value: FullCodec + 'static, + Error: FullCodec + 'static, + OnEmpty: crate::traits::Get>, +{ + const METADATA: StorageEntryModifier = StorageEntryModifier::Optional; + + type Query = Result; + + fn from_optional_value_to_query(v: Option) -> Self::Query { + match v { + Some(v) => Ok(v), + None => OnEmpty::get(), + } + } + + fn from_query_to_optional_value(v: Self::Query) -> Option { + v.ok() + } +} + /// Implement QueryKindTrait with query being `Value` pub struct ValueQuery; impl QueryKindTrait for ValueQuery diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index c4bbc59c70373..e96e52d3d2c6e 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -229,6 +229,7 @@ pub mod pallet { pub enum Error { /// doc comment put into metadata InsufficientProposersBalance, + NonExistentStorageValue, Code(u8), #[codec(skip)] Skipped(u128), @@ -282,6 +283,10 @@ pub mod pallet { pub type Map2 = StorageMap>; + #[pallet::storage] + pub type Map3 = + StorageMap<_, Blake2_128Concat, u32, u64, ResultQuery::NonExistentStorageValue>>; + #[pallet::storage] pub type DoubleMap = StorageDoubleMap<_, Blake2_128Concat, u8, Twox64Concat, u16, u32>; @@ -295,6 +300,17 @@ pub mod pallet { MaxValues = ConstU32<5>, >; + #[pallet::storage] + pub type DoubleMap3 = StorageDoubleMap< + _, + Blake2_128Concat, + u32, + Twox64Concat, + u64, + u128, + ResultQuery::NonExistentStorageValue>, + >; + #[pallet::storage] #[pallet::getter(fn nmap)] pub type NMap = StorageNMap<_, storage::Key, u32>; @@ -307,6 +323,15 @@ pub mod pallet { MaxValues = ConstU32<11>, >; + #[pallet::storage] + #[pallet::getter(fn nmap3)] + pub type NMap3 = StorageNMap< + _, + (NMapKey, NMapKey), + u128, + ResultQuery::NonExistentStorageValue>, + >; + #[pallet::storage] #[pallet::getter(fn conditional_value)] #[cfg(feature = "conditional-storage")] @@ -934,6 +959,16 @@ fn storage_expand() { assert_eq!(unhashed::get::(&k), Some(2u32)); assert_eq!(&k[..32], &>::final_prefix()); + pallet::Map3::::insert(1, 2); + let mut k = [twox_128(b"Example"), twox_128(b"Map3")].concat(); + k.extend(1u32.using_encoded(blake2_128_concat)); + assert_eq!(unhashed::get::(&k), Some(2u64)); + assert_eq!(&k[..32], &>::final_prefix()); + assert_eq!( + pallet::Map3::::get(2), + Err(pallet::Error::::NonExistentStorageValue), + ); + pallet::DoubleMap::::insert(&1, &2, &3); let mut k = [twox_128(b"Example"), twox_128(b"DoubleMap")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); @@ -948,6 +983,17 @@ fn storage_expand() { assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); + pallet::DoubleMap3::::insert(&1, &2, &3); + let mut k = [twox_128(b"Example"), twox_128(b"DoubleMap3")].concat(); + k.extend(1u32.using_encoded(blake2_128_concat)); + k.extend(2u64.using_encoded(twox_64_concat)); + assert_eq!(unhashed::get::(&k), Some(3u128)); + assert_eq!(&k[..32], &>::final_prefix()); + assert_eq!( + pallet::DoubleMap3::::get(2, 3), + Err(pallet::Error::::NonExistentStorageValue), + ); + pallet::NMap::::insert((&1,), &3); let mut k = [twox_128(b"Example"), twox_128(b"NMap")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); @@ -961,6 +1007,17 @@ fn storage_expand() { assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); + pallet::NMap3::::insert((&1, &2), &3); + let mut k = [twox_128(b"Example"), twox_128(b"NMap3")].concat(); + k.extend(1u8.using_encoded(blake2_128_concat)); + k.extend(2u16.using_encoded(twox_64_concat)); + assert_eq!(unhashed::get::(&k), Some(3u128)); + assert_eq!(&k[..32], &>::final_prefix()); + assert_eq!( + pallet::NMap3::::get((2, 3)), + Err(pallet::Error::::NonExistentStorageValue), + ); + #[cfg(feature = "conditional-storage")] { pallet::ConditionalValue::::put(1); @@ -1171,6 +1228,17 @@ fn metadata() { default: vec![0], docs: vec![], }, + StorageEntryMetadata { + name: "Map3", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + key: meta_type::(), + value: meta_type::(), + hashers: vec![StorageHasher::Blake2_128Concat], + }, + default: vec![1, 1], + docs: vec![], + }, StorageEntryMetadata { name: "DoubleMap", modifier: StorageEntryModifier::Optional, @@ -1199,6 +1267,20 @@ fn metadata() { default: vec![0], docs: vec![], }, + StorageEntryMetadata { + name: "DoubleMap3", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + value: meta_type::(), + key: meta_type::<(u32, u64)>(), + hashers: vec![ + StorageHasher::Blake2_128Concat, + StorageHasher::Twox64Concat, + ], + }, + default: vec![1, 1], + docs: vec![], + }, StorageEntryMetadata { name: "NMap", modifier: StorageEntryModifier::Optional, @@ -1224,6 +1306,20 @@ fn metadata() { default: vec![0], docs: vec![], }, + StorageEntryMetadata { + name: "NMap3", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + key: meta_type::<(u8, u16)>(), + hashers: vec![ + StorageHasher::Blake2_128Concat, + StorageHasher::Twox64Concat, + ], + value: meta_type::(), + }, + default: vec![1, 1], + docs: vec![], + }, #[cfg(feature = "conditional-storage")] StorageEntryMetadata { name: "ConditionalValue", @@ -1436,6 +1532,8 @@ fn test_storage_info() { traits::{StorageInfo, StorageInfoTrait}, }; + // Storage max size is calculated by adding up all the hasher size, the key type size and the + // value type size assert_eq!( Example::storage_info(), vec![ @@ -1465,42 +1563,63 @@ fn test_storage_info() { storage_name: b"Map".to_vec(), prefix: prefix(b"Example", b"Map").to_vec(), max_values: None, - max_size: Some(3 + 16), + max_size: Some(16 + 1 + 2), }, StorageInfo { pallet_name: b"Example".to_vec(), storage_name: b"Map2".to_vec(), prefix: prefix(b"Example", b"Map2").to_vec(), max_values: Some(3), - max_size: Some(6 + 8), + max_size: Some(8 + 2 + 4), + }, + StorageInfo { + pallet_name: b"Example".to_vec(), + storage_name: b"Map3".to_vec(), + prefix: prefix(b"Example", b"Map3").to_vec(), + max_values: None, + max_size: Some(16 + 4 + 8), }, StorageInfo { pallet_name: b"Example".to_vec(), storage_name: b"DoubleMap".to_vec(), prefix: prefix(b"Example", b"DoubleMap").to_vec(), max_values: None, - max_size: Some(7 + 16 + 8), + max_size: Some(16 + 1 + 8 + 2 + 4), }, StorageInfo { pallet_name: b"Example".to_vec(), storage_name: b"DoubleMap2".to_vec(), prefix: prefix(b"Example", b"DoubleMap2").to_vec(), max_values: Some(5), - max_size: Some(14 + 8 + 16), + max_size: Some(8 + 2 + 16 + 4 + 8), + }, + StorageInfo { + pallet_name: b"Example".to_vec(), + storage_name: b"DoubleMap3".to_vec(), + prefix: prefix(b"Example", b"DoubleMap3").to_vec(), + max_values: None, + max_size: Some(16 + 4 + 8 + 8 + 16), }, StorageInfo { pallet_name: b"Example".to_vec(), storage_name: b"NMap".to_vec(), prefix: prefix(b"Example", b"NMap").to_vec(), max_values: None, - max_size: Some(5 + 16), + max_size: Some(16 + 1 + 4), }, StorageInfo { pallet_name: b"Example".to_vec(), storage_name: b"NMap2".to_vec(), prefix: prefix(b"Example", b"NMap2").to_vec(), max_values: Some(11), - max_size: Some(14 + 8 + 16), + max_size: Some(8 + 2 + 16 + 4 + 8), + }, + StorageInfo { + pallet_name: b"Example".to_vec(), + storage_name: b"NMap3".to_vec(), + prefix: prefix(b"Example", b"NMap3").to_vec(), + max_values: None, + max_size: Some(16 + 1 + 8 + 2 + 16), }, #[cfg(feature = "conditional-storage")] { @@ -1519,7 +1638,7 @@ fn test_storage_info() { storage_name: b"ConditionalMap".to_vec(), prefix: prefix(b"Example", b"ConditionalMap").to_vec(), max_values: Some(12), - max_size: Some(6 + 8), + max_size: Some(8 + 2 + 4), } }, #[cfg(feature = "conditional-storage")] @@ -1529,7 +1648,7 @@ fn test_storage_info() { storage_name: b"ConditionalDoubleMap".to_vec(), prefix: prefix(b"Example", b"ConditionalDoubleMap").to_vec(), max_values: None, - max_size: Some(7 + 16 + 8), + max_size: Some(16 + 1 + 8 + 2 + 4), } }, #[cfg(feature = "conditional-storage")] @@ -1539,7 +1658,7 @@ fn test_storage_info() { storage_name: b"ConditionalNMap".to_vec(), prefix: prefix(b"Example", b"ConditionalNMap").to_vec(), max_values: None, - max_size: Some(7 + 16 + 8), + max_size: Some(16 + 1 + 8 + 2 + 4), } }, StorageInfo { @@ -1547,7 +1666,7 @@ fn test_storage_info() { storage_name: b"RenamedCountedMap".to_vec(), prefix: prefix(b"Example", b"RenamedCountedMap").to_vec(), max_values: None, - max_size: Some(1 + 4 + 8), + max_size: Some(8 + 1 + 4), }, StorageInfo { pallet_name: b"Example".to_vec(), diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 360a73e5ea2a3..f4ef5f802c44f 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -31,7 +31,7 @@ use sp_runtime::{DispatchError, ModuleError}; #[frame_support::pallet] pub mod pallet { use codec::MaxEncodedLen; - use frame_support::{pallet_prelude::*, scale_info}; + use frame_support::{pallet_prelude::*, parameter_types, scale_info}; use frame_system::pallet_prelude::*; use sp_std::any::TypeId; @@ -104,9 +104,11 @@ pub mod pallet { } #[pallet::error] + #[derive(PartialEq, Eq)] pub enum Error { /// doc comment put into metadata InsufficientProposersBalance, + NonExistentStorageValue, } #[pallet::event] @@ -128,6 +130,20 @@ pub mod pallet { #[pallet::storage] pub type Map2 = StorageMap<_, Twox64Concat, u16, u32>; + parameter_types! { + pub const Map3Default: Result> = Ok(1337); + } + + #[pallet::storage] + pub type Map3 = StorageMap< + _, + Blake2_128Concat, + u32, + u64, + ResultQuery::NonExistentStorageValue>, + Map3Default, + >; + #[pallet::storage] pub type DoubleMap = StorageDoubleMap<_, Blake2_128Concat, u8, Twox64Concat, u16, u32>; @@ -136,6 +152,17 @@ pub mod pallet { pub type DoubleMap2 = StorageDoubleMap<_, Twox64Concat, u16, Blake2_128Concat, u32, u64>; + #[pallet::storage] + pub type DoubleMap3 = StorageDoubleMap< + _, + Blake2_128Concat, + u32, + Twox64Concat, + u64, + u128, + ResultQuery::NonExistentStorageValue>, + >; + #[pallet::storage] #[pallet::getter(fn nmap)] pub type NMap = StorageNMap<_, storage::Key, u32>; @@ -145,6 +172,15 @@ pub mod pallet { pub type NMap2 = StorageNMap<_, (storage::Key, storage::Key), u64>; + #[pallet::storage] + #[pallet::getter(fn nmap3)] + pub type NMap3 = StorageNMap< + _, + (NMapKey, NMapKey), + u128, + ResultQuery::NonExistentStorageValue>, + >; + #[pallet::genesis_config] #[derive(Default)] pub struct GenesisConfig { @@ -436,6 +472,13 @@ fn storage_expand() { assert_eq!(unhashed::get::(&k), Some(2u32)); assert_eq!(&k[..32], &>::final_prefix()); + >::insert(1, 2); + let mut k = [twox_128(b"Example"), twox_128(b"Map3")].concat(); + k.extend(1u32.using_encoded(blake2_128_concat)); + assert_eq!(unhashed::get::(&k), Some(2u64)); + assert_eq!(&k[..32], &>::final_prefix()); + assert_eq!(>::get(2), Ok(1337)); + >::insert(&1, &2, &3); let mut k = [twox_128(b"Example"), twox_128(b"DoubleMap")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); @@ -450,6 +493,17 @@ fn storage_expand() { assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); + >::insert(&1, &2, &3); + let mut k = [twox_128(b"Example"), twox_128(b"DoubleMap3")].concat(); + k.extend(1u32.using_encoded(blake2_128_concat)); + k.extend(2u64.using_encoded(twox_64_concat)); + assert_eq!(unhashed::get::(&k), Some(3u128)); + assert_eq!(&k[..32], &>::final_prefix()); + assert_eq!( + >::get(2, 3), + Err(pallet::Error::::NonExistentStorageValue), + ); + >::insert((&1,), &3); let mut k = [twox_128(b"Example"), twox_128(b"NMap")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); @@ -462,6 +516,17 @@ fn storage_expand() { k.extend(2u32.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); + + >::insert((&1, &2), &3); + let mut k = [twox_128(b"Example"), twox_128(b"NMap3")].concat(); + k.extend(1u8.using_encoded(blake2_128_concat)); + k.extend(2u16.using_encoded(twox_64_concat)); + assert_eq!(unhashed::get::(&k), Some(3u128)); + assert_eq!(&k[..32], &>::final_prefix()); + assert_eq!( + >::get((2, 3)), + Err(pallet::Error::::NonExistentStorageValue), + ); }); TestExternalities::default().execute_with(|| { @@ -481,6 +546,13 @@ fn storage_expand() { assert_eq!(unhashed::get::(&k), Some(2u32)); assert_eq!(&k[..32], &>::final_prefix()); + >::insert(1, 2); + let mut k = [twox_128(b"Instance1Example"), twox_128(b"Map3")].concat(); + k.extend(1u32.using_encoded(blake2_128_concat)); + assert_eq!(unhashed::get::(&k), Some(2u64)); + assert_eq!(&k[..32], &>::final_prefix()); + assert_eq!(>::get(2), Ok(1337)); + >::insert(&1, &2, &3); let mut k = [twox_128(b"Instance1Example"), twox_128(b"DoubleMap")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); @@ -495,6 +567,17 @@ fn storage_expand() { assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); + >::insert(&1, &2, &3); + let mut k = [twox_128(b"Instance1Example"), twox_128(b"DoubleMap3")].concat(); + k.extend(1u32.using_encoded(blake2_128_concat)); + k.extend(2u64.using_encoded(twox_64_concat)); + assert_eq!(unhashed::get::(&k), Some(3u128)); + assert_eq!(&k[..32], &>::final_prefix()); + assert_eq!( + >::get(2, 3), + Err(pallet::Error::::NonExistentStorageValue), + ); + >::insert((&1,), &3); let mut k = [twox_128(b"Instance1Example"), twox_128(b"NMap")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); @@ -507,6 +590,17 @@ fn storage_expand() { k.extend(2u32.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); + + >::insert((&1, &2), &3); + let mut k = [twox_128(b"Instance1Example"), twox_128(b"NMap3")].concat(); + k.extend(1u8.using_encoded(blake2_128_concat)); + k.extend(2u16.using_encoded(twox_64_concat)); + assert_eq!(unhashed::get::(&k), Some(3u128)); + assert_eq!(&k[..32], &>::final_prefix()); + assert_eq!( + >::get((2, 3)), + Err(pallet::Error::::NonExistentStorageValue), + ); }); } @@ -688,6 +782,17 @@ fn metadata() { default: vec![0], docs: vec![], }, + StorageEntryMetadata { + name: "Map3", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + key: scale_info::meta_type::(), + value: scale_info::meta_type::(), + hashers: vec![StorageHasher::Blake2_128Concat], + }, + default: vec![0, 57, 5, 0, 0, 0, 0, 0, 0], + docs: vec![], + }, StorageEntryMetadata { name: "DoubleMap", modifier: StorageEntryModifier::Optional, @@ -710,6 +815,17 @@ fn metadata() { default: vec![0], docs: vec![], }, + StorageEntryMetadata { + name: "DoubleMap3", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + value: scale_info::meta_type::(), + key: scale_info::meta_type::<(u32, u64)>(), + hashers: vec![StorageHasher::Blake2_128Concat, StorageHasher::Twox64Concat], + }, + default: vec![1, 1], + docs: vec![], + }, StorageEntryMetadata { name: "NMap", modifier: StorageEntryModifier::Optional, @@ -732,6 +848,17 @@ fn metadata() { default: vec![0], docs: vec![], }, + StorageEntryMetadata { + name: "NMap3", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + key: scale_info::meta_type::<(u8, u16)>(), + hashers: vec![StorageHasher::Blake2_128Concat, StorageHasher::Twox64Concat], + value: scale_info::meta_type::(), + }, + default: vec![1, 1], + docs: vec![], + }, ], }), calls: Some(scale_info::meta_type::>().into()), diff --git a/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.rs b/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.rs new file mode 100644 index 0000000000000..a051cc087db58 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.rs @@ -0,0 +1,21 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::error] + pub enum Error { + NonExistentValue, + } + + #[pallet::storage] + type Foo = StorageValue<_, u8, ResultQuery>; +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.stderr b/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.stderr new file mode 100644 index 0000000000000..98265462bbdfb --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_result_query_missing_generics.stderr @@ -0,0 +1,15 @@ +error[E0107]: missing generics for enum `pallet::Error` + --> tests/pallet_ui/storage_result_query_missing_generics.rs:17:56 + | +17 | type Foo = StorageValue<_, u8, ResultQuery>; + | ^^^^^ expected 1 generic argument + | +note: enum defined here, with 1 generic parameter: `T` + --> tests/pallet_ui/storage_result_query_missing_generics.rs:12:11 + | +12 | pub enum Error { + | ^^^^^ - +help: add missing generic argument + | +17 | type Foo = StorageValue<_, u8, ResultQuery::NonExistentValue>>; + | ~~~~~~~~ diff --git a/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.rs b/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.rs new file mode 100644 index 0000000000000..9e0da4b62128d --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.rs @@ -0,0 +1,23 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::BlockNumberFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::error] + pub enum Error { + NonExistentValue, + SomeOtherError, + } + + #[pallet::storage] + type Foo = StorageValue<_, u8, ResultQuery::NonExistentValue, SomeOtherError>>; +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.stderr b/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.stderr new file mode 100644 index 0000000000000..4be2a36eb89e1 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_result_query_multiple_type_args.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::storage, unexpected number of generic arguments for ResultQuery, expected 1 type argument, found 2 + --> tests/pallet_ui/storage_result_query_multiple_type_args.rs:19:56 + | +19 | type Foo = StorageValue<_, u8, ResultQuery::NonExistentValue, SomeOtherError>>; + | ^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs b/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs new file mode 100644 index 0000000000000..102a2261f8333 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs @@ -0,0 +1,16 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::storage] + type Foo = StorageValue<_, u8, ResultQuery>; +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.stderr b/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.stderr new file mode 100644 index 0000000000000..77a7972a5b5cf --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_result_query_no_defined_pallet_error.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::storage, unexpected number of path segments for the generics in ResultQuery, expected a path with at least 2 segments, found 1 + --> tests/pallet_ui/storage_result_query_no_defined_pallet_error.rs:12:56 + | +12 | type Foo = StorageValue<_, u8, ResultQuery>; + | ^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.rs b/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.rs new file mode 100644 index 0000000000000..f30dc3b6a3cc7 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.rs @@ -0,0 +1,22 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::BlockNumberFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::error] + pub enum Error { + NonExistentValue, + } + + #[pallet::storage] + type Foo = StorageValue<_, u8, ResultQuery(NonExistentValue)>; +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.stderr b/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.stderr new file mode 100644 index 0000000000000..caffd846f272a --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_result_query_parenthesized_generics.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::storage, unexpected generic args for ResultQuery, expected angle-bracketed arguments, found `(NonExistentValue)` + --> tests/pallet_ui/storage_result_query_parenthesized_generics.rs:18:55 + | +18 | type Foo = StorageValue<_, u8, ResultQuery(NonExistentValue)>; + | ^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.rs b/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.rs new file mode 100644 index 0000000000000..a5065398b3970 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.rs @@ -0,0 +1,22 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::BlockNumberFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::error] + pub enum Error { + NonExistentValue, + } + + #[pallet::storage] + type Foo = StorageValue<_, u8, ResultQuery<'static>>; +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.stderr b/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.stderr new file mode 100644 index 0000000000000..9f333ae28e6aa --- /dev/null +++ b/frame/support/test/tests/pallet_ui/storage_result_query_wrong_generic_kind.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::storage, unexpected generic argument kind, expected a type path to a `PalletError` enum variant, found `'static` + --> tests/pallet_ui/storage_result_query_wrong_generic_kind.rs:18:56 + | +18 | type Foo = StorageValue<_, u8, ResultQuery<'static>>; + | ^^^^^^^ From 1c2cdfc82be3970cf4019fd46932454d0cc4cf4a Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 25 Aug 2022 16:56:18 +0800 Subject: [PATCH 1088/1472] Allow construct_runtime to take cfg attributes for pallets (#11818) * Allow construct_runtime to take cfg attributes for pallets * cargo fmt * Remove commented out code * Fixes * cargo fmt * Remove inaccurate comments * Fix typo * Properly reverse pallets * Fixes * cargo fmt * Add missing newlines --- Cargo.lock | 11 + frame/support/procedural/Cargo.toml | 2 + .../src/construct_runtime/expand/call.rs | 32 ++- .../src/construct_runtime/expand/config.rs | 21 +- .../src/construct_runtime/expand/event.rs | 43 +++- .../src/construct_runtime/expand/inherent.rs | 55 +++-- .../src/construct_runtime/expand/metadata.rs | 10 + .../src/construct_runtime/expand/origin.rs | 45 +++- .../src/construct_runtime/expand/unsigned.rs | 21 +- .../procedural/src/construct_runtime/mod.rs | 217 ++++++++++++++---- .../procedural/src/construct_runtime/parse.rs | 31 ++- .../feature_gated_system_pallet.rs | 14 ++ .../feature_gated_system_pallet.stderr | 5 + .../invalid_meta_literal.rs | 15 ++ .../invalid_meta_literal.stderr | 6 + .../unsupported_meta_structure.rs | 15 ++ .../unsupported_meta_structure.stderr | 6 + .../unsupported_pallet_attr.rs | 15 ++ .../unsupported_pallet_attr.stderr | 5 + frame/support/test/tests/pallet.rs | 2 + 20 files changed, 483 insertions(+), 88 deletions(-) create mode 100644 frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.stderr create mode 100644 frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.stderr create mode 100644 frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.stderr create mode 100644 frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.stderr diff --git a/Cargo.lock b/Cargo.lock index c99212ba06ba8..ed0d5777d94fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -852,6 +852,15 @@ 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" @@ -2284,7 +2293,9 @@ name = "frame-support-procedural" version = "4.0.0-dev" dependencies = [ "Inflector", + "cfg-expr", "frame-support-procedural-tools", + "itertools", "proc-macro2", "quote", "syn", diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 7ddec39cad9fb..06b8056aff982 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -16,6 +16,8 @@ proc-macro = true [dependencies] Inflector = "0.11.4" +cfg-expr = "0.10.3" +itertools = "0.10.3" proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index 801b69035121d..028e68f0198d1 100644 --- a/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -18,6 +18,7 @@ use crate::construct_runtime::Pallet; use proc_macro2::TokenStream; use quote::quote; +use std::str::FromStr; use syn::Ident; pub fn expand_outer_dispatch( @@ -30,6 +31,7 @@ pub fn expand_outer_dispatch( let mut variant_patterns = Vec::new(); let mut query_call_part_macros = Vec::new(); let mut pallet_names = Vec::new(); + let mut pallet_attrs = Vec::new(); let system_path = &system_pallet.path; let pallets_with_call = pallet_decls.iter().filter(|decl| decl.exists_part("Call")); @@ -38,12 +40,24 @@ pub fn expand_outer_dispatch( let name = &pallet_declaration.name; let path = &pallet_declaration.path; let index = pallet_declaration.index; + let attr = + pallet_declaration.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); - variant_defs.extend( - quote!(#[codec(index = #index)] #name( #scrate::dispatch::CallableCallFor<#name, #runtime> ),), - ); + variant_defs.extend(quote! { + #attr + #[codec(index = #index)] + #name( #scrate::dispatch::CallableCallFor<#name, #runtime> ), + }); variant_patterns.push(quote!(Call::#name(call))); pallet_names.push(name); + pallet_attrs.push(attr); query_call_part_macros.push(quote! { #path::__substrate_call_check::is_call_part_defined!(#name); }); @@ -69,6 +83,7 @@ pub fn expand_outer_dispatch( use #scrate::dispatch::Callable; use core::mem::size_of; &[#( + #pallet_attrs ( stringify!(#pallet_names), size_of::< <#pallet_names as Callable<#runtime>>::Call >(), @@ -101,7 +116,10 @@ pub fn expand_outer_dispatch( impl #scrate::dispatch::GetDispatchInfo for Call { fn get_dispatch_info(&self) -> #scrate::dispatch::DispatchInfo { match self { - #( #variant_patterns => call.get_dispatch_info(), )* + #( + #pallet_attrs + #variant_patterns => call.get_dispatch_info(), + )* } } } @@ -110,6 +128,7 @@ pub fn expand_outer_dispatch( use #scrate::dispatch::GetCallName; match self { #( + #pallet_attrs #variant_patterns => { let function_name = call.get_call_name(); let pallet_name = stringify!(#pallet_names); @@ -121,6 +140,7 @@ pub fn expand_outer_dispatch( fn get_module_names() -> &'static [&'static str] { &[#( + #pallet_attrs stringify!(#pallet_names), )*] } @@ -129,6 +149,7 @@ pub fn expand_outer_dispatch( use #scrate::dispatch::{Callable, GetCallName}; match module { #( + #pallet_attrs stringify!(#pallet_names) => <<#pallet_names as Callable<#runtime>>::Call as GetCallName>::get_call_names(), @@ -157,6 +178,7 @@ pub fn expand_outer_dispatch( fn dispatch_bypass_filter(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { match self { #( + #pallet_attrs #variant_patterns => #scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(call, origin), )* @@ -165,6 +187,7 @@ pub fn expand_outer_dispatch( } #( + #pallet_attrs impl #scrate::traits::IsSubType<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for Call { #[allow(unreachable_patterns)] fn is_sub_type(&self) -> Option<&#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> { @@ -176,6 +199,7 @@ pub fn expand_outer_dispatch( } } + #pallet_attrs impl From<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for Call { fn from(call: #scrate::dispatch::CallableCallFor<#pallet_names, #runtime>) -> Self { #variant_patterns diff --git a/frame/support/procedural/src/construct_runtime/expand/config.rs b/frame/support/procedural/src/construct_runtime/expand/config.rs index a3d70f18529c7..9b731a5825a3c 100644 --- a/frame/support/procedural/src/construct_runtime/expand/config.rs +++ b/frame/support/procedural/src/construct_runtime/expand/config.rs @@ -19,6 +19,7 @@ use crate::construct_runtime::Pallet; use inflector::Inflector; use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; +use std::str::FromStr; use syn::Ident; pub fn expand_outer_config( @@ -40,11 +41,19 @@ pub fn expand_outer_config( let field_name = &Ident::new(&pallet_name.to_string().to_snake_case(), decl.name.span()); let part_is_generic = !pallet_entry.generics.params.is_empty(); + let attr = &decl.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); - types.extend(expand_config_types(runtime, decl, &config, part_is_generic)); - fields.extend(quote!(pub #field_name: #config,)); + types.extend(expand_config_types(attr, runtime, decl, &config, part_is_generic)); + fields.extend(quote!(#attr pub #field_name: #config,)); build_storage_calls - .extend(expand_config_build_storage_call(scrate, runtime, decl, field_name)); + .extend(expand_config_build_storage_call(scrate, attr, runtime, decl, field_name)); query_genesis_config_part_macros.push(quote! { #path::__substrate_genesis_config_check::is_genesis_config_defined!(#pallet_name); #[cfg(feature = "std")] @@ -88,6 +97,7 @@ pub fn expand_outer_config( } fn expand_config_types( + attr: &TokenStream, runtime: &Ident, decl: &Pallet, config: &Ident, @@ -97,14 +107,17 @@ fn expand_config_types( match (decl.instance.as_ref(), part_is_generic) { (Some(inst), true) => quote! { + #attr #[cfg(any(feature = "std", test))] pub type #config = #path::GenesisConfig<#runtime, #path::#inst>; }, (None, true) => quote! { + #attr #[cfg(any(feature = "std", test))] pub type #config = #path::GenesisConfig<#runtime>; }, (_, false) => quote! { + #attr #[cfg(any(feature = "std", test))] pub type #config = #path::GenesisConfig; }, @@ -113,6 +126,7 @@ fn expand_config_types( fn expand_config_build_storage_call( scrate: &TokenStream, + attr: &TokenStream, runtime: &Ident, decl: &Pallet, field_name: &Ident, @@ -125,6 +139,7 @@ fn expand_config_build_storage_call( }; quote! { + #attr #scrate::sp_runtime::BuildModuleGenesisStorage:: <#runtime, #instance>::build_module_genesis_storage(&self.#field_name, storage)?; } diff --git a/frame/support/procedural/src/construct_runtime/expand/event.rs b/frame/support/procedural/src/construct_runtime/expand/event.rs index b242f9641562c..f145327d37af5 100644 --- a/frame/support/procedural/src/construct_runtime/expand/event.rs +++ b/frame/support/procedural/src/construct_runtime/expand/event.rs @@ -18,6 +18,7 @@ use crate::construct_runtime::Pallet; use proc_macro2::TokenStream; use quote::quote; +use std::str::FromStr; use syn::{Generics, Ident}; pub fn expand_outer_event( @@ -97,19 +98,35 @@ fn expand_event_variant( let path = &pallet.path; let variant_name = &pallet.name; let part_is_generic = !generics.params.is_empty(); + let attr = pallet.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); match instance { - Some(inst) if part_is_generic => { - quote!(#[codec(index = #index)] #variant_name(#path::Event<#runtime, #path::#inst>),) + Some(inst) if part_is_generic => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Event<#runtime, #path::#inst>), }, - Some(inst) => { - quote!(#[codec(index = #index)] #variant_name(#path::Event<#path::#inst>),) + Some(inst) => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Event<#path::#inst>), }, - None if part_is_generic => { - quote!(#[codec(index = #index)] #variant_name(#path::Event<#runtime>),) + None if part_is_generic => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Event<#runtime>), }, - None => { - quote!(#[codec(index = #index)] #variant_name(#path::Event),) + None => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Event), }, } } @@ -120,13 +137,23 @@ fn expand_event_conversion( pallet_event: &TokenStream, ) -> TokenStream { let variant_name = &pallet.name; + let attr = pallet.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); quote! { + #attr impl From<#pallet_event> for Event { fn from(x: #pallet_event) -> Self { Event::#variant_name(x) } } + #attr impl TryInto<#pallet_event> for Event { type Error = (); diff --git a/frame/support/procedural/src/construct_runtime/expand/inherent.rs b/frame/support/procedural/src/construct_runtime/expand/inherent.rs index 0f0d538643240..599b34ba87241 100644 --- a/frame/support/procedural/src/construct_runtime/expand/inherent.rs +++ b/frame/support/procedural/src/construct_runtime/expand/inherent.rs @@ -18,6 +18,7 @@ use crate::construct_runtime::Pallet; use proc_macro2::TokenStream; use quote::quote; +use std::str::FromStr; use syn::{Ident, TypePath}; pub fn expand_outer_inherent( @@ -28,14 +29,24 @@ pub fn expand_outer_inherent( scrate: &TokenStream, ) -> TokenStream { let mut pallet_names = Vec::new(); + let mut pallet_attrs = Vec::new(); let mut query_inherent_part_macros = Vec::new(); for pallet_decl in pallet_decls { if pallet_decl.exists_part("Inherent") { let name = &pallet_decl.name; let path = &pallet_decl.path; + let attr = pallet_decl.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); pallet_names.push(name); + pallet_attrs.push(attr); query_inherent_part_macros.push(quote! { #path::__substrate_inherent_check::is_inherent_part_defined!(#name); }); @@ -60,6 +71,7 @@ pub fn expand_outer_inherent( let mut inherents = Vec::new(); #( + #pallet_attrs if let Some(inherent) = #pallet_names::create_inherent(self) { let inherent = <#unchecked_extrinsic as #scrate::inherent::Extrinsic>::new( inherent.into(), @@ -90,22 +102,25 @@ pub fn expand_outer_inherent( let mut is_inherent = false; - #({ - let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt); - if let Some(call) = IsSubType::<_>::is_sub_type(call) { - if #pallet_names::is_inherent(call) { - is_inherent = true; - if let Err(e) = #pallet_names::check_inherent(call, self) { - result.put_error( - #pallet_names::INHERENT_IDENTIFIER, &e - ).expect("There is only one fatal error; qed"); - if e.is_fatal_error() { - return result; + #( + #pallet_attrs + { + let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt); + if let Some(call) = IsSubType::<_>::is_sub_type(call) { + if #pallet_names::is_inherent(call) { + is_inherent = true; + if let Err(e) = #pallet_names::check_inherent(call, self) { + result.put_error( + #pallet_names::INHERENT_IDENTIFIER, &e + ).expect("There is only one fatal error; qed"); + if e.is_fatal_error() { + return result; + } } } } } - })* + )* // Inherents are before any other extrinsics. // No module marked it as inherent thus it is not. @@ -115,6 +130,7 @@ pub fn expand_outer_inherent( } #( + #pallet_attrs match #pallet_names::is_inherent_required(self) { Ok(Some(e)) => { let found = block.extrinsics().iter().any(|xt| { @@ -177,14 +193,17 @@ pub fn expand_outer_inherent( false } else { let mut is_inherent = false; - #({ - let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt); - if let Some(call) = IsSubType::<_>::is_sub_type(call) { - if #pallet_names::is_inherent(&call) { - is_inherent = true; + #( + #pallet_attrs + { + let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt); + if let Some(call) = IsSubType::<_>::is_sub_type(call) { + if #pallet_names::is_inherent(&call) { + is_inherent = true; + } } } - })* + )* is_inherent }; diff --git a/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/frame/support/procedural/src/construct_runtime/expand/metadata.rs index 6e2dd5fc002c6..ec90a0d30f98b 100644 --- a/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -18,6 +18,7 @@ use crate::construct_runtime::Pallet; use proc_macro2::TokenStream; use quote::quote; +use std::str::FromStr; use syn::{Ident, TypePath}; pub fn expand_runtime_metadata( @@ -47,8 +48,17 @@ pub fn expand_runtime_metadata( let event = expand_pallet_metadata_events(&filtered_names, runtime, scrate, decl); let constants = expand_pallet_metadata_constants(runtime, decl); let errors = expand_pallet_metadata_errors(runtime, decl); + let attr = decl.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); quote! { + #attr #scrate::metadata::PalletMetadata { name: stringify!(#name), index: #index, diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index 46f08832f0bb4..a4bb0d9cbaa02 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -18,6 +18,7 @@ use crate::construct_runtime::{Pallet, SYSTEM_PALLET_NAME}; use proc_macro2::TokenStream; use quote::quote; +use std::str::FromStr; use syn::{Generics, Ident}; pub fn expand_outer_origin( @@ -303,19 +304,35 @@ fn expand_origin_caller_variant( let part_is_generic = !generics.params.is_empty(); let variant_name = &pallet.name; let path = &pallet.path; + let attr = pallet.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); match instance { - Some(inst) if part_is_generic => { - quote!(#[codec(index = #index)] #variant_name(#path::Origin<#runtime, #path::#inst>),) + Some(inst) if part_is_generic => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Origin<#runtime, #path::#inst>), }, - Some(inst) => { - quote!(#[codec(index = #index)] #variant_name(#path::Origin<#path::#inst>),) + Some(inst) => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Origin<#path::#inst>), }, - None if part_is_generic => { - quote!(#[codec(index = #index)] #variant_name(#path::Origin<#runtime>),) + None if part_is_generic => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Origin<#runtime>), }, - None => { - quote!(#[codec(index = #index)] #variant_name(#path::Origin),) + None => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Origin), }, } } @@ -339,14 +356,24 @@ fn expand_origin_pallet_conversions( }; let doc_string = get_intra_doc_string(" Convert to runtime origin using", &path.module_name()); + let attr = pallet.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); quote! { + #attr impl From<#pallet_origin> for OriginCaller { fn from(x: #pallet_origin) -> Self { OriginCaller::#variant_name(x) } } + #attr impl From<#pallet_origin> for Origin { #[doc = #doc_string] fn from(x: #pallet_origin) -> Self { @@ -355,6 +382,7 @@ fn expand_origin_pallet_conversions( } } + #attr impl From for #scrate::sp_std::result::Result<#pallet_origin, Origin> { /// NOTE: converting to pallet origin loses the origin filter information. fn from(val: Origin) -> Self { @@ -366,6 +394,7 @@ fn expand_origin_pallet_conversions( } } + #attr impl TryFrom for #pallet_origin { type Error = OriginCaller; fn try_from( diff --git a/frame/support/procedural/src/construct_runtime/expand/unsigned.rs b/frame/support/procedural/src/construct_runtime/expand/unsigned.rs index c030676802093..310516793472f 100644 --- a/frame/support/procedural/src/construct_runtime/expand/unsigned.rs +++ b/frame/support/procedural/src/construct_runtime/expand/unsigned.rs @@ -18,6 +18,7 @@ use crate::construct_runtime::Pallet; use proc_macro2::TokenStream; use quote::quote; +use std::str::FromStr; use syn::Ident; pub fn expand_outer_validate_unsigned( @@ -26,14 +27,24 @@ pub fn expand_outer_validate_unsigned( scrate: &TokenStream, ) -> TokenStream { let mut pallet_names = Vec::new(); + let mut pallet_attrs = Vec::new(); let mut query_validate_unsigned_part_macros = Vec::new(); for pallet_decl in pallet_decls { if pallet_decl.exists_part("ValidateUnsigned") { let name = &pallet_decl.name; let path = &pallet_decl.path; + let attr = pallet_decl.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); pallet_names.push(name); + pallet_attrs.push(attr); query_validate_unsigned_part_macros.push(quote! { #path::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined!(#name); }); @@ -49,7 +60,10 @@ pub fn expand_outer_validate_unsigned( fn pre_dispatch(call: &Self::Call) -> Result<(), #scrate::unsigned::TransactionValidityError> { #[allow(unreachable_patterns)] match call { - #( Call::#pallet_names(inner_call) => #pallet_names::pre_dispatch(inner_call), )* + #( + #pallet_attrs + Call::#pallet_names(inner_call) => #pallet_names::pre_dispatch(inner_call), + )* // pre-dispatch should not stop inherent extrinsics, validation should prevent // including arbitrary (non-inherent) extrinsics to blocks. _ => Ok(()), @@ -63,7 +77,10 @@ pub fn expand_outer_validate_unsigned( ) -> #scrate::unsigned::TransactionValidity { #[allow(unreachable_patterns)] match call { - #( Call::#pallet_names(inner_call) => #pallet_names::validate_unsigned(source, inner_call), )* + #( + #pallet_attrs + Call::#pallet_names(inner_call) => #pallet_names::validate_unsigned(source, inner_call), + )* _ => #scrate::unsigned::UnknownTransaction::NoUnsignedValidator.into(), } } diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 042af31be6bf4..cfd582d0e4472 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -144,9 +144,11 @@ mod expand; mod parse; +use cfg_expr::Predicate; use frame_support_procedural_tools::{ generate_crate_access, generate_crate_access_2018, generate_hidden_includes, }; +use itertools::Itertools; use parse::{ ExplicitRuntimeDeclaration, ImplicitRuntimeDeclaration, Pallet, RuntimeDeclaration, WhereSection, @@ -154,6 +156,10 @@ use parse::{ use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; +use std::{ + collections::{HashMap, HashSet}, + str::FromStr, +}; use syn::{Ident, Result}; /// The fixed name of the system pallet. @@ -223,6 +229,28 @@ fn construct_runtime_final_expansion( Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},`", ) })?; + if !system_pallet.cfg_pattern.is_empty() { + return Err(syn::Error::new( + system_pallet.name.span(), + "`System` pallet declaration is feature gated, please remove any `#[cfg]` attributes", + )) + } + + let features = pallets + .iter() + .filter_map(|decl| { + (!decl.cfg_pattern.is_empty()).then(|| { + decl.cfg_pattern.iter().flat_map(|attr| { + attr.predicates().filter_map(|pred| match pred { + Predicate::Feature(feat) => Some(feat), + Predicate::Test => Some("test"), + _ => None, + }) + }) + }) + }) + .flatten() + .collect::>(); let hidden_crate_name = "construct_runtime"; let scrate = generate_crate_access(hidden_crate_name, "frame-support"); @@ -231,7 +259,7 @@ fn construct_runtime_final_expansion( let outer_event = expand::expand_outer_event(&name, &pallets, &scrate)?; let outer_origin = expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?; - let all_pallets = decl_all_pallets(&name, pallets.iter()); + let all_pallets = decl_all_pallets(&name, pallets.iter(), &features); let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate); let dispatch = expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate); @@ -293,40 +321,140 @@ fn construct_runtime_final_expansion( fn decl_all_pallets<'a>( runtime: &'a Ident, pallet_declarations: impl Iterator, + features: &HashSet<&str>, ) -> TokenStream2 { let mut types = TokenStream2::new(); - let mut names = Vec::new(); + let mut names_by_feature = features + .iter() + .powerset() + .map(|feat| (feat, Vec::new())) + .collect::>(); for pallet_declaration in pallet_declarations { let type_name = &pallet_declaration.name; let pallet = &pallet_declaration.path; let mut generics = vec![quote!(#runtime)]; generics.extend(pallet_declaration.instance.iter().map(|name| quote!(#pallet::#name))); + let mut attrs = Vec::new(); + for cfg in &pallet_declaration.cfg_pattern { + let feat = format!("#[cfg({})]\n", cfg.original()); + attrs.extend(TokenStream2::from_str(&feat).expect("was parsed successfully; qed")); + } let type_decl = quote!( + #(#attrs)* pub type #type_name = #pallet::Pallet <#(#generics),*>; ); types.extend(type_decl); - names.push(&pallet_declaration.name); + + if pallet_declaration.cfg_pattern.is_empty() { + for names in names_by_feature.values_mut() { + names.push(&pallet_declaration.name); + } + } else { + for (feature_set, names) in &mut names_by_feature { + // Rust tidbit: if we have multiple `#[cfg]` feature on the same item, then the + // predicates listed in all `#[cfg]` attributes are effectively joined by `and()`, + // meaning that all of them must match in order to activate the item + let is_feature_active = pallet_declaration.cfg_pattern.iter().all(|expr| { + expr.eval(|pred| match pred { + Predicate::Feature(f) => feature_set.contains(&f), + Predicate::Test => feature_set.contains(&&"test"), + _ => false, + }) + }); + if is_feature_active { + names.push(&pallet_declaration.name); + } + } + } } - let system_pallet = match names.iter().find(|n| **n == SYSTEM_PALLET_NAME) { - Some(name) => name, - None => - return syn::Error::new( - proc_macro2::Span::call_site(), - "`System` pallet declaration is missing. \ - Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},`", - ) - .into_compile_error(), - }; + let all_pallets_without_system = names_by_feature.iter().map(|(feature_set, names)| { + let mut feature_set = feature_set.iter().collect::>(); + let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); + let feature_set = feature_set.into_iter(); + let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types. + /// Excludes the System pallet. + pub type AllPalletsWithoutSystem = ( #(#names,)* ); + } + }); - let names_without_system = - names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).collect::>(); - let names_reversed = names.clone().into_iter().rev().collect::>(); - let names_without_system_reverse = - names_without_system.clone().into_iter().rev().collect::>(); - let names_reversed_with_system_first = std::iter::once(system_pallet) - .chain(names_without_system_reverse.clone().into_iter()) - .collect::>(); + let all_pallets_with_system = names_by_feature.iter().map(|(feature_set, names)| { + let mut feature_set = feature_set.iter().collect::>(); + let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); + let feature_set = feature_set.into_iter(); + let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types. + pub type AllPalletsWithSystem = ( #(#names,)* ); + } + }); + + let all_pallets_without_system_reversed = + names_by_feature.iter().map(|(feature_set, names)| { + let mut feature_set = feature_set.iter().collect::>(); + let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); + let feature_set = feature_set.into_iter(); + let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).rev(); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types in reversed order. + /// Excludes the System pallet. + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsWithoutSystemReversed = ( #(#names,)* ); + } + }); + + let all_pallets_with_system_reversed = names_by_feature.iter().map(|(feature_set, names)| { + let mut feature_set = feature_set.iter().collect::>(); + let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); + let feature_set = feature_set.into_iter(); + let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + let names = names.iter().rev(); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types in reversed order. + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsWithSystemReversed = ( #(#names,)* ); + } + }); + + let system_pallet = + match names_by_feature[&Vec::new()].iter().find(|n| **n == SYSTEM_PALLET_NAME) { + Some(name) => name, + None => + return syn::Error::new( + proc_macro2::Span::call_site(), + "`System` pallet declaration is missing. \ + Please add this line: `System: frame_system,`", + ) + .into_compile_error(), + }; + + let all_pallets_reversed_with_system_first = + names_by_feature.iter().map(|(feature_set, names)| { + let mut feature_set = feature_set.iter().collect::>(); + let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); + let feature_set = feature_set.into_iter(); + let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + let names = std::iter::once(system_pallet) + .chain(names.iter().rev().filter(|n| **n != SYSTEM_PALLET_NAME)); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types in reversed order. + /// With the system pallet first. + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsReversedWithSystemFirst = ( #(#names,)* ); + } + }); quote!( #types @@ -342,29 +470,15 @@ fn decl_all_pallets<'a>( https://github.com/paritytech/substrate/pull/10043")] pub type AllPallets = AllPalletsWithSystem; - /// All pallets included in the runtime as a nested tuple of types. - pub type AllPalletsWithSystem = ( #(#names),* ); + #( #all_pallets_with_system )* - /// All pallets included in the runtime as a nested tuple of types. - /// Excludes the System pallet. - pub type AllPalletsWithoutSystem = ( #(#names_without_system),* ); - - /// All pallets included in the runtime as a nested tuple of types in reversed order. - /// Excludes the System pallet. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsWithoutSystemReversed =( #(#names_without_system_reverse),* ); - - /// All pallets included in the runtime as a nested tuple of types in reversed order. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsWithSystemReversed = ( #(#names_reversed),* ); - - /// All pallets included in the runtime as a nested tuple of types in reversed order. - /// With the system pallet first. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsReversedWithSystemFirst = ( #(#names_reversed_with_system_first),* ); + #( #all_pallets_without_system )* + + #( #all_pallets_with_system_reversed )* + + #( #all_pallets_without_system_reversed )* + + #( #all_pallets_reversed_with_system_first )* ) } @@ -387,6 +501,19 @@ fn decl_pallet_runtime_setup( } }) .collect::>(); + let pallet_attrs = pallet_declarations + .iter() + .map(|pallet| { + pallet.cfg_pattern.iter().fold(TokenStream2::new(), |acc, pattern| { + let attr = TokenStream2::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }) + }) + .collect::>(); quote!( /// Provides an implementation of `PalletInfo` to provide information @@ -397,6 +524,7 @@ fn decl_pallet_runtime_setup( fn index() -> Option { let type_id = #scrate::sp_std::any::TypeId::of::

(); #( + #pallet_attrs if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { return Some(#indices) } @@ -408,6 +536,7 @@ fn decl_pallet_runtime_setup( fn name() -> Option<&'static str> { let type_id = #scrate::sp_std::any::TypeId::of::

(); #( + #pallet_attrs if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { return Some(#name_strings) } @@ -419,6 +548,7 @@ fn decl_pallet_runtime_setup( fn module_name() -> Option<&'static str> { let type_id = #scrate::sp_std::any::TypeId::of::

(); #( + #pallet_attrs if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { return Some(#module_names) } @@ -430,6 +560,7 @@ fn decl_pallet_runtime_setup( fn crate_version() -> Option<#scrate::traits::CrateVersion> { let type_id = #scrate::sp_std::any::TypeId::of::

(); #( + #pallet_attrs if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { return Some( <#pallet_structs as #scrate::traits::PalletInfoAccess>::crate_version() diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index 711da85c10cfc..7a5acf43b92b0 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -23,7 +23,7 @@ use syn::{ parse::{Parse, ParseStream}, punctuated::Punctuated, spanned::Spanned, - token, Error, Ident, Path, Result, Token, + token, Attribute, Error, Ident, Path, Result, Token, }; mod keyword { @@ -185,6 +185,8 @@ impl Parse for WhereDefinition { pub struct PalletDeclaration { /// The name of the pallet, e.g.`System` in `System: frame_system`. pub name: Ident, + /// Optional attributes tagged right above a pallet declaration. + pub attrs: Vec, /// Optional fixed index, e.g. `MyPallet ... = 3,`. pub index: Option, /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. @@ -212,6 +214,8 @@ pub enum SpecifiedParts { impl Parse for PalletDeclaration { fn parse(input: ParseStream) -> Result { + let attrs = input.call(Attribute::parse_outer)?; + let name = input.parse()?; let _: Token![:] = input.parse()?; let path = input.parse()?; @@ -279,7 +283,7 @@ impl Parse for PalletDeclaration { None }; - Ok(Self { name, path, instance, pallet_parts, specified_parts, index }) + Ok(Self { attrs, name, path, instance, pallet_parts, specified_parts, index }) } } @@ -535,6 +539,8 @@ pub struct Pallet { pub instance: Option, /// The pallet parts to use for the pallet. pub pallet_parts: Vec, + /// Expressions specified inside of a #[cfg] attribute. + pub cfg_pattern: Vec, } impl Pallet { @@ -647,11 +653,32 @@ fn convert_pallets(pallets: Vec) -> syn::Result (), } + let cfg_pattern = pallet + .attrs + .iter() + .map(|attr| { + if attr.path.segments.len() != 1 || attr.path.segments[0].ident != "cfg" { + let msg = "Unsupported attribute, only #[cfg] is supported on pallet \ + declarations in `construct_runtime`"; + return Err(syn::Error::new(attr.span(), msg)) + } + + attr.parse_args_with(|input: syn::parse::ParseStream| { + // Required, otherwise the parse stream doesn't advance and will result in + // an error. + let input = input.parse::()?; + cfg_expr::Expression::parse(&input.to_string()) + .map_err(|e| syn::Error::new(attr.span(), e.to_string())) + }) + }) + .collect::>>()?; + Ok(Pallet { name: pallet.name, index: final_index, path: pallet.path, instance: pallet.instance, + cfg_pattern, pallet_parts, }) }) diff --git a/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.rs b/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.rs new file mode 100644 index 0000000000000..79b5632babd95 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.rs @@ -0,0 +1,14 @@ +use frame_support::construct_runtime; + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + #[cfg(test)] + System: frame_system::{Pallet, Call, Storage, Config, Event}, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.stderr b/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.stderr new file mode 100644 index 0000000000000..a86a839615aa0 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/feature_gated_system_pallet.stderr @@ -0,0 +1,5 @@ +error: `System` pallet declaration is feature gated, please remove any `#[cfg]` attributes + --> tests/construct_runtime_ui/feature_gated_system_pallet.rs:10:3 + | +10 | System: frame_system::{Pallet, Call, Storage, Config, Event}, + | ^^^^^^ diff --git a/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.rs b/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.rs new file mode 100644 index 0000000000000..a1d39fa76ea85 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.rs @@ -0,0 +1,15 @@ +use frame_support::construct_runtime; + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Pallet}, + #[cfg(feature = 1)] + Balance: balances::{Config, Call}, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.stderr b/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.stderr new file mode 100644 index 0000000000000..68366a3410bf1 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/invalid_meta_literal.stderr @@ -0,0 +1,6 @@ +error: feature = 1 + ^ expected one of ``, `all`, `any`, `not` here + --> tests/construct_runtime_ui/invalid_meta_literal.rs:10:3 + | +10 | #[cfg(feature = 1)] + | ^ diff --git a/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.rs b/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.rs new file mode 100644 index 0000000000000..b93adf9a780a7 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.rs @@ -0,0 +1,15 @@ +use frame_support::construct_runtime; + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Pallet}, + #[cfg(feature(test))] + Balance: balances::{Config, Call}, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.stderr b/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.stderr new file mode 100644 index 0000000000000..98d99a0d34997 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.stderr @@ -0,0 +1,6 @@ +error: feature(test) + ^ expected one of `=`, `,`, `)` here + --> tests/construct_runtime_ui/unsupported_meta_structure.rs:10:3 + | +10 | #[cfg(feature(test))] + | ^ diff --git a/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.rs b/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.rs new file mode 100644 index 0000000000000..3ec8b9db1d435 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.rs @@ -0,0 +1,15 @@ +use frame_support::construct_runtime; + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Pallet}, + #[attr] + Balance: balances::{Config, Call}, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.stderr b/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.stderr new file mode 100644 index 0000000000000..fceb2b8a99db8 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.stderr @@ -0,0 +1,5 @@ +error: Unsupported attribute, only #[cfg] is supported on pallet declarations in `construct_runtime` + --> tests/construct_runtime_ui/unsupported_pallet_attr.rs:10:3 + | +10 | #[attr] + | ^ diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index e96e52d3d2c6e..497b7bb04c36a 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -626,6 +626,8 @@ frame_support::construct_runtime!( System: frame_system exclude_parts { Pallet, Storage }, Example: pallet, Example2: pallet2 exclude_parts { Call }, + #[cfg(feature = "example3")] + Example3: pallet3, Example4: pallet4 use_parts { Call }, } ); From 088b5e0d71b57886957cfbedfb68b36b8014dc5e Mon Sep 17 00:00:00 2001 From: Squirrel Date: Thu, 25 Aug 2022 12:11:15 +0100 Subject: [PATCH 1089/1472] clone not required as copy. (#12110) --- frame/support/procedural/src/pallet/parse/storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 97abdd3ad0977..f0e1353774910 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -775,7 +775,7 @@ impl StorageDef { error.push_value(last); Ok(Some(QueryKind::ResultQuery( - syn::Path { leading_colon: leading_colon.clone(), segments: error }, + syn::Path { leading_colon, segments: error }, err_variant, ))) }, From 85d7e106be0885c7f4dfd7e38f8684ae93d39ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 25 Aug 2022 13:18:53 +0200 Subject: [PATCH 1090/1472] Fix `wasm_export_functions` when using a return statement (#12107) When used a return statement before we directly returned from the function which is obviously wrong. --- client/executor/runtime-test/src/lib.rs | 531 ++++++++++--------- client/executor/src/integration_tests/mod.rs | 11 + primitives/core/src/testing.rs | 4 +- 3 files changed, 281 insertions(+), 265 deletions(-) diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 0c61d6fcd38a2..5a741f51c3899 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -54,287 +54,287 @@ static mut MUTABLE_STATIC: u64 = 32; static mut MUTABLE_STATIC_BSS: u64 = 0; sp_core::wasm_export_functions! { - fn test_calling_missing_external() { - unsafe { missing_external() } - } + fn test_calling_missing_external() { + unsafe { missing_external() } + } - fn test_calling_yet_another_missing_external() { - unsafe { yet_another_missing_external() } - } + fn test_calling_yet_another_missing_external() { + unsafe { yet_another_missing_external() } + } - fn test_data_in(input: Vec) -> Vec { - print("set_storage"); - storage::set(b"input", &input); + fn test_data_in(input: Vec) -> Vec { + print("set_storage"); + storage::set(b"input", &input); - print("storage"); - let foo = storage::get(b"foo").unwrap(); + print("storage"); + let foo = storage::get(b"foo").unwrap(); - print("set_storage"); - storage::set(b"baz", &foo); + print("set_storage"); + storage::set(b"baz", &foo); - print("finished!"); - b"all ok!".to_vec() - } + print("finished!"); + b"all ok!".to_vec() + } - fn test_clear_prefix(input: Vec) -> Vec { - storage::clear_prefix(&input, None); - b"all ok!".to_vec() - } + fn test_clear_prefix(input: Vec) -> Vec { + storage::clear_prefix(&input, None); + b"all ok!".to_vec() + } - fn test_empty_return() {} + fn test_empty_return() {} - fn test_dirty_plenty_memory(heap_base: u32, heap_pages: u32) { - // This piece of code will dirty multiple pages of memory. The number of pages is given by - // the `heap_pages`. It's unit is a wasm page (64KiB). The first page to be cleared - // is a wasm page that that follows the one that holds the `heap_base` address. - // - // This function dirties the **host** pages. I.e. we dirty 4KiB at a time and it will take - // 16 writes to process a single wasm page. + fn test_dirty_plenty_memory(heap_base: u32, heap_pages: u32) { + // This piece of code will dirty multiple pages of memory. The number of pages is given by + // the `heap_pages`. It's unit is a wasm page (64KiB). The first page to be cleared + // is a wasm page that that follows the one that holds the `heap_base` address. + // + // This function dirties the **host** pages. I.e. we dirty 4KiB at a time and it will take + // 16 writes to process a single wasm page. - let heap_ptr = heap_base as usize; + let heap_ptr = heap_base as usize; - // Find the next wasm page boundary. - let heap_ptr = round_up_to(heap_ptr, 65536); + // Find the next wasm page boundary. + let heap_ptr = round_up_to(heap_ptr, 65536); - // Make it an actual pointer - let heap_ptr = heap_ptr as *mut u8; + // Make it an actual pointer + let heap_ptr = heap_ptr as *mut u8; - // Traverse the host pages and make each one dirty - let host_pages = heap_pages as usize * 16; - for i in 0..host_pages { - unsafe { - // technically this is an UB, but there is no way Rust can find this out. - heap_ptr.add(i * 4096).write(0); - } - } + // Traverse the host pages and make each one dirty + let host_pages = heap_pages as usize * 16; + for i in 0..host_pages { + unsafe { + // technically this is an UB, but there is no way Rust can find this out. + heap_ptr.add(i * 4096).write(0); + } + } - fn round_up_to(n: usize, divisor: usize) -> usize { - (n + divisor - 1) / divisor - } - } + fn round_up_to(n: usize, divisor: usize) -> usize { + (n + divisor - 1) / divisor + } + } fn test_allocate_vec(size: u32) -> Vec { Vec::with_capacity(size as usize) } - fn test_fp_f32add(a: [u8; 4], b: [u8; 4]) -> [u8; 4] { - let a = f32::from_le_bytes(a); - let b = f32::from_le_bytes(b); - f32::to_le_bytes(a + b) - } - - fn test_panic() { panic!("test panic") } - - fn test_conditional_panic(input: Vec) -> Vec { - if input.len() > 0 { - panic!("test panic") - } - - input - } - - fn test_blake2_256(input: Vec) -> Vec { - blake2_256(&input).to_vec() - } - - fn test_blake2_128(input: Vec) -> Vec { - blake2_128(&input).to_vec() - } - - fn test_sha2_256(input: Vec) -> Vec { - sha2_256(&input).to_vec() - } - - fn test_twox_256(input: Vec) -> Vec { - twox_256(&input).to_vec() - } - - fn test_twox_128(input: Vec) -> Vec { - twox_128(&input).to_vec() - } - - fn test_ed25519_verify(input: Vec) -> bool { - let mut pubkey = [0; 32]; - let mut sig = [0; 64]; - - pubkey.copy_from_slice(&input[0..32]); - sig.copy_from_slice(&input[32..96]); - - let msg = b"all ok!"; - ed25519_verify(&ed25519::Signature(sig), &msg[..], &ed25519::Public(pubkey)) - } - - fn test_sr25519_verify(input: Vec) -> bool { - let mut pubkey = [0; 32]; - let mut sig = [0; 64]; - - pubkey.copy_from_slice(&input[0..32]); - sig.copy_from_slice(&input[32..96]); - - let msg = b"all ok!"; - sr25519_verify(&sr25519::Signature(sig), &msg[..], &sr25519::Public(pubkey)) - } - - fn test_ordered_trie_root() -> Vec { - BlakeTwo256::ordered_trie_root( - vec![ - b"zero"[..].into(), - b"one"[..].into(), - b"two"[..].into(), - ], - sp_core::storage::StateVersion::V1, - ).as_ref().to_vec() - } - - fn test_offchain_index_set() { - sp_io::offchain_index::set(b"k", b"v"); - } - - fn test_offchain_local_storage() -> bool { - let kind = sp_core::offchain::StorageKind::PERSISTENT; - assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), None); - sp_io::offchain::local_storage_set(kind, b"test", b"asd"); - assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), Some(b"asd".to_vec())); - - let res = sp_io::offchain::local_storage_compare_and_set( - kind, - b"test", - Some(b"asd".to_vec()), - b"", - ); - assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), Some(b"".to_vec())); - res - } - - fn test_offchain_local_storage_with_none() { - let kind = sp_core::offchain::StorageKind::PERSISTENT; - assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), None); - - let res = sp_io::offchain::local_storage_compare_and_set(kind, b"test", None, b"value"); - assert_eq!(res, true); - assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), Some(b"value".to_vec())); - } - - fn test_offchain_http() -> bool { - use sp_core::offchain::HttpRequestStatus; - let run = || -> Option<()> { - let id = sp_io::offchain::http_request_start( - "POST", - "http://localhost:12345", - &[], - ).ok()?; - sp_io::offchain::http_request_add_header(id, "X-Auth", "test").ok()?; - sp_io::offchain::http_request_write_body(id, &[1, 2, 3, 4], None).ok()?; - sp_io::offchain::http_request_write_body(id, &[], None).ok()?; - let status = sp_io::offchain::http_response_wait(&[id], None); - assert!(status == vec![HttpRequestStatus::Finished(200)], "Expected Finished(200) status."); - let headers = sp_io::offchain::http_response_headers(id); - assert_eq!(headers, vec![(b"X-Auth".to_vec(), b"hello".to_vec())]); - let mut buffer = vec![0; 64]; - let read = sp_io::offchain::http_response_read_body(id, &mut buffer, None).ok()?; - assert_eq!(read, 3); - assert_eq!(&buffer[0..read as usize], &[1, 2, 3]); - let read = sp_io::offchain::http_response_read_body(id, &mut buffer, None).ok()?; - assert_eq!(read, 0); - - Some(()) - }; - - run().is_some() - } - - fn test_enter_span() -> u64 { - wasm_tracing::enter_span(Default::default()) - } - - fn test_exit_span(span_id: u64) { - wasm_tracing::exit(span_id) - } - - fn test_nested_spans() { - sp_io::init_tracing(); - let span_id = wasm_tracing::enter_span(Default::default()); - { - sp_io::init_tracing(); - let span_id = wasm_tracing::enter_span(Default::default()); - wasm_tracing::exit(span_id); - } - wasm_tracing::exit(span_id); - } - - fn returns_mutable_static() -> u64 { - unsafe { - MUTABLE_STATIC += 1; - MUTABLE_STATIC - } - } - - fn returns_mutable_static_bss() -> u64 { - unsafe { - MUTABLE_STATIC_BSS += 1; - MUTABLE_STATIC_BSS - } - } - - fn allocates_huge_stack_array(trap: bool) -> Vec { - // Allocate a stack frame that is approx. 75% of the stack (assuming it is 1MB). - // This will just decrease (stacks in wasm32-u-u grow downwards) the stack - // pointer. This won't trap on the current compilers. - let mut data = [0u8; 1024 * 768]; - - // Then make sure we actually write something to it. - // - // If: - // 1. the stack area is placed at the beginning of the linear memory space, and - // 2. the stack pointer points to out-of-bounds area, and - // 3. a write is performed around the current stack pointer. - // - // then a trap should happen. - // - for (i, v) in data.iter_mut().enumerate() { - *v = i as u8; // deliberate truncation - } - - if trap { - // There is a small chance of this to be pulled up in theory. In practice - // the probability of that is rather low. - panic!() - } - - data.to_vec() - } - - // Check that the heap at `heap_base + offset` don't contains the test message. - // After the check succeeds the test message is written into the heap. - // - // It is expected that the given pointer is not allocated. - fn check_and_set_in_heap(heap_base: u32, offset: u32) { - let test_message = b"Hello invalid heap memory"; - let ptr = (heap_base + offset) as *mut u8; - - let message_slice = unsafe { sp_std::slice::from_raw_parts_mut(ptr, test_message.len()) }; - - assert_ne!(test_message, message_slice); - message_slice.copy_from_slice(test_message); - } - - fn test_spawn() { - let data = vec![1u8, 2u8]; - let data_new = sp_tasks::spawn(tasks::incrementer, data).join(); - - assert_eq!(data_new, vec![2u8, 3u8]); - } - - fn test_nested_spawn() { - let data = vec![7u8, 13u8]; - let data_new = sp_tasks::spawn(tasks::parallel_incrementer, data).join(); - - assert_eq!(data_new, vec![10u8, 16u8]); - } - - fn test_panic_in_spawned() { - sp_tasks::spawn(tasks::panicker, vec![]).join(); - } + fn test_fp_f32add(a: [u8; 4], b: [u8; 4]) -> [u8; 4] { + let a = f32::from_le_bytes(a); + let b = f32::from_le_bytes(b); + f32::to_le_bytes(a + b) + } + + fn test_panic() { panic!("test panic") } + + fn test_conditional_panic(input: Vec) -> Vec { + if input.len() > 0 { + panic!("test panic") + } + + input + } + + fn test_blake2_256(input: Vec) -> Vec { + blake2_256(&input).to_vec() + } + + fn test_blake2_128(input: Vec) -> Vec { + blake2_128(&input).to_vec() + } + + fn test_sha2_256(input: Vec) -> Vec { + sha2_256(&input).to_vec() + } + + fn test_twox_256(input: Vec) -> Vec { + twox_256(&input).to_vec() + } + + fn test_twox_128(input: Vec) -> Vec { + twox_128(&input).to_vec() + } + + fn test_ed25519_verify(input: Vec) -> bool { + let mut pubkey = [0; 32]; + let mut sig = [0; 64]; + + pubkey.copy_from_slice(&input[0..32]); + sig.copy_from_slice(&input[32..96]); + + let msg = b"all ok!"; + ed25519_verify(&ed25519::Signature(sig), &msg[..], &ed25519::Public(pubkey)) + } + + fn test_sr25519_verify(input: Vec) -> bool { + let mut pubkey = [0; 32]; + let mut sig = [0; 64]; + + pubkey.copy_from_slice(&input[0..32]); + sig.copy_from_slice(&input[32..96]); + + let msg = b"all ok!"; + sr25519_verify(&sr25519::Signature(sig), &msg[..], &sr25519::Public(pubkey)) + } + + fn test_ordered_trie_root() -> Vec { + BlakeTwo256::ordered_trie_root( + vec![ + b"zero"[..].into(), + b"one"[..].into(), + b"two"[..].into(), + ], + sp_core::storage::StateVersion::V1, + ).as_ref().to_vec() + } + + fn test_offchain_index_set() { + sp_io::offchain_index::set(b"k", b"v"); + } + + fn test_offchain_local_storage() -> bool { + let kind = sp_core::offchain::StorageKind::PERSISTENT; + assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), None); + sp_io::offchain::local_storage_set(kind, b"test", b"asd"); + assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), Some(b"asd".to_vec())); + + let res = sp_io::offchain::local_storage_compare_and_set( + kind, + b"test", + Some(b"asd".to_vec()), + b"", + ); + assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), Some(b"".to_vec())); + res + } + + fn test_offchain_local_storage_with_none() { + let kind = sp_core::offchain::StorageKind::PERSISTENT; + assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), None); + + let res = sp_io::offchain::local_storage_compare_and_set(kind, b"test", None, b"value"); + assert_eq!(res, true); + assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), Some(b"value".to_vec())); + } + + fn test_offchain_http() -> bool { + use sp_core::offchain::HttpRequestStatus; + let run = || -> Option<()> { + let id = sp_io::offchain::http_request_start( + "POST", + "http://localhost:12345", + &[], + ).ok()?; + sp_io::offchain::http_request_add_header(id, "X-Auth", "test").ok()?; + sp_io::offchain::http_request_write_body(id, &[1, 2, 3, 4], None).ok()?; + sp_io::offchain::http_request_write_body(id, &[], None).ok()?; + let status = sp_io::offchain::http_response_wait(&[id], None); + assert!(status == vec![HttpRequestStatus::Finished(200)], "Expected Finished(200) status."); + let headers = sp_io::offchain::http_response_headers(id); + assert_eq!(headers, vec![(b"X-Auth".to_vec(), b"hello".to_vec())]); + let mut buffer = vec![0; 64]; + let read = sp_io::offchain::http_response_read_body(id, &mut buffer, None).ok()?; + assert_eq!(read, 3); + assert_eq!(&buffer[0..read as usize], &[1, 2, 3]); + let read = sp_io::offchain::http_response_read_body(id, &mut buffer, None).ok()?; + assert_eq!(read, 0); + + Some(()) + }; + + run().is_some() + } + + fn test_enter_span() -> u64 { + wasm_tracing::enter_span(Default::default()) + } + + fn test_exit_span(span_id: u64) { + wasm_tracing::exit(span_id) + } + + fn test_nested_spans() { + sp_io::init_tracing(); + let span_id = wasm_tracing::enter_span(Default::default()); + { + sp_io::init_tracing(); + let span_id = wasm_tracing::enter_span(Default::default()); + wasm_tracing::exit(span_id); + } + wasm_tracing::exit(span_id); + } + + fn returns_mutable_static() -> u64 { + unsafe { + MUTABLE_STATIC += 1; + MUTABLE_STATIC + } + } + + fn returns_mutable_static_bss() -> u64 { + unsafe { + MUTABLE_STATIC_BSS += 1; + MUTABLE_STATIC_BSS + } + } + + fn allocates_huge_stack_array(trap: bool) -> Vec { + // Allocate a stack frame that is approx. 75% of the stack (assuming it is 1MB). + // This will just decrease (stacks in wasm32-u-u grow downwards) the stack + // pointer. This won't trap on the current compilers. + let mut data = [0u8; 1024 * 768]; + + // Then make sure we actually write something to it. + // + // If: + // 1. the stack area is placed at the beginning of the linear memory space, and + // 2. the stack pointer points to out-of-bounds area, and + // 3. a write is performed around the current stack pointer. + // + // then a trap should happen. + // + for (i, v) in data.iter_mut().enumerate() { + *v = i as u8; // deliberate truncation + } + + if trap { + // There is a small chance of this to be pulled up in theory. In practice + // the probability of that is rather low. + panic!() + } + + data.to_vec() + } + + // Check that the heap at `heap_base + offset` don't contains the test message. + // After the check succeeds the test message is written into the heap. + // + // It is expected that the given pointer is not allocated. + fn check_and_set_in_heap(heap_base: u32, offset: u32) { + let test_message = b"Hello invalid heap memory"; + let ptr = (heap_base + offset) as *mut u8; + + let message_slice = unsafe { sp_std::slice::from_raw_parts_mut(ptr, test_message.len()) }; + + assert_ne!(test_message, message_slice); + message_slice.copy_from_slice(test_message); + } + + fn test_spawn() { + let data = vec![1u8, 2u8]; + let data_new = sp_tasks::spawn(tasks::incrementer, data).join(); + + assert_eq!(data_new, vec![2u8, 3u8]); + } + + fn test_nested_spawn() { + let data = vec![7u8, 13u8]; + let data_new = sp_tasks::spawn(tasks::parallel_incrementer, data).join(); + + assert_eq!(data_new, vec![10u8, 16u8]); + } + + fn test_panic_in_spawned() { + sp_tasks::spawn(tasks::panicker, vec![]).join(); + } fn test_return_i8() -> i8 { -66 @@ -351,6 +351,11 @@ sp_core::wasm_export_functions! { fn test_unreachable_intrinsic() { core::arch::wasm32::unreachable() } + + fn test_return_value() -> u64 { + // Mainly a test that the macro is working when we have a return statement here. + return 1234; + } } #[cfg(not(feature = "std"))] diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 8ce0b56da2389..ba0c93630cf6c 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -918,3 +918,14 @@ fn unreachable_intrinsic(wasm_method: WasmExecutionMethod) { error => panic!("unexpected error: {:?}", error), } } + +test_wasm_execution!(return_value); +fn return_value(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + + assert_eq!( + call_in_wasm("test_return_value", &[], wasm_method, &mut ext).unwrap(), + (1234u64).encode() + ); +} diff --git a/primitives/core/src/testing.rs b/primitives/core/src/testing.rs index d5ca1dc45fa0c..d3fa3fc86fce5 100644 --- a/primitives/core/src/testing.rs +++ b/primitives/core/src/testing.rs @@ -90,7 +90,7 @@ macro_rules! wasm_export_functions { &mut &input[..], ).expect("Input data is correctly encoded"); - $( $fn_impl )* + (|| { $( $fn_impl )* })() } $crate::to_substrate_wasm_fn_return_value(&()) @@ -118,7 +118,7 @@ macro_rules! wasm_export_functions { &mut &input[..], ).expect("Input data is correctly encoded"); - $( $fn_impl )* + (|| { $( $fn_impl )* })() }; $crate::to_substrate_wasm_fn_return_value(&output) From 2b54771bf923b1f220b6997e710d7169f3dc613b Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Thu, 25 Aug 2022 17:52:58 +0300 Subject: [PATCH 1091/1472] pin gha versions (#12100) --- .github/workflows/auto-label-issues.yml | 4 ++-- .github/workflows/auto-label-prs.yml | 4 ++-- .github/workflows/md-link-check.yml | 2 +- .github/workflows/monthly-tag.yml | 2 +- .github/workflows/release-tagging.yml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/auto-label-issues.yml b/.github/workflows/auto-label-issues.yml index cd889b5941989..2633bf55f0789 100644 --- a/.github/workflows/auto-label-issues.yml +++ b/.github/workflows/auto-label-issues.yml @@ -8,10 +8,10 @@ on: jobs: label-new-issues: - runs-on: ubuntu-latest + runs-on: ubuntu-latest steps: - name: Label drafts - uses: andymckay/labeler@master + uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90 # 1.0.4 if: github.event.issue.author_association == 'NONE' with: add-labels: 'Z0-unconfirmed' diff --git a/.github/workflows/auto-label-prs.yml b/.github/workflows/auto-label-prs.yml index f0b8e9b343e29..50539b80b98b7 100644 --- a/.github/workflows/auto-label-prs.yml +++ b/.github/workflows/auto-label-prs.yml @@ -8,13 +8,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Label drafts - uses: andymckay/labeler@master + uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90 # 1.0.4 if: github.event.pull_request.draft == true with: add-labels: 'A3-inprogress' remove-labels: 'A0-pleasereview' - name: Label PRs - uses: andymckay/labeler@master + uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90 # 1.0.4 if: github.event.pull_request.draft == false && ! contains(github.event.pull_request.labels.*.name, 'A2-insubstantial') with: add-labels: 'A0-pleasereview' diff --git a/.github/workflows/md-link-check.yml b/.github/workflows/md-link-check.yml index 4b6b9166be2df..e1387f6da13f7 100644 --- a/.github/workflows/md-link-check.yml +++ b/.github/workflows/md-link-check.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: gaurav-nelson/github-action-markdown-link-check@9710f0fec812ce0a3b98bef4c9d842fc1f39d976 # v1.0.13 + - uses: gaurav-nelson/github-action-markdown-link-check@0a51127e9955b855a9bbfa1ff5577f1d1338c9a5 # 1.0.14 with: use-quiet-mode: 'yes' config-file: '.github/workflows/mlc_config.json' diff --git a/.github/workflows/monthly-tag.yml b/.github/workflows/monthly-tag.yml index ade8bd4717c39..6bec03d27e7be 100644 --- a/.github/workflows/monthly-tag.yml +++ b/.github/workflows/monthly-tag.yml @@ -32,7 +32,7 @@ jobs: ./scripts/ci/github/generate_changelog.sh ${{ steps.tags.outputs.old }} >> Changelog.md - name: Release snapshot id: release-snapshot - uses: actions/create-release@latest + uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # v1.1.4 latest version, repo archived env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/release-tagging.yml b/.github/workflows/release-tagging.yml index c55fc13a626e0..f7fa913c69709 100644 --- a/.github/workflows/release-tagging.yml +++ b/.github/workflows/release-tagging.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Set Git tag - uses: s3krit/walking-tag-action@master + uses: s3krit/walking-tag-action@d04f7a53b72ceda4e20283736ce3627011275178 # latest version from master with: TAG_NAME: release TAG_MESSAGE: Latest release From 4262c63fecf5de9a459775d772329828bcb549c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Aug 2022 23:52:19 +0200 Subject: [PATCH 1092/1472] Bump parking_lot from 0.12.0 to 0.12.1 (#12098) Bumps [parking_lot](https://github.com/Amanieu/parking_lot) from 0.12.0 to 0.12.1. - [Release notes](https://github.com/Amanieu/parking_lot/releases) - [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md) - [Commits](https://github.com/Amanieu/parking_lot/compare/0.12.0...0.12.1) --- updated-dependencies: - dependency-name: parking_lot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 100 +++++++++--------- client/api/Cargo.toml | 2 +- client/basic-authorship/Cargo.toml | 2 +- client/beefy/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/service/test/Cargo.toml | 2 +- client/state-db/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- client/utils/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 2 +- frame/state-trie-migration/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/database/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 2 +- .../runtime/transaction-pool/Cargo.toml | 2 +- 35 files changed, 84 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed0d5777d94fe..f82cc5d61671e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -448,7 +448,7 @@ dependencies = [ "hex", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -491,7 +491,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-rpc", "sc-utils", "serde", @@ -2037,7 +2037,7 @@ dependencies = [ "log", "num-traits", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.8.4", "scale-info", ] @@ -3214,7 +3214,7 @@ dependencies = [ "hyper", "jsonrpsee-types", "lazy_static", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.8.4", "rustc-hash", "serde", @@ -3453,7 +3453,7 @@ checksum = "ece7e668abd21387aeb6628130a6f4c802787f014fa46bc83221448322250357" dependencies = [ "kvdb", "parity-util-mem", - "parking_lot 0.12.0", + "parking_lot 0.12.1", ] [[package]] @@ -3468,7 +3468,7 @@ dependencies = [ "num_cpus", "owning_ref", "parity-util-mem", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "regex", "rocksdb", "smallvec", @@ -3574,7 +3574,7 @@ dependencies = [ "libp2p-websocket", "libp2p-yamux", "multiaddr", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pin-project", "rand 0.7.3", "smallvec", @@ -3619,7 +3619,7 @@ dependencies = [ "multiaddr", "multihash", "multistream-select", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pin-project", "prost", "prost-build", @@ -3655,7 +3655,7 @@ dependencies = [ "futures", "libp2p-core", "log", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "smallvec", "trust-dns-resolver", ] @@ -3804,7 +3804,7 @@ dependencies = [ "libp2p-core", "log", "nohash-hasher", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.7.3", "smallvec", "unsigned-varint", @@ -4030,7 +4030,7 @@ dependencies = [ "futures-rustls", "libp2p-core", "log", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "quicksink", "rw-stream-sink", "soketto", @@ -4046,7 +4046,7 @@ checksum = "c6dea686217a06072033dc025631932810e2f6ad784e4fafa42e27d311c7a81c" dependencies = [ "futures", "libp2p-core", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "thiserror", "yamux", ] @@ -5597,7 +5597,7 @@ dependencies = [ "pallet-balances", "pallet-election-provider-support-benchmarking", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.7.3", "scale-info", "sp-arithmetic", @@ -6295,7 +6295,7 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "remote-externalities", "scale-info", "serde", @@ -6586,7 +6586,7 @@ dependencies = [ "hashbrown 0.12.3", "impl-trait-for-tuples", "parity-util-mem-derive", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "primitive-types", "smallvec", "winapi", @@ -6637,9 +6637,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core 0.9.1", @@ -7762,7 +7762,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -7869,7 +7869,7 @@ dependencies = [ "hash-db", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-executor", "sc-transaction-pool-api", "sc-utils", @@ -7904,7 +7904,7 @@ dependencies = [ "log", "parity-db", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "quickcheck", "rand 0.8.4", "sc-client-api", @@ -7930,7 +7930,7 @@ dependencies = [ "futures-timer", "libp2p", "log", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-client-api", "sc-utils", "serde", @@ -7953,7 +7953,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -7995,7 +7995,7 @@ dependencies = [ "num-rational 0.2.4", "num-traits", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.7.3", "rand_chacha 0.2.2", "sc-block-builder", @@ -8117,7 +8117,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-client-api", "sc-consensus", "sp-api", @@ -8178,7 +8178,7 @@ dependencies = [ "lru", "num_cpus", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "paste 1.0.6", "regex", "sc-executor-common", @@ -8277,7 +8277,7 @@ dependencies = [ "hex", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.8.4", "sc-block-builder", "sc-chain-spec", @@ -8357,7 +8357,7 @@ version = "4.0.0-dev" dependencies = [ "async-trait", "hex", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "serde_json", "sp-application-crypto", "sp-core", @@ -8390,7 +8390,7 @@ dependencies = [ "log", "lru", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pin-project", "prost", "prost-build", @@ -8526,7 +8526,7 @@ dependencies = [ "futures-timer", "libp2p", "log", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8562,7 +8562,7 @@ dependencies = [ "num_cpus", "once_cell", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8617,7 +8617,7 @@ dependencies = [ "lazy_static", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -8652,7 +8652,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-chain-spec", "sc-transaction-pool-api", "scale-info", @@ -8707,7 +8707,7 @@ dependencies = [ "log", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pin-project", "rand 0.7.3", "sc-block-builder", @@ -8771,7 +8771,7 @@ dependencies = [ "hex-literal", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -8806,7 +8806,7 @@ dependencies = [ "parity-scale-codec", "parity-util-mem", "parity-util-mem-derive", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-client-api", "sp-core", ] @@ -8855,7 +8855,7 @@ dependencies = [ "futures", "libp2p", "log", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pin-project", "rand 0.7.3", "serde", @@ -8876,7 +8876,7 @@ dependencies = [ "libc", "log", "once_cell", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "regex", "rustc-hash", "sc-client-api", @@ -8918,7 +8918,7 @@ dependencies = [ "log", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-block-builder", "sc-client-api", "sc-transaction-pool-api", @@ -8958,7 +8958,7 @@ dependencies = [ "futures-timer", "lazy_static", "log", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "prometheus", "tokio-test", ] @@ -9543,7 +9543,7 @@ dependencies = [ "log", "lru", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sp-api", "sp-consensus", "sp-database", @@ -9670,7 +9670,7 @@ dependencies = [ "num-traits", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "primitive-types", "rand 0.7.3", "regex", @@ -9724,7 +9724,7 @@ name = "sp-database" version = "4.0.0-dev" dependencies = [ "kvdb", - "parking_lot 0.12.0", + "parking_lot 0.12.1", ] [[package]] @@ -9787,7 +9787,7 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "secp256k1", "sp-core", "sp-externalities", @@ -9820,7 +9820,7 @@ dependencies = [ "futures", "merlin", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.7.3", "rand_chacha 0.2.2", "schnorrkel", @@ -10065,7 +10065,7 @@ dependencies = [ "log", "num-traits", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pretty_assertions", "rand 0.7.3", "smallvec", @@ -10185,7 +10185,7 @@ dependencies = [ "memory-db", "nohash-hasher", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "scale-info", "sp-core", "sp-runtime", @@ -10522,7 +10522,7 @@ version = "2.0.0" dependencies = [ "futures", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-transaction-pool", "sc-transaction-pool-api", "sp-blockchain", @@ -10808,7 +10808,7 @@ dependencies = [ "mio", "num_cpus", "once_cell", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pin-project-lite 0.2.6", "signal-hook-registry", "socket2", @@ -11070,7 +11070,7 @@ dependencies = [ "lazy_static", "log", "lru-cache", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "resolv-conf", "smallvec", "thiserror", @@ -12137,7 +12137,7 @@ dependencies = [ "futures", "log", "nohash-hasher", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.8.4", "static_assertions", ] diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index c8e9dc7482823..8cb3ad565afb0 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -21,7 +21,7 @@ fnv = "1.0.6" futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } log = "0.4.17" -parking_lot = "0.12.0" +parking_lot = "0.12.1" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-executor = { version = "0.10.0-dev", path = "../executor" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index a2ccba486ae29..43493ada051f8 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -31,6 +31,6 @@ sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] -parking_lot = "0.12.0" +parking_lot = "0.12.1" sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index e219420959c9f..cc29fb0d809b3 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -16,7 +16,7 @@ futures = "0.3" futures-timer = "3.0.1" hex = "0.4.2" log = "0.4" -parking_lot = "0.12.0" +parking_lot = "0.12.1" thiserror = "1.0" wasm-timer = "0.2.5" beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 46ee7640d710a..744dbb72ff277 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -13,7 +13,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive futures = "0.3.21" jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } log = "0.4" -parking_lot = "0.12.0" +parking_lot = "0.12.1" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0" beefy-gadget = { version = "4.0.0-dev", path = "../." } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 69499fa346e31..7f3164a6ae5be 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -37,7 +37,7 @@ sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [dev-dependencies] -parking_lot = "0.12.0" +parking_lot = "0.12.1" tempfile = "3.1.0" sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } sc-network = { version = "0.10.0-dev", path = "../../network" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 59d7854619fc0..f8c057344db0f 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -24,7 +24,7 @@ merlin = "2.0" num-bigint = "0.2.3" num-rational = "0.2.2" num-traits = "0.2.8" -parking_lot = "0.12.0" +parking_lot = "0.12.1" rand = "0.7.2" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } serde = { version = "1.0.136", features = ["derive"] } diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 12b630f36b89b..b713059074173 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -18,7 +18,7 @@ futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" libp2p = { version = "0.46.1", default-features = false } log = "0.4.17" -parking_lot = "0.12.0" +parking_lot = "0.12.1" serde = { version = "1.0", features = ["derive"] } thiserror = "1.0.30" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 7e9b43fac8a57..bc0ab55d4b492 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.17" -parking_lot = "0.12.0" +parking_lot = "0.12.1" thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 144791fda5c3c..7f564ae642433 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -23,7 +23,7 @@ kvdb-rocksdb = { version = "0.15.2", optional = true } linked-hash-map = "0.5.4" log = "0.4.17" parity-db = "0.3.16" -parking_lot = "0.12.0" +parking_lot = "0.12.1" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 566ed0a50fc0f..6a4b2a44a2d44 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] lazy_static = "1.4.0" lru = "0.7.5" -parking_lot = "0.12.0" +parking_lot = "0.12.1" tracing = "0.1.29" wasmi = "0.9.1" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index a5f20b9f3261d..ed29a9a11881d 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -23,7 +23,7 @@ futures-timer = "3.0.1" hex = "0.4.2" log = "0.4.17" parity-scale-codec = { version = "3.0.0", features = ["derive"] } -parking_lot = "0.12.0" +parking_lot = "0.12.1" rand = "0.8.4" serde_json = "1.0.79" thiserror = "1.0" diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index be4adba2a52fe..cc6a597da72c7 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.50" hex = "0.4.0" -parking_lot = "0.12.0" +parking_lot = "0.12.1" serde_json = "1.0.79" thiserror = "1.0" sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 2742262b57e40..0580e80d629f9 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -34,7 +34,7 @@ linked_hash_set = "0.1.3" linked-hash-map = "0.5.4" log = "0.4.17" lru = "0.7.5" -parking_lot = "0.12.0" +parking_lot = "0.12.1" pin-project = "1.0.10" prost = "0.10" rand = "0.7.2" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 1aa6ebd8bf357..ecdf146696253 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.21" futures-timer = "3.0.1" libp2p = { version = "0.46.1", default-features = false } log = "0.4.17" -parking_lot = "0.12.0" +parking_lot = "0.12.1" rand = "0.7.2" sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 89b77dbb5fea7..ff97f29961155 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -24,7 +24,7 @@ hyper-rustls = { version = "0.23.0", features = ["http2"] } libp2p = { version = "0.46.1", default-features = false } num_cpus = "1.13" once_cell = "1.8" -parking_lot = "0.12.0" +parking_lot = "0.12.1" rand = "0.7.2" threadpool = "1.7" tracing = "0.1.29" diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 101d558663f9f..e9cd08923d020 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" log = "0.4.17" -parking_lot = "0.12.0" +parking_lot = "0.12.1" scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 2381323d25a24..205df580139b8 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -19,7 +19,7 @@ hash-db = { version = "0.15.2", default-features = false } jsonrpsee = { version = "0.15.1", features = ["server"] } lazy_static = { version = "1.4.0", optional = true } log = "0.4.17" -parking_lot = "0.12.0" +parking_lot = "0.12.1" serde_json = "1.0.79" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index e8ddf40a0ae03..e3fe30b08d815 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -26,7 +26,7 @@ jsonrpsee = { version = "0.15.1", features = ["server"] } thiserror = "1.0.30" futures = "0.3.21" rand = "0.7.3" -parking_lot = "0.12.0" +parking_lot = "0.12.1" log = "0.4.17" futures-timer = "3.0.1" exit-future = "0.2.0" diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 01c3ee2348ef5..92df5381c202b 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -18,7 +18,7 @@ hex = "0.4" hex-literal = "0.3.4" log = "0.4.17" parity-scale-codec = "3.0.0" -parking_lot = "0.12.0" +parking_lot = "0.12.1" tempfile = "3.1.0" tokio = { version = "1.17.0", features = ["time"] } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 08856ce3f48a9..4243968ec79b4 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -17,6 +17,6 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive log = "0.4.17" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } parity-util-mem-derive = "0.1.0" -parking_lot = "0.12.0" +parking_lot = "0.12.1" sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-core = { version = "6.0.0", path = "../../primitives/core" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 0d966dacfc2c8..040e7b5dc8ca3 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -18,7 +18,7 @@ chrono = "0.4.19" futures = "0.3.21" libp2p = { version = "0.46.1", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.17" -parking_lot = "0.12.0" +parking_lot = "0.12.1" pin-project = "1.0.10" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 476e03ee741f3..8bc5d770c9c5a 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -20,7 +20,7 @@ lazy_static = "1.4.0" libc = "0.2.121" log = { version = "0.4.17" } once_cell = "1.8.0" -parking_lot = "0.12.0" +parking_lot = "0.12.1" regex = "1.5.5" rustc-hash = "1.1.0" serde = "1.0.136" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 3fdcde48d9e22..9aa05694b6619 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -19,7 +19,7 @@ futures-timer = "3.0.2" linked-hash-map = "0.5.4" log = "0.4.17" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } -parking_lot = "0.12.0" +parking_lot = "0.12.1" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index 2df04be7fb4af..082ac3b55e80d 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -14,7 +14,7 @@ futures = "0.3.21" futures-timer = "3.0.2" lazy_static = "1.4.0" log = "0.4" -parking_lot = "0.12.0" +parking_lot = "0.12.1" prometheus = { version = "0.13.0", default-features = false } [features] diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index bbb0adf02e366..aea3b5cd6d2b0 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -40,7 +40,7 @@ rand = { version = "0.7.3", default-features = false, features = ["alloc", "smal strum = { version = "0.24.1", default-features = false, features = ["derive"], optional = true } [dev-dependencies] -parking_lot = "0.12.0" +parking_lot = "0.12.1" rand = { version = "0.7.3" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", path = "../../primitives/io" } diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index 5a93701141da9..f8a3b1ba3aab4 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -30,7 +30,7 @@ sp-std = { default-features = false, path = "../../primitives/std" } substrate-state-trie-migration-rpc = { optional = true, path = "../../utils/frame/rpc/state-trie-migration-rpc" } [dev-dependencies] -parking_lot = "0.12.0" +parking_lot = "0.12.1" tokio = { version = "1.17.0", features = ["macros"] } pallet-balances = { path = "../balances" } sp-tracing = { path = "../../primitives/tracing" } diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index a5137606e16a2..4d4718b4038d4 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = futures = "0.3.21" log = "0.4.17" lru = "0.7.5" -parking_lot = "0.12.0" +parking_lot = "0.12.1" thiserror = "1.0.30" sp-api = { version = "4.0.0-dev", path = "../api" } sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 2cdfd04e942d7..d591657ee4bd9 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -35,7 +35,7 @@ num-traits = { version = "0.2.8", default-features = false } zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } -parking_lot = { version = "0.12.0", optional = true } +parking_lot = { version = "0.12.1", optional = true } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } diff --git a/primitives/database/Cargo.toml b/primitives/database/Cargo.toml index 5aa3d9a239aa3..a3f09536f4f5c 100644 --- a/primitives/database/Cargo.toml +++ b/primitives/database/Cargo.toml @@ -12,4 +12,4 @@ readme = "README.md" [dependencies] kvdb = "0.11.0" -parking_lot = "0.12.0" +parking_lot = "0.12.1" diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index fda6b7fdd11dd..2e271d3949dee 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -30,7 +30,7 @@ sp-externalities = { version = "0.12.0", default-features = false, path = "../ex sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.17", optional = true } futures = { version = "0.3.21", features = ["thread-pool"], optional = true } -parking_lot = { version = "0.12.0", optional = true } +parking_lot = { version = "0.12.1", optional = true } secp256k1 = { version = "0.24.0", features = ["recovery", "global-context"], optional = true } tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.28", default-features = false} diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 3c3b7933c50da..ed12a5cfcee7f 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -17,7 +17,7 @@ async-trait = "0.1.50" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } futures = "0.3.21" merlin = { version = "2.0", default-features = false } -parking_lot = { version = "0.12.0", default-features = false } +parking_lot = { version = "0.12.1", default-features = false } schnorrkel = { version = "0.9.1", default-features = false, features = ["preaudit_deprecated", "u64_backend"] } serde = { version = "1.0", optional = true } thiserror = "1.0" diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 00acca7e86788..5de6eb7112eea 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = hash-db = { version = "0.15.2", default-features = false } log = { version = "0.4.17", optional = true } num-traits = { version = "0.2.8", default-features = false } -parking_lot = { version = "0.12.0", optional = true } +parking_lot = { version = "0.12.1", optional = true } rand = { version = "0.7.2", optional = true } smallvec = "1.8.0" thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 84b97a9f88da8..291615c9354c1 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -26,7 +26,7 @@ lazy_static = { version = "1.4.0", optional = true } lru = { version = "0.7.5", optional = true } memory-db = { version = "0.29.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } -parking_lot = { version = "0.12.0", optional = true } +parking_lot = { version = "0.12.1", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } tracing = { version = "0.1.29", optional = true } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index 98378309ad9c1..fa6dde5b5b57e 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -parking_lot = "0.12.0" +parking_lot = "0.12.1" thiserror = "1.0" sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } From a5e28701dd9eb8fdbc315395609bf92cd8a5e731 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Aug 2022 09:31:56 +0200 Subject: [PATCH 1093/1472] Bump async-trait from 0.1.51 to 0.1.57 (#11948) Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.51 to 0.1.57. - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](https://github.com/dtolnay/async-trait/compare/0.1.51...0.1.57) --- updated-dependencies: - dependency-name: async-trait dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- client/beefy/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/consensus/pow/Cargo.toml | 2 +- client/consensus/slots/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/network/common/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- primitives/authorship/Cargo.toml | 2 +- primitives/consensus/aura/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/consensus/common/Cargo.toml | 2 +- primitives/inherents/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- primitives/timestamp/Cargo.toml | 2 +- primitives/transaction-storage-proof/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- 22 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f82cc5d61671e..0eec6698fae5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -343,9 +343,9 @@ checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] name = "async-trait" -version = "0.1.51" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" dependencies = [ "proc-macro2", "quote", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index cc29fb0d809b3..5cc2952e26ba5 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -9,7 +9,7 @@ description = "BEEFY Client gadget for substrate" homepage = "https://substrate.io" [dependencies] -async-trait = "0.1.50" +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } fnv = "1.0.6" futures = "0.3" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 7f3164a6ae5be..3fe9891e9a7ba 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.50" +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" log = "0.4.17" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index f8c057344db0f..e559ec165a793 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.50" +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index b713059074173..180ad7c38008d 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.42" +async-trait = "0.1.57" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" libp2p = { version = "0.46.1", default-features = false } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 83c156ef5667f..9c3bc5413317d 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } assert_matches = "1.3.0" -async-trait = "0.1.50" +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" log = "0.4.17" diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index bc0ab55d4b492..4833786d2b990 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.50" +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.1" diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 41a6c1ad5e641..208e31971257d 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.50" +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" futures-timer = "3.0.1" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index ed29a9a11881d..0155b4d4197d7 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ahash = "0.7.6" -async-trait = "0.1.50" +async-trait = "0.1.57" dyn-clone = "1.0" finality-grandpa = { version = "0.16.0", features = ["derive-codec"] } futures = "0.3.21" diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index cc6a597da72c7..2605a767f9c04 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.50" +async-trait = "0.1.57" hex = "0.4.0" parking_lot = "0.12.1" serde_json = "1.0.79" diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 8f0702e05cac5..ea50c8b794ccb 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.10" [dependencies] -async-trait = "0.1.50" +async-trait = "0.1.57" bitflags = "1.3.2" bytes = "1" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index ecdf146696253..990129229a40f 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-std = "1.11.0" -async-trait = "0.1.50" +async-trait = "0.1.57" futures = "0.3.21" futures-timer = "3.0.1" libp2p = { version = "0.46.1", default-features = false } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index e3fe30b08d815..0c448b5e80b94 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -80,7 +80,7 @@ tracing-futures = { version = "0.2.4" } parity-util-mem = { version = "0.11.0", default-features = false, features = [ "primitive-types", ] } -async-trait = "0.1.50" +async-trait = "0.1.57" tokio = { version = "1.17.0", features = ["time", "rt-multi-thread", "parking_lot"] } tempfile = "3.1.0" directories = "4.0.1" diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index 714d0a2610312..3a8cb3f37cbd3 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.50", optional = true } +async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index dbb67a27c5144..30f5c89650a78 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.50", optional = true } +async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 736a78ab67b1a..049e511175867 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.50", optional = true } +async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } merlin = { version = "2.0", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 973cb3e410e0d..d160cd118998c 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.42" +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index c7e10be32fe28..628f938880e9f 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.50", optional = true } +async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index ed12a5cfcee7f..cbb8a22ba4dd6 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -13,7 +13,7 @@ documentation = "https://docs.rs/sp-core" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.50" +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } futures = "0.3.21" merlin = { version = "2.0", default-features = false } diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 42701f5ad3bf1..2e8f281cd7c7b 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.50", optional = true } +async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } futures-timer = { version = "3.0.2", optional = true } log = { version = "0.4.17", optional = true } diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index a5a80528c6734..e916462675435 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.50", optional = true } +async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index ce5ef2ffcc01a..28dbe29949660 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -12,7 +12,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.50" +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" hex = "0.4" From 6dd5631aefb004e9704ce9244c4ef79f4fc9c002 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Aug 2022 09:32:20 +0200 Subject: [PATCH 1094/1472] Bump serde_json from 1.0.79 to 1.0.85 (#12079) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.79 to 1.0.85. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.79...v1.0.85) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- bin/node/bench/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/chain-spec/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/keystore/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/sysinfo/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/transaction-payment/Cargo.toml | 2 +- frame/transaction-payment/asset-tx-payment/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/serializer/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- 27 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0eec6698fae5e..64e84fe4710af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9175,9 +9175,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "itoa 1.0.1", "ryu", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 4d090c71a72e9..c7a747c30ed2e 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -18,7 +18,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } serde = "1.0.136" -serde_json = "1.0.79" +serde_json = "1.0.85" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } kvdb = "0.11.0" kvdb-rocksdb = "0.15.1" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 89ca3ebb45576..d84b8491cb162 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -98,7 +98,7 @@ sc-cli = { version = "0.10.0-dev", optional = true, path = "../../../client/cli" frame-benchmarking-cli = { version = "4.0.0-dev", optional = true, path = "../../../utils/frame/benchmarking-cli" } node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../utils/frame/try-runtime/cli" } -serde_json = "1.0.79" +serde_json = "1.0.85" [target.'cfg(any(target_arch="x86_64", target_arch="aarch64"))'.dependencies] node-executor = { version = "3.0.0-dev", path = "../executor", features = ["wasmtime"] } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 744dbb72ff277..3ccf83c1f5106 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -24,7 +24,7 @@ sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.79" +serde_json = "1.0.85" sc-rpc = { version = "4.0.0-dev", features = [ "test-helpers", ], path = "../../rpc" } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index bd4ee548e296b..b38dba03d6b7f 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } impl-trait-for-tuples = "0.2.2" memmap2 = "0.5.0" serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.79" +serde_json = "1.0.85" sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 5f4c00d06aea3..50d110d40eabd 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -26,7 +26,7 @@ rand = "0.7.3" regex = "1.5.5" rpassword = "7.0.0" serde = "1.0.136" -serde_json = "1.0.79" +serde_json = "1.0.85" thiserror = "1.0.30" tiny-bip39 = "0.8.2" tokio = { version = "1.17.0", features = ["signal", "rt-multi-thread", "parking_lot"] } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 488036277d7b6..8433e3ac92e57 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -30,7 +30,7 @@ sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.79" +serde_json = "1.0.85" tempfile = "3.1.0" tokio = "1.17.0" sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 0155b4d4197d7..5950b108ca4ab 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -25,7 +25,7 @@ log = "0.4.17" parity-scale-codec = { version = "3.0.0", features = ["derive"] } parking_lot = "0.12.1" rand = "0.8.4" -serde_json = "1.0.79" +serde_json = "1.0.85" thiserror = "1.0" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 2605a767f9c04..9b7afba759c60 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.57" hex = "0.4.0" parking_lot = "0.12.1" -serde_json = "1.0.79" +serde_json = "1.0.85" thiserror = "1.0" sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } sp-core = { version = "6.0.0", path = "../../primitives/core" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 0580e80d629f9..82f77fa44450f 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -39,7 +39,7 @@ pin-project = "1.0.10" prost = "0.10" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.79" +serde_json = "1.0.85" smallvec = "1.8.0" thiserror = "1.0" unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index 510ebf7006155..d3d6e267f1768 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] futures = "0.3.21" libp2p = { version = "0.46.1", default-features = false } log = "0.4.17" -serde_json = "1.0.79" +serde_json = "1.0.85" wasm-timer = "0.2" sc-utils = { version = "4.0.0-dev", path = "../utils" } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index e9cd08923d020..7c4057154bdb0 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -19,7 +19,7 @@ log = "0.4.17" parking_lot = "0.12.1" scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.79" +serde_json = "1.0.85" thiserror = "1.0" sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index 8b40972527be8..ef2e6bec4cdb0 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -16,6 +16,6 @@ targets = ["x86_64-unknown-linux-gnu"] futures = "0.3.21" jsonrpsee = { version = "0.15.1", features = ["server"] } log = "0.4.17" -serde_json = "1.0.79" +serde_json = "1.0.85" tokio = { version = "1.17.0", features = ["parking_lot"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 205df580139b8..4131fecaf510e 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -20,7 +20,7 @@ jsonrpsee = { version = "0.15.1", features = ["server"] } lazy_static = { version = "1.4.0", optional = true } log = "0.4.17" parking_lot = "0.12.1" -serde_json = "1.0.79" +serde_json = "1.0.85" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 0c448b5e80b94..0acdbb1b1b63e 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -33,7 +33,7 @@ exit-future = "0.2.0" pin-project = "1.0.10" hash-db = "0.15.2" serde = "1.0.136" -serde_json = "1.0.79" +serde_json = "1.0.85" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } sp-trie = { version = "6.0.0", path = "../../primitives/trie" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index d02637fcf884b..12ffc0c2e8d7a 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.79" +serde_json = "1.0.85" thiserror = "1.0.30" sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/sysinfo/Cargo.toml b/client/sysinfo/Cargo.toml index 0973631a3cc24..1e96f69a92dfe 100644 --- a/client/sysinfo/Cargo.toml +++ b/client/sysinfo/Cargo.toml @@ -21,7 +21,7 @@ rand = "0.7.3" rand_pcg = "0.2.1" regex = "1" serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.79" +serde_json = "1.0.85" sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-io = { version = "6.0.0", path = "../../primitives/io" } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 040e7b5dc8ca3..4be7c186720fc 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -22,6 +22,6 @@ parking_lot = "0.12.1" pin-project = "1.0.10" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.79" +serde_json = "1.0.85" thiserror = "1.0.30" wasm-timer = "0.2.5" diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index c7d9662904747..3da6678a39bf2 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -23,4 +23,4 @@ sp-mmr-primitives = { version = "4.0.0-dev", path = "../../../primitives/merkle- sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.79" +serde_json = "1.0.85" diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 1b6488bbd4712..6f0831b751b45 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -39,7 +39,7 @@ sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/ k256 = { version = "0.10.4", default-features = false, features = ["ecdsa"] } [dev-dependencies] -serde_json = "1.0.79" +serde_json = "1.0.85" assert_matches = "1.3.0" pretty_assertions = "1.2.1" frame-system = { version = "4.0.0-dev", path = "../system" } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 51aeeabe99db8..9150f87c7175a 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -26,7 +26,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -serde_json = "1.0.79" +serde_json = "1.0.85" pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 2d4da250212f2..de9772d885529 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -29,7 +29,7 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" serde = { version = "1.0.136", optional = true } [dev-dependencies] -serde_json = "1.0.79" +serde_json = "1.0.85" sp-storage = { version = "6.0.0", default-features = false, path = "../../../primitives/storage" } diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index 335eb6d6c9a0e..f4a4fe12f6c47 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -18,4 +18,4 @@ serde = { version = "1.0.136", features = ["derive"] } sp-core = { version = "6.0.0", path = "../core" } [dev-dependencies] -serde_json = "1.0.79" +serde_json = "1.0.85" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 1493aa2324f56..9e4b36c584e91 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -32,7 +32,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] rand = "0.7.2" -serde_json = "1.0.79" +serde_json = "1.0.85" zstd = { version = "0.11.2", default-features = false } sp-api = { version = "4.0.0-dev", path = "../api" } sp-state-machine = { version = "0.12.0", path = "../state-machine" } diff --git a/primitives/serializer/Cargo.toml b/primitives/serializer/Cargo.toml index c81f1cd10a824..585e4b4e0dc20 100644 --- a/primitives/serializer/Cargo.toml +++ b/primitives/serializer/Cargo.toml @@ -15,4 +15,4 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = "1.0.136" -serde_json = "1.0.79" +serde_json = "1.0.85" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 28dbe29949660..f8a1f437d45e1 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" hex = "0.4" serde = "1.0.136" -serde_json = "1.0.79" +serde_json = "1.0.85" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } sc-client-db = { version = "0.10.0-dev", default-features = false, features = [ "test-helpers", diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 31b8f1332a653..4f9d703544096 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -30,7 +30,7 @@ memory-db = "0.29.0" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.136" -serde_json = "1.0.79" +serde_json = "1.0.85" serde_nanos = "0.1.2" tempfile = "3.2.0" thiserror = "1.0.30" From ea4f532cffde1b90651d8f1be13a10c3721dd3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Sat, 27 Aug 2022 06:56:24 +0200 Subject: [PATCH 1095/1472] `try-runtime` - support all state versions (#12089) * Add argument * Apply * More verbose parsing * fmt * fmt again * Invalid state version * reuse parsing * type mismatch --- .../try-runtime/cli/src/commands/execute_block.rs | 3 ++- .../try-runtime/cli/src/commands/follow_chain.rs | 12 +++++++----- .../try-runtime/cli/src/commands/offchain_worker.rs | 2 +- .../cli/src/commands/on_runtime_upgrade.rs | 2 +- utils/frame/try-runtime/cli/src/lib.rs | 5 +++++ utils/frame/try-runtime/cli/src/parse.rs | 9 +++++++++ 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index 204acd879312f..aee3c34a1e0e8 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -139,7 +139,8 @@ where .state .builder::()? // make sure the state is being build with the parent hash, if it is online. - .overwrite_online_at(parent_hash.to_owned()); + .overwrite_online_at(parent_hash.to_owned()) + .state_version(shared.state_version); let builder = if command.overwrite_wasm_code { log::info!( diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index e2e6bd7244945..b6a11699a3d72 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -102,11 +102,13 @@ where // create an ext at the state of this block, whatever is the first subscription event. if maybe_state_ext.is_none() { - let builder = Builder::::new().mode(Mode::Online(OnlineConfig { - transport: command.uri.clone().into(), - at: Some(*header.parent_hash()), - ..Default::default() - })); + let builder = Builder::::new() + .mode(Mode::Online(OnlineConfig { + transport: command.uri.clone().into(), + at: Some(*header.parent_hash()), + ..Default::default() + })) + .state_version(shared.state_version); let new_ext = builder .inject_hashed_key_value(&[(code_key.clone(), code.clone())]) diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index 50780f4513b2f..11ceb0a81cf37 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -128,7 +128,7 @@ where ); let ext = { - let builder = command.state.builder::()?; + let builder = command.state.builder::()?.state_version(shared.state_version); let builder = if command.overwrite_wasm_code { log::info!( diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 616498da02497..9bc6d32d4762a 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -52,7 +52,7 @@ where let execution = shared.execution; let ext = { - let builder = command.state.builder::()?; + let builder = command.state.builder::()?.state_version(shared.state_version); let (code_key, code) = extract_code(&config.chain_spec)?; builder.inject_hashed_key_value(&[(code_key, code)]).build().await? }; diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index be7ec923a55bc..9013da95f1722 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -294,6 +294,7 @@ use sp_runtime::{ DeserializeOwned, }; use sp_state_machine::{OverlayedChanges, StateMachine, TrieBackendBuilder}; +use sp_version::StateVersion; use std::{fmt::Debug, path::PathBuf, str::FromStr}; mod commands; @@ -421,6 +422,10 @@ pub struct SharedParams { /// When enabled, the spec name check will not panic, and instead only show a warning. #[clap(long)] pub no_spec_name_check: bool, + + /// State version that is used by the chain. + #[clap(long, default_value = "1", parse(try_from_str = parse::state_version))] + pub state_version: StateVersion, } /// Our `try-runtime` command. diff --git a/utils/frame/try-runtime/cli/src/parse.rs b/utils/frame/try-runtime/cli/src/parse.rs index 15a0251ebc34a..257a99566979f 100644 --- a/utils/frame/try-runtime/cli/src/parse.rs +++ b/utils/frame/try-runtime/cli/src/parse.rs @@ -17,6 +17,8 @@ //! Utils for parsing user input +use sp_version::StateVersion; + pub(crate) fn hash(block_hash: &str) -> Result { let (block_hash, offset) = if let Some(block_hash) = block_hash.strip_prefix("0x") { (block_hash, 2) @@ -42,3 +44,10 @@ pub(crate) fn url(s: &str) -> Result { Err("not a valid WS(S) url: must start with 'ws://' or 'wss://'") } } + +pub(crate) fn state_version(s: &str) -> Result { + s.parse::() + .map_err(|_| ()) + .and_then(StateVersion::try_from) + .map_err(|_| "Invalid state version.") +} From 4c83ee0a406939f1393d19f87675e1fbc49e328d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sun, 28 Aug 2022 13:55:54 +0100 Subject: [PATCH 1096/1472] Fix nomination pools pending rewards RPC (#12095) * Fix nomination pools pending rewards RPC * Fix node * Update frame/nomination-pools/src/lib.rs * Fix docs --- bin/node/runtime/src/lib.rs | 2 +- frame/nomination-pools/src/lib.rs | 18 ++++++---- frame/nomination-pools/src/tests.rs | 53 +++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index ff793a49b5ce6..0816fedff0347 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1842,7 +1842,7 @@ impl_runtime_apis! { impl pallet_nomination_pools_runtime_api::NominationPoolsApi for Runtime { fn pending_rewards(member_account: AccountId) -> Balance { - NominationPools::pending_rewards(member_account) + NominationPools::pending_rewards(member_account).unwrap_or_default() } } diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 62d0b3ddd55cb..40db4ac64851a 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2156,16 +2156,20 @@ pub mod pallet { impl Pallet { /// Returns the pending rewards for the specified `member_account`. /// - /// In the case of error the function returns balance of zero. - pub fn pending_rewards(member_account: T::AccountId) -> BalanceOf { + /// In the case of error, `None` is returned. + pub fn pending_rewards(member_account: T::AccountId) -> Option> { if let Some(pool_member) = PoolMembers::::get(member_account) { - if let Some(reward_pool) = RewardPools::::get(pool_member.pool_id) { - return pool_member - .pending_rewards(reward_pool.last_recorded_reward_counter()) - .unwrap_or_default() + if let Some((reward_pool, bonded_pool)) = RewardPools::::get(pool_member.pool_id) + .zip(BondedPools::::get(pool_member.pool_id)) + { + let current_reward_counter = reward_pool + .current_reward_counter(pool_member.pool_id, bonded_pool.points) + .ok()?; + return pool_member.pending_rewards(current_reward_counter).ok() } } - BalanceOf::::default() + + None } /// The amount of bond that MUST REMAIN IN BONDED in ALL POOLS. diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 5aa8e97266e0d..705f8ce3a6449 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -1285,6 +1285,59 @@ mod claim_payout { }); } + #[test] + fn pending_rewards_per_member_works() { + ExtBuilder::default().build_and_execute(|| { + let ed = Balances::minimum_balance(); + + assert_eq!(Pools::pending_rewards(10), Some(0)); + Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + assert_eq!(Pools::pending_rewards(10), Some(30)); + assert_eq!(Pools::pending_rewards(20), None); + + Balances::make_free_balance_be(&20, ed + 10); + assert_ok!(Pools::join(Origin::signed(20), 10, 1)); + + assert_eq!(Pools::pending_rewards(10), Some(30)); + assert_eq!(Pools::pending_rewards(20), Some(0)); + + Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); + + assert_eq!(Pools::pending_rewards(10), Some(30 + 50)); + assert_eq!(Pools::pending_rewards(20), Some(50)); + assert_eq!(Pools::pending_rewards(30), None); + + Balances::make_free_balance_be(&30, ed + 10); + assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + + assert_eq!(Pools::pending_rewards(10), Some(30 + 50)); + assert_eq!(Pools::pending_rewards(20), Some(50)); + assert_eq!(Pools::pending_rewards(30), Some(0)); + + Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); + + assert_eq!(Pools::pending_rewards(10), Some(30 + 50 + 20)); + assert_eq!(Pools::pending_rewards(20), Some(50 + 20)); + assert_eq!(Pools::pending_rewards(30), Some(20)); + + // 10 should claim 10, 20 should claim nothing. + assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_eq!(Pools::pending_rewards(10), Some(0)); + assert_eq!(Pools::pending_rewards(20), Some(50 + 20)); + assert_eq!(Pools::pending_rewards(30), Some(20)); + + assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_eq!(Pools::pending_rewards(10), Some(0)); + assert_eq!(Pools::pending_rewards(20), Some(0)); + assert_eq!(Pools::pending_rewards(30), Some(20)); + + assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_eq!(Pools::pending_rewards(10), Some(0)); + assert_eq!(Pools::pending_rewards(20), Some(0)); + assert_eq!(Pools::pending_rewards(30), Some(0)); + }); + } + #[test] fn rewards_distribution_is_fair_bond_extra() { ExtBuilder::default().build_and_execute(|| { From 915f3c10f22777a1dc49c1ed894525280ce12244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Kula?= Date: Mon, 29 Aug 2022 10:01:37 +0200 Subject: [PATCH 1097/1472] Additional constraints for NotificationSender (#12121) Co-authored-by: Jedrzej Kula --- client/network/common/src/service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/network/common/src/service.rs b/client/network/common/src/service.rs index 0fff32b12d66c..6df99acf0bdfd 100644 --- a/client/network/common/src/service.rs +++ b/client/network/common/src/service.rs @@ -387,7 +387,7 @@ pub trait NotificationSenderReady { /// A `NotificationSender` allows for sending notifications to a peer with a chosen protocol. #[async_trait::async_trait] -pub trait NotificationSender { +pub trait NotificationSender: Send + Sync + 'static { /// Returns a future that resolves when the `NotificationSender` is ready to send a /// notification. async fn ready(&self) From 419924c4e252b9af75957d3112c9c7a8ea521034 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 29 Aug 2022 14:22:40 +0300 Subject: [PATCH 1098/1472] Bug fix of currencies implementation for `pallet-balances` (#11875) * Add test * Fix the bug * Add similar test for named reservable * Extend test with "overflow" repatriation * Expand test for `NamedReservableCurrency` * Add notes about return values meaning --- frame/balances/src/lib.rs | 6 +++++- frame/balances/src/tests.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 0cb32a4e3ecd6..0a45350366449 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -1000,6 +1000,8 @@ impl, I: 'static> Pallet { /// Is a no-op if: /// - the value to be moved is zero; or /// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`. + /// + /// NOTE: returns actual amount of transferred value in `Ok` case. fn do_transfer_reserved( slashed: &T::AccountId, beneficiary: &T::AccountId, @@ -1013,7 +1015,7 @@ impl, I: 'static> Pallet { if slashed == beneficiary { return match status { - Status::Free => Ok(Self::unreserve(slashed, value)), + Status::Free => Ok(value.saturating_sub(Self::unreserve(slashed, value))), Status::Reserved => Ok(value.saturating_sub(Self::reserved_balance(slashed))), } } @@ -1785,6 +1787,8 @@ where /// Unreserve some funds, returning any amount that was unable to be unreserved. /// /// Is a no-op if the value to be unreserved is zero or the account does not exist. + /// + /// NOTE: returns amount value which wasn't successfully unreserved. fn unreserve(who: &T::AccountId, value: Self::Balance) -> Self::Balance { if value.is_zero() { return Zero::zero() diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 8f5470ae3cac2..a9e44f085977a 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -528,6 +528,22 @@ macro_rules! decl_tests { }); } + #[test] + fn transferring_reserved_balance_to_yourself_should_work() { + <$ext_builder>::default().build().execute_with(|| { + let _ = Balances::deposit_creating(&1, 110); + assert_ok!(Balances::reserve(&1, 50)); + assert_ok!(Balances::repatriate_reserved(&1, &1, 50, Status::Free), 0); + assert_eq!(Balances::free_balance(1), 110); + assert_eq!(Balances::reserved_balance(1), 0); + + assert_ok!(Balances::reserve(&1, 50)); + assert_ok!(Balances::repatriate_reserved(&1, &1, 60, Status::Free), 10); + assert_eq!(Balances::free_balance(1), 110); + assert_eq!(Balances::reserved_balance(1), 0); + }); + } + #[test] fn transferring_reserved_balance_to_nonexistent_should_fail() { <$ext_builder>::default().build().execute_with(|| { @@ -1167,6 +1183,25 @@ macro_rules! decl_tests { }); } + #[test] + fn reserved_named_to_yourself_should_work() { + <$ext_builder>::default().build().execute_with(|| { + let _ = Balances::deposit_creating(&1, 110); + + let id = [1u8; 8]; + + assert_ok!(Balances::reserve_named(&id, &1, 50)); + assert_ok!(Balances::repatriate_reserved_named(&id, &1, &1, 50, Status::Free), 0); + assert_eq!(Balances::free_balance(1), 110); + assert_eq!(Balances::reserved_balance_named(&id, &1), 0); + + assert_ok!(Balances::reserve_named(&id, &1, 50)); + assert_ok!(Balances::repatriate_reserved_named(&id, &1, &1, 60, Status::Free), 10); + assert_eq!(Balances::free_balance(1), 110); + assert_eq!(Balances::reserved_balance_named(&id, &1), 0); + }); + } + #[test] fn ensure_reserved_named_should_work() { <$ext_builder>::default().build().execute_with(|| { From 32c1a0efeddd622707e3ba5e16eb19334c730d28 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Mon, 29 Aug 2022 14:54:57 +0300 Subject: [PATCH 1099/1472] Make `NetworkService::add_reserved_peer()` accept `MultiaddrWithPeerId` (#12102) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make `add_reserved_peer()` accept `MultiaddrWithPeerId` * minor: cargo fmt * minor: error to string conversion Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- .../src/communication/tests.rs | 3 ++- client/network-gossip/src/bridge.rs | 3 ++- client/network-gossip/src/state_machine.rs | 3 ++- client/network/common/src/service.rs | 8 +++--- client/network/src/service.rs | 16 +++++------ client/offchain/src/api.rs | 7 +++-- client/offchain/src/lib.rs | 3 ++- client/service/src/lib.rs | 13 ++++++--- client/service/test/src/lib.rs | 27 ++++++++++--------- 9 files changed, 49 insertions(+), 34 deletions(-) diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index 5b2436b23351e..4d709f56f3d61 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -27,6 +27,7 @@ use futures::prelude::*; use parity_scale_codec::Encode; use sc_network::{config::Role, Multiaddr, PeerId, ReputationChange}; use sc_network_common::{ + config::MultiaddrWithPeerId, protocol::event::{Event as NetworkEvent, ObservedRole}, service::{ NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, @@ -87,7 +88,7 @@ impl NetworkPeers for TestNetwork { unimplemented!(); } - fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { + fn add_reserved_peer(&self, _peer: MultiaddrWithPeerId) -> Result<(), String> { unimplemented!(); } diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index b63e3f64a1256..45eff09332f67 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -317,6 +317,7 @@ mod tests { }; use quickcheck::{Arbitrary, Gen, QuickCheck}; use sc_network_common::{ + config::MultiaddrWithPeerId, protocol::event::ObservedRole, service::{ NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, @@ -371,7 +372,7 @@ mod tests { unimplemented!(); } - fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { + fn add_reserved_peer(&self, _peer: MultiaddrWithPeerId) -> Result<(), String> { unimplemented!(); } diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index a870ca6a3acdf..ff75b4520bf03 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -514,6 +514,7 @@ mod tests { use crate::multiaddr::Multiaddr; use futures::prelude::*; use sc_network_common::{ + config::MultiaddrWithPeerId, protocol::event::Event, service::{ NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, @@ -610,7 +611,7 @@ mod tests { unimplemented!(); } - fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { + fn add_reserved_peer(&self, _peer: MultiaddrWithPeerId) -> Result<(), String> { unimplemented!(); } diff --git a/client/network/common/src/service.rs b/client/network/common/src/service.rs index 6df99acf0bdfd..9544cddf013cf 100644 --- a/client/network/common/src/service.rs +++ b/client/network/common/src/service.rs @@ -19,6 +19,7 @@ // If you read this, you are very thorough, congratulations. use crate::{ + config::MultiaddrWithPeerId, protocol::event::Event, request_responses::{IfDisconnected, RequestFailure}, sync::{warp::WarpSyncProgress, StateDownloadProgress, SyncState}, @@ -179,12 +180,11 @@ pub trait NetworkPeers { /// purposes. fn deny_unreserved_peers(&self); - /// Adds a `PeerId` and its address as reserved. The string should encode the address - /// and peer ID of the remote node. + /// Adds a `PeerId` and its `Multiaddr` as reserved. /// /// Returns an `Err` if the given string is not a valid multiaddress /// or contains an invalid peer ID (which includes the local peer ID). - fn add_reserved_peer(&self, peer: String) -> Result<(), String>; + fn add_reserved_peer(&self, peer: MultiaddrWithPeerId) -> Result<(), String>; /// Removes a `PeerId` from the list of reserved peers. fn remove_reserved_peer(&self, peer_id: PeerId); @@ -285,7 +285,7 @@ where T::deny_unreserved_peers(self) } - fn add_reserved_peer(&self, peer: String) -> Result<(), String> { + fn add_reserved_peer(&self, peer: MultiaddrWithPeerId) -> Result<(), String> { T::add_reserved_peer(self, peer) } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 162b9c6a30491..68ac4b8db8a7d 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -62,7 +62,7 @@ use parking_lot::Mutex; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; use sc_network_common::{ - config::parse_str_addr, + config::MultiaddrWithPeerId, protocol::event::{DhtEvent, Event}, request_responses::{IfDisconnected, RequestFailure}, service::{ @@ -702,9 +702,8 @@ where self.service.remove_reserved_peer(peer); } - /// Adds a `PeerId` and its address as reserved. The string should encode the address - /// and peer ID of the remote node. - pub fn add_reserved_peer(&self, peer: String) -> Result<(), String> { + /// Adds a `PeerId` and its `Multiaddr` as reserved. + pub fn add_reserved_peer(&self, peer: MultiaddrWithPeerId) -> Result<(), String> { self.service.add_reserved_peer(peer) } @@ -912,17 +911,16 @@ where let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::SetReservedOnly(true)); } - fn add_reserved_peer(&self, peer: String) -> Result<(), String> { - let (peer_id, addr) = parse_str_addr(&peer).map_err(|e| format!("{:?}", e))?; + fn add_reserved_peer(&self, peer: MultiaddrWithPeerId) -> Result<(), String> { // Make sure the local peer ID is never added to the PSM. - if peer_id == self.local_peer_id { + if peer.peer_id == self.local_peer_id { return Err("Local peer ID cannot be added as a reserved peer.".to_string()) } let _ = self .to_worker - .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id, addr)); - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::AddReserved(peer_id)); + .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer.peer_id, peer.multiaddr)); + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::AddReserved(peer.peer_id)); Ok(()) } diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 5c8139d4505e7..f40bceb615148 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -326,7 +326,10 @@ mod tests { use super::*; use libp2p::PeerId; use sc_client_db::offchain::LocalStorage; - use sc_network_common::service::{NetworkPeers, NetworkStateInfo}; + use sc_network_common::{ + config::MultiaddrWithPeerId, + service::{NetworkPeers, NetworkStateInfo}, + }; use sc_peerset::ReputationChange; use sp_core::offchain::{DbExternalities, Externalities}; use std::{borrow::Cow, time::SystemTime}; @@ -362,7 +365,7 @@ mod tests { unimplemented!(); } - fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { + fn add_reserved_peer(&self, _peer: MultiaddrWithPeerId) -> Result<(), String> { unimplemented!(); } diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 5eed142ff3871..e215a016872cc 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -249,6 +249,7 @@ mod tests { use libp2p::{Multiaddr, PeerId}; use sc_block_builder::BlockBuilderProvider as _; use sc_client_api::Backend as _; + use sc_network_common::config::MultiaddrWithPeerId; use sc_peerset::ReputationChange; use sc_transaction_pool::{BasicPool, FullChainApi}; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; @@ -300,7 +301,7 @@ mod tests { unimplemented!(); } - fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { + fn add_reserved_peer(&self, _peer: MultiaddrWithPeerId) -> Result<(), String> { unimplemented!(); } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 2f35a04451e79..19358c1e5bc4c 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -42,7 +42,7 @@ use jsonrpsee::{core::Error as JsonRpseeError, RpcModule}; use log::{debug, error, warn}; use sc_client_api::{blockchain::HeaderBackend, BlockBackend, BlockchainEvents, ProofProvider}; use sc_network::PeerId; -use sc_network_common::service::NetworkBlock; +use sc_network_common::{config::MultiaddrWithPeerId, service::NetworkBlock}; use sc_rpc_server::WsConfig; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; @@ -230,8 +230,15 @@ async fn build_network_future< } } sc_rpc::system::Request::NetworkAddReservedPeer(peer_addr, sender) => { - let x = network.add_reserved_peer(peer_addr) - .map_err(sc_rpc::system::error::Error::MalformattedPeerArg); + let result = match MultiaddrWithPeerId::try_from(peer_addr) { + Ok(peer) => { + network.add_reserved_peer(peer) + }, + Err(err) => { + Err(err.to_string()) + }, + }; + let x = result.map_err(sc_rpc::system::error::Error::MalformattedPeerArg); let _ = sender.send(x); } sc_rpc::system::Request::NetworkRemoveReservedPeer(peer_id, sender) => { diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 919c90400e94c..11c1cbaf7afb1 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -24,9 +24,12 @@ use parking_lot::Mutex; use sc_client_api::{Backend, CallExecutor}; use sc_network::{ config::{NetworkConfiguration, TransportConfig}, - multiaddr, Multiaddr, + multiaddr, +}; +use sc_network_common::{ + config::MultiaddrWithPeerId, + service::{NetworkBlock, NetworkPeers, NetworkStateInfo}, }; -use sc_network_common::service::{NetworkBlock, NetworkPeers, NetworkStateInfo}; use sc_service::{ client::Client, config::{BasePath, DatabaseSource, KeystoreConfig}, @@ -49,8 +52,8 @@ const MAX_WAIT_TIME: Duration = Duration::from_secs(60 * 3); struct TestNet { runtime: Runtime, - authority_nodes: Vec<(usize, F, U, Multiaddr)>, - full_nodes: Vec<(usize, F, U, Multiaddr)>, + authority_nodes: Vec<(usize, F, U, MultiaddrWithPeerId)>, + full_nodes: Vec<(usize, F, U, MultiaddrWithPeerId)>, chain_spec: GenericChainSpec, base_port: u16, nodes: usize, @@ -320,7 +323,7 @@ where handle.spawn(service.clone().map_err(|_| ())); let addr = - addr.with(multiaddr::Protocol::P2p((service.network().local_peer_id()).into())); + MultiaddrWithPeerId { multiaddr: addr, peer_id: service.network().local_peer_id() }; self.authority_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; } @@ -340,7 +343,7 @@ where handle.spawn(service.clone().map_err(|_| ())); let addr = - addr.with(multiaddr::Protocol::P2p((service.network().local_peer_id()).into())); + MultiaddrWithPeerId { multiaddr: addr, peer_id: service.network().local_peer_id() }; self.full_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; } @@ -382,7 +385,7 @@ where for (_, service, _, _) in network.full_nodes.iter().skip(1) { service .network() - .add_reserved_peer(first_address.to_string()) + .add_reserved_peer(first_address.clone()) .expect("Error adding reserved peer"); } @@ -414,7 +417,7 @@ where if let Some((_, service, _, node_id)) = network.full_nodes.get(i) { service .network() - .add_reserved_peer(address.to_string()) + .add_reserved_peer(address) .expect("Error adding reserved peer"); address = node_id.clone(); } @@ -479,7 +482,7 @@ pub fn sync( for (_, service, _, _) in network.full_nodes.iter().skip(1) { service .network() - .add_reserved_peer(first_address.to_string()) + .add_reserved_peer(first_address.clone()) .expect("Error adding reserved peer"); } @@ -532,13 +535,13 @@ pub fn consensus( for (_, service, _, _) in network.full_nodes.iter() { service .network() - .add_reserved_peer(first_address.to_string()) + .add_reserved_peer(first_address.clone()) .expect("Error adding reserved peer"); } for (_, service, _, _) in network.authority_nodes.iter().skip(1) { service .network() - .add_reserved_peer(first_address.to_string()) + .add_reserved_peer(first_address.clone()) .expect("Error adding reserved peer"); } network.run_until_all_full(|_index, service| { @@ -556,7 +559,7 @@ pub fn consensus( for (_, service, _, _) in network.full_nodes.iter() { service .network() - .add_reserved_peer(first_address.to_string()) + .add_reserved_peer(first_address.clone()) .expect("Error adding reserved peer"); } From 3db5c9512c6782efa651fa185061806c7dceb6aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 29 Aug 2022 17:11:19 +0200 Subject: [PATCH 1100/1472] Fix flaky trie-db cache test (#12139) --- primitives/trie/src/cache/mod.rs | 44 ++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/primitives/trie/src/cache/mod.rs b/primitives/trie/src/cache/mod.rs index 67348919250cd..f6a447763a80e 100644 --- a/primitives/trie/src/cache/mod.rs +++ b/primitives/trie/src/cache/mod.rs @@ -593,26 +593,35 @@ mod tests { .map(|d| d.0) .all(|l| TEST_DATA.iter().any(|d| l.storage_key().unwrap() == d.0))); - { - let local_cache = shared_cache.local_cache(); + // Run this in a loop. The first time we check that with the filled value cache, + // the expected values are at the top of the LRU. + // The second run is using an empty value cache to ensure that we access the nodes. + for _ in 0..2 { + { + let local_cache = shared_cache.local_cache(); - let mut cache = local_cache.as_trie_db_cache(root); - let trie = TrieDBBuilder::::new(&db, &root).with_cache(&mut cache).build(); + let mut cache = local_cache.as_trie_db_cache(root); + let trie = TrieDBBuilder::::new(&db, &root).with_cache(&mut cache).build(); - for (k, _) in TEST_DATA.iter().take(2) { - trie.get(k).unwrap().unwrap(); + for (k, _) in TEST_DATA.iter().take(2) { + trie.get(k).unwrap().unwrap(); + } } - } - // Ensure that the accessed items are most recently used items of the shared value cache. - assert!(shared_cache - .read_lock_inner() - .value_cache() - .lru - .iter() - .take(2) - .map(|d| d.0) - .all(|l| { TEST_DATA.iter().take(2).any(|d| l.storage_key().unwrap() == d.0) })); + // Ensure that the accessed items are most recently used items of the shared value + // cache. + assert!(shared_cache + .read_lock_inner() + .value_cache() + .lru + .iter() + .take(2) + .map(|d| d.0) + .all(|l| { TEST_DATA.iter().take(2).any(|d| l.storage_key().unwrap() == d.0) })); + + // Delete the value cache, so that we access the nodes. + shared_cache.reset_value_cache(); + } let most_recently_used_nodes = shared_cache .read_lock_inner() @@ -622,9 +631,6 @@ mod tests { .map(|d| *d.0) .collect::>(); - // Delete the value cache, so that we access the nodes. - shared_cache.reset_value_cache(); - { let local_cache = shared_cache.local_cache(); From 4ba739adc0d2b2c81687cfa9faf3a747ffe6193d Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 30 Aug 2022 00:30:37 +0900 Subject: [PATCH 1101/1472] Force `rustix` to use libc (#12123) --- Cargo.lock | 1 + client/executor/wasmtime/Cargo.toml | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 64e84fe4710af..bf06efd65aa53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8249,6 +8249,7 @@ dependencies = [ "parity-scale-codec", "parity-wasm 0.42.2", "paste 1.0.6", + "rustix 0.33.7", "rustix 0.35.6", "sc-allocator", "sc-executor-common", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 2dcfde378bb87..e75f2d9d043d0 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -18,6 +18,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } libc = "0.2.121" log = "0.4.17" parity-wasm = "0.42.0" + +# When bumping wasmtime do not forget to also bump rustix +# to exactly the same version as used by wasmtime! wasmtime = { version = "0.38.0", default-features = false, features = [ "cache", "cranelift", @@ -33,9 +36,16 @@ sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-wasm-interface = { version = "6.0.0", features = ["wasmtime"], path = "../../../primitives/wasm-interface" } [target.'cfg(target_os = "linux")'.dependencies] -rustix = { version = "0.35.6", default-features = false, features = ["std", "mm", "fs", "param"] } +rustix = { version = "0.35.6", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] } once_cell = "1.12.0" +# Here we include the rustix crate used by wasmtime just to enable its 'use-libc' flag. +# +# By default rustix directly calls the appropriate syscalls completely bypassing libc; +# this doesn't have any actual benefits for us besides making it harder to debug memory +# problems (since then `mmap` etc. cannot be easily hooked into). +rustix_wasmtime = { package = "rustix", version = "0.33.7", default-features = false, features = ["std", "use-libc"] } + [dev-dependencies] wat = "1.0" sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } From 5cdb054049980eecb449c36a7ccfe4990329c494 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Mon, 29 Aug 2022 18:02:23 +0200 Subject: [PATCH 1102/1472] Alliance pallet: retirement notice call (#11970) * Alliance pallet: retirement notice * add alliance pallet to benchmark list for dev chain * fix type * ".git/.scripts/bench-bot.sh" pallet dev pallet_alliance * ".git/.scripts/bench-bot.sh" pallet dev pallet_alliance * link weight generated by bench for retirement_notice method * migration to clear UpForKicking storage prefix * rename migration from v1 to v0_to_v1 * Apply suggestions from code review Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * rename `retirement-notice to give-retirement-notice * Apply suggestions from code review Co-authored-by: Squirrel * review fixes: update doc, saturating add, BlockNumber type alias * add suffix to duratin consts *_IN_BLOCKS * ".git/.scripts/bench-bot.sh" pallet dev pallet_alliance * add negative tests (#11995) * add negative tests * remove tests powerless asserts checking against announcment origin * assert bad origin from announcement origin checks Co-authored-by: muharem Co-authored-by: command-bot <> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Squirrel --- bin/node/runtime/src/lib.rs | 16 +- frame/alliance/README.md | 1 + frame/alliance/src/benchmarking.rs | 31 ++- frame/alliance/src/lib.rs | 79 ++++-- frame/alliance/src/migration.rs | 72 +++++ frame/alliance/src/mock.rs | 16 +- frame/alliance/src/tests.rs | 110 ++++++-- frame/alliance/src/weights.rs | 428 +++++++++++++++++------------ 8 files changed, 511 insertions(+), 242 deletions(-) create mode 100644 frame/alliance/src/migration.rs diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0816fedff0347..f8ea312d1a496 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1518,8 +1518,10 @@ impl pallet_state_trie_migration::Config for Runtime { type WeightInfo = (); } +const ALLIANCE_MOTION_DURATION_IN_BLOCKS: BlockNumber = 5 * DAYS; + parameter_types! { - pub const AllianceMotionDuration: BlockNumber = 5 * DAYS; + pub const AllianceMotionDuration: BlockNumber = ALLIANCE_MOTION_DURATION_IN_BLOCKS; pub const AllianceMaxProposals: u32 = 100; pub const AllianceMaxMembers: u32 = 100; } @@ -1541,6 +1543,7 @@ parameter_types! { pub const MaxFellows: u32 = AllianceMaxMembers::get() - MaxFounders::get(); pub const MaxAllies: u32 = 100; pub const AllyDeposit: Balance = 10 * DOLLARS; + pub const RetirementPeriod: BlockNumber = ALLIANCE_MOTION_DURATION_IN_BLOCKS + (1 * DAYS); } impl pallet_alliance::Config for Runtime { @@ -1577,6 +1580,7 @@ impl pallet_alliance::Config for Runtime { type MaxMembersCount = AllianceMaxMembers; type AllyDeposit = AllyDeposit; type WeightInfo = pallet_alliance::weights::SubstrateWeight; + type RetirementPeriod = RetirementPeriod; } construct_runtime!( @@ -1682,9 +1686,16 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - pallet_nomination_pools::migration::v2::MigrateToV2, + Migrations, >; +// All migrations executed on runtime upgrade as a nested tuple of types implementing +// `OnRuntimeUpgrade`. +type Migrations = ( + pallet_nomination_pools::migration::v2::MigrateToV2, + pallet_alliance::migration::Migration, +); + /// MMR helper types. mod mmr { use super::Runtime; @@ -1703,6 +1714,7 @@ extern crate frame_benchmarking; mod benches { define_benchmarks!( [frame_benchmarking, BaselineBench::] + [pallet_alliance, Alliance] [pallet_assets, Assets] [pallet_babe, Babe] [pallet_bags_list, BagsList] diff --git a/frame/alliance/README.md b/frame/alliance/README.md index f0900c84cbd85..f91475a5984ea 100644 --- a/frame/alliance/README.md +++ b/frame/alliance/README.md @@ -43,6 +43,7 @@ to update the Alliance's rule and make announcements. #### For Members (All) +- `give_retirement_notice` - Give a retirement notice and start a retirement period required to pass in order to retire. - `retire` - Retire from the Alliance and release the caller's deposit. #### For Members (Founders/Fellows) diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index c23ded1640b58..25dcb18b175ef 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -691,12 +691,37 @@ benchmarks_instance_pallet! { assert_last_event::(Event::AllyElevated { ally: ally1 }.into()); } + give_retirement_notice { + set_members::(); + let fellow2 = fellow::(2); + + assert!(Alliance::::is_fellow(&fellow2)); + }: _(SystemOrigin::Signed(fellow2.clone())) + verify { + assert!(Alliance::::is_member_of(&fellow2, MemberRole::Retiring)); + + assert_eq!( + RetiringMembers::::get(&fellow2), + Some(System::::block_number() + T::RetirementPeriod::get()) + ); + assert_last_event::( + Event::MemberRetirementPeriodStarted {member: fellow2}.into() + ); + } + retire { set_members::(); let fellow2 = fellow::(2); assert!(Alliance::::is_fellow(&fellow2)); - assert!(!Alliance::::is_up_for_kicking(&fellow2)); + + assert_eq!( + Alliance::::give_retirement_notice( + SystemOrigin::Signed(fellow2.clone()).into() + ), + Ok(()) + ); + System::::set_block_number(System::::block_number() + T::RetirementPeriod::get()); assert_eq!(DepositOf::::get(&fellow2), Some(T::AllyDeposit::get())); }: _(SystemOrigin::Signed(fellow2.clone())) @@ -713,11 +738,7 @@ benchmarks_instance_pallet! { set_members::(); let fellow2 = fellow::(2); - UpForKicking::::insert(&fellow2, true); - assert!(Alliance::::is_member_of(&fellow2, MemberRole::Fellow)); - assert!(Alliance::::is_up_for_kicking(&fellow2)); - assert_eq!(DepositOf::::get(&fellow2), Some(T::AllyDeposit::get())); let fellow2_lookup = T::Lookup::unlookup(fellow2.clone()); diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 0f4d43505e3f9..bc0a119cd54a6 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -60,6 +60,8 @@ //! //! #### For Members (All) //! +//! - `give_retirement_notice` - Give a retirement notice and start a retirement period required to +//! pass in order to retire. //! - `retire` - Retire from the Alliance and release the caller's deposit. //! //! #### For Members (Founders/Fellows) @@ -93,13 +95,14 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; mod types; pub mod weights; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use sp_runtime::{ - traits::{StaticLookup, Zero}, + traits::{Saturating, StaticLookup, Zero}, RuntimeDebug, }; use sp_std::{convert::TryInto, prelude::*}; @@ -124,6 +127,9 @@ pub use pallet::*; pub use types::*; pub use weights::*; +/// The log target of this pallet. +pub const LOG_TARGET: &str = "runtime::alliance"; + /// Simple index type for proposal counting. pub type ProposalIndex = u32; @@ -198,6 +204,7 @@ pub enum MemberRole { Founder, Fellow, Ally, + Retiring, } /// The type of item that may be deemed unscrupulous. @@ -218,6 +225,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] + #[pallet::storage_version(migration::STORAGE_VERSION)] pub struct Pallet(PhantomData<(T, I)>); #[pallet::config] @@ -308,6 +316,10 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// The number of blocks a member must wait between giving a retirement notice and retiring. + /// Supposed to be greater than time required to `kick_member`. + type RetirementPeriod: Get; } #[pallet::error] @@ -324,8 +336,6 @@ pub mod pallet { NotAlly, /// Account is not a founder. NotFounder, - /// This member is up for being kicked from the Alliance and cannot perform this operation. - UpForKicking, /// Account does not have voting rights. NoVotingRights, /// Account is already an elevated (fellow) member. @@ -357,6 +367,12 @@ pub mod pallet { TooManyMembers, /// Number of announcements exceeds `MaxAnnouncementsCount`. TooManyAnnouncements, + /// Account already gave retirement notice + AlreadyRetiring, + /// Account did not give a retirement notice required to retire. + RetirementNoticeNotGiven, + /// Retirement period has not passed. + RetirementPeriodNotPassed, } #[pallet::event] @@ -382,6 +398,8 @@ pub mod pallet { }, /// An ally has been elevated to Fellow. AllyElevated { ally: T::AccountId }, + /// A member gave retirement notice and their retirement period started. + MemberRetirementPeriodStarted { member: T::AccountId }, /// A member has retired with its deposit unreserved. MemberRetired { member: T::AccountId, unreserved: Option> }, /// A member has been kicked out with its deposit slashed. @@ -485,12 +503,12 @@ pub mod pallet { ValueQuery, >; - /// A set of members that are (potentially) being kicked out. They cannot retire until the - /// motion is settled. + /// A set of members who gave a retirement notice. They can retire after the end of retirement + /// period stored as a future block number. #[pallet::storage] - #[pallet::getter(fn up_for_kicking)] - pub type UpForKicking, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, T::AccountId, bool, ValueQuery>; + #[pallet::getter(fn retiring_members)] + pub type RetiringMembers, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, T::AccountId, T::BlockNumber, OptionQuery>; /// The current list of accounts deemed unscrupulous. These accounts non grata cannot submit /// candidacy. @@ -525,11 +543,6 @@ pub mod pallet { let proposor = ensure_signed(origin)?; ensure!(Self::has_voting_rights(&proposor), Error::::NoVotingRights); - if let Some(Call::kick_member { who }) = proposal.is_sub_type() { - let strike = T::Lookup::lookup(who.clone())?; - >::insert(strike, true); - } - T::ProposalProvider::propose_proposal(proposor, threshold, proposal, length_bound)?; Ok(()) } @@ -783,15 +796,40 @@ pub mod pallet { Ok(()) } + /// As a member, give a retirement notice and start a retirement period required to pass in + /// order to retire. + #[pallet::weight(T::WeightInfo::give_retirement_notice())] + pub fn give_retirement_notice(origin: OriginFor) -> DispatchResult { + let who = ensure_signed(origin)?; + let role = Self::member_role_of(&who).ok_or(Error::::NotMember)?; + ensure!(role.ne(&MemberRole::Retiring), Error::::AlreadyRetiring); + + Self::remove_member(&who, role)?; + Self::add_member(&who, MemberRole::Retiring)?; + >::insert( + &who, + frame_system::Pallet::::block_number() + .saturating_add(T::RetirementPeriod::get()), + ); + + Self::deposit_event(Event::MemberRetirementPeriodStarted { member: who }); + Ok(()) + } + /// As a member, retire from the alliance and unreserve the deposit. + /// This can only be done once you have `give_retirement_notice` and it has expired. #[pallet::weight(T::WeightInfo::retire())] pub fn retire(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; - // A member up for kicking cannot retire. - ensure!(!Self::is_up_for_kicking(&who), Error::::UpForKicking); + let retirement_period_end = RetiringMembers::::get(&who) + .ok_or(Error::::RetirementNoticeNotGiven)?; + ensure!( + frame_system::Pallet::::block_number() >= retirement_period_end, + Error::::RetirementPeriodNotPassed + ); - let role = Self::member_role_of(&who).ok_or(Error::::NotMember)?; - Self::remove_member(&who, role)?; + Self::remove_member(&who, MemberRole::Retiring)?; + >::remove(&who); let deposit = DepositOf::::take(&who); if let Some(deposit) = deposit { let err_amount = T::Currency::unreserve(&who, deposit); @@ -814,8 +852,6 @@ pub mod pallet { T::Slashed::on_unbalanced(T::Currency::slash_reserved(&member, deposit).0); } - >::remove(&member); - Self::deposit_event(Event::MemberKicked { member, slashed: deposit }); Ok(()) } @@ -930,11 +966,6 @@ impl, I: 'static> Pallet { founders.into() } - /// Check if an account's forced removal is up for consideration. - fn is_up_for_kicking(who: &T::AccountId) -> bool { - >::contains_key(&who) - } - /// Add a user to the sorted alliance member set. fn add_member(who: &T::AccountId, role: MemberRole) -> DispatchResult { >::try_mutate(role, |members| -> DispatchResult { diff --git a/frame/alliance/src/migration.rs b/frame/alliance/src/migration.rs new file mode 100644 index 0000000000000..cd54eed7a9a75 --- /dev/null +++ b/frame/alliance/src/migration.rs @@ -0,0 +1,72 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{Config, Pallet, Weight, LOG_TARGET}; +use frame_support::{pallet_prelude::*, storage::migration, traits::OnRuntimeUpgrade}; +use log; + +/// The current storage version. +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + +/// Wrapper for all migrations of this pallet. +pub fn migrate, I: 'static>() -> Weight { + let onchain_version = Pallet::::on_chain_storage_version(); + let mut weight: Weight = 0; + + if onchain_version < 1 { + weight = weight.saturating_add(v0_to_v1::migrate::()); + } + + STORAGE_VERSION.put::>(); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + + weight +} + +/// Implements `OnRuntimeUpgrade` trait. +pub struct Migration(PhantomData<(T, I)>); + +impl, I: 'static> OnRuntimeUpgrade for Migration { + fn on_runtime_upgrade() -> Weight { + migrate::() + } +} + +/// v0_to_v1: `UpForKicking` is replaced by a retirement period. +mod v0_to_v1 { + use super::*; + + pub fn migrate, I: 'static>() -> Weight { + if migration::clear_storage_prefix( + >::name().as_bytes(), + b"UpForKicking", + b"", + None, + None, + ) + .maybe_cursor + .is_some() + { + log::error!( + target: LOG_TARGET, + "Storage prefix 'UpForKicking' is not completely cleared." + ); + } + + T::DbWeight::get().writes(1) + } +} diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index 91986300aa2e1..adc313e28ed7e 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -37,8 +37,10 @@ pub use crate as pallet_alliance; use super::*; +type BlockNumber = u64; + parameter_types! { - pub const BlockHashCount: u64 = 250; + pub const BlockHashCount: BlockNumber = 250; } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; @@ -47,7 +49,7 @@ impl frame_system::Config for Test { type Origin = Origin; type Call = Call; type Index = u64; - type BlockNumber = u64; + type BlockNumber = BlockNumber; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; @@ -83,8 +85,10 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; } +const MOTION_DURATION_IN_BLOCKS: BlockNumber = 3; + parameter_types! { - pub const MotionDuration: u64 = 3; + pub const MotionDuration: BlockNumber = MOTION_DURATION_IN_BLOCKS; pub const MaxProposals: u32 = 100; pub const MaxMembers: u32 = 100; } @@ -199,6 +203,7 @@ parameter_types! { pub const MaxFellows: u32 = MaxMembers::get() - MaxFounders::get(); pub const MaxAllies: u32 = 100; pub const AllyDeposit: u64 = 25; + pub const RetirementPeriod: BlockNumber = MOTION_DURATION_IN_BLOCKS + 1; } impl Config for Test { type Event = Event; @@ -225,6 +230,7 @@ impl Config for Test { type MaxMembersCount = MaxMembers; type AllyDeposit = AllyDeposit; type WeightInfo = (); + type RetirementPeriod = RetirementPeriod; } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -324,7 +330,3 @@ pub fn make_proposal(value: u64) -> Call { pub fn make_set_rule_proposal(rule: Cid) -> Call { Call::Alliance(pallet_alliance::Call::set_rule { rule }) } - -pub fn make_kick_member_proposal(who: u64) -> Call { - Call::Alliance(pallet_alliance::Call::kick_member { who }) -} diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index 14265cad5aa76..918cfa840c3f0 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -19,7 +19,7 @@ use sp_runtime::traits::Hash; -use frame_support::{assert_noop, assert_ok, Hashable}; +use frame_support::{assert_noop, assert_ok, error::BadOrigin, Hashable}; use frame_system::{EventRecord, Phase}; use super::*; @@ -241,6 +241,9 @@ fn set_rule_works() { fn announce_works() { new_test_ext().execute_with(|| { let cid = test_cid(); + + assert_noop!(Alliance::announce(Origin::signed(2), cid.clone()), BadOrigin); + assert_ok!(Alliance::announce(Origin::signed(3), cid.clone())); assert_eq!(Alliance::announcements(), vec![cid.clone()]); @@ -390,48 +393,111 @@ fn elevate_ally_works() { } #[test] -fn retire_works() { +fn give_retirement_notice_work() { new_test_ext().execute_with(|| { - let proposal = make_kick_member_proposal(2); - let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - assert_ok!(Alliance::propose( - Origin::signed(1), - 3, - Box::new(proposal.clone()), - proposal_len + assert_noop!( + Alliance::give_retirement_notice(Origin::signed(4)), + Error::::NotMember + ); + + assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); + assert_ok!(Alliance::give_retirement_notice(Origin::signed(3))); + assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); + assert_eq!(Alliance::members(MemberRole::Retiring), vec![3]); + System::assert_last_event(mock::Event::Alliance( + crate::Event::MemberRetirementPeriodStarted { member: (3) }, )); - assert_noop!(Alliance::retire(Origin::signed(2)), Error::::UpForKicking); - assert_noop!(Alliance::retire(Origin::signed(4)), Error::::NotMember); + assert_noop!( + Alliance::give_retirement_notice(Origin::signed(3)), + Error::::AlreadyRetiring + ); + }); +} + +#[test] +fn retire_works() { + new_test_ext().execute_with(|| { + assert_noop!( + Alliance::retire(Origin::signed(2)), + Error::::RetirementNoticeNotGiven + ); + + assert_noop!( + Alliance::retire(Origin::signed(4)), + Error::::RetirementNoticeNotGiven + ); assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); + assert_ok!(Alliance::give_retirement_notice(Origin::signed(3))); + assert_noop!( + Alliance::retire(Origin::signed(3)), + Error::::RetirementPeriodNotPassed + ); + System::set_block_number(System::block_number() + RetirementPeriod::get()); assert_ok!(Alliance::retire(Origin::signed(3))); assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); + System::assert_last_event(mock::Event::Alliance(crate::Event::MemberRetired { + member: (3), + unreserved: None, + })); + + // Move time on: + System::set_block_number(System::block_number() + RetirementPeriod::get()); + + assert_powerless(Origin::signed(3)); }); } +fn assert_powerless(user: Origin) { + //vote / veto with a valid propsal + let cid = test_cid(); + let proposal = make_proposal(42); + + assert_noop!(Alliance::init_members(user.clone(), vec![], vec![], vec![]), BadOrigin); + + assert_noop!(Alliance::set_rule(user.clone(), cid.clone()), BadOrigin); + + assert_noop!(Alliance::retire(user.clone()), Error::::RetirementNoticeNotGiven); + + assert_noop!(Alliance::give_retirement_notice(user.clone()), Error::::NotMember); + + assert_noop!(Alliance::elevate_ally(user.clone(), 4), BadOrigin); + + assert_noop!(Alliance::kick_member(user.clone(), 1), BadOrigin); + + assert_noop!(Alliance::nominate_ally(user.clone(), 4), Error::::NoVotingRights); + + assert_noop!( + Alliance::propose(user.clone(), 5, Box::new(proposal), 1000), + Error::::NoVotingRights + ); +} + #[test] fn kick_member_works() { new_test_ext().execute_with(|| { - let proposal = make_kick_member_proposal(2); - let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - assert_ok!(Alliance::propose( - Origin::signed(1), - 3, - Box::new(proposal.clone()), - proposal_len - )); - assert_eq!(Alliance::up_for_kicking(2), true); - assert_eq!(Alliance::members(MemberRole::Founder), vec![1, 2]); + assert_noop!(Alliance::kick_member(Origin::signed(4), 4), BadOrigin); + + assert_noop!(Alliance::kick_member(Origin::signed(2), 4), Error::::NotMember); + >::insert(2, 25); + assert_eq!(Alliance::members(MemberRole::Founder), vec![1, 2]); assert_ok!(Alliance::kick_member(Origin::signed(2), 2)); assert_eq!(Alliance::members(MemberRole::Founder), vec![1]); + assert_eq!(>::get(2), None); + System::assert_last_event(mock::Event::Alliance(crate::Event::MemberKicked { + member: (2), + slashed: Some(25), + })); }); } #[test] fn add_unscrupulous_items_works() { new_test_ext().execute_with(|| { + assert_noop!(Alliance::add_unscrupulous_items(Origin::signed(2), vec![]), BadOrigin); + assert_ok!(Alliance::add_unscrupulous_items( Origin::signed(3), vec![ @@ -455,6 +521,8 @@ fn add_unscrupulous_items_works() { #[test] fn remove_unscrupulous_items_works() { new_test_ext().execute_with(|| { + assert_noop!(Alliance::remove_unscrupulous_items(Origin::signed(2), vec![]), BadOrigin); + assert_noop!( Alliance::remove_unscrupulous_items( Origin::signed(3), diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 495dd1b83df93..aa9ebde528683 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,24 +18,25 @@ //! Autogenerated weights for pallet_alliance //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-10-11, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-08-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/release/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark -// --chain=dev +// pallet // --steps=50 // --repeat=20 -// --pallet=pallet_alliance // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 +// --pallet=pallet_alliance +// --chain=dev // --output=./frame/alliance/src/weights.rs // --template=./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -59,6 +60,7 @@ pub trait WeightInfo { fn join_alliance() -> Weight; fn nominate_ally() -> Weight; fn elevate_ally() -> Weight; + fn give_retirement_notice() -> Weight; fn retire() -> Weight; fn kick_member() -> Weight; fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight; @@ -73,23 +75,33 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: AllianceMotion ProposalCount (r:1 w:1) // Storage: AllianceMotion Voting (r:0 w:1) - fn propose_proposed(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - (39_992_000 as Weight) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[0, 90]`. + /// The range of component `p` is `[1, 100]`. + fn propose_proposed(b: u32, x: u32, y: u32, p: u32, ) -> Weight { + (22_575_000 as Weight) + // Standard Error: 0 + .saturating_add((11_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 23_000 + .saturating_add((158_000 as Weight).saturating_mul(x as Weight)) // Standard Error: 2_000 - .saturating_add((44_000 as Weight).saturating_mul(y as Weight)) + .saturating_add((90_000 as Weight).saturating_mul(y as Weight)) // Standard Error: 2_000 - .saturating_add((323_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((216_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Alliance Members (r:2 w:0) // Storage: AllianceMotion Voting (r:1 w:1) + /// The range of component `x` is `[3, 10]`. + /// The range of component `y` is `[2, 90]`. fn vote(x: u32, y: u32, ) -> Weight { - (36_649_000 as Weight) - // Standard Error: 90_000 - .saturating_add((42_000 as Weight).saturating_mul(x as Weight)) - // Standard Error: 3_000 - .saturating_add((195_000 as Weight).saturating_mul(y as Weight)) + (45_486_000 as Weight) + // Standard Error: 29_000 + .saturating_add((78_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 2_000 + .saturating_add((128_000 as Weight).saturating_mul(y as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -97,125 +109,135 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: AllianceMotion Voting (r:0 w:1) + /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - (30_301_000 as Weight) - // Standard Error: 1_000 - .saturating_add((330_000 as Weight).saturating_mul(p as Weight)) + (35_296_000 as Weight) + // Standard Error: 2_000 + .saturating_add((171_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Alliance Members (r:1 w:0) - // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Voting (r:1 w:1) // Storage: AllianceMotion Members (r:1 w:0) // Storage: AllianceMotion Proposals (r:1 w:1) + // Storage: AllianceMotion ProposalOf (r:0 w:1) + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[2, 90]`. + /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - (40_472_000 as Weight) - // Standard Error: 69_000 - .saturating_add((485_000 as Weight).saturating_mul(x as Weight)) - // Standard Error: 2_000 - .saturating_add((192_000 as Weight).saturating_mul(y as Weight)) - // Standard Error: 2_000 - .saturating_add((330_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) + (39_252_000 as Weight) + // Standard Error: 18_000 + .saturating_add((75_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 1_000 + .saturating_add((107_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 1_000 + .saturating_add((170_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Alliance Members (r:1 w:0) - // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Voting (r:1 w:1) // Storage: AllianceMotion Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Proposals (r:1 w:1) - fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - (52_076_000 as Weight) - // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(b as Weight)) - // Standard Error: 77_000 - .saturating_add((194_000 as Weight).saturating_mul(x as Weight)) - // Standard Error: 3_000 - .saturating_add((188_000 as Weight).saturating_mul(y as Weight)) - // Standard Error: 2_000 - .saturating_add((329_000 as Weight).saturating_mul(p as Weight)) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[2, 90]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + (50_357_000 as Weight) + // Standard Error: 1_000 + .saturating_add((103_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 1_000 + .saturating_add((204_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Alliance Members (r:1 w:0) - // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Voting (r:1 w:1) // Storage: AllianceMotion Members (r:1 w:0) // Storage: AllianceMotion Prime (r:1 w:0) // Storage: AllianceMotion Proposals (r:1 w:1) - fn close_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - (47_009_000 as Weight) - // Standard Error: 66_000 - .saturating_add((256_000 as Weight).saturating_mul(x as Weight)) - // Standard Error: 2_000 - .saturating_add((176_000 as Weight).saturating_mul(y as Weight)) - // Standard Error: 2_000 - .saturating_add((327_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) + // Storage: AllianceMotion ProposalOf (r:0 w:1) + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[2, 90]`. + /// The range of component `p` is `[1, 100]`. + fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { + (41_258_000 as Weight) + // Standard Error: 1_000 + .saturating_add((111_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 1_000 + .saturating_add((186_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } // Storage: Alliance Members (r:1 w:0) - // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Voting (r:1 w:1) // Storage: AllianceMotion Members (r:1 w:0) // Storage: AllianceMotion Prime (r:1 w:0) // Storage: AllianceMotion Proposals (r:1 w:1) - fn close_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - (43_650_000 as Weight) - // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) - // Standard Error: 85_000 - .saturating_add((124_000 as Weight).saturating_mul(x as Weight)) - // Standard Error: 3_000 - .saturating_add((199_000 as Weight).saturating_mul(y as Weight)) - // Standard Error: 3_000 - .saturating_add((326_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) + // Storage: AllianceMotion ProposalOf (r:0 w:1) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[2, 90]`. + /// The range of component `p` is `[1, 100]`. + fn close_approved(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { + (40_490_000 as Weight) + // Standard Error: 16_000 + .saturating_add((119_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 1_000 + .saturating_add((93_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 1_000 + .saturating_add((195_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Alliance Members (r:3 w:3) + // Storage: Alliance Members (r:2 w:3) // Storage: AllianceMotion Members (r:1 w:1) + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[0, 90]`. + /// The range of component `z` is `[0, 100]`. fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { - (45_100_000 as Weight) - // Standard Error: 4_000 - .saturating_add((162_000 as Weight).saturating_mul(y as Weight)) - // Standard Error: 4_000 - .saturating_add((151_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + (35_186_000 as Weight) + // Standard Error: 1_000 + .saturating_add((161_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 1_000 + .saturating_add((127_000 as Weight).saturating_mul(z as Weight)) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - (14_517_000 as Weight) + (18_189_000 as Weight) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - (16_801_000 as Weight) + (21_106_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - (17_133_000 as Weight) + (22_208_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) - // Storage: Alliance Members (r:4 w:0) // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - (95_370_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) + (53_771_000 as Weight) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - // Storage: Alliance Members (r:4 w:0) + // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - (44_764_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) + (41_912_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Alliance Members (r:3 w:2) @@ -223,23 +245,29 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - (44_013_000 as Weight) + (36_811_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } - // Storage: Alliance KickingMembers (r:1 w:0) - // Storage: Alliance Members (r:3 w:1) + // Storage: Alliance Members (r:4 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) - // Storage: Alliance DepositOf (r:1 w:1) - // Storage: System Account (r:1 w:1) // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) - fn retire() -> Weight { - (60_183_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) + // Storage: Alliance RetiringMembers (r:0 w:1) + fn give_retirement_notice() -> Weight { + (41_079_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } - // Storage: Alliance KickingMembers (r:1 w:0) + // Storage: Alliance RetiringMembers (r:1 w:1) + // Storage: Alliance Members (r:1 w:1) + // Storage: Alliance DepositOf (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn retire() -> Weight { + (42_703_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } // Storage: Alliance Members (r:3 w:1) // Storage: AllianceMotion Proposals (r:1 w:0) // Storage: Alliance DepositOf (r:1 w:1) @@ -247,29 +275,33 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - (67_467_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) + (61_370_000 as Weight) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// The range of component `n` is `[1, 100]`. + /// The range of component `l` is `[1, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((2_673_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 7_000 - .saturating_add((224_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((1_385_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 1_000 + .saturating_add((119_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// The range of component `n` is `[1, 100]`. + /// The range of component `l` is `[1, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { (0 as Weight) - // Standard Error: 343_000 - .saturating_add((59_025_000 as Weight).saturating_mul(n as Weight)) // Standard Error: 153_000 - .saturating_add((6_725_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((21_484_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 59_000 + .saturating_add((3_772_000 as Weight).saturating_mul(l as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -282,23 +314,33 @@ impl WeightInfo for () { // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: AllianceMotion ProposalCount (r:1 w:1) // Storage: AllianceMotion Voting (r:0 w:1) - fn propose_proposed(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - (39_992_000 as Weight) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[0, 90]`. + /// The range of component `p` is `[1, 100]`. + fn propose_proposed(b: u32, x: u32, y: u32, p: u32, ) -> Weight { + (22_575_000 as Weight) + // Standard Error: 0 + .saturating_add((11_000 as Weight).saturating_mul(b as Weight)) + // Standard Error: 23_000 + .saturating_add((158_000 as Weight).saturating_mul(x as Weight)) // Standard Error: 2_000 - .saturating_add((44_000 as Weight).saturating_mul(y as Weight)) + .saturating_add((90_000 as Weight).saturating_mul(y as Weight)) // Standard Error: 2_000 - .saturating_add((323_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((216_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Alliance Members (r:2 w:0) // Storage: AllianceMotion Voting (r:1 w:1) + /// The range of component `x` is `[3, 10]`. + /// The range of component `y` is `[2, 90]`. fn vote(x: u32, y: u32, ) -> Weight { - (36_649_000 as Weight) - // Standard Error: 90_000 - .saturating_add((42_000 as Weight).saturating_mul(x as Weight)) - // Standard Error: 3_000 - .saturating_add((195_000 as Weight).saturating_mul(y as Weight)) + (45_486_000 as Weight) + // Standard Error: 29_000 + .saturating_add((78_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 2_000 + .saturating_add((128_000 as Weight).saturating_mul(y as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -306,125 +348,135 @@ impl WeightInfo for () { // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: AllianceMotion Voting (r:0 w:1) + /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - (30_301_000 as Weight) - // Standard Error: 1_000 - .saturating_add((330_000 as Weight).saturating_mul(p as Weight)) + (35_296_000 as Weight) + // Standard Error: 2_000 + .saturating_add((171_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Alliance Members (r:1 w:0) - // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Voting (r:1 w:1) // Storage: AllianceMotion Members (r:1 w:0) // Storage: AllianceMotion Proposals (r:1 w:1) + // Storage: AllianceMotion ProposalOf (r:0 w:1) + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[2, 90]`. + /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - (40_472_000 as Weight) - // Standard Error: 69_000 - .saturating_add((485_000 as Weight).saturating_mul(x as Weight)) - // Standard Error: 2_000 - .saturating_add((192_000 as Weight).saturating_mul(y as Weight)) - // Standard Error: 2_000 - .saturating_add((330_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + (39_252_000 as Weight) + // Standard Error: 18_000 + .saturating_add((75_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 1_000 + .saturating_add((107_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 1_000 + .saturating_add((170_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Alliance Members (r:1 w:0) - // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Voting (r:1 w:1) // Storage: AllianceMotion Members (r:1 w:0) + // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Proposals (r:1 w:1) - fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - (52_076_000 as Weight) - // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(b as Weight)) - // Standard Error: 77_000 - .saturating_add((194_000 as Weight).saturating_mul(x as Weight)) - // Standard Error: 3_000 - .saturating_add((188_000 as Weight).saturating_mul(y as Weight)) - // Standard Error: 2_000 - .saturating_add((329_000 as Weight).saturating_mul(p as Weight)) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[2, 90]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + (50_357_000 as Weight) + // Standard Error: 1_000 + .saturating_add((103_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 1_000 + .saturating_add((204_000 as Weight).saturating_mul(p as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Alliance Members (r:1 w:0) - // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Voting (r:1 w:1) // Storage: AllianceMotion Members (r:1 w:0) // Storage: AllianceMotion Prime (r:1 w:0) // Storage: AllianceMotion Proposals (r:1 w:1) - fn close_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - (47_009_000 as Weight) - // Standard Error: 66_000 - .saturating_add((256_000 as Weight).saturating_mul(x as Weight)) - // Standard Error: 2_000 - .saturating_add((176_000 as Weight).saturating_mul(y as Weight)) - // Standard Error: 2_000 - .saturating_add((327_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + // Storage: AllianceMotion ProposalOf (r:0 w:1) + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[2, 90]`. + /// The range of component `p` is `[1, 100]`. + fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { + (41_258_000 as Weight) + // Standard Error: 1_000 + .saturating_add((111_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 1_000 + .saturating_add((186_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } // Storage: Alliance Members (r:1 w:0) - // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Voting (r:1 w:1) // Storage: AllianceMotion Members (r:1 w:0) // Storage: AllianceMotion Prime (r:1 w:0) // Storage: AllianceMotion Proposals (r:1 w:1) - fn close_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - (43_650_000 as Weight) - // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(b as Weight)) - // Standard Error: 85_000 - .saturating_add((124_000 as Weight).saturating_mul(x as Weight)) - // Standard Error: 3_000 - .saturating_add((199_000 as Weight).saturating_mul(y as Weight)) - // Standard Error: 3_000 - .saturating_add((326_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + // Storage: AllianceMotion ProposalOf (r:0 w:1) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[2, 90]`. + /// The range of component `p` is `[1, 100]`. + fn close_approved(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { + (40_490_000 as Weight) + // Standard Error: 16_000 + .saturating_add((119_000 as Weight).saturating_mul(x as Weight)) + // Standard Error: 1_000 + .saturating_add((93_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 1_000 + .saturating_add((195_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Alliance Members (r:3 w:3) + // Storage: Alliance Members (r:2 w:3) // Storage: AllianceMotion Members (r:1 w:1) + /// The range of component `x` is `[2, 10]`. + /// The range of component `y` is `[0, 90]`. + /// The range of component `z` is `[0, 100]`. fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { - (45_100_000 as Weight) - // Standard Error: 4_000 - .saturating_add((162_000 as Weight).saturating_mul(y as Weight)) - // Standard Error: 4_000 - .saturating_add((151_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + (35_186_000 as Weight) + // Standard Error: 1_000 + .saturating_add((161_000 as Weight).saturating_mul(y as Weight)) + // Standard Error: 1_000 + .saturating_add((127_000 as Weight).saturating_mul(z as Weight)) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - (14_517_000 as Weight) + (18_189_000 as Weight) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - (16_801_000 as Weight) + (21_106_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - (17_133_000 as Weight) + (22_208_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) - // Storage: Alliance Members (r:4 w:0) // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - (95_370_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + (53_771_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } - // Storage: Alliance Members (r:4 w:0) + // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - (44_764_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + (41_912_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Alliance Members (r:3 w:2) @@ -432,23 +484,29 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - (44_013_000 as Weight) + (36_811_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } - // Storage: Alliance KickingMembers (r:1 w:0) - // Storage: Alliance Members (r:3 w:1) + // Storage: Alliance Members (r:4 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) - // Storage: Alliance DepositOf (r:1 w:1) - // Storage: System Account (r:1 w:1) // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) - fn retire() -> Weight { - (60_183_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + // Storage: Alliance RetiringMembers (r:0 w:1) + fn give_retirement_notice() -> Weight { + (41_079_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } - // Storage: Alliance KickingMembers (r:1 w:0) + // Storage: Alliance RetiringMembers (r:1 w:1) + // Storage: Alliance Members (r:1 w:1) + // Storage: Alliance DepositOf (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn retire() -> Weight { + (42_703_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } // Storage: Alliance Members (r:3 w:1) // Storage: AllianceMotion Proposals (r:1 w:0) // Storage: Alliance DepositOf (r:1 w:1) @@ -456,29 +514,33 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - (67_467_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + (61_370_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// The range of component `n` is `[1, 100]`. + /// The range of component `l` is `[1, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((2_673_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 7_000 - .saturating_add((224_000 as Weight).saturating_mul(l as Weight)) + // Standard Error: 2_000 + .saturating_add((1_385_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 1_000 + .saturating_add((119_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// The range of component `n` is `[1, 100]`. + /// The range of component `l` is `[1, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { (0 as Weight) - // Standard Error: 343_000 - .saturating_add((59_025_000 as Weight).saturating_mul(n as Weight)) // Standard Error: 153_000 - .saturating_add((6_725_000 as Weight).saturating_mul(l as Weight)) + .saturating_add((21_484_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 59_000 + .saturating_add((3_772_000 as Weight).saturating_mul(l as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } From ca1f81cd0864ae0614aaff07fa121d2d42110586 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 30 Aug 2022 11:12:19 +0200 Subject: [PATCH 1103/1472] Fix sporadic test failure (#12140) Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 12 ++++++++++ frame/benchmarking/Cargo.toml | 1 + frame/benchmarking/src/tests.rs | 42 +++++++++++++++++++-------------- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf06efd65aa53..d90de9da4f579 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2107,6 +2107,7 @@ dependencies = [ "log", "parity-scale-codec", "paste 1.0.6", + "rusty-fork", "scale-info", "serde", "sp-api", @@ -7672,6 +7673,17 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error 1.2.3", + "tempfile", +] + [[package]] name = "rw-stream-sink" version = "0.3.0" diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index d3a2704724f12..c098eee528233 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -32,6 +32,7 @@ sp-storage = { version = "6.0.0", default-features = false, path = "../../primit [dev-dependencies] hex-literal = "0.3.4" +rusty-fork = { version = "0.3.0", default-features = false } sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } [features] diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index be5c23fff17f6..b8a888767bf2c 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -139,6 +139,7 @@ mod benchmarks { use crate::{account, BenchmarkError, BenchmarkParameter, BenchmarkResult, BenchmarkingSetup}; use frame_support::{assert_err, assert_ok, ensure, traits::Get}; use frame_system::RawOrigin; + use rusty_fork::rusty_fork_test; use sp_std::prelude::*; // Additional used internally by the benchmark macro. @@ -409,24 +410,29 @@ mod benchmarks { }); } - /// Test that the benchmarking uses the correct values for each component and - /// that the number of components can be controlled with `VALUES_PER_COMPONENT`. - #[test] - fn test_values_per_component() { - let tests = vec![ - (Some("1"), Err("`VALUES_PER_COMPONENT` must be at least 2".into())), - (Some("asdf"), Err("Could not parse env var `VALUES_PER_COMPONENT` as u32.".into())), - (None, Ok(vec![0, 2, 4, 6, 8, 10])), - (Some("2"), Ok(vec![0, 10])), - (Some("4"), Ok(vec![0, 3, 6, 10])), - (Some("6"), Ok(vec![0, 2, 4, 6, 8, 10])), - (Some("10"), Ok(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 10])), - (Some("11"), Ok(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), - (Some("99"), Ok(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), - ]; - - for (num, expected) in tests { - run_test_values_per_component(num, expected); + rusty_fork_test! { + /// Test that the benchmarking uses the correct values for each component and + /// that the number of components can be controlled with `VALUES_PER_COMPONENT`. + /// + /// NOTE: This test needs to run in its own process, since it + /// otherwise messes up the env variable for the other tests. + #[test] + fn test_values_per_component() { + let tests = vec![ + (Some("1"), Err("`VALUES_PER_COMPONENT` must be at least 2".into())), + (Some("asdf"), Err("Could not parse env var `VALUES_PER_COMPONENT` as u32.".into())), + (None, Ok(vec![0, 2, 4, 6, 8, 10])), + (Some("2"), Ok(vec![0, 10])), + (Some("4"), Ok(vec![0, 3, 6, 10])), + (Some("6"), Ok(vec![0, 2, 4, 6, 8, 10])), + (Some("10"), Ok(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 10])), + (Some("11"), Ok(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), + (Some("99"), Ok(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), + ]; + + for (num, expected) in tests { + run_test_values_per_component(num, expected); + } } } From 0246883c404d498090f33e795feb8075fa8d3b6b Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 31 Aug 2022 12:26:13 +0100 Subject: [PATCH 1104/1472] Weight v1.5: Opaque Struct (#12138) * initial idea * update frame_support * update a bunch more * add ord * adjust RuntimeDbWeight * frame_system builds * re-export * frame_support tests pass * frame_executive compile * frame_executive builds * frame_system tests passing * pallet-utility tests pass * fix a bunch of pallets * more * phragmen * state-trie-migration * scheduler and referenda * pallet-election-provider-multi-phase * aura * staking * more * babe * balances * bunch more * sudo * transaction-payment * asset-tx-payment * last pallets * fix alliance merge * fix node template runtime * fix pallet-contracts cc @athei * fix node runtime * fix compile on runtime-benchmarks feature * comment * fix frame-support-test * fix more tests * weight regex * frame system works * fix a bunch * more * more * more * more * more * more fixes * update templates * fix contracts benchmarks * Update lib.rs * Update lib.rs * fix ui * make scalar saturating mul const * more const functions * scalar div * refactor using constant functions * move impl * fix overhead template * use compactas * Update lib.rs --- .maintain/frame-weight-template.hbs | 26 +- bin/node-template/pallets/template/src/lib.rs | 4 +- bin/node/executor/tests/basic.rs | 6 +- bin/node/executor/tests/fees.rs | 2 +- bin/node/runtime/src/impls.rs | 39 +- bin/node/runtime/src/lib.rs | 6 +- frame/alliance/src/benchmarking.rs | 8 +- frame/alliance/src/migration.rs | 2 +- frame/alliance/src/weights.rs | 318 ++-- frame/assets/src/weights.rs | 326 ++-- frame/atomic-swap/src/lib.rs | 9 +- frame/atomic-swap/src/tests.rs | 2 +- frame/aura/src/mock.rs | 2 +- frame/authority-discovery/src/lib.rs | 2 +- frame/authorship/src/lib.rs | 4 +- frame/babe/src/default_weights.rs | 8 +- frame/babe/src/lib.rs | 4 +- frame/babe/src/mock.rs | 2 +- frame/babe/src/tests.rs | 2 +- frame/bags-list/src/migrations.rs | 1 - frame/bags-list/src/weights.rs | 38 +- frame/balances/src/tests.rs | 8 +- frame/balances/src/tests_composite.rs | 2 +- frame/balances/src/tests_local.rs | 2 +- frame/balances/src/tests_reentrancy.rs | 2 +- frame/balances/src/weights.rs | 86 +- frame/benchmarking/src/utils.rs | 2 +- frame/benchmarking/src/weights.rs | 54 +- frame/bounties/src/migrations/v4.rs | 4 +- frame/bounties/src/weights.rs | 146 +- frame/child-bounties/src/tests.rs | 2 +- frame/child-bounties/src/weights.rs | 102 +- frame/collective/src/benchmarking.rs | 8 +- frame/collective/src/migrations/v4.rs | 4 +- frame/collective/src/tests.rs | 24 +- frame/collective/src/weights.rs | 210 +-- frame/contracts/rpc/src/lib.rs | 4 +- frame/contracts/src/benchmarking/mod.rs | 4 +- frame/contracts/src/chain_extension.rs | 7 +- frame/contracts/src/exec.rs | 46 +- frame/contracts/src/gas.rs | 24 +- frame/contracts/src/lib.rs | 12 +- frame/contracts/src/migration.rs | 6 +- frame/contracts/src/schedule.rs | 116 +- frame/contracts/src/storage.rs | 20 +- frame/contracts/src/tests.rs | 34 +- frame/contracts/src/wasm/code_cache.rs | 8 +- frame/contracts/src/wasm/mod.rs | 8 +- frame/contracts/src/wasm/runtime.rs | 8 +- frame/contracts/src/weights.rs | 1534 ++++++++--------- frame/conviction-voting/src/tests.rs | 3 +- frame/conviction-voting/src/weights.rs | 110 +- frame/democracy/src/lib.rs | 2 +- frame/democracy/src/tests.rs | 2 +- frame/democracy/src/weights.rs | 398 ++--- .../election-provider-multi-phase/src/lib.rs | 7 +- .../election-provider-multi-phase/src/mock.rs | 8 +- .../src/signed.rs | 12 +- .../src/unsigned.rs | 191 +- .../src/weights.rs | 158 +- .../election-provider-support/src/weights.rs | 34 +- frame/elections-phragmen/src/lib.rs | 31 +- frame/elections-phragmen/src/migrations/v3.rs | 4 +- frame/elections-phragmen/src/migrations/v4.rs | 4 +- frame/elections-phragmen/src/migrations/v5.rs | 2 +- frame/elections-phragmen/src/weights.rs | 182 +- frame/examples/basic/src/lib.rs | 4 +- frame/examples/basic/src/tests.rs | 4 +- frame/examples/basic/src/weights.rs | 38 +- frame/examples/offchain-worker/src/tests.rs | 2 +- frame/executive/README.md | 2 +- frame/executive/src/lib.rs | 43 +- frame/gilt/src/lib.rs | 2 +- frame/gilt/src/weights.rs | 122 +- frame/grandpa/src/default_weights.rs | 2 +- frame/grandpa/src/migrations/v4.rs | 4 +- frame/grandpa/src/mock.rs | 2 +- frame/grandpa/src/tests.rs | 2 +- frame/identity/src/tests.rs | 2 +- frame/identity/src/weights.rs | 310 ++-- frame/im-online/src/mock.rs | 2 +- frame/im-online/src/weights.rs | 22 +- frame/indices/src/mock.rs | 2 +- frame/indices/src/weights.rs | 62 +- frame/lottery/src/weights.rs | 74 +- frame/membership/src/lib.rs | 2 +- frame/membership/src/migrations/v4.rs | 4 +- frame/membership/src/weights.rs | 110 +- .../src/default_weights.rs | 2 +- frame/merkle-mountain-range/src/tests.rs | 4 +- frame/multisig/src/benchmarking.rs | 32 +- frame/multisig/src/lib.rs | 4 +- frame/multisig/src/tests.rs | 173 +- frame/multisig/src/weights.rs | 170 +- frame/nicks/src/lib.rs | 2 +- frame/node-authorization/src/weights.rs | 20 +- frame/nomination-pools/src/migration.rs | 1 + frame/nomination-pools/src/weights.rs | 198 +-- frame/offences/benchmarking/src/mock.rs | 4 +- frame/preimage/src/mock.rs | 2 +- frame/preimage/src/weights.rs | 158 +- frame/proxy/src/lib.rs | 8 +- frame/proxy/src/tests.rs | 2 +- frame/proxy/src/weights.rs | 174 +- frame/randomness-collective-flip/src/lib.rs | 4 +- frame/ranked-collective/src/tests.rs | 3 +- frame/ranked-collective/src/weights.rs | 98 +- frame/recovery/src/mock.rs | 2 +- frame/recovery/src/weights.rs | 122 +- frame/referenda/src/branch.rs | 16 +- frame/referenda/src/mock.rs | 6 +- frame/referenda/src/weights.rs | 326 ++-- frame/remark/src/weights.rs | 14 +- frame/scheduler/src/mock.rs | 2 +- frame/scheduler/src/tests.rs | 209 ++- frame/scheduler/src/weights.rs | 290 ++-- frame/scored-pool/src/lib.rs | 2 +- frame/scored-pool/src/mock.rs | 2 +- frame/session/src/lib.rs | 2 +- frame/session/src/migrations/v1.rs | 4 +- frame/session/src/mock.rs | 2 +- frame/session/src/weights.rs | 26 +- frame/society/src/lib.rs | 2 +- frame/society/src/mock.rs | 2 +- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/tests.rs | 74 +- frame/staking/src/weights.rs | 458 ++--- frame/state-trie-migration/src/lib.rs | 34 +- frame/state-trie-migration/src/weights.rs | 70 +- frame/sudo/src/lib.rs | 3 +- frame/sudo/src/mock.rs | 3 +- frame/sudo/src/tests.rs | 64 +- frame/support/src/dispatch.rs | 47 +- frame/support/src/lib.rs | 2 +- frame/support/src/migrations.rs | 2 +- frame/support/src/traits/hooks.rs | 84 +- frame/support/src/weights.rs | 255 ++- frame/support/src/weights/block_weights.rs | 2 +- .../support/src/weights/extrinsic_weights.rs | 2 +- frame/support/src/weights/paritydb_weights.rs | 4 +- frame/support/src/weights/rocksdb_weights.rs | 4 +- frame/support/src/weights/weight_v2.rs | 483 ++++++ frame/support/test/tests/construct_runtime.rs | 14 +- frame/support/test/tests/pallet.rs | 34 +- .../test/tests/pallet_compatibility.rs | 17 +- .../tests/pallet_compatibility_instance.rs | 17 +- frame/support/test/tests/pallet_instance.rs | 28 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 6 +- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 6 +- .../pallet_ui/storage_info_unsatisfied.stderr | 2 +- .../storage_info_unsatisfied_nmap.stderr | 2 +- .../tests/pallet_with_name_trait_is_valid.rs | 2 +- frame/system/benches/bench.rs | 7 +- .../system/src/extensions/check_mortality.rs | 9 +- frame/system/src/extensions/check_weight.rs | 159 +- frame/system/src/lib.rs | 12 +- frame/system/src/limits.rs | 22 +- frame/system/src/migrations/mod.rs | 6 +- frame/system/src/mock.rs | 6 +- frame/system/src/tests.rs | 51 +- frame/system/src/weights.rs | 62 +- frame/timestamp/src/mock.rs | 2 +- frame/timestamp/src/weights.rs | 18 +- frame/tips/src/migrations/v4.rs | 4 +- frame/tips/src/weights.rs | 98 +- .../asset-tx-payment/src/tests.rs | 80 +- frame/transaction-payment/src/lib.rs | 303 ++-- frame/transaction-payment/src/types.rs | 8 +- frame/transaction-storage/src/weights.rs | 42 +- frame/treasury/src/lib.rs | 4 +- frame/treasury/src/tests.rs | 2 +- frame/treasury/src/weights.rs | 90 +- frame/uniques/src/migration.rs | 7 +- frame/uniques/src/weights.rs | 354 ++-- frame/utility/src/lib.rs | 20 +- frame/utility/src/tests.rs | 30 +- frame/utility/src/weights.rs | 34 +- frame/vesting/src/mock.rs | 2 +- frame/vesting/src/weights.rs | 162 +- frame/whitelist/src/mock.rs | 2 +- frame/whitelist/src/tests.rs | 12 +- frame/whitelist/src/weights.rs | 54 +- test-utils/runtime/src/lib.rs | 4 +- .../frame/benchmarking-cli/src/block/bench.rs | 3 +- .../benchmarking-cli/src/overhead/README.md | 58 +- .../benchmarking-cli/src/overhead/weights.hbs | 11 +- .../benchmarking-cli/src/pallet/template.hbs | 14 +- 187 files changed, 5913 insertions(+), 4911 deletions(-) create mode 100644 frame/support/src/weights/weight_v2.rs diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 593da06f4a7c0..c6df85194ac99 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -31,7 +31,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for {{pallet}}. @@ -64,22 +64,22 @@ impl WeightInfo for SubstrateWeight { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { - ({{underscore benchmark.base_weight}} as Weight) + Weight::from_ref_time({{underscore benchmark.base_weight}} as RefTimeWeight) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).scalar_saturating_mul({{cw.name}} as RefTimeWeight)) {{/each}} {{#if (ne benchmark.base_reads "0")}} - .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight)) + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as RefTimeWeight)) {{/if}} {{#each benchmark.component_reads as |cr|}} - .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) + .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as RefTimeWeight).saturating_mul({{cr.name}} as RefTimeWeight))) {{/each}} {{#if (ne benchmark.base_writes "0")}} - .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight)) + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as RefTimeWeight)) {{/if}} {{#each benchmark.component_writes as |cw|}} - .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) + .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight))) {{/each}} } {{/each}} @@ -99,22 +99,22 @@ impl WeightInfo for () { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { - ({{underscore benchmark.base_weight}} as Weight) + Weight::from_ref_time({{underscore benchmark.base_weight}} as RefTimeWeight) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).scalar_saturating_mul({{cw.name}} as RefTimeWeight)) {{/each}} {{#if (ne benchmark.base_reads "0")}} - .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}} as Weight)) + .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}} as RefTimeWeight)) {{/if}} {{#each benchmark.component_reads as |cr|}} - .saturating_add(RocksDbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) + .saturating_add(RocksDbWeight::get().reads(({{cr.slope}} as RefTimeWeight).saturating_mul({{cr.name}} as RefTimeWeight))) {{/each}} {{#if (ne benchmark.base_writes "0")}} - .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}} as Weight)) + .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}} as RefTimeWeight)) {{/if}} {{#each benchmark.component_writes as |cw|}} - .saturating_add(RocksDbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) + .saturating_add(RocksDbWeight::get().writes(({{cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight))) {{/each}} } {{/each}} diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index f1519efe062bd..a9209a9040b6d 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -64,7 +64,7 @@ pub mod pallet { impl Pallet { /// An example dispatchable that takes a singles value as a parameter, writes the value to /// storage and emits an event. This function must be dispatched by a signed extrinsic. - #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + #[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { // Check that the extrinsic was signed and get the signer. // This function will return an error if the extrinsic is not signed. @@ -81,7 +81,7 @@ pub mod pallet { } /// An example dispatchable that may throw a custom error. - #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))] + #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] pub fn cause_error(origin: OriginFor) -> DispatchResult { let _who = ensure_signed(origin)?; diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 468b9c8ac4c1b..3426df5872c35 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -18,7 +18,7 @@ use codec::{Decode, Encode, Joiner}; use frame_support::{ traits::Currency, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo}, + weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Weight}, }; use frame_system::{self, AccountInfo, EventRecord, Phase}; use sp_core::{storage::well_known_keys, traits::Externalities, NeverNativeValue}; @@ -733,7 +733,7 @@ fn deploying_wasm_contract_should_work() { function: Call::Contracts( pallet_contracts::Call::instantiate_with_code:: { value: 0, - gas_limit: 500_000_000, + gas_limit: Weight::from_ref_time(500_000_000), storage_deposit_limit: None, code: transfer_code, data: Vec::new(), @@ -746,7 +746,7 @@ fn deploying_wasm_contract_should_work() { function: Call::Contracts(pallet_contracts::Call::call:: { dest: sp_runtime::MultiAddress::Id(addr.clone()), value: 10, - gas_limit: 500_000_000, + gas_limit: Weight::from_ref_time(500_000_000), storage_deposit_limit: None, data: vec![0x00, 0x01, 0x02, 0x03], }), diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index 296d1d8e28798..dd1318254d9b7 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -208,7 +208,7 @@ fn transaction_fee_is_correct() { // we know that weight to fee multiplier is effect-less in block 1. // current weight of transfer = 200_000_000 // Linear weight to fee is 1:1 right now (1 weight = 1 unit of balance) - assert_eq!(weight_fee, weight as Balance); + assert_eq!(weight_fee, weight.ref_time() as Balance); balance_alice -= base_fee; balance_alice -= weight_fee; balance_alice -= tip; diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index eaf872d6f3fec..510955a5b7b3e 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -163,13 +163,13 @@ mod multiplier_tests { let previous_float = previous_float.max(min_multiplier().into_inner() as f64 / accuracy); // maximum tx weight - let m = max_normal() as f64; + let m = max_normal().ref_time() as f64; // block weight always truncated to max weight - let block_weight = (block_weight as f64).min(m); + let block_weight = (block_weight.ref_time() as f64).min(m); let v: f64 = AdjustmentVariable::get().to_float(); // Ideal saturation in terms of weight - let ss = target() as f64; + let ss = target().ref_time() as f64; // Current saturation in terms of weight let s = block_weight; @@ -197,9 +197,9 @@ mod multiplier_tests { fn truth_value_update_poc_works() { let fm = Multiplier::saturating_from_rational(1, 2); let test_set = vec![ - (0, fm), - (100, fm), - (1000, fm), + (Weight::zero(), fm), + (Weight::from_ref_time(100), fm), + (Weight::from_ref_time(1000), fm), (target(), fm), (max_normal() / 2, fm), (max_normal(), fm), @@ -229,7 +229,7 @@ mod multiplier_tests { #[test] fn multiplier_cannot_go_below_limit() { // will not go any further below even if block is empty. - run_with_system_weight(0, || { + run_with_system_weight(Weight::new(), || { let next = runtime_multiplier_update(min_multiplier()); assert_eq!(next, min_multiplier()); }) @@ -247,7 +247,7 @@ mod multiplier_tests { // 1 < 0.00001 * k * 0.1875 // 10^9 / 1875 < k // k > 533_333 ~ 18,5 days. - run_with_system_weight(0, || { + run_with_system_weight(Weight::new(), || { // start from 1, the default. let mut fm = Multiplier::one(); let mut iterations: u64 = 0; @@ -283,7 +283,8 @@ mod multiplier_tests { // `cargo test congested_chain_simulation -- --nocapture` to get some insight. // almost full. The entire quota of normal transactions is taken. - let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap() - 100; + let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap() - + Weight::from_ref_time(100); // Default substrate weight. let tx_weight = frame_support::weights::constants::ExtrinsicBaseWeight::get(); @@ -407,27 +408,27 @@ mod multiplier_tests { #[test] fn weight_to_fee_should_not_overflow_on_large_weights() { - let kb = 1024 as Weight; + let kb = Weight::from_ref_time(1024); let mb = kb * kb; let max_fm = Multiplier::saturating_from_integer(i128::MAX); // check that for all values it can compute, correctly. vec![ - 0, - 1, - 10, - 1000, + Weight::zero(), + Weight::one(), + Weight::from_ref_time(10), + Weight::from_ref_time(1000), kb, 10 * kb, 100 * kb, mb, 10 * mb, - 2147483647, - 4294967295, + Weight::from_ref_time(2147483647), + Weight::from_ref_time(4294967295), BlockWeights::get().max_block / 2, BlockWeights::get().max_block, - Weight::max_value() / 2, - Weight::max_value(), + Weight::MAX / 2, + Weight::MAX, ] .into_iter() .for_each(|i| { @@ -440,7 +441,7 @@ mod multiplier_tests { // Some values that are all above the target and will cause an increase. let t = target(); - vec![t + 100, t * 2, t * 4].into_iter().for_each(|i| { + vec![t + Weight::from_ref_time(100), t * 2, t * 4].into_iter().for_each(|i| { run_with_system_weight(i, || { let fm = runtime_multiplier_update(max_fm); // won't grow. The convert saturates everything. diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f8ea312d1a496..5d4a21cea09b2 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -170,7 +170,7 @@ const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// by Operational extrinsics. const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); /// We allow for 2 seconds of compute with a 6 second average block time. -const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND; +const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND.scalar_saturating_mul(2); parameter_types! { pub const BlockHashCount: BlockNumber = 2400; @@ -1936,7 +1936,7 @@ impl_runtime_apis! { storage_deposit_limit: Option, input_data: Vec, ) -> pallet_contracts_primitives::ContractExecResult { - Contracts::bare_call(origin, dest, value, gas_limit, storage_deposit_limit, input_data, true) + Contracts::bare_call(origin, dest, value, Weight::from_ref_time(gas_limit), storage_deposit_limit, input_data, true) } fn instantiate( @@ -1949,7 +1949,7 @@ impl_runtime_apis! { salt: Vec, ) -> pallet_contracts_primitives::ContractInstantiateResult { - Contracts::bare_instantiate(origin, value, gas_limit, storage_deposit_limit, code, data, salt, true) + Contracts::bare_instantiate(origin, value, Weight::from_ref_time(gas_limit), storage_deposit_limit, code, data, salt, true) } fn upload_code( diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index 25dcb18b175ef..33cf933aba421 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -332,7 +332,7 @@ benchmarks_instance_pallet! { // Whitelist voter account from further DB operations. let voter_key = frame_system::Account::::hashed_key_for(&voter); frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into()); - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::max_value(), bytes_in_storage) + }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) verify { // The last proposal is removed. assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); @@ -417,7 +417,7 @@ benchmarks_instance_pallet! { index, true, )?; - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::max_value(), bytes_in_storage) + }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) verify { // The last proposal is removed. assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); @@ -489,7 +489,7 @@ benchmarks_instance_pallet! { System::::set_block_number(T::BlockNumber::max_value()); - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::max_value(), bytes_in_storage) + }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) verify { // The last proposal is removed. assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); @@ -562,7 +562,7 @@ benchmarks_instance_pallet! { // caller is prime, prime already votes aye by creating the proposal System::::set_block_number(T::BlockNumber::max_value()); - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::max_value(), bytes_in_storage) + }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) verify { // The last proposal is removed. assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); diff --git a/frame/alliance/src/migration.rs b/frame/alliance/src/migration.rs index cd54eed7a9a75..010603902f0fd 100644 --- a/frame/alliance/src/migration.rs +++ b/frame/alliance/src/migration.rs @@ -25,7 +25,7 @@ pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); /// Wrapper for all migrations of this pallet. pub fn migrate, I: 'static>() -> Weight { let onchain_version = Pallet::::on_chain_storage_version(); - let mut weight: Weight = 0; + let mut weight: Weight = Weight::new(); if onchain_version < 1 { weight = weight.saturating_add(v0_to_v1::migrate::()); diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index aa9ebde528683..048bea3d1e5a4 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_alliance. @@ -80,30 +80,30 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[0, 90]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - (22_575_000 as Weight) + Weight::from_ref_time(22_575_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((11_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(11_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 23_000 - .saturating_add((158_000 as Weight).saturating_mul(x as Weight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((90_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(90_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((216_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(216_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Alliance Members (r:2 w:0) // Storage: AllianceMotion Voting (r:1 w:1) /// The range of component `x` is `[3, 10]`. /// The range of component `y` is `[2, 90]`. fn vote(x: u32, y: u32, ) -> Weight { - (45_486_000 as Weight) + Weight::from_ref_time(45_486_000 as RefTimeWeight) // Standard Error: 29_000 - .saturating_add((78_000 as Weight).saturating_mul(x as Weight)) + .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((128_000 as Weight).saturating_mul(y as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(128_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion ProposalOf (r:1 w:1) @@ -111,11 +111,11 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - (35_296_000 as Weight) + Weight::from_ref_time(35_296_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((171_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(171_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -126,15 +126,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - (39_252_000 as Weight) + Weight::from_ref_time(39_252_000 as RefTimeWeight) // Standard Error: 18_000 - .saturating_add((75_000 as Weight).saturating_mul(x as Weight)) + .saturating_add(Weight::from_ref_time(75_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((107_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((170_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(170_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -146,13 +146,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - (50_357_000 as Weight) + Weight::from_ref_time(50_357_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((103_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(103_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((204_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(204_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -164,13 +164,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - (41_258_000 as Weight) + Weight::from_ref_time(41_258_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((111_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(111_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((186_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -183,15 +183,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_approved(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - (40_490_000 as Weight) + Weight::from_ref_time(40_490_000 as RefTimeWeight) // Standard Error: 16_000 - .saturating_add((119_000 as Weight).saturating_mul(x as Weight)) + .saturating_add(Weight::from_ref_time(119_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((93_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((195_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(195_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:2 w:3) // Storage: AllianceMotion Members (r:1 w:1) @@ -199,55 +199,55 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[0, 90]`. /// The range of component `z` is `[0, 100]`. fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { - (35_186_000 as Weight) + Weight::from_ref_time(35_186_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((161_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((127_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(127_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - (18_189_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_189_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - (21_106_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(21_106_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - (22_208_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(22_208_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - (53_771_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(53_771_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - (41_912_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(41_912_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Members (r:3 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - (36_811_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(36_811_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Alliance Members (r:4 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -255,18 +255,18 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - (41_079_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(41_079_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Alliance RetiringMembers (r:1 w:1) // Storage: Alliance Members (r:1 w:1) // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - (42_703_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(42_703_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Alliance Members (r:3 w:1) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -275,35 +275,35 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - (61_370_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(61_370_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_385_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(1_385_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((119_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(119_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 153_000 - .saturating_add((21_484_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(21_484_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 59_000 - .saturating_add((3_772_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(3_772_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } } @@ -319,30 +319,30 @@ impl WeightInfo for () { /// The range of component `y` is `[0, 90]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - (22_575_000 as Weight) + Weight::from_ref_time(22_575_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((11_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(11_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 23_000 - .saturating_add((158_000 as Weight).saturating_mul(x as Weight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((90_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(90_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((216_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(216_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Alliance Members (r:2 w:0) // Storage: AllianceMotion Voting (r:1 w:1) /// The range of component `x` is `[3, 10]`. /// The range of component `y` is `[2, 90]`. fn vote(x: u32, y: u32, ) -> Weight { - (45_486_000 as Weight) + Weight::from_ref_time(45_486_000 as RefTimeWeight) // Standard Error: 29_000 - .saturating_add((78_000 as Weight).saturating_mul(x as Weight)) + .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((128_000 as Weight).saturating_mul(y as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(128_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion ProposalOf (r:1 w:1) @@ -350,11 +350,11 @@ impl WeightInfo for () { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - (35_296_000 as Weight) + Weight::from_ref_time(35_296_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((171_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(171_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -365,15 +365,15 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - (39_252_000 as Weight) + Weight::from_ref_time(39_252_000 as RefTimeWeight) // Standard Error: 18_000 - .saturating_add((75_000 as Weight).saturating_mul(x as Weight)) + .saturating_add(Weight::from_ref_time(75_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((107_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((170_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(170_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -385,13 +385,13 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - (50_357_000 as Weight) + Weight::from_ref_time(50_357_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((103_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(103_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((204_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(204_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -403,13 +403,13 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - (41_258_000 as Weight) + Weight::from_ref_time(41_258_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((111_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(111_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((186_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -422,15 +422,15 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_approved(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - (40_490_000 as Weight) + Weight::from_ref_time(40_490_000 as RefTimeWeight) // Standard Error: 16_000 - .saturating_add((119_000 as Weight).saturating_mul(x as Weight)) + .saturating_add(Weight::from_ref_time(119_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((93_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((195_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(195_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:2 w:3) // Storage: AllianceMotion Members (r:1 w:1) @@ -438,55 +438,55 @@ impl WeightInfo for () { /// The range of component `y` is `[0, 90]`. /// The range of component `z` is `[0, 100]`. fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { - (35_186_000 as Weight) + Weight::from_ref_time(35_186_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((161_000 as Weight).saturating_mul(y as Weight)) + .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((127_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(127_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - (18_189_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_189_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - (21_106_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(21_106_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - (22_208_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(22_208_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - (53_771_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(53_771_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - (41_912_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(41_912_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Members (r:3 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - (36_811_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(36_811_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Alliance Members (r:4 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -494,18 +494,18 @@ impl WeightInfo for () { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - (41_079_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(41_079_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Alliance RetiringMembers (r:1 w:1) // Storage: Alliance Members (r:1 w:1) // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - (42_703_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(42_703_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Alliance Members (r:3 w:1) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -514,34 +514,34 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - (61_370_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(61_370_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_385_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(1_385_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((119_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(119_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 153_000 - .saturating_add((21_484_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(21_484_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 59_000 - .saturating_add((3_772_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(3_772_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } } diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index e8f1184cf570f..971728df46c24 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_assets. @@ -74,15 +74,15 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (27_167_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(27_167_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (15_473_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(15_473_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:5002 w:5001) @@ -90,168 +90,168 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Metadata (r:1 w:0) // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 37_000 - .saturating_add((17_145_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) // Standard Error: 37_000 - .saturating_add((19_333_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(19_333_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 375_000 - .saturating_add((17_046_000 as Weight).saturating_mul(a as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) - .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(c as Weight))) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) + .saturating_add(Weight::from_ref_time(17_046_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (30_819_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(30_819_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (35_212_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(35_212_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (47_401_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(47_401_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (42_300_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(42_300_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (47_946_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(47_946_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (21_670_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(21_670_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (21_503_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(21_503_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (18_158_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_158_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (18_525_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_525_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (19_858_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(19_858_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (18_045_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_045_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn set_metadata(n: u32, s: u32, ) -> Weight { - (32_395_000 as Weight) + Weight::from_ref_time(32_395_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (32_893_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(32_893_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - (19_586_000 as Weight) + Weight::from_ref_time(19_586_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (32_478_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(32_478_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (17_143_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(17_143_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (36_389_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(36_389_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Assets Approvals (r:1 w:1) // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (61_854_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(61_854_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (36_759_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(36_759_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - (37_753_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(37_753_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } } @@ -259,15 +259,15 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (27_167_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(27_167_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (15_473_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(15_473_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:5002 w:5001) @@ -275,167 +275,167 @@ impl WeightInfo for () { // Storage: Assets Metadata (r:1 w:0) // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 37_000 - .saturating_add((17_145_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) // Standard Error: 37_000 - .saturating_add((19_333_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(19_333_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 375_000 - .saturating_add((17_046_000 as Weight).saturating_mul(a as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) - .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(c as Weight))) - .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) + .saturating_add(Weight::from_ref_time(17_046_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (30_819_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(30_819_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (35_212_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(35_212_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (47_401_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(47_401_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (42_300_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(42_300_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (47_946_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(47_946_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (21_670_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(21_670_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (21_503_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(21_503_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (18_158_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_158_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (18_525_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_525_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (19_858_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(19_858_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (18_045_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_045_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn set_metadata(n: u32, s: u32, ) -> Weight { - (32_395_000 as Weight) + Weight::from_ref_time(32_395_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (32_893_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(32_893_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - (19_586_000 as Weight) + Weight::from_ref_time(19_586_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (32_478_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(32_478_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (17_143_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(17_143_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (36_389_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(36_389_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Assets Approvals (r:1 w:1) // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (61_854_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(61_854_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (36_759_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(36_759_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - (37_753_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(37_753_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } } diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 54643001ad6fc..1b6c62c55ee20 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -243,7 +243,7 @@ pub mod pallet { /// - `duration`: Locked duration of the atomic swap. For safety reasons, it is recommended /// that the revealer uses a shorter duration than the counterparty, to prevent the /// situation where the revealer reveals the proof too late around the end block. - #[pallet::weight(T::DbWeight::get().reads_writes(1, 1).saturating_add(40_000_000))] + #[pallet::weight(T::DbWeight::get().reads_writes(1, 1).ref_time().saturating_add(40_000_000))] pub fn create_swap( origin: OriginFor, target: T::AccountId, @@ -280,9 +280,10 @@ pub mod pallet { /// the operation fails. This is used for weight calculation. #[pallet::weight( T::DbWeight::get().reads_writes(1, 1) - .saturating_add(40_000_000) - .saturating_add((proof.len() as Weight).saturating_mul(100)) .saturating_add(action.weight()) + .ref_time() + .saturating_add(40_000_000) + .saturating_add((proof.len() as u64).saturating_mul(100)) )] pub fn claim_swap( origin: OriginFor, @@ -317,7 +318,7 @@ pub mod pallet { /// /// - `target`: Target of the original atomic swap. /// - `hashed_proof`: Hashed proof of the original atomic swap. - #[pallet::weight(T::DbWeight::get().reads_writes(1, 1).saturating_add(40_000_000))] + #[pallet::weight(T::DbWeight::get().reads_writes(1, 1).ref_time().saturating_add(40_000_000))] pub fn cancel_swap( origin: OriginFor, target: T::AccountId, diff --git a/frame/atomic-swap/src/tests.rs b/frame/atomic-swap/src/tests.rs index 688d3ff17f786..ffb548a1f29ed 100644 --- a/frame/atomic-swap/src/tests.rs +++ b/frame/atomic-swap/src/tests.rs @@ -30,7 +30,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 636a28692ba28..5023feeaf8aea 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -49,7 +49,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index a56d8e785f6ac..d5f9783f153c8 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -227,7 +227,7 @@ mod tests { pub const Period: BlockNumber = 1; pub const Offset: BlockNumber = 0; pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 8ddccfd9cf939..ff18e047db048 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -190,7 +190,7 @@ pub mod pallet { T::EventHandler::note_author(author); } - 0 + Weight::zero() } fn on_finalize(_: T::BlockNumber) { @@ -460,7 +460,7 @@ mod tests { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { diff --git a/frame/babe/src/default_weights.rs b/frame/babe/src/default_weights.rs index 57c74323b7932..cc1d11108b2e1 100644 --- a/frame/babe/src/default_weights.rs +++ b/frame/babe/src/default_weights.rs @@ -38,8 +38,8 @@ impl crate::WeightInfo for () { const MAX_NOMINATORS: u64 = 200; // checking membership proof - (35 * WEIGHT_PER_MICROS) - .saturating_add((175 * WEIGHT_PER_NANOS).saturating_mul(validator_count)) + let ref_time_weight = (35 * WEIGHT_PER_MICROS) + .saturating_add((175 * WEIGHT_PER_NANOS).scalar_saturating_mul(validator_count)) .saturating_add(DbWeight::get().reads(5)) // check equivocation proof .saturating_add(110 * WEIGHT_PER_MICROS) @@ -47,6 +47,8 @@ impl crate::WeightInfo for () { .saturating_add(110 * WEIGHT_PER_MICROS) .saturating_add(25 * WEIGHT_PER_MICROS * MAX_NOMINATORS) .saturating_add(DbWeight::get().reads(14 + 3 * MAX_NOMINATORS)) - .saturating_add(DbWeight::get().writes(10 + 3 * MAX_NOMINATORS)) + .saturating_add(DbWeight::get().writes(10 + 3 * MAX_NOMINATORS)); + + ref_time_weight } } diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 1effc2c1989fa..48ca62a5b1a09 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -336,7 +336,7 @@ pub mod pallet { /// Initialization fn on_initialize(now: BlockNumberFor) -> Weight { Self::initialize(now); - 0 + Weight::zero() } /// Block finalization @@ -1008,6 +1008,6 @@ pub mod migrations { writes += 3; - T::DbWeight::get().writes(writes) + T::DbWeight::get().reads(reads) + T::DbWeight::get().reads_writes(reads, writes) } } diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index c2ba3c2be06d8..3a6348404b9a7 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -66,7 +66,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index ece0883387709..2f967b658e396 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -852,7 +852,7 @@ fn valid_equivocation_reports_dont_pay_fees() { .get_dispatch_info(); // it should have non-zero weight and the fee has to be paid. - assert!(info.weight > 0); + assert!(info.weight > Weight::zero()); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. diff --git a/frame/bags-list/src/migrations.rs b/frame/bags-list/src/migrations.rs index a77beb23bd667..49b7d136125e2 100644 --- a/frame/bags-list/src/migrations.rs +++ b/frame/bags-list/src/migrations.rs @@ -21,7 +21,6 @@ use codec::{Decode, Encode}; use core::marker::PhantomData; use frame_election_provider_support::ScoreProvider; use frame_support::traits::OnRuntimeUpgrade; -use sp_runtime::traits::Zero; #[cfg(feature = "try-runtime")] use frame_support::ensure; diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index a554a9bd4ad1a..049967e3024c0 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_bags_list. @@ -57,18 +57,18 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (55_040_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(55_040_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (53_671_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(53_671_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: BagsList ListNodes (r:4 w:4) // Storage: Staking Bonded (r:2 w:0) @@ -76,9 +76,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (56_410_000 as Weight) - .saturating_add(T::DbWeight::get().reads(10 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(56_410_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(10 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } } @@ -89,18 +89,18 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - (55_040_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(55_040_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - (53_671_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(53_671_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: BagsList ListNodes (r:4 w:4) // Storage: Staking Bonded (r:2 w:0) @@ -108,8 +108,8 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - (56_410_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(10 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(56_410_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(10 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } } diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index a9e44f085977a..6605af530563d 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -188,14 +188,14 @@ macro_rules! decl_tests { ChargeTransactionPayment::from(1), &1, CALL, - &info_from_weight(1), + &info_from_weight(Weight::one()), 1, ).is_err()); assert_ok!( as SignedExtension>::pre_dispatch( ChargeTransactionPayment::from(0), &1, CALL, - &info_from_weight(1), + &info_from_weight(Weight::one()), 1, )); @@ -206,14 +206,14 @@ macro_rules! decl_tests { ChargeTransactionPayment::from(1), &1, CALL, - &info_from_weight(1), + &info_from_weight(Weight::one()), 1, ).is_err()); assert!( as SignedExtension>::pre_dispatch( ChargeTransactionPayment::from(0), &1, CALL, - &info_from_weight(1), + &info_from_weight(Weight::one()), 1, ).is_err()); }); diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 4ab913cf1411a..266c37063d2f8 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -46,7 +46,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); pub static ExistentialDeposit: u64 = 0; } impl frame_system::Config for Test { diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index 48c6574c3b39f..ebb82f41a545c 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -47,7 +47,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); pub static ExistentialDeposit: u64 = 0; } impl frame_system::Config for Test { diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 4c028840d553c..fbfd62eb63259 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -51,7 +51,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); pub static ExistentialDeposit: u64 = 0; } impl frame_system::Config for Test { diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index f612d31997996..17b2541e0a998 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_balances. @@ -58,45 +58,45 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (41_860_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(41_860_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (32_760_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(32_760_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (22_279_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(22_279_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (25_488_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_488_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (42_190_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(42_190_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (37_789_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(37_789_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (20_056_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(20_056_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } } @@ -104,44 +104,44 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (41_860_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(41_860_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (32_760_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(32_760_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (22_279_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(22_279_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (25_488_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_488_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (42_190_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(42_190_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (37_789_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(37_789_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (20_056_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(20_056_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } } diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index 8c642f74358db..b483208e3ef69 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -127,7 +127,7 @@ pub struct BenchmarkResult { impl BenchmarkResult { pub fn from_weight(w: Weight) -> Self { - Self { extrinsic_time: (w as u128) / 1_000, ..Default::default() } + Self { extrinsic_time: (w.ref_time() / 1_000) as u128, ..Default::default() } } } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index 8b36601940cf3..dc2ca26e1af02 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for frame_benchmarking. @@ -58,75 +58,75 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn addition(_i: u32, ) -> Weight { - (103_000 as Weight) + Weight::from_ref_time(103_000 as RefTimeWeight) } fn subtraction(_i: u32, ) -> Weight { - (105_000 as Weight) + Weight::from_ref_time(105_000 as RefTimeWeight) } fn multiplication(_i: u32, ) -> Weight { - (113_000 as Weight) + Weight::from_ref_time(113_000 as RefTimeWeight) } fn division(_i: u32, ) -> Weight { - (102_000 as Weight) + Weight::from_ref_time(102_000 as RefTimeWeight) } fn hashing(_i: u32, ) -> Weight { - (20_865_902_000 as Weight) + Weight::from_ref_time(20_865_902_000 as RefTimeWeight) } fn sr25519_verification(i: u32, ) -> Weight { - (319_000 as Weight) + Weight::from_ref_time(319_000 as RefTimeWeight) // Standard Error: 8_000 - .saturating_add((47_171_000 as Weight).saturating_mul(i as Weight)) + .saturating_add(Weight::from_ref_time(47_171_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((2_110_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) + .saturating_add(Weight::from_ref_time(2_110_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((372_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) + .saturating_add(Weight::from_ref_time(372_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } } // For backwards compatibility and tests impl WeightInfo for () { fn addition(_i: u32, ) -> Weight { - (103_000 as Weight) + Weight::from_ref_time(103_000 as RefTimeWeight) } fn subtraction(_i: u32, ) -> Weight { - (105_000 as Weight) + Weight::from_ref_time(105_000 as RefTimeWeight) } fn multiplication(_i: u32, ) -> Weight { - (113_000 as Weight) + Weight::from_ref_time(113_000 as RefTimeWeight) } fn division(_i: u32, ) -> Weight { - (102_000 as Weight) + Weight::from_ref_time(102_000 as RefTimeWeight) } fn hashing(_i: u32, ) -> Weight { - (20_865_902_000 as Weight) + Weight::from_ref_time(20_865_902_000 as RefTimeWeight) } fn sr25519_verification(i: u32, ) -> Weight { - (319_000 as Weight) + Weight::from_ref_time(319_000 as RefTimeWeight) // Standard Error: 8_000 - .saturating_add((47_171_000 as Weight).saturating_mul(i as Weight)) + .saturating_add(Weight::from_ref_time(47_171_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((2_110_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) + .saturating_add(Weight::from_ref_time(2_110_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((372_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) + .saturating_add(Weight::from_ref_time(372_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } } diff --git a/frame/bounties/src/migrations/v4.rs b/frame/bounties/src/migrations/v4.rs index 8f5f3ebe55bf4..2f81c97127bcd 100644 --- a/frame/bounties/src/migrations/v4.rs +++ b/frame/bounties/src/migrations/v4.rs @@ -54,7 +54,7 @@ pub fn migrate< target: "runtime::bounties", "New pallet name is equal to the old prefix. No migration needs to be done.", ); - return 0 + return Weight::zero() } let on_chain_storage_version =

::on_chain_storage_version(); @@ -105,7 +105,7 @@ pub fn migrate< "Attempted to apply migration to v4 but failed because storage version is {:?}", on_chain_storage_version, ); - 0 + Weight::zero() } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index d3e054cfc6351..27a23cb4ffeae 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_bounties. @@ -65,88 +65,88 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(_d: u32, ) -> Weight { - (28_903_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(28_903_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (10_997_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(10_997_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (8_967_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(8_967_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (28_665_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(28_665_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (25_141_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(25_141_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (21_295_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(21_295_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:3 w:3) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (67_951_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(67_951_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (33_654_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(33_654_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (50_582_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(50_582_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (18_322_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_322_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add((29_233_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(b as Weight))) + .saturating_add(Weight::from_ref_time(29_233_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) } } @@ -157,87 +157,87 @@ impl WeightInfo for () { // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(_d: u32, ) -> Weight { - (28_903_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(28_903_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - (10_997_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(10_997_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - (8_967_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(8_967_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (28_665_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(28_665_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (25_141_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(25_141_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - (21_295_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(21_295_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:3 w:3) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - (67_951_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(67_951_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - (33_654_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(33_654_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - (50_582_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(50_582_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - (18_322_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_322_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add((29_233_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(b as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(b as Weight))) + .saturating_add(Weight::from_ref_time(29_233_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) } } diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index 2584445071471..f42715f14bbee 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -60,7 +60,7 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockWeight: Weight = Weight::from_ref_time(1024); pub const MaximumBlockLength: u32 = 2 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); } diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index ad08e00149a30..c5d00d6ed0bd4 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_child_bounties. @@ -64,51 +64,51 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) fn add_child_bounty(d: u32, ) -> Weight { - (51_064_000 as Weight) + Weight::from_ref_time(51_064_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - (15_286_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(15_286_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (29_929_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(29_929_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (32_449_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(32_449_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - (23_793_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(23_793_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:3 w:3) // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - (67_529_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(67_529_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) @@ -117,9 +117,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - (48_436_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(48_436_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) @@ -128,9 +128,9 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - (58_044_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(7 as Weight)) + Weight::from_ref_time(58_044_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(7 as RefTimeWeight)) } } @@ -143,51 +143,51 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) fn add_child_bounty(d: u32, ) -> Weight { - (51_064_000 as Weight) + Weight::from_ref_time(51_064_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - (15_286_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(15_286_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - (29_929_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(29_929_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - (32_449_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(32_449_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - (23_793_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(23_793_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:3 w:3) // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - (67_529_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(67_529_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) @@ -196,9 +196,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - (48_436_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(48_436_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) @@ -207,8 +207,8 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - (58_044_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(7 as Weight)) + Weight::from_ref_time(58_044_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(7 as RefTimeWeight)) } } diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index 076afcd203030..b80a4aef28d38 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -355,7 +355,7 @@ benchmarks_instance_pallet! { // Whitelist voter account from further DB operations. let voter_key = frame_system::Account::::hashed_key_for(&voter); frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into()); - }: close(SystemOrigin::Signed(voter), last_hash, index, Weight::max_value(), bytes_in_storage) + }: close(SystemOrigin::Signed(voter), last_hash, index, Weight::MAX, bytes_in_storage) verify { // The last proposal is removed. assert_eq!(Collective::::proposals().len(), (p - 1) as usize); @@ -436,7 +436,7 @@ benchmarks_instance_pallet! { index, approve, )?; - }: close(SystemOrigin::Signed(caller), last_hash, index, Weight::max_value(), bytes_in_storage) + }: close(SystemOrigin::Signed(caller), last_hash, index, Weight::MAX, bytes_in_storage) verify { // The last proposal is removed. assert_eq!(Collective::::proposals().len(), (p - 1) as usize); @@ -511,7 +511,7 @@ benchmarks_instance_pallet! { assert_eq!(Collective::::proposals().len(), p as usize); // Prime nay will close it as disapproved - }: close(SystemOrigin::Signed(caller), last_hash, index, Weight::max_value(), bytes_in_storage) + }: close(SystemOrigin::Signed(caller), last_hash, index, Weight::MAX, bytes_in_storage) verify { assert_eq!(Collective::::proposals().len(), (p - 1) as usize); assert_last_event::(Event::Disapproved { proposal_hash: last_hash }.into()); @@ -583,7 +583,7 @@ benchmarks_instance_pallet! { assert_eq!(Collective::::proposals().len(), p as usize); // Prime aye will close it as approved - }: close(SystemOrigin::Signed(caller), last_hash, p - 1, Weight::max_value(), bytes_in_storage) + }: close(SystemOrigin::Signed(caller), last_hash, p - 1, Weight::MAX, bytes_in_storage) verify { assert_eq!(Collective::::proposals().len(), (p - 1) as usize); assert_last_event::(Event::Executed { proposal_hash: last_hash, result: Err(DispatchError::BadOrigin) }.into()); diff --git a/frame/collective/src/migrations/v4.rs b/frame/collective/src/migrations/v4.rs index 4e6cd05584138..483c3f9fa9e69 100644 --- a/frame/collective/src/migrations/v4.rs +++ b/frame/collective/src/migrations/v4.rs @@ -45,7 +45,7 @@ pub fn migrate::on_chain_storage_version(); @@ -70,7 +70,7 @@ pub fn migrate::WrongProposalWeight ); assert_ok!(Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len)); @@ -301,7 +307,7 @@ fn proposal_weight_limit_ignored_on_disapprove() { Origin::signed(4), hash, 0, - proposal_weight - 100, + proposal_weight - Weight::from_ref_time(100), proposal_len )); }) @@ -687,7 +693,11 @@ fn correct_validate_and_get_proposal() { Error::::WrongProposalLength ); assert_noop!( - Collective::validate_and_get_proposal(&hash, length, weight - 10), + Collective::validate_and_get_proposal( + &hash, + length, + weight - Weight::from_ref_time(10) + ), Error::::WrongProposalWeight ); let res = Collective::validate_and_get_proposal(&hash, length, weight); @@ -1196,18 +1206,18 @@ fn close_disapprove_does_not_care_about_weight_or_len() { assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); // It will not close with bad weight/len information assert_noop!( - Collective::close(Origin::signed(2), hash, 0, 0, 0), + Collective::close(Origin::signed(2), hash, 0, Weight::zero(), 0), Error::::WrongProposalLength, ); assert_noop!( - Collective::close(Origin::signed(2), hash, 0, 0, proposal_len), + Collective::close(Origin::signed(2), hash, 0, Weight::zero(), proposal_len), Error::::WrongProposalWeight, ); // Now we make the proposal fail assert_ok!(Collective::vote(Origin::signed(1), hash, 0, false)); assert_ok!(Collective::vote(Origin::signed(2), hash, 0, false)); // It can close even if the weight/len information is bad - assert_ok!(Collective::close(Origin::signed(2), hash, 0, 0, 0)); + assert_ok!(Collective::close(Origin::signed(2), hash, 0, Weight::zero(), 0)); }) } diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index 2f5c6f590a999..a0cc64cc2408d 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_collective. @@ -64,36 +64,36 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Voting (r:100 w:100) // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 12_000 - .saturating_add((10_280_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(10_280_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add((126_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(126_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add((13_310_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(p as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) + .saturating_add(Weight::from_ref_time(13_310_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) } // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - (16_819_000 as Weight) + Weight::from_ref_time(16_819_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 0 - .saturating_add((33_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - (18_849_000 as Weight) + Weight::from_ref_time(18_849_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 0 - .saturating_add((56_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) @@ -101,52 +101,52 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - (22_204_000 as Weight) + Weight::from_ref_time(22_204_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((8_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(8_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((49_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((180_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(180_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - (30_941_000 as Weight) + Weight::from_ref_time(30_941_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((77_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - (32_485_000 as Weight) + Weight::from_ref_time(32_485_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((39_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(39_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((124_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - (33_487_000 as Weight) + Weight::from_ref_time(33_487_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((66_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((157_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(157_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) @@ -154,13 +154,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - (33_494_000 as Weight) + Weight::from_ref_time(33_494_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((58_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(58_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((124_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) @@ -168,25 +168,25 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - (36_566_000 as Weight) + Weight::from_ref_time(36_566_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((63_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(63_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((158_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Council Proposals (r:1 w:1) // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - (20_159_000 as Weight) + Weight::from_ref_time(20_159_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((173_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } } @@ -197,36 +197,36 @@ impl WeightInfo for () { // Storage: Council Voting (r:100 w:100) // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 12_000 - .saturating_add((10_280_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(10_280_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add((126_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(126_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add((13_310_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(p as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) + .saturating_add(Weight::from_ref_time(13_310_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) } // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - (16_819_000 as Weight) + Weight::from_ref_time(16_819_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 0 - .saturating_add((33_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - (18_849_000 as Weight) + Weight::from_ref_time(18_849_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 0 - .saturating_add((56_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) @@ -234,52 +234,52 @@ impl WeightInfo for () { // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - (22_204_000 as Weight) + Weight::from_ref_time(22_204_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((8_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(8_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((49_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((180_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(180_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - (30_941_000 as Weight) + Weight::from_ref_time(30_941_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((77_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - (32_485_000 as Weight) + Weight::from_ref_time(32_485_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((39_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(39_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((124_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - (33_487_000 as Weight) + Weight::from_ref_time(33_487_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((66_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((157_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(157_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) @@ -287,13 +287,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - (33_494_000 as Weight) + Weight::from_ref_time(33_494_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((58_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(58_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((124_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) @@ -301,24 +301,24 @@ impl WeightInfo for () { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - (36_566_000 as Weight) + Weight::from_ref_time(36_566_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((63_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(63_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((158_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Council Proposals (r:1 w:1) // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - (20_159_000 as Weight) + Weight::from_ref_time(20_159_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((173_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } } diff --git a/frame/contracts/rpc/src/lib.rs b/frame/contracts/rpc/src/lib.rs index 0df8f90237ed3..1df7a5753f77e 100644 --- a/frame/contracts/rpc/src/lib.rs +++ b/frame/contracts/rpc/src/lib.rs @@ -229,7 +229,7 @@ where call_request; let value: Balance = decode_hex(value, "balance")?; - let gas_limit: Weight = decode_hex(gas_limit, "weight")?; + let gas_limit: u64 = decode_hex(gas_limit, "weight")?; let storage_deposit_limit: Option = storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; limit_gas(gas_limit)?; @@ -259,7 +259,7 @@ where } = instantiate_request; let value: Balance = decode_hex(value, "balance")?; - let gas_limit: Weight = decode_hex(gas_limit, "weight")?; + let gas_limit: u64 = decode_hex(gas_limit, "weight")?; let storage_deposit_limit: Option = storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; limit_gas(gas_limit)?; diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 1a0b735ac76ce..e29cb51728e1e 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -2853,8 +2853,8 @@ benchmarks! { println!("{:#?}", Schedule::::default()); println!("###############################################"); println!("Lazy deletion throughput per block (empty queue, full queue): {}, {}", - weight_limit / weight_per_key, - (weight_limit - weight_per_queue_item * queue_depth) / weight_per_key, + weight_limit / weight_per_key.ref_time(), + (weight_limit - weight_per_queue_item * queue_depth) / weight_per_key.ref_time(), ); } #[cfg(not(feature = "std"))] diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 29f8ad44a56ac..d0e0cf5cf95cb 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -238,7 +238,7 @@ where /// /// Weight is synonymous with gas in substrate. pub fn charge_weight(&mut self, amount: Weight) -> Result { - self.inner.runtime.charge_gas(RuntimeCosts::ChainExtension(amount)) + self.inner.runtime.charge_gas(RuntimeCosts::ChainExtension(amount.ref_time())) } /// Adjust a previously charged amount down to its actual amount. @@ -248,7 +248,7 @@ where pub fn adjust_weight(&mut self, charged: ChargedAmount, actual_weight: Weight) { self.inner .runtime - .adjust_gas(charged, RuntimeCosts::ChainExtension(actual_weight)) + .adjust_gas(charged, RuntimeCosts::ChainExtension(actual_weight.ref_time())) } /// Grants access to the execution environment of the current contract call. @@ -411,7 +411,8 @@ where buffer, allow_skip, |len| { - weight_per_byte.map(|w| RuntimeCosts::ChainExtension(w.saturating_mul(len.into()))) + weight_per_byte + .map(|w| RuntimeCosts::ChainExtension(w.ref_time().saturating_mul(len.into()))) }, ) } diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 3b186236dd0fa..81e1aef92cbfc 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -664,7 +664,7 @@ where debug_message: Option<&'a mut Vec>, ) -> Result<(Self, E), ExecError> { let (first_frame, executable, nonce) = - Self::new_frame(args, value, gas_meter, storage_meter, 0, schedule)?; + Self::new_frame(args, value, gas_meter, storage_meter, Weight::zero(), schedule)?; let stack = Self { origin, schedule, @@ -1089,7 +1089,7 @@ where delegated_call: Some(DelegatedCall { executable, caller: self.caller().clone() }), }, value, - 0, + Weight::zero(), )?; self.run(executable, input_data) } @@ -1825,7 +1825,7 @@ mod tests { let value = Default::default(); let recurse_ch = MockLoader::insert(Call, |ctx, _| { // Try to call into yourself. - let r = ctx.ext.call(0, BOB, 0, vec![], true); + let r = ctx.ext.call(Weight::zero(), BOB, 0, vec![], true); REACHED_BOTTOM.with(|reached_bottom| { let mut reached_bottom = reached_bottom.borrow_mut(); @@ -1880,7 +1880,7 @@ mod tests { .with(|caller| *caller.borrow_mut() = Some(ctx.ext.caller().clone())); // Call into CHARLIE contract. - assert_matches!(ctx.ext.call(0, CHARLIE, 0, vec![], true), Ok(_)); + assert_matches!(ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], true), Ok(_)); exec_success() }); let charlie_ch = MockLoader::insert(Call, |ctx, _| { @@ -2011,7 +2011,7 @@ mod tests { // ALICE is the origin of the call stack assert!(ctx.ext.caller_is_origin()); // BOB calls CHARLIE - ctx.ext.call(0, CHARLIE, 0, vec![], true) + ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], true) }); ExtBuilder::default().build().execute_with(|| { @@ -2041,7 +2041,7 @@ mod tests { assert_eq!(*ctx.ext.address(), BOB); // Call into charlie contract. - assert_matches!(ctx.ext.call(0, CHARLIE, 0, vec![], true), Ok(_)); + assert_matches!(ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], true), Ok(_)); exec_success() }); let charlie_ch = MockLoader::insert(Call, |ctx, _| { @@ -2190,7 +2190,7 @@ mod tests { let (address, output) = ctx .ext .instantiate( - 0, + Weight::zero(), dummy_ch, ::Currency::minimum_balance(), vec![], @@ -2250,7 +2250,7 @@ mod tests { // Instantiate a contract and save it's address in `instantiated_contract_address`. assert_matches!( ctx.ext.instantiate( - 0, + Weight::zero(), dummy_ch, ::Currency::minimum_balance(), vec![], @@ -2342,13 +2342,13 @@ mod tests { let info = ctx.ext.contract_info(); assert_eq!(info.storage_deposit, 0); info.storage_deposit = 42; - assert_eq!(ctx.ext.call(0, CHARLIE, 0, vec![], true), exec_trapped()); + assert_eq!(ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], true), exec_trapped()); assert_eq!(ctx.ext.contract_info().storage_deposit, 42); } exec_success() }); let code_charlie = MockLoader::insert(Call, |ctx, _| { - assert!(ctx.ext.call(0, BOB, 0, vec![99], true).is_ok()); + assert!(ctx.ext.call(Weight::zero(), BOB, 0, vec![99], true).is_ok()); exec_trapped() }); @@ -2377,7 +2377,7 @@ mod tests { fn recursive_call_during_constructor_fails() { let code = MockLoader::insert(Constructor, |ctx, _| { assert_matches!( - ctx.ext.call(0, ctx.ext.address().clone(), 0, vec![], true), + ctx.ext.call(Weight::zero(), ctx.ext.address().clone(), 0, vec![], true), Err(ExecError{error, ..}) if error == >::ContractNotFound.into() ); exec_success() @@ -2479,7 +2479,7 @@ mod tests { // call the contract passed as input with disabled reentry let code_bob = MockLoader::insert(Call, |ctx, _| { let dest = Decode::decode(&mut ctx.input_data.as_ref()).unwrap(); - ctx.ext.call(0, dest, 0, vec![], false) + ctx.ext.call(Weight::zero(), dest, 0, vec![], false) }); let code_charlie = MockLoader::insert(Call, |_, _| exec_success()); @@ -2524,7 +2524,7 @@ mod tests { fn call_deny_reentry() { let code_bob = MockLoader::insert(Call, |ctx, _| { if ctx.input_data[0] == 0 { - ctx.ext.call(0, CHARLIE, 0, vec![], false) + ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], false) } else { exec_success() } @@ -2532,7 +2532,7 @@ mod tests { // call BOB with input set to '1' let code_charlie = - MockLoader::insert(Call, |ctx, _| ctx.ext.call(0, BOB, 0, vec![1], true)); + MockLoader::insert(Call, |ctx, _| ctx.ext.call(Weight::zero(), BOB, 0, vec![1], true)); ExtBuilder::default().build().execute_with(|| { let schedule = ::Schedule::get(); @@ -2695,18 +2695,30 @@ mod tests { let success_code = MockLoader::insert(Constructor, |_, _| exec_success()); let succ_fail_code = MockLoader::insert(Constructor, move |ctx, _| { ctx.ext - .instantiate(0, fail_code, ctx.ext.minimum_balance() * 100, vec![], &[]) + .instantiate( + Weight::zero(), + fail_code, + ctx.ext.minimum_balance() * 100, + vec![], + &[], + ) .ok(); exec_success() }); let succ_succ_code = MockLoader::insert(Constructor, move |ctx, _| { let (account_id, _) = ctx .ext - .instantiate(0, success_code, ctx.ext.minimum_balance() * 100, vec![], &[]) + .instantiate( + Weight::zero(), + success_code, + ctx.ext.minimum_balance() * 100, + vec![], + &[], + ) .unwrap(); // a plain call should not influence the account counter - ctx.ext.call(0, account_id, 0, vec![], false).unwrap(); + ctx.ext.call(Weight::zero(), account_id, 0, vec![], false).unwrap(); exec_success() }); diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index 41df125da0170..ae20e4eeb0def 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -107,7 +107,7 @@ where /// /// Passing `0` as amount is interpreted as "all remaining gas". pub fn nested(&mut self, amount: Weight) -> Result { - let amount = if amount == 0 { self.gas_left } else { amount }; + let amount = if amount == Weight::zero() { self.gas_left } else { amount }; // NOTE that it is ok to allocate all available gas since it still ensured // by `charge` that it doesn't reach zero. @@ -121,7 +121,7 @@ where /// Absorb the remaining gas of a nested meter after we are done using it. pub fn absorb_nested(&mut self, nested: Self) { - if self.gas_left == 0 { + if self.gas_left == Weight::zero() { // All of the remaining gas was inherited by the nested gas meter. When absorbing // we can therefore safely inherit the lowest gas that the nested gas meter experienced // as long as it is lower than the lowest gas that was experienced by the parent. @@ -157,7 +157,7 @@ where } let amount = token.weight(); - let new_value = self.gas_left.checked_sub(amount); + let new_value = self.gas_left.checked_sub(&amount); // We always consume the gas even if there is not enough gas. self.gas_left = new_value.unwrap_or_else(Zero::zero); @@ -227,7 +227,7 @@ where #[cfg(test)] mod tests { - use super::{GasMeter, Token}; + use super::{GasMeter, Token, Weight}; use crate::tests::Test; /// A simple utility macro that helps to match against a @@ -271,20 +271,20 @@ mod tests { #[derive(Copy, Clone, PartialEq, Eq, Debug)] struct SimpleToken(u64); impl Token for SimpleToken { - fn weight(&self) -> u64 { - self.0 + fn weight(&self) -> Weight { + Weight::from_ref_time(self.0) } } #[test] fn it_works() { - let gas_meter = GasMeter::::new(50000); - assert_eq!(gas_meter.gas_left(), 50000); + let gas_meter = GasMeter::::new(Weight::from_ref_time(50000)); + assert_eq!(gas_meter.gas_left(), Weight::from_ref_time(50000)); } #[test] fn tracing() { - let mut gas_meter = GasMeter::::new(50000); + let mut gas_meter = GasMeter::::new(Weight::from_ref_time(50000)); assert!(!gas_meter.charge(SimpleToken(1)).is_err()); let mut tokens = gas_meter.tokens().iter(); @@ -294,7 +294,7 @@ mod tests { // This test makes sure that nothing can be executed if there is no gas. #[test] fn refuse_to_execute_anything_if_zero() { - let mut gas_meter = GasMeter::::new(0); + let mut gas_meter = GasMeter::::new(Weight::zero()); assert!(gas_meter.charge(SimpleToken(1)).is_err()); } @@ -305,7 +305,7 @@ mod tests { // if the gas meter runs out of gas. However, this is just a nice property to have. #[test] fn overcharge_is_unrecoverable() { - let mut gas_meter = GasMeter::::new(200); + let mut gas_meter = GasMeter::::new(Weight::from_ref_time(200)); // The first charge is should lead to OOG. assert!(gas_meter.charge(SimpleToken(300)).is_err()); @@ -318,7 +318,7 @@ mod tests { // possible. #[test] fn charge_exact_amount() { - let mut gas_meter = GasMeter::::new(25); + let mut gas_meter = GasMeter::::new(Weight::from_ref_time(25)); assert!(!gas_meter.charge(SimpleToken(25)).is_err()); } } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 06fd419d88bf3..ee0db17ade95b 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -110,7 +110,7 @@ use frame_support::{ dispatch::Dispatchable, ensure, traits::{ConstU32, Contains, Currency, Get, Randomness, ReservableCurrency, Time}, - weights::{DispatchClass, GetDispatchInfo, Pays, PostDispatchInfo, Weight}, + weights::{DispatchClass, GetDispatchInfo, Pays, PostDispatchInfo, RefTimeWeight, Weight}, BoundedVec, }; use frame_system::{limits::BlockWeights, Pallet as System}; @@ -214,7 +214,7 @@ impl, const P: u32> Get for DefaultContractAccessWe .get(DispatchClass::Normal) .max_total .unwrap_or(block_weights.max_block) / - Weight::from(P) + RefTimeWeight::from(P) } } @@ -873,8 +873,8 @@ where ); ContractExecResult { result: output.result.map_err(|r| r.error), - gas_consumed: output.gas_meter.gas_consumed(), - gas_required: output.gas_meter.gas_required(), + gas_consumed: output.gas_meter.gas_consumed().ref_time(), + gas_required: output.gas_meter.gas_required().ref_time(), storage_deposit: output.storage_deposit, debug_message: debug_message.unwrap_or_default(), } @@ -918,8 +918,8 @@ where .result .map(|(account_id, result)| InstantiateReturnValue { result, account_id }) .map_err(|e| e.error), - gas_consumed: output.gas_meter.gas_consumed(), - gas_required: output.gas_meter.gas_required(), + gas_consumed: output.gas_meter.gas_consumed().ref_time(), + gas_required: output.gas_meter.gas_required().ref_time(), storage_deposit: output.storage_deposit, debug_message: debug_message.unwrap_or_default(), } diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 19e699a855461..9d90cf38269b1 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -26,7 +26,7 @@ use sp_std::{marker::PhantomData, prelude::*}; /// Wrapper for all migrations of this pallet, based on `StorageVersion`. pub fn migrate() -> Weight { let version = StorageVersion::get::>(); - let mut weight: Weight = 0; + let mut weight = Weight::new(); if version < 4 { weight = weight.saturating_add(v4::migrate::()); @@ -127,7 +127,7 @@ mod v5 { type DeletionQueue = StorageValue, Vec>; pub fn migrate() -> Weight { - let mut weight: Weight = 0; + let mut weight = Weight::new(); >::translate(|_key, old: OldContractInfo| { weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); @@ -216,7 +216,7 @@ mod v6 { type OwnerInfoOf = StorageMap, Identity, CodeHash, OwnerInfo>; pub fn migrate() -> Weight { - let mut weight: Weight = 0; + let mut weight = Weight::new(); >::translate(|_key, old: OldContractInfo| { weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 907ce9e088648..b5c80642a5356 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -21,7 +21,7 @@ use crate::{weights::WeightInfo, Config}; use codec::{Decode, Encode}; -use frame_support::{weights::Weight, DefaultNoBound}; +use frame_support::{weights::RefTimeWeight, DefaultNoBound}; use pallet_contracts_proc_macro::{ScheduleDebug, WeightDebug}; use scale_info::TypeInfo; #[cfg(feature = "std")] @@ -255,166 +255,166 @@ pub struct InstructionWeights { #[scale_info(skip_type_params(T))] pub struct HostFnWeights { /// Weight of calling `seal_caller`. - pub caller: Weight, + pub caller: RefTimeWeight, /// Weight of calling `seal_is_contract`. - pub is_contract: Weight, + pub is_contract: RefTimeWeight, /// Weight of calling `seal_code_hash`. - pub code_hash: Weight, + pub code_hash: RefTimeWeight, /// Weight of calling `seal_own_code_hash`. - pub own_code_hash: Weight, + pub own_code_hash: RefTimeWeight, /// Weight of calling `seal_caller_is_origin`. - pub caller_is_origin: Weight, + pub caller_is_origin: RefTimeWeight, /// Weight of calling `seal_address`. - pub address: Weight, + pub address: RefTimeWeight, /// Weight of calling `seal_gas_left`. - pub gas_left: Weight, + pub gas_left: RefTimeWeight, /// Weight of calling `seal_balance`. - pub balance: Weight, + pub balance: RefTimeWeight, /// Weight of calling `seal_value_transferred`. - pub value_transferred: Weight, + pub value_transferred: RefTimeWeight, /// Weight of calling `seal_minimum_balance`. - pub minimum_balance: Weight, + pub minimum_balance: RefTimeWeight, /// Weight of calling `seal_block_number`. - pub block_number: Weight, + pub block_number: RefTimeWeight, /// Weight of calling `seal_now`. - pub now: Weight, + pub now: RefTimeWeight, /// Weight of calling `seal_weight_to_fee`. - pub weight_to_fee: Weight, + pub weight_to_fee: RefTimeWeight, /// Weight of calling `gas`. - pub gas: Weight, + pub gas: RefTimeWeight, /// Weight of calling `seal_input`. - pub input: Weight, + pub input: RefTimeWeight, /// Weight per input byte copied to contract memory by `seal_input`. - pub input_per_byte: Weight, + pub input_per_byte: RefTimeWeight, /// Weight of calling `seal_return`. - pub r#return: Weight, + pub r#return: RefTimeWeight, /// Weight per byte returned through `seal_return`. - pub return_per_byte: Weight, + pub return_per_byte: RefTimeWeight, /// Weight of calling `seal_terminate`. - pub terminate: Weight, + pub terminate: RefTimeWeight, /// Weight of calling `seal_random`. - pub random: Weight, + pub random: RefTimeWeight, /// Weight of calling `seal_reposit_event`. - pub deposit_event: Weight, + pub deposit_event: RefTimeWeight, /// Weight per topic supplied to `seal_deposit_event`. - pub deposit_event_per_topic: Weight, + pub deposit_event_per_topic: RefTimeWeight, /// Weight per byte of an event deposited through `seal_deposit_event`. - pub deposit_event_per_byte: Weight, + pub deposit_event_per_byte: RefTimeWeight, /// Weight of calling `seal_debug_message`. - pub debug_message: Weight, + pub debug_message: RefTimeWeight, /// Weight of calling `seal_set_storage`. - pub set_storage: Weight, + pub set_storage: RefTimeWeight, /// Weight per written byten of an item stored with `seal_set_storage`. - pub set_storage_per_new_byte: Weight, + pub set_storage_per_new_byte: RefTimeWeight, /// Weight per overwritten byte of an item stored with `seal_set_storage`. - pub set_storage_per_old_byte: Weight, + pub set_storage_per_old_byte: RefTimeWeight, /// Weight of calling `seal_set_code_hash`. - pub set_code_hash: Weight, + pub set_code_hash: RefTimeWeight, /// Weight of calling `seal_clear_storage`. - pub clear_storage: Weight, + pub clear_storage: RefTimeWeight, /// Weight of calling `seal_clear_storage` per byte of the stored item. - pub clear_storage_per_byte: Weight, + pub clear_storage_per_byte: RefTimeWeight, /// Weight of calling `seal_contains_storage`. - pub contains_storage: Weight, + pub contains_storage: RefTimeWeight, /// Weight of calling `seal_contains_storage` per byte of the stored item. - pub contains_storage_per_byte: Weight, + pub contains_storage_per_byte: RefTimeWeight, /// Weight of calling `seal_get_storage`. - pub get_storage: Weight, + pub get_storage: RefTimeWeight, /// Weight per byte of an item received via `seal_get_storage`. - pub get_storage_per_byte: Weight, + pub get_storage_per_byte: RefTimeWeight, /// Weight of calling `seal_take_storage`. - pub take_storage: Weight, + pub take_storage: RefTimeWeight, /// Weight per byte of an item received via `seal_take_storage`. - pub take_storage_per_byte: Weight, + pub take_storage_per_byte: RefTimeWeight, /// Weight of calling `seal_transfer`. - pub transfer: Weight, + pub transfer: RefTimeWeight, /// Weight of calling `seal_call`. - pub call: Weight, + pub call: RefTimeWeight, /// Weight of calling `seal_delegate_call`. - pub delegate_call: Weight, + pub delegate_call: RefTimeWeight, /// Weight surcharge that is claimed if `seal_call` does a balance transfer. - pub call_transfer_surcharge: Weight, + pub call_transfer_surcharge: RefTimeWeight, /// Weight per byte that is cloned by supplying the `CLONE_INPUT` flag. - pub call_per_cloned_byte: Weight, + pub call_per_cloned_byte: RefTimeWeight, /// Weight of calling `seal_instantiate`. - pub instantiate: Weight, + pub instantiate: RefTimeWeight, /// Weight surcharge that is claimed if `seal_instantiate` does a balance transfer. - pub instantiate_transfer_surcharge: Weight, + pub instantiate_transfer_surcharge: RefTimeWeight, /// Weight per salt byte supplied to `seal_instantiate`. - pub instantiate_per_salt_byte: Weight, + pub instantiate_per_salt_byte: RefTimeWeight, /// Weight of calling `seal_hash_sha_256`. - pub hash_sha2_256: Weight, + pub hash_sha2_256: RefTimeWeight, /// Weight per byte hashed by `seal_hash_sha_256`. - pub hash_sha2_256_per_byte: Weight, + pub hash_sha2_256_per_byte: RefTimeWeight, /// Weight of calling `seal_hash_keccak_256`. - pub hash_keccak_256: Weight, + pub hash_keccak_256: RefTimeWeight, /// Weight per byte hashed by `seal_hash_keccak_256`. - pub hash_keccak_256_per_byte: Weight, + pub hash_keccak_256_per_byte: RefTimeWeight, /// Weight of calling `seal_hash_blake2_256`. - pub hash_blake2_256: Weight, + pub hash_blake2_256: RefTimeWeight, /// Weight per byte hashed by `seal_hash_blake2_256`. - pub hash_blake2_256_per_byte: Weight, + pub hash_blake2_256_per_byte: RefTimeWeight, /// Weight of calling `seal_hash_blake2_128`. - pub hash_blake2_128: Weight, + pub hash_blake2_128: RefTimeWeight, /// Weight per byte hashed by `seal_hash_blake2_128`. - pub hash_blake2_128_per_byte: Weight, + pub hash_blake2_128_per_byte: RefTimeWeight, /// Weight of calling `seal_ecdsa_recover`. - pub ecdsa_recover: Weight, + pub ecdsa_recover: RefTimeWeight, /// Weight of calling `seal_ecdsa_to_eth_address`. - pub ecdsa_to_eth_address: Weight, + pub ecdsa_to_eth_address: RefTimeWeight, /// The type parameter is used in the default implementation. #[codec(skip)] @@ -435,19 +435,19 @@ macro_rules! call_zero { macro_rules! cost_args { ($name:ident, $( $arg: expr ),+) => { - (T::WeightInfo::$name($( $arg ),+).saturating_sub(call_zero!($name, $( $arg ),+))) + (T::WeightInfo::$name($( $arg ),+).saturating_sub(call_zero!($name, $( $arg ),+))).ref_time() } } macro_rules! cost_batched_args { ($name:ident, $( $arg: expr ),+) => { - cost_args!($name, $( $arg ),+) / Weight::from(API_BENCHMARK_BATCH_SIZE) + cost_args!($name, $( $arg ),+) / RefTimeWeight::from(API_BENCHMARK_BATCH_SIZE) } } macro_rules! cost_instr_no_params_with_batch_size { ($name:ident, $batch_size:expr) => { - (cost_args!($name, 1) / Weight::from($batch_size)) as u32 + (cost_args!($name, 1) / RefTimeWeight::from($batch_size)) as u32 }; } diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 01c809da8675e..76e2d74f3d887 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -28,7 +28,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::{DispatchError, DispatchResult}, storage::child::{self, ChildInfo}, - weights::Weight, + weights::{RefTimeWeight, Weight}, }; use scale_info::TypeInfo; use sp_core::crypto::UncheckedFrom; @@ -227,9 +227,11 @@ where let base_weight = T::WeightInfo::on_process_deletion_queue_batch(); let weight_per_queue_item = T::WeightInfo::on_initialize_per_queue_item(1) - T::WeightInfo::on_initialize_per_queue_item(0); - let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) - - T::WeightInfo::on_initialize_per_trie_key(0); - let decoding_weight = weight_per_queue_item.saturating_mul(queue_len as Weight); + let weight_per_key = (T::WeightInfo::on_initialize_per_trie_key(1) - + T::WeightInfo::on_initialize_per_trie_key(0)) + .ref_time(); + let decoding_weight = + weight_per_queue_item.scalar_saturating_mul(queue_len as RefTimeWeight); // `weight_per_key` being zero makes no sense and would constitute a failure to // benchmark properly. We opt for not removing any keys at all in this case. @@ -237,7 +239,8 @@ where .saturating_sub(base_weight) .saturating_sub(decoding_weight) .checked_div(weight_per_key) - .unwrap_or(0) as u32; + .unwrap_or(Weight::zero()) + .ref_time() as u32; (weight_per_key, key_budget) } @@ -248,7 +251,7 @@ where pub fn process_deletion_queue_batch(weight_limit: Weight) -> Weight { let queue_len = >::decode_len().unwrap_or(0); if queue_len == 0 { - return 0 + return Weight::zero() } let (weight_per_key, mut remaining_key_budget) = @@ -282,7 +285,10 @@ where } >::put(queue); - weight_limit.saturating_sub(weight_per_key.saturating_mul(remaining_key_budget as Weight)) + let ref_time_weight = weight_limit + .ref_time() + .saturating_sub(weight_per_key.saturating_mul(remaining_key_budget as RefTimeWeight)); + Weight::from_ref_time(ref_time_weight) } /// Generates a unique trie id by returning `hash(account_id ++ nonce)`. diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 204908cc4a989..3571434bb823b 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -175,7 +175,7 @@ impl ChainExtension for TestExtension { }, 0x8002 => { let mut env = env.buf_in_buf_out(); - let weight = env.read(5)?[4].into(); + let weight = Weight::from_ref_time(env.read(5)?[4].into()); env.charge_weight(weight)?; Ok(RetVal::Converging(id)) }, @@ -332,7 +332,7 @@ parameter_types! { impl Convert> for Test { fn convert(w: Weight) -> BalanceOf { - w + w.ref_time() } } @@ -355,6 +355,10 @@ impl Contains for TestFilter { } } +parameter_types! { + pub const DeletionWeightLimit: Weight = Weight::from_ref_time(500_000_000_000); +} + impl Config for Test { type Time = Timestamp; type Randomness = Randomness; @@ -368,7 +372,7 @@ impl Config for Test { type ChainExtension = (TestExtension, DisabledExtension, RevertingExtension, TempStorageExtension); type DeletionQueueDepth = ConstU32<1024>; - type DeletionWeightLimit = ConstU64<500_000_000_000>; + type DeletionWeightLimit = DeletionWeightLimit; type Schedule = MySchedule; type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; @@ -384,7 +388,7 @@ pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]); pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]); -pub const GAS_LIMIT: Weight = 100_000_000_000; +pub const GAS_LIMIT: Weight = Weight::from_ref_time(100_000_000_000); pub struct ExtBuilder { existential_deposit: u64, @@ -642,7 +646,7 @@ fn run_out_of_gas() { Origin::signed(ALICE), addr, // newly created account 0, - 1_000_000_000_000, + Weight::from_ref_time(1_000_000_000_000), None, vec![], ), @@ -1826,7 +1830,7 @@ fn lazy_removal_works() { assert_matches!(child::get(trie, &[99]), Some(42)); // Run the lazy removal - Contracts::on_idle(System::block_number(), Weight::max_value()); + Contracts::on_idle(System::block_number(), Weight::MAX); // Value should be gone now assert_matches!(child::get::(trie, &[99]), None); @@ -1896,7 +1900,7 @@ fn lazy_batch_removal_works() { } // Run single lazy removal - Contracts::on_idle(System::block_number(), Weight::max_value()); + Contracts::on_idle(System::block_number(), Weight::MAX); // The single lazy removal should have removed all queued tries for trie in tries.iter() { @@ -1911,7 +1915,7 @@ fn lazy_removal_partial_remove_works() { // We create a contract with some extra keys above the weight limit let extra_keys = 7u32; - let weight_limit = 5_000_000_000; + let weight_limit = Weight::from_ref_time(5_000_000_000); let (_, max_keys) = Storage::::deletion_budget(1, weight_limit); let vals: Vec<_> = (0..max_keys + extra_keys) .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode())) @@ -2085,7 +2089,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { assert_matches!(child::get::(trie, &[99]), Some(42)); // Run on_idle with max remaining weight, this should remove the value - Contracts::on_idle(System::block_number(), Weight::max_value()); + Contracts::on_idle(System::block_number(), Weight::MAX); // Value should be gone assert_matches!(child::get::(trie, &[99]), None); @@ -2096,7 +2100,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { fn lazy_removal_does_not_use_all_weight() { let (code, hash) = compile_module::("self_destruct").unwrap(); - let weight_limit = 5_000_000_000; + let weight_limit = Weight::from_ref_time(5_000_000_000); let mut ext = ExtBuilder::default().existential_deposit(50).build(); let (trie, vals, weight_per_key) = ext.execute_with(|| { @@ -2167,7 +2171,7 @@ fn lazy_removal_does_not_use_all_weight() { let weight_used = Storage::::process_deletion_queue_batch(weight_limit); // We have one less key in our trie than our weight limit suffices for - assert_eq!(weight_used, weight_limit - weight_per_key); + assert_eq!(weight_used, weight_limit - Weight::from_ref_time(weight_per_key)); // All the keys are removed for val in vals { @@ -2322,7 +2326,7 @@ fn reinstrument_does_charge() { assert!(result2.gas_consumed > result1.gas_consumed); assert_eq!( result2.gas_consumed, - result1.gas_consumed + ::WeightInfo::reinstrument(code_len), + result1.gas_consumed + ::WeightInfo::reinstrument(code_len).ref_time(), ); }); } @@ -2430,7 +2434,7 @@ fn gas_estimation_nested_call_fixed_limit() { let input: Vec = AsRef::<[u8]>::as_ref(&addr_callee) .iter() .cloned() - .chain((GAS_LIMIT / 5).to_le_bytes()) + .chain((GAS_LIMIT / 5).ref_time().to_le_bytes()) .collect(); // Call in order to determine the gas that is required for this call @@ -2454,7 +2458,7 @@ fn gas_estimation_nested_call_fixed_limit() { ALICE, addr_caller, 0, - result.gas_required, + Weight::from_ref_time(result.gas_required), Some(result.storage_deposit.charge_or_zero()), input, false, @@ -2524,7 +2528,7 @@ fn gas_estimation_call_runtime() { ALICE, addr_caller, 0, - result.gas_required, + Weight::from_ref_time(result.gas_required), None, call.encode(), false, diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 61826c7c323aa..659caafa7f0b0 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -218,14 +218,16 @@ impl Token for CodeToken { // contract code. This is why we subtract `T::*::(0)`. We need to do this at this // point because when charging the general weight for calling the contract we not know the // size of the contract. - match *self { + let ref_time_weight = match *self { Reinstrument(len) => T::WeightInfo::reinstrument(len), Load(len) => { let computation = T::WeightInfo::call_with_code_per_byte(len) .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)); - let bandwidth = T::ContractAccessWeight::get().saturating_mul(len.into()); + let bandwidth = T::ContractAccessWeight::get().scalar_saturating_mul(len as u64); computation.max(bandwidth) }, - } + }; + + ref_time_weight } } diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 02a360fe86b45..f989c21b00ffc 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -365,7 +365,7 @@ mod tests { events: Default::default(), runtime_calls: Default::default(), schedule: Default::default(), - gas_meter: GasMeter::new(10_000_000_000), + gas_meter: GasMeter::new(Weight::from_ref_time(10_000_000_000)), debug_buffer: Default::default(), ecdsa_recover: Default::default(), } @@ -406,7 +406,7 @@ mod tests { code_hash, value, data: data.to_vec(), - gas_left: gas_limit, + gas_left: gas_limit.ref_time(), salt: salt.to_vec(), }); Ok(( @@ -520,7 +520,7 @@ mod tests { 16_384 } fn get_weight_price(&self, weight: Weight) -> BalanceOf { - BalanceOf::::from(1312_u32).saturating_mul(weight.into()) + BalanceOf::::from(1312_u32).saturating_mul(weight.ref_time().into()) } fn schedule(&self) -> &Schedule { &self.schedule @@ -1911,7 +1911,7 @@ mod tests { )] ); - assert!(mock_ext.gas_meter.gas_left() > 0); + assert!(mock_ext.gas_meter.gas_left() > Weight::zero()); } const CODE_DEPOSIT_EVENT_MAX_TOPICS: &str = r#" diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 1d5478a5277cd..296f322f494d0 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -327,14 +327,14 @@ impl RuntimeCosts { EcdsaRecovery => s.ecdsa_recover, ChainExtension(amount) => amount, #[cfg(feature = "unstable-interface")] - CallRuntime(weight) => weight, + CallRuntime(weight) => weight.ref_time(), SetCodeHash => s.set_code_hash, EcdsaToEthAddress => s.ecdsa_to_eth_address, }; RuntimeToken { #[cfg(test)] _created_from: *self, - weight, + weight: Weight::from_ref_time(weight), } } } @@ -857,7 +857,7 @@ where self.charge_gas(RuntimeCosts::CallSurchargeTransfer)?; } self.ext.call( - gas, + Weight::from_ref_time(gas), callee, value, input_data, @@ -906,6 +906,7 @@ where salt_ptr: u32, salt_len: u32, ) -> Result { + let gas = Weight::from_ref_time(gas); self.charge_gas(RuntimeCosts::InstantiateBase { input_data_len, salt_len })?; let value: BalanceOf<::T> = self.read_sandbox_memory_as(value_ptr)?; if value > 0u32.into() { @@ -1704,6 +1705,7 @@ pub mod env { out_ptr: u32, out_len_ptr: u32, ) -> Result<(), TrapReason> { + let gas = Weight::from_ref_time(gas); ctx.charge_gas(RuntimeCosts::WeightToFee)?; Ok(ctx.write_sandbox_output( out_ptr, diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 3c90579e65d53..17be3c3da0138 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_contracts. @@ -166,37 +166,37 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - (1_654_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + Weight::from_ref_time(1_654_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (8_564_000 as Weight) + Weight::from_ref_time(8_564_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((868_000 as Weight).saturating_mul(k as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) + .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) } // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 1024]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((1_944_000 as Weight).saturating_mul(q as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_944_000 as RefTimeWeight).scalar_saturating_mul(q as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - (19_016_000 as Weight) + Weight::from_ref_time(19_016_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) @@ -204,11 +204,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - (205_194_000 as Weight) + Weight::from_ref_time(205_194_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(53_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -220,13 +220,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (288_487_000 as Weight) + Weight::from_ref_time(288_487_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((124_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -236,46 +236,46 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - (186_136_000 as Weight) + Weight::from_ref_time(186_136_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (149_232_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(149_232_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - (51_721_000 as Weight) + Weight::from_ref_time(51_721_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((48_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Contracts OwnerInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (30_016_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(30_016_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) fn set_code() -> Weight { - (27_192_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(27_192_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -283,11 +283,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - (206_405_000 as Weight) + Weight::from_ref_time(206_405_000 as RefTimeWeight) // Standard Error: 112_000 - .saturating_add((40_987_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_987_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -295,12 +295,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - (106_220_000 as Weight) + Weight::from_ref_time(106_220_000 as RefTimeWeight) // Standard Error: 710_000 - .saturating_add((307_648_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(307_648_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -308,12 +308,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - (104_498_000 as Weight) + Weight::from_ref_time(104_498_000 as RefTimeWeight) // Standard Error: 633_000 - .saturating_add((368_901_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(368_901_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -321,11 +321,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - (208_696_000 as Weight) + Weight::from_ref_time(208_696_000 as RefTimeWeight) // Standard Error: 101_000 - .saturating_add((44_445_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(44_445_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -333,11 +333,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - (205_612_000 as Weight) + Weight::from_ref_time(205_612_000 as RefTimeWeight) // Standard Error: 68_000 - .saturating_add((17_145_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -345,11 +345,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - (206_947_000 as Weight) + Weight::from_ref_time(206_947_000 as RefTimeWeight) // Standard Error: 107_000 - .saturating_add((40_789_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_789_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -357,11 +357,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - (208_692_000 as Weight) + Weight::from_ref_time(208_692_000 as RefTimeWeight) // Standard Error: 109_000 - .saturating_add((40_600_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_600_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -369,11 +369,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - (209_811_000 as Weight) + Weight::from_ref_time(209_811_000 as RefTimeWeight) // Standard Error: 208_000 - .saturating_add((116_831_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(116_831_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -381,11 +381,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - (207_406_000 as Weight) + Weight::from_ref_time(207_406_000 as RefTimeWeight) // Standard Error: 117_000 - .saturating_add((40_702_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_702_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -393,11 +393,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - (209_260_000 as Weight) + Weight::from_ref_time(209_260_000 as RefTimeWeight) // Standard Error: 130_000 - .saturating_add((40_479_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_479_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -405,11 +405,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - (206_448_000 as Weight) + Weight::from_ref_time(206_448_000 as RefTimeWeight) // Standard Error: 95_000 - .saturating_add((40_134_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_134_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -417,11 +417,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - (206_969_000 as Weight) + Weight::from_ref_time(206_969_000 as RefTimeWeight) // Standard Error: 116_000 - .saturating_add((40_251_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_251_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -430,11 +430,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - (211_611_000 as Weight) + Weight::from_ref_time(211_611_000 as RefTimeWeight) // Standard Error: 175_000 - .saturating_add((98_675_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(98_675_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -442,11 +442,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - (134_484_000 as Weight) + Weight::from_ref_time(134_484_000 as RefTimeWeight) // Standard Error: 57_000 - .saturating_add((19_329_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(19_329_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -454,11 +454,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - (208_556_000 as Weight) + Weight::from_ref_time(208_556_000 as RefTimeWeight) // Standard Error: 125_000 - .saturating_add((40_328_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_328_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -466,11 +466,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - (268_886_000 as Weight) + Weight::from_ref_time(268_886_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((9_627_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(9_627_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -478,9 +478,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 1]`. fn seal_return(_r: u32, ) -> Weight { - (203_591_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(203_591_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -488,11 +488,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - (204_258_000 as Weight) + Weight::from_ref_time(204_258_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((183_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(183_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -502,13 +502,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - (206_625_000 as Weight) + Weight::from_ref_time(206_625_000 as RefTimeWeight) // Standard Error: 672_000 - .saturating_add((59_377_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(59_377_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((4 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((5 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -517,11 +517,11 @@ impl WeightInfo for SubstrateWeight { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - (208_866_000 as Weight) + Weight::from_ref_time(208_866_000 as RefTimeWeight) // Standard Error: 164_000 - .saturating_add((133_438_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(133_438_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -529,11 +529,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - (220_860_000 as Weight) + Weight::from_ref_time(220_860_000 as RefTimeWeight) // Standard Error: 209_000 - .saturating_add((239_951_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(239_951_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -543,15 +543,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (439_782_000 as Weight) + Weight::from_ref_time(439_782_000 as RefTimeWeight) // Standard Error: 1_643_000 - .saturating_add((264_687_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(264_687_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 323_000 - .saturating_add((67_636_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(t as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(t as Weight))) + .saturating_add(Weight::from_ref_time(67_636_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -559,128 +559,128 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - (140_280_000 as Weight) + Weight::from_ref_time(140_280_000 as RefTimeWeight) // Standard Error: 82_000 - .saturating_add((32_717_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(32_717_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - (161_247_000 as Weight) + Weight::from_ref_time(161_247_000 as RefTimeWeight) // Standard Error: 883_000 - .saturating_add((423_997_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(423_997_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (529_247_000 as Weight) + Weight::from_ref_time(529_247_000 as RefTimeWeight) // Standard Error: 2_745_000 - .saturating_add((85_282_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(55 as Weight)) - .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(53 as Weight)) - .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(85_282_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(53 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (529_812_000 as Weight) + Weight::from_ref_time(529_812_000 as RefTimeWeight) // Standard Error: 2_513_000 - .saturating_add((74_554_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(55 as Weight)) - .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(53 as Weight)) - .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(74_554_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(53 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - (184_803_000 as Weight) + Weight::from_ref_time(184_803_000 as RefTimeWeight) // Standard Error: 733_000 - .saturating_add((404_933_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(404_933_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (500_958_000 as Weight) + Weight::from_ref_time(500_958_000 as RefTimeWeight) // Standard Error: 2_980_000 - .saturating_add((75_996_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(55 as Weight)) - .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(52 as Weight)) - .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(75_996_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(52 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - (177_682_000 as Weight) + Weight::from_ref_time(177_682_000 as RefTimeWeight) // Standard Error: 743_000 - .saturating_add((338_172_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(338_172_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (465_285_000 as Weight) + Weight::from_ref_time(465_285_000 as RefTimeWeight) // Standard Error: 2_599_000 - .saturating_add((155_106_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(55 as Weight)) - .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(155_106_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - (179_118_000 as Weight) + Weight::from_ref_time(179_118_000 as RefTimeWeight) // Standard Error: 572_000 - .saturating_add((311_083_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(311_083_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (423_056_000 as Weight) + Weight::from_ref_time(423_056_000 as RefTimeWeight) // Standard Error: 2_037_000 - .saturating_add((69_665_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(54 as Weight)) - .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(69_665_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(54 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - (188_884_000 as Weight) + Weight::from_ref_time(188_884_000 as RefTimeWeight) // Standard Error: 761_000 - .saturating_add((432_781_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(432_781_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (532_408_000 as Weight) + Weight::from_ref_time(532_408_000 as RefTimeWeight) // Standard Error: 3_348_000 - .saturating_add((164_943_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(55 as Weight)) - .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(53 as Weight)) - .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(164_943_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(53 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -688,13 +688,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - (127_181_000 as Weight) + Weight::from_ref_time(127_181_000 as RefTimeWeight) // Standard Error: 1_495_000 - .saturating_add((1_500_589_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(1_500_589_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -702,13 +702,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_803_000 - .saturating_add((14_860_909_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(14_860_909_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -716,11 +716,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 6_045_000 - .saturating_add((14_797_140_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(14_797_140_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -729,15 +729,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (9_196_444_000 as Weight) + Weight::from_ref_time(9_196_444_000 as RefTimeWeight) // Standard Error: 20_486_000 - .saturating_add((1_458_153_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(1_458_153_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 8_000 - .saturating_add((9_718_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(85 as Weight)) - .saturating_add(T::DbWeight::get().reads((81 as Weight).saturating_mul(t as Weight))) - .saturating_add(T::DbWeight::get().writes(81 as Weight)) - .saturating_add(T::DbWeight::get().writes((81 as Weight).saturating_mul(t as Weight))) + .saturating_add(Weight::from_ref_time(9_718_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(85 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((81 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(81 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((81 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -747,13 +747,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 36_253_000 - .saturating_add((21_201_529_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().reads((320 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - .saturating_add(T::DbWeight::get().writes((320 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(21_201_529_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((320 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((320 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: System Account (r:81 w:81) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -764,15 +764,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (12_282_498_000 as Weight) + Weight::from_ref_time(12_282_498_000 as RefTimeWeight) // Standard Error: 48_112_000 - .saturating_add((720_795_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(720_795_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 22_000 - .saturating_add((124_274_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(167 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) - .saturating_add(T::DbWeight::get().writes(165 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(t as Weight))) + .saturating_add(Weight::from_ref_time(124_274_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(167 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(165 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -780,11 +780,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - (203_959_000 as Weight) + Weight::from_ref_time(203_959_000 as RefTimeWeight) // Standard Error: 142_000 - .saturating_add((61_311_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(61_311_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -792,11 +792,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (349_915_000 as Weight) + Weight::from_ref_time(349_915_000 as RefTimeWeight) // Standard Error: 40_000 - .saturating_add((320_652_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(320_652_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -804,11 +804,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - (209_219_000 as Weight) + Weight::from_ref_time(209_219_000 as RefTimeWeight) // Standard Error: 157_000 - .saturating_add((73_728_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(73_728_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -816,11 +816,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (208_860_000 as Weight) + Weight::from_ref_time(208_860_000 as RefTimeWeight) // Standard Error: 25_000 - .saturating_add((245_718_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(245_718_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -828,11 +828,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - (206_165_000 as Weight) + Weight::from_ref_time(206_165_000 as RefTimeWeight) // Standard Error: 138_000 - .saturating_add((51_644_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(51_644_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -840,11 +840,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (255_955_000 as Weight) + Weight::from_ref_time(255_955_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((95_090_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(95_090_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -852,11 +852,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - (208_153_000 as Weight) + Weight::from_ref_time(208_153_000 as RefTimeWeight) // Standard Error: 140_000 - .saturating_add((51_264_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(51_264_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -864,11 +864,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (278_368_000 as Weight) + Weight::from_ref_time(278_368_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((95_006_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(95_006_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -876,11 +876,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - (331_955_000 as Weight) + Weight::from_ref_time(331_955_000 as RefTimeWeight) // Standard Error: 1_155_000 - .saturating_add((3_069_955_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(3_069_955_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -888,11 +888,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - (207_838_000 as Weight) + Weight::from_ref_time(207_838_000 as RefTimeWeight) // Standard Error: 783_000 - .saturating_add((2_058_503_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_058_503_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -901,317 +901,317 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_567_000 - .saturating_add((774_380_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes((79 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(774_380_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - (73_955_000 as Weight) + Weight::from_ref_time(73_955_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((612_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(612_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - (74_057_000 as Weight) + Weight::from_ref_time(74_057_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - (74_137_000 as Weight) + Weight::from_ref_time(74_137_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((1_427_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - (73_844_000 as Weight) + Weight::from_ref_time(73_844_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_773_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_773_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - (73_979_000 as Weight) + Weight::from_ref_time(73_979_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((1_952_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_952_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - (73_924_000 as Weight) + Weight::from_ref_time(73_924_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((941_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(941_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - (73_574_000 as Weight) + Weight::from_ref_time(73_574_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((1_439_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_439_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - (73_343_000 as Weight) + Weight::from_ref_time(73_343_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((1_603_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_603_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_267_000 as Weight) + Weight::from_ref_time(76_267_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - (74_877_000 as Weight) + Weight::from_ref_time(74_877_000 as RefTimeWeight) // Standard Error: 12_000 - .saturating_add((7_144_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(7_144_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - (88_665_000 as Weight) + Weight::from_ref_time(88_665_000 as RefTimeWeight) // Standard Error: 20_000 - .saturating_add((9_142_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(9_142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (98_600_000 as Weight) + Weight::from_ref_time(98_600_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((469_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(Weight::from_ref_time(469_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - (74_555_000 as Weight) + Weight::from_ref_time(74_555_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((624_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(624_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - (74_329_000 as Weight) + Weight::from_ref_time(74_329_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((688_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(688_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - (74_612_000 as Weight) + Weight::from_ref_time(74_612_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((909_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(909_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - (76_906_000 as Weight) + Weight::from_ref_time(76_906_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_192_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_192_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - (76_979_000 as Weight) + Weight::from_ref_time(76_979_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_361_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - (74_370_000 as Weight) + Weight::from_ref_time(74_370_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((661_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(661_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - (73_584_000 as Weight) + Weight::from_ref_time(73_584_000 as RefTimeWeight) // Standard Error: 353_000 - .saturating_add((187_114_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(187_114_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - (74_206_000 as Weight) + Weight::from_ref_time(74_206_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(884_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - (73_992_000 as Weight) + Weight::from_ref_time(73_992_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(893_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - (73_985_000 as Weight) + Weight::from_ref_time(73_985_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((891_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(891_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - (74_117_000 as Weight) + Weight::from_ref_time(74_117_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((901_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(901_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - (73_981_000 as Weight) + Weight::from_ref_time(73_981_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((866_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(866_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - (74_104_000 as Weight) + Weight::from_ref_time(74_104_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((868_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_293_000 as Weight) + Weight::from_ref_time(74_293_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((878_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(878_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - (74_055_000 as Weight) + Weight::from_ref_time(74_055_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - (73_710_000 as Weight) + Weight::from_ref_time(73_710_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - (73_917_000 as Weight) + Weight::from_ref_time(73_917_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_355_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - (74_048_000 as Weight) + Weight::from_ref_time(74_048_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - (74_029_000 as Weight) + Weight::from_ref_time(74_029_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_349_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - (74_267_000 as Weight) + Weight::from_ref_time(74_267_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - (73_952_000 as Weight) + Weight::from_ref_time(73_952_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - (73_851_000 as Weight) + Weight::from_ref_time(73_851_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_368_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - (74_034_000 as Weight) + Weight::from_ref_time(74_034_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_348_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - (73_979_000 as Weight) + Weight::from_ref_time(73_979_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - (74_000_000 as Weight) + Weight::from_ref_time(74_000_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_328_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_328_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - (73_883_000 as Weight) + Weight::from_ref_time(73_883_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_331_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_331_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - (74_216_000 as Weight) + Weight::from_ref_time(74_216_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - (73_989_000 as Weight) + Weight::from_ref_time(73_989_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_998_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_998_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - (73_857_000 as Weight) + Weight::from_ref_time(73_857_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((2_073_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(2_073_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - (73_801_000 as Weight) + Weight::from_ref_time(73_801_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((2_027_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(2_027_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - (74_130_000 as Weight) + Weight::from_ref_time(74_130_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((2_064_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(2_064_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - (74_071_000 as Weight) + Weight::from_ref_time(74_071_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_327_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - (74_201_000 as Weight) + Weight::from_ref_time(74_201_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((1_330_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_330_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - (74_241_000 as Weight) + Weight::from_ref_time(74_241_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_321_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_321_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - (74_331_000 as Weight) + Weight::from_ref_time(74_331_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_347_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - (73_674_000 as Weight) + Weight::from_ref_time(73_674_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_359_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - (73_807_000 as Weight) + Weight::from_ref_time(73_807_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - (73_725_000 as Weight) + Weight::from_ref_time(73_725_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - (73_755_000 as Weight) + Weight::from_ref_time(73_755_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } } @@ -1219,37 +1219,37 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - (1_654_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + Weight::from_ref_time(1_654_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (8_564_000 as Weight) + Weight::from_ref_time(8_564_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((868_000 as Weight).saturating_mul(k as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) + .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) } // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 1024]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((1_944_000 as Weight).saturating_mul(q as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_944_000 as RefTimeWeight).scalar_saturating_mul(q as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - (19_016_000 as Weight) + Weight::from_ref_time(19_016_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((49_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) @@ -1257,11 +1257,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - (205_194_000 as Weight) + Weight::from_ref_time(205_194_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((53_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(53_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -1273,13 +1273,13 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (288_487_000 as Weight) + Weight::from_ref_time(288_487_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((124_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -1289,46 +1289,46 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - (186_136_000 as Weight) + Weight::from_ref_time(186_136_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - (149_232_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(149_232_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - (51_721_000 as Weight) + Weight::from_ref_time(51_721_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((48_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Contracts OwnerInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - (30_016_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(30_016_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) fn set_code() -> Weight { - (27_192_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(27_192_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1336,11 +1336,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - (206_405_000 as Weight) + Weight::from_ref_time(206_405_000 as RefTimeWeight) // Standard Error: 112_000 - .saturating_add((40_987_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_987_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1348,12 +1348,12 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - (106_220_000 as Weight) + Weight::from_ref_time(106_220_000 as RefTimeWeight) // Standard Error: 710_000 - .saturating_add((307_648_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(307_648_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1361,12 +1361,12 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - (104_498_000 as Weight) + Weight::from_ref_time(104_498_000 as RefTimeWeight) // Standard Error: 633_000 - .saturating_add((368_901_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(368_901_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1374,11 +1374,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - (208_696_000 as Weight) + Weight::from_ref_time(208_696_000 as RefTimeWeight) // Standard Error: 101_000 - .saturating_add((44_445_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(44_445_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1386,11 +1386,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - (205_612_000 as Weight) + Weight::from_ref_time(205_612_000 as RefTimeWeight) // Standard Error: 68_000 - .saturating_add((17_145_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1398,11 +1398,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - (206_947_000 as Weight) + Weight::from_ref_time(206_947_000 as RefTimeWeight) // Standard Error: 107_000 - .saturating_add((40_789_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_789_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1410,11 +1410,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - (208_692_000 as Weight) + Weight::from_ref_time(208_692_000 as RefTimeWeight) // Standard Error: 109_000 - .saturating_add((40_600_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_600_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1422,11 +1422,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - (209_811_000 as Weight) + Weight::from_ref_time(209_811_000 as RefTimeWeight) // Standard Error: 208_000 - .saturating_add((116_831_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(116_831_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1434,11 +1434,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - (207_406_000 as Weight) + Weight::from_ref_time(207_406_000 as RefTimeWeight) // Standard Error: 117_000 - .saturating_add((40_702_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_702_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1446,11 +1446,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - (209_260_000 as Weight) + Weight::from_ref_time(209_260_000 as RefTimeWeight) // Standard Error: 130_000 - .saturating_add((40_479_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_479_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1458,11 +1458,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - (206_448_000 as Weight) + Weight::from_ref_time(206_448_000 as RefTimeWeight) // Standard Error: 95_000 - .saturating_add((40_134_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_134_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1470,11 +1470,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - (206_969_000 as Weight) + Weight::from_ref_time(206_969_000 as RefTimeWeight) // Standard Error: 116_000 - .saturating_add((40_251_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_251_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1483,11 +1483,11 @@ impl WeightInfo for () { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - (211_611_000 as Weight) + Weight::from_ref_time(211_611_000 as RefTimeWeight) // Standard Error: 175_000 - .saturating_add((98_675_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(98_675_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1495,11 +1495,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - (134_484_000 as Weight) + Weight::from_ref_time(134_484_000 as RefTimeWeight) // Standard Error: 57_000 - .saturating_add((19_329_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(19_329_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1507,11 +1507,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - (208_556_000 as Weight) + Weight::from_ref_time(208_556_000 as RefTimeWeight) // Standard Error: 125_000 - .saturating_add((40_328_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(40_328_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1519,11 +1519,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - (268_886_000 as Weight) + Weight::from_ref_time(268_886_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((9_627_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(9_627_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1531,9 +1531,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 1]`. fn seal_return(_r: u32, ) -> Weight { - (203_591_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(203_591_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1541,11 +1541,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - (204_258_000 as Weight) + Weight::from_ref_time(204_258_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((183_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(183_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1555,13 +1555,13 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - (206_625_000 as Weight) + Weight::from_ref_time(206_625_000 as RefTimeWeight) // Standard Error: 672_000 - .saturating_add((59_377_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(59_377_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((4 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((5 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1570,11 +1570,11 @@ impl WeightInfo for () { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - (208_866_000 as Weight) + Weight::from_ref_time(208_866_000 as RefTimeWeight) // Standard Error: 164_000 - .saturating_add((133_438_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(133_438_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1582,11 +1582,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - (220_860_000 as Weight) + Weight::from_ref_time(220_860_000 as RefTimeWeight) // Standard Error: 209_000 - .saturating_add((239_951_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(239_951_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1596,15 +1596,15 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (439_782_000 as Weight) + Weight::from_ref_time(439_782_000 as RefTimeWeight) // Standard Error: 1_643_000 - .saturating_add((264_687_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(264_687_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 323_000 - .saturating_add((67_636_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(t as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(t as Weight))) + .saturating_add(Weight::from_ref_time(67_636_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1612,128 +1612,128 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - (140_280_000 as Weight) + Weight::from_ref_time(140_280_000 as RefTimeWeight) // Standard Error: 82_000 - .saturating_add((32_717_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(32_717_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - (161_247_000 as Weight) + Weight::from_ref_time(161_247_000 as RefTimeWeight) // Standard Error: 883_000 - .saturating_add((423_997_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(423_997_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - (529_247_000 as Weight) + Weight::from_ref_time(529_247_000 as RefTimeWeight) // Standard Error: 2_745_000 - .saturating_add((85_282_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(55 as Weight)) - .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(53 as Weight)) - .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(85_282_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(53 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - (529_812_000 as Weight) + Weight::from_ref_time(529_812_000 as RefTimeWeight) // Standard Error: 2_513_000 - .saturating_add((74_554_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(55 as Weight)) - .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(53 as Weight)) - .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(74_554_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(53 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - (184_803_000 as Weight) + Weight::from_ref_time(184_803_000 as RefTimeWeight) // Standard Error: 733_000 - .saturating_add((404_933_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(404_933_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - (500_958_000 as Weight) + Weight::from_ref_time(500_958_000 as RefTimeWeight) // Standard Error: 2_980_000 - .saturating_add((75_996_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(55 as Weight)) - .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(52 as Weight)) - .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(75_996_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(52 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - (177_682_000 as Weight) + Weight::from_ref_time(177_682_000 as RefTimeWeight) // Standard Error: 743_000 - .saturating_add((338_172_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(338_172_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (465_285_000 as Weight) + Weight::from_ref_time(465_285_000 as RefTimeWeight) // Standard Error: 2_599_000 - .saturating_add((155_106_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(55 as Weight)) - .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(155_106_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - (179_118_000 as Weight) + Weight::from_ref_time(179_118_000 as RefTimeWeight) // Standard Error: 572_000 - .saturating_add((311_083_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(311_083_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - (423_056_000 as Weight) + Weight::from_ref_time(423_056_000 as RefTimeWeight) // Standard Error: 2_037_000 - .saturating_add((69_665_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(54 as Weight)) - .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(69_665_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(54 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - (188_884_000 as Weight) + Weight::from_ref_time(188_884_000 as RefTimeWeight) // Standard Error: 761_000 - .saturating_add((432_781_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(432_781_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - (532_408_000 as Weight) + Weight::from_ref_time(532_408_000 as RefTimeWeight) // Standard Error: 3_348_000 - .saturating_add((164_943_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(55 as Weight)) - .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(53 as Weight)) - .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(164_943_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(53 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1741,13 +1741,13 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - (127_181_000 as Weight) + Weight::from_ref_time(127_181_000 as RefTimeWeight) // Standard Error: 1_495_000 - .saturating_add((1_500_589_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(1_500_589_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1755,13 +1755,13 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_803_000 - .saturating_add((14_860_909_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((80 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((80 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(14_860_909_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1769,11 +1769,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 6_045_000 - .saturating_add((14_797_140_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(14_797_140_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -1782,15 +1782,15 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - (9_196_444_000 as Weight) + Weight::from_ref_time(9_196_444_000 as RefTimeWeight) // Standard Error: 20_486_000 - .saturating_add((1_458_153_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(1_458_153_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 8_000 - .saturating_add((9_718_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(RocksDbWeight::get().reads(85 as Weight)) - .saturating_add(RocksDbWeight::get().reads((81 as Weight).saturating_mul(t as Weight))) - .saturating_add(RocksDbWeight::get().writes(81 as Weight)) - .saturating_add(RocksDbWeight::get().writes((81 as Weight).saturating_mul(t as Weight))) + .saturating_add(Weight::from_ref_time(9_718_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(85 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((81 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(81 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((81 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1800,13 +1800,13 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 36_253_000 - .saturating_add((21_201_529_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().reads((320 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes((320 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(21_201_529_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((320 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((320 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: System Account (r:81 w:81) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -1817,15 +1817,15 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - (12_282_498_000 as Weight) + Weight::from_ref_time(12_282_498_000 as RefTimeWeight) // Standard Error: 48_112_000 - .saturating_add((720_795_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(720_795_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 22_000 - .saturating_add((124_274_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(167 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(t as Weight))) - .saturating_add(RocksDbWeight::get().writes(165 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(t as Weight))) + .saturating_add(Weight::from_ref_time(124_274_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(167 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(165 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1833,11 +1833,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - (203_959_000 as Weight) + Weight::from_ref_time(203_959_000 as RefTimeWeight) // Standard Error: 142_000 - .saturating_add((61_311_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(61_311_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1845,11 +1845,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (349_915_000 as Weight) + Weight::from_ref_time(349_915_000 as RefTimeWeight) // Standard Error: 40_000 - .saturating_add((320_652_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(320_652_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1857,11 +1857,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - (209_219_000 as Weight) + Weight::from_ref_time(209_219_000 as RefTimeWeight) // Standard Error: 157_000 - .saturating_add((73_728_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(73_728_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1869,11 +1869,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (208_860_000 as Weight) + Weight::from_ref_time(208_860_000 as RefTimeWeight) // Standard Error: 25_000 - .saturating_add((245_718_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(245_718_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1881,11 +1881,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - (206_165_000 as Weight) + Weight::from_ref_time(206_165_000 as RefTimeWeight) // Standard Error: 138_000 - .saturating_add((51_644_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(51_644_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1893,11 +1893,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (255_955_000 as Weight) + Weight::from_ref_time(255_955_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((95_090_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(95_090_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1905,11 +1905,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - (208_153_000 as Weight) + Weight::from_ref_time(208_153_000 as RefTimeWeight) // Standard Error: 140_000 - .saturating_add((51_264_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(51_264_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1917,11 +1917,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (278_368_000 as Weight) + Weight::from_ref_time(278_368_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((95_006_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(95_006_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1929,11 +1929,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - (331_955_000 as Weight) + Weight::from_ref_time(331_955_000 as RefTimeWeight) // Standard Error: 1_155_000 - .saturating_add((3_069_955_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(3_069_955_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1941,11 +1941,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - (207_838_000 as Weight) + Weight::from_ref_time(207_838_000 as RefTimeWeight) // Standard Error: 783_000 - .saturating_add((2_058_503_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_058_503_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1954,316 +1954,316 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_567_000 - .saturating_add((774_380_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads((79 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes((79 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(774_380_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - (73_955_000 as Weight) + Weight::from_ref_time(73_955_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((612_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(612_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - (74_057_000 as Weight) + Weight::from_ref_time(74_057_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - (74_137_000 as Weight) + Weight::from_ref_time(74_137_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((1_427_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - (73_844_000 as Weight) + Weight::from_ref_time(73_844_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_773_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_773_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - (73_979_000 as Weight) + Weight::from_ref_time(73_979_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((1_952_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_952_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - (73_924_000 as Weight) + Weight::from_ref_time(73_924_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((941_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(941_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - (73_574_000 as Weight) + Weight::from_ref_time(73_574_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((1_439_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_439_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - (73_343_000 as Weight) + Weight::from_ref_time(73_343_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((1_603_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_603_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - (76_267_000 as Weight) + Weight::from_ref_time(76_267_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(e as Weight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - (74_877_000 as Weight) + Weight::from_ref_time(74_877_000 as RefTimeWeight) // Standard Error: 12_000 - .saturating_add((7_144_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(7_144_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - (88_665_000 as Weight) + Weight::from_ref_time(88_665_000 as RefTimeWeight) // Standard Error: 20_000 - .saturating_add((9_142_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(9_142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (98_600_000 as Weight) + Weight::from_ref_time(98_600_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((469_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(Weight::from_ref_time(469_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - (74_555_000 as Weight) + Weight::from_ref_time(74_555_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((624_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(624_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - (74_329_000 as Weight) + Weight::from_ref_time(74_329_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((688_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(688_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - (74_612_000 as Weight) + Weight::from_ref_time(74_612_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((909_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(909_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - (76_906_000 as Weight) + Weight::from_ref_time(76_906_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_192_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_192_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - (76_979_000 as Weight) + Weight::from_ref_time(76_979_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_361_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_361_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - (74_370_000 as Weight) + Weight::from_ref_time(74_370_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((661_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(661_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - (73_584_000 as Weight) + Weight::from_ref_time(73_584_000 as RefTimeWeight) // Standard Error: 353_000 - .saturating_add((187_114_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(187_114_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - (74_206_000 as Weight) + Weight::from_ref_time(74_206_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((884_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(884_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - (73_992_000 as Weight) + Weight::from_ref_time(73_992_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((893_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(893_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - (73_985_000 as Weight) + Weight::from_ref_time(73_985_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((891_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(891_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - (74_117_000 as Weight) + Weight::from_ref_time(74_117_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((901_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(901_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - (73_981_000 as Weight) + Weight::from_ref_time(73_981_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((866_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(866_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - (74_104_000 as Weight) + Weight::from_ref_time(74_104_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((868_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - (74_293_000 as Weight) + Weight::from_ref_time(74_293_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((878_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(878_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - (74_055_000 as Weight) + Weight::from_ref_time(74_055_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - (73_710_000 as Weight) + Weight::from_ref_time(73_710_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - (73_917_000 as Weight) + Weight::from_ref_time(73_917_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_355_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_355_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - (74_048_000 as Weight) + Weight::from_ref_time(74_048_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - (74_029_000 as Weight) + Weight::from_ref_time(74_029_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_349_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_349_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - (74_267_000 as Weight) + Weight::from_ref_time(74_267_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - (73_952_000 as Weight) + Weight::from_ref_time(73_952_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_350_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - (73_851_000 as Weight) + Weight::from_ref_time(73_851_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_368_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_368_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - (74_034_000 as Weight) + Weight::from_ref_time(74_034_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_348_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_348_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - (73_979_000 as Weight) + Weight::from_ref_time(73_979_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((1_353_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - (74_000_000 as Weight) + Weight::from_ref_time(74_000_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_328_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_328_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - (73_883_000 as Weight) + Weight::from_ref_time(73_883_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_331_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_331_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - (74_216_000 as Weight) + Weight::from_ref_time(74_216_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((1_324_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - (73_989_000 as Weight) + Weight::from_ref_time(73_989_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_998_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_998_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - (73_857_000 as Weight) + Weight::from_ref_time(73_857_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((2_073_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(2_073_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - (73_801_000 as Weight) + Weight::from_ref_time(73_801_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((2_027_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(2_027_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - (74_130_000 as Weight) + Weight::from_ref_time(74_130_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((2_064_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(2_064_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - (74_071_000 as Weight) + Weight::from_ref_time(74_071_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_327_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_327_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - (74_201_000 as Weight) + Weight::from_ref_time(74_201_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((1_330_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_330_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - (74_241_000 as Weight) + Weight::from_ref_time(74_241_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_321_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_321_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - (74_331_000 as Weight) + Weight::from_ref_time(74_331_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add((1_347_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_347_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - (73_674_000 as Weight) + Weight::from_ref_time(73_674_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_359_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_359_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - (73_807_000 as Weight) + Weight::from_ref_time(73_807_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - (73_725_000 as Weight) + Weight::from_ref_time(73_725_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_358_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - (73_755_000 as Weight) + Weight::from_ref_time(73_755_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((1_360_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) } } diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index 9eb7f679efca3..cbd2b0619ac2b 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -22,6 +22,7 @@ use std::collections::BTreeMap; use frame_support::{ assert_noop, assert_ok, parameter_types, traits::{ConstU32, ConstU64, Contains, Polling, VoteTally}, + weights::Weight, }; use sp_core::H256; use sp_runtime::{ @@ -57,7 +58,7 @@ impl Contains for BaseFilter { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1_000_000); + frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(1_000_000)); } impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index 330d02755cb8b..10c5c975a81f1 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_conviction_voting. @@ -62,9 +62,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_new() -> Weight { - (148_804_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(148_804_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: ConvictionVoting VotingFor (r:1 w:1) @@ -72,24 +72,24 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_existing() -> Weight { - (313_333_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(313_333_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn remove_vote() -> Weight { - (300_591_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(300_591_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:0) fn remove_other_vote() -> Weight { - (53_887_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(53_887_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: ConvictionVoting VotingFor (r:2 w:2) // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) @@ -97,33 +97,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn delegate(r: u32, ) -> Weight { - (51_518_000 as Weight) + Weight::from_ref_time(51_518_000 as RefTimeWeight) // Standard Error: 83_000 - .saturating_add((27_235_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(27_235_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: ConvictionVoting VotingFor (r:2 w:2) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn undelegate(r: u32, ) -> Weight { - (37_885_000 as Weight) + Weight::from_ref_time(37_885_000 as RefTimeWeight) // Standard Error: 75_000 - .saturating_add((24_395_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(24_395_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn unlock() -> Weight { - (67_703_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(67_703_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } } @@ -135,9 +135,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_new() -> Weight { - (148_804_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(148_804_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: ConvictionVoting VotingFor (r:1 w:1) @@ -145,24 +145,24 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_existing() -> Weight { - (313_333_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(313_333_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn remove_vote() -> Weight { - (300_591_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(300_591_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:0) fn remove_other_vote() -> Weight { - (53_887_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(53_887_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: ConvictionVoting VotingFor (r:2 w:2) // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) @@ -170,32 +170,32 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn delegate(r: u32, ) -> Weight { - (51_518_000 as Weight) + Weight::from_ref_time(51_518_000 as RefTimeWeight) // Standard Error: 83_000 - .saturating_add((27_235_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(27_235_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: ConvictionVoting VotingFor (r:2 w:2) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn undelegate(r: u32, ) -> Weight { - (37_885_000 as Weight) + Weight::from_ref_time(37_885_000 as RefTimeWeight) // Standard Error: 75_000 - .saturating_add((24_395_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(24_395_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn unlock() -> Weight { - (67_703_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(67_703_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } } diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index a347f47efe121..5bbc97fa16e30 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1765,7 +1765,7 @@ impl Pallet { /// # fn begin_block(now: T::BlockNumber) -> Weight { let max_block_weight = T::BlockWeights::get().max_block; - let mut weight = 0; + let mut weight = Weight::new(); let next = Self::lowest_unbaked(); let last = Self::referendum_count(); diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 0fe83a07610d1..def8f84067909 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -78,7 +78,7 @@ impl Contains for BaseFilter { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1_000_000); + frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(1_000_000)); } impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 45686b43f7152..351ed42cca8e9 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_democracy. @@ -80,44 +80,44 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (48_328_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(48_328_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (30_923_000 as Weight) + Weight::from_ref_time(30_923_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((142_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (40_345_000 as Weight) + Weight::from_ref_time(40_345_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((140_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(140_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (39_853_000 as Weight) + Weight::from_ref_time(39_853_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((150_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (19_364_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(19_364_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy NextExternal (r:1 w:1) @@ -126,82 +126,82 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (57_708_000 as Weight) + Weight::from_ref_time(57_708_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((192_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (10_714_000 as Weight) + Weight::from_ref_time(10_714_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((33_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (3_697_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_697_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (3_831_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_831_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (20_271_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(20_271_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (21_319_000 as Weight) + Weight::from_ref_time(21_319_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (43_960_000 as Weight) + Weight::from_ref_time(43_960_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((184_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(184_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (13_475_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(13_475_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (24_320_000 as Weight) + Weight::from_ref_time(24_320_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((560_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(560_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (3_428_000 as Weight) + Weight::from_ref_time(3_428_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((3_171_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(3_171_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) @@ -210,103 +210,103 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - (7_867_000 as Weight) + Weight::from_ref_time(7_867_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((3_177_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(3_177_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy VotingOf (r:3 w:3) // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (37_902_000 as Weight) + Weight::from_ref_time(37_902_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((4_335_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(4_335_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (21_272_000 as Weight) + Weight::from_ref_time(21_272_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((4_351_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(4_351_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (4_913_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(4_913_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (27_986_000 as Weight) + Weight::from_ref_time(27_986_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (20_058_000 as Weight) + Weight::from_ref_time(20_058_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (28_619_000 as Weight) + Weight::from_ref_time(28_619_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (26_619_000 as Weight) + Weight::from_ref_time(26_619_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((56_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (25_373_000 as Weight) + Weight::from_ref_time(25_373_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (15_961_000 as Weight) + Weight::from_ref_time(15_961_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (15_992_000 as Weight) + Weight::from_ref_time(15_992_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((113_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(113_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } } @@ -317,44 +317,44 @@ impl WeightInfo for () { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - (48_328_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(48_328_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - (30_923_000 as Weight) + Weight::from_ref_time(30_923_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((142_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - (40_345_000 as Weight) + Weight::from_ref_time(40_345_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((140_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(140_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - (39_853_000 as Weight) + Weight::from_ref_time(39_853_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((150_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - (19_364_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(19_364_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy NextExternal (r:1 w:1) @@ -363,82 +363,82 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - (57_708_000 as Weight) + Weight::from_ref_time(57_708_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((192_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - (10_714_000 as Weight) + Weight::from_ref_time(10_714_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((33_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - (3_697_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_697_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - (3_831_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_831_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - (20_271_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(20_271_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - (21_319_000 as Weight) + Weight::from_ref_time(21_319_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - (43_960_000 as Weight) + Weight::from_ref_time(43_960_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((184_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(184_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - (13_475_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(13_475_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - (24_320_000 as Weight) + Weight::from_ref_time(24_320_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((560_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(560_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - (3_428_000 as Weight) + Weight::from_ref_time(3_428_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((3_171_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(3_171_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) @@ -447,102 +447,102 @@ impl WeightInfo for () { // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - (7_867_000 as Weight) + Weight::from_ref_time(7_867_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((3_177_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(3_177_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy VotingOf (r:3 w:3) // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - (37_902_000 as Weight) + Weight::from_ref_time(37_902_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((4_335_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(4_335_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - (21_272_000 as Weight) + Weight::from_ref_time(21_272_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((4_351_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(4_351_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - (4_913_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(4_913_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - (27_986_000 as Weight) + Weight::from_ref_time(27_986_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - (20_058_000 as Weight) + Weight::from_ref_time(20_058_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - (28_619_000 as Weight) + Weight::from_ref_time(28_619_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - (26_619_000 as Weight) + Weight::from_ref_time(26_619_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((56_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - (25_373_000 as Weight) + Weight::from_ref_time(25_373_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - (15_961_000 as Weight) + Weight::from_ref_time(15_961_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - (15_992_000 as Weight) + Weight::from_ref_time(15_992_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((113_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(113_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } } diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index e1d3cb8ed5dee..906de8a6c9d20 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -234,7 +234,6 @@ use frame_election_provider_support::{ ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolution, }; use frame_support::{ - dispatch::DispatchResultWithPostInfo, ensure, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, weights::{DispatchClass, Weight}, @@ -877,7 +876,7 @@ pub mod pallet { origin: OriginFor, raw_solution: Box>>, witness: SolutionOrSnapshotSize, - ) -> DispatchResultWithPostInfo { + ) -> DispatchResult { ensure_none(origin)?; let error_message = "Invalid unsigned submission must produce invalid block and \ deprive validator from their authoring reward."; @@ -905,7 +904,7 @@ pub mod pallet { prev_ejected: ejected_a_solution, }); - Ok(None.into()) + Ok(()) } /// Set a new value for `MinimumUntrustedScore`. @@ -992,7 +991,7 @@ pub mod pallet { let deposit = Self::deposit_for(&raw_solution, size); let call_fee = { let call = Call::submit { raw_solution: raw_solution.clone() }; - T::EstimateCallFee::estimate_call_fee(&call, None.into()) + T::EstimateCallFee::estimate_call_fee(&call, None::.into()) }; let submission = SignedSubmission { diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 7eff70b47eba5..72b3ec9764079 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -349,9 +349,11 @@ impl MinerConfig for Runtime { fn solution_weight(v: u32, t: u32, a: u32, d: u32) -> Weight { match MockWeightInfo::get() { - MockedWeightInfo::Basic => - (10 as Weight).saturating_add((5 as Weight).saturating_mul(a as Weight)), - MockedWeightInfo::Complex => (0 * v + 0 * t + 1000 * a + 0 * d) as Weight, + MockedWeightInfo::Basic => Weight::from_ref_time( + (10 as u64).saturating_add((5 as u64).saturating_mul(a as u64)), + ), + MockedWeightInfo::Complex => + Weight::from_ref_time((0 * v + 0 * t + 1000 * a + 0 * d) as u64), MockedWeightInfo::Real => <() as multi_phase::weights::WeightInfo>::feasibility_check(v, t, a, d), } diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index eca75139f925a..b9abfdfba14fb 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -514,8 +514,8 @@ impl Pallet { let feasibility_weight = Self::solution_weight_of(raw_solution, size); let len_deposit = T::SignedDepositByte::get().saturating_mul(encoded_len); - let weight_deposit = - T::SignedDepositWeight::get().saturating_mul(feasibility_weight.saturated_into()); + let weight_deposit = T::SignedDepositWeight::get() + .saturating_mul(feasibility_weight.ref_time().saturated_into()); T::SignedDepositBase::get() .saturating_add(len_deposit) @@ -957,7 +957,7 @@ mod tests { #[test] fn cannot_consume_too_much_future_weight() { ExtBuilder::default() - .signed_weight(40) + .signed_weight(Weight::from_ref_time(40)) .mock_weight_info(MockedWeightInfo::Basic) .build_and_execute(|| { roll_to(15); @@ -971,13 +971,13 @@ mod tests { raw.solution.unique_targets().len() as u32, ); // default solution will have 5 edges (5 * 5 + 10) - assert_eq!(solution_weight, 35); + assert_eq!(solution_weight, Weight::from_ref_time(35)); assert_eq!(raw.solution.voter_count(), 5); - assert_eq!(::SignedMaxWeight::get(), 40); + assert_eq!(::SignedMaxWeight::get(), Weight::from_ref_time(40)); assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(raw.clone()))); - ::set(30); + ::set(Weight::from_ref_time(30)); // note: resubmitting the same solution is technically okay as long as the queue has // space. diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index de25355f0ca5b..8ef7d87473159 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -699,54 +699,153 @@ mod max_weight { fn find_max_voter_binary_search_works() { let w = SolutionOrSnapshotSize { voters: 10, targets: 0 }; MockWeightInfo::set(crate::mock::MockedWeightInfo::Complex); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 0), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 999), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1000), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1001), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1990), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1999), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2000), 2); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2001), 2); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2010), 2); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2990), 2); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2999), 2); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 3000), 3); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 3333), 3); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 5500), 5); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 7777), 7); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 9999), 9); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 10_000), 10); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 10_999), 10); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 11_000), 10); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 22_000), 10); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::zero()), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1)), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(999)), 0); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1000)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1001)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1990)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1999)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2000)), + 2 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2001)), + 2 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2010)), + 2 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2990)), + 2 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2999)), + 2 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3000)), + 3 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3333)), + 3 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(5500)), + 5 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(7777)), + 7 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(9999)), + 9 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(10_000)), + 10 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(10_999)), + 10 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(11_000)), + 10 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(22_000)), + 10 + ); let w = SolutionOrSnapshotSize { voters: 1, targets: 0 }; - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 0), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 999), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1000), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1001), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1990), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1999), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2000), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2001), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2010), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 3333), 1); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(0)), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1)), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(999)), 0); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1000)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1001)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1990)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1999)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2000)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2001)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2010)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3333)), + 1 + ); let w = SolutionOrSnapshotSize { voters: 2, targets: 0 }; - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 0), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 999), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1000), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1001), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 1999), 1); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2000), 2); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2001), 2); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 2010), 2); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, 3333), 2); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(0)), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1)), 0); + assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(999)), 0); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1000)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1001)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1999)), + 1 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2000)), + 2 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2001)), + 2 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2010)), + 2 + ); + assert_eq!( + Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3333)), + 2 + ); } } @@ -1024,7 +1123,7 @@ mod tests { #[test] fn miner_trims_weight() { ExtBuilder::default() - .miner_weight(100) + .miner_weight(Weight::from_ref_time(100)) .mock_weight_info(crate::mock::MockedWeightInfo::Basic) .build_and_execute(|| { roll_to(25); @@ -1038,11 +1137,11 @@ mod tests { raw.solution.unique_targets().len() as u32, ); // default solution will have 5 edges (5 * 5 + 10) - assert_eq!(solution_weight, 35); + assert_eq!(solution_weight, Weight::from_ref_time(35)); assert_eq!(raw.solution.voter_count(), 5); // now reduce the max weight - ::set(25); + ::set(Weight::from_ref_time(25)); let (raw, witness) = MultiPhase::mine_solution().unwrap(); let solution_weight = ::solution_weight( @@ -1052,7 +1151,7 @@ mod tests { raw.solution.unique_targets().len() as u32, ); // default solution will have 5 edges (5 * 5 + 10) - assert_eq!(solution_weight, 25); + assert_eq!(solution_weight, Weight::from_ref_time(25)); assert_eq!(raw.solution.voter_count(), 3); }) } diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 68ce00dd0de32..7ceb4a20e042a 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_election_provider_multi_phase. @@ -68,46 +68,46 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (13_495_000 as Weight) - .saturating_add(T::DbWeight::get().reads(8 as Weight)) + Weight::from_ref_time(13_495_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (14_114_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(14_114_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (13_756_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(13_756_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (28_467_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(28_467_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (21_991_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(21_991_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (3_186_000 as Weight) + Weight::from_ref_time(3_186_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((202_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(202_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add((60_000 as Weight).saturating_mul(t as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(60_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) @@ -119,13 +119,13 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (137_653_000 as Weight) + Weight::from_ref_time(137_653_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((640_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(640_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 6_000 - .saturating_add((48_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(8 as Weight)) + .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(8 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) @@ -134,9 +134,9 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit() -> Weight { - (49_313_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(49_313_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: ElectionProviderMultiPhase Round (r:1 w:0) @@ -146,33 +146,33 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((867_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 7_000 - .saturating_add((107_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add((6_907_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(6_907_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 18_000 - .saturating_add((1_427_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((844_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(844_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 5_000 - .saturating_add((150_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 8_000 - .saturating_add((5_421_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(5_421_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 13_000 - .saturating_add((1_167_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(Weight::from_ref_time(1_167_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) } } @@ -187,46 +187,46 @@ impl WeightInfo for () { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - (13_495_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(8 as Weight)) + Weight::from_ref_time(13_495_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - (14_114_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(14_114_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - (13_756_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(13_756_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - (28_467_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(28_467_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - (21_991_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(21_991_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - (3_186_000 as Weight) + Weight::from_ref_time(3_186_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((202_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(202_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add((60_000 as Weight).saturating_mul(t as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(60_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) @@ -238,13 +238,13 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - (137_653_000 as Weight) + Weight::from_ref_time(137_653_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((640_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(640_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 6_000 - .saturating_add((48_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(8 as Weight)) + .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(8 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) @@ -253,9 +253,9 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit() -> Weight { - (49_313_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(49_313_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: ElectionProviderMultiPhase Round (r:1 w:0) @@ -265,32 +265,32 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((867_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 7_000 - .saturating_add((107_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add((6_907_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(6_907_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 18_000 - .saturating_add((1_427_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((844_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(844_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 5_000 - .saturating_add((150_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 8_000 - .saturating_add((5_421_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(5_421_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 13_000 - .saturating_add((1_167_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(Weight::from_ref_time(1_167_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) } } diff --git a/frame/election-provider-support/src/weights.rs b/frame/election-provider-support/src/weights.rs index c603b196519b5..4f9e47b09a4da 100644 --- a/frame/election-provider-support/src/weights.rs +++ b/frame/election-provider-support/src/weights.rs @@ -40,7 +40,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_election_provider_support_benchmarking. @@ -53,43 +53,43 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 667_000 - .saturating_add((32_973_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(32_973_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 1_334_000 - .saturating_add((1_334_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(1_334_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 60_644_000 - .saturating_add((2_636_364_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(Weight::from_ref_time(2_636_364_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) } fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 73_000 - .saturating_add((21_073_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(21_073_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 146_000 - .saturating_add((65_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(65_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 6_649_000 - .saturating_add((1_711_424_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(Weight::from_ref_time(1_711_424_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) } } // For backwards compatibility and tests impl WeightInfo for () { fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 667_000 - .saturating_add((32_973_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(32_973_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 1_334_000 - .saturating_add((1_334_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(1_334_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 60_644_000 - .saturating_add((2_636_364_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(Weight::from_ref_time(2_636_364_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) } fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 73_000 - .saturating_add((21_073_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(21_073_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 146_000 - .saturating_add((65_000 as Weight).saturating_mul(t as Weight)) + .saturating_add(Weight::from_ref_time(65_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) // Standard Error: 6_649_000 - .saturating_add((1_711_424_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(Weight::from_ref_time(1_711_424_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) } } diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 1076ae77fbdda..539e90d0179ff 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -279,7 +279,7 @@ pub mod pallet { if !term_duration.is_zero() && (n % term_duration).is_zero() { Self::do_phragmen() } else { - 0 + Weight::zero() } } } @@ -363,7 +363,7 @@ pub mod pallet { T::Currency::set_lock(T::PalletId::get(), &who, locked_stake, WithdrawReasons::all()); Voting::::insert(&who, Voter { votes, deposit: new_deposit, stake: locked_stake }); - Ok(None.into()) + Ok(None::.into()) } /// Remove `origin` as a voter. @@ -372,11 +372,11 @@ pub mod pallet { /// /// The dispatch origin of this call must be signed and be a voter. #[pallet::weight(T::WeightInfo::remove_voter())] - pub fn remove_voter(origin: OriginFor) -> DispatchResultWithPostInfo { + pub fn remove_voter(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; ensure!(Self::is_voter(&who), Error::::MustBeVoter); Self::do_remove_voter(&who); - Ok(None.into()) + Ok(()) } /// Submit oneself for candidacy. A fixed amount of deposit is recorded. @@ -398,7 +398,7 @@ pub mod pallet { pub fn submit_candidacy( origin: OriginFor, #[pallet::compact] candidate_count: u32, - ) -> DispatchResultWithPostInfo { + ) -> DispatchResult { let who = ensure_signed(origin)?; let actual_count = >::decode_len().unwrap_or(0) as u32; @@ -417,7 +417,7 @@ pub mod pallet { .map_err(|_| Error::::InsufficientCandidateFunds)?; >::mutate(|c| c.insert(index, (who, T::CandidacyBond::get()))); - Ok(None.into()) + Ok(()) } /// Renounce one's intention to be a candidate for the next election round. 3 potential @@ -443,10 +443,7 @@ pub mod pallet { Renouncing::Member => T::WeightInfo::renounce_candidacy_members(), Renouncing::RunnerUp => T::WeightInfo::renounce_candidacy_runners_up(), })] - pub fn renounce_candidacy( - origin: OriginFor, - renouncing: Renouncing, - ) -> DispatchResultWithPostInfo { + pub fn renounce_candidacy(origin: OriginFor, renouncing: Renouncing) -> DispatchResult { let who = ensure_signed(origin)?; match renouncing { Renouncing::Member => { @@ -482,7 +479,7 @@ pub mod pallet { })?; }, }; - Ok(None.into()) + Ok(()) } /// Remove a particular member from the set. This is effective immediately and the bond of @@ -513,7 +510,7 @@ pub mod pallet { who: AccountIdLookupOf, slash_bond: bool, rerun_election: bool, - ) -> DispatchResultWithPostInfo { + ) -> DispatchResult { ensure_root(origin)?; let who = T::Lookup::lookup(who)?; @@ -525,7 +522,7 @@ pub mod pallet { } // no refund needed. - Ok(None.into()) + Ok(()) } /// Clean all voters who are defunct (i.e. they do not serve any purpose at all). The @@ -543,13 +540,13 @@ pub mod pallet { origin: OriginFor, _num_voters: u32, _num_defunct: u32, - ) -> DispatchResultWithPostInfo { + ) -> DispatchResult { let _ = ensure_root(origin)?; >::iter() .filter(|(_, x)| Self::is_defunct_voter(&x.votes)) .for_each(|(dv, _)| Self::do_remove_voter(&dv)); - Ok(None.into()) + Ok(()) } } @@ -1177,7 +1174,7 @@ mod tests { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { @@ -1488,7 +1485,7 @@ mod tests { ensure_members_has_approval_stake(); } - fn submit_candidacy(origin: Origin) -> DispatchResultWithPostInfo { + fn submit_candidacy(origin: Origin) -> sp_runtime::DispatchResult { Elections::submit_candidacy(origin, Elections::candidates().len() as u32) } diff --git a/frame/elections-phragmen/src/migrations/v3.rs b/frame/elections-phragmen/src/migrations/v3.rs index b1cdd4be98541..9ec9c6e7eea6c 100644 --- a/frame/elections-phragmen/src/migrations/v3.rs +++ b/frame/elections-phragmen/src/migrations/v3.rs @@ -101,14 +101,14 @@ pub fn apply( StorageVersion::new(3).put::>(); - Weight::max_value() + Weight::MAX } else { log::warn!( target: "runtime::elections-phragmen", "Attempted to apply migration to V3 but failed because storage version is {:?}", storage_version, ); - 0 + Weight::zero() } } diff --git a/frame/elections-phragmen/src/migrations/v4.rs b/frame/elections-phragmen/src/migrations/v4.rs index e0fc17ec2a12d..76ef630706c50 100644 --- a/frame/elections-phragmen/src/migrations/v4.rs +++ b/frame/elections-phragmen/src/migrations/v4.rs @@ -38,7 +38,7 @@ pub fn migrate>(new_pallet_name: N) -> Weight { target: "runtime::elections-phragmen", "New pallet name is equal to the old prefix. No migration needs to be done.", ); - return 0 + return Weight::zero() } let storage_version = StorageVersion::get::>(); log::info!( @@ -63,7 +63,7 @@ pub fn migrate>(new_pallet_name: N) -> Weight { "Attempted to apply migration to v4 but failed because storage version is {:?}", storage_version, ); - 0 + Weight::zero() } } diff --git a/frame/elections-phragmen/src/migrations/v5.rs b/frame/elections-phragmen/src/migrations/v5.rs index a9fb018ba0219..eb96d7ddf6a99 100644 --- a/frame/elections-phragmen/src/migrations/v5.rs +++ b/frame/elections-phragmen/src/migrations/v5.rs @@ -8,7 +8,7 @@ use super::super::*; /// situation where they could increase their free balance but still not be able to use their funds /// because they were less than the lock. pub fn migrate(to_migrate: Vec) -> Weight { - let mut weight = 0; + let mut weight = Weight::new(); for who in to_migrate.iter() { if let Ok(mut voter) = Voting::::try_get(who) { diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 0e067699e5fac..14c69bf16f7f1 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_elections_phragmen. @@ -70,11 +70,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - (27_011_000 as Weight) + Weight::from_ref_time(27_011_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((214_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(214_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Candidates (r:1 w:0) // Storage: Elections Members (r:1 w:0) @@ -83,11 +83,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - (40_240_000 as Weight) + Weight::from_ref_time(40_240_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((244_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(244_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Candidates (r:1 w:0) // Storage: Elections Members (r:1 w:0) @@ -96,38 +96,38 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - (40_394_000 as Weight) + Weight::from_ref_time(40_394_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((217_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(217_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (37_651_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(37_651_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - (42_217_000 as Weight) + Weight::from_ref_time(42_217_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((50_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(50_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Elections Candidates (r:1 w:1) /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (46_459_000 as Weight) + Weight::from_ref_time(46_459_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((26_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(26_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Elections Members (r:1 w:1) // Storage: Elections RunnersUp (r:1 w:1) @@ -135,19 +135,19 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (45_189_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(45_189_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (34_516_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(34_516_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Benchmark Override (r:0 w:0) fn remove_member_without_replacement() -> Weight { - (2_000_000_000_000 as Weight) + Weight::from_ref_time(2_000_000_000_000 as RefTimeWeight) } // Storage: Elections Members (r:1 w:1) // Storage: System Account (r:1 w:1) @@ -156,9 +156,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (51_838_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(51_838_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Elections Voting (r:5001 w:5000) // Storage: Elections Members (r:1 w:0) @@ -169,12 +169,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[5000, 10000]`. /// The range of component `d` is `[1, 5000]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 76_000 - .saturating_add((63_721_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) + .saturating_add(Weight::from_ref_time(63_721_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) } // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:1) @@ -189,15 +189,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 10000]`. /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 773_000 - .saturating_add((81_534_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(81_534_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 51_000 - .saturating_add((4_453_000 as Weight).saturating_mul(e as Weight)) - .saturating_add(T::DbWeight::get().reads(280 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(c as Weight))) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) + .saturating_add(Weight::from_ref_time(4_453_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(280 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) } } @@ -210,11 +210,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - (27_011_000 as Weight) + Weight::from_ref_time(27_011_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((214_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(214_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Candidates (r:1 w:0) // Storage: Elections Members (r:1 w:0) @@ -223,11 +223,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - (40_240_000 as Weight) + Weight::from_ref_time(40_240_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((244_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(244_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Candidates (r:1 w:0) // Storage: Elections Members (r:1 w:0) @@ -236,38 +236,38 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - (40_394_000 as Weight) + Weight::from_ref_time(40_394_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((217_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(217_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - (37_651_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(37_651_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - (42_217_000 as Weight) + Weight::from_ref_time(42_217_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((50_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(50_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Elections Candidates (r:1 w:1) /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - (46_459_000 as Weight) + Weight::from_ref_time(46_459_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((26_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(26_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Elections Members (r:1 w:1) // Storage: Elections RunnersUp (r:1 w:1) @@ -275,19 +275,19 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - (45_189_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(45_189_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - (34_516_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(34_516_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Benchmark Override (r:0 w:0) fn remove_member_without_replacement() -> Weight { - (2_000_000_000_000 as Weight) + Weight::from_ref_time(2_000_000_000_000 as RefTimeWeight) } // Storage: Elections Members (r:1 w:1) // Storage: System Account (r:1 w:1) @@ -296,9 +296,9 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - (51_838_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(51_838_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Elections Voting (r:5001 w:5000) // Storage: Elections Members (r:1 w:0) @@ -309,12 +309,12 @@ impl WeightInfo for () { /// The range of component `v` is `[5000, 10000]`. /// The range of component `d` is `[1, 5000]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 76_000 - .saturating_add((63_721_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight))) - .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) + .saturating_add(Weight::from_ref_time(63_721_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) } // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:1) @@ -329,14 +329,14 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 10000]`. /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 773_000 - .saturating_add((81_534_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(81_534_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 51_000 - .saturating_add((4_453_000 as Weight).saturating_mul(e as Weight)) - .saturating_add(RocksDbWeight::get().reads(280 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(c as Weight))) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) + .saturating_add(Weight::from_ref_time(4_453_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(280 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) } } diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 03dc2c613c01e..ad46bdc4185bd 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -329,7 +329,7 @@ impl WeighData<(&BalanceOf,)> for WeightForSetDum let multiplier = self.0; // *target.0 is the amount passed into the extrinsic let cents = *target.0 / >::from(MILLICENTS); - (cents * multiplier).saturated_into::() + Weight::from_ref_time((cents * multiplier).saturated_into::()) } } @@ -392,7 +392,7 @@ pub mod pallet { fn on_initialize(_n: T::BlockNumber) -> Weight { // Anything that needs to be done at the start of the block. // We don't do anything here. - 0 + Weight::zero() } // `on_finalize` is executed at the end of block after all extrinsic are dispatched. diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 0f659e12fb443..f6afb7a0c77f1 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -52,7 +52,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; @@ -190,7 +190,7 @@ fn weights_work() { let default_call = pallet_example_basic::Call::::accumulate_dummy { increase_by: 10 }; let info1 = default_call.get_dispatch_info(); // aka. `let info = as GetDispatchInfo>::get_dispatch_info(&default_call);` - assert!(info1.weight > 0); + assert!(info1.weight > Weight::zero()); // `set_dummy` is simpler than `accumulate_dummy`, and the weight // should be less. diff --git a/frame/examples/basic/src/weights.rs b/frame/examples/basic/src/weights.rs index 5fc6434e396eb..e8fc44bc4b050 100644 --- a/frame/examples/basic/src/weights.rs +++ b/frame/examples/basic/src/weights.rs @@ -49,7 +49,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_example_basic. @@ -63,39 +63,39 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn set_dummy_benchmark(b: u32, ) -> Weight { - (5_834_000 as Weight) - .saturating_add((24_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(5_834_000 as RefTimeWeight) + .saturating_add(Weight::from_ref_time(24_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } fn accumulate_dummy(b: u32, ) -> Weight { - (51_353_000 as Weight) - .saturating_add((14_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(51_353_000 as RefTimeWeight) + .saturating_add(Weight::from_ref_time(14_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } fn sort_vector(x: u32, ) -> Weight { - (2_569_000 as Weight) + Weight::from_ref_time(2_569_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(x as Weight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) } } // For backwards compatibility and tests impl WeightInfo for () { fn set_dummy_benchmark(b: u32, ) -> Weight { - (5_834_000 as Weight) - .saturating_add((24_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(5_834_000 as RefTimeWeight) + .saturating_add(Weight::from_ref_time(24_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } fn accumulate_dummy(b: u32, ) -> Weight { - (51_353_000 as Weight) - .saturating_add((14_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(51_353_000 as RefTimeWeight) + .saturating_add(Weight::from_ref_time(14_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } fn sort_vector(x: u32, ) -> Weight { - (2_569_000 as Weight) + Weight::from_ref_time(2_569_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(x as Weight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) } } diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 703220e64fa8a..5b03614333cc9 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -53,7 +53,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/executive/README.md b/frame/executive/README.md index e96d07b0843f2..c14c3912b082d 100644 --- a/frame/executive/README.md +++ b/frame/executive/README.md @@ -56,7 +56,7 @@ struct CustomOnRuntimeUpgrade; impl frame_support::traits::OnRuntimeUpgrade for CustomOnRuntimeUpgrade { fn on_runtime_upgrade() -> frame_support::weights::Weight { // Do whatever you want. - 0 + frame_support::weights::Weight::zero() } } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index cd3e1c500db26..45361084f2f42 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -107,7 +107,7 @@ //! impl frame_support::traits::OnRuntimeUpgrade for CustomOnRuntimeUpgrade { //! fn on_runtime_upgrade() -> frame_support::weights::Weight { //! // Do whatever you want. -//! 0 +//! frame_support::weights::Weight::zero() //! } //! } //! @@ -123,12 +123,12 @@ use frame_support::{ EnsureInherentsAreFirst, ExecuteBlock, OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, }, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo}, + weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Weight}, }; use sp_runtime::{ generic::Digest, traits::{ - self, Applyable, CheckEqual, Checkable, Dispatchable, Header, NumberFor, One, Saturating, + self, Applyable, CheckEqual, Checkable, Dispatchable, Header, NumberFor, One, ValidateUnsigned, Zero, }, transaction_validity::{TransactionSource, TransactionValidity}, @@ -299,7 +299,7 @@ where // This means the format of all the event related storages must always be compatible. >::reset_events(); - let mut weight = 0; + let mut weight = Weight::new(); if Self::runtime_upgraded() { weight = weight.saturating_add(Self::execute_on_runtime_upgrade()); } @@ -413,7 +413,7 @@ where let max_weight = >::get().max_block; let remaining_weight = max_weight.saturating_sub(weight.total()); - if remaining_weight > 0 { + if remaining_weight > Weight::zero() { let used_weight = >::on_idle( block_number, remaining_weight, @@ -593,12 +593,12 @@ mod tests { // one with block number arg and one without fn on_initialize(n: T::BlockNumber) -> Weight { println!("on_initialize({})", n); - 175 + Weight::from_ref_time(175) } fn on_idle(n: T::BlockNumber, remaining_weight: Weight) -> Weight { println!("on_idle{}, {})", n, remaining_weight); - 175 + Weight::from_ref_time(175) } fn on_finalize(n: T::BlockNumber) { @@ -607,7 +607,7 @@ mod tests { fn on_runtime_upgrade() -> Weight { sp_io::storage::set(super::TEST_KEY, "module".as_bytes()); - 200 + Weight::from_ref_time(200) } fn offchain_worker(n: T::BlockNumber) { @@ -721,9 +721,9 @@ mod tests { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::builder() - .base_block(10) - .for_class(DispatchClass::all(), |weights| weights.base_extrinsic = 5) - .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = 1024.into()) + .base_block(Weight::from_ref_time(10)) + .for_class(DispatchClass::all(), |weights| weights.base_extrinsic = Weight::from_ref_time(5)) + .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = Weight::from_ref_time(1024).into()) .build_or_panic(); pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 10, @@ -814,7 +814,7 @@ mod tests { sp_io::storage::set(TEST_KEY, "custom_upgrade".as_bytes()); sp_io::storage::set(CUSTOM_ON_RUNTIME_KEY, &true.encode()); System::deposit_event(frame_system::Event::CodeUpdated); - 100 + Weight::from_ref_time(100) } } @@ -988,12 +988,12 @@ mod tests { sign_extra(1, 0, 0), ); let encoded = xt.encode(); - let encoded_len = encoded.len() as Weight; + let encoded_len = encoded.len() as u64; // on_initialize weight + base block execution weight let block_weights = ::BlockWeights::get(); - let base_block_weight = 175 + block_weights.base_block; + let base_block_weight = Weight::from_ref_time(175) + block_weights.base_block; let limit = block_weights.get(DispatchClass::Normal).max_total.unwrap() - base_block_weight; - let num_to_exhaust_block = limit / (encoded_len + 5); + let num_to_exhaust_block = limit.ref_time() / (encoded_len + 5); t.execute_with(|| { Executive::initialize_block(&Header::new( 1, @@ -1016,7 +1016,7 @@ mod tests { assert_eq!( >::block_weight().total(), //--------------------- on_initialize + block_execution + extrinsic_base weight - (encoded_len + 5) * (nonce + 1) + base_block_weight, + Weight::from_ref_time((encoded_len + 5) * (nonce + 1)) + base_block_weight, ); assert_eq!( >::extrinsic_index(), @@ -1047,8 +1047,8 @@ mod tests { let mut t = new_test_ext(1); t.execute_with(|| { // Block execution weight + on_initialize weight from custom module - let base_block_weight = - 175 + ::BlockWeights::get().base_block; + let base_block_weight = Weight::from_ref_time(175) + + ::BlockWeights::get().base_block; Executive::initialize_block(&Header::new( 1, @@ -1066,7 +1066,7 @@ mod tests { assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok()); // default weight for `TestXt` == encoded length. - let extrinsic_weight = len as Weight + + let extrinsic_weight = Weight::from_ref_time(len as u64) + ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic; @@ -1180,7 +1180,10 @@ mod tests { // NOTE: might need updates over time if new weights are introduced. // For now it only accounts for the base block execution weight and // the `on_initialize` weight defined in the custom test module. - assert_eq!(>::block_weight().total(), 175 + 175 + 10); + assert_eq!( + >::block_weight().total(), + Weight::from_ref_time(175 + 175 + 10) + ); }) } diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index 59522f9a106f2..b94b7d164f04c 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -335,7 +335,7 @@ pub mod pallet { if (n % T::IntakePeriod::get()).is_zero() { Self::pursue_target(T::MaxIntakeBids::get()) } else { - 0 + Weight::zero() } } } diff --git a/frame/gilt/src/weights.rs b/frame/gilt/src/weights.rs index 952080a2d030b..3d2b629e8b16b 100644 --- a/frame/gilt/src/weights.rs +++ b/frame/gilt/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_gilt. @@ -60,70 +60,70 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - (41_605_000 as Weight) + Weight::from_ref_time(41_605_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((62_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(62_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - (97_715_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(97_715_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - (42_061_000 as Weight) + Weight::from_ref_time(42_061_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - (5_026_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(5_026_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - (47_753_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(47_753_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - (1_663_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + Weight::from_ref_time(1_663_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - (40_797_000 as Weight) + Weight::from_ref_time(40_797_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((4_122_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(b as Weight))) + .saturating_add(Weight::from_ref_time(4_122_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - (14_944_000 as Weight) + Weight::from_ref_time(14_944_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add((8_135_000 as Weight).saturating_mul(q as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(q as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(q as Weight))) + .saturating_add(Weight::from_ref_time(8_135_000 as RefTimeWeight).scalar_saturating_mul(q as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(q as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(q as RefTimeWeight))) } } @@ -132,69 +132,69 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - (41_605_000 as Weight) + Weight::from_ref_time(41_605_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((62_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(62_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - (97_715_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(97_715_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - (42_061_000 as Weight) + Weight::from_ref_time(42_061_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - (5_026_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(5_026_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - (47_753_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(47_753_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - (1_663_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + Weight::from_ref_time(1_663_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - (40_797_000 as Weight) + Weight::from_ref_time(40_797_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((4_122_000 as Weight).saturating_mul(b as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(b as Weight))) + .saturating_add(Weight::from_ref_time(4_122_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - (14_944_000 as Weight) + Weight::from_ref_time(14_944_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add((8_135_000 as Weight).saturating_mul(q as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(q as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(q as Weight))) + .saturating_add(Weight::from_ref_time(8_135_000 as RefTimeWeight).scalar_saturating_mul(q as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(q as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(q as RefTimeWeight))) } } diff --git a/frame/grandpa/src/default_weights.rs b/frame/grandpa/src/default_weights.rs index 330e9bb255177..f21c3ddc101f7 100644 --- a/frame/grandpa/src/default_weights.rs +++ b/frame/grandpa/src/default_weights.rs @@ -35,7 +35,7 @@ impl crate::WeightInfo for () { // checking membership proof (35 * WEIGHT_PER_MICROS) - .saturating_add((175 * WEIGHT_PER_NANOS).saturating_mul(validator_count)) + .saturating_add((175 * WEIGHT_PER_NANOS).scalar_saturating_mul(validator_count)) .saturating_add(DbWeight::get().reads(5)) // check equivocation proof .saturating_add(95 * WEIGHT_PER_MICROS) diff --git a/frame/grandpa/src/migrations/v4.rs b/frame/grandpa/src/migrations/v4.rs index ab43f7baef4e9..81dbd3bab4b67 100644 --- a/frame/grandpa/src/migrations/v4.rs +++ b/frame/grandpa/src/migrations/v4.rs @@ -37,7 +37,7 @@ pub fn migrate>(new_pallet_name: N) -> Weight { target: "runtime::afg", "New pallet name is equal to the old prefix. No migration needs to be done.", ); - return 0 + return Weight::zero() } let storage_version = StorageVersion::get::>(); log::info!( @@ -57,7 +57,7 @@ pub fn migrate>(new_pallet_name: N) -> Weight { ::BlockWeights::get().max_block } else { - 0 + Weight::zero() } } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 5e6c955c441c5..d246466cf0db4 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -71,7 +71,7 @@ impl_opaque_keys! { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index ab0a9c677b00e..9c39069bf9538 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -856,7 +856,7 @@ fn valid_equivocation_reports_dont_pay_fees() { .get_dispatch_info(); // it should have non-zero weight and the fee has to be paid. - assert!(info.weight > 0); + assert!(info.weight > Weight::zero()); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 6066f176a6106..a0773e9904a1c 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -50,7 +50,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 7d3371c31b03b..780abf1bb01df 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -40,7 +40,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_identity. @@ -69,48 +69,48 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - (16_649_000 as Weight) + Weight::from_ref_time(16_649_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((241_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(241_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - (31_322_000 as Weight) + Weight::from_ref_time(31_322_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add((252_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(252_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((312_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(312_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn set_subs_new(s: u32, ) -> Weight { - (30_012_000 as Weight) + Weight::from_ref_time(30_012_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((3_005_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(3_005_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn set_subs_old(p: u32, ) -> Weight { - (29_623_000 as Weight) + Weight::from_ref_time(29_623_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_100_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) + .saturating_add(Weight::from_ref_time(1_100_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) } // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity IdentityOf (r:1 w:1) @@ -119,81 +119,81 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. /// The range of component `x` is `[1, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (34_370_000 as Weight) + Weight::from_ref_time(34_370_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add((186_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((1_114_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(1_114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((189_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(189_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - (34_759_000 as Weight) + Weight::from_ref_time(34_759_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((251_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(251_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add((340_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(340_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - (32_254_000 as Weight) + Weight::from_ref_time(32_254_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add((159_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(159_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add((347_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(347_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - (7_858_000 as Weight) + Weight::from_ref_time(7_858_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((190_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(190_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - (8_011_000 as Weight) + Weight::from_ref_time(8_011_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((187_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(187_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - (7_970_000 as Weight) + Weight::from_ref_time(7_970_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((175_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 19]`. /// The range of component `x` is `[1, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - (24_730_000 as Weight) + Weight::from_ref_time(24_730_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((196_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(196_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(341_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity IdentityOf (r:1 w:1) @@ -203,58 +203,58 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. /// The range of component `x` is `[1, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - (44_988_000 as Weight) + Weight::from_ref_time(44_988_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add((201_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((1_126_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(1_126_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((2_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 99]`. fn add_sub(s: u32, ) -> Weight { - (36_768_000 as Weight) + Weight::from_ref_time(36_768_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - (13_474_000 as Weight) + Weight::from_ref_time(13_474_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - (37_720_000 as Weight) + Weight::from_ref_time(37_720_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 99]`. fn quit_sub(s: u32, ) -> Weight { - (26_848_000 as Weight) + Weight::from_ref_time(26_848_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } } @@ -263,48 +263,48 @@ impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - (16_649_000 as Weight) + Weight::from_ref_time(16_649_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((241_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(241_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - (31_322_000 as Weight) + Weight::from_ref_time(31_322_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add((252_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(252_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((312_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(312_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn set_subs_new(s: u32, ) -> Weight { - (30_012_000 as Weight) + Weight::from_ref_time(30_012_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((3_005_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(3_005_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn set_subs_old(p: u32, ) -> Weight { - (29_623_000 as Weight) + Weight::from_ref_time(29_623_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_100_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) + .saturating_add(Weight::from_ref_time(1_100_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) } // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity IdentityOf (r:1 w:1) @@ -313,81 +313,81 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. /// The range of component `x` is `[1, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - (34_370_000 as Weight) + Weight::from_ref_time(34_370_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add((186_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((1_114_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(1_114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((189_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(189_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - (34_759_000 as Weight) + Weight::from_ref_time(34_759_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((251_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(251_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add((340_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(340_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - (32_254_000 as Weight) + Weight::from_ref_time(32_254_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add((159_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(159_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add((347_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(347_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - (7_858_000 as Weight) + Weight::from_ref_time(7_858_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((190_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(190_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - (8_011_000 as Weight) + Weight::from_ref_time(8_011_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((187_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(187_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - (7_970_000 as Weight) + Weight::from_ref_time(7_970_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((175_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 19]`. /// The range of component `x` is `[1, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - (24_730_000 as Weight) + Weight::from_ref_time(24_730_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((196_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(196_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add((341_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(341_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity IdentityOf (r:1 w:1) @@ -397,57 +397,57 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. /// The range of component `x` is `[1, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - (44_988_000 as Weight) + Weight::from_ref_time(44_988_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add((201_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((1_126_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(1_126_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((2_000 as Weight).saturating_mul(x as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 99]`. fn add_sub(s: u32, ) -> Weight { - (36_768_000 as Weight) + Weight::from_ref_time(36_768_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - (13_474_000 as Weight) + Weight::from_ref_time(13_474_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - (37_720_000 as Weight) + Weight::from_ref_time(37_720_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 99]`. fn quit_sub(s: u32, ) -> Weight { - (26_848_000 as Weight) + Weight::from_ref_time(26_848_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } } diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 2459f7e748941..b734bd37b6fd4 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -123,7 +123,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Runtime { diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index 34762e66ec301..09fbc55854288 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_im_online. @@ -56,13 +56,13 @@ impl WeightInfo for SubstrateWeight { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - (79_225_000 as Weight) + Weight::from_ref_time(79_225_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((41_000 as Weight).saturating_mul(k as Weight)) + .saturating_add(Weight::from_ref_time(41_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) // Standard Error: 0 - .saturating_add((293_000 as Weight).saturating_mul(e as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(293_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } } @@ -74,12 +74,12 @@ impl WeightInfo for () { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - (79_225_000 as Weight) + Weight::from_ref_time(79_225_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((41_000 as Weight).saturating_mul(k as Weight)) + .saturating_add(Weight::from_ref_time(41_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) // Standard Error: 0 - .saturating_add((293_000 as Weight).saturating_mul(e as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(293_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } } diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index 6bd79708c3dd2..693296a3b1064 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -44,7 +44,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 6635d45272048..2475c86fd499b 100644 --- a/frame/indices/src/weights.rs +++ b/frame/indices/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_indices. @@ -56,35 +56,35 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - (25_929_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_929_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (32_627_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(32_627_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - (26_804_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(26_804_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (27_390_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(27_390_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - (30_973_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(30_973_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } } @@ -92,34 +92,34 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - (25_929_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_929_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (32_627_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(32_627_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - (26_804_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(26_804_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (27_390_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(27_390_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - (30_973_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(30_973_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index 193958cfd41aa..f646ca02a0377 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_lottery. @@ -63,30 +63,30 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (44_706_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(44_706_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (12_556_000 as Weight) + Weight::from_ref_time(12_556_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add((295_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(295_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (38_051_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(38_051_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (6_910_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(6_910_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -94,9 +94,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (53_732_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(53_732_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -105,9 +105,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (55_868_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(55_868_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } } @@ -121,30 +121,30 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - (44_706_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(44_706_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - (12_556_000 as Weight) + Weight::from_ref_time(12_556_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add((295_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(295_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - (38_051_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(38_051_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - (6_910_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(6_910_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -152,9 +152,9 @@ impl WeightInfo for () { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - (53_732_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(53_732_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -163,8 +163,8 @@ impl WeightInfo for () { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - (55_868_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(55_868_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } } diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 32e1130f3d944..b4c9c3b38f1da 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -532,7 +532,7 @@ mod tests { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); pub static Members: Vec = vec![]; pub static Prime: Option = None; } diff --git a/frame/membership/src/migrations/v4.rs b/frame/membership/src/migrations/v4.rs index b3b52751d9598..5b8735aa2bac9 100644 --- a/frame/membership/src/migrations/v4.rs +++ b/frame/membership/src/migrations/v4.rs @@ -46,7 +46,7 @@ pub fn migrate::on_chain_storage_version(); @@ -71,7 +71,7 @@ pub fn migrate WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - (15_318_000 as Weight) + Weight::from_ref_time(15_318_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(51_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -73,11 +73,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - (18_005_000 as Weight) + Weight::from_ref_time(18_005_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((45_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(45_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -85,11 +85,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - (18_029_000 as Weight) + Weight::from_ref_time(18_029_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -97,11 +97,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - (18_105_000 as Weight) + Weight::from_ref_time(18_105_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((158_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -109,29 +109,29 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - (18_852_000 as Weight) + Weight::from_ref_time(18_852_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: TechnicalMembership Members (r:1 w:0) // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - (4_869_000 as Weight) + Weight::from_ref_time(4_869_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((28_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(28_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - (1_593_000 as Weight) + Weight::from_ref_time(1_593_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } } @@ -142,11 +142,11 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - (15_318_000 as Weight) + Weight::from_ref_time(15_318_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((51_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(51_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -154,11 +154,11 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - (18_005_000 as Weight) + Weight::from_ref_time(18_005_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((45_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(45_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -166,11 +166,11 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - (18_029_000 as Weight) + Weight::from_ref_time(18_029_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -178,11 +178,11 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - (18_105_000 as Weight) + Weight::from_ref_time(18_105_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((158_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -190,28 +190,28 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - (18_852_000 as Weight) + Weight::from_ref_time(18_852_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((55_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: TechnicalMembership Members (r:1 w:0) // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - (4_869_000 as Weight) + Weight::from_ref_time(4_869_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((28_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(28_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - (1_593_000 as Weight) + Weight::from_ref_time(1_593_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(m as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } } diff --git a/frame/merkle-mountain-range/src/default_weights.rs b/frame/merkle-mountain-range/src/default_weights.rs index 73d1963a42964..e7a4b6ab31c4a 100644 --- a/frame/merkle-mountain-range/src/default_weights.rs +++ b/frame/merkle-mountain-range/src/default_weights.rs @@ -30,7 +30,7 @@ impl crate::WeightInfo for () { // Blake2 hash cost. let hash_weight = 2 * WEIGHT_PER_NANOS; // No-op hook. - let hook_weight = 0; + let hook_weight = Weight::zero(); leaf_weight .saturating_add(hash_weight) diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 566a051823d5e..e13f89617bb9a 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -39,7 +39,7 @@ fn register_offchain_ext(ext: &mut sp_io::TestExternalities) { ext.register_extension(OffchainWorkerExt::new(offchain)); } -fn new_block() -> u64 { +fn new_block() -> Weight { let number = frame_system::Pallet::::block_number() + 1; let hash = H256::repeat_byte(number as u8); LEAF_DATA.with(|r| r.borrow_mut().a = number); @@ -110,7 +110,7 @@ fn should_start_empty() { crate::RootHash::::get(), hex("4320435e8c3318562dba60116bdbcc0b82ffcecb9bb39aae3300cfda3ad0b8b0") ); - assert!(weight != 0); + assert!(weight != Weight::zero()); }); } diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index 8201426f5330f..dafc421a7b72d 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -80,7 +80,7 @@ benchmarks! { // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, false, 0) + }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, false, Weight::zero()) verify { assert!(Multisigs::::contains_key(multi_account_id, call_hash)); assert!(!Calls::::contains_key(call_hash)); @@ -99,7 +99,7 @@ benchmarks! { // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, true, 0) + }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, true, Weight::zero()) verify { assert!(Multisigs::::contains_key(multi_account_id, call_hash)); assert!(Calls::::contains_key(call_hash)); @@ -118,13 +118,13 @@ benchmarks! { // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi, storing for worst case - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, 0)?; + Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?; assert!(Calls::::contains_key(call_hash)); let caller2 = signatories2.remove(0); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, 0) + }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::zero()) verify { let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; assert_eq!(multisig.approvals.len(), 2); @@ -143,13 +143,13 @@ benchmarks! { // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi, not storing - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), false, 0)?; + Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), false, Weight::zero())?; assert!(!Calls::::contains_key(call_hash)); let caller2 = signatories2.remove(0); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, true, 0) + }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, true, Weight::zero()) verify { let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; assert_eq!(multisig.approvals.len(), 2); @@ -169,20 +169,20 @@ benchmarks! { // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi, storing it for worst case - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, 0)?; + Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?; // Everyone except the first person approves for i in 1 .. s - 1 { let mut signatories_loop = signatories2.clone(); let caller_loop = signatories_loop.remove(i as usize); let o = RawOrigin::Signed(caller_loop).into(); - Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, 0)?; + Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, Weight::zero())?; } let caller2 = signatories2.remove(0); assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::max_value()) + }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::MAX) verify { assert!(!Multisigs::::contains_key(&multi_account_id, call_hash)); } @@ -200,7 +200,7 @@ benchmarks! { let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); // Create the multi - }: approve_as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call_hash, 0) + }: approve_as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call_hash, Weight::zero()) verify { assert!(Multisigs::::contains_key(multi_account_id, call_hash)); } @@ -225,13 +225,13 @@ benchmarks! { None, call, false, - 0 + Weight::zero() )?; let caller2 = signatories2.remove(0); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: approve_as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call_hash, 0) + }: approve_as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call_hash, Weight::zero()) verify { let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; assert_eq!(multisig.approvals.len(), 2); @@ -251,13 +251,13 @@ benchmarks! { // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, 0)?; + Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?; // Everyone except the first person approves for i in 1 .. s - 1 { let mut signatories_loop = signatories2.clone(); let caller_loop = signatories_loop.remove(i as usize); let o = RawOrigin::Signed(caller_loop).into(); - Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, 0)?; + Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, Weight::zero())?; } let caller2 = signatories2.remove(0); assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); @@ -270,7 +270,7 @@ benchmarks! { signatories2, Some(timepoint), call_hash, - Weight::max_value() + Weight::MAX ) verify { assert!(!Multisigs::::contains_key(multi_account_id, call_hash)); @@ -288,7 +288,7 @@ benchmarks! { let timepoint = Multisig::::timepoint(); // Create the multi let o = RawOrigin::Signed(caller.clone()).into(); - Multisig::::as_multi(o, s as u16, signatories.clone(), None, call, true, 0)?; + Multisig::::as_multi(o, s as u16, signatories.clone(), None, call, true, Weight::zero())?; assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); assert!(Calls::::contains_key(call_hash)); // Whitelist caller account from further DB operations. diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index d4ea041e5820e..10184ce84a9a8 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -257,9 +257,9 @@ pub mod pallet { let dispatch_info = call.get_dispatch_info(); ( T::WeightInfo::as_multi_threshold_1(call.using_encoded(|c| c.len() as u32)) - .saturating_add(dispatch_info.weight) // AccountData for inner call origin accountdata. - .saturating_add(T::DbWeight::get().reads_writes(1, 1)), + .saturating_add(T::DbWeight::get().reads_writes(1, 1)) + .saturating_add(dispatch_info.weight), dispatch_info.class, ) })] diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index 5d37e32e4d8a4..ddf5197ab734c 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -50,7 +50,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type BaseCallFilter = TestBaseCallFilter; @@ -152,7 +152,7 @@ fn multisig_deposit_is_taken_and_returned() { None, OpaqueCall::from_encoded(data.clone()), false, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(1), 2); assert_eq!(Balances::reserved_balance(1), 3); @@ -190,7 +190,7 @@ fn multisig_deposit_is_taken_and_returned_with_call_storage() { None, OpaqueCall::from_encoded(data), true, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(1), 0); assert_eq!(Balances::reserved_balance(1), 5); @@ -221,7 +221,14 @@ fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() { let data = call.encode(); let hash = blake2_256(&data); - assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); + assert_ok!(Multisig::approve_as_multi( + Origin::signed(1), + 3, + vec![2, 3], + None, + hash, + Weight::zero() + )); assert_eq!(Balances::free_balance(1), 1); assert_eq!(Balances::reserved_balance(1), 4); @@ -232,7 +239,7 @@ fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() { Some(now()), OpaqueCall::from_encoded(data), true, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(2), 3); assert_eq!(Balances::reserved_balance(2), 2); @@ -259,18 +266,25 @@ fn cancel_multisig_returns_deposit() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); - assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); + assert_ok!(Multisig::approve_as_multi( + Origin::signed(1), + 3, + vec![2, 3], + None, + hash, + Weight::zero() + )); assert_ok!(Multisig::approve_as_multi( Origin::signed(2), 3, vec![1, 3], Some(now()), hash, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(1), 6); assert_eq!(Balances::reserved_balance(1), 4); - assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash),); + assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash)); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::reserved_balance(1), 0); }); @@ -288,11 +302,25 @@ fn timepoint_checking_works() { let hash = blake2_256(&call); assert_noop!( - Multisig::approve_as_multi(Origin::signed(2), 2, vec![1, 3], Some(now()), hash, 0), + Multisig::approve_as_multi( + Origin::signed(2), + 2, + vec![1, 3], + Some(now()), + hash, + Weight::zero() + ), Error::::UnexpectedTimepoint, ); - assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 2, vec![2, 3], None, hash, 0)); + assert_ok!(Multisig::approve_as_multi( + Origin::signed(1), + 2, + vec![2, 3], + None, + hash, + Weight::zero() + )); assert_noop!( Multisig::as_multi( @@ -302,7 +330,7 @@ fn timepoint_checking_works() { None, OpaqueCall::from_encoded(call.clone()), false, - 0 + Weight::zero() ), Error::::NoTimepoint, ); @@ -315,7 +343,7 @@ fn timepoint_checking_works() { Some(later), OpaqueCall::from_encoded(call), false, - 0 + Weight::zero() ), Error::::WrongTimepoint, ); @@ -341,7 +369,7 @@ fn multisig_2_of_3_works_with_call_storing() { None, OpaqueCall::from_encoded(data), true, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(6), 0); @@ -369,7 +397,14 @@ fn multisig_2_of_3_works() { let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); - assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 2, vec![2, 3], None, hash, 0)); + assert_ok!(Multisig::approve_as_multi( + Origin::signed(1), + 2, + vec![2, 3], + None, + hash, + Weight::zero() + )); assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::as_multi( @@ -397,14 +432,21 @@ fn multisig_3_of_3_works() { let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); - assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); + assert_ok!(Multisig::approve_as_multi( + Origin::signed(1), + 3, + vec![2, 3], + None, + hash, + Weight::zero() + )); assert_ok!(Multisig::approve_as_multi( Origin::signed(2), 3, vec![1, 3], Some(now()), hash, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(6), 0); @@ -426,14 +468,21 @@ fn cancel_multisig_works() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); - assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); + assert_ok!(Multisig::approve_as_multi( + Origin::signed(1), + 3, + vec![2, 3], + None, + hash, + Weight::zero() + )); assert_ok!(Multisig::approve_as_multi( Origin::signed(2), 3, vec![1, 3], Some(now()), hash, - 0 + Weight::zero() )); assert_noop!( Multisig::cancel_as_multi(Origin::signed(2), 3, vec![1, 3], now(), hash), @@ -455,7 +504,7 @@ fn cancel_multisig_with_call_storage_works() { None, OpaqueCall::from_encoded(call), true, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(1), 4); assert_ok!(Multisig::approve_as_multi( @@ -464,7 +513,7 @@ fn cancel_multisig_with_call_storage_works() { vec![1, 3], Some(now()), hash, - 0 + Weight::zero() )); assert_noop!( Multisig::cancel_as_multi(Origin::signed(2), 3, vec![1, 3], now(), hash), @@ -480,7 +529,14 @@ fn cancel_multisig_with_alt_call_storage_works() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); - assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); + assert_ok!(Multisig::approve_as_multi( + Origin::signed(1), + 3, + vec![2, 3], + None, + hash, + Weight::zero() + )); assert_eq!(Balances::free_balance(1), 6); assert_ok!(Multisig::as_multi( Origin::signed(2), @@ -489,7 +545,7 @@ fn cancel_multisig_with_alt_call_storage_works() { Some(now()), OpaqueCall::from_encoded(call), true, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(2), 8); assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash)); @@ -516,7 +572,7 @@ fn multisig_2_of_3_as_multi_works() { None, OpaqueCall::from_encoded(data.clone()), false, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(6), 0); @@ -555,7 +611,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { None, OpaqueCall::from_encoded(data1.clone()), false, - 0 + Weight::zero() )); assert_ok!(Multisig::as_multi( Origin::signed(2), @@ -564,7 +620,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { None, OpaqueCall::from_encoded(data2.clone()), false, - 0 + Weight::zero() )); assert_ok!(Multisig::as_multi( Origin::signed(3), @@ -609,7 +665,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { None, OpaqueCall::from_encoded(data.clone()), false, - 0 + Weight::zero() )); assert_ok!(Multisig::as_multi( Origin::signed(2), @@ -629,7 +685,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { None, OpaqueCall::from_encoded(data.clone()), false, - 0 + Weight::zero() )); assert_ok!(Multisig::as_multi( Origin::signed(3), @@ -667,7 +723,7 @@ fn minimum_threshold_check_works() { None, OpaqueCall::from_encoded(call.clone()), false, - 0 + Weight::zero() ), Error::::MinimumThreshold, ); @@ -679,7 +735,7 @@ fn minimum_threshold_check_works() { None, OpaqueCall::from_encoded(call.clone()), false, - 0 + Weight::zero() ), Error::::MinimumThreshold, ); @@ -698,7 +754,7 @@ fn too_many_signatories_fails() { None, OpaqueCall::from_encoded(call), false, - 0 + Weight::zero() ), Error::::TooManySignatories, ); @@ -710,9 +766,23 @@ fn duplicate_approvals_are_ignored() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); - assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 2, vec![2, 3], None, hash, 0)); + assert_ok!(Multisig::approve_as_multi( + Origin::signed(1), + 2, + vec![2, 3], + None, + hash, + Weight::zero() + )); assert_noop!( - Multisig::approve_as_multi(Origin::signed(1), 2, vec![2, 3], Some(now()), hash, 0), + Multisig::approve_as_multi( + Origin::signed(1), + 2, + vec![2, 3], + Some(now()), + hash, + Weight::zero() + ), Error::::AlreadyApproved, ); assert_ok!(Multisig::approve_as_multi( @@ -721,10 +791,17 @@ fn duplicate_approvals_are_ignored() { vec![1, 3], Some(now()), hash, - 0 + Weight::zero() )); assert_noop!( - Multisig::approve_as_multi(Origin::signed(3), 2, vec![1, 2], Some(now()), hash, 0), + Multisig::approve_as_multi( + Origin::signed(3), + 2, + vec![1, 2], + Some(now()), + hash, + Weight::zero() + ), Error::::AlreadyApproved, ); }); @@ -741,7 +818,14 @@ fn multisig_1_of_3_works() { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_noop!( - Multisig::approve_as_multi(Origin::signed(1), 1, vec![2, 3], None, hash, 0), + Multisig::approve_as_multi( + Origin::signed(1), + 1, + vec![2, 3], + None, + hash, + Weight::zero() + ), Error::::MinimumThreshold, ); assert_noop!( @@ -752,7 +836,7 @@ fn multisig_1_of_3_works() { None, OpaqueCall::from_encoded(call), false, - 0 + Weight::zero() ), Error::::MinimumThreshold, ); @@ -791,7 +875,7 @@ fn weight_check_works() { None, OpaqueCall::from_encoded(data.clone()), false, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(6), 0); @@ -803,7 +887,7 @@ fn weight_check_works() { Some(now()), OpaqueCall::from_encoded(data), false, - 0 + Weight::zero() ), Error::::MaxWeightTooLow, ); @@ -825,14 +909,21 @@ fn multisig_handles_no_preimage_after_all_approve() { let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); - assert_ok!(Multisig::approve_as_multi(Origin::signed(1), 3, vec![2, 3], None, hash, 0)); + assert_ok!(Multisig::approve_as_multi( + Origin::signed(1), + 3, + vec![2, 3], + None, + hash, + Weight::zero() + )); assert_ok!(Multisig::approve_as_multi( Origin::signed(2), 3, vec![1, 3], Some(now()), hash, - 0 + Weight::zero() )); assert_ok!(Multisig::approve_as_multi( Origin::signed(3), @@ -840,7 +931,7 @@ fn multisig_handles_no_preimage_after_all_approve() { vec![1, 2], Some(now()), hash, - 0 + Weight::zero() )); assert_eq!(Balances::free_balance(6), 0); diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index 7946b96546768..0b580ec82b640 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_multisig. @@ -60,199 +60,199 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn as_multi_threshold_1(_z: u32, ) -> Weight { - (17_537_000 as Weight) + Weight::from_ref_time(17_537_000 as RefTimeWeight) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - (36_535_000 as Weight) + Weight::from_ref_time(36_535_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((99_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(99_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - (39_918_000 as Weight) + Weight::from_ref_time(39_918_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((95_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(95_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - (25_524_000 as Weight) + Weight::from_ref_time(25_524_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((94_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(94_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - (39_923_000 as Weight) + Weight::from_ref_time(39_923_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((91_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(91_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - (45_877_000 as Weight) + Weight::from_ref_time(45_877_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((146_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(146_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - (34_309_000 as Weight) + Weight::from_ref_time(34_309_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - (22_848_000 as Weight) + Weight::from_ref_time(22_848_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - (63_239_000 as Weight) + Weight::from_ref_time(63_239_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((161_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - (51_254_000 as Weight) + Weight::from_ref_time(51_254_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((118_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } } // For backwards compatibility and tests impl WeightInfo for () { fn as_multi_threshold_1(_z: u32, ) -> Weight { - (17_537_000 as Weight) + Weight::from_ref_time(17_537_000 as RefTimeWeight) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - (36_535_000 as Weight) + Weight::from_ref_time(36_535_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((99_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(99_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - (39_918_000 as Weight) + Weight::from_ref_time(39_918_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((95_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(95_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - (25_524_000 as Weight) + Weight::from_ref_time(25_524_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((94_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(94_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - (39_923_000 as Weight) + Weight::from_ref_time(39_923_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((91_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(91_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - (45_877_000 as Weight) + Weight::from_ref_time(45_877_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((146_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(Weight::from_ref_time(146_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - (34_309_000 as Weight) + Weight::from_ref_time(34_309_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - (22_848_000 as Weight) + Weight::from_ref_time(22_848_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - (63_239_000 as Weight) + Weight::from_ref_time(63_239_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((161_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - (51_254_000 as Weight) + Weight::from_ref_time(51_254_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((118_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } } diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 8eb6936ec0450..cf5af649b7843 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -273,7 +273,7 @@ mod tests { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/node-authorization/src/weights.rs b/frame/node-authorization/src/weights.rs index cf182f94273ce..f5a816ddaecee 100644 --- a/frame/node-authorization/src/weights.rs +++ b/frame/node-authorization/src/weights.rs @@ -21,7 +21,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; pub trait WeightInfo { @@ -37,13 +37,13 @@ pub trait WeightInfo { } impl WeightInfo for () { - fn add_well_known_node() -> Weight { 50_000_000 } - fn remove_well_known_node() -> Weight { 50_000_000 } - fn swap_well_known_node() -> Weight { 50_000_000 } - fn reset_well_known_nodes() -> Weight { 50_000_000 } - fn claim_node() -> Weight { 50_000_000 } - fn remove_claim() -> Weight { 50_000_000 } - fn transfer_node() -> Weight { 50_000_000 } - fn add_connections() -> Weight { 50_000_000 } - fn remove_connections() -> Weight { 50_000_000 } + fn add_well_known_node() -> Weight { Weight::from_ref_time(50_000_000) } + fn remove_well_known_node() -> Weight { Weight::from_ref_time(50_000_000) } + fn swap_well_known_node() -> Weight { Weight::from_ref_time(50_000_000) } + fn reset_well_known_nodes() -> Weight { Weight::from_ref_time(50_000_000) } + fn claim_node() -> Weight { Weight::from_ref_time(50_000_000) } + fn remove_claim() -> Weight { Weight::from_ref_time(50_000_000) } + fn transfer_node() -> Weight { Weight::from_ref_time(50_000_000) } + fn add_connections() -> Weight { Weight::from_ref_time(50_000_000) } + fn remove_connections() -> Weight { Weight::from_ref_time(50_000_000) } } diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index 243e5489b5445..412c954a2bbf3 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -320,6 +320,7 @@ pub mod v2 { current ); current.put::>(); + T::DbWeight::get().reads_writes(members_translated + 1, reward_pools_translated + 1) } } diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index a9003ffd3fb4c..1f0d2ce8cddc4 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_nomination_pools. @@ -80,9 +80,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (123_947_000 as Weight) - .saturating_add(T::DbWeight::get().reads(17 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) + Weight::from_ref_time(123_947_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(17 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(12 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -94,9 +94,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (118_236_000 as Weight) - .saturating_add(T::DbWeight::get().reads(14 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) + Weight::from_ref_time(118_236_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(14 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(12 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -108,18 +108,18 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (132_475_000 as Weight) - .saturating_add(T::DbWeight::get().reads(14 as Weight)) - .saturating_add(T::DbWeight::get().writes(13 as Weight)) + Weight::from_ref_time(132_475_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(14 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(13 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (50_299_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(50_299_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -136,9 +136,9 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (121_254_000 as Weight) - .saturating_add(T::DbWeight::get().reads(18 as Weight)) - .saturating_add(T::DbWeight::get().writes(13 as Weight)) + Weight::from_ref_time(121_254_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(18 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(13 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -146,11 +146,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (41_928_000 as Weight) + Weight::from_ref_time(41_928_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -162,11 +162,11 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - (81_611_000 as Weight) + Weight::from_ref_time(81_611_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(8 as Weight)) - .saturating_add(T::DbWeight::get().writes(7 as Weight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(7 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -189,9 +189,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (139_849_000 as Weight) - .saturating_add(T::DbWeight::get().reads(19 as Weight)) - .saturating_add(T::DbWeight::get().writes(16 as Weight)) + Weight::from_ref_time(139_849_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(19 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(16 as RefTimeWeight)) } // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: NominationPools MinCreateBond (r:1 w:0) @@ -216,9 +216,9 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (126_246_000 as Weight) - .saturating_add(T::DbWeight::get().reads(22 as Weight)) - .saturating_add(T::DbWeight::get().writes(15 as Weight)) + Weight::from_ref_time(126_246_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(22 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(15 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -234,30 +234,30 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - (48_829_000 as Weight) + Weight::from_ref_time(48_829_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add((2_204_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(12 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + .saturating_add(Weight::from_ref_time(2_204_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (26_761_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(26_761_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - (14_519_000 as Weight) + Weight::from_ref_time(14_519_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: NominationPools MinJoinBond (r:0 w:1) // Storage: NominationPools MaxPoolMembers (r:0 w:1) @@ -265,14 +265,14 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (6_173_000 as Weight) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(6_173_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (22_261_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(22_261_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -283,9 +283,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (47_959_000 as Weight) - .saturating_add(T::DbWeight::get().reads(8 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(47_959_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } } @@ -305,9 +305,9 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - (123_947_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(17 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + Weight::from_ref_time(123_947_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(17 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(12 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -319,9 +319,9 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - (118_236_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(14 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + Weight::from_ref_time(118_236_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(14 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(12 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -333,18 +333,18 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - (132_475_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(14 as Weight)) - .saturating_add(RocksDbWeight::get().writes(13 as Weight)) + Weight::from_ref_time(132_475_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(14 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(13 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - (50_299_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(50_299_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -361,9 +361,9 @@ impl WeightInfo for () { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - (121_254_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(18 as Weight)) - .saturating_add(RocksDbWeight::get().writes(13 as Weight)) + Weight::from_ref_time(121_254_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(18 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(13 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -371,11 +371,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - (41_928_000 as Weight) + Weight::from_ref_time(41_928_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((52_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -387,11 +387,11 @@ impl WeightInfo for () { // Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - (81_611_000 as Weight) + Weight::from_ref_time(81_611_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(8 as Weight)) - .saturating_add(RocksDbWeight::get().writes(7 as Weight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(7 as RefTimeWeight)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -414,9 +414,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (139_849_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(19 as Weight)) - .saturating_add(RocksDbWeight::get().writes(16 as Weight)) + Weight::from_ref_time(139_849_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(19 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(16 as RefTimeWeight)) } // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: NominationPools MinCreateBond (r:1 w:0) @@ -441,9 +441,9 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - (126_246_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(22 as Weight)) - .saturating_add(RocksDbWeight::get().writes(15 as Weight)) + Weight::from_ref_time(126_246_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(22 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(15 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -459,30 +459,30 @@ impl WeightInfo for () { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - (48_829_000 as Weight) + Weight::from_ref_time(48_829_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add((2_204_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(12 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + .saturating_add(Weight::from_ref_time(2_204_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - (26_761_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(26_761_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - (14_519_000 as Weight) + Weight::from_ref_time(14_519_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: NominationPools MinJoinBond (r:0 w:1) // Storage: NominationPools MaxPoolMembers (r:0 w:1) @@ -490,14 +490,14 @@ impl WeightInfo for () { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - (6_173_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(6_173_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - (22_261_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(22_261_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -508,8 +508,8 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (47_959_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(8 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(47_959_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } } diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index d51a81b1212c0..312bc4e18f413 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -40,7 +40,9 @@ type Balance = u64; parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND); + frame_system::limits::BlockWeights::simple_max( + 2 * WEIGHT_PER_SECOND + ); } impl frame_system::Config for Test { diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index 109806049a0fd..1a1f05cb9c088 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -50,7 +50,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); + frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(2_000_000_000_000)); } impl frame_system::Config for Test { type BaseCallFilter = Everything; diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index de3eb6607fe8c..183b704ec705d 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_preimage. @@ -64,87 +64,87 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn note_preimage(s: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_requested_preimage(s: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_no_deposit_preimage(s: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (44_380_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(44_380_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (30_280_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(30_280_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (42_809_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(42_809_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (28_964_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(28_964_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (17_555_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(17_555_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (7_745_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(7_745_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (29_758_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(29_758_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (18_360_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(18_360_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (7_439_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(7_439_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } } @@ -153,86 +153,86 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn note_preimage(s: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_requested_preimage(s: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_no_deposit_preimage(s: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (44_380_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(44_380_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (30_280_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(30_280_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (42_809_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(42_809_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (28_964_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(28_964_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (17_555_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(17_555_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (7_745_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(7_745_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (29_758_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(29_758_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (18_360_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(18_360_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (7_439_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(7_439_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } } diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 761d530954100..2d8dfc238bcd0 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -199,9 +199,9 @@ pub mod pallet { #[pallet::weight({ let di = call.get_dispatch_info(); (T::WeightInfo::proxy(T::MaxProxies::get()) - .saturating_add(di.weight) // AccountData for inner call origin accountdata. - .saturating_add(T::DbWeight::get().reads_writes(1, 1)), + .saturating_add(T::DbWeight::get().reads_writes(1, 1)) + .saturating_add(di.weight), di.class) })] pub fn proxy( @@ -529,9 +529,9 @@ pub mod pallet { #[pallet::weight({ let di = call.get_dispatch_info(); (T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get()) - .saturating_add(di.weight) // AccountData for inner call origin accountdata. - .saturating_add(T::DbWeight::get().reads_writes(1, 1)), + .saturating_add(T::DbWeight::get().reads_writes(1, 1)) + .saturating_add(di.weight), di.class) })] pub fn proxy_announced( diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 72acee1e0347e..b8d5a55705efa 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -54,7 +54,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 19beaf4d1401b..119df271e0d55 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_proxy. @@ -61,97 +61,97 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - (17_768_000 as Weight) + Weight::from_ref_time(17_768_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((76_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(Weight::from_ref_time(76_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - (35_682_000 as Weight) + Weight::from_ref_time(35_682_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((158_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((73_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn remove_announcement(a: u32, p: u32, ) -> Weight { - (25_586_000 as Weight) + Weight::from_ref_time(25_586_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((175_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((18_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(18_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_announcement(a: u32, p: u32, ) -> Weight { - (25_794_000 as Weight) + Weight::from_ref_time(25_794_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((173_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((13_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(13_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - (33_002_000 as Weight) + Weight::from_ref_time(33_002_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((163_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(163_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((79_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - (28_166_000 as Weight) + Weight::from_ref_time(28_166_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(105_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - (28_128_000 as Weight) + Weight::from_ref_time(28_128_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((118_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - (24_066_000 as Weight) + Weight::from_ref_time(24_066_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((81_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(81_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - (31_077_000 as Weight) + Weight::from_ref_time(31_077_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((37_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - (24_657_000 as Weight) + Weight::from_ref_time(24_657_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((87_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } } @@ -159,96 +159,96 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - (17_768_000 as Weight) + Weight::from_ref_time(17_768_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((76_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(Weight::from_ref_time(76_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - (35_682_000 as Weight) + Weight::from_ref_time(35_682_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((158_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((73_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn remove_announcement(a: u32, p: u32, ) -> Weight { - (25_586_000 as Weight) + Weight::from_ref_time(25_586_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((175_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((18_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(18_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_announcement(a: u32, p: u32, ) -> Weight { - (25_794_000 as Weight) + Weight::from_ref_time(25_794_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((173_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add((13_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(13_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - (33_002_000 as Weight) + Weight::from_ref_time(33_002_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((163_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(Weight::from_ref_time(163_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((79_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - (28_166_000 as Weight) + Weight::from_ref_time(28_166_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((105_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(105_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - (28_128_000 as Weight) + Weight::from_ref_time(28_128_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((118_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - (24_066_000 as Weight) + Weight::from_ref_time(24_066_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((81_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(81_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - (31_077_000 as Weight) + Weight::from_ref_time(31_077_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((37_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - (24_657_000 as Weight) + Weight::from_ref_time(24_657_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((87_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } } diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index f709578f6941a..467cae9728fae 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -69,7 +69,7 @@ use safe_mix::TripletMix; use codec::Encode; -use frame_support::traits::Randomness; +use frame_support::{pallet_prelude::Weight, traits::Randomness}; use sp_runtime::traits::{Hash, Saturating}; const RANDOM_MATERIAL_LEN: u32 = 81; @@ -187,7 +187,7 @@ mod tests { parameter_types! { pub BlockWeights: limits::BlockWeights = limits::BlockWeights - ::simple_max(1024); + ::simple_max(Weight::from_ref_time(1024)); pub BlockLength: limits::BlockLength = limits::BlockLength ::max(2 * 1024); } diff --git a/frame/ranked-collective/src/tests.rs b/frame/ranked-collective/src/tests.rs index 530388d83f3c4..b4173b30b0c2e 100644 --- a/frame/ranked-collective/src/tests.rs +++ b/frame/ranked-collective/src/tests.rs @@ -22,6 +22,7 @@ use std::collections::BTreeMap; use frame_support::{ assert_noop, assert_ok, error::BadOrigin, + pallet_prelude::Weight, parameter_types, traits::{ConstU16, ConstU32, ConstU64, EitherOf, Everything, MapSuccess, Polling}, }; @@ -50,7 +51,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1_000_000); + frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(1_000_000)); } impl frame_system::Config for Test { type BaseCallFilter = Everything; diff --git a/frame/ranked-collective/src/weights.rs b/frame/ranked-collective/src/weights.rs index 3048dd804a5e2..a0309daea2263 100644 --- a/frame/ranked-collective/src/weights.rs +++ b/frame/ranked-collective/src/weights.rs @@ -40,7 +40,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_ranked_collective. @@ -61,62 +61,62 @@ impl WeightInfo for SubstrateWeight { // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) fn add_member() -> Weight { - (11_000_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(11_000_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) fn remove_member(r: u32, ) -> Weight { - (16_855_000 as Weight) + Weight::from_ref_time(16_855_000 as RefTimeWeight) // Standard Error: 27_000 - .saturating_add((8_107_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(8_107_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) fn promote_member(r: u32, ) -> Weight { - (11_936_000 as Weight) + Weight::from_ref_time(11_936_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((9_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(9_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) fn demote_member(r: u32, ) -> Weight { - (17_582_000 as Weight) + Weight::from_ref_time(17_582_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: RankedCollective Members (r:1 w:0) // Storage: RankedPolls ReferendumInfoFor (r:1 w:1) // Storage: RankedCollective Voting (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote() -> Weight { - (22_000_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(22_000_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: RankedPolls ReferendumInfoFor (r:1 w:0) // Storage: RankedCollective Voting (r:0 w:1) fn cleanup_poll(n: u32, ) -> Weight { - (6_188_000 as Weight) + Weight::from_ref_time(6_188_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((867_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } } @@ -127,61 +127,61 @@ impl WeightInfo for () { // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) fn add_member() -> Weight { - (11_000_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(11_000_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) fn remove_member(r: u32, ) -> Weight { - (16_855_000 as Weight) + Weight::from_ref_time(16_855_000 as RefTimeWeight) // Standard Error: 27_000 - .saturating_add((8_107_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(r as Weight))) + .saturating_add(Weight::from_ref_time(8_107_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) fn promote_member(r: u32, ) -> Weight { - (11_936_000 as Weight) + Weight::from_ref_time(11_936_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((9_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(9_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) fn demote_member(r: u32, ) -> Weight { - (17_582_000 as Weight) + Weight::from_ref_time(17_582_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((142_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: RankedCollective Members (r:1 w:0) // Storage: RankedPolls ReferendumInfoFor (r:1 w:1) // Storage: RankedCollective Voting (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote() -> Weight { - (22_000_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(22_000_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: RankedPolls ReferendumInfoFor (r:1 w:0) // Storage: RankedCollective Voting (r:0 w:1) fn cleanup_poll(n: u32, ) -> Weight { - (6_188_000 as Weight) + Weight::from_ref_time(6_188_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((867_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } } diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 44fc4d72a4a5f..5dc49fff09b32 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -47,7 +47,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index 0887180a533fc..8b82454d5849d 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_recovery. @@ -60,71 +60,71 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Recovery Proxy (r:1 w:0) fn as_recovered() -> Weight { - (6_579_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + Weight::from_ref_time(6_579_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Recovery Proxy (r:0 w:1) fn set_recovered() -> Weight { - (13_402_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(13_402_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery Recoverable (r:1 w:1) fn create_recovery(n: u32, ) -> Weight { - (28_217_000 as Weight) + Weight::from_ref_time(28_217_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add((172_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn initiate_recovery() -> Weight { - (34_082_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(34_082_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn vouch_recovery(n: u32, ) -> Weight { - (22_038_000 as Weight) + Weight::from_ref_time(22_038_000 as RefTimeWeight) // Standard Error: 19_000 - .saturating_add((307_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(307_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Proxy (r:1 w:1) fn claim_recovery(n: u32, ) -> Weight { - (28_621_000 as Weight) + Weight::from_ref_time(28_621_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add((353_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(353_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery ActiveRecoveries (r:1 w:1) // Storage: System Account (r:1 w:1) fn close_recovery(n: u32, ) -> Weight { - (33_287_000 as Weight) + Weight::from_ref_time(33_287_000 as RefTimeWeight) // Standard Error: 19_000 - .saturating_add((264_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(264_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Recoverable (r:1 w:1) fn remove_recovery(n: u32, ) -> Weight { - (31_964_000 as Weight) + Weight::from_ref_time(31_964_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add((222_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(222_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery Proxy (r:1 w:1) fn cancel_recovered() -> Weight { - (12_702_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(12_702_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } } @@ -132,70 +132,70 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Recovery Proxy (r:1 w:0) fn as_recovered() -> Weight { - (6_579_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + Weight::from_ref_time(6_579_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Recovery Proxy (r:0 w:1) fn set_recovered() -> Weight { - (13_402_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(13_402_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery Recoverable (r:1 w:1) fn create_recovery(n: u32, ) -> Weight { - (28_217_000 as Weight) + Weight::from_ref_time(28_217_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add((172_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn initiate_recovery() -> Weight { - (34_082_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(34_082_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn vouch_recovery(n: u32, ) -> Weight { - (22_038_000 as Weight) + Weight::from_ref_time(22_038_000 as RefTimeWeight) // Standard Error: 19_000 - .saturating_add((307_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(307_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Proxy (r:1 w:1) fn claim_recovery(n: u32, ) -> Weight { - (28_621_000 as Weight) + Weight::from_ref_time(28_621_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add((353_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(353_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery ActiveRecoveries (r:1 w:1) // Storage: System Account (r:1 w:1) fn close_recovery(n: u32, ) -> Weight { - (33_287_000 as Weight) + Weight::from_ref_time(33_287_000 as RefTimeWeight) // Standard Error: 19_000 - .saturating_add((264_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(264_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Recoverable (r:1 w:1) fn remove_recovery(n: u32, ) -> Weight { - (31_964_000 as Weight) + Weight::from_ref_time(31_964_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add((222_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(222_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Recovery Proxy (r:1 w:1) fn cancel_recovered() -> Weight { - (12_702_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(12_702_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } } diff --git a/frame/referenda/src/branch.rs b/frame/referenda/src/branch.rs index f381f5fe5b709..172b5af999df5 100644 --- a/frame/referenda/src/branch.rs +++ b/frame/referenda/src/branch.rs @@ -19,6 +19,7 @@ use super::Config; use crate::weights::WeightInfo; +use frame_support::weights::Weight; /// Branches within the `begin_deciding` function. pub enum BeginDecidingBranch { @@ -82,7 +83,8 @@ impl ServiceBranch { /// Return the maximum possible weight of the `nudge` function. pub fn max_weight_of_nudge, I: 'static>() -> frame_support::weights::Weight { - 0.max(T::WeightInfo::nudge_referendum_no_deposit()) + Weight::new() + .max(T::WeightInfo::nudge_referendum_no_deposit()) .max(T::WeightInfo::nudge_referendum_preparing()) .max(T::WeightInfo::nudge_referendum_queued()) .max(T::WeightInfo::nudge_referendum_not_queued()) @@ -105,7 +107,7 @@ impl ServiceBranch { self, ) -> Option { use ServiceBranch::*; - Some(match self { + let ref_time_weight = match self { Preparing => T::WeightInfo::place_decision_deposit_preparing(), Queued => T::WeightInfo::place_decision_deposit_queued(), NotQueued => T::WeightInfo::place_decision_deposit_not_queued(), @@ -122,12 +124,15 @@ impl ServiceBranch { TimedOut | Fail | NoDeposit => return None, - }) + }; + + Some(ref_time_weight) } /// Return the maximum possible weight of the `place_decision_deposit` function. pub fn max_weight_of_deposit, I: 'static>() -> frame_support::weights::Weight { - 0.max(T::WeightInfo::place_decision_deposit_preparing()) + Weight::new() + .max(T::WeightInfo::place_decision_deposit_preparing()) .max(T::WeightInfo::place_decision_deposit_queued()) .max(T::WeightInfo::place_decision_deposit_not_queued()) .max(T::WeightInfo::place_decision_deposit_passing()) @@ -167,7 +172,8 @@ impl OneFewerDecidingBranch { /// Return the maximum possible weight of the `one_fewer_deciding` function. pub fn max_weight, I: 'static>() -> frame_support::weights::Weight { - 0.max(T::WeightInfo::one_fewer_deciding_queue_empty()) + Weight::new() + .max(T::WeightInfo::one_fewer_deciding_queue_empty()) .max(T::WeightInfo::one_fewer_deciding_passing()) .max(T::WeightInfo::one_fewer_deciding_failing()) } diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index dbe22cd562349..698bea8cc9f67 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -26,6 +26,7 @@ use frame_support::{ ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling, PreimageRecipient, SortedMembers, }, + weights::Weight, }; use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; @@ -61,8 +62,9 @@ impl Contains for BaseFilter { } parameter_types! { + pub MaxWeight: Weight = Weight::from_ref_time(2_000_000_000_000); pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1_000_000); + frame_system::limits::BlockWeights::simple_max(MaxWeight::get()); } impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; @@ -104,7 +106,7 @@ impl pallet_scheduler::Config for Test { type Origin = Origin; type PalletsOrigin = OriginCaller; type Call = Call; - type MaximumWeight = ConstU64<2_000_000_000_000>; + type MaximumWeight = MaxWeight; type ScheduleOrigin = EnsureRoot; type MaxScheduledPerBlock = ConstU32<100>; type WeightInfo = (); diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index d48ebb1014d48..84a726d9e4fbe 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_referenda. @@ -80,205 +80,205 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - (34_640_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(34_640_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - (44_290_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(44_290_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - (49_428_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(49_428_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - (50_076_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(50_076_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - (55_935_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(55_935_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - (52_921_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(52_921_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - (29_160_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(29_160_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - (34_972_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(34_972_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - (60_620_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(60_620_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - (9_615_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(9_615_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - (113_077_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(113_077_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - (114_376_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(114_376_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - (43_901_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(43_901_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - (43_279_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(43_279_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - (45_564_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(45_564_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - (45_061_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(45_061_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - (23_757_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(23_757_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - (24_781_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(24_781_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - (18_344_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_344_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - (34_752_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(34_752_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - (37_055_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(37_055_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - (31_442_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(31_442_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - (33_201_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(33_201_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - (30_047_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(30_047_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - (29_195_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(29_195_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn nudge_referendum_approved() -> Weight { - (50_119_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(50_119_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - (32_203_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(32_203_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } } @@ -288,204 +288,204 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - (34_640_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(34_640_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - (44_290_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(44_290_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - (49_428_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(49_428_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - (50_076_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(50_076_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - (55_935_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(55_935_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - (52_921_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(52_921_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - (29_160_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(29_160_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - (34_972_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(34_972_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - (60_620_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(60_620_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - (9_615_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(9_615_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - (113_077_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(113_077_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - (114_376_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(114_376_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - (43_901_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(43_901_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - (43_279_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(43_279_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - (45_564_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(45_564_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - (45_061_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(45_061_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - (23_757_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(23_757_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - (24_781_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(24_781_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - (18_344_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(18_344_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - (34_752_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(34_752_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - (37_055_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(37_055_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - (31_442_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(31_442_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - (33_201_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(33_201_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - (30_047_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(30_047_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - (29_195_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(29_195_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn nudge_referendum_approved() -> Weight { - (50_119_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(50_119_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - (32_203_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(32_203_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } } diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index b8bd4618f8def..a098670ccf100 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_remark. @@ -52,10 +52,10 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn store(l: u32, ) -> Weight { - (13_140_000 as Weight) + Weight::from_ref_time(13_140_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) } } @@ -63,9 +63,9 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn store(l: u32, ) -> Weight { - (13_140_000 as Weight) + Weight::from_ref_time(13_140_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) } } diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 008105dc737ea..7bbc628604bc6 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -119,7 +119,7 @@ impl Contains for BaseFilter { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); + frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(2_000_000_000_000)); } impl system::Config for Test { type BaseCallFilter = BaseFilter; diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index d03e13da4747a..56f9298dd4b0c 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -30,7 +30,7 @@ use substrate_test_utils::assert_eq_uvec; #[test] fn basic_scheduling_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into())); run_to_block(3); @@ -45,7 +45,7 @@ fn basic_scheduling_works() { #[test] fn scheduling_with_preimages_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); let hash = ::Hashing::hash_of(&call); let hashed = MaybeHashed::Hash(hash); assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); @@ -65,7 +65,7 @@ fn scheduling_with_preimages_works() { #[test] fn scheduling_with_preimage_postpones_correctly() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); let hash = ::Hashing::hash_of(&call); let hashed = MaybeHashed::Hash(hash); @@ -98,7 +98,7 @@ fn scheduling_with_preimage_postpones_correctly() { fn schedule_after_works() { new_test_ext().execute_with(|| { run_to_block(2); - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call.into())); @@ -115,7 +115,7 @@ fn schedule_after_works() { fn schedule_after_zero_works() { new_test_ext().execute_with(|| { run_to_block(2); - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call.into())); // Will trigger on the next block. @@ -135,7 +135,7 @@ fn periodic_scheduling_works() { Some((3, 3)), 127, root(), - Call::Logger(logger::Call::log { i: 42, weight: 1000 }).into() + Call::Logger(logger::Call::log { i: 42, weight: Weight::from_ref_time(1000) }).into() )); run_to_block(3); assert!(logger::log().is_empty()); @@ -157,7 +157,7 @@ fn periodic_scheduling_works() { #[test] fn reschedule_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into()).unwrap(), @@ -188,7 +188,7 @@ fn reschedule_works() { #[test] fn reschedule_named_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule_named( @@ -230,7 +230,7 @@ fn reschedule_named_works() { #[test] fn reschedule_named_perodic_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule_named( @@ -292,7 +292,7 @@ fn cancel_named_scheduling_works_with_normal_cancel() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), ) .unwrap(); let i = Scheduler::do_schedule( @@ -300,7 +300,7 @@ fn cancel_named_scheduling_works_with_normal_cancel() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into(), + Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), ) .unwrap(); run_to_block(3); @@ -322,7 +322,7 @@ fn cancel_named_periodic_scheduling_works() { Some((3, 3)), 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into(), + Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), ) .unwrap(); // same id results in error. @@ -332,7 +332,7 @@ fn cancel_named_periodic_scheduling_works() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), ) .is_err()); // different id is ok. @@ -342,7 +342,7 @@ fn cancel_named_periodic_scheduling_works() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), ) .unwrap(); run_to_block(3); @@ -458,8 +458,11 @@ fn scheduler_respects_priority_ordering_with_soft_deadlines() { None, 126, root(), - Call::Logger(LoggerCall::log { i: 2600, weight: max_weight / 2 - item_weight + 1 }) - .into(), + Call::Logger(LoggerCall::log { + i: 2600, + weight: max_weight / 2 - item_weight + Weight::one() + }) + .into(), )); // 2600 does not fit with 69 or 42, but has higher priority, so will go through @@ -484,7 +487,7 @@ fn on_initialize_weight_is_correct() { None, 255, root(), - Call::Logger(LoggerCall::log { i: 3, weight: call_weight + 1 }).into(), + Call::Logger(LoggerCall::log { i: 3, weight: call_weight + Weight::one() }).into(), )); // Anon Periodic assert_ok!(Scheduler::do_schedule( @@ -492,7 +495,8 @@ fn on_initialize_weight_is_correct() { Some((1000, 3)), 128, root(), - Call::Logger(LoggerCall::log { i: 42, weight: call_weight + 2 }).into(), + Call::Logger(LoggerCall::log { i: 42, weight: call_weight + Weight::from_ref_time(2) }) + .into(), )); // Anon assert_ok!(Scheduler::do_schedule( @@ -500,7 +504,8 @@ fn on_initialize_weight_is_correct() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: call_weight + 3 }).into(), + Call::Logger(LoggerCall::log { i: 69, weight: call_weight + Weight::from_ref_time(3) }) + .into(), )); // Named Periodic assert_ok!(Scheduler::do_schedule_named( @@ -509,7 +514,11 @@ fn on_initialize_weight_is_correct() { Some((1000, 3)), 126, root(), - Call::Logger(LoggerCall::log { i: 2600, weight: call_weight + 4 }).into(), + Call::Logger(LoggerCall::log { + i: 2600, + weight: call_weight + Weight::from_ref_time(4) + }) + .into(), )); // Will include the named periodic only @@ -517,7 +526,8 @@ fn on_initialize_weight_is_correct() { assert_eq!( actual_weight, base_weight + - call_weight + 4 + <() as MarginalWeightInfo>::item(true, true, Some(false)) + call_weight + Weight::from_ref_time(4) + + <() as MarginalWeightInfo>::item(true, true, Some(false)) ); assert_eq!(logger::log(), vec![(root(), 2600u32)]); @@ -526,8 +536,10 @@ fn on_initialize_weight_is_correct() { assert_eq!( actual_weight, base_weight + - call_weight + 2 + <() as MarginalWeightInfo>::item(false, false, Some(false)) + - call_weight + 3 + <() as MarginalWeightInfo>::item(true, false, Some(false)) + call_weight + Weight::from_ref_time(2) + + <() as MarginalWeightInfo>::item(false, false, Some(false)) + + call_weight + Weight::from_ref_time(3) + + <() as MarginalWeightInfo>::item(true, false, Some(false)) ); assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); @@ -536,7 +548,8 @@ fn on_initialize_weight_is_correct() { assert_eq!( actual_weight, base_weight + - call_weight + 1 + <() as MarginalWeightInfo>::item(false, true, Some(false)) + call_weight + Weight::from_ref_time(1) + + <() as MarginalWeightInfo>::item(false, true, Some(false)) ); assert_eq!( logger::log(), @@ -552,8 +565,12 @@ fn on_initialize_weight_is_correct() { #[test] fn root_calls_works() { new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + let call = Box::new( + Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + ); + let call2 = Box::new( + Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + ); assert_ok!(Scheduler::schedule_named(Origin::root(), 1u32.encode(), 4, None, 127, call,)); assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); run_to_block(3); @@ -573,9 +590,15 @@ fn fails_to_schedule_task_in_the_past() { new_test_ext().execute_with(|| { run_to_block(3); - let call1 = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); - let call3 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + let call1 = Box::new( + Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + ); + let call2 = Box::new( + Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + ); + let call3 = Box::new( + Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + ); assert_err!( Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call1), @@ -597,8 +620,12 @@ fn fails_to_schedule_task_in_the_past() { #[test] fn should_use_orign() { new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + let call = Box::new( + Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + ); + let call2 = Box::new( + Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + ); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), 1u32.encode(), @@ -623,8 +650,12 @@ fn should_use_orign() { #[test] fn should_check_orign() { new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + let call = Box::new( + Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + ); + let call2 = Box::new( + Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + ); assert_noop!( Scheduler::schedule_named( system::RawOrigin::Signed(2).into(), @@ -646,10 +677,20 @@ fn should_check_orign() { #[test] fn should_check_orign_for_cancel() { new_test_ext().execute_with(|| { - let call = - Box::new(Call::Logger(LoggerCall::log_without_filter { i: 69, weight: 1000 }).into()); - let call2 = - Box::new(Call::Logger(LoggerCall::log_without_filter { i: 42, weight: 1000 }).into()); + let call = Box::new( + Call::Logger(LoggerCall::log_without_filter { + i: 69, + weight: Weight::from_ref_time(1000), + }) + .into(), + ); + let call2 = Box::new( + Call::Logger(LoggerCall::log_without_filter { + i: 42, + weight: Weight::from_ref_time(1000), + }) + .into(), + ); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), 1u32.encode(), @@ -693,14 +734,20 @@ fn migration_to_v3_works() { Some(ScheduledV1 { maybe_id: None, priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), + call: Call::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100), + }), maybe_periodic: None, }), None, Some(ScheduledV1 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + call: Call::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(1000), + }), maybe_periodic: Some((456u64, 10)), }), ]; @@ -718,7 +765,11 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: None, priority: 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + call: Call::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100) + }) + .into(), maybe_periodic: None, origin: root(), _phantom: PhantomData::::default(), @@ -727,7 +778,11 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + call: Call::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(1000) + }) + .into(), maybe_periodic: Some((456u64, 10)), origin: root(), _phantom: PhantomData::::default(), @@ -740,7 +795,11 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: None, priority: 11, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + call: Call::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100) + }) + .into(), maybe_periodic: None, origin: root(), _phantom: PhantomData::::default(), @@ -749,7 +808,11 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + call: Call::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(1000) + }) + .into(), maybe_periodic: Some((456u64, 10)), origin: root(), _phantom: PhantomData::::default(), @@ -762,7 +825,11 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: None, priority: 12, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + call: Call::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100) + }) + .into(), maybe_periodic: None, origin: root(), _phantom: PhantomData::::default(), @@ -771,7 +838,11 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + call: Call::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(1000) + }) + .into(), maybe_periodic: Some((456u64, 10)), origin: root(), _phantom: PhantomData::::default(), @@ -794,7 +865,11 @@ fn test_migrate_origin() { Some(Scheduled { maybe_id: None, priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + call: Call::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100), + }) + .into(), origin: 3u32, maybe_periodic: None, _phantom: Default::default(), @@ -804,7 +879,11 @@ fn test_migrate_origin() { maybe_id: Some(b"test".to_vec()), priority: 123, origin: 2u32, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + call: Call::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(1000), + }) + .into(), maybe_periodic: Some((456u64, 10)), _phantom: Default::default(), }), @@ -833,7 +912,11 @@ fn test_migrate_origin() { Some(ScheduledV2::, u64, OriginCaller, u64> { maybe_id: None, priority: 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + call: Call::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100) + }) + .into(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), @@ -842,7 +925,11 @@ fn test_migrate_origin() { Some(ScheduledV2 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + call: Call::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(1000) + }) + .into(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), @@ -855,7 +942,11 @@ fn test_migrate_origin() { Some(ScheduledV2 { maybe_id: None, priority: 11, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + call: Call::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100) + }) + .into(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), @@ -864,7 +955,11 @@ fn test_migrate_origin() { Some(ScheduledV2 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + call: Call::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(1000) + }) + .into(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), @@ -877,7 +972,11 @@ fn test_migrate_origin() { Some(ScheduledV2 { maybe_id: None, priority: 12, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + call: Call::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100) + }) + .into(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), @@ -886,7 +985,11 @@ fn test_migrate_origin() { Some(ScheduledV2 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + call: Call::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(1000) + }) + .into(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index dd7ed8104420d..f201c89eaf278 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_scheduler. @@ -68,146 +68,146 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (9_994_000 as Weight) + Weight::from_ref_time(9_994_000 as RefTimeWeight) // Standard Error: 20_000 - .saturating_add((19_843_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(19_843_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((4 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (10_318_000 as Weight) + Weight::from_ref_time(10_318_000 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add((15_451_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(15_451_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (11_675_000 as Weight) + Weight::from_ref_time(11_675_000 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add((17_019_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(17_019_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (11_934_000 as Weight) + Weight::from_ref_time(11_934_000 as RefTimeWeight) // Standard Error: 11_000 - .saturating_add((14_134_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(14_134_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (7_279_000 as Weight) + Weight::from_ref_time(7_279_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((5_388_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(5_388_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (8_619_000 as Weight) + Weight::from_ref_time(8_619_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((2_969_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(2_969_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (16_129_000 as Weight) + Weight::from_ref_time(16_129_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add((9_772_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(9_772_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (15_785_000 as Weight) + Weight::from_ref_time(15_785_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((7_208_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(7_208_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (15_778_000 as Weight) + Weight::from_ref_time(15_778_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((5_597_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(5_597_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (15_912_000 as Weight) + Weight::from_ref_time(15_912_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((4_530_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(4_530_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (18_013_000 as Weight) + Weight::from_ref_time(18_013_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((87_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (18_131_000 as Weight) + Weight::from_ref_time(18_131_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((595_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (21_230_000 as Weight) + Weight::from_ref_time(21_230_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((98_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(98_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (20_139_000 as Weight) + Weight::from_ref_time(20_139_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((595_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } } @@ -218,145 +218,145 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (9_994_000 as Weight) + Weight::from_ref_time(9_994_000 as RefTimeWeight) // Standard Error: 20_000 - .saturating_add((19_843_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(19_843_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((4 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (10_318_000 as Weight) + Weight::from_ref_time(10_318_000 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add((15_451_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(15_451_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (11_675_000 as Weight) + Weight::from_ref_time(11_675_000 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add((17_019_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(17_019_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (11_934_000 as Weight) + Weight::from_ref_time(11_934_000 as RefTimeWeight) // Standard Error: 11_000 - .saturating_add((14_134_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(14_134_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (7_279_000 as Weight) + Weight::from_ref_time(7_279_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((5_388_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(5_388_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (8_619_000 as Weight) + Weight::from_ref_time(8_619_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add((2_969_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(2_969_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (16_129_000 as Weight) + Weight::from_ref_time(16_129_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add((9_772_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(9_772_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (15_785_000 as Weight) + Weight::from_ref_time(15_785_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((7_208_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(7_208_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (15_778_000 as Weight) + Weight::from_ref_time(15_778_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((5_597_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(5_597_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (15_912_000 as Weight) + Weight::from_ref_time(15_912_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((4_530_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(4_530_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - (18_013_000 as Weight) + Weight::from_ref_time(18_013_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((87_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (18_131_000 as Weight) + Weight::from_ref_time(18_131_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((595_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (21_230_000 as Weight) + Weight::from_ref_time(21_230_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((98_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(98_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (20_139_000 as Weight) + Weight::from_ref_time(20_139_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((595_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } } diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index aa4f75255b120..dd96a5df2baf9 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -281,7 +281,7 @@ pub mod pallet { let pool = >::get(); >::refresh_members(pool, ChangeReceiver::MembershipChanged); } - 0 + Weight::zero() } } diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index 4fef5385eb2c5..e38e0a18b99c8 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -50,7 +50,7 @@ frame_support::construct_runtime!( parameter_types! { pub const CandidateDeposit: u64 = 25; pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } ord_parameter_types! { pub const KickOrigin: u64 = 2; diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 71ee9d1e0758a..34c560984661d 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -574,7 +574,7 @@ pub mod pallet { // NOTE: the non-database part of the weight for `should_end_session(n)` is // included as weight for empty block, the database part is expected to be in // cache. - 0 + Weight::zero() } } } diff --git a/frame/session/src/migrations/v1.rs b/frame/session/src/migrations/v1.rs index 3c687ea7d9d66..c0dce422fe8b5 100644 --- a/frame/session/src/migrations/v1.rs +++ b/frame/session/src/migrations/v1.rs @@ -47,7 +47,7 @@ pub fn migrate::on_chain_storage_version(); @@ -82,7 +82,7 @@ pub fn migrate sp_io::TestExternalities { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index 40ae7f1be4265..5208a679c6bb7 100644 --- a/frame/session/src/weights.rs +++ b/frame/session/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_session. @@ -55,17 +55,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - (48_484_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(48_484_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - (38_003_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(38_003_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } } @@ -75,16 +75,16 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - (48_484_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(48_484_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - (38_003_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(38_003_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } } diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index ec4cca1813ec6..626562f7a45f8 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -614,7 +614,7 @@ pub mod pallet { fn on_initialize(n: T::BlockNumber) -> Weight { let mut members = vec![]; - let mut weight = 0; + let mut weight = Weight::new(); let weights = T::BlockWeights::get(); // Run a candidate/membership rotation diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 04ea705eed556..ed668e79269fd 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -50,7 +50,7 @@ frame_support::construct_runtime!( parameter_types! { pub const SocietyPalletId: PalletId = PalletId(*b"py/socie"); pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } ord_parameter_types! { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 68aa97db8a324..2a55d3baea2e6 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1167,7 +1167,7 @@ where disable_strategy: DisableStrategy, ) -> Weight { let reward_proportion = SlashRewardFraction::::get(); - let mut consumed_weight: Weight = 0; + let mut consumed_weight = Weight::from_ref_time(0); let mut add_db_reads_writes = |reads, writes| { consumed_weight += T::DbWeight::get().reads_writes(reads, writes); }; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 485a9dc3ae66a..cda606008a9cc 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3759,7 +3759,7 @@ fn payout_stakers_handles_weight_refund() { let half_max_nom_rewarded_weight = ::WeightInfo::payout_stakers_alive_staked(half_max_nom_rewarded); let zero_nom_payouts_weight = ::WeightInfo::payout_stakers_alive_staked(0); - assert!(zero_nom_payouts_weight > 0); + assert!(zero_nom_payouts_weight > Weight::zero()); assert!(half_max_nom_rewarded_weight > zero_nom_payouts_weight); assert!(max_nom_rewarded_weight > half_max_nom_rewarded_weight); @@ -3898,42 +3898,68 @@ fn bond_during_era_correctly_populates_claimed_rewards() { fn offences_weight_calculated_correctly() { ExtBuilder::default().nominate(true).build_and_execute(|| { // On offence with zero offenders: 4 Reads, 1 Write - let zero_offence_weight = ::DbWeight::get().reads_writes(4, 1); - assert_eq!(Staking::on_offence(&[], &[Perbill::from_percent(50)], 0, DisableStrategy::WhenSlashed), zero_offence_weight); + let zero_offence_weight = + ::DbWeight::get().reads_writes(4, 1); + assert_eq!( + Staking::on_offence(&[], &[Perbill::from_percent(50)], 0, DisableStrategy::WhenSlashed), + zero_offence_weight + ); // On Offence with N offenders, Unapplied: 4 Reads, 1 Write + 4 Reads, 5 Writes - let n_offence_unapplied_weight = ::DbWeight::get().reads_writes(4, 1) - + ::DbWeight::get().reads_writes(4, 5); - - let offenders: Vec::AccountId, pallet_session::historical::IdentificationTuple>> - = (1..10).map(|i| - OffenceDetails { - offender: (i, Staking::eras_stakers(active_era(), i)), - reporters: vec![], - } - ).collect(); - assert_eq!(Staking::on_offence(&offenders, &[Perbill::from_percent(50)], 0, DisableStrategy::WhenSlashed), n_offence_unapplied_weight); + let n_offence_unapplied_weight = ::DbWeight::get() + .reads_writes(4, 1) + + ::DbWeight::get().reads_writes(4, 5); + + let offenders: Vec< + OffenceDetails< + ::AccountId, + pallet_session::historical::IdentificationTuple, + >, + > = (1..10) + .map(|i| OffenceDetails { + offender: (i, Staking::eras_stakers(active_era(), i)), + reporters: vec![], + }) + .collect(); + assert_eq!( + Staking::on_offence( + &offenders, + &[Perbill::from_percent(50)], + 0, + DisableStrategy::WhenSlashed + ), + n_offence_unapplied_weight + ); // On Offence with one offenders, Applied - let one_offender = [ - OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![1], - }, - ]; + let one_offender = [OffenceDetails { + offender: (11, Staking::eras_stakers(active_era(), 11)), + reporters: vec![1], + }]; let n = 1; // Number of offenders let rw = 3 + 3 * n; // rw reads and writes - let one_offence_unapplied_weight = ::DbWeight::get().reads_writes(4, 1) - + ::DbWeight::get().reads_writes(rw, rw) + let one_offence_unapplied_weight = + ::DbWeight::get().reads_writes(4, 1) + + + ::DbWeight::get().reads_writes(rw, rw) // One `slash_cost` + ::DbWeight::get().reads_writes(6, 5) // `slash_cost` * nominators (1) + ::DbWeight::get().reads_writes(6, 5) // `reward_cost` * reporters (1) - + ::DbWeight::get().reads_writes(2, 2); + + ::DbWeight::get().reads_writes(2, 2) + ; - assert_eq!(Staking::on_offence(&one_offender, &[Perbill::from_percent(50)], 0, DisableStrategy::WhenSlashed), one_offence_unapplied_weight); + assert_eq!( + Staking::on_offence( + &one_offender, + &[Perbill::from_percent(50)], + 0, + DisableStrategy::WhenSlashed + ), + one_offence_unapplied_weight + ); }); } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 1bdfb01bddc86..c5f584054d1f4 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_staking. @@ -86,9 +86,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (43_992_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(43_992_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -96,9 +96,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (75_827_000 as Weight) - .saturating_add(T::DbWeight::get().reads(8 as Weight)) - .saturating_add(T::DbWeight::get().writes(7 as Weight)) + Weight::from_ref_time(75_827_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(7 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Nominators (r:1 w:0) @@ -110,20 +110,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (81_075_000 as Weight) - .saturating_add(T::DbWeight::get().reads(12 as Weight)) - .saturating_add(T::DbWeight::get().writes(8 as Weight)) + Weight::from_ref_time(81_075_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(8 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (35_763_000 as Weight) + Weight::from_ref_time(35_763_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((57_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(57_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -139,9 +139,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (66_938_000 as Weight) - .saturating_add(T::DbWeight::get().reads(13 as Weight)) - .saturating_add(T::DbWeight::get().writes(11 as Weight)) + Weight::from_ref_time(66_938_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(13 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(11 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) @@ -155,19 +155,19 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (52_943_000 as Weight) - .saturating_add(T::DbWeight::get().reads(11 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(52_943_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(11 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (23_264_000 as Weight) + Weight::from_ref_time(23_264_000 as RefTimeWeight) // Standard Error: 11_000 - .saturating_add((8_006_000 as Weight).saturating_mul(k as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) + .saturating_add(Weight::from_ref_time(8_006_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinNominatorBond (r:1 w:0) @@ -181,12 +181,12 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (56_596_000 as Weight) + Weight::from_ref_time(56_596_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((3_644_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(12 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + .saturating_add(Weight::from_ref_time(3_644_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Validators (r:1 w:0) @@ -196,50 +196,50 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (51_117_000 as Weight) - .saturating_add(T::DbWeight::get().reads(8 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(51_117_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (11_223_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(11_223_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (19_826_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(19_826_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (3_789_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_789_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (3_793_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_793_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (3_802_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_802_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (3_762_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_762_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (4_318_000 as Weight) + Weight::from_ref_time(4_318_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((10_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(10_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) @@ -255,20 +255,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (65_265_000 as Weight) + Weight::from_ref_time(65_265_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_029_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(11 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(1_029_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(11 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(12 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (903_312_000 as Weight) + Weight::from_ref_time(903_312_000 as RefTimeWeight) // Standard Error: 56_000 - .saturating_add((4_968_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(4_968_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:0) @@ -281,13 +281,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (87_569_000 as Weight) + Weight::from_ref_time(87_569_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((24_232_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(10 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(24_232_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(10 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:0) @@ -301,13 +301,13 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (98_839_000 as Weight) + Weight::from_ref_time(98_839_000 as RefTimeWeight) // Standard Error: 21_000 - .saturating_add((34_480_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(11 as Weight)) - .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(34_480_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(11 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) @@ -316,11 +316,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (74_865_000 as Weight) + Weight::from_ref_time(74_865_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((64_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(T::DbWeight::get().reads(9 as Weight)) - .saturating_add(T::DbWeight::get().writes(8 as Weight)) + .saturating_add(Weight::from_ref_time(64_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(9 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(8 as RefTimeWeight)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:1) @@ -332,12 +332,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 62_000 - .saturating_add((22_829_000 as Weight).saturating_mul(e as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) - .saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) + .saturating_add(Weight::from_ref_time(22_829_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((7 as RefTimeWeight).saturating_mul(e as RefTimeWeight))) } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) @@ -353,12 +353,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (70_933_000 as Weight) + Weight::from_ref_time(70_933_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_021_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(12 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(1_021_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(12 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: BagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) @@ -379,16 +379,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 897_000 - .saturating_add((213_100_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(213_100_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 45_000 - .saturating_add((31_123_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(208 as Weight)) - .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) - .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) + .saturating_add(Weight::from_ref_time(31_123_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(208 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(T::DbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) } // Storage: BagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) @@ -399,25 +399,25 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 116_000 - .saturating_add((23_745_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(23_745_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 116_000 - .saturating_add((22_497_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(22_497_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 3_968_000 - .saturating_add((20_676_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(202 as Weight)) - .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) - .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(20_676_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(202 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(T::DbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 36_000 - .saturating_add((8_097_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) + .saturating_add(Weight::from_ref_time(8_097_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -426,8 +426,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - (7_041_000 as Weight) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(7_041_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -436,8 +436,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - (6_495_000 as Weight) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(6_495_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) @@ -450,16 +450,16 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (62_014_000 as Weight) - .saturating_add(T::DbWeight::get().reads(11 as Weight)) - .saturating_add(T::DbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(62_014_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(11 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - (12_814_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(12_814_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } } @@ -472,9 +472,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - (43_992_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(43_992_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -482,9 +482,9 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - (75_827_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(8 as Weight)) - .saturating_add(RocksDbWeight::get().writes(7 as Weight)) + Weight::from_ref_time(75_827_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(7 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Nominators (r:1 w:0) @@ -496,20 +496,20 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - (81_075_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(12 as Weight)) - .saturating_add(RocksDbWeight::get().writes(8 as Weight)) + Weight::from_ref_time(81_075_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(8 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - (35_763_000 as Weight) + Weight::from_ref_time(35_763_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((57_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(57_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -525,9 +525,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - (66_938_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(13 as Weight)) - .saturating_add(RocksDbWeight::get().writes(11 as Weight)) + Weight::from_ref_time(66_938_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(13 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(11 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) @@ -541,19 +541,19 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - (52_943_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(11 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + Weight::from_ref_time(52_943_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(11 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - (23_264_000 as Weight) + Weight::from_ref_time(23_264_000 as RefTimeWeight) // Standard Error: 11_000 - .saturating_add((8_006_000 as Weight).saturating_mul(k as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(k as Weight))) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) + .saturating_add(Weight::from_ref_time(8_006_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinNominatorBond (r:1 w:0) @@ -567,12 +567,12 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - (56_596_000 as Weight) + Weight::from_ref_time(56_596_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((3_644_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(12 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + .saturating_add(Weight::from_ref_time(3_644_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Validators (r:1 w:0) @@ -582,50 +582,50 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - (51_117_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(8 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(51_117_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - (11_223_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(11_223_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - (19_826_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(19_826_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - (3_789_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_789_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - (3_793_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_793_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - (3_802_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_802_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - (3_762_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(3_762_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - (4_318_000 as Weight) + Weight::from_ref_time(4_318_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((10_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(10_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) @@ -641,20 +641,20 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - (65_265_000 as Weight) + Weight::from_ref_time(65_265_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_029_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(11 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(1_029_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(11 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(12 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - (903_312_000 as Weight) + Weight::from_ref_time(903_312_000 as RefTimeWeight) // Standard Error: 56_000 - .saturating_add((4_968_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(4_968_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:0) @@ -667,13 +667,13 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (87_569_000 as Weight) + Weight::from_ref_time(87_569_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((24_232_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(10 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(24_232_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(10 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:0) @@ -687,13 +687,13 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (98_839_000 as Weight) + Weight::from_ref_time(98_839_000 as RefTimeWeight) // Standard Error: 21_000 - .saturating_add((34_480_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(11 as Weight)) - .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(n as Weight))) + .saturating_add(Weight::from_ref_time(34_480_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(11 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) @@ -702,11 +702,11 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - (74_865_000 as Weight) + Weight::from_ref_time(74_865_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add((64_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(RocksDbWeight::get().reads(9 as Weight)) - .saturating_add(RocksDbWeight::get().writes(8 as Weight)) + .saturating_add(Weight::from_ref_time(64_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(9 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(8 as RefTimeWeight)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:1) @@ -718,12 +718,12 @@ impl WeightInfo for () { // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 62_000 - .saturating_add((22_829_000 as Weight).saturating_mul(e as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) + .saturating_add(Weight::from_ref_time(22_829_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((7 as RefTimeWeight).saturating_mul(e as RefTimeWeight))) } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) @@ -739,12 +739,12 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - (70_933_000 as Weight) + Weight::from_ref_time(70_933_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_021_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(12 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(1_021_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(12 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: BagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) @@ -765,16 +765,16 @@ impl WeightInfo for () { // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 897_000 - .saturating_add((213_100_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(213_100_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 45_000 - .saturating_add((31_123_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(208 as Weight)) - .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) - .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) + .saturating_add(Weight::from_ref_time(31_123_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(208 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) } // Storage: BagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) @@ -785,25 +785,25 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 116_000 - .saturating_add((23_745_000 as Weight).saturating_mul(v as Weight)) + .saturating_add(Weight::from_ref_time(23_745_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) // Standard Error: 116_000 - .saturating_add((22_497_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(22_497_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 3_968_000 - .saturating_add((20_676_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(202 as Weight)) - .saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(v as Weight))) - .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(Weight::from_ref_time(20_676_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(202 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) } // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 36_000 - .saturating_add((8_097_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) + .saturating_add(Weight::from_ref_time(8_097_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -812,8 +812,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - (7_041_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(7_041_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -822,8 +822,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - (6_495_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(6_495_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) @@ -836,15 +836,15 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - (62_014_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(11 as Weight)) - .saturating_add(RocksDbWeight::get().writes(6 as Weight)) + Weight::from_ref_time(62_014_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(11 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - (12_814_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(12_814_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } } diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 9b0172bf97aa2..93b5bd3468f6b 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -839,9 +839,10 @@ pub mod pallet { impl Pallet { /// The real weight of a migration of the given number of `items` with total `size`. fn dynamic_weight(items: u32, size: u32) -> frame_support::pallet_prelude::Weight { - let items = items as Weight; - items - .saturating_mul(::DbWeight::get().reads_writes(1, 1)) + let items = items as u64; + ::DbWeight::get() + .reads_writes(1, 1) + .scalar_saturating_mul(items) // we assume that the read/write per-byte weight is the same for child and top tree. .saturating_add(T::WeightInfo::process_top_key(size)) } @@ -1129,25 +1130,25 @@ mod mock { impl WeightInfo for StateMigrationTestWeight { fn process_top_key(_: u32) -> Weight { - 1000000 + Weight::from_ref_time(1000000) } fn continue_migrate() -> Weight { - 1000000 + Weight::from_ref_time(1000000) } fn continue_migrate_wrong_witness() -> Weight { - 1000000 + Weight::from_ref_time(1000000) } fn migrate_custom_top_fail() -> Weight { - 1000000 + Weight::from_ref_time(1000000) } fn migrate_custom_top_success() -> Weight { - 1000000 + Weight::from_ref_time(1000000) } fn migrate_custom_child_fail() -> Weight { - 1000000 + Weight::from_ref_time(1000000) } fn migrate_custom_child_success() -> Weight { - 1000000 + Weight::from_ref_time(1000000) } } @@ -1243,9 +1244,9 @@ mod mock { (custom_storage, version).into() } - pub(crate) fn run_to_block(n: u32) -> (H256, u64) { + pub(crate) fn run_to_block(n: u32) -> (H256, Weight) { let mut root = Default::default(); - let mut weight_sum = 0; + let mut weight_sum = Weight::new(); log::trace!(target: LOG_TARGET, "running from {:?} to {:?}", System::block_number(), n); while System::block_number() < n { System::set_block_number(System::block_number() + 1); @@ -1606,7 +1607,10 @@ pub(crate) mod remote_tests { use crate::{AutoLimits, MigrationLimits, Pallet as StateTrieMigration, LOG_TARGET}; use codec::Encode; use frame_benchmarking::Zero; - use frame_support::traits::{Get, Hooks}; + use frame_support::{ + traits::{Get, Hooks}, + weights::Weight, + }; use frame_system::Pallet as System; use remote_externalities::Mode; use sp_core::H256; @@ -1616,9 +1620,9 @@ pub(crate) mod remote_tests { #[allow(dead_code)] fn run_to_block>( n: ::BlockNumber, - ) -> (H256, u64) { + ) -> (H256, Weight) { let mut root = Default::default(); - let mut weight_sum = 0; + let mut weight_sum = Weight::new(); while System::::block_number() < n { System::::set_block_number(System::::block_number() + One::one()); System::::on_initialize(System::::block_number()); diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs index f2566f949c058..6fccc0b68f3d7 100644 --- a/frame/state-trie-migration/src/weights.rs +++ b/frame/state-trie-migration/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_state_trie_migration. @@ -59,40 +59,40 @@ impl WeightInfo for SubstrateWeight { // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) // Storage: StateTrieMigration MigrationProcess (r:1 w:1) fn continue_migrate() -> Weight { - (19_019_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(19_019_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) fn continue_migrate_wrong_witness() -> Weight { - (1_874_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + Weight::from_ref_time(1_874_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) } fn migrate_custom_top_success() -> Weight { - (16_381_000 as Weight) + Weight::from_ref_time(16_381_000 as RefTimeWeight) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_top_fail() -> Weight { - (25_966_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_966_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } fn migrate_custom_child_success() -> Weight { - (16_712_000 as Weight) + Weight::from_ref_time(16_712_000 as RefTimeWeight) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_child_fail() -> Weight { - (29_885_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(29_885_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: unknown [0x6b6579] (r:1 w:1) fn process_top_key(v: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } } @@ -101,39 +101,39 @@ impl WeightInfo for () { // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) // Storage: StateTrieMigration MigrationProcess (r:1 w:1) fn continue_migrate() -> Weight { - (19_019_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(19_019_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) fn continue_migrate_wrong_witness() -> Weight { - (1_874_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + Weight::from_ref_time(1_874_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) } fn migrate_custom_top_success() -> Weight { - (16_381_000 as Weight) + Weight::from_ref_time(16_381_000 as RefTimeWeight) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_top_fail() -> Weight { - (25_966_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_966_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } fn migrate_custom_child_success() -> Weight { - (16_712_000 as Weight) + Weight::from_ref_time(16_712_000 as RefTimeWeight) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_child_fail() -> Weight { - (29_885_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(29_885_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: unknown [0x6b6579] (r:1 w:1) fn process_top_key(v: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(v as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } } diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 07fdc56e82da6..bde69f11106dc 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -139,7 +139,7 @@ pub mod pallet { /// # #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); - (dispatch_info.weight.saturating_add(10_000), dispatch_info.class) + (dispatch_info.weight, dispatch_info.class) })] pub fn sudo( origin: OriginFor, @@ -222,7 +222,6 @@ pub mod pallet { let dispatch_info = call.get_dispatch_info(); ( dispatch_info.weight - .saturating_add(10_000) // AccountData for inner call origin accountdata. .saturating_add(T::DbWeight::get().reads_writes(1, 1)), dispatch_info.class, diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index 71f0f26b1a1d5..c895eaf830136 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -22,6 +22,7 @@ use crate as sudo; use frame_support::{ parameter_types, traits::{ConstU32, ConstU64, Contains, GenesisBuild}, + weights::Weight, }; use frame_system::limits; use sp_core::H256; @@ -109,7 +110,7 @@ frame_support::construct_runtime!( ); parameter_types! { - pub BlockWeights: limits::BlockWeights = limits::BlockWeights::simple_max(1024); + pub BlockWeights: limits::BlockWeights = limits::BlockWeights::simple_max(Weight::from_ref_time(1024)); } pub struct BlockEverything; diff --git a/frame/sudo/src/tests.rs b/frame/sudo/src/tests.rs index 84c8e0c5c254e..502c6476935a2 100644 --- a/frame/sudo/src/tests.rs +++ b/frame/sudo/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for the module. use super::*; -use frame_support::{assert_noop, assert_ok}; +use frame_support::{assert_noop, assert_ok, weights::Weight}; use mock::{ new_test_ext, Call, Event as TestEvent, Logger, LoggerCall, Origin, Sudo, SudoCall, System, Test, @@ -39,12 +39,18 @@ fn sudo_basics() { // Configure a default test environment and set the root `key` to 1. new_test_ext(1).execute_with(|| { // A privileged function should work when `sudo` is passed the root `key` as `origin`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: 1_000 })); + let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + i: 42, + weight: Weight::from_ref_time(1_000), + })); assert_ok!(Sudo::sudo(Origin::signed(1), call)); assert_eq!(Logger::i32_log(), vec![42i32]); // A privileged function should not work when `sudo` is passed a non-root `key` as `origin`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: 1_000 })); + let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + i: 42, + weight: Weight::from_ref_time(1_000), + })); assert_noop!(Sudo::sudo(Origin::signed(2), call), Error::::RequireSudo); }); } @@ -56,7 +62,8 @@ fn sudo_emits_events_correctly() { System::set_block_number(1); // Should emit event to indicate success when called with the root `key` and `call` is `Ok`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: 1 })); + let call = + Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::one() })); assert_ok!(Sudo::sudo(Origin::signed(1), call)); System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) })); }) @@ -66,24 +73,36 @@ fn sudo_emits_events_correctly() { fn sudo_unchecked_weight_basics() { new_test_ext(1).execute_with(|| { // A privileged function should work when `sudo` is passed the root `key` as origin. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: 1_000 })); - assert_ok!(Sudo::sudo_unchecked_weight(Origin::signed(1), call, 1_000)); + let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + i: 42, + weight: Weight::from_ref_time(1_000), + })); + assert_ok!(Sudo::sudo_unchecked_weight( + Origin::signed(1), + call, + Weight::from_ref_time(1_000) + )); assert_eq!(Logger::i32_log(), vec![42i32]); // A privileged function should not work when called with a non-root `key`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: 1_000 })); + let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + i: 42, + weight: Weight::from_ref_time(1_000), + })); assert_noop!( - Sudo::sudo_unchecked_weight(Origin::signed(2), call, 1_000), + Sudo::sudo_unchecked_weight(Origin::signed(2), call, Weight::from_ref_time(1_000)), Error::::RequireSudo, ); // `I32Log` is unchanged after unsuccessful call. assert_eq!(Logger::i32_log(), vec![42i32]); // Controls the dispatched weight. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: 1 })); - let sudo_unchecked_weight_call = SudoCall::sudo_unchecked_weight { call, weight: 1_000 }; + let call = + Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::one() })); + let sudo_unchecked_weight_call = + SudoCall::sudo_unchecked_weight { call, weight: Weight::from_ref_time(1_000) }; let info = sudo_unchecked_weight_call.get_dispatch_info(); - assert_eq!(info.weight, 1_000); + assert_eq!(info.weight, Weight::from_ref_time(1_000)); }); } @@ -94,8 +113,13 @@ fn sudo_unchecked_weight_emits_events_correctly() { System::set_block_number(1); // Should emit event to indicate success when called with the root `key` and `call` is `Ok`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: 1 })); - assert_ok!(Sudo::sudo_unchecked_weight(Origin::signed(1), call, 1_000)); + let call = + Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::one() })); + assert_ok!(Sudo::sudo_unchecked_weight( + Origin::signed(1), + call, + Weight::from_ref_time(1_000) + )); System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) })); }) } @@ -134,17 +158,22 @@ fn set_key_emits_events_correctly() { fn sudo_as_basics() { new_test_ext(1).execute_with(|| { // A privileged function will not work when passed to `sudo_as`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: 1_000 })); + let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + i: 42, + weight: Weight::from_ref_time(1_000), + })); assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); assert!(Logger::i32_log().is_empty()); assert!(Logger::account_log().is_empty()); // A non-privileged function should not work when called with a non-root `key`. - let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { i: 42, weight: 1 })); + let call = + Box::new(Call::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::one() })); assert_noop!(Sudo::sudo_as(Origin::signed(3), 2, call), Error::::RequireSudo); // A non-privileged function will work when passed to `sudo_as` with the root `key`. - let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { i: 42, weight: 1 })); + let call = + Box::new(Call::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::one() })); assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); assert_eq!(Logger::i32_log(), vec![42i32]); // The correct user makes the call within `sudo_as`. @@ -159,7 +188,8 @@ fn sudo_as_emits_events_correctly() { System::set_block_number(1); // A non-privileged function will work when passed to `sudo_as` with the root `key`. - let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { i: 42, weight: 1 })); + let call = + Box::new(Call::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::one() })); assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); System::assert_has_event(TestEvent::Sudo(Event::SudoAsDone { sudo_result: Ok(()) })); }); diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index a658f01fa6854..97312ac3476b5 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -176,18 +176,18 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// ``` /// # #[macro_use] /// # extern crate frame_support; -/// # use frame_support::dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo}; +/// # use frame_support::{weights::Weight, dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo}}; /// # use frame_system::{Config, ensure_signed}; /// decl_module! { /// pub struct Module for enum Call where origin: T::Origin { /// #[weight = 1_000_000] /// fn my_long_function(origin, do_expensive_calc: bool) -> DispatchResultWithPostInfo { -/// ensure_signed(origin).map_err(|e| e.with_weight(100_000))?; +/// ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100_000)))?; /// if do_expensive_calc { /// // do the expensive calculation /// // ... /// // return None to indicate that we are using all weight (the default) -/// return Ok(None.into()); +/// return Ok(None::.into()); /// } /// // expensive calculation not executed: use only a portion of the weight /// Ok(Some(100_000).into()) @@ -1614,7 +1614,7 @@ macro_rules! decl_module { pallet_name, ); - 0 + $crate::dispatch::Weight::new() } #[cfg(feature = "try-runtime")] @@ -2649,13 +2649,13 @@ mod tests { #[weight = (5, DispatchClass::Operational)] fn operational(_origin) { unreachable!() } - fn on_initialize(n: T::BlockNumber,) -> Weight { if n.into() == 42 { panic!("on_initialize") } 7 } + fn on_initialize(n: T::BlockNumber,) -> Weight { if n.into() == 42 { panic!("on_initialize") } Weight::from_ref_time(7) } fn on_idle(n: T::BlockNumber, remaining_weight: Weight,) -> Weight { - if n.into() == 42 || remaining_weight == 42 { panic!("on_idle") } - 7 + if n.into() == 42 || remaining_weight == Weight::from_ref_time(42) { panic!("on_idle") } + Weight::from_ref_time(7) } fn on_finalize(n: T::BlockNumber,) { if n.into() == 42 { panic!("on_finalize") } } - fn on_runtime_upgrade() -> Weight { 10 } + fn on_runtime_upgrade() -> Weight { Weight::from_ref_time(10) } fn offchain_worker() {} /// Some doc fn integrity_test() { panic!("integrity_test") } @@ -2814,24 +2814,30 @@ mod tests { #[test] fn on_initialize_should_work_2() { - assert_eq!( as OnInitialize>::on_initialize(10), 7); + assert_eq!( + as OnInitialize>::on_initialize(10), + Weight::from_ref_time(7) + ); } #[test] #[should_panic(expected = "on_idle")] fn on_idle_should_work_1() { - as OnIdle>::on_idle(42, 9); + as OnIdle>::on_idle(42, Weight::from_ref_time(9)); } #[test] #[should_panic(expected = "on_idle")] fn on_idle_should_work_2() { - as OnIdle>::on_idle(9, 42); + as OnIdle>::on_idle(9, Weight::from_ref_time(42)); } #[test] fn on_idle_should_work_3() { - assert_eq!( as OnIdle>::on_idle(10, 11), 7); + assert_eq!( + as OnIdle>::on_idle(10, Weight::from_ref_time(11)), + Weight::from_ref_time(7) + ); } #[test] @@ -2843,7 +2849,10 @@ mod tests { #[test] fn on_runtime_upgrade_should_work() { sp_io::TestExternalities::default().execute_with(|| { - assert_eq!( as OnRuntimeUpgrade>::on_runtime_upgrade(), 10) + assert_eq!( + as OnRuntimeUpgrade>::on_runtime_upgrade(), + Weight::from_ref_time(10) + ) }); } @@ -2852,12 +2861,20 @@ mod tests { // operational. assert_eq!( Call::::operational {}.get_dispatch_info(), - DispatchInfo { weight: 5, class: DispatchClass::Operational, pays_fee: Pays::Yes }, + DispatchInfo { + weight: Weight::from_ref_time(5), + class: DispatchClass::Operational, + pays_fee: Pays::Yes + }, ); // custom basic assert_eq!( Call::::aux_3 {}.get_dispatch_info(), - DispatchInfo { weight: 3, class: DispatchClass::Normal, pays_fee: Pays::Yes }, + DispatchInfo { + weight: Weight::from_ref_time(3), + class: DispatchClass::Normal, + pays_fee: Pays::Yes + }, ); } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 72551980bc7e9..a81a266fb9a3d 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1374,7 +1374,7 @@ pub mod pallet_prelude { ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, IsType, PalletInfoAccess, StorageInfoTrait, StorageVersion, TypedGet, }, - weights::{DispatchClass, Pays, Weight}, + weights::{DispatchClass, Pays, RefTimeWeight, Weight}, Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity, PartialEqNoBound, RuntimeDebug, RuntimeDebugNoBound, Twox128, Twox256, Twox64Concat, }; diff --git a/frame/support/src/migrations.rs b/frame/support/src/migrations.rs index f594b98ede4ff..b559d3aca615f 100644 --- a/frame/support/src/migrations.rs +++ b/frame/support/src/migrations.rs @@ -48,7 +48,7 @@ impl PalletVersionToStorageVersionHelpe #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl PalletVersionToStorageVersionHelper for T { fn migrate(db_weight: &RuntimeDbWeight) -> Weight { - let mut weight: Weight = 0; + let mut weight = Weight::new(); for_tuples!( #( weight = weight.saturating_add(T::migrate(db_weight)); )* ); diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index 2b7234006e0ff..f8e91886edf0c 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -17,8 +17,8 @@ //! Traits for hooking tasks to events in a blockchain's lifecycle. +use crate::weights::Weight; use impl_trait_for_tuples::impl_for_tuples; -use sp_arithmetic::traits::Saturating; use sp_runtime::traits::AtLeast32BitUnsigned; /// The block initialization trait. @@ -33,8 +33,8 @@ pub trait OnInitialize { /// NOTE: This function is called BEFORE ANY extrinsic in a block is applied, /// including inherent extrinsics. Hence for instance, if you runtime includes /// `pallet_timestamp`, the `timestamp` is not yet up to date at this point. - fn on_initialize(_n: BlockNumber) -> crate::weights::Weight { - 0 + fn on_initialize(_n: BlockNumber) -> Weight { + Weight::new() } } @@ -42,8 +42,8 @@ pub trait OnInitialize { #[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnInitialize for Tuple { - fn on_initialize(n: BlockNumber) -> crate::weights::Weight { - let mut weight = 0; + fn on_initialize(n: BlockNumber) -> Weight { + let mut weight = Weight::new(); for_tuples!( #( weight = weight.saturating_add(Tuple::on_initialize(n.clone())); )* ); weight } @@ -75,11 +75,8 @@ pub trait OnIdle { /// /// NOTE: This function is called AFTER ALL extrinsics - including inherent extrinsics - /// in a block are applied but before `on_finalize` is executed. - fn on_idle( - _n: BlockNumber, - _remaining_weight: crate::weights::Weight, - ) -> crate::weights::Weight { - 0 + fn on_idle(_n: BlockNumber, _remaining_weight: Weight) -> Weight { + Weight::new() } } @@ -87,12 +84,10 @@ pub trait OnIdle { #[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnIdle for Tuple { - fn on_idle(n: BlockNumber, remaining_weight: crate::weights::Weight) -> crate::weights::Weight { - let on_idle_functions: &[fn( - BlockNumber, - crate::weights::Weight, - ) -> crate::weights::Weight] = &[for_tuples!( #( Tuple::on_idle ),* )]; - let mut weight = 0; + fn on_idle(n: BlockNumber, remaining_weight: Weight) -> Weight { + let on_idle_functions: &[fn(BlockNumber, Weight) -> Weight] = + &[for_tuples!( #( Tuple::on_idle ),* )]; + let mut weight = Weight::new(); let len = on_idle_functions.len(); let start_index = n % (len as u32).into(); let start_index = start_index.try_into().ok().expect( @@ -174,8 +169,8 @@ pub trait OnRuntimeUpgrade { /// block local data are not accessible. /// /// Return the non-negotiable weight consumed for runtime upgrade. - fn on_runtime_upgrade() -> crate::weights::Weight { - 0 + fn on_runtime_upgrade() -> Weight { + Weight::new() } /// Execute some pre-checks prior to a runtime upgrade. @@ -199,8 +194,8 @@ pub trait OnRuntimeUpgrade { #[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnRuntimeUpgrade for Tuple { - fn on_runtime_upgrade() -> crate::weights::Weight { - let mut weight = 0; + fn on_runtime_upgrade() -> Weight { + let mut weight = Weight::new(); for_tuples!( #( weight = weight.saturating_add(Tuple::on_runtime_upgrade()); )* ); weight } @@ -243,18 +238,15 @@ pub trait Hooks { /// Will not fire if the remaining weight is 0. /// Return the weight used, the hook will subtract it from current weight used /// and pass the result to the next `on_idle` hook if it exists. - fn on_idle( - _n: BlockNumber, - _remaining_weight: crate::weights::Weight, - ) -> crate::weights::Weight { - 0 + fn on_idle(_n: BlockNumber, _remaining_weight: Weight) -> Weight { + Weight::new() } /// The block is being initialized. Implement to have something happen. /// /// Return the non-negotiable weight consumed in the block. - fn on_initialize(_n: BlockNumber) -> crate::weights::Weight { - 0 + fn on_initialize(_n: BlockNumber) -> Weight { + Weight::new() } /// Perform a module upgrade. @@ -276,8 +268,8 @@ pub trait Hooks { /// pallet is discouraged and might get deprecated in the future. Alternatively, export the same /// logic as a free-function from your pallet, and pass it to `type Executive` from the /// top-level runtime. - fn on_runtime_upgrade() -> crate::weights::Weight { - 0 + fn on_runtime_upgrade() -> Weight { + Weight::new() } /// Execute some pre-checks prior to a runtime upgrade. @@ -360,18 +352,18 @@ mod tests { fn on_initialize_and_on_runtime_upgrade_weight_merge_works() { struct Test; impl OnInitialize for Test { - fn on_initialize(_n: u8) -> crate::weights::Weight { - 10 + fn on_initialize(_n: u8) -> Weight { + Weight::from_ref_time(10) } } impl OnRuntimeUpgrade for Test { - fn on_runtime_upgrade() -> crate::weights::Weight { - 20 + fn on_runtime_upgrade() -> Weight { + Weight::from_ref_time(20) } } - assert_eq!(<(Test, Test)>::on_initialize(0), 20); - assert_eq!(<(Test, Test)>::on_runtime_upgrade(), 40); + assert_eq!(<(Test, Test)>::on_initialize(0), Weight::from_ref_time(20)); + assert_eq!(<(Test, Test)>::on_runtime_upgrade(), Weight::from_ref_time(40)); } #[test] @@ -383,48 +375,48 @@ mod tests { struct Test3; type TestTuple = (Test1, Test2, Test3); impl OnIdle for Test1 { - fn on_idle(_n: u32, _weight: crate::weights::Weight) -> crate::weights::Weight { + fn on_idle(_n: u32, _weight: Weight) -> Weight { unsafe { ON_IDLE_INVOCATION_ORDER.push("Test1"); } - 0 + Weight::zero() } } impl OnIdle for Test2 { - fn on_idle(_n: u32, _weight: crate::weights::Weight) -> crate::weights::Weight { + fn on_idle(_n: u32, _weight: Weight) -> Weight { unsafe { ON_IDLE_INVOCATION_ORDER.push("Test2"); } - 0 + Weight::zero() } } impl OnIdle for Test3 { - fn on_idle(_n: u32, _weight: crate::weights::Weight) -> crate::weights::Weight { + fn on_idle(_n: u32, _weight: Weight) -> Weight { unsafe { ON_IDLE_INVOCATION_ORDER.push("Test3"); } - 0 + Weight::zero() } } unsafe { - TestTuple::on_idle(0, 0); + TestTuple::on_idle(0, Weight::zero()); assert_eq!(ON_IDLE_INVOCATION_ORDER, ["Test1", "Test2", "Test3"].to_vec()); ON_IDLE_INVOCATION_ORDER.clear(); - TestTuple::on_idle(1, 0); + TestTuple::on_idle(1, Weight::zero()); assert_eq!(ON_IDLE_INVOCATION_ORDER, ["Test2", "Test3", "Test1"].to_vec()); ON_IDLE_INVOCATION_ORDER.clear(); - TestTuple::on_idle(2, 0); + TestTuple::on_idle(2, Weight::zero()); assert_eq!(ON_IDLE_INVOCATION_ORDER, ["Test3", "Test1", "Test2"].to_vec()); ON_IDLE_INVOCATION_ORDER.clear(); - TestTuple::on_idle(3, 0); + TestTuple::on_idle(3, Weight::zero()); assert_eq!(ON_IDLE_INVOCATION_ORDER, ["Test1", "Test2", "Test3"].to_vec()); ON_IDLE_INVOCATION_ORDER.clear(); - TestTuple::on_idle(4, 0); + TestTuple::on_idle(4, Weight::zero()); assert_eq!(ON_IDLE_INVOCATION_ORDER, ["Test2", "Test3", "Test1"].to_vec()); ON_IDLE_INVOCATION_ORDER.clear(); } diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index fb34484416063..568cb5535ccda 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -123,6 +123,7 @@ mod block_weights; mod extrinsic_weights; mod paritydb_weights; mod rocksdb_weights; +mod weight_v2; use crate::{ dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo}, @@ -146,18 +147,17 @@ use sp_runtime::{ /// Re-export priority as type pub use sp_runtime::transaction_validity::TransactionPriority; -/// Numeric range of a transaction weight. -pub type Weight = u64; +pub use weight_v2::*; /// These constants are specific to FRAME, and the current implementation of its various components. /// For example: FRAME System, FRAME Executive, our FRAME support libraries, etc... pub mod constants { use super::Weight; - pub const WEIGHT_PER_SECOND: Weight = 1_000_000_000_000; - pub const WEIGHT_PER_MILLIS: Weight = WEIGHT_PER_SECOND / 1000; // 1_000_000_000 - pub const WEIGHT_PER_MICROS: Weight = WEIGHT_PER_MILLIS / 1000; // 1_000_000 - pub const WEIGHT_PER_NANOS: Weight = WEIGHT_PER_MICROS / 1000; // 1_000 + pub const WEIGHT_PER_SECOND: Weight = Weight::from_ref_time(1_000_000_000_000); + pub const WEIGHT_PER_MILLIS: Weight = Weight::from_ref_time(1_000_000_000); + pub const WEIGHT_PER_MICROS: Weight = Weight::from_ref_time(1_000_000); + pub const WEIGHT_PER_NANOS: Weight = Weight::from_ref_time(1_000); // Expose the Block and Extrinsic base weights. pub use super::{block_weights::BlockExecutionWeight, extrinsic_weights::ExtrinsicBaseWeight}; @@ -204,6 +204,12 @@ impl Default for Pays { } } +impl From for PostDispatchInfo { + fn from(pays_fee: Pays) -> Self { + Self { actual_weight: None, pays_fee } + } +} + /// A generalized group of dispatch types. /// /// NOTE whenever upgrading the enum make sure to also update @@ -359,25 +365,6 @@ pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &Dispa .pays_fee(info) } -impl From<(Option, Pays)> for PostDispatchInfo { - fn from(post_weight_info: (Option, Pays)) -> Self { - let (actual_weight, pays_fee) = post_weight_info; - Self { actual_weight, pays_fee } - } -} - -impl From for PostDispatchInfo { - fn from(pays_fee: Pays) -> Self { - Self { actual_weight: None, pays_fee } - } -} - -impl From> for PostDispatchInfo { - fn from(actual_weight: Option) -> Self { - Self { actual_weight, pays_fee: Default::default() } - } -} - impl From<()> for PostDispatchInfo { fn from(_: ()) -> Self { Self { actual_weight: None, pays_fee: Default::default() } @@ -407,7 +394,7 @@ pub trait WithPostDispatchInfo { /// # Example /// /// ```ignore - /// let who = ensure_signed(origin).map_err(|e| e.with_weight(100))?; + /// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100)))?; /// ensure!(who == me, Error::::NotMe.with_weight(200_000)); /// ``` fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo; @@ -428,78 +415,6 @@ where } } -impl WeighData for Weight { - fn weigh_data(&self, _: T) -> Weight { - *self - } -} - -impl ClassifyDispatch for Weight { - fn classify_dispatch(&self, _: T) -> DispatchClass { - DispatchClass::Normal - } -} - -impl PaysFee for Weight { - fn pays_fee(&self, _: T) -> Pays { - Pays::Yes - } -} - -impl WeighData for (Weight, DispatchClass, Pays) { - fn weigh_data(&self, _: T) -> Weight { - self.0 - } -} - -impl ClassifyDispatch for (Weight, DispatchClass, Pays) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - self.1 - } -} - -impl PaysFee for (Weight, DispatchClass, Pays) { - fn pays_fee(&self, _: T) -> Pays { - self.2 - } -} - -impl WeighData for (Weight, DispatchClass) { - fn weigh_data(&self, _: T) -> Weight { - self.0 - } -} - -impl ClassifyDispatch for (Weight, DispatchClass) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - self.1 - } -} - -impl PaysFee for (Weight, DispatchClass) { - fn pays_fee(&self, _: T) -> Pays { - Pays::Yes - } -} - -impl WeighData for (Weight, Pays) { - fn weigh_data(&self, _: T) -> Weight { - self.0 - } -} - -impl ClassifyDispatch for (Weight, Pays) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - DispatchClass::Normal - } -} - -impl PaysFee for (Weight, Pays) { - fn pays_fee(&self, _: T) -> Pays { - self.1 - } -} - /// Implementation for unchecked extrinsic. impl GetDispatchInfo for UncheckedExtrinsic @@ -527,30 +442,37 @@ where impl GetDispatchInfo for sp_runtime::testing::TestXt { fn get_dispatch_info(&self) -> DispatchInfo { // for testing: weight == size. - DispatchInfo { weight: self.encode().len() as _, pays_fee: Pays::Yes, ..Default::default() } + DispatchInfo { + weight: Weight::from_ref_time(self.encode().len() as _), + pays_fee: Pays::Yes, + ..Default::default() + } } } /// The weight of database operations that the runtime can invoke. +/// +/// NOTE: This is currently only measured in computational time, and will probably +/// be updated all together once proof size is accounted for. #[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] pub struct RuntimeDbWeight { - pub read: Weight, - pub write: Weight, + pub read: RefTimeWeight, + pub write: RefTimeWeight, } impl RuntimeDbWeight { - pub fn reads(self, r: Weight) -> Weight { - self.read.saturating_mul(r) + pub fn reads(self, r: u64) -> Weight { + Weight::from_ref_time(self.read.saturating_mul(r)) } - pub fn writes(self, w: Weight) -> Weight { - self.write.saturating_mul(w) + pub fn writes(self, w: u64) -> Weight { + Weight::from_ref_time(self.write.saturating_mul(w)) } - pub fn reads_writes(self, r: Weight, w: Weight) -> Weight { + pub fn reads_writes(self, r: u64, w: u64) -> Weight { let read_weight = self.read.saturating_mul(r); let write_weight = self.write.saturating_mul(w); - read_weight.saturating_add(write_weight) + Weight::from_ref_time(read_weight.saturating_add(write_weight)) } } @@ -618,7 +540,8 @@ where Self::polynomial() .iter() .fold(Self::Balance::saturated_from(0u32), |mut acc, args| { - let w = Self::Balance::saturated_from(*weight).saturating_pow(args.degree.into()); + let w = Self::Balance::saturated_from(weight.ref_time()) + .saturating_pow(args.degree.into()); // The sum could get negative. Therefore we only sum with the accumulator. // The Perbill Mul implementation is non overflowing. @@ -648,7 +571,7 @@ where type Balance = T; fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(*weight) + Self::Balance::saturated_from(weight.ref_time()) } } @@ -671,7 +594,7 @@ where type Balance = T; fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(*weight).saturating_mul(M::get()) + Self::Balance::saturated_from(weight.ref_time()).saturating_mul(M::get()) } } @@ -727,7 +650,7 @@ impl PerDispatchClass { impl PerDispatchClass { /// Returns the total weight consumed by all extrinsics in the block. pub fn total(&self) -> Weight { - let mut sum = 0; + let mut sum = Weight::new(); for class in DispatchClass::all() { sum = sum.saturating_add(*self.get(*class)); } @@ -744,7 +667,7 @@ impl PerDispatchClass { /// occur. pub fn checked_add(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> { let value = self.get_mut(class); - *value = value.checked_add(weight).ok_or(())?; + *value = value.checked_add(&weight).ok_or(())?; Ok(()) } @@ -804,16 +727,16 @@ mod tests { fn f03(_origin) { unimplemented!(); } // weight = a x 10 + b - #[weight = ((_a * 10 + _eb * 1) as Weight, DispatchClass::Normal, Pays::Yes)] + #[weight = ((_a * 10 + _eb * 1) as RefTimeWeight, DispatchClass::Normal, Pays::Yes)] fn f11(_origin, _a: u32, _eb: u32) { unimplemented!(); } #[weight = (0, DispatchClass::Operational, Pays::Yes)] fn f12(_origin, _a: u32, _eb: u32) { unimplemented!(); } - #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + 10_000] + #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_ref_time(10_000)] fn f20(_origin) { unimplemented!(); } - #[weight = T::DbWeight::get().reads_writes(6, 5) + 40_000] + #[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_ref_time(40_000)] fn f21(_origin) { unimplemented!(); } } @@ -823,80 +746,98 @@ mod tests { fn weights_are_correct() { // #[weight = 1000] let info = Call::::f00 {}.get_dispatch_info(); - assert_eq!(info.weight, 1000); + assert_eq!(info.weight, Weight::from_ref_time(1000)); assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::Yes); // #[weight = (1000, DispatchClass::Mandatory)] let info = Call::::f01 {}.get_dispatch_info(); - assert_eq!(info.weight, 1000); + assert_eq!(info.weight, Weight::from_ref_time(1000)); assert_eq!(info.class, DispatchClass::Mandatory); assert_eq!(info.pays_fee, Pays::Yes); // #[weight = (1000, Pays::No)] let info = Call::::f02 {}.get_dispatch_info(); - assert_eq!(info.weight, 1000); + assert_eq!(info.weight, Weight::from_ref_time(1000)); assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::No); // #[weight = (1000, DispatchClass::Operational, Pays::No)] let info = Call::::f03 {}.get_dispatch_info(); - assert_eq!(info.weight, 1000); + assert_eq!(info.weight, Weight::from_ref_time(1000)); assert_eq!(info.class, DispatchClass::Operational); assert_eq!(info.pays_fee, Pays::No); // #[weight = ((_a * 10 + _eb * 1) as Weight, DispatchClass::Normal, Pays::Yes)] let info = Call::::f11 { _a: 13, _eb: 20 }.get_dispatch_info(); - assert_eq!(info.weight, 150); // 13*10 + 20 + assert_eq!(info.weight, Weight::from_ref_time(150)); // 13*10 + 20 assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::Yes); // #[weight = (0, DispatchClass::Operational, Pays::Yes)] let info = Call::::f12 { _a: 10, _eb: 20 }.get_dispatch_info(); - assert_eq!(info.weight, 0); + assert_eq!(info.weight, Weight::from_ref_time(0)); assert_eq!(info.class, DispatchClass::Operational); assert_eq!(info.pays_fee, Pays::Yes); // #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + 10_000] let info = Call::::f20 {}.get_dispatch_info(); - assert_eq!(info.weight, 12300); // 100*3 + 1000*2 + 10_1000 + assert_eq!(info.weight, Weight::from_ref_time(12300)); // 100*3 + 1000*2 + 10_1000 assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::Yes); // #[weight = T::DbWeight::get().reads_writes(6, 5) + 40_000] let info = Call::::f21 {}.get_dispatch_info(); - assert_eq!(info.weight, 45600); // 100*6 + 1000*5 + 40_1000 + assert_eq!(info.weight, Weight::from_ref_time(45600)); // 100*6 + 1000*5 + 40_1000 assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::Yes); } #[test] fn extract_actual_weight_works() { - let pre = DispatchInfo { weight: 1000, ..Default::default() }; - assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), 7); - assert_eq!(extract_actual_weight(&Ok(Some(1000).into()), &pre), 1000); - assert_eq!(extract_actual_weight(&Err(DispatchError::BadOrigin.with_weight(9)), &pre), 9); + let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; + assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), Weight::from_ref_time(7)); + assert_eq!( + extract_actual_weight(&Ok(Some(1000).into()), &pre), + Weight::from_ref_time(1000) + ); + assert_eq!( + extract_actual_weight( + &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), + &pre + ), + Weight::from_ref_time(9) + ); } #[test] fn extract_actual_weight_caps_at_pre_weight() { - let pre = DispatchInfo { weight: 1000, ..Default::default() }; - assert_eq!(extract_actual_weight(&Ok(Some(1250).into()), &pre), 1000); + let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; assert_eq!( - extract_actual_weight(&Err(DispatchError::BadOrigin.with_weight(1300)), &pre), - 1000 + extract_actual_weight(&Ok(Some(1250).into()), &pre), + Weight::from_ref_time(1000) + ); + assert_eq!( + extract_actual_weight( + &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(1300))), + &pre + ), + Weight::from_ref_time(1000), ); } #[test] fn extract_actual_pays_fee_works() { - let pre = DispatchInfo { weight: 1000, ..Default::default() }; + let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::Yes); assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::Yes); assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::Yes); assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::No).into()), &pre), Pays::No); assert_eq!( - extract_actual_pays_fee(&Err(DispatchError::BadOrigin.with_weight(9)), &pre), + extract_actual_pays_fee( + &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), + &pre + ), Pays::Yes ); assert_eq!( @@ -910,7 +851,11 @@ mod tests { Pays::No ); - let pre = DispatchInfo { weight: 1000, pays_fee: Pays::No, ..Default::default() }; + let pre = DispatchInfo { + weight: Weight::from_ref_time(1000), + pays_fee: Pays::No, + ..Default::default() + }; assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::No); assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::No); assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::No); @@ -956,40 +901,52 @@ mod tests { #[test] fn polynomial_works() { // 100^3/2=500000 100^2*(2+1/3)=23333 700 -10000 - assert_eq!(Poly::weight_to_fee(&100), 514033); + assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(100)), 514033); // 10123^3/2=518677865433 10123^2*(2+1/3)=239108634 70861 -10000 - assert_eq!(Poly::weight_to_fee(&10_123), 518917034928); + assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10_123)), 518917034928); } #[test] fn polynomial_does_not_underflow() { - assert_eq!(Poly::weight_to_fee(&0), 0); - assert_eq!(Poly::weight_to_fee(&10), 0); + assert_eq!(Poly::weight_to_fee(&Weight::zero()), 0); + assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10)), 0); } #[test] fn polynomial_does_not_overflow() { - assert_eq!(Poly::weight_to_fee(&Weight::max_value()), Balance::max_value() - 10_000); + assert_eq!(Poly::weight_to_fee(&Weight::MAX), Balance::max_value() - 10_000); } #[test] fn identity_fee_works() { - assert_eq!(IdentityFee::::weight_to_fee(&0), 0); - assert_eq!(IdentityFee::::weight_to_fee(&50), 50); - assert_eq!( - IdentityFee::::weight_to_fee(&Weight::max_value()), - Balance::max_value() - ); + assert_eq!(IdentityFee::::weight_to_fee(&Weight::zero()), 0); + assert_eq!(IdentityFee::::weight_to_fee(&Weight::from_ref_time(50)), 50); + assert_eq!(IdentityFee::::weight_to_fee(&Weight::MAX), Balance::max_value()); } #[test] fn constant_fee_works() { use crate::traits::ConstU128; - assert_eq!(ConstantMultiplier::>::weight_to_fee(&0), 0); - assert_eq!(ConstantMultiplier::>::weight_to_fee(&50), 500); - assert_eq!(ConstantMultiplier::>::weight_to_fee(&16), 16384); assert_eq!( - ConstantMultiplier::>::weight_to_fee(&2), + ConstantMultiplier::>::weight_to_fee(&Weight::zero()), + 0 + ); + assert_eq!( + ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( + 50 + )), + 500 + ); + assert_eq!( + ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( + 16 + )), + 16384 + ); + assert_eq!( + ConstantMultiplier::>::weight_to_fee( + &Weight::from_ref_time(2) + ), u128::MAX ); } diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index b86334514af2f..93a80d12db96b 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -53,7 +53,7 @@ parameter_types! { /// 99th: 5_489_273 /// 95th: 5_433_314 /// 75th: 5_354_812 - pub const BlockExecutionWeight: Weight = 5_346_284 * WEIGHT_PER_NANOS; + pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul(5_346_284); } #[cfg(test)] diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index b8a52c164d8fe..d223eb7c10efc 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -53,7 +53,7 @@ parameter_types! { /// 99th: 86_924 /// 95th: 86_828 /// 75th: 86_347 - pub const ExtrinsicBaseWeight: Weight = 86_298 * WEIGHT_PER_NANOS; + pub const ExtrinsicBaseWeight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul(86_298); } #[cfg(test)] diff --git a/frame/support/src/weights/paritydb_weights.rs b/frame/support/src/weights/paritydb_weights.rs index 572187ba78a92..f498991729d7a 100644 --- a/frame/support/src/weights/paritydb_weights.rs +++ b/frame/support/src/weights/paritydb_weights.rs @@ -25,8 +25,8 @@ pub mod constants { /// ParityDB can be enabled with a feature flag, but is still experimental. These weights /// are available for brave runtime engineers who may want to try this out as default. pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 8_000 * constants::WEIGHT_PER_NANOS, - write: 50_000 * constants::WEIGHT_PER_NANOS, + read: 8_000 * constants::WEIGHT_PER_NANOS.ref_time(), + write: 50_000 * constants::WEIGHT_PER_NANOS.ref_time(), }; } diff --git a/frame/support/src/weights/rocksdb_weights.rs b/frame/support/src/weights/rocksdb_weights.rs index f37964dcbd825..67571c4723f94 100644 --- a/frame/support/src/weights/rocksdb_weights.rs +++ b/frame/support/src/weights/rocksdb_weights.rs @@ -25,8 +25,8 @@ pub mod constants { /// By default, Substrate uses RocksDB, so this will be the weight used throughout /// the runtime. pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 25_000 * constants::WEIGHT_PER_NANOS, - write: 100_000 * constants::WEIGHT_PER_NANOS, + read: 25_000 * constants::WEIGHT_PER_NANOS.ref_time(), + write: 100_000 * constants::WEIGHT_PER_NANOS.ref_time(), }; } diff --git a/frame/support/src/weights/weight_v2.rs b/frame/support/src/weights/weight_v2.rs new file mode 100644 index 0000000000000..d02aac3268838 --- /dev/null +++ b/frame/support/src/weights/weight_v2.rs @@ -0,0 +1,483 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; +use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign}; +use sp_runtime::{ + traits::{Bounded, CheckedAdd, CheckedSub, One, Zero}, + Perquintill, RuntimeDebug, +}; + +use super::*; + +/// The unit of measurement for computational time spent when executing runtime logic on reference +/// hardware. +pub type RefTimeWeight = u64; + +#[derive( + Encode, + Decode, + MaxEncodedLen, + TypeInfo, + Eq, + PartialEq, + Copy, + Clone, + RuntimeDebug, + Default, + Ord, + PartialOrd, + CompactAs, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Weight { + /// The weight of computational time used based on some reference hardware. + ref_time: RefTimeWeight, +} + +impl Weight { + /// Create a new Weight with zero. + pub const fn new() -> Self { + Self { ref_time: 0 } + } + + /// Set the reference time part of the weight. + pub const fn set_ref_time(mut self, c: RefTimeWeight) -> Self { + self.ref_time = c; + self + } + + /// Return the reference time part of the weight. + pub const fn ref_time(&self) -> RefTimeWeight { + self.ref_time + } + + /// Return a mutable reference time part of the weight. + pub fn ref_time_mut(&mut self) -> &mut RefTimeWeight { + &mut self.ref_time + } + + pub const MAX: Self = Self { ref_time: RefTimeWeight::MAX }; + + /// Get the conservative min of `self` and `other` weight. + pub fn min(&self, other: Self) -> Self { + Self { ref_time: self.ref_time.min(other.ref_time) } + } + + /// Get the aggressive max of `self` and `other` weight. + pub fn max(&self, other: Self) -> Self { + Self { ref_time: self.ref_time.max(other.ref_time) } + } + + /// Try to add some `other` weight while upholding the `limit`. + pub fn try_add(&self, other: &Self, limit: &Self) -> Option { + let total = self.checked_add(other)?; + if total.ref_time > limit.ref_time { + None + } else { + Some(total) + } + } + + /// Construct with reference time weight. + pub const fn from_ref_time(ref_time: RefTimeWeight) -> Self { + Self { ref_time } + } + + pub fn checked_mul(self, rhs: u64) -> Option { + let ref_time = self.ref_time.checked_mul(rhs)?; + Some(Self { ref_time }) + } + + pub fn checked_div(self, rhs: u64) -> Option { + let ref_time = self.ref_time.checked_div(rhs)?; + Some(Self { ref_time }) + } + + pub const fn scalar_saturating_mul(self, rhs: u64) -> Self { + Self { ref_time: self.ref_time.saturating_mul(rhs) } + } + + pub const fn scalar_div(self, rhs: u64) -> Self { + Self { ref_time: self.ref_time / rhs } + } +} + +impl Zero for Weight { + fn zero() -> Self { + Self::zero() + } + + fn is_zero(&self) -> bool { + self.ref_time == 0 + } +} + +impl One for Weight { + fn one() -> Self { + Self::one() + } +} + +impl Add for Weight { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Self { ref_time: self.ref_time + rhs.ref_time } + } +} + +impl Sub for Weight { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + Self { ref_time: self.ref_time - rhs.ref_time } + } +} + +impl Mul for Weight { + type Output = Self; + fn mul(self, b: Self) -> Self { + Self { ref_time: b.ref_time * self.ref_time } + } +} + +impl Mul for Weight +where + T: Mul + Copy, +{ + type Output = Self; + fn mul(self, b: T) -> Self { + Self { ref_time: b * self.ref_time } + } +} + +impl Mul for Perbill { + type Output = Weight; + fn mul(self, b: Weight) -> Weight { + Weight { ref_time: self * b.ref_time } + } +} + +impl Mul for Perquintill { + type Output = Weight; + fn mul(self, b: Weight) -> Weight { + Weight { ref_time: self * b.ref_time } + } +} + +impl Mul for u64 { + type Output = Weight; + fn mul(self, b: Weight) -> Weight { + Weight { ref_time: self * b.ref_time } + } +} + +impl Div for Weight +where + u64: Div, + T: Copy, +{ + type Output = Self; + fn div(self, b: T) -> Self { + Self { ref_time: self.ref_time / b } + } +} + +impl Saturating for Weight { + fn saturating_add(self, rhs: Self) -> Self { + self.saturating_add(rhs) + } + + fn saturating_sub(self, rhs: Self) -> Self { + self.saturating_sub(rhs) + } + + fn saturating_mul(self, rhs: Self) -> Self { + self.saturating_mul(rhs) + } + + fn saturating_pow(self, exp: usize) -> Self { + self.saturating_pow(exp) + } +} + +impl CheckedAdd for Weight { + fn checked_add(&self, rhs: &Self) -> Option { + self.checked_add(rhs) + } +} + +impl CheckedSub for Weight { + fn checked_sub(&self, rhs: &Self) -> Option { + self.checked_sub(rhs) + } +} + +impl PaysFee for (Weight, DispatchClass, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.2 + } +} + +impl WeighData for (Weight, DispatchClass) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl WeighData for (Weight, DispatchClass, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (Weight, DispatchClass) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +impl PaysFee for (Weight, DispatchClass) { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl WeighData for (Weight, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (Weight, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for (Weight, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.1 + } +} + +impl From<(Option, Pays)> for PostDispatchInfo { + fn from(post_weight_info: (Option, Pays)) -> Self { + let (actual_weight, pays_fee) = post_weight_info; + Self { actual_weight, pays_fee } + } +} + +impl From> for PostDispatchInfo { + fn from(actual_weight: Option) -> Self { + Self { actual_weight, pays_fee: Default::default() } + } +} + +impl WeighData for Weight { + fn weigh_data(&self, _: T) -> Weight { + return *self + } +} + +impl ClassifyDispatch for Weight { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for Weight { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl ClassifyDispatch for (Weight, DispatchClass, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +impl core::fmt::Display for Weight { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Weight(ref_time: {})", self.ref_time) + } +} + +impl Bounded for Weight { + fn min_value() -> Self { + Zero::zero() + } + fn max_value() -> Self { + Self::MAX + } +} + +impl AddAssign for Weight { + fn add_assign(&mut self, other: Self) { + *self = Self { ref_time: self.ref_time + other.ref_time }; + } +} + +impl SubAssign for Weight { + fn sub_assign(&mut self, other: Self) { + *self = Self { ref_time: self.ref_time - other.ref_time }; + } +} + +impl sp_runtime::traits::Printable for Weight { + fn print(&self) { + self.ref_time().print() + } +} + +// Re-export common functions so you do not need to import trait. +impl Weight { + pub const fn zero() -> Self { + Self { ref_time: 0 } + } + + pub const fn one() -> Self { + Self { ref_time: 1 } + } + + pub const fn saturating_add(self, rhs: Self) -> Self { + Self { ref_time: self.ref_time.saturating_add(rhs.ref_time) } + } + + pub const fn saturating_sub(self, rhs: Self) -> Self { + Self { ref_time: self.ref_time.saturating_sub(rhs.ref_time) } + } + + pub const fn saturating_mul(self, rhs: Self) -> Self { + Self { ref_time: self.ref_time.saturating_mul(rhs.ref_time) } + } + + pub const fn saturating_pow(self, exp: usize) -> Self { + Self { ref_time: self.ref_time.saturating_pow(exp as u32) } + } + + pub const fn checked_add(&self, rhs: &Self) -> Option { + match self.ref_time.checked_add(rhs.ref_time) { + Some(ref_time) => Some(Self { ref_time }), + None => None, + } + } + + pub const fn checked_sub(&self, rhs: &Self) -> Option { + match self.ref_time.checked_sub(rhs.ref_time) { + Some(ref_time) => Some(Self { ref_time }), + None => None, + } + } +} + +// TODO: Eventually remove these + +impl From> for PostDispatchInfo { + fn from(maybe_actual_computation: Option) -> Self { + let actual_weight = match maybe_actual_computation { + Some(actual_computation) => Some(Weight::new().set_ref_time(actual_computation)), + None => None, + }; + Self { actual_weight, pays_fee: Default::default() } + } +} + +impl From<(Option, Pays)> for PostDispatchInfo { + fn from(post_weight_info: (Option, Pays)) -> Self { + let (maybe_actual_time, pays_fee) = post_weight_info; + let actual_weight = match maybe_actual_time { + Some(actual_time) => Some(Weight::new().set_ref_time(actual_time)), + None => None, + }; + Self { actual_weight, pays_fee } + } +} + +impl WeighData for RefTimeWeight { + fn weigh_data(&self, _: T) -> Weight { + return Weight::new().set_ref_time(*self) + } +} + +impl ClassifyDispatch for RefTimeWeight { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for RefTimeWeight { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl WeighData for (RefTimeWeight, DispatchClass, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (RefTimeWeight, DispatchClass, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +impl PaysFee for (RefTimeWeight, DispatchClass, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.2 + } +} + +impl WeighData for (RefTimeWeight, DispatchClass) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (RefTimeWeight, DispatchClass) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +impl PaysFee for (RefTimeWeight, DispatchClass) { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl WeighData for (RefTimeWeight, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (RefTimeWeight, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for (RefTimeWeight, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.1 + } +} + +// END TODO diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index d388127f29abd..aed98579a0fd8 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -503,17 +503,25 @@ fn call_encode_is_correct_and_decode_works() { fn call_weight_should_attach_to_call_enum() { use frame_support::{ dispatch::{DispatchInfo, GetDispatchInfo}, - weights::{DispatchClass, Pays}, + weights::{DispatchClass, Pays, Weight}, }; // operational. assert_eq!( module3::Call::::operational {}.get_dispatch_info(), - DispatchInfo { weight: 5, class: DispatchClass::Operational, pays_fee: Pays::Yes }, + DispatchInfo { + weight: Weight::from_ref_time(5), + class: DispatchClass::Operational, + pays_fee: Pays::Yes + }, ); // custom basic assert_eq!( module3::Call::::aux_4 {}.get_dispatch_info(), - DispatchInfo { weight: 3, class: DispatchClass::Normal, pays_fee: Pays::Yes }, + DispatchInfo { + weight: Weight::from_ref_time(3), + class: DispatchClass::Normal, + pays_fee: Pays::Yes + }, ); } diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 497b7bb04c36a..907a52f1184cc 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -23,7 +23,7 @@ use frame_support::{ ConstU32, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade, PalletError, PalletInfoAccess, StorageVersion, }, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, RuntimeDbWeight}, + weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, RuntimeDbWeight, Weight}, }; use scale_info::{meta_type, TypeInfo}; use sp_io::{ @@ -165,7 +165,7 @@ pub mod pallet { let _ = T::AccountId::from(SomeType1); // Test for where clause let _ = T::AccountId::from(SomeType2); // Test for where clause Self::deposit_event(Event::Something(10)); - 10 + Weight::from_ref_time(10) } fn on_finalize(_: BlockNumberFor) { let _ = T::AccountId::from(SomeType1); // Test for where clause @@ -176,7 +176,7 @@ pub mod pallet { let _ = T::AccountId::from(SomeType1); // Test for where clause let _ = T::AccountId::from(SomeType2); // Test for where clause Self::deposit_event(Event::Something(30)); - 30 + Weight::from_ref_time(30) } fn integrity_test() { let _ = T::AccountId::from(SomeType1); // Test for where clause @@ -190,7 +190,7 @@ pub mod pallet { T::AccountId: From + From + SomeAssociation1, { /// Doc comment put in metadata - #[pallet::weight(Weight::from(*_foo))] + #[pallet::weight(Weight::from_ref_time(*_foo as u64))] pub fn foo( origin: OriginFor, #[pallet::compact] _foo: u32, @@ -492,14 +492,14 @@ pub mod pallet2 { { fn on_initialize(_: BlockNumberFor) -> Weight { Self::deposit_event(Event::Something(11)); - 0 + Weight::zero() } fn on_finalize(_: BlockNumberFor) { Self::deposit_event(Event::Something(21)); } fn on_runtime_upgrade() -> Weight { Self::deposit_event(Event::Something(31)); - 0 + Weight::zero() } } @@ -668,7 +668,11 @@ fn call_expand() { let call_foo = pallet::Call::::foo { foo: 3, bar: 0 }; assert_eq!( call_foo.get_dispatch_info(), - DispatchInfo { weight: 3, class: DispatchClass::Normal, pays_fee: Pays::Yes } + DispatchInfo { + weight: frame_support::weights::Weight::from_ref_time(3), + class: DispatchClass::Normal, + pays_fee: Pays::Yes + } ); assert_eq!(call_foo.get_call_name(), "foo"); assert_eq!( @@ -1046,10 +1050,10 @@ fn pallet_hooks_expand() { TestExternalities::default().execute_with(|| { frame_system::Pallet::::set_block_number(1); - assert_eq!(AllPalletsWithoutSystem::on_initialize(1), 10); + assert_eq!(AllPalletsWithoutSystem::on_initialize(1), Weight::from_ref_time(10)); AllPalletsWithoutSystem::on_finalize(1); - assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), 30); + assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), Weight::from_ref_time(30)); assert_eq!( frame_system::Pallet::::events()[0].event, @@ -1085,10 +1089,16 @@ fn all_pallets_type_reversed_order_is_correct() { #[allow(deprecated)] { - assert_eq!(AllPalletsWithoutSystemReversed::on_initialize(1), 10); + assert_eq!( + AllPalletsWithoutSystemReversed::on_initialize(1), + Weight::from_ref_time(10) + ); AllPalletsWithoutSystemReversed::on_finalize(1); - assert_eq!(AllPalletsWithoutSystemReversed::on_runtime_upgrade(), 30); + assert_eq!( + AllPalletsWithoutSystemReversed::on_runtime_upgrade(), + Weight::from_ref_time(30) + ); } assert_eq!( @@ -1155,7 +1165,7 @@ fn migrate_from_pallet_version_to_storage_version() { >(&db_weight); // 4 pallets, 2 writes and every write costs 5 weight. - assert_eq!(4 * 2 * 5, weight); + assert_eq!(Weight::from_ref_time(4 * 2 * 5), weight); // All pallet versions should be removed assert!(sp_io::storage::get(&pallet_version_key(Example::name())).is_none()); diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index 9327f5b6a3304..4d597e24356c7 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -31,7 +31,10 @@ impl SomeAssociation for u64 { mod pallet_old { use super::SomeAssociation; use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, traits::Get, weights::Weight, Parameter, + decl_error, decl_event, decl_module, decl_storage, + traits::Get, + weights::{RefTimeWeight, Weight}, + Parameter, }; use frame_system::ensure_root; @@ -40,7 +43,7 @@ mod pallet_old { type Balance: Parameter + codec::HasCompact + From - + Into + + Into + Default + SomeAssociation; type Event: From> + Into<::Event>; @@ -75,7 +78,7 @@ mod pallet_old { fn deposit_event() = default; const SomeConst: T::Balance = T::SomeConst::get(); - #[weight = >::into(new_value.clone())] + #[weight = >::into(new_value.clone())] fn set_dummy(origin, #[compact] new_value: T::Balance) { ensure_root(origin)?; @@ -85,7 +88,7 @@ mod pallet_old { fn on_initialize(_n: T::BlockNumber) -> Weight { >::put(T::Balance::from(10)); - 10 + Weight::from_ref_time(10) } fn on_finalize(_n: T::BlockNumber) { @@ -113,7 +116,7 @@ pub mod pallet { type Balance: Parameter + codec::HasCompact + From - + Into + + Into + Default + MaybeSerializeDeserialize + SomeAssociation @@ -131,7 +134,7 @@ pub mod pallet { impl Hooks for Pallet { fn on_initialize(_n: T::BlockNumber) -> Weight { >::put(T::Balance::from(10)); - 10 + Weight::from_ref_time(10) } fn on_finalize(_n: T::BlockNumber) { @@ -141,7 +144,7 @@ pub mod pallet { #[pallet::call] impl Pallet { - #[pallet::weight(>::into(new_value.clone()))] + #[pallet::weight(>::into(new_value.clone()))] pub fn set_dummy( origin: OriginFor, #[pallet::compact] new_value: T::Balance, diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 3de45df223674..2fd6833eaa428 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -23,13 +23,16 @@ use frame_support::traits::{ConstU32, ConstU64}; mod pallet_old { use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, traits::Get, weights::Weight, Parameter, + decl_error, decl_event, decl_module, decl_storage, + traits::Get, + weights::{RefTimeWeight, Weight}, + Parameter, }; use frame_system::ensure_root; pub trait Config: frame_system::Config { type SomeConst: Get; - type Balance: Parameter + codec::HasCompact + From + Into + Default; + type Balance: Parameter + codec::HasCompact + From + Into + Default; type Event: From> + Into<::Event>; } @@ -62,7 +65,7 @@ mod pallet_old { fn deposit_event() = default; const SomeConst: T::Balance = T::SomeConst::get(); - #[weight = >::into(new_value.clone())] + #[weight = >::into(new_value.clone())] fn set_dummy(origin, #[compact] new_value: T::Balance) { ensure_root(origin)?; @@ -72,7 +75,7 @@ mod pallet_old { fn on_initialize(_n: T::BlockNumber) -> Weight { >::put(T::Balance::from(10)); - 10 + Weight::from_ref_time(10) } fn on_finalize(_n: T::BlockNumber) { @@ -99,7 +102,7 @@ pub mod pallet { type Balance: Parameter + codec::HasCompact + From - + Into + + Into + Default + MaybeSerializeDeserialize + scale_info::StaticTypeInfo; @@ -116,7 +119,7 @@ pub mod pallet { impl, I: 'static> Hooks for Pallet { fn on_initialize(_n: T::BlockNumber) -> Weight { >::put(T::Balance::from(10)); - 10 + Weight::from_ref_time(10) } fn on_finalize(_n: T::BlockNumber) { @@ -126,7 +129,7 @@ pub mod pallet { #[pallet::call] impl, I: 'static> Pallet { - #[pallet::weight(>::into(new_value.clone()))] + #[pallet::weight(>::into(new_value.clone()))] pub fn set_dummy( origin: OriginFor, #[pallet::compact] new_value: T::Balance, diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index f4ef5f802c44f..2ae910e73d87e 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -54,10 +54,10 @@ pub mod pallet { fn on_initialize(_: BlockNumberFor) -> Weight { if TypeId::of::() == TypeId::of::<()>() { Self::deposit_event(Event::Something(10)); - 10 + Weight::from_ref_time(10) } else { Self::deposit_event(Event::Something(11)); - 11 + Weight::from_ref_time(11) } } fn on_finalize(_: BlockNumberFor) { @@ -70,10 +70,10 @@ pub mod pallet { fn on_runtime_upgrade() -> Weight { if TypeId::of::() == TypeId::of::<()>() { Self::deposit_event(Event::Something(30)); - 30 + Weight::from_ref_time(30) } else { Self::deposit_event(Event::Something(31)); - 31 + Weight::from_ref_time(31) } } fn integrity_test() {} @@ -82,7 +82,7 @@ pub mod pallet { #[pallet::call] impl, I: 'static> Pallet { /// Doc comment put in metadata - #[pallet::weight(Weight::from(*_foo))] + #[pallet::weight(Weight::from_ref_time(*_foo as u64))] pub fn foo( origin: OriginFor, #[pallet::compact] _foo: u32, @@ -345,12 +345,18 @@ frame_support::construct_runtime!( } ); +use frame_support::weights::Weight; + #[test] fn call_expand() { let call_foo = pallet::Call::::foo { foo: 3 }; assert_eq!( call_foo.get_dispatch_info(), - DispatchInfo { weight: 3, class: DispatchClass::Normal, pays_fee: Pays::Yes } + DispatchInfo { + weight: Weight::from_ref_time(3), + class: DispatchClass::Normal, + pays_fee: Pays::Yes + } ); assert_eq!(call_foo.get_call_name(), "foo"); assert_eq!(pallet::Call::::get_call_names(), &["foo", "foo_storage_layer"]); @@ -358,7 +364,11 @@ fn call_expand() { let call_foo = pallet::Call::::foo { foo: 3 }; assert_eq!( call_foo.get_dispatch_info(), - DispatchInfo { weight: 3, class: DispatchClass::Normal, pays_fee: Pays::Yes } + DispatchInfo { + weight: Weight::from_ref_time(3), + class: DispatchClass::Normal, + pays_fee: Pays::Yes + } ); assert_eq!(call_foo.get_call_name(), "foo"); assert_eq!( @@ -651,10 +661,10 @@ fn pallet_hooks_expand() { TestExternalities::default().execute_with(|| { frame_system::Pallet::::set_block_number(1); - assert_eq!(AllPalletsWithoutSystem::on_initialize(1), 21); + assert_eq!(AllPalletsWithoutSystem::on_initialize(1), Weight::from_ref_time(21)); AllPalletsWithoutSystem::on_finalize(1); - assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), 61); + assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), Weight::from_ref_time(61)); assert_eq!( frame_system::Pallet::::events()[0].event, diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index 45cdfad67b8ae..e674e49eddbe5 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) - and 158 others + and 159 others = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index d7441e8b18562..ecdc18263432e 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) - and 158 others + and 159 others = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index 6c49e1220a3a5..d9cd20711403d 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -13,5 +13,5 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 75 others + and 76 others = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 9a0731683a953..9a4e8d740cb2c 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -13,6 +13,6 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 75 others + and 76 others = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` diff --git a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs index 7ed8454668327..6415c3c0d2c07 100644 --- a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs +++ b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs @@ -54,7 +54,7 @@ frame_support::decl_module! { } fn on_initialize(_n: T::BlockNumber) -> frame_support::weights::Weight { - 0 + frame_support::weights::Weight::zero() } } } diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index 0bc34fcbc5be2..017298dab3928 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -16,7 +16,10 @@ // limitations under the License. use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use frame_support::traits::{ConstU32, ConstU64}; +use frame_support::{ + traits::{ConstU32, ConstU64}, + weights::Weight, +}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -61,7 +64,7 @@ frame_support::construct_runtime!( frame_support::parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::with_sensible_defaults( - 4 * 1024 * 1024, Perbill::from_percent(75), + Weight::from_ref_time(4 * 1024 * 1024), Perbill::from_percent(75), ); pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength::max_with_normal_ratio( diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index 5090093fe168f..59a6e14aca175 100644 --- a/frame/system/src/extensions/check_mortality.rs +++ b/frame/system/src/extensions/check_mortality.rs @@ -101,7 +101,7 @@ impl SignedExtension for CheckMortality { mod tests { use super::*; use crate::mock::{new_test_ext, System, Test, CALL}; - use frame_support::weights::{DispatchClass, DispatchInfo, Pays}; + use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight}; use sp_core::H256; #[test] @@ -126,8 +126,11 @@ mod tests { #[test] fn signed_ext_check_era_should_change_longevity() { new_test_ext().execute_with(|| { - let normal = - DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; + let normal = DispatchInfo { + weight: Weight::from_ref_time(100), + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }; let len = 0_usize; let ext = ( crate::CheckWeight::::new(), diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index b59c36ecb53b5..b7232c430696d 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -19,7 +19,7 @@ use crate::{limits::BlockWeights, Config, Pallet}; use codec::{Decode, Encode}; use frame_support::{ traits::Get, - weights::{DispatchClass, DispatchInfo, PostDispatchInfo}, + weights::{DispatchClass, DispatchInfo, PostDispatchInfo, Weight}, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -238,7 +238,7 @@ where } let unspent = post_info.calc_unspent(info); - if unspent > 0 { + if unspent > Weight::zero() { crate::BlockWeight::::mutate(|current_weight| { current_weight.sub(unspent, info.class); }) @@ -297,7 +297,7 @@ mod tests { fn check(call: impl FnOnce(&DispatchInfo, usize)) { new_test_ext().execute_with(|| { let max = DispatchInfo { - weight: Weight::max_value(), + weight: Weight::MAX, class: DispatchClass::Mandatory, ..Default::default() }; @@ -309,7 +309,7 @@ mod tests { check(|max, len| { assert_ok!(CheckWeight::::do_pre_dispatch(max, len)); - assert_eq!(System::block_weight().total(), Weight::max_value()); + assert_eq!(System::block_weight().total(), Weight::MAX); assert!(System::block_weight().total() > block_weight_limit()); }); check(|max, len| { @@ -321,7 +321,8 @@ mod tests { fn normal_extrinsic_limited_by_maximum_extrinsic_weight() { new_test_ext().execute_with(|| { let max = DispatchInfo { - weight: block_weights().get(DispatchClass::Normal).max_extrinsic.unwrap() + 1, + weight: block_weights().get(DispatchClass::Normal).max_extrinsic.unwrap() + + Weight::one(), class: DispatchClass::Normal, ..Default::default() }; @@ -347,7 +348,7 @@ mod tests { let okay = DispatchInfo { weight, class: DispatchClass::Operational, ..Default::default() }; let max = DispatchInfo { - weight: weight + 1, + weight: weight + Weight::one(), class: DispatchClass::Operational, ..Default::default() }; @@ -364,8 +365,8 @@ mod tests { #[test] fn register_extra_weight_unchecked_doesnt_care_about_limits() { new_test_ext().execute_with(|| { - System::register_extra_weight_unchecked(Weight::max_value(), DispatchClass::Normal); - assert_eq!(System::block_weight().total(), Weight::max_value()); + System::register_extra_weight_unchecked(Weight::MAX, DispatchClass::Normal); + assert_eq!(System::block_weight().total(), Weight::MAX); assert!(System::block_weight().total() > block_weight_limit()); }); } @@ -378,9 +379,10 @@ mod tests { // 10 is taken for block execution weight // So normal extrinsic can be 758 weight (-5 for base extrinsic weight) // And Operational can be 256 to produce a full block (-5 for base) - let max_normal = DispatchInfo { weight: 753, ..Default::default() }; + let max_normal = + DispatchInfo { weight: Weight::from_ref_time(753), ..Default::default() }; let rest_operational = DispatchInfo { - weight: 251, + weight: Weight::from_ref_time(251), class: DispatchClass::Operational, ..Default::default() }; @@ -388,9 +390,9 @@ mod tests { let len = 0_usize; assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); - assert_eq!(System::block_weight().total(), 768); + assert_eq!(System::block_weight().total(), Weight::from_ref_time(768)); assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); - assert_eq!(block_weight_limit(), 1024); + assert_eq!(block_weight_limit(), Weight::from_ref_time(1024)); assert_eq!(System::block_weight().total(), block_weight_limit()); // Checking single extrinsic should not take current block weight into account. assert_eq!(CheckWeight::::check_extrinsic_weight(&rest_operational), Ok(())); @@ -401,9 +403,10 @@ mod tests { fn dispatch_order_does_not_effect_weight_logic() { new_test_ext().execute_with(|| { // We switch the order of `full_block_with_normal_and_operational` - let max_normal = DispatchInfo { weight: 753, ..Default::default() }; + let max_normal = + DispatchInfo { weight: Weight::from_ref_time(753), ..Default::default() }; let rest_operational = DispatchInfo { - weight: 251, + weight: Weight::from_ref_time(251), class: DispatchClass::Operational, ..Default::default() }; @@ -412,9 +415,9 @@ mod tests { assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); // Extra 15 here from block execution + base extrinsic weight - assert_eq!(System::block_weight().total(), 266); + assert_eq!(System::block_weight().total(), Weight::from_ref_time(266)); assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); - assert_eq!(block_weight_limit(), 1024); + assert_eq!(block_weight_limit(), Weight::from_ref_time(1024)); assert_eq!(System::block_weight().total(), block_weight_limit()); }); } @@ -423,11 +426,14 @@ mod tests { fn operational_works_on_full_block() { new_test_ext().execute_with(|| { // An on_initialize takes up the whole block! (Every time!) - System::register_extra_weight_unchecked(Weight::max_value(), DispatchClass::Mandatory); - let dispatch_normal = - DispatchInfo { weight: 251, class: DispatchClass::Normal, ..Default::default() }; + System::register_extra_weight_unchecked(Weight::MAX, DispatchClass::Mandatory); + let dispatch_normal = DispatchInfo { + weight: Weight::from_ref_time(251), + class: DispatchClass::Normal, + ..Default::default() + }; let dispatch_operational = DispatchInfo { - weight: 251, + weight: Weight::from_ref_time(251), class: DispatchClass::Operational, ..Default::default() }; @@ -453,9 +459,9 @@ mod tests { #[test] fn signed_ext_check_weight_works_operational_tx() { new_test_ext().execute_with(|| { - let normal = DispatchInfo { weight: 100, ..Default::default() }; + let normal = DispatchInfo { weight: Weight::from_ref_time(100), ..Default::default() }; let op = DispatchInfo { - weight: 100, + weight: Weight::from_ref_time(100), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -489,7 +495,7 @@ mod tests { fn signed_ext_check_weight_block_size_works() { new_test_ext().execute_with(|| { let normal = DispatchInfo::default(); - let normal_limit = normal_weight_limit() as usize; + let normal_limit = normal_weight_limit().ref_time() as usize; let reset_check_weight = |tx, s, f| { AllExtrinsicsLen::::put(0); let r = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, tx, s); @@ -505,8 +511,11 @@ mod tests { reset_check_weight(&normal, normal_limit + 1, true); // Operational ones don't have this limit. - let op = - DispatchInfo { weight: 0, class: DispatchClass::Operational, pays_fee: Pays::Yes }; + let op = DispatchInfo { + weight: Weight::zero(), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; reset_check_weight(&op, normal_limit, false); reset_check_weight(&op, normal_limit + 100, false); reset_check_weight(&op, 1024, false); @@ -518,12 +527,14 @@ mod tests { fn signed_ext_check_weight_works_normal_tx() { new_test_ext().execute_with(|| { let normal_limit = normal_weight_limit(); - let small = DispatchInfo { weight: 100, ..Default::default() }; + let small = DispatchInfo { weight: Weight::from_ref_time(100), ..Default::default() }; let base_extrinsic = block_weights().get(DispatchClass::Normal).base_extrinsic; let medium = DispatchInfo { weight: normal_limit - base_extrinsic, ..Default::default() }; - let big = - DispatchInfo { weight: normal_limit - base_extrinsic + 1, ..Default::default() }; + let big = DispatchInfo { + weight: normal_limit - base_extrinsic + Weight::one(), + ..Default::default() + }; let len = 0_usize; let reset_check_weight = |i, f, s| { @@ -538,9 +549,9 @@ mod tests { } }; - reset_check_weight(&small, false, 0); - reset_check_weight(&medium, false, 0); - reset_check_weight(&big, true, 1); + reset_check_weight(&small, false, Weight::zero()); + reset_check_weight(&medium, false, Weight::zero()); + reset_check_weight(&big, true, Weight::one()); }) } @@ -548,20 +559,26 @@ mod tests { fn signed_ext_check_weight_refund_works() { new_test_ext().execute_with(|| { // This is half of the max block weight - let info = DispatchInfo { weight: 512, ..Default::default() }; - let post_info = - PostDispatchInfo { actual_weight: Some(128), pays_fee: Default::default() }; + let info = DispatchInfo { weight: Weight::from_ref_time(512), ..Default::default() }; + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_ref_time(128)), + pays_fee: Default::default(), + }; let len = 0_usize; let base_extrinsic = block_weights().get(DispatchClass::Normal).base_extrinsic; // We allow 75% for normal transaction, so we put 25% - extrinsic base weight BlockWeight::::mutate(|current_weight| { - current_weight.set(0, DispatchClass::Mandatory); - current_weight.set(256 - base_extrinsic, DispatchClass::Normal); + current_weight.set(Weight::zero(), DispatchClass::Mandatory); + current_weight + .set(Weight::from_ref_time(256) - base_extrinsic, DispatchClass::Normal); }); let pre = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap(); - assert_eq!(BlockWeight::::get().total(), info.weight + 256); + assert_eq!( + BlockWeight::::get().total(), + info.weight + Weight::from_ref_time(256) + ); assert_ok!(CheckWeight::::post_dispatch( Some(pre), @@ -570,27 +587,34 @@ mod tests { len, &Ok(()) )); - assert_eq!(BlockWeight::::get().total(), post_info.actual_weight.unwrap() + 256); + assert_eq!( + BlockWeight::::get().total(), + post_info.actual_weight.unwrap() + Weight::from_ref_time(256) + ); }) } #[test] fn signed_ext_check_weight_actual_weight_higher_than_max_is_capped() { new_test_ext().execute_with(|| { - let info = DispatchInfo { weight: 512, ..Default::default() }; - let post_info = - PostDispatchInfo { actual_weight: Some(700), pays_fee: Default::default() }; + let info = DispatchInfo { weight: Weight::from_ref_time(512), ..Default::default() }; + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_ref_time(700)), + pays_fee: Default::default(), + }; let len = 0_usize; BlockWeight::::mutate(|current_weight| { - current_weight.set(0, DispatchClass::Mandatory); - current_weight.set(128, DispatchClass::Normal); + current_weight.set(Weight::zero(), DispatchClass::Mandatory); + current_weight.set(Weight::from_ref_time(128), DispatchClass::Normal); }); let pre = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap(); assert_eq!( BlockWeight::::get().total(), - info.weight + 128 + block_weights().get(DispatchClass::Normal).base_extrinsic, + info.weight + + Weight::from_ref_time(128) + + block_weights().get(DispatchClass::Normal).base_extrinsic, ); assert_ok!(CheckWeight::::post_dispatch( @@ -602,7 +626,9 @@ mod tests { )); assert_eq!( BlockWeight::::get().total(), - info.weight + 128 + block_weights().get(DispatchClass::Normal).base_extrinsic, + info.weight + + Weight::from_ref_time(128) + + block_weights().get(DispatchClass::Normal).base_extrinsic, ); }) } @@ -611,7 +637,7 @@ mod tests { fn zero_weight_extrinsic_still_has_base_weight() { new_test_ext().execute_with(|| { let weights = block_weights(); - let free = DispatchInfo { weight: 0, ..Default::default() }; + let free = DispatchInfo { weight: Weight::zero(), ..Default::default() }; let len = 0_usize; // Initial weight from `weights.base_block` @@ -630,9 +656,10 @@ mod tests { // Max block is 1024 // Max normal is 768 (75%) // Max mandatory is unlimited - let max_normal = DispatchInfo { weight: 753, ..Default::default() }; + let max_normal = + DispatchInfo { weight: Weight::from_ref_time(753), ..Default::default() }; let mandatory = DispatchInfo { - weight: 1019, + weight: Weight::from_ref_time(1019), class: DispatchClass::Mandatory, ..Default::default() }; @@ -640,10 +667,10 @@ mod tests { let len = 0_usize; assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); - assert_eq!(System::block_weight().total(), 768); + assert_eq!(System::block_weight().total(), Weight::from_ref_time(768)); assert_ok!(CheckWeight::::do_pre_dispatch(&mandatory, len)); - assert_eq!(block_weight_limit(), 1024); - assert_eq!(System::block_weight().total(), 1024 + 768); + assert_eq!(block_weight_limit(), Weight::from_ref_time(1024)); + assert_eq!(System::block_weight().total(), Weight::from_ref_time(1024 + 768)); assert_eq!(CheckWeight::::check_extrinsic_weight(&mandatory), Ok(())); }); } @@ -652,30 +679,36 @@ mod tests { fn no_max_total_should_still_be_limited_by_max_block() { // given let maximum_weight = BlockWeights::builder() - .base_block(0) + .base_block(Weight::zero()) .for_class(DispatchClass::non_mandatory(), |w| { - w.base_extrinsic = 0; - w.max_total = Some(20); + w.base_extrinsic = Weight::zero(); + w.max_total = Some(Weight::from_ref_time(20)); }) .for_class(DispatchClass::Mandatory, |w| { - w.base_extrinsic = 0; - w.reserved = Some(5); + w.base_extrinsic = Weight::zero(); + w.reserved = Some(Weight::from_ref_time(5)); w.max_total = None; }) .build_or_panic(); let all_weight = crate::ConsumedWeight::new(|class| match class { - DispatchClass::Normal => 10, - DispatchClass::Operational => 10, - DispatchClass::Mandatory => 0, + DispatchClass::Normal => Weight::from_ref_time(10), + DispatchClass::Operational => Weight::from_ref_time(10), + DispatchClass::Mandatory => Weight::zero(), }); assert_eq!(maximum_weight.max_block, all_weight.total()); // fits into reserved - let mandatory1 = - DispatchInfo { weight: 5, class: DispatchClass::Mandatory, ..Default::default() }; + let mandatory1 = DispatchInfo { + weight: Weight::from_ref_time(5), + class: DispatchClass::Mandatory, + ..Default::default() + }; // does not fit into reserved and the block is full. - let mandatory2 = - DispatchInfo { weight: 6, class: DispatchClass::Mandatory, ..Default::default() }; + let mandatory2 = DispatchInfo { + weight: Weight::from_ref_time(6), + class: DispatchClass::Mandatory, + ..Default::default() + }; // when assert_ok!(calculate_consumed_weight::<::Call>( diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 990e3cdd14de1..d9afa17eec959 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1327,18 +1327,18 @@ impl Pallet { ).deconstruct(), Self::block_weight().get(DispatchClass::Normal), sp_runtime::Percent::from_rational( - *Self::block_weight().get(DispatchClass::Normal), - T::BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap_or(Bounded::max_value()) + Self::block_weight().get(DispatchClass::Normal).ref_time(), + T::BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap_or(Bounded::max_value()).ref_time() ).deconstruct(), Self::block_weight().get(DispatchClass::Operational), sp_runtime::Percent::from_rational( - *Self::block_weight().get(DispatchClass::Operational), - T::BlockWeights::get().get(DispatchClass::Operational).max_total.unwrap_or(Bounded::max_value()) + Self::block_weight().get(DispatchClass::Operational).ref_time(), + T::BlockWeights::get().get(DispatchClass::Operational).max_total.unwrap_or(Bounded::max_value()).ref_time() ).deconstruct(), Self::block_weight().get(DispatchClass::Mandatory), sp_runtime::Percent::from_rational( - *Self::block_weight().get(DispatchClass::Mandatory), - T::BlockWeights::get().get(DispatchClass::Mandatory).max_total.unwrap_or(Bounded::max_value()) + Self::block_weight().get(DispatchClass::Mandatory).ref_time(), + T::BlockWeights::get().get(DispatchClass::Mandatory).max_total.unwrap_or(Bounded::max_value()).ref_time() ).deconstruct(), ); ExecutionPhase::::kill(); diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index 6076414ba6bcb..d9be460b3a4fb 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -27,7 +27,7 @@ use frame_support::weights::{constants, DispatchClass, OneOrMany, PerDispatchClass, Weight}; use scale_info::TypeInfo; -use sp_runtime::{Perbill, RuntimeDebug}; +use sp_runtime::{traits::Bounded, Perbill, RuntimeDebug}; /// Block length limit configuration. #[derive(RuntimeDebug, Clone, codec::Encode, codec::Decode, TypeInfo)] @@ -230,14 +230,15 @@ impl BlockWeights { // base_for_class error_assert!( (max_for_class > self.base_block && max_for_class > base_for_class) - || max_for_class == 0, + || max_for_class == Weight::zero(), &mut error, "[{:?}] {:?} (total) has to be greater than {:?} (base block) & {:?} (base extrinsic)", class, max_for_class, self.base_block, base_for_class, ); // Max extrinsic can't be greater than max_for_class. error_assert!( - weights.max_extrinsic.unwrap_or(0) <= max_for_class.saturating_sub(base_for_class), + weights.max_extrinsic.unwrap_or(Weight::zero()) <= + max_for_class.saturating_sub(base_for_class), &mut error, "[{:?}] {:?} (max_extrinsic) can't be greater than {:?} (max for class)", class, @@ -246,14 +247,14 @@ impl BlockWeights { ); // Max extrinsic should not be 0 error_assert!( - weights.max_extrinsic.unwrap_or_else(Weight::max_value) > 0, + weights.max_extrinsic.unwrap_or_else(Weight::max_value) > Weight::zero(), &mut error, "[{:?}] {:?} (max_extrinsic) must not be 0. Check base cost and average initialization cost.", class, weights.max_extrinsic, ); // Make sure that if reserved is set it's greater than base_for_class. error_assert!( - reserved > base_for_class || reserved == 0, + reserved > base_for_class || reserved == Weight::zero(), &mut error, "[{:?}] {:?} (reserved) has to be greater than {:?} (base extrinsic) if set", class, @@ -262,7 +263,7 @@ impl BlockWeights { ); // Make sure max block is greater than max_total if it's set. error_assert!( - self.max_block >= weights.max_total.unwrap_or(0), + self.max_block >= weights.max_total.unwrap_or(Weight::zero()), &mut error, "[{:?}] {:?} (max block) has to be greater than {:?} (max for class)", class, @@ -294,9 +295,9 @@ impl BlockWeights { /// is not suitable for production deployments. pub fn simple_max(block_weight: Weight) -> Self { Self::builder() - .base_block(0) + .base_block(Weight::new()) .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = 0; + weights.base_extrinsic = Weight::new(); }) .for_class(DispatchClass::non_mandatory(), |weights| { weights.max_total = block_weight.into(); @@ -333,9 +334,10 @@ impl BlockWeights { BlockWeightsBuilder { weights: BlockWeights { base_block: constants::BlockExecutionWeight::get(), - max_block: 0, + max_block: Weight::zero(), per_class: PerDispatchClass::new(|class| { - let initial = if class == DispatchClass::Mandatory { None } else { Some(0) }; + let initial = + if class == DispatchClass::Mandatory { None } else { Some(Weight::zero()) }; WeightsPerClass { base_extrinsic: constants::ExtrinsicBaseWeight::get(), max_extrinsic: None, diff --git a/frame/system/src/migrations/mod.rs b/frame/system/src/migrations/mod.rs index f02af7a316fe1..15746d7376ac5 100644 --- a/frame/system/src/migrations/mod.rs +++ b/frame/system/src/migrations/mod.rs @@ -81,7 +81,7 @@ pub fn migrate_from_single_u8_to_triple_ref_count() -> Wei ); >::put(true); >::put(true); - Weight::max_value() + Weight::MAX } /// Migrate from unique `u32` reference counting to triple `u32` reference counting. @@ -99,7 +99,7 @@ pub fn migrate_from_single_to_triple_ref_count() -> Weight translated ); >::put(true); - Weight::max_value() + Weight::MAX } /// Migrate from dual `u32` reference counting to triple `u32` reference counting. @@ -117,5 +117,5 @@ pub fn migrate_from_dual_to_triple_ref_count() -> Weight { translated ); >::put(true); - Weight::max_value() + Weight::MAX } diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index f3f542aa83a9a..23ab3c2af20b0 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -42,7 +42,7 @@ frame_support::construct_runtime!( ); const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -const MAX_BLOCK_WEIGHT: Weight = 1024; +const MAX_BLOCK_WEIGHT: Weight = Weight::from_ref_time(1024); parameter_types! { pub Version: RuntimeVersion = RuntimeVersion { @@ -60,9 +60,9 @@ parameter_types! { write: 100, }; pub RuntimeBlockWeights: limits::BlockWeights = limits::BlockWeights::builder() - .base_block(10) + .base_block(Weight::from_ref_time(10)) .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = 5; + weights.base_extrinsic = Weight::from_ref_time(5); }) .for_class(DispatchClass::Normal, |weights| { weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAX_BLOCK_WEIGHT); diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index 417dca12045ee..f82ea338bd146 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -224,7 +224,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::note_finished_initialize(); - let pre_info = DispatchInfo { weight: 1000, ..Default::default() }; + let pre_info = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; System::note_applied_extrinsic(&Ok(Some(300).into()), pre_info); System::note_applied_extrinsic(&Ok(Some(1000).into()), pre_info); System::note_applied_extrinsic( @@ -236,7 +236,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { System::note_applied_extrinsic(&Ok(Pays::No.into()), pre_info); System::note_applied_extrinsic(&Ok((Some(2_500_000), Pays::No).into()), pre_info); System::note_applied_extrinsic(&Ok((Some(500), Pays::No).into()), pre_info); - System::note_applied_extrinsic(&Err(DispatchError::BadOrigin.with_weight(999)), pre_info); + System::note_applied_extrinsic( + &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(999))), + pre_info, + ); System::note_applied_extrinsic( &Err(DispatchErrorWithPostInfo { @@ -247,14 +250,20 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { ); System::note_applied_extrinsic( &Err(DispatchErrorWithPostInfo { - post_info: PostDispatchInfo { actual_weight: Some(800), pays_fee: Pays::Yes }, + post_info: PostDispatchInfo { + actual_weight: Some(Weight::from_ref_time(800)), + pays_fee: Pays::Yes, + }, error: DispatchError::BadOrigin, }), pre_info, ); System::note_applied_extrinsic( &Err(DispatchErrorWithPostInfo { - post_info: PostDispatchInfo { actual_weight: Some(800), pays_fee: Pays::No }, + post_info: PostDispatchInfo { + actual_weight: Some(Weight::from_ref_time(800)), + pays_fee: Pays::No, + }, error: DispatchError::BadOrigin, }), pre_info, @@ -266,7 +275,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(0), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { weight: 300, ..Default::default() }, + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(300), + ..Default::default() + }, } .into(), topics: vec![] @@ -274,7 +286,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(1), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { weight: 1000, ..Default::default() }, + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000), + ..Default::default() + }, } .into(), topics: vec![] @@ -282,7 +297,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(2), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { weight: 1000, ..Default::default() }, + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000), + ..Default::default() + }, } .into(), topics: vec![] @@ -291,7 +309,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(3), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: 1000, + weight: Weight::from_ref_time(1000), pays_fee: Pays::Yes, ..Default::default() }, @@ -303,7 +321,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(4), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: 1000, + weight: Weight::from_ref_time(1000), pays_fee: Pays::No, ..Default::default() }, @@ -315,7 +333,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(5), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: 1000, + weight: Weight::from_ref_time(1000), pays_fee: Pays::No, ..Default::default() }, @@ -327,7 +345,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(6), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: 500, + weight: Weight::from_ref_time(500), pays_fee: Pays::No, ..Default::default() }, @@ -339,7 +357,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(7), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { weight: 999, ..Default::default() }, + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(999), + ..Default::default() + }, } .into(), topics: vec![] @@ -349,7 +370,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { - weight: 1000, + weight: Weight::from_ref_time(1000), pays_fee: Pays::Yes, ..Default::default() }, @@ -362,7 +383,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { - weight: 800, + weight: Weight::from_ref_time(800), pays_fee: Pays::Yes, ..Default::default() }, @@ -375,7 +396,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { - weight: 800, + weight: Weight::from_ref_time(800), pays_fee: Pays::No, ..Default::default() }, diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index 19719032587ef..4f7f168eb55ab 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for frame_system. @@ -59,44 +59,44 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[0, 3932160]`. fn remark(_b: u32, ) -> Weight { - (1_000_000 as Weight) + Weight::from_ref_time(1_000_000 as RefTimeWeight) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) } // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (5_367_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(5_367_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `i` is `[1, 1000]`. fn set_storage(i: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((603_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) + .saturating_add(Weight::from_ref_time(603_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `i` is `[1, 1000]`. fn kill_storage(i: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((513_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) + .saturating_add(Weight::from_ref_time(513_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `p` is `[1, 1000]`. fn kill_prefix(p: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_026_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) + .saturating_add(Weight::from_ref_time(1_026_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) } } @@ -104,43 +104,43 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// The range of component `b` is `[0, 3932160]`. fn remark(_b: u32, ) -> Weight { - (1_000_000 as Weight) + Weight::from_ref_time(1_000_000 as RefTimeWeight) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) } // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - (5_367_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(5_367_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `i` is `[1, 1000]`. fn set_storage(i: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((603_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) + .saturating_add(Weight::from_ref_time(603_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `i` is `[1, 1000]`. fn kill_storage(i: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((513_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) + .saturating_add(Weight::from_ref_time(513_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `p` is `[1, 1000]`. fn kill_prefix(p: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((1_026_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(p as Weight))) + .saturating_add(Weight::from_ref_time(1_026_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) } } diff --git a/frame/timestamp/src/mock.rs b/frame/timestamp/src/mock.rs index 0da94deb7112a..b4c377cfa30ef 100644 --- a/frame/timestamp/src/mock.rs +++ b/frame/timestamp/src/mock.rs @@ -49,7 +49,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index 6b4ebfa74dd87..f71a0f753a43e 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_timestamp. @@ -54,12 +54,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - (8_080_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(8_080_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } fn on_finalize() -> Weight { - (2_681_000 as Weight) + Weight::from_ref_time(2_681_000 as RefTimeWeight) } } @@ -68,11 +68,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - (8_080_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(8_080_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } fn on_finalize() -> Weight { - (2_681_000 as Weight) + Weight::from_ref_time(2_681_000 as RefTimeWeight) } } diff --git a/frame/tips/src/migrations/v4.rs b/frame/tips/src/migrations/v4.rs index 34f7a43ec12de..5e10fa7dd2c6d 100644 --- a/frame/tips/src/migrations/v4.rs +++ b/frame/tips/src/migrations/v4.rs @@ -49,7 +49,7 @@ pub fn migrate::on_chain_storage_version(); @@ -84,7 +84,7 @@ pub fn migrate WeightInfo for SubstrateWeight { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - (30_669_000 as Weight) + Weight::from_ref_time(30_669_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - (28_768_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(28_768_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - (20_385_000 as Weight) + Weight::from_ref_time(20_385_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add((166_000 as Weight).saturating_mul(t as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(166_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - (12_287_000 as Weight) + Weight::from_ref_time(12_287_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add((363_000 as Weight).saturating_mul(t as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(363_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - (45_656_000 as Weight) + Weight::from_ref_time(45_656_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((276_000 as Weight).saturating_mul(t as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(276_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - (18_525_000 as Weight) + Weight::from_ref_time(18_525_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((37_000 as Weight).saturating_mul(t as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } } @@ -119,58 +119,58 @@ impl WeightInfo for () { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - (30_669_000 as Weight) + Weight::from_ref_time(30_669_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((4_000 as Weight).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - (28_768_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(28_768_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - (20_385_000 as Weight) + Weight::from_ref_time(20_385_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((2_000 as Weight).saturating_mul(r as Weight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add((166_000 as Weight).saturating_mul(t as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(166_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - (12_287_000 as Weight) + Weight::from_ref_time(12_287_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add((363_000 as Weight).saturating_mul(t as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(363_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - (45_656_000 as Weight) + Weight::from_ref_time(45_656_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add((276_000 as Weight).saturating_mul(t as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(276_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - (18_525_000 as Weight) + Weight::from_ref_time(18_525_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add((37_000 as Weight).saturating_mul(t as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } } diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index 08b17a6bf459c..a296a52b5e840 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -59,19 +59,19 @@ const CALL: &::Call = &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(0); + static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::new()); } pub struct BlockWeights; impl Get for BlockWeights { fn get() -> frame_system::limits::BlockWeights { frame_system::limits::BlockWeights::builder() - .base_block(0) + .base_block(Weight::zero()) .for_class(DispatchClass::all(), |weights| { weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into(); }) .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = 1024.into(); + weights.max_total = Weight::from_ref_time(1024).into(); }) .build_or_panic() } @@ -129,7 +129,8 @@ impl WeightToFeeT for WeightToFee { type Balance = u64; fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(*weight).saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) + Self::Balance::saturated_from(weight.ref_time()) + .saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) } } @@ -137,7 +138,7 @@ impl WeightToFeeT for TransactionByteFee { type Balance = u64; fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(*weight) + Self::Balance::saturated_from(weight.ref_time()) .saturating_mul(TRANSACTION_BYTE_FEE.with(|v| *v.borrow())) } } @@ -208,19 +209,24 @@ impl Config for Runtime { pub struct ExtBuilder { balance_factor: u64, - base_weight: u64, + base_weight: Weight, byte_fee: u64, weight_to_fee: u64, } impl Default for ExtBuilder { fn default() -> Self { - Self { balance_factor: 1, base_weight: 0, byte_fee: 1, weight_to_fee: 1 } + Self { + balance_factor: 1, + base_weight: Weight::from_ref_time(0), + byte_fee: 1, + weight_to_fee: 1, + } } } impl ExtBuilder { - pub fn base_weight(mut self, base_weight: u64) -> Self { + pub fn base_weight(mut self, base_weight: Weight) -> Self { self.base_weight = base_weight; self } @@ -283,19 +289,19 @@ fn transaction_payment_in_native_possible() { let balance_factor = 100; ExtBuilder::default() .balance_factor(balance_factor) - .base_weight(5) + .base_weight(Weight::from_ref_time(5)) .build() .execute_with(|| { let len = 10; let pre = ChargeAssetTxPayment::::from(0, None) - .pre_dispatch(&1, CALL, &info_from_weight(5), len) + .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_ref_time(5)), len) .unwrap(); let initial_balance = 10 * balance_factor; assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), - &info_from_weight(5), + &info_from_weight(Weight::from_ref_time(5)), &default_post_info(), len, &Ok(()) @@ -303,15 +309,15 @@ fn transaction_payment_in_native_possible() { assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); let pre = ChargeAssetTxPayment::::from(5 /* tipped */, None) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_ref_time(100)), len) .unwrap(); let initial_balance_for_2 = 20 * balance_factor; assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5); assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), - &info_from_weight(100), - &post_info_from_weight(50), + &info_from_weight(Weight::from_ref_time(100)), + &post_info_from_weight(Weight::from_ref_time(50)), len, &Ok(()) )); @@ -325,7 +331,7 @@ fn transaction_payment_in_asset_possible() { let balance_factor = 100; ExtBuilder::default() .balance_factor(balance_factor) - .base_weight(base_weight) + .base_weight(Weight::from_ref_time(base_weight)) .build() .execute_with(|| { // create the asset @@ -351,7 +357,7 @@ fn transaction_payment_in_asset_possible() { // existential deposit let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_ref_time(weight)), len) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -361,7 +367,7 @@ fn transaction_payment_in_asset_possible() { assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), - &info_from_weight(weight), + &info_from_weight(Weight::from_ref_time(weight)), &default_post_info(), len, &Ok(()) @@ -378,7 +384,7 @@ fn transaction_payment_without_fee() { let balance_factor = 100; ExtBuilder::default() .balance_factor(balance_factor) - .base_weight(base_weight) + .base_weight(Weight::from_ref_time(base_weight)) .build() .execute_with(|| { // create the asset @@ -404,7 +410,7 @@ fn transaction_payment_without_fee() { // existential deposit let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_ref_time(weight)), len) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -414,7 +420,7 @@ fn transaction_payment_without_fee() { assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), - &info_from_weight(weight), + &info_from_weight(Weight::from_ref_time(weight)), &post_info_from_pays(Pays::No), len, &Ok(()) @@ -431,7 +437,7 @@ fn asset_transaction_payment_with_tip_and_refund() { let base_weight = 5; ExtBuilder::default() .balance_factor(100) - .base_weight(base_weight) + .base_weight(Weight::from_ref_time(base_weight)) .build() .execute_with(|| { // create the asset @@ -459,15 +465,15 @@ fn asset_transaction_payment_with_tip_and_refund() { let fee_with_tip = (base_weight + weight + len as u64 + tip) * min_balance / ExistentialDeposit::get(); let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_ref_time(weight)), len) .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip); let final_weight = 50; assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), - &info_from_weight(weight), - &post_info_from_weight(final_weight), + &info_from_weight(Weight::from_ref_time(weight)), + &post_info_from_weight(Weight::from_ref_time(final_weight)), len, &Ok(()) )); @@ -483,7 +489,7 @@ fn payment_from_account_with_only_assets() { let base_weight = 5; ExtBuilder::default() .balance_factor(100) - .base_weight(base_weight) + .base_weight(Weight::from_ref_time(base_weight)) .build() .execute_with(|| { // create the asset @@ -511,7 +517,7 @@ fn payment_from_account_with_only_assets() { // existential deposit let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_ref_time(weight)), len) .unwrap(); assert_eq!(Balances::free_balance(caller), 0); // check that fee was charged in the given asset @@ -519,7 +525,7 @@ fn payment_from_account_with_only_assets() { assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), - &info_from_weight(weight), + &info_from_weight(Weight::from_ref_time(weight)), &default_post_info(), len, &Ok(()) @@ -534,7 +540,7 @@ fn payment_only_with_existing_sufficient_asset() { let base_weight = 5; ExtBuilder::default() .balance_factor(100) - .base_weight(base_weight) + .base_weight(Weight::from_ref_time(base_weight)) .build() .execute_with(|| { let asset_id = 1; @@ -543,7 +549,7 @@ fn payment_only_with_existing_sufficient_asset() { let len = 10; // pre_dispatch fails for non-existent asset assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_ref_time(weight)), len) .is_err()); // create the non-sufficient asset @@ -557,7 +563,7 @@ fn payment_only_with_existing_sufficient_asset() { )); // pre_dispatch fails for non-sufficient asset assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_ref_time(weight)), len) .is_err()); }); } @@ -567,7 +573,7 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { let base_weight = 1; ExtBuilder::default() .balance_factor(100) - .base_weight(base_weight) + .base_weight(Weight::from_ref_time(base_weight)) .build() .execute_with(|| { // create the asset @@ -611,14 +617,14 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { assert_eq!(Assets::balance(asset_id, caller), balance); } let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_ref_time(weight)), len) .unwrap(); // check that at least one coin was charged in the given asset assert_eq!(Assets::balance(asset_id, caller), balance - 1); assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), - &info_from_weight(weight), + &info_from_weight(Weight::from_ref_time(weight)), &default_post_info(), len, &Ok(()) @@ -632,7 +638,7 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { let base_weight = 1; ExtBuilder::default() .balance_factor(100) - .base_weight(base_weight) + .base_weight(Weight::from_ref_time(base_weight)) .build() .execute_with(|| { // create the asset @@ -689,7 +695,7 @@ fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { let base_weight = 1; ExtBuilder::default() .balance_factor(100) - .base_weight(base_weight) + .base_weight(Weight::from_ref_time(base_weight)) .build() .execute_with(|| { // create the asset @@ -713,7 +719,7 @@ fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { let len = 1; ChargeAssetTxPayment::::pre_dispatch_unsigned( CALL, - &info_from_weight(weight), + &info_from_weight(Weight::from_ref_time(weight)), len, ) .unwrap(); @@ -724,7 +730,7 @@ fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { // initial fee) assert_ok!(ChargeAssetTxPayment::::post_dispatch( None, - &info_from_weight(weight), + &info_from_weight(Weight::from_ref_time(weight)), &post_info_from_pays(Pays::Yes), len, &Ok(()) diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 707f7d8a22065..9777d7d240491 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -66,7 +66,8 @@ use frame_support::{ dispatch::DispatchResult, traits::{EstimateCallFee, Get}, weights::{ - DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight, WeightToFee, + DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, RefTimeWeight, + Weight, WeightToFee, }, }; @@ -189,7 +190,11 @@ where weights.get(DispatchClass::Normal).max_total.unwrap_or(weights.max_block); let current_block_weight = >::block_weight(); let normal_block_weight = - *current_block_weight.get(DispatchClass::Normal).min(&normal_max_weight); + current_block_weight.get(DispatchClass::Normal).min(normal_max_weight); + + // TODO: Handle all weight dimensions + let normal_max_weight = normal_max_weight.ref_time(); + let normal_block_weight = normal_block_weight.ref_time(); let s = S::get(); let v = V::get(); @@ -347,7 +352,7 @@ pub mod pallet { assert!( ::max_value() >= Multiplier::checked_from_integer::( - T::BlockWeights::get().max_block.try_into().unwrap() + T::BlockWeights::get().max_block.ref_time().try_into().unwrap() ) .unwrap(), ); @@ -359,7 +364,7 @@ pub mod pallet { ); // add 1 percent; let addition = target / 100; - if addition == 0 { + if addition == Weight::zero() { // this is most likely because in a test setup we set everything to (). return } @@ -554,7 +559,7 @@ where } fn length_to_fee(length: u32) -> BalanceOf { - T::LengthToFee::weight_to_fee(&(length as Weight)) + T::LengthToFee::weight_to_fee(&Weight::from_ref_time(length as RefTimeWeight)) } fn weight_to_fee(weight: Weight) -> BalanceOf { @@ -655,7 +660,11 @@ where let max_block_weight = T::BlockWeights::get().max_block; let max_block_length = *T::BlockLength::get().max.get(info.class) as u64; - let bounded_weight = info.weight.max(1).min(max_block_weight); + // TODO: Take into account all dimensions of weight + let max_block_weight = max_block_weight.ref_time(); + let info_weight = info.weight.ref_time(); + + let bounded_weight = info_weight.max(1).min(max_block_weight); let bounded_length = (len as u64).max(1).min(max_block_length); let max_tx_per_block_weight = max_block_weight / bounded_weight; @@ -836,19 +845,19 @@ mod tests { &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(0); + static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::new()); } pub struct BlockWeights; impl Get for BlockWeights { fn get() -> frame_system::limits::BlockWeights { frame_system::limits::BlockWeights::builder() - .base_block(0) + .base_block(Weight::zero()) .for_class(DispatchClass::all(), |weights| { weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into(); }) .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = 1024.into(); + weights.max_total = Weight::from_ref_time(1024).into(); }) .build_or_panic() } @@ -903,7 +912,7 @@ mod tests { type Balance = u64; fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(*weight) + Self::Balance::saturated_from(weight.ref_time()) .saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) } } @@ -912,7 +921,7 @@ mod tests { type Balance = u64; fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(*weight) + Self::Balance::saturated_from(weight.ref_time()) .saturating_mul(TRANSACTION_BYTE_FEE.with(|v| *v.borrow())) } } @@ -947,19 +956,19 @@ mod tests { pub struct ExtBuilder { balance_factor: u64, - base_weight: u64, + base_weight: Weight, byte_fee: u64, weight_to_fee: u64, } impl Default for ExtBuilder { fn default() -> Self { - Self { balance_factor: 1, base_weight: 0, byte_fee: 1, weight_to_fee: 1 } + Self { balance_factor: 1, base_weight: Weight::zero(), byte_fee: 1, weight_to_fee: 1 } } } impl ExtBuilder { - pub fn base_weight(mut self, base_weight: u64) -> Self { + pub fn base_weight(mut self, base_weight: Weight) -> Self { self.base_weight = base_weight; self } @@ -1025,18 +1034,18 @@ mod tests { fn signed_extension_transaction_payment_work() { ExtBuilder::default() .balance_factor(10) - .base_weight(5) + .base_weight(Weight::from_ref_time(5)) .build() .execute_with(|| { let len = 10; let pre = ChargeTransactionPayment::::from(0) - .pre_dispatch(&1, CALL, &info_from_weight(5), len) + .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_ref_time(5)), len) .unwrap(); assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); assert_ok!(ChargeTransactionPayment::::post_dispatch( Some(pre), - &info_from_weight(5), + &info_from_weight(Weight::from_ref_time(5)), &default_post_info(), len, &Ok(()) @@ -1048,14 +1057,14 @@ mod tests { FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() = 0); let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_ref_time(100)), len) .unwrap(); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); assert_ok!(ChargeTransactionPayment::::post_dispatch( Some(pre), - &info_from_weight(100), - &post_info_from_weight(50), + &info_from_weight(Weight::from_ref_time(100)), + &post_info_from_weight(Weight::from_ref_time(50)), len, &Ok(()) )); @@ -1069,22 +1078,22 @@ mod tests { fn signed_extension_transaction_payment_multiplied_refund_works() { ExtBuilder::default() .balance_factor(10) - .base_weight(5) + .base_weight(Weight::from_ref_time(5)) .build() .execute_with(|| { let len = 10; >::put(Multiplier::saturating_from_rational(3, 2)); let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_ref_time(100)), len) .unwrap(); // 5 base fee, 10 byte fee, 3/2 * 100 weight fee, 5 tip assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 150 - 5); assert_ok!(ChargeTransactionPayment::::post_dispatch( Some(pre), - &info_from_weight(100), - &post_info_from_weight(50), + &info_from_weight(Weight::from_ref_time(100)), + &post_info_from_weight(Weight::from_ref_time(50)), len, &Ok(()) )); @@ -1100,13 +1109,14 @@ mod tests { assert_ok!(ChargeTransactionPayment::::from(0).pre_dispatch( &1, CALL, - &info_from_weight(Weight::max_value()), + &info_from_weight(Weight::MAX), 10 )); // fee will be proportional to what is the actual maximum weight in the runtime. assert_eq!( Balances::free_balance(&1), - (10000 - ::BlockWeights::get().max_block) as u64 + (10000 - + ::BlockWeights::get().max_block.ref_time()) as u64 ); }); } @@ -1114,7 +1124,7 @@ mod tests { #[test] fn signed_extension_allows_free_transactions() { ExtBuilder::default() - .base_weight(100) + .base_weight(Weight::from_ref_time(100)) .balance_factor(0) .build() .execute_with(|| { @@ -1125,7 +1135,7 @@ mod tests { // This is a completely free (and thus wholly insecure/DoS-ridden) transaction. let operational_transaction = DispatchInfo { - weight: 0, + weight: Weight::from_ref_time(0), class: DispatchClass::Operational, pays_fee: Pays::No, }; @@ -1137,8 +1147,11 @@ mod tests { )); // like a InsecureFreeNormal - let free_transaction = - DispatchInfo { weight: 0, class: DispatchClass::Normal, pays_fee: Pays::Yes }; + let free_transaction = DispatchInfo { + weight: Weight::from_ref_time(0), + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }; assert_noop!( ChargeTransactionPayment::::from(0).validate( &1, @@ -1154,7 +1167,7 @@ mod tests { #[test] fn signed_ext_length_fee_is_also_updated_per_congestion() { ExtBuilder::default() - .base_weight(5) + .base_weight(Weight::from_ref_time(5)) .balance_factor(10) .build() .execute_with(|| { @@ -1162,8 +1175,10 @@ mod tests { >::put(Multiplier::saturating_from_rational(3, 2)); let len = 10; - assert_ok!(ChargeTransactionPayment::::from(10) // tipped - .pre_dispatch(&1, CALL, &info_from_weight(3), len)); + assert_ok!( + ChargeTransactionPayment::::from(10) // tipped + .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_ref_time(3)), len) + ); assert_eq!( Balances::free_balance(1), 100 // original @@ -1188,48 +1203,54 @@ mod tests { let unsigned_xt = TestXt::<_, ()>::new(call, None); let unsigned_xt_info = unsigned_xt.get_dispatch_info(); - ExtBuilder::default().base_weight(5).weight_fee(2).build().execute_with(|| { - // all fees should be x1.5 - >::put(Multiplier::saturating_from_rational(3, 2)); + ExtBuilder::default() + .base_weight(Weight::from_ref_time(5)) + .weight_fee(2) + .build() + .execute_with(|| { + // all fees should be x1.5 + >::put(Multiplier::saturating_from_rational(3, 2)); - assert_eq!( - TransactionPayment::query_info(xt.clone(), len), - RuntimeDispatchInfo { - weight: info.weight, - class: info.class, - partial_fee: 5 * 2 /* base * weight_fee */ + assert_eq!( + TransactionPayment::query_info(xt.clone(), len), + RuntimeDispatchInfo { + weight: info.weight, + class: info.class, + partial_fee: 5 * 2 /* base * weight_fee */ + len as u64 /* len * 1 */ - + info.weight.min(BlockWeights::get().max_block) as u64 * 2 * 3 / 2 /* weight */ - }, - ); + + info.weight.min(BlockWeights::get().max_block).ref_time() as u64 * 2 * 3 / 2 /* weight */ + }, + ); - assert_eq!( - TransactionPayment::query_info(unsigned_xt.clone(), len), - RuntimeDispatchInfo { - weight: unsigned_xt_info.weight, - class: unsigned_xt_info.class, - partial_fee: 0, - }, - ); + assert_eq!( + TransactionPayment::query_info(unsigned_xt.clone(), len), + RuntimeDispatchInfo { + weight: unsigned_xt_info.weight, + class: unsigned_xt_info.class, + partial_fee: 0, + }, + ); - assert_eq!( - TransactionPayment::query_fee_details(xt, len), - FeeDetails { - inclusion_fee: Some(InclusionFee { - base_fee: 5 * 2, - len_fee: len as u64, - adjusted_weight_fee: info.weight.min(BlockWeights::get().max_block) as u64 * - 2 * 3 / 2 - }), - tip: 0, - }, - ); + assert_eq!( + TransactionPayment::query_fee_details(xt, len), + FeeDetails { + inclusion_fee: Some(InclusionFee { + base_fee: 5 * 2, + len_fee: len as u64, + adjusted_weight_fee: info + .weight + .min(BlockWeights::get().max_block) + .ref_time() as u64 * 2 * 3 / 2 + }), + tip: 0, + }, + ); - assert_eq!( - TransactionPayment::query_fee_details(unsigned_xt, len), - FeeDetails { inclusion_fee: None, tip: 0 }, - ); - }); + assert_eq!( + TransactionPayment::query_fee_details(unsigned_xt, len), + FeeDetails { inclusion_fee: None, tip: 0 }, + ); + }); } #[test] @@ -1239,40 +1260,46 @@ mod tests { let encoded_call = call.encode(); let len = encoded_call.len() as u32; - ExtBuilder::default().base_weight(5).weight_fee(2).build().execute_with(|| { - // all fees should be x1.5 - >::put(Multiplier::saturating_from_rational(3, 2)); + ExtBuilder::default() + .base_weight(Weight::from_ref_time(5)) + .weight_fee(2) + .build() + .execute_with(|| { + // all fees should be x1.5 + >::put(Multiplier::saturating_from_rational(3, 2)); - assert_eq!( - TransactionPayment::query_call_info(call.clone(), len), - RuntimeDispatchInfo { - weight: info.weight, - class: info.class, - partial_fee: 5 * 2 /* base * weight_fee */ + assert_eq!( + TransactionPayment::query_call_info(call.clone(), len), + RuntimeDispatchInfo { + weight: info.weight, + class: info.class, + partial_fee: 5 * 2 /* base * weight_fee */ + len as u64 /* len * 1 */ - + info.weight.min(BlockWeights::get().max_block) as u64 * 2 * 3 / 2 /* weight */ - }, - ); + + info.weight.min(BlockWeights::get().max_block).ref_time() as u64 * 2 * 3 / 2 /* weight */ + }, + ); - assert_eq!( - TransactionPayment::query_call_fee_details(call, len), - FeeDetails { - inclusion_fee: Some(InclusionFee { - base_fee: 5 * 2, /* base * weight_fee */ - len_fee: len as u64, /* len * 1 */ - adjusted_weight_fee: info.weight.min(BlockWeights::get().max_block) as u64 * - 2 * 3 / 2 /* weight * weight_fee * multipler */ - }), - tip: 0, - }, - ); - }); + assert_eq!( + TransactionPayment::query_call_fee_details(call, len), + FeeDetails { + inclusion_fee: Some(InclusionFee { + base_fee: 5 * 2, /* base * weight_fee */ + len_fee: len as u64, /* len * 1 */ + adjusted_weight_fee: info + .weight + .min(BlockWeights::get().max_block) + .ref_time() as u64 * 2 * 3 / 2 /* weight * weight_fee * multipler */ + }), + tip: 0, + }, + ); + }); } #[test] fn compute_fee_works_without_multiplier() { ExtBuilder::default() - .base_weight(100) + .base_weight(Weight::from_ref_time(100)) .byte_fee(10) .balance_factor(0) .build() @@ -1282,14 +1309,14 @@ mod tests { // Tip only, no fees works let dispatch_info = DispatchInfo { - weight: 0, + weight: Weight::from_ref_time(0), class: DispatchClass::Operational, pays_fee: Pays::No, }; assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 10), 10); // No tip, only base fee works let dispatch_info = DispatchInfo { - weight: 0, + weight: Weight::from_ref_time(0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -1300,7 +1327,7 @@ mod tests { assert_eq!(Pallet::::compute_fee(42, &dispatch_info, 0), 520); // Weight fee + base fee works let dispatch_info = DispatchInfo { - weight: 1000, + weight: Weight::from_ref_time(1000), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -1311,7 +1338,7 @@ mod tests { #[test] fn compute_fee_works_with_multiplier() { ExtBuilder::default() - .base_weight(100) + .base_weight(Weight::from_ref_time(100)) .byte_fee(10) .balance_factor(0) .build() @@ -1320,7 +1347,7 @@ mod tests { >::put(Multiplier::saturating_from_rational(3, 2)); // Base fee is unaffected by multiplier let dispatch_info = DispatchInfo { - weight: 0, + weight: Weight::from_ref_time(0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -1328,7 +1355,7 @@ mod tests { // Everything works together :) let dispatch_info = DispatchInfo { - weight: 123, + weight: Weight::from_ref_time(123), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -1343,7 +1370,7 @@ mod tests { #[test] fn compute_fee_works_with_negative_multiplier() { ExtBuilder::default() - .base_weight(100) + .base_weight(Weight::from_ref_time(100)) .byte_fee(10) .balance_factor(0) .build() @@ -1353,7 +1380,7 @@ mod tests { // Base fee is unaffected by multiplier. let dispatch_info = DispatchInfo { - weight: 0, + weight: Weight::from_ref_time(0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -1361,7 +1388,7 @@ mod tests { // Everything works together. let dispatch_info = DispatchInfo { - weight: 123, + weight: Weight::from_ref_time(123), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -1376,14 +1403,14 @@ mod tests { #[test] fn compute_fee_does_not_overflow() { ExtBuilder::default() - .base_weight(100) + .base_weight(Weight::from_ref_time(100)) .byte_fee(10) .balance_factor(0) .build() .execute_with(|| { // Overflow is handled let dispatch_info = DispatchInfo { - weight: Weight::max_value(), + weight: Weight::MAX, class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -1398,14 +1425,14 @@ mod tests { fn refund_does_not_recreate_account() { ExtBuilder::default() .balance_factor(10) - .base_weight(5) + .base_weight(Weight::from_ref_time(5)) .build() .execute_with(|| { // So events are emitted System::set_block_number(10); let len = 10; let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_ref_time(100)), len) .unwrap(); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); @@ -1415,8 +1442,8 @@ mod tests { assert_ok!(ChargeTransactionPayment::::post_dispatch( Some(pre), - &info_from_weight(100), - &post_info_from_weight(50), + &info_from_weight(Weight::from_ref_time(100)), + &post_info_from_weight(Weight::from_ref_time(50)), len, &Ok(()) )); @@ -1438,19 +1465,19 @@ mod tests { fn actual_weight_higher_than_max_refunds_nothing() { ExtBuilder::default() .balance_factor(10) - .base_weight(5) + .base_weight(Weight::from_ref_time(5)) .build() .execute_with(|| { let len = 10; let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_ref_time(100)), len) .unwrap(); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); assert_ok!(ChargeTransactionPayment::::post_dispatch( Some(pre), - &info_from_weight(100), - &post_info_from_weight(101), + &info_from_weight(Weight::from_ref_time(100)), + &post_info_from_weight(Weight::from_ref_time(101)), len, &Ok(()) )); @@ -1462,14 +1489,17 @@ mod tests { fn zero_transfer_on_free_transaction() { ExtBuilder::default() .balance_factor(10) - .base_weight(5) + .base_weight(Weight::from_ref_time(5)) .build() .execute_with(|| { // So events are emitted System::set_block_number(10); let len = 10; - let dispatch_info = - DispatchInfo { weight: 100, pays_fee: Pays::No, class: DispatchClass::Normal }; + let dispatch_info = DispatchInfo { + weight: Weight::from_ref_time(100), + pays_fee: Pays::No, + class: DispatchClass::Normal, + }; let user = 69; let pre = ChargeTransactionPayment::::from(0) .pre_dispatch(&user, CALL, &dispatch_info, len) @@ -1498,11 +1528,11 @@ mod tests { fn refund_consistent_with_actual_weight() { ExtBuilder::default() .balance_factor(10) - .base_weight(7) + .base_weight(Weight::from_ref_time(7)) .build() .execute_with(|| { - let info = info_from_weight(100); - let post_info = post_info_from_weight(33); + let info = info_from_weight(Weight::from_ref_time(100)); + let post_info = post_info_from_weight(Weight::from_ref_time(33)); let prev_balance = Balances::free_balance(2); let len = 10; let tip = 5; @@ -1538,8 +1568,11 @@ mod tests { let len = 10; ExtBuilder::default().balance_factor(100).build().execute_with(|| { - let normal = - DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; + let normal = DispatchInfo { + weight: Weight::from_ref_time(100), + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }; let priority = ChargeTransactionPayment::(tip) .validate(&2, CALL, &normal, len) .unwrap() @@ -1557,7 +1590,7 @@ mod tests { ExtBuilder::default().balance_factor(100).build().execute_with(|| { let op = DispatchInfo { - weight: 100, + weight: Weight::from_ref_time(100), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -1581,8 +1614,11 @@ mod tests { let len = 10; ExtBuilder::default().balance_factor(100).build().execute_with(|| { - let normal = - DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; + let normal = DispatchInfo { + weight: Weight::from_ref_time(100), + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }; let priority = ChargeTransactionPayment::(tip) .validate(&2, CALL, &normal, len) .unwrap() @@ -1593,7 +1629,7 @@ mod tests { ExtBuilder::default().balance_factor(100).build().execute_with(|| { let op = DispatchInfo { - weight: 100, + weight: Weight::from_ref_time(100), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -1612,8 +1648,11 @@ mod tests { let mut priority2 = 0; let len = 10; ExtBuilder::default().balance_factor(100).build().execute_with(|| { - let normal = - DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; + let normal = DispatchInfo { + weight: Weight::from_ref_time(100), + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }; priority1 = ChargeTransactionPayment::(tip) .validate(&2, CALL, &normal, len) .unwrap() @@ -1622,7 +1661,7 @@ mod tests { ExtBuilder::default().balance_factor(100).build().execute_with(|| { let op = DispatchInfo { - weight: 100, + weight: Weight::from_ref_time(100), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -1649,10 +1688,10 @@ mod tests { fn post_info_can_change_pays_fee() { ExtBuilder::default() .balance_factor(10) - .base_weight(7) + .base_weight(Weight::from_ref_time(7)) .build() .execute_with(|| { - let info = info_from_weight(100); + let info = info_from_weight(Weight::from_ref_time(100)); let post_info = post_info_from_pays(Pays::No); let prev_balance = Balances::free_balance(2); let len = 10; diff --git a/frame/transaction-payment/src/types.rs b/frame/transaction-payment/src/types.rs index 3faebfed48946..5e915d62a26d4 100644 --- a/frame/transaction-payment/src/types.rs +++ b/frame/transaction-payment/src/types.rs @@ -135,12 +135,12 @@ mod tests { #[test] fn should_serialize_and_deserialize_properly_with_string() { let info = RuntimeDispatchInfo { - weight: 5, + weight: Weight::from_ref_time(5), class: DispatchClass::Normal, partial_fee: 1_000_000_u64, }; - let json_str = r#"{"weight":5,"class":"normal","partialFee":"1000000"}"#; + let json_str = r#"{"weight":{"ref_time":5},"class":"normal","partialFee":"1000000"}"#; assert_eq!(serde_json::to_string(&info).unwrap(), json_str); assert_eq!(serde_json::from_str::>(json_str).unwrap(), info); @@ -152,12 +152,12 @@ mod tests { #[test] fn should_serialize_and_deserialize_properly_large_value() { let info = RuntimeDispatchInfo { - weight: 5, + weight: Weight::from_ref_time(5), class: DispatchClass::Normal, partial_fee: u128::max_value(), }; - let json_str = r#"{"weight":5,"class":"normal","partialFee":"340282366920938463463374607431768211455"}"#; + let json_str = r#"{"weight":{"ref_time":5},"class":"normal","partialFee":"340282366920938463463374607431768211455"}"#; assert_eq!(serde_json::to_string(&info).unwrap(), json_str); assert_eq!(serde_json::from_str::>(json_str).unwrap(), info); diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index b8bc4890a416e..54d5b0723aad6 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_transaction_storage. @@ -59,11 +59,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn store(l: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: TransactionStorage Transactions (r:1 w:0) // Storage: TransactionStorage ByteFee (r:1 w:0) @@ -72,9 +72,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - (50_978_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(50_978_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: TransactionStorage ProofChecked (r:1 w:1) // Storage: TransactionStorage StoragePeriod (r:1 w:0) @@ -82,9 +82,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - (106_990_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(106_990_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } } @@ -97,11 +97,11 @@ impl WeightInfo for () { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn store(l: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(l as Weight)) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: TransactionStorage Transactions (r:1 w:0) // Storage: TransactionStorage ByteFee (r:1 w:0) @@ -110,9 +110,9 @@ impl WeightInfo for () { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - (50_978_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(50_978_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: TransactionStorage ProofChecked (r:1 w:1) // Storage: TransactionStorage StoragePeriod (r:1 w:0) @@ -120,8 +120,8 @@ impl WeightInfo for () { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - (106_990_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(106_990_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } } diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index ed38177e1c499..eecf225beea9b 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -319,7 +319,7 @@ pub mod pallet { if (n % T::SpendPeriod::get()).is_zero() { Self::spend_funds() } else { - 0 + Weight::zero() } } } @@ -500,7 +500,7 @@ impl, I: 'static> Pallet { /// Spend some money! returns number of approvals before spend. pub fn spend_funds() -> Weight { - let mut total_weight: Weight = Zero::zero(); + let mut total_weight = Weight::new(); let mut budget_remaining = Self::pot(); Self::deposit_event(Event::Spending { budget_remaining }); diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index 61eafb652427b..bec96daf576e3 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -55,7 +55,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index f6b5414a05652..74e6e9779000e 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_treasury. @@ -58,51 +58,51 @@ impl WeightInfo for SubstrateWeight { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn spend() -> Weight { - (22_063_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(22_063_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (26_473_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(26_473_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (29_955_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(29_955_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (10_786_000 as Weight) + Weight::from_ref_time(10_786_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((110_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(110_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Treasury Approvals (r:1 w:1) fn remove_approval() -> Weight { - (6_647_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(6_647_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Treasury Approvals (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (25_805_000 as Weight) + Weight::from_ref_time(25_805_000 as RefTimeWeight) // Standard Error: 18_000 - .saturating_add((28_473_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(p as Weight))) + .saturating_add(Weight::from_ref_time(28_473_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) } } @@ -111,50 +111,50 @@ impl WeightInfo for () { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn spend() -> Weight { - (22_063_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(22_063_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - (26_473_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(26_473_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - (29_955_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(29_955_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - (10_786_000 as Weight) + Weight::from_ref_time(10_786_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((110_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(Weight::from_ref_time(110_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Treasury Approvals (r:1 w:1) fn remove_approval() -> Weight { - (6_647_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(6_647_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Treasury Approvals (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - (25_805_000 as Weight) + Weight::from_ref_time(25_805_000 as RefTimeWeight) // Standard Error: 18_000 - .saturating_add((28_473_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(p as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(p as Weight))) + .saturating_add(Weight::from_ref_time(28_473_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) } } diff --git a/frame/uniques/src/migration.rs b/frame/uniques/src/migration.rs index d301f0a3d1eb1..8a2a0ef808d90 100644 --- a/frame/uniques/src/migration.rs +++ b/frame/uniques/src/migration.rs @@ -17,10 +17,7 @@ //! Various pieces of common functionality. use super::*; -use frame_support::{ - traits::{Get, GetStorageVersion, PalletInfoAccess, StorageVersion}, - weights::Weight, -}; +use frame_support::traits::{Get, GetStorageVersion, PalletInfoAccess, StorageVersion}; /// Migrate the pallet storage to v1. pub fn migrate_to_v1, I: 'static, P: GetStorageVersion + PalletInfoAccess>( @@ -45,7 +42,7 @@ pub fn migrate_to_v1, I: 'static, P: GetStorageVersion + PalletInfo on_chain_storage_version, ); // calculate and return migration weights - T::DbWeight::get().reads_writes(count as Weight + 1, count as Weight + 1) + T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1) } else { log::warn!( target: "runtime::uniques", diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 7c8cb170b1b1d..4ed01e463cc86 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_uniques. @@ -80,16 +80,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (33_075_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(33_075_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (19_528_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(19_528_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:0) @@ -103,192 +103,192 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 25_000 - .saturating_add((13_639_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(13_639_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 25_000 - .saturating_add((2_393_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(2_393_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 25_000 - .saturating_add((2_217_000 as Weight).saturating_mul(a as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(m as Weight))) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) + .saturating_add(Weight::from_ref_time(2_217_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (42_146_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(42_146_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - (42_960_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(42_960_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - (33_025_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(33_025_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:100 w:100) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 24_000 - .saturating_add((15_540_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) + .saturating_add(Weight::from_ref_time(15_540_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (25_194_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_194_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (25_397_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_397_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (19_278_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(19_278_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (19_304_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(19_304_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (28_615_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(28_615_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (19_943_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(19_943_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (22_583_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(22_583_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (47_520_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(47_520_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (45_316_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(45_316_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (38_391_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(38_391_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (38_023_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(38_023_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (37_398_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(37_398_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (35_621_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(35_621_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (25_856_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_856_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (26_098_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(26_098_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (24_076_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(24_076_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (22_035_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(22_035_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - (22_534_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(22_534_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques ItemPriceOf (r:1 w:1) // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - (45_272_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(45_272_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } } @@ -297,16 +297,16 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - (33_075_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(33_075_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - (19_528_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(19_528_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:0) @@ -320,191 +320,191 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 25_000 - .saturating_add((13_639_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(Weight::from_ref_time(13_639_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 25_000 - .saturating_add((2_393_000 as Weight).saturating_mul(m as Weight)) + .saturating_add(Weight::from_ref_time(2_393_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) // Standard Error: 25_000 - .saturating_add((2_217_000 as Weight).saturating_mul(a as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(n as Weight))) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(m as Weight))) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) + .saturating_add(Weight::from_ref_time(2_217_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (42_146_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(42_146_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - (42_960_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(42_960_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - (33_025_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(33_025_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:100 w:100) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - (0 as Weight) + Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 24_000 - .saturating_add((15_540_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) + .saturating_add(Weight::from_ref_time(15_540_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (25_194_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_194_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (25_397_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_397_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - (19_278_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(19_278_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - (19_304_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(19_304_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - (28_615_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(28_615_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (19_943_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(19_943_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - (22_583_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(22_583_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (47_520_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(47_520_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (45_316_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(45_316_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (38_391_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(38_391_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (38_023_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(38_023_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - (37_398_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(37_398_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - (35_621_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(35_621_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (25_856_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(25_856_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (26_098_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(26_098_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - (24_076_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(24_076_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - (22_035_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(22_035_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - (22_534_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + Weight::from_ref_time(22_534_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques ItemPriceOf (r:1 w:1) // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - (45_272_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + Weight::from_ref_time(45_272_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } } diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 0aae2615702dd..3df12d69e84eb 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -185,7 +185,7 @@ pub mod pallet { let dispatch_infos = calls.iter().map(|call| call.get_dispatch_info()).collect::>(); let dispatch_weight = dispatch_infos.iter() .map(|di| di.weight) - .fold(0, |total: Weight, weight: Weight| total.saturating_add(weight)) + .fold(Weight::new(), |total: Weight, weight: Weight| total.saturating_add(weight)) .saturating_add(T::WeightInfo::batch(calls.len() as u32)); let dispatch_class = { let all_operational = dispatch_infos.iter() @@ -208,7 +208,7 @@ pub mod pallet { ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); // Track the actual weight of each of the batch calls. - let mut weight: Weight = 0; + let mut weight = Weight::new(); for (index, call) in calls.into_iter().enumerate() { let info = call.get_dispatch_info(); // If origin is root, don't apply any dispatch filters; root can call anything. @@ -253,9 +253,9 @@ pub mod pallet { let dispatch_info = call.get_dispatch_info(); ( T::WeightInfo::as_derivative() - .saturating_add(dispatch_info.weight) // AccountData for inner call origin accountdata. - .saturating_add(T::DbWeight::get().reads_writes(1, 1)), + .saturating_add(T::DbWeight::get().reads_writes(1, 1)) + .saturating_add(dispatch_info.weight), dispatch_info.class, ) })] @@ -301,7 +301,7 @@ pub mod pallet { let dispatch_infos = calls.iter().map(|call| call.get_dispatch_info()).collect::>(); let dispatch_weight = dispatch_infos.iter() .map(|di| di.weight) - .fold(0, |total: Weight, weight: Weight| total.saturating_add(weight)) + .fold(Weight::new(), |total: Weight, weight: Weight| total.saturating_add(weight)) .saturating_add(T::WeightInfo::batch_all(calls.len() as u32)); let dispatch_class = { let all_operational = dispatch_infos.iter() @@ -324,7 +324,7 @@ pub mod pallet { ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); // Track the actual weight of each of the batch calls. - let mut weight: Weight = 0; + let mut weight = Weight::new(); for (index, call) in calls.into_iter().enumerate() { let info = call.get_dispatch_info(); // If origin is root, bypass any dispatch filter; root can call anything. @@ -352,7 +352,7 @@ pub mod pallet { } Self::deposit_event(Event::BatchCompleted); let base_weight = T::WeightInfo::batch_all(calls_len as u32); - Ok(Some(base_weight + weight).into()) + Ok(Some(base_weight.saturating_add(weight)).into()) } /// Dispatches a function call with a provided origin. @@ -406,7 +406,7 @@ pub mod pallet { let dispatch_infos = calls.iter().map(|call| call.get_dispatch_info()).collect::>(); let dispatch_weight = dispatch_infos.iter() .map(|di| di.weight) - .fold(0, |total: Weight, weight: Weight| total.saturating_add(weight)) + .fold(Weight::zero(), |total: Weight, weight: Weight| total.saturating_add(weight)) .saturating_add(T::WeightInfo::force_batch(calls.len() as u32)); let dispatch_class = { let all_operational = dispatch_infos.iter() @@ -429,7 +429,7 @@ pub mod pallet { ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); // Track the actual weight of each of the batch calls. - let mut weight: Weight = 0; + let mut weight = Weight::new(); // Track failed dispatch occur. let mut has_error: bool = false; for call in calls.into_iter() { @@ -455,7 +455,7 @@ pub mod pallet { Self::deposit_event(Event::BatchCompleted); } let base_weight = T::WeightInfo::batch(calls_len as u32); - Ok(Some(base_weight + weight).into()) + Ok(Some(base_weight.saturating_add(weight)).into()) } } } diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 6368473ac8708..e3b16b5244fc0 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -99,7 +99,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::max_value()); + frame_system::limits::BlockWeights::simple_max(Weight::MAX); } impl frame_system::Config for Test { type BaseCallFilter = TestBaseCallFilter; @@ -191,7 +191,7 @@ fn call_transfer(dest: u64, value: u64) -> Call { Call::Balances(BalancesCall::transfer { dest, value }) } -fn call_foobar(err: bool, start_weight: u64, end_weight: Option) -> Call { +fn call_foobar(err: bool, start_weight: Weight, end_weight: Option) -> Call { Call::Example(ExampleCall::foobar { err, start_weight, end_weight }) } @@ -213,8 +213,8 @@ fn as_derivative_works() { #[test] fn as_derivative_handles_weight_refund() { new_test_ext().execute_with(|| { - let start_weight = 100; - let end_weight = 75; + let start_weight = Weight::from_ref_time(100); + let end_weight = Weight::from_ref_time(75); let diff = start_weight - end_weight; // Full weight when ok @@ -364,24 +364,24 @@ fn batch_weight_calculation_doesnt_overflow() { use sp_runtime::Perbill; new_test_ext().execute_with(|| { let big_call = Call::System(SystemCall::fill_block { ratio: Perbill::from_percent(50) }); - assert_eq!(big_call.get_dispatch_info().weight, Weight::max_value() / 2); + assert_eq!(big_call.get_dispatch_info().weight, Weight::MAX / 2); // 3 * 50% saturates to 100% let batch_call = Call::Utility(crate::Call::batch { calls: vec![big_call.clone(), big_call.clone(), big_call.clone()], }); - assert_eq!(batch_call.get_dispatch_info().weight, Weight::max_value()); + assert_eq!(batch_call.get_dispatch_info().weight, Weight::MAX); }); } #[test] fn batch_handles_weight_refund() { new_test_ext().execute_with(|| { - let start_weight = 100; - let end_weight = 75; + let start_weight = Weight::from_ref_time(100); + let end_weight = Weight::from_ref_time(75); let diff = start_weight - end_weight; - let batch_len: Weight = 4; + let batch_len = 4; // Full weight when ok let inner_call = call_foobar(false, start_weight, None); @@ -420,7 +420,7 @@ fn batch_handles_weight_refund() { let good_call = call_foobar(false, start_weight, Some(end_weight)); let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call]; - let batch_len = batch_calls.len() as Weight; + let batch_len = Weight::from_ref_time(batch_calls.len() as u64); let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); @@ -494,10 +494,10 @@ fn batch_all_revert() { #[test] fn batch_all_handles_weight_refund() { new_test_ext().execute_with(|| { - let start_weight = 100; - let end_weight = 75; + let start_weight = Weight::from_ref_time(100); + let end_weight = Weight::from_ref_time(75); let diff = start_weight - end_weight; - let batch_len: Weight = 4; + let batch_len = 4; // Full weight when ok let inner_call = call_foobar(false, start_weight, None); @@ -533,7 +533,7 @@ fn batch_all_handles_weight_refund() { let good_call = call_foobar(false, start_weight, Some(end_weight)); let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call]; - let batch_len = batch_calls.len() as Weight; + let batch_len = Weight::from_ref_time(batch_calls.len() as u64); let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); @@ -616,7 +616,7 @@ fn force_batch_works() { Origin::signed(1), vec![ call_transfer(2, 5), - call_foobar(true, 75, None), + call_foobar(true, Weight::from_ref_time(75), None), call_transfer(2, 10), call_transfer(2, 5), ] diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 3660a54fb6a8f..0f0d171d8d4ee 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_utility. @@ -58,27 +58,27 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - (23_113_000 as Weight) + Weight::from_ref_time(23_113_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((2_701_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(Weight::from_ref_time(2_701_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) } fn as_derivative() -> Weight { - (4_182_000 as Weight) + Weight::from_ref_time(4_182_000 as RefTimeWeight) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - (18_682_000 as Weight) + Weight::from_ref_time(18_682_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((2_794_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(Weight::from_ref_time(2_794_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) } fn dispatch_as() -> Weight { - (12_049_000 as Weight) + Weight::from_ref_time(12_049_000 as RefTimeWeight) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - (19_136_000 as Weight) + Weight::from_ref_time(19_136_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((2_697_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(Weight::from_ref_time(2_697_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) } } @@ -86,26 +86,26 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - (23_113_000 as Weight) + Weight::from_ref_time(23_113_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((2_701_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(Weight::from_ref_time(2_701_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) } fn as_derivative() -> Weight { - (4_182_000 as Weight) + Weight::from_ref_time(4_182_000 as RefTimeWeight) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - (18_682_000 as Weight) + Weight::from_ref_time(18_682_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((2_794_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(Weight::from_ref_time(2_794_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) } fn dispatch_as() -> Weight { - (12_049_000 as Weight) + Weight::from_ref_time(12_049_000 as RefTimeWeight) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - (19_136_000 as Weight) + Weight::from_ref_time(19_136_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((2_697_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(Weight::from_ref_time(2_697_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) } } diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index 9ad8e57500e89..8875404f03fa2 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -45,7 +45,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type AccountData = pallet_balances::AccountData; diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index 4596157e63b7b..bd3af72cdd182 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_vesting. @@ -60,96 +60,96 @@ impl WeightInfo for SubstrateWeight { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - (32_978_000 as Weight) + Weight::from_ref_time(32_978_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((82_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(82_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((88_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(88_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - (32_856_000 as Weight) + Weight::from_ref_time(32_856_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((79_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - (33_522_000 as Weight) + Weight::from_ref_time(33_522_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((74_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(74_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((72_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(72_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - (32_558_000 as Weight) + Weight::from_ref_time(32_558_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((78_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((61_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(61_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - (49_260_000 as Weight) + Weight::from_ref_time(49_260_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((80_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - (49_166_000 as Weight) + Weight::from_ref_time(49_166_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 4_000 - .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(43_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (34_042_000 as Weight) + Weight::from_ref_time(34_042_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((83_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(83_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((80_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (33_937_000 as Weight) + Weight::from_ref_time(33_937_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((78_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((73_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } } @@ -158,95 +158,95 @@ impl WeightInfo for () { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - (32_978_000 as Weight) + Weight::from_ref_time(32_978_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((82_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(82_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((88_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(88_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - (32_856_000 as Weight) + Weight::from_ref_time(32_856_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((79_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((56_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - (33_522_000 as Weight) + Weight::from_ref_time(33_522_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((74_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(74_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((72_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(72_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - (32_558_000 as Weight) + Weight::from_ref_time(32_558_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((78_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((61_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(61_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - (49_260_000 as Weight) + Weight::from_ref_time(49_260_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((80_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add((55_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - (49_166_000 as Weight) + Weight::from_ref_time(49_166_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add((77_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 4_000 - .saturating_add((43_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(Weight::from_ref_time(43_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (34_042_000 as Weight) + Weight::from_ref_time(34_042_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((83_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(83_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((80_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - (33_937_000 as Weight) + Weight::from_ref_time(33_937_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add((78_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add((73_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } } diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs index 634db53a09a4e..b18236099d445 100644 --- a/frame/whitelist/src/mock.rs +++ b/frame/whitelist/src/mock.rs @@ -51,7 +51,7 @@ construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } impl frame_system::Config for Test { type BaseCallFilter = Nothing; diff --git a/frame/whitelist/src/tests.rs b/frame/whitelist/src/tests.rs index 67bccaeaeebe1..3e20cd29efb4f 100644 --- a/frame/whitelist/src/tests.rs +++ b/frame/whitelist/src/tests.rs @@ -19,7 +19,9 @@ use crate::mock::*; use codec::Encode; -use frame_support::{assert_noop, assert_ok, dispatch::GetDispatchInfo, traits::PreimageProvider}; +use frame_support::{ + assert_noop, assert_ok, dispatch::GetDispatchInfo, traits::PreimageProvider, weights::Weight, +}; use sp_runtime::{traits::Hash, DispatchError}; #[test] @@ -94,7 +96,11 @@ fn test_whitelist_call_and_execute() { assert!(Preimage::preimage_requested(&call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight - 1), + Whitelist::dispatch_whitelisted_call( + Origin::root(), + call_hash, + call_weight - Weight::one() + ), crate::Error::::InvalidCallWeightWitness, ); @@ -114,7 +120,7 @@ fn test_whitelist_call_and_execute_failing_call() { new_test_ext().execute_with(|| { let call = Call::Whitelist(crate::Call::dispatch_whitelisted_call { call_hash: Default::default(), - call_weight_witness: 0, + call_weight_witness: Weight::zero(), }); let call_weight = call.get_dispatch_info().weight; let encoded_call = call.encode(); diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index 81482c35e3de8..bb2ed9700c833 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_whitelist. @@ -56,35 +56,35 @@ impl WeightInfo for SubstrateWeight { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - (20_938_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(20_938_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn remove_whitelisted_call() -> Weight { - (22_332_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(22_332_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn dispatch_whitelisted_call() -> Weight { - (5_989_917_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(5_989_917_000 as RefTimeWeight) + .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - (25_325_000 as Weight) + Weight::from_ref_time(25_325_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } } @@ -93,34 +93,34 @@ impl WeightInfo for () { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - (20_938_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + Weight::from_ref_time(20_938_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn remove_whitelisted_call() -> Weight { - (22_332_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(22_332_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn dispatch_whitelisted_call() -> Weight { - (5_989_917_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + Weight::from_ref_time(5_989_917_000 as RefTimeWeight) + .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - (25_325_000 as Weight) + Weight::from_ref_time(25_325_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(n as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index aa436f1ad2a91..181e3fec62b24 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -39,7 +39,7 @@ use cfg_if::cfg_if; use frame_support::{ parameter_types, traits::{ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem}, - weights::RuntimeDbWeight, + weights::{RuntimeDbWeight, Weight}, }; use frame_system::limits::{BlockLength, BlockWeights}; use sp_api::{decl_runtime_apis, impl_runtime_apis}; @@ -577,7 +577,7 @@ parameter_types! { pub RuntimeBlockLength: BlockLength = BlockLength::max(4 * 1024 * 1024); pub RuntimeBlockWeights: BlockWeights = - BlockWeights::with_sensible_defaults(4 * 1024 * 1024, Perbill::from_percent(75)); + BlockWeights::with_sensible_defaults(Weight::from_ref_time(4 * 1024 * 1024), Perbill::from_percent(75)); } impl frame_system::Config for Runtime { diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index e48a7e8b3c6f5..36215c8a0586d 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -142,7 +142,8 @@ where let weight = ConsumedWeight::decode_all(&mut raw_weight)?; // Should be divisible, but still use floats in case we ever change that. - Ok((weight.total() as f64 / WEIGHT_PER_NANOS as f64).floor() as NanoSeconds) + Ok((weight.total().ref_time() as f64 / WEIGHT_PER_NANOS.ref_time() as f64).floor() + as NanoSeconds) } /// Prints the weight info of a block to the console. diff --git a/utils/frame/benchmarking-cli/src/overhead/README.md b/utils/frame/benchmarking-cli/src/overhead/README.md index 6f41e881d0572..a1da5da0d0792 100644 --- a/utils/frame/benchmarking-cli/src/overhead/README.md +++ b/utils/frame/benchmarking-cli/src/overhead/README.md @@ -1,21 +1,21 @@ # The `benchmark overhead` command -Each time an extrinsic or a block is executed, a fixed weight is charged as "execution overhead". -This is necessary since the weight that is calculated by the pallet benchmarks does not include this overhead. -The exact overhead to can vary per Substrate chain and needs to be calculated per chain. +Each time an extrinsic or a block is executed, a fixed weight is charged as "execution overhead". +This is necessary since the weight that is calculated by the pallet benchmarks does not include this overhead. +The exact overhead to can vary per Substrate chain and needs to be calculated per chain. This command calculates the exact values of these overhead weights for any Substrate chain that supports it. ## How does it work? -The benchmark consists of two parts; the [`BlockExecutionWeight`] and the [`ExtrinsicBaseWeight`]. +The benchmark consists of two parts; the [`BlockExecutionWeight`] and the [`ExtrinsicBaseWeight`]. Both are executed sequentially when invoking the command. ## BlockExecutionWeight -The block execution weight is defined as the weight that it takes to execute an *empty block*. -It is measured by constructing an empty block and measuring its executing time. -The result are written to a `block_weights.rs` file which is created from a template. -The file will contain the concrete weight value and various statistics about the measurements. For example: +The block execution weight is defined as the weight that it takes to execute an *empty block*. +It is measured by constructing an empty block and measuring its executing time. +The result are written to a `block_weights.rs` file which is created from a template. +The file will contain the concrete weight value and various statistics about the measurements. For example: ```rust /// Time to execute an empty block. /// Calculated by multiplying the *Average* with `1` and adding `0`. @@ -30,21 +30,21 @@ The file will contain the concrete weight value and various statistics about the /// 99th: 3_631_863 /// 95th: 3_595_674 /// 75th: 3_526_435 -pub const BlockExecutionWeight: Weight = 3_532_484 * WEIGHT_PER_NANOS; +pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul(3_532_484); ``` -In this example it takes 3.5 ms to execute an empty block. That means that it always takes at least 3.5 ms to execute *any* block. +In this example it takes 3.5 ms to execute an empty block. That means that it always takes at least 3.5 ms to execute *any* block. This constant weight is therefore added to each block to ensure that Substrate budgets enough time to execute it. ## ExtrinsicBaseWeight -The extrinsic base weight is defined as the weight that it takes to execute an *empty* extrinsic. -An *empty* extrinsic is also called a *NO-OP*. It does nothing and is the equivalent to the empty block form above. +The extrinsic base weight is defined as the weight that it takes to execute an *empty* extrinsic. +An *empty* extrinsic is also called a *NO-OP*. It does nothing and is the equivalent to the empty block form above. The benchmark now constructs a block which is filled with only NO-OP extrinsics. -This block is then executed many times and the weights are measured. -The result is divided by the number of extrinsics in that block and the results are written to `extrinsic_weights.rs`. +This block is then executed many times and the weights are measured. +The result is divided by the number of extrinsics in that block and the results are written to `extrinsic_weights.rs`. -The relevant section in the output file looks like this: +The relevant section in the output file looks like this: ```rust /// Time to execute a NO-OP extrinsic, for example `System::remark`. /// Calculated by multiplying the *Average* with `1` and adding `0`. @@ -59,10 +59,10 @@ The relevant section in the output file looks like this: /// 99th: 68_758 /// 95th: 67_843 /// 75th: 67_749 -pub const ExtrinsicBaseWeight: Weight = 67_745 * WEIGHT_PER_NANOS; +pub const ExtrinsicBaseWeight: Weight = Weight::from_ref_time(67_745 * WEIGHT_PER_NANOS); ``` -In this example it takes 67.7 µs to execute a NO-OP extrinsic. That means that it always takes at least 67.7 µs to execute *any* extrinsic. +In this example it takes 67.7 µs to execute a NO-OP extrinsic. That means that it always takes at least 67.7 µs to execute *any* extrinsic. This constant weight is therefore added to each extrinsic to ensure that Substrate budgets enough time to execute it. ## Invocation @@ -76,48 +76,48 @@ Output: ```pre # BlockExecutionWeight Running 10 warmups... -Executing block 100 times +Executing block 100 times Per-block execution overhead [ns]: Total: 353248430 Min: 3508416, Max: 3680498 Average: 3532484, Median: 3522111, Stddev: 27070.23 -Percentiles 99th, 95th, 75th: 3631863, 3595674, 3526435 +Percentiles 99th, 95th, 75th: 3631863, 3595674, 3526435 Writing weights to "block_weights.rs" # Setup -Building block, this takes some time... +Building block, this takes some time... Extrinsics per block: 12000 # ExtrinsicBaseWeight Running 10 warmups... -Executing block 100 times +Executing block 100 times Per-extrinsic execution overhead [ns]: Total: 6774590 Min: 67561, Max: 69855 Average: 67745, Median: 67701, Stddev: 264.68 -Percentiles 99th, 95th, 75th: 68758, 67843, 67749 +Percentiles 99th, 95th, 75th: 68758, 67843, 67749 Writing weights to "extrinsic_weights.rs" ``` -The complete command for Polkadot looks like this: +The complete command for Polkadot looks like this: ```sh cargo run --profile=production -- benchmark overhead --chain=polkadot-dev --execution=wasm --wasm-execution=compiled --weight-path=runtime/polkadot/constants/src/weights/ ``` -This will overwrite the the [block_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/block_weights.rs) and [extrinsic_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/extrinsic_weights.rs) files in the Polkadot runtime directory. -You can try the same for *Rococo* and to see that the results slightly differ. +This will overwrite the the [block_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/block_weights.rs) and [extrinsic_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/extrinsic_weights.rs) files in the Polkadot runtime directory. +You can try the same for *Rococo* and to see that the results slightly differ. 👉 It is paramount to use `--profile=production`, `--execution=wasm` and `--wasm-execution=compiled` as the results are otherwise useless. ## Output Interpretation -Lower is better. The less weight the execution overhead needs, the better. -Since the weights of the overhead is charged per extrinsic and per block, a larger weight results in less extrinsics per block. +Lower is better. The less weight the execution overhead needs, the better. +Since the weights of the overhead is charged per extrinsic and per block, a larger weight results in less extrinsics per block. Minimizing this is important to have a large transaction throughput. ## Arguments -- `--chain` / `--dev` Set the chain specification. -- `--weight-path` Set the output directory or file to write the weights to. +- `--chain` / `--dev` Set the chain specification. +- `--weight-path` Set the output directory or file to write the weights to. - `--repeat` Set the repetitions of both benchmarks. - `--warmup` Set the rounds of warmup before measuring. - `--execution` Should be set to `wasm` for correct results. diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index f8312b0052592..d07533e9dbaa8 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -52,11 +52,12 @@ parameter_types! { /// 99th: {{underscore stats.p99}} /// 95th: {{underscore stats.p95}} /// 75th: {{underscore stats.p75}} - pub const {{long_name}}Weight: Weight = {{underscore weight}} * WEIGHT_PER_NANOS; + pub const {{long_name}}Weight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul({{underscore weight}}); } #[cfg(test)] mod test_weights { + use super::*; use frame_support::weights::constants; /// Checks that the weight exists and is sane. @@ -68,14 +69,14 @@ mod test_weights { {{#if (eq short_name "block")}} // At least 100 µs. - assert!(w >= 100 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); + assert!(w >= Weight::from_ref_time(100 * constants::WEIGHT_PER_MICROS), "Weight should be at least 100 µs."); // At most 50 ms. - assert!(w <= 50 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms."); + assert!(w <= Weight::from_ref_time(50 * constants::WEIGHT_PER_MILLIS), "Weight should be at most 50 ms."); {{else}} // At least 10 µs. - assert!(w >= 10 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs."); + assert!(w >= Weight::from_ref_time(10 * constants::WEIGHT_PER_MICROS), "Weight should be at least 10 µs."); // At most 1 ms. - assert!(w <= constants::WEIGHT_PER_MILLIS, "Weight should be at most 1 ms."); + assert!(w <= Weight::from_ref_time(constants::WEIGHT_PER_MILLIS), "Weight should be at most 1 ms."); {{/if}} } } diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index 688ad4d3934f5..bf18e23367bc9 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -15,7 +15,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::Weight}; +use frame_support::{traits::Get, weights::{RefTimeWeight, Weight}}; use sp_std::marker::PhantomData; /// Weight functions for `{{pallet}}`. @@ -33,22 +33,22 @@ impl {{pallet}}::WeightInfo for WeightInfo { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { - ({{underscore benchmark.base_weight}} as Weight) + Weight::from_ref_time({{underscore benchmark.base_weight}} as RefTimeWeight) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).scalar_saturating_mul({{cw.name}} as RefTimeWeight)) {{/each}} {{#if (ne benchmark.base_reads "0")}} - .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight)) + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as RefTimeWeight)) {{/if}} {{#each benchmark.component_reads as |cr|}} - .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) + .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as RefTimeWeight).saturating_mul({{cr.name}} as RefTimeWeight))) {{/each}} {{#if (ne benchmark.base_writes "0")}} - .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight)) + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as RefTimeWeight)) {{/if}} {{#each benchmark.component_writes as |cw|}} - .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) + .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight))) {{/each}} } {{/each}} From 7c1a39f0e526a181c7e454322723768b83ab5ef8 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 31 Aug 2022 14:55:46 +0200 Subject: [PATCH 1105/1472] Simplify trait bounds in network to prepare for collator-rpc (#12082) * Hack towards PoC * Abstract away runtime requirement * blockchainevents * Remove bitswap * Remove unused sync more * Remove unused features in network * Re-enable bitswap change * Remove `Chain` trait bound * Reimplement blockchain-rpc-events * Move network to cumulus * Make AuthorityDiscovery async * Remove `ProofProvider` requirement from network behaviour * Extract bitswap * Adjustments after merge * Remove HeaderMetadata trait from network * Introduce NetworkHeaderBackend * Add comments * Improve comments * Move NetworkHeaderBackend to new module * Improve naming, remove redundand send + sync * Clean up generics * Fix CI * Improve comment and readability * Remove NetworkHeaderBackend * Fix Cargo.lock Co-authored-by: Sebastian Kunert --- Cargo.lock | 2 + client/authority-discovery/Cargo.toml | 1 + client/authority-discovery/src/lib.rs | 13 +-- client/authority-discovery/src/worker.rs | 44 +++++++-- .../authority-discovery/src/worker/tests.rs | 1 + client/network/common/Cargo.toml | 1 + client/network/src/behaviour.rs | 71 +++----------- client/network/src/bitswap.rs | 92 +++++++++++++++++-- client/network/src/config.rs | 5 +- client/network/src/protocol.rs | 21 +---- client/network/src/service.rs | 58 ++---------- client/network/src/service/tests.rs | 1 + client/network/test/src/lib.rs | 1 + client/service/src/builder.rs | 9 +- 14 files changed, 165 insertions(+), 155 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d90de9da4f579..b0d0206a35300 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7742,6 +7742,7 @@ dependencies = [ name = "sc-authority-discovery" version = "0.10.0-dev" dependencies = [ + "async-trait", "futures", "futures-timer", "ip_network", @@ -8451,6 +8452,7 @@ dependencies = [ "sc-peerset", "serde", "smallvec", + "sp-blockchain", "sp-consensus", "sp-finality-grandpa", "sp-runtime", diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index b7a140f24a111..d9e9df4f2a97c 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -35,6 +35,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +async-trait = "0.1.56" [dev-dependencies] quickcheck = { version = "1.0.3", default-features = false } diff --git a/client/authority-discovery/src/lib.rs b/client/authority-discovery/src/lib.rs index f0ef374551617..db3802b168fe5 100644 --- a/client/authority-discovery/src/lib.rs +++ b/client/authority-discovery/src/lib.rs @@ -29,7 +29,7 @@ pub use crate::{ service::Service, - worker::{NetworkProvider, Role, Worker}, + worker::{AuthorityDiscovery, NetworkProvider, Role, Worker}, }; use std::{collections::HashSet, sync::Arc, time::Duration}; @@ -40,10 +40,9 @@ use futures::{ }; use libp2p::{Multiaddr, PeerId}; -use sc_client_api::blockchain::HeaderBackend; use sc_network_common::protocol::event::DhtEvent; -use sp_api::ProvideRuntimeApi; -use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId}; +use sp_authority_discovery::AuthorityId; +use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; mod error; @@ -122,8 +121,7 @@ pub fn new_worker_and_service( where Block: BlockT + Unpin + 'static, Network: NetworkProvider, - Client: ProvideRuntimeApi + Send + Sync + 'static + HeaderBackend, - >::Api: AuthorityDiscoveryApi, + Client: AuthorityDiscovery + Send + Sync + 'static + HeaderBackend, DhtEventStream: Stream + Unpin, { new_worker_and_service_with_config( @@ -150,8 +148,7 @@ pub fn new_worker_and_service_with_config + Send + Sync + 'static + HeaderBackend, - >::Api: AuthorityDiscoveryApi, + Client: AuthorityDiscovery + HeaderBackend + 'static, DhtEventStream: Stream + Unpin, { let (to_worker, from_service) = mpsc::channel(0); diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index f13a1cf33581b..4121b64e00b9b 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -43,15 +43,16 @@ use log::{debug, error, log_enabled}; use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64}; use prost::Message; use rand::{seq::SliceRandom, thread_rng}; -use sc_client_api::blockchain::HeaderBackend; use sc_network_common::{ protocol::event::DhtEvent, service::{KademliaKey, NetworkDHTProvider, NetworkSigner, NetworkStateInfo, Signature}, }; -use sp_api::ProvideRuntimeApi; +use sp_api::{ApiError, ProvideRuntimeApi}; use sp_authority_discovery::{ AuthorityDiscoveryApi, AuthorityId, AuthorityPair, AuthoritySignature, }; +use sp_blockchain::HeaderBackend; + use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair}; use sp_keystore::CryptoStore; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; @@ -150,12 +151,35 @@ pub struct Worker { phantom: PhantomData, } +/// Wrapper for [`AuthorityDiscoveryApi`](sp_authority_discovery::AuthorityDiscoveryApi). Can be +/// be implemented by any struct without dependency on the runtime. +#[async_trait::async_trait] +pub trait AuthorityDiscovery { + /// Retrieve authority identifiers of the current and next authority set. + async fn authorities(&self, at: Block::Hash) + -> std::result::Result, ApiError>; +} + +#[async_trait::async_trait] +impl AuthorityDiscovery for T +where + T: ProvideRuntimeApi + Send + Sync, + T::Api: AuthorityDiscoveryApi, + Block: BlockT, +{ + async fn authorities( + &self, + at: Block::Hash, + ) -> std::result::Result, ApiError> { + self.runtime_api().authorities(&BlockId::Hash(at)) + } +} + impl Worker where Block: BlockT + Unpin + 'static, Network: NetworkProvider, - Client: ProvideRuntimeApi + Send + Sync + 'static + HeaderBackend, - >::Api: AuthorityDiscoveryApi, + Client: AuthorityDiscovery + HeaderBackend + 'static, DhtEventStream: Stream + Unpin, { /// Construct a [`Worker`]. @@ -354,7 +378,7 @@ where } async fn refill_pending_lookups_queue(&mut self) -> Result<()> { - let id = BlockId::hash(self.client.info().best_hash); + let best_hash = self.client.info().best_hash; let local_keys = match &self.role { Role::PublishAndDiscover(key_store) => key_store @@ -367,8 +391,8 @@ where let mut authorities = self .client - .runtime_api() - .authorities(&id) + .authorities(best_hash) + .await .map_err(|e| Error::CallingRuntime(e.into()))? .into_iter() .filter(|id| !local_keys.contains(id.as_ref())) @@ -574,10 +598,10 @@ where .into_iter() .collect::>(); - let id = BlockId::hash(client.info().best_hash); + let best_hash = client.info().best_hash; let authorities = client - .runtime_api() - .authorities(&id) + .authorities(best_hash) + .await .map_err(|e| Error::CallingRuntime(e.into()))? .into_iter() .map(Into::into) diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index 7b0ee45833e19..8e7a221877574 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -32,6 +32,7 @@ use futures::{ use libp2p::{core::multiaddr, identity::Keypair, PeerId}; use prometheus_endpoint::prometheus::default_registry; +use sc_client_api::HeaderBackend; use sc_network_common::service::{KademliaKey, Signature, SigningError}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_keystore::{testing::KeyStore, CryptoStore}; diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index ea50c8b794ccb..47d43e8b4b03f 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -32,4 +32,5 @@ serde = { version = "1.0.136", features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } thiserror = "1.0" diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 4ff415788f4ea..4177c2452c7f7 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -39,7 +39,6 @@ use libp2p::{ }; use log::debug; -use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::import_queue::{IncomingBlock, Origin}; use sc_network_common::{ config::ProtocolId, @@ -47,7 +46,7 @@ use sc_network_common::{ request_responses::{IfDisconnected, ProtocolConfig, RequestFailure}, }; use sc_peerset::PeersetHandle; -use sp_blockchain::{HeaderBackend, HeaderMetadata}; +use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use sp_runtime::{ traits::{Block as BlockT, NumberFor}, @@ -69,13 +68,7 @@ pub use crate::request_responses::{InboundFailure, OutboundFailure, RequestId, R pub struct Behaviour where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { /// All the substrate-specific protocols. substrate: Protocol, @@ -85,7 +78,7 @@ where /// Discovers nodes of the network. discovery: DiscoveryBehaviour, /// Bitswap server for blockchain data. - bitswap: Toggle>, + bitswap: Toggle>, /// Generic request-response protocols. request_responses: request_responses::RequestResponsesBehaviour, @@ -208,13 +201,7 @@ pub enum BehaviourOut { impl Behaviour where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { /// Builds a new `Behaviour`. pub fn new( @@ -225,7 +212,7 @@ where block_request_protocol_config: ProtocolConfig, state_request_protocol_config: ProtocolConfig, warp_sync_protocol_config: Option, - bitswap: Option>, + bitswap: Option>, light_client_request_protocol_config: ProtocolConfig, // All remaining request protocol configs. mut request_response_protocols: Vec, @@ -352,13 +339,7 @@ fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole { impl NetworkBehaviourEventProcess for Behaviour where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { fn inject_event(&mut self, event: void::Void) { void::unreachable(event) @@ -368,13 +349,7 @@ where impl NetworkBehaviourEventProcess> for Behaviour where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { fn inject_event(&mut self, event: CustomMessageOutcome) { match event { @@ -483,13 +458,7 @@ where impl NetworkBehaviourEventProcess for Behaviour where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { fn inject_event(&mut self, event: request_responses::Event) { match event { @@ -515,13 +484,7 @@ where impl NetworkBehaviourEventProcess for Behaviour where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { fn inject_event(&mut self, event: peer_info::PeerInfoEvent) { let peer_info::PeerInfoEvent::Identified { @@ -548,13 +511,7 @@ where impl NetworkBehaviourEventProcess for Behaviour where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { fn inject_event(&mut self, out: DiscoveryOut) { match out { @@ -592,13 +549,7 @@ where impl Behaviour where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { fn poll( &mut self, diff --git a/client/network/src/bitswap.rs b/client/network/src/bitswap.rs index 2dab45adc5618..52fa0c36caedf 100644 --- a/client/network/src/bitswap.rs +++ b/client/network/src/bitswap.rs @@ -178,24 +178,99 @@ impl Prefix { } } +/// Bitswap trait +pub trait BitswapT { + /// Get single indexed transaction by content hash. + /// + /// Note that this will only fetch transactions + /// that are indexed by the runtime with `storage_index_transaction`. + fn indexed_transaction( + &self, + hash: ::Hash, + ) -> sp_blockchain::Result>>; + + /// Queue of blocks ready to be sent out on `poll()` + fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)>; +} + /// Network behaviour that handles sending and receiving IPFS blocks. -pub struct Bitswap { +struct BitswapInternal { client: Arc, ready_blocks: VecDeque<(PeerId, BitswapMessage)>, _block: PhantomData, } -impl Bitswap { +impl BitswapInternal { /// Create a new instance of the bitswap protocol handler. pub fn new(client: Arc) -> Self { Self { client, ready_blocks: Default::default(), _block: PhantomData::default() } } } -impl NetworkBehaviour for Bitswap +impl BitswapT for BitswapInternal +where + Block: BlockT, + Client: BlockBackend, +{ + fn indexed_transaction( + &self, + hash: ::Hash, + ) -> sp_blockchain::Result>> { + self.client.indexed_transaction(&hash) + } + + fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)> { + &mut self.ready_blocks + } +} + +/// Wrapper for bitswap trait object implement NetworkBehaviour +pub struct Bitswap { + inner: Box + Sync + Send>, +} + +impl Bitswap { + /// Create new Bitswap wrapper + pub fn from_client + Send + Sync + 'static>( + client: Arc, + ) -> Self { + let inner = Box::new(BitswapInternal::new(client)) as Box<_>; + Self { inner } + } +} + +impl BitswapT for Bitswap { + fn indexed_transaction( + &self, + hash: ::Hash, + ) -> sp_blockchain::Result>> { + self.inner.indexed_transaction(hash) + } + + fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)> { + self.inner.ready_blocks() + } +} + +impl BitswapT for Box +where + T: BitswapT, +{ + fn indexed_transaction( + &self, + hash: ::Hash, + ) -> sp_blockchain::Result>> { + T::indexed_transaction(self, hash) + } + + fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)> { + T::ready_blocks(self) + } +} + +impl NetworkBehaviour for Bitswap where B: BlockT, - Client: BlockBackend + Send + Sync + 'static, { type ConnectionHandler = OneShotHandler; type OutEvent = void::Void; @@ -214,10 +289,11 @@ where HandlerEvent::Request(msg) => msg, }; trace!(target: LOG_TARGET, "Received request: {:?} from {}", request, peer); - if self.ready_blocks.len() > MAX_RESPONSE_QUEUE { + if self.ready_blocks().len() > MAX_RESPONSE_QUEUE { debug!(target: LOG_TARGET, "Ignored request: queue is full"); return } + let mut response = BitswapMessage { wantlist: None, blocks: Default::default(), @@ -253,7 +329,7 @@ where } let mut hash = B::Hash::default(); hash.as_mut().copy_from_slice(&cid.hash().digest()[0..32]); - let transaction = match self.client.indexed_transaction(&hash) { + let transaction = match self.indexed_transaction(hash) { Ok(ex) => ex, Err(e) => { error!(target: LOG_TARGET, "Error retrieving transaction {}: {}", hash, e); @@ -292,7 +368,7 @@ where } } trace!(target: LOG_TARGET, "Response: {:?}", response); - self.ready_blocks.push_back((peer, response)); + self.ready_blocks().push_back((peer, response)); } fn poll( @@ -300,7 +376,7 @@ where _ctx: &mut Context, _: &mut impl PollParameters, ) -> Poll> { - if let Some((peer_id, message)) = self.ready_blocks.pop_front() { + if let Some((peer_id, message)) = self.ready_blocks().pop_front() { return Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, handler: NotifyHandler::Any, diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 52fa28e76e207..521aa42827563 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -31,7 +31,7 @@ pub use sc_network_common::{ pub use libp2p::{build_multiaddr, core::PublicKey, identity}; -use crate::ExHashT; +use crate::{bitswap::Bitswap, ExHashT}; use core::{fmt, iter}; use futures::future; @@ -80,6 +80,9 @@ where /// Client that contains the blockchain. pub chain: Arc, + /// Bitswap block request protocol implementation. + pub bitswap: Option>, + /// Pool of transactions. /// /// The network worker will fetch transactions from this object in order to propagate them on diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 351e7d207ad1e..64794538999b0 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -40,7 +40,7 @@ use message::{ }; use notifications::{Notifications, NotificationsOut}; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; -use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; +use sc_client_api::HeaderBackend; use sc_consensus::import_queue::{BlockImportError, BlockImportStatus, IncomingBlock, Origin}; use sc_network_common::{ config::ProtocolId, @@ -56,7 +56,6 @@ use sc_network_common::{ }, }; use sp_arithmetic::traits::SaturatedConversion; -use sp_blockchain::HeaderMetadata; use sp_consensus::BlockOrigin; use sp_runtime::{ generic::BlockId, @@ -262,13 +261,7 @@ impl BlockAnnouncesHandshake { impl Protocol where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { /// Create a new instance. pub fn new( @@ -373,7 +366,7 @@ where let block_announces_protocol = { let genesis_hash = - chain.block_hash(0u32.into()).ok().flatten().expect("Genesis block exists; qed"); + chain.hash(0u32.into()).ok().flatten().expect("Genesis block exists; qed"); if let Some(fork_id) = fork_id { format!("/{}/{}/block-announces/1", hex::encode(genesis_hash), fork_id) } else { @@ -1318,13 +1311,7 @@ pub enum CustomMessageOutcome { impl NetworkBehaviour for Protocol where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { type ConnectionHandler = ::ConnectionHandler; type OutEvent = CustomMessageOutcome; diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 68ac4b8db8a7d..7a196da25260a 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -29,7 +29,6 @@ use crate::{ behaviour::{self, Behaviour, BehaviourOut}, - bitswap::Bitswap, config::{Params, TransportConfig}, discovery::DiscoveryConfig, error::Error, @@ -59,7 +58,6 @@ use libp2p::{ use log::{debug, error, info, trace, warn}; use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; -use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; use sc_network_common::{ config::MultiaddrWithPeerId, @@ -75,7 +73,7 @@ use sc_network_common::{ }; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; -use sp_blockchain::{HeaderBackend, HeaderMetadata}; +use sp_blockchain::HeaderBackend; use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::{ borrow::Cow, @@ -137,13 +135,7 @@ impl NetworkWorker where B: BlockT + 'static, H: ExHashT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: sp_blockchain::HeaderBackend + 'static, { /// Creates the network service. /// @@ -220,7 +212,7 @@ where params.protocol_id.clone(), params .chain - .block_hash(0u32.into()) + .hash(0u32.into()) .ok() .flatten() .expect("Genesis block exists; qed"), @@ -374,7 +366,6 @@ where }; let behaviour = { - let bitswap = params.network_config.ipfs_server.then(|| Bitswap::new(params.chain)); let result = Behaviour::new( protocol, user_agent, @@ -383,7 +374,7 @@ where params.block_request_protocol_config, params.state_request_protocol_config, params.warp_sync_protocol_config, - bitswap, + params.bitswap, params.light_client_request_protocol_config, params.network_config.request_response_protocols, peerset_handle.clone(), @@ -1297,13 +1288,7 @@ pub struct NetworkWorker where B: BlockT + 'static, H: ExHashT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. external_addresses: Arc>>, @@ -1336,13 +1321,7 @@ impl Future for NetworkWorker where B: BlockT + 'static, H: ExHashT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { type Output = (); @@ -1375,7 +1354,6 @@ where Poll::Ready(None) => return Poll::Ready(()), Poll::Pending => break, }; - match msg { ServiceToWorkerMsg::AnnounceBlock(hash, data) => this .network_service @@ -1988,13 +1966,7 @@ impl Unpin for NetworkWorker where B: BlockT + 'static, H: ExHashT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { } @@ -2002,13 +1974,7 @@ where struct NetworkLink<'a, B, Client> where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { protocol: &'a mut Swarm>, } @@ -2016,13 +1982,7 @@ where impl<'a, B, Client> Link for NetworkLink<'a, B, Client> where B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, + Client: HeaderBackend + 'static, { fn blocks_processed( &mut self, diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index e2fe58423abfe..e0d8798aef91e 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -146,6 +146,7 @@ fn build_test_full_node( import_queue, chain_sync: Box::new(chain_sync), metrics_registry: None, + bitswap: None, block_request_protocol_config, state_request_protocol_config, light_client_request_protocol_config, diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index fbe56f463d0f3..323af13943de7 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -883,6 +883,7 @@ where import_queue, chain_sync: Box::new(chain_sync), metrics_registry: None, + bitswap: None, block_request_protocol_config, state_request_protocol_config, light_client_request_protocol_config, diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index de04af259600b..f03ba6de2866d 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -37,7 +37,7 @@ use sc_client_db::{Backend, DatabaseSettings}; use sc_consensus::import_queue::ImportQueue; use sc_executor::RuntimeVersionOf; use sc_keystore::LocalKeystore; -use sc_network::{config::SyncMode, NetworkService}; +use sc_network::{bitswap::Bitswap, config::SyncMode, NetworkService}; use sc_network_common::{ service::{NetworkStateInfo, NetworkStatusProvider, NetworkTransaction}, sync::warp::WarpSyncProvider, @@ -711,7 +711,6 @@ pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> { /// An optional warp sync provider. pub warp_sync: Option>>, } - /// Build the network service, the network status sinks and an RPC sender. pub fn build_network( params: BuildNetworkParams, @@ -857,6 +856,7 @@ where fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), import_queue: Box::new(import_queue), chain_sync: Box::new(chain_sync), + bitswap: config.network.ipfs_server.then(|| Bitswap::from_client(client.clone())), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_request_protocol_config, state_request_protocol_config, @@ -923,6 +923,11 @@ where pub struct NetworkStarter(oneshot::Sender<()>); impl NetworkStarter { + /// Create a new NetworkStarter + pub fn new(sender: oneshot::Sender<()>) -> Self { + NetworkStarter(sender) + } + /// Start the network. Call this after all sub-components have been initialized. /// /// > **Note**: If you don't call this function, the networking will not work. From 435218f5c4d0045d92d094641c915c31513cf2bf Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Thu, 1 Sep 2022 04:31:05 +0800 Subject: [PATCH 1106/1472] Only log when the transaction is actually to be propagated (#12158) The logging before is confusing as it says Propagating but it's not in fact when gossip_enabled is false. Now it's also consistent with `propagate_transactions` below. --- client/network/src/transactions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index f7e4d774ca812..f557ec0cec7c7 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -425,11 +425,11 @@ impl TransactionsHandler { /// Propagate one transaction. pub fn propagate_transaction(&mut self, hash: &H) { - debug!(target: "sync", "Propagating transaction [{:?}]", hash); // Accept transactions only when enabled if !self.gossip_enabled.load(Ordering::Relaxed) { return } + debug!(target: "sync", "Propagating transaction [{:?}]", hash); if let Some(transaction) = self.transaction_pool.transaction(hash) { let propagated_to = self.do_propagate_transactions(&[(hash.clone(), transaction)]); self.transaction_pool.on_broadcasted(propagated_to); From 6fbcc571ddf42fc62306e5ac7f5bc8e22a7757e7 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Thu, 1 Sep 2022 10:45:20 +0200 Subject: [PATCH 1107/1472] Uniques: Reset approved account after transfer (#12145) * reset approved account * wrap at 100 * doc * fmt * Update frame/uniques/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * new test * Update frame/uniques/src/lib.rs Co-authored-by: Keith Yeung * fmt Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Keith Yeung --- frame/uniques/src/functions.rs | 6 ++++++ frame/uniques/src/lib.rs | 4 ++++ frame/uniques/src/tests.rs | 38 ++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 107214558307f..4e68f1139420d 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -48,6 +48,12 @@ impl, I: 'static> Pallet { Account::::insert((&dest, &collection, &item), ()); let origin = details.owner; details.owner = dest; + + // The approved account has to be reset to None, because otherwise pre-approve attack would + // be possible, where the owner can approve his second account before making the transaction + // and then claiming the item back. + details.approved = None; + Item::::insert(&collection, &item, &details); ItemPriceOf::::remove(&collection, &item); diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 70f10ca4f8b39..3b0cf6dc673c9 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -606,6 +606,8 @@ pub mod pallet { /// Move an item from the sender account to another. /// + /// This resets the approved account of the item. + /// /// Origin must be Signed and the signing account must be either: /// - the Admin of the `collection`; /// - the Owner of the `item`; @@ -914,6 +916,8 @@ pub mod pallet { /// - `item`: The item of the item to be approved for delegated transfer. /// - `delegate`: The account to delegate permission to transfer the item. /// + /// Important NOTE: The `approved` account gets reset after each transfer. + /// /// Emits `ApprovedTransfer` on success. /// /// Weight: `O(1)` diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 8b1d00d7ba0c7..85d1bec574cf0 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -557,6 +557,44 @@ fn approval_lifecycle_works() { }); } +#[test] +fn approved_account_gets_reset_after_transfer() { + new_test_ext().execute_with(|| { + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + + assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 5)); + + // this shouldn't work because we have just transfered the item to another account. + assert_noop!(Uniques::transfer(Origin::signed(3), 0, 42, 4), Error::::NoPermission); + // The new owner can transfer fine: + assert_ok!(Uniques::transfer(Origin::signed(5), 0, 42, 6)); + }); +} + +#[test] +fn approved_account_gets_reset_after_buy_item() { + new_test_ext().execute_with(|| { + let item = 1; + let price = 15; + + Balances::make_free_balance_be(&2, 100); + + assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(Origin::signed(1), 0, item, 1)); + assert_ok!(Uniques::approve_transfer(Origin::signed(1), 0, item, 5)); + + assert_ok!(Uniques::set_price(Origin::signed(1), 0, item, Some(price), None)); + + assert_ok!(Uniques::buy_item(Origin::signed(2), 0, item, price)); + + // this shouldn't work because the item has been bough and the approved account should be + // reset. + assert_noop!(Uniques::transfer(Origin::signed(5), 0, item, 4), Error::::NoPermission); + }); +} + #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { From 4f8207d80868eba5bafabef179f991ccc12fc555 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Thu, 1 Sep 2022 12:31:32 +0200 Subject: [PATCH 1108/1472] Alliance pallet: add force_set_members instead of init_members function (#11997) * Alliance pallet: add force_set_members instead of init_members function * benchmark with witness data * remove invalid limit for clear * Apply suggestions from code review Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Revert "remove invalid limit for clear" This reverts commit b654d6834c321541b5aa4c8589937a233ade411f. * compile constructor only for test * Update comments for force_set_members Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * ".git/.scripts/bench-bot.sh" pallet dev pallet_alliance * benchmark - founders count range * Revert "benchmark - founders count range" This reverts commit 744178f7680e5dc6d5b870bf9c4ce601990ab13b. * witness members count instead votable members count * update the doc * use decode_len for witness data checks * change witness data member count to voting member count; update clear limits * ".git/.scripts/bench-bot.sh" pallet dev pallet_alliance * merge master * fixes after merge master * revert to cb3e63 * disband alliance and return deposits * revert debug changes * weights * update docs * update test comments * Apply Joe suggestions from code review Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * rename event from AllianceDisband to AllianceDisbanded * ".git/.scripts/bench-bot.sh" pallet dev pallet_alliance Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: command-bot <> --- bin/node/runtime/src/impls.rs | 12 +- frame/alliance/README.md | 2 +- frame/alliance/src/benchmarking.rs | 174 ++++++++++++++++-- frame/alliance/src/lib.rs | 154 +++++++++++++--- frame/alliance/src/mock.rs | 56 +++++- frame/alliance/src/tests.rs | 183 ++++++++++++++++--- frame/alliance/src/types.rs | 31 ++++ frame/alliance/src/weights.rs | 280 ++++++++++++++++------------- 8 files changed, 711 insertions(+), 181 deletions(-) diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 510955a5b7b3e..4d58abc81d16d 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -18,7 +18,8 @@ //! Some configurable implementations as associated type for the substrate runtime. use crate::{ - AccountId, AllianceMotion, Assets, Authorship, Balances, Call, Hash, NegativeImbalance, Runtime, + AccountId, AllianceCollective, AllianceMotion, Assets, Authorship, Balances, Call, Hash, + NegativeImbalance, Runtime, }; use frame_support::{ pallet_prelude::*, @@ -112,6 +113,15 @@ impl ProposalProvider for AllianceProposalProvider { fn proposal_of(proposal_hash: Hash) -> Option { AllianceMotion::proposal_of(proposal_hash) } + + fn proposals() -> Vec { + AllianceMotion::proposals().into_inner() + } + + fn proposals_count() -> u32 { + pallet_collective::Proposals::::decode_len().unwrap_or(0) + as u32 + } } #[cfg(test)] diff --git a/frame/alliance/README.md b/frame/alliance/README.md index f91475a5984ea..3fcd40b9527ce 100644 --- a/frame/alliance/README.md +++ b/frame/alliance/README.md @@ -66,4 +66,4 @@ to update the Alliance's rule and make announcements. #### Root Calls -- `init_founders` - Initialize the founding members. +- `force_set_members` - Set the members via chain governance. diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index 33cf933aba421..60df1e1a84d37 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -38,6 +38,11 @@ fn assert_last_event, I: 'static>(generic_event: >:: frame_system::Pallet::::assert_last_event(generic_event.into()); } +fn assert_prev_event, I: 'static>(generic_event: >::Event) { + let events = frame_system::Pallet::::events(); + assert_eq!(events.get(events.len() - 2).expect("events expected").event, generic_event.into()); +} + fn cid(input: impl AsRef<[u8]>) -> Cid { use sha2::{Digest, Sha256}; let mut hasher = Sha256::new(); @@ -121,7 +126,13 @@ benchmarks_instance_pallet! { let proposer = founders[0].clone(); let fellows = (0 .. y).map(fellow::).collect::>(); - Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + Alliance::::force_set_members( + SystemOrigin::Root.into(), + founders, + fellows, + vec![], + Default::default(), + )?; let threshold = m; // Add previous proposals. @@ -167,7 +178,13 @@ benchmarks_instance_pallet! { members.extend(founders.clone()); members.extend(fellows.clone()); - Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + Alliance::::force_set_members( + SystemOrigin::Root.into(), + founders, + fellows, + vec![], + Default::default(), + )?; // Threshold is 1 less than the number of members so that one person can vote nay let threshold = m - 1; @@ -230,7 +247,13 @@ benchmarks_instance_pallet! { let founders = (0 .. m).map(founder::).collect::>(); let vetor = founders[0].clone(); - Alliance::::init_members(SystemOrigin::Root.into(), founders, vec![], vec![])?; + Alliance::::force_set_members( + SystemOrigin::Root.into(), + founders, + vec![], + vec![], + Default::default(), + )?; // Threshold is one less than total members so that two nays will disapprove the vote let threshold = m - 1; @@ -276,7 +299,13 @@ benchmarks_instance_pallet! { members.extend(founders.clone()); members.extend(fellows.clone()); - Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + Alliance::::force_set_members( + SystemOrigin::Root.into(), + founders, + fellows, + vec![], + Default::default(), + )?; let proposer = members[0].clone(); let voter = members[1].clone(); @@ -356,7 +385,13 @@ benchmarks_instance_pallet! { members.extend(founders.clone()); members.extend(fellows.clone()); - Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + Alliance::::force_set_members( + SystemOrigin::Root.into(), + founders, + fellows, + vec![], + Default::default(), + )?; let proposer = members[0].clone(); let voter = members[1].clone(); @@ -442,7 +477,13 @@ benchmarks_instance_pallet! { members.extend(founders.clone()); members.extend(fellows.clone()); - Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + Alliance::::force_set_members( + SystemOrigin::Root.into(), + founders, + fellows, + vec![], + Default::default(), + )?; let proposer = members[0].clone(); let voter = members[1].clone(); @@ -513,7 +554,13 @@ benchmarks_instance_pallet! { members.extend(founders.clone()); members.extend(fellows.clone()); - Alliance::::init_members(SystemOrigin::Root.into(), founders, fellows, vec![])?; + Alliance::::force_set_members( + SystemOrigin::Root.into(), + founders, + fellows, + vec![], + Default::default(), + )?; let proposer = members[0].clone(); let voter = members[1].clone(); @@ -568,21 +615,124 @@ benchmarks_instance_pallet! { assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); } - init_members { - // at least 2 founders - let x in 2 .. T::MaxFounders::get(); + force_set_members { + // at least 1 founders + let x in 1 .. T::MaxFounders::get(); let y in 0 .. T::MaxFellows::get(); let z in 0 .. T::MaxAllies::get(); + let p in 0 .. T::MaxProposals::get(); + let c in 0 .. T::MaxFounders::get() + T::MaxFellows::get(); + let m in 0 .. T::MaxAllies::get(); - let mut founders = (2 .. x).map(founder::).collect::>(); + let mut founders = (0 .. x).map(founder::).collect::>(); + let mut proposer = founders[0].clone(); let mut fellows = (0 .. y).map(fellow::).collect::>(); let mut allies = (0 .. z).map(ally::).collect::>(); + let witness = ForceSetWitness{ + proposals: p, + voting_members: c, + ally_members: m, + }; + let mut old_fellows: Vec = Vec::new(); + let mut old_allies: Vec = Vec::new(); + + let mut cc = c; + if (m > 0 && c == 0) || (p > 0 && c == 0) { + // if total member count `m` greater than zero, + // one voting member required to set non voting members. + // OR + // if some proposals, + // one voting member required to create proposal. + cc = 1; + } - }: _(SystemOrigin::Root, founders.clone(), fellows.clone(), allies.clone()) + // setting the Alliance to disband on the benchmark call + if cc > 0 { + old_fellows = (0..cc).map(fellow::).collect::>(); + old_allies = (0..m).map(ally::).collect::>(); + + // used later for proposal creation. + proposer = old_fellows[0].clone(); + + // set alliance before benchmarked call to include alliance disband. + Alliance::::force_set_members( + SystemOrigin::Root.into(), + vec![old_fellows[0].clone()], + vec![], + vec![], + Default::default(), + )?; + + // using `join_alliance` instead `force_set_members` to join alliance + // to have deposit reserved and bench the worst case scenario. + for fellow in old_fellows.iter().skip(1) { + Alliance::::join_alliance( + SystemOrigin::Signed(fellow.clone()).into() + ).unwrap(); + } + + // elevating allies to have desired voting members count. + for fellow in old_fellows.iter().skip(1) { + Alliance::::elevate_ally( + T::MembershipManager::successful_origin(), + T::Lookup::unlookup(fellow.clone()) + ).unwrap(); + } + + for ally in old_allies.iter() { + Alliance::::join_alliance( + SystemOrigin::Signed(ally.clone()).into() + ).unwrap(); + } + + assert_eq!(Alliance::::votable_members_count(), cc); + assert_eq!(Alliance::::ally_members_count(), m); + } + + // adding proposals to veto on the Alliance reset + for i in 0..p { + let threshold = cc; + let bytes_in_storage = i + size_of::() as u32 + 32; + // proposals should be different so that different proposal hashes are generated + let proposal: T::Proposal = + AllianceCall::::set_rule { rule: rule(vec![i as u8; i as usize]) }.into(); + Alliance::::propose( + SystemOrigin::Signed(proposer.clone()).into(), + threshold, + Box::new(proposal), + bytes_in_storage, + )?; + } + let mut proposals = T::ProposalProvider::proposals(); + if c != cc { + // removing a helper founder from the alliance which should not be + // included in the actual benchmark call. + Alliance::::give_retirement_notice( + SystemOrigin::Signed(proposer.clone()).into() + )?; + System::::set_block_number( + System::::block_number() + T::RetirementPeriod::get() + ); + Alliance::::retire( + SystemOrigin::Signed(proposer.clone()).into() + )?; + // remove a helper founder from fellows list. + old_fellows.remove(0); + } + }: _(SystemOrigin::Root, founders.clone(), fellows.clone(), allies.clone(), witness) verify { founders.sort(); fellows.sort(); allies.sort(); + if !witness.is_zero() { + old_fellows.append(&mut old_allies); + old_fellows.sort(); + proposals.sort(); + assert_prev_event::(Event::AllianceDisbanded { + members: old_fellows, + proposals: proposals, + }.into()); + } assert_last_event::(Event::MembersInitialized { founders: founders.clone(), fellows: fellows.clone(), diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index bc0a119cd54a6..99cb46c9ef58d 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -84,7 +84,7 @@ //! //! #### Root Calls //! -//! - `init_founders` - Initialize the founding members. +//! - `force_set_members` - Set the members via chain governance. #![cfg_attr(not(feature = "std"), no_std)] @@ -172,6 +172,8 @@ impl IdentityVerifier for () { /// The provider of a collective action interface, for example an instance of `pallet-collective`. pub trait ProposalProvider { + /// Add a new proposal. + /// Returns a proposal length and active proposals count if successful. fn propose_proposal( who: AccountId, threshold: u32, @@ -179,6 +181,8 @@ pub trait ProposalProvider { length_bound: u32, ) -> Result<(u32, u32), DispatchError>; + /// Add an aye or nay vote for the sender to the given proposal. + /// Returns true if the sender votes first time if successful. fn vote_proposal( who: AccountId, proposal: Hash, @@ -186,8 +190,11 @@ pub trait ProposalProvider { approve: bool, ) -> Result; + /// Veto a proposal, closing and removing it from the system, regardless of its current state. + /// Returns an active proposals count, which includes removed proposal. fn veto_proposal(proposal_hash: Hash) -> u32; + /// Close a proposal that is either approved, disapproved, or whose voting period has ended. fn close_proposal( proposal_hash: Hash, index: ProposalIndex, @@ -195,7 +202,16 @@ pub trait ProposalProvider { length_bound: u32, ) -> DispatchResultWithPostInfo; + /// Return a proposal of the given hash. fn proposal_of(proposal_hash: Hash) -> Option; + + /// Return hashes of all active proposals. + fn proposals() -> Vec; + + // Return count of all active proposals. + // + // Used to check witness data for an extrinsic. + fn proposals_count() -> u32; } /// The various roles that a member can hold. @@ -324,10 +340,10 @@ pub mod pallet { #[pallet::error] pub enum Error { - /// The founders/fellows/allies have already been initialized. - AllianceAlreadyInitialized, /// The Alliance has not been initialized yet, therefore accounts cannot join it. AllianceNotYetInitialized, + /// The Alliance has been initialized, therefore cannot be initialized again. + AllianceAlreadyInitialized, /// Account is already a member. AlreadyMember, /// Account is not a member. @@ -367,12 +383,16 @@ pub mod pallet { TooManyMembers, /// Number of announcements exceeds `MaxAnnouncementsCount`. TooManyAnnouncements, + /// Invalid witness data given. + BadWitness, /// Account already gave retirement notice AlreadyRetiring, /// Account did not give a retirement notice required to retire. RetirementNoticeNotGiven, /// Retirement period has not passed. RetirementPeriodNotPassed, + /// Founders must be provided to initialize the Alliance. + FoundersMissing, } #[pallet::event] @@ -408,6 +428,8 @@ pub mod pallet { UnscrupulousItemAdded { items: Vec> }, /// Accounts or websites have been removed from the list of unscrupulous items. UnscrupulousItemRemoved { items: Vec> }, + /// Alliance disbanded. + AllianceDisbanded { members: Vec, proposals: Vec }, } #[pallet::genesis_config] @@ -451,15 +473,22 @@ pub mod pallet { !Pallet::::has_member(MemberRole::Fellow), "Fellows are already initialized!" ); + assert!( + !self.founders.is_empty(), + "Founders must be provided to initialize the Alliance" + ); let members: BoundedVec = self.fellows.clone().try_into().expect("Too many genesis fellows"); Members::::insert(MemberRole::Fellow, members); } if !self.allies.is_empty() { - // Only allow Allies if the Alliance is "initialized". assert!( - Pallet::::is_initialized(), - "Alliance must have Founders or Fellows to have Allies" + !Pallet::::has_member(MemberRole::Ally), + "Allies are already initialized!" + ); + assert!( + !self.founders.is_empty(), + "Founders must be provided to initialize the Alliance" ); let members: BoundedVec = self.allies.clone().try_into().expect("Too many genesis allies"); @@ -619,24 +648,80 @@ pub mod pallet { } /// Initialize the founders, fellows, and allies. + /// Founders must be provided to initialize the Alliance. + /// + /// Provide witness data to disband current Alliance before initializing new. + /// Alliance must be empty or disband first to initialize new. /// - /// This should only be called once, and must be called by the Root origin. - #[pallet::weight(T::WeightInfo::init_members( + /// Alliance is only disbanded if new member set is not provided. + /// + /// Must be called by the Root origin. + #[pallet::weight(T::WeightInfo::force_set_members( T::MaxFounders::get(), T::MaxFellows::get(), - T::MaxAllies::get() + T::MaxAllies::get(), + witness.proposals, + witness.voting_members, + witness.ally_members, ))] - pub fn init_members( + pub fn force_set_members( origin: OriginFor, founders: Vec, fellows: Vec, allies: Vec, + witness: ForceSetWitness, ) -> DispatchResult { ensure_root(origin)?; - // Cannot be called if the Alliance already has Founders or Fellows. - // TODO: Remove check and allow Root to set members at any time. - // https://github.com/paritytech/substrate/issues/11928 + if !witness.is_zero() { + // Disband Alliance by removing all members and returning deposits. + // Veto and remove all active proposals to avoid any unexpected behavior from + // actionable items managed outside of the pallet. Items managed within the pallet, + // like `UnscrupulousWebsites`, are left for the new Alliance to clean up or keep. + + ensure!( + T::ProposalProvider::proposals_count() <= witness.proposals, + Error::::BadWitness + ); + ensure!( + Self::votable_members_count() <= witness.voting_members, + Error::::BadWitness + ); + ensure!( + Self::ally_members_count() <= witness.ally_members, + Error::::BadWitness + ); + + let mut proposals = T::ProposalProvider::proposals(); + for hash in proposals.iter() { + T::ProposalProvider::veto_proposal(*hash); + } + + let mut members = Self::votable_members(); + T::MembershipChanged::change_members_sorted(&[], &members, &[]); + + members.append(&mut Self::members_of(MemberRole::Ally)); + for member in members.iter() { + if let Some(deposit) = DepositOf::::take(&member) { + let err_amount = T::Currency::unreserve(&member, deposit); + debug_assert!(err_amount.is_zero()); + } + } + + Members::::remove(&MemberRole::Founder); + Members::::remove(&MemberRole::Fellow); + Members::::remove(&MemberRole::Ally); + + members.sort(); + proposals.sort(); + Self::deposit_event(Event::AllianceDisbanded { members, proposals }); + } + + if founders.is_empty() { + ensure!(fellows.is_empty() && allies.is_empty(), Error::::FoundersMissing); + // new members set not provided. + return Ok(()) + } ensure!(!Self::is_initialized(), Error::::AllianceAlreadyInitialized); let mut founders: BoundedVec = @@ -665,9 +750,11 @@ pub mod pallet { T::InitializeMembers::initialize_members(&voteable_members); log::debug!( - target: "runtime::alliance", + target: LOG_TARGET, "Initialize alliance founders: {:?}, fellows: {:?}, allies: {:?}", - founders, fellows, allies + founders, + fellows, + allies ); Self::deposit_event(Event::MembersInitialized { @@ -913,7 +1000,9 @@ pub mod pallet { impl, I: 'static> Pallet { /// Check if the Alliance has been initialized. fn is_initialized() -> bool { - Self::has_member(MemberRole::Founder) || Self::has_member(MemberRole::Fellow) + Self::has_member(MemberRole::Founder) || + Self::has_member(MemberRole::Fellow) || + Self::has_member(MemberRole::Ally) } /// Check if a given role has any members. @@ -957,13 +1046,36 @@ impl, I: 'static> Pallet { Self::is_founder(who) || Self::is_fellow(who) } + /// Count of ally members. + fn ally_members_count() -> u32 { + Members::::decode_len(MemberRole::Ally).unwrap_or(0) as u32 + } + + /// Count of all members who have voting rights. + fn votable_members_count() -> u32 { + Members::::decode_len(MemberRole::Founder) + .unwrap_or(0) + .saturating_add(Members::::decode_len(MemberRole::Fellow).unwrap_or(0)) as u32 + } + + /// Get all members of a given role. + fn members_of(role: MemberRole) -> Vec { + Members::::get(role).into_inner() + } + /// Collect all members who have voting rights into one list. - fn votable_members_sorted() -> Vec { - let mut founders = Members::::get(MemberRole::Founder).into_inner(); - let mut fellows = Members::::get(MemberRole::Fellow).into_inner(); + fn votable_members() -> Vec { + let mut founders = Self::members_of(MemberRole::Founder); + let mut fellows = Self::members_of(MemberRole::Fellow); founders.append(&mut fellows); - founders.sort(); - founders.into() + founders + } + + /// Collect all members who have voting rights into one sorted list. + fn votable_members_sorted() -> Vec { + let mut members = Self::votable_members(); + members.sort(); + members } /// Add a user to the sorted alliance member set. diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index adc313e28ed7e..f2632ec3db08c 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -18,6 +18,7 @@ //! Test utilities pub use sp_core::H256; +use sp_runtime::traits::Hash; pub use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, @@ -196,6 +197,14 @@ impl ProposalProvider for AllianceProposalProvider { fn proposal_of(proposal_hash: H256) -> Option { AllianceMotion::proposal_of(proposal_hash) } + + fn proposals() -> Vec { + AllianceMotion::proposals().into_inner() + } + + fn proposals_count() -> u32 { + pallet_collective::Proposals::::decode_len().unwrap_or(0) as u32 + } } parameter_types! { @@ -254,7 +263,17 @@ pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { - balances: vec![(1, 50), (2, 50), (3, 50), (4, 50), (5, 30), (6, 50), (7, 50)], + balances: vec![ + (1, 50), + (2, 50), + (3, 50), + (4, 50), + (5, 30), + (6, 50), + (7, 50), + (8, 50), + (9, 50), + ], } .assimilate_storage(&mut t) .unwrap(); @@ -296,6 +315,10 @@ pub fn new_test_ext() -> sp_io::TestExternalities { assert_ok!(Identity::set_identity(Origin::signed(5), Box::new(info.clone()))); assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 5, Judgement::KnownGood)); assert_ok!(Identity::set_identity(Origin::signed(6), Box::new(info.clone()))); + assert_ok!(Identity::set_identity(Origin::signed(8), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 8, Judgement::KnownGood)); + assert_ok!(Identity::set_identity(Origin::signed(9), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 9, Judgement::KnownGood)); // Joining before init should fail. assert_noop!( @@ -303,7 +326,13 @@ pub fn new_test_ext() -> sp_io::TestExternalities { Error::::AllianceNotYetInitialized ); - assert_ok!(Alliance::init_members(Origin::root(), vec![1, 2], vec![3], vec![])); + assert_ok!(Alliance::force_set_members( + Origin::root(), + vec![1, 2], + vec![3], + vec![], + Default::default() + )); System::set_block_number(1); }); @@ -323,10 +352,25 @@ pub fn test_cid() -> Cid { Cid::new_v0(&*result) } -pub fn make_proposal(value: u64) -> Call { - Call::System(frame_system::Call::remark { remark: value.encode() }) +pub fn make_remark_proposal(value: u64) -> (Call, u32, H256) { + make_proposal(Call::System(frame_system::Call::remark { remark: value.encode() })) +} + +pub fn make_set_rule_proposal(rule: Cid) -> (Call, u32, H256) { + make_proposal(Call::Alliance(pallet_alliance::Call::set_rule { rule })) +} + +pub fn make_kick_member_proposal(who: u64) -> (Call, u32, H256) { + make_proposal(Call::Alliance(pallet_alliance::Call::kick_member { who })) +} + +pub fn make_proposal(proposal: Call) -> (Call, u32, H256) { + let len: u32 = proposal.using_encoded(|p| p.len() as u32); + let hash = BlakeTwo256::hash_of(&proposal); + (proposal, len, hash) } -pub fn make_set_rule_proposal(rule: Cid) -> Call { - Call::Alliance(pallet_alliance::Call::set_rule { rule }) +pub fn assert_prev_event(event: Event) { + let events = System::events(); + assert_eq!(events.get(events.len() - 2).expect("events expected").event, event); } diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index 918cfa840c3f0..3bd82a8870efe 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -17,9 +17,7 @@ //! Tests for the alliance pallet. -use sp_runtime::traits::Hash; - -use frame_support::{assert_noop, assert_ok, error::BadOrigin, Hashable}; +use frame_support::{assert_noop, assert_ok, error::BadOrigin}; use frame_system::{EventRecord, Phase}; use super::*; @@ -27,12 +25,156 @@ use crate::mock::*; type AllianceMotionEvent = pallet_collective::Event; +#[test] +fn force_set_members_works() { + new_test_ext().execute_with(|| { + // ensure alliance is set + assert_eq!(Alliance::votable_members_sorted(), vec![1, 2, 3]); + + // creating and proposing proposals + let (proposal, proposal_len, hash) = make_remark_proposal(42); + assert_ok!(Alliance::propose(Origin::signed(1), 3, Box::new(proposal), proposal_len)); + + let (k_proposal, k_proposal_len, k_hash) = make_kick_member_proposal(2); + assert_ok!(Alliance::propose(Origin::signed(1), 3, Box::new(k_proposal), k_proposal_len)); + let mut proposals = vec![hash, k_hash]; + + // give a retirement notice to check later a retiring member not removed + assert_ok!(Alliance::give_retirement_notice(Origin::signed(2))); + assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); + + // join alliance and reserve funds + assert_eq!(Balances::free_balance(9), 40); + assert_ok!(Alliance::join_alliance(Origin::signed(9))); + assert_eq!(Alliance::deposit_of(9), Some(25)); + assert_eq!(Balances::free_balance(9), 15); + assert!(Alliance::is_member_of(&9, MemberRole::Ally)); + + // ensure proposal is listed as active proposal + assert_eq!(::ProposalProvider::proposals(), proposals); + assert_eq!(::ProposalProvider::proposals_count(), 2); + + // fails without root + assert_noop!( + Alliance::force_set_members( + Origin::signed(1), + vec![], + vec![], + vec![], + Default::default() + ), + BadOrigin + ); + + // nothing to do, witness data is default, new members not provided. + assert_ok!(Alliance::force_set_members( + Origin::root(), + vec![], + vec![], + vec![], + Default::default() + )); + + // alliance must be reset first, no witness data. + assert_noop!( + Alliance::force_set_members( + Origin::root(), + vec![8], + vec![], + vec![], + Default::default() + ), + Error::::AllianceAlreadyInitialized, + ); + + // wrong witness data checks + assert_noop!( + Alliance::force_set_members( + Origin::root(), + vec![], + vec![], + vec![], + ForceSetWitness::new(1, 3, 1) + ), + Error::::BadWitness, + ); + assert_noop!( + Alliance::force_set_members( + Origin::root(), + vec![], + vec![], + vec![], + ForceSetWitness::new(2, 1, 1) + ), + Error::::BadWitness, + ); + assert_noop!( + Alliance::force_set_members( + Origin::root(), + vec![], + vec![], + vec![], + ForceSetWitness::new(1, 3, 0) + ), + Error::::BadWitness, + ); + + // founders missing, other members given + assert_noop!( + Alliance::force_set_members( + Origin::root(), + vec![], + vec![4], + vec![2], + ForceSetWitness::new(2, 3, 1) + ), + Error::::FoundersMissing, + ); + + // success call + assert_ok!(Alliance::force_set_members( + Origin::root(), + vec![8, 5], + vec![4], + vec![2], + ForceSetWitness::new(2, 3, 1) + )); + + // assert new set of voting members + assert_eq!(Alliance::votable_members_sorted(), vec![4, 5, 8]); + // assert new ally member + assert!(Alliance::is_ally(&2)); + // assert a retiring member from previous Alliance not removed + assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); + // assert old alliance disband. + assert!(!Alliance::is_member(&1)); + assert!(!Alliance::is_member(&3)); + assert!(!Alliance::is_member(&9)); + // deposit unreserved + assert_eq!(Balances::free_balance(9), 40); + // all proposals are removed + assert_eq!(::ProposalProvider::proposals(), vec![]); + assert_eq!(::ProposalProvider::proposals_count(), 0); + + // assert events + proposals.sort(); + assert_prev_event(mock::Event::Alliance(crate::Event::AllianceDisbanded { + members: vec![1, 3, 9], + proposals, + })); + + System::assert_last_event(mock::Event::Alliance(crate::Event::MembersInitialized { + founders: vec![5, 8], + fellows: vec![4], + allies: vec![2], + })); + }) +} + #[test] fn propose_works() { new_test_ext().execute_with(|| { - let proposal = make_proposal(42); - let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let hash: H256 = proposal.blake2_256().into(); + let (proposal, proposal_len, hash) = make_remark_proposal(42); // only votable member can propose proposal, 4 is ally not have vote rights assert_noop!( @@ -67,9 +209,7 @@ fn propose_works() { #[test] fn vote_works() { new_test_ext().execute_with(|| { - let proposal = make_proposal(42); - let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let hash: H256 = proposal.blake2_256().into(); + let (proposal, proposal_len, hash) = make_remark_proposal(42); assert_ok!(Alliance::propose( Origin::signed(1), 3, @@ -103,9 +243,7 @@ fn vote_works() { #[test] fn veto_works() { new_test_ext().execute_with(|| { - let proposal = make_proposal(42); - let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let hash: H256 = proposal.blake2_256().into(); + let (proposal, proposal_len, hash) = make_remark_proposal(42); assert_ok!(Alliance::propose( Origin::signed(1), 3, @@ -119,9 +257,7 @@ fn veto_works() { ); let cid = test_cid(); - let vetoable_proposal = make_set_rule_proposal(cid); - let vetoable_proposal_len: u32 = vetoable_proposal.using_encoded(|p| p.len() as u32); - let vetoable_hash: H256 = vetoable_proposal.blake2_256().into(); + let (vetoable_proposal, vetoable_proposal_len, vetoable_hash) = make_set_rule_proposal(cid); assert_ok!(Alliance::propose( Origin::signed(1), 3, @@ -163,10 +299,8 @@ fn veto_works() { #[test] fn close_works() { new_test_ext().execute_with(|| { - let proposal = make_proposal(42); - let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); + let (proposal, proposal_len, hash) = make_remark_proposal(42); let proposal_weight = proposal.get_dispatch_info().weight; - let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Alliance::propose( Origin::signed(1), 3, @@ -452,9 +586,18 @@ fn retire_works() { fn assert_powerless(user: Origin) { //vote / veto with a valid propsal let cid = test_cid(); - let proposal = make_proposal(42); + let (proposal, _, _) = make_kick_member_proposal(42); - assert_noop!(Alliance::init_members(user.clone(), vec![], vec![], vec![]), BadOrigin); + assert_noop!( + Alliance::force_set_members( + user.clone(), + vec![], + vec![], + vec![], + ForceSetWitness { voting_members: 3, ..Default::default() } + ), + BadOrigin + ); assert_noop!(Alliance::set_rule(user.clone(), cid.clone()), BadOrigin); diff --git a/frame/alliance/src/types.rs b/frame/alliance/src/types.rs index 8fb0ae96fd02d..a7fa9f83e4cf3 100644 --- a/frame/alliance/src/types.rs +++ b/frame/alliance/src/types.rs @@ -93,3 +93,34 @@ impl Cid { } } } + +/// Witness data for the `force_set_members` call. +/// Relevant only if executed on an initialized alliance to reset it. +#[derive( + Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo, Default, +)] +pub struct ForceSetWitness { + /// Number of active proposals which will be vetoed and removed. + #[codec(compact)] + pub(super) proposals: u32, + /// Total number of voting members in the current alliance. + #[codec(compact)] + pub(super) voting_members: u32, + /// Total number of ally members in the current alliance. + #[codec(compact)] + pub(super) ally_members: u32, +} + +#[cfg(test)] +impl ForceSetWitness { + // Creates new ForceSetWitness. + pub(super) fn new(proposals: u32, voting_members: u32, ally_members: u32) -> Self { + Self { proposals, voting_members, ally_members } + } +} + +impl ForceSetWitness { + pub(super) fn is_zero(self) -> bool { + self == Self::default() + } +} diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 048bea3d1e5a4..8436b3ddbd530 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_alliance //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-08-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-09-01, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -53,7 +53,7 @@ pub trait WeightInfo { fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight; fn close_disapproved(x: u32, y: u32, p: u32, ) -> Weight; fn close_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight; - fn init_members(x: u32, y: u32, z: u32, ) -> Weight; + fn force_set_members(x: u32, y: u32, z: u32, p: u32, c: u32, m: u32, ) -> Weight; fn set_rule() -> Weight; fn announce() -> Weight; fn remove_announcement() -> Weight; @@ -79,16 +79,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[0, 90]`. /// The range of component `p` is `[1, 100]`. - fn propose_proposed(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(22_575_000 as RefTimeWeight) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(11_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) - // Standard Error: 23_000 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + fn propose_proposed(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { + Weight::from_ref_time(37_864_000 as RefTimeWeight) + // Standard Error: 28_000 + .saturating_add(Weight::from_ref_time(69_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(90_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(216_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } @@ -96,12 +94,10 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Voting (r:1 w:1) /// The range of component `x` is `[3, 10]`. /// The range of component `y` is `[2, 90]`. - fn vote(x: u32, y: u32, ) -> Weight { - Weight::from_ref_time(45_486_000 as RefTimeWeight) - // Standard Error: 29_000 - .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + fn vote(_x: u32, y: u32, ) -> Weight { + Weight::from_ref_time(46_813_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(128_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(125_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -111,9 +107,9 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - Weight::from_ref_time(35_296_000 as RefTimeWeight) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(171_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + Weight::from_ref_time(35_316_000 as RefTimeWeight) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -126,13 +122,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(39_252_000 as RefTimeWeight) + Weight::from_ref_time(36_245_000 as RefTimeWeight) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(75_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(336_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(109_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(170_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(178_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -145,12 +141,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_early_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(50_357_000 as RefTimeWeight) + fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { + Weight::from_ref_time(48_088_000 as RefTimeWeight) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + // Standard Error: 16_000 + .saturating_add(Weight::from_ref_time(194_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(103_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(204_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -164,11 +164,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(41_258_000 as RefTimeWeight) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(111_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + Weight::from_ref_time(43_374_000 as RefTimeWeight) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(101_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(182_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -182,45 +182,65 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_approved(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(40_490_000 as RefTimeWeight) - // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(119_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + fn close_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + Weight::from_ref_time(42_798_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(195_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } - // Storage: Alliance Members (r:2 w:3) - // Storage: AllianceMotion Members (r:1 w:1) - /// The range of component `x` is `[2, 10]`. + // Storage: AllianceMotion Proposals (r:1 w:1) + // Storage: Alliance Members (r:3 w:3) + // Storage: Alliance DepositOf (r:200 w:199) + // Storage: System Account (r:199 w:199) + // Storage: AllianceMotion Voting (r:0 w:100) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + // Storage: AllianceMotion ProposalOf (r:0 w:100) + /// The range of component `x` is `[1, 10]`. /// The range of component `y` is `[0, 90]`. /// The range of component `z` is `[0, 100]`. - fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { - Weight::from_ref_time(35_186_000 as RefTimeWeight) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(127_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + /// The range of component `p` is `[0, 100]`. + /// The range of component `c` is `[0, 100]`. + /// The range of component `m` is `[0, 100]`. + fn force_set_members(x: u32, y: u32, z: u32, p: u32, c: u32, m: u32, ) -> Weight { + Weight::from_ref_time(0 as RefTimeWeight) + // Standard Error: 221_000 + .saturating_add(Weight::from_ref_time(1_294_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + // Standard Error: 23_000 + .saturating_add(Weight::from_ref_time(231_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + // Standard Error: 21_000 + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + // Standard Error: 21_000 + .saturating_add(Weight::from_ref_time(9_371_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + // Standard Error: 21_000 + .saturating_add(Weight::from_ref_time(11_673_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + // Standard Error: 21_000 + .saturating_add(Weight::from_ref_time(11_581_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - Weight::from_ref_time(18_189_000 as RefTimeWeight) + Weight::from_ref_time(18_721_000 as RefTimeWeight) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - Weight::from_ref_time(21_106_000 as RefTimeWeight) + Weight::from_ref_time(21_887_000 as RefTimeWeight) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - Weight::from_ref_time(22_208_000 as RefTimeWeight) + Weight::from_ref_time(23_052_000 as RefTimeWeight) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -229,14 +249,14 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - Weight::from_ref_time(53_771_000 as RefTimeWeight) + Weight::from_ref_time(54_504_000 as RefTimeWeight) .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - Weight::from_ref_time(41_912_000 as RefTimeWeight) + Weight::from_ref_time(42_601_000 as RefTimeWeight) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -245,7 +265,7 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - Weight::from_ref_time(36_811_000 as RefTimeWeight) + Weight::from_ref_time(37_704_000 as RefTimeWeight) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } @@ -255,7 +275,7 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - Weight::from_ref_time(41_079_000 as RefTimeWeight) + Weight::from_ref_time(40_859_000 as RefTimeWeight) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } @@ -264,7 +284,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - Weight::from_ref_time(42_703_000 as RefTimeWeight) + Weight::from_ref_time(43_447_000 as RefTimeWeight) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } @@ -275,7 +295,7 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - Weight::from_ref_time(61_370_000 as RefTimeWeight) + Weight::from_ref_time(61_718_000 as RefTimeWeight) .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } @@ -284,11 +304,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(359_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_385_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_376_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(119_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(112_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -298,10 +318,10 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[1, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) - // Standard Error: 153_000 - .saturating_add(Weight::from_ref_time(21_484_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) - // Standard Error: 59_000 - .saturating_add(Weight::from_ref_time(3_772_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + // Standard Error: 145_000 + .saturating_add(Weight::from_ref_time(20_932_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + // Standard Error: 56_000 + .saturating_add(Weight::from_ref_time(3_649_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -318,16 +338,14 @@ impl WeightInfo for () { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[0, 90]`. /// The range of component `p` is `[1, 100]`. - fn propose_proposed(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(22_575_000 as RefTimeWeight) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(11_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) - // Standard Error: 23_000 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + fn propose_proposed(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { + Weight::from_ref_time(37_864_000 as RefTimeWeight) + // Standard Error: 28_000 + .saturating_add(Weight::from_ref_time(69_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(90_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(216_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } @@ -335,12 +353,10 @@ impl WeightInfo for () { // Storage: AllianceMotion Voting (r:1 w:1) /// The range of component `x` is `[3, 10]`. /// The range of component `y` is `[2, 90]`. - fn vote(x: u32, y: u32, ) -> Weight { - Weight::from_ref_time(45_486_000 as RefTimeWeight) - // Standard Error: 29_000 - .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + fn vote(_x: u32, y: u32, ) -> Weight { + Weight::from_ref_time(46_813_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(128_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(125_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -350,9 +366,9 @@ impl WeightInfo for () { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - Weight::from_ref_time(35_296_000 as RefTimeWeight) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(171_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + Weight::from_ref_time(35_316_000 as RefTimeWeight) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -365,13 +381,13 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(39_252_000 as RefTimeWeight) + Weight::from_ref_time(36_245_000 as RefTimeWeight) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(75_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(336_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(109_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(170_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(178_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -384,12 +400,16 @@ impl WeightInfo for () { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_early_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(50_357_000 as RefTimeWeight) + fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { + Weight::from_ref_time(48_088_000 as RefTimeWeight) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + // Standard Error: 16_000 + .saturating_add(Weight::from_ref_time(194_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(103_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(204_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -403,11 +423,11 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(41_258_000 as RefTimeWeight) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(111_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + Weight::from_ref_time(43_374_000 as RefTimeWeight) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(101_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(182_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -421,45 +441,65 @@ impl WeightInfo for () { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_approved(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(40_490_000 as RefTimeWeight) - // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(119_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + fn close_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + Weight::from_ref_time(42_798_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(195_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } - // Storage: Alliance Members (r:2 w:3) - // Storage: AllianceMotion Members (r:1 w:1) - /// The range of component `x` is `[2, 10]`. + // Storage: AllianceMotion Proposals (r:1 w:1) + // Storage: Alliance Members (r:3 w:3) + // Storage: Alliance DepositOf (r:200 w:199) + // Storage: System Account (r:199 w:199) + // Storage: AllianceMotion Voting (r:0 w:100) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + // Storage: AllianceMotion ProposalOf (r:0 w:100) + /// The range of component `x` is `[1, 10]`. /// The range of component `y` is `[0, 90]`. /// The range of component `z` is `[0, 100]`. - fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { - Weight::from_ref_time(35_186_000 as RefTimeWeight) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(127_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + /// The range of component `p` is `[0, 100]`. + /// The range of component `c` is `[0, 100]`. + /// The range of component `m` is `[0, 100]`. + fn force_set_members(x: u32, y: u32, z: u32, p: u32, c: u32, m: u32, ) -> Weight { + Weight::from_ref_time(0 as RefTimeWeight) + // Standard Error: 221_000 + .saturating_add(Weight::from_ref_time(1_294_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + // Standard Error: 23_000 + .saturating_add(Weight::from_ref_time(231_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + // Standard Error: 21_000 + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + // Standard Error: 21_000 + .saturating_add(Weight::from_ref_time(9_371_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + // Standard Error: 21_000 + .saturating_add(Weight::from_ref_time(11_673_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + // Standard Error: 21_000 + .saturating_add(Weight::from_ref_time(11_581_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - Weight::from_ref_time(18_189_000 as RefTimeWeight) + Weight::from_ref_time(18_721_000 as RefTimeWeight) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - Weight::from_ref_time(21_106_000 as RefTimeWeight) + Weight::from_ref_time(21_887_000 as RefTimeWeight) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - Weight::from_ref_time(22_208_000 as RefTimeWeight) + Weight::from_ref_time(23_052_000 as RefTimeWeight) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -468,14 +508,14 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - Weight::from_ref_time(53_771_000 as RefTimeWeight) + Weight::from_ref_time(54_504_000 as RefTimeWeight) .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - Weight::from_ref_time(41_912_000 as RefTimeWeight) + Weight::from_ref_time(42_601_000 as RefTimeWeight) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -484,7 +524,7 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - Weight::from_ref_time(36_811_000 as RefTimeWeight) + Weight::from_ref_time(37_704_000 as RefTimeWeight) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } @@ -494,7 +534,7 @@ impl WeightInfo for () { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - Weight::from_ref_time(41_079_000 as RefTimeWeight) + Weight::from_ref_time(40_859_000 as RefTimeWeight) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } @@ -503,7 +543,7 @@ impl WeightInfo for () { // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - Weight::from_ref_time(42_703_000 as RefTimeWeight) + Weight::from_ref_time(43_447_000 as RefTimeWeight) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } @@ -514,7 +554,7 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - Weight::from_ref_time(61_370_000 as RefTimeWeight) + Weight::from_ref_time(61_718_000 as RefTimeWeight) .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } @@ -523,11 +563,11 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(359_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_385_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_376_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(119_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(112_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -537,10 +577,10 @@ impl WeightInfo for () { /// The range of component `l` is `[1, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) - // Standard Error: 153_000 - .saturating_add(Weight::from_ref_time(21_484_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) - // Standard Error: 59_000 - .saturating_add(Weight::from_ref_time(3_772_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + // Standard Error: 145_000 + .saturating_add(Weight::from_ref_time(20_932_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + // Standard Error: 56_000 + .saturating_add(Weight::from_ref_time(3_649_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } From 324a18e3c5cbf333672c54f9367f530ea976928d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 1 Sep 2022 11:33:22 +0100 Subject: [PATCH 1109/1472] Runtime State Test + Integration with `try-runtime` (#10174) * add missing version to dependencies * Huh * add features more * more fixing * last touches * it all finally works * remove some feature gates * remove unused * fix old macro * make it work again * fmt * remove unused import * ".git/.scripts/fmt.sh" 1 * Cleanup more * fix and rename everything * a few clippy fixes * Add try-runtime feature Signed-off-by: Oliver Tale-Yazdi * small fixes * fmt * Update bin/node-template/runtime/src/lib.rs * fix build * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: David * Update utils/frame/try-runtime/cli/src/commands/execute_block.rs Co-authored-by: David * address all review comments * fix typos * revert spec change * last touches * update docs * fmt * remove some debug_assertions * fmt Signed-off-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi Co-authored-by: David --- Cargo.lock | 3 + bin/node-template/runtime/Cargo.toml | 4 +- bin/node-template/runtime/src/lib.rs | 10 +- bin/node/runtime/Cargo.toml | 20 +- bin/node/runtime/src/lib.rs | 17 +- frame/bags-list/fuzzer/src/main.rs | 2 +- frame/bags-list/remote-tests/src/lib.rs | 2 +- .../src/{sanity_check.rs => try_state.rs} | 2 +- frame/bags-list/src/lib.rs | 15 +- frame/bags-list/src/list/mod.rs | 43 ++--- frame/bags-list/src/list/tests.rs | 26 +-- frame/bags-list/src/mock.rs | 2 +- frame/beefy-mmr/Cargo.toml | 1 + frame/beefy/Cargo.toml | 1 + frame/election-provider-support/src/lib.rs | 4 +- frame/executive/Cargo.toml | 3 +- frame/executive/src/lib.rs | 77 ++++++-- frame/nomination-pools/Cargo.toml | 2 +- .../nomination-pools/benchmarking/src/lib.rs | 4 +- frame/nomination-pools/src/lib.rs | 16 +- frame/nomination-pools/src/mock.rs | 2 +- frame/remark/Cargo.toml | 1 + frame/staking/src/migrations.rs | 4 +- frame/staking/src/pallet/impls.rs | 107 ++++++++++- frame/staking/src/pallet/mod.rs | 6 +- .../procedural/src/pallet/expand/hooks.rs | 32 +++- frame/support/src/dispatch.rs | 36 ++++ frame/support/src/traits.rs | 7 +- frame/support/src/traits/hooks.rs | 55 ++---- frame/support/src/traits/try_runtime.rs | 174 ++++++++++++++++++ frame/system/src/lib.rs | 5 +- frame/transaction-storage/Cargo.toml | 1 + frame/try-runtime/Cargo.toml | 4 +- frame/try-runtime/src/lib.rs | 3 +- utils/frame/remote-externalities/src/lib.rs | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 1 + .../cli/src/commands/execute_block.rs | 43 ++++- .../cli/src/commands/follow_chain.rs | 22 ++- utils/frame/try-runtime/cli/src/lib.rs | 41 +++-- 39 files changed, 621 insertions(+), 179 deletions(-) rename frame/bags-list/remote-tests/src/{sanity_check.rs => try_state.rs} (96%) create mode 100644 frame/support/src/traits/try_runtime.rs diff --git a/Cargo.lock b/Cargo.lock index b0d0206a35300..ae225184c5b28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2228,6 +2228,7 @@ version = "4.0.0-dev" dependencies = [ "frame-support", "frame-system", + "frame-try-runtime", "hex-literal", "pallet-balances", "pallet-transaction-payment", @@ -2414,6 +2415,7 @@ name = "frame-try-runtime" version = "0.10.0-dev" dependencies = [ "frame-support", + "parity-scale-codec", "sp-api", "sp-runtime", "sp-std", @@ -11103,6 +11105,7 @@ name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ "clap 3.1.18", + "frame-try-runtime", "jsonrpsee", "log", "parity-scale-codec", diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 734ed089aa4bd..bbe3e8eef7d3c 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -63,6 +63,7 @@ std = [ "frame-support/std", "frame-system-rpc-runtime-api/std", "frame-system/std", + "frame-try-runtime/std", "pallet-aura/std", "pallet-balances/std", "pallet-grandpa/std", @@ -97,9 +98,10 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", ] try-runtime = [ - "frame-executive/try-runtime", "frame-try-runtime", + "frame-executive/try-runtime", "frame-system/try-runtime", + "frame-support/try-runtime", "pallet-aura/try-runtime", "pallet-balances/try-runtime", "pallet-grandpa/try-runtime", diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index b43fbde52dcdc..7280336cada3d 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -545,8 +545,14 @@ impl_runtime_apis! { (weight, BlockWeights::get().max_block) } - fn execute_block_no_check(block: Block) -> Weight { - Executive::execute_block_no_check(block) + fn execute_block( + block: Block, + state_root_check: bool, + select: frame_try_runtime::TryStateSelect + ) -> Weight { + // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to + // have a backtrace here. + Executive::try_execute_block(block, state_root_check, select).expect("execute-block failed") } } } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 10b15b6ec554d..ebec9b8b755f6 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -245,14 +245,16 @@ runtime-benchmarks = [ "hex-literal", ] try-runtime = [ - "frame-executive/try-runtime", "frame-try-runtime", + "frame-executive/try-runtime", "frame-system/try-runtime", + "frame-support/try-runtime", "pallet-alliance/try-runtime", "pallet-assets/try-runtime", "pallet-authority-discovery/try-runtime", "pallet-authorship/try-runtime", "pallet-babe/try-runtime", + "pallet-bags-list/try-runtime", "pallet-balances/try-runtime", "pallet-bounties/try-runtime", "pallet-child-bounties/try-runtime", @@ -264,32 +266,36 @@ try-runtime = [ "pallet-elections-phragmen/try-runtime", "pallet-gilt/try-runtime", "pallet-grandpa/try-runtime", - "pallet-identity/try-runtime", "pallet-im-online/try-runtime", "pallet-indices/try-runtime", + "pallet-identity/try-runtime", "pallet-lottery/try-runtime", "pallet-membership/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", + "pallet-nomination-pools/try-runtime", "pallet-offences/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", - "pallet-ranked-collective/try-runtime", "pallet-randomness-collective-flip/try-runtime", + "pallet-ranked-collective/try-runtime", "pallet-recovery/try-runtime", "pallet-referenda/try-runtime", - "pallet-scheduler/try-runtime", + "pallet-remark/try-runtime", "pallet-session/try-runtime", - "pallet-society/try-runtime", "pallet-staking/try-runtime", "pallet-state-trie-migration/try-runtime", + "pallet-scheduler/try-runtime", + "pallet-society/try-runtime", "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", "pallet-tips/try-runtime", - "pallet-transaction-payment/try-runtime", "pallet-treasury/try-runtime", - "pallet-uniques/try-runtime", "pallet-utility/try-runtime", + "pallet-transaction-payment/try-runtime", + "pallet-asset-tx-payment/try-runtime", + "pallet-transaction-storage/try-runtime", + "pallet-uniques/try-runtime", "pallet-vesting/try-runtime", "pallet-whitelist/try-runtime", ] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 5d4a21cea09b2..8ef7e7852ad02 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2079,8 +2079,21 @@ impl_runtime_apis! { (weight, RuntimeBlockWeights::get().max_block) } - fn execute_block_no_check(block: Block) -> Weight { - Executive::execute_block_no_check(block) + fn execute_block( + block: Block, + state_root_check: bool, + select: frame_try_runtime::TryStateSelect + ) -> Weight { + log::info!( + target: "node-runtime", + "try-runtime: executing block {:?} / root checks: {:?} / try-state-select: {:?}", + block.header.hash(), + state_root_check, + select, + ); + // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to + // have a backtrace here. + Executive::try_execute_block(block, state_root_check, select).unwrap() } } diff --git a/frame/bags-list/fuzzer/src/main.rs b/frame/bags-list/fuzzer/src/main.rs index c17fbe0a2f77f..9f7ca464cc2b8 100644 --- a/frame/bags-list/fuzzer/src/main.rs +++ b/frame/bags-list/fuzzer/src/main.rs @@ -88,7 +88,7 @@ fn main() { }, } - assert!(BagsList::sanity_check().is_ok()); + assert!(BagsList::try_state().is_ok()); }) }); } diff --git a/frame/bags-list/remote-tests/src/lib.rs b/frame/bags-list/remote-tests/src/lib.rs index 458064cf79f57..927c3dc91cb58 100644 --- a/frame/bags-list/remote-tests/src/lib.rs +++ b/frame/bags-list/remote-tests/src/lib.rs @@ -24,8 +24,8 @@ use sp_std::prelude::*; pub const LOG_TARGET: &str = "runtime::bags-list::remote-tests"; pub mod migration; -pub mod sanity_check; pub mod snapshot; +pub mod try_state; /// A wrapper for a runtime that the functions of this crate expect. /// diff --git a/frame/bags-list/remote-tests/src/sanity_check.rs b/frame/bags-list/remote-tests/src/try_state.rs similarity index 96% rename from frame/bags-list/remote-tests/src/sanity_check.rs rename to frame/bags-list/remote-tests/src/try_state.rs index 1027efb8539ee..11278c20eb8ed 100644 --- a/frame/bags-list/remote-tests/src/sanity_check.rs +++ b/frame/bags-list/remote-tests/src/try_state.rs @@ -44,7 +44,7 @@ pub async fn execute ext.execute_with(|| { sp_core::crypto::set_default_ss58_version(Runtime::SS58Prefix::get().try_into().unwrap()); - pallet_bags_list::Pallet::::sanity_check().unwrap(); + pallet_bags_list::Pallet::::try_state().unwrap(); log::info!(target: crate::LOG_TARGET, "executed bags-list sanity check with no errors."); crate::display_and_check_bags::(currency_unit, currency_name); diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 5163a579c6f43..70f8b2a32f817 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -263,6 +263,11 @@ pub mod pallet { "thresholds must strictly increase, and have no duplicates", ); } + + #[cfg(feature = "try-runtime")] + fn try_state(_: BlockNumberFor) -> Result<(), &'static str> { + >::try_state() + } } } @@ -340,14 +345,8 @@ impl, I: 'static> SortedListProvider for Pallet List::::unsafe_regenerate(all, score_of) } - #[cfg(feature = "std")] - fn sanity_check() -> Result<(), &'static str> { - List::::sanity_check() - } - - #[cfg(not(feature = "std"))] - fn sanity_check() -> Result<(), &'static str> { - Ok(()) + fn try_state() -> Result<(), &'static str> { + List::::try_state() } fn unsafe_clear() { diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index b4f852685842d..cfa7daf198937 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -28,8 +28,8 @@ use crate::Config; use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::ScoreProvider; use frame_support::{ - ensure, - traits::{Defensive, Get}, + defensive, ensure, + traits::{Defensive, DefensiveOption, Get}, DefaultNoBound, PalletError, }; use scale_info::TypeInfo; @@ -220,7 +220,8 @@ impl, I: 'static> List { crate::ListBags::::remove(removed_bag); } - debug_assert_eq!(Self::sanity_check(), Ok(())); + #[cfg(feature = "std")] + debug_assert_eq!(Self::try_state(), Ok(())); num_affected } @@ -325,8 +326,7 @@ impl, I: 'static> List { crate::log!( debug, - "inserted {:?} with score {:? - } into bag {:?}, new count is {}", + "inserted {:?} with score {:?} into bag {:?}, new count is {}", id, score, bag_score, @@ -457,11 +457,8 @@ impl, I: 'static> List { // re-fetch `lighter_node` from storage since it may have been updated when `heavier_node` // was removed. - let lighter_node = Node::::get(lighter_id).ok_or_else(|| { - debug_assert!(false, "id that should exist cannot be found"); - crate::log!(warn, "id that should exist cannot be found"); - ListError::NodeNotFound - })?; + let lighter_node = + Node::::get(lighter_id).defensive_ok_or_else(|| ListError::NodeNotFound)?; // insert `heavier_node` directly in front of `lighter_node`. This will update both nodes // in storage and update the node counter. @@ -508,7 +505,7 @@ impl, I: 'static> List { node.put(); } - /// Sanity check the list. + /// Check the internal state of the list. /// /// This should be called from the call-site, whenever one of the mutating apis (e.g. `insert`) /// is being used, after all other staking data (such as counter) has been updated. It checks: @@ -517,8 +514,7 @@ impl, I: 'static> List { /// * length of this list is in sync with `ListNodes::count()`, /// * and sanity-checks all bags and nodes. This will cascade down all the checks and makes sure /// all bags and nodes are checked per *any* update to `List`. - #[cfg(feature = "std")] - pub(crate) fn sanity_check() -> Result<(), &'static str> { + pub(crate) fn try_state() -> Result<(), &'static str> { let mut seen_in_list = BTreeSet::new(); ensure!( Self::iter().map(|node| node.id).all(|id| seen_in_list.insert(id)), @@ -546,7 +542,7 @@ impl, I: 'static> List { thresholds.into_iter().filter_map(|t| Bag::::get(t)) }; - let _ = active_bags.clone().try_for_each(|b| b.sanity_check())?; + let _ = active_bags.clone().try_for_each(|b| b.try_state())?; let nodes_in_bags_count = active_bags.clone().fold(0u32, |acc, cur| acc + cur.iter().count() as u32); @@ -557,17 +553,12 @@ impl, I: 'static> List { // check that all nodes are sane. We check the `ListNodes` storage item directly in case we // have some "stale" nodes that are not in a bag. for (_id, node) in crate::ListNodes::::iter() { - node.sanity_check()? + node.try_state()? } Ok(()) } - #[cfg(not(feature = "std"))] - pub(crate) fn sanity_check() -> Result<(), &'static str> { - Ok(()) - } - /// Returns the nodes of all non-empty bags. For testing and benchmarks. #[cfg(any(feature = "std", feature = "runtime-benchmarks"))] #[allow(dead_code)] @@ -701,8 +692,7 @@ impl, I: 'static> Bag { if *tail == node.id { // this should never happen, but this check prevents one path to a worst case // infinite loop. - debug_assert!(false, "system logic error: inserting a node who has the id of tail"); - crate::log!(warn, "system logic error: inserting a node who has the id of tail"); + defensive!("system logic error: inserting a node who has the id of tail"); return }; } @@ -753,7 +743,7 @@ impl, I: 'static> Bag { } } - /// Sanity check this bag. + /// Check the internal state of the bag. /// /// Should be called by the call-site, after any mutating operation on a bag. The call site of /// this struct is always `List`. @@ -761,8 +751,7 @@ impl, I: 'static> Bag { /// * Ensures head has no prev. /// * Ensures tail has no next. /// * Ensures there are no loops, traversal from head to tail is correct. - #[cfg(feature = "std")] - fn sanity_check(&self) -> Result<(), &'static str> { + fn try_state(&self) -> Result<(), &'static str> { frame_support::ensure!( self.head() .map(|head| head.prev().is_none()) @@ -801,7 +790,6 @@ impl, I: 'static> Bag { } /// Check if the bag contains a node with `id`. - #[cfg(feature = "std")] fn contains(&self, id: &T::AccountId) -> bool { self.iter().any(|n| n.id() == id) } @@ -906,8 +894,7 @@ impl, I: 'static> Node { self.bag_upper } - #[cfg(feature = "std")] - fn sanity_check(&self) -> Result<(), &'static str> { + fn try_state(&self) -> Result<(), &'static str> { let expected_bag = Bag::::get(self.bag_upper).ok_or("bag not found for node")?; let id = self.id(); diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index 9bdd54289fd88..966ea1a74c71c 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -350,15 +350,15 @@ mod list { } #[test] - fn sanity_check_works() { + fn try_state_works() { ExtBuilder::default().build_and_execute_no_post_check(|| { - assert_ok!(List::::sanity_check()); + assert_ok!(List::::try_state()); }); // make sure there are no duplicates. ExtBuilder::default().build_and_execute_no_post_check(|| { Bag::::get(10).unwrap().insert_unchecked(2, 10); - assert_eq!(List::::sanity_check(), Err("duplicate identified")); + assert_eq!(List::::try_state(), Err("duplicate identified")); }); // ensure count is in sync with `ListNodes::count()`. @@ -372,7 +372,7 @@ mod list { CounterForListNodes::::mutate(|counter| *counter += 1); assert_eq!(crate::ListNodes::::count(), 5); - assert_eq!(List::::sanity_check(), Err("iter_count != stored_count")); + assert_eq!(List::::try_state(), Err("iter_count != stored_count")); }); } @@ -804,7 +804,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![2, 3, 13, 14]); - assert_ok!(bag_1000.sanity_check()); + assert_ok!(bag_1000.try_state()); // and the node isn't mutated when its removed assert_eq!(node_4, node_4_pre_remove); @@ -814,7 +814,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![3, 13, 14]); - assert_ok!(bag_1000.sanity_check()); + assert_ok!(bag_1000.try_state()); // when removing a tail that is not pointing at the head let node_14 = Node::::get(&14).unwrap(); @@ -822,7 +822,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![3, 13]); - assert_ok!(bag_1000.sanity_check()); + assert_ok!(bag_1000.try_state()); // when removing a tail that is pointing at the head let node_13 = Node::::get(&13).unwrap(); @@ -830,7 +830,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![3]); - assert_ok!(bag_1000.sanity_check()); + assert_ok!(bag_1000.try_state()); // when removing a node that is both the head & tail let node_3 = Node::::get(&3).unwrap(); @@ -846,7 +846,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_10), vec![1, 12]); - assert_ok!(bag_10.sanity_check()); + assert_ok!(bag_10.try_state()); // when removing a head that is pointing at the tail let node_1 = Node::::get(&1).unwrap(); @@ -854,7 +854,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_10), vec![12]); - assert_ok!(bag_10.sanity_check()); + assert_ok!(bag_10.try_state()); // and since we updated the bag's head/tail, we need to write this storage so we // can correctly `get` it again in later checks bag_10.put(); @@ -865,7 +865,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_2000), vec![15, 17, 18, 19]); - assert_ok!(bag_2000.sanity_check()); + assert_ok!(bag_2000.try_state()); // when removing a node that is pointing at tail, but not head let node_18 = Node::::get(&18).unwrap(); @@ -873,7 +873,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_2000), vec![15, 17, 19]); - assert_ok!(bag_2000.sanity_check()); + assert_ok!(bag_2000.try_state()); // finally, when reading from storage, the state of all bags is as expected assert_eq!( @@ -905,7 +905,7 @@ mod bags { // .. and the bag it was removed from let bag_1000 = Bag::::get(1_000).unwrap(); // is sane - assert_ok!(bag_1000.sanity_check()); + assert_ok!(bag_1000.try_state()); // and has the correct head and tail. assert_eq!(bag_1000.head, Some(3)); assert_eq!(bag_1000.tail, Some(4)); diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 961bf2b83552f..3bc1b34657262 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -147,7 +147,7 @@ impl ExtBuilder { pub fn build_and_execute(self, test: impl FnOnce() -> ()) { self.build().execute_with(|| { test(); - List::::sanity_check().expect("Sanity check post condition failed") + List::::try_state().expect("Try-state post condition failed") }) } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 8da182f1c29fc..e8366943c85b0 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -50,3 +50,4 @@ std = [ "sp-runtime/std", "sp-std/std", ] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index eecce963d19f0..84aa8c7757c45 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -37,3 +37,4 @@ std = [ "sp-runtime/std", "sp-std/std", ] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index eee865d0b737b..21a01ce1904ec 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -513,8 +513,8 @@ pub trait SortedListProvider { /// unbounded amount of storage accesses. fn unsafe_clear(); - /// Sanity check internal state of list. Only meant for debug compilation. - fn sanity_check() -> Result<(), &'static str>; + /// Check internal state of list. Only meant for debugging. + fn try_state() -> Result<(), &'static str>; /// If `who` changes by the returned amount they are guaranteed to have a worst case change /// in their list position. diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index b67f3313e612b..1ae22ddbb0260 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -19,6 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +frame-try-runtime = { version = "0.10.0-dev", default-features = false, path = "../try-runtime", optional = true } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } @@ -48,4 +49,4 @@ std = [ "sp-std/std", "sp-tracing/std", ] -try-runtime = ["frame-support/try-runtime"] +try-runtime = ["frame-support/try-runtime", "frame-try-runtime" ] diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 45361084f2f42..d7cd1da7910a4 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -202,6 +202,7 @@ where } } +#[cfg(feature = "try-runtime")] impl< System: frame_system::Config + EnsureInherentsAreFirst, Block: traits::Block

, @@ -211,7 +212,8 @@ impl< + OnInitialize + OnIdle + OnFinalize - + OffchainWorker, + + OffchainWorker + + frame_support::traits::TryState, COnRuntimeUpgrade: OnRuntimeUpgrade, > Executive where @@ -222,16 +224,20 @@ where OriginOf: From>, UnsignedValidator: ValidateUnsigned>, { - /// Execute all `OnRuntimeUpgrade` of this runtime, and return the aggregate weight. - pub fn execute_on_runtime_upgrade() -> frame_support::weights::Weight { - <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::on_runtime_upgrade() - } - - /// Execute given block, but don't do any of the `final_checks`. + /// Execute given block, but don't as strict is the normal block execution. /// - /// Should only be used for testing. - #[cfg(feature = "try-runtime")] - pub fn execute_block_no_check(block: Block) -> frame_support::weights::Weight { + /// Some consensus related checks such as the state root check can be switched off via + /// `try_state_root`. Some additional non-consensus checks can be additionally enabled via + /// `try_state`. + /// + /// Should only be used for testing ONLY. + pub fn try_execute_block( + block: Block, + try_state_root: bool, + select: frame_try_runtime::TryStateSelect, + ) -> Result { + use frame_support::traits::TryState; + Self::initialize_block(block.header()); Self::initial_checks(&block); @@ -239,7 +245,17 @@ where Self::execute_extrinsics_with_book_keeping(extrinsics, *header.number()); - // do some of the checks that would normally happen in `final_checks`, but definitely skip + // run the try-state checks of all pallets. + >::try_state( + *header.number(), + select, + ) + .map_err(|e| { + frame_support::log::error!(target: "runtime::executive", "failure: {:?}", e); + e + })?; + + // do some of the checks that would normally happen in `final_checks`, but perhaps skip // the state root check. { let new_header = >::finalize(); @@ -249,27 +265,60 @@ where assert!(header_item == computed_item, "Digest item must match that calculated."); } + if try_state_root { + let storage_root = new_header.state_root(); + header.state_root().check_equal(storage_root); + assert!( + header.state_root() == storage_root, + "Storage root must match that calculated." + ); + } + assert!( header.extrinsics_root() == new_header.extrinsics_root(), "Transaction trie root must be valid.", ); } - frame_system::Pallet::::block_weight().total() + Ok(frame_system::Pallet::::block_weight().total()) } /// Execute all `OnRuntimeUpgrade` of this runtime, including the pre and post migration checks. /// /// This should only be used for testing. - #[cfg(feature = "try-runtime")] pub fn try_runtime_upgrade() -> Result { <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::pre_upgrade().unwrap(); let weight = Self::execute_on_runtime_upgrade(); - <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::post_upgrade().unwrap(); Ok(weight) } +} + +impl< + System: frame_system::Config + EnsureInherentsAreFirst, + Block: traits::Block
, + Context: Default, + UnsignedValidator, + AllPalletsWithSystem: OnRuntimeUpgrade + + OnInitialize + + OnIdle + + OnFinalize + + OffchainWorker, + COnRuntimeUpgrade: OnRuntimeUpgrade, + > Executive +where + Block::Extrinsic: Checkable + Codec, + CheckedOf: Applyable + GetDispatchInfo, + CallOf: + Dispatchable, + OriginOf: From>, + UnsignedValidator: ValidateUnsigned>, +{ + /// Execute all `OnRuntimeUpgrade` of this runtime, and return the aggregate weight. + pub fn execute_on_runtime_upgrade() -> frame_support::weights::Weight { + <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::on_runtime_upgrade() + } /// Start the execution of a particular block. pub fn initialize_block(header: &System::Header) { diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index be5c38d85552c..1d613511eacec 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -32,7 +32,7 @@ sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } [features] runtime-benchmarks = [] -try-runtime = [] +try-runtime = [ "frame-support/try-runtime" ] default = ["std"] std = [ "codec/std", diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index f4ecb4a9b0ff1..07d5c63493ef8 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -201,11 +201,11 @@ impl ListScenario { Pools::::join(Origin::Signed(joiner.clone()).into(), amount, 1).unwrap(); - // Sanity check that the vote weight is still the same as the original bonded + // check that the vote weight is still the same as the original bonded let weight_of = pallet_staking::Pallet::::weight_of_fn(); assert_eq!(vote_to_balance::(weight_of(&self.origin1)).unwrap(), original_bonded); - // Sanity check the member was added correctly + // check the member was added correctly let member = PoolMembers::::get(&joiner).unwrap(); assert_eq!(member.points, amount); assert_eq!(member.pool_id, 1); diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 40db4ac64851a..3809a70440d27 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1110,7 +1110,7 @@ impl SubPools { } /// The sum of all unbonding balance, regardless of whether they are actually unlocked or not. - #[cfg(any(test, debug_assertions))] + #[cfg(any(feature = "try-runtime", test, debug_assertions))] fn sum_unbonding_balance(&self) -> BalanceOf { self.no_era.balance.saturating_add( self.with_era @@ -2138,6 +2138,11 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), &'static str> { + Self::do_try_state(u8::MAX) + } + fn integrity_test() { assert!( T::MaxPointsToBalance::get() > 0, @@ -2389,9 +2394,9 @@ impl Pallet { /// /// To cater for tests that want to escape parts of these checks, this function is split into /// multiple `level`s, where the higher the level, the more checks we performs. So, - /// `sanity_check(255)` is the strongest sanity check, and `0` performs no checks. - #[cfg(any(test, debug_assertions))] - pub fn sanity_checks(level: u8) -> Result<(), &'static str> { + /// `try_state(255)` is the strongest sanity check, and `0` performs no checks. + #[cfg(any(feature = "try-runtime", test, debug_assertions))] + pub fn do_try_state(level: u8) -> Result<(), &'static str> { if level.is_zero() { return Ok(()) } @@ -2401,7 +2406,8 @@ impl Pallet { let reward_pools = RewardPools::::iter_keys().collect::>(); assert_eq!(bonded_pools, reward_pools); - assert!(Metadata::::iter_keys().all(|k| bonded_pools.contains(&k))); + // TODO: can't check this right now: https://github.com/paritytech/substrate/issues/12077 + // assert!(Metadata::::iter_keys().all(|k| bonded_pools.contains(&k))); assert!(SubPoolsStorage::::iter_keys().all(|k| bonded_pools.contains(&k))); assert!(MaxPools::::get().map_or(true, |max| bonded_pools.len() <= (max as usize))); diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 5138c55afccac..3bb260e56f180 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -304,7 +304,7 @@ impl ExtBuilder { pub fn build_and_execute(self, test: impl FnOnce() -> ()) { self.build().execute_with(|| { test(); - Pools::sanity_checks(CheckLevel::get()).unwrap(); + Pools::do_try_state(CheckLevel::get()).unwrap(); }) } } diff --git a/frame/remark/Cargo.toml b/frame/remark/Cargo.toml index 71a65ce554975..fe20365b7c904 100644 --- a/frame/remark/Cargo.toml +++ b/frame/remark/Cargo.toml @@ -41,3 +41,4 @@ std = [ "sp-runtime/std", "sp-std/std", ] +try-runtime = [ "frame-support/try-runtime" ] diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 7e3bf6ccb93e1..ff01e1fe3b09b 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -153,7 +153,7 @@ pub mod v8 { Nominators::::iter().map(|(id, _)| id), Pallet::::weight_of_fn(), ); - debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); + debug_assert_eq!(T::VoterList::try_state(), Ok(())); StorageVersion::::put(crate::Releases::V8_0_0); crate::log!( @@ -170,7 +170,7 @@ pub mod v8 { #[cfg(feature = "try-runtime")] pub fn post_migrate() -> Result<(), &'static str> { - T::VoterList::sanity_check().map_err(|_| "VoterList is not in a sane state.")?; + T::VoterList::try_state().map_err(|_| "VoterList is not in a sane state.")?; crate::log!(info, "👜 staking bags-list migration passes POST migrate checks ✅",); Ok(()) } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 2a55d3baea2e6..386c413132f6c 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -789,7 +789,6 @@ impl Pallet { Nominators::::count() + Validators::::count(), T::VoterList::count() ); - debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); } /// This function will remove a nominator from the `Nominators` storage map, @@ -809,7 +808,6 @@ impl Pallet { false }; - debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); debug_assert_eq!( Nominators::::count() + Validators::::count(), T::VoterList::count() @@ -837,7 +835,6 @@ impl Pallet { Nominators::::count() + Validators::::count(), T::VoterList::count() ); - debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); } /// This function will remove a validator from the `Validators` storage map. @@ -856,7 +853,6 @@ impl Pallet { false }; - debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); debug_assert_eq!( Nominators::::count() + Validators::::count(), T::VoterList::count() @@ -1369,7 +1365,7 @@ impl SortedListProvider for UseNominatorsAndValidatorsM // nothing to do upon regenerate. 0 } - fn sanity_check() -> Result<(), &'static str> { + fn try_state() -> Result<(), &'static str> { Ok(()) } @@ -1452,3 +1448,104 @@ impl StakingInterface for Pallet { Nominators::::get(who).map(|n| n.targets.into_inner()) } } + +#[cfg(feature = "try-runtime")] +impl Pallet { + pub(crate) fn do_try_state(_: BlockNumberFor) -> Result<(), &'static str> { + T::VoterList::try_state()?; + Self::check_nominators()?; + Self::check_exposures()?; + Self::check_ledgers()?; + Self::check_count() + } + + fn check_count() -> Result<(), &'static str> { + ensure!( + ::VoterList::count() == + Nominators::::count() + Validators::::count(), + "wrong external count" + ); + Ok(()) + } + + fn check_ledgers() -> Result<(), &'static str> { + Bonded::::iter() + .map(|(_, ctrl)| Self::ensure_ledger_consistent(ctrl)) + .collect::>() + } + + fn check_exposures() -> Result<(), &'static str> { + // a check per validator to ensure the exposure struct is always sane. + let era = Self::active_era().unwrap().index; + ErasStakers::::iter_prefix_values(era) + .map(|expo| { + ensure!( + expo.total == + expo.own + + expo.others + .iter() + .map(|e| e.value) + .fold(Zero::zero(), |acc, x| acc + x), + "wrong total exposure.", + ); + Ok(()) + }) + .collect::>() + } + + fn check_nominators() -> Result<(), &'static str> { + // a check per nominator to ensure their entire stake is correctly distributed. Will only + // kick-in if the nomination was submitted before the current era. + let era = Self::active_era().unwrap().index; + >::iter() + .filter_map( + |(nominator, nomination)| { + if nomination.submitted_in > era { + Some(nominator) + } else { + None + } + }, + ) + .map(|nominator| { + // must be bonded. + Self::ensure_is_stash(&nominator)?; + let mut sum = BalanceOf::::zero(); + T::SessionInterface::validators() + .iter() + .map(|v| Self::eras_stakers(era, v)) + .map(|e| { + let individual = + e.others.iter().filter(|e| e.who == nominator).collect::>(); + let len = individual.len(); + match len { + 0 => { /* not supporting this validator at all. */ }, + 1 => sum += individual[0].value, + _ => return Err("nominator cannot back a validator more than once."), + }; + Ok(()) + }) + .collect::>() + }) + .collect::>() + } + + fn ensure_is_stash(who: &T::AccountId) -> Result<(), &'static str> { + ensure!(Self::bonded(who).is_some(), "Not a stash."); + Ok(()) + } + + fn ensure_ledger_consistent(ctrl: T::AccountId) -> Result<(), &'static str> { + // ensures ledger.total == ledger.active + sum(ledger.unlocking). + let ledger = Self::ledger(ctrl.clone()).ok_or("Not a controller.")?; + let real_total: BalanceOf = + ledger.unlocking.iter().fold(ledger.active, |a, c| a + c.value); + ensure!(real_total == ledger.total, "ledger.total corrupt"); + + if !(ledger.active >= T::Currency::minimum_balance() || ledger.active.is_zero()) { + log!(warn, "ledger.active less than ED: {:?}, {:?}", ctrl, ledger) + } + + Ok(()) + } +} diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 1f11f0ff00ac1..74374cc586a23 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -744,6 +744,11 @@ pub mod pallet { ); } } + + #[cfg(feature = "try-runtime")] + fn try_state(n: BlockNumberFor) -> Result<(), &'static str> { + Self::do_try_state(n) + } } #[pallet::call] @@ -856,7 +861,6 @@ pub mod pallet { if T::VoterList::contains(&stash) { let _ = T::VoterList::on_update(&stash, Self::weight_of(&ledger.stash)).defensive(); - debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); } Self::deposit_event(Event::::Bonded(stash, extra)); diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index 7a1a94cf46d31..03878f3f186df 100644 --- a/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/frame/support/procedural/src/pallet/expand/hooks.rs @@ -17,7 +17,6 @@ use crate::pallet::Def; -/// /// * implement the individual traits using the Hooks trait pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { let (where_clause, span, has_runtime_upgrade) = match def.hooks.as_ref() { @@ -59,6 +58,19 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { } }; + let log_try_state = quote::quote! { + let pallet_name = < + ::PalletInfo + as + #frame_support::traits::PalletInfo + >::name::().expect("Every active pallet has a name in the runtime; qed"); + #frame_support::log::debug!( + target: #frame_support::LOG_TARGET, + "🩺 try-state pallet {:?}", + pallet_name, + ); + }; + let hooks_impl = if def.hooks.is_none() { let frame_system = &def.frame_system; quote::quote! { @@ -191,5 +203,23 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { >::integrity_test() } } + + #[cfg(feature = "try-runtime")] + impl<#type_impl_gen> + #frame_support::traits::TryState<::BlockNumber> + for #pallet_ident<#type_use_gen> #where_clause + { + fn try_state( + n: ::BlockNumber, + _s: #frame_support::traits::TryStateSelect + ) -> Result<(), &'static str> { + #log_try_state + < + Self as #frame_support::traits::Hooks< + ::BlockNumber + > + >::try_state(n) + } + } ) } diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 97312ac3476b5..94974888c1d5c 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -1549,6 +1549,35 @@ macro_rules! decl_module { {} }; + (@impl_try_state_default + { $system:ident } + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + { $( $other_where_bounds:tt )* } + ) => { + #[cfg(feature = "try-runtime")] + impl<$trait_instance: $system::Config + $trait_name$(, $instance: $instantiable)?> + $crate::traits::TryState<<$trait_instance as $system::Config>::BlockNumber> + for $module<$trait_instance$(, $instance)?> where $( $other_where_bounds )* + { + fn try_state( + _: <$trait_instance as $system::Config>::BlockNumber, + _: $crate::traits::TryStateSelect, + ) -> Result<(), &'static str> { + let pallet_name = << + $trait_instance + as + $system::Config + >::PalletInfo as $crate::traits::PalletInfo>::name::().unwrap_or(""); + $crate::log::debug!( + target: $crate::LOG_TARGET, + "⚠️ pallet {} cannot have try-state because it is using decl_module!", + pallet_name, + ); + Ok(()) + } + } + }; + (@impl_on_runtime_upgrade { $system:ident } $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; @@ -2026,6 +2055,13 @@ macro_rules! decl_module { $( $on_initialize )* } + $crate::decl_module! { + @impl_try_state_default + { $system } + $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; + { $( $other_where_bounds )* } + } + $crate::decl_module! { @impl_on_runtime_upgrade { $system } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 16504beb16907..d4f0e73557c77 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -84,8 +84,6 @@ pub use hooks::{ Hooks, IntegrityTest, OnFinalize, OnGenesis, OnIdle, OnInitialize, OnRuntimeUpgrade, OnTimestampSet, }; -#[cfg(feature = "try-runtime")] -pub use hooks::{OnRuntimeUpgradeHelpersExt, ON_RUNTIME_UPGRADE_PREFIX}; pub mod schedule; mod storage; @@ -106,3 +104,8 @@ pub use voting::{ ClassCountOf, CurrencyToVote, PollStatus, Polling, SaturatingCurrencyToVote, U128CurrencyToVote, VoteTally, }; + +#[cfg(feature = "try-runtime")] +mod try_runtime; +#[cfg(feature = "try-runtime")] +pub use try_runtime::{OnRuntimeUpgradeHelpersExt, Select as TryStateSelect, TryState}; diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index f8e91886edf0c..e8cd87823f3c3 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -20,6 +20,7 @@ use crate::weights::Weight; use impl_trait_for_tuples::impl_for_tuples; use sp_runtime::traits::AtLeast32BitUnsigned; +use sp_std::prelude::*; /// The block initialization trait. /// @@ -93,9 +94,9 @@ impl OnIdle for Tuple { let start_index = start_index.try_into().ok().expect( "`start_index % len` always fits into `usize`, because `len` can be in maximum `usize::MAX`; qed" ); - for on_idle in on_idle_functions.iter().cycle().skip(start_index).take(len) { + for on_idle_fn in on_idle_functions.iter().cycle().skip(start_index).take(len) { let adjusted_remaining_weight = remaining_weight.saturating_sub(weight); - weight = weight.saturating_add(on_idle(n, adjusted_remaining_weight)); + weight = weight.saturating_add(on_idle_fn(n, adjusted_remaining_weight)); } weight } @@ -114,47 +115,6 @@ pub trait OnGenesis { fn on_genesis() {} } -/// Prefix to be used (optionally) for implementing [`OnRuntimeUpgradeHelpersExt::storage_key`]. -#[cfg(feature = "try-runtime")] -pub const ON_RUNTIME_UPGRADE_PREFIX: &[u8] = b"__ON_RUNTIME_UPGRADE__"; - -/// Some helper functions for [`OnRuntimeUpgrade`] during `try-runtime` testing. -#[cfg(feature = "try-runtime")] -pub trait OnRuntimeUpgradeHelpersExt { - /// Generate a storage key unique to this runtime upgrade. - /// - /// This can be used to communicate data from pre-upgrade to post-upgrade state and check - /// them. See [`Self::set_temp_storage`] and [`Self::get_temp_storage`]. - #[cfg(feature = "try-runtime")] - fn storage_key(ident: &str) -> [u8; 32] { - crate::storage::storage_prefix(ON_RUNTIME_UPGRADE_PREFIX, ident.as_bytes()) - } - - /// Get temporary storage data written by [`Self::set_temp_storage`]. - /// - /// Returns `None` if either the data is unavailable or un-decodable. - /// - /// A `at` storage identifier must be provided to indicate where the storage is being read from. - #[cfg(feature = "try-runtime")] - fn get_temp_storage(at: &str) -> Option { - sp_io::storage::get(&Self::storage_key(at)) - .and_then(|bytes| codec::Decode::decode(&mut &*bytes).ok()) - } - - /// Write some temporary data to a specific storage that can be read (potentially in - /// post-upgrade hook) via [`Self::get_temp_storage`]. - /// - /// A `at` storage identifier must be provided to indicate where the storage is being written - /// to. - #[cfg(feature = "try-runtime")] - fn set_temp_storage(data: T, at: &str) { - sp_io::storage::set(&Self::storage_key(at), &data.encode()); - } -} - -#[cfg(feature = "try-runtime")] -impl OnRuntimeUpgradeHelpersExt for U {} - /// The runtime upgrade trait. /// /// Implementing this lets you express what should happen when the runtime upgrades, @@ -272,6 +232,15 @@ pub trait Hooks { Weight::new() } + /// Execute the sanity checks of this pallet, per block. + /// + /// It should focus on certain checks to ensure that the state is sensible. This is never + /// executed in a consensus code-path, therefore it can consume as much weight as it needs. + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumber) -> Result<(), &'static str> { + Ok(()) + } + /// Execute some pre-checks prior to a runtime upgrade. /// /// This hook is never meant to be executed on-chain but is meant to be used by testing tools. diff --git a/frame/support/src/traits/try_runtime.rs b/frame/support/src/traits/try_runtime.rs new file mode 100644 index 0000000000000..c5ddd1cae42be --- /dev/null +++ b/frame/support/src/traits/try_runtime.rs @@ -0,0 +1,174 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Try-runtime specific traits and types. + +use super::*; +use impl_trait_for_tuples::impl_for_tuples; +use sp_arithmetic::traits::AtLeast32BitUnsigned; +use sp_std::prelude::*; + +/// Prefix to be used (optionally) for implementing [`OnRuntimeUpgradeHelpersExt::storage_key`]. +const ON_RUNTIME_UPGRADE_PREFIX: &[u8] = b"__ON_RUNTIME_UPGRADE__"; + +/// Some helper functions for [`OnRuntimeUpgrade`] during `try-runtime` testing. +pub trait OnRuntimeUpgradeHelpersExt { + /// Generate a storage key unique to this runtime upgrade. + /// + /// This can be used to communicate data from pre-upgrade to post-upgrade state and check + /// them. See [`Self::set_temp_storage`] and [`Self::get_temp_storage`]. + fn storage_key(ident: &str) -> [u8; 32] { + crate::storage::storage_prefix(ON_RUNTIME_UPGRADE_PREFIX, ident.as_bytes()) + } + + /// Get temporary storage data written by [`Self::set_temp_storage`]. + /// + /// Returns `None` if either the data is unavailable or un-decodable. + /// + /// A `at` storage identifier must be provided to indicate where the storage is being read from. + fn get_temp_storage(at: &str) -> Option { + sp_io::storage::get(&Self::storage_key(at)) + .and_then(|bytes| codec::Decode::decode(&mut &*bytes).ok()) + } + + /// Write some temporary data to a specific storage that can be read (potentially in + /// post-upgrade hook) via [`Self::get_temp_storage`]. + /// + /// A `at` storage identifier must be provided to indicate where the storage is being written + /// to. + fn set_temp_storage(data: T, at: &str) { + sp_io::storage::set(&Self::storage_key(at), &data.encode()); + } +} + +impl OnRuntimeUpgradeHelpersExt for U {} + +// Which state tests to execute. +#[derive(codec::Encode, codec::Decode, Clone)] +pub enum Select { + /// None of them. + None, + /// All of them. + All, + /// Run a fixed number of them in a round robin manner. + RoundRobin(u32), + /// Run only pallets who's name matches the given list. + /// + /// Pallet names are obtained from [`PalletInfoAccess`]. + Only(Vec>), +} + +impl Default for Select { + fn default() -> Self { + Select::None + } +} + +impl sp_std::fmt::Debug for Select { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + match self { + Select::RoundRobin(x) => write!(f, "RoundRobin({})", x), + Select::Only(x) => write!( + f, + "Only({:?})", + x.iter() + .map(|x| sp_std::str::from_utf8(x).unwrap_or("")) + .collect::>(), + ), + Select::All => write!(f, "All"), + Select::None => write!(f, "None"), + } + } +} + +#[cfg(feature = "std")] +impl sp_std::str::FromStr for Select { + type Err = &'static str; + fn from_str(s: &str) -> Result { + match s { + "all" | "All" => Ok(Select::All), + "none" | "None" => Ok(Select::None), + _ => + if s.starts_with("rr-") { + let count = s + .split_once('-') + .and_then(|(_, count)| count.parse::().ok()) + .ok_or("failed to parse count")?; + Ok(Select::RoundRobin(count)) + } else { + let pallets = s.split(',').map(|x| x.as_bytes().to_vec()).collect::>(); + Ok(Select::Only(pallets)) + }, + } + } +} + +/// Execute some checks to ensure the internal state of a pallet is consistent. +/// +/// Usually, these checks should check all of the invariants that are expected to be held on all of +/// the storage items of your pallet. +pub trait TryState { + /// Execute the state checks. + fn try_state(_: BlockNumber, _: Select) -> Result<(), &'static str>; +} + +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(all(feature = "tuples-128"), impl_for_tuples(128))] +impl TryState + for Tuple +{ + for_tuples!( where #( Tuple: crate::traits::PalletInfoAccess )* ); + fn try_state(n: BlockNumber, targets: Select) -> Result<(), &'static str> { + match targets { + Select::None => Ok(()), + Select::All => { + let mut result = Ok(()); + for_tuples!( #( result = result.and(Tuple::try_state(n.clone(), targets.clone())); )* ); + result + }, + Select::RoundRobin(len) => { + let functions: &[fn(BlockNumber, Select) -> Result<(), &'static str>] = + &[for_tuples!(#( Tuple::try_state ),*)]; + let skip = n.clone() % (functions.len() as u32).into(); + let skip: u32 = + skip.try_into().unwrap_or_else(|_| sp_runtime::traits::Bounded::max_value()); + let mut result = Ok(()); + for try_state_fn in functions.iter().cycle().skip(skip as usize).take(len as usize) + { + result = result.and(try_state_fn(n.clone(), targets.clone())); + } + result + }, + Select::Only(ref pallet_names) => { + let try_state_fns: &[( + &'static str, + fn(BlockNumber, Select) -> Result<(), &'static str>, + )] = &[for_tuples!( + #( (::name(), Tuple::try_state) ),* + )]; + let mut result = Ok(()); + for (name, try_state_fn) in try_state_fns { + if pallet_names.iter().any(|n| n == name.as_bytes()) { + result = result.and(try_state_fn(n.clone(), targets.clone())); + } + } + result + }, + } + } +} diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index d9afa17eec959..ba076d963bda7 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1309,9 +1309,10 @@ impl Pallet { pub fn finalize() -> T::Header { log::debug!( target: "runtime::system", - "[{:?}] length: {} (normal {}%, op: {}%, mandatory {}%) / normal weight: {} ({}%) \ - / op weight {} ({}%) / mandatory weight {} ({}%)", + "[{:?}] {} extrinsics, length: {} (normal {}%, op: {}%, mandatory {}%) / normal weight:\ + {} ({}%) op weight {} ({}%) / mandatory weight {} ({}%)", Self::block_number(), + Self::extrinsic_index().unwrap_or_default(), Self::all_extrinsics_len(), sp_runtime::Percent::from_rational( Self::all_extrinsics_len(), diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index f001ef6acd468..8ed34cb50a652 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -48,3 +48,4 @@ std = [ "sp-std/std", "sp-transaction-storage-proof/std", ] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index 075de318c2a05..dd77c0438d71f 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -13,7 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"]} +frame-support = { version = "4.0.0-dev", default-features = false, features = [ "try-runtime" ], path = "../support" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -21,6 +22,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives [features] default = [ "std" ] std = [ + "codec/std", "frame-support/std", "sp-api/std", "sp-runtime/std", diff --git a/frame/try-runtime/src/lib.rs b/frame/try-runtime/src/lib.rs index e4f01d40c9d42..7fec92712cd19 100644 --- a/frame/try-runtime/src/lib.rs +++ b/frame/try-runtime/src/lib.rs @@ -19,6 +19,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +pub use frame_support::traits::TryStateSelect; use frame_support::weights::Weight; sp_api::decl_runtime_apis! { @@ -37,6 +38,6 @@ sp_api::decl_runtime_apis! { /// /// This is only sensible where the incoming block is from a different network, yet it has /// the same block format as the runtime implementing this API. - fn execute_block_no_check(block: Block) -> Weight; + fn execute_block(block: Block, state_root_check: bool, try_state: TryStateSelect) -> Weight; } } diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 202560f18cf84..83481e745f5ee 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -56,7 +56,7 @@ type ChildKeyValues = Vec<(ChildInfo, Vec)>; const LOG_TARGET: &str = "remote-ext"; const DEFAULT_TARGET: &str = "wss://rpc.polkadot.io:443"; const BATCH_SIZE: usize = 1000; -const PAGE: u32 = 512; +const PAGE: u32 = 1000; #[rpc(client)] pub trait RpcApi { diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 4b4f9bdb2809a..dd98854e84d75 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -31,3 +31,4 @@ sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../../primitives/state-machine" } sp-version = { version = "5.0.0", path = "../../../../primitives/version" } +frame-try-runtime = { path = "../../../../frame/try-runtime" } diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index aee3c34a1e0e8..6a3ef24ff3771 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -19,6 +19,7 @@ use crate::{ build_executor, ensure_matching_spec, extract_code, full_extensions, hash_of, local_spec, state_machine_call_with_proof, SharedParams, State, LOG_TARGET, }; +use parity_scale_codec::Encode; use remote_externalities::rpc_api; use sc_service::{Configuration, NativeExecutionDispatch}; use sp_core::storage::well_known_keys; @@ -26,17 +27,30 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use std::{fmt::Debug, str::FromStr}; /// Configurations of the [`Command::ExecuteBlock`]. +/// +/// This will always call into `TryRuntime_execute_block`, which can optionally skip the state-root +/// check (useful for trying a unreleased runtime), and can execute runtime sanity checks as well. #[derive(Debug, Clone, clap::Parser)] pub struct ExecuteBlockCmd { /// Overwrite the wasm code in state or not. #[clap(long)] overwrite_wasm_code: bool, - /// If set, then the state root check is disabled by the virtue of calling into - /// `TryRuntime_execute_block_no_check` instead of - /// `Core_execute_block`. + /// If set the state root check is disabled. #[clap(long)] - no_check: bool, + no_state_root_check: bool, + + /// Which try-state targets to execute when running this command. + /// + /// Expected values: + /// - `all` + /// - `none` + /// - A comma separated list of pallets, as per pallet names in `construct_runtime!()` (e.g. + /// `Staking, System`). + /// - `rr-[x]` where `[x]` is a number. Then, the given number of pallets are checked in a + /// round-robin fashion. + #[clap(long, default_value = "none")] + try_state: frame_try_runtime::TryStateSelect, /// The block hash at which to fetch the block. /// @@ -70,7 +84,7 @@ pub struct ExecuteBlockCmd { } impl ExecuteBlockCmd { - fn block_at(&self) -> sc_cli::Result + async fn block_at(&self, ws_uri: String) -> sc_cli::Result where Block::Hash: FromStr, ::Err: Debug, @@ -81,6 +95,15 @@ impl ExecuteBlockCmd { log::warn!(target: LOG_TARGET, "--block-at is provided while state type is live. the `Live::at` will be ignored"); hash_of::(block_at) }, + (None, State::Live { at: None, .. }) => { + log::warn!( + target: LOG_TARGET, + "No --block-at or --at provided, using the latest finalized block instead" + ); + remote_externalities::rpc_api::get_finalized_head::(ws_uri) + .await + .map_err(Into::into) + }, (None, State::Live { at: Some(at), .. }) => hash_of::(at), _ => { panic!("either `--block-at` must be provided, or state must be `live with a proper `--at``"); @@ -123,13 +146,14 @@ where let executor = build_executor::(&shared, &config); let execution = shared.execution; - let block_at = command.block_at::()?; let block_ws_uri = command.block_ws_uri::(); + let block_at = command.block_at::(block_ws_uri.clone()).await?; let block: Block = rpc_api::get_block::(block_ws_uri.clone(), block_at).await?; let parent_hash = block.header().parent_hash(); log::info!( target: LOG_TARGET, - "fetched block from {:?}, parent_hash to fetch the state {:?}", + "fetched block #{:?} from {:?}, parent_hash to fetch the state {:?}", + block.header().number(), block_ws_uri, parent_hash ); @@ -162,6 +186,7 @@ where let (mut header, extrinsics) = block.deconstruct(); header.digest_mut().pop(); let block = Block::new(header, extrinsics); + let payload = (block.clone(), !command.no_state_root_check, command.try_state).encode(); let (expected_spec_name, expected_spec_version, _) = local_spec::(&ext, &executor); @@ -177,8 +202,8 @@ where &ext, &executor, execution, - if command.no_check { "TryRuntime_execute_block_no_check" } else { "Core_execute_block" }, - block.encode().as_ref(), + "TryRuntime_execute_block", + &payload, full_extensions(), )?; diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index b6a11699a3d72..01fc1dae15a05 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -23,7 +23,7 @@ use jsonrpsee::{ core::client::{Subscription, SubscriptionClientT}, ws_client::WsClientBuilder, }; -use parity_scale_codec::Decode; +use parity_scale_codec::{Decode, Encode}; use remote_externalities::{rpc_api, Builder, Mode, OnlineConfig}; use sc_executor::NativeExecutionDispatch; use sc_service::Configuration; @@ -40,6 +40,22 @@ pub struct FollowChainCmd { /// The url to connect to. #[clap(short, long, parse(try_from_str = parse::url))] uri: String, + + /// If set, then the state root check is enabled. + #[clap(long)] + state_root_check: bool, + + /// Which try-state targets to execute when running this command. + /// + /// Expected values: + /// - `all` + /// - `none` + /// - A comma separated list of pallets, as per pallet names in `construct_runtime!()` (e.g. + /// `Staking, System`). + /// - `rr-[x]` where `[x]` is a number. Then, the given number of pallets are checked in a + /// round-robin fashion. + #[clap(long, default_value = "none")] + try_state: frame_try_runtime::TryStateSelect, } pub(crate) async fn follow_chain( @@ -141,8 +157,8 @@ where state_ext, &executor, execution, - "TryRuntime_execute_block_no_check", - block.encode().as_ref(), + "TryRuntime_execute_block", + (block, command.state_root_check, command.try_state.clone()).encode().as_ref(), full_extensions(), )?; diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 9013da95f1722..76679c43f7f14 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -335,17 +335,18 @@ pub enum Command { /// different state transition function. /// /// To make testing slightly more dynamic, you can disable the state root check by enabling - /// `ExecuteBlockCmd::no_check`. If you get signature verification errors, you should - /// manually tweak your local runtime's spec version to fix this. + /// `ExecuteBlockCmd::no_check`. If you get signature verification errors, you should manually + /// tweak your local runtime's spec version to fix this. /// /// A subtle detail of execute block is that if you want to execute block 100 of a live chain /// again, you need to scrape the state of block 99. This is already done automatically if you /// use [`State::Live`], and the parent hash of the target block is used to scrape the state. /// If [`State::Snap`] is being used, then this needs to be manually taken into consideration. /// - /// This executes the same runtime api as normal block import, namely `Core_execute_block`. If - /// `ExecuteBlockCmd::no_check` is set, it uses a custom, try-runtime-only runtime - /// api called `TryRuntime_execute_block_no_check`. + /// This does not execute the same runtime api as normal block import do, namely + /// `Core_execute_block`. Instead, it uses `TryRuntime_execute_block`, which can optionally + /// skip state-root check (useful for trying a unreleased runtime), and can execute runtime + /// sanity checks as well. ExecuteBlock(commands::execute_block::ExecuteBlockCmd), /// Executes *the offchain worker hooks* of a given block against some state. @@ -656,21 +657,27 @@ pub(crate) async fn ensure_matching_spec { - log::error!( - target: LOG_TARGET, + let msg = format!( "failed to fetch runtime version from {}: {:?}. Skipping the check", - uri, - why + uri, why ); + if relaxed { + log::error!(target: LOG_TARGET, "{}", msg); + } else { + panic!("{}", msg); + } }, } } @@ -801,15 +808,15 @@ pub(crate) fn state_machine_call_with_proof>()), proof_nodes.len() ); - log::info!(target: LOG_TARGET, "proof size: {}", humanize(proof_size)); - log::info!(target: LOG_TARGET, "compact proof size: {}", humanize(compact_proof_size),); - log::info!( + log::debug!(target: LOG_TARGET, "proof size: {}", humanize(proof_size)); + log::debug!(target: LOG_TARGET, "compact proof size: {}", humanize(compact_proof_size),); + log::debug!( target: LOG_TARGET, "zstd-compressed compact proof {}", humanize(compressed_proof.len()), From 5b0f999d6be8a29e4d6adfdfb22c314292f1d318 Mon Sep 17 00:00:00 2001 From: ZhiYong Date: Thu, 1 Sep 2022 18:39:25 +0800 Subject: [PATCH 1110/1472] Name the score of the election in election finalized event (#12069) * Name the score of the election in ElectionFinalized event * fmt * 1.Adjust the logic of the function 'do_elect()'. 2.Add one test that does ElectionCompute::Signed and one that does ElectionCompute::Unsigned to check 'Event::SolutionStored' and 'Event::ElectionFinalized' * Fix from kian * fmt and update comment. Co-authored-by: kianenigma --- .../election-provider-multi-phase/src/lib.rs | 146 +++++++++++++++--- 1 file changed, 121 insertions(+), 25 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 906de8a6c9d20..84949080aa58c 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -494,6 +494,8 @@ pub enum ElectionError { DataProvider(&'static str), /// An error nested in the fallback. Fallback(FallbackErrorOf), + /// No solution has been queued. + NothingQueued, } // NOTE: we have to do this manually because of the additional where clause needed on @@ -900,7 +902,7 @@ pub mod pallet { let ejected_a_solution = >::exists(); >::put(ready); Self::deposit_event(Event::SolutionStored { - election_compute: ElectionCompute::Unsigned, + compute: ElectionCompute::Unsigned, prev_ejected: ejected_a_solution, }); @@ -948,7 +950,7 @@ pub mod pallet { }; Self::deposit_event(Event::SolutionStored { - election_compute: ElectionCompute::Emergency, + compute: ElectionCompute::Emergency, prev_ejected: QueuedSolution::::exists(), }); @@ -1024,7 +1026,7 @@ pub mod pallet { signed_submissions.put(); Self::deposit_event(Event::SolutionStored { - election_compute: ElectionCompute::Signed, + compute: ElectionCompute::Signed, prev_ejected: ejected_a_solution, }); Ok(()) @@ -1062,7 +1064,7 @@ pub mod pallet { }; Self::deposit_event(Event::SolutionStored { - election_compute: ElectionCompute::Fallback, + compute: ElectionCompute::Fallback, prev_ejected: QueuedSolution::::exists(), }); @@ -1080,10 +1082,13 @@ pub mod pallet { /// solution is unsigned, this means that it has also been processed. /// /// The `bool` is `true` when a previous solution was ejected to make room for this one. - SolutionStored { election_compute: ElectionCompute, prev_ejected: bool }, - /// The election has been finalized, with `Some` of the given computation, or else if the - /// election failed, `None`. - ElectionFinalized { election_compute: Option }, + SolutionStored { compute: ElectionCompute, prev_ejected: bool }, + /// The election has been finalized, with the given computation and score. + ElectionFinalized { compute: ElectionCompute, score: ElectionScore }, + /// An election failed. + /// + /// Not much can be said about which computes failed in the process. + ElectionFailed, /// An account has been rewarded for their signed submission being finalized. Rewarded { account: ::AccountId, value: BalanceOf }, /// An account has been slashed for submitting an invalid signed submission. @@ -1530,23 +1535,25 @@ impl Pallet { // inexpensive (1 read of an empty vector). let _ = Self::finalize_signed_phase(); >::take() - .map_or_else( - || { - T::Fallback::elect() - .map_err(|fe| ElectionError::Fallback(fe)) - .map(|supports| (supports, ElectionCompute::Fallback)) - }, - |ReadySolution { supports, compute, .. }| Ok((supports, compute)), - ) - .map(|(supports, compute)| { - Self::deposit_event(Event::ElectionFinalized { election_compute: Some(compute) }); + .ok_or(ElectionError::::NothingQueued) + .or_else(|_| { + T::Fallback::elect() + .map(|supports| ReadySolution { + supports, + score: Default::default(), + compute: ElectionCompute::Fallback, + }) + .map_err(|fe| ElectionError::Fallback(fe)) + }) + .map(|ReadySolution { compute, score, supports }| { + Self::deposit_event(Event::ElectionFinalized { compute, score }); if Self::round() != 1 { log!(info, "Finalized election round with compute {:?}.", compute); } supports }) .map_err(|err| { - Self::deposit_event(Event::ElectionFinalized { election_compute: None }); + Self::deposit_event(Event::ElectionFailed); if Self::round() != 1 { log!(warn, "Failed to finalize election round. reason {:?}", err); } @@ -1800,8 +1807,9 @@ mod tests { use super::*; use crate::{ mock::{ - multi_phase_events, roll_to, AccountId, ExtBuilder, MockWeightInfo, MockedWeightInfo, - MultiPhase, Origin, Runtime, SignedMaxSubmissions, System, TargetIndex, Targets, + multi_phase_events, raw_solution, roll_to, AccountId, ExtBuilder, MockWeightInfo, + MockedWeightInfo, MultiPhase, Origin, Runtime, SignedMaxSubmissions, System, + TargetIndex, Targets, }, Phase, }; @@ -1967,7 +1975,10 @@ mod tests { multi_phase_events(), vec![ Event::SignedPhaseStarted { round: 1 }, - Event::ElectionFinalized { election_compute: Some(ElectionCompute::Fallback) } + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: Default::default() + } ], ); // All storage items must be cleared. @@ -2016,6 +2027,88 @@ mod tests { }) } + #[test] + fn check_events_with_compute_signed() { + ExtBuilder::default().build_and_execute(|| { + roll_to(14); + assert_eq!(MultiPhase::current_phase(), Phase::Off); + + roll_to(15); + assert!(MultiPhase::current_phase().is_signed()); + + let solution = raw_solution(); + assert_ok!(MultiPhase::submit(crate::mock::Origin::signed(99), Box::new(solution))); + + roll_to(30); + assert_ok!(MultiPhase::elect()); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Rewarded { account: 99, value: 7 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Signed, + score: ElectionScore { + minimal_stake: 40, + sum_stake: 100, + sum_stake_squared: 5200 + } + } + ], + ); + }) + } + + #[test] + fn check_events_with_compute_unsigned() { + ExtBuilder::default().build_and_execute(|| { + roll_to(25); + assert!(MultiPhase::current_phase().is_unsigned()); + + // ensure we have snapshots in place. + assert!(MultiPhase::snapshot().is_some()); + assert_eq!(MultiPhase::desired_targets().unwrap(), 2); + + // mine seq_phragmen solution with 2 iters. + let (solution, witness) = MultiPhase::mine_solution().unwrap(); + + // ensure this solution is valid. + assert!(MultiPhase::queued_solution().is_none()); + assert_ok!(MultiPhase::submit_unsigned( + crate::mock::Origin::none(), + Box::new(solution), + witness + )); + assert!(MultiPhase::queued_solution().is_some()); + + roll_to(30); + assert_ok!(MultiPhase::elect()); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Unsigned, + prev_ejected: false + }, + Event::ElectionFinalized { + compute: ElectionCompute::Unsigned, + score: ElectionScore { + minimal_stake: 40, + sum_stake: 100, + sum_stake_squared: 5200 + } + } + ], + ); + }) + } + #[test] fn fallback_strategy_works() { ExtBuilder::default().onchain_fallback(true).build_and_execute(|| { @@ -2080,12 +2173,15 @@ mod tests { vec![ Event::SignedPhaseStarted { round: 1 }, Event::UnsignedPhaseStarted { round: 1 }, - Event::ElectionFinalized { election_compute: None }, + Event::ElectionFailed, Event::SolutionStored { - election_compute: ElectionCompute::Fallback, + compute: ElectionCompute::Fallback, prev_ejected: false }, - Event::ElectionFinalized { election_compute: Some(ElectionCompute::Fallback) } + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: Default::default() + } ] ); }) From 6bd6b3109d2fa759e384353791aadd2988454881 Mon Sep 17 00:00:00 2001 From: NingLin-P Date: Thu, 1 Sep 2022 23:45:34 +0800 Subject: [PATCH 1111/1472] statedb: allow longer state pruning history (#11980) * introduce DbBackedQueue for the state pruning window Signed-off-by: linning * avoid cloning for next_hash Signed-off-by: linning * add tests Signed-off-by: linning * make clippy happy Signed-off-by: linning * impl have_block by checking block number Signed-off-by: linning * refactor Signed-off-by: linning * fix tests & add test for init db-backed queue Signed-off-by: linning * update comment Signed-off-by: linning * add check for have_state_at Signed-off-by: linning * address comment Signed-off-by: linning * renanme unload_blocks to uncached_blocks Signed-off-by: linning * address comment Signed-off-by: linning * fix syncs_state test Signed-off-by: linning * address comment Signed-off-by: linning * revert change to make_test_db to add test cases Signed-off-by: linning * do not prune unavailable block & add tests Signed-off-by: linning * Update client/state-db/src/lib.rs Signed-off-by: linning Co-authored-by: cheme * Update client/state-db/src/pruning.rs Signed-off-by: linning Co-authored-by: cheme * address comment Signed-off-by: linning Signed-off-by: linning Co-authored-by: cheme --- client/db/src/lib.rs | 67 +- client/state-db/src/lib.rs | 281 +++++--- client/state-db/src/noncanonical.rs | 11 +- client/state-db/src/pruning.rs | 976 ++++++++++++++++++++++------ client/state-db/src/test.rs | 34 +- 5 files changed, 1051 insertions(+), 318 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 465db08fe3afc..79ef7e9b6625d 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -63,7 +63,7 @@ use sc_client_api::{ utils::is_descendent_of, IoInfo, MemoryInfo, MemorySize, UsageInfo, }; -use sc_state_db::StateDb; +use sc_state_db::{IsPruned, StateDb}; use sp_arithmetic::traits::Saturating; use sp_blockchain::{ well_known_cache_keys, Backend as _, CachedHeaderMetadata, Error as ClientError, HeaderBackend, @@ -442,9 +442,10 @@ struct PendingBlock { } // wrapper that implements trait required for state_db -struct StateMetaDb<'a>(&'a dyn Database); +#[derive(Clone)] +struct StateMetaDb(Arc>); -impl<'a> sc_state_db::MetaDb for StateMetaDb<'a> { +impl sc_state_db::MetaDb for StateMetaDb { type Error = sp_database::error::DatabaseError; fn get_meta(&self, key: &[u8]) -> Result>, Self::Error> { @@ -915,7 +916,7 @@ impl sc_client_api::backend::BlockImportOperation struct StorageDb { pub db: Arc>, - pub state_db: StateDb>, + pub state_db: StateDb, StateMetaDb>, prefix_keys: bool, } @@ -1104,11 +1105,11 @@ impl Backend { let mut db_init_transaction = Transaction::new(); let requested_state_pruning = config.state_pruning.clone(); - let state_meta_db = StateMetaDb(db.as_ref()); + let state_meta_db = StateMetaDb(db.clone()); let map_e = sp_blockchain::Error::from_state_db; let (state_db_init_commit_set, state_db) = StateDb::open( - &state_meta_db, + state_meta_db, requested_state_pruning, !db.supports_ref_counting(), should_init, @@ -1317,10 +1318,11 @@ impl Backend { } trace!(target: "db", "Canonicalize block #{} ({:?})", new_canonical, hash); - let commit = - self.storage.state_db.canonicalize_block(&hash).map_err( - sp_blockchain::Error::from_state_db::>, - )?; + let commit = self.storage.state_db.canonicalize_block(&hash).map_err( + sp_blockchain::Error::from_state_db::< + sc_state_db::Error, + >, + )?; apply_state_commit(transaction, commit); } Ok(()) @@ -1471,14 +1473,16 @@ impl Backend { .storage .state_db .insert_block(&hash, number_u64, pending_block.header.parent_hash(), changeset) - .map_err(|e: sc_state_db::Error| { + .map_err(|e: sc_state_db::Error| { sp_blockchain::Error::from_state_db(e) })?; apply_state_commit(&mut transaction, commit); if number <= last_finalized_num { // Canonicalize in the db when re-importing existing blocks with state. let commit = self.storage.state_db.canonicalize_block(&hash).map_err( - sp_blockchain::Error::from_state_db::>, + sp_blockchain::Error::from_state_db::< + sc_state_db::Error, + >, )?; apply_state_commit(&mut transaction, commit); meta_updates.push(MetaUpdate { @@ -1679,10 +1683,11 @@ impl Backend { .map(|c| f_num.saturated_into::() > c) .unwrap_or(true) { - let commit = - self.storage.state_db.canonicalize_block(&f_hash).map_err( - sp_blockchain::Error::from_state_db::>, - )?; + let commit = self.storage.state_db.canonicalize_block(&f_hash).map_err( + sp_blockchain::Error::from_state_db::< + sc_state_db::Error, + >, + )?; apply_state_commit(transaction, commit); } @@ -2294,13 +2299,14 @@ impl sc_client_api::backend::Backend for Backend { match self.blockchain.header_metadata(hash) { Ok(ref hdr) => { - if !self.have_state_at(&hash, hdr.number) { - return Err(sp_blockchain::Error::UnknownBlock(format!( - "State already discarded for {:?}", - block - ))) - } - if let Ok(()) = self.storage.state_db.pin(&hash) { + let hint = || { + sc_state_db::NodeDb::get(self.storage.as_ref(), hdr.state_root.as_ref()) + .unwrap_or(None) + .is_some() + }; + if let Ok(()) = + self.storage.state_db.pin(&hash, hdr.number.saturated_into::(), hint) + { let root = hdr.state_root; let db_state = DbStateBuilder::::new(self.storage.clone(), root) .with_optional_cache( @@ -2333,7 +2339,20 @@ impl sc_client_api::backend::Backend for Backend { _ => false, } } else { - !self.storage.state_db.is_pruned(hash, number.saturated_into::()) + match self.storage.state_db.is_pruned(hash, number.saturated_into::()) { + IsPruned::Pruned => false, + IsPruned::NotPruned => true, + IsPruned::MaybePruned => match self.blockchain.header_metadata(*hash) { + Ok(header) => sp_state_machine::Storage::get( + self.storage.as_ref(), + &header.state_root, + (&[], None), + ) + .unwrap_or(None) + .is_some(), + _ => false, + }, + } } } diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 1c7140777e16e..f21b707a489f0 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -51,7 +51,7 @@ use log::trace; use noncanonical::NonCanonicalOverlay; use parity_util_mem::{malloc_size, MallocSizeOf}; use parking_lot::RwLock; -use pruning::RefWindow; +use pruning::{HaveBlock, RefWindow}; use sc_client_api::{MemorySize, StateDbMemoryInfo}; use std::{ collections::{hash_map::Entry, HashMap}, @@ -62,6 +62,7 @@ const PRUNING_MODE: &[u8] = b"mode"; const PRUNING_MODE_ARCHIVE: &[u8] = b"archive"; const PRUNING_MODE_ARCHIVE_CANON: &[u8] = b"archive_canonical"; const PRUNING_MODE_CONSTRAINED: &[u8] = b"constrained"; +pub(crate) const DEFAULT_MAX_BLOCK_CONSTRAINT: u32 = 256; /// Database value type. pub type DBValue = Vec; @@ -115,12 +116,14 @@ pub trait NodeDb { } /// Error type. +#[derive(Eq, PartialEq)] pub enum Error { /// Database backend error. Db(E), StateDb(StateDbError), } +#[derive(Eq, PartialEq)] pub enum StateDbError { /// `Codec` decoding error. Decoding(codec::Error), @@ -138,6 +141,10 @@ pub enum StateDbError { BlockAlreadyExists, /// Invalid metadata Metadata(String), + /// Trying to get a block record from db while it is not commit to db yet + BlockUnavailable, + /// Block record is missing from the pruning window + BlockMissing, } impl From for Error { @@ -182,6 +189,9 @@ impl fmt::Debug for StateDbError { Self::TooManySiblingBlocks => write!(f, "Too many sibling blocks inserted"), Self::BlockAlreadyExists => write!(f, "Block already exists"), Self::Metadata(message) => write!(f, "Invalid metadata: {}", message), + Self::BlockUnavailable => + write!(f, "Trying to get a block record from db while it is not commit to db yet"), + Self::BlockMissing => write!(f, "Block record is missing from the pruning window"), } } } @@ -266,7 +276,7 @@ impl Default for PruningMode { impl Default for Constraints { fn default() -> Self { - Self { max_blocks: Some(256), max_mem: None } + Self { max_blocks: Some(DEFAULT_MAX_BLOCK_CONSTRAINT), max_mem: None } } } @@ -276,38 +286,41 @@ fn to_meta_key(suffix: &[u8], data: &S) -> Vec { buffer } -struct StateDbSync { +pub struct StateDbSync { mode: PruningMode, non_canonical: NonCanonicalOverlay, - pruning: Option>, + pruning: Option>, pinned: HashMap, } -impl StateDbSync { - fn new( +impl + StateDbSync +{ + fn new( mode: PruningMode, ref_counting: bool, - db: &D, - ) -> Result, Error> { + db: D, + ) -> Result, Error> { trace!(target: "state-db", "StateDb settings: {:?}. Ref-counting: {}", mode, ref_counting); - let non_canonical: NonCanonicalOverlay = NonCanonicalOverlay::new(db)?; - let pruning: Option> = match mode { + let non_canonical: NonCanonicalOverlay = NonCanonicalOverlay::new(&db)?; + let pruning: Option> = match mode { PruningMode::Constrained(Constraints { max_mem: Some(_), .. }) => unimplemented!(), - PruningMode::Constrained(_) => Some(RefWindow::new(db, ref_counting)?), + PruningMode::Constrained(Constraints { max_blocks, .. }) => + Some(RefWindow::new(db, max_blocks.unwrap_or(0), ref_counting)?), PruningMode::ArchiveAll | PruningMode::ArchiveCanonical => None, }; Ok(StateDbSync { mode, non_canonical, pruning, pinned: Default::default() }) } - fn insert_block( + fn insert_block( &mut self, hash: &BlockHash, number: u64, parent_hash: &BlockHash, mut changeset: ChangeSet, - ) -> Result, Error> { + ) -> Result, Error> { match self.mode { PruningMode::ArchiveAll => { changeset.deleted.clear(); @@ -321,25 +334,23 @@ impl StateDbSync( - &mut self, - hash: &BlockHash, - ) -> Result, Error> { + fn canonicalize_block(&mut self, hash: &BlockHash) -> Result, Error> { + // NOTE: it is important that the change to `LAST_CANONICAL` (emit from + // `non_canonical.canonicalize`) and the insert of the new pruning journal (emit from + // `pruning.note_canonical`) are collected into the same `CommitSet` and are committed to + // the database atomically to keep their consistency when restarting the node let mut commit = CommitSet::default(); if self.mode == PruningMode::ArchiveAll { return Ok(commit) } - match self.non_canonical.canonicalize(hash, &mut commit) { - Ok(()) => - if self.mode == PruningMode::ArchiveCanonical { - commit.data.deleted.clear(); - }, - Err(e) => return Err(e.into()), - }; + let number = self.non_canonical.canonicalize(hash, &mut commit)?; + if self.mode == PruningMode::ArchiveCanonical { + commit.data.deleted.clear(); + } if let Some(ref mut pruning) = self.pruning { - pruning.note_canonical(hash, &mut commit); + pruning.note_canonical(hash, number, &mut commit)?; } - self.prune(&mut commit); + self.prune(&mut commit)?; Ok(commit) } @@ -347,22 +358,31 @@ impl StateDbSync bool { + fn is_pruned(&self, hash: &BlockHash, number: u64) -> IsPruned { match self.mode { - PruningMode::ArchiveAll => false, + PruningMode::ArchiveAll => IsPruned::NotPruned, PruningMode::ArchiveCanonical | PruningMode::Constrained(_) => { if self.best_canonical().map(|c| number > c).unwrap_or(true) { - !self.non_canonical.have_block(hash) + if self.non_canonical.have_block(hash) { + IsPruned::NotPruned + } else { + IsPruned::Pruned + } } else { - self.pruning.as_ref().map_or(false, |pruning| { - number < pruning.pending() || !pruning.have_block(hash) - }) + match self.pruning.as_ref() { + None => IsPruned::NotPruned, + Some(pruning) => match pruning.have_block(hash, number) { + HaveBlock::NotHave => IsPruned::Pruned, + HaveBlock::Have => IsPruned::NotPruned, + HaveBlock::MayHave => IsPruned::MaybePruned, + }, + } } }, } } - fn prune(&mut self, commit: &mut CommitSet) { + fn prune(&mut self, commit: &mut CommitSet) -> Result<(), Error> { if let (&mut Some(ref mut pruning), &PruningMode::Constrained(ref constraints)) = (&mut self.pruning, &self.mode) { @@ -376,12 +396,23 @@ impl StateDbSync break, + res => + if res?.map_or(false, |h| pinned.contains_key(&h)) { + break + }, + } + match pruning.prune_one(commit) { + // this branch should not reach as previous `next_hash` don't return error + // keeping it for robustness + Err(Error::StateDb(StateDbError::BlockUnavailable)) => break, + res => res?, } - pruning.prune_one(commit); } } + Ok(()) } /// Revert all non-canonical blocks with the best block number. @@ -403,13 +434,22 @@ impl StateDbSync Result<(), PinError> { + fn pin(&mut self, hash: &BlockHash, number: u64, hint: F) -> Result<(), PinError> + where + F: Fn() -> bool, + { match self.mode { PruningMode::ArchiveAll => Ok(()), PruningMode::ArchiveCanonical | PruningMode::Constrained(_) => { - if self.non_canonical.have_block(hash) || - self.pruning.as_ref().map_or(false, |pruning| pruning.have_block(hash)) - { + let have_block = self.non_canonical.have_block(hash) || + self.pruning.as_ref().map_or(false, |pruning| { + match pruning.have_block(hash, number) { + HaveBlock::NotHave => false, + HaveBlock::Have => true, + HaveBlock::MayHave => hint(), + } + }); + if have_block { let refs = self.pinned.entry(hash.clone()).or_default(); if *refs == 0 { trace!(target: "state-db-pin", "Pinned block: {:?}", hash); @@ -440,13 +480,13 @@ impl StateDbSync( + pub fn get( &self, key: &Q, - db: &D, - ) -> Result, Error> + db: &DB, + ) -> Result, Error> where - Q: AsRef, + Q: AsRef, Key: std::borrow::Borrow, Q: std::hash::Hash + Eq, { @@ -461,10 +501,11 @@ impl StateDbSync StateDbSync StateDbMemoryInfo { StateDbMemoryInfo { non_canonical: MemorySize::from_bytes(malloc_size(&self.non_canonical)), - pruning: self.pruning.as_ref().map(|p| MemorySize::from_bytes(malloc_size(p))), + pruning: self.pruning.as_ref().map(|p| MemorySize::from_bytes(malloc_size(&p))), pinned: MemorySize::from_bytes(malloc_size(&self.pinned)), } } @@ -490,22 +531,21 @@ impl StateDbSync { - db: RwLock>, +pub struct StateDb { + db: RwLock>, } -impl StateDb { +impl + StateDb +{ /// Create an instance of [`StateDb`]. - pub fn open( - db: &D, + pub fn open( + db: D, requested_mode: Option, ref_counting: bool, should_init: bool, - ) -> Result<(CommitSet, StateDb), Error> - where - D: MetaDb, - { - let stored_mode = fetch_stored_pruning_mode(db)?; + ) -> Result<(CommitSet, StateDb), Error> { + let stored_mode = fetch_stored_pruning_mode(&db)?; let selected_mode = match (should_init, stored_mode, requested_mode) { (true, stored_mode, requested_mode) => { @@ -548,27 +588,28 @@ impl StateDb( + pub fn insert_block( &self, hash: &BlockHash, number: u64, parent_hash: &BlockHash, changeset: ChangeSet, - ) -> Result, Error> { + ) -> Result, Error> { self.db.write().insert_block(hash, number, parent_hash, changeset) } /// Finalize a previously inserted block. - pub fn canonicalize_block( - &self, - hash: &BlockHash, - ) -> Result, Error> { + pub fn canonicalize_block(&self, hash: &BlockHash) -> Result, Error> { self.db.write().canonicalize_block(hash) } /// Prevents pruning of specified block and its descendants. - pub fn pin(&self, hash: &BlockHash) -> Result<(), PinError> { - self.db.write().pin(hash) + /// `hint` used for futher checking if the given block exists + pub fn pin(&self, hash: &BlockHash, number: u64, hint: F) -> Result<(), PinError> + where + F: Fn() -> bool, + { + self.db.write().pin(hash, number, hint) } /// Allows pruning of specified block. @@ -577,13 +618,13 @@ impl StateDb( + pub fn get( &self, key: &Q, - db: &D, - ) -> Result, Error> + db: &DB, + ) -> Result, Error> where - Q: AsRef, + Q: AsRef, Key: std::borrow::Borrow, Q: std::hash::Hash + Eq, { @@ -609,7 +650,7 @@ impl StateDb bool { + pub fn is_pruned(&self, hash: &BlockHash, number: u64) -> IsPruned { return self.db.read().is_pruned(hash, number) } @@ -629,6 +670,17 @@ impl StateDb(db: &D) -> Result, Error> { let meta_key_mode = to_meta_key(PRUNING_MODE, &()); if let Some(stored_mode) = db.get_meta(&meta_key_mode).map_err(Error::Db)? { @@ -664,20 +716,19 @@ fn choose_pruning_mode( mod tests { use crate::{ test::{make_changeset, make_db, TestDb}, - Constraints, Error, PruningMode, StateDb, StateDbError, + Constraints, Error, IsPruned, PruningMode, StateDb, StateDbError, }; use sp_core::H256; - use std::io; - fn make_test_db(settings: PruningMode) -> (TestDb, StateDb) { + fn make_test_db(settings: PruningMode) -> (TestDb, StateDb) { let mut db = make_db(&[91, 921, 922, 93, 94]); let (state_db_init, state_db) = - StateDb::open(&mut db, Some(settings), false, true).unwrap(); + StateDb::open(db.clone(), Some(settings), false, true).unwrap(); db.commit(&state_db_init); db.commit( &state_db - .insert_block::( + .insert_block( &H256::from_low_u64_be(1), 1, &H256::from_low_u64_be(0), @@ -687,7 +738,7 @@ mod tests { ); db.commit( &state_db - .insert_block::( + .insert_block( &H256::from_low_u64_be(21), 2, &H256::from_low_u64_be(1), @@ -697,7 +748,7 @@ mod tests { ); db.commit( &state_db - .insert_block::( + .insert_block( &H256::from_low_u64_be(22), 2, &H256::from_low_u64_be(1), @@ -707,7 +758,7 @@ mod tests { ); db.commit( &state_db - .insert_block::( + .insert_block( &H256::from_low_u64_be(3), 3, &H256::from_low_u64_be(21), @@ -716,11 +767,11 @@ mod tests { .unwrap(), ); state_db.apply_pending(); - db.commit(&state_db.canonicalize_block::(&H256::from_low_u64_be(1)).unwrap()); + db.commit(&state_db.canonicalize_block(&H256::from_low_u64_be(1)).unwrap()); state_db.apply_pending(); db.commit( &state_db - .insert_block::( + .insert_block( &H256::from_low_u64_be(4), 4, &H256::from_low_u64_be(3), @@ -729,9 +780,9 @@ mod tests { .unwrap(), ); state_db.apply_pending(); - db.commit(&state_db.canonicalize_block::(&H256::from_low_u64_be(21)).unwrap()); + db.commit(&state_db.canonicalize_block(&H256::from_low_u64_be(21)).unwrap()); state_db.apply_pending(); - db.commit(&state_db.canonicalize_block::(&H256::from_low_u64_be(3)).unwrap()); + db.commit(&state_db.canonicalize_block(&H256::from_low_u64_be(3)).unwrap()); state_db.apply_pending(); (db, state_db) @@ -741,7 +792,7 @@ mod tests { fn full_archive_keeps_everything() { let (db, sdb) = make_test_db(PruningMode::ArchiveAll); assert!(db.data_eq(&make_db(&[1, 21, 22, 3, 4, 91, 921, 922, 93, 94]))); - assert!(!sdb.is_pruned(&H256::from_low_u64_be(0), 0)); + assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(0), 0), IsPruned::NotPruned); } #[test] @@ -750,6 +801,43 @@ mod tests { assert!(db.data_eq(&make_db(&[1, 21, 3, 91, 921, 922, 93, 94]))); } + #[test] + fn block_record_unavailable() { + let (mut db, state_db) = make_test_db(PruningMode::Constrained(Constraints { + max_blocks: Some(1), + max_mem: None, + })); + // import 2 blocks + for i in &[5, 6] { + db.commit( + &state_db + .insert_block( + &H256::from_low_u64_be(*i), + *i, + &H256::from_low_u64_be(*i - 1), + make_changeset(&[], &[]), + ) + .unwrap(), + ); + } + // canonicalize block 4 but not commit it to db + let c1 = state_db.canonicalize_block(&H256::from_low_u64_be(4)).unwrap(); + assert_eq!(state_db.is_pruned(&H256::from_low_u64_be(3), 3), IsPruned::Pruned); + + // canonicalize block 5 but not commit it to db, block 4 is not pruned due to it is not + // commit to db yet (unavailable), return `MaybePruned` here because `apply_pending` is not + // called and block 3 is still in cache + let c2 = state_db.canonicalize_block(&H256::from_low_u64_be(5)).unwrap(); + assert_eq!(state_db.is_pruned(&H256::from_low_u64_be(4), 4), IsPruned::MaybePruned); + + // commit block 4 and 5 to db, and import a new block will prune both block 4 and 5 + db.commit(&c1); + db.commit(&c2); + db.commit(&state_db.canonicalize_block(&H256::from_low_u64_be(6)).unwrap()); + assert_eq!(state_db.is_pruned(&H256::from_low_u64_be(4), 4), IsPruned::Pruned); + assert_eq!(state_db.is_pruned(&H256::from_low_u64_be(5), 5), IsPruned::Pruned); + } + #[test] fn prune_window_0() { let (db, _) = make_test_db(PruningMode::Constrained(Constraints { @@ -765,10 +853,10 @@ mod tests { max_blocks: Some(1), max_mem: None, })); - assert!(sdb.is_pruned(&H256::from_low_u64_be(0), 0)); - assert!(sdb.is_pruned(&H256::from_low_u64_be(1), 1)); - assert!(sdb.is_pruned(&H256::from_low_u64_be(21), 2)); - assert!(sdb.is_pruned(&H256::from_low_u64_be(22), 2)); + assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(0), 0), IsPruned::Pruned); + assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(1), 1), IsPruned::Pruned); + assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(21), 2), IsPruned::Pruned); + assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(22), 2), IsPruned::Pruned); assert!(db.data_eq(&make_db(&[21, 3, 922, 93, 94]))); } @@ -778,10 +866,10 @@ mod tests { max_blocks: Some(2), max_mem: None, })); - assert!(sdb.is_pruned(&H256::from_low_u64_be(0), 0)); - assert!(sdb.is_pruned(&H256::from_low_u64_be(1), 1)); - assert!(!sdb.is_pruned(&H256::from_low_u64_be(21), 2)); - assert!(sdb.is_pruned(&H256::from_low_u64_be(22), 2)); + assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(0), 0), IsPruned::Pruned); + assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(1), 1), IsPruned::Pruned); + assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(21), 2), IsPruned::NotPruned); + assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(22), 2), IsPruned::Pruned); assert!(db.data_eq(&make_db(&[1, 21, 3, 921, 922, 93, 94]))); } @@ -789,11 +877,11 @@ mod tests { fn detects_incompatible_mode() { let mut db = make_db(&[]); let (state_db_init, state_db) = - StateDb::open(&mut db, Some(PruningMode::ArchiveAll), false, true).unwrap(); + StateDb::open(db.clone(), Some(PruningMode::ArchiveAll), false, true).unwrap(); db.commit(&state_db_init); db.commit( &state_db - .insert_block::( + .insert_block( &H256::from_low_u64_be(0), 0, &H256::from_low_u64_be(0), @@ -802,8 +890,8 @@ mod tests { .unwrap(), ); let new_mode = PruningMode::Constrained(Constraints { max_blocks: Some(2), max_mem: None }); - let state_db_open_result: Result<(_, StateDb), _> = - StateDb::open(&mut db, Some(new_mode), false, false); + let state_db_open_result: Result<(_, StateDb), _> = + StateDb::open(db.clone(), Some(new_mode), false, false); assert!(state_db_open_result.is_err()); } @@ -814,12 +902,13 @@ mod tests { ) { let mut db = make_db(&[]); let (state_db_init, state_db) = - StateDb::::open(&mut db, mode_when_created, false, true).unwrap(); + StateDb::::open(db.clone(), mode_when_created, false, true) + .unwrap(); db.commit(&state_db_init); std::mem::drop(state_db); let state_db_reopen_result = - StateDb::::open(&mut db, mode_when_reopened, false, false); + StateDb::::open(db.clone(), mode_when_reopened, false, false); if let Ok(expected_mode) = expected_effective_mode_when_reopenned { let (state_db_init, state_db_reopened) = state_db_reopen_result.unwrap(); db.commit(&state_db_init); diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index 13cf5825b1b24..559fc7ca023fe 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -28,7 +28,7 @@ use log::trace; use std::collections::{hash_map::Entry, HashMap, VecDeque}; const NON_CANONICAL_JOURNAL: &[u8] = b"noncanonical_journal"; -const LAST_CANONICAL: &[u8] = b"last_canonical"; +pub(crate) const LAST_CANONICAL: &[u8] = b"last_canonical"; const MAX_BLOCKS_PER_LEVEL: u64 = 32; /// See module documentation. @@ -376,12 +376,13 @@ impl NonCanonicalOverlay { } /// Select a top-level root and canonicalized it. Discards all sibling subtrees and the root. - /// Returns a set of changes that need to be added to the DB. + /// Add a set of changes of the canonicalized block to `CommitSet` + /// Return the block number of the canonicalized block pub fn canonicalize( &mut self, hash: &BlockHash, commit: &mut CommitSet, - ) -> Result<(), StateDbError> { + ) -> Result { trace!(target: "state-db", "Canonicalizing {:?}", hash); let level = self .levels @@ -431,7 +432,7 @@ impl NonCanonicalOverlay { .push((to_meta_key(LAST_CANONICAL, &()), canonicalized.encode())); trace!(target: "state-db", "Discarding {} records", commit.meta.deleted.len()); self.pending_canonicalizations.push(hash.clone()); - Ok(()) + Ok(canonicalized.1) } fn apply_canonicalizations(&mut self) { @@ -755,7 +756,7 @@ mod tests { .unwrap(), ); db.commit(&overlay.insert(&h2, 11, &h1, make_changeset(&[5], &[3])).unwrap()); - assert_eq!(db.meta.len(), 3); + assert_eq!(db.meta_len(), 3); let overlay2 = NonCanonicalOverlay::::new(&db).unwrap(); assert_eq!(overlay.levels, overlay2.levels); diff --git a/client/state-db/src/pruning.rs b/client/state-db/src/pruning.rs index 0fdcb8e822b6f..2c23110910495 100644 --- a/client/state-db/src/pruning.rs +++ b/client/state-db/src/pruning.rs @@ -24,74 +24,74 @@ //! the death list. //! The changes are journaled in the DB. -use crate::{to_meta_key, CommitSet, Error, Hash, MetaDb}; +use crate::{ + noncanonical::LAST_CANONICAL, to_meta_key, CommitSet, Error, Hash, MetaDb, StateDbError, + DEFAULT_MAX_BLOCK_CONSTRAINT, +}; use codec::{Decode, Encode}; -use log::{trace, warn}; -use std::collections::{HashMap, HashSet, VecDeque}; +use log::{error, trace, warn}; +use std::{ + cmp, + collections::{HashMap, HashSet, VecDeque}, +}; -const LAST_PRUNED: &[u8] = b"last_pruned"; +pub(crate) const LAST_PRUNED: &[u8] = b"last_pruned"; const PRUNING_JOURNAL: &[u8] = b"pruning_journal"; /// See module documentation. #[derive(parity_util_mem_derive::MallocSizeOf)] -pub struct RefWindow { - /// A queue of keys that should be deleted for each block in the pruning window. - death_rows: VecDeque>, - /// An index that maps each key from `death_rows` to block number. - death_index: HashMap, +pub struct RefWindow { + /// A queue of blocks keep tracking keys that should be deleted for each block in the + /// pruning window. + queue: DeathRowQueue, /// Block number that corresponds to the front of `death_rows`. - pending_number: u64, + base: u64, /// Number of call of `note_canonical` after /// last call `apply_pending` or `revert_pending` pending_canonicalizations: usize, /// Number of calls of `prune_one` after /// last call `apply_pending` or `revert_pending` pending_prunings: usize, - /// Keep track of re-inserted keys and do not delete them when pruning. - /// Setting this to false requires backend that supports reference - /// counting. - count_insertions: bool, } -#[derive(Debug, PartialEq, Eq, parity_util_mem_derive::MallocSizeOf)] -struct DeathRow { - hash: BlockHash, - journal_key: Vec, - deleted: HashSet, -} - -#[derive(Encode, Decode)] -struct JournalRecord { - hash: BlockHash, - inserted: Vec, - deleted: Vec, -} - -fn to_journal_key(block: u64) -> Vec { - to_meta_key(PRUNING_JOURNAL, &block) +/// `DeathRowQueue` used to keep track of blocks in the pruning window, there are two flavors: +/// - `Mem`, used when the backend database do not supports reference counting, keep all +/// blocks in memory, and keep track of re-inserted keys to not delete them when pruning +/// - `DbBacked`, used when the backend database supports reference counting, only keep +/// a few number of blocks in memory and load more blocks on demand +#[derive(parity_util_mem_derive::MallocSizeOf)] +enum DeathRowQueue { + Mem { + /// A queue of keys that should be deleted for each block in the pruning window. + death_rows: VecDeque>, + /// An index that maps each key from `death_rows` to block number. + death_index: HashMap, + }, + DbBacked { + // The backend database + #[ignore_malloc_size_of = "Shared data"] + db: D, + /// A queue of keys that should be deleted for each block in the pruning window. + /// Only caching the first fews blocks of the pruning window, blocks inside are + /// successive and ordered by block number + cache: VecDeque>, + /// A soft limit of the cache's size + cache_capacity: usize, + /// The number of blocks in queue that are not loaded into `cache`. + uncached_blocks: usize, + }, } -impl RefWindow { - pub fn new( - db: &D, - count_insertions: bool, - ) -> Result, Error> { - let last_pruned = db.get_meta(&to_meta_key(LAST_PRUNED, &())).map_err(Error::Db)?; - let pending_number: u64 = match last_pruned { - Some(buffer) => u64::decode(&mut buffer.as_slice())? + 1, - None => 0, - }; - let mut block = pending_number; - let mut pruning = RefWindow { - death_rows: Default::default(), - death_index: Default::default(), - pending_number, - pending_canonicalizations: 0, - pending_prunings: 0, - count_insertions, +impl DeathRowQueue { + /// Return a `DeathRowQueue` that all blocks are keep in memory + fn new_mem(db: &D, base: u64) -> Result, Error> { + let mut block = base; + let mut queue = DeathRowQueue::::Mem { + death_rows: VecDeque::new(), + death_index: HashMap::new(), }; // read the journal - trace!(target: "state-db", "Reading pruning journal. Pending #{}", pending_number); + trace!(target: "state-db", "Reading pruning journal for the memory queue. Pending #{}", base); loop { let journal_key = to_journal_key(block); match db.get_meta(&journal_key).map_err(Error::Db)? { @@ -99,102 +99,444 @@ impl RefWindow { let record: JournalRecord = Decode::decode(&mut record.as_slice())?; trace!(target: "state-db", "Pruning journal entry {} ({} inserted, {} deleted)", block, record.inserted.len(), record.deleted.len()); - pruning.import( - &record.hash, - journal_key, - record.inserted.into_iter(), - record.deleted, - ); + queue.import(base, record); }, None => break, } block += 1; } - Ok(pruning) + Ok(queue) + } + + /// Return a `DeathRowQueue` that backed by an database, and only keep a few number + /// of blocks in memory + fn new_db_backed( + db: D, + base: u64, + mut uncached_blocks: usize, + window_size: u32, + ) -> Result, Error> { + // limit the cache capacity from 1 to `DEFAULT_MAX_BLOCK_CONSTRAINT` + let cache_capacity = window_size.max(1).min(DEFAULT_MAX_BLOCK_CONSTRAINT) as usize; + let mut cache = VecDeque::with_capacity(cache_capacity); + trace!(target: "state-db", "Reading pruning journal for the database-backed queue. Pending #{}", base); + // Load block from db + DeathRowQueue::load_batch_from_db( + &db, + &mut uncached_blocks, + &mut cache, + base, + cache_capacity, + )?; + Ok(DeathRowQueue::DbBacked { db, cache, cache_capacity, uncached_blocks }) + } + + /// import a new block to the back of the queue + fn import(&mut self, base: u64, journal_record: JournalRecord) { + let JournalRecord { hash, inserted, deleted } = journal_record; + match self { + DeathRowQueue::DbBacked { uncached_blocks, cache, cache_capacity, .. } => { + // `uncached_blocks` is zero means currently all block are loaded into `cache` + // thus if `cache` is not full, load the next block into `cache` too + if *uncached_blocks == 0 && cache.len() < *cache_capacity { + cache.push_back(DeathRow { hash, deleted: deleted.into_iter().collect() }); + } else { + *uncached_blocks += 1; + } + }, + DeathRowQueue::Mem { death_rows, death_index } => { + // remove all re-inserted keys from death rows + for k in inserted { + if let Some(block) = death_index.remove(&k) { + death_rows[(block - base) as usize].deleted.remove(&k); + } + } + // add new keys + let imported_block = base + death_rows.len() as u64; + for k in deleted.iter() { + death_index.insert(k.clone(), imported_block); + } + death_rows.push_back(DeathRow { hash, deleted: deleted.into_iter().collect() }); + }, + } } - fn import>( + /// Pop out one block from the front of the queue, `base` is the block number + /// of the first block of the queue + fn pop_front( &mut self, - hash: &BlockHash, - journal_key: Vec, - inserted: I, - deleted: Vec, - ) { - if self.count_insertions { - // remove all re-inserted keys from death rows - for k in inserted { - if let Some(block) = self.death_index.remove(&k) { - self.death_rows[(block - self.pending_number) as usize].deleted.remove(&k); + base: u64, + ) -> Result>, Error> { + match self { + DeathRowQueue::DbBacked { db, uncached_blocks, cache, cache_capacity } => { + if cache.is_empty() && *uncached_blocks != 0 { + // load more blocks from db since there are still blocks in it + DeathRowQueue::load_batch_from_db( + db, + uncached_blocks, + cache, + base, + *cache_capacity, + )?; } - } + Ok(cache.pop_front()) + }, + DeathRowQueue::Mem { death_rows, death_index } => match death_rows.pop_front() { + Some(row) => { + for k in row.deleted.iter() { + death_index.remove(k); + } + Ok(Some(row)) + }, + None => Ok(None), + }, + } + } - // add new keys - let imported_block = self.pending_number + self.death_rows.len() as u64; - for k in deleted.iter() { - self.death_index.insert(k.clone(), imported_block); + /// Revert recent additions to the queue, namely remove `amount` number of blocks from the back + /// of the queue, `base` is the block number of the first block of the queue + fn revert_recent_add(&mut self, base: u64, amout: usize) { + debug_assert!(amout <= self.len()); + match self { + DeathRowQueue::DbBacked { uncached_blocks, cache, .. } => { + // remove from `uncached_blocks` if it can cover + if *uncached_blocks >= amout { + *uncached_blocks -= amout; + return + } + // reset `uncached_blocks` and remove remain blocks from `cache` + let remain = amout - *uncached_blocks; + *uncached_blocks = 0; + cache.truncate(cache.len() - remain); + }, + DeathRowQueue::Mem { death_rows, death_index } => { + // Revert recent addition to the queue + // Note that pending insertions might cause some existing deletions to be removed + // from `death_index` We don't bother to track and revert that for now. This means + // that a few nodes might end up no being deleted in case transaction fails and + // `revert_pending` is called. + death_rows.truncate(death_rows.len() - amout); + let new_max_block = death_rows.len() as u64 + base; + death_index.retain(|_, block| *block < new_max_block); + }, + } + } + + /// Load a batch of blocks from the backend database into `cache`, start from (and include) the + /// next block followe the last block of `cache`, `base` is the block number of the first block + /// of the queue + fn load_batch_from_db( + db: &D, + uncached_blocks: &mut usize, + cache: &mut VecDeque>, + base: u64, + cache_capacity: usize, + ) -> Result<(), Error> { + // return if all blocks already loaded into `cache` and there are no other + // blocks in the backend database + if *uncached_blocks == 0 { + return Ok(()) + } + let start = base + cache.len() as u64; + let batch_size = cmp::min(*uncached_blocks, cache_capacity); + let mut loaded = 0; + for i in 0..batch_size as u64 { + match load_death_row_from_db::(db, start + i)? { + Some(row) => { + cache.push_back(row); + loaded += 1; + }, + // block may added to the queue but not commit into the db yet, if there are + // data missing in the db `load_death_row_from_db` should return a db error + None => break, } } - self.death_rows.push_back(DeathRow { - hash: hash.clone(), - deleted: deleted.into_iter().collect(), - journal_key, - }); + *uncached_blocks -= loaded; + Ok(()) + } + + /// Get the block in the given index of the queue, `base` is the block number of the + /// first block of the queue + fn get( + &mut self, + base: u64, + index: usize, + ) -> Result>, Error> { + match self { + DeathRowQueue::DbBacked { db, uncached_blocks, cache, cache_capacity } => { + // check if `index` target a block reside on disk + if index >= cache.len() && index < cache.len() + *uncached_blocks { + // if `index` target the next batch of `DeathRow`, load a batch from db + if index - cache.len() < cmp::min(*uncached_blocks, *cache_capacity) { + DeathRowQueue::load_batch_from_db( + db, + uncached_blocks, + cache, + base, + *cache_capacity, + )?; + } else { + // load a single `DeathRow` from db, but do not insert it to `cache` + // because `cache` is a queue of successive `DeathRow` + // NOTE: this branch should not be entered because blocks are visited + // in successive increasing order, just keeping it for robustness + return load_death_row_from_db(db, base + index as u64) + } + } + Ok(cache.get(index).cloned()) + }, + DeathRowQueue::Mem { death_rows, .. } => Ok(death_rows.get(index).cloned()), + } + } + + /// Check if the block at the given `index` of the queue exist + /// it is the caller's responsibility to ensure `index` won't be out of bound + fn have_block(&self, hash: &BlockHash, index: usize) -> HaveBlock { + match self { + DeathRowQueue::DbBacked { cache, .. } => { + if cache.len() > index { + (cache[index].hash == *hash).into() + } else { + // the block not exist in `cache`, but it may exist in the unload + // blocks + HaveBlock::MayHave + } + }, + DeathRowQueue::Mem { death_rows, .. } => (death_rows[index].hash == *hash).into(), + } + } + + /// Return the number of block in the pruning window + fn len(&self) -> usize { + match self { + DeathRowQueue::DbBacked { uncached_blocks, cache, .. } => + cache.len() + *uncached_blocks, + DeathRowQueue::Mem { death_rows, .. } => death_rows.len(), + } + } + + #[cfg(test)] + fn get_mem_queue_state( + &self, + ) -> Option<(&VecDeque>, &HashMap)> { + match self { + DeathRowQueue::DbBacked { .. } => None, + DeathRowQueue::Mem { death_rows, death_index } => Some((death_rows, death_index)), + } + } + + #[cfg(test)] + fn get_db_backed_queue_state(&self) -> Option<(&VecDeque>, usize)> { + match self { + DeathRowQueue::DbBacked { cache, uncached_blocks, .. } => + Some((cache, *uncached_blocks)), + DeathRowQueue::Mem { .. } => None, + } + } +} + +fn load_death_row_from_db( + db: &D, + block: u64, +) -> Result>, Error> { + let journal_key = to_journal_key(block); + match db.get_meta(&journal_key).map_err(Error::Db)? { + Some(record) => { + let JournalRecord { hash, deleted, .. } = Decode::decode(&mut record.as_slice())?; + Ok(Some(DeathRow { hash, deleted: deleted.into_iter().collect() })) + }, + None => Ok(None), + } +} + +#[derive(Clone, Debug, PartialEq, Eq, parity_util_mem_derive::MallocSizeOf)] +struct DeathRow { + hash: BlockHash, + deleted: HashSet, +} + +#[derive(Encode, Decode, Default)] +struct JournalRecord { + hash: BlockHash, + inserted: Vec, + deleted: Vec, +} + +fn to_journal_key(block: u64) -> Vec { + to_meta_key(PRUNING_JOURNAL, &block) +} + +/// The result return by `RefWindow::have_block` +#[derive(Debug, PartialEq, Eq)] +pub enum HaveBlock { + /// Definitely not having this block + NotHave, + /// May or may not have this block, need futher checking + MayHave, + /// Definitely having this block + Have, +} + +impl From for HaveBlock { + fn from(have: bool) -> Self { + if have { + HaveBlock::Have + } else { + HaveBlock::NotHave + } + } +} + +impl RefWindow { + pub fn new( + db: D, + window_size: u32, + count_insertions: bool, + ) -> Result, Error> { + // the block number of the first block in the queue or the next block number if the queue is + // empty + let base = match db.get_meta(&to_meta_key(LAST_PRUNED, &())).map_err(Error::Db)? { + Some(buffer) => u64::decode(&mut buffer.as_slice())? + 1, + None => 0, + }; + // the block number of the last block in the queue + let last_canonicalized_number = + match db.get_meta(&to_meta_key(LAST_CANONICAL, &())).map_err(Error::Db)? { + Some(buffer) => Some(<(BlockHash, u64)>::decode(&mut buffer.as_slice())?.1), + None => None, + }; + + let queue = if count_insertions { + DeathRowQueue::new_mem(&db, base)? + } else { + let unload = match last_canonicalized_number { + Some(last_canonicalized_number) => { + debug_assert!(last_canonicalized_number + 1 >= base); + last_canonicalized_number + 1 - base + }, + // None means `LAST_CANONICAL` is never been wrote, since the pruning journals are + // in the same `CommitSet` as `LAST_CANONICAL`, it means no pruning journal have + // ever been committed to the db, thus set `unload` to zero + None => 0, + }; + DeathRowQueue::new_db_backed(db, base, unload as usize, window_size)? + }; + + Ok(RefWindow { queue, base, pending_canonicalizations: 0, pending_prunings: 0 }) } pub fn window_size(&self) -> u64 { - (self.death_rows.len() - self.pending_prunings) as u64 + (self.queue.len() - self.pending_prunings) as u64 } - pub fn next_hash(&self) -> Option { - self.death_rows.get(self.pending_prunings).map(|r| r.hash.clone()) + /// Get the hash of the next pruning block + pub fn next_hash(&mut self) -> Result, Error> { + let res = match &self.queue { + DeathRowQueue::DbBacked { cache, .. } => + if self.pending_prunings < cache.len() { + cache.get(self.pending_prunings).map(|r| r.hash.clone()) + } else { + self.get(self.pending_prunings)?.map(|r| r.hash) + }, + DeathRowQueue::Mem { death_rows, .. } => + death_rows.get(self.pending_prunings).map(|r| r.hash.clone()), + }; + Ok(res) } pub fn mem_used(&self) -> usize { 0 } + // Return the block number of the first block that not been pending pruned pub fn pending(&self) -> u64 { - self.pending_number + self.pending_prunings as u64 + self.base + self.pending_prunings as u64 } - pub fn have_block(&self, hash: &BlockHash) -> bool { - self.death_rows.iter().skip(self.pending_prunings).any(|r| r.hash == *hash) + fn is_empty(&self) -> bool { + self.queue.len() <= self.pending_prunings + } + + // Check if a block is in the pruning window and not be pruned yet + pub fn have_block(&self, hash: &BlockHash, number: u64) -> HaveBlock { + // if the queue is empty or the block number exceed the pruning window, we definitely + // do not have this block + if self.is_empty() || + number < self.pending() || + number >= self.base + self.queue.len() as u64 + { + return HaveBlock::NotHave + } + self.queue.have_block(hash, (number - self.base) as usize) + } + + fn get(&mut self, index: usize) -> Result>, Error> { + if index >= self.queue.len() { + return Ok(None) + } + match self.queue.get(self.base, index)? { + None => { + if matches!(self.queue, DeathRowQueue::DbBacked { .. }) && + // whether trying to get a pending canonicalize block which may not commit to the db yet + index >= self.queue.len() - self.pending_canonicalizations + { + trace!(target: "state-db", "Trying to get a pending canonicalize block that not commit to the db yet"); + Err(Error::StateDb(StateDbError::BlockUnavailable)) + } else { + // A block of the queue is missing, this may happen if `CommitSet` are commit to + // db concurrently and calling `apply_pending/revert_pending` out of order, this + // should not happen under current implementation but keeping it as a defensive + error!(target: "state-db", "Block record is missing from the pruning window, block number {}", self.base + index as u64); + Err(Error::StateDb(StateDbError::BlockMissing)) + } + }, + s => Ok(s), + } } /// Prune next block. Expects at least one block in the window. Adds changes to `commit`. - pub fn prune_one(&mut self, commit: &mut CommitSet) { - if let Some(pruned) = self.death_rows.get(self.pending_prunings) { + pub fn prune_one(&mut self, commit: &mut CommitSet) -> Result<(), Error> { + if let Some(pruned) = self.get(self.pending_prunings)? { trace!(target: "state-db", "Pruning {:?} ({} deleted)", pruned.hash, pruned.deleted.len()); - let index = self.pending_number + self.pending_prunings as u64; - commit.data.deleted.extend(pruned.deleted.iter().cloned()); + let index = self.base + self.pending_prunings as u64; + commit.data.deleted.extend(pruned.deleted.into_iter()); commit.meta.inserted.push((to_meta_key(LAST_PRUNED, &()), index.encode())); - commit.meta.deleted.push(pruned.journal_key.clone()); + commit + .meta + .deleted + .push(to_journal_key(self.base + self.pending_prunings as u64)); self.pending_prunings += 1; } else { warn!(target: "state-db", "Trying to prune when there's nothing to prune"); } + Ok(()) } /// Add a change set to the window. Creates a journal record and pushes it to `commit` - pub fn note_canonical(&mut self, hash: &BlockHash, commit: &mut CommitSet) { + pub fn note_canonical( + &mut self, + hash: &BlockHash, + number: u64, + commit: &mut CommitSet, + ) -> Result<(), Error> { + if self.base == 0 && self.queue.len() == 0 && number > 0 { + // assume that parent was canonicalized + self.base = number; + } else if (self.base + self.queue.len() as u64) != number { + return Err(Error::StateDb(StateDbError::InvalidBlockNumber)) + } trace!(target: "state-db", "Adding to pruning window: {:?} ({} inserted, {} deleted)", hash, commit.data.inserted.len(), commit.data.deleted.len()); - let inserted = if self.count_insertions { + let inserted = if matches!(self.queue, DeathRowQueue::Mem { .. }) { commit.data.inserted.iter().map(|(k, _)| k.clone()).collect() } else { Default::default() }; let deleted = ::std::mem::take(&mut commit.data.deleted); let journal_record = JournalRecord { hash: hash.clone(), inserted, deleted }; - let block = self.pending_number + self.death_rows.len() as u64; - let journal_key = to_journal_key(block); - commit.meta.inserted.push((journal_key.clone(), journal_record.encode())); - self.import( - &journal_record.hash, - journal_key, - journal_record.inserted.into_iter(), - journal_record.deleted, - ); + commit.meta.inserted.push((to_journal_key(number), journal_record.encode())); + self.queue.import(self.base, journal_record); self.pending_canonicalizations += 1; + Ok(()) } /// Apply all pending changes @@ -202,32 +544,22 @@ impl RefWindow { self.pending_canonicalizations = 0; for _ in 0..self.pending_prunings { let pruned = self - .death_rows - .pop_front() - .expect("pending_prunings is always < death_rows.len()"); + .queue + .pop_front(self.base) + // NOTE: `pop_front` should not return `MetaDb::Error` because blocks are visited + // by `RefWindow::prune_one` first then `RefWindow::apply_pending` and + // `DeathRowQueue::get` should load the blocks into cache already + .expect("block must loaded in cache thus no MetaDb::Error") + .expect("pending_prunings is always < queue.len()"); trace!(target: "state-db", "Applying pruning {:?} ({} deleted)", pruned.hash, pruned.deleted.len()); - if self.count_insertions { - for k in pruned.deleted.iter() { - self.death_index.remove(k); - } - } - self.pending_number += 1; + self.base += 1; } self.pending_prunings = 0; } /// Revert all pending changes pub fn revert_pending(&mut self) { - // Revert pending deletions. - // Note that pending insertions might cause some existing deletions to be removed from - // `death_index` We don't bother to track and revert that for now. This means that a few - // nodes might end up no being deleted in case transaction fails and `revert_pending` is - // called. - self.death_rows.truncate(self.death_rows.len() - self.pending_canonicalizations); - if self.count_insertions { - let new_max_block = self.death_rows.len() as u64 + self.pending_number; - self.death_index.retain(|_, block| *block < new_max_block); - } + self.queue.revert_recent_add(self.base, self.pending_canonicalizations); self.pending_canonicalizations = 0; self.pending_prunings = 0; } @@ -235,38 +567,45 @@ impl RefWindow { #[cfg(test)] mod tests { - use super::RefWindow; + use super::{to_journal_key, DeathRowQueue, HaveBlock, JournalRecord, RefWindow, LAST_PRUNED}; use crate::{ + noncanonical::LAST_CANONICAL, test::{make_commit, make_db, TestDb}, - CommitSet, + to_meta_key, CommitSet, Error, Hash, StateDbError, DEFAULT_MAX_BLOCK_CONSTRAINT, }; + use codec::Encode; use sp_core::H256; - fn check_journal(pruning: &RefWindow, db: &TestDb) { - let restored: RefWindow = RefWindow::new(db, pruning.count_insertions).unwrap(); - assert_eq!(pruning.pending_number, restored.pending_number); - assert_eq!(pruning.death_rows, restored.death_rows); - assert_eq!(pruning.death_index, restored.death_index); + fn check_journal(pruning: &RefWindow, db: &TestDb) { + let count_insertions = matches!(pruning.queue, DeathRowQueue::Mem { .. }); + let restored: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, count_insertions).unwrap(); + assert_eq!(pruning.base, restored.base); + assert_eq!(pruning.queue.get_mem_queue_state(), restored.queue.get_mem_queue_state()); } #[test] fn created_from_empty_db() { let db = make_db(&[]); - let pruning: RefWindow = RefWindow::new(&db, true).unwrap(); - assert_eq!(pruning.pending_number, 0); - assert!(pruning.death_rows.is_empty()); - assert!(pruning.death_index.is_empty()); + let pruning: RefWindow = + RefWindow::new(db, DEFAULT_MAX_BLOCK_CONSTRAINT, true).unwrap(); + assert_eq!(pruning.base, 0); + let (death_rows, death_index) = pruning.queue.get_mem_queue_state().unwrap(); + assert!(death_rows.is_empty()); + assert!(death_index.is_empty()); } #[test] fn prune_empty() { let db = make_db(&[]); - let mut pruning: RefWindow = RefWindow::new(&db, true).unwrap(); + let mut pruning: RefWindow = + RefWindow::new(db, DEFAULT_MAX_BLOCK_CONSTRAINT, true).unwrap(); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); - assert_eq!(pruning.pending_number, 0); - assert!(pruning.death_rows.is_empty()); - assert!(pruning.death_index.is_empty()); + pruning.prune_one(&mut commit).unwrap(); + assert_eq!(pruning.base, 0); + let (death_rows, death_index) = pruning.queue.get_mem_queue_state().unwrap(); + assert!(death_rows.is_empty()); + assert!(death_index.is_empty()); assert!(pruning.pending_prunings == 0); assert!(pruning.pending_canonicalizations == 0); } @@ -274,41 +613,45 @@ mod tests { #[test] fn prune_one() { let mut db = make_db(&[1, 2, 3]); - let mut pruning: RefWindow = RefWindow::new(&db, true).unwrap(); + let mut pruning: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, true).unwrap(); let mut commit = make_commit(&[4, 5], &[1, 3]); - let h = H256::random(); - pruning.note_canonical(&h, &mut commit); + let hash = H256::random(); + pruning.note_canonical(&hash, 0, &mut commit).unwrap(); db.commit(&commit); - assert!(pruning.have_block(&h)); + assert_eq!(pruning.have_block(&hash, 0), HaveBlock::Have); pruning.apply_pending(); - assert!(pruning.have_block(&h)); + assert_eq!(pruning.have_block(&hash, 0), HaveBlock::Have); assert!(commit.data.deleted.is_empty()); - assert_eq!(pruning.death_rows.len(), 1); - assert_eq!(pruning.death_index.len(), 2); + let (death_rows, death_index) = pruning.queue.get_mem_queue_state().unwrap(); + assert_eq!(death_rows.len(), 1); + assert_eq!(death_index.len(), 2); assert!(db.data_eq(&make_db(&[1, 2, 3, 4, 5]))); check_journal(&pruning, &db); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); - assert!(!pruning.have_block(&h)); + pruning.prune_one(&mut commit).unwrap(); + assert_eq!(pruning.have_block(&hash, 0), HaveBlock::NotHave); db.commit(&commit); pruning.apply_pending(); - assert!(!pruning.have_block(&h)); + assert_eq!(pruning.have_block(&hash, 0), HaveBlock::NotHave); assert!(db.data_eq(&make_db(&[2, 4, 5]))); - assert!(pruning.death_rows.is_empty()); - assert!(pruning.death_index.is_empty()); - assert_eq!(pruning.pending_number, 1); + let (death_rows, death_index) = pruning.queue.get_mem_queue_state().unwrap(); + assert!(death_rows.is_empty()); + assert!(death_index.is_empty()); + assert_eq!(pruning.base, 1); } #[test] fn prune_two() { let mut db = make_db(&[1, 2, 3]); - let mut pruning: RefWindow = RefWindow::new(&db, true).unwrap(); + let mut pruning: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, true).unwrap(); let mut commit = make_commit(&[4], &[1]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 0, &mut commit).unwrap(); db.commit(&commit); let mut commit = make_commit(&[5], &[2]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 1, &mut commit).unwrap(); db.commit(&commit); pruning.apply_pending(); assert!(db.data_eq(&make_db(&[1, 2, 3, 4, 5]))); @@ -316,53 +659,55 @@ mod tests { check_journal(&pruning, &db); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); pruning.apply_pending(); assert!(db.data_eq(&make_db(&[2, 3, 4, 5]))); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); pruning.apply_pending(); assert!(db.data_eq(&make_db(&[3, 4, 5]))); - assert_eq!(pruning.pending_number, 2); + assert_eq!(pruning.base, 2); } #[test] fn prune_two_pending() { let mut db = make_db(&[1, 2, 3]); - let mut pruning: RefWindow = RefWindow::new(&db, true).unwrap(); + let mut pruning: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, true).unwrap(); let mut commit = make_commit(&[4], &[1]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 0, &mut commit).unwrap(); db.commit(&commit); let mut commit = make_commit(&[5], &[2]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 1, &mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 2, 3, 4, 5]))); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[2, 3, 4, 5]))); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); pruning.apply_pending(); assert!(db.data_eq(&make_db(&[3, 4, 5]))); - assert_eq!(pruning.pending_number, 2); + assert_eq!(pruning.base, 2); } #[test] fn reinserted_survives() { let mut db = make_db(&[1, 2, 3]); - let mut pruning: RefWindow = RefWindow::new(&db, true).unwrap(); + let mut pruning: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, true).unwrap(); let mut commit = make_commit(&[], &[2]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 0, &mut commit).unwrap(); db.commit(&commit); let mut commit = make_commit(&[2], &[]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 1, &mut commit).unwrap(); db.commit(&commit); let mut commit = make_commit(&[], &[2]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 2, &mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 2, 3]))); pruning.apply_pending(); @@ -370,62 +715,64 @@ mod tests { check_journal(&pruning, &db); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 2, 3]))); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 2, 3]))); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 3]))); pruning.apply_pending(); - assert_eq!(pruning.pending_number, 3); + assert_eq!(pruning.base, 3); } #[test] fn reinserted_survive_pending() { let mut db = make_db(&[1, 2, 3]); - let mut pruning: RefWindow = RefWindow::new(&db, true).unwrap(); + let mut pruning: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, true).unwrap(); let mut commit = make_commit(&[], &[2]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 0, &mut commit).unwrap(); db.commit(&commit); let mut commit = make_commit(&[2], &[]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 1, &mut commit).unwrap(); db.commit(&commit); let mut commit = make_commit(&[], &[2]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 2, &mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 2, 3]))); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 2, 3]))); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 2, 3]))); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 3]))); pruning.apply_pending(); - assert_eq!(pruning.pending_number, 3); + assert_eq!(pruning.base, 3); } #[test] fn reinserted_ignores() { let mut db = make_db(&[1, 2, 3]); - let mut pruning: RefWindow = RefWindow::new(&db, false).unwrap(); + let mut pruning: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, false).unwrap(); let mut commit = make_commit(&[], &[2]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 0, &mut commit).unwrap(); db.commit(&commit); let mut commit = make_commit(&[2], &[]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 1, &mut commit).unwrap(); db.commit(&commit); let mut commit = make_commit(&[], &[2]); - pruning.note_canonical(&H256::random(), &mut commit); + pruning.note_canonical(&H256::random(), 2, &mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 2, 3]))); pruning.apply_pending(); @@ -433,9 +780,276 @@ mod tests { check_journal(&pruning, &db); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit); + pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 3]))); - assert!(pruning.death_index.is_empty()); + } + + fn push_last_canonicalized(block: u64, commit: &mut CommitSet) { + commit + .meta + .inserted + .push((to_meta_key(LAST_CANONICAL, &()), (block, block).encode())); + } + + fn push_last_pruned(block: u64, commit: &mut CommitSet) { + commit.meta.inserted.push((to_meta_key(LAST_PRUNED, &()), block.encode())); + } + + #[test] + fn init_db_backed_queue() { + let mut db = make_db(&[]); + let mut commit = CommitSet::default(); + + fn load_pruning_from_db(db: TestDb) -> (usize, u64) { + let pruning: RefWindow = + RefWindow::new(db, DEFAULT_MAX_BLOCK_CONSTRAINT, false).unwrap(); + let (cache, _) = pruning.queue.get_db_backed_queue_state().unwrap(); + (cache.len(), pruning.base) + } + + fn push_record(block: u64, commit: &mut CommitSet) { + commit + .meta + .inserted + .push((to_journal_key(block), JournalRecord::::default().encode())); + } + + // empty database + let (loaded_blocks, base) = load_pruning_from_db(db.clone()); + assert_eq!(loaded_blocks, 0); + assert_eq!(base, 0); + + // canonicalized the genesis block but no pruning + push_last_canonicalized(0, &mut commit); + push_record(0, &mut commit); + db.commit(&commit); + let (loaded_blocks, base) = load_pruning_from_db(db.clone()); + assert_eq!(loaded_blocks, 1); + assert_eq!(base, 0); + + // pruned the genesis block + push_last_pruned(0, &mut commit); + db.commit(&commit); + let (loaded_blocks, base) = load_pruning_from_db(db.clone()); + assert_eq!(loaded_blocks, 0); + assert_eq!(base, 1); + + // canonicalize more blocks + push_last_canonicalized(10, &mut commit); + for i in 1..=10 { + push_record(i, &mut commit); + } + db.commit(&commit); + let (loaded_blocks, base) = load_pruning_from_db(db.clone()); + assert_eq!(loaded_blocks, 10); + assert_eq!(base, 1); + + // pruned all blocks + push_last_pruned(10, &mut commit); + db.commit(&commit); + let (loaded_blocks, base) = load_pruning_from_db(db.clone()); + assert_eq!(loaded_blocks, 0); + assert_eq!(base, 11); + } + + #[test] + fn db_backed_queue() { + let mut db = make_db(&[]); + let mut pruning: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, false).unwrap(); + let cache_capacity = DEFAULT_MAX_BLOCK_CONSTRAINT as usize; + + // start as an empty queue + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(cache.len(), 0); + assert_eq!(uncached_blocks, 0); + + // import blocks + // queue size and content should match + for i in 0..(cache_capacity + 10) { + let mut commit = make_commit(&[], &[]); + pruning.note_canonical(&(i as u64), i as u64, &mut commit).unwrap(); + push_last_canonicalized(i as u64, &mut commit); + db.commit(&commit); + // block will fill in cache first + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + if i < cache_capacity { + assert_eq!(cache.len(), i + 1); + assert_eq!(uncached_blocks, 0); + } else { + assert_eq!(cache.len(), cache_capacity); + assert_eq!(uncached_blocks, i - cache_capacity + 1); + } + } + pruning.apply_pending(); + assert_eq!(pruning.queue.len(), cache_capacity + 10); + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(cache.len(), cache_capacity); + assert_eq!(uncached_blocks, 10); + for i in 0..cache_capacity { + assert_eq!(cache[i].hash, i as u64); + } + + // import a new block to the end of the queue + // won't keep the new block in memory + let mut commit = CommitSet::default(); + pruning + .note_canonical(&(cache_capacity as u64 + 10), cache_capacity as u64 + 10, &mut commit) + .unwrap(); + assert_eq!(pruning.queue.len(), cache_capacity + 11); + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(cache.len(), cache_capacity); + assert_eq!(uncached_blocks, 11); + + // revert the last add that no apply yet + // NOTE: do not commit the previous `CommitSet` to db + pruning.revert_pending(); + assert_eq!(pruning.queue.len(), cache_capacity + 10); + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(cache.len(), cache_capacity); + assert_eq!(uncached_blocks, 10); + + // remove one block from the start of the queue + // block is removed from the head of cache + let mut commit = CommitSet::default(); + pruning.prune_one(&mut commit).unwrap(); + db.commit(&commit); + pruning.apply_pending(); + assert_eq!(pruning.queue.len(), cache_capacity + 9); + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(cache.len(), cache_capacity - 1); + assert_eq!(uncached_blocks, 10); + for i in 0..(cache_capacity - 1) { + assert_eq!(cache[i].hash, (i + 1) as u64); + } + + // load a new queue from db + // `cache` is full again but the content of the queue should be the same + let pruning: RefWindow = + RefWindow::new(db, DEFAULT_MAX_BLOCK_CONSTRAINT, false).unwrap(); + assert_eq!(pruning.queue.len(), cache_capacity + 9); + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(cache.len(), cache_capacity); + assert_eq!(uncached_blocks, 9); + for i in 0..cache_capacity { + assert_eq!(cache[i].hash, (i + 1) as u64); + } + } + + #[test] + fn load_block_from_db() { + let mut db = make_db(&[]); + let mut pruning: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, false).unwrap(); + let cache_capacity = DEFAULT_MAX_BLOCK_CONSTRAINT as usize; + + // import blocks + for i in 0..(cache_capacity as u64 * 2 + 10) { + let mut commit = make_commit(&[], &[]); + pruning.note_canonical(&i, i, &mut commit).unwrap(); + push_last_canonicalized(i as u64, &mut commit); + db.commit(&commit); + } + + // the following operations won't triger loading block from db: + // - getting block in cache + // - getting block not in the queue + let index = cache_capacity; + assert_eq!( + pruning.queue.get(0, index - 1).unwrap().unwrap().hash, + cache_capacity as u64 - 1 + ); + assert_eq!(pruning.queue.get(0, cache_capacity * 2 + 10).unwrap(), None); + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(cache.len(), cache_capacity); + assert_eq!(uncached_blocks, cache_capacity + 10); + + // getting a block not in cache will triger loading block from db + assert_eq!(pruning.queue.get(0, index).unwrap().unwrap().hash, cache_capacity as u64); + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(cache.len(), cache_capacity * 2); + assert_eq!(uncached_blocks, 10); + + // clear all block loaded in cache + for _ in 0..cache_capacity * 2 { + let mut commit = CommitSet::default(); + pruning.prune_one(&mut commit).unwrap(); + db.commit(&commit); + } + pruning.apply_pending(); + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert!(cache.is_empty()); + assert_eq!(uncached_blocks, 10); + + // getting the hash of block that not in cache will also triger loading + // the remaining blocks from db + assert_eq!( + pruning.queue.get(pruning.base, 0).unwrap().unwrap().hash, + (cache_capacity * 2) as u64 + ); + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(cache.len(), 10); + assert_eq!(uncached_blocks, 0); + + // load a new queue from db + // `cache` should be the same + let pruning: RefWindow = + RefWindow::new(db, DEFAULT_MAX_BLOCK_CONSTRAINT, false).unwrap(); + assert_eq!(pruning.queue.len(), 10); + let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(cache.len(), 10); + assert_eq!(uncached_blocks, 0); + for i in 0..10 { + assert_eq!(cache[i].hash, (cache_capacity * 2 + i) as u64); + } + } + + #[test] + fn get_block_from_queue() { + let mut db = make_db(&[]); + let mut pruning: RefWindow = + RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, false).unwrap(); + let cache_capacity = DEFAULT_MAX_BLOCK_CONSTRAINT as u64; + + // import blocks and commit to db + let mut commit = make_commit(&[], &[]); + for i in 0..(cache_capacity + 10) { + pruning.note_canonical(&i, i, &mut commit).unwrap(); + } + db.commit(&commit); + + // import a block but not commit to db yet + let mut pending_commit = make_commit(&[], &[]); + let index = cache_capacity + 10; + pruning.note_canonical(&index, index, &mut pending_commit).unwrap(); + + let mut commit = make_commit(&[], &[]); + // prune blocks that had committed to db + for i in 0..(cache_capacity + 10) { + assert_eq!(pruning.next_hash().unwrap(), Some(i)); + pruning.prune_one(&mut commit).unwrap(); + } + // return `BlockUnavailable` for block that did not commit to db + assert_eq!( + pruning.next_hash().unwrap_err(), + Error::StateDb(StateDbError::BlockUnavailable) + ); + assert_eq!( + pruning.prune_one(&mut commit).unwrap_err(), + Error::StateDb(StateDbError::BlockUnavailable) + ); + // commit block to db and no error return + db.commit(&pending_commit); + assert_eq!(pruning.next_hash().unwrap(), Some(index)); + pruning.prune_one(&mut commit).unwrap(); + db.commit(&commit); + + // import a block and do not commit it to db before calling `apply_pending` + pruning + .note_canonical(&(index + 1), index + 1, &mut make_commit(&[], &[])) + .unwrap(); + pruning.apply_pending(); + assert_eq!(pruning.next_hash().unwrap_err(), Error::StateDb(StateDbError::BlockMissing)); } } diff --git a/client/state-db/src/test.rs b/client/state-db/src/test.rs index 9fb97036b2f24..314ec2902452a 100644 --- a/client/state-db/src/test.rs +++ b/client/state-db/src/test.rs @@ -20,10 +20,16 @@ use crate::{ChangeSet, CommitSet, DBValue, MetaDb, NodeDb}; use sp_core::H256; -use std::collections::HashMap; +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, +}; + +#[derive(Default, Debug, Clone)] +pub struct TestDb(Arc>); #[derive(Default, Debug, Clone, PartialEq, Eq)] -pub struct TestDb { +struct TestDbInner { pub data: HashMap, pub meta: HashMap, DBValue>, } @@ -32,7 +38,7 @@ impl MetaDb for TestDb { type Error = (); fn get_meta(&self, key: &[u8]) -> Result, ()> { - Ok(self.meta.get(key).cloned()) + Ok(self.0.read().unwrap().meta.get(key).cloned()) } } @@ -41,25 +47,29 @@ impl NodeDb for TestDb { type Key = H256; fn get(&self, key: &H256) -> Result, ()> { - Ok(self.data.get(key).cloned()) + Ok(self.0.read().unwrap().data.get(key).cloned()) } } impl TestDb { pub fn commit(&mut self, commit: &CommitSet) { - self.data.extend(commit.data.inserted.iter().cloned()); - self.meta.extend(commit.meta.inserted.iter().cloned()); + self.0.write().unwrap().data.extend(commit.data.inserted.iter().cloned()); + self.0.write().unwrap().meta.extend(commit.meta.inserted.iter().cloned()); for k in commit.data.deleted.iter() { - self.data.remove(k); + self.0.write().unwrap().data.remove(k); } - self.meta.extend(commit.meta.inserted.iter().cloned()); + self.0.write().unwrap().meta.extend(commit.meta.inserted.iter().cloned()); for k in commit.meta.deleted.iter() { - self.meta.remove(k); + self.0.write().unwrap().meta.remove(k); } } pub fn data_eq(&self, other: &TestDb) -> bool { - self.data == other.data + self.0.read().unwrap().data == other.0.read().unwrap().data + } + + pub fn meta_len(&self) -> usize { + self.0.read().unwrap().meta.len() } } @@ -78,11 +88,11 @@ pub fn make_commit(inserted: &[u64], deleted: &[u64]) -> CommitSet { } pub fn make_db(inserted: &[u64]) -> TestDb { - TestDb { + TestDb(Arc::new(RwLock::new(TestDbInner { data: inserted .iter() .map(|v| (H256::from_low_u64_be(*v), H256::from_low_u64_be(*v).as_bytes().to_vec())) .collect(), meta: Default::default(), - } + }))) } From ed12e6065c505a5225e2156985a75d1fb75fa0a4 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 1 Sep 2022 18:48:03 +0100 Subject: [PATCH 1112/1472] Weight v1.5 Follow Ups (#12155) * update api * update * remove unused * remove `one` api * fix unused * fmt * add saturating accrue * remove `Weight::new()` * use some macros * div makes no sense * Update weight_v2.rs * missed some * more patch * fixes * more fixes * more fix * more fix * Update frame/support/src/weights/weight_v2.rs * not needed * fix weight file --- .maintain/frame-weight-template.hbs | 4 +- bin/node-template/runtime/src/lib.rs | 2 +- bin/node/runtime/src/impls.rs | 14 +- bin/node/runtime/src/lib.rs | 2 +- docs/Upgrading-2.0-to-3.0.md | 4 +- frame/alliance/src/migration.rs | 2 +- frame/alliance/src/weights.rs | 104 ++-- frame/assets/src/weights.rs | 24 +- frame/babe/src/default_weights.rs | 10 +- frame/balances/src/tests.rs | 8 +- frame/benchmarking/src/weights.rs | 12 +- frame/bounties/src/weights.rs | 4 +- frame/child-bounties/src/weights.rs | 4 +- frame/collective/src/weights.rs | 88 ++-- frame/contracts/src/migration.rs | 6 +- frame/contracts/src/storage.rs | 3 +- frame/contracts/src/tests.rs | 2 +- frame/contracts/src/wasm/code_cache.rs | 2 +- frame/contracts/src/weights.rs | 448 +++++++++--------- frame/conviction-voting/src/weights.rs | 8 +- frame/democracy/src/lib.rs | 2 +- frame/democracy/src/weights.rs | 76 +-- .../election-provider-multi-phase/src/mock.rs | 2 +- .../src/weights.rs | 48 +- .../election-provider-support/src/weights.rs | 24 +- frame/elections-phragmen/src/migrations/v5.rs | 2 +- frame/elections-phragmen/src/weights.rs | 32 +- frame/examples/basic/src/weights.rs | 12 +- frame/executive/src/lib.rs | 4 +- frame/gilt/src/weights.rs | 16 +- frame/grandpa/src/default_weights.rs | 12 +- frame/identity/src/weights.rs | 96 ++-- frame/im-online/src/weights.rs | 8 +- frame/lottery/src/weights.rs | 4 +- frame/membership/src/weights.rs | 28 +- .../src/default_weights.rs | 2 +- frame/multisig/src/weights.rs | 56 +-- frame/nomination-pools/src/weights.rs | 16 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/offences/src/mock.rs | 2 +- frame/preimage/src/weights.rs | 12 +- frame/proxy/src/weights.rs | 56 +-- frame/ranked-collective/src/weights.rs | 16 +- frame/recovery/src/weights.rs | 20 +- frame/referenda/src/branch.rs | 6 +- frame/remark/src/weights.rs | 4 +- frame/scheduler/src/tests.rs | 5 +- frame/scheduler/src/weights.rs | 56 +-- frame/society/src/lib.rs | 2 +- frame/staking/src/tests.rs | 4 +- frame/staking/src/weights.rs | 68 +-- frame/state-trie-migration/src/lib.rs | 6 +- frame/state-trie-migration/src/weights.rs | 4 +- frame/sudo/src/tests.rs | 36 +- frame/support/src/dispatch.rs | 2 +- frame/support/src/migrations.rs | 2 +- frame/support/src/traits/hooks.rs | 18 +- frame/support/src/weights.rs | 2 +- frame/support/src/weights/block_weights.rs | 6 +- .../support/src/weights/extrinsic_weights.rs | 4 +- frame/support/src/weights/weight_v2.rs | 209 ++++---- frame/system/src/extensions/check_weight.rs | 8 +- frame/system/src/limits.rs | 6 +- frame/system/src/weights.rs | 16 +- frame/tips/src/weights.rs | 24 +- .../asset-tx-payment/src/tests.rs | 2 +- frame/transaction-payment/src/lib.rs | 2 +- frame/transaction-storage/src/weights.rs | 4 +- frame/treasury/src/lib.rs | 2 +- frame/treasury/src/weights.rs | 8 +- frame/uniques/src/weights.rs | 16 +- frame/utility/src/lib.rs | 10 +- frame/utility/src/tests.rs | 4 +- frame/utility/src/weights.rs | 12 +- frame/vesting/src/weights.rs | 64 +-- frame/whitelist/src/tests.rs | 2 +- frame/whitelist/src/weights.rs | 4 +- .../benchmarking-cli/src/overhead/README.md | 4 +- .../benchmarking-cli/src/overhead/weights.hbs | 2 +- .../benchmarking-cli/src/pallet/template.hbs | 2 +- 80 files changed, 965 insertions(+), 960 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index c6df85194ac99..5beeaf5f0521e 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -67,7 +67,7 @@ impl WeightInfo for SubstrateWeight { Weight::from_ref_time({{underscore benchmark.base_weight}} as RefTimeWeight) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).scalar_saturating_mul({{cw.name}} as RefTimeWeight)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight)) {{/each}} {{#if (ne benchmark.base_reads "0")}} .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as RefTimeWeight)) @@ -102,7 +102,7 @@ impl WeightInfo for () { Weight::from_ref_time({{underscore benchmark.base_weight}} as RefTimeWeight) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).scalar_saturating_mul({{cw.name}} as RefTimeWeight)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight)) {{/each}} {{#if (ne benchmark.base_reads "0")}} .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}} as RefTimeWeight)) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 7280336cada3d..e28a3bb2adb9d 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -138,7 +138,7 @@ parameter_types! { pub const Version: RuntimeVersion = VERSION; /// We allow for 2 seconds of compute with a 6 second average block time. pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights - ::with_sensible_defaults(2 * WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); + ::with_sensible_defaults(2u64 * WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); pub const SS58Prefix: u8 = 42; diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 4d58abc81d16d..0d0f864097af5 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -239,7 +239,7 @@ mod multiplier_tests { #[test] fn multiplier_cannot_go_below_limit() { // will not go any further below even if block is empty. - run_with_system_weight(Weight::new(), || { + run_with_system_weight(Weight::zero(), || { let next = runtime_multiplier_update(min_multiplier()); assert_eq!(next, min_multiplier()); }) @@ -257,7 +257,7 @@ mod multiplier_tests { // 1 < 0.00001 * k * 0.1875 // 10^9 / 1875 < k // k > 533_333 ~ 18,5 days. - run_with_system_weight(Weight::new(), || { + run_with_system_weight(Weight::zero(), || { // start from 1, the default. let mut fm = Multiplier::one(); let mut iterations: u64 = 0; @@ -419,20 +419,20 @@ mod multiplier_tests { #[test] fn weight_to_fee_should_not_overflow_on_large_weights() { let kb = Weight::from_ref_time(1024); - let mb = kb * kb; + let mb = 1024u64 * kb; let max_fm = Multiplier::saturating_from_integer(i128::MAX); // check that for all values it can compute, correctly. vec![ Weight::zero(), - Weight::one(), + Weight::from_ref_time(1), Weight::from_ref_time(10), Weight::from_ref_time(1000), kb, - 10 * kb, - 100 * kb, + 10u64 * kb, + 100u64 * kb, mb, - 10 * mb, + 10u64 * mb, Weight::from_ref_time(2147483647), Weight::from_ref_time(4294967295), BlockWeights::get().max_block / 2, diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8ef7e7852ad02..fa0f877c5938d 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -170,7 +170,7 @@ const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// by Operational extrinsics. const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); /// We allow for 2 seconds of compute with a 6 second average block time. -const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND.scalar_saturating_mul(2); +const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND.saturating_mul(2); parameter_types! { pub const BlockHashCount: BlockNumber = 2400; diff --git a/docs/Upgrading-2.0-to-3.0.md b/docs/Upgrading-2.0-to-3.0.md index f750c6dd5865b..bcba7d88047ce 100644 --- a/docs/Upgrading-2.0-to-3.0.md +++ b/docs/Upgrading-2.0-to-3.0.md @@ -100,12 +100,12 @@ And update the overall definition for weights on frame and a few related types a +/// by Operational extrinsics. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +/// We allow for 2 seconds of compute with a 6 second average block time. -+const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND; ++const MAXIMUM_BLOCK_WEIGHT: Weight = 2u64 * WEIGHT_PER_SECOND; + parameter_types! { pub const BlockHashCount: BlockNumber = 2400; - /// We allow for 2 seconds of compute with a 6 second average block time. -- pub const MaximumBlockWeight: Weight = 2 * WEIGHT_PER_SECOND; +- pub const MaximumBlockWeight: Weight = 2u64 * WEIGHT_PER_SECOND; - pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); - /// Assume 10% of weight for average on_initialize calls. - pub MaximumExtrinsicWeight: Weight = diff --git a/frame/alliance/src/migration.rs b/frame/alliance/src/migration.rs index 010603902f0fd..7e3df5219f25b 100644 --- a/frame/alliance/src/migration.rs +++ b/frame/alliance/src/migration.rs @@ -25,7 +25,7 @@ pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); /// Wrapper for all migrations of this pallet. pub fn migrate, I: 'static>() -> Weight { let onchain_version = Pallet::::on_chain_storage_version(); - let mut weight: Weight = Weight::new(); + let mut weight: Weight = Weight::zero(); if onchain_version < 1 { weight = weight.saturating_add(v0_to_v1::migrate::()); diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 8436b3ddbd530..2da5782f1bb4f 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -82,11 +82,11 @@ impl WeightInfo for SubstrateWeight { fn propose_proposed(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { Weight::from_ref_time(37_864_000 as RefTimeWeight) // Standard Error: 28_000 - .saturating_add(Weight::from_ref_time(69_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(69_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } @@ -97,7 +97,7 @@ impl WeightInfo for SubstrateWeight { fn vote(_x: u32, y: u32, ) -> Weight { Weight::from_ref_time(46_813_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(125_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(125_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -109,7 +109,7 @@ impl WeightInfo for SubstrateWeight { fn veto(p: u32, ) -> Weight { Weight::from_ref_time(35_316_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -124,11 +124,11 @@ impl WeightInfo for SubstrateWeight { fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { Weight::from_ref_time(36_245_000 as RefTimeWeight) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(336_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(336_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(109_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(109_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(178_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(178_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -144,13 +144,13 @@ impl WeightInfo for SubstrateWeight { fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { Weight::from_ref_time(48_088_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(194_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(194_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -166,9 +166,9 @@ impl WeightInfo for SubstrateWeight { fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { Weight::from_ref_time(43_374_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(101_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(101_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(182_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(182_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -185,9 +185,9 @@ impl WeightInfo for SubstrateWeight { fn close_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { Weight::from_ref_time(42_798_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -208,17 +208,17 @@ impl WeightInfo for SubstrateWeight { fn force_set_members(x: u32, y: u32, z: u32, p: u32, c: u32, m: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 221_000 - .saturating_add(Weight::from_ref_time(1_294_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_294_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) // Standard Error: 23_000 - .saturating_add(Weight::from_ref_time(231_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(231_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(9_371_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_371_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_673_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(11_673_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_581_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(11_581_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) @@ -306,9 +306,9 @@ impl WeightInfo for SubstrateWeight { fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { Weight::from_ref_time(359_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_376_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_376_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(112_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(112_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -319,9 +319,9 @@ impl WeightInfo for SubstrateWeight { fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 145_000 - .saturating_add(Weight::from_ref_time(20_932_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(20_932_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(3_649_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_649_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -341,11 +341,11 @@ impl WeightInfo for () { fn propose_proposed(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { Weight::from_ref_time(37_864_000 as RefTimeWeight) // Standard Error: 28_000 - .saturating_add(Weight::from_ref_time(69_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(69_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } @@ -356,7 +356,7 @@ impl WeightInfo for () { fn vote(_x: u32, y: u32, ) -> Weight { Weight::from_ref_time(46_813_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(125_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(125_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -368,7 +368,7 @@ impl WeightInfo for () { fn veto(p: u32, ) -> Weight { Weight::from_ref_time(35_316_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -383,11 +383,11 @@ impl WeightInfo for () { fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { Weight::from_ref_time(36_245_000 as RefTimeWeight) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(336_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(336_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(109_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(109_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(178_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(178_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -403,13 +403,13 @@ impl WeightInfo for () { fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { Weight::from_ref_time(48_088_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(194_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(194_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -425,9 +425,9 @@ impl WeightInfo for () { fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { Weight::from_ref_time(43_374_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(101_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(101_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(182_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(182_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -444,9 +444,9 @@ impl WeightInfo for () { fn close_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { Weight::from_ref_time(42_798_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -467,17 +467,17 @@ impl WeightInfo for () { fn force_set_members(x: u32, y: u32, z: u32, p: u32, c: u32, m: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 221_000 - .saturating_add(Weight::from_ref_time(1_294_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_294_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) // Standard Error: 23_000 - .saturating_add(Weight::from_ref_time(231_000 as RefTimeWeight).scalar_saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(231_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(9_371_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_371_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_673_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(11_673_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_581_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(11_581_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) @@ -565,9 +565,9 @@ impl WeightInfo for () { fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { Weight::from_ref_time(359_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_376_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_376_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(112_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(112_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -578,9 +578,9 @@ impl WeightInfo for () { fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 145_000 - .saturating_add(Weight::from_ref_time(20_932_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(20_932_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(3_649_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_649_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 971728df46c24..d59567e00ef69 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -92,11 +92,11 @@ impl WeightInfo for SubstrateWeight { fn destroy(c: u32, s: u32, a: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(19_333_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(19_333_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 375_000 - .saturating_add(Weight::from_ref_time(17_046_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_046_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -188,9 +188,9 @@ impl WeightInfo for SubstrateWeight { fn set_metadata(n: u32, s: u32, ) -> Weight { Weight::from_ref_time(32_395_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -206,7 +206,7 @@ impl WeightInfo for SubstrateWeight { fn force_set_metadata(_n: u32, s: u32, ) -> Weight { Weight::from_ref_time(19_586_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -277,11 +277,11 @@ impl WeightInfo for () { fn destroy(c: u32, s: u32, a: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(19_333_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(19_333_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 375_000 - .saturating_add(Weight::from_ref_time(17_046_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_046_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -373,9 +373,9 @@ impl WeightInfo for () { fn set_metadata(n: u32, s: u32, ) -> Weight { Weight::from_ref_time(32_395_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -391,7 +391,7 @@ impl WeightInfo for () { fn force_set_metadata(_n: u32, s: u32, ) -> Weight { Weight::from_ref_time(19_586_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } diff --git a/frame/babe/src/default_weights.rs b/frame/babe/src/default_weights.rs index cc1d11108b2e1..d3e0c9d044883 100644 --- a/frame/babe/src/default_weights.rs +++ b/frame/babe/src/default_weights.rs @@ -38,14 +38,14 @@ impl crate::WeightInfo for () { const MAX_NOMINATORS: u64 = 200; // checking membership proof - let ref_time_weight = (35 * WEIGHT_PER_MICROS) - .saturating_add((175 * WEIGHT_PER_NANOS).scalar_saturating_mul(validator_count)) + let ref_time_weight = (35u64 * WEIGHT_PER_MICROS) + .saturating_add((175u64 * WEIGHT_PER_NANOS).saturating_mul(validator_count)) .saturating_add(DbWeight::get().reads(5)) // check equivocation proof - .saturating_add(110 * WEIGHT_PER_MICROS) + .saturating_add(110u64 * WEIGHT_PER_MICROS) // report offence - .saturating_add(110 * WEIGHT_PER_MICROS) - .saturating_add(25 * WEIGHT_PER_MICROS * MAX_NOMINATORS) + .saturating_add(110u64 * WEIGHT_PER_MICROS) + .saturating_add(25u64 * WEIGHT_PER_MICROS * MAX_NOMINATORS) .saturating_add(DbWeight::get().reads(14 + 3 * MAX_NOMINATORS)) .saturating_add(DbWeight::get().writes(10 + 3 * MAX_NOMINATORS)); diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 6605af530563d..96bee9be1991c 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -188,14 +188,14 @@ macro_rules! decl_tests { ChargeTransactionPayment::from(1), &1, CALL, - &info_from_weight(Weight::one()), + &info_from_weight(Weight::from_ref_time(1)), 1, ).is_err()); assert_ok!( as SignedExtension>::pre_dispatch( ChargeTransactionPayment::from(0), &1, CALL, - &info_from_weight(Weight::one()), + &info_from_weight(Weight::from_ref_time(1)), 1, )); @@ -206,14 +206,14 @@ macro_rules! decl_tests { ChargeTransactionPayment::from(1), &1, CALL, - &info_from_weight(Weight::one()), + &info_from_weight(Weight::from_ref_time(1)), 1, ).is_err()); assert!( as SignedExtension>::pre_dispatch( ChargeTransactionPayment::from(0), &1, CALL, - &info_from_weight(Weight::one()), + &info_from_weight(Weight::from_ref_time(1)), 1, ).is_err()); }); diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index dc2ca26e1af02..9a40e488b7243 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -75,20 +75,20 @@ impl WeightInfo for SubstrateWeight { fn sr25519_verification(i: u32, ) -> Weight { Weight::from_ref_time(319_000 as RefTimeWeight) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(47_171_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(47_171_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_110_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_110_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(372_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(372_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } } @@ -113,20 +113,20 @@ impl WeightInfo for () { fn sr25519_verification(i: u32, ) -> Weight { Weight::from_ref_time(319_000 as RefTimeWeight) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(47_171_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(47_171_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_110_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_110_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(372_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(372_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 27a23cb4ffeae..0bb9a16d3cd8a 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -142,7 +142,7 @@ impl WeightInfo for SubstrateWeight { fn spend_funds(b: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(29_233_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(29_233_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -234,7 +234,7 @@ impl WeightInfo for () { fn spend_funds(b: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(29_233_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(29_233_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index c5d00d6ed0bd4..d806a676356b6 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -66,7 +66,7 @@ impl WeightInfo for SubstrateWeight { fn add_child_bounty(d: u32, ) -> Weight { Weight::from_ref_time(51_064_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } @@ -145,7 +145,7 @@ impl WeightInfo for () { fn add_child_bounty(d: u32, ) -> Weight { Weight::from_ref_time(51_064_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index a0cc64cc2408d..fcc0e7134f51c 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -66,11 +66,11 @@ impl WeightInfo for SubstrateWeight { fn set_members(m: u32, n: u32, p: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(10_280_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(10_280_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(126_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(126_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(13_310_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(13_310_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -80,9 +80,9 @@ impl WeightInfo for SubstrateWeight { fn execute(b: u32, m: u32, ) -> Weight { Weight::from_ref_time(16_819_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Council Members (r:1 w:0) @@ -90,9 +90,9 @@ impl WeightInfo for SubstrateWeight { fn propose_execute(b: u32, m: u32, ) -> Weight { Weight::from_ref_time(18_849_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) } // Storage: Council Members (r:1 w:0) @@ -103,11 +103,11 @@ impl WeightInfo for SubstrateWeight { fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { Weight::from_ref_time(22_204_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(8_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(180_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(180_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } @@ -116,7 +116,7 @@ impl WeightInfo for SubstrateWeight { fn vote(m: u32, ) -> Weight { Weight::from_ref_time(30_941_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -127,9 +127,9 @@ impl WeightInfo for SubstrateWeight { fn close_early_disapproved(m: u32, p: u32, ) -> Weight { Weight::from_ref_time(32_485_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(39_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(39_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -140,11 +140,11 @@ impl WeightInfo for SubstrateWeight { fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { Weight::from_ref_time(33_487_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(157_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(157_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -156,9 +156,9 @@ impl WeightInfo for SubstrateWeight { fn close_disapproved(m: u32, p: u32, ) -> Weight { Weight::from_ref_time(33_494_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(58_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(58_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -170,11 +170,11 @@ impl WeightInfo for SubstrateWeight { fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { Weight::from_ref_time(36_566_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(63_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(63_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -184,7 +184,7 @@ impl WeightInfo for SubstrateWeight { fn disapprove_proposal(p: u32, ) -> Weight { Weight::from_ref_time(20_159_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -199,11 +199,11 @@ impl WeightInfo for () { fn set_members(m: u32, n: u32, p: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(10_280_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(10_280_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(126_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(126_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(13_310_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(13_310_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) @@ -213,9 +213,9 @@ impl WeightInfo for () { fn execute(b: u32, m: u32, ) -> Weight { Weight::from_ref_time(16_819_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Council Members (r:1 w:0) @@ -223,9 +223,9 @@ impl WeightInfo for () { fn propose_execute(b: u32, m: u32, ) -> Weight { Weight::from_ref_time(18_849_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) } // Storage: Council Members (r:1 w:0) @@ -236,11 +236,11 @@ impl WeightInfo for () { fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { Weight::from_ref_time(22_204_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(8_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(180_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(180_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } @@ -249,7 +249,7 @@ impl WeightInfo for () { fn vote(m: u32, ) -> Weight { Weight::from_ref_time(30_941_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -260,9 +260,9 @@ impl WeightInfo for () { fn close_early_disapproved(m: u32, p: u32, ) -> Weight { Weight::from_ref_time(32_485_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(39_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(39_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -273,11 +273,11 @@ impl WeightInfo for () { fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { Weight::from_ref_time(33_487_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(157_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(157_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -289,9 +289,9 @@ impl WeightInfo for () { fn close_disapproved(m: u32, p: u32, ) -> Weight { Weight::from_ref_time(33_494_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(58_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(58_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -303,11 +303,11 @@ impl WeightInfo for () { fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { Weight::from_ref_time(36_566_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(63_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(63_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -317,7 +317,7 @@ impl WeightInfo for () { fn disapprove_proposal(p: u32, ) -> Weight { Weight::from_ref_time(20_159_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 9d90cf38269b1..0db285e81a91f 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -26,7 +26,7 @@ use sp_std::{marker::PhantomData, prelude::*}; /// Wrapper for all migrations of this pallet, based on `StorageVersion`. pub fn migrate() -> Weight { let version = StorageVersion::get::>(); - let mut weight = Weight::new(); + let mut weight = Weight::zero(); if version < 4 { weight = weight.saturating_add(v4::migrate::()); @@ -127,7 +127,7 @@ mod v5 { type DeletionQueue = StorageValue, Vec>; pub fn migrate() -> Weight { - let mut weight = Weight::new(); + let mut weight = Weight::zero(); >::translate(|_key, old: OldContractInfo| { weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); @@ -216,7 +216,7 @@ mod v6 { type OwnerInfoOf = StorageMap, Identity, CodeHash, OwnerInfo>; pub fn migrate() -> Weight { - let mut weight = Weight::new(); + let mut weight = Weight::zero(); >::translate(|_key, old: OldContractInfo| { weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 76e2d74f3d887..9c340b5c93deb 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -230,8 +230,7 @@ where let weight_per_key = (T::WeightInfo::on_initialize_per_trie_key(1) - T::WeightInfo::on_initialize_per_trie_key(0)) .ref_time(); - let decoding_weight = - weight_per_queue_item.scalar_saturating_mul(queue_len as RefTimeWeight); + let decoding_weight = weight_per_queue_item.saturating_mul(queue_len as RefTimeWeight); // `weight_per_key` being zero makes no sense and would constitute a failure to // benchmark properly. We opt for not removing any keys at all in this case. diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 3571434bb823b..f4fa6bb3d72db 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -264,7 +264,7 @@ impl RegisteredChainExtension for TempStorageExtension { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND); + frame_system::limits::BlockWeights::simple_max(2u64 * WEIGHT_PER_SECOND); pub static ExistentialDeposit: u64 = 1; } impl frame_system::Config for Test { diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 659caafa7f0b0..d482d5c4bbf3f 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -223,7 +223,7 @@ impl Token for CodeToken { Load(len) => { let computation = T::WeightInfo::call_with_code_per_byte(len) .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)); - let bandwidth = T::ContractAccessWeight::get().scalar_saturating_mul(len as u64); + let bandwidth = T::ContractAccessWeight::get().saturating_mul(len as u64); computation.max(bandwidth) }, }; diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 17be3c3da0138..daee41bc63f32 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -174,7 +174,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_per_trie_key(k: u32, ) -> Weight { Weight::from_ref_time(8_564_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) @@ -184,7 +184,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_per_queue_item(q: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_944_000 as RefTimeWeight).scalar_saturating_mul(q as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_944_000 as RefTimeWeight).saturating_mul(q as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -194,7 +194,7 @@ impl WeightInfo for SubstrateWeight { fn reinstrument(c: u32, ) -> Weight { Weight::from_ref_time(19_016_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -206,7 +206,7 @@ impl WeightInfo for SubstrateWeight { fn call_with_code_per_byte(c: u32, ) -> Weight { Weight::from_ref_time(205_194_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(53_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(53_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -222,9 +222,9 @@ impl WeightInfo for SubstrateWeight { fn instantiate_with_code(c: u32, s: u32, ) -> Weight { Weight::from_ref_time(288_487_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } @@ -238,7 +238,7 @@ impl WeightInfo for SubstrateWeight { fn instantiate(s: u32, ) -> Weight { Weight::from_ref_time(186_136_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) } @@ -258,7 +258,7 @@ impl WeightInfo for SubstrateWeight { fn upload_code(c: u32, ) -> Weight { Weight::from_ref_time(51_721_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -285,7 +285,7 @@ impl WeightInfo for SubstrateWeight { fn seal_caller(r: u32, ) -> Weight { Weight::from_ref_time(206_405_000 as RefTimeWeight) // Standard Error: 112_000 - .saturating_add(Weight::from_ref_time(40_987_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_987_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -297,7 +297,7 @@ impl WeightInfo for SubstrateWeight { fn seal_is_contract(r: u32, ) -> Weight { Weight::from_ref_time(106_220_000 as RefTimeWeight) // Standard Error: 710_000 - .saturating_add(Weight::from_ref_time(307_648_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(307_648_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -310,7 +310,7 @@ impl WeightInfo for SubstrateWeight { fn seal_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(104_498_000 as RefTimeWeight) // Standard Error: 633_000 - .saturating_add(Weight::from_ref_time(368_901_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(368_901_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -323,7 +323,7 @@ impl WeightInfo for SubstrateWeight { fn seal_own_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(208_696_000 as RefTimeWeight) // Standard Error: 101_000 - .saturating_add(Weight::from_ref_time(44_445_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(44_445_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -335,7 +335,7 @@ impl WeightInfo for SubstrateWeight { fn seal_caller_is_origin(r: u32, ) -> Weight { Weight::from_ref_time(205_612_000 as RefTimeWeight) // Standard Error: 68_000 - .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -347,7 +347,7 @@ impl WeightInfo for SubstrateWeight { fn seal_address(r: u32, ) -> Weight { Weight::from_ref_time(206_947_000 as RefTimeWeight) // Standard Error: 107_000 - .saturating_add(Weight::from_ref_time(40_789_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_789_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -359,7 +359,7 @@ impl WeightInfo for SubstrateWeight { fn seal_gas_left(r: u32, ) -> Weight { Weight::from_ref_time(208_692_000 as RefTimeWeight) // Standard Error: 109_000 - .saturating_add(Weight::from_ref_time(40_600_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_600_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -371,7 +371,7 @@ impl WeightInfo for SubstrateWeight { fn seal_balance(r: u32, ) -> Weight { Weight::from_ref_time(209_811_000 as RefTimeWeight) // Standard Error: 208_000 - .saturating_add(Weight::from_ref_time(116_831_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(116_831_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -383,7 +383,7 @@ impl WeightInfo for SubstrateWeight { fn seal_value_transferred(r: u32, ) -> Weight { Weight::from_ref_time(207_406_000 as RefTimeWeight) // Standard Error: 117_000 - .saturating_add(Weight::from_ref_time(40_702_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_702_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -395,7 +395,7 @@ impl WeightInfo for SubstrateWeight { fn seal_minimum_balance(r: u32, ) -> Weight { Weight::from_ref_time(209_260_000 as RefTimeWeight) // Standard Error: 130_000 - .saturating_add(Weight::from_ref_time(40_479_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_479_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -407,7 +407,7 @@ impl WeightInfo for SubstrateWeight { fn seal_block_number(r: u32, ) -> Weight { Weight::from_ref_time(206_448_000 as RefTimeWeight) // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(40_134_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_134_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -419,7 +419,7 @@ impl WeightInfo for SubstrateWeight { fn seal_now(r: u32, ) -> Weight { Weight::from_ref_time(206_969_000 as RefTimeWeight) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(40_251_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_251_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -432,7 +432,7 @@ impl WeightInfo for SubstrateWeight { fn seal_weight_to_fee(r: u32, ) -> Weight { Weight::from_ref_time(211_611_000 as RefTimeWeight) // Standard Error: 175_000 - .saturating_add(Weight::from_ref_time(98_675_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(98_675_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -444,7 +444,7 @@ impl WeightInfo for SubstrateWeight { fn seal_gas(r: u32, ) -> Weight { Weight::from_ref_time(134_484_000 as RefTimeWeight) // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(19_329_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(19_329_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -456,7 +456,7 @@ impl WeightInfo for SubstrateWeight { fn seal_input(r: u32, ) -> Weight { Weight::from_ref_time(208_556_000 as RefTimeWeight) // Standard Error: 125_000 - .saturating_add(Weight::from_ref_time(40_328_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_328_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -468,7 +468,7 @@ impl WeightInfo for SubstrateWeight { fn seal_input_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(268_886_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_627_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_627_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -490,7 +490,7 @@ impl WeightInfo for SubstrateWeight { fn seal_return_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(204_258_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(183_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(183_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -504,7 +504,7 @@ impl WeightInfo for SubstrateWeight { fn seal_terminate(r: u32, ) -> Weight { Weight::from_ref_time(206_625_000 as RefTimeWeight) // Standard Error: 672_000 - .saturating_add(Weight::from_ref_time(59_377_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(59_377_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((4 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -519,7 +519,7 @@ impl WeightInfo for SubstrateWeight { fn seal_random(r: u32, ) -> Weight { Weight::from_ref_time(208_866_000 as RefTimeWeight) // Standard Error: 164_000 - .saturating_add(Weight::from_ref_time(133_438_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(133_438_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -531,7 +531,7 @@ impl WeightInfo for SubstrateWeight { fn seal_deposit_event(r: u32, ) -> Weight { Weight::from_ref_time(220_860_000 as RefTimeWeight) // Standard Error: 209_000 - .saturating_add(Weight::from_ref_time(239_951_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(239_951_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -545,9 +545,9 @@ impl WeightInfo for SubstrateWeight { fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { Weight::from_ref_time(439_782_000 as RefTimeWeight) // Standard Error: 1_643_000 - .saturating_add(Weight::from_ref_time(264_687_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(264_687_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 323_000 - .saturating_add(Weight::from_ref_time(67_636_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(67_636_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -561,7 +561,7 @@ impl WeightInfo for SubstrateWeight { fn seal_debug_message(r: u32, ) -> Weight { Weight::from_ref_time(140_280_000 as RefTimeWeight) // Standard Error: 82_000 - .saturating_add(Weight::from_ref_time(32_717_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(32_717_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -570,7 +570,7 @@ impl WeightInfo for SubstrateWeight { fn seal_set_storage(r: u32, ) -> Weight { Weight::from_ref_time(161_247_000 as RefTimeWeight) // Standard Error: 883_000 - .saturating_add(Weight::from_ref_time(423_997_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(423_997_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -581,7 +581,7 @@ impl WeightInfo for SubstrateWeight { fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { Weight::from_ref_time(529_247_000 as RefTimeWeight) // Standard Error: 2_745_000 - .saturating_add(Weight::from_ref_time(85_282_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(85_282_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(53 as RefTimeWeight)) @@ -592,7 +592,7 @@ impl WeightInfo for SubstrateWeight { fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { Weight::from_ref_time(529_812_000 as RefTimeWeight) // Standard Error: 2_513_000 - .saturating_add(Weight::from_ref_time(74_554_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(74_554_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(53 as RefTimeWeight)) @@ -603,7 +603,7 @@ impl WeightInfo for SubstrateWeight { fn seal_clear_storage(r: u32, ) -> Weight { Weight::from_ref_time(184_803_000 as RefTimeWeight) // Standard Error: 733_000 - .saturating_add(Weight::from_ref_time(404_933_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(404_933_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -614,7 +614,7 @@ impl WeightInfo for SubstrateWeight { fn seal_clear_storage_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(500_958_000 as RefTimeWeight) // Standard Error: 2_980_000 - .saturating_add(Weight::from_ref_time(75_996_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(75_996_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(52 as RefTimeWeight)) @@ -625,7 +625,7 @@ impl WeightInfo for SubstrateWeight { fn seal_get_storage(r: u32, ) -> Weight { Weight::from_ref_time(177_682_000 as RefTimeWeight) // Standard Error: 743_000 - .saturating_add(Weight::from_ref_time(338_172_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(338_172_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -635,7 +635,7 @@ impl WeightInfo for SubstrateWeight { fn seal_get_storage_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(465_285_000 as RefTimeWeight) // Standard Error: 2_599_000 - .saturating_add(Weight::from_ref_time(155_106_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(155_106_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -645,7 +645,7 @@ impl WeightInfo for SubstrateWeight { fn seal_contains_storage(r: u32, ) -> Weight { Weight::from_ref_time(179_118_000 as RefTimeWeight) // Standard Error: 572_000 - .saturating_add(Weight::from_ref_time(311_083_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(311_083_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -655,7 +655,7 @@ impl WeightInfo for SubstrateWeight { fn seal_contains_storage_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(423_056_000 as RefTimeWeight) // Standard Error: 2_037_000 - .saturating_add(Weight::from_ref_time(69_665_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(69_665_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(54 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -665,7 +665,7 @@ impl WeightInfo for SubstrateWeight { fn seal_take_storage(r: u32, ) -> Weight { Weight::from_ref_time(188_884_000 as RefTimeWeight) // Standard Error: 761_000 - .saturating_add(Weight::from_ref_time(432_781_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(432_781_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -676,7 +676,7 @@ impl WeightInfo for SubstrateWeight { fn seal_take_storage_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(532_408_000 as RefTimeWeight) // Standard Error: 3_348_000 - .saturating_add(Weight::from_ref_time(164_943_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(164_943_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(53 as RefTimeWeight)) @@ -690,7 +690,7 @@ impl WeightInfo for SubstrateWeight { fn seal_transfer(r: u32, ) -> Weight { Weight::from_ref_time(127_181_000 as RefTimeWeight) // Standard Error: 1_495_000 - .saturating_add(Weight::from_ref_time(1_500_589_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_500_589_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -704,7 +704,7 @@ impl WeightInfo for SubstrateWeight { fn seal_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_803_000 - .saturating_add(Weight::from_ref_time(14_860_909_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(14_860_909_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -718,7 +718,7 @@ impl WeightInfo for SubstrateWeight { fn seal_delegate_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 6_045_000 - .saturating_add(Weight::from_ref_time(14_797_140_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(14_797_140_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -731,9 +731,9 @@ impl WeightInfo for SubstrateWeight { fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { Weight::from_ref_time(9_196_444_000 as RefTimeWeight) // Standard Error: 20_486_000 - .saturating_add(Weight::from_ref_time(1_458_153_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_458_153_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(9_718_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_718_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(85 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((81 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(81 as RefTimeWeight)) @@ -749,7 +749,7 @@ impl WeightInfo for SubstrateWeight { fn seal_instantiate(r: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 36_253_000 - .saturating_add(Weight::from_ref_time(21_201_529_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(21_201_529_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((320 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) @@ -766,9 +766,9 @@ impl WeightInfo for SubstrateWeight { fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { Weight::from_ref_time(12_282_498_000 as RefTimeWeight) // Standard Error: 48_112_000 - .saturating_add(Weight::from_ref_time(720_795_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(720_795_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 22_000 - .saturating_add(Weight::from_ref_time(124_274_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_274_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(167 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(165 as RefTimeWeight)) @@ -782,7 +782,7 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_sha2_256(r: u32, ) -> Weight { Weight::from_ref_time(203_959_000 as RefTimeWeight) // Standard Error: 142_000 - .saturating_add(Weight::from_ref_time(61_311_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(61_311_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -794,7 +794,7 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(349_915_000 as RefTimeWeight) // Standard Error: 40_000 - .saturating_add(Weight::from_ref_time(320_652_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(320_652_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -806,7 +806,7 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_keccak_256(r: u32, ) -> Weight { Weight::from_ref_time(209_219_000 as RefTimeWeight) // Standard Error: 157_000 - .saturating_add(Weight::from_ref_time(73_728_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_728_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -818,7 +818,7 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(208_860_000 as RefTimeWeight) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(245_718_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(245_718_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -830,7 +830,7 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_blake2_256(r: u32, ) -> Weight { Weight::from_ref_time(206_165_000 as RefTimeWeight) // Standard Error: 138_000 - .saturating_add(Weight::from_ref_time(51_644_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_644_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -842,7 +842,7 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(255_955_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_090_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_090_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -854,7 +854,7 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_blake2_128(r: u32, ) -> Weight { Weight::from_ref_time(208_153_000 as RefTimeWeight) // Standard Error: 140_000 - .saturating_add(Weight::from_ref_time(51_264_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_264_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -866,7 +866,7 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(278_368_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_006_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_006_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -878,7 +878,7 @@ impl WeightInfo for SubstrateWeight { fn seal_ecdsa_recover(r: u32, ) -> Weight { Weight::from_ref_time(331_955_000 as RefTimeWeight) // Standard Error: 1_155_000 - .saturating_add(Weight::from_ref_time(3_069_955_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_069_955_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -890,7 +890,7 @@ impl WeightInfo for SubstrateWeight { fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { Weight::from_ref_time(207_838_000 as RefTimeWeight) // Standard Error: 783_000 - .saturating_add(Weight::from_ref_time(2_058_503_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_058_503_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -903,7 +903,7 @@ impl WeightInfo for SubstrateWeight { fn seal_set_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_567_000 - .saturating_add(Weight::from_ref_time(774_380_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(774_380_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } @@ -911,307 +911,307 @@ impl WeightInfo for SubstrateWeight { fn instr_i64const(r: u32, ) -> Weight { Weight::from_ref_time(73_955_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(612_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(612_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { Weight::from_ref_time(74_057_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { Weight::from_ref_time(74_137_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { Weight::from_ref_time(73_844_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_773_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_773_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { Weight::from_ref_time(73_979_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_952_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_952_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { Weight::from_ref_time(73_924_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(941_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(941_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { Weight::from_ref_time(73_574_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_439_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_439_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { Weight::from_ref_time(73_343_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_603_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_603_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { Weight::from_ref_time(76_267_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { Weight::from_ref_time(74_877_000 as RefTimeWeight) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(7_144_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(7_144_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { Weight::from_ref_time(88_665_000 as RefTimeWeight) // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(9_142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { Weight::from_ref_time(98_600_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(469_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(469_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { Weight::from_ref_time(74_555_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(624_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(624_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { Weight::from_ref_time(74_329_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(688_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(688_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { Weight::from_ref_time(74_612_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(909_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(909_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { Weight::from_ref_time(76_906_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_192_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_192_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { Weight::from_ref_time(76_979_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_361_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_361_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { Weight::from_ref_time(74_370_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(661_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(661_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { Weight::from_ref_time(73_584_000 as RefTimeWeight) // Standard Error: 353_000 - .saturating_add(Weight::from_ref_time(187_114_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(187_114_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { Weight::from_ref_time(74_206_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(884_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(884_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { Weight::from_ref_time(73_992_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(893_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(893_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { Weight::from_ref_time(73_985_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(891_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(891_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { Weight::from_ref_time(74_117_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(901_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(901_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { Weight::from_ref_time(73_981_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(866_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(866_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { Weight::from_ref_time(74_104_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { Weight::from_ref_time(74_293_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(878_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(878_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { Weight::from_ref_time(74_055_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { Weight::from_ref_time(73_710_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { Weight::from_ref_time(73_917_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_355_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_355_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { Weight::from_ref_time(74_048_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { Weight::from_ref_time(74_029_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_349_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_349_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { Weight::from_ref_time(74_267_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { Weight::from_ref_time(73_952_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { Weight::from_ref_time(73_851_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_368_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_368_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { Weight::from_ref_time(74_034_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_348_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_348_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { Weight::from_ref_time(73_979_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { Weight::from_ref_time(74_000_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_328_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_328_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { Weight::from_ref_time(73_883_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_331_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_331_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { Weight::from_ref_time(74_216_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { Weight::from_ref_time(73_989_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_998_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_998_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { Weight::from_ref_time(73_857_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_073_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_073_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { Weight::from_ref_time(73_801_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_027_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_027_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { Weight::from_ref_time(74_130_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_064_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_064_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { Weight::from_ref_time(74_071_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_327_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_327_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { Weight::from_ref_time(74_201_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_330_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_330_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { Weight::from_ref_time(74_241_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_321_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_321_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { Weight::from_ref_time(74_331_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_347_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_347_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { Weight::from_ref_time(73_674_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_359_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_359_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { Weight::from_ref_time(73_807_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { Weight::from_ref_time(73_725_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { Weight::from_ref_time(73_755_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } } @@ -1227,7 +1227,7 @@ impl WeightInfo for () { fn on_initialize_per_trie_key(k: u32, ) -> Weight { Weight::from_ref_time(8_564_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) @@ -1237,7 +1237,7 @@ impl WeightInfo for () { fn on_initialize_per_queue_item(q: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_944_000 as RefTimeWeight).scalar_saturating_mul(q as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_944_000 as RefTimeWeight).saturating_mul(q as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1247,7 +1247,7 @@ impl WeightInfo for () { fn reinstrument(c: u32, ) -> Weight { Weight::from_ref_time(19_016_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1259,7 +1259,7 @@ impl WeightInfo for () { fn call_with_code_per_byte(c: u32, ) -> Weight { Weight::from_ref_time(205_194_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(53_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(53_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -1275,9 +1275,9 @@ impl WeightInfo for () { fn instantiate_with_code(c: u32, s: u32, ) -> Weight { Weight::from_ref_time(288_487_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } @@ -1291,7 +1291,7 @@ impl WeightInfo for () { fn instantiate(s: u32, ) -> Weight { Weight::from_ref_time(186_136_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) } @@ -1311,7 +1311,7 @@ impl WeightInfo for () { fn upload_code(c: u32, ) -> Weight { Weight::from_ref_time(51_721_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -1338,7 +1338,7 @@ impl WeightInfo for () { fn seal_caller(r: u32, ) -> Weight { Weight::from_ref_time(206_405_000 as RefTimeWeight) // Standard Error: 112_000 - .saturating_add(Weight::from_ref_time(40_987_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_987_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1350,7 +1350,7 @@ impl WeightInfo for () { fn seal_is_contract(r: u32, ) -> Weight { Weight::from_ref_time(106_220_000 as RefTimeWeight) // Standard Error: 710_000 - .saturating_add(Weight::from_ref_time(307_648_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(307_648_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -1363,7 +1363,7 @@ impl WeightInfo for () { fn seal_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(104_498_000 as RefTimeWeight) // Standard Error: 633_000 - .saturating_add(Weight::from_ref_time(368_901_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(368_901_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -1376,7 +1376,7 @@ impl WeightInfo for () { fn seal_own_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(208_696_000 as RefTimeWeight) // Standard Error: 101_000 - .saturating_add(Weight::from_ref_time(44_445_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(44_445_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1388,7 +1388,7 @@ impl WeightInfo for () { fn seal_caller_is_origin(r: u32, ) -> Weight { Weight::from_ref_time(205_612_000 as RefTimeWeight) // Standard Error: 68_000 - .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1400,7 +1400,7 @@ impl WeightInfo for () { fn seal_address(r: u32, ) -> Weight { Weight::from_ref_time(206_947_000 as RefTimeWeight) // Standard Error: 107_000 - .saturating_add(Weight::from_ref_time(40_789_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_789_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1412,7 +1412,7 @@ impl WeightInfo for () { fn seal_gas_left(r: u32, ) -> Weight { Weight::from_ref_time(208_692_000 as RefTimeWeight) // Standard Error: 109_000 - .saturating_add(Weight::from_ref_time(40_600_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_600_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1424,7 +1424,7 @@ impl WeightInfo for () { fn seal_balance(r: u32, ) -> Weight { Weight::from_ref_time(209_811_000 as RefTimeWeight) // Standard Error: 208_000 - .saturating_add(Weight::from_ref_time(116_831_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(116_831_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1436,7 +1436,7 @@ impl WeightInfo for () { fn seal_value_transferred(r: u32, ) -> Weight { Weight::from_ref_time(207_406_000 as RefTimeWeight) // Standard Error: 117_000 - .saturating_add(Weight::from_ref_time(40_702_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_702_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1448,7 +1448,7 @@ impl WeightInfo for () { fn seal_minimum_balance(r: u32, ) -> Weight { Weight::from_ref_time(209_260_000 as RefTimeWeight) // Standard Error: 130_000 - .saturating_add(Weight::from_ref_time(40_479_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_479_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1460,7 +1460,7 @@ impl WeightInfo for () { fn seal_block_number(r: u32, ) -> Weight { Weight::from_ref_time(206_448_000 as RefTimeWeight) // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(40_134_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_134_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1472,7 +1472,7 @@ impl WeightInfo for () { fn seal_now(r: u32, ) -> Weight { Weight::from_ref_time(206_969_000 as RefTimeWeight) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(40_251_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_251_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1485,7 +1485,7 @@ impl WeightInfo for () { fn seal_weight_to_fee(r: u32, ) -> Weight { Weight::from_ref_time(211_611_000 as RefTimeWeight) // Standard Error: 175_000 - .saturating_add(Weight::from_ref_time(98_675_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(98_675_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1497,7 +1497,7 @@ impl WeightInfo for () { fn seal_gas(r: u32, ) -> Weight { Weight::from_ref_time(134_484_000 as RefTimeWeight) // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(19_329_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(19_329_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1509,7 +1509,7 @@ impl WeightInfo for () { fn seal_input(r: u32, ) -> Weight { Weight::from_ref_time(208_556_000 as RefTimeWeight) // Standard Error: 125_000 - .saturating_add(Weight::from_ref_time(40_328_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_328_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1521,7 +1521,7 @@ impl WeightInfo for () { fn seal_input_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(268_886_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_627_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_627_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1543,7 +1543,7 @@ impl WeightInfo for () { fn seal_return_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(204_258_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(183_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(183_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1557,7 +1557,7 @@ impl WeightInfo for () { fn seal_terminate(r: u32, ) -> Weight { Weight::from_ref_time(206_625_000 as RefTimeWeight) // Standard Error: 672_000 - .saturating_add(Weight::from_ref_time(59_377_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(59_377_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((4 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -1572,7 +1572,7 @@ impl WeightInfo for () { fn seal_random(r: u32, ) -> Weight { Weight::from_ref_time(208_866_000 as RefTimeWeight) // Standard Error: 164_000 - .saturating_add(Weight::from_ref_time(133_438_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(133_438_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1584,7 +1584,7 @@ impl WeightInfo for () { fn seal_deposit_event(r: u32, ) -> Weight { Weight::from_ref_time(220_860_000 as RefTimeWeight) // Standard Error: 209_000 - .saturating_add(Weight::from_ref_time(239_951_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(239_951_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1598,9 +1598,9 @@ impl WeightInfo for () { fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { Weight::from_ref_time(439_782_000 as RefTimeWeight) // Standard Error: 1_643_000 - .saturating_add(Weight::from_ref_time(264_687_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(264_687_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 323_000 - .saturating_add(Weight::from_ref_time(67_636_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(67_636_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -1614,7 +1614,7 @@ impl WeightInfo for () { fn seal_debug_message(r: u32, ) -> Weight { Weight::from_ref_time(140_280_000 as RefTimeWeight) // Standard Error: 82_000 - .saturating_add(Weight::from_ref_time(32_717_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(32_717_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1623,7 +1623,7 @@ impl WeightInfo for () { fn seal_set_storage(r: u32, ) -> Weight { Weight::from_ref_time(161_247_000 as RefTimeWeight) // Standard Error: 883_000 - .saturating_add(Weight::from_ref_time(423_997_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(423_997_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -1634,7 +1634,7 @@ impl WeightInfo for () { fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { Weight::from_ref_time(529_247_000 as RefTimeWeight) // Standard Error: 2_745_000 - .saturating_add(Weight::from_ref_time(85_282_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(85_282_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(53 as RefTimeWeight)) @@ -1645,7 +1645,7 @@ impl WeightInfo for () { fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { Weight::from_ref_time(529_812_000 as RefTimeWeight) // Standard Error: 2_513_000 - .saturating_add(Weight::from_ref_time(74_554_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(74_554_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(53 as RefTimeWeight)) @@ -1656,7 +1656,7 @@ impl WeightInfo for () { fn seal_clear_storage(r: u32, ) -> Weight { Weight::from_ref_time(184_803_000 as RefTimeWeight) // Standard Error: 733_000 - .saturating_add(Weight::from_ref_time(404_933_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(404_933_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) @@ -1667,7 +1667,7 @@ impl WeightInfo for () { fn seal_clear_storage_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(500_958_000 as RefTimeWeight) // Standard Error: 2_980_000 - .saturating_add(Weight::from_ref_time(75_996_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(75_996_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(52 as RefTimeWeight)) @@ -1678,7 +1678,7 @@ impl WeightInfo for () { fn seal_get_storage(r: u32, ) -> Weight { Weight::from_ref_time(177_682_000 as RefTimeWeight) // Standard Error: 743_000 - .saturating_add(Weight::from_ref_time(338_172_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(338_172_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -1688,7 +1688,7 @@ impl WeightInfo for () { fn seal_get_storage_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(465_285_000 as RefTimeWeight) // Standard Error: 2_599_000 - .saturating_add(Weight::from_ref_time(155_106_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(155_106_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -1698,7 +1698,7 @@ impl WeightInfo for () { fn seal_contains_storage(r: u32, ) -> Weight { Weight::from_ref_time(179_118_000 as RefTimeWeight) // Standard Error: 572_000 - .saturating_add(Weight::from_ref_time(311_083_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(311_083_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -1708,7 +1708,7 @@ impl WeightInfo for () { fn seal_contains_storage_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(423_056_000 as RefTimeWeight) // Standard Error: 2_037_000 - .saturating_add(Weight::from_ref_time(69_665_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(69_665_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(54 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -1718,7 +1718,7 @@ impl WeightInfo for () { fn seal_take_storage(r: u32, ) -> Weight { Weight::from_ref_time(188_884_000 as RefTimeWeight) // Standard Error: 761_000 - .saturating_add(Weight::from_ref_time(432_781_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(432_781_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) @@ -1729,7 +1729,7 @@ impl WeightInfo for () { fn seal_take_storage_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(532_408_000 as RefTimeWeight) // Standard Error: 3_348_000 - .saturating_add(Weight::from_ref_time(164_943_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(164_943_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(53 as RefTimeWeight)) @@ -1743,7 +1743,7 @@ impl WeightInfo for () { fn seal_transfer(r: u32, ) -> Weight { Weight::from_ref_time(127_181_000 as RefTimeWeight) // Standard Error: 1_495_000 - .saturating_add(Weight::from_ref_time(1_500_589_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_500_589_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) @@ -1757,7 +1757,7 @@ impl WeightInfo for () { fn seal_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_803_000 - .saturating_add(Weight::from_ref_time(14_860_909_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(14_860_909_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -1771,7 +1771,7 @@ impl WeightInfo for () { fn seal_delegate_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 6_045_000 - .saturating_add(Weight::from_ref_time(14_797_140_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(14_797_140_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1784,9 +1784,9 @@ impl WeightInfo for () { fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { Weight::from_ref_time(9_196_444_000 as RefTimeWeight) // Standard Error: 20_486_000 - .saturating_add(Weight::from_ref_time(1_458_153_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_458_153_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(9_718_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_718_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(85 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((81 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(81 as RefTimeWeight)) @@ -1802,7 +1802,7 @@ impl WeightInfo for () { fn seal_instantiate(r: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 36_253_000 - .saturating_add(Weight::from_ref_time(21_201_529_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(21_201_529_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((320 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) @@ -1819,9 +1819,9 @@ impl WeightInfo for () { fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { Weight::from_ref_time(12_282_498_000 as RefTimeWeight) // Standard Error: 48_112_000 - .saturating_add(Weight::from_ref_time(720_795_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(720_795_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 22_000 - .saturating_add(Weight::from_ref_time(124_274_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_274_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(167 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(165 as RefTimeWeight)) @@ -1835,7 +1835,7 @@ impl WeightInfo for () { fn seal_hash_sha2_256(r: u32, ) -> Weight { Weight::from_ref_time(203_959_000 as RefTimeWeight) // Standard Error: 142_000 - .saturating_add(Weight::from_ref_time(61_311_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(61_311_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1847,7 +1847,7 @@ impl WeightInfo for () { fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(349_915_000 as RefTimeWeight) // Standard Error: 40_000 - .saturating_add(Weight::from_ref_time(320_652_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(320_652_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1859,7 +1859,7 @@ impl WeightInfo for () { fn seal_hash_keccak_256(r: u32, ) -> Weight { Weight::from_ref_time(209_219_000 as RefTimeWeight) // Standard Error: 157_000 - .saturating_add(Weight::from_ref_time(73_728_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_728_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1871,7 +1871,7 @@ impl WeightInfo for () { fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(208_860_000 as RefTimeWeight) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(245_718_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(245_718_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1883,7 +1883,7 @@ impl WeightInfo for () { fn seal_hash_blake2_256(r: u32, ) -> Weight { Weight::from_ref_time(206_165_000 as RefTimeWeight) // Standard Error: 138_000 - .saturating_add(Weight::from_ref_time(51_644_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_644_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1895,7 +1895,7 @@ impl WeightInfo for () { fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(255_955_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_090_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_090_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1907,7 +1907,7 @@ impl WeightInfo for () { fn seal_hash_blake2_128(r: u32, ) -> Weight { Weight::from_ref_time(208_153_000 as RefTimeWeight) // Standard Error: 140_000 - .saturating_add(Weight::from_ref_time(51_264_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_264_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1919,7 +1919,7 @@ impl WeightInfo for () { fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(278_368_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_006_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_006_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1931,7 +1931,7 @@ impl WeightInfo for () { fn seal_ecdsa_recover(r: u32, ) -> Weight { Weight::from_ref_time(331_955_000 as RefTimeWeight) // Standard Error: 1_155_000 - .saturating_add(Weight::from_ref_time(3_069_955_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_069_955_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1943,7 +1943,7 @@ impl WeightInfo for () { fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { Weight::from_ref_time(207_838_000 as RefTimeWeight) // Standard Error: 783_000 - .saturating_add(Weight::from_ref_time(2_058_503_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_058_503_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -1956,7 +1956,7 @@ impl WeightInfo for () { fn seal_set_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_567_000 - .saturating_add(Weight::from_ref_time(774_380_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(774_380_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) } @@ -1964,306 +1964,306 @@ impl WeightInfo for () { fn instr_i64const(r: u32, ) -> Weight { Weight::from_ref_time(73_955_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(612_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(612_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { Weight::from_ref_time(74_057_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { Weight::from_ref_time(74_137_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { Weight::from_ref_time(73_844_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_773_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_773_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { Weight::from_ref_time(73_979_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_952_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_952_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { Weight::from_ref_time(73_924_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(941_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(941_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { Weight::from_ref_time(73_574_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_439_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_439_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { Weight::from_ref_time(73_343_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_603_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_603_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { Weight::from_ref_time(76_267_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { Weight::from_ref_time(74_877_000 as RefTimeWeight) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(7_144_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(7_144_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { Weight::from_ref_time(88_665_000 as RefTimeWeight) // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(9_142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { Weight::from_ref_time(98_600_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(469_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(469_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { Weight::from_ref_time(74_555_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(624_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(624_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { Weight::from_ref_time(74_329_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(688_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(688_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { Weight::from_ref_time(74_612_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(909_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(909_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { Weight::from_ref_time(76_906_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_192_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_192_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { Weight::from_ref_time(76_979_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_361_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_361_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { Weight::from_ref_time(74_370_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(661_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(661_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { Weight::from_ref_time(73_584_000 as RefTimeWeight) // Standard Error: 353_000 - .saturating_add(Weight::from_ref_time(187_114_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(187_114_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { Weight::from_ref_time(74_206_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(884_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(884_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { Weight::from_ref_time(73_992_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(893_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(893_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { Weight::from_ref_time(73_985_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(891_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(891_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { Weight::from_ref_time(74_117_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(901_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(901_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { Weight::from_ref_time(73_981_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(866_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(866_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { Weight::from_ref_time(74_104_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { Weight::from_ref_time(74_293_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(878_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(878_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { Weight::from_ref_time(74_055_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { Weight::from_ref_time(73_710_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { Weight::from_ref_time(73_917_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_355_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_355_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { Weight::from_ref_time(74_048_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { Weight::from_ref_time(74_029_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_349_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_349_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { Weight::from_ref_time(74_267_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { Weight::from_ref_time(73_952_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { Weight::from_ref_time(73_851_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_368_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_368_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { Weight::from_ref_time(74_034_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_348_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_348_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { Weight::from_ref_time(73_979_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { Weight::from_ref_time(74_000_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_328_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_328_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { Weight::from_ref_time(73_883_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_331_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_331_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { Weight::from_ref_time(74_216_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { Weight::from_ref_time(73_989_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_998_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_998_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { Weight::from_ref_time(73_857_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_073_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_073_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { Weight::from_ref_time(73_801_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_027_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_027_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { Weight::from_ref_time(74_130_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_064_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_064_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { Weight::from_ref_time(74_071_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_327_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_327_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { Weight::from_ref_time(74_201_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_330_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_330_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { Weight::from_ref_time(74_241_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_321_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_321_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { Weight::from_ref_time(74_331_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_347_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_347_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { Weight::from_ref_time(73_674_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_359_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_359_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { Weight::from_ref_time(73_807_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { Weight::from_ref_time(73_725_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { Weight::from_ref_time(73_755_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) } } diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index 10c5c975a81f1..dbc7ce06ee825 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -99,7 +99,7 @@ impl WeightInfo for SubstrateWeight { fn delegate(r: u32, ) -> Weight { Weight::from_ref_time(51_518_000 as RefTimeWeight) // Standard Error: 83_000 - .saturating_add(Weight::from_ref_time(27_235_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(27_235_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) @@ -111,7 +111,7 @@ impl WeightInfo for SubstrateWeight { fn undelegate(r: u32, ) -> Weight { Weight::from_ref_time(37_885_000 as RefTimeWeight) // Standard Error: 75_000 - .saturating_add(Weight::from_ref_time(24_395_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(24_395_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -172,7 +172,7 @@ impl WeightInfo for () { fn delegate(r: u32, ) -> Weight { Weight::from_ref_time(51_518_000 as RefTimeWeight) // Standard Error: 83_000 - .saturating_add(Weight::from_ref_time(27_235_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(27_235_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) @@ -184,7 +184,7 @@ impl WeightInfo for () { fn undelegate(r: u32, ) -> Weight { Weight::from_ref_time(37_885_000 as RefTimeWeight) // Standard Error: 75_000 - .saturating_add(Weight::from_ref_time(24_395_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(24_395_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 5bbc97fa16e30..bbc5b767e97ff 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1765,7 +1765,7 @@ impl Pallet { /// # fn begin_block(now: T::BlockNumber) -> Weight { let max_block_weight = T::BlockWeights::get().max_block; - let mut weight = Weight::new(); + let mut weight = Weight::zero(); let next = Self::lowest_unbaked(); let last = Self::referendum_count(); diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 351ed42cca8e9..ad11526736c9c 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -88,7 +88,7 @@ impl WeightInfo for SubstrateWeight { fn second(s: u32, ) -> Weight { Weight::from_ref_time(30_923_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -98,7 +98,7 @@ impl WeightInfo for SubstrateWeight { fn vote_new(r: u32, ) -> Weight { Weight::from_ref_time(40_345_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(140_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(140_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -108,7 +108,7 @@ impl WeightInfo for SubstrateWeight { fn vote_existing(r: u32, ) -> Weight { Weight::from_ref_time(39_853_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -128,7 +128,7 @@ impl WeightInfo for SubstrateWeight { fn blacklist(p: u32, ) -> Weight { Weight::from_ref_time(57_708_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) } @@ -137,7 +137,7 @@ impl WeightInfo for SubstrateWeight { fn external_propose(v: u32, ) -> Weight { Weight::from_ref_time(10_714_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -164,7 +164,7 @@ impl WeightInfo for SubstrateWeight { fn veto_external(v: u32, ) -> Weight { Weight::from_ref_time(21_319_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -174,7 +174,7 @@ impl WeightInfo for SubstrateWeight { fn cancel_proposal(p: u32, ) -> Weight { Weight::from_ref_time(43_960_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(184_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(184_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -188,7 +188,7 @@ impl WeightInfo for SubstrateWeight { fn cancel_queued(r: u32, ) -> Weight { Weight::from_ref_time(24_320_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(560_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(560_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -198,7 +198,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_base(r: u32, ) -> Weight { Weight::from_ref_time(3_428_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_171_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_171_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -212,7 +212,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { Weight::from_ref_time(7_867_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_177_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_177_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -223,7 +223,7 @@ impl WeightInfo for SubstrateWeight { fn delegate(r: u32, ) -> Weight { Weight::from_ref_time(37_902_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(4_335_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_335_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) @@ -234,7 +234,7 @@ impl WeightInfo for SubstrateWeight { fn undelegate(r: u32, ) -> Weight { Weight::from_ref_time(21_272_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(4_351_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_351_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -249,7 +249,7 @@ impl WeightInfo for SubstrateWeight { fn note_preimage(b: u32, ) -> Weight { Weight::from_ref_time(27_986_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -257,7 +257,7 @@ impl WeightInfo for SubstrateWeight { fn note_imminent_preimage(b: u32, ) -> Weight { Weight::from_ref_time(20_058_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -266,7 +266,7 @@ impl WeightInfo for SubstrateWeight { fn reap_preimage(b: u32, ) -> Weight { Weight::from_ref_time(28_619_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -276,7 +276,7 @@ impl WeightInfo for SubstrateWeight { fn unlock_remove(r: u32, ) -> Weight { Weight::from_ref_time(26_619_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -286,7 +286,7 @@ impl WeightInfo for SubstrateWeight { fn unlock_set(r: u32, ) -> Weight { Weight::from_ref_time(25_373_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -295,7 +295,7 @@ impl WeightInfo for SubstrateWeight { fn remove_vote(r: u32, ) -> Weight { Weight::from_ref_time(15_961_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -304,7 +304,7 @@ impl WeightInfo for SubstrateWeight { fn remove_other_vote(r: u32, ) -> Weight { Weight::from_ref_time(15_992_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(113_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(113_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -325,7 +325,7 @@ impl WeightInfo for () { fn second(s: u32, ) -> Weight { Weight::from_ref_time(30_923_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -335,7 +335,7 @@ impl WeightInfo for () { fn vote_new(r: u32, ) -> Weight { Weight::from_ref_time(40_345_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(140_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(140_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -345,7 +345,7 @@ impl WeightInfo for () { fn vote_existing(r: u32, ) -> Weight { Weight::from_ref_time(39_853_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -365,7 +365,7 @@ impl WeightInfo for () { fn blacklist(p: u32, ) -> Weight { Weight::from_ref_time(57_708_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) } @@ -374,7 +374,7 @@ impl WeightInfo for () { fn external_propose(v: u32, ) -> Weight { Weight::from_ref_time(10_714_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -401,7 +401,7 @@ impl WeightInfo for () { fn veto_external(v: u32, ) -> Weight { Weight::from_ref_time(21_319_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -411,7 +411,7 @@ impl WeightInfo for () { fn cancel_proposal(p: u32, ) -> Weight { Weight::from_ref_time(43_960_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(184_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(184_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -425,7 +425,7 @@ impl WeightInfo for () { fn cancel_queued(r: u32, ) -> Weight { Weight::from_ref_time(24_320_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(560_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(560_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -435,7 +435,7 @@ impl WeightInfo for () { fn on_initialize_base(r: u32, ) -> Weight { Weight::from_ref_time(3_428_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_171_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_171_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -449,7 +449,7 @@ impl WeightInfo for () { fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { Weight::from_ref_time(7_867_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_177_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_177_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -460,7 +460,7 @@ impl WeightInfo for () { fn delegate(r: u32, ) -> Weight { Weight::from_ref_time(37_902_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(4_335_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_335_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) @@ -471,7 +471,7 @@ impl WeightInfo for () { fn undelegate(r: u32, ) -> Weight { Weight::from_ref_time(21_272_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(4_351_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_351_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) @@ -486,7 +486,7 @@ impl WeightInfo for () { fn note_preimage(b: u32, ) -> Weight { Weight::from_ref_time(27_986_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -494,7 +494,7 @@ impl WeightInfo for () { fn note_imminent_preimage(b: u32, ) -> Weight { Weight::from_ref_time(20_058_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -503,7 +503,7 @@ impl WeightInfo for () { fn reap_preimage(b: u32, ) -> Weight { Weight::from_ref_time(28_619_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -513,7 +513,7 @@ impl WeightInfo for () { fn unlock_remove(r: u32, ) -> Weight { Weight::from_ref_time(26_619_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -523,7 +523,7 @@ impl WeightInfo for () { fn unlock_set(r: u32, ) -> Weight { Weight::from_ref_time(25_373_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -532,7 +532,7 @@ impl WeightInfo for () { fn remove_vote(r: u32, ) -> Weight { Weight::from_ref_time(15_961_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -541,7 +541,7 @@ impl WeightInfo for () { fn remove_other_vote(r: u32, ) -> Weight { Weight::from_ref_time(15_992_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(113_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(113_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 72b3ec9764079..48b76bbb98a8f 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -226,7 +226,7 @@ const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); parameter_types! { pub const ExistentialDeposit: u64 = 1; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights - ::with_sensible_defaults(2 * frame_support::weights::constants::WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); + ::with_sensible_defaults(2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); } impl pallet_balances::Config for Runtime { diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 7ceb4a20e042a..0e7af39badd44 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -104,9 +104,9 @@ impl WeightInfo for SubstrateWeight { fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { Weight::from_ref_time(3_186_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(202_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(202_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(60_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(60_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -121,9 +121,9 @@ impl WeightInfo for SubstrateWeight { fn elect_queued(a: u32, d: u32, ) -> Weight { Weight::from_ref_time(137_653_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(640_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(640_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(8 as RefTimeWeight)) } @@ -148,13 +148,13 @@ impl WeightInfo for SubstrateWeight { fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(6_907_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(6_907_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -165,13 +165,13 @@ impl WeightInfo for SubstrateWeight { fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(844_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(844_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(5_421_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_421_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(1_167_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_167_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) } } @@ -223,9 +223,9 @@ impl WeightInfo for () { fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { Weight::from_ref_time(3_186_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(202_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(202_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(60_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(60_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -240,9 +240,9 @@ impl WeightInfo for () { fn elect_queued(a: u32, d: u32, ) -> Weight { Weight::from_ref_time(137_653_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(640_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(640_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(8 as RefTimeWeight)) } @@ -267,13 +267,13 @@ impl WeightInfo for () { fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(6_907_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(6_907_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -284,13 +284,13 @@ impl WeightInfo for () { fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(844_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(844_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(5_421_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_421_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(1_167_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_167_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) } } diff --git a/frame/election-provider-support/src/weights.rs b/frame/election-provider-support/src/weights.rs index 4f9e47b09a4da..ed7360940ba58 100644 --- a/frame/election-provider-support/src/weights.rs +++ b/frame/election-provider-support/src/weights.rs @@ -55,20 +55,20 @@ impl WeightInfo for SubstrateWeight { fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 667_000 - .saturating_add(Weight::from_ref_time(32_973_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(32_973_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 1_334_000 - .saturating_add(Weight::from_ref_time(1_334_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_334_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 60_644_000 - .saturating_add(Weight::from_ref_time(2_636_364_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_636_364_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) } fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 73_000 - .saturating_add(Weight::from_ref_time(21_073_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(21_073_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 146_000 - .saturating_add(Weight::from_ref_time(65_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(65_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 6_649_000 - .saturating_add(Weight::from_ref_time(1_711_424_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_711_424_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) } } @@ -77,19 +77,19 @@ impl WeightInfo for () { fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 667_000 - .saturating_add(Weight::from_ref_time(32_973_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(32_973_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 1_334_000 - .saturating_add(Weight::from_ref_time(1_334_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_334_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 60_644_000 - .saturating_add(Weight::from_ref_time(2_636_364_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_636_364_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) } fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 73_000 - .saturating_add(Weight::from_ref_time(21_073_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(21_073_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 146_000 - .saturating_add(Weight::from_ref_time(65_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(65_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) // Standard Error: 6_649_000 - .saturating_add(Weight::from_ref_time(1_711_424_000 as RefTimeWeight).scalar_saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_711_424_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) } } diff --git a/frame/elections-phragmen/src/migrations/v5.rs b/frame/elections-phragmen/src/migrations/v5.rs index eb96d7ddf6a99..eb35c1fae0f29 100644 --- a/frame/elections-phragmen/src/migrations/v5.rs +++ b/frame/elections-phragmen/src/migrations/v5.rs @@ -8,7 +8,7 @@ use super::super::*; /// situation where they could increase their free balance but still not be able to use their funds /// because they were less than the lock. pub fn migrate(to_migrate: Vec) -> Weight { - let mut weight = Weight::new(); + let mut weight = Weight::zero(); for who in to_migrate.iter() { if let Ok(mut voter) = Voting::::try_get(who) { diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 14c69bf16f7f1..051aaa793588c 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -72,7 +72,7 @@ impl WeightInfo for SubstrateWeight { fn vote_equal(v: u32, ) -> Weight { Weight::from_ref_time(27_011_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(214_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(214_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -85,7 +85,7 @@ impl WeightInfo for SubstrateWeight { fn vote_more(v: u32, ) -> Weight { Weight::from_ref_time(40_240_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(244_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(244_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -98,7 +98,7 @@ impl WeightInfo for SubstrateWeight { fn vote_less(v: u32, ) -> Weight { Weight::from_ref_time(40_394_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(217_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(217_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -116,7 +116,7 @@ impl WeightInfo for SubstrateWeight { fn submit_candidacy(c: u32, ) -> Weight { Weight::from_ref_time(42_217_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(50_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(50_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -125,7 +125,7 @@ impl WeightInfo for SubstrateWeight { fn renounce_candidacy_candidate(c: u32, ) -> Weight { Weight::from_ref_time(46_459_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(26_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(26_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -171,7 +171,7 @@ impl WeightInfo for SubstrateWeight { fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 76_000 - .saturating_add(Weight::from_ref_time(63_721_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(63_721_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) @@ -191,9 +191,9 @@ impl WeightInfo for SubstrateWeight { fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 773_000 - .saturating_add(Weight::from_ref_time(81_534_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(81_534_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 51_000 - .saturating_add(Weight::from_ref_time(4_453_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_453_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(280 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) @@ -212,7 +212,7 @@ impl WeightInfo for () { fn vote_equal(v: u32, ) -> Weight { Weight::from_ref_time(27_011_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(214_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(214_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -225,7 +225,7 @@ impl WeightInfo for () { fn vote_more(v: u32, ) -> Weight { Weight::from_ref_time(40_240_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(244_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(244_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -238,7 +238,7 @@ impl WeightInfo for () { fn vote_less(v: u32, ) -> Weight { Weight::from_ref_time(40_394_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(217_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(217_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -256,7 +256,7 @@ impl WeightInfo for () { fn submit_candidacy(c: u32, ) -> Weight { Weight::from_ref_time(42_217_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(50_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(50_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -265,7 +265,7 @@ impl WeightInfo for () { fn renounce_candidacy_candidate(c: u32, ) -> Weight { Weight::from_ref_time(46_459_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(26_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(26_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -311,7 +311,7 @@ impl WeightInfo for () { fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 76_000 - .saturating_add(Weight::from_ref_time(63_721_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(63_721_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) @@ -331,9 +331,9 @@ impl WeightInfo for () { fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 773_000 - .saturating_add(Weight::from_ref_time(81_534_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(81_534_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 51_000 - .saturating_add(Weight::from_ref_time(4_453_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_453_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(280 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) diff --git a/frame/examples/basic/src/weights.rs b/frame/examples/basic/src/weights.rs index e8fc44bc4b050..d27915ef1b02a 100644 --- a/frame/examples/basic/src/weights.rs +++ b/frame/examples/basic/src/weights.rs @@ -64,19 +64,19 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn set_dummy_benchmark(b: u32, ) -> Weight { Weight::from_ref_time(5_834_000 as RefTimeWeight) - .saturating_add(Weight::from_ref_time(24_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(24_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } fn accumulate_dummy(b: u32, ) -> Weight { Weight::from_ref_time(51_353_000 as RefTimeWeight) - .saturating_add(Weight::from_ref_time(14_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(14_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } fn sort_vector(x: u32, ) -> Weight { Weight::from_ref_time(2_569_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) } } @@ -84,18 +84,18 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { fn set_dummy_benchmark(b: u32, ) -> Weight { Weight::from_ref_time(5_834_000 as RefTimeWeight) - .saturating_add(Weight::from_ref_time(24_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(24_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } fn accumulate_dummy(b: u32, ) -> Weight { Weight::from_ref_time(51_353_000 as RefTimeWeight) - .saturating_add(Weight::from_ref_time(14_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(14_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } fn sort_vector(x: u32, ) -> Weight { Weight::from_ref_time(2_569_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) } } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index d7cd1da7910a4..5d3954ded0998 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -348,7 +348,7 @@ where // This means the format of all the event related storages must always be compatible. >::reset_events(); - let mut weight = Weight::new(); + let mut weight = Weight::zero(); if Self::runtime_upgraded() { weight = weight.saturating_add(Self::execute_on_runtime_upgrade()); } @@ -1121,7 +1121,7 @@ mod tests { .base_extrinsic; assert_eq!( >::block_weight().total(), - base_block_weight + 3 * extrinsic_weight, + base_block_weight + 3u64 * extrinsic_weight, ); assert_eq!(>::all_extrinsics_len(), 3 * len); diff --git a/frame/gilt/src/weights.rs b/frame/gilt/src/weights.rs index 3d2b629e8b16b..124ee7593a778 100644 --- a/frame/gilt/src/weights.rs +++ b/frame/gilt/src/weights.rs @@ -62,7 +62,7 @@ impl WeightInfo for SubstrateWeight { fn place_bid(l: u32, ) -> Weight { Weight::from_ref_time(41_605_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(62_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(62_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -78,7 +78,7 @@ impl WeightInfo for SubstrateWeight { fn retract_bid(l: u32, ) -> Weight { Weight::from_ref_time(42_061_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -107,7 +107,7 @@ impl WeightInfo for SubstrateWeight { fn pursue_target_per_item(b: u32, ) -> Weight { Weight::from_ref_time(40_797_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(4_122_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_122_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) @@ -119,7 +119,7 @@ impl WeightInfo for SubstrateWeight { fn pursue_target_per_queue(q: u32, ) -> Weight { Weight::from_ref_time(14_944_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(8_135_000 as RefTimeWeight).scalar_saturating_mul(q as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_135_000 as RefTimeWeight).saturating_mul(q as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(q as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -134,7 +134,7 @@ impl WeightInfo for () { fn place_bid(l: u32, ) -> Weight { Weight::from_ref_time(41_605_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(62_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(62_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -150,7 +150,7 @@ impl WeightInfo for () { fn retract_bid(l: u32, ) -> Weight { Weight::from_ref_time(42_061_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -179,7 +179,7 @@ impl WeightInfo for () { fn pursue_target_per_item(b: u32, ) -> Weight { Weight::from_ref_time(40_797_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(4_122_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_122_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) @@ -191,7 +191,7 @@ impl WeightInfo for () { fn pursue_target_per_queue(q: u32, ) -> Weight { Weight::from_ref_time(14_944_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(8_135_000 as RefTimeWeight).scalar_saturating_mul(q as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_135_000 as RefTimeWeight).saturating_mul(q as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(q as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) diff --git a/frame/grandpa/src/default_weights.rs b/frame/grandpa/src/default_weights.rs index f21c3ddc101f7..4ca94dd576fb7 100644 --- a/frame/grandpa/src/default_weights.rs +++ b/frame/grandpa/src/default_weights.rs @@ -34,14 +34,14 @@ impl crate::WeightInfo for () { const MAX_NOMINATORS: u64 = 200; // checking membership proof - (35 * WEIGHT_PER_MICROS) - .saturating_add((175 * WEIGHT_PER_NANOS).scalar_saturating_mul(validator_count)) + (35u64 * WEIGHT_PER_MICROS) + .saturating_add((175u64 * WEIGHT_PER_NANOS).saturating_mul(validator_count)) .saturating_add(DbWeight::get().reads(5)) // check equivocation proof - .saturating_add(95 * WEIGHT_PER_MICROS) + .saturating_add(95u64 * WEIGHT_PER_MICROS) // report offence - .saturating_add(110 * WEIGHT_PER_MICROS) - .saturating_add(25 * WEIGHT_PER_MICROS * MAX_NOMINATORS) + .saturating_add(110u64 * WEIGHT_PER_MICROS) + .saturating_add(25u64 * WEIGHT_PER_MICROS * MAX_NOMINATORS) .saturating_add(DbWeight::get().reads(14 + 3 * MAX_NOMINATORS)) .saturating_add(DbWeight::get().writes(10 + 3 * MAX_NOMINATORS)) // fetching set id -> session index mappings @@ -49,6 +49,6 @@ impl crate::WeightInfo for () { } fn note_stalled() -> Weight { - (3 * WEIGHT_PER_MICROS).saturating_add(DbWeight::get().writes(1)) + (3u64 * WEIGHT_PER_MICROS).saturating_add(DbWeight::get().writes(1)) } } diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 780abf1bb01df..1aa8d7963223e 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -71,7 +71,7 @@ impl WeightInfo for SubstrateWeight { fn add_registrar(r: u32, ) -> Weight { Weight::from_ref_time(16_649_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(241_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(241_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -81,9 +81,9 @@ impl WeightInfo for SubstrateWeight { fn set_identity(r: u32, x: u32, ) -> Weight { Weight::from_ref_time(31_322_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(252_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(252_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(312_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(312_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -94,7 +94,7 @@ impl WeightInfo for SubstrateWeight { fn set_subs_new(s: u32, ) -> Weight { Weight::from_ref_time(30_012_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_005_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_005_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -107,7 +107,7 @@ impl WeightInfo for SubstrateWeight { fn set_subs_old(p: u32, ) -> Weight { Weight::from_ref_time(29_623_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_100_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_100_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) @@ -121,11 +121,11 @@ impl WeightInfo for SubstrateWeight { fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { Weight::from_ref_time(34_370_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(189_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(189_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -137,9 +137,9 @@ impl WeightInfo for SubstrateWeight { fn request_judgement(r: u32, x: u32, ) -> Weight { Weight::from_ref_time(34_759_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(251_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(251_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(340_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(340_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -149,9 +149,9 @@ impl WeightInfo for SubstrateWeight { fn cancel_request(r: u32, x: u32, ) -> Weight { Weight::from_ref_time(32_254_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(159_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(159_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(347_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(347_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -160,7 +160,7 @@ impl WeightInfo for SubstrateWeight { fn set_fee(r: u32, ) -> Weight { Weight::from_ref_time(7_858_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(190_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(190_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -169,7 +169,7 @@ impl WeightInfo for SubstrateWeight { fn set_account_id(r: u32, ) -> Weight { Weight::from_ref_time(8_011_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(187_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(187_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -178,7 +178,7 @@ impl WeightInfo for SubstrateWeight { fn set_fields(r: u32, ) -> Weight { Weight::from_ref_time(7_970_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -189,9 +189,9 @@ impl WeightInfo for SubstrateWeight { fn provide_judgement(r: u32, x: u32, ) -> Weight { Weight::from_ref_time(24_730_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(196_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(196_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(341_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(341_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -205,11 +205,11 @@ impl WeightInfo for SubstrateWeight { fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { Weight::from_ref_time(44_988_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_126_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_126_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -221,7 +221,7 @@ impl WeightInfo for SubstrateWeight { fn add_sub(s: u32, ) -> Weight { Weight::from_ref_time(36_768_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -231,7 +231,7 @@ impl WeightInfo for SubstrateWeight { fn rename_sub(s: u32, ) -> Weight { Weight::from_ref_time(13_474_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -242,7 +242,7 @@ impl WeightInfo for SubstrateWeight { fn remove_sub(s: u32, ) -> Weight { Weight::from_ref_time(37_720_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -252,7 +252,7 @@ impl WeightInfo for SubstrateWeight { fn quit_sub(s: u32, ) -> Weight { Weight::from_ref_time(26_848_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -265,7 +265,7 @@ impl WeightInfo for () { fn add_registrar(r: u32, ) -> Weight { Weight::from_ref_time(16_649_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(241_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(241_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -275,9 +275,9 @@ impl WeightInfo for () { fn set_identity(r: u32, x: u32, ) -> Weight { Weight::from_ref_time(31_322_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(252_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(252_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(312_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(312_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -288,7 +288,7 @@ impl WeightInfo for () { fn set_subs_new(s: u32, ) -> Weight { Weight::from_ref_time(30_012_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_005_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_005_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -301,7 +301,7 @@ impl WeightInfo for () { fn set_subs_old(p: u32, ) -> Weight { Weight::from_ref_time(29_623_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_100_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_100_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) @@ -315,11 +315,11 @@ impl WeightInfo for () { fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { Weight::from_ref_time(34_370_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(189_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(189_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -331,9 +331,9 @@ impl WeightInfo for () { fn request_judgement(r: u32, x: u32, ) -> Weight { Weight::from_ref_time(34_759_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(251_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(251_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(340_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(340_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -343,9 +343,9 @@ impl WeightInfo for () { fn cancel_request(r: u32, x: u32, ) -> Weight { Weight::from_ref_time(32_254_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(159_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(159_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(347_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(347_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -354,7 +354,7 @@ impl WeightInfo for () { fn set_fee(r: u32, ) -> Weight { Weight::from_ref_time(7_858_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(190_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(190_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -363,7 +363,7 @@ impl WeightInfo for () { fn set_account_id(r: u32, ) -> Weight { Weight::from_ref_time(8_011_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(187_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(187_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -372,7 +372,7 @@ impl WeightInfo for () { fn set_fields(r: u32, ) -> Weight { Weight::from_ref_time(7_970_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -383,9 +383,9 @@ impl WeightInfo for () { fn provide_judgement(r: u32, x: u32, ) -> Weight { Weight::from_ref_time(24_730_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(196_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(196_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(341_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(341_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -399,11 +399,11 @@ impl WeightInfo for () { fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { Weight::from_ref_time(44_988_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_126_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_126_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -415,7 +415,7 @@ impl WeightInfo for () { fn add_sub(s: u32, ) -> Weight { Weight::from_ref_time(36_768_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -425,7 +425,7 @@ impl WeightInfo for () { fn rename_sub(s: u32, ) -> Weight { Weight::from_ref_time(13_474_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -436,7 +436,7 @@ impl WeightInfo for () { fn remove_sub(s: u32, ) -> Weight { Weight::from_ref_time(37_720_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -446,7 +446,7 @@ impl WeightInfo for () { fn quit_sub(s: u32, ) -> Weight { Weight::from_ref_time(26_848_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index 09fbc55854288..acad1e1165d4c 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -58,9 +58,9 @@ impl WeightInfo for SubstrateWeight { fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { Weight::from_ref_time(79_225_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(41_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(41_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(293_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(293_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -76,9 +76,9 @@ impl WeightInfo for () { fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { Weight::from_ref_time(79_225_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(41_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(41_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(293_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(293_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index f646ca02a0377..10eda18e0e24f 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -71,7 +71,7 @@ impl WeightInfo for SubstrateWeight { fn set_calls(n: u32, ) -> Weight { Weight::from_ref_time(12_556_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(295_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(295_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Lottery Lottery (r:1 w:1) @@ -129,7 +129,7 @@ impl WeightInfo for () { fn set_calls(n: u32, ) -> Weight { Weight::from_ref_time(12_556_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(295_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(295_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Lottery Lottery (r:1 w:1) diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 54b67e5b68a8a..636f8eba64694 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -63,7 +63,7 @@ impl WeightInfo for SubstrateWeight { fn add_member(m: u32, ) -> Weight { Weight::from_ref_time(15_318_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(51_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -75,7 +75,7 @@ impl WeightInfo for SubstrateWeight { fn remove_member(m: u32, ) -> Weight { Weight::from_ref_time(18_005_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(45_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -87,7 +87,7 @@ impl WeightInfo for SubstrateWeight { fn swap_member(m: u32, ) -> Weight { Weight::from_ref_time(18_029_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -99,7 +99,7 @@ impl WeightInfo for SubstrateWeight { fn reset_member(m: u32, ) -> Weight { Weight::from_ref_time(18_105_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -111,7 +111,7 @@ impl WeightInfo for SubstrateWeight { fn change_key(m: u32, ) -> Weight { Weight::from_ref_time(18_852_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } @@ -121,7 +121,7 @@ impl WeightInfo for SubstrateWeight { fn set_prime(m: u32, ) -> Weight { Weight::from_ref_time(4_869_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(28_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(28_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -130,7 +130,7 @@ impl WeightInfo for SubstrateWeight { fn clear_prime(m: u32, ) -> Weight { Weight::from_ref_time(1_593_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } } @@ -144,7 +144,7 @@ impl WeightInfo for () { fn add_member(m: u32, ) -> Weight { Weight::from_ref_time(15_318_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(51_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -156,7 +156,7 @@ impl WeightInfo for () { fn remove_member(m: u32, ) -> Weight { Weight::from_ref_time(18_005_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(45_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -168,7 +168,7 @@ impl WeightInfo for () { fn swap_member(m: u32, ) -> Weight { Weight::from_ref_time(18_029_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -180,7 +180,7 @@ impl WeightInfo for () { fn reset_member(m: u32, ) -> Weight { Weight::from_ref_time(18_105_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -192,7 +192,7 @@ impl WeightInfo for () { fn change_key(m: u32, ) -> Weight { Weight::from_ref_time(18_852_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } @@ -202,7 +202,7 @@ impl WeightInfo for () { fn set_prime(m: u32, ) -> Weight { Weight::from_ref_time(4_869_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(28_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(28_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -211,7 +211,7 @@ impl WeightInfo for () { fn clear_prime(m: u32, ) -> Weight { Weight::from_ref_time(1_593_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } } diff --git a/frame/merkle-mountain-range/src/default_weights.rs b/frame/merkle-mountain-range/src/default_weights.rs index e7a4b6ab31c4a..e513e2197f1c6 100644 --- a/frame/merkle-mountain-range/src/default_weights.rs +++ b/frame/merkle-mountain-range/src/default_weights.rs @@ -28,7 +28,7 @@ impl crate::WeightInfo for () { // Reading the parent hash. let leaf_weight = DbWeight::get().reads(1); // Blake2 hash cost. - let hash_weight = 2 * WEIGHT_PER_NANOS; + let hash_weight = 2u64 * WEIGHT_PER_NANOS; // No-op hook. let hook_weight = Weight::zero(); diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index 0b580ec82b640..455326b71de8c 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -67,9 +67,9 @@ impl WeightInfo for SubstrateWeight { fn as_multi_create(s: u32, z: u32, ) -> Weight { Weight::from_ref_time(36_535_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(99_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(99_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -79,9 +79,9 @@ impl WeightInfo for SubstrateWeight { fn as_multi_create_store(s: u32, z: u32, ) -> Weight { Weight::from_ref_time(39_918_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(95_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -89,9 +89,9 @@ impl WeightInfo for SubstrateWeight { fn as_multi_approve(s: u32, z: u32, ) -> Weight { Weight::from_ref_time(25_524_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(94_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(94_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -100,9 +100,9 @@ impl WeightInfo for SubstrateWeight { fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { Weight::from_ref_time(39_923_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(91_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(91_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -112,9 +112,9 @@ impl WeightInfo for SubstrateWeight { fn as_multi_complete(s: u32, z: u32, ) -> Weight { Weight::from_ref_time(45_877_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(146_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(146_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -123,7 +123,7 @@ impl WeightInfo for SubstrateWeight { fn approve_as_multi_create(s: u32, ) -> Weight { Weight::from_ref_time(34_309_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -132,7 +132,7 @@ impl WeightInfo for SubstrateWeight { fn approve_as_multi_approve(s: u32, ) -> Weight { Weight::from_ref_time(22_848_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -142,7 +142,7 @@ impl WeightInfo for SubstrateWeight { fn approve_as_multi_complete(s: u32, ) -> Weight { Weight::from_ref_time(63_239_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -151,7 +151,7 @@ impl WeightInfo for SubstrateWeight { fn cancel_as_multi(s: u32, ) -> Weight { Weight::from_ref_time(51_254_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -167,9 +167,9 @@ impl WeightInfo for () { fn as_multi_create(s: u32, z: u32, ) -> Weight { Weight::from_ref_time(36_535_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(99_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(99_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -179,9 +179,9 @@ impl WeightInfo for () { fn as_multi_create_store(s: u32, z: u32, ) -> Weight { Weight::from_ref_time(39_918_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(95_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -189,9 +189,9 @@ impl WeightInfo for () { fn as_multi_approve(s: u32, z: u32, ) -> Weight { Weight::from_ref_time(25_524_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(94_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(94_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -200,9 +200,9 @@ impl WeightInfo for () { fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { Weight::from_ref_time(39_923_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(91_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(91_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -212,9 +212,9 @@ impl WeightInfo for () { fn as_multi_complete(s: u32, z: u32, ) -> Weight { Weight::from_ref_time(45_877_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(146_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(146_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -223,7 +223,7 @@ impl WeightInfo for () { fn approve_as_multi_create(s: u32, ) -> Weight { Weight::from_ref_time(34_309_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -232,7 +232,7 @@ impl WeightInfo for () { fn approve_as_multi_approve(s: u32, ) -> Weight { Weight::from_ref_time(22_848_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -242,7 +242,7 @@ impl WeightInfo for () { fn approve_as_multi_complete(s: u32, ) -> Weight { Weight::from_ref_time(63_239_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -251,7 +251,7 @@ impl WeightInfo for () { fn cancel_as_multi(s: u32, ) -> Weight { Weight::from_ref_time(51_254_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index 1f0d2ce8cddc4..f24aeb6a0ee0d 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -148,7 +148,7 @@ impl WeightInfo for SubstrateWeight { fn pool_withdraw_unbonded(s: u32, ) -> Weight { Weight::from_ref_time(41_928_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -164,7 +164,7 @@ impl WeightInfo for SubstrateWeight { fn withdraw_unbonded_update(s: u32, ) -> Weight { Weight::from_ref_time(81_611_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(7 as RefTimeWeight)) } @@ -236,7 +236,7 @@ impl WeightInfo for SubstrateWeight { fn nominate(n: u32, ) -> Weight { Weight::from_ref_time(48_829_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(2_204_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_204_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) @@ -255,7 +255,7 @@ impl WeightInfo for SubstrateWeight { fn set_metadata(n: u32, ) -> Weight { Weight::from_ref_time(14_519_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -373,7 +373,7 @@ impl WeightInfo for () { fn pool_withdraw_unbonded(s: u32, ) -> Weight { Weight::from_ref_time(41_928_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -389,7 +389,7 @@ impl WeightInfo for () { fn withdraw_unbonded_update(s: u32, ) -> Weight { Weight::from_ref_time(81_611_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(7 as RefTimeWeight)) } @@ -461,7 +461,7 @@ impl WeightInfo for () { fn nominate(n: u32, ) -> Weight { Weight::from_ref_time(48_829_000 as RefTimeWeight) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(2_204_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_204_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) @@ -480,7 +480,7 @@ impl WeightInfo for () { fn set_metadata(n: u32, ) -> Weight { Weight::from_ref_time(14_519_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 312bc4e18f413..6d66f5251c78c 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -41,7 +41,7 @@ type Balance = u64; parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max( - 2 * WEIGHT_PER_SECOND + 2u64 * WEIGHT_PER_SECOND ); } diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index d9ecf44ad8734..a578a6082cf3e 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -86,7 +86,7 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND); + frame_system::limits::BlockWeights::simple_max(2u64 * WEIGHT_PER_SECOND); } impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 183b704ec705d..0d93611a1f097 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -66,7 +66,7 @@ impl WeightInfo for SubstrateWeight { fn note_preimage(s: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -75,7 +75,7 @@ impl WeightInfo for SubstrateWeight { fn note_requested_preimage(s: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -84,7 +84,7 @@ impl WeightInfo for SubstrateWeight { fn note_no_deposit_preimage(s: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -155,7 +155,7 @@ impl WeightInfo for () { fn note_preimage(s: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -164,7 +164,7 @@ impl WeightInfo for () { fn note_requested_preimage(s: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -173,7 +173,7 @@ impl WeightInfo for () { fn note_no_deposit_preimage(s: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 119df271e0d55..5b332d98db09b 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -63,7 +63,7 @@ impl WeightInfo for SubstrateWeight { fn proxy(p: u32, ) -> Weight { Weight::from_ref_time(17_768_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(76_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(76_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:0) @@ -72,9 +72,9 @@ impl WeightInfo for SubstrateWeight { fn proxy_announced(a: u32, p: u32, ) -> Weight { Weight::from_ref_time(35_682_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -83,9 +83,9 @@ impl WeightInfo for SubstrateWeight { fn remove_announcement(a: u32, p: u32, ) -> Weight { Weight::from_ref_time(25_586_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(18_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(18_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -94,9 +94,9 @@ impl WeightInfo for SubstrateWeight { fn reject_announcement(a: u32, p: u32, ) -> Weight { Weight::from_ref_time(25_794_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(13_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(13_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -106,9 +106,9 @@ impl WeightInfo for SubstrateWeight { fn announce(a: u32, p: u32, ) -> Weight { Weight::from_ref_time(33_002_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(163_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(163_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -116,7 +116,7 @@ impl WeightInfo for SubstrateWeight { fn add_proxy(p: u32, ) -> Weight { Weight::from_ref_time(28_166_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(105_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(105_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -124,7 +124,7 @@ impl WeightInfo for SubstrateWeight { fn remove_proxy(p: u32, ) -> Weight { Weight::from_ref_time(28_128_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -132,7 +132,7 @@ impl WeightInfo for SubstrateWeight { fn remove_proxies(p: u32, ) -> Weight { Weight::from_ref_time(24_066_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(81_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(81_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -141,7 +141,7 @@ impl WeightInfo for SubstrateWeight { fn anonymous(p: u32, ) -> Weight { Weight::from_ref_time(31_077_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -149,7 +149,7 @@ impl WeightInfo for SubstrateWeight { fn kill_anonymous(p: u32, ) -> Weight { Weight::from_ref_time(24_657_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -161,7 +161,7 @@ impl WeightInfo for () { fn proxy(p: u32, ) -> Weight { Weight::from_ref_time(17_768_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(76_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(76_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) } // Storage: Proxy Proxies (r:1 w:0) @@ -170,9 +170,9 @@ impl WeightInfo for () { fn proxy_announced(a: u32, p: u32, ) -> Weight { Weight::from_ref_time(35_682_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -181,9 +181,9 @@ impl WeightInfo for () { fn remove_announcement(a: u32, p: u32, ) -> Weight { Weight::from_ref_time(25_586_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(18_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(18_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -192,9 +192,9 @@ impl WeightInfo for () { fn reject_announcement(a: u32, p: u32, ) -> Weight { Weight::from_ref_time(25_794_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(13_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(13_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -204,9 +204,9 @@ impl WeightInfo for () { fn announce(a: u32, p: u32, ) -> Weight { Weight::from_ref_time(33_002_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(163_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(163_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -214,7 +214,7 @@ impl WeightInfo for () { fn add_proxy(p: u32, ) -> Weight { Weight::from_ref_time(28_166_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(105_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(105_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -222,7 +222,7 @@ impl WeightInfo for () { fn remove_proxy(p: u32, ) -> Weight { Weight::from_ref_time(28_128_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -230,7 +230,7 @@ impl WeightInfo for () { fn remove_proxies(p: u32, ) -> Weight { Weight::from_ref_time(24_066_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(81_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(81_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -239,7 +239,7 @@ impl WeightInfo for () { fn anonymous(p: u32, ) -> Weight { Weight::from_ref_time(31_077_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -247,7 +247,7 @@ impl WeightInfo for () { fn kill_anonymous(p: u32, ) -> Weight { Weight::from_ref_time(24_657_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } diff --git a/frame/ranked-collective/src/weights.rs b/frame/ranked-collective/src/weights.rs index a0309daea2263..052a9bfdcc9e1 100644 --- a/frame/ranked-collective/src/weights.rs +++ b/frame/ranked-collective/src/weights.rs @@ -72,7 +72,7 @@ impl WeightInfo for SubstrateWeight { fn remove_member(r: u32, ) -> Weight { Weight::from_ref_time(16_855_000 as RefTimeWeight) // Standard Error: 27_000 - .saturating_add(Weight::from_ref_time(8_107_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_107_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) @@ -85,7 +85,7 @@ impl WeightInfo for SubstrateWeight { fn promote_member(r: u32, ) -> Weight { Weight::from_ref_time(11_936_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(9_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } @@ -96,7 +96,7 @@ impl WeightInfo for SubstrateWeight { fn demote_member(r: u32, ) -> Weight { Weight::from_ref_time(17_582_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } @@ -114,7 +114,7 @@ impl WeightInfo for SubstrateWeight { fn cleanup_poll(n: u32, ) -> Weight { Weight::from_ref_time(6_188_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } @@ -138,7 +138,7 @@ impl WeightInfo for () { fn remove_member(r: u32, ) -> Weight { Weight::from_ref_time(16_855_000 as RefTimeWeight) // Standard Error: 27_000 - .saturating_add(Weight::from_ref_time(8_107_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_107_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) @@ -151,7 +151,7 @@ impl WeightInfo for () { fn promote_member(r: u32, ) -> Weight { Weight::from_ref_time(11_936_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(9_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } @@ -162,7 +162,7 @@ impl WeightInfo for () { fn demote_member(r: u32, ) -> Weight { Weight::from_ref_time(17_582_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } @@ -180,7 +180,7 @@ impl WeightInfo for () { fn cleanup_poll(n: u32, ) -> Weight { Weight::from_ref_time(6_188_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) } diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index 8b82454d5849d..06a4759938964 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -72,7 +72,7 @@ impl WeightInfo for SubstrateWeight { fn create_recovery(n: u32, ) -> Weight { Weight::from_ref_time(28_217_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -88,7 +88,7 @@ impl WeightInfo for SubstrateWeight { fn vouch_recovery(n: u32, ) -> Weight { Weight::from_ref_time(22_038_000 as RefTimeWeight) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(307_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(307_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -98,7 +98,7 @@ impl WeightInfo for SubstrateWeight { fn claim_recovery(n: u32, ) -> Weight { Weight::from_ref_time(28_621_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(353_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(353_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -107,7 +107,7 @@ impl WeightInfo for SubstrateWeight { fn close_recovery(n: u32, ) -> Weight { Weight::from_ref_time(33_287_000 as RefTimeWeight) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(264_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(264_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -116,7 +116,7 @@ impl WeightInfo for SubstrateWeight { fn remove_recovery(n: u32, ) -> Weight { Weight::from_ref_time(31_964_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(222_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(222_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -144,7 +144,7 @@ impl WeightInfo for () { fn create_recovery(n: u32, ) -> Weight { Weight::from_ref_time(28_217_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -160,7 +160,7 @@ impl WeightInfo for () { fn vouch_recovery(n: u32, ) -> Weight { Weight::from_ref_time(22_038_000 as RefTimeWeight) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(307_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(307_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -170,7 +170,7 @@ impl WeightInfo for () { fn claim_recovery(n: u32, ) -> Weight { Weight::from_ref_time(28_621_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(353_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(353_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -179,7 +179,7 @@ impl WeightInfo for () { fn close_recovery(n: u32, ) -> Weight { Weight::from_ref_time(33_287_000 as RefTimeWeight) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(264_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(264_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -188,7 +188,7 @@ impl WeightInfo for () { fn remove_recovery(n: u32, ) -> Weight { Weight::from_ref_time(31_964_000 as RefTimeWeight) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(222_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(222_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } diff --git a/frame/referenda/src/branch.rs b/frame/referenda/src/branch.rs index 172b5af999df5..d3744979fc547 100644 --- a/frame/referenda/src/branch.rs +++ b/frame/referenda/src/branch.rs @@ -83,7 +83,7 @@ impl ServiceBranch { /// Return the maximum possible weight of the `nudge` function. pub fn max_weight_of_nudge, I: 'static>() -> frame_support::weights::Weight { - Weight::new() + Weight::zero() .max(T::WeightInfo::nudge_referendum_no_deposit()) .max(T::WeightInfo::nudge_referendum_preparing()) .max(T::WeightInfo::nudge_referendum_queued()) @@ -131,7 +131,7 @@ impl ServiceBranch { /// Return the maximum possible weight of the `place_decision_deposit` function. pub fn max_weight_of_deposit, I: 'static>() -> frame_support::weights::Weight { - Weight::new() + Weight::zero() .max(T::WeightInfo::place_decision_deposit_preparing()) .max(T::WeightInfo::place_decision_deposit_queued()) .max(T::WeightInfo::place_decision_deposit_not_queued()) @@ -172,7 +172,7 @@ impl OneFewerDecidingBranch { /// Return the maximum possible weight of the `one_fewer_deciding` function. pub fn max_weight, I: 'static>() -> frame_support::weights::Weight { - Weight::new() + Weight::zero() .max(T::WeightInfo::one_fewer_deciding_queue_empty()) .max(T::WeightInfo::one_fewer_deciding_passing()) .max(T::WeightInfo::one_fewer_deciding_failing()) diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index a098670ccf100..f33ef47cd67e8 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -54,7 +54,7 @@ impl WeightInfo for SubstrateWeight { fn store(l: u32, ) -> Weight { Weight::from_ref_time(13_140_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) } } @@ -65,7 +65,7 @@ impl WeightInfo for () { fn store(l: u32, ) -> Weight { Weight::from_ref_time(13_140_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) } } diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 56f9298dd4b0c..999a810d3b7c1 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -460,7 +460,7 @@ fn scheduler_respects_priority_ordering_with_soft_deadlines() { root(), Call::Logger(LoggerCall::log { i: 2600, - weight: max_weight / 2 - item_weight + Weight::one() + weight: max_weight / 2 - item_weight + Weight::from_ref_time(1) }) .into(), )); @@ -487,7 +487,8 @@ fn on_initialize_weight_is_correct() { None, 255, root(), - Call::Logger(LoggerCall::log { i: 3, weight: call_weight + Weight::one() }).into(), + Call::Logger(LoggerCall::log { i: 3, weight: call_weight + Weight::from_ref_time(1) }) + .into(), )); // Anon Periodic assert_ok!(Scheduler::do_schedule( diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index f201c89eaf278..9688c9f1a2f9f 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -70,7 +70,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { Weight::from_ref_time(9_994_000 as RefTimeWeight) // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(19_843_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(19_843_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -83,7 +83,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_named_resolved(s: u32, ) -> Weight { Weight::from_ref_time(10_318_000 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(15_451_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(15_451_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -95,7 +95,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_periodic_resolved(s: u32, ) -> Weight { Weight::from_ref_time(11_675_000 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(17_019_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_019_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -107,7 +107,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_resolved(s: u32, ) -> Weight { Weight::from_ref_time(11_934_000 as RefTimeWeight) // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(14_134_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(14_134_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -119,7 +119,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_named_aborted(s: u32, ) -> Weight { Weight::from_ref_time(7_279_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(5_388_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_388_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -130,7 +130,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_aborted(s: u32, ) -> Weight { Weight::from_ref_time(8_619_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_969_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_969_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -140,7 +140,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_periodic_named(s: u32, ) -> Weight { Weight::from_ref_time(16_129_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(9_772_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_772_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -150,7 +150,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_periodic(s: u32, ) -> Weight { Weight::from_ref_time(15_785_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(7_208_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(7_208_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -161,7 +161,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_named(s: u32, ) -> Weight { Weight::from_ref_time(15_778_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(5_597_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_597_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -170,7 +170,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize(s: u32, ) -> Weight { Weight::from_ref_time(15_912_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(4_530_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_530_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -178,7 +178,7 @@ impl WeightInfo for SubstrateWeight { fn schedule(s: u32, ) -> Weight { Weight::from_ref_time(18_013_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -187,7 +187,7 @@ impl WeightInfo for SubstrateWeight { fn cancel(s: u32, ) -> Weight { Weight::from_ref_time(18_131_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -196,7 +196,7 @@ impl WeightInfo for SubstrateWeight { fn schedule_named(s: u32, ) -> Weight { Weight::from_ref_time(21_230_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(98_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(98_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -205,7 +205,7 @@ impl WeightInfo for SubstrateWeight { fn cancel_named(s: u32, ) -> Weight { Weight::from_ref_time(20_139_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -220,7 +220,7 @@ impl WeightInfo for () { fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { Weight::from_ref_time(9_994_000 as RefTimeWeight) // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(19_843_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(19_843_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -233,7 +233,7 @@ impl WeightInfo for () { fn on_initialize_named_resolved(s: u32, ) -> Weight { Weight::from_ref_time(10_318_000 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(15_451_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(15_451_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -245,7 +245,7 @@ impl WeightInfo for () { fn on_initialize_periodic_resolved(s: u32, ) -> Weight { Weight::from_ref_time(11_675_000 as RefTimeWeight) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(17_019_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_019_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -257,7 +257,7 @@ impl WeightInfo for () { fn on_initialize_resolved(s: u32, ) -> Weight { Weight::from_ref_time(11_934_000 as RefTimeWeight) // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(14_134_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(14_134_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -269,7 +269,7 @@ impl WeightInfo for () { fn on_initialize_named_aborted(s: u32, ) -> Weight { Weight::from_ref_time(7_279_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(5_388_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_388_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) @@ -280,7 +280,7 @@ impl WeightInfo for () { fn on_initialize_aborted(s: u32, ) -> Weight { Weight::from_ref_time(8_619_000 as RefTimeWeight) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_969_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_969_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) @@ -290,7 +290,7 @@ impl WeightInfo for () { fn on_initialize_periodic_named(s: u32, ) -> Weight { Weight::from_ref_time(16_129_000 as RefTimeWeight) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(9_772_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_772_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -300,7 +300,7 @@ impl WeightInfo for () { fn on_initialize_periodic(s: u32, ) -> Weight { Weight::from_ref_time(15_785_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(7_208_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(7_208_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) @@ -311,7 +311,7 @@ impl WeightInfo for () { fn on_initialize_named(s: u32, ) -> Weight { Weight::from_ref_time(15_778_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(5_597_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_597_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -320,7 +320,7 @@ impl WeightInfo for () { fn on_initialize(s: u32, ) -> Weight { Weight::from_ref_time(15_912_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(4_530_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_530_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -328,7 +328,7 @@ impl WeightInfo for () { fn schedule(s: u32, ) -> Weight { Weight::from_ref_time(18_013_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -337,7 +337,7 @@ impl WeightInfo for () { fn cancel(s: u32, ) -> Weight { Weight::from_ref_time(18_131_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -346,7 +346,7 @@ impl WeightInfo for () { fn schedule_named(s: u32, ) -> Weight { Weight::from_ref_time(21_230_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(98_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(98_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -355,7 +355,7 @@ impl WeightInfo for () { fn cancel_named(s: u32, ) -> Weight { Weight::from_ref_time(20_139_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 626562f7a45f8..9717486644761 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -614,7 +614,7 @@ pub mod pallet { fn on_initialize(n: T::BlockNumber) -> Weight { let mut members = vec![]; - let mut weight = Weight::new(); + let mut weight = Weight::zero(); let weights = T::BlockWeights::get(); // Run a candidate/membership rotation diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index cda606008a9cc..107d494a9711b 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4250,7 +4250,7 @@ mod election_data_provider { fn targets_2sec_block() { let mut validators = 1000; while ::WeightInfo::get_npos_targets(validators) < - 2 * frame_support::weights::constants::WEIGHT_PER_SECOND + 2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND { validators += 1; } @@ -4268,7 +4268,7 @@ mod election_data_provider { let mut nominators = 1000; while ::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) < - 2 * frame_support::weights::constants::WEIGHT_PER_SECOND + 2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND { nominators += 1; } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index c5f584054d1f4..82ab44f428372 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -121,7 +121,7 @@ impl WeightInfo for SubstrateWeight { fn withdraw_unbonded_update(s: u32, ) -> Weight { Weight::from_ref_time(35_763_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(57_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(57_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -164,7 +164,7 @@ impl WeightInfo for SubstrateWeight { fn kick(k: u32, ) -> Weight { Weight::from_ref_time(23_264_000 as RefTimeWeight) // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(8_006_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_006_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) @@ -183,7 +183,7 @@ impl WeightInfo for SubstrateWeight { fn nominate(n: u32, ) -> Weight { Weight::from_ref_time(56_596_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(3_644_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_644_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) @@ -238,7 +238,7 @@ impl WeightInfo for SubstrateWeight { fn set_invulnerables(v: u32, ) -> Weight { Weight::from_ref_time(4_318_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(10_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(10_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking Bonded (r:1 w:1) @@ -257,7 +257,7 @@ impl WeightInfo for SubstrateWeight { fn force_unstake(s: u32, ) -> Weight { Weight::from_ref_time(65_265_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_029_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_029_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(11 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(12 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -266,7 +266,7 @@ impl WeightInfo for SubstrateWeight { fn cancel_deferred_slash(s: u32, ) -> Weight { Weight::from_ref_time(903_312_000 as RefTimeWeight) // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(4_968_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_968_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -283,7 +283,7 @@ impl WeightInfo for SubstrateWeight { fn payout_stakers_dead_controller(n: u32, ) -> Weight { Weight::from_ref_time(87_569_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(24_232_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(24_232_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(10 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -303,7 +303,7 @@ impl WeightInfo for SubstrateWeight { fn payout_stakers_alive_staked(n: u32, ) -> Weight { Weight::from_ref_time(98_839_000 as RefTimeWeight) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(34_480_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(34_480_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(11 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) @@ -318,7 +318,7 @@ impl WeightInfo for SubstrateWeight { fn rebond(l: u32, ) -> Weight { Weight::from_ref_time(74_865_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(64_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(64_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(9 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(8 as RefTimeWeight)) } @@ -334,7 +334,7 @@ impl WeightInfo for SubstrateWeight { fn set_history_depth(e: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 62_000 - .saturating_add(Weight::from_ref_time(22_829_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(22_829_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((7 as RefTimeWeight).saturating_mul(e as RefTimeWeight))) @@ -355,7 +355,7 @@ impl WeightInfo for SubstrateWeight { fn reap_stash(s: u32, ) -> Weight { Weight::from_ref_time(70_933_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_021_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_021_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(12 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -381,9 +381,9 @@ impl WeightInfo for SubstrateWeight { fn new_era(v: u32, n: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 897_000 - .saturating_add(Weight::from_ref_time(213_100_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(213_100_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(31_123_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(31_123_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(208 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) .saturating_add(T::DbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) @@ -401,11 +401,11 @@ impl WeightInfo for SubstrateWeight { fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(23_745_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(23_745_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(22_497_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(22_497_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 3_968_000 - .saturating_add(Weight::from_ref_time(20_676_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(20_676_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(202 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) .saturating_add(T::DbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) @@ -415,7 +415,7 @@ impl WeightInfo for SubstrateWeight { fn get_npos_targets(v: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 36_000 - .saturating_add(Weight::from_ref_time(8_097_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_097_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) } @@ -507,7 +507,7 @@ impl WeightInfo for () { fn withdraw_unbonded_update(s: u32, ) -> Weight { Weight::from_ref_time(35_763_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(57_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(57_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -550,7 +550,7 @@ impl WeightInfo for () { fn kick(k: u32, ) -> Weight { Weight::from_ref_time(23_264_000 as RefTimeWeight) // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(8_006_000 as RefTimeWeight).scalar_saturating_mul(k as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_006_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) @@ -569,7 +569,7 @@ impl WeightInfo for () { fn nominate(n: u32, ) -> Weight { Weight::from_ref_time(56_596_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(3_644_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_644_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) @@ -624,7 +624,7 @@ impl WeightInfo for () { fn set_invulnerables(v: u32, ) -> Weight { Weight::from_ref_time(4_318_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(10_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(10_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } // Storage: Staking Bonded (r:1 w:1) @@ -643,7 +643,7 @@ impl WeightInfo for () { fn force_unstake(s: u32, ) -> Weight { Weight::from_ref_time(65_265_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_029_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_029_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(11 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(12 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -652,7 +652,7 @@ impl WeightInfo for () { fn cancel_deferred_slash(s: u32, ) -> Weight { Weight::from_ref_time(903_312_000 as RefTimeWeight) // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(4_968_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_968_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -669,7 +669,7 @@ impl WeightInfo for () { fn payout_stakers_dead_controller(n: u32, ) -> Weight { Weight::from_ref_time(87_569_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(24_232_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(24_232_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(10 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) @@ -689,7 +689,7 @@ impl WeightInfo for () { fn payout_stakers_alive_staked(n: u32, ) -> Weight { Weight::from_ref_time(98_839_000 as RefTimeWeight) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(34_480_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(34_480_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(11 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) @@ -704,7 +704,7 @@ impl WeightInfo for () { fn rebond(l: u32, ) -> Weight { Weight::from_ref_time(74_865_000 as RefTimeWeight) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(64_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(64_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(9 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(8 as RefTimeWeight)) } @@ -720,7 +720,7 @@ impl WeightInfo for () { fn set_history_depth(e: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 62_000 - .saturating_add(Weight::from_ref_time(22_829_000 as RefTimeWeight).scalar_saturating_mul(e as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(22_829_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((7 as RefTimeWeight).saturating_mul(e as RefTimeWeight))) @@ -741,7 +741,7 @@ impl WeightInfo for () { fn reap_stash(s: u32, ) -> Weight { Weight::from_ref_time(70_933_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_021_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_021_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(12 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) @@ -767,9 +767,9 @@ impl WeightInfo for () { fn new_era(v: u32, n: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 897_000 - .saturating_add(Weight::from_ref_time(213_100_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(213_100_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(31_123_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(31_123_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(208 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) .saturating_add(RocksDbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) @@ -787,11 +787,11 @@ impl WeightInfo for () { fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(23_745_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(23_745_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(22_497_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(22_497_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 3_968_000 - .saturating_add(Weight::from_ref_time(20_676_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(20_676_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(202 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) .saturating_add(RocksDbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) @@ -801,7 +801,7 @@ impl WeightInfo for () { fn get_npos_targets(v: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 36_000 - .saturating_add(Weight::from_ref_time(8_097_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_097_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) } diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 93b5bd3468f6b..e29115382819a 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -842,7 +842,7 @@ pub mod pallet { let items = items as u64; ::DbWeight::get() .reads_writes(1, 1) - .scalar_saturating_mul(items) + .saturating_mul(items) // we assume that the read/write per-byte weight is the same for child and top tree. .saturating_add(T::WeightInfo::process_top_key(size)) } @@ -1246,7 +1246,7 @@ mod mock { pub(crate) fn run_to_block(n: u32) -> (H256, Weight) { let mut root = Default::default(); - let mut weight_sum = Weight::new(); + let mut weight_sum = Weight::zero(); log::trace!(target: LOG_TARGET, "running from {:?} to {:?}", System::block_number(), n); while System::block_number() < n { System::set_block_number(System::block_number() + 1); @@ -1622,7 +1622,7 @@ pub(crate) mod remote_tests { n: ::BlockNumber, ) -> (H256, Weight) { let mut root = Default::default(); - let mut weight_sum = Weight::new(); + let mut weight_sum = Weight::zero(); while System::::block_number() < n { System::::set_block_number(System::::block_number() + One::one()); System::::on_initialize(System::::block_number()); diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs index 6fccc0b68f3d7..1967874157f75 100644 --- a/frame/state-trie-migration/src/weights.rs +++ b/frame/state-trie-migration/src/weights.rs @@ -90,7 +90,7 @@ impl WeightInfo for SubstrateWeight { fn process_top_key(v: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -132,7 +132,7 @@ impl WeightInfo for () { fn process_top_key(v: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } diff --git a/frame/sudo/src/tests.rs b/frame/sudo/src/tests.rs index 502c6476935a2..0508772cc88ec 100644 --- a/frame/sudo/src/tests.rs +++ b/frame/sudo/src/tests.rs @@ -62,8 +62,10 @@ fn sudo_emits_events_correctly() { System::set_block_number(1); // Should emit event to indicate success when called with the root `key` and `call` is `Ok`. - let call = - Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::one() })); + let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + i: 42, + weight: Weight::from_ref_time(1), + })); assert_ok!(Sudo::sudo(Origin::signed(1), call)); System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) })); }) @@ -97,8 +99,10 @@ fn sudo_unchecked_weight_basics() { assert_eq!(Logger::i32_log(), vec![42i32]); // Controls the dispatched weight. - let call = - Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::one() })); + let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + i: 42, + weight: Weight::from_ref_time(1), + })); let sudo_unchecked_weight_call = SudoCall::sudo_unchecked_weight { call, weight: Weight::from_ref_time(1_000) }; let info = sudo_unchecked_weight_call.get_dispatch_info(); @@ -113,8 +117,10 @@ fn sudo_unchecked_weight_emits_events_correctly() { System::set_block_number(1); // Should emit event to indicate success when called with the root `key` and `call` is `Ok`. - let call = - Box::new(Call::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::one() })); + let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + i: 42, + weight: Weight::from_ref_time(1), + })); assert_ok!(Sudo::sudo_unchecked_weight( Origin::signed(1), call, @@ -167,13 +173,17 @@ fn sudo_as_basics() { assert!(Logger::account_log().is_empty()); // A non-privileged function should not work when called with a non-root `key`. - let call = - Box::new(Call::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::one() })); + let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { + i: 42, + weight: Weight::from_ref_time(1), + })); assert_noop!(Sudo::sudo_as(Origin::signed(3), 2, call), Error::::RequireSudo); // A non-privileged function will work when passed to `sudo_as` with the root `key`. - let call = - Box::new(Call::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::one() })); + let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { + i: 42, + weight: Weight::from_ref_time(1), + })); assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); assert_eq!(Logger::i32_log(), vec![42i32]); // The correct user makes the call within `sudo_as`. @@ -188,8 +198,10 @@ fn sudo_as_emits_events_correctly() { System::set_block_number(1); // A non-privileged function will work when passed to `sudo_as` with the root `key`. - let call = - Box::new(Call::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::one() })); + let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { + i: 42, + weight: Weight::from_ref_time(1), + })); assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); System::assert_has_event(TestEvent::Sudo(Event::SudoAsDone { sudo_result: Ok(()) })); }); diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 94974888c1d5c..fc976b03556a4 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -1643,7 +1643,7 @@ macro_rules! decl_module { pallet_name, ); - $crate::dispatch::Weight::new() + $crate::dispatch::Weight::zero() } #[cfg(feature = "try-runtime")] diff --git a/frame/support/src/migrations.rs b/frame/support/src/migrations.rs index b559d3aca615f..63679fd56d667 100644 --- a/frame/support/src/migrations.rs +++ b/frame/support/src/migrations.rs @@ -48,7 +48,7 @@ impl PalletVersionToStorageVersionHelpe #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl PalletVersionToStorageVersionHelper for T { fn migrate(db_weight: &RuntimeDbWeight) -> Weight { - let mut weight = Weight::new(); + let mut weight = Weight::zero(); for_tuples!( #( weight = weight.saturating_add(T::migrate(db_weight)); )* ); diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index e8cd87823f3c3..25ec333a7dbe0 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -35,7 +35,7 @@ pub trait OnInitialize { /// including inherent extrinsics. Hence for instance, if you runtime includes /// `pallet_timestamp`, the `timestamp` is not yet up to date at this point. fn on_initialize(_n: BlockNumber) -> Weight { - Weight::new() + Weight::zero() } } @@ -44,7 +44,7 @@ pub trait OnInitialize { #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnInitialize for Tuple { fn on_initialize(n: BlockNumber) -> Weight { - let mut weight = Weight::new(); + let mut weight = Weight::zero(); for_tuples!( #( weight = weight.saturating_add(Tuple::on_initialize(n.clone())); )* ); weight } @@ -77,7 +77,7 @@ pub trait OnIdle { /// NOTE: This function is called AFTER ALL extrinsics - including inherent extrinsics - /// in a block are applied but before `on_finalize` is executed. fn on_idle(_n: BlockNumber, _remaining_weight: Weight) -> Weight { - Weight::new() + Weight::zero() } } @@ -88,7 +88,7 @@ impl OnIdle for Tuple { fn on_idle(n: BlockNumber, remaining_weight: Weight) -> Weight { let on_idle_functions: &[fn(BlockNumber, Weight) -> Weight] = &[for_tuples!( #( Tuple::on_idle ),* )]; - let mut weight = Weight::new(); + let mut weight = Weight::zero(); let len = on_idle_functions.len(); let start_index = n % (len as u32).into(); let start_index = start_index.try_into().ok().expect( @@ -130,7 +130,7 @@ pub trait OnRuntimeUpgrade { /// /// Return the non-negotiable weight consumed for runtime upgrade. fn on_runtime_upgrade() -> Weight { - Weight::new() + Weight::zero() } /// Execute some pre-checks prior to a runtime upgrade. @@ -155,7 +155,7 @@ pub trait OnRuntimeUpgrade { #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnRuntimeUpgrade for Tuple { fn on_runtime_upgrade() -> Weight { - let mut weight = Weight::new(); + let mut weight = Weight::zero(); for_tuples!( #( weight = weight.saturating_add(Tuple::on_runtime_upgrade()); )* ); weight } @@ -199,14 +199,14 @@ pub trait Hooks { /// Return the weight used, the hook will subtract it from current weight used /// and pass the result to the next `on_idle` hook if it exists. fn on_idle(_n: BlockNumber, _remaining_weight: Weight) -> Weight { - Weight::new() + Weight::zero() } /// The block is being initialized. Implement to have something happen. /// /// Return the non-negotiable weight consumed in the block. fn on_initialize(_n: BlockNumber) -> Weight { - Weight::new() + Weight::zero() } /// Perform a module upgrade. @@ -229,7 +229,7 @@ pub trait Hooks { /// logic as a free-function from your pallet, and pass it to `type Executive` from the /// top-level runtime. fn on_runtime_upgrade() -> Weight { - Weight::new() + Weight::zero() } /// Execute the sanity checks of this pallet, per block. diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index 568cb5535ccda..dab7f4a2746cf 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -650,7 +650,7 @@ impl PerDispatchClass { impl PerDispatchClass { /// Returns the total weight consumed by all extrinsics in the block. pub fn total(&self) -> Weight { - let mut sum = Weight::new(); + let mut sum = Weight::zero(); for class in DispatchClass::all() { sum = sum.saturating_add(*self.get(*class)); } diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index 93a80d12db96b..51f707b2b0df5 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -53,7 +53,7 @@ parameter_types! { /// 99th: 5_489_273 /// 95th: 5_433_314 /// 75th: 5_354_812 - pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul(5_346_284); + pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(5_346_284); } #[cfg(test)] @@ -68,8 +68,8 @@ mod test_weights { let w = super::BlockExecutionWeight::get(); // At least 100 µs. - assert!(w >= 100 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); + assert!(w >= 100u32 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); // At most 50 ms. - assert!(w <= 50 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms."); + assert!(w <= 50u32 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms."); } } diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index d223eb7c10efc..2bee1059b0dad 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -53,7 +53,7 @@ parameter_types! { /// 99th: 86_924 /// 95th: 86_828 /// 75th: 86_347 - pub const ExtrinsicBaseWeight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul(86_298); + pub const ExtrinsicBaseWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(86_298); } #[cfg(test)] @@ -68,7 +68,7 @@ mod test_weights { let w = super::ExtrinsicBaseWeight::get(); // At least 10 µs. - assert!(w >= 10 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs."); + assert!(w >= 10u32 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs."); // At most 1 ms. assert!(w <= constants::WEIGHT_PER_MILLIS, "Weight should be at most 1 ms."); } diff --git a/frame/support/src/weights/weight_v2.rs b/frame/support/src/weights/weight_v2.rs index d02aac3268838..bcda6358c965f 100644 --- a/frame/support/src/weights/weight_v2.rs +++ b/frame/support/src/weights/weight_v2.rs @@ -18,8 +18,8 @@ use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign}; use sp_runtime::{ - traits::{Bounded, CheckedAdd, CheckedSub, One, Zero}, - Perquintill, RuntimeDebug, + traits::{Bounded, CheckedAdd, CheckedSub, Zero}, + RuntimeDebug, }; use super::*; @@ -50,11 +50,6 @@ pub struct Weight { } impl Weight { - /// Create a new Weight with zero. - pub const fn new() -> Self { - Self { ref_time: 0 } - } - /// Set the reference time part of the weight. pub const fn set_ref_time(mut self, c: RefTimeWeight) -> Self { self.ref_time = c; @@ -93,27 +88,84 @@ impl Weight { } } - /// Construct with reference time weight. + /// Construct [`Weight`] with reference time weight. pub const fn from_ref_time(ref_time: RefTimeWeight) -> Self { Self { ref_time } } - pub fn checked_mul(self, rhs: u64) -> Option { - let ref_time = self.ref_time.checked_mul(rhs)?; - Some(Self { ref_time }) + /// Saturating [`Weight`] addition. Computes `self + rhs`, saturating at the numeric bounds of + /// all fields instead of overflowing. + pub const fn saturating_add(self, rhs: Self) -> Self { + Self { ref_time: self.ref_time.saturating_add(rhs.ref_time) } + } + + /// Saturating [`Weight`] subtraction. Computes `self - rhs`, saturating at the numeric bounds + /// of all fields instead of overflowing. + pub const fn saturating_sub(self, rhs: Self) -> Self { + Self { ref_time: self.ref_time.saturating_sub(rhs.ref_time) } + } + + /// Saturating [`Weight`] scalar multiplication. Computes `self.field * scalar` for all fields, + /// saturating at the numeric bounds of all fields instead of overflowing. + pub const fn saturating_mul(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time.saturating_mul(scalar) } } - pub fn checked_div(self, rhs: u64) -> Option { - let ref_time = self.ref_time.checked_div(rhs)?; - Some(Self { ref_time }) + /// Saturating [`Weight`] scalar division. Computes `self.field / scalar` for all fields, + /// saturating at the numeric bounds of all fields instead of overflowing. + pub const fn saturating_div(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time.saturating_div(scalar) } } - pub const fn scalar_saturating_mul(self, rhs: u64) -> Self { - Self { ref_time: self.ref_time.saturating_mul(rhs) } + /// Saturating [`Weight`] scalar exponentiation. Computes `self.field.pow(exp)` for all fields, + /// saturating at the numeric bounds of all fields instead of overflowing. + pub const fn saturating_pow(self, exp: u32) -> Self { + Self { ref_time: self.ref_time.saturating_pow(exp) } } - pub const fn scalar_div(self, rhs: u64) -> Self { - Self { ref_time: self.ref_time / rhs } + /// Increment [`Weight`] by `amount` via saturating addition. + pub fn saturating_accrue(&mut self, amount: Self) { + *self = self.saturating_add(amount); + } + + /// Checked [`Weight`] addition. Computes `self + rhs`, returning `None` if overflow occurred. + pub const fn checked_add(&self, rhs: &Self) -> Option { + match self.ref_time.checked_add(rhs.ref_time) { + Some(ref_time) => Some(Self { ref_time }), + None => None, + } + } + + /// Checked [`Weight`] subtraction. Computes `self - rhs`, returning `None` if overflow + /// occurred. + pub const fn checked_sub(&self, rhs: &Self) -> Option { + match self.ref_time.checked_sub(rhs.ref_time) { + Some(ref_time) => Some(Self { ref_time }), + None => None, + } + } + + /// Checked [`Weight`] scalar multiplication. Computes `self.field * scalar` for each field, + /// returning `None` if overflow occurred. + pub const fn checked_mul(self, scalar: u64) -> Option { + match self.ref_time.checked_mul(scalar) { + Some(ref_time) => Some(Self { ref_time }), + None => None, + } + } + + /// Checked [`Weight`] scalar division. Computes `self.field / scalar` for each field, returning + /// `None` if overflow occurred. + pub const fn checked_div(self, scalar: u64) -> Option { + match self.ref_time.checked_div(scalar) { + Some(ref_time) => Some(Self { ref_time }), + None => None, + } + } + + /// Return a [`Weight`] where all fields are zero. + pub const fn zero() -> Self { + Self { ref_time: 0 } } } @@ -127,12 +179,6 @@ impl Zero for Weight { } } -impl One for Weight { - fn one() -> Self { - Self::one() - } -} - impl Add for Weight { type Output = Self; fn add(self, rhs: Self) -> Self { @@ -147,13 +193,6 @@ impl Sub for Weight { } } -impl Mul for Weight { - type Output = Self; - fn mul(self, b: Self) -> Self { - Self { ref_time: b.ref_time * self.ref_time } - } -} - impl Mul for Weight where T: Mul + Copy, @@ -164,26 +203,39 @@ where } } -impl Mul for Perbill { - type Output = Weight; - fn mul(self, b: Weight) -> Weight { - Weight { ref_time: self * b.ref_time } +macro_rules! weight_mul_per_impl { + ($($t:ty),* $(,)?) => { + $( + impl Mul for $t { + type Output = Weight; + fn mul(self, b: Weight) -> Weight { + Weight { ref_time: self * b.ref_time } + } + } + )* } } +weight_mul_per_impl!( + sp_runtime::Percent, + sp_runtime::PerU16, + sp_runtime::Permill, + sp_runtime::Perbill, + sp_runtime::Perquintill, +); -impl Mul for Perquintill { - type Output = Weight; - fn mul(self, b: Weight) -> Weight { - Weight { ref_time: self * b.ref_time } - } -} - -impl Mul for u64 { - type Output = Weight; - fn mul(self, b: Weight) -> Weight { - Weight { ref_time: self * b.ref_time } +macro_rules! weight_mul_primitive_impl { + ($($t:ty),* $(,)?) => { + $( + impl Mul for $t { + type Output = Weight; + fn mul(self, b: Weight) -> Weight { + Weight { ref_time: u64::from(self) * b.ref_time } + } + } + )* } } +weight_mul_primitive_impl!(u8, u16, u32, u64); impl Div for Weight where @@ -196,24 +248,6 @@ where } } -impl Saturating for Weight { - fn saturating_add(self, rhs: Self) -> Self { - self.saturating_add(rhs) - } - - fn saturating_sub(self, rhs: Self) -> Self { - self.saturating_sub(rhs) - } - - fn saturating_mul(self, rhs: Self) -> Self { - self.saturating_mul(rhs) - } - - fn saturating_pow(self, exp: usize) -> Self { - self.saturating_pow(exp) - } -} - impl CheckedAdd for Weight { fn checked_add(&self, rhs: &Self) -> Option { self.checked_add(rhs) @@ -344,53 +378,12 @@ impl sp_runtime::traits::Printable for Weight { } } -// Re-export common functions so you do not need to import trait. -impl Weight { - pub const fn zero() -> Self { - Self { ref_time: 0 } - } - - pub const fn one() -> Self { - Self { ref_time: 1 } - } - - pub const fn saturating_add(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time.saturating_add(rhs.ref_time) } - } - - pub const fn saturating_sub(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time.saturating_sub(rhs.ref_time) } - } - - pub const fn saturating_mul(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time.saturating_mul(rhs.ref_time) } - } - - pub const fn saturating_pow(self, exp: usize) -> Self { - Self { ref_time: self.ref_time.saturating_pow(exp as u32) } - } - - pub const fn checked_add(&self, rhs: &Self) -> Option { - match self.ref_time.checked_add(rhs.ref_time) { - Some(ref_time) => Some(Self { ref_time }), - None => None, - } - } - - pub const fn checked_sub(&self, rhs: &Self) -> Option { - match self.ref_time.checked_sub(rhs.ref_time) { - Some(ref_time) => Some(Self { ref_time }), - None => None, - } - } -} - // TODO: Eventually remove these impl From> for PostDispatchInfo { fn from(maybe_actual_computation: Option) -> Self { let actual_weight = match maybe_actual_computation { - Some(actual_computation) => Some(Weight::new().set_ref_time(actual_computation)), + Some(actual_computation) => Some(Weight::zero().set_ref_time(actual_computation)), None => None, }; Self { actual_weight, pays_fee: Default::default() } @@ -401,7 +394,7 @@ impl From<(Option, Pays)> for PostDispatchInfo { fn from(post_weight_info: (Option, Pays)) -> Self { let (maybe_actual_time, pays_fee) = post_weight_info; let actual_weight = match maybe_actual_time { - Some(actual_time) => Some(Weight::new().set_ref_time(actual_time)), + Some(actual_time) => Some(Weight::zero().set_ref_time(actual_time)), None => None, }; Self { actual_weight, pays_fee } @@ -410,7 +403,7 @@ impl From<(Option, Pays)> for PostDispatchInfo { impl WeighData for RefTimeWeight { fn weigh_data(&self, _: T) -> Weight { - return Weight::new().set_ref_time(*self) + return Weight::zero().set_ref_time(*self) } } diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index b7232c430696d..d6434b6c63d8a 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -322,7 +322,7 @@ mod tests { new_test_ext().execute_with(|| { let max = DispatchInfo { weight: block_weights().get(DispatchClass::Normal).max_extrinsic.unwrap() + - Weight::one(), + Weight::from_ref_time(1), class: DispatchClass::Normal, ..Default::default() }; @@ -348,7 +348,7 @@ mod tests { let okay = DispatchInfo { weight, class: DispatchClass::Operational, ..Default::default() }; let max = DispatchInfo { - weight: weight + Weight::one(), + weight: weight + Weight::from_ref_time(1), class: DispatchClass::Operational, ..Default::default() }; @@ -532,7 +532,7 @@ mod tests { let medium = DispatchInfo { weight: normal_limit - base_extrinsic, ..Default::default() }; let big = DispatchInfo { - weight: normal_limit - base_extrinsic + Weight::one(), + weight: normal_limit - base_extrinsic + Weight::from_ref_time(1), ..Default::default() }; let len = 0_usize; @@ -551,7 +551,7 @@ mod tests { reset_check_weight(&small, false, Weight::zero()); reset_check_weight(&medium, false, Weight::zero()); - reset_check_weight(&big, true, Weight::one()); + reset_check_weight(&big, true, Weight::from_ref_time(1)); }) } diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index d9be460b3a4fb..7626c7e8665e6 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -204,7 +204,7 @@ pub struct BlockWeights { impl Default for BlockWeights { fn default() -> Self { - Self::with_sensible_defaults(1 * constants::WEIGHT_PER_SECOND, DEFAULT_NORMAL_RATIO) + Self::with_sensible_defaults(1u32 * constants::WEIGHT_PER_SECOND, DEFAULT_NORMAL_RATIO) } } @@ -295,9 +295,9 @@ impl BlockWeights { /// is not suitable for production deployments. pub fn simple_max(block_weight: Weight) -> Self { Self::builder() - .base_block(Weight::new()) + .base_block(Weight::zero()) .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = Weight::new(); + weights.base_extrinsic = Weight::zero(); }) .for_class(DispatchClass::non_mandatory(), |weights| { weights.max_total = block_weight.into(); diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index 4f7f168eb55ab..8b6c291096d5a 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -65,7 +65,7 @@ impl WeightInfo for SubstrateWeight { fn remark_with_event(b: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) } // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) @@ -79,7 +79,7 @@ impl WeightInfo for SubstrateWeight { fn set_storage(i: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(603_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(603_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) @@ -87,7 +87,7 @@ impl WeightInfo for SubstrateWeight { fn kill_storage(i: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(513_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(513_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) @@ -95,7 +95,7 @@ impl WeightInfo for SubstrateWeight { fn kill_prefix(p: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_026_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_026_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) } } @@ -110,7 +110,7 @@ impl WeightInfo for () { fn remark_with_event(b: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) } // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) @@ -124,7 +124,7 @@ impl WeightInfo for () { fn set_storage(i: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(603_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(603_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) @@ -132,7 +132,7 @@ impl WeightInfo for () { fn kill_storage(i: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(513_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(513_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) } // Storage: Skipped Metadata (r:0 w:0) @@ -140,7 +140,7 @@ impl WeightInfo for () { fn kill_prefix(p: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_026_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_026_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 6fd4ccc7478f6..106e5e163f02d 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -60,7 +60,7 @@ impl WeightInfo for SubstrateWeight { fn report_awesome(r: u32, ) -> Weight { Weight::from_ref_time(30_669_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -77,9 +77,9 @@ impl WeightInfo for SubstrateWeight { fn tip_new(r: u32, t: u32, ) -> Weight { Weight::from_ref_time(20_385_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(166_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(166_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -88,7 +88,7 @@ impl WeightInfo for SubstrateWeight { fn tip(t: u32, ) -> Weight { Weight::from_ref_time(12_287_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(363_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(363_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -99,7 +99,7 @@ impl WeightInfo for SubstrateWeight { fn close_tip(t: u32, ) -> Weight { Weight::from_ref_time(45_656_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(276_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(276_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -108,7 +108,7 @@ impl WeightInfo for SubstrateWeight { fn slash_tip(t: u32, ) -> Weight { Weight::from_ref_time(18_525_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -121,7 +121,7 @@ impl WeightInfo for () { fn report_awesome(r: u32, ) -> Weight { Weight::from_ref_time(30_669_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -138,9 +138,9 @@ impl WeightInfo for () { fn tip_new(r: u32, t: u32, ) -> Weight { Weight::from_ref_time(20_385_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).scalar_saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(166_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(166_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -149,7 +149,7 @@ impl WeightInfo for () { fn tip(t: u32, ) -> Weight { Weight::from_ref_time(12_287_000 as RefTimeWeight) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(363_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(363_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -160,7 +160,7 @@ impl WeightInfo for () { fn close_tip(t: u32, ) -> Weight { Weight::from_ref_time(45_656_000 as RefTimeWeight) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(276_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(276_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -169,7 +169,7 @@ impl WeightInfo for () { fn slash_tip(t: u32, ) -> Weight { Weight::from_ref_time(18_525_000 as RefTimeWeight) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).scalar_saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index a296a52b5e840..a17d564d7a334 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -59,7 +59,7 @@ const CALL: &::Call = &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::new()); + static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::zero()); } pub struct BlockWeights; diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 9777d7d240491..16986203de1e5 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -845,7 +845,7 @@ mod tests { &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::new()); + static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::zero()); } pub struct BlockWeights; diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index 54d5b0723aad6..04fa4e3048c22 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -61,7 +61,7 @@ impl WeightInfo for SubstrateWeight { fn store(l: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -99,7 +99,7 @@ impl WeightInfo for () { fn store(l: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index eecf225beea9b..cd4d9cf036abe 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -500,7 +500,7 @@ impl, I: 'static> Pallet { /// Spend some money! returns number of approvals before spend. pub fn spend_funds() -> Weight { - let mut total_weight = Weight::new(); + let mut total_weight = Weight::zero(); let mut budget_remaining = Self::pot(); Self::deposit_event(Event::Spending { budget_remaining }); diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index 74e6e9779000e..d2a5bc9f1f258 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -81,7 +81,7 @@ impl WeightInfo for SubstrateWeight { fn approve_proposal(p: u32, ) -> Weight { Weight::from_ref_time(10_786_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(110_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(110_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) } @@ -98,7 +98,7 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_proposals(p: u32, ) -> Weight { Weight::from_ref_time(25_805_000 as RefTimeWeight) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(28_473_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(28_473_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) @@ -134,7 +134,7 @@ impl WeightInfo for () { fn approve_proposal(p: u32, ) -> Weight { Weight::from_ref_time(10_786_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(110_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(110_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) } @@ -151,7 +151,7 @@ impl WeightInfo for () { fn on_initialize_proposals(p: u32, ) -> Weight { Weight::from_ref_time(25_805_000 as RefTimeWeight) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(28_473_000 as RefTimeWeight).scalar_saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(28_473_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 4ed01e463cc86..dae72accd2adc 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -105,11 +105,11 @@ impl WeightInfo for SubstrateWeight { fn destroy(n: u32, m: u32, a: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(13_639_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(13_639_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_393_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_393_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_217_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_217_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) @@ -150,7 +150,7 @@ impl WeightInfo for SubstrateWeight { fn redeposit(i: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 24_000 - .saturating_add(Weight::from_ref_time(15_540_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(15_540_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) @@ -322,11 +322,11 @@ impl WeightInfo for () { fn destroy(n: u32, m: u32, a: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(13_639_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(13_639_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_393_000 as RefTimeWeight).scalar_saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_393_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_217_000 as RefTimeWeight).scalar_saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_217_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) @@ -367,7 +367,7 @@ impl WeightInfo for () { fn redeposit(i: u32, ) -> Weight { Weight::from_ref_time(0 as RefTimeWeight) // Standard Error: 24_000 - .saturating_add(Weight::from_ref_time(15_540_000 as RefTimeWeight).scalar_saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(15_540_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 3df12d69e84eb..2209bc65d4958 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -185,7 +185,7 @@ pub mod pallet { let dispatch_infos = calls.iter().map(|call| call.get_dispatch_info()).collect::>(); let dispatch_weight = dispatch_infos.iter() .map(|di| di.weight) - .fold(Weight::new(), |total: Weight, weight: Weight| total.saturating_add(weight)) + .fold(Weight::zero(), |total: Weight, weight: Weight| total.saturating_add(weight)) .saturating_add(T::WeightInfo::batch(calls.len() as u32)); let dispatch_class = { let all_operational = dispatch_infos.iter() @@ -208,7 +208,7 @@ pub mod pallet { ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); // Track the actual weight of each of the batch calls. - let mut weight = Weight::new(); + let mut weight = Weight::zero(); for (index, call) in calls.into_iter().enumerate() { let info = call.get_dispatch_info(); // If origin is root, don't apply any dispatch filters; root can call anything. @@ -301,7 +301,7 @@ pub mod pallet { let dispatch_infos = calls.iter().map(|call| call.get_dispatch_info()).collect::>(); let dispatch_weight = dispatch_infos.iter() .map(|di| di.weight) - .fold(Weight::new(), |total: Weight, weight: Weight| total.saturating_add(weight)) + .fold(Weight::zero(), |total: Weight, weight: Weight| total.saturating_add(weight)) .saturating_add(T::WeightInfo::batch_all(calls.len() as u32)); let dispatch_class = { let all_operational = dispatch_infos.iter() @@ -324,7 +324,7 @@ pub mod pallet { ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); // Track the actual weight of each of the batch calls. - let mut weight = Weight::new(); + let mut weight = Weight::zero(); for (index, call) in calls.into_iter().enumerate() { let info = call.get_dispatch_info(); // If origin is root, bypass any dispatch filter; root can call anything. @@ -429,7 +429,7 @@ pub mod pallet { ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); // Track the actual weight of each of the batch calls. - let mut weight = Weight::new(); + let mut weight = Weight::zero(); // Track failed dispatch occur. let mut has_error: bool = false; for call in calls.into_iter() { diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index e3b16b5244fc0..09a2c6a4e4d38 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -420,7 +420,7 @@ fn batch_handles_weight_refund() { let good_call = call_foobar(false, start_weight, Some(end_weight)); let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call]; - let batch_len = Weight::from_ref_time(batch_calls.len() as u64); + let batch_len = batch_calls.len() as u64; let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); @@ -533,7 +533,7 @@ fn batch_all_handles_weight_refund() { let good_call = call_foobar(false, start_weight, Some(end_weight)); let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call]; - let batch_len = Weight::from_ref_time(batch_calls.len() as u64); + let batch_len = batch_calls.len() as u64; let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 0f0d171d8d4ee..1df9c2e67cc1f 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -60,7 +60,7 @@ impl WeightInfo for SubstrateWeight { fn batch(c: u32, ) -> Weight { Weight::from_ref_time(23_113_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_701_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_701_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) } fn as_derivative() -> Weight { Weight::from_ref_time(4_182_000 as RefTimeWeight) @@ -69,7 +69,7 @@ impl WeightInfo for SubstrateWeight { fn batch_all(c: u32, ) -> Weight { Weight::from_ref_time(18_682_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_794_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_794_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) } fn dispatch_as() -> Weight { Weight::from_ref_time(12_049_000 as RefTimeWeight) @@ -78,7 +78,7 @@ impl WeightInfo for SubstrateWeight { fn force_batch(c: u32, ) -> Weight { Weight::from_ref_time(19_136_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_697_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_697_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) } } @@ -88,7 +88,7 @@ impl WeightInfo for () { fn batch(c: u32, ) -> Weight { Weight::from_ref_time(23_113_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_701_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_701_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) } fn as_derivative() -> Weight { Weight::from_ref_time(4_182_000 as RefTimeWeight) @@ -97,7 +97,7 @@ impl WeightInfo for () { fn batch_all(c: u32, ) -> Weight { Weight::from_ref_time(18_682_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_794_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_794_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) } fn dispatch_as() -> Weight { Weight::from_ref_time(12_049_000 as RefTimeWeight) @@ -106,6 +106,6 @@ impl WeightInfo for () { fn force_batch(c: u32, ) -> Weight { Weight::from_ref_time(19_136_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_697_000 as RefTimeWeight).scalar_saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_697_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index bd3af72cdd182..5988b0bd47d54 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -62,9 +62,9 @@ impl WeightInfo for SubstrateWeight { fn vest_locked(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(32_978_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(82_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(82_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(88_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(88_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -73,9 +73,9 @@ impl WeightInfo for SubstrateWeight { fn vest_unlocked(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(32_856_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) } @@ -85,9 +85,9 @@ impl WeightInfo for SubstrateWeight { fn vest_other_locked(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(33_522_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(74_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(74_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(72_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(72_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -97,9 +97,9 @@ impl WeightInfo for SubstrateWeight { fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(32_558_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(61_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(61_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -109,9 +109,9 @@ impl WeightInfo for SubstrateWeight { fn vested_transfer(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(49_260_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -121,9 +121,9 @@ impl WeightInfo for SubstrateWeight { fn force_vested_transfer(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(49_166_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(43_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(43_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) } @@ -133,9 +133,9 @@ impl WeightInfo for SubstrateWeight { fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(34_042_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(83_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(83_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -145,9 +145,9 @@ impl WeightInfo for SubstrateWeight { fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(33_937_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -160,9 +160,9 @@ impl WeightInfo for () { fn vest_locked(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(32_978_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(82_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(82_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(88_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(88_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -171,9 +171,9 @@ impl WeightInfo for () { fn vest_unlocked(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(32_856_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) } @@ -183,9 +183,9 @@ impl WeightInfo for () { fn vest_other_locked(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(33_522_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(74_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(74_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(72_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(72_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -195,9 +195,9 @@ impl WeightInfo for () { fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(32_558_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(61_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(61_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -207,9 +207,9 @@ impl WeightInfo for () { fn vested_transfer(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(49_260_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -219,9 +219,9 @@ impl WeightInfo for () { fn force_vested_transfer(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(49_166_000 as RefTimeWeight) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(43_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(43_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) } @@ -231,9 +231,9 @@ impl WeightInfo for () { fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(34_042_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(83_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(83_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } @@ -243,9 +243,9 @@ impl WeightInfo for () { fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { Weight::from_ref_time(33_937_000 as RefTimeWeight) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).scalar_saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).scalar_saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } diff --git a/frame/whitelist/src/tests.rs b/frame/whitelist/src/tests.rs index 3e20cd29efb4f..24974bd726d43 100644 --- a/frame/whitelist/src/tests.rs +++ b/frame/whitelist/src/tests.rs @@ -99,7 +99,7 @@ fn test_whitelist_call_and_execute() { Whitelist::dispatch_whitelisted_call( Origin::root(), call_hash, - call_weight - Weight::one() + call_weight - Weight::from_ref_time(1) ), crate::Error::::InvalidCallWeightWitness, ); diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index bb2ed9700c833..88d1dedb2de47 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -82,7 +82,7 @@ impl WeightInfo for SubstrateWeight { fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { Weight::from_ref_time(25_325_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) } @@ -119,7 +119,7 @@ impl WeightInfo for () { fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { Weight::from_ref_time(25_325_000 as RefTimeWeight) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).scalar_saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) } diff --git a/utils/frame/benchmarking-cli/src/overhead/README.md b/utils/frame/benchmarking-cli/src/overhead/README.md index a1da5da0d0792..9d723c3424f7b 100644 --- a/utils/frame/benchmarking-cli/src/overhead/README.md +++ b/utils/frame/benchmarking-cli/src/overhead/README.md @@ -30,7 +30,7 @@ The file will contain the concrete weight value and various statistics about the /// 99th: 3_631_863 /// 95th: 3_595_674 /// 75th: 3_526_435 -pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul(3_532_484); +pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(3_532_484); ``` In this example it takes 3.5 ms to execute an empty block. That means that it always takes at least 3.5 ms to execute *any* block. @@ -59,7 +59,7 @@ The relevant section in the output file looks like this: /// 99th: 68_758 /// 95th: 67_843 /// 75th: 67_749 -pub const ExtrinsicBaseWeight: Weight = Weight::from_ref_time(67_745 * WEIGHT_PER_NANOS); +pub const ExtrinsicBaseWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(67_745); ``` In this example it takes 67.7 µs to execute a NO-OP extrinsic. That means that it always takes at least 67.7 µs to execute *any* extrinsic. diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index d07533e9dbaa8..bddaa642a5a29 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -52,7 +52,7 @@ parameter_types! { /// 99th: {{underscore stats.p99}} /// 95th: {{underscore stats.p95}} /// 75th: {{underscore stats.p75}} - pub const {{long_name}}Weight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul({{underscore weight}}); + pub const {{long_name}}Weight: Weight = WEIGHT_PER_NANOS.saturating_mul({{underscore weight}}); } #[cfg(test)] diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index bf18e23367bc9..f6be16cf69ac9 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -36,7 +36,7 @@ impl {{pallet}}::WeightInfo for WeightInfo { Weight::from_ref_time({{underscore benchmark.base_weight}} as RefTimeWeight) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).scalar_saturating_mul({{cw.name}} as RefTimeWeight)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight)) {{/each}} {{#if (ne benchmark.base_reads "0")}} .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as RefTimeWeight)) From 41b6b389466991167831558e6742295455f15dfb Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 1 Sep 2022 23:39:30 +0200 Subject: [PATCH 1113/1472] Add `StorageNoopGuard` (#12163) * Add StorageNoopGuard Signed-off-by: Oliver Tale-Yazdi * Fix import Signed-off-by: Oliver Tale-Yazdi * Fix feature gate Signed-off-by: Oliver Tale-Yazdi * Fix feature gate Signed-off-by: Oliver Tale-Yazdi * Use sp-std Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/support/src/lib.rs | 2 + frame/support/src/storage/mod.rs | 1 + .../support/src/storage/storage_noop_guard.rs | 114 ++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 frame/support/src/storage/storage_noop_guard.rs diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index a81a266fb9a3d..c556322b6cf93 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -93,6 +93,8 @@ pub mod unsigned { }; } +#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] +pub use self::storage::storage_noop_guard::StorageNoopGuard; pub use self::{ dispatch::{Callable, Parameter}, hash::{ diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index d9e50a1e1345e..b70436785af12 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -46,6 +46,7 @@ pub mod child; pub mod generator; pub mod hashed; pub mod migration; +pub mod storage_noop_guard; pub mod transactional; pub mod types; pub mod unhashed; diff --git a/frame/support/src/storage/storage_noop_guard.rs b/frame/support/src/storage/storage_noop_guard.rs new file mode 100644 index 0000000000000..afcc699d91313 --- /dev/null +++ b/frame/support/src/storage/storage_noop_guard.rs @@ -0,0 +1,114 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Feature gated since it can panic. +#![cfg(any(feature = "std", feature = "runtime-benchmarks", test))] + +//! Contains the [`crate::StorageNoopGuard`] for conveniently asserting +//! that no storage mutation has been made by a whole code block. + +/// Asserts that no storage changes took place between con- and destruction of [`Self`]. +/// +/// This is easier than wrapping the whole code-block inside a `assert_storage_noop!`. +/// +/// # Example +/// +/// ```should_panic +/// use frame_support::{StorageNoopGuard, storage::unhashed::put}; +/// +/// sp_io::TestExternalities::default().execute_with(|| { +/// let _guard = frame_support::StorageNoopGuard::default(); +/// put(b"key", b"value"); +/// // Panics since there are storage changes. +/// }); +/// ``` +#[must_use] +pub struct StorageNoopGuard(sp_std::vec::Vec); + +impl Default for StorageNoopGuard { + fn default() -> Self { + Self(frame_support::storage_root(frame_support::StateVersion::V1)) + } +} + +impl Drop for StorageNoopGuard { + fn drop(&mut self) { + // No need to double panic, eg. inside a test assertion failure. + if sp_std::thread::panicking() { + return + } + assert_eq!( + frame_support::storage_root(frame_support::StateVersion::V1), + self.0, + "StorageNoopGuard detected wrongful storage changes.", + ); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_io::TestExternalities; + + #[test] + #[should_panic(expected = "StorageNoopGuard detected wrongful storage changes.")] + fn storage_noop_guard_panics_on_changed() { + TestExternalities::default().execute_with(|| { + let _guard = StorageNoopGuard::default(); + frame_support::storage::unhashed::put(b"key", b"value"); + }); + } + + #[test] + fn storage_noop_guard_works_on_unchanged() { + TestExternalities::default().execute_with(|| { + let _guard = StorageNoopGuard::default(); + frame_support::storage::unhashed::put(b"key", b"value"); + frame_support::storage::unhashed::kill(b"key"); + }); + } + + #[test] + #[should_panic(expected = "StorageNoopGuard detected wrongful storage changes.")] + fn storage_noop_guard_panics_on_early_drop() { + TestExternalities::default().execute_with(|| { + let guard = StorageNoopGuard::default(); + frame_support::storage::unhashed::put(b"key", b"value"); + sp_std::mem::drop(guard); + frame_support::storage::unhashed::kill(b"key"); + }); + } + + #[test] + fn storage_noop_guard_works_on_changed_forget() { + TestExternalities::default().execute_with(|| { + let guard = StorageNoopGuard::default(); + frame_support::storage::unhashed::put(b"key", b"value"); + sp_std::mem::forget(guard); + }); + } + + #[test] + #[should_panic(expected = "Something else")] + fn storage_noop_guard_does_not_double_panic() { + TestExternalities::default().execute_with(|| { + let _guard = StorageNoopGuard::default(); + frame_support::storage::unhashed::put(b"key", b"value"); + panic!("Something else"); + }); + } +} From e986f05062a5c7a8608967febcd5c1d2bb02eb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 2 Sep 2022 09:27:00 +0200 Subject: [PATCH 1114/1472] Do not drop the `task_manager` for benchmarking stuff (#12147) We can not drop the `task_manager` for benchmarking stuff, because otherwise stuff that may needs this feature (like background signature verification) will fail. Besides the base path setup is moved to `SharedParams` directly. Meaning any call to `base_path` will now directly return a tmp path when `--dev` is given. --- bin/node/cli/src/command.rs | 30 +++++++++++++++----------- client/cli/src/commands/insert_key.rs | 2 +- client/cli/src/commands/run_cmd.rs | 2 +- client/cli/src/config.rs | 2 +- client/cli/src/params/shared_params.rs | 9 ++++++-- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 85e5415dbe139..1d88e9b539421 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -115,35 +115,39 @@ pub fn run() -> Result<()> { cmd.run::(config) }, BenchmarkCmd::Block(cmd) => { - let PartialComponents { client, .. } = new_partial(&config)?; - cmd.run(client) + // ensure that we keep the task manager alive + let partial = new_partial(&config)?; + cmd.run(partial.client) }, BenchmarkCmd::Storage(cmd) => { - let PartialComponents { client, backend, .. } = new_partial(&config)?; - let db = backend.expose_db(); - let storage = backend.expose_storage(); + // ensure that we keep the task manager alive + let partial = new_partial(&config)?; + let db = partial.backend.expose_db(); + let storage = partial.backend.expose_storage(); - cmd.run(config, client, db, storage) + cmd.run(config, partial.client, db, storage) }, BenchmarkCmd::Overhead(cmd) => { - let PartialComponents { client, .. } = new_partial(&config)?; - let ext_builder = RemarkBuilder::new(client.clone()); + // ensure that we keep the task manager alive + let partial = new_partial(&config)?; + let ext_builder = RemarkBuilder::new(partial.client.clone()); - cmd.run(config, client, inherent_benchmark_data()?, &ext_builder) + cmd.run(config, partial.client, inherent_benchmark_data()?, &ext_builder) }, BenchmarkCmd::Extrinsic(cmd) => { - let PartialComponents { client, .. } = service::new_partial(&config)?; + // ensure that we keep the task manager alive + let partial = service::new_partial(&config)?; // Register the *Remark* and *TKA* builders. let ext_factory = ExtrinsicFactory(vec![ - Box::new(RemarkBuilder::new(client.clone())), + Box::new(RemarkBuilder::new(partial.client.clone())), Box::new(TransferKeepAliveBuilder::new( - client.clone(), + partial.client.clone(), Sr25519Keyring::Alice.to_account_id(), ExistentialDeposit::get(), )), ]); - cmd.run(client, inherent_benchmark_data()?, &ext_factory) + cmd.run(partial.client, inherent_benchmark_data()?, &ext_factory) }, BenchmarkCmd::Machine(cmd) => cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index 68201d7b4bffc..5029ecd29248c 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -60,7 +60,7 @@ impl InsertKeyCmd { let suri = utils::read_uri(self.suri.as_ref())?; let base_path = self .shared_params - .base_path() + .base_path()? .unwrap_or_else(|| BasePath::from_project("", "", &C::executable_name())); let chain_id = self.shared_params.chain_id(self.shared_params.is_dev()); let chain_spec = cli.load_spec(&chain_id)?; diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index fd236aa0211dd..11cfb9d0ff651 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -485,7 +485,7 @@ impl CliConfiguration for RunCmd { Ok(if self.tmp { Some(BasePath::new_temp_dir()?) } else { - match self.shared_params().base_path() { + match self.shared_params().base_path()? { Some(r) => Some(r), // If `dev` is enabled, we use the temp base path. None if self.shared_params().is_dev() => Some(BasePath::new_temp_dir()?), diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 92091ea118ff1..bc5941914de89 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -125,7 +125,7 @@ pub trait CliConfiguration: Sized { /// /// By default this is retrieved from `SharedParams`. fn base_path(&self) -> Result> { - Ok(self.shared_params().base_path()) + self.shared_params().base_path() } /// Returns `true` if the node is for development or not diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 67b18aa8b09e2..4a8fc4bcfffdd 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -82,8 +82,13 @@ pub struct SharedParams { impl SharedParams { /// Specify custom base path. - pub fn base_path(&self) -> Option { - self.base_path.clone().map(Into::into) + pub fn base_path(&self) -> Result, crate::Error> { + match &self.base_path { + Some(r) => Ok(Some(r.clone().into())), + // If `dev` is enabled, we use the temp base path. + None if self.is_dev() => Ok(Some(BasePath::new_temp_dir()?)), + None => Ok(None), + } } /// Specify the development chain. From 91b27bcabe205aeeee4486f07ad14365cf0d20f2 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Fri, 2 Sep 2022 18:54:30 +0200 Subject: [PATCH 1115/1472] Alliance pallet: fix func name, fix migration weights (#12174) * Alliance pallet: fix func name, fix migration weights * update comment order --- frame/alliance/src/benchmarking.rs | 2 +- frame/alliance/src/lib.rs | 16 ++++++++-------- frame/alliance/src/migration.rs | 19 +++++++++++++------ frame/alliance/src/tests.rs | 8 ++++---- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index 60df1e1a84d37..d3917b9d2ed95 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -685,7 +685,7 @@ benchmarks_instance_pallet! { ).unwrap(); } - assert_eq!(Alliance::::votable_members_count(), cc); + assert_eq!(Alliance::::voting_members_count(), cc); assert_eq!(Alliance::::ally_members_count(), m); } diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 99cb46c9ef58d..b60077c4ef99e 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -684,7 +684,7 @@ pub mod pallet { Error::::BadWitness ); ensure!( - Self::votable_members_count() <= witness.voting_members, + Self::voting_members_count() <= witness.voting_members, Error::::BadWitness ); ensure!( @@ -697,7 +697,7 @@ pub mod pallet { T::ProposalProvider::veto_proposal(*hash); } - let mut members = Self::votable_members(); + let mut members = Self::voting_members(); T::MembershipChanged::change_members_sorted(&[], &members, &[]); members.append(&mut Self::members_of(MemberRole::Ally)); @@ -1052,7 +1052,7 @@ impl, I: 'static> Pallet { } /// Count of all members who have voting rights. - fn votable_members_count() -> u32 { + fn voting_members_count() -> u32 { Members::::decode_len(MemberRole::Founder) .unwrap_or(0) .saturating_add(Members::::decode_len(MemberRole::Fellow).unwrap_or(0)) as u32 @@ -1064,7 +1064,7 @@ impl, I: 'static> Pallet { } /// Collect all members who have voting rights into one list. - fn votable_members() -> Vec { + fn voting_members() -> Vec { let mut founders = Self::members_of(MemberRole::Founder); let mut fellows = Self::members_of(MemberRole::Fellow); founders.append(&mut fellows); @@ -1072,8 +1072,8 @@ impl, I: 'static> Pallet { } /// Collect all members who have voting rights into one sorted list. - fn votable_members_sorted() -> Vec { - let mut members = Self::votable_members(); + fn voting_members_sorted() -> Vec { + let mut members = Self::voting_members(); members.sort(); members } @@ -1089,7 +1089,7 @@ impl, I: 'static> Pallet { })?; if role == MemberRole::Founder || role == MemberRole::Fellow { - let members = Self::votable_members_sorted(); + let members = Self::voting_members_sorted(); T::MembershipChanged::change_members_sorted(&[who.clone()], &[], &members[..]); } Ok(()) @@ -1104,7 +1104,7 @@ impl, I: 'static> Pallet { })?; if matches!(role, MemberRole::Founder | MemberRole::Fellow) { - let members = Self::votable_members_sorted(); + let members = Self::voting_members_sorted(); T::MembershipChanged::change_members_sorted(&[], &[who.clone()], &members[..]); } Ok(()) diff --git a/frame/alliance/src/migration.rs b/frame/alliance/src/migration.rs index 7e3df5219f25b..8f98484240061 100644 --- a/frame/alliance/src/migration.rs +++ b/frame/alliance/src/migration.rs @@ -51,22 +51,29 @@ mod v0_to_v1 { use super::*; pub fn migrate, I: 'static>() -> Weight { - if migration::clear_storage_prefix( + log::info!(target: LOG_TARGET, "Running migration v0_to_v1."); + + let res = migration::clear_storage_prefix( >::name().as_bytes(), b"UpForKicking", b"", None, None, - ) - .maybe_cursor - .is_some() - { + ); + + log::info!( + target: LOG_TARGET, + "Cleared '{}' entries from 'UpForKicking' storage prefix", + res.unique + ); + + if res.maybe_cursor.is_some() { log::error!( target: LOG_TARGET, "Storage prefix 'UpForKicking' is not completely cleared." ); } - T::DbWeight::get().writes(1) + T::DbWeight::get().writes(res.unique.into()) } } diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index 3bd82a8870efe..9c61561d7ddb5 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -29,7 +29,7 @@ type AllianceMotionEvent = pallet_collective::Event::NoVotingRights @@ -465,7 +465,7 @@ fn nominate_ally_works() { Error::::AlreadyMember ); - // only votable member(founder/fellow) have nominate right + // only voting member(founder/fellow) have nominate right assert_noop!( Alliance::nominate_ally(Origin::signed(5), 4), Error::::NoVotingRights From 82b538e3ae6e035b39a3ac8f069c9fb06757b6ac Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Fri, 2 Sep 2022 19:19:49 +0100 Subject: [PATCH 1116/1472] Remove RefTimeWeight (#12157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update api * update * remove unused * remove `one` api * fix unused * fmt * add saturating accrue * remove `Weight::new()` * use some macros * div makes no sense * Update weight_v2.rs * missed some * more patch * fixes * more fixes * more fix * more fix * remove RefTimeWeight * Update frame/contracts/src/storage.rs Co-authored-by: Alexander Theißen * not needed * Fixes Co-authored-by: Alexander Theißen Co-authored-by: Keith Yeung --- .maintain/frame-weight-template.hbs | 26 +- frame/alliance/src/weights.rs | 350 ++-- frame/assets/src/weights.rs | 326 ++-- frame/bags-list/src/weights.rs | 38 +- frame/balances/src/weights.rs | 86 +- frame/benchmarking/src/weights.rs | 54 +- frame/bounties/src/weights.rs | 146 +- frame/child-bounties/src/weights.rs | 102 +- frame/collective/src/weights.rs | 210 +-- frame/contracts/src/lib.rs | 4 +- frame/contracts/src/schedule.rs | 114 +- frame/contracts/src/storage.rs | 6 +- frame/contracts/src/weights.rs | 1534 ++++++++--------- frame/conviction-voting/src/weights.rs | 110 +- frame/democracy/src/weights.rs | 398 ++--- .../src/weights.rs | 158 +- .../election-provider-support/src/weights.rs | 34 +- frame/elections-phragmen/src/weights.rs | 182 +- frame/examples/basic/src/weights.rs | 38 +- frame/gilt/src/weights.rs | 122 +- frame/identity/src/weights.rs | 310 ++-- frame/im-online/src/weights.rs | 22 +- frame/indices/src/weights.rs | 62 +- frame/lottery/src/weights.rs | 74 +- frame/membership/src/weights.rs | 110 +- frame/multisig/src/weights.rs | 170 +- frame/node-authorization/src/weights.rs | 2 +- frame/nomination-pools/src/weights.rs | 198 +-- frame/preimage/src/weights.rs | 158 +- frame/proxy/src/weights.rs | 174 +- frame/ranked-collective/src/weights.rs | 98 +- frame/recovery/src/weights.rs | 122 +- frame/referenda/src/weights.rs | 326 ++-- frame/remark/src/weights.rs | 14 +- frame/scheduler/src/weights.rs | 290 ++-- frame/session/src/weights.rs | 26 +- frame/staking/src/weights.rs | 458 ++--- frame/state-trie-migration/src/weights.rs | 70 +- frame/support/src/lib.rs | 2 +- frame/support/src/weights.rs | 6 +- frame/support/src/weights/weight_v2.rs | 48 +- .../test/tests/pallet_compatibility.rs | 13 +- .../tests/pallet_compatibility_instance.rs | 13 +- frame/system/src/weights.rs | 62 +- frame/timestamp/src/weights.rs | 18 +- frame/tips/src/weights.rs | 98 +- frame/transaction-payment/src/lib.rs | 5 +- frame/transaction-storage/src/weights.rs | 42 +- frame/treasury/src/weights.rs | 90 +- frame/uniques/src/weights.rs | 354 ++-- frame/utility/src/weights.rs | 34 +- frame/vesting/src/weights.rs | 162 +- frame/whitelist/src/weights.rs | 54 +- .../benchmarking-cli/src/pallet/template.hbs | 14 +- 54 files changed, 3863 insertions(+), 3874 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 5beeaf5f0521e..b0244fbdab85b 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -31,7 +31,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for {{pallet}}. @@ -64,22 +64,22 @@ impl WeightInfo for SubstrateWeight { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { - Weight::from_ref_time({{underscore benchmark.base_weight}} as RefTimeWeight) + Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as u64).saturating_mul({{cw.name}} as u64)) {{/each}} {{#if (ne benchmark.base_reads "0")}} - .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as u64)) {{/if}} {{#each benchmark.component_reads as |cr|}} - .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as RefTimeWeight).saturating_mul({{cr.name}} as RefTimeWeight))) + .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as u64).saturating_mul({{cr.name}} as u64))) {{/each}} {{#if (ne benchmark.base_writes "0")}} - .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as u64)) {{/if}} {{#each benchmark.component_writes as |cw|}} - .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as u64).saturating_mul({{cw.name}} as u64))) {{/each}} } {{/each}} @@ -99,22 +99,22 @@ impl WeightInfo for () { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { - Weight::from_ref_time({{underscore benchmark.base_weight}} as RefTimeWeight) + Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as u64).saturating_mul({{cw.name}} as u64)) {{/each}} {{#if (ne benchmark.base_reads "0")}} - .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}} as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}} as u64)) {{/if}} {{#each benchmark.component_reads as |cr|}} - .saturating_add(RocksDbWeight::get().reads(({{cr.slope}} as RefTimeWeight).saturating_mul({{cr.name}} as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().reads(({{cr.slope}} as u64).saturating_mul({{cr.name}} as u64))) {{/each}} {{#if (ne benchmark.base_writes "0")}} - .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}} as RefTimeWeight)) + .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}} as u64)) {{/if}} {{#each benchmark.component_writes as |cw|}} - .saturating_add(RocksDbWeight::get().writes(({{cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight))) + .saturating_add(RocksDbWeight::get().writes(({{cw.slope}} as u64).saturating_mul({{cw.name}} as u64))) {{/each}} } {{/each}} diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 2da5782f1bb4f..26946c71bf314 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_alliance. @@ -80,26 +80,26 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[0, 90]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(37_864_000 as RefTimeWeight) + Weight::from_ref_time(37_864_000 as u64) // Standard Error: 28_000 - .saturating_add(Weight::from_ref_time(69_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(69_000 as u64).saturating_mul(x as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(66_000 as u64).saturating_mul(y as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Alliance Members (r:2 w:0) // Storage: AllianceMotion Voting (r:1 w:1) /// The range of component `x` is `[3, 10]`. /// The range of component `y` is `[2, 90]`. fn vote(_x: u32, y: u32, ) -> Weight { - Weight::from_ref_time(46_813_000 as RefTimeWeight) + Weight::from_ref_time(46_813_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(125_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(125_000 as u64).saturating_mul(y as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion ProposalOf (r:1 w:1) @@ -107,11 +107,11 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - Weight::from_ref_time(35_316_000 as RefTimeWeight) + Weight::from_ref_time(35_316_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(172_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -122,15 +122,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(36_245_000 as RefTimeWeight) + Weight::from_ref_time(36_245_000 as u64) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(336_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(336_000 as u64).saturating_mul(x as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(109_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(109_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(178_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(178_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -142,17 +142,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(48_088_000 as RefTimeWeight) + Weight::from_ref_time(48_088_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(194_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(194_000 as u64).saturating_mul(x as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(93_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(201_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -164,13 +164,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(43_374_000 as RefTimeWeight) + Weight::from_ref_time(43_374_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(101_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(101_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(182_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(182_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -183,13 +183,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(42_798_000 as RefTimeWeight) + Weight::from_ref_time(42_798_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: Alliance Members (r:3 w:3) @@ -206,68 +206,68 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 100]`. /// The range of component `m` is `[0, 100]`. fn force_set_members(x: u32, y: u32, z: u32, p: u32, c: u32, m: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 221_000 - .saturating_add(Weight::from_ref_time(1_294_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_294_000 as u64).saturating_mul(x as u64)) // Standard Error: 23_000 - .saturating_add(Weight::from_ref_time(231_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(231_000 as u64).saturating_mul(y as u64)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(z as u64)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(9_371_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_371_000 as u64).saturating_mul(p as u64)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_673_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(11_673_000 as u64).saturating_mul(c as u64)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_581_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) - .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(11_581_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(c as u64))) + .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(m as u64))) + .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(p as u64))) + .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(c as u64))) + .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(m as u64))) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - Weight::from_ref_time(18_721_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_721_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - Weight::from_ref_time(21_887_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(21_887_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - Weight::from_ref_time(23_052_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(23_052_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - Weight::from_ref_time(54_504_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(54_504_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - Weight::from_ref_time(42_601_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(42_601_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Members (r:3 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - Weight::from_ref_time(37_704_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(37_704_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Alliance Members (r:4 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -275,18 +275,18 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - Weight::from_ref_time(40_859_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(40_859_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Alliance RetiringMembers (r:1 w:1) // Storage: Alliance Members (r:1 w:1) // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - Weight::from_ref_time(43_447_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(43_447_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Alliance Members (r:3 w:1) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -295,35 +295,35 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - Weight::from_ref_time(61_718_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(61_718_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(359_000 as RefTimeWeight) + Weight::from_ref_time(359_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_376_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_376_000 as u64).saturating_mul(n as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(112_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(112_000 as u64).saturating_mul(l as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 145_000 - .saturating_add(Weight::from_ref_time(20_932_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(20_932_000 as u64).saturating_mul(n as u64)) // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(3_649_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_649_000 as u64).saturating_mul(l as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } } @@ -339,26 +339,26 @@ impl WeightInfo for () { /// The range of component `y` is `[0, 90]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(37_864_000 as RefTimeWeight) + Weight::from_ref_time(37_864_000 as u64) // Standard Error: 28_000 - .saturating_add(Weight::from_ref_time(69_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(69_000 as u64).saturating_mul(x as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(66_000 as u64).saturating_mul(y as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Alliance Members (r:2 w:0) // Storage: AllianceMotion Voting (r:1 w:1) /// The range of component `x` is `[3, 10]`. /// The range of component `y` is `[2, 90]`. fn vote(_x: u32, y: u32, ) -> Weight { - Weight::from_ref_time(46_813_000 as RefTimeWeight) + Weight::from_ref_time(46_813_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(125_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(125_000 as u64).saturating_mul(y as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion ProposalOf (r:1 w:1) @@ -366,11 +366,11 @@ impl WeightInfo for () { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - Weight::from_ref_time(35_316_000 as RefTimeWeight) + Weight::from_ref_time(35_316_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(172_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -381,15 +381,15 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(36_245_000 as RefTimeWeight) + Weight::from_ref_time(36_245_000 as u64) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(336_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(336_000 as u64).saturating_mul(x as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(109_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(109_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(178_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(178_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -401,17 +401,17 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(48_088_000 as RefTimeWeight) + Weight::from_ref_time(48_088_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(194_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(194_000 as u64).saturating_mul(x as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(93_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(93_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(201_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -423,13 +423,13 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(43_374_000 as RefTimeWeight) + Weight::from_ref_time(43_374_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(101_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(101_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(182_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(182_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -442,13 +442,13 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(42_798_000 as RefTimeWeight) + Weight::from_ref_time(42_798_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: Alliance Members (r:3 w:3) @@ -465,68 +465,68 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 100]`. /// The range of component `m` is `[0, 100]`. fn force_set_members(x: u32, y: u32, z: u32, p: u32, c: u32, m: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 221_000 - .saturating_add(Weight::from_ref_time(1_294_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_294_000 as u64).saturating_mul(x as u64)) // Standard Error: 23_000 - .saturating_add(Weight::from_ref_time(231_000 as RefTimeWeight).saturating_mul(y as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(231_000 as u64).saturating_mul(y as u64)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(z as u64)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(9_371_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_371_000 as u64).saturating_mul(p as u64)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_673_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(11_673_000 as u64).saturating_mul(c as u64)) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_581_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(11_581_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(c as u64))) + .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(m as u64))) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(p as u64))) + .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(c as u64))) + .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(m as u64))) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - Weight::from_ref_time(18_721_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_721_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - Weight::from_ref_time(21_887_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(21_887_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - Weight::from_ref_time(23_052_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(23_052_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - Weight::from_ref_time(54_504_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(54_504_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - Weight::from_ref_time(42_601_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(42_601_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Members (r:3 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - Weight::from_ref_time(37_704_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(37_704_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Alliance Members (r:4 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -534,18 +534,18 @@ impl WeightInfo for () { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - Weight::from_ref_time(40_859_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(40_859_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Alliance RetiringMembers (r:1 w:1) // Storage: Alliance Members (r:1 w:1) // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - Weight::from_ref_time(43_447_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(43_447_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Alliance Members (r:3 w:1) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -554,34 +554,34 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - Weight::from_ref_time(61_718_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(61_718_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(359_000 as RefTimeWeight) + Weight::from_ref_time(359_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_376_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_376_000 as u64).saturating_mul(n as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(112_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(112_000 as u64).saturating_mul(l as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 145_000 - .saturating_add(Weight::from_ref_time(20_932_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(20_932_000 as u64).saturating_mul(n as u64)) // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(3_649_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_649_000 as u64).saturating_mul(l as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index d59567e00ef69..cba78f12c218c 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_assets. @@ -74,15 +74,15 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - Weight::from_ref_time(27_167_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(27_167_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - Weight::from_ref_time(15_473_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(15_473_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:5002 w:5001) @@ -90,168 +90,168 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Metadata (r:1 w:0) // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(c as u64)) // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(19_333_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(19_333_000 as u64).saturating_mul(s as u64)) // Standard Error: 375_000 - .saturating_add(Weight::from_ref_time(17_046_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) - .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(17_046_000 as u64).saturating_mul(a as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(c as u64))) + .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(a as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(c as u64))) + .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(a as u64))) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - Weight::from_ref_time(30_819_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(30_819_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - Weight::from_ref_time(35_212_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(35_212_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(47_401_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(47_401_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(42_300_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(42_300_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - Weight::from_ref_time(47_946_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(47_946_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - Weight::from_ref_time(21_670_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(21_670_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - Weight::from_ref_time(21_503_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(21_503_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - Weight::from_ref_time(18_158_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_158_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - Weight::from_ref_time(18_525_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_525_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - Weight::from_ref_time(19_858_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(19_858_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(18_045_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_045_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn set_metadata(n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_395_000 as RefTimeWeight) + Weight::from_ref_time(32_395_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(n as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(32_893_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(32_893_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(19_586_000 as RefTimeWeight) + Weight::from_ref_time(19_586_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - Weight::from_ref_time(32_478_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(32_478_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - Weight::from_ref_time(17_143_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(17_143_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(36_389_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(36_389_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Assets Approvals (r:1 w:1) // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - Weight::from_ref_time(61_854_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(61_854_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(36_759_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(36_759_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - Weight::from_ref_time(37_753_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(37_753_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } } @@ -259,15 +259,15 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - Weight::from_ref_time(27_167_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(27_167_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - Weight::from_ref_time(15_473_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(15_473_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:5002 w:5001) @@ -275,167 +275,167 @@ impl WeightInfo for () { // Storage: Assets Metadata (r:1 w:0) // Storage: Assets Approvals (r:501 w:500) fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(c as u64)) // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(19_333_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(19_333_000 as u64).saturating_mul(s as u64)) // Standard Error: 375_000 - .saturating_add(Weight::from_ref_time(17_046_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(17_046_000 as u64).saturating_mul(a as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(c as u64))) + .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(a as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(c as u64))) + .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(a as u64))) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - Weight::from_ref_time(30_819_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(30_819_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - Weight::from_ref_time(35_212_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(35_212_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(47_401_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(47_401_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(42_300_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(42_300_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - Weight::from_ref_time(47_946_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(47_946_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - Weight::from_ref_time(21_670_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(21_670_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - Weight::from_ref_time(21_503_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(21_503_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - Weight::from_ref_time(18_158_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_158_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - Weight::from_ref_time(18_525_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_525_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - Weight::from_ref_time(19_858_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(19_858_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(18_045_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_045_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn set_metadata(n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_395_000 as RefTimeWeight) + Weight::from_ref_time(32_395_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(n as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(32_893_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(32_893_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(19_586_000 as RefTimeWeight) + Weight::from_ref_time(19_586_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - Weight::from_ref_time(32_478_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(32_478_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - Weight::from_ref_time(17_143_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(17_143_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(36_389_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(36_389_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Assets Approvals (r:1 w:1) // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - Weight::from_ref_time(61_854_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(61_854_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(36_759_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(36_759_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - Weight::from_ref_time(37_753_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(37_753_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index 049967e3024c0..46f001972c519 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_bags_list. @@ -57,18 +57,18 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - Weight::from_ref_time(55_040_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(55_040_000 as u64) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - Weight::from_ref_time(53_671_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(53_671_000 as u64) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: BagsList ListNodes (r:4 w:4) // Storage: Staking Bonded (r:2 w:0) @@ -76,9 +76,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - Weight::from_ref_time(56_410_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(10 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(56_410_000 as u64) + .saturating_add(T::DbWeight::get().reads(10 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } } @@ -89,18 +89,18 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:4 w:4) // Storage: BagsList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - Weight::from_ref_time(55_040_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(55_040_000 as u64) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - Weight::from_ref_time(53_671_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(53_671_000 as u64) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: BagsList ListNodes (r:4 w:4) // Storage: Staking Bonded (r:2 w:0) @@ -108,8 +108,8 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: BagsList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - Weight::from_ref_time(56_410_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(10 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(56_410_000 as u64) + .saturating_add(RocksDbWeight::get().reads(10 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } } diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index 17b2541e0a998..42d165e61a38e 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_balances. @@ -58,45 +58,45 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(41_860_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(41_860_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(32_760_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(32_760_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - Weight::from_ref_time(22_279_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(22_279_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - Weight::from_ref_time(25_488_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_488_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - Weight::from_ref_time(42_190_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(42_190_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - Weight::from_ref_time(37_789_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(37_789_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - Weight::from_ref_time(20_056_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(20_056_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } @@ -104,44 +104,44 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(41_860_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(41_860_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(32_760_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(32_760_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - Weight::from_ref_time(22_279_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(22_279_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - Weight::from_ref_time(25_488_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_488_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - Weight::from_ref_time(42_190_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(42_190_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - Weight::from_ref_time(37_789_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(37_789_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - Weight::from_ref_time(20_056_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(20_056_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index 9a40e488b7243..62117a6f65b07 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for frame_benchmarking. @@ -58,75 +58,75 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn addition(_i: u32, ) -> Weight { - Weight::from_ref_time(103_000 as RefTimeWeight) + Weight::from_ref_time(103_000 as u64) } fn subtraction(_i: u32, ) -> Weight { - Weight::from_ref_time(105_000 as RefTimeWeight) + Weight::from_ref_time(105_000 as u64) } fn multiplication(_i: u32, ) -> Weight { - Weight::from_ref_time(113_000 as RefTimeWeight) + Weight::from_ref_time(113_000 as u64) } fn division(_i: u32, ) -> Weight { - Weight::from_ref_time(102_000 as RefTimeWeight) + Weight::from_ref_time(102_000 as u64) } fn hashing(_i: u32, ) -> Weight { - Weight::from_ref_time(20_865_902_000 as RefTimeWeight) + Weight::from_ref_time(20_865_902_000 as u64) } fn sr25519_verification(i: u32, ) -> Weight { - Weight::from_ref_time(319_000 as RefTimeWeight) + Weight::from_ref_time(319_000 as u64) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(47_171_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(47_171_000 as u64).saturating_mul(i as u64)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_110_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(2_110_000 as u64).saturating_mul(i as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(372_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(372_000 as u64).saturating_mul(i as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } } // For backwards compatibility and tests impl WeightInfo for () { fn addition(_i: u32, ) -> Weight { - Weight::from_ref_time(103_000 as RefTimeWeight) + Weight::from_ref_time(103_000 as u64) } fn subtraction(_i: u32, ) -> Weight { - Weight::from_ref_time(105_000 as RefTimeWeight) + Weight::from_ref_time(105_000 as u64) } fn multiplication(_i: u32, ) -> Weight { - Weight::from_ref_time(113_000 as RefTimeWeight) + Weight::from_ref_time(113_000 as u64) } fn division(_i: u32, ) -> Weight { - Weight::from_ref_time(102_000 as RefTimeWeight) + Weight::from_ref_time(102_000 as u64) } fn hashing(_i: u32, ) -> Weight { - Weight::from_ref_time(20_865_902_000 as RefTimeWeight) + Weight::from_ref_time(20_865_902_000 as u64) } fn sr25519_verification(i: u32, ) -> Weight { - Weight::from_ref_time(319_000 as RefTimeWeight) + Weight::from_ref_time(319_000 as u64) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(47_171_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(47_171_000 as u64).saturating_mul(i as u64)) } // Storage: Skipped Metadata (r:0 w:0) fn storage_read(i: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_110_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(2_110_000 as u64).saturating_mul(i as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) fn storage_write(i: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(372_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(372_000 as u64).saturating_mul(i as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 0bb9a16d3cd8a..7255ece5c223a 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_bounties. @@ -65,88 +65,88 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(_d: u32, ) -> Weight { - Weight::from_ref_time(28_903_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(28_903_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - Weight::from_ref_time(10_997_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(10_997_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - Weight::from_ref_time(8_967_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(8_967_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - Weight::from_ref_time(28_665_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(28_665_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - Weight::from_ref_time(25_141_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(25_141_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - Weight::from_ref_time(21_295_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(21_295_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:3 w:3) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - Weight::from_ref_time(67_951_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(67_951_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - Weight::from_ref_time(33_654_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(33_654_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - Weight::from_ref_time(50_582_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(50_582_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - Weight::from_ref_time(18_322_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_322_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(29_233_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(29_233_000 as u64).saturating_mul(b as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(b as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(b as u64))) } } @@ -157,87 +157,87 @@ impl WeightInfo for () { // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) fn propose_bounty(_d: u32, ) -> Weight { - Weight::from_ref_time(28_903_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(28_903_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - Weight::from_ref_time(10_997_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(10_997_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - Weight::from_ref_time(8_967_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(8_967_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - Weight::from_ref_time(28_665_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(28_665_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - Weight::from_ref_time(25_141_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(25_141_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - Weight::from_ref_time(21_295_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(21_295_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:3 w:3) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - Weight::from_ref_time(67_951_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(67_951_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - Weight::from_ref_time(33_654_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(33_654_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - Weight::from_ref_time(50_582_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(50_582_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - Weight::from_ref_time(18_322_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_322_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:2 w:2) fn spend_funds(b: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(29_233_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(29_233_000 as u64).saturating_mul(b as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(b as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(b as u64))) } } diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index d806a676356b6..564fb0ae23d15 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_child_bounties. @@ -64,51 +64,51 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) fn add_child_bounty(d: u32, ) -> Weight { - Weight::from_ref_time(51_064_000 as RefTimeWeight) + Weight::from_ref_time(51_064_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(d as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - Weight::from_ref_time(15_286_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(15_286_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - Weight::from_ref_time(29_929_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(29_929_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - Weight::from_ref_time(32_449_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(32_449_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - Weight::from_ref_time(23_793_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(23_793_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:3 w:3) // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - Weight::from_ref_time(67_529_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(67_529_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) @@ -117,9 +117,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - Weight::from_ref_time(48_436_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(48_436_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) @@ -128,9 +128,9 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - Weight::from_ref_time(58_044_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(7 as RefTimeWeight)) + Weight::from_ref_time(58_044_000 as u64) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(7 as u64)) } } @@ -143,51 +143,51 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) fn add_child_bounty(d: u32, ) -> Weight { - Weight::from_ref_time(51_064_000 as RefTimeWeight) + Weight::from_ref_time(51_064_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(d as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - Weight::from_ref_time(15_286_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(15_286_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - Weight::from_ref_time(29_929_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(29_929_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - Weight::from_ref_time(32_449_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(32_449_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - Weight::from_ref_time(23_793_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(23_793_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:3 w:3) // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - Weight::from_ref_time(67_529_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(67_529_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) @@ -196,9 +196,9 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - Weight::from_ref_time(48_436_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(48_436_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) @@ -207,8 +207,8 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - Weight::from_ref_time(58_044_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(7 as RefTimeWeight)) + Weight::from_ref_time(58_044_000 as u64) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(7 as u64)) } } diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index fcc0e7134f51c..50029046230af 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_collective. @@ -64,36 +64,36 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Voting (r:100 w:100) // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(10_280_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(10_280_000 as u64).saturating_mul(m as u64)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(126_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(126_000 as u64).saturating_mul(n as u64)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(13_310_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(13_310_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(p as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(p as u64))) } // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - Weight::from_ref_time(16_819_000 as RefTimeWeight) + Weight::from_ref_time(16_819_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - Weight::from_ref_time(18_849_000 as RefTimeWeight) + Weight::from_ref_time(18_849_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) @@ -101,52 +101,52 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(22_204_000 as RefTimeWeight) + Weight::from_ref_time(22_204_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(8_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_000 as u64).saturating_mul(b as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(49_000 as u64).saturating_mul(m as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(180_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(180_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - Weight::from_ref_time(30_941_000 as RefTimeWeight) + Weight::from_ref_time(30_941_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(77_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(32_485_000 as RefTimeWeight) + Weight::from_ref_time(32_485_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(39_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(39_000 as u64).saturating_mul(m as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_487_000 as RefTimeWeight) + Weight::from_ref_time(33_487_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(b as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(66_000 as u64).saturating_mul(m as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(157_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(157_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) @@ -154,13 +154,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_494_000 as RefTimeWeight) + Weight::from_ref_time(33_494_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(58_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(58_000 as u64).saturating_mul(m as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) @@ -168,25 +168,25 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(36_566_000 as RefTimeWeight) + Weight::from_ref_time(36_566_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(b as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(63_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(63_000 as u64).saturating_mul(m as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Council Proposals (r:1 w:1) // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(20_159_000 as RefTimeWeight) + Weight::from_ref_time(20_159_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(173_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } } @@ -197,36 +197,36 @@ impl WeightInfo for () { // Storage: Council Voting (r:100 w:100) // Storage: Council Prime (r:0 w:1) fn set_members(m: u32, n: u32, p: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(10_280_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(10_280_000 as u64).saturating_mul(m as u64)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(126_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(126_000 as u64).saturating_mul(n as u64)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(13_310_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(13_310_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(p as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(p as u64))) } // Storage: Council Members (r:1 w:0) fn execute(b: u32, m: u32, ) -> Weight { - Weight::from_ref_time(16_819_000 as RefTimeWeight) + Weight::from_ref_time(16_819_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) fn propose_execute(b: u32, m: u32, ) -> Weight { - Weight::from_ref_time(18_849_000 as RefTimeWeight) + Weight::from_ref_time(18_849_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) @@ -234,52 +234,52 @@ impl WeightInfo for () { // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(22_204_000 as RefTimeWeight) + Weight::from_ref_time(22_204_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(8_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(8_000 as u64).saturating_mul(b as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(49_000 as u64).saturating_mul(m as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(180_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(180_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) fn vote(m: u32, ) -> Weight { - Weight::from_ref_time(30_941_000 as RefTimeWeight) + Weight::from_ref_time(30_941_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(77_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(32_485_000 as RefTimeWeight) + Weight::from_ref_time(32_485_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(39_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(39_000 as u64).saturating_mul(m as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_487_000 as RefTimeWeight) + Weight::from_ref_time(33_487_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(b as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(66_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(66_000 as u64).saturating_mul(m as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(157_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(157_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) @@ -287,13 +287,13 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) fn close_disapproved(m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_494_000 as RefTimeWeight) + Weight::from_ref_time(33_494_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(58_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(58_000 as u64).saturating_mul(m as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Council Voting (r:1 w:1) // Storage: Council Members (r:1 w:0) @@ -301,24 +301,24 @@ impl WeightInfo for () { // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(36_566_000 as RefTimeWeight) + Weight::from_ref_time(36_566_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(b as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(63_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(63_000 as u64).saturating_mul(m as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Council Proposals (r:1 w:1) // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) fn disapprove_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(20_159_000 as RefTimeWeight) + Weight::from_ref_time(20_159_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(173_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index ee0db17ade95b..7fda4bca36d2e 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -110,7 +110,7 @@ use frame_support::{ dispatch::Dispatchable, ensure, traits::{ConstU32, Contains, Currency, Get, Randomness, ReservableCurrency, Time}, - weights::{DispatchClass, GetDispatchInfo, Pays, PostDispatchInfo, RefTimeWeight, Weight}, + weights::{DispatchClass, GetDispatchInfo, Pays, PostDispatchInfo, Weight}, BoundedVec, }; use frame_system::{limits::BlockWeights, Pallet as System}; @@ -214,7 +214,7 @@ impl, const P: u32> Get for DefaultContractAccessWe .get(DispatchClass::Normal) .max_total .unwrap_or(block_weights.max_block) / - RefTimeWeight::from(P) + u64::from(P) } } diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index b5c80642a5356..63867a0cc7448 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -21,7 +21,7 @@ use crate::{weights::WeightInfo, Config}; use codec::{Decode, Encode}; -use frame_support::{weights::RefTimeWeight, DefaultNoBound}; +use frame_support::DefaultNoBound; use pallet_contracts_proc_macro::{ScheduleDebug, WeightDebug}; use scale_info::TypeInfo; #[cfg(feature = "std")] @@ -255,166 +255,166 @@ pub struct InstructionWeights { #[scale_info(skip_type_params(T))] pub struct HostFnWeights { /// Weight of calling `seal_caller`. - pub caller: RefTimeWeight, + pub caller: u64, /// Weight of calling `seal_is_contract`. - pub is_contract: RefTimeWeight, + pub is_contract: u64, /// Weight of calling `seal_code_hash`. - pub code_hash: RefTimeWeight, + pub code_hash: u64, /// Weight of calling `seal_own_code_hash`. - pub own_code_hash: RefTimeWeight, + pub own_code_hash: u64, /// Weight of calling `seal_caller_is_origin`. - pub caller_is_origin: RefTimeWeight, + pub caller_is_origin: u64, /// Weight of calling `seal_address`. - pub address: RefTimeWeight, + pub address: u64, /// Weight of calling `seal_gas_left`. - pub gas_left: RefTimeWeight, + pub gas_left: u64, /// Weight of calling `seal_balance`. - pub balance: RefTimeWeight, + pub balance: u64, /// Weight of calling `seal_value_transferred`. - pub value_transferred: RefTimeWeight, + pub value_transferred: u64, /// Weight of calling `seal_minimum_balance`. - pub minimum_balance: RefTimeWeight, + pub minimum_balance: u64, /// Weight of calling `seal_block_number`. - pub block_number: RefTimeWeight, + pub block_number: u64, /// Weight of calling `seal_now`. - pub now: RefTimeWeight, + pub now: u64, /// Weight of calling `seal_weight_to_fee`. - pub weight_to_fee: RefTimeWeight, + pub weight_to_fee: u64, /// Weight of calling `gas`. - pub gas: RefTimeWeight, + pub gas: u64, /// Weight of calling `seal_input`. - pub input: RefTimeWeight, + pub input: u64, /// Weight per input byte copied to contract memory by `seal_input`. - pub input_per_byte: RefTimeWeight, + pub input_per_byte: u64, /// Weight of calling `seal_return`. - pub r#return: RefTimeWeight, + pub r#return: u64, /// Weight per byte returned through `seal_return`. - pub return_per_byte: RefTimeWeight, + pub return_per_byte: u64, /// Weight of calling `seal_terminate`. - pub terminate: RefTimeWeight, + pub terminate: u64, /// Weight of calling `seal_random`. - pub random: RefTimeWeight, + pub random: u64, /// Weight of calling `seal_reposit_event`. - pub deposit_event: RefTimeWeight, + pub deposit_event: u64, /// Weight per topic supplied to `seal_deposit_event`. - pub deposit_event_per_topic: RefTimeWeight, + pub deposit_event_per_topic: u64, /// Weight per byte of an event deposited through `seal_deposit_event`. - pub deposit_event_per_byte: RefTimeWeight, + pub deposit_event_per_byte: u64, /// Weight of calling `seal_debug_message`. - pub debug_message: RefTimeWeight, + pub debug_message: u64, /// Weight of calling `seal_set_storage`. - pub set_storage: RefTimeWeight, + pub set_storage: u64, /// Weight per written byten of an item stored with `seal_set_storage`. - pub set_storage_per_new_byte: RefTimeWeight, + pub set_storage_per_new_byte: u64, /// Weight per overwritten byte of an item stored with `seal_set_storage`. - pub set_storage_per_old_byte: RefTimeWeight, + pub set_storage_per_old_byte: u64, /// Weight of calling `seal_set_code_hash`. - pub set_code_hash: RefTimeWeight, + pub set_code_hash: u64, /// Weight of calling `seal_clear_storage`. - pub clear_storage: RefTimeWeight, + pub clear_storage: u64, /// Weight of calling `seal_clear_storage` per byte of the stored item. - pub clear_storage_per_byte: RefTimeWeight, + pub clear_storage_per_byte: u64, /// Weight of calling `seal_contains_storage`. - pub contains_storage: RefTimeWeight, + pub contains_storage: u64, /// Weight of calling `seal_contains_storage` per byte of the stored item. - pub contains_storage_per_byte: RefTimeWeight, + pub contains_storage_per_byte: u64, /// Weight of calling `seal_get_storage`. - pub get_storage: RefTimeWeight, + pub get_storage: u64, /// Weight per byte of an item received via `seal_get_storage`. - pub get_storage_per_byte: RefTimeWeight, + pub get_storage_per_byte: u64, /// Weight of calling `seal_take_storage`. - pub take_storage: RefTimeWeight, + pub take_storage: u64, /// Weight per byte of an item received via `seal_take_storage`. - pub take_storage_per_byte: RefTimeWeight, + pub take_storage_per_byte: u64, /// Weight of calling `seal_transfer`. - pub transfer: RefTimeWeight, + pub transfer: u64, /// Weight of calling `seal_call`. - pub call: RefTimeWeight, + pub call: u64, /// Weight of calling `seal_delegate_call`. - pub delegate_call: RefTimeWeight, + pub delegate_call: u64, /// Weight surcharge that is claimed if `seal_call` does a balance transfer. - pub call_transfer_surcharge: RefTimeWeight, + pub call_transfer_surcharge: u64, /// Weight per byte that is cloned by supplying the `CLONE_INPUT` flag. - pub call_per_cloned_byte: RefTimeWeight, + pub call_per_cloned_byte: u64, /// Weight of calling `seal_instantiate`. - pub instantiate: RefTimeWeight, + pub instantiate: u64, /// Weight surcharge that is claimed if `seal_instantiate` does a balance transfer. - pub instantiate_transfer_surcharge: RefTimeWeight, + pub instantiate_transfer_surcharge: u64, /// Weight per salt byte supplied to `seal_instantiate`. - pub instantiate_per_salt_byte: RefTimeWeight, + pub instantiate_per_salt_byte: u64, /// Weight of calling `seal_hash_sha_256`. - pub hash_sha2_256: RefTimeWeight, + pub hash_sha2_256: u64, /// Weight per byte hashed by `seal_hash_sha_256`. - pub hash_sha2_256_per_byte: RefTimeWeight, + pub hash_sha2_256_per_byte: u64, /// Weight of calling `seal_hash_keccak_256`. - pub hash_keccak_256: RefTimeWeight, + pub hash_keccak_256: u64, /// Weight per byte hashed by `seal_hash_keccak_256`. - pub hash_keccak_256_per_byte: RefTimeWeight, + pub hash_keccak_256_per_byte: u64, /// Weight of calling `seal_hash_blake2_256`. - pub hash_blake2_256: RefTimeWeight, + pub hash_blake2_256: u64, /// Weight per byte hashed by `seal_hash_blake2_256`. - pub hash_blake2_256_per_byte: RefTimeWeight, + pub hash_blake2_256_per_byte: u64, /// Weight of calling `seal_hash_blake2_128`. - pub hash_blake2_128: RefTimeWeight, + pub hash_blake2_128: u64, /// Weight per byte hashed by `seal_hash_blake2_128`. - pub hash_blake2_128_per_byte: RefTimeWeight, + pub hash_blake2_128_per_byte: u64, /// Weight of calling `seal_ecdsa_recover`. - pub ecdsa_recover: RefTimeWeight, + pub ecdsa_recover: u64, /// Weight of calling `seal_ecdsa_to_eth_address`. - pub ecdsa_to_eth_address: RefTimeWeight, + pub ecdsa_to_eth_address: u64, /// The type parameter is used in the default implementation. #[codec(skip)] @@ -441,13 +441,13 @@ macro_rules! cost_args { macro_rules! cost_batched_args { ($name:ident, $( $arg: expr ),+) => { - cost_args!($name, $( $arg ),+) / RefTimeWeight::from(API_BENCHMARK_BATCH_SIZE) + cost_args!($name, $( $arg ),+) / u64::from(API_BENCHMARK_BATCH_SIZE) } } macro_rules! cost_instr_no_params_with_batch_size { ($name:ident, $batch_size:expr) => { - (cost_args!($name, 1) / RefTimeWeight::from($batch_size)) as u32 + (cost_args!($name, 1) / u64::from($batch_size)) as u32 }; } diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 9c340b5c93deb..ec49a6325c125 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -28,7 +28,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::{DispatchError, DispatchResult}, storage::child::{self, ChildInfo}, - weights::{RefTimeWeight, Weight}, + weights::Weight, }; use scale_info::TypeInfo; use sp_core::crypto::UncheckedFrom; @@ -230,7 +230,7 @@ where let weight_per_key = (T::WeightInfo::on_initialize_per_trie_key(1) - T::WeightInfo::on_initialize_per_trie_key(0)) .ref_time(); - let decoding_weight = weight_per_queue_item.saturating_mul(queue_len as RefTimeWeight); + let decoding_weight = weight_per_queue_item.saturating_mul(queue_len as u64); // `weight_per_key` being zero makes no sense and would constitute a failure to // benchmark properly. We opt for not removing any keys at all in this case. @@ -286,7 +286,7 @@ where >::put(queue); let ref_time_weight = weight_limit .ref_time() - .saturating_sub(weight_per_key.saturating_mul(remaining_key_budget as RefTimeWeight)); + .saturating_sub(weight_per_key.saturating_mul(u64::from(remaining_key_budget))); Weight::from_ref_time(ref_time_weight) } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index daee41bc63f32..f1f80ba7a43df 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_contracts. @@ -166,37 +166,37 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(1_654_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + Weight::from_ref_time(1_654_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(8_564_000 as RefTimeWeight) + Weight::from_ref_time(8_564_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(k as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 1024]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_944_000 as RefTimeWeight).saturating_mul(q as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_944_000 as u64).saturating_mul(q as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(19_016_000 as RefTimeWeight) + Weight::from_ref_time(19_016_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(49_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) @@ -204,11 +204,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(205_194_000 as RefTimeWeight) + Weight::from_ref_time(205_194_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(53_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(53_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -220,13 +220,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(288_487_000 as RefTimeWeight) + Weight::from_ref_time(288_487_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(c as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -236,46 +236,46 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(186_136_000 as RefTimeWeight) + Weight::from_ref_time(186_136_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - Weight::from_ref_time(149_232_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(149_232_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(51_721_000 as RefTimeWeight) + Weight::from_ref_time(51_721_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(48_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Contracts OwnerInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(30_016_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(30_016_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) fn set_code() -> Weight { - Weight::from_ref_time(27_192_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(27_192_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -283,11 +283,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(206_405_000 as RefTimeWeight) + Weight::from_ref_time(206_405_000 as u64) // Standard Error: 112_000 - .saturating_add(Weight::from_ref_time(40_987_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_987_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -295,12 +295,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(106_220_000 as RefTimeWeight) + Weight::from_ref_time(106_220_000 as u64) // Standard Error: 710_000 - .saturating_add(Weight::from_ref_time(307_648_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(307_648_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -308,12 +308,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(104_498_000 as RefTimeWeight) + Weight::from_ref_time(104_498_000 as u64) // Standard Error: 633_000 - .saturating_add(Weight::from_ref_time(368_901_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(368_901_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -321,11 +321,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(208_696_000 as RefTimeWeight) + Weight::from_ref_time(208_696_000 as u64) // Standard Error: 101_000 - .saturating_add(Weight::from_ref_time(44_445_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(44_445_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -333,11 +333,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(205_612_000 as RefTimeWeight) + Weight::from_ref_time(205_612_000 as u64) // Standard Error: 68_000 - .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -345,11 +345,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(206_947_000 as RefTimeWeight) + Weight::from_ref_time(206_947_000 as u64) // Standard Error: 107_000 - .saturating_add(Weight::from_ref_time(40_789_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_789_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -357,11 +357,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(208_692_000 as RefTimeWeight) + Weight::from_ref_time(208_692_000 as u64) // Standard Error: 109_000 - .saturating_add(Weight::from_ref_time(40_600_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_600_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -369,11 +369,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_811_000 as RefTimeWeight) + Weight::from_ref_time(209_811_000 as u64) // Standard Error: 208_000 - .saturating_add(Weight::from_ref_time(116_831_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(116_831_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -381,11 +381,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(207_406_000 as RefTimeWeight) + Weight::from_ref_time(207_406_000 as u64) // Standard Error: 117_000 - .saturating_add(Weight::from_ref_time(40_702_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_702_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -393,11 +393,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_260_000 as RefTimeWeight) + Weight::from_ref_time(209_260_000 as u64) // Standard Error: 130_000 - .saturating_add(Weight::from_ref_time(40_479_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_479_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -405,11 +405,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(206_448_000 as RefTimeWeight) + Weight::from_ref_time(206_448_000 as u64) // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(40_134_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_134_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -417,11 +417,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(206_969_000 as RefTimeWeight) + Weight::from_ref_time(206_969_000 as u64) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(40_251_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_251_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -430,11 +430,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(211_611_000 as RefTimeWeight) + Weight::from_ref_time(211_611_000 as u64) // Standard Error: 175_000 - .saturating_add(Weight::from_ref_time(98_675_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(98_675_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -442,11 +442,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(134_484_000 as RefTimeWeight) + Weight::from_ref_time(134_484_000 as u64) // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(19_329_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(19_329_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -454,11 +454,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(208_556_000 as RefTimeWeight) + Weight::from_ref_time(208_556_000 as u64) // Standard Error: 125_000 - .saturating_add(Weight::from_ref_time(40_328_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_328_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -466,11 +466,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(268_886_000 as RefTimeWeight) + Weight::from_ref_time(268_886_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_627_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_627_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -478,9 +478,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 1]`. fn seal_return(_r: u32, ) -> Weight { - Weight::from_ref_time(203_591_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(203_591_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -488,11 +488,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(204_258_000 as RefTimeWeight) + Weight::from_ref_time(204_258_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(183_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(183_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -502,13 +502,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(206_625_000 as RefTimeWeight) + Weight::from_ref_time(206_625_000 as u64) // Standard Error: 672_000 - .saturating_add(Weight::from_ref_time(59_377_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((4 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((5 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(59_377_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -517,11 +517,11 @@ impl WeightInfo for SubstrateWeight { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(208_866_000 as RefTimeWeight) + Weight::from_ref_time(208_866_000 as u64) // Standard Error: 164_000 - .saturating_add(Weight::from_ref_time(133_438_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(133_438_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -529,11 +529,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(220_860_000 as RefTimeWeight) + Weight::from_ref_time(220_860_000 as u64) // Standard Error: 209_000 - .saturating_add(Weight::from_ref_time(239_951_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(239_951_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -543,15 +543,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(439_782_000 as RefTimeWeight) + Weight::from_ref_time(439_782_000 as u64) // Standard Error: 1_643_000 - .saturating_add(Weight::from_ref_time(264_687_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(264_687_000 as u64).saturating_mul(t as u64)) // Standard Error: 323_000 - .saturating_add(Weight::from_ref_time(67_636_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(67_636_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(t as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -559,128 +559,128 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(140_280_000 as RefTimeWeight) + Weight::from_ref_time(140_280_000 as u64) // Standard Error: 82_000 - .saturating_add(Weight::from_ref_time(32_717_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(32_717_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(161_247_000 as RefTimeWeight) + Weight::from_ref_time(161_247_000 as u64) // Standard Error: 883_000 - .saturating_add(Weight::from_ref_time(423_997_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(423_997_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_247_000 as RefTimeWeight) + Weight::from_ref_time(529_247_000 as u64) // Standard Error: 2_745_000 - .saturating_add(Weight::from_ref_time(85_282_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(53 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(85_282_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(55 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(53 as u64)) + .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_812_000 as RefTimeWeight) + Weight::from_ref_time(529_812_000 as u64) // Standard Error: 2_513_000 - .saturating_add(Weight::from_ref_time(74_554_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(53 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(74_554_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(55 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(53 as u64)) + .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(184_803_000 as RefTimeWeight) + Weight::from_ref_time(184_803_000 as u64) // Standard Error: 733_000 - .saturating_add(Weight::from_ref_time(404_933_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(404_933_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(500_958_000 as RefTimeWeight) + Weight::from_ref_time(500_958_000 as u64) // Standard Error: 2_980_000 - .saturating_add(Weight::from_ref_time(75_996_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(52 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(75_996_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(55 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(52 as u64)) + .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(177_682_000 as RefTimeWeight) + Weight::from_ref_time(177_682_000 as u64) // Standard Error: 743_000 - .saturating_add(Weight::from_ref_time(338_172_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(338_172_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(465_285_000 as RefTimeWeight) + Weight::from_ref_time(465_285_000 as u64) // Standard Error: 2_599_000 - .saturating_add(Weight::from_ref_time(155_106_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(155_106_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(55 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(179_118_000 as RefTimeWeight) + Weight::from_ref_time(179_118_000 as u64) // Standard Error: 572_000 - .saturating_add(Weight::from_ref_time(311_083_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(311_083_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(423_056_000 as RefTimeWeight) + Weight::from_ref_time(423_056_000 as u64) // Standard Error: 2_037_000 - .saturating_add(Weight::from_ref_time(69_665_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(54 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(69_665_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(54 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(188_884_000 as RefTimeWeight) + Weight::from_ref_time(188_884_000 as u64) // Standard Error: 761_000 - .saturating_add(Weight::from_ref_time(432_781_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(432_781_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(532_408_000 as RefTimeWeight) + Weight::from_ref_time(532_408_000 as u64) // Standard Error: 3_348_000 - .saturating_add(Weight::from_ref_time(164_943_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(55 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(53 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(164_943_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(55 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(53 as u64)) + .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -688,13 +688,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(127_181_000 as RefTimeWeight) + Weight::from_ref_time(127_181_000 as u64) // Standard Error: 1_495_000 - .saturating_add(Weight::from_ref_time(1_500_589_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(1_500_589_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -702,13 +702,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 3_803_000 - .saturating_add(Weight::from_ref_time(14_860_909_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(14_860_909_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -716,11 +716,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 6_045_000 - .saturating_add(Weight::from_ref_time(14_797_140_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(14_797_140_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads((79 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -729,15 +729,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(9_196_444_000 as RefTimeWeight) + Weight::from_ref_time(9_196_444_000 as u64) // Standard Error: 20_486_000 - .saturating_add(Weight::from_ref_time(1_458_153_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_458_153_000 as u64).saturating_mul(t as u64)) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(9_718_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(85 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((81 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(81 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((81 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(9_718_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(85 as u64)) + .saturating_add(T::DbWeight::get().reads((81 as u64).saturating_mul(t as u64))) + .saturating_add(T::DbWeight::get().writes(81 as u64)) + .saturating_add(T::DbWeight::get().writes((81 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -747,13 +747,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 36_253_000 - .saturating_add(Weight::from_ref_time(21_201_529_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((320 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((320 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(21_201_529_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().reads((320 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((320 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:81 w:81) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -764,15 +764,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(12_282_498_000 as RefTimeWeight) + Weight::from_ref_time(12_282_498_000 as u64) // Standard Error: 48_112_000 - .saturating_add(Weight::from_ref_time(720_795_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(720_795_000 as u64).saturating_mul(t as u64)) // Standard Error: 22_000 - .saturating_add(Weight::from_ref_time(124_274_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(167 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(165 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(124_274_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(167 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(t as u64))) + .saturating_add(T::DbWeight::get().writes(165 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -780,11 +780,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(203_959_000 as RefTimeWeight) + Weight::from_ref_time(203_959_000 as u64) // Standard Error: 142_000 - .saturating_add(Weight::from_ref_time(61_311_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(61_311_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -792,11 +792,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(349_915_000 as RefTimeWeight) + Weight::from_ref_time(349_915_000 as u64) // Standard Error: 40_000 - .saturating_add(Weight::from_ref_time(320_652_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(320_652_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -804,11 +804,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(209_219_000 as RefTimeWeight) + Weight::from_ref_time(209_219_000 as u64) // Standard Error: 157_000 - .saturating_add(Weight::from_ref_time(73_728_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_728_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -816,11 +816,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(208_860_000 as RefTimeWeight) + Weight::from_ref_time(208_860_000 as u64) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(245_718_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(245_718_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -828,11 +828,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(206_165_000 as RefTimeWeight) + Weight::from_ref_time(206_165_000 as u64) // Standard Error: 138_000 - .saturating_add(Weight::from_ref_time(51_644_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_644_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -840,11 +840,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(255_955_000 as RefTimeWeight) + Weight::from_ref_time(255_955_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_090_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_090_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -852,11 +852,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(208_153_000 as RefTimeWeight) + Weight::from_ref_time(208_153_000 as u64) // Standard Error: 140_000 - .saturating_add(Weight::from_ref_time(51_264_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_264_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -864,11 +864,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(278_368_000 as RefTimeWeight) + Weight::from_ref_time(278_368_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_006_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_006_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -876,11 +876,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(331_955_000 as RefTimeWeight) + Weight::from_ref_time(331_955_000 as u64) // Standard Error: 1_155_000 - .saturating_add(Weight::from_ref_time(3_069_955_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_069_955_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -888,11 +888,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(207_838_000 as RefTimeWeight) + Weight::from_ref_time(207_838_000 as u64) // Standard Error: 783_000 - .saturating_add(Weight::from_ref_time(2_058_503_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_058_503_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -901,317 +901,317 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 1_567_000 - .saturating_add(Weight::from_ref_time(774_380_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(774_380_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads((79 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes((79 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(73_955_000 as RefTimeWeight) + Weight::from_ref_time(73_955_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(612_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(612_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(74_057_000 as RefTimeWeight) + Weight::from_ref_time(74_057_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(74_137_000 as RefTimeWeight) + Weight::from_ref_time(74_137_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_427_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(73_844_000 as RefTimeWeight) + Weight::from_ref_time(73_844_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_773_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_773_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as RefTimeWeight) + Weight::from_ref_time(73_979_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_952_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_952_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(73_924_000 as RefTimeWeight) + Weight::from_ref_time(73_924_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(941_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(941_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_574_000 as RefTimeWeight) + Weight::from_ref_time(73_574_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_439_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_439_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(73_343_000 as RefTimeWeight) + Weight::from_ref_time(73_343_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_603_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_603_000 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(76_267_000 as RefTimeWeight) + Weight::from_ref_time(76_267_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(74_877_000 as RefTimeWeight) + Weight::from_ref_time(74_877_000 as u64) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(7_144_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(7_144_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(88_665_000 as RefTimeWeight) + Weight::from_ref_time(88_665_000 as u64) // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(9_142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_142_000 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(98_600_000 as RefTimeWeight) + Weight::from_ref_time(98_600_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(469_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(469_000 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(74_555_000 as RefTimeWeight) + Weight::from_ref_time(74_555_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(624_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(624_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(74_329_000 as RefTimeWeight) + Weight::from_ref_time(74_329_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(688_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(688_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(74_612_000 as RefTimeWeight) + Weight::from_ref_time(74_612_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(909_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(909_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(76_906_000 as RefTimeWeight) + Weight::from_ref_time(76_906_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_192_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_192_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(76_979_000 as RefTimeWeight) + Weight::from_ref_time(76_979_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_361_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_361_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(74_370_000 as RefTimeWeight) + Weight::from_ref_time(74_370_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(661_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(661_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(73_584_000 as RefTimeWeight) + Weight::from_ref_time(73_584_000 as u64) // Standard Error: 353_000 - .saturating_add(Weight::from_ref_time(187_114_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(187_114_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(74_206_000 as RefTimeWeight) + Weight::from_ref_time(74_206_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(884_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(884_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(73_992_000 as RefTimeWeight) + Weight::from_ref_time(73_992_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(893_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(893_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(73_985_000 as RefTimeWeight) + Weight::from_ref_time(73_985_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(891_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(891_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(74_117_000 as RefTimeWeight) + Weight::from_ref_time(74_117_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(901_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(73_981_000 as RefTimeWeight) + Weight::from_ref_time(73_981_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(866_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(866_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(74_104_000 as RefTimeWeight) + Weight::from_ref_time(74_104_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(74_293_000 as RefTimeWeight) + Weight::from_ref_time(74_293_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(878_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(878_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(74_055_000 as RefTimeWeight) + Weight::from_ref_time(74_055_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(73_710_000 as RefTimeWeight) + Weight::from_ref_time(73_710_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(73_917_000 as RefTimeWeight) + Weight::from_ref_time(73_917_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_355_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(74_048_000 as RefTimeWeight) + Weight::from_ref_time(74_048_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(74_029_000 as RefTimeWeight) + Weight::from_ref_time(74_029_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_349_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_349_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(74_267_000 as RefTimeWeight) + Weight::from_ref_time(74_267_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(73_952_000 as RefTimeWeight) + Weight::from_ref_time(73_952_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(73_851_000 as RefTimeWeight) + Weight::from_ref_time(73_851_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_368_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_368_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(74_034_000 as RefTimeWeight) + Weight::from_ref_time(74_034_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_348_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_348_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as RefTimeWeight) + Weight::from_ref_time(73_979_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(74_000_000 as RefTimeWeight) + Weight::from_ref_time(74_000_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_328_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_328_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(73_883_000 as RefTimeWeight) + Weight::from_ref_time(73_883_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_331_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_331_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(74_216_000 as RefTimeWeight) + Weight::from_ref_time(74_216_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(73_989_000 as RefTimeWeight) + Weight::from_ref_time(73_989_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_998_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_998_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(73_857_000 as RefTimeWeight) + Weight::from_ref_time(73_857_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_073_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_073_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(73_801_000 as RefTimeWeight) + Weight::from_ref_time(73_801_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_027_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_027_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(74_130_000 as RefTimeWeight) + Weight::from_ref_time(74_130_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_064_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_064_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(74_071_000 as RefTimeWeight) + Weight::from_ref_time(74_071_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_327_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_327_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(74_201_000 as RefTimeWeight) + Weight::from_ref_time(74_201_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_330_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_330_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(74_241_000 as RefTimeWeight) + Weight::from_ref_time(74_241_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_321_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_321_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(74_331_000 as RefTimeWeight) + Weight::from_ref_time(74_331_000 as u64) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_347_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_347_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(73_674_000 as RefTimeWeight) + Weight::from_ref_time(73_674_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_359_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_359_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(73_807_000 as RefTimeWeight) + Weight::from_ref_time(73_807_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(73_725_000 as RefTimeWeight) + Weight::from_ref_time(73_725_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(73_755_000 as RefTimeWeight) + Weight::from_ref_time(73_755_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) } } @@ -1219,37 +1219,37 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(1_654_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + Weight::from_ref_time(1_654_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(8_564_000 as RefTimeWeight) + Weight::from_ref_time(8_564_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(k as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 1024]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_944_000 as RefTimeWeight).saturating_mul(q as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_944_000 as u64).saturating_mul(q as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(19_016_000 as RefTimeWeight) + Weight::from_ref_time(19_016_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(49_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(49_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) @@ -1257,11 +1257,11 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(205_194_000 as RefTimeWeight) + Weight::from_ref_time(205_194_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(53_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(53_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -1273,13 +1273,13 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(288_487_000 as RefTimeWeight) + Weight::from_ref_time(288_487_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(124_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(c as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -1289,46 +1289,46 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(186_136_000 as RefTimeWeight) + Weight::from_ref_time(186_136_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) fn call() -> Weight { - Weight::from_ref_time(149_232_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(149_232_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(51_721_000 as RefTimeWeight) + Weight::from_ref_time(51_721_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(48_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Contracts OwnerInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(30_016_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(30_016_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) fn set_code() -> Weight { - Weight::from_ref_time(27_192_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(27_192_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1336,11 +1336,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(206_405_000 as RefTimeWeight) + Weight::from_ref_time(206_405_000 as u64) // Standard Error: 112_000 - .saturating_add(Weight::from_ref_time(40_987_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_987_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1348,12 +1348,12 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(106_220_000 as RefTimeWeight) + Weight::from_ref_time(106_220_000 as u64) // Standard Error: 710_000 - .saturating_add(Weight::from_ref_time(307_648_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(307_648_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1361,12 +1361,12 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(104_498_000 as RefTimeWeight) + Weight::from_ref_time(104_498_000 as u64) // Standard Error: 633_000 - .saturating_add(Weight::from_ref_time(368_901_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(368_901_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1374,11 +1374,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(208_696_000 as RefTimeWeight) + Weight::from_ref_time(208_696_000 as u64) // Standard Error: 101_000 - .saturating_add(Weight::from_ref_time(44_445_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(44_445_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1386,11 +1386,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(205_612_000 as RefTimeWeight) + Weight::from_ref_time(205_612_000 as u64) // Standard Error: 68_000 - .saturating_add(Weight::from_ref_time(17_145_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1398,11 +1398,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(206_947_000 as RefTimeWeight) + Weight::from_ref_time(206_947_000 as u64) // Standard Error: 107_000 - .saturating_add(Weight::from_ref_time(40_789_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_789_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1410,11 +1410,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(208_692_000 as RefTimeWeight) + Weight::from_ref_time(208_692_000 as u64) // Standard Error: 109_000 - .saturating_add(Weight::from_ref_time(40_600_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_600_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1422,11 +1422,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_811_000 as RefTimeWeight) + Weight::from_ref_time(209_811_000 as u64) // Standard Error: 208_000 - .saturating_add(Weight::from_ref_time(116_831_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(116_831_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1434,11 +1434,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(207_406_000 as RefTimeWeight) + Weight::from_ref_time(207_406_000 as u64) // Standard Error: 117_000 - .saturating_add(Weight::from_ref_time(40_702_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_702_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1446,11 +1446,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_260_000 as RefTimeWeight) + Weight::from_ref_time(209_260_000 as u64) // Standard Error: 130_000 - .saturating_add(Weight::from_ref_time(40_479_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_479_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1458,11 +1458,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(206_448_000 as RefTimeWeight) + Weight::from_ref_time(206_448_000 as u64) // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(40_134_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_134_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1470,11 +1470,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(206_969_000 as RefTimeWeight) + Weight::from_ref_time(206_969_000 as u64) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(40_251_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_251_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1483,11 +1483,11 @@ impl WeightInfo for () { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(211_611_000 as RefTimeWeight) + Weight::from_ref_time(211_611_000 as u64) // Standard Error: 175_000 - .saturating_add(Weight::from_ref_time(98_675_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(98_675_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1495,11 +1495,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(134_484_000 as RefTimeWeight) + Weight::from_ref_time(134_484_000 as u64) // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(19_329_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(19_329_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1507,11 +1507,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(208_556_000 as RefTimeWeight) + Weight::from_ref_time(208_556_000 as u64) // Standard Error: 125_000 - .saturating_add(Weight::from_ref_time(40_328_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(40_328_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1519,11 +1519,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(268_886_000 as RefTimeWeight) + Weight::from_ref_time(268_886_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_627_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_627_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1531,9 +1531,9 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 1]`. fn seal_return(_r: u32, ) -> Weight { - Weight::from_ref_time(203_591_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(203_591_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1541,11 +1541,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(204_258_000 as RefTimeWeight) + Weight::from_ref_time(204_258_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(183_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(183_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1555,13 +1555,13 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(206_625_000 as RefTimeWeight) + Weight::from_ref_time(206_625_000 as u64) // Standard Error: 672_000 - .saturating_add(Weight::from_ref_time(59_377_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((4 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((5 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(59_377_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1570,11 +1570,11 @@ impl WeightInfo for () { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(208_866_000 as RefTimeWeight) + Weight::from_ref_time(208_866_000 as u64) // Standard Error: 164_000 - .saturating_add(Weight::from_ref_time(133_438_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(133_438_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1582,11 +1582,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(220_860_000 as RefTimeWeight) + Weight::from_ref_time(220_860_000 as u64) // Standard Error: 209_000 - .saturating_add(Weight::from_ref_time(239_951_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(239_951_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1596,15 +1596,15 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(439_782_000 as RefTimeWeight) + Weight::from_ref_time(439_782_000 as u64) // Standard Error: 1_643_000 - .saturating_add(Weight::from_ref_time(264_687_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(264_687_000 as u64).saturating_mul(t as u64)) // Standard Error: 323_000 - .saturating_add(Weight::from_ref_time(67_636_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(67_636_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(t as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1612,128 +1612,128 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(140_280_000 as RefTimeWeight) + Weight::from_ref_time(140_280_000 as u64) // Standard Error: 82_000 - .saturating_add(Weight::from_ref_time(32_717_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(32_717_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(161_247_000 as RefTimeWeight) + Weight::from_ref_time(161_247_000 as u64) // Standard Error: 883_000 - .saturating_add(Weight::from_ref_time(423_997_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(423_997_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_247_000 as RefTimeWeight) + Weight::from_ref_time(529_247_000 as u64) // Standard Error: 2_745_000 - .saturating_add(Weight::from_ref_time(85_282_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(53 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(85_282_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(55 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(53 as u64)) + .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_812_000 as RefTimeWeight) + Weight::from_ref_time(529_812_000 as u64) // Standard Error: 2_513_000 - .saturating_add(Weight::from_ref_time(74_554_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(53 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(74_554_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(55 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(53 as u64)) + .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(184_803_000 as RefTimeWeight) + Weight::from_ref_time(184_803_000 as u64) // Standard Error: 733_000 - .saturating_add(Weight::from_ref_time(404_933_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(404_933_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(500_958_000 as RefTimeWeight) + Weight::from_ref_time(500_958_000 as u64) // Standard Error: 2_980_000 - .saturating_add(Weight::from_ref_time(75_996_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(52 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(75_996_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(55 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(52 as u64)) + .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(177_682_000 as RefTimeWeight) + Weight::from_ref_time(177_682_000 as u64) // Standard Error: 743_000 - .saturating_add(Weight::from_ref_time(338_172_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(338_172_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(465_285_000 as RefTimeWeight) + Weight::from_ref_time(465_285_000 as u64) // Standard Error: 2_599_000 - .saturating_add(Weight::from_ref_time(155_106_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(155_106_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(55 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(179_118_000 as RefTimeWeight) + Weight::from_ref_time(179_118_000 as u64) // Standard Error: 572_000 - .saturating_add(Weight::from_ref_time(311_083_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(311_083_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(423_056_000 as RefTimeWeight) + Weight::from_ref_time(423_056_000 as u64) // Standard Error: 2_037_000 - .saturating_add(Weight::from_ref_time(69_665_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(54 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(69_665_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(54 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(188_884_000 as RefTimeWeight) + Weight::from_ref_time(188_884_000 as u64) // Standard Error: 761_000 - .saturating_add(Weight::from_ref_time(432_781_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(432_781_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(532_408_000 as RefTimeWeight) + Weight::from_ref_time(532_408_000 as u64) // Standard Error: 3_348_000 - .saturating_add(Weight::from_ref_time(164_943_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(55 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(53 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(164_943_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(55 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(53 as u64)) + .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1741,13 +1741,13 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(127_181_000 as RefTimeWeight) + Weight::from_ref_time(127_181_000 as u64) // Standard Error: 1_495_000 - .saturating_add(Weight::from_ref_time(1_500_589_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(1_500_589_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1755,13 +1755,13 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 3_803_000 - .saturating_add(Weight::from_ref_time(14_860_909_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((80 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(14_860_909_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1769,11 +1769,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 6_045_000 - .saturating_add(Weight::from_ref_time(14_797_140_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(14_797_140_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads((79 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -1782,15 +1782,15 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(9_196_444_000 as RefTimeWeight) + Weight::from_ref_time(9_196_444_000 as u64) // Standard Error: 20_486_000 - .saturating_add(Weight::from_ref_time(1_458_153_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_458_153_000 as u64).saturating_mul(t as u64)) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(9_718_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(85 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((81 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(81 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((81 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(9_718_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(85 as u64)) + .saturating_add(RocksDbWeight::get().reads((81 as u64).saturating_mul(t as u64))) + .saturating_add(RocksDbWeight::get().writes(81 as u64)) + .saturating_add(RocksDbWeight::get().writes((81 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1800,13 +1800,13 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 36_253_000 - .saturating_add(Weight::from_ref_time(21_201_529_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((320 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((320 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(21_201_529_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().reads((320 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((320 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:81 w:81) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -1817,15 +1817,15 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(12_282_498_000 as RefTimeWeight) + Weight::from_ref_time(12_282_498_000 as u64) // Standard Error: 48_112_000 - .saturating_add(Weight::from_ref_time(720_795_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(720_795_000 as u64).saturating_mul(t as u64)) // Standard Error: 22_000 - .saturating_add(Weight::from_ref_time(124_274_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(167 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(165 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(t as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(124_274_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(167 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(t as u64))) + .saturating_add(RocksDbWeight::get().writes(165 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1833,11 +1833,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(203_959_000 as RefTimeWeight) + Weight::from_ref_time(203_959_000 as u64) // Standard Error: 142_000 - .saturating_add(Weight::from_ref_time(61_311_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(61_311_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1845,11 +1845,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(349_915_000 as RefTimeWeight) + Weight::from_ref_time(349_915_000 as u64) // Standard Error: 40_000 - .saturating_add(Weight::from_ref_time(320_652_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(320_652_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1857,11 +1857,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(209_219_000 as RefTimeWeight) + Weight::from_ref_time(209_219_000 as u64) // Standard Error: 157_000 - .saturating_add(Weight::from_ref_time(73_728_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_728_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1869,11 +1869,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(208_860_000 as RefTimeWeight) + Weight::from_ref_time(208_860_000 as u64) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(245_718_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(245_718_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1881,11 +1881,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(206_165_000 as RefTimeWeight) + Weight::from_ref_time(206_165_000 as u64) // Standard Error: 138_000 - .saturating_add(Weight::from_ref_time(51_644_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_644_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1893,11 +1893,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(255_955_000 as RefTimeWeight) + Weight::from_ref_time(255_955_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_090_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_090_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1905,11 +1905,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(208_153_000 as RefTimeWeight) + Weight::from_ref_time(208_153_000 as u64) // Standard Error: 140_000 - .saturating_add(Weight::from_ref_time(51_264_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_264_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1917,11 +1917,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(278_368_000 as RefTimeWeight) + Weight::from_ref_time(278_368_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_006_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_006_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1929,11 +1929,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(331_955_000 as RefTimeWeight) + Weight::from_ref_time(331_955_000 as u64) // Standard Error: 1_155_000 - .saturating_add(Weight::from_ref_time(3_069_955_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_069_955_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1941,11 +1941,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(207_838_000 as RefTimeWeight) + Weight::from_ref_time(207_838_000 as u64) // Standard Error: 783_000 - .saturating_add(Weight::from_ref_time(2_058_503_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_058_503_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1954,316 +1954,316 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 1_567_000 - .saturating_add(Weight::from_ref_time(774_380_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes((79 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(774_380_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads((79 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes((79 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(73_955_000 as RefTimeWeight) + Weight::from_ref_time(73_955_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(612_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(612_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(74_057_000 as RefTimeWeight) + Weight::from_ref_time(74_057_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(74_137_000 as RefTimeWeight) + Weight::from_ref_time(74_137_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_427_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(73_844_000 as RefTimeWeight) + Weight::from_ref_time(73_844_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_773_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_773_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as RefTimeWeight) + Weight::from_ref_time(73_979_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_952_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_952_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(73_924_000 as RefTimeWeight) + Weight::from_ref_time(73_924_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(941_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(941_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_574_000 as RefTimeWeight) + Weight::from_ref_time(73_574_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_439_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_439_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(73_343_000 as RefTimeWeight) + Weight::from_ref_time(73_343_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_603_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_603_000 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(76_267_000 as RefTimeWeight) + Weight::from_ref_time(76_267_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(74_877_000 as RefTimeWeight) + Weight::from_ref_time(74_877_000 as u64) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(7_144_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(7_144_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(88_665_000 as RefTimeWeight) + Weight::from_ref_time(88_665_000 as u64) // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(9_142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_142_000 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(98_600_000 as RefTimeWeight) + Weight::from_ref_time(98_600_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(469_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(469_000 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(74_555_000 as RefTimeWeight) + Weight::from_ref_time(74_555_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(624_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(624_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(74_329_000 as RefTimeWeight) + Weight::from_ref_time(74_329_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(688_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(688_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(74_612_000 as RefTimeWeight) + Weight::from_ref_time(74_612_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(909_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(909_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(76_906_000 as RefTimeWeight) + Weight::from_ref_time(76_906_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_192_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_192_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(76_979_000 as RefTimeWeight) + Weight::from_ref_time(76_979_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_361_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_361_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(74_370_000 as RefTimeWeight) + Weight::from_ref_time(74_370_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(661_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(661_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(73_584_000 as RefTimeWeight) + Weight::from_ref_time(73_584_000 as u64) // Standard Error: 353_000 - .saturating_add(Weight::from_ref_time(187_114_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(187_114_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(74_206_000 as RefTimeWeight) + Weight::from_ref_time(74_206_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(884_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(884_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(73_992_000 as RefTimeWeight) + Weight::from_ref_time(73_992_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(893_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(893_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(73_985_000 as RefTimeWeight) + Weight::from_ref_time(73_985_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(891_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(891_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(74_117_000 as RefTimeWeight) + Weight::from_ref_time(74_117_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(901_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(73_981_000 as RefTimeWeight) + Weight::from_ref_time(73_981_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(866_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(866_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(74_104_000 as RefTimeWeight) + Weight::from_ref_time(74_104_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(868_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(74_293_000 as RefTimeWeight) + Weight::from_ref_time(74_293_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(878_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(878_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(74_055_000 as RefTimeWeight) + Weight::from_ref_time(74_055_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(73_710_000 as RefTimeWeight) + Weight::from_ref_time(73_710_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(73_917_000 as RefTimeWeight) + Weight::from_ref_time(73_917_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_355_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(74_048_000 as RefTimeWeight) + Weight::from_ref_time(74_048_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(74_029_000 as RefTimeWeight) + Weight::from_ref_time(74_029_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_349_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_349_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(74_267_000 as RefTimeWeight) + Weight::from_ref_time(74_267_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(73_952_000 as RefTimeWeight) + Weight::from_ref_time(73_952_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_350_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(73_851_000 as RefTimeWeight) + Weight::from_ref_time(73_851_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_368_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_368_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(74_034_000 as RefTimeWeight) + Weight::from_ref_time(74_034_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_348_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_348_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as RefTimeWeight) + Weight::from_ref_time(73_979_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_353_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(74_000_000 as RefTimeWeight) + Weight::from_ref_time(74_000_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_328_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_328_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(73_883_000 as RefTimeWeight) + Weight::from_ref_time(73_883_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_331_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_331_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(74_216_000 as RefTimeWeight) + Weight::from_ref_time(74_216_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_324_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(73_989_000 as RefTimeWeight) + Weight::from_ref_time(73_989_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_998_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_998_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(73_857_000 as RefTimeWeight) + Weight::from_ref_time(73_857_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_073_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_073_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(73_801_000 as RefTimeWeight) + Weight::from_ref_time(73_801_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_027_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_027_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(74_130_000 as RefTimeWeight) + Weight::from_ref_time(74_130_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_064_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_064_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(74_071_000 as RefTimeWeight) + Weight::from_ref_time(74_071_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_327_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_327_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(74_201_000 as RefTimeWeight) + Weight::from_ref_time(74_201_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_330_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_330_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(74_241_000 as RefTimeWeight) + Weight::from_ref_time(74_241_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_321_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_321_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(74_331_000 as RefTimeWeight) + Weight::from_ref_time(74_331_000 as u64) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_347_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_347_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(73_674_000 as RefTimeWeight) + Weight::from_ref_time(73_674_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_359_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_359_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(73_807_000 as RefTimeWeight) + Weight::from_ref_time(73_807_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(73_725_000 as RefTimeWeight) + Weight::from_ref_time(73_725_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(73_755_000 as RefTimeWeight) + Weight::from_ref_time(73_755_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_360_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) } } diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index dbc7ce06ee825..6428d82c94c39 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_conviction_voting. @@ -62,9 +62,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_new() -> Weight { - Weight::from_ref_time(148_804_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(148_804_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: ConvictionVoting VotingFor (r:1 w:1) @@ -72,24 +72,24 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_existing() -> Weight { - Weight::from_ref_time(313_333_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(313_333_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn remove_vote() -> Weight { - Weight::from_ref_time(300_591_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(300_591_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:0) fn remove_other_vote() -> Weight { - Weight::from_ref_time(53_887_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(53_887_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: ConvictionVoting VotingFor (r:2 w:2) // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) @@ -97,33 +97,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(51_518_000 as RefTimeWeight) + Weight::from_ref_time(51_518_000 as u64) // Standard Error: 83_000 - .saturating_add(Weight::from_ref_time(27_235_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(27_235_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(r as u64))) } // Storage: ConvictionVoting VotingFor (r:2 w:2) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(37_885_000 as RefTimeWeight) + Weight::from_ref_time(37_885_000 as u64) // Standard Error: 75_000 - .saturating_add(Weight::from_ref_time(24_395_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(24_395_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(r as u64))) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn unlock() -> Weight { - Weight::from_ref_time(67_703_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(67_703_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } } @@ -135,9 +135,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_new() -> Weight { - Weight::from_ref_time(148_804_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(148_804_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: ConvictionVoting VotingFor (r:1 w:1) @@ -145,24 +145,24 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_existing() -> Weight { - Weight::from_ref_time(313_333_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(313_333_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn remove_vote() -> Weight { - Weight::from_ref_time(300_591_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(300_591_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:0) fn remove_other_vote() -> Weight { - Weight::from_ref_time(53_887_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(53_887_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: ConvictionVoting VotingFor (r:2 w:2) // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) @@ -170,32 +170,32 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(51_518_000 as RefTimeWeight) + Weight::from_ref_time(51_518_000 as u64) // Standard Error: 83_000 - .saturating_add(Weight::from_ref_time(27_235_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(27_235_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(r as u64))) } // Storage: ConvictionVoting VotingFor (r:2 w:2) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(37_885_000 as RefTimeWeight) + Weight::from_ref_time(37_885_000 as u64) // Standard Error: 75_000 - .saturating_add(Weight::from_ref_time(24_395_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(24_395_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(r as u64))) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn unlock() -> Weight { - Weight::from_ref_time(67_703_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(67_703_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } } diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index ad11526736c9c..272921ed3a15d 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_democracy. @@ -80,44 +80,44 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - Weight::from_ref_time(48_328_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(48_328_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - Weight::from_ref_time(30_923_000 as RefTimeWeight) + Weight::from_ref_time(30_923_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - Weight::from_ref_time(40_345_000 as RefTimeWeight) + Weight::from_ref_time(40_345_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(140_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(140_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - Weight::from_ref_time(39_853_000 as RefTimeWeight) + Weight::from_ref_time(39_853_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - Weight::from_ref_time(19_364_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(19_364_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy NextExternal (r:1 w:1) @@ -126,82 +126,82 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - Weight::from_ref_time(57_708_000 as RefTimeWeight) + Weight::from_ref_time(57_708_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - Weight::from_ref_time(10_714_000 as RefTimeWeight) + Weight::from_ref_time(10_714_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - Weight::from_ref_time(3_697_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_697_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - Weight::from_ref_time(3_831_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_831_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - Weight::from_ref_time(20_271_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(20_271_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - Weight::from_ref_time(21_319_000 as RefTimeWeight) + Weight::from_ref_time(21_319_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(43_960_000 as RefTimeWeight) + Weight::from_ref_time(43_960_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(184_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - Weight::from_ref_time(13_475_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(13_475_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - Weight::from_ref_time(24_320_000 as RefTimeWeight) + Weight::from_ref_time(24_320_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(560_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(560_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - Weight::from_ref_time(3_428_000 as RefTimeWeight) + Weight::from_ref_time(3_428_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_171_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_171_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) @@ -210,103 +210,103 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - Weight::from_ref_time(7_867_000 as RefTimeWeight) + Weight::from_ref_time(7_867_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_177_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_177_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:3 w:3) // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(37_902_000 as RefTimeWeight) + Weight::from_ref_time(37_902_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(4_335_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(4_335_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(r as u64))) } // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(21_272_000 as RefTimeWeight) + Weight::from_ref_time(21_272_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(4_351_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(4_351_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(r as u64))) } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - Weight::from_ref_time(4_913_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(4_913_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(27_986_000 as RefTimeWeight) + Weight::from_ref_time(27_986_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(20_058_000 as RefTimeWeight) + Weight::from_ref_time(20_058_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(28_619_000 as RefTimeWeight) + Weight::from_ref_time(28_619_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - Weight::from_ref_time(26_619_000 as RefTimeWeight) + Weight::from_ref_time(26_619_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - Weight::from_ref_time(25_373_000 as RefTimeWeight) + Weight::from_ref_time(25_373_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_961_000 as RefTimeWeight) + Weight::from_ref_time(15_961_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_992_000 as RefTimeWeight) + Weight::from_ref_time(15_992_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(113_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } } @@ -317,44 +317,44 @@ impl WeightInfo for () { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - Weight::from_ref_time(48_328_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(48_328_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy DepositOf (r:1 w:1) fn second(s: u32, ) -> Weight { - Weight::from_ref_time(30_923_000 as RefTimeWeight) + Weight::from_ref_time(30_923_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new(r: u32, ) -> Weight { - Weight::from_ref_time(40_345_000 as RefTimeWeight) + Weight::from_ref_time(40_345_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(140_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(140_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing(r: u32, ) -> Weight { - Weight::from_ref_time(39_853_000 as RefTimeWeight) + Weight::from_ref_time(39_853_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - Weight::from_ref_time(19_364_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(19_364_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy NextExternal (r:1 w:1) @@ -363,82 +363,82 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn blacklist(p: u32, ) -> Weight { - Weight::from_ref_time(57_708_000 as RefTimeWeight) + Weight::from_ref_time(57_708_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(192_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose(v: u32, ) -> Weight { - Weight::from_ref_time(10_714_000 as RefTimeWeight) + Weight::from_ref_time(10_714_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - Weight::from_ref_time(3_697_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_697_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - Weight::from_ref_time(3_831_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_831_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - Weight::from_ref_time(20_271_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(20_271_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external(v: u32, ) -> Weight { - Weight::from_ref_time(21_319_000 as RefTimeWeight) + Weight::from_ref_time(21_319_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(43_960_000 as RefTimeWeight) + Weight::from_ref_time(43_960_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(184_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - Weight::from_ref_time(13_475_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(13_475_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_queued(r: u32, ) -> Weight { - Weight::from_ref_time(24_320_000 as RefTimeWeight) + Weight::from_ref_time(24_320_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(560_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(560_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base(r: u32, ) -> Weight { - Weight::from_ref_time(3_428_000 as RefTimeWeight) + Weight::from_ref_time(3_428_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_171_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_171_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) @@ -447,102 +447,102 @@ impl WeightInfo for () { // Storage: Democracy PublicProps (r:1 w:0) // Storage: Democracy ReferendumInfoOf (r:1 w:0) fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - Weight::from_ref_time(7_867_000 as RefTimeWeight) + Weight::from_ref_time(7_867_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_177_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_177_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:3 w:3) // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(37_902_000 as RefTimeWeight) + Weight::from_ref_time(37_902_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(4_335_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(4_335_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(r as u64))) } // Storage: Democracy VotingOf (r:2 w:2) // Storage: Democracy ReferendumInfoOf (r:1 w:1) fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(21_272_000 as RefTimeWeight) + Weight::from_ref_time(21_272_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(4_351_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(4_351_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(r as u64))) } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - Weight::from_ref_time(4_913_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(4_913_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy Preimages (r:1 w:1) fn note_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(27_986_000 as RefTimeWeight) + Weight::from_ref_time(27_986_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy Preimages (r:1 w:1) fn note_imminent_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(20_058_000 as RefTimeWeight) + Weight::from_ref_time(20_058_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy Preimages (r:1 w:1) // Storage: System Account (r:1 w:0) fn reap_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(28_619_000 as RefTimeWeight) + Weight::from_ref_time(28_619_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_remove(r: u32, ) -> Weight { - Weight::from_ref_time(26_619_000 as RefTimeWeight) + Weight::from_ref_time(26_619_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlock_set(r: u32, ) -> Weight { - Weight::from_ref_time(25_373_000 as RefTimeWeight) + Weight::from_ref_time(25_373_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_961_000 as RefTimeWeight) + Weight::from_ref_time(15_961_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) fn remove_other_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_992_000 as RefTimeWeight) + Weight::from_ref_time(15_992_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(113_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 0e7af39badd44..5e5191242bd77 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_election_provider_multi_phase. @@ -68,46 +68,46 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - Weight::from_ref_time(13_495_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) + Weight::from_ref_time(13_495_000 as u64) + .saturating_add(T::DbWeight::get().reads(8 as u64)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - Weight::from_ref_time(14_114_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(14_114_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - Weight::from_ref_time(13_756_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(13_756_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - Weight::from_ref_time(28_467_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(28_467_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - Weight::from_ref_time(21_991_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(21_991_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - Weight::from_ref_time(3_186_000 as RefTimeWeight) + Weight::from_ref_time(3_186_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(202_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(202_000 as u64).saturating_mul(v as u64)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(60_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(60_000 as u64).saturating_mul(t as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) @@ -119,13 +119,13 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(137_653_000 as RefTimeWeight) + Weight::from_ref_time(137_653_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(640_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(640_000 as u64).saturating_mul(a as u64)) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(8 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(48_000 as u64).saturating_mul(d as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(8 as u64)) } // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) @@ -134,9 +134,9 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit() -> Weight { - Weight::from_ref_time(49_313_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(49_313_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: ElectionProviderMultiPhase Round (r:1 w:0) @@ -146,33 +146,33 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(867_000 as u64).saturating_mul(v as u64)) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(107_000 as u64).saturating_mul(t as u64)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(6_907_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(6_907_000 as u64).saturating_mul(a as u64)) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_427_000 as u64).saturating_mul(d as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(844_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(844_000 as u64).saturating_mul(v as u64)) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(t as u64)) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(5_421_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_421_000 as u64).saturating_mul(a as u64)) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(1_167_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_167_000 as u64).saturating_mul(d as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) } } @@ -187,46 +187,46 @@ impl WeightInfo for () { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - Weight::from_ref_time(13_495_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) + Weight::from_ref_time(13_495_000 as u64) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - Weight::from_ref_time(14_114_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(14_114_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - Weight::from_ref_time(13_756_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(13_756_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - Weight::from_ref_time(28_467_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(28_467_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - Weight::from_ref_time(21_991_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(21_991_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - Weight::from_ref_time(3_186_000 as RefTimeWeight) + Weight::from_ref_time(3_186_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(202_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(202_000 as u64).saturating_mul(v as u64)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(60_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(60_000 as u64).saturating_mul(t as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) @@ -238,13 +238,13 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn elect_queued(a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(137_653_000 as RefTimeWeight) + Weight::from_ref_time(137_653_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(640_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(640_000 as u64).saturating_mul(a as u64)) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(48_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(8 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(48_000 as u64).saturating_mul(d as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(8 as u64)) } // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) @@ -253,9 +253,9 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit() -> Weight { - Weight::from_ref_time(49_313_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(49_313_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: ElectionProviderMultiPhase Round (r:1 w:0) @@ -265,32 +265,32 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(867_000 as u64).saturating_mul(v as u64)) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(107_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(107_000 as u64).saturating_mul(t as u64)) // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(6_907_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(6_907_000 as u64).saturating_mul(a as u64)) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(1_427_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_427_000 as u64).saturating_mul(d as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(844_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(844_000 as u64).saturating_mul(v as u64)) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(150_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(t as u64)) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(5_421_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_421_000 as u64).saturating_mul(a as u64)) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(1_167_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_167_000 as u64).saturating_mul(d as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) } } diff --git a/frame/election-provider-support/src/weights.rs b/frame/election-provider-support/src/weights.rs index ed7360940ba58..44075ba871228 100644 --- a/frame/election-provider-support/src/weights.rs +++ b/frame/election-provider-support/src/weights.rs @@ -40,7 +40,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_election_provider_support_benchmarking. @@ -53,43 +53,43 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 667_000 - .saturating_add(Weight::from_ref_time(32_973_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(32_973_000 as u64).saturating_mul(v as u64)) // Standard Error: 1_334_000 - .saturating_add(Weight::from_ref_time(1_334_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_334_000 as u64).saturating_mul(t as u64)) // Standard Error: 60_644_000 - .saturating_add(Weight::from_ref_time(2_636_364_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_636_364_000 as u64).saturating_mul(d as u64)) } fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 73_000 - .saturating_add(Weight::from_ref_time(21_073_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(21_073_000 as u64).saturating_mul(v as u64)) // Standard Error: 146_000 - .saturating_add(Weight::from_ref_time(65_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(65_000 as u64).saturating_mul(t as u64)) // Standard Error: 6_649_000 - .saturating_add(Weight::from_ref_time(1_711_424_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_711_424_000 as u64).saturating_mul(d as u64)) } } // For backwards compatibility and tests impl WeightInfo for () { fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 667_000 - .saturating_add(Weight::from_ref_time(32_973_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(32_973_000 as u64).saturating_mul(v as u64)) // Standard Error: 1_334_000 - .saturating_add(Weight::from_ref_time(1_334_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_334_000 as u64).saturating_mul(t as u64)) // Standard Error: 60_644_000 - .saturating_add(Weight::from_ref_time(2_636_364_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_636_364_000 as u64).saturating_mul(d as u64)) } fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 73_000 - .saturating_add(Weight::from_ref_time(21_073_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(21_073_000 as u64).saturating_mul(v as u64)) // Standard Error: 146_000 - .saturating_add(Weight::from_ref_time(65_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(65_000 as u64).saturating_mul(t as u64)) // Standard Error: 6_649_000 - .saturating_add(Weight::from_ref_time(1_711_424_000 as RefTimeWeight).saturating_mul(d as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_711_424_000 as u64).saturating_mul(d as u64)) } } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 051aaa793588c..52a5dedc723d4 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_elections_phragmen. @@ -70,11 +70,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - Weight::from_ref_time(27_011_000 as RefTimeWeight) + Weight::from_ref_time(27_011_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(214_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(214_000 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Elections Candidates (r:1 w:0) // Storage: Elections Members (r:1 w:0) @@ -83,11 +83,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - Weight::from_ref_time(40_240_000 as RefTimeWeight) + Weight::from_ref_time(40_240_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(244_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(244_000 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Elections Candidates (r:1 w:0) // Storage: Elections Members (r:1 w:0) @@ -96,38 +96,38 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - Weight::from_ref_time(40_394_000 as RefTimeWeight) + Weight::from_ref_time(40_394_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(217_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(217_000 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - Weight::from_ref_time(37_651_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(37_651_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - Weight::from_ref_time(42_217_000 as RefTimeWeight) + Weight::from_ref_time(42_217_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(50_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(50_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Elections Candidates (r:1 w:1) /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - Weight::from_ref_time(46_459_000 as RefTimeWeight) + Weight::from_ref_time(46_459_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(26_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(26_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Elections Members (r:1 w:1) // Storage: Elections RunnersUp (r:1 w:1) @@ -135,19 +135,19 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - Weight::from_ref_time(45_189_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(45_189_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - Weight::from_ref_time(34_516_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(34_516_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Benchmark Override (r:0 w:0) fn remove_member_without_replacement() -> Weight { - Weight::from_ref_time(2_000_000_000_000 as RefTimeWeight) + Weight::from_ref_time(2_000_000_000_000 as u64) } // Storage: Elections Members (r:1 w:1) // Storage: System Account (r:1 w:1) @@ -156,9 +156,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - Weight::from_ref_time(51_838_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(51_838_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Elections Voting (r:5001 w:5000) // Storage: Elections Members (r:1 w:0) @@ -169,12 +169,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[5000, 10000]`. /// The range of component `d` is `[1, 5000]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 76_000 - .saturating_add(Weight::from_ref_time(63_721_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(63_721_000 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(v as u64))) + .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(v as u64))) } // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:1) @@ -189,15 +189,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 10000]`. /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 773_000 - .saturating_add(Weight::from_ref_time(81_534_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(81_534_000 as u64).saturating_mul(v as u64)) // Standard Error: 51_000 - .saturating_add(Weight::from_ref_time(4_453_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(280 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(4_453_000 as u64).saturating_mul(e as u64)) + .saturating_add(T::DbWeight::get().reads(280 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(c as u64))) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(c as u64))) } } @@ -210,11 +210,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - Weight::from_ref_time(27_011_000 as RefTimeWeight) + Weight::from_ref_time(27_011_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(214_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(214_000 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Elections Candidates (r:1 w:0) // Storage: Elections Members (r:1 w:0) @@ -223,11 +223,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - Weight::from_ref_time(40_240_000 as RefTimeWeight) + Weight::from_ref_time(40_240_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(244_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(244_000 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Elections Candidates (r:1 w:0) // Storage: Elections Members (r:1 w:0) @@ -236,38 +236,38 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - Weight::from_ref_time(40_394_000 as RefTimeWeight) + Weight::from_ref_time(40_394_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(217_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(217_000 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - Weight::from_ref_time(37_651_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(37_651_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: Elections RunnersUp (r:1 w:0) /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - Weight::from_ref_time(42_217_000 as RefTimeWeight) + Weight::from_ref_time(42_217_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(50_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(50_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Elections Candidates (r:1 w:1) /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - Weight::from_ref_time(46_459_000 as RefTimeWeight) + Weight::from_ref_time(46_459_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(26_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(26_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Elections Members (r:1 w:1) // Storage: Elections RunnersUp (r:1 w:1) @@ -275,19 +275,19 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - Weight::from_ref_time(45_189_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(45_189_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - Weight::from_ref_time(34_516_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(34_516_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Benchmark Override (r:0 w:0) fn remove_member_without_replacement() -> Weight { - Weight::from_ref_time(2_000_000_000_000 as RefTimeWeight) + Weight::from_ref_time(2_000_000_000_000 as u64) } // Storage: Elections Members (r:1 w:1) // Storage: System Account (r:1 w:1) @@ -296,9 +296,9 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - Weight::from_ref_time(51_838_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(51_838_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Elections Voting (r:5001 w:5000) // Storage: Elections Members (r:1 w:0) @@ -309,12 +309,12 @@ impl WeightInfo for () { /// The range of component `v` is `[5000, 10000]`. /// The range of component `d` is `[1, 5000]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 76_000 - .saturating_add(Weight::from_ref_time(63_721_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(63_721_000 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(v as u64))) + .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(v as u64))) } // Storage: Elections Candidates (r:1 w:1) // Storage: Elections Members (r:1 w:1) @@ -329,14 +329,14 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 10000]`. /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 773_000 - .saturating_add(Weight::from_ref_time(81_534_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(81_534_000 as u64).saturating_mul(v as u64)) // Standard Error: 51_000 - .saturating_add(Weight::from_ref_time(4_453_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(280 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(c as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(4_453_000 as u64).saturating_mul(e as u64)) + .saturating_add(RocksDbWeight::get().reads(280 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(c as u64))) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(c as u64))) } } diff --git a/frame/examples/basic/src/weights.rs b/frame/examples/basic/src/weights.rs index d27915ef1b02a..986648b4302bc 100644 --- a/frame/examples/basic/src/weights.rs +++ b/frame/examples/basic/src/weights.rs @@ -49,7 +49,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_example_basic. @@ -63,39 +63,39 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn set_dummy_benchmark(b: u32, ) -> Weight { - Weight::from_ref_time(5_834_000 as RefTimeWeight) - .saturating_add(Weight::from_ref_time(24_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(5_834_000 as u64) + .saturating_add(Weight::from_ref_time(24_000 as u64).saturating_mul(b as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } fn accumulate_dummy(b: u32, ) -> Weight { - Weight::from_ref_time(51_353_000 as RefTimeWeight) - .saturating_add(Weight::from_ref_time(14_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(51_353_000 as u64) + .saturating_add(Weight::from_ref_time(14_000 as u64).saturating_mul(b as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } fn sort_vector(x: u32, ) -> Weight { - Weight::from_ref_time(2_569_000 as RefTimeWeight) + Weight::from_ref_time(2_569_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(x as u64)) } } // For backwards compatibility and tests impl WeightInfo for () { fn set_dummy_benchmark(b: u32, ) -> Weight { - Weight::from_ref_time(5_834_000 as RefTimeWeight) - .saturating_add(Weight::from_ref_time(24_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(5_834_000 as u64) + .saturating_add(Weight::from_ref_time(24_000 as u64).saturating_mul(b as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } fn accumulate_dummy(b: u32, ) -> Weight { - Weight::from_ref_time(51_353_000 as RefTimeWeight) - .saturating_add(Weight::from_ref_time(14_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(51_353_000 as u64) + .saturating_add(Weight::from_ref_time(14_000 as u64).saturating_mul(b as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } fn sort_vector(x: u32, ) -> Weight { - Weight::from_ref_time(2_569_000 as RefTimeWeight) + Weight::from_ref_time(2_569_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(x as u64)) } } diff --git a/frame/gilt/src/weights.rs b/frame/gilt/src/weights.rs index 124ee7593a778..15eeb7c5104cd 100644 --- a/frame/gilt/src/weights.rs +++ b/frame/gilt/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_gilt. @@ -60,70 +60,70 @@ impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - Weight::from_ref_time(41_605_000 as RefTimeWeight) + Weight::from_ref_time(41_605_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(62_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(62_000 as u64).saturating_mul(l as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - Weight::from_ref_time(97_715_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(97_715_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - Weight::from_ref_time(42_061_000 as RefTimeWeight) + Weight::from_ref_time(42_061_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(l as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - Weight::from_ref_time(5_026_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(5_026_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - Weight::from_ref_time(47_753_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(47_753_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - Weight::from_ref_time(1_663_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + Weight::from_ref_time(1_663_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - Weight::from_ref_time(40_797_000 as RefTimeWeight) + Weight::from_ref_time(40_797_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(4_122_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(4_122_000 as u64).saturating_mul(b as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(b as u64))) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - Weight::from_ref_time(14_944_000 as RefTimeWeight) + Weight::from_ref_time(14_944_000 as u64) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(8_135_000 as RefTimeWeight).saturating_mul(q as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(q as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(q as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(8_135_000 as u64).saturating_mul(q as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(q as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(q as u64))) } } @@ -132,69 +132,69 @@ impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { - Weight::from_ref_time(41_605_000 as RefTimeWeight) + Weight::from_ref_time(41_605_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(62_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(62_000 as u64).saturating_mul(l as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - Weight::from_ref_time(97_715_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(97_715_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { - Weight::from_ref_time(42_061_000 as RefTimeWeight) + Weight::from_ref_time(42_061_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(l as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - Weight::from_ref_time(5_026_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(5_026_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - Weight::from_ref_time(47_753_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(47_753_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - Weight::from_ref_time(1_663_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + Weight::from_ref_time(1_663_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_item(b: u32, ) -> Weight { - Weight::from_ref_time(40_797_000 as RefTimeWeight) + Weight::from_ref_time(40_797_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(4_122_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(b as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(4_122_000 as u64).saturating_mul(b as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(b as u64))) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt Active (r:0 w:1) fn pursue_target_per_queue(q: u32, ) -> Weight { - Weight::from_ref_time(14_944_000 as RefTimeWeight) + Weight::from_ref_time(14_944_000 as u64) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(8_135_000 as RefTimeWeight).saturating_mul(q as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(q as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(q as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(8_135_000 as u64).saturating_mul(q as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(q as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(q as u64))) } } diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 1aa8d7963223e..d65499034d74a 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -40,7 +40,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_identity. @@ -69,48 +69,48 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - Weight::from_ref_time(16_649_000 as RefTimeWeight) + Weight::from_ref_time(16_649_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(241_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(241_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(31_322_000 as RefTimeWeight) + Weight::from_ref_time(31_322_000 as u64) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(252_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(252_000 as u64).saturating_mul(r as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(312_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(312_000 as u64).saturating_mul(x as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn set_subs_new(s: u32, ) -> Weight { - Weight::from_ref_time(30_012_000 as RefTimeWeight) + Weight::from_ref_time(30_012_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_005_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(3_005_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn set_subs_old(p: u32, ) -> Weight { - Weight::from_ref_time(29_623_000 as RefTimeWeight) + Weight::from_ref_time(29_623_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_100_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(1_100_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(p as u64))) } // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity IdentityOf (r:1 w:1) @@ -119,81 +119,81 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. /// The range of component `x` is `[1, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - Weight::from_ref_time(34_370_000 as RefTimeWeight) + Weight::from_ref_time(34_370_000 as u64) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(186_000 as u64).saturating_mul(r as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_114_000 as u64).saturating_mul(s as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(189_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(189_000 as u64).saturating_mul(x as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(34_759_000 as RefTimeWeight) + Weight::from_ref_time(34_759_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(251_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(251_000 as u64).saturating_mul(r as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(340_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(340_000 as u64).saturating_mul(x as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(32_254_000 as RefTimeWeight) + Weight::from_ref_time(32_254_000 as u64) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(159_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(159_000 as u64).saturating_mul(r as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(347_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(347_000 as u64).saturating_mul(x as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - Weight::from_ref_time(7_858_000 as RefTimeWeight) + Weight::from_ref_time(7_858_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(190_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(190_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - Weight::from_ref_time(8_011_000 as RefTimeWeight) + Weight::from_ref_time(8_011_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(187_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(187_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - Weight::from_ref_time(7_970_000 as RefTimeWeight) + Weight::from_ref_time(7_970_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(175_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 19]`. /// The range of component `x` is `[1, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(24_730_000 as RefTimeWeight) + Weight::from_ref_time(24_730_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(196_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(196_000 as u64).saturating_mul(r as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(341_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(341_000 as u64).saturating_mul(x as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity IdentityOf (r:1 w:1) @@ -203,58 +203,58 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. /// The range of component `x` is `[1, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - Weight::from_ref_time(44_988_000 as RefTimeWeight) + Weight::from_ref_time(44_988_000 as u64) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(201_000 as u64).saturating_mul(r as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_126_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_126_000 as u64).saturating_mul(s as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(x as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 99]`. fn add_sub(s: u32, ) -> Weight { - Weight::from_ref_time(36_768_000 as RefTimeWeight) + Weight::from_ref_time(36_768_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - Weight::from_ref_time(13_474_000 as RefTimeWeight) + Weight::from_ref_time(13_474_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - Weight::from_ref_time(37_720_000 as RefTimeWeight) + Weight::from_ref_time(37_720_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 99]`. fn quit_sub(s: u32, ) -> Weight { - Weight::from_ref_time(26_848_000 as RefTimeWeight) + Weight::from_ref_time(26_848_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } } @@ -263,48 +263,48 @@ impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - Weight::from_ref_time(16_649_000 as RefTimeWeight) + Weight::from_ref_time(16_649_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(241_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(241_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(31_322_000 as RefTimeWeight) + Weight::from_ref_time(31_322_000 as u64) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(252_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(252_000 as u64).saturating_mul(r as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(312_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(312_000 as u64).saturating_mul(x as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn set_subs_new(s: u32, ) -> Weight { - Weight::from_ref_time(30_012_000 as RefTimeWeight) + Weight::from_ref_time(30_012_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_005_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(3_005_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn set_subs_old(p: u32, ) -> Weight { - Weight::from_ref_time(29_623_000 as RefTimeWeight) + Weight::from_ref_time(29_623_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_100_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(1_100_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(p as u64))) } // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity IdentityOf (r:1 w:1) @@ -313,81 +313,81 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. /// The range of component `x` is `[1, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - Weight::from_ref_time(34_370_000 as RefTimeWeight) + Weight::from_ref_time(34_370_000 as u64) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(186_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(186_000 as u64).saturating_mul(r as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_114_000 as u64).saturating_mul(s as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(189_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(189_000 as u64).saturating_mul(x as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(34_759_000 as RefTimeWeight) + Weight::from_ref_time(34_759_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(251_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(251_000 as u64).saturating_mul(r as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(340_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(340_000 as u64).saturating_mul(x as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[1, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(32_254_000 as RefTimeWeight) + Weight::from_ref_time(32_254_000 as u64) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(159_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(159_000 as u64).saturating_mul(r as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(347_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(347_000 as u64).saturating_mul(x as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - Weight::from_ref_time(7_858_000 as RefTimeWeight) + Weight::from_ref_time(7_858_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(190_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(190_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - Weight::from_ref_time(8_011_000 as RefTimeWeight) + Weight::from_ref_time(8_011_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(187_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(187_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - Weight::from_ref_time(7_970_000 as RefTimeWeight) + Weight::from_ref_time(7_970_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(175_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 19]`. /// The range of component `x` is `[1, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(24_730_000 as RefTimeWeight) + Weight::from_ref_time(24_730_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(196_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(196_000 as u64).saturating_mul(r as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(341_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(341_000 as u64).saturating_mul(x as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity SubsOf (r:1 w:1) // Storage: Identity IdentityOf (r:1 w:1) @@ -397,57 +397,57 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. /// The range of component `x` is `[1, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - Weight::from_ref_time(44_988_000 as RefTimeWeight) + Weight::from_ref_time(44_988_000 as u64) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(201_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(201_000 as u64).saturating_mul(r as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_126_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_126_000 as u64).saturating_mul(s as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(x as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(x as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 99]`. fn add_sub(s: u32, ) -> Weight { - Weight::from_ref_time(36_768_000 as RefTimeWeight) + Weight::from_ref_time(36_768_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - Weight::from_ref_time(13_474_000 as RefTimeWeight) + Weight::from_ref_time(13_474_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - Weight::from_ref_time(37_720_000 as RefTimeWeight) + Weight::from_ref_time(37_720_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 99]`. fn quit_sub(s: u32, ) -> Weight { - Weight::from_ref_time(26_848_000 as RefTimeWeight) + Weight::from_ref_time(26_848_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index acad1e1165d4c..3d20c9a0e614c 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_im_online. @@ -56,13 +56,13 @@ impl WeightInfo for SubstrateWeight { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - Weight::from_ref_time(79_225_000 as RefTimeWeight) + Weight::from_ref_time(79_225_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(41_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(41_000 as u64).saturating_mul(k as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(293_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(293_000 as u64).saturating_mul(e as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } @@ -74,12 +74,12 @@ impl WeightInfo for () { // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - Weight::from_ref_time(79_225_000 as RefTimeWeight) + Weight::from_ref_time(79_225_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(41_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(41_000 as u64).saturating_mul(k as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(293_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(293_000 as u64).saturating_mul(e as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 2475c86fd499b..64bfa744d9b46 100644 --- a/frame/indices/src/weights.rs +++ b/frame/indices/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_indices. @@ -56,35 +56,35 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - Weight::from_ref_time(25_929_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_929_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(32_627_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(32_627_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - Weight::from_ref_time(26_804_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(26_804_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - Weight::from_ref_time(27_390_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(27_390_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - Weight::from_ref_time(30_973_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(30_973_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } @@ -92,34 +92,34 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - Weight::from_ref_time(25_929_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_929_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(32_627_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(32_627_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - Weight::from_ref_time(26_804_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(26_804_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - Weight::from_ref_time(27_390_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(27_390_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - Weight::from_ref_time(30_973_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(30_973_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index 10eda18e0e24f..bae2e8a89c4e5 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_lottery. @@ -63,30 +63,30 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - Weight::from_ref_time(44_706_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(44_706_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - Weight::from_ref_time(12_556_000 as RefTimeWeight) + Weight::from_ref_time(12_556_000 as u64) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(295_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(295_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - Weight::from_ref_time(38_051_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(38_051_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - Weight::from_ref_time(6_910_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(6_910_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -94,9 +94,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - Weight::from_ref_time(53_732_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(53_732_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -105,9 +105,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - Weight::from_ref_time(55_868_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(7 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(55_868_000 as u64) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } } @@ -121,30 +121,30 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - Weight::from_ref_time(44_706_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(44_706_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Lottery CallIndices (r:0 w:1) fn set_calls(n: u32, ) -> Weight { - Weight::from_ref_time(12_556_000 as RefTimeWeight) + Weight::from_ref_time(12_556_000 as u64) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(295_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(295_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - Weight::from_ref_time(38_051_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(38_051_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - Weight::from_ref_time(6_910_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(6_910_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -152,9 +152,9 @@ impl WeightInfo for () { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - Weight::from_ref_time(53_732_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(53_732_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -163,8 +163,8 @@ impl WeightInfo for () { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - Weight::from_ref_time(55_868_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(7 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(55_868_000 as u64) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } } diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 636f8eba64694..4876b3d13e2e3 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_membership. @@ -61,11 +61,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - Weight::from_ref_time(15_318_000 as RefTimeWeight) + Weight::from_ref_time(15_318_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(51_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -73,11 +73,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_005_000 as RefTimeWeight) + Weight::from_ref_time(18_005_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -85,11 +85,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_029_000 as RefTimeWeight) + Weight::from_ref_time(18_029_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -97,11 +97,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_105_000 as RefTimeWeight) + Weight::from_ref_time(18_105_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -109,29 +109,29 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - Weight::from_ref_time(18_852_000 as RefTimeWeight) + Weight::from_ref_time(18_852_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: TechnicalMembership Members (r:1 w:0) // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - Weight::from_ref_time(4_869_000 as RefTimeWeight) + Weight::from_ref_time(4_869_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(28_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(28_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - Weight::from_ref_time(1_593_000 as RefTimeWeight) + Weight::from_ref_time(1_593_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } } @@ -142,11 +142,11 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn add_member(m: u32, ) -> Weight { - Weight::from_ref_time(15_318_000 as RefTimeWeight) + Weight::from_ref_time(15_318_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(51_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(51_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -154,11 +154,11 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn remove_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_005_000 as RefTimeWeight) + Weight::from_ref_time(18_005_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -166,11 +166,11 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn swap_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_029_000 as RefTimeWeight) + Weight::from_ref_time(18_029_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -178,11 +178,11 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn reset_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_105_000 as RefTimeWeight) + Weight::from_ref_time(18_105_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: TechnicalMembership Members (r:1 w:1) // Storage: TechnicalCommittee Proposals (r:1 w:0) @@ -190,28 +190,28 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn change_key(m: u32, ) -> Weight { - Weight::from_ref_time(18_852_000 as RefTimeWeight) + Weight::from_ref_time(18_852_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: TechnicalMembership Members (r:1 w:0) // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn set_prime(m: u32, ) -> Weight { - Weight::from_ref_time(4_869_000 as RefTimeWeight) + Weight::from_ref_time(4_869_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(28_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(28_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) fn clear_prime(m: u32, ) -> Weight { - Weight::from_ref_time(1_593_000 as RefTimeWeight) + Weight::from_ref_time(1_593_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index 455326b71de8c..d8d576775408a 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_multisig. @@ -60,199 +60,199 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn as_multi_threshold_1(_z: u32, ) -> Weight { - Weight::from_ref_time(17_537_000 as RefTimeWeight) + Weight::from_ref_time(17_537_000 as u64) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(36_535_000 as RefTimeWeight) + Weight::from_ref_time(36_535_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(99_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(99_000 as u64).saturating_mul(s as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_918_000 as RefTimeWeight) + Weight::from_ref_time(39_918_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(95_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_000 as u64).saturating_mul(s as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(25_524_000 as RefTimeWeight) + Weight::from_ref_time(25_524_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(94_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(94_000 as u64).saturating_mul(s as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_923_000 as RefTimeWeight) + Weight::from_ref_time(39_923_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(91_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(91_000 as u64).saturating_mul(s as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(45_877_000 as RefTimeWeight) + Weight::from_ref_time(45_877_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(146_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(146_000 as u64).saturating_mul(s as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - Weight::from_ref_time(34_309_000 as RefTimeWeight) + Weight::from_ref_time(34_309_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - Weight::from_ref_time(22_848_000 as RefTimeWeight) + Weight::from_ref_time(22_848_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - Weight::from_ref_time(63_239_000 as RefTimeWeight) + Weight::from_ref_time(63_239_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(161_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - Weight::from_ref_time(51_254_000 as RefTimeWeight) + Weight::from_ref_time(51_254_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(118_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } } // For backwards compatibility and tests impl WeightInfo for () { fn as_multi_threshold_1(_z: u32, ) -> Weight { - Weight::from_ref_time(17_537_000 as RefTimeWeight) + Weight::from_ref_time(17_537_000 as u64) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(36_535_000 as RefTimeWeight) + Weight::from_ref_time(36_535_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(99_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(99_000 as u64).saturating_mul(s as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_918_000 as RefTimeWeight) + Weight::from_ref_time(39_918_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(95_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(95_000 as u64).saturating_mul(s as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) fn as_multi_approve(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(25_524_000 as RefTimeWeight) + Weight::from_ref_time(25_524_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(94_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(94_000 as u64).saturating_mul(s as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_923_000 as RefTimeWeight) + Weight::from_ref_time(39_923_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(91_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(91_000 as u64).saturating_mul(s as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn as_multi_complete(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(45_877_000 as RefTimeWeight) + Weight::from_ref_time(45_877_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(146_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(146_000 as u64).saturating_mul(s as u64)) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(z as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn approve_as_multi_create(s: u32, ) -> Weight { - Weight::from_ref_time(34_309_000 as RefTimeWeight) + Weight::from_ref_time(34_309_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:0) fn approve_as_multi_approve(s: u32, ) -> Weight { - Weight::from_ref_time(22_848_000 as RefTimeWeight) + Weight::from_ref_time(22_848_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(114_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) fn approve_as_multi_complete(s: u32, ) -> Weight { - Weight::from_ref_time(63_239_000 as RefTimeWeight) + Weight::from_ref_time(63_239_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(161_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(161_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: Multisig Calls (r:1 w:1) fn cancel_as_multi(s: u32, ) -> Weight { - Weight::from_ref_time(51_254_000 as RefTimeWeight) + Weight::from_ref_time(51_254_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(118_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } diff --git a/frame/node-authorization/src/weights.rs b/frame/node-authorization/src/weights.rs index f5a816ddaecee..63728c21b65c4 100644 --- a/frame/node-authorization/src/weights.rs +++ b/frame/node-authorization/src/weights.rs @@ -21,7 +21,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; pub trait WeightInfo { diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index f24aeb6a0ee0d..e20394ca668b9 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_nomination_pools. @@ -80,9 +80,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - Weight::from_ref_time(123_947_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(17 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(12 as RefTimeWeight)) + Weight::from_ref_time(123_947_000 as u64) + .saturating_add(T::DbWeight::get().reads(17 as u64)) + .saturating_add(T::DbWeight::get().writes(12 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -94,9 +94,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - Weight::from_ref_time(118_236_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(14 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(12 as RefTimeWeight)) + Weight::from_ref_time(118_236_000 as u64) + .saturating_add(T::DbWeight::get().reads(14 as u64)) + .saturating_add(T::DbWeight::get().writes(12 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -108,18 +108,18 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - Weight::from_ref_time(132_475_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(14 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(13 as RefTimeWeight)) + Weight::from_ref_time(132_475_000 as u64) + .saturating_add(T::DbWeight::get().reads(14 as u64)) + .saturating_add(T::DbWeight::get().writes(13 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - Weight::from_ref_time(50_299_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(50_299_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -136,9 +136,9 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - Weight::from_ref_time(121_254_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(18 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(13 as RefTimeWeight)) + Weight::from_ref_time(121_254_000 as u64) + .saturating_add(T::DbWeight::get().reads(18 as u64)) + .saturating_add(T::DbWeight::get().writes(13 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -146,11 +146,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - Weight::from_ref_time(41_928_000 as RefTimeWeight) + Weight::from_ref_time(41_928_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -162,11 +162,11 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(81_611_000 as RefTimeWeight) + Weight::from_ref_time(81_611_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(7 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().writes(7 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -189,9 +189,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - Weight::from_ref_time(139_849_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(19 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(16 as RefTimeWeight)) + Weight::from_ref_time(139_849_000 as u64) + .saturating_add(T::DbWeight::get().reads(19 as u64)) + .saturating_add(T::DbWeight::get().writes(16 as u64)) } // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: NominationPools MinCreateBond (r:1 w:0) @@ -216,9 +216,9 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(126_246_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(22 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(15 as RefTimeWeight)) + Weight::from_ref_time(126_246_000 as u64) + .saturating_add(T::DbWeight::get().reads(22 as u64)) + .saturating_add(T::DbWeight::get().writes(15 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -234,30 +234,30 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(48_829_000 as RefTimeWeight) + Weight::from_ref_time(48_829_000 as u64) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(2_204_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_204_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(12 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - Weight::from_ref_time(26_761_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(26_761_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - Weight::from_ref_time(14_519_000 as RefTimeWeight) + Weight::from_ref_time(14_519_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: NominationPools MinJoinBond (r:0 w:1) // Storage: NominationPools MaxPoolMembers (r:0 w:1) @@ -265,14 +265,14 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - Weight::from_ref_time(6_173_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(6_173_000 as u64) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - Weight::from_ref_time(22_261_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(22_261_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -283,9 +283,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(47_959_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(47_959_000 as u64) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } } @@ -305,9 +305,9 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn join() -> Weight { - Weight::from_ref_time(123_947_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(17 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(12 as RefTimeWeight)) + Weight::from_ref_time(123_947_000 as u64) + .saturating_add(RocksDbWeight::get().reads(17 as u64)) + .saturating_add(RocksDbWeight::get().writes(12 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -319,9 +319,9 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - Weight::from_ref_time(118_236_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(14 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(12 as RefTimeWeight)) + Weight::from_ref_time(118_236_000 as u64) + .saturating_add(RocksDbWeight::get().reads(14 as u64)) + .saturating_add(RocksDbWeight::get().writes(12 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -333,18 +333,18 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - Weight::from_ref_time(132_475_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(14 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(13 as RefTimeWeight)) + Weight::from_ref_time(132_475_000 as u64) + .saturating_add(RocksDbWeight::get().reads(14 as u64)) + .saturating_add(RocksDbWeight::get().writes(13 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - Weight::from_ref_time(50_299_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(50_299_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) @@ -361,9 +361,9 @@ impl WeightInfo for () { // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - Weight::from_ref_time(121_254_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(18 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(13 as RefTimeWeight)) + Weight::from_ref_time(121_254_000 as u64) + .saturating_add(RocksDbWeight::get().reads(18 as u64)) + .saturating_add(RocksDbWeight::get().writes(13 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -371,11 +371,11 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - Weight::from_ref_time(41_928_000 as RefTimeWeight) + Weight::from_ref_time(41_928_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -387,11 +387,11 @@ impl WeightInfo for () { // Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(81_611_000 as RefTimeWeight) + Weight::from_ref_time(81_611_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(7 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().writes(7 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -414,9 +414,9 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - Weight::from_ref_time(139_849_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(19 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(16 as RefTimeWeight)) + Weight::from_ref_time(139_849_000 as u64) + .saturating_add(RocksDbWeight::get().reads(19 as u64)) + .saturating_add(RocksDbWeight::get().writes(16 as u64)) } // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: NominationPools MinCreateBond (r:1 w:0) @@ -441,9 +441,9 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(126_246_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(22 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(15 as RefTimeWeight)) + Weight::from_ref_time(126_246_000 as u64) + .saturating_add(RocksDbWeight::get().reads(22 as u64)) + .saturating_add(RocksDbWeight::get().writes(15 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -459,30 +459,30 @@ impl WeightInfo for () { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(48_829_000 as RefTimeWeight) + Weight::from_ref_time(48_829_000 as u64) // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(2_204_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_204_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(12 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - Weight::from_ref_time(26_761_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(26_761_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForMetadata (r:1 w:1) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - Weight::from_ref_time(14_519_000 as RefTimeWeight) + Weight::from_ref_time(14_519_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: NominationPools MinJoinBond (r:0 w:1) // Storage: NominationPools MaxPoolMembers (r:0 w:1) @@ -490,14 +490,14 @@ impl WeightInfo for () { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - Weight::from_ref_time(6_173_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(6_173_000 as u64) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - Weight::from_ref_time(22_261_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(22_261_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -508,8 +508,8 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(47_959_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(47_959_000 as u64) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } } diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 0d93611a1f097..ad9e3e569e733 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_preimage. @@ -64,87 +64,87 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn note_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_requested_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_no_deposit_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - Weight::from_ref_time(44_380_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(44_380_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - Weight::from_ref_time(30_280_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(30_280_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - Weight::from_ref_time(42_809_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(42_809_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - Weight::from_ref_time(28_964_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(28_964_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - Weight::from_ref_time(17_555_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(17_555_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - Weight::from_ref_time(7_745_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(7_745_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - Weight::from_ref_time(29_758_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(29_758_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - Weight::from_ref_time(18_360_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(18_360_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - Weight::from_ref_time(7_439_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(7_439_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } @@ -153,86 +153,86 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn note_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_requested_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_no_deposit_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - Weight::from_ref_time(44_380_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(44_380_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - Weight::from_ref_time(30_280_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(30_280_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - Weight::from_ref_time(42_809_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(42_809_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - Weight::from_ref_time(28_964_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(28_964_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - Weight::from_ref_time(17_555_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(17_555_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - Weight::from_ref_time(7_745_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(7_745_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - Weight::from_ref_time(29_758_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(29_758_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - Weight::from_ref_time(18_360_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(18_360_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - Weight::from_ref_time(7_439_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(7_439_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 5b332d98db09b..2d409d977f875 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_proxy. @@ -61,97 +61,97 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - Weight::from_ref_time(17_768_000 as RefTimeWeight) + Weight::from_ref_time(17_768_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(76_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(76_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(35_682_000 as RefTimeWeight) + Weight::from_ref_time(35_682_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(a as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn remove_announcement(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(25_586_000 as RefTimeWeight) + Weight::from_ref_time(25_586_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(175_000 as u64).saturating_mul(a as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(18_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(18_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_announcement(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(25_794_000 as RefTimeWeight) + Weight::from_ref_time(25_794_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(173_000 as u64).saturating_mul(a as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(13_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(13_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_002_000 as RefTimeWeight) + Weight::from_ref_time(33_002_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(163_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(163_000 as u64).saturating_mul(a as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(79_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - Weight::from_ref_time(28_166_000 as RefTimeWeight) + Weight::from_ref_time(28_166_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(105_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(105_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - Weight::from_ref_time(28_128_000 as RefTimeWeight) + Weight::from_ref_time(28_128_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(118_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - Weight::from_ref_time(24_066_000 as RefTimeWeight) + Weight::from_ref_time(24_066_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(81_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(81_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - Weight::from_ref_time(31_077_000 as RefTimeWeight) + Weight::from_ref_time(31_077_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - Weight::from_ref_time(24_657_000 as RefTimeWeight) + Weight::from_ref_time(24_657_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } @@ -159,96 +159,96 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Proxy Proxies (r:1 w:0) fn proxy(p: u32, ) -> Weight { - Weight::from_ref_time(17_768_000 as RefTimeWeight) + Weight::from_ref_time(17_768_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(76_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(76_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn proxy_announced(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(35_682_000 as RefTimeWeight) + Weight::from_ref_time(35_682_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(158_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(a as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn remove_announcement(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(25_586_000 as RefTimeWeight) + Weight::from_ref_time(25_586_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(175_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(175_000 as u64).saturating_mul(a as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(18_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(18_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_announcement(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(25_794_000 as RefTimeWeight) + Weight::from_ref_time(25_794_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(173_000 as u64).saturating_mul(a as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(13_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(13_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) fn announce(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_002_000 as RefTimeWeight) + Weight::from_ref_time(33_002_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(163_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(163_000 as u64).saturating_mul(a as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(79_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Proxy Proxies (r:1 w:1) fn add_proxy(p: u32, ) -> Weight { - Weight::from_ref_time(28_166_000 as RefTimeWeight) + Weight::from_ref_time(28_166_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(105_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(105_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxy(p: u32, ) -> Weight { - Weight::from_ref_time(28_128_000 as RefTimeWeight) + Weight::from_ref_time(28_128_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(118_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(118_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) fn remove_proxies(p: u32, ) -> Weight { - Weight::from_ref_time(24_066_000 as RefTimeWeight) + Weight::from_ref_time(24_066_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(81_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(81_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) fn anonymous(p: u32, ) -> Weight { - Weight::from_ref_time(31_077_000 as RefTimeWeight) + Weight::from_ref_time(31_077_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) fn kill_anonymous(p: u32, ) -> Weight { - Weight::from_ref_time(24_657_000 as RefTimeWeight) + Weight::from_ref_time(24_657_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/ranked-collective/src/weights.rs b/frame/ranked-collective/src/weights.rs index 052a9bfdcc9e1..6b6cca52316c9 100644 --- a/frame/ranked-collective/src/weights.rs +++ b/frame/ranked-collective/src/weights.rs @@ -40,7 +40,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_ranked_collective. @@ -61,62 +61,62 @@ impl WeightInfo for SubstrateWeight { // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) fn add_member() -> Weight { - Weight::from_ref_time(11_000_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(11_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) fn remove_member(r: u32, ) -> Weight { - Weight::from_ref_time(16_855_000 as RefTimeWeight) + Weight::from_ref_time(16_855_000 as u64) // Standard Error: 27_000 - .saturating_add(Weight::from_ref_time(8_107_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(8_107_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(r as u64))) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) fn promote_member(r: u32, ) -> Weight { - Weight::from_ref_time(11_936_000 as RefTimeWeight) + Weight::from_ref_time(11_936_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(9_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) fn demote_member(r: u32, ) -> Weight { - Weight::from_ref_time(17_582_000 as RefTimeWeight) + Weight::from_ref_time(17_582_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: RankedCollective Members (r:1 w:0) // Storage: RankedPolls ReferendumInfoFor (r:1 w:1) // Storage: RankedCollective Voting (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote() -> Weight { - Weight::from_ref_time(22_000_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(22_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: RankedPolls ReferendumInfoFor (r:1 w:0) // Storage: RankedCollective Voting (r:0 w:1) fn cleanup_poll(n: u32, ) -> Weight { - Weight::from_ref_time(6_188_000 as RefTimeWeight) + Weight::from_ref_time(6_188_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(867_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } } @@ -127,61 +127,61 @@ impl WeightInfo for () { // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) fn add_member() -> Weight { - Weight::from_ref_time(11_000_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(11_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) fn remove_member(r: u32, ) -> Weight { - Weight::from_ref_time(16_855_000 as RefTimeWeight) + Weight::from_ref_time(16_855_000 as u64) // Standard Error: 27_000 - .saturating_add(Weight::from_ref_time(8_107_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(r as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(8_107_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(r as u64))) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) fn promote_member(r: u32, ) -> Weight { - Weight::from_ref_time(11_936_000 as RefTimeWeight) + Weight::from_ref_time(11_936_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(9_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(9_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: RankedCollective Members (r:1 w:1) // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) fn demote_member(r: u32, ) -> Weight { - Weight::from_ref_time(17_582_000 as RefTimeWeight) + Weight::from_ref_time(17_582_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(142_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: RankedCollective Members (r:1 w:0) // Storage: RankedPolls ReferendumInfoFor (r:1 w:1) // Storage: RankedCollective Voting (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote() -> Weight { - Weight::from_ref_time(22_000_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(22_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: RankedPolls ReferendumInfoFor (r:1 w:0) // Storage: RankedCollective Voting (r:0 w:1) fn cleanup_poll(n: u32, ) -> Weight { - Weight::from_ref_time(6_188_000 as RefTimeWeight) + Weight::from_ref_time(6_188_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(867_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(867_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } } diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index 06a4759938964..b496f16a46b28 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_recovery. @@ -60,71 +60,71 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Recovery Proxy (r:1 w:0) fn as_recovered() -> Weight { - Weight::from_ref_time(6_579_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + Weight::from_ref_time(6_579_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Recovery Proxy (r:0 w:1) fn set_recovered() -> Weight { - Weight::from_ref_time(13_402_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(13_402_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:1) fn create_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(28_217_000 as RefTimeWeight) + Weight::from_ref_time(28_217_000 as u64) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(172_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn initiate_recovery() -> Weight { - Weight::from_ref_time(34_082_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(34_082_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn vouch_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(22_038_000 as RefTimeWeight) + Weight::from_ref_time(22_038_000 as u64) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(307_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(307_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Proxy (r:1 w:1) fn claim_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(28_621_000 as RefTimeWeight) + Weight::from_ref_time(28_621_000 as u64) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(353_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(353_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery ActiveRecoveries (r:1 w:1) // Storage: System Account (r:1 w:1) fn close_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(33_287_000 as RefTimeWeight) + Weight::from_ref_time(33_287_000 as u64) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(264_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(264_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Recoverable (r:1 w:1) fn remove_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(31_964_000 as RefTimeWeight) + Weight::from_ref_time(31_964_000 as u64) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(222_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(222_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery Proxy (r:1 w:1) fn cancel_recovered() -> Weight { - Weight::from_ref_time(12_702_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(12_702_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } @@ -132,70 +132,70 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Recovery Proxy (r:1 w:0) fn as_recovered() -> Weight { - Weight::from_ref_time(6_579_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + Weight::from_ref_time(6_579_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Recovery Proxy (r:0 w:1) fn set_recovered() -> Weight { - Weight::from_ref_time(13_402_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(13_402_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:1) fn create_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(28_217_000 as RefTimeWeight) + Weight::from_ref_time(28_217_000 as u64) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(172_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(172_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn initiate_recovery() -> Weight { - Weight::from_ref_time(34_082_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(34_082_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn vouch_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(22_038_000 as RefTimeWeight) + Weight::from_ref_time(22_038_000 as u64) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(307_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(307_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Proxy (r:1 w:1) fn claim_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(28_621_000 as RefTimeWeight) + Weight::from_ref_time(28_621_000 as u64) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(353_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(353_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery ActiveRecoveries (r:1 w:1) // Storage: System Account (r:1 w:1) fn close_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(33_287_000 as RefTimeWeight) + Weight::from_ref_time(33_287_000 as u64) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(264_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(264_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Recoverable (r:1 w:1) fn remove_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(31_964_000 as RefTimeWeight) + Weight::from_ref_time(31_964_000 as u64) // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(222_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(222_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery Proxy (r:1 w:1) fn cancel_recovered() -> Weight { - Weight::from_ref_time(12_702_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(12_702_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index 84a726d9e4fbe..50f8aa41b30aa 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_referenda. @@ -80,205 +80,205 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - Weight::from_ref_time(34_640_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(34_640_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - Weight::from_ref_time(44_290_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(44_290_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - Weight::from_ref_time(49_428_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(49_428_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - Weight::from_ref_time(50_076_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(50_076_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - Weight::from_ref_time(55_935_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(55_935_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - Weight::from_ref_time(52_921_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(52_921_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - Weight::from_ref_time(29_160_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(29_160_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - Weight::from_ref_time(34_972_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(34_972_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - Weight::from_ref_time(60_620_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(60_620_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - Weight::from_ref_time(9_615_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(9_615_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - Weight::from_ref_time(113_077_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(113_077_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - Weight::from_ref_time(114_376_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(114_376_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - Weight::from_ref_time(43_901_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(43_901_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - Weight::from_ref_time(43_279_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(43_279_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - Weight::from_ref_time(45_564_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(45_564_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - Weight::from_ref_time(45_061_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(45_061_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - Weight::from_ref_time(23_757_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(23_757_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - Weight::from_ref_time(24_781_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(24_781_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - Weight::from_ref_time(18_344_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_344_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - Weight::from_ref_time(34_752_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(34_752_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - Weight::from_ref_time(37_055_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(37_055_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - Weight::from_ref_time(31_442_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(31_442_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - Weight::from_ref_time(33_201_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(33_201_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - Weight::from_ref_time(30_047_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(30_047_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - Weight::from_ref_time(29_195_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(29_195_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn nudge_referendum_approved() -> Weight { - Weight::from_ref_time(50_119_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(50_119_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - Weight::from_ref_time(32_203_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(32_203_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } } @@ -288,204 +288,204 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - Weight::from_ref_time(34_640_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(34_640_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - Weight::from_ref_time(44_290_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(44_290_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - Weight::from_ref_time(49_428_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(49_428_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - Weight::from_ref_time(50_076_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(50_076_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - Weight::from_ref_time(55_935_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(55_935_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - Weight::from_ref_time(52_921_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(52_921_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - Weight::from_ref_time(29_160_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(29_160_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - Weight::from_ref_time(34_972_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(34_972_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - Weight::from_ref_time(60_620_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(60_620_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - Weight::from_ref_time(9_615_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(9_615_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - Weight::from_ref_time(113_077_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(113_077_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - Weight::from_ref_time(114_376_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(114_376_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - Weight::from_ref_time(43_901_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(43_901_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - Weight::from_ref_time(43_279_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(43_279_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - Weight::from_ref_time(45_564_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(45_564_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - Weight::from_ref_time(45_061_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(45_061_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - Weight::from_ref_time(23_757_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(23_757_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - Weight::from_ref_time(24_781_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(24_781_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - Weight::from_ref_time(18_344_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(18_344_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - Weight::from_ref_time(34_752_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(34_752_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - Weight::from_ref_time(37_055_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(37_055_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - Weight::from_ref_time(31_442_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(31_442_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - Weight::from_ref_time(33_201_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(33_201_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - Weight::from_ref_time(30_047_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(30_047_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - Weight::from_ref_time(29_195_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(29_195_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn nudge_referendum_approved() -> Weight { - Weight::from_ref_time(50_119_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(50_119_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - Weight::from_ref_time(32_203_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(32_203_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index f33ef47cd67e8..40e9e933aab2b 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_remark. @@ -52,10 +52,10 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn store(l: u32, ) -> Weight { - Weight::from_ref_time(13_140_000 as RefTimeWeight) + Weight::from_ref_time(13_140_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(l as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) } } @@ -63,9 +63,9 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) fn store(l: u32, ) -> Weight { - Weight::from_ref_time(13_140_000 as RefTimeWeight) + Weight::from_ref_time(13_140_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(l as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) } } diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index 9688c9f1a2f9f..afbcf9373b2de 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_scheduler. @@ -68,146 +68,146 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(9_994_000 as RefTimeWeight) + Weight::from_ref_time(9_994_000 as u64) // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(19_843_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((4 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(19_843_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(10_318_000 as RefTimeWeight) + Weight::from_ref_time(10_318_000 as u64) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(15_451_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(15_451_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_675_000 as RefTimeWeight) + Weight::from_ref_time(11_675_000 as u64) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(17_019_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(17_019_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_934_000 as RefTimeWeight) + Weight::from_ref_time(11_934_000 as u64) // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(14_134_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(14_134_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(7_279_000 as RefTimeWeight) + Weight::from_ref_time(7_279_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(5_388_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(5_388_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(8_619_000 as RefTimeWeight) + Weight::from_ref_time(8_619_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_969_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_969_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - Weight::from_ref_time(16_129_000 as RefTimeWeight) + Weight::from_ref_time(16_129_000 as u64) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(9_772_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(9_772_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - Weight::from_ref_time(15_785_000 as RefTimeWeight) + Weight::from_ref_time(15_785_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(7_208_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(7_208_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - Weight::from_ref_time(15_778_000 as RefTimeWeight) + Weight::from_ref_time(15_778_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(5_597_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(5_597_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - Weight::from_ref_time(15_912_000 as RefTimeWeight) + Weight::from_ref_time(15_912_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(4_530_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_530_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - Weight::from_ref_time(18_013_000 as RefTimeWeight) + Weight::from_ref_time(18_013_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - Weight::from_ref_time(18_131_000 as RefTimeWeight) + Weight::from_ref_time(18_131_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - Weight::from_ref_time(21_230_000 as RefTimeWeight) + Weight::from_ref_time(21_230_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(98_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(98_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - Weight::from_ref_time(20_139_000 as RefTimeWeight) + Weight::from_ref_time(20_139_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } } @@ -218,145 +218,145 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(9_994_000 as RefTimeWeight) + Weight::from_ref_time(9_994_000 as u64) // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(19_843_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((4 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(19_843_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(10_318_000 as RefTimeWeight) + Weight::from_ref_time(10_318_000 as u64) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(15_451_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(15_451_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_675_000 as RefTimeWeight) + Weight::from_ref_time(11_675_000 as u64) // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(17_019_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(17_019_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_934_000 as RefTimeWeight) + Weight::from_ref_time(11_934_000 as u64) // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(14_134_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(14_134_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(7_279_000 as RefTimeWeight) + Weight::from_ref_time(7_279_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(5_388_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(5_388_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(8_619_000 as RefTimeWeight) + Weight::from_ref_time(8_619_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_969_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_969_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - Weight::from_ref_time(16_129_000 as RefTimeWeight) + Weight::from_ref_time(16_129_000 as u64) // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(9_772_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(9_772_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - Weight::from_ref_time(15_785_000 as RefTimeWeight) + Weight::from_ref_time(15_785_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(7_208_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(7_208_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - Weight::from_ref_time(15_778_000 as RefTimeWeight) + Weight::from_ref_time(15_778_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(5_597_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(5_597_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - Weight::from_ref_time(15_912_000 as RefTimeWeight) + Weight::from_ref_time(15_912_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(4_530_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_530_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(s: u32, ) -> Weight { - Weight::from_ref_time(18_013_000 as RefTimeWeight) + Weight::from_ref_time(18_013_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - Weight::from_ref_time(18_131_000 as RefTimeWeight) + Weight::from_ref_time(18_131_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - Weight::from_ref_time(21_230_000 as RefTimeWeight) + Weight::from_ref_time(21_230_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(98_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(98_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - Weight::from_ref_time(20_139_000 as RefTimeWeight) + Weight::from_ref_time(20_139_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index 5208a679c6bb7..6e775d3d6f47a 100644 --- a/frame/session/src/weights.rs +++ b/frame/session/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_session. @@ -55,17 +55,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - Weight::from_ref_time(48_484_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(48_484_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - Weight::from_ref_time(38_003_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(38_003_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } } @@ -75,16 +75,16 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - Weight::from_ref_time(48_484_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(48_484_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - Weight::from_ref_time(38_003_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(38_003_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 82ab44f428372..09c2d8b5de113 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_staking. @@ -86,9 +86,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - Weight::from_ref_time(43_992_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(43_992_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -96,9 +96,9 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - Weight::from_ref_time(75_827_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(7 as RefTimeWeight)) + Weight::from_ref_time(75_827_000 as u64) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().writes(7 as u64)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Nominators (r:1 w:0) @@ -110,20 +110,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - Weight::from_ref_time(81_075_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(8 as RefTimeWeight)) + Weight::from_ref_time(81_075_000 as u64) + .saturating_add(T::DbWeight::get().reads(12 as u64)) + .saturating_add(T::DbWeight::get().writes(8 as u64)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(35_763_000 as RefTimeWeight) + Weight::from_ref_time(35_763_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(57_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(57_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -139,9 +139,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - Weight::from_ref_time(66_938_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(13 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(11 as RefTimeWeight)) + Weight::from_ref_time(66_938_000 as u64) + .saturating_add(T::DbWeight::get().reads(13 as u64)) + .saturating_add(T::DbWeight::get().writes(11 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) @@ -155,19 +155,19 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - Weight::from_ref_time(52_943_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(11 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(52_943_000 as u64) + .saturating_add(T::DbWeight::get().reads(11 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - Weight::from_ref_time(23_264_000 as RefTimeWeight) + Weight::from_ref_time(23_264_000 as u64) // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(8_006_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(8_006_000 as u64).saturating_mul(k as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(k as u64))) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinNominatorBond (r:1 w:0) @@ -181,12 +181,12 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(56_596_000 as RefTimeWeight) + Weight::from_ref_time(56_596_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(3_644_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_644_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(12 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Validators (r:1 w:0) @@ -196,50 +196,50 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(51_117_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(8 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(51_117_000 as u64) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - Weight::from_ref_time(11_223_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(11_223_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - Weight::from_ref_time(19_826_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(19_826_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - Weight::from_ref_time(3_789_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_789_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - Weight::from_ref_time(3_793_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_793_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - Weight::from_ref_time(3_802_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_802_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - Weight::from_ref_time(3_762_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_762_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - Weight::from_ref_time(4_318_000 as RefTimeWeight) + Weight::from_ref_time(4_318_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(10_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(10_000 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) @@ -255,20 +255,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - Weight::from_ref_time(65_265_000 as RefTimeWeight) + Weight::from_ref_time(65_265_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_029_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(11 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(12 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(1_029_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(11 as u64)) + .saturating_add(T::DbWeight::get().writes(12 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - Weight::from_ref_time(903_312_000 as RefTimeWeight) + Weight::from_ref_time(903_312_000 as u64) // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(4_968_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_968_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:0) @@ -281,13 +281,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - Weight::from_ref_time(87_569_000 as RefTimeWeight) + Weight::from_ref_time(87_569_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(24_232_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(10 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(24_232_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(10 as u64)) + .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:0) @@ -301,13 +301,13 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - Weight::from_ref_time(98_839_000 as RefTimeWeight) + Weight::from_ref_time(98_839_000 as u64) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(34_480_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(11 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(34_480_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(11 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(n as u64))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) @@ -316,11 +316,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - Weight::from_ref_time(74_865_000 as RefTimeWeight) + Weight::from_ref_time(74_865_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(64_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(9 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(8 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(64_000 as u64).saturating_mul(l as u64)) + .saturating_add(T::DbWeight::get().reads(9 as u64)) + .saturating_add(T::DbWeight::get().writes(8 as u64)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:1) @@ -332,12 +332,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 62_000 - .saturating_add(Weight::from_ref_time(22_829_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((7 as RefTimeWeight).saturating_mul(e as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(22_829_000 as u64).saturating_mul(e as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(e as u64))) } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) @@ -353,12 +353,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - Weight::from_ref_time(70_933_000 as RefTimeWeight) + Weight::from_ref_time(70_933_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_021_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(12 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(12 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(1_021_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(12 as u64)) + .saturating_add(T::DbWeight::get().writes(12 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: BagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) @@ -379,16 +379,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 897_000 - .saturating_add(Weight::from_ref_time(213_100_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(213_100_000 as u64).saturating_mul(v as u64)) // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(31_123_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(208 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) - .saturating_add(T::DbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(31_123_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(208 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(v as u64))) + .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(v as u64))) } // Storage: BagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) @@ -399,25 +399,25 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(23_745_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(23_745_000 as u64).saturating_mul(v as u64)) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(22_497_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(22_497_000 as u64).saturating_mul(n as u64)) // Standard Error: 3_968_000 - .saturating_add(Weight::from_ref_time(20_676_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(202 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) - .saturating_add(T::DbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(20_676_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(202 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(v as u64))) + .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) } // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 36_000 - .saturating_add(Weight::from_ref_time(8_097_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(8_097_000 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(v as u64))) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -426,8 +426,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - Weight::from_ref_time(7_041_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(7_041_000 as u64) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -436,8 +436,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - Weight::from_ref_time(6_495_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(6_495_000 as u64) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) @@ -450,16 +450,16 @@ impl WeightInfo for SubstrateWeight { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - Weight::from_ref_time(62_014_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(11 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(62_014_000 as u64) + .saturating_add(T::DbWeight::get().reads(11 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - Weight::from_ref_time(12_814_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(12_814_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } @@ -472,9 +472,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - Weight::from_ref_time(43_992_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(43_992_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -482,9 +482,9 @@ impl WeightInfo for () { // Storage: BagsList ListNodes (r:3 w:3) // Storage: BagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - Weight::from_ref_time(75_827_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(7 as RefTimeWeight)) + Weight::from_ref_time(75_827_000 as u64) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().writes(7 as u64)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Nominators (r:1 w:0) @@ -496,20 +496,20 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn unbond() -> Weight { - Weight::from_ref_time(81_075_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(8 as RefTimeWeight)) + Weight::from_ref_time(81_075_000 as u64) + .saturating_add(RocksDbWeight::get().reads(12 as u64)) + .saturating_add(RocksDbWeight::get().writes(8 as u64)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(35_763_000 as RefTimeWeight) + Weight::from_ref_time(35_763_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(57_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(57_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -525,9 +525,9 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - Weight::from_ref_time(66_938_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(13 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(11 as RefTimeWeight)) + Weight::from_ref_time(66_938_000 as u64) + .saturating_add(RocksDbWeight::get().reads(13 as u64)) + .saturating_add(RocksDbWeight::get().writes(11 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) @@ -541,19 +541,19 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - Weight::from_ref_time(52_943_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(11 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(5 as RefTimeWeight)) + Weight::from_ref_time(52_943_000 as u64) + .saturating_add(RocksDbWeight::get().reads(11 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) fn kick(k: u32, ) -> Weight { - Weight::from_ref_time(23_264_000 as RefTimeWeight) + Weight::from_ref_time(23_264_000 as u64) // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(8_006_000 as RefTimeWeight).saturating_mul(k as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(k as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(8_006_000 as u64).saturating_mul(k as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(k as u64))) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinNominatorBond (r:1 w:0) @@ -567,12 +567,12 @@ impl WeightInfo for () { // Storage: BagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(56_596_000 as RefTimeWeight) + Weight::from_ref_time(56_596_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(3_644_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(3_644_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(12 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Validators (r:1 w:0) @@ -582,50 +582,50 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(51_117_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(8 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(51_117_000 as u64) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - Weight::from_ref_time(11_223_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(11_223_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - Weight::from_ref_time(19_826_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(19_826_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - Weight::from_ref_time(3_789_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_789_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - Weight::from_ref_time(3_793_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_793_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - Weight::from_ref_time(3_802_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_802_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - Weight::from_ref_time(3_762_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(3_762_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Invulnerables (r:0 w:1) fn set_invulnerables(v: u32, ) -> Weight { - Weight::from_ref_time(4_318_000 as RefTimeWeight) + Weight::from_ref_time(4_318_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(10_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(10_000 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) @@ -641,20 +641,20 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) fn force_unstake(s: u32, ) -> Weight { - Weight::from_ref_time(65_265_000 as RefTimeWeight) + Weight::from_ref_time(65_265_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_029_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(11 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(12 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(1_029_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(11 as u64)) + .saturating_add(RocksDbWeight::get().writes(12 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Staking UnappliedSlashes (r:1 w:1) fn cancel_deferred_slash(s: u32, ) -> Weight { - Weight::from_ref_time(903_312_000 as RefTimeWeight) + Weight::from_ref_time(903_312_000 as u64) // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(4_968_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_968_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:0) @@ -667,13 +667,13 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) fn payout_stakers_dead_controller(n: u32, ) -> Weight { - Weight::from_ref_time(87_569_000 as RefTimeWeight) + Weight::from_ref_time(87_569_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(24_232_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(10 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(24_232_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(10 as u64)) + .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:0) @@ -687,13 +687,13 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) fn payout_stakers_alive_staked(n: u32, ) -> Weight { - Weight::from_ref_time(98_839_000 as RefTimeWeight) + Weight::from_ref_time(98_839_000 as u64) // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(34_480_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(11 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(34_480_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(11 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(n as u64))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) @@ -702,11 +702,11 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: BagsList ListBags (r:2 w:2) fn rebond(l: u32, ) -> Weight { - Weight::from_ref_time(74_865_000 as RefTimeWeight) + Weight::from_ref_time(74_865_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(64_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(9 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(8 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(64_000 as u64).saturating_mul(l as u64)) + .saturating_add(RocksDbWeight::get().reads(9 as u64)) + .saturating_add(RocksDbWeight::get().writes(8 as u64)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking HistoryDepth (r:1 w:1) @@ -718,12 +718,12 @@ impl WeightInfo for () { // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn set_history_depth(e: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 62_000 - .saturating_add(Weight::from_ref_time(22_829_000 as RefTimeWeight).saturating_mul(e as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((7 as RefTimeWeight).saturating_mul(e as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(22_829_000 as u64).saturating_mul(e as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(e as u64))) } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) @@ -739,12 +739,12 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) fn reap_stash(s: u32, ) -> Weight { - Weight::from_ref_time(70_933_000 as RefTimeWeight) + Weight::from_ref_time(70_933_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_021_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(12 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(12 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(1_021_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(12 as u64)) + .saturating_add(RocksDbWeight::get().writes(12 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: BagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) @@ -765,16 +765,16 @@ impl WeightInfo for () { // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) fn new_era(v: u32, n: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 897_000 - .saturating_add(Weight::from_ref_time(213_100_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(213_100_000 as u64).saturating_mul(v as u64)) // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(31_123_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(208 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(31_123_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(208 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(v as u64))) + .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(v as u64))) } // Storage: BagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) @@ -785,25 +785,25 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(23_745_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(23_745_000 as u64).saturating_mul(v as u64)) // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(22_497_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(22_497_000 as u64).saturating_mul(n as u64)) // Standard Error: 3_968_000 - .saturating_add(Weight::from_ref_time(20_676_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(202 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((5 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().reads((4 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(s as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(20_676_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(202 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(v as u64))) + .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) } // Storage: Staking Validators (r:501 w:0) fn get_npos_targets(v: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 36_000 - .saturating_add(Weight::from_ref_time(8_097_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(v as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(8_097_000 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(v as u64))) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -812,8 +812,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - Weight::from_ref_time(7_041_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(7_041_000 as u64) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -822,8 +822,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - Weight::from_ref_time(6_495_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(6_495_000 as u64) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) @@ -836,15 +836,15 @@ impl WeightInfo for () { // Storage: BagsList ListBags (r:1 w:1) // Storage: BagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - Weight::from_ref_time(62_014_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(11 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(6 as RefTimeWeight)) + Weight::from_ref_time(62_014_000 as u64) + .saturating_add(RocksDbWeight::get().reads(11 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - Weight::from_ref_time(12_814_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(12_814_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs index 1967874157f75..851f4cba077c0 100644 --- a/frame/state-trie-migration/src/weights.rs +++ b/frame/state-trie-migration/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_state_trie_migration. @@ -59,40 +59,40 @@ impl WeightInfo for SubstrateWeight { // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) // Storage: StateTrieMigration MigrationProcess (r:1 w:1) fn continue_migrate() -> Weight { - Weight::from_ref_time(19_019_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(19_019_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) fn continue_migrate_wrong_witness() -> Weight { - Weight::from_ref_time(1_874_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) + Weight::from_ref_time(1_874_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) } fn migrate_custom_top_success() -> Weight { - Weight::from_ref_time(16_381_000 as RefTimeWeight) + Weight::from_ref_time(16_381_000 as u64) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_top_fail() -> Weight { - Weight::from_ref_time(25_966_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_966_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } fn migrate_custom_child_success() -> Weight { - Weight::from_ref_time(16_712_000 as RefTimeWeight) + Weight::from_ref_time(16_712_000 as u64) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_child_fail() -> Weight { - Weight::from_ref_time(29_885_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(29_885_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: unknown [0x6b6579] (r:1 w:1) fn process_top_key(v: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } @@ -101,39 +101,39 @@ impl WeightInfo for () { // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) // Storage: StateTrieMigration MigrationProcess (r:1 w:1) fn continue_migrate() -> Weight { - Weight::from_ref_time(19_019_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(19_019_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) fn continue_migrate_wrong_witness() -> Weight { - Weight::from_ref_time(1_874_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) + Weight::from_ref_time(1_874_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) } fn migrate_custom_top_success() -> Weight { - Weight::from_ref_time(16_381_000 as RefTimeWeight) + Weight::from_ref_time(16_381_000 as u64) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_top_fail() -> Weight { - Weight::from_ref_time(25_966_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_966_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } fn migrate_custom_child_success() -> Weight { - Weight::from_ref_time(16_712_000 as RefTimeWeight) + Weight::from_ref_time(16_712_000 as u64) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_child_fail() -> Weight { - Weight::from_ref_time(29_885_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(29_885_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: unknown [0x6b6579] (r:1 w:1) fn process_top_key(v: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(v as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index c556322b6cf93..3b2a8b3b62fc2 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1376,7 +1376,7 @@ pub mod pallet_prelude { ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, IsType, PalletInfoAccess, StorageInfoTrait, StorageVersion, TypedGet, }, - weights::{DispatchClass, Pays, RefTimeWeight, Weight}, + weights::{DispatchClass, Pays, Weight}, Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity, PartialEqNoBound, RuntimeDebug, RuntimeDebugNoBound, Twox128, Twox256, Twox64Concat, }; diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index dab7f4a2746cf..b4fd896e865dc 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -456,8 +456,8 @@ impl GetDispatchInfo for sp_runtime::testing::TestX /// be updated all together once proof size is accounted for. #[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] pub struct RuntimeDbWeight { - pub read: RefTimeWeight, - pub write: RefTimeWeight, + pub read: u64, + pub write: u64, } impl RuntimeDbWeight { @@ -727,7 +727,7 @@ mod tests { fn f03(_origin) { unimplemented!(); } // weight = a x 10 + b - #[weight = ((_a * 10 + _eb * 1) as RefTimeWeight, DispatchClass::Normal, Pays::Yes)] + #[weight = ((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes)] fn f11(_origin, _a: u32, _eb: u32) { unimplemented!(); } #[weight = (0, DispatchClass::Operational, Pays::Yes)] diff --git a/frame/support/src/weights/weight_v2.rs b/frame/support/src/weights/weight_v2.rs index bcda6358c965f..4bfab36663394 100644 --- a/frame/support/src/weights/weight_v2.rs +++ b/frame/support/src/weights/weight_v2.rs @@ -24,10 +24,6 @@ use sp_runtime::{ use super::*; -/// The unit of measurement for computational time spent when executing runtime logic on reference -/// hardware. -pub type RefTimeWeight = u64; - #[derive( Encode, Decode, @@ -46,27 +42,27 @@ pub type RefTimeWeight = u64; #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct Weight { /// The weight of computational time used based on some reference hardware. - ref_time: RefTimeWeight, + ref_time: u64, } impl Weight { /// Set the reference time part of the weight. - pub const fn set_ref_time(mut self, c: RefTimeWeight) -> Self { + pub const fn set_ref_time(mut self, c: u64) -> Self { self.ref_time = c; self } /// Return the reference time part of the weight. - pub const fn ref_time(&self) -> RefTimeWeight { + pub const fn ref_time(&self) -> u64 { self.ref_time } /// Return a mutable reference time part of the weight. - pub fn ref_time_mut(&mut self) -> &mut RefTimeWeight { + pub fn ref_time_mut(&mut self) -> &mut u64 { &mut self.ref_time } - pub const MAX: Self = Self { ref_time: RefTimeWeight::MAX }; + pub const MAX: Self = Self { ref_time: u64::MAX }; /// Get the conservative min of `self` and `other` weight. pub fn min(&self, other: Self) -> Self { @@ -89,7 +85,7 @@ impl Weight { } /// Construct [`Weight`] with reference time weight. - pub const fn from_ref_time(ref_time: RefTimeWeight) -> Self { + pub const fn from_ref_time(ref_time: u64) -> Self { Self { ref_time } } @@ -380,8 +376,8 @@ impl sp_runtime::traits::Printable for Weight { // TODO: Eventually remove these -impl From> for PostDispatchInfo { - fn from(maybe_actual_computation: Option) -> Self { +impl From> for PostDispatchInfo { + fn from(maybe_actual_computation: Option) -> Self { let actual_weight = match maybe_actual_computation { Some(actual_computation) => Some(Weight::zero().set_ref_time(actual_computation)), None => None, @@ -390,8 +386,8 @@ impl From> for PostDispatchInfo { } } -impl From<(Option, Pays)> for PostDispatchInfo { - fn from(post_weight_info: (Option, Pays)) -> Self { +impl From<(Option, Pays)> for PostDispatchInfo { + fn from(post_weight_info: (Option, Pays)) -> Self { let (maybe_actual_time, pays_fee) = post_weight_info; let actual_weight = match maybe_actual_time { Some(actual_time) => Some(Weight::zero().set_ref_time(actual_time)), @@ -401,73 +397,73 @@ impl From<(Option, Pays)> for PostDispatchInfo { } } -impl WeighData for RefTimeWeight { +impl WeighData for u64 { fn weigh_data(&self, _: T) -> Weight { return Weight::zero().set_ref_time(*self) } } -impl ClassifyDispatch for RefTimeWeight { +impl ClassifyDispatch for u64 { fn classify_dispatch(&self, _: T) -> DispatchClass { DispatchClass::Normal } } -impl PaysFee for RefTimeWeight { +impl PaysFee for u64 { fn pays_fee(&self, _: T) -> Pays { Pays::Yes } } -impl WeighData for (RefTimeWeight, DispatchClass, Pays) { +impl WeighData for (u64, DispatchClass, Pays) { fn weigh_data(&self, args: T) -> Weight { return self.0.weigh_data(args) } } -impl ClassifyDispatch for (RefTimeWeight, DispatchClass, Pays) { +impl ClassifyDispatch for (u64, DispatchClass, Pays) { fn classify_dispatch(&self, _: T) -> DispatchClass { self.1 } } -impl PaysFee for (RefTimeWeight, DispatchClass, Pays) { +impl PaysFee for (u64, DispatchClass, Pays) { fn pays_fee(&self, _: T) -> Pays { self.2 } } -impl WeighData for (RefTimeWeight, DispatchClass) { +impl WeighData for (u64, DispatchClass) { fn weigh_data(&self, args: T) -> Weight { return self.0.weigh_data(args) } } -impl ClassifyDispatch for (RefTimeWeight, DispatchClass) { +impl ClassifyDispatch for (u64, DispatchClass) { fn classify_dispatch(&self, _: T) -> DispatchClass { self.1 } } -impl PaysFee for (RefTimeWeight, DispatchClass) { +impl PaysFee for (u64, DispatchClass) { fn pays_fee(&self, _: T) -> Pays { Pays::Yes } } -impl WeighData for (RefTimeWeight, Pays) { +impl WeighData for (u64, Pays) { fn weigh_data(&self, args: T) -> Weight { return self.0.weigh_data(args) } } -impl ClassifyDispatch for (RefTimeWeight, Pays) { +impl ClassifyDispatch for (u64, Pays) { fn classify_dispatch(&self, _: T) -> DispatchClass { DispatchClass::Normal } } -impl PaysFee for (RefTimeWeight, Pays) { +impl PaysFee for (u64, Pays) { fn pays_fee(&self, _: T) -> Pays { self.1 } diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index 4d597e24356c7..dc107b345c2b8 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -31,10 +31,7 @@ impl SomeAssociation for u64 { mod pallet_old { use super::SomeAssociation; use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, - traits::Get, - weights::{RefTimeWeight, Weight}, - Parameter, + decl_error, decl_event, decl_module, decl_storage, traits::Get, weights::Weight, Parameter, }; use frame_system::ensure_root; @@ -43,7 +40,7 @@ mod pallet_old { type Balance: Parameter + codec::HasCompact + From - + Into + + Into + Default + SomeAssociation; type Event: From> + Into<::Event>; @@ -78,7 +75,7 @@ mod pallet_old { fn deposit_event() = default; const SomeConst: T::Balance = T::SomeConst::get(); - #[weight = >::into(new_value.clone())] + #[weight = >::into(new_value.clone())] fn set_dummy(origin, #[compact] new_value: T::Balance) { ensure_root(origin)?; @@ -116,7 +113,7 @@ pub mod pallet { type Balance: Parameter + codec::HasCompact + From - + Into + + Into + Default + MaybeSerializeDeserialize + SomeAssociation @@ -144,7 +141,7 @@ pub mod pallet { #[pallet::call] impl Pallet { - #[pallet::weight(>::into(new_value.clone()))] + #[pallet::weight(>::into(new_value.clone()))] pub fn set_dummy( origin: OriginFor, #[pallet::compact] new_value: T::Balance, diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 2fd6833eaa428..428de08864f29 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -23,16 +23,13 @@ use frame_support::traits::{ConstU32, ConstU64}; mod pallet_old { use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, - traits::Get, - weights::{RefTimeWeight, Weight}, - Parameter, + decl_error, decl_event, decl_module, decl_storage, traits::Get, weights::Weight, Parameter, }; use frame_system::ensure_root; pub trait Config: frame_system::Config { type SomeConst: Get; - type Balance: Parameter + codec::HasCompact + From + Into + Default; + type Balance: Parameter + codec::HasCompact + From + Into + Default; type Event: From> + Into<::Event>; } @@ -65,7 +62,7 @@ mod pallet_old { fn deposit_event() = default; const SomeConst: T::Balance = T::SomeConst::get(); - #[weight = >::into(new_value.clone())] + #[weight = >::into(new_value.clone())] fn set_dummy(origin, #[compact] new_value: T::Balance) { ensure_root(origin)?; @@ -102,7 +99,7 @@ pub mod pallet { type Balance: Parameter + codec::HasCompact + From - + Into + + Into + Default + MaybeSerializeDeserialize + scale_info::StaticTypeInfo; @@ -129,7 +126,7 @@ pub mod pallet { #[pallet::call] impl, I: 'static> Pallet { - #[pallet::weight(>::into(new_value.clone()))] + #[pallet::weight(>::into(new_value.clone()))] pub fn set_dummy( origin: OriginFor, #[pallet::compact] new_value: T::Balance, diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index 8b6c291096d5a..9080c9aad43f2 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for frame_system. @@ -59,44 +59,44 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[0, 3932160]`. fn remark(_b: u32, ) -> Weight { - Weight::from_ref_time(1_000_000 as RefTimeWeight) + Weight::from_ref_time(1_000_000 as u64) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) } // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - Weight::from_ref_time(5_367_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(5_367_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `i` is `[1, 1000]`. fn set_storage(i: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(603_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(603_000 as u64).saturating_mul(i as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `i` is `[1, 1000]`. fn kill_storage(i: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(513_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(513_000 as u64).saturating_mul(i as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `p` is `[1, 1000]`. fn kill_prefix(p: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_026_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(1_026_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(p as u64))) } } @@ -104,43 +104,43 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// The range of component `b` is `[0, 3932160]`. fn remark(_b: u32, ) -> Weight { - Weight::from_ref_time(1_000_000 as RefTimeWeight) + Weight::from_ref_time(1_000_000 as u64) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(b as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) } // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - Weight::from_ref_time(5_367_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(5_367_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `i` is `[1, 1000]`. fn set_storage(i: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(603_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(603_000 as u64).saturating_mul(i as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `i` is `[1, 1000]`. fn kill_storage(i: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(513_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(513_000 as u64).saturating_mul(i as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `p` is `[1, 1000]`. fn kill_prefix(p: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_026_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(1_026_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(p as u64))) } } diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index f71a0f753a43e..d51f7c9cfe79d 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_timestamp. @@ -54,12 +54,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - Weight::from_ref_time(8_080_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(8_080_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } fn on_finalize() -> Weight { - Weight::from_ref_time(2_681_000 as RefTimeWeight) + Weight::from_ref_time(2_681_000 as u64) } } @@ -68,11 +68,11 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - Weight::from_ref_time(8_080_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(8_080_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } fn on_finalize() -> Weight { - Weight::from_ref_time(2_681_000 as RefTimeWeight) + Weight::from_ref_time(2_681_000 as u64) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 106e5e163f02d..086b1c72b21c0 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_tips. @@ -58,59 +58,59 @@ impl WeightInfo for SubstrateWeight { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - Weight::from_ref_time(30_669_000 as RefTimeWeight) + Weight::from_ref_time(30_669_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - Weight::from_ref_time(28_768_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(28_768_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - Weight::from_ref_time(20_385_000 as RefTimeWeight) + Weight::from_ref_time(20_385_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(r as u64)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(166_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(166_000 as u64).saturating_mul(t as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - Weight::from_ref_time(12_287_000 as RefTimeWeight) + Weight::from_ref_time(12_287_000 as u64) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(363_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(363_000 as u64).saturating_mul(t as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Tips Tips (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - Weight::from_ref_time(45_656_000 as RefTimeWeight) + Weight::from_ref_time(45_656_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(276_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(276_000 as u64).saturating_mul(t as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - Weight::from_ref_time(18_525_000 as RefTimeWeight) + Weight::from_ref_time(18_525_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(t as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } } @@ -119,58 +119,58 @@ impl WeightInfo for () { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) fn report_awesome(r: u32, ) -> Weight { - Weight::from_ref_time(30_669_000 as RefTimeWeight) + Weight::from_ref_time(30_669_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - Weight::from_ref_time(28_768_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(28_768_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) fn tip_new(r: u32, t: u32, ) -> Weight { - Weight::from_ref_time(20_385_000 as RefTimeWeight) + Weight::from_ref_time(20_385_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as RefTimeWeight).saturating_mul(r as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(r as u64)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(166_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(166_000 as u64).saturating_mul(t as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) fn tip(t: u32, ) -> Weight { - Weight::from_ref_time(12_287_000 as RefTimeWeight) + Weight::from_ref_time(12_287_000 as u64) // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(363_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(363_000 as u64).saturating_mul(t as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Tips Tips (r:1 w:1) // Storage: Elections Members (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn close_tip(t: u32, ) -> Weight { - Weight::from_ref_time(45_656_000 as RefTimeWeight) + Weight::from_ref_time(45_656_000 as u64) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(276_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(276_000 as u64).saturating_mul(t as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn slash_tip(t: u32, ) -> Weight { - Weight::from_ref_time(18_525_000 as RefTimeWeight) + Weight::from_ref_time(18_525_000 as u64) // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(37_000 as RefTimeWeight).saturating_mul(t as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(t as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 16986203de1e5..8fe58dbf03d2b 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -66,8 +66,7 @@ use frame_support::{ dispatch::DispatchResult, traits::{EstimateCallFee, Get}, weights::{ - DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, RefTimeWeight, - Weight, WeightToFee, + DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight, WeightToFee, }, }; @@ -559,7 +558,7 @@ where } fn length_to_fee(length: u32) -> BalanceOf { - T::LengthToFee::weight_to_fee(&Weight::from_ref_time(length as RefTimeWeight)) + T::LengthToFee::weight_to_fee(&Weight::from_ref_time(length as u64)) } fn weight_to_fee(weight: Weight) -> BalanceOf { diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index 04fa4e3048c22..6fd9b1b818df6 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_transaction_storage. @@ -59,11 +59,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn store(l: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(l as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: TransactionStorage Transactions (r:1 w:0) // Storage: TransactionStorage ByteFee (r:1 w:0) @@ -72,9 +72,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - Weight::from_ref_time(50_978_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(50_978_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: TransactionStorage ProofChecked (r:1 w:1) // Storage: TransactionStorage StoragePeriod (r:1 w:0) @@ -82,9 +82,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - Weight::from_ref_time(106_990_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(106_990_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } @@ -97,11 +97,11 @@ impl WeightInfo for () { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn store(l: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(l as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: TransactionStorage Transactions (r:1 w:0) // Storage: TransactionStorage ByteFee (r:1 w:0) @@ -110,9 +110,9 @@ impl WeightInfo for () { // Storage: TransactionStorage BlockTransactions (r:1 w:1) // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - Weight::from_ref_time(50_978_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(6 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(50_978_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: TransactionStorage ProofChecked (r:1 w:1) // Storage: TransactionStorage StoragePeriod (r:1 w:0) @@ -120,8 +120,8 @@ impl WeightInfo for () { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - Weight::from_ref_time(106_990_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(5 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(106_990_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index d2a5bc9f1f258..37c62e0c18c52 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_treasury. @@ -58,51 +58,51 @@ impl WeightInfo for SubstrateWeight { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn spend() -> Weight { - Weight::from_ref_time(22_063_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(22_063_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - Weight::from_ref_time(26_473_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(26_473_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - Weight::from_ref_time(29_955_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(29_955_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(10_786_000 as RefTimeWeight) + Weight::from_ref_time(10_786_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(110_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Treasury Approvals (r:1 w:1) fn remove_approval() -> Weight { - Weight::from_ref_time(6_647_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(6_647_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Treasury Approvals (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - Weight::from_ref_time(25_805_000 as RefTimeWeight) + Weight::from_ref_time(25_805_000 as u64) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(28_473_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((3 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((3 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(28_473_000 as u64).saturating_mul(p as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(p as u64))) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(p as u64))) } } @@ -111,50 +111,50 @@ impl WeightInfo for () { // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn spend() -> Weight { - Weight::from_ref_time(22_063_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(22_063_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - Weight::from_ref_time(26_473_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(26_473_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - Weight::from_ref_time(29_955_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(29_955_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) fn approve_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(10_786_000 as RefTimeWeight) + Weight::from_ref_time(10_786_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(110_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Treasury Approvals (r:1 w:1) fn remove_approval() -> Weight { - Weight::from_ref_time(6_647_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(6_647_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Treasury Approvals (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) fn on_initialize_proposals(p: u32, ) -> Weight { - Weight::from_ref_time(25_805_000 as RefTimeWeight) + Weight::from_ref_time(25_805_000 as u64) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(28_473_000 as RefTimeWeight).saturating_mul(p as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((3 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((3 as RefTimeWeight).saturating_mul(p as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(28_473_000 as u64).saturating_mul(p as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(p as u64))) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(p as u64))) } } diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index dae72accd2adc..c7a8a2f6baa0f 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_uniques. @@ -80,16 +80,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(33_075_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(33_075_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - Weight::from_ref_time(19_528_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(19_528_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:0) @@ -103,192 +103,192 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(13_639_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(13_639_000 as u64).saturating_mul(n as u64)) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_393_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_393_000 as u64).saturating_mul(m as u64)) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_217_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((2 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(2_217_000 as u64).saturating_mul(a as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(m as u64))) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(a as u64))) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - Weight::from_ref_time(42_146_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(42_146_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - Weight::from_ref_time(42_960_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(42_960_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - Weight::from_ref_time(33_025_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(33_025_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:100 w:100) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 24_000 - .saturating_add(Weight::from_ref_time(15_540_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(15_540_000 as u64).saturating_mul(i as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(i as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - Weight::from_ref_time(25_194_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_194_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - Weight::from_ref_time(25_397_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_397_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - Weight::from_ref_time(19_278_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(19_278_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - Weight::from_ref_time(19_304_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(19_304_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - Weight::from_ref_time(28_615_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(28_615_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(19_943_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(19_943_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - Weight::from_ref_time(22_583_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(22_583_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - Weight::from_ref_time(47_520_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(47_520_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - Weight::from_ref_time(45_316_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(45_316_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - Weight::from_ref_time(38_391_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(38_391_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(38_023_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(38_023_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - Weight::from_ref_time(37_398_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(37_398_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - Weight::from_ref_time(35_621_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(35_621_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(25_856_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_856_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(26_098_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(26_098_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - Weight::from_ref_time(24_076_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(24_076_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - Weight::from_ref_time(22_035_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(22_035_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - Weight::from_ref_time(22_534_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(22_534_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques ItemPriceOf (r:1 w:1) // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - Weight::from_ref_time(45_272_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(45_272_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } } @@ -297,16 +297,16 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(33_075_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(33_075_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - Weight::from_ref_time(19_528_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(19_528_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:0) @@ -320,191 +320,191 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(13_639_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(13_639_000 as u64).saturating_mul(n as u64)) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_393_000 as RefTimeWeight).saturating_mul(m as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_393_000 as u64).saturating_mul(m as u64)) // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_217_000 as RefTimeWeight).saturating_mul(a as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((2 as RefTimeWeight).saturating_mul(n as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(m as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(a as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(2_217_000 as u64).saturating_mul(a as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(m as u64))) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(a as u64))) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - Weight::from_ref_time(42_146_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(42_146_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - Weight::from_ref_time(42_960_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(42_960_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - Weight::from_ref_time(33_025_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(33_025_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques Asset (r:100 w:100) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - Weight::from_ref_time(0 as RefTimeWeight) + Weight::from_ref_time(0 as u64) // Standard Error: 24_000 - .saturating_add(Weight::from_ref_time(15_540_000 as RefTimeWeight).saturating_mul(i as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes((1 as RefTimeWeight).saturating_mul(i as RefTimeWeight))) + .saturating_add(Weight::from_ref_time(15_540_000 as u64).saturating_mul(i as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(i as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - Weight::from_ref_time(25_194_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_194_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - Weight::from_ref_time(25_397_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_397_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - Weight::from_ref_time(19_278_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(19_278_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - Weight::from_ref_time(19_304_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(19_304_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - Weight::from_ref_time(28_615_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(28_615_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(19_943_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(19_943_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - Weight::from_ref_time(22_583_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(22_583_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - Weight::from_ref_time(47_520_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(47_520_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - Weight::from_ref_time(45_316_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(45_316_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - Weight::from_ref_time(38_391_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(38_391_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(38_023_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(38_023_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - Weight::from_ref_time(37_398_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(37_398_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - Weight::from_ref_time(35_621_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(35_621_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(25_856_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(25_856_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(26_098_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(26_098_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - Weight::from_ref_time(24_076_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(24_076_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - Weight::from_ref_time(22_035_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(22_035_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - Weight::from_ref_time(22_534_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(1 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(1 as RefTimeWeight)) + Weight::from_ref_time(22_534_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques ItemPriceOf (r:1 w:1) // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - Weight::from_ref_time(45_272_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + Weight::from_ref_time(45_272_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 1df9c2e67cc1f..b88319f2597c9 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -41,7 +41,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_utility. @@ -58,27 +58,27 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - Weight::from_ref_time(23_113_000 as RefTimeWeight) + Weight::from_ref_time(23_113_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_701_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_701_000 as u64).saturating_mul(c as u64)) } fn as_derivative() -> Weight { - Weight::from_ref_time(4_182_000 as RefTimeWeight) + Weight::from_ref_time(4_182_000 as u64) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - Weight::from_ref_time(18_682_000 as RefTimeWeight) + Weight::from_ref_time(18_682_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_794_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_794_000 as u64).saturating_mul(c as u64)) } fn dispatch_as() -> Weight { - Weight::from_ref_time(12_049_000 as RefTimeWeight) + Weight::from_ref_time(12_049_000 as u64) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - Weight::from_ref_time(19_136_000 as RefTimeWeight) + Weight::from_ref_time(19_136_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_697_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_697_000 as u64).saturating_mul(c as u64)) } } @@ -86,26 +86,26 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - Weight::from_ref_time(23_113_000 as RefTimeWeight) + Weight::from_ref_time(23_113_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_701_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_701_000 as u64).saturating_mul(c as u64)) } fn as_derivative() -> Weight { - Weight::from_ref_time(4_182_000 as RefTimeWeight) + Weight::from_ref_time(4_182_000 as u64) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - Weight::from_ref_time(18_682_000 as RefTimeWeight) + Weight::from_ref_time(18_682_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_794_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_794_000 as u64).saturating_mul(c as u64)) } fn dispatch_as() -> Weight { - Weight::from_ref_time(12_049_000 as RefTimeWeight) + Weight::from_ref_time(12_049_000 as u64) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - Weight::from_ref_time(19_136_000 as RefTimeWeight) + Weight::from_ref_time(19_136_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_697_000 as RefTimeWeight).saturating_mul(c as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(2_697_000 as u64).saturating_mul(c as u64)) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index 5988b0bd47d54..567d2fef74130 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_vesting. @@ -60,96 +60,96 @@ impl WeightInfo for SubstrateWeight { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_978_000 as RefTimeWeight) + Weight::from_ref_time(32_978_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(82_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(82_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(88_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(88_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_856_000 as RefTimeWeight) + Weight::from_ref_time(32_856_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(79_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(33_522_000 as RefTimeWeight) + Weight::from_ref_time(33_522_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(74_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(74_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(72_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(72_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_558_000 as RefTimeWeight) + Weight::from_ref_time(32_558_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(78_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(61_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(61_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(49_260_000 as RefTimeWeight) + Weight::from_ref_time(49_260_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(l as u64)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(49_166_000 as RefTimeWeight) + Weight::from_ref_time(49_166_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(77_000 as u64).saturating_mul(l as u64)) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(43_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(43_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(34_042_000 as RefTimeWeight) + Weight::from_ref_time(34_042_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(83_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(83_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(33_937_000 as RefTimeWeight) + Weight::from_ref_time(33_937_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(78_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } } @@ -158,95 +158,95 @@ impl WeightInfo for () { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_locked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_978_000 as RefTimeWeight) + Weight::from_ref_time(32_978_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(82_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(82_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(88_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(88_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vest_unlocked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_856_000 as RefTimeWeight) + Weight::from_ref_time(32_856_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(79_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(79_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(56_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_locked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(33_522_000 as RefTimeWeight) + Weight::from_ref_time(33_522_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(74_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(74_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(72_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(72_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_558_000 as RefTimeWeight) + Weight::from_ref_time(32_558_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(78_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(61_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(61_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vested_transfer(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(49_260_000 as RefTimeWeight) + Weight::from_ref_time(49_260_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(l as u64)) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(55_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(49_166_000 as RefTimeWeight) + Weight::from_ref_time(49_166_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(77_000 as u64).saturating_mul(l as u64)) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(43_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(4 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(4 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(43_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(34_042_000 as RefTimeWeight) + Weight::from_ref_time(34_042_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(83_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(83_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(80_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(33_937_000 as RefTimeWeight) + Weight::from_ref_time(33_937_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as RefTimeWeight).saturating_mul(l as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(78_000 as u64).saturating_mul(l as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as RefTimeWeight).saturating_mul(s as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(73_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } } diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index 88d1dedb2de47..ca474d5e55634 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -39,7 +39,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_whitelist. @@ -56,35 +56,35 @@ impl WeightInfo for SubstrateWeight { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - Weight::from_ref_time(20_938_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(20_938_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn remove_whitelisted_call() -> Weight { - Weight::from_ref_time(22_332_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(22_332_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn dispatch_whitelisted_call() -> Weight { - Weight::from_ref_time(5_989_917_000 as RefTimeWeight) - .saturating_add(T::DbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(5_989_917_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - Weight::from_ref_time(25_325_000 as RefTimeWeight) + Weight::from_ref_time(25_325_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(T::DbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(T::DbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } } @@ -93,34 +93,34 @@ impl WeightInfo for () { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - Weight::from_ref_time(20_938_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(2 as RefTimeWeight)) + Weight::from_ref_time(20_938_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn remove_whitelisted_call() -> Weight { - Weight::from_ref_time(22_332_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(22_332_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn dispatch_whitelisted_call() -> Weight { - Weight::from_ref_time(5_989_917_000 as RefTimeWeight) - .saturating_add(RocksDbWeight::get().reads(3 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + Weight::from_ref_time(5_989_917_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - Weight::from_ref_time(25_325_000 as RefTimeWeight) + Weight::from_ref_time(25_325_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as RefTimeWeight).saturating_mul(n as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().reads(2 as RefTimeWeight)) - .saturating_add(RocksDbWeight::get().writes(3 as RefTimeWeight)) + .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } } diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index f6be16cf69ac9..6e016c47ef010 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -15,7 +15,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{RefTimeWeight, Weight}}; +use frame_support::{traits::Get, weights::{Weight}}; use sp_std::marker::PhantomData; /// Weight functions for `{{pallet}}`. @@ -33,22 +33,22 @@ impl {{pallet}}::WeightInfo for WeightInfo { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { - Weight::from_ref_time({{underscore benchmark.base_weight}} as RefTimeWeight) + Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as u64).saturating_mul({{cw.name}} as u64)) {{/each}} {{#if (ne benchmark.base_reads "0")}} - .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as RefTimeWeight)) + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as u64)) {{/if}} {{#each benchmark.component_reads as |cr|}} - .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as RefTimeWeight).saturating_mul({{cr.name}} as RefTimeWeight))) + .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as u64).saturating_mul({{cr.name}} as u64))) {{/each}} {{#if (ne benchmark.base_writes "0")}} - .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as RefTimeWeight)) + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as u64)) {{/if}} {{#each benchmark.component_writes as |cw|}} - .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight))) + .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as u64).saturating_mul({{cw.name}} as u64))) {{/each}} } {{/each}} From 1c0d0083c2d3105c32b4fb7331f474ec2f0510dc Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Fri, 2 Sep 2022 21:33:26 +0000 Subject: [PATCH 1117/1472] Add benchmarking support for digest items (#12159) * Add benchmarking support for digest items * fmt --- bin/node-template/node/src/command.rs | 10 ++++++++-- bin/node/cli/src/command.rs | 15 +++++++++++++-- .../frame/benchmarking-cli/src/extrinsic/bench.rs | 8 +++++--- utils/frame/benchmarking-cli/src/extrinsic/cmd.rs | 5 +++-- utils/frame/benchmarking-cli/src/overhead/cmd.rs | 5 +++-- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index 142f0b40c325e..f8f02ed8fc2dd 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -139,7 +139,13 @@ pub fn run() -> sc_cli::Result<()> { let PartialComponents { client, .. } = service::new_partial(&config)?; let ext_builder = RemarkBuilder::new(client.clone()); - cmd.run(config, client, inherent_benchmark_data()?, &ext_builder) + cmd.run( + config, + client, + inherent_benchmark_data()?, + Vec::new(), + &ext_builder, + ) }, BenchmarkCmd::Extrinsic(cmd) => { let PartialComponents { client, .. } = service::new_partial(&config)?; @@ -153,7 +159,7 @@ pub fn run() -> sc_cli::Result<()> { )), ]); - cmd.run(client, inherent_benchmark_data()?, &ext_factory) + cmd.run(client, inherent_benchmark_data()?, Vec::new(), &ext_factory) }, BenchmarkCmd::Machine(cmd) => cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 1d88e9b539421..79abe8975f3b6 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -132,7 +132,13 @@ pub fn run() -> Result<()> { let partial = new_partial(&config)?; let ext_builder = RemarkBuilder::new(partial.client.clone()); - cmd.run(config, partial.client, inherent_benchmark_data()?, &ext_builder) + cmd.run( + config, + partial.client, + inherent_benchmark_data()?, + Vec::new(), + &ext_builder, + ) }, BenchmarkCmd::Extrinsic(cmd) => { // ensure that we keep the task manager alive @@ -147,7 +153,12 @@ pub fn run() -> Result<()> { )), ]); - cmd.run(partial.client, inherent_benchmark_data()?, &ext_factory) + cmd.run( + partial.client, + inherent_benchmark_data()?, + Vec::new(), + &ext_factory, + ) }, BenchmarkCmd::Machine(cmd) => cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), diff --git a/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index 27fc40fb34774..5dcf05956d42c 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -28,7 +28,7 @@ use sp_blockchain::{ use sp_runtime::{ traits::{Block as BlockT, Zero}, transaction_validity::{InvalidTransaction, TransactionValidityError}, - OpaqueExtrinsic, + Digest, DigestItem, OpaqueExtrinsic, }; use clap::Args; @@ -65,6 +65,7 @@ pub(crate) struct Benchmark { client: Arc, params: BenchmarkParams, inherent_data: sp_inherents::InherentData, + digest_items: Vec, _p: PhantomData<(Block, BA)>, } @@ -80,8 +81,9 @@ where client: Arc, params: BenchmarkParams, inherent_data: sp_inherents::InherentData, + digest_items: Vec, ) -> Self { - Self { client, params, inherent_data, _p: PhantomData } + Self { client, params, inherent_data, digest_items, _p: PhantomData } } /// Benchmark a block with only inherents. @@ -125,7 +127,7 @@ where &self, ext_builder: Option<&dyn ExtrinsicBuilder>, ) -> Result<(Block, Option)> { - let mut builder = self.client.new_block(Default::default())?; + let mut builder = self.client.new_block(Digest { logs: self.digest_items.clone() })?; // Create and insert the inherents. let inherents = builder.create_inherents(self.inherent_data.clone())?; for inherent in inherents { diff --git a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs index 6b4fd0fad6638..2c94a6be50255 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs @@ -19,7 +19,7 @@ use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; use sc_client_api::Backend as ClientBackend; use sp_api::{ApiExt, ProvideRuntimeApi}; -use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; +use sp_runtime::{traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; use clap::{Args, Parser}; use log::info; @@ -82,6 +82,7 @@ impl ExtrinsicCmd { &self, client: Arc, inherent_data: sp_inherents::InherentData, + digest_items: Vec, ext_factory: &ExtrinsicFactory, ) -> Result<()> where @@ -109,7 +110,7 @@ impl ExtrinsicCmd { return Err("Unknown pallet or extrinsic. Use --list for a complete list.".into()), }; - let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data); + let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data, digest_items); let stats = bench.bench_extrinsic(ext_builder)?; info!( "Executing a {}::{} extrinsic takes[ns]:\n{:?}", diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 28ceea63f1572..4d0e2e52df17d 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -23,7 +23,7 @@ use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; use sc_client_api::Backend as ClientBackend; use sc_service::Configuration; use sp_api::{ApiExt, ProvideRuntimeApi}; -use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; +use sp_runtime::{traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; use clap::{Args, Parser}; use log::info; @@ -90,6 +90,7 @@ impl OverheadCmd { cfg: Configuration, client: Arc, inherent_data: sp_inherents::InherentData, + digest_items: Vec, ext_builder: &dyn ExtrinsicBuilder, ) -> Result<()> where @@ -101,7 +102,7 @@ impl OverheadCmd { if ext_builder.pallet() != "system" || ext_builder.extrinsic() != "remark" { return Err(format!("The extrinsic builder is required to build `System::Remark` extrinsics but builds `{}` extrinsics instead", ext_builder.name()).into()); } - let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data); + let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data, digest_items); // per-block execution overhead { From 4b7911607b48a5ca7ebf1d655f12d91cdd241866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Sat, 3 Sep 2022 10:03:36 +0200 Subject: [PATCH 1118/1472] Emit events for inter contract calls (#12136) * Add topics to contract events * Add `Call` events * Fix compilation for no_std * Added docs --- frame/contracts/src/exec.rs | 143 +++++++++++++++--------- frame/contracts/src/lib.rs | 50 ++++++++- frame/contracts/src/tests.rs | 147 ++++++++++++++++++++----- frame/contracts/src/wasm/code_cache.rs | 10 +- 4 files changed, 266 insertions(+), 84 deletions(-) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 81e1aef92cbfc..4ae336a907001 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -34,7 +34,7 @@ use pallet_contracts_primitives::ExecReturnValue; use smallvec::{Array, SmallVec}; use sp_core::{crypto::UncheckedFrom, ecdsa::Public as ECDSAPublic}; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; -use sp_runtime::traits::Convert; +use sp_runtime::traits::{Convert, Hash}; use sp_std::{marker::PhantomData, mem, prelude::*}; pub type AccountIdOf = ::AccountId; @@ -784,16 +784,19 @@ where /// /// This can be either a call or an instantiate. fn run(&mut self, executable: E, input_data: Vec) -> Result { - let entry_point = self.top_frame().entry_point; + let frame = self.top_frame(); + let entry_point = frame.entry_point; + let delegated_code_hash = + if frame.delegate_caller.is_some() { Some(*executable.code_hash()) } else { None }; let do_transaction = || { // We need to charge the storage deposit before the initial transfer so that // it can create the account in case the initial transfer is < ed. if entry_point == ExportedFunction::Constructor { - let top_frame = top_frame_mut!(self); - top_frame.nested_storage.charge_instantiate( + let frame = top_frame_mut!(self); + frame.nested_storage.charge_instantiate( &self.origin, - &top_frame.account_id, - top_frame.contract_info.get(&top_frame.account_id), + &frame.account_id, + frame.contract_info.get(&frame.account_id), )?; } @@ -805,23 +808,42 @@ where .execute(self, &entry_point, input_data) .map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?; - // Additional work needs to be performed in case of an instantiation. - if !output.did_revert() && entry_point == ExportedFunction::Constructor { - let frame = self.top_frame(); - - // It is not allowed to terminate a contract inside its constructor. - if matches!(frame.contract_info, CachedContract::Terminated) { - return Err(Error::::TerminatedInConstructor.into()) - } + // Avoid useless work that would be reverted anyways. + if output.did_revert() { + return Ok(output) + } - // Deposit an instantiation event. - deposit_event::( - vec![], - Event::Instantiated { - deployer: self.caller().clone(), - contract: frame.account_id.clone(), - }, - ); + let frame = self.top_frame(); + let account_id = &frame.account_id; + match (entry_point, delegated_code_hash) { + (ExportedFunction::Constructor, _) => { + // It is not allowed to terminate a contract inside its constructor. + if matches!(frame.contract_info, CachedContract::Terminated) { + return Err(Error::::TerminatedInConstructor.into()) + } + + // Deposit an instantiation event. + Contracts::::deposit_event( + vec![T::Hashing::hash_of(self.caller()), T::Hashing::hash_of(account_id)], + Event::Instantiated { + deployer: self.caller().clone(), + contract: account_id.clone(), + }, + ); + }, + (ExportedFunction::Call, Some(code_hash)) => { + Contracts::::deposit_event( + vec![T::Hashing::hash_of(account_id), T::Hashing::hash_of(&code_hash)], + Event::DelegateCalled { contract: account_id.clone(), code_hash }, + ); + }, + (ExportedFunction::Call, None) => { + let caller = self.caller(); + Contracts::::deposit_event( + vec![T::Hashing::hash_of(caller), T::Hashing::hash_of(account_id)], + Event::Called { caller: caller.clone(), contract: account_id.clone() }, + ); + }, } Ok(output) @@ -850,6 +872,7 @@ where // has changed. Err(error) => (false, Err(error.into())), }; + self.pop_frame(success); output } @@ -1134,10 +1157,13 @@ where )?; ContractInfoOf::::remove(&frame.account_id); E::remove_user(info.code_hash); - Contracts::::deposit_event(Event::Terminated { - contract: frame.account_id.clone(), - beneficiary: beneficiary.clone(), - }); + Contracts::::deposit_event( + vec![T::Hashing::hash_of(&frame.account_id), T::Hashing::hash_of(&beneficiary)], + Event::Terminated { + contract: frame.account_id.clone(), + beneficiary: beneficiary.clone(), + }, + ); Ok(()) } @@ -1242,7 +1268,7 @@ where } fn deposit_event(&mut self, topics: Vec, data: Vec) { - deposit_event::( + Contracts::::deposit_event( topics, Event::ContractEmitted { contract: self.top_frame().account_id.clone(), data }, ); @@ -1304,22 +1330,18 @@ where let prev_hash = top_frame.contract_info().code_hash; E::remove_user(prev_hash); top_frame.contract_info().code_hash = hash; - Contracts::::deposit_event(Event::ContractCodeUpdated { - contract: top_frame.account_id.clone(), - new_code_hash: hash, - old_code_hash: prev_hash, - }); + Contracts::::deposit_event( + vec![T::Hashing::hash_of(&top_frame.account_id), hash, prev_hash], + Event::ContractCodeUpdated { + contract: top_frame.account_id.clone(), + new_code_hash: hash, + old_code_hash: prev_hash, + }, + ); Ok(()) } } -fn deposit_event(topics: Vec, event: Event) { - >::deposit_event_indexed( - &topics, - ::Event::from(event).into(), - ) -} - mod sealing { use super::*; @@ -1347,7 +1369,7 @@ mod tests { gas::GasMeter, storage::Storage, tests::{ - test_utils::{get_balance, place_contract, set_balance}, + test_utils::{get_balance, hash, place_contract, set_balance}, Call, Event as MetaEvent, ExtBuilder, Test, TestFilter, ALICE, BOB, CHARLIE, GAS_LIMIT, }, Error, @@ -2237,7 +2259,10 @@ mod tests { ); assert_eq!( &events(), - &[Event::Instantiated { deployer: BOB, contract: instantiated_contract_address }] + &[ + Event::Instantiated { deployer: BOB, contract: instantiated_contract_address }, + Event::Called { caller: ALICE, contract: BOB }, + ] ); }); } @@ -2289,7 +2314,7 @@ mod tests { // The contract wasn't instantiated so we don't expect to see an instantiation // event here. - assert_eq!(&events(), &[]); + assert_eq!(&events(), &[Event::Called { caller: ALICE, contract: BOB },]); }); } @@ -2591,14 +2616,24 @@ mod tests { let remark_hash = ::Hashing::hash(b"Hello World"); assert_eq!( System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: MetaEvent::System(frame_system::Event::Remarked { - sender: BOB, - hash: remark_hash - }), - topics: vec![], - },] + vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::System(frame_system::Event::Remarked { + sender: BOB, + hash: remark_hash + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::Contracts(crate::Event::Called { + caller: ALICE, + contract: BOB, + }), + topics: vec![hash(&ALICE), hash(&BOB)], + }, + ] ); }); } @@ -2684,6 +2719,14 @@ mod tests { },), topics: vec![], }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::Contracts(crate::Event::Called { + caller: ALICE, + contract: BOB, + }), + topics: vec![hash(&ALICE), hash(&BOB)], + }, ] ); }); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 7fda4bca36d2e..3c63ad86016f3 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -631,11 +631,14 @@ pub mod pallet { }; >::add_user(code_hash)?; >::remove_user(contract.code_hash); - Self::deposit_event(Event::ContractCodeUpdated { - contract: dest.clone(), - new_code_hash: code_hash, - old_code_hash: contract.code_hash, - }); + Self::deposit_event( + vec![T::Hashing::hash_of(&dest), code_hash, contract.code_hash], + Event::ContractCodeUpdated { + contract: dest.clone(), + new_code_hash: code_hash, + old_code_hash: contract.code_hash, + }, + ); contract.code_hash = code_hash; Ok(()) }) @@ -643,7 +646,6 @@ pub mod pallet { } #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Contract deployed by address at the specified address. Instantiated { deployer: T::AccountId, contract: T::AccountId }, @@ -685,6 +687,35 @@ pub mod pallet { /// Previous code hash of the contract. old_code_hash: T::Hash, }, + + /// A contract was called either by a plain account or another contract. + /// + /// # Note + /// + /// Please keep in mind that like all events this is only emitted for successful + /// calls. This is because on failure all storage changes including events are + /// rolled back. + Called { + /// The account that called the `contract`. + caller: T::AccountId, + /// The contract that was called. + contract: T::AccountId, + }, + + /// A contract delegate called a code hash. + /// + /// # Note + /// + /// Please keep in mind that like all events this is only emitted for successful + /// calls. This is because on failure all storage changes including events are + /// rolled back. + DelegateCalled { + /// The contract that performed the delegate call and hence in whose context + /// the `code_hash` is executed. + contract: T::AccountId, + /// The code hash that was delegate called. + code_hash: CodeHash, + }, } #[pallet::error] @@ -1084,4 +1115,11 @@ where }; InternalInstantiateOutput { result: try_exec(), gas_meter, storage_deposit } } + + fn deposit_event(topics: Vec, event: Event) { + >::deposit_event_indexed( + &topics, + ::Event::from(event).into(), + ) + } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index f4fa6bb3d72db..f65f845f7b9fe 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use self::test_utils::hash; use crate::{ chain_extension::{ ChainExtension, Environment, Ext, InitState, RegisteredChainExtension, @@ -74,8 +75,9 @@ frame_support::construct_runtime!( #[macro_use] pub mod test_utils { - use super::{Balances, Test}; + use super::{Balances, Hash, SysConfig, Test}; use crate::{exec::AccountIdOf, storage::Storage, CodeHash, Config, ContractInfoOf, Nonce}; + use codec::Encode; use frame_support::traits::Currency; pub fn place_contract(address: &AccountIdOf, code_hash: CodeHash) { @@ -95,6 +97,9 @@ pub mod test_utils { pub fn get_balance(who: &AccountIdOf) -> u64 { Balances::free_balance(who) } + pub fn hash(s: &S) -> <::Hashing as Hash>::Output { + <::Hashing as Hash>::hash_of(s) + } macro_rules! assert_return_code { ( $x:expr , $y:expr $(,)? ) => {{ assert_eq!(u32::from_le_bytes($x.data[..].try_into().unwrap()), $y as u32); @@ -571,7 +576,7 @@ fn instantiate_and_call_and_deposit_event() { deployer: ALICE, contract: addr.clone() }), - topics: vec![], + topics: vec![hash(&ALICE), hash(&addr)], }, ] ); @@ -857,7 +862,7 @@ fn deploy_and_call_other_contract() { deployer: caller_addr.clone(), contract: callee_addr.clone(), }), - topics: vec![], + topics: vec![hash(&caller_addr), hash(&callee_addr)], }, EventRecord { phase: Phase::Initialization, @@ -868,6 +873,22 @@ fn deploy_and_call_other_contract() { }), topics: vec![], }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: caller_addr.clone(), + contract: callee_addr.clone(), + }), + topics: vec![hash(&caller_addr), hash(&callee_addr)], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: ALICE, + contract: caller_addr.clone(), + }), + topics: vec![hash(&ALICE), hash(&caller_addr)], + }, ] ); }); @@ -1067,6 +1088,14 @@ fn cannot_self_destruct_by_refund_after_slash() { }), topics: vec![], }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: ALICE, + contract: addr.clone(), + }), + topics: vec![hash(&ALICE), hash(&addr)], + }, EventRecord { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::ReserveRepatriated { @@ -1174,7 +1203,15 @@ fn self_destruct_works() { contract: addr.clone(), beneficiary: DJANGO }), - topics: vec![], + topics: vec![hash(&addr), hash(&DJANGO)], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: ALICE, + contract: addr.clone(), + }), + topics: vec![hash(&ALICE), hash(&addr)], }, EventRecord { phase: Phase::Initialization, @@ -2621,7 +2658,7 @@ fn upload_code_works() { EventRecord { phase: Phase::Initialization, event: Event::Contracts(crate::Event::CodeStored { code_hash }), - topics: vec![], + topics: vec![code_hash], }, ] ); @@ -2700,7 +2737,7 @@ fn remove_code_works() { EventRecord { phase: Phase::Initialization, event: Event::Contracts(crate::Event::CodeStored { code_hash }), - topics: vec![], + topics: vec![code_hash], }, EventRecord { phase: Phase::Initialization, @@ -2713,7 +2750,7 @@ fn remove_code_works() { EventRecord { phase: Phase::Initialization, event: Event::Contracts(crate::Event::CodeRemoved { code_hash }), - topics: vec![], + topics: vec![code_hash], }, ] ); @@ -2755,7 +2792,7 @@ fn remove_code_wrong_origin() { EventRecord { phase: Phase::Initialization, event: Event::Contracts(crate::Event::CodeStored { code_hash }), - topics: vec![], + topics: vec![code_hash], }, ] ); @@ -2886,7 +2923,7 @@ fn instantiate_with_zero_balance_works() { EventRecord { phase: Phase::Initialization, event: Event::Contracts(crate::Event::CodeStored { code_hash }), - topics: vec![], + topics: vec![code_hash], }, EventRecord { phase: Phase::Initialization, @@ -2894,7 +2931,7 @@ fn instantiate_with_zero_balance_works() { deployer: ALICE, contract: addr.clone(), }), - topics: vec![], + topics: vec![hash(&ALICE), hash(&addr)], }, ] ); @@ -2986,7 +3023,7 @@ fn instantiate_with_below_existential_deposit_works() { EventRecord { phase: Phase::Initialization, event: Event::Contracts(crate::Event::CodeStored { code_hash }), - topics: vec![], + topics: vec![code_hash], }, EventRecord { phase: Phase::Initialization, @@ -2994,7 +3031,7 @@ fn instantiate_with_below_existential_deposit_works() { deployer: ALICE, contract: addr.clone(), }), - topics: vec![], + topics: vec![hash(&ALICE), hash(&addr)], }, ] ); @@ -3074,6 +3111,14 @@ fn storage_deposit_works() { }), topics: vec![], }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: ALICE, + contract: addr.clone(), + }), + topics: vec![hash(&ALICE), hash(&addr)], + }, EventRecord { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::Transfer { @@ -3091,6 +3136,14 @@ fn storage_deposit_works() { }), topics: vec![], }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: ALICE, + contract: addr.clone(), + }), + topics: vec![hash(&ALICE), hash(&addr)], + }, EventRecord { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::Transfer { @@ -3108,6 +3161,14 @@ fn storage_deposit_works() { }), topics: vec![], }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: ALICE, + contract: addr.clone(), + }), + topics: vec![hash(&ALICE), hash(&addr)], + }, EventRecord { phase: Phase::Initialization, event: Event::Balances(pallet_balances::Event::ReserveRepatriated { @@ -3193,11 +3254,11 @@ fn set_code_extrinsic() { vec![EventRecord { phase: Phase::Initialization, event: Event::Contracts(pallet_contracts::Event::ContractCodeUpdated { - contract: addr, + contract: addr.clone(), new_code_hash, old_code_hash: code_hash, }), - topics: vec![], + topics: vec![hash(&addr), new_code_hash, code_hash], },] ); }); @@ -3226,7 +3287,7 @@ fn call_after_killed_account_needs_funding() { // Destroy the account of the contract by slashing. // Slashing can actually happen if the contract takes part in staking. - // It is a corner case and we except the destruction of the account. + // It is a corner case and we accept the destruction of the account. let _ = ::Currency::slash( &addr, ::Currency::total_balance(&addr), @@ -3284,6 +3345,14 @@ fn call_after_killed_account_needs_funding() { }), topics: vec![], }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: ALICE, + contract: addr.clone(), + }), + topics: vec![hash(&ALICE), hash(&addr)], + }, EventRecord { phase: Phase::Initialization, event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), @@ -3306,6 +3375,14 @@ fn call_after_killed_account_needs_funding() { }), topics: vec![], }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: ALICE, + contract: addr.clone(), + }), + topics: vec![hash(&ALICE), hash(&addr)], + }, ] ); }); @@ -3454,6 +3531,8 @@ fn set_code_hash() { // upload new code assert_ok!(Contracts::upload_code(Origin::signed(ALICE), new_wasm.clone(), None)); + System::reset_events(); + // First call sets new code_hash and returns 1 let result = Contracts::bare_call( ALICE, @@ -3477,16 +3556,34 @@ fn set_code_hash() { // Checking for the last event only assert_eq!( - System::events().pop().unwrap(), - EventRecord { - phase: Phase::Initialization, - event: Event::Contracts(crate::Event::ContractCodeUpdated { - contract: contract_addr.clone(), - new_code_hash, - old_code_hash: code_hash, - }), - topics: vec![], - }, + &System::events(), + &[ + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::ContractCodeUpdated { + contract: contract_addr.clone(), + new_code_hash, + old_code_hash: code_hash, + }), + topics: vec![hash(&contract_addr), new_code_hash, code_hash], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: ALICE, + contract: contract_addr.clone(), + }), + topics: vec![hash(&ALICE), hash(&contract_addr)], + }, + EventRecord { + phase: Phase::Initialization, + event: Event::Contracts(crate::Event::Called { + caller: ALICE, + contract: contract_addr.clone(), + }), + topics: vec![hash(&ALICE), hash(&contract_addr)], + }, + ], ); }); } diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index d482d5c4bbf3f..eb5551e342bca 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -42,6 +42,7 @@ use frame_support::{ }; use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::BadOrigin; +use sp_std::vec; /// Put the instrumented module in storage. /// @@ -96,7 +97,7 @@ where >::insert(&code_hash, orig_code); >::insert(&code_hash, owner_info); *existing = Some(module); - >::deposit_event(Event::CodeStored { code_hash }); + >::deposit_event(vec![code_hash], Event::CodeStored { code_hash }); Ok(()) }, }) @@ -133,7 +134,10 @@ pub fn increment_refcount(code_hash: CodeHash) -> Result<(), Dispa } /// Try to remove code together with all associated information. -pub fn try_remove(origin: &T::AccountId, code_hash: CodeHash) -> DispatchResult { +pub fn try_remove(origin: &T::AccountId, code_hash: CodeHash) -> DispatchResult +where + T::AccountId: UncheckedFrom + AsRef<[u8]>, +{ >::try_mutate_exists(&code_hash, |existing| { if let Some(owner_info) = existing { ensure!(owner_info.refcount == 0, >::CodeInUse); @@ -142,7 +146,7 @@ pub fn try_remove(origin: &T::AccountId, code_hash: CodeHash) -> D *existing = None; >::remove(&code_hash); >::remove(&code_hash); - >::deposit_event(Event::CodeRemoved { code_hash }); + >::deposit_event(vec![code_hash], Event::CodeRemoved { code_hash }); Ok(()) } else { Err(>::CodeNotFound.into()) From 78bff0efb83b8b3cff1d09561c335c9b76504066 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Sat, 3 Sep 2022 23:34:47 +0300 Subject: [PATCH 1119/1472] Use custom type for ProtocolName (#12172) * Add ProtocolName custom type * Use new ProtocolName in sc_network_common * Use new ProtocolName in sc_network * Use new ProtocolName for BEEFY and GRANDPA * Use new ProtocolName for notifications * Use new ProtocolName in sc_network (part 2) * Use new ProtocolName in sc_network_gossip * Use new ProtocolName in sc_offchain * Remove unused imports * Some more fixes * Add tests * Fix minor import issues * Re-export ProtocolName in sc_network * Revert "Re-export ProtocolName in sc_network" This reverts commit 8d8ff71927e7750757f29c9bbd88dc0ba181d214. * Re-export ProtocolName in sc_network * Remove dependency on sc-network-common from beefy-gadget --- client/beefy/src/lib.rs | 8 +- .../finality-grandpa/src/communication/mod.rs | 3 +- .../src/communication/tests.rs | 22 +-- client/finality-grandpa/src/lib.rs | 5 +- client/network-gossip/src/bridge.rs | 38 ++---- client/network-gossip/src/lib.rs | 9 +- client/network-gossip/src/state_machine.rs | 37 ++--- client/network/common/src/config.rs | 4 +- client/network/common/src/protocol.rs | 127 ++++++++++++++++++ client/network/common/src/protocol/event.rs | 10 +- .../network/common/src/request_responses.rs | 7 +- client/network/common/src/service.rs | 44 +++--- client/network/src/behaviour.rs | 20 +-- client/network/src/config.rs | 11 +- client/network/src/error.rs | 5 +- client/network/src/lib.rs | 5 +- client/network/src/protocol.rs | 26 ++-- .../src/protocol/notifications/behaviour.rs | 9 +- .../src/protocol/notifications/handler.rs | 9 +- .../notifications/upgrade/notifications.rs | 65 +++------ client/network/src/request_responses.rs | 29 ++-- client/network/src/service.rs | 50 +++---- client/network/src/service/tests.rs | 63 +++++---- client/network/src/transactions.rs | 12 +- client/network/test/src/lib.rs | 4 +- client/offchain/src/api.rs | 19 ++- client/offchain/src/lib.rs | 20 ++- 27 files changed, 381 insertions(+), 280 deletions(-) diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index bdf44e056786c..cdb7fca10320d 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -20,6 +20,7 @@ use beefy_primitives::{BeefyApi, MmrRootHash}; use prometheus::Registry; use sc_client_api::{Backend, BlockchainEvents, Finalizer}; use sc_consensus::BlockImport; +use sc_network::ProtocolName; use sc_network_gossip::Network as GossipNetwork; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; @@ -55,6 +56,7 @@ pub use beefy_protocol_name::standard_name as protocol_standard_name; pub(crate) mod beefy_protocol_name { use sc_chain_spec::ChainSpec; + use sc_network::ProtocolName; const NAME: &str = "/beefy/1"; /// Old names for the notifications protocol, used for backward compatibility. @@ -66,7 +68,7 @@ pub(crate) mod beefy_protocol_name { pub fn standard_name>( genesis_hash: &Hash, chain_spec: &Box, - ) -> std::borrow::Cow<'static, str> { + ) -> ProtocolName { let chain_prefix = match chain_spec.fork_id() { Some(fork_id) => format!("/{}/{}", hex::encode(genesis_hash), fork_id), None => format!("/{}", hex::encode(genesis_hash)), @@ -79,7 +81,7 @@ pub(crate) mod beefy_protocol_name { /// [`sc_network::config::NetworkConfiguration::extra_sets`]. /// For standard protocol name see [`beefy_protocol_name::standard_name`]. pub fn beefy_peers_set_config( - protocol_name: std::borrow::Cow<'static, str>, + protocol_name: ProtocolName, ) -> sc_network::config::NonDefaultSetConfig { let mut cfg = sc_network::config::NonDefaultSetConfig::new(protocol_name, 1024 * 1024); @@ -202,7 +204,7 @@ where /// Prometheus metric registry pub prometheus_registry: Option, /// Chain specific GRANDPA protocol name. See [`beefy_protocol_name::standard_name`]. - pub protocol_name: std::borrow::Cow<'static, str>, + pub protocol_name: ProtocolName, /// Links between the block importer, the background voter and the RPC layer. pub links: BeefyVoterLinks, } diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 7a47ebe214950..04d7ceaa05c8c 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -70,6 +70,7 @@ pub(crate) mod tests; pub mod grandpa_protocol_name { use sc_chain_spec::ChainSpec; + use sc_network_common::protocol::ProtocolName; pub(crate) const NAME: &str = "/grandpa/1"; /// Old names for the notifications protocol, used for backward compatibility. @@ -81,7 +82,7 @@ pub mod grandpa_protocol_name { pub fn standard_name>( genesis_hash: &Hash, chain_spec: &Box, - ) -> std::borrow::Cow<'static, str> { + ) -> ProtocolName { let chain_prefix = match chain_spec.fork_id() { Some(fork_id) => format!("/{}/{}", hex::encode(genesis_hash), fork_id), None => format!("/{}", hex::encode(genesis_hash)), diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index 4d709f56f3d61..1f607e8d68c02 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -28,7 +28,10 @@ use parity_scale_codec::Encode; use sc_network::{config::Role, Multiaddr, PeerId, ReputationChange}; use sc_network_common::{ config::MultiaddrWithPeerId, - protocol::event::{Event as NetworkEvent, ObservedRole}, + protocol::{ + event::{Event as NetworkEvent, ObservedRole}, + ProtocolName, + }, service::{ NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkSyncForkRequest, NotificationSender, NotificationSenderError, @@ -41,7 +44,6 @@ use sp_finality_grandpa::AuthorityList; use sp_keyring::Ed25519Keyring; use sp_runtime::traits::NumberFor; use std::{ - borrow::Cow, collections::HashSet, pin::Pin, sync::Arc, @@ -78,7 +80,7 @@ impl NetworkPeers for TestNetwork { let _ = self.sender.unbounded_send(Event::Report(who, cost_benefit)); } - fn disconnect_peer(&self, _who: PeerId, _protocol: Cow<'static, str>) {} + fn disconnect_peer(&self, _who: PeerId, _protocol: ProtocolName) {} fn accept_unreserved_peers(&self) { unimplemented!(); @@ -98,7 +100,7 @@ impl NetworkPeers for TestNetwork { fn set_reserved_peers( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); @@ -106,23 +108,23 @@ impl NetworkPeers for TestNetwork { fn add_peers_to_reserved_set( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); } - fn remove_peers_from_reserved_set(&self, _protocol: Cow<'static, str>, _peers: Vec) {} + fn remove_peers_from_reserved_set(&self, _protocol: ProtocolName, _peers: Vec) {} fn add_to_peers_set( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); } - fn remove_from_peers_set(&self, _protocol: Cow<'static, str>, _peers: Vec) { + fn remove_from_peers_set(&self, _protocol: ProtocolName, _peers: Vec) { unimplemented!(); } @@ -143,14 +145,14 @@ impl NetworkEventStream for TestNetwork { } impl NetworkNotification for TestNetwork { - fn write_notification(&self, target: PeerId, _protocol: Cow<'static, str>, message: Vec) { + fn write_notification(&self, target: PeerId, _protocol: ProtocolName, message: Vec) { let _ = self.sender.unbounded_send(Event::WriteNotification(target, message)); } fn notification_sender( &self, _target: PeerId, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, ) -> Result, NotificationSenderError> { unimplemented!(); } diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index cb32957c0b0bf..149cf1f89a222 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -68,6 +68,7 @@ use sc_client_api::{ StorageProvider, TransactionFor, }; use sc_consensus::BlockImport; +use sc_network_common::protocol::ProtocolName; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; use sp_api::ProvideRuntimeApi; @@ -266,7 +267,7 @@ pub struct Config { /// TelemetryHandle instance. pub telemetry: Option, /// Chain specific GRANDPA protocol name. See [`crate::protocol_standard_name`]. - pub protocol_name: std::borrow::Cow<'static, str>, + pub protocol_name: ProtocolName, } impl Config { @@ -723,7 +724,7 @@ pub struct GrandpaParams { /// [`sc_network::config::NetworkConfiguration::extra_sets`]. /// For standard protocol name see [`crate::protocol_standard_name`]. pub fn grandpa_peers_set_config( - protocol_name: std::borrow::Cow<'static, str>, + protocol_name: ProtocolName, ) -> sc_network::config::NonDefaultSetConfig { use communication::grandpa_protocol_name; sc_network::config::NonDefaultSetConfig { diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 45eff09332f67..121fa6dc9a50d 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -21,7 +21,7 @@ use crate::{ Network, Validator, }; -use sc_network_common::protocol::event::Event; +use sc_network_common::protocol::{event::Event, ProtocolName}; use sc_peerset::ReputationChange; use futures::{ @@ -33,7 +33,6 @@ use log::trace; use prometheus_endpoint::Registry; use sp_runtime::traits::Block as BlockT; use std::{ - borrow::Cow, collections::{HashMap, VecDeque}, pin::Pin, sync::Arc, @@ -46,7 +45,7 @@ pub struct GossipEngine { state_machine: ConsensusGossip, network: Box + Send>, periodic_maintenance_interval: futures_timer::Delay, - protocol: Cow<'static, str>, + protocol: ProtocolName, /// Incoming events from the network. network_event_stream: Pin + Send>>, @@ -78,7 +77,7 @@ impl GossipEngine { /// Create a new instance. pub fn new + Send + Clone + 'static>( network: N, - protocol: impl Into>, + protocol: impl Into, validator: Arc>, metrics_registry: Option<&Registry>, ) -> Self @@ -329,7 +328,6 @@ mod tests { traits::{Block as BlockT, NumberFor}, }; use std::{ - borrow::Cow, collections::HashSet, sync::{Arc, Mutex}, }; @@ -360,7 +358,7 @@ mod tests { fn report_peer(&self, _who: PeerId, _cost_benefit: ReputationChange) {} - fn disconnect_peer(&self, _who: PeerId, _protocol: Cow<'static, str>) { + fn disconnect_peer(&self, _who: PeerId, _protocol: ProtocolName) { unimplemented!(); } @@ -382,7 +380,7 @@ mod tests { fn set_reserved_peers( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); @@ -390,28 +388,23 @@ mod tests { fn add_peers_to_reserved_set( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); } - fn remove_peers_from_reserved_set( - &self, - _protocol: Cow<'static, str>, - _peers: Vec, - ) { - } + fn remove_peers_from_reserved_set(&self, _protocol: ProtocolName, _peers: Vec) {} fn add_to_peers_set( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); } - fn remove_from_peers_set(&self, _protocol: Cow<'static, str>, _peers: Vec) { + fn remove_from_peers_set(&self, _protocol: ProtocolName, _peers: Vec) { unimplemented!(); } @@ -430,19 +423,14 @@ mod tests { } impl NetworkNotification for TestNetwork { - fn write_notification( - &self, - _target: PeerId, - _protocol: Cow<'static, str>, - _message: Vec, - ) { + fn write_notification(&self, _target: PeerId, _protocol: ProtocolName, _message: Vec) { unimplemented!(); } fn notification_sender( &self, _target: PeerId, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, ) -> Result, NotificationSenderError> { unimplemented!(); } @@ -505,7 +493,7 @@ mod tests { #[test] fn keeps_multiple_subscribers_per_topic_updated_with_both_old_and_new_messages() { let topic = H256::default(); - let protocol = Cow::Borrowed("/my_protocol"); + let protocol = ProtocolName::from("/my_protocol"); let remote_peer = PeerId::random(); let network = TestNetwork::default(); @@ -622,7 +610,7 @@ mod tests { } fn prop(channels: Vec, notifications: Vec>) { - let protocol = Cow::Borrowed("/my_protocol"); + let protocol = ProtocolName::from("/my_protocol"); let remote_peer = PeerId::random(); let network = TestNetwork::default(); diff --git a/client/network-gossip/src/lib.rs b/client/network-gossip/src/lib.rs index 0fdde1feac6c6..1c8fb8ba05ce7 100644 --- a/client/network-gossip/src/lib.rs +++ b/client/network-gossip/src/lib.rs @@ -68,11 +68,12 @@ pub use self::{ }; use libp2p::{multiaddr, PeerId}; -use sc_network_common::service::{ - NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, +use sc_network_common::{ + protocol::ProtocolName, + service::{NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers}, }; use sp_runtime::traits::{Block as BlockT, NumberFor}; -use std::{borrow::Cow, iter}; +use std::iter; mod bridge; mod state_machine; @@ -82,7 +83,7 @@ mod validator; pub trait Network: NetworkPeers + NetworkEventStream + NetworkNotification + NetworkBlock> { - fn add_set_reserved(&self, who: PeerId, protocol: Cow<'static, str>) { + fn add_set_reserved(&self, who: PeerId, protocol: ProtocolName) { let addr = iter::once(multiaddr::Protocol::P2p(who.into())).collect::(); let result = self.add_peers_to_reserved_set(protocol, iter::once(addr).collect()); diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index ff75b4520bf03..30a2e9d1494be 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -22,9 +22,9 @@ use ahash::AHashSet; use libp2p::PeerId; use lru::LruCache; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; -use sc_network_common::protocol::event::ObservedRole; +use sc_network_common::protocol::{event::ObservedRole, ProtocolName}; use sp_runtime::traits::{Block as BlockT, Hash, HashFor}; -use std::{borrow::Cow, collections::HashMap, iter, sync::Arc, time, time::Instant}; +use std::{collections::HashMap, iter, sync::Arc, time, time::Instant}; // FIXME: Add additional spam/DoS attack protection: https://github.com/paritytech/substrate/issues/1115 // NOTE: The current value is adjusted based on largest production network deployment (Kusama) and @@ -99,7 +99,7 @@ impl<'g, 'p, B: BlockT> ValidatorContext for NetworkContext<'g, 'p, B> { fn propagate<'a, B: BlockT, I>( network: &mut dyn Network, - protocol: Cow<'static, str>, + protocol: ProtocolName, messages: I, intent: MessageIntent, peers: &mut HashMap>, @@ -155,7 +155,7 @@ pub struct ConsensusGossip { peers: HashMap>, messages: Vec>, known_messages: LruCache, - protocol: Cow<'static, str>, + protocol: ProtocolName, validator: Arc>, next_broadcast: Instant, metrics: Option, @@ -165,7 +165,7 @@ impl ConsensusGossip { /// Create a new instance using the given validator. pub fn new( validator: Arc>, - protocol: Cow<'static, str>, + protocol: ProtocolName, metrics_registry: Option<&Registry>, ) -> Self { let metrics = match metrics_registry.map(Metrics::register) { @@ -527,7 +527,6 @@ mod tests { traits::NumberFor, }; use std::{ - borrow::Cow, collections::HashSet, pin::Pin, sync::{Arc, Mutex}, @@ -599,7 +598,7 @@ mod tests { self.inner.lock().unwrap().peer_reports.push((who, cost_benefit)); } - fn disconnect_peer(&self, _who: PeerId, _protocol: Cow<'static, str>) { + fn disconnect_peer(&self, _who: PeerId, _protocol: ProtocolName) { unimplemented!(); } @@ -621,7 +620,7 @@ mod tests { fn set_reserved_peers( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); @@ -629,28 +628,23 @@ mod tests { fn add_peers_to_reserved_set( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); } - fn remove_peers_from_reserved_set( - &self, - _protocol: Cow<'static, str>, - _peers: Vec, - ) { - } + fn remove_peers_from_reserved_set(&self, _protocol: ProtocolName, _peers: Vec) {} fn add_to_peers_set( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); } - fn remove_from_peers_set(&self, _protocol: Cow<'static, str>, _peers: Vec) { + fn remove_from_peers_set(&self, _protocol: ProtocolName, _peers: Vec) { unimplemented!(); } @@ -666,19 +660,14 @@ mod tests { } impl NetworkNotification for NoOpNetwork { - fn write_notification( - &self, - _target: PeerId, - _protocol: Cow<'static, str>, - _message: Vec, - ) { + fn write_notification(&self, _target: PeerId, _protocol: ProtocolName, _message: Vec) { unimplemented!(); } fn notification_sender( &self, _target: PeerId, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, ) -> Result, NotificationSenderError> { unimplemented!(); } diff --git a/client/network/common/src/config.rs b/client/network/common/src/config.rs index c2e61424c88e0..8b7e045780d7d 100644 --- a/client/network/common/src/config.rs +++ b/client/network/common/src/config.rs @@ -21,7 +21,9 @@ use libp2p::{multiaddr, Multiaddr, PeerId}; use std::{fmt, str, str::FromStr}; -/// Name of a protocol, transmitted on the wire. Should be unique for each chain. Always UTF-8. +/// Protocol name prefix, transmitted on the wire for legacy protocol names. +/// I.e., `dot` in `/dot/sync/2`. Should be unique for each chain. Always UTF-8. +/// Deprecated in favour of genesis hash & fork ID based protocol names. #[derive(Clone, PartialEq, Eq, Hash)] pub struct ProtocolId(smallvec::SmallVec<[u8; 6]>); diff --git a/client/network/common/src/protocol.rs b/client/network/common/src/protocol.rs index 0fd36cb511112..11edc373a2620 100644 --- a/client/network/common/src/protocol.rs +++ b/client/network/common/src/protocol.rs @@ -16,4 +16,131 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use std::{ + borrow::Borrow, + fmt, + hash::{Hash, Hasher}, + ops::Deref, + sync::Arc, +}; + +use libp2p::core::upgrade; + pub mod event; + +/// The protocol name transmitted on the wire. +#[derive(Debug, Clone)] +pub enum ProtocolName { + /// The protocol name as a static string. + Static(&'static str), + /// The protocol name as a dynamically allocated string. + OnHeap(Arc), +} + +impl From<&'static str> for ProtocolName { + fn from(name: &'static str) -> Self { + Self::Static(name) + } +} + +impl From> for ProtocolName { + fn from(name: Arc) -> Self { + Self::OnHeap(name) + } +} + +impl From for ProtocolName { + fn from(name: String) -> Self { + Self::OnHeap(Arc::from(name)) + } +} + +impl Deref for ProtocolName { + type Target = str; + + fn deref(&self) -> &str { + match self { + Self::Static(name) => name, + Self::OnHeap(name) => &name, + } + } +} + +impl Borrow for ProtocolName { + fn borrow(&self) -> &str { + self + } +} + +impl PartialEq for ProtocolName { + fn eq(&self, other: &Self) -> bool { + (self as &str) == (other as &str) + } +} + +impl Eq for ProtocolName {} + +impl Hash for ProtocolName { + fn hash(&self, state: &mut H) { + (self as &str).hash(state) + } +} + +impl fmt::Display for ProtocolName { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self) + } +} + +impl upgrade::ProtocolName for ProtocolName { + fn protocol_name(&self) -> &[u8] { + (self as &str).as_bytes() + } +} + +#[cfg(test)] +mod tests { + use super::ProtocolName; + use std::{ + borrow::Borrow, + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher}, + }; + + #[test] + fn protocol_name_keys_are_equivalent_to_str_keys() { + const PROTOCOL: &'static str = "/some/protocol/1"; + let static_protocol_name = ProtocolName::from(PROTOCOL); + let on_heap_protocol_name = ProtocolName::from(String::from(PROTOCOL)); + + assert_eq!(>::borrow(&static_protocol_name), PROTOCOL); + assert_eq!(>::borrow(&on_heap_protocol_name), PROTOCOL); + assert_eq!(static_protocol_name, on_heap_protocol_name); + + assert_eq!(hash(static_protocol_name), hash(PROTOCOL)); + assert_eq!(hash(on_heap_protocol_name), hash(PROTOCOL)); + } + + #[test] + fn different_protocol_names_do_not_compare_equal() { + const PROTOCOL1: &'static str = "/some/protocol/1"; + let static_protocol_name1 = ProtocolName::from(PROTOCOL1); + let on_heap_protocol_name1 = ProtocolName::from(String::from(PROTOCOL1)); + + const PROTOCOL2: &'static str = "/some/protocol/2"; + let static_protocol_name2 = ProtocolName::from(PROTOCOL2); + let on_heap_protocol_name2 = ProtocolName::from(String::from(PROTOCOL2)); + + assert_ne!(>::borrow(&static_protocol_name1), PROTOCOL2); + assert_ne!(>::borrow(&on_heap_protocol_name1), PROTOCOL2); + assert_ne!(static_protocol_name1, static_protocol_name2); + assert_ne!(static_protocol_name1, on_heap_protocol_name2); + assert_ne!(on_heap_protocol_name1, on_heap_protocol_name2); + } + + fn hash(x: T) -> u64 { + let mut hasher = DefaultHasher::new(); + x.hash(&mut hasher); + hasher.finish() + } +} diff --git a/client/network/common/src/protocol/event.rs b/client/network/common/src/protocol/event.rs index c6fb4a2faf9f9..3d8c183da495c 100644 --- a/client/network/common/src/protocol/event.rs +++ b/client/network/common/src/protocol/event.rs @@ -19,9 +19,9 @@ //! Network event types. These are are not the part of the protocol, but rather //! events that happen on the network like DHT get/put results received. +use super::ProtocolName; use bytes::Bytes; use libp2p::{core::PeerId, kad::record::Key}; -use std::borrow::Cow; /// Events generated by DHT as a response to get_value and put_value requests. #[derive(Debug, Clone)] @@ -69,13 +69,13 @@ pub enum Event { /// This is always equal to the value of /// `sc_network::config::NonDefaultSetConfig::notifications_protocol` of one of the /// configured sets. - protocol: Cow<'static, str>, + protocol: ProtocolName, /// If the negotiation didn't use the main name of the protocol (the one in /// `notifications_protocol`), then this field contains which name has actually been /// used. /// Always contains a value equal to the value in /// `sc_network::config::NonDefaultSetConfig::fallback_names`. - negotiated_fallback: Option>, + negotiated_fallback: Option, /// Role of the remote. role: ObservedRole, }, @@ -86,7 +86,7 @@ pub enum Event { /// Node we closed the substream with. remote: PeerId, /// The concerned protocol. Each protocol uses a different substream. - protocol: Cow<'static, str>, + protocol: ProtocolName, }, /// Received one or more messages from the given node using the given protocol. @@ -94,7 +94,7 @@ pub enum Event { /// Node we received the message from. remote: PeerId, /// Concerned protocol and associated message. - messages: Vec<(Cow<'static, str>, Bytes)>, + messages: Vec<(ProtocolName, Bytes)>, }, } diff --git a/client/network/common/src/request_responses.rs b/client/network/common/src/request_responses.rs index a216c9c2d254d..1a8d48e11be53 100644 --- a/client/network/common/src/request_responses.rs +++ b/client/network/common/src/request_responses.rs @@ -18,19 +18,20 @@ //! Collection of generic data structures for request-response protocols. +use crate::protocol::ProtocolName; use futures::channel::{mpsc, oneshot}; use libp2p::{request_response::OutboundFailure, PeerId}; use sc_peerset::ReputationChange; -use std::{borrow::Cow, time::Duration}; +use std::time::Duration; /// Configuration for a single request-response protocol. #[derive(Debug, Clone)] pub struct ProtocolConfig { /// Name of the protocol on the wire. Should be something like `/foo/bar`. - pub name: Cow<'static, str>, + pub name: ProtocolName, /// Fallback on the wire protocol names to support. - pub fallback_names: Vec>, + pub fallback_names: Vec, /// Maximum allowed size, in bytes, of a request. /// diff --git a/client/network/common/src/service.rs b/client/network/common/src/service.rs index 9544cddf013cf..88583832e4c38 100644 --- a/client/network/common/src/service.rs +++ b/client/network/common/src/service.rs @@ -20,7 +20,7 @@ use crate::{ config::MultiaddrWithPeerId, - protocol::event::Event, + protocol::{event::Event, ProtocolName}, request_responses::{IfDisconnected, RequestFailure}, sync::{warp::WarpSyncProgress, StateDownloadProgress, SyncState}, }; @@ -30,7 +30,7 @@ use libp2p::{Multiaddr, PeerId}; use sc_peerset::ReputationChange; pub use signature::Signature; use sp_runtime::traits::{Block as BlockT, NumberFor}; -use std::{borrow::Cow, collections::HashSet, future::Future, pin::Pin, sync::Arc}; +use std::{collections::HashSet, future::Future, pin::Pin, sync::Arc}; mod signature; @@ -171,7 +171,7 @@ pub trait NetworkPeers { /// See also [`NetworkPeers::remove_from_peers_set`], which has the same effect but also /// prevents the local node from re-establishing an outgoing substream to this peer until it /// is added again. - fn disconnect_peer(&self, who: PeerId, protocol: Cow<'static, str>); + fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName); /// Connect to unreserved peers and allow unreserved peers to connect for syncing purposes. fn accept_unreserved_peers(&self); @@ -207,7 +207,7 @@ pub trait NetworkPeers { /// invalid peer ID (which includes the local peer ID). fn set_reserved_peers( &self, - protocol: Cow<'static, str>, + protocol: ProtocolName, peers: HashSet, ) -> Result<(), String>; @@ -220,12 +220,12 @@ pub trait NetworkPeers { /// invalid peer ID (which includes the local peer ID). fn add_peers_to_reserved_set( &self, - protocol: Cow<'static, str>, + protocol: ProtocolName, peers: HashSet, ) -> Result<(), String>; /// Remove peers from a peer set. - fn remove_peers_from_reserved_set(&self, protocol: Cow<'static, str>, peers: Vec); + fn remove_peers_from_reserved_set(&self, protocol: ProtocolName, peers: Vec); /// Add a peer to a set of peers. /// @@ -238,14 +238,14 @@ pub trait NetworkPeers { /// invalid peer ID (which includes the local peer ID). fn add_to_peers_set( &self, - protocol: Cow<'static, str>, + protocol: ProtocolName, peers: HashSet, ) -> Result<(), String>; /// Remove peers from a peer set. /// /// If we currently have an open substream with this peer, it will soon be closed. - fn remove_from_peers_set(&self, protocol: Cow<'static, str>, peers: Vec); + fn remove_from_peers_set(&self, protocol: ProtocolName, peers: Vec); /// Returns the number of peers in the sync peer set we're connected to. fn sync_num_connected(&self) -> usize; @@ -273,7 +273,7 @@ where T::report_peer(self, who, cost_benefit) } - fn disconnect_peer(&self, who: PeerId, protocol: Cow<'static, str>) { + fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { T::disconnect_peer(self, who, protocol) } @@ -295,7 +295,7 @@ where fn set_reserved_peers( &self, - protocol: Cow<'static, str>, + protocol: ProtocolName, peers: HashSet, ) -> Result<(), String> { T::set_reserved_peers(self, protocol, peers) @@ -303,25 +303,25 @@ where fn add_peers_to_reserved_set( &self, - protocol: Cow<'static, str>, + protocol: ProtocolName, peers: HashSet, ) -> Result<(), String> { T::add_peers_to_reserved_set(self, protocol, peers) } - fn remove_peers_from_reserved_set(&self, protocol: Cow<'static, str>, peers: Vec) { + fn remove_peers_from_reserved_set(&self, protocol: ProtocolName, peers: Vec) { T::remove_peers_from_reserved_set(self, protocol, peers) } fn add_to_peers_set( &self, - protocol: Cow<'static, str>, + protocol: ProtocolName, peers: HashSet, ) -> Result<(), String> { T::add_to_peers_set(self, protocol, peers) } - fn remove_from_peers_set(&self, protocol: Cow<'static, str>, peers: Vec) { + fn remove_from_peers_set(&self, protocol: ProtocolName, peers: Vec) { T::remove_from_peers_set(self, protocol, peers) } @@ -431,7 +431,7 @@ pub trait NetworkNotification { /// /// The protocol must have been registered with /// `crate::config::NetworkConfiguration::notifications_protocols`. - fn write_notification(&self, target: PeerId, protocol: Cow<'static, str>, message: Vec); + fn write_notification(&self, target: PeerId, protocol: ProtocolName, message: Vec); /// Obtains a [`NotificationSender`] for a connected peer, if it exists. /// @@ -502,7 +502,7 @@ pub trait NetworkNotification { fn notification_sender( &self, target: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, ) -> Result, NotificationSenderError>; } @@ -511,14 +511,14 @@ where T: ?Sized, T: NetworkNotification, { - fn write_notification(&self, target: PeerId, protocol: Cow<'static, str>, message: Vec) { + fn write_notification(&self, target: PeerId, protocol: ProtocolName, message: Vec) { T::write_notification(self, target, protocol, message) } fn notification_sender( &self, target: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, ) -> Result, NotificationSenderError> { T::notification_sender(self, target, protocol) } @@ -547,7 +547,7 @@ pub trait NetworkRequest { async fn request( &self, target: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, request: Vec, connect: IfDisconnected, ) -> Result, RequestFailure>; @@ -565,7 +565,7 @@ pub trait NetworkRequest { fn start_request( &self, target: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, request: Vec, tx: oneshot::Sender, RequestFailure>>, connect: IfDisconnected, @@ -581,7 +581,7 @@ where fn request<'life0, 'async_trait>( &'life0 self, target: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, request: Vec, connect: IfDisconnected, ) -> Pin, RequestFailure>> + Send + 'async_trait>> @@ -595,7 +595,7 @@ where fn start_request( &self, target: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, request: Vec, tx: oneshot::Sender, RequestFailure>>, connect: IfDisconnected, diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 4177c2452c7f7..24df47db6803f 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -42,7 +42,10 @@ use log::debug; use sc_consensus::import_queue::{IncomingBlock, Origin}; use sc_network_common::{ config::ProtocolId, - protocol::event::{DhtEvent, ObservedRole}, + protocol::{ + event::{DhtEvent, ObservedRole}, + ProtocolName, + }, request_responses::{IfDisconnected, ProtocolConfig, RequestFailure}, }; use sc_peerset::PeersetHandle; @@ -53,7 +56,6 @@ use sp_runtime::{ Justifications, }; use std::{ - borrow::Cow, collections::{HashSet, VecDeque}, iter, task::{Context, Poll}, @@ -117,7 +119,7 @@ pub enum BehaviourOut { /// Peer which sent us a request. peer: PeerId, /// Protocol name of the request. - protocol: Cow<'static, str>, + protocol: ProtocolName, /// If `Ok`, contains the time elapsed between when we received the request and when we /// sent back the response. If `Err`, the error that happened. result: Result, @@ -130,7 +132,7 @@ pub enum BehaviourOut { /// Peer that we send a request to. peer: PeerId, /// Name of the protocol in question. - protocol: Cow<'static, str>, + protocol: ProtocolName, /// Duration the request took. duration: Duration, /// Result of the request. @@ -144,12 +146,12 @@ pub enum BehaviourOut { /// Node we opened the substream with. remote: PeerId, /// The concerned protocol. Each protocol uses a different substream. - protocol: Cow<'static, str>, + protocol: ProtocolName, /// If the negotiation didn't use the main name of the protocol (the one in /// `notifications_protocol`), then this field contains which name has actually been /// used. /// See also [`crate::Event::NotificationStreamOpened`]. - negotiated_fallback: Option>, + negotiated_fallback: Option, /// Object that permits sending notifications to the peer. notifications_sink: NotificationsSink, /// Role of the remote. @@ -165,7 +167,7 @@ pub enum BehaviourOut { /// Id of the peer we are connected to. remote: PeerId, /// The concerned protocol. Each protocol uses a different substream. - protocol: Cow<'static, str>, + protocol: ProtocolName, /// Replacement for the previous [`NotificationsSink`]. notifications_sink: NotificationsSink, }, @@ -176,7 +178,7 @@ pub enum BehaviourOut { /// Node we closed the substream with. remote: PeerId, /// The concerned protocol. Each protocol uses a different substream. - protocol: Cow<'static, str>, + protocol: ProtocolName, }, /// Received one or more messages from the given node using the given protocol. @@ -184,7 +186,7 @@ pub enum BehaviourOut { /// Node we received the message from. remote: PeerId, /// Concerned protocol and associated message. - messages: Vec<(Cow<'static, str>, Bytes)>, + messages: Vec<(ProtocolName, Bytes)>, }, /// Now connected to a new peer for syncing purposes. diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 521aa42827563..3fe95deb0c1ed 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -41,10 +41,9 @@ use libp2p::{ }; use prometheus_endpoint::Registry; use sc_consensus::ImportQueue; -use sc_network_common::{config::MultiaddrWithPeerId, sync::ChainSync}; +use sc_network_common::{config::MultiaddrWithPeerId, protocol::ProtocolName, sync::ChainSync}; use sp_runtime::traits::Block as BlockT; use std::{ - borrow::Cow, collections::HashMap, error::Error, fs, @@ -431,14 +430,14 @@ pub struct NonDefaultSetConfig { /// /// > **Note**: This field isn't present for the default set, as this is handled internally /// > by the networking code. - pub notifications_protocol: Cow<'static, str>, + pub notifications_protocol: ProtocolName, /// If the remote reports that it doesn't support the protocol indicated in the /// `notifications_protocol` field, then each of these fallback names will be tried one by /// one. /// /// If a fallback is used, it will be reported in /// [`crate::Event::NotificationStreamOpened::negotiated_fallback`]. - pub fallback_names: Vec>, + pub fallback_names: Vec, /// Maximum allowed size of single notifications. pub max_notification_size: u64, /// Base configuration. @@ -447,7 +446,7 @@ pub struct NonDefaultSetConfig { impl NonDefaultSetConfig { /// Creates a new [`NonDefaultSetConfig`]. Zero slots and accepts only reserved nodes. - pub fn new(notifications_protocol: Cow<'static, str>, max_notification_size: u64) -> Self { + pub fn new(notifications_protocol: ProtocolName, max_notification_size: u64) -> Self { Self { notifications_protocol, max_notification_size, @@ -476,7 +475,7 @@ impl NonDefaultSetConfig { /// Add a list of protocol names used for backward compatibility. /// /// See the explanations in [`NonDefaultSetConfig::fallback_names`]. - pub fn add_fallback_names(&mut self, fallback_names: Vec>) { + pub fn add_fallback_names(&mut self, fallback_names: Vec) { self.fallback_names.extend(fallback_names); } } diff --git a/client/network/src/error.rs b/client/network/src/error.rs index 716235193a80f..b4287ffbd55db 100644 --- a/client/network/src/error.rs +++ b/client/network/src/error.rs @@ -20,8 +20,9 @@ use crate::config::TransportConfig; use libp2p::{Multiaddr, PeerId}; +use sc_network_common::protocol::ProtocolName; -use std::{borrow::Cow, fmt}; +use std::fmt; /// Result type alias for the network. pub type Result = std::result::Result; @@ -65,7 +66,7 @@ pub enum Error { #[error("Request-response protocol registered multiple times: {protocol}")] DuplicateRequestResponseProtocol { /// Name of the protocol registered multiple times. - protocol: Cow<'static, str>, + protocol: ProtocolName, }, } diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index b1d70c28289bd..35a91e77da524 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -264,7 +264,10 @@ pub mod transactions; pub use libp2p::{multiaddr, Multiaddr, PeerId}; pub use protocol::PeerInfo; pub use sc_network_common::{ - protocol::event::{DhtEvent, Event, ObservedRole}, + protocol::{ + event::{DhtEvent, Event, ObservedRole}, + ProtocolName, + }, request_responses::{IfDisconnected, RequestFailure}, service::{ KademliaKey, NetworkBlock, NetworkDHTProvider, NetworkRequest, NetworkSigner, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 64794538999b0..9bcf363cd0692 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -44,6 +44,7 @@ use sc_client_api::HeaderBackend; use sc_consensus::import_queue::{BlockImportError, BlockImportStatus, IncomingBlock, Origin}; use sc_network_common::{ config::ProtocolId, + protocol::ProtocolName, request_responses::RequestFailure, sync::{ message::{ @@ -63,7 +64,6 @@ use sp_runtime::{ Justifications, }; use std::{ - borrow::Cow, collections::{HashMap, HashSet, VecDeque}, io, iter, num::NonZeroUsize, @@ -190,7 +190,7 @@ pub struct Protocol { /// Handles opening the unique substream and sending and receiving raw messages. behaviour: Notifications, /// List of notifications protocols that have been registered. - notification_protocols: Vec>, + notification_protocols: Vec, /// If we receive a new "substream open" event that contains an invalid handshake, we ask the /// inner layer to force-close the substream. Force-closing the substream will generate a /// "substream closed" event. This is a problem: since we can't propagate the "substream open" @@ -460,7 +460,7 @@ where } /// Disconnects the given peer if we are connected to it. - pub fn disconnect_peer(&mut self, peer_id: &PeerId, protocol_name: &str) { + pub fn disconnect_peer(&mut self, peer_id: &PeerId, protocol_name: ProtocolName) { if let Some(position) = self.notification_protocols.iter().position(|p| *p == protocol_name) { self.behaviour.disconnect_peer( @@ -1085,7 +1085,7 @@ where } /// Sets the list of reserved peers for the given protocol/peerset. - pub fn set_reserved_peerset_peers(&self, protocol: Cow<'static, str>, peers: HashSet) { + pub fn set_reserved_peerset_peers(&self, protocol: ProtocolName, peers: HashSet) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { self.peerset_handle .set_reserved_peers(sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), peers); @@ -1099,7 +1099,7 @@ where } /// Removes a `PeerId` from the list of reserved peers. - pub fn remove_set_reserved_peer(&self, protocol: Cow<'static, str>, peer: PeerId) { + pub fn remove_set_reserved_peer(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { self.peerset_handle.remove_reserved_peer( sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), @@ -1115,7 +1115,7 @@ where } /// Adds a `PeerId` to the list of reserved peers. - pub fn add_set_reserved_peer(&self, protocol: Cow<'static, str>, peer: PeerId) { + pub fn add_set_reserved_peer(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { self.peerset_handle .add_reserved_peer(sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), peer); @@ -1138,7 +1138,7 @@ where } /// Add a peer to a peers set. - pub fn add_to_peers_set(&self, protocol: Cow<'static, str>, peer: PeerId) { + pub fn add_to_peers_set(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { self.peerset_handle .add_to_peers_set(sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), peer); @@ -1152,7 +1152,7 @@ where } /// Remove a peer from a peers set. - pub fn remove_from_peers_set(&self, protocol: Cow<'static, str>, peer: PeerId) { + pub fn remove_from_peers_set(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { self.peerset_handle.remove_from_peers_set( sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), @@ -1259,27 +1259,27 @@ pub enum CustomMessageOutcome { /// Notification protocols have been opened with a remote. NotificationStreamOpened { remote: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, /// See [`crate::Event::NotificationStreamOpened::negotiated_fallback`]. - negotiated_fallback: Option>, + negotiated_fallback: Option, roles: Roles, notifications_sink: NotificationsSink, }, /// The [`NotificationsSink`] of some notification protocols need an update. NotificationStreamReplaced { remote: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, notifications_sink: NotificationsSink, }, /// Notification protocols have been closed with a remote. NotificationStreamClosed { remote: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, }, /// Messages have been received on one or more notifications protocols. NotificationsReceived { remote: PeerId, - messages: Vec<(Cow<'static, str>, Bytes)>, + messages: Vec<(ProtocolName, Bytes)>, }, /// A new block request must be emitted. BlockRequest { diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 1f872ec857e79..04f6fe445ac63 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -33,15 +33,14 @@ use libp2p::{ use log::{error, trace, warn}; use parking_lot::RwLock; use rand::distributions::{Distribution as _, Uniform}; +use sc_network_common::protocol::ProtocolName; use sc_peerset::DropReason; use smallvec::SmallVec; use std::{ - borrow::Cow, cmp, collections::{hash_map::Entry, VecDeque}, mem, pin::Pin, - str, sync::Arc, task::{Context, Poll}, time::{Duration, Instant}, @@ -140,9 +139,9 @@ pub struct Notifications { #[derive(Debug, Clone)] pub struct ProtocolConfig { /// Name of the protocol. - pub name: Cow<'static, str>, + pub name: ProtocolName, /// Names of the protocol to use if the main one isn't available. - pub fallback_names: Vec>, + pub fallback_names: Vec, /// Handshake of the protocol. pub handshake: Vec, /// Maximum allowed size for a notification. @@ -309,7 +308,7 @@ pub enum NotificationsOut { set_id: sc_peerset::SetId, /// If `Some`, a fallback protocol name has been used rather the main protocol name. /// Always matches one of the fallback names passed at initialization. - negotiated_fallback: Option>, + negotiated_fallback: Option, /// Handshake that was sent to us. /// This is normally a "Status" message, but this is out of the concern of this code. received_handshake: Vec, diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index c1602319d0ac4..ea09cb76edce1 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -80,12 +80,11 @@ use libp2p::{ }; use log::error; use parking_lot::{Mutex, RwLock}; +use sc_network_common::protocol::ProtocolName; use std::{ - borrow::Cow, collections::VecDeque, mem, pin::Pin, - str, sync::Arc, task::{Context, Poll}, time::{Duration, Instant}, @@ -146,9 +145,9 @@ pub struct NotifsHandler { #[derive(Debug, Clone)] pub struct ProtocolConfig { /// Name of the protocol. - pub name: Cow<'static, str>, + pub name: ProtocolName, /// Names of the protocol to use if the main one isn't available. - pub fallback_names: Vec>, + pub fallback_names: Vec, /// Handshake of the protocol. The `RwLock` is locked every time a new substream is opened. pub handshake: Arc>>, /// Maximum allowed size for a notification. @@ -297,7 +296,7 @@ pub enum NotifsHandlerOut { /// Index of the protocol in the list of protocols passed at initialization. protocol_index: usize, /// Name of the protocol that was actually negotiated, if the default one wasn't available. - negotiated_fallback: Option>, + negotiated_fallback: Option, /// The endpoint of the connection that is open for custom protocols. endpoint: ConnectedPoint, /// Handshake that was sent to us. diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 3fbb59d399a0e..56cfefd75d53d 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -39,8 +39,8 @@ use bytes::BytesMut; use futures::prelude::*; use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use log::{error, warn}; +use sc_network_common::protocol::ProtocolName; use std::{ - borrow::Cow, convert::Infallible, io, mem, pin::Pin, @@ -58,7 +58,7 @@ const MAX_HANDSHAKE_SIZE: usize = 1024; pub struct NotificationsIn { /// Protocol name to use when negotiating the substream. /// The first one is the main name, while the other ones are fall backs. - protocol_names: Vec>, + protocol_names: Vec, /// Maximum allowed size for a single notification. max_notification_size: u64, } @@ -69,7 +69,7 @@ pub struct NotificationsIn { pub struct NotificationsOut { /// Protocol name to use when negotiating the substream. /// The first one is the main name, while the other ones are fall backs. - protocol_names: Vec>, + protocol_names: Vec, /// Message to send when we start the handshake. initial_message: Vec, /// Maximum allowed size for a single notification. @@ -114,8 +114,8 @@ pub struct NotificationsOutSubstream { impl NotificationsIn { /// Builds a new potential upgrade. pub fn new( - main_protocol_name: impl Into>, - fallback_names: Vec>, + main_protocol_name: impl Into, + fallback_names: Vec, max_notification_size: u64, ) -> Self { let mut protocol_names = fallback_names; @@ -126,16 +126,11 @@ impl NotificationsIn { } impl UpgradeInfo for NotificationsIn { - type Info = StringProtocolName; + type Info = ProtocolName; type InfoIter = vec::IntoIter; fn protocol_info(&self) -> Self::InfoIter { - self.protocol_names - .iter() - .cloned() - .map(StringProtocolName) - .collect::>() - .into_iter() + self.protocol_names.clone().into_iter() } } @@ -172,10 +167,10 @@ where Ok(NotificationsInOpen { handshake, - negotiated_fallback: if negotiated_name.0 == self.protocol_names[0] { + negotiated_fallback: if negotiated_name == self.protocol_names[0] { None } else { - Some(negotiated_name.0) + Some(negotiated_name) }, substream, }) @@ -189,7 +184,7 @@ pub struct NotificationsInOpen { pub handshake: Vec, /// If the negotiated name is not the "main" protocol name but a fallback, contains the /// name of the negotiated fallback. - pub negotiated_fallback: Option>, + pub negotiated_fallback: Option, /// Implementation of `Stream` that allows receives messages from the substream. pub substream: NotificationsInSubstream, } @@ -334,8 +329,8 @@ where impl NotificationsOut { /// Builds a new potential upgrade. pub fn new( - main_protocol_name: impl Into>, - fallback_names: Vec>, + main_protocol_name: impl Into, + fallback_names: Vec, initial_message: impl Into>, max_notification_size: u64, ) -> Self { @@ -351,27 +346,12 @@ impl NotificationsOut { } } -/// Implementation of the `ProtocolName` trait, where the protocol name is a string. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StringProtocolName(Cow<'static, str>); - -impl upgrade::ProtocolName for StringProtocolName { - fn protocol_name(&self) -> &[u8] { - self.0.as_bytes() - } -} - impl UpgradeInfo for NotificationsOut { - type Info = StringProtocolName; + type Info = ProtocolName; type InfoIter = vec::IntoIter; fn protocol_info(&self) -> Self::InfoIter { - self.protocol_names - .iter() - .cloned() - .map(StringProtocolName) - .collect::>() - .into_iter() + self.protocol_names.clone().into_iter() } } @@ -406,10 +386,10 @@ where Ok(NotificationsOutOpen { handshake, - negotiated_fallback: if negotiated_name.0 == self.protocol_names[0] { + negotiated_fallback: if negotiated_name == self.protocol_names[0] { None } else { - Some(negotiated_name.0) + Some(negotiated_name) }, substream: NotificationsOutSubstream { socket: Framed::new(socket, codec) }, }) @@ -423,7 +403,7 @@ pub struct NotificationsOutOpen { pub handshake: Vec, /// If the negotiated name is not the "main" protocol name but a fallback, contains the /// name of the negotiated fallback. - pub negotiated_fallback: Option>, + pub negotiated_fallback: Option, /// Implementation of `Sink` that allows sending messages on the substream. pub substream: NotificationsOutSubstream, } @@ -505,11 +485,10 @@ mod tests { use async_std::net::{TcpListener, TcpStream}; use futures::{channel::oneshot, prelude::*}; use libp2p::core::upgrade; - use std::borrow::Cow; #[test] fn basic_works() { - const PROTO_NAME: Cow<'static, str> = Cow::Borrowed("/test/proto/1"); + const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); let client = async_std::task::spawn(async move { @@ -552,7 +531,7 @@ mod tests { fn empty_handshake() { // Check that everything still works when the handshake messages are empty. - const PROTO_NAME: Cow<'static, str> = Cow::Borrowed("/test/proto/1"); + const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); let client = async_std::task::spawn(async move { @@ -593,7 +572,7 @@ mod tests { #[test] fn refused() { - const PROTO_NAME: Cow<'static, str> = Cow::Borrowed("/test/proto/1"); + const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); let client = async_std::task::spawn(async move { @@ -634,7 +613,7 @@ mod tests { #[test] fn large_initial_message_refused() { - const PROTO_NAME: Cow<'static, str> = Cow::Borrowed("/test/proto/1"); + const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); let client = async_std::task::spawn(async move { @@ -672,7 +651,7 @@ mod tests { #[test] fn large_handshake_refused() { - const PROTO_NAME: Cow<'static, str> = Cow::Borrowed("/test/proto/1"); + const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); let client = async_std::task::spawn(async move { diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 9eab85a4c1ce1..d49cbd8051341 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -50,11 +50,13 @@ use libp2p::{ NetworkBehaviourAction, PollParameters, }, }; -use sc_network_common::request_responses::{ - IfDisconnected, IncomingRequest, OutgoingResponse, ProtocolConfig, RequestFailure, +use sc_network_common::{ + protocol::ProtocolName, + request_responses::{ + IfDisconnected, IncomingRequest, OutgoingResponse, ProtocolConfig, RequestFailure, + }, }; use std::{ - borrow::Cow, collections::{hash_map::Entry, HashMap}, io, iter, pin::Pin, @@ -75,7 +77,7 @@ pub enum Event { /// Peer which has emitted the request. peer: PeerId, /// Name of the protocol in question. - protocol: Cow<'static, str>, + protocol: ProtocolName, /// Whether handling the request was successful or unsuccessful. /// /// When successful contains the time elapsed between when we received the request and when @@ -91,7 +93,7 @@ pub enum Event { /// Peer that we send a request to. peer: PeerId, /// Name of the protocol in question. - protocol: Cow<'static, str>, + protocol: ProtocolName, /// Duration the request took. duration: Duration, /// Result of the request. @@ -110,12 +112,12 @@ pub enum Event { /// [`ProtocolRequestId`]s. #[derive(Debug, Clone, PartialEq, Eq, Hash)] struct ProtocolRequestId { - protocol: Cow<'static, str>, + protocol: ProtocolName, request_id: RequestId, } -impl From<(Cow<'static, str>, RequestId)> for ProtocolRequestId { - fn from((protocol, request_id): (Cow<'static, str>, RequestId)) -> Self { +impl From<(ProtocolName, RequestId)> for ProtocolRequestId { + fn from((protocol, request_id): (ProtocolName, RequestId)) -> Self { Self { protocol, request_id } } } @@ -126,7 +128,7 @@ pub struct RequestResponsesBehaviour { /// Contains the underlying libp2p `RequestResponse` behaviour, plus an optional /// "response builder" used to build responses for incoming requests. protocols: HashMap< - Cow<'static, str>, + ProtocolName, (RequestResponse, Option>), >, @@ -162,7 +164,7 @@ struct MessageRequest { request_id: RequestId, request: Vec, channel: ResponseChannel, ()>>, - protocol: String, + protocol: ProtocolName, resp_builder: Option>, // Once we get incoming request we save all params, create an async call to Peerset // to get the reputation of the peer. @@ -173,7 +175,7 @@ struct MessageRequest { struct RequestProcessingOutcome { peer: PeerId, request_id: RequestId, - protocol: Cow<'static, str>, + protocol: ProtocolName, inner_channel: ResponseChannel, ()>>, response: OutgoingResponse, } @@ -495,7 +497,6 @@ impl NetworkBehaviour for RequestResponsesBehaviour { debug_assert!(false, "Received message on outbound-only protocol."); } - let protocol = Cow::from(protocol); self.pending_responses.push(Box::pin(async move { // The `tx` created above can be dropped if we are not capable of // processing this request, which is reflected as a @@ -618,7 +619,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { request_id, request, channel, - protocol: protocol.to_string(), + protocol: protocol.clone(), resp_builder: resp_builder.clone(), get_peer_reputation, }); @@ -766,7 +767,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { pub enum RegisterError { /// A protocol has been specified multiple times. #[error("{0}")] - DuplicateProtocol(Cow<'static, str>), + DuplicateProtocol(ProtocolName), } /// Error when processing a request sent by a remote. diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 7a196da25260a..4610b025dde0d 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -61,7 +61,10 @@ use parking_lot::Mutex; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; use sc_network_common::{ config::MultiaddrWithPeerId, - protocol::event::{DhtEvent, Event}, + protocol::{ + event::{DhtEvent, Event}, + ProtocolName, + }, request_responses::{IfDisconnected, RequestFailure}, service::{ NetworkDHTProvider, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkSigner, @@ -76,7 +79,6 @@ use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnbound use sp_blockchain::HeaderBackend; use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::{ - borrow::Cow, cmp, collections::{HashMap, HashSet}, fs, iter, @@ -122,7 +124,7 @@ pub struct NetworkService { to_worker: TracingUnboundedSender>, /// For each peer and protocol combination, an object that allows sending notifications to /// that peer. Updated by the [`NetworkWorker`]. - peers_notifications_sinks: Arc), NotificationsSink>>>, + peers_notifications_sinks: Arc>>, /// Field extracted from the [`Metrics`] struct and necessary to report the /// notifications-related metrics. notifications_sizes_metric: Option, @@ -890,7 +892,7 @@ where self.peerset.report_peer(who, cost_benefit); } - fn disconnect_peer(&self, who: PeerId, protocol: Cow<'static, str>) { + fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::DisconnectPeer(who, protocol)); } @@ -921,7 +923,7 @@ where fn set_reserved_peers( &self, - protocol: Cow<'static, str>, + protocol: ProtocolName, peers: HashSet, ) -> Result<(), String> { let peers_addrs = self.split_multiaddr_and_peer_id(peers)?; @@ -952,7 +954,7 @@ where fn add_peers_to_reserved_set( &self, - protocol: Cow<'static, str>, + protocol: ProtocolName, peers: HashSet, ) -> Result<(), String> { let peers = self.split_multiaddr_and_peer_id(peers)?; @@ -976,7 +978,7 @@ where Ok(()) } - fn remove_peers_from_reserved_set(&self, protocol: Cow<'static, str>, peers: Vec) { + fn remove_peers_from_reserved_set(&self, protocol: ProtocolName, peers: Vec) { for peer_id in peers.into_iter() { let _ = self .to_worker @@ -986,7 +988,7 @@ where fn add_to_peers_set( &self, - protocol: Cow<'static, str>, + protocol: ProtocolName, peers: HashSet, ) -> Result<(), String> { let peers = self.split_multiaddr_and_peer_id(peers)?; @@ -1010,7 +1012,7 @@ where Ok(()) } - fn remove_from_peers_set(&self, protocol: Cow<'static, str>, peers: Vec) { + fn remove_from_peers_set(&self, protocol: ProtocolName, peers: Vec) { for peer_id in peers.into_iter() { let _ = self .to_worker @@ -1040,7 +1042,7 @@ where B: BlockT + 'static, H: ExHashT, { - fn write_notification(&self, target: PeerId, protocol: Cow<'static, str>, message: Vec) { + fn write_notification(&self, target: PeerId, protocol: ProtocolName, message: Vec) { // We clone the `NotificationsSink` in order to be able to unlock the network-wide // `peers_notifications_sinks` mutex as soon as possible. let sink = { @@ -1077,7 +1079,7 @@ where fn notification_sender( &self, target: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, ) -> Result, NotificationSenderError> { // We clone the `NotificationsSink` in order to be able to unlock the network-wide // `peers_notifications_sinks` mutex as soon as possible. @@ -1108,7 +1110,7 @@ where async fn request( &self, target: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, request: Vec, connect: IfDisconnected, ) -> Result, RequestFailure> { @@ -1128,7 +1130,7 @@ where fn start_request( &self, target: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, request: Vec, tx: oneshot::Sender, RequestFailure>>, connect: IfDisconnected, @@ -1179,7 +1181,7 @@ pub struct NotificationSender { sink: NotificationsSink, /// Name of the protocol on the wire. - protocol_name: Cow<'static, str>, + protocol_name: ProtocolName, /// Field extracted from the [`Metrics`] struct and necessary to report the /// notifications-related metrics. @@ -1212,7 +1214,7 @@ pub struct NotificationSenderReady<'a> { peer_id: &'a PeerId, /// Name of the protocol on the wire. - protocol_name: &'a Cow<'static, str>, + protocol_name: &'a ProtocolName, /// Field extracted from the [`Metrics`] struct and necessary to report the /// notifications-related metrics. @@ -1256,16 +1258,16 @@ enum ServiceToWorkerMsg { AddReserved(PeerId), RemoveReserved(PeerId), SetReserved(HashSet), - SetPeersetReserved(Cow<'static, str>, HashSet), - AddSetReserved(Cow<'static, str>, PeerId), - RemoveSetReserved(Cow<'static, str>, PeerId), - AddToPeersSet(Cow<'static, str>, PeerId), - RemoveFromPeersSet(Cow<'static, str>, PeerId), + SetPeersetReserved(ProtocolName, HashSet), + AddSetReserved(ProtocolName, PeerId), + RemoveSetReserved(ProtocolName, PeerId), + AddToPeersSet(ProtocolName, PeerId), + RemoveFromPeersSet(ProtocolName, PeerId), SyncFork(Vec, B::Hash, NumberFor), EventStream(out_events::Sender), Request { target: PeerId, - protocol: Cow<'static, str>, + protocol: ProtocolName, request: Vec, pending_response: oneshot::Sender, RequestFailure>>, connect: IfDisconnected, @@ -1276,7 +1278,7 @@ enum ServiceToWorkerMsg { NetworkState { pending_response: oneshot::Sender>, }, - DisconnectPeer(PeerId, Cow<'static, str>), + DisconnectPeer(PeerId, ProtocolName), NewBestBlockImported(B::Hash, NumberFor), } @@ -1312,7 +1314,7 @@ where boot_node_ids: Arc>, /// For each peer and protocol combination, an object that allows sending notifications to /// that peer. Shared with the [`NetworkService`]. - peers_notifications_sinks: Arc), NotificationsSink>>>, + peers_notifications_sinks: Arc>>, /// Controller for the handler of incoming and outgoing transactions. tx_handler_controller: transactions::TransactionsHandlerController, } @@ -1456,7 +1458,7 @@ where .network_service .behaviour_mut() .user_protocol_mut() - .disconnect_peer(&who, &protocol_name), + .disconnect_peer(&who, protocol_name), ServiceToWorkerMsg::NewBestBlockImported(hash, number) => this .network_service .behaviour_mut() diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index e0d8798aef91e..8770e14bf5338 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -32,7 +32,7 @@ use sc_network_sync::{ }; use sp_consensus::block_validation::DefaultBlockAnnounceValidator; use sp_runtime::traits::{Block as BlockT, Header as _}; -use std::{borrow::Cow, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; type TestNetworkService = NetworkService< @@ -165,7 +165,7 @@ fn build_test_full_node( (service, event_stream) } -const PROTOCOL_NAME: Cow<'static, str> = Cow::Borrowed("/foo"); +const PROTOCOL_NAME: &str = "/foo"; /// Builds two nodes and their associated events stream. /// The nodes are connected together and have the `PROTOCOL_NAME` protocol registered. @@ -179,7 +179,7 @@ fn build_nodes_one_proto() -> ( let (node1, events_stream1) = build_test_full_node(config::NetworkConfiguration { extra_sets: vec![config::NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME, + notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, set_config: Default::default(), @@ -191,7 +191,7 @@ fn build_nodes_one_proto() -> ( let (node2, events_stream2) = build_test_full_node(config::NetworkConfiguration { extra_sets: vec![config::NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME, + notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, set_config: config::SetConfig { @@ -219,10 +219,18 @@ fn notifications_state_consistent() { // Write some initial notifications that shouldn't get through. for _ in 0..(rand::random::() % 5) { - node1.write_notification(node2.local_peer_id(), PROTOCOL_NAME, b"hello world".to_vec()); + node1.write_notification( + node2.local_peer_id(), + PROTOCOL_NAME.into(), + b"hello world".to_vec(), + ); } for _ in 0..(rand::random::() % 5) { - node2.write_notification(node1.local_peer_id(), PROTOCOL_NAME, b"hello world".to_vec()); + node2.write_notification( + node1.local_peer_id(), + PROTOCOL_NAME.into(), + b"hello world".to_vec(), + ); } async_std::task::block_on(async move { @@ -247,24 +255,24 @@ fn notifications_state_consistent() { if rand::random::() % 5 >= 3 { node1.write_notification( node2.local_peer_id(), - PROTOCOL_NAME, + PROTOCOL_NAME.into(), b"hello world".to_vec(), ); } if rand::random::() % 5 >= 3 { node2.write_notification( node1.local_peer_id(), - PROTOCOL_NAME, + PROTOCOL_NAME.into(), b"hello world".to_vec(), ); } // Also randomly disconnect the two nodes from time to time. if rand::random::() % 20 == 0 { - node1.disconnect_peer(node2.local_peer_id(), PROTOCOL_NAME); + node1.disconnect_peer(node2.local_peer_id(), PROTOCOL_NAME.into()); } if rand::random::() % 20 == 0 { - node2.disconnect_peer(node1.local_peer_id(), PROTOCOL_NAME); + node2.disconnect_peer(node1.local_peer_id(), PROTOCOL_NAME.into()); } // Grab next event from either `events_stream1` or `events_stream2`. @@ -288,7 +296,7 @@ fn notifications_state_consistent() { future::Either::Left(Event::NotificationStreamOpened { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME { + if protocol == PROTOCOL_NAME.into() { something_happened = true; assert!(!node1_to_node2_open); node1_to_node2_open = true; @@ -297,7 +305,7 @@ fn notifications_state_consistent() { future::Either::Right(Event::NotificationStreamOpened { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME { + if protocol == PROTOCOL_NAME.into() { something_happened = true; assert!(!node2_to_node1_open); node2_to_node1_open = true; @@ -306,7 +314,7 @@ fn notifications_state_consistent() { future::Either::Left(Event::NotificationStreamClosed { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME { + if protocol == PROTOCOL_NAME.into() { assert!(node1_to_node2_open); node1_to_node2_open = false; assert_eq!(remote, node2.local_peer_id()); @@ -314,7 +322,7 @@ fn notifications_state_consistent() { future::Either::Right(Event::NotificationStreamClosed { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME { + if protocol == PROTOCOL_NAME.into() { assert!(node2_to_node1_open); node2_to_node1_open = false; assert_eq!(remote, node1.local_peer_id()); @@ -325,7 +333,7 @@ fn notifications_state_consistent() { if rand::random::() % 5 >= 4 { node1.write_notification( node2.local_peer_id(), - PROTOCOL_NAME, + PROTOCOL_NAME.into(), b"hello world".to_vec(), ); } @@ -336,7 +344,7 @@ fn notifications_state_consistent() { if rand::random::() % 5 >= 4 { node2.write_notification( node1.local_peer_id(), - PROTOCOL_NAME, + PROTOCOL_NAME.into(), b"hello world".to_vec(), ); } @@ -361,7 +369,7 @@ fn lots_of_incoming_peers_works() { let (main_node, _) = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], extra_sets: vec![config::NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME, + notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, set_config: config::SetConfig { in_peers: u32::MAX, ..Default::default() }, @@ -380,7 +388,7 @@ fn lots_of_incoming_peers_works() { let (_dialing_node, event_stream) = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![], extra_sets: vec![config::NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME, + notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, set_config: config::SetConfig { @@ -449,7 +457,7 @@ fn notifications_back_pressure() { Event::NotificationStreamClosed { .. } => panic!(), Event::NotificationsReceived { messages, .. } => for message in messages { - assert_eq!(message.0, PROTOCOL_NAME); + assert_eq!(message.0, PROTOCOL_NAME.into()); assert_eq!(message.1, format!("hello #{}", received_notifications)); received_notifications += 1; }, @@ -473,7 +481,7 @@ fn notifications_back_pressure() { // Sending! for num in 0..TOTAL_NOTIFS { - let notif = node1.notification_sender(node2_id, PROTOCOL_NAME).unwrap(); + let notif = node1.notification_sender(node2_id, PROTOCOL_NAME.into()).unwrap(); notif .ready() .await @@ -491,15 +499,14 @@ fn fallback_name_working() { // Node 1 supports the protocols "new" and "old". Node 2 only supports "old". Checks whether // they can connect. - const NEW_PROTOCOL_NAME: Cow<'static, str> = - Cow::Borrowed("/new-shiny-protocol-that-isnt-PROTOCOL_NAME"); + const NEW_PROTOCOL_NAME: &str = "/new-shiny-protocol-that-isnt-PROTOCOL_NAME"; let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let (node1, mut events_stream1) = build_test_full_node(config::NetworkConfiguration { extra_sets: vec![config::NonDefaultSetConfig { - notifications_protocol: NEW_PROTOCOL_NAME.clone(), - fallback_names: vec![PROTOCOL_NAME], + notifications_protocol: NEW_PROTOCOL_NAME.into(), + fallback_names: vec![PROTOCOL_NAME.into()], max_notification_size: 1024 * 1024, set_config: Default::default(), }], @@ -510,7 +517,7 @@ fn fallback_name_working() { let (_, mut events_stream2) = build_test_full_node(config::NetworkConfiguration { extra_sets: vec![config::NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME, + notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, set_config: config::SetConfig { @@ -531,7 +538,7 @@ fn fallback_name_working() { loop { match events_stream2.next().await.unwrap() { Event::NotificationStreamOpened { protocol, negotiated_fallback, .. } => { - assert_eq!(protocol, PROTOCOL_NAME); + assert_eq!(protocol, PROTOCOL_NAME.into()); assert_eq!(negotiated_fallback, None); break }, @@ -545,9 +552,9 @@ fn fallback_name_working() { loop { match events_stream1.next().await.unwrap() { Event::NotificationStreamOpened { protocol, negotiated_fallback, .. } - if protocol == NEW_PROTOCOL_NAME => + if protocol == NEW_PROTOCOL_NAME.into() => { - assert_eq!(negotiated_fallback, Some(PROTOCOL_NAME)); + assert_eq!(negotiated_fallback, Some(PROTOCOL_NAME.into())); break }, _ => {}, diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index f557ec0cec7c7..1cf532f33ddc6 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -42,12 +42,14 @@ use log::{debug, trace, warn}; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network_common::{ config::ProtocolId, - protocol::event::{Event, ObservedRole}, + protocol::{ + event::{Event, ObservedRole}, + ProtocolName, + }, service::{NetworkEventStream, NetworkNotification, NetworkPeers}, }; use sp_runtime::traits::Block as BlockT; use std::{ - borrow::Cow, collections::{hash_map::Entry, HashMap}, iter, num::NonZeroUsize, @@ -130,8 +132,8 @@ impl Future for PendingTransaction { /// Prototype for a [`TransactionsHandler`]. pub struct TransactionsHandlerPrototype { - protocol_name: Cow<'static, str>, - fallback_protocol_names: Vec>, + protocol_name: ProtocolName, + fallback_protocol_names: Vec, } impl TransactionsHandlerPrototype { @@ -244,7 +246,7 @@ enum ToHandler { /// Handler for transactions. Call [`TransactionsHandler::run`] to start the processing. pub struct TransactionsHandler { - protocol_name: Cow<'static, str>, + protocol_name: ProtocolName, /// Interval at which we call `propagate_transactions`. propagate_timeout: Pin + Send>>, /// Pending transactions verification tasks. diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 323af13943de7..837cdeed0f3d1 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -23,7 +23,6 @@ mod block_import; mod sync; use std::{ - borrow::Cow, collections::HashMap, marker::PhantomData, pin::Pin, @@ -58,6 +57,7 @@ use sc_network::{ }; use sc_network_common::{ config::{MultiaddrWithPeerId, ProtocolId}, + protocol::ProtocolName, service::{NetworkBlock, NetworkStateInfo, NetworkSyncForkRequest}, sync::warp::{AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider}, }; @@ -682,7 +682,7 @@ pub struct FullPeerConfig { /// Block announce validator. pub block_announce_validator: Option + Send + Sync>>, /// List of notification protocols that the network must support. - pub notifications_protocols: Vec>, + pub notifications_protocols: Vec, /// The indices of the peers the peer should be connected to. /// /// If `None`, it will be connected to all other peers. diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index f40bceb615148..6d6c52c989c34 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -328,11 +328,12 @@ mod tests { use sc_client_db::offchain::LocalStorage; use sc_network_common::{ config::MultiaddrWithPeerId, + protocol::ProtocolName, service::{NetworkPeers, NetworkStateInfo}, }; use sc_peerset::ReputationChange; use sp_core::offchain::{DbExternalities, Externalities}; - use std::{borrow::Cow, time::SystemTime}; + use std::time::SystemTime; pub(super) struct TestNetwork(); @@ -353,7 +354,7 @@ mod tests { unimplemented!(); } - fn disconnect_peer(&self, _who: PeerId, _protocol: Cow<'static, str>) { + fn disconnect_peer(&self, _who: PeerId, _protocol: ProtocolName) { unimplemented!(); } @@ -375,7 +376,7 @@ mod tests { fn set_reserved_peers( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); @@ -383,29 +384,25 @@ mod tests { fn add_peers_to_reserved_set( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); } - fn remove_peers_from_reserved_set( - &self, - _protocol: Cow<'static, str>, - _peers: Vec, - ) { + fn remove_peers_from_reserved_set(&self, _protocol: ProtocolName, _peers: Vec) { unimplemented!(); } fn add_to_peers_set( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); } - fn remove_from_peers_set(&self, _protocol: Cow<'static, str>, _peers: Vec) { + fn remove_from_peers_set(&self, _protocol: ProtocolName, _peers: Vec) { unimplemented!(); } diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index e215a016872cc..87e79833b9706 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -249,12 +249,12 @@ mod tests { use libp2p::{Multiaddr, PeerId}; use sc_block_builder::BlockBuilderProvider as _; use sc_client_api::Backend as _; - use sc_network_common::config::MultiaddrWithPeerId; + use sc_network_common::{config::MultiaddrWithPeerId, protocol::ProtocolName}; use sc_peerset::ReputationChange; use sc_transaction_pool::{BasicPool, FullChainApi}; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_consensus::BlockOrigin; - use std::{borrow::Cow, collections::HashSet, sync::Arc}; + use std::{collections::HashSet, sync::Arc}; use substrate_test_runtime_client::{ runtime::Block, ClientBlockImportExt, DefaultTestClientBuilderExt, TestClient, TestClientBuilderExt, @@ -289,7 +289,7 @@ mod tests { unimplemented!(); } - fn disconnect_peer(&self, _who: PeerId, _protocol: Cow<'static, str>) { + fn disconnect_peer(&self, _who: PeerId, _protocol: ProtocolName) { unimplemented!(); } @@ -311,7 +311,7 @@ mod tests { fn set_reserved_peers( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); @@ -319,29 +319,25 @@ mod tests { fn add_peers_to_reserved_set( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); } - fn remove_peers_from_reserved_set( - &self, - _protocol: Cow<'static, str>, - _peers: Vec, - ) { + fn remove_peers_from_reserved_set(&self, _protocol: ProtocolName, _peers: Vec) { unimplemented!(); } fn add_to_peers_set( &self, - _protocol: Cow<'static, str>, + _protocol: ProtocolName, _peers: HashSet, ) -> Result<(), String> { unimplemented!(); } - fn remove_from_peers_set(&self, _protocol: Cow<'static, str>, _peers: Vec) { + fn remove_from_peers_set(&self, _protocol: ProtocolName, _peers: Vec) { unimplemented!(); } From 1a15071a83aa104927e313afb65262359850b0d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Mon, 5 Sep 2022 09:26:45 +0200 Subject: [PATCH 1120/1472] `try-runtime`::`follow-chain` - execute all blocks (#12048) * extract subscription * FinalizedHeaders * Fool of a Took * testability * tests * review comments * clippy --- Cargo.lock | 1 + utils/frame/try-runtime/cli/Cargo.toml | 3 + .../cli/src/commands/follow_chain.rs | 264 ++++++++++++++++-- 3 files changed, 239 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae225184c5b28..f6c2df81d6ee1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11122,6 +11122,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-version", + "tokio", "zstd", ] diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index dd98854e84d75..56ead30644d86 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -32,3 +32,6 @@ sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../../primitives/state-machine" } sp-version = { version = "5.0.0", path = "../../../../primitives/version" } frame-try-runtime = { path = "../../../../frame/try-runtime" } + +[dev-dependencies] +tokio = "1.17.0" diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index 01fc1dae15a05..9f598694d0ff1 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -20,16 +20,20 @@ use crate::{ state_machine_call_with_proof, SharedParams, LOG_TARGET, }; use jsonrpsee::{ - core::client::{Subscription, SubscriptionClientT}, + core::{ + async_trait, + client::{Client, Subscription, SubscriptionClientT}, + }, ws_client::WsClientBuilder, }; use parity_scale_codec::{Decode, Encode}; use remote_externalities::{rpc_api, Builder, Mode, OnlineConfig}; use sc_executor::NativeExecutionDispatch; use sc_service::Configuration; +use serde::de::DeserializeOwned; use sp_core::H256; -use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; -use std::{fmt::Debug, str::FromStr}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use std::{collections::VecDeque, fmt::Debug, marker::PhantomData, str::FromStr}; const SUB: &str = "chain_subscribeFinalizedHeads"; const UN_SUB: &str = "chain_unsubscribeFinalizedHeads"; @@ -58,51 +62,182 @@ pub struct FollowChainCmd { try_state: frame_try_runtime::TryStateSelect, } +/// Start listening for with `SUB` at `url`. +/// +/// Returns a pair `(client, subscription)` - `subscription` alone will be useless, because it +/// relies on the related alive `client`. +async fn start_subscribing( + url: &str, +) -> sc_cli::Result<(Client, Subscription
)> { + let client = WsClientBuilder::default() + .connection_timeout(std::time::Duration::new(20, 0)) + .max_notifs_per_subscription(1024) + .max_request_body_size(u32::MAX) + .build(url) + .await + .map_err(|e| sc_cli::Error::Application(e.into()))?; + + log::info!(target: LOG_TARGET, "subscribing to {:?} / {:?}", SUB, UN_SUB); + + let sub = client + .subscribe(SUB, None, UN_SUB) + .await + .map_err(|e| sc_cli::Error::Application(e.into()))?; + Ok((client, sub)) +} + +/// Abstraction over RPC calling for headers. +#[async_trait] +trait HeaderProvider +where + Block::Header: HeaderT, +{ + /// Awaits for the header of the block with hash `hash`. + async fn get_header(&mut self, hash: Block::Hash) -> Block::Header; +} + +struct RpcHeaderProvider { + uri: String, + _phantom: PhantomData, +} + +#[async_trait] +impl HeaderProvider for RpcHeaderProvider +where + Block::Header: DeserializeOwned, +{ + async fn get_header(&mut self, hash: Block::Hash) -> Block::Header { + rpc_api::get_header::(&self.uri, hash).await.unwrap() + } +} + +/// Abstraction over RPC subscription for finalized headers. +#[async_trait] +trait HeaderSubscription +where + Block::Header: HeaderT, +{ + /// Await for the next finalized header from the subscription. + /// + /// Returns `None` if either the subscription has been closed or there was an error when reading + /// an object from the client. + async fn next_header(&mut self) -> Option; +} + +#[async_trait] +impl HeaderSubscription for Subscription +where + Block::Header: DeserializeOwned, +{ + async fn next_header(&mut self) -> Option { + match self.next().await { + Some(Ok(header)) => Some(header), + None => { + log::warn!("subscription closed"); + None + }, + Some(Err(why)) => { + log::warn!("subscription returned error: {:?}. Probably decoding has failed.", why); + None + }, + } + } +} + +/// Stream of all finalized headers. +/// +/// Returned headers are guaranteed to be ordered. There are no missing headers (even if some of +/// them lack justification). +struct FinalizedHeaders, HS: HeaderSubscription> { + header_provider: HP, + subscription: HS, + fetched_headers: VecDeque, + last_returned: Option<::Hash>, +} + +impl, HS: HeaderSubscription> + FinalizedHeaders +where + ::Header: DeserializeOwned, +{ + pub fn new(header_provider: HP, subscription: HS) -> Self { + Self { + header_provider, + subscription, + fetched_headers: VecDeque::new(), + last_returned: None, + } + } + + /// Reads next finalized header from the subscription. If some headers (without justification) + /// have been skipped, fetches them as well. Returns number of headers that have been fetched. + /// + /// All fetched headers are stored in `self.fetched_headers`. + async fn fetch(&mut self) -> usize { + let last_finalized = match self.subscription.next_header().await { + Some(header) => header, + None => return 0, + }; + + self.fetched_headers.push_front(last_finalized.clone()); + + let mut last_finalized_parent = *last_finalized.parent_hash(); + let last_returned = self.last_returned.unwrap_or(last_finalized_parent); + + while last_finalized_parent != last_returned { + let parent_header = self.header_provider.get_header(last_finalized_parent).await; + self.fetched_headers.push_front(parent_header.clone()); + last_finalized_parent = *parent_header.parent_hash(); + } + + self.fetched_headers.len() + } + + /// Get the next finalized header. + pub async fn next(&mut self) -> Option { + if self.fetched_headers.is_empty() { + self.fetch().await; + } + + if let Some(header) = self.fetched_headers.pop_front() { + self.last_returned = Some(header.hash()); + Some(header) + } else { + None + } + } +} + pub(crate) async fn follow_chain( shared: SharedParams, command: FollowChainCmd, config: Configuration, ) -> sc_cli::Result<()> where - Block: BlockT + serde::de::DeserializeOwned, + Block: BlockT + DeserializeOwned, Block::Hash: FromStr, - Block::Header: serde::de::DeserializeOwned, + Block::Header: DeserializeOwned, ::Err: Debug, NumberFor: FromStr, as FromStr>::Err: Debug, ExecDispatch: NativeExecutionDispatch + 'static, { let mut maybe_state_ext = None; - - let client = WsClientBuilder::default() - .connection_timeout(std::time::Duration::new(20, 0)) - .max_notifs_per_subscription(1024) - .max_request_body_size(u32::MAX) - .build(&command.uri) - .await - .unwrap(); - - log::info!(target: LOG_TARGET, "subscribing to {:?} / {:?}", SUB, UN_SUB); - let mut subscription: Subscription = - client.subscribe(SUB, None, UN_SUB).await.unwrap(); + let (_client, subscription) = start_subscribing::(&command.uri).await?; let (code_key, code) = extract_code(&config.chain_spec)?; let executor = build_executor::(&shared, &config); let execution = shared.execution; - loop { - let header = match subscription.next().await { - Some(Ok(header)) => header, - None => { - log::warn!("subscription closed"); - break - }, - Some(Err(why)) => { - log::warn!("subscription returned error: {:?}. Probably decoding has failed.", why); - continue - }, - }; + let header_provider: RpcHeaderProvider = + RpcHeaderProvider { uri: command.uri.clone(), _phantom: PhantomData {} }; + let mut finalized_headers: FinalizedHeaders< + Block, + RpcHeaderProvider, + Subscription, + > = FinalizedHeaders::new(header_provider, subscription); + while let Some(header) = finalized_headers.next().await { let hash = header.hash(); let number = header.number(); @@ -193,3 +328,74 @@ where log::error!(target: LOG_TARGET, "ws subscription must have terminated."); Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + use sp_runtime::testing::{Block as TBlock, ExtrinsicWrapper, Header}; + + type Block = TBlock>; + type BlockNumber = u64; + type Hash = H256; + + struct MockHeaderProvider(pub VecDeque); + + fn headers() -> Vec
{ + let mut headers = vec![Header::new_from_number(0)]; + for n in 1..11 { + headers.push(Header { + parent_hash: headers.last().unwrap().hash(), + ..Header::new_from_number(n) + }) + } + headers + } + + #[async_trait] + impl HeaderProvider for MockHeaderProvider { + async fn get_header(&mut self, _hash: Hash) -> Header { + let height = self.0.pop_front().unwrap(); + headers()[height as usize].clone() + } + } + + struct MockHeaderSubscription(pub VecDeque); + + #[async_trait] + impl HeaderSubscription for MockHeaderSubscription { + async fn next_header(&mut self) -> Option
{ + self.0.pop_front().map(|h| headers()[h as usize].clone()) + } + } + + #[tokio::test] + async fn finalized_headers_works_when_every_block_comes_from_subscription() { + let heights = vec![4, 5, 6, 7]; + + let provider = MockHeaderProvider(vec![].into()); + let subscription = MockHeaderSubscription(heights.clone().into()); + let mut headers = FinalizedHeaders::new(provider, subscription); + + for h in heights { + assert_eq!(h, headers.next().await.unwrap().number); + } + assert_eq!(None, headers.next().await); + } + + #[tokio::test] + async fn finalized_headers_come_from_subscription_and_provider_if_in_need() { + let all_heights = 3..11; + let heights_in_subscription = vec![3, 4, 6, 10]; + // Consecutive headers will be requested in the reversed order. + let heights_not_in_subscription = vec![5, 9, 8, 7]; + + let provider = MockHeaderProvider(heights_not_in_subscription.into()); + let subscription = MockHeaderSubscription(heights_in_subscription.into()); + let mut headers = FinalizedHeaders::new(provider, subscription); + + for h in all_heights { + assert_eq!(h, headers.next().await.unwrap().number); + } + assert_eq!(None, headers.next().await); + } +} From 58d3bc67b9595d0a26f5abba88fe4941a6e75b4a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 5 Sep 2022 13:47:15 +0300 Subject: [PATCH 1121/1472] beefy: initialize voter from genesis and fix initial sync (#11959) * client/beefy: use backend instead of client where possible * client/beefy: initialize voter from genesis Now that we have justifications import, we can drop the "lean beefy" behaviour and start building justifications chain from Genesis with containing all past sessions' mandatory blocks justifications. * client/beefy: walk finality tree_route to catch session changes * client/beefy: fix block import During initial block import blocks are not finalized, so trying to validate and append justifications within block import fails (for initial network sync imported blocks). Changes: - Move justification validation to _after_ `inner.block_import()`, so block is imported in backend and runtime api can be called to get the BEEFY authorities for said block. - Move append-to-backend for imported BEEFY justification to voter, because it already has the required logic to BEEFY-finalize blocks only after GRANDPA finalized them. - Mark voting rounds as concluded when finalizing through imported justifications as well as when finalizing through voting. * client/beefy: valid justifications are one per block number The only way we'd get _different_ _validated_ justifications for same block number is if authorities are double voting, which will be handled later. * client/beefy: process incoming justifs during major sync * client/beefy: correct voter initialization BEEFY voter should resume voting from either: - last BEEFY finalized block, - session start, whichever is closest to head. * client/beefy: test voter initialization * client/beefy: impl review suggestions Signed-off-by: acatangiu --- client/beefy/src/import.rs | 75 ++------ client/beefy/src/round.rs | 28 ++- client/beefy/src/tests.rs | 12 +- client/beefy/src/worker.rs | 374 +++++++++++++++++++++++++++++-------- 4 files changed, 342 insertions(+), 147 deletions(-) diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index 129484199de89..db4d8bfba7450 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -17,12 +17,11 @@ // along with this program. If not, see . use beefy_primitives::{BeefyApi, BEEFY_ENGINE_ID}; -use codec::Encode; -use log::error; +use log::debug; use std::{collections::HashMap, sync::Arc}; use sp_api::{ProvideRuntimeApi, TransactionFor}; -use sp_blockchain::{well_known_cache_keys, HeaderBackend}; +use sp_blockchain::well_known_cache_keys; use sp_consensus::Error as ConsensusError; use sp_runtime::{ generic::BlockId, @@ -97,29 +96,6 @@ where decode_and_verify_finality_proof::(&encoded[..], number, &validator_set) } - - /// Import BEEFY justification: Send it to worker for processing and also append it to backend. - /// - /// This function assumes: - /// - `justification` is verified and valid, - /// - the block referred by `justification` has been imported _and_ finalized. - fn import_beefy_justification_unchecked( - &self, - number: NumberFor, - justification: BeefyVersionedFinalityProof, - ) { - // Append the justification to the block in the backend. - if let Err(e) = self.backend.append_justification( - BlockId::Number(number), - (BEEFY_ENGINE_ID, justification.encode()), - ) { - error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, justification); - } - // Send the justification to the BEEFY voter for processing. - self.justification_sender - .notify(|| Ok::<_, ()>(justification)) - .expect("forwards closure result; the closure always returns Ok; qed."); - } } #[async_trait::async_trait] @@ -147,42 +123,31 @@ where let hash = block.post_hash(); let number = *block.header.number(); - let beefy_proof = block - .justifications - .as_mut() - .and_then(|just| { - let decoded = just - .get(BEEFY_ENGINE_ID) - .map(|encoded| self.decode_and_verify(encoded, number, hash)); - // Remove BEEFY justification from the list before giving to `inner`; - // we will append it to backend ourselves at the end if all goes well. - just.remove(BEEFY_ENGINE_ID); - decoded - }) - .transpose() - .unwrap_or(None); + let beefy_encoded = block.justifications.as_mut().and_then(|just| { + let encoded = just.get(BEEFY_ENGINE_ID).cloned(); + // Remove BEEFY justification from the list before giving to `inner`; we send it to the + // voter (beefy-gadget) and it will append it to the backend after block is finalized. + just.remove(BEEFY_ENGINE_ID); + encoded + }); // Run inner block import. let inner_import_result = self.inner.import_block(block, new_cache).await?; - match (beefy_proof, &inner_import_result) { - (Some(proof), ImportResult::Imported(_)) => { - let status = self.backend.blockchain().info(); - if number <= status.finalized_number && - Some(hash) == - self.backend - .blockchain() - .hash(number) - .map_err(|e| ConsensusError::ClientImport(e.to_string()))? - { + match (beefy_encoded, &inner_import_result) { + (Some(encoded), ImportResult::Imported(_)) => { + if let Ok(proof) = self.decode_and_verify(&encoded, number, hash) { // The proof is valid and the block is imported and final, we can import. - self.import_beefy_justification_unchecked(number, proof); + debug!(target: "beefy", "🥩 import justif {:?} for block number {:?}.", proof, number); + // Send the justification to the BEEFY voter for processing. + self.justification_sender + .notify(|| Ok::<_, ()>(proof)) + .expect("forwards closure result; the closure always returns Ok; qed."); } else { - error!( + debug!( target: "beefy", - "🥩 Cannot import justification: {:?} for, not yet final, block number {:?}", - proof, - number, + "🥩 error decoding justification: {:?} for imported block {:?}", + encoded, number, ); } }, diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index 762a8f7e5d544..c96613eb38a95 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -147,13 +147,8 @@ where trace!(target: "beefy", "🥩 Round #{} done: {}", round.1, done); if done { - // remove this and older (now stale) rounds let signatures = self.rounds.remove(round)?.votes; - self.rounds.retain(|&(_, number), _| number > round.1); - self.mandatory_done = self.mandatory_done || round.1 == self.session_start; - self.best_done = self.best_done.max(Some(round.1)); - debug!(target: "beefy", "🥩 Concluded round #{}", round.1); - + self.conclude(round.1); Some( self.validators() .iter() @@ -165,9 +160,12 @@ where } } - #[cfg(test)] - pub(crate) fn test_set_mandatory_done(&mut self, done: bool) { - self.mandatory_done = done; + pub(crate) fn conclude(&mut self, round_num: NumberFor) { + // Remove this and older (now stale) rounds. + self.rounds.retain(|&(_, number), _| number > round_num); + self.mandatory_done = self.mandatory_done || round_num == self.session_start; + self.best_done = self.best_done.max(Some(round_num)); + debug!(target: "beefy", "🥩 Concluded round #{}", round_num); } } @@ -178,9 +176,19 @@ mod tests { use beefy_primitives::{crypto::Public, ValidatorSet}; - use super::{threshold, RoundTracker, Rounds}; + use super::{threshold, Block as BlockT, Hash, RoundTracker, Rounds}; use crate::keystore::tests::Keyring; + impl Rounds + where + P: Ord + Hash + Clone, + B: BlockT, + { + pub(crate) fn test_set_mandatory_done(&mut self, done: bool) { + self.mandatory_done = done; + } + } + #[test] fn round_tracker() { let mut rt = RoundTracker::default(); diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index f0257d179cb33..e8d32fe3e8127 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -145,7 +145,7 @@ impl BeefyTestNet { }) } - pub(crate) fn generate_blocks( + pub(crate) fn generate_blocks_and_sync( &mut self, count: usize, session_length: u64, @@ -168,6 +168,7 @@ impl BeefyTestNet { block }); + self.block_until_sync(); } } @@ -528,8 +529,7 @@ fn beefy_finalizing_blocks() { runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); // push 42 blocks including `AuthorityChange` digests every 10 blocks. - net.generate_blocks(42, session_len, &validator_set, true); - net.block_until_sync(); + net.generate_blocks_and_sync(42, session_len, &validator_set, true); let net = Arc::new(Mutex::new(net)); @@ -567,8 +567,7 @@ fn lagging_validators() { runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); // push 62 blocks including `AuthorityChange` digests every 30 blocks. - net.generate_blocks(62, session_len, &validator_set, true); - net.block_until_sync(); + net.generate_blocks_and_sync(62, session_len, &validator_set, true); let net = Arc::new(Mutex::new(net)); @@ -644,8 +643,7 @@ fn correct_beefy_payload() { runtime.spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); // push 10 blocks - net.generate_blocks(12, session_len, &validator_set, false); - net.block_until_sync(); + net.generate_blocks_and_sync(12, session_len, &validator_set, false); let net = Arc::new(Mutex::new(net)); // with 3 good voters and 1 bad one, consensus should happen and best blocks produced. diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 9f1938fa91c33..9f54a300472de 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -27,11 +27,12 @@ use codec::{Codec, Decode, Encode}; use futures::StreamExt; use log::{debug, error, info, log_enabled, trace, warn}; -use sc_client_api::{Backend, FinalityNotification}; +use sc_client_api::{Backend, FinalityNotification, HeaderBackend}; use sc_network_gossip::GossipEngine; use sp_api::{BlockId, ProvideRuntimeApi}; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; +use sp_blockchain::Backend as BlockchainBackend; use sp_consensus::SyncOracle; use sp_mmr_primitives::MmrApi; use sp_runtime::{ @@ -212,7 +213,7 @@ pub(crate) struct BeefyWorker { /// Buffer holding votes for future processing. pending_votes: BTreeMap, Vec, AuthorityId, Signature>>>, /// Buffer holding justifications for future processing. - pending_justifications: BTreeMap, Vec>>, + pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, /// Chooses which incoming votes to accept and which votes to generate. voting_oracle: VoterOracle, } @@ -246,8 +247,9 @@ where min_block_delta, } = worker_params; - let last_finalized_header = client - .expect_header(BlockId::number(client.info().finalized_number)) + let last_finalized_header = backend + .blockchain() + .expect_header(BlockId::number(backend.blockchain().info().finalized_number)) .expect("latest block always has header available; qed."); BeefyWorker { @@ -313,9 +315,8 @@ where new_session_start: NumberFor, ) { debug!(target: "beefy", "🥩 New active validator set: {:?}", validator_set); - metric_set!(self, beefy_validator_set_id, validator_set.id()); - // BEEFY should produce the mandatory block of each session. + // BEEFY should finalize a mandatory block during each session. if let Some(active_session) = self.voting_oracle.rounds_mut() { if !active_session.mandatory_done() { debug!( @@ -334,7 +335,12 @@ where let id = validator_set.id(); self.voting_oracle.add_session(Rounds::new(new_session_start, validator_set)); - info!(target: "beefy", "🥩 New Rounds for validator set id: {:?} with session_start {:?}", id, new_session_start); + metric_set!(self, beefy_validator_set_id, id); + info!( + target: "beefy", + "🥩 New Rounds for validator set id: {:?} with session_start {:?}", + id, new_session_start + ); } fn handle_finality_notification(&mut self, notification: &FinalityNotification) { @@ -345,11 +351,24 @@ where // update best GRANDPA finalized block we have seen self.best_grandpa_block_header = header.clone(); - // Check for and enqueue potential new session. - if let Some(new_validator_set) = find_authorities_change::(header) { - self.init_session_at(new_validator_set, *header.number()); - // TODO: when adding SYNC protocol, fire up a request for justification for this - // mandatory block here. + // Check all (newly) finalized blocks for new session(s). + let backend = self.backend.clone(); + for header in notification + .tree_route + .iter() + .map(|hash| { + backend + .blockchain() + .expect_header(BlockId::hash(*hash)) + .expect("just finalized block should be available; qed.") + }) + .chain(std::iter::once(header.clone())) + { + if let Some(new_validator_set) = find_authorities_change::(&header) { + self.init_session_at(new_validator_set, *header.number()); + // TODO (grandpa-bridge-gadget/issues/20): when adding SYNC protocol, + // fire up a request for justification for this mandatory block here. + } } } } @@ -389,10 +408,10 @@ where let block_num = signed_commitment.commitment.block_number; let best_grandpa = *self.best_grandpa_block_header.number(); match self.voting_oracle.triage_round(block_num, best_grandpa)? { - RoundAction::Process => self.finalize(justification), + RoundAction::Process => self.finalize(justification)?, RoundAction::Enqueue => { debug!(target: "beefy", "🥩 Buffer justification for round: {:?}.", block_num); - self.pending_justifications.entry(block_num).or_default().push(justification) + self.pending_justifications.entry(block_num).or_insert(justification); }, RoundAction::Drop => (), }; @@ -427,15 +446,8 @@ where info!(target: "beefy", "🥩 Round #{} concluded, finality_proof: {:?}.", round.1, finality_proof); - if let Err(e) = self.backend.append_justification( - BlockId::Number(block_num), - (BEEFY_ENGINE_ID, finality_proof.clone().encode()), - ) { - debug!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, finality_proof); - } - // We created the `finality_proof` and know to be valid. - self.finalize(finality_proof); + self.finalize(finality_proof)?; } } Ok(()) @@ -447,19 +459,29 @@ where /// 3. Send best block hash and `finality_proof` to RPC worker. /// /// Expects `finality proof` to be valid. - fn finalize(&mut self, finality_proof: BeefyVersionedFinalityProof) { + fn finalize(&mut self, finality_proof: BeefyVersionedFinalityProof) -> Result<(), Error> { + let block_num = match finality_proof { + VersionedFinalityProof::V1(ref sc) => sc.commitment.block_number, + }; + + // Conclude voting round for this block. + self.voting_oracle.rounds_mut().ok_or(Error::UninitSession)?.conclude(block_num); // Prune any now "finalized" sessions from queue. self.voting_oracle.try_prune(); - let signed_commitment = match finality_proof { - VersionedFinalityProof::V1(ref sc) => sc, - }; - let block_num = signed_commitment.commitment.block_number; + if Some(block_num) > self.best_beefy_block { // Set new best BEEFY block number. self.best_beefy_block = Some(block_num); metric_set!(self, beefy_best_block, block_num); - self.client.hash(block_num).ok().flatten().map(|hash| { + if let Err(e) = self.backend.append_justification( + BlockId::Number(block_num), + (BEEFY_ENGINE_ID, finality_proof.clone().encode()), + ) { + error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, finality_proof); + } + + self.backend.blockchain().hash(block_num).ok().flatten().map(|hash| { self.links .to_rpc_best_block_sender .notify(|| Ok::<_, ()>(hash)) @@ -473,6 +495,7 @@ where } else { debug!(target: "beefy", "🥩 Can't set best beefy to older: {}", block_num); } + Ok(()) } /// Handle previously buffered justifications and votes that now land in the voting interval. @@ -481,10 +504,10 @@ where let _ph = PhantomData::::default(); fn to_process_for( - pending: &mut BTreeMap, Vec>, + pending: &mut BTreeMap, T>, (start, end): (NumberFor, NumberFor), _: PhantomData, - ) -> BTreeMap, Vec> { + ) -> BTreeMap, T> { // These are still pending. let still_pending = pending.split_off(&end.saturating_add(1u32.into())); // These can be processed. @@ -494,21 +517,23 @@ where // Return ones to process. to_handle } + // Interval of blocks for which we can process justifications and votes right now. + let mut interval = self.voting_oracle.accepted_interval(best_grandpa)?; // Process pending justifications. - let interval = self.voting_oracle.accepted_interval(best_grandpa)?; if !self.pending_justifications.is_empty() { let justifs_to_handle = to_process_for(&mut self.pending_justifications, interval, _ph); - for (num, justifications) in justifs_to_handle.into_iter() { - debug!(target: "beefy", "🥩 Handle buffered justifications for: {:?}.", num); - for justif in justifications.into_iter() { - self.finalize(justif); + for (num, justification) in justifs_to_handle.into_iter() { + debug!(target: "beefy", "🥩 Handle buffered justification for: {:?}.", num); + if let Err(err) = self.finalize(justification) { + error!(target: "beefy", "🥩 Error finalizing block: {}", err); } } + // Possibly new interval after processing justifications. + interval = self.voting_oracle.accepted_interval(best_grandpa)?; } // Process pending votes. - let interval = self.voting_oracle.accepted_interval(best_grandpa)?; if !self.pending_votes.is_empty() { let votes_to_handle = to_process_for(&mut self.pending_votes, interval, _ph); for (num, votes) in votes_to_handle.into_iter() { @@ -547,17 +572,20 @@ where debug!(target: "beefy", "🥩 Try voting on {}", target_number); // Most of the time we get here, `target` is actually `best_grandpa`, - // avoid asking `client` for header in that case. + // avoid getting header from backend in that case. let target_header = if target_number == *self.best_grandpa_block_header.number() { self.best_grandpa_block_header.clone() } else { - self.client.expect_header(BlockId::Number(target_number)).map_err(|err| { - let err_msg = format!( - "Couldn't get header for block #{:?} (error: {:?}), skipping vote..", - target_number, err - ); - Error::Backend(err_msg) - })? + self.backend + .blockchain() + .expect_header(BlockId::Number(target_number)) + .map_err(|err| { + let err_msg = format!( + "Couldn't get header for block #{:?} (error: {:?}), skipping vote..", + target_number, err + ); + Error::Backend(err_msg) + })? }; let target_hash = target_header.hash(); @@ -623,7 +651,78 @@ where Ok(()) } + /// Initialize BEEFY voter state. + /// + /// Should be called only once during worker initialization with latest GRANDPA finalized + /// `header` and the validator set `active` at that point. + fn initialize_voter(&mut self, header: &B::Header, active: ValidatorSet) { + // just a sanity check. + if let Some(rounds) = self.voting_oracle.rounds_mut() { + error!( + target: "beefy", + "🥩 Voting session already initialized at: {:?}, validator set id {}.", + rounds.session_start(), + rounds.validator_set_id(), + ); + return + } + + self.best_grandpa_block_header = header.clone(); + if active.id() == GENESIS_AUTHORITY_SET_ID { + // When starting from genesis, there is no session boundary digest. + // Just initialize `rounds` to Block #1 as BEEFY mandatory block. + info!(target: "beefy", "🥩 Initialize voting session at genesis, block 1."); + self.init_session_at(active, 1u32.into()); + } else { + // TODO (issue #11837): persist local progress to avoid following look-up during init. + let blockchain = self.backend.blockchain(); + let mut header = header.clone(); + + // Walk back the imported blocks and initialize voter either, at the last block with + // a BEEFY justification, or at this session's boundary; voter will resume from there. + loop { + if let Some(true) = blockchain + .justifications(BlockId::hash(header.hash())) + .ok() + .flatten() + .map(|justifs| justifs.get(BEEFY_ENGINE_ID).is_some()) + { + info!( + target: "beefy", + "🥩 Initialize voting session at last BEEFY finalized block: {:?}.", + *header.number() + ); + self.init_session_at(active, *header.number()); + // Mark the round as already finalized. + if let Some(round) = self.voting_oracle.rounds_mut() { + round.conclude(*header.number()); + } + self.best_beefy_block = Some(*header.number()); + break + } + + if let Some(validator_set) = find_authorities_change::(&header) { + info!( + target: "beefy", + "🥩 Initialize voting session at current session boundary: {:?}.", + *header.number() + ); + self.init_session_at(validator_set, *header.number()); + break + } + + // Move up the chain. + header = self + .client + .expect_header(BlockId::Hash(*header.parent_hash())) + // in case of db failure here we want to kill the worker + .expect("db failure, voter going down."); + } + } + } + /// Wait for BEEFY runtime pallet to be available. + /// Should be called only once during worker initialization. async fn wait_for_runtime_pallet(&mut self) { let mut gossip_engine = &mut self.gossip_engine; let mut finality_stream = self.client.finality_notification_stream().fuse(); @@ -635,25 +734,19 @@ where None => break }; let at = BlockId::hash(notif.header.hash()); - if let Some(active) = self.runtime.runtime_api().validator_set(&at).ok().flatten() { - if active.id() == GENESIS_AUTHORITY_SET_ID { - // When starting from genesis, there is no session boundary digest. - // Just initialize `rounds` to Block #1 as BEEFY mandatory block. - self.init_session_at(active, 1u32.into()); - } - // In all other cases, we just go without `rounds` initialized, meaning the - // worker won't vote until it witnesses a session change. - // Once we'll implement 'initial sync' (catch-up), the worker will be able to - // start voting right away. - self.handle_finality_notification(¬if); - if let Err(err) = self.try_to_vote() { - debug!(target: "beefy", "🥩 {}", err); + if let Some(active) = self.runtime.runtime_api().validator_set(&at).ok().flatten() { + self.initialize_voter(¬if.header, active); + if !self.sync_oracle.is_major_syncing() { + if let Err(err) = self.try_to_vote() { + debug!(target: "beefy", "🥩 {}", err); + } + } + // Beefy pallet available and voter initialized. + break + } else { + trace!(target: "beefy", "🥩 Finality notification: {:?}", notif); + debug!(target: "beefy", "🥩 Waiting for BEEFY pallet to become available..."); } - break - } else { - trace!(target: "beefy", "🥩 Finality notification: {:?}", notif); - debug!(target: "beefy", "🥩 Waiting for BEEFY pallet to become available..."); - } }, _ = gossip_engine => { break @@ -668,7 +761,10 @@ where /// which is driven by finality notifications and gossiped votes. pub(crate) async fn run(mut self) { info!(target: "beefy", "🥩 run BEEFY worker, best grandpa: #{:?}.", self.best_grandpa_block_header.number()); + let mut block_import_justif = self.links.from_block_import_justif_stream.subscribe().fuse(); + self.wait_for_runtime_pallet().await; + trace!(target: "beefy", "🥩 BEEFY pallet available, starting voter."); let mut finality_notifications = self.client.finality_notification_stream().fuse(); let mut votes = Box::pin( @@ -684,7 +780,6 @@ where }) .fuse(), ); - let mut block_import_justif = self.links.from_block_import_justif_stream.subscribe().fuse(); loop { let mut gossip_engine = &mut self.gossip_engine; @@ -728,17 +823,19 @@ where } } - // Don't bother acting on 'state' changes during major sync. - if !self.sync_oracle.is_major_syncing() { - // Handle pending justifications and/or votes for now GRANDPA finalized blocks. - if let Err(err) = self.try_pending_justif_and_votes() { - debug!(target: "beefy", "🥩 {}", err); - } + // Handle pending justifications and/or votes for now GRANDPA finalized blocks. + if let Err(err) = self.try_pending_justif_and_votes() { + debug!(target: "beefy", "🥩 {}", err); + } + // Don't bother voting during major sync. + if !self.sync_oracle.is_major_syncing() { // There were external events, 'state' is changed, author a vote if needed/possible. if let Err(err) = self.try_to_vote() { debug!(target: "beefy", "🥩 {}", err); } + } else { + debug!(target: "beefy", "🥩 Skipping voting while major syncing."); } } } @@ -845,13 +942,14 @@ pub(crate) mod tests { use futures::{executor::block_on, future::poll_fn, task::Poll}; - use sc_client_api::HeaderBackend; + use sc_client_api::{Backend as BackendT, HeaderBackend}; use sc_network::NetworkService; use sc_network_test::{PeersFullClient, TestNetFactory}; use sp_api::HeaderT; + use sp_blockchain::Backend as BlockchainBackendT; use substrate_test_runtime_client::{ runtime::{Block, Digest, DigestItem, Header, H256}, - Backend, + Backend, ClientExt, }; fn create_beefy_worker( @@ -1166,10 +1264,11 @@ pub(crate) mod tests { } #[test] - fn test_finalize() { + fn should_finalize_correctly() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1, 0); + let backend = net.peer(0).client().as_backend(); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); let (mut best_block_streams, mut finality_proofs) = get_beefy_streams(&mut net, keys); @@ -1198,10 +1297,16 @@ pub(crate) mod tests { let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); let mut finality_proof = finality_proofs.drain(..).next().unwrap(); let justif = create_finality_proof(1); - worker.finalize(justif.clone()); + // create new session at block #1 + worker.voting_oracle.add_session(Rounds::new(1, validator_set.clone())); + // try to finalize block #1 + worker.finalize(justif.clone()).unwrap(); + // verify block finalized assert_eq!(worker.best_beefy_block, Some(1)); block_on(poll_fn(move |cx| { + // unknown hash -> nothing streamed assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); + // commitment streamed match finality_proof.poll_next_unpin(cx) { // expect justification Poll::Ready(Some(received)) => assert_eq!(received, justif), @@ -1213,10 +1318,20 @@ pub(crate) mod tests { // generate 2 blocks, try again expect success let (mut best_block_streams, _) = get_beefy_streams(&mut net, keys); let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); - net.generate_blocks(2, 10, &validator_set, false); + net.peer(0).push_blocks(2, false); + // finalize 1 and 2 without justifications + backend.finalize_block(BlockId::number(1), None).unwrap(); + backend.finalize_block(BlockId::number(2), None).unwrap(); let justif = create_finality_proof(2); - worker.finalize(justif); + // create new session at block #2 + worker.voting_oracle.add_session(Rounds::new(2, validator_set)); + worker.finalize(justif).unwrap(); + // verify old session pruned + assert_eq!(worker.voting_oracle.sessions.len(), 1); + // new session starting at #2 is in front + assert_eq!(worker.voting_oracle.rounds_mut().unwrap().session_start(), 2); + // verify block finalized assert_eq!(worker.best_beefy_block, Some(2)); block_on(poll_fn(move |cx| { match best_block_stream.poll_next_unpin(cx) { @@ -1229,6 +1344,10 @@ pub(crate) mod tests { } Poll::Ready(()) })); + + // check BEEFY justifications are also appended to backend + let justifs = backend.blockchain().justifications(BlockId::number(2)).unwrap().unwrap(); + assert!(justifs.get(BEEFY_ENGINE_ID).is_some()) } #[test] @@ -1325,4 +1444,109 @@ pub(crate) mod tests { assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 21); assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 22); } + + #[test] + fn should_initialize_correct_voter() { + let keys = &[Keyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); + let mut net = BeefyTestNet::new(1, 0); + let backend = net.peer(0).client().as_backend(); + + // push 15 blocks with `AuthorityChange` digests every 10 blocks + net.generate_blocks_and_sync(15, 10, &validator_set, false); + // finalize 13 without justifications + net.peer(0) + .client() + .as_client() + .finalize_block(BlockId::number(13), None) + .unwrap(); + + // Test initialization at session boundary. + { + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + + // initialize voter at block 13, expect rounds initialized at session_start = 10 + let header = backend.blockchain().header(BlockId::number(13)).unwrap().unwrap(); + worker.initialize_voter(&header, validator_set.clone()); + + // verify voter initialized with single session starting at block 10 + assert_eq!(worker.voting_oracle.sessions.len(), 1); + let rounds = worker.voting_oracle.rounds_mut().unwrap(); + assert_eq!(rounds.session_start(), 10); + assert_eq!(rounds.validator_set_id(), validator_set.id()); + + // verify next vote target is mandatory block 10 + assert_eq!(worker.best_beefy_block, None); + assert_eq!(*worker.best_grandpa_block_header.number(), 13); + assert_eq!(worker.voting_oracle.voting_target(worker.best_beefy_block, 13), Some(10)); + } + + // Test corner-case where session boundary == last beefy finalized. + { + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + + // import/append BEEFY justification for session boundary block 10 + let commitment = Commitment { + payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + block_number: 10, + validator_set_id: validator_set.id(), + }; + let justif = VersionedFinalityProof::<_, Signature>::V1(SignedCommitment { + commitment, + signatures: vec![None], + }); + backend + .append_justification(BlockId::Number(10), (BEEFY_ENGINE_ID, justif.encode())) + .unwrap(); + + // initialize voter at block 13, expect rounds initialized at last beefy finalized 10 + let header = backend.blockchain().header(BlockId::number(13)).unwrap().unwrap(); + worker.initialize_voter(&header, validator_set.clone()); + + // verify voter initialized with single session starting at block 10 + assert_eq!(worker.voting_oracle.sessions.len(), 1); + let rounds = worker.voting_oracle.rounds_mut().unwrap(); + assert_eq!(rounds.session_start(), 10); + assert_eq!(rounds.validator_set_id(), validator_set.id()); + + // verify next vote target is mandatory block 10 + assert_eq!(worker.best_beefy_block, Some(10)); + assert_eq!(*worker.best_grandpa_block_header.number(), 13); + assert_eq!(worker.voting_oracle.voting_target(worker.best_beefy_block, 13), Some(12)); + } + + // Test initialization at last BEEFY finalized. + { + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + + // import/append BEEFY justification for block 12 + let commitment = Commitment { + payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + block_number: 12, + validator_set_id: validator_set.id(), + }; + let justif = VersionedFinalityProof::<_, Signature>::V1(SignedCommitment { + commitment, + signatures: vec![None], + }); + backend + .append_justification(BlockId::Number(12), (BEEFY_ENGINE_ID, justif.encode())) + .unwrap(); + + // initialize voter at block 13, expect rounds initialized at last beefy finalized 12 + let header = backend.blockchain().header(BlockId::number(13)).unwrap().unwrap(); + worker.initialize_voter(&header, validator_set.clone()); + + // verify voter initialized with single session starting at block 12 + assert_eq!(worker.voting_oracle.sessions.len(), 1); + let rounds = worker.voting_oracle.rounds_mut().unwrap(); + assert_eq!(rounds.session_start(), 12); + assert_eq!(rounds.validator_set_id(), validator_set.id()); + + // verify next vote target is 13 + assert_eq!(worker.best_beefy_block, Some(12)); + assert_eq!(*worker.best_grandpa_block_header.number(), 13); + assert_eq!(worker.voting_oracle.voting_target(worker.best_beefy_block, 13), Some(13)); + } + } } From 6d84315348d1fca9ca59454b9f37411c80e05ab4 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Mon, 5 Sep 2022 15:04:14 +0100 Subject: [PATCH 1122/1472] drive by spelling fixes (#12175) --- frame/assets/src/types.rs | 2 +- frame/support/src/traits/metadata.rs | 2 +- frame/support/src/traits/tokens/fungibles/approvals.rs | 2 +- frame/support/src/traits/tokens/fungibles/balanced.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index 2e8a1f911fb0f..677fc5847c614 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -165,7 +165,7 @@ pub trait FrozenBalance { /// /// Under normal behaviour, the account balance should not go below the sum of this (if `Some`) /// and the asset's minimum balance. However, the account balance may reasonably begin below - /// this sum (e.g. if less than the sum had ever been transfered into the account). + /// this sum (e.g. if less than the sum had ever been transferred into the account). /// /// In special cases (privileged intervention) the account balance may also go below the sum. /// diff --git a/frame/support/src/traits/metadata.rs b/frame/support/src/traits/metadata.rs index b0dd5bd5160b4..42f2d759a597d 100644 --- a/frame/support/src/traits/metadata.rs +++ b/frame/support/src/traits/metadata.rs @@ -71,7 +71,7 @@ pub trait PalletsInfoAccess { /// /// You probably don't want this function but `infos()` instead. fn count() -> usize { - // for backwards compatibility with XCM-3, Mark is deprecated. + // for backwards compatibility with XCM-3, Mark as deprecated. Self::infos().len() } diff --git a/frame/support/src/traits/tokens/fungibles/approvals.rs b/frame/support/src/traits/tokens/fungibles/approvals.rs index 7a08f11cf042a..48929955d9497 100644 --- a/frame/support/src/traits/tokens/fungibles/approvals.rs +++ b/frame/support/src/traits/tokens/fungibles/approvals.rs @@ -24,7 +24,7 @@ pub trait Inspect: super::Inspect { } pub trait Mutate: Inspect { - // Aprove a delegate account to spend an amount of tokens owned by an owner + // Approve a delegate account to spend an amount of tokens owned by an owner fn approve( asset: Self::AssetId, owner: &AccountId, diff --git a/frame/support/src/traits/tokens/fungibles/balanced.rs b/frame/support/src/traits/tokens/fungibles/balanced.rs index a75832e4c440f..a870168e4db91 100644 --- a/frame/support/src/traits/tokens/fungibles/balanced.rs +++ b/frame/support/src/traits/tokens/fungibles/balanced.rs @@ -163,7 +163,7 @@ pub trait Balanced: Inspect { /// **WARNING** /// Do not use this directly unless you want trouble, since it allows you to alter account balances /// without keeping the issuance up to date. It has no safeguards against accidentally creating -/// token imbalances in your system leading to accidental imflation or deflation. It's really just +/// token imbalances in your system leading to accidental inflation or deflation. It's really just /// for the underlying datatype to implement so the user gets the much safer `Balanced` trait to /// use. pub trait Unbalanced: Inspect { From 19e628072cfb9b9651767b50bfaff4841b4141a3 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Mon, 5 Sep 2022 17:06:20 +0300 Subject: [PATCH 1123/1472] Enforce blocks response limit (#12146) --- client/network/sync/src/block_request_handler.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index f4f10ac73c8d9..cc61be2b57256 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -405,11 +405,20 @@ where indexed_body, }; - total_size += block_data.body.iter().map(|ex| ex.len()).sum::(); - total_size += block_data.indexed_body.iter().map(|ex| ex.len()).sum::(); + let new_total_size = total_size + + block_data.body.iter().map(|ex| ex.len()).sum::() + + block_data.indexed_body.iter().map(|ex| ex.len()).sum::(); + + // Send at least one block, but make sure to not exceed the limit. + if !blocks.is_empty() && new_total_size > MAX_BODY_BYTES { + break + } + + total_size = new_total_size; + blocks.push(block_data); - if blocks.len() >= max_blocks as usize || total_size > MAX_BODY_BYTES { + if blocks.len() >= max_blocks as usize { break } From fd399c15c33ed8a7215d711fcf93c524a7473023 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Mon, 5 Sep 2022 08:37:25 -0600 Subject: [PATCH 1124/1472] Impl transaction-payment GenesisConfig with NextFeeMultplier support (#12177) * Impl GenesisConfig with NextFeeMultplier support * Update lib.rs * Use documented const * Unit test multiplier genesis * fmt Co-authored-by: Shawn Tabrizi --- frame/transaction-payment/src/lib.rs | 54 +++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 8fe58dbf03d2b..21d516cda1aa6 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -241,6 +241,10 @@ impl Default for Releases { } } +/// Default value for NextFeeMultiplier. This is used in genesis and is also used in +/// NextFeeMultiplierOnEmpty() to provide a value when none exists in storage. +const MULTIPLIER_DEFAULT_VALUE: Multiplier = Multiplier::from_u32(1); + #[frame_support::pallet] pub mod pallet { use super::*; @@ -300,7 +304,7 @@ pub mod pallet { #[pallet::type_value] pub fn NextFeeMultiplierOnEmpty() -> Multiplier { - Multiplier::saturating_from_integer(1) + MULTIPLIER_DEFAULT_VALUE } #[pallet::storage] @@ -312,12 +316,14 @@ pub mod pallet { pub(super) type StorageVersion = StorageValue<_, Releases, ValueQuery>; #[pallet::genesis_config] - pub struct GenesisConfig; + pub struct GenesisConfig { + pub multiplier: Multiplier, + } #[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { - Self + Self { multiplier: MULTIPLIER_DEFAULT_VALUE } } } @@ -325,6 +331,7 @@ pub mod pallet { impl GenesisBuild for GenesisConfig { fn build(&self) { StorageVersion::::put(Releases::V2); + NextFeeMultiplier::::put(self.multiplier); } } @@ -816,7 +823,7 @@ mod tests { use frame_support::{ assert_noop, assert_ok, parameter_types, - traits::{ConstU32, ConstU64, Currency, Imbalance, OnUnbalanced}, + traits::{ConstU32, ConstU64, Currency, GenesisBuild, Imbalance, OnUnbalanced}, weights::{ DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo, Weight, WeightToFee as WeightToFeeT, @@ -958,11 +965,18 @@ mod tests { base_weight: Weight, byte_fee: u64, weight_to_fee: u64, + initial_multiplier: Option, } impl Default for ExtBuilder { fn default() -> Self { - Self { balance_factor: 1, base_weight: Weight::zero(), byte_fee: 1, weight_to_fee: 1 } + Self { + balance_factor: 1, + base_weight: Weight::zero(), + byte_fee: 1, + weight_to_fee: 1, + initial_multiplier: None, + } } } @@ -983,6 +997,10 @@ mod tests { self.balance_factor = factor; self } + pub fn with_initial_multiplier(mut self, multiplier: Multiplier) -> Self { + self.initial_multiplier = Some(multiplier); + self + } fn set_constants(&self) { EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee); @@ -1007,6 +1025,12 @@ mod tests { } .assimilate_storage(&mut t) .unwrap(); + + if let Some(multiplier) = self.initial_multiplier { + let genesis = pallet::GenesisConfig { multiplier }; + GenesisBuild::::assimilate_storage(&genesis, &mut t).unwrap(); + } + t.into() } } @@ -1720,4 +1744,24 @@ mod tests { assert_eq!(refund_based_fee, actual_fee); }); } + + #[test] + fn genesis_config_works() { + ExtBuilder::default() + .with_initial_multiplier(Multiplier::from_u32(100)) + .build() + .execute_with(|| { + assert_eq!( + >::get(), + Multiplier::saturating_from_integer(100) + ); + }); + } + + #[test] + fn genesis_default_works() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(>::get(), Multiplier::saturating_from_integer(1)); + }); + } } From 5f18a8b729894d0dcc34d6a7c269d62aa593d910 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Mon, 5 Sep 2022 17:08:50 +0200 Subject: [PATCH 1125/1472] Alliance pallet: split force_set_members call (#12179) * Alliance pallet: split force_set_members call * use counts for event * ".git/.scripts/bench-bot.sh" pallet dev pallet_alliance Co-authored-by: command-bot <> --- bin/node/runtime/src/impls.rs | 12 +- frame/alliance/README.md | 3 +- frame/alliance/src/benchmarking.rs | 175 +++++----------- frame/alliance/src/lib.rs | 142 ++++++------- frame/alliance/src/mock.rs | 21 +- frame/alliance/src/tests.rs | 186 +++++++---------- frame/alliance/src/types.rs | 22 +- frame/alliance/src/weights.rs | 309 +++++++++++++++-------------- 8 files changed, 358 insertions(+), 512 deletions(-) diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 0d0f864097af5..cedc945b0af7e 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -18,8 +18,7 @@ //! Some configurable implementations as associated type for the substrate runtime. use crate::{ - AccountId, AllianceCollective, AllianceMotion, Assets, Authorship, Balances, Call, Hash, - NegativeImbalance, Runtime, + AccountId, AllianceMotion, Assets, Authorship, Balances, Call, Hash, NegativeImbalance, Runtime, }; use frame_support::{ pallet_prelude::*, @@ -113,15 +112,6 @@ impl ProposalProvider for AllianceProposalProvider { fn proposal_of(proposal_hash: Hash) -> Option { AllianceMotion::proposal_of(proposal_hash) } - - fn proposals() -> Vec { - AllianceMotion::proposals().into_inner() - } - - fn proposals_count() -> u32 { - pallet_collective::Proposals::::decode_len().unwrap_or(0) - as u32 - } } #[cfg(test)] diff --git a/frame/alliance/README.md b/frame/alliance/README.md index 3fcd40b9527ce..dff9e0a47aa2c 100644 --- a/frame/alliance/README.md +++ b/frame/alliance/README.md @@ -66,4 +66,5 @@ to update the Alliance's rule and make announcements. #### Root Calls -- `force_set_members` - Set the members via chain governance. +- `init_members` - Initialize the Alliance, onboard founders, fellows, and allies. +- `disband` - Disband the Alliance, remove all active members and unreserve deposits. diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index d3917b9d2ed95..de2fc392db8f1 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -19,6 +19,7 @@ use sp_runtime::traits::{Bounded, Hash, StaticLookup}; use sp_std::{ + cmp, convert::{TryFrom, TryInto}, mem::size_of, prelude::*, @@ -38,11 +39,6 @@ fn assert_last_event, I: 'static>(generic_event: >:: frame_system::Pallet::::assert_last_event(generic_event.into()); } -fn assert_prev_event, I: 'static>(generic_event: >::Event) { - let events = frame_system::Pallet::::events(); - assert_eq!(events.get(events.len() - 2).expect("events expected").event, generic_event.into()); -} - fn cid(input: impl AsRef<[u8]>) -> Cid { use sha2::{Digest, Sha256}; let mut hasher = Sha256::new(); @@ -126,12 +122,11 @@ benchmarks_instance_pallet! { let proposer = founders[0].clone(); let fellows = (0 .. y).map(fellow::).collect::>(); - Alliance::::force_set_members( + Alliance::::init_members( SystemOrigin::Root.into(), founders, fellows, vec![], - Default::default(), )?; let threshold = m; @@ -178,12 +173,11 @@ benchmarks_instance_pallet! { members.extend(founders.clone()); members.extend(fellows.clone()); - Alliance::::force_set_members( + Alliance::::init_members( SystemOrigin::Root.into(), founders, fellows, vec![], - Default::default(), )?; // Threshold is 1 less than the number of members so that one person can vote nay @@ -247,12 +241,11 @@ benchmarks_instance_pallet! { let founders = (0 .. m).map(founder::).collect::>(); let vetor = founders[0].clone(); - Alliance::::force_set_members( + Alliance::::init_members( SystemOrigin::Root.into(), founders, vec![], vec![], - Default::default(), )?; // Threshold is one less than total members so that two nays will disapprove the vote @@ -299,12 +292,11 @@ benchmarks_instance_pallet! { members.extend(founders.clone()); members.extend(fellows.clone()); - Alliance::::force_set_members( + Alliance::::init_members( SystemOrigin::Root.into(), founders, fellows, vec![], - Default::default(), )?; let proposer = members[0].clone(); @@ -385,12 +377,11 @@ benchmarks_instance_pallet! { members.extend(founders.clone()); members.extend(fellows.clone()); - Alliance::::force_set_members( + Alliance::::init_members( SystemOrigin::Root.into(), founders, fellows, vec![], - Default::default(), )?; let proposer = members[0].clone(); @@ -477,12 +468,11 @@ benchmarks_instance_pallet! { members.extend(founders.clone()); members.extend(fellows.clone()); - Alliance::::force_set_members( + Alliance::::init_members( SystemOrigin::Root.into(), founders, fellows, vec![], - Default::default(), )?; let proposer = members[0].clone(); @@ -554,12 +544,11 @@ benchmarks_instance_pallet! { members.extend(founders.clone()); members.extend(fellows.clone()); - Alliance::::force_set_members( + Alliance::::init_members( SystemOrigin::Root.into(), founders, fellows, vec![], - Default::default(), )?; let proposer = members[0].clone(); @@ -615,124 +604,21 @@ benchmarks_instance_pallet! { assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); } - force_set_members { + init_members { // at least 1 founders let x in 1 .. T::MaxFounders::get(); let y in 0 .. T::MaxFellows::get(); let z in 0 .. T::MaxAllies::get(); - let p in 0 .. T::MaxProposals::get(); - let c in 0 .. T::MaxFounders::get() + T::MaxFellows::get(); - let m in 0 .. T::MaxAllies::get(); let mut founders = (0 .. x).map(founder::).collect::>(); - let mut proposer = founders[0].clone(); let mut fellows = (0 .. y).map(fellow::).collect::>(); let mut allies = (0 .. z).map(ally::).collect::>(); - let witness = ForceSetWitness{ - proposals: p, - voting_members: c, - ally_members: m, - }; - let mut old_fellows: Vec = Vec::new(); - let mut old_allies: Vec = Vec::new(); - - let mut cc = c; - if (m > 0 && c == 0) || (p > 0 && c == 0) { - // if total member count `m` greater than zero, - // one voting member required to set non voting members. - // OR - // if some proposals, - // one voting member required to create proposal. - cc = 1; - } - - // setting the Alliance to disband on the benchmark call - if cc > 0 { - old_fellows = (0..cc).map(fellow::).collect::>(); - old_allies = (0..m).map(ally::).collect::>(); - - // used later for proposal creation. - proposer = old_fellows[0].clone(); - - // set alliance before benchmarked call to include alliance disband. - Alliance::::force_set_members( - SystemOrigin::Root.into(), - vec![old_fellows[0].clone()], - vec![], - vec![], - Default::default(), - )?; - - // using `join_alliance` instead `force_set_members` to join alliance - // to have deposit reserved and bench the worst case scenario. - for fellow in old_fellows.iter().skip(1) { - Alliance::::join_alliance( - SystemOrigin::Signed(fellow.clone()).into() - ).unwrap(); - } - - // elevating allies to have desired voting members count. - for fellow in old_fellows.iter().skip(1) { - Alliance::::elevate_ally( - T::MembershipManager::successful_origin(), - T::Lookup::unlookup(fellow.clone()) - ).unwrap(); - } - - for ally in old_allies.iter() { - Alliance::::join_alliance( - SystemOrigin::Signed(ally.clone()).into() - ).unwrap(); - } - - assert_eq!(Alliance::::voting_members_count(), cc); - assert_eq!(Alliance::::ally_members_count(), m); - } - // adding proposals to veto on the Alliance reset - for i in 0..p { - let threshold = cc; - let bytes_in_storage = i + size_of::() as u32 + 32; - // proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = - AllianceCall::::set_rule { rule: rule(vec![i as u8; i as usize]) }.into(); - Alliance::::propose( - SystemOrigin::Signed(proposer.clone()).into(), - threshold, - Box::new(proposal), - bytes_in_storage, - )?; - } - let mut proposals = T::ProposalProvider::proposals(); - if c != cc { - // removing a helper founder from the alliance which should not be - // included in the actual benchmark call. - Alliance::::give_retirement_notice( - SystemOrigin::Signed(proposer.clone()).into() - )?; - System::::set_block_number( - System::::block_number() + T::RetirementPeriod::get() - ); - Alliance::::retire( - SystemOrigin::Signed(proposer.clone()).into() - )?; - // remove a helper founder from fellows list. - old_fellows.remove(0); - } - }: _(SystemOrigin::Root, founders.clone(), fellows.clone(), allies.clone(), witness) + }: _(SystemOrigin::Root, founders.clone(), fellows.clone(), allies.clone()) verify { founders.sort(); fellows.sort(); allies.sort(); - if !witness.is_zero() { - old_fellows.append(&mut old_allies); - old_fellows.sort(); - proposals.sort(); - assert_prev_event::(Event::AllianceDisbanded { - members: old_fellows, - proposals: proposals, - }.into()); - } assert_last_event::(Event::MembersInitialized { founders: founders.clone(), fellows: fellows.clone(), @@ -743,6 +629,47 @@ benchmarks_instance_pallet! { assert_eq!(Alliance::::members(MemberRole::Ally), allies); } + disband { + // at least 1 founders + let x in 1 .. T::MaxFounders::get() + T::MaxFellows::get(); + let y in 0 .. T::MaxAllies::get(); + let z in 0 .. T::MaxMembersCount::get() / 2; + + let voting_members = (0 .. x).map(founder::).collect::>(); + let allies = (0 .. y).map(ally::).collect::>(); + let witness = DisbandWitness{ + voting_members: x, + ally_members: y, + }; + + // setting the Alliance to disband on the benchmark call + Alliance::::init_members( + SystemOrigin::Root.into(), + voting_members.clone(), + vec![], + allies.clone(), + )?; + + // reserve deposits + let deposit = T::AllyDeposit::get(); + for member in voting_members.iter().chain(allies.iter()).take(z as usize) { + T::Currency::reserve(&member, deposit)?; + >::insert(&member, deposit); + } + + assert_eq!(Alliance::::voting_members_count(), x); + assert_eq!(Alliance::::ally_members_count(), y); + }: _(SystemOrigin::Root, witness) + verify { + assert_last_event::(Event::AllianceDisbanded { + voting_members: x, + ally_members: y, + unreserved: cmp::min(z, x + y), + }.into()); + + assert!(!Alliance::::is_initialized()); + } + set_rule { set_members::(); diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index b60077c4ef99e..8f39b6b51cabd 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -84,7 +84,8 @@ //! //! #### Root Calls //! -//! - `force_set_members` - Set the members via chain governance. +//! - `init_members` - Initialize the Alliance, onboard founders, fellows, and allies. +//! - `disband` - Disband the Alliance, remove all active members and unreserve deposits. #![cfg_attr(not(feature = "std"), no_std)] @@ -204,14 +205,6 @@ pub trait ProposalProvider { /// Return a proposal of the given hash. fn proposal_of(proposal_hash: Hash) -> Option; - - /// Return hashes of all active proposals. - fn proposals() -> Vec; - - // Return count of all active proposals. - // - // Used to check witness data for an extrinsic. - fn proposals_count() -> u32; } /// The various roles that a member can hold. @@ -428,8 +421,8 @@ pub mod pallet { UnscrupulousItemAdded { items: Vec> }, /// Accounts or websites have been removed from the list of unscrupulous items. UnscrupulousItemRemoved { items: Vec> }, - /// Alliance disbanded. - AllianceDisbanded { members: Vec, proposals: Vec }, + /// Alliance disbanded. Includes number deleted members and unreserved deposits. + AllianceDisbanded { voting_members: u32, ally_members: u32, unreserved: u32 }, } #[pallet::genesis_config] @@ -647,81 +640,25 @@ pub mod pallet { Ok(info.into()) } - /// Initialize the founders, fellows, and allies. - /// Founders must be provided to initialize the Alliance. - /// - /// Provide witness data to disband current Alliance before initializing new. - /// Alliance must be empty or disband first to initialize new. - /// - /// Alliance is only disbanded if new member set is not provided. + /// Initialize the Alliance, onboard founders, fellows, and allies. /// + /// Founders must be not empty. + /// The Alliance must be empty. /// Must be called by the Root origin. - #[pallet::weight(T::WeightInfo::force_set_members( - T::MaxFounders::get(), - T::MaxFellows::get(), - T::MaxAllies::get(), - witness.proposals, - witness.voting_members, - witness.ally_members, + #[pallet::weight(T::WeightInfo::init_members( + founders.len() as u32, + fellows.len() as u32, + allies.len() as u32, ))] - pub fn force_set_members( + pub fn init_members( origin: OriginFor, founders: Vec, fellows: Vec, allies: Vec, - witness: ForceSetWitness, ) -> DispatchResult { ensure_root(origin)?; - if !witness.is_zero() { - // Disband Alliance by removing all members and returning deposits. - // Veto and remove all active proposals to avoid any unexpected behavior from - // actionable items managed outside of the pallet. Items managed within the pallet, - // like `UnscrupulousWebsites`, are left for the new Alliance to clean up or keep. - - ensure!( - T::ProposalProvider::proposals_count() <= witness.proposals, - Error::::BadWitness - ); - ensure!( - Self::voting_members_count() <= witness.voting_members, - Error::::BadWitness - ); - ensure!( - Self::ally_members_count() <= witness.ally_members, - Error::::BadWitness - ); - - let mut proposals = T::ProposalProvider::proposals(); - for hash in proposals.iter() { - T::ProposalProvider::veto_proposal(*hash); - } - - let mut members = Self::voting_members(); - T::MembershipChanged::change_members_sorted(&[], &members, &[]); - - members.append(&mut Self::members_of(MemberRole::Ally)); - for member in members.iter() { - if let Some(deposit) = DepositOf::::take(&member) { - let err_amount = T::Currency::unreserve(&member, deposit); - debug_assert!(err_amount.is_zero()); - } - } - - Members::::remove(&MemberRole::Founder); - Members::::remove(&MemberRole::Fellow); - Members::::remove(&MemberRole::Ally); - - members.sort(); - proposals.sort(); - Self::deposit_event(Event::AllianceDisbanded { members, proposals }); - } - - if founders.is_empty() { - ensure!(fellows.is_empty() && allies.is_empty(), Error::::FoundersMissing); - // new members set not provided. - return Ok(()) - } + ensure!(!founders.is_empty(), Error::::FoundersMissing); ensure!(!Self::is_initialized(), Error::::AllianceAlreadyInitialized); let mut founders: BoundedVec = @@ -765,6 +702,59 @@ pub mod pallet { Ok(()) } + /// Disband the Alliance, remove all active members and unreserve deposits. + /// + /// Witness data must be set. + #[pallet::weight(T::WeightInfo::disband( + witness.voting_members, + witness.ally_members, + witness.voting_members + witness.ally_members, + ))] + pub fn disband( + origin: OriginFor, + witness: DisbandWitness, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + + ensure!(!witness.is_zero(), Error::::BadWitness); + ensure!( + Self::voting_members_count() <= witness.voting_members, + Error::::BadWitness + ); + ensure!(Self::ally_members_count() <= witness.ally_members, Error::::BadWitness); + ensure!(Self::is_initialized(), Error::::AllianceNotYetInitialized); + + let voting_members = Self::voting_members(); + T::MembershipChanged::change_members_sorted(&[], &voting_members, &[]); + + let ally_members = Self::members_of(MemberRole::Ally); + let mut unreserve_count: u32 = 0; + for member in voting_members.iter().chain(ally_members.iter()) { + if let Some(deposit) = DepositOf::::take(&member) { + let err_amount = T::Currency::unreserve(&member, deposit); + debug_assert!(err_amount.is_zero()); + unreserve_count += 1; + } + } + + Members::::remove(&MemberRole::Founder); + Members::::remove(&MemberRole::Fellow); + Members::::remove(&MemberRole::Ally); + + Self::deposit_event(Event::AllianceDisbanded { + voting_members: voting_members.len() as u32, + ally_members: ally_members.len() as u32, + unreserved: unreserve_count, + }); + + Ok(Some(T::WeightInfo::disband( + voting_members.len() as u32, + ally_members.len() as u32, + unreserve_count, + )) + .into()) + } + /// Set a new IPFS CID to the alliance rule. #[pallet::weight(T::WeightInfo::set_rule())] pub fn set_rule(origin: OriginFor, rule: Cid) -> DispatchResult { diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index f2632ec3db08c..c140c040fbd0f 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -197,14 +197,6 @@ impl ProposalProvider for AllianceProposalProvider { fn proposal_of(proposal_hash: H256) -> Option { AllianceMotion::proposal_of(proposal_hash) } - - fn proposals() -> Vec { - AllianceMotion::proposals().into_inner() - } - - fn proposals_count() -> u32 { - pallet_collective::Proposals::::decode_len().unwrap_or(0) as u32 - } } parameter_types! { @@ -326,13 +318,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { Error::::AllianceNotYetInitialized ); - assert_ok!(Alliance::force_set_members( - Origin::root(), - vec![1, 2], - vec![3], - vec![], - Default::default() - )); + assert_ok!(Alliance::init_members(Origin::root(), vec![1, 2], vec![3], vec![])); System::set_block_number(1); }); @@ -369,8 +355,3 @@ pub fn make_proposal(proposal: Call) -> (Call, u32, H256) { let hash = BlakeTwo256::hash_of(&proposal); (proposal, len, hash) } - -pub fn assert_prev_event(event: Event) { - let events = System::events(); - assert_eq!(events.get(events.len() - 2).expect("events expected").event, event); -} diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index 9c61561d7ddb5..943c39a2d69c0 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -26,18 +26,56 @@ use crate::mock::*; type AllianceMotionEvent = pallet_collective::Event; #[test] -fn force_set_members_works() { +fn init_members_works() { new_test_ext().execute_with(|| { - // ensure alliance is set - assert_eq!(Alliance::voting_members_sorted(), vec![1, 2, 3]); + // alliance must be reset first, no witness data + assert_noop!( + Alliance::init_members(Origin::root(), vec![8], vec![], vec![],), + Error::::AllianceAlreadyInitialized, + ); - // creating and proposing proposals - let (proposal, proposal_len, hash) = make_remark_proposal(42); - assert_ok!(Alliance::propose(Origin::signed(1), 3, Box::new(proposal), proposal_len)); + // give a retirement notice to check later a retiring member not removed + assert_ok!(Alliance::give_retirement_notice(Origin::signed(2))); + assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); + + // disband the Alliance to init new + assert_ok!(Alliance::disband(Origin::root(), DisbandWitness::new(2, 0))); + + // fails without root + assert_noop!(Alliance::init_members(Origin::signed(1), vec![], vec![], vec![]), BadOrigin); + + // founders missing, other members given + assert_noop!( + Alliance::init_members(Origin::root(), vec![], vec![4], vec![2],), + Error::::FoundersMissing, + ); + + // success call + assert_ok!(Alliance::init_members(Origin::root(), vec![8, 5], vec![4], vec![2],)); - let (k_proposal, k_proposal_len, k_hash) = make_kick_member_proposal(2); - assert_ok!(Alliance::propose(Origin::signed(1), 3, Box::new(k_proposal), k_proposal_len)); - let mut proposals = vec![hash, k_hash]; + // assert new set of voting members + assert_eq!(Alliance::voting_members_sorted(), vec![4, 5, 8]); + // assert new members member + assert!(Alliance::is_founder(&8)); + assert!(Alliance::is_founder(&5)); + assert!(Alliance::is_fellow(&4)); + assert!(Alliance::is_ally(&2)); + // assert a retiring member from previous Alliance not removed + assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); + + System::assert_last_event(mock::Event::Alliance(crate::Event::MembersInitialized { + founders: vec![5, 8], + fellows: vec![4], + allies: vec![2], + })); + }) +} + +#[test] +fn disband_works() { + new_test_ext().execute_with(|| { + // ensure alliance is set + assert_eq!(Alliance::voting_members_sorted(), vec![1, 2, 3]); // give a retirement notice to check later a retiring member not removed assert_ok!(Alliance::give_retirement_notice(Origin::signed(2))); @@ -50,124 +88,46 @@ fn force_set_members_works() { assert_eq!(Balances::free_balance(9), 15); assert!(Alliance::is_member_of(&9, MemberRole::Ally)); - // ensure proposal is listed as active proposal - assert_eq!(::ProposalProvider::proposals(), proposals); - assert_eq!(::ProposalProvider::proposals_count(), 2); - // fails without root - assert_noop!( - Alliance::force_set_members( - Origin::signed(1), - vec![], - vec![], - vec![], - Default::default() - ), - BadOrigin - ); + assert_noop!(Alliance::disband(Origin::signed(1), Default::default()), BadOrigin); - // nothing to do, witness data is default, new members not provided. - assert_ok!(Alliance::force_set_members( - Origin::root(), - vec![], - vec![], - vec![], - Default::default() - )); - - // alliance must be reset first, no witness data. + // bad witness data checks assert_noop!( - Alliance::force_set_members( - Origin::root(), - vec![8], - vec![], - vec![], - Default::default() - ), - Error::::AllianceAlreadyInitialized, + Alliance::disband(Origin::root(), Default::default(),), + Error::::BadWitness ); - // wrong witness data checks - assert_noop!( - Alliance::force_set_members( - Origin::root(), - vec![], - vec![], - vec![], - ForceSetWitness::new(1, 3, 1) - ), - Error::::BadWitness, - ); assert_noop!( - Alliance::force_set_members( - Origin::root(), - vec![], - vec![], - vec![], - ForceSetWitness::new(2, 1, 1) - ), + Alliance::disband(Origin::root(), DisbandWitness::new(1, 1)), Error::::BadWitness, ); assert_noop!( - Alliance::force_set_members( - Origin::root(), - vec![], - vec![], - vec![], - ForceSetWitness::new(1, 3, 0) - ), + Alliance::disband(Origin::root(), DisbandWitness::new(2, 0)), Error::::BadWitness, ); - // founders missing, other members given - assert_noop!( - Alliance::force_set_members( - Origin::root(), - vec![], - vec![4], - vec![2], - ForceSetWitness::new(2, 3, 1) - ), - Error::::FoundersMissing, - ); - // success call - assert_ok!(Alliance::force_set_members( - Origin::root(), - vec![8, 5], - vec![4], - vec![2], - ForceSetWitness::new(2, 3, 1) - )); + assert_ok!(Alliance::disband(Origin::root(), DisbandWitness::new(2, 1))); - // assert new set of voting members - assert_eq!(Alliance::voting_members_sorted(), vec![4, 5, 8]); - // assert new ally member - assert!(Alliance::is_ally(&2)); - // assert a retiring member from previous Alliance not removed - assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); - // assert old alliance disband. + // assert members disband assert!(!Alliance::is_member(&1)); - assert!(!Alliance::is_member(&3)); - assert!(!Alliance::is_member(&9)); + assert!(!Alliance::is_initialized()); + // assert a retiring member from the previous Alliance not removed + assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); // deposit unreserved assert_eq!(Balances::free_balance(9), 40); - // all proposals are removed - assert_eq!(::ProposalProvider::proposals(), vec![]); - assert_eq!(::ProposalProvider::proposals_count(), 0); - - // assert events - proposals.sort(); - assert_prev_event(mock::Event::Alliance(crate::Event::AllianceDisbanded { - members: vec![1, 3, 9], - proposals, - })); - System::assert_last_event(mock::Event::Alliance(crate::Event::MembersInitialized { - founders: vec![5, 8], - fellows: vec![4], - allies: vec![2], + System::assert_last_event(mock::Event::Alliance(crate::Event::AllianceDisbanded { + voting_members: 2, + ally_members: 1, + unreserved: 1, })); + + // the Alliance must be set first + assert_noop!( + Alliance::disband(Origin::root(), DisbandWitness::new(100, 100)), + Error::::AllianceNotYetInitialized, + ); }) } @@ -588,14 +548,10 @@ fn assert_powerless(user: Origin) { let cid = test_cid(); let (proposal, _, _) = make_kick_member_proposal(42); + assert_noop!(Alliance::init_members(user.clone(), vec![], vec![], vec![],), BadOrigin); + assert_noop!( - Alliance::force_set_members( - user.clone(), - vec![], - vec![], - vec![], - ForceSetWitness { voting_members: 3, ..Default::default() } - ), + Alliance::disband(user.clone(), DisbandWitness { voting_members: 3, ..Default::default() }), BadOrigin ); diff --git a/frame/alliance/src/types.rs b/frame/alliance/src/types.rs index a7fa9f83e4cf3..90f7ce41b9613 100644 --- a/frame/alliance/src/types.rs +++ b/frame/alliance/src/types.rs @@ -94,32 +94,28 @@ impl Cid { } } -/// Witness data for the `force_set_members` call. -/// Relevant only if executed on an initialized alliance to reset it. +/// Witness data for the `disband` call. #[derive( Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo, Default, )] -pub struct ForceSetWitness { - /// Number of active proposals which will be vetoed and removed. - #[codec(compact)] - pub(super) proposals: u32, - /// Total number of voting members in the current alliance. +pub struct DisbandWitness { + /// Total number of voting members in the current Alliance. #[codec(compact)] pub(super) voting_members: u32, - /// Total number of ally members in the current alliance. + /// Total number of ally members in the current Alliance. #[codec(compact)] pub(super) ally_members: u32, } #[cfg(test)] -impl ForceSetWitness { - // Creates new ForceSetWitness. - pub(super) fn new(proposals: u32, voting_members: u32, ally_members: u32) -> Self { - Self { proposals, voting_members, ally_members } +impl DisbandWitness { + // Creates new DisbandWitness. + pub(super) fn new(voting_members: u32, ally_members: u32) -> Self { + Self { voting_members, ally_members } } } -impl ForceSetWitness { +impl DisbandWitness { pub(super) fn is_zero(self) -> bool { self == Self::default() } diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 26946c71bf314..9e2ee5681aa99 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_alliance //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-01, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-09-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -53,7 +53,8 @@ pub trait WeightInfo { fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight; fn close_disapproved(x: u32, y: u32, p: u32, ) -> Weight; fn close_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight; - fn force_set_members(x: u32, y: u32, z: u32, p: u32, c: u32, m: u32, ) -> Weight; + fn init_members(x: u32, y: u32, z: u32, ) -> Weight; + fn disband(x: u32, y: u32, z: u32, ) -> Weight; fn set_rule() -> Weight; fn announce() -> Weight; fn remove_announcement() -> Weight; @@ -80,13 +81,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[0, 90]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(37_864_000 as u64) - // Standard Error: 28_000 - .saturating_add(Weight::from_ref_time(69_000 as u64).saturating_mul(x as u64)) + Weight::from_ref_time(34_420_000 as u64) + // Standard Error: 25_000 + .saturating_add(Weight::from_ref_time(145_000 as u64).saturating_mul(x as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(66_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(y as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(197_000 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -95,9 +96,9 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[3, 10]`. /// The range of component `y` is `[2, 90]`. fn vote(_x: u32, y: u32, ) -> Weight { - Weight::from_ref_time(46_813_000 as u64) + Weight::from_ref_time(48_443_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(125_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(y as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -107,9 +108,9 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - Weight::from_ref_time(35_316_000 as u64) + Weight::from_ref_time(35_056_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(172_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(171_000 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -122,13 +123,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(36_245_000 as u64) - // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(336_000 as u64).saturating_mul(x as u64)) + Weight::from_ref_time(36_929_000 as u64) + // Standard Error: 19_000 + .saturating_add(Weight::from_ref_time(287_000 as u64).saturating_mul(x as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(109_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(105_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(178_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(180_000 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -141,16 +142,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(48_088_000 as u64) + fn close_early_approved(b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + Weight::from_ref_time(48_085_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) - // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(194_000 as u64).saturating_mul(x as u64)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(93_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(100_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(201_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(210_000 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -164,11 +163,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(43_374_000 as u64) + Weight::from_ref_time(43_377_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(101_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(99_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(182_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(190_000 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -182,65 +181,69 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(42_798_000 as u64) + fn close_approved(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { + Weight::from_ref_time(41_417_000 as u64) + // Standard Error: 14_000 + .saturating_add(Weight::from_ref_time(67_000 as u64).saturating_mul(x as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(88_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(196_000 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } - // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: Alliance Members (r:3 w:3) - // Storage: Alliance DepositOf (r:200 w:199) - // Storage: System Account (r:199 w:199) - // Storage: AllianceMotion Voting (r:0 w:100) - // Storage: AllianceMotion Members (r:0 w:1) - // Storage: AllianceMotion Prime (r:0 w:1) - // Storage: AllianceMotion ProposalOf (r:0 w:100) + // Storage: AllianceMotion Members (r:1 w:1) /// The range of component `x` is `[1, 10]`. /// The range of component `y` is `[0, 90]`. /// The range of component `z` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - /// The range of component `c` is `[0, 100]`. - /// The range of component `m` is `[0, 100]`. - fn force_set_members(x: u32, y: u32, z: u32, p: u32, c: u32, m: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 221_000 - .saturating_add(Weight::from_ref_time(1_294_000 as u64).saturating_mul(x as u64)) - // Standard Error: 23_000 - .saturating_add(Weight::from_ref_time(231_000 as u64).saturating_mul(y as u64)) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(z as u64)) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(9_371_000 as u64).saturating_mul(p as u64)) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_673_000 as u64).saturating_mul(c as u64)) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_581_000 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(c as u64))) - .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(m as u64))) + fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { + Weight::from_ref_time(37_202_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(149_000 as u64).saturating_mul(y as u64)) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(120_000 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(p as u64))) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(c as u64))) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(m as u64))) + } + // Storage: Alliance Members (r:3 w:3) + // Storage: AllianceMotion Proposals (r:1 w:0) + // Storage: Alliance DepositOf (r:101 w:50) + // Storage: System Account (r:50 w:50) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + /// The range of component `x` is `[1, 100]`. + /// The range of component `y` is `[0, 100]`. + /// The range of component `z` is `[0, 50]`. + fn disband(x: u32, y: u32, z: u32, ) -> Weight { + Weight::from_ref_time(0 as u64) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(1_447_000 as u64).saturating_mul(x as u64)) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(1_512_000 as u64).saturating_mul(y as u64)) + // Standard Error: 19_000 + .saturating_add(Weight::from_ref_time(10_760_000 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(x as u64))) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(y as u64))) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(z as u64))) + .saturating_add(T::DbWeight::get().writes(5 as u64)) + .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(z as u64))) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - Weight::from_ref_time(18_721_000 as u64) + Weight::from_ref_time(18_101_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - Weight::from_ref_time(21_887_000 as u64) + Weight::from_ref_time(21_090_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - Weight::from_ref_time(23_052_000 as u64) + Weight::from_ref_time(22_118_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -249,14 +252,14 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - Weight::from_ref_time(54_504_000 as u64) + Weight::from_ref_time(53_446_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - Weight::from_ref_time(42_601_000 as u64) + Weight::from_ref_time(42_690_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -265,7 +268,7 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - Weight::from_ref_time(37_704_000 as u64) + Weight::from_ref_time(37_396_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -275,7 +278,7 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - Weight::from_ref_time(40_859_000 as u64) + Weight::from_ref_time(40_644_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -284,7 +287,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - Weight::from_ref_time(43_447_000 as u64) + Weight::from_ref_time(43_440_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -295,7 +298,7 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - Weight::from_ref_time(61_718_000 as u64) + Weight::from_ref_time(61_060_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -304,11 +307,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(359_000 as u64) + Weight::from_ref_time(0 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_376_000 as u64).saturating_mul(n as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(112_000 as u64).saturating_mul(l as u64)) + .saturating_add(Weight::from_ref_time(1_362_000 as u64).saturating_mul(n as u64)) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -318,10 +321,10 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[1, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 145_000 - .saturating_add(Weight::from_ref_time(20_932_000 as u64).saturating_mul(n as u64)) - // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(3_649_000 as u64).saturating_mul(l as u64)) + // Standard Error: 147_000 + .saturating_add(Weight::from_ref_time(21_060_000 as u64).saturating_mul(n as u64)) + // Standard Error: 57_000 + .saturating_add(Weight::from_ref_time(3_683_000 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -339,13 +342,13 @@ impl WeightInfo for () { /// The range of component `y` is `[0, 90]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(37_864_000 as u64) - // Standard Error: 28_000 - .saturating_add(Weight::from_ref_time(69_000 as u64).saturating_mul(x as u64)) + Weight::from_ref_time(34_420_000 as u64) + // Standard Error: 25_000 + .saturating_add(Weight::from_ref_time(145_000 as u64).saturating_mul(x as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(66_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(y as u64)) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(197_000 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -354,9 +357,9 @@ impl WeightInfo for () { /// The range of component `x` is `[3, 10]`. /// The range of component `y` is `[2, 90]`. fn vote(_x: u32, y: u32, ) -> Weight { - Weight::from_ref_time(46_813_000 as u64) + Weight::from_ref_time(48_443_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(125_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(y as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -366,9 +369,9 @@ impl WeightInfo for () { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - Weight::from_ref_time(35_316_000 as u64) + Weight::from_ref_time(35_056_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(172_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(171_000 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -381,13 +384,13 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(36_245_000 as u64) - // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(336_000 as u64).saturating_mul(x as u64)) + Weight::from_ref_time(36_929_000 as u64) + // Standard Error: 19_000 + .saturating_add(Weight::from_ref_time(287_000 as u64).saturating_mul(x as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(109_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(105_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(178_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(180_000 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -400,16 +403,14 @@ impl WeightInfo for () { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(48_088_000 as u64) + fn close_early_approved(b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + Weight::from_ref_time(48_085_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) - // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(194_000 as u64).saturating_mul(x as u64)) + .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(93_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(100_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(201_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(210_000 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -423,11 +424,11 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(43_374_000 as u64) + Weight::from_ref_time(43_377_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(101_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(99_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(182_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(190_000 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -441,65 +442,69 @@ impl WeightInfo for () { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_approved(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(42_798_000 as u64) + fn close_approved(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { + Weight::from_ref_time(41_417_000 as u64) + // Standard Error: 14_000 + .saturating_add(Weight::from_ref_time(67_000 as u64).saturating_mul(x as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(y as u64)) + .saturating_add(Weight::from_ref_time(88_000 as u64).saturating_mul(y as u64)) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + .saturating_add(Weight::from_ref_time(196_000 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } - // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: Alliance Members (r:3 w:3) - // Storage: Alliance DepositOf (r:200 w:199) - // Storage: System Account (r:199 w:199) - // Storage: AllianceMotion Voting (r:0 w:100) - // Storage: AllianceMotion Members (r:0 w:1) - // Storage: AllianceMotion Prime (r:0 w:1) - // Storage: AllianceMotion ProposalOf (r:0 w:100) + // Storage: AllianceMotion Members (r:1 w:1) /// The range of component `x` is `[1, 10]`. /// The range of component `y` is `[0, 90]`. /// The range of component `z` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - /// The range of component `c` is `[0, 100]`. - /// The range of component `m` is `[0, 100]`. - fn force_set_members(x: u32, y: u32, z: u32, p: u32, c: u32, m: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 221_000 - .saturating_add(Weight::from_ref_time(1_294_000 as u64).saturating_mul(x as u64)) - // Standard Error: 23_000 - .saturating_add(Weight::from_ref_time(231_000 as u64).saturating_mul(y as u64)) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(z as u64)) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(9_371_000 as u64).saturating_mul(p as u64)) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_673_000 as u64).saturating_mul(c as u64)) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(11_581_000 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(c as u64))) - .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(m as u64))) + fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { + Weight::from_ref_time(37_202_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(149_000 as u64).saturating_mul(y as u64)) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(120_000 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(p as u64))) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(c as u64))) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(m as u64))) + } + // Storage: Alliance Members (r:3 w:3) + // Storage: AllianceMotion Proposals (r:1 w:0) + // Storage: Alliance DepositOf (r:101 w:50) + // Storage: System Account (r:50 w:50) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + /// The range of component `x` is `[1, 100]`. + /// The range of component `y` is `[0, 100]`. + /// The range of component `z` is `[0, 50]`. + fn disband(x: u32, y: u32, z: u32, ) -> Weight { + Weight::from_ref_time(0 as u64) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(1_447_000 as u64).saturating_mul(x as u64)) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(1_512_000 as u64).saturating_mul(y as u64)) + // Standard Error: 19_000 + .saturating_add(Weight::from_ref_time(10_760_000 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(x as u64))) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(y as u64))) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(z as u64))) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) + .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(z as u64))) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - Weight::from_ref_time(18_721_000 as u64) + Weight::from_ref_time(18_101_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - Weight::from_ref_time(21_887_000 as u64) + Weight::from_ref_time(21_090_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - Weight::from_ref_time(23_052_000 as u64) + Weight::from_ref_time(22_118_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -508,14 +513,14 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - Weight::from_ref_time(54_504_000 as u64) + Weight::from_ref_time(53_446_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - Weight::from_ref_time(42_601_000 as u64) + Weight::from_ref_time(42_690_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -524,7 +529,7 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - Weight::from_ref_time(37_704_000 as u64) + Weight::from_ref_time(37_396_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -534,7 +539,7 @@ impl WeightInfo for () { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - Weight::from_ref_time(40_859_000 as u64) + Weight::from_ref_time(40_644_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } @@ -543,7 +548,7 @@ impl WeightInfo for () { // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - Weight::from_ref_time(43_447_000 as u64) + Weight::from_ref_time(43_440_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -554,7 +559,7 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - Weight::from_ref_time(61_718_000 as u64) + Weight::from_ref_time(61_060_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } @@ -563,11 +568,11 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 100]`. /// The range of component `l` is `[1, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(359_000 as u64) + Weight::from_ref_time(0 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_376_000 as u64).saturating_mul(n as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(112_000 as u64).saturating_mul(l as u64)) + .saturating_add(Weight::from_ref_time(1_362_000 as u64).saturating_mul(n as u64)) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -577,10 +582,10 @@ impl WeightInfo for () { /// The range of component `l` is `[1, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 145_000 - .saturating_add(Weight::from_ref_time(20_932_000 as u64).saturating_mul(n as u64)) - // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(3_649_000 as u64).saturating_mul(l as u64)) + // Standard Error: 147_000 + .saturating_add(Weight::from_ref_time(21_060_000 as u64).saturating_mul(n as u64)) + // Standard Error: 57_000 + .saturating_add(Weight::from_ref_time(3_683_000 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } From e24e9ad5855daef00f64a652ef70ac3848850d56 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 5 Sep 2022 19:41:32 +0200 Subject: [PATCH 1126/1472] Fetch Babe configuration from runtime state (#11760) * Fetch babe config data from runtime state * Some renaming * More renaming * Final nits * Fix tests and benches * Rename to in BabeConfiguration * Remove duplicate babe parameter description Already specified over the 'PRIMARY_PROBABILITY' constant value * trigger pipeline * trigger pipeline --- bin/node/cli/src/service.rs | 7 +- bin/node/rpc/src/lib.rs | 4 +- bin/node/runtime/src/lib.rs | 16 +-- client/consensus/babe/rpc/src/lib.rs | 18 +-- client/consensus/babe/src/aux_schema.rs | 10 +- client/consensus/babe/src/lib.rs | 120 +++++++----------- client/consensus/babe/src/migration.rs | 4 +- client/consensus/babe/src/tests.rs | 33 +++-- client/consensus/manual-seal/src/consensus.rs | 2 +- .../manual-seal/src/consensus/babe.rs | 18 +-- .../manual-seal/src/consensus/timestamp.rs | 2 +- frame/babe/src/lib.rs | 1 + primitives/consensus/babe/src/lib.rs | 33 +++-- test-utils/runtime/src/lib.rs | 12 +- 14 files changed, 125 insertions(+), 155 deletions(-) diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index b20a3ac59a96a..13003c1a7a41f 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -199,7 +199,7 @@ pub fn new_partial( let justification_import = grandpa_block_import.clone(); let (block_import, babe_link) = sc_consensus_babe::block_import( - sc_consensus_babe::Config::get(&*client)?, + sc_consensus_babe::configuration(&*client)?, grandpa_block_import, client.clone(), )?; @@ -682,10 +682,7 @@ mod tests { .epoch_changes() .shared_data() .epoch_data(&epoch_descriptor, |slot| { - sc_consensus_babe::Epoch::genesis( - babe_link.config().genesis_config(), - slot, - ) + sc_consensus_babe::Epoch::genesis(babe_link.config(), slot) }) .unwrap(); diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index e5b666195e1bc..1c8b9cce1a744 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -36,7 +36,7 @@ use std::sync::Arc; use jsonrpsee::RpcModule; use node_primitives::{AccountId, Balance, Block, BlockNumber, Hash, Index}; use sc_client_api::AuxStore; -use sc_consensus_babe::{Config, Epoch}; +use sc_consensus_babe::{BabeConfiguration, Epoch}; use sc_consensus_epochs::SharedEpochChanges; use sc_finality_grandpa::{ FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState, @@ -54,7 +54,7 @@ use sp_keystore::SyncCryptoStorePtr; /// Extra dependencies for BABE. pub struct BabeDeps { /// BABE protocol config. - pub babe_config: Config, + pub babe_config: BabeConfiguration, /// BABE pending epoch changes. pub shared_epoch_changes: SharedEpochChanges, /// The keystore that manages the keys of the node. diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index fa0f877c5938d..5aa488f328a5e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1859,19 +1859,15 @@ impl_runtime_apis! { } impl sp_consensus_babe::BabeApi for Runtime { - fn configuration() -> sp_consensus_babe::BabeGenesisConfiguration { - // 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::BabeGenesisConfiguration { + fn configuration() -> sp_consensus_babe::BabeConfiguration { + let epoch_config = Babe::epoch_config().unwrap_or(BABE_GENESIS_EPOCH_CONFIG); + sp_consensus_babe::BabeConfiguration { slot_duration: Babe::slot_duration(), epoch_length: EpochDuration::get(), - c: BABE_GENESIS_EPOCH_CONFIG.c, - genesis_authorities: Babe::authorities().to_vec(), + c: epoch_config.c, + authorities: Babe::authorities().to_vec(), randomness: Babe::randomness(), - allowed_slots: BABE_GENESIS_EPOCH_CONFIG.allowed_slots, + allowed_slots: epoch_config.allowed_slots, } } diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index b000d38a44f02..288f852a5c989 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -25,7 +25,7 @@ use jsonrpsee::{ types::{error::CallError, ErrorObject}, }; -use sc_consensus_babe::{authorship, Config, Epoch}; +use sc_consensus_babe::{authorship, Epoch}; use sc_consensus_epochs::{descendent_query, Epoch as EpochT, SharedEpochChanges}; use sc_rpc_api::DenyUnsafe; use serde::{Deserialize, Serialize}; @@ -33,7 +33,9 @@ use sp_api::{BlockId, ProvideRuntimeApi}; use sp_application_crypto::AppKey; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_consensus::{Error as ConsensusError, SelectChain}; -use sp_consensus_babe::{digests::PreDigest, AuthorityId, BabeApi as BabeRuntimeApi}; +use sp_consensus_babe::{ + digests::PreDigest, AuthorityId, BabeApi as BabeRuntimeApi, BabeConfiguration, +}; use sp_core::crypto::ByteArray; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::traits::{Block as BlockT, Header as _}; @@ -57,7 +59,7 @@ pub struct Babe { /// shared reference to the Keystore keystore: SyncCryptoStorePtr, /// config (actually holds the slot duration) - babe_config: Config, + babe_config: BabeConfiguration, /// The SelectChain strategy select_chain: SC, /// Whether to deny unsafe calls @@ -70,7 +72,7 @@ impl Babe { client: Arc, shared_epoch_changes: SharedEpochChanges, keystore: SyncCryptoStorePtr, - babe_config: Config, + babe_config: BabeConfiguration, select_chain: SC, deny_unsafe: DenyUnsafe, ) -> Self { @@ -185,7 +187,7 @@ impl From for JsonRpseeError { async fn epoch_data( epoch_changes: &SharedEpochChanges, client: &Arc, - babe_config: &Config, + babe_config: &BabeConfiguration, slot: u64, select_chain: &SC, ) -> Result @@ -202,7 +204,7 @@ where &parent.hash(), *parent.number(), slot.into(), - |slot| Epoch::genesis(babe_config.genesis_config(), slot), + |slot| Epoch::genesis(babe_config, slot), ) .map_err(|e| Error::Consensus(ConsensusError::ChainLookup(e.to_string())))? .ok_or(Error::Consensus(ConsensusError::InvalidAuthoritiesSet)) @@ -221,7 +223,7 @@ mod tests { TestClientBuilderExt, }; - use sc_consensus_babe::{block_import, AuthorityPair, Config}; + use sc_consensus_babe::{block_import, AuthorityPair}; use std::sync::Arc; /// creates keystore backed by a temp file @@ -243,7 +245,7 @@ mod tests { let builder = TestClientBuilder::new(); let (client, longest_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); - let config = Config::get(&*client).expect("config available"); + let config = sc_consensus_babe::configuration(&*client).expect("config available"); let (_, link) = block_import(config.clone(), client.clone(), client.clone()) .expect("can initialize block-import"); diff --git a/client/consensus/babe/src/aux_schema.rs b/client/consensus/babe/src/aux_schema.rs index 2ab84b9b132cc..fef84bda86974 100644 --- a/client/consensus/babe/src/aux_schema.rs +++ b/client/consensus/babe/src/aux_schema.rs @@ -28,7 +28,7 @@ use sc_consensus_epochs::{ EpochChangesFor, SharedEpochChanges, }; use sp_blockchain::{Error as ClientError, Result as ClientResult}; -use sp_consensus_babe::{BabeBlockWeight, BabeGenesisConfiguration}; +use sp_consensus_babe::{BabeBlockWeight, BabeConfiguration}; use sp_runtime::traits::Block as BlockT; const BABE_EPOCH_CHANGES_VERSION: &[u8] = b"babe_epoch_changes_version"; @@ -57,7 +57,7 @@ where /// Load or initialize persistent epoch change data from backend. pub fn load_epoch_changes( backend: &B, - config: &BabeGenesisConfiguration, + config: &BabeConfiguration, ) -> ClientResult> { let version = load_decode::<_, u32>(backend, BABE_EPOCH_CHANGES_VERSION)?; @@ -143,7 +143,7 @@ mod test { use sc_consensus_epochs::{EpochHeader, PersistedEpoch, PersistedEpochHeader}; use sc_network_test::Block as TestBlock; use sp_consensus::Error as ConsensusError; - use sp_consensus_babe::{AllowedSlots, BabeGenesisConfiguration}; + use sp_consensus_babe::AllowedSlots; use sp_core::H256; use sp_runtime::traits::NumberFor; use substrate_test_runtime_client; @@ -182,11 +182,11 @@ mod test { let epoch_changes = load_epoch_changes::( &client, - &BabeGenesisConfiguration { + &BabeConfiguration { slot_duration: 10, epoch_length: 4, c: (3, 10), - genesis_authorities: Vec::new(), + authorities: Vec::new(), randomness: Default::default(), allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, }, diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index f61ba23d920f3..1303915efee49 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -119,7 +119,7 @@ use sp_consensus::{ SelectChain, }; use sp_consensus_babe::inherents::BabeInherentData; -use sp_consensus_slots::{Slot, SlotDuration}; +use sp_consensus_slots::Slot; use sp_core::{crypto::ByteArray, ExecutionContext}; use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; @@ -137,8 +137,7 @@ pub use sp_consensus_babe::{ PrimaryPreDigest, SecondaryPlainPreDigest, }, AuthorityId, AuthorityPair, AuthoritySignature, BabeApi, BabeAuthorityWeight, BabeBlockWeight, - BabeEpochConfiguration, BabeGenesisConfiguration, ConsensusLog, BABE_ENGINE_ID, - VRF_OUTPUT_LENGTH, + BabeConfiguration, BabeEpochConfiguration, ConsensusLog, BABE_ENGINE_ID, VRF_OUTPUT_LENGTH, }; pub use aux_schema::load_block_weight as block_weight; @@ -211,12 +210,12 @@ impl From for Epoch { impl Epoch { /// Create the genesis epoch (epoch #0). This is defined to start at the slot of /// the first block, so that has to be provided. - pub fn genesis(genesis_config: &BabeGenesisConfiguration, slot: Slot) -> Epoch { + pub fn genesis(genesis_config: &BabeConfiguration, slot: Slot) -> Epoch { Epoch { epoch_index: 0, start_slot: slot, duration: genesis_config.epoch_length, - authorities: genesis_config.genesis_authorities.clone(), + authorities: genesis_config.authorities.clone(), randomness: genesis_config.randomness, config: BabeEpochConfiguration { c: genesis_config.c, @@ -338,56 +337,36 @@ pub struct BabeIntermediate { /// Intermediate key for Babe engine. pub static INTERMEDIATE_KEY: &[u8] = b"babe1"; -/// Configuration for BABE used for defining block verification parameters as -/// well as authoring (e.g. the slot duration). -#[derive(Clone)] -pub struct Config { - genesis_config: BabeGenesisConfiguration, -} - -impl Config { - /// Create a new config by reading the genesis configuration from the runtime. - pub fn get(client: &C) -> ClientResult - where - C: AuxStore + ProvideRuntimeApi + UsageProvider, - C::Api: BabeApi, - { - trace!(target: "babe", "Getting slot duration"); - - let mut best_block_id = BlockId::Hash(client.usage_info().chain.best_hash); - if client.usage_info().chain.finalized_state.is_none() { - debug!(target: "babe", "No finalized state is available. Reading config from genesis"); - best_block_id = BlockId::Hash(client.usage_info().chain.genesis_hash); - } - let runtime_api = client.runtime_api(); +/// Read configuration from the runtime state at current best block. +pub fn configuration(client: &C) -> ClientResult +where + C: AuxStore + ProvideRuntimeApi + UsageProvider, + C::Api: BabeApi, +{ + let block_id = if client.usage_info().chain.finalized_state.is_some() { + BlockId::Hash(client.usage_info().chain.best_hash) + } else { + debug!(target: "babe", "No finalized state is available. Reading config from genesis"); + BlockId::Hash(client.usage_info().chain.genesis_hash) + }; - let version = runtime_api.api_version::>(&best_block_id)?; + let runtime_api = client.runtime_api(); + let version = runtime_api.api_version::>(&block_id)?; - let genesis_config = if version == Some(1) { + let config = match version { + Some(1) => { #[allow(deprecated)] { - runtime_api.configuration_before_version_2(&best_block_id)?.into() + runtime_api.configuration_before_version_2(&block_id)?.into() } - } else if version == Some(2) { - runtime_api.configuration(&best_block_id)? - } else { + }, + Some(2) => runtime_api.configuration(&block_id)?, + _ => return Err(sp_blockchain::Error::VersionInvalid( "Unsupported or invalid BabeApi version".to_string(), - )) - }; - - Ok(Config { genesis_config }) - } - - /// Get the genesis configuration. - pub fn genesis_config(&self) -> &BabeGenesisConfiguration { - &self.genesis_config - } - - /// Get the slot duration defined in the genesis configuration. - pub fn slot_duration(&self) -> SlotDuration { - SlotDuration::from_millis(self.genesis_config.slot_duration) - } + )), + }; + Ok(config) } /// Parameters for BABE. @@ -611,7 +590,7 @@ fn aux_storage_cleanup + HeaderBackend, Block: B async fn answer_requests( mut request_rx: Receiver>, - config: Config, + config: BabeConfiguration, client: Arc, epoch_changes: SharedEpochChanges, ) where @@ -640,9 +619,7 @@ async fn answer_requests( .ok_or(Error::::FetchEpoch(parent_hash))?; let viable_epoch = epoch_changes - .viable_epoch(&epoch_descriptor, |slot| { - Epoch::genesis(&config.genesis_config, slot) - }) + .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&config, slot)) .ok_or(Error::::FetchEpoch(parent_hash))?; Ok(sp_consensus_babe::Epoch { @@ -739,7 +716,7 @@ struct BabeSlotWorker { keystore: SyncCryptoStorePtr, epoch_changes: SharedEpochChanges, slot_notification_sinks: SlotNotificationSinks, - config: Config, + config: BabeConfiguration, block_proposal_slot_portion: SlotProportion, max_block_proposal_slot_portion: Option, telemetry: Option, @@ -797,9 +774,7 @@ where fn authorities_len(&self, epoch_descriptor: &Self::EpochData) -> Option { self.epoch_changes .shared_data() - .viable_epoch(epoch_descriptor, |slot| { - Epoch::genesis(&self.config.genesis_config, slot) - }) + .viable_epoch(epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) .map(|epoch| epoch.as_ref().authorities.len()) } @@ -814,9 +789,7 @@ where slot, self.epoch_changes .shared_data() - .viable_epoch(epoch_descriptor, |slot| { - Epoch::genesis(&self.config.genesis_config, slot) - })? + .viable_epoch(epoch_descriptor, |slot| Epoch::genesis(&self.config, slot))? .as_ref(), &self.keystore, ); @@ -1020,7 +993,7 @@ fn find_next_config_digest( #[derive(Clone)] pub struct BabeLink { epoch_changes: SharedEpochChanges, - config: Config, + config: BabeConfiguration, } impl BabeLink { @@ -1030,7 +1003,7 @@ impl BabeLink { } /// Get the config of this link. - pub fn config(&self) -> &Config { + pub fn config(&self) -> &BabeConfiguration { &self.config } } @@ -1040,7 +1013,7 @@ pub struct BabeVerifier { client: Arc, select_chain: SelectChain, create_inherent_data_providers: CIDP, - config: Config, + config: BabeConfiguration, epoch_changes: SharedEpochChanges, can_author_with: CAW, telemetry: Option, @@ -1245,9 +1218,7 @@ where .map_err(|e| Error::::ForkTree(Box::new(e)))? .ok_or(Error::::FetchEpoch(parent_hash))?; let viable_epoch = epoch_changes - .viable_epoch(&epoch_descriptor, |slot| { - Epoch::genesis(&self.config.genesis_config, slot) - }) + .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) .ok_or(Error::::FetchEpoch(parent_hash))?; // We add one to the current slot to allow for some small drift. @@ -1353,7 +1324,7 @@ pub struct BabeBlockImport { inner: I, client: Arc, epoch_changes: SharedEpochChanges, - config: Config, + config: BabeConfiguration, } impl Clone for BabeBlockImport { @@ -1372,7 +1343,7 @@ impl BabeBlockImport { client: Arc, epoch_changes: SharedEpochChanges, block_import: I, - config: Config, + config: BabeConfiguration, ) -> Self { BabeBlockImport { client, inner: block_import, epoch_changes, config } } @@ -1580,9 +1551,7 @@ where old_epoch_changes = Some((*epoch_changes).clone()); let viable_epoch = epoch_changes - .viable_epoch(&epoch_descriptor, |slot| { - Epoch::genesis(&self.config.genesis_config, slot) - }) + .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) .ok_or_else(|| { ConsensusError::ClientImport(Error::::FetchEpoch(parent_hash).into()) })?; @@ -1761,7 +1730,7 @@ where /// Also returns a link object used to correctly instantiate the import queue /// and background worker. pub fn block_import( - config: Config, + config: BabeConfiguration, wrapped_block_import: I, client: Arc, ) -> ClientResult<(BabeBlockImport, BabeLink)> @@ -1772,8 +1741,7 @@ where + PreCommitActions + 'static, { - let epoch_changes = - aux_schema::load_epoch_changes::(&*client, &config.genesis_config)?; + let epoch_changes = aux_schema::load_epoch_changes::(&*client, &config)?; let link = BabeLink { epoch_changes: epoch_changes.clone(), config: config.clone() }; // NOTE: this isn't entirely necessary, but since we didn't use to prune the @@ -1884,9 +1852,9 @@ where // Revert epoch changes tree. - let config = Config::get(&*client)?; - let epoch_changes = - aux_schema::load_epoch_changes::(&*client, config.genesis_config())?; + // This config is only used on-genesis. + let config = configuration(&*client)?; + let epoch_changes = aux_schema::load_epoch_changes::(&*client, &config)?; let mut epoch_changes = epoch_changes.shared_data(); if revert_up_to_number == Zero::zero() { diff --git a/client/consensus/babe/src/migration.rs b/client/consensus/babe/src/migration.rs index a8c3772bbefb8..23413aa6a7b1b 100644 --- a/client/consensus/babe/src/migration.rs +++ b/client/consensus/babe/src/migration.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::{ - AuthorityId, BabeAuthorityWeight, BabeEpochConfiguration, BabeGenesisConfiguration, Epoch, + AuthorityId, BabeAuthorityWeight, BabeConfiguration, BabeEpochConfiguration, Epoch, NextEpochDescriptor, VRF_OUTPUT_LENGTH, }; use codec::{Decode, Encode}; @@ -64,7 +64,7 @@ impl EpochT for EpochV0 { impl EpochV0 { /// Migrate the sturct to current epoch version. - pub fn migrate(self, config: &BabeGenesisConfiguration) -> Epoch { + pub fn migrate(self, config: &BabeConfiguration) -> Epoch { Epoch { epoch_index: self.epoch_index, start_slot: self.start_slot, diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 5ecdb42f7f177..7207b7a36c3d4 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -36,6 +36,7 @@ use sp_consensus_babe::{ inherents::InherentDataProvider, make_transcript, make_transcript_data, AllowedSlots, AuthorityPair, Slot, }; +use sp_consensus_slots::SlotDuration; use sp_core::crypto::Pair; use sp_keystore::{vrf::make_transcript as transcript_from_data, SyncCryptoStore}; use sp_runtime::{ @@ -71,7 +72,7 @@ type BabeBlockImport = struct DummyFactory { client: Arc, epoch_changes: SharedEpochChanges, - config: Config, + config: BabeConfiguration, mutator: Mutator, } @@ -139,7 +140,7 @@ impl DummyProposer { &self.parent_hash, self.parent_number, this_slot, - |slot| Epoch::genesis(self.factory.config.genesis_config(), slot), + |slot| Epoch::genesis(&self.factory.config, slot), ) .expect("client has data to find epoch") .expect("can compute epoch for baked block"); @@ -288,7 +289,7 @@ impl TestNetFactory for BabeTestNet { ) { let client = client.as_client(); - let config = Config::get(&*client).expect("config available"); + let config = crate::configuration(&*client).expect("config available"); let (block_import, link) = crate::block_import(config, client.clone(), client.clone()) .expect("can initialize block-import"); @@ -559,11 +560,11 @@ fn can_author_block() { }, }; - let mut config = crate::BabeGenesisConfiguration { + let mut config = crate::BabeConfiguration { slot_duration: 1000, epoch_length: 100, c: (3, 10), - genesis_authorities: Vec::new(), + authorities: Vec::new(), randomness: [0; 32], allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, }; @@ -708,12 +709,12 @@ fn importing_block_one_sets_genesis_epoch() { &mut block_import, ); - let genesis_epoch = Epoch::genesis(data.link.config.genesis_config(), 999.into()); + let genesis_epoch = Epoch::genesis(&data.link.config, 999.into()); let epoch_changes = data.link.epoch_changes.shared_data(); let epoch_for_second_block = epoch_changes .epoch_data_for_child_of(descendent_query(&*client), &block_hash, 1, 1000.into(), |slot| { - Epoch::genesis(data.link.config.genesis_config(), slot) + Epoch::genesis(&data.link.config, slot) }) .unwrap() .unwrap(); @@ -771,16 +772,14 @@ fn revert_prunes_epoch_changes_and_removes_weights() { // Load and check epoch changes. - let actual_nodes = aux_schema::load_epoch_changes::( - &*client, - data.link.config.genesis_config(), - ) - .expect("load epoch changes") - .shared_data() - .tree() - .iter() - .map(|(h, _, _)| *h) - .collect::>(); + let actual_nodes = + aux_schema::load_epoch_changes::(&*client, &data.link.config) + .expect("load epoch changes") + .shared_data() + .tree() + .iter() + .map(|(h, _, _)| *h) + .collect::>(); let expected_nodes = vec![ canon[0], // A diff --git a/client/consensus/manual-seal/src/consensus.rs b/client/consensus/manual-seal/src/consensus.rs index b5dfc3d809c13..a812bb028c7f2 100644 --- a/client/consensus/manual-seal/src/consensus.rs +++ b/client/consensus/manual-seal/src/consensus.rs @@ -39,7 +39,7 @@ pub trait ConsensusDataProvider: Send + Sync { /// Attempt to create a consensus digest. fn create_digest(&self, parent: &B::Header, inherents: &InherentData) -> Result; - /// set up the neccessary import params. + /// Set up the necessary import params. fn append_block_import( &self, parent: &B::Header, diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index cc73a3fa961ce..300a96695c90a 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -24,8 +24,7 @@ use crate::Error; use codec::Encode; use sc_client_api::{AuxStore, UsageProvider}; use sc_consensus_babe::{ - authorship, find_pre_digest, BabeIntermediate, CompatibleDigestItem, Config, Epoch, - INTERMEDIATE_KEY, + authorship, find_pre_digest, BabeIntermediate, CompatibleDigestItem, Epoch, INTERMEDIATE_KEY, }; use sc_consensus_epochs::{ descendent_query, EpochHeader, SharedEpochChanges, ViableEpochDescriptor, @@ -40,7 +39,7 @@ use sp_consensus::CacheKeyId; use sp_consensus_babe::{ digests::{NextEpochDescriptor, PreDigest, SecondaryPlainPreDigest}, inherents::BabeInherentData, - AuthorityId, BabeApi, BabeAuthorityWeight, ConsensusLog, BABE_ENGINE_ID, + AuthorityId, BabeApi, BabeAuthorityWeight, BabeConfiguration, ConsensusLog, BABE_ENGINE_ID, }; use sp_consensus_slots::Slot; use sp_inherents::InherentData; @@ -64,7 +63,10 @@ pub struct BabeConsensusDataProvider { epoch_changes: SharedEpochChanges, /// BABE config, gotten from the runtime. - config: Config, + /// NOTE: This is used to fetch `slot_duration` and `epoch_length` in the + /// `ConsensusDataProvider` implementation. Correct as far as these values + /// are not changed during an epoch change. + config: BabeConfiguration, /// Authorities to be used for this babe chain. authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, @@ -152,7 +154,7 @@ where return Err(Error::StringError("Cannot supply empty authority set!".into())) } - let config = Config::get(&*client)?; + let config = sc_consensus_babe::configuration(&*client)?; Ok(Self { config, @@ -177,9 +179,7 @@ where .ok_or(sp_consensus::Error::InvalidAuthoritiesSet)?; let epoch = epoch_changes - .viable_epoch(&epoch_descriptor, |slot| { - Epoch::genesis(self.config.genesis_config(), slot) - }) + .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) .ok_or_else(|| { log::info!(target: "babe", "create_digest: no viable_epoch :("); sp_consensus::Error::InvalidAuthoritiesSet @@ -306,7 +306,7 @@ where identifier, EpochHeader { start_slot: slot, - end_slot: (*slot * self.config.genesis_config().epoch_length).into(), + end_slot: (*slot * self.config.epoch_length).into(), }, ), _ => unreachable!( diff --git a/client/consensus/manual-seal/src/consensus/timestamp.rs b/client/consensus/manual-seal/src/consensus/timestamp.rs index 70b5e5de4ec6c..f899b80d6c9af 100644 --- a/client/consensus/manual-seal/src/consensus/timestamp.rs +++ b/client/consensus/manual-seal/src/consensus/timestamp.rs @@ -63,7 +63,7 @@ impl SlotTimestampProvider { C: AuxStore + HeaderBackend + ProvideRuntimeApi + UsageProvider, C::Api: BabeApi, { - let slot_duration = sc_consensus_babe::Config::get(&*client)?.slot_duration(); + let slot_duration = sc_consensus_babe::configuration(&*client)?.slot_duration(); let time = Self::with_header(&client, slot_duration, |header| { let slot_number = *sc_consensus_babe::find_pre_digest::(&header) diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 48ca62a5b1a09..9a99d8ed995ab 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -306,6 +306,7 @@ pub mod pallet { /// The configuration for the current epoch. Should never be `None` as it is initialized in /// genesis. #[pallet::storage] + #[pallet::getter(fn epoch_config)] pub(super) type EpochConfig = StorageValue<_, BabeEpochConfiguration>; /// The configuration for the next epoch, `None` if the config will not change diff --git a/primitives/consensus/babe/src/lib.rs b/primitives/consensus/babe/src/lib.rs index 492d1a9a7238f..621ab859b914f 100644 --- a/primitives/consensus/babe/src/lib.rs +++ b/primitives/consensus/babe/src/lib.rs @@ -137,7 +137,7 @@ pub enum ConsensusLog { /// Configuration data used by the BABE consensus engine. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] -pub struct BabeGenesisConfigurationV1 { +pub struct BabeConfigurationV1 { /// The slot duration in milliseconds for BABE. Currently, only /// the value provided by this type at genesis will be used. /// @@ -156,7 +156,7 @@ pub struct BabeGenesisConfigurationV1 { pub c: (u64, u64), /// The authorities for the genesis epoch. - pub genesis_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, + pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, /// The randomness for the genesis epoch. pub randomness: Randomness, @@ -166,13 +166,13 @@ pub struct BabeGenesisConfigurationV1 { pub secondary_slots: bool, } -impl From for BabeGenesisConfiguration { - fn from(v1: BabeGenesisConfigurationV1) -> Self { +impl From for BabeConfiguration { + fn from(v1: BabeConfigurationV1) -> Self { Self { slot_duration: v1.slot_duration, epoch_length: v1.epoch_length, c: v1.c, - genesis_authorities: v1.genesis_authorities, + authorities: v1.authorities, randomness: v1.randomness, allowed_slots: if v1.secondary_slots { AllowedSlots::PrimaryAndSecondaryPlainSlots @@ -185,7 +185,7 @@ impl From for BabeGenesisConfiguration { /// Configuration data used by the BABE consensus engine. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] -pub struct BabeGenesisConfiguration { +pub struct BabeConfiguration { /// The slot duration in milliseconds for BABE. Currently, only /// the value provided by this type at genesis will be used. /// @@ -203,16 +203,23 @@ pub struct BabeGenesisConfiguration { /// of a slot being empty. pub c: (u64, u64), - /// The authorities for the genesis epoch. - pub genesis_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, + /// The authorities + pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, - /// The randomness for the genesis epoch. + /// The randomness pub randomness: Randomness, /// Type of allowed slots. pub allowed_slots: AllowedSlots, } +impl BabeConfiguration { + /// Convenience method to get the slot duration as a `SlotDuration` value. + pub fn slot_duration(&self) -> SlotDuration { + SlotDuration::from_millis(self.slot_duration) + } +} + /// Types of allowed slots. #[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] @@ -237,7 +244,7 @@ impl AllowedSlots { } } -/// Configuration data used by the BABE consensus engine. +/// Configuration data used by the BABE consensus engine that may change with epochs. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct BabeEpochConfiguration { @@ -357,12 +364,12 @@ sp_api::decl_runtime_apis! { /// API necessary for block authorship with BABE. #[api_version(2)] pub trait BabeApi { - /// Return the genesis configuration for BABE. The configuration is only read on genesis. - fn configuration() -> BabeGenesisConfiguration; + /// Return the configuration for BABE. + fn configuration() -> BabeConfiguration; /// Return the configuration for BABE. Version 1. #[changed_in(2)] - fn configuration() -> BabeGenesisConfigurationV1; + fn configuration() -> BabeConfigurationV1; /// Returns the slot that started the current epoch. fn current_epoch_start() -> Slot; diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 181e3fec62b24..bb526010dddd5 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -849,12 +849,12 @@ cfg_if! { } impl sp_consensus_babe::BabeApi for Runtime { - fn configuration() -> sp_consensus_babe::BabeGenesisConfiguration { - sp_consensus_babe::BabeGenesisConfiguration { + fn configuration() -> sp_consensus_babe::BabeConfiguration { + sp_consensus_babe::BabeConfiguration { slot_duration: 1000, epoch_length: EpochDuration::get(), c: (3, 10), - genesis_authorities: system::authorities() + authorities: system::authorities() .into_iter().map(|x|(x, 1)).collect(), randomness: >::randomness(), allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, @@ -1123,12 +1123,12 @@ cfg_if! { } impl sp_consensus_babe::BabeApi for Runtime { - fn configuration() -> sp_consensus_babe::BabeGenesisConfiguration { - sp_consensus_babe::BabeGenesisConfiguration { + fn configuration() -> sp_consensus_babe::BabeConfiguration { + sp_consensus_babe::BabeConfiguration { slot_duration: 1000, epoch_length: EpochDuration::get(), c: (3, 10), - genesis_authorities: system::authorities() + authorities: system::authorities() .into_iter().map(|x|(x, 1)).collect(), randomness: >::randomness(), allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, From 6bdf4c0f8c5b977b3b21ce6302798f6b7df2491d Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 6 Sep 2022 08:34:29 +0200 Subject: [PATCH 1127/1472] [Fix] Make sure pool metadata is removed on pool dissolve (#12154) * [Fix] Make sure pool metadata is removed on pool dissolve * add migration * remove_metadata helper removed * fix typo and add a comment * fix pre_upgrade * fix migration * Update frame/nomination-pools/src/migration.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/src/migration.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * address comments * fix comments * Update frame/nomination-pools/src/migration.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * address comments * permissions fix Co-authored-by: parity-processbot <> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/nomination-pools/src/lib.rs | 12 +++-- frame/nomination-pools/src/migration.rs | 65 +++++++++++++++++++++++++ frame/nomination-pools/src/mock.rs | 2 +- frame/nomination-pools/src/tests.rs | 11 ++++- 4 files changed, 83 insertions(+), 7 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 3809a70440d27..a8c4e50daa0b5 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1141,7 +1141,7 @@ pub mod pallet { use sp_runtime::traits::CheckedAdd; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] @@ -2191,8 +2191,8 @@ impl Pallet { } /// Remove everything related to the given bonded pool. /// - /// All sub-pools are also deleted. All accounts are dusted and the leftover of the reward - /// account is returned to the depositor. + /// Metadata and all of the sub-pools are also deleted. All accounts are dusted and the leftover + /// of the reward account is returned to the depositor. pub fn dissolve_pool(bonded_pool: BondedPool) { let reward_account = bonded_pool.reward_account(); let bonded_account = bonded_pool.bonded_account(); @@ -2229,6 +2229,9 @@ impl Pallet { T::Currency::make_free_balance_be(&bonded_pool.bonded_account(), Zero::zero()); Self::deposit_event(Event::::Destroyed { pool_id: bonded_pool.id }); + // Remove bonded pool metadata. + Metadata::::remove(bonded_pool.id); + bonded_pool.remove(); } @@ -2406,8 +2409,7 @@ impl Pallet { let reward_pools = RewardPools::::iter_keys().collect::>(); assert_eq!(bonded_pools, reward_pools); - // TODO: can't check this right now: https://github.com/paritytech/substrate/issues/12077 - // assert!(Metadata::::iter_keys().all(|k| bonded_pools.contains(&k))); + assert!(Metadata::::iter_keys().all(|k| bonded_pools.contains(&k))); assert!(SubPoolsStorage::::iter_keys().all(|k| bonded_pools.contains(&k))); assert!(MaxPools::::get().map_or(true, |max| bonded_pools.len() <= (max as usize))); diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index 412c954a2bbf3..bcf23ee863a39 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -100,6 +100,7 @@ pub mod v1 { fn post_upgrade() -> Result<(), &'static str> { // new version must be set. assert_eq!(Pallet::::on_chain_storage_version(), 1); + Pallet::::try_state(frame_system::Pallet::::block_number())?; Ok(()) } } @@ -384,3 +385,67 @@ pub mod v2 { } } } + +pub mod v3 { + use super::*; + + /// This migration removes stale bonded-pool metadata, if any. + pub struct MigrateToV3(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV3 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); + + log!( + info, + "Running migration with current storage version {:?} / onchain {:?}", + current, + onchain + ); + + if current > onchain { + let mut metadata_iterated = 0u64; + let mut metadata_removed = 0u64; + Metadata::::iter_keys() + .filter(|id| { + metadata_iterated += 1; + !BondedPools::::contains_key(&id) + }) + .collect::>() + .into_iter() + .for_each(|id| { + metadata_removed += 1; + Metadata::::remove(&id); + }); + current.put::>(); + // metadata iterated + bonded pools read + a storage version read + let total_reads = metadata_iterated * 2 + 1; + // metadata removed + a storage version write + let total_writes = metadata_removed + 1; + T::DbWeight::get().reads_writes(total_reads, total_writes) + } else { + log!(info, "MigrateToV3 should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + ensure!( + Pallet::::current_storage_version() > Pallet::::on_chain_storage_version(), + "the on_chain version is equal or more than the current one" + ); + Ok(()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + ensure!( + Metadata::::iter_keys().all(|id| BondedPools::::contains_key(&id)), + "not all of the stale metadata has been removed" + ); + ensure!(Pallet::::on_chain_storage_version() == 3, "wrong storage version"); + Ok(()) + } + } +} diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 3bb260e56f180..4428c28558f18 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -290,7 +290,7 @@ impl ExtBuilder { let amount_to_bond = Pools::depositor_min_bond(); Balances::make_free_balance_be(&10, amount_to_bond * 5); assert_ok!(Pools::create(RawOrigin::Signed(10).into(), amount_to_bond, 900, 901, 902)); - + assert_ok!(Pools::set_metadata(Origin::signed(900), 1, vec![1, 1])); let last_pool = LastPoolId::::get(); for (account_id, bonded) in self.members { Balances::make_free_balance_be(&account_id, bonded * 2); diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 705f8ce3a6449..20ba2b76fe31a 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -47,6 +47,7 @@ fn test_setup_works() { assert_eq!(SubPoolsStorage::::count(), 0); assert_eq!(PoolMembers::::count(), 1); assert_eq!(StakingMock::bonding_duration(), 3); + assert!(Metadata::::contains_key(1)); let last_pool = LastPoolId::::get(); assert_eq!( @@ -1928,6 +1929,7 @@ mod claim_payout { ] ); + assert!(!Metadata::::contains_key(1)); // original ed + ed put into reward account + reward + bond + dust. assert_eq!(Balances::free_balance(&10), 35 + 5 + 13 + 10 + 1); }) @@ -3159,6 +3161,7 @@ mod withdraw_unbonded { Event::Destroyed { pool_id: 1 } ] ); + assert!(!Metadata::::contains_key(1)); assert_eq!( balances_events_since_last_call(), vec![ @@ -3269,6 +3272,10 @@ mod withdraw_unbonded { CurrentEra::set(CurrentEra::get() + 3); + // set metadata to check that it's being removed on dissolve + assert_ok!(Pools::set_metadata(Origin::signed(900), 1, vec![1, 1])); + assert!(Metadata::::contains_key(1)); + // when assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); @@ -3287,6 +3294,7 @@ mod withdraw_unbonded { Event::Destroyed { pool_id: 1 } ] ); + assert!(!Metadata::::contains_key(1)); assert_eq!( balances_events_since_last_call(), vec![ @@ -3797,6 +3805,7 @@ mod withdraw_unbonded { Event::Destroyed { pool_id: 1 }, ] ); + assert!(!Metadata::::contains_key(1)); }) } } @@ -4039,7 +4048,7 @@ mod set_state { // Then assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); - // If the pool is not ok to be open, it cannot be permissionleslly set to a state that + // If the pool is not ok to be open, it cannot be permissionlessly set to a state that // isn't destroying unsafe_set_state(1, PoolState::Open); assert_noop!( From 20037d573c0c2b319998541c6140df4c3d07eb56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Tue, 6 Sep 2022 10:01:35 +0200 Subject: [PATCH 1128/1472] `try-runtime`::`follow-chain` - keep connection (#12167) * Refactor RPC module * Add flag to `follow-chain` * Multithreading remark * fmt * O_O * unused import * cmon * accidental removal reverted * remove RpcHeaderProvider * mut refs * fmt * no mutability * now? * now? * arc mutex * async mutex * async mutex * uhm * connect in constructor * remove dep * old import * another take * trigger polkadot pipeline * trigger pipeline --- bin/node/cli/tests/common.rs | 5 +- .../frame/remote-externalities/src/rpc_api.rs | 175 +++++++++++------- .../cli/src/commands/execute_block.rs | 9 +- .../cli/src/commands/follow_chain.rs | 61 +++--- .../cli/src/commands/offchain_worker.rs | 3 +- utils/frame/try-runtime/cli/src/lib.rs | 13 +- 6 files changed, 160 insertions(+), 106 deletions(-) diff --git a/bin/node/cli/tests/common.rs b/bin/node/cli/tests/common.rs index 9c739c2cf2d28..3b83f4339611d 100644 --- a/bin/node/cli/tests/common.rs +++ b/bin/node/cli/tests/common.rs @@ -24,7 +24,7 @@ use nix::{ unistd::Pid, }; use node_primitives::Block; -use remote_externalities::rpc_api; +use remote_externalities::rpc_api::RpcService; use std::{ io::{BufRead, BufReader, Read}, ops::{Deref, DerefMut}, @@ -71,9 +71,10 @@ pub async fn wait_n_finalized_blocks( pub async fn wait_n_finalized_blocks_from(n: usize, url: &str) { let mut built_blocks = std::collections::HashSet::new(); let mut interval = tokio::time::interval(Duration::from_secs(2)); + let rpc_service = RpcService::new(url, false).await.unwrap(); loop { - if let Ok(block) = rpc_api::get_finalized_head::(url.to_string()).await { + if let Ok(block) = rpc_service.get_finalized_head::().await { built_blocks.insert(block); if built_blocks.len() > n { break diff --git a/utils/frame/remote-externalities/src/rpc_api.rs b/utils/frame/remote-externalities/src/rpc_api.rs index 37555de480d4c..3ea30a30221a2 100644 --- a/utils/frame/remote-externalities/src/rpc_api.rs +++ b/utils/frame/remote-externalities/src/rpc_api.rs @@ -19,82 +19,131 @@ // TODO: Consolidate one off RPC calls https://github.com/paritytech/substrate/issues/8988 use jsonrpsee::{ - core::client::ClientT, + core::client::{Client, ClientT}, rpc_params, + types::ParamsSer, ws_client::{WsClient, WsClientBuilder}, }; -use sp_runtime::{ - generic::SignedBlock, - traits::{Block as BlockT, Header as HeaderT}, -}; - -/// Get the header of the block identified by `at` -pub async fn get_header(from: S, at: Block::Hash) -> Result -where - Block: BlockT, - Block::Header: serde::de::DeserializeOwned, - S: AsRef, -{ - let client = build_client(from).await?; +use serde::de::DeserializeOwned; +use sp_runtime::{generic::SignedBlock, traits::Block as BlockT}; +use std::sync::Arc; - client - .request::("chain_getHeader", rpc_params!(at)) - .await - .map_err(|e| format!("chain_getHeader request failed: {:?}", e)) +enum RpcCall { + GetHeader, + GetFinalizedHead, + GetBlock, + GetRuntimeVersion, } -/// Get the finalized head -pub async fn get_finalized_head(from: S) -> Result -where - Block: BlockT, - S: AsRef, -{ - let client = build_client(from).await?; +impl RpcCall { + fn as_str(&self) -> &'static str { + match self { + RpcCall::GetHeader => "chain_getHeader", + RpcCall::GetFinalizedHead => "chain_getFinalizedHead", + RpcCall::GetBlock => "chain_getBlock", + RpcCall::GetRuntimeVersion => "state_getRuntimeVersion", + } + } +} +/// General purpose method for making RPC calls. +async fn make_request<'a, T: DeserializeOwned>( + client: &Arc, + call: RpcCall, + params: Option>, +) -> Result { client - .request::("chain_getFinalizedHead", None) + .request::(call.as_str(), params) .await - .map_err(|e| format!("chain_getFinalizedHead request failed: {:?}", e)) + .map_err(|e| format!("{} request failed: {:?}", call.as_str(), e)) } -/// Get the signed block identified by `at`. -pub async fn get_block(from: S, at: Block::Hash) -> Result -where - S: AsRef, - Block: BlockT + serde::de::DeserializeOwned, - Block::Header: HeaderT, -{ - let client = build_client(from).await?; - let signed_block = client - .request::>("chain_getBlock", rpc_params!(at)) - .await - .map_err(|e| format!("chain_getBlock request failed: {:?}", e))?; - - Ok(signed_block.block) +enum ConnectionPolicy { + Reuse(Arc), + Reconnect, } -/// Build a websocket client that connects to `from`. -async fn build_client>(from: S) -> Result { - WsClientBuilder::default() - .max_request_body_size(u32::MAX) - .build(from.as_ref()) - .await - .map_err(|e| format!("`WsClientBuilder` failed to build: {:?}", e)) +/// Simple RPC service that is capable of keeping the connection. +/// +/// Service will connect to `uri` for the first time already during initialization. +/// +/// Be careful with reusing the connection in a multithreaded environment. +pub struct RpcService { + uri: String, + policy: ConnectionPolicy, } -/// Get the runtime version of a given chain. -pub async fn get_runtime_version( - from: S, - at: Option, -) -> Result -where - S: AsRef, - Block: BlockT + serde::de::DeserializeOwned, - Block::Header: HeaderT, -{ - let client = build_client(from).await?; - client - .request::("state_getRuntimeVersion", rpc_params!(at)) - .await - .map_err(|e| format!("state_getRuntimeVersion request failed: {:?}", e)) +impl RpcService { + /// Creates a new RPC service. If `keep_connection`, then connects to `uri` right away. + pub async fn new>(uri: S, keep_connection: bool) -> Result { + let policy = if keep_connection { + ConnectionPolicy::Reuse(Arc::new(Self::build_client(uri.as_ref()).await?)) + } else { + ConnectionPolicy::Reconnect + }; + Ok(Self { uri: uri.as_ref().to_string(), policy }) + } + + /// Returns the address at which requests are sent. + pub fn uri(&self) -> String { + self.uri.clone() + } + + /// Build a websocket client that connects to `self.uri`. + async fn build_client>(uri: S) -> Result { + WsClientBuilder::default() + .max_request_body_size(u32::MAX) + .build(uri) + .await + .map_err(|e| format!("`WsClientBuilder` failed to build: {:?}", e)) + } + + /// Generic method for making RPC requests. + async fn make_request<'a, T: DeserializeOwned>( + &self, + call: RpcCall, + params: Option>, + ) -> Result { + match self.policy { + // `self.keep_connection` must have been `true`. + ConnectionPolicy::Reuse(ref client) => make_request(client, call, params).await, + ConnectionPolicy::Reconnect => { + let client = Arc::new(Self::build_client(&self.uri).await?); + make_request(&client, call, params).await + }, + } + } + + /// Get the header of the block identified by `at`. + pub async fn get_header(&self, at: Block::Hash) -> Result + where + Block: BlockT, + Block::Header: DeserializeOwned, + { + self.make_request(RpcCall::GetHeader, rpc_params!(at)).await + } + + /// Get the finalized head. + pub async fn get_finalized_head(&self) -> Result { + self.make_request(RpcCall::GetFinalizedHead, None).await + } + + /// Get the signed block identified by `at`. + pub async fn get_block( + &self, + at: Block::Hash, + ) -> Result { + Ok(self + .make_request::>(RpcCall::GetBlock, rpc_params!(at)) + .await? + .block) + } + + /// Get the runtime version of a given chain. + pub async fn get_runtime_version( + &self, + at: Option, + ) -> Result { + self.make_request(RpcCall::GetRuntimeVersion, rpc_params!(at)).await + } } diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index 6a3ef24ff3771..70ba3615f874a 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -89,6 +89,8 @@ impl ExecuteBlockCmd { Block::Hash: FromStr, ::Err: Debug, { + let rpc_service = rpc_api::RpcService::new(ws_uri, false).await?; + match (&self.block_at, &self.state) { (Some(block_at), State::Snap { .. }) => hash_of::(block_at), (Some(block_at), State::Live { .. }) => { @@ -100,9 +102,7 @@ impl ExecuteBlockCmd { target: LOG_TARGET, "No --block-at or --at provided, using the latest finalized block instead" ); - remote_externalities::rpc_api::get_finalized_head::(ws_uri) - .await - .map_err(Into::into) + rpc_service.get_finalized_head::().await.map_err(Into::into) }, (None, State::Live { at: Some(at), .. }) => hash_of::(at), _ => { @@ -148,7 +148,8 @@ where let block_ws_uri = command.block_ws_uri::(); let block_at = command.block_at::(block_ws_uri.clone()).await?; - let block: Block = rpc_api::get_block::(block_ws_uri.clone(), block_at).await?; + let rpc_service = rpc_api::RpcService::new(block_ws_uri.clone(), false).await?; + let block: Block = rpc_service.get_block::(block_at).await?; let parent_hash = block.header().parent_hash(); log::info!( target: LOG_TARGET, diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index 9f598694d0ff1..f493d5c10cd29 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -27,13 +27,13 @@ use jsonrpsee::{ ws_client::WsClientBuilder, }; use parity_scale_codec::{Decode, Encode}; -use remote_externalities::{rpc_api, Builder, Mode, OnlineConfig}; +use remote_externalities::{rpc_api::RpcService, Builder, Mode, OnlineConfig}; use sc_executor::NativeExecutionDispatch; use sc_service::Configuration; use serde::de::DeserializeOwned; use sp_core::H256; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; -use std::{collections::VecDeque, fmt::Debug, marker::PhantomData, str::FromStr}; +use std::{collections::VecDeque, fmt::Debug, str::FromStr}; const SUB: &str = "chain_subscribeFinalizedHeads"; const UN_SUB: &str = "chain_unsubscribeFinalizedHeads"; @@ -60,6 +60,10 @@ pub struct FollowChainCmd { /// round-robin fashion. #[clap(long, default_value = "none")] try_state: frame_try_runtime::TryStateSelect, + + /// If present, a single connection to a node will be kept and reused for fetching blocks. + #[clap(long)] + keep_connection: bool, } /// Start listening for with `SUB` at `url`. @@ -93,21 +97,16 @@ where Block::Header: HeaderT, { /// Awaits for the header of the block with hash `hash`. - async fn get_header(&mut self, hash: Block::Hash) -> Block::Header; -} - -struct RpcHeaderProvider { - uri: String, - _phantom: PhantomData, + async fn get_header(&self, hash: Block::Hash) -> Block::Header; } #[async_trait] -impl HeaderProvider for RpcHeaderProvider +impl HeaderProvider for RpcService where Block::Header: DeserializeOwned, { - async fn get_header(&mut self, hash: Block::Hash) -> Block::Header { - rpc_api::get_header::(&self.uri, hash).await.unwrap() + async fn get_header(&self, hash: Block::Hash) -> Block::Header { + self.get_header::(hash).await.unwrap() } } @@ -148,19 +147,20 @@ where /// /// Returned headers are guaranteed to be ordered. There are no missing headers (even if some of /// them lack justification). -struct FinalizedHeaders, HS: HeaderSubscription> { - header_provider: HP, +struct FinalizedHeaders<'a, Block: BlockT, HP: HeaderProvider, HS: HeaderSubscription> +{ + header_provider: &'a HP, subscription: HS, fetched_headers: VecDeque, last_returned: Option<::Hash>, } -impl, HS: HeaderSubscription> - FinalizedHeaders +impl<'a, Block: BlockT, HP: HeaderProvider, HS: HeaderSubscription> + FinalizedHeaders<'a, Block, HP, HS> where ::Header: DeserializeOwned, { - pub fn new(header_provider: HP, subscription: HS) -> Self { + pub fn new(header_provider: &'a HP, subscription: HS) -> Self { Self { header_provider, subscription, @@ -229,19 +229,16 @@ where let executor = build_executor::(&shared, &config); let execution = shared.execution; - let header_provider: RpcHeaderProvider = - RpcHeaderProvider { uri: command.uri.clone(), _phantom: PhantomData {} }; - let mut finalized_headers: FinalizedHeaders< - Block, - RpcHeaderProvider, - Subscription, - > = FinalizedHeaders::new(header_provider, subscription); + let rpc_service = RpcService::new(&command.uri, command.keep_connection).await?; + + let mut finalized_headers: FinalizedHeaders> = + FinalizedHeaders::new(&rpc_service, subscription); while let Some(header) = finalized_headers.next().await { let hash = header.hash(); let number = header.number(); - let block = rpc_api::get_block::(&command.uri, hash).await.unwrap(); + let block = rpc_service.get_block::(hash).await.unwrap(); log::debug!( target: LOG_TARGET, @@ -333,12 +330,14 @@ where mod tests { use super::*; use sp_runtime::testing::{Block as TBlock, ExtrinsicWrapper, Header}; + use std::sync::Arc; + use tokio::sync::Mutex; type Block = TBlock>; type BlockNumber = u64; type Hash = H256; - struct MockHeaderProvider(pub VecDeque); + struct MockHeaderProvider(pub Arc>>); fn headers() -> Vec
{ let mut headers = vec![Header::new_from_number(0)]; @@ -353,8 +352,8 @@ mod tests { #[async_trait] impl HeaderProvider for MockHeaderProvider { - async fn get_header(&mut self, _hash: Hash) -> Header { - let height = self.0.pop_front().unwrap(); + async fn get_header(&self, _hash: Hash) -> Header { + let height = self.0.lock().await.pop_front().unwrap(); headers()[height as usize].clone() } } @@ -372,9 +371,9 @@ mod tests { async fn finalized_headers_works_when_every_block_comes_from_subscription() { let heights = vec![4, 5, 6, 7]; - let provider = MockHeaderProvider(vec![].into()); + let provider = MockHeaderProvider(Default::default()); let subscription = MockHeaderSubscription(heights.clone().into()); - let mut headers = FinalizedHeaders::new(provider, subscription); + let mut headers = FinalizedHeaders::new(&provider, subscription); for h in heights { assert_eq!(h, headers.next().await.unwrap().number); @@ -389,9 +388,9 @@ mod tests { // Consecutive headers will be requested in the reversed order. let heights_not_in_subscription = vec![5, 9, 8, 7]; - let provider = MockHeaderProvider(heights_not_in_subscription.into()); + let provider = MockHeaderProvider(Arc::new(Mutex::new(heights_not_in_subscription.into()))); let subscription = MockHeaderSubscription(heights_in_subscription.into()); - let mut headers = FinalizedHeaders::new(provider, subscription); + let mut headers = FinalizedHeaders::new(&provider, subscription); for h in all_heights { assert_eq!(h, headers.next().await.unwrap().number); diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index 11ceb0a81cf37..a579692abd9e2 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -119,7 +119,8 @@ where let header_at = command.header_at::()?; let header_ws_uri = command.header_ws_uri::(); - let header = rpc_api::get_header::(header_ws_uri.clone(), header_at).await?; + let rpc_service = rpc_api::RpcService::new(header_ws_uri.clone(), false).await?; + let header = rpc_service.get_header::(header_at).await?; log::info!( target: LOG_TARGET, "fetched header from {:?}, block number: {:?}", diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 76679c43f7f14..c71496e0b850c 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -267,7 +267,8 @@ use parity_scale_codec::Decode; use remote_externalities::{ - Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, TestExternalities, + rpc_api::RpcService, Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, + TestExternalities, }; use sc_chain_spec::ChainSpec; use sc_cli::{ @@ -541,8 +542,8 @@ impl State { impl TryRuntimeCmd { pub async fn run(&self, config: Configuration) -> sc_cli::Result<()> where - Block: BlockT + serde::de::DeserializeOwned, - Block::Header: serde::de::DeserializeOwned, + Block: BlockT + DeserializeOwned, + Block::Header: DeserializeOwned, Block::Hash: FromStr, ::Err: Debug, NumberFor: FromStr, @@ -626,13 +627,15 @@ where /// /// If the spec names don't match, if `relaxed`, then it emits a warning, else it panics. /// If the spec versions don't match, it only ever emits a warning. -pub(crate) async fn ensure_matching_spec( +pub(crate) async fn ensure_matching_spec( uri: String, expected_spec_name: String, expected_spec_version: u32, relaxed: bool, ) { - match remote_externalities::rpc_api::get_runtime_version::(uri.clone(), None) + let rpc_service = RpcService::new(uri.clone(), false).await.unwrap(); + match rpc_service + .get_runtime_version::(None) .await .map(|version| (String::from(version.spec_name.clone()), version.spec_version)) .map(|(spec_name, spec_version)| (spec_name.to_lowercase(), spec_version)) From 12b0d8e9957c6159d433cd4601d5f297b9bf4313 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Tue, 6 Sep 2022 14:16:29 +0200 Subject: [PATCH 1129/1472] Uniques: Small fix in docs (#12143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * small fix in docs * Update frame/uniques/src/lib.rs Co-authored-by: Bastian Köcher * Update lib.rs * Update lib.rs * Update lib.rs Co-authored-by: Bastian Köcher --- frame/uniques/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 3b0cf6dc673c9..bbecb08e51b3b 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -910,7 +910,8 @@ pub mod pallet { /// Approve an item to be transferred by a delegated third-party account. /// - /// Origin must be Signed and must be the owner of the `item`. + /// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be + /// either the owner of the `item` or the admin of the collection. /// /// - `collection`: The collection of the item to be approved for delegated transfer. /// - `item`: The item of the item to be approved for delegated transfer. From dcfaa41d11e70cfc976e292b2975c7285cf3668c Mon Sep 17 00:00:00 2001 From: NingLin-P Date: Tue, 6 Sep 2022 20:24:31 +0800 Subject: [PATCH 1130/1472] staking: avoid proportional slashing leak dust into chunks that should not be slashed (#12058) * replace slash ratio with remaining ratio Signed-off-by: linning * little refactor Signed-off-by: linning * fix test Signed-off-by: linning * fix typo Signed-off-by: linning * revert refactor Signed-off-by: linning * rounding up instead of remaining ratio Signed-off-by: linning * address comment Signed-off-by: linning * Update frame/nomination-pools/test-staking/src/lib.rs Signed-off-by: linning Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/test-staking/src/lib.rs Signed-off-by: linning Co-authored-by: Roman Useinov Signed-off-by: linning Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Roman Useinov Co-authored-by: parity-processbot <> --- .../nomination-pools/test-staking/src/lib.rs | 10 ++++---- frame/staking/src/lib.rs | 12 +++++++--- frame/staking/src/tests.rs | 24 +++++++++++++++---- primitives/runtime/src/lib.rs | 2 +- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs index 5a7cd494362ca..8c6ecae937063 100644 --- a/frame/nomination-pools/test-staking/src/lib.rs +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -490,12 +490,10 @@ fn pool_slash_proportional() { assert_eq!( pool_events_since_last_call(), vec![ - // This last pool got slashed only the leftover dust. Otherwise in principle, this - // chunk/pool should have not been affected. - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 19 }, - // This pool got slashed 12.5, which rounded down to 12. - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 8 }, - // This pool got slashed 12.5, which rounded down to 12. + // This era got slashed 12.5, which rounded up to 13. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 7 }, + // This era got slashed 12 instead of 12.5 because an earlier chunk got 0.5 more + // slashed, and 12 is all the remaining slash PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 129, balance: 8 }, // Bonded pool got slashed for 25, remaining 15 in it. PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 38466c8cb1d62..4a1f0cb886ed0 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -310,7 +310,7 @@ use scale_info::TypeInfo; use sp_runtime::{ curve::PiecewiseLinear, traits::{AtLeast32BitUnsigned, Convert, Saturating, StaticLookup, Zero}, - Perbill, Perquintill, RuntimeDebug, + Perbill, Perquintill, Rounding, RuntimeDebug, }; use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, @@ -564,6 +564,7 @@ impl StakingLedger { return Zero::zero() } + use sp_runtime::PerThing as _; use sp_staking::OnStakerSlash as _; let mut remaining_slash = slash_amount; let pre_slash_total = self.total; @@ -594,7 +595,12 @@ impl StakingLedger { } }); let affected_balance = self.active.saturating_add(unbonding_affected_balance); - let ratio = Perquintill::from_rational(slash_amount, affected_balance); + let ratio = Perquintill::from_rational_with_rounding( + slash_amount, + affected_balance, + Rounding::Up, + ) + .unwrap_or_else(|_| Perquintill::one()); ( Some(ratio), affected_indices.chain((0..first_slashable_index).rev()).collect::>(), @@ -618,7 +624,7 @@ impl StakingLedger { let mut slash_out_of = |target: &mut BalanceOf, slash_remaining: &mut BalanceOf| { let mut slash_from_target = if let Some(ratio) = maybe_proportional { - ratio * (*target) + ratio.mul_ceil(*target) } else { *slash_remaining } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 107d494a9711b..0d00f5a5e61df 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -31,7 +31,7 @@ use pallet_balances::Error as BalancesError; use sp_runtime::{ assert_eq_error_rate, traits::{BadOrigin, Dispatchable}, - Perbill, Percent, + Perbill, Percent, Rounding, }; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, @@ -5125,6 +5125,18 @@ fn proportional_ledger_slash_works() { assert_eq!(LedgerSlashPerEra::get().0, 0); assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)])); + // Given + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.total = 4 * 100; + ledger.active = 0; + // When the first 2 chunks don't overlap with the affected range of unlock eras. + assert_eq!(ledger.slash(15, 0, 3), 15); + // Then + assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 100 - 8), c(7, 100 - 7)]); + assert_eq!(ledger.total, 4 * 100 - 15); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 92), (7, 93)])); + // Given ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; ledger.active = 500; @@ -5247,6 +5259,7 @@ fn proportional_ledger_slash_works() { assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0), (6, 0), (7, 0)])); // Given + use sp_runtime::PerThing as _; let slash = u64::MAX as Balance * 2; let value = u64::MAX as Balance * 2; let unit = 100; @@ -5259,18 +5272,19 @@ fn proportional_ledger_slash_works() { ledger.active = unit; ledger.total = unit * 4 + value; // When - assert_eq!(ledger.slash(slash, 0, 0), slash - 43); + assert_eq!(ledger.slash(slash, 0, 0), slash - 5); // Then // The amount slashed out of `unit` let affected_balance = value + unit * 4; - let ratio = Perquintill::from_rational(slash, affected_balance); + let ratio = + Perquintill::from_rational_with_rounding(slash, affected_balance, Rounding::Up).unwrap(); // `unit` after the slash is applied let unit_slashed = { - let unit_slash = ratio * unit; + let unit_slash = ratio.mul_ceil(unit); unit - unit_slash }; let value_slashed = { - let value_slash = ratio * value; + let value_slash = ratio.mul_ceil(value); value - value_slash }; assert_eq!(ledger.active, unit_slashed); diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index cd43038522914..811ca33dbfa25 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -97,7 +97,7 @@ pub use sp_arithmetic::helpers_128bit; pub use sp_arithmetic::{ traits::SaturatedConversion, FixedI128, FixedI64, FixedPointNumber, FixedPointOperand, FixedU128, InnerOf, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, Rational128, - UpperOf, + Rounding, UpperOf, }; pub use either::Either; From 3f70bcedf020d072e2f611a2448f2af46a4ae9b4 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Wed, 7 Sep 2022 11:54:17 +0300 Subject: [PATCH 1131/1472] [contracts] API host functions: remove `seal_` name prefix + enable aliasing (#12126) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * works but ugly * refactored + renamed host fns * fixed tests * fix benchmarks * updated marco docs * Update frame/contracts/proc-macro/src/lib.rs Co-authored-by: Alexander Theißen * fix for the duplicated prefixed alias bug + test * refactored a bit * fix warnings + try to make macro rustdoc compile * fmt after clearing * examples update + nocompile * add seal_ prefixes to unstable host functions * updated after a review Co-authored-by: Alexander Theißen --- frame/contracts/fixtures/call_runtime.wat | 4 +- frame/contracts/proc-macro/src/lib.rs | 72 ++++-- frame/contracts/src/benchmarking/mod.rs | 22 +- frame/contracts/src/wasm/mod.rs | 66 +++++- frame/contracts/src/wasm/runtime.rs | 260 +++++++++++----------- 5 files changed, 262 insertions(+), 162 deletions(-) diff --git a/frame/contracts/fixtures/call_runtime.wat b/frame/contracts/fixtures/call_runtime.wat index d5467f6e95e3e..62fa08680a097 100644 --- a/frame/contracts/fixtures/call_runtime.wat +++ b/frame/contracts/fixtures/call_runtime.wat @@ -1,6 +1,6 @@ ;; This passes its input to `seal_call_runtime` and returns the return value to its caller. (module - (import "__unstable__" "seal_call_runtime" (func $seal_call_runtime (param i32 i32) (result i32))) + (import "__unstable__" "call_runtime" (func $call_runtime (param i32 i32) (result i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) @@ -17,7 +17,7 @@ ) ;; Just use the call passed as input and store result to memory (i32.store (i32.const 0) - (call $seal_call_runtime + (call $call_runtime (i32.const 4) ;; Pointer where the call is stored (i32.load (i32.const 0)) ;; Size of the call ) diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index 65c13bb1fc607..648bf0fd1f812 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -174,22 +174,16 @@ impl ToTokens for HostFn { } impl HostFn { - pub fn try_from(item: syn::Item) -> syn::Result { + pub fn try_from(item: syn::ItemFn) -> syn::Result { let err = |span, msg| { let msg = format!("Invalid host function definition. {}", msg); syn::Error::new(span, msg) }; let msg = "only #[version()] or #[unstable] attribute is allowed."; let span = item.span(); - let item = match item { - syn::Item::Fn(i_fn) => Ok(i_fn), - _ => Err(err(span, msg)), - }?; - + let mut attrs = item.attrs.clone(); + attrs.retain(|a| !(a.path.is_ident("doc") || a.path.is_ident("prefixed_alias"))); let name = item.sig.ident.to_string(); - let attrs: Vec<&syn::Attribute> = - item.attrs.iter().filter(|m| !m.path.is_ident("doc")).collect(); - let module = match attrs.len() { 0 => Ok("seal0".to_string()), 1 => { @@ -306,6 +300,7 @@ impl HostFn { } } } + impl EnvDef { pub fn try_from(item: syn::ItemMod) -> syn::Result { let span = item.span(); @@ -316,9 +311,32 @@ impl EnvDef { .ok_or(err("Invalid environment definition, expected `mod` to be inlined."))? .1; + let extract_fn = |i: &syn::Item| match i { + syn::Item::Fn(i_fn) => Some(i_fn.clone()), + _ => None, + }; + + let selector = |a: &syn::Attribute| a.path.is_ident("prefixed_alias"); + + let aliases = items + .iter() + .filter_map(extract_fn) + .filter(|i| i.attrs.iter().any(selector)) + .map(|mut i| { + i.attrs.retain(|i| !selector(i)); + i.sig.ident = syn::Ident::new( + &format!("seal_{}", &i.sig.ident.to_string()), + i.sig.ident.span(), + ); + i + }) + .map(|i| HostFn::try_from(i)); + let host_funcs = items .iter() - .map(|i| HostFn::try_from(i.clone())) + .filter_map(extract_fn) + .map(|i| HostFn::try_from(i)) + .chain(aliases) .collect::, _>>()?; Ok(Self { host_funcs }) @@ -484,7 +502,7 @@ fn expand_impls(def: &mut EnvDef) -> proc_macro2::TokenStream { /// ```nocompile /// #[define_env] /// pub mod some_env { -/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<(), TrapReason> { +/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<(), TrapReason> { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// } @@ -499,17 +517,45 @@ fn expand_impls(def: &mut EnvDef) -> proc_macro2::TokenStream { /// #[define_env] /// pub mod some_env { /// #[version(1)] -/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) +/// } +/// +/// #[unstable] +/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) +/// } +/// } +/// ``` +/// +/// In legacy versions of pallet_contracts, it was a naming convention that all host functions had +/// to be named with the `seal_` prefix. For the sake of backwards compatibility, each host function +/// now can get a such prefix-named alias function generated by marking it by the +/// `#[prefixed_alias]` attribute: +/// +/// ## Example +/// +/// ```nocompile +/// #[define_env] +/// pub mod some_env { +/// #[version(1)] +/// #[prefixed_alias] +/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// /// #[unstable] -/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// } /// ``` /// +/// In this example, the following host functions will be generated by the macro: +/// - `some_host_fn()` in module `seal1`, +/// - `seal_some_host_fn()` in module `seal1`, +/// - `some_host_fn()` in module `__unstable__`. +/// /// Only following return types are allowed for the host functions defined with the macro: /// - `Result<(), TrapReason>`, /// - `Result`, diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index e29cb51728e1e..2f8d101504ffa 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -920,7 +920,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_set_storage", + name: "set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], @@ -968,7 +968,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_set_storage", + name: "set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], @@ -1016,7 +1016,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_set_storage", + name: "set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], @@ -1068,7 +1068,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_clear_storage", + name: "clear_storage", params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], @@ -1115,7 +1115,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_clear_storage", + name: "clear_storage", params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], @@ -1163,7 +1163,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_get_storage", + name: "get_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], @@ -1217,7 +1217,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_get_storage", + name: "get_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], @@ -1272,7 +1272,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_contains_storage", + name: "contains_storage", params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], @@ -1319,7 +1319,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_contains_storage", + name: "contains_storage", params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], @@ -1367,7 +1367,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_take_storage", + name: "take_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], @@ -1421,7 +1421,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "seal_take_storage", + name: "take_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index f989c21b00ffc..6790830b97e02 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -929,7 +929,7 @@ mod tests { (module (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "__unstable__" "seal_contains_storage" (func $seal_contains_storage (param i32 i32) (result i32))) + (import "__unstable__" "contains_storage" (func $contains_storage (param i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) @@ -947,7 +947,7 @@ mod tests { ) ;; Call seal_clear_storage and save what it returns at 0 (i32.store (i32.const 0) - (call $seal_contains_storage + (call $contains_storage (i32.const 8) ;; key_ptr (i32.load (i32.const 4)) ;; key_len ) @@ -1678,11 +1678,53 @@ mod tests { ) (func (export "deploy")) ) +"#; + + const CODE_TIMESTAMP_NOW_UNPREFIXED: &str = r#" +(module + (import "seal0" "now" (func $now (param i32 i32))) + (import "env" "memory" (memory 1 1)) + + ;; size of our buffer is 32 bytes + (data (i32.const 32) "\20") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + ;; This stores the block timestamp in the buffer + (call $now (i32.const 0) (i32.const 32)) + + ;; assert len == 8 + (call $assert + (i32.eq + (i32.load (i32.const 32)) + (i32.const 8) + ) + ) + + ;; assert that contents of the buffer is equal to the i64 value of 1111. + (call $assert + (i64.eq + (i64.load (i32.const 0)) + (i64.const 1111) + ) + ) + ) + (func (export "deploy")) +) "#; #[test] fn now() { assert_ok!(execute(CODE_TIMESTAMP_NOW, vec![], MockExt::default())); + assert_ok!(execute(CODE_TIMESTAMP_NOW_UNPREFIXED, vec![], MockExt::default())); } const CODE_MINIMUM_BALANCE: &str = r#" @@ -2221,7 +2263,7 @@ mod tests { #[cfg(feature = "unstable-interface")] const CODE_CALL_RUNTIME: &str = r#" (module - (import "__unstable__" "seal_call_runtime" (func $seal_call_runtime (param i32 i32) (result i32))) + (import "__unstable__" "call_runtime" (func $call_runtime (param i32 i32) (result i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) @@ -2238,7 +2280,7 @@ mod tests { ) ;; Just use the call passed as input and store result to memory (i32.store (i32.const 0) - (call $seal_call_runtime + (call $call_runtime (i32.const 4) ;; Pointer where the call is stored (i32.load (i32.const 0)) ;; Size of the call ) @@ -2350,7 +2392,7 @@ mod tests { (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "__unstable__" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32 i32) (result i32))) + (import "__unstable__" "set_storage" (func $set_storage (param i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 4) size of input buffer @@ -2367,7 +2409,7 @@ mod tests { ) ;; Store the passed value to the passed key and store result to memory (i32.store (i32.const 168) - (call $seal_set_storage + (call $set_storage (i32.const 8) ;; key_ptr (i32.load (i32.const 4)) ;; key_len (i32.add ;; value_ptr = 8 + key_len @@ -2421,7 +2463,7 @@ mod tests { (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "__unstable__" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32 i32) (result i32))) + (import "__unstable__" "get_storage" (func $get_storage (param i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 4) size of input buffer (160 bytes as we copy the key+len here) @@ -2442,7 +2484,7 @@ mod tests { ) ;; Load a storage value and result of this call into the output buffer (i32.store (i32.const 168) - (call $seal_get_storage + (call $get_storage (i32.const 12) ;; key_ptr (i32.load (i32.const 8)) ;; key_len (i32.const 172) ;; Pointer to the output buffer @@ -2515,7 +2557,7 @@ mod tests { (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "__unstable__" "seal_clear_storage" (func $seal_clear_storage (param i32 i32) (result i32))) + (import "__unstable__" "clear_storage" (func $clear_storage (param i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; size of input buffer @@ -2532,7 +2574,7 @@ mod tests { ) ;; Call seal_clear_storage and save what it returns at 0 (i32.store (i32.const 0) - (call $seal_clear_storage + (call $clear_storage (i32.const 8) ;; key_ptr (i32.load (i32.const 4)) ;; key_len ) @@ -2601,7 +2643,7 @@ mod tests { (module (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "__unstable__" "seal_take_storage" (func $seal_take_storage (param i32 i32 i32 i32) (result i32))) + (import "__unstable__" "take_storage" (func $take_storage (param i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 4) size of input buffer (160 bytes as we copy the key+len here) @@ -2623,7 +2665,7 @@ mod tests { ;; Load a storage value and result of this call into the output buffer (i32.store (i32.const 168) - (call $seal_take_storage + (call $take_storage (i32.const 12) ;; key_ptr (i32.load (i32.const 8)) ;; key_len (i32.const 172) ;; Pointer to the output buffer diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 296f322f494d0..334223e3b8432 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -957,7 +957,7 @@ pub mod env { /// This call is supposed to be called only by instrumentation injected code. /// /// - amount: How much gas is used. - fn gas(ctx: Runtime, amount: u32) -> Result<(), TrapReason> { + fn gas(ctx: Runtime, amount: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::MeteringBlock(amount))?; Ok(()) } @@ -966,8 +966,9 @@ pub mod env { /// /// Equivalent to the newer version of `seal_set_storage` with the exception of the return /// type. Still a valid thing to call when not interested in the return value. - fn seal_set_storage( - ctx: Runtime, + #[prefixed_alias] + fn set_storage( + ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32, @@ -994,8 +995,9 @@ pub mod env { /// Returns the size of the pre-existing value at the specified key if any. Otherwise /// `SENTINEL` is returned as a sentinel value. #[version(1)] - fn seal_set_storage( - ctx: Runtime, + #[prefixed_alias] + fn set_storage( + ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32, @@ -1020,8 +1022,9 @@ pub mod env { /// Returns the size of the pre-existing value at the specified key if any. Otherwise /// `SENTINEL` is returned as a sentinel value. #[unstable] - fn seal_set_storage( - ctx: Runtime, + #[prefixed_alias] + fn set_storage( + ctx: Runtime, key_ptr: u32, key_len: u32, value_ptr: u32, @@ -1034,7 +1037,8 @@ pub mod env { /// /// Equivalent to the newer version of `seal_clear_storage` with the exception of the return /// type. Still a valid thing to call when not interested in the return value. - fn seal_clear_storage(ctx: Runtime, key_ptr: u32) -> Result<(), TrapReason> { + #[prefixed_alias] + fn clear_storage(ctx: Runtime, key_ptr: u32) -> Result<(), TrapReason> { ctx.clear_storage(KeyType::Fix, key_ptr).map(|_| ()) } @@ -1050,11 +1054,8 @@ pub mod env { /// Returns the size of the pre-existing value at the specified key if any. Otherwise /// `SENTINEL` is returned as a sentinel value. #[unstable] - fn seal_clear_storage( - ctx: Runtime, - key_ptr: u32, - key_len: u32, - ) -> Result { + #[prefixed_alias] + fn clear_storage(ctx: Runtime, key_ptr: u32, key_len: u32) -> Result { ctx.clear_storage(KeyType::Variable(key_len), key_ptr) } @@ -1073,8 +1074,9 @@ pub mod env { /// # Errors /// /// `ReturnCode::KeyNotFound` - fn seal_get_storage( - ctx: Runtime, + #[prefixed_alias] + fn get_storage( + ctx: Runtime, key_ptr: u32, out_ptr: u32, out_len_ptr: u32, @@ -1101,8 +1103,9 @@ pub mod env { /// /// `ReturnCode::KeyNotFound` #[unstable] - fn seal_get_storage( - ctx: Runtime, + #[prefixed_alias] + fn get_storage( + ctx: Runtime, key_ptr: u32, key_len: u32, out_ptr: u32, @@ -1124,7 +1127,8 @@ pub mod env { /// /// Returns the size of the pre-existing value at the specified key if any. Otherwise /// `SENTINEL` is returned as a sentinel value. - fn seal_contains_storage(ctx: Runtime, key_ptr: u32) -> Result { + #[prefixed_alias] + fn contains_storage(ctx: Runtime, key_ptr: u32) -> Result { ctx.contains_storage(KeyType::Fix, key_ptr) } @@ -1142,11 +1146,8 @@ pub mod env { /// Returns the size of the pre-existing value at the specified key if any. Otherwise /// `SENTINEL` is returned as a sentinel value. #[unstable] - fn seal_contains_storage( - ctx: Runtime, - key_ptr: u32, - key_len: u32, - ) -> Result { + #[prefixed_alias] + fn contains_storage(ctx: Runtime, key_ptr: u32, key_len: u32) -> Result { ctx.contains_storage(KeyType::Variable(key_len), key_ptr) } @@ -1164,8 +1165,9 @@ pub mod env { /// /// `ReturnCode::KeyNotFound` #[unstable] - fn seal_take_storage( - ctx: Runtime, + #[prefixed_alias] + fn take_storage( + ctx: Runtime, key_ptr: u32, key_len: u32, out_ptr: u32, @@ -1200,8 +1202,9 @@ pub mod env { /// # Errors /// /// `ReturnCode::TransferFailed` - fn seal_transfer( - ctx: Runtime, + #[prefixed_alias] + fn transfer( + ctx: Runtime, account_ptr: u32, _account_len: u32, value_ptr: u32, @@ -1233,8 +1236,9 @@ pub mod env { /// The values `_callee_len` and `_value_len` are ignored because the encoded sizes /// of those types are fixed through `[`MaxEncodedLen`]. The fields exist for backwards /// compatibility. Consider switching to the newest version of this function. - fn seal_call( - ctx: Runtime, + #[prefixed_alias] + fn call( + ctx: Runtime, callee_ptr: u32, _callee_len: u32, gas: u64, @@ -1285,8 +1289,9 @@ pub mod env { /// `ReturnCode::TransferFailed` /// `ReturnCode::NotCallable` #[version(1)] - fn seal_call( - ctx: Runtime, + #[prefixed_alias] + fn call( + ctx: Runtime, flags: u32, callee_ptr: u32, gas: u64, @@ -1330,8 +1335,9 @@ pub mod env { /// `ReturnCode::CalleeReverted`: Output buffer is returned. /// `ReturnCode::CalleeTrapped` /// `ReturnCode::CodeNotFound` - fn seal_delegate_call( - ctx: Runtime, + #[prefixed_alias] + fn delegate_call( + ctx: Runtime, flags: u32, code_hash_ptr: u32, input_data_ptr: u32, @@ -1360,8 +1366,9 @@ pub mod env { /// The values `_code_hash_len` and `_value_len` are ignored because the encoded sizes /// of those types are fixed through `[`MaxEncodedLen`]. The fields exist for backwards /// compatibility. Consider switching to the newest version of this function. - fn seal_instantiate( - ctx: Runtime, + #[prefixed_alias] + fn instantiate( + ctx: Runtime, code_hash_ptr: u32, _code_hash_len: u32, gas: u64, @@ -1432,8 +1439,9 @@ pub mod env { /// `ReturnCode::TransferFailed` /// `ReturnCode::CodeNotFound` #[version(1)] - fn seal_instantiate( - ctx: Runtime, + #[prefixed_alias] + fn instantiate( + ctx: Runtime, code_hash_ptr: u32, gas: u64, value_ptr: u32, @@ -1473,8 +1481,9 @@ pub mod env { /// The value `_beneficiary_len` is ignored because the encoded sizes /// this type is fixed through `[`MaxEncodedLen`]. The field exist for backwards /// compatibility. Consider switching to the newest version of this function. - fn seal_terminate( - ctx: Runtime, + #[prefixed_alias] + fn terminate( + ctx: Runtime, beneficiary_ptr: u32, _beneficiary_len: u32, ) -> Result<(), TrapReason> { @@ -1497,7 +1506,8 @@ pub mod env { /// - Failed to send the balance to the beneficiary. /// - The deletion queue is full. #[version(1)] - fn seal_terminate(ctx: Runtime, beneficiary_ptr: u32) -> Result<(), TrapReason> { + #[prefixed_alias] + fn terminate(ctx: Runtime, beneficiary_ptr: u32) -> Result<(), TrapReason> { ctx.terminate(beneficiary_ptr) } @@ -1511,7 +1521,8 @@ pub mod env { /// # Note /// /// This function traps if the input was previously forwarded by a `seal_call`. - fn seal_input(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + #[prefixed_alias] + fn input(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::InputBase)?; if let Some(input) = ctx.input_data.take() { ctx.write_sandbox_output(out_ptr, out_len_ptr, &input, false, |len| { @@ -1542,7 +1553,7 @@ pub mod env { /// /// Using a reserved bit triggers a trap. fn seal_return( - ctx: Runtime, + ctx: Runtime, flags: u32, data_ptr: u32, data_len: u32, @@ -1564,7 +1575,8 @@ pub mod env { /// If this is a top-level call (i.e. initiated by an extrinsic) the origin address of the /// extrinsic will be returned. Otherwise, if this call is initiated by another contract then /// the address of the contract will be returned. The value is encoded as T::AccountId. - fn seal_caller(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + #[prefixed_alias] + fn caller(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Caller)?; Ok(ctx.write_sandbox_output( out_ptr, @@ -1583,7 +1595,8 @@ pub mod env { /// `T::AccountId`. Traps otherwise. /// /// Returned value is a u32-encoded boolean: (0 = false, 1 = true). - fn seal_is_contract(ctx: Runtime, account_ptr: u32) -> Result { + #[prefixed_alias] + fn is_contract(ctx: Runtime, account_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::IsContract)?; let address: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(account_ptr)?; @@ -1604,8 +1617,9 @@ pub mod env { /// # Errors /// /// `ReturnCode::KeyNotFound` - fn seal_code_hash( - ctx: Runtime, + #[prefixed_alias] + fn code_hash( + ctx: Runtime, account_ptr: u32, out_ptr: u32, out_len_ptr: u32, @@ -1634,11 +1648,8 @@ pub mod env { /// - `out_ptr`: pointer to the linear memory where the returning value is written to. /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and /// the value length is written to. - fn seal_own_code_hash( - ctx: Runtime, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { + #[prefixed_alias] + fn own_code_hash(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::OwnCodeHash)?; let code_hash_encoded = &ctx.ext.own_code_hash().encode(); Ok(ctx.write_sandbox_output( @@ -1660,7 +1671,8 @@ pub mod env { /// and `false` indicates that the caller is another contract. /// /// Returned value is a u32-encoded boolean: (0 = false, 1 = true). - fn seal_caller_is_origin(ctx: Runtime) -> Result { + #[prefixed_alias] + fn caller_is_origin(ctx: Runtime) -> Result { ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?; Ok(ctx.ext.caller_is_origin() as u32) } @@ -1671,11 +1683,8 @@ pub mod env { /// `out_len_ptr` must point to a u32 value that describes the available space at /// `out_ptr`. This call overwrites it with the size of the value. If the available /// space at `out_ptr` is less than the size of the value a trap is triggered. - fn seal_address( - ctx: Runtime, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { + #[prefixed_alias] + fn address(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Address)?; Ok(ctx.write_sandbox_output( out_ptr, @@ -1699,8 +1708,9 @@ pub mod env { /// /// It is recommended to avoid specifying very small values for `gas` as the prices for a single /// gas can be smaller than one. - fn seal_weight_to_fee( - ctx: Runtime, + #[prefixed_alias] + fn weight_to_fee( + ctx: Runtime, gas: u64, out_ptr: u32, out_len_ptr: u32, @@ -1724,11 +1734,8 @@ pub mod env { /// space at `out_ptr` is less than the size of the value a trap is triggered. /// /// The data is encoded as Gas. - fn seal_gas_left( - ctx: Runtime, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { + #[prefixed_alias] + fn gas_left(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::GasLeft)?; let gas_left = &ctx.ext.gas_meter().gas_left().encode(); Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, gas_left, false, already_charged)?) @@ -1742,11 +1749,8 @@ pub mod env { /// space at `out_ptr` is less than the size of the value a trap is triggered. /// /// The data is encoded as T::Balance. - fn seal_balance( - ctx: Runtime, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { + #[prefixed_alias] + fn balance(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Balance)?; Ok(ctx.write_sandbox_output( out_ptr, @@ -1765,8 +1769,9 @@ pub mod env { /// space at `out_ptr` is less than the size of the value a trap is triggered. /// /// The data is encoded as T::Balance. - fn seal_value_transferred( - ctx: Runtime, + #[prefixed_alias] + fn value_transferred( + ctx: Runtime, out_ptr: u32, out_len_ptr: u32, ) -> Result<(), TrapReason> { @@ -1792,8 +1797,9 @@ pub mod env { /// # Deprecation /// /// This function is deprecated. Users should migrate to the version in the "seal1" module. - fn seal_random( - ctx: Runtime, + #[prefixed_alias] + fn random( + ctx: Runtime, subject_ptr: u32, subject_len: u32, out_ptr: u32, @@ -1835,8 +1841,9 @@ pub mod env { /// call this on later blocks until the block number returned is later than the latest /// commitment. #[version(1)] - fn seal_random( - ctx: Runtime, + #[prefixed_alias] + fn random( + ctx: Runtime, subject_ptr: u32, subject_len: u32, out_ptr: u32, @@ -1862,7 +1869,8 @@ pub mod env { /// `out_len_ptr` must point to a u32 value that describes the available space at /// `out_ptr`. This call overwrites it with the size of the value. If the available /// space at `out_ptr` is less than the size of the value a trap is triggered. - fn seal_now(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + #[prefixed_alias] + fn now(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Now)?; Ok(ctx.write_sandbox_output( out_ptr, @@ -1876,11 +1884,8 @@ pub mod env { /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. /// /// The data is encoded as T::Balance. - fn seal_minimum_balance( - ctx: Runtime, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { + #[prefixed_alias] + fn minimum_balance(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::MinimumBalance)?; Ok(ctx.write_sandbox_output( out_ptr, @@ -1901,8 +1906,9 @@ pub mod env { /// # Deprecation /// /// There is no longer a tombstone deposit. This function always returns 0. - fn seal_tombstone_deposit( - ctx: Runtime, + #[prefixed_alias] + fn tombstone_deposit( + ctx: Runtime, out_ptr: u32, out_len_ptr: u32, ) -> Result<(), TrapReason> { @@ -1917,8 +1923,9 @@ pub mod env { /// /// The state rent functionality was removed. This is stub only exists for /// backwards compatiblity - fn seal_restore_to( - ctx: Runtime, + #[prefixed_alias] + fn restore_to( + ctx: Runtime, _dest_ptr: u32, _dest_len: u32, _code_hash_ptr: u32, @@ -1939,8 +1946,9 @@ pub mod env { /// The state rent functionality was removed. This is stub only exists for /// backwards compatiblity #[version(1)] - fn seal_restore_to( - ctx: Runtime, + #[prefixed_alias] + fn restore_to( + ctx: Runtime, _dest_ptr: u32, _code_hash_ptr: u32, _rent_allowance_ptr: u32, @@ -1959,8 +1967,9 @@ pub mod env { /// - topics_len - the length of the topics buffer. Pass 0 if you want to pass an empty vector. /// - data_ptr - a pointer to a raw data buffer which will saved along the event. /// - data_len - the length of the data buffer. - fn seal_deposit_event( - ctx: Runtime, + #[prefixed_alias] + fn deposit_event( + ctx: Runtime, topics_ptr: u32, topics_len: u32, data_ptr: u32, @@ -2017,8 +2026,9 @@ pub mod env { /// /// The state rent functionality was removed. This is stub only exists for /// backwards compatiblity. - fn seal_set_rent_allowance( - ctx: Runtime, + #[prefixed_alias] + fn set_rent_allowance( + ctx: Runtime, _value_ptr: u32, _value_len: u32, ) -> Result<(), TrapReason> { @@ -2033,7 +2043,8 @@ pub mod env { /// The state rent functionality was removed. This is stub only exists for /// backwards compatiblity. #[version(1)] - fn seal_set_rent_allowance(ctx: Runtime, _value_ptr: u32) -> Result<(), TrapReason> { + #[prefixed_alias] + fn set_rent_allowance(ctx: Runtime, _value_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::DebugMessage)?; Ok(()) } @@ -2044,11 +2055,8 @@ pub mod env { /// /// The state rent functionality was removed. This is stub only exists for /// backwards compatiblity. - fn seal_rent_allowance( - ctx: Runtime, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { + #[prefixed_alias] + fn rent_allowance(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Balance)?; let rent_allowance = >::max_value().encode(); Ok(ctx.write_sandbox_output( @@ -2066,11 +2074,8 @@ pub mod env { /// `out_len_ptr` must point to a u32 value that describes the available space at /// `out_ptr`. This call overwrites it with the size of the value. If the available /// space at `out_ptr` is less than the size of the value a trap is triggered. - fn seal_block_number( - ctx: Runtime, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { + #[prefixed_alias] + fn block_number(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::BlockNumber)?; Ok(ctx.write_sandbox_output( out_ptr, @@ -2098,8 +2103,9 @@ pub mod env { /// - `input_len`: the length of the input data in bytes. /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The /// function will write the result directly into this buffer. - fn seal_hash_sha2_256( - ctx: Runtime, + #[prefixed_alias] + fn hash_sha2_256( + ctx: Runtime, input_ptr: u32, input_len: u32, output_ptr: u32, @@ -2125,8 +2131,9 @@ pub mod env { /// - `input_len`: the length of the input data in bytes. /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The /// function will write the result directly into this buffer. - fn seal_hash_keccak_256( - ctx: Runtime, + #[prefixed_alias] + fn hash_keccak_256( + ctx: Runtime, input_ptr: u32, input_len: u32, output_ptr: u32, @@ -2152,8 +2159,9 @@ pub mod env { /// - `input_len`: the length of the input data in bytes. /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The /// function will write the result directly into this buffer. - fn seal_hash_blake2_256( - ctx: Runtime, + #[prefixed_alias] + fn hash_blake2_256( + ctx: Runtime, input_ptr: u32, input_len: u32, output_ptr: u32, @@ -2179,8 +2187,9 @@ pub mod env { /// - `input_len`: the length of the input data in bytes. /// - `output_ptr`: the pointer into the linear memory where the output data is placed. The /// function will write the result directly into this buffer. - fn seal_hash_blake2_128( - ctx: Runtime, + #[prefixed_alias] + fn hash_blake2_128( + ctx: Runtime, input_ptr: u32, input_len: u32, output_ptr: u32, @@ -2200,8 +2209,9 @@ pub mod env { /// /// If no chain extension exists the contract will trap with the `NoChainExtension` /// module error. - fn seal_call_chain_extension( - ctx: Runtime, + #[prefixed_alias] + fn call_chain_extension( + ctx: Runtime, id: u32, input_ptr: u32, input_len: u32, @@ -2243,8 +2253,9 @@ pub mod env { /// not being executed as an RPC. For example, they could allow users to disable logging /// through compile time flags (cargo features) for on-chain deployment. Additionally, the /// return value of this function can be cached in order to prevent further calls at runtime. - fn seal_debug_message( - ctx: Runtime, + #[prefixed_alias] + fn debug_message( + ctx: Runtime, str_ptr: u32, str_len: u32, ) -> Result { @@ -2297,8 +2308,9 @@ pub mod env { /// This function is unstable and subject to change (or removal) in the future. Do not /// deploy a contract using it to a production chain. #[unstable] - fn seal_call_runtime( - ctx: Runtime, + #[prefixed_alias] + fn call_runtime( + ctx: Runtime, call_ptr: u32, call_len: u32, ) -> Result { @@ -2334,8 +2346,9 @@ pub mod env { /// # Errors /// /// `ReturnCode::EcdsaRecoverFailed` - fn seal_ecdsa_recover( - ctx: Runtime, + #[prefixed_alias] + fn ecdsa_recover( + ctx: Runtime, signature_ptr: u32, message_hash_ptr: u32, output_ptr: u32, @@ -2387,10 +2400,8 @@ pub mod env { /// # Errors /// /// `ReturnCode::CodeNotFound` - fn seal_set_code_hash( - ctx: Runtime, - code_hash_ptr: u32, - ) -> Result { + #[prefixed_alias] + fn set_code_hash(ctx: Runtime, code_hash_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::SetCodeHash)?; let code_hash: CodeHash<::T> = ctx.read_sandbox_memory_as(code_hash_ptr)?; match ctx.ext.set_code_hash(code_hash) { @@ -2418,8 +2429,9 @@ pub mod env { /// # Errors /// /// `ReturnCode::EcdsaRecoverFailed` - fn seal_ecdsa_to_eth_address( - ctx: Runtime, + #[prefixed_alias] + fn ecdsa_to_eth_address( + ctx: Runtime, key_ptr: u32, out_ptr: u32, ) -> Result { From 021f71264133d1cf0db5bd3e0112dbf8dcecdd9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 7 Sep 2022 14:49:44 +0100 Subject: [PATCH 1132/1472] Update contract weights (#12192) * Dummy commit * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts Co-authored-by: command-bot <> --- frame/contracts/src/weights.rs | 1876 +++++++++++++++++--------------- 1 file changed, 984 insertions(+), 892 deletions(-) diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index f1f80ba7a43df..4ec30437c57f1 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,22 +18,22 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-06-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-09-06, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_contracts // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 +// --pallet=pallet_contracts +// --chain=dev // --output=./frame/contracts/src/weights.rs // --template=./.maintain/frame-weight-template.hbs @@ -166,25 +166,25 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(1_654_000 as u64) + Weight::from_ref_time(2_948_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(8_564_000 as u64) + Weight::from_ref_time(14_858_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(k as u64)) + .saturating_add(Weight::from_ref_time(890_000 as u64).saturating_mul(k as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Contracts DeletionQueue (r:1 w:0) - /// The range of component `q` is `[0, 1024]`. + /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_944_000 as u64).saturating_mul(q as u64)) + Weight::from_ref_time(14_778_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_228_000 as u64).saturating_mul(q as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -192,9 +192,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(19_016_000 as u64) + Weight::from_ref_time(21_622_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(49_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -202,31 +202,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(205_194_000 as u64) + Weight::from_ref_time(207_601_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(53_000 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:3 w:3) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(288_487_000 as u64) + Weight::from_ref_time(287_355_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(c as u64)) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().writes(9 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -234,526 +236,560 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(186_136_000 as u64) + Weight::from_ref_time(178_912_000 as u64) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().writes(7 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(149_232_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + Weight::from_ref_time(159_188_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) + // Storage: System EventTopics (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(51_721_000 as u64) + Weight::from_ref_time(52_177_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(48_000 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(Weight::from_ref_time(47_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:1 w:1) // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(30_016_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + Weight::from_ref_time(37_011_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) + // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(27_192_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + Weight::from_ref_time(40_206_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(206_405_000 as u64) - // Standard Error: 112_000 - .saturating_add(Weight::from_ref_time(40_987_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(224_309_000 as u64) + // Standard Error: 53_000 + .saturating_add(Weight::from_ref_time(36_885_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(106_220_000 as u64) - // Standard Error: 710_000 - .saturating_add(Weight::from_ref_time(307_648_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(166_137_000 as u64) + // Standard Error: 428_000 + .saturating_add(Weight::from_ref_time(214_063_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(104_498_000 as u64) - // Standard Error: 633_000 - .saturating_add(Weight::from_ref_time(368_901_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(174_069_000 as u64) + // Standard Error: 443_000 + .saturating_add(Weight::from_ref_time(272_524_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(208_696_000 as u64) - // Standard Error: 101_000 - .saturating_add(Weight::from_ref_time(44_445_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(225_577_000 as u64) + // Standard Error: 39_000 + .saturating_add(Weight::from_ref_time(40_425_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(205_612_000 as u64) - // Standard Error: 68_000 - .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(221_162_000 as u64) + // Standard Error: 20_000 + .saturating_add(Weight::from_ref_time(15_192_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(206_947_000 as u64) - // Standard Error: 107_000 - .saturating_add(Weight::from_ref_time(40_789_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(224_517_000 as u64) + // Standard Error: 38_000 + .saturating_add(Weight::from_ref_time(36_722_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(208_692_000 as u64) - // Standard Error: 109_000 - .saturating_add(Weight::from_ref_time(40_600_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(223_864_000 as u64) + // Standard Error: 35_000 + .saturating_add(Weight::from_ref_time(36_355_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_811_000 as u64) - // Standard Error: 208_000 - .saturating_add(Weight::from_ref_time(116_831_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(226_396_000 as u64) + // Standard Error: 86_000 + .saturating_add(Weight::from_ref_time(112_018_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(207_406_000 as u64) - // Standard Error: 117_000 - .saturating_add(Weight::from_ref_time(40_702_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(222_775_000 as u64) + // Standard Error: 45_000 + .saturating_add(Weight::from_ref_time(36_691_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_260_000 as u64) - // Standard Error: 130_000 - .saturating_add(Weight::from_ref_time(40_479_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(223_202_000 as u64) + // Standard Error: 42_000 + .saturating_add(Weight::from_ref_time(36_393_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(206_448_000 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(40_134_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(223_507_000 as u64) + // Standard Error: 44_000 + .saturating_add(Weight::from_ref_time(36_211_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(206_969_000 as u64) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(40_251_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(225_500_000 as u64) + // Standard Error: 58_000 + .saturating_add(Weight::from_ref_time(36_290_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(211_611_000 as u64) - // Standard Error: 175_000 - .saturating_add(Weight::from_ref_time(98_675_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(225_310_000 as u64) + // Standard Error: 86_000 + .saturating_add(Weight::from_ref_time(98_714_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(134_484_000 as u64) - // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(19_329_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(149_071_000 as u64) + // Standard Error: 30_000 + .saturating_add(Weight::from_ref_time(18_084_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(208_556_000 as u64) - // Standard Error: 125_000 - .saturating_add(Weight::from_ref_time(40_328_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(222_918_000 as u64) + // Standard Error: 48_000 + .saturating_add(Weight::from_ref_time(34_848_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(268_886_000 as u64) + Weight::from_ref_time(280_543_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_627_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(9_599_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. - fn seal_return(_r: u32, ) -> Weight { - Weight::from_ref_time(203_591_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + fn seal_return(r: u32, ) -> Weight { + Weight::from_ref_time(219_310_000 as u64) + // Standard Error: 303_000 + .saturating_add(Weight::from_ref_time(1_187_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(204_258_000 as u64) + Weight::from_ref_time(221_399_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(183_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(182_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(206_625_000 as u64) - // Standard Error: 672_000 - .saturating_add(Weight::from_ref_time(59_377_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(r as u64))) + Weight::from_ref_time(222_285_000 as u64) + // Standard Error: 163_000 + .saturating_add(Weight::from_ref_time(52_104_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((6 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(208_866_000 as u64) - // Standard Error: 164_000 - .saturating_add(Weight::from_ref_time(133_438_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(233_586_000 as u64) + // Standard Error: 90_000 + .saturating_add(Weight::from_ref_time(133_209_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(220_860_000 as u64) - // Standard Error: 209_000 - .saturating_add(Weight::from_ref_time(239_951_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(231_267_000 as u64) + // Standard Error: 118_000 + .saturating_add(Weight::from_ref_time(232_306_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:80 w:80) + // Storage: System EventTopics (r:2 w:2) /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(439_782_000 as u64) - // Standard Error: 1_643_000 - .saturating_add(Weight::from_ref_time(264_687_000 as u64).saturating_mul(t as u64)) - // Standard Error: 323_000 - .saturating_add(Weight::from_ref_time(67_636_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(438_016_000 as u64) + // Standard Error: 538_000 + .saturating_add(Weight::from_ref_time(179_846_000 as u64).saturating_mul(t as u64)) + // Standard Error: 147_000 + .saturating_add(Weight::from_ref_time(66_893_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(t as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(140_280_000 as u64) - // Standard Error: 82_000 - .saturating_add(Weight::from_ref_time(32_717_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(156_730_000 as u64) + // Standard Error: 48_000 + .saturating_add(Weight::from_ref_time(29_019_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(161_247_000 as u64) - // Standard Error: 883_000 - .saturating_add(Weight::from_ref_time(423_997_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(185_733_000 as u64) + // Standard Error: 384_000 + .saturating_add(Weight::from_ref_time(427_052_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_247_000 as u64) - // Standard Error: 2_745_000 - .saturating_add(Weight::from_ref_time(85_282_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(55 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(53 as u64)) - .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(520_776_000 as u64) + // Standard Error: 1_346_000 + .saturating_add(Weight::from_ref_time(93_389_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(52 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(50 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_812_000 as u64) - // Standard Error: 2_513_000 - .saturating_add(Weight::from_ref_time(74_554_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(55 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(53 as u64)) - .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(504_262_000 as u64) + // Standard Error: 1_198_000 + .saturating_add(Weight::from_ref_time(68_581_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(52 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(50 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(184_803_000 as u64) - // Standard Error: 733_000 - .saturating_add(Weight::from_ref_time(404_933_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) + Weight::from_ref_time(188_507_000 as u64) + // Standard Error: 514_000 + .saturating_add(Weight::from_ref_time(416_965_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(500_958_000 as u64) - // Standard Error: 2_980_000 - .saturating_add(Weight::from_ref_time(75_996_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(55 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(52 as u64)) - .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(481_328_000 as u64) + // Standard Error: 1_304_000 + .saturating_add(Weight::from_ref_time(70_798_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(49 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(177_682_000 as u64) - // Standard Error: 743_000 - .saturating_add(Weight::from_ref_time(338_172_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(200_040_000 as u64) + // Standard Error: 292_000 + .saturating_add(Weight::from_ref_time(341_568_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(465_285_000 as u64) - // Standard Error: 2_599_000 - .saturating_add(Weight::from_ref_time(155_106_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(55 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(443_969_000 as u64) + // Standard Error: 1_076_000 + .saturating_add(Weight::from_ref_time(154_674_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(179_118_000 as u64) - // Standard Error: 572_000 - .saturating_add(Weight::from_ref_time(311_083_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(194_849_000 as u64) + // Standard Error: 310_000 + .saturating_add(Weight::from_ref_time(320_113_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(423_056_000 as u64) - // Standard Error: 2_037_000 - .saturating_add(Weight::from_ref_time(69_665_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(54 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(416_712_000 as u64) + // Standard Error: 932_000 + .saturating_add(Weight::from_ref_time(63_903_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(188_884_000 as u64) - // Standard Error: 761_000 - .saturating_add(Weight::from_ref_time(432_781_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) + Weight::from_ref_time(194_760_000 as u64) + // Standard Error: 375_000 + .saturating_add(Weight::from_ref_time(438_855_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(532_408_000 as u64) - // Standard Error: 3_348_000 - .saturating_add(Weight::from_ref_time(164_943_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(55 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(53 as u64)) - .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(509_485_000 as u64) + // Standard Error: 1_486_000 + .saturating_add(Weight::from_ref_time(162_250_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(52 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(49 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(127_181_000 as u64) - // Standard Error: 1_495_000 - .saturating_add(Weight::from_ref_time(1_500_589_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) + Weight::from_ref_time(162_740_000 as u64) + // Standard Error: 691_000 + .saturating_add(Weight::from_ref_time(1_338_567_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 3_803_000 - .saturating_add(Weight::from_ref_time(14_860_909_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Standard Error: 8_018_000 + .saturating_add(Weight::from_ref_time(16_181_274_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().reads((160 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((160 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 6_045_000 - .saturating_add(Weight::from_ref_time(14_797_140_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads((79 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Standard Error: 8_806_000 + .saturating_add(Weight::from_ref_time(15_988_209_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads((158 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes((79 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:82 w:82) /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(9_196_444_000 as u64) - // Standard Error: 20_486_000 - .saturating_add(Weight::from_ref_time(1_458_153_000 as u64).saturating_mul(t as u64)) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(9_718_000 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(85 as u64)) + Weight::from_ref_time(9_685_415_000 as u64) + // Standard Error: 6_048_000 + .saturating_add(Weight::from_ref_time(1_132_315_000 as u64).saturating_mul(t as u64)) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(9_753_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(167 as u64)) .saturating_add(T::DbWeight::get().reads((81 as u64).saturating_mul(t as u64))) - .saturating_add(T::DbWeight::get().writes(81 as u64)) + .saturating_add(T::DbWeight::get().writes(163 as u64)) .saturating_add(T::DbWeight::get().writes((81 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 36_253_000 - .saturating_add(Weight::from_ref_time(21_201_529_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((320 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((320 as u64).saturating_mul(r as u64))) + // Standard Error: 30_079_000 + .saturating_add(Weight::from_ref_time(21_155_990_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().reads((400 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(5 as u64)) + .saturating_add(T::DbWeight::get().writes((400 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:81 w:81) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -761,457 +797,467 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:82 w:82) /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(12_282_498_000 as u64) - // Standard Error: 48_112_000 - .saturating_add(Weight::from_ref_time(720_795_000 as u64).saturating_mul(t as u64)) - // Standard Error: 22_000 - .saturating_add(Weight::from_ref_time(124_274_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(167 as u64)) + Weight::from_ref_time(12_321_649_000 as u64) + // Standard Error: 77_000 + .saturating_add(Weight::from_ref_time(125_883_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(249 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(t as u64))) - .saturating_add(T::DbWeight::get().writes(165 as u64)) + .saturating_add(T::DbWeight::get().writes(247 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(203_959_000 as u64) - // Standard Error: 142_000 - .saturating_add(Weight::from_ref_time(61_311_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(224_020_000 as u64) + // Standard Error: 63_000 + .saturating_add(Weight::from_ref_time(57_966_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(349_915_000 as u64) - // Standard Error: 40_000 - .saturating_add(Weight::from_ref_time(320_652_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 86_000 + .saturating_add(Weight::from_ref_time(319_801_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(209_219_000 as u64) - // Standard Error: 157_000 - .saturating_add(Weight::from_ref_time(73_728_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(222_308_000 as u64) + // Standard Error: 78_000 + .saturating_add(Weight::from_ref_time(70_579_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(208_860_000 as u64) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(245_718_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 97_000 + .saturating_add(Weight::from_ref_time(247_328_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(206_165_000 as u64) - // Standard Error: 138_000 - .saturating_add(Weight::from_ref_time(51_644_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(221_851_000 as u64) + // Standard Error: 57_000 + .saturating_add(Weight::from_ref_time(48_446_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(255_955_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_090_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 93_000 + .saturating_add(Weight::from_ref_time(97_258_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(208_153_000 as u64) - // Standard Error: 140_000 - .saturating_add(Weight::from_ref_time(51_264_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(221_346_000 as u64) + // Standard Error: 46_000 + .saturating_add(Weight::from_ref_time(47_910_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(278_368_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_006_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 116_000 + .saturating_add(Weight::from_ref_time(97_458_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(331_955_000 as u64) - // Standard Error: 1_155_000 - .saturating_add(Weight::from_ref_time(3_069_955_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(355_672_000 as u64) + // Standard Error: 678_000 + .saturating_add(Weight::from_ref_time(2_970_861_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(207_838_000 as u64) - // Standard Error: 783_000 - .saturating_add(Weight::from_ref_time(2_058_503_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(232_179_000 as u64) + // Standard Error: 463_000 + .saturating_add(Weight::from_ref_time(2_059_953_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 1_567_000 - .saturating_add(Weight::from_ref_time(774_380_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads((79 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes((79 as u64).saturating_mul(r as u64))) + // Standard Error: 1_725_000 + .saturating_add(Weight::from_ref_time(1_107_351_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads((158 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes((158 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(73_955_000 as u64) + Weight::from_ref_time(70_023_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(612_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(848_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(74_057_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_335_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_761_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(74_137_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_427_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_875_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_289_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(73_844_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_773_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_128_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(2_288_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_952_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(68_850_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(2_558_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(73_924_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(941_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_585_000 as u64) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(1_293_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_574_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_439_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_492_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(73_343_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_603_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_344_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(2_089_000 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(76_267_000 as u64) + Weight::from_ref_time(72_833_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(e as u64)) + .saturating_add(Weight::from_ref_time(3_000 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(74_877_000 as u64) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(7_144_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_722_000 as u64) + // Standard Error: 10_000 + .saturating_add(Weight::from_ref_time(6_545_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(88_665_000 as u64) - // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(9_142_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(84_465_000 as u64) + // Standard Error: 13_000 + .saturating_add(Weight::from_ref_time(8_307_000 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(98_600_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(469_000 as u64).saturating_mul(p as u64)) + Weight::from_ref_time(93_185_000 as u64) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(599_000 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(74_555_000 as u64) + Weight::from_ref_time(70_473_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(624_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(875_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(74_329_000 as u64) + Weight::from_ref_time(70_352_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(688_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(907_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(74_612_000 as u64) + Weight::from_ref_time(70_239_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(909_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_219_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(76_906_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_192_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_049_000 as u64) + // Standard Error: 7_000 + .saturating_add(Weight::from_ref_time(1_543_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(76_979_000 as u64) + Weight::from_ref_time(72_551_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_361_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_693_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(74_370_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(661_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_228_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(889_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(73_584_000 as u64) - // Standard Error: 353_000 - .saturating_add(Weight::from_ref_time(187_114_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_987_000 as u64) + // Standard Error: 88_000 + .saturating_add(Weight::from_ref_time(186_348_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(74_206_000 as u64) + Weight::from_ref_time(70_186_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(884_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_304_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(73_992_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(893_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_796_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(73_985_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(891_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_184_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_315_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(74_117_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_059_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_316_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(73_981_000 as u64) + Weight::from_ref_time(70_066_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(866_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_282_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(74_104_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_100_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_285_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(74_293_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(878_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_992_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_330_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(74_055_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_935_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_829_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(73_710_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_024_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(1_820_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(73_917_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_794_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_831_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(74_048_000 as u64) + Weight::from_ref_time(69_997_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_817_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(74_029_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_349_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_610_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_804_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(74_267_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_759_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_846_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(73_952_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_405_000 as u64) + // Standard Error: 8_000 + .saturating_add(Weight::from_ref_time(1_808_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(73_851_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_368_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_968_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_838_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(74_034_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_348_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_825_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_854_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_973_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_822_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(74_000_000 as u64) + Weight::from_ref_time(69_907_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_328_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_824_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(73_883_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_331_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_280_000 as u64) + // Standard Error: 16_000 + .saturating_add(Weight::from_ref_time(1_756_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(74_216_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_827_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(73_989_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_998_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_995_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(2_461_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(73_857_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_073_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_627_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_453_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(73_801_000 as u64) + Weight::from_ref_time(70_040_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_027_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(2_456_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(74_130_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_064_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_754_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_450_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(74_071_000 as u64) + Weight::from_ref_time(69_848_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_327_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_836_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(74_201_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_330_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_904_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_837_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(74_241_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_321_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_912_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_839_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(74_331_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_347_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_656_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_858_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(73_674_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_359_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_927_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(73_807_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_025_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(73_725_000 as u64) + Weight::from_ref_time(69_916_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_843_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(73_755_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_988_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_842_000 as u64).saturating_mul(r as u64)) } } @@ -1219,25 +1265,25 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(1_654_000 as u64) + Weight::from_ref_time(2_948_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(8_564_000 as u64) + Weight::from_ref_time(14_858_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(k as u64)) + .saturating_add(Weight::from_ref_time(890_000 as u64).saturating_mul(k as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Contracts DeletionQueue (r:1 w:0) - /// The range of component `q` is `[0, 1024]`. + /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_944_000 as u64).saturating_mul(q as u64)) + Weight::from_ref_time(14_778_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_228_000 as u64).saturating_mul(q as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1245,9 +1291,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(19_016_000 as u64) + Weight::from_ref_time(21_622_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(49_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1255,31 +1301,33 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(205_194_000 as u64) + Weight::from_ref_time(207_601_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(53_000 as u64).saturating_mul(c as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:3 w:3) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(288_487_000 as u64) + Weight::from_ref_time(287_355_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(c as u64)) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().writes(9 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -1287,526 +1335,560 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(186_136_000 as u64) + Weight::from_ref_time(178_912_000 as u64) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().writes(7 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(149_232_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + Weight::from_ref_time(159_188_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) + // Storage: System EventTopics (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(51_721_000 as u64) + Weight::from_ref_time(52_177_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(48_000 as u64).saturating_mul(c as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(Weight::from_ref_time(47_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:1 w:1) // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(30_016_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + Weight::from_ref_time(37_011_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) + // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(27_192_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + Weight::from_ref_time(40_206_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(206_405_000 as u64) - // Standard Error: 112_000 - .saturating_add(Weight::from_ref_time(40_987_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(224_309_000 as u64) + // Standard Error: 53_000 + .saturating_add(Weight::from_ref_time(36_885_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(106_220_000 as u64) - // Standard Error: 710_000 - .saturating_add(Weight::from_ref_time(307_648_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(166_137_000 as u64) + // Standard Error: 428_000 + .saturating_add(Weight::from_ref_time(214_063_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(104_498_000 as u64) - // Standard Error: 633_000 - .saturating_add(Weight::from_ref_time(368_901_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(174_069_000 as u64) + // Standard Error: 443_000 + .saturating_add(Weight::from_ref_time(272_524_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(208_696_000 as u64) - // Standard Error: 101_000 - .saturating_add(Weight::from_ref_time(44_445_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(225_577_000 as u64) + // Standard Error: 39_000 + .saturating_add(Weight::from_ref_time(40_425_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(205_612_000 as u64) - // Standard Error: 68_000 - .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(221_162_000 as u64) + // Standard Error: 20_000 + .saturating_add(Weight::from_ref_time(15_192_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(206_947_000 as u64) - // Standard Error: 107_000 - .saturating_add(Weight::from_ref_time(40_789_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(224_517_000 as u64) + // Standard Error: 38_000 + .saturating_add(Weight::from_ref_time(36_722_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(208_692_000 as u64) - // Standard Error: 109_000 - .saturating_add(Weight::from_ref_time(40_600_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(223_864_000 as u64) + // Standard Error: 35_000 + .saturating_add(Weight::from_ref_time(36_355_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_811_000 as u64) - // Standard Error: 208_000 - .saturating_add(Weight::from_ref_time(116_831_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(226_396_000 as u64) + // Standard Error: 86_000 + .saturating_add(Weight::from_ref_time(112_018_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(207_406_000 as u64) - // Standard Error: 117_000 - .saturating_add(Weight::from_ref_time(40_702_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(222_775_000 as u64) + // Standard Error: 45_000 + .saturating_add(Weight::from_ref_time(36_691_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_260_000 as u64) - // Standard Error: 130_000 - .saturating_add(Weight::from_ref_time(40_479_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(223_202_000 as u64) + // Standard Error: 42_000 + .saturating_add(Weight::from_ref_time(36_393_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(206_448_000 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(40_134_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(223_507_000 as u64) + // Standard Error: 44_000 + .saturating_add(Weight::from_ref_time(36_211_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(206_969_000 as u64) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(40_251_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(225_500_000 as u64) + // Standard Error: 58_000 + .saturating_add(Weight::from_ref_time(36_290_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(211_611_000 as u64) - // Standard Error: 175_000 - .saturating_add(Weight::from_ref_time(98_675_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(225_310_000 as u64) + // Standard Error: 86_000 + .saturating_add(Weight::from_ref_time(98_714_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(134_484_000 as u64) - // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(19_329_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(149_071_000 as u64) + // Standard Error: 30_000 + .saturating_add(Weight::from_ref_time(18_084_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(208_556_000 as u64) - // Standard Error: 125_000 - .saturating_add(Weight::from_ref_time(40_328_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(222_918_000 as u64) + // Standard Error: 48_000 + .saturating_add(Weight::from_ref_time(34_848_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(268_886_000 as u64) + Weight::from_ref_time(280_543_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_627_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(9_599_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. - fn seal_return(_r: u32, ) -> Weight { - Weight::from_ref_time(203_591_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + fn seal_return(r: u32, ) -> Weight { + Weight::from_ref_time(219_310_000 as u64) + // Standard Error: 303_000 + .saturating_add(Weight::from_ref_time(1_187_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(204_258_000 as u64) + Weight::from_ref_time(221_399_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(183_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(182_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(206_625_000 as u64) - // Standard Error: 672_000 - .saturating_add(Weight::from_ref_time(59_377_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(r as u64))) + Weight::from_ref_time(222_285_000 as u64) + // Standard Error: 163_000 + .saturating_add(Weight::from_ref_time(52_104_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((6 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(208_866_000 as u64) - // Standard Error: 164_000 - .saturating_add(Weight::from_ref_time(133_438_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(233_586_000 as u64) + // Standard Error: 90_000 + .saturating_add(Weight::from_ref_time(133_209_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(220_860_000 as u64) - // Standard Error: 209_000 - .saturating_add(Weight::from_ref_time(239_951_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(231_267_000 as u64) + // Standard Error: 118_000 + .saturating_add(Weight::from_ref_time(232_306_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:80 w:80) + // Storage: System EventTopics (r:2 w:2) /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(439_782_000 as u64) - // Standard Error: 1_643_000 - .saturating_add(Weight::from_ref_time(264_687_000 as u64).saturating_mul(t as u64)) - // Standard Error: 323_000 - .saturating_add(Weight::from_ref_time(67_636_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(438_016_000 as u64) + // Standard Error: 538_000 + .saturating_add(Weight::from_ref_time(179_846_000 as u64).saturating_mul(t as u64)) + // Standard Error: 147_000 + .saturating_add(Weight::from_ref_time(66_893_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(t as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(140_280_000 as u64) - // Standard Error: 82_000 - .saturating_add(Weight::from_ref_time(32_717_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(156_730_000 as u64) + // Standard Error: 48_000 + .saturating_add(Weight::from_ref_time(29_019_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(161_247_000 as u64) - // Standard Error: 883_000 - .saturating_add(Weight::from_ref_time(423_997_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(185_733_000 as u64) + // Standard Error: 384_000 + .saturating_add(Weight::from_ref_time(427_052_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_247_000 as u64) - // Standard Error: 2_745_000 - .saturating_add(Weight::from_ref_time(85_282_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(55 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(53 as u64)) - .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(520_776_000 as u64) + // Standard Error: 1_346_000 + .saturating_add(Weight::from_ref_time(93_389_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(52 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(50 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_812_000 as u64) - // Standard Error: 2_513_000 - .saturating_add(Weight::from_ref_time(74_554_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(55 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(53 as u64)) - .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(504_262_000 as u64) + // Standard Error: 1_198_000 + .saturating_add(Weight::from_ref_time(68_581_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(52 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(50 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(184_803_000 as u64) - // Standard Error: 733_000 - .saturating_add(Weight::from_ref_time(404_933_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) + Weight::from_ref_time(188_507_000 as u64) + // Standard Error: 514_000 + .saturating_add(Weight::from_ref_time(416_965_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(500_958_000 as u64) - // Standard Error: 2_980_000 - .saturating_add(Weight::from_ref_time(75_996_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(55 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(52 as u64)) - .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(481_328_000 as u64) + // Standard Error: 1_304_000 + .saturating_add(Weight::from_ref_time(70_798_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(49 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(177_682_000 as u64) - // Standard Error: 743_000 - .saturating_add(Weight::from_ref_time(338_172_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(200_040_000 as u64) + // Standard Error: 292_000 + .saturating_add(Weight::from_ref_time(341_568_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(465_285_000 as u64) - // Standard Error: 2_599_000 - .saturating_add(Weight::from_ref_time(155_106_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(55 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(443_969_000 as u64) + // Standard Error: 1_076_000 + .saturating_add(Weight::from_ref_time(154_674_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(179_118_000 as u64) - // Standard Error: 572_000 - .saturating_add(Weight::from_ref_time(311_083_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(194_849_000 as u64) + // Standard Error: 310_000 + .saturating_add(Weight::from_ref_time(320_113_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(423_056_000 as u64) - // Standard Error: 2_037_000 - .saturating_add(Weight::from_ref_time(69_665_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(54 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(416_712_000 as u64) + // Standard Error: 932_000 + .saturating_add(Weight::from_ref_time(63_903_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(188_884_000 as u64) - // Standard Error: 761_000 - .saturating_add(Weight::from_ref_time(432_781_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) + Weight::from_ref_time(194_760_000 as u64) + // Standard Error: 375_000 + .saturating_add(Weight::from_ref_time(438_855_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(532_408_000 as u64) - // Standard Error: 3_348_000 - .saturating_add(Weight::from_ref_time(164_943_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(55 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(53 as u64)) - .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(509_485_000 as u64) + // Standard Error: 1_486_000 + .saturating_add(Weight::from_ref_time(162_250_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(52 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(49 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(127_181_000 as u64) - // Standard Error: 1_495_000 - .saturating_add(Weight::from_ref_time(1_500_589_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) + Weight::from_ref_time(162_740_000 as u64) + // Standard Error: 691_000 + .saturating_add(Weight::from_ref_time(1_338_567_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 3_803_000 - .saturating_add(Weight::from_ref_time(14_860_909_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Standard Error: 8_018_000 + .saturating_add(Weight::from_ref_time(16_181_274_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().reads((160 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((160 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 6_045_000 - .saturating_add(Weight::from_ref_time(14_797_140_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads((79 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Standard Error: 8_806_000 + .saturating_add(Weight::from_ref_time(15_988_209_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads((158 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes((79 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:82 w:82) /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(9_196_444_000 as u64) - // Standard Error: 20_486_000 - .saturating_add(Weight::from_ref_time(1_458_153_000 as u64).saturating_mul(t as u64)) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(9_718_000 as u64).saturating_mul(c as u64)) - .saturating_add(RocksDbWeight::get().reads(85 as u64)) + Weight::from_ref_time(9_685_415_000 as u64) + // Standard Error: 6_048_000 + .saturating_add(Weight::from_ref_time(1_132_315_000 as u64).saturating_mul(t as u64)) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(9_753_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(167 as u64)) .saturating_add(RocksDbWeight::get().reads((81 as u64).saturating_mul(t as u64))) - .saturating_add(RocksDbWeight::get().writes(81 as u64)) + .saturating_add(RocksDbWeight::get().writes(163 as u64)) .saturating_add(RocksDbWeight::get().writes((81 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 36_253_000 - .saturating_add(Weight::from_ref_time(21_201_529_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((320 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((320 as u64).saturating_mul(r as u64))) + // Standard Error: 30_079_000 + .saturating_add(Weight::from_ref_time(21_155_990_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().reads((400 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) + .saturating_add(RocksDbWeight::get().writes((400 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:81 w:81) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -1814,456 +1896,466 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:82 w:82) /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(12_282_498_000 as u64) - // Standard Error: 48_112_000 - .saturating_add(Weight::from_ref_time(720_795_000 as u64).saturating_mul(t as u64)) - // Standard Error: 22_000 - .saturating_add(Weight::from_ref_time(124_274_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(167 as u64)) + Weight::from_ref_time(12_321_649_000 as u64) + // Standard Error: 77_000 + .saturating_add(Weight::from_ref_time(125_883_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(249 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(t as u64))) - .saturating_add(RocksDbWeight::get().writes(165 as u64)) + .saturating_add(RocksDbWeight::get().writes(247 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(203_959_000 as u64) - // Standard Error: 142_000 - .saturating_add(Weight::from_ref_time(61_311_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(224_020_000 as u64) + // Standard Error: 63_000 + .saturating_add(Weight::from_ref_time(57_966_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(349_915_000 as u64) - // Standard Error: 40_000 - .saturating_add(Weight::from_ref_time(320_652_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 86_000 + .saturating_add(Weight::from_ref_time(319_801_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(209_219_000 as u64) - // Standard Error: 157_000 - .saturating_add(Weight::from_ref_time(73_728_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(222_308_000 as u64) + // Standard Error: 78_000 + .saturating_add(Weight::from_ref_time(70_579_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(208_860_000 as u64) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(245_718_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 97_000 + .saturating_add(Weight::from_ref_time(247_328_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(206_165_000 as u64) - // Standard Error: 138_000 - .saturating_add(Weight::from_ref_time(51_644_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(221_851_000 as u64) + // Standard Error: 57_000 + .saturating_add(Weight::from_ref_time(48_446_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(255_955_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_090_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 93_000 + .saturating_add(Weight::from_ref_time(97_258_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(208_153_000 as u64) - // Standard Error: 140_000 - .saturating_add(Weight::from_ref_time(51_264_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(221_346_000 as u64) + // Standard Error: 46_000 + .saturating_add(Weight::from_ref_time(47_910_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(278_368_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_006_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 116_000 + .saturating_add(Weight::from_ref_time(97_458_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(331_955_000 as u64) - // Standard Error: 1_155_000 - .saturating_add(Weight::from_ref_time(3_069_955_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(355_672_000 as u64) + // Standard Error: 678_000 + .saturating_add(Weight::from_ref_time(2_970_861_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(207_838_000 as u64) - // Standard Error: 783_000 - .saturating_add(Weight::from_ref_time(2_058_503_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(232_179_000 as u64) + // Standard Error: 463_000 + .saturating_add(Weight::from_ref_time(2_059_953_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 1_567_000 - .saturating_add(Weight::from_ref_time(774_380_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads((79 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes((79 as u64).saturating_mul(r as u64))) + // Standard Error: 1_725_000 + .saturating_add(Weight::from_ref_time(1_107_351_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads((158 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes((158 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(73_955_000 as u64) + Weight::from_ref_time(70_023_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(612_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(848_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(74_057_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_335_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_761_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(74_137_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_427_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_875_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_289_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(73_844_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_773_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_128_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(2_288_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_952_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(68_850_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(2_558_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(73_924_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(941_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_585_000 as u64) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(1_293_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_574_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_439_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_492_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(73_343_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_603_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_344_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(2_089_000 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(76_267_000 as u64) + Weight::from_ref_time(72_833_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(e as u64)) + .saturating_add(Weight::from_ref_time(3_000 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(74_877_000 as u64) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(7_144_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_722_000 as u64) + // Standard Error: 10_000 + .saturating_add(Weight::from_ref_time(6_545_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(88_665_000 as u64) - // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(9_142_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(84_465_000 as u64) + // Standard Error: 13_000 + .saturating_add(Weight::from_ref_time(8_307_000 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(98_600_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(469_000 as u64).saturating_mul(p as u64)) + Weight::from_ref_time(93_185_000 as u64) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(599_000 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(74_555_000 as u64) + Weight::from_ref_time(70_473_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(624_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(875_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(74_329_000 as u64) + Weight::from_ref_time(70_352_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(688_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(907_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(74_612_000 as u64) + Weight::from_ref_time(70_239_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(909_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_219_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(76_906_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_192_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_049_000 as u64) + // Standard Error: 7_000 + .saturating_add(Weight::from_ref_time(1_543_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(76_979_000 as u64) + Weight::from_ref_time(72_551_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_361_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_693_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(74_370_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(661_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_228_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(889_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(73_584_000 as u64) - // Standard Error: 353_000 - .saturating_add(Weight::from_ref_time(187_114_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_987_000 as u64) + // Standard Error: 88_000 + .saturating_add(Weight::from_ref_time(186_348_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(74_206_000 as u64) + Weight::from_ref_time(70_186_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(884_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_304_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(73_992_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(893_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_796_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(73_985_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(891_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_184_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_315_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(74_117_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_059_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_316_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(73_981_000 as u64) + Weight::from_ref_time(70_066_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(866_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_282_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(74_104_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_100_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_285_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(74_293_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(878_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_992_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_330_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(74_055_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_935_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_829_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(73_710_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_024_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(1_820_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(73_917_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_794_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_831_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(74_048_000 as u64) + Weight::from_ref_time(69_997_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_817_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(74_029_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_349_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_610_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_804_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(74_267_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_759_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_846_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(73_952_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_405_000 as u64) + // Standard Error: 8_000 + .saturating_add(Weight::from_ref_time(1_808_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(73_851_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_368_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_968_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_838_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(74_034_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_348_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_825_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_854_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_973_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_822_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(74_000_000 as u64) + Weight::from_ref_time(69_907_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_328_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_824_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(73_883_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_331_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_280_000 as u64) + // Standard Error: 16_000 + .saturating_add(Weight::from_ref_time(1_756_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(74_216_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_827_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(73_989_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_998_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_995_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(2_461_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(73_857_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_073_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_627_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_453_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(73_801_000 as u64) + Weight::from_ref_time(70_040_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_027_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(2_456_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(74_130_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_064_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_754_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_450_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(74_071_000 as u64) + Weight::from_ref_time(69_848_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_327_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_836_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(74_201_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_330_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_904_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_837_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(74_241_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_321_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_912_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_839_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(74_331_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_347_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_656_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_858_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(73_674_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_359_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_927_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(73_807_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_025_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(73_725_000 as u64) + Weight::from_ref_time(69_916_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_843_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(73_755_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_988_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_842_000 as u64).saturating_mul(r as u64)) } } From 5e2ffeb21b0864f7b78ef819a33cba5da357beb1 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 7 Sep 2022 23:41:45 +0800 Subject: [PATCH 1133/1472] Move Get and bounded types to sp-core (#12203) * Move Get and bounded types to sp-core * Fixes * cargo fmt * Fixes --- primitives/{runtime => core}/src/bounded.rs | 0 .../src/bounded/bounded_btree_map.rs | 4 +- .../src/bounded/bounded_btree_set.rs | 4 +- .../src/bounded/bounded_vec.rs | 4 +- .../src/bounded/weak_bounded_vec.rs | 4 +- primitives/core/src/lib.rs | 237 ++++++++++++++++++ primitives/runtime/src/lib.rs | 47 +--- primitives/runtime/src/traits.rs | 202 +-------------- 8 files changed, 254 insertions(+), 248 deletions(-) rename primitives/{runtime => core}/src/bounded.rs (100%) rename primitives/{runtime => core}/src/bounded/bounded_btree_map.rs (99%) rename primitives/{runtime => core}/src/bounded/bounded_btree_set.rs (99%) rename primitives/{runtime => core}/src/bounded/bounded_vec.rs (99%) rename primitives/{runtime => core}/src/bounded/weak_bounded_vec.rs (99%) diff --git a/primitives/runtime/src/bounded.rs b/primitives/core/src/bounded.rs similarity index 100% rename from primitives/runtime/src/bounded.rs rename to primitives/core/src/bounded.rs diff --git a/primitives/runtime/src/bounded/bounded_btree_map.rs b/primitives/core/src/bounded/bounded_btree_map.rs similarity index 99% rename from primitives/runtime/src/bounded/bounded_btree_map.rs rename to primitives/core/src/bounded/bounded_btree_map.rs index 725864b462694..32f8d85ca795b 100644 --- a/primitives/runtime/src/bounded/bounded_btree_map.rs +++ b/primitives/core/src/bounded/bounded_btree_map.rs @@ -17,7 +17,7 @@ //! Traits, types and structs to support a bounded BTreeMap. -use crate::traits::{Get, TryCollect}; +use crate::{Get, TryCollect}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_std::{borrow::Borrow, collections::btree_map::BTreeMap, marker::PhantomData, ops::Deref}; @@ -363,7 +363,7 @@ where #[cfg(test)] pub mod test { use super::*; - use crate::traits::ConstU32; + use crate::ConstU32; fn map_from_keys(keys: &[K]) -> BTreeMap where diff --git a/primitives/runtime/src/bounded/bounded_btree_set.rs b/primitives/core/src/bounded/bounded_btree_set.rs similarity index 99% rename from primitives/runtime/src/bounded/bounded_btree_set.rs rename to primitives/core/src/bounded/bounded_btree_set.rs index c19d176f11bef..5feac6b7150f0 100644 --- a/primitives/runtime/src/bounded/bounded_btree_set.rs +++ b/primitives/core/src/bounded/bounded_btree_set.rs @@ -17,7 +17,7 @@ //! Traits, types and structs to support a bounded `BTreeSet`. -use crate::traits::{Get, TryCollect}; +use crate::{Get, TryCollect}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_std::{borrow::Borrow, collections::btree_set::BTreeSet, marker::PhantomData, ops::Deref}; @@ -321,7 +321,7 @@ where #[cfg(test)] pub mod test { use super::*; - use crate::traits::ConstU32; + use crate::ConstU32; fn set_from_keys(keys: &[T]) -> BTreeSet where diff --git a/primitives/runtime/src/bounded/bounded_vec.rs b/primitives/core/src/bounded/bounded_vec.rs similarity index 99% rename from primitives/runtime/src/bounded/bounded_vec.rs rename to primitives/core/src/bounded/bounded_vec.rs index aed1a156ad699..85f2bed316793 100644 --- a/primitives/runtime/src/bounded/bounded_vec.rs +++ b/primitives/core/src/bounded/bounded_vec.rs @@ -19,7 +19,7 @@ //! or a double map. use super::WeakBoundedVec; -use crate::traits::{Get, TryCollect}; +use crate::{Get, TryCollect}; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use core::{ ops::{Deref, Index, IndexMut, RangeBounds}, @@ -884,7 +884,7 @@ where #[cfg(test)] pub mod test { use super::*; - use crate::{bounded_vec, traits::ConstU32}; + use crate::{bounded_vec, ConstU32}; #[test] fn slide_works() { diff --git a/primitives/runtime/src/bounded/weak_bounded_vec.rs b/primitives/core/src/bounded/weak_bounded_vec.rs similarity index 99% rename from primitives/runtime/src/bounded/weak_bounded_vec.rs rename to primitives/core/src/bounded/weak_bounded_vec.rs index a447e7285f906..5aff35f010c8b 100644 --- a/primitives/runtime/src/bounded/weak_bounded_vec.rs +++ b/primitives/core/src/bounded/weak_bounded_vec.rs @@ -19,7 +19,7 @@ //! or a double map. use super::{BoundedSlice, BoundedVec}; -use crate::traits::Get; +use crate::Get; use codec::{Decode, Encode, MaxEncodedLen}; use core::{ ops::{Deref, Index, IndexMut}, @@ -453,7 +453,7 @@ where #[cfg(test)] pub mod test { use super::*; - use crate::traits::ConstU32; + use crate::ConstU32; #[test] fn bound_returns_correct_value() { diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index f48adc274f524..fadbdada1f004 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -53,6 +53,7 @@ pub mod hashing; #[cfg(feature = "full_crypto")] pub use hashing::{blake2_128, blake2_256, keccak_256, twox_128, twox_256, twox_64}; +pub mod bounded; pub mod crypto; pub mod hexdisplay; @@ -466,3 +467,239 @@ macro_rules! impl_maybe_marker { // The maximum possible allocation size was chosen rather arbitrary, 32 MiB should be enough for // everybody. pub const MAX_POSSIBLE_ALLOCATION: u32 = 33554432; // 2^25 bytes, 32 MiB + +/// A trait for querying a single value from a type defined in the trait. +/// +/// It is not required that the value is constant. +pub trait TypedGet { + /// The type which is returned. + type Type; + /// Return the current value. + fn get() -> Self::Type; +} + +/// A trait for querying a single value from a type. +/// +/// It is not required that the value is constant. +pub trait Get { + /// Return the current value. + fn get() -> T; +} + +impl Get for () { + fn get() -> T { + T::default() + } +} + +/// Implement Get by returning Default for any type that implements Default. +pub struct GetDefault; +impl Get for GetDefault { + fn get() -> T { + T::default() + } +} + +macro_rules! impl_const_get { + ($name:ident, $t:ty) => { + #[doc = "Const getter for a basic type."] + #[derive($crate::RuntimeDebug)] + pub struct $name; + impl Get<$t> for $name { + fn get() -> $t { + T + } + } + impl Get> for $name { + fn get() -> Option<$t> { + Some(T) + } + } + impl TypedGet for $name { + type Type = $t; + fn get() -> $t { + T + } + } + }; +} + +impl_const_get!(ConstBool, bool); +impl_const_get!(ConstU8, u8); +impl_const_get!(ConstU16, u16); +impl_const_get!(ConstU32, u32); +impl_const_get!(ConstU64, u64); +impl_const_get!(ConstU128, u128); +impl_const_get!(ConstI8, i8); +impl_const_get!(ConstI16, i16); +impl_const_get!(ConstI32, i32); +impl_const_get!(ConstI64, i64); +impl_const_get!(ConstI128, i128); + +/// Try and collect into a collection `C`. +pub trait TryCollect { + /// The error type that gets returned when a collection can't be made from `self`. + type Error; + /// Consume self and try to collect the results into `C`. + /// + /// This is useful in preventing the undesirable `.collect().try_into()` call chain on + /// collections that need to be converted into a bounded type (e.g. `BoundedVec`). + fn try_collect(self) -> Result; +} + +/// Create new implementations of the [`Get`](crate::Get) trait. +/// +/// The so-called parameter type can be created in four different ways: +/// +/// - Using `const` to create a parameter type that provides a `const` getter. It is required that +/// the `value` is const. +/// +/// - Declare the parameter type without `const` to have more freedom when creating the value. +/// +/// NOTE: A more substantial version of this macro is available in `frame_support` crate which +/// allows mutable and persistant variants. +/// +/// # Examples +/// +/// ``` +/// # use sp_core::Get; +/// # use sp_core::parameter_types; +/// // This function cannot be used in a const context. +/// fn non_const_expression() -> u64 { 99 } +/// +/// const FIXED_VALUE: u64 = 10; +/// parameter_types! { +/// pub const Argument: u64 = 42 + FIXED_VALUE; +/// /// Visibility of the type is optional +/// OtherArgument: u64 = non_const_expression(); +/// } +/// +/// trait Config { +/// type Parameter: Get; +/// type OtherParameter: Get; +/// } +/// +/// struct Runtime; +/// impl Config for Runtime { +/// type Parameter = Argument; +/// type OtherParameter = OtherArgument; +/// } +/// ``` +/// +/// # Invalid example: +/// +/// ```compile_fail +/// # use sp_core::Get; +/// # use sp_core::parameter_types; +/// // This function cannot be used in a const context. +/// fn non_const_expression() -> u64 { 99 } +/// +/// parameter_types! { +/// pub const Argument: u64 = non_const_expression(); +/// } +/// ``` +#[macro_export] +macro_rules! parameter_types { + ( + $( #[ $attr:meta ] )* + $vis:vis const $name:ident: $type:ty = $value:expr; + $( $rest:tt )* + ) => ( + $( #[ $attr ] )* + $vis struct $name; + $crate::parameter_types!(@IMPL_CONST $name , $type , $value); + $crate::parameter_types!( $( $rest )* ); + ); + ( + $( #[ $attr:meta ] )* + $vis:vis $name:ident: $type:ty = $value:expr; + $( $rest:tt )* + ) => ( + $( #[ $attr ] )* + $vis struct $name; + $crate::parameter_types!(@IMPL $name, $type, $value); + $crate::parameter_types!( $( $rest )* ); + ); + () => (); + (@IMPL_CONST $name:ident, $type:ty, $value:expr) => { + impl $name { + /// Returns the value of this parameter type. + pub const fn get() -> $type { + $value + } + } + + impl> $crate::Get for $name { + fn get() -> I { + I::from(Self::get()) + } + } + + impl $crate::TypedGet for $name { + type Type = $type; + fn get() -> $type { + Self::get() + } + } + }; + (@IMPL $name:ident, $type:ty, $value:expr) => { + impl $name { + /// Returns the value of this parameter type. + pub fn get() -> $type { + $value + } + } + + impl> $crate::Get for $name { + fn get() -> I { + I::from(Self::get()) + } + } + + impl $crate::TypedGet for $name { + type Type = $type; + fn get() -> $type { + Self::get() + } + } + }; +} + +/// Build a bounded vec from the given literals. +/// +/// The type of the outcome must be known. +/// +/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding +/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. +#[macro_export] +#[cfg(feature = "std")] +macro_rules! bounded_vec { + ($ ($values:expr),* $(,)?) => { + { + $crate::sp_std::vec![$($values),*].try_into().unwrap() + } + }; + ( $value:expr ; $repetition:expr ) => { + { + $crate::sp_std::vec![$value ; $repetition].try_into().unwrap() + } + } +} + +/// Build a bounded btree-map from the given literals. +/// +/// The type of the outcome must be known. +/// +/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding +/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. +#[macro_export] +#[cfg(feature = "std")] +macro_rules! bounded_btree_map { + ($ ( $key:expr => $value:expr ),* $(,)?) => { + { + $crate::TryCollect::<$crate::bounded::BoundedBTreeMap<_, _, _>>::try_collect( + $crate::sp_std::vec![$(($key, $value)),*].into_iter() + ).unwrap() + } + }; +} diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 811ca33dbfa25..7006a13e415e4 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -55,7 +55,6 @@ use sp_std::prelude::*; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -pub mod bounded; pub mod curve; pub mod generic; pub mod legacy; @@ -70,9 +69,6 @@ pub mod transaction_validity; pub use crate::runtime_string::*; -// Re-export bounded types -pub use bounded::{BoundedBTreeMap, BoundedBTreeSet, BoundedSlice, BoundedVec, WeakBoundedVec}; - // Re-export Multiaddress pub use multiaddress::MultiAddress; @@ -82,9 +78,13 @@ pub use generic::{Digest, DigestItem}; pub use sp_application_crypto::{BoundToRuntimeAppPublic, RuntimeAppPublic}; /// Re-export this since it's part of the API of this crate. pub use sp_core::{ + bounded::{BoundedBTreeMap, BoundedBTreeSet, BoundedSlice, BoundedVec, WeakBoundedVec}, crypto::{key_types, AccountId32, CryptoType, CryptoTypeId, KeyTypeId}, TypeId, }; +/// Re-export bounded_vec and bounded_btree_map macros only when std is enabled. +#[cfg(feature = "std")] +pub use sp_core::{bounded_btree_map, bounded_vec}; /// Re-export `RuntimeDebug`, to avoid dependency clutter. pub use sp_core::RuntimeDebug; @@ -834,45 +834,6 @@ macro_rules! assert_eq_error_rate { }; } -/// Build a bounded vec from the given literals. -/// -/// The type of the outcome must be known. -/// -/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding -/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. -#[macro_export] -#[cfg(feature = "std")] -macro_rules! bounded_vec { - ($ ($values:expr),* $(,)?) => { - { - $crate::sp_std::vec![$($values),*].try_into().unwrap() - } - }; - ( $value:expr ; $repetition:expr ) => { - { - $crate::sp_std::vec![$value ; $repetition].try_into().unwrap() - } - } -} - -/// Build a bounded btree-map from the given literals. -/// -/// The type of the outcome must be known. -/// -/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding -/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. -#[macro_export] -#[cfg(feature = "std")] -macro_rules! bounded_btree_map { - ($ ( $key:expr => $value:expr ),* $(,)?) => { - { - $crate::traits::TryCollect::<$crate::BoundedBTreeMap<_, _, _>>::try_collect( - $crate::sp_std::vec![$(($key, $value)),*].into_iter() - ).unwrap() - } - }; -} - /// Simple blob to hold an extrinsic without committing to its format and ensure it is serialized /// correctly. #[derive(PartialEq, Eq, Clone, Default, Encode, Decode, TypeInfo)] diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index a82ae1d62f56a..2cf98b4e638d3 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -38,6 +38,11 @@ pub use sp_arithmetic::traits::{ }; use sp_core::{self, storage::StateVersion, Hasher, RuntimeDebug, TypeId}; #[doc(hidden)] +pub use sp_core::{ + parameter_types, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, + ConstU16, ConstU32, ConstU64, ConstU8, Get, GetDefault, TryCollect, TypedGet, +}; +#[doc(hidden)] pub use sp_std::marker::PhantomData; use sp_std::{self, fmt::Debug, prelude::*}; #[cfg(feature = "std")] @@ -276,203 +281,6 @@ where } } -/// A trait for querying a single value from a type defined in the trait. -/// -/// It is not required that the value is constant. -pub trait TypedGet { - /// The type which is returned. - type Type; - /// Return the current value. - fn get() -> Self::Type; -} - -/// A trait for querying a single value from a type. -/// -/// It is not required that the value is constant. -pub trait Get { - /// Return the current value. - fn get() -> T; -} - -impl Get for () { - fn get() -> T { - T::default() - } -} - -/// Implement Get by returning Default for any type that implements Default. -pub struct GetDefault; -impl Get for GetDefault { - fn get() -> T { - T::default() - } -} - -/// Try and collect into a collection `C`. -pub trait TryCollect { - /// The error type that gets returned when a collection can't be made from `self`. - type Error; - /// Consume self and try to collect the results into `C`. - /// - /// This is useful in preventing the undesirable `.collect().try_into()` call chain on - /// collections that need to be converted into a bounded type (e.g. `BoundedVec`). - fn try_collect(self) -> Result; -} - -macro_rules! impl_const_get { - ($name:ident, $t:ty) => { - #[doc = "Const getter for a basic type."] - #[derive($crate::RuntimeDebug)] - pub struct $name; - impl Get<$t> for $name { - fn get() -> $t { - T - } - } - impl Get> for $name { - fn get() -> Option<$t> { - Some(T) - } - } - impl TypedGet for $name { - type Type = $t; - fn get() -> $t { - T - } - } - }; -} - -impl_const_get!(ConstBool, bool); -impl_const_get!(ConstU8, u8); -impl_const_get!(ConstU16, u16); -impl_const_get!(ConstU32, u32); -impl_const_get!(ConstU64, u64); -impl_const_get!(ConstU128, u128); -impl_const_get!(ConstI8, i8); -impl_const_get!(ConstI16, i16); -impl_const_get!(ConstI32, i32); -impl_const_get!(ConstI64, i64); -impl_const_get!(ConstI128, i128); - -/// Create new implementations of the [`Get`](crate::traits::Get) trait. -/// -/// The so-called parameter type can be created in four different ways: -/// -/// - Using `const` to create a parameter type that provides a `const` getter. It is required that -/// the `value` is const. -/// -/// - Declare the parameter type without `const` to have more freedom when creating the value. -/// -/// NOTE: A more substantial version of this macro is available in `frame_support` crate which -/// allows mutable and persistant variants. -/// -/// # Examples -/// -/// ``` -/// # use sp_runtime::traits::Get; -/// # use sp_runtime::parameter_types; -/// // This function cannot be used in a const context. -/// fn non_const_expression() -> u64 { 99 } -/// -/// const FIXED_VALUE: u64 = 10; -/// parameter_types! { -/// pub const Argument: u64 = 42 + FIXED_VALUE; -/// /// Visibility of the type is optional -/// OtherArgument: u64 = non_const_expression(); -/// } -/// -/// trait Config { -/// type Parameter: Get; -/// type OtherParameter: Get; -/// } -/// -/// struct Runtime; -/// impl Config for Runtime { -/// type Parameter = Argument; -/// type OtherParameter = OtherArgument; -/// } -/// ``` -/// -/// # Invalid example: -/// -/// ```compile_fail -/// # use sp_runtime::traits::Get; -/// # use sp_runtime::parameter_types; -/// // This function cannot be used in a const context. -/// fn non_const_expression() -> u64 { 99 } -/// -/// parameter_types! { -/// pub const Argument: u64 = non_const_expression(); -/// } -/// ``` -#[macro_export] -macro_rules! parameter_types { - ( - $( #[ $attr:meta ] )* - $vis:vis const $name:ident: $type:ty = $value:expr; - $( $rest:tt )* - ) => ( - $( #[ $attr ] )* - $vis struct $name; - $crate::parameter_types!(@IMPL_CONST $name , $type , $value); - $crate::parameter_types!( $( $rest )* ); - ); - ( - $( #[ $attr:meta ] )* - $vis:vis $name:ident: $type:ty = $value:expr; - $( $rest:tt )* - ) => ( - $( #[ $attr ] )* - $vis struct $name; - $crate::parameter_types!(@IMPL $name, $type, $value); - $crate::parameter_types!( $( $rest )* ); - ); - () => (); - (@IMPL_CONST $name:ident, $type:ty, $value:expr) => { - impl $name { - /// Returns the value of this parameter type. - pub const fn get() -> $type { - $value - } - } - - impl> $crate::traits::Get for $name { - fn get() -> I { - I::from(Self::get()) - } - } - - impl $crate::traits::TypedGet for $name { - type Type = $type; - fn get() -> $type { - Self::get() - } - } - }; - (@IMPL $name:ident, $type:ty, $value:expr) => { - impl $name { - /// Returns the value of this parameter type. - pub fn get() -> $type { - $value - } - } - - impl> $crate::traits::Get for $name { - fn get() -> I { - I::from(Self::get()) - } - } - - impl $crate::traits::TypedGet for $name { - type Type = $type; - fn get() -> $type { - Self::get() - } - } - }; -} - /// Extensible conversion trait. Generic over only source type, with destination type being /// associated. pub trait Morph { From c0e1cdbff91bc0e1db54a2c369e2e1fc5fb17c2f Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 7 Sep 2022 23:16:54 +0200 Subject: [PATCH 1134/1472] Add `--header` to `benchmark overhead + storage` (#12204) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add header to 'overhead' command Signed-off-by: Oliver Tale-Yazdi * Add header to 'storage' command Signed-off-by: Oliver Tale-Yazdi * Update READMEs Signed-off-by: Oliver Tale-Yazdi * Apply suggestions from code review Co-authored-by: Bastian Köcher * .as_ref() and fmt Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher --- .../benchmarking-cli/src/overhead/README.md | 1 + .../frame/benchmarking-cli/src/overhead/cmd.rs | 8 +++++++- .../benchmarking-cli/src/overhead/template.rs | 9 +++++++++ .../benchmarking-cli/src/overhead/weights.hbs | 18 +----------------- .../benchmarking-cli/src/shared/README.md | 1 + .../benchmarking-cli/src/storage/README.md | 1 + .../frame/benchmarking-cli/src/storage/cmd.rs | 8 +++++++- .../benchmarking-cli/src/storage/template.rs | 16 +++++++++++++--- .../benchmarking-cli/src/storage/weights.hbs | 18 +----------------- 9 files changed, 41 insertions(+), 39 deletions(-) diff --git a/utils/frame/benchmarking-cli/src/overhead/README.md b/utils/frame/benchmarking-cli/src/overhead/README.md index 9d723c3424f7b..b21d051e9d44c 100644 --- a/utils/frame/benchmarking-cli/src/overhead/README.md +++ b/utils/frame/benchmarking-cli/src/overhead/README.md @@ -126,6 +126,7 @@ Minimizing this is important to have a large transaction throughput. - [`--add`](../shared/README.md#arguments) - [`--metric`](../shared/README.md#arguments) - [`--weight-path`](../shared/README.md#arguments) +- [`--header`](../shared/README.md#arguments) License: Apache-2.0 diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 4d0e2e52df17d..1c6753b4a20ea 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -28,7 +28,7 @@ use sp_runtime::{traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; use clap::{Args, Parser}; use log::info; use serde::Serialize; -use std::{fmt::Debug, sync::Arc}; +use std::{fmt::Debug, path::PathBuf, sync::Arc}; use crate::{ extrinsic::{ @@ -69,6 +69,12 @@ pub struct OverheadParams { #[allow(missing_docs)] #[clap(flatten)] pub hostinfo: HostInfoParams, + + /// Add a header to the generated weight output file. + /// + /// Good for adding LICENSE headers. + #[clap(long, value_name = "PATH")] + pub header: Option, } /// Type of a benchmark. diff --git a/utils/frame/benchmarking-cli/src/overhead/template.rs b/utils/frame/benchmarking-cli/src/overhead/template.rs index aa82e45cf6db9..ceed34d1981f9 100644 --- a/utils/frame/benchmarking-cli/src/overhead/template.rs +++ b/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -51,6 +51,8 @@ pub(crate) struct TemplateData { hostname: String, /// CPU name of the machine that executed the benchmarks. cpuname: String, + /// Header for the generated file. + header: String, /// Command line arguments that were passed to the CLI. args: Vec, /// Params of the executed command. @@ -70,6 +72,12 @@ impl TemplateData { stats: &Stats, ) -> Result { let weight = params.weight.calc_weight(stats)?; + let header = params + .header + .as_ref() + .map(|p| std::fs::read_to_string(p)) + .transpose()? + .unwrap_or_default(); Ok(TemplateData { short_name: t.short_name().into(), @@ -79,6 +87,7 @@ impl TemplateData { date: chrono::Utc::now().format("%Y-%m-%d (Y/M/D)").to_string(), hostname: params.hostinfo.hostname(), cpuname: params.hostinfo.cpuname(), + header, args: env::args().collect::>(), params: params.clone(), stats: stats.clone(), diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index bddaa642a5a29..5feac07b3a7d8 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -1,20 +1,4 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +{{header}} //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} //! DATE: {{date}} //! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` diff --git a/utils/frame/benchmarking-cli/src/shared/README.md b/utils/frame/benchmarking-cli/src/shared/README.md index 2a3719b85498c..08e25b0e08f76 100644 --- a/utils/frame/benchmarking-cli/src/shared/README.md +++ b/utils/frame/benchmarking-cli/src/shared/README.md @@ -11,5 +11,6 @@ Contains code that is shared among multiple sub-commands. - `--db` The database backend to use. This depends on your snapshot. - `--pruning` Set the pruning mode of the node. Some benchmarks require you to set this to `archive`. - `--base-path` The location on the disk that should be used for the benchmarks. You can try this on different disks or even on a mounted RAM-disk. It is important to use the same location that will later-on be used to store the chain data to get the correct results. +- `--header` Optional file header which will be prepended to the weight output file. Can be used for adding LICENSE headers. License: Apache-2.0 diff --git a/utils/frame/benchmarking-cli/src/storage/README.md b/utils/frame/benchmarking-cli/src/storage/README.md index 820785f7ea20c..ecaf4edadab38 100644 --- a/utils/frame/benchmarking-cli/src/storage/README.md +++ b/utils/frame/benchmarking-cli/src/storage/README.md @@ -97,6 +97,7 @@ write: 71_347 * constants::WEIGHT_PER_NANOS, - [`--weight-path`](../shared/README.md#arguments) - `--json-read-path` Write the raw 'read' results to this file or directory. - `--json-write-path` Write the raw 'write' results to this file or directory. +- [`--header`](../shared/README.md#arguments) License: Apache-2.0 diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index de5e189b40db0..d28ac4102152f 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -79,6 +79,12 @@ pub struct StorageParams { #[clap(long)] pub template_path: Option, + /// Add a header to the generated weight output file. + /// + /// Good for adding LICENSE headers. + #[clap(long, value_name = "PATH")] + pub header: Option, + /// Path to write the raw 'read' results in JSON format to. Can be a file or directory. #[clap(long)] pub json_read_path: Option, @@ -122,7 +128,7 @@ impl StorageCmd { Block: BlockT, C: UsageProvider + StorageProvider + HeaderBackend, { - let mut template = TemplateData::new(&cfg, &self.params); + let mut template = TemplateData::new(&cfg, &self.params)?; let block_id = BlockId::::Number(client.usage_info().chain.best_number); template.set_block_number(block_id.to_string()); diff --git a/utils/frame/benchmarking-cli/src/storage/template.rs b/utils/frame/benchmarking-cli/src/storage/template.rs index 20fbd58134f20..ebc415ccb8189 100644 --- a/utils/frame/benchmarking-cli/src/storage/template.rs +++ b/utils/frame/benchmarking-cli/src/storage/template.rs @@ -45,6 +45,8 @@ pub(crate) struct TemplateData { hostname: String, /// CPU name of the machine that executed the benchmarks. cpuname: String, + /// Header for the generated file. + header: String, /// Command line arguments that were passed to the CLI. args: Vec, /// Storage params of the executed command. @@ -63,18 +65,26 @@ pub(crate) struct TemplateData { impl TemplateData { /// Returns a new [`Self`] from the given configuration. - pub fn new(cfg: &Configuration, params: &StorageParams) -> Self { - TemplateData { + pub fn new(cfg: &Configuration, params: &StorageParams) -> Result { + let header = params + .header + .as_ref() + .map(|p| std::fs::read_to_string(p)) + .transpose()? + .unwrap_or_default(); + + Ok(TemplateData { db_name: format!("{}", cfg.database), runtime_name: cfg.chain_spec.name().into(), version: VERSION.into(), date: chrono::Utc::now().format("%Y-%m-%d (Y/M/D)").to_string(), hostname: params.hostinfo.hostname(), cpuname: params.hostinfo.cpuname(), + header, args: env::args().collect::>(), params: params.clone(), ..Default::default() - } + }) } /// Sets the stats and calculates the final weights. diff --git a/utils/frame/benchmarking-cli/src/storage/weights.hbs b/utils/frame/benchmarking-cli/src/storage/weights.hbs index 8c19aaa0dff36..3aa4703e29eb2 100644 --- a/utils/frame/benchmarking-cli/src/storage/weights.hbs +++ b/utils/frame/benchmarking-cli/src/storage/weights.hbs @@ -1,20 +1,4 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +{{header}} //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} //! DATE: {{date}} //! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` From 26193945883c773f2f14f976da3c3bd11dc0eb79 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 8 Sep 2022 12:22:41 +0800 Subject: [PATCH 1135/1472] Remove Ord impl for Weights V2 and add comparison fns (#12183) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove Ord impl for Weights V2 and add comparison fns * Remove TODO * Update frame/multisig/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/election-provider-multi-phase/src/unsigned.rs Co-authored-by: Oliver Tale-Yazdi * Remove unused import * cargo fmt * Fix tests * Fix more tests * cargo fmt * Fix more tests * Update frame/contracts/src/wasm/mod.rs Co-authored-by: Alexander Theißen * Update weight benchmarking templates Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Alexander Theißen --- frame/babe/src/tests.rs | 4 +- frame/collective/src/lib.rs | 2 +- frame/contracts/src/gas.rs | 2 +- frame/contracts/src/wasm/mod.rs | 6 +- .../election-provider-multi-phase/src/lib.rs | 6 +- .../src/unsigned.rs | 29 +++++----- frame/examples/basic/src/tests.rs | 4 +- frame/executive/src/lib.rs | 2 +- frame/grandpa/src/tests.rs | 4 +- frame/multisig/src/lib.rs | 5 +- frame/scheduler/src/lib.rs | 2 +- frame/staking/src/pallet/mod.rs | 10 ++-- frame/staking/src/tests.rs | 16 ++--- frame/support/src/weights/block_weights.rs | 10 +++- .../support/src/weights/extrinsic_weights.rs | 10 +++- frame/support/src/weights/paritydb_weights.rs | 8 +-- frame/support/src/weights/rocksdb_weights.rs | 8 +-- frame/support/src/weights/weight_v2.rs | 58 ++++++++++++++++++- frame/system/src/extensions/check_weight.rs | 16 ++--- frame/system/src/limits.rs | 18 +++--- frame/whitelist/src/lib.rs | 2 +- .../benchmarking-cli/src/overhead/weights.hbs | 8 +-- .../benchmarking-cli/src/storage/weights.hbs | 8 +-- 23 files changed, 156 insertions(+), 82 deletions(-) diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 2f967b658e396..065105eda1c32 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -823,7 +823,7 @@ fn report_equivocation_has_valid_weight() { .map(::WeightInfo::report_equivocation) .collect::>() .windows(2) - .all(|w| w[0] < w[1])); + .all(|w| w[0].ref_time() < w[1].ref_time())); } #[test] @@ -852,7 +852,7 @@ fn valid_equivocation_reports_dont_pay_fees() { .get_dispatch_info(); // it should have non-zero weight and the fee has to be paid. - assert!(info.weight > Weight::zero()); + assert!(info.weight.all_gt(Weight::zero())); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 0323be1382392..02faf876806e1 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -881,7 +881,7 @@ impl, I: 'static> Pallet { ensure!(proposal_len <= length_bound, Error::::WrongProposalLength); let proposal = ProposalOf::::get(hash).ok_or(Error::::ProposalMissing)?; let proposal_weight = proposal.get_dispatch_info().weight; - ensure!(proposal_weight <= weight_bound, Error::::WrongProposalWeight); + ensure!(proposal_weight.all_lte(weight_bound), Error::::WrongProposalWeight); Ok((proposal, proposal_len as usize)) } diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index ae20e4eeb0def..215b4d42daa06 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -111,7 +111,7 @@ where // NOTE that it is ok to allocate all available gas since it still ensured // by `charge` that it doesn't reach zero. - if self.gas_left < amount { + if self.gas_left.any_lt(amount) { Err(>::OutOfGas.into()) } else { self.gas_left -= amount; diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 6790830b97e02..3718be756e39d 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -1555,8 +1555,8 @@ mod tests { let gas_left = Weight::decode(&mut &*output.data).unwrap(); let actual_left = ext.gas_meter.gas_left(); - assert!(gas_left < gas_limit, "gas_left must be less than initial"); - assert!(gas_left > actual_left, "gas_left must be greater than final"); + assert!(gas_left.all_lt(gas_limit), "gas_left must be less than initial"); + assert!(gas_left.all_gt(actual_left), "gas_left must be greater than final"); } const CODE_VALUE_TRANSFERRED: &str = r#" @@ -1953,7 +1953,7 @@ mod tests { )] ); - assert!(mock_ext.gas_meter.gas_left() > Weight::zero()); + assert!(mock_ext.gas_meter.gas_left().all_gt(Weight::zero())); } const CODE_DEPOSIT_EVENT_MAX_TOPICS: &str = r#" diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 84949080aa58c..bfe5cb2e96728 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -985,7 +985,7 @@ pub mod pallet { let size = Self::snapshot_metadata().ok_or(Error::::MissingSnapshotMetadata)?; ensure!( - Self::solution_weight_of(&raw_solution, size) < T::SignedMaxWeight::get(), + Self::solution_weight_of(&raw_solution, size).all_lt(T::SignedMaxWeight::get()), Error::::SignedTooMuchWeight, ); @@ -2299,8 +2299,8 @@ mod tests { }; let mut active = 1; - while weight_with(active) <= - ::BlockWeights::get().max_block || + while weight_with(active) + .all_lte(::BlockWeights::get().max_block) || active == all_voters { active += 1; diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 8ef7d87473159..e99f2e9cef028 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -34,7 +34,7 @@ use sp_runtime::{ offchain::storage::{MutateStorageError, StorageValueRef}, DispatchError, SaturatedConversion, }; -use sp_std::{cmp::Ordering, prelude::*}; +use sp_std::prelude::*; /// Storage key used to store the last block number at which offchain worker ran. pub(crate) const OFFCHAIN_LAST_BLOCK: &[u8] = b"parity/multi-phase-unsigned-election"; @@ -638,16 +638,17 @@ impl Miner { }; let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result { - match current_weight.cmp(&max_weight) { - Ordering::Less => { - let next_voters = voters.checked_add(step); - match next_voters { - Some(voters) if voters < max_voters => Ok(voters), - _ => Err(()), - } - }, - Ordering::Greater => voters.checked_sub(step).ok_or(()), - Ordering::Equal => Ok(voters), + if current_weight.all_lt(max_weight) { + let next_voters = voters.checked_add(step); + match next_voters { + Some(voters) if voters < max_voters => Ok(voters), + _ => Err(()), + } + } else if current_weight.any_gt(max_weight) { + voters.checked_sub(step).ok_or(()) + } else { + // If any of the constituent weights is equal to the max weight, we're at max + Ok(voters) } }; @@ -672,16 +673,16 @@ impl Miner { // Time to finish. We might have reduced less than expected due to rounding error. Increase // one last time if we have any room left, the reduce until we are sure we are below limit. - while voters < max_voters && weight_with(voters + 1) < max_weight { + while voters < max_voters && weight_with(voters + 1).all_lt(max_weight) { voters += 1; } - while voters.checked_sub(1).is_some() && weight_with(voters) > max_weight { + while voters.checked_sub(1).is_some() && weight_with(voters).any_gt(max_weight) { voters -= 1; } let final_decision = voters.min(size.voters); debug_assert!( - weight_with(final_decision) <= max_weight, + weight_with(final_decision).all_lte(max_weight), "weight_with({}) <= {}", final_decision, max_weight, diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index f6afb7a0c77f1..567117e621921 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -190,11 +190,11 @@ fn weights_work() { let default_call = pallet_example_basic::Call::::accumulate_dummy { increase_by: 10 }; let info1 = default_call.get_dispatch_info(); // aka. `let info = as GetDispatchInfo>::get_dispatch_info(&default_call);` - assert!(info1.weight > Weight::zero()); + assert!(info1.weight.all_gt(Weight::zero())); // `set_dummy` is simpler than `accumulate_dummy`, and the weight // should be less. let custom_call = pallet_example_basic::Call::::set_dummy { new_value: 20 }; let info2 = custom_call.get_dispatch_info(); - assert!(info1.weight > info2.weight); + assert!(info1.weight.all_gt(info2.weight)); } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 5d3954ded0998..87ed8b93bbf8e 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -462,7 +462,7 @@ where let max_weight = >::get().max_block; let remaining_weight = max_weight.saturating_sub(weight.total()); - if remaining_weight > Weight::zero() { + if remaining_weight.all_gt(Weight::zero()) { let used_weight = >::on_idle( block_number, remaining_weight, diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 9c39069bf9538..07c4fcad3078d 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -823,7 +823,7 @@ fn report_equivocation_has_valid_weight() { .map(::WeightInfo::report_equivocation) .collect::>() .windows(2) - .all(|w| w[0] < w[1])); + .all(|w| w[0].ref_time() < w[1].ref_time())); } #[test] @@ -856,7 +856,7 @@ fn valid_equivocation_reports_dont_pay_fees() { .get_dispatch_info(); // it should have non-zero weight and the fee has to be paid. - assert!(info.weight > Weight::zero()); + assert!(info.weight.all_gt(Weight::zero())); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 10184ce84a9a8..01904de9a96fa 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -563,7 +563,10 @@ impl Pallet { if let Some((call, call_len)) = maybe_approved_call { // verify weight - ensure!(call.get_dispatch_info().weight <= max_weight, Error::::MaxWeightTooLow); + ensure!( + call.get_dispatch_info().weight.all_lte(max_weight), + Error::::MaxWeightTooLow + ); // Clean up storage before executing call to avoid an possibility of reentrancy // attack. diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index a005c051a1abc..7746b7d0123f4 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -368,7 +368,7 @@ pub mod pallet { let hard_deadline = s.priority <= schedule::HARD_DEADLINE; let test_weight = total_weight.saturating_add(call_weight).saturating_add(item_weight); - if !hard_deadline && order > 0 && test_weight > limit { + if !hard_deadline && order > 0 && test_weight.any_gt(limit) { // Cannot be scheduled this block - postpone until next. total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); if let Some(ref id) = s.maybe_id { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 74374cc586a23..f651cc06b1cb0 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -33,7 +33,7 @@ use sp_runtime::{ Perbill, Percent, }; use sp_staking::{EraIndex, SessionIndex}; -use sp_std::{cmp::max, prelude::*}; +use sp_std::prelude::*; mod impls; @@ -1571,10 +1571,10 @@ pub mod pallet { /// to kick people under the new limits, `chill_other` should be called. // We assume the worst case for this call is either: all items are set or all items are // removed. - #[pallet::weight(max( - T::WeightInfo::set_staking_configs_all_set(), - T::WeightInfo::set_staking_configs_all_remove() - ))] + #[pallet::weight( + T::WeightInfo::set_staking_configs_all_set() + .max(T::WeightInfo::set_staking_configs_all_remove()) + )] pub fn set_staking_configs( origin: OriginFor, min_nominator_bond: ConfigOp>, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 0d00f5a5e61df..448fbd2382454 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3759,9 +3759,9 @@ fn payout_stakers_handles_weight_refund() { let half_max_nom_rewarded_weight = ::WeightInfo::payout_stakers_alive_staked(half_max_nom_rewarded); let zero_nom_payouts_weight = ::WeightInfo::payout_stakers_alive_staked(0); - assert!(zero_nom_payouts_weight > Weight::zero()); - assert!(half_max_nom_rewarded_weight > zero_nom_payouts_weight); - assert!(max_nom_rewarded_weight > half_max_nom_rewarded_weight); + assert!(zero_nom_payouts_weight.any_gt(Weight::zero())); + assert!(half_max_nom_rewarded_weight.any_gt(zero_nom_payouts_weight)); + assert!(max_nom_rewarded_weight.any_gt(half_max_nom_rewarded_weight)); let balance = 1000; bond_validator(11, 10, balance); @@ -4238,7 +4238,7 @@ fn do_not_die_when_active_is_ed() { fn on_finalize_weight_is_nonzero() { ExtBuilder::default().build_and_execute(|| { let on_finalize_weight = ::DbWeight::get().reads(1); - assert!(>::on_initialize(1) >= on_finalize_weight); + assert!(>::on_initialize(1).all_gte(on_finalize_weight)); }) } @@ -4249,8 +4249,8 @@ mod election_data_provider { #[test] fn targets_2sec_block() { let mut validators = 1000; - while ::WeightInfo::get_npos_targets(validators) < - 2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND + while ::WeightInfo::get_npos_targets(validators) + .all_lt(2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND) { validators += 1; } @@ -4267,8 +4267,8 @@ mod election_data_provider { let slashing_spans = validators; let mut nominators = 1000; - while ::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) < - 2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND + while ::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) + .all_lt(2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND) { nominators += 1; } diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index 51f707b2b0df5..57978f60a4ecb 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -68,8 +68,14 @@ mod test_weights { let w = super::BlockExecutionWeight::get(); // At least 100 µs. - assert!(w >= 100u32 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); + assert!( + w.ref_time() >= 100u64 * constants::WEIGHT_PER_MICROS.ref_time(), + "Weight should be at least 100 µs." + ); // At most 50 ms. - assert!(w <= 50u32 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms."); + assert!( + w.ref_time() <= 50u64 * constants::WEIGHT_PER_MILLIS.ref_time(), + "Weight should be at most 50 ms." + ); } } diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 2bee1059b0dad..54f70a063cdec 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -68,8 +68,14 @@ mod test_weights { let w = super::ExtrinsicBaseWeight::get(); // At least 10 µs. - assert!(w >= 10u32 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs."); + assert!( + w.ref_time() >= 10u64 * constants::WEIGHT_PER_MICROS.ref_time(), + "Weight should be at least 10 µs." + ); // At most 1 ms. - assert!(w <= constants::WEIGHT_PER_MILLIS, "Weight should be at most 1 ms."); + assert!( + w.ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + "Weight should be at most 1 ms." + ); } } diff --git a/frame/support/src/weights/paritydb_weights.rs b/frame/support/src/weights/paritydb_weights.rs index f498991729d7a..9f6ba82dbbff6 100644 --- a/frame/support/src/weights/paritydb_weights.rs +++ b/frame/support/src/weights/paritydb_weights.rs @@ -42,20 +42,20 @@ pub mod constants { fn sane() { // At least 1 µs. assert!( - W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + W::get().reads(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Read weight should be at least 1 µs." ); assert!( - W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + W::get().writes(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Write weight should be at least 1 µs." ); // At most 1 ms. assert!( - W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + W::get().reads(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Read weight should be at most 1 ms." ); assert!( - W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + W::get().writes(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Write weight should be at most 1 ms." ); } diff --git a/frame/support/src/weights/rocksdb_weights.rs b/frame/support/src/weights/rocksdb_weights.rs index 67571c4723f94..cab983de0ad0a 100644 --- a/frame/support/src/weights/rocksdb_weights.rs +++ b/frame/support/src/weights/rocksdb_weights.rs @@ -42,20 +42,20 @@ pub mod constants { fn sane() { // At least 1 µs. assert!( - W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + W::get().reads(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Read weight should be at least 1 µs." ); assert!( - W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + W::get().writes(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Write weight should be at least 1 µs." ); // At most 1 ms. assert!( - W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + W::get().reads(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Read weight should be at most 1 ms." ); assert!( - W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + W::get().writes(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Write weight should be at most 1 ms." ); } diff --git a/frame/support/src/weights/weight_v2.rs b/frame/support/src/weights/weight_v2.rs index 4bfab36663394..2d50f07add596 100644 --- a/frame/support/src/weights/weight_v2.rs +++ b/frame/support/src/weights/weight_v2.rs @@ -35,8 +35,6 @@ use super::*; Clone, RuntimeDebug, Default, - Ord, - PartialOrd, CompactAs, )] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] @@ -163,6 +161,62 @@ impl Weight { pub const fn zero() -> Self { Self { ref_time: 0 } } + + /// Returns true if any of `self`'s constituent weights is strictly greater than that of the + /// `other`'s, otherwise returns false. + pub const fn any_gt(self, other: Self) -> bool { + self.ref_time > other.ref_time + } + + /// Returns true if all of `self`'s constituent weights is strictly greater than that of the + /// `other`'s, otherwise returns false. + pub const fn all_gt(self, other: Self) -> bool { + self.ref_time > other.ref_time + } + + /// Returns true if any of `self`'s constituent weights is strictly less than that of the + /// `other`'s, otherwise returns false. + pub const fn any_lt(self, other: Self) -> bool { + self.ref_time < other.ref_time + } + + /// Returns true if all of `self`'s constituent weights is strictly less than that of the + /// `other`'s, otherwise returns false. + pub const fn all_lt(self, other: Self) -> bool { + self.ref_time < other.ref_time + } + + /// Returns true if any of `self`'s constituent weights is greater than or equal to that of the + /// `other`'s, otherwise returns false. + pub const fn any_gte(self, other: Self) -> bool { + self.ref_time >= other.ref_time + } + + /// Returns true if all of `self`'s constituent weights is greater than or equal to that of the + /// `other`'s, otherwise returns false. + pub const fn all_gte(self, other: Self) -> bool { + self.ref_time >= other.ref_time + } + + /// Returns true if any of `self`'s constituent weights is less than or equal to that of the + /// `other`'s, otherwise returns false. + pub const fn any_lte(self, other: Self) -> bool { + self.ref_time <= other.ref_time + } + + /// Returns true if all of `self`'s constituent weights is less than or equal to that of the + /// `other`'s, otherwise returns false. + pub const fn all_lte(self, other: Self) -> bool { + self.ref_time <= other.ref_time + } + + /// Returns true if any of `self`'s constituent weights is equal to that of the `other`'s, + /// otherwise returns false. + pub const fn any_eq(self, other: Self) -> bool { + self.ref_time == other.ref_time + } + + // NOTE: `all_eq` does not exist, as it's simply the `eq` method from the `PartialEq` trait. } impl Zero for Weight { diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index d6434b6c63d8a..6e73a9e40179f 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -49,7 +49,8 @@ where ) -> Result<(), TransactionValidityError> { let max = T::BlockWeights::get().get(info.class).max_extrinsic; match max { - Some(max) if info.weight > max => Err(InvalidTransaction::ExhaustsResources.into()), + Some(max) if info.weight.any_gt(max) => + Err(InvalidTransaction::ExhaustsResources.into()), _ => Ok(()), } } @@ -144,7 +145,8 @@ where // Check if we don't exceed per-class allowance match limit_per_class.max_total { - Some(max) if per_class > max => return Err(InvalidTransaction::ExhaustsResources.into()), + Some(max) if per_class.any_gt(max) => + return Err(InvalidTransaction::ExhaustsResources.into()), // There is no `max_total` limit (`None`), // or we are below the limit. _ => {}, @@ -152,10 +154,10 @@ where // In cases total block weight is exceeded, we need to fall back // to `reserved` pool if there is any. - if all_weight.total() > maximum_weight.max_block { + if all_weight.total().any_gt(maximum_weight.max_block) { match limit_per_class.reserved { // We are over the limit in reserved pool. - Some(reserved) if per_class > reserved => + Some(reserved) if per_class.any_gt(reserved) => return Err(InvalidTransaction::ExhaustsResources.into()), // There is either no limit in reserved pool (`None`), // or we are below the limit. @@ -238,7 +240,7 @@ where } let unspent = post_info.calc_unspent(info); - if unspent > Weight::zero() { + if unspent.any_gt(Weight::zero()) { crate::BlockWeight::::mutate(|current_weight| { current_weight.sub(unspent, info.class); }) @@ -310,7 +312,7 @@ mod tests { check(|max, len| { assert_ok!(CheckWeight::::do_pre_dispatch(max, len)); assert_eq!(System::block_weight().total(), Weight::MAX); - assert!(System::block_weight().total() > block_weight_limit()); + assert!(System::block_weight().total().all_gt(block_weight_limit())); }); check(|max, len| { assert_ok!(CheckWeight::::do_validate(max, len)); @@ -367,7 +369,7 @@ mod tests { new_test_ext().execute_with(|| { System::register_extra_weight_unchecked(Weight::MAX, DispatchClass::Normal); assert_eq!(System::block_weight().total(), Weight::MAX); - assert!(System::block_weight().total() > block_weight_limit()); + assert!(System::block_weight().total().all_gt(block_weight_limit())); }); } diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index 7626c7e8665e6..ba73d29806bba 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -229,7 +229,7 @@ impl BlockWeights { // Make sure that if total is set it's greater than base_block && // base_for_class error_assert!( - (max_for_class > self.base_block && max_for_class > base_for_class) + (max_for_class.all_gt(self.base_block) && max_for_class.all_gt(base_for_class)) || max_for_class == Weight::zero(), &mut error, "[{:?}] {:?} (total) has to be greater than {:?} (base block) & {:?} (base extrinsic)", @@ -237,8 +237,10 @@ impl BlockWeights { ); // Max extrinsic can't be greater than max_for_class. error_assert!( - weights.max_extrinsic.unwrap_or(Weight::zero()) <= - max_for_class.saturating_sub(base_for_class), + weights + .max_extrinsic + .unwrap_or(Weight::zero()) + .all_lte(max_for_class.saturating_sub(base_for_class)), &mut error, "[{:?}] {:?} (max_extrinsic) can't be greater than {:?} (max for class)", class, @@ -247,14 +249,14 @@ impl BlockWeights { ); // Max extrinsic should not be 0 error_assert!( - weights.max_extrinsic.unwrap_or_else(Weight::max_value) > Weight::zero(), + weights.max_extrinsic.unwrap_or_else(Weight::max_value).all_gt(Weight::zero()), &mut error, "[{:?}] {:?} (max_extrinsic) must not be 0. Check base cost and average initialization cost.", class, weights.max_extrinsic, ); // Make sure that if reserved is set it's greater than base_for_class. error_assert!( - reserved > base_for_class || reserved == Weight::zero(), + reserved.all_gt(base_for_class) || reserved == Weight::zero(), &mut error, "[{:?}] {:?} (reserved) has to be greater than {:?} (base extrinsic) if set", class, @@ -263,7 +265,7 @@ impl BlockWeights { ); // Make sure max block is greater than max_total if it's set. error_assert!( - self.max_block >= weights.max_total.unwrap_or(Weight::zero()), + self.max_block.all_gte(weights.max_total.unwrap_or(Weight::zero())), &mut error, "[{:?}] {:?} (max block) has to be greater than {:?} (max for class)", class, @@ -272,7 +274,7 @@ impl BlockWeights { ); // Make sure we can fit at least one extrinsic. error_assert!( - self.max_block > base_for_class + self.base_block, + self.max_block.all_gt(base_for_class + self.base_block), &mut error, "[{:?}] {:?} (max block) must fit at least one extrinsic {:?} (base weight)", class, @@ -400,7 +402,7 @@ impl BlockWeightsBuilder { // compute max block size. for class in DispatchClass::all() { weights.max_block = match weights.per_class.get(*class).max_total { - Some(max) if max > weights.max_block => max, + Some(max) => max.max(weights.max_block), _ => weights.max_block, }; } diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index 5fb4e3aeb9ba6..a3e02b6caf740 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -172,7 +172,7 @@ pub mod pallet { .map_err(|_| Error::::UndecodableCall)?; ensure!( - call.get_dispatch_info().weight <= call_weight_witness, + call.get_dispatch_info().weight.all_lte(call_weight_witness), Error::::InvalidCallWeightWitness ); diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index 5feac07b3a7d8..0a4100953401f 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -53,14 +53,14 @@ mod test_weights { {{#if (eq short_name "block")}} // At least 100 µs. - assert!(w >= Weight::from_ref_time(100 * constants::WEIGHT_PER_MICROS), "Weight should be at least 100 µs."); + assert!(w.ref_time() >= 100u64 * constants::WEIGHT_PER_MICROS.ref_time(), "Weight should be at least 100 µs."); // At most 50 ms. - assert!(w <= Weight::from_ref_time(50 * constants::WEIGHT_PER_MILLIS), "Weight should be at most 50 ms."); + assert!(w.ref_time() <= 50u64 * constants::WEIGHT_PER_MILLIS.ref_time(), "Weight should be at most 50 ms."); {{else}} // At least 10 µs. - assert!(w >= Weight::from_ref_time(10 * constants::WEIGHT_PER_MICROS), "Weight should be at least 10 µs."); + assert!(w.ref_time() >= 10u64 * constants::WEIGHT_PER_MICROS.ref_time(), "Weight should be at least 10 µs."); // At most 1 ms. - assert!(w <= Weight::from_ref_time(constants::WEIGHT_PER_MILLIS), "Weight should be at most 1 ms."); + assert!(w.ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Weight should be at most 1 ms."); {{/if}} } } diff --git a/utils/frame/benchmarking-cli/src/storage/weights.hbs b/utils/frame/benchmarking-cli/src/storage/weights.hbs index 3aa4703e29eb2..95f42c411d1fd 100644 --- a/utils/frame/benchmarking-cli/src/storage/weights.hbs +++ b/utils/frame/benchmarking-cli/src/storage/weights.hbs @@ -75,20 +75,20 @@ pub mod constants { fn bound() { // At least 1 µs. assert!( - W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + W::get().reads(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Read weight should be at least 1 µs." ); assert!( - W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + W::get().writes(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Write weight should be at least 1 µs." ); // At most 1 ms. assert!( - W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + W::get().reads(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Read weight should be at most 1 ms." ); assert!( - W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + W::get().writes(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Write weight should be at most 1 ms." ); } From 8075aa489e6cebf5f5855fe614e5107db2b1b1aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 8 Sep 2022 09:52:25 +0100 Subject: [PATCH 1136/1472] pallet-identity: Be more paranoid ;) (#12170) * pallet-identity: Be more paranoid ;) Check that a registrar is providing judgement for the correct identity. * Fixes * Fix alliance * :facepalm: * Fixes * ... --- frame/alliance/src/mock.rs | 56 +++++++++++++++++--- frame/benchmarking/src/lib.rs | 4 +- frame/identity/src/benchmarking.rs | 46 +++++++++------- frame/identity/src/lib.rs | 12 ++++- frame/identity/src/tests.rs | 85 ++++++++++++++++++++++++++---- 5 files changed, 163 insertions(+), 40 deletions(-) diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index c140c040fbd0f..45c13b76cc525 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -297,20 +297,62 @@ pub fn new_test_ext() -> sp_io::TestExternalities { twitter: Data::default(), }; assert_ok!(Identity::set_identity(Origin::signed(1), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 1, Judgement::KnownGood)); + assert_ok!(Identity::provide_judgement( + Origin::signed(1), + 0, + 1, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); assert_ok!(Identity::set_identity(Origin::signed(2), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 2, Judgement::KnownGood)); + assert_ok!(Identity::provide_judgement( + Origin::signed(1), + 0, + 2, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); assert_ok!(Identity::set_identity(Origin::signed(3), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 3, Judgement::KnownGood)); + assert_ok!(Identity::provide_judgement( + Origin::signed(1), + 0, + 3, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); assert_ok!(Identity::set_identity(Origin::signed(4), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 4, Judgement::KnownGood)); + assert_ok!(Identity::provide_judgement( + Origin::signed(1), + 0, + 4, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); assert_ok!(Identity::set_identity(Origin::signed(5), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 5, Judgement::KnownGood)); + assert_ok!(Identity::provide_judgement( + Origin::signed(1), + 0, + 5, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); assert_ok!(Identity::set_identity(Origin::signed(6), Box::new(info.clone()))); assert_ok!(Identity::set_identity(Origin::signed(8), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 8, Judgement::KnownGood)); + assert_ok!(Identity::provide_judgement( + Origin::signed(1), + 0, + 8, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); assert_ok!(Identity::set_identity(Origin::signed(9), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 9, Judgement::KnownGood)); + assert_ok!(Identity::provide_judgement( + Origin::signed(1), + 0, + 9, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); // Joining before init should fail. assert_noop!( diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 18472595f15b9..614216a96940a 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -86,12 +86,12 @@ macro_rules! whitelist { /// ``` /// /// Note that due to parsing restrictions, if the `from` expression is not a single token (i.e. a -/// literal or constant), then it must be parenthesised. +/// literal or constant), then it must be parenthesized. /// /// The macro allows for a number of "arms", each representing an individual benchmark. Using the /// simple syntax, the associated dispatchable function maps 1:1 with the benchmark and the name of /// the benchmark is the same as that of the associated function. However, extended syntax allows -/// for arbitrary expresions to be evaluated in a benchmark (including for example, +/// for arbitrary expressions to be evaluated in a benchmark (including for example, /// `on_initialize`). /// /// Note that the ranges are *inclusive* on both sides. This is in contrast to ranges in Rust which diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 5d409f48bf567..6596f227383f2 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -76,9 +76,11 @@ fn create_sub_accounts( } // Set identity so `set_subs` does not fail. - let _ = T::Currency::make_free_balance_be(who, BalanceOf::::max_value() / 2u32.into()); - let info = create_identity_info::(1); - Identity::::set_identity(who_origin.into(), Box::new(info))?; + if IdentityOf::::get(who).is_none() { + let _ = T::Currency::make_free_balance_be(who, BalanceOf::::max_value() / 2u32.into()); + let info = create_identity_info::(1); + Identity::::set_identity(who_origin.into(), Box::new(info))?; + } Ok(subs) } @@ -138,7 +140,7 @@ benchmarks! { // Add an initial identity let initial_info = create_identity_info::(1); - Identity::::set_identity(caller_origin.clone(), Box::new(initial_info))?; + Identity::::set_identity(caller_origin.clone(), Box::new(initial_info.clone()))?; // User requests judgement from all the registrars, and they approve for i in 0..r { @@ -147,7 +149,8 @@ benchmarks! { RawOrigin::Signed(account("registrar", i, SEED)).into(), i, caller_lookup.clone(), - Judgement::Reasonable + Judgement::Reasonable, + T::Hashing::hash_of(&initial_info), )?; } caller @@ -200,13 +203,13 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); let _ = add_sub_accounts::(&caller, s)?; }; - let x in 1 .. T::MaxAdditionalFields::get() => { - // Create their main identity with x additional fields - let info = create_identity_info::(x); - let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller)); - Identity::::set_identity(caller_origin, Box::new(info))?; - }; + let x in 1 .. T::MaxAdditionalFields::get(); + + // Create their main identity with x additional fields + let info = create_identity_info::(x); + let caller: T::AccountId = whitelisted_caller(); + let caller_origin = ::Origin::from(RawOrigin::Signed(caller.clone())); + Identity::::set_identity(caller_origin.clone(), Box::new(info.clone()))?; // User requests judgement from all the registrars, and they approve for i in 0..r { @@ -215,7 +218,8 @@ benchmarks! { RawOrigin::Signed(account("registrar", i, SEED)).into(), i, caller_lookup.clone(), - Judgement::Reasonable + Judgement::Reasonable, + T::Hashing::hash_of(&info), )?; } ensure!(IdentityOf::::contains_key(&caller), "Identity does not exist."); @@ -328,15 +332,16 @@ benchmarks! { let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - let x in 1 .. T::MaxAdditionalFields::get() => { - let info = create_identity_info::(x); - Identity::::set_identity(user_origin.clone(), Box::new(info))?; - }; + let x in 1 .. T::MaxAdditionalFields::get(); + + let info = create_identity_info::(x); + let info_hash = T::Hashing::hash_of(&info); + Identity::::set_identity(user_origin.clone(), Box::new(info))?; let registrar_origin = T::RegistrarOrigin::successful_origin(); Identity::::add_registrar(registrar_origin, caller_lookup)?; Identity::::request_judgement(user_origin, r, 10u32.into())?; - }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable) + }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable, info_hash) verify { assert_last_event::(Event::::JudgementGiven { target: user, registrar_index: r }.into()) } @@ -352,7 +357,7 @@ benchmarks! { let _ = T::Currency::make_free_balance_be(&target, BalanceOf::::max_value()); let info = create_identity_info::(x); - Identity::::set_identity(target_origin.clone(), Box::new(info))?; + Identity::::set_identity(target_origin.clone(), Box::new(info.clone()))?; let _ = add_sub_accounts::(&target, s)?; // User requests judgement from all the registrars, and they approve @@ -362,7 +367,8 @@ benchmarks! { RawOrigin::Signed(account("registrar", i, SEED)).into(), i, target_lookup.clone(), - Judgement::Reasonable + Judgement::Reasonable, + T::Hashing::hash_of(&info), )?; } ensure!(IdentityOf::::contains_key(&target), "Identity not set"); diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 0f80acceb949c..d24b17eb86ee0 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -79,7 +79,7 @@ mod types; pub mod weights; use frame_support::traits::{BalanceStatus, Currency, OnUnbalanced, ReservableCurrency}; -use sp_runtime::traits::{AppendZerosInput, Saturating, StaticLookup, Zero}; +use sp_runtime::traits::{AppendZerosInput, Hash, Saturating, StaticLookup, Zero}; use sp_std::prelude::*; pub use weights::WeightInfo; @@ -236,6 +236,8 @@ pub mod pallet { NotSub, /// Sub-account isn't owned by sender. NotOwned, + /// The provided judgement was for a different identity. + JudgementForDifferentIdentity, } #[pallet::event] @@ -746,6 +748,7 @@ pub mod pallet { /// - `target`: the account whose identity the judgement is upon. This must be an account /// with a registered identity. /// - `judgement`: the judgement of the registrar of index `reg_index` about `target`. + /// - `identity`: The hash of the [`IdentityInfo`] for that the judgement is provided. /// /// Emits `JudgementGiven` if successful. /// @@ -765,6 +768,7 @@ pub mod pallet { #[pallet::compact] reg_index: RegistrarIndex, target: AccountIdLookupOf, judgement: Judgement>, + identity: T::Hash, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; let target = T::Lookup::lookup(target)?; @@ -772,10 +776,14 @@ pub mod pallet { >::get() .get(reg_index as usize) .and_then(Option::as_ref) - .and_then(|r| if r.account == sender { Some(r) } else { None }) + .filter(|r| r.account == sender) .ok_or(Error::::InvalidIndex)?; let mut id = >::get(&target).ok_or(Error::::InvalidTarget)?; + if T::Hashing::hash_of(&id.info) != identity { + return Err(Error::::JudgementForDifferentIdentity.into()) + } + let item = (reg_index, judgement); match id.judgements.binary_search_by_key(®_index, |x| x.0) { Ok(position) => { diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index a0773e9904a1c..4c1ced0a83324 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -279,27 +279,70 @@ fn registration_should_work() { fn uninvited_judgement_should_work() { new_test_ext().execute_with(|| { assert_noop!( - Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable), + Identity::provide_judgement( + Origin::signed(3), + 0, + 10, + Judgement::Reasonable, + H256::random() + ), Error::::InvalidIndex ); assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); assert_noop!( - Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable), + Identity::provide_judgement( + Origin::signed(3), + 0, + 10, + Judgement::Reasonable, + H256::random() + ), Error::::InvalidTarget ); assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); assert_noop!( - Identity::provide_judgement(Origin::signed(10), 0, 10, Judgement::Reasonable), + Identity::provide_judgement( + Origin::signed(3), + 0, + 10, + Judgement::Reasonable, + H256::random() + ), + Error::::JudgementForDifferentIdentity + ); + + let identity_hash = BlakeTwo256::hash_of(&ten()); + + assert_noop!( + Identity::provide_judgement( + Origin::signed(10), + 0, + 10, + Judgement::Reasonable, + identity_hash + ), Error::::InvalidIndex ); assert_noop!( - Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::FeePaid(1)), + Identity::provide_judgement( + Origin::signed(3), + 0, + 10, + Judgement::FeePaid(1), + identity_hash + ), Error::::InvalidJudgement ); - assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable)); + assert_ok!(Identity::provide_judgement( + Origin::signed(3), + 0, + 10, + Judgement::Reasonable, + identity_hash + )); assert_eq!(Identity::identity(10).unwrap().judgements, vec![(0, Judgement::Reasonable)]); }); } @@ -309,7 +352,13 @@ fn clearing_judgement_should_work() { new_test_ext().execute_with(|| { assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); - assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable)); + assert_ok!(Identity::provide_judgement( + Origin::signed(3), + 0, + 10, + Judgement::Reasonable, + BlakeTwo256::hash_of(&ten()) + )); assert_ok!(Identity::clear_identity(Origin::signed(10))); assert_eq!(Identity::identity(10), None); }); @@ -411,7 +460,13 @@ fn cancelling_requested_judgement_should_work() { assert_eq!(Balances::free_balance(10), 90); assert_noop!(Identity::cancel_request(Origin::signed(10), 0), Error::::NotFound); - assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable)); + assert_ok!(Identity::provide_judgement( + Origin::signed(3), + 0, + 10, + Judgement::Reasonable, + BlakeTwo256::hash_of(&ten()) + )); assert_noop!( Identity::cancel_request(Origin::signed(10), 0), Error::::JudgementGiven @@ -438,7 +493,13 @@ fn requesting_judgement_should_work() { Identity::request_judgement(Origin::signed(10), 0, 10), Error::::StickyJudgement ); - assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Erroneous)); + assert_ok!(Identity::provide_judgement( + Origin::signed(3), + 0, + 10, + Judgement::Erroneous, + BlakeTwo256::hash_of(&ten()) + )); // Registrar got their payment now. assert_eq!(Balances::free_balance(3), 20); @@ -453,7 +514,13 @@ fn requesting_judgement_should_work() { assert_ok!(Identity::request_judgement(Origin::signed(10), 1, 10)); // Re-requesting after the judgement has been reduced works. - assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::OutOfDate)); + assert_ok!(Identity::provide_judgement( + Origin::signed(3), + 0, + 10, + Judgement::OutOfDate, + BlakeTwo256::hash_of(&ten()) + )); assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); }); } From e20209240e7a5e7b32b91e9fcbe0e78a7397c8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 8 Sep 2022 09:57:23 +0100 Subject: [PATCH 1137/1472] Upgrade wasmtime to 0.40.0 (#12096) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Upgrade wasmtime to 0.40.0 * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Update in the other Cargo.toml * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts Co-authored-by: command-bot <> Co-authored-by: Alexander Theißen --- Cargo.lock | 237 ++--- client/executor/wasmtime/Cargo.toml | 9 +- client/executor/wasmtime/src/runtime.rs | 8 +- frame/contracts/src/weights.rs | 1254 +++++++++++------------ primitives/wasm-interface/Cargo.toml | 2 +- 5 files changed, 739 insertions(+), 771 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6c2df81d6ee1..223a14efd73b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1137,11 +1137,11 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.85.0" +version = "0.87.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899dc8d22f7771e7f887fb8bafa0c0d3ac1dea0c7f2c0ded6e20a855a7a1e890" +checksum = "9f91425bea5a5ac6d76b788477064944a7e21f0e240fd93f6f368a774a3efdd1" dependencies = [ - "cranelift-entity 0.85.0", + "cranelift-entity 0.87.1", ] [[package]] @@ -1163,14 +1163,14 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.85.0" +version = "0.87.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dbdc03f695cf67e7bc45da57155528274f47390b85060af8107eb304ef167c4" +checksum = "8b83b4bbf7bc96db77b7b5b5e41fafc4001536e9f0cbfd702ed7d4d8f848dc06" dependencies = [ - "cranelift-bforest 0.85.0", - "cranelift-codegen-meta 0.85.0", - "cranelift-codegen-shared 0.85.0", - "cranelift-entity 0.85.0", + "cranelift-bforest 0.87.1", + "cranelift-codegen-meta 0.87.1", + "cranelift-codegen-shared 0.87.1", + "cranelift-entity 0.87.1", "cranelift-isle", "gimli 0.26.1", "log", @@ -1191,11 +1191,11 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.85.0" +version = "0.87.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea66cbba3eb7fcb3ec9f42839a6d381bd40cf97780397e7167daf9725d4ffa0" +checksum = "da02e8fff048c381b313a3dfef4deb2343976fb6d7acc8e7d9c86d4c93e3fa06" dependencies = [ - "cranelift-codegen-shared 0.85.0", + "cranelift-codegen-shared 0.87.1", ] [[package]] @@ -1206,9 +1206,9 @@ checksum = "9dabb5fe66e04d4652e434195b45ae65b5c8172d520247b8f66d8df42b2b45dc" [[package]] name = "cranelift-codegen-shared" -version = "0.85.0" +version = "0.87.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712fbebd119a476f59122b4ba51fdce893a66309b5c92bd5506bfb11a0587496" +checksum = "9abc2a06e8fc29e36660ebbc9e2503e18a051057072acbb1e75e7f7cf19cb95e" [[package]] name = "cranelift-entity" @@ -1218,9 +1218,9 @@ checksum = "3329733e4d4b8e91c809efcaa4faee80bf66f20164e3dd16d707346bd3494799" [[package]] name = "cranelift-entity" -version = "0.85.0" +version = "0.87.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cb8b95859c4e14c9e860db78d596a904fdbe9261990233b62bd526346cb56cb" +checksum = "aeced7874890fc25d85cacc5e626c4d67931c7c25aad1c2ad521684744c1ff5c" dependencies = [ "serde", ] @@ -1239,11 +1239,11 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.85.0" +version = "0.87.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7b91b19a7d1221a73f190c0e865c12be77a84f661cac89abfd4ab5820142886" +checksum = "fc1d301ccad6fce05d9c9793d433d225fafdd57661b98d268d8d162e9291ff2e" dependencies = [ - "cranelift-codegen 0.85.0", + "cranelift-codegen 0.87.1", "log", "smallvec", "target-lexicon", @@ -1251,34 +1251,34 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.85.0" +version = "0.87.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d4f53bc86fb458e59c695c6a95ce8346e6a8377ee7ffc058e3ac08b5f94cb1" +checksum = "bd7b100db19320848986b4df1da19501dbddeb706a799f502222f72f889b0fab" [[package]] name = "cranelift-native" -version = "0.85.0" +version = "0.87.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "592f035d0ed41214dfeeb37abd536233536a27be6b4c2d39f380cd402f0cff4f" +checksum = "7be18d8b976cddc822e52343f328b7593d26dd2f1aeadd90da071596a210d524" dependencies = [ - "cranelift-codegen 0.85.0", + "cranelift-codegen 0.87.1", "libc", "target-lexicon", ] [[package]] name = "cranelift-wasm" -version = "0.85.0" +version = "0.87.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "295add6bf0b527a8bc50d02e31ff878585d2d2db53cb7e8754d6d82b84480086" +checksum = "2f9e48bb632a2e189b38a9fa89fa5a6eea687a5a4c613bbef7c2b7522c3ad0e0" dependencies = [ - "cranelift-codegen 0.85.0", - "cranelift-entity 0.85.0", - "cranelift-frontend 0.85.0", + "cranelift-codegen 0.87.1", + "cranelift-entity 0.87.1", + "cranelift-frontend 0.87.1", "itertools", "log", "smallvec", - "wasmparser 0.85.0", + "wasmparser 0.88.0", "wasmtime-types", ] @@ -3087,12 +3087,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "io-lifetimes" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6" - [[package]] name = "io-lifetimes" version = "0.7.2" @@ -4154,12 +4148,6 @@ dependencies = [ "statrs", ] -[[package]] -name = "linux-raw-sys" -version = "0.0.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5284f00d480e1c39af34e72f8ad60b94f47007e3481cd3b731c1d67190ddc7b7" - [[package]] name = "linux-raw-sys" version = "0.0.46" @@ -4315,11 +4303,11 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memfd" -version = "0.4.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6627dc657574b49d6ad27105ed671822be56e0d2547d413bfbf3e8d8fa92e7a" +checksum = "480b5a5de855d11ff13195950bdc8b98b5e942ef47afc447f6615cdcc4e15d80" dependencies = [ - "libc", + "rustix", ] [[package]] @@ -5096,6 +5084,18 @@ dependencies = [ "memchr", ] +[[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 = "once_cell" version = "1.12.0" @@ -7378,9 +7378,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.2.2" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d37148700dbb38f994cd99a1431613057f37ed934d7e4d799b7ab758c482461" +checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779" dependencies = [ "fxhash", "log", @@ -7415,18 +7415,6 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "region" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0" -dependencies = [ - "bitflags", - "libc", - "mach", - "winapi", -] - [[package]] name = "region" version = "3.0.0" @@ -7610,29 +7598,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.33.7" +version = "0.35.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938a344304321a9da4973b9ff4f9f8db9caf4597dfd9dda6a60b523340a0fff0" +checksum = "72c825b8aa8010eb9ee99b75f05e10180b9278d161583034d7574c9d617aeada" dependencies = [ "bitflags", "errno", - "io-lifetimes 0.5.3", + "io-lifetimes", "libc", - "linux-raw-sys 0.0.42", - "winapi", -] - -[[package]] -name = "rustix" -version = "0.35.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef258c11e17f5c01979a10543a30a4e12faef6aab217a74266e747eefa3aed88" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes 0.7.2", - "libc", - "linux-raw-sys 0.0.46", + "linux-raw-sys", "windows-sys 0.36.1", ] @@ -8264,8 +8238,7 @@ dependencies = [ "parity-scale-codec", "parity-wasm 0.42.2", "paste 1.0.6", - "rustix 0.33.7", - "rustix 0.35.6", + "rustix", "sc-allocator", "sc-executor-common", "sc-runtime-test", @@ -11620,7 +11593,7 @@ dependencies = [ "enumset", "leb128", "loupe", - "region 3.0.0", + "region", "rkyv", "wasmer-compiler", "wasmer-engine", @@ -11669,7 +11642,7 @@ dependencies = [ "loupe", "memoffset", "more-asserts", - "region 3.0.0", + "region", "rkyv", "serde", "thiserror", @@ -11711,49 +11684,55 @@ checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" [[package]] name = "wasmparser" -version = "0.85.0" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "570460c58b21e9150d2df0eaaedbb7816c34bcec009ae0dcc976e40ba81463e7" +checksum = "fb8cf7dd82407fe68161bedcd57fde15596f32ebf6e9b3bdbf3ae1da20e38e5e" dependencies = [ "indexmap", ] [[package]] name = "wasmtime" -version = "0.38.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c842f9c8e190fe01300fc8d715e9368c775670fb9856247c67abffdb5236d6db" +checksum = "a020a3f6587fa7a7d98a021156177735ebb07212a6239a85ab5f14b2f728508f" dependencies = [ "anyhow", - "backtrace", "bincode", "cfg-if 1.0.0", "indexmap", - "lazy_static", "libc", "log", - "object 0.28.3", + "object 0.29.0", "once_cell", "paste 1.0.6", "psm", "rayon", - "region 2.2.0", "serde", "target-lexicon", - "wasmparser 0.85.0", + "wasmparser 0.88.0", "wasmtime-cache", "wasmtime-cranelift", "wasmtime-environ", "wasmtime-jit", "wasmtime-runtime", - "winapi", + "windows-sys 0.36.1", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "0.40.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed4ada1fdd4d9a2aa37be652abcc31ae3188ad0efcefb4571ef4f785be2d777" +dependencies = [ + "cfg-if 1.0.0", ] [[package]] name = "wasmtime-cache" -version = "0.38.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cce2aa752e864a33eef2a6629edc59554e75f0bc1719431dac5e49eed516af69" +checksum = "d96a03a5732ef39b83943d9d72de8ac2d58623d3bfaaea4d9a92aea5fcd9acf5" dependencies = [ "anyhow", "base64", @@ -11761,61 +11740,59 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix 0.33.7", + "rustix", "serde", "sha2 0.9.8", "toml", - "winapi", + "windows-sys 0.36.1", "zstd", ] [[package]] name = "wasmtime-cranelift" -version = "0.38.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "922361eb8c03cea8909bc922471202f6c6bc2f0c682fac2fe473740441c86b3b" +checksum = "1fc59c28fe895112db09e262fb9c483f9e7b82c78a82a6ded69567ccc0e9795b" dependencies = [ "anyhow", - "cranelift-codegen 0.85.0", - "cranelift-entity 0.85.0", - "cranelift-frontend 0.85.0", + "cranelift-codegen 0.87.1", + "cranelift-entity 0.87.1", + "cranelift-frontend 0.87.1", "cranelift-native", "cranelift-wasm", "gimli 0.26.1", "log", - "more-asserts", - "object 0.28.3", + "object 0.29.0", "target-lexicon", "thiserror", - "wasmparser 0.85.0", + "wasmparser 0.88.0", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.38.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e602f1120fc40a3f016f1f69d08c86cfeff7b867bed1462901953e6871f85167" +checksum = "11086e573d2635a45ac0d44697a8e4586e058cf1b190f76bea466ca2ec36c30a" dependencies = [ "anyhow", - "cranelift-entity 0.85.0", + "cranelift-entity 0.87.1", "gimli 0.26.1", "indexmap", "log", - "more-asserts", - "object 0.28.3", + "object 0.29.0", "serde", "target-lexicon", "thiserror", - "wasmparser 0.85.0", + "wasmparser 0.88.0", "wasmtime-types", ] [[package]] name = "wasmtime-jit" -version = "0.38.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49af1445759a8e797a92f27dd0983c155615648263052e0b80d69e7d223896b7" +checksum = "d5444a78b74144718633f8642eccd7c4858f4c6f0c98ae6a3668998adf177ba2" dependencies = [ "addr2line", "anyhow", @@ -11824,38 +11801,36 @@ dependencies = [ "cpp_demangle", "gimli 0.26.1", "log", - "object 0.28.3", - "region 2.2.0", + "object 0.29.0", "rustc-demangle", - "rustix 0.33.7", + "rustix", "serde", "target-lexicon", "thiserror", "wasmtime-environ", "wasmtime-jit-debug", "wasmtime-runtime", - "winapi", + "windows-sys 0.36.1", ] [[package]] name = "wasmtime-jit-debug" -version = "0.38.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5dd480cc6dc0a401653e45b79796a3317f8228990d84bc2271bdaf0810071" +checksum = "c2bf6a667d2a29b2b0ed42bcf7564f00c595d92c24acb4d241c7c4d950b1910c" dependencies = [ - "lazy_static", - "object 0.28.3", - "rustix 0.33.7", + "object 0.29.0", + "once_cell", + "rustix", ] [[package]] name = "wasmtime-runtime" -version = "0.38.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e875bcd02d1ecfc7d099dd58354d55d73467652eb2b103ff470fe3aecb7d0381" +checksum = "ee064ce7b563cc201cdf3bb1cc4b233f386d8c57a96e55f4c4afe6103f4bd6a1" dependencies = [ "anyhow", - "backtrace", "cc", "cfg-if 1.0.0", "indexmap", @@ -11864,26 +11839,26 @@ dependencies = [ "mach", "memfd", "memoffset", - "more-asserts", + "paste 1.0.6", "rand 0.8.4", - "region 2.2.0", - "rustix 0.33.7", + "rustix", "thiserror", + "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", - "winapi", + "windows-sys 0.36.1", ] [[package]] name = "wasmtime-types" -version = "0.38.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd63a19ba61ac7448add4dc1fecb8d78304812af2a52dad04b89f887791b156" +checksum = "01e104bd9e625181d53ead85910bbc0863aa5f0c6ef96836fe9a5cc65da11b69" dependencies = [ - "cranelift-entity 0.85.0", + "cranelift-entity 0.87.1", "serde", "thiserror", - "wasmparser 0.85.0", + "wasmparser 0.88.0", ] [[package]] diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index e75f2d9d043d0..e4df2791c2ff8 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -21,7 +21,7 @@ parity-wasm = "0.42.0" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! -wasmtime = { version = "0.38.0", default-features = false, features = [ +wasmtime = { version = "0.40.1", default-features = false, features = [ "cache", "cranelift", "jitdump", @@ -35,16 +35,13 @@ sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime- sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-wasm-interface = { version = "6.0.0", features = ["wasmtime"], path = "../../../primitives/wasm-interface" } -[target.'cfg(target_os = "linux")'.dependencies] -rustix = { version = "0.35.6", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] } -once_cell = "1.12.0" - # Here we include the rustix crate used by wasmtime just to enable its 'use-libc' flag. # # By default rustix directly calls the appropriate syscalls completely bypassing libc; # this doesn't have any actual benefits for us besides making it harder to debug memory # problems (since then `mmap` etc. cannot be easily hooked into). -rustix_wasmtime = { package = "rustix", version = "0.33.7", default-features = false, features = ["std", "use-libc"] } +rustix = { version = "0.35.9", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] } +once_cell = "1.12.0" [dev-dependencies] wat = "1.0" diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 871de4e2300d2..5925a1792aef2 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -320,9 +320,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result native_stack_max, @@ -334,9 +332,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result 1024 * 1024, }; - config - .max_wasm_stack(native_stack_max as usize) - .map_err(|e| WasmError::Other(format!("cannot set max wasm stack: {:#}", e)))?; + config.max_wasm_stack(native_stack_max as usize); config.parallel_compilation(semantics.parallel_compilation); diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 4ec30437c57f1..6ec10b3590349 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-06, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-09-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -166,15 +166,15 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(2_948_000 as u64) + Weight::from_ref_time(2_985_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(14_858_000 as u64) + Weight::from_ref_time(14_335_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(890_000 as u64).saturating_mul(k as u64)) + .saturating_add(Weight::from_ref_time(891_000 as u64).saturating_mul(k as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -182,9 +182,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(14_778_000 as u64) + Weight::from_ref_time(13_905_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_228_000 as u64).saturating_mul(q as u64)) + .saturating_add(Weight::from_ref_time(1_257_000 as u64).saturating_mul(q as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -192,9 +192,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(21_622_000 as u64) + Weight::from_ref_time(26_333_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(44_000 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -205,9 +205,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(207_601_000 as u64) + Weight::from_ref_time(238_784_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -222,9 +222,9 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(287_355_000 as u64) + Weight::from_ref_time(325_497_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(107_000 as u64).saturating_mul(c as u64)) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) @@ -239,7 +239,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(178_912_000 as u64) + Weight::from_ref_time(201_129_000 as u64) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) @@ -251,7 +251,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(159_188_000 as u64) + Weight::from_ref_time(176_645_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -261,9 +261,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(52_177_000 as u64) + Weight::from_ref_time(53_613_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(47_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -272,7 +272,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(37_011_000 as u64) + Weight::from_ref_time(37_441_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -280,7 +280,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(40_206_000 as u64) + Weight::from_ref_time(40_030_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -291,9 +291,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(224_309_000 as u64) - // Standard Error: 53_000 - .saturating_add(Weight::from_ref_time(36_885_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_426_000 as u64) + // Standard Error: 46_000 + .saturating_add(Weight::from_ref_time(37_834_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -304,9 +304,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(166_137_000 as u64) - // Standard Error: 428_000 - .saturating_add(Weight::from_ref_time(214_063_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(181_406_000 as u64) + // Standard Error: 474_000 + .saturating_add(Weight::from_ref_time(206_995_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -318,9 +318,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(174_069_000 as u64) - // Standard Error: 443_000 - .saturating_add(Weight::from_ref_time(272_524_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(198_301_000 as u64) + // Standard Error: 432_000 + .saturating_add(Weight::from_ref_time(264_877_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -332,9 +332,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(225_577_000 as u64) - // Standard Error: 39_000 - .saturating_add(Weight::from_ref_time(40_425_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(243_754_000 as u64) + // Standard Error: 51_000 + .saturating_add(Weight::from_ref_time(41_219_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -345,9 +345,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(221_162_000 as u64) - // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(15_192_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_352_000 as u64) + // Standard Error: 33_000 + .saturating_add(Weight::from_ref_time(15_228_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -358,9 +358,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(224_517_000 as u64) - // Standard Error: 38_000 - .saturating_add(Weight::from_ref_time(36_722_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_637_000 as u64) + // Standard Error: 45_000 + .saturating_add(Weight::from_ref_time(37_717_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -371,9 +371,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(223_864_000 as u64) - // Standard Error: 35_000 - .saturating_add(Weight::from_ref_time(36_355_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_127_000 as u64) + // Standard Error: 45_000 + .saturating_add(Weight::from_ref_time(37_481_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -384,9 +384,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(226_396_000 as u64) - // Standard Error: 86_000 - .saturating_add(Weight::from_ref_time(112_018_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(246_236_000 as u64) + // Standard Error: 97_000 + .saturating_add(Weight::from_ref_time(110_095_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -397,9 +397,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(222_775_000 as u64) - // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(36_691_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_552_000 as u64) + // Standard Error: 38_000 + .saturating_add(Weight::from_ref_time(37_189_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -410,9 +410,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(223_202_000 as u64) - // Standard Error: 42_000 - .saturating_add(Weight::from_ref_time(36_393_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_622_000 as u64) + // Standard Error: 56_000 + .saturating_add(Weight::from_ref_time(37_630_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -423,9 +423,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(223_507_000 as u64) - // Standard Error: 44_000 - .saturating_add(Weight::from_ref_time(36_211_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_284_000 as u64) + // Standard Error: 49_000 + .saturating_add(Weight::from_ref_time(37_375_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -436,9 +436,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(225_500_000 as u64) - // Standard Error: 58_000 - .saturating_add(Weight::from_ref_time(36_290_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_463_000 as u64) + // Standard Error: 43_000 + .saturating_add(Weight::from_ref_time(37_313_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -450,9 +450,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(225_310_000 as u64) - // Standard Error: 86_000 - .saturating_add(Weight::from_ref_time(98_714_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(245_287_000 as u64) + // Standard Error: 88_000 + .saturating_add(Weight::from_ref_time(99_890_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -463,9 +463,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(149_071_000 as u64) - // Standard Error: 30_000 - .saturating_add(Weight::from_ref_time(18_084_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(168_156_000 as u64) + // Standard Error: 14_000 + .saturating_add(Weight::from_ref_time(17_991_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -476,9 +476,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(222_918_000 as u64) - // Standard Error: 48_000 - .saturating_add(Weight::from_ref_time(34_848_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_833_000 as u64) + // Standard Error: 50_000 + .saturating_add(Weight::from_ref_time(35_622_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -489,9 +489,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(280_543_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_599_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(330_765_000 as u64) + // Standard Error: 8_000 + .saturating_add(Weight::from_ref_time(8_609_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -502,9 +502,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - Weight::from_ref_time(219_310_000 as u64) - // Standard Error: 303_000 - .saturating_add(Weight::from_ref_time(1_187_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(237_729_000 as u64) + // Standard Error: 488_000 + .saturating_add(Weight::from_ref_time(2_053_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -515,9 +515,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(221_399_000 as u64) + Weight::from_ref_time(240_005_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(182_000 as u64).saturating_mul(n as u64)) + .saturating_add(Weight::from_ref_time(169_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -530,9 +530,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(222_285_000 as u64) - // Standard Error: 163_000 - .saturating_add(Weight::from_ref_time(52_104_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_524_000 as u64) + // Standard Error: 426_000 + .saturating_add(Weight::from_ref_time(51_863_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -546,9 +546,9 @@ impl WeightInfo for SubstrateWeight { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(233_586_000 as u64) - // Standard Error: 90_000 - .saturating_add(Weight::from_ref_time(133_209_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(250_710_000 as u64) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(132_741_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -559,9 +559,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(231_267_000 as u64) - // Standard Error: 118_000 - .saturating_add(Weight::from_ref_time(232_306_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(245_816_000 as u64) + // Standard Error: 115_000 + .saturating_add(Weight::from_ref_time(235_313_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -573,11 +573,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(438_016_000 as u64) - // Standard Error: 538_000 - .saturating_add(Weight::from_ref_time(179_846_000 as u64).saturating_mul(t as u64)) - // Standard Error: 147_000 - .saturating_add(Weight::from_ref_time(66_893_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(469_886_000 as u64) + // Standard Error: 463_000 + .saturating_add(Weight::from_ref_time(177_286_000 as u64).saturating_mul(t as u64)) + // Standard Error: 127_000 + .saturating_add(Weight::from_ref_time(64_646_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -590,18 +590,18 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(156_730_000 as u64) - // Standard Error: 48_000 - .saturating_add(Weight::from_ref_time(29_019_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(174_414_000 as u64) + // Standard Error: 26_000 + .saturating_add(Weight::from_ref_time(29_037_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(185_733_000 as u64) - // Standard Error: 384_000 - .saturating_add(Weight::from_ref_time(427_052_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(196_960_000 as u64) + // Standard Error: 414_000 + .saturating_add(Weight::from_ref_time(412_810_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -610,9 +610,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(520_776_000 as u64) - // Standard Error: 1_346_000 - .saturating_add(Weight::from_ref_time(93_389_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(529_493_000 as u64) + // Standard Error: 1_251_000 + .saturating_add(Weight::from_ref_time(88_835_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(52 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(50 as u64)) @@ -621,9 +621,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(504_262_000 as u64) - // Standard Error: 1_198_000 - .saturating_add(Weight::from_ref_time(68_581_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(512_531_000 as u64) + // Standard Error: 1_107_000 + .saturating_add(Weight::from_ref_time(67_926_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(52 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(50 as u64)) @@ -632,9 +632,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(188_507_000 as u64) - // Standard Error: 514_000 - .saturating_add(Weight::from_ref_time(416_965_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(208_848_000 as u64) + // Standard Error: 398_000 + .saturating_add(Weight::from_ref_time(400_478_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -643,9 +643,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(481_328_000 as u64) - // Standard Error: 1_304_000 - .saturating_add(Weight::from_ref_time(70_798_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(488_903_000 as u64) + // Standard Error: 1_226_000 + .saturating_add(Weight::from_ref_time(69_519_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(49 as u64)) @@ -654,9 +654,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(200_040_000 as u64) - // Standard Error: 292_000 - .saturating_add(Weight::from_ref_time(341_568_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(211_825_000 as u64) + // Standard Error: 401_000 + .saturating_add(Weight::from_ref_time(328_607_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -664,9 +664,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(443_969_000 as u64) - // Standard Error: 1_076_000 - .saturating_add(Weight::from_ref_time(154_674_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(452_324_000 as u64) + // Standard Error: 1_026_000 + .saturating_add(Weight::from_ref_time(150_657_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -674,9 +674,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(194_849_000 as u64) - // Standard Error: 310_000 - .saturating_add(Weight::from_ref_time(320_113_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(218_730_000 as u64) + // Standard Error: 318_000 + .saturating_add(Weight::from_ref_time(302_022_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -684,9 +684,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(416_712_000 as u64) - // Standard Error: 932_000 - .saturating_add(Weight::from_ref_time(63_903_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(425_128_000 as u64) + // Standard Error: 875_000 + .saturating_add(Weight::from_ref_time(60_095_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -694,9 +694,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(194_760_000 as u64) - // Standard Error: 375_000 - .saturating_add(Weight::from_ref_time(438_855_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(208_039_000 as u64) + // Standard Error: 445_000 + .saturating_add(Weight::from_ref_time(425_933_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -705,9 +705,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(509_485_000 as u64) - // Standard Error: 1_486_000 - .saturating_add(Weight::from_ref_time(162_250_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(518_112_000 as u64) + // Standard Error: 1_406_000 + .saturating_add(Weight::from_ref_time(159_006_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(52 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(49 as u64)) @@ -720,9 +720,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(162_740_000 as u64) - // Standard Error: 691_000 - .saturating_add(Weight::from_ref_time(1_338_567_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(169_573_000 as u64) + // Standard Error: 701_000 + .saturating_add(Weight::from_ref_time(1_345_943_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -736,8 +736,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 8_018_000 - .saturating_add(Weight::from_ref_time(16_181_274_000 as u64).saturating_mul(r as u64)) + // Standard Error: 8_472_000 + .saturating_add(Weight::from_ref_time(17_569_902_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -751,8 +751,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 8_806_000 - .saturating_add(Weight::from_ref_time(15_988_209_000 as u64).saturating_mul(r as u64)) + // Standard Error: 7_932_000 + .saturating_add(Weight::from_ref_time(17_368_706_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads((158 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes((79 as u64).saturating_mul(r as u64))) } @@ -764,11 +764,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(9_685_415_000 as u64) - // Standard Error: 6_048_000 - .saturating_add(Weight::from_ref_time(1_132_315_000 as u64).saturating_mul(t as u64)) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(9_753_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(11_036_172_000 as u64) + // Standard Error: 5_683_000 + .saturating_add(Weight::from_ref_time(1_154_945_000 as u64).saturating_mul(t as u64)) + // Standard Error: 8_000 + .saturating_add(Weight::from_ref_time(8_670_000 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(167 as u64)) .saturating_add(T::DbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(163 as u64)) @@ -784,8 +784,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 30_079_000 - .saturating_add(Weight::from_ref_time(21_155_990_000 as u64).saturating_mul(r as u64)) + // Standard Error: 25_721_000 + .saturating_add(Weight::from_ref_time(22_827_927_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().reads((400 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(5 as u64)) @@ -801,9 +801,9 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(12_321_649_000 as u64) - // Standard Error: 77_000 - .saturating_add(Weight::from_ref_time(125_883_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(13_991_911_000 as u64) + // Standard Error: 70_000 + .saturating_add(Weight::from_ref_time(124_789_000 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(249 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(247 as u64)) @@ -816,9 +816,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(224_020_000 as u64) - // Standard Error: 63_000 - .saturating_add(Weight::from_ref_time(57_966_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_026_000 as u64) + // Standard Error: 69_000 + .saturating_add(Weight::from_ref_time(58_077_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -830,8 +830,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 86_000 - .saturating_add(Weight::from_ref_time(319_801_000 as u64).saturating_mul(n as u64)) + // Standard Error: 104_000 + .saturating_add(Weight::from_ref_time(320_432_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -842,9 +842,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(222_308_000 as u64) - // Standard Error: 78_000 - .saturating_add(Weight::from_ref_time(70_579_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(242_548_000 as u64) + // Standard Error: 88_000 + .saturating_add(Weight::from_ref_time(70_774_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -856,8 +856,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 97_000 - .saturating_add(Weight::from_ref_time(247_328_000 as u64).saturating_mul(n as u64)) + // Standard Error: 152_000 + .saturating_add(Weight::from_ref_time(246_268_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -868,9 +868,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(221_851_000 as u64) - // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(48_446_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(242_368_000 as u64) + // Standard Error: 68_000 + .saturating_add(Weight::from_ref_time(48_368_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -882,8 +882,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 93_000 - .saturating_add(Weight::from_ref_time(97_258_000 as u64).saturating_mul(n as u64)) + // Standard Error: 94_000 + .saturating_add(Weight::from_ref_time(95_913_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -894,9 +894,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(221_346_000 as u64) - // Standard Error: 46_000 - .saturating_add(Weight::from_ref_time(47_910_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_100_000 as u64) + // Standard Error: 56_000 + .saturating_add(Weight::from_ref_time(48_043_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -908,8 +908,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(97_458_000 as u64).saturating_mul(n as u64)) + // Standard Error: 93_000 + .saturating_add(Weight::from_ref_time(96_000_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -920,9 +920,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(355_672_000 as u64) - // Standard Error: 678_000 - .saturating_add(Weight::from_ref_time(2_970_861_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(375_902_000 as u64) + // Standard Error: 613_000 + .saturating_add(Weight::from_ref_time(2_972_514_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -933,9 +933,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(232_179_000 as u64) - // Standard Error: 463_000 - .saturating_add(Weight::from_ref_time(2_059_953_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(260_758_000 as u64) + // Standard Error: 396_000 + .saturating_add(Weight::from_ref_time(2_069_937_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -948,316 +948,316 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 1_725_000 - .saturating_add(Weight::from_ref_time(1_107_351_000 as u64).saturating_mul(r as u64)) + // Standard Error: 1_629_000 + .saturating_add(Weight::from_ref_time(1_093_632_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads((158 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes((158 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(70_023_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(848_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_130_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(798_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(70_335_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_761_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_439_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_717_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(69_875_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_289_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_647_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_112_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(71_128_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(2_288_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_045_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_228_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(68_850_000 as u64) + Weight::from_ref_time(71_013_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_558_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(2_284_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(69_585_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_293_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_846_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_278_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_492_000 as u64) + Weight::from_ref_time(69_471_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_774_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(69_344_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_089_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(68_967_000 as u64) + // Standard Error: 6_000 + .saturating_add(Weight::from_ref_time(1_984_000 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(72_833_000 as u64) + Weight::from_ref_time(72_756_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(3_000 as u64).saturating_mul(e as u64)) + .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(70_722_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(6_545_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_426_000 as u64) + // Standard Error: 13_000 + .saturating_add(Weight::from_ref_time(7_095_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(84_465_000 as u64) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(8_307_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(85_090_000 as u64) + // Standard Error: 34_000 + .saturating_add(Weight::from_ref_time(8_897_000 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(93_185_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(599_000 as u64).saturating_mul(p as u64)) + Weight::from_ref_time(94_306_000 as u64) + // Standard Error: 7_000 + .saturating_add(Weight::from_ref_time(585_000 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(70_473_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(875_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_494_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(857_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(70_352_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(907_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_467_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(890_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(70_239_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_219_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_451_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_196_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(72_049_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(1_543_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_857_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_442_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(72_551_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_693_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_589_000 as u64) + // Standard Error: 6_000 + .saturating_add(Weight::from_ref_time(1_682_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(70_228_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(889_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_230_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(820_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(70_987_000 as u64) - // Standard Error: 88_000 - .saturating_add(Weight::from_ref_time(186_348_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_027_000 as u64) + // Standard Error: 296_000 + .saturating_add(Weight::from_ref_time(177_139_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(70_186_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_304_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_270_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_250_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(69_796_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_088_000 as u64) + // Standard Error: 14_000 + .saturating_add(Weight::from_ref_time(1_281_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(70_184_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_315_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_538_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(1_283_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(70_059_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_316_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_842_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_266_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(70_066_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_282_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_754_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_230_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(70_100_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_285_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_842_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_193_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(69_992_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_330_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_670_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_281_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(69_935_000 as u64) + Weight::from_ref_time(69_728_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_829_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_770_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(70_024_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_820_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_522_000 as u64) + // Standard Error: 7_000 + .saturating_add(Weight::from_ref_time(1_767_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(69_794_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_831_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_224_000 as u64) + // Standard Error: 10_000 + .saturating_add(Weight::from_ref_time(1_752_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(69_997_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_817_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_625_000 as u64) + // Standard Error: 7_000 + .saturating_add(Weight::from_ref_time(1_763_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(70_610_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_804_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_816_000 as u64) + // Standard Error: 31_000 + .saturating_add(Weight::from_ref_time(1_852_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(69_759_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_846_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_019_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_780_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(70_405_000 as u64) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(1_808_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_881_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(1_783_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(69_968_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_838_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_021_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_766_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(69_825_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_854_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_156_000 as u64) + // Standard Error: 17_000 + .saturating_add(Weight::from_ref_time(1_712_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(69_973_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_822_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_004_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_820_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(69_907_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_824_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_028_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_772_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(72_280_000 as u64) - // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(1_756_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_159_000 as u64) + // Standard Error: 7_000 + .saturating_add(Weight::from_ref_time(1_813_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(69_827_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_033_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_760_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(69_995_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_461_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_702_000 as u64) + // Standard Error: 6_000 + .saturating_add(Weight::from_ref_time(2_512_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(69_627_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_453_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(68_933_000 as u64) + // Standard Error: 23_000 + .saturating_add(Weight::from_ref_time(2_501_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(70_040_000 as u64) + Weight::from_ref_time(69_447_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_456_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(2_555_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(69_754_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_450_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_872_000 as u64) + // Standard Error: 6_000 + .saturating_add(Weight::from_ref_time(2_459_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(69_848_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_836_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_867_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_783_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(69_904_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_837_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_982_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_772_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(69_912_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_839_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_822_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_779_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(69_656_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_858_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_511_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_806_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(69_927_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_956_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_788_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(70_025_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_069_000 as u64) + // Standard Error: 11_000 + .saturating_add(Weight::from_ref_time(1_789_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(69_916_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_843_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_719_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_792_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(69_988_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_842_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_709_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_800_000 as u64).saturating_mul(r as u64)) } } @@ -1265,15 +1265,15 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(2_948_000 as u64) + Weight::from_ref_time(2_985_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(14_858_000 as u64) + Weight::from_ref_time(14_335_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(890_000 as u64).saturating_mul(k as u64)) + .saturating_add(Weight::from_ref_time(891_000 as u64).saturating_mul(k as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -1281,9 +1281,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(14_778_000 as u64) + Weight::from_ref_time(13_905_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_228_000 as u64).saturating_mul(q as u64)) + .saturating_add(Weight::from_ref_time(1_257_000 as u64).saturating_mul(q as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1291,9 +1291,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(21_622_000 as u64) + Weight::from_ref_time(26_333_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(44_000 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1304,9 +1304,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(207_601_000 as u64) + Weight::from_ref_time(238_784_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1321,9 +1321,9 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(287_355_000 as u64) + Weight::from_ref_time(325_497_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(107_000 as u64).saturating_mul(c as u64)) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) @@ -1338,7 +1338,7 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(178_912_000 as u64) + Weight::from_ref_time(201_129_000 as u64) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) @@ -1350,7 +1350,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(159_188_000 as u64) + Weight::from_ref_time(176_645_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1360,9 +1360,9 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(52_177_000 as u64) + Weight::from_ref_time(53_613_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(47_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1371,7 +1371,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(37_011_000 as u64) + Weight::from_ref_time(37_441_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1379,7 +1379,7 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(40_206_000 as u64) + Weight::from_ref_time(40_030_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -1390,9 +1390,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(224_309_000 as u64) - // Standard Error: 53_000 - .saturating_add(Weight::from_ref_time(36_885_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_426_000 as u64) + // Standard Error: 46_000 + .saturating_add(Weight::from_ref_time(37_834_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1403,9 +1403,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(166_137_000 as u64) - // Standard Error: 428_000 - .saturating_add(Weight::from_ref_time(214_063_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(181_406_000 as u64) + // Standard Error: 474_000 + .saturating_add(Weight::from_ref_time(206_995_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1417,9 +1417,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(174_069_000 as u64) - // Standard Error: 443_000 - .saturating_add(Weight::from_ref_time(272_524_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(198_301_000 as u64) + // Standard Error: 432_000 + .saturating_add(Weight::from_ref_time(264_877_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1431,9 +1431,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(225_577_000 as u64) - // Standard Error: 39_000 - .saturating_add(Weight::from_ref_time(40_425_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(243_754_000 as u64) + // Standard Error: 51_000 + .saturating_add(Weight::from_ref_time(41_219_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1444,9 +1444,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(221_162_000 as u64) - // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(15_192_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_352_000 as u64) + // Standard Error: 33_000 + .saturating_add(Weight::from_ref_time(15_228_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1457,9 +1457,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(224_517_000 as u64) - // Standard Error: 38_000 - .saturating_add(Weight::from_ref_time(36_722_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_637_000 as u64) + // Standard Error: 45_000 + .saturating_add(Weight::from_ref_time(37_717_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1470,9 +1470,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(223_864_000 as u64) - // Standard Error: 35_000 - .saturating_add(Weight::from_ref_time(36_355_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_127_000 as u64) + // Standard Error: 45_000 + .saturating_add(Weight::from_ref_time(37_481_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1483,9 +1483,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(226_396_000 as u64) - // Standard Error: 86_000 - .saturating_add(Weight::from_ref_time(112_018_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(246_236_000 as u64) + // Standard Error: 97_000 + .saturating_add(Weight::from_ref_time(110_095_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1496,9 +1496,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(222_775_000 as u64) - // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(36_691_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_552_000 as u64) + // Standard Error: 38_000 + .saturating_add(Weight::from_ref_time(37_189_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1509,9 +1509,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(223_202_000 as u64) - // Standard Error: 42_000 - .saturating_add(Weight::from_ref_time(36_393_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_622_000 as u64) + // Standard Error: 56_000 + .saturating_add(Weight::from_ref_time(37_630_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1522,9 +1522,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(223_507_000 as u64) - // Standard Error: 44_000 - .saturating_add(Weight::from_ref_time(36_211_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_284_000 as u64) + // Standard Error: 49_000 + .saturating_add(Weight::from_ref_time(37_375_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1535,9 +1535,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(225_500_000 as u64) - // Standard Error: 58_000 - .saturating_add(Weight::from_ref_time(36_290_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_463_000 as u64) + // Standard Error: 43_000 + .saturating_add(Weight::from_ref_time(37_313_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1549,9 +1549,9 @@ impl WeightInfo for () { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(225_310_000 as u64) - // Standard Error: 86_000 - .saturating_add(Weight::from_ref_time(98_714_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(245_287_000 as u64) + // Standard Error: 88_000 + .saturating_add(Weight::from_ref_time(99_890_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1562,9 +1562,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(149_071_000 as u64) - // Standard Error: 30_000 - .saturating_add(Weight::from_ref_time(18_084_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(168_156_000 as u64) + // Standard Error: 14_000 + .saturating_add(Weight::from_ref_time(17_991_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1575,9 +1575,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(222_918_000 as u64) - // Standard Error: 48_000 - .saturating_add(Weight::from_ref_time(34_848_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_833_000 as u64) + // Standard Error: 50_000 + .saturating_add(Weight::from_ref_time(35_622_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1588,9 +1588,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(280_543_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_599_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(330_765_000 as u64) + // Standard Error: 8_000 + .saturating_add(Weight::from_ref_time(8_609_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1601,9 +1601,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - Weight::from_ref_time(219_310_000 as u64) - // Standard Error: 303_000 - .saturating_add(Weight::from_ref_time(1_187_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(237_729_000 as u64) + // Standard Error: 488_000 + .saturating_add(Weight::from_ref_time(2_053_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1614,9 +1614,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(221_399_000 as u64) + Weight::from_ref_time(240_005_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(182_000 as u64).saturating_mul(n as u64)) + .saturating_add(Weight::from_ref_time(169_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1629,9 +1629,9 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(222_285_000 as u64) - // Standard Error: 163_000 - .saturating_add(Weight::from_ref_time(52_104_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_524_000 as u64) + // Standard Error: 426_000 + .saturating_add(Weight::from_ref_time(51_863_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1645,9 +1645,9 @@ impl WeightInfo for () { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(233_586_000 as u64) - // Standard Error: 90_000 - .saturating_add(Weight::from_ref_time(133_209_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(250_710_000 as u64) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(132_741_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1658,9 +1658,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(231_267_000 as u64) - // Standard Error: 118_000 - .saturating_add(Weight::from_ref_time(232_306_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(245_816_000 as u64) + // Standard Error: 115_000 + .saturating_add(Weight::from_ref_time(235_313_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1672,11 +1672,11 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(438_016_000 as u64) - // Standard Error: 538_000 - .saturating_add(Weight::from_ref_time(179_846_000 as u64).saturating_mul(t as u64)) - // Standard Error: 147_000 - .saturating_add(Weight::from_ref_time(66_893_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(469_886_000 as u64) + // Standard Error: 463_000 + .saturating_add(Weight::from_ref_time(177_286_000 as u64).saturating_mul(t as u64)) + // Standard Error: 127_000 + .saturating_add(Weight::from_ref_time(64_646_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1689,18 +1689,18 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(156_730_000 as u64) - // Standard Error: 48_000 - .saturating_add(Weight::from_ref_time(29_019_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(174_414_000 as u64) + // Standard Error: 26_000 + .saturating_add(Weight::from_ref_time(29_037_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(185_733_000 as u64) - // Standard Error: 384_000 - .saturating_add(Weight::from_ref_time(427_052_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(196_960_000 as u64) + // Standard Error: 414_000 + .saturating_add(Weight::from_ref_time(412_810_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1709,9 +1709,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(520_776_000 as u64) - // Standard Error: 1_346_000 - .saturating_add(Weight::from_ref_time(93_389_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(529_493_000 as u64) + // Standard Error: 1_251_000 + .saturating_add(Weight::from_ref_time(88_835_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(52 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(50 as u64)) @@ -1720,9 +1720,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(504_262_000 as u64) - // Standard Error: 1_198_000 - .saturating_add(Weight::from_ref_time(68_581_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(512_531_000 as u64) + // Standard Error: 1_107_000 + .saturating_add(Weight::from_ref_time(67_926_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(52 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(50 as u64)) @@ -1731,9 +1731,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(188_507_000 as u64) - // Standard Error: 514_000 - .saturating_add(Weight::from_ref_time(416_965_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(208_848_000 as u64) + // Standard Error: 398_000 + .saturating_add(Weight::from_ref_time(400_478_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -1742,9 +1742,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(481_328_000 as u64) - // Standard Error: 1_304_000 - .saturating_add(Weight::from_ref_time(70_798_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(488_903_000 as u64) + // Standard Error: 1_226_000 + .saturating_add(Weight::from_ref_time(69_519_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(49 as u64)) @@ -1753,9 +1753,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(200_040_000 as u64) - // Standard Error: 292_000 - .saturating_add(Weight::from_ref_time(341_568_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(211_825_000 as u64) + // Standard Error: 401_000 + .saturating_add(Weight::from_ref_time(328_607_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1763,9 +1763,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(443_969_000 as u64) - // Standard Error: 1_076_000 - .saturating_add(Weight::from_ref_time(154_674_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(452_324_000 as u64) + // Standard Error: 1_026_000 + .saturating_add(Weight::from_ref_time(150_657_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1773,9 +1773,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(194_849_000 as u64) - // Standard Error: 310_000 - .saturating_add(Weight::from_ref_time(320_113_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(218_730_000 as u64) + // Standard Error: 318_000 + .saturating_add(Weight::from_ref_time(302_022_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1783,9 +1783,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(416_712_000 as u64) - // Standard Error: 932_000 - .saturating_add(Weight::from_ref_time(63_903_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(425_128_000 as u64) + // Standard Error: 875_000 + .saturating_add(Weight::from_ref_time(60_095_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1793,9 +1793,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(194_760_000 as u64) - // Standard Error: 375_000 - .saturating_add(Weight::from_ref_time(438_855_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(208_039_000 as u64) + // Standard Error: 445_000 + .saturating_add(Weight::from_ref_time(425_933_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -1804,9 +1804,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(509_485_000 as u64) - // Standard Error: 1_486_000 - .saturating_add(Weight::from_ref_time(162_250_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(518_112_000 as u64) + // Standard Error: 1_406_000 + .saturating_add(Weight::from_ref_time(159_006_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(52 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(49 as u64)) @@ -1819,9 +1819,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(162_740_000 as u64) - // Standard Error: 691_000 - .saturating_add(Weight::from_ref_time(1_338_567_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(169_573_000 as u64) + // Standard Error: 701_000 + .saturating_add(Weight::from_ref_time(1_345_943_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -1835,8 +1835,8 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 8_018_000 - .saturating_add(Weight::from_ref_time(16_181_274_000 as u64).saturating_mul(r as u64)) + // Standard Error: 8_472_000 + .saturating_add(Weight::from_ref_time(17_569_902_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1850,8 +1850,8 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 8_806_000 - .saturating_add(Weight::from_ref_time(15_988_209_000 as u64).saturating_mul(r as u64)) + // Standard Error: 7_932_000 + .saturating_add(Weight::from_ref_time(17_368_706_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads((158 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes((79 as u64).saturating_mul(r as u64))) } @@ -1863,11 +1863,11 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(9_685_415_000 as u64) - // Standard Error: 6_048_000 - .saturating_add(Weight::from_ref_time(1_132_315_000 as u64).saturating_mul(t as u64)) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(9_753_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(11_036_172_000 as u64) + // Standard Error: 5_683_000 + .saturating_add(Weight::from_ref_time(1_154_945_000 as u64).saturating_mul(t as u64)) + // Standard Error: 8_000 + .saturating_add(Weight::from_ref_time(8_670_000 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(167 as u64)) .saturating_add(RocksDbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(163 as u64)) @@ -1883,8 +1883,8 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 30_079_000 - .saturating_add(Weight::from_ref_time(21_155_990_000 as u64).saturating_mul(r as u64)) + // Standard Error: 25_721_000 + .saturating_add(Weight::from_ref_time(22_827_927_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().reads((400 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(5 as u64)) @@ -1900,9 +1900,9 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(12_321_649_000 as u64) - // Standard Error: 77_000 - .saturating_add(Weight::from_ref_time(125_883_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(13_991_911_000 as u64) + // Standard Error: 70_000 + .saturating_add(Weight::from_ref_time(124_789_000 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(249 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(247 as u64)) @@ -1915,9 +1915,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(224_020_000 as u64) - // Standard Error: 63_000 - .saturating_add(Weight::from_ref_time(57_966_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_026_000 as u64) + // Standard Error: 69_000 + .saturating_add(Weight::from_ref_time(58_077_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1929,8 +1929,8 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 86_000 - .saturating_add(Weight::from_ref_time(319_801_000 as u64).saturating_mul(n as u64)) + // Standard Error: 104_000 + .saturating_add(Weight::from_ref_time(320_432_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1941,9 +1941,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(222_308_000 as u64) - // Standard Error: 78_000 - .saturating_add(Weight::from_ref_time(70_579_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(242_548_000 as u64) + // Standard Error: 88_000 + .saturating_add(Weight::from_ref_time(70_774_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1955,8 +1955,8 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 97_000 - .saturating_add(Weight::from_ref_time(247_328_000 as u64).saturating_mul(n as u64)) + // Standard Error: 152_000 + .saturating_add(Weight::from_ref_time(246_268_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1967,9 +1967,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(221_851_000 as u64) - // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(48_446_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(242_368_000 as u64) + // Standard Error: 68_000 + .saturating_add(Weight::from_ref_time(48_368_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1981,8 +1981,8 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 93_000 - .saturating_add(Weight::from_ref_time(97_258_000 as u64).saturating_mul(n as u64)) + // Standard Error: 94_000 + .saturating_add(Weight::from_ref_time(95_913_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1993,9 +1993,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(221_346_000 as u64) - // Standard Error: 46_000 - .saturating_add(Weight::from_ref_time(47_910_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_100_000 as u64) + // Standard Error: 56_000 + .saturating_add(Weight::from_ref_time(48_043_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2007,8 +2007,8 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(97_458_000 as u64).saturating_mul(n as u64)) + // Standard Error: 93_000 + .saturating_add(Weight::from_ref_time(96_000_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2019,9 +2019,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(355_672_000 as u64) - // Standard Error: 678_000 - .saturating_add(Weight::from_ref_time(2_970_861_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(375_902_000 as u64) + // Standard Error: 613_000 + .saturating_add(Weight::from_ref_time(2_972_514_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2032,9 +2032,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(232_179_000 as u64) - // Standard Error: 463_000 - .saturating_add(Weight::from_ref_time(2_059_953_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(260_758_000 as u64) + // Standard Error: 396_000 + .saturating_add(Weight::from_ref_time(2_069_937_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2047,315 +2047,315 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 1_725_000 - .saturating_add(Weight::from_ref_time(1_107_351_000 as u64).saturating_mul(r as u64)) + // Standard Error: 1_629_000 + .saturating_add(Weight::from_ref_time(1_093_632_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads((158 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes((158 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(70_023_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(848_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_130_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(798_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(70_335_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_761_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_439_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_717_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(69_875_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_289_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_647_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_112_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(71_128_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(2_288_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_045_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_228_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(68_850_000 as u64) + Weight::from_ref_time(71_013_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_558_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(2_284_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(69_585_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_293_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_846_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_278_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_492_000 as u64) + Weight::from_ref_time(69_471_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_774_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(69_344_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_089_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(68_967_000 as u64) + // Standard Error: 6_000 + .saturating_add(Weight::from_ref_time(1_984_000 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(72_833_000 as u64) + Weight::from_ref_time(72_756_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(3_000 as u64).saturating_mul(e as u64)) + .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(70_722_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(6_545_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_426_000 as u64) + // Standard Error: 13_000 + .saturating_add(Weight::from_ref_time(7_095_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(84_465_000 as u64) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(8_307_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(85_090_000 as u64) + // Standard Error: 34_000 + .saturating_add(Weight::from_ref_time(8_897_000 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(93_185_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(599_000 as u64).saturating_mul(p as u64)) + Weight::from_ref_time(94_306_000 as u64) + // Standard Error: 7_000 + .saturating_add(Weight::from_ref_time(585_000 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(70_473_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(875_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_494_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(857_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(70_352_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(907_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_467_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(890_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(70_239_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_219_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_451_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_196_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(72_049_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(1_543_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_857_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_442_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(72_551_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_693_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_589_000 as u64) + // Standard Error: 6_000 + .saturating_add(Weight::from_ref_time(1_682_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(70_228_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(889_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_230_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(820_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(70_987_000 as u64) - // Standard Error: 88_000 - .saturating_add(Weight::from_ref_time(186_348_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_027_000 as u64) + // Standard Error: 296_000 + .saturating_add(Weight::from_ref_time(177_139_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(70_186_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_304_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_270_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_250_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(69_796_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_088_000 as u64) + // Standard Error: 14_000 + .saturating_add(Weight::from_ref_time(1_281_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(70_184_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_315_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_538_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(1_283_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(70_059_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_316_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_842_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_266_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(70_066_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_282_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_754_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_230_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(70_100_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_285_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_842_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_193_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(69_992_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_330_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_670_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_281_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(69_935_000 as u64) + Weight::from_ref_time(69_728_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_829_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_770_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(70_024_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_820_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_522_000 as u64) + // Standard Error: 7_000 + .saturating_add(Weight::from_ref_time(1_767_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(69_794_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_831_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_224_000 as u64) + // Standard Error: 10_000 + .saturating_add(Weight::from_ref_time(1_752_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(69_997_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_817_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_625_000 as u64) + // Standard Error: 7_000 + .saturating_add(Weight::from_ref_time(1_763_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(70_610_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_804_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_816_000 as u64) + // Standard Error: 31_000 + .saturating_add(Weight::from_ref_time(1_852_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(69_759_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_846_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_019_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_780_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(70_405_000 as u64) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(1_808_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_881_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(1_783_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(69_968_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_838_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_021_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_766_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(69_825_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_854_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_156_000 as u64) + // Standard Error: 17_000 + .saturating_add(Weight::from_ref_time(1_712_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(69_973_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_822_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_004_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_820_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(69_907_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_824_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_028_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_772_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(72_280_000 as u64) - // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(1_756_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_159_000 as u64) + // Standard Error: 7_000 + .saturating_add(Weight::from_ref_time(1_813_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(69_827_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_033_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_760_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(69_995_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_461_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_702_000 as u64) + // Standard Error: 6_000 + .saturating_add(Weight::from_ref_time(2_512_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(69_627_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_453_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(68_933_000 as u64) + // Standard Error: 23_000 + .saturating_add(Weight::from_ref_time(2_501_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(70_040_000 as u64) + Weight::from_ref_time(69_447_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_456_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(2_555_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(69_754_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_450_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_872_000 as u64) + // Standard Error: 6_000 + .saturating_add(Weight::from_ref_time(2_459_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(69_848_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_836_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_867_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_783_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(69_904_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_837_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_982_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_772_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(69_912_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_839_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_822_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_779_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(69_656_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_858_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_511_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_806_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(69_927_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_956_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_788_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(70_025_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_069_000 as u64) + // Standard Error: 11_000 + .saturating_add(Weight::from_ref_time(1_789_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(69_916_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_843_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_719_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_792_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(69_988_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_842_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_709_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_800_000 as u64).saturating_mul(r as u64)) } } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index ee6ce51efdc02..89542d8229a0c 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } wasmi = { version = "0.9.1", optional = true } -wasmtime = { version = "0.38.0", default-features = false, optional = true } +wasmtime = { version = "0.40.1", default-features = false, optional = true } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] From 047853550b19efacf48fffc87077381bc6fb8bb5 Mon Sep 17 00:00:00 2001 From: Boluwatife Bakre Date: Thu, 8 Sep 2022 11:46:25 +0100 Subject: [PATCH 1138/1472] Use parameter_types instead of thread_local for test-setup (#12036) * Edit to Assets. parameter_types * fixes * Test Fixes. WIP * Edits to pallet-aura * Camel Case Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Implementation of mutate fn * update to pallet-aura * Update to frame-system. Fixes * Update to frame-support-test. CamelCases * Updates to frame- contracts, offences, staking, bounties, child bounties * Edit to mutate fn. Changes to frame-contracts. CamelCase pallet-aura * Edits to frame-contracts & executive * cargo +nightly fmt * unused import removed * unused import removed * cargo +nightly fmt * minor adjustment * updates * updates * cargo +nightly fmt * cargo +nightly fmt * take fn implemented * update * update * Fixes to CallFilter * cargo +nightly fmt * final fixes * Default changed to $value * Update frame/support/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/assets/src/mock.rs | 29 +-- frame/aura/src/mock.rs | 14 +- frame/bounties/src/tests.rs | 4 - frame/child-bounties/src/tests.rs | 4 - frame/contracts/src/exec.rs | 59 +++--- frame/contracts/src/storage/meter.rs | 183 ++++++++---------- frame/contracts/src/tests.rs | 45 +++-- .../election-provider-multi-phase/src/mock.rs | 3 +- frame/executive/src/lib.rs | 50 +++-- frame/im-online/src/mock.rs | 34 ++-- frame/im-online/src/tests.rs | 41 ++-- frame/merkle-mountain-range/src/mock.rs | 13 +- frame/merkle-mountain-range/src/tests.rs | 2 +- frame/offences/src/mock.rs | 15 +- frame/scheduler/src/mock.rs | 17 +- frame/scored-pool/src/mock.rs | 11 +- frame/scored-pool/src/tests.rs | 10 +- frame/session/src/historical/mod.rs | 10 +- frame/session/src/historical/offchain.rs | 11 +- frame/session/src/mock.rs | 87 +++++---- frame/session/src/tests.rs | 12 +- frame/staking/src/mock.rs | 9 +- frame/staking/src/tests.rs | 7 +- frame/support/src/lib.rs | 15 ++ frame/support/test/tests/construct_runtime.rs | 16 +- frame/system/src/mock.rs | 7 +- frame/system/src/tests.rs | 4 +- frame/timestamp/src/mock.rs | 11 +- frame/tips/src/tests.rs | 13 +- .../asset-tx-payment/src/tests.rs | 9 +- frame/transaction-payment/src/lib.rs | 30 ++- frame/treasury/src/tests.rs | 5 - 32 files changed, 378 insertions(+), 402 deletions(-) diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 0fd4dd3281516..5429c89084e78 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_assets; use frame_support::{ - construct_runtime, + construct_runtime, parameter_types, traits::{ConstU32, ConstU64, GenesisBuild}, }; use sp_core::H256; @@ -101,44 +101,49 @@ impl Config for Test { type Extra = (); } -use std::{cell::RefCell, collections::HashMap}; +use std::collections::HashMap; #[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub(crate) enum Hook { +pub enum Hook { Died(u32, u64), } -thread_local! { - static FROZEN: RefCell> = RefCell::new(Default::default()); - static HOOKS: RefCell> = RefCell::new(Default::default()); +parameter_types! { + static Frozen: HashMap<(u32, u64), u64> = Default::default(); + static Hooks: Vec = Default::default(); } pub struct TestFreezer; impl FrozenBalance for TestFreezer { fn frozen_balance(asset: u32, who: &u64) -> Option { - FROZEN.with(|f| f.borrow().get(&(asset, *who)).cloned()) + Frozen::get().get(&(asset, *who)).cloned() } fn died(asset: u32, who: &u64) { - HOOKS.with(|h| h.borrow_mut().push(Hook::Died(asset, *who))); + Hooks::mutate(|v| v.push(Hook::Died(asset, *who))); + // Sanity check: dead accounts have no balance. assert!(Assets::balance(asset, *who).is_zero()); } } pub(crate) fn set_frozen_balance(asset: u32, who: u64, amount: u64) { - FROZEN.with(|f| f.borrow_mut().insert((asset, who), amount)); + Frozen::mutate(|v| { + v.insert((asset, who), amount); + }); } pub(crate) fn clear_frozen_balance(asset: u32, who: u64) { - FROZEN.with(|f| f.borrow_mut().remove(&(asset, who))); + Frozen::mutate(|v| { + v.remove(&(asset, who)); + }); } pub(crate) fn hooks() -> Vec { - HOOKS.with(|h| h.borrow().clone()) + Hooks::get().clone() } pub(crate) fn take_hooks() -> Vec { - HOOKS.with(|h| h.take()) + Hooks::take() } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 5023feeaf8aea..5fa298bb008b0 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -30,7 +30,6 @@ use sp_runtime::{ testing::{Header, UintAuthorityId}, traits::IdentityLookup, }; -use sp_std::cell::RefCell; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -86,18 +85,17 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } -thread_local! { - static DISABLED_VALIDATORS: RefCell> = RefCell::new(Default::default()); +parameter_types! { + static DisabledValidatorTestValue: Vec = Default::default(); } pub struct MockDisabledValidators; impl MockDisabledValidators { pub fn disable_validator(index: AuthorityIndex) { - DISABLED_VALIDATORS.with(|v| { - let mut disabled = v.borrow_mut(); - if let Err(i) = disabled.binary_search(&index) { - disabled.insert(i, index); + DisabledValidatorTestValue::mutate(|v| { + if let Err(i) = v.binary_search(&index) { + v.insert(i, index); } }) } @@ -105,7 +103,7 @@ impl MockDisabledValidators { impl DisabledValidators for MockDisabledValidators { fn is_disabled(index: AuthorityIndex) -> bool { - DISABLED_VALIDATORS.with(|v| v.borrow().binary_search(&index).is_ok()) + DisabledValidatorTestValue::get().binary_search(&index).is_ok() } } diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index b4ce039b35fbc..cf4b8d23b0458 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -21,7 +21,6 @@ use super::*; use crate as pallet_bounties; -use std::cell::RefCell; use frame_support::{ assert_noop, assert_ok, @@ -102,9 +101,6 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); } -thread_local! { - static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); -} parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub static Burn: Permill = Permill::from_percent(50); diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index f42715f14bbee..0edee8468b86f 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -21,7 +21,6 @@ use super::*; use crate as pallet_child_bounties; -use std::cell::RefCell; use frame_support::{ assert_noop, assert_ok, @@ -105,9 +104,6 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); } -thread_local! { - static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); -} parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 4ae336a907001..f91be3a9e491c 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1376,7 +1376,7 @@ mod tests { }; use assert_matches::assert_matches; use codec::{Decode, Encode}; - use frame_support::{assert_err, assert_ok}; + use frame_support::{assert_err, assert_ok, parameter_types}; use frame_system::{EventRecord, Phase}; use hex_literal::hex; use pallet_contracts_primitives::ReturnFlags; @@ -1393,8 +1393,8 @@ mod tests { type MockStack<'a> = Stack<'a, Test, MockExecutable>; - thread_local! { - static LOADER: RefCell = RefCell::new(MockLoader::default()); + parameter_types! { + static Loader: MockLoader = MockLoader::default(); } fn events() -> Vec> { @@ -1420,8 +1420,8 @@ mod tests { refcount: u64, } - #[derive(Default)] - struct MockLoader { + #[derive(Default, Clone)] + pub struct MockLoader { map: HashMap, MockExecutable>, counter: u64, } @@ -1431,8 +1431,7 @@ mod tests { func_type: ExportedFunction, f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static, ) -> CodeHash { - LOADER.with(|loader| { - let mut loader = loader.borrow_mut(); + Loader::mutate(|loader| { // Generate code hashes as monotonically increasing values. let hash = ::Hash::from_low_u64_be(loader.counter); loader.counter += 1; @@ -1445,8 +1444,7 @@ mod tests { } fn increment_refcount(code_hash: CodeHash) -> Result<(), DispatchError> { - LOADER.with(|loader| { - let mut loader = loader.borrow_mut(); + Loader::mutate(|loader| { match loader.map.entry(code_hash) { Entry::Vacant(_) => Err(>::CodeNotFound)?, Entry::Occupied(mut entry) => entry.get_mut().refcount += 1, @@ -1457,8 +1455,7 @@ mod tests { fn decrement_refcount(code_hash: CodeHash) { use std::collections::hash_map::Entry::Occupied; - LOADER.with(|loader| { - let mut loader = loader.borrow_mut(); + Loader::mutate(|loader| { let mut entry = match loader.map.entry(code_hash) { Occupied(e) => e, _ => panic!("code_hash does not exist"), @@ -1478,13 +1475,8 @@ mod tests { _schedule: &Schedule, _gas_meter: &mut GasMeter, ) -> Result { - LOADER.with(|loader| { - loader - .borrow_mut() - .map - .get(&code_hash) - .cloned() - .ok_or(Error::::CodeNotFound.into()) + Loader::mutate(|loader| { + loader.map.get(&code_hash).cloned().ok_or(Error::::CodeNotFound.into()) }) } @@ -1531,14 +1523,14 @@ mod tests { #[test] fn it_works() { - thread_local! { - static TEST_DATA: RefCell> = RefCell::new(vec![0]); + parameter_types! { + static TestData: Vec = vec![0]; } let value = Default::default(); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let exec_ch = MockLoader::insert(Call, |_ctx, _executable| { - TEST_DATA.with(|data| data.borrow_mut().push(1)); + TestData::mutate(|data| data.push(1)); exec_success() }); @@ -1562,7 +1554,7 @@ mod tests { ); }); - TEST_DATA.with(|data| assert_eq!(*data.borrow(), vec![0, 1])); + assert_eq!(TestData::get(), vec![0, 1]); } #[test] @@ -1841,16 +1833,15 @@ mod tests { fn max_depth() { // This test verifies that when we reach the maximal depth creation of an // yet another context fails. - thread_local! { - static REACHED_BOTTOM: RefCell = RefCell::new(false); + parameter_types! { + static ReachedBottom: bool = false; } let value = Default::default(); let recurse_ch = MockLoader::insert(Call, |ctx, _| { // Try to call into yourself. let r = ctx.ext.call(Weight::zero(), BOB, 0, vec![], true); - REACHED_BOTTOM.with(|reached_bottom| { - let mut reached_bottom = reached_bottom.borrow_mut(); + ReachedBottom::mutate(|reached_bottom| { if !*reached_bottom { // We are first time here, it means we just reached bottom. // Verify that we've got proper error and set `reached_bottom`. @@ -1891,15 +1882,14 @@ mod tests { let origin = ALICE; let dest = BOB; - thread_local! { - static WITNESSED_CALLER_BOB: RefCell>> = RefCell::new(None); - static WITNESSED_CALLER_CHARLIE: RefCell>> = RefCell::new(None); + parameter_types! { + static WitnessedCallerBob: Option> = None; + static WitnessedCallerCharlie: Option> = None; } let bob_ch = MockLoader::insert(Call, |ctx, _| { // Record the caller for bob. - WITNESSED_CALLER_BOB - .with(|caller| *caller.borrow_mut() = Some(ctx.ext.caller().clone())); + WitnessedCallerBob::mutate(|caller| *caller = Some(ctx.ext.caller().clone())); // Call into CHARLIE contract. assert_matches!(ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], true), Ok(_)); @@ -1907,8 +1897,7 @@ mod tests { }); let charlie_ch = MockLoader::insert(Call, |ctx, _| { // Record the caller for charlie. - WITNESSED_CALLER_CHARLIE - .with(|caller| *caller.borrow_mut() = Some(ctx.ext.caller().clone())); + WitnessedCallerCharlie::mutate(|caller| *caller = Some(ctx.ext.caller().clone())); exec_success() }); @@ -1932,8 +1921,8 @@ mod tests { assert_matches!(result, Ok(_)); }); - WITNESSED_CALLER_BOB.with(|caller| assert_eq!(*caller.borrow(), Some(origin))); - WITNESSED_CALLER_CHARLIE.with(|caller| assert_eq!(*caller.borrow(), Some(dest))); + assert_eq!(WitnessedCallerBob::get(), Some(origin)); + assert_eq!(WitnessedCallerCharlie::get(), Some(dest)); } #[test] diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index b06f7ea4aedb5..d89208812bcac 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -441,23 +441,23 @@ mod tests { exec::AccountIdOf, tests::{Test, ALICE, BOB, CHARLIE}, }; + use frame_support::parameter_types; use pretty_assertions::assert_eq; - use std::cell::RefCell; type TestMeter = RawMeter; - thread_local! { - static TEST_EXT: RefCell = RefCell::new(Default::default()); + parameter_types! { + static TestExtTestValue: TestExt = Default::default(); } - #[derive(Debug, PartialEq, Eq)] + #[derive(Debug, PartialEq, Eq, Clone)] struct LimitCheck { origin: AccountIdOf, limit: BalanceOf, min_leftover: BalanceOf, } - #[derive(Debug, PartialEq, Eq)] + #[derive(Debug, PartialEq, Eq, Clone)] struct Charge { origin: AccountIdOf, contract: AccountIdOf, @@ -465,8 +465,8 @@ mod tests { terminated: bool, } - #[derive(Default, Debug, PartialEq, Eq)] - struct TestExt { + #[derive(Default, Debug, PartialEq, Eq, Clone)] + pub struct TestExt { limit_checks: Vec, charges: Vec, } @@ -485,12 +485,9 @@ mod tests { min_leftover: BalanceOf, ) -> Result, DispatchError> { let limit = limit.unwrap_or(42); - TEST_EXT.with(|ext| { - ext.borrow_mut().limit_checks.push(LimitCheck { - origin: origin.clone(), - limit, - min_leftover, - }) + TestExtTestValue::mutate(|ext| { + ext.limit_checks + .push(LimitCheck { origin: origin.clone(), limit, min_leftover }) }); Ok(limit) } @@ -501,8 +498,8 @@ mod tests { amount: &DepositOf, terminated: bool, ) { - TEST_EXT.with(|ext| { - ext.borrow_mut().charges.push(Charge { + TestExtTestValue::mutate(|ext| { + ext.charges.push(Charge { origin: origin.clone(), contract: contract.clone(), amount: amount.clone(), @@ -513,7 +510,7 @@ mod tests { } fn clear_ext() { - TEST_EXT.with(|ext| ext.borrow_mut().clear()) + TestExtTestValue::mutate(|ext| ext.clear()) } fn new_info(deposit: BalanceOf) -> ContractInfo { @@ -533,15 +530,13 @@ mod tests { TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); - TEST_EXT.with(|ext| { - assert_eq!( - *ext.borrow(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - ..Default::default() - } - ) - }); + assert_eq!( + TestExtTestValue::get(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + ..Default::default() + } + ) } #[test] @@ -556,15 +551,13 @@ mod tests { nested0.charge(&Default::default()).unwrap(); meter.absorb(nested0, &ALICE, &BOB, None); - TEST_EXT.with(|ext| { - assert_eq!( - *ext.borrow(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - ..Default::default() - } - ) - }); + assert_eq!( + TestExtTestValue::get(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + ..Default::default() + } + ) } #[test] @@ -582,20 +575,18 @@ mod tests { .unwrap(); meter.absorb(nested0, &ALICE, &BOB, None); - TEST_EXT.with(|ext| { - assert_eq!( - *ext.borrow(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - charges: vec![Charge { - origin: ALICE, - contract: BOB, - amount: Deposit::Charge(::Currency::minimum_balance() * 2), - terminated: false, - }] - } - ) - }); + assert_eq!( + TestExtTestValue::get(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + charges: vec![Charge { + origin: ALICE, + contract: BOB, + amount: Deposit::Charge(::Currency::minimum_balance() * 2), + terminated: false, + }] + } + ) } #[test] @@ -638,34 +629,32 @@ mod tests { assert_eq!(nested1_info.storage_deposit, 40); assert_eq!(nested2_info.storage_deposit, min_balance); - TEST_EXT.with(|ext| { - assert_eq!( - *ext.borrow(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - charges: vec![ - Charge { - origin: ALICE, - contract: CHARLIE, - amount: Deposit::Refund(10), - terminated: false - }, - Charge { - origin: ALICE, - contract: CHARLIE, - amount: Deposit::Refund(4), - terminated: false - }, - Charge { - origin: ALICE, - contract: BOB, - amount: Deposit::Charge(2), - terminated: false - } - ] - } - ) - }); + assert_eq!( + TestExtTestValue::get(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + charges: vec![ + Charge { + origin: ALICE, + contract: CHARLIE, + amount: Deposit::Refund(10), + terminated: false + }, + Charge { + origin: ALICE, + contract: CHARLIE, + amount: Deposit::Refund(4), + terminated: false + }, + Charge { + origin: ALICE, + contract: BOB, + amount: Deposit::Charge(2), + terminated: false + } + ] + } + ) } #[test] @@ -697,27 +686,25 @@ mod tests { meter.absorb(nested0, &ALICE, &BOB, None); drop(meter); - TEST_EXT.with(|ext| { - assert_eq!( - *ext.borrow(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - charges: vec![ - Charge { - origin: ALICE, - contract: CHARLIE, - amount: Deposit::Refund(400), - terminated: true - }, - Charge { - origin: ALICE, - contract: BOB, - amount: Deposit::Charge(12), - terminated: false - } - ] - } - ) - }); + assert_eq!( + TestExtTestValue::get(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + charges: vec![ + Charge { + origin: ALICE, + contract: CHARLIE, + amount: Deposit::Refund(400), + terminated: true + }, + Charge { + origin: ALICE, + contract: BOB, + amount: Deposit::Charge(12), + terminated: false + } + ] + } + ) } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index f65f845f7b9fe..8bca18c5d1c42 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -51,7 +51,7 @@ use sp_runtime::{ traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, AccountId32, }; -use std::{cell::RefCell, sync::Arc}; +use std::sync::Arc; use crate as pallet_contracts; @@ -113,10 +113,11 @@ pub mod test_utils { } } -thread_local! { - static TEST_EXTENSION: RefCell = Default::default(); +parameter_types! { + static TestExtensionTestValue: TestExtension = Default::default(); } +#[derive(Clone)] pub struct TestExtension { enabled: bool, last_seen_buffer: Vec, @@ -136,15 +137,15 @@ pub struct TempStorageExtension { impl TestExtension { fn disable() { - TEST_EXTENSION.with(|e| e.borrow_mut().enabled = false) + TestExtensionTestValue::mutate(|e| e.enabled = false) } fn last_seen_buffer() -> Vec { - TEST_EXTENSION.with(|e| e.borrow().last_seen_buffer.clone()) + TestExtensionTestValue::get().last_seen_buffer.clone() } fn last_seen_inputs() -> (u32, u32, u32, u32) { - TEST_EXTENSION.with(|e| e.borrow().last_seen_inputs) + TestExtensionTestValue::get().last_seen_inputs } } @@ -167,14 +168,13 @@ impl ChainExtension for TestExtension { let mut env = env.buf_in_buf_out(); let input = env.read(8)?; env.write(&input, false, None)?; - TEST_EXTENSION.with(|e| e.borrow_mut().last_seen_buffer = input); + TestExtensionTestValue::mutate(|e| e.last_seen_buffer = input); Ok(RetVal::Converging(id)) }, 0x8001 => { let env = env.only_in(); - TEST_EXTENSION.with(|e| { - e.borrow_mut().last_seen_inputs = - (env.val0(), env.val1(), env.val2(), env.val3()) + TestExtensionTestValue::mutate(|e| { + e.last_seen_inputs = (env.val0(), env.val1(), env.val2(), env.val3()) }); Ok(RetVal::Converging(id)) }, @@ -192,7 +192,7 @@ impl ChainExtension for TestExtension { } fn enabled() -> bool { - TEST_EXTENSION.with(|e| e.borrow().enabled) + TestExtensionTestValue::get().enabled } } @@ -210,7 +210,7 @@ impl ChainExtension for RevertingExtension { } fn enabled() -> bool { - TEST_EXTENSION.with(|e| e.borrow().enabled) + TestExtensionTestValue::get().enabled } } @@ -259,7 +259,7 @@ impl ChainExtension for TempStorageExtension { } fn enabled() -> bool { - TEST_EXTENSION.with(|e| e.borrow().enabled) + TestExtensionTestValue::get().enabled } } @@ -344,19 +344,30 @@ impl Convert> for Test { /// A filter whose filter function can be swapped at runtime. pub struct TestFilter; -thread_local! { - static CALL_FILTER: RefCell bool> = RefCell::new(|_| true); +#[derive(Clone)] +pub struct Filters { + filter: fn(&Call) -> bool, +} + +impl Default for Filters { + fn default() -> Self { + Filters { filter: (|_| true) } + } +} + +parameter_types! { + static CallFilter: Filters = Default::default(); } impl TestFilter { pub fn set_filter(filter: fn(&Call) -> bool) { - CALL_FILTER.with(|fltr| *fltr.borrow_mut() = filter); + CallFilter::mutate(|fltr| fltr.filter = filter); } } impl Contains for TestFilter { fn contains(call: &Call) -> bool { - CALL_FILTER.with(|fltr| fltr.borrow()(call)) + (CallFilter::get().filter)(call) } } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 48b76bbb98a8f..4e9672fc1d4f6 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -241,8 +241,9 @@ impl pallet_balances::Config for Runtime { type WeightInfo = (); } -#[derive(Eq, PartialEq, Debug, Clone, Copy)] +#[derive(Default, Eq, PartialEq, Debug, Clone, Copy)] pub enum MockedWeightInfo { + #[default] Basic, Complex, Real, diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 87ed8b93bbf8e..b23342800f8b9 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -835,12 +835,12 @@ mod tests { pub struct RuntimeVersion; impl frame_support::traits::Get for RuntimeVersion { fn get() -> sp_version::RuntimeVersion { - RUNTIME_VERSION.with(|v| v.borrow().clone()) + RuntimeVersionTestValues::get().clone() } } - thread_local! { - pub static RUNTIME_VERSION: std::cell::RefCell = + parameter_types! { + pub static RuntimeVersionTestValues: sp_version::RuntimeVersion = Default::default(); } @@ -1239,14 +1239,13 @@ mod tests { #[test] fn runtime_upgraded_should_work() { new_test_ext(1).execute_with(|| { - RUNTIME_VERSION.with(|v| *v.borrow_mut() = Default::default()); + RuntimeVersionTestValues::mutate(|v| *v = Default::default()); // It should be added at genesis assert!(frame_system::LastRuntimeUpgrade::::exists()); assert!(!Executive::runtime_upgraded()); - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); assert!(Executive::runtime_upgraded()); assert_eq!( @@ -1254,8 +1253,8 @@ mod tests { frame_system::LastRuntimeUpgrade::::get(), ); - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = sp_version::RuntimeVersion { + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, spec_name: "test".into(), ..Default::default() @@ -1267,8 +1266,8 @@ mod tests { frame_system::LastRuntimeUpgrade::::get(), ); - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = sp_version::RuntimeVersion { + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, spec_name: "test".into(), impl_version: 2, @@ -1316,9 +1315,8 @@ mod tests { fn custom_runtime_upgrade_is_called_before_modules() { new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called. - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); Executive::initialize_block(&Header::new( @@ -1338,9 +1336,8 @@ mod tests { fn event_from_runtime_upgrade_is_included() { new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called. - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); // set block number to non zero so events are not excluded @@ -1369,9 +1366,8 @@ mod tests { let header = new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called. - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); // Let's build some fake block. @@ -1389,15 +1385,14 @@ mod tests { }); // Reset to get the correct new genesis below. - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = sp_version::RuntimeVersion { spec_version: 0, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 0, ..Default::default() } }); new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called. - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); >>::execute_block(Block::new(header, vec![xt])); @@ -1411,9 +1406,8 @@ mod tests { fn all_weights_are_recorded_correctly() { new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called for maximum complexity - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); let block_number = 1; diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index b734bd37b6fd4..6ea5a16d64f58 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -19,8 +19,6 @@ #![cfg(test)] -use std::cell::RefCell; - use frame_support::{ parameter_types, traits::{ConstU32, ConstU64}, @@ -57,18 +55,18 @@ frame_support::construct_runtime!( } ); -thread_local! { - pub static VALIDATORS: RefCell>> = RefCell::new(Some(vec![ +parameter_types! { + pub static Validators: Option> = Some(vec![ 1, 2, 3, - ])); + ]); } pub struct TestSessionManager; impl pallet_session::SessionManager for TestSessionManager { fn new_session(_new_index: SessionIndex) -> Option> { - VALIDATORS.with(|l| l.borrow_mut().take()) + Validators::mutate(|l| l.take()) } fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} @@ -76,10 +74,8 @@ impl pallet_session::SessionManager for TestSessionManager { impl pallet_session::historical::SessionManager for TestSessionManager { fn new_session(_new_index: SessionIndex) -> Option> { - VALIDATORS.with(|l| { - l.borrow_mut() - .take() - .map(|validators| validators.iter().map(|v| (*v, *v)).collect()) + Validators::mutate(|l| { + l.take().map(|validators| validators.iter().map(|v| (*v, *v)).collect()) }) } fn end_session(_: SessionIndex) {} @@ -91,15 +87,15 @@ pub type Extrinsic = TestXt; type IdentificationTuple = (u64, u64); type Offence = crate::UnresponsivenessOffence; -thread_local! { - pub static OFFENCES: RefCell, Offence)>> = RefCell::new(vec![]); +parameter_types! { + pub static Offences: Vec<(Vec, Offence)> = vec![]; } /// A mock offence report handler. pub struct OffenceHandler; impl ReportOffence for OffenceHandler { fn report_offence(reporters: Vec, offence: Offence) -> Result<(), OffenceError> { - OFFENCES.with(|l| l.borrow_mut().push((reporters, offence))); + Offences::mutate(|l| l.push((reporters, offence))); Ok(()) } @@ -183,12 +179,12 @@ impl pallet_authorship::Config for Runtime { type EventHandler = ImOnline; } -thread_local! { - pub static MOCK_CURRENT_SESSION_PROGRESS: RefCell>> = RefCell::new(None); +parameter_types! { + pub static MockCurrentSessionProgress: Option> = None; } -thread_local! { - pub static MOCK_AVERAGE_SESSION_LENGTH: RefCell> = RefCell::new(None); +parameter_types! { + pub static MockAverageSessionLength: Option = None; } pub struct TestNextSessionRotation; @@ -196,7 +192,7 @@ pub struct TestNextSessionRotation; impl frame_support::traits::EstimateNextSessionRotation for TestNextSessionRotation { fn average_session_length() -> u64 { // take the mock result if any and return it - let mock = MOCK_AVERAGE_SESSION_LENGTH.with(|p| p.borrow_mut().take()); + let mock = MockAverageSessionLength::mutate(|p| p.take()); mock.unwrap_or(pallet_session::PeriodicSessions::::average_session_length()) } @@ -208,7 +204,7 @@ impl frame_support::traits::EstimateNextSessionRotation for TestNextSession ); // take the mock result if any and return it - let mock = MOCK_CURRENT_SESSION_PROGRESS.with(|p| p.borrow_mut().take()); + let mock = MockCurrentSessionProgress::mutate(|p| p.take()); (mock.unwrap_or(estimate), weight) } diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index 05e1af169dba9..6ef7cce7c353b 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -68,7 +68,7 @@ fn should_report_offline_validators() { advance_session(); // enact the change and buffer another one let validators = vec![1, 2, 3, 4, 5, 6]; - VALIDATORS.with(|l| *l.borrow_mut() = Some(validators.clone())); + Validators::mutate(|l| *l = Some(validators.clone())); advance_session(); // when @@ -76,7 +76,7 @@ fn should_report_offline_validators() { advance_session(); // then - let offences = OFFENCES.with(|l| l.replace(vec![])); + let offences = Offences::take(); assert_eq!( offences, vec![( @@ -96,7 +96,7 @@ fn should_report_offline_validators() { advance_session(); // then - let offences = OFFENCES.with(|l| l.replace(vec![])); + let offences = Offences::take(); assert_eq!( offences, vec![( @@ -149,7 +149,7 @@ fn should_mark_online_validator_when_heartbeat_is_received() { new_test_ext().execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3, 4, 5, 6])); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -184,7 +184,7 @@ fn late_heartbeat_and_invalid_keys_len_should_fail() { new_test_ext().execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3, 4, 5, 6])); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -226,7 +226,7 @@ fn should_generate_heartbeats() { // buffer new validators Session::rotate_session(); // enact the change and buffer another one - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3, 4, 5, 6])); Session::rotate_session(); // when @@ -262,7 +262,7 @@ fn should_cleanup_received_heartbeats_on_session_end() { new_test_ext().execute_with(|| { advance_session(); - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3])); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one @@ -293,7 +293,7 @@ fn should_mark_online_validator_when_block_is_authored() { new_test_ext().execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3, 4, 5, 6])); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -330,7 +330,7 @@ fn should_not_send_a_report_if_already_online() { ext.execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3, 4, 5, 6])); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -393,12 +393,12 @@ fn should_handle_missing_progress_estimates() { Session::rotate_session(); // enact the change and buffer another one - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![0, 1, 2])); + Validators::mutate(|l| *l = Some(vec![0, 1, 2])); Session::rotate_session(); // we will return `None` on the next call to `estimate_current_session_progress` // and the offchain worker should fallback to checking `HeartbeatAfter` - MOCK_CURRENT_SESSION_PROGRESS.with(|p| *p.borrow_mut() = Some(None)); + MockCurrentSessionProgress::mutate(|p| *p = Some(None)); ImOnline::offchain_worker(block); assert_eq!(state.read().transactions.len(), 3); @@ -427,26 +427,25 @@ fn should_handle_non_linear_session_progress() { // mock the session length as being 10 blocks long, // enact the change and buffer another one - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![0, 1, 2])); + Validators::mutate(|l| *l = Some(vec![0, 1, 2])); // mock the session length has being 10 which should make us assume the fallback for half // session will be reached by block 5. - MOCK_AVERAGE_SESSION_LENGTH.with(|p| *p.borrow_mut() = Some(10)); + MockAverageSessionLength::mutate(|p| *p = Some(10)); Session::rotate_session(); // if we don't have valid results for the current session progres then // we'll fallback to `HeartbeatAfter` and only heartbeat on block 5. - MOCK_CURRENT_SESSION_PROGRESS.with(|p| *p.borrow_mut() = Some(None)); + MockCurrentSessionProgress::mutate(|p| *p = Some(None)); assert_eq!(ImOnline::send_heartbeats(2).err(), Some(OffchainErr::TooEarly)); - MOCK_CURRENT_SESSION_PROGRESS.with(|p| *p.borrow_mut() = Some(None)); + MockCurrentSessionProgress::mutate(|p| *p = Some(None)); assert!(ImOnline::send_heartbeats(5).ok().is_some()); // if we have a valid current session progress then we'll heartbeat as soon // as we're past 80% of the session regardless of the block number - MOCK_CURRENT_SESSION_PROGRESS - .with(|p| *p.borrow_mut() = Some(Some(Permill::from_percent(81)))); + MockCurrentSessionProgress::mutate(|p| *p = Some(Some(Permill::from_percent(81)))); assert!(ImOnline::send_heartbeats(2).ok().is_some()); }); @@ -464,8 +463,7 @@ fn test_does_not_heartbeat_early_in_the_session() { ext.execute_with(|| { // mock current session progress as being 5%. we only randomly start // heartbeating after 10% of the session has elapsed. - MOCK_CURRENT_SESSION_PROGRESS - .with(|p| *p.borrow_mut() = Some(Some(Permill::from_float(0.05)))); + MockCurrentSessionProgress::mutate(|p| *p = Some(Some(Permill::from_float(0.05)))); assert_eq!(ImOnline::send_heartbeats(2).err(), Some(OffchainErr::TooEarly)); }); } @@ -483,9 +481,8 @@ fn test_probability_of_heartbeating_increases_with_session_progress() { let set_test = |progress, random: f64| { // the average session length is 100 blocks, therefore the residual // probability of sending a heartbeat is 1% - MOCK_AVERAGE_SESSION_LENGTH.with(|p| *p.borrow_mut() = Some(100)); - MOCK_CURRENT_SESSION_PROGRESS - .with(|p| *p.borrow_mut() = Some(Some(Permill::from_float(progress)))); + MockAverageSessionLength::mutate(|p| *p = Some(100)); + MockCurrentSessionProgress::mutate(|p| *p = Some(Some(Permill::from_float(progress)))); let mut seed = [0u8; 32]; let encoded = ((random * Permill::ACCURACY as f64) as u32).encode(); diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index b2b6821fcd054..30dd6da3d3b8d 100644 --- a/frame/merkle-mountain-range/src/mock.rs +++ b/frame/merkle-mountain-range/src/mock.rs @@ -19,14 +19,17 @@ use crate as pallet_mmr; use crate::*; use codec::{Decode, Encode}; -use frame_support::traits::{ConstU32, ConstU64}; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, +}; use sp_core::H256; use sp_mmr_primitives::{Compact, LeafDataProvider}; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup, Keccak256}, }; -use sp_std::{cell::RefCell, prelude::*}; +use sp_std::prelude::*; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -91,14 +94,14 @@ impl LeafData { } } -thread_local! { - pub static LEAF_DATA: RefCell = RefCell::new(Default::default()); +parameter_types! { + pub static LeafDataTestValue: LeafData = Default::default(); } impl LeafDataProvider for LeafData { type LeafData = Self; fn leaf_data() -> Self::LeafData { - LEAF_DATA.with(|r| r.borrow().clone()) + LeafDataTestValue::get().clone() } } diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index e13f89617bb9a..d6886f90a5da7 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -42,7 +42,7 @@ fn register_offchain_ext(ext: &mut sp_io::TestExternalities) { fn new_block() -> Weight { let number = frame_system::Pallet::::block_number() + 1; let hash = H256::repeat_byte(number as u8); - LEAF_DATA.with(|r| r.borrow_mut().a = number); + LeafDataTestValue::mutate(|r| r.a = number); frame_system::Pallet::::reset_events(); frame_system::Pallet::::initialize(&number, &hash, &Default::default()); diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index a578a6082cf3e..bf4daf0c89944 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -40,13 +40,12 @@ use sp_staking::{ offence::{self, DisableStrategy, Kind, OffenceDetails}, SessionIndex, }; -use std::cell::RefCell; pub struct OnOffenceHandler; -thread_local! { - pub static ON_OFFENCE_PERBILL: RefCell> = RefCell::new(Default::default()); - pub static OFFENCE_WEIGHT: RefCell = RefCell::new(Default::default()); +parameter_types! { + pub static OnOffencePerbill: Vec = Default::default(); + pub static OffenceWeight: Weight = Default::default(); } impl offence::OnOffenceHandler @@ -58,16 +57,16 @@ impl offence::OnOffenceHandler _offence_session: SessionIndex, _disable_strategy: DisableStrategy, ) -> Weight { - ON_OFFENCE_PERBILL.with(|f| { - *f.borrow_mut() = slash_fraction.to_vec(); + OnOffencePerbill::mutate(|f| { + *f = slash_fraction.to_vec(); }); - OFFENCE_WEIGHT.with(|w| *w.borrow()) + OffenceWeight::get() } } pub fn with_on_offence_fractions) -> R>(f: F) -> R { - ON_OFFENCE_PERBILL.with(|fractions| f(&mut fractions.borrow_mut())) + OnOffencePerbill::mutate(|fractions| f(fractions)) } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 7bbc628604bc6..1639c9a046142 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -39,15 +39,14 @@ use sp_runtime::{ #[frame_support::pallet] pub mod logger { use super::{OriginCaller, OriginTrait}; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, parameter_types}; use frame_system::pallet_prelude::*; - use std::cell::RefCell; - thread_local! { - static LOG: RefCell> = RefCell::new(Vec::new()); + parameter_types! { + static Log: Vec<(OriginCaller, u32)> = Vec::new(); } pub fn log() -> Vec<(OriginCaller, u32)> { - LOG.with(|log| log.borrow().clone()) + Log::get().clone() } #[pallet::pallet] @@ -76,8 +75,8 @@ pub mod logger { #[pallet::weight(*weight)] pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { Self::deposit_event(Event::Logged(i, weight)); - LOG.with(|log| { - log.borrow_mut().push((origin.caller().clone(), i)); + Log::mutate(|log| { + log.push((origin.caller().clone(), i)); }); Ok(()) } @@ -85,8 +84,8 @@ pub mod logger { #[pallet::weight(*weight)] pub fn log_without_filter(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { Self::deposit_event(Event::Logged(i, weight)); - LOG.with(|log| { - log.borrow_mut().push((origin.caller().clone(), i)); + Log::mutate(|log| { + log.push((origin.caller().clone(), i)); }); Ok(()) } diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index e38e0a18b99c8..00c66c3bdefe8 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -30,7 +30,6 @@ use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, }; -use std::cell::RefCell; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -96,14 +95,14 @@ impl pallet_balances::Config for Test { type WeightInfo = (); } -thread_local! { - pub static MEMBERS: RefCell> = RefCell::new(vec![]); +parameter_types! { + pub static MembersTestValue: Vec = vec![]; } pub struct TestChangeMembers; impl ChangeMembers for TestChangeMembers { fn change_members_sorted(incoming: &[u64], outgoing: &[u64], new: &[u64]) { - let mut old_plus_incoming = MEMBERS.with(|m| m.borrow().to_vec()); + let mut old_plus_incoming = MembersTestValue::get().to_vec(); old_plus_incoming.extend_from_slice(incoming); old_plus_incoming.sort(); @@ -113,13 +112,13 @@ impl ChangeMembers for TestChangeMembers { assert_eq!(old_plus_incoming, new_plus_outgoing); - MEMBERS.with(|m| *m.borrow_mut() = new.to_vec()); + MembersTestValue::mutate(|m| *m = new.to_vec()); } } impl InitializeMembers for TestChangeMembers { fn initialize_members(new_members: &[u64]) { - MEMBERS.with(|m| *m.borrow_mut() = new_members.to_vec()); + MembersTestValue::mutate(|m| *m = new_members.to_vec()); } } diff --git a/frame/scored-pool/src/tests.rs b/frame/scored-pool/src/tests.rs index 7b431160ddfe5..42f0b47e8b940 100644 --- a/frame/scored-pool/src/tests.rs +++ b/frame/scored-pool/src/tests.rs @@ -33,7 +33,7 @@ fn query_membership_works() { assert_eq!(ScoredPool::members(), vec![20, 40]); assert_eq!(Balances::reserved_balance(31), CandidateDeposit::get()); assert_eq!(Balances::reserved_balance(40), CandidateDeposit::get()); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), vec![20, 40]); + assert_eq!(MembersTestValue::get().clone(), vec![20, 40]); }); } @@ -128,7 +128,7 @@ fn kicking_works() { // then assert_eq!(find_in_pool(who), None); assert_eq!(ScoredPool::members(), vec![20, 31]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), ScoredPool::members()); + assert_eq!(MembersTestValue::get().clone(), ScoredPool::members()); assert_eq!(Balances::reserved_balance(who), 0); // deposit must have been returned }); } @@ -152,7 +152,7 @@ fn unscored_entities_must_not_be_used_for_filling_members() { // then // the `None` candidates should not have been filled in assert!(ScoredPool::members().is_empty()); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), ScoredPool::members()); + assert_eq!(MembersTestValue::get().clone(), ScoredPool::members()); }); } @@ -170,7 +170,7 @@ fn refreshing_works() { // then assert_eq!(ScoredPool::members(), vec![15, 40]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), ScoredPool::members()); + assert_eq!(MembersTestValue::get().clone(), ScoredPool::members()); }); } @@ -190,7 +190,7 @@ fn refreshing_happens_every_period() { // then assert_eq!(ScoredPool::members(), vec![15, 40]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), ScoredPool::members()); + assert_eq!(MembersTestValue::get().clone(), ScoredPool::members()); }); } diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index c72ab8c210d69..45b4ba3c0a799 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -375,7 +375,7 @@ impl> KeyOwnerProofSystem<(KeyTypeId, D)> for Pallet sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let keys: Vec<_> = NEXT_VALIDATORS.with(|l| { - l.borrow().iter().cloned().map(|i| (i, i, UintAuthorityId(i).into())).collect() - }); + let keys: Vec<_> = NextValidators::get() + .iter() + .cloned() + .map(|i| (i, i, UintAuthorityId(i).into())) + .collect(); BasicExternalities::execute_with_storage(&mut t, || { for (ref k, ..) in &keys { frame_system::Pallet::::inc_providers(k); diff --git a/frame/session/src/historical/offchain.rs b/frame/session/src/historical/offchain.rs index 95813d0a70272..ececb8af5ad58 100644 --- a/frame/session/src/historical/offchain.rs +++ b/frame/session/src/historical/offchain.rs @@ -141,7 +141,7 @@ mod tests { use super::*; use crate::{ historical::{onchain, Pallet}, - mock::{force_new_session, set_next_validators, Session, System, Test, NEXT_VALIDATORS}, + mock::{force_new_session, set_next_validators, NextValidators, Session, System, Test}, }; use codec::Encode; @@ -163,9 +163,12 @@ mod tests { .build_storage::() .expect("Failed to create test externalities."); - let keys: Vec<_> = NEXT_VALIDATORS.with(|l| { - l.borrow().iter().cloned().map(|i| (i, i, UintAuthorityId(i).into())).collect() - }); + let keys: Vec<_> = NextValidators::get() + .iter() + .cloned() + .map(|i| (i, i, UintAuthorityId(i).into())) + .collect(); + BasicExternalities::execute_with_storage(&mut t, || { for (ref k, ..) in &keys { frame_system::Pallet::::inc_providers(k); diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index 3044d6558e33e..c1858d0bff774 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -22,7 +22,7 @@ use crate as pallet_session; #[cfg(feature = "historical")] use crate::historical as pallet_session_historical; -use std::{cell::RefCell, collections::BTreeMap}; +use std::collections::BTreeMap; use sp_core::{crypto::key_types::DUMMY, H256}; use sp_runtime::{ @@ -103,29 +103,29 @@ frame_support::construct_runtime!( } ); -thread_local! { - pub static VALIDATORS: RefCell> = RefCell::new(vec![1, 2, 3]); - pub static NEXT_VALIDATORS: RefCell> = RefCell::new(vec![1, 2, 3]); - pub static AUTHORITIES: RefCell> = - RefCell::new(vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); - pub static FORCE_SESSION_END: RefCell = RefCell::new(false); - pub static SESSION_LENGTH: RefCell = RefCell::new(2); - pub static SESSION_CHANGED: RefCell = RefCell::new(false); - pub static TEST_SESSION_CHANGED: RefCell = RefCell::new(false); - pub static DISABLED: RefCell = RefCell::new(false); +parameter_types! { + pub static Validators: Vec = vec![1, 2, 3]; + pub static NextValidators: Vec = vec![1, 2, 3]; + pub static Authorities: Vec = + vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]; + pub static ForceSessionEnd: bool = false; + pub static SessionLength: u64 = 2; + pub static SessionChanged: bool = false; + pub static TestSessionChanged: bool = false; + pub static Disabled: bool = false; // Stores if `on_before_session_end` was called - pub static BEFORE_SESSION_END_CALLED: RefCell = RefCell::new(false); - pub static VALIDATOR_ACCOUNTS: RefCell> = RefCell::new(BTreeMap::new()); + pub static BeforeSessionEndCalled: bool = false; + pub static ValidatorAccounts: BTreeMap = BTreeMap::new(); } pub struct TestShouldEndSession; impl ShouldEndSession for TestShouldEndSession { fn should_end_session(now: u64) -> bool { - let l = SESSION_LENGTH.with(|l| *l.borrow()); + let l = SessionLength::get(); now % l == 0 || - FORCE_SESSION_END.with(|l| { - let r = *l.borrow(); - *l.borrow_mut() = false; + ForceSessionEnd::mutate(|l| { + let r = *l; + *l = false; r }) } @@ -140,19 +140,19 @@ impl SessionHandler for TestSessionHandler { validators: &[(u64, T)], _queued_validators: &[(u64, T)], ) { - SESSION_CHANGED.with(|l| *l.borrow_mut() = changed); - AUTHORITIES.with(|l| { - *l.borrow_mut() = validators + SessionChanged::mutate(|l| *l = changed); + Authorities::mutate(|l| { + *l = validators .iter() .map(|(_, id)| id.get::(DUMMY).unwrap_or_default()) .collect() }); } fn on_disabled(_validator_index: u32) { - DISABLED.with(|l| *l.borrow_mut() = true) + Disabled::mutate(|l| *l = true) } fn on_before_session_ending() { - BEFORE_SESSION_END_CALLED.with(|b| *b.borrow_mut() = true); + BeforeSessionEndCalled::mutate(|b| *b = true); } } @@ -161,16 +161,15 @@ impl SessionManager for TestSessionManager { fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} fn new_session(_: SessionIndex) -> Option> { - if !TEST_SESSION_CHANGED.with(|l| *l.borrow()) { - VALIDATORS.with(|v| { - let mut v = v.borrow_mut(); - *v = NEXT_VALIDATORS.with(|l| l.borrow().clone()); + if !TestSessionChanged::get() { + Validators::mutate(|v| { + *v = NextValidators::get().clone(); Some(v.clone()) }) - } else if DISABLED.with(|l| std::mem::replace(&mut *l.borrow_mut(), false)) { + } else if Disabled::mutate(|l| std::mem::replace(&mut *l, false)) { // If there was a disabled validator, underlying conditions have changed // so we return `Some`. - Some(VALIDATORS.with(|v| v.borrow().clone())) + Some(Validators::get().clone()) } else { None } @@ -188,37 +187,40 @@ impl crate::historical::SessionManager for TestSessionManager { } pub fn authorities() -> Vec { - AUTHORITIES.with(|l| l.borrow().to_vec()) + Authorities::get().to_vec() } pub fn force_new_session() { - FORCE_SESSION_END.with(|l| *l.borrow_mut() = true) + ForceSessionEnd::mutate(|l| *l = true) } pub fn set_session_length(x: u64) { - SESSION_LENGTH.with(|l| *l.borrow_mut() = x) + SessionLength::mutate(|l| *l = x) } pub fn session_changed() -> bool { - SESSION_CHANGED.with(|l| *l.borrow()) + SessionChanged::get() } pub fn set_next_validators(next: Vec) { - NEXT_VALIDATORS.with(|v| *v.borrow_mut() = next); + NextValidators::mutate(|v| *v = next); } pub fn before_session_end_called() -> bool { - BEFORE_SESSION_END_CALLED.with(|b| *b.borrow()) + BeforeSessionEndCalled::get() } pub fn reset_before_session_end_called() { - BEFORE_SESSION_END_CALLED.with(|b| *b.borrow_mut() = false); + BeforeSessionEndCalled::mutate(|b| *b = false); } pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let keys: Vec<_> = NEXT_VALIDATORS - .with(|l| l.borrow().iter().cloned().map(|i| (i, i, UintAuthorityId(i).into())).collect()); + let keys: Vec<_> = NextValidators::get() + .iter() + .cloned() + .map(|i| (i, i, UintAuthorityId(i).into())) + .collect(); BasicExternalities::execute_with_storage(&mut t, || { for (ref k, ..) in &keys { frame_system::Pallet::::inc_providers(k); @@ -230,10 +232,9 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pallet_session::GenesisConfig:: { keys } .assimilate_storage(&mut t) .unwrap(); - NEXT_VALIDATORS.with(|l| { - let v = l.borrow().iter().map(|&i| (i, i)).collect(); - VALIDATOR_ACCOUNTS.with(|m| *m.borrow_mut() = v); - }); + + let v = NextValidators::get().iter().map(|&i| (i, i)).collect(); + ValidatorAccounts::mutate(|m| *m = v); sp_io::TestExternalities::new(t) } @@ -279,12 +280,12 @@ impl pallet_timestamp::Config for Test { pub struct TestValidatorIdOf; impl TestValidatorIdOf { pub fn set(v: BTreeMap) { - VALIDATOR_ACCOUNTS.with(|m| *m.borrow_mut() = v); + ValidatorAccounts::mutate(|m| *m = v); } } impl Convert> for TestValidatorIdOf { fn convert(x: u64) -> Option { - VALIDATOR_ACCOUNTS.with(|m| m.borrow().get(&x).cloned()) + ValidatorAccounts::get().get(&x).cloned() } } diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index c9d2dbb53d9ba..7947a8a670b5a 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -21,8 +21,8 @@ use super::*; use crate::mock::{ authorities, before_session_end_called, force_new_session, new_test_ext, reset_before_session_end_called, session_changed, set_next_validators, set_session_length, - Origin, PreUpgradeMockSessionKeys, Session, System, Test, TestValidatorIdOf, SESSION_CHANGED, - TEST_SESSION_CHANGED, + Origin, PreUpgradeMockSessionKeys, Session, SessionChanged, System, Test, TestSessionChanged, + TestValidatorIdOf, }; use codec::Decode; @@ -35,7 +35,7 @@ use frame_support::{ }; fn initialize_block(block: u64) { - SESSION_CHANGED.with(|l| *l.borrow_mut() = false); + SessionChanged::mutate(|l| *l = false); System::set_block_number(block); Session::on_initialize(block); } @@ -235,7 +235,7 @@ fn session_changed_flag_works() { new_test_ext().execute_with(|| { TestValidatorIdOf::set(vec![(1, 1), (2, 2), (3, 3), (69, 69)].into_iter().collect()); - TEST_SESSION_CHANGED.with(|l| *l.borrow_mut() = true); + TestSessionChanged::mutate(|l| *l = true); force_new_session(); initialize_block(1); @@ -384,8 +384,8 @@ fn upgrade_keys() { use sp_core::crypto::key_types::DUMMY; // This test assumes certain mocks. - assert_eq!(mock::NEXT_VALIDATORS.with(|l| l.borrow().clone()), vec![1, 2, 3]); - assert_eq!(mock::VALIDATORS.with(|l| l.borrow().clone()), vec![1, 2, 3]); + assert_eq!(mock::NextValidators::get().clone(), vec![1, 2, 3]); + assert_eq!(mock::Validators::get().clone(), vec![1, 2, 3]); new_test_ext().execute_with(|| { let pre_one = PreUpgradeMockSessionKeys { a: [1u8; 32], b: [1u8; 64] }; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 7911428b3337c..cdad11589f743 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -37,7 +37,6 @@ use sp_runtime::{ traits::{IdentityLookup, Zero}, }; use sp_staking::offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}; -use std::cell::RefCell; pub const INIT_TIMESTAMP: u64 = 30_000; pub const BLOCK_TIME: u64 = 1000; @@ -216,16 +215,16 @@ parameter_types! { pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(75); } -thread_local! { - pub static REWARD_REMAINDER_UNBALANCED: RefCell = RefCell::new(0); +parameter_types! { + pub static RewardRemainderUnbalanced: u128 = 0; } pub struct RewardRemainderMock; impl OnUnbalanced> for RewardRemainderMock { fn on_nonzero_unbalanced(amount: NegativeImbalanceOf) { - REWARD_REMAINDER_UNBALANCED.with(|v| { - *v.borrow_mut() += amount.peek(); + RewardRemainderUnbalanced::mutate(|v| { + *v += amount.peek(); }); drop(amount); } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 448fbd2382454..969ff8e4e2881 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -301,10 +301,7 @@ fn rewards_should_work() { start_session(3); assert_eq!(active_era(), 1); - assert_eq!( - mock::REWARD_REMAINDER_UNBALANCED.with(|v| *v.borrow()), - maximum_payout - total_payout_0, - ); + assert_eq!(mock::RewardRemainderUnbalanced::get(), maximum_payout - total_payout_0,); assert_eq!( *mock::staking_events().last().unwrap(), Event::EraPaid(0, total_payout_0, maximum_payout - total_payout_0) @@ -340,7 +337,7 @@ fn rewards_should_work() { mock::start_active_era(2); assert_eq!( - mock::REWARD_REMAINDER_UNBALANCED.with(|v| *v.borrow()), + mock::RewardRemainderUnbalanced::get(), maximum_payout * 2 - total_payout_0 - total_payout_1, ); assert_eq!( diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 3b2a8b3b62fc2..55ded6da9c5a1 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -446,6 +446,21 @@ macro_rules! parameter_types_impl_thread_local { pub fn set(t: $type) { [<$name:snake:upper>].with(|v| *v.borrow_mut() = t); } + + /// Mutate the internal value in place. + pub fn mutate R>(mutate: F) -> R{ + let mut current = Self::get(); + let result = mutate(&mut current); + Self::set(current); + result + } + + /// Get current value and replace with initial value of the parameter type. + pub fn take() -> $type { + let current = Self::get(); + Self::set($value); + current + } } )* } diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index aed98579a0fd8..04b3dbcedcbf2 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -22,7 +22,10 @@ #![recursion_limit = "128"] use codec::MaxEncodedLen; -use frame_support::traits::{CrateVersion, PalletInfo as _}; +use frame_support::{ + parameter_types, + traits::{CrateVersion, PalletInfo as _}, +}; use scale_info::TypeInfo; use sp_core::{sr25519, H256}; use sp_runtime::{ @@ -30,14 +33,13 @@ use sp_runtime::{ traits::{BlakeTwo256, Verify}, DispatchError, ModuleError, }; -use sp_std::cell::RefCell; mod system; pub trait Currency {} -thread_local! { - pub static INTEGRITY_TEST_EXEC: RefCell = RefCell::new(0); +parameter_types! { + pub static IntegrityTestExec: u32 = 0; } mod module1 { @@ -95,7 +97,7 @@ mod module2 { } fn integrity_test() { - INTEGRITY_TEST_EXEC.with(|i| *i.borrow_mut() += 1); + IntegrityTestExec::mutate(|i| *i += 1); } } } @@ -140,7 +142,7 @@ mod nested { } fn integrity_test() { - INTEGRITY_TEST_EXEC.with(|i| *i.borrow_mut() += 1); + IntegrityTestExec::mutate(|i| *i += 1); } } } @@ -377,7 +379,7 @@ fn check_modules_error_type() { #[test] fn integrity_test_works() { __construct_runtime_integrity_test::runtime_integrity_tests(); - assert_eq!(INTEGRITY_TEST_EXEC.with(|i| *i.borrow()), 2); + assert_eq!(IntegrityTestExec::get(), 2); } #[test] diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index 23ab3c2af20b0..09a018e2be70e 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -26,7 +26,6 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, BuildStorage, }; -use sp_std::cell::RefCell; type UncheckedExtrinsic = mocking::MockUncheckedExtrinsic; type Block = mocking::MockBlock; @@ -79,14 +78,14 @@ parameter_types! { limits::BlockLength::max_with_normal_ratio(1024, NORMAL_DISPATCH_RATIO); } -thread_local! { - pub static KILLED: RefCell> = RefCell::new(vec![]); +parameter_types! { + pub static Killed: Vec = vec![]; } pub struct RecordKilled; impl OnKilledAccount for RecordKilled { fn on_killed_account(who: &u64) { - KILLED.with(|r| r.borrow_mut().push(*who)) + Killed::mutate(|r| r.push(*who)) } } diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index f82ea338bd146..641cda13b07a4 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -55,9 +55,9 @@ fn stored_map_works() { System::dec_consumers(&0); assert!(!System::is_provider_required(&0)); - assert!(KILLED.with(|r| r.borrow().is_empty())); + assert!(Killed::get().is_empty()); assert_ok!(System::remove(&0)); - assert_eq!(KILLED.with(|r| r.borrow().clone()), vec![0u64]); + assert_eq!(Killed::get(), vec![0u64]); }); } diff --git a/frame/timestamp/src/mock.rs b/frame/timestamp/src/mock.rs index b4c377cfa30ef..1ea553aa548ec 100644 --- a/frame/timestamp/src/mock.rs +++ b/frame/timestamp/src/mock.rs @@ -19,7 +19,6 @@ use super::*; use crate as pallet_timestamp; -use sp_std::cell::RefCell; use frame_support::{ parameter_types, @@ -78,14 +77,14 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } -thread_local! { - pub static CAPTURED_MOMENT: RefCell> = RefCell::new(None); +parameter_types! { + pub static CapturedMoment: Option = None; } pub struct MockOnTimestampSet; impl OnTimestampSet for MockOnTimestampSet { fn on_timestamp_set(moment: Moment) { - CAPTURED_MOMENT.with(|x| *x.borrow_mut() = Some(moment)); + CapturedMoment::mutate(|x| *x = Some(moment)); } } @@ -97,11 +96,11 @@ impl Config for Test { } pub(crate) fn clear_captured_moment() { - CAPTURED_MOMENT.with(|x| *x.borrow_mut() = None); + CapturedMoment::mutate(|x| *x = None); } pub(crate) fn get_captured_moment() -> Option { - CAPTURED_MOMENT.with(|x| *x.borrow()) + CapturedMoment::get() } pub(crate) fn new_test_ext() -> TestExternalities { diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index bcaa99285d2e7..b12885fc59f16 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -19,8 +19,6 @@ #![cfg(test)] -use std::cell::RefCell; - use sp_core::H256; use sp_runtime::{ testing::Header, @@ -100,18 +98,17 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); } -thread_local! { - static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); +parameter_types! { + static TenToFourteenTestValue: Vec = vec![10,11,12,13,14]; } pub struct TenToFourteen; impl SortedMembers for TenToFourteen { fn sorted_members() -> Vec { - TEN_TO_FOURTEEN.with(|v| v.borrow().clone()) + TenToFourteenTestValue::get().clone() } #[cfg(feature = "runtime-benchmarks")] fn add(new: &u128) { - TEN_TO_FOURTEEN.with(|v| { - let mut members = v.borrow_mut(); + TenToFourteenTestValue::mutate(|members| { members.push(*new); members.sort(); }) @@ -119,7 +116,7 @@ impl SortedMembers for TenToFourteen { } impl ContainsLengthBound for TenToFourteen { fn max_len() -> usize { - TEN_TO_FOURTEEN.with(|v| v.borrow().len()) + TenToFourteenTestValue::get().len() } fn min_len() -> usize { 0 diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index a17d564d7a334..dd7c086a82469 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -33,7 +33,6 @@ use sp_runtime::{ testing::Header, traits::{BlakeTwo256, ConvertInto, IdentityLookup, SaturatedConversion, StaticLookup}, }; -use std::cell::RefCell; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -58,8 +57,8 @@ frame_support::construct_runtime!( const CALL: &::Call = &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); -thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::zero()); +parameter_types! { + static ExtrinsicBaseWeight: Weight = Weight::zero(); } pub struct BlockWeights; @@ -68,7 +67,7 @@ impl Get for BlockWeights { frame_system::limits::BlockWeights::builder() .base_block(Weight::zero()) .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into(); + weights.base_extrinsic = ExtrinsicBaseWeight::get().into(); }) .for_class(DispatchClass::non_mandatory(), |weights| { weights.max_total = Weight::from_ref_time(1024).into(); @@ -235,7 +234,7 @@ impl ExtBuilder { self } fn set_constants(&self) { - EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); + ExtrinsicBaseWeight::mutate(|v| *v = self.base_weight); TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee); WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 21d516cda1aa6..cbdc9dcb1e846 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -810,8 +810,6 @@ mod tests { use super::*; use crate as pallet_transaction_payment; - use std::cell::RefCell; - use codec::Encode; use sp_core::H256; @@ -850,8 +848,8 @@ mod tests { const CALL: &::Call = &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); - thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::zero()); + parameter_types! { + static ExtrinsicBaseWeight: Weight = Weight::zero(); } pub struct BlockWeights; @@ -860,7 +858,7 @@ mod tests { frame_system::limits::BlockWeights::builder() .base_block(Weight::zero()) .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into(); + weights.base_extrinsic = ExtrinsicBaseWeight::get().into(); }) .for_class(DispatchClass::non_mandatory(), |weights| { weights.max_total = Weight::from_ref_time(1024).into(); @@ -932,9 +930,9 @@ mod tests { } } - thread_local! { - static TIP_UNBALANCED_AMOUNT: RefCell = RefCell::new(0); - static FEE_UNBALANCED_AMOUNT: RefCell = RefCell::new(0); + parameter_types! { + static TipUnbalancedAmount: u64 = 0; + static FeeUnbalancedAmount: u64 = 0; } pub struct DealWithFees; @@ -943,9 +941,9 @@ mod tests { mut fees_then_tips: impl Iterator>, ) { if let Some(fees) = fees_then_tips.next() { - FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() += fees.peek()); + FeeUnbalancedAmount::mutate(|a| *a += fees.peek()); if let Some(tips) = fees_then_tips.next() { - TIP_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() += tips.peek()); + TipUnbalancedAmount::mutate(|a| *a += tips.peek()); } } } @@ -1002,7 +1000,7 @@ mod tests { self } fn set_constants(&self) { - EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); + ExtrinsicBaseWeight::mutate(|v| *v = self.base_weight); TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee); WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); } @@ -1074,10 +1072,10 @@ mod tests { &Ok(()) )); assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); - assert_eq!(FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 5 + 5 + 10); - assert_eq!(TIP_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 0); + assert_eq!(FeeUnbalancedAmount::get(), 5 + 5 + 10); + assert_eq!(TipUnbalancedAmount::get(), 0); - FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() = 0); + FeeUnbalancedAmount::mutate(|a| *a = 0); let pre = ChargeTransactionPayment::::from(5 /* tipped */) .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_ref_time(100)), len) @@ -1092,8 +1090,8 @@ mod tests { &Ok(()) )); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 50 - 5); - assert_eq!(FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 5 + 10 + 50); - assert_eq!(TIP_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 5); + assert_eq!(FeeUnbalancedAmount::get(), 5 + 10 + 50); + assert_eq!(TipUnbalancedAmount::get(), 5); }); } diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index bec96daf576e3..c9c6d01f129e6 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -19,8 +19,6 @@ #![cfg(test)] -use std::cell::RefCell; - use sp_core::H256; use sp_runtime::{ testing::Header, @@ -94,9 +92,6 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); } -thread_local! { - static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); -} parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); From cd66db5d1867fc37247d6622d893ac05557bc9bb Mon Sep 17 00:00:00 2001 From: Vlad Date: Thu, 8 Sep 2022 15:35:44 +0300 Subject: [PATCH 1139/1472] Fully remove `rusty-cachier` from the `node-bench-regression-guard` job (#11904) Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> --- scripts/ci/gitlab/pipeline/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index acd2cb1fa7855..8036e2cec26bb 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -110,6 +110,8 @@ node-bench-regression-guard: - job: cargo-check-benches artifacts: true # polls artifact from master to compare with current result + # need to specify both parallel jobs from master because of the bug + # https://gitlab.com/gitlab-org/gitlab/-/issues/39063 - project: $CI_PROJECT_PATH job: "cargo-check-benches 1/2" ref: master @@ -127,6 +129,7 @@ node-bench-regression-guard: - echo "In case of this job failure, check your pipeline's cargo-check-benches" - 'node-bench-regression-guard --reference artifacts/benches/master-* --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA' + after_script: [""] cargo-check-subkey: stage: test From b8c3d8cc2301a46070ddc9dbd90c135f9db5cd0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 8 Sep 2022 13:48:19 +0100 Subject: [PATCH 1140/1472] Upgrade wasm crate dependencies (#12173) * Upgrade wasm crate dependencies * New wasmi version changed error output a bit * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts Co-authored-by: command-bot <> --- Cargo.lock | 69 +- bin/node/cli/Cargo.toml | 1 - bin/node/executor/Cargo.toml | 1 - client/executor/Cargo.toml | 3 +- client/executor/common/Cargo.toml | 4 +- .../common/src/sandbox/wasmi_backend.rs | 17 +- client/executor/src/integration_tests/mod.rs | 6 +- client/executor/wasmi/Cargo.toml | 2 +- client/executor/wasmi/src/lib.rs | 2 + client/executor/wasmtime/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 4 +- frame/contracts/src/benchmarking/code.rs | 10 +- frame/contracts/src/wasm/prepare.rs | 2 +- frame/contracts/src/weights.rs | 1250 ++++++++--------- primitives/core/Cargo.toml | 2 +- primitives/sandbox/Cargo.toml | 10 +- primitives/sandbox/src/embedded_executor.rs | 4 +- primitives/version/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- 19 files changed, 708 insertions(+), 685 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 223a14efd73b7..38439947258a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4360,9 +4360,9 @@ dependencies = [ [[package]] name = "memory_units" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" [[package]] name = "merlin" @@ -4991,6 +4991,17 @@ dependencies = [ "num-traits", ] +[[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.0" @@ -5027,7 +5038,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ "autocfg", - "num-bigint", + "num-bigint 0.2.6", "num-integer", "num-traits", ] @@ -5039,6 +5050,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" dependencies = [ "autocfg", + "num-bigint 0.4.3", "num-integer", "num-traits", ] @@ -6617,9 +6629,9 @@ dependencies = [ [[package]] name = "parity-wasm" -version = "0.42.2" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" +checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" [[package]] name = "parking" @@ -7980,7 +7992,7 @@ dependencies = [ "futures", "log", "merlin", - "num-bigint", + "num-bigint 0.2.6", "num-rational 0.2.4", "num-traits", "parity-scale-codec", @@ -8236,7 +8248,7 @@ dependencies = [ "log", "once_cell", "parity-scale-codec", - "parity-wasm 0.42.2", + "parity-wasm 0.45.0", "paste 1.0.6", "rustix", "sc-allocator", @@ -9486,7 +9498,7 @@ name = "sp-arithmetic-fuzzer" version = "2.0.0" dependencies = [ "honggfuzz", - "num-bigint", + "num-bigint 0.2.6", "primitive-types", "sp-arithmetic", ] @@ -10194,7 +10206,7 @@ version = "5.0.0" dependencies = [ "impl-serde", "parity-scale-codec", - "parity-wasm 0.42.2", + "parity-wasm 0.45.0", "scale-info", "serde", "sp-core-hashing-proc-macro", @@ -11415,11 +11427,11 @@ dependencies = [ [[package]] name = "wasm-instrument" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "962e5b0401bbb6c887f54e69b8c496ea36f704df65db73e81fd5ff8dc3e63a9f" +checksum = "8bca81f5279342b38b17d9acbf007a46ddeb73144e2bd5f0a21bfa9fc5d4ab3e" dependencies = [ - "parity-wasm 0.42.2", + "parity-wasm 0.45.0", ] [[package]] @@ -11652,28 +11664,35 @@ dependencies = [ [[package]] name = "wasmi" -version = "0.9.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca00c5147c319a8ec91ec1a0edbec31e566ce2c9cc93b3f9bb86a9efd0eb795d" +checksum = "fc13b3c219ca9aafeec59150d80d89851df02e0061bc357b4d66fc55a8d38787" dependencies = [ - "downcast-rs", - "errno", - "libc", - "libm", - "memory_units", - "num-rational 0.2.4", - "num-traits", - "parity-wasm 0.42.2", + "parity-wasm 0.45.0", "wasmi-validation", + "wasmi_core", ] [[package]] name = "wasmi-validation" -version = "0.4.0" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ff416ad1ff0c42e5a926ed5d5fab74c0f098749aa0ad8b2a34b982ce0e867b" +dependencies = [ + "parity-wasm 0.45.0", +] + +[[package]] +name = "wasmi_core" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb8e860796d8be48efef530b60eebf84e74a88bce107374fffb0da97d504b8" +checksum = "e0a088e8c4c59c6f2b9eae169bf86328adccc477c00b56d3661e3e9fb397b184" dependencies = [ - "parity-wasm 0.42.2", + "downcast-rs", + "libm", + "memory_units", + "num-rational 0.4.0", + "num-traits", ] [[package]] diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index d84b8491cb162..247a61d835dc3 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -149,7 +149,6 @@ pallet-balances = { version = "4.0.0-dev", path = "../../../frame/balances" } [features] default = ["cli"] cli = [ - "node-executor/wasmi-errno", "node-inspect", "sc-cli", "frame-benchmarking-cli", diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 71865783da8ac..651e4657dde32 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -46,7 +46,6 @@ sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [features] wasmtime = ["sc-executor/wasmtime"] -wasmi-errno = ["sc-executor/wasmi-errno"] stress-test = [] [[bench]] diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 6a4b2a44a2d44..2fe7e822b36c3 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -18,7 +18,7 @@ lazy_static = "1.4.0" lru = "0.7.5" parking_lot = "0.12.1" tracing = "0.1.29" -wasmi = "0.9.1" +wasmi = "0.13" codec = { package = "parity-scale-codec", version = "3.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "common" } @@ -63,5 +63,4 @@ default = ["std"] std = [] wasm-extern-trace = [] wasmtime = ["sc-executor-wasmtime"] -wasmi-errno = ["wasmi/errno"] wasmer-sandbox = ["sc-executor-common/wasmer-sandbox"] diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index b16ed7e8552ce..1af75c7e31610 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } environmental = "1.1.3" thiserror = "1.0.30" -wasm-instrument = "0.1" +wasm-instrument = "0.2" wasmer = { version = "2.2", features = ["singlepass"], optional = true } -wasmi = "0.9.1" +wasmi = "0.13" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } diff --git a/client/executor/common/src/sandbox/wasmi_backend.rs b/client/executor/common/src/sandbox/wasmi_backend.rs index 03fa5dc06dea8..2ba133f5f15b1 100644 --- a/client/executor/common/src/sandbox/wasmi_backend.rs +++ b/client/executor/common/src/sandbox/wasmi_backend.rs @@ -18,14 +18,14 @@ //! Wasmi specific impls for sandbox -use std::rc::Rc; +use std::{fmt, rc::Rc}; use codec::{Decode, Encode}; use sp_sandbox::HostError; use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; use wasmi::{ memory_units::Pages, ImportResolver, MemoryInstance, Module, ModuleInstance, RuntimeArgs, - RuntimeValue, Trap, TrapKind, + RuntimeValue, Trap, }; use crate::{ @@ -39,9 +39,20 @@ use crate::{ environmental::environmental!(SandboxContextStore: trait SandboxContext); +#[derive(Debug)] +struct CustomHostError(String); + +impl fmt::Display for CustomHostError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "HostError: {}", self.0) + } +} + +impl wasmi::HostError for CustomHostError {} + /// Construct trap error from specified message fn trap(msg: &'static str) -> Trap { - TrapKind::Host(Box::new(Error::Other(msg.into()))).into() + Trap::host(CustomHostError(msg.into())) } impl ImportResolver for Imports { diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index ba0c93630cf6c..25280f856f2a5 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -253,7 +253,7 @@ fn call_not_existing_function(wasm_method: WasmExecutionMethod) { match call_in_wasm("test_calling_missing_external", &[], wasm_method, &mut ext).unwrap_err() { Error::AbortedDueToTrap(error) => { let expected = match wasm_method { - WasmExecutionMethod::Interpreted => "Trap: Host(Other(\"Function `missing_external` is only a stub. Calling a stub is not allowed.\"))", + WasmExecutionMethod::Interpreted => "Other: Function `missing_external` is only a stub. Calling a stub is not allowed.", #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled { .. } => "call to a missing function env:missing_external" }; @@ -273,7 +273,7 @@ fn call_yet_another_not_existing_function(wasm_method: WasmExecutionMethod) { { Error::AbortedDueToTrap(error) => { let expected = match wasm_method { - WasmExecutionMethod::Interpreted => "Trap: Host(Other(\"Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.\"))", + WasmExecutionMethod::Interpreted => "Other: Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.", #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled { .. } => "call to a missing function env:yet_another_missing_external" }; @@ -909,7 +909,7 @@ fn unreachable_intrinsic(wasm_method: WasmExecutionMethod) { match call_in_wasm("test_unreachable_intrinsic", &[], wasm_method, &mut ext).unwrap_err() { Error::AbortedDueToTrap(error) => { let expected = match wasm_method { - WasmExecutionMethod::Interpreted => "Trap: Unreachable", + WasmExecutionMethod::Interpreted => "unreachable", #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled { .. } => "wasm trap: wasm `unreachable` instruction executed", }; diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 46bacf54a42c6..879af677ca042 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } log = "0.4.17" -wasmi = "0.9.1" +wasmi = "0.13" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index e17707e158321..1284cc23e4c96 100644 --- a/client/executor/wasmi/src/lib.rs +++ b/client/executor/wasmi/src/lib.rs @@ -181,6 +181,7 @@ impl Sandbox for FunctionExecutor { let len = val_len as usize; + #[allow(deprecated)] let buffer = match self.memory.get(val_ptr.into(), len) { Err(_) => return Ok(sandbox_env::ERR_OUT_OF_BOUNDS), Ok(buffer) => buffer, @@ -568,6 +569,7 @@ fn call_in_wasm_module( match result { Ok(Some(I64(r))) => { let (ptr, length) = unpack_ptr_and_len(r as u64); + #[allow(deprecated)] memory.get(ptr, length as usize).map_err(|_| Error::Runtime) }, Err(e) => { diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index e4df2791c2ff8..94ad25bdc948c 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = "1.0" codec = { package = "parity-scale-codec", version = "3.0.0" } libc = "0.2.121" log = "0.4.17" -parity-wasm = "0.42.0" +parity-wasm = "0.45" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index ac85c469354fe..019f111302a55 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -20,12 +20,12 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } log = { version = "0.4", default-features = false } -wasm-instrument = { version = "0.1", default-features = false } +wasm-instrument = { version = "0.2", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } smallvec = { version = "1", default-features = false, features = [ "const_generics", ] } -wasmi-validation = { version = "0.4", default-features = false } +wasmi-validation = { version = "0.5", default-features = false } impl-trait-for-tuples = "0.2" # Only used in benchmarking to generate random contract code diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 5f9b43d3e3b7a..32ee2dbf93914 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -195,7 +195,7 @@ where for func in def.imported_functions { let sig = builder::signature() .with_params(func.params) - .with_results(func.return_type.into_iter().collect()) + .with_results(func.return_type) .build_sig(); let sig = contract.push_signature(sig); contract = contract @@ -254,9 +254,9 @@ where code = inject_stack_metering::(code); } - let code = code.to_bytes().unwrap(); + let code = code.into_bytes().unwrap(); let hash = T::Hashing::hash(&code); - Self { code, hash, memory: def.memory } + Self { code: code.into(), hash, memory: def.memory } } } @@ -285,11 +285,11 @@ where .find_map(|e| if let External::Memory(mem) = e.external() { Some(mem) } else { None }) .unwrap() .limits(); - let code = module.to_bytes().unwrap(); + let code = module.into_bytes().unwrap(); let hash = T::Hashing::hash(&code); let memory = ImportedMemory { min_pages: limits.initial(), max_pages: limits.maximum().unwrap() }; - Self { code, hash, memory: Some(memory) } + Self { code: code.into(), hash, memory: Some(memory) } } /// Creates a wasm module with an empty `call` and `deploy` function and nothing else. diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 7b81c1c55b3bd..9c130b562c275 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -54,7 +54,7 @@ impl<'a, T: Config> ContractModule<'a, T> { elements::deserialize_buffer(original_code).map_err(|_| "Can't decode wasm code")?; // Make sure that the module is valid. - validate_module::(&module).map_err(|_| "Module is not valid")?; + validate_module::(&module, ()).map_err(|_| "Module is not valid")?; // Return a `ContractModule` instance with // __valid__ module. diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 6ec10b3590349..4e4a6b6e6a2b7 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-09-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -166,15 +166,15 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(2_985_000 as u64) + Weight::from_ref_time(3_089_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(14_335_000 as u64) + Weight::from_ref_time(13_917_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(891_000 as u64).saturating_mul(k as u64)) + .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(k as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -182,9 +182,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(13_905_000 as u64) + Weight::from_ref_time(14_172_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_257_000 as u64).saturating_mul(q as u64)) + .saturating_add(Weight::from_ref_time(1_301_000 as u64).saturating_mul(q as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -192,9 +192,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(26_333_000 as u64) + Weight::from_ref_time(21_644_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(44_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -205,9 +205,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(238_784_000 as u64) + Weight::from_ref_time(234_349_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -222,9 +222,9 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(325_497_000 as u64) + Weight::from_ref_time(294_077_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(107_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(c as u64)) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) @@ -239,7 +239,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(201_129_000 as u64) + Weight::from_ref_time(199_028_000 as u64) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) @@ -251,7 +251,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(176_645_000 as u64) + Weight::from_ref_time(176_247_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -261,9 +261,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(53_613_000 as u64) + Weight::from_ref_time(54_917_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -272,7 +272,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(37_441_000 as u64) + Weight::from_ref_time(37_611_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -280,7 +280,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(40_030_000 as u64) + Weight::from_ref_time(40_121_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -291,9 +291,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(241_426_000 as u64) - // Standard Error: 46_000 - .saturating_add(Weight::from_ref_time(37_834_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_129_000 as u64) + // Standard Error: 54_000 + .saturating_add(Weight::from_ref_time(35_413_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -304,9 +304,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(181_406_000 as u64) - // Standard Error: 474_000 - .saturating_add(Weight::from_ref_time(206_995_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(189_418_000 as u64) + // Standard Error: 419_000 + .saturating_add(Weight::from_ref_time(207_107_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -318,9 +318,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(198_301_000 as u64) - // Standard Error: 432_000 - .saturating_add(Weight::from_ref_time(264_877_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(203_928_000 as u64) + // Standard Error: 439_000 + .saturating_add(Weight::from_ref_time(268_983_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -332,9 +332,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(243_754_000 as u64) - // Standard Error: 51_000 - .saturating_add(Weight::from_ref_time(41_219_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(243_800_000 as u64) + // Standard Error: 40_000 + .saturating_add(Weight::from_ref_time(38_797_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -345,9 +345,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(239_352_000 as u64) - // Standard Error: 33_000 - .saturating_add(Weight::from_ref_time(15_228_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_667_000 as u64) + // Standard Error: 27_000 + .saturating_add(Weight::from_ref_time(15_826_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -358,9 +358,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(240_637_000 as u64) - // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(37_717_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_116_000 as u64) + // Standard Error: 41_000 + .saturating_add(Weight::from_ref_time(35_402_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -371,9 +371,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(241_127_000 as u64) - // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(37_481_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_515_000 as u64) + // Standard Error: 50_000 + .saturating_add(Weight::from_ref_time(35_144_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -384,9 +384,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(246_236_000 as u64) - // Standard Error: 97_000 - .saturating_add(Weight::from_ref_time(110_095_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_087_000 as u64) + // Standard Error: 87_000 + .saturating_add(Weight::from_ref_time(110_236_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -397,9 +397,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(241_552_000 as u64) - // Standard Error: 38_000 - .saturating_add(Weight::from_ref_time(37_189_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_774_000 as u64) + // Standard Error: 50_000 + .saturating_add(Weight::from_ref_time(35_216_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -410,9 +410,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(239_622_000 as u64) - // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(37_630_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_146_000 as u64) + // Standard Error: 54_000 + .saturating_add(Weight::from_ref_time(35_101_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -423,9 +423,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(240_284_000 as u64) - // Standard Error: 49_000 - .saturating_add(Weight::from_ref_time(37_375_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_096_000 as u64) + // Standard Error: 55_000 + .saturating_add(Weight::from_ref_time(34_612_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -436,9 +436,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(241_463_000 as u64) - // Standard Error: 43_000 - .saturating_add(Weight::from_ref_time(37_313_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(242_978_000 as u64) + // Standard Error: 53_000 + .saturating_add(Weight::from_ref_time(34_780_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -450,9 +450,9 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(245_287_000 as u64) - // Standard Error: 88_000 - .saturating_add(Weight::from_ref_time(99_890_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(246_175_000 as u64) + // Standard Error: 86_000 + .saturating_add(Weight::from_ref_time(99_827_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -463,9 +463,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(168_156_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(17_991_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(168_655_000 as u64) + // Standard Error: 16_000 + .saturating_add(Weight::from_ref_time(15_635_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -476,9 +476,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(240_833_000 as u64) - // Standard Error: 50_000 - .saturating_add(Weight::from_ref_time(35_622_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_729_000 as u64) + // Standard Error: 52_000 + .saturating_add(Weight::from_ref_time(33_477_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -489,9 +489,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(330_765_000 as u64) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(8_609_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(296_718_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(9_616_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -502,9 +502,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - Weight::from_ref_time(237_729_000 as u64) - // Standard Error: 488_000 - .saturating_add(Weight::from_ref_time(2_053_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(237_666_000 as u64) + // Standard Error: 497_000 + .saturating_add(Weight::from_ref_time(2_090_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -515,9 +515,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(240_005_000 as u64) + Weight::from_ref_time(239_842_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(169_000 as u64).saturating_mul(n as u64)) + .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -530,9 +530,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(240_524_000 as u64) - // Standard Error: 426_000 - .saturating_add(Weight::from_ref_time(51_863_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_563_000 as u64) + // Standard Error: 519_000 + .saturating_add(Weight::from_ref_time(52_855_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -546,9 +546,9 @@ impl WeightInfo for SubstrateWeight { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(250_710_000 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(132_741_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(248_136_000 as u64) + // Standard Error: 94_000 + .saturating_add(Weight::from_ref_time(137_406_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -559,9 +559,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(245_816_000 as u64) - // Standard Error: 115_000 - .saturating_add(Weight::from_ref_time(235_313_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(253_433_000 as u64) + // Standard Error: 105_000 + .saturating_add(Weight::from_ref_time(242_337_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -573,11 +573,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(469_886_000 as u64) - // Standard Error: 463_000 - .saturating_add(Weight::from_ref_time(177_286_000 as u64).saturating_mul(t as u64)) - // Standard Error: 127_000 - .saturating_add(Weight::from_ref_time(64_646_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(478_106_000 as u64) + // Standard Error: 557_000 + .saturating_add(Weight::from_ref_time(176_325_000 as u64).saturating_mul(t as u64)) + // Standard Error: 153_000 + .saturating_add(Weight::from_ref_time(67_413_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -590,18 +590,18 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(174_414_000 as u64) - // Standard Error: 26_000 - .saturating_add(Weight::from_ref_time(29_037_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(172_751_000 as u64) + // Standard Error: 37_000 + .saturating_add(Weight::from_ref_time(26_536_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(196_960_000 as u64) - // Standard Error: 414_000 - .saturating_add(Weight::from_ref_time(412_810_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(196_276_000 as u64) + // Standard Error: 428_000 + .saturating_add(Weight::from_ref_time(416_783_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -610,9 +610,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_493_000 as u64) - // Standard Error: 1_251_000 - .saturating_add(Weight::from_ref_time(88_835_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(532_439_000 as u64) + // Standard Error: 1_323_000 + .saturating_add(Weight::from_ref_time(93_843_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(52 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(50 as u64)) @@ -621,9 +621,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(512_531_000 as u64) - // Standard Error: 1_107_000 - .saturating_add(Weight::from_ref_time(67_926_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(511_358_000 as u64) + // Standard Error: 1_144_000 + .saturating_add(Weight::from_ref_time(68_754_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(52 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(50 as u64)) @@ -632,9 +632,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(208_848_000 as u64) - // Standard Error: 398_000 - .saturating_add(Weight::from_ref_time(400_478_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(204_133_000 as u64) + // Standard Error: 498_000 + .saturating_add(Weight::from_ref_time(406_798_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -643,9 +643,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(488_903_000 as u64) - // Standard Error: 1_226_000 - .saturating_add(Weight::from_ref_time(69_519_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(489_339_000 as u64) + // Standard Error: 1_269_000 + .saturating_add(Weight::from_ref_time(70_700_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(49 as u64)) @@ -654,9 +654,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(211_825_000 as u64) - // Standard Error: 401_000 - .saturating_add(Weight::from_ref_time(328_607_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(211_344_000 as u64) + // Standard Error: 399_000 + .saturating_add(Weight::from_ref_time(330_244_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -664,9 +664,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(452_324_000 as u64) - // Standard Error: 1_026_000 - .saturating_add(Weight::from_ref_time(150_657_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(449_353_000 as u64) + // Standard Error: 1_027_000 + .saturating_add(Weight::from_ref_time(153_022_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -674,9 +674,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(218_730_000 as u64) - // Standard Error: 318_000 - .saturating_add(Weight::from_ref_time(302_022_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(216_197_000 as u64) + // Standard Error: 341_000 + .saturating_add(Weight::from_ref_time(305_401_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -684,9 +684,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(425_128_000 as u64) - // Standard Error: 875_000 - .saturating_add(Weight::from_ref_time(60_095_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(423_033_000 as u64) + // Standard Error: 878_000 + .saturating_add(Weight::from_ref_time(61_940_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -694,9 +694,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(208_039_000 as u64) - // Standard Error: 445_000 - .saturating_add(Weight::from_ref_time(425_933_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(204_244_000 as u64) + // Standard Error: 448_000 + .saturating_add(Weight::from_ref_time(429_399_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -705,9 +705,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(518_112_000 as u64) - // Standard Error: 1_406_000 - .saturating_add(Weight::from_ref_time(159_006_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(516_945_000 as u64) + // Standard Error: 1_412_000 + .saturating_add(Weight::from_ref_time(162_098_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(52 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(49 as u64)) @@ -720,9 +720,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(169_573_000 as u64) - // Standard Error: 701_000 - .saturating_add(Weight::from_ref_time(1_345_943_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(170_412_000 as u64) + // Standard Error: 761_000 + .saturating_add(Weight::from_ref_time(1_367_307_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -736,8 +736,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 8_472_000 - .saturating_add(Weight::from_ref_time(17_569_902_000 as u64).saturating_mul(r as u64)) + // Standard Error: 9_269_000 + .saturating_add(Weight::from_ref_time(17_505_281_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -751,8 +751,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 7_932_000 - .saturating_add(Weight::from_ref_time(17_368_706_000 as u64).saturating_mul(r as u64)) + // Standard Error: 8_780_000 + .saturating_add(Weight::from_ref_time(17_368_867_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads((158 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes((79 as u64).saturating_mul(r as u64))) } @@ -764,11 +764,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(11_036_172_000 as u64) - // Standard Error: 5_683_000 - .saturating_add(Weight::from_ref_time(1_154_945_000 as u64).saturating_mul(t as u64)) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(8_670_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(11_076_579_000 as u64) + // Standard Error: 6_568_000 + .saturating_add(Weight::from_ref_time(1_158_818_000 as u64).saturating_mul(t as u64)) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(9_731_000 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(167 as u64)) .saturating_add(T::DbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(163 as u64)) @@ -784,8 +784,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 25_721_000 - .saturating_add(Weight::from_ref_time(22_827_927_000 as u64).saturating_mul(r as u64)) + // Standard Error: 24_125_000 + .saturating_add(Weight::from_ref_time(22_830_521_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().reads((400 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(5 as u64)) @@ -801,9 +801,9 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(13_991_911_000 as u64) - // Standard Error: 70_000 - .saturating_add(Weight::from_ref_time(124_789_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(13_739_440_000 as u64) + // Standard Error: 79_000 + .saturating_add(Weight::from_ref_time(126_148_000 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(249 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(247 as u64)) @@ -816,9 +816,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(244_026_000 as u64) - // Standard Error: 69_000 - .saturating_add(Weight::from_ref_time(58_077_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_753_000 as u64) + // Standard Error: 60_000 + .saturating_add(Weight::from_ref_time(55_067_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -830,8 +830,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 104_000 - .saturating_add(Weight::from_ref_time(320_432_000 as u64).saturating_mul(n as u64)) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(320_367_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -842,9 +842,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(242_548_000 as u64) - // Standard Error: 88_000 - .saturating_add(Weight::from_ref_time(70_774_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_849_000 as u64) + // Standard Error: 80_000 + .saturating_add(Weight::from_ref_time(67_626_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -856,8 +856,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 152_000 - .saturating_add(Weight::from_ref_time(246_268_000 as u64).saturating_mul(n as u64)) + // Standard Error: 106_000 + .saturating_add(Weight::from_ref_time(247_771_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -868,9 +868,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(242_368_000 as u64) - // Standard Error: 68_000 - .saturating_add(Weight::from_ref_time(48_368_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(242_162_000 as u64) + // Standard Error: 58_000 + .saturating_add(Weight::from_ref_time(45_169_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -882,8 +882,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 94_000 - .saturating_add(Weight::from_ref_time(95_913_000 as u64).saturating_mul(n as u64)) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(97_479_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -894,9 +894,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(239_100_000 as u64) - // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(48_043_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_072_000 as u64) + // Standard Error: 53_000 + .saturating_add(Weight::from_ref_time(44_847_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -908,8 +908,8 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 93_000 - .saturating_add(Weight::from_ref_time(96_000_000 as u64).saturating_mul(n as u64)) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(97_432_000 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -920,9 +920,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(375_902_000 as u64) - // Standard Error: 613_000 - .saturating_add(Weight::from_ref_time(2_972_514_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(374_614_000 as u64) + // Standard Error: 634_000 + .saturating_add(Weight::from_ref_time(2_968_637_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -933,9 +933,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(260_758_000 as u64) - // Standard Error: 396_000 - .saturating_add(Weight::from_ref_time(2_069_937_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(249_022_000 as u64) + // Standard Error: 408_000 + .saturating_add(Weight::from_ref_time(2_062_013_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -948,316 +948,316 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 1_629_000 - .saturating_add(Weight::from_ref_time(1_093_632_000 as u64).saturating_mul(r as u64)) + // Standard Error: 1_536_000 + .saturating_add(Weight::from_ref_time(1_099_219_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads((158 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes((158 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(70_130_000 as u64) + Weight::from_ref_time(70_276_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(798_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(933_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(70_439_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_717_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_309_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(2_977_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(70_647_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_112_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_165_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_686_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(70_045_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_228_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_872_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(2_374_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(71_013_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_284_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_891_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_629_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(69_846_000 as u64) + Weight::from_ref_time(69_747_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_278_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_639_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_471_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_774_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_262_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(2_142_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(68_967_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_984_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(68_808_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(2_342_000 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(72_756_000 as u64) + Weight::from_ref_time(73_245_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(e as u64)) + .saturating_add(Weight::from_ref_time(3_000 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(70_426_000 as u64) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(7_095_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_308_000 as u64) + // Standard Error: 10_000 + .saturating_add(Weight::from_ref_time(7_333_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(85_090_000 as u64) - // Standard Error: 34_000 - .saturating_add(Weight::from_ref_time(8_897_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(83_967_000 as u64) + // Standard Error: 12_000 + .saturating_add(Weight::from_ref_time(9_205_000 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(94_306_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(585_000 as u64).saturating_mul(p as u64)) + Weight::from_ref_time(93_600_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(546_000 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(70_494_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(857_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_449_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_052_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(70_467_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(890_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_326_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(998_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(70_451_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_196_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_525_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_467_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(72_857_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_442_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(73_703_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_495_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(72_589_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_682_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(73_578_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(1_546_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(70_230_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(820_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_379_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(934_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(71_027_000 as u64) - // Standard Error: 296_000 - .saturating_add(Weight::from_ref_time(177_139_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_069_000 as u64) + // Standard Error: 114_000 + .saturating_add(Weight::from_ref_time(182_540_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(70_270_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_250_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_188_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(70_088_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(1_281_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_970_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_366_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(69_538_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_283_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_352_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(69_842_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_266_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_229_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_354_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(69_754_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_230_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_202_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(70_842_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_193_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_065_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(69_670_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_281_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_252_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(69_728_000 as u64) + Weight::from_ref_time(70_049_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_770_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_823_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(70_522_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(1_767_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_519_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_815_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(71_224_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(1_752_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_953_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_834_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(70_625_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(1_763_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_299_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_818_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(71_816_000 as u64) - // Standard Error: 31_000 - .saturating_add(Weight::from_ref_time(1_852_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_141_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(70_019_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_780_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_209_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_827_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(69_881_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_783_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_980_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_831_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(70_021_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_766_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_022_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_829_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(72_156_000 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(1_712_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_030_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(70_004_000 as u64) + Weight::from_ref_time(70_170_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_820_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_833_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(70_028_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_772_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_895_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(69_159_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(1_813_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_932_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_830_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(70_033_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_760_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_091_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(69_702_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(2_512_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_025_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_556_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(68_933_000 as u64) - // Standard Error: 23_000 - .saturating_add(Weight::from_ref_time(2_501_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_910_000 as u64) + // Standard Error: 19_000 + .saturating_add(Weight::from_ref_time(2_290_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(69_447_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_555_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_268_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_550_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(69_872_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(2_459_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_126_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_340_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(69_867_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_783_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_381_000 as u64) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(69_982_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_772_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_095_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(69_822_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_779_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_471_000 as u64) + // Standard Error: 8_000 + .saturating_add(Weight::from_ref_time(1_836_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(69_511_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_806_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_302_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(69_956_000 as u64) + Weight::from_ref_time(70_097_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_788_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(70_069_000 as u64) - // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(1_789_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_166_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_845_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(69_719_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_792_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_630_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_879_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(69_709_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_800_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_101_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_861_000 as u64).saturating_mul(r as u64)) } } @@ -1265,15 +1265,15 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(2_985_000 as u64) + Weight::from_ref_time(3_089_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(14_335_000 as u64) + Weight::from_ref_time(13_917_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(891_000 as u64).saturating_mul(k as u64)) + .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(k as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -1281,9 +1281,9 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(13_905_000 as u64) + Weight::from_ref_time(14_172_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_257_000 as u64).saturating_mul(q as u64)) + .saturating_add(Weight::from_ref_time(1_301_000 as u64).saturating_mul(q as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1291,9 +1291,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(26_333_000 as u64) + Weight::from_ref_time(21_644_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(44_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1304,9 +1304,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(238_784_000 as u64) + Weight::from_ref_time(234_349_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1321,9 +1321,9 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(325_497_000 as u64) + Weight::from_ref_time(294_077_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(107_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(c as u64)) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) @@ -1338,7 +1338,7 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(201_129_000 as u64) + Weight::from_ref_time(199_028_000 as u64) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) @@ -1350,7 +1350,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(176_645_000 as u64) + Weight::from_ref_time(176_247_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1360,9 +1360,9 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(53_613_000 as u64) + Weight::from_ref_time(54_917_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1371,7 +1371,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(37_441_000 as u64) + Weight::from_ref_time(37_611_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1379,7 +1379,7 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(40_030_000 as u64) + Weight::from_ref_time(40_121_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -1390,9 +1390,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(241_426_000 as u64) - // Standard Error: 46_000 - .saturating_add(Weight::from_ref_time(37_834_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_129_000 as u64) + // Standard Error: 54_000 + .saturating_add(Weight::from_ref_time(35_413_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1403,9 +1403,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(181_406_000 as u64) - // Standard Error: 474_000 - .saturating_add(Weight::from_ref_time(206_995_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(189_418_000 as u64) + // Standard Error: 419_000 + .saturating_add(Weight::from_ref_time(207_107_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1417,9 +1417,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(198_301_000 as u64) - // Standard Error: 432_000 - .saturating_add(Weight::from_ref_time(264_877_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(203_928_000 as u64) + // Standard Error: 439_000 + .saturating_add(Weight::from_ref_time(268_983_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1431,9 +1431,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(243_754_000 as u64) - // Standard Error: 51_000 - .saturating_add(Weight::from_ref_time(41_219_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(243_800_000 as u64) + // Standard Error: 40_000 + .saturating_add(Weight::from_ref_time(38_797_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1444,9 +1444,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(239_352_000 as u64) - // Standard Error: 33_000 - .saturating_add(Weight::from_ref_time(15_228_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_667_000 as u64) + // Standard Error: 27_000 + .saturating_add(Weight::from_ref_time(15_826_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1457,9 +1457,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(240_637_000 as u64) - // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(37_717_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_116_000 as u64) + // Standard Error: 41_000 + .saturating_add(Weight::from_ref_time(35_402_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1470,9 +1470,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(241_127_000 as u64) - // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(37_481_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_515_000 as u64) + // Standard Error: 50_000 + .saturating_add(Weight::from_ref_time(35_144_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1483,9 +1483,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(246_236_000 as u64) - // Standard Error: 97_000 - .saturating_add(Weight::from_ref_time(110_095_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_087_000 as u64) + // Standard Error: 87_000 + .saturating_add(Weight::from_ref_time(110_236_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1496,9 +1496,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(241_552_000 as u64) - // Standard Error: 38_000 - .saturating_add(Weight::from_ref_time(37_189_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_774_000 as u64) + // Standard Error: 50_000 + .saturating_add(Weight::from_ref_time(35_216_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1509,9 +1509,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(239_622_000 as u64) - // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(37_630_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_146_000 as u64) + // Standard Error: 54_000 + .saturating_add(Weight::from_ref_time(35_101_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1522,9 +1522,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(240_284_000 as u64) - // Standard Error: 49_000 - .saturating_add(Weight::from_ref_time(37_375_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_096_000 as u64) + // Standard Error: 55_000 + .saturating_add(Weight::from_ref_time(34_612_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1535,9 +1535,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(241_463_000 as u64) - // Standard Error: 43_000 - .saturating_add(Weight::from_ref_time(37_313_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(242_978_000 as u64) + // Standard Error: 53_000 + .saturating_add(Weight::from_ref_time(34_780_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1549,9 +1549,9 @@ impl WeightInfo for () { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(245_287_000 as u64) - // Standard Error: 88_000 - .saturating_add(Weight::from_ref_time(99_890_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(246_175_000 as u64) + // Standard Error: 86_000 + .saturating_add(Weight::from_ref_time(99_827_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1562,9 +1562,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(168_156_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(17_991_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(168_655_000 as u64) + // Standard Error: 16_000 + .saturating_add(Weight::from_ref_time(15_635_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1575,9 +1575,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(240_833_000 as u64) - // Standard Error: 50_000 - .saturating_add(Weight::from_ref_time(35_622_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_729_000 as u64) + // Standard Error: 52_000 + .saturating_add(Weight::from_ref_time(33_477_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1588,9 +1588,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(330_765_000 as u64) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(8_609_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(296_718_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(9_616_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1601,9 +1601,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - Weight::from_ref_time(237_729_000 as u64) - // Standard Error: 488_000 - .saturating_add(Weight::from_ref_time(2_053_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(237_666_000 as u64) + // Standard Error: 497_000 + .saturating_add(Weight::from_ref_time(2_090_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1614,9 +1614,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(240_005_000 as u64) + Weight::from_ref_time(239_842_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(169_000 as u64).saturating_mul(n as u64)) + .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1629,9 +1629,9 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(240_524_000 as u64) - // Standard Error: 426_000 - .saturating_add(Weight::from_ref_time(51_863_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_563_000 as u64) + // Standard Error: 519_000 + .saturating_add(Weight::from_ref_time(52_855_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1645,9 +1645,9 @@ impl WeightInfo for () { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(250_710_000 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(132_741_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(248_136_000 as u64) + // Standard Error: 94_000 + .saturating_add(Weight::from_ref_time(137_406_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1658,9 +1658,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(245_816_000 as u64) - // Standard Error: 115_000 - .saturating_add(Weight::from_ref_time(235_313_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(253_433_000 as u64) + // Standard Error: 105_000 + .saturating_add(Weight::from_ref_time(242_337_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1672,11 +1672,11 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(469_886_000 as u64) - // Standard Error: 463_000 - .saturating_add(Weight::from_ref_time(177_286_000 as u64).saturating_mul(t as u64)) - // Standard Error: 127_000 - .saturating_add(Weight::from_ref_time(64_646_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(478_106_000 as u64) + // Standard Error: 557_000 + .saturating_add(Weight::from_ref_time(176_325_000 as u64).saturating_mul(t as u64)) + // Standard Error: 153_000 + .saturating_add(Weight::from_ref_time(67_413_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1689,18 +1689,18 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(174_414_000 as u64) - // Standard Error: 26_000 - .saturating_add(Weight::from_ref_time(29_037_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(172_751_000 as u64) + // Standard Error: 37_000 + .saturating_add(Weight::from_ref_time(26_536_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(196_960_000 as u64) - // Standard Error: 414_000 - .saturating_add(Weight::from_ref_time(412_810_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(196_276_000 as u64) + // Standard Error: 428_000 + .saturating_add(Weight::from_ref_time(416_783_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1709,9 +1709,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_493_000 as u64) - // Standard Error: 1_251_000 - .saturating_add(Weight::from_ref_time(88_835_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(532_439_000 as u64) + // Standard Error: 1_323_000 + .saturating_add(Weight::from_ref_time(93_843_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(52 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(50 as u64)) @@ -1720,9 +1720,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(512_531_000 as u64) - // Standard Error: 1_107_000 - .saturating_add(Weight::from_ref_time(67_926_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(511_358_000 as u64) + // Standard Error: 1_144_000 + .saturating_add(Weight::from_ref_time(68_754_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(52 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(50 as u64)) @@ -1731,9 +1731,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(208_848_000 as u64) - // Standard Error: 398_000 - .saturating_add(Weight::from_ref_time(400_478_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(204_133_000 as u64) + // Standard Error: 498_000 + .saturating_add(Weight::from_ref_time(406_798_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -1742,9 +1742,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(488_903_000 as u64) - // Standard Error: 1_226_000 - .saturating_add(Weight::from_ref_time(69_519_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(489_339_000 as u64) + // Standard Error: 1_269_000 + .saturating_add(Weight::from_ref_time(70_700_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(49 as u64)) @@ -1753,9 +1753,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(211_825_000 as u64) - // Standard Error: 401_000 - .saturating_add(Weight::from_ref_time(328_607_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(211_344_000 as u64) + // Standard Error: 399_000 + .saturating_add(Weight::from_ref_time(330_244_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1763,9 +1763,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(452_324_000 as u64) - // Standard Error: 1_026_000 - .saturating_add(Weight::from_ref_time(150_657_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(449_353_000 as u64) + // Standard Error: 1_027_000 + .saturating_add(Weight::from_ref_time(153_022_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1773,9 +1773,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(218_730_000 as u64) - // Standard Error: 318_000 - .saturating_add(Weight::from_ref_time(302_022_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(216_197_000 as u64) + // Standard Error: 341_000 + .saturating_add(Weight::from_ref_time(305_401_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1783,9 +1783,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(425_128_000 as u64) - // Standard Error: 875_000 - .saturating_add(Weight::from_ref_time(60_095_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(423_033_000 as u64) + // Standard Error: 878_000 + .saturating_add(Weight::from_ref_time(61_940_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1793,9 +1793,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(208_039_000 as u64) - // Standard Error: 445_000 - .saturating_add(Weight::from_ref_time(425_933_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(204_244_000 as u64) + // Standard Error: 448_000 + .saturating_add(Weight::from_ref_time(429_399_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -1804,9 +1804,9 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(518_112_000 as u64) - // Standard Error: 1_406_000 - .saturating_add(Weight::from_ref_time(159_006_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(516_945_000 as u64) + // Standard Error: 1_412_000 + .saturating_add(Weight::from_ref_time(162_098_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(52 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(49 as u64)) @@ -1819,9 +1819,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(169_573_000 as u64) - // Standard Error: 701_000 - .saturating_add(Weight::from_ref_time(1_345_943_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(170_412_000 as u64) + // Standard Error: 761_000 + .saturating_add(Weight::from_ref_time(1_367_307_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -1835,8 +1835,8 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 8_472_000 - .saturating_add(Weight::from_ref_time(17_569_902_000 as u64).saturating_mul(r as u64)) + // Standard Error: 9_269_000 + .saturating_add(Weight::from_ref_time(17_505_281_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1850,8 +1850,8 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 7_932_000 - .saturating_add(Weight::from_ref_time(17_368_706_000 as u64).saturating_mul(r as u64)) + // Standard Error: 8_780_000 + .saturating_add(Weight::from_ref_time(17_368_867_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads((158 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes((79 as u64).saturating_mul(r as u64))) } @@ -1863,11 +1863,11 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(11_036_172_000 as u64) - // Standard Error: 5_683_000 - .saturating_add(Weight::from_ref_time(1_154_945_000 as u64).saturating_mul(t as u64)) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(8_670_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(11_076_579_000 as u64) + // Standard Error: 6_568_000 + .saturating_add(Weight::from_ref_time(1_158_818_000 as u64).saturating_mul(t as u64)) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(9_731_000 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(167 as u64)) .saturating_add(RocksDbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(163 as u64)) @@ -1883,8 +1883,8 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 25_721_000 - .saturating_add(Weight::from_ref_time(22_827_927_000 as u64).saturating_mul(r as u64)) + // Standard Error: 24_125_000 + .saturating_add(Weight::from_ref_time(22_830_521_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().reads((400 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(5 as u64)) @@ -1900,9 +1900,9 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(13_991_911_000 as u64) - // Standard Error: 70_000 - .saturating_add(Weight::from_ref_time(124_789_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(13_739_440_000 as u64) + // Standard Error: 79_000 + .saturating_add(Weight::from_ref_time(126_148_000 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(249 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(247 as u64)) @@ -1915,9 +1915,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(244_026_000 as u64) - // Standard Error: 69_000 - .saturating_add(Weight::from_ref_time(58_077_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(241_753_000 as u64) + // Standard Error: 60_000 + .saturating_add(Weight::from_ref_time(55_067_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1929,8 +1929,8 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 104_000 - .saturating_add(Weight::from_ref_time(320_432_000 as u64).saturating_mul(n as u64)) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(320_367_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1941,9 +1941,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(242_548_000 as u64) - // Standard Error: 88_000 - .saturating_add(Weight::from_ref_time(70_774_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(239_849_000 as u64) + // Standard Error: 80_000 + .saturating_add(Weight::from_ref_time(67_626_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1955,8 +1955,8 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 152_000 - .saturating_add(Weight::from_ref_time(246_268_000 as u64).saturating_mul(n as u64)) + // Standard Error: 106_000 + .saturating_add(Weight::from_ref_time(247_771_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1967,9 +1967,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(242_368_000 as u64) - // Standard Error: 68_000 - .saturating_add(Weight::from_ref_time(48_368_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(242_162_000 as u64) + // Standard Error: 58_000 + .saturating_add(Weight::from_ref_time(45_169_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1981,8 +1981,8 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 94_000 - .saturating_add(Weight::from_ref_time(95_913_000 as u64).saturating_mul(n as u64)) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(97_479_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1993,9 +1993,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(239_100_000 as u64) - // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(48_043_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(240_072_000 as u64) + // Standard Error: 53_000 + .saturating_add(Weight::from_ref_time(44_847_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2007,8 +2007,8 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 93_000 - .saturating_add(Weight::from_ref_time(96_000_000 as u64).saturating_mul(n as u64)) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(97_432_000 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2019,9 +2019,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(375_902_000 as u64) - // Standard Error: 613_000 - .saturating_add(Weight::from_ref_time(2_972_514_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(374_614_000 as u64) + // Standard Error: 634_000 + .saturating_add(Weight::from_ref_time(2_968_637_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2032,9 +2032,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(260_758_000 as u64) - // Standard Error: 396_000 - .saturating_add(Weight::from_ref_time(2_069_937_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(249_022_000 as u64) + // Standard Error: 408_000 + .saturating_add(Weight::from_ref_time(2_062_013_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2047,315 +2047,315 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 1_629_000 - .saturating_add(Weight::from_ref_time(1_093_632_000 as u64).saturating_mul(r as u64)) + // Standard Error: 1_536_000 + .saturating_add(Weight::from_ref_time(1_099_219_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads((158 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes((158 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(70_130_000 as u64) + Weight::from_ref_time(70_276_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(798_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(933_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(70_439_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_717_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_309_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(2_977_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(70_647_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_112_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_165_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_686_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(70_045_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_228_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_872_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(2_374_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(71_013_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_284_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_891_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_629_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(69_846_000 as u64) + Weight::from_ref_time(69_747_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_278_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_639_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_471_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_774_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_262_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(2_142_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(68_967_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_984_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(68_808_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(2_342_000 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(72_756_000 as u64) + Weight::from_ref_time(73_245_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(e as u64)) + .saturating_add(Weight::from_ref_time(3_000 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(70_426_000 as u64) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(7_095_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_308_000 as u64) + // Standard Error: 10_000 + .saturating_add(Weight::from_ref_time(7_333_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(85_090_000 as u64) - // Standard Error: 34_000 - .saturating_add(Weight::from_ref_time(8_897_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(83_967_000 as u64) + // Standard Error: 12_000 + .saturating_add(Weight::from_ref_time(9_205_000 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(94_306_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(585_000 as u64).saturating_mul(p as u64)) + Weight::from_ref_time(93_600_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(546_000 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(70_494_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(857_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_449_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_052_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(70_467_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(890_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_326_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(998_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(70_451_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_196_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_525_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_467_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(72_857_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_442_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(73_703_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_495_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(72_589_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_682_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(73_578_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(1_546_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(70_230_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(820_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_379_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(934_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(71_027_000 as u64) - // Standard Error: 296_000 - .saturating_add(Weight::from_ref_time(177_139_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_069_000 as u64) + // Standard Error: 114_000 + .saturating_add(Weight::from_ref_time(182_540_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(70_270_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_250_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_188_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(70_088_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(1_281_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_970_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_366_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(69_538_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_283_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_352_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(69_842_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_266_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_229_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_354_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(69_754_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_230_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_202_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(70_842_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_193_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_065_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(69_670_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_281_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_252_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(69_728_000 as u64) + Weight::from_ref_time(70_049_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_770_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_823_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(70_522_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(1_767_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_519_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_815_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(71_224_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(1_752_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_953_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_834_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(70_625_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(1_763_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_299_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_818_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(71_816_000 as u64) - // Standard Error: 31_000 - .saturating_add(Weight::from_ref_time(1_852_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_141_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(70_019_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_780_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_209_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_827_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(69_881_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_783_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_980_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_831_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(70_021_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_766_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_022_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_829_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(72_156_000 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(1_712_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_030_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(70_004_000 as u64) + Weight::from_ref_time(70_170_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_820_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_833_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(70_028_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_772_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_895_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(69_159_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(1_813_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_932_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_830_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(70_033_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_760_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_091_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(69_702_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(2_512_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_025_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_556_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(68_933_000 as u64) - // Standard Error: 23_000 - .saturating_add(Weight::from_ref_time(2_501_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_910_000 as u64) + // Standard Error: 19_000 + .saturating_add(Weight::from_ref_time(2_290_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(69_447_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_555_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_268_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_550_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(69_872_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(2_459_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_126_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_340_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(69_867_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_783_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_381_000 as u64) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(69_982_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_772_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_095_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(69_822_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_779_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_471_000 as u64) + // Standard Error: 8_000 + .saturating_add(Weight::from_ref_time(1_836_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(69_511_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_806_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_302_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(69_956_000 as u64) + Weight::from_ref_time(70_097_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_788_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(70_069_000 as u64) - // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(1_789_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_166_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_845_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(69_719_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_792_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_630_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_879_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(69_709_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_800_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_101_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_861_000 as u64).saturating_mul(r as u64)) } } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index d591657ee4bd9..27865f0e61a4f 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -23,7 +23,7 @@ serde = { version = "1.0.136", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } primitive-types = { version = "0.11.1", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.3.0", optional = true } -wasmi = { version = "0.9.1", optional = true } +wasmi = { version = "0.13", optional = true } hash-db = { version = "0.15.2", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } base58 = { version = "0.2.0", optional = true } diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index 6a83e20a94618..90b7df105ecde 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -12,16 +12,10 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] -[target.'cfg(target_arch = "wasm32")'.dependencies] -wasmi = { version = "0.9.1", default-features = false, features = ["core"] } - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -wasmi = "0.9.0" - [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4", default-features = false } -wasmi = { version = "0.9.0", optional = true } +wasmi = { version = "0.13", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } @@ -40,7 +34,7 @@ std = [ "sp-io/std", "sp-std/std", "sp-wasm-interface/std", - "wasmi", + "wasmi/std", ] strict = [] wasmer-sandbox = [] diff --git a/primitives/sandbox/src/embedded_executor.rs b/primitives/sandbox/src/embedded_executor.rs index 4410e26c8d122..115c3192f3d89 100644 --- a/primitives/sandbox/src/embedded_executor.rs +++ b/primitives/sandbox/src/embedded_executor.rs @@ -22,7 +22,7 @@ use alloc::string::String; use wasmi::{ memory_units::Pages, Externals, FuncInstance, FuncRef, GlobalDescriptor, GlobalRef, ImportResolver, MemoryDescriptor, MemoryInstance, MemoryRef, Module, ModuleInstance, ModuleRef, - RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableRef, Trap, TrapKind, + RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableRef, Trap, }; use sp_std::{ @@ -113,7 +113,7 @@ impl<'a, T> Externals for GuestExternals<'a, T> { ReturnValue::Value(v) => Some(to_wasmi(v)), ReturnValue::Unit => None, }), - Err(HostError) => Err(TrapKind::Host(Box::new(DummyHostError)).into()), + Err(HostError) => Err(Trap::host(DummyHostError)), } } } diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 0ca78940fbbbc..1750ebb8cd90b 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } impl-serde = { version = "0.3.1", optional = true } -parity-wasm = { version = "0.42.2", optional = true } +parity-wasm = { version = "0.45", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 89542d8229a0c..05ccad88ec37a 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } -wasmi = { version = "0.9.1", optional = true } +wasmi = { version = "0.13", optional = true } wasmtime = { version = "0.40.1", default-features = false, optional = true } sp-std = { version = "4.0.0", default-features = false, path = "../std" } From f9fdee10ef4b37dd820406491bb526d3c470e823 Mon Sep 17 00:00:00 2001 From: Hector Bulgarini Date: Thu, 8 Sep 2022 17:57:42 +0200 Subject: [PATCH 1141/1472] Removing without_storage_info from scored-pool pallet. (#11996) * Removing without_storage_info from scored-pool pallet. * Addressing PR feedback * typo * typo * Addressing PR comments and formatting code * Removing unwanted import * Adding a map_err * cargo fmt Co-authored-by: parity-processbot <> --- frame/scored-pool/src/lib.rs | 62 +++++++++++++++++++++++----------- frame/scored-pool/src/mock.rs | 39 ++++++++++----------- frame/scored-pool/src/tests.rs | 17 ++++++++++ 3 files changed, 80 insertions(+), 38 deletions(-) diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index dd96a5df2baf9..8d4c4715096b7 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -98,10 +98,11 @@ mod mock; #[cfg(test)] mod tests; -use codec::FullCodec; +use codec::{FullCodec, MaxEncodedLen}; use frame_support::{ ensure, traits::{ChangeMembers, Currency, Get, InitializeMembers, ReservableCurrency}, + BoundedVec, }; pub use pallet::*; use sp_runtime::traits::{AtLeast32Bit, StaticLookup, Zero}; @@ -109,7 +110,12 @@ use sp_std::{fmt::Debug, prelude::*}; type BalanceOf = <>::Currency as Currency<::AccountId>>::Balance; -type PoolT = Vec<(::AccountId, Option<>::Score>)>; +type PoolT = BoundedVec< + (::AccountId, Option<>::Score>), + >::MaximumMembers, +>; +type MembersT = + BoundedVec<::AccountId, >::MaximumMembers>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// The enum is supplied when refreshing the members set. @@ -130,7 +136,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -138,6 +143,10 @@ pub mod pallet { /// The currency used for deposits. type Currency: Currency + ReservableCurrency; + /// Maximum members length allowed. + #[pallet::constant] + type MaximumMembers: Get; + /// The score attributed to a member or candidate. type Score: AtLeast32Bit + Clone @@ -146,7 +155,8 @@ pub mod pallet { + FullCodec + MaybeSerializeDeserialize + Debug - + scale_info::TypeInfo; + + scale_info::TypeInfo + + MaxEncodedLen; /// The overarching event type. type Event: From> + IsType<::Event>; @@ -207,9 +217,11 @@ pub mod pallet { InvalidIndex, /// Index does not match requested account. WrongAccountIndex, + /// Number of members exceeds `MaximumMembers`. + TooManyMembers, } - /// The current pool of candidates, stored as an ordered Vec + /// The current pool of candidates, stored as an ordered Bounded Vec /// (ordered descending by score, `None` last, highest first). #[pallet::storage] #[pallet::getter(fn pool)] @@ -229,7 +241,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn members)] pub(crate) type Members, I: 'static = ()> = - StorageValue<_, Vec, ValueQuery>; + StorageValue<_, MembersT, ValueQuery>; /// Size of the `Members` set. #[pallet::storage] @@ -263,10 +275,10 @@ pub mod pallet { }); // Sorts the `Pool` by score in a descending order. Entities which - // have a score of `None` are sorted to the beginning of the vec. + // have a score of `None` are sorted to the end of the bounded vec. pool.sort_by_key(|(_, maybe_score)| Reverse(maybe_score.unwrap_or_default())); - - >::put(self.member_count); + >::update_member_count(self.member_count) + .expect("Number of allowed members exceeded"); >::put(&pool); >::refresh_members(pool, ChangeReceiver::MembershipInitialized); } @@ -308,7 +320,8 @@ pub mod pallet { // can be inserted as last element in pool, since entities with // `None` are always sorted to the end. - >::append((who.clone(), Option::<>::Score>::None)); + >::try_append((who.clone(), Option::<>::Score>::None)) + .map_err(|_| Error::::TooManyMembers)?; >::insert(&who, true); @@ -394,7 +407,7 @@ pub mod pallet { Reverse(maybe_score.unwrap_or_default()) }) .unwrap_or_else(|l| l); - pool.insert(location, item); + pool.try_insert(location, item).map_err(|_| Error::::TooManyMembers)?; >::put(&pool); Self::deposit_event(Event::::CandidateScored); @@ -410,8 +423,7 @@ pub mod pallet { #[pallet::weight(0)] pub fn change_member_count(origin: OriginFor, count: u32) -> DispatchResult { ensure_root(origin)?; - MemberCount::::put(&count); - Ok(()) + Self::update_member_count(count).map_err(Into::into) } } } @@ -424,23 +436,28 @@ impl, I: 'static> Pallet { /// type function to invoke at the end of the method. fn refresh_members(pool: PoolT, notify: ChangeReceiver) { let count = MemberCount::::get(); + let old_members = >::get(); - let mut new_members: Vec = pool + let new_members: Vec = pool .into_iter() .filter(|(_, score)| score.is_some()) .take(count as usize) .map(|(account_id, _)| account_id) .collect(); - new_members.sort(); - let old_members = >::get(); - >::put(&new_members); + // It's safe to truncate_from at this point since MemberCount + // is verified that it does not exceed the MaximumMembers value + let mut new_members_bounded: MembersT = BoundedVec::truncate_from(new_members); + + new_members_bounded.sort(); + + >::put(&new_members_bounded); match notify { ChangeReceiver::MembershipInitialized => - T::MembershipInitialized::initialize_members(&new_members), + T::MembershipInitialized::initialize_members(&new_members_bounded), ChangeReceiver::MembershipChanged => - T::MembershipChanged::set_members_sorted(&new_members[..], &old_members[..]), + T::MembershipChanged::set_members_sorted(&new_members_bounded[..], &old_members[..]), } } @@ -486,4 +503,11 @@ impl, I: 'static> Pallet { Ok(()) } + + /// Make sure the new member count value does not exceed the MaximumMembers + fn update_member_count(new_member_count: u32) -> Result<(), Error> { + ensure!(new_member_count <= T::MaximumMembers::get(), Error::::TooManyMembers); + >::put(new_member_count); + Ok(()) + } } diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index 00c66c3bdefe8..74f084673e4c2 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_scored_pool; use frame_support::{ - ord_parameter_types, parameter_types, + bounded_vec, construct_runtime, ord_parameter_types, parameter_types, traits::{ConstU32, ConstU64, GenesisBuild}, }; use frame_system::EnsureSignedBy; @@ -34,7 +34,7 @@ use sp_runtime::{ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; -frame_support::construct_runtime!( +construct_runtime!( pub enum Test where Block = Block, NodeBlock = Block, @@ -96,13 +96,13 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub static MembersTestValue: Vec = vec![]; + pub static MembersTestValue: BoundedVec> = bounded_vec![0,10]; } pub struct TestChangeMembers; impl ChangeMembers for TestChangeMembers { fn change_members_sorted(incoming: &[u64], outgoing: &[u64], new: &[u64]) { - let mut old_plus_incoming = MembersTestValue::get().to_vec(); + let mut old_plus_incoming = MembersTestValue::get().into_inner(); old_plus_incoming.extend_from_slice(incoming); old_plus_incoming.sort(); @@ -112,13 +112,15 @@ impl ChangeMembers for TestChangeMembers { assert_eq!(old_plus_incoming, new_plus_outgoing); - MembersTestValue::mutate(|m| *m = new.to_vec()); + MembersTestValue::set(>>::truncate_from(new.to_vec())); } } impl InitializeMembers for TestChangeMembers { fn initialize_members(new_members: &[u64]) { - MembersTestValue::mutate(|m| *m = new_members.to_vec()); + MembersTestValue::set(>>::truncate_from( + new_members.to_vec(), + )); } } @@ -132,25 +134,24 @@ impl Config for Test { type Period = ConstU64<4>; type Score = u64; type ScoreOrigin = EnsureSignedBy; + type MaximumMembers = ConstU32<10>; } pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (5, 500_000), - (10, 500_000), - (15, 500_000), - (20, 500_000), - (31, 500_000), - (40, 500_000), - (99, 1), - ], + let mut balances = vec![]; + for i in 1..31 { + balances.push((i, 500_000)); } - .assimilate_storage(&mut t) - .unwrap(); + balances.push((31, 500_000)); + balances.push((40, 500_000)); + balances.push((99, 1)); + + pallet_balances::GenesisConfig:: { balances } + .assimilate_storage(&mut t) + .unwrap(); pallet_scored_pool::GenesisConfig:: { - pool: vec![(5, None), (10, Some(1)), (20, Some(2)), (31, Some(2)), (40, Some(3))], + pool: bounded_vec![(10, Some(1)), (20, Some(2)), (31, Some(2)), (40, Some(3)), (5, None)], member_count: 2, } .assimilate_storage(&mut t) diff --git a/frame/scored-pool/src/tests.rs b/frame/scored-pool/src/tests.rs index 42f0b47e8b940..1a68891be0f50 100644 --- a/frame/scored-pool/src/tests.rs +++ b/frame/scored-pool/src/tests.rs @@ -297,3 +297,20 @@ fn candidacy_resubmitting_works() { assert_eq!(ScoredPool::candidate_exists(who), true); }); } + +#[test] +fn pool_candidates_exceeded() { + new_test_ext().execute_with(|| { + for i in [1, 2, 3, 4, 6] { + let who = i as u64; + assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + let index = find_in_pool(who).expect("entity must be in pool") as u32; + assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, 99)); + } + + assert_noop!( + ScoredPool::submit_candidacy(Origin::signed(8)), + Error::::TooManyMembers + ); + }); +} From c8bfc91737b8a9e94e06578a1fc5dec80129e025 Mon Sep 17 00:00:00 2001 From: MOZGIII Date: Thu, 8 Sep 2022 20:37:23 +0400 Subject: [PATCH 1142/1472] Update ss58-registry (#12220) --- Cargo.lock | 4 ++-- primitives/core/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38439947258a0..f47ac8ba408b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10247,9 +10247,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "ss58-registry" -version = "1.18.0" +version = "1.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceb8b72a924ccfe7882d0e26144c114503760a4d1248bb5cd06c8ab2d55404cc" +checksum = "b0837b5d62f42082c9d56cd946495ae273a3c68083b637b9153341d5e465146d" dependencies = [ "Inflector", "num-format", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 27865f0e61a4f..bf54f8467d1ef 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -57,7 +57,7 @@ hex = { version = "0.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"], optional = true } -ss58-registry = { version = "1.18.0", default-features = false } +ss58-registry = { version = "1.29.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } From 5a48536a49859f83dbbbab1285311f14c192e7b1 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Thu, 8 Sep 2022 18:50:31 +0200 Subject: [PATCH 1143/1472] Add missing metadata specs to crate manifests (#12221) Some crates were missing repository or description specs, which are required for publishing crates with cargo unleash. --- bin/node/bench/Cargo.toml | 2 ++ bin/node/inspect/Cargo.toml | 1 + bin/node/primitives/Cargo.toml | 1 + bin/node/rpc/Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 1 + 5 files changed, 6 insertions(+) diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index c7a747c30ed2e..878c5d07c8e78 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -5,6 +5,8 @@ authors = ["Parity Technologies "] description = "Substrate node integration benchmarks." edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index c41681d11be1e..ede96a76206ce 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -2,6 +2,7 @@ name = "node-inspect" version = "0.9.0-dev" authors = ["Parity Technologies "] +description = "Substrate node block inspection tool." edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index bc6fa669ca4ea..65a4223a7fb9f 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -2,6 +2,7 @@ name = "node-primitives" version = "2.0.0" authors = ["Parity Technologies "] +description = "Substrate node low-level primitives." edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 07b25085b9d10..851eb2cfc5104 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -2,6 +2,7 @@ name = "node-rpc" version = "3.0.0-dev" authors = ["Parity Technologies "] +description = "Substrate node rpc methods." edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index ebec9b8b755f6..eb9c91a3baa05 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -2,6 +2,7 @@ name = "kitchensink-runtime" version = "3.0.0-dev" authors = ["Parity Technologies "] +description = "Substrate node kitchensink runtime." edition = "2021" build = "build.rs" license = "Apache-2.0" From 51f60d00db606e508f76e2b5f67f5eebe8647f2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 10 Sep 2022 20:50:59 +0100 Subject: [PATCH 1144/1472] construct_runtime: Fix generation of types behind features (#12229) * construct_runtime: Fix generation of types behind features With the recent addition of supporting features in `construct_runtime!` there was a bug overseen. The `AllPalletsWithSystem` etc type declarations would be declared twice when a certain was enabled. The problem was that in the macro we didn't feature gate the types that should be declared when there is no feature enabled. This pull request now takes care of feature gating this type behind `all(#( not(feature) ))`. So, these types will only be enabled if no of the configured features is enabled. * Fix tests * FMT --- .../procedural/src/construct_runtime/mod.rs | 138 +++++++++--------- frame/support/test/Cargo.toml | 7 +- frame/support/test/tests/pallet.rs | 78 +++++++--- scripts/ci/gitlab/pipeline/test.yml | 2 +- 4 files changed, 133 insertions(+), 92 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index cfd582d0e4472..e20cb61b7aec1 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -156,10 +156,7 @@ use parse::{ use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use std::{ - collections::{HashMap, HashSet}, - str::FromStr, -}; +use std::{collections::HashSet, str::FromStr}; use syn::{Ident, Result}; /// The fixed name of the system pallet. @@ -324,11 +321,15 @@ fn decl_all_pallets<'a>( features: &HashSet<&str>, ) -> TokenStream2 { let mut types = TokenStream2::new(); - let mut names_by_feature = features + + // Every feature set to the pallet names that should be included by this feature set. + let mut features_to_names = features .iter() + .map(|f| *f) .powerset() - .map(|feat| (feat, Vec::new())) - .collect::>(); + .map(|feat| (HashSet::from_iter(feat), Vec::new())) + .collect::, Vec<_>)>>(); + for pallet_declaration in pallet_declarations { let type_name = &pallet_declaration.name; let pallet = &pallet_declaration.path; @@ -346,21 +347,22 @@ fn decl_all_pallets<'a>( types.extend(type_decl); if pallet_declaration.cfg_pattern.is_empty() { - for names in names_by_feature.values_mut() { + for (_, names) in features_to_names.iter_mut() { names.push(&pallet_declaration.name); } } else { - for (feature_set, names) in &mut names_by_feature { + for (feature_set, names) in &mut features_to_names { // Rust tidbit: if we have multiple `#[cfg]` feature on the same item, then the // predicates listed in all `#[cfg]` attributes are effectively joined by `and()`, // meaning that all of them must match in order to activate the item let is_feature_active = pallet_declaration.cfg_pattern.iter().all(|expr| { expr.eval(|pred| match pred { - Predicate::Feature(f) => feature_set.contains(&f), - Predicate::Test => feature_set.contains(&&"test"), + Predicate::Feature(f) => feature_set.contains(f), + Predicate::Test => feature_set.contains(&"test"), _ => false, }) }); + if is_feature_active { names.push(&pallet_declaration.name); } @@ -368,11 +370,34 @@ fn decl_all_pallets<'a>( } } - let all_pallets_without_system = names_by_feature.iter().map(|(feature_set, names)| { - let mut feature_set = feature_set.iter().collect::>(); - let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); - let feature_set = feature_set.into_iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + // All possible features. This will be used below for the empty feature set. + let mut all_features = features_to_names + .iter() + .flat_map(|f| f.0.iter().cloned()) + .collect::>(); + let attribute_to_names = features_to_names + .into_iter() + .map(|(mut features, names)| { + // If this is the empty feature set, it needs to be changed to negate all available + // features. So, we ensure that there is some type declared when all features are not + // enabled. + if features.is_empty() { + let test_cfg = all_features.remove("test").then_some(quote!(test)).into_iter(); + let features = all_features.iter(); + let attr = quote!(#[cfg(all( #(not(#test_cfg)),* #(not(feature = #features)),* ))]); + + (attr, names) + } else { + let test_cfg = features.remove("test").then_some(quote!(test)).into_iter(); + let features = features.iter(); + let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #features),* ))]); + + (attr, names) + } + }) + .collect::>(); + + let all_pallets_without_system = attribute_to_names.iter().map(|(attr, names)| { let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME); quote! { #attr @@ -382,11 +407,7 @@ fn decl_all_pallets<'a>( } }); - let all_pallets_with_system = names_by_feature.iter().map(|(feature_set, names)| { - let mut feature_set = feature_set.iter().collect::>(); - let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); - let feature_set = feature_set.into_iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + let all_pallets_with_system = attribute_to_names.iter().map(|(attr, names)| { quote! { #attr /// All pallets included in the runtime as a nested tuple of types. @@ -394,28 +415,19 @@ fn decl_all_pallets<'a>( } }); - let all_pallets_without_system_reversed = - names_by_feature.iter().map(|(feature_set, names)| { - let mut feature_set = feature_set.iter().collect::>(); - let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); - let feature_set = feature_set.into_iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); - let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).rev(); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types in reversed order. - /// Excludes the System pallet. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsWithoutSystemReversed = ( #(#names,)* ); - } - }); + let all_pallets_without_system_reversed = attribute_to_names.iter().map(|(attr, names)| { + let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).rev(); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types in reversed order. + /// Excludes the System pallet. + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsWithoutSystemReversed = ( #(#names,)* ); + } + }); - let all_pallets_with_system_reversed = names_by_feature.iter().map(|(feature_set, names)| { - let mut feature_set = feature_set.iter().collect::>(); - let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); - let feature_set = feature_set.into_iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + let all_pallets_with_system_reversed = attribute_to_names.iter().map(|(attr, names)| { let names = names.iter().rev(); quote! { #attr @@ -426,35 +438,19 @@ fn decl_all_pallets<'a>( } }); - let system_pallet = - match names_by_feature[&Vec::new()].iter().find(|n| **n == SYSTEM_PALLET_NAME) { - Some(name) => name, - None => - return syn::Error::new( - proc_macro2::Span::call_site(), - "`System` pallet declaration is missing. \ - Please add this line: `System: frame_system,`", - ) - .into_compile_error(), - }; - - let all_pallets_reversed_with_system_first = - names_by_feature.iter().map(|(feature_set, names)| { - let mut feature_set = feature_set.iter().collect::>(); - let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); - let feature_set = feature_set.into_iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); - let names = std::iter::once(system_pallet) - .chain(names.iter().rev().filter(|n| **n != SYSTEM_PALLET_NAME)); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types in reversed order. - /// With the system pallet first. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsReversedWithSystemFirst = ( #(#names,)* ); - } - }); + let all_pallets_reversed_with_system_first = attribute_to_names.iter().map(|(attr, names)| { + let system = quote::format_ident!("{}", SYSTEM_PALLET_NAME); + let names = std::iter::once(&system) + .chain(names.iter().rev().filter(|n| **n != SYSTEM_PALLET_NAME).cloned()); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types in reversed order. + /// With the system pallet first. + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsReversedWithSystemFirst = ( #(#names,)* ); + } + }); quote!( #types diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index dd23d7e6b0d96..d7d3bfc98f3d7 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -47,9 +47,10 @@ std = [ "sp-version/std", ] try-runtime = ["frame-support/try-runtime"] -# WARNING: CI only execute pallet test with this feature, -# if the feature intended to be used outside, CI and this message need to be updated. -conditional-storage = [] +# WARNING: +# Only CI runs with this feature enabled. This feature is for testing stuff related to the FRAME macros +# in conjunction with rust features. +frame-feature-testing = [] # Disable ui tests disable-ui-tests = [] no-metadata-docs = ["frame-support/no-metadata-docs"] diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 907a52f1184cc..d683399482bf4 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -334,22 +334,22 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn conditional_value)] - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] pub type ConditionalValue = StorageValue<_, u32>; - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] #[pallet::storage] #[pallet::getter(fn conditional_map)] pub type ConditionalMap = StorageMap<_, Twox64Concat, u16, u32, OptionQuery, GetDefault, ConstU32<12>>; - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] #[pallet::storage] #[pallet::getter(fn conditional_double_map)] pub type ConditionalDoubleMap = StorageDoubleMap<_, Blake2_128Concat, u8, Twox64Concat, u16, u32>; - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] #[pallet::storage] #[pallet::getter(fn conditional_nmap)] pub type ConditionalNMap = @@ -550,7 +550,9 @@ pub mod pallet2 { #[frame_support::pallet] pub mod pallet3 { #[pallet::config] - pub trait Config: frame_system::Config {} + pub trait Config: frame_system::Config::Origin> { + type Origin; + } #[pallet::pallet] pub struct Pallet(_); @@ -612,6 +614,11 @@ impl pallet2::Config for Runtime { impl pallet4::Config for Runtime {} +#[cfg(feature = "frame-feature-testing")] +impl pallet3::Config for Runtime { + type Origin = Origin; +} + pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; @@ -626,7 +633,7 @@ frame_support::construct_runtime!( System: frame_system exclude_parts { Pallet, Storage }, Example: pallet, Example2: pallet2 exclude_parts { Call }, - #[cfg(feature = "example3")] + #[cfg(feature = "frame-feature-testing")] Example3: pallet3, Example4: pallet4 use_parts { Call }, } @@ -1024,7 +1031,7 @@ fn storage_expand() { Err(pallet::Error::::NonExistentStorageValue), ); - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] { pallet::ConditionalValue::::put(1); pallet::ConditionalMap::::insert(1, 2); @@ -1164,8 +1171,10 @@ fn migrate_from_pallet_version_to_storage_version() { AllPalletsWithSystem, >(&db_weight); - // 4 pallets, 2 writes and every write costs 5 weight. - assert_eq!(Weight::from_ref_time(4 * 2 * 5), weight); + let pallet_num = if cfg!(feature = "frame-feature-testing") { 5 } else { 4 }; + + // `pallet_num` pallets, 2 writes and every write costs 5 weight. + assert_eq!(Weight::from_ref_time(pallet_num * 2 * 5), weight); // All pallet versions should be removed assert!(sp_io::storage::get(&pallet_version_key(Example::name())).is_none()); @@ -1332,7 +1341,7 @@ fn metadata() { default: vec![1, 1], docs: vec![], }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] StorageEntryMetadata { name: "ConditionalValue", modifier: StorageEntryModifier::Optional, @@ -1340,7 +1349,7 @@ fn metadata() { default: vec![0], docs: vec![], }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] StorageEntryMetadata { name: "ConditionalMap", modifier: StorageEntryModifier::Optional, @@ -1352,7 +1361,7 @@ fn metadata() { default: vec![0], docs: vec![], }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] StorageEntryMetadata { name: "ConditionalDoubleMap", modifier: StorageEntryModifier::Optional, @@ -1367,7 +1376,7 @@ fn metadata() { default: vec![0], docs: vec![], }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] StorageEntryMetadata { name: "ConditionalNMap", modifier: StorageEntryModifier::Optional, @@ -1489,6 +1498,16 @@ fn metadata() { constants: vec![], error: None, }, + #[cfg(feature = "frame-feature-testing")] + PalletMetadata { + index: 3, + name: "Example3", + storage: None, + calls: None, + event: None, + constants: vec![], + error: None, + }, ]; let empty_doc = pallets[0].event.as_ref().unwrap().ty.type_info().docs().is_empty() && @@ -1633,7 +1652,7 @@ fn test_storage_info() { max_values: None, max_size: Some(16 + 1 + 8 + 2 + 16), }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] { StorageInfo { pallet_name: b"Example".to_vec(), @@ -1643,7 +1662,7 @@ fn test_storage_info() { max_size: Some(4), } }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] { StorageInfo { pallet_name: b"Example".to_vec(), @@ -1653,7 +1672,7 @@ fn test_storage_info() { max_size: Some(8 + 2 + 4), } }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] { StorageInfo { pallet_name: b"Example".to_vec(), @@ -1663,7 +1682,7 @@ fn test_storage_info() { max_size: Some(16 + 1 + 8 + 2 + 4), } }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] { StorageInfo { pallet_name: b"Example".to_vec(), @@ -1730,27 +1749,42 @@ fn assert_type_all_pallets_reversed_with_system_first_is_correct() { // Just ensure the 2 types are same. #[allow(deprecated)] fn _a(_t: AllPalletsReversedWithSystemFirst) {} + #[cfg(not(feature = "frame-feature-testing"))] fn _b(t: (System, Example4, Example2, Example)) { _a(t) } + #[cfg(feature = "frame-feature-testing")] + fn _b(t: (System, Example4, Example3, Example2, Example)) { + _a(t) + } } #[test] fn assert_type_all_pallets_with_system_is_correct() { // Just ensure the 2 types are same. fn _a(_t: AllPalletsWithSystem) {} + #[cfg(not(feature = "frame-feature-testing"))] fn _b(t: (System, Example, Example2, Example4)) { _a(t) } + #[cfg(feature = "frame-feature-testing")] + fn _b(t: (System, Example, Example2, Example3, Example4)) { + _a(t) + } } #[test] fn assert_type_all_pallets_without_system_is_correct() { // Just ensure the 2 types are same. fn _a(_t: AllPalletsWithoutSystem) {} + #[cfg(not(feature = "frame-feature-testing"))] fn _b(t: (Example, Example2, Example4)) { _a(t) } + #[cfg(feature = "frame-feature-testing")] + fn _b(t: (Example, Example2, Example3, Example4)) { + _a(t) + } } #[test] @@ -1758,9 +1792,14 @@ fn assert_type_all_pallets_with_system_reversed_is_correct() { // Just ensure the 2 types are same. #[allow(deprecated)] fn _a(_t: AllPalletsWithSystemReversed) {} + #[cfg(not(feature = "frame-feature-testing"))] fn _b(t: (Example4, Example2, Example, System)) { _a(t) } + #[cfg(feature = "frame-feature-testing")] + fn _b(t: (Example4, Example3, Example2, Example, System)) { + _a(t) + } } #[test] @@ -1768,9 +1807,14 @@ fn assert_type_all_pallets_without_system_reversed_is_correct() { // Just ensure the 2 types are same. #[allow(deprecated)] fn _a(_t: AllPalletsWithoutSystemReversed) {} + #[cfg(not(feature = "frame-feature-testing"))] fn _b(t: (Example4, Example2, Example)) { _a(t) } + #[cfg(feature = "frame-feature-testing")] + fn _b(t: (Example4, Example3, Example2, Example)) { + _a(t) + } } #[test] diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 8036e2cec26bb..50916a37fcf55 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -251,7 +251,7 @@ test-frame-support: RUN_UI_TESTS: 1 script: - rusty-cachier snapshot create - - time cargo test -p frame-support-test --features=conditional-storage,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec + - time cargo test -p frame-support-test --features=frame-feature-testing,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout - rusty-cachier cache upload From 7de3d7870f63a525977fd4e91cda16039e7b1d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 12 Sep 2022 11:25:56 +0100 Subject: [PATCH 1145/1472] Remove native call (#12201) * Remove native call With the recent introduction of staging runtime apis the native call wasn't supported anymore. This removes the entire support for this as it is not used anymore. * FMT * Fix benchmarks * FIX ui tests --- bin/node/executor/benches/bench.rs | 44 +--- bin/node/executor/tests/basic.rs | 204 ++++------------ bin/node/executor/tests/common.rs | 51 +--- bin/node/executor/tests/fees.rs | 59 +---- client/api/src/call_executor.rs | 15 +- client/api/src/execution_extensions.rs | 4 +- client/executor/src/native_executor.rs | 82 +++---- client/service/src/client/call_executor.rs | 40 +--- client/service/src/client/client.rs | 24 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 4 +- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 4 +- .../api/proc-macro/src/impl_runtime_apis.rs | 40 ++-- primitives/api/src/lib.rs | 22 +- primitives/core/src/lib.rs | 81 ------- primitives/core/src/traits.rs | 9 +- primitives/state-machine/src/lib.rs | 220 +++++------------- test-utils/runtime/src/system.rs | 19 +- 17 files changed, 214 insertions(+), 708 deletions(-) diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index a1d31a5a966db..3ad5dc61d528f 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -31,7 +31,6 @@ use sc_executor::{Externalities, NativeElseWasmExecutor, RuntimeVersionOf, WasmE use sp_core::{ storage::well_known_keys, traits::{CodeExecutor, RuntimeCode}, - NativeOrEncoded, NeverNativeValue, }; use sp_runtime::traits::BlakeTwo256; use sp_state_machine::TestExternalities as CoreTestExternalities; @@ -112,46 +111,24 @@ fn construct_block( // execute the block to get the real header. executor - .call:: _>( - ext, - &runtime_code, - "Core_initialize_block", - &header.encode(), - true, - None, - ) + .call(ext, &runtime_code, "Core_initialize_block", &header.encode(), true) .0 .unwrap(); for i in extrinsics.iter() { executor - .call:: _>( - ext, - &runtime_code, - "BlockBuilder_apply_extrinsic", - &i.encode(), - true, - None, - ) + .call(ext, &runtime_code, "BlockBuilder_apply_extrinsic", &i.encode(), true) .0 .unwrap(); } - let header = match executor - .call:: _>( - ext, - &runtime_code, - "BlockBuilder_finalize_block", - &[0u8; 0], - true, - None, - ) - .0 - .unwrap() - { - NativeOrEncoded::Native(_) => unreachable!(), - NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), - }; + let header = Header::decode( + &mut &executor + .call(ext, &runtime_code, "BlockBuilder_finalize_block", &[0u8; 0], true) + .0 + .unwrap()[..], + ) + .unwrap(); let hash = header.blake2_256(); (Block { header, extrinsics }.encode(), hash.into()) @@ -218,13 +195,12 @@ fn bench_execute_block(c: &mut Criterion) { |test_ext| { for block in blocks.iter() { executor - .call:: _>( + .call( &mut test_ext.ext(), &runtime_code, "Core_execute_block", &block.0, use_native, - None, ) .0 .unwrap(); diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 3426df5872c35..35063f6933c98 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -21,7 +21,7 @@ use frame_support::{ weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Weight}, }; use frame_system::{self, AccountInfo, EventRecord, Phase}; -use sp_core::{storage::well_known_keys, traits::Externalities, NeverNativeValue}; +use sp_core::{storage::well_known_keys, traits::Externalities}; use sp_runtime::{ traits::Hash as HashT, transaction_validity::InvalidTransaction, ApplyExtrinsicResult, }; @@ -187,25 +187,14 @@ fn panic_execution_with_foreign_code_gives_error() { t.insert(>::hashed_key().to_vec(), 69_u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - true, - None, - ) - .0; + let r = + executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) + .0; assert!(r.is_ok()); - let v = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ) - .0 - .unwrap(); - let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap(); + let v = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true) + .0 + .unwrap(); + let r = ApplyExtrinsicResult::decode(&mut &v[..]).unwrap(); assert_eq!(r, Err(InvalidTransaction::Payment.into())); } @@ -219,25 +208,14 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() { t.insert(>::hashed_key().to_vec(), 69_u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - true, - None, - ) - .0; + let r = + executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) + .0; assert!(r.is_ok()); - let v = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ) - .0 - .unwrap(); - let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap(); + let v = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true) + .0 + .unwrap(); + let r = ApplyExtrinsicResult::decode(&mut &v[..]).unwrap(); assert_eq!(r, Err(InvalidTransaction::Payment.into())); } @@ -266,26 +244,14 @@ fn successful_execution_with_native_equivalent_code_gives_ok() { ); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - true, - None, - ) - .0; + let r = + executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) + .0; assert!(r.is_ok()); let fees = t.execute_with(|| transfer_fee(&xt())); - let r = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ) - .0; + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; assert!(r.is_ok()); t.execute_with(|| { @@ -319,26 +285,14 @@ fn successful_execution_with_foreign_code_gives_ok() { ); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - true, - None, - ) - .0; + let r = + executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) + .0; assert!(r.is_ok()); let fees = t.execute_with(|| transfer_fee(&xt())); - let r = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ) - .0; + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; assert!(r.is_ok()); t.execute_with(|| { @@ -361,15 +315,7 @@ fn full_native_block_import_works() { .get_dispatch_info() .weight; - executor_call:: _>( - &mut t, - "Core_execute_block", - &block1.0, - true, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block1.0, true).0.unwrap(); t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); @@ -441,15 +387,7 @@ fn full_native_block_import_works() { fees = t.execute_with(|| transfer_fee(&xt())); - executor_call:: _>( - &mut t, - "Core_execute_block", - &block2.0, - true, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block2.0, true).0.unwrap(); t.execute_with(|| { assert_eq!( @@ -579,15 +517,7 @@ fn full_wasm_block_import_works() { let mut alice_last_known_balance: Balance = Default::default(); let mut fees = t.execute_with(|| transfer_fee(&xt())); - executor_call:: _>( - &mut t, - "Core_execute_block", - &block1.0, - false, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block1.0, false).0.unwrap(); t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); @@ -597,15 +527,7 @@ fn full_wasm_block_import_works() { fees = t.execute_with(|| transfer_fee(&xt())); - executor_call:: _>( - &mut t, - "Core_execute_block", - &block2.0, - false, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block2.0, false).0.unwrap(); t.execute_with(|| { assert_eq!( @@ -757,9 +679,7 @@ fn deploying_wasm_contract_should_work() { let mut t = new_test_ext(compact_code_unwrap()); - executor_call:: _>(&mut t, "Core_execute_block", &b.0, false, None) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &b.0, false).0.unwrap(); t.execute_with(|| { // Verify that the contract does exist by querying some of its storage items @@ -778,14 +698,8 @@ fn wasm_big_block_import_fails() { set_heap_pages(&mut t.ext(), 4); - let result = executor_call:: _>( - &mut t, - "Core_execute_block", - &block_with_size(42, 0, 120_000).0, - false, - None, - ) - .0; + let result = + executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, false).0; assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) }))) } @@ -793,15 +707,9 @@ fn wasm_big_block_import_fails() { fn native_big_block_import_succeeds() { let mut t = new_test_ext(compact_code_unwrap()); - executor_call:: _>( - &mut t, - "Core_execute_block", - &block_with_size(42, 0, 120_000).0, - true, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, true) + .0 + .unwrap(); } #[test] @@ -812,15 +720,11 @@ fn native_big_block_import_fails_on_fallback() { // block. set_heap_pages(&mut t.ext(), 8); - assert!(executor_call:: _>( - &mut t, - "Core_execute_block", - &block_with_size(42, 0, 120_000).0, - false, - None, - ) - .0 - .is_err()); + assert!( + executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, false,) + .0 + .is_err() + ); } #[test] @@ -837,25 +741,17 @@ fn panic_execution_gives_error() { t.insert(>::hashed_key().to_vec(), 0_u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( + let r = executor_call( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), false, - None, ) .0; assert!(r.is_ok()); - let r = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - false, - None, - ) - .0 - .unwrap() - .into_encoded(); + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), false) + .0 + .unwrap(); let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap(); assert_eq!(r, Err(InvalidTransaction::Payment.into())); } @@ -885,12 +781,11 @@ fn successful_execution_gives_ok() { ); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( + let r = executor_call( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), false, - None, ) .0; assert!(r.is_ok()); @@ -900,16 +795,9 @@ fn successful_execution_gives_ok() { let fees = t.execute_with(|| transfer_fee(&xt())); - let r = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - false, - None, - ) - .0 - .unwrap() - .into_encoded(); + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), false) + .0 + .unwrap(); ApplyExtrinsicResult::decode(&mut &r[..]) .unwrap() .expect("Extrinsic could not be applied") diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index 407a1e09f8efb..803ec78329eea 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -27,7 +27,6 @@ use sp_core::{ crypto::KeyTypeId, sr25519::Signature, traits::{CodeExecutor, RuntimeCode}, - NativeOrEncoded, NeverNativeValue, }; use sp_runtime::{ traits::{BlakeTwo256, Header as HeaderT}, @@ -99,17 +98,12 @@ pub fn executor() -> NativeElseWasmExecutor { NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2) } -pub fn executor_call< - R: Decode + Encode + PartialEq, - NC: FnOnce() -> std::result::Result> - + std::panic::UnwindSafe, ->( +pub fn executor_call( t: &mut TestExternalities, method: &str, data: &[u8], use_native: bool, - native_call: Option, -) -> (Result>, bool) { +) -> (Result>, bool) { let mut t = t.ext(); let code = t.storage(sp_core::storage::well_known_keys::CODE).unwrap(); @@ -120,7 +114,7 @@ pub fn executor_call< heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()), }; sp_tracing::try_init_simple(); - executor().call::(&mut t, &runtime_code, method, data, use_native, native_call) + executor().call(&mut t, &runtime_code, method, data, use_native) } pub fn new_test_ext(code: &[u8]) -> TestExternalities { @@ -171,29 +165,15 @@ pub fn construct_block( }; // execute the block to get the real header. - executor_call:: _>( - env, - "Core_initialize_block", - &header.encode(), - true, - None, - ) - .0 - .unwrap(); + executor_call(env, "Core_initialize_block", &header.encode(), true).0.unwrap(); for extrinsic in extrinsics.iter() { // Try to apply the `extrinsic`. It should be valid, in the sense that it passes // all pre-inclusion checks. - let r = executor_call:: _>( - env, - "BlockBuilder_apply_extrinsic", - &extrinsic.encode(), - true, - None, - ) - .0 - .expect("application of an extrinsic failed") - .into_encoded(); + let r = executor_call(env, "BlockBuilder_apply_extrinsic", &extrinsic.encode(), true) + .0 + .expect("application of an extrinsic failed"); + match ApplyExtrinsicResult::decode(&mut &r[..]) .expect("apply result deserialization failed") { @@ -202,19 +182,10 @@ pub fn construct_block( } } - let header = match executor_call:: _>( - env, - "BlockBuilder_finalize_block", - &[0u8; 0], - true, - None, + let header = Header::decode( + &mut &executor_call(env, "BlockBuilder_finalize_block", &[0u8; 0], true).0.unwrap()[..], ) - .0 - .unwrap() - { - NativeOrEncoded::Native(_) => unreachable!(), - NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), - }; + .unwrap(); let hash = header.blake2_256(); (Block { header, extrinsics }.encode(), hash.into()) diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index dd1318254d9b7..c5c2d01ca5c13 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -26,7 +26,6 @@ use kitchensink_runtime::{ }; use node_primitives::Balance; use node_testing::keyring::*; -use sp_core::NeverNativeValue; use sp_runtime::{traits::One, Perbill}; pub mod common; @@ -94,15 +93,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { ); // execute a big block. - executor_call:: _>( - &mut t, - "Core_execute_block", - &block1.0, - true, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block1.0, true).0.unwrap(); // weight multiplier is increased for next block. t.execute_with(|| { @@ -113,15 +104,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { }); // execute a big block. - executor_call:: _>( - &mut t, - "Core_execute_block", - &block2.0, - true, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block2.0, true).0.unwrap(); // weight multiplier is increased for next block. t.execute_with(|| { @@ -166,24 +149,12 @@ fn transaction_fee_is_correct() { function: Call::Balances(default_transfer_call()), }); - let r = executor_call:: _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - true, - None, - ) - .0; + let r = + executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) + .0; assert!(r.is_ok()); - let r = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt.clone()), - true, - None, - ) - .0; + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt.clone()), true).0; assert!(r.is_ok()); t.execute_with(|| { @@ -274,14 +245,7 @@ fn block_weight_capacity_report() { len / 1024 / 1024, ); - let r = executor_call:: _>( - &mut t, - "Core_execute_block", - &block.0, - true, - None, - ) - .0; + let r = executor_call(&mut t, "Core_execute_block", &block.0, true).0; println!(" || Result = {:?}", r); assert!(r.is_ok()); @@ -342,14 +306,7 @@ fn block_length_capacity_report() { len / 1024 / 1024, ); - let r = executor_call:: _>( - &mut t, - "Core_execute_block", - &block.0, - true, - None, - ) - .0; + let r = executor_call(&mut t, "Core_execute_block", &block.0, true).0; println!(" || Result = {:?}", r); assert!(r.is_ok()); diff --git a/client/api/src/call_executor.rs b/client/api/src/call_executor.rs index 738f932a47bf0..949fd16a30704 100644 --- a/client/api/src/call_executor.rs +++ b/client/api/src/call_executor.rs @@ -18,13 +18,11 @@ //! A method call executor interface. -use codec::{Decode, Encode}; use sc_executor::{RuntimeVersion, RuntimeVersionOf}; -use sp_core::NativeOrEncoded; use sp_externalities::Extensions; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_state_machine::{ExecutionManager, ExecutionStrategy, OverlayedChanges, StorageProof}; -use std::{cell::RefCell, panic::UnwindSafe, result}; +use std::cell::RefCell; use crate::execution_extensions::ExecutionExtensions; use sp_api::{ProofRecorder, StorageTransactionCache}; @@ -68,11 +66,9 @@ pub trait CallExecutor: RuntimeVersionOf { /// of the execution context. fn contextual_call< EM: Fn( - Result, Self::Error>, - Result, Self::Error>, - ) -> Result, Self::Error>, - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, + Result, Self::Error>, + Result, Self::Error>, + ) -> Result, Self::Error>, >( &self, at: &BlockId, @@ -85,10 +81,9 @@ pub trait CallExecutor: RuntimeVersionOf { >, >, execution_manager: ExecutionManager, - native_call: Option, proof_recorder: &Option>, extensions: Option, - ) -> sp_blockchain::Result> + ) -> sp_blockchain::Result> where ExecutionManager: Clone; diff --git a/client/api/src/execution_extensions.rs b/client/api/src/execution_extensions.rs index 574687312c82b..07a483bc3eaf2 100644 --- a/client/api/src/execution_extensions.rs +++ b/client/api/src/execution_extensions.rs @@ -201,11 +201,11 @@ impl ExecutionExtensions { /// /// Based on the execution context and capabilities it produces /// the right manager and extensions object to support desired set of APIs. - pub fn manager_and_extensions( + pub fn manager_and_extensions( &self, at: &BlockId, context: ExecutionContext, - ) -> (ExecutionManager>, Extensions) { + ) -> (ExecutionManager>, Extensions) { let manager = match context { ExecutionContext::BlockConstruction => self.strategies.block_construction.get_manager(), ExecutionContext::Syncing => self.strategies.syncing.get_manager(), diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 7610c4c8f32e0..b164b427e306d 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -27,22 +27,18 @@ use std::{ marker::PhantomData, panic::{AssertUnwindSafe, UnwindSafe}, path::PathBuf, - result, sync::{ atomic::{AtomicU64, Ordering}, mpsc, Arc, }, }; -use codec::{Decode, Encode}; +use codec::Encode; use sc_executor_common::{ runtime_blob::RuntimeBlob, wasm_runtime::{AllocationStats, InvokeMethod, WasmInstance, WasmModule}, }; -use sp_core::{ - traits::{CodeExecutor, Externalities, RuntimeCode, RuntimeSpawn, RuntimeSpawnExt}, - NativeOrEncoded, -}; +use sp_core::traits::{CodeExecutor, Externalities, RuntimeCode, RuntimeSpawn, RuntimeSpawnExt}; use sp_externalities::ExternalitiesExt as _; use sp_tasks::new_async_externalities; use sp_version::{GetNativeVersion, NativeVersion, RuntimeVersion}; @@ -339,18 +335,14 @@ where { type Error = Error; - fn call< - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> + UnwindSafe, - >( + fn call( &self, ext: &mut dyn Externalities, runtime_code: &RuntimeCode, method: &str, data: &[u8], _use_native: bool, - _native_call: Option, - ) -> (Result>, bool) { + ) -> (Result>, bool) { tracing::trace!( target: "executor", %method, @@ -363,7 +355,7 @@ where |module, mut instance, _onchain_version, mut ext| { with_externalities_safe(&mut **ext, move || { preregister_builtin_ext(module.clone()); - instance.call_export(method, data).map(NativeOrEncoded::Encoded) + instance.call_export(method, data) }) }, ); @@ -594,18 +586,14 @@ fn preregister_builtin_ext(module: Arc) { impl CodeExecutor for NativeElseWasmExecutor { type Error = Error; - fn call< - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> + UnwindSafe, - >( + fn call( &self, ext: &mut dyn Externalities, runtime_code: &RuntimeCode, method: &str, data: &[u8], use_native: bool, - native_call: Option, - ) -> (Result>, bool) { + ) -> (Result>, bool) { tracing::trace!( target: "executor", function = %method, @@ -623,49 +611,31 @@ impl CodeExecutor for NativeElseWasmExecut let can_call_with = onchain_version.can_call_with(&self.native_version.runtime_version); - match (use_native, can_call_with, native_call) { - (_, false, _) | (false, _, _) => { - if !can_call_with { - tracing::trace!( - target: "executor", - native = %self.native_version.runtime_version, - chain = %onchain_version, - "Request for native execution failed", - ); - } - - with_externalities_safe(&mut **ext, move || { - preregister_builtin_ext(module.clone()); - instance.call_export(method, data).map(NativeOrEncoded::Encoded) - }) - }, - (true, true, Some(call)) => { - tracing::trace!( - target: "executor", - native = %self.native_version.runtime_version, - chain = %onchain_version, - "Request for native execution with native call succeeded" - ); - - used_native = true; - let res = with_externalities_safe(&mut **ext, move || (call)()) - .and_then(|r| r.map(NativeOrEncoded::Native).map_err(Error::ApiError)); - - Ok(res) - }, - _ => { + if use_native && can_call_with { + tracing::trace!( + target: "executor", + native = %self.native_version.runtime_version, + chain = %onchain_version, + "Request for native execution succeeded", + ); + + used_native = true; + Ok(with_externalities_safe(&mut **ext, move || D::dispatch(method, data))? + .ok_or_else(|| Error::MethodNotFound(method.to_owned()))) + } else { + if !can_call_with { tracing::trace!( target: "executor", native = %self.native_version.runtime_version, chain = %onchain_version, - "Request for native execution succeeded", + "Request for native execution failed", ); + } - used_native = true; - Ok(with_externalities_safe(&mut **ext, move || D::dispatch(method, data))? - .map(NativeOrEncoded::Encoded) - .ok_or_else(|| Error::MethodNotFound(method.to_owned()))) - }, + with_externalities_safe(&mut **ext, move || { + preregister_builtin_ext(module.clone()); + instance.call_export(method, data) + }) } }, ); diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index de851ac848919..e39436ec641d7 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -17,21 +17,17 @@ // along with this program. If not, see . use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes}; -use codec::{Decode, Encode}; use sc_client_api::{backend, call_executor::CallExecutor, HeaderBackend}; use sc_executor::{RuntimeVersion, RuntimeVersionOf}; use sp_api::{ProofRecorder, StorageTransactionCache}; -use sp_core::{ - traits::{CodeExecutor, RuntimeCode, SpawnNamed}, - NativeOrEncoded, NeverNativeValue, -}; +use sp_core::traits::{CodeExecutor, RuntimeCode, SpawnNamed}; use sp_externalities::Extensions; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_state_machine::{ backend::AsTrieBackend, ExecutionManager, ExecutionStrategy, Ext, OverlayedChanges, StateMachine, StorageProof, }; -use std::{cell::RefCell, panic::UnwindSafe, result, sync::Arc}; +use std::{cell::RefCell, sync::Arc}; /// Call executor that executes methods locally, querying all required /// data from local backend. @@ -162,7 +158,7 @@ where sp_blockchain::Error::UnknownBlock(format!("Could not find block hash for {:?}", at)) })?; - let return_data = StateMachine::new( + let mut sm = StateMachine::new( &state, &mut changes, &self.executor, @@ -172,22 +168,17 @@ where &runtime_code, self.spawn_handle.clone(), ) - .set_parent_hash(at_hash) - .execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - strategy.get_manager(), - None, - )?; + .set_parent_hash(at_hash); - Ok(return_data.into_encoded()) + sm.execute_using_consensus_failure_handler(strategy.get_manager()) + .map_err(Into::into) } fn contextual_call< EM: Fn( - Result, Self::Error>, - Result, Self::Error>, - ) -> Result, Self::Error>, - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, + Result, Self::Error>, + Result, Self::Error>, + ) -> Result, Self::Error>, >( &self, at: &BlockId, @@ -196,10 +187,9 @@ where changes: &RefCell, storage_transaction_cache: Option<&RefCell>>, execution_manager: ExecutionManager, - native_call: Option, recorder: &Option>, extensions: Option, - ) -> Result, sp_blockchain::Error> + ) -> Result, sp_blockchain::Error> where ExecutionManager: Clone, { @@ -242,10 +232,7 @@ where ) .with_storage_transaction_cache(storage_transaction_cache.as_deref_mut()) .set_parent_hash(at_hash); - state_machine.execute_using_consensus_failure_handler( - execution_manager, - native_call.map(|n| || (n)().map_err(|e| Box::new(e) as Box<_>)), - ) + state_machine.execute_using_consensus_failure_handler(execution_manager) }, None => { let mut state_machine = StateMachine::new( @@ -260,10 +247,7 @@ where ) .with_storage_transaction_cache(storage_transaction_cache.as_deref_mut()) .set_parent_hash(at_hash); - state_machine.execute_using_consensus_failure_handler( - execution_manager, - native_call.map(|n| || (n)().map_err(|e| Box::new(e) as Box<_>)), - ) + state_machine.execute_using_consensus_failure_handler(execution_manager) }, } .map_err(Into::into) diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 9d6a2e0457a84..27561046c3481 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -22,7 +22,6 @@ use super::{ block_rules::{BlockRules, LookupResult as BlockLookupResult}, genesis, }; -use codec::{Decode, Encode}; use log::{info, trace, warn}; use parking_lot::{Mutex, RwLock}; use prometheus_endpoint::Registry; @@ -59,12 +58,9 @@ use sp_blockchain::{ use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; -use sp_core::{ - storage::{ - well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, Storage, StorageChild, - StorageData, StorageKey, - }, - NativeOrEncoded, +use sp_core::storage::{ + well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, Storage, StorageChild, StorageData, + StorageKey, }; #[cfg(feature = "test-helpers")] use sp_keystore::SyncCryptoStorePtr; @@ -85,9 +81,7 @@ use sp_trie::{CompactProof, StorageProof}; use std::{ collections::{hash_map::DefaultHasher, HashMap, HashSet}, marker::PhantomData, - panic::UnwindSafe, path::PathBuf, - result, sync::Arc, }; @@ -1659,27 +1653,23 @@ where { type StateBackend = B::State; - fn call_api_at< - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, - >( + fn call_api_at( &self, - params: CallApiAtParams, - ) -> Result, sp_api::ApiError> { + params: CallApiAtParams, + ) -> Result, sp_api::ApiError> { let at = params.at; let (manager, extensions) = self.execution_extensions.manager_and_extensions(at, params.context); self.executor - .contextual_call:: _, _, _>( + .contextual_call( at, params.function, ¶ms.arguments, params.overlayed_changes, Some(params.storage_transaction_cache), manager, - params.native_call, params.recorder, Some(extensions), ) diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index e674e49eddbe5..5d159ec961c7f 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index ecdc18263432e..4671855431b27 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index 5ab8fa0521699..7a26ead0f586a 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -449,28 +449,30 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { } let res = (|| { - let version = #crate_::CallApiAt::<__SR_API_BLOCK__>::runtime_version_at(self.call, at)?; - - let params = #crate_::CallApiAtParams::<_, fn() -> _, _> { - at, - function: (*fn_name)(version), - native_call: None, - arguments: params, - overlayed_changes: &self.changes, - storage_transaction_cache: &self.storage_transaction_cache, - context, - recorder: &self.recorder, - }; - - #crate_::CallApiAt::<__SR_API_BLOCK__>::call_api_at::<#crate_::NeverNativeValue, _>( - self.call, - params, - ) - })(); + let version = #crate_::CallApiAt::<__SR_API_BLOCK__>::runtime_version_at( + self.call, + at, + )?; + + let params = #crate_::CallApiAtParams { + at, + function: (*fn_name)(version), + arguments: params, + overlayed_changes: &self.changes, + storage_transaction_cache: &self.storage_transaction_cache, + context, + recorder: &self.recorder, + }; + + #crate_::CallApiAt::<__SR_API_BLOCK__>::call_api_at( + self.call, + params, + ) + })(); self.commit_or_rollback(std::result::Result::is_ok(&res)); - res.map(#crate_::NativeOrEncoded::into_encoded) + res } }); diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index 353ebd91cf5df..91d4b07a1cefc 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -83,8 +83,6 @@ use sp_core::OpaqueMetadata; pub use sp_core::{offchain, ExecutionContext}; #[doc(hidden)] #[cfg(feature = "std")] -pub use sp_core::{NativeOrEncoded, NeverNativeValue}; -#[cfg(feature = "std")] pub use sp_runtime::StateVersion; #[doc(hidden)] pub use sp_runtime::{ @@ -102,14 +100,12 @@ pub use sp_state_machine::{ backend::AsTrieBackend, Backend as StateBackend, InMemoryBackend, OverlayedChanges, StorageProof, TrieBackend, TrieBackendBuilder, }; -#[cfg(feature = "std")] -use sp_std::result; #[doc(hidden)] pub use sp_std::{mem, slice}; #[doc(hidden)] pub use sp_version::{create_apis_vec, ApiId, ApisVec, RuntimeVersion}; #[cfg(feature = "std")] -use std::{cell::RefCell, panic::UnwindSafe}; +use std::cell::RefCell; /// Maximum nesting level for extrinsics. pub const MAX_EXTRINSIC_DEPTH: u32 = 256; @@ -590,16 +586,11 @@ pub trait ApiExt { /// Parameters for [`CallApiAt::call_api_at`]. #[cfg(feature = "std")] -pub struct CallApiAtParams<'a, Block: BlockT, NC, Backend: StateBackend>> { +pub struct CallApiAtParams<'a, Block: BlockT, Backend: StateBackend>> { /// The block id that determines the state that should be setup when calling the function. pub at: &'a BlockId, /// The name of the function that should be called. pub function: &'static str, - /// An optional native call that calls the `function`. This is an optimization to call into a - /// native runtime without requiring to encode/decode the parameters. The native runtime can - /// still be called when this value is `None`, we then just fallback to encoding/decoding the - /// parameters. - pub native_call: Option, /// The encoded arguments of the function. pub arguments: Vec, /// The overlayed changes that are on top of the state. @@ -620,13 +611,10 @@ pub trait CallApiAt { /// Calls the given api function with the given encoded arguments at the given block and returns /// the encoded result. - fn call_api_at< - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, - >( + fn call_api_at( &self, - params: CallApiAtParams, - ) -> Result, ApiError>; + params: CallApiAtParams, + ) -> Result, ApiError>; /// Returns the runtime version at the given block. fn runtime_version_at(&self, at: &BlockId) -> Result; diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index fadbdada1f004..fda7604d5337f 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -40,8 +40,6 @@ pub use serde; use serde::{Deserialize, Serialize}; use sp_runtime_interface::pass_by::{PassByEnum, PassByInner}; use sp_std::{ops::Deref, prelude::*}; -#[cfg(feature = "std")] -use std::borrow::Cow; pub use sp_debug_derive::RuntimeDebug; @@ -209,85 +207,6 @@ impl OpaquePeerId { } } -/// Something that is either a native or an encoded value. -#[cfg(feature = "std")] -pub enum NativeOrEncoded { - /// The native representation. - Native(R), - /// The encoded representation. - Encoded(Vec), -} - -#[cfg(feature = "std")] -impl From for NativeOrEncoded { - fn from(val: R) -> Self { - Self::Native(val) - } -} - -#[cfg(feature = "std")] -impl sp_std::fmt::Debug for NativeOrEncoded { - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - hexdisplay::HexDisplay::from(&self.as_encoded().as_ref()).fmt(f) - } -} - -#[cfg(feature = "std")] -impl NativeOrEncoded { - /// Return the value as the encoded format. - pub fn as_encoded(&self) -> Cow<'_, [u8]> { - match self { - NativeOrEncoded::Encoded(e) => Cow::Borrowed(e.as_slice()), - NativeOrEncoded::Native(n) => Cow::Owned(n.encode()), - } - } - - /// Return the value as the encoded format. - pub fn into_encoded(self) -> Vec { - match self { - NativeOrEncoded::Encoded(e) => e, - NativeOrEncoded::Native(n) => n.encode(), - } - } -} - -#[cfg(feature = "std")] -impl PartialEq for NativeOrEncoded { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (NativeOrEncoded::Native(l), NativeOrEncoded::Native(r)) => l == r, - (NativeOrEncoded::Native(n), NativeOrEncoded::Encoded(e)) | - (NativeOrEncoded::Encoded(e), NativeOrEncoded::Native(n)) => - Some(n) == codec::Decode::decode(&mut &e[..]).ok().as_ref(), - (NativeOrEncoded::Encoded(l), NativeOrEncoded::Encoded(r)) => l == r, - } - } -} - -/// A value that is never in a native representation. -/// This is type is useful in conjunction with `NativeOrEncoded`. -#[cfg(feature = "std")] -#[derive(PartialEq)] -pub enum NeverNativeValue {} - -#[cfg(feature = "std")] -impl codec::Encode for NeverNativeValue { - fn encode(&self) -> Vec { - // The enum is not constructable, so this function should never be callable! - unreachable!() - } -} - -#[cfg(feature = "std")] -impl codec::EncodeLike for NeverNativeValue {} - -#[cfg(feature = "std")] -impl codec::Decode for NeverNativeValue { - fn decode(_: &mut I) -> Result { - Err("`NeverNativeValue` should never be decoded".into()) - } -} - /// Provide a simple 4 byte identifier for a type. pub trait TypeId { /// Simple 4 byte identifier. diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs index 80e8963a2909d..c5149cc48c074 100644 --- a/primitives/core/src/traits.rs +++ b/primitives/core/src/traits.rs @@ -20,7 +20,6 @@ use std::{ borrow::Cow, fmt::{Debug, Display}, - panic::UnwindSafe, }; pub use sp_externalities::{Externalities, ExternalitiesExt}; @@ -32,18 +31,14 @@ pub trait CodeExecutor: Sized + Send + Sync + ReadRuntimeVersion + Clone + 'stat /// Call a given method in the runtime. Returns a tuple of the result (either the output data /// or an execution error) together with a `bool`, which is true if native execution was used. - fn call< - R: codec::Codec + PartialEq, - NC: FnOnce() -> Result> + UnwindSafe, - >( + fn call( &self, ext: &mut dyn Externalities, runtime_code: &RuntimeCode, method: &str, data: &[u8], use_native: bool, - native_call: Option, - ) -> (Result, Self::Error>, bool); + ) -> (Result, Self::Error>, bool); } /// Something that can fetch the runtime `:code`. diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 59488599883e9..4126aea478d5b 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -157,31 +157,28 @@ mod execution { use crate::backend::AsTrieBackend; use super::*; - use codec::{Codec, Decode, Encode}; + use codec::Codec; use hash_db::Hasher; use smallvec::SmallVec; use sp_core::{ hexdisplay::HexDisplay, storage::{ChildInfo, ChildType, PrefixedStorageKey}, traits::{CodeExecutor, ReadRuntimeVersionExt, RuntimeCode, SpawnNamed}, - NativeOrEncoded, NeverNativeValue, }; use sp_externalities::Extensions; use std::{ collections::{HashMap, HashSet}, fmt, - panic::UnwindSafe, - result, }; const PROOF_CLOSE_TRANSACTION: &str = "\ Closing a transaction that was started in this function. Client initiated transactions are protected from being closed by the runtime. qed"; - pub(crate) type CallResult = Result, E>; + pub(crate) type CallResult = Result, E>; /// Default handler of the execution manager. - pub type DefaultHandler = fn(CallResult, CallResult) -> CallResult; + pub type DefaultHandler = fn(CallResult, CallResult) -> CallResult; /// Trie backend with in-memory storage. pub type InMemoryBackend = TrieBackend, H>; @@ -243,9 +240,7 @@ mod execution { impl ExecutionStrategy { /// Gets the corresponding manager for the execution strategy. - pub fn get_manager( - self, - ) -> ExecutionManager> { + pub fn get_manager(self) -> ExecutionManager> { match self { ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted), @@ -265,19 +260,19 @@ mod execution { } /// Evaluate to ExecutionManager::NativeElseWasm, without having to figure out the type. - pub fn native_else_wasm() -> ExecutionManager> { + pub fn native_else_wasm() -> ExecutionManager> { ExecutionManager::NativeElseWasm } /// Evaluate to ExecutionManager::AlwaysWasm with trusted backend, without having to figure out /// the type. - fn always_wasm() -> ExecutionManager> { + fn always_wasm() -> ExecutionManager> { ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted) } /// Evaluate ExecutionManager::AlwaysWasm with untrusted backend, without having to figure out /// the type. - fn always_untrusted_wasm() -> ExecutionManager> { + fn always_untrusted_wasm() -> ExecutionManager> { ExecutionManager::AlwaysWasm(BackendTrustLevel::Untrusted) } @@ -379,23 +374,10 @@ mod execution { pub fn execute(&mut self, strategy: ExecutionStrategy) -> Result, Box> { // We are not giving a native call and thus we are sure that the result can never be a // native value. - self.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - strategy.get_manager(), - None, - ) - .map(NativeOrEncoded::into_encoded) + self.execute_using_consensus_failure_handler(strategy.get_manager()) } - fn execute_aux( - &mut self, - use_native: bool, - native_call: Option, - ) -> (CallResult, bool) - where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> - + UnwindSafe, - { + fn execute_aux(&mut self, use_native: bool) -> (CallResult, bool) { let mut cache = StorageTransactionCache::default(); let cache = match self.storage_transaction_cache.as_mut() { @@ -426,7 +408,6 @@ mod execution { self.method, self.call_data, use_native, - native_call, ); self.overlay @@ -444,26 +425,20 @@ mod execution { (result, was_native) } - fn execute_call_with_both_strategy( + fn execute_call_with_both_strategy( &mut self, - mut native_call: Option, on_consensus_failure: Handler, - ) -> CallResult + ) -> CallResult where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> - + UnwindSafe, - Handler: FnOnce( - CallResult, - CallResult, - ) -> CallResult, + Handler: + FnOnce(CallResult, CallResult) -> CallResult, { self.overlay.start_transaction(); - let (result, was_native) = self.execute_aux(true, native_call.take()); + let (result, was_native) = self.execute_aux(true); if was_native { self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION); - let (wasm_result, _) = self.execute_aux(false, native_call); + let (wasm_result, _) = self.execute_aux(false); if (result.is_ok() && wasm_result.is_ok() && result.as_ref().ok() == wasm_result.as_ref().ok()) || @@ -479,25 +454,16 @@ mod execution { } } - fn execute_call_with_native_else_wasm_strategy( - &mut self, - mut native_call: Option, - ) -> CallResult - where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> - + UnwindSafe, - { + fn execute_call_with_native_else_wasm_strategy(&mut self) -> CallResult { self.overlay.start_transaction(); - let (result, was_native) = self.execute_aux(true, native_call.take()); + let (result, was_native) = self.execute_aux(true); if !was_native || result.is_ok() { self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION); result } else { self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION); - let (wasm_result, _) = self.execute_aux(false, native_call); - wasm_result + self.execute_aux(false).0 } } @@ -510,35 +476,29 @@ mod execution { /// /// Returns the result of the executed function either in native representation `R` or /// in SCALE encoded representation. - pub fn execute_using_consensus_failure_handler( + pub fn execute_using_consensus_failure_handler( &mut self, manager: ExecutionManager, - mut native_call: Option, - ) -> Result, Box> + ) -> Result, Box> where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> - + UnwindSafe, - Handler: FnOnce( - CallResult, - CallResult, - ) -> CallResult, + Handler: + FnOnce(CallResult, CallResult) -> CallResult, { let result = { match manager { - ExecutionManager::Both(on_consensus_failure) => self - .execute_call_with_both_strategy(native_call.take(), on_consensus_failure), + ExecutionManager::Both(on_consensus_failure) => + self.execute_call_with_both_strategy(on_consensus_failure), ExecutionManager::NativeElseWasm => - self.execute_call_with_native_else_wasm_strategy(native_call.take()), + self.execute_call_with_native_else_wasm_strategy(), ExecutionManager::AlwaysWasm(trust_level) => { let _abort_guard = match trust_level { BackendTrustLevel::Trusted => None, BackendTrustLevel::Untrusted => Some(sp_panic_handler::AbortGuard::never_abort()), }; - self.execute_aux(false, native_call).0 + self.execute_aux(false).0 }, - ExecutionManager::NativeWhenPossible => self.execute_aux(true, native_call).0, + ExecutionManager::NativeWhenPossible => self.execute_aux(true).0, } }; @@ -603,29 +563,23 @@ mod execution { let proving_backend = TrieBackendBuilder::wrap(trie_backend).with_recorder(Default::default()).build(); - let result = { - let mut sm = StateMachine::<_, H, Exec>::new( - &proving_backend, - overlay, - exec, - method, - call_data, - Extensions::default(), - runtime_code, - spawn_handle, - ); - - sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - always_wasm(), - None, - )? - }; + let result = StateMachine::<_, H, Exec>::new( + &proving_backend, + overlay, + exec, + method, + call_data, + Extensions::default(), + runtime_code, + spawn_handle, + ) + .execute_using_consensus_failure_handler::<_>(always_wasm())?; let proof = proving_backend .extract_proof() .expect("A recorder was set and thus, a storage proof can be extracted; qed"); - Ok((result.into_encoded(), proof)) + Ok((result, proof)) } /// Check execution proof, generated by `prove_execution` call. @@ -673,7 +627,7 @@ mod execution { Exec: CodeExecutor + Clone + 'static, Spawn: SpawnNamed + Send + 'static, { - let mut sm = StateMachine::<_, H, Exec>::new( + StateMachine::<_, H, Exec>::new( trie_backend, overlay, exec, @@ -682,13 +636,8 @@ mod execution { Extensions::default(), runtime_code, spawn_handle, - ); - - sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - always_untrusted_wasm(), - None, ) - .map(NativeOrEncoded::into_encoded) + .execute_using_consensus_failure_handler(always_untrusted_wasm()) } /// Generate storage read proof. @@ -1362,21 +1311,16 @@ mod tests { use super::{backend::AsTrieBackend, ext::Ext, *}; use crate::{execution::CallResult, in_memory_backend::new_in_mem_hash_key}; use assert_matches::assert_matches; - use codec::{Decode, Encode}; + use codec::Encode; use sp_core::{ map, storage::{ChildInfo, StateVersion}, testing::TaskExecutor, traits::{CodeExecutor, Externalities, RuntimeCode}, - NativeOrEncoded, NeverNativeValue, }; use sp_runtime::traits::BlakeTwo256; use sp_trie::trie_types::{TrieDBMutBuilderV0, TrieDBMutBuilderV1}; - use std::{ - collections::{BTreeMap, HashMap}, - panic::UnwindSafe, - result, - }; + use std::collections::{BTreeMap, HashMap}; #[derive(Clone)] struct DummyCodeExecutor { @@ -1388,28 +1332,20 @@ mod tests { impl CodeExecutor for DummyCodeExecutor { type Error = u8; - fn call< - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result> + UnwindSafe, - >( + fn call( &self, ext: &mut dyn Externalities, _: &RuntimeCode, _method: &str, _data: &[u8], use_native: bool, - native_call: Option, - ) -> (CallResult, bool) { + ) -> (CallResult, bool) { let using_native = use_native && self.native_available; - match (using_native, self.native_succeeds, self.fallback_succeeds, native_call) { - (true, true, _, Some(call)) => { - let res = sp_externalities::set_and_run_with_externalities(ext, call); - (res.map(NativeOrEncoded::Native).map_err(|_| 0), true) - }, - (true, true, _, None) | (false, _, true, None) => ( - Ok(NativeOrEncoded::Encoded(vec![ + match (using_native, self.native_succeeds, self.fallback_succeeds) { + (true, true, _) | (false, _, true) => ( + Ok(vec![ ext.storage(b"value1").unwrap()[0] + ext.storage(b"value2").unwrap()[0], - ])), + ]), using_native, ), _ => (Err(0), using_native), @@ -1510,13 +1446,10 @@ mod tests { ); assert!(state_machine - .execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - ExecutionManager::Both(|we, _ne| { - consensus_failed = true; - we - }), - None, - ) + .execute_using_consensus_failure_handler(ExecutionManager::Both(|we, _ne| { + consensus_failed = true; + we + }),) .is_err()); assert!(consensus_failed); } @@ -2260,51 +2193,4 @@ mod tests { overlay.commit_transaction().unwrap(); assert_eq!(overlay.storage(b"ccc"), Some(None)); } - - #[test] - fn runtime_registered_extensions_are_removed_after_execution() { - let state_version = StateVersion::default(); - use sp_externalities::ExternalitiesExt; - sp_externalities::decl_extension! { - struct DummyExt(u32); - } - - let backend = trie_backend::tests::test_trie(state_version, None, None); - let mut overlayed_changes = Default::default(); - let wasm_code = RuntimeCode::empty(); - - let mut state_machine = StateMachine::new( - &backend, - &mut overlayed_changes, - &DummyCodeExecutor { - native_available: true, - native_succeeds: true, - fallback_succeeds: false, - }, - "test", - &[], - Default::default(), - &wasm_code, - TaskExecutor::new(), - ); - - let run_state_machine = |state_machine: &mut StateMachine<_, _, _>| { - state_machine - .execute_using_consensus_failure_handler:: _, _, _>( - ExecutionManager::NativeWhenPossible, - Some(|| { - sp_externalities::with_externalities(|mut ext| { - ext.register_extension(DummyExt(2)).unwrap(); - }) - .unwrap(); - - Ok(()) - }), - ) - .unwrap(); - }; - - run_state_machine(&mut state_machine); - run_state_machine(&mut state_machine); - } } diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 77cd18c028364..45a6f66416d8c 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -322,7 +322,6 @@ mod tests { use sp_core::{ map, traits::{CodeExecutor, RuntimeCode}, - NeverNativeValue, }; use sp_io::{hashing::twox_128, TestExternalities}; use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring}; @@ -406,14 +405,7 @@ mod tests { }; executor() - .call:: _>( - &mut ext, - &runtime_code, - "Core_execute_block", - &b.encode(), - false, - None, - ) + .call(&mut ext, &runtime_code, "Core_execute_block", &b.encode(), false) .0 .unwrap(); }) @@ -515,14 +507,7 @@ mod tests { }; executor() - .call:: _>( - &mut ext, - &runtime_code, - "Core_execute_block", - &b.encode(), - false, - None, - ) + .call(&mut ext, &runtime_code, "Core_execute_block", &b.encode(), false) .0 .unwrap(); }) From d5de897396d2e816b7eea94caecf5de179ed29a5 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 12 Sep 2022 15:27:11 +0100 Subject: [PATCH 1146/1472] Fuzz testing for nomination pools (#12002) * some additional tests and stuff * make sanity public * add some sort of fuzz test for pools * breaks every now and then * breaks every now and then * IT WORKS AND PASSES 100k TESTS * cleanup * safe id addition * fix assert_eq_error_rate * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * add some doc * Fix * ".git/.scripts/fmt.sh" 1 Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- Cargo.lock | 77 ++- frame/nomination-pools/Cargo.toml | 2 + frame/nomination-pools/src/lib.rs | 49 +- frame/nomination-pools/src/mock.rs | 3 +- frame/nomination-pools/src/tests.rs | 537 ++++++++++++++++++ frame/support/src/traits/misc.rs | 15 +- primitives/runtime/src/lib.rs | 21 +- .../benchmarking-cli/src/machine/hardware.rs | 8 +- 8 files changed, 647 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f47ac8ba408b3..335e8b3526792 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -905,7 +905,7 @@ dependencies = [ "ansi_term", "clap 3.1.18", "node-cli", - "rand 0.8.4", + "rand 0.8.5", "sc-chain-spec", "sc-keystore", "sp-core", @@ -2038,7 +2038,7 @@ dependencies = [ "num-traits", "parity-scale-codec", "parking_lot 0.12.1", - "rand 0.8.4", + "rand 0.8.5", "scale-info", ] @@ -2049,7 +2049,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" dependencies = [ "byteorder", - "rand 0.8.4", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -2143,7 +2143,7 @@ dependencies = [ "log", "memory-db", "parity-scale-codec", - "rand 0.8.4", + "rand 0.8.5", "rand_pcg 0.3.1", "sc-block-builder", "sc-cli", @@ -2215,7 +2215,7 @@ dependencies = [ "frame-support", "honggfuzz", "parity-scale-codec", - "rand 0.8.4", + "rand 0.8.5", "scale-info", "sp-arithmetic", "sp-npos-elections", @@ -3212,7 +3212,7 @@ dependencies = [ "jsonrpsee-types", "lazy_static", "parking_lot 0.12.1", - "rand 0.8.4", + "rand 0.8.5", "rustc-hash", "serde", "serde_json", @@ -3593,7 +3593,7 @@ dependencies = [ "log", "prost", "prost-build", - "rand 0.8.4", + "rand 0.8.5", ] [[package]] @@ -3620,7 +3620,7 @@ dependencies = [ "pin-project", "prost", "prost-build", - "rand 0.8.4", + "rand 0.8.5", "ring", "rw-stream-sink", "sha2 0.10.2", @@ -3767,7 +3767,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "rand 0.8.4", + "rand 0.8.5", "smallvec", "socket2", "void", @@ -3821,7 +3821,7 @@ dependencies = [ "log", "prost", "prost-build", - "rand 0.8.4", + "rand 0.8.5", "sha2 0.10.2", "snow", "static_assertions", @@ -3895,7 +3895,7 @@ dependencies = [ "prost", "prost-build", "prost-codec", - "rand 0.8.4", + "rand 0.8.5", "smallvec", "static_assertions", "thiserror", @@ -3918,7 +3918,7 @@ dependencies = [ "log", "prost", "prost-build", - "rand 0.8.4", + "rand 0.8.5", "sha2 0.10.2", "thiserror", "unsigned-varint", @@ -4076,7 +4076,7 @@ dependencies = [ "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", - "rand 0.8.4", + "rand 0.8.5", "serde", "sha2 0.9.8", "typenum", @@ -4502,7 +4502,7 @@ dependencies = [ "num-complex", "num-rational 0.4.0", "num-traits", - "rand 0.8.4", + "rand 0.8.5", "rand_distr", "simba", "typenum", @@ -4525,7 +4525,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7d66043b25d4a6cccb23619d10c19c25304b355a7dccd4a8e11423dd2382146" dependencies = [ - "rand 0.8.4", + "rand 0.8.5", ] [[package]] @@ -4685,7 +4685,7 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "platforms", - "rand 0.8.4", + "rand 0.8.5", "regex", "remote-externalities", "sc-authority-discovery", @@ -5341,7 +5341,7 @@ dependencies = [ "frame-election-provider-support", "honggfuzz", "pallet-bags-list", - "rand 0.8.4", + "rand 0.8.5", ] [[package]] @@ -5495,7 +5495,7 @@ dependencies = [ "pallet-utility", "parity-scale-codec", "pretty_assertions", - "rand 0.8.4", + "rand 0.8.5", "rand_pcg 0.3.1", "scale-info", "serde", @@ -5931,6 +5931,7 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", + "rand 0.8.5", "scale-info", "sp-core", "sp-io", @@ -6554,7 +6555,7 @@ dependencies = [ "lz4", "memmap2 0.2.1", "parking_lot 0.11.2", - "rand 0.8.4", + "rand 0.8.5", "snap", ] @@ -7168,7 +7169,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ - "rand 0.8.4", + "rand 0.8.5", ] [[package]] @@ -7207,20 +7208,19 @@ dependencies = [ "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", - "rand_hc 0.2.0", + "rand_hc", "rand_pcg 0.2.1", ] [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.0", "rand_core 0.6.2", - "rand_hc 0.3.0", ] [[package]] @@ -7268,7 +7268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ "num-traits", - "rand 0.8.4", + "rand 0.8.5", ] [[package]] @@ -7280,15 +7280,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core 0.6.2", -] - [[package]] name = "rand_pcg" version = "0.2.1" @@ -7907,7 +7898,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "quickcheck", - "rand 0.8.4", + "rand 0.8.5", "sc-client-api", "sc-state-db", "sp-arithmetic", @@ -8279,7 +8270,7 @@ dependencies = [ "log", "parity-scale-codec", "parking_lot 0.12.1", - "rand 0.8.4", + "rand 0.8.5", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -9397,7 +9388,7 @@ dependencies = [ "futures", "httparse", "log", - "rand 0.8.4", + "rand 0.8.5", "sha-1 0.9.4", ] @@ -9877,7 +9868,7 @@ dependencies = [ "clap 3.1.18", "honggfuzz", "parity-scale-codec", - "rand 0.8.4", + "rand 0.8.5", "scale-info", "sp-npos-elections", "sp-runtime", @@ -10282,7 +10273,7 @@ dependencies = [ "lazy_static", "nalgebra", "num-traits", - "rand 0.8.4", + "rand 0.8.5", ] [[package]] @@ -11053,7 +11044,7 @@ dependencies = [ "ipnet", "lazy_static", "log", - "rand 0.8.4", + "rand 0.8.5", "smallvec", "thiserror", "tinyvec", @@ -11141,7 +11132,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if 1.0.0", "digest 0.10.3", - "rand 0.8.4", + "rand 0.7.3", "static_assertions", ] @@ -11859,7 +11850,7 @@ dependencies = [ "memfd", "memoffset", "paste 1.0.6", - "rand 0.8.4", + "rand 0.8.5", "rustix", "thiserror", "wasmtime-asm-macros", @@ -12151,7 +12142,7 @@ dependencies = [ "log", "nohash-hasher", "parking_lot 0.12.1", - "rand 0.8.4", + "rand 0.8.5", "static_assertions", ] diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index 1d613511eacec..ef8465e670bf6 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -29,10 +29,12 @@ log = { version = "0.4.0", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +rand = { version = "0.8.5", features = ["small_rng"] } [features] runtime-benchmarks = [] try-runtime = [ "frame-support/try-runtime" ] +fuzz-test = [] default = ["std"] std = [ "codec/std", diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index a8c4e50daa0b5..9e872955669f8 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1453,7 +1453,7 @@ pub mod pallet { PartialUnbondNotAllowedPermissionlessly, } - #[derive(Encode, Decode, PartialEq, TypeInfo, frame_support::PalletError)] + #[derive(Encode, Decode, PartialEq, TypeInfo, frame_support::PalletError, RuntimeDebug)] pub enum DefensiveError { /// There isn't enough space in the unbond pool. NotEnoughSpaceInUnbondPool, @@ -1758,8 +1758,8 @@ pub mod pallet { let bonded_pool = BondedPool::::get(member.pool_id) .defensive_ok_or::>(DefensiveError::PoolNotFound.into())?; - let mut sub_pools = SubPoolsStorage::::get(member.pool_id) - .defensive_ok_or::>(DefensiveError::SubPoolsNotFound.into())?; + let mut sub_pools = + SubPoolsStorage::::get(member.pool_id).ok_or(Error::::SubPoolsNotFound)?; bonded_pool.ok_to_withdraw_unbonded_with(&caller, &member_account)?; @@ -1887,10 +1887,10 @@ pub mod pallet { ); ensure!(!PoolMembers::::contains_key(&who), Error::::AccountBelongsToOtherPool); - let pool_id = LastPoolId::::mutate(|id| { - *id += 1; - *id - }); + let pool_id = LastPoolId::::try_mutate::<_, Error, _>(|id| { + *id = id.checked_add(1).ok_or(Error::::OverflowRisk)?; + Ok(*id) + })?; let mut bonded_pool = BondedPool::::new( pool_id, PoolRoles { @@ -2416,16 +2416,46 @@ impl Pallet { for id in reward_pools { let account = Self::create_reward_account(id); - assert!(T::Currency::free_balance(&account) >= T::Currency::minimum_balance()); + assert!( + T::Currency::free_balance(&account) >= T::Currency::minimum_balance(), + "reward pool of {id}: {:?} (ed = {:?})", + T::Currency::free_balance(&account), + T::Currency::minimum_balance() + ); } let mut pools_members = BTreeMap::::new(); + let mut pools_members_pending_rewards = BTreeMap::>::new(); let mut all_members = 0u32; PoolMembers::::iter().for_each(|(_, d)| { - assert!(BondedPools::::contains_key(d.pool_id)); + let bonded_pool = BondedPools::::get(d.pool_id).unwrap(); assert!(!d.total_points().is_zero(), "no member should have zero points: {:?}", d); *pools_members.entry(d.pool_id).or_default() += 1; all_members += 1; + + let reward_pool = RewardPools::::get(d.pool_id).unwrap(); + if !bonded_pool.points.is_zero() { + let current_rc = + reward_pool.current_reward_counter(d.pool_id, bonded_pool.points).unwrap(); + *pools_members_pending_rewards.entry(d.pool_id).or_default() += + d.pending_rewards(current_rc).unwrap(); + } // else this pool has been heavily slashed and cannot have any rewards anymore. + }); + + RewardPools::::iter_keys().for_each(|id| { + // the sum of the pending rewards must be less than the leftover balance. Since the + // reward math rounds down, we might accumulate some dust here. + log!( + trace, + "pool {:?}, sum pending rewards = {:?}, remaining balance = {:?}", + id, + pools_members_pending_rewards.get(&id), + RewardPool::::current_balance(id) + ); + assert!( + RewardPool::::current_balance(id) >= + pools_members_pending_rewards.get(&id).map(|x| *x).unwrap_or_default() + ) }); BondedPools::::iter().for_each(|(id, inner)| { @@ -2470,6 +2500,7 @@ impl Pallet { sum_unbonding_balance ); } + Ok(()) } diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 4428c28558f18..f1574b3684aab 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -4,6 +4,7 @@ use frame_support::{assert_ok, parameter_types, PalletId}; use frame_system::RawOrigin; use sp_runtime::FixedU128; +pub type BlockNumber = u64; pub type AccountId = u128; pub type Balance = u128; pub type RewardCounter = FixedU128; @@ -129,7 +130,7 @@ impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Origin = Origin; type Index = u64; - type BlockNumber = u64; + type BlockNumber = BlockNumber; type Call = Call; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 20ba2b76fe31a..362fece3f3daf 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -1774,6 +1774,54 @@ mod claim_payout { }) } + #[test] + fn bond_extra_pending_rewards_works() { + ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { + MaxPoolMembers::::set(None); + MaxPoolMembersPerPool::::set(None); + + // pool receives some rewards. + Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + System::reset_events(); + + // 10 cashes it out, and bonds it. + { + assert_ok!(Pools::claim_payout(Origin::signed(10))); + let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); + // there is 30 points and 30 reward points in the system RC is 1. + assert_eq!(member.last_recorded_reward_counter, 1.into()); + assert_eq!(reward_pool.total_rewards_claimed, 10); + // these two are not updated -- only updated when the points change. + assert_eq!(reward_pool.last_recorded_total_payouts, 0); + assert_eq!(reward_pool.last_recorded_reward_counter, 0.into()); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 10 }] + ); + } + + // 20 re-bonds it. + { + assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::Rewards)); + let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); + assert_eq!(member.last_recorded_reward_counter, 1.into()); + assert_eq!(reward_pool.total_rewards_claimed, 30); + // since points change, these two are updated. + assert_eq!(reward_pool.last_recorded_total_payouts, 30); + assert_eq!(reward_pool.last_recorded_reward_counter, 1.into()); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 20, pool_id: 1, payout: 20 }, + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: false } + ] + ); + } + }) + } + #[test] fn unbond_updates_recorded_data() { ExtBuilder::default() @@ -3733,6 +3781,170 @@ mod withdraw_unbonded { }) } + #[test] + fn out_of_sync_unbonding_chunks() { + // the unbonding_eras in pool member are always fixed to the era at which they are unlocked, + // but the actual unbonding pools get pruned and might get combined in the no_era pool. + // Pools are only merged when one unbonds, so we unbond a little bit on every era to + // simulate this. + ExtBuilder::default() + .add_members(vec![(20, 100), (30, 100)]) + .build_and_execute(|| { + System::reset_events(); + + // when + assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(Origin::signed(30), 30, 5)); + + // then member-local unbonding is pretty much in sync with the global pools. + assert_eq!( + PoolMembers::::get(20).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 5) + ); + assert_eq!( + PoolMembers::::get(30).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 5) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 10, balance: 10 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5, era: 3 }, + Event::Unbonded { member: 30, pool_id: 1, points: 5, balance: 5, era: 3 }, + ] + ); + + // when + CurrentEra::set(1); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + + // then still member-local unbonding is pretty much in sync with the global pools. + assert_eq!( + PoolMembers::::get(20).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 5, 4 => 5) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 10, balance: 10 }, + 4 => UnbondPool { points: 5, balance: 5 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5, era: 4 }] + ); + + // when + CurrentEra::set(2); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + + // then still member-local unbonding is pretty much in sync with the global pools. + assert_eq!( + PoolMembers::::get(20).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 5, 4 => 5, 5 => 5) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 10, balance: 10 }, + 4 => UnbondPool { points: 5, balance: 5 }, + 5 => UnbondPool { points: 5, balance: 5 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5, era: 5 }] + ); + + // when + CurrentEra::set(5); + assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + + // then + assert_eq!( + PoolMembers::::get(20).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 5, 4 => 5, 5 => 5, 8 => 5) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + // era 3 is merged into no_era. + no_era: UnbondPool { points: 10, balance: 10 }, + with_era: unbonding_pools_with_era! { + 4 => UnbondPool { points: 5, balance: 5 }, + 5 => UnbondPool { points: 5, balance: 5 }, + 8 => UnbondPool { points: 5, balance: 5 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5, era: 8 }] + ); + + // now we start withdrawing unlocked bonds. + + // when + assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); + // then + assert_eq!( + PoolMembers::::get(20).unwrap().unbonding_eras, + member_unbonding_eras!(8 => 5) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + // era 3 is merged into no_era. + no_era: UnbondPool { points: 5, balance: 5 }, + with_era: unbonding_pools_with_era! { + 8 => UnbondPool { points: 5, balance: 5 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Withdrawn { member: 20, pool_id: 1, points: 15, balance: 15 }] + ); + + // when + assert_ok!(Pools::withdraw_unbonded(Origin::signed(30), 30, 0)); + // then + assert_eq!( + PoolMembers::::get(30).unwrap().unbonding_eras, + member_unbonding_eras!() + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + // era 3 is merged into no_era. + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 8 => UnbondPool { points: 5, balance: 5 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Withdrawn { member: 30, pool_id: 1, points: 5, balance: 5 }] + ); + }) + } + #[test] fn full_multi_step_withdrawing_depositor() { ExtBuilder::default().ed(1).build_and_execute(|| { @@ -4768,3 +4980,328 @@ mod reward_counter_precision { }); } } + +// NOTE: run this with debug_assertions, but in release mode. +#[cfg(feature = "fuzz-test")] +mod fuzz_test { + use super::*; + use crate::pallet::{Call as PoolsCall, Event as PoolsEvents}; + use frame_support::traits::UnfilteredDispatchable; + use rand::{seq::SliceRandom, thread_rng, Rng}; + use sp_runtime::{assert_eq_error_rate, Perquintill}; + + const ERA: BlockNumber = 1000; + const MAX_ED_MULTIPLE: Balance = 10_000; + const MIN_ED_MULTIPLE: Balance = 10; + + // not quite elegant, just to make it available in random_signed_origin. + const REWARD_AGENT_ACCOUNT: AccountId = 42; + + /// Grab random accounts, either known ones, or new ones. + fn random_signed_origin(rng: &mut R) -> (Origin, AccountId) { + let count = PoolMembers::::count(); + if rng.gen::() && count > 0 { + // take an existing account. + let skip = rng.gen_range(0..count as usize); + + // this is tricky: the account might be our reward agent, which we never want to be + // randomly chosen here. Try another one, or, if it is only our agent, return a random + // one nonetheless. + let candidate = PoolMembers::::iter_keys().skip(skip).take(1).next().unwrap(); + let acc = + if candidate == REWARD_AGENT_ACCOUNT { rng.gen::() } else { candidate }; + + (Origin::signed(acc), acc) + } else { + // create a new account + let acc = rng.gen::(); + (Origin::signed(acc), acc) + } + } + + fn random_ed_multiple(rng: &mut R) -> Balance { + let multiple = rng.gen_range(MIN_ED_MULTIPLE..MAX_ED_MULTIPLE); + ExistentialDeposit::get() * multiple + } + + fn fund_account(rng: &mut R, account: &AccountId) { + let target_amount = random_ed_multiple(rng); + if let Some(top_up) = target_amount.checked_sub(Balances::free_balance(account)) { + let _ = Balances::deposit_creating(account, top_up); + } + assert!(Balances::free_balance(account) >= target_amount); + } + + fn random_existing_pool(mut rng: &mut R) -> Option { + BondedPools::::iter_keys().collect::>().choose(&mut rng).map(|x| *x) + } + + fn random_call(mut rng: &mut R) -> (crate::pallet::Call, Origin) { + let op = rng.gen::(); + let mut op_count = + as frame_support::dispatch::GetCallName>::get_call_names() + .len(); + // Exclude set_state, set_metadata, set_configs, update_roles and chill. + op_count -= 5; + + match op % op_count { + 0 => { + // join + let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); + let (origin, who) = random_signed_origin(&mut rng); + fund_account(&mut rng, &who); + let amount = random_ed_multiple(&mut rng); + (PoolsCall::::join { amount, pool_id }, origin) + }, + 1 => { + // bond_extra + let (origin, who) = random_signed_origin(&mut rng); + let extra = if rng.gen::() { + BondExtra::Rewards + } else { + fund_account(&mut rng, &who); + let amount = random_ed_multiple(&mut rng); + BondExtra::FreeBalance(amount) + }; + (PoolsCall::::bond_extra { extra }, origin) + }, + 2 => { + // claim_payout + let (origin, _) = random_signed_origin(&mut rng); + (PoolsCall::::claim_payout {}, origin) + }, + 3 => { + // unbond + let (origin, who) = random_signed_origin(&mut rng); + let amount = random_ed_multiple(&mut rng); + (PoolsCall::::unbond { member_account: who, unbonding_points: amount }, origin) + }, + 4 => { + // pool_withdraw_unbonded + let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); + let (origin, _) = random_signed_origin(&mut rng); + (PoolsCall::::pool_withdraw_unbonded { pool_id, num_slashing_spans: 0 }, origin) + }, + 5 => { + // withdraw_unbonded + let (origin, who) = random_signed_origin(&mut rng); + ( + PoolsCall::::withdraw_unbonded { + member_account: who, + num_slashing_spans: 0, + }, + origin, + ) + }, + 6 => { + // create + let (origin, who) = random_signed_origin(&mut rng); + let amount = random_ed_multiple(&mut rng); + fund_account(&mut rng, &who); + let root = who.clone(); + let state_toggler = who.clone(); + let nominator = who.clone(); + (PoolsCall::::create { amount, root, state_toggler, nominator }, origin) + }, + 7 => { + // nominate + let (origin, _) = random_signed_origin(&mut rng); + let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); + let validators = Default::default(); + (PoolsCall::::nominate { pool_id, validators }, origin) + }, + _ => unreachable!(), + } + } + + #[derive(Default)] + struct RewardAgent { + who: AccountId, + pool_id: Option, + expected_reward: Balance, + } + + // TODO: inject some slashes into the game. + impl RewardAgent { + fn new(who: AccountId) -> Self { + Self { who, ..Default::default() } + } + + fn join(&mut self) { + if self.pool_id.is_some() { + return + } + let pool_id = LastPoolId::::get(); + let amount = 10 * ExistentialDeposit::get(); + let origin = Origin::signed(self.who); + let _ = Balances::deposit_creating(&self.who, 10 * amount); + self.pool_id = Some(pool_id); + log::info!(target: "reward-agent", "🤖 reward agent joining in {} with {}", pool_id, amount); + assert_ok!(PoolsCall::join:: { amount, pool_id }.dispatch_bypass_filter(origin)); + } + + fn claim_payout(&mut self) { + // 10 era later, we claim our payout. We expect our income to be roughly what we + // calculated. + if !PoolMembers::::contains_key(&self.who) { + log!(warn, "reward agent is not in the pool yet, cannot claim"); + return + } + let pre = Balances::free_balance(&42); + let origin = Origin::signed(42); + assert_ok!(PoolsCall::::claim_payout {}.dispatch_bypass_filter(origin)); + let post = Balances::free_balance(&42); + + let income = post - pre; + log::info!( + target: "reward-agent", "🤖 CLAIM: actual: {}, expected: {}", + income, + self.expected_reward, + ); + assert_eq_error_rate!(income, self.expected_reward, 10); + self.expected_reward = 0; + } + } + + #[test] + fn fuzz_test() { + let mut reward_agent = RewardAgent::new(42); + sp_tracing::try_init_simple(); + // NOTE: use this to get predictable (non)randomness: + // use::{rngs::SmallRng, SeedableRng}; + // let mut rng = SmallRng::from_seed([0u8; 32]); + let mut rng = thread_rng(); + let mut ext = sp_io::TestExternalities::new_empty(); + // NOTE: sadly events don't fulfill the requirements of hashmap or btreemap. + let mut events_histogram = Vec::<(PoolsEvents, u32)>::default(); + let mut iteration = 0 as BlockNumber; + let mut ok = 0; + let mut err = 0; + + ext.execute_with(|| { + MaxPoolMembers::::set(Some(10_000)); + MaxPoolMembersPerPool::::set(Some(1000)); + MaxPools::::set(Some(1_000)); + + MinCreateBond::::set(10 * ExistentialDeposit::get()); + MinJoinBond::::set(5 * ExistentialDeposit::get()); + System::set_block_number(1); + }); + + ExistentialDeposit::set(10u128.pow(12u32)); + BondingDuration::set(8); + + loop { + ext.execute_with(|| { + iteration += 1; + let (call, origin) = random_call(&mut rng); + let outcome = call.clone().dispatch_bypass_filter(origin.clone()); + + match outcome { + Ok(_) => ok += 1, + Err(_) => err += 1, + }; + + log!( + debug, + "iteration {}, call {:?}, origin {:?}, outcome: {:?}, so far {} ok {} err", + iteration, + call, + origin, + outcome, + ok, + err, + ); + + // possibly join the reward_agent + if iteration > ERA / 2 && BondedPools::::count() > 0 { + reward_agent.join(); + } + // and possibly roughly every 4 era, trigger payout for the agent. Doing this more + // frequent is also harmless. + if rng.gen_range(0..(4 * ERA)) == 0 { + reward_agent.claim_payout(); + } + + // execute sanity checks at a fixed interval, possibly on every block. + if iteration % + (std::env::var("SANITY_CHECK_INTERVAL") + .ok() + .and_then(|x| x.parse::().ok())) + .unwrap_or(1) == 0 + { + log!(info, "running sanity checks at {}", iteration); + Pools::do_try_state(u8::MAX).unwrap(); + } + + // collect and reset events. + System::events() + .into_iter() + .map(|r| r.event) + .filter_map( + |e| if let mock::Event::Pools(inner) = e { Some(inner) } else { None }, + ) + .for_each(|e| { + if let Some((_, c)) = events_histogram + .iter_mut() + .find(|(x, _)| std::mem::discriminant(x) == std::mem::discriminant(&e)) + { + *c += 1; + } else { + events_histogram.push((e, 1)) + } + }); + System::reset_events(); + + // trigger an era change, and check the status of the reward agent. + if iteration % ERA == 0 { + CurrentEra::mutate(|c| *c += 1); + BondedPools::::iter().for_each(|(id, _)| { + let amount = random_ed_multiple(&mut rng); + let _ = + Balances::deposit_creating(&Pools::create_reward_account(id), amount); + // if we just paid out the reward agent, let's calculate how much we expect + // our reward agent to have earned. + if reward_agent.pool_id.map_or(false, |mid| mid == id) { + let all_points = BondedPool::::get(id).map(|p| p.points).unwrap(); + let member_points = + PoolMembers::::get(reward_agent.who).map(|m| m.points).unwrap(); + let agent_share = Perquintill::from_rational(member_points, all_points); + log::info!( + target: "reward-agent", + "🤖 REWARD = amount = {:?}, ratio: {:?}, share {:?}", + amount, + agent_share, + agent_share * amount, + ); + reward_agent.expected_reward += agent_share * amount; + } + }); + + log!( + info, + "iteration {}, {} pools, {} members, {} ok {} err, events = {:?}", + iteration, + BondedPools::::count(), + PoolMembers::::count(), + ok, + err, + events_histogram + .iter() + .map(|(x, c)| ( + format!("{:?}", x) + .split(" ") + .map(|x| x.to_string()) + .collect::>() + .first() + .cloned() + .unwrap(), + c, + )) + .collect::>(), + ); + } + }); + } + } +} diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 0f781d0bbd4cf..59d5ec067baed 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -151,10 +151,10 @@ pub trait DefensiveOption { /// Defensively transform this option to a result, mapping `None` to the return value of an /// error closure. - fn defensive_ok_or_else E>(self, err: F) -> Result; + fn defensive_ok_or_else E>(self, err: F) -> Result; /// Defensively transform this option to a result, mapping `None` to a default value. - fn defensive_ok_or(self, err: E) -> Result; + fn defensive_ok_or(self, err: E) -> Result; /// Exactly the same as `map`, but it prints the appropriate warnings if the value being mapped /// is `None`. @@ -318,16 +318,17 @@ impl DefensiveOption for Option { ) } - fn defensive_ok_or_else E>(self, err: F) -> Result { + fn defensive_ok_or_else E>(self, err: F) -> Result { self.ok_or_else(|| { - defensive!(); - err() + let err_value = err(); + defensive!(err_value); + err_value }) } - fn defensive_ok_or(self, err: E) -> Result { + fn defensive_ok_or(self, err: E) -> Result { self.ok_or_else(|| { - defensive!(); + defensive!(err); err }) } diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 7006a13e415e4..9c2b691f64faa 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -36,6 +36,8 @@ pub use sp_std; #[doc(hidden)] pub use paste; +#[doc(hidden)] +pub use sp_arithmetic::traits::Saturating; #[doc(hidden)] pub use sp_application_crypto as app_crypto; @@ -825,7 +827,24 @@ pub fn verify_encoded_lazy( macro_rules! assert_eq_error_rate { ($x:expr, $y:expr, $error:expr $(,)?) => { assert!( - ($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error)), + ($x >= $crate::Saturating::saturating_sub($y, $error)) && + ($x <= $crate::Saturating::saturating_add($y, $error)), + "{:?} != {:?} (with error rate {:?})", + $x, + $y, + $error, + ); + }; +} + +/// Same as [`assert_eq_error_rate`], but intended to be used with floating point number, or +/// generally those who do not have over/underflow potentials. +#[macro_export] +#[cfg(feature = "std")] +macro_rules! assert_eq_error_rate_float { + ($x:expr, $y:expr, $error:expr $(,)?) => { + assert!( + ($x >= $y - $error) && ($x <= $y + $error), "{:?} != {:?} (with error rate {:?})", $x, $y, diff --git a/utils/frame/benchmarking-cli/src/machine/hardware.rs b/utils/frame/benchmarking-cli/src/machine/hardware.rs index 5c62660cc7cf4..97960de99c4bf 100644 --- a/utils/frame/benchmarking-cli/src/machine/hardware.rs +++ b/utils/frame/benchmarking-cli/src/machine/hardware.rs @@ -161,7 +161,7 @@ impl fmt::Display for Throughput { #[cfg(test)] mod tests { use super::*; - use sp_runtime::assert_eq_error_rate; + use sp_runtime::assert_eq_error_rate_float; /// `SUBSTRATE_REFERENCE_HARDWARE` can be en- and decoded. #[test] @@ -179,9 +179,9 @@ mod tests { const EPS: f64 = 0.1; let gib = Throughput::GiBs(14.324); - assert_eq_error_rate!(14.324, gib.to_gibs(), EPS); - assert_eq_error_rate!(14667.776, gib.to_mibs(), EPS); - assert_eq_error_rate!(14667.776 * 1024.0, gib.to_kibs(), EPS); + assert_eq_error_rate_float!(14.324, gib.to_gibs(), EPS); + assert_eq_error_rate_float!(14667.776, gib.to_mibs(), EPS); + assert_eq_error_rate_float!(14667.776 * 1024.0, gib.to_kibs(), EPS); assert_eq!("14.32 GiB/s", gib.to_string()); assert_eq!("14.32 GiB/s", gib.normalize().to_string()); From c997a62ee6e4efcfa0d7850700f315f4af39ffb4 Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Mon, 12 Sep 2022 18:37:27 +0200 Subject: [PATCH 1147/1472] Add `ConstFeeMultiplier` to the transaction payment pallet (#12222) * fix: FeeMultiplierUpdate * fix: cargo fmt * fix: rustdoc * Revert "fix: rustdoc" This reverts commit 96b6ad80a4cd4d856cf5a830889858c4dd4c385b. * Revert "fix: cargo fmt" This reverts commit 13016527bdbc53d9484642d6b52430550c0efc55. * Revert "fix: FeeMultiplierUpdate" This reverts commit 2cbddd0b85e0293d0eeda859807ddf70cee29067. * feat: add ConstFeeMultiplier * fix: use cConstFeeMultiplier in the template node --- bin/node-template/runtime/src/lib.rs | 12 +++++++++--- frame/transaction-payment/src/lib.rs | 27 ++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index e28a3bb2adb9d..e9c2800ffa3f5 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -14,7 +14,9 @@ use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, Verify}, + traits::{ + AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, Verify, + }, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, MultiSignature, }; @@ -38,7 +40,7 @@ pub use frame_support::{ pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_timestamp::Call as TimestampCall; -use pallet_transaction_payment::CurrencyAdapter; +use pallet_transaction_payment::{ConstFeeMultiplier, CurrencyAdapter, Multiplier}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; @@ -251,13 +253,17 @@ impl pallet_balances::Config for Runtime { type WeightInfo = pallet_balances::weights::SubstrateWeight; } +parameter_types! { + pub FeeMultiplier: Multiplier = Multiplier::one(); +} + impl pallet_transaction_payment::Config for Runtime { type Event = Event; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; type LengthToFee = IdentityFee; - type FeeMultiplierUpdate = (); + type FeeMultiplierUpdate = ConstFeeMultiplier; } impl pallet_sudo::Config for Runtime { diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index cbdc9dcb1e846..b3c53cc048bad 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -226,6 +226,30 @@ where } } +/// A struct to make the fee multiplier a constant +pub struct ConstFeeMultiplier>(sp_std::marker::PhantomData); + +impl> MultiplierUpdate for ConstFeeMultiplier { + fn min() -> Multiplier { + M::get() + } + fn target() -> Perquintill { + Default::default() + } + fn variability() -> Multiplier { + Default::default() + } +} + +impl Convert for ConstFeeMultiplier +where + M: Get, +{ + fn convert(_previous: Multiplier) -> Multiplier { + Self::min() + } +} + /// Storage releases of the pallet. #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] enum Releases { @@ -371,7 +395,8 @@ pub mod pallet { // add 1 percent; let addition = target / 100; if addition == Weight::zero() { - // this is most likely because in a test setup we set everything to (). + // this is most likely because in a test setup we set everything to () + // or to `ConstFeeMultiplier`. return } From 7cb78ff1b0df2ac947e8198890b73f5b7f741e0b Mon Sep 17 00:00:00 2001 From: Vlad Date: Mon, 12 Sep 2022 20:48:10 +0300 Subject: [PATCH 1148/1472] Don't run `cargo-check-benches` for `master` based downstream staging pipelines (#12233) --- .gitlab-ci.yml | 12 ++++++++++++ scripts/ci/gitlab/pipeline/test.yml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 765112bfa9e62..a639505b3bb03 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -150,6 +150,18 @@ default: - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs +# handle the specific case where benches could store incorrect bench data because of the downstream staging runs +# exclude cargo-check-benches from such runs +.test-refs-no-trigger-prs-only-check-benches: + rules: + - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "parent_pipeline" && $CI_IMAGE =~ /staging$/ + when: never + - if: $CI_PIPELINE_SOURCE == "pipeline" + when: never + - if: $CI_PIPELINE_SOURCE == "web" + - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + .test-refs-wasmer-sandbox: rules: - if: $CI_PIPELINE_SOURCE == "web" diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 50916a37fcf55..7be445b0bca98 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -59,7 +59,7 @@ cargo-check-benches: CI_JOB_NAME: "cargo-check-benches" extends: - .docker-env - - .test-refs + - .test-refs-no-trigger-prs-only-check-benches - .collect-artifacts - .pipeline-stopper-artifacts before_script: From dd1f1b5f291aa2325eddf5f26037b84cfbbe0957 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 12 Sep 2022 19:10:32 +0100 Subject: [PATCH 1149/1472] Expose some of the staking miner types over metadata (#12245) * Expose some of the staking miner types over metadata * Update frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Emily Ostbo <47109040+EmilyOstbo@users.noreply.github.com> Co-authored-by: Emily Ostbo <47109040+EmilyOstbo@users.noreply.github.com> --- .../election-provider-multi-phase/src/lib.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index bfe5cb2e96728..a9ce35499a329 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -708,6 +708,25 @@ pub mod pallet { type WeightInfo: WeightInfo; } + // Expose miner configs over the metadata such that they can be re-implemented. + #[pallet::extra_constants] + impl Pallet { + #[pallet::constant_name(MinerMaxLength)] + fn max_length() -> u32 { + ::MaxLength::get() + } + + #[pallet::constant_name(MinerMaxWeight)] + fn max_weight() -> Weight { + ::MaxWeight::get() + } + + #[pallet::constant_name(MinerMaxVotesPerVoter)] + fn max_votes_per_voter() -> u32 { + ::MaxVotesPerVoter::get() + } + } + #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(now: T::BlockNumber) -> Weight { From f1c60e529a6c1d158a0a37fe0a8daf887b2b9f74 Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 13 Sep 2022 05:34:43 +0800 Subject: [PATCH 1150/1472] extract some grandpa types to Primitives crate (#12208) * extract some grandpa types to primitives * fmt * fmt --- client/finality-grandpa/src/aux_schema.rs | 10 +-- .../src/communication/gossip.rs | 16 ++--- .../finality-grandpa/src/communication/mod.rs | 27 ++++---- client/finality-grandpa/src/environment.rs | 62 +++++++++++-------- client/finality-grandpa/src/finality_proof.rs | 9 ++- client/finality-grandpa/src/justification.rs | 57 ++++++++++++----- client/finality-grandpa/src/lib.rs | 53 +++------------- client/finality-grandpa/src/tests.rs | 2 +- client/finality-grandpa/src/until_imported.rs | 21 ++++--- frame/transaction-payment/rpc/src/lib.rs | 3 +- primitives/finality-grandpa/src/lib.rs | 62 ++++++++++++++++++- 11 files changed, 197 insertions(+), 125 deletions(-) diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/finality-grandpa/src/aux_schema.rs index 25ed4a3f490e0..235453ea35df1 100644 --- a/client/finality-grandpa/src/aux_schema.rs +++ b/client/finality-grandpa/src/aux_schema.rs @@ -191,7 +191,7 @@ where "state is for completed round; completed rounds must have a prevote ghost; qed.", ); - let mut current_rounds = CurrentRounds::new(); + let mut current_rounds = CurrentRounds::::new(); current_rounds.insert(last_round_number + 1, HasVoted::No); let set_state = VoterSetState::Live { @@ -255,7 +255,7 @@ where let base = set_state.prevote_ghost .expect("state is for completed round; completed rounds must have a prevote ghost; qed."); - let mut current_rounds = CurrentRounds::new(); + let mut current_rounds = CurrentRounds::::new(); current_rounds.insert(last_round_number + 1, HasVoted::No); VoterSetState::Live { @@ -500,7 +500,7 @@ mod test { use super::*; use sp_core::{crypto::UncheckedFrom, H256}; use sp_finality_grandpa::AuthorityId; - use substrate_test_runtime_client; + use substrate_test_runtime_client::{self, runtime::Block}; fn dummy_id() -> AuthorityId { AuthorityId::unchecked_from([1; 32]) @@ -574,7 +574,7 @@ mod test { .unwrap(), ); - let mut current_rounds = CurrentRounds::new(); + let mut current_rounds = CurrentRounds::::new(); current_rounds.insert(round_number + 1, HasVoted::No); assert_eq!( @@ -667,7 +667,7 @@ mod test { .unwrap(), ); - let mut current_rounds = CurrentRounds::new(); + let mut current_rounds = CurrentRounds::::new(); current_rounds.insert(round_number + 1, HasVoted::No); assert_eq!( diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 5f94a4d1b65be..95efedf7b23b7 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -350,7 +350,7 @@ pub(super) struct VoteMessage { /// The voter set ID this message is from. pub(super) set_id: SetId, /// The message itself. - pub(super) message: SignedMessage, + pub(super) message: SignedMessage, } /// Network level commit message with topic information. @@ -361,7 +361,7 @@ pub(super) struct FullCommitMessage { /// The voter set ID this message is from. pub(super) set_id: SetId, /// The compact commit message. - pub(super) message: CompactCommit, + pub(super) message: CompactCommit, } /// V1 neighbor packet. Neighbor packets are sent from nodes to their peers @@ -406,7 +406,7 @@ pub(super) struct FullCatchUpMessage { /// The voter set ID this message is from. pub(super) set_id: SetId, /// The compact commit message. - pub(super) message: CatchUp, + pub(super) message: CatchUp, } /// Misbehavior that peers can perform. @@ -1071,7 +1071,7 @@ impl Inner { let (base_hash, base_number) = last_completed_round.base; - let catch_up = CatchUp:: { + let catch_up = CatchUp:: { round_number: last_completed_round.number, prevotes, precommits, @@ -1651,8 +1651,8 @@ mod tests { use crate::communication; use sc_network::config::Role; use sc_network_gossip::Validator as GossipValidatorT; - use sc_network_test::Block; use sp_core::{crypto::UncheckedFrom, H256}; + use substrate_test_runtime_client::runtime::{Block, Header}; // some random config (not really needed) fn config() -> crate::Config { @@ -1856,7 +1856,7 @@ mod tests { &VoteMessage { round: Round(1), set_id: SetId(set_id), - message: SignedMessage:: { + message: SignedMessage::
{ message: finality_grandpa::Message::Prevote(finality_grandpa::Prevote { target_hash: Default::default(), target_number: 10, @@ -1872,7 +1872,7 @@ mod tests { &VoteMessage { round: Round(1), set_id: SetId(set_id), - message: SignedMessage:: { + message: SignedMessage::
{ message: finality_grandpa::Message::Prevote(finality_grandpa::Prevote { target_hash: Default::default(), target_number: 10, @@ -1943,7 +1943,7 @@ mod tests { votes: Default::default(), }); - let mut current_rounds = environment::CurrentRounds::new(); + let mut current_rounds = environment::CurrentRounds::::new(); current_rounds.insert(3, environment::HasVoted::No); let set_state = diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 04d7ceaa05c8c..d211c10ae62be 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -312,8 +312,8 @@ impl> NetworkBridge { round: Round, set_id: SetId, voters: Arc>, - has_voted: HasVoted, - ) -> (impl Stream> + Unpin, OutgoingMessages) { + has_voted: HasVoted, + ) -> (impl Stream> + Unpin, OutgoingMessages) { self.note_round(round, set_id, &voters); let keystore = keystore.and_then(|ks| { @@ -675,15 +675,15 @@ pub(crate) struct OutgoingMessages { round: RoundNumber, set_id: SetIdNumber, keystore: Option, - sender: mpsc::Sender>, + sender: mpsc::Sender>, network: Arc>>, - has_voted: HasVoted, + has_voted: HasVoted, telemetry: Option, } impl Unpin for OutgoingMessages {} -impl Sink> for OutgoingMessages { +impl Sink> for OutgoingMessages { type Error = Error; fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { @@ -694,7 +694,10 @@ impl Sink> for OutgoingMessages { }) } - fn start_send(mut self: Pin<&mut Self>, mut msg: Message) -> Result<(), Self::Error> { + fn start_send( + mut self: Pin<&mut Self>, + mut msg: Message, + ) -> Result<(), Self::Error> { // if we've voted on this round previously under the same key, send that vote instead match &mut msg { finality_grandpa::Message::PrimaryPropose(ref mut vote) => { @@ -784,7 +787,7 @@ impl Sink> for OutgoingMessages { // checks a compact commit. returns the cost associated with processing it if // the commit was bad. fn check_compact_commit( - msg: &CompactCommit, + msg: &CompactCommit, voters: &VoterSet, round: Round, set_id: SetId, @@ -852,7 +855,7 @@ fn check_compact_commit( // checks a catch up. returns the cost associated with processing it if // the catch up was bad. fn check_catch_up( - msg: &CatchUp, + msg: &CatchUp, voters: &VoterSet, set_id: SetId, telemetry: Option, @@ -902,7 +905,7 @@ fn check_catch_up( ) -> Result where B: BlockT, - I: Iterator, &'a AuthorityId, &'a AuthoritySignature)>, + I: Iterator, &'a AuthorityId, &'a AuthoritySignature)>, { use crate::communication::gossip::Misbehavior; @@ -996,7 +999,7 @@ impl CommitsOut { } } -impl Sink<(RoundNumber, Commit)> for CommitsOut { +impl Sink<(RoundNumber, Commit)> for CommitsOut { type Error = Error; fn poll_ready(self: Pin<&mut Self>, _: &mut Context) -> Poll> { @@ -1005,7 +1008,7 @@ impl Sink<(RoundNumber, Commit)> for CommitsOut { fn start_send( self: Pin<&mut Self>, - input: (RoundNumber, Commit), + input: (RoundNumber, Commit), ) -> Result<(), Self::Error> { if !self.is_voter { return Ok(()) @@ -1027,7 +1030,7 @@ impl Sink<(RoundNumber, Commit)> for CommitsOut { .map(|signed| (signed.precommit, (signed.signature, signed.id))) .unzip(); - let compact_commit = CompactCommit:: { + let compact_commit = CompactCommit:: { target_hash: commit.target_hash, target_number: commit.target_number, precommits, diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 63c8697053842..3d708a95f41cb 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -81,7 +81,7 @@ pub struct CompletedRound { /// The target block base used for voting in the round. pub base: (Block::Hash, NumberFor), /// All the votes observed in the round. - pub votes: Vec>, + pub votes: Vec>, } // Data about last completed rounds within a single voter set. Stores @@ -170,7 +170,7 @@ impl CompletedRounds { /// A map with voter status information for currently live rounds, /// which votes have we cast and what are they. -pub type CurrentRounds = BTreeMap>; +pub type CurrentRounds = BTreeMap::Header>>; /// The state of the current voter set, whether it is currently active or not /// and information related to the previously completed rounds. Current round @@ -214,7 +214,7 @@ impl VoterSetState { authority_set, ); - let mut current_rounds = CurrentRounds::new(); + let mut current_rounds = CurrentRounds::::new(); current_rounds.insert(1, HasVoted::No); VoterSetState::Live { completed_rounds, current_rounds } @@ -258,27 +258,27 @@ impl VoterSetState { /// Whether we've voted already during a prior run of the program. #[derive(Clone, Debug, Decode, Encode, PartialEq)] -pub enum HasVoted { +pub enum HasVoted { /// Has not voted already in this round. No, /// Has voted in this round. - Yes(AuthorityId, Vote), + Yes(AuthorityId, Vote
), } /// The votes cast by this voter already during a prior run of the program. #[derive(Debug, Clone, Decode, Encode, PartialEq)] -pub enum Vote { +pub enum Vote { /// Has cast a proposal. - Propose(PrimaryPropose), + Propose(PrimaryPropose
), /// Has cast a prevote. - Prevote(Option>, Prevote), + Prevote(Option>, Prevote
), /// Has cast a precommit (implies prevote.) - Precommit(Option>, Prevote, Precommit), + Precommit(Option>, Prevote
, Precommit
), } -impl HasVoted { +impl HasVoted
{ /// Returns the proposal we should vote with (if any.) - pub fn propose(&self) -> Option<&PrimaryPropose> { + pub fn propose(&self) -> Option<&PrimaryPropose
> { match self { HasVoted::Yes(_, Vote::Propose(propose)) => Some(propose), HasVoted::Yes(_, Vote::Prevote(propose, _)) | @@ -288,7 +288,7 @@ impl HasVoted { } /// Returns the prevote we should vote with (if any.) - pub fn prevote(&self) -> Option<&Prevote> { + pub fn prevote(&self) -> Option<&Prevote
> { match self { HasVoted::Yes(_, Vote::Prevote(_, prevote)) | HasVoted::Yes(_, Vote::Precommit(_, prevote, _)) => Some(prevote), @@ -297,7 +297,7 @@ impl HasVoted { } /// Returns the precommit we should vote with (if any.) - pub fn precommit(&self) -> Option<&Precommit> { + pub fn precommit(&self) -> Option<&Precommit
> { match self { HasVoted::Yes(_, Vote::Precommit(_, _, precommit)) => Some(precommit), _ => None, @@ -368,7 +368,7 @@ impl SharedVoterSetState { } /// Return vote status information for the current round. - pub(crate) fn has_voted(&self, round: RoundNumber) -> HasVoted { + pub(crate) fn has_voted(&self, round: RoundNumber) -> HasVoted { match &*self.inner.read() { VoterSetState::Live { current_rounds, .. } => current_rounds .get(&round) @@ -771,7 +771,7 @@ where fn proposed( &self, round: RoundNumber, - propose: PrimaryPropose, + propose: PrimaryPropose, ) -> Result<(), Self::Error> { let local_id = match self.voter_set_state.voting_on(round) { Some(id) => id, @@ -811,13 +811,17 @@ where Ok(()) } - fn prevoted(&self, round: RoundNumber, prevote: Prevote) -> Result<(), Self::Error> { + fn prevoted( + &self, + round: RoundNumber, + prevote: Prevote, + ) -> Result<(), Self::Error> { let local_id = match self.voter_set_state.voting_on(round) { Some(id) => id, None => return Ok(()), }; - let report_prevote_metrics = |prevote: &Prevote| { + let report_prevote_metrics = |prevote: &Prevote| { telemetry!( self.telemetry; CONSENSUS_DEBUG; @@ -873,14 +877,14 @@ where fn precommitted( &self, round: RoundNumber, - precommit: Precommit, + precommit: Precommit, ) -> Result<(), Self::Error> { let local_id = match self.voter_set_state.voting_on(round) { Some(id) => id, None => return Ok(()), }; - let report_precommit_metrics = |precommit: &Precommit| { + let report_precommit_metrics = |precommit: &Precommit| { telemetry!( self.telemetry; CONSENSUS_DEBUG; @@ -1065,7 +1069,7 @@ where hash: Block::Hash, number: NumberFor, round: RoundNumber, - commit: Commit, + commit: Commit, ) -> Result<(), Self::Error> { finalize_block( self.client.clone(), @@ -1092,7 +1096,11 @@ where fn prevote_equivocation( &self, _round: RoundNumber, - equivocation: finality_grandpa::Equivocation, Self::Signature>, + equivocation: finality_grandpa::Equivocation< + Self::Id, + Prevote, + Self::Signature, + >, ) { warn!(target: "afg", "Detected prevote equivocation in the finality worker: {:?}", equivocation); if let Err(err) = self.report_equivocation(equivocation.into()) { @@ -1103,7 +1111,11 @@ where fn precommit_equivocation( &self, _round: RoundNumber, - equivocation: finality_grandpa::Equivocation, Self::Signature>, + equivocation: finality_grandpa::Equivocation< + Self::Id, + Precommit, + Self::Signature, + >, ) { warn!(target: "afg", "Detected precommit equivocation in the finality worker: {:?}", equivocation); if let Err(err) = self.report_equivocation(equivocation.into()) { @@ -1114,11 +1126,11 @@ where pub(crate) enum JustificationOrCommit { Justification(GrandpaJustification), - Commit((RoundNumber, Commit)), + Commit((RoundNumber, Commit)), } -impl From<(RoundNumber, Commit)> for JustificationOrCommit { - fn from(commit: (RoundNumber, Commit)) -> JustificationOrCommit { +impl From<(RoundNumber, Commit)> for JustificationOrCommit { + fn from(commit: (RoundNumber, Commit)) -> JustificationOrCommit { JustificationOrCommit::Commit(commit) } } diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index ac243a1633ee1..e7578fa669463 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -380,8 +380,13 @@ mod tests { precommits: Vec::new(), }; - let grandpa_just = - GrandpaJustification:: { round: 8, votes_ancestries: Vec::new(), commit }; + let grandpa_just: GrandpaJustification = + sp_finality_grandpa::GrandpaJustification::
{ + round: 8, + votes_ancestries: Vec::new(), + commit, + } + .into(); let finality_proof = FinalityProof { block: header(2).hash(), diff --git a/client/finality-grandpa/src/justification.rs b/client/finality-grandpa/src/justification.rs index 6c3b6aa826ded..56b26c964ce9b 100644 --- a/client/finality-grandpa/src/justification.rs +++ b/client/finality-grandpa/src/justification.rs @@ -18,6 +18,7 @@ use std::{ collections::{HashMap, HashSet}, + marker::PhantomData, sync::Arc, }; @@ -42,9 +43,25 @@ use crate::{AuthorityList, Commit, Error}; /// nodes, and are used by syncing nodes to prove authority set handoffs. #[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)] pub struct GrandpaJustification { - pub(crate) round: u64, - pub(crate) commit: Commit, - pub(crate) votes_ancestries: Vec, + /// The GRANDPA justification for block finality. + pub justification: sp_finality_grandpa::GrandpaJustification, + _block: PhantomData, +} + +impl From> + for GrandpaJustification +{ + fn from(justification: sp_finality_grandpa::GrandpaJustification) -> Self { + Self { justification, _block: Default::default() } + } +} + +impl Into> + for GrandpaJustification +{ + fn into(self) -> sp_finality_grandpa::GrandpaJustification { + self.justification + } } impl GrandpaJustification { @@ -53,8 +70,8 @@ impl GrandpaJustification { pub fn from_commit( client: &Arc, round: u64, - commit: Commit, - ) -> Result, Error> + commit: Commit, + ) -> Result where C: HeaderBackend, { @@ -108,7 +125,7 @@ impl GrandpaJustification { } } - Ok(GrandpaJustification { round, commit, votes_ancestries }) + Ok(sp_finality_grandpa::GrandpaJustification { round, commit, votes_ancestries }.into()) } /// Decode a GRANDPA justification and validate the commit and the votes' @@ -118,15 +135,17 @@ impl GrandpaJustification { finalized_target: (Block::Hash, NumberFor), set_id: u64, voters: &VoterSet, - ) -> Result, ClientError> + ) -> Result where NumberFor: finality_grandpa::BlockNumberOps, { let justification = GrandpaJustification::::decode(&mut &*encoded) .map_err(|_| ClientError::JustificationDecode)?; - if (justification.commit.target_hash, justification.commit.target_number) != - finalized_target + if ( + justification.justification.commit.target_hash, + justification.justification.commit.target_number, + ) != finalized_target { let msg = "invalid commit target in grandpa justification".to_string(); Err(ClientError::BadJustification(msg)) @@ -157,9 +176,10 @@ impl GrandpaJustification { { use finality_grandpa::Chain; - let ancestry_chain = AncestryChain::::new(&self.votes_ancestries); + let ancestry_chain = AncestryChain::::new(&self.justification.votes_ancestries); - match finality_grandpa::validate_commit(&self.commit, voters, &ancestry_chain) { + match finality_grandpa::validate_commit(&self.justification.commit, voters, &ancestry_chain) + { Ok(ref result) if result.is_valid() => {}, _ => { let msg = "invalid commit in grandpa justification".to_string(); @@ -171,6 +191,7 @@ impl GrandpaJustification { // should serve as the root block for populating ancestry (i.e. // collect all headers from all precommit blocks to the base) let base_hash = self + .justification .commit .precommits .iter() @@ -186,12 +207,12 @@ impl GrandpaJustification { let mut buf = Vec::new(); let mut visited_hashes = HashSet::new(); - for signed in self.commit.precommits.iter() { + for signed in self.justification.commit.precommits.iter() { if !sp_finality_grandpa::check_message_signature_with_buffer( &finality_grandpa::Message::Precommit(signed.precommit.clone()), &signed.id, &signed.signature, - self.round, + self.justification.round, set_id, &mut buf, ) { @@ -220,8 +241,12 @@ impl GrandpaJustification { } } - let ancestry_hashes: HashSet<_> = - self.votes_ancestries.iter().map(|h: &Block::Header| h.hash()).collect(); + let ancestry_hashes: HashSet<_> = self + .justification + .votes_ancestries + .iter() + .map(|h: &Block::Header| h.hash()) + .collect(); if visited_hashes != ancestry_hashes { return Err(ClientError::BadJustification( @@ -235,7 +260,7 @@ impl GrandpaJustification { /// The target block number and hash that this justifications proves finality for. pub fn target(&self) -> (NumberFor, Block::Hash) { - (self.commit.target_number, self.commit.target_hash) + (self.justification.commit.target_number, self.justification.commit.target_hash) } } diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 149cf1f89a222..7e47b70bd6b98 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -144,72 +144,35 @@ use sp_finality_grandpa::{AuthorityList, AuthoritySignature, SetId}; use until_imported::UntilGlobalMessageBlocksImported; // Re-export these two because it's just so damn convenient. -pub use sp_finality_grandpa::{AuthorityId, AuthorityPair, GrandpaApi, ScheduledChange}; +pub use sp_finality_grandpa::{ + AuthorityId, AuthorityPair, CatchUp, Commit, CompactCommit, GrandpaApi, Message, Precommit, + Prevote, PrimaryPropose, ScheduledChange, SignedMessage, +}; use std::marker::PhantomData; #[cfg(test)] mod tests; -/// A GRANDPA message for a substrate chain. -pub type Message = finality_grandpa::Message<::Hash, NumberFor>; - -/// A signed message. -pub type SignedMessage = finality_grandpa::SignedMessage< - ::Hash, - NumberFor, - AuthoritySignature, - AuthorityId, ->; - -/// A primary propose message for this chain's block type. -pub type PrimaryPropose = - finality_grandpa::PrimaryPropose<::Hash, NumberFor>; -/// A prevote message for this chain's block type. -pub type Prevote = finality_grandpa::Prevote<::Hash, NumberFor>; -/// A precommit message for this chain's block type. -pub type Precommit = finality_grandpa::Precommit<::Hash, NumberFor>; -/// A catch up message for this chain's block type. -pub type CatchUp = finality_grandpa::CatchUp< - ::Hash, - NumberFor, - AuthoritySignature, - AuthorityId, ->; -/// A commit message for this chain's block type. -pub type Commit = finality_grandpa::Commit< - ::Hash, - NumberFor, - AuthoritySignature, - AuthorityId, ->; -/// A compact commit message for this chain's block type. -pub type CompactCommit = finality_grandpa::CompactCommit< - ::Hash, - NumberFor, - AuthoritySignature, - AuthorityId, ->; /// A global communication input stream for commits and catch up messages. Not /// exposed publicly, used internally to simplify types in the communication /// layer. -type CommunicationIn = finality_grandpa::voter::CommunicationIn< +type CommunicationIn = voter::CommunicationIn< ::Hash, NumberFor, AuthoritySignature, AuthorityId, >; - /// Global communication input stream for commits and catch up messages, with /// the hash type not being derived from the block, useful for forcing the hash /// to some type (e.g. `H256`) when the compiler can't do the inference. type CommunicationInH = - finality_grandpa::voter::CommunicationIn, AuthoritySignature, AuthorityId>; + voter::CommunicationIn, AuthoritySignature, AuthorityId>; /// Global communication sink for commits with the hash type not being derived /// from the block, useful for forcing the hash to some type (e.g. `H256`) when /// the compiler can't do the inference. type CommunicationOutH = - finality_grandpa::voter::CommunicationOut, AuthoritySignature, AuthorityId>; + voter::CommunicationOut, AuthoritySignature, AuthorityId>; /// Shared voter state for querying. pub struct SharedVoterState { @@ -233,7 +196,7 @@ impl SharedVoterState { } /// Get the inner `VoterState` instance. - pub fn voter_state(&self) -> Option> { + pub fn voter_state(&self) -> Option> { self.inner.read().as_ref().map(|vs| vs.get()) } } diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 3dd21d51b6a2d..b1e46be5cabde 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -450,7 +450,7 @@ fn finalize_3_voters_1_full_observer() { let justification = crate::aux_schema::best_justification::<_, Block>(&*client).unwrap().unwrap(); - assert_eq!(justification.commit.target_number, 20); + assert_eq!(justification.justification.commit.target_number, 20); } } diff --git a/client/finality-grandpa/src/until_imported.rs b/client/finality-grandpa/src/until_imported.rs index fe7caf74422db..df0b63348e94b 100644 --- a/client/finality-grandpa/src/until_imported.rs +++ b/client/finality-grandpa/src/until_imported.rs @@ -354,7 +354,7 @@ fn warn_authority_wrong_target(hash: H, id: AuthorityId) ); } -impl BlockUntilImported for SignedMessage { +impl BlockUntilImported for SignedMessage { type Blocked = Self; fn needs_waiting>( @@ -389,8 +389,13 @@ impl BlockUntilImported for SignedMessage { /// Helper type definition for the stream which waits until vote targets for /// signed messages are imported. -pub(crate) type UntilVoteTargetImported = - UntilImported>; +pub(crate) type UntilVoteTargetImported = UntilImported< + Block, + BlockStatus, + BlockSyncRequester, + I, + SignedMessage<::Header>, +>; /// This blocks a global message import, i.e. a commit or catch up messages, /// until all blocks referenced in its votes are known. @@ -646,7 +651,7 @@ mod tests { // unwrap the commit from `CommunicationIn` returning its fields in a tuple, // panics if the given message isn't a commit - fn unapply_commit(msg: CommunicationIn) -> (u64, CompactCommit) { + fn unapply_commit(msg: CommunicationIn) -> (u64, CompactCommit
) { match msg { voter::CommunicationIn::Commit(round, commit, ..) => (round, commit), _ => panic!("expected commit"), @@ -655,7 +660,7 @@ mod tests { // unwrap the catch up from `CommunicationIn` returning its inner representation, // panics if the given message isn't a catch up - fn unapply_catch_up(msg: CommunicationIn) -> CatchUp { + fn unapply_catch_up(msg: CommunicationIn) -> CatchUp
{ match msg { voter::CommunicationIn::CatchUp(catch_up, ..) => catch_up, _ => panic!("expected catch up"), @@ -740,7 +745,7 @@ mod tests { let h2 = make_header(6); let h3 = make_header(7); - let unknown_commit = CompactCommit:: { + let unknown_commit = CompactCommit::
{ target_hash: h1.hash(), target_number: 5, precommits: vec![ @@ -768,7 +773,7 @@ mod tests { let h2 = make_header(6); let h3 = make_header(7); - let known_commit = CompactCommit:: { + let known_commit = CompactCommit::
{ target_hash: h1.hash(), target_number: 5, precommits: vec![ @@ -910,7 +915,7 @@ mod tests { // we create a commit message, with precommits for blocks 6 and 7 which // we haven't imported. - let unknown_commit = CompactCommit:: { + let unknown_commit = CompactCommit::
{ target_hash: h1.hash(), target_number: 5, precommits: vec![ diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index 75ec42321ef5e..0c7e26cec0f58 100644 --- a/frame/transaction-payment/rpc/src/lib.rs +++ b/frame/transaction-payment/rpc/src/lib.rs @@ -21,7 +21,7 @@ use std::{convert::TryInto, sync::Arc}; use codec::{Codec, Decode}; use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, + core::{Error as JsonRpseeError, RpcResult}, proc_macros::rpc, types::error::{CallError, ErrorCode, ErrorObject}, }; @@ -81,7 +81,6 @@ impl From for i32 { } } -#[async_trait] impl TransactionPaymentApiServer<::Hash, RuntimeDispatchInfo> for TransactionPayment diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index 4be42c3d19b6c..2adfce1bea241 100644 --- a/primitives/finality-grandpa/src/lib.rs +++ b/primitives/finality-grandpa/src/lib.rs @@ -29,7 +29,10 @@ use codec::{Codec, Decode, Encode, Input}; use scale_info::TypeInfo; #[cfg(feature = "std")] use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; -use sp_runtime::{traits::NumberFor, ConsensusEngineId, RuntimeDebug}; +use sp_runtime::{ + traits::{Header as HeaderT, NumberFor}, + ConsensusEngineId, RuntimeDebug, +}; use sp_std::{borrow::Cow, vec::Vec}; #[cfg(feature = "std")] @@ -76,6 +79,63 @@ pub type RoundNumber = u64; /// A list of Grandpa authorities with associated weights. pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>; +/// A GRANDPA message for a substrate chain. +pub type Message
= grandpa::Message<
::Hash,
::Number>; + +/// A signed message. +pub type SignedMessage
= grandpa::SignedMessage< +
::Hash, +
::Number, + AuthoritySignature, + AuthorityId, +>; + +/// A primary propose message for this chain's block type. +pub type PrimaryPropose
= + grandpa::PrimaryPropose<
::Hash,
::Number>; +/// A prevote message for this chain's block type. +pub type Prevote
= grandpa::Prevote<
::Hash,
::Number>; +/// A precommit message for this chain's block type. +pub type Precommit
= + grandpa::Precommit<
::Hash,
::Number>; +/// A catch up message for this chain's block type. +pub type CatchUp
= grandpa::CatchUp< +
::Hash, +
::Number, + AuthoritySignature, + AuthorityId, +>; +/// A commit message for this chain's block type. +pub type Commit
= grandpa::Commit< +
::Hash, +
::Number, + AuthoritySignature, + AuthorityId, +>; + +/// A compact commit message for this chain's block type. +pub type CompactCommit
= grandpa::CompactCommit< +
::Hash, +
::Number, + AuthoritySignature, + AuthorityId, +>; + +/// A GRANDPA justification for block finality, it includes a commit message and +/// an ancestry proof including all headers routing all precommit target blocks +/// to the commit target block. Due to the current voting strategy the precommit +/// targets should be the same as the commit target, since honest voters don't +/// vote past authority set change blocks. +/// +/// This is meant to be stored in the db and passed around the network to other +/// nodes, and are used by syncing nodes to prove authority set handoffs. +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)] +pub struct GrandpaJustification { + pub round: u64, + pub commit: Commit
, + pub votes_ancestries: Vec
, +} + /// A scheduled change of authority set. #[cfg_attr(feature = "std", derive(Serialize))] #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)] From 5527263978a763bafc78d60955c662c20f465d18 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Tue, 13 Sep 2022 00:03:31 +0200 Subject: [PATCH 1151/1472] BREAKING: Rename Call & Event (#11981) * rename Event to RuntimeEvent * rename Call * rename in runtimes * small fix * rename Event * small fix & rename RuntimeCall back to Call for now * small fixes * more renaming * a bit more renaming * fmt * small fix * commit * prep for renaming associated types * fix * rename associated Event type * rename to RuntimeEvent * commit * merge conflict fixes & fmt * additional renaming * fix. * fix decl_event * rename in tests * remove warnings * remove accidental rename * . * commit * update .stderr * fix in test * update .stderr * TRYBUILD=overwrite * docs * fmt * small change in docs * rename PalletEvent to Event * rename Call to RuntimeCall * renamed at wrong places :P * rename Call * rename * rename associated type * fix * fix & fmt * commit * frame-support-test * passing tests * update docs * rustdoc fix * update .stderr * wrong code in docs * merge fix * fix in error message * update .stderr * docs & error message * . * merge fix * merge fix * fmt * fmt * merge fix * more fixing * fmt * remove unused * fmt * fix Co-authored-by: Shawn Tabrizi --- bin/node-template/node/src/benchmarking.rs | 2 +- bin/node-template/pallets/template/src/lib.rs | 2 +- .../pallets/template/src/mock.rs | 6 +- bin/node-template/runtime/src/lib.rs | 29 +-- bin/node/cli/benches/block_production.rs | 2 +- bin/node/cli/src/service.rs | 10 +- bin/node/executor/benches/bench.rs | 8 +- bin/node/executor/tests/basic.rs | 94 +++++---- bin/node/executor/tests/fees.rs | 25 ++- bin/node/runtime/src/impls.rs | 9 +- bin/node/runtime/src/lib.rs | 188 ++++++++--------- bin/node/testing/src/bench.rs | 11 +- docs/Upgrading-2.0-to-3.0.md | 2 +- frame/alliance/src/benchmarking.rs | 2 +- frame/alliance/src/lib.rs | 5 +- frame/alliance/src/mock.rs | 36 ++-- frame/alliance/src/tests.rs | 50 ++--- frame/assets/src/benchmarking.rs | 4 +- frame/assets/src/lib.rs | 3 +- frame/assets/src/mock.rs | 8 +- frame/atomic-swap/src/lib.rs | 2 +- frame/atomic-swap/src/tests.rs | 8 +- frame/aura/src/mock.rs | 4 +- frame/authority-discovery/src/lib.rs | 6 +- frame/authorship/src/lib.rs | 4 +- frame/babe/src/mock.rs | 18 +- frame/bags-list/src/lib.rs | 3 +- frame/bags-list/src/mock.rs | 6 +- frame/balances/src/lib.rs | 3 +- frame/balances/src/tests.rs | 44 ++-- frame/balances/src/tests_composite.rs | 8 +- frame/balances/src/tests_local.rs | 25 ++- frame/balances/src/tests_reentrancy.rs | 33 +-- frame/beefy-mmr/src/mock.rs | 6 +- frame/beefy/src/mock.rs | 6 +- frame/benchmarking/src/baseline.rs | 4 +- frame/benchmarking/src/tests.rs | 4 +- frame/benchmarking/src/tests_instance.rs | 20 +- frame/bounties/src/benchmarking.rs | 2 +- frame/bounties/src/lib.rs | 3 +- frame/bounties/src/tests.rs | 16 +- frame/child-bounties/src/benchmarking.rs | 2 +- frame/child-bounties/src/lib.rs | 2 +- frame/child-bounties/src/tests.rs | 14 +- frame/collective/src/benchmarking.rs | 2 +- frame/collective/src/lib.rs | 3 +- frame/collective/src/tests.rs | 167 ++++++++------- frame/contracts/src/exec.rs | 18 +- frame/contracts/src/lib.rs | 12 +- frame/contracts/src/tests.rs | 195 +++++++++--------- frame/contracts/src/wasm/mod.rs | 12 +- frame/contracts/src/wasm/runtime.rs | 2 +- frame/conviction-voting/src/lib.rs | 3 +- frame/conviction-voting/src/tests.rs | 14 +- frame/democracy/src/benchmarking.rs | 2 +- frame/democracy/src/lib.rs | 2 +- frame/democracy/src/tests.rs | 30 +-- .../election-provider-multi-phase/src/lib.rs | 4 +- .../election-provider-multi-phase/src/mock.rs | 19 +- .../src/unsigned.rs | 4 +- .../election-provider-support/src/onchain.rs | 4 +- frame/elections-phragmen/src/lib.rs | 23 ++- frame/examples/basic/src/lib.rs | 6 +- frame/examples/basic/src/tests.rs | 8 +- frame/examples/offchain-worker/src/lib.rs | 5 +- frame/examples/offchain-worker/src/tests.rs | 30 +-- frame/examples/parallel/src/lib.rs | 5 +- frame/examples/parallel/src/tests.rs | 8 +- frame/executive/src/lib.rs | 40 ++-- frame/gilt/src/lib.rs | 2 +- frame/gilt/src/mock.rs | 8 +- frame/grandpa/src/lib.rs | 9 +- frame/grandpa/src/mock.rs | 21 +- frame/identity/src/benchmarking.rs | 2 +- frame/identity/src/lib.rs | 2 +- frame/identity/src/tests.rs | 8 +- frame/im-online/src/lib.rs | 2 +- frame/im-online/src/mock.rs | 14 +- frame/im-online/src/tests.rs | 6 +- frame/indices/src/lib.rs | 2 +- frame/indices/src/mock.rs | 8 +- frame/lottery/src/lib.rs | 26 ++- frame/lottery/src/mock.rs | 10 +- frame/lottery/src/tests.rs | 72 ++++--- frame/membership/src/lib.rs | 11 +- frame/merkle-mountain-range/src/mock.rs | 4 +- frame/multisig/src/benchmarking.rs | 4 +- frame/multisig/src/lib.rs | 10 +- frame/multisig/src/tests.rs | 24 +-- frame/nicks/src/lib.rs | 10 +- frame/node-authorization/src/lib.rs | 2 +- frame/node-authorization/src/mock.rs | 6 +- .../nomination-pools/benchmarking/src/mock.rs | 12 +- frame/nomination-pools/src/lib.rs | 2 +- frame/nomination-pools/src/mock.rs | 12 +- frame/nomination-pools/src/tests.rs | 2 +- .../nomination-pools/test-staking/src/mock.rs | 16 +- frame/offences/benchmarking/src/lib.rs | 14 +- frame/offences/benchmarking/src/mock.rs | 22 +- frame/offences/src/lib.rs | 2 +- frame/offences/src/mock.rs | 6 +- frame/offences/src/tests.rs | 8 +- frame/preimage/src/lib.rs | 2 +- frame/preimage/src/mock.rs | 8 +- frame/proxy/src/benchmarking.rs | 12 +- frame/proxy/src/lib.rs | 18 +- frame/proxy/src/tests.rs | 69 ++++--- frame/randomness-collective-flip/src/lib.rs | 4 +- frame/ranked-collective/src/benchmarking.rs | 2 +- frame/ranked-collective/src/lib.rs | 3 +- frame/ranked-collective/src/tests.rs | 6 +- frame/recovery/src/benchmarking.rs | 4 +- frame/recovery/src/lib.rs | 6 +- frame/recovery/src/mock.rs | 10 +- frame/recovery/src/tests.rs | 12 +- frame/referenda/src/benchmarking.rs | 2 +- frame/referenda/src/lib.rs | 5 +- frame/referenda/src/mock.rs | 32 +-- frame/referenda/src/tests.rs | 2 +- frame/referenda/src/types.rs | 2 +- frame/remark/src/benchmarking.rs | 4 +- frame/remark/src/lib.rs | 2 +- frame/remark/src/mock.rs | 6 +- frame/remark/src/tests.rs | 2 +- frame/scheduler/src/benchmarking.rs | 4 +- frame/scheduler/src/lib.rs | 54 ++--- frame/scheduler/src/mock.rs | 20 +- frame/scheduler/src/tests.rs | 183 ++++++++++------ frame/scored-pool/src/lib.rs | 3 +- frame/scored-pool/src/mock.rs | 8 +- frame/session/benchmarking/src/mock.rs | 10 +- frame/session/src/lib.rs | 2 +- frame/session/src/mock.rs | 6 +- frame/society/src/lib.rs | 3 +- frame/society/src/mock.rs | 8 +- frame/staking/src/mock.rs | 18 +- frame/staking/src/pallet/mod.rs | 2 +- frame/staking/src/tests.rs | 15 +- frame/state-trie-migration/src/lib.rs | 12 +- frame/sudo/src/lib.rs | 12 +- frame/sudo/src/mock.rs | 16 +- frame/sudo/src/tests.rs | 26 +-- .../src/construct_runtime/expand/call.rs | 24 +-- .../src/construct_runtime/expand/event.rs | 8 +- .../src/construct_runtime/expand/origin.rs | 6 +- .../src/construct_runtime/expand/unsigned.rs | 6 +- frame/support/procedural/src/lib.rs | 2 +- .../procedural/src/pallet/expand/call.rs | 2 +- .../procedural/src/pallet/expand/event.rs | 9 +- .../procedural/src/pallet/parse/config.rs | 24 ++- .../procedural/src/pallet/parse/mod.rs | 28 +-- frame/support/src/dispatch.rs | 16 +- frame/support/src/lib.rs | 12 +- frame/support/test/compile_pass/src/lib.rs | 6 +- frame/support/test/tests/construct_runtime.rs | 60 +++--- .../both_use_and_excluded_parts.rs | 2 +- .../both_use_and_excluded_parts.stderr | 25 +-- .../exclude_undefined_part.rs | 2 +- .../exclude_undefined_part.stderr | 25 +-- .../no_std_genesis_config.rs | 6 +- .../pallet_error_too_large.rs | 6 +- .../undefined_call_part.rs | 6 +- .../undefined_event_part.rs | 6 +- .../undefined_event_part.stderr | 33 --- .../undefined_genesis_config_part.rs | 6 +- .../undefined_inherent_part.rs | 6 +- .../undefined_origin_part.rs | 6 +- .../undefined_validate_unsigned_part.rs | 6 +- .../undefined_validate_unsigned_part.stderr | 4 +- .../use_undefined_part.rs | 2 +- .../use_undefined_part.stderr | 25 +-- frame/support/test/tests/instance.rs | 22 +- frame/support/test/tests/issue2219.rs | 6 +- frame/support/test/tests/origin.rs | 14 +- frame/support/test/tests/pallet.rs | 78 +++---- .../test/tests/pallet_compatibility.rs | 14 +- .../tests/pallet_compatibility_instance.rs | 23 ++- frame/support/test/tests/pallet_instance.rs | 36 ++-- .../tests/pallet_ui/event_field_not_member.rs | 2 +- .../tests/pallet_ui/event_not_in_trait.stderr | 2 +- .../pallet_ui/event_type_invalid_bound.rs | 2 +- .../pallet_ui/event_type_invalid_bound.stderr | 4 +- .../pallet_ui/event_type_invalid_bound_2.rs | 2 +- .../event_type_invalid_bound_2.stderr | 4 +- .../tests/pallet_with_name_trait_is_valid.rs | 10 +- frame/support/test/tests/storage_layers.rs | 14 +- frame/support/test/tests/system.rs | 8 +- frame/system/benches/bench.rs | 8 +- frame/system/benchmarking/src/mock.rs | 4 +- frame/system/src/extensions/check_genesis.rs | 2 +- .../system/src/extensions/check_mortality.rs | 2 +- .../src/extensions/check_non_zero_sender.rs | 4 +- frame/system/src/extensions/check_nonce.rs | 4 +- .../src/extensions/check_spec_version.rs | 2 +- .../system/src/extensions/check_tx_version.rs | 2 +- frame/system/src/extensions/check_weight.rs | 22 +- frame/system/src/lib.rs | 26 +-- frame/system/src/mock.rs | 8 +- frame/system/src/mocking.rs | 2 +- frame/system/src/offchain.rs | 8 +- frame/timestamp/src/mock.rs | 4 +- frame/tips/src/lib.rs | 3 +- frame/tips/src/tests.rs | 16 +- .../asset-tx-payment/src/lib.rs | 12 +- .../asset-tx-payment/src/payment.rs | 16 +- .../asset-tx-payment/src/tests.rs | 16 +- frame/transaction-payment/src/lib.rs | 84 ++++---- frame/transaction-payment/src/payment.rs | 16 +- frame/transaction-storage/src/benchmarking.rs | 4 +- frame/transaction-storage/src/lib.rs | 4 +- frame/transaction-storage/src/mock.rs | 10 +- frame/treasury/src/benchmarking.rs | 2 +- frame/treasury/src/lib.rs | 3 +- frame/treasury/src/tests.rs | 8 +- frame/uniques/src/benchmarking.rs | 4 +- frame/uniques/src/lib.rs | 3 +- frame/uniques/src/mock.rs | 8 +- frame/uniques/src/tests.rs | 6 +- frame/utility/src/benchmarking.rs | 8 +- frame/utility/src/lib.rs | 33 +-- frame/utility/src/tests.rs | 111 ++++++---- frame/vesting/src/lib.rs | 2 +- frame/vesting/src/mock.rs | 8 +- frame/whitelist/src/benchmarking.rs | 4 +- frame/whitelist/src/lib.rs | 10 +- frame/whitelist/src/mock.rs | 12 +- frame/whitelist/src/tests.rs | 13 +- test-utils/runtime/src/lib.rs | 10 +- 228 files changed, 1792 insertions(+), 1673 deletions(-) diff --git a/bin/node-template/node/src/benchmarking.rs b/bin/node-template/node/src/benchmarking.rs index f0e32104cd3ee..90fe06edf04b8 100644 --- a/bin/node-template/node/src/benchmarking.rs +++ b/bin/node-template/node/src/benchmarking.rs @@ -119,7 +119,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { pub fn create_benchmark_extrinsic( client: &FullClient, sender: sp_core::sr25519::Pair, - call: runtime::Call, + call: runtime::RuntimeCall, nonce: u32, ) -> runtime::UncheckedExtrinsic { let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index a9209a9040b6d..0b55d7ae86fcf 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -27,7 +27,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// Because this pallet emits events, it depends on the runtime's definition of an event. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } // The pallet's runtime storage items. diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index e03f37b2eea69..3289ec2da4952 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -28,7 +28,7 @@ impl system::Config for Test { type BlockLength = (); type DbWeight = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -36,7 +36,7 @@ impl system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -50,7 +50,7 @@ impl system::Config for Test { } impl pallet_template::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } // Build genesis storage according to the mock runtime. diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index e9c2800ffa3f5..099654a12a420 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -158,7 +158,7 @@ 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 Call = Call; + 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. @@ -172,7 +172,7 @@ impl frame_system::Config for Runtime { /// The header type. type Header = generic::Header; /// The ubiquitous event type. - type Event = Event; + type RuntimeEvent = RuntimeEvent; /// The ubiquitous origin type. type Origin = Origin; /// Maximum number of block number to block hash mappings to keep (oldest pruned first). @@ -209,8 +209,7 @@ impl pallet_aura::Config for Runtime { } impl pallet_grandpa::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; type KeyOwnerProofSystem = (); @@ -246,7 +245,7 @@ impl pallet_balances::Config for Runtime { /// The type for recording an account's balance. type Balance = Balance; /// The ubiquitous event type. - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU128; type AccountStore = System; @@ -258,7 +257,7 @@ parameter_types! { } impl pallet_transaction_payment::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; @@ -267,13 +266,13 @@ impl pallet_transaction_payment::Config for Runtime { } impl pallet_sudo::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; } /// Configure the pallet-template in pallets/template. impl pallet_template::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } // Create the runtime by composing the FRAME pallets that were previously configured. @@ -314,10 +313,12 @@ pub type SignedExtra = ( frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, ); + /// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -473,17 +474,17 @@ impl_runtime_apis! { } } - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi for Runtime { fn query_call_info( - call: Call, + call: RuntimeCall, len: u32, ) -> pallet_transaction_payment::RuntimeDispatchInfo { TransactionPayment::query_call_info(call, len) } fn query_call_fee_details( - call: Call, + call: RuntimeCall, len: u32, ) -> pallet_transaction_payment::FeeDetails { TransactionPayment::query_call_fee_details(call, len) diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index c0f3b96e093cb..0a734fa447448 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -122,7 +122,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { kitchensink_runtime::UncheckedExtrinsic { signature: None, - function: kitchensink_runtime::Call::Timestamp(pallet_timestamp::Call::set { now }), + function: kitchensink_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now }), } .into() } diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 13003c1a7a41f..2152301ac2d42 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -69,7 +69,7 @@ pub fn fetch_nonce(client: &FullClient, account: sp_core::sr25519::Pair) -> u32 pub fn create_extrinsic( client: &FullClient, sender: sp_core::sr25519::Pair, - function: impl Into, + function: impl Into, nonce: Option, ) -> kitchensink_runtime::UncheckedExtrinsic { let function = function.into(); @@ -570,7 +570,7 @@ mod tests { use codec::Encode; use kitchensink_runtime::{ constants::{currency::CENTS, time::SLOT_DURATION}, - Address, BalancesCall, Call, UncheckedExtrinsic, + Address, BalancesCall, RuntimeCall, UncheckedExtrinsic, }; use node_primitives::{Block, DigestItem, Signature}; use sc_client_api::BlockBackend; @@ -759,8 +759,10 @@ mod tests { }; let signer = charlie.clone(); - let function = - Call::Balances(BalancesCall::transfer { dest: to.into(), value: amount }); + let function = RuntimeCall::Balances(BalancesCall::transfer { + dest: to.into(), + value: amount, + }); let check_non_zero_sender = frame_system::CheckNonZeroSender::new(); let check_spec_version = frame_system::CheckSpecVersion::new(); diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index 3ad5dc61d528f..850be3e3c6281 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -19,8 +19,8 @@ use codec::{Decode, Encode}; use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; use frame_support::Hashable; use kitchensink_runtime::{ - constants::currency::*, Block, BuildStorage, Call, CheckedExtrinsic, GenesisConfig, Header, - UncheckedExtrinsic, + constants::currency::*, Block, BuildStorage, CheckedExtrinsic, GenesisConfig, Header, + RuntimeCall, UncheckedExtrinsic, }; use node_executor::ExecutorDispatch; use node_primitives::{BlockNumber, Hash}; @@ -141,11 +141,11 @@ fn test_blocks( let mut test_ext = new_test_ext(genesis_config); let mut block1_extrinsics = vec![CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: 0 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: 0 }), }]; block1_extrinsics.extend((0..20).map(|i| CheckedExtrinsic { signed: Some((alice(), signed_extra(i, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: bob().into(), value: 1 * DOLLARS, }), diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 35063f6933c98..33f71568ec6c5 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -28,8 +28,8 @@ use sp_runtime::{ use kitchensink_runtime::{ constants::{currency::*, time::SLOT_DURATION}, - Balances, Call, CheckedExtrinsic, Event, Header, Runtime, System, TransactionPayment, - UncheckedExtrinsic, + Balances, CheckedExtrinsic, Header, Runtime, RuntimeCall, RuntimeEvent, System, + TransactionPayment, UncheckedExtrinsic, }; use node_primitives::{Balance, Hash}; use node_testing::keyring::*; @@ -67,7 +67,7 @@ fn transfer_fee(extrinsic: &E) -> Balance { fn xt() -> UncheckedExtrinsic { sign(CheckedExtrinsic { signed: Some((alice(), signed_extra(0, 0))), - function: Call::Balances(default_transfer_call()), + function: RuntimeCall::Balances(default_transfer_call()), }) } @@ -84,11 +84,11 @@ fn changes_trie_block() -> (Vec, Hash) { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time }), }, CheckedExtrinsic { signed: Some((alice(), signed_extra(0, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: bob().into(), value: 69 * DOLLARS, }), @@ -111,11 +111,11 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time1 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time1 }), }, CheckedExtrinsic { signed: Some((alice(), signed_extra(0, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: bob().into(), value: 69 * DOLLARS, }), @@ -131,18 +131,18 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time2 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time2 }), }, CheckedExtrinsic { signed: Some((bob(), signed_extra(0, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: alice().into(), value: 5 * DOLLARS, }), }, CheckedExtrinsic { signed: Some((alice(), signed_extra(1, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: bob().into(), value: 15 * DOLLARS, }), @@ -166,11 +166,11 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec, Hash) { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), }, CheckedExtrinsic { signed: Some((alice(), signed_extra(nonce, 0))), - function: Call::System(frame_system::Call::remark { remark: vec![0; size] }), + function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0; size] }), }, ], (time * 1000 / SLOT_DURATION).into(), @@ -324,7 +324,7 @@ fn full_native_block_import_works() { let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), - event: Event::System(frame_system::Event::ExtrinsicSuccess { + event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, @@ -335,7 +335,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Withdraw { + event: RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who: alice().into(), amount: fees, }), @@ -343,7 +343,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: alice().into(), to: bob().into(), amount: 69 * DOLLARS, @@ -352,7 +352,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Deposit { + event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), amount: fees * 8 / 10, }), @@ -360,12 +360,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), + event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { + value: fees * 8 / 10, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::TransactionPayment( + event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: alice().into(), actual_fee: fees, @@ -376,7 +378,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::System(frame_system::Event::ExtrinsicSuccess { + event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, }), topics: vec![], @@ -398,7 +400,7 @@ fn full_native_block_import_works() { let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), - event: Event::System(frame_system::Event::ExtrinsicSuccess { + event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, @@ -409,7 +411,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Withdraw { + event: RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who: bob().into(), amount: fees, }), @@ -417,7 +419,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: bob().into(), to: alice().into(), amount: 5 * DOLLARS, @@ -426,7 +428,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Deposit { + event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), amount: fees * 8 / 10, }), @@ -434,12 +436,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), + event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { + value: fees * 8 / 10, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::TransactionPayment( + event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: bob().into(), actual_fee: fees, @@ -450,14 +454,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::System(frame_system::Event::ExtrinsicSuccess { + event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Balances(pallet_balances::Event::Withdraw { + event: RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who: alice().into(), amount: fees, }), @@ -465,7 +469,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: alice().into(), to: bob().into(), amount: 15 * DOLLARS, @@ -474,7 +478,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Balances(pallet_balances::Event::Deposit { + event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), amount: fees * 8 / 10, }), @@ -482,12 +486,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), + event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { + value: fees * 8 / 10, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::TransactionPayment( + event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: alice().into(), actual_fee: fees, @@ -498,7 +504,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::System(frame_system::Event::ExtrinsicSuccess { + event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, }), topics: vec![], @@ -648,24 +654,24 @@ fn deploying_wasm_contract_should_work() { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time }), }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(0, 0))), - function: Call::Contracts( - pallet_contracts::Call::instantiate_with_code:: { - value: 0, - gas_limit: Weight::from_ref_time(500_000_000), - storage_deposit_limit: None, - code: transfer_code, - data: Vec::new(), - salt: Vec::new(), - }, - ), + function: RuntimeCall::Contracts(pallet_contracts::Call::instantiate_with_code::< + Runtime, + > { + value: 0, + gas_limit: Weight::from_ref_time(500_000_000), + storage_deposit_limit: None, + code: transfer_code, + data: Vec::new(), + salt: Vec::new(), + }), }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(1, 0))), - function: Call::Contracts(pallet_contracts::Call::call:: { + function: RuntimeCall::Contracts(pallet_contracts::Call::call:: { dest: sp_runtime::MultiAddress::Id(addr.clone()), value: 10, gas_limit: Weight::from_ref_time(500_000_000), diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index c5c2d01ca5c13..ae1bfa371469c 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -22,7 +22,8 @@ use frame_support::{ }; use kitchensink_runtime::{ constants::{currency::*, time::SLOT_DURATION}, - Balances, Call, CheckedExtrinsic, Multiplier, Runtime, TransactionByteFee, TransactionPayment, + Balances, CheckedExtrinsic, Multiplier, Runtime, RuntimeCall, TransactionByteFee, + TransactionPayment, }; use node_primitives::Balance; use node_testing::keyring::*; @@ -53,12 +54,12 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time1 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time1 }), }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(0, 0))), - function: Call::Sudo(pallet_sudo::Call::sudo { - call: Box::new(Call::System(frame_system::Call::fill_block { + function: RuntimeCall::Sudo(pallet_sudo::Call::sudo { + call: Box::new(RuntimeCall::System(frame_system::Call::fill_block { ratio: Perbill::from_percent(60), })), }), @@ -76,11 +77,11 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time2 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time2 }), }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(1, 0))), - function: Call::System(frame_system::Call::remark { remark: vec![0; 1] }), + function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 1] }), }, ], (time2 / SLOT_DURATION).into(), @@ -146,7 +147,7 @@ fn transaction_fee_is_correct() { let tip = 1_000_000; let xt = sign(CheckedExtrinsic { signed: Some((alice(), signed_extra(0, tip))), - function: Call::Balances(default_transfer_call()), + function: RuntimeCall::Balances(default_transfer_call()), }); let r = @@ -212,7 +213,7 @@ fn block_weight_capacity_report() { let mut xts = (0..num_transfers) .map(|i| CheckedExtrinsic { signed: Some((charlie(), signed_extra(nonce + i as Index, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: bob().into(), value: 0, }), @@ -223,7 +224,7 @@ fn block_weight_capacity_report() { 0, CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), }, ); @@ -286,11 +287,13 @@ fn block_length_capacity_report() { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { + now: time * 1000, + }), }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(nonce, 0))), - function: Call::System(frame_system::Call::remark { + function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0u8; (block_number * factor) as usize], }), }, diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index cedc945b0af7e..3509592ebf04a 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -18,7 +18,8 @@ //! Some configurable implementations as associated type for the substrate runtime. use crate::{ - AccountId, AllianceMotion, Assets, Authorship, Balances, Call, Hash, NegativeImbalance, Runtime, + AccountId, AllianceMotion, Assets, Authorship, Balances, Hash, NegativeImbalance, Runtime, + RuntimeCall, }; use frame_support::{ pallet_prelude::*, @@ -77,11 +78,11 @@ impl IdentityVerifier for AllianceIdentityVerifier { } pub struct AllianceProposalProvider; -impl ProposalProvider for AllianceProposalProvider { +impl ProposalProvider for AllianceProposalProvider { fn propose_proposal( who: AccountId, threshold: u32, - proposal: Box, + proposal: Box, length_bound: u32, ) -> Result<(u32, u32), DispatchError> { AllianceMotion::do_propose_proposed(who, threshold, proposal, length_bound) @@ -109,7 +110,7 @@ impl ProposalProvider for AllianceProposalProvider { AllianceMotion::do_close(proposal_hash, proposal_index, proposal_weight_bound, length_bound) } - fn proposal_of(proposal_hash: Hash) -> Option { + fn proposal_of(proposal_hash: Hash) -> Option { AllianceMotion::proposal_of(proposal_hash) } } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 5aa488f328a5e..966a2e17ea475 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -205,7 +205,7 @@ impl frame_system::Config for Runtime { type BlockLength = RuntimeBlockLength; type DbWeight = RocksDbWeight; type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = Index; type BlockNumber = BlockNumber; type Hash = Hash; @@ -213,7 +213,7 @@ impl frame_system::Config for Runtime { type AccountId = AccountId; type Lookup = Indices; type Header = generic::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; type Version = Version; type PalletInfo = PalletInfo; @@ -229,8 +229,8 @@ impl frame_system::Config for Runtime { impl pallet_randomness_collective_flip::Config for Runtime {} impl pallet_utility::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; type WeightInfo = pallet_utility::weights::SubstrateWeight; } @@ -243,8 +243,8 @@ parameter_types! { } impl pallet_multisig::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type DepositBase = DepositBase; type DepositFactor = DepositFactor; @@ -286,25 +286,28 @@ impl Default for ProxyType { Self::Any } } -impl InstanceFilter for ProxyType { - fn filter(&self, c: &Call) -> bool { +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { match self { ProxyType::Any => true, ProxyType::NonTransfer => !matches!( c, - Call::Balances(..) | - Call::Assets(..) | Call::Uniques(..) | - Call::Vesting(pallet_vesting::Call::vested_transfer { .. }) | - Call::Indices(pallet_indices::Call::transfer { .. }) + RuntimeCall::Balances(..) | + RuntimeCall::Assets(..) | + RuntimeCall::Uniques(..) | + RuntimeCall::Vesting(pallet_vesting::Call::vested_transfer { .. }) | + RuntimeCall::Indices(pallet_indices::Call::transfer { .. }) ), ProxyType::Governance => matches!( c, - Call::Democracy(..) | - Call::Council(..) | Call::Society(..) | - Call::TechnicalCommittee(..) | - Call::Elections(..) | Call::Treasury(..) + RuntimeCall::Democracy(..) | + RuntimeCall::Council(..) | + RuntimeCall::Society(..) | + RuntimeCall::TechnicalCommittee(..) | + RuntimeCall::Elections(..) | + RuntimeCall::Treasury(..) ), - ProxyType::Staking => matches!(c, Call::Staking(..)), + ProxyType::Staking => matches!(c, RuntimeCall::Staking(..)), } } fn is_superset(&self, o: &Self) -> bool { @@ -319,8 +322,8 @@ impl InstanceFilter for ProxyType { } impl pallet_proxy::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type ProxyType = ProxyType; type ProxyDepositBase = ProxyDepositBase; @@ -341,10 +344,10 @@ parameter_types! { } impl pallet_scheduler::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Origin = Origin; type PalletsOrigin = OriginCaller; - type Call = Call; + type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureRoot; type MaxScheduledPerBlock = ConstU32<50>; @@ -363,7 +366,7 @@ parameter_types! { impl pallet_preimage::Config for Runtime { type WeightInfo = pallet_preimage::weights::SubstrateWeight; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; type MaxSize = PreimageMaxSize; @@ -413,7 +416,7 @@ impl pallet_indices::Config for Runtime { type AccountIndex = AccountIndex; type Currency = Balances; type Deposit = IndexDeposit; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_indices::weights::SubstrateWeight; } @@ -431,7 +434,7 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type Balance = Balance; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = frame_system::Pallet; type WeightInfo = pallet_balances::weights::SubstrateWeight; @@ -446,7 +449,7 @@ parameter_types! { } impl pallet_transaction_payment::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; @@ -456,7 +459,7 @@ impl pallet_transaction_payment::Config for Runtime { } impl pallet_asset_tx_payment::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< pallet_assets::BalanceToAssetBalance, @@ -496,7 +499,7 @@ impl_opaque_keys! { } impl pallet_session::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = ::AccountId; type ValidatorIdOf = pallet_staking::StashOf; type ShouldEndSession = Babe; @@ -546,7 +549,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = Timestamp; type CurrencyToVote = U128CurrencyToVote; type RewardRemainder = Treasury; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = Treasury; // send the slashed funds to the treasury. type Reward = (); // rewards are minted from the void type SessionsPerEra = SessionsPerEra; @@ -686,7 +689,7 @@ impl pallet_election_provider_multi_phase::MinerConfig for Runtime { } impl pallet_election_provider_multi_phase::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type EstimateCallFee = TransactionPayment; type SignedPhase = SignedPhase; @@ -721,7 +724,7 @@ parameter_types! { } impl pallet_bags_list::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ScoreProvider = Staking; type WeightInfo = pallet_bags_list::weights::SubstrateWeight; type BagThresholds = BagThresholds; @@ -750,7 +753,7 @@ impl Convert for U256ToBalance { impl pallet_nomination_pools::Config for Runtime { type WeightInfo = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = Balance; type RewardCounter = FixedU128; @@ -770,7 +773,7 @@ parameter_types! { impl pallet_conviction_voting::Config for Runtime { type WeightInfo = pallet_conviction_voting::weights::SubstrateWeight; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type VoteLockingPeriod = VoteLockingPeriod; type MaxVotes = ConstU32<512>; @@ -827,8 +830,8 @@ impl pallet_referenda::TracksInfo for TracksInfo { impl pallet_referenda::Config for Runtime { type WeightInfo = pallet_referenda::weights::SubstrateWeight; - type Call = Call; - type Event = Event; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type Scheduler = Scheduler; type Currency = pallet_balances::Pallet; type SubmitOrigin = EnsureSigned; @@ -846,8 +849,8 @@ impl pallet_referenda::Config for Runtime { impl pallet_referenda::Config for Runtime { type WeightInfo = pallet_referenda::weights::SubstrateWeight; - type Call = Call; - type Event = Event; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type Scheduler = Scheduler; type Currency = pallet_balances::Pallet; type SubmitOrigin = EnsureSigned; @@ -865,7 +868,7 @@ impl pallet_referenda::Config for Runtime { impl pallet_ranked_collective::Config for Runtime { type WeightInfo = pallet_ranked_collective::weights::SubstrateWeight; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PromoteOrigin = EnsureRootWithSuccess>; type DemoteOrigin = EnsureRootWithSuccess>; type Polls = RankedPolls; @@ -875,7 +878,7 @@ impl pallet_ranked_collective::Config for Runtime { impl pallet_remark::Config for Runtime { type WeightInfo = pallet_remark::weights::SubstrateWeight; - type Event = Event; + type RuntimeEvent = RuntimeEvent; } parameter_types! { @@ -889,8 +892,8 @@ parameter_types! { } impl pallet_democracy::Config for Runtime { - type Proposal = Call; - type Event = Event; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type EnactmentPeriod = EnactmentPeriod; type LaunchPeriod = LaunchPeriod; @@ -948,8 +951,8 @@ parameter_types! { type CouncilCollective = pallet_collective::Instance1; impl pallet_collective::Config for Runtime { type Origin = Origin; - type Proposal = Call; - type Event = Event; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = CouncilMotionDuration; type MaxProposals = CouncilMaxProposals; type MaxMembers = CouncilMaxMembers; @@ -975,7 +978,7 @@ parameter_types! { const_assert!(DesiredMembers::get() <= CouncilMaxMembers::get()); impl pallet_elections_phragmen::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletId = ElectionsPhragmenPalletId; type Currency = Balances; type ChangeMembers = Council; @@ -1005,8 +1008,8 @@ parameter_types! { type TechnicalCollective = pallet_collective::Instance2; impl pallet_collective::Config for Runtime { type Origin = Origin; - type Proposal = Call; - type Event = Event; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = TechnicalMotionDuration; type MaxProposals = TechnicalMaxProposals; type MaxMembers = TechnicalMaxMembers; @@ -1019,7 +1022,7 @@ type EnsureRootOrHalfCouncil = EitherOfDiverse< pallet_collective::EnsureProportionMoreThan, >; impl pallet_membership::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type AddOrigin = EnsureRootOrHalfCouncil; type RemoveOrigin = EnsureRootOrHalfCouncil; type SwapOrigin = EnsureRootOrHalfCouncil; @@ -1056,7 +1059,7 @@ impl pallet_treasury::Config for Runtime { EnsureRoot, pallet_collective::EnsureProportionMoreThan, >; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ProposalBondMinimum; @@ -1082,7 +1085,7 @@ parameter_types! { } impl pallet_bounties::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BountyDepositBase = BountyDepositBase; type BountyDepositPayoutDelay = BountyDepositPayoutDelay; type BountyUpdatePeriod = BountyUpdatePeriod; @@ -1101,14 +1104,14 @@ parameter_types! { } impl pallet_child_bounties::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MaxActiveChildBountyCount = ConstU32<5>; type ChildBountyValueMinimum = ChildBountyValueMinimum; type WeightInfo = pallet_child_bounties::weights::SubstrateWeight; } impl pallet_tips::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DataDepositPerByte = DataDepositPerByte; type MaximumReasonLength = MaximumReasonLength; type Tippers = Elections; @@ -1136,8 +1139,8 @@ impl pallet_contracts::Config for Runtime { type Time = Timestamp; type Randomness = RandomnessCollectiveFlip; type Currency = Balances; - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; /// The safest default is to allow no calls at all. /// /// Runtimes should whitelist dispatchables that are allowed to be called from contracts @@ -1162,8 +1165,8 @@ impl pallet_contracts::Config for Runtime { } impl pallet_sudo::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; } parameter_types! { @@ -1178,14 +1181,14 @@ parameter_types! { impl frame_system::offchain::CreateSignedTransaction for Runtime where - Call: From, + RuntimeCall: From, { fn create_transaction>( - call: Call, + call: RuntimeCall, public: ::Signer, account: AccountId, nonce: Index, - ) -> Option<(Call, ::SignaturePayload)> { + ) -> Option<(RuntimeCall, ::SignaturePayload)> { let tip = 0; // take the biggest period possible. let period = @@ -1225,15 +1228,15 @@ impl frame_system::offchain::SigningTypes for Runtime { impl frame_system::offchain::SendTransactionTypes for Runtime where - Call: From, + RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; } impl pallet_im_online::Config for Runtime { type AuthorityId = ImOnlineId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type NextSessionRotation = Babe; type ValidatorSet = Historical; type ReportUnresponsiveness = Offences; @@ -1245,7 +1248,7 @@ impl pallet_im_online::Config for Runtime { } impl pallet_offences::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; } @@ -1255,8 +1258,7 @@ impl pallet_authority_discovery::Config for Runtime { } impl pallet_grandpa::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; type KeyOwnerProofSystem = Historical; @@ -1288,7 +1290,7 @@ parameter_types! { } impl pallet_identity::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BasicDeposit = BasicDeposit; type FieldDeposit = FieldDeposit; @@ -1310,9 +1312,9 @@ parameter_types! { } impl pallet_recovery::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_recovery::weights::SubstrateWeight; - type Call = Call; + type RuntimeCall = RuntimeCall; type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; @@ -1333,7 +1335,7 @@ parameter_types! { } impl pallet_society::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletId = SocietyPalletId; type Currency = Balances; type Randomness = RandomnessCollectiveFlip; @@ -1356,7 +1358,7 @@ parameter_types! { } impl pallet_vesting::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BlockNumberToBalance = ConvertInto; type MinVestedTransfer = MinVestedTransfer; @@ -1383,10 +1385,10 @@ parameter_types! { impl pallet_lottery::Config for Runtime { type PalletId = LotteryPalletId; - type Call = Call; + type RuntimeCall = RuntimeCall; type Currency = Balances; type Randomness = RandomnessCollectiveFlip; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ManagerOrigin = EnsureRoot; type MaxCalls = MaxCalls; type ValidateCall = Lottery; @@ -1403,7 +1405,7 @@ parameter_types! { } impl pallet_assets::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Balance = u128; type AssetId = u32; type Currency = Balances; @@ -1431,7 +1433,7 @@ parameter_types! { } impl pallet_gilt::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = Balance; type AdminOrigin = frame_system::EnsureRoot; @@ -1456,7 +1458,7 @@ parameter_types! { } impl pallet_uniques::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type CollectionId = u32; type ItemId = u32; type Currency = Balances; @@ -1477,9 +1479,9 @@ impl pallet_uniques::Config for Runtime { } impl pallet_transaction_storage::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type Call = Call; + type RuntimeCall = RuntimeCall; type FeeDestination = (); type WeightInfo = pallet_transaction_storage::weights::SubstrateWeight; type MaxBlockTransactions = @@ -1489,8 +1491,8 @@ impl pallet_transaction_storage::Config for Runtime { } impl pallet_whitelist::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type WhitelistOrigin = EnsureRoot; type DispatchWhitelistedOrigin = EnsureRoot; type PreimageProvider = Preimage; @@ -1504,7 +1506,7 @@ parameter_types! { } impl pallet_state_trie_migration::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ControlOrigin = EnsureRoot; type Currency = Balances; type MaxKeyLen = MigrationMaxKeyLen; @@ -1529,8 +1531,8 @@ parameter_types! { type AllianceCollective = pallet_collective::Instance3; impl pallet_collective::Config for Runtime { type Origin = Origin; - type Proposal = Call; - type Event = Event; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = AllianceMotionDuration; type MaxProposals = AllianceMaxProposals; type MaxMembers = AllianceMaxMembers; @@ -1547,8 +1549,8 @@ parameter_types! { } impl pallet_alliance::Config for Runtime { - type Event = Event; - type Proposal = Call; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; type AdminOrigin = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionMoreThan, @@ -1673,12 +1675,14 @@ pub type SignedExtra = ( frame_system::CheckWeight, pallet_asset_tx_payment::ChargeAssetTxPayment, ); + /// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; /// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = generic::CheckedExtrinsic; +pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -1977,13 +1981,13 @@ impl_runtime_apis! { } } - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi for Runtime { - fn query_call_info(call: Call, len: u32) -> RuntimeDispatchInfo { + fn query_call_info(call: RuntimeCall, len: u32) -> RuntimeDispatchInfo { TransactionPayment::query_call_info(call, len) } - fn query_call_fee_details(call: Call, len: u32) -> FeeDetails { + fn query_call_fee_details(call: RuntimeCall, len: u32) -> FeeDetails { TransactionPayment::query_call_fee_details(call, len) } } @@ -2178,7 +2182,7 @@ mod tests { fn validate_transaction_submitter_bounds() { fn is_submit_signed_transaction() where - T: CreateSignedTransaction, + T: CreateSignedTransaction, { } @@ -2198,11 +2202,11 @@ mod tests { #[test] fn call_size() { - let size = core::mem::size_of::(); + let size = core::mem::size_of::(); assert!( size <= 208, - "size of Call {} is more than 208 bytes: some calls have too big arguments, use Box to reduce the - size of Call. + "size of RuntimeCall {} is more than 208 bytes: some calls have too big arguments, use Box to reduce the + size of RuntimeCall. If the limit is too strong, maybe consider increase the limit to 300.", size, ); diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 534f0a4f09732..7980cc102fb38 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -35,8 +35,8 @@ use crate::{ use codec::{Decode, Encode}; use futures::executor; use kitchensink_runtime::{ - constants::currency::DOLLARS, AccountId, BalancesCall, Call, CheckedExtrinsic, MinimumPeriod, - Signature, SystemCall, UncheckedExtrinsic, + constants::currency::DOLLARS, AccountId, BalancesCall, CheckedExtrinsic, MinimumPeriod, + RuntimeCall, Signature, SystemCall, UncheckedExtrinsic, }; use node_primitives::Block; use sc_block_builder::BlockBuilderProvider; @@ -308,12 +308,12 @@ impl<'a> Iterator for BlockContentIterator<'a> { )), function: match self.content.block_type { BlockType::RandomTransfersKeepAlive => - Call::Balances(BalancesCall::transfer_keep_alive { + RuntimeCall::Balances(BalancesCall::transfer_keep_alive { dest: sp_runtime::MultiAddress::Id(receiver), value: kitchensink_runtime::ExistentialDeposit::get() + 1, }), BlockType::RandomTransfersReaping => { - Call::Balances(BalancesCall::transfer { + RuntimeCall::Balances(BalancesCall::transfer { dest: sp_runtime::MultiAddress::Id(receiver), // Transfer so that ending balance would be 1 less than existential // deposit so that we kill the sender account. @@ -321,7 +321,8 @@ impl<'a> Iterator for BlockContentIterator<'a> { (kitchensink_runtime::ExistentialDeposit::get() - 1), }) }, - BlockType::Noop => Call::System(SystemCall::remark { remark: Vec::new() }), + BlockType::Noop => + RuntimeCall::System(SystemCall::remark { remark: Vec::new() }), }, }, self.runtime_version.spec_version, diff --git a/docs/Upgrading-2.0-to-3.0.md b/docs/Upgrading-2.0-to-3.0.md index bcba7d88047ce..210023c3aec5a 100644 --- a/docs/Upgrading-2.0-to-3.0.md +++ b/docs/Upgrading-2.0-to-3.0.md @@ -148,7 +148,7 @@ And update the overall definition for weights on frame and a few related types a + type BlockLength = RuntimeBlockLength; + type DbWeight = RocksDbWeight; type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = Index; @@ -171,25 +198,19 @@ impl frame_system::Trait for Runtime { type Header = generic::Header; diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index de2fc392db8f1..e07d7c44a97ff 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -35,7 +35,7 @@ const SEED: u32 = 0; const MAX_BYTES: u32 = 1_024; -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 8f39b6b51cabd..9d320c4215a70 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -240,7 +240,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The outer call dispatch type. type Proposal: Parameter @@ -249,7 +250,7 @@ pub mod pallet { + From> + GetDispatchInfo + IsSubType> - + IsType<::Call>; + + IsType<::RuntimeCall>; /// Origin for admin-level operations, like setting the Alliance's rules. type AdminOrigin: EnsureOrigin; diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index 45c13b76cc525..42c97876d40b0 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -48,7 +48,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = BlockNumber; type Hash = H256; @@ -56,7 +56,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; type DbWeight = (); type Version = (); @@ -77,7 +77,7 @@ parameter_types! { impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); @@ -96,8 +96,8 @@ parameter_types! { type AllianceCollective = pallet_collective::Instance1; impl pallet_collective::Config for Test { type Origin = Origin; - type Proposal = Call; - type Event = Event; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = MotionDuration; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; @@ -124,7 +124,7 @@ type EnsureOneOrRoot = EitherOfDiverse, EnsureSignedBy type EnsureTwoOrRoot = EitherOfDiverse, EnsureSignedBy>; impl pallet_identity::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BasicDeposit = BasicDeposit; type FieldDeposit = FieldDeposit; @@ -162,11 +162,11 @@ impl IdentityVerifier for AllianceIdentityVerifier { } pub struct AllianceProposalProvider; -impl ProposalProvider for AllianceProposalProvider { +impl ProposalProvider for AllianceProposalProvider { fn propose_proposal( who: u64, threshold: u32, - proposal: Box, + proposal: Box, length_bound: u32, ) -> Result<(u32, u32), DispatchError> { AllianceMotion::do_propose_proposed(who, threshold, proposal, length_bound) @@ -194,7 +194,7 @@ impl ProposalProvider for AllianceProposalProvider { AllianceMotion::do_close(proposal_hash, proposal_index, proposal_weight_bound, length_bound) } - fn proposal_of(proposal_hash: H256) -> Option { + fn proposal_of(proposal_hash: H256) -> Option { AllianceMotion::proposal_of(proposal_hash) } } @@ -207,8 +207,8 @@ parameter_types! { pub const RetirementPeriod: BlockNumber = MOTION_DURATION_IN_BLOCKS + 1; } impl Config for Test { - type Event = Event; - type Proposal = Call; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; type AdminOrigin = EnsureSignedBy; type MembershipManager = EnsureSignedBy; type AnnouncementOrigin = EnsureSignedBy; @@ -380,19 +380,19 @@ pub fn test_cid() -> Cid { Cid::new_v0(&*result) } -pub fn make_remark_proposal(value: u64) -> (Call, u32, H256) { - make_proposal(Call::System(frame_system::Call::remark { remark: value.encode() })) +pub fn make_remark_proposal(value: u64) -> (RuntimeCall, u32, H256) { + make_proposal(RuntimeCall::System(frame_system::Call::remark { remark: value.encode() })) } -pub fn make_set_rule_proposal(rule: Cid) -> (Call, u32, H256) { - make_proposal(Call::Alliance(pallet_alliance::Call::set_rule { rule })) +pub fn make_set_rule_proposal(rule: Cid) -> (RuntimeCall, u32, H256) { + make_proposal(RuntimeCall::Alliance(pallet_alliance::Call::set_rule { rule })) } -pub fn make_kick_member_proposal(who: u64) -> (Call, u32, H256) { - make_proposal(Call::Alliance(pallet_alliance::Call::kick_member { who })) +pub fn make_kick_member_proposal(who: u64) -> (RuntimeCall, u32, H256) { + make_proposal(RuntimeCall::Alliance(pallet_alliance::Call::kick_member { who })) } -pub fn make_proposal(proposal: Call) -> (Call, u32, H256) { +pub fn make_proposal(proposal: RuntimeCall) -> (RuntimeCall, u32, H256) { let len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash = BlakeTwo256::hash_of(&proposal); (proposal, len, hash) diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index 943c39a2d69c0..79fd33965edb5 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -63,7 +63,7 @@ fn init_members_works() { // assert a retiring member from previous Alliance not removed assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); - System::assert_last_event(mock::Event::Alliance(crate::Event::MembersInitialized { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MembersInitialized { founders: vec![5, 8], fellows: vec![4], allies: vec![2], @@ -117,7 +117,7 @@ fn disband_works() { // deposit unreserved assert_eq!(Balances::free_balance(9), 40); - System::assert_last_event(mock::Event::Alliance(crate::Event::AllianceDisbanded { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::AllianceDisbanded { voting_members: 2, ally_members: 1, unreserved: 1, @@ -154,7 +154,7 @@ fn propose_works() { System::events(), vec![EventRecord { phase: Phase::Initialization, - event: mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + event: mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, @@ -182,13 +182,13 @@ fn vote_works() { assert_eq!( System::events(), vec![ - record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Voted { account: 2, proposal_hash: hash, voted: true, @@ -236,19 +236,19 @@ fn veto_works() { assert_eq!( System::events(), vec![ - record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 1, proposal_hash: vetoable_hash, threshold: 3 })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Disapproved { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Disapproved { proposal_hash: vetoable_hash })), ] @@ -276,42 +276,42 @@ fn close_works() { assert_eq!( System::events(), vec![ - record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0, })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0, })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Voted { account: 3, proposal_hash: hash, voted: true, yes: 3, no: 0, })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Closed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Closed { proposal_hash: hash, yes: 3, no: 0, })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Approved { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Approved { proposal_hash: hash })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Executed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Executed { proposal_hash: hash, result: Err(DispatchError::BadOrigin), })) @@ -327,7 +327,9 @@ fn set_rule_works() { assert_ok!(Alliance::set_rule(Origin::signed(1), cid.clone())); assert_eq!(Alliance::rule(), Some(cid.clone())); - System::assert_last_event(mock::Event::Alliance(crate::Event::NewRuleSet { rule: cid })); + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::NewRuleSet { + rule: cid, + })); }); } @@ -341,7 +343,7 @@ fn announce_works() { assert_ok!(Alliance::announce(Origin::signed(3), cid.clone())); assert_eq!(Alliance::announcements(), vec![cid.clone()]); - System::assert_last_event(mock::Event::Alliance(crate::Event::Announced { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::Announced { announcement: cid, })); }); @@ -353,7 +355,7 @@ fn remove_announcement_works() { let cid = test_cid(); assert_ok!(Alliance::announce(Origin::signed(3), cid.clone())); assert_eq!(Alliance::announcements(), vec![cid.clone()]); - System::assert_last_event(mock::Event::Alliance(crate::Event::Announced { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::Announced { announcement: cid.clone(), })); @@ -361,9 +363,9 @@ fn remove_announcement_works() { assert_ok!(Alliance::remove_announcement(Origin::signed(3), cid.clone())); assert_eq!(Alliance::announcements(), vec![]); - System::assert_last_event(mock::Event::Alliance(crate::Event::AnnouncementRemoved { - announcement: cid, - })); + System::assert_last_event(mock::RuntimeEvent::Alliance( + crate::Event::AnnouncementRemoved { announcement: cid }, + )); }); } @@ -498,7 +500,7 @@ fn give_retirement_notice_work() { assert_ok!(Alliance::give_retirement_notice(Origin::signed(3))); assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); assert_eq!(Alliance::members(MemberRole::Retiring), vec![3]); - System::assert_last_event(mock::Event::Alliance( + System::assert_last_event(mock::RuntimeEvent::Alliance( crate::Event::MemberRetirementPeriodStarted { member: (3) }, )); @@ -531,7 +533,7 @@ fn retire_works() { System::set_block_number(System::block_number() + RetirementPeriod::get()); assert_ok!(Alliance::retire(Origin::signed(3))); assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); - System::assert_last_event(mock::Event::Alliance(crate::Event::MemberRetired { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberRetired { member: (3), unreserved: None, })); @@ -585,7 +587,7 @@ fn kick_member_works() { assert_ok!(Alliance::kick_member(Origin::signed(2), 2)); assert_eq!(Alliance::members(MemberRole::Founder), vec![1]); assert_eq!(>::get(2), None); - System::assert_last_event(mock::Event::Alliance(crate::Event::MemberKicked { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberKicked { member: (2), slashed: Some(25), })); diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 043d3f1a1aef4..ca891c2f42e4a 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -140,11 +140,11 @@ fn add_approvals, I: 'static>(minter: T::AccountId, n: u32) { } } -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } -fn assert_event, I: 'static>(generic_event: >::Event) { +fn assert_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_has_event(generic_event.into()); } diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index d7ca83c8a84e3..fbb4a3ea1568b 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -180,7 +180,8 @@ pub mod pallet { /// The module configuration trait. pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The units in which we record balances. type Balance: Member diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 5429c89084e78..9344e5920d205 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -50,7 +50,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -58,7 +58,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -75,7 +75,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -85,7 +85,7 @@ impl pallet_balances::Config for Test { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Balance = u64; type AssetId = u32; type Currency = Balances; diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 1b6c62c55ee20..9c6056497118c 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -166,7 +166,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Swap action. type SwapAction: SwapAction + Parameter + MaxEncodedLen; /// Limit of proof size. diff --git a/frame/atomic-swap/src/tests.rs b/frame/atomic-swap/src/tests.rs index ffb548a1f29ed..d3d8b37d82794 100644 --- a/frame/atomic-swap/src/tests.rs +++ b/frame/atomic-swap/src/tests.rs @@ -41,12 +41,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -65,14 +65,14 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SwapAction = BalanceSwapAction; type ProofLimit = ConstU32<1024>; } diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 5fa298bb008b0..673190c95f2e1 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -59,13 +59,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index d5f9783f153c8..3505f20a05929 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -209,7 +209,7 @@ mod tests { type Keys = UintAuthorityId; type ShouldEndSession = pallet_session::PeriodicSessions; type SessionHandler = TestSessionHandler; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = AuthorityId; type ValidatorIdOf = ConvertInto; type NextSessionRotation = pallet_session::PeriodicSessions; @@ -238,13 +238,13 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AuthorityId; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index ff18e047db048..3f484ef24eec0 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -471,13 +471,13 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 3a6348404b9a7..0ac8214f45c23 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -77,14 +77,14 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Version = (); type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = DummyValidatorId; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -98,10 +98,10 @@ impl frame_system::Config for Test { impl frame_system::offchain::SendTransactionTypes for Test where - Call: From, + RuntimeCall: From, { - type OverarchingCall = Call; - type Extrinsic = TestXt; + type OverarchingCall = RuntimeCall; + type Extrinsic = TestXt; } impl_opaque_keys! { @@ -111,7 +111,7 @@ impl_opaque_keys! { } impl pallet_session::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = ::AccountId; type ValidatorIdOf = pallet_staking::StashOf; type ShouldEndSession = Babe; @@ -147,7 +147,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u128; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU128<1>; type AccountStore = System; type WeightInfo = (); @@ -184,7 +184,7 @@ impl pallet_staking::Config for Test { type MaxNominations = ConstU32<16>; type RewardRemainder = (); type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = ::Balance; type Slash = (); @@ -209,7 +209,7 @@ impl pallet_staking::Config for Test { } impl pallet_offences::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; } diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 70f8b2a32f817..02adc064790f2 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -105,7 +105,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: weights::WeightInfo; diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 3bc1b34657262..1044e4c450a41 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -52,13 +52,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = sp_runtime::traits::IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type DbWeight = (); type BlockLength = (); @@ -78,7 +78,7 @@ parameter_types! { } impl bags_list::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type BagThresholds = BagThresholds; type ScoreProvider = StakingMock; diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 0a45350366449..e425381172dab 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -218,7 +218,8 @@ pub mod pallet { type DustRemoval: OnUnbalanced>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The minimum amount required to keep an account open. #[pallet::constant] diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 96bee9be1991c..9c641f6b38a22 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -38,15 +38,15 @@ macro_rules! decl_tests { const ID_1: LockIdentifier = *b"1 "; const ID_2: LockIdentifier = *b"2 "; - pub const CALL: &<$test as frame_system::Config>::Call = - &Call::Balances(pallet_balances::Call::transfer { dest: 0, value: 0 }); + pub const CALL: &<$test as frame_system::Config>::RuntimeCall = + &RuntimeCall::Balances(pallet_balances::Call::transfer { dest: 0, value: 0 }); /// create a transaction info struct from weight. Handy to avoid building the whole struct. pub fn info_from_weight(w: Weight) -> DispatchInfo { DispatchInfo { weight: w, ..Default::default() } } - fn events() -> Vec { + fn events() -> Vec { let evt = System::events().into_iter().map(|evt| evt.event).collect::>(); System::reset_events(); @@ -314,7 +314,7 @@ macro_rules! decl_tests { <$ext_builder>::default().monied(true).build().execute_with(|| { assert_eq!(Balances::total_balance(&1), 10); assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop)); - System::assert_last_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 10 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Deposit { who: 1, amount: 10 })); assert_eq!(Balances::total_balance(&1), 20); assert_eq!(>::get(), 120); }); @@ -342,7 +342,7 @@ macro_rules! decl_tests { fn balance_works() { <$ext_builder>::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 42); - System::assert_has_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 42 })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { who: 1, amount: 42 })); assert_eq!(Balances::free_balance(1), 42); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::total_balance(&1), 42); @@ -444,7 +444,7 @@ macro_rules! decl_tests { let _ = Balances::withdraw( &2, 11, WithdrawReasons::TRANSFER, ExistenceRequirement::KeepAlive ); - System::assert_last_event(Event::Balances(crate::Event::Withdraw { who: 2, amount: 11 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Withdraw { who: 2, amount: 11 })); assert_eq!(Balances::free_balance(2), 100); assert_eq!(>::get(), 100); }); @@ -505,7 +505,7 @@ macro_rules! decl_tests { assert_ok!(Balances::reserve(&1, 110)); assert_ok!(Balances::repatriate_reserved(&1, &2, 41, Status::Free), 0); System::assert_last_event( - Event::Balances(crate::Event::ReserveRepatriated { from: 1, to: 2, amount: 41, destination_status: Status::Free }) + RuntimeEvent::Balances(crate::Event::ReserveRepatriated { from: 1, to: 2, amount: 41, destination_status: Status::Free }) ); assert_eq!(Balances::reserved_balance(1), 69); assert_eq!(Balances::free_balance(1), 0); @@ -740,18 +740,18 @@ macro_rules! decl_tests { System::set_block_number(2); assert_ok!(Balances::reserve(&1, 10)); - System::assert_last_event(Event::Balances(crate::Event::Reserved { who: 1, amount: 10 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Reserved { who: 1, amount: 10 })); System::set_block_number(3); assert!(Balances::unreserve(&1, 5).is_zero()); - System::assert_last_event(Event::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); System::set_block_number(4); assert_eq!(Balances::unreserve(&1, 6), 1); // should only unreserve 5 - System::assert_last_event(Event::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); }); } @@ -766,9 +766,9 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::NewAccount { account: 1 }), - Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), - Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), + RuntimeEvent::System(system::Event::NewAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), + RuntimeEvent::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] ); @@ -778,9 +778,9 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::KilledAccount { account: 1 }), - Event::Balances(crate::Event::DustLost { account: 1, amount: 99 }), - Event::Balances(crate::Event::Slashed { who: 1, amount: 1 }), + RuntimeEvent::System(system::Event::KilledAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::DustLost { account: 1, amount: 99 }), + RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 1 }), ] ); }); @@ -797,9 +797,9 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::NewAccount { account: 1 }), - Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), - Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), + RuntimeEvent::System(system::Event::NewAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), + RuntimeEvent::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] ); @@ -809,8 +809,8 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::KilledAccount { account: 1 }), - Event::Balances(crate::Event::Slashed { who: 1, amount: 100 }), + RuntimeEvent::System(system::Event::KilledAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 100 }), ] ); }); @@ -830,7 +830,7 @@ macro_rules! decl_tests { assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0)); // Account is still alive assert!(System::account_exists(&1)); - System::assert_last_event(Event::Balances(crate::Event::Slashed { who: 1, amount: 900 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 900 })); // SCENARIO: Slash will kill account because not enough balance left. assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 266c37063d2f8..fa1d2db8b1e49 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -57,13 +57,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -77,7 +77,7 @@ impl frame_system::Config for Test { } impl pallet_transaction_payment::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter, ()>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; @@ -88,7 +88,7 @@ impl pallet_transaction_payment::Config for Test { impl Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = frame_system::Pallet; type MaxLocks = (); diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index ebb82f41a545c..3301d90027682 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -58,13 +58,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -78,7 +78,7 @@ impl frame_system::Config for Test { } impl pallet_transaction_payment::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter, ()>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; @@ -89,7 +89,7 @@ impl pallet_transaction_payment::Config for Test { impl Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = StorageMapShim, system::Provider, u64, super::AccountData>; @@ -158,9 +158,9 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { assert_eq!( events(), [ - Event::System(system::Event::NewAccount { account: 1 }), - Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), - Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), + RuntimeEvent::System(system::Event::NewAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), + RuntimeEvent::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] ); @@ -168,7 +168,10 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { assert_eq!(res, (NegativeImbalance::new(98), 0)); // no events - assert_eq!(events(), [Event::Balances(crate::Event::Slashed { who: 1, amount: 98 })]); + assert_eq!( + events(), + [RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 98 })] + ); let res = Balances::slash(&1, 1); assert_eq!(res, (NegativeImbalance::new(1), 0)); @@ -176,9 +179,9 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { assert_eq!( events(), [ - Event::System(system::Event::KilledAccount { account: 1 }), - Event::Balances(crate::Event::DustLost { account: 1, amount: 1 }), - Event::Balances(crate::Event::Slashed { who: 1, amount: 1 }) + RuntimeEvent::System(system::Event::KilledAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::DustLost { account: 1, amount: 1 }), + RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 1 }) ] ); }); diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index fbfd62eb63259..6fda1697dcfeb 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -62,13 +62,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -91,7 +91,7 @@ impl OnUnbalanced> for OnDustRemoval { impl Config for Test { type Balance = u64; type DustRemoval = OnDustRemoval; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = StorageMapShim, system::Provider, u64, super::AccountData>; @@ -157,16 +157,19 @@ fn transfer_dust_removal_tst1_should_work() { // Verify the events assert_eq!(System::events().len(), 12); - System::assert_has_event(Event::Balances(crate::Event::Transfer { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Transfer { from: 2, to: 3, amount: 450, })); - System::assert_has_event(Event::Balances(crate::Event::DustLost { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { account: 2, amount: 50, })); - System::assert_has_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 50 })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { + who: 1, + amount: 50, + })); }); } @@ -192,16 +195,19 @@ fn transfer_dust_removal_tst2_should_work() { // Verify the events assert_eq!(System::events().len(), 10); - System::assert_has_event(Event::Balances(crate::Event::Transfer { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Transfer { from: 2, to: 1, amount: 450, })); - System::assert_has_event(Event::Balances(crate::Event::DustLost { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { account: 2, amount: 50, })); - System::assert_has_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 50 })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { + who: 1, + amount: 50, + })); }); } @@ -236,18 +242,21 @@ fn repatriating_reserved_balance_dust_removal_should_work() { // Verify the events assert_eq!(System::events().len(), 11); - System::assert_has_event(Event::Balances(crate::Event::ReserveRepatriated { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::ReserveRepatriated { from: 2, to: 1, amount: 450, destination_status: Status::Free, })); - System::assert_has_event(Event::Balances(crate::Event::DustLost { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { account: 2, amount: 50, })); - System::assert_last_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 50 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Deposit { + who: 1, + amount: 50, + })); }); } diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 8a673c9d4e914..792b775b77998 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -71,12 +71,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -90,7 +90,7 @@ impl frame_system::Config for Test { } impl pallet_session::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = u64; type ValidatorIdOf = ConvertInto; type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 3bb59c7c39485..7c4cd1af01533 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -66,12 +66,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -95,7 +95,7 @@ parameter_types! { } impl pallet_session::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = u64; type ValidatorIdOf = ConvertInto; type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 1ceb9a4f8904c..38aa7b261cb01 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -179,13 +179,13 @@ pub mod mock { type Origin = Origin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index b8a888767bf2c..fd7e0cce03c22 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -94,12 +94,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index ef8351d37e957..7617696a949cf 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -33,7 +33,7 @@ mod pallet_test { frame_support::decl_storage! { trait Store for Module, I: Instance = DefaultInstance> as Test where - ::OtherEvent: Into<>::Event> + ::OtherEvent: Into<>::RuntimeEvent> { pub Value get(fn value): Option; } @@ -41,7 +41,7 @@ mod pallet_test { frame_support::decl_module! { pub struct Module, I: Instance = DefaultInstance> for enum Call where - origin: T::Origin, ::OtherEvent: Into<>::Event> + origin: T::Origin, ::OtherEvent: Into<>::RuntimeEvent> { #[weight = 0] fn set_value(origin, n: u32) -> frame_support::dispatch::DispatchResult { @@ -64,9 +64,9 @@ mod pallet_test { pub trait Config: frame_system::Config + OtherConfig where - Self::OtherEvent: Into<>::Event>, + Self::OtherEvent: Into<>::RuntimeEvent>, { - type Event; + type RuntimeEvent; type LowerBound: Get; type UpperBound: Get; } @@ -95,12 +95,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; @@ -114,13 +114,13 @@ impl frame_system::Config for Test { } impl pallet_test::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type LowerBound = ConstU32<1>; type UpperBound = ConstU32<100>; } impl pallet_test::OtherConfig for Test { - type OtherEvent = Event; + type OtherEvent = RuntimeEvent; } fn new_test_ext() -> sp_io::TestExternalities { @@ -142,8 +142,8 @@ mod benchmarks { where_clause { where ::OtherEvent: Clone - + Into<>::Event>, - >::Event: Clone, + + Into<>::RuntimeEvent>, + >::RuntimeEvent: Clone, } set_value { diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 0c8c875dc611c..9dc920f6cca28 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -82,7 +82,7 @@ fn setup_pot_account, I: 'static>() { let _ = T::Currency::make_free_balance_be(&pot_account, value); } -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 74e67b7ea5b92..b95940a2835ce 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -230,7 +230,8 @@ pub mod pallet { type DataDepositPerByte: Get>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Maximum acceptable reason length. /// diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index cf4b8d23b0458..f1d794eb89dbe 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -71,13 +71,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -95,7 +95,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -113,7 +113,7 @@ impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -132,7 +132,7 @@ impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -155,7 +155,7 @@ parameter_types! { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BountyDepositBase = ConstU64<80>; type BountyDepositPayoutDelay = ConstU64<3>; type BountyUpdatePeriod = ConstU64<20>; @@ -170,7 +170,7 @@ impl Config for Test { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BountyDepositBase = ConstU64<80>; type BountyDepositPayoutDelay = ConstU64<3>; type BountyUpdatePeriod = ConstU64<20>; @@ -204,7 +204,7 @@ fn last_event() -> BountiesEvent { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::Bounties(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::Bounties(inner) = e { Some(inner) } else { None }) .last() .unwrap() } diff --git a/frame/child-bounties/src/benchmarking.rs b/frame/child-bounties/src/benchmarking.rs index ca5af50276b9d..697ed40e0071f 100644 --- a/frame/child-bounties/src/benchmarking.rs +++ b/frame/child-bounties/src/benchmarking.rs @@ -160,7 +160,7 @@ fn setup_pot_account() { let _ = T::Currency::make_free_balance_be(&pot_account, value); } -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 5f396cd2d4567..2dfe0660ad68e 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -146,7 +146,7 @@ pub mod pallet { type ChildBountyValueMinimum: Get>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index 0edee8468b86f..c9dbc8742c56a 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -74,13 +74,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u128; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -98,7 +98,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -115,7 +115,7 @@ impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -136,7 +136,7 @@ parameter_types! { } impl pallet_bounties::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BountyDepositBase = ConstU64<80>; type BountyDepositPayoutDelay = ConstU64<3>; type BountyUpdatePeriod = ConstU64<10>; @@ -150,7 +150,7 @@ impl pallet_bounties::Config for Test { type ChildBountyManager = ChildBounties; } impl pallet_child_bounties::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MaxActiveChildBountyCount = ConstU32<2>; type ChildBountyValueMinimum = ConstU64<1>; type WeightInfo = (); @@ -172,7 +172,7 @@ fn last_event() -> ChildBountiesEvent { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::ChildBounties(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::ChildBounties(inner) = e { Some(inner) } else { None }) .last() .unwrap() } diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index b80a4aef28d38..7c444dbaa7b6a 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -30,7 +30,7 @@ const SEED: u32 = 0; const MAX_BYTES: u32 = 1_024; -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 02faf876806e1..7944f826255ec 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -187,7 +187,8 @@ pub mod pallet { + GetDispatchInfo; /// The outer event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The time-out for council motions. type MotionDuration: Get; diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index e7b97a39e020a..b063cc21bd426 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -32,7 +32,7 @@ use sp_runtime::{ }; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Test where @@ -61,7 +61,8 @@ mod mock_democracy { #[pallet::config] pub trait Config: frame_system::Config + Sized { - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; type ExternalMajorityOrigin: EnsureOrigin; } @@ -99,13 +100,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -119,8 +120,8 @@ impl frame_system::Config for Test { } impl Config for Test { type Origin = Origin; - type Proposal = Call; - type Event = Event; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = ConstU64<3>; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; @@ -129,8 +130,8 @@ impl Config for Test { } impl Config for Test { type Origin = Origin; - type Proposal = Call; - type Event = Event; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = ConstU64<3>; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; @@ -138,13 +139,13 @@ impl Config for Test { type WeightInfo = (); } impl mock_democracy::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExternalMajorityOrigin = EnsureProportionAtLeast; } impl Config for Test { type Origin = Origin; - type Proposal = Call; - type Event = Event; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = ConstU64<3>; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; @@ -171,11 +172,13 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ext } -fn make_proposal(value: u64) -> Call { - Call::System(frame_system::Call::remark_with_event { remark: value.to_be_bytes().to_vec() }) +fn make_proposal(value: u64) -> RuntimeCall { + RuntimeCall::System(frame_system::Call::remark_with_event { + remark: value.to_be_bytes().to_vec(), + }) } -fn record(event: Event) -> EventRecord { +fn record(event: RuntimeEvent) -> EventRecord { EventRecord { phase: Phase::Initialization, event, topics: vec![] } } @@ -216,32 +219,34 @@ fn close_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 2, no: 1 })), - record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) + record(RuntimeEvent::Collective(CollectiveEvent::Disapproved { + proposal_hash: hash + })) ] ); }); @@ -250,7 +255,7 @@ fn close_works() { #[test] fn proposal_weight_limit_works_on_approve() { new_test_ext().execute_with(|| { - let proposal = Call::Collective(crate::Call::set_members { + let proposal = RuntimeCall::Collective(crate::Call::set_members { new_members: vec![1, 2, 3], prime: None, old_count: MaxMembers::get(), @@ -286,7 +291,7 @@ fn proposal_weight_limit_works_on_approve() { #[test] fn proposal_weight_limit_ignored_on_disapprove() { new_test_ext().execute_with(|| { - let proposal = Call::Collective(crate::Call::set_members { + let proposal = RuntimeCall::Collective(crate::Call::set_members { new_members: vec![1, 2, 3], prime: None, old_count: MaxMembers::get(), @@ -342,32 +347,34 @@ fn close_with_prime_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 2, no: 1 })), - record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) + record(RuntimeEvent::Collective(CollectiveEvent::Disapproved { + proposal_hash: hash + })) ] ); }); @@ -402,33 +409,33 @@ fn close_with_voting_prime_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 3, no: 0 })), - record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), - record(Event::Collective(CollectiveEvent::Executed { + record(RuntimeEvent::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(RuntimeEvent::Collective(CollectiveEvent::Executed { proposal_hash: hash, result: Err(DispatchError::BadOrigin) })) @@ -473,42 +480,42 @@ fn close_with_no_prime_but_majority_works() { assert_eq!( System::events(), vec![ - record(Event::CollectiveMajority(CollectiveEvent::Proposed { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 5 })), - record(Event::CollectiveMajority(CollectiveEvent::Voted { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::CollectiveMajority(CollectiveEvent::Voted { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::CollectiveMajority(CollectiveEvent::Voted { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Voted { account: 3, proposal_hash: hash, voted: true, yes: 3, no: 0 })), - record(Event::CollectiveMajority(CollectiveEvent::Closed { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Closed { proposal_hash: hash, yes: 5, no: 0 })), - record(Event::CollectiveMajority(CollectiveEvent::Approved { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Approved { proposal_hash: hash })), - record(Event::CollectiveMajority(CollectiveEvent::Executed { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Executed { proposal_hash: hash, result: Err(DispatchError::BadOrigin) })) @@ -635,7 +642,7 @@ fn propose_works() { assert_eq!( System::events(), - vec![record(Event::Collective(CollectiveEvent::Proposed { + vec![record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, @@ -670,7 +677,7 @@ fn limit_active_proposals() { #[test] fn correct_validate_and_get_proposal() { new_test_ext().execute_with(|| { - let proposal = Call::Collective(crate::Call::set_members { + let proposal = RuntimeCall::Collective(crate::Call::set_members { new_members: vec![1, 2, 3], prime: None, old_count: MaxMembers::get(), @@ -803,20 +810,20 @@ fn motions_vote_after_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 2 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: false, @@ -915,7 +922,7 @@ fn motions_reproposing_disapproved_works() { #[test] fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { new_test_ext().execute_with(|| { - let proposal = Call::Democracy(mock_democracy::Call::external_propose_majority {}); + let proposal = RuntimeCall::Democracy(mock_democracy::Call::external_propose_majority {}); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let proposal_weight = proposal.get_dispatch_info().weight; let hash: H256 = proposal.blake2_256().into(); @@ -936,33 +943,33 @@ fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 2 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), - record(Event::Collective(CollectiveEvent::Executed { + record(RuntimeEvent::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(RuntimeEvent::Collective(CollectiveEvent::Executed { proposal_hash: hash, result: Err(DispatchError::BadOrigin) })), @@ -985,41 +992,43 @@ fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 1, proposal_hash: hash, threshold: 2 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 3, proposal_hash: hash, voted: true, yes: 3, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 3, no: 0 })), - record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), - record(Event::Democracy(mock_democracy::pallet::Event::::ExternalProposed)), - record(Event::Collective(CollectiveEvent::Executed { + record(RuntimeEvent::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(RuntimeEvent::Democracy( + mock_democracy::pallet::Event::::ExternalProposed + )), + record(RuntimeEvent::Collective(CollectiveEvent::Executed { proposal_hash: hash, result: Ok(()) })), @@ -1048,32 +1057,34 @@ fn motions_disapproval_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: false, yes: 1, no: 1 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 1, no: 1 })), - record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })), + record(RuntimeEvent::Collective(CollectiveEvent::Disapproved { + proposal_hash: hash + })), ] ); }); @@ -1099,33 +1110,33 @@ fn motions_approval_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 2 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), - record(Event::Collective(CollectiveEvent::Executed { + record(RuntimeEvent::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(RuntimeEvent::Collective(CollectiveEvent::Executed { proposal_hash: hash, result: Err(DispatchError::BadOrigin) })), @@ -1149,7 +1160,7 @@ fn motion_with_no_votes_closes_with_disapproval() { )); assert_eq!( System::events()[0], - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, @@ -1173,7 +1184,7 @@ fn motion_with_no_votes_closes_with_disapproval() { // Events show that the close ended in a disapproval. assert_eq!( System::events()[1], - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 0, no: 3 @@ -1181,7 +1192,7 @@ fn motion_with_no_votes_closes_with_disapproval() { ); assert_eq!( System::events()[2], - record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) + record(RuntimeEvent::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) ); }) } @@ -1241,27 +1252,29 @@ fn disapprove_proposal_works() { assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 2 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })), + record(RuntimeEvent::Collective(CollectiveEvent::Disapproved { + proposal_hash: hash + })), ] ); }) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index f91be3a9e491c..0fbf821b2e284 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -282,7 +282,7 @@ pub trait Ext: sealing::Sealed { fn append_debug_buffer(&mut self, msg: &str) -> bool; /// Call some dispatchable and return the result. - fn call_runtime(&self, call: ::Call) -> DispatchResultWithPostInfo; + fn call_runtime(&self, call: ::RuntimeCall) -> DispatchResultWithPostInfo; /// Recovers ECDSA compressed public key based on signature and message hash. fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()>; @@ -1305,7 +1305,7 @@ where } } - fn call_runtime(&self, call: ::Call) -> DispatchResultWithPostInfo { + fn call_runtime(&self, call: ::RuntimeCall) -> DispatchResultWithPostInfo { let mut origin: T::Origin = RawOrigin::Signed(self.address().clone()).into(); origin.add_filter(T::CallFilter::contains); call.dispatch(origin) @@ -1370,7 +1370,8 @@ mod tests { storage::Storage, tests::{ test_utils::{get_balance, hash, place_contract, set_balance}, - Call, Event as MetaEvent, ExtBuilder, Test, TestFilter, ALICE, BOB, CHARLIE, GAS_LIMIT, + ExtBuilder, RuntimeCall, RuntimeEvent as MetaEvent, Test, TestFilter, ALICE, BOB, + CHARLIE, GAS_LIMIT, }, Error, }; @@ -2575,7 +2576,7 @@ mod tests { #[test] fn call_runtime_works() { let code_hash = MockLoader::insert(Call, |ctx, _| { - let call = Call::System(frame_system::Call::remark_with_event { + let call = RuntimeCall::System(frame_system::Call::remark_with_event { remark: b"Hello World".to_vec(), }); ctx.ext.call_runtime(call).unwrap(); @@ -2636,10 +2637,11 @@ mod tests { // remark should still be allowed let allowed_call = - Call::System(SysCall::remark_with_event { remark: b"Hello".to_vec() }); + RuntimeCall::System(SysCall::remark_with_event { remark: b"Hello".to_vec() }); // transfers are disallowed by the `TestFiler` (see below) - let forbidden_call = Call::Balances(BalanceCall::transfer { dest: CHARLIE, value: 22 }); + let forbidden_call = + RuntimeCall::Balances(BalanceCall::transfer { dest: CHARLIE, value: 22 }); // simple cases: direct call assert_err!( @@ -2648,7 +2650,7 @@ mod tests { ); // as part of a patch: return is OK (but it interrupted the batch) - assert_ok!(ctx.ext.call_runtime(Call::Utility(UtilCall::batch { + assert_ok!(ctx.ext.call_runtime(RuntimeCall::Utility(UtilCall::batch { calls: vec![allowed_call.clone(), forbidden_call, allowed_call] })),); @@ -2659,7 +2661,7 @@ mod tests { }); TestFilter::set_filter(|call| match call { - Call::Balances(pallet_balances::Call::transfer { .. }) => false, + RuntimeCall::Balances(pallet_balances::Call::transfer { .. }) => false, _ => true, }); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 3c63ad86016f3..9890bd840cc3a 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -243,13 +243,13 @@ pub mod pallet { type Currency: ReservableCurrency; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The overarching call type. - type Call: Dispatchable + type RuntimeCall: Dispatchable + GetDispatchInfo + codec::Decode - + IsType<::Call>; + + IsType<::RuntimeCall>; /// Filter that is applied to calls dispatched by contracts. /// @@ -260,7 +260,7 @@ pub mod pallet { /// # Stability /// /// The runtime **must** make sure that all dispatchables that are callable by - /// contracts remain stable. In addition [`Self::Call`] itself must remain stable. + /// contracts remain stable. In addition [`Self::RuntimeCall`] itself must remain stable. /// This means that no existing variants are allowed to switch their positions. /// /// # Note @@ -270,7 +270,7 @@ pub mod pallet { /// Therefore please make sure to be restrictive about which dispatchables are allowed /// in order to not introduce a new DoS vector like memory allocation patterns that can /// be exploited to drive the runtime into a panic. - type CallFilter: Contains<::Call>; + type CallFilter: Contains<::RuntimeCall>; /// Used to answer contracts' queries regarding the current weight price. This is **not** /// used to calculate the actual fee and is only for informational purposes. @@ -1119,7 +1119,7 @@ where fn deposit_event(topics: Vec, event: Event) { >::deposit_event_indexed( &topics, - ::Event::from(event).into(), + ::RuntimeEvent::from(event).into(), ) } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 8bca18c5d1c42..1193d17676e1d 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -164,27 +164,27 @@ impl ChainExtension for TestExtension { let func_id = env.func_id(); let id = env.ext_id() as u32 | func_id as u32; match func_id { - 0x8000 => { + 0 => { let mut env = env.buf_in_buf_out(); let input = env.read(8)?; env.write(&input, false, None)?; TestExtensionTestValue::mutate(|e| e.last_seen_buffer = input); Ok(RetVal::Converging(id)) }, - 0x8001 => { + 1 => { let env = env.only_in(); TestExtensionTestValue::mutate(|e| { e.last_seen_inputs = (env.val0(), env.val1(), env.val2(), env.val3()) }); Ok(RetVal::Converging(id)) }, - 0x8002 => { + 2 => { let mut env = env.buf_in_buf_out(); let weight = Weight::from_ref_time(env.read(5)?[4].into()); env.charge_weight(weight)?; Ok(RetVal::Converging(id)) }, - 0x8003 => Ok(RetVal::Diverging { flags: ReturnFlags::REVERT, data: vec![42, 99] }), + 3 => Ok(RetVal::Diverging { flags: ReturnFlags::REVERT, data: vec![42, 99] }), _ => { panic!("Passed unknown id to test chain extension: {}", func_id); }, @@ -281,12 +281,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = AccountId32; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -304,7 +304,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -318,8 +318,8 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } impl pallet_utility::Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; type WeightInfo = (); } @@ -346,7 +346,7 @@ pub struct TestFilter; #[derive(Clone)] pub struct Filters { - filter: fn(&Call) -> bool, + filter: fn(&RuntimeCall) -> bool, } impl Default for Filters { @@ -360,13 +360,13 @@ parameter_types! { } impl TestFilter { - pub fn set_filter(filter: fn(&Call) -> bool) { + pub fn set_filter(filter: fn(&RuntimeCall) -> bool) { CallFilter::mutate(|fltr| fltr.filter = filter); } } -impl Contains for TestFilter { - fn contains(call: &Call) -> bool { +impl Contains for TestFilter { + fn contains(call: &RuntimeCall) -> bool { (CallFilter::get().filter)(call) } } @@ -379,8 +379,8 @@ impl Config for Test { type Time = Timestamp; type Randomness = Randomness; type Currency = Balances; - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type CallFilter = TestFilter; type CallStack = [Frame; 31]; type WeightPrice = Self; @@ -536,12 +536,14 @@ fn instantiate_and_call_and_deposit_event() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone() + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { account: addr.clone(), free_balance: min_balance, }), @@ -549,7 +551,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: min_balance, @@ -558,7 +560,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: addr.clone(), amount: min_balance, }), @@ -566,7 +568,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: value, @@ -575,7 +577,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::ContractEmitted { + event: RuntimeEvent::Contracts(crate::Event::ContractEmitted { contract: addr.clone(), data: vec![1, 2, 3, 4] }), @@ -583,7 +585,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Instantiated { + event: RuntimeEvent::Contracts(crate::Event::Instantiated { deployer: ALICE, contract: addr.clone() }), @@ -828,14 +830,14 @@ fn deploy_and_call_other_contract() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { + event: RuntimeEvent::System(frame_system::Event::NewAccount { account: callee_addr.clone() }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { account: callee_addr.clone(), free_balance: min_balance, }), @@ -843,7 +845,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: callee_addr.clone(), amount: min_balance, @@ -852,7 +854,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: callee_addr.clone(), amount: min_balance, }), @@ -860,7 +862,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: caller_addr.clone(), to: callee_addr.clone(), amount: 32768, // hard coded in wasm @@ -869,7 +871,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Instantiated { + event: RuntimeEvent::Contracts(crate::Event::Instantiated { deployer: caller_addr.clone(), contract: callee_addr.clone(), }), @@ -877,7 +879,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: caller_addr.clone(), to: callee_addr.clone(), amount: 32768, @@ -886,7 +888,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: caller_addr.clone(), contract: callee_addr.clone(), }), @@ -894,7 +896,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: caller_addr.clone(), }), @@ -1093,7 +1095,7 @@ fn cannot_self_destruct_by_refund_after_slash() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Slashed { + event: RuntimeEvent::Balances(pallet_balances::Event::Slashed { who: addr.clone(), amount: 90, }), @@ -1101,7 +1103,7 @@ fn cannot_self_destruct_by_refund_after_slash() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -1109,7 +1111,7 @@ fn cannot_self_destruct_by_refund_after_slash() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::ReserveRepatriated { + event: RuntimeEvent::Balances(pallet_balances::Event::ReserveRepatriated { from: addr.clone(), to: ALICE, amount: 10, @@ -1201,7 +1203,7 @@ fn self_destruct_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: addr.clone(), to: DJANGO, amount: 100_000, @@ -1210,7 +1212,7 @@ fn self_destruct_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Terminated { + event: RuntimeEvent::Contracts(crate::Event::Terminated { contract: addr.clone(), beneficiary: DJANGO }), @@ -1218,7 +1220,7 @@ fn self_destruct_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -1226,14 +1228,14 @@ fn self_destruct_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::KilledAccount { + event: RuntimeEvent::System(frame_system::Event::KilledAccount { account: addr.clone() }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::ReserveRepatriated { + event: RuntimeEvent::Balances(pallet_balances::Event::ReserveRepatriated { from: addr.clone(), to: ALICE, amount: 1_000, @@ -1698,22 +1700,21 @@ fn chain_extension_works() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - // 0x8000 = read input buffer and pass it through as output - let input: Vec = - ExtensionInput { extension_id: 0, func_id: 0x8000, extra: &[99] }.into(); + // 0 = read input buffer and pass it through as output + let input: Vec = ExtensionInput { extension_id: 0, func_id: 0, extra: &[99] }.into(); let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false); assert_eq!(TestExtension::last_seen_buffer(), input); assert_eq!(result.result.unwrap().data, Bytes(input)); - // 0x8001 = treat inputs as integer primitives and store the supplied integers + // 1 = treat inputs as integer primitives and store the supplied integers Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 0x8001, extra: &[] }.into(), + ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into(), false, ) .result @@ -1721,14 +1722,14 @@ fn chain_extension_works() { // those values passed in the fixture assert_eq!(TestExtension::last_seen_inputs(), (4, 4, 16, 12)); - // 0x8002 = charge some extra weight (amount supplied in the fifth byte) + // 2 = charge some extra weight (amount supplied in the fifth byte) let result = Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 0x8002, extra: &[0] }.into(), + ExtensionInput { extension_id: 0, func_id: 2, extra: &[0] }.into(), false, ); assert_ok!(result.result); @@ -1739,7 +1740,7 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 0x8002, extra: &[42] }.into(), + ExtensionInput { extension_id: 0, func_id: 2, extra: &[42] }.into(), false, ); assert_ok!(result.result); @@ -1750,20 +1751,20 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 0x8002, extra: &[95] }.into(), + ExtensionInput { extension_id: 0, func_id: 2, extra: &[95] }.into(), false, ); assert_ok!(result.result); assert_eq!(result.gas_consumed, gas_consumed + 95); - // 0x8003 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer + // 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer let result = Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 0x8003, extra: &[] }.into(), + ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into(), false, ) .result @@ -2550,7 +2551,7 @@ fn gas_estimation_call_runtime() { // Call something trivial with a huge gas limit so that we can observe the effects // of pre-charging. This should create a difference between consumed and required. - let call = Call::Contracts(crate::Call::call { + let call = RuntimeCall::Contracts(crate::Call::call { dest: addr_callee, value: 0, gas_limit: GAS_LIMIT / 3, @@ -2660,7 +2661,7 @@ fn upload_code_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, amount: 240, }), @@ -2668,7 +2669,7 @@ fn upload_code_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash }), topics: vec![code_hash], }, ] @@ -2739,7 +2740,7 @@ fn remove_code_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, amount: 240, }), @@ -2747,12 +2748,12 @@ fn remove_code_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash }), topics: vec![code_hash], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Unreserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Unreserved { who: ALICE, amount: 240, }), @@ -2760,7 +2761,7 @@ fn remove_code_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeRemoved { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeRemoved { code_hash }), topics: vec![code_hash], }, ] @@ -2794,7 +2795,7 @@ fn remove_code_wrong_origin() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, amount: 240, }), @@ -2802,7 +2803,7 @@ fn remove_code_wrong_origin() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash }), topics: vec![code_hash], }, ] @@ -2895,12 +2896,14 @@ fn instantiate_with_zero_balance_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone() + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { account: addr.clone(), free_balance: min_balance, }), @@ -2908,7 +2911,7 @@ fn instantiate_with_zero_balance_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: min_balance, @@ -2917,7 +2920,7 @@ fn instantiate_with_zero_balance_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: addr.clone(), amount: min_balance, }), @@ -2925,7 +2928,7 @@ fn instantiate_with_zero_balance_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, amount: 240, }), @@ -2933,12 +2936,12 @@ fn instantiate_with_zero_balance_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash }), topics: vec![code_hash], }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Instantiated { + event: RuntimeEvent::Contracts(crate::Event::Instantiated { deployer: ALICE, contract: addr.clone(), }), @@ -2986,12 +2989,14 @@ fn instantiate_with_below_existential_deposit_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone() + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { account: addr.clone(), free_balance: min_balance, }), @@ -2999,7 +3004,7 @@ fn instantiate_with_below_existential_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: min_balance, @@ -3008,7 +3013,7 @@ fn instantiate_with_below_existential_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: addr.clone(), amount: min_balance, }), @@ -3016,7 +3021,7 @@ fn instantiate_with_below_existential_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: 50, @@ -3025,7 +3030,7 @@ fn instantiate_with_below_existential_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, amount: 240, }), @@ -3033,12 +3038,12 @@ fn instantiate_with_below_existential_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash }), topics: vec![code_hash], }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Instantiated { + event: RuntimeEvent::Contracts(crate::Event::Instantiated { deployer: ALICE, contract: addr.clone(), }), @@ -3115,7 +3120,7 @@ fn storage_deposit_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: 42, @@ -3124,7 +3129,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -3132,7 +3137,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: charged0, @@ -3141,7 +3146,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: addr.clone(), amount: charged0, }), @@ -3149,7 +3154,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -3157,7 +3162,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: charged1, @@ -3166,7 +3171,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: addr.clone(), amount: charged1, }), @@ -3174,7 +3179,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -3182,7 +3187,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::ReserveRepatriated { + event: RuntimeEvent::Balances(pallet_balances::Event::ReserveRepatriated { from: addr.clone(), to: ALICE, amount: refunded0, @@ -3264,7 +3269,7 @@ fn set_code_extrinsic() { System::events(), vec![EventRecord { phase: Phase::Initialization, - event: Event::Contracts(pallet_contracts::Event::ContractCodeUpdated { + event: RuntimeEvent::Contracts(pallet_contracts::Event::ContractCodeUpdated { contract: addr.clone(), new_code_hash, old_code_hash: code_hash, @@ -3343,14 +3348,14 @@ fn call_after_killed_account_needs_funding() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::KilledAccount { + event: RuntimeEvent::System(frame_system::Event::KilledAccount { account: addr.clone() }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Slashed { + event: RuntimeEvent::Balances(pallet_balances::Event::Slashed { who: addr.clone(), amount: min_balance + 700 }), @@ -3358,7 +3363,7 @@ fn call_after_killed_account_needs_funding() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -3366,12 +3371,14 @@ fn call_after_killed_account_needs_funding() { }, EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone() + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { account: addr.clone(), free_balance: min_balance }), @@ -3379,7 +3386,7 @@ fn call_after_killed_account_needs_funding() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: min_balance @@ -3388,7 +3395,7 @@ fn call_after_killed_account_needs_funding() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -3571,7 +3578,7 @@ fn set_code_hash() { &[ EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::ContractCodeUpdated { + event: RuntimeEvent::Contracts(crate::Event::ContractCodeUpdated { contract: contract_addr.clone(), new_code_hash, old_code_hash: code_hash, @@ -3580,7 +3587,7 @@ fn set_code_hash() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: contract_addr.clone(), }), @@ -3588,7 +3595,7 @@ fn set_code_hash() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: contract_addr.clone(), }), diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 3718be756e39d..e850f458bb745 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -280,7 +280,7 @@ mod tests { }, gas::GasMeter, storage::WriteOutcome, - tests::{Call, Test, ALICE, BOB}, + tests::{RuntimeCall, Test, ALICE, BOB}, BalanceOf, CodeHash, Error, Pallet as Contracts, }; use assert_matches::assert_matches; @@ -339,7 +339,7 @@ mod tests { transfers: Vec, // (topics, data) events: Vec<(Vec, Vec)>, - runtime_calls: RefCell>, + runtime_calls: RefCell>, schedule: Schedule, gas_meter: GasMeter, debug_buffer: Vec, @@ -532,7 +532,10 @@ mod tests { self.debug_buffer.extend(msg.as_bytes()); true } - fn call_runtime(&self, call: ::Call) -> DispatchResultWithPostInfo { + fn call_runtime( + &self, + call: ::RuntimeCall, + ) -> DispatchResultWithPostInfo { self.runtime_calls.borrow_mut().push(call); Ok(Default::default()) } @@ -2299,7 +2302,8 @@ mod tests { #[test] #[cfg(feature = "unstable-interface")] fn call_runtime_works() { - let call = Call::System(frame_system::Call::remark { remark: b"Hello World".to_vec() }); + let call = + RuntimeCall::System(frame_system::Call::remark { remark: b"Hello World".to_vec() }); let mut ext = MockExt::default(); let result = execute(CODE_CALL_RUNTIME, call.encode(), &mut ext).unwrap(); assert_eq!(*ext.runtime_calls.borrow(), vec![call]); diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 334223e3b8432..5b94611843169 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -2316,7 +2316,7 @@ pub mod env { ) -> Result { use frame_support::{dispatch::GetDispatchInfo, weights::extract_actual_weight}; ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?; - let call: ::Call = + let call: ::RuntimeCall = ctx.read_sandbox_memory_as_unbounded(call_ptr, call_len)?; let dispatch_info = call.get_dispatch_info(); let charged = ctx.charge_gas(RuntimeCosts::CallRuntime(dispatch_info.weight))?; diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index cd16fccd6661d..534941d6f7f66 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -98,7 +98,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + Sized { // System level stuff. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// Currency type with which voting happens. diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index cbd2b0619ac2b..7a97a46086398 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -50,9 +50,9 @@ frame_support::construct_runtime!( // Test that a fitlered call can be dispatched. pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, &Call::Balances(pallet_balances::Call::set_balance { .. })) +impl Contains for BaseFilter { + fn contains(call: &RuntimeCall) -> bool { + !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::set_balance { .. })) } } @@ -68,13 +68,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -92,7 +92,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type MaxLocks = ConstU32<10>; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -187,7 +187,7 @@ impl Polling> for TestPolls { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = pallet_balances::Pallet; type VoteLockingPeriod = ConstU64<3>; type MaxVotes = ConstU32<3>; diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index d5db82de3840d..ab4075bc82fc5 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -37,7 +37,7 @@ const MAX_REFERENDUMS: u32 = 99; const MAX_SECONDERS: u32 = 100; const MAX_BYTES: u32 = 16_384; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index bbc5b767e97ff..f6696065bfc87 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -254,7 +254,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + Sized { type Proposal: Parameter + Dispatchable + From>; - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Currency type for this pallet. type Currency: ReservableCurrency diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index def8f84067909..e3ed046813e23 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -70,9 +70,9 @@ frame_support::construct_runtime!( // Test that a fitlered call can be dispatched. pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, &Call::Balances(pallet_balances::Call::set_balance { .. })) +impl Contains for BaseFilter { + fn contains(call: &RuntimeCall) -> bool { + !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::set_balance { .. })) } } @@ -88,13 +88,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -110,10 +110,10 @@ parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; } impl pallet_scheduler::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Origin = Origin; type PalletsOrigin = OriginCaller; - type Call = Call; + type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureRoot; type MaxScheduledPerBlock = (); @@ -128,7 +128,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type MaxLocks = ConstU32<10>; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -156,8 +156,8 @@ impl SortedMembers for OneToFive { } impl Config for Test { - type Proposal = Call; - type Event = Event; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type Currency = pallet_balances::Pallet; type EnactmentPeriod = ConstU64<2>; type LaunchPeriod = ConstU64<2>; @@ -217,14 +217,18 @@ fn params_should_work() { } fn set_balance_proposal(value: u64) -> Vec { - Call::Balances(pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 }) - .encode() + RuntimeCall::Balances(pallet_balances::Call::set_balance { + who: 42, + new_free: value, + new_reserved: 0, + }) + .encode() } #[test] fn set_balance_proposal_is_correctly_filtered_out() { for i in 0..10 { - let call = Call::decode(&mut &set_balance_proposal(i)[..]).unwrap(); + let call = RuntimeCall::decode(&mut &set_balance_proposal(i)[..]).unwrap(); assert!(!::BaseCallFilter::contains(&call)); } } diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index a9ce35499a329..f0378ea7dc83f 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -570,8 +570,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + SendTransactionTypes> { - type Event: From> - + IsType<::Event> + type RuntimeEvent: From> + + IsType<::RuntimeEvent> + TryInto>; /// Currency type. diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 4e9672fc1d4f6..efe9d8ea587cb 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -50,7 +50,8 @@ use sp_runtime::{ use std::sync::Arc; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = + sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime where @@ -85,7 +86,7 @@ pub(crate) fn multi_phase_events() -> Vec> { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::MultiPhase(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::MultiPhase(inner) = e { Some(inner) } else { None }) .collect::>() } @@ -201,13 +202,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type DbWeight = (); type BlockLength = (); @@ -231,7 +232,7 @@ parameter_types! { impl pallet_balances::Config for Runtime { type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -362,7 +363,7 @@ impl MinerConfig for Runtime { } impl crate::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type EstimateCallFee = frame_support::traits::ConstU32<8>; type SignedPhase = SignedPhase; @@ -394,13 +395,13 @@ impl crate::Config for Runtime { impl frame_system::offchain::SendTransactionTypes for Runtime where - Call: From, + RuntimeCall: From, { - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; type Extrinsic = Extrinsic; } -pub type Extrinsic = sp_runtime::testing::TestXt; +pub type Extrinsic = sp_runtime::testing::TestXt; parameter_types! { pub MaxNominations: u32 = ::LIMIT as u32; diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index e99f2e9cef028..7dadd320abdf8 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -855,8 +855,8 @@ mod tests { use super::*; use crate::{ mock::{ - roll_to, roll_to_with_ocw, trim_helpers, witness, BlockNumber, Call as OuterCall, - ExtBuilder, Extrinsic, MinerMaxWeight, MultiPhase, Origin, Runtime, System, + roll_to, roll_to_with_ocw, trim_helpers, witness, BlockNumber, ExtBuilder, Extrinsic, + MinerMaxWeight, MultiPhase, Origin, Runtime, RuntimeCall as OuterCall, System, TestNposSolution, TrimHelpers, UnsignedPhase, }, CurrentPhase, InvalidTransaction, Phase, QueuedSolution, TransactionSource, diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 62e76c3888822..c899e021f974a 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -214,13 +214,13 @@ mod tests { type Origin = Origin; type Index = AccountId; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = sp_runtime::traits::IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = (); + type RuntimeEvent = (); type BlockHashCount = (); type DbWeight = (); type BlockLength = (); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 539e90d0179ff..18210513f8ab6 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -195,7 +195,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Identifier for the elections-phragmen pallet's lock #[pallet::constant] @@ -1185,13 +1185,13 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -1206,7 +1206,7 @@ mod tests { impl pallet_balances::Config for Test { type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = frame_system::Pallet; @@ -1279,7 +1279,7 @@ mod tests { impl Config for Test { type PalletId = ElectionsPhragmenPalletId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type ChangeMembers = TestChangeMembers; @@ -1298,7 +1298,8 @@ mod tests { } pub type Block = sp_runtime::generic::Block; - pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; + pub type UncheckedExtrinsic = + sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Test where @@ -2201,7 +2202,7 @@ mod tests { System::set_block_number(5); Elections::on_initialize(System::block_number()); - System::assert_last_event(Event::Elections(super::Event::EmptyTerm)); + System::assert_last_event(RuntimeEvent::Elections(super::Event::EmptyTerm)); }) } @@ -2217,7 +2218,7 @@ mod tests { System::set_block_number(5); Elections::on_initialize(System::block_number()); - System::assert_last_event(Event::Elections(super::Event::NewTerm { + System::assert_last_event(RuntimeEvent::Elections(super::Event::NewTerm { new_members: vec![(4, 35), (5, 45)], })); @@ -2230,7 +2231,7 @@ mod tests { System::set_block_number(10); Elections::on_initialize(System::block_number()); - System::assert_last_event(Event::Elections(super::Event::NewTerm { + System::assert_last_event(RuntimeEvent::Elections(super::Event::NewTerm { new_members: vec![], })); @@ -2302,7 +2303,7 @@ mod tests { assert_eq!(Elections::election_rounds(), 1); assert!(members_ids().is_empty()); - System::assert_last_event(Event::Elections(super::Event::NewTerm { + System::assert_last_event(RuntimeEvent::Elections(super::Event::NewTerm { new_members: vec![], })); }); @@ -2610,7 +2611,7 @@ mod tests { // 5 is an outgoing loser. will also get slashed. assert_eq!(balances(&5), (45, 2)); - System::assert_has_event(Event::Elections(super::Event::NewTerm { + System::assert_has_event(RuntimeEvent::Elections(super::Event::NewTerm { new_members: vec![(4, 35), (5, 45)], })); }) diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index ad46bdc4185bd..756333b197090 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -370,7 +370,7 @@ pub mod pallet { type MagicNumber: Get; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Type representing the weight of this pallet type WeightInfo: WeightInfo; @@ -719,11 +719,11 @@ impl sp_std::fmt::Debug for WatchDummy { impl SignedExtension for WatchDummy where - ::Call: IsSubType>, + ::RuntimeCall: IsSubType>, { const IDENTIFIER: &'static str = "WatchDummy"; type AccountId = T::AccountId; - type Call = ::Call; + type Call = ::RuntimeCall; type AdditionalSigned = (); type Pre = (); diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 567117e621921..78cdb3794f8d3 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -63,12 +63,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -87,7 +87,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -95,7 +95,7 @@ impl pallet_balances::Config for Test { impl Config for Test { type MagicNumber = ConstU64<1_000_000_000>; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index b40311051594b..fdf8b61a01acd 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -126,10 +126,7 @@ pub mod pallet { type AuthorityId: AppCrypto; /// The overarching event type. - type Event: From> + IsType<::Event>; - - /// The overarching dispatch call type. - type Call: From>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; // Configuration parameters diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 5b03614333cc9..2c189935ac19d 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -61,7 +61,7 @@ impl frame_system::Config for Test { type BlockLength = (); type DbWeight = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -69,7 +69,7 @@ impl frame_system::Config for Test { type AccountId = sp_core::sr25519::Public; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -82,7 +82,7 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } -type Extrinsic = TestXt; +type Extrinsic = TestXt; type AccountId = <::Signer as IdentifyAccount>::AccountId; impl frame_system::offchain::SigningTypes for Test { @@ -92,22 +92,22 @@ impl frame_system::offchain::SigningTypes for Test { impl frame_system::offchain::SendTransactionTypes for Test where - Call: From, + RuntimeCall: From, { - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; type Extrinsic = Extrinsic; } impl frame_system::offchain::CreateSignedTransaction for Test where - Call: From, + RuntimeCall: From, { fn create_transaction>( - call: Call, + call: RuntimeCall, _public: ::Signer, _account: AccountId, nonce: u64, - ) -> Option<(Call, ::SignaturePayload)> { + ) -> Option<(RuntimeCall, ::SignaturePayload)> { Some((call, (nonce, ()))) } } @@ -117,9 +117,8 @@ parameter_types! { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type AuthorityId = crypto::TestAuthId; - type Call = Call; type GracePeriod = ConstU64<5>; type UnsignedInterval = ConstU64<128>; type UnsignedPriority = UnsignedPriority; @@ -233,7 +232,7 @@ fn should_submit_signed_transaction_on_chain() { assert!(pool_state.read().transactions.is_empty()); let tx = Extrinsic::decode(&mut &*tx).unwrap(); assert_eq!(tx.signature.unwrap().0, 0); - assert_eq!(tx.call, Call::Example(crate::Call::submit_price { price: 15523 })); + assert_eq!(tx.call, RuntimeCall::Example(crate::Call::submit_price { price: 15523 })); }); } @@ -278,7 +277,7 @@ fn should_submit_unsigned_transaction_on_chain_for_any_account() { let tx = pool_state.write().transactions.pop().unwrap(); let tx = Extrinsic::decode(&mut &*tx).unwrap(); assert_eq!(tx.signature, None); - if let Call::Example(crate::Call::submit_price_unsigned_with_signed_payload { + if let RuntimeCall::Example(crate::Call::submit_price_unsigned_with_signed_payload { price_payload: body, signature, }) = tx.call @@ -337,7 +336,7 @@ fn should_submit_unsigned_transaction_on_chain_for_all_accounts() { let tx = pool_state.write().transactions.pop().unwrap(); let tx = Extrinsic::decode(&mut &*tx).unwrap(); assert_eq!(tx.signature, None); - if let Call::Example(crate::Call::submit_price_unsigned_with_signed_payload { + if let RuntimeCall::Example(crate::Call::submit_price_unsigned_with_signed_payload { price_payload: body, signature, }) = tx.call @@ -379,7 +378,10 @@ fn should_submit_raw_unsigned_transaction_on_chain() { assert_eq!(tx.signature, None); assert_eq!( tx.call, - Call::Example(crate::Call::submit_price_unsigned { block_number: 1, price: 15523 }) + RuntimeCall::Example(crate::Call::submit_price_unsigned { + block_number: 1, + price: 15523 + }) ); }); } diff --git a/frame/examples/parallel/src/lib.rs b/frame/examples/parallel/src/lib.rs index 7b8948c2ebd09..3432a79638664 100644 --- a/frame/examples/parallel/src/lib.rs +++ b/frame/examples/parallel/src/lib.rs @@ -41,10 +41,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching dispatch call type. - type Call: From>; - } + pub trait Config: frame_system::Config {} #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] diff --git a/frame/examples/parallel/src/tests.rs b/frame/examples/parallel/src/tests.rs index 67d823d8b204b..80c8213fdfb1c 100644 --- a/frame/examples/parallel/src/tests.rs +++ b/frame/examples/parallel/src/tests.rs @@ -46,7 +46,7 @@ parameter_types! { impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type PalletInfo = PalletInfo; type Index = u64; type BlockNumber = u64; @@ -55,7 +55,7 @@ impl frame_system::Config for Test { type AccountId = sp_core::sr25519::Public; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU64<250>; type DbWeight = (); type BlockWeights = (); @@ -70,9 +70,7 @@ impl frame_system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl Config for Test { - type Call = Call; -} +impl Config for Test {} fn test_pub(n: u8) -> sp_core::sr25519::Public { sp_core::sr25519::Public::from_raw([n; 32]) diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index b23342800f8b9..7b71224904378 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -786,14 +786,14 @@ mod tests { type DbWeight = (); type Origin = Origin; type Index = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type BlockNumber = u64; type Hash = sp_core::H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = RuntimeVersion; type PalletInfo = PalletInfo; @@ -809,7 +809,7 @@ mod tests { type Balance = u64; impl pallet_balances::Config for Runtime { type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -823,7 +823,7 @@ mod tests { pub const TransactionByteFee: Balance = 0; } impl pallet_transaction_payment::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; @@ -850,7 +850,7 @@ mod tests { frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, ); - type TestXt = sp_runtime::testing::TestXt; + type TestXt = sp_runtime::testing::TestXt; type TestBlock = Block; type TestUncheckedExtrinsic = TestXt; @@ -889,8 +889,8 @@ mod tests { Some((who, extra(nonce, fee))) } - fn call_transfer(dest: u64, value: u64) -> Call { - Call::Balances(BalancesCall::transfer { dest, value }) + fn call_transfer(dest: u64, value: u64) -> RuntimeCall { + RuntimeCall::Balances(BalancesCall::transfer { dest, value }) } #[test] @@ -1033,7 +1033,7 @@ mod tests { let mut t = new_test_ext(10000); // given: TestXt uses the encoded len as fixed Len: let xt = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); let encoded = xt.encode(); @@ -1056,7 +1056,7 @@ mod tests { for nonce in 0..=num_to_exhaust_block { let xt = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, nonce.into(), 0), ); let res = Executive::apply_extrinsic(xt); @@ -1081,15 +1081,15 @@ mod tests { #[test] fn block_weight_and_size_is_stored_per_tx() { let xt = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); let x1 = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 1, 0), ); let x2 = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 2, 0), ); let len = xt.clone().encode().len() as u32; @@ -1145,8 +1145,8 @@ mod tests { #[test] fn validate_unsigned() { - let valid = TestXt::new(Call::Custom(custom::Call::allowed_unsigned {}), None); - let invalid = TestXt::new(Call::Custom(custom::Call::unallowed_unsigned {}), None); + let valid = TestXt::new(RuntimeCall::Custom(custom::Call::allowed_unsigned {}), None); + let invalid = TestXt::new(RuntimeCall::Custom(custom::Call::unallowed_unsigned {}), None); let mut t = new_test_ext(1); t.execute_with(|| { @@ -1184,7 +1184,7 @@ mod tests { id, &1, 110, lock, ); let xt = TestXt::new( - Call::System(SystemCall::remark { remark: vec![1u8] }), + RuntimeCall::System(SystemCall::remark { remark: vec![1u8] }), sign_extra(1, 0, 0), ); let weight = xt.get_dispatch_info().weight + @@ -1360,7 +1360,7 @@ mod tests { #[test] fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { let xt = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); @@ -1459,7 +1459,7 @@ mod tests { #[test] fn calculating_storage_root_twice_works() { - let call = Call::Custom(custom::Call::calculate_storage_root {}); + let call = RuntimeCall::Custom(custom::Call::calculate_storage_root {}); let xt = TestXt::new(call, sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { @@ -1486,10 +1486,10 @@ mod tests { #[should_panic(expected = "Invalid inherent position for extrinsic at index 1")] fn invalid_inherent_position_fail() { let xt1 = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); - let xt2 = TestXt::new(Call::Custom(custom::Call::inherent_call {}), None); + let xt2 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1514,7 +1514,7 @@ mod tests { #[test] fn valid_inherents_position_works() { - let xt1 = TestXt::new(Call::Custom(custom::Call::inherent_call {}), None); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index b94b7d164f04c..157aa8284f2f1 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -98,7 +98,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// Overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Currency type that this works on. type Currency: ReservableCurrency; diff --git a/frame/gilt/src/mock.rs b/frame/gilt/src/mock.rs index 369b34ba77f44..a9cca0ff22780 100644 --- a/frame/gilt/src/mock.rs +++ b/frame/gilt/src/mock.rs @@ -50,7 +50,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -58,7 +58,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -75,7 +75,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = frame_support::traits::ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -92,7 +92,7 @@ ord_parameter_types! { } impl pallet_gilt::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = ::Balance; type AdminOrigin = frame_system::EnsureSignedBy; diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 1781f0a8e40a2..1fcf5c67150b5 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -87,12 +87,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The event type of this module. - type Event: From - + Into<::Event> - + IsType<::Event>; - - /// The function call. - type Call: From>; + type RuntimeEvent: From + + Into<::RuntimeEvent> + + IsType<::RuntimeEvent>; /// The proof of key ownership, used for validating equivocation reports /// The proof must include the session index and validator count of the diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index d246466cf0db4..5aae751de9ea6 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -82,13 +82,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -103,10 +103,10 @@ impl frame_system::Config for Test { impl frame_system::offchain::SendTransactionTypes for Test where - Call: From, + RuntimeCall: From, { - type OverarchingCall = Call; - type Extrinsic = TestXt; + type OverarchingCall = RuntimeCall; + type Extrinsic = TestXt; } parameter_types! { @@ -116,7 +116,7 @@ parameter_types! { /// Custom `SessionHandler` since we use `TestSessionKeys` as `Keys`. impl pallet_session::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = u64; type ValidatorIdOf = pallet_staking::StashOf; type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; @@ -145,7 +145,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u128; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU128<1>; type AccountStore = System; type WeightInfo = (); @@ -188,7 +188,7 @@ impl pallet_staking::Config for Test { type MaxNominations = ConstU32<16>; type RewardRemainder = (); type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = ::Balance; type Slash = (); @@ -213,7 +213,7 @@ impl pallet_staking::Config for Test { } impl pallet_offences::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; } @@ -224,8 +224,7 @@ parameter_types! { } impl Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; type KeyOwnerProofSystem = Historical; diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 6596f227383f2..7ab5d416eb533 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -32,7 +32,7 @@ use sp_runtime::traits::Bounded; const SEED: u32 = 0; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index d24b17eb86ee0..c4f35a06e830a 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -105,7 +105,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The currency trait. type Currency: ReservableCurrency; diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 4c1ced0a83324..0fb5d4587af16 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -60,12 +60,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -81,7 +81,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -103,7 +103,7 @@ ord_parameter_types! { type EnsureOneOrRoot = EitherOfDiverse, EnsureSignedBy>; type EnsureTwoOrRoot = EitherOfDiverse, EnsureSignedBy>; impl pallet_identity::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type Slashed = (); type BasicDeposit = ConstU64<10>; diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 34c1c70d79f75..342522ff29b19 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -337,7 +337,7 @@ pub mod pallet { type MaxPeerDataEncodingSize: Get; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// A type for retrieving the validators supposed to be online in a session. type ValidatorSet: ValidatorSetWithIdentification; diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 6ea5a16d64f58..a193843a3d661 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -83,7 +83,7 @@ impl pallet_session::historical::SessionManager for TestSessionManager } /// An extrinsic type used for tests. -pub type Extrinsic = TestXt; +pub type Extrinsic = TestXt; type IdentificationTuple = (u64, u64); type Offence = crate::UnresponsivenessOffence; @@ -130,13 +130,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -162,7 +162,7 @@ impl pallet_session::Config for Runtime { type ValidatorId = u64; type ValidatorIdOf = ConvertInto; type Keys = UintAuthorityId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type NextSessionRotation = pallet_session::PeriodicSessions; type WeightInfo = (); } @@ -216,7 +216,7 @@ impl frame_support::traits::EstimateNextSessionRotation for TestNextSession impl Config for Runtime { type AuthorityId = UintAuthorityId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorSet = Historical; type NextSessionRotation = TestNextSessionRotation; type ReportUnresponsiveness = OffenceHandler; @@ -229,9 +229,9 @@ impl Config for Runtime { impl frame_system::offchain::SendTransactionTypes for Runtime where - Call: From, + RuntimeCall: From, { - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; type Extrinsic = Extrinsic; } diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index 6ef7cce7c353b..e6154a634f4a4 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -240,7 +240,8 @@ fn should_generate_heartbeats() { // check stuff about the transaction. let ex: Extrinsic = Decode::decode(&mut &*transaction).unwrap(); let heartbeat = match ex.call { - crate::mock::Call::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => heartbeat, + crate::mock::RuntimeCall::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => + heartbeat, e => panic!("Unexpected call: {:?}", e), }; @@ -355,7 +356,8 @@ fn should_not_send_a_report_if_already_online() { // check stuff about the transaction. let ex: Extrinsic = Decode::decode(&mut &*transaction).unwrap(); let heartbeat = match ex.call { - crate::mock::Call::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => heartbeat, + crate::mock::RuntimeCall::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => + heartbeat, e => panic!("Unexpected call: {:?}", e), }; diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index 49380f18e24db..41893254c3c97 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -68,7 +68,7 @@ pub mod pallet { type Deposit: Get>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index 693296a3b1064..255080f345eee 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -53,7 +53,7 @@ impl frame_system::Config for Test { type BlockLength = (); type DbWeight = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -61,7 +61,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = Indices; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -80,7 +80,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -90,7 +90,7 @@ impl Config for Test { type AccountIndex = u64; type Currency = Balances; type Deposit = ConstU64<1>; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index 02df65a3336bf..505dd1bb98caa 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -96,17 +96,17 @@ pub struct LotteryConfig { } pub trait ValidateCall { - fn validate_call(call: &::Call) -> bool; + fn validate_call(call: &::RuntimeCall) -> bool; } impl ValidateCall for () { - fn validate_call(_: &::Call) -> bool { + fn validate_call(_: &::RuntimeCall) -> bool { false } } impl ValidateCall for Pallet { - fn validate_call(call: &::Call) -> bool { + fn validate_call(call: &::RuntimeCall) -> bool { let valid_calls = CallIndices::::get(); let call_index = match Self::call_to_index(call) { Ok(call_index) => call_index, @@ -134,7 +134,7 @@ pub mod pallet { type PalletId: Get; /// A dispatchable call. - type Call: Parameter + type RuntimeCall: Parameter + Dispatchable + GetDispatchInfo + From>; @@ -146,7 +146,7 @@ pub mod pallet { type Randomness: Randomness; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The manager origin. type ManagerOrigin: EnsureOrigin; @@ -300,7 +300,10 @@ pub mod pallet { T::WeightInfo::buy_ticket() .saturating_add(call.get_dispatch_info().weight) )] - pub fn buy_ticket(origin: OriginFor, call: Box<::Call>) -> DispatchResult { + pub fn buy_ticket( + origin: OriginFor, + call: Box<::RuntimeCall>, + ) -> DispatchResult { let caller = ensure_signed(origin.clone())?; call.clone().dispatch(origin).map_err(|e| e.error)?; @@ -315,7 +318,10 @@ pub mod pallet { /// /// This extrinsic must be called by the Manager origin. #[pallet::weight(T::WeightInfo::set_calls(calls.len() as u32))] - pub fn set_calls(origin: OriginFor, calls: Vec<::Call>) -> DispatchResult { + pub fn set_calls( + origin: OriginFor, + calls: Vec<::RuntimeCall>, + ) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; ensure!(calls.len() <= T::MaxCalls::get() as usize, Error::::TooManyCalls); if calls.is_empty() { @@ -404,7 +410,7 @@ impl Pallet { /// Converts a vector of calls into a vector of call indices. fn calls_to_indices( - calls: &[::Call], + calls: &[::RuntimeCall], ) -> Result, DispatchError> { let mut indices = BoundedVec::::with_bounded_capacity(calls.len()); for c in calls.iter() { @@ -415,7 +421,7 @@ impl Pallet { } /// Convert a call to it's call index by encoding the call and taking the first two bytes. - fn call_to_index(call: &::Call) -> Result { + fn call_to_index(call: &::RuntimeCall) -> Result { let encoded_call = call.encode(); if encoded_call.len() < 2 { return Err(Error::::EncodingFailed.into()) @@ -424,7 +430,7 @@ impl Pallet { } /// Logic for buying a ticket. - fn do_buy_ticket(caller: &T::AccountId, call: &::Call) -> DispatchResult { + fn do_buy_ticket(caller: &T::AccountId, call: &::RuntimeCall) -> DispatchResult { // Check the call is valid lottery let config = Lottery::::get().ok_or(Error::::NotConfigured)?; let block_number = frame_system::Pallet::::block_number(); diff --git a/frame/lottery/src/mock.rs b/frame/lottery/src/mock.rs index 592551fb6b93f..b521b83e7ce2b 100644 --- a/frame/lottery/src/mock.rs +++ b/frame/lottery/src/mock.rs @@ -59,14 +59,14 @@ impl frame_system::Config for Test { type DbWeight = (); type Origin = Origin; type Index = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type BlockNumber = u64; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -84,7 +84,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -97,10 +97,10 @@ parameter_types! { impl Config for Test { type PalletId = LotteryPalletId; - type Call = Call; + type RuntimeCall = RuntimeCall; type Currency = Balances; type Randomness = TestRandomness; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ManagerOrigin = EnsureRoot; type MaxCalls = ConstU32<2>; type ValidateCall = Lottery; diff --git a/frame/lottery/src/tests.rs b/frame/lottery/src/tests.rs index d8dd6e4b7fe6c..ff3111b52db77 100644 --- a/frame/lottery/src/tests.rs +++ b/frame/lottery/src/tests.rs @@ -20,7 +20,8 @@ use super::*; use frame_support::{assert_noop, assert_ok, assert_storage_noop}; use mock::{ - new_test_ext, run_to_block, Balances, BalancesCall, Call, Lottery, Origin, SystemCall, Test, + new_test_ext, run_to_block, Balances, BalancesCall, Lottery, Origin, RuntimeCall, SystemCall, + Test, }; use pallet_balances::Error as BalancesError; use sp_runtime::traits::BadOrigin; @@ -43,8 +44,8 @@ fn basic_end_to_end_works() { let length = 20; let delay = 5; let calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; // Set calls for the lottery @@ -55,7 +56,7 @@ fn basic_end_to_end_works() { assert!(crate::Lottery::::get().is_some()); assert_eq!(Balances::free_balance(&1), 100); - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 2, value: 20 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 20 })); assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); // 20 from the transfer, 10 from buying a ticket assert_eq!(Balances::free_balance(&1), 100 - 20 - 10); @@ -127,17 +128,17 @@ fn set_calls_works() { assert!(!CallIndices::::exists()); let calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; assert_ok!(Lottery::set_calls(Origin::root(), calls)); assert!(CallIndices::::exists()); let too_many_calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), - Call::System(SystemCall::remark { remark: vec![] }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::System(SystemCall::remark { remark: vec![] }), ]; assert_noop!( @@ -155,8 +156,8 @@ fn set_calls_works() { fn call_to_indices_works() { new_test_ext().execute_with(|| { let calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; let indices = Lottery::calls_to_indices(&calls).unwrap().into_inner(); // Only comparing the length since it is otherwise dependant on the API @@ -164,9 +165,9 @@ fn call_to_indices_works() { assert_eq!(indices.len(), calls.len()); let too_many_calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), - Call::System(SystemCall::remark { remark: vec![] }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::System(SystemCall::remark { remark: vec![] }), ]; assert_noop!(Lottery::calls_to_indices(&too_many_calls), Error::::TooManyCalls); }); @@ -202,7 +203,7 @@ fn buy_ticket_works_as_simple_passthrough() { // as a simple passthrough to the real call. new_test_ext().execute_with(|| { // No lottery set up - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 2, value: 20 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 20 })); // This is just a basic transfer then assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); assert_eq!(Balances::free_balance(&1), 100 - 20); @@ -210,8 +211,8 @@ fn buy_ticket_works_as_simple_passthrough() { // Lottery is set up, but too expensive to enter, so `do_buy_ticket` fails. let calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; assert_ok!(Lottery::set_calls(Origin::root(), calls)); @@ -222,24 +223,28 @@ fn buy_ticket_works_as_simple_passthrough() { assert_eq!(TicketsCount::::get(), 0); // If call would fail, the whole thing still fails the same - let fail_call = Box::new(Call::Balances(BalancesCall::transfer { dest: 2, value: 1000 })); + let fail_call = + Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 1000 })); assert_noop!( Lottery::buy_ticket(Origin::signed(1), fail_call), BalancesError::::InsufficientBalance, ); - let bad_origin_call = - Box::new(Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 })); + let bad_origin_call = Box::new(RuntimeCall::Balances(BalancesCall::force_transfer { + source: 0, + dest: 0, + value: 0, + })); assert_noop!(Lottery::buy_ticket(Origin::signed(1), bad_origin_call), BadOrigin,); // User can call other txs, but doesn't get a ticket let remark_call = - Box::new(Call::System(SystemCall::remark { remark: b"hello, world!".to_vec() })); + Box::new(RuntimeCall::System(SystemCall::remark { remark: b"hello, world!".to_vec() })); assert_ok!(Lottery::buy_ticket(Origin::signed(2), remark_call)); assert_eq!(TicketsCount::::get(), 0); let successful_call = - Box::new(Call::Balances(BalancesCall::transfer { dest: 2, value: 1 })); + Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 1 })); assert_ok!(Lottery::buy_ticket(Origin::signed(2), successful_call)); assert_eq!(TicketsCount::::get(), 1); }); @@ -250,13 +255,13 @@ fn buy_ticket_works() { new_test_ext().execute_with(|| { // Set calls for the lottery. let calls = vec![ - Call::System(SystemCall::remark { remark: vec![] }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::System(SystemCall::remark { remark: vec![] }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; assert_ok!(Lottery::set_calls(Origin::root(), calls)); // Can't buy ticket before start - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 2, value: 1 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 1 })); assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); assert_eq!(TicketsCount::::get(), 0); @@ -269,12 +274,13 @@ fn buy_ticket_works() { assert_eq!(TicketsCount::::get(), 1); // Can't buy another of the same ticket (even if call is slightly changed) - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 3, value: 30 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 3, value: 30 })); assert_ok!(Lottery::buy_ticket(Origin::signed(1), call)); assert_eq!(TicketsCount::::get(), 1); // Buy ticket for remark - let call = Box::new(Call::System(SystemCall::remark { remark: b"hello, world!".to_vec() })); + let call = + Box::new(RuntimeCall::System(SystemCall::remark { remark: b"hello, world!".to_vec() })); assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); assert_eq!(TicketsCount::::get(), 2); @@ -296,7 +302,7 @@ fn buy_ticket_works() { #[test] fn do_buy_ticket_already_participating() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); assert_ok!(Lottery::start_lottery(Origin::root(), 1, 10, 10, false)); @@ -311,7 +317,7 @@ fn do_buy_ticket_already_participating() { #[test] fn buy_ticket_already_participating() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); assert_ok!(Lottery::start_lottery(Origin::root(), 1, 10, 10, false)); @@ -331,7 +337,7 @@ fn buy_ticket_already_participating() { #[test] fn buy_ticket_insufficient_balance() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); // Price set to 100. assert_ok!(Lottery::start_lottery(Origin::root(), 100, 10, 10, false)); @@ -346,7 +352,7 @@ fn buy_ticket_insufficient_balance() { #[test] fn do_buy_ticket_insufficient_balance() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); // Price set to 101. assert_ok!(Lottery::start_lottery(Origin::root(), 101, 10, 10, false)); @@ -363,7 +369,7 @@ fn do_buy_ticket_insufficient_balance() { #[test] fn do_buy_ticket_keep_alive() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); // Price set to 100. assert_ok!(Lottery::start_lottery(Origin::root(), 100, 10, 10, false)); @@ -415,7 +421,7 @@ fn choose_ticket_trivial_cases() { #[test] fn choose_account_one_participant() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); assert_ok!(Lottery::start_lottery(Origin::root(), 10, 10, 10, false)); let call = Box::new(calls[0].clone()); diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index b4c9c3b38f1da..a3f79ab2052e9 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -55,7 +55,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Required origin for adding a member (though can always be Root). type AddOrigin: EnsureOrigin; @@ -147,7 +148,7 @@ pub mod pallet { /// One of the members' keys changed. KeyChanged, /// Phantom member, never used. - Dummy { _phantom_data: PhantomData<(T::AccountId, >::Event)> }, + Dummy { _phantom_data: PhantomData<(T::AccountId, >::RuntimeEvent)> }, } #[pallet::error] @@ -546,12 +547,12 @@ mod tests { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -600,7 +601,7 @@ mod tests { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type AddOrigin = EnsureSignedBy; type RemoveOrigin = EnsureSignedBy; type SwapOrigin = EnsureSignedBy; diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index 30dd6da3d3b8d..abaa7b106d539 100644 --- a/frame/merkle-mountain-range/src/mock.rs +++ b/frame/merkle-mountain-range/src/mock.rs @@ -48,7 +48,7 @@ frame_support::construct_runtime!( impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -56,7 +56,7 @@ impl frame_system::Config for Test { type AccountId = sp_core::sr25519::Public; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type BlockWeights = (); diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index dafc421a7b72d..8d0651002305b 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -42,7 +42,7 @@ fn setup_multi( } signatories.sort(); // Must first convert to outer call type. - let call: ::Call = + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![0; z as usize] }.into(); let call_data = OpaqueCall::::from_encoded(call.encode()); Ok((signatories, call_data)) @@ -54,7 +54,7 @@ benchmarks! { let z in 0 .. 10_000; let max_signatories = T::MaxSignatories::get().into(); let (mut signatories, _) = setup_multi::(max_signatories, z)?; - let call: ::Call = frame_system::Call::::remark { + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![0; z as usize] }.into(); let call_hash = call.using_encoded(blake2_256); diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 01904de9a96fa..4593d6dade690 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -99,7 +99,7 @@ pub struct Multisig { approvals: Vec, } -type OpaqueCall = WrapperKeepOpaque<::Call>; +type OpaqueCall = WrapperKeepOpaque<::RuntimeCall>; type CallHash = [u8; 32]; @@ -117,10 +117,10 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The overarching call type. - type Call: Parameter + type RuntimeCall: Parameter + Dispatchable + GetDispatchInfo + From>; @@ -266,7 +266,7 @@ pub mod pallet { pub fn as_multi_threshold_1( origin: OriginFor, other_signatories: Vec, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let max_sigs = T::MaxSignatories::get() as usize; @@ -698,7 +698,7 @@ impl Pallet { fn get_call( hash: &[u8; 32], maybe_known: Option<&OpaqueCall>, - ) -> Option<(::Call, usize)> { + ) -> Option<(::RuntimeCall, usize)> { maybe_known.map_or_else( || { Calls::::get(hash) diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index ddf5197ab734c..7eb9a9c3aae32 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -61,12 +61,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -84,7 +84,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -92,19 +92,19 @@ impl pallet_balances::Config for Test { } pub struct TestBaseCallFilter; -impl Contains for TestBaseCallFilter { - fn contains(c: &Call) -> bool { +impl Contains for TestBaseCallFilter { + fn contains(c: &RuntimeCall) -> bool { match *c { - Call::Balances(_) => true, + RuntimeCall::Balances(_) => true, // Needed for benchmarking - Call::System(frame_system::Call::remark { .. }) => true, + RuntimeCall::System(frame_system::Call::remark { .. }) => true, _ => false, } } } impl Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type DepositBase = ConstU64<1>; type DepositFactor = ConstU64<1>; @@ -130,8 +130,8 @@ fn now() -> Timepoint { Multisig::timepoint() } -fn call_transfer(dest: u64, value: u64) -> Call { - Call::Balances(BalancesCall::transfer { dest, value }) +fn call_transfer(dest: u64, value: u64) -> RuntimeCall { + RuntimeCall::Balances(BalancesCall::transfer { dest, value }) } #[test] @@ -850,7 +850,7 @@ fn multisig_1_of_3_works() { #[test] fn multisig_filters() { new_test_ext().execute_with(|| { - let call = Box::new(Call::System(frame_system::Call::set_code { code: vec![] })); + let call = Box::new(RuntimeCall::System(frame_system::Call::set_code { code: vec![] })); assert_noop!( Multisig::as_multi_threshold_1(Origin::signed(1), vec![2], call.clone()), DispatchError::from(frame_system::Error::::CallFiltered), diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index cf5af649b7843..0ab9a509a568f 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -58,7 +58,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The currency trait. type Currency: ReservableCurrency; @@ -284,12 +284,12 @@ mod tests { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -307,7 +307,7 @@ mod tests { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -318,7 +318,7 @@ mod tests { pub const One: u64 = 1; } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ReservationFee = ConstU64<2>; type Slashed = (); diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 427e71af6e8c4..42f1fcf7b55e6 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -67,7 +67,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The maximum number of well known nodes that are allowed to set #[pallet::constant] diff --git a/frame/node-authorization/src/mock.rs b/frame/node-authorization/src/mock.rs index d959d1b8610f5..448f8cef80e28 100644 --- a/frame/node-authorization/src/mock.rs +++ b/frame/node-authorization/src/mock.rs @@ -56,12 +56,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -82,7 +82,7 @@ ord_parameter_types! { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MaxWellKnownNodes = ConstU32<4>; type MaxPeerIdLength = ConstU32<2>; type AddOrigin = EnsureSignedBy; diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index d239d4f072b80..aad38ee8475d2 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -35,13 +35,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; @@ -69,7 +69,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -96,7 +96,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = (); type SessionsPerEra = (); @@ -123,7 +123,7 @@ parameter_types! { } impl pallet_bags_list::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type BagThresholds = BagThresholds; type ScoreProvider = Staking; @@ -151,7 +151,7 @@ parameter_types! { } impl pallet_nomination_pools::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; type CurrencyBalance = Balance; diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 9e872955669f8..dfe4bf1931068 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1151,7 +1151,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: weights::WeightInfo; diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index f1574b3684aab..13df09c47fa92 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -131,13 +131,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = sp_runtime::traits::IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type DbWeight = (); type BlockLength = (); @@ -161,7 +161,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -189,7 +189,7 @@ parameter_types! { pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); } impl pools::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; type CurrencyBalance = Balance; @@ -329,7 +329,7 @@ pub(crate) fn pool_events_since_last_call() -> Vec> { let events = System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::Pools(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::Pools(inner) = e { Some(inner) } else { None }) .collect::>(); let already_seen = PoolsEvents::get(); PoolsEvents::set(&(events.len() as u32)); @@ -341,7 +341,7 @@ pub(crate) fn balances_events_since_last_call() -> Vec>(); let already_seen = BalancesEvents::get(); BalancesEvents::set(&(events.len() as u32)); diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 362fece3f3daf..bcc735a9cef99 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -4147,7 +4147,7 @@ mod create { Balances::make_free_balance_be(&11, 5 + 20); // Then - let create = Call::Pools(crate::Call::::create { + let create = RuntimeCall::Pools(crate::Call::::create { amount: 20, root: 11, nominator: 11, diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 055ba7b4b3c06..d616ee1ffc180 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -46,13 +46,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; @@ -81,7 +81,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -111,7 +111,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = (); type SessionsPerEra = (); @@ -138,7 +138,7 @@ parameter_types! { } impl pallet_bags_list::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type BagThresholds = BagThresholds; type ScoreProvider = Staking; @@ -165,7 +165,7 @@ parameter_types! { } impl pallet_nomination_pools::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; type CurrencyBalance = Balance; @@ -248,7 +248,7 @@ pub(crate) fn pool_events_since_last_call() -> Vec>(); let already_seen = ObservedEventsPools::get(); ObservedEventsPools::set(events.len()); @@ -259,7 +259,7 @@ pub(crate) fn staking_events_since_last_call() -> Vec>(); let already_seen = ObservedEventsStaking::get(); ObservedEventsStaking::set(events.len()); diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 5d81a71d4c47c..f73dd9caac9c6 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -216,7 +216,7 @@ fn make_offenders_im_online( } #[cfg(test)] -fn check_events::Event>>(expected: I) { +fn check_events::RuntimeEvent>>(expected: I) { let events = System::::events() .into_iter() .map(|frame_system::EventRecord { event, .. }| event) @@ -308,16 +308,16 @@ benchmarks! { let reward_amount = slash_amount.saturating_mul(1 + n) / 2; let reward = reward_amount / r; let slash = |id| core::iter::once( - ::Event::from(StakingEvent::::Slashed(id, BalanceOf::::from(slash_amount))) + ::RuntimeEvent::from(StakingEvent::::Slashed(id, BalanceOf::::from(slash_amount))) ); let balance_slash = |id| core::iter::once( - ::Event::from(pallet_balances::Event::::Slashed{who: id, amount: slash_amount.into()}) + ::RuntimeEvent::from(pallet_balances::Event::::Slashed{who: id, amount: slash_amount.into()}) ); let chill = |id| core::iter::once( - ::Event::from(StakingEvent::::Chilled(id)) + ::RuntimeEvent::from(StakingEvent::::Chilled(id)) ); let balance_deposit = |id, amount: u32| - ::Event::from(pallet_balances::Event::::Deposit{who: id, amount: amount.into()}); + ::RuntimeEvent::from(pallet_balances::Event::::Deposit{who: id, amount: amount.into()}); let mut first = true; let slash_events = raw_offenders.into_iter() .flat_map(|offender| { @@ -339,7 +339,7 @@ benchmarks! { .flat_map(|reporter| vec![ balance_deposit(reporter.clone(), reward).into(), frame_system::Event::::NewAccount { account: reporter.clone() }.into(), - ::Event::from( + ::RuntimeEvent::from( pallet_balances::Event::::Endowed{account: reporter, free_balance: reward.into()} ).into(), ]) @@ -366,7 +366,7 @@ benchmarks! { check_events::( std::iter::empty() .chain(slash_events.into_iter().map(Into::into)) - .chain(std::iter::once(::Event::from( + .chain(std::iter::once(::RuntimeEvent::from( pallet_offences::Event::Offence{ kind: UnresponsivenessOffence::::ID, timeslot: 0_u32.to_le_bytes().to_vec(), diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 6d66f5251c78c..3483f5ec240a5 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -53,13 +53,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; @@ -77,7 +77,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<10>; type AccountStore = System; @@ -128,7 +128,7 @@ impl pallet_session::Config for Test { type ShouldEndSession = pallet_session::PeriodicSessions; type NextSessionRotation = pallet_session::PeriodicSessions; type SessionHandler = TestSessionHandler; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = AccountId; type ValidatorIdOf = pallet_staking::StashOf; type WeightInfo = (); @@ -148,7 +148,7 @@ parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; } -pub type Extrinsic = sp_runtime::testing::TestXt; +pub type Extrinsic = sp_runtime::testing::TestXt; pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { @@ -165,7 +165,7 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = (); type SessionsPerEra = (); @@ -188,7 +188,7 @@ impl pallet_staking::Config for Test { impl pallet_im_online::Config for Test { type AuthorityId = UintAuthorityId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorSet = Historical; type NextSessionRotation = pallet_session::PeriodicSessions; type ReportUnresponsiveness = Offences; @@ -200,23 +200,23 @@ impl pallet_im_online::Config for Test { } impl pallet_offences::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; } impl frame_system::offchain::SendTransactionTypes for Test where - Call: From, + RuntimeCall: From, { type Extrinsic = Extrinsic; - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; } impl crate::Config for Test {} pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Test where diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index ae454d6b06740..7858b02719c4c 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -57,7 +57,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From + IsType<::Event>; + type RuntimeEvent: From + IsType<::RuntimeEvent>; /// Full identification of the validator. type IdentificationTuple: Parameter; /// A handler called for every offence report. diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index bf4daf0c89944..5b07aab5bd85e 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -95,13 +95,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -115,7 +115,7 @@ impl frame_system::Config for Runtime { } impl Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type IdentificationTuple = u64; type OnOffenceHandler = OnOffenceHandler; } diff --git a/frame/offences/src/tests.rs b/frame/offences/src/tests.rs index 49bd2fb5a6923..266e05debf050 100644 --- a/frame/offences/src/tests.rs +++ b/frame/offences/src/tests.rs @@ -21,8 +21,8 @@ use super::*; use crate::mock::{ - new_test_ext, offence_reports, report_id, with_on_offence_fractions, Event, Offence, Offences, - System, KIND, + new_test_ext, offence_reports, report_id, with_on_offence_fractions, Offence, Offences, + RuntimeEvent, System, KIND, }; use frame_system::{EventRecord, Phase}; use sp_runtime::Perbill; @@ -114,7 +114,7 @@ fn should_deposit_event() { System::events(), vec![EventRecord { phase: Phase::Initialization, - event: Event::Offences(crate::Event::Offence { + event: RuntimeEvent::Offences(crate::Event::Offence { kind: KIND, timeslot: time_slot.encode() }), @@ -148,7 +148,7 @@ fn doesnt_deposit_event_for_dups() { System::events(), vec![EventRecord { phase: Phase::Initialization, - event: Event::Offences(crate::Event::Offence { + event: RuntimeEvent::Offences(crate::Event::Offence { kind: KIND, timeslot: time_slot.encode() }), diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 09f6ecd52f9ad..e4616078b0761 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -76,7 +76,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The Weight information for this pallet. type WeightInfo: weights::WeightInfo; diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index 1a1f05cb9c088..75e8767f3e59f 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -58,7 +58,7 @@ impl frame_system::Config for Test { type BlockLength = (); type DbWeight = RocksDbWeight; type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -66,7 +66,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -81,7 +81,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<5>; type AccountStore = System; @@ -102,7 +102,7 @@ ord_parameter_types! { impl Config for Test { type WeightInfo = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureSignedBy; type MaxSize = ConstU32<1024>; diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index c01a8da000c09..f7e440d1f7d6f 100644 --- a/frame/proxy/src/benchmarking.rs +++ b/frame/proxy/src/benchmarking.rs @@ -27,7 +27,7 @@ use sp_runtime::traits::Bounded; const SEED: u32 = 0; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -88,7 +88,7 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); }: _(RawOrigin::Signed(caller), real_lookup, Some(T::ProxyType::default()), Box::new(call)) verify { assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) @@ -105,7 +105,7 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(delegate.clone()).into(), real_lookup.clone(), @@ -126,7 +126,7 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), real_lookup.clone(), @@ -149,7 +149,7 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real.clone()); - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), real_lookup, @@ -172,7 +172,7 @@ benchmarks! { let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real.clone()); add_announcements::(a, Some(caller.clone()), None)?; - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); let call_hash = T::CallHasher::hash_of(&call); }: _(RawOrigin::Signed(caller.clone()), real_lookup, call_hash) verify { diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 2d8dfc238bcd0..7467fb0988dd6 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -110,15 +110,15 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The overarching call type. - type Call: Parameter + type RuntimeCall: Parameter + Dispatchable + GetDispatchInfo + From> + IsSubType> - + IsType<::Call>; + + IsType<::RuntimeCall>; /// The currency mechanism. type Currency: ReservableCurrency; @@ -131,7 +131,7 @@ pub mod pallet { + Member + Ord + PartialOrd - + InstanceFilter<::Call> + + InstanceFilter<::RuntimeCall> + Default + MaxEncodedLen; @@ -208,7 +208,7 @@ pub mod pallet { origin: OriginFor, real: AccountIdLookupOf, force_proxy_type: Option, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResult { let who = ensure_signed(origin)?; let real = T::Lookup::lookup(real)?; @@ -539,7 +539,7 @@ pub mod pallet { delegate: AccountIdLookupOf, real: AccountIdLookupOf, force_proxy_type: Option, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResult { ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; @@ -817,12 +817,12 @@ impl Pallet { fn do_proxy( def: ProxyDefinition, real: T::AccountId, - call: ::Call, + call: ::RuntimeCall, ) { // This is a freshly authenticated new account, the origin restrictions doesn't apply. let mut origin: T::Origin = frame_system::RawOrigin::Signed(real).into(); - origin.add_filter(move |c: &::Call| { - let c = ::Call::from_ref(c); + origin.add_filter(move |c: &::RuntimeCall| { + let c = ::RuntimeCall::from_ref(c); // We make sure the proxy call does access this pallet to change modify proxies. match c.is_sub_type() { // Proxy call cannot add or remove a proxy with more permissions than it already diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index b8d5a55705efa..0025b1510526e 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -65,12 +65,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -88,15 +88,15 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } impl pallet_utility::Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; type WeightInfo = (); } @@ -124,14 +124,14 @@ impl Default for ProxyType { Self::Any } } -impl InstanceFilter for ProxyType { - fn filter(&self, c: &Call) -> bool { +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { match self { ProxyType::Any => true, ProxyType::JustTransfer => { - matches!(c, Call::Balances(pallet_balances::Call::transfer { .. })) + matches!(c, RuntimeCall::Balances(pallet_balances::Call::transfer { .. })) }, - ProxyType::JustUtility => matches!(c, Call::Utility { .. }), + ProxyType::JustUtility => matches!(c, RuntimeCall::Utility { .. }), } } fn is_superset(&self, o: &Self) -> bool { @@ -139,19 +139,19 @@ impl InstanceFilter for ProxyType { } } pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(c: &Call) -> bool { +impl Contains for BaseFilter { + fn contains(c: &RuntimeCall) -> bool { match *c { // Remark is used as a no-op call in the benchmarking - Call::System(SystemCall::remark { .. }) => true, - Call::System(_) => false, + RuntimeCall::System(SystemCall::remark { .. }) => true, + RuntimeCall::System(_) => false, _ => true, } } } impl Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type ProxyType = ProxyType; type ProxyDepositBase = ConstU64<1>; @@ -183,7 +183,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ext } -fn last_events(n: usize) -> Vec { +fn last_events(n: usize) -> Vec { system::Pallet::::events() .into_iter() .rev() @@ -193,12 +193,12 @@ fn last_events(n: usize) -> Vec { .collect() } -fn expect_events(e: Vec) { +fn expect_events(e: Vec) { assert_eq!(last_events(e.len()), e); } -fn call_transfer(dest: u64, value: u64) -> Call { - Call::Balances(BalancesCall::transfer { dest, value }) +fn call_transfer(dest: u64, value: u64) -> RuntimeCall { + RuntimeCall::Balances(BalancesCall::transfer { dest, value }) } #[test] @@ -346,8 +346,10 @@ fn filtering_works() { assert!(Balances::mutate_account(&derivative_id, |a| a.free = 1000).is_ok()); let inner = Box::new(call_transfer(6, 1)); - let call = - Box::new(Call::Utility(UtilityCall::as_derivative { index: 0, call: inner.clone() })); + let call = Box::new(RuntimeCall::Utility(UtilityCall::as_derivative { + index: 0, + call: inner.clone(), + })); assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); @@ -359,7 +361,7 @@ fn filtering_works() { ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - let call = Box::new(Call::Utility(UtilityCall::batch { calls: vec![*inner] })); + let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { calls: vec![*inner] })); assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchCompleted.into(), @@ -376,9 +378,12 @@ fn filtering_works() { ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); - let inner = - Box::new(Call::Proxy(ProxyCall::new_call_variant_add_proxy(5, ProxyType::Any, 0))); - let call = Box::new(Call::Utility(UtilityCall::batch { calls: vec![*inner] })); + let inner = Box::new(RuntimeCall::Proxy(ProxyCall::new_call_variant_add_proxy( + 5, + ProxyType::Any, + 0, + ))); + let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { calls: vec![*inner] })); assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchCompleted.into(), @@ -395,7 +400,7 @@ fn filtering_works() { ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); - let call = Box::new(Call::Proxy(ProxyCall::remove_proxies {})); + let call = Box::new(RuntimeCall::Proxy(ProxyCall::remove_proxies {})); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), @@ -517,15 +522,17 @@ fn proxying_works() { System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 1); - let call = Box::new(Call::System(SystemCall::set_code { code: vec![] })); + let call = Box::new(RuntimeCall::System(SystemCall::set_code { code: vec![] })); assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - let call = - Box::new(Call::Balances(BalancesCall::transfer_keep_alive { dest: 6, value: 1 })); - assert_ok!(Call::Proxy(super::Call::new_call_variant_proxy(1, None, call.clone())) + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_keep_alive { + dest: 6, + value: 1, + })); + assert_ok!(RuntimeCall::Proxy(super::Call::new_call_variant_proxy(1, None, call.clone())) .dispatch(Origin::signed(2))); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), @@ -572,7 +579,7 @@ fn anonymous_works() { System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 1); - let call = Box::new(Call::Proxy(ProxyCall::new_call_variant_kill_anonymous( + let call = Box::new(RuntimeCall::Proxy(ProxyCall::new_call_variant_kill_anonymous( 1, ProxyType::Any, 0, diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index 467cae9728fae..bd86cc0d4029d 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -200,13 +200,13 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/ranked-collective/src/benchmarking.rs b/frame/ranked-collective/src/benchmarking.rs index 611a4ce7334a9..a4d074450e836 100644 --- a/frame/ranked-collective/src/benchmarking.rs +++ b/frame/ranked-collective/src/benchmarking.rs @@ -27,7 +27,7 @@ use frame_system::RawOrigin as SystemOrigin; const SEED: u32 = 0; -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index b8eaac9823634..7f212b3859776 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -363,7 +363,8 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The outer event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The origin required to add or promote a mmember. The success value indicates the /// maximum rank *to which* the promotion may be. diff --git a/frame/ranked-collective/src/tests.rs b/frame/ranked-collective/src/tests.rs index b4173b30b0c2e..25413b490483c 100644 --- a/frame/ranked-collective/src/tests.rs +++ b/frame/ranked-collective/src/tests.rs @@ -61,13 +61,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -171,7 +171,7 @@ impl Polling> for TestPolls { impl Config for Test { type WeightInfo = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PromoteOrigin = EitherOf< // Root can promote arbitrarily. frame_system::EnsureRootWithSuccess>, diff --git a/frame/recovery/src/benchmarking.rs b/frame/recovery/src/benchmarking.rs index 56d5df22d49c5..870543d9bd290 100644 --- a/frame/recovery/src/benchmarking.rs +++ b/frame/recovery/src/benchmarking.rs @@ -28,7 +28,7 @@ use sp_runtime::traits::Bounded; const SEED: u32 = 0; const DEFAULT_DELAY: u32 = 0; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -107,7 +107,7 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); let recovered_account: T::AccountId = account("recovered_account", 0, SEED); let recovered_account_lookup = T::Lookup::unlookup(recovered_account.clone()); - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::insert(&caller, &recovered_account); }: _( diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index 45260b577f700..dd9e7208320c4 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -226,13 +226,13 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// The overarching call type. - type Call: Parameter + type RuntimeCall: Parameter + Dispatchable + GetDispatchInfo + From>; @@ -384,7 +384,7 @@ pub mod pallet { pub fn as_recovered( origin: OriginFor, account: AccountIdLookupOf, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResult { let who = ensure_signed(origin)?; let account = T::Lookup::lookup(account)?; diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 5dc49fff09b32..6496ceb253b77 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -56,7 +56,7 @@ impl frame_system::Config for Test { type BlockLength = (); type DbWeight = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -64,7 +64,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -87,7 +87,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u128; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); @@ -102,9 +102,9 @@ parameter_types! { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); - type Call = Call; + type RuntimeCall = RuntimeCall; type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; diff --git a/frame/recovery/src/tests.rs b/frame/recovery/src/tests.rs index a900a5b6bfa2a..a3f19e5a61bc8 100644 --- a/frame/recovery/src/tests.rs +++ b/frame/recovery/src/tests.rs @@ -20,8 +20,8 @@ use super::*; use frame_support::{assert_noop, assert_ok, bounded_vec, traits::Currency}; use mock::{ - new_test_ext, run_to_block, Balances, BalancesCall, Call, MaxFriends, Origin, Recovery, - RecoveryCall, Test, + new_test_ext, run_to_block, Balances, BalancesCall, MaxFriends, Origin, Recovery, RecoveryCall, + RuntimeCall, Test, }; use sp_runtime::traits::BadOrigin; @@ -45,7 +45,7 @@ fn set_recovered_works() { // Root can set a recovered account though assert_ok!(Recovery::set_recovered(Origin::root(), 5, 1)); // Account 1 should now be able to make a call through account 5 - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 1, value: 100 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 1, value: 100 })); assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); // Account 1 has successfully drained the funds from account 5 assert_eq!(Balances::free_balance(1), 200); @@ -77,15 +77,15 @@ fn recovery_life_cycle_works() { assert_ok!(Recovery::claim_recovery(Origin::signed(1), 5)); // Account 1 can use account 5 to close the active recovery process, claiming the deposited // funds used to initiate the recovery process into account 5. - let call = Box::new(Call::Recovery(RecoveryCall::close_recovery { rescuer: 1 })); + let call = Box::new(RuntimeCall::Recovery(RecoveryCall::close_recovery { rescuer: 1 })); assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); // Account 1 can then use account 5 to remove the recovery configuration, claiming the // deposited funds used to create the recovery configuration into account 5. - let call = Box::new(Call::Recovery(RecoveryCall::remove_recovery {})); + let call = Box::new(RuntimeCall::Recovery(RecoveryCall::remove_recovery {})); assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); // Account 1 should now be able to make a call through account 5 to get all of their funds assert_eq!(Balances::free_balance(5), 110); - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 1, value: 110 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 1, value: 110 })); assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); // All funds have been fully recovered! assert_eq!(Balances::free_balance(1), 200); diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 4a64a9aa03b77..2116d56f4647b 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -32,7 +32,7 @@ use sp_runtime::traits::{Bounded, Hash}; const SEED: u32 = 0; #[allow(dead_code)] -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index e9e14e1d4a96a..92e5ecf5e539b 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -123,8 +123,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + Sized { // System level stuff. - type Call: Parameter + Dispatchable + From>; - type Event: From> + IsType<::Event>; + type RuntimeCall: Parameter + Dispatchable + From>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// The Scheduler. diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 698bea8cc9f67..e046b29898e7b 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -55,9 +55,9 @@ frame_support::construct_runtime!( // Test that a fitlered call can be dispatched. pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, &Call::Balances(pallet_balances::Call::set_balance { .. })) +impl Contains for BaseFilter { + fn contains(call: &RuntimeCall) -> bool { + !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::set_balance { .. })) } } @@ -74,13 +74,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -93,7 +93,7 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } impl pallet_preimage::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; type ManagerOrigin = EnsureRoot; @@ -102,10 +102,10 @@ impl pallet_preimage::Config for Test { type ByteDeposit = (); } impl pallet_scheduler::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Origin = Origin; type PalletsOrigin = OriginCaller; - type Call = Call; + type RuntimeCall = RuntimeCall; type MaximumWeight = MaxWeight; type ScheduleOrigin = EnsureRoot; type MaxScheduledPerBlock = ConstU32<100>; @@ -119,7 +119,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type MaxLocks = ConstU32<10>; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -213,8 +213,8 @@ impl TracksInfo for TestTracksInfo { impl Config for Test { type WeightInfo = (); - type Call = Call; - type Event = Event; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type Scheduler = Scheduler; type Currency = pallet_balances::Pallet; type SubmitOrigin = frame_system::EnsureSigned; @@ -297,12 +297,16 @@ impl VoteTally for Tally { } pub fn set_balance_proposal(value: u64) -> Vec { - Call::Balances(pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 }) - .encode() + RuntimeCall::Balances(pallet_balances::Call::set_balance { + who: 42, + new_free: value, + new_reserved: 0, + }) + .encode() } pub fn set_balance_proposal_hash(value: u64) -> H256 { - let c = Call::Balances(pallet_balances::Call::set_balance { + let c = RuntimeCall::Balances(pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0, diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index d5435daf185bd..69cd62f79159a 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -500,7 +500,7 @@ fn kill_errors_works() { #[test] fn set_balance_proposal_is_correctly_filtered_out() { for i in 0..10 { - let call = crate::mock::Call::decode(&mut &set_balance_proposal(i)[..]).unwrap(); + let call = crate::mock::RuntimeCall::decode(&mut &set_balance_proposal(i)[..]).unwrap(); assert!(!::BaseCallFilter::contains(&call)); } } diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 3eba783246e10..984bd0642d959 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -30,7 +30,7 @@ pub type BalanceOf = pub type NegativeImbalanceOf = <>::Currency as Currency< ::AccountId, >>::NegativeImbalance; -pub type CallOf = >::Call; +pub type CallOf = >::RuntimeCall; pub type VotesOf = >::Votes; pub type TallyOf = >::Tally; pub type PalletsOriginOf = <::Origin as OriginTrait>::PalletsOrigin; diff --git a/frame/remark/src/benchmarking.rs b/frame/remark/src/benchmarking.rs index d30a8aa5df07d..c0db8d5d3d59b 100644 --- a/frame/remark/src/benchmarking.rs +++ b/frame/remark/src/benchmarking.rs @@ -27,9 +27,9 @@ use sp_std::*; #[cfg(test)] use crate::Pallet as Remark; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { let events = System::::events(); - let system_event: ::Event = generic_event.into(); + let system_event: ::RuntimeEvent = generic_event.into(); let EventRecord { event, .. } = &events[events.len() - 1]; assert_eq!(event, &system_event); } diff --git a/frame/remark/src/lib.rs b/frame/remark/src/lib.rs index c69f95907019f..b61c79f7f273d 100644 --- a/frame/remark/src/lib.rs +++ b/frame/remark/src/lib.rs @@ -43,7 +43,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } diff --git a/frame/remark/src/mock.rs b/frame/remark/src/mock.rs index 67a0399e9c386..6ce7115345e57 100644 --- a/frame/remark/src/mock.rs +++ b/frame/remark/src/mock.rs @@ -46,7 +46,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -54,7 +54,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -69,7 +69,7 @@ impl frame_system::Config for Test { } impl pallet_remark::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } diff --git a/frame/remark/src/tests.rs b/frame/remark/src/tests.rs index 580b64cc64997..2278e3817b48a 100644 --- a/frame/remark/src/tests.rs +++ b/frame/remark/src/tests.rs @@ -31,7 +31,7 @@ fn generates_event() { assert_ok!(Remark::::store(RawOrigin::Signed(caller).into(), data.clone(),)); let events = System::events(); // this one we create as we expect it - let system_event: ::Event = Event::Stored { + let system_event: ::RuntimeEvent = Event::Stored { content_hash: sp_io::hashing::blake2_256(&data).into(), sender: caller, } diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index a8e36b72814b7..fbd59555b5ebc 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -77,9 +77,9 @@ fn fill_schedule( Ok(()) } -fn call_and_hash(i: u32) -> (::Call, T::Hash) { +fn call_and_hash(i: u32) -> (::RuntimeCall, T::Hash) { // Essentially a no-op call. - let call: ::Call = frame_system::Call::remark { remark: i.encode() }.into(); + let call: ::RuntimeCall = frame_system::Call::remark { remark: i.encode() }.into(); let hash = T::Hashing::hash_of(&call); (call, hash) } diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 7746b7d0123f4..39dbac17cedd2 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -82,7 +82,8 @@ pub type PeriodicIndex = u32; /// The location of a scheduled task that can be used to remove it. pub type TaskAddress = (BlockNumber, u32); -pub type CallOrHashOf = MaybeHashed<::Call, ::Hash>; +pub type CallOrHashOf = + MaybeHashed<::RuntimeCall, ::Hash>; #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] #[derive(Clone, RuntimeDebug, Encode, Decode)] @@ -113,7 +114,7 @@ pub struct ScheduledV3 { use crate::ScheduledV3 as ScheduledV2; pub type ScheduledV2Of = ScheduledV3< - ::Call, + ::RuntimeCall, ::BlockNumber, ::PalletsOrigin, ::AccountId, @@ -198,7 +199,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The aggregated origin which the dispatch will take. type Origin: OriginTrait @@ -209,7 +210,7 @@ pub mod pallet { type PalletsOrigin: From> + Codec + Clone + Eq + TypeInfo; /// The aggregated call type. - type Call: Parameter + type RuntimeCall: Parameter + Dispatchable::Origin, PostInfo = PostDispatchInfo> + GetDispatchInfo + From>; @@ -543,27 +544,28 @@ impl Pallet { pub fn migrate_v1_to_v3() -> Weight { let mut weight = T::DbWeight::get().reads_writes(1, 1); - Agenda::::translate::::Call, T::BlockNumber>>>, _>( - |_, agenda| { - Some( - agenda - .into_iter() - .map(|schedule| { - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - - schedule.map(|schedule| ScheduledV3 { - maybe_id: schedule.maybe_id, - priority: schedule.priority, - call: schedule.call.into(), - maybe_periodic: schedule.maybe_periodic, - origin: system::RawOrigin::Root.into(), - _phantom: Default::default(), - }) + Agenda::::translate::< + Vec::RuntimeCall, T::BlockNumber>>>, + _, + >(|_, agenda| { + Some( + agenda + .into_iter() + .map(|schedule| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + schedule.map(|schedule| ScheduledV3 { + maybe_id: schedule.maybe_id, + priority: schedule.priority, + call: schedule.call.into(), + maybe_periodic: schedule.maybe_periodic, + origin: system::RawOrigin::Root.into(), + _phantom: Default::default(), }) - .collect::>(), - ) - }, - ); + }) + .collect::>(), + ) + }); #[allow(deprecated)] frame_support::storage::migration::remove_storage_prefix( @@ -859,7 +861,7 @@ impl Pallet { } } -impl schedule::v2::Anon::Call, T::PalletsOrigin> +impl schedule::v2::Anon::RuntimeCall, T::PalletsOrigin> for Pallet { type Address = TaskAddress; @@ -891,7 +893,7 @@ impl schedule::v2::Anon::Call, T::Palle } } -impl schedule::v2::Named::Call, T::PalletsOrigin> +impl schedule::v2::Named::RuntimeCall, T::PalletsOrigin> for Pallet { type Address = TaskAddress; diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 1639c9a046142..6460d0f4c1cd1 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -58,7 +58,7 @@ pub mod logger { #[pallet::config] pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::event] @@ -110,9 +110,9 @@ frame_support::construct_runtime!( // Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, Call::Logger(LoggerCall::log { .. })) +impl Contains for BaseFilter { + fn contains(call: &RuntimeCall) -> bool { + !matches!(call, RuntimeCall::Logger(LoggerCall::log { .. })) } } @@ -126,7 +126,7 @@ impl system::Config for Test { type BlockLength = (); type DbWeight = RocksDbWeight; type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -134,7 +134,7 @@ impl system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -147,7 +147,7 @@ impl system::Config for Test { type MaxConsumers = ConstU32<16>; } impl logger::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; @@ -158,7 +158,7 @@ ord_parameter_types! { } impl pallet_preimage::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = (); type ManagerOrigin = EnsureRoot; @@ -168,10 +168,10 @@ impl pallet_preimage::Config for Test { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Origin = Origin; type PalletsOrigin = OriginCaller; - type Call = Call; + type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EitherOfDiverse, EnsureSignedBy>; type MaxScheduledPerBlock = ConstU32<10>; diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 999a810d3b7c1..f1168e6e9d26f 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -18,7 +18,9 @@ //! # Scheduler tests. use super::*; -use crate::mock::{logger, new_test_ext, root, run_to_block, Call, LoggerCall, Scheduler, Test, *}; +use crate::mock::{ + logger, new_test_ext, root, run_to_block, LoggerCall, RuntimeCall, Scheduler, Test, *, +}; use frame_support::{ assert_err, assert_noop, assert_ok, traits::{Contains, GetStorageVersion, OnInitialize, PreimageProvider}, @@ -30,7 +32,8 @@ use substrate_test_utils::assert_eq_uvec; #[test] fn basic_scheduling_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into())); run_to_block(3); @@ -45,7 +48,8 @@ fn basic_scheduling_works() { #[test] fn scheduling_with_preimages_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); let hash = ::Hashing::hash_of(&call); let hashed = MaybeHashed::Hash(hash); assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); @@ -65,7 +69,8 @@ fn scheduling_with_preimages_works() { #[test] fn scheduling_with_preimage_postpones_correctly() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); let hash = ::Hashing::hash_of(&call); let hashed = MaybeHashed::Hash(hash); @@ -98,7 +103,8 @@ fn scheduling_with_preimage_postpones_correctly() { fn schedule_after_works() { new_test_ext().execute_with(|| { run_to_block(2); - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call.into())); @@ -115,7 +121,8 @@ fn schedule_after_works() { fn schedule_after_zero_works() { new_test_ext().execute_with(|| { run_to_block(2); - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call.into())); // Will trigger on the next block. @@ -135,7 +142,8 @@ fn periodic_scheduling_works() { Some((3, 3)), 127, root(), - Call::Logger(logger::Call::log { i: 42, weight: Weight::from_ref_time(1000) }).into() + RuntimeCall::Logger(logger::Call::log { i: 42, weight: Weight::from_ref_time(1000) }) + .into() )); run_to_block(3); assert!(logger::log().is_empty()); @@ -157,7 +165,8 @@ fn periodic_scheduling_works() { #[test] fn reschedule_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into()).unwrap(), @@ -188,7 +197,8 @@ fn reschedule_works() { #[test] fn reschedule_named_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule_named( @@ -230,7 +240,8 @@ fn reschedule_named_works() { #[test] fn reschedule_named_perodic_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule_named( @@ -292,7 +303,8 @@ fn cancel_named_scheduling_works_with_normal_cancel() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) + .into(), ) .unwrap(); let i = Scheduler::do_schedule( @@ -300,7 +312,8 @@ fn cancel_named_scheduling_works_with_normal_cancel() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) + .into(), ) .unwrap(); run_to_block(3); @@ -322,7 +335,8 @@ fn cancel_named_periodic_scheduling_works() { Some((3, 3)), 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) + .into(), ) .unwrap(); // same id results in error. @@ -332,7 +346,8 @@ fn cancel_named_periodic_scheduling_works() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) + .into(), ) .is_err()); // different id is ok. @@ -342,7 +357,8 @@ fn cancel_named_periodic_scheduling_works() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) + .into(), ) .unwrap(); run_to_block(3); @@ -364,16 +380,22 @@ fn scheduler_respects_weight_limits() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: MaximumSchedulerWeight::get() / 2 + }) + .into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: MaximumSchedulerWeight::get() / 2 + }) + .into(), )); // 69 and 42 do not fit together run_to_block(4); @@ -391,16 +413,22 @@ fn scheduler_respects_hard_deadlines_more() { None, 0, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: MaximumSchedulerWeight::get() / 2 + }) + .into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 0, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: MaximumSchedulerWeight::get() / 2 + }) + .into(), )); // With base weights, 69 and 42 should not fit together, but do because of hard // deadlines @@ -417,16 +445,22 @@ fn scheduler_respects_priority_ordering() { None, 1, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: MaximumSchedulerWeight::get() / 2 + }) + .into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 0, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: MaximumSchedulerWeight::get() / 2 + }) + .into(), )); run_to_block(4); assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); @@ -444,21 +478,23 @@ fn scheduler_respects_priority_ordering_with_soft_deadlines() { None, 255, root(), - Call::Logger(LoggerCall::log { i: 42, weight: max_weight / 2 - item_weight }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 2 - item_weight }) + .into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: max_weight / 2 - item_weight }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 2 - item_weight }) + .into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 126, root(), - Call::Logger(LoggerCall::log { + RuntimeCall::Logger(LoggerCall::log { i: 2600, weight: max_weight / 2 - item_weight + Weight::from_ref_time(1) }) @@ -487,8 +523,11 @@ fn on_initialize_weight_is_correct() { None, 255, root(), - Call::Logger(LoggerCall::log { i: 3, weight: call_weight + Weight::from_ref_time(1) }) - .into(), + RuntimeCall::Logger(LoggerCall::log { + i: 3, + weight: call_weight + Weight::from_ref_time(1) + }) + .into(), )); // Anon Periodic assert_ok!(Scheduler::do_schedule( @@ -496,8 +535,11 @@ fn on_initialize_weight_is_correct() { Some((1000, 3)), 128, root(), - Call::Logger(LoggerCall::log { i: 42, weight: call_weight + Weight::from_ref_time(2) }) - .into(), + RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: call_weight + Weight::from_ref_time(2) + }) + .into(), )); // Anon assert_ok!(Scheduler::do_schedule( @@ -505,8 +547,11 @@ fn on_initialize_weight_is_correct() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: call_weight + Weight::from_ref_time(3) }) - .into(), + RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: call_weight + Weight::from_ref_time(3) + }) + .into(), )); // Named Periodic assert_ok!(Scheduler::do_schedule_named( @@ -515,7 +560,7 @@ fn on_initialize_weight_is_correct() { Some((1000, 3)), 126, root(), - Call::Logger(LoggerCall::log { + RuntimeCall::Logger(LoggerCall::log { i: 2600, weight: call_weight + Weight::from_ref_time(4) }) @@ -567,10 +612,12 @@ fn on_initialize_weight_is_correct() { fn root_calls_works() { new_test_ext().execute_with(|| { let call = Box::new( - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) + .into(), ); let call2 = Box::new( - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) + .into(), ); assert_ok!(Scheduler::schedule_named(Origin::root(), 1u32.encode(), 4, None, 127, call,)); assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); @@ -592,15 +639,17 @@ fn fails_to_schedule_task_in_the_past() { run_to_block(3); let call1 = Box::new( - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) + .into(), ); let call2 = Box::new( - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) + .into(), ); let call3 = Box::new( - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) + .into(), ); - assert_err!( Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call1), Error::::TargetBlockNumberInPast, @@ -622,10 +671,12 @@ fn fails_to_schedule_task_in_the_past() { fn should_use_orign() { new_test_ext().execute_with(|| { let call = Box::new( - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) + .into(), ); let call2 = Box::new( - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) + .into(), ); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), @@ -652,10 +703,12 @@ fn should_use_orign() { fn should_check_orign() { new_test_ext().execute_with(|| { let call = Box::new( - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) + .into(), ); let call2 = Box::new( - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) + .into(), ); assert_noop!( Scheduler::schedule_named( @@ -679,14 +732,14 @@ fn should_check_orign() { fn should_check_orign_for_cancel() { new_test_ext().execute_with(|| { let call = Box::new( - Call::Logger(LoggerCall::log_without_filter { + RuntimeCall::Logger(LoggerCall::log_without_filter { i: 69, weight: Weight::from_ref_time(1000), }) .into(), ); let call2 = Box::new( - Call::Logger(LoggerCall::log_without_filter { + RuntimeCall::Logger(LoggerCall::log_without_filter { i: 42, weight: Weight::from_ref_time(1000), }) @@ -735,7 +788,7 @@ fn migration_to_v3_works() { Some(ScheduledV1 { maybe_id: None, priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100), }), @@ -745,7 +798,7 @@ fn migration_to_v3_works() { Some(ScheduledV1 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000), }), @@ -766,7 +819,7 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: None, priority: 10, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) }) @@ -779,7 +832,7 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) @@ -796,7 +849,7 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: None, priority: 11, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) }) @@ -809,7 +862,7 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) @@ -826,7 +879,7 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: None, priority: 12, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) }) @@ -839,7 +892,7 @@ fn migration_to_v3_works() { Some(ScheduledV3Of:: { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) @@ -866,7 +919,7 @@ fn test_migrate_origin() { Some(Scheduled { maybe_id: None, priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100), }) @@ -880,7 +933,7 @@ fn test_migrate_origin() { maybe_id: Some(b"test".to_vec()), priority: 123, origin: 2u32, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000), }) @@ -913,7 +966,7 @@ fn test_migrate_origin() { Some(ScheduledV2::, u64, OriginCaller, u64> { maybe_id: None, priority: 10, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) }) @@ -926,7 +979,7 @@ fn test_migrate_origin() { Some(ScheduledV2 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) @@ -943,7 +996,7 @@ fn test_migrate_origin() { Some(ScheduledV2 { maybe_id: None, priority: 11, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) }) @@ -956,7 +1009,7 @@ fn test_migrate_origin() { Some(ScheduledV2 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) @@ -973,7 +1026,7 @@ fn test_migrate_origin() { Some(ScheduledV2 { maybe_id: None, priority: 12, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) }) @@ -986,7 +1039,7 @@ fn test_migrate_origin() { Some(ScheduledV2 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index 8d4c4715096b7..c9ba30df80b8b 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -159,7 +159,8 @@ pub mod pallet { + MaxEncodedLen; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; // The deposit which is reserved from candidates if they want to // start a candidacy. The deposit gets returned when the candidacy is diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index 74f084673e4c2..20fa47baf639f 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -65,12 +65,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -88,7 +88,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -125,7 +125,7 @@ impl InitializeMembers for TestChangeMembers { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type KickOrigin = EnsureSignedBy; type MembershipInitialized = TestChangeMembers; type MembershipChanged = TestChangeMembers; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 2181493f72947..01be3605601f4 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -55,13 +55,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; @@ -79,7 +79,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<10>; type AccountStore = System; @@ -125,7 +125,7 @@ impl pallet_session::Config for Test { type ShouldEndSession = pallet_session::PeriodicSessions<(), ()>; type NextSessionRotation = pallet_session::PeriodicSessions<(), ()>; type SessionHandler = TestSessionHandler; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = AccountId; type ValidatorIdOf = pallet_staking::StashOf; type WeightInfo = (); @@ -159,7 +159,7 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = (); type SessionsPerEra = (); diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 34c560984661d..7b97a20860175 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -379,7 +379,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From + IsType<::Event>; + type RuntimeEvent: From + IsType<::RuntimeEvent>; /// A stable ID for a validator. type ValidatorId: Member diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index c1858d0bff774..f6d9e65c1e0b0 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -251,13 +251,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -299,7 +299,7 @@ impl Config for Test { type ValidatorId = u64; type ValidatorIdOf = TestValidatorIdOf; type Keys = MockSessionKeys; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type NextSessionRotation = (); type WeightInfo = (); } diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 9717486644761..122dedabbcf0d 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -378,7 +378,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The societies's pallet id #[pallet::constant] diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index ed668e79269fd..1d9eebdda65ce 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -67,12 +67,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u128; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -90,7 +90,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -98,7 +98,7 @@ impl pallet_balances::Config for Test { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = pallet_balances::Pallet; type Randomness = TestRandomness; type CandidateDeposit = ConstU64<25>; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index cdad11589f743..b8f6254d9a8e8 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -134,13 +134,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -157,7 +157,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -174,7 +174,7 @@ impl pallet_session::Config for Test { type Keys = SessionKeys; type ShouldEndSession = pallet_session::PeriodicSessions; type SessionHandler = (OtherSessionHandler,); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = AccountId; type ValidatorIdOf = crate::StashOf; type NextSessionRotation = pallet_session::PeriodicSessions; @@ -241,7 +241,7 @@ parameter_types! { } impl pallet_bags_list::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type ScoreProvider = Staking; type BagThresholds = BagThresholds; @@ -281,7 +281,7 @@ impl crate::pallet::pallet::Config for Test { type UnixTime = Timestamp; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = RewardRemainderMock; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = MockReward; type SessionsPerEra = SessionsPerEra; @@ -304,7 +304,7 @@ impl crate::pallet::pallet::Config for Test { } pub(crate) type StakingCall = crate::Call; -pub(crate) type TestRuntimeCall = ::Call; +pub(crate) type TestCall = ::RuntimeCall; pub struct ExtBuilder { nominate: bool, @@ -871,7 +871,7 @@ pub(crate) fn staking_events() -> Vec> { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::Staking(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::Staking(inner) = e { Some(inner) } else { None }) .collect() } @@ -882,7 +882,7 @@ parameter_types! { pub(crate) fn staking_events_since_last_call() -> Vec> { let all: Vec<_> = System::events() .into_iter() - .filter_map(|r| if let Event::Staking(inner) = r.event { Some(inner) } else { None }) + .filter_map(|r| if let RuntimeEvent::Staking(inner) = r.event { Some(inner) } else { None }) .collect(); let seen = StakingEventsIndex::get(); StakingEventsIndex::set(all.len()); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index f651cc06b1cb0..1b38f236fc6f3 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -129,7 +129,7 @@ pub mod pallet { type RewardRemainder: OnUnbalanced>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Handler for the unbalanced reduction when slashing a staker. type Slash: OnUnbalanced>; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 969ff8e4e2881..9807cffd43909 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3779,8 +3779,7 @@ fn payout_stakers_handles_weight_refund() { start_active_era(2); // Collect payouts when there are no nominators - let call = - TestRuntimeCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 1 }); + let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 1 }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(20)); assert_ok!(result); @@ -3793,8 +3792,7 @@ fn payout_stakers_handles_weight_refund() { start_active_era(3); // Collect payouts for an era where the validator did not receive any points. - let call = - TestRuntimeCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 2 }); + let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 2 }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(20)); assert_ok!(result); @@ -3807,8 +3805,7 @@ fn payout_stakers_handles_weight_refund() { start_active_era(4); // Collect payouts when the validator has `half_max_nom_rewarded` nominators. - let call = - TestRuntimeCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 3 }); + let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 3 }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(20)); assert_ok!(result); @@ -3831,16 +3828,14 @@ fn payout_stakers_handles_weight_refund() { start_active_era(6); // Collect payouts when the validator had `half_max_nom_rewarded` nominators. - let call = - TestRuntimeCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); + let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), max_nom_rewarded_weight); // Try and collect payouts for an era that has already been collected. - let call = - TestRuntimeCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); + let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(20)); assert!(result.is_err()); diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index e29115382819a..8c73f99be3aea 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -452,7 +452,7 @@ pub mod pallet { type SignedFilter: EnsureOrigin; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The currency provider type. type Currency: Currency; @@ -964,7 +964,7 @@ mod benchmarks { ); frame_system::Pallet::::assert_last_event( - ::Event::from(crate::Event::Slashed { + ::RuntimeEvent::from(crate::Event::Slashed { who: caller.clone(), amount: T::SignedDepositBase::get() .saturating_add(T::SignedDepositPerItem::get().saturating_mul(1u32.into())), @@ -1085,7 +1085,7 @@ mod mock { type BlockWeights = (); type BlockLength = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u32; type Hash = H256; @@ -1093,7 +1093,7 @@ mod mock { type AccountId = u64; type Lookup = IdentityLookup; type Header = sp_runtime::generic::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type DbWeight = (); type Version = (); @@ -1115,7 +1115,7 @@ mod mock { impl pallet_balances::Config for Test { type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -1153,7 +1153,7 @@ mod mock { } impl pallet_state_trie_migration::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ControlOrigin = EnsureRoot; type Currency = Balances; type MaxKeyLen = MigrationMaxKeyLen; diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index bde69f11106dc..96cd2d1615449 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -115,10 +115,12 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// A sudo-able call. - type Call: Parameter + UnfilteredDispatchable + GetDispatchInfo; + type RuntimeCall: Parameter + + UnfilteredDispatchable + + GetDispatchInfo; } #[pallet::pallet] @@ -143,7 +145,7 @@ pub mod pallet { })] pub fn sudo( origin: OriginFor, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; @@ -168,7 +170,7 @@ pub mod pallet { #[pallet::weight((*_weight, call.get_dispatch_info().class))] pub fn sudo_unchecked_weight( origin: OriginFor, - call: Box<::Call>, + call: Box<::RuntimeCall>, _weight: Weight, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. @@ -230,7 +232,7 @@ pub mod pallet { pub fn sudo_as( origin: OriginFor, who: AccountIdLookupOf, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index c895eaf830136..67c221b234de1 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -40,7 +40,7 @@ pub mod logger { #[pallet::config] pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -114,8 +114,8 @@ parameter_types! { } pub struct BlockEverything; -impl Contains for BlockEverything { - fn contains(_: &Call) -> bool { +impl Contains for BlockEverything { + fn contains(_: &RuntimeCall) -> bool { false } } @@ -126,7 +126,7 @@ impl frame_system::Config for Test { type BlockLength = (); type DbWeight = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -134,7 +134,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -149,13 +149,13 @@ impl frame_system::Config for Test { // Implement the logger module's `Config` on the Test runtime. impl logger::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } // Implement the sudo module's `Config` on the Test runtime. impl Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; } // New types for dispatchable functions. diff --git a/frame/sudo/src/tests.rs b/frame/sudo/src/tests.rs index 0508772cc88ec..fbf4063c992e4 100644 --- a/frame/sudo/src/tests.rs +++ b/frame/sudo/src/tests.rs @@ -20,8 +20,8 @@ use super::*; use frame_support::{assert_noop, assert_ok, weights::Weight}; use mock::{ - new_test_ext, Call, Event as TestEvent, Logger, LoggerCall, Origin, Sudo, SudoCall, System, - Test, + new_test_ext, Logger, LoggerCall, Origin, RuntimeCall, RuntimeEvent as TestEvent, Sudo, + SudoCall, System, Test, }; #[test] @@ -39,7 +39,7 @@ fn sudo_basics() { // Configure a default test environment and set the root `key` to 1. new_test_ext(1).execute_with(|| { // A privileged function should work when `sudo` is passed the root `key` as `origin`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1_000), })); @@ -47,7 +47,7 @@ fn sudo_basics() { assert_eq!(Logger::i32_log(), vec![42i32]); // A privileged function should not work when `sudo` is passed a non-root `key` as `origin`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1_000), })); @@ -62,7 +62,7 @@ fn sudo_emits_events_correctly() { System::set_block_number(1); // Should emit event to indicate success when called with the root `key` and `call` is `Ok`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1), })); @@ -75,7 +75,7 @@ fn sudo_emits_events_correctly() { fn sudo_unchecked_weight_basics() { new_test_ext(1).execute_with(|| { // A privileged function should work when `sudo` is passed the root `key` as origin. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1_000), })); @@ -87,7 +87,7 @@ fn sudo_unchecked_weight_basics() { assert_eq!(Logger::i32_log(), vec![42i32]); // A privileged function should not work when called with a non-root `key`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1_000), })); @@ -99,7 +99,7 @@ fn sudo_unchecked_weight_basics() { assert_eq!(Logger::i32_log(), vec![42i32]); // Controls the dispatched weight. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1), })); @@ -117,7 +117,7 @@ fn sudo_unchecked_weight_emits_events_correctly() { System::set_block_number(1); // Should emit event to indicate success when called with the root `key` and `call` is `Ok`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1), })); @@ -164,7 +164,7 @@ fn set_key_emits_events_correctly() { fn sudo_as_basics() { new_test_ext(1).execute_with(|| { // A privileged function will not work when passed to `sudo_as`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1_000), })); @@ -173,14 +173,14 @@ fn sudo_as_basics() { assert!(Logger::account_log().is_empty()); // A non-privileged function should not work when called with a non-root `key`. - let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::from_ref_time(1), })); assert_noop!(Sudo::sudo_as(Origin::signed(3), 2, call), Error::::RequireSudo); // A non-privileged function will work when passed to `sudo_as` with the root `key`. - let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::from_ref_time(1), })); @@ -198,7 +198,7 @@ fn sudo_as_emits_events_correctly() { System::set_block_number(1); // A non-privileged function will work when passed to `sudo_as` with the root `key`. - let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::from_ref_time(1), })); diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index 028e68f0198d1..b415132ab0426 100644 --- a/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -55,7 +55,7 @@ pub fn expand_outer_dispatch( #[codec(index = #index)] #name( #scrate::dispatch::CallableCallFor<#name, #runtime> ), }); - variant_patterns.push(quote!(Call::#name(call))); + variant_patterns.push(quote!(RuntimeCall::#name(call))); pallet_names.push(name); pallet_attrs.push(attr); query_call_part_macros.push(quote! { @@ -73,11 +73,11 @@ pub fn expand_outer_dispatch( #scrate::scale_info::TypeInfo, #scrate::RuntimeDebug, )] - pub enum Call { + pub enum RuntimeCall { #variant_defs } #[cfg(test)] - impl Call { + impl RuntimeCall { /// Return a list of the module names together with their size in memory. pub const fn sizes() -> &'static [( &'static str, usize )] { use #scrate::dispatch::Callable; @@ -86,7 +86,7 @@ pub fn expand_outer_dispatch( #pallet_attrs ( stringify!(#pallet_names), - size_of::< <#pallet_names as Callable<#runtime>>::Call >(), + size_of::< <#pallet_names as Callable<#runtime>>::RuntimeCall >(), ), )*] } @@ -113,7 +113,7 @@ pub fn expand_outer_dispatch( } } } - impl #scrate::dispatch::GetDispatchInfo for Call { + impl #scrate::dispatch::GetDispatchInfo for RuntimeCall { fn get_dispatch_info(&self) -> #scrate::dispatch::DispatchInfo { match self { #( @@ -123,7 +123,7 @@ pub fn expand_outer_dispatch( } } } - impl #scrate::dispatch::GetCallMetadata for Call { + impl #scrate::dispatch::GetCallMetadata for RuntimeCall { fn get_call_metadata(&self) -> #scrate::dispatch::CallMetadata { use #scrate::dispatch::GetCallName; match self { @@ -151,16 +151,16 @@ pub fn expand_outer_dispatch( #( #pallet_attrs stringify!(#pallet_names) => - <<#pallet_names as Callable<#runtime>>::Call + <<#pallet_names as Callable<#runtime>>::RuntimeCall as GetCallName>::get_call_names(), )* _ => unreachable!(), } } } - impl #scrate::dispatch::Dispatchable for Call { + impl #scrate::dispatch::Dispatchable for RuntimeCall { type Origin = Origin; - type Config = Call; + type Config = RuntimeCall; type Info = #scrate::weights::DispatchInfo; type PostInfo = #scrate::weights::PostDispatchInfo; fn dispatch(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { @@ -173,7 +173,7 @@ pub fn expand_outer_dispatch( #scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(self, origin) } } - impl #scrate::traits::UnfilteredDispatchable for Call { + impl #scrate::traits::UnfilteredDispatchable for RuntimeCall { type Origin = Origin; fn dispatch_bypass_filter(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { match self { @@ -188,7 +188,7 @@ pub fn expand_outer_dispatch( #( #pallet_attrs - impl #scrate::traits::IsSubType<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for Call { + impl #scrate::traits::IsSubType<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for RuntimeCall { #[allow(unreachable_patterns)] fn is_sub_type(&self) -> Option<&#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> { match self { @@ -200,7 +200,7 @@ pub fn expand_outer_dispatch( } #pallet_attrs - impl From<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for Call { + impl From<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for RuntimeCall { fn from(call: #scrate::dispatch::CallableCallFor<#pallet_names, #runtime>) -> Self { #variant_patterns } diff --git a/frame/support/procedural/src/construct_runtime/expand/event.rs b/frame/support/procedural/src/construct_runtime/expand/event.rs index f145327d37af5..b11fcef1bfd53 100644 --- a/frame/support/procedural/src/construct_runtime/expand/event.rs +++ b/frame/support/procedural/src/construct_runtime/expand/event.rs @@ -80,7 +80,7 @@ pub fn expand_outer_event( #scrate::RuntimeDebug, )] #[allow(non_camel_case_types)] - pub enum Event { + pub enum RuntimeEvent { #event_variants } @@ -148,13 +148,13 @@ fn expand_event_conversion( quote! { #attr - impl From<#pallet_event> for Event { + impl From<#pallet_event> for RuntimeEvent { fn from(x: #pallet_event) -> Self { - Event::#variant_name(x) + RuntimeEvent::#variant_name(x) } } #attr - impl TryInto<#pallet_event> for Event { + impl TryInto<#pallet_event> for RuntimeEvent { type Error = (); fn try_into(self) -> #scrate::sp_std::result::Result<#pallet_event, Self::Error> { diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index a4bb0d9cbaa02..d234ca6415115 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -105,7 +105,7 @@ pub fn expand_outer_origin( #[derive(Clone)] pub struct Origin { caller: OriginCaller, - filter: #scrate::sp_std::rc::Rc::Call) -> bool>>, + filter: #scrate::sp_std::rc::Rc::RuntimeCall) -> bool>>, } #[cfg(not(feature = "std"))] @@ -132,7 +132,7 @@ pub fn expand_outer_origin( } impl #scrate::traits::OriginTrait for Origin { - type Call = <#runtime as #system_path::Config>::Call; + type Call = <#runtime as #system_path::Config>::RuntimeCall; type PalletsOrigin = OriginCaller; type AccountId = <#runtime as #system_path::Config>::AccountId; @@ -147,7 +147,7 @@ pub fn expand_outer_origin( fn reset_filter(&mut self) { let filter = < <#runtime as #system_path::Config>::BaseCallFilter - as #scrate::traits::Contains<<#runtime as #system_path::Config>::Call> + as #scrate::traits::Contains<<#runtime as #system_path::Config>::RuntimeCall> >::contains; self.filter = #scrate::sp_std::rc::Rc::new(Box::new(filter)); diff --git a/frame/support/procedural/src/construct_runtime/expand/unsigned.rs b/frame/support/procedural/src/construct_runtime/expand/unsigned.rs index 310516793472f..1d528779423a7 100644 --- a/frame/support/procedural/src/construct_runtime/expand/unsigned.rs +++ b/frame/support/procedural/src/construct_runtime/expand/unsigned.rs @@ -55,14 +55,14 @@ pub fn expand_outer_validate_unsigned( #( #query_validate_unsigned_part_macros )* impl #scrate::unsigned::ValidateUnsigned for #runtime { - type Call = Call; + type Call = RuntimeCall; fn pre_dispatch(call: &Self::Call) -> Result<(), #scrate::unsigned::TransactionValidityError> { #[allow(unreachable_patterns)] match call { #( #pallet_attrs - Call::#pallet_names(inner_call) => #pallet_names::pre_dispatch(inner_call), + RuntimeCall::#pallet_names(inner_call) => #pallet_names::pre_dispatch(inner_call), )* // pre-dispatch should not stop inherent extrinsics, validation should prevent // including arbitrary (non-inherent) extrinsics to blocks. @@ -79,7 +79,7 @@ pub fn expand_outer_validate_unsigned( match call { #( #pallet_attrs - Call::#pallet_names(inner_call) => #pallet_names::validate_unsigned(source, inner_call), + RuntimeCall::#pallet_names(inner_call) => #pallet_names::validate_unsigned(source, inner_call), )* _ => #scrate::unsigned::UnknownTransaction::NoUnsignedValidator.into(), } diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 00204b7a4d906..0f72b28748cee 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -311,7 +311,7 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { /// System: frame_system::{Pallet, Call, Event, Config} = 0, /// Test: path::to::test::{Pallet, Call} = 1, /// -/// // Pallets with instances +/// // Pallets with instances. /// Test2_Instance1: test2::::{Pallet, Call, Storage, Event, Config, Origin}, /// Test2_DefaultInstance: test2::{Pallet, Call, Storage, Event, Config, Origin} = 4, /// diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index a9468451ad1d4..8b2922b5fa4f2 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -300,7 +300,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { impl<#type_impl_gen> #frame_support::dispatch::Callable for #pallet_ident<#type_use_gen> #where_clause { - type Call = #call_ident<#type_use_gen>; + type RuntimeCall = #call_ident<#type_use_gen>; } impl<#type_impl_gen> #pallet_ident<#type_use_gen> #where_clause { diff --git a/frame/support/procedural/src/pallet/expand/event.rs b/frame/support/procedural/src/pallet/expand/event.rs index 791f930302207..abed680eb245e 100644 --- a/frame/support/procedural/src/pallet/expand/event.rs +++ b/frame/support/procedural/src/pallet/expand/event.rs @@ -61,7 +61,8 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { let event_where_clause = &event.where_clause; // NOTE: actually event where clause must be a subset of config where clause because of - // `type Event: From>`. But we merge either way for potential better error message + // `type RuntimeEvent: From>`. But we merge either way for potential better error + // message let completed_where_clause = super::merge_where_clauses(&[&event.where_clause, &def.config.where_clause]); @@ -136,13 +137,13 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { impl<#type_impl_gen> Pallet<#type_use_gen> #completed_where_clause { #fn_vis fn deposit_event(event: Event<#event_use_gen>) { let event = < - ::Event as + ::RuntimeEvent as From> >::from(event); let event = < - ::Event as - Into<::Event> + ::RuntimeEvent as + Into<::RuntimeEvent> >::into(event); <#frame_system::Pallet>::deposit_event(event) diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 60888fc5dd357..0f3aa69b170ce 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -28,6 +28,7 @@ mod keyword { syn::custom_keyword!(I); syn::custom_keyword!(config); syn::custom_keyword!(IsType); + syn::custom_keyword!(RuntimeEvent); syn::custom_keyword!(Event); syn::custom_keyword!(constant); syn::custom_keyword!(frame_system); @@ -42,8 +43,9 @@ pub struct ConfigDef { pub has_instance: bool, /// Const associated type. pub consts_metadata: Vec, - /// Whether the trait has the associated type `Event`, note that those bounds are checked: - /// * `IsType::Event` + /// Whether the trait has the associated type `Event`, note that those bounds are + /// checked: + /// * `IsType::RuntimeEvent` /// * `From` or `From>` or `From>` pub has_event_type: bool, /// The where clause on trait definition but modified so `Self` is `T`. @@ -159,7 +161,7 @@ impl syn::parse::Parse for ConfigBoundParse { } } -/// Parse for `IsType<::Event>` and retrieve `$ident` +/// Parse for `IsType<::RuntimeEvent>` and retrieve `$ident` pub struct IsTypeBoundEventParse(syn::Ident); impl syn::parse::Parse for IsTypeBoundEventParse { @@ -174,7 +176,7 @@ impl syn::parse::Parse for IsTypeBoundEventParse { input.parse::()?; input.parse::]>()?; input.parse::()?; - input.parse::()?; + input.parse::()?; input.parse::]>()?; Ok(Self(ident)) @@ -212,7 +214,7 @@ impl syn::parse::Parse for FromEventParse { } } -/// Check if trait_item is `type Event`, if so checks its bounds are those expected. +/// Check if trait_item is `type RuntimeEvent`, if so checks its bounds are those expected. /// (Event type is reserved type) fn check_event_type( frame_system: &syn::Ident, @@ -220,10 +222,10 @@ fn check_event_type( trait_has_instance: bool, ) -> syn::Result { if let syn::TraitItem::Type(type_) = trait_item { - if type_.ident == "Event" { + if type_.ident == "RuntimeEvent" { // Check event has no generics if !type_.generics.params.is_empty() || type_.generics.where_clause.is_some() { - let msg = "Invalid `type Event`, associated type `Event` is reserved and must have\ + let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must have\ no generics nor where_clause"; return Err(syn::Error::new(trait_item.span(), msg)) } @@ -236,8 +238,8 @@ fn check_event_type( if !has_is_type_bound { let msg = format!( - "Invalid `type Event`, associated type `Event` is reserved and must \ - bound: `IsType<::Event>`", + "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \ + bound: `IsType<::RuntimeEvent>`", frame_system, ); return Err(syn::Error::new(type_.span(), msg)) @@ -251,14 +253,14 @@ fn check_event_type( let from_event_bound = if let Some(b) = from_event_bound { b } else { - let msg = "Invalid `type Event`, associated type `Event` is reserved and must \ + let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \ bound: `From` or `From>` or `From>`"; return Err(syn::Error::new(type_.span(), msg)) }; if from_event_bound.is_generic && (from_event_bound.has_instance != trait_has_instance) { - let msg = "Invalid `type Event`, associated type `Event` bounds inconsistent \ + let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` bounds inconsistent \ `From`. Config and generic Event must be both with instance or \ without instance"; return Err(syn::Error::new(type_.span(), msg)) diff --git a/frame/support/procedural/src/pallet/parse/mod.rs b/frame/support/procedural/src/pallet/parse/mod.rs index a436f7e09c1d7..f1e520952d872 100644 --- a/frame/support/procedural/src/pallet/parse/mod.rs +++ b/frame/support/procedural/src/pallet/parse/mod.rs @@ -105,11 +105,11 @@ impl Def { let m = hooks::HooksDef::try_from(span, index, item)?; hooks = Some(m); }, - Some(PalletAttr::Call(span)) if call.is_none() => + Some(PalletAttr::RuntimeCall(span)) if call.is_none() => call = Some(call::CallDef::try_from(span, index, item)?), Some(PalletAttr::Error(span)) if error.is_none() => error = Some(error::ErrorDef::try_from(span, index, item)?), - Some(PalletAttr::Event(span)) if event.is_none() => + Some(PalletAttr::RuntimeEvent(span)) if event.is_none() => event = Some(event::EventDef::try_from(span, index, item)?), Some(PalletAttr::GenesisConfig(_)) if genesis_config.is_none() => { let g = genesis_config::GenesisConfigDef::try_from(index, item)?; @@ -182,19 +182,19 @@ impl Def { } /// Check that usage of trait `Event` is consistent with the definition, i.e. it is declared - /// and trait defines type Event, or not declared and no trait associated type. + /// and trait defines type RuntimeEvent, or not declared and no trait associated type. fn check_event_usage(&self) -> syn::Result<()> { match (self.config.has_event_type, self.event.is_some()) { (true, false) => { - let msg = "Invalid usage of Event, `Config` contains associated type `Event`, \ + let msg = "Invalid usage of RuntimeEvent, `Config` contains associated type `RuntimeEvent`, \ but enum `Event` is not declared (i.e. no use of `#[pallet::event]`). \ - Note that type `Event` in trait is reserved to work alongside pallet event."; + Note that type `RuntimeEvent` in trait is reserved to work alongside pallet event."; Err(syn::Error::new(proc_macro2::Span::call_site(), msg)) }, (false, true) => { - let msg = "Invalid usage of Event, `Config` contains no associated type \ - `Event`, but enum `Event` is declared (in use of `#[pallet::event]`). \ - An Event associated type must be declare on trait `Config`."; + let msg = "Invalid usage of RuntimeEvent, `Config` contains no associated type \ + `RuntimeEvent`, but enum `Event` is declared (in use of `#[pallet::event]`). \ + An RuntimeEvent associated type must be declare on trait `Config`."; Err(syn::Error::new(proc_macro2::Span::call_site(), msg)) }, _ => Ok(()), @@ -391,9 +391,9 @@ enum PalletAttr { Config(proc_macro2::Span), Pallet(proc_macro2::Span), Hooks(proc_macro2::Span), - Call(proc_macro2::Span), + RuntimeCall(proc_macro2::Span), Error(proc_macro2::Span), - Event(proc_macro2::Span), + RuntimeEvent(proc_macro2::Span), Origin(proc_macro2::Span), Inherent(proc_macro2::Span), Storage(proc_macro2::Span), @@ -410,9 +410,9 @@ impl PalletAttr { Self::Config(span) => *span, Self::Pallet(span) => *span, Self::Hooks(span) => *span, - Self::Call(span) => *span, + Self::RuntimeCall(span) => *span, Self::Error(span) => *span, - Self::Event(span) => *span, + Self::RuntimeEvent(span) => *span, Self::Origin(span) => *span, Self::Inherent(span) => *span, Self::Storage(span) => *span, @@ -441,11 +441,11 @@ impl syn::parse::Parse for PalletAttr { } else if lookahead.peek(keyword::hooks) { Ok(PalletAttr::Hooks(content.parse::()?.span())) } else if lookahead.peek(keyword::call) { - Ok(PalletAttr::Call(content.parse::()?.span())) + Ok(PalletAttr::RuntimeCall(content.parse::()?.span())) } else if lookahead.peek(keyword::error) { Ok(PalletAttr::Error(content.parse::()?.span())) } else if lookahead.peek(keyword::event) { - Ok(PalletAttr::Event(content.parse::()?.span())) + Ok(PalletAttr::RuntimeEvent(content.parse::()?.span())) } else if lookahead.peek(keyword::origin) { Ok(PalletAttr::Origin(content.parse::()?.span())) } else if lookahead.peek(keyword::inherent) { diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index fc976b03556a4..9a6654d5524d4 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -56,12 +56,12 @@ pub type DispatchErrorWithPostInfo = /// Serializable version of pallet dispatchable. pub trait Callable { - type Call: UnfilteredDispatchable + Codec + Clone + PartialEq + Eq; + type RuntimeCall: UnfilteredDispatchable + Codec + Clone + PartialEq + Eq; } // dirty hack to work around serde_derive issue // https://github.com/rust-lang/rust/issues/51331 -pub type CallableCallFor = >::Call; +pub type CallableCallFor = >::RuntimeCall; /// Origin for the System pallet. #[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] @@ -1497,7 +1497,7 @@ macro_rules! decl_module { { /// Deposits an event using `frame_system::Pallet::deposit_event`. $vis fn deposit_event( - event: impl Into<< $trait_instance as $trait_name $(<$instance>)? >::Event> + event: impl Into<< $trait_instance as $trait_name $(<$instance>)? >::RuntimeEvent> ) { <$system::Pallet<$trait_instance>>::deposit_event(event.into()) } @@ -2376,7 +2376,7 @@ macro_rules! decl_module { impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Callable<$trait_instance> for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { - type Call = $call_type<$trait_instance $(, $instance)?>; + type RuntimeCall = $call_type<$trait_instance $(, $instance)?>; } $crate::__dispatch_impl_metadata! { @@ -2648,9 +2648,9 @@ mod tests { pub trait Config: 'static { type AccountId; - type Call; + type RuntimeCall; type BaseCallFilter; - type Origin: crate::traits::OriginTrait; + type Origin: crate::traits::OriginTrait; type BlockNumber: Into; type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; @@ -2751,7 +2751,7 @@ mod tests { } impl crate::traits::OriginTrait for OuterOrigin { - type Call = ::Call; + type Call = ::RuntimeCall; type PalletsOrigin = OuterOrigin; type AccountId = ::AccountId; @@ -2799,7 +2799,7 @@ mod tests { impl system::Config for TraitImpl { type Origin = OuterOrigin; type AccountId = u32; - type Call = (); + type RuntimeCall = (); type BaseCallFilter = frame_support::traits::Everything; type BlockNumber = u32; type PalletInfo = Self; diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 55ded6da9c5a1..315d856e5d0f8 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1452,9 +1452,9 @@ pub mod pallet_prelude { /// I.e. a regular trait definition named `Config`, with supertrait `frame_system::Config`, /// optionally other supertrait and where clause. /// -/// The associated type `Event` is reserved, if defined it must bounds `From` and -/// `IsType<::Event>`, see `#[pallet::event]` for more -/// information. +/// The associated type `RuntimeEvent` is reserved, if defined it must bounds +/// `From` and `IsType<::RuntimeEvent>`, see +/// `#[pallet::event]` for more information. /// /// To put `Get` associated type into metadatas, use the attribute `#[pallet::constant]`, e.g.: /// ```ignore @@ -2078,7 +2078,7 @@ pub mod pallet_prelude { /// #[pallet::constant] // put the constant in metadata /// type MyGetParam: Get; /// type Balance: Parameter + MaxEncodedLen + From; -/// type Event: From> + IsType<::Event>; +/// type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// } /// /// // Define some additional constant to put into the constant metadata. @@ -2267,7 +2267,7 @@ pub mod pallet_prelude { /// #[pallet::constant] /// type MyGetParam: Get; /// type Balance: Parameter + MaxEncodedLen + From; -/// type Event: From> + IsType<::Event>; +/// type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// } /// /// #[pallet::extra_constants] @@ -2423,7 +2423,7 @@ pub mod pallet_prelude { /// ``` /// 5. **migrate Config**: move trait into the module with /// * all const in decl_module to `#[pallet::constant]` -/// * add bound `IsType<::Event>` to `type Event` +/// * add bound `IsType<::RuntimeEvent>` to `type RuntimeEvent` /// 7. **migrate decl_module**: write: /// ```ignore /// #[pallet::hooks] diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index 7850726048546..6e4d2363b2f7c 100644 --- a/frame/support/test/compile_pass/src/lib.rs +++ b/frame/support/test/compile_pass/src/lib.rs @@ -68,9 +68,9 @@ impl frame_system::Config for Runtime { type Origin = Origin; type BlockNumber = BlockNumber; type AccountId = AccountId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); type OnNewAccount = (); type OnKilledAccount = (); @@ -82,7 +82,7 @@ impl frame_system::Config for Runtime { pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; construct_runtime!( pub enum Runtime where diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 04b3dbcedcbf2..4f3c783252e00 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -250,9 +250,9 @@ impl system::Config for Runtime { type Origin = Origin; type BlockNumber = BlockNumber; type AccountId = AccountId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); } @@ -280,7 +280,7 @@ frame_support::construct_runtime!( pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; #[test] fn check_modules_error_type() { @@ -373,7 +373,7 @@ fn check_modules_error_type() { message: Some("Something") })), ); - }); + }) } #[test] @@ -422,53 +422,53 @@ fn event_codec() { use codec::Encode; let event = system::Event::::ExtrinsicSuccess; - assert_eq!(Event::from(event).encode()[0], 30); + assert_eq!(RuntimeEvent::from(event).encode()[0], 30); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 31); + assert_eq!(RuntimeEvent::from(event).encode()[0], 31); let event = module2::Event::A; - assert_eq!(Event::from(event).encode()[0], 32); + assert_eq!(RuntimeEvent::from(event).encode()[0], 32); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 33); + assert_eq!(RuntimeEvent::from(event).encode()[0], 33); let event = nested::module3::Event::A; - assert_eq!(Event::from(event).encode()[0], 34); + assert_eq!(RuntimeEvent::from(event).encode()[0], 34); let event = module3::Event::A; - assert_eq!(Event::from(event).encode()[0], 35); + assert_eq!(RuntimeEvent::from(event).encode()[0], 35); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 4); + assert_eq!(RuntimeEvent::from(event).encode()[0], 4); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 1); + assert_eq!(RuntimeEvent::from(event).encode()[0], 1); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 2); + assert_eq!(RuntimeEvent::from(event).encode()[0], 2); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 12); + assert_eq!(RuntimeEvent::from(event).encode()[0], 12); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 13); + assert_eq!(RuntimeEvent::from(event).encode()[0], 13); } #[test] fn call_codec() { use codec::Encode; - assert_eq!(Call::System(system::Call::noop {}).encode()[0], 30); - assert_eq!(Call::Module1_1(module1::Call::fail {}).encode()[0], 31); - assert_eq!(Call::Module2(module2::Call::fail {}).encode()[0], 32); - assert_eq!(Call::Module1_2(module1::Call::fail {}).encode()[0], 33); - assert_eq!(Call::NestedModule3(nested::module3::Call::fail {}).encode()[0], 34); - assert_eq!(Call::Module3(module3::Call::fail {}).encode()[0], 35); - assert_eq!(Call::Module1_4(module1::Call::fail {}).encode()[0], 3); - assert_eq!(Call::Module1_6(module1::Call::fail {}).encode()[0], 1); - assert_eq!(Call::Module1_7(module1::Call::fail {}).encode()[0], 2); - assert_eq!(Call::Module1_8(module1::Call::fail {}).encode()[0], 12); - assert_eq!(Call::Module1_9(module1::Call::fail {}).encode()[0], 13); + assert_eq!(RuntimeCall::System(system::Call::noop {}).encode()[0], 30); + assert_eq!(RuntimeCall::Module1_1(module1::Call::fail {}).encode()[0], 31); + assert_eq!(RuntimeCall::Module2(module2::Call::fail {}).encode()[0], 32); + assert_eq!(RuntimeCall::Module1_2(module1::Call::fail {}).encode()[0], 33); + assert_eq!(RuntimeCall::NestedModule3(nested::module3::Call::fail {}).encode()[0], 34); + assert_eq!(RuntimeCall::Module3(module3::Call::fail {}).encode()[0], 35); + assert_eq!(RuntimeCall::Module1_4(module1::Call::fail {}).encode()[0], 3); + assert_eq!(RuntimeCall::Module1_6(module1::Call::fail {}).encode()[0], 1); + assert_eq!(RuntimeCall::Module1_7(module1::Call::fail {}).encode()[0], 2); + assert_eq!(RuntimeCall::Module1_8(module1::Call::fail {}).encode()[0], 12); + assert_eq!(RuntimeCall::Module1_9(module1::Call::fail {}).encode()[0], 13); } #[test] @@ -537,7 +537,7 @@ fn call_name() { #[test] fn call_metadata() { use frame_support::dispatch::{CallMetadata, GetCallMetadata}; - let call = Call::Module3(module3::Call::::aux_4 {}); + let call = RuntimeCall::Module3(module3::Call::::aux_4 {}); let metadata = call.get_call_metadata(); let expected = CallMetadata { function_name: "aux_4".into(), pallet_name: "Module3".into() }; assert_eq!(metadata, expected); @@ -553,7 +553,7 @@ fn get_call_names() { #[test] fn get_module_names() { use frame_support::dispatch::GetCallMetadata; - let module_names = Call::get_module_names(); + let module_names = RuntimeCall::get_module_names(); assert_eq!( [ "System", @@ -575,13 +575,13 @@ fn get_module_names() { #[test] fn call_subtype_conversion() { use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; - let call = Call::Module3(module3::Call::::fail {}); + let call = RuntimeCall::Module3(module3::Call::::fail {}); let subcall: Option<&CallableCallFor> = call.is_sub_type(); let subcall_none: Option<&CallableCallFor> = call.is_sub_type(); assert_eq!(Some(&module3::Call::::fail {}), subcall); assert_eq!(None, subcall_none); - let from = Call::from(subcall.unwrap().clone()); + let from = RuntimeCall::from(subcall.unwrap().clone()); assert_eq!(from, call); } diff --git a/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs index 98cd1f197f619..7a074db9986a2 100644 --- a/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs +++ b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs @@ -15,7 +15,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u64; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} diff --git a/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr index 608d57d6a97fc..5f1fccd43c549 100644 --- a/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr +++ b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr @@ -1,28 +1,19 @@ error: Unexpected tokens, expected one of `=`, `,` - --> $DIR/both_use_and_excluded_parts.rs:29:43 + --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:29:43 | 29 | Pallet: pallet exclude_parts { Pallet } use_parts { Pallet }, | ^^^^^^^^^ -error[E0412]: cannot find type `Call` in this scope - --> $DIR/both_use_and_excluded_parts.rs:18:64 - | -18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; - | ^^^^ not found in this scope - | -help: consider importing one of these items - | -1 | use crate::pallet::Call; - | -1 | use frame_support_test::Call; - | -1 | use frame_system::Call; - | -1 | use test_pallet::Call; +error[E0412]: cannot find type `RuntimeCall` in this scope + --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:18:64 | +18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | - ^^^^^^^^^^^ not found in this scope + | | + | help: you might be missing a type parameter: `` error[E0412]: cannot find type `Runtime` in this scope - --> $DIR/both_use_and_excluded_parts.rs:20:25 + --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:20:25 | 20 | impl pallet::Config for Runtime {} | ^^^^^^^ not found in this scope diff --git a/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs index 51be7e30bd3eb..302b5af7ecd26 100644 --- a/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs @@ -20,7 +20,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u64; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} diff --git a/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr index 4e31cfb75c074..c623ecfbf4cdf 100644 --- a/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr @@ -1,28 +1,19 @@ error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`. - --> $DIR/exclude_undefined_part.rs:34:34 + --> tests/construct_runtime_ui/exclude_undefined_part.rs:34:34 | 34 | Pallet: pallet exclude_parts { Call }, | ^^^^ -error[E0412]: cannot find type `Call` in this scope - --> $DIR/exclude_undefined_part.rs:23:64 - | -23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; - | ^^^^ not found in this scope - | -help: consider importing one of these items - | -1 | use crate::pallet::Call; - | -1 | use frame_support_test::Call; - | -1 | use frame_system::Call; - | -1 | use test_pallet::Call; +error[E0412]: cannot find type `RuntimeCall` in this scope + --> tests/construct_runtime_ui/exclude_undefined_part.rs:23:64 | +23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | - ^^^^^^^^^^^ not found in this scope + | | + | help: you might be missing a type parameter: `` error[E0412]: cannot find type `Runtime` in this scope - --> $DIR/exclude_undefined_part.rs:25:25 + --> tests/construct_runtime_ui/exclude_undefined_part.rs:25:25 | 25 | impl pallet::Config for Runtime {} | ^^^^^^^ not found in this scope diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs index c06333795e3c5..fd6b51db07672 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs @@ -6,7 +6,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl test_pallet::Config for Runtime {} @@ -15,13 +15,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs index 827d8a58af733..f73c611d29686 100644 --- a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs +++ b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs @@ -40,7 +40,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} @@ -49,13 +49,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs index 1653e830f0b4f..f90af88d23a9b 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs @@ -15,7 +15,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} @@ -24,13 +24,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs index b8f91cf4bc690..60d4b166c41fd 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs @@ -15,7 +15,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} @@ -24,13 +24,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index 2af4d3fb15000..920e627d43c31 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -45,36 +45,3 @@ help: if you import `Event`, refer to it directly 57 - } 58 - } | - -error[E0412]: cannot find type `Event` in module `pallet` - --> tests/construct_runtime_ui/undefined_event_part.rs:49:1 - | -49 | / construct_runtime! { -50 | | pub enum Runtime where -51 | | Block = Block, -52 | | NodeBlock = Block, -... | -57 | | } -58 | | } - | |_^ not found in `pallet` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use crate::Event; - | -1 | use frame_system::Event; - | -help: if you import `Event`, refer to it directly - | -49 - construct_runtime! { -50 - pub enum Runtime where -51 - Block = Block, -52 - NodeBlock = Block, -53 - UncheckedExtrinsic = UncheckedExtrinsic -54 - { -55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, -56 - Pallet: pallet::{Pallet, Event}, -57 - } -58 - } - | diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs index a61d545b3279e..5f7beed686339 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs @@ -15,7 +15,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} @@ -24,13 +24,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs index 6e4764286ab41..fb866c161ccb8 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs @@ -15,7 +15,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} @@ -24,13 +24,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs index 9233404a865b9..26ca5d6eb4cb0 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs @@ -15,7 +15,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} @@ -24,13 +24,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs index 621683aca3754..81c040c660451 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs @@ -15,7 +15,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} @@ -24,13 +24,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr index 94226075d9a4b..a5e4fe3c1cd5a 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr @@ -15,14 +15,14 @@ error: `Pallet` does not have #[pallet::validate_unsigned] defined, perhaps you | = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0599]: no variant or associated item named `Pallet` found for enum `Call` in the current scope +error[E0599]: no variant or associated item named `Pallet` found for enum `RuntimeCall` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:56:3 | 49 | construct_runtime! { | ------------------ variant or associated item `Pallet` not found here ... 56 | Pallet: pallet::{Pallet, ValidateUnsigned}, - | ^^^^^^ variant or associated item not found in `Call` + | ^^^^^^ variant or associated item not found in `RuntimeCall` error[E0599]: no function or associated item named `pre_dispatch` found for struct `pallet::Pallet` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 diff --git a/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs index 1664dcc42b755..c74e29bc05469 100644 --- a/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs @@ -20,7 +20,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u64; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} diff --git a/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr index ed41f0ce673a4..e289c75fb008a 100644 --- a/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr @@ -1,28 +1,19 @@ error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`. - --> $DIR/use_undefined_part.rs:34:30 + --> tests/construct_runtime_ui/use_undefined_part.rs:34:30 | 34 | Pallet: pallet use_parts { Call }, | ^^^^ -error[E0412]: cannot find type `Call` in this scope - --> $DIR/use_undefined_part.rs:23:64 - | -23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; - | ^^^^ not found in this scope - | -help: consider importing one of these items - | -1 | use crate::pallet::Call; - | -1 | use frame_support_test::Call; - | -1 | use frame_system::Call; - | -1 | use test_pallet::Call; +error[E0412]: cannot find type `RuntimeCall` in this scope + --> tests/construct_runtime_ui/use_undefined_part.rs:23:64 | +23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | - ^^^^^^^^^^^ not found in this scope + | | + | help: you might be missing a type parameter: `` error[E0412]: cannot find type `Runtime` in this scope - --> $DIR/use_undefined_part.rs:25:25 + --> tests/construct_runtime_ui/use_undefined_part.rs:25:25 | 25 | impl pallet::Config for Runtime {} | ^^^^^^^ not found in this scope diff --git a/frame/support/test/tests/instance.rs b/frame/support/test/tests/instance.rs index 75a96f628245a..c9eebdaff6bc4 100644 --- a/frame/support/test/tests/instance.rs +++ b/frame/support/test/tests/instance.rs @@ -50,7 +50,7 @@ mod module1 { where ::BlockNumber: From, { - type Event: From> + Into<::Event>; + type RuntimeEvent: From> + Into<::RuntimeEvent>; type Origin: From>; type SomeParameter: Get; type GenericType: Default + Clone + Codec + EncodeLike + TypeInfo; @@ -154,7 +154,7 @@ mod module2 { pub trait Config: system::Config { type Amount: Parameter + Default; - type Event: From> + Into<::Event>; + type RuntimeEvent: From> + Into<::RuntimeEvent>; type Origin: From>; } @@ -233,35 +233,35 @@ mod module3 { } impl module1::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Origin = Origin; type SomeParameter = ConstU32<100>; type GenericType = u32; } impl module1::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Origin = Origin; type SomeParameter = ConstU32<100>; type GenericType = u32; } impl module2::Config for Runtime { type Amount = u16; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Origin = Origin; } impl module2::Config for Runtime { type Amount = u32; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Origin = Origin; } impl module2::Config for Runtime { type Amount = u32; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Origin = Origin; } impl module2::Config for Runtime { type Amount = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Origin = Origin; } impl module3::Config for Runtime { @@ -280,9 +280,9 @@ impl system::Config for Runtime { type Origin = Origin; type BlockNumber = BlockNumber; type AccountId = AccountId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); } @@ -315,7 +315,7 @@ frame_support::construct_runtime!( pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; fn new_test_ext() -> sp_io::TestExternalities { GenesisConfig { diff --git a/frame/support/test/tests/issue2219.rs b/frame/support/test/tests/issue2219.rs index d7e3d2cb5b135..0b24a6aa89828 100644 --- a/frame/support/test/tests/issue2219.rs +++ b/frame/support/test/tests/issue2219.rs @@ -155,7 +155,7 @@ pub type BlockNumber = u64; pub type Index = u64; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; @@ -163,9 +163,9 @@ impl system::Config for Runtime { type Origin = Origin; type BlockNumber = BlockNumber; type AccountId = AccountId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); } diff --git a/frame/support/test/tests/origin.rs b/frame/support/test/tests/origin.rs index cff531ff2e529..53124059e6353 100644 --- a/frame/support/test/tests/origin.rs +++ b/frame/support/test/tests/origin.rs @@ -134,10 +134,10 @@ impl nested::module::Config for RuntimeOriginTest {} impl module::Config for RuntimeOriginTest {} pub struct BaseCallFilter; -impl Contains for BaseCallFilter { - fn contains(c: &Call) -> bool { +impl Contains for BaseCallFilter { + fn contains(c: &RuntimeCall) -> bool { match c { - Call::NestedModule(_) => true, + RuntimeCall::NestedModule(_) => true, _ => false, } } @@ -149,9 +149,9 @@ impl system::Config for RuntimeOriginTest { type Origin = Origin; type BlockNumber = BlockNumber; type AccountId = u32; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); } @@ -170,7 +170,7 @@ frame_support::construct_runtime!( pub type Signature = sr25519::Signature; pub type BlockNumber = u64; pub type Header = generic::Header; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; pub type Block = generic::Block; #[test] @@ -192,7 +192,7 @@ fn origin_default_filter() { assert_eq!(Origin::from(nested::module::Origin).filter_call(&rejected_call), false); let mut origin = Origin::from(Some(0)); - origin.add_filter(|c| matches!(c, Call::Module(_))); + origin.add_filter(|c| matches!(c, RuntimeCall::Module(_))); assert_eq!(origin.filter_call(&accepted_call), false); assert_eq!(origin.filter_call(&rejected_call), false); diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index d683399482bf4..420617a9e4f24 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -125,7 +125,7 @@ pub mod pallet { type Balance: Parameter + Default + TypeInfo; - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::extra_constants] @@ -477,7 +477,7 @@ pub mod pallet2 { where ::AccountId: From + SomeAssociation1, { - type Event: From + IsType<::Event>; + type RuntimeEvent: From + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -579,13 +579,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type BlockWeights = (); type BlockLength = (); @@ -601,7 +601,7 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MyGetParam = ConstU32<10>; type MyGetParam2 = ConstU32<11>; type MyGetParam3 = MyGetParam3; @@ -609,7 +609,7 @@ impl pallet::Config for Runtime { } impl pallet2::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } impl pallet4::Config for Runtime {} @@ -621,7 +621,7 @@ impl pallet3::Config for Runtime { pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime where @@ -639,10 +639,10 @@ frame_support::construct_runtime!( } ); -// Test that the part `Call` is excluded from Example2 and included in Example4. -fn _ensure_call_is_correctly_excluded_and_included(call: Call) { +// Test that the part `RuntimeCall` is excluded from Example2 and included in Example4. +fn _ensure_call_is_correctly_excluded_and_included(call: RuntimeCall) { match call { - Call::System(_) | Call::Example(_) | Call::Example4(_) => (), + RuntimeCall::System(_) | RuntimeCall::Example(_) | RuntimeCall::Example4(_) => (), } } @@ -665,7 +665,7 @@ fn transactional_works() { .iter() .map(|e| &e.event) .collect::>(), - vec![&Event::Example(pallet::Event::Something(0))], + vec![&RuntimeEvent::Example(pallet::Event::Something(0))], ); }) } @@ -730,7 +730,7 @@ fn inherent_expand() { let inherents = InherentData::new().create_extrinsics(); let expected = vec![UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: None, }]; assert_eq!(expected, inherents); @@ -745,11 +745,11 @@ fn inherent_expand() { ), vec![ UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 1, bar: 0 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 0 }), signature: None, }, ], @@ -767,11 +767,11 @@ fn inherent_expand() { ), vec![ UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 0, bar: 0 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 0, bar: 0 }), signature: None, }, ], @@ -788,7 +788,7 @@ fn inherent_expand() { Digest::default(), ), vec![UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_storage_layer { foo: 0 }), + function: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), signature: None, }], ); @@ -806,7 +806,7 @@ fn inherent_expand() { Digest::default(), ), vec![UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: Some((1, (), ())), }], ); @@ -825,11 +825,11 @@ fn inherent_expand() { ), vec![ UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 1, bar: 1 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_storage_layer { foo: 0 }), + function: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), signature: None, }, ], @@ -847,15 +847,15 @@ fn inherent_expand() { ), vec![ UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 1, bar: 1 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_storage_layer { foo: 0 }), + function: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: None, }, ], @@ -873,15 +873,15 @@ fn inherent_expand() { ), vec![ UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 1, bar: 1 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 1, bar: 0 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 0 }), signature: Some((1, (), ())), }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: None, }, ], @@ -925,7 +925,7 @@ fn pallet_expand_deposit_event() { .unwrap(); assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Example(pallet::Event::Something(3)), + RuntimeEvent::Example(pallet::Event::Something(3)), ); }) } @@ -1064,27 +1064,27 @@ fn pallet_hooks_expand() { assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Example(pallet::Event::Something(10)), + RuntimeEvent::Example(pallet::Event::Something(10)), ); assert_eq!( frame_system::Pallet::::events()[1].event, - Event::Example2(pallet2::Event::Something(11)), + RuntimeEvent::Example2(pallet2::Event::Something(11)), ); assert_eq!( frame_system::Pallet::::events()[2].event, - Event::Example(pallet::Event::Something(20)), + RuntimeEvent::Example(pallet::Event::Something(20)), ); assert_eq!( frame_system::Pallet::::events()[3].event, - Event::Example2(pallet2::Event::Something(21)), + RuntimeEvent::Example2(pallet2::Event::Something(21)), ); assert_eq!( frame_system::Pallet::::events()[4].event, - Event::Example(pallet::Event::Something(30)), + RuntimeEvent::Example(pallet::Event::Something(30)), ); assert_eq!( frame_system::Pallet::::events()[5].event, - Event::Example2(pallet2::Event::Something(31)), + RuntimeEvent::Example2(pallet2::Event::Something(31)), ); }) } @@ -1110,27 +1110,27 @@ fn all_pallets_type_reversed_order_is_correct() { assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Example2(pallet2::Event::Something(11)), + RuntimeEvent::Example2(pallet2::Event::Something(11)), ); assert_eq!( frame_system::Pallet::::events()[1].event, - Event::Example(pallet::Event::Something(10)), + RuntimeEvent::Example(pallet::Event::Something(10)), ); assert_eq!( frame_system::Pallet::::events()[2].event, - Event::Example2(pallet2::Event::Something(21)), + RuntimeEvent::Example2(pallet2::Event::Something(21)), ); assert_eq!( frame_system::Pallet::::events()[3].event, - Event::Example(pallet::Event::Something(20)), + RuntimeEvent::Example(pallet::Event::Something(20)), ); assert_eq!( frame_system::Pallet::::events()[4].event, - Event::Example2(pallet2::Event::Something(31)), + RuntimeEvent::Example2(pallet2::Event::Something(31)), ); assert_eq!( frame_system::Pallet::::events()[5].event, - Event::Example(pallet::Event::Something(30)), + RuntimeEvent::Example(pallet::Event::Something(30)), ); }) } diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index dc107b345c2b8..2342f25fb98b9 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -43,7 +43,7 @@ mod pallet_old { + Into + Default + SomeAssociation; - type Event: From> + Into<::Event>; + type RuntimeEvent: From> + Into<::RuntimeEvent>; } decl_storage! { @@ -120,7 +120,7 @@ pub mod pallet { + scale_info::StaticTypeInfo; #[pallet::constant] type SomeConst: Get; - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -229,13 +229,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type BlockWeights = (); type BlockLength = (); @@ -251,19 +251,19 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime where diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 428de08864f29..b89ab410621e5 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -30,7 +30,7 @@ mod pallet_old { pub trait Config: frame_system::Config { type SomeConst: Get; type Balance: Parameter + codec::HasCompact + From + Into + Default; - type Event: From> + Into<::Event>; + type RuntimeEvent: From> + Into<::RuntimeEvent>; } decl_storage! { @@ -105,7 +105,8 @@ pub mod pallet { + scale_info::StaticTypeInfo; #[pallet::constant] type SomeConst: Get; - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -212,13 +213,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type Version = (); type PalletInfo = PalletInfo; @@ -231,39 +232,39 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime where diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 2ae910e73d87e..f01ce17d71bf9 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -42,7 +42,8 @@ pub mod pallet { #[pallet::constant] type MyGetParam: Get; type Balance: Parameter + Default + scale_info::StaticTypeInfo; - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -253,7 +254,8 @@ pub mod pallet2 { #[pallet::config] pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -288,13 +290,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type BlockWeights = (); type BlockLength = (); @@ -310,25 +312,25 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MyGetParam = ConstU32<10>; type Balance = u64; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MyGetParam = ConstU32<10>; type Balance = u64; } impl pallet2::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } impl pallet2::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime where @@ -433,7 +435,7 @@ fn pallet_expand_deposit_event() { .unwrap(); assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Example(pallet::Event::Something(3)), + RuntimeEvent::Example(pallet::Event::Something(3)), ); }); @@ -444,7 +446,7 @@ fn pallet_expand_deposit_event() { .unwrap(); assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Instance1Example(pallet::Event::Something(3)), + RuntimeEvent::Instance1Example(pallet::Event::Something(3)), ); }); } @@ -668,27 +670,27 @@ fn pallet_hooks_expand() { assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Example(pallet::Event::Something(10)), + RuntimeEvent::Example(pallet::Event::Something(10)), ); assert_eq!( frame_system::Pallet::::events()[1].event, - Event::Instance1Example(pallet::Event::Something(11)), + RuntimeEvent::Instance1Example(pallet::Event::Something(11)), ); assert_eq!( frame_system::Pallet::::events()[2].event, - Event::Example(pallet::Event::Something(20)), + RuntimeEvent::Example(pallet::Event::Something(20)), ); assert_eq!( frame_system::Pallet::::events()[3].event, - Event::Instance1Example(pallet::Event::Something(21)), + RuntimeEvent::Instance1Example(pallet::Event::Something(21)), ); assert_eq!( frame_system::Pallet::::events()[4].event, - Event::Example(pallet::Event::Something(30)), + RuntimeEvent::Example(pallet::Event::Something(30)), ); assert_eq!( frame_system::Pallet::::events()[5].event, - Event::Instance1Example(pallet::Event::Something(31)), + RuntimeEvent::Instance1Example(pallet::Event::Something(31)), ); }) } diff --git a/frame/support/test/tests/pallet_ui/event_field_not_member.rs b/frame/support/test/tests/pallet_ui/event_field_not_member.rs index 0ecde4c130878..2b45a971788fb 100644 --- a/frame/support/test/tests/pallet_ui/event_field_not_member.rs +++ b/frame/support/test/tests/pallet_ui/event_field_not_member.rs @@ -6,7 +6,7 @@ mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type Bar; - type Event: IsType<::Event> + From>; + type RuntimeEvent: IsType<::RuntimeEvent> + From>; } #[pallet::pallet] diff --git a/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr b/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr index e3126ad6a85dc..2eda72eb5f72f 100644 --- a/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr +++ b/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr @@ -1,4 +1,4 @@ -error: Invalid usage of Event, `Config` contains no associated type `Event`, but enum `Event` is declared (in use of `#[pallet::event]`). An Event associated type must be declare on trait `Config`. +error: Invalid usage of RuntimeEvent, `Config` contains no associated type `RuntimeEvent`, but enum `Event` is declared (in use of `#[pallet::event]`). An RuntimeEvent associated type must be declare on trait `Config`. --> $DIR/event_not_in_trait.rs:1:1 | 1 | #[frame_support::pallet] diff --git a/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs b/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs index fa3bf04d3530d..a02cc9b9de883 100644 --- a/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs +++ b/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs @@ -6,7 +6,7 @@ mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type Bar; - type Event; + type RuntimeEvent; } #[pallet::pallet] diff --git a/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr b/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr index 1f58a37576d0d..d54149d719a3b 100644 --- a/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr +++ b/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr @@ -1,5 +1,5 @@ -error: Invalid `type Event`, associated type `Event` is reserved and must bound: `IsType<::Event>` +error: Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must bound: `IsType<::RuntimeEvent>` --> $DIR/event_type_invalid_bound.rs:9:3 | -9 | type Event; +9 | type RuntimeEvent; | ^^^^ diff --git a/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs b/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs index 564a539b89f57..99df89d67278c 100644 --- a/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs +++ b/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs @@ -6,7 +6,7 @@ mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type Bar; - type Event: IsType<::Event>; + type RuntimeEvent: IsType<::RuntimeEvent>; } #[pallet::pallet] diff --git a/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr index 8b8946f3b25eb..ea8b2ff000ceb 100644 --- a/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr @@ -1,5 +1,5 @@ -error: Invalid `type Event`, associated type `Event` is reserved and must bound: `From` or `From>` or `From>` +error: Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must bound: `From` or `From>` or `From>` --> $DIR/event_type_invalid_bound_2.rs:9:3 | -9 | type Event: IsType<::Event>; +9 | type RuntimeEvent: IsType<::RuntimeEvent>; | ^^^^ diff --git a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs index 6415c3c0d2c07..788e852ba58e9 100644 --- a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs +++ b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs @@ -18,7 +18,7 @@ pub trait Trait: frame_system::Config { type Balance: frame_support::dispatch::Parameter; /// The overarching event type. - type Event: From> + Into<::Event>; + type RuntimeEvent: From> + Into<::RuntimeEvent>; } frame_support::decl_storage! { @@ -108,7 +108,7 @@ mod tests { type TestHeader = sp_runtime::generic::Header; type TestUncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic< ::AccountId, - ::Call, + ::RuntimeCall, (), SignedExtra, >; @@ -130,12 +130,12 @@ mod tests { type Index = u64; type BlockNumber = u64; type Hash = sp_core::H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = TestHeader; - type Event = (); + type RuntimeEvent = (); type BlockHashCount = ConstU64<250>; type DbWeight = (); type BlockWeights = (); @@ -153,6 +153,6 @@ mod tests { impl pallet_test::Trait for Runtime { type Balance = u32; - type Event = (); + type RuntimeEvent = (); } } diff --git a/frame/support/test/tests/storage_layers.rs b/frame/support/test/tests/storage_layers.rs index 7404ccace2c09..a3e512302fe4f 100644 --- a/frame/support/test/tests/storage_layers.rs +++ b/frame/support/test/tests/storage_layers.rs @@ -79,7 +79,7 @@ pub type BlockNumber = u64; pub type Index = u64; pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; impl frame_system::Config for Runtime { type BlockWeights = (); @@ -89,13 +89,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type Version = (); type PalletInfo = PalletInfo; @@ -255,11 +255,11 @@ fn storage_layer_commit_then_rollback() { fn storage_layer_in_pallet_call() { TestExternalities::default().execute_with(|| { use sp_runtime::traits::Dispatchable; - let call1 = Call::MyPallet(pallet::Call::set_value { value: 2 }); + let call1 = RuntimeCall::MyPallet(pallet::Call::set_value { value: 2 }); assert_ok!(call1.dispatch(Origin::signed(0))); assert_eq!(Value::::get(), 2); - let call2 = Call::MyPallet(pallet::Call::set_value { value: 1 }); + let call2 = RuntimeCall::MyPallet(pallet::Call::set_value { value: 1 }); assert_noop!(call2.dispatch(Origin::signed(0)), Error::::Revert); }); } @@ -270,11 +270,11 @@ fn storage_layer_in_decl_pallet_call() { use frame_support::StorageValue; use sp_runtime::traits::Dispatchable; - let call1 = Call::DeclPallet(decl_pallet::Call::set_value { value: 2 }); + let call1 = RuntimeCall::DeclPallet(decl_pallet::Call::set_value { value: 2 }); assert_ok!(call1.dispatch(Origin::signed(0))); assert_eq!(decl_pallet::DeclValue::get(), 2); - let call2 = Call::DeclPallet(decl_pallet::Call::set_value { value: 1 }); + let call2 = RuntimeCall::DeclPallet(decl_pallet::Call::set_value { value: 1 }); assert_noop!(call2.dispatch(Origin::signed(0)), "Revert!"); // Calling the function directly also works with storage layers. assert_noop!(decl_pallet::Module::::set_value(Origin::signed(1), 1), "Revert!"); diff --git a/frame/support/test/tests/system.rs b/frame/support/test/tests/system.rs index b30fd8d5ec561..9736c74dc236d 100644 --- a/frame/support/test/tests/system.rs +++ b/frame/support/test/tests/system.rs @@ -25,12 +25,12 @@ pub trait Config: 'static + Eq + Clone { type Origin: Into, Self::Origin>> + From>; - type BaseCallFilter: frame_support::traits::Contains; + type BaseCallFilter: frame_support::traits::Contains; type BlockNumber: Decode + Encode + EncodeLike + Clone + Default + scale_info::TypeInfo; type Hash; type AccountId: Encode + EncodeLike + Decode + scale_info::TypeInfo; - type Call; - type Event: From>; + type RuntimeCall; + type RuntimeEvent: From>; type PalletInfo: frame_support::traits::PalletInfo; type DbWeight: Get; } @@ -43,7 +43,7 @@ frame_support::decl_module! { } impl Module { - pub fn deposit_event(_event: impl Into) {} + pub fn deposit_event(_event: impl Into) {} } frame_support::decl_event!( diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index 017298dab3928..03d3a65812d56 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -37,7 +37,7 @@ mod module { #[pallet::config] pub trait Config: frame_system::Config { - type Event: From + IsType<::Event>; + type RuntimeEvent: From + IsType<::RuntimeEvent>; } #[pallet::event] @@ -79,13 +79,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -99,7 +99,7 @@ impl frame_system::Config for Runtime { } impl module::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/system/benchmarking/src/mock.rs b/frame/system/benchmarking/src/mock.rs index 08b043ae62741..1c0a7efa03735 100644 --- a/frame/system/benchmarking/src/mock.rs +++ b/frame/system/benchmarking/src/mock.rs @@ -46,13 +46,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/system/src/extensions/check_genesis.rs b/frame/system/src/extensions/check_genesis.rs index a0679b11487f6..f5811f306cfe3 100644 --- a/frame/system/src/extensions/check_genesis.rs +++ b/frame/system/src/extensions/check_genesis.rs @@ -54,7 +54,7 @@ impl CheckGenesis { impl SignedExtension for CheckGenesis { type AccountId = T::AccountId; - type Call = ::Call; + type Call = ::RuntimeCall; type AdditionalSigned = T::Hash; type Pre = (); const IDENTIFIER: &'static str = "CheckGenesis"; diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index 59a6e14aca175..f515f1ae0fa27 100644 --- a/frame/system/src/extensions/check_mortality.rs +++ b/frame/system/src/extensions/check_mortality.rs @@ -56,7 +56,7 @@ impl sp_std::fmt::Debug for CheckMortality { impl SignedExtension for CheckMortality { type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = T::Hash; type Pre = (); const IDENTIFIER: &'static str = "CheckMortality"; diff --git a/frame/system/src/extensions/check_non_zero_sender.rs b/frame/system/src/extensions/check_non_zero_sender.rs index 9a6c4007b3779..093424999aab3 100644 --- a/frame/system/src/extensions/check_non_zero_sender.rs +++ b/frame/system/src/extensions/check_non_zero_sender.rs @@ -53,10 +53,10 @@ impl CheckNonZeroSender { impl SignedExtension for CheckNonZeroSender where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = (); type Pre = (); const IDENTIFIER: &'static str = "CheckNonZeroSender"; diff --git a/frame/system/src/extensions/check_nonce.rs b/frame/system/src/extensions/check_nonce.rs index 476aa2fb7478c..7259b80013ae5 100644 --- a/frame/system/src/extensions/check_nonce.rs +++ b/frame/system/src/extensions/check_nonce.rs @@ -60,10 +60,10 @@ impl sp_std::fmt::Debug for CheckNonce { impl SignedExtension for CheckNonce where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = (); type Pre = (); const IDENTIFIER: &'static str = "CheckNonce"; diff --git a/frame/system/src/extensions/check_spec_version.rs b/frame/system/src/extensions/check_spec_version.rs index 0280d31f657ae..ef5f40402692c 100644 --- a/frame/system/src/extensions/check_spec_version.rs +++ b/frame/system/src/extensions/check_spec_version.rs @@ -54,7 +54,7 @@ impl CheckSpecVersion { impl SignedExtension for CheckSpecVersion { type AccountId = T::AccountId; - type Call = ::Call; + type Call = ::RuntimeCall; type AdditionalSigned = u32; type Pre = (); const IDENTIFIER: &'static str = "CheckSpecVersion"; diff --git a/frame/system/src/extensions/check_tx_version.rs b/frame/system/src/extensions/check_tx_version.rs index b92d8978bde01..be0b8fe2354aa 100644 --- a/frame/system/src/extensions/check_tx_version.rs +++ b/frame/system/src/extensions/check_tx_version.rs @@ -54,7 +54,7 @@ impl CheckTxVersion { impl SignedExtension for CheckTxVersion { type AccountId = T::AccountId; - type Call = ::Call; + type Call = ::RuntimeCall; type AdditionalSigned = u32; type Pre = (); const IDENTIFIER: &'static str = "CheckTxVersion"; diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index 6e73a9e40179f..9af79e480b394 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -40,12 +40,12 @@ pub struct CheckWeight(sp_std::marker::PhantomData); impl CheckWeight where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { /// Checks if the current extrinsic does not exceed the maximum weight a single extrinsic /// with given `DispatchClass` can have. fn check_extrinsic_weight( - info: &DispatchInfoOf, + info: &DispatchInfoOf, ) -> Result<(), TransactionValidityError> { let max = T::BlockWeights::get().get(info.class).max_extrinsic; match max { @@ -59,18 +59,18 @@ where /// /// Upon successes, it returns the new block weight as a `Result`. fn check_block_weight( - info: &DispatchInfoOf, + info: &DispatchInfoOf, ) -> Result { let maximum_weight = T::BlockWeights::get(); let all_weight = Pallet::::block_weight(); - calculate_consumed_weight::(maximum_weight, all_weight, info) + calculate_consumed_weight::(maximum_weight, all_weight, info) } /// Checks if the current extrinsic can fit into the block with respect to block length limits. /// /// Upon successes, it returns the new block length as a `Result`. fn check_block_length( - info: &DispatchInfoOf, + info: &DispatchInfoOf, len: usize, ) -> Result { let length_limit = T::BlockLength::get(); @@ -93,7 +93,7 @@ where /// /// It checks and notes the new weight and length. pub fn do_pre_dispatch( - info: &DispatchInfoOf, + info: &DispatchInfoOf, len: usize, ) -> Result<(), TransactionValidityError> { let next_len = Self::check_block_length(info, len)?; @@ -108,7 +108,7 @@ where /// Do the validate checks. This can be applied to both signed and unsigned. /// /// It only checks that the block weight and length limit will not exceed. - pub fn do_validate(info: &DispatchInfoOf, len: usize) -> TransactionValidity { + pub fn do_validate(info: &DispatchInfoOf, len: usize) -> TransactionValidity { // ignore the next length. If they return `Ok`, then it is below the limit. let _ = Self::check_block_length(info, len)?; // during validation we skip block limit check. Since the `validate_transaction` @@ -170,10 +170,10 @@ where impl SignedExtension for CheckWeight where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = (); type Pre = (); const IDENTIFIER: &'static str = "CheckWeight"; @@ -713,13 +713,13 @@ mod tests { }; // when - assert_ok!(calculate_consumed_weight::<::Call>( + assert_ok!(calculate_consumed_weight::<::RuntimeCall>( maximum_weight.clone(), all_weight.clone(), &mandatory1 )); assert_err!( - calculate_consumed_weight::<::Call>( + calculate_consumed_weight::<::RuntimeCall>( maximum_weight, all_weight, &mandatory2 diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index ba076d963bda7..550e3939f995a 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -205,7 +205,7 @@ pub mod pallet { pub trait Config: 'static + Eq + Clone { /// The basic call filter to use in Origin. All origins are built with this filter as base, /// except Root. - type BaseCallFilter: Contains; + type BaseCallFilter: Contains; /// Block & extrinsics weights: base values and limits. #[pallet::constant] @@ -219,10 +219,10 @@ pub mod pallet { type Origin: Into, Self::Origin>> + From> + Clone - + OriginTrait; + + OriginTrait; - /// The aggregated `Call` type. - type Call: Dispatchable + Debug; + /// The aggregated `RuntimeCall` type. + type RuntimeCall: Dispatchable + Debug; /// Account index (aka nonce) type. This stores the number of previous transactions /// associated with a sender account. @@ -293,11 +293,11 @@ pub mod pallet { type Header: Parameter + traits::Header; /// The aggregated event type of the runtime. - type Event: Parameter + type RuntimeEvent: Parameter + Member + From> + Debug - + IsType<::Event>; + + IsType<::RuntimeEvent>; /// Maximum number of block number to block hash mappings to keep (oldest pruned first). #[pallet::constant] @@ -608,7 +608,7 @@ pub mod pallet { #[pallet::storage] #[pallet::unbounded] pub(super) type Events = - StorageValue<_, Vec>>, ValueQuery>; + StorageValue<_, Vec>>, ValueQuery>; /// The number of events in the `Events` list. #[pallet::storage] @@ -1216,7 +1216,7 @@ impl Pallet { } /// Deposits an event into this block's event record. - pub fn deposit_event(event: impl Into) { + pub fn deposit_event(event: impl Into) { Self::deposit_event_indexed(&[], event.into()); } @@ -1225,7 +1225,7 @@ impl Pallet { /// /// This will update storage entries that correspond to the specified topics. /// It is expected that light-clients could subscribe to this topics. - pub fn deposit_event_indexed(topics: &[T::Hash], event: T::Event) { + pub fn deposit_event_indexed(topics: &[T::Hash], event: T::RuntimeEvent) { let block_number = Self::block_number(); // Don't populate events on genesis. if block_number.is_zero() { @@ -1415,7 +1415,7 @@ impl Pallet { /// impact on the PoV size of a block. Users should use alternative and well bounded storage /// items for any behavior like this. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] - pub fn events() -> Vec> { + pub fn events() -> Vec> { // Dereferencing the events here is fine since we are not in the // memory-restricted runtime. Self::read_events_no_consensus().into_iter().map(|e| *e).collect() @@ -1425,7 +1425,7 @@ impl Pallet { /// /// Should only be called if you know what you are doing and outside of the runtime block /// execution else it can have a large impact on the PoV size of a block. - pub fn read_events_no_consensus() -> Vec>> { + pub fn read_events_no_consensus() -> Vec>> { Events::::get() } @@ -1470,13 +1470,13 @@ impl Pallet { /// Assert the given `event` exists. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] - pub fn assert_has_event(event: T::Event) { + pub fn assert_has_event(event: T::RuntimeEvent) { assert!(Self::events().iter().any(|record| record.event == event)) } /// Assert the last event equal to the given `event`. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] - pub fn assert_last_event(event: T::Event) { + pub fn assert_last_event(event: T::RuntimeEvent) { assert_eq!(Self::events().last().expect("events expected").event, event); } diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index 09a018e2be70e..fdaaceaf8abe0 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -94,7 +94,7 @@ impl Config for Test { type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -102,7 +102,7 @@ impl Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<10>; type DbWeight = DbWeight; type Version = Version; @@ -119,8 +119,8 @@ impl Config for Test { pub type SysEvent = frame_system::Event; /// A simple call, which one doesn't matter. -pub const CALL: &::Call = - &Call::System(frame_system::Call::set_heap_pages { pages: 0u64 }); +pub const CALL: &::RuntimeCall = + &RuntimeCall::System(frame_system::Call::set_heap_pages { pages: 0u64 }); /// Create new externalities for `System` module tests. pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/system/src/mocking.rs b/frame/system/src/mocking.rs index ccb63f9bb236c..d8cfcb9baf268 100644 --- a/frame/system/src/mocking.rs +++ b/frame/system/src/mocking.rs @@ -22,7 +22,7 @@ use sp_runtime::generic; /// An unchecked extrinsic type to be used in tests. pub type MockUncheckedExtrinsic = generic::UncheckedExtrinsic< ::AccountId, - ::Call, + ::RuntimeCall, Signature, Extra, >; diff --git a/frame/system/src/offchain.rs b/frame/system/src/offchain.rs index 86440188a765c..99a4c1541d30f 100644 --- a/frame/system/src/offchain.rs +++ b/frame/system/src/offchain.rs @@ -617,7 +617,7 @@ pub trait SignedPayload: Encode { #[cfg(test)] mod tests { use super::*; - use crate::mock::{Call, Test as TestRuntime, CALL}; + use crate::mock::{RuntimeCall, Test as TestRuntime, CALL}; use codec::Decode; use sp_core::offchain::{testing, TransactionPoolExt}; use sp_runtime::testing::{TestSignature, TestXt, UintAuthorityId}; @@ -627,11 +627,11 @@ mod tests { type Signature = TestSignature; } - type Extrinsic = TestXt; + type Extrinsic = TestXt; - impl SendTransactionTypes for TestRuntime { + impl SendTransactionTypes for TestRuntime { type Extrinsic = Extrinsic; - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; } #[derive(codec::Encode, codec::Decode)] diff --git a/frame/timestamp/src/mock.rs b/frame/timestamp/src/mock.rs index 1ea553aa548ec..7d3da0e8a0b83 100644 --- a/frame/timestamp/src/mock.rs +++ b/frame/timestamp/src/mock.rs @@ -58,13 +58,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index a4697284e38a0..9313a26e52e00 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -127,7 +127,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + pallet_treasury::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Maximum acceptable reason length. /// diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index b12885fc59f16..9b721bd77a8bc 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -68,13 +68,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -92,7 +92,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -133,7 +133,7 @@ impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -152,7 +152,7 @@ impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -176,7 +176,7 @@ impl Config for Test { type TipFindersFee = TipFindersFee; type TipReportDepositBase = ConstU64<1>; type DataDepositPerByte = ConstU64<1>; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -187,7 +187,7 @@ impl Config for Test { type TipFindersFee = TipFindersFee; type TipReportDepositBase = ConstU64<1>; type DataDepositPerByte = ConstU64<1>; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -209,7 +209,7 @@ fn last_event() -> TipEvent { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::Tips(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::Tips(inner) = e { Some(inner) } else { None }) .last() .unwrap() } diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index 08561375247ae..c14c7ba11b546 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -114,7 +114,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + pallet_transaction_payment::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The fungibles instance used to pay for transactions in assets. type Fungibles: Balanced; /// The actual transaction charging logic that charges the fees. @@ -154,7 +154,7 @@ pub struct ChargeAssetTxPayment { impl ChargeAssetTxPayment where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, AssetBalanceOf: Send + Sync + FixedPointOperand, BalanceOf: Send + Sync + FixedPointOperand + IsType>, ChargeAssetIdOf: Send + Sync, @@ -170,8 +170,8 @@ where fn withdraw_fee( &self, who: &T::AccountId, - call: &T::Call, - info: &DispatchInfoOf, + call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, ) -> Result<(BalanceOf, InitialPayment), TransactionValidityError> { let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); @@ -211,7 +211,7 @@ impl sp_std::fmt::Debug for ChargeAssetTxPayment { impl SignedExtension for ChargeAssetTxPayment where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, AssetBalanceOf: Send + Sync + FixedPointOperand, BalanceOf: Send + Sync + From + FixedPointOperand + IsType>, ChargeAssetIdOf: Send + Sync, @@ -219,7 +219,7 @@ where { const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = (); type Pre = ( // tip diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs index 394696cc18929..80ff4e40dcffa 100644 --- a/frame/transaction-payment/asset-tx-payment/src/payment.rs +++ b/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -54,8 +54,8 @@ pub trait OnChargeAssetTransaction { /// Note: The `fee` already includes the `tip`. fn withdraw_fee( who: &T::AccountId, - call: &T::Call, - dispatch_info: &DispatchInfoOf, + call: &T::RuntimeCall, + dispatch_info: &DispatchInfoOf, asset_id: Self::AssetId, fee: Self::Balance, tip: Self::Balance, @@ -68,8 +68,8 @@ pub trait OnChargeAssetTransaction { /// Note: The `fee` already includes the `tip`. fn correct_and_deposit_fee( who: &T::AccountId, - dispatch_info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + dispatch_info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, tip: Self::Balance, already_withdrawn: Self::LiquidityInfo, @@ -114,8 +114,8 @@ where /// Note: The `fee` already includes the `tip`. fn withdraw_fee( who: &T::AccountId, - _call: &T::Call, - _info: &DispatchInfoOf, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, asset_id: Self::AssetId, fee: Self::Balance, _tip: Self::Balance, @@ -142,8 +142,8 @@ where /// Note: The `corrected_fee` already includes the `tip`. fn correct_and_deposit_fee( who: &T::AccountId, - _dispatch_info: &DispatchInfoOf, - _post_info: &PostDispatchInfoOf, + _dispatch_info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, _tip: Self::Balance, paid: Self::LiquidityInfo, diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index dd7c086a82469..dfce28fda43d2 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -54,8 +54,8 @@ frame_support::construct_runtime!( } ); -const CALL: &::Call = - &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); +const CALL: &::RuntimeCall = + &RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); parameter_types! { static ExtrinsicBaseWeight: Weight = Weight::zero(); @@ -89,13 +89,13 @@ impl frame_system::Config for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -114,7 +114,7 @@ parameter_types! { impl pallet_balances::Config for Runtime { type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<10>; type AccountStore = System; @@ -143,7 +143,7 @@ impl WeightToFeeT for TransactionByteFee { } impl pallet_transaction_payment::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; @@ -152,7 +152,7 @@ impl pallet_transaction_payment::Config for Runtime { } impl pallet_assets::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Balance = Balance; type AssetId = u32; type Currency = Balances; @@ -198,7 +198,7 @@ impl HandleCredit for CreditToBlockAuthor { } impl Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; type OnChargeAssetTransaction = FungiblesAdapter< pallet_assets::BalanceToAssetBalance, diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index b3c53cc048bad..5f1f8321456be 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -282,7 +282,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Handler for withdrawing, refunding and depositing the transaction fee. /// Transaction fees are withdrawn before the transaction is executed. @@ -440,7 +440,7 @@ where len: u32, ) -> RuntimeDispatchInfo> where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { // NOTE: we can actually make it understand `ChargeTransactionPayment`, but would be some // hassle for sure. We have to make it aware of the index of `ChargeTransactionPayment` in @@ -467,7 +467,7 @@ where len: u32, ) -> FeeDetails> where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); @@ -482,11 +482,11 @@ where } /// Query information of a dispatch class, weight, and fee of a given encoded `Call`. - pub fn query_call_info(call: T::Call, len: u32) -> RuntimeDispatchInfo> + pub fn query_call_info(call: T::RuntimeCall, len: u32) -> RuntimeDispatchInfo> where - T::Call: Dispatchable + GetDispatchInfo, + T::RuntimeCall: Dispatchable + GetDispatchInfo, { - let dispatch_info = ::get_dispatch_info(&call); + let dispatch_info = ::get_dispatch_info(&call); let DispatchInfo { weight, class, .. } = dispatch_info; RuntimeDispatchInfo { @@ -497,20 +497,24 @@ where } /// Query fee details of a given encoded `Call`. - pub fn query_call_fee_details(call: T::Call, len: u32) -> FeeDetails> + pub fn query_call_fee_details(call: T::RuntimeCall, len: u32) -> FeeDetails> where - T::Call: Dispatchable + GetDispatchInfo, + T::RuntimeCall: Dispatchable + GetDispatchInfo, { - let dispatch_info = ::get_dispatch_info(&call); + let dispatch_info = ::get_dispatch_info(&call); let tip = 0u32.into(); Self::compute_fee_details(len, &dispatch_info, tip) } /// Compute the final fee value for a particular transaction. - pub fn compute_fee(len: u32, info: &DispatchInfoOf, tip: BalanceOf) -> BalanceOf + pub fn compute_fee( + len: u32, + info: &DispatchInfoOf, + tip: BalanceOf, + ) -> BalanceOf where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { Self::compute_fee_details(len, info, tip).final_fee() } @@ -518,11 +522,11 @@ where /// Compute the fee details for a particular transaction. pub fn compute_fee_details( len: u32, - info: &DispatchInfoOf, + info: &DispatchInfoOf, tip: BalanceOf, ) -> FeeDetails> where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { Self::compute_fee_raw(len, info.weight, tip, info.pays_fee, info.class) } @@ -533,12 +537,12 @@ where /// weight is used for the weight fee calculation. pub fn compute_actual_fee( len: u32, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, tip: BalanceOf, ) -> BalanceOf where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { Self::compute_actual_fee_details(len, info, post_info, tip).final_fee() } @@ -546,12 +550,12 @@ where /// Compute the actual post dispatch fee details for a particular transaction. pub fn compute_actual_fee_details( len: u32, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, tip: BalanceOf, ) -> FeeDetails> where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { Self::compute_fee_raw( len, @@ -632,7 +636,7 @@ pub struct ChargeTransactionPayment(#[codec(compact)] BalanceOf); impl ChargeTransactionPayment where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, BalanceOf: Send + Sync + FixedPointOperand, { /// utility constructor. Used only in client/factory code. @@ -648,8 +652,8 @@ where fn withdraw_fee( &self, who: &T::AccountId, - call: &T::Call, - info: &DispatchInfoOf, + call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, ) -> Result< ( @@ -681,7 +685,7 @@ where /// state of-the-art blockchains, number of per-block transactions is expected to be in a /// range reasonable enough to not saturate the `Balance` type while multiplying by the tip. pub fn get_priority( - info: &DispatchInfoOf, + info: &DispatchInfoOf, len: usize, tip: BalanceOf, final_fee: BalanceOf, @@ -755,11 +759,11 @@ impl sp_std::fmt::Debug for ChargeTransactionPayment { impl SignedExtension for ChargeTransactionPayment where BalanceOf: Send + Sync + From + FixedPointOperand, - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { const IDENTIFIER: &'static str = "ChargeTransactionPayment"; type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = (); type Pre = ( // tip @@ -821,7 +825,7 @@ impl EstimateCallFee where BalanceOf: FixedPointOperand, - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { fn estimate_call_fee(call: &AnyCall, post_info: PostDispatchInfo) -> BalanceOf { let len = call.encoded_size() as u32; @@ -870,8 +874,8 @@ mod tests { } ); - const CALL: &::Call = - &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + const CALL: &::RuntimeCall = + &RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); parameter_types! { static ExtrinsicBaseWeight: Weight = Weight::zero(); @@ -906,13 +910,13 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -927,7 +931,7 @@ mod tests { impl pallet_balances::Config for Runtime { type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -975,7 +979,7 @@ mod tests { } impl Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = WeightToFee; @@ -1238,7 +1242,7 @@ mod tests { #[test] fn query_info_and_fee_details_works() { - let call = Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + let call = RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); let origin = 111111; let extra = (); let xt = TestXt::new(call.clone(), Some((origin, extra))); @@ -1301,7 +1305,7 @@ mod tests { #[test] fn query_call_info_and_fee_details_works() { - let call = Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + let call = RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); let info = call.get_dispatch_info(); let encoded_call = call.encode(); let len = encoded_call.len() as u32; @@ -1495,13 +1499,11 @@ mod tests { )); assert_eq!(Balances::free_balance(2), 0); // Transfer Event - System::assert_has_event(Event::Balances(pallet_balances::Event::Transfer { - from: 2, - to: 3, - amount: 80, - })); + System::assert_has_event(RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from: 2, to: 3, amount: 80 }, + )); // Killed Event - System::assert_has_event(Event::System(system::Event::KilledAccount { + System::assert_has_event(RuntimeEvent::System(system::Event::KilledAccount { account: 2, })); }); @@ -1560,7 +1562,7 @@ mod tests { )); assert_eq!(Balances::total_balance(&user), 0); // TransactionFeePaid Event - System::assert_has_event(Event::TransactionPayment( + System::assert_has_event(RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: user, actual_fee: 0, diff --git a/frame/transaction-payment/src/payment.rs b/frame/transaction-payment/src/payment.rs index 3a5fad0d66a52..ebc9c5c5afd62 100644 --- a/frame/transaction-payment/src/payment.rs +++ b/frame/transaction-payment/src/payment.rs @@ -37,8 +37,8 @@ pub trait OnChargeTransaction { /// Note: The `fee` already includes the `tip`. fn withdraw_fee( who: &T::AccountId, - call: &T::Call, - dispatch_info: &DispatchInfoOf, + call: &T::RuntimeCall, + dispatch_info: &DispatchInfoOf, fee: Self::Balance, tip: Self::Balance, ) -> Result; @@ -50,8 +50,8 @@ pub trait OnChargeTransaction { /// Note: The `fee` already includes the `tip`. fn correct_and_deposit_fee( who: &T::AccountId, - dispatch_info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + dispatch_info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, tip: Self::Balance, already_withdrawn: Self::LiquidityInfo, @@ -92,8 +92,8 @@ where /// Note: The `fee` already includes the `tip`. fn withdraw_fee( who: &T::AccountId, - _call: &T::Call, - _info: &DispatchInfoOf, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, fee: Self::Balance, tip: Self::Balance, ) -> Result { @@ -120,8 +120,8 @@ where /// Note: The `corrected_fee` already includes the `tip`. fn correct_and_deposit_fee( who: &T::AccountId, - _dispatch_info: &DispatchInfoOf, - _post_info: &PostDispatchInfoOf, + _dispatch_info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, tip: Self::Balance, already_withdrawn: Self::LiquidityInfo, diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs index 83dd37922a31f..cab4c92317bb5 100644 --- a/frame/transaction-storage/src/benchmarking.rs +++ b/frame/transaction-storage/src/benchmarking.rs @@ -105,9 +105,9 @@ const PROOF: &[u8] = &hex_literal::hex!( type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { let events = System::::events(); - let system_event: ::Event = generic_event.into(); + let system_event: ::RuntimeEvent = generic_event.into(); let EventRecord { event, .. } = &events[events.len() - 1]; assert_eq!(event, &system_event); } diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index 681cd29af8222..e623079ac863b 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -92,9 +92,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// A dispatchable call. - type Call: Parameter + type RuntimeCall: Parameter + Dispatchable + GetDispatchInfo + From>; diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs index 771387ef705be..1cb725e63e83b 100644 --- a/frame/transaction-storage/src/mock.rs +++ b/frame/transaction-storage/src/mock.rs @@ -52,7 +52,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -60,7 +60,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -77,7 +77,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -87,8 +87,8 @@ impl pallet_balances::Config for Test { } impl pallet_transaction_storage::Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type FeeDestination = (); type WeightInfo = (); diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index b2b670d86f07c..b3787e2063c45 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -61,7 +61,7 @@ fn setup_pot_account, I: 'static>() { let _ = T::Currency::make_free_balance_be(&pot_account, value); } -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index cd4d9cf036abe..bebbcda2effb6 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -155,7 +155,8 @@ pub mod pallet { type RejectOrigin: EnsureOrigin; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Handler for the unbalanced decrease when slashing for a rejected proposal or bounty. type OnSlash: OnUnbalanced>; diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index c9c6d01f129e6..af77b419d67d2 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -63,13 +63,13 @@ impl frame_system::Config for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -86,7 +86,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -121,7 +121,7 @@ impl Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 3e3148b5b5fc2..ab34558f95eb3 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -126,9 +126,9 @@ fn add_item_attribute, I: 'static>( (key, caller, caller_lookup) } -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { let events = frame_system::Pallet::::events(); - let system_event: ::Event = generic_event.into(); + let system_event: ::RuntimeEvent = generic_event.into(); // compare to the last event record let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; assert_eq!(event, &system_event); diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index bbecb08e51b3b..e25607e67a224 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -91,7 +91,8 @@ pub mod pallet { /// The module configuration trait. pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Identifier for the collection of item. type CollectionId: Member + Parameter + MaxEncodedLen + Copy; diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index ff7b791de4950..6808c48007a92 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -50,7 +50,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type Origin = Origin; - type Call = Call; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -58,7 +58,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -75,7 +75,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -85,7 +85,7 @@ impl pallet_balances::Config for Test { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type CollectionId = u32; type ItemId = u32; type Currency = Balances; diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 85d1bec574cf0..5ac677758316a 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -74,7 +74,7 @@ fn events() -> Vec> { let result = System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let mock::Event::Uniques(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let mock::RuntimeEvent::Uniques(inner) = e { Some(inner) } else { None }) .collect::>(); System::reset_events(); @@ -887,7 +887,7 @@ fn buy_item_should_work() { // freeze collection assert_ok!(Uniques::freeze_collection(Origin::signed(user_1), collection_id)); - let buy_item_call = mock::Call::Uniques(crate::Call::::buy_item { + let buy_item_call = mock::RuntimeCall::Uniques(crate::Call::::buy_item { collection: collection_id, item: item_3, bid_price: price_1, @@ -899,7 +899,7 @@ fn buy_item_should_work() { // freeze item assert_ok!(Uniques::freeze(Origin::signed(user_1), collection_id, item_3)); - let buy_item_call = mock::Call::Uniques(crate::Call::::buy_item { + let buy_item_call = mock::RuntimeCall::Uniques(crate::Call::::buy_item { collection: collection_id, item: item_3, bid_price: price_1, diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index 018280f69baeb..c29eded25aa5b 100644 --- a/frame/utility/src/benchmarking.rs +++ b/frame/utility/src/benchmarking.rs @@ -25,7 +25,7 @@ use frame_system::RawOrigin; const SEED: u32 = 0; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -33,7 +33,7 @@ benchmarks! { where_clause { where ::PalletsOrigin: Clone } batch { let c in 0 .. 1000; - let mut calls: Vec<::Call> = Vec::new(); + let mut calls: Vec<::RuntimeCall> = Vec::new(); for i in 0 .. c { let call = frame_system::Call::remark { remark: vec![] }.into(); calls.push(call); @@ -54,7 +54,7 @@ benchmarks! { batch_all { let c in 0 .. 1000; - let mut calls: Vec<::Call> = Vec::new(); + let mut calls: Vec<::RuntimeCall> = Vec::new(); for i in 0 .. c { let call = frame_system::Call::remark { remark: vec![] }.into(); calls.push(call); @@ -75,7 +75,7 @@ benchmarks! { force_batch { let c in 0 .. 1000; - let mut calls: Vec<::Call> = Vec::new(); + let mut calls: Vec<::RuntimeCall> = Vec::new(); for i in 0 .. c { let call = frame_system::Call::remark { remark: vec![] }.into(); calls.push(call); diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 2209bc65d4958..b5bd686b59f00 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -84,16 +84,16 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From + IsType<::Event>; + type RuntimeEvent: From + IsType<::RuntimeEvent>; /// The overarching call type. - type Call: Parameter + type RuntimeCall: Parameter + Dispatchable + GetDispatchInfo + From> + UnfilteredDispatchable + IsSubType> - + IsType<::Call>; + + IsType<::RuntimeCall>; /// The caller origin, overarching type of all pallets origins. type PalletsOrigin: Parameter + @@ -133,8 +133,9 @@ pub mod pallet { /// The limit on the number of batched calls. fn batched_calls_limit() -> u32 { let allocator_limit = sp_core::MAX_POSSIBLE_ALLOCATION; - let call_size = ((sp_std::mem::size_of::<::Call>() as u32 + CALL_ALIGN - - 1) / CALL_ALIGN) * CALL_ALIGN; + let call_size = ((sp_std::mem::size_of::<::RuntimeCall>() as u32 + + CALL_ALIGN - 1) / CALL_ALIGN) * + CALL_ALIGN; // The margin to take into account vec doubling capacity. let margin_factor = 3; @@ -147,7 +148,7 @@ pub mod pallet { fn integrity_test() { // If you hit this error, you need to try to `Box` big dispatchable parameters. assert!( - sp_std::mem::size_of::<::Call>() as u32 <= CALL_ALIGN, + sp_std::mem::size_of::<::RuntimeCall>() as u32 <= CALL_ALIGN, "Call enum size should be smaller than {} bytes.", CALL_ALIGN, ); @@ -201,7 +202,7 @@ pub mod pallet { })] pub fn batch( origin: OriginFor, - calls: Vec<::Call>, + calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { let is_root = ensure_root(origin.clone()).is_ok(); let calls_len = calls.len(); @@ -262,7 +263,7 @@ pub mod pallet { pub fn as_derivative( origin: OriginFor, index: u16, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { let mut origin = origin; let who = ensure_signed(origin.clone())?; @@ -317,7 +318,7 @@ pub mod pallet { })] pub fn batch_all( origin: OriginFor, - calls: Vec<::Call>, + calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { let is_root = ensure_root(origin.clone()).is_ok(); let calls_len = calls.len(); @@ -333,10 +334,12 @@ pub mod pallet { } else { let mut filtered_origin = origin.clone(); // Don't allow users to nest `batch_all` calls. - filtered_origin.add_filter(move |c: &::Call| { - let c = ::Call::from_ref(c); - !matches!(c.is_sub_type(), Some(Call::batch_all { .. })) - }); + filtered_origin.add_filter( + move |c: &::RuntimeCall| { + let c = ::RuntimeCall::from_ref(c); + !matches!(c.is_sub_type(), Some(Call::batch_all { .. })) + }, + ); call.dispatch(filtered_origin) }; // Add the weight of this call. @@ -376,7 +379,7 @@ pub mod pallet { pub fn dispatch_as( origin: OriginFor, as_origin: Box, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResult { ensure_root(origin)?; @@ -422,7 +425,7 @@ pub mod pallet { })] pub fn force_batch( origin: OriginFor, - calls: Vec<::Call>, + calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { let is_root = ensure_root(origin.clone()).is_ok(); let calls_len = calls.len(); diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 09a2c6a4e4d38..1985cc3022114 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -110,12 +110,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -134,7 +134,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -148,23 +148,23 @@ parameter_types! { impl example::Config for Test {} pub struct TestBaseCallFilter; -impl Contains for TestBaseCallFilter { - fn contains(c: &Call) -> bool { +impl Contains for TestBaseCallFilter { + fn contains(c: &RuntimeCall) -> bool { match *c { // Transfer works. Use `transfer_keep_alive` for a call that doesn't pass the filter. - Call::Balances(pallet_balances::Call::transfer { .. }) => true, - Call::Utility(_) => true, + RuntimeCall::Balances(pallet_balances::Call::transfer { .. }) => true, + RuntimeCall::Utility(_) => true, // For benchmarking, this acts as a noop call - Call::System(frame_system::Call::remark { .. }) => true, + RuntimeCall::System(frame_system::Call::remark { .. }) => true, // For tests - Call::Example(_) => true, + RuntimeCall::Example(_) => true, _ => false, } } } impl Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; type WeightInfo = (); } @@ -187,12 +187,12 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ext } -fn call_transfer(dest: u64, value: u64) -> Call { - Call::Balances(BalancesCall::transfer { dest, value }) +fn call_transfer(dest: u64, value: u64) -> RuntimeCall { + RuntimeCall::Balances(BalancesCall::transfer { dest, value }) } -fn call_foobar(err: bool, start_weight: Weight, end_weight: Option) -> Call { - Call::Example(ExampleCall::foobar { err, start_weight, end_weight }) +fn call_foobar(err: bool, start_weight: Weight, end_weight: Option) -> RuntimeCall { + RuntimeCall::Example(ExampleCall::foobar { err, start_weight, end_weight }) } #[test] @@ -219,8 +219,10 @@ fn as_derivative_handles_weight_refund() { // Full weight when ok let inner_call = call_foobar(false, start_weight, None); - let call = - Call::Utility(UtilityCall::as_derivative { index: 0, call: Box::new(inner_call) }); + let call = RuntimeCall::Utility(UtilityCall::as_derivative { + index: 0, + call: Box::new(inner_call), + }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_ok!(result); @@ -228,8 +230,10 @@ fn as_derivative_handles_weight_refund() { // Refund weight when ok let inner_call = call_foobar(false, start_weight, Some(end_weight)); - let call = - Call::Utility(UtilityCall::as_derivative { index: 0, call: Box::new(inner_call) }); + let call = RuntimeCall::Utility(UtilityCall::as_derivative { + index: 0, + call: Box::new(inner_call), + }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_ok!(result); @@ -238,8 +242,10 @@ fn as_derivative_handles_weight_refund() { // Full weight when err let inner_call = call_foobar(true, start_weight, None); - let call = - Call::Utility(UtilityCall::as_derivative { index: 0, call: Box::new(inner_call) }); + let call = RuntimeCall::Utility(UtilityCall::as_derivative { + index: 0, + call: Box::new(inner_call), + }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_noop!( @@ -256,8 +262,10 @@ fn as_derivative_handles_weight_refund() { // Refund weight when err let inner_call = call_foobar(true, start_weight, Some(end_weight)); - let call = - Call::Utility(UtilityCall::as_derivative { index: 0, call: Box::new(inner_call) }); + let call = RuntimeCall::Utility(UtilityCall::as_derivative { + index: 0, + call: Box::new(inner_call), + }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_noop!( @@ -281,7 +289,7 @@ fn as_derivative_filters() { Utility::as_derivative( Origin::signed(1), 1, - Box::new(Call::Balances(pallet_balances::Call::transfer_keep_alive { + Box::new(RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { dest: 2, value: 1 })), @@ -295,16 +303,25 @@ fn as_derivative_filters() { fn batch_with_root_works() { new_test_ext().execute_with(|| { let k = b"a".to_vec(); - let call = - Call::System(frame_system::Call::set_storage { items: vec![(k.clone(), k.clone())] }); + let call = RuntimeCall::System(frame_system::Call::set_storage { + items: vec![(k.clone(), k.clone())], + }); assert!(!TestBaseCallFilter::contains(&call)); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::batch( Origin::root(), vec![ - Call::Balances(BalancesCall::force_transfer { source: 1, dest: 2, value: 5 }), - Call::Balances(BalancesCall::force_transfer { source: 1, dest: 2, value: 5 }), + RuntimeCall::Balances(BalancesCall::force_transfer { + source: 1, + dest: 2, + value: 5 + }), + RuntimeCall::Balances(BalancesCall::force_transfer { + source: 1, + dest: 2, + value: 5 + }), call, // Check filters are correctly bypassed ] )); @@ -333,7 +350,10 @@ fn batch_with_signed_filters() { new_test_ext().execute_with(|| { assert_ok!(Utility::batch( Origin::signed(1), - vec![Call::Balances(pallet_balances::Call::transfer_keep_alive { dest: 2, value: 1 })] + vec![RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { + dest: 2, + value: 1 + })] ),); System::assert_last_event( utility::Event::BatchInterrupted { @@ -363,11 +383,12 @@ fn batch_early_exit_works() { fn batch_weight_calculation_doesnt_overflow() { use sp_runtime::Perbill; new_test_ext().execute_with(|| { - let big_call = Call::System(SystemCall::fill_block { ratio: Perbill::from_percent(50) }); + let big_call = + RuntimeCall::System(SystemCall::fill_block { ratio: Perbill::from_percent(50) }); assert_eq!(big_call.get_dispatch_info().weight, Weight::MAX / 2); // 3 * 50% saturates to 100% - let batch_call = Call::Utility(crate::Call::batch { + let batch_call = RuntimeCall::Utility(crate::Call::batch { calls: vec![big_call.clone(), big_call.clone(), big_call.clone()], }); @@ -386,7 +407,7 @@ fn batch_handles_weight_refund() { // Full weight when ok let inner_call = call_foobar(false, start_weight, None); let batch_calls = vec![inner_call; batch_len as usize]; - let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_ok!(result); @@ -395,7 +416,7 @@ fn batch_handles_weight_refund() { // Refund weight when ok let inner_call = call_foobar(false, start_weight, Some(end_weight)); let batch_calls = vec![inner_call; batch_len as usize]; - let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_ok!(result); @@ -406,7 +427,7 @@ fn batch_handles_weight_refund() { let good_call = call_foobar(false, start_weight, None); let bad_call = call_foobar(true, start_weight, None); let batch_calls = vec![good_call, bad_call]; - let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_ok!(result); @@ -421,7 +442,7 @@ fn batch_handles_weight_refund() { let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call]; let batch_len = batch_calls.len() as u64; - let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_ok!(result); @@ -434,7 +455,7 @@ fn batch_handles_weight_refund() { let good_call = call_foobar(false, start_weight, Some(end_weight)); let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call.clone(), bad_call]; - let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_ok!(result); @@ -471,7 +492,7 @@ fn batch_all_revert() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); - let batch_all_calls = Call::Utility(crate::Call::::batch_all { + let batch_all_calls = RuntimeCall::Utility(crate::Call::::batch_all { calls: vec![call_transfer(2, 5), call_transfer(2, 10), call_transfer(2, 5)], }); assert_noop!( @@ -502,7 +523,7 @@ fn batch_all_handles_weight_refund() { // Full weight when ok let inner_call = call_foobar(false, start_weight, None); let batch_calls = vec![inner_call; batch_len as usize]; - let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_ok!(result); @@ -511,7 +532,7 @@ fn batch_all_handles_weight_refund() { // Refund weight when ok let inner_call = call_foobar(false, start_weight, Some(end_weight)); let batch_calls = vec![inner_call; batch_len as usize]; - let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_ok!(result); @@ -522,7 +543,7 @@ fn batch_all_handles_weight_refund() { let good_call = call_foobar(false, start_weight, None); let bad_call = call_foobar(true, start_weight, None); let batch_calls = vec![good_call, bad_call]; - let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); @@ -534,7 +555,7 @@ fn batch_all_handles_weight_refund() { let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call]; let batch_len = batch_calls.len() as u64; - let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); @@ -544,7 +565,7 @@ fn batch_all_handles_weight_refund() { let good_call = call_foobar(false, start_weight, Some(end_weight)); let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call.clone(), bad_call]; - let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); let result = call.dispatch(Origin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); @@ -559,7 +580,7 @@ fn batch_all_handles_weight_refund() { #[test] fn batch_all_does_not_nest() { new_test_ext().execute_with(|| { - let batch_all = Call::Utility(UtilityCall::batch_all { + let batch_all = RuntimeCall::Utility(UtilityCall::batch_all { calls: vec![call_transfer(2, 1), call_transfer(2, 1), call_transfer(2, 1)], }); @@ -582,7 +603,7 @@ fn batch_all_does_not_nest() { // And for those who want to get a little fancy, we check that the filter persists across // other kinds of dispatch wrapping functions... in this case // `batch_all(batch(batch_all(..)))` - let batch_nested = Call::Utility(UtilityCall::batch { calls: vec![batch_all] }); + let batch_nested = RuntimeCall::Utility(UtilityCall::batch { calls: vec![batch_all] }); // Batch will end with `Ok`, but does not actually execute as we can see from the event // and balances. assert_ok!(Utility::batch_all(Origin::signed(1), vec![batch_nested])); @@ -601,7 +622,7 @@ fn batch_all_does_not_nest() { #[test] fn batch_limit() { new_test_ext().execute_with(|| { - let calls = vec![Call::System(SystemCall::remark { remark: vec![] }); 40_000]; + let calls = vec![RuntimeCall::System(SystemCall::remark { remark: vec![] }); 40_000]; assert_noop!(Utility::batch(Origin::signed(1), calls.clone()), Error::::TooManyCalls); assert_noop!(Utility::batch_all(Origin::signed(1), calls), Error::::TooManyCalls); }); diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 8ac625e775e4f..1ca8d41f9a41c 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -155,7 +155,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The currency trait. type Currency: LockableCurrency; diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index 8875404f03fa2..cc4a3523459d7 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -55,9 +55,9 @@ impl frame_system::Config for Test { type BlockLength = (); type BlockNumber = u64; type BlockWeights = (); - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Hash = H256; type Hashing = BlakeTwo256; type Header = Header; @@ -78,7 +78,7 @@ impl pallet_balances::Config for Test { type AccountStore = System; type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type MaxLocks = ConstU32<10>; type MaxReserves = (); @@ -92,7 +92,7 @@ parameter_types! { impl Config for Test { type BlockNumberToBalance = Identity; type Currency = Balances; - type Event = Event; + type RuntimeEvent = RuntimeEvent; const MAX_VESTING_SCHEDULES: u32 = 3; type MinVestedTransfer = MinVestedTransfer; type WeightInfo = (); diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index cafd1668819dd..9e55d38fd8140 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -71,7 +71,7 @@ benchmarks! { let remark_len = >::MaxSize::get() - 10; let remark = sp_std::vec![1u8; remark_len as usize]; - let call: ::Call = frame_system::Call::remark { remark }.into(); + let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); let call_weight = call.get_dispatch_info().weight; let encoded_call = call.encode(); let call_hash = T::Hashing::hash(&encoded_call[..]); @@ -100,7 +100,7 @@ benchmarks! { let origin = T::DispatchWhitelistedOrigin::successful_origin(); let remark = sp_std::vec![1u8; n as usize]; - let call: ::Call = frame_system::Call::remark { remark }.into(); + let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); let call_hash = T::Hashing::hash_of(&call); Pallet::::whitelist_call(origin.clone(), call_hash) diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index a3e02b6caf740..19e53f2491614 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -61,10 +61,10 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The overarching call type. - type Call: IsType<::Call> + type RuntimeCall: IsType<::RuntimeCall> + Dispatchable + GetDispatchInfo + FullCodec @@ -165,7 +165,7 @@ pub mod pallet { let call = T::PreimageProvider::get_preimage(&call_hash) .ok_or(Error::::UnavailablePreImage)?; - let call = ::Call::decode_all_with_depth_limit( + let call = ::RuntimeCall::decode_all_with_depth_limit( sp_api::MAX_EXTRINSIC_DEPTH, &mut &call[..], ) @@ -191,7 +191,7 @@ pub mod pallet { })] pub fn dispatch_whitelisted_call_with_preimage( origin: OriginFor, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { T::DispatchWhitelistedOrigin::ensure_origin(origin)?; @@ -216,7 +216,7 @@ impl Pallet { /// Clean whitelisting/preimage and dispatch call. /// /// Return the call actual weight of the dispatched call if there is some. - fn clean_and_dispatch(call_hash: T::Hash, call: ::Call) -> Option { + fn clean_and_dispatch(call_hash: T::Hash, call: ::RuntimeCall) -> Option { WhitelistedCall::::remove(call_hash); T::PreimageProvider::unrequest_preimage(&call_hash); diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs index b18236099d445..b6eac316bc113 100644 --- a/frame/whitelist/src/mock.rs +++ b/frame/whitelist/src/mock.rs @@ -62,12 +62,12 @@ impl frame_system::Config for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -85,7 +85,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -93,7 +93,7 @@ impl pallet_balances::Config for Test { } impl pallet_preimage::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; type MaxSize = ConstU32<{ 4096 * 1024 }>; // PreimageMaxSize Taken from Polkadot as reference. @@ -103,8 +103,8 @@ impl pallet_preimage::Config for Test { } impl pallet_whitelist::Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type WhitelistOrigin = EnsureRoot; type DispatchWhitelistedOrigin = EnsureRoot; type PreimageProvider = Preimage; diff --git a/frame/whitelist/src/tests.rs b/frame/whitelist/src/tests.rs index 24974bd726d43..ebb111149fd42 100644 --- a/frame/whitelist/src/tests.rs +++ b/frame/whitelist/src/tests.rs @@ -27,7 +27,7 @@ use sp_runtime::{traits::Hash, DispatchError}; #[test] fn test_whitelist_call_and_remove() { new_test_ext().execute_with(|| { - let call = Call::System(frame_system::Call::remark { remark: vec![] }); + let call = RuntimeCall::System(frame_system::Call::remark { remark: vec![] }); let encoded_call = call.encode(); let call_hash = ::Hashing::hash(&encoded_call[..]); @@ -69,7 +69,7 @@ fn test_whitelist_call_and_remove() { #[test] fn test_whitelist_call_and_execute() { new_test_ext().execute_with(|| { - let call = Call::System(frame_system::Call::remark_with_event { remark: vec![1] }); + let call = RuntimeCall::System(frame_system::Call::remark_with_event { remark: vec![1] }); let call_weight = call.get_dispatch_info().weight; let encoded_call = call.encode(); let call_hash = ::Hashing::hash(&encoded_call[..]); @@ -118,7 +118,7 @@ fn test_whitelist_call_and_execute() { #[test] fn test_whitelist_call_and_execute_failing_call() { new_test_ext().execute_with(|| { - let call = Call::Whitelist(crate::Call::dispatch_whitelisted_call { + let call = RuntimeCall::Whitelist(crate::Call::dispatch_whitelisted_call { call_hash: Default::default(), call_weight_witness: Weight::zero(), }); @@ -137,8 +137,9 @@ fn test_whitelist_call_and_execute_failing_call() { #[test] fn test_whitelist_call_and_execute_without_note_preimage() { new_test_ext().execute_with(|| { - let call = - Box::new(Call::System(frame_system::Call::remark_with_event { remark: vec![1] })); + let call = Box::new(RuntimeCall::System(frame_system::Call::remark_with_event { + remark: vec![1], + })); let call_hash = ::Hashing::hash_of(&call); assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); @@ -161,7 +162,7 @@ fn test_whitelist_call_and_execute_without_note_preimage() { #[test] fn test_whitelist_call_and_execute_decode_consumes_all() { new_test_ext().execute_with(|| { - let call = Call::System(frame_system::Call::remark_with_event { remark: vec![1] }); + let call = RuntimeCall::System(frame_system::Call::remark_with_event { remark: vec![1] }); let call_weight = call.get_dispatch_info().weight; let mut call = call.encode(); // Appending something does not make the encoded call invalid. diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index bb526010dddd5..4ed159fd7e2ed 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -455,7 +455,7 @@ impl From for Result, Origin> { } impl frame_support::traits::OriginTrait for Origin { - type Call = ::Call; + type Call = ::RuntimeCall; type PalletsOrigin = Origin; type AccountId = ::AccountId; @@ -501,9 +501,9 @@ impl frame_support::traits::OriginTrait for Origin { } #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct Event; +pub struct RuntimeEvent; -impl From> for Event { +impl From> for RuntimeEvent { fn from(_evt: frame_system::Event) -> Self { unimplemented!("Not required in tests!") } @@ -585,7 +585,7 @@ impl frame_system::Config for Runtime { type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; type Origin = Origin; - type Call = Extrinsic; + type RuntimeCall = Extrinsic; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -593,7 +593,7 @@ impl frame_system::Config for Runtime { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<2400>; type DbWeight = (); type Version = (); From 379813cafc7aa60deeda79ceccdcc31d83d47876 Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Mon, 12 Sep 2022 18:01:05 -0600 Subject: [PATCH 1152/1472] Update README (#12247) * Update README - rm Matrix chat banner reads as `inaccessible` and the channel is read only (not chat) - add SE banner - update links & call to action to SE * Update README.md * Update README.md * Update README.md --- README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c609641af7ce2..d7e6650290fba 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,24 @@ -# Substrate · [![GitHub license](https://img.shields.io/badge/license-GPL3%2FApache2-blue)](#LICENSE) [![GitLab Status](https://gitlab.parity.io/parity/substrate/badges/master/pipeline.svg)](https://gitlab.parity.io/parity/substrate/pipelines) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/CONTRIBUTING.adoc) [![Matrix](https://img.shields.io/matrix/substrate-technical:matrix.org)](https://matrix.to/#/#substrate-technical:matrix.org) - +# Substrate · [![GitHub license](https://img.shields.io/badge/license-GPL3%2FApache2-blue)](#LICENSE) [![GitLab Status](https://gitlab.parity.io/parity/substrate/badges/master/pipeline.svg)](https://gitlab.parity.io/parity/substrate/pipelines) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/CONTRIBUTING.adoc) [![Stack Exchange](https://img.shields.io/badge/Substrate-Community%20&%20Support-24CC85?logo=stackexchange)](https://substrate.stackexchange.com/)

Substrate is a next-generation framework for blockchain innovation 🚀. -## Trying it out +## Getting Started + +Head to [docs.substrate.io](https://docs.substrate.io) and follow the [installation](https://docs.substrate.io/install/) instructions. +Then try out one of the [tutorials](https://docs.substrate.io/tutorials/). + +## Community & Support -Simply go to [docs.substrate.io](https://docs.substrate.io) and follow the -[installation](https://docs.substrate.io/main-docs/install/) instructions. You can -also try out one of the [tutorials](https://docs.substrate.io/tutorials/). +Join the highly active and supportive community on the [Susbstrate Stack Exchange](https://substrate.stackexchange.com/) to ask questions about use and problems you run into using this software. +Please do report bugs and [isssues here](https://github.com/paritytech/substrate/issues) for anything you suspect requires action in the source. ## Contributions & Code of Conduct -Please follow the contributions guidelines as outlined in [`docs/CONTRIBUTING.adoc`](docs/CONTRIBUTING.adoc). In all communications and contributions, this project follows the [Contributor Covenant Code of Conduct](docs/CODE_OF_CONDUCT.md). +Please follow the contributions guidelines as outlined in [`docs/CONTRIBUTING.adoc`](docs/CONTRIBUTING.adoc). +In all communications and contributions, this project follows the [Contributor Covenant Code of Conduct](docs/CODE_OF_CONDUCT.md). ## Security From 5daa20c69049bcfa6df290124e5b6a9da88b71c3 Mon Sep 17 00:00:00 2001 From: girazoki Date: Tue, 13 Sep 2022 02:12:09 +0200 Subject: [PATCH 1153/1472] Add inspect trait for asset roles (#11738) Co-authored-by: Shawn Tabrizi --- frame/assets/src/impl_fungibles.rs | 20 +++++++++++++ frame/assets/src/tests.rs | 22 ++++++++++++++ frame/support/src/traits/tokens/fungibles.rs | 1 + .../src/traits/tokens/fungibles/roles.rs | 29 +++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 frame/support/src/traits/tokens/fungibles/roles.rs diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 6b263bc0c7bef..842ee5c102c1d 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -263,3 +263,23 @@ impl, I: 'static> fungibles::approvals::Mutate<: Self::do_transfer_approved(asset, owner, delegate, dest, amount) } } + +impl, I: 'static> fungibles::roles::Inspect<::AccountId> + for Pallet +{ + fn owner(asset: T::AssetId) -> Option<::AccountId> { + Asset::::get(asset).map(|x| x.owner) + } + + fn issuer(asset: T::AssetId) -> Option<::AccountId> { + Asset::::get(asset).map(|x| x.issuer) + } + + fn admin(asset: T::AssetId) -> Option<::AccountId> { + Asset::::get(asset).map(|x| x.admin) + } + + fn freezer(asset: T::AssetId) -> Option<::AccountId> { + Asset::::get(asset).map(|x| x.freezer) + } +} diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 50ab04111edff..598b6049b3d57 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -977,3 +977,25 @@ fn transfer_large_asset() { assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, amount - 1)); }) } + +#[test] +fn querying_roles_should_work() { + new_test_ext().execute_with(|| { + use frame_support::traits::tokens::fungibles::roles::Inspect; + assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::set_team( + Origin::signed(1), + 0, + // Issuer + 2, + // Admin + 3, + // Freezer + 4, + )); + assert_eq!(Assets::owner(0), Some(1)); + assert_eq!(Assets::issuer(0), Some(2)); + assert_eq!(Assets::admin(0), Some(3)); + assert_eq!(Assets::freezer(0), Some(4)); + }); +} diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index dab50d56962f6..e4108b7f80a98 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -31,6 +31,7 @@ pub mod metadata; pub use balanced::{Balanced, Unbalanced}; mod imbalance; pub use imbalance::{CreditOf, DebtOf, HandleImbalanceDrop, Imbalance}; +pub mod roles; /// Trait for providing balance-inspection access to a set of named fungible assets. pub trait Inspect { diff --git a/frame/support/src/traits/tokens/fungibles/roles.rs b/frame/support/src/traits/tokens/fungibles/roles.rs new file mode 100644 index 0000000000000..18fd1cc801210 --- /dev/null +++ b/frame/support/src/traits/tokens/fungibles/roles.rs @@ -0,0 +1,29 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Inspect traits for Asset roles + +pub trait Inspect: super::Inspect { + // Get owner for an AssetId. + fn owner(asset: Self::AssetId) -> Option; + // Get issuer for an AssetId. + fn issuer(asset: Self::AssetId) -> Option; + // Get admin for an AssetId. + fn admin(asset: Self::AssetId) -> Option; + // Get freezer for an AssetId. + fn freezer(asset: Self::AssetId) -> Option; +} From c1103fd803a974ee4d4098eb631a8839f6cb8618 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Tue, 13 Sep 2022 11:02:31 +0300 Subject: [PATCH 1154/1472] Move bitswap to its own crate (#12242) * Introduce `sc-network-bitswap` Move the bitswap protocol out of `sc-network` to its own crate. * Improve test coverage * Remove mention of bitswap from `sc-network` * Fix documentation * Fix clippy and remove the void dependency * Remove unneeded trait bound and bump prost to 0.11 --- Cargo.lock | 152 +++-- Cargo.toml | 1 + client/network/Cargo.toml | 4 - client/network/bitswap/Cargo.toml | 40 ++ client/network/{ => bitswap}/build.rs | 2 +- client/network/bitswap/src/lib.rs | 524 ++++++++++++++++++ client/network/{ => bitswap}/src/schema.rs | 2 +- .../src/schema/bitswap.v1.2.0.proto | 0 client/network/src/behaviour.rs | 18 +- client/network/src/bitswap.rs | 416 -------------- client/network/src/config.rs | 8 +- client/network/src/lib.rs | 2 - client/network/src/service.rs | 11 +- client/network/src/service/tests.rs | 2 +- client/network/test/src/lib.rs | 2 +- client/service/Cargo.toml | 1 + client/service/src/builder.rs | 17 +- 17 files changed, 708 insertions(+), 494 deletions(-) create mode 100644 client/network/bitswap/Cargo.toml rename client/network/{ => bitswap}/build.rs (56%) create mode 100644 client/network/bitswap/src/lib.rs rename client/network/{ => bitswap}/src/schema.rs (97%) rename client/network/{ => bitswap}/src/schema/bitswap.v1.2.0.proto (100%) delete mode 100644 client/network/src/bitswap.rs diff --git a/Cargo.lock b/Cargo.lock index 335e8b3526792..08915196d5374 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -927,9 +927,9 @@ dependencies = [ [[package]] name = "cid" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a52cffa791ce5cf490ac3b2d6df970dc04f931b04e727be3c3e220e17164dfc4" +checksum = "f6ed9c8b2d17acb8110c46f1da5bf4a696d745e1474a16db0cd2b49cd0249bf2" dependencies = [ "core2", "multibase", @@ -3591,8 +3591,8 @@ dependencies = [ "libp2p-request-response", "libp2p-swarm", "log", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.8.5", ] @@ -3618,8 +3618,8 @@ dependencies = [ "multistream-select", "parking_lot 0.12.1", "pin-project", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.8.5", "ring", "rw-stream-sink", @@ -3669,8 +3669,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.7.3", "smallvec", ] @@ -3693,8 +3693,8 @@ dependencies = [ "libp2p-swarm", "log", "prometheus-client", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.7.3", "regex", "sha2 0.10.2", @@ -3716,8 +3716,8 @@ dependencies = [ "libp2p-swarm", "log", "lru", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "prost-codec", "smallvec", "thiserror", @@ -3741,8 +3741,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.7.3", "sha2 0.10.2", "smallvec", @@ -3819,8 +3819,8 @@ dependencies = [ "lazy_static", "libp2p-core", "log", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.8.5", "sha2 0.10.2", "snow", @@ -3856,8 +3856,8 @@ dependencies = [ "futures", "libp2p-core", "log", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "unsigned-varint", "void", ] @@ -3892,8 +3892,8 @@ dependencies = [ "libp2p-swarm", "log", "pin-project", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "prost-codec", "rand 0.8.5", "smallvec", @@ -3916,8 +3916,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "rand 0.8.5", "sha2 0.10.2", "thiserror", @@ -7061,7 +7061,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc03e116981ff7d8da8e5c220e374587b98d294af7ba7dd7fda761158f00086f" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.10.1", +] + +[[package]] +name = "prost" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "399c3c31cdec40583bb68f0b18403400d01ec4289c383aa047560439952c4dd7" +dependencies = [ + "bytes", + "prost-derive 0.11.0", ] [[package]] @@ -7079,8 +7089,28 @@ dependencies = [ "log", "multimap", "petgraph", - "prost", - "prost-types", + "prost 0.10.3", + "prost-types 0.10.1", + "regex", + "tempfile", + "which", +] + +[[package]] +name = "prost-build" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f835c582e6bd972ba8347313300219fed5bfa52caf175298d860b61ff6069bb" +dependencies = [ + "bytes", + "heck", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prost 0.11.0", + "prost-types 0.11.1", "regex", "tempfile", "which", @@ -7094,7 +7124,7 @@ checksum = "00af1e92c33b4813cc79fda3f2dbf56af5169709be0202df730e9ebc3e4cd007" dependencies = [ "asynchronous-codec", "bytes", - "prost", + "prost 0.10.3", "thiserror", "unsigned-varint", ] @@ -7112,6 +7142,19 @@ dependencies = [ "syn", ] +[[package]] +name = "prost-derive" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7345d5f0e08c0536d7ac7229952590239e77abf0a0100a1b1d890add6ea96364" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "prost-types" version = "0.10.1" @@ -7119,7 +7162,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" dependencies = [ "bytes", - "prost", + "prost 0.10.3", +] + +[[package]] +name = "prost-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dfaa718ad76a44b3415e6c4d53b17c8f99160dcb3a99b10470fce8ad43f6e3e" +dependencies = [ + "bytes", + "prost 0.11.0", ] [[package]] @@ -7728,8 +7781,8 @@ dependencies = [ "libp2p", "log", "parity-scale-codec", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "quickcheck", "rand 0.7.3", "sc-client-api", @@ -8384,8 +8437,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "pin-project", - "prost", - "prost-build", + "prost 0.10.3", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8411,10 +8463,35 @@ dependencies = [ "tempfile", "thiserror", "unsigned-varint", - "void", "zeroize", ] +[[package]] +name = "sc-network-bitswap" +version = "0.10.0-dev" +dependencies = [ + "cid", + "futures", + "libp2p", + "log", + "prost 0.11.0", + "prost-build 0.11.1", + "sc-block-builder", + "sc-client-api", + "sc-consensus", + "sc-network-common", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-runtime", + "substrate-test-runtime", + "substrate-test-runtime-client", + "thiserror", + "tokio", + "unsigned-varint", + "void", +] + [[package]] name = "sc-network-common" version = "0.10.0-dev" @@ -8425,7 +8502,7 @@ dependencies = [ "futures", "libp2p", "parity-scale-codec", - "prost-build", + "prost-build 0.10.4", "sc-consensus", "sc-peerset", "serde", @@ -8466,8 +8543,8 @@ dependencies = [ "libp2p", "log", "parity-scale-codec", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "sc-client-api", "sc-network-common", "sc-peerset", @@ -8488,8 +8565,8 @@ dependencies = [ "log", "lru", "parity-scale-codec", - "prost", - "prost-build", + "prost 0.10.3", + "prost-build 0.10.4", "quickcheck", "sc-block-builder", "sc-client-api", @@ -8712,6 +8789,7 @@ dependencies = [ "sc-informant", "sc-keystore", "sc-network", + "sc-network-bitswap", "sc-network-common", "sc-network-light", "sc-network-sync", diff --git a/Cargo.toml b/Cargo.toml index e2907716ca9f2..9c71dbdf4b52c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ members = [ "client/keystore", "client/network", "client/network-gossip", + "client/network/bitswap", "client/network/common", "client/network/light", "client/network/sync", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 82f77fa44450f..ae115220d6843 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -13,9 +13,6 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] -[build-dependencies] -prost-build = "0.10" - [dependencies] async-trait = "0.1" asynchronous-codec = "0.6" @@ -43,7 +40,6 @@ serde_json = "1.0.85" smallvec = "1.8.0" thiserror = "1.0" unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } -void = "1.0.2" zeroize = "1.4.3" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/network/bitswap/Cargo.toml b/client/network/bitswap/Cargo.toml new file mode 100644 index 0000000000000..9fa34aab17dfb --- /dev/null +++ b/client/network/bitswap/Cargo.toml @@ -0,0 +1,40 @@ +[package] +description = "Substrate bitswap protocol" +name = "sc-network-bitswap" +version = "0.10.0-dev" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +documentation = "https://docs.rs/sc-network-bitswap" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +prost-build = "0.11" + +[dependencies] +cid = "0.8.6" +futures = "0.3.21" +libp2p = "0.46.1" +log = "0.4.17" +prost = "0.11" +thiserror = "1.0" +unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } +void = "1.0.2" +sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-network-common = { version = "0.10.0-dev", path = "../common" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } + +[dev-dependencies] +tokio = { version = "1", features = ["full"] } +sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } +sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/network/build.rs b/client/network/bitswap/build.rs similarity index 56% rename from client/network/build.rs rename to client/network/bitswap/build.rs index 671277230a774..bd6222d546851 100644 --- a/client/network/build.rs +++ b/client/network/bitswap/build.rs @@ -1,4 +1,4 @@ -const PROTOS: &[&str] = &["src/schema/bitswap.v1.2.0.proto"]; +const PROTOS: &[&str] = &["bitswap.v1.2.0.proto"]; fn main() { prost_build::compile_protos(PROTOS, &["src/schema"]).unwrap(); diff --git a/client/network/bitswap/src/lib.rs b/client/network/bitswap/src/lib.rs new file mode 100644 index 0000000000000..aba7f40ce632f --- /dev/null +++ b/client/network/bitswap/src/lib.rs @@ -0,0 +1,524 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Bitswap server for Substrate. +//! +//! Allows querying transactions by hash over standard bitswap protocol +//! Only supports bitswap 1.2.0. +//! CID is expected to reference 256-bit Blake2b transaction hash. + +use cid::{self, Version}; +use futures::{channel::mpsc, StreamExt}; +use libp2p::core::PeerId; +use log::{debug, error, trace}; +use prost::Message; +use sc_client_api::BlockBackend; +use sc_network_common::{ + protocol::ProtocolName, + request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, +}; +use schema::bitswap::{ + message::{wantlist::WantType, Block as MessageBlock, BlockPresence, BlockPresenceType}, + Message as BitswapMessage, +}; +use sp_runtime::traits::Block as BlockT; +use std::{io, sync::Arc, time::Duration}; +use unsigned_varint::encode as varint_encode; + +mod schema; + +const LOG_TARGET: &str = "bitswap"; + +// Undocumented, but according to JS the bitswap messages have a max size of 512*1024 bytes +// https://github.com/ipfs/js-ipfs-bitswap/blob/ +// d8f80408aadab94c962f6b88f343eb9f39fa0fcc/src/decision-engine/index.js#L16 +// We set it to the same value as max substrate protocol message +const MAX_PACKET_SIZE: u64 = 16 * 1024 * 1024; + +/// Max number of queued responses before denying requests. +const MAX_REQUEST_QUEUE: usize = 20; + +/// Max number of blocks per wantlist +const MAX_WANTED_BLOCKS: usize = 16; + +/// Bitswap protocol name +const PROTOCOL_NAME: &'static str = "/ipfs/bitswap/1.2.0"; + +/// Prefix represents all metadata of a CID, without the actual content. +#[derive(PartialEq, Eq, Clone, Debug)] +struct Prefix { + /// The version of CID. + pub version: Version, + /// The codec of CID. + pub codec: u64, + /// The multihash type of CID. + pub mh_type: u64, + /// The multihash length of CID. + pub mh_len: u8, +} + +impl Prefix { + /// Convert the prefix to encoded bytes. + pub fn to_bytes(&self) -> Vec { + let mut res = Vec::with_capacity(4); + let mut buf = varint_encode::u64_buffer(); + let version = varint_encode::u64(self.version.into(), &mut buf); + res.extend_from_slice(version); + let mut buf = varint_encode::u64_buffer(); + let codec = varint_encode::u64(self.codec, &mut buf); + res.extend_from_slice(codec); + let mut buf = varint_encode::u64_buffer(); + let mh_type = varint_encode::u64(self.mh_type, &mut buf); + res.extend_from_slice(mh_type); + let mut buf = varint_encode::u64_buffer(); + let mh_len = varint_encode::u64(self.mh_len as u64, &mut buf); + res.extend_from_slice(mh_len); + res + } +} + +/// Bitswap request handler +pub struct BitswapRequestHandler { + client: Arc + Send + Sync>, + request_receiver: mpsc::Receiver, +} + +impl BitswapRequestHandler { + /// Create a new [`BitswapRequestHandler`]. + pub fn new(client: Arc + Send + Sync>) -> (Self, ProtocolConfig) { + let (tx, request_receiver) = mpsc::channel(MAX_REQUEST_QUEUE); + + let config = ProtocolConfig { + name: ProtocolName::from(PROTOCOL_NAME), + fallback_names: vec![], + max_request_size: MAX_PACKET_SIZE, + max_response_size: MAX_PACKET_SIZE, + request_timeout: Duration::from_secs(15), + inbound_queue: Some(tx), + }; + + (Self { client, request_receiver }, config) + } + + /// Run [`BitswapRequestHandler`]. + pub async fn run(mut self) { + while let Some(request) = self.request_receiver.next().await { + let IncomingRequest { peer, payload, pending_response } = request; + + match self.handle_message(&peer, &payload) { + Ok(response) => { + let response = OutgoingResponse { + result: Ok(response), + reputation_changes: Vec::new(), + sent_feedback: None, + }; + + match pending_response.send(response) { + Ok(()) => + trace!(target: LOG_TARGET, "Handled bitswap request from {peer}.",), + Err(_) => debug!( + target: LOG_TARGET, + "Failed to handle light client request from {peer}: {}", + BitswapError::SendResponse, + ), + } + }, + Err(err) => { + error!(target: LOG_TARGET, "Failed to process request from {peer}: {err}"); + + // TODO: adjust reputation? + + let response = OutgoingResponse { + result: Err(()), + reputation_changes: vec![], + sent_feedback: None, + }; + + if pending_response.send(response).is_err() { + debug!( + target: LOG_TARGET, + "Failed to handle bitswap request from {peer}: {}", + BitswapError::SendResponse, + ); + } + }, + } + } + } + + /// Handle received Bitswap request + fn handle_message( + &mut self, + peer: &PeerId, + payload: &Vec, + ) -> Result, BitswapError> { + let request = schema::bitswap::Message::decode(&payload[..])?; + + trace!(target: LOG_TARGET, "Received request: {:?} from {}", request, peer); + + let mut response = BitswapMessage::default(); + + let wantlist = match request.wantlist { + Some(wantlist) => wantlist, + None => { + debug!(target: LOG_TARGET, "Unexpected bitswap message from {}", peer); + return Err(BitswapError::InvalidWantList) + }, + }; + + if wantlist.entries.len() > MAX_WANTED_BLOCKS { + trace!(target: LOG_TARGET, "Ignored request: too many entries"); + return Err(BitswapError::TooManyEntries) + } + + for entry in wantlist.entries { + let cid = match cid::Cid::read_bytes(entry.block.as_slice()) { + Ok(cid) => cid, + Err(e) => { + trace!(target: LOG_TARGET, "Bad CID {:?}: {:?}", entry.block, e); + continue + }, + }; + + if cid.version() != cid::Version::V1 || + cid.hash().code() != u64::from(cid::multihash::Code::Blake2b256) || + cid.hash().size() != 32 + { + debug!(target: LOG_TARGET, "Ignoring unsupported CID {}: {}", peer, cid); + continue + } + + let mut hash = B::Hash::default(); + hash.as_mut().copy_from_slice(&cid.hash().digest()[0..32]); + let transaction = match self.client.indexed_transaction(&hash) { + Ok(ex) => ex, + Err(e) => { + error!(target: LOG_TARGET, "Error retrieving transaction {}: {}", hash, e); + None + }, + }; + + match transaction { + Some(transaction) => { + trace!(target: LOG_TARGET, "Found CID {:?}, hash {:?}", cid, hash); + + if entry.want_type == WantType::Block as i32 { + let prefix = Prefix { + version: cid.version(), + codec: cid.codec(), + mh_type: cid.hash().code(), + mh_len: cid.hash().size(), + }; + response + .payload + .push(MessageBlock { prefix: prefix.to_bytes(), data: transaction }); + } else { + response.block_presences.push(BlockPresence { + r#type: BlockPresenceType::Have as i32, + cid: cid.to_bytes(), + }); + } + }, + None => { + trace!(target: LOG_TARGET, "Missing CID {:?}, hash {:?}", cid, hash); + + if entry.send_dont_have { + response.block_presences.push(BlockPresence { + r#type: BlockPresenceType::DontHave as i32, + cid: cid.to_bytes(), + }); + } + }, + } + } + + Ok(response.encode_to_vec()) + } +} + +/// Bitswap protocol error. +#[derive(Debug, thiserror::Error)] +pub enum BitswapError { + /// Protobuf decoding error. + #[error("Failed to decode request: {0}.")] + DecodeProto(#[from] prost::DecodeError), + + /// Protobuf encoding error. + #[error("Failed to encode response: {0}.")] + EncodeProto(#[from] prost::EncodeError), + + /// Client backend error. + #[error(transparent)] + Client(#[from] sp_blockchain::Error), + + /// Error parsing CID + #[error(transparent)] + BadCid(#[from] cid::Error), + + /// Packet read error. + #[error(transparent)] + Read(#[from] io::Error), + + /// Error sending response. + #[error("Failed to send response.")] + SendResponse, + + /// Message doesn't have a WANT list. + #[error("Invalid WANT list.")] + InvalidWantList, + + /// Too many blocks requested. + #[error("Too many block entries in the request.")] + TooManyEntries, +} + +#[cfg(test)] +mod tests { + use super::*; + use futures::{channel::oneshot, SinkExt}; + use sc_block_builder::BlockBuilderProvider; + use schema::bitswap::{ + message::{wantlist::Entry, Wantlist}, + Message as BitswapMessage, + }; + use sp_consensus::BlockOrigin; + use sp_runtime::codec::Encode; + use substrate_test_runtime::Extrinsic; + use substrate_test_runtime_client::{self, prelude::*, TestClientBuilder}; + + #[tokio::test] + async fn undecodeable_message() { + let client = substrate_test_runtime_client::new(); + let (bitswap, config) = BitswapRequestHandler::new(Arc::new(client)); + + tokio::spawn(async move { bitswap.run().await }); + + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: vec![0x13, 0x37, 0x13, 0x38], + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(result, Err(())); + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + } else { + panic!("invalid event received"); + } + } + + #[tokio::test] + async fn empty_want_list() { + let client = substrate_test_runtime_client::new(); + let (bitswap, mut config) = BitswapRequestHandler::new(Arc::new(client)); + + tokio::spawn(async move { bitswap.run().await }); + + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .as_mut() + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: BitswapMessage { wantlist: None, ..Default::default() }.encode_to_vec(), + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(result, Err(())); + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + } else { + panic!("invalid event received"); + } + + // Empty WANT list should not cause an error + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: BitswapMessage { + wantlist: Some(Default::default()), + ..Default::default() + } + .encode_to_vec(), + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(result, Ok(BitswapMessage::default().encode_to_vec())); + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + } else { + panic!("invalid event received"); + } + } + + #[tokio::test] + async fn too_long_want_list() { + let client = substrate_test_runtime_client::new(); + let (bitswap, config) = BitswapRequestHandler::new(Arc::new(client)); + + tokio::spawn(async move { bitswap.run().await }); + + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: BitswapMessage { + wantlist: Some(Wantlist { + entries: (0..MAX_WANTED_BLOCKS + 1) + .map(|_| Entry::default()) + .collect::>(), + full: false, + }), + ..Default::default() + } + .encode_to_vec(), + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(result, Err(())); + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + } else { + panic!("invalid event received"); + } + } + + #[tokio::test] + async fn transaction_not_found() { + let client = TestClientBuilder::with_tx_storage(u32::MAX).build(); + + let (bitswap, config) = BitswapRequestHandler::new(Arc::new(client)); + tokio::spawn(async move { bitswap.run().await }); + + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: BitswapMessage { + wantlist: Some(Wantlist { + entries: vec![Entry { + block: cid::Cid::new_v1( + 0x70, + cid::multihash::Multihash::wrap( + u64::from(cid::multihash::Code::Blake2b256), + &[0u8; 32], + ) + .unwrap(), + ) + .to_bytes(), + ..Default::default() + }], + full: false, + }), + ..Default::default() + } + .encode_to_vec(), + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(result, Ok(vec![])); + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + } else { + panic!("invalid event received"); + } + } + + #[tokio::test] + async fn transaction_found() { + let mut client = TestClientBuilder::with_tx_storage(u32::MAX).build(); + let mut block_builder = client.new_block(Default::default()).unwrap(); + + let ext = Extrinsic::Store(vec![0x13, 0x37, 0x13, 0x38]); + + block_builder.push(ext.clone()).unwrap(); + let block = block_builder.build().unwrap().block; + + client.import(BlockOrigin::File, block).await.unwrap(); + + let (bitswap, config) = BitswapRequestHandler::new(Arc::new(client)); + + tokio::spawn(async move { bitswap.run().await }); + + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: BitswapMessage { + wantlist: Some(Wantlist { + entries: vec![Entry { + block: cid::Cid::new_v1( + 0x70, + cid::multihash::Multihash::wrap( + u64::from(cid::multihash::Code::Blake2b256), + &sp_core::hashing::blake2_256(&ext.encode()[2..]), + ) + .unwrap(), + ) + .to_bytes(), + ..Default::default() + }], + full: false, + }), + ..Default::default() + } + .encode_to_vec(), + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + + let response = + schema::bitswap::Message::decode(&result.expect("fetch to succeed")[..]).unwrap(); + assert_eq!(response.payload[0].data, vec![0x13, 0x37, 0x13, 0x38]); + } else { + panic!("invalid event received"); + } + } +} diff --git a/client/network/src/schema.rs b/client/network/bitswap/src/schema.rs similarity index 97% rename from client/network/src/schema.rs rename to client/network/bitswap/src/schema.rs index 4893bc28a7355..362e59aca68f9 100644 --- a/client/network/src/schema.rs +++ b/client/network/bitswap/src/schema.rs @@ -18,6 +18,6 @@ //! Include sources generated from protobuf definitions. -pub mod bitswap { +pub(crate) mod bitswap { include!(concat!(env!("OUT_DIR"), "/bitswap.message.rs")); } diff --git a/client/network/src/schema/bitswap.v1.2.0.proto b/client/network/bitswap/src/schema/bitswap.v1.2.0.proto similarity index 100% rename from client/network/src/schema/bitswap.v1.2.0.proto rename to client/network/bitswap/src/schema/bitswap.v1.2.0.proto diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 24df47db6803f..88571647fb0e3 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -17,7 +17,6 @@ // along with this program. If not, see . use crate::{ - bitswap::Bitswap, discovery::{DiscoveryBehaviour, DiscoveryConfig, DiscoveryOut}, peer_info, protocol::{message::Roles, CustomMessageOutcome, NotificationsSink, Protocol}, @@ -32,8 +31,7 @@ use libp2p::{ identify::IdentifyInfo, kad::record, swarm::{ - behaviour::toggle::Toggle, NetworkBehaviour, NetworkBehaviourAction, - NetworkBehaviourEventProcess, PollParameters, + NetworkBehaviour, NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters, }, NetworkBehaviour, }; @@ -79,8 +77,6 @@ where peer_info: peer_info::PeerInfoBehaviour, /// Discovers nodes of the network. discovery: DiscoveryBehaviour, - /// Bitswap server for blockchain data. - bitswap: Toggle>, /// Generic request-response protocols. request_responses: request_responses::RequestResponsesBehaviour, @@ -214,7 +210,6 @@ where block_request_protocol_config: ProtocolConfig, state_request_protocol_config: ProtocolConfig, warp_sync_protocol_config: Option, - bitswap: Option>, light_client_request_protocol_config: ProtocolConfig, // All remaining request protocol configs. mut request_response_protocols: Vec, @@ -239,7 +234,6 @@ where substrate, peer_info: peer_info::PeerInfoBehaviour::new(user_agent, local_public_key), discovery: disco_config.finish(), - bitswap: bitswap.into(), request_responses: request_responses::RequestResponsesBehaviour::new( request_response_protocols.into_iter(), peerset, @@ -338,16 +332,6 @@ fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole { } } -impl NetworkBehaviourEventProcess for Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn inject_event(&mut self, event: void::Void) { - void::unreachable(event) - } -} - impl NetworkBehaviourEventProcess> for Behaviour where B: BlockT, diff --git a/client/network/src/bitswap.rs b/client/network/src/bitswap.rs deleted file mode 100644 index 52fa0c36caedf..0000000000000 --- a/client/network/src/bitswap.rs +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! Bitswap server for substrate. -//! -//! Allows querying transactions by hash over standard bitswap protocol -//! Only supports bitswap 1.2.0. -//! CID is expected to reference 256-bit Blake2b transaction hash. - -use crate::schema::bitswap::{ - message::{wantlist::WantType, Block as MessageBlock, BlockPresence, BlockPresenceType}, - Message as BitswapMessage, -}; -use cid::Version; -use core::pin::Pin; -use futures::{ - io::{AsyncRead, AsyncWrite}, - Future, -}; -use libp2p::{ - core::{ - connection::ConnectionId, upgrade, InboundUpgrade, Multiaddr, OutboundUpgrade, PeerId, - UpgradeInfo, - }, - swarm::{ - NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, OneShotHandler, PollParameters, - }, -}; -use log::{debug, error, trace}; -use prost::Message; -use sc_client_api::BlockBackend; -use sp_runtime::traits::Block as BlockT; -use std::{ - collections::VecDeque, - io, - marker::PhantomData, - sync::Arc, - task::{Context, Poll}, -}; -use unsigned_varint::encode as varint_encode; - -const LOG_TARGET: &str = "bitswap"; - -// Undocumented, but according to JS the bitswap messages have a max size of 512*1024 bytes -// https://github.com/ipfs/js-ipfs-bitswap/blob/ -// d8f80408aadab94c962f6b88f343eb9f39fa0fcc/src/decision-engine/index.js#L16 -// We set it to the same value as max substrate protocol message -const MAX_PACKET_SIZE: usize = 16 * 1024 * 1024; - -// Max number of queued responses before denying requests. -const MAX_RESPONSE_QUEUE: usize = 20; -// Max number of blocks per wantlist -const MAX_WANTED_BLOCKS: usize = 16; - -const PROTOCOL_NAME: &[u8] = b"/ipfs/bitswap/1.2.0"; - -type FutureResult = Pin> + Send>>; - -/// Bitswap protocol config -#[derive(Clone, Copy, Debug, Default)] -pub struct BitswapConfig; - -impl UpgradeInfo for BitswapConfig { - type Info = &'static [u8]; - type InfoIter = std::iter::Once; - - fn protocol_info(&self) -> Self::InfoIter { - std::iter::once(PROTOCOL_NAME) - } -} - -impl InboundUpgrade for BitswapConfig -where - TSocket: AsyncRead + AsyncWrite + Send + Unpin + 'static, -{ - type Output = BitswapMessage; - type Error = BitswapError; - type Future = FutureResult; - - fn upgrade_inbound(self, mut socket: TSocket, _info: Self::Info) -> Self::Future { - Box::pin(async move { - let packet = upgrade::read_length_prefixed(&mut socket, MAX_PACKET_SIZE).await?; - let message: BitswapMessage = Message::decode(packet.as_slice())?; - Ok(message) - }) - } -} - -impl UpgradeInfo for BitswapMessage { - type Info = &'static [u8]; - type InfoIter = std::iter::Once; - - fn protocol_info(&self) -> Self::InfoIter { - std::iter::once(PROTOCOL_NAME) - } -} - -impl OutboundUpgrade for BitswapMessage -where - TSocket: AsyncRead + AsyncWrite + Send + Unpin + 'static, -{ - type Output = (); - type Error = io::Error; - type Future = FutureResult; - - fn upgrade_outbound(self, mut socket: TSocket, _info: Self::Info) -> Self::Future { - Box::pin(async move { - let data = self.encode_to_vec(); - upgrade::write_length_prefixed(&mut socket, data).await - }) - } -} - -/// Internal protocol handler event. -#[derive(Debug)] -pub enum HandlerEvent { - /// We received a `BitswapMessage` from a remote. - Request(BitswapMessage), - /// We successfully sent a `BitswapMessage`. - ResponseSent, -} - -impl From for HandlerEvent { - fn from(message: BitswapMessage) -> Self { - Self::Request(message) - } -} - -impl From<()> for HandlerEvent { - fn from(_: ()) -> Self { - Self::ResponseSent - } -} - -/// Prefix represents all metadata of a CID, without the actual content. -#[derive(PartialEq, Eq, Clone, Debug)] -struct Prefix { - /// The version of CID. - pub version: Version, - /// The codec of CID. - pub codec: u64, - /// The multihash type of CID. - pub mh_type: u64, - /// The multihash length of CID. - pub mh_len: u8, -} - -impl Prefix { - /// Convert the prefix to encoded bytes. - pub fn to_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(4); - let mut buf = varint_encode::u64_buffer(); - let version = varint_encode::u64(self.version.into(), &mut buf); - res.extend_from_slice(version); - let mut buf = varint_encode::u64_buffer(); - let codec = varint_encode::u64(self.codec, &mut buf); - res.extend_from_slice(codec); - let mut buf = varint_encode::u64_buffer(); - let mh_type = varint_encode::u64(self.mh_type, &mut buf); - res.extend_from_slice(mh_type); - let mut buf = varint_encode::u64_buffer(); - let mh_len = varint_encode::u64(self.mh_len as u64, &mut buf); - res.extend_from_slice(mh_len); - res - } -} - -/// Bitswap trait -pub trait BitswapT { - /// Get single indexed transaction by content hash. - /// - /// Note that this will only fetch transactions - /// that are indexed by the runtime with `storage_index_transaction`. - fn indexed_transaction( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result>>; - - /// Queue of blocks ready to be sent out on `poll()` - fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)>; -} - -/// Network behaviour that handles sending and receiving IPFS blocks. -struct BitswapInternal { - client: Arc, - ready_blocks: VecDeque<(PeerId, BitswapMessage)>, - _block: PhantomData, -} - -impl BitswapInternal { - /// Create a new instance of the bitswap protocol handler. - pub fn new(client: Arc) -> Self { - Self { client, ready_blocks: Default::default(), _block: PhantomData::default() } - } -} - -impl BitswapT for BitswapInternal -where - Block: BlockT, - Client: BlockBackend, -{ - fn indexed_transaction( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result>> { - self.client.indexed_transaction(&hash) - } - - fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)> { - &mut self.ready_blocks - } -} - -/// Wrapper for bitswap trait object implement NetworkBehaviour -pub struct Bitswap { - inner: Box + Sync + Send>, -} - -impl Bitswap { - /// Create new Bitswap wrapper - pub fn from_client + Send + Sync + 'static>( - client: Arc, - ) -> Self { - let inner = Box::new(BitswapInternal::new(client)) as Box<_>; - Self { inner } - } -} - -impl BitswapT for Bitswap { - fn indexed_transaction( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result>> { - self.inner.indexed_transaction(hash) - } - - fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)> { - self.inner.ready_blocks() - } -} - -impl BitswapT for Box -where - T: BitswapT, -{ - fn indexed_transaction( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result>> { - T::indexed_transaction(self, hash) - } - - fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)> { - T::ready_blocks(self) - } -} - -impl NetworkBehaviour for Bitswap -where - B: BlockT, -{ - type ConnectionHandler = OneShotHandler; - type OutEvent = void::Void; - - fn new_handler(&mut self) -> Self::ConnectionHandler { - Default::default() - } - - fn addresses_of_peer(&mut self, _peer: &PeerId) -> Vec { - Vec::new() - } - - fn inject_event(&mut self, peer: PeerId, _connection: ConnectionId, message: HandlerEvent) { - let request = match message { - HandlerEvent::ResponseSent => return, - HandlerEvent::Request(msg) => msg, - }; - trace!(target: LOG_TARGET, "Received request: {:?} from {}", request, peer); - if self.ready_blocks().len() > MAX_RESPONSE_QUEUE { - debug!(target: LOG_TARGET, "Ignored request: queue is full"); - return - } - - let mut response = BitswapMessage { - wantlist: None, - blocks: Default::default(), - payload: Default::default(), - block_presences: Default::default(), - pending_bytes: 0, - }; - let wantlist = match request.wantlist { - Some(wantlist) => wantlist, - None => { - debug!(target: LOG_TARGET, "Unexpected bitswap message from {}", peer); - return - }, - }; - if wantlist.entries.len() > MAX_WANTED_BLOCKS { - trace!(target: LOG_TARGET, "Ignored request: too many entries"); - return - } - for entry in wantlist.entries { - let cid = match cid::Cid::read_bytes(entry.block.as_slice()) { - Ok(cid) => cid, - Err(e) => { - trace!(target: LOG_TARGET, "Bad CID {:?}: {:?}", entry.block, e); - continue - }, - }; - if cid.version() != cid::Version::V1 || - cid.hash().code() != u64::from(cid::multihash::Code::Blake2b256) || - cid.hash().size() != 32 - { - debug!(target: LOG_TARGET, "Ignoring unsupported CID {}: {}", peer, cid); - continue - } - let mut hash = B::Hash::default(); - hash.as_mut().copy_from_slice(&cid.hash().digest()[0..32]); - let transaction = match self.indexed_transaction(hash) { - Ok(ex) => ex, - Err(e) => { - error!(target: LOG_TARGET, "Error retrieving transaction {}: {}", hash, e); - None - }, - }; - match transaction { - Some(transaction) => { - trace!(target: LOG_TARGET, "Found CID {:?}, hash {:?}", cid, hash); - if entry.want_type == WantType::Block as i32 { - let prefix = Prefix { - version: cid.version(), - codec: cid.codec(), - mh_type: cid.hash().code(), - mh_len: cid.hash().size(), - }; - response - .payload - .push(MessageBlock { prefix: prefix.to_bytes(), data: transaction }); - } else { - response.block_presences.push(BlockPresence { - r#type: BlockPresenceType::Have as i32, - cid: cid.to_bytes(), - }); - } - }, - None => { - trace!(target: LOG_TARGET, "Missing CID {:?}, hash {:?}", cid, hash); - if entry.send_dont_have { - response.block_presences.push(BlockPresence { - r#type: BlockPresenceType::DontHave as i32, - cid: cid.to_bytes(), - }); - } - }, - } - } - trace!(target: LOG_TARGET, "Response: {:?}", response); - self.ready_blocks().push_back((peer, response)); - } - - fn poll( - &mut self, - _ctx: &mut Context, - _: &mut impl PollParameters, - ) -> Poll> { - if let Some((peer_id, message)) = self.ready_blocks().pop_front() { - return Poll::Ready(NetworkBehaviourAction::NotifyHandler { - peer_id, - handler: NotifyHandler::Any, - event: message, - }) - } - Poll::Pending - } -} - -/// Bitswap protocol error. -#[derive(Debug, thiserror::Error)] -pub enum BitswapError { - /// Protobuf decoding error. - #[error("Failed to decode request: {0}.")] - DecodeProto(#[from] prost::DecodeError), - - /// Protobuf encoding error. - #[error("Failed to encode response: {0}.")] - EncodeProto(#[from] prost::EncodeError), - - /// Client backend error. - #[error(transparent)] - Client(#[from] sp_blockchain::Error), - - /// Error parsing CID - #[error(transparent)] - BadCid(#[from] cid::Error), - - /// Packet read error. - #[error(transparent)] - Read(#[from] io::Error), - - /// Error sending response. - #[error("Failed to send response.")] - SendResponse, -} diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 3fe95deb0c1ed..d7ca8b48a7c88 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -31,7 +31,7 @@ pub use sc_network_common::{ pub use libp2p::{build_multiaddr, core::PublicKey, identity}; -use crate::{bitswap::Bitswap, ExHashT}; +use crate::ExHashT; use core::{fmt, iter}; use futures::future; @@ -79,9 +79,6 @@ where /// Client that contains the blockchain. pub chain: Arc, - /// Bitswap block request protocol implementation. - pub bitswap: Option>, - /// Pool of transactions. /// /// The network worker will fetch transactions from this object in order to propagate them on @@ -139,6 +136,9 @@ where /// Optional warp sync protocol config. pub warp_sync_protocol_config: Option, + + /// Request response protocol configurations + pub request_response_protocol_configs: Vec, } /// Role of the local node. diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 35a91e77da524..320104d0f9554 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -249,12 +249,10 @@ mod discovery; mod peer_info; mod protocol; mod request_responses; -mod schema; mod service; mod transport; mod utils; -pub mod bitswap; pub mod config; pub mod error; pub mod network_state; diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 4610b025dde0d..fb98db3251647 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -137,7 +137,7 @@ impl NetworkWorker where B: BlockT + 'static, H: ExHashT, - Client: sp_blockchain::HeaderBackend + 'static, + Client: HeaderBackend + 'static, { /// Creates the network service. /// @@ -376,7 +376,6 @@ where params.block_request_protocol_config, params.state_request_protocol_config, params.warp_sync_protocol_config, - params.bitswap, params.light_client_request_protocol_config, params.network_config.request_response_protocols, peerset_handle.clone(), @@ -1743,14 +1742,10 @@ where let reason = match cause { Some(ConnectionError::IO(_)) => "transport-error", Some(ConnectionError::Handler(EitherError::A(EitherError::A( - EitherError::A(EitherError::B(EitherError::A( - PingFailure::Timeout, - ))), + EitherError::B(EitherError::A(PingFailure::Timeout)), )))) => "ping-timeout", Some(ConnectionError::Handler(EitherError::A(EitherError::A( - EitherError::A(EitherError::A( - NotifsHandlerError::SyncNotificationsClogged, - )), + EitherError::A(NotifsHandlerError::SyncNotificationsClogged), )))) => "sync-notifications-clogged", Some(ConnectionError::Handler(_)) => "protocol-error", Some(ConnectionError::KeepAliveTimeout) => "keep-alive-timeout", diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 8770e14bf5338..a9505c5341c3d 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -146,11 +146,11 @@ fn build_test_full_node( import_queue, chain_sync: Box::new(chain_sync), metrics_registry: None, - bitswap: None, block_request_protocol_config, state_request_protocol_config, light_client_request_protocol_config, warp_sync_protocol_config: None, + request_response_protocol_configs: Vec::new(), }) .unwrap(); diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 837cdeed0f3d1..5a29e587ceff5 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -883,11 +883,11 @@ where import_queue, chain_sync: Box::new(chain_sync), metrics_registry: None, - bitswap: None, block_request_protocol_config, state_request_protocol_config, light_client_request_protocol_config, warp_sync_protocol_config: Some(warp_protocol_config), + request_response_protocol_configs: Vec::new(), }) .unwrap(); diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 0acdbb1b1b63e..e96421d031d9a 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -51,6 +51,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sp-storage = { version = "6.0.0", path = "../../primitives/storage" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-bitswap = { version = "0.10.0-dev", path = "../network/bitswap" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-network-light = { version = "0.10.0-dev", path = "../network/light" } sc-network-sync = { version = "0.10.0-dev", path = "../network/sync" } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index f03ba6de2866d..5a2f4cf978b41 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -37,7 +37,8 @@ use sc_client_db::{Backend, DatabaseSettings}; use sc_consensus::import_queue::ImportQueue; use sc_executor::RuntimeVersionOf; use sc_keystore::LocalKeystore; -use sc_network::{bitswap::Bitswap, config::SyncMode, NetworkService}; +use sc_network::{config::SyncMode, NetworkService}; +use sc_network_bitswap::BitswapRequestHandler; use sc_network_common::{ service::{NetworkStateInfo, NetworkStatusProvider, NetworkTransaction}, sync::warp::WarpSyncProvider, @@ -746,6 +747,8 @@ where warp_sync, } = params; + let mut request_response_protocol_configs = Vec::new(); + if warp_sync.is_none() && config.network.sync_mode.is_warp() { return Err("Warp sync enabled, but no warp sync provider configured.".into()) } @@ -835,6 +838,13 @@ where config.network.max_parallel_downloads, warp_sync_provider, )?; + + request_response_protocol_configs.push(config.network.ipfs_server.then(|| { + let (handler, protocol_config) = BitswapRequestHandler::new(client.clone()); + spawn_handle.spawn("bitswap-request-handler", Some("networking"), handler.run()); + protocol_config + })); + let network_params = sc_network::config::Params { role: config.role.clone(), executor: { @@ -856,12 +866,15 @@ where fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), import_queue: Box::new(import_queue), chain_sync: Box::new(chain_sync), - bitswap: config.network.ipfs_server.then(|| Bitswap::from_client(client.clone())), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_request_protocol_config, state_request_protocol_config, warp_sync_protocol_config, light_client_request_protocol_config, + request_response_protocol_configs: request_response_protocol_configs + .into_iter() + .flatten() + .collect::>(), }; let has_bootnodes = !network_params.network_config.boot_nodes.is_empty(); From 9df944835d4fa5268cb30d281f8aed21cf7ecf64 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 13 Sep 2022 13:32:34 +0200 Subject: [PATCH 1155/1472] benches: disable caching per default (#12232) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Disable cache for storage benches Signed-off-by: Oliver Tale-Yazdi * Disable caching per default Signed-off-by: Oliver Tale-Yazdi * Update utils/frame/benchmarking-cli/src/storage/cmd.rs Co-authored-by: Bastian Köcher * Add --enable-trie-cache to 'storage' command Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher --- utils/frame/benchmarking-cli/src/block/cmd.rs | 14 ++++++++++++++ utils/frame/benchmarking-cli/src/extrinsic/cmd.rs | 14 ++++++++++++++ utils/frame/benchmarking-cli/src/overhead/cmd.rs | 14 ++++++++++++++ utils/frame/benchmarking-cli/src/storage/cmd.rs | 14 ++++++++++---- 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/utils/frame/benchmarking-cli/src/block/cmd.rs b/utils/frame/benchmarking-cli/src/block/cmd.rs index e4e1716b1c5ac..14cbb1b438686 100644 --- a/utils/frame/benchmarking-cli/src/block/cmd.rs +++ b/utils/frame/benchmarking-cli/src/block/cmd.rs @@ -67,6 +67,12 @@ pub struct BlockCmd { #[allow(missing_docs)] #[clap(flatten)] pub params: BenchmarkParams, + + /// Enable the Trie cache. + /// + /// This should only be used for performance analysis and not for final results. + #[clap(long)] + pub enable_trie_cache: bool, } impl BlockCmd { @@ -98,4 +104,12 @@ impl CliConfiguration for BlockCmd { fn import_params(&self) -> Option<&ImportParams> { Some(&self.import_params) } + + fn trie_cache_maximum_size(&self) -> Result> { + if self.enable_trie_cache { + Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) + } else { + Ok(None) + } + } } diff --git a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs index 2c94a6be50255..339d6126bcd09 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs @@ -72,6 +72,12 @@ pub struct ExtrinsicParams { /// Extrinsic to benchmark. #[clap(long, value_name = "EXTRINSIC", required_unless_present = "list")] pub extrinsic: Option, + + /// Enable the Trie cache. + /// + /// This should only be used for performance analysis and not for final results. + #[clap(long)] + pub enable_trie_cache: bool, } impl ExtrinsicCmd { @@ -132,4 +138,12 @@ impl CliConfiguration for ExtrinsicCmd { fn import_params(&self) -> Option<&ImportParams> { Some(&self.import_params) } + + fn trie_cache_maximum_size(&self) -> Result> { + if self.params.enable_trie_cache { + Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) + } else { + Ok(None) + } + } } diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 1c6753b4a20ea..93b0e7c472647 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -75,6 +75,12 @@ pub struct OverheadParams { /// Good for adding LICENSE headers. #[clap(long, value_name = "PATH")] pub header: Option, + + /// Enable the Trie cache. + /// + /// This should only be used for performance analysis and not for final results. + #[clap(long)] + pub enable_trie_cache: bool, } /// Type of a benchmark. @@ -156,4 +162,12 @@ impl CliConfiguration for OverheadCmd { fn import_params(&self) -> Option<&ImportParams> { Some(&self.import_params) } + + fn trie_cache_maximum_size(&self) -> Result> { + if self.params.enable_trie_cache { + Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) + } else { + Ok(None) + } + } } diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index d28ac4102152f..1d91e8f0b0517 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -105,9 +105,15 @@ pub struct StorageParams { /// Trie cache size in bytes. /// /// Providing `0` will disable the cache. - #[clap(long, default_value = "1024")] + #[clap(long, value_name = "Bytes", default_value = "67108864")] pub trie_cache_size: usize, + /// Enable the Trie cache. + /// + /// This should only be used for performance analysis and not for final results. + #[clap(long)] + pub enable_trie_cache: bool, + /// Include child trees in benchmark. #[clap(long)] pub include_child_trees: bool, @@ -220,10 +226,10 @@ impl CliConfiguration for StorageCmd { } fn trie_cache_maximum_size(&self) -> Result> { - if self.params.trie_cache_size == 0 { - Ok(None) - } else { + if self.params.enable_trie_cache && self.params.trie_cache_size > 0 { Ok(Some(self.params.trie_cache_size)) + } else { + Ok(None) } } } From bb7fb64c0561853080c7f9708af22840030c9727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 13 Sep 2022 12:48:46 +0100 Subject: [PATCH 1156/1472] Make `BasePath::new_temp_dir` return the same path for the program lifetime (#12246) * Make `BasePath::new_temp_dir` return the same path for the program lifetime Instead of returning always a different path, this now returns the same path for the entire lifetime of the program. We still ensure that the path is cleared at the end of the program. * Update client/service/src/config.rs Co-authored-by: Koute * Update client/service/src/config.rs Co-authored-by: Nitwit <47109040+nitwit69@users.noreply.github.com> * FMT Co-authored-by: Koute Co-authored-by: Nitwit <47109040+nitwit69@users.noreply.github.com> --- Cargo.lock | 37 +++++++++++++++++++++++++++++++++- client/service/Cargo.toml | 1 + client/service/src/config.rs | 39 ++++++++++++++++++++++-------------- 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 08915196d5374..efc1aa2976cdd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -873,6 +873,12 @@ 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.1" @@ -8822,6 +8828,7 @@ dependencies = [ "sp-transaction-storage-proof", "sp-trie", "sp-version", + "static_init", "substrate-prometheus-endpoint", "substrate-test-runtime", "substrate-test-runtime-client", @@ -10341,6 +10348,34 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[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.5", + "static_init_macro", + "winapi", +] + +[[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", + "quote", + "syn", +] + [[package]] name = "statrs" version = "0.15.0" @@ -11210,7 +11245,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if 1.0.0", "digest 0.10.3", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index e96421d031d9a..76c61fe17f0da 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -85,6 +85,7 @@ async-trait = "0.1.57" tokio = { version = "1.17.0", features = ["time", "rt-multi-thread", "parking_lot"] } tempfile = "3.1.0" directories = "4.0.1" +static_init = "1.0.3" [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 2fb3f820ebf15..44153e3b914f3 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -262,31 +262,43 @@ impl Default for RpcMethods { } } -/// The base path that is used for everything that needs to be write on disk to run a node. +#[static_init::dynamic(drop, lazy)] +static mut BASE_PATH_TEMP: Option = None; + +/// The base path that is used for everything that needs to be written on disk to run a node. #[derive(Debug)] -pub enum BasePath { - /// A temporary directory is used as base path and will be deleted when dropped. - Temporary(TempDir), - /// A path on the disk. - Permanenent(PathBuf), +pub struct BasePath { + path: PathBuf, } impl BasePath { /// Create a `BasePath` instance using a temporary directory prefixed with "substrate" and use /// it as base path. /// - /// Note: the temporary directory will be created automatically and deleted when the `BasePath` - /// instance is dropped. + /// Note: The temporary directory will be created automatically and deleted when the program + /// exits. Every call to this function will return the same path for the lifetime of the + /// program. pub fn new_temp_dir() -> io::Result { - Ok(BasePath::Temporary(tempfile::Builder::new().prefix("substrate").tempdir()?)) + let mut temp = BASE_PATH_TEMP.write(); + + match &*temp { + Some(p) => Ok(Self::new(p.path())), + None => { + let temp_dir = tempfile::Builder::new().prefix("substrate").tempdir()?; + let path = PathBuf::from(temp_dir.path()); + + *temp = Some(temp_dir); + Ok(Self::new(path)) + }, + } } /// Create a `BasePath` instance based on an existing path on disk. /// /// Note: this function will not ensure that the directory exist nor create the directory. It /// will also not delete the directory when the instance is dropped. - pub fn new>(path: P) -> BasePath { - BasePath::Permanenent(path.as_ref().to_path_buf()) + pub fn new>(path: P) -> BasePath { + Self { path: path.into() } } /// Create a base path from values describing the project. @@ -300,10 +312,7 @@ impl BasePath { /// Retrieve the base path. pub fn path(&self) -> &Path { - match self { - BasePath::Temporary(temp_dir) => temp_dir.path(), - BasePath::Permanenent(path) => path.as_path(), - } + &self.path } /// Returns the configuration directory inside this base path. From 3449fb003534c0c361a92a2d1fe03abc80e4997d Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 13 Sep 2022 14:19:26 +0200 Subject: [PATCH 1157/1472] Remove CanAuthorWith trait (#12213) * Remove CanAuthorWith trait CanAuthotWith trait removed. Also all dependencies, parameters, type paramers were removed. This is related to removal of native runtime. * Remove commented code * Fix code formatting * trigger CI job * trigger CI job * trigger CI job * trigger CI job * trigger CI job * trigger CI job * trigger CI job --- bin/node-template/node/src/service.rs | 13 ++--- bin/node/cli/src/service.rs | 7 +-- client/consensus/aura/src/import_queue.rs | 53 ++++++-------------- client/consensus/aura/src/lib.rs | 24 +++------ client/consensus/babe/src/lib.rs | 41 ++++------------ client/consensus/babe/src/tests.rs | 5 +- client/consensus/pow/src/lib.rs | 45 +++-------------- client/consensus/slots/src/lib.rs | 25 ++-------- primitives/consensus/common/src/lib.rs | 59 ----------------------- 9 files changed, 45 insertions(+), 227 deletions(-) diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index ffb2440caa0ed..caa01761636df 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -1,7 +1,7 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. use node_template_runtime::{self, opaque::Block, RuntimeApi}; -use sc_client_api::{BlockBackend, ExecutorProvider}; +use sc_client_api::BlockBackend; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; pub use sc_executor::NativeElseWasmExecutor; use sc_finality_grandpa::SharedVoterState; @@ -113,7 +113,7 @@ pub fn new_partial( let slot_duration = sc_consensus_aura::slot_duration(&*client)?; let import_queue = - sc_consensus_aura::import_queue::(ImportQueueParams { + sc_consensus_aura::import_queue::(ImportQueueParams { block_import: grandpa_block_import.clone(), justification_import: Some(Box::new(grandpa_block_import.clone())), client: client.clone(), @@ -129,9 +129,6 @@ pub fn new_partial( Ok((timestamp, slot)) }, spawner: &task_manager.spawn_essential_handle(), - can_author_with: sp_consensus::CanAuthorWithNativeVersion::new( - client.executor().clone(), - ), registry: config.prometheus_registry(), check_for_equivocation: Default::default(), telemetry: telemetry.as_ref().map(|x| x.handle()), @@ -254,12 +251,9 @@ pub fn new_full(mut config: Configuration) -> Result telemetry.as_ref().map(|x| x.handle()), ); - let can_author_with = - sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); - let slot_duration = sc_consensus_aura::slot_duration(&*client)?; - let aura = sc_consensus_aura::start_aura::( + let aura = sc_consensus_aura::start_aura::( StartAuraParams { slot_duration, client, @@ -280,7 +274,6 @@ pub fn new_full(mut config: Configuration) -> Result force_authoring, backoff_authoring_blocks, keystore: keystore_container.sync_keystore(), - can_author_with, sync_oracle: network.clone(), justification_sync_link: network.clone(), block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32), diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 2152301ac2d42..c058e22fa7a97 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -26,7 +26,7 @@ use futures::prelude::*; use kitchensink_runtime::RuntimeApi; use node_executor::ExecutorDispatch; use node_primitives::Block; -use sc_client_api::{BlockBackend, ExecutorProvider}; +use sc_client_api::BlockBackend; use sc_consensus_babe::{self, SlotProportion}; use sc_executor::NativeElseWasmExecutor; use sc_network::NetworkService; @@ -227,7 +227,6 @@ pub fn new_partial( }, &task_manager.spawn_essential_handle(), config.prometheus_registry(), - sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()), telemetry.as_ref().map(|x| x.handle()), )?; @@ -422,9 +421,6 @@ pub fn new_full_base( telemetry.as_ref().map(|x| x.handle()), ); - let can_author_with = - sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); - let client_clone = client.clone(); let slot_duration = babe_link.config().slot_duration(); let babe_config = sc_consensus_babe::BabeParams { @@ -463,7 +459,6 @@ pub fn new_full_base( force_authoring, backoff_authoring_blocks, babe_link, - can_author_with, block_proposal_slot_portion: SlotProportion::new(0.5), max_block_proposal_slot_portion: None, telemetry: telemetry.as_ref().map(|x| x.handle()), diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 30554006732c0..31fe7bbaa1095 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -35,7 +35,7 @@ use sp_blockchain::{ well_known_cache_keys::{self, Id as CacheKeyId}, HeaderBackend, }; -use sp_consensus::{CanAuthorWith, Error as ConsensusError}; +use sp_consensus::Error as ConsensusError; use sp_consensus_aura::{ digests::CompatibleDigestItem, inherents::AuraInherentData, AuraApi, ConsensusLog, AURA_ENGINE_ID, @@ -109,27 +109,24 @@ where } /// A verifier for Aura blocks. -pub struct AuraVerifier { +pub struct AuraVerifier { client: Arc, phantom: PhantomData

, create_inherent_data_providers: CIDP, - can_author_with: CAW, check_for_equivocation: CheckForEquivocation, telemetry: Option, } -impl AuraVerifier { +impl AuraVerifier { pub(crate) fn new( client: Arc, create_inherent_data_providers: CIDP, - can_author_with: CAW, check_for_equivocation: CheckForEquivocation, telemetry: Option, ) -> Self { Self { client, create_inherent_data_providers, - can_author_with, check_for_equivocation, telemetry, phantom: PhantomData, @@ -137,10 +134,9 @@ impl AuraVerifier { } } -impl AuraVerifier +impl AuraVerifier where P: Send + Sync + 'static, - CAW: Send + Sync + 'static, CIDP: Send, { async fn check_inherents( @@ -154,19 +150,8 @@ where where C: ProvideRuntimeApi, C::Api: BlockBuilderApi, - CAW: CanAuthorWith, CIDP: CreateInherentDataProviders, { - if let Err(e) = self.can_author_with.can_author_with(&block_id) { - debug!( - target: "aura", - "Skipping `check_inherents` as authoring version is not compatible: {}", - e, - ); - - return Ok(()) - } - let inherent_res = self .client .runtime_api() @@ -187,14 +172,13 @@ where } #[async_trait::async_trait] -impl Verifier for AuraVerifier +impl Verifier for AuraVerifier where C: ProvideRuntimeApi + Send + Sync + sc_client_api::backend::AuxStore + BlockOf, C::Api: BlockBuilderApi + AuraApi> + ApiExt, P: Pair + Send + Sync + 'static, P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + 'static, P::Signature: Encode + Decode, - CAW: CanAuthorWith + Send + Sync + 'static, CIDP: CreateInherentDataProviders + Send + Sync, CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { @@ -338,7 +322,7 @@ impl Default for CheckForEquivocation { } /// Parameters of [`import_queue`]. -pub struct ImportQueueParams<'a, Block, I, C, S, CAW, CIDP> { +pub struct ImportQueueParams<'a, Block, I, C, S, CIDP> { /// The block import to use. pub block_import: I, /// The justification import. @@ -351,8 +335,6 @@ pub struct ImportQueueParams<'a, Block, I, C, S, CAW, CIDP> { pub spawner: &'a S, /// The prometheus registry. pub registry: Option<&'a Registry>, - /// Can we author with the current node? - pub can_author_with: CAW, /// Should we check for equivocation? pub check_for_equivocation: CheckForEquivocation, /// Telemetry instance used to report telemetry metrics. @@ -360,7 +342,7 @@ pub struct ImportQueueParams<'a, Block, I, C, S, CAW, CIDP> { } /// Start an import queue for the Aura consensus algorithm. -pub fn import_queue( +pub fn import_queue( ImportQueueParams { block_import, justification_import, @@ -368,10 +350,9 @@ pub fn import_queue( create_inherent_data_providers, spawner, registry, - can_author_with, check_for_equivocation, telemetry, - }: ImportQueueParams, + }: ImportQueueParams, ) -> Result, sp_consensus::Error> where Block: BlockT, @@ -392,14 +373,12 @@ where P::Public: Clone + Eq + Send + Sync + Hash + Debug + Encode + Decode, P::Signature: Encode + Decode, S: sp_core::traits::SpawnEssentialNamed, - CAW: CanAuthorWith + Send + Sync + 'static, CIDP: CreateInherentDataProviders + Sync + Send + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { - let verifier = build_verifier::(BuildVerifierParams { + let verifier = build_verifier::(BuildVerifierParams { client, create_inherent_data_providers, - can_author_with, check_for_equivocation, telemetry, }); @@ -408,13 +387,11 @@ where } /// Parameters of [`build_verifier`]. -pub struct BuildVerifierParams { +pub struct BuildVerifierParams { /// The client to interact with the chain. pub client: Arc, /// Something that can create the inherent data providers. pub create_inherent_data_providers: CIDP, - /// Can we author with the current node? - pub can_author_with: CAW, /// Should we check for equivocation? pub check_for_equivocation: CheckForEquivocation, /// Telemetry instance used to report telemetry metrics. @@ -422,19 +399,17 @@ pub struct BuildVerifierParams { } /// Build the [`AuraVerifier`] -pub fn build_verifier( +pub fn build_verifier( BuildVerifierParams { client, create_inherent_data_providers, - can_author_with, check_for_equivocation, telemetry, - }: BuildVerifierParams, -) -> AuraVerifier { - AuraVerifier::<_, P, _, _>::new( + }: BuildVerifierParams, +) -> AuraVerifier { + AuraVerifier::<_, P, _>::new( client, create_inherent_data_providers, - can_author_with, check_for_equivocation, telemetry, ) diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 92fe1fa3cf29d..0bdc663815051 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -47,9 +47,7 @@ use sc_telemetry::TelemetryHandle; use sp_api::ProvideRuntimeApi; use sp_application_crypto::{AppKey, AppPublic}; use sp_blockchain::{HeaderBackend, Result as CResult}; -use sp_consensus::{ - BlockOrigin, CanAuthorWith, Environment, Error as ConsensusError, Proposer, SelectChain, -}; +use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain}; use sp_consensus_slots::Slot; use sp_core::crypto::{ByteArray, Pair, Public}; use sp_inherents::CreateInherentDataProviders; @@ -108,7 +106,7 @@ fn slot_author(slot: Slot, authorities: &[AuthorityId

]) -> Option<&A } /// Parameters of [`start_aura`]. -pub struct StartAuraParams { +pub struct StartAuraParams { /// The duration of a slot. pub slot_duration: SlotDuration, /// The client to interact with the chain. @@ -131,8 +129,6 @@ pub struct StartAuraParams { pub backoff_authoring_blocks: Option, /// The keystore used by the node. pub keystore: SyncCryptoStorePtr, - /// Can we author a block with this node? - pub can_author_with: CAW, /// The proportion of the slot dedicated to proposing. /// /// The block proposing will be limited to this proportion of the slot from the starting of the @@ -147,7 +143,7 @@ pub struct StartAuraParams { } /// Start the aura worker. The returned future should be run in a futures executor. -pub fn start_aura( +pub fn start_aura( StartAuraParams { slot_duration, client, @@ -160,11 +156,10 @@ pub fn start_aura( force_authoring, backoff_authoring_blocks, keystore, - can_author_with, block_proposal_slot_portion, max_block_proposal_slot_portion, telemetry, - }: StartAuraParams, + }: StartAuraParams, ) -> Result, sp_consensus::Error> where P: Pair + Send + Sync, @@ -182,7 +177,6 @@ where CIDP: CreateInherentDataProviders + Send, CIDP::InherentDataProviders: InherentDataProviderExt + Send, BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, - CAW: CanAuthorWith + Send, Error: std::error::Error + Send + From + 'static, { let worker = build_aura_worker::(BuildAuraWorkerParams { @@ -205,7 +199,6 @@ where SimpleSlotWorkerToSlotWorker(worker), sync_oracle, create_inherent_data_providers, - can_author_with, )) } @@ -568,9 +561,7 @@ mod tests { use sc_keystore::LocalKeystore; use sc_network_test::{Block as TestBlock, *}; use sp_application_crypto::key_types::AURA; - use sp_consensus::{ - AlwaysCanAuthor, DisableProofRecording, NoNetwork as DummyOracle, Proposal, - }; + use sp_consensus::{DisableProofRecording, NoNetwork as DummyOracle, Proposal}; use sp_consensus_aura::sr25519::AuthorityPair; use sp_inherents::InherentData; use sp_keyring::sr25519::Keyring; @@ -633,7 +624,6 @@ mod tests { type AuraVerifier = import_queue::AuraVerifier< PeersFullClient, AuthorityPair, - AlwaysCanAuthor, Box< dyn CreateInherentDataProviders< TestBlock, @@ -670,7 +660,6 @@ mod tests { Ok((timestamp, slot)) }), - AlwaysCanAuthor, CheckForEquivocation::Yes, None, ) @@ -738,7 +727,7 @@ mod tests { let slot_duration = slot_duration(&*client).expect("slot duration available"); aura_futures.push( - start_aura::(StartAuraParams { + start_aura::(StartAuraParams { slot_duration, block_import: client.clone(), select_chain, @@ -760,7 +749,6 @@ mod tests { BackoffAuthoringOnFinalizedHeadLagging::default(), ), keystore, - can_author_with: sp_consensus::AlwaysCanAuthor, block_proposal_slot_portion: SlotProportion::new(0.5), max_block_proposal_slot_portion: None, telemetry: None, diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 1303915efee49..198de865bb290 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -115,8 +115,7 @@ use sp_blockchain::{ Backend as _, Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult, }; use sp_consensus::{ - BlockOrigin, CacheKeyId, CanAuthorWith, Environment, Error as ConsensusError, Proposer, - SelectChain, + BlockOrigin, CacheKeyId, Environment, Error as ConsensusError, Proposer, SelectChain, }; use sp_consensus_babe::inherents::BabeInherentData; use sp_consensus_slots::Slot; @@ -370,7 +369,7 @@ where } /// Parameters for BABE. -pub struct BabeParams { +pub struct BabeParams { /// The keystore that manages the keys of the node. pub keystore: SyncCryptoStorePtr, @@ -406,9 +405,6 @@ pub struct BabeParams { /// The source of timestamps for relative slots pub babe_link: BabeLink, - /// Checks if the current native implementation can author with a runtime at a given block. - pub can_author_with: CAW, - /// The proportion of the slot dedicated to proposing. /// /// The block proposing will be limited to this proportion of the slot from the starting of the @@ -425,7 +421,7 @@ pub struct BabeParams { } /// Start the babe worker. -pub fn start_babe( +pub fn start_babe( BabeParams { keystore, client, @@ -438,11 +434,10 @@ pub fn start_babe( force_authoring, backoff_authoring_blocks, babe_link, - can_author_with, block_proposal_slot_portion, max_block_proposal_slot_portion, telemetry, - }: BabeParams, + }: BabeParams, ) -> Result, sp_consensus::Error> where B: BlockT, @@ -468,7 +463,6 @@ where CIDP: CreateInherentDataProviders + Send + Sync + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send, BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, - CAW: CanAuthorWith + Send + Sync + 'static, Error: std::error::Error + Send + From + From + 'static, { const HANDLE_BUFFER_SIZE: usize = 1024; @@ -500,7 +494,6 @@ where sc_consensus_slots::SimpleSlotWorkerToSlotWorker(worker), sync_oracle, create_inherent_data_providers, - can_author_with, ); let (worker_tx, worker_rx) = channel(HANDLE_BUFFER_SIZE); @@ -1009,23 +1002,21 @@ impl BabeLink { } /// A verifier for Babe blocks. -pub struct BabeVerifier { +pub struct BabeVerifier { client: Arc, select_chain: SelectChain, create_inherent_data_providers: CIDP, config: BabeConfiguration, epoch_changes: SharedEpochChanges, - can_author_with: CAW, telemetry: Option, } -impl BabeVerifier +impl BabeVerifier where Block: BlockT, Client: AuxStore + HeaderBackend + HeaderMetadata + ProvideRuntimeApi, Client::Api: BlockBuilderApi + BabeApi, SelectChain: sp_consensus::SelectChain, - CAW: CanAuthorWith, CIDP: CreateInherentDataProviders, { async fn check_inherents( @@ -1036,16 +1027,6 @@ where create_inherent_data_providers: CIDP::InherentDataProviders, execution_context: ExecutionContext, ) -> Result<(), Error> { - if let Err(e) = self.can_author_with.can_author_with(&block_id) { - debug!( - target: "babe", - "Skipping `check_inherents` as authoring version is not compatible: {}", - e, - ); - - return Ok(()) - } - let inherent_res = self .client .runtime_api() @@ -1150,8 +1131,8 @@ type BlockVerificationResult = Result<(BlockImportParams, Option)>>), String>; #[async_trait::async_trait] -impl Verifier - for BabeVerifier +impl Verifier + for BabeVerifier where Block: BlockT, Client: HeaderMetadata @@ -1162,7 +1143,6 @@ where + AuxStore, Client::Api: BlockBuilderApi + BabeApi, SelectChain: sp_consensus::SelectChain, - CAW: CanAuthorWith + Send + Sync, CIDP: CreateInherentDataProviders + Send + Sync, CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { @@ -1773,7 +1753,7 @@ where /// /// The block import object provided must be the `BabeBlockImport` or a wrapper /// of it, otherwise crucial import logic will be omitted. -pub fn import_queue( +pub fn import_queue( babe_link: BabeLink, block_import: Inner, justification_import: Option>, @@ -1782,7 +1762,6 @@ pub fn import_queue( create_inherent_data_providers: CIDP, spawner: &impl sp_core::traits::SpawnEssentialNamed, registry: Option<&Registry>, - can_author_with: CAW, telemetry: Option, ) -> ClientResult> where @@ -1802,7 +1781,6 @@ where + 'static, Client::Api: BlockBuilderApi + BabeApi + ApiExt, SelectChain: sp_consensus::SelectChain + 'static, - CAW: CanAuthorWith + Send + Sync + 'static, CIDP: CreateInherentDataProviders + Send + Sync + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { @@ -1811,7 +1789,6 @@ where create_inherent_data_providers, config: babe_link.config, epoch_changes: babe_link.epoch_changes, - can_author_with, telemetry, client, }; diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 7207b7a36c3d4..ab3805138482c 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -31,7 +31,7 @@ use sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging; use sc_keystore::LocalKeystore; use sc_network_test::{Block as TestBlock, *}; use sp_application_crypto::key_types::BABE; -use sp_consensus::{AlwaysCanAuthor, DisableProofRecording, NoNetwork as DummyOracle, Proposal}; +use sp_consensus::{DisableProofRecording, NoNetwork as DummyOracle, Proposal}; use sp_consensus_babe::{ inherents::InherentDataProvider, make_transcript, make_transcript_data, AllowedSlots, AuthorityPair, Slot, @@ -235,7 +235,6 @@ pub struct TestVerifier { TestBlock, PeersFullClient, TestSelectChain, - AlwaysCanAuthor, Box< dyn CreateInherentDataProviders< TestBlock, @@ -332,7 +331,6 @@ impl TestNetFactory for BabeTestNet { }), config: data.link.config.clone(), epoch_changes: data.link.epoch_changes.clone(), - can_author_with: AlwaysCanAuthor, telemetry: None, }, mutator: MUTATOR.with(|m| m.borrow().clone()), @@ -447,7 +445,6 @@ fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static backoff_authoring_blocks: Some(BackoffAuthoringOnFinalizedHeadLagging::default()), babe_link: data.link.clone(), keystore, - can_author_with: sp_consensus::AlwaysCanAuthor, justification_sync_link: (), block_proposal_slot_portion: SlotProportion::new(0.5), max_block_proposal_slot_portion: None, diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index f63e453a48026..6c492931d445c 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -56,9 +56,7 @@ use sc_consensus::{ use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder as BlockBuilderApi; use sp_blockchain::{well_known_cache_keys::Id as CacheKeyId, HeaderBackend}; -use sp_consensus::{ - CanAuthorWith, Environment, Error as ConsensusError, Proposer, SelectChain, SyncOracle, -}; +use sp_consensus::{Environment, Error as ConsensusError, Proposer, SelectChain, SyncOracle}; use sp_consensus_pow::{Seal, TotalDifficulty, POW_ENGINE_ID}; use sp_core::ExecutionContext; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; @@ -214,18 +212,17 @@ pub trait PowAlgorithm { } /// A block importer for PoW. -pub struct PowBlockImport { +pub struct PowBlockImport { algorithm: Algorithm, inner: I, select_chain: S, client: Arc, create_inherent_data_providers: Arc, check_inherents_after: <::Header as HeaderT>::Number, - can_author_with: CAW, } -impl Clone - for PowBlockImport +impl Clone + for PowBlockImport { fn clone(&self) -> Self { Self { @@ -235,12 +232,11 @@ impl Clone client: self.client.clone(), create_inherent_data_providers: self.create_inherent_data_providers.clone(), check_inherents_after: self.check_inherents_after, - can_author_with: self.can_author_with.clone(), } } } -impl PowBlockImport +impl PowBlockImport where B: BlockT, I: BlockImport> + Send + Sync, @@ -248,7 +244,6 @@ where C: ProvideRuntimeApi + Send + Sync + HeaderBackend + AuxStore + BlockOf, C::Api: BlockBuilderApi, Algorithm: PowAlgorithm, - CAW: CanAuthorWith, CIDP: CreateInherentDataProviders, { /// Create a new block import suitable to be used in PoW @@ -259,7 +254,6 @@ where check_inherents_after: <::Header as HeaderT>::Number, select_chain: S, create_inherent_data_providers: CIDP, - can_author_with: CAW, ) -> Self { Self { inner, @@ -268,7 +262,6 @@ where check_inherents_after, select_chain, create_inherent_data_providers: Arc::new(create_inherent_data_providers), - can_author_with, } } @@ -283,16 +276,6 @@ where return Ok(()) } - if let Err(e) = self.can_author_with.can_author_with(&block_id) { - debug!( - target: "pow", - "Skipping `check_inherents` as authoring version is not compatible: {}", - e, - ); - - return Ok(()) - } - let inherent_data = inherent_data_providers .create_inherent_data() .map_err(|e| Error::CreateInherents(e))?; @@ -317,8 +300,7 @@ where } #[async_trait::async_trait] -impl BlockImport - for PowBlockImport +impl BlockImport for PowBlockImport where B: BlockT, I: BlockImport> + Send + Sync, @@ -328,7 +310,6 @@ where C::Api: BlockBuilderApi, Algorithm: PowAlgorithm + Send + Sync, Algorithm::Difficulty: 'static + Send, - CAW: CanAuthorWith + Send + Sync, CIDP: CreateInherentDataProviders + Send + Sync, { type Error = ConsensusError; @@ -512,7 +493,7 @@ where /// /// `pre_runtime` is a parameter that allows a custom additional pre-runtime digest to be inserted /// for blocks being built. This can encode authorship information, or just be a graffiti. -pub fn start_mining_worker( +pub fn start_mining_worker( block_import: BoxBlockImport>, client: Arc, select_chain: S, @@ -524,7 +505,6 @@ pub fn start_mining_worker( create_inherent_data_providers: CIDP, timeout: Duration, build_time: Duration, - can_author_with: CAW, ) -> ( MiningHandle>::Proof>, impl Future, @@ -541,7 +521,6 @@ where SO: SyncOracle + Clone + Send + Sync + 'static, L: sc_consensus::JustificationSyncLink, CIDP: CreateInherentDataProviders, - CAW: CanAuthorWith + Clone + Send + 'static, { let mut timer = UntilImportedOrTimeout::new(client.import_notification_stream(), timeout); let worker = MiningHandle::new(algorithm.clone(), block_import, justification_sync_link); @@ -573,16 +552,6 @@ where }; let best_hash = best_header.hash(); - if let Err(err) = can_author_with.can_author_with(&BlockId::Hash(best_hash)) { - warn!( - target: "pow", - "Skipping proposal `can_author_with` returned: {} \ - Probably a node update is required!", - err, - ); - continue - } - if worker.best_hash() == Some(best_hash) { continue } diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 39b40a32f18ca..b9f8c03f2ac88 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -38,13 +38,10 @@ use log::{debug, info, warn}; use sc_consensus::{BlockImport, JustificationSyncLink}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO, CONSENSUS_WARN}; use sp_arithmetic::traits::BaseArithmetic; -use sp_consensus::{CanAuthorWith, Proposal, Proposer, SelectChain, SyncOracle}; +use sp_consensus::{Proposal, Proposer, SelectChain, SyncOracle}; use sp_consensus_slots::{Slot, SlotDuration}; use sp_inherents::CreateInherentDataProviders; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, HashFor, Header as HeaderT}, -}; +use sp_runtime::traits::{Block as BlockT, HashFor, Header as HeaderT}; use sp_timestamp::Timestamp; use std::{fmt::Debug, ops::Deref, time::Duration}; @@ -486,13 +483,12 @@ impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F, G, H, I, J); /// /// Every time a new slot is triggered, `worker.on_slot` is called and the future it returns is /// polled until completion, unless we are major syncing. -pub async fn start_slot_worker( +pub async fn start_slot_worker( slot_duration: SlotDuration, client: C, mut worker: W, sync_oracle: SO, create_inherent_data_providers: CIDP, - can_author_with: CAW, ) where B: BlockT, C: SelectChain, @@ -500,7 +496,6 @@ pub async fn start_slot_worker( SO: SyncOracle + Send, CIDP: CreateInherentDataProviders + Send, CIDP::InherentDataProviders: InherentDataProviderExt + Send, - CAW: CanAuthorWith + Send, { let mut slots = Slots::new(slot_duration.as_duration(), create_inherent_data_providers, client); @@ -518,19 +513,7 @@ pub async fn start_slot_worker( continue } - if let Err(err) = - can_author_with.can_author_with(&BlockId::Hash(slot_info.chain_head.hash())) - { - warn!( - target: "slots", - "Unable to author block in slot {},. `can_author_with` returned: {} \ - Probably a node update is required!", - slot_info.slot, - err, - ); - } else { - let _ = worker.on_slot(slot_info).await; - } + let _ = worker.on_slot(slot_info).await; } } diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index 043533cbf2258..458a5eee259a9 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -25,7 +25,6 @@ use std::{sync::Arc, time::Duration}; use futures::prelude::*; use sp_runtime::{ - generic::BlockId, traits::{Block as BlockT, HashFor}, Digest, }; @@ -268,61 +267,3 @@ where T::is_offline(self) } } - -/// Checks if the current active native block authoring implementation can author with the runtime -/// at the given block. -pub trait CanAuthorWith { - /// See trait docs for more information. - /// - /// # Return - /// - /// - Returns `Ok(())` when authoring is supported. - /// - Returns `Err(_)` when authoring is not supported. - fn can_author_with(&self, at: &BlockId) -> Result<(), String>; -} - -/// Checks if the node can author blocks by using -/// [`NativeVersion::can_author_with`](sp_version::NativeVersion::can_author_with). -#[derive(Clone)] -pub struct CanAuthorWithNativeVersion(T); - -impl CanAuthorWithNativeVersion { - /// Creates a new instance of `Self`. - pub fn new(inner: T) -> Self { - Self(inner) - } -} - -impl + sp_version::GetNativeVersion, Block: BlockT> - CanAuthorWith for CanAuthorWithNativeVersion -{ - fn can_author_with(&self, at: &BlockId) -> Result<(), String> { - match self.0.runtime_version(at) { - Ok(version) => self.0.native_version().can_author_with(&version), - Err(e) => Err(format!( - "Failed to get runtime version at `{}` and will disable authoring. Error: {}", - at, e, - )), - } - } -} - -/// Returns always `true` for `can_author_with`. This is useful for tests. -#[derive(Clone)] -pub struct AlwaysCanAuthor; - -impl CanAuthorWith for AlwaysCanAuthor { - fn can_author_with(&self, _: &BlockId) -> Result<(), String> { - Ok(()) - } -} - -/// Never can author. -#[derive(Clone)] -pub struct NeverCanAuthor; - -impl CanAuthorWith for NeverCanAuthor { - fn can_author_with(&self, _: &BlockId) -> Result<(), String> { - Err("Authoring is always disabled.".to_string()) - } -} From 23bb5a6255bbcd7ce2999044710428bc4a7a924f Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Tue, 13 Sep 2022 21:23:44 +0800 Subject: [PATCH 1158/1472] Create sp-weights crate to store weight primitives (#12219) * Create sp-weights crate to store weight primitives * Fix templates * Fix templates * Fixes * Fixes * cargo fmt * Fixes * Fixes * Use deprecated type alias instead of deprecated unit types * Use deprecated subtraits instead of deprecated hollow new traits * Fixes * Allow deprecation in macro expansion * Add missing where clause during call macro expansion * cargo fmt * Fixes * cargo fmt * Fixes * Fixes * Fixes * Fixes * Move FRAME-specific weight files back to frame_support * Fixes * Update frame/support/src/dispatch.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/src/dispatch.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/src/dispatch.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Add missing header * Rewrite module docs * Fixes * Fixes * Fixes * Fixes * cargo fmt Co-authored-by: Shawn Tabrizi Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 18 + Cargo.toml | 1 + bin/node/executor/tests/basic.rs | 3 +- bin/node/executor/tests/fees.rs | 3 +- bin/node/runtime/src/impls.rs | 5 +- bin/node/runtime/src/lib.rs | 3 +- frame/babe/src/lib.rs | 4 +- frame/babe/src/tests.rs | 2 +- frame/balances/src/tests_composite.rs | 3 +- frame/balances/src/tests_local.rs | 3 +- frame/collective/src/lib.rs | 7 +- frame/collective/src/tests.rs | 5 +- frame/contracts/src/lib.rs | 4 +- frame/contracts/src/tests.rs | 4 +- frame/contracts/src/wasm/runtime.rs | 2 +- .../election-provider-multi-phase/src/lib.rs | 3 +- .../election-provider-support/src/onchain.rs | 2 +- frame/examples/basic/src/lib.rs | 4 +- frame/examples/basic/src/tests.rs | 5 +- frame/executive/src/lib.rs | 4 +- frame/grandpa/src/lib.rs | 4 +- frame/grandpa/src/tests.rs | 2 +- frame/multisig/src/lib.rs | 5 +- frame/preimage/src/lib.rs | 2 +- frame/proxy/src/lib.rs | 3 +- frame/ranked-collective/src/lib.rs | 3 +- frame/recovery/src/lib.rs | 3 +- frame/scheduler/src/lib.rs | 4 +- frame/staking/src/pallet/impls.rs | 3 +- frame/staking/src/tests.rs | 3 +- frame/sudo/src/lib.rs | 2 +- frame/support/Cargo.toml | 2 + .../src/construct_runtime/expand/call.rs | 7 +- .../procedural/src/pallet/expand/call.rs | 4 + frame/support/src/dispatch.rs | 754 +++++++++++++- frame/support/src/lib.rs | 7 +- frame/support/src/traits/misc.rs | 4 +- frame/support/src/weights.rs | 976 ++---------------- frame/support/src/weights/block_weights.rs | 8 +- .../support/src/weights/extrinsic_weights.rs | 8 +- frame/support/src/weights/paritydb_weights.rs | 9 +- frame/support/src/weights/rocksdb_weights.rs | 9 +- frame/support/test/tests/construct_runtime.rs | 6 +- frame/support/test/tests/origin.rs | 2 +- frame/support/test/tests/pallet.rs | 6 +- frame/support/test/tests/pallet_instance.rs | 3 +- frame/system/Cargo.toml | 2 + frame/system/benchmarking/src/lib.rs | 2 +- .../system/src/extensions/check_mortality.rs | 5 +- .../src/extensions/check_non_zero_sender.rs | 2 +- frame/system/src/extensions/check_nonce.rs | 2 +- frame/system/src/extensions/check_weight.rs | 8 +- frame/system/src/lib.rs | 10 +- frame/system/src/limits.rs | 5 +- frame/system/src/tests.rs | 3 +- .../asset-tx-payment/src/lib.rs | 3 +- .../asset-tx-payment/src/tests.rs | 3 +- frame/transaction-payment/src/lib.rs | 17 +- frame/transaction-payment/src/types.rs | 2 +- frame/utility/src/lib.rs | 3 +- frame/utility/src/tests.rs | 4 +- frame/whitelist/src/lib.rs | 3 +- primitives/runtime/Cargo.toml | 1 + primitives/runtime/src/traits.rs | 6 + primitives/weights/Cargo.toml | 40 + primitives/weights/src/lib.rs | 299 ++++++ .../weights/src}/weight_v2.rs | 204 +--- .../benchmarking-cli/src/overhead/weights.hbs | 8 +- .../benchmarking-cli/src/storage/weights.hbs | 9 +- 69 files changed, 1328 insertions(+), 1237 deletions(-) create mode 100644 primitives/weights/Cargo.toml create mode 100644 primitives/weights/src/lib.rs rename {frame/support/src/weights => primitives/weights/src}/weight_v2.rs (68%) diff --git a/Cargo.lock b/Cargo.lock index efc1aa2976cdd..34d2296e019ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2293,6 +2293,7 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-tracing", + "sp-weights", "tt-call", ] @@ -2390,6 +2391,7 @@ dependencies = [ "sp-runtime", "sp-std", "sp-version", + "sp-weights", "substrate-test-runtime-client", ] @@ -10010,6 +10012,7 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-tracing", + "sp-weights", "substrate-test-runtime-client", "zstd", ] @@ -10315,6 +10318,21 @@ dependencies = [ "wasmtime", ] +[[package]] +name = "sp-weights" +version = "4.0.0" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic", + "sp-core", + "sp-debug-derive", + "sp-std", +] + [[package]] name = "spin" version = "0.5.2" diff --git a/Cargo.toml b/Cargo.toml index 9c71dbdf4b52c..4dbf65dc7e1fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -212,6 +212,7 @@ members = [ "primitives/version", "primitives/version/proc-macro", "primitives/wasm-interface", + "primitives/weights", "test-utils/client", "test-utils/derive", "test-utils/runtime", diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 33f71568ec6c5..99a9b83596acf 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -17,8 +17,9 @@ use codec::{Decode, Encode, Joiner}; use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo}, traits::Currency, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Weight}, + weights::Weight, }; use frame_system::{self, AccountInfo, EventRecord, Phase}; use sp_core::{storage::well_known_keys, traits::Externalities}; diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index ae1bfa371469c..6932cb2cea867 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -17,8 +17,9 @@ use codec::{Encode, Joiner}; use frame_support::{ + dispatch::GetDispatchInfo, traits::Currency, - weights::{constants::ExtrinsicBaseWeight, GetDispatchInfo, IdentityFee, WeightToFee}, + weights::{constants::ExtrinsicBaseWeight, IdentityFee, WeightToFee}, }; use kitchensink_runtime::{ constants::{currency::*, time::SLOT_DURATION}, diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 3509592ebf04a..fb2f3cec65290 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -129,7 +129,10 @@ mod multiplier_tests { AdjustmentVariable, MinimumMultiplier, Runtime, RuntimeBlockWeights as BlockWeights, System, TargetBlockFullness, TransactionPayment, }; - use frame_support::weights::{DispatchClass, Weight, WeightToFee}; + use frame_support::{ + dispatch::DispatchClass, + weights::{Weight, WeightToFee}, + }; fn max_normal() -> Weight { BlockWeights::get() diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 966a2e17ea475..2f0efcaa56740 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -28,6 +28,7 @@ use frame_election_provider_support::{ }; use frame_support::{ construct_runtime, + dispatch::DispatchClass, pallet_prelude::Get, parameter_types, traits::{ @@ -37,7 +38,7 @@ use frame_support::{ }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, - ConstantMultiplier, DispatchClass, IdentityFee, Weight, + ConstantMultiplier, IdentityFee, Weight, }, PalletId, RuntimeDebug, }; diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 9a99d8ed995ab..eadaa036332fa 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -23,13 +23,13 @@ use codec::{Decode, Encode}; use frame_support::{ - dispatch::DispatchResultWithPostInfo, + dispatch::{DispatchResultWithPostInfo, Pays}, ensure, traits::{ ConstU32, DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem, OnTimestampSet, OneSessionHandler, }, - weights::{Pays, Weight}, + weights::Weight, BoundedVec, WeakBoundedVec, }; use sp_application_crypto::ByteArray; diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 065105eda1c32..84e55ed5d050b 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -20,8 +20,8 @@ use super::{Call, *}; use frame_support::{ assert_err, assert_noop, assert_ok, + dispatch::{GetDispatchInfo, Pays}, traits::{Currency, EstimateNextSessionRotation, OnFinalize}, - weights::{GetDispatchInfo, Pays}, }; use mock::*; use pallet_session::ShouldEndSession; diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index fa1d2db8b1e49..1276a812c7861 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -21,9 +21,10 @@ use crate::{self as pallet_balances, decl_tests, Config, Pallet}; use frame_support::{ + dispatch::DispatchInfo, parameter_types, traits::{ConstU32, ConstU64, ConstU8}, - weights::{DispatchInfo, IdentityFee, Weight}, + weights::{IdentityFee, Weight}, }; use pallet_transaction_payment::CurrencyAdapter; use sp_core::H256; diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index 3301d90027682..b391b03ed6b6a 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -21,9 +21,10 @@ use crate::{self as pallet_balances, decl_tests, Config, Pallet}; use frame_support::{ + dispatch::DispatchInfo, parameter_types, traits::{ConstU32, ConstU64, ConstU8, StorageMapShim}, - weights::{DispatchInfo, IdentityFee, Weight}, + weights::{IdentityFee, Weight}, }; use pallet_transaction_payment::CurrencyAdapter; use sp_core::H256; diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 7944f826255ec..49da641e3e204 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -49,12 +49,15 @@ use sp_std::{marker::PhantomData, prelude::*, result}; use frame_support::{ codec::{Decode, Encode, MaxEncodedLen}, - dispatch::{DispatchError, DispatchResultWithPostInfo, Dispatchable, PostDispatchInfo}, + dispatch::{ + DispatchError, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, Pays, + PostDispatchInfo, + }, ensure, traits::{ Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers, StorageVersion, }, - weights::{GetDispatchInfo, Pays, Weight}, + weights::Weight, }; #[cfg(test)] diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index b063cc21bd426..13b9a24f7889d 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -18,9 +18,10 @@ use super::{Event as CollectiveEvent, *}; use crate as pallet_collective; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, + dispatch::Pays, + parameter_types, traits::{ConstU32, ConstU64, GenesisBuild, StorageVersion}, - weights::Pays, Hashable, }; use frame_system::{EventRecord, Phase}; diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 9890bd840cc3a..48f1668440387 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -107,10 +107,10 @@ use crate::{ }; use codec::{Encode, HasCompact}; use frame_support::{ - dispatch::Dispatchable, + dispatch::{DispatchClass, Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, ensure, traits::{ConstU32, Contains, Currency, Get, Randomness, ReservableCurrency, Time}, - weights::{DispatchClass, GetDispatchInfo, Pays, PostDispatchInfo, Weight}, + weights::Weight, BoundedVec, }; use frame_system::{limits::BlockWeights, Pallet as System}; diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 1193d17676e1d..c40968eb2ea57 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -32,14 +32,14 @@ use assert_matches::assert_matches; use codec::Encode; use frame_support::{ assert_err, assert_err_ignore_postinfo, assert_noop, assert_ok, - dispatch::DispatchErrorWithPostInfo, + dispatch::{DispatchClass, DispatchErrorWithPostInfo, PostDispatchInfo}, parameter_types, storage::child, traits::{ BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, OnIdle, OnInitialize, ReservableCurrency, }, - weights::{constants::WEIGHT_PER_SECOND, DispatchClass, PostDispatchInfo, Weight}, + weights::{constants::WEIGHT_PER_SECOND, Weight}, }; use frame_system::{self as system, EventRecord, Phase}; use pretty_assertions::{assert_eq, assert_ne}; diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 5b94611843169..7caa7c5c6fa1f 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -2314,7 +2314,7 @@ pub mod env { call_ptr: u32, call_len: u32, ) -> Result { - use frame_support::{dispatch::GetDispatchInfo, weights::extract_actual_weight}; + use frame_support::dispatch::{extract_actual_weight, GetDispatchInfo}; ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?; let call: ::RuntimeCall = ctx.read_sandbox_memory_as_unbounded(call_ptr, call_len)?; diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index f0378ea7dc83f..1188e3353bc96 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -234,9 +234,10 @@ use frame_election_provider_support::{ ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolution, }; use frame_support::{ + dispatch::DispatchClass, ensure, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, - weights::{DispatchClass, Weight}, + weights::Weight, }; use frame_system::{ensure_none, offchain::SendTransactionTypes}; use scale_info::TypeInfo; diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index c899e021f974a..05bbd11e1ae9d 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -22,7 +22,7 @@ use crate::{ Debug, ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolver, WeightInfo, }; -use frame_support::{traits::Get, weights::DispatchClass}; +use frame_support::{dispatch::DispatchClass, traits::Get}; use sp_npos_elections::*; use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 756333b197090..caa2d825262db 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -273,9 +273,9 @@ use codec::{Decode, Encode}; use frame_support::{ - dispatch::DispatchResult, + dispatch::{ClassifyDispatch, DispatchClass, DispatchResult, Pays, PaysFee, WeighData}, traits::IsSubType, - weights::{ClassifyDispatch, DispatchClass, Pays, PaysFee, WeighData, Weight}, + weights::Weight, }; use frame_system::ensure_signed; use log::info; diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 78cdb3794f8d3..793cb4287f505 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -19,9 +19,10 @@ use crate::*; use frame_support::{ - assert_ok, parameter_types, + assert_ok, + dispatch::{DispatchInfo, GetDispatchInfo}, + parameter_types, traits::{ConstU64, OnInitialize}, - weights::{DispatchInfo, GetDispatchInfo}, }; use sp_core::H256; // The testing primitives are very useful for avoiding having to work with signatures diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 7b71224904378..96e71512e54bc 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -118,12 +118,12 @@ use codec::{Codec, Encode}; use frame_support::{ - dispatch::PostDispatchInfo, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, traits::{ EnsureInherentsAreFirst, ExecuteBlock, OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, }, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Weight}, + weights::Weight, }; use sp_runtime::{ generic::Digest, diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 1fcf5c67150b5..fe5b9861853bf 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -40,11 +40,11 @@ use fg_primitives::{ GRANDPA_ENGINE_ID, }; use frame_support::{ - dispatch::DispatchResultWithPostInfo, + dispatch::{DispatchResultWithPostInfo, Pays}, pallet_prelude::Get, storage, traits::{KeyOwnerProofSystem, OneSessionHandler}, - weights::{Pays, Weight}, + weights::Weight, WeakBoundedVec, }; use scale_info::TypeInfo; diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 07c4fcad3078d..baf71dfff71dc 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -25,8 +25,8 @@ use codec::Encode; use fg_primitives::ScheduledChange; use frame_support::{ assert_err, assert_noop, assert_ok, + dispatch::{GetDispatchInfo, Pays}, traits::{Currency, OnFinalize, OneSessionHandler}, - weights::{GetDispatchInfo, Pays}, }; use frame_system::{EventRecord, Phase}; use sp_core::H256; diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 4593d6dade690..0c7e931e5ea2e 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -53,11 +53,12 @@ pub mod weights; use codec::{Decode, Encode}; use frame_support::{ dispatch::{ - DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, PostDispatchInfo, + DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo, + PostDispatchInfo, }, ensure, traits::{Currency, Get, ReservableCurrency, WrapperKeepOpaque}, - weights::{GetDispatchInfo, Weight}, + weights::Weight, RuntimeDebug, }; use frame_system::{self as system, RawOrigin}; diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index e4616078b0761..749e5924cc885 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -41,10 +41,10 @@ use sp_std::prelude::*; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ + dispatch::Pays, ensure, pallet_prelude::Get, traits::{Currency, PreimageProvider, PreimageRecipient, ReservableCurrency}, - weights::Pays, BoundedVec, }; use scale_info::TypeInfo; diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 7467fb0988dd6..dcc19e85085f8 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -35,10 +35,9 @@ pub mod weights; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::DispatchError, + dispatch::{DispatchError, GetDispatchInfo}, ensure, traits::{Currency, Get, InstanceFilter, IsSubType, IsType, OriginTrait, ReservableCurrency}, - weights::GetDispatchInfo, RuntimeDebug, }; use frame_system::{self as system}; diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 7f212b3859776..44b942d000012 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -52,10 +52,9 @@ use sp_std::{marker::PhantomData, prelude::*}; use frame_support::{ codec::{Decode, Encode, MaxEncodedLen}, - dispatch::{DispatchError, DispatchResultWithPostInfo}, + dispatch::{DispatchError, DispatchResultWithPostInfo, PostDispatchInfo}, ensure, traits::{EnsureOrigin, PollStatus, Polling, VoteTally}, - weights::PostDispatchInfo, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index dd9e7208320c4..7b85c119e68c5 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -160,9 +160,8 @@ use sp_runtime::traits::{CheckedAdd, CheckedMul, Dispatchable, SaturatedConversi use sp_std::prelude::*; use frame_support::{ - dispatch::PostDispatchInfo, + dispatch::{GetDispatchInfo, PostDispatchInfo}, traits::{BalanceStatus, Currency, ReservableCurrency}, - weights::GetDispatchInfo, BoundedVec, RuntimeDebug, }; diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 39dbac17cedd2..7e9b8e1b92fb7 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -60,12 +60,12 @@ pub mod weights; use codec::{Codec, Decode, Encode}; use frame_support::{ - dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter}, + dispatch::{DispatchError, DispatchResult, Dispatchable, GetDispatchInfo, Parameter}, traits::{ schedule::{self, DispatchTime, MaybeHashed}, EnsureOrigin, Get, IsType, OriginTrait, PalletInfoAccess, PrivilegeCmp, StorageVersion, }, - weights::{GetDispatchInfo, Weight}, + weights::Weight, }; use frame_system::{self as system, ensure_signed}; pub use pallet::*; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 386c413132f6c..13038527bc2f8 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -22,12 +22,13 @@ use frame_election_provider_support::{ Supports, VoteWeight, VoterOf, }; use frame_support::{ + dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ Currency, CurrencyToVote, Defensive, EstimateNextNewSession, Get, Imbalance, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, }, - weights::{Weight, WithPostDispatchInfo}, + weights::Weight, }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 9807cffd43909..85badfac769af 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -21,10 +21,9 @@ use super::{ConfigOp, Event, MaxUnlockingChunks, *}; use frame_election_provider_support::{ElectionProvider, SortedListProvider, Support}; use frame_support::{ assert_noop, assert_ok, assert_storage_noop, bounded_vec, - dispatch::WithPostDispatchInfo, + dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, pallet_prelude::*, traits::{Currency, Get, ReservableCurrency}, - weights::{extract_actual_weight, GetDispatchInfo}, }; use mock::*; use pallet_balances::Error as BalancesError; diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 96cd2d1615449..69eac2c1b93c4 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -95,7 +95,7 @@ use sp_runtime::{traits::StaticLookup, DispatchResult}; use sp_std::prelude::*; -use frame_support::{traits::UnfilteredDispatchable, weights::GetDispatchInfo}; +use frame_support::{dispatch::GetDispatchInfo, traits::UnfilteredDispatchable}; #[cfg(test)] mod mock; diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 6f0831b751b45..d0a40a09f2211 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -26,6 +26,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } +sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" @@ -62,6 +63,7 @@ std = [ "sp-inherents/std", "sp-staking/std", "sp-state-machine", + "sp-weights/std", "frame-support-procedural/std", "log/std", ] diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index b415132ab0426..101f0c371382f 100644 --- a/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -123,6 +123,9 @@ pub fn expand_outer_dispatch( } } } + // Deprecated, but will warn when used + #[allow(deprecated)] + impl #scrate::weights::GetDispatchInfo for RuntimeCall {} impl #scrate::dispatch::GetCallMetadata for RuntimeCall { fn get_call_metadata(&self) -> #scrate::dispatch::CallMetadata { use #scrate::dispatch::GetCallName; @@ -161,8 +164,8 @@ pub fn expand_outer_dispatch( impl #scrate::dispatch::Dispatchable for RuntimeCall { type Origin = Origin; type Config = RuntimeCall; - type Info = #scrate::weights::DispatchInfo; - type PostInfo = #scrate::weights::PostDispatchInfo; + type Info = #scrate::dispatch::DispatchInfo; + type PostInfo = #scrate::dispatch::PostDispatchInfo; fn dispatch(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { if !::filter_call(&origin, &self) { return #scrate::sp_std::result::Result::Err( diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 8b2922b5fa4f2..d5c84fa37510d 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -255,6 +255,10 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { } } + // Deprecated, but will warn when used + #[allow(deprecated)] + impl<#type_impl_gen> #frame_support::weights::GetDispatchInfo for #call_ident<#type_use_gen> #where_clause {} + impl<#type_impl_gen> #frame_support::dispatch::GetCallName for #call_ident<#type_use_gen> #where_clause { diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 9a6654d5524d4..1d8930f96fbe5 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -31,18 +31,22 @@ pub use crate::{ traits::{ CallMetadata, GetCallMetadata, GetCallName, GetStorageVersion, UnfilteredDispatchable, }, - weights::{ - ClassifyDispatch, DispatchInfo, GetDispatchInfo, PaysFee, PostDispatchInfo, - TransactionPriority, WeighData, Weight, WithPostDispatchInfo, - }, }; -pub use sp_runtime::{traits::Dispatchable, DispatchError, RuntimeDebug}; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_runtime::{ + generic::{CheckedExtrinsic, UncheckedExtrinsic}, + traits::SignedExtension, +}; +pub use sp_runtime::{ + traits::Dispatchable, transaction_validity::TransactionPriority, DispatchError, RuntimeDebug, +}; +pub use sp_weights::Weight; /// The return type of a `Dispatchable` in frame. When returned explicitly from /// a dispatchable function it allows overriding the default `PostDispatchInfo` /// returned from a dispatch. -pub type DispatchResultWithPostInfo = - sp_runtime::DispatchResultWithInfo; +pub type DispatchResultWithPostInfo = sp_runtime::DispatchResultWithInfo; /// Unaugmented version of `DispatchResultWithPostInfo` that can be returned from /// dispatchable functions and is automatically converted to the augmented type. Should be @@ -51,8 +55,7 @@ pub type DispatchResultWithPostInfo = pub type DispatchResult = Result<(), sp_runtime::DispatchError>; /// The error type contained in a `DispatchResultWithPostInfo`. -pub type DispatchErrorWithPostInfo = - sp_runtime::DispatchErrorWithPostInfo; +pub type DispatchErrorWithPostInfo = sp_runtime::DispatchErrorWithPostInfo; /// Serializable version of pallet dispatchable. pub trait Callable { @@ -91,6 +94,552 @@ impl From> for RawOrigin { pub trait Parameter: Codec + EncodeLike + Clone + Eq + fmt::Debug + scale_info::TypeInfo {} impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + scale_info::TypeInfo {} +/// Means of classifying a dispatchable function. +pub trait ClassifyDispatch { + /// Classify the dispatch function based on input data `target` of type `T`. When implementing + /// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except + /// origin). + fn classify_dispatch(&self, target: T) -> DispatchClass; +} + +/// Indicates if dispatch function should pay fees or not. +/// +/// If set to `Pays::No`, the block resource limits are applied, yet no fee is deducted. +pub trait PaysFee { + fn pays_fee(&self, _target: T) -> Pays; +} + +/// Explicit enum to denote if a transaction pays fee or not. +#[derive(Clone, Copy, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)] +pub enum Pays { + /// Transactor will pay related fees. + Yes, + /// Transactor will NOT pay related fees. + No, +} + +impl Default for Pays { + fn default() -> Self { + Self::Yes + } +} + +impl From for PostDispatchInfo { + fn from(pays_fee: Pays) -> Self { + Self { actual_weight: None, pays_fee } + } +} + +/// A generalized group of dispatch types. +/// +/// NOTE whenever upgrading the enum make sure to also update +/// [DispatchClass::all] and [DispatchClass::non_mandatory] helper functions. +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum DispatchClass { + /// A normal dispatch. + Normal, + /// An operational dispatch. + Operational, + /// A mandatory dispatch. These kinds of dispatch are always included regardless of their + /// weight, therefore it is critical that they are separately validated to ensure that a + /// malicious validator cannot craft a valid but impossibly heavy block. Usually this just + /// means ensuring that the extrinsic can only be included once and that it is always very + /// light. + /// + /// Do *NOT* use it for extrinsics that can be heavy. + /// + /// The only real use case for this is inherent extrinsics that are required to execute in a + /// block for the block to be valid, and it solves the issue in the case that the block + /// initialization is sufficiently heavy to mean that those inherents do not fit into the + /// block. Essentially, we assume that in these exceptional circumstances, it is better to + /// allow an overweight block to be created than to not allow any block at all to be created. + Mandatory, +} + +impl Default for DispatchClass { + fn default() -> Self { + Self::Normal + } +} + +impl DispatchClass { + /// Returns an array containing all dispatch classes. + pub fn all() -> &'static [DispatchClass] { + &[DispatchClass::Normal, DispatchClass::Operational, DispatchClass::Mandatory] + } + + /// Returns an array of all dispatch classes except `Mandatory`. + pub fn non_mandatory() -> &'static [DispatchClass] { + &[DispatchClass::Normal, DispatchClass::Operational] + } +} + +/// A trait that represents one or many values of given type. +/// +/// Useful to accept as parameter type to let the caller pass either a single value directly +/// or an iterator. +pub trait OneOrMany { + /// The iterator type. + type Iter: Iterator; + /// Convert this item into an iterator. + fn into_iter(self) -> Self::Iter; +} + +impl OneOrMany for DispatchClass { + type Iter = sp_std::iter::Once; + fn into_iter(self) -> Self::Iter { + sp_std::iter::once(self) + } +} + +impl<'a> OneOrMany for &'a [DispatchClass] { + type Iter = sp_std::iter::Cloned>; + fn into_iter(self) -> Self::Iter { + self.iter().cloned() + } +} + +/// A bundle of static information collected from the `#[pallet::weight]` attributes. +#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] +pub struct DispatchInfo { + /// Weight of this transaction. + pub weight: Weight, + /// Class of this transaction. + pub class: DispatchClass, + /// Does this transaction pay fees. + pub pays_fee: Pays, +} + +/// A `Dispatchable` function (aka transaction) that can carry some static information along with +/// it, using the `#[pallet::weight]` attribute. +pub trait GetDispatchInfo { + /// Return a `DispatchInfo`, containing relevant information of this dispatch. + /// + /// This is done independently of its encoded size. + fn get_dispatch_info(&self) -> DispatchInfo; +} + +impl GetDispatchInfo for () { + fn get_dispatch_info(&self) -> DispatchInfo { + DispatchInfo::default() + } +} + +/// Extract the actual weight from a dispatch result if any or fall back to the default weight. +pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Weight { + match result { + Ok(post_info) => post_info, + Err(err) => &err.post_info, + } + .calc_actual_weight(info) +} + +/// Extract the actual pays_fee from a dispatch result if any or fall back to the default weight. +pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays { + match result { + Ok(post_info) => post_info, + Err(err) => &err.post_info, + } + .pays_fee(info) +} + +/// Weight information that is only available post dispatch. +/// NOTE: This can only be used to reduce the weight or fee, not increase it. +#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] +pub struct PostDispatchInfo { + /// Actual weight consumed by a call or `None` which stands for the worst case static weight. + pub actual_weight: Option, + /// Whether this transaction should pay fees when all is said and done. + pub pays_fee: Pays, +} + +impl PostDispatchInfo { + /// Calculate how much (if any) weight was not used by the `Dispatchable`. + pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight { + info.weight - self.calc_actual_weight(info) + } + + /// Calculate how much weight was actually spent by the `Dispatchable`. + pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight { + if let Some(actual_weight) = self.actual_weight { + actual_weight.min(info.weight) + } else { + info.weight + } + } + + /// Determine if user should actually pay fees at the end of the dispatch. + pub fn pays_fee(&self, info: &DispatchInfo) -> Pays { + // If they originally were not paying fees, or the post dispatch info + // says they should not pay fees, then they don't pay fees. + // This is because the pre dispatch information must contain the + // worst case for weight and fees paid. + if info.pays_fee == Pays::No || self.pays_fee == Pays::No { + Pays::No + } else { + // Otherwise they pay. + Pays::Yes + } + } +} + +impl From<()> for PostDispatchInfo { + fn from(_: ()) -> Self { + Self { actual_weight: None, pays_fee: Default::default() } + } +} + +impl sp_runtime::traits::Printable for PostDispatchInfo { + fn print(&self) { + "actual_weight=".print(); + match self.actual_weight { + Some(weight) => weight.print(), + None => "max-weight".print(), + }; + "pays_fee=".print(); + match self.pays_fee { + Pays::Yes => "Yes".print(), + Pays::No => "No".print(), + } + } +} + +/// Allows easy conversion from `DispatchError` to `DispatchErrorWithPostInfo` for dispatchables +/// that want to return a custom a posterior weight on error. +pub trait WithPostDispatchInfo { + /// Call this on your modules custom errors type in order to return a custom weight on error. + /// + /// # Example + /// + /// ```ignore + /// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100)))?; + /// ensure!(who == me, Error::::NotMe.with_weight(200_000)); + /// ``` + fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo; +} + +impl WithPostDispatchInfo for T +where + T: Into, +{ + fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo { + DispatchErrorWithPostInfo { + post_info: PostDispatchInfo { + actual_weight: Some(actual_weight), + pays_fee: Default::default(), + }, + error: self.into(), + } + } +} + +/// Implementation for unchecked extrinsic. +impl GetDispatchInfo + for UncheckedExtrinsic +where + Call: GetDispatchInfo, + Extra: SignedExtension, +{ + fn get_dispatch_info(&self) -> DispatchInfo { + self.function.get_dispatch_info() + } +} + +/// Implementation for checked extrinsic. +impl GetDispatchInfo for CheckedExtrinsic +where + Call: GetDispatchInfo, +{ + fn get_dispatch_info(&self) -> DispatchInfo { + self.function.get_dispatch_info() + } +} + +/// Implementation for test extrinsic. +#[cfg(feature = "std")] +impl GetDispatchInfo for sp_runtime::testing::TestXt { + fn get_dispatch_info(&self) -> DispatchInfo { + // for testing: weight == size. + DispatchInfo { + weight: Weight::from_ref_time(self.encode().len() as _), + pays_fee: Pays::Yes, + ..Default::default() + } + } +} + +/// A struct holding value for each `DispatchClass`. +#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub struct PerDispatchClass { + /// Value for `Normal` extrinsics. + normal: T, + /// Value for `Operational` extrinsics. + operational: T, + /// Value for `Mandatory` extrinsics. + mandatory: T, +} + +impl PerDispatchClass { + /// Create new `PerDispatchClass` with the same value for every class. + pub fn new(val: impl Fn(DispatchClass) -> T) -> Self { + Self { + normal: val(DispatchClass::Normal), + operational: val(DispatchClass::Operational), + mandatory: val(DispatchClass::Mandatory), + } + } + + /// Get a mutable reference to current value of given class. + pub fn get_mut(&mut self, class: DispatchClass) -> &mut T { + match class { + DispatchClass::Operational => &mut self.operational, + DispatchClass::Normal => &mut self.normal, + DispatchClass::Mandatory => &mut self.mandatory, + } + } + + /// Get current value for given class. + pub fn get(&self, class: DispatchClass) -> &T { + match class { + DispatchClass::Normal => &self.normal, + DispatchClass::Operational => &self.operational, + DispatchClass::Mandatory => &self.mandatory, + } + } +} + +impl PerDispatchClass { + /// Set the value of given class. + pub fn set(&mut self, new: T, class: impl OneOrMany) { + for class in class.into_iter() { + *self.get_mut(class) = new.clone(); + } + } +} + +impl PerDispatchClass { + /// Returns the total weight consumed by all extrinsics in the block. + pub fn total(&self) -> Weight { + let mut sum = Weight::zero(); + for class in DispatchClass::all() { + sum = sum.saturating_add(*self.get(*class)); + } + sum + } + + /// Add some weight of a specific dispatch class, saturating at the numeric bounds of `Weight`. + pub fn add(&mut self, weight: Weight, class: DispatchClass) { + let value = self.get_mut(class); + *value = value.saturating_add(weight); + } + + /// Try to add some weight of a specific dispatch class, returning Err(()) if overflow would + /// occur. + pub fn checked_add(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> { + let value = self.get_mut(class); + *value = value.checked_add(&weight).ok_or(())?; + Ok(()) + } + + /// Subtract some weight of a specific dispatch class, saturating at the numeric bounds of + /// `Weight`. + pub fn sub(&mut self, weight: Weight, class: DispatchClass) { + let value = self.get_mut(class); + *value = value.saturating_sub(weight); + } +} + +/// Means of weighing some particular kind of data (`T`). +pub trait WeighData { + /// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be + /// a tuple of all arguments given to the function (except origin). + fn weigh_data(&self, target: T) -> Weight; +} + +impl WeighData for Weight { + fn weigh_data(&self, _: T) -> Weight { + return *self + } +} + +impl PaysFee for (Weight, DispatchClass, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.2 + } +} + +impl WeighData for (Weight, DispatchClass) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl WeighData for (Weight, DispatchClass, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (Weight, DispatchClass) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +impl PaysFee for (Weight, DispatchClass) { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl WeighData for (Weight, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (Weight, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for (Weight, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.1 + } +} + +impl From<(Option, Pays)> for PostDispatchInfo { + fn from(post_weight_info: (Option, Pays)) -> Self { + let (actual_weight, pays_fee) = post_weight_info; + Self { actual_weight, pays_fee } + } +} + +impl From> for PostDispatchInfo { + fn from(actual_weight: Option) -> Self { + Self { actual_weight, pays_fee: Default::default() } + } +} + +impl ClassifyDispatch for Weight { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for Weight { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl ClassifyDispatch for (Weight, DispatchClass, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +// TODO: Eventually remove these + +impl From> for PostDispatchInfo { + fn from(maybe_actual_computation: Option) -> Self { + let actual_weight = match maybe_actual_computation { + Some(actual_computation) => Some(Weight::zero().set_ref_time(actual_computation)), + None => None, + }; + Self { actual_weight, pays_fee: Default::default() } + } +} + +impl From<(Option, Pays)> for PostDispatchInfo { + fn from(post_weight_info: (Option, Pays)) -> Self { + let (maybe_actual_time, pays_fee) = post_weight_info; + let actual_weight = match maybe_actual_time { + Some(actual_time) => Some(Weight::zero().set_ref_time(actual_time)), + None => None, + }; + Self { actual_weight, pays_fee } + } +} + +impl ClassifyDispatch for u64 { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for u64 { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl WeighData for u64 { + fn weigh_data(&self, _: T) -> Weight { + return Weight::zero().set_ref_time(*self) + } +} + +impl WeighData for (u64, DispatchClass, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (u64, DispatchClass, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +impl PaysFee for (u64, DispatchClass, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.2 + } +} + +impl WeighData for (u64, DispatchClass) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (u64, DispatchClass) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +impl PaysFee for (u64, DispatchClass) { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl WeighData for (u64, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (u64, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for (u64, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.1 + } +} + +// END TODO + /// Declares a `Module` struct and a `Call` enum, which implements the dispatch logic. /// /// ## Declaration @@ -2629,13 +3178,14 @@ macro_rules! __check_reserved_fn_name { mod tests { use super::*; use crate::{ + dispatch::{DispatchClass, DispatchInfo, Pays}, metadata::*, traits::{ CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, PalletInfo, }, - weights::{DispatchClass, DispatchInfo, Pays, RuntimeDbWeight}, }; + use sp_weights::RuntimeDbWeight; pub trait Config: system::Config + Sized where @@ -2940,3 +3490,187 @@ mod tests { Call::::new_call_variant_aux_0(); } } + +#[cfg(test)] +// Do not complain about unused `dispatch` and `dispatch_aux`. +#[allow(dead_code)] +mod weight_tests { + use super::*; + use sp_core::{parameter_types, Get}; + use sp_weights::RuntimeDbWeight; + + pub trait Config: 'static { + type Origin; + type Balance; + type BlockNumber; + type DbWeight: Get; + type PalletInfo: crate::traits::PalletInfo; + } + + pub struct TraitImpl {} + + parameter_types! { + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 100, + write: 1000, + }; + } + + impl Config for TraitImpl { + type Origin = u32; + type BlockNumber = u32; + type Balance = u32; + type DbWeight = DbWeight; + type PalletInfo = crate::tests::PanicPalletInfo; + } + + decl_module! { + pub struct Module for enum Call where origin: T::Origin, system=self { + // no arguments, fixed weight + #[weight = 1000] + fn f00(_origin) { unimplemented!(); } + + #[weight = (1000, DispatchClass::Mandatory)] + fn f01(_origin) { unimplemented!(); } + + #[weight = (1000, Pays::No)] + fn f02(_origin) { unimplemented!(); } + + #[weight = (1000, DispatchClass::Operational, Pays::No)] + fn f03(_origin) { unimplemented!(); } + + // weight = a x 10 + b + #[weight = ((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes)] + fn f11(_origin, _a: u32, _eb: u32) { unimplemented!(); } + + #[weight = (0, DispatchClass::Operational, Pays::Yes)] + fn f12(_origin, _a: u32, _eb: u32) { unimplemented!(); } + + #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_ref_time(10_000)] + fn f20(_origin) { unimplemented!(); } + + #[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_ref_time(40_000)] + fn f21(_origin) { unimplemented!(); } + + } + } + + #[test] + fn weights_are_correct() { + // #[weight = 1000] + let info = Call::::f00 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(1000)); + assert_eq!(info.class, DispatchClass::Normal); + assert_eq!(info.pays_fee, Pays::Yes); + + // #[weight = (1000, DispatchClass::Mandatory)] + let info = Call::::f01 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(1000)); + assert_eq!(info.class, DispatchClass::Mandatory); + assert_eq!(info.pays_fee, Pays::Yes); + + // #[weight = (1000, Pays::No)] + let info = Call::::f02 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(1000)); + assert_eq!(info.class, DispatchClass::Normal); + assert_eq!(info.pays_fee, Pays::No); + + // #[weight = (1000, DispatchClass::Operational, Pays::No)] + let info = Call::::f03 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(1000)); + assert_eq!(info.class, DispatchClass::Operational); + assert_eq!(info.pays_fee, Pays::No); + + // #[weight = ((_a * 10 + _eb * 1) as Weight, DispatchClass::Normal, Pays::Yes)] + let info = Call::::f11 { _a: 13, _eb: 20 }.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(150)); // 13*10 + 20 + assert_eq!(info.class, DispatchClass::Normal); + assert_eq!(info.pays_fee, Pays::Yes); + + // #[weight = (0, DispatchClass::Operational, Pays::Yes)] + let info = Call::::f12 { _a: 10, _eb: 20 }.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(0)); + assert_eq!(info.class, DispatchClass::Operational); + assert_eq!(info.pays_fee, Pays::Yes); + + // #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + 10_000] + let info = Call::::f20 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(12300)); // 100*3 + 1000*2 + 10_1000 + assert_eq!(info.class, DispatchClass::Normal); + assert_eq!(info.pays_fee, Pays::Yes); + + // #[weight = T::DbWeight::get().reads_writes(6, 5) + 40_000] + let info = Call::::f21 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(45600)); // 100*6 + 1000*5 + 40_1000 + assert_eq!(info.class, DispatchClass::Normal); + assert_eq!(info.pays_fee, Pays::Yes); + } + + #[test] + fn extract_actual_weight_works() { + let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; + assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), Weight::from_ref_time(7)); + assert_eq!( + extract_actual_weight(&Ok(Some(1000).into()), &pre), + Weight::from_ref_time(1000) + ); + assert_eq!( + extract_actual_weight( + &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), + &pre + ), + Weight::from_ref_time(9) + ); + } + + #[test] + fn extract_actual_weight_caps_at_pre_weight() { + let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; + assert_eq!( + extract_actual_weight(&Ok(Some(1250).into()), &pre), + Weight::from_ref_time(1000) + ); + assert_eq!( + extract_actual_weight( + &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(1300))), + &pre + ), + Weight::from_ref_time(1000), + ); + } + + #[test] + fn extract_actual_pays_fee_works() { + let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; + assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::Yes); + assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::Yes); + assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::Yes); + assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::No).into()), &pre), Pays::No); + assert_eq!( + extract_actual_pays_fee( + &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), + &pre + ), + Pays::Yes + ); + assert_eq!( + extract_actual_pays_fee( + &Err(DispatchErrorWithPostInfo { + post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::No }, + error: DispatchError::BadOrigin, + }), + &pre + ), + Pays::No + ); + + let pre = DispatchInfo { + weight: Weight::from_ref_time(1000), + pays_fee: Pays::No, + ..Default::default() + }; + assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::No); + assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::No); + assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::No); + } +} diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 315d856e5d0f8..8dcc51226923b 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1376,7 +1376,10 @@ pub mod pallet_prelude { #[cfg(feature = "std")] pub use crate::traits::GenesisBuild; pub use crate::{ - dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo, Parameter}, + dispatch::{ + DispatchClass, DispatchError, DispatchResult, DispatchResultWithPostInfo, Parameter, + Pays, + }, ensure, inherent::{InherentData, InherentIdentifier, ProvideInherent}, storage, @@ -1391,7 +1394,6 @@ pub mod pallet_prelude { ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, IsType, PalletInfoAccess, StorageInfoTrait, StorageVersion, TypedGet, }, - weights::{DispatchClass, Pays, Weight}, Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity, PartialEqNoBound, RuntimeDebug, RuntimeDebugNoBound, Twox128, Twox256, Twox64Concat, }; @@ -1407,6 +1409,7 @@ pub mod pallet_prelude { MAX_MODULE_ERROR_ENCODED_SIZE, }; pub use sp_std::marker::PhantomData; + pub use sp_weights::Weight; } /// `pallet` attribute macro allows to define a pallet to be used in `construct_runtime!`. diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 59d5ec067baed..7fc4a6fb08a5a 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -711,13 +711,13 @@ pub trait EstimateCallFee { /// /// The dispatch info and the length is deduced from the call. The post info can optionally be /// provided. - fn estimate_call_fee(call: &Call, post_info: crate::weights::PostDispatchInfo) -> Balance; + fn estimate_call_fee(call: &Call, post_info: crate::dispatch::PostDispatchInfo) -> Balance; } // Useful for building mocks. #[cfg(feature = "std")] impl, const T: u32> EstimateCallFee for ConstU32 { - fn estimate_call_fee(_: &Call, _: crate::weights::PostDispatchInfo) -> Balance { + fn estimate_call_fee(_: &Call, _: crate::dispatch::PostDispatchInfo) -> Balance { T.into() } } diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index b4fd896e865dc..9ff49b97bf21f 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -15,102 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Primitives for transaction weighting. -//! -//! Every dispatchable function is responsible for providing `#[weight = $x]` attribute. In this -//! snipped, `$x` can be any user provided struct that implements the following traits: -//! -//! - [`WeighData`]: the weight amount. -//! - [`ClassifyDispatch`]: class of the dispatch. -//! - [`PaysFee`]: whether this weight should be translated to fee and deducted upon dispatch. -//! -//! Substrate then bundles the output information of the three traits into [`DispatchInfo`] struct -//! and provides it by implementing the [`GetDispatchInfo`] for all `Call` both inner and outer call -//! types. -//! -//! Substrate provides two pre-defined ways to annotate weight: -//! -//! ### 1. Fixed values -//! -//! This can only be used when all 3 traits can be resolved statically. You have 3 degrees of -//! configuration: -//! -//! 1. Define only weight, **in which case `ClassifyDispatch` will be `Normal` and `PaysFee` will be -//! `Yes`**. -//! -//! ``` -//! # use frame_system::Config; -//! frame_support::decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = 1000] -//! fn dispatching(origin) { unimplemented!() } -//! } -//! } -//! # fn main() {} -//! ``` -//! -//! 2.1 Define weight and class, **in which case `PaysFee` would be `Yes`**. -//! -//! ``` -//! # use frame_system::Config; -//! # use frame_support::weights::DispatchClass; -//! frame_support::decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = (1000, DispatchClass::Operational)] -//! fn dispatching(origin) { unimplemented!() } -//! } -//! } -//! # fn main() {} -//! ``` -//! -//! 2.2 Define weight and `PaysFee`, **in which case `ClassifyDispatch` would be `Normal`**. -//! -//! ``` -//! # use frame_system::Config; -//! # use frame_support::weights::Pays; -//! frame_support::decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = (1000, Pays::No)] -//! fn dispatching(origin) { unimplemented!() } -//! } -//! } -//! # fn main() {} -//! ``` -//! -//! 3. Define all 3 parameters. -//! -//! ``` -//! # use frame_system::Config; -//! # use frame_support::weights::{DispatchClass, Pays}; -//! frame_support::decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = (1000, DispatchClass::Operational, Pays::No)] -//! fn dispatching(origin) { unimplemented!() } -//! } -//! } -//! # fn main() {} -//! ``` -//! -//! ### 2. Define weights as a function of input arguments. -//! -//! The arguments of the dispatch are available in the weight expressions as a borrowed value. -//! -//! ``` -//! # use frame_system::Config; -//! # use frame_support::weights::{DispatchClass, Pays}; -//! frame_support::decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = ( -//! *a as u64 + *b, -//! DispatchClass::Operational, -//! if *a > 1000 { Pays::Yes } else { Pays::No } -//! )] -//! fn dispatching(origin, a: u32, b: u64) { unimplemented!() } -//! } -//! } -//! # fn main() {} -//! ``` -//! FRAME assumes a weight of `1_000_000_000_000` equals 1 second of compute on a standard machine. +//! Re-exports `sp-weights` public API, and contains benchmarked weight constants specific to +//! FRAME. //! //! Latest machine specification used to benchmark are: //! - Digital Ocean: ubuntu-s-2vcpu-4gb-ams3-01 @@ -123,41 +29,14 @@ mod block_weights; mod extrinsic_weights; mod paritydb_weights; mod rocksdb_weights; -mod weight_v2; - -use crate::{ - dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo}, - traits::Get, -}; -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; -use smallvec::SmallVec; -use sp_arithmetic::{ - traits::{BaseArithmetic, Saturating, Unsigned}, - Perbill, -}; -use sp_runtime::{ - generic::{CheckedExtrinsic, UncheckedExtrinsic}, - traits::{SaturatedConversion, SignedExtension}, - RuntimeDebug, -}; - -/// Re-export priority as type -pub use sp_runtime::transaction_validity::TransactionPriority; -pub use weight_v2::*; +use crate::dispatch; +pub use sp_weights::*; /// These constants are specific to FRAME, and the current implementation of its various components. /// For example: FRAME System, FRAME Executive, our FRAME support libraries, etc... pub mod constants { - use super::Weight; - - pub const WEIGHT_PER_SECOND: Weight = Weight::from_ref_time(1_000_000_000_000); - pub const WEIGHT_PER_MILLIS: Weight = Weight::from_ref_time(1_000_000_000); - pub const WEIGHT_PER_MICROS: Weight = Weight::from_ref_time(1_000_000); - pub const WEIGHT_PER_NANOS: Weight = Weight::from_ref_time(1_000); + pub use sp_weights::constants::*; // Expose the Block and Extrinsic base weights. pub use super::{block_weights::BlockExecutionWeight, extrinsic_weights::ExtrinsicBaseWeight}; @@ -168,786 +47,69 @@ pub mod constants { }; } -/// Means of weighing some particular kind of data (`T`). -pub trait WeighData { - /// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be - /// a tuple of all arguments given to the function (except origin). - fn weigh_data(&self, target: T) -> Weight; -} - -/// Means of classifying a dispatchable function. -pub trait ClassifyDispatch { - /// Classify the dispatch function based on input data `target` of type `T`. When implementing - /// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except - /// origin). - fn classify_dispatch(&self, target: T) -> DispatchClass; -} - -/// Indicates if dispatch function should pay fees or not. -/// If set to `Pays::No`, the block resource limits are applied, yet no fee is deducted. -pub trait PaysFee { - fn pays_fee(&self, _target: T) -> Pays; -} - -/// Explicit enum to denote if a transaction pays fee or not. -#[derive(Clone, Copy, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)] -pub enum Pays { - /// Transactor will pay related fees. - Yes, - /// Transactor will NOT pay related fees. - No, -} - -impl Default for Pays { - fn default() -> Self { - Self::Yes - } -} - -impl From for PostDispatchInfo { - fn from(pays_fee: Pays) -> Self { - Self { actual_weight: None, pays_fee } - } -} - -/// A generalized group of dispatch types. -/// -/// NOTE whenever upgrading the enum make sure to also update -/// [DispatchClass::all] and [DispatchClass::non_mandatory] helper functions. -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum DispatchClass { - /// A normal dispatch. - Normal, - /// An operational dispatch. - Operational, - /// A mandatory dispatch. These kinds of dispatch are always included regardless of their - /// weight, therefore it is critical that they are separately validated to ensure that a - /// malicious validator cannot craft a valid but impossibly heavy block. Usually this just - /// means ensuring that the extrinsic can only be included once and that it is always very - /// light. - /// - /// Do *NOT* use it for extrinsics that can be heavy. - /// - /// The only real use case for this is inherent extrinsics that are required to execute in a - /// block for the block to be valid, and it solves the issue in the case that the block - /// initialization is sufficiently heavy to mean that those inherents do not fit into the - /// block. Essentially, we assume that in these exceptional circumstances, it is better to - /// allow an overweight block to be created than to not allow any block at all to be created. - Mandatory, -} - -impl Default for DispatchClass { - fn default() -> Self { - Self::Normal - } -} - -impl DispatchClass { - /// Returns an array containing all dispatch classes. - pub fn all() -> &'static [DispatchClass] { - &[DispatchClass::Normal, DispatchClass::Operational, DispatchClass::Mandatory] - } - - /// Returns an array of all dispatch classes except `Mandatory`. - pub fn non_mandatory() -> &'static [DispatchClass] { - &[DispatchClass::Normal, DispatchClass::Operational] - } -} - -/// A trait that represents one or many values of given type. -/// -/// Useful to accept as parameter type to let the caller pass either a single value directly -/// or an iterator. -pub trait OneOrMany { - /// The iterator type. - type Iter: Iterator; - /// Convert this item into an iterator. - fn into_iter(self) -> Self::Iter; -} - -impl OneOrMany for DispatchClass { - type Iter = sp_std::iter::Once; - fn into_iter(self) -> Self::Iter { - sp_std::iter::once(self) - } -} - -impl<'a> OneOrMany for &'a [DispatchClass] { - type Iter = sp_std::iter::Cloned>; - fn into_iter(self) -> Self::Iter { - self.iter().cloned() - } -} - -/// A bundle of static information collected from the `#[weight = $x]` attributes. -#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct DispatchInfo { - /// Weight of this transaction. - pub weight: Weight, - /// Class of this transaction. - pub class: DispatchClass, - /// Does this transaction pay fees. - pub pays_fee: Pays, -} - -/// A `Dispatchable` function (aka transaction) that can carry some static information along with -/// it, using the `#[weight]` attribute. -pub trait GetDispatchInfo { - /// Return a `DispatchInfo`, containing relevant information of this dispatch. - /// - /// This is done independently of its encoded size. - fn get_dispatch_info(&self) -> DispatchInfo; -} - -impl GetDispatchInfo for () { - fn get_dispatch_info(&self) -> DispatchInfo { - DispatchInfo::default() - } -} - -/// Weight information that is only available post dispatch. -/// NOTE: This can only be used to reduce the weight or fee, not increase it. -#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct PostDispatchInfo { - /// Actual weight consumed by a call or `None` which stands for the worst case static weight. - pub actual_weight: Option, - /// Whether this transaction should pay fees when all is said and done. - pub pays_fee: Pays, -} - -impl PostDispatchInfo { - /// Calculate how much (if any) weight was not used by the `Dispatchable`. - pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight { - info.weight - self.calc_actual_weight(info) - } - - /// Calculate how much weight was actually spent by the `Dispatchable`. - pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight { - if let Some(actual_weight) = self.actual_weight { - actual_weight.min(info.weight) - } else { - info.weight - } - } - - /// Determine if user should actually pay fees at the end of the dispatch. - pub fn pays_fee(&self, info: &DispatchInfo) -> Pays { - // If they originally were not paying fees, or the post dispatch info - // says they should not pay fees, then they don't pay fees. - // This is because the pre dispatch information must contain the - // worst case for weight and fees paid. - if info.pays_fee == Pays::No || self.pays_fee == Pays::No { - Pays::No - } else { - // Otherwise they pay. - Pays::Yes - } - } -} - -/// Extract the actual weight from a dispatch result if any or fall back to the default weight. -pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Weight { - match result { - Ok(post_info) => post_info, - Err(err) => &err.post_info, - } - .calc_actual_weight(info) -} - -/// Extract the actual pays_fee from a dispatch result if any or fall back to the default weight. -pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays { - match result { - Ok(post_info) => post_info, - Err(err) => &err.post_info, - } - .pays_fee(info) -} - -impl From<()> for PostDispatchInfo { - fn from(_: ()) -> Self { - Self { actual_weight: None, pays_fee: Default::default() } - } -} - -impl sp_runtime::traits::Printable for PostDispatchInfo { - fn print(&self) { - "actual_weight=".print(); - match self.actual_weight { - Some(weight) => weight.print(), - None => "max-weight".print(), - }; - "pays_fee=".print(); - match self.pays_fee { - Pays::Yes => "Yes".print(), - Pays::No => "No".print(), - } - } -} - -/// Allows easy conversion from `DispatchError` to `DispatchErrorWithPostInfo` for dispatchables -/// that want to return a custom a posterior weight on error. -pub trait WithPostDispatchInfo { - /// Call this on your modules custom errors type in order to return a custom weight on error. - /// - /// # Example - /// - /// ```ignore - /// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100)))?; - /// ensure!(who == me, Error::::NotMe.with_weight(200_000)); - /// ``` - fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo; -} - -impl WithPostDispatchInfo for T -where - T: Into, -{ - fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo { - DispatchErrorWithPostInfo { - post_info: PostDispatchInfo { - actual_weight: Some(actual_weight), - pays_fee: Default::default(), - }, - error: self.into(), - } - } -} - -/// Implementation for unchecked extrinsic. -impl GetDispatchInfo - for UncheckedExtrinsic -where - Call: GetDispatchInfo, - Extra: SignedExtension, -{ - fn get_dispatch_info(&self) -> DispatchInfo { - self.function.get_dispatch_info() - } -} - -/// Implementation for checked extrinsic. -impl GetDispatchInfo for CheckedExtrinsic -where - Call: GetDispatchInfo, -{ - fn get_dispatch_info(&self) -> DispatchInfo { - self.function.get_dispatch_info() - } -} - -/// Implementation for test extrinsic. -#[cfg(feature = "std")] -impl GetDispatchInfo for sp_runtime::testing::TestXt { - fn get_dispatch_info(&self) -> DispatchInfo { - // for testing: weight == size. - DispatchInfo { - weight: Weight::from_ref_time(self.encode().len() as _), - pays_fee: Pays::Yes, - ..Default::default() - } - } -} - -/// The weight of database operations that the runtime can invoke. -/// -/// NOTE: This is currently only measured in computational time, and will probably -/// be updated all together once proof size is accounted for. -#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct RuntimeDbWeight { - pub read: u64, - pub write: u64, -} - -impl RuntimeDbWeight { - pub fn reads(self, r: u64) -> Weight { - Weight::from_ref_time(self.read.saturating_mul(r)) - } - - pub fn writes(self, w: u64) -> Weight { - Weight::from_ref_time(self.write.saturating_mul(w)) - } - - pub fn reads_writes(self, r: u64, w: u64) -> Weight { - let read_weight = self.read.saturating_mul(r); - let write_weight = self.write.saturating_mul(w); - Weight::from_ref_time(read_weight.saturating_add(write_weight)) - } -} - -/// One coefficient and its position in the `WeightToFee`. -/// -/// One term of polynomial is calculated as: -/// -/// ```ignore -/// coeff_integer * x^(degree) + coeff_frac * x^(degree) -/// ``` -/// -/// The `negative` value encodes whether the term is added or substracted from the -/// overall polynomial result. -#[derive(Clone, Encode, Decode, TypeInfo)] -pub struct WeightToFeeCoefficient { - /// The integral part of the coefficient. - pub coeff_integer: Balance, - /// The fractional part of the coefficient. - pub coeff_frac: Perbill, - /// True iff the coefficient should be interpreted as negative. - pub negative: bool, - /// Degree/exponent of the term. - pub degree: u8, -} - -/// A list of coefficients that represent one polynomial. -pub type WeightToFeeCoefficients = SmallVec<[WeightToFeeCoefficient; 4]>; - -/// A trait that describes the weight to fee calculation. -pub trait WeightToFee { - /// The type that is returned as result from calculation. - type Balance: BaseArithmetic + From + Copy + Unsigned; - - /// Calculates the fee from the passed `weight`. - fn weight_to_fee(weight: &Weight) -> Self::Balance; -} - -/// A trait that describes the weight to fee calculation as polynomial. -/// -/// An implementor should only implement the `polynomial` function. -pub trait WeightToFeePolynomial { - /// The type that is returned as result from polynomial evaluation. - type Balance: BaseArithmetic + From + Copy + Unsigned; - - /// Returns a polynomial that describes the weight to fee conversion. - /// - /// This is the only function that should be manually implemented. Please note - /// that all calculation is done in the probably unsigned `Balance` type. This means - /// that the order of coefficients is important as putting the negative coefficients - /// first will most likely saturate the result to zero mid evaluation. - fn polynomial() -> WeightToFeeCoefficients; -} - -impl WeightToFee for T -where - T: WeightToFeePolynomial, -{ - type Balance = ::Balance; - - /// Calculates the fee from the passed `weight` according to the `polynomial`. - /// - /// This should not be overridden in most circumstances. Calculation is done in the - /// `Balance` type and never overflows. All evaluation is saturating. - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::polynomial() - .iter() - .fold(Self::Balance::saturated_from(0u32), |mut acc, args| { - let w = Self::Balance::saturated_from(weight.ref_time()) - .saturating_pow(args.degree.into()); - - // The sum could get negative. Therefore we only sum with the accumulator. - // The Perbill Mul implementation is non overflowing. - let frac = args.coeff_frac * w; - let integer = args.coeff_integer.saturating_mul(w); - - if args.negative { - acc = acc.saturating_sub(frac); - acc = acc.saturating_sub(integer); - } else { - acc = acc.saturating_add(frac); - acc = acc.saturating_add(integer); - } - - acc - }) - } -} - -/// Implementor of `WeightToFee` that maps one unit of weight to one unit of fee. -pub struct IdentityFee(sp_std::marker::PhantomData); - -impl WeightToFee for IdentityFee -where - T: BaseArithmetic + From + Copy + Unsigned, -{ - type Balance = T; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(weight.ref_time()) - } -} - -/// Implementor of [`WeightToFee`] that uses a constant multiplier. -/// # Example -/// -/// ``` -/// # use frame_support::traits::ConstU128; -/// # use frame_support::weights::ConstantMultiplier; -/// // Results in a multiplier of 10 for each unit of weight (or length) -/// type LengthToFee = ConstantMultiplier::>; -/// ``` -pub struct ConstantMultiplier(sp_std::marker::PhantomData<(T, M)>); - -impl WeightToFee for ConstantMultiplier -where - T: BaseArithmetic + From + Copy + Unsigned, - M: Get, -{ - type Balance = T; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(weight.ref_time()).saturating_mul(M::get()) - } -} - -/// A struct holding value for each `DispatchClass`. -#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct PerDispatchClass { - /// Value for `Normal` extrinsics. - normal: T, - /// Value for `Operational` extrinsics. - operational: T, - /// Value for `Mandatory` extrinsics. - mandatory: T, -} - -impl PerDispatchClass { - /// Create new `PerDispatchClass` with the same value for every class. - pub fn new(val: impl Fn(DispatchClass) -> T) -> Self { - Self { - normal: val(DispatchClass::Normal), - operational: val(DispatchClass::Operational), - mandatory: val(DispatchClass::Mandatory), - } - } - - /// Get a mutable reference to current value of given class. - pub fn get_mut(&mut self, class: DispatchClass) -> &mut T { - match class { - DispatchClass::Operational => &mut self.operational, - DispatchClass::Normal => &mut self.normal, - DispatchClass::Mandatory => &mut self.mandatory, - } - } - - /// Get current value for given class. - pub fn get(&self, class: DispatchClass) -> &T { - match class { - DispatchClass::Normal => &self.normal, - DispatchClass::Operational => &self.operational, - DispatchClass::Mandatory => &self.mandatory, - } - } -} - -impl PerDispatchClass { - /// Set the value of given class. - pub fn set(&mut self, new: T, class: impl OneOrMany) { - for class in class.into_iter() { - *self.get_mut(class) = new.clone(); - } - } -} - -impl PerDispatchClass { - /// Returns the total weight consumed by all extrinsics in the block. - pub fn total(&self) -> Weight { - let mut sum = Weight::zero(); - for class in DispatchClass::all() { - sum = sum.saturating_add(*self.get(*class)); - } - sum - } - - /// Add some weight of a specific dispatch class, saturating at the numeric bounds of `Weight`. - pub fn add(&mut self, weight: Weight, class: DispatchClass) { - let value = self.get_mut(class); - *value = value.saturating_add(weight); - } - - /// Try to add some weight of a specific dispatch class, returning Err(()) if overflow would - /// occur. - pub fn checked_add(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> { - let value = self.get_mut(class); - *value = value.checked_add(&weight).ok_or(())?; - Ok(()) - } - - /// Subtract some weight of a specific dispatch class, saturating at the numeric bounds of - /// `Weight`. - pub fn sub(&mut self, weight: Weight, class: DispatchClass) { - let value = self.get_mut(class); - *value = value.saturating_sub(weight); - } -} - -#[cfg(test)] -#[allow(dead_code)] -mod tests { - use super::*; - use crate::{decl_module, parameter_types, traits::Get}; - use smallvec::smallvec; - - pub trait Config: 'static { - type Origin; - type Balance; - type BlockNumber; - type DbWeight: Get; - type PalletInfo: crate::traits::PalletInfo; - } - - pub struct TraitImpl {} - - parameter_types! { - pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 100, - write: 1000, - }; - } - - impl Config for TraitImpl { - type Origin = u32; - type BlockNumber = u32; - type Balance = u32; - type DbWeight = DbWeight; - type PalletInfo = crate::tests::PanicPalletInfo; - } - - decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self { - // no arguments, fixed weight - #[weight = 1000] - fn f00(_origin) { unimplemented!(); } - - #[weight = (1000, DispatchClass::Mandatory)] - fn f01(_origin) { unimplemented!(); } - - #[weight = (1000, Pays::No)] - fn f02(_origin) { unimplemented!(); } - - #[weight = (1000, DispatchClass::Operational, Pays::No)] - fn f03(_origin) { unimplemented!(); } - - // weight = a x 10 + b - #[weight = ((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes)] - fn f11(_origin, _a: u32, _eb: u32) { unimplemented!(); } - - #[weight = (0, DispatchClass::Operational, Pays::Yes)] - fn f12(_origin, _a: u32, _eb: u32) { unimplemented!(); } - - #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_ref_time(10_000)] - fn f20(_origin) { unimplemented!(); } - - #[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_ref_time(40_000)] - fn f21(_origin) { unimplemented!(); } - - } - } - - #[test] - fn weights_are_correct() { - // #[weight = 1000] - let info = Call::::f00 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(1000)); - assert_eq!(info.class, DispatchClass::Normal); - assert_eq!(info.pays_fee, Pays::Yes); - - // #[weight = (1000, DispatchClass::Mandatory)] - let info = Call::::f01 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(1000)); - assert_eq!(info.class, DispatchClass::Mandatory); - assert_eq!(info.pays_fee, Pays::Yes); - - // #[weight = (1000, Pays::No)] - let info = Call::::f02 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(1000)); - assert_eq!(info.class, DispatchClass::Normal); - assert_eq!(info.pays_fee, Pays::No); - - // #[weight = (1000, DispatchClass::Operational, Pays::No)] - let info = Call::::f03 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(1000)); - assert_eq!(info.class, DispatchClass::Operational); - assert_eq!(info.pays_fee, Pays::No); - - // #[weight = ((_a * 10 + _eb * 1) as Weight, DispatchClass::Normal, Pays::Yes)] - let info = Call::::f11 { _a: 13, _eb: 20 }.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(150)); // 13*10 + 20 - assert_eq!(info.class, DispatchClass::Normal); - assert_eq!(info.pays_fee, Pays::Yes); - - // #[weight = (0, DispatchClass::Operational, Pays::Yes)] - let info = Call::::f12 { _a: 10, _eb: 20 }.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(0)); - assert_eq!(info.class, DispatchClass::Operational); - assert_eq!(info.pays_fee, Pays::Yes); - - // #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + 10_000] - let info = Call::::f20 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(12300)); // 100*3 + 1000*2 + 10_1000 - assert_eq!(info.class, DispatchClass::Normal); - assert_eq!(info.pays_fee, Pays::Yes); - - // #[weight = T::DbWeight::get().reads_writes(6, 5) + 40_000] - let info = Call::::f21 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(45600)); // 100*6 + 1000*5 + 40_1000 - assert_eq!(info.class, DispatchClass::Normal); - assert_eq!(info.pays_fee, Pays::Yes); - } - - #[test] - fn extract_actual_weight_works() { - let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; - assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), Weight::from_ref_time(7)); - assert_eq!( - extract_actual_weight(&Ok(Some(1000).into()), &pre), - Weight::from_ref_time(1000) - ); - assert_eq!( - extract_actual_weight( - &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), - &pre - ), - Weight::from_ref_time(9) - ); - } - - #[test] - fn extract_actual_weight_caps_at_pre_weight() { - let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; - assert_eq!( - extract_actual_weight(&Ok(Some(1250).into()), &pre), - Weight::from_ref_time(1000) - ); - assert_eq!( - extract_actual_weight( - &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(1300))), - &pre - ), - Weight::from_ref_time(1000), - ); - } - - #[test] - fn extract_actual_pays_fee_works() { - let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; - assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::Yes); - assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::Yes); - assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::Yes); - assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::No).into()), &pre), Pays::No); - assert_eq!( - extract_actual_pays_fee( - &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), - &pre - ), - Pays::Yes - ); - assert_eq!( - extract_actual_pays_fee( - &Err(DispatchErrorWithPostInfo { - post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::No }, - error: DispatchError::BadOrigin, - }), - &pre - ), - Pays::No - ); - - let pre = DispatchInfo { - weight: Weight::from_ref_time(1000), - pays_fee: Pays::No, - ..Default::default() - }; - assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::No); - assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::No); - assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::No); - } - - type Balance = u64; - - // 0.5x^3 + 2.333x^2 + 7x - 10_000 - struct Poly; - impl WeightToFeePolynomial for Poly { - type Balance = Balance; - - fn polynomial() -> WeightToFeeCoefficients { - smallvec![ - WeightToFeeCoefficient { - coeff_integer: 0, - coeff_frac: Perbill::from_float(0.5), - negative: false, - degree: 3 - }, - WeightToFeeCoefficient { - coeff_integer: 2, - coeff_frac: Perbill::from_rational(1u32, 3u32), - negative: false, - degree: 2 - }, - WeightToFeeCoefficient { - coeff_integer: 7, - coeff_frac: Perbill::zero(), - negative: false, - degree: 1 - }, - WeightToFeeCoefficient { - coeff_integer: 10_000, - coeff_frac: Perbill::zero(), - negative: true, - degree: 0 - }, - ] - } - } - - #[test] - fn polynomial_works() { - // 100^3/2=500000 100^2*(2+1/3)=23333 700 -10000 - assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(100)), 514033); - // 10123^3/2=518677865433 10123^2*(2+1/3)=239108634 70861 -10000 - assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10_123)), 518917034928); - } - - #[test] - fn polynomial_does_not_underflow() { - assert_eq!(Poly::weight_to_fee(&Weight::zero()), 0); - assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10)), 0); - } - - #[test] - fn polynomial_does_not_overflow() { - assert_eq!(Poly::weight_to_fee(&Weight::MAX), Balance::max_value() - 10_000); - } - - #[test] - fn identity_fee_works() { - assert_eq!(IdentityFee::::weight_to_fee(&Weight::zero()), 0); - assert_eq!(IdentityFee::::weight_to_fee(&Weight::from_ref_time(50)), 50); - assert_eq!(IdentityFee::::weight_to_fee(&Weight::MAX), Balance::max_value()); - } - - #[test] - fn constant_fee_works() { - use crate::traits::ConstU128; - assert_eq!( - ConstantMultiplier::>::weight_to_fee(&Weight::zero()), - 0 - ); - assert_eq!( - ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( - 50 - )), - 500 - ); - assert_eq!( - ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( - 16 - )), - 16384 - ); - assert_eq!( - ConstantMultiplier::>::weight_to_fee( - &Weight::from_ref_time(2) - ), - u128::MAX - ); +#[deprecated = "Function has moved to `frame_support::dispatch`"] +pub fn extract_actual_pays_fee( + res: &dispatch::DispatchResultWithPostInfo, + info: &dispatch::DispatchInfo, +) -> dispatch::Pays { + dispatch::extract_actual_pays_fee(res, info) +} +#[deprecated = "Function has moved to `frame_support::dispatch`"] +pub fn extract_actual_weight( + res: &dispatch::DispatchResultWithPostInfo, + info: &dispatch::DispatchInfo, +) -> Weight { + dispatch::extract_actual_weight(res, info) +} +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait ClassifyDispatch: dispatch::ClassifyDispatch { + fn classify_dispatch(&self, target: T) -> dispatch::DispatchClass { + >::classify_dispatch(self, target) + } +} +#[deprecated = "Enum has moved to `frame_support::dispatch`"] +pub type DispatchClass = dispatch::DispatchClass; +#[deprecated = "Struct has moved to `frame_support::dispatch`"] +pub type DispatchInfo = dispatch::DispatchInfo; +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait GetDispatchInfo: dispatch::GetDispatchInfo { + fn get_dispatch_info(&self) -> dispatch::DispatchInfo { + ::get_dispatch_info(self) + } +} +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait OneOrMany: dispatch::OneOrMany { + fn into_iter(self) -> Self::Iter + where + Self: Sized, + { + >::into_iter(self) + } +} +#[deprecated = "Enum has moved to `frame_support::dispatch`"] +pub type Pays = dispatch::Pays; +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait PaysFee: dispatch::PaysFee { + fn pays_fee(&self, target: T) -> dispatch::Pays { + >::pays_fee(self, target) + } +} +#[deprecated = "Struct has moved to `frame_support::dispatch`"] +pub type PerDispatchClass = dispatch::PerDispatchClass; +#[deprecated = "Struct has moved to `frame_support::dispatch`"] +pub type PostDispatchInfo = dispatch::PostDispatchInfo; +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait WeighData: dispatch::WeighData { + fn weigh_data(&self, target: T) -> Weight { + >::weigh_data(self, target) + } +} +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait WithPostDispatchInfo: dispatch::WithPostDispatchInfo { + fn with_weight(self, actual_weight: Weight) -> dispatch::DispatchErrorWithPostInfo + where + Self: Sized, + { + ::with_weight(self, actual_weight) } } diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index 57978f60a4ecb..240b80460aa09 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -34,10 +34,8 @@ // --warmup=10 // --repeat=100 -use frame_support::{ - parameter_types, - weights::{constants::WEIGHT_PER_NANOS, Weight}, -}; +use sp_core::parameter_types; +use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; parameter_types! { /// Time to execute an empty block. @@ -58,7 +56,7 @@ parameter_types! { #[cfg(test)] mod test_weights { - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that the weight exists and is sane. // NOTE: If this test fails but you are sure that the generated values are fine, diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 54f70a063cdec..913dbc4e91fc1 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -34,10 +34,8 @@ // --warmup=10 // --repeat=100 -use frame_support::{ - parameter_types, - weights::{constants::WEIGHT_PER_NANOS, Weight}, -}; +use sp_core::parameter_types; +use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; parameter_types! { /// Time to execute a NO-OP extrinsic, for example `System::remark`. @@ -58,7 +56,7 @@ parameter_types! { #[cfg(test)] mod test_weights { - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that the weight exists and is sane. // NOTE: If this test fails but you are sure that the generated values are fine, diff --git a/frame/support/src/weights/paritydb_weights.rs b/frame/support/src/weights/paritydb_weights.rs index 9f6ba82dbbff6..344e6cf0ddb6e 100644 --- a/frame/support/src/weights/paritydb_weights.rs +++ b/frame/support/src/weights/paritydb_weights.rs @@ -16,10 +16,9 @@ // limitations under the License. pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; + use frame_support::weights::constants; + use sp_core::parameter_types; + use sp_weights::RuntimeDbWeight; parameter_types! { /// ParityDB can be enabled with a feature flag, but is still experimental. These weights @@ -33,7 +32,7 @@ pub mod constants { #[cfg(test)] mod test_db_weights { use super::constants::ParityDbWeight as W; - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that all weights exist and have sane values. // NOTE: If this test fails but you are sure that the generated values are fine, diff --git a/frame/support/src/weights/rocksdb_weights.rs b/frame/support/src/weights/rocksdb_weights.rs index cab983de0ad0a..4dec2d8c877ea 100644 --- a/frame/support/src/weights/rocksdb_weights.rs +++ b/frame/support/src/weights/rocksdb_weights.rs @@ -16,10 +16,9 @@ // limitations under the License. pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; + use frame_support::weights::constants; + use sp_core::parameter_types; + use sp_weights::RuntimeDbWeight; parameter_types! { /// By default, Substrate uses RocksDB, so this will be the weight used throughout @@ -33,7 +32,7 @@ pub mod constants { #[cfg(test)] mod test_db_weights { use super::constants::RocksDbWeight as W; - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that all weights exist and have sane values. // NOTE: If this test fails but you are sure that the generated values are fine, diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 4f3c783252e00..4306314b4c005 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -200,7 +200,7 @@ pub mod module3 { } #[weight = 3] fn aux_4(_origin) -> frame_support::dispatch::DispatchResult { unreachable!() } - #[weight = (5, frame_support::weights::DispatchClass::Operational)] + #[weight = (5, frame_support::dispatch::DispatchClass::Operational)] fn operational(_origin) { unreachable!() } } } @@ -504,8 +504,8 @@ fn call_encode_is_correct_and_decode_works() { #[test] fn call_weight_should_attach_to_call_enum() { use frame_support::{ - dispatch::{DispatchInfo, GetDispatchInfo}, - weights::{DispatchClass, Pays, Weight}, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, + weights::Weight, }; // operational. assert_eq!( diff --git a/frame/support/test/tests/origin.rs b/frame/support/test/tests/origin.rs index 53124059e6353..620f64ec3cfc2 100644 --- a/frame/support/test/tests/origin.rs +++ b/frame/support/test/tests/origin.rs @@ -100,7 +100,7 @@ pub mod module { } #[weight = 3] fn aux_4(_origin) -> frame_support::dispatch::DispatchResult { unreachable!() } - #[weight = (5, frame_support::weights::DispatchClass::Operational)] + #[weight = (5, frame_support::dispatch::DispatchClass::Operational)] fn operational(_origin) { unreachable!() } } } diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 420617a9e4f24..4304aa1533a8b 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -16,14 +16,16 @@ // limitations under the License. use frame_support::{ - dispatch::{Parameter, UnfilteredDispatchable}, + dispatch::{ + DispatchClass, DispatchInfo, GetDispatchInfo, Parameter, Pays, UnfilteredDispatchable, + }, pallet_prelude::ValueQuery, storage::unhashed, traits::{ ConstU32, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade, PalletError, PalletInfoAccess, StorageVersion, }, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, RuntimeDbWeight, Weight}, + weights::{RuntimeDbWeight, Weight}, }; use scale_info::{meta_type, TypeInfo}; use sp_io::{ diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index f01ce17d71bf9..3bbbc559ff9b8 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -16,11 +16,10 @@ // limitations under the License. use frame_support::{ - dispatch::UnfilteredDispatchable, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, UnfilteredDispatchable}, pallet_prelude::ValueQuery, storage::unhashed, traits::{ConstU32, GetCallName, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade}, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, }; use sp_io::{ hashing::{blake2_128, twox_128, twox_64}, diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 3429c6546c7fd..dd3a5d606bad5 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -23,6 +23,7 @@ sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-version = { version = "5.0.0", default-features = false, path = "../../primitives/version" } +sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } [dev-dependencies] criterion = "0.3.3" @@ -42,6 +43,7 @@ std = [ "sp-runtime/std", "sp-std/std", "sp-version/std", + "sp-weights/std", ] runtime-benchmarks = [ "frame-support/runtime-benchmarks", diff --git a/frame/system/benchmarking/src/lib.rs b/frame/system/benchmarking/src/lib.rs index 367e6c73c4134..dbe38da5775a7 100644 --- a/frame/system/benchmarking/src/lib.rs +++ b/frame/system/benchmarking/src/lib.rs @@ -21,7 +21,7 @@ use codec::Encode; use frame_benchmarking::{benchmarks, whitelisted_caller}; -use frame_support::{storage, traits::Get, weights::DispatchClass}; +use frame_support::{dispatch::DispatchClass, storage, traits::Get}; use frame_system::{Call, Pallet as System, RawOrigin}; use sp_core::storage::well_known_keys; use sp_runtime::traits::Hash; diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index f515f1ae0fa27..635ab4ef1d9a9 100644 --- a/frame/system/src/extensions/check_mortality.rs +++ b/frame/system/src/extensions/check_mortality.rs @@ -101,7 +101,10 @@ impl SignedExtension for CheckMortality { mod tests { use super::*; use crate::mock::{new_test_ext, System, Test, CALL}; - use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight}; + use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, Pays}, + weights::Weight, + }; use sp_core::H256; #[test] diff --git a/frame/system/src/extensions/check_non_zero_sender.rs b/frame/system/src/extensions/check_non_zero_sender.rs index 093424999aab3..036f70c2fdd48 100644 --- a/frame/system/src/extensions/check_non_zero_sender.rs +++ b/frame/system/src/extensions/check_non_zero_sender.rs @@ -17,7 +17,7 @@ use crate::Config; use codec::{Decode, Encode}; -use frame_support::weights::DispatchInfo; +use frame_support::dispatch::DispatchInfo; use scale_info::TypeInfo; use sp_runtime::{ traits::{DispatchInfoOf, Dispatchable, SignedExtension}, diff --git a/frame/system/src/extensions/check_nonce.rs b/frame/system/src/extensions/check_nonce.rs index 7259b80013ae5..1616a2d8a119e 100644 --- a/frame/system/src/extensions/check_nonce.rs +++ b/frame/system/src/extensions/check_nonce.rs @@ -17,7 +17,7 @@ use crate::Config; use codec::{Decode, Encode}; -use frame_support::weights::DispatchInfo; +use frame_support::dispatch::DispatchInfo; use scale_info::TypeInfo; use sp_runtime::{ traits::{DispatchInfoOf, Dispatchable, One, SignedExtension}, diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index 9af79e480b394..466231b8455ec 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -18,8 +18,8 @@ use crate::{limits::BlockWeights, Config, Pallet}; use codec::{Decode, Encode}; use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, traits::Get, - weights::{DispatchClass, DispatchInfo, PostDispatchInfo, Weight}, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -27,6 +27,7 @@ use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidity, TransactionValidityError}, DispatchResult, }; +use sp_weights::Weight; /// Block resource (weight) limit check. /// @@ -269,10 +270,7 @@ mod tests { mock::{new_test_ext, System, Test, CALL}, AllExtrinsicsLen, BlockWeight, }; - use frame_support::{ - assert_err, assert_ok, - weights::{Pays, Weight}, - }; + use frame_support::{assert_err, assert_ok, dispatch::Pays, weights::Weight}; use sp_std::marker::PhantomData; fn block_weights() -> crate::limits::BlockWeights { diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 550e3939f995a..739dcadde9ac1 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -84,20 +84,20 @@ use sp_version::RuntimeVersion; use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; use frame_support::{ - dispatch::{DispatchResult, DispatchResultWithPostInfo}, + dispatch::{ + extract_actual_pays_fee, extract_actual_weight, DispatchClass, DispatchInfo, + DispatchResult, DispatchResultWithPostInfo, PerDispatchClass, + }, storage, traits::{ ConstU32, Contains, EnsureOrigin, Get, HandleLifetime, OnKilledAccount, OnNewAccount, OriginTrait, PalletInfo, SortedMembers, StoredMap, TypedGet, }, - weights::{ - extract_actual_pays_fee, extract_actual_weight, DispatchClass, DispatchInfo, - PerDispatchClass, RuntimeDbWeight, Weight, - }, Parameter, }; use scale_info::TypeInfo; use sp_core::storage::well_known_keys; +use sp_weights::{RuntimeDbWeight, Weight}; #[cfg(feature = "std")] use frame_support::traits::GenesisBuild; diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index ba73d29806bba..e182eb626424d 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -25,7 +25,10 @@ //! `DispatchClass`. This module contains configuration object for both resources, //! which should be passed to `frame_system` configuration when runtime is being set up. -use frame_support::weights::{constants, DispatchClass, OneOrMany, PerDispatchClass, Weight}; +use frame_support::{ + dispatch::{DispatchClass, OneOrMany, PerDispatchClass}, + weights::{constants, Weight}, +}; use scale_info::TypeInfo; use sp_runtime::{traits::Bounded, Perbill, RuntimeDebug}; diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index 641cda13b07a4..b6fdda8d9cbe2 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -18,8 +18,7 @@ use crate::*; use frame_support::{ assert_noop, assert_ok, - dispatch::PostDispatchInfo, - weights::{Pays, WithPostDispatchInfo}, + dispatch::{Pays, PostDispatchInfo, WithPostDispatchInfo}, }; use mock::{Origin, *}; use sp_core::H256; diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index c14c7ba11b546..e136da8b0bb75 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -39,7 +39,7 @@ use sp_std::prelude::*; use codec::{Decode, Encode}; use frame_support::{ - dispatch::DispatchResult, + dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo}, traits::{ tokens::{ fungibles::{Balanced, CreditOf, Inspect}, @@ -47,7 +47,6 @@ use frame_support::{ }, IsType, }, - weights::{DispatchInfo, PostDispatchInfo}, DefaultNoBound, }; use pallet_transaction_payment::OnChargeTransaction; diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index dfce28fda43d2..1f6113aabdddd 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -18,10 +18,11 @@ use crate as pallet_asset_tx_payment; use frame_support::{ assert_ok, + dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, pallet_prelude::*, parameter_types, traits::{fungibles::Mutate, ConstU32, ConstU64, ConstU8, FindAuthor}, - weights::{DispatchClass, DispatchInfo, PostDispatchInfo, Weight, WeightToFee as WeightToFeeT}, + weights::{Weight, WeightToFee as WeightToFeeT}, ConsensusEngineId, }; use frame_system as system; diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 5f1f8321456be..0447ea6bfd99d 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -63,11 +63,11 @@ use sp_runtime::{ use sp_std::prelude::*; use frame_support::{ - dispatch::DispatchResult, - traits::{EstimateCallFee, Get}, - weights::{ - DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight, WeightToFee, + dispatch::{ + DispatchClass, DispatchInfo, DispatchResult, GetDispatchInfo, Pays, PostDispatchInfo, }, + traits::{EstimateCallFee, Get}, + weights::{Weight, WeightToFee}, }; mod payment; @@ -849,12 +849,11 @@ mod tests { }; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, + parameter_types, traits::{ConstU32, ConstU64, Currency, GenesisBuild, Imbalance, OnUnbalanced}, - weights::{ - DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo, Weight, - WeightToFee as WeightToFeeT, - }, + weights::{Weight, WeightToFee as WeightToFeeT}, }; use frame_system as system; use pallet_balances::Call as BalancesCall; diff --git a/frame/transaction-payment/src/types.rs b/frame/transaction-payment/src/types.rs index 5e915d62a26d4..1f41ba7b0b72e 100644 --- a/frame/transaction-payment/src/types.rs +++ b/frame/transaction-payment/src/types.rs @@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize}; use sp_runtime::traits::{AtLeast32BitUnsigned, Zero}; use sp_std::prelude::*; -use frame_support::weights::{DispatchClass, Weight}; +use frame_support::{dispatch::DispatchClass, weights::Weight}; /// The base fee and adjusted weight and length fees constitute the _inclusion fee_. #[derive(Encode, Decode, Clone, Eq, PartialEq)] diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index b5bd686b59f00..08fb34ed9e3c1 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -58,9 +58,8 @@ pub mod weights; use codec::{Decode, Encode}; use frame_support::{ - dispatch::PostDispatchInfo, + dispatch::{extract_actual_weight, GetDispatchInfo, PostDispatchInfo}, traits::{IsSubType, OriginTrait, UnfilteredDispatchable}, - weights::{extract_actual_weight, GetDispatchInfo}, }; use sp_core::TypeId; use sp_io::hashing::blake2_256; diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 1985cc3022114..93b80672f55e2 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -24,10 +24,10 @@ use super::*; use crate as utility; use frame_support::{ assert_err_ignore_postinfo, assert_noop, assert_ok, - dispatch::{DispatchError, DispatchErrorWithPostInfo, Dispatchable}, + dispatch::{DispatchError, DispatchErrorWithPostInfo, Dispatchable, Pays}, parameter_types, storage, traits::{ConstU32, ConstU64, Contains}, - weights::{Pays, Weight}, + weights::Weight, }; use sp_core::H256; use sp_runtime::{ diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index 19e53f2491614..c5621a239f3a6 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -42,9 +42,10 @@ pub use weights::WeightInfo; use codec::{DecodeLimit, Encode, FullCodec}; use frame_support::{ + dispatch::{GetDispatchInfo, PostDispatchInfo}, ensure, traits::{PreimageProvider, PreimageRecipient}, - weights::{GetDispatchInfo, PostDispatchInfo, Weight}, + weights::Weight, }; use scale_info::TypeInfo; use sp_runtime::traits::{Dispatchable, Hash}; diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 9e4b36c584e91..030c44c284593 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -29,6 +29,7 @@ sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithm sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-weights = { version = "4.0.0", default-features = false, path = "../weights" } [dev-dependencies] rand = "0.7.2" diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 2cf98b4e638d3..495dfa66c5462 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1820,6 +1820,12 @@ impl Printable for bool { } } +impl Printable for sp_weights::Weight { + fn print(&self) { + self.ref_time().print() + } +} + impl Printable for () { fn print(&self) { "()".print() diff --git a/primitives/weights/Cargo.toml b/primitives/weights/Cargo.toml new file mode 100644 index 0000000000000..8c0302ff5d1b2 --- /dev/null +++ b/primitives/weights/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "sp-weights" +version = "4.0.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Types and traits for interfacing between the host and the wasm runtime." +documentation = "https://docs.rs/sp-wasm-interface" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +impl-trait-for-tuples = "0.2.2" +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } +smallvec = "1.8.0" +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } + +[features] +default = [ "std" ] +std = [ + "codec/std", + "scale-info/std", + "serde", + "sp-arithmetic/std", + "sp-core/std", + "sp-debug-derive/std", + "sp-std/std" +] +# By default some types have documentation, `full-metadata-docs` allows to add documentation to +# more types in the metadata. +full-metadata-docs = ["scale-info/docs"] diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs new file mode 100644 index 0000000000000..d260f73d41268 --- /dev/null +++ b/primitives/weights/src/lib.rs @@ -0,0 +1,299 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Primitives for transaction weighting. +//! +//! Latest machine specification used to benchmark are: +//! - Digital Ocean: ubuntu-s-2vcpu-4gb-ams3-01 +//! - 2x Intel(R) Xeon(R) CPU E5-2650 v4 @ 2.20GHz +//! - 4GB RAM +//! - Ubuntu 19.10 (GNU/Linux 5.3.0-18-generic x86_64) +//! - rustc 1.42.0 (b8cedc004 2020-03-09) + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate self as sp_weights; + +mod weight_v2; + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use smallvec::SmallVec; +use sp_arithmetic::{ + traits::{BaseArithmetic, SaturatedConversion, Saturating, Unsigned}, + Perbill, +}; +use sp_core::Get; +use sp_debug_derive::RuntimeDebug; + +pub use weight_v2::*; + +pub mod constants { + use super::Weight; + + pub const WEIGHT_PER_SECOND: Weight = Weight::from_ref_time(1_000_000_000_000); + pub const WEIGHT_PER_MILLIS: Weight = Weight::from_ref_time(1_000_000_000); + pub const WEIGHT_PER_MICROS: Weight = Weight::from_ref_time(1_000_000); + pub const WEIGHT_PER_NANOS: Weight = Weight::from_ref_time(1_000); +} + +/// The weight of database operations that the runtime can invoke. +/// +/// NOTE: This is currently only measured in computational time, and will probably +/// be updated all together once proof size is accounted for. +#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] +pub struct RuntimeDbWeight { + pub read: u64, + pub write: u64, +} + +impl RuntimeDbWeight { + pub fn reads(self, r: u64) -> Weight { + Weight::from_ref_time(self.read.saturating_mul(r)) + } + + pub fn writes(self, w: u64) -> Weight { + Weight::from_ref_time(self.write.saturating_mul(w)) + } + + pub fn reads_writes(self, r: u64, w: u64) -> Weight { + let read_weight = self.read.saturating_mul(r); + let write_weight = self.write.saturating_mul(w); + Weight::from_ref_time(read_weight.saturating_add(write_weight)) + } +} + +/// One coefficient and its position in the `WeightToFee`. +/// +/// One term of polynomial is calculated as: +/// +/// ```ignore +/// coeff_integer * x^(degree) + coeff_frac * x^(degree) +/// ``` +/// +/// The `negative` value encodes whether the term is added or substracted from the +/// overall polynomial result. +#[derive(Clone, Encode, Decode, TypeInfo)] +pub struct WeightToFeeCoefficient { + /// The integral part of the coefficient. + pub coeff_integer: Balance, + /// The fractional part of the coefficient. + pub coeff_frac: Perbill, + /// True iff the coefficient should be interpreted as negative. + pub negative: bool, + /// Degree/exponent of the term. + pub degree: u8, +} + +/// A list of coefficients that represent one polynomial. +pub type WeightToFeeCoefficients = SmallVec<[WeightToFeeCoefficient; 4]>; + +/// A trait that describes the weight to fee calculation. +pub trait WeightToFee { + /// The type that is returned as result from calculation. + type Balance: BaseArithmetic + From + Copy + Unsigned; + + /// Calculates the fee from the passed `weight`. + fn weight_to_fee(weight: &Weight) -> Self::Balance; +} + +/// A trait that describes the weight to fee calculation as polynomial. +/// +/// An implementor should only implement the `polynomial` function. +pub trait WeightToFeePolynomial { + /// The type that is returned as result from polynomial evaluation. + type Balance: BaseArithmetic + From + Copy + Unsigned; + + /// Returns a polynomial that describes the weight to fee conversion. + /// + /// This is the only function that should be manually implemented. Please note + /// that all calculation is done in the probably unsigned `Balance` type. This means + /// that the order of coefficients is important as putting the negative coefficients + /// first will most likely saturate the result to zero mid evaluation. + fn polynomial() -> WeightToFeeCoefficients; +} + +impl WeightToFee for T +where + T: WeightToFeePolynomial, +{ + type Balance = ::Balance; + + /// Calculates the fee from the passed `weight` according to the `polynomial`. + /// + /// This should not be overridden in most circumstances. Calculation is done in the + /// `Balance` type and never overflows. All evaluation is saturating. + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::polynomial() + .iter() + .fold(Self::Balance::saturated_from(0u32), |mut acc, args| { + let w = Self::Balance::saturated_from(weight.ref_time()) + .saturating_pow(args.degree.into()); + + // The sum could get negative. Therefore we only sum with the accumulator. + // The Perbill Mul implementation is non overflowing. + let frac = args.coeff_frac * w; + let integer = args.coeff_integer.saturating_mul(w); + + if args.negative { + acc = acc.saturating_sub(frac); + acc = acc.saturating_sub(integer); + } else { + acc = acc.saturating_add(frac); + acc = acc.saturating_add(integer); + } + + acc + }) + } +} + +/// Implementor of `WeightToFee` that maps one unit of weight to one unit of fee. +pub struct IdentityFee(sp_std::marker::PhantomData); + +impl WeightToFee for IdentityFee +where + T: BaseArithmetic + From + Copy + Unsigned, +{ + type Balance = T; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(weight.ref_time()) + } +} + +/// Implementor of [`WeightToFee`] that uses a constant multiplier. +/// # Example +/// +/// ``` +/// # use sp_core::ConstU128; +/// # use sp_weights::ConstantMultiplier; +/// // Results in a multiplier of 10 for each unit of weight (or length) +/// type LengthToFee = ConstantMultiplier::>; +/// ``` +pub struct ConstantMultiplier(sp_std::marker::PhantomData<(T, M)>); + +impl WeightToFee for ConstantMultiplier +where + T: BaseArithmetic + From + Copy + Unsigned, + M: Get, +{ + type Balance = T; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(weight.ref_time()).saturating_mul(M::get()) + } +} + +#[cfg(test)] +#[allow(dead_code)] +mod tests { + use super::*; + use smallvec::smallvec; + + type Balance = u64; + + // 0.5x^3 + 2.333x^2 + 7x - 10_000 + struct Poly; + impl WeightToFeePolynomial for Poly { + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![ + WeightToFeeCoefficient { + coeff_integer: 0, + coeff_frac: Perbill::from_float(0.5), + negative: false, + degree: 3 + }, + WeightToFeeCoefficient { + coeff_integer: 2, + coeff_frac: Perbill::from_rational(1u32, 3u32), + negative: false, + degree: 2 + }, + WeightToFeeCoefficient { + coeff_integer: 7, + coeff_frac: Perbill::zero(), + negative: false, + degree: 1 + }, + WeightToFeeCoefficient { + coeff_integer: 10_000, + coeff_frac: Perbill::zero(), + negative: true, + degree: 0 + }, + ] + } + } + + #[test] + fn polynomial_works() { + // 100^3/2=500000 100^2*(2+1/3)=23333 700 -10000 + assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(100)), 514033); + // 10123^3/2=518677865433 10123^2*(2+1/3)=239108634 70861 -10000 + assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10_123)), 518917034928); + } + + #[test] + fn polynomial_does_not_underflow() { + assert_eq!(Poly::weight_to_fee(&Weight::zero()), 0); + assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10)), 0); + } + + #[test] + fn polynomial_does_not_overflow() { + assert_eq!(Poly::weight_to_fee(&Weight::MAX), Balance::max_value() - 10_000); + } + + #[test] + fn identity_fee_works() { + assert_eq!(IdentityFee::::weight_to_fee(&Weight::zero()), 0); + assert_eq!(IdentityFee::::weight_to_fee(&Weight::from_ref_time(50)), 50); + assert_eq!(IdentityFee::::weight_to_fee(&Weight::MAX), Balance::max_value()); + } + + #[test] + fn constant_fee_works() { + use sp_core::ConstU128; + assert_eq!( + ConstantMultiplier::>::weight_to_fee(&Weight::zero()), + 0 + ); + assert_eq!( + ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( + 50 + )), + 500 + ); + assert_eq!( + ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( + 16 + )), + 16384 + ); + assert_eq!( + ConstantMultiplier::>::weight_to_fee( + &Weight::from_ref_time(2) + ), + u128::MAX + ); + } +} diff --git a/frame/support/src/weights/weight_v2.rs b/primitives/weights/src/weight_v2.rs similarity index 68% rename from frame/support/src/weights/weight_v2.rs rename to primitives/weights/src/weight_v2.rs index 2d50f07add596..a4e4da4f8a7b3 100644 --- a/frame/support/src/weights/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -17,10 +17,8 @@ use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign}; -use sp_runtime::{ - traits::{Bounded, CheckedAdd, CheckedSub, Zero}, - RuntimeDebug, -}; +use sp_arithmetic::traits::{Bounded, CheckedAdd, CheckedSub, Zero}; +use sp_debug_derive::RuntimeDebug; use super::*; @@ -266,11 +264,11 @@ macro_rules! weight_mul_per_impl { } } weight_mul_per_impl!( - sp_runtime::Percent, - sp_runtime::PerU16, - sp_runtime::Permill, - sp_runtime::Perbill, - sp_runtime::Perquintill, + sp_arithmetic::Percent, + sp_arithmetic::PerU16, + sp_arithmetic::Permill, + sp_arithmetic::Perbill, + sp_arithmetic::Perquintill, ); macro_rules! weight_mul_primitive_impl { @@ -310,91 +308,6 @@ impl CheckedSub for Weight { } } -impl PaysFee for (Weight, DispatchClass, Pays) { - fn pays_fee(&self, _: T) -> Pays { - self.2 - } -} - -impl WeighData for (Weight, DispatchClass) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl WeighData for (Weight, DispatchClass, Pays) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl ClassifyDispatch for (Weight, DispatchClass) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - self.1 - } -} - -impl PaysFee for (Weight, DispatchClass) { - fn pays_fee(&self, _: T) -> Pays { - Pays::Yes - } -} - -impl WeighData for (Weight, Pays) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl ClassifyDispatch for (Weight, Pays) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - DispatchClass::Normal - } -} - -impl PaysFee for (Weight, Pays) { - fn pays_fee(&self, _: T) -> Pays { - self.1 - } -} - -impl From<(Option, Pays)> for PostDispatchInfo { - fn from(post_weight_info: (Option, Pays)) -> Self { - let (actual_weight, pays_fee) = post_weight_info; - Self { actual_weight, pays_fee } - } -} - -impl From> for PostDispatchInfo { - fn from(actual_weight: Option) -> Self { - Self { actual_weight, pays_fee: Default::default() } - } -} - -impl WeighData for Weight { - fn weigh_data(&self, _: T) -> Weight { - return *self - } -} - -impl ClassifyDispatch for Weight { - fn classify_dispatch(&self, _: T) -> DispatchClass { - DispatchClass::Normal - } -} - -impl PaysFee for Weight { - fn pays_fee(&self, _: T) -> Pays { - Pays::Yes - } -} - -impl ClassifyDispatch for (Weight, DispatchClass, Pays) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - self.1 - } -} - impl core::fmt::Display for Weight { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Weight(ref_time: {})", self.ref_time) @@ -421,106 +334,3 @@ impl SubAssign for Weight { *self = Self { ref_time: self.ref_time - other.ref_time }; } } - -impl sp_runtime::traits::Printable for Weight { - fn print(&self) { - self.ref_time().print() - } -} - -// TODO: Eventually remove these - -impl From> for PostDispatchInfo { - fn from(maybe_actual_computation: Option) -> Self { - let actual_weight = match maybe_actual_computation { - Some(actual_computation) => Some(Weight::zero().set_ref_time(actual_computation)), - None => None, - }; - Self { actual_weight, pays_fee: Default::default() } - } -} - -impl From<(Option, Pays)> for PostDispatchInfo { - fn from(post_weight_info: (Option, Pays)) -> Self { - let (maybe_actual_time, pays_fee) = post_weight_info; - let actual_weight = match maybe_actual_time { - Some(actual_time) => Some(Weight::zero().set_ref_time(actual_time)), - None => None, - }; - Self { actual_weight, pays_fee } - } -} - -impl WeighData for u64 { - fn weigh_data(&self, _: T) -> Weight { - return Weight::zero().set_ref_time(*self) - } -} - -impl ClassifyDispatch for u64 { - fn classify_dispatch(&self, _: T) -> DispatchClass { - DispatchClass::Normal - } -} - -impl PaysFee for u64 { - fn pays_fee(&self, _: T) -> Pays { - Pays::Yes - } -} - -impl WeighData for (u64, DispatchClass, Pays) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl ClassifyDispatch for (u64, DispatchClass, Pays) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - self.1 - } -} - -impl PaysFee for (u64, DispatchClass, Pays) { - fn pays_fee(&self, _: T) -> Pays { - self.2 - } -} - -impl WeighData for (u64, DispatchClass) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl ClassifyDispatch for (u64, DispatchClass) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - self.1 - } -} - -impl PaysFee for (u64, DispatchClass) { - fn pays_fee(&self, _: T) -> Pays { - Pays::Yes - } -} - -impl WeighData for (u64, Pays) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl ClassifyDispatch for (u64, Pays) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - DispatchClass::Normal - } -} - -impl PaysFee for (u64, Pays) { - fn pays_fee(&self, _: T) -> Pays { - self.1 - } -} - -// END TODO diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index 0a4100953401f..86b2c0b0e0cdb 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -13,10 +13,8 @@ // {{arg}} {{/each}} -use frame_support::{ - parameter_types, - weights::{constants::WEIGHT_PER_NANOS, Weight}, -}; +use sp_core::parameter_types; +use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; parameter_types! { {{#if (eq short_name "block")}} @@ -42,7 +40,7 @@ parameter_types! { #[cfg(test)] mod test_weights { use super::*; - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that the weight exists and is sane. // NOTE: If this test fails but you are sure that the generated values are fine, diff --git a/utils/frame/benchmarking-cli/src/storage/weights.hbs b/utils/frame/benchmarking-cli/src/storage/weights.hbs index 95f42c411d1fd..82e581cf990c8 100644 --- a/utils/frame/benchmarking-cli/src/storage/weights.hbs +++ b/utils/frame/benchmarking-cli/src/storage/weights.hbs @@ -17,10 +17,9 @@ /// Storage DB weights for the `{{runtime_name}}` runtime and `{{db_name}}`. pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; + use frame_support::weights::constants; + use sp_core::parameter_types; + use sp_weights::RuntimeDbWeight; parameter_types! { {{#if (eq db_name "ParityDb")}} @@ -66,7 +65,7 @@ pub mod constants { #[cfg(test)] mod test_db_weights { use super::constants::{{db_name}}Weight as W; - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that all weights exist and have sane values. // NOTE: If this test fails but you are sure that the generated values are fine, From b5e25424f369fe9481e1fa68e4278e694238755a Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 14 Sep 2022 11:43:19 -0400 Subject: [PATCH 1159/1472] fix sp-weight std (#12265) --- primitives/runtime/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 030c44c284593..278962bcf57c4 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -58,4 +58,5 @@ std = [ "sp-core/std", "sp-io/std", "sp-std/std", + "sp-weights/std", ] From 7c2c0c10ec2ad5788894cef001fc724d1b8a6127 Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 15 Sep 2022 01:01:13 +0900 Subject: [PATCH 1160/1472] Improve base weights consistency and make sure they're never zero (#11806) * Improve base weights consistency and make sure they're never zero * Switch back to `linregress` crate; add back estimation errors * Move the test into `mod tests` * Use all of the samples instead of only the first one * Use full precision extrinsic base weights and slopes * Add an extra comment * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts Co-authored-by: parity-processbot <> Co-authored-by: Shawn Tabrizi --- frame/benchmarking/src/analysis.rs | 258 ++++++++++++++---- frame/benchmarking/src/lib.rs | 2 +- .../benchmarking-cli/src/pallet/writer.rs | 31 +-- 3 files changed, 219 insertions(+), 72 deletions(-) diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index c19af781234f8..9ba2ea657bab0 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -18,17 +18,15 @@ //! Tools for analyzing the benchmark results. use crate::BenchmarkResult; -use linregress::{FormulaRegressionBuilder, RegressionDataBuilder}; use std::collections::BTreeMap; -pub use linregress::RegressionModel; - pub struct Analysis { pub base: u128, pub slopes: Vec, pub names: Vec, pub value_dists: Option, u128, u128)>>, - pub model: Option, + pub errors: Option>, + selector: BenchmarkSelector, } #[derive(Clone, Copy)] @@ -40,6 +38,44 @@ pub enum BenchmarkSelector { ProofSize, } +/// Multiplies the value by 1000 and converts it into an u128. +fn mul_1000_into_u128(value: f64) -> u128 { + // This is slighly more precise than the alternative of `(value * 1000.0) as u128`. + (value as u128) + .saturating_mul(1000) + .saturating_add((value.fract() * 1000.0) as u128) +} + +impl BenchmarkSelector { + fn scale_and_cast_weight(self, value: f64, round_up: bool) -> u128 { + if let BenchmarkSelector::ExtrinsicTime = self { + mul_1000_into_u128(value) + } else { + if round_up { + (value + 0.5) as u128 + } else { + value as u128 + } + } + } + + fn scale_weight(self, value: u128) -> u128 { + if let BenchmarkSelector::ExtrinsicTime = self { + value.saturating_mul(1000) + } else { + value + } + } + + fn nanos_from_weight(self, value: u128) -> u128 { + if let BenchmarkSelector::ExtrinsicTime = self { + value / 1000 + } else { + value + } + } +} + #[derive(Debug)] pub enum AnalysisChoice { /// Use minimum squares regression for analyzing the benchmarking results. @@ -72,6 +108,60 @@ impl TryFrom> for AnalysisChoice { } } +fn raw_linear_regression( + xs: Vec, + ys: Vec, + x_vars: usize, + with_intercept: bool, +) -> Option<(f64, Vec, Vec)> { + let mut data: Vec = Vec::new(); + + // Here we build a raw matrix of linear equations for the `linregress` crate to solve for us + // and build a linear regression model around it. + // + // Each row of the matrix contains as the first column the actual value which we want + // the model to predict for us (the `y`), and the rest of the columns contain the input + // parameters on which the model will base its predictions on (the `xs`). + // + // In machine learning terms this is essentially the training data for the model. + // + // As a special case the very first input parameter represents the constant factor + // of the linear equation: the so called "intercept value". Since it's supposed to + // be constant we can just put a dummy input parameter of either a `1` (in case we want it) + // or a `0` (in case we do not). + for (&y, xs) in ys.iter().zip(xs.chunks_exact(x_vars)) { + data.push(y); + if with_intercept { + data.push(1.0); + } else { + data.push(0.0); + } + data.extend(xs); + } + let model = linregress::fit_low_level_regression_model(&data, ys.len(), x_vars + 2).ok()?; + Some((model.parameters[0], model.parameters[1..].to_vec(), model.se)) +} + +fn linear_regression( + xs: Vec, + mut ys: Vec, + x_vars: usize, +) -> Option<(f64, Vec, Vec)> { + let mut min = ys[0]; + for &value in &ys { + if value < min { + min = value; + } + } + + for value in &mut ys { + *value -= min; + } + + let (intercept, params, errors) = raw_linear_regression(xs, ys, x_vars, false)?; + Some((intercept + min, params, errors[1..].to_vec())) +} + impl Analysis { // Useful for when there are no components, and we just need an median value of the benchmark // results. Note: We choose the median value because it is more robust to outliers. @@ -95,11 +185,12 @@ impl Analysis { let mid = values.len() / 2; Some(Self { - base: values[mid], + base: selector.scale_weight(values[mid]), slopes: Vec::new(), names: Vec::new(), value_dists: None, - model: None, + errors: None, + selector, }) } @@ -186,15 +277,19 @@ impl Analysis { }) .collect::>(); - let base = models[0].0.max(0f64) as u128; - let slopes = models.iter().map(|x| x.1.max(0f64) as u128).collect::>(); + let base = selector.scale_and_cast_weight(models[0].0.max(0f64), false); + let slopes = models + .iter() + .map(|x| selector.scale_and_cast_weight(x.1.max(0f64), false)) + .collect::>(); Some(Self { base, slopes, names: results.into_iter().map(|x| x.0).collect::>(), value_dists: None, - model: None, + errors: None, + selector, }) } @@ -221,36 +316,7 @@ impl Analysis { *rs = rs[ql..rs.len() - ql].to_vec(); } - let mut data = - vec![("Y", results.iter().flat_map(|x| x.1.iter().map(|v| *v as f64)).collect())]; - let names = r[0].components.iter().map(|x| format!("{:?}", x.0)).collect::>(); - data.extend(names.iter().enumerate().map(|(i, p)| { - ( - p.as_str(), - results - .iter() - .flat_map(|x| Some(x.0[i] as f64).into_iter().cycle().take(x.1.len())) - .collect::>(), - ) - })); - - let data = RegressionDataBuilder::new().build_from(data).ok()?; - - let model = FormulaRegressionBuilder::new() - .data(&data) - .formula(format!("Y ~ {}", names.join(" + "))) - .fit() - .ok()?; - - let slopes = model - .parameters - .regressor_values - .iter() - .enumerate() - .map(|(_, x)| (*x + 0.5) as u128) - .collect(); - let value_dists = results .iter() .map(|(p, vs)| { @@ -269,12 +335,33 @@ impl Analysis { }) .collect::>(); + let mut ys: Vec = Vec::new(); + let mut xs: Vec = Vec::new(); + for result in results { + let x: Vec = result.0.iter().map(|value| *value as f64).collect(); + for y in result.1 { + xs.extend(x.iter().copied()); + ys.push(y as f64); + } + } + + let (intercept, slopes, errors) = linear_regression(xs, ys, r[0].components.len())?; + Some(Self { - base: (model.parameters.intercept_value + 0.5) as u128, - slopes, + base: selector.scale_and_cast_weight(intercept, true), + slopes: slopes + .into_iter() + .map(|value| selector.scale_and_cast_weight(value, true)) + .collect(), names, value_dists: Some(value_dists), - model: Some(model), + errors: Some( + errors + .into_iter() + .map(|value| selector.scale_and_cast_weight(value, false)) + .collect(), + ), + selector, }) } @@ -304,9 +391,9 @@ impl Analysis { .for_each(|(a, b)| assert!(a == b, "benchmark results not in the same order")); let names = median_slopes.names; let value_dists = min_squares.value_dists; - let model = min_squares.model; + let errors = min_squares.errors; - Some(Self { base, slopes, names, value_dists, model }) + Some(Self { base, slopes, names, value_dists, errors, selector }) } } @@ -363,18 +450,19 @@ impl std::fmt::Display for Analysis { } } } - if let Some(ref model) = self.model { + + if let Some(ref errors) = self.errors { writeln!(f, "\nQuality and confidence:")?; writeln!(f, "param error")?; - for (p, se) in self.names.iter().zip(model.se.regressor_values.iter()) { - writeln!(f, "{} {:>8}", p, ms(*se as u128))?; + for (p, se) in self.names.iter().zip(errors.iter()) { + writeln!(f, "{} {:>8}", p, ms(self.selector.nanos_from_weight(*se)))?; } } writeln!(f, "\nModel:")?; - writeln!(f, "Time ~= {:>8}", ms(self.base))?; + writeln!(f, "Time ~= {:>8}", ms(self.selector.nanos_from_weight(self.base)))?; for (&t, n) in self.slopes.iter().zip(self.names.iter()) { - writeln!(f, " + {} {:>8}", n, ms(t))?; + writeln!(f, " + {} {:>8}", n, ms(self.selector.nanos_from_weight(t)))?; } writeln!(f, " µs") } @@ -415,6 +503,53 @@ mod tests { } } + #[test] + fn test_linear_regression() { + let ys = vec![ + 3797981.0, + 37857779.0, + 70569402.0, + 104004114.0, + 137233924.0, + 169826237.0, + 203521133.0, + 237552333.0, + 271082065.0, + 305554637.0, + 335218347.0, + 371759065.0, + 405086197.0, + 438353555.0, + 472891417.0, + 505339532.0, + 527784778.0, + 562590596.0, + 635291991.0, + 673027090.0, + 708119408.0, + ]; + let xs = vec![ + 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, + 16.0, 17.0, 18.0, 19.0, 20.0, + ]; + + let (intercept, params, errors) = + raw_linear_regression(xs.clone(), ys.clone(), 1, true).unwrap(); + assert_eq!(intercept as i64, -2712997); + assert_eq!(params.len(), 1); + assert_eq!(params[0] as i64, 34444926); + assert_eq!(errors.len(), 2); + assert_eq!(errors[0] as i64, 4805766); + assert_eq!(errors[1] as i64, 411084); + + let (intercept, params, errors) = linear_regression(xs, ys, 1).unwrap(); + assert_eq!(intercept as i64, 3797981); + assert_eq!(params.len(), 1); + assert_eq!(params[0] as i64, 33968513); + assert_eq!(errors.len(), 1); + assert_eq!(errors[0] as i64, 217331); + } + #[test] fn analysis_median_slopes_should_work() { let data = vec![ @@ -478,8 +613,8 @@ mod tests { let extrinsic_time = Analysis::median_slopes(&data, BenchmarkSelector::ExtrinsicTime).unwrap(); - assert_eq!(extrinsic_time.base, 10_000_000); - assert_eq!(extrinsic_time.slopes, vec![1_000_000, 100_000]); + assert_eq!(extrinsic_time.base, 10_000_000_000); + assert_eq!(extrinsic_time.slopes, vec![1_000_000_000, 100_000_000]); let reads = Analysis::median_slopes(&data, BenchmarkSelector::Reads).unwrap(); assert_eq!(reads.base, 2); @@ -553,15 +688,30 @@ mod tests { let extrinsic_time = Analysis::min_squares_iqr(&data, BenchmarkSelector::ExtrinsicTime).unwrap(); - assert_eq!(extrinsic_time.base, 10_000_000); - assert_eq!(extrinsic_time.slopes, vec![1_000_000, 100_000]); + assert_eq!(extrinsic_time.base, 11_500_000_000); + assert_eq!(extrinsic_time.slopes, vec![630635838, 23699421]); let reads = Analysis::min_squares_iqr(&data, BenchmarkSelector::Reads).unwrap(); - assert_eq!(reads.base, 2); + assert_eq!(reads.base, 3); assert_eq!(reads.slopes, vec![1, 0]); let writes = Analysis::min_squares_iqr(&data, BenchmarkSelector::Writes).unwrap(); - assert_eq!(writes.base, 0); + assert_eq!(writes.base, 2); assert_eq!(writes.slopes, vec![0, 2]); } + + #[test] + fn analysis_min_squares_iqr_uses_multiple_samples_for_same_parameters() { + let data = vec![ + benchmark_result(vec![(BenchmarkParameter::n, 0)], 2_000_000, 0, 0, 0), + benchmark_result(vec![(BenchmarkParameter::n, 0)], 4_000_000, 0, 0, 0), + benchmark_result(vec![(BenchmarkParameter::n, 1)], 4_000_000, 0, 0, 0), + benchmark_result(vec![(BenchmarkParameter::n, 1)], 8_000_000, 0, 0, 0), + ]; + + let extrinsic_time = + Analysis::min_squares_iqr(&data, BenchmarkSelector::ExtrinsicTime).unwrap(); + assert_eq!(extrinsic_time.base, 2_000_000_000); + assert_eq!(extrinsic_time.slopes, vec![4_000_000_000]); + } } diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 614216a96940a..3e3888dbf111d 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -30,7 +30,7 @@ mod utils; pub mod baseline; #[cfg(feature = "std")] -pub use analysis::{Analysis, AnalysisChoice, BenchmarkSelector, RegressionModel}; +pub use analysis::{Analysis, AnalysisChoice, BenchmarkSelector}; #[doc(hidden)] pub use frame_support; #[doc(hidden)] diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index 42a237fcf3ce3..a601c09eb5033 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -29,7 +29,6 @@ use serde::Serialize; use crate::{pallet::command::ComponentRange, shared::UnderscoreHelper, PalletCmd}; use frame_benchmarking::{ Analysis, AnalysisChoice, BenchmarkBatchSplitResults, BenchmarkResult, BenchmarkSelector, - RegressionModel, }; use frame_support::traits::StorageInfo; use sp_core::hexdisplay::HexDisplay; @@ -145,13 +144,15 @@ fn map_results( Ok(all_benchmarks) } -// Get an iterator of errors from a model. If the model is `None` all errors are zero. -fn extract_errors(model: &Option) -> impl Iterator + '_ { - let mut errors = model.as_ref().map(|m| m.se.regressor_values.iter()); - std::iter::from_fn(move || match &mut errors { - Some(model) => model.next().map(|val| *val as u128), - _ => Some(0), - }) +// Get an iterator of errors. +fn extract_errors(errors: &Option>) -> impl Iterator + '_ { + errors + .as_ref() + .map(|e| e.as_slice()) + .unwrap_or(&[]) + .iter() + .copied() + .chain(std::iter::repeat(0)) } // Analyze and return the relevant results for a given benchmark. @@ -190,24 +191,20 @@ fn get_benchmark_data( .slopes .into_iter() .zip(extrinsic_time.names.iter()) - .zip(extract_errors(&extrinsic_time.model)) + .zip(extract_errors(&extrinsic_time.errors)) .for_each(|((slope, name), error)| { if !slope.is_zero() { if !used_components.contains(&name) { used_components.push(name); } - used_extrinsic_time.push(ComponentSlope { - name: name.clone(), - slope: slope.saturating_mul(1000), - error: error.saturating_mul(1000), - }); + used_extrinsic_time.push(ComponentSlope { name: name.clone(), slope, error }); } }); reads .slopes .into_iter() .zip(reads.names.iter()) - .zip(extract_errors(&reads.model)) + .zip(extract_errors(&reads.errors)) .for_each(|((slope, name), error)| { if !slope.is_zero() { if !used_components.contains(&name) { @@ -220,7 +217,7 @@ fn get_benchmark_data( .slopes .into_iter() .zip(writes.names.iter()) - .zip(extract_errors(&writes.model)) + .zip(extract_errors(&writes.errors)) .for_each(|((slope, name), error)| { if !slope.is_zero() { if !used_components.contains(&name) { @@ -251,7 +248,7 @@ fn get_benchmark_data( BenchmarkData { name: String::from_utf8(batch.benchmark.clone()).unwrap(), components, - base_weight: extrinsic_time.base.saturating_mul(1000), + base_weight: extrinsic_time.base, base_reads: reads.base, base_writes: writes.base, component_weight: used_extrinsic_time, From dc22e48e1da70b84fb7b8a1ffc2076cf1b6e1d99 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 14 Sep 2022 18:31:58 +0200 Subject: [PATCH 1161/1472] Fix Rust features (#11976) * Add std feature Signed-off-by: Oliver Tale-Yazdi * Fix features Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * Fix features Signed-off-by: Oliver Tale-Yazdi * Fmt Signed-off-by: Oliver Tale-Yazdi * Fix features Signed-off-by: Oliver Tale-Yazdi * Cleanup Signed-off-by: Oliver Tale-Yazdi * Impl function also in tests Signed-off-by: Oliver Tale-Yazdi * Make compile Signed-off-by: Oliver Tale-Yazdi * Fix sp-trie feature Something makes the bench regression guard fail, maybe this? Signed-off-by: Oliver Tale-Yazdi * Add runtime-benchmarks feature to sc-service Signed-off-by: Oliver Tale-Yazdi * Revert "Fix sp-trie feature" This reverts commit f2cddfe41bc72e6f2f8133795ec9408ba0c3ec63. Was already fixed, only needed a CI retry. Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 29 +++++++++++++++++++ bin/node-template/node/Cargo.toml | 7 ++++- bin/node-template/node/src/command.rs | 6 ++++ bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 5 +++- bin/node/cli/Cargo.toml | 5 +++- bin/node/cli/src/command.rs | 6 ++++ bin/node/runtime/Cargo.toml | 21 ++++++++++---- client/service/Cargo.toml | 1 + frame/alliance/Cargo.toml | 4 ++- frame/assets/Cargo.toml | 2 +- frame/babe/Cargo.toml | 2 +- frame/babe/src/benchmarking.rs | 29 ++----------------- frame/babe/src/tests.rs | 21 ++++++++++++++ frame/bags-list/Cargo.toml | 9 +++++- frame/bags-list/fuzzer/Cargo.toml | 2 +- frame/bags-list/src/lib.rs | 2 +- frame/bags-list/src/list/mod.rs | 2 +- frame/bags-list/src/mock.rs | 3 +- frame/balances/Cargo.toml | 2 +- frame/benchmarking/Cargo.toml | 4 ++- frame/benchmarking/src/lib.rs | 2 ++ frame/bounties/Cargo.toml | 1 + frame/child-bounties/Cargo.toml | 1 + frame/collective/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/conviction-voting/Cargo.toml | 5 ++-- frame/democracy/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 3 +- frame/election-provider-support/Cargo.toml | 1 + .../benchmarking/Cargo.toml | 2 +- frame/election-provider-support/src/lib.rs | 8 ++--- frame/elections-phragmen/Cargo.toml | 1 + frame/examples/basic/Cargo.toml | 2 +- frame/gilt/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/identity/Cargo.toml | 2 +- frame/im-online/Cargo.toml | 1 + frame/indices/Cargo.toml | 1 + frame/lottery/Cargo.toml | 1 + frame/membership/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- .../merkle-mountain-range/src/benchmarking.rs | 2 ++ frame/merkle-mountain-range/src/lib.rs | 2 +- frame/multisig/Cargo.toml | 1 + frame/nomination-pools/Cargo.toml | 10 +++++-- .../nomination-pools/benchmarking/Cargo.toml | 25 ++++++++++++---- .../nomination-pools/benchmarking/src/lib.rs | 1 + frame/offences/benchmarking/Cargo.toml | 12 ++++---- frame/offences/benchmarking/src/lib.rs | 1 + frame/preimage/Cargo.toml | 2 +- frame/proxy/Cargo.toml | 1 + frame/ranked-collective/Cargo.toml | 2 +- frame/recovery/Cargo.toml | 2 +- frame/referenda/Cargo.toml | 2 +- frame/remark/Cargo.toml | 1 + frame/scheduler/Cargo.toml | 2 +- frame/session/benchmarking/Cargo.toml | 6 +++- frame/session/benchmarking/src/lib.rs | 1 + frame/staking/Cargo.toml | 8 ++++- frame/staking/src/pallet/impls.rs | 7 ++++- frame/state-trie-migration/Cargo.toml | 2 +- frame/support/Cargo.toml | 6 ++-- frame/system/benchmarking/Cargo.toml | 6 ++++ frame/timestamp/Cargo.toml | 3 +- frame/tips/Cargo.toml | 1 + .../asset-tx-payment/Cargo.toml | 1 + frame/transaction-storage/Cargo.toml | 2 ++ frame/treasury/Cargo.toml | 1 + frame/uniques/Cargo.toml | 2 +- frame/utility/Cargo.toml | 1 + frame/vesting/Cargo.toml | 1 + frame/whitelist/Cargo.toml | 1 + primitives/api/Cargo.toml | 8 ++--- primitives/core/Cargo.toml | 2 ++ primitives/core/hashing/Cargo.toml | 1 + primitives/inherents/Cargo.toml | 4 +-- primitives/io/Cargo.toml | 9 +++--- primitives/runtime-interface/Cargo.toml | 2 ++ primitives/runtime/Cargo.toml | 1 - primitives/runtime/src/lib.rs | 4 --- test-utils/runtime/Cargo.toml | 1 + utils/frame/benchmarking-cli/Cargo.toml | 2 +- utils/frame/generate-bags/Cargo.toml | 2 +- 84 files changed, 250 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34d2296e019ce..2aad399f3bde3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,6 +427,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64ct" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851" + [[package]] name = "beef" version = "0.5.1" @@ -5968,6 +5974,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-runtime-interface", "sp-staking", "sp-std", ] @@ -6842,6 +6849,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] + [[package]] name = "pkg-config" version = "0.3.19" @@ -9127,6 +9145,7 @@ checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" dependencies = [ "der", "generic-array 0.14.4", + "pkcs8", "subtle", "zeroize", ] @@ -10339,6 +10358,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "ss58-registry" version = "1.29.0" diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index eeba198da8212..dc1d3caa8b75d 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -67,7 +67,12 @@ substrate-build-script-utils = { version = "3.0.0", path = "../../../utils/build [features] default = [] -runtime-benchmarks = ["node-template-runtime/runtime-benchmarks"] +# Dependencies that are only required if runtime benchmarking should be build. +runtime-benchmarks = [ + "node-template-runtime/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-benchmarking-cli/runtime-benchmarks", +] # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. try-runtime = ["node-template-runtime/try-runtime", "try-runtime-cli"] diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index f8f02ed8fc2dd..6d293b7b85fcc 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -127,6 +127,12 @@ pub fn run() -> sc_cli::Result<()> { let PartialComponents { client, .. } = service::new_partial(&config)?; cmd.run(client) }, + #[cfg(not(feature = "runtime-benchmarks"))] + BenchmarkCmd::Storage(_) => Err( + "Storage benchmarking can be enabled with `--features runtime-benchmarks`." + .into(), + ), + #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Storage(cmd) => { let PartialComponents { client, backend, .. } = service::new_partial(&config)?; diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 6f7a4b1d25841..3cfcef9d902ce 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -30,7 +30,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../ default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index bbe3e8eef7d3c..c6c4b2ea911ec 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -57,6 +57,9 @@ substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-bu [features] default = ["std"] std = [ + "frame-try-runtime?/std", + "frame-system-benchmarking?/std", + "frame-benchmarking?/std", "codec/std", "scale-info/std", "frame-executive/std", @@ -88,7 +91,7 @@ std = [ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", - "frame-system-benchmarking", + "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "hex-literal", "pallet-balances/runtime-benchmarks", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 247a61d835dc3..a435945168e0d 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -159,7 +159,10 @@ cli = [ "substrate-build-script-utils", "try-runtime-cli", ] -runtime-benchmarks = ["kitchensink-runtime/runtime-benchmarks", "frame-benchmarking-cli"] +runtime-benchmarks = [ + "kitchensink-runtime/runtime-benchmarks", + "frame-benchmarking-cli/runtime-benchmarks" +] # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. try-runtime = ["kitchensink-runtime/try-runtime", "try-runtime-cli"] diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 79abe8975f3b6..108d7743843b6 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -119,6 +119,12 @@ pub fn run() -> Result<()> { let partial = new_partial(&config)?; cmd.run(partial.client) }, + #[cfg(not(feature = "runtime-benchmarks"))] + BenchmarkCmd::Storage(_) => Err( + "Storage benchmarking can be enabled with `--features runtime-benchmarks`." + .into(), + ), + #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Storage(cmd) => { // ensure that we keep the task manager alive let partial = new_partial(&config)?; diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index eb9c91a3baa05..6a81c16780240 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -117,6 +117,13 @@ substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-bu default = ["std"] with-tracing = ["frame-executive/with-tracing"] std = [ + "sp-sandbox/std", + "pallet-whitelist/std", + "pallet-offences-benchmarking?/std", + "pallet-election-provider-support-benchmarking?/std", + "pallet-asset-tx-payment/std", + "frame-system-benchmarking?/std", + "frame-election-provider-support/std", "sp-authority-discovery/std", "pallet-assets/std", "pallet-authority-discovery/std", @@ -148,6 +155,7 @@ std = [ "pallet-multisig/std", "pallet-nomination-pools/std", "pallet-nomination-pools-runtime-api/std", + "pallet-nomination-pools-benchmarking?/std", "pallet-identity/std", "pallet-scheduler/std", "node-primitives/std", @@ -159,6 +167,7 @@ std = [ "pallet-randomness-collective-flip/std", "sp-std/std", "pallet-session/std", + "pallet-session-benchmarking?/std", "sp-api/std", "sp-runtime/std", "sp-staking/std", @@ -167,7 +176,7 @@ std = [ "sp-session/std", "pallet-sudo/std", "frame-support/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-system-rpc-runtime-api/std", "frame-system/std", "pallet-election-provider-multi-phase/std", @@ -188,7 +197,7 @@ std = [ "pallet-uniques/std", "pallet-vesting/std", "log/std", - "frame-try-runtime/std", + "frame-try-runtime?/std", "sp-io/std", "pallet-child-bounties/std", "pallet-alliance/std", @@ -221,8 +230,8 @@ runtime-benchmarks = [ "pallet-membership/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", - "pallet-nomination-pools-benchmarking", - "pallet-offences-benchmarking", + "pallet-nomination-pools-benchmarking/runtime-benchmarks", + "pallet-offences-benchmarking/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", @@ -230,7 +239,7 @@ runtime-benchmarks = [ "pallet-referenda/runtime-benchmarks", "pallet-recovery/runtime-benchmarks", "pallet-remark/runtime-benchmarks", - "pallet-session-benchmarking", + "pallet-session-benchmarking/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", @@ -242,7 +251,7 @@ runtime-benchmarks = [ "pallet-uniques/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-whitelist/runtime-benchmarks", - "frame-system-benchmarking", + "frame-system-benchmarking/runtime-benchmarks", "hex-literal", ] try-runtime = [ diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 76c61fe17f0da..3c574ef13c8e6 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -20,6 +20,7 @@ rocksdb = ["sc-client-db/rocksdb"] wasmtime = ["sc-executor/wasmtime"] # exposes the client type test-helpers = [] +runtime-benchmarks = ["sc-client-db/runtime-benchmarks"] [dependencies] jsonrpsee = { version = "0.15.1", features = ["server"] } diff --git a/frame/alliance/Cargo.toml b/frame/alliance/Cargo.toml index 706827708ce88..24e047091009b 100644 --- a/frame/alliance/Cargo.toml +++ b/frame/alliance/Cargo.toml @@ -41,6 +41,8 @@ pallet-collective = { version = "4.0.0-dev", path = "../collective" } [features] default = ["std"] std = [ + "pallet-collective?/std", + "frame-benchmarking?/std", "log/std", "codec/std", "scale-info/std", @@ -55,7 +57,7 @@ std = [ runtime-benchmarks = [ "hex", "sha2", - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 9e98d4e15aed4..7e750f7618437 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -39,7 +39,7 @@ std = [ "sp-runtime/std", "frame-support/std", "frame-system/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index dd76726df3017..9f79a404724e0 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -43,7 +43,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/babe/src/benchmarking.rs b/frame/babe/src/benchmarking.rs index ac7ab28b5164a..20002c97f8e56 100644 --- a/frame/babe/src/benchmarking.rs +++ b/frame/babe/src/benchmarking.rs @@ -17,6 +17,8 @@ //! Benchmarks for the BABE Pallet. +#![cfg(feature = "runtime-benchmarks")] + use super::*; use frame_benchmarking::benchmarks; @@ -70,30 +72,3 @@ benchmarks! { crate::mock::Test, ) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::*; - - #[test] - fn test_generate_equivocation_report_blob() { - let (pairs, mut ext) = new_test_ext_with_pairs(3); - - let offending_authority_index = 0; - let offending_authority_pair = &pairs[0]; - - ext.execute_with(|| { - start_era(1); - - let equivocation_proof = generate_equivocation_proof( - offending_authority_index, - offending_authority_pair, - CurrentSlot::::get() + 1, - ); - - println!("equivocation_proof: {:?}", equivocation_proof); - println!("equivocation_proof.encode(): {:?}", equivocation_proof.encode()); - }); - } -} diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 84e55ed5d050b..1015ada7f0185 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -926,3 +926,24 @@ fn add_epoch_configurations_migration_works() { assert_eq!(PendingEpochConfigChange::::get(), Some(next_config_descriptor)); }); } + +#[test] +fn generate_equivocation_report_blob() { + let (pairs, mut ext) = new_test_ext_with_pairs(3); + + let offending_authority_index = 0; + let offending_authority_pair = &pairs[0]; + + ext.execute_with(|| { + start_era(1); + + let equivocation_proof = generate_equivocation_proof( + offending_authority_index, + offending_authority_pair, + CurrentSlot::::get() + 1, + ); + + println!("equivocation_proof: {:?}", equivocation_proof); + println!("equivocation_proof.encode(): {:?}", equivocation_proof.encode()); + }); +} diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 9590d3d3ec4a4..2f9fa6c624538 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -41,12 +41,18 @@ sp-core = { version = "6.0.0", path = "../../primitives/core"} sp-io = { version = "6.0.0", path = "../../primitives/io"} sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } -frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support", features = ["runtime-benchmarks"] } +frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } [features] default = ["std"] std = [ + "sp-tracing?/std", + "sp-io?/std", + "sp-core?/std", + "pallet-balances?/std", + "frame-benchmarking?/std", + "scale-info/std", "codec/std", "sp-runtime/std", "sp-std/std", @@ -68,5 +74,6 @@ fuzz = [ "sp-io", "pallet-balances", "sp-tracing", + "frame-election-provider-support/fuzz", ] try-runtime = [ "frame-support/try-runtime" ] diff --git a/frame/bags-list/fuzzer/Cargo.toml b/frame/bags-list/fuzzer/Cargo.toml index ec7d98255b019..0f10077dcbce8 100644 --- a/frame/bags-list/fuzzer/Cargo.toml +++ b/frame/bags-list/fuzzer/Cargo.toml @@ -13,7 +13,7 @@ publish = false [dependencies] honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } -frame-election-provider-support = { version = "4.0.0-dev", features = ["runtime-benchmarks"], path = "../../election-provider-support" } +frame-election-provider-support = { version = "4.0.0-dev", features = ["fuzz"], path = "../../election-provider-support" } pallet-bags-list = { version = "4.0.0-dev", features = ["fuzz"], path = ".." } [[bin]] diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 02adc064790f2..2b48fbf0ca630 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -387,7 +387,7 @@ impl, I: 'static> ScoreProvider for Pallet { Node::::get(id).map(|node| node.score()).unwrap_or_default() } - #[cfg(any(feature = "runtime-benchmarks", test))] + #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", test))] fn set_score_of(id: &T::AccountId, new_score: T::Score) { ListNodes::::mutate(id, |maybe_node| { if let Some(node) = maybe_node.as_mut() { diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index cfa7daf198937..272526ad1a636 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -882,7 +882,7 @@ impl, I: 'static> Node { &self.id } - #[cfg(any(feature = "runtime-benchmarks", test))] + #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", test))] pub fn set_score(&mut self, s: T::Score) { self.score = s } diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 1044e4c450a41..f6bde63b3867c 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -40,7 +40,7 @@ impl frame_election_provider_support::ScoreProvider for StakingMock { *NextVoteWeightMap::get().get(id).unwrap_or(&NextVoteWeight::get()) } - #[cfg(any(feature = "runtime-benchmarks", test))] + #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", test))] fn set_score_of(id: &AccountId, weight: Self::Score) { NEXT_VOTE_WEIGHT_MAP.with(|m| m.borrow_mut().insert(*id, weight)); } @@ -108,6 +108,7 @@ pub struct ExtBuilder { skip_genesis_ids: bool, } +#[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", test))] impl ExtBuilder { /// Skip adding the default genesis ids to the list. #[cfg(test)] diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 10150f0895906..fd2312993b7e7 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -31,7 +31,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index c098eee528233..49603915ca6da 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -54,4 +54,6 @@ std = [ "sp-std/std", "sp-storage/std", ] -runtime-benchmarks = [] +runtime-benchmarks = [ + "frame-system/runtime-benchmarks", +] diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 3e3888dbf111d..d96ed4dd17b6e 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -975,6 +975,8 @@ macro_rules! impl_benchmark { ( $( $name_extra:ident ),* ) ( $( $name_skip_meta:ident ),* ) ) => { + // We only need to implement benchmarks for the runtime-benchmarks feature or testing. + #[cfg(any(feature = "runtime-benchmarks", test))] impl, $instance: $instance_bound )? > $crate::Benchmarking for Pallet where T: frame_system::Config, $( $where_clause )* diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 645772fb27669..4aaf088abb5b6 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -33,6 +33,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 575f3e38c8183..ee9a838744d25 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -34,6 +34,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index 0cb2a8b136044..aca2434127f03 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -28,7 +28,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 019f111302a55..284b186a8dff2 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -69,7 +69,7 @@ std = [ "sp-io/std", "sp-std/std", "sp-sandbox/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "wasm-instrument/std", diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index ab6d04d199bc6..3c40017ece8e7 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -36,7 +36,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", @@ -46,7 +46,8 @@ std = [ "sp-std/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index e0b85ed7d18df..f0ab3162c892b 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -34,7 +34,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index aea3b5cd6d2b0..ca94fef6a4356 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -52,6 +52,7 @@ frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } [features] default = ["std"] std = [ + "pallet-election-provider-support-benchmarking?/std", "codec/std", "scale-info/std", "log/std", @@ -68,7 +69,7 @@ std = [ "frame-election-provider-support/std", "log/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "rand/std", "strum/std", ] diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 67e1ea63cb655..5d064c770f8d9 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -31,6 +31,7 @@ sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elect [features] default = ["std"] +fuzz = ["default"] std = [ "codec/std", "frame-support/std", diff --git a/frame/election-provider-support/benchmarking/Cargo.toml b/frame/election-provider-support/benchmarking/Cargo.toml index 00037d460db17..0f296d9a70ee0 100644 --- a/frame/election-provider-support/benchmarking/Cargo.toml +++ b/frame/election-provider-support/benchmarking/Cargo.toml @@ -25,7 +25,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../../pri default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-election-provider-support/std", "frame-system/std", "sp-npos-elections/std", diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 21a01ce1904ec..9f60411435da0 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -519,9 +519,7 @@ pub trait SortedListProvider { /// If `who` changes by the returned amount they are guaranteed to have a worst case change /// in their list position. #[cfg(feature = "runtime-benchmarks")] - fn score_update_worst_case(_who: &AccountId, _is_increase: bool) -> Self::Score { - Self::Score::max_value() - } + fn score_update_worst_case(_who: &AccountId, _is_increase: bool) -> Self::Score; } /// Something that can provide the `Score` of an account. Similar to [`ElectionProvider`] and @@ -533,8 +531,8 @@ pub trait ScoreProvider { /// Get the current `Score` of `who`. fn score(who: &AccountId) -> Self::Score; - /// For tests and benchmarks, set the `score`. - #[cfg(any(feature = "runtime-benchmarks", test))] + /// For tests, benchmarks and fuzzing, set the `score`. + #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", test))] fn set_score_of(_: &AccountId, _: Self::Score) {} } diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index d71a74f76a114..2d71a6bed39df 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -36,6 +36,7 @@ substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index a5f0c7c89321a..e06bfa374cd9b 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -31,7 +31,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../../primit default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index d6f61c6d250ba..8c60c847027a3 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -31,7 +31,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 2090a4ea2e228..4bd17b914cefa 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -45,7 +45,7 @@ sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 8e821537fd9b2..92e55c5c2b934 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -31,7 +31,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index a90b95b21cd88..8c08ad1a8a89a 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -33,6 +33,7 @@ pallet-session = { version = "4.0.0-dev", path = "../session" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index 90eb18a106000..adc3f2a6ea90f 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -30,6 +30,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 8f7c8eefe800d..486bb356059f6 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -32,6 +32,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 0473fd46956af..8ec1087e5ac0e 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -28,7 +28,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 75301afed0094..43d7d6ba2eed7 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -33,7 +33,7 @@ itertools = "0.10.3" default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "mmr-lib/std", diff --git a/frame/merkle-mountain-range/src/benchmarking.rs b/frame/merkle-mountain-range/src/benchmarking.rs index b698e432534d8..d24364a55f9e6 100644 --- a/frame/merkle-mountain-range/src/benchmarking.rs +++ b/frame/merkle-mountain-range/src/benchmarking.rs @@ -17,6 +17,8 @@ //! Benchmarks for the MMR pallet. +#![cfg(feature = "runtime-benchmarks")] + use crate::*; use frame_benchmarking::benchmarks_instance_pallet; use frame_support::traits::OnInitialize; diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 4644ebcb7da1c..9f989847af0f9 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -63,7 +63,7 @@ use sp_runtime::{ SaturatedConversion, }; -#[cfg(any(feature = "runtime-benchmarks", test))] +#[cfg(feature = "runtime-benchmarks")] mod benchmarking; mod default_weights; mod mmr; diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index a370215032714..6c8b5fbaa7362 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -29,6 +29,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index ef8465e670bf6..459ee5f440a12 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -32,9 +32,6 @@ sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } rand = { version = "0.8.5", features = ["small_rng"] } [features] -runtime-benchmarks = [] -try-runtime = [ "frame-support/try-runtime" ] -fuzz-test = [] default = ["std"] std = [ "codec/std", @@ -48,3 +45,10 @@ std = [ "sp-core/std", "log/std", ] +runtime-benchmarks = [ + "sp-staking/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime" +] +fuzz-test = [] diff --git a/frame/nomination-pools/benchmarking/Cargo.toml b/frame/nomination-pools/benchmarking/Cargo.toml index 2e045c95ec9b3..69ba6585481d5 100644 --- a/frame/nomination-pools/benchmarking/Cargo.toml +++ b/frame/nomination-pools/benchmarking/Cargo.toml @@ -22,12 +22,13 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -pallet-bags-list = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../bags-list" } -pallet-staking = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../staking" } -pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../", features = ["runtime-benchmarks"] } +pallet-bags-list = { version = "4.0.0-dev", default-features = false, path = "../../bags-list" } +pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../staking" } +pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../" } # Substrate Primitives sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime-interface" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } @@ -40,6 +41,7 @@ sp-io = { version = "6.0.0", path = "../../../primitives/io" } [features] default = ["std"] + std = [ "frame-benchmarking/std", "frame-election-provider-support/std", @@ -49,7 +51,20 @@ std = [ "pallet-staking/std", "pallet-nomination-pools/std", "sp-runtime/std", + "sp-runtime-interface/std", + "sp-io/std", "sp-staking/std", - "sp-std/std", - "pallet-balances/std", + "sp-std/std", +] + +runtime-benchmarks = [ + "frame-election-provider-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "sp-staking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", + "pallet-nomination-pools/runtime-benchmarks", + "pallet-bags-list/runtime-benchmarks", ] diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 07d5c63493ef8..581cfc12a3121 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -17,6 +17,7 @@ //! Benchmarks for the nomination pools coupled with the staking and bags list pallets. +#![cfg(feature = "runtime-benchmarks")] #![cfg_attr(not(feature = "std"), no_std)] #[cfg(test)] diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index 2b8e461b84192..3c7a43068af82 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -23,13 +23,9 @@ pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../b pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../grandpa" } pallet-im-online = { version = "4.0.0-dev", default-features = false, path = "../../im-online" } -pallet-offences = { version = "4.0.0-dev", default-features = false, features = [ - "runtime-benchmarks", -], path = "../../offences" } +pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../offences" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../../session" } -pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ - "runtime-benchmarks", -], path = "../../staking" } +pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../staking" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } @@ -60,3 +56,7 @@ std = [ "sp-staking/std", "sp-std/std", ] + +runtime-benchmarks = [ + "pallet-staking/runtime-benchmarks", +] diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index f73dd9caac9c6..c9498214eade4 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -17,6 +17,7 @@ //! Offences pallet benchmarking. +#![cfg(feature = "runtime-benchmarks")] #![cfg_attr(not(feature = "std"), no_std)] mod mock; diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 325e906c61a3c..9a5cc186cca64 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -33,7 +33,7 @@ runtime-benchmarks = [ ] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index aaacaa23021e7..afec89ad40fb8 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -30,6 +30,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/ranked-collective/Cargo.toml b/frame/ranked-collective/Cargo.toml index cb43b9ea4c831..c8cf671a97467 100644 --- a/frame/ranked-collective/Cargo.toml +++ b/frame/ranked-collective/Cargo.toml @@ -29,7 +29,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 396555b3e2758..fb33b88d2dfab 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -36,7 +36,7 @@ runtime-benchmarks = [ ] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index 508f5a5ef8688..4e68d7528ad8a 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -38,7 +38,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "sp-runtime/std", "sp-arithmetic/std", diff --git a/frame/remark/Cargo.toml b/frame/remark/Cargo.toml index fe20365b7c904..f644ea723b59f 100644 --- a/frame/remark/Cargo.toml +++ b/frame/remark/Cargo.toml @@ -31,6 +31,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive default = ["std"] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index d92d0df0c8037..e78d8cd5061c1 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -34,7 +34,7 @@ runtime-benchmarks = [ ] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 930ddb0ce7057..5b2fc0c9e1ebf 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -18,7 +18,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../../session" } -pallet-staking = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../staking" } +pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../staking" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } @@ -46,3 +46,7 @@ std = [ "sp-session/std", "sp-std/std", ] + +runtime-benchmarks = [ + "pallet-staking/runtime-benchmarks", +] diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index 265c35cbe4908..9e478ada53cf2 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -18,6 +18,7 @@ //! Benchmarks for the Session Pallet. // This is separated into its own crate due to cyclic dependency issues. +#![cfg(feature = "runtime-benchmarks")] #![cfg_attr(not(feature = "std"), no_std)] mod mock; diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 37d13a54ba5ed..54d21f7ca6bcc 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -43,7 +43,7 @@ sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elect pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } -pallet-bags-list = { version = "4.0.0-dev", features = ["runtime-benchmarks"], path = "../bags-list" } +pallet-bags-list = { version = "4.0.0-dev", path = "../bags-list" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } @@ -52,6 +52,7 @@ rand_chacha = { version = "0.2" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "serde", "codec/std", "scale-info/std", @@ -61,6 +62,7 @@ std = [ "sp-runtime/std", "sp-staking/std", "pallet-session/std", + "pallet-bags-list/std", "frame-system/std", "pallet-authorship/std", "sp-application-crypto/std", @@ -74,3 +76,7 @@ runtime-benchmarks = [ "sp-staking/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] +fuzz = [ + "pallet-bags-list/fuzz", + "frame-election-provider-support/fuzz", +] diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 13038527bc2f8..aa8b2c01c6ff2 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1282,7 +1282,7 @@ impl ScoreProvider for Pallet { Self::weight_of(who) } - #[cfg(feature = "runtime-benchmarks")] + #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz"))] fn set_score_of(who: &T::AccountId, weight: Self::Score) { // this will clearly results in an inconsistent state, but it should not matter for a // benchmark. @@ -1378,6 +1378,11 @@ impl SortedListProvider for UseNominatorsAndValidatorsM #[allow(deprecated)] Validators::::remove_all(); } + + #[cfg(feature = "runtime-benchmarks")] + fn score_update_worst_case(_who: &T::AccountId, _is_increase: bool) -> Self::Score { + unimplemented!() + } } impl StakingInterface for Pallet { diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index f8a3b1ba3aab4..b803aad69263f 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -39,7 +39,7 @@ sp-tracing = { path = "../../primitives/tracing" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index d0a40a09f2211..98db3aa6aa49d 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -31,7 +31,7 @@ tt-call = "1.0.8" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } -sp-state-machine = { version = "0.12.0", optional = true, path = "../../primitives/state-machine" } +sp-state-machine = { version = "0.12.0", default-features = false, optional = true, path = "../../primitives/state-machine" } bitflags = "1.3" impl-trait-for-tuples = "0.2.2" smallvec = "1.8.0" @@ -49,6 +49,8 @@ parity-util-mem = { version = "0.11.0", default-features = false, features = ["p [features] default = ["std"] std = [ + "sp-core/std", + "k256/std", "once_cell", "serde", "sp-api/std", @@ -62,7 +64,7 @@ std = [ "frame-metadata/std", "sp-inherents/std", "sp-staking/std", - "sp-state-machine", + "sp-state-machine/std", "sp-weights/std", "frame-support-procedural/std", "log/std", diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 437d06a17c781..9ec9ed2ae6d21 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -37,3 +37,9 @@ std = [ "sp-runtime/std", "sp-std/std", ] + +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 8967733f7c5c8..ac495d84b2c1e 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -33,8 +33,9 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ + "sp-io?/std", "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index e2ca152148db6..b00a684c1c83b 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -33,6 +33,7 @@ sp-storage = { version = "6.0.0", path = "../../primitives/storage" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index de9772d885529..2c1247cfc557a 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -41,6 +41,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../../balances" } [features] default = ["std"] std = [ + "scale-info/std", "serde", "codec/std", "sp-std/std", diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 8ed34cb50a652..61b71b000a616 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -36,6 +36,8 @@ sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = true, default = ["std"] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "hex-literal"] std = [ + "log/std", + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 56c2fcdab58f7..08b0acdba5deb 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -34,6 +34,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 19b0790947f84..31aa608ff84b6 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -32,7 +32,7 @@ sp-std = { version = "4.0.0", path = "../../primitives/std" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 7b56d7974e4b5..cbe2892d72dc7 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -30,6 +30,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index eb902c0633331..6a64b474d1485 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -32,6 +32,7 @@ sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/ [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/whitelist/Cargo.toml b/frame/whitelist/Cargo.toml index daee560904a08..895a6e753816d 100644 --- a/frame/whitelist/Cargo.toml +++ b/frame/whitelist/Cargo.toml @@ -31,6 +31,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index 75c935bf844bd..a322799048a31 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -19,8 +19,8 @@ sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-version = { version = "5.0.0", default-features = false, path = "../version" } -sp-state-machine = { version = "0.12.0", optional = true, path = "../state-machine" } -sp-trie = { version = "6.0.0", optional = true, path = "../trie" } +sp-state-machine = { version = "0.12.0", default-features = false, optional = true, path = "../state-machine" } +sp-trie = { version = "6.0.0", default-features = false, optional = true, path = "../trie" } hash-db = { version = "0.15.2", optional = true } thiserror = { version = "1.0.30", optional = true } @@ -36,8 +36,8 @@ std = [ "sp-core/std", "sp-std/std", "sp-runtime/std", - "sp-state-machine", - "sp-trie", + "sp-state-machine/std", + "sp-trie/std", "sp-version/std", "hash-db", "thiserror", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index bf54f8467d1ef..b611449b6730f 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -79,6 +79,8 @@ bench = false [features] default = ["std"] std = [ + "parity-util-mem/std", + "merlin?/std", "full_crypto", "log/std", "thiserror", diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index d85e28d1b2e56..d6fc6bed31fec 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -24,6 +24,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../std" } [features] default = ["std"] std = [ + "digest/std", "blake2/std", "byteorder/std", "sha2/std", diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 628f938880e9f..b176147c053a6 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = impl-trait-for-tuples = "0.2.2" thiserror = { version = "1.0.30", optional = true } sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "6.0.0", optional = true, path = "../runtime" } +sp-runtime = { version = "6.0.0", optional = true, default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] @@ -31,7 +31,7 @@ std = [ "async-trait", "codec/std", "sp-core/std", - "sp-runtime", + "sp-runtime/std", "sp-std/std", "thiserror", ] diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 2e271d3949dee..26dec17e032dd 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -22,10 +22,10 @@ sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-keystore = { version = "0.12.0", default-features = false, optional = true, path = "../keystore" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } libsecp256k1 = { version = "0.7", optional = true } -sp-state-machine = { version = "0.12.0", optional = true, path = "../state-machine" } +sp-state-machine = { version = "0.12.0", default-features = false, optional = true, path = "../state-machine" } sp-wasm-interface = { version = "6.0.0", path = "../wasm-interface", default-features = false } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } -sp-trie = { version = "6.0.0", optional = true, path = "../trie" } +sp-trie = { version = "6.0.0", default-features = false, optional = true, path = "../trie" } sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.17", optional = true } @@ -38,14 +38,15 @@ tracing-core = { version = "0.1.28", default-features = false} [features] default = ["std"] std = [ + "bytes/std", "sp-externalities/std", "sp-core/std", "sp-keystore", "codec/std", "sp-std/std", "hash-db/std", - "sp-trie", - "sp-state-machine", + "sp-trie/std", + "sp-state-machine/std", "libsecp256k1", "secp256k1", "sp-runtime-interface/std", diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index a657c98381c9a..51367d40d0cd0 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -37,6 +37,8 @@ trybuild = "1.0.60" [features] default = [ "std" ] std = [ + "sp-storage/std", + "bytes/std", "sp-wasm-interface/std", "sp-std/std", "sp-tracing/std", diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 278962bcf57c4..1d1a7a2c38b1d 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -41,7 +41,6 @@ sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] -bench = [] runtime-benchmarks = [] default = ["std"] std = [ diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 9c2b691f64faa..8017a6ac529a2 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -19,10 +19,6 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -// to allow benchmarking -#![cfg_attr(feature = "bench", feature(test))] -#[cfg(feature = "bench")] -extern crate test; #[doc(hidden)] pub use codec; diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 6cea6282f5bd8..744cc527e6012 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -67,6 +67,7 @@ default = [ "std", ] std = [ + "parity-util-mem/std", "beefy-primitives/std", "beefy-merkle-tree/std", "sp-application-crypto/std", diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 4f9d703544096..9e5cb12070af9 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -59,6 +59,6 @@ sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } gethostname = "0.2.3" [features] -default = ["rocksdb", "runtime-benchmarks"] +default = ["rocksdb"] runtime-benchmarks = ["sc-client-db/runtime-benchmarks"] rocksdb = ["sc-cli/rocksdb", "sc-client-db/rocksdb"] diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 34d62ab0d8b5f..18f668485114b 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" [dependencies] # FRAME frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } -frame-election-provider-support = { version = "4.0.0-dev", path = "../../../frame/election-provider-support", features = ["runtime-benchmarks"] } +frame-election-provider-support = { version = "4.0.0-dev", path = "../../../frame/election-provider-support" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-staking = { version = "4.0.0-dev", path = "../../../frame/staking" } From 1dcb9ceea7e252eb779f044448bc693ec6161baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 14 Sep 2022 22:08:02 +0200 Subject: [PATCH 1162/1472] Clean up the logging output (#12253) * Clean up the logging output Sadly `trust-dns` and `libp2p::iface` are printing stuff that isn't very informative and just confuses the user. So, we just disable logging output from both of these crates as we already have done this for other crates as well. * FMT --- client/tracing/src/logging/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index 58941617bfb6a..978e24df68d78 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -133,7 +133,14 @@ where .add_directive( parse_default_directive("cranelift_wasm=warn").expect("provided directive is valid"), ) - .add_directive(parse_default_directive("hyper=warn").expect("provided directive is valid")); + .add_directive(parse_default_directive("hyper=warn").expect("provided directive is valid")) + .add_directive( + parse_default_directive("trust_dns_proto=off").expect("provided directive is valid"), + ) + .add_directive( + parse_default_directive("libp2p_mdns::behaviour::iface=off") + .expect("provided directive is valid"), + ); if let Ok(lvl) = std::env::var("RUST_LOG") { if lvl != "" { From fd549573b2fffd620d9f2fcea76edab1cdabc62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 15 Sep 2022 08:00:11 +0200 Subject: [PATCH 1163/1472] Bump wasm-instrument (#12234) * Bump wasm-instrument * Fix benchmarks --- Cargo.lock | 4 ++-- client/executor/common/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/src/benchmarking/mod.rs | 4 ++-- frame/contracts/src/schedule.rs | 2 +- frame/contracts/src/wasm/runtime.rs | 8 ++++---- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2aad399f3bde3..367713b9361ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11578,9 +11578,9 @@ dependencies = [ [[package]] name = "wasm-instrument" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bca81f5279342b38b17d9acbf007a46ddeb73144e2bd5f0a21bfa9fc5d4ab3e" +checksum = "aa1dafb3e60065305741e83db35c6c2584bb3725b692b5b66148a38d72ace6cd" dependencies = [ "parity-wasm 0.45.0", ] diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 1af75c7e31610..71a6f2c324591 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } environmental = "1.1.3" thiserror = "1.0.30" -wasm-instrument = "0.2" +wasm-instrument = "0.3" wasmer = { version = "2.2", features = ["singlepass"], optional = true } wasmi = "0.13" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 284b186a8dff2..e9a90504d7db7 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } log = { version = "0.4", default-features = false } -wasm-instrument = { version = "0.2", default-features = false } +wasm-instrument = { version = "0.3", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } smallvec = { version = "1", default-features = false, features = [ "const_generics", diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 2f8d101504ffa..4a987fd8dde78 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -618,11 +618,11 @@ benchmarks! { imported_functions: vec![ImportedFunction { module: "seal0", name: "gas", - params: vec![ValueType::I32], + params: vec![ValueType::I64], return_type: None, }], call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ - Instruction::I32Const(42), + Instruction::I64Const(42), Instruction::Call(0), ])), .. Default::default() diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 63867a0cc7448..790b74106860a 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -525,7 +525,7 @@ impl Default for InstructionWeights { fn default() -> Self { let max_pages = Limits::default().memory_pages; Self { - version: 2, + version: 3, i64const: cost_instr!(instr_i64const, 1), i64load: cost_instr!(instr_i64load, 2), i64store: cost_instr!(instr_i64store, 2), diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 7caa7c5c6fa1f..edd413aa45bf0 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -164,7 +164,7 @@ impl> From for TrapReason { pub enum RuntimeCosts { /// Charge the gas meter with the cost of a metering block. The charged costs are /// the supplied cost of the block plus the overhead of the metering itself. - MeteringBlock(u32), + MeteringBlock(u64), /// Weight charged for copying data from the sandbox. CopyFromContract(u32), /// Weight charged for copying data to the sandbox. @@ -261,7 +261,7 @@ impl RuntimeCosts { { use self::RuntimeCosts::*; let weight = match *self { - MeteringBlock(amount) => s.gas.saturating_add(amount.into()), + MeteringBlock(amount) => s.gas.saturating_add(amount), CopyFromContract(len) => s.return_per_byte.saturating_mul(len.into()), CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()), Caller => s.caller, @@ -957,7 +957,7 @@ pub mod env { /// This call is supposed to be called only by instrumentation injected code. /// /// - amount: How much gas is used. - fn gas(ctx: Runtime, amount: u32) -> Result<(), TrapReason> { + fn gas(ctx: Runtime, amount: u64) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::MeteringBlock(amount))?; Ok(()) } @@ -1737,7 +1737,7 @@ pub mod env { #[prefixed_alias] fn gas_left(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::GasLeft)?; - let gas_left = &ctx.ext.gas_meter().gas_left().encode(); + let gas_left = &ctx.ext.gas_meter().gas_left().ref_time().encode(); Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, gas_left, false, already_charged)?) } From 3bef1baae8c428524152e6c5fbb1c35285a128b3 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Thu, 15 Sep 2022 10:27:56 +0300 Subject: [PATCH 1164/1472] Include Bitswap into request response protocols (#12262) --- client/network/src/service.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/network/src/service.rs b/client/network/src/service.rs index fb98db3251647..dceb57d9e695c 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -150,6 +150,11 @@ where let local_public = local_identity.public(); let local_peer_id = local_public.to_peer_id(); + params + .network_config + .request_response_protocols + .extend(params.request_response_protocol_configs); + params.network_config.boot_nodes = params .network_config .boot_nodes From 12b5b5a523def11125e5302ba0c9b664be51f19a Mon Sep 17 00:00:00 2001 From: Vlad Date: Thu, 15 Sep 2022 14:21:17 +0300 Subject: [PATCH 1165/1472] Use `--locked` for Cargo in CI everywhere (#12270) --- scripts/ci/gitlab/pipeline/build.yml | 8 +++--- scripts/ci/gitlab/pipeline/test.yml | 38 ++++++++++++++-------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index eedd2ee0bb409..482d54b50f73d 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -62,7 +62,7 @@ build-linux-substrate: - !reference [.rusty-cachier, before_script] script: - rusty-cachier snapshot create - - WASM_BUILD_NO_COLOR=1 time cargo build --release --verbose + - WASM_BUILD_NO_COLOR=1 time cargo build --locked --release --verbose - mv $CARGO_TARGET_DIR/release/substrate ./artifacts/substrate/. - echo -n "Substrate version = " - if [ "${CI_COMMIT_TAG}" ]; then @@ -95,7 +95,7 @@ build-linux-substrate: script: - rusty-cachier snapshot create - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo build --release --verbose + - SKIP_WASM_BUILD=1 time cargo build --locked --release --verbose - cd - - mv $CARGO_TARGET_DIR/release/subkey ./artifacts/subkey/. - echo -n "Subkey version = " @@ -117,7 +117,7 @@ build-subkey-macos: - mkdir -p ./artifacts/subkey script: - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo build --release --verbose + - SKIP_WASM_BUILD=1 time cargo build --locked --release --verbose - cd - - mv ./target/release/subkey ./artifacts/subkey/. - echo -n "Subkey version = " @@ -149,7 +149,7 @@ build-rustdoc: - ./crate-docs/ script: - rusty-cachier snapshot create - - time cargo +nightly doc --workspace --all-features --verbose --no-deps + - time cargo +nightly doc --locked --workspace --all-features --verbose --no-deps - rm -f $CARGO_TARGET_DIR/doc/.lock - mv $CARGO_TARGET_DIR/doc ./crate-docs # FIXME: remove me after CI image gets nonroot diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 7be445b0bca98..bbe38cfb02293 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -83,14 +83,14 @@ cargo-check-benches: - echo "___Running benchmarks___"; - case ${CI_NODE_INDEX} in 1) - SKIP_WASM_BUILD=1 time cargo +nightly check --benches --all; - cargo run --release -p node-bench -- ::trie::read::small --json + SKIP_WASM_BUILD=1 time cargo +nightly check --locked --benches --all; + cargo run --locked --release -p node-bench -- ::trie::read::small --json | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json; echo "___Uploading cache for rusty-cachier___"; rusty-cachier cache upload ;; 2) - cargo run --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json + cargo run --locked --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::native::sr25519::transfer_keep_alive::paritydb::small.json ;; esac @@ -140,7 +140,7 @@ cargo-check-subkey: script: - rusty-cachier snapshot create - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo check --release + - SKIP_WASM_BUILD=1 time cargo check --locked --release - rusty-cachier cache upload cargo-check-try-runtime: @@ -154,7 +154,7 @@ cargo-check-try-runtime: - .test-refs script: - rusty-cachier snapshot create - - time cargo check --features try-runtime + - time cargo check --locked --features try-runtime - rusty-cachier cache upload cargo-check-wasmer-sandbox: @@ -168,7 +168,7 @@ cargo-check-wasmer-sandbox: - .test-refs script: - rusty-cachier snapshot create - - time cargo check --features wasmer-sandbox + - time cargo check --locked --features wasmer-sandbox - rusty-cachier cache upload test-deterministic-wasm: @@ -187,13 +187,13 @@ test-deterministic-wasm: script: - rusty-cachier snapshot create # build runtime - - cargo build --verbose --release -p kitchensink-runtime + - cargo build --locked --verbose --release -p kitchensink-runtime # make checksum - sha256sum $CARGO_TARGET_DIR/release/wbuild/kitchensink-runtime/target/wasm32-unknown-unknown/release/kitchensink_runtime.wasm > checksum.sha256 # clean up - rm -rf $CARGO_TARGET_DIR/release/wbuild # build again - - cargo build --verbose --release -p kitchensink-runtime + - cargo build --locked --verbose --release -p kitchensink-runtime # confirm checksum - sha256sum -c ./checksum.sha256 # clean up again, don't put release binaries into the cache @@ -251,7 +251,7 @@ test-frame-support: RUN_UI_TESTS: 1 script: - rusty-cachier snapshot create - - time cargo test -p frame-support-test --features=frame-feature-testing,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec + - time cargo test --locked -p frame-support-test --features=frame-feature-testing,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout - rusty-cachier cache upload @@ -295,7 +295,7 @@ quick-benchmarks: WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - rusty-cachier snapshot create - - time cargo run --release --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 + - time cargo run --locked --release --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 - rusty-cachier cache upload test-frame-examples-compile-to-wasm: @@ -314,9 +314,9 @@ test-frame-examples-compile-to-wasm: script: - rusty-cachier snapshot create - cd ./frame/examples/offchain-worker/ - - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features + - cargo +nightly build --locked --target=wasm32-unknown-unknown --no-default-features - cd ../basic - - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features + - cargo +nightly build --locked --target=wasm32-unknown-unknown --no-default-features - rusty-cachier cache upload test-linux-stable-int: @@ -358,8 +358,8 @@ check-tracing: script: - rusty-cachier snapshot create # with-tracing must be explicitly activated, we run a test to ensure this works as expected in both cases - - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features - - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing + - time cargo +nightly test --locked --manifest-path ./primitives/tracing/Cargo.toml --no-default-features + - time cargo +nightly test --locked --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing - rusty-cachier cache upload # more information about this job can be found here: @@ -383,9 +383,9 @@ test-full-crypto-feature: script: - rusty-cachier snapshot create - cd primitives/core/ - - time cargo +nightly build --verbose --no-default-features --features full_crypto + - time cargo +nightly build --locked --verbose --no-default-features --features full_crypto - cd ../application-crypto - - time cargo +nightly build --verbose --no-default-features --features full_crypto + - time cargo +nightly build --locked --verbose --no-default-features --features full_crypto - rusty-cachier cache upload test-wasmer-sandbox: @@ -399,7 +399,7 @@ test-wasmer-sandbox: script: - rusty-cachier snapshot create - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" - - time cargo nextest run --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} + - time cargo nextest run --locked --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} - if [ ${CI_NODE_INDEX} == 1 ]; then rusty-cachier cache upload; fi cargo-check-macos: @@ -408,7 +408,7 @@ cargo-check-macos: before_script: - !reference [.rust-info-script, script] script: - - SKIP_WASM_BUILD=1 time cargo check --release + - SKIP_WASM_BUILD=1 time cargo check --locked --release tags: - osx @@ -424,5 +424,5 @@ check-rustdoc: RUSTDOCFLAGS: "-Dwarnings" script: - rusty-cachier snapshot create - - time cargo +nightly doc --workspace --all-features --verbose --no-deps + - time cargo +nightly doc --locked --workspace --all-features --verbose --no-deps - rusty-cachier cache upload From 8bd5510971a8fba46a7b1a6ead8254b9cbf0a73f Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 15 Sep 2022 17:12:55 +0200 Subject: [PATCH 1166/1472] Replace 'blake2-rfc' with rust-crypto 'blake2' crate (#12266) * Replace 'blake2-rfc with rust-crypto 'blake2' crate * Bump blake2 to 0.10.4 --- Cargo.lock | 6 ++--- primitives/api/proc-macro/Cargo.toml | 2 +- primitives/core/Cargo.toml | 6 ++--- primitives/core/hashing/Cargo.toml | 2 +- primitives/core/src/crypto.rs | 36 ++++++++++++++++++++-------- 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 367713b9361ba..8216b8b92aef5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -593,9 +593,9 @@ dependencies = [ [[package]] name = "blake2" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94ba84325db59637ffc528bbe8c7f86c02c57cff5c0e2b9b00f9a851f42f309" +checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" dependencies = [ "digest 0.10.3", ] @@ -9751,7 +9751,7 @@ version = "6.0.0" dependencies = [ "base58", "bitflags", - "blake2-rfc", + "blake2", "byteorder", "criterion", "dyn-clonable", diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index 0a57be8d7a300..8acc15d6a0591 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true quote = "1.0.10" syn = { version = "1.0.98", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.37" -blake2 = { version = "0.10.2", default-features = false } +blake2 = { version = "0.10.4", default-features = false } proc-macro-crate = "1.1.3" # Required for the doc tests diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index b611449b6730f..2233a3443447c 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -48,7 +48,7 @@ bitflags = "1.3" # full crypto ed25519-zebra = { version = "3.0.0", default-features = false, optional = true} -blake2-rfc = { version = "0.2.18", default-features = false, optional = true } +blake2 = { version = "0.10.4", default-features = false, optional = true } schnorrkel = { version = "0.9.1", features = [ "preaudit_deprecated", "u64_backend", @@ -98,7 +98,7 @@ std = [ "hash-db/std", "sp-std/std", "serde", - "blake2-rfc/std", + "blake2/std", "ed25519-zebra", "hex/std", "base58", @@ -130,7 +130,7 @@ std = [ # For the regular wasm runtime builds this should not be used. full_crypto = [ "ed25519-zebra", - "blake2-rfc", + "blake2", "schnorrkel", "hex", "libsecp256k1", diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index d6fc6bed31fec..efe38af1602dd 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -13,7 +13,7 @@ documentation = "https://docs.rs/sp-core-hashing" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -blake2 = { version = "0.10.2", default-features = false } +blake2 = { version = "0.10.4", default-features = false } byteorder = { version = "1.3.2", default-features = false } digest = { version = "0.10.3", default-features = false } sha2 = { version = "0.10.2", default-features = false } diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 80b44449dbac1..377ae480edd17 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -132,9 +132,7 @@ impl DeriveJunction { let mut cc: [u8; JUNCTION_ID_LEN] = Default::default(); index.using_encoded(|data| { if data.len() > JUNCTION_ID_LEN { - let hash_result = blake2_rfc::blake2b::blake2b(JUNCTION_ID_LEN, &[], data); - let hash = hash_result.as_bytes(); - cc.copy_from_slice(hash); + cc.copy_from_slice(&sp_core_hashing::blake2_256(data)); } else { cc[0..data.len()].copy_from_slice(data); } @@ -292,7 +290,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray { } let hash = ss58hash(&data[0..body_len + prefix_len]); - let checksum = &hash.as_bytes()[0..CHECKSUM_LEN]; + let checksum = &hash[0..CHECKSUM_LEN]; if data[body_len + prefix_len..body_len + prefix_len + CHECKSUM_LEN] != *checksum { // Invalid checksum. return Err(PublicError::InvalidChecksum) @@ -333,7 +331,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray { }; v.extend(self.as_ref()); let r = ss58hash(&v); - v.extend(&r.as_bytes()[0..2]); + v.extend(&r[0..2]); v.to_base58() } @@ -366,11 +364,13 @@ pub trait Derive: Sized { const PREFIX: &[u8] = b"SS58PRE"; #[cfg(feature = "std")] -fn ss58hash(data: &[u8]) -> blake2_rfc::blake2b::Blake2bResult { - let mut context = blake2_rfc::blake2b::Blake2b::new(64); - context.update(PREFIX); - context.update(data); - context.finalize() +fn ss58hash(data: &[u8]) -> Vec { + use blake2::{Blake2b512, Digest}; + + let mut ctx = Blake2b512::new(); + ctx.update(PREFIX); + ctx.update(data); + ctx.finalize().to_vec() } /// Default prefix number @@ -1311,6 +1311,14 @@ mod tests { path: vec![DeriveJunction::soft("DOT")] }) ); + assert_eq!( + TestPair::from_string("hello world/0123456789012345678901234567890123456789", None), + Ok(TestPair::Standard { + phrase: "hello world".to_owned(), + password: None, + path: vec![DeriveJunction::soft("0123456789012345678901234567890123456789")] + }) + ); assert_eq!( TestPair::from_string("hello world//1", None), Ok(TestPair::Standard { @@ -1327,6 +1335,14 @@ mod tests { path: vec![DeriveJunction::hard("DOT")] }) ); + assert_eq!( + TestPair::from_string("hello world//0123456789012345678901234567890123456789", None), + Ok(TestPair::Standard { + phrase: "hello world".to_owned(), + password: None, + path: vec![DeriveJunction::hard("0123456789012345678901234567890123456789")] + }) + ); assert_eq!( TestPair::from_string("hello world//1/DOT", None), Ok(TestPair::Standard { From 21adbaf88fc3d1a216ab71d19acedd348c74ad15 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 15 Sep 2022 18:59:06 +0100 Subject: [PATCH 1167/1472] Expose tracks as a constant. (#12273) * Expose tracks as a constant. * Formatting --- bin/node/runtime/src/lib.rs | 1 + frame/referenda/src/lib.rs | 42 +++++++++++++++++++++++++++++++------ frame/referenda/src/mock.rs | 1 + 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 2f0efcaa56740..1e476f358876c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -828,6 +828,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { } } } +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); impl pallet_referenda::Config for Runtime { type WeightInfo = pallet_referenda::weights::SubstrateWeight; diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 92e5ecf5e539b..a2a5aae4e617b 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -72,7 +72,7 @@ use frame_support::{ v2::{Anon as ScheduleAnon, Named as ScheduleNamed}, DispatchTime, MaybeHashed, }, - Currency, Get, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, + Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, ReservableCurrency, VoteTally, }, BoundedVec, @@ -108,6 +108,30 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; +pub use frame_support::traits::Get; +pub use sp_std::vec::Vec; + +#[macro_export] +macro_rules! impl_tracksinfo_get { + ($tracksinfo:ty, $balance:ty, $blocknumber:ty) => { + impl + $crate::Get< + $crate::Vec<( + <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::Id, + $crate::TrackInfo<$balance, $blocknumber>, + )>, + > for $tracksinfo + { + fn get() -> $crate::Vec<( + <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::Id, + $crate::TrackInfo<$balance, $blocknumber>, + )> { + <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::tracks().to_vec() + } + } + }; +} + const ASSEMBLY_ID: LockIdentifier = *b"assembly"; #[frame_support::pallet] @@ -184,11 +208,17 @@ pub mod pallet { // The other stuff. /// Information concerning the different referendum tracks. - type Tracks: TracksInfo< - BalanceOf, - Self::BlockNumber, - Origin = ::PalletsOrigin, - >; + #[pallet::constant] + type Tracks: Get< + Vec<( + , Self::BlockNumber>>::Id, + TrackInfo, Self::BlockNumber>, + )>, + > + TracksInfo< + BalanceOf, + Self::BlockNumber, + Origin = ::PalletsOrigin, + >; } /// The next free referendum index, aka the number of referenda started so far. diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index e046b29898e7b..70ca304eed3cb 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -210,6 +210,7 @@ impl TracksInfo for TestTracksInfo { } } } +impl_tracksinfo_get!(TestTracksInfo, u64, u64); impl Config for Test { type WeightInfo = (); From d65f4bbdf1d34ae228fbad444951176278a03d05 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 16 Sep 2022 10:50:21 +0300 Subject: [PATCH 1168/1472] client/beefy: fix voter initialization (#12274) Fix corner case where voter gets a single burst of finality notifications just when it starts. The notification stream was consumed by "wait_for_pallet" logic, then main loop would subscribe to finality notifications, but by that time some notifications might've been lost. Fix this by subscribing the main loop to notifications before waiting for pallet to become available. Share the same stream with the main loop so that notifications for blocks before pallet available are ignored, while _all_ notifications after pallet available are processed. Add regression test for this. Signed-off-by: acatangiu --- client/beefy/src/tests.rs | 34 ++++++++++++++++++++++++++++++++++ client/beefy/src/worker.rs | 15 ++++++++------- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index e8d32fe3e8127..e0058e5238d6a 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -811,3 +811,37 @@ fn beefy_importing_blocks() { })); } } + +#[test] +fn voter_initialization() { + sp_tracing::try_init_simple(); + // Regression test for voter initialization where finality notifications were dropped + // after waiting for BEEFY pallet availability. + + let mut runtime = Runtime::new().unwrap(); + let peers = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let session_len = 5; + // Should vote on all mandatory blocks no matter the `min_block_delta`. + let min_block_delta = 10; + + let mut net = BeefyTestNet::new(2, 0); + let api = Arc::new(two_validators::TestApi {}); + let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); + runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); + + // push 30 blocks + net.generate_blocks_and_sync(26, session_len, &validator_set, false); + let net = Arc::new(Mutex::new(net)); + + // Finalize multiple blocks at once to get a burst of finality notifications right from start. + // Need to finalize at least one block in each session, choose randomly. + // Expect voters to pick up all of them and BEEFY-finalize the mandatory blocks of each session. + finalize_block_and_wait_for_beefy( + &net, + peers, + &mut runtime, + &[1, 6, 10, 17, 24, 26], + &[1, 5, 10, 15, 20, 25], + ); +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 9f54a300472de..6e8c89d804984 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -24,10 +24,10 @@ use std::{ }; use codec::{Codec, Decode, Encode}; -use futures::StreamExt; +use futures::{stream::Fuse, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn}; -use sc_client_api::{Backend, FinalityNotification, HeaderBackend}; +use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; use sc_network_gossip::GossipEngine; use sp_api::{BlockId, ProvideRuntimeApi}; @@ -723,12 +723,11 @@ where /// Wait for BEEFY runtime pallet to be available. /// Should be called only once during worker initialization. - async fn wait_for_runtime_pallet(&mut self) { + async fn wait_for_runtime_pallet(&mut self, finality: &mut Fuse>) { let mut gossip_engine = &mut self.gossip_engine; - let mut finality_stream = self.client.finality_notification_stream().fuse(); loop { futures::select! { - notif = finality_stream.next() => { + notif = finality.next() => { let notif = match notif { Some(notif) => notif, None => break @@ -762,11 +761,13 @@ where pub(crate) async fn run(mut self) { info!(target: "beefy", "🥩 run BEEFY worker, best grandpa: #{:?}.", self.best_grandpa_block_header.number()); let mut block_import_justif = self.links.from_block_import_justif_stream.subscribe().fuse(); + // Subscribe to finality notifications before waiting for runtime pallet and reuse stream, + // so we process notifications for all finalized blocks after pallet is available. + let mut finality_notifications = self.client.finality_notification_stream().fuse(); - self.wait_for_runtime_pallet().await; + self.wait_for_runtime_pallet(&mut finality_notifications).await; trace!(target: "beefy", "🥩 BEEFY pallet available, starting voter."); - let mut finality_notifications = self.client.finality_notification_stream().fuse(); let mut votes = Box::pin( self.gossip_engine .messages_for(topic::()) From 7202ca616799a1d78e37ae8ec0093f16c49417c6 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 16 Sep 2022 16:16:37 +0200 Subject: [PATCH 1169/1472] Fix warp sync (#12281) --- client/consensus/aura/src/import_queue.rs | 19 ++++++------ client/consensus/babe/src/lib.rs | 34 +++++++++++---------- client/consensus/common/src/block_import.rs | 12 ++++++++ client/consensus/pow/src/lib.rs | 20 ++++++------ 4 files changed, 51 insertions(+), 34 deletions(-) diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 31fe7bbaa1095..90f15fef1b34b 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -225,15 +225,16 @@ where inherent_data.aura_replace_inherent_data(slot); - // skip the inherents verification if the runtime API is old. - if self - .client - .runtime_api() - .has_api_with::, _>( - &BlockId::Hash(parent_hash), - |v| v >= 2, - ) - .map_err(|e| e.to_string())? + // skip the inherents verification if the runtime API is old or not expected to + // exist. + if !block.state_action.skip_execution_checks() && + self.client + .runtime_api() + .has_api_with::, _>( + &BlockId::Hash(parent_hash), + |v| v >= 2, + ) + .map_err(|e| e.to_string())? { self.check_inherents( new_block.clone(), diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 198de865bb290..eca6654f6e4dc 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1237,24 +1237,26 @@ where warn!(target: "babe", "Error checking/reporting BABE equivocation: {}", err); } - // if the body is passed through, we need to use the runtime - // to check that the internally-set timestamp in the inherents - // actually matches the slot set in the seal. if let Some(inner_body) = block.body { - let mut inherent_data = create_inherent_data_providers - .create_inherent_data() - .map_err(Error::::CreateInherents)?; - inherent_data.babe_replace_inherent_data(slot); let new_block = Block::new(pre_header.clone(), inner_body); - - self.check_inherents( - new_block.clone(), - BlockId::Hash(parent_hash), - inherent_data, - create_inherent_data_providers, - block.origin.into(), - ) - .await?; + if !block.state_action.skip_execution_checks() { + // if the body is passed through and the block was executed, + // we need to use the runtime to check that the internally-set + // timestamp in the inherents actually matches the slot set in the seal. + let mut inherent_data = create_inherent_data_providers + .create_inherent_data() + .map_err(Error::::CreateInherents)?; + inherent_data.babe_replace_inherent_data(slot); + + self.check_inherents( + new_block.clone(), + BlockId::Hash(parent_hash), + inherent_data, + create_inherent_data_providers, + block.origin.into(), + ) + .await?; + } let (_, inner_body) = new_block.deconstruct(); block.body = Some(inner_body); diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index 10739f63ef779..b8fc815cc5c5c 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -153,6 +153,18 @@ pub enum StateAction { Skip, } +impl StateAction { + /// Check if execution checks that require runtime calls should be skipped. + pub fn skip_execution_checks(&self) -> bool { + match self { + StateAction::ApplyChanges(_) | + StateAction::Execute | + StateAction::ExecuteIfPossible => false, + StateAction::Skip => true, + } + } +} + /// Data required to import a Block. #[non_exhaustive] pub struct BlockImportParams { diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 6c492931d445c..9b3ef501d2396 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -341,15 +341,17 @@ where if let Some(inner_body) = block.body.take() { let check_block = B::new(block.header.clone(), inner_body); - self.check_inherents( - check_block.clone(), - BlockId::Hash(parent_hash), - self.create_inherent_data_providers - .create_inherent_data_providers(parent_hash, ()) - .await?, - block.origin.into(), - ) - .await?; + if !block.state_action.skip_execution_checks() { + self.check_inherents( + check_block.clone(), + BlockId::Hash(parent_hash), + self.create_inherent_data_providers + .create_inherent_data_providers(parent_hash, ()) + .await?, + block.origin.into(), + ) + .await?; + } block.body = Some(check_block.deconstruct().1); } From 4d04aba0f864b62532cac6d39ac373812eeea3dc Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 16 Sep 2022 17:45:44 -0400 Subject: [PATCH 1170/1472] Add special tag to exclude runtime storage items from benchmarking (#12205) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial setup * add WhitelistedStorageKeys trait * add (A, B) tuple implementation for whitelisted_storage_keys() * fix formatting * implement WhitelistedStorageKeys for all tuple combinations * impl_for_tuples up to 128 for WhitelistedStorageKeys * refactor to #[benchmarking(cached)] * tweak error message and mark BlockNumber as cached * add benchmarking(cached) to the other default types * add docs for benchmarking(cached) * properly parse storage type declaration * make storage_alias structs public so we can use them in this macro * use BTreeMap since TrackedStorageKey missing Ord outside of std * make WhitelistedStorageKeys accessible * basic detection of benchmarking(cached) :boom: * proper parsing of #[benchmarking(cached)] from pallet parse macro * store presence of #[benchmarking(cached)] macro on StorageDef * will be used for later expansion * compiling blank impl for WhitelistedStorageKeys * move impl to expand_pallet_struct * use frame_support::sp_std::vec::Vec properly * successfully compiling with storage info loaded into a variable :boom: * plausible implementation for whitelisted_storage_keys() * depends on the assumption that storage_info.encode() can be loaded into TrackedStorageKey::new(..) * use Pallet::whitelisted_storage_keys() instead of hard-coded list * AllPallets::whitelisted_storage_keys() properly working :boom: * collect storage names * whitelisted_storage_keys() impl working :boom: * clean up * fix compiler error * just one compiler error * fix doc compiler error * use better import path * fix comment * whoops * whoops again * fix macro import issue * cargo fmt * mark example as ignore * use keyword tokens instead of string parsing * fix keyword-based parsing of benchmarking(cached) * preliminary spec for check_whitelist() * add additional test for benchmarking whitelist * add TODO note * remove irrelevant line from example * use filter_map instead of filter and map * simplify syntax Co-authored-by: Keith Yeung * clean up * fix test * fix tests * use keyword parsing instead of string parsing * use collect() instead of a for loop Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fix compiler error * clean up benchmarking(cached) marking code * use cloned() * refactor to not use panic! and remove need for pub types in storage_alias * remove unneeded use Co-authored-by: Bastian Köcher * remove unneeded visibility changes * don't manually hard code hash for treasury account as hex * proper Ord, PartialOrd, and Hash impls for TrackedStorageKey * now based just on key, and available in no-std * use BTreeSet instead of BTreeMap * fix comments * cargo fmt * switch to pallet::whitelist and re-do it basti's way :D * make PartialOrd for TrackedStorageKey consistent with Ord * more correct implementation of hash-related traits for TrackedStorageKey * fix integration test * update TODO * remove unused keyword * remove more unused keywords * use into_iter() Co-authored-by: Keith Yeung * Update frame/support/procedural/src/pallet/parse/mod.rs Co-authored-by: Bastian Köcher * add docs for whitelisted * fix comment Co-authored-by: Keith Yeung Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Bastian Köcher --- bin/node-template/runtime/src/lib.rs | 51 ++++++++++++---- bin/node/runtime/src/lib.rs | 60 ++++++++++++++----- frame/balances/src/lib.rs | 1 + .../src/pallet/expand/pallet_struct.rs | 19 ++++++ .../procedural/src/pallet/parse/storage.rs | 21 ++++++- frame/support/procedural/src/storage/mod.rs | 1 + frame/support/src/lib.rs | 15 +++++ frame/support/src/traits.rs | 1 + frame/support/src/traits/storage.rs | 28 +++++++++ .../storage_invalid_attribute.stderr | 2 +- frame/system/src/lib.rs | 5 ++ primitives/storage/src/lib.rs | 5 +- 12 files changed, 175 insertions(+), 34 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 099654a12a420..c309b27682080 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -521,18 +521,8 @@ impl_runtime_apis! { impl frame_system_benchmarking::Config for Runtime {} impl baseline::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(), - ]; + use frame_support::traits::WhitelistedStorageKeys; + let whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); let mut batches = Vec::::new(); let params = (&config, &whitelist); @@ -563,3 +553,40 @@ impl_runtime_apis! { } } } + +#[cfg(test)] +mod tests { + use super::*; + use frame_support::traits::WhitelistedStorageKeys; + use sp_core::hexdisplay::HexDisplay; + use std::collections::HashSet; + + #[test] + fn check_whitelist() { + let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys() + .iter() + .map(|e| HexDisplay::from(&e.key).to_string()) + .collect(); + + // Block Number + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac") + ); + // Total Issuance + assert!( + whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80") + ); + // Execution Phase + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a") + ); + // Event Count + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850") + ); + // System Events + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7") + ); + } +} diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1e476f358876c..1b0d12f8530a2 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2148,22 +2148,14 @@ impl_runtime_apis! { impl baseline::Config for Runtime {} impl pallet_nomination_pools_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(), - // System BlockWeight - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96").to_vec().into(), - // Treasury Account - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95ecffd7b6c0f78751baa9d281e0bfa3a6d6f646c70792f74727372790000000000000000000000000000000000000000").to_vec().into(), - ]; + use frame_support::traits::WhitelistedStorageKeys; + let mut whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); + + // Treasury Account + // TODO: this is manual for now, someday we might be able to use a + // macro for this particular key + let treasury_key = frame_system::Account::::hashed_key_for(Treasury::account_id()); + whitelist.push(treasury_key.to_vec().into()); let mut batches = Vec::::new(); let params = (&config, &whitelist); @@ -2177,8 +2169,44 @@ impl_runtime_apis! { mod tests { use super::*; use frame_election_provider_support::NposSolution; + use frame_support::traits::WhitelistedStorageKeys; use frame_system::offchain::CreateSignedTransaction; + use sp_core::hexdisplay::HexDisplay; use sp_runtime::UpperOf; + use std::collections::HashSet; + + #[test] + fn check_whitelist() { + let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys() + .iter() + .map(|e| HexDisplay::from(&e.key).to_string()) + .collect(); + + // Block Number + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac") + ); + // Total Issuance + assert!( + whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80") + ); + // Execution Phase + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a") + ); + // Event Count + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850") + ); + // System Events + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7") + ); + // System BlockWeight + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96") + ); + } #[test] fn validate_transaction_submitter_bounds() { diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index e425381172dab..82d6f87dbde1a 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -493,6 +493,7 @@ pub mod pallet { /// The total units issued in the system. #[pallet::storage] #[pallet::getter(fn total_issuance)] + #[pallet::whitelist_storage] pub type TotalIssuance, I: 'static = ()> = StorageValue<_, T::Balance, ValueQuery>; /// The Balances pallet example of storing the balance of an account. diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index f0fb6bacedffb..e5941a33fee13 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -166,6 +166,24 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { quote::quote! { #frame_support::traits::StorageVersion::default() } }; + let whitelisted_storage_idents: Vec = def + .storages + .iter() + .filter_map(|s| s.whitelisted.then_some(s.ident.clone())) + .collect(); + + let whitelisted_storage_keys_impl = quote::quote![ + use #frame_support::traits::{StorageInfoTrait, TrackedStorageKey, WhitelistedStorageKeys}; + impl<#type_impl_gen> WhitelistedStorageKeys for #pallet_ident<#type_use_gen> #storages_where_clauses { + fn whitelisted_storage_keys() -> #frame_support::sp_std::vec::Vec { + use #frame_support::sp_std::vec; + vec![#( + TrackedStorageKey::new(#whitelisted_storage_idents::<#type_use_gen>::hashed_key().to_vec()) + ),*] + } + } + ]; + quote::quote_spanned!(def.pallet_struct.attr_span => #pallet_error_metadata @@ -253,5 +271,6 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { } #storage_info + #whitelisted_storage_keys_impl ) } diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index f0e1353774910..321c4dd5d4914 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -28,6 +28,7 @@ mod keyword { syn::custom_keyword!(getter); syn::custom_keyword!(storage_prefix); syn::custom_keyword!(unbounded); + syn::custom_keyword!(whitelist_storage); syn::custom_keyword!(OptionQuery); syn::custom_keyword!(ResultQuery); syn::custom_keyword!(ValueQuery); @@ -37,16 +38,21 @@ mod keyword { /// * `#[pallet::getter(fn dummy)]` /// * `#[pallet::storage_prefix = "CustomName"]` /// * `#[pallet::unbounded]` +/// * `#[pallet::whitelist_storage] pub enum PalletStorageAttr { Getter(syn::Ident, proc_macro2::Span), StorageName(syn::LitStr, proc_macro2::Span), Unbounded(proc_macro2::Span), + WhitelistStorage(proc_macro2::Span), } impl PalletStorageAttr { fn attr_span(&self) -> proc_macro2::Span { match self { - Self::Getter(_, span) | Self::StorageName(_, span) | Self::Unbounded(span) => *span, + Self::Getter(_, span) | + Self::StorageName(_, span) | + Self::Unbounded(span) | + Self::WhitelistStorage(span) => *span, } } } @@ -84,6 +90,9 @@ impl syn::parse::Parse for PalletStorageAttr { content.parse::()?; Ok(Self::Unbounded(attr_span)) + } else if lookahead.peek(keyword::whitelist_storage) { + content.parse::()?; + Ok(Self::WhitelistStorage(attr_span)) } else { Err(lookahead.error()) } @@ -94,6 +103,7 @@ struct PalletStorageAttrInfo { getter: Option, rename_as: Option, unbounded: bool, + whitelisted: bool, } impl PalletStorageAttrInfo { @@ -101,12 +111,14 @@ impl PalletStorageAttrInfo { let mut getter = None; let mut rename_as = None; let mut unbounded = false; + let mut whitelisted = false; for attr in attrs { match attr { PalletStorageAttr::Getter(ident, ..) if getter.is_none() => getter = Some(ident), PalletStorageAttr::StorageName(name, ..) if rename_as.is_none() => rename_as = Some(name), PalletStorageAttr::Unbounded(..) if !unbounded => unbounded = true, + PalletStorageAttr::WhitelistStorage(..) if !whitelisted => whitelisted = true, attr => return Err(syn::Error::new( attr.attr_span(), @@ -115,7 +127,7 @@ impl PalletStorageAttrInfo { } } - Ok(PalletStorageAttrInfo { getter, rename_as, unbounded }) + Ok(PalletStorageAttrInfo { getter, rename_as, unbounded, whitelisted }) } } @@ -171,6 +183,8 @@ pub struct StorageDef { pub named_generics: Option, /// If the value stored in this storage is unbounded. pub unbounded: bool, + /// Whether or not reads to this storage key will be ignored by benchmarking + pub whitelisted: bool, } /// The parsed generic from the @@ -672,7 +686,7 @@ impl StorageDef { }; let attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; - let PalletStorageAttrInfo { getter, rename_as, unbounded } = + let PalletStorageAttrInfo { getter, rename_as, unbounded, whitelisted } = PalletStorageAttrInfo::from_attrs(attrs)?; let cfg_attrs = helper::get_item_cfg_attrs(&item.attrs); @@ -814,6 +828,7 @@ impl StorageDef { cfg_attrs, named_generics, unbounded, + whitelisted, }) } } diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 756653f7ba85d..e8e2d7529cb3f 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -32,6 +32,7 @@ pub(crate) use instance_trait::INHERENT_INSTANCE_NAME; use frame_support_procedural_tools::{ generate_crate_access, generate_hidden_includes, syn_ext as ext, }; + use quote::quote; /// All information contained in input of decl_storage diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 8dcc51226923b..e9578cccc23bc 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1858,6 +1858,21 @@ pub mod pallet_prelude { /// pub(super) type MyStorage = StorageValue; /// ``` /// +/// The optional attribute `#[pallet::whitelist_storage]` will declare the +/// storage as whitelisted from benchmarking. Doing so will exclude reads of +/// that value's storage key from counting towards weight calculations during +/// benchmarking. +/// +/// This attribute should only be attached to storages that are known to be +/// read/used in every block. This will result in a more accurate benchmarking weight. +/// +/// ### Example +/// ```ignore +/// #[pallet::storage] +/// #[pallet::whitelist_storage] +/// pub(super) type Number = StorageValue<_, T::BlockNumber, ValueQuery>; +/// ``` +/// /// All the `cfg` attributes are automatically copied to the items generated for the storage, /// i.e. the getter, storage prefix, and the metadata element etc. /// diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index d4f0e73557c77..16ac7929831b4 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -89,6 +89,7 @@ pub mod schedule; mod storage; pub use storage::{ Instance, PartialStorageInfoTrait, StorageInfo, StorageInfoTrait, StorageInstance, + TrackedStorageKey, WhitelistedStorageKeys, }; mod dispatch; diff --git a/frame/support/src/traits/storage.rs b/frame/support/src/traits/storage.rs index d40d82c28e87e..24653d1899836 100644 --- a/frame/support/src/traits/storage.rs +++ b/frame/support/src/traits/storage.rs @@ -17,7 +17,9 @@ //! Traits for encoding data related to pallet's storage items. +use crate::sp_std::collections::btree_set::BTreeSet; use impl_trait_for_tuples::impl_for_tuples; +pub use sp_core::storage::TrackedStorageKey; use sp_std::prelude::*; /// An instance of a pallet in the storage. @@ -90,3 +92,29 @@ impl StorageInfoTrait for Tuple { pub trait PartialStorageInfoTrait { fn partial_storage_info() -> Vec; } + +/// Allows a pallet to specify storage keys to whitelist during benchmarking. +/// This means those keys will be excluded from the benchmarking performance +/// calculation. +pub trait WhitelistedStorageKeys { + /// Returns a [`Vec`] indicating the storage keys that + /// should be whitelisted during benchmarking. This means that those keys + /// will be excluded from the benchmarking performance calculation. + fn whitelisted_storage_keys() -> Vec; +} + +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] +impl WhitelistedStorageKeys for Tuple { + fn whitelisted_storage_keys() -> Vec { + // de-duplicate the storage keys + let mut combined_keys: BTreeSet = BTreeSet::new(); + for_tuples!( #( + for storage_key in Tuple::whitelisted_storage_keys() { + combined_keys.insert(storage_key); + } + )* ); + combined_keys.into_iter().collect::>() + } +} diff --git a/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr b/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr index 6313bd691f943..80c6526bbf888 100644 --- a/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr +++ b/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr @@ -1,4 +1,4 @@ -error: expected one of: `getter`, `storage_prefix`, `unbounded` +error: expected one of: `getter`, `storage_prefix`, `unbounded`, `whitelist_storage` --> $DIR/storage_invalid_attribute.rs:16:12 | 16 | #[pallet::generate_store(pub trait Store)] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 739dcadde9ac1..f60e3e7349d6b 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -562,6 +562,7 @@ pub mod pallet { /// The current weight for the block. #[pallet::storage] + #[pallet::whitelist_storage] #[pallet::getter(fn block_weight)] pub(super) type BlockWeight = StorageValue<_, ConsumedWeight, ValueQuery>; @@ -584,6 +585,7 @@ pub mod pallet { /// The current block number being processed. Set by `execute_block`. #[pallet::storage] + #[pallet::whitelist_storage] #[pallet::getter(fn block_number)] pub(super) type Number = StorageValue<_, T::BlockNumber, ValueQuery>; @@ -606,12 +608,14 @@ pub mod pallet { /// Events have a large in-memory size. Box the events to not go out-of-memory /// just in case someone still reads them from within the runtime. #[pallet::storage] + #[pallet::whitelist_storage] #[pallet::unbounded] pub(super) type Events = StorageValue<_, Vec>>, ValueQuery>; /// The number of events in the `Events` list. #[pallet::storage] + #[pallet::whitelist_storage] #[pallet::getter(fn event_count)] pub(super) type EventCount = StorageValue<_, EventIndex, ValueQuery>; @@ -647,6 +651,7 @@ pub mod pallet { /// The execution phase of the block. #[pallet::storage] + #[pallet::whitelist_storage] pub(super) type ExecutionPhase = StorageValue<_, Phase>; #[cfg_attr(feature = "std", derive(Default))] diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index 0948cf431158d..9c046bf9d2dd1 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -47,8 +47,9 @@ impl AsRef<[u8]> for StorageKey { } /// Storage key with read/write tracking information. -#[derive(PartialEq, Eq, RuntimeDebug, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Hash, PartialOrd, Ord))] +#[derive( + PartialEq, Eq, Ord, PartialOrd, sp_std::hash::Hash, RuntimeDebug, Clone, Encode, Decode, +)] pub struct TrackedStorageKey { pub key: Vec, pub reads: u32, From 03eb807e4e8efa9d0f94f36f528caf4fc92ccffb Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Sun, 18 Sep 2022 11:28:16 +0200 Subject: [PATCH 1171/1472] [Feature] Part 1: add TargetList for validator ranking (#12034) * [Feature] Part 1: add TargetList for validator ranking * remove redundant todo * remove typo * cleanup * implement score * more fixes * fix thresholds * fmt * Remove the stuff that has to come in the next PR, some fixes * extended balance import * Change all the references from VoteWeight to Self::Score * Add a migration for VoterBagsList * fix score * add targetList to nomination-pools tests * fix bench * address review comments * change get_npos_targets * address more comments * remove thresholds for the time being * fix instance reference * VoterBagsListInstance * reus * remove params that are not used yet * Introduced pre/post upgrade try-runtime checks * fix * fixes * fix migration * fix migration * fix post_upgrade * change * Fix * eloquent PhantomData * fix PD * more fixes * Update frame/staking/src/pallet/impls.rs Co-authored-by: Squirrel * is_nominator now works * fix test-staking * build fixes * fix remote-tests * Apply suggestions from code review Co-authored-by: parity-processbot <> Co-authored-by: kianenigma Co-authored-by: Squirrel Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- bin/node/runtime/src/lib.rs | 15 ++- bin/node/runtime/src/voter_bags.rs | 9 +- frame/babe/src/mock.rs | 1 + frame/bags-list/remote-tests/src/lib.rs | 33 +++++-- frame/bags-list/remote-tests/src/migration.rs | 5 +- frame/bags-list/remote-tests/src/snapshot.rs | 8 +- frame/bags-list/remote-tests/src/try_state.rs | 10 +- frame/grandpa/src/mock.rs | 1 + .../nomination-pools/benchmarking/src/lib.rs | 5 +- .../nomination-pools/benchmarking/src/mock.rs | 8 +- .../nomination-pools/test-staking/src/mock.rs | 8 +- frame/offences/benchmarking/src/mock.rs | 1 + frame/session/benchmarking/src/mock.rs | 1 + frame/staking/src/benchmarking.rs | 2 +- frame/staking/src/lib.rs | 3 +- frame/staking/src/migrations.rs | 93 +++++++++++++++++ frame/staking/src/mock.rs | 9 +- frame/staking/src/pallet/impls.rs | 99 ++++++++++++++++--- frame/staking/src/pallet/mod.rs | 28 ++++++ utils/frame/generate-bags/src/lib.rs | 15 +++ 20 files changed, 307 insertions(+), 47 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1b0d12f8530a2..b5467aa6f8ea7 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -568,7 +568,9 @@ impl pallet_staking::Config for Runtime { type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::UnboundedExecution; - type VoterList = BagsList; + type VoterList = VoterBagsList; + // This a placeholder, to be introduced in the next PR as an instance of bags-list + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type OnStakerSlash = NominationPools; type WeightInfo = pallet_staking::weights::SubstrateWeight; @@ -724,12 +726,15 @@ parameter_types! { pub const BagThresholds: &'static [u64] = &voter_bags::THRESHOLDS; } -impl pallet_bags_list::Config for Runtime { +type VoterBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Runtime { type RuntimeEvent = RuntimeEvent; + /// The voter bags-list is loosely kept up to date, and the real source of truth for the score + /// of each node is the staking pallet. type ScoreProvider = Staking; - type WeightInfo = pallet_bags_list::weights::SubstrateWeight; type BagThresholds = BagThresholds; type Score = VoteWeight; + type WeightInfo = pallet_bags_list::weights::SubstrateWeight; } parameter_types! { @@ -1637,7 +1642,7 @@ construct_runtime!( Gilt: pallet_gilt, Uniques: pallet_uniques, TransactionStorage: pallet_transaction_storage, - BagsList: pallet_bags_list, + VoterBagsList: pallet_bags_list::, StateTrieMigration: pallet_state_trie_migration, ChildBounties: pallet_child_bounties, Referenda: pallet_referenda, @@ -1723,7 +1728,7 @@ mod benches { [pallet_alliance, Alliance] [pallet_assets, Assets] [pallet_babe, Babe] - [pallet_bags_list, BagsList] + [pallet_bags_list, VoterBagsList] [pallet_balances, Balances] [pallet_bounties, Bounties] [pallet_child_bounties, ChildBounties] diff --git a/bin/node/runtime/src/voter_bags.rs b/bin/node/runtime/src/voter_bags.rs index 93790f028f457..eb540c27abcc7 100644 --- a/bin/node/runtime/src/voter_bags.rs +++ b/bin/node/runtime/src/voter_bags.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,9 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated voter bag thresholds. +//! Autogenerated bag thresholds. //! -//! Generated on 2021-07-05T09:17:40.469754927+00:00 +//! Generated on 2022-08-15T19:26:59.939787+00:00 +//! Arguments +//! Total issuance: 100000000000000 +//! Minimum balance: 100000000000000 //! for the node runtime. /// Existential weight for this runtime. diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 0ac8214f45c23..fb251457db9ca 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -202,6 +202,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; diff --git a/frame/bags-list/remote-tests/src/lib.rs b/frame/bags-list/remote-tests/src/lib.rs index 927c3dc91cb58..fc25e3b65ddb1 100644 --- a/frame/bags-list/remote-tests/src/lib.rs +++ b/frame/bags-list/remote-tests/src/lib.rs @@ -18,6 +18,7 @@ //! Utilities for remote-testing pallet-bags-list. use frame_election_provider_support::ScoreProvider; +use pallet_bags_list::Instance1; use sp_std::prelude::*; /// A common log target to use. @@ -30,18 +31,26 @@ pub mod try_state; /// A wrapper for a runtime that the functions of this crate expect. /// /// For example, this can be the `Runtime` type of the Polkadot runtime. -pub trait RuntimeT: - pallet_staking::Config + pallet_bags_list::Config + frame_system::Config +pub trait RuntimeT: + pallet_staking::Config + pallet_bags_list::Config + frame_system::Config +{ +} +impl< + I: 'static, + T: pallet_staking::Config + pallet_bags_list::Config + frame_system::Config, + > RuntimeT for T { } -impl RuntimeT for T {} fn percent(portion: u32, total: u32) -> f64 { (portion as f64 / total as f64) * 100f64 } /// Display the number of nodes in each bag, while identifying those that need a rebag. -pub fn display_and_check_bags(currency_unit: u64, currency_name: &'static str) { +pub fn display_and_check_bags>( + currency_unit: u64, + currency_name: &'static str, +) { use frame_election_provider_support::SortedListProvider; use frame_support::traits::Get; @@ -55,7 +64,8 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na let mut seen_in_bags = 0; let mut rebaggable = 0; let mut active_bags = 0; - for vote_weight_thresh in ::BagThresholds::get() { + for vote_weight_thresh in >::BagThresholds::get() + { let vote_weight_thresh_u64: u64 = (*vote_weight_thresh) .try_into() .map_err(|_| "runtime must configure score to at most u64 to use this test") @@ -64,7 +74,9 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na let vote_weight_thresh_as_unit = vote_weight_thresh_u64 as f64 / currency_unit as f64; let pretty_thresh = format!("Threshold: {}. {}", vote_weight_thresh_as_unit, currency_name); - let bag = match pallet_bags_list::Pallet::::list_bags_get(*vote_weight_thresh) { + let bag = match pallet_bags_list::Pallet::::list_bags_get( + *vote_weight_thresh, + ) { Some(bag) => bag, None => { log::info!(target: LOG_TARGET, "{} NO VOTERS.", pretty_thresh); @@ -75,7 +87,8 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na active_bags += 1; for id in bag.std_iter().map(|node| node.std_id().clone()) { - let vote_weight = ::ScoreProvider::score(&id); + let vote_weight = + >::ScoreProvider::score(&id); let vote_weight_thresh_u64: u64 = (*vote_weight_thresh) .try_into() .map_err(|_| "runtime must configure score to at most u64 to use this test") @@ -92,8 +105,8 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na ); } - let node = - pallet_bags_list::Node::::get(&id).expect("node in bag must exist."); + let node = pallet_bags_list::Node::::get(&id) + .expect("node in bag must exist."); if node.is_misplaced(vote_weight) { rebaggable += 1; let notional_bag = pallet_bags_list::notional_bag_for::(vote_weight); @@ -141,7 +154,7 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na "a total of {} nodes are in {} active bags [{} total bags], {} of which can be rebagged.", voter_list_count, active_bags, - ::BagThresholds::get().len(), + >::BagThresholds::get().len(), rebaggable, ); } diff --git a/frame/bags-list/remote-tests/src/migration.rs b/frame/bags-list/remote-tests/src/migration.rs index c4cd73c45d377..675dfbe072670 100644 --- a/frame/bags-list/remote-tests/src/migration.rs +++ b/frame/bags-list/remote-tests/src/migration.rs @@ -24,7 +24,10 @@ use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; /// Test voter bags migration. `currency_unit` is the number of planks per the the runtimes `UNITS` /// (i.e. number of decimal places per DOT, KSM etc) -pub async fn execute( +pub async fn execute< + Runtime: RuntimeT, + Block: BlockT + DeserializeOwned, +>( currency_unit: u64, currency_name: &'static str, ws_url: String, diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index 408f5f2bd8aa2..655de10c4af9b 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -22,7 +22,10 @@ use remote_externalities::{Builder, Mode, OnlineConfig}; use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; /// Execute create a snapshot from pallet-staking. -pub async fn execute( +pub async fn execute< + Runtime: crate::RuntimeT, + Block: BlockT + DeserializeOwned, +>( voter_limit: Option, currency_unit: u64, ws_url: String, @@ -34,7 +37,8 @@ pub async fn execute transport: ws_url.to_string().into(), // NOTE: we don't scrape pallet-staking, this kinda ensures that the source of the data // is bags-list. - pallets: vec![pallet_bags_list::Pallet::::name().to_string()], + pallets: vec![pallet_bags_list::Pallet::::name() + .to_string()], at: None, ..Default::default() })) diff --git a/frame/bags-list/remote-tests/src/try_state.rs b/frame/bags-list/remote-tests/src/try_state.rs index 11278c20eb8ed..9817ef4ceb9e4 100644 --- a/frame/bags-list/remote-tests/src/try_state.rs +++ b/frame/bags-list/remote-tests/src/try_state.rs @@ -25,7 +25,10 @@ use remote_externalities::{Builder, Mode, OnlineConfig}; use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; /// Execute the sanity check of the bags-list. -pub async fn execute( +pub async fn execute< + Runtime: crate::RuntimeT, + Block: BlockT + DeserializeOwned, +>( currency_unit: u64, currency_name: &'static str, ws_url: String, @@ -33,7 +36,8 @@ pub async fn execute let mut ext = Builder::::new() .mode(Mode::Online(OnlineConfig { transport: ws_url.to_string().into(), - pallets: vec![pallet_bags_list::Pallet::::name().to_string()], + pallets: vec![pallet_bags_list::Pallet::::name() + .to_string()], ..Default::default() })) .inject_hashed_prefix(&>::prefix_hash()) @@ -44,7 +48,7 @@ pub async fn execute ext.execute_with(|| { sp_core::crypto::set_default_ss58_version(Runtime::SS58Prefix::get().try_into().unwrap()); - pallet_bags_list::Pallet::::try_state().unwrap(); + pallet_bags_list::Pallet::::try_state().unwrap(); log::info!(target: crate::LOG_TARGET, "executed bags-list sanity check with no errors."); crate::display_and_check_bags::(currency_unit, currency_name); diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 5aae751de9ea6..19caf0766a3e0 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -206,6 +206,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 581cfc12a3121..18b081367d135 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -42,8 +42,11 @@ type CurrencyOf = ::Currency; const USER_SEED: u32 = 0; const MAX_SPANS: u32 = 100; +type VoterBagsListInstance = pallet_bags_list::Instance1; pub trait Config: - pallet_nomination_pools::Config + pallet_staking::Config + pallet_bags_list::Config + pallet_nomination_pools::Config + + pallet_staking::Config + + pallet_bags_list::Config { } diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index aad38ee8475d2..2dcac34d39a11 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::VoterBagsListInstance; use frame_election_provider_support::VoteWeight; use frame_support::{pallet_prelude::*, parameter_types, traits::ConstU64, PalletId}; use sp_runtime::{ @@ -111,7 +112,8 @@ impl pallet_staking::Config for Runtime { type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking)>; type GenesisElectionProvider = Self::ElectionProvider; - type VoterList = pallet_bags_list::Pallet; + type VoterList = VoterList; + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type OnStakerSlash = Pools; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; @@ -122,7 +124,7 @@ parameter_types! { pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; } -impl pallet_bags_list::Config for Runtime { +impl pallet_bags_list::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type BagThresholds = BagThresholds; @@ -180,7 +182,7 @@ frame_support::construct_runtime!( Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, - BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, + VoterList: pallet_bags_list::::{Pallet, Call, Storage, Event}, Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event}, } ); diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index d616ee1ffc180..cb63ad04d1a38 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -126,7 +126,8 @@ impl pallet_staking::Config for Runtime { type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking)>; type GenesisElectionProvider = Self::ElectionProvider; - type VoterList = pallet_bags_list::Pallet; + type VoterList = VoterList; + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type OnStakerSlash = Pools; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; @@ -137,7 +138,8 @@ parameter_types! { pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; } -impl pallet_bags_list::Config for Runtime { +type VoterBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type BagThresholds = BagThresholds; @@ -193,7 +195,7 @@ frame_support::construct_runtime!( Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, - BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, + VoterList: pallet_bags_list::::{Pallet, Call, Storage, Event}, Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event}, } ); diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 3483f5ec240a5..43c248a09a0b8 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -180,6 +180,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 01be3605601f4..de2f4ae23f423 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -175,6 +175,7 @@ impl pallet_staking::Config for Test { type GenesisElectionProvider = Self::ElectionProvider; type MaxUnlockingChunks = ConstU32<32>; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 2d5943b51758d..a79eac3c4dc46 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -844,7 +844,7 @@ benchmarks! { v, n, T::MaxNominations::get() as usize, false, None )?; }: { - let targets = >::get_npos_targets(); + let targets = >::get_npos_targets(None); assert_eq!(targets.len() as u32, v); } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 4a1f0cb886ed0..4ff9e99306727 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -886,11 +886,12 @@ enum Releases { V8_0_0, // populate `VoterList`. V9_0_0, // inject validators into `VoterList` as well. V10_0_0, // remove `EarliestUnappliedSlash`. + V11_0_0, // Move pallet storage prefix, e.g. BagsList -> VoterBagsList } impl Default for Releases { fn default() -> Self { - Releases::V10_0_0 + Releases::V11_0_0 } } diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index ff01e1fe3b09b..2556f6d989e1b 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -20,6 +20,99 @@ use super::*; use frame_election_provider_support::SortedListProvider; use frame_support::traits::OnRuntimeUpgrade; +pub mod v11 { + use super::*; + use frame_support::{ + storage::migration::move_pallet, + traits::{GetStorageVersion, PalletInfoAccess}, + }; + #[cfg(feature = "try-runtime")] + use sp_io::hashing::twox_128; + + pub struct MigrateToV11(sp_std::marker::PhantomData<(T, P, N)>); + impl> OnRuntimeUpgrade + for MigrateToV11 + { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + frame_support::ensure!( + StorageVersion::::get() == crate::Releases::V10_0_0, + "must upgrade linearly" + ); + let old_pallet_prefix = twox_128(N::get().as_bytes()); + + frame_support::ensure!( + sp_io::storage::next_key(&old_pallet_prefix).is_some(), + "no data for the old pallet name has been detected" + ); + + Ok(()) + } + + /// Migrate the entire storage of this pallet to a new prefix. + /// + /// This new prefix must be the same as the one set in construct_runtime. For safety, use + /// `PalletInfo` to get it, as: + /// `::PalletInfo::name::`. + /// + /// The migration will look into the storage version in order to avoid triggering a + /// migration on an up to date storage. + fn on_runtime_upgrade() -> Weight { + let old_pallet_name = N::get(); + let new_pallet_name =

::name(); + + if StorageVersion::::get() == Releases::V10_0_0 { + // bump version anyway, even if we don't need to move the prefix + StorageVersion::::put(Releases::V11_0_0); + if new_pallet_name == old_pallet_name { + log!( + warn, + "new bags-list name is equal to the old one, only bumping the version" + ); + return T::DbWeight::get().reads(1).saturating_add(T::DbWeight::get().writes(1)) + } + + move_pallet(old_pallet_name.as_bytes(), new_pallet_name.as_bytes()); + ::BlockWeights::get().max_block + } else { + log!(warn, "v11::migrate should be removed."); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + frame_support::ensure!( + StorageVersion::::get() == crate::Releases::V11_0_0, + "wrong version after the upgrade" + ); + + let old_pallet_name = N::get(); + let new_pallet_name =

::name(); + + // skip storage prefix checks for the same pallet names + if new_pallet_name == old_pallet_name { + return Ok(()) + } + + let old_pallet_prefix = twox_128(N::get().as_bytes()); + frame_support::ensure!( + sp_io::storage::next_key(&old_pallet_prefix).is_none(), + "old pallet data hasn't been removed" + ); + + let new_pallet_name =

::name(); + let new_pallet_prefix = twox_128(new_pallet_name.as_bytes()); + frame_support::ensure!( + sp_io::storage::next_key(&new_pallet_prefix).is_some(), + "new pallet data hasn't been created" + ); + + Ok(()) + } + } +} + pub mod v10 { use super::*; use frame_support::storage_alias; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index b8f6254d9a8e8..5980e6b40d15d 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -99,7 +99,7 @@ frame_support::construct_runtime!( Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, Historical: pallet_session::historical::{Pallet, Storage}, - BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, + VoterBagsList: pallet_bags_list::::{Pallet, Call, Storage, Event}, } ); @@ -240,9 +240,11 @@ parameter_types! { pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); } -impl pallet_bags_list::Config for Test { +type VoterBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Test { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); + // Staking is the source of truth for voter bags list, since they are not kept up to date. type ScoreProvider = Staking; type BagThresholds = BagThresholds; type Score = VoteWeight; @@ -296,7 +298,8 @@ impl crate::pallet::pallet::Config for Test { type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. - type VoterList = BagsList; + type VoterList = VoterBagsList; + type TargetList = UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type OnStakerSlash = OnStakerSlashMock; type BenchmarkingConfig = TestBenchmarkingConfig; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index aa8b2c01c6ff2..f2f9918cb8bc4 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -756,18 +756,32 @@ impl Pallet { /// Get the targets for an upcoming npos election. /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. - pub fn get_npos_targets() -> Vec { - let mut validator_count = 0u32; - let targets = Validators::::iter() - .map(|(v, _)| { - validator_count.saturating_inc(); - v - }) - .collect::>(); + pub fn get_npos_targets(maybe_max_len: Option) -> Vec { + let max_allowed_len = maybe_max_len.unwrap_or_else(|| T::TargetList::count() as usize); + let mut all_targets = Vec::::with_capacity(max_allowed_len); + let mut targets_seen = 0; + + let mut targets_iter = T::TargetList::iter(); + while all_targets.len() < max_allowed_len && + targets_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * max_allowed_len as u32) + { + let target = match targets_iter.next() { + Some(target) => { + targets_seen.saturating_inc(); + target + }, + None => break, + }; + + if Validators::::contains_key(&target) { + all_targets.push(target); + } + } - Self::register_weight(T::WeightInfo::get_npos_targets(validator_count)); + Self::register_weight(T::WeightInfo::get_npos_targets(all_targets.len() as u32)); + log!(info, "generated {} npos targets", all_targets.len()); - targets + all_targets } /// This function will add a nominator to the `Nominators` storage map, @@ -899,7 +913,7 @@ impl ElectionDataProvider for Pallet { return Err("Target snapshot too big") } - Ok(Self::get_npos_targets()) + Ok(Self::get_npos_targets(None)) } fn next_election_prediction(now: T::BlockNumber) -> T::BlockNumber { @@ -1306,6 +1320,65 @@ impl ScoreProvider for Pallet { } } +/// A simple sorted list implementation that does not require any additional pallets. Note, this +/// does not provide validators in sorted order. If you desire nominators in a sorted order take +/// a look at [`pallet-bags-list`]. +pub struct UseValidatorsMap(sp_std::marker::PhantomData); +impl SortedListProvider for UseValidatorsMap { + type Score = BalanceOf; + type Error = (); + + /// Returns iterator over voter list, which can have `take` called on it. + fn iter() -> Box> { + Box::new(Validators::::iter().map(|(v, _)| v)) + } + fn iter_from( + start: &T::AccountId, + ) -> Result>, Self::Error> { + if Validators::::contains_key(start) { + let start_key = Validators::::hashed_key_for(start); + Ok(Box::new(Validators::::iter_from(start_key).map(|(n, _)| n))) + } else { + Err(()) + } + } + fn count() -> u32 { + Validators::::count() + } + fn contains(id: &T::AccountId) -> bool { + Validators::::contains_key(id) + } + fn on_insert(_: T::AccountId, _weight: Self::Score) -> Result<(), Self::Error> { + // nothing to do on insert. + Ok(()) + } + fn get_score(id: &T::AccountId) -> Result { + Ok(Pallet::::weight_of(id).into()) + } + fn on_update(_: &T::AccountId, _weight: Self::Score) -> Result<(), Self::Error> { + // nothing to do on update. + Ok(()) + } + fn on_remove(_: &T::AccountId) -> Result<(), Self::Error> { + // nothing to do on remove. + Ok(()) + } + fn unsafe_regenerate( + _: impl IntoIterator, + _: Box Self::Score>, + ) -> u32 { + // nothing to do upon regenerate. + 0 + } + fn try_state() -> Result<(), &'static str> { + Ok(()) + } + fn unsafe_clear() { + #[allow(deprecated)] + Validators::::remove_all(); + } +} + /// A simple voter list implementation that does not require any additional pallets. Note, this /// does not provided nominators in sorted ordered. If you desire nominators in a sorted order take /// a look at [`pallet-bags-list]. @@ -1458,6 +1531,10 @@ impl StakingInterface for Pallet { #[cfg(feature = "try-runtime")] impl Pallet { pub(crate) fn do_try_state(_: BlockNumberFor) -> Result<(), &'static str> { + ensure!( + T::VoterList::iter().all(|x| >::contains_key(&x)), + "VoterList contains non-nominators" + ); T::VoterList::try_state()?; Self::check_nominators()?; Self::check_exposures()?; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 1b38f236fc6f3..b8a457beb5eae 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -184,8 +184,36 @@ pub mod pallet { /// /// The changes to nominators are reported to this. Moreover, each validator's self-vote is /// also reported as one independent vote. + /// + /// To keep the load off the chain as much as possible, changes made to the staked amount + /// via rewards and slashes are not reported and thus need to be manually fixed by the + /// staker. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`. + /// + /// Invariant: what comes out of this list will always be a nominator. type VoterList: SortedListProvider; + /// WIP: This is a noop as of now, the actual business logic that's described below is going + /// to be introduced in a follow-up PR. + /// + /// Something that provides a best-effort sorted list of targets aka electable validators, + /// used for NPoS election. + /// + /// The changes to the approval stake of each validator are reported to this. This means any + /// change to: + /// 1. The stake of any validator or nominator. + /// 2. The targets of any nominator + /// 3. The role of any staker (e.g. validator -> chilled, nominator -> validator, etc) + /// + /// Unlike `VoterList`, the values in this list are always kept up to date with reward and + /// slash as well, and thus represent the accurate approval stake of all account being + /// nominated by nominators. + /// + /// Note that while at the time of nomination, all targets are checked to be real + /// validators, they can chill at any point, and their approval stakes will still be + /// recorded. This implies that what comes out of iterating this list MIGHT NOT BE AN ACTIVE + /// VALIDATOR. + type TargetList: SortedListProvider>; + /// The maximum number of `unlocking` chunks a [`StakingLedger`] can have. Effectively /// determines how many unique eras a staker may be unbonding in. #[pallet::constant] diff --git a/utils/frame/generate-bags/src/lib.rs b/utils/frame/generate-bags/src/lib.rs index d4507c3be33ef..23da131a668d8 100644 --- a/utils/frame/generate-bags/src/lib.rs +++ b/utils/frame/generate-bags/src/lib.rs @@ -207,6 +207,10 @@ pub fn generate_thresholds( writeln!(buf, "//! Autogenerated bag thresholds.")?; writeln!(buf, "//!")?; writeln!(buf, "//! Generated on {}", now.to_rfc3339())?; + writeln!(buf, "//! Arguments")?; + writeln!(buf, "//! Total issuance: {}", &total_issuance)?; + writeln!(buf, "//! Minimum balance: {}", &minimum_balance)?; + writeln!( buf, "//! for the {} runtime.", @@ -234,6 +238,17 @@ pub fn generate_thresholds( writeln!(buf)?; writeln!(buf, "/// Upper thresholds delimiting the bag list.")?; writeln!(buf, "pub const THRESHOLDS: [u64; {}] = [", thresholds.len())?; + for threshold in &thresholds { + num_buf.write_formatted(threshold, &format); + // u64::MAX, with spacers every 3 digits, is 26 characters wide + writeln!(buf, " {:>26},", num_buf.as_str())?; + } + writeln!(buf, "];")?; + + // thresholds balance + writeln!(buf)?; + writeln!(buf, "/// Upper thresholds delimiting the bag list.")?; + writeln!(buf, "pub const THRESHOLDS_BALANCES: [u128; {}] = [", thresholds.len())?; for threshold in thresholds { num_buf.write_formatted(&threshold, &format); // u64::MAX, with spacers every 3 digits, is 26 characters wide From 91b97b016618fcc515f55a15b1f008b68e13f5a2 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Sun, 18 Sep 2022 14:50:38 +0200 Subject: [PATCH 1172/1472] [Fix] Benchmark issue in staking (#12290) --- frame/staking/src/pallet/impls.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index f2f9918cb8bc4..62faaaf68ef62 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1377,6 +1377,11 @@ impl SortedListProvider for UseValidatorsMap { #[allow(deprecated)] Validators::::remove_all(); } + + #[cfg(feature = "runtime-benchmarks")] + fn score_update_worst_case(_who: &T::AccountId, _is_increase: bool) -> Self::Score { + unimplemented!() + } } /// A simple voter list implementation that does not require any additional pallets. Note, this From ee3c159829398add73a7c26fd7cba6de1c51257b Mon Sep 17 00:00:00 2001 From: NingLin-P Date: Mon, 19 Sep 2022 18:52:55 +0800 Subject: [PATCH 1173/1472] support upgrade hooks to directly pass data (#12185) * update interfaces of OnRuntimeUpgrade & Hooks Signed-off-by: linning * remove try-runtime for PreStateDigest Signed-off-by: linning * remove the Default bound of PreStateDigest Signed-off-by: linning * remove try-runtime for PreStateDigest & pre_upgrade Signed-off-by: linning * remove tmp storage between upgrade hooks Signed-off-by: linning * ensure hooks are storage noop Signed-off-by: linning * remove OnRuntimeUpgradeHelpersExt Signed-off-by: linning * cargo check & fmt Signed-off-by: linning * rename PreStateDigest to PreUpgradeState Signed-off-by: linning * replace associate type with codec & vec Signed-off-by: linning * add helper strcut to help encode/decode tuple Signed-off-by: linning * update comment Signed-off-by: linning * fix Signed-off-by: linning * add test Signed-off-by: linning * address comment Signed-off-by: linning * fix doc Signed-off-by: linning * fix ci Signed-off-by: linning * address comment Signed-off-by: linning * add more test cases Signed-off-by: linning * make clippy happy Signed-off-by: linning * fmt Signed-off-by: linning * update comment Signed-off-by: linning * fmt Signed-off-by: linning Signed-off-by: linning --- frame/bags-list/src/migrations.rs | 22 ++- frame/executive/src/lib.rs | 11 +- frame/nomination-pools/src/migration.rs | 16 +- frame/staking/src/migrations.rs | 17 ++- .../procedural/src/pallet/expand/hooks.rs | 6 +- frame/support/src/dispatch.rs | 12 +- frame/support/src/lib.rs | 2 +- .../support/src/storage/storage_noop_guard.rs | 2 +- frame/support/src/traits.rs | 2 +- frame/support/src/traits/hooks.rs | 141 ++++++++++++++++-- frame/support/src/traits/try_runtime.rs | 38 +---- utils/frame/try-runtime/cli/src/lib.rs | 12 +- 12 files changed, 182 insertions(+), 99 deletions(-) diff --git a/frame/bags-list/src/migrations.rs b/frame/bags-list/src/migrations.rs index 49b7d136125e2..e1dc9f777e537 100644 --- a/frame/bags-list/src/migrations.rs +++ b/frame/bags-list/src/migrations.rs @@ -24,6 +24,8 @@ use frame_support::traits::OnRuntimeUpgrade; #[cfg(feature = "try-runtime")] use frame_support::ensure; +#[cfg(feature = "try-runtime")] +use sp_std::vec::Vec; /// A struct that does not migration, but only checks that the counter prefix exists and is correct. pub struct CheckCounterPrefix, I: 'static>(sp_std::marker::PhantomData<(T, I)>); @@ -33,7 +35,7 @@ impl, I: 'static> OnRuntimeUpgrade for CheckCounterPrefix Result<(), &'static str> { + fn pre_upgrade() -> Result, &'static str> { // The old explicit storage item. #[frame_support::storage_alias] type CounterForListNodes, I: 'static> = @@ -51,7 +53,7 @@ impl, I: 'static> OnRuntimeUpgrade for CheckCounterPrefix::count() ); - Ok(()) + Ok(Vec::new()) } } @@ -80,17 +82,13 @@ mod old { #[frame_support::storage_alias] pub type CounterForListNodes, I: 'static> = StorageValue, u32, ValueQuery>; - - #[frame_support::storage_alias] - pub type TempStorage, I: 'static> = - StorageValue, u32, ValueQuery>; } /// A struct that migrates all bags lists to contain a score value. pub struct AddScore, I: 'static = ()>(sp_std::marker::PhantomData<(T, I)>); impl, I: 'static> OnRuntimeUpgrade for AddScore { #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { + fn pre_upgrade() -> Result, &'static str> { // The list node data should be corrupt at this point, so this is zero. ensure!(crate::ListNodes::::iter().count() == 0, "list node data is not corrupt"); // We can use the helper `old::ListNode` to get the existing data. @@ -98,8 +96,7 @@ impl, I: 'static> OnRuntimeUpgrade for AddScore { let tracked_node_count: u32 = old::CounterForListNodes::::get(); crate::log!(info, "number of nodes before: {:?} {:?}", iter_node_count, tracked_node_count); ensure!(iter_node_count == tracked_node_count, "Node count is wrong."); - old::TempStorage::::put(iter_node_count); - Ok(()) + Ok(iter_node_count.encode()) } fn on_runtime_upgrade() -> frame_support::weights::Weight { @@ -122,9 +119,10 @@ impl, I: 'static> OnRuntimeUpgrade for AddScore { } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { - let node_count_before = old::TempStorage::::take(); - // Now, the list node data is not corrupt anymore. + fn post_upgrade(node_count_before: Vec) -> Result<(), &'static str> { + let node_count_before: u32 = Decode::decode(&mut node_count_before.as_slice()) + .expect("the state parameter should be something that was generated by pre_upgrade"); + // Now the list node data is not corrupt anymore. let iter_node_count_after: u32 = crate::ListNodes::::iter().count() as u32; let tracked_node_count_after: u32 = crate::ListNodes::::count(); crate::log!( diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 96e71512e54bc..88cefb17c2895 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -287,10 +287,15 @@ where /// /// This should only be used for testing. pub fn try_runtime_upgrade() -> Result { - <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::pre_upgrade().unwrap(); + // ensure both `pre_upgrade` and `post_upgrade` won't change the storage root + let state = { + let _guard = frame_support::StorageNoopGuard::default(); + <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::pre_upgrade().unwrap() + }; let weight = Self::execute_on_runtime_upgrade(); - <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::post_upgrade().unwrap(); - + let _guard = frame_support::StorageNoopGuard::default(); + <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::post_upgrade(state) + .unwrap(); Ok(weight) } } diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index bcf23ee863a39..4d78f2fa76c96 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -18,7 +18,7 @@ use super::*; use crate::log; use frame_support::traits::OnRuntimeUpgrade; -use sp_std::collections::btree_map::BTreeMap; +use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; pub mod v1 { use super::*; @@ -97,7 +97,7 @@ pub mod v1 { } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_: Vec) -> Result<(), &'static str> { // new version must be set. assert_eq!(Pallet::::on_chain_storage_version(), 1); Pallet::::try_state(frame_system::Pallet::::block_number())?; @@ -347,7 +347,7 @@ pub mod v2 { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { + fn pre_upgrade() -> Result, &'static str> { // all reward accounts must have more than ED. RewardPools::::iter().for_each(|(id, _)| { assert!( @@ -356,11 +356,11 @@ pub mod v2 { ) }); - Ok(()) + Ok(Vec::new()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_: Vec) -> Result<(), &'static str> { // new version must be set. assert_eq!(Pallet::::on_chain_storage_version(), 2); @@ -430,16 +430,16 @@ pub mod v3 { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { + fn pre_upgrade() -> Result, &'static str> { ensure!( Pallet::::current_storage_version() > Pallet::::on_chain_storage_version(), "the on_chain version is equal or more than the current one" ); - Ok(()) + Ok(Vec::new()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_: Vec) -> Result<(), &'static str> { ensure!( Metadata::::iter_keys().all(|id| BondedPools::::contains_key(&id)), "not all of the stale metadata has been removed" diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 2556f6d989e1b..4f5dcf49d6ab4 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -154,6 +154,10 @@ pub mod v10 { pub mod v9 { use super::*; + #[cfg(feature = "try-runtime")] + use frame_support::codec::{Decode, Encode}; + #[cfg(feature = "try-runtime")] + use sp_std::vec::Vec; /// Migration implementation that injects all validators into sorted list. /// @@ -192,23 +196,22 @@ pub mod v9 { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - use frame_support::traits::OnRuntimeUpgradeHelpersExt; + fn pre_upgrade() -> Result, &'static str> { frame_support::ensure!( StorageVersion::::get() == crate::Releases::V8_0_0, "must upgrade linearly" ); let prev_count = T::VoterList::count(); - Self::set_temp_storage(prev_count, "prev"); - Ok(()) + Ok(prev_count.encode()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { - use frame_support::traits::OnRuntimeUpgradeHelpersExt; + fn post_upgrade(prev_count: Vec) -> Result<(), &'static str> { + let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect( + "the state parameter should be something that was generated by pre_upgrade", + ); let post_count = T::VoterList::count(); - let prev_count = Self::get_temp_storage::("prev").unwrap(); let validators = Validators::::count(); assert!(post_count == prev_count + validators); diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index 03878f3f186df..48d4aec436d40 100644 --- a/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/frame/support/procedural/src/pallet/expand/hooks.rs @@ -160,7 +160,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { + fn pre_upgrade() -> Result<#frame_support::sp_std::vec::Vec, &'static str> { < Self as @@ -169,12 +169,12 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(state: #frame_support::sp_std::vec::Vec) -> Result<(), &'static str> { < Self as #frame_support::traits::Hooks<::BlockNumber> - >::post_upgrade() + >::post_upgrade(state) } } diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 1d8930f96fbe5..cacd599fa008c 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -2158,12 +2158,12 @@ macro_rules! decl_module { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - Ok(()) + fn pre_upgrade() -> Result<$crate::sp_std::vec::Vec, &'static str> { + Ok($crate::sp_std::vec::Vec::new()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_: $crate::sp_std::vec::Vec) -> Result<(), &'static str> { Ok(()) } } @@ -2196,12 +2196,12 @@ macro_rules! decl_module { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - Ok(()) + fn pre_upgrade() -> Result<$crate::sp_std::vec::Vec, &'static str> { + Ok($crate::sp_std::vec::Vec::new()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_: $crate::sp_std::vec::Vec) -> Result<(), &'static str> { Ok(()) } } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index e9578cccc23bc..31b95de5f413d 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -93,7 +93,7 @@ pub mod unsigned { }; } -#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] +#[cfg(any(feature = "std", feature = "runtime-benchmarks", feature = "try-runtime", test))] pub use self::storage::storage_noop_guard::StorageNoopGuard; pub use self::{ dispatch::{Callable, Parameter}, diff --git a/frame/support/src/storage/storage_noop_guard.rs b/frame/support/src/storage/storage_noop_guard.rs index afcc699d91313..7186c3eaf467a 100644 --- a/frame/support/src/storage/storage_noop_guard.rs +++ b/frame/support/src/storage/storage_noop_guard.rs @@ -16,7 +16,7 @@ // limitations under the License. // Feature gated since it can panic. -#![cfg(any(feature = "std", feature = "runtime-benchmarks", test))] +#![cfg(any(feature = "std", feature = "runtime-benchmarks", feature = "try-runtime", test))] //! Contains the [`crate::StorageNoopGuard`] for conveniently asserting //! that no storage mutation has been made by a whole code block. diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 16ac7929831b4..d51c32649a797 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -109,4 +109,4 @@ pub use voting::{ #[cfg(feature = "try-runtime")] mod try_runtime; #[cfg(feature = "try-runtime")] -pub use try_runtime::{OnRuntimeUpgradeHelpersExt, Select as TryStateSelect, TryState}; +pub use try_runtime::{Select as TryStateSelect, TryState}; diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index 25ec333a7dbe0..eb1106e4c383f 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -22,6 +22,9 @@ use impl_trait_for_tuples::impl_for_tuples; use sp_runtime::traits::AtLeast32BitUnsigned; use sp_std::prelude::*; +#[cfg(feature = "try-runtime")] +use codec::{Decode, Encode}; + /// The block initialization trait. /// /// Implementing this lets you express what should happen for your pallet when the block is @@ -135,17 +138,25 @@ pub trait OnRuntimeUpgrade { /// Execute some pre-checks prior to a runtime upgrade. /// + /// Return a `Vec` that can contain arbitrary encoded data (usually some pre-upgrade state), + /// which will be passed to `post_upgrade` after upgrading for post-check. An empty vector + /// should be returned if there is no such need. + /// /// This hook is never meant to be executed on-chain but is meant to be used by testing tools. #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - Ok(()) + fn pre_upgrade() -> Result, &'static str> { + Ok(Vec::new()) } /// Execute some post-checks after a runtime upgrade. /// + /// The `state` parameter is the `Vec` returned by `pre_upgrade` before upgrading, which + /// can be used for post-check. NOTE: if `pre_upgrade` is not implemented an empty vector will + /// be passed in, in such case `post_upgrade` should ignore it. + /// /// This hook is never meant to be executed on-chain but is meant to be used by testing tools. #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { Ok(()) } } @@ -161,17 +172,21 @@ impl OnRuntimeUpgrade for Tuple { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - let mut result = Ok(()); - for_tuples!( #( result = result.and(Tuple::pre_upgrade()); )* ); - result + fn pre_upgrade() -> Result, &'static str> { + let mut state: Vec> = Vec::default(); + for_tuples!( #( state.push(Tuple::pre_upgrade()?); )* ); + Ok(state.encode()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { - let mut result = Ok(()); - for_tuples!( #( result = result.and(Tuple::post_upgrade()); )* ); - result + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let state: Vec> = Decode::decode(&mut state.as_slice()) + .expect("the state parameter should be the same as pre_upgrade generated"); + let mut state_iter = state.into_iter(); + for_tuples!( #( Tuple::post_upgrade( + state_iter.next().expect("the state parameter should be the same as pre_upgrade generated") + )?; )* ); + Ok(()) } } @@ -243,17 +258,25 @@ pub trait Hooks { /// Execute some pre-checks prior to a runtime upgrade. /// + /// Return a `Vec` that can contain arbitrary encoded data (usually some pre-upgrade state), + /// which will be passed to `post_upgrade` after upgrading for post-check. An empty vector + /// should be returned if there is no such need. + /// /// This hook is never meant to be executed on-chain but is meant to be used by testing tools. #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - Ok(()) + fn pre_upgrade() -> Result, &'static str> { + Ok(Vec::new()) } /// Execute some post-checks after a runtime upgrade. /// + /// The `state` parameter is the `Vec` returned by `pre_upgrade` before upgrading, which + /// can be used for post-check. NOTE: if `pre_upgrade` is not implemented an empty vector will + /// be passed in, in such case `post_upgrade` should ignore it. + /// /// This hook is never meant to be executed on-chain but is meant to be used by testing tools. #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { Ok(()) } @@ -390,4 +413,94 @@ mod tests { ON_IDLE_INVOCATION_ORDER.clear(); } } + + #[cfg(feature = "try-runtime")] + #[test] + fn on_runtime_upgrade_tuple() { + struct Test1; + struct Test2; + struct Test3; + + impl OnRuntimeUpgrade for Test1 { + fn pre_upgrade() -> Result, &'static str> { + Ok("Test1".encode()) + } + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let s: String = Decode::decode(&mut state.as_slice()).unwrap(); + assert_eq!(s, "Test1"); + Ok(()) + } + } + impl OnRuntimeUpgrade for Test2 { + fn pre_upgrade() -> Result, &'static str> { + Ok(100u32.encode()) + } + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let s: u32 = Decode::decode(&mut state.as_slice()).unwrap(); + assert_eq!(s, 100); + Ok(()) + } + } + impl OnRuntimeUpgrade for Test3 { + fn pre_upgrade() -> Result, &'static str> { + Ok(true.encode()) + } + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let s: bool = Decode::decode(&mut state.as_slice()).unwrap(); + assert_eq!(s, true); + Ok(()) + } + } + + type TestEmpty = (); + let origin_state = ::pre_upgrade().unwrap(); + let states: Vec> = Decode::decode(&mut origin_state.as_slice()).unwrap(); + assert!(states.is_empty()); + ::post_upgrade(origin_state).unwrap(); + + type Test1Tuple = (Test1,); + let origin_state = ::pre_upgrade().unwrap(); + let states: Vec> = Decode::decode(&mut origin_state.as_slice()).unwrap(); + assert_eq!(states.len(), 1); + assert_eq!( + ::decode(&mut states[0].as_slice()).unwrap(), + "Test1".to_owned() + ); + ::post_upgrade(origin_state).unwrap(); + + type Test123 = (Test1, Test2, Test3); + let origin_state = ::pre_upgrade().unwrap(); + let states: Vec> = Decode::decode(&mut origin_state.as_slice()).unwrap(); + assert_eq!( + ::decode(&mut states[0].as_slice()).unwrap(), + "Test1".to_owned() + ); + assert_eq!(::decode(&mut states[1].as_slice()).unwrap(), 100u32); + assert_eq!(::decode(&mut states[2].as_slice()).unwrap(), true); + ::post_upgrade(origin_state).unwrap(); + + type Test321 = (Test3, Test2, Test1); + let origin_state = ::pre_upgrade().unwrap(); + let states: Vec> = Decode::decode(&mut origin_state.as_slice()).unwrap(); + assert_eq!(::decode(&mut states[0].as_slice()).unwrap(), true); + assert_eq!(::decode(&mut states[1].as_slice()).unwrap(), 100u32); + assert_eq!( + ::decode(&mut states[2].as_slice()).unwrap(), + "Test1".to_owned() + ); + ::post_upgrade(origin_state).unwrap(); + + type TestNested123 = (Test1, (Test2, Test3)); + let origin_state = ::pre_upgrade().unwrap(); + let states: Vec> = Decode::decode(&mut origin_state.as_slice()).unwrap(); + assert_eq!( + ::decode(&mut states[0].as_slice()).unwrap(), + "Test1".to_owned() + ); + // nested state for (Test2, Test3) + let nested_states: Vec> = Decode::decode(&mut states[1].as_slice()).unwrap(); + assert_eq!(::decode(&mut nested_states[0].as_slice()).unwrap(), 100u32); + assert_eq!(::decode(&mut nested_states[1].as_slice()).unwrap(), true); + ::post_upgrade(origin_state).unwrap(); + } } diff --git a/frame/support/src/traits/try_runtime.rs b/frame/support/src/traits/try_runtime.rs index c5ddd1cae42be..640bb566a65af 100644 --- a/frame/support/src/traits/try_runtime.rs +++ b/frame/support/src/traits/try_runtime.rs @@ -17,46 +17,10 @@ //! Try-runtime specific traits and types. -use super::*; use impl_trait_for_tuples::impl_for_tuples; use sp_arithmetic::traits::AtLeast32BitUnsigned; use sp_std::prelude::*; -/// Prefix to be used (optionally) for implementing [`OnRuntimeUpgradeHelpersExt::storage_key`]. -const ON_RUNTIME_UPGRADE_PREFIX: &[u8] = b"__ON_RUNTIME_UPGRADE__"; - -/// Some helper functions for [`OnRuntimeUpgrade`] during `try-runtime` testing. -pub trait OnRuntimeUpgradeHelpersExt { - /// Generate a storage key unique to this runtime upgrade. - /// - /// This can be used to communicate data from pre-upgrade to post-upgrade state and check - /// them. See [`Self::set_temp_storage`] and [`Self::get_temp_storage`]. - fn storage_key(ident: &str) -> [u8; 32] { - crate::storage::storage_prefix(ON_RUNTIME_UPGRADE_PREFIX, ident.as_bytes()) - } - - /// Get temporary storage data written by [`Self::set_temp_storage`]. - /// - /// Returns `None` if either the data is unavailable or un-decodable. - /// - /// A `at` storage identifier must be provided to indicate where the storage is being read from. - fn get_temp_storage(at: &str) -> Option { - sp_io::storage::get(&Self::storage_key(at)) - .and_then(|bytes| codec::Decode::decode(&mut &*bytes).ok()) - } - - /// Write some temporary data to a specific storage that can be read (potentially in - /// post-upgrade hook) via [`Self::get_temp_storage`]. - /// - /// A `at` storage identifier must be provided to indicate where the storage is being written - /// to. - fn set_temp_storage(data: T, at: &str) { - sp_io::storage::set(&Self::storage_key(at), &data.encode()); - } -} - -impl OnRuntimeUpgradeHelpersExt for U {} - // Which state tests to execute. #[derive(codec::Encode, codec::Decode, Clone)] pub enum Select { @@ -68,7 +32,7 @@ pub enum Select { RoundRobin(u32), /// Run only pallets who's name matches the given list. /// - /// Pallet names are obtained from [`PalletInfoAccess`]. + /// Pallet names are obtained from [`super::PalletInfoAccess`]. Only(Vec>), } diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index c71496e0b850c..c3382045add16 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -132,20 +132,20 @@ //! added, given the right flag: //! //! ```ignore +//! //! #[cfg(feature = try-runtime)] -//! fn pre_upgrade() -> Result<(), &'static str> {} +//! fn pre_upgrade() -> Result, &'static str> {} //! //! #[cfg(feature = try-runtime)] -//! fn post_upgrade() -> Result<(), &'static str> {} +//! fn post_upgrade(state: Vec) -> Result<(), &'static str> {} //! ``` //! //! (The pallet macro syntax will support this simply as a part of `#[pallet::hooks]`). //! //! These hooks allow you to execute some code, only within the `on-runtime-upgrade` command, before -//! and after the migration. If any data needs to be temporarily stored between the pre/post -//! migration hooks, `OnRuntimeUpgradeHelpersExt` can help with that. Note that you should be -//! mindful with any mutable storage ops in the pre/post migration checks, as you almost certainly -//! will not want to mutate any of the storage that is to be migrated. +//! and after the migration. Moreover, `pre_upgrade` can return a `Vec` that contains arbitrary +//! encoded data (usually some pre-upgrade state) which will be passed to `post_upgrade` after +//! upgrading and used for post checking. //! //! #### Logging //! From b541b2d2c9259c8617cd1ce2cf9a98ac06602679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 19 Sep 2022 12:56:46 +0200 Subject: [PATCH 1174/1472] contracts: Use `WeakBoundedVec` for instrumented code (#12186) * Use WeakBoundedVec for instrumented code * Remove `RelaxedMaxCodeLen` from kitchensink --- bin/node/runtime/src/lib.rs | 1 - frame/contracts/src/lib.rs | 13 ++----------- frame/contracts/src/tests.rs | 1 - frame/contracts/src/wasm/code_cache.rs | 14 ++++++++++---- frame/contracts/src/wasm/mod.rs | 12 +----------- 5 files changed, 13 insertions(+), 28 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index b5467aa6f8ea7..8b150dca849f0 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1167,7 +1167,6 @@ impl pallet_contracts::Config for Runtime { type AddressGenerator = pallet_contracts::DefaultAddressGenerator; type ContractAccessWeight = pallet_contracts::DefaultContractAccessWeight; type MaxCodeLen = ConstU32<{ 128 * 1024 }>; - type RelaxedMaxCodeLen = ConstU32<{ 256 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 48f1668440387..842fa02f34529 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -111,7 +111,7 @@ use frame_support::{ ensure, traits::{ConstU32, Contains, Currency, Get, Randomness, ReservableCurrency, Time}, weights::Weight, - BoundedVec, + BoundedVec, WeakBoundedVec, }; use frame_system::{limits::BlockWeights, Pallet as System}; use pallet_contracts_primitives::{ @@ -135,7 +135,7 @@ type TrieId = BoundedVec>; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type CodeVec = BoundedVec::MaxCodeLen>; -type RelaxedCodeVec = BoundedVec::RelaxedMaxCodeLen>; +type RelaxedCodeVec = WeakBoundedVec::MaxCodeLen>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// Used as a sentinel value when reading and writing contract memory. @@ -366,15 +366,6 @@ pub mod pallet { /// a wasm binary below this maximum size. type MaxCodeLen: Get; - /// The maximum length of a contract code after reinstrumentation. - /// - /// When uploading a new contract the size defined by [`Self::MaxCodeLen`] is used for both - /// the pristine **and** the instrumented version. When a existing contract needs to be - /// reinstrumented after a runtime upgrade we apply this bound. The reason is that if the - /// new instrumentation increases the size beyond the limit it would make that contract - /// inaccessible until rectified by another runtime upgrade. - type RelaxedMaxCodeLen: Get; - /// The maximum allowable length in bytes for storage keys. type MaxStorageKeyLen: Get; } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index c40968eb2ea57..d5f4df161b723 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -395,7 +395,6 @@ impl Config for Test { type AddressGenerator = DefaultAddressGenerator; type ContractAccessWeight = DefaultContractAccessWeight; type MaxCodeLen = ConstU32<{ 128 * 1024 }>; - type RelaxedMaxCodeLen = ConstU32<{ 256 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; } diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index eb5551e342bca..137eccf3db686 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -39,6 +39,7 @@ use frame_support::{ dispatch::{DispatchError, DispatchResult}, ensure, traits::{Get, ReservableCurrency}, + WeakBoundedVec, }; use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::BadOrigin; @@ -195,10 +196,15 @@ pub fn reinstrument( let original_code = >::get(&prefab_module.code_hash).ok_or(Error::::CodeNotFound)?; let original_code_len = original_code.len(); - prefab_module.code = prepare::reinstrument_contract::(&original_code, schedule) - .map_err(|_| >::CodeRejected)? - .try_into() - .map_err(|_| >::CodeTooLarge)?; + // We need to allow contracts growing too big after re-instrumentation. Otherwise + // the contract can become inaccessible. The user has no influence over this size + // as the contract is already deployed and every change in size would be the result + // of changes in the instrumentation algorithm controlled by the chain authors. + prefab_module.code = WeakBoundedVec::force_from( + prepare::reinstrument_contract::(&original_code, schedule) + .map_err(|_| >::CodeRejected)?, + Some("Contract exceeds limit after re-instrumentation."), + ); prefab_module.instruction_weights_version = schedule.instruction_weights.version; >::insert(&prefab_module.code_hash, &*prefab_module); Ok(original_code_len as u32) diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index e850f458bb745..085bc5a8c6423 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -35,11 +35,7 @@ use crate::{ Schedule, }; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - dispatch::{DispatchError, DispatchResult}, - ensure, - traits::Get, -}; +use frame_support::dispatch::{DispatchError, DispatchResult}; use sp_core::crypto::UncheckedFrom; use sp_sandbox::{SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory}; use sp_std::prelude::*; @@ -134,12 +130,6 @@ where schedule, owner, )?; - // When instrumenting a new code we apply a stricter limit than enforced by the - // `RelaxedCodeVec` in order to leave some headroom for reinstrumentation. - ensure!( - module.code.len() as u32 <= T::MaxCodeLen::get(), - (>::CodeTooLarge.into(), ""), - ); Ok(module) } From c24431eb6a95197550b30715a4c124be1aea79de Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 19 Sep 2022 15:12:29 +0200 Subject: [PATCH 1175/1472] Fix CI (#12297) * Put type constraint at the end Signed-off-by: Oliver Tale-Yazdi * Fix rust features Signed-off-by: Oliver Tale-Yazdi * Use new OnRuntimeUpgrade hooks Signed-off-by: Oliver Tale-Yazdi * Use new OnRuntimeUpgrade hooks Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/bags-list/Cargo.toml | 2 +- frame/staking/Cargo.toml | 1 + frame/staking/src/migrations.rs | 6 +++--- frame/uniques/src/lib.rs | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 2f9fa6c624538..19eb66ae624af 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -65,7 +65,7 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "sp-core", "sp-io", - "pallet-balances", + "pallet-balances/runtime-benchmarks", "sp-tracing", "frame-election-provider-support/runtime-benchmarks", ] diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 54d21f7ca6bcc..cf9e12dcd82b4 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -74,6 +74,7 @@ runtime-benchmarks = [ "frame-election-provider-support/runtime-benchmarks", "rand_chacha", "sp-staking/runtime-benchmarks", + "pallet-bags-list/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] fuzz = [ diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 4f5dcf49d6ab4..427570e5cf14f 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -34,7 +34,7 @@ pub mod v11 { for MigrateToV11 { #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { + fn pre_upgrade() -> Result, &'static str> { frame_support::ensure!( StorageVersion::::get() == crate::Releases::V10_0_0, "must upgrade linearly" @@ -46,7 +46,7 @@ pub mod v11 { "no data for the old pallet name has been detected" ); - Ok(()) + Ok(Default::default()) } /// Migrate the entire storage of this pallet to a new prefix. @@ -81,7 +81,7 @@ pub mod v11 { } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { frame_support::ensure!( StorageVersion::::get() == crate::Releases::V11_0_0, "wrong version after the upgrade" diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index e25607e67a224..b02a10270dd7d 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -110,9 +110,9 @@ pub mod pallet { /// Standard collection creation is only allowed if the origin attempting it and the /// collection are in this set. type CreateOrigin: EnsureOriginWithArg< - Success = Self::AccountId, Self::Origin, Self::CollectionId, + Success = Self::AccountId, >; /// Locker trait to enable Locking mechanism downstream. From df3722c8b42dd9ac8e3705d0d06bdba03237d94f Mon Sep 17 00:00:00 2001 From: Vlad Date: Tue, 20 Sep 2022 12:15:48 +0300 Subject: [PATCH 1176/1472] Fix `cargo-check-benches` job (#12301) --- .gitlab-ci.yml | 18 +++++++++--------- scripts/ci/gitlab/pipeline/test.yml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a639505b3bb03..9df4c0b618661 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -131,31 +131,31 @@ default: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 -.test-refs-no-trigger: +# handle the specific case where benches could store incorrect bench data because of the downstream staging runs +# exclude cargo-check-benches from such runs +.test-refs-check-benches: rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" + - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "parent_pipeline" && $CI_IMAGE =~ /staging$/ when: never - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ -.test-refs-no-trigger-prs-only: +.test-refs-no-trigger: rules: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ -# handle the specific case where benches could store incorrect bench data because of the downstream staging runs -# exclude cargo-check-benches from such runs -.test-refs-no-trigger-prs-only-check-benches: +.test-refs-no-trigger-prs-only: rules: - - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "parent_pipeline" && $CI_IMAGE =~ /staging$/ - when: never - if: $CI_PIPELINE_SOURCE == "pipeline" when: never - if: $CI_PIPELINE_SOURCE == "web" diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index bbe38cfb02293..e85ab85afe6ed 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -59,7 +59,7 @@ cargo-check-benches: CI_JOB_NAME: "cargo-check-benches" extends: - .docker-env - - .test-refs-no-trigger-prs-only-check-benches + - .test-refs-check-benches - .collect-artifacts - .pipeline-stopper-artifacts before_script: From 625de4f9cb50cda954df07552222be4ee0de774d Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 20 Sep 2022 12:31:58 +0200 Subject: [PATCH 1177/1472] [ci] Revert cancel-pipeline job (#12309) * [WIP][ci] Revert cancel-pipeline job * fail test-linux-stable * fix test-linux-stable --- .gitlab-ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9df4c0b618661..e6f26cbfd5cf7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,7 +41,7 @@ workflow: - if: $CI_COMMIT_TAG - if: $CI_COMMIT_BRANCH -variables: &default-vars +variables: GIT_STRATEGY: fetch GIT_DEPTH: 100 CARGO_INCREMENTAL: 0 @@ -278,8 +278,6 @@ rusty-cachier-notify: PR_NUM: "${PR_NUM}" trigger: project: "parity/infrastructure/ci_cd/pipeline-stopper" - # remove branch, when pipeline-stopper for polakdot is updated to the same branch - branch: "as-improve" # need to copy jobs this way because otherwise gitlab will wait # for all 3 jobs to finish instead of cancelling if one fails From e7c515dad67ee8d9c197cc9c0def8ecb3cd72e97 Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Tue, 20 Sep 2022 17:17:34 +0300 Subject: [PATCH 1178/1472] Proper naming wrt expectations (#12311) Signed-off-by: Andrei Sandu Signed-off-by: Andrei Sandu --- utils/frame/try-runtime/cli/src/commands/execute_block.rs | 2 +- utils/frame/try-runtime/cli/src/commands/follow_chain.rs | 2 +- utils/frame/try-runtime/cli/src/commands/offchain_worker.rs | 2 +- .../frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs | 2 +- utils/frame/try-runtime/cli/src/lib.rs | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index 70ba3615f874a..0c8b968d1b4b1 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -195,7 +195,7 @@ where block_ws_uri.clone(), expected_spec_name, expected_spec_version, - shared.no_spec_name_check, + shared.no_spec_check_panic, ) .await; diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index f493d5c10cd29..88866b538169b 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -275,7 +275,7 @@ where command.uri.clone(), expected_spec_name, expected_spec_version, - shared.no_spec_name_check, + shared.no_spec_check_panic, ) .await; diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index a579692abd9e2..b0404fff18135 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -152,7 +152,7 @@ where header_ws_uri, expected_spec_name, expected_spec_version, - shared.no_spec_name_check, + shared.no_spec_check_panic, ) .await; diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 9bc6d32d4762a..5055e4fb34581 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -64,7 +64,7 @@ where uri, expected_spec_name, expected_spec_version, - shared.no_spec_name_check, + shared.no_spec_check_panic, ) .await; } diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index c3382045add16..b8a2779d57e19 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -421,9 +421,9 @@ pub struct SharedParams { #[clap(long)] pub heap_pages: Option, - /// When enabled, the spec name check will not panic, and instead only show a warning. + /// When enabled, the spec check will not panic, and instead only show a warning. #[clap(long)] - pub no_spec_name_check: bool, + pub no_spec_check_panic: bool, /// State version that is used by the chain. #[clap(long, default_value = "1", parse(try_from_str = parse::state_version))] From 97ad64bd507eacf1dc8c597cf8538c98facb3220 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Tue, 20 Sep 2022 18:05:44 +0300 Subject: [PATCH 1179/1472] Import target block body during warp sync (#12300) * Receive and import target block body * Request target block * minor: wording * Check for block body in the test * Import target block justifications * Fix: do not fail block validation if no justifications received * Fix: import target blocks without justifications Co-authored-by: arkpar --- client/network/common/src/sync.rs | 2 + client/network/common/src/sync/warp.rs | 3 + client/network/src/protocol.rs | 2 + client/network/sync/src/lib.rs | 90 ++++++++++++++++++--- client/network/sync/src/state.rs | 27 +++++-- client/network/sync/src/warp.rs | 105 ++++++++++++++++++++++--- client/network/test/src/lib.rs | 9 ++- client/network/test/src/sync.rs | 4 +- 8 files changed, 211 insertions(+), 31 deletions(-) diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index 2ee8f8c51814b..020b2c9efa4c7 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -96,6 +96,8 @@ pub enum OnBlockData { Import(BlockOrigin, Vec>), /// A new block request needs to be made to the given peer. Request(PeerId, BlockRequest), + /// Continue processing events. + Continue, } /// Result of [`ChainSync::on_block_justification`]. diff --git a/client/network/common/src/sync/warp.rs b/client/network/common/src/sync/warp.rs index 339a4c33a7eeb..c9b9037542388 100644 --- a/client/network/common/src/sync/warp.rs +++ b/client/network/common/src/sync/warp.rs @@ -64,6 +64,8 @@ pub enum WarpSyncPhase { AwaitingPeers, /// Downloading and verifying grandpa warp proofs. DownloadingWarpProofs, + /// Downloading target block. + DownloadingTargetBlock, /// Downloading state data. DownloadingState, /// Importing state. @@ -77,6 +79,7 @@ impl fmt::Display for WarpSyncPhase { match self { Self::AwaitingPeers => write!(f, "Waiting for peers"), Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"), + Self::DownloadingTargetBlock => write!(f, "Downloading target block"), Self::DownloadingState => write!(f, "Downloading state"), Self::ImportingState => write!(f, "Importing state"), Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n), diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 9bcf363cd0692..a7af43d53d3b7 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -627,6 +627,7 @@ where CustomMessageOutcome::BlockImport(origin, blocks), Ok(OnBlockData::Request(peer, req)) => prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, peer, req), + Ok(OnBlockData::Continue) => CustomMessageOutcome::None, Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); @@ -974,6 +975,7 @@ where CustomMessageOutcome::BlockImport(origin, blocks), Ok(OnBlockData::Request(peer, req)) => prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, peer, req), + Ok(OnBlockData::Continue) => CustomMessageOutcome::None, Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index aae5f4de353fe..6ad4a8fbbdcc5 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -80,6 +80,7 @@ use std::{ pin::Pin, sync::Arc, }; +use warp::TargetBlockImportResult; mod extra_requests; @@ -315,6 +316,8 @@ pub enum PeerSyncState { DownloadingState, /// Downloading warp proof. DownloadingWarpProof, + /// Downloading warp sync target block. + DownloadingWarpTargetBlock, /// Actively downloading block history after warp sync. DownloadingGap(NumberFor), } @@ -659,10 +662,11 @@ where } fn block_requests(&mut self) -> Box)> + '_> { - if self.allowed_requests.is_empty() || - self.state_sync.is_some() || - self.mode == SyncMode::Warp - { + if self.mode == SyncMode::Warp { + return Box::new(std::iter::once(self.warp_target_block_request()).flatten()) + } + + if self.allowed_requests.is_empty() || self.state_sync.is_some() { return Box::new(std::iter::empty()) } @@ -824,7 +828,7 @@ where // Only one pending state request is allowed. return None } - if let Some(request) = sync.next_warp_poof_request() { + if let Some(request) = sync.next_warp_proof_request() { let mut targets: Vec<_> = self.peers.values().map(|p| p.best_number).collect(); if !targets.is_empty() { targets.sort(); @@ -1031,6 +1035,40 @@ where Vec::new() } }, + PeerSyncState::DownloadingWarpTargetBlock => { + peer.state = PeerSyncState::Available; + if let Some(warp_sync) = &mut self.warp_sync { + if blocks.len() == 1 { + validate_blocks::(&blocks, who, Some(request))?; + match warp_sync.import_target_block( + blocks.pop().expect("`blocks` len checked above."), + ) { + TargetBlockImportResult::Success => + return Ok(OnBlockData::Continue), + TargetBlockImportResult::BadResponse => + return Err(BadPeer(*who, rep::VERIFICATION_FAIL)), + } + } else if blocks.is_empty() { + debug!(target: "sync", "Empty block response from {}", who); + return Err(BadPeer(*who, rep::NO_BLOCK)) + } else { + debug!( + target: "sync", + "Too many blocks ({}) in warp target block response from {}", + blocks.len(), + who, + ); + return Err(BadPeer(*who, rep::NOT_REQUESTED)) + } + } else { + debug!( + target: "sync", + "Logic error: we think we are downloading warp target block from {}, but no warp sync is happening.", + who, + ); + return Ok(OnBlockData::Continue) + } + }, PeerSyncState::Available | PeerSyncState::DownloadingJustification(..) | PeerSyncState::DownloadingState | @@ -1112,14 +1150,14 @@ where }; match import_result { - state::ImportResult::Import(hash, header, state) => { + state::ImportResult::Import(hash, header, state, body, justifications) => { let origin = BlockOrigin::NetworkInitialSync; let block = IncomingBlock { hash, header: Some(header), - body: None, + body, indexed_body: None, - justifications: None, + justifications, origin: None, allow_missing_state: true, import_existing: true, @@ -1399,8 +1437,13 @@ where number, hash, ); - self.state_sync = - Some(StateSync::new(self.client.clone(), header, *skip_proofs)); + self.state_sync = Some(StateSync::new( + self.client.clone(), + header, + None, + None, + *skip_proofs, + )); self.allowed_requests.set_all(); } } @@ -2163,6 +2206,33 @@ where }) .collect() } + + /// Generate block request for downloading of the target block body during warp sync. + fn warp_target_block_request(&mut self) -> Option<(&PeerId, BlockRequest)> { + if let Some(sync) = &self.warp_sync { + if self.allowed_requests.is_empty() || + sync.is_complete() || + self.peers + .iter() + .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpTargetBlock) + { + // Only one pending warp target block request is allowed. + return None + } + if let Some((target_number, request)) = sync.next_target_block_request() { + // Find a random peer that has a block with the target number. + for (id, peer) in self.peers.iter_mut() { + if peer.state.is_available() && peer.best_number >= target_number { + trace!(target: "sync", "New warp target block request for {}", id); + peer.state = PeerSyncState::DownloadingWarpTargetBlock; + self.allowed_requests.clear(); + return Some((id, request)) + } + } + } + } + None + } } // This is purely during a backwards compatible transitionary period and should be removed diff --git a/client/network/sync/src/state.rs b/client/network/sync/src/state.rs index e70d3b6b33a28..9f64b52334c8a 100644 --- a/client/network/sync/src/state.rs +++ b/client/network/sync/src/state.rs @@ -26,7 +26,10 @@ use sc_consensus::ImportedState; use sc_network_common::sync::StateDownloadProgress; use smallvec::SmallVec; use sp_core::storage::well_known_keys; -use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; +use sp_runtime::{ + traits::{Block as BlockT, Header, NumberFor}, + Justifications, +}; use std::{collections::HashMap, sync::Arc}; /// State sync state machine. Accumulates partial state data until it @@ -35,6 +38,8 @@ pub struct StateSync { target_block: B::Hash, target_header: B::Header, target_root: B::Hash, + target_body: Option>, + target_justifications: Option, last_key: SmallVec<[Vec; 2]>, state: HashMap, (Vec<(Vec, Vec)>, Vec>)>, complete: bool, @@ -46,7 +51,7 @@ pub struct StateSync { /// Import state chunk result. pub enum ImportResult { /// State is complete and ready for import. - Import(B::Hash, B::Header, ImportedState), + Import(B::Hash, B::Header, ImportedState, Option>, Option), /// Continue downloading. Continue, /// Bad state chunk. @@ -59,12 +64,20 @@ where Client: ProofProvider + Send + Sync + 'static, { /// Create a new instance. - pub fn new(client: Arc, target: B::Header, skip_proof: bool) -> Self { + pub fn new( + client: Arc, + target_header: B::Header, + target_body: Option>, + target_justifications: Option, + skip_proof: bool, + ) -> Self { Self { client, - target_block: target.hash(), - target_root: *target.state_root(), - target_header: target, + target_block: target_header.hash(), + target_root: *target_header.state_root(), + target_header, + target_body, + target_justifications, last_key: SmallVec::default(), state: HashMap::default(), complete: false, @@ -213,6 +226,8 @@ where block: self.target_block, state: std::mem::take(&mut self.state).into(), }, + self.target_body.clone(), + self.target_justifications.clone(), ) } else { ImportResult::Continue diff --git a/client/network/sync/src/warp.rs b/client/network/sync/src/warp.rs index f3fad6c1b7fdb..4f2a71d98613e 100644 --- a/client/network/sync/src/warp.rs +++ b/client/network/sync/src/warp.rs @@ -23,17 +23,21 @@ use crate::{ state::{ImportResult, StateSync}, }; use sc_client_api::ProofProvider; -use sc_network_common::sync::warp::{ - EncodedProof, VerificationResult, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, - WarpSyncProvider, +use sc_network_common::sync::{ + message::{BlockAttributes, BlockData, BlockRequest, Direction, FromBlock}, + warp::{ + EncodedProof, VerificationResult, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, + WarpSyncProvider, + }, }; use sp_blockchain::HeaderBackend; use sp_finality_grandpa::{AuthorityList, SetId}; -use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; +use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; use std::sync::Arc; enum Phase { WarpProof { set_id: SetId, authorities: AuthorityList, last_hash: B::Hash }, + TargetBlock(B::Header), State(StateSync), } @@ -45,6 +49,14 @@ pub enum WarpProofImportResult { BadResponse, } +/// Import target block result. +pub enum TargetBlockImportResult { + /// Import was successful. + Success, + /// Invalid block. + BadResponse, +} + /// Warp sync state machine. Accumulates warp proofs and state. pub struct WarpSync { phase: Phase, @@ -72,7 +84,7 @@ where /// Validate and import a state response. pub fn import_state(&mut self, response: StateResponse) -> ImportResult { match &mut self.phase { - Phase::WarpProof { .. } => { + Phase::WarpProof { .. } | Phase::TargetBlock(_) => { log::debug!(target: "sync", "Unexpected state response"); ImportResult::BadResponse }, @@ -83,7 +95,7 @@ where /// Validate and import a warp proof response. pub fn import_warp_proof(&mut self, response: EncodedProof) -> WarpProofImportResult { match &mut self.phase { - Phase::State(_) => { + Phase::State(_) | Phase::TargetBlock(_) => { log::debug!(target: "sync", "Unexpected warp proof response"); WarpProofImportResult::BadResponse }, @@ -104,8 +116,7 @@ where Ok(VerificationResult::Complete(new_set_id, _, header)) => { log::debug!(target: "sync", "Verified complete proof, set_id={:?}", new_set_id); self.total_proof_bytes += response.0.len() as u64; - let state_sync = StateSync::new(self.client.clone(), header, false); - self.phase = Phase::State(state_sync); + self.phase = Phase::TargetBlock(header); WarpProofImportResult::Success }, } @@ -113,35 +124,100 @@ where } } + /// Import the target block body. + pub fn import_target_block(&mut self, block: BlockData) -> TargetBlockImportResult { + match &mut self.phase { + Phase::WarpProof { .. } | Phase::State(_) => { + log::debug!(target: "sync", "Unexpected target block response"); + TargetBlockImportResult::BadResponse + }, + Phase::TargetBlock(header) => + if let Some(block_header) = &block.header { + if block_header == header { + if block.body.is_some() { + let state_sync = StateSync::new( + self.client.clone(), + header.clone(), + block.body, + block.justifications, + false, + ); + self.phase = Phase::State(state_sync); + TargetBlockImportResult::Success + } else { + log::debug!( + target: "sync", + "Importing target block failed: missing body.", + ); + TargetBlockImportResult::BadResponse + } + } else { + log::debug!( + target: "sync", + "Importing target block failed: different header.", + ); + TargetBlockImportResult::BadResponse + } + } else { + log::debug!(target: "sync", "Importing target block failed: missing header."); + TargetBlockImportResult::BadResponse + }, + } + } + /// Produce next state request. pub fn next_state_request(&self) -> Option { match &self.phase { Phase::WarpProof { .. } => None, + Phase::TargetBlock(_) => None, Phase::State(sync) => Some(sync.next_request()), } } /// Produce next warp proof request. - pub fn next_warp_poof_request(&self) -> Option> { + pub fn next_warp_proof_request(&self) -> Option> { match &self.phase { - Phase::State(_) => None, Phase::WarpProof { last_hash, .. } => Some(WarpProofRequest { begin: *last_hash }), + Phase::TargetBlock(_) => None, + Phase::State(_) => None, + } + } + + /// Produce next target block request. + pub fn next_target_block_request(&self) -> Option<(NumberFor, BlockRequest)> { + match &self.phase { + Phase::WarpProof { .. } => None, + Phase::TargetBlock(header) => { + let request = BlockRequest:: { + id: 0, + fields: BlockAttributes::HEADER | + BlockAttributes::BODY | BlockAttributes::JUSTIFICATION, + from: FromBlock::Hash(header.hash()), + to: Some(header.hash()), + direction: Direction::Ascending, + max: Some(1), + }; + Some((*header.number(), request)) + }, + Phase::State(_) => None, } } /// Return target block hash if it is known. pub fn target_block_hash(&self) -> Option { match &self.phase { - Phase::State(s) => Some(s.target()), Phase::WarpProof { .. } => None, + Phase::TargetBlock(_) => None, + Phase::State(s) => Some(s.target()), } } /// Return target block number if it is known. pub fn target_block_number(&self) -> Option> { match &self.phase { - Phase::State(s) => Some(s.target_block_num()), Phase::WarpProof { .. } => None, + Phase::TargetBlock(header) => Some(*header.number()), + Phase::State(s) => Some(s.target_block_num()), } } @@ -149,6 +225,7 @@ where pub fn is_complete(&self) -> bool { match &self.phase { Phase::WarpProof { .. } => false, + Phase::TargetBlock(_) => false, Phase::State(sync) => sync.is_complete(), } } @@ -160,6 +237,10 @@ where phase: WarpSyncPhase::DownloadingWarpProofs, total_bytes: self.total_proof_bytes, }, + Phase::TargetBlock(_) => WarpSyncProgress { + phase: WarpSyncPhase::DownloadingTargetBlock, + total_bytes: self.total_proof_bytes, + }, Phase::State(sync) => WarpSyncProgress { phase: if self.is_complete() { WarpSyncPhase::ImportingState diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 5a29e587ceff5..e78b91a4e04ee 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -69,7 +69,7 @@ use sc_network_sync::{ use sc_service::client::Client; use sp_blockchain::{ well_known_cache_keys::{self, Id as CacheKeyId}, - HeaderBackend, Info as BlockchainInfo, Result as ClientResult, + Backend as BlockchainBackend, HeaderBackend, Info as BlockchainInfo, Result as ClientResult, }; use sp_consensus::{ block_validation::{BlockAnnounceValidator, DefaultBlockAnnounceValidator}, @@ -540,6 +540,13 @@ where .map(|backend| backend.blockchain().header(BlockId::hash(*hash)).unwrap().is_some()) .unwrap_or(false) } + + pub fn has_body(&self, hash: &H256) -> bool { + self.backend + .as_ref() + .map(|backend| backend.blockchain().body(BlockId::hash(*hash)).unwrap().is_some()) + .unwrap_or(false) + } } pub trait BlockImportAdapterFull: diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index c0778767b75af..6115e0e3b2c86 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -1192,7 +1192,7 @@ fn warp_sync() { ..Default::default() }); let gap_end = net.peer(0).push_blocks(63, false); - net.peer(0).push_blocks(1, false); + let target = net.peer(0).push_blocks(1, false); net.peer(1).push_blocks(64, false); net.peer(2).push_blocks(64, false); // Wait for peer 1 to sync state. @@ -1203,7 +1203,7 @@ fn warp_sync() { // Wait for peer 1 download block history block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(3).has_block(&gap_end) { + if net.peer(3).has_body(&gap_end) && net.peer(3).has_body(&target) { Poll::Ready(()) } else { Poll::Pending From de5a7f60a5144d79e3641ac7fe9d2019aef35931 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 20 Sep 2022 18:18:03 +0300 Subject: [PATCH 1180/1472] rpc: Implement `chainSpec` RPC API (#12261) * rpc/chain_spec: Add traits for `chainSpec` API Signed-off-by: Alexandru Vasile * rpc/chain_spec: Implement `chainSpec` RPC methods Signed-off-by: Alexandru Vasile * rpc/chain_spec: Add tests Signed-off-by: Alexandru Vasile * bin/node: Enable `chainSpec` API Signed-off-by: Alexandru Vasile * rpc/chain_spec: Assume `genesis_hash` as non-empty Signed-off-by: Alexandru Vasile * Update client/rpc-spec/Cargo.toml Co-authored-by: Niklas Adolfsson * Update client/rpc-spec/src/lib.rs Co-authored-by: Niklas Adolfsson * client/rpc_spec: Rename crate to `rpc_spec_v2` Signed-off-by: Alexandru Vasile * rpc-servers: Remove the `version` field from `rpc_methods` Signed-off-by: Alexandru Vasile * rpc/chain_spec: Fix copyright years Signed-off-by: Alexandru Vasile Signed-off-by: Alexandru Vasile Co-authored-by: Niklas Adolfsson --- Cargo.lock | 12 ++++ Cargo.toml | 1 + bin/node/rpc/Cargo.toml | 1 + bin/node/rpc/src/lib.rs | 6 ++ client/rpc-servers/src/lib.rs | 1 - client/rpc-spec-v2/Cargo.toml | 23 +++++++ client/rpc-spec-v2/README.md | 5 ++ client/rpc-spec-v2/src/chain_spec/api.rs | 53 ++++++++++++++++ .../rpc-spec-v2/src/chain_spec/chain_spec.rs | 60 ++++++++++++++++++ client/rpc-spec-v2/src/chain_spec/mod.rs | 38 ++++++++++++ client/rpc-spec-v2/src/chain_spec/tests.rs | 61 +++++++++++++++++++ client/rpc-spec-v2/src/lib.rs | 26 ++++++++ 12 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 client/rpc-spec-v2/Cargo.toml create mode 100644 client/rpc-spec-v2/README.md create mode 100644 client/rpc-spec-v2/src/chain_spec/api.rs create mode 100644 client/rpc-spec-v2/src/chain_spec/chain_spec.rs create mode 100644 client/rpc-spec-v2/src/chain_spec/mod.rs create mode 100644 client/rpc-spec-v2/src/chain_spec/tests.rs create mode 100644 client/rpc-spec-v2/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 8216b8b92aef5..d04f82f4bbecc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4836,6 +4836,7 @@ dependencies = [ "sc-finality-grandpa-rpc", "sc-rpc", "sc-rpc-api", + "sc-rpc-spec-v2", "sc-sync-state-rpc", "sc-transaction-pool-api", "sp-api", @@ -8774,6 +8775,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "sc-rpc-spec-v2" +version = "0.10.0-dev" +dependencies = [ + "hex", + "jsonrpsee", + "sc-chain-spec", + "serde_json", + "tokio", +] + [[package]] name = "sc-runtime-test" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 4dbf65dc7e1fe..48a31940fd3bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ members = [ "client/rpc", "client/rpc-api", "client/rpc-servers", + "client/rpc-spec-v2", "client/service", "client/service/test", "client/state-db", diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 851eb2cfc5104..0b69ae27010fa 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -26,6 +26,7 @@ sc-finality-grandpa = { version = "0.10.0-dev", path = "../../../client/finality sc-finality-grandpa-rpc = { version = "0.10.0-dev", path = "../../../client/finality-grandpa/rpc" } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" } +sc-rpc-spec-v2 = { version = "0.10.0-dev", path = "../../../client/rpc-spec-v2" } sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state-rpc" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 1c8b9cce1a744..0e6b04087fa63 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -124,6 +124,7 @@ where use sc_consensus_babe_rpc::{Babe, BabeApiServer}; use sc_finality_grandpa_rpc::{Grandpa, GrandpaApiServer}; use sc_rpc::dev::{Dev, DevApiServer}; + use sc_rpc_spec_v2::chain_spec::{ChainSpec, ChainSpecApiServer}; use sc_sync_state_rpc::{SyncState, SyncStateApiServer}; use substrate_frame_rpc_system::{System, SystemApiServer}; use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; @@ -140,6 +141,11 @@ where finality_provider, } = grandpa; + let chain_name = chain_spec.name().to_string(); + let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); + let properties = chain_spec.properties(); + io.merge(ChainSpec::new(chain_name, genesis_hash, properties).into_rpc())?; + io.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; // Making synchronous calls in light client freezes the browser currently, // more context: https://github.com/paritytech/substrate/pull/3480 diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 68b4aa6767348..0e2aca0dcc829 100644 --- a/client/rpc-servers/src/lib.rs +++ b/client/rpc-servers/src/lib.rs @@ -203,7 +203,6 @@ fn build_rpc_api(mut rpc_api: RpcModule) -> RpcModu rpc_api .register_method("rpc_methods", move |_, _| { Ok(serde_json::json!({ - "version": 1, "methods": available_methods, })) }) diff --git a/client/rpc-spec-v2/Cargo.toml b/client/rpc-spec-v2/Cargo.toml new file mode 100644 index 0000000000000..12dec7464e6d0 --- /dev/null +++ b/client/rpc-spec-v2/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "sc-rpc-spec-v2" +version = "0.10.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Substrate RPC interface v2." +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +# Internal chain structures for "chain_spec". +sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } +hex = "0.4" + +[dev-dependencies] +serde_json = "1.0" +tokio = { version = "1.17.0", features = ["macros"] } diff --git a/client/rpc-spec-v2/README.md b/client/rpc-spec-v2/README.md new file mode 100644 index 0000000000000..e860e0c2334da --- /dev/null +++ b/client/rpc-spec-v2/README.md @@ -0,0 +1,5 @@ +Substrate RPC interfaces. + +A collection of RPC methods and subscriptions supported by all substrate clients. + +License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file diff --git a/client/rpc-spec-v2/src/chain_spec/api.rs b/client/rpc-spec-v2/src/chain_spec/api.rs new file mode 100644 index 0000000000000..dfe2d76de6501 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_spec/api.rs @@ -0,0 +1,53 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! API trait of the chain spec. + +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use sc_chain_spec::Properties; + +#[rpc(client, server)] +pub trait ChainSpecApi { + /// Get the chain name, as present in the chain specification. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "chainSpec_unstable_chainName")] + fn chain_spec_unstable_chain_name(&self) -> RpcResult; + + /// Get the chain's genesis hash. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "chainSpec_unstable_genesisHash")] + fn chain_spec_unstable_genesis_hash(&self) -> RpcResult; + + /// Get the properties of the chain, as present in the chain specification. + /// + /// # Note + /// + /// The json whitespaces are not guaranteed to persist. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "chainSpec_unstable_properties")] + fn chain_spec_unstable_properties(&self) -> RpcResult; +} diff --git a/client/rpc-spec-v2/src/chain_spec/chain_spec.rs b/client/rpc-spec-v2/src/chain_spec/chain_spec.rs new file mode 100644 index 0000000000000..90d05f1d9d41d --- /dev/null +++ b/client/rpc-spec-v2/src/chain_spec/chain_spec.rs @@ -0,0 +1,60 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! API implementation for the specification of a chain. + +use crate::chain_spec::api::ChainSpecApiServer; +use jsonrpsee::core::RpcResult; +use sc_chain_spec::Properties; + +/// An API for chain spec RPC calls. +pub struct ChainSpec { + /// The name of the chain. + name: String, + /// The hexadecimal encoded hash of the genesis block. + genesis_hash: String, + /// Chain properties. + properties: Properties, +} + +impl ChainSpec { + /// Creates a new [`ChainSpec`]. + pub fn new>( + name: String, + genesis_hash: Hash, + properties: Properties, + ) -> Self { + let genesis_hash = format!("0x{}", hex::encode(genesis_hash)); + + Self { name, properties, genesis_hash } + } +} + +impl ChainSpecApiServer for ChainSpec { + fn chain_spec_unstable_chain_name(&self) -> RpcResult { + Ok(self.name.clone()) + } + + fn chain_spec_unstable_genesis_hash(&self) -> RpcResult { + Ok(self.genesis_hash.clone()) + } + + fn chain_spec_unstable_properties(&self) -> RpcResult { + Ok(self.properties.clone()) + } +} diff --git a/client/rpc-spec-v2/src/chain_spec/mod.rs b/client/rpc-spec-v2/src/chain_spec/mod.rs new file mode 100644 index 0000000000000..cd4fcf246f603 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_spec/mod.rs @@ -0,0 +1,38 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate chain specification API. +//! +//! The *chain spec* (short for *chain specification*) allows inspecting the content of +//! the specification of the chain that a JSON-RPC server is targeting. +//! +//! The values returned by the API are guaranteed to never change during the lifetime of the +//! JSON-RPC server. +//! +//! # Note +//! +//! Methods are prefixed by `chainSpec`. + +#[cfg(test)] +mod tests; + +pub mod api; +pub mod chain_spec; + +pub use api::ChainSpecApiServer; +pub use chain_spec::ChainSpec; diff --git a/client/rpc-spec-v2/src/chain_spec/tests.rs b/client/rpc-spec-v2/src/chain_spec/tests.rs new file mode 100644 index 0000000000000..6c078b2974e98 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_spec/tests.rs @@ -0,0 +1,61 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; +use jsonrpsee::{types::EmptyParams, RpcModule}; +use sc_chain_spec::Properties; + +const CHAIN_NAME: &'static str = "TEST_CHAIN_NAME"; +const CHAIN_GENESIS: [u8; 32] = [0; 32]; +const CHAIN_PROPERTIES: &'static str = r#"{"three": "123", "one": 1, "two": 12}"#; + +fn api() -> RpcModule { + ChainSpec::new( + CHAIN_NAME.to_string(), + CHAIN_GENESIS, + serde_json::from_str(CHAIN_PROPERTIES).unwrap(), + ) + .into_rpc() +} + +#[tokio::test] +async fn chain_spec_chain_name_works() { + let name = api() + .call::<_, String>("chainSpec_unstable_chainName", EmptyParams::new()) + .await + .unwrap(); + assert_eq!(name, CHAIN_NAME); +} + +#[tokio::test] +async fn chain_spec_genesis_hash_works() { + let genesis = api() + .call::<_, String>("chainSpec_unstable_genesisHash", EmptyParams::new()) + .await + .unwrap(); + assert_eq!(genesis, format!("0x{}", hex::encode(CHAIN_GENESIS))); +} + +#[tokio::test] +async fn chain_spec_properties_works() { + let properties = api() + .call::<_, Properties>("chainSpec_unstable_properties", EmptyParams::new()) + .await + .unwrap(); + assert_eq!(properties, serde_json::from_str(CHAIN_PROPERTIES).unwrap()); +} diff --git a/client/rpc-spec-v2/src/lib.rs b/client/rpc-spec-v2/src/lib.rs new file mode 100644 index 0000000000000..297fda13172d6 --- /dev/null +++ b/client/rpc-spec-v2/src/lib.rs @@ -0,0 +1,26 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate JSON-RPC interface v2. +//! +//! Specification [document](https://paritytech.github.io/json-rpc-interface-spec/). + +#![warn(missing_docs)] +#![deny(unused_crate_dependencies)] + +pub mod chain_spec; From 006dbc01304b9d3644f3fc4c1bf0e610acd3ad90 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 20 Sep 2022 23:19:38 +0200 Subject: [PATCH 1181/1472] Use temporary db for benchmarking (#12254) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use temporary db for benchmarking If no db option was given benchmarks shall use temporary database. Otherwise the test can use locally stored database which maybe out-of-date causing test to fail. * nicer syntax * explanatory comment added * Update utils/frame/benchmarking-cli/src/lib.rs Co-authored-by: Bastian Köcher --- utils/frame/benchmarking-cli/src/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 6e4f092084ef5..a44a208b16ae9 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -30,6 +30,7 @@ pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, Requirements, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::OverheadCmd; pub use pallet::PalletCmd; +pub use sc_service::BasePath; pub use storage::StorageCmd; use sc_cli::{CliConfiguration, DatabaseParams, ImportParams, PruningParams, Result, SharedParams}; @@ -87,6 +88,19 @@ impl CliConfiguration for BenchmarkCmd { } } + fn base_path(&self) -> Result> { + let inner = unwrap_cmd! { + self, cmd, cmd.base_path() + }; + + // If the base path was not provided, benchmark command shall use temporary path. Otherwise + // we may end up using shared path, which may be inappropriate for benchmarking. + match inner { + Ok(None) => Some(BasePath::new_temp_dir()).transpose().map_err(|e| e.into()), + e => e, + } + } + fn pruning_params(&self) -> Option<&PruningParams> { unwrap_cmd! { self, cmd, cmd.pruning_params() From a47f200eebeb88a5bde6f1ed2be9728b82536dde Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Wed, 21 Sep 2022 00:13:09 +0200 Subject: [PATCH 1182/1472] BREAKING: Rename Origin (#12258) * BREAKING: Rename Origin * more renaming * a bit more renaming * fix * more fixing * fix in frame_support * even more fixes * fix * small fix * ... * update .stderr * docs * update docs * update docs * docs --- .../pallets/template/src/mock.rs | 2 +- .../pallets/template/src/tests.rs | 7 +- bin/node-template/runtime/src/lib.rs | 2 +- bin/node/runtime/src/lib.rs | 14 +- client/consensus/common/src/import_queue.rs | 20 +- .../common/src/import_queue/basic_queue.rs | 10 +- .../common/src/import_queue/buffered_link.rs | 6 +- client/network/src/behaviour.rs | 4 +- client/network/src/protocol.rs | 6 +- docs/Upgrading-2.0-to-3.0.md | 2 +- frame/alliance/src/lib.rs | 8 +- frame/alliance/src/mock.rs | 40 +- frame/alliance/src/tests.rs | 177 ++-- frame/assets/src/lib.rs | 2 +- frame/assets/src/mock.rs | 2 +- frame/assets/src/tests.rs | 614 ++++++++------ frame/atomic-swap/src/tests.rs | 22 +- frame/aura/src/mock.rs | 2 +- frame/authority-discovery/src/lib.rs | 2 +- frame/authorship/src/lib.rs | 4 +- frame/babe/src/mock.rs | 2 +- frame/babe/src/tests.rs | 24 +- frame/bags-list/src/mock.rs | 2 +- frame/bags-list/src/tests.rs | 59 +- frame/balances/src/tests.rs | 62 +- frame/balances/src/tests_composite.rs | 2 +- frame/balances/src/tests_local.rs | 2 +- frame/balances/src/tests_reentrancy.rs | 2 +- frame/beefy-mmr/src/mock.rs | 2 +- frame/beefy/src/mock.rs | 2 +- frame/benchmarking/src/baseline.rs | 2 +- frame/benchmarking/src/lib.rs | 12 +- frame/benchmarking/src/tests.rs | 4 +- frame/benchmarking/src/tests_instance.rs | 4 +- frame/bounties/src/benchmarking.rs | 8 +- frame/bounties/src/tests.rs | 275 ++++--- frame/child-bounties/src/tests.rs | 336 ++++---- frame/collective/src/lib.rs | 8 +- frame/collective/src/tests.rs | 293 ++++--- frame/contracts/src/exec.rs | 2 +- frame/contracts/src/lib.rs | 2 +- frame/contracts/src/tests.rs | 259 +++--- frame/conviction-voting/src/tests.rs | 343 ++++---- frame/democracy/src/benchmarking.rs | 16 +- frame/democracy/src/lib.rs | 24 +- frame/democracy/src/tests.rs | 10 +- frame/democracy/src/tests/cancellation.rs | 19 +- frame/democracy/src/tests/delegation.rs | 76 +- .../democracy/src/tests/external_proposing.rs | 60 +- frame/democracy/src/tests/fast_tracking.rs | 30 +- frame/democracy/src/tests/lock_voting.rs | 154 ++-- frame/democracy/src/tests/preimage.rs | 64 +- frame/democracy/src/tests/public_proposals.rs | 39 +- frame/democracy/src/tests/scheduling.rs | 26 +- frame/democracy/src/tests/voting.rs | 39 +- .../election-provider-multi-phase/src/lib.rs | 20 +- .../election-provider-multi-phase/src/mock.rs | 2 +- .../src/signed.rs | 62 +- .../src/unsigned.rs | 16 +- .../election-provider-support/src/onchain.rs | 2 +- frame/elections-phragmen/src/lib.rs | 769 +++++++++--------- frame/examples/basic/src/lib.rs | 2 +- frame/examples/basic/src/tests.rs | 10 +- frame/examples/offchain-worker/src/tests.rs | 6 +- frame/examples/parallel/src/tests.rs | 8 +- frame/executive/src/lib.rs | 4 +- frame/gilt/src/benchmarking.rs | 2 +- frame/gilt/src/lib.rs | 2 +- frame/gilt/src/mock.rs | 2 +- frame/gilt/src/tests.rs | 158 ++-- frame/grandpa/src/mock.rs | 2 +- frame/grandpa/src/tests.rs | 18 +- frame/identity/src/benchmarking.rs | 20 +- frame/identity/src/lib.rs | 4 +- frame/identity/src/tests.rs | 181 +++-- frame/im-online/src/mock.rs | 4 +- frame/im-online/src/tests.rs | 2 +- frame/indices/src/mock.rs | 2 +- frame/indices/src/tests.rs | 4 +- frame/lottery/src/benchmarking.rs | 6 +- frame/lottery/src/lib.rs | 4 +- frame/lottery/src/mock.rs | 2 +- frame/lottery/src/tests.rs | 110 +-- frame/membership/src/lib.rs | 71 +- frame/merkle-mountain-range/src/mock.rs | 2 +- frame/multisig/src/lib.rs | 2 +- frame/multisig/src/tests.rs | 202 ++--- frame/nicks/src/lib.rs | 43 +- frame/node-authorization/src/lib.rs | 8 +- frame/node-authorization/src/mock.rs | 2 +- frame/node-authorization/src/tests.rs | 100 ++- .../nomination-pools/benchmarking/src/lib.rs | 48 +- .../nomination-pools/benchmarking/src/mock.rs | 2 +- frame/nomination-pools/src/migration.rs | 2 +- frame/nomination-pools/src/mock.rs | 6 +- frame/nomination-pools/src/tests.rs | 631 +++++++------- .../nomination-pools/test-staking/src/lib.rs | 88 +- .../nomination-pools/test-staking/src/mock.rs | 4 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/offences/src/mock.rs | 2 +- frame/preimage/src/benchmarking.rs | 18 +- frame/preimage/src/lib.rs | 6 +- frame/preimage/src/mock.rs | 2 +- frame/preimage/src/tests.rs | 82 +- frame/proxy/src/lib.rs | 4 +- frame/proxy/src/tests.rs | 174 ++-- frame/randomness-collective-flip/src/lib.rs | 2 +- frame/ranked-collective/src/lib.rs | 28 +- frame/ranked-collective/src/tests.rs | 241 +++--- frame/recovery/src/lib.rs | 2 +- frame/recovery/src/mock.rs | 2 +- frame/recovery/src/tests.rs | 220 +++-- frame/referenda/src/benchmarking.rs | 24 +- frame/referenda/src/lib.rs | 12 +- frame/referenda/src/mock.rs | 14 +- frame/referenda/src/tests.rs | 86 +- frame/referenda/src/types.rs | 28 +- frame/remark/src/mock.rs | 2 +- frame/scheduler/src/benchmarking.rs | 2 +- frame/scheduler/src/lib.rs | 31 +- frame/scheduler/src/mock.rs | 6 +- frame/scheduler/src/tests.rs | 25 +- frame/scored-pool/README.md | 2 +- frame/scored-pool/src/lib.rs | 6 +- frame/scored-pool/src/mock.rs | 2 +- frame/scored-pool/src/tests.rs | 63 +- frame/session/benchmarking/src/mock.rs | 2 +- frame/session/src/mock.rs | 2 +- frame/session/src/tests.rs | 30 +- frame/society/src/lib.rs | 14 +- frame/society/src/mock.rs | 2 +- frame/society/src/tests.rs | 274 ++++--- frame/staking/src/benchmarking.rs | 8 +- frame/staking/src/mock.rs | 21 +- frame/staking/src/pallet/mod.rs | 12 +- frame/staking/src/tests.rs | 581 +++++++------ frame/state-trie-migration/src/lib.rs | 28 +- frame/sudo/src/lib.rs | 2 +- frame/sudo/src/mock.rs | 2 +- frame/sudo/src/tests.rs | 34 +- .../src/construct_runtime/expand/call.rs | 10 +- .../src/construct_runtime/expand/origin.rs | 34 +- .../procedural/src/pallet/expand/call.rs | 4 +- .../procedural/src/pallet/parse/mod.rs | 8 +- frame/support/src/dispatch.rs | 38 +- frame/support/src/error.rs | 2 +- frame/support/src/lib.rs | 6 +- .../src/storage/generator/double_map.rs | 4 +- frame/support/src/storage/generator/map.rs | 4 +- frame/support/src/storage/generator/mod.rs | 6 +- frame/support/src/storage/generator/nmap.rs | 4 +- frame/support/src/traits/dispatch.rs | 8 +- frame/support/src/traits/schedule.rs | 28 +- frame/support/test/compile_pass/src/lib.rs | 2 +- frame/support/test/src/lib.rs | 4 +- frame/support/test/tests/construct_runtime.rs | 10 +- .../no_std_genesis_config.rs | 2 +- .../old_unsupported_pallet_decl.rs | 2 +- .../pallet_error_too_large.rs | 2 +- .../undefined_call_part.rs | 2 +- .../undefined_event_part.rs | 2 +- .../undefined_genesis_config_part.rs | 2 +- .../undefined_inherent_part.rs | 2 +- .../undefined_origin_part.rs | 2 +- .../undefined_origin_part.stderr | 33 - .../undefined_validate_unsigned_part.rs | 2 +- ...served_keyword_two_times_integrity_test.rs | 2 +- ...ed_keyword_two_times_integrity_test.stderr | 2 +- ...eserved_keyword_two_times_on_initialize.rs | 2 +- ...ved_keyword_two_times_on_initialize.stderr | 2 +- frame/support/test/tests/decl_storage.rs | 16 +- .../tests/decl_storage_ui/config_duplicate.rs | 2 +- .../decl_storage_ui/config_get_duplicate.rs | 2 +- .../tests/decl_storage_ui/get_duplicate.rs | 2 +- frame/support/test/tests/final_keys.rs | 4 +- frame/support/test/tests/genesisconfig.rs | 4 +- frame/support/test/tests/instance.rs | 24 +- frame/support/test/tests/issue2219.rs | 4 +- frame/support/test/tests/origin.rs | 44 +- frame/support/test/tests/pallet.rs | 10 +- .../test/tests/pallet_compatibility.rs | 4 +- .../tests/pallet_compatibility_instance.rs | 4 +- frame/support/test/tests/pallet_instance.rs | 2 +- .../tests/pallet_with_name_trait_is_valid.rs | 4 +- frame/support/test/tests/storage_layers.rs | 17 +- .../support/test/tests/storage_transaction.rs | 4 +- frame/support/test/tests/system.rs | 4 +- frame/system/benches/bench.rs | 2 +- frame/system/benchmarking/src/mock.rs | 2 +- frame/system/src/lib.rs | 6 +- frame/system/src/mock.rs | 2 +- frame/system/src/tests.rs | 12 +- frame/timestamp/src/mock.rs | 2 +- frame/timestamp/src/tests.rs | 6 +- frame/tips/src/benchmarking.rs | 2 +- frame/tips/src/tests.rs | 129 +-- .../asset-tx-payment/src/tests.rs | 18 +- frame/transaction-payment/src/lib.rs | 2 +- frame/transaction-storage/src/lib.rs | 2 +- frame/transaction-storage/src/mock.rs | 4 +- frame/transaction-storage/src/tests.rs | 6 +- frame/treasury/src/benchmarking.rs | 6 +- frame/treasury/src/lib.rs | 6 +- frame/treasury/src/tests.rs | 120 +-- frame/uniques/src/lib.rs | 4 +- frame/uniques/src/mock.rs | 2 +- frame/uniques/src/tests.rs | 564 ++++++++----- frame/utility/src/benchmarking.rs | 6 +- frame/utility/src/lib.rs | 8 +- frame/utility/src/tests.rs | 74 +- frame/vesting/src/mock.rs | 2 +- frame/whitelist/src/benchmarking.rs | 8 +- frame/whitelist/src/lib.rs | 6 +- frame/whitelist/src/mock.rs | 2 +- frame/whitelist/src/tests.rs | 56 +- .../runtime/src/generic/checked_extrinsic.rs | 9 +- primitives/runtime/src/testing.rs | 11 +- primitives/runtime/src/traits.rs | 12 +- test-utils/runtime/src/lib.rs | 21 +- test-utils/runtime/src/system.rs | 2 +- utils/frame/rpc/support/src/lib.rs | 2 +- 221 files changed, 5238 insertions(+), 4205 deletions(-) diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index 3289ec2da4952..989681fa59a00 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -27,7 +27,7 @@ impl system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/bin/node-template/pallets/template/src/tests.rs b/bin/node-template/pallets/template/src/tests.rs index 2205658601721..527aec8ed00c0 100644 --- a/bin/node-template/pallets/template/src/tests.rs +++ b/bin/node-template/pallets/template/src/tests.rs @@ -5,7 +5,7 @@ use frame_support::{assert_noop, assert_ok}; fn it_works_for_default_value() { new_test_ext().execute_with(|| { // Dispatch a signed extrinsic. - assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); + assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); // Read pallet storage and assert an expected result. assert_eq!(TemplateModule::something(), Some(42)); }); @@ -15,6 +15,9 @@ fn it_works_for_default_value() { fn correct_error_for_none_value() { new_test_ext().execute_with(|| { // Ensure the expected error is thrown when no value is present. - assert_noop!(TemplateModule::cause_error(Origin::signed(1)), Error::::NoneValue); + assert_noop!( + TemplateModule::cause_error(RuntimeOrigin::signed(1)), + Error::::NoneValue + ); }); } diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index c309b27682080..f801068b10fda 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -174,7 +174,7 @@ impl frame_system::Config for Runtime { /// The ubiquitous event type. type RuntimeEvent = RuntimeEvent; /// The ubiquitous origin type. - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; /// Maximum number of block number to block hash mappings to keep (oldest pruned first). type BlockHashCount = BlockHashCount; /// The weight of database operations that the runtime can invoke. diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8b150dca849f0..21ed23d6244a5 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -205,7 +205,7 @@ impl frame_system::Config for Runtime { type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; type DbWeight = RocksDbWeight; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = Index; type BlockNumber = BlockNumber; @@ -346,7 +346,7 @@ parameter_types! { impl pallet_scheduler::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type PalletsOrigin = OriginCaller; type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; @@ -796,7 +796,7 @@ parameter_types! { pub struct TracksInfo; impl pallet_referenda::TracksInfo for TracksInfo { type Id = u16; - type Origin = ::PalletsOrigin; + type RuntimeOrigin = ::PalletsOrigin; fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { static DATA: [(u16, pallet_referenda::TrackInfo); 1] = [( 0u16, @@ -822,7 +822,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { )]; &DATA[..] } - fn track_for(id: &Self::Origin) -> Result { + fn track_for(id: &Self::RuntimeOrigin) -> Result { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { match system_origin { frame_system::RawOrigin::Root => Ok(0), @@ -957,7 +957,7 @@ parameter_types! { type CouncilCollective = pallet_collective::Instance1; impl pallet_collective::Config for Runtime { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type MotionDuration = CouncilMotionDuration; @@ -1014,7 +1014,7 @@ parameter_types! { type TechnicalCollective = pallet_collective::Instance2; impl pallet_collective::Config for Runtime { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type MotionDuration = TechnicalMotionDuration; @@ -1536,7 +1536,7 @@ parameter_types! { type AllianceCollective = pallet_collective::Instance3; impl pallet_collective::Config for Runtime { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type MotionDuration = AllianceMotionDuration; diff --git a/client/consensus/common/src/import_queue.rs b/client/consensus/common/src/import_queue.rs index c71e21ccd4b00..3741fa99663cd 100644 --- a/client/consensus/common/src/import_queue.rs +++ b/client/consensus/common/src/import_queue.rs @@ -62,8 +62,8 @@ pub type BoxBlockImport = pub type BoxJustificationImport = Box + Send + Sync>; -/// Maps to the Origin used by the network. -pub type Origin = libp2p::PeerId; +/// Maps to the RuntimeOrigin used by the network. +pub type RuntimeOrigin = libp2p::PeerId; /// Block data used by the queue. #[derive(Debug, PartialEq, Eq, Clone)] @@ -79,7 +79,7 @@ pub struct IncomingBlock { /// Justification(s) if requested. pub justifications: Option, /// The peer, we received this from - pub origin: Option, + pub origin: Option, /// Allow importing the block skipping state verification if parent state is missing. pub allow_missing_state: bool, /// Skip block execution and state verification. @@ -112,7 +112,7 @@ pub trait ImportQueue: Send { /// Import block justifications. fn import_justifications( &mut self, - who: Origin, + who: RuntimeOrigin, hash: B::Hash, number: NumberFor, justifications: Justifications, @@ -140,7 +140,7 @@ pub trait Link: Send { /// Justification import result. fn justification_imported( &mut self, - _who: Origin, + _who: RuntimeOrigin, _hash: &B::Hash, _number: NumberFor, _success: bool, @@ -155,9 +155,9 @@ pub trait Link: Send { #[derive(Debug, PartialEq)] pub enum BlockImportStatus { /// Imported known block. - ImportedKnown(N, Option), + ImportedKnown(N, Option), /// Imported unknown block. - ImportedUnknown(N, ImportedAux, Option), + ImportedUnknown(N, ImportedAux, Option), } impl BlockImportStatus { @@ -175,15 +175,15 @@ impl BlockImportStatus { pub enum BlockImportError { /// Block missed header, can't be imported #[error("block is missing a header (origin = {0:?})")] - IncompleteHeader(Option), + IncompleteHeader(Option), /// Block verification failed, can't be imported #[error("block verification failed (origin = {0:?}): {1}")] - VerificationFailed(Option, String), + VerificationFailed(Option, String), /// Block is known to be Bad #[error("bad block (origin = {0:?})")] - BadBlock(Option), + BadBlock(Option), /// Parent state is missing. #[error("block is missing parent state")] diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index 84ccba990e599..0e607159b75c3 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -34,7 +34,7 @@ use crate::{ import_queue::{ buffered_link::{self, BufferedLinkReceiver, BufferedLinkSender}, import_single_block_metered, BlockImportError, BlockImportStatus, BoxBlockImport, - BoxJustificationImport, ImportQueue, IncomingBlock, Link, Origin, Verifier, + BoxJustificationImport, ImportQueue, IncomingBlock, Link, RuntimeOrigin, Verifier, }, metrics::Metrics, }; @@ -120,7 +120,7 @@ impl ImportQueue for BasicQueue fn import_justifications( &mut self, - who: Origin, + who: RuntimeOrigin, hash: B::Hash, number: NumberFor, justifications: Justifications, @@ -152,7 +152,7 @@ mod worker_messages { pub struct ImportBlocks(pub BlockOrigin, pub Vec>); pub struct ImportJustification( - pub Origin, + pub RuntimeOrigin, pub B::Hash, pub NumberFor, pub Justification, @@ -289,7 +289,7 @@ impl BlockImportWorker { async fn import_justification( &mut self, - who: Origin, + who: RuntimeOrigin, hash: B::Hash, number: NumberFor, justification: Justification, @@ -530,7 +530,7 @@ mod tests { fn justification_imported( &mut self, - _who: Origin, + _who: RuntimeOrigin, hash: &Hash, _number: BlockNumber, _success: bool, diff --git a/client/consensus/common/src/import_queue/buffered_link.rs b/client/consensus/common/src/import_queue/buffered_link.rs index d3d91f5bd31c5..5d418dddf0853 100644 --- a/client/consensus/common/src/import_queue/buffered_link.rs +++ b/client/consensus/common/src/import_queue/buffered_link.rs @@ -38,7 +38,7 @@ //! }); //! ``` -use crate::import_queue::{Link, Origin}; +use crate::import_queue::{Link, RuntimeOrigin}; use futures::prelude::*; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -82,7 +82,7 @@ impl Clone for BufferedLinkSender { /// Internal buffered message. enum BlockImportWorkerMsg { BlocksProcessed(usize, usize, Vec<(BlockImportResult, B::Hash)>), - JustificationImported(Origin, B::Hash, NumberFor, bool), + JustificationImported(RuntimeOrigin, B::Hash, NumberFor, bool), RequestJustification(B::Hash, NumberFor), } @@ -100,7 +100,7 @@ impl Link for BufferedLinkSender { fn justification_imported( &mut self, - who: Origin, + who: RuntimeOrigin, hash: &B::Hash, number: NumberFor, success: bool, diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 88571647fb0e3..14962c837aa10 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -37,7 +37,7 @@ use libp2p::{ }; use log::debug; -use sc_consensus::import_queue::{IncomingBlock, Origin}; +use sc_consensus::import_queue::{IncomingBlock, RuntimeOrigin}; use sc_network_common::{ config::ProtocolId, protocol::{ @@ -103,7 +103,7 @@ where /// Event generated by `Behaviour`. pub enum BehaviourOut { BlockImport(BlockOrigin, Vec>), - JustificationImport(Origin, B::Hash, NumberFor, Justifications), + JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), /// Started a random iterative Kademlia discovery query. RandomKademliaStarted(ProtocolId), diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index a7af43d53d3b7..17187f2d63c1c 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -41,7 +41,9 @@ use message::{ use notifications::{Notifications, NotificationsOut}; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; use sc_client_api::HeaderBackend; -use sc_consensus::import_queue::{BlockImportError, BlockImportStatus, IncomingBlock, Origin}; +use sc_consensus::import_queue::{ + BlockImportError, BlockImportStatus, IncomingBlock, RuntimeOrigin, +}; use sc_network_common::{ config::ProtocolId, protocol::ProtocolName, @@ -1257,7 +1259,7 @@ fn prepare_warp_sync_request( #[must_use] pub enum CustomMessageOutcome { BlockImport(BlockOrigin, Vec>), - JustificationImport(Origin, B::Hash, NumberFor, Justifications), + JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), /// Notification protocols have been opened with a remote. NotificationStreamOpened { remote: PeerId, diff --git a/docs/Upgrading-2.0-to-3.0.md b/docs/Upgrading-2.0-to-3.0.md index 210023c3aec5a..7540e0d5b5b8c 100644 --- a/docs/Upgrading-2.0-to-3.0.md +++ b/docs/Upgrading-2.0-to-3.0.md @@ -147,7 +147,7 @@ And update the overall definition for weights on frame and a few related types a + type BlockWeights = RuntimeBlockWeights; + type BlockLength = RuntimeBlockLength; + type DbWeight = RocksDbWeight; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = Index; @@ -171,25 +198,19 @@ impl frame_system::Trait for Runtime { diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 9d320c4215a70..82c7e21dba3af 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -245,7 +245,7 @@ pub mod pallet { /// The outer call dispatch type. type Proposal: Parameter - + Dispatchable + + Dispatchable + From> + From> + GetDispatchInfo @@ -253,13 +253,13 @@ pub mod pallet { + IsType<::RuntimeCall>; /// Origin for admin-level operations, like setting the Alliance's rules. - type AdminOrigin: EnsureOrigin; + type AdminOrigin: EnsureOrigin; /// Origin that manages entry and forcible discharge from the Alliance. - type MembershipManager: EnsureOrigin; + type MembershipManager: EnsureOrigin; /// Origin for making announcements and adding/removing unscrupulous items. - type AnnouncementOrigin: EnsureOrigin; + type AnnouncementOrigin: EnsureOrigin; /// The currency used for deposits. type Currency: ReservableCurrency; diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index 42c97876d40b0..196e0003b537f 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -47,7 +47,7 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = BlockNumber; @@ -95,7 +95,7 @@ parameter_types! { } type AllianceCollective = pallet_collective::Instance1; impl pallet_collective::Config for Test { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type MotionDuration = MotionDuration; @@ -283,7 +283,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 1)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 1)); let info = IdentityInfo { additional: BoundedVec::default(), @@ -296,58 +296,58 @@ pub fn new_test_ext() -> sp_io::TestExternalities { image: Data::default(), twitter: Data::default(), }; - assert_ok!(Identity::set_identity(Origin::signed(1), Box::new(info.clone()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(1), Box::new(info.clone()))); assert_ok!(Identity::provide_judgement( - Origin::signed(1), + RuntimeOrigin::signed(1), 0, 1, Judgement::KnownGood, BlakeTwo256::hash_of(&info) )); - assert_ok!(Identity::set_identity(Origin::signed(2), Box::new(info.clone()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(2), Box::new(info.clone()))); assert_ok!(Identity::provide_judgement( - Origin::signed(1), + RuntimeOrigin::signed(1), 0, 2, Judgement::KnownGood, BlakeTwo256::hash_of(&info) )); - assert_ok!(Identity::set_identity(Origin::signed(3), Box::new(info.clone()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(3), Box::new(info.clone()))); assert_ok!(Identity::provide_judgement( - Origin::signed(1), + RuntimeOrigin::signed(1), 0, 3, Judgement::KnownGood, BlakeTwo256::hash_of(&info) )); - assert_ok!(Identity::set_identity(Origin::signed(4), Box::new(info.clone()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(4), Box::new(info.clone()))); assert_ok!(Identity::provide_judgement( - Origin::signed(1), + RuntimeOrigin::signed(1), 0, 4, Judgement::KnownGood, BlakeTwo256::hash_of(&info) )); - assert_ok!(Identity::set_identity(Origin::signed(5), Box::new(info.clone()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(5), Box::new(info.clone()))); assert_ok!(Identity::provide_judgement( - Origin::signed(1), + RuntimeOrigin::signed(1), 0, 5, Judgement::KnownGood, BlakeTwo256::hash_of(&info) )); - assert_ok!(Identity::set_identity(Origin::signed(6), Box::new(info.clone()))); - assert_ok!(Identity::set_identity(Origin::signed(8), Box::new(info.clone()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(6), Box::new(info.clone()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(8), Box::new(info.clone()))); assert_ok!(Identity::provide_judgement( - Origin::signed(1), + RuntimeOrigin::signed(1), 0, 8, Judgement::KnownGood, BlakeTwo256::hash_of(&info) )); - assert_ok!(Identity::set_identity(Origin::signed(9), Box::new(info.clone()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(9), Box::new(info.clone()))); assert_ok!(Identity::provide_judgement( - Origin::signed(1), + RuntimeOrigin::signed(1), 0, 9, Judgement::KnownGood, @@ -356,11 +356,11 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // Joining before init should fail. assert_noop!( - Alliance::join_alliance(Origin::signed(1)), + Alliance::join_alliance(RuntimeOrigin::signed(1)), Error::::AllianceNotYetInitialized ); - assert_ok!(Alliance::init_members(Origin::root(), vec![1, 2], vec![3], vec![])); + assert_ok!(Alliance::init_members(RuntimeOrigin::root(), vec![1, 2], vec![3], vec![])); System::set_block_number(1); }); diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index 79fd33965edb5..c55826768c695 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -30,28 +30,31 @@ fn init_members_works() { new_test_ext().execute_with(|| { // alliance must be reset first, no witness data assert_noop!( - Alliance::init_members(Origin::root(), vec![8], vec![], vec![],), + Alliance::init_members(RuntimeOrigin::root(), vec![8], vec![], vec![],), Error::::AllianceAlreadyInitialized, ); // give a retirement notice to check later a retiring member not removed - assert_ok!(Alliance::give_retirement_notice(Origin::signed(2))); + assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(2))); assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); // disband the Alliance to init new - assert_ok!(Alliance::disband(Origin::root(), DisbandWitness::new(2, 0))); + assert_ok!(Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(2, 0))); // fails without root - assert_noop!(Alliance::init_members(Origin::signed(1), vec![], vec![], vec![]), BadOrigin); + assert_noop!( + Alliance::init_members(RuntimeOrigin::signed(1), vec![], vec![], vec![]), + BadOrigin + ); // founders missing, other members given assert_noop!( - Alliance::init_members(Origin::root(), vec![], vec![4], vec![2],), + Alliance::init_members(RuntimeOrigin::root(), vec![], vec![4], vec![2],), Error::::FoundersMissing, ); // success call - assert_ok!(Alliance::init_members(Origin::root(), vec![8, 5], vec![4], vec![2],)); + assert_ok!(Alliance::init_members(RuntimeOrigin::root(), vec![8, 5], vec![4], vec![2],)); // assert new set of voting members assert_eq!(Alliance::voting_members_sorted(), vec![4, 5, 8]); @@ -78,36 +81,36 @@ fn disband_works() { assert_eq!(Alliance::voting_members_sorted(), vec![1, 2, 3]); // give a retirement notice to check later a retiring member not removed - assert_ok!(Alliance::give_retirement_notice(Origin::signed(2))); + assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(2))); assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); // join alliance and reserve funds assert_eq!(Balances::free_balance(9), 40); - assert_ok!(Alliance::join_alliance(Origin::signed(9))); + assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(9))); assert_eq!(Alliance::deposit_of(9), Some(25)); assert_eq!(Balances::free_balance(9), 15); assert!(Alliance::is_member_of(&9, MemberRole::Ally)); // fails without root - assert_noop!(Alliance::disband(Origin::signed(1), Default::default()), BadOrigin); + assert_noop!(Alliance::disband(RuntimeOrigin::signed(1), Default::default()), BadOrigin); // bad witness data checks assert_noop!( - Alliance::disband(Origin::root(), Default::default(),), + Alliance::disband(RuntimeOrigin::root(), Default::default(),), Error::::BadWitness ); assert_noop!( - Alliance::disband(Origin::root(), DisbandWitness::new(1, 1)), + Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(1, 1)), Error::::BadWitness, ); assert_noop!( - Alliance::disband(Origin::root(), DisbandWitness::new(2, 0)), + Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(2, 0)), Error::::BadWitness, ); // success call - assert_ok!(Alliance::disband(Origin::root(), DisbandWitness::new(2, 1))); + assert_ok!(Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(2, 1))); // assert members disband assert!(!Alliance::is_member(&1)); @@ -125,7 +128,7 @@ fn disband_works() { // the Alliance must be set first assert_noop!( - Alliance::disband(Origin::root(), DisbandWitness::new(100, 100)), + Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(100, 100)), Error::::AllianceNotYetInitialized, ); }) @@ -138,12 +141,17 @@ fn propose_works() { // only voting member can propose proposal, 4 is ally not have vote rights assert_noop!( - Alliance::propose(Origin::signed(4), 3, Box::new(proposal.clone()), proposal_len), + Alliance::propose( + RuntimeOrigin::signed(4), + 3, + Box::new(proposal.clone()), + proposal_len + ), Error::::NoVotingRights ); assert_ok!(Alliance::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len @@ -171,12 +179,12 @@ fn vote_works() { new_test_ext().execute_with(|| { let (proposal, proposal_len, hash) = make_remark_proposal(42); assert_ok!(Alliance::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Alliance::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Alliance::vote(RuntimeOrigin::signed(2), hash, 0, true)); let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; assert_eq!( @@ -205,21 +213,21 @@ fn veto_works() { new_test_ext().execute_with(|| { let (proposal, proposal_len, hash) = make_remark_proposal(42); assert_ok!(Alliance::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); // only set_rule/elevate_ally can be veto assert_noop!( - Alliance::veto(Origin::signed(1), hash), + Alliance::veto(RuntimeOrigin::signed(1), hash), Error::::NotVetoableProposal ); let cid = test_cid(); let (vetoable_proposal, vetoable_proposal_len, vetoable_hash) = make_set_rule_proposal(cid); assert_ok!(Alliance::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(vetoable_proposal.clone()), vetoable_proposal_len @@ -227,11 +235,11 @@ fn veto_works() { // only founder have veto rights, 3 is fellow assert_noop!( - Alliance::veto(Origin::signed(3), vetoable_hash), + Alliance::veto(RuntimeOrigin::signed(3), vetoable_hash), Error::::NotFounder ); - assert_ok!(Alliance::veto(Origin::signed(2), vetoable_hash)); + assert_ok!(Alliance::veto(RuntimeOrigin::signed(2), vetoable_hash)); let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; assert_eq!( System::events(), @@ -262,15 +270,21 @@ fn close_works() { let (proposal, proposal_len, hash) = make_remark_proposal(42); let proposal_weight = proposal.get_dispatch_info().weight; assert_ok!(Alliance::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Alliance::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Alliance::vote(Origin::signed(2), hash, 0, true)); - assert_ok!(Alliance::vote(Origin::signed(3), hash, 0, true)); - assert_ok!(Alliance::close(Origin::signed(1), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Alliance::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Alliance::vote(RuntimeOrigin::signed(2), hash, 0, true)); + assert_ok!(Alliance::vote(RuntimeOrigin::signed(3), hash, 0, true)); + assert_ok!(Alliance::close( + RuntimeOrigin::signed(1), + hash, + 0, + proposal_weight, + proposal_len + )); let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; assert_eq!( @@ -324,7 +338,7 @@ fn close_works() { fn set_rule_works() { new_test_ext().execute_with(|| { let cid = test_cid(); - assert_ok!(Alliance::set_rule(Origin::signed(1), cid.clone())); + assert_ok!(Alliance::set_rule(RuntimeOrigin::signed(1), cid.clone())); assert_eq!(Alliance::rule(), Some(cid.clone())); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::NewRuleSet { @@ -338,9 +352,9 @@ fn announce_works() { new_test_ext().execute_with(|| { let cid = test_cid(); - assert_noop!(Alliance::announce(Origin::signed(2), cid.clone()), BadOrigin); + assert_noop!(Alliance::announce(RuntimeOrigin::signed(2), cid.clone()), BadOrigin); - assert_ok!(Alliance::announce(Origin::signed(3), cid.clone())); + assert_ok!(Alliance::announce(RuntimeOrigin::signed(3), cid.clone())); assert_eq!(Alliance::announcements(), vec![cid.clone()]); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::Announced { @@ -353,7 +367,7 @@ fn announce_works() { fn remove_announcement_works() { new_test_ext().execute_with(|| { let cid = test_cid(); - assert_ok!(Alliance::announce(Origin::signed(3), cid.clone())); + assert_ok!(Alliance::announce(RuntimeOrigin::signed(3), cid.clone())); assert_eq!(Alliance::announcements(), vec![cid.clone()]); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::Announced { announcement: cid.clone(), @@ -361,7 +375,7 @@ fn remove_announcement_works() { System::set_block_number(2); - assert_ok!(Alliance::remove_announcement(Origin::signed(3), cid.clone())); + assert_ok!(Alliance::remove_announcement(RuntimeOrigin::signed(3), cid.clone())); assert_eq!(Alliance::announcements(), vec![]); System::assert_last_event(mock::RuntimeEvent::Alliance( crate::Event::AnnouncementRemoved { announcement: cid }, @@ -373,46 +387,52 @@ fn remove_announcement_works() { fn join_alliance_works() { new_test_ext().execute_with(|| { // check already member - assert_noop!(Alliance::join_alliance(Origin::signed(1)), Error::::AlreadyMember); + assert_noop!( + Alliance::join_alliance(RuntimeOrigin::signed(1)), + Error::::AlreadyMember + ); // check already listed as unscrupulous assert_ok!(Alliance::add_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(4)] )); assert_noop!( - Alliance::join_alliance(Origin::signed(4)), + Alliance::join_alliance(RuntimeOrigin::signed(4)), Error::::AccountNonGrata ); assert_ok!(Alliance::remove_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(4)] )); // check deposit funds assert_noop!( - Alliance::join_alliance(Origin::signed(5)), + Alliance::join_alliance(RuntimeOrigin::signed(5)), Error::::InsufficientFunds ); // success to submit - assert_ok!(Alliance::join_alliance(Origin::signed(4))); + assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); assert_eq!(Alliance::deposit_of(4), Some(25)); assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); // check already member - assert_noop!(Alliance::join_alliance(Origin::signed(4)), Error::::AlreadyMember); + assert_noop!( + Alliance::join_alliance(RuntimeOrigin::signed(4)), + Error::::AlreadyMember + ); // check missing identity judgement #[cfg(not(feature = "runtime-benchmarks"))] assert_noop!( - Alliance::join_alliance(Origin::signed(6)), + Alliance::join_alliance(RuntimeOrigin::signed(6)), Error::::WithoutGoodIdentityJudgement ); // check missing identity info #[cfg(not(feature = "runtime-benchmarks"))] assert_noop!( - Alliance::join_alliance(Origin::signed(7)), + Alliance::join_alliance(RuntimeOrigin::signed(7)), Error::::WithoutIdentityDisplayAndWebsite ); }); @@ -423,51 +443,51 @@ fn nominate_ally_works() { new_test_ext().execute_with(|| { // check already member assert_noop!( - Alliance::nominate_ally(Origin::signed(1), 2), + Alliance::nominate_ally(RuntimeOrigin::signed(1), 2), Error::::AlreadyMember ); // only voting member(founder/fellow) have nominate right assert_noop!( - Alliance::nominate_ally(Origin::signed(5), 4), + Alliance::nominate_ally(RuntimeOrigin::signed(5), 4), Error::::NoVotingRights ); // check already listed as unscrupulous assert_ok!(Alliance::add_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(4)] )); assert_noop!( - Alliance::nominate_ally(Origin::signed(1), 4), + Alliance::nominate_ally(RuntimeOrigin::signed(1), 4), Error::::AccountNonGrata ); assert_ok!(Alliance::remove_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(4)] )); // success to nominate - assert_ok!(Alliance::nominate_ally(Origin::signed(1), 4)); + assert_ok!(Alliance::nominate_ally(RuntimeOrigin::signed(1), 4)); assert_eq!(Alliance::deposit_of(4), None); assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); // check already member assert_noop!( - Alliance::nominate_ally(Origin::signed(1), 4), + Alliance::nominate_ally(RuntimeOrigin::signed(1), 4), Error::::AlreadyMember ); // check missing identity judgement #[cfg(not(feature = "runtime-benchmarks"))] assert_noop!( - Alliance::join_alliance(Origin::signed(6)), + Alliance::join_alliance(RuntimeOrigin::signed(6)), Error::::WithoutGoodIdentityJudgement ); // check missing identity info #[cfg(not(feature = "runtime-benchmarks"))] assert_noop!( - Alliance::join_alliance(Origin::signed(7)), + Alliance::join_alliance(RuntimeOrigin::signed(7)), Error::::WithoutIdentityDisplayAndWebsite ); }); @@ -476,13 +496,16 @@ fn nominate_ally_works() { #[test] fn elevate_ally_works() { new_test_ext().execute_with(|| { - assert_noop!(Alliance::elevate_ally(Origin::signed(2), 4), Error::::NotAlly); + assert_noop!( + Alliance::elevate_ally(RuntimeOrigin::signed(2), 4), + Error::::NotAlly + ); - assert_ok!(Alliance::join_alliance(Origin::signed(4))); + assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); - assert_ok!(Alliance::elevate_ally(Origin::signed(2), 4)); + assert_ok!(Alliance::elevate_ally(RuntimeOrigin::signed(2), 4)); assert_eq!(Alliance::members(MemberRole::Ally), Vec::::new()); assert_eq!(Alliance::members(MemberRole::Fellow), vec![3, 4]); }); @@ -492,12 +515,12 @@ fn elevate_ally_works() { fn give_retirement_notice_work() { new_test_ext().execute_with(|| { assert_noop!( - Alliance::give_retirement_notice(Origin::signed(4)), + Alliance::give_retirement_notice(RuntimeOrigin::signed(4)), Error::::NotMember ); assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); - assert_ok!(Alliance::give_retirement_notice(Origin::signed(3))); + assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(3))); assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); assert_eq!(Alliance::members(MemberRole::Retiring), vec![3]); System::assert_last_event(mock::RuntimeEvent::Alliance( @@ -505,7 +528,7 @@ fn give_retirement_notice_work() { )); assert_noop!( - Alliance::give_retirement_notice(Origin::signed(3)), + Alliance::give_retirement_notice(RuntimeOrigin::signed(3)), Error::::AlreadyRetiring ); }); @@ -515,23 +538,23 @@ fn give_retirement_notice_work() { fn retire_works() { new_test_ext().execute_with(|| { assert_noop!( - Alliance::retire(Origin::signed(2)), + Alliance::retire(RuntimeOrigin::signed(2)), Error::::RetirementNoticeNotGiven ); assert_noop!( - Alliance::retire(Origin::signed(4)), + Alliance::retire(RuntimeOrigin::signed(4)), Error::::RetirementNoticeNotGiven ); assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); - assert_ok!(Alliance::give_retirement_notice(Origin::signed(3))); + assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(3))); assert_noop!( - Alliance::retire(Origin::signed(3)), + Alliance::retire(RuntimeOrigin::signed(3)), Error::::RetirementPeriodNotPassed ); System::set_block_number(System::block_number() + RetirementPeriod::get()); - assert_ok!(Alliance::retire(Origin::signed(3))); + assert_ok!(Alliance::retire(RuntimeOrigin::signed(3))); assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberRetired { member: (3), @@ -541,11 +564,11 @@ fn retire_works() { // Move time on: System::set_block_number(System::block_number() + RetirementPeriod::get()); - assert_powerless(Origin::signed(3)); + assert_powerless(RuntimeOrigin::signed(3)); }); } -fn assert_powerless(user: Origin) { +fn assert_powerless(user: RuntimeOrigin) { //vote / veto with a valid propsal let cid = test_cid(); let (proposal, _, _) = make_kick_member_proposal(42); @@ -578,13 +601,16 @@ fn assert_powerless(user: Origin) { #[test] fn kick_member_works() { new_test_ext().execute_with(|| { - assert_noop!(Alliance::kick_member(Origin::signed(4), 4), BadOrigin); + assert_noop!(Alliance::kick_member(RuntimeOrigin::signed(4), 4), BadOrigin); - assert_noop!(Alliance::kick_member(Origin::signed(2), 4), Error::::NotMember); + assert_noop!( + Alliance::kick_member(RuntimeOrigin::signed(2), 4), + Error::::NotMember + ); >::insert(2, 25); assert_eq!(Alliance::members(MemberRole::Founder), vec![1, 2]); - assert_ok!(Alliance::kick_member(Origin::signed(2), 2)); + assert_ok!(Alliance::kick_member(RuntimeOrigin::signed(2), 2)); assert_eq!(Alliance::members(MemberRole::Founder), vec![1]); assert_eq!(>::get(2), None); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberKicked { @@ -597,10 +623,10 @@ fn kick_member_works() { #[test] fn add_unscrupulous_items_works() { new_test_ext().execute_with(|| { - assert_noop!(Alliance::add_unscrupulous_items(Origin::signed(2), vec![]), BadOrigin); + assert_noop!(Alliance::add_unscrupulous_items(RuntimeOrigin::signed(2), vec![]), BadOrigin); assert_ok!(Alliance::add_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![ UnscrupulousItem::AccountId(3), UnscrupulousItem::Website("abc".as_bytes().to_vec().try_into().unwrap()) @@ -611,7 +637,7 @@ fn add_unscrupulous_items_works() { assert_noop!( Alliance::add_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] ), Error::::AlreadyUnscrupulous @@ -622,23 +648,26 @@ fn add_unscrupulous_items_works() { #[test] fn remove_unscrupulous_items_works() { new_test_ext().execute_with(|| { - assert_noop!(Alliance::remove_unscrupulous_items(Origin::signed(2), vec![]), BadOrigin); + assert_noop!( + Alliance::remove_unscrupulous_items(RuntimeOrigin::signed(2), vec![]), + BadOrigin + ); assert_noop!( Alliance::remove_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] ), Error::::NotListedAsUnscrupulous ); assert_ok!(Alliance::add_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] )); assert_eq!(Alliance::unscrupulous_accounts(), vec![3]); assert_ok!(Alliance::remove_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] )); assert_eq!(Alliance::unscrupulous_accounts(), Vec::::new()); diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index fbb4a3ea1568b..28743f917d323 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -208,7 +208,7 @@ pub mod pallet { /// The origin which may forcibly create or destroy an asset or otherwise alter privileged /// attributes. - type ForceOrigin: EnsureOrigin; + type ForceOrigin: EnsureOrigin; /// The basic amount of funds that must be reserved for an asset. #[pallet::constant] diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 9344e5920d205..1f105eb6b4fbc 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -49,7 +49,7 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 598b6049b3d57..48cfad45a49fc 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -26,10 +26,10 @@ use sp_runtime::{traits::ConvertInto, TokenError}; #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); assert_eq!(Assets::balance(0, 2), 100); }); } @@ -37,46 +37,46 @@ fn basic_minting_should_work() { #[test] fn minting_too_many_insufficient_assets_fails() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); - assert_ok!(Assets::force_create(Origin::root(), 1, 1, false, 1)); - assert_ok!(Assets::force_create(Origin::root(), 2, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 2, 1, false, 1)); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 1, 1, 100)); - assert_noop!(Assets::mint(Origin::signed(1), 2, 1, 100), TokenError::CannotCreate); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 1, 1, 100)); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100), TokenError::CannotCreate); Balances::make_free_balance_be(&2, 1); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 2, 1, 100)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100)); }); } #[test] fn minting_insufficient_asset_with_deposit_should_work_when_consumers_exhausted() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); - assert_ok!(Assets::force_create(Origin::root(), 1, 1, false, 1)); - assert_ok!(Assets::force_create(Origin::root(), 2, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 2, 1, false, 1)); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 1, 1, 100)); - assert_noop!(Assets::mint(Origin::signed(1), 2, 1, 100), TokenError::CannotCreate); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 1, 1, 100)); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100), TokenError::CannotCreate); - assert_ok!(Assets::touch(Origin::signed(1), 2)); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 2)); assert_eq!(Balances::reserved_balance(&1), 10); - assert_ok!(Assets::mint(Origin::signed(1), 2, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100)); }); } #[test] fn minting_insufficient_assets_with_deposit_without_consumer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); - assert_noop!(Assets::mint(Origin::signed(1), 0, 1, 100), TokenError::CannotCreate); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100), TokenError::CannotCreate); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::touch(Origin::signed(1), 0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Balances::reserved_balance(&1), 10); assert_eq!(System::consumers(&1), 0); }); @@ -85,11 +85,11 @@ fn minting_insufficient_assets_with_deposit_without_consumer_should_work() { #[test] fn refunding_asset_deposit_with_burn_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::touch(Origin::signed(1), 0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::refund(Origin::signed(1), 0, true)); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::refund(RuntimeOrigin::signed(1), 0, true)); assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Assets::balance(1, 0), 0); }); @@ -98,28 +98,28 @@ fn refunding_asset_deposit_with_burn_should_work() { #[test] fn refunding_asset_deposit_with_burn_disallowed_should_fail() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::touch(Origin::signed(1), 0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_noop!(Assets::refund(Origin::signed(1), 0, false), Error::::WouldBurn); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_noop!(Assets::refund(RuntimeOrigin::signed(1), 0, false), Error::::WouldBurn); }); } #[test] fn refunding_asset_deposit_without_burn_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); - assert_noop!(Assets::mint(Origin::signed(1), 0, 1, 100), TokenError::CannotCreate); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100), TokenError::CannotCreate); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::touch(Origin::signed(1), 0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&2, 100); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 100)); assert_eq!(Assets::balance(0, 2), 100); assert_eq!(Assets::balance(0, 1), 0); assert_eq!(Balances::reserved_balance(&1), 10); - assert_ok!(Assets::refund(Origin::signed(1), 0, false)); + assert_ok!(Assets::refund(RuntimeOrigin::signed(1), 0, false)); assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Assets::balance(1, 0), 0); }); @@ -129,11 +129,11 @@ fn refunding_asset_deposit_without_burn_should_work() { #[test] fn refunding_calls_died_hook() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::touch(Origin::signed(1), 0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::refund(Origin::signed(1), 0, true)); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::refund(RuntimeOrigin::signed(1), 0, true)); assert_eq!(Asset::::get(0).unwrap().accounts, 0); assert_eq!(hooks(), vec![Hook::Died(0, 1)]); @@ -144,17 +144,20 @@ fn refunding_calls_died_hook() { fn approval_lifecycle_works() { new_test_ext().execute_with(|| { // can't approve non-existent token - assert_noop!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50), Error::::Unknown); + assert_noop!( + Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), + Error::::Unknown + ); // so we create it :) - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); assert_eq!(Balances::reserved_balance(&1), 1); - assert_ok!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 40)); + assert_ok!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 40)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); - assert_ok!(Assets::cancel_approval(Origin::signed(1), 0, 2)); + assert_ok!(Assets::cancel_approval(RuntimeOrigin::signed(1), 0, 2)); assert_eq!(Asset::::get(0).unwrap().approvals, 0); assert_eq!(Assets::balance(0, 1), 60); assert_eq!(Assets::balance(0, 3), 40); @@ -166,17 +169,20 @@ fn approval_lifecycle_works() { fn transfer_approved_all_funds() { new_test_ext().execute_with(|| { // can't approve non-existent token - assert_noop!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50), Error::::Unknown); + assert_noop!( + Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), + Error::::Unknown + ); // so we create it :) - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); assert_eq!(Balances::reserved_balance(&1), 1); // transfer the full amount, which should trigger auto-cleanup - assert_ok!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 50)); + assert_ok!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 0); assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 3), 50); @@ -187,20 +193,20 @@ fn transfer_approved_all_funds() { #[test] fn approval_deposits_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); let e = BalancesError::::InsufficientBalance; - assert_noop!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50), e); + assert_noop!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), e); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Balances::reserved_balance(&1), 1); - assert_ok!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 50)); + assert_ok!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 50)); assert_eq!(Balances::reserved_balance(&1), 0); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); - assert_ok!(Assets::cancel_approval(Origin::signed(1), 0, 2)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + assert_ok!(Assets::cancel_approval(RuntimeOrigin::signed(1), 0, 2)); assert_eq!(Balances::reserved_balance(&1), 0); }); } @@ -208,72 +214,84 @@ fn approval_deposits_work() { #[test] fn cannot_transfer_more_than_approved() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); let e = Error::::Unapproved; - assert_noop!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 51), e); + assert_noop!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 51), e); }); } #[test] fn cannot_transfer_more_than_exists() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 101)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 101)); let e = Error::::BalanceLow; - assert_noop!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 101), e); + assert_noop!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 101), e); }); } #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); - assert_noop!(Assets::cancel_approval(Origin::signed(1), 1, 2), Error::::Unknown); - assert_noop!(Assets::cancel_approval(Origin::signed(2), 0, 2), Error::::Unknown); - assert_noop!(Assets::cancel_approval(Origin::signed(1), 0, 3), Error::::Unknown); + assert_noop!( + Assets::cancel_approval(RuntimeOrigin::signed(1), 1, 2), + Error::::Unknown + ); + assert_noop!( + Assets::cancel_approval(RuntimeOrigin::signed(2), 0, 2), + Error::::Unknown + ); + assert_noop!( + Assets::cancel_approval(RuntimeOrigin::signed(1), 0, 3), + Error::::Unknown + ); assert_eq!(Asset::::get(0).unwrap().approvals, 1); - assert_ok!(Assets::cancel_approval(Origin::signed(1), 0, 2)); + assert_ok!(Assets::cancel_approval(RuntimeOrigin::signed(1), 0, 2)); assert_eq!(Asset::::get(0).unwrap().approvals, 0); - assert_noop!(Assets::cancel_approval(Origin::signed(1), 0, 2), Error::::Unknown); + assert_noop!( + Assets::cancel_approval(RuntimeOrigin::signed(1), 0, 2), + Error::::Unknown + ); }); } #[test] fn force_cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); let e = Error::::NoPermission; - assert_noop!(Assets::force_cancel_approval(Origin::signed(2), 0, 1, 2), e); + assert_noop!(Assets::force_cancel_approval(RuntimeOrigin::signed(2), 0, 1, 2), e); assert_noop!( - Assets::force_cancel_approval(Origin::signed(1), 1, 1, 2), + Assets::force_cancel_approval(RuntimeOrigin::signed(1), 1, 1, 2), Error::::Unknown ); assert_noop!( - Assets::force_cancel_approval(Origin::signed(1), 0, 2, 2), + Assets::force_cancel_approval(RuntimeOrigin::signed(1), 0, 2, 2), Error::::Unknown ); assert_noop!( - Assets::force_cancel_approval(Origin::signed(1), 0, 1, 3), + Assets::force_cancel_approval(RuntimeOrigin::signed(1), 0, 1, 3), Error::::Unknown ); assert_eq!(Asset::::get(0).unwrap().approvals, 1); - assert_ok!(Assets::force_cancel_approval(Origin::signed(1), 0, 1, 2)); + assert_ok!(Assets::force_cancel_approval(RuntimeOrigin::signed(1), 0, 1, 2)); assert_eq!(Asset::::get(0).unwrap().approvals, 0); assert_noop!( - Assets::force_cancel_approval(Origin::signed(1), 0, 1, 2), + Assets::force_cancel_approval(RuntimeOrigin::signed(1), 0, 1, 2), Error::::Unknown ); }); @@ -283,42 +301,42 @@ fn force_cancel_approval_works() { fn lifecycle_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::create(Origin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); assert_eq!(Balances::reserved_balance(&1), 1); assert!(Asset::::contains_key(0)); - assert_ok!(Assets::set_metadata(Origin::signed(1), 0, vec![0], vec![0], 12)); + assert_ok!(Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0], vec![0], 12)); assert_eq!(Balances::reserved_balance(&1), 4); assert!(Metadata::::contains_key(0)); Balances::make_free_balance_be(&10, 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 10, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); Balances::make_free_balance_be(&20, 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 20, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 20, 100)); assert_eq!(Account::::iter_prefix(0).count(), 2); let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(Origin::signed(1), 0, w)); + assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); assert_eq!(Balances::reserved_balance(&1), 0); assert!(!Asset::::contains_key(0)); assert!(!Metadata::::contains_key(0)); assert_eq!(Account::::iter_prefix(0).count(), 0); - assert_ok!(Assets::create(Origin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); assert_eq!(Balances::reserved_balance(&1), 1); assert!(Asset::::contains_key(0)); - assert_ok!(Assets::set_metadata(Origin::signed(1), 0, vec![0], vec![0], 12)); + assert_ok!(Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0], vec![0], 12)); assert_eq!(Balances::reserved_balance(&1), 4); assert!(Metadata::::contains_key(0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 10, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 20, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 20, 100)); assert_eq!(Account::::iter_prefix(0).count(), 2); let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(Origin::root(), 0, w)); + assert_ok!(Assets::destroy(RuntimeOrigin::root(), 0, w)); assert_eq!(Balances::reserved_balance(&1), 0); assert!(!Asset::::contains_key(0)); @@ -331,15 +349,15 @@ fn lifecycle_should_work() { fn destroy_with_bad_witness_should_not_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); let mut w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::mint(Origin::signed(1), 0, 10, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); // witness too low - assert_noop!(Assets::destroy(Origin::signed(1), 0, w), Error::::BadWitness); + assert_noop!(Assets::destroy(RuntimeOrigin::signed(1), 0, w), Error::::BadWitness); // witness too high is okay though w.accounts += 2; w.sufficients += 2; - assert_ok!(Assets::destroy(Origin::signed(1), 0, w)); + assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); }); } @@ -347,15 +365,15 @@ fn destroy_with_bad_witness_should_not_work() { fn destroy_should_refund_approvals() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 10, 100)); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 3, 50)); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 4, 50)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 3, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 4, 50)); assert_eq!(Balances::reserved_balance(&1), 3); let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(Origin::signed(1), 0, w)); + assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); assert_eq!(Balances::reserved_balance(&1), 0); // all approvals are removed @@ -366,69 +384,72 @@ fn destroy_should_refund_approvals() { #[test] fn non_providing_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); Balances::make_free_balance_be(&0, 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 0, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 0, 100)); // Cannot mint into account 2 since it doesn't (yet) exist... - assert_noop!(Assets::mint(Origin::signed(1), 0, 1, 100), TokenError::CannotCreate); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100), TokenError::CannotCreate); // ...or transfer... - assert_noop!(Assets::transfer(Origin::signed(0), 0, 1, 50), TokenError::CannotCreate); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(0), 0, 1, 50), + TokenError::CannotCreate + ); // ...or force-transfer assert_noop!( - Assets::force_transfer(Origin::signed(1), 0, 0, 1, 50), + Assets::force_transfer(RuntimeOrigin::signed(1), 0, 0, 1, 50), TokenError::CannotCreate ); Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); - assert_ok!(Assets::transfer(Origin::signed(0), 0, 1, 25)); - assert_ok!(Assets::force_transfer(Origin::signed(1), 0, 0, 2, 25)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(0), 0, 1, 25)); + assert_ok!(Assets::force_transfer(RuntimeOrigin::signed(1), 0, 0, 2, 25)); }); } #[test] fn min_balance_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 10)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Asset::::get(0).unwrap().accounts, 1); // Cannot create a new account with a balance that is below minimum... - assert_noop!(Assets::mint(Origin::signed(1), 0, 2, 9), TokenError::BelowMinimum); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 9), TokenError::BelowMinimum); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 9), TokenError::BelowMinimum); + assert_noop!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 9), TokenError::BelowMinimum); assert_noop!( - Assets::force_transfer(Origin::signed(1), 0, 1, 2, 9), + Assets::force_transfer(RuntimeOrigin::signed(1), 0, 1, 2, 9), TokenError::BelowMinimum ); // When deducting from an account to below minimum, it should be reaped. // Death by `transfer`. - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 91)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 91)); assert!(Assets::maybe_balance(0, 1).is_none()); assert_eq!(Assets::balance(0, 2), 100); assert_eq!(Asset::::get(0).unwrap().accounts, 1); assert_eq!(take_hooks(), vec![Hook::Died(0, 1)]); // Death by `force_transfer`. - assert_ok!(Assets::force_transfer(Origin::signed(1), 0, 2, 1, 91)); + assert_ok!(Assets::force_transfer(RuntimeOrigin::signed(1), 0, 2, 1, 91)); assert!(Assets::maybe_balance(0, 2).is_none()); assert_eq!(Assets::balance(0, 1), 100); assert_eq!(Asset::::get(0).unwrap().accounts, 1); assert_eq!(take_hooks(), vec![Hook::Died(0, 2)]); // Death by `burn`. - assert_ok!(Assets::burn(Origin::signed(1), 0, 1, 91)); + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 1, 91)); assert!(Assets::maybe_balance(0, 1).is_none()); assert_eq!(Asset::::get(0).unwrap().accounts, 0); assert_eq!(take_hooks(), vec![Hook::Died(0, 1)]); // Death by `transfer_approved`. - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 100)); - assert_ok!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 91)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 100)); + assert_ok!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 91)); assert_eq!(take_hooks(), vec![Hook::Died(0, 1)]); }); } @@ -436,17 +457,17 @@ fn min_balance_should_work() { #[test] fn querying_total_supply_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 2), 50); - assert_ok!(Assets::transfer(Origin::signed(2), 0, 3, 31)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 3, 31)); assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 2), 19); assert_eq!(Assets::balance(0, 3), 31); - assert_ok!(Assets::burn(Origin::signed(1), 0, 3, u64::MAX)); + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 3, u64::MAX)); assert_eq!(Assets::total_supply(0), 69); }); } @@ -454,10 +475,10 @@ fn querying_total_supply_should_work() { #[test] fn transferring_amount_below_available_balance_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 2), 50); }); @@ -466,14 +487,14 @@ fn transferring_amount_below_available_balance_should_work() { #[test] fn transferring_enough_to_kill_source_when_keep_alive_should_fail() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 10)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_noop!( - Assets::transfer_keep_alive(Origin::signed(1), 0, 2, 91), + Assets::transfer_keep_alive(RuntimeOrigin::signed(1), 0, 2, 91), Error::::BalanceLow ); - assert_ok!(Assets::transfer_keep_alive(Origin::signed(1), 0, 2, 90)); + assert_ok!(Assets::transfer_keep_alive(RuntimeOrigin::signed(1), 0, 2, 90)); assert_eq!(Assets::balance(0, 1), 10); assert_eq!(Assets::balance(0, 2), 90); assert!(hooks().is_empty()); @@ -483,26 +504,26 @@ fn transferring_enough_to_kill_source_when_keep_alive_should_fail() { #[test] fn transferring_frozen_user_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::freeze(Origin::signed(1), 0, 1)); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 50), Error::::Frozen); - assert_ok!(Assets::thaw(Origin::signed(1), 0, 1)); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 1)); + assert_noop!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50), Error::::Frozen); + assert_ok!(Assets::thaw(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); }); } #[test] fn transferring_frozen_asset_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::freeze_asset(Origin::signed(1), 0)); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 50), Error::::Frozen); - assert_ok!(Assets::thaw_asset(Origin::signed(1), 0)); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + assert_noop!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50), Error::::Frozen); + assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); }); } @@ -510,36 +531,48 @@ fn transferring_frozen_asset_should_not_work() { fn approve_transfer_frozen_asset_should_not_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::freeze_asset(Origin::signed(1), 0)); - assert_noop!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50), Error::::Frozen); - assert_ok!(Assets::thaw_asset(Origin::signed(1), 0)); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + assert_noop!( + Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), + Error::::Frozen + ); + assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); }); } #[test] fn origin_guards_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_noop!( + Assets::transfer_ownership(RuntimeOrigin::signed(2), 0, 2), + Error::::NoPermission + ); + assert_noop!( + Assets::set_team(RuntimeOrigin::signed(2), 0, 2, 2, 2), + Error::::NoPermission + ); + assert_noop!(Assets::freeze(RuntimeOrigin::signed(2), 0, 1), Error::::NoPermission); + assert_noop!(Assets::thaw(RuntimeOrigin::signed(2), 0, 2), Error::::NoPermission); + assert_noop!( + Assets::mint(RuntimeOrigin::signed(2), 0, 2, 100), + Error::::NoPermission + ); assert_noop!( - Assets::transfer_ownership(Origin::signed(2), 0, 2), + Assets::burn(RuntimeOrigin::signed(2), 0, 1, 100), Error::::NoPermission ); - assert_noop!(Assets::set_team(Origin::signed(2), 0, 2, 2, 2), Error::::NoPermission); - assert_noop!(Assets::freeze(Origin::signed(2), 0, 1), Error::::NoPermission); - assert_noop!(Assets::thaw(Origin::signed(2), 0, 2), Error::::NoPermission); - assert_noop!(Assets::mint(Origin::signed(2), 0, 2, 100), Error::::NoPermission); - assert_noop!(Assets::burn(Origin::signed(2), 0, 1, 100), Error::::NoPermission); assert_noop!( - Assets::force_transfer(Origin::signed(2), 0, 1, 2, 100), + Assets::force_transfer(RuntimeOrigin::signed(2), 0, 1, 2, 100), Error::::NoPermission ); let w = Asset::::get(0).unwrap().destroy_witness(); - assert_noop!(Assets::destroy(Origin::signed(2), 0, w), Error::::NoPermission); + assert_noop!(Assets::destroy(RuntimeOrigin::signed(2), 0, w), Error::::NoPermission); }); } @@ -548,22 +581,28 @@ fn transfer_owner_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); - assert_ok!(Assets::create(Origin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); assert_eq!(Balances::reserved_balance(&1), 1); - assert_ok!(Assets::transfer_ownership(Origin::signed(1), 0, 2)); + assert_ok!(Assets::transfer_ownership(RuntimeOrigin::signed(1), 0, 2)); assert_eq!(Balances::reserved_balance(&2), 1); assert_eq!(Balances::reserved_balance(&1), 0); assert_noop!( - Assets::transfer_ownership(Origin::signed(1), 0, 1), + Assets::transfer_ownership(RuntimeOrigin::signed(1), 0, 1), Error::::NoPermission ); // Set metadata now and make sure that deposit gets transferred back. - assert_ok!(Assets::set_metadata(Origin::signed(2), 0, vec![0u8; 10], vec![0u8; 10], 12)); - assert_ok!(Assets::transfer_ownership(Origin::signed(2), 0, 1)); + assert_ok!(Assets::set_metadata( + RuntimeOrigin::signed(2), + 0, + vec![0u8; 10], + vec![0u8; 10], + 12 + )); + assert_ok!(Assets::transfer_ownership(RuntimeOrigin::signed(2), 0, 1)); assert_eq!(Balances::reserved_balance(&1), 22); assert_eq!(Balances::reserved_balance(&2), 0); }); @@ -572,27 +611,27 @@ fn transfer_owner_should_work() { #[test] fn set_team_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::set_team(Origin::signed(1), 0, 2, 3, 4)); - - assert_ok!(Assets::mint(Origin::signed(2), 0, 2, 100)); - assert_ok!(Assets::freeze(Origin::signed(4), 0, 2)); - assert_ok!(Assets::thaw(Origin::signed(3), 0, 2)); - assert_ok!(Assets::force_transfer(Origin::signed(3), 0, 2, 3, 100)); - assert_ok!(Assets::burn(Origin::signed(3), 0, 3, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(2), 0, 2, 100)); + assert_ok!(Assets::freeze(RuntimeOrigin::signed(4), 0, 2)); + assert_ok!(Assets::thaw(RuntimeOrigin::signed(3), 0, 2)); + assert_ok!(Assets::force_transfer(RuntimeOrigin::signed(3), 0, 2, 3, 100)); + assert_ok!(Assets::burn(RuntimeOrigin::signed(3), 0, 3, 100)); }); } #[test] fn transferring_to_frozen_account_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_eq!(Assets::balance(0, 2), 100); - assert_ok!(Assets::freeze(Origin::signed(1), 0, 2)); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Assets::balance(0, 2), 150); }); } @@ -600,26 +639,32 @@ fn transferring_to_frozen_account_should_work() { #[test] fn transferring_amount_more_than_available_balance_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 2), 50); - assert_ok!(Assets::burn(Origin::signed(1), 0, 1, u64::MAX)); + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 1, u64::MAX)); assert_eq!(Assets::balance(0, 1), 0); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 1, 50), Error::::NoAccount); - assert_noop!(Assets::transfer(Origin::signed(2), 0, 1, 51), Error::::BalanceLow); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(1), 0, 1, 50), + Error::::NoAccount + ); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 51), + Error::::BalanceLow + ); }); } #[test] fn transferring_less_than_one_unit_is_fine() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 0)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 0)); // `ForceCreated` and `Issued` but no `Transferred` event. assert_eq!(System::events().len(), 2); }); @@ -628,20 +673,23 @@ fn transferring_less_than_one_unit_is_fine() { #[test] fn transferring_more_units_than_total_supply_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 101), Error::::BalanceLow); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 101), + Error::::BalanceLow + ); }); } #[test] fn burning_asset_balance_with_positive_balance_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::burn(Origin::signed(1), 0, 1, u64::MAX)); + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 1, u64::MAX)); assert_eq!(Assets::balance(0, 1), 0); }); } @@ -649,10 +697,13 @@ fn burning_asset_balance_with_positive_balance_should_work() { #[test] fn burning_asset_balance_with_zero_balance_does_nothing() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 2), 0); - assert_noop!(Assets::burn(Origin::signed(1), 0, 2, u64::MAX), Error::::NoAccount); + assert_noop!( + Assets::burn(RuntimeOrigin::signed(1), 0, 2, u64::MAX), + Error::::NoAccount + ); assert_eq!(Assets::balance(0, 2), 0); assert_eq!(Assets::total_supply(0), 100); }); @@ -663,48 +714,69 @@ fn set_metadata_should_work() { new_test_ext().execute_with(|| { // Cannot add metadata to unknown asset assert_noop!( - Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 10], vec![0u8; 10], 12), + Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0u8; 10], vec![0u8; 10], 12), Error::::Unknown, ); - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); // Cannot add metadata to unowned asset assert_noop!( - Assets::set_metadata(Origin::signed(2), 0, vec![0u8; 10], vec![0u8; 10], 12), + Assets::set_metadata(RuntimeOrigin::signed(2), 0, vec![0u8; 10], vec![0u8; 10], 12), Error::::NoPermission, ); // Cannot add oversized metadata assert_noop!( - Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 100], vec![0u8; 10], 12), + Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0u8; 100], vec![0u8; 10], 12), Error::::BadMetadata, ); assert_noop!( - Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 10], vec![0u8; 100], 12), + Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0u8; 10], vec![0u8; 100], 12), Error::::BadMetadata, ); // Successfully add metadata and take deposit Balances::make_free_balance_be(&1, 30); - assert_ok!(Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 10], vec![0u8; 10], 12)); + assert_ok!(Assets::set_metadata( + RuntimeOrigin::signed(1), + 0, + vec![0u8; 10], + vec![0u8; 10], + 12 + )); assert_eq!(Balances::free_balance(&1), 9); // Update deposit - assert_ok!(Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 10], vec![0u8; 5], 12)); + assert_ok!(Assets::set_metadata( + RuntimeOrigin::signed(1), + 0, + vec![0u8; 10], + vec![0u8; 5], + 12 + )); assert_eq!(Balances::free_balance(&1), 14); - assert_ok!(Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 10], vec![0u8; 15], 12)); + assert_ok!(Assets::set_metadata( + RuntimeOrigin::signed(1), + 0, + vec![0u8; 10], + vec![0u8; 15], + 12 + )); assert_eq!(Balances::free_balance(&1), 4); // Cannot over-reserve assert_noop!( - Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 20], vec![0u8; 20], 12), + Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0u8; 20], vec![0u8; 20], 12), BalancesError::::InsufficientBalance, ); // Clear Metadata assert!(Metadata::::contains_key(0)); - assert_noop!(Assets::clear_metadata(Origin::signed(2), 0), Error::::NoPermission); - assert_noop!(Assets::clear_metadata(Origin::signed(1), 1), Error::::Unknown); - assert_ok!(Assets::clear_metadata(Origin::signed(1), 0)); + assert_noop!( + Assets::clear_metadata(RuntimeOrigin::signed(2), 0), + Error::::NoPermission + ); + assert_noop!(Assets::clear_metadata(RuntimeOrigin::signed(1), 1), Error::::Unknown); + assert_ok!(Assets::clear_metadata(RuntimeOrigin::signed(1), 0)); assert!(!Metadata::::contains_key(0)); }); } @@ -713,13 +785,13 @@ fn set_metadata_should_work() { #[test] fn destroy_calls_died_hooks() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 50)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 50)); // Create account 1 and 2. - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); // Destroy the asset. let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(Origin::signed(1), 0, w)); + assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); // Asset is gone and accounts 1 and 2 died. assert!(Asset::::get(0).is_none()); @@ -730,36 +802,39 @@ fn destroy_calls_died_hooks() { #[test] fn freezer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 10)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); // freeze 50 of it. set_frozen_balance(0, 1, 50); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 20)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 20)); // cannot transfer another 21 away as this would take the non-frozen balance (30) to below // the minimum balance (10). - assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 21), Error::::BalanceLow); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 21), + Error::::BalanceLow + ); // create an approved transfer... Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); let e = Error::::BalanceLow; // ...but that wont work either: - assert_noop!(Assets::transfer_approved(Origin::signed(2), 0, 1, 2, 21), e); + assert_noop!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 2, 21), e); // a force transfer won't work also. let e = Error::::BalanceLow; - assert_noop!(Assets::force_transfer(Origin::signed(1), 0, 1, 2, 21), e); + assert_noop!(Assets::force_transfer(RuntimeOrigin::signed(1), 0, 1, 2, 21), e); // reduce it to only 49 frozen... set_frozen_balance(0, 1, 49); // ...and it's all good: - assert_ok!(Assets::force_transfer(Origin::signed(1), 0, 1, 2, 21)); + assert_ok!(Assets::force_transfer(RuntimeOrigin::signed(1), 0, 1, 2, 21)); // and if we clear it, we can remove the account completely. clear_frozen_balance(0, 1); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(hooks(), vec![Hook::Died(0, 1)]); }); } @@ -769,7 +844,7 @@ fn imbalances_should_work() { use frame_support::traits::tokens::fungibles::Balanced; new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); let imb = Assets::issue(0, 100); assert_eq!(Assets::total_supply(0), 100); @@ -792,9 +867,9 @@ fn imbalances_should_work() { fn force_metadata_should_work() { new_test_ext().execute_with(|| { // force set metadata works - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::force_set_metadata( - Origin::root(), + RuntimeOrigin::root(), 0, vec![0u8; 10], vec![0u8; 10], @@ -806,7 +881,7 @@ fn force_metadata_should_work() { // overwrites existing metadata let asset_original_metadata = Metadata::::get(0); assert_ok!(Assets::force_set_metadata( - Origin::root(), + RuntimeOrigin::root(), 0, vec![1u8; 10], vec![1u8; 10], @@ -817,7 +892,14 @@ fn force_metadata_should_work() { // attempt to set metadata for non-existent asset class assert_noop!( - Assets::force_set_metadata(Origin::root(), 1, vec![0u8; 10], vec![0u8; 10], 8, false), + Assets::force_set_metadata( + RuntimeOrigin::root(), + 1, + vec![0u8; 10], + vec![0u8; 10], + 8, + false + ), Error::::Unknown ); @@ -825,7 +907,7 @@ fn force_metadata_should_work() { let limit = 50usize; assert_noop!( Assets::force_set_metadata( - Origin::root(), + RuntimeOrigin::root(), 0, vec![0u8; limit + 1], vec![0u8; 10], @@ -836,7 +918,7 @@ fn force_metadata_should_work() { ); assert_noop!( Assets::force_set_metadata( - Origin::root(), + RuntimeOrigin::root(), 0, vec![0u8; 10], vec![0u8; limit + 1], @@ -848,11 +930,14 @@ fn force_metadata_should_work() { // force clear metadata works assert!(Metadata::::contains_key(0)); - assert_ok!(Assets::force_clear_metadata(Origin::root(), 0)); + assert_ok!(Assets::force_clear_metadata(RuntimeOrigin::root(), 0)); assert!(!Metadata::::contains_key(0)); // Error handles clearing non-existent asset class - assert_noop!(Assets::force_clear_metadata(Origin::root(), 1), Error::::Unknown); + assert_noop!( + Assets::force_clear_metadata(RuntimeOrigin::root(), 1), + Error::::Unknown + ); }); } @@ -861,34 +946,57 @@ fn force_asset_status_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 10); Balances::make_free_balance_be(&2, 10); - assert_ok!(Assets::create(Origin::signed(1), 0, 1, 30)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 50)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 2, 150)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 30)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 50)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 150)); // force asset status to change min_balance > balance - assert_ok!(Assets::force_asset_status(Origin::root(), 0, 1, 1, 1, 1, 100, true, false)); + assert_ok!(Assets::force_asset_status( + RuntimeOrigin::root(), + 0, + 1, + 1, + 1, + 1, + 100, + true, + false + )); assert_eq!(Assets::balance(0, 1), 50); // account can recieve assets for balance < min_balance - assert_ok!(Assets::transfer(Origin::signed(2), 0, 1, 1)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 1)); assert_eq!(Assets::balance(0, 1), 51); // account on outbound transfer will cleanup for balance < min_balance - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 1)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 1)); assert_eq!(Assets::balance(0, 1), 0); // won't create new account with balance below min_balance - assert_noop!(Assets::transfer(Origin::signed(2), 0, 3, 50), TokenError::BelowMinimum); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(2), 0, 3, 50), + TokenError::BelowMinimum + ); // force asset status will not execute for non-existent class assert_noop!( - Assets::force_asset_status(Origin::root(), 1, 1, 1, 1, 1, 90, true, false), + Assets::force_asset_status(RuntimeOrigin::root(), 1, 1, 1, 1, 1, 90, true, false), Error::::Unknown ); // account drains to completion when funds dip below min_balance - assert_ok!(Assets::force_asset_status(Origin::root(), 0, 1, 1, 1, 1, 110, true, false)); - assert_ok!(Assets::transfer(Origin::signed(2), 0, 1, 110)); + assert_ok!(Assets::force_asset_status( + RuntimeOrigin::root(), + 0, + 1, + 1, + 1, + 1, + 110, + true, + false + )); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 110)); assert_eq!(Assets::balance(0, 1), 200); assert_eq!(Assets::balance(0, 2), 0); assert_eq!(Assets::total_supply(0), 200); @@ -901,9 +1009,9 @@ fn balance_conversion_should_work() { use frame_support::traits::tokens::BalanceConversion; let id = 42; - assert_ok!(Assets::force_create(Origin::root(), id, 1, true, 10)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), id, 1, true, 10)); let not_sufficient = 23; - assert_ok!(Assets::force_create(Origin::root(), not_sufficient, 1, false, 10)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), not_sufficient, 1, false, 10)); assert_eq!( BalanceToAssetBalance::::to_asset_balance(100, 1234), @@ -938,9 +1046,9 @@ fn assets_from_genesis_should_exist() { fn querying_name_symbol_and_decimals_should_work() { new_test_ext().execute_with(|| { use frame_support::traits::tokens::fungibles::metadata::Inspect; - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::force_set_metadata( - Origin::root(), + RuntimeOrigin::root(), 0, vec![0u8; 10], vec![1u8; 10], @@ -957,8 +1065,8 @@ fn querying_name_symbol_and_decimals_should_work() { fn querying_allowance_should_work() { new_test_ext().execute_with(|| { use frame_support::traits::tokens::fungibles::approvals::{Inspect, Mutate}; - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); assert_ok!(Assets::approve(0, &1, &2, 50)); assert_eq!(Assets::allowance(0, &1, &2), 50); @@ -972,9 +1080,9 @@ fn querying_allowance_should_work() { fn transfer_large_asset() { new_test_ext().execute_with(|| { let amount = u64::pow(2, 63) + 2; - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, amount)); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, amount - 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, amount)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, amount - 1)); }) } @@ -982,9 +1090,9 @@ fn transfer_large_asset() { fn querying_roles_should_work() { new_test_ext().execute_with(|| { use frame_support::traits::tokens::fungibles::roles::Inspect; - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::set_team( - Origin::signed(1), + RuntimeOrigin::signed(1), 0, // Issuer 2, diff --git a/frame/atomic-swap/src/tests.rs b/frame/atomic-swap/src/tests.rs index d3d8b37d82794..5ad63dfce55b4 100644 --- a/frame/atomic-swap/src/tests.rs +++ b/frame/atomic-swap/src/tests.rs @@ -37,7 +37,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -100,7 +100,7 @@ fn two_party_successful_swap() { // A creates the swap on chain1. chain1.execute_with(|| { AtomicSwap::create_swap( - Origin::signed(A), + RuntimeOrigin::signed(A), B, hashed_proof, BalanceSwapAction::new(50), @@ -115,7 +115,7 @@ fn two_party_successful_swap() { // B creates the swap on chain2. chain2.execute_with(|| { AtomicSwap::create_swap( - Origin::signed(B), + RuntimeOrigin::signed(B), A, hashed_proof, BalanceSwapAction::new(75), @@ -129,8 +129,12 @@ fn two_party_successful_swap() { // A reveals the proof and claims the swap on chain2. chain2.execute_with(|| { - AtomicSwap::claim_swap(Origin::signed(A), proof.to_vec(), BalanceSwapAction::new(75)) - .unwrap(); + AtomicSwap::claim_swap( + RuntimeOrigin::signed(A), + proof.to_vec(), + BalanceSwapAction::new(75), + ) + .unwrap(); assert_eq!(Balances::free_balance(A), 100 + 75); assert_eq!(Balances::free_balance(B), 200 - 75); @@ -138,8 +142,12 @@ fn two_party_successful_swap() { // B use the revealed proof to claim the swap on chain1. chain1.execute_with(|| { - AtomicSwap::claim_swap(Origin::signed(B), proof.to_vec(), BalanceSwapAction::new(50)) - .unwrap(); + AtomicSwap::claim_swap( + RuntimeOrigin::signed(B), + proof.to_vec(), + BalanceSwapAction::new(50), + ) + .unwrap(); assert_eq!(Balances::free_balance(A), 100 - 50); assert_eq!(Balances::free_balance(B), 200 + 50); diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 673190c95f2e1..07fa9aa680e80 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -56,7 +56,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index 3505f20a05929..b642a9ac283f2 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -235,7 +235,7 @@ mod tests { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 3f484ef24eec0..c08e773abe3a7 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -468,7 +468,7 @@ mod tests { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -738,7 +738,7 @@ mod tests { System::reset_events(); System::initialize(¤t_depth, &parent_hash, &Default::default()); Authorship::on_initialize(current_depth); - Authorship::set_uncles(Origin::none(), uncles).unwrap(); + Authorship::set_uncles(RuntimeOrigin::none(), uncles).unwrap(); Authorship::on_finalize(current_depth); max_item_count = std::cmp::max(max_item_count, ::Uncles::get().len()); diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index fb251457db9ca..8264cd11ddc88 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -74,7 +74,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 1015ada7f0185..8d2a9b326cd0f 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -289,7 +289,7 @@ fn can_enact_next_config() { assert_eq!(NextEpochConfig::::get(), Some(next_config.clone())); Babe::plan_config_change( - Origin::root(), + RuntimeOrigin::root(), NextConfigDescriptor::V1 { c: next_next_config.c, allowed_slots: next_next_config.allowed_slots, @@ -323,15 +323,15 @@ fn only_root_can_enact_config_change() { let next_config = NextConfigDescriptor::V1 { c: (1, 4), allowed_slots: AllowedSlots::PrimarySlots }; - let res = Babe::plan_config_change(Origin::none(), next_config.clone()); + let res = Babe::plan_config_change(RuntimeOrigin::none(), next_config.clone()); assert_noop!(res, DispatchError::BadOrigin); - let res = Babe::plan_config_change(Origin::signed(1), next_config.clone()); + let res = Babe::plan_config_change(RuntimeOrigin::signed(1), next_config.clone()); assert_noop!(res, DispatchError::BadOrigin); - let res = Babe::plan_config_change(Origin::root(), next_config); + let res = Babe::plan_config_change(RuntimeOrigin::root(), next_config); assert!(res.is_ok()); }); @@ -464,7 +464,7 @@ fn report_equivocation_current_session_works() { // report the equivocation Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) @@ -536,7 +536,7 @@ fn report_equivocation_old_session_works() { // report the equivocation Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) @@ -588,7 +588,7 @@ fn report_equivocation_invalid_key_owner_proof() { key_owner_proof.session = 0; assert_err!( Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof.clone()), key_owner_proof ), @@ -608,7 +608,7 @@ fn report_equivocation_invalid_key_owner_proof() { assert_err!( Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ), @@ -642,7 +642,7 @@ fn report_equivocation_invalid_equivocation_proof() { let assert_invalid_equivocation = |equivocation_proof| { assert_err!( Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof.clone(), ), @@ -784,7 +784,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() { // we submit the report Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) @@ -857,7 +857,7 @@ fn valid_equivocation_reports_dont_pay_fees() { // report the equivocation. let post_info = Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof.clone()), key_owner_proof.clone(), ) @@ -871,7 +871,7 @@ fn valid_equivocation_reports_dont_pay_fees() { // report the equivocation again which is invalid now since it is // duplicate. let post_info = Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index f6bde63b3867c..8cc96a988e72a 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -49,7 +49,7 @@ impl frame_election_provider_support::ScoreProvider for StakingMock { impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs index 01c1642f882c1..63a395ed0d65a 100644 --- a/frame/bags-list/src/tests.rs +++ b/frame/bags-list/src/tests.rs @@ -37,7 +37,7 @@ mod pallet { // when increasing score to the level of non-existent bag assert_eq!(List::::get_score(&42).unwrap(), 20); StakingMock::set_score_of(&42, 2_000); - assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 42)); assert_eq!(List::::get_score(&42).unwrap(), 2_000); // then a new bag is created and the id moves into it @@ -48,7 +48,7 @@ mod pallet { // when decreasing score within the range of the current bag StakingMock::set_score_of(&42, 1_001); - assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 42)); // then the id does not move assert_eq!( @@ -60,7 +60,7 @@ mod pallet { // when reducing score to the level of a non-existent bag StakingMock::set_score_of(&42, 30); - assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 42)); // then a new bag is created and the id moves into it assert_eq!( @@ -71,7 +71,7 @@ mod pallet { // when increasing score to the level of a pre-existing bag StakingMock::set_score_of(&42, 500); - assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 42)); // then the id moves into that bag assert_eq!( @@ -92,7 +92,7 @@ mod pallet { // when StakingMock::set_score_of(&4, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 4)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 4)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 4]), (1_000, vec![2, 3])]); @@ -100,7 +100,7 @@ mod pallet { // when StakingMock::set_score_of(&3, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 3)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 3)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 4, 3]), (1_000, vec![2])]); @@ -111,7 +111,7 @@ mod pallet { // when StakingMock::set_score_of(&2, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 2)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 2)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 4, 3, 2])]); @@ -126,7 +126,7 @@ mod pallet { ExtBuilder::default().build_and_execute(|| { // when StakingMock::set_score_of(&2, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 2)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 2)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 2]), (1_000, vec![3, 4])]); @@ -134,7 +134,7 @@ mod pallet { // when StakingMock::set_score_of(&3, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 3)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 3)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 2, 3]), (1_000, vec![4])]); @@ -142,7 +142,7 @@ mod pallet { // when StakingMock::set_score_of(&4, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 4)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 4)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 2, 3, 4])]); @@ -159,12 +159,15 @@ mod pallet { assert!(!node_3.is_misplaced(500)); // then calling rebag on account 3 with score 500 is a noop - assert_storage_noop!(assert_eq!(BagsList::rebag(Origin::signed(0), 3), Ok(()))); + assert_storage_noop!(assert_eq!(BagsList::rebag(RuntimeOrigin::signed(0), 3), Ok(()))); // when account 42 is not in the list assert!(!BagsList::contains(&42)); // then rebag-ing account 42 is an error - assert_storage_noop!(assert!(matches!(BagsList::rebag(Origin::signed(0), 42), Err(_)))); + assert_storage_noop!(assert!(matches!( + BagsList::rebag(RuntimeOrigin::signed(0), 42), + Err(_) + ))); }); } @@ -200,7 +203,7 @@ mod pallet { ); // any rebag is noop. - assert_storage_noop!(assert_eq!(BagsList::rebag(Origin::signed(0), 1), Ok(()))); + assert_storage_noop!(assert_eq!(BagsList::rebag(RuntimeOrigin::signed(0), 1), Ok(()))); }) } @@ -214,7 +217,7 @@ mod pallet { assert_eq!(List::::get_bags(), vec![(20, vec![10, 11])]); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(11), 10)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(11), 10)); // then assert_eq!(List::::get_bags(), vec![(20, vec![11, 10])]); @@ -231,7 +234,7 @@ mod pallet { assert_eq!(List::::get_bags(), vec![(20, vec![11, 10])]); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(11), 10)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(11), 10)); // then assert_eq!(List::::get_bags(), vec![(20, vec![11, 10])]); @@ -247,7 +250,7 @@ mod pallet { StakingMock::set_score_of(&3, 999); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(4), 3)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(4), 3)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 4, 3, 5])]); @@ -268,7 +271,7 @@ mod pallet { StakingMock::set_score_of(&5, 999); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(3), 5)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(3), 5)); // then assert_eq!( @@ -287,7 +290,7 @@ mod pallet { StakingMock::set_score_of(&2, 999); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(3), 2)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(3), 2)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 2, 4])]); @@ -303,7 +306,7 @@ mod pallet { StakingMock::set_score_of(&3, 999); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(4), 3)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(4), 3)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 4, 3])]); @@ -319,7 +322,7 @@ mod pallet { StakingMock::set_score_of(&2, 999); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(5), 2)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(5), 2)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![5, 2, 3, 4])]); @@ -335,7 +338,7 @@ mod pallet { StakingMock::set_score_of(&4, 999); // when - BagsList::put_in_front_of(Origin::signed(2), 4).unwrap(); + BagsList::put_in_front_of(RuntimeOrigin::signed(2), 4).unwrap(); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 2, 4, 5])]); @@ -349,7 +352,7 @@ mod pallet { assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5])]); // when - BagsList::put_in_front_of(Origin::signed(3), 5).unwrap(); + BagsList::put_in_front_of(RuntimeOrigin::signed(3), 5).unwrap(); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 4, 3, 5])]); @@ -365,7 +368,7 @@ mod pallet { StakingMock::set_score_of(&4, 999); // when - BagsList::put_in_front_of(Origin::signed(2), 4).unwrap(); + BagsList::put_in_front_of(RuntimeOrigin::signed(2), 4).unwrap(); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 2, 4])]); @@ -382,7 +385,7 @@ mod pallet { // then assert_noop!( - BagsList::put_in_front_of(Origin::signed(3), 2), + BagsList::put_in_front_of(RuntimeOrigin::signed(3), 2), crate::pallet::Error::::List(ListError::NotHeavier) ); }); @@ -396,7 +399,7 @@ mod pallet { // then assert_noop!( - BagsList::put_in_front_of(Origin::signed(3), 4), + BagsList::put_in_front_of(RuntimeOrigin::signed(3), 4), crate::pallet::Error::::List(ListError::NotHeavier) ); }); @@ -413,7 +416,7 @@ mod pallet { // then assert_noop!( - BagsList::put_in_front_of(Origin::signed(5), 4), + BagsList::put_in_front_of(RuntimeOrigin::signed(5), 4), crate::pallet::Error::::List(ListError::NodeNotFound) ); }); @@ -427,7 +430,7 @@ mod pallet { // then assert_noop!( - BagsList::put_in_front_of(Origin::signed(4), 5), + BagsList::put_in_front_of(RuntimeOrigin::signed(4), 5), crate::pallet::Error::::List(ListError::NodeNotFound) ); }); @@ -441,7 +444,7 @@ mod pallet { // then assert_noop!( - BagsList::put_in_front_of(Origin::signed(4), 1), + BagsList::put_in_front_of(RuntimeOrigin::signed(4), 1), crate::pallet::Error::::List(ListError::NotInSameBag) ); }); diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 9c641f6b38a22..faf53e16cb028 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -825,7 +825,7 @@ macro_rules! decl_tests { /* User has no reference counter, so they can die in these scenarios */ // SCENARIO: Slash would not kill account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); // Slashed completed in full assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0)); // Account is still alive @@ -833,35 +833,35 @@ macro_rules! decl_tests { System::assert_last_event(RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 900 })); // SCENARIO: Slash will kill account because not enough balance left. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); // Slashed completed in full assert_eq!(Balances::slash(&1, 950), (NegativeImbalance::new(950), 0)); // Account is killed assert!(!System::account_exists(&1)); // SCENARIO: Over-slash will kill account, and report missing slash amount. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); // Slashed full free_balance, and reports 300 not slashed assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1000), 300)); // Account is dead assert!(!System::account_exists(&1)); // SCENARIO: Over-slash can take from reserved, but keep alive. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 400)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 400)); // Slashed full free_balance and 300 of reserved balance assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1300), 0)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash can take from reserved, and kill. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 350)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 350)); // Slashed full free_balance and 300 of reserved balance assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1300), 0)); // Account is dead because 50 reserved balance is not enough to keep alive assert!(!System::account_exists(&1)); // SCENARIO: Over-slash can take as much as possible from reserved, kill, and report missing amount. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 250)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 250)); // Slashed full free_balance and 300 of reserved balance assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1250), 50)); // Account is super dead @@ -870,7 +870,7 @@ macro_rules! decl_tests { /* User will now have a reference counter on them, keeping them alive in these scenarios */ // SCENARIO: Slash would not kill account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); assert_ok!(System::inc_consumers(&1)); // <-- Reference counter added here is enough for all tests // Slashed completed in full assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0)); @@ -878,35 +878,35 @@ macro_rules! decl_tests { assert!(System::account_exists(&1)); // SCENARIO: Slash will take as much as possible without killing account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); // Slashed completed in full assert_eq!(Balances::slash(&1, 950), (NegativeImbalance::new(900), 50)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash will not kill account, and report missing slash amount. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); // Slashed full free_balance minus ED, and reports 400 not slashed assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(900), 400)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash can take from reserved, but keep alive. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 400)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 400)); // Slashed full free_balance and 300 of reserved balance assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1300), 0)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash can take from reserved, but keep alive. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 350)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 350)); // Slashed full free_balance and 250 of reserved balance to leave ED assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1250), 50)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash can take as much as possible from reserved and report missing amount. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 250)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 250)); // Slashed full free_balance and 300 of reserved balance assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1150), 150)); // Account is still alive @@ -926,28 +926,28 @@ macro_rules! decl_tests { /* User has no reference counter, so they can die in these scenarios */ // SCENARIO: Slash would not kill account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); // Slashed completed in full assert_eq!(Balances::slash_reserved(&1, 900), (NegativeImbalance::new(900), 0)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Slash would kill account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); // Slashed completed in full assert_eq!(Balances::slash_reserved(&1, 1_000), (NegativeImbalance::new(1_000), 0)); // Account is dead assert!(!System::account_exists(&1)); // SCENARIO: Over-slash would kill account, and reports left over slash. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); // Slashed completed in full assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(1_000), 300)); // Account is dead assert!(!System::account_exists(&1)); // SCENARIO: Over-slash does not take from free balance. - assert_ok!(Balances::set_balance(Origin::root(), 1, 300, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 300, 1_000)); // Slashed completed in full assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(1_000), 300)); // Account is alive because of free balance @@ -956,7 +956,7 @@ macro_rules! decl_tests { /* User has a reference counter, so they cannot die */ // SCENARIO: Slash would not kill account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); assert_ok!(System::inc_consumers(&1)); // <-- Reference counter added here is enough for all tests // Slashed completed in full assert_eq!(Balances::slash_reserved(&1, 900), (NegativeImbalance::new(900), 0)); @@ -964,21 +964,21 @@ macro_rules! decl_tests { assert!(System::account_exists(&1)); // SCENARIO: Slash as much as possible without killing. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); // Slashed as much as possible assert_eq!(Balances::slash_reserved(&1, 1_000), (NegativeImbalance::new(950), 50)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash reports correctly, where reserved is needed to keep alive. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); // Slashed as much as possible assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(950), 350)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash reports correctly, where full reserved is removed. - assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 200, 1_000)); // Slashed as much as possible assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(1_000), 300)); // Account is still alive @@ -1018,7 +1018,7 @@ macro_rules! decl_tests { .existential_deposit(100) .build() .execute_with(|| { - assert_ok!(Balances::set_balance(Origin::root(), 1, 100, 100)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 100, 100)); assert_ok!(Balances::transfer_keep_alive(Some(1).into(), 2, 100)); assert_eq!(Balances::total_balance(&1), 100); assert_eq!(Balances::total_balance(&2), 100); @@ -1032,32 +1032,32 @@ macro_rules! decl_tests { .build() .execute_with(|| { // setup - assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 0)); - assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 200, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 0, 0)); // transfer all and allow death assert_ok!(Balances::transfer_all(Some(1).into(), 2, false)); assert_eq!(Balances::total_balance(&1), 0); assert_eq!(Balances::total_balance(&2), 200); // setup - assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 0)); - assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 200, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 0, 0)); // transfer all and keep alive assert_ok!(Balances::transfer_all(Some(1).into(), 2, true)); assert_eq!(Balances::total_balance(&1), 100); assert_eq!(Balances::total_balance(&2), 100); // setup - assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 10)); - assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 200, 10)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 0, 0)); // transfer all and allow death w/ reserved assert_ok!(Balances::transfer_all(Some(1).into(), 2, false)); assert_eq!(Balances::total_balance(&1), 0); assert_eq!(Balances::total_balance(&2), 200); // setup - assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 10)); - assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 200, 10)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 0, 0)); // transfer all and keep alive w/ reserved assert_ok!(Balances::transfer_all(Some(1).into(), 2, true)); assert_eq!(Balances::total_balance(&1), 100); @@ -1281,7 +1281,7 @@ macro_rules! decl_tests { let _ = Balances::deposit_creating(&1, 111); assert_ok!(frame_system::Pallet::::inc_consumers(&1)); assert_noop!( - Balances::set_balance(Origin::root(), 1, 0, 0), + Balances::set_balance(RuntimeOrigin::root(), 1, 0, 0), DispatchError::ConsumerRemaining, ); }); @@ -1291,7 +1291,7 @@ macro_rules! decl_tests { fn set_balance_handles_total_issuance() { <$ext_builder>::default().build().execute_with(|| { let old_total_issuance = Balances::total_issuance(); - assert_ok!(Balances::set_balance(Origin::root(), 1337, 69, 42)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1337, 69, 42)); assert_eq!(Balances::total_issuance(), old_total_issuance + 69 + 42); assert_eq!(Balances::total_balance(&1337), 69 + 42); assert_eq!(Balances::free_balance(&1337), 69); diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 1276a812c7861..1e38d611773d4 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -55,7 +55,7 @@ impl frame_system::Config for Test { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index b391b03ed6b6a..e080eafb66067 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -56,7 +56,7 @@ impl frame_system::Config for Test { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 6fda1697dcfeb..fa2eb0e488e7d 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -59,7 +59,7 @@ impl frame_system::Config for Test { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 792b775b77998..602d0aa5fe1a6 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -67,7 +67,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 7c4cd1af01533..ad3a672333dd5 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -62,7 +62,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 38aa7b261cb01..6a310330cafb1 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -176,7 +176,7 @@ pub mod mock { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index d96ed4dd17b6e..4401fb059f90b 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -112,14 +112,14 @@ macro_rules! whitelist { /// foo { /// let caller = account::(b"caller", 0, benchmarks_seed); /// let l in 1 .. MAX_LENGTH => initialize_l(l); -/// }: _(Origin::Signed(caller), vec![0u8; l]) +/// }: _(RuntimeOrigin::Signed(caller), vec![0u8; l]) /// /// // second dispatchable: bar; this is a root dispatchable and accepts a `u8` vector of size /// // `l`. /// // In this case, we explicitly name the call using `bar` instead of `_`. /// bar { /// let l in 1 .. MAX_LENGTH => initialize_l(l); -/// }: bar(Origin::Root, vec![0u8; l]) +/// }: bar(RuntimeOrigin::Root, vec![0u8; l]) /// /// // third dispatchable: baz; this is a user dispatchable. It isn't dependent on length like the /// // other two but has its own complexity `c` that needs setting up. It uses `caller` (in the @@ -128,20 +128,20 @@ macro_rules! whitelist { /// baz1 { /// let caller = account::(b"caller", 0, benchmarks_seed); /// let c = 0 .. 10 => setup_c(&caller, c); -/// }: baz(Origin::Signed(caller)) +/// }: baz(RuntimeOrigin::Signed(caller)) /// /// // this is a second benchmark of the baz dispatchable with a different setup. /// baz2 { /// let caller = account::(b"caller", 0, benchmarks_seed); /// let c = 0 .. 10 => setup_c_in_some_other_way(&caller, c); -/// }: baz(Origin::Signed(caller)) +/// }: baz(RuntimeOrigin::Signed(caller)) /// /// // You may optionally specify the origin type if it can't be determined automatically like /// // this. /// baz3 { /// let caller = account::(b"caller", 0, benchmarks_seed); /// let l in 1 .. MAX_LENGTH => initialize_l(l); -/// }: baz(Origin::Signed(caller), vec![0u8; l]) +/// }: baz(RuntimeOrigin::Signed(caller), vec![0u8; l]) /// /// // this is benchmarking some code that is not a dispatchable. /// populate_a_set { @@ -617,7 +617,7 @@ macro_rules! to_origin { $origin.into() }; ($origin:expr, $origin_type:ty) => { - <::Origin as From<$origin_type>>::from($origin) + <::RuntimeOrigin as From<$origin_type>>::from($origin) }; } diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index fd7e0cce03c22..3bbd06ea64f84 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -90,7 +90,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -148,7 +148,7 @@ mod benchmarks { crate::benchmarks! { where_clause { where - crate::tests::Origin: From::AccountId>>, + crate::tests::RuntimeOrigin: From::AccountId>>, } set_value { diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index 7617696a949cf..1fb122f031a76 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -41,7 +41,7 @@ mod pallet_test { frame_support::decl_module! { pub struct Module, I: Instance = DefaultInstance> for enum Call where - origin: T::Origin, ::OtherEvent: Into<>::RuntimeEvent> + origin: T::RuntimeOrigin, ::OtherEvent: Into<>::RuntimeEvent> { #[weight = 0] fn set_value(origin, n: u32) -> frame_support::dispatch::DispatchResult { @@ -91,7 +91,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 9dc920f6cca28..6ccd587cebc10 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -98,7 +98,7 @@ benchmarks_instance_pallet! { Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; let approve_origin = T::ApproveOrigin::successful_origin(); - }: _(approve_origin, bounty_id) + }: _(approve_origin, bounty_id) propose_curator { setup_pot_account::(); @@ -110,7 +110,7 @@ benchmarks_instance_pallet! { Bounties::::approve_bounty(approve_origin, bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); let approve_origin = T::ApproveOrigin::successful_origin(); - }: _(approve_origin, bounty_id, curator_lookup, fee) + }: _(approve_origin, bounty_id, curator_lookup, fee) // Worst case when curator is inactive and any sender unassigns the curator. unassign_curator { @@ -171,7 +171,7 @@ benchmarks_instance_pallet! { Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; let approve_origin = T::ApproveOrigin::successful_origin(); - }: close_bounty(approve_origin, bounty_id) + }: close_bounty(approve_origin, bounty_id) close_bounty_active { setup_pot_account::(); @@ -179,7 +179,7 @@ benchmarks_instance_pallet! { Treasury::::on_initialize(T::BlockNumber::zero()); let bounty_id = BountyCount::::get() - 1; let approve_origin = T::ApproveOrigin::successful_origin(); - }: close_bounty(approve_origin, bounty_id) + }: close_bounty(approve_origin, bounty_id) verify { assert_last_event::(Event::BountyCanceled { index: bounty_id }.into()) } diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index f1d794eb89dbe..68aa56ccdde7f 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -68,7 +68,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -229,7 +229,7 @@ fn minting_works() { #[test] fn spend_proposal_takes_min_deposit() { new_test_ext().execute_with(|| { - assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3)); assert_eq!(Balances::free_balance(0), 99); assert_eq!(Balances::reserved_balance(0), 1); }); @@ -238,7 +238,7 @@ fn spend_proposal_takes_min_deposit() { #[test] fn spend_proposal_takes_proportional_deposit() { new_test_ext().execute_with(|| { - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); assert_eq!(Balances::free_balance(0), 95); assert_eq!(Balances::reserved_balance(0), 5); }); @@ -248,7 +248,7 @@ fn spend_proposal_takes_proportional_deposit() { fn spend_proposal_fails_when_proposer_poor() { new_test_ext().execute_with(|| { assert_noop!( - Treasury::propose_spend(Origin::signed(2), 100, 3), + Treasury::propose_spend(RuntimeOrigin::signed(2), 100, 3), TreasuryError::InsufficientProposersBalance, ); }); @@ -259,8 +259,8 @@ fn accepted_spend_proposal_ignored_outside_spend_period() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(1); assert_eq!(Balances::free_balance(3), 0); @@ -286,8 +286,8 @@ fn rejected_spend_proposal_ignored_on_spend_period() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Balances::free_balance(3), 0); @@ -300,9 +300,12 @@ fn reject_already_rejected_spend_proposal_fails() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); - assert_noop!(Treasury::reject_proposal(Origin::root(), 0), TreasuryError::InvalidIndex); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); + assert_noop!( + Treasury::reject_proposal(RuntimeOrigin::root(), 0), + TreasuryError::InvalidIndex + ); }); } @@ -310,7 +313,7 @@ fn reject_already_rejected_spend_proposal_fails() { fn reject_non_existent_spend_proposal_fails() { new_test_ext().execute_with(|| { assert_noop!( - Treasury::reject_proposal(Origin::root(), 0), + Treasury::reject_proposal(RuntimeOrigin::root(), 0), pallet_treasury::Error::::InvalidIndex ); }); @@ -319,7 +322,10 @@ fn reject_non_existent_spend_proposal_fails() { #[test] fn accept_non_existent_spend_proposal_fails() { new_test_ext().execute_with(|| { - assert_noop!(Treasury::approve_proposal(Origin::root(), 0), TreasuryError::InvalidIndex); + assert_noop!( + Treasury::approve_proposal(RuntimeOrigin::root(), 0), + TreasuryError::InvalidIndex + ); }); } @@ -328,9 +334,12 @@ fn accept_already_rejected_spend_proposal_fails() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); - assert_noop!(Treasury::approve_proposal(Origin::root(), 0), TreasuryError::InvalidIndex); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); + assert_noop!( + Treasury::approve_proposal(RuntimeOrigin::root(), 0), + TreasuryError::InvalidIndex + ); }); } @@ -340,8 +349,8 @@ fn accepted_spend_proposal_enacted_on_spend_period() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Balances::free_balance(3), 100); @@ -355,8 +364,8 @@ fn pot_underflow_should_not_diminish() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 150, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 150, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed @@ -377,14 +386,14 @@ fn treasury_account_doesnt_get_deleted() { assert_eq!(Treasury::pot(), 100); let treasury_balance = Balances::free_balance(&Treasury::account_id()); - assert_ok!(Treasury::propose_spend(Origin::signed(0), treasury_balance, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), treasury_balance, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed - assert_ok!(Treasury::propose_spend(Origin::signed(0), Treasury::pot(), 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 1)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), Treasury::pot(), 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 1)); >::on_initialize(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied @@ -407,10 +416,10 @@ fn inexistent_account_works() { assert_eq!(Balances::free_balance(Treasury::account_id()), 0); // Account does not exist assert_eq!(Treasury::pot(), 0); // Pot is empty - assert_ok!(Treasury::propose_spend(Origin::signed(0), 99, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 1)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 99, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 1)); >::on_initialize(2); assert_eq!(Treasury::pot(), 0); // Pot hasn't changed assert_eq!(Balances::free_balance(3), 0); // Balance of `3` hasn't changed @@ -434,7 +443,7 @@ fn propose_bounty_works() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 10, b"1234567890".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 10, b"1234567890".to_vec())); assert_eq!(last_event(), BountiesEvent::BountyProposed { index: 0 }); @@ -469,17 +478,21 @@ fn propose_bounty_validation_works() { assert_eq!(Treasury::pot(), 100); assert_noop!( - Bounties::propose_bounty(Origin::signed(1), 0, [0; 17_000].to_vec()), + Bounties::propose_bounty(RuntimeOrigin::signed(1), 0, [0; 17_000].to_vec()), Error::::ReasonTooBig ); assert_noop!( - Bounties::propose_bounty(Origin::signed(1), 10, b"12345678901234567890".to_vec()), + Bounties::propose_bounty( + RuntimeOrigin::signed(1), + 10, + b"12345678901234567890".to_vec() + ), Error::::InsufficientProposersBalance ); assert_noop!( - Bounties::propose_bounty(Origin::signed(1), 0, b"12345678901234567890".to_vec()), + Bounties::propose_bounty(RuntimeOrigin::signed(1), 0, b"12345678901234567890".to_vec()), Error::::InvalidValue ); }); @@ -490,11 +503,11 @@ fn close_bounty_works() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_noop!(Bounties::close_bounty(Origin::root(), 0), Error::::InvalidIndex); + assert_noop!(Bounties::close_bounty(RuntimeOrigin::root(), 0), Error::::InvalidIndex); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 10, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 10, b"12345".to_vec())); - assert_ok!(Bounties::close_bounty(Origin::root(), 0)); + assert_ok!(Bounties::close_bounty(RuntimeOrigin::root(), 0)); let deposit: u64 = 80 + 5; @@ -515,11 +528,14 @@ fn approve_bounty_works() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_noop!(Bounties::approve_bounty(Origin::root(), 0), Error::::InvalidIndex); + assert_noop!( + Bounties::approve_bounty(RuntimeOrigin::root(), 0), + Error::::InvalidIndex + ); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); let deposit: u64 = 80 + 5; @@ -536,7 +552,10 @@ fn approve_bounty_works() { ); assert_eq!(Bounties::bounty_approvals(), vec![0]); - assert_noop!(Bounties::close_bounty(Origin::root(), 0), Error::::UnexpectedStatus); + assert_noop!( + Bounties::close_bounty(RuntimeOrigin::root(), 0), + Error::::UnexpectedStatus + ); // deposit not returned yet assert_eq!(Balances::reserved_balance(0), deposit); @@ -572,24 +591,24 @@ fn assign_curator_works() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_noop!( - Bounties::propose_curator(Origin::root(), 0, 4, 4), + Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 4), Error::::InvalidIndex ); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); assert_noop!( - Bounties::propose_curator(Origin::root(), 0, 4, 50), + Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 50), Error::::InvalidFee ); let fee = 4; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -603,15 +622,18 @@ fn assign_curator_works() { } ); - assert_noop!(Bounties::accept_curator(Origin::signed(1), 0), Error::::RequireCurator); assert_noop!( - Bounties::accept_curator(Origin::signed(4), 0), + Bounties::accept_curator(RuntimeOrigin::signed(1), 0), + Error::::RequireCurator + ); + assert_noop!( + Bounties::accept_curator(RuntimeOrigin::signed(4), 0), pallet_balances::Error::::InsufficientBalance ); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); let expected_deposit = Bounties::calculate_curator_deposit(&fee); @@ -637,18 +659,18 @@ fn unassign_curator_works() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); let fee = 4; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); - assert_noop!(Bounties::unassign_curator(Origin::signed(1), 0), BadOrigin); - assert_ok!(Bounties::unassign_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); + assert_noop!(Bounties::unassign_curator(RuntimeOrigin::signed(1), 0), BadOrigin); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(4), 0)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -662,11 +684,11 @@ fn unassign_curator_works() { } ); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); let expected_deposit = Bounties::calculate_curator_deposit(&fee); - assert_ok!(Bounties::unassign_curator(Origin::root(), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::root(), 0)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -691,26 +713,26 @@ fn award_and_claim_bounty_works() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); let fee = 4; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); let expected_deposit = Bounties::calculate_curator_deposit(&fee); assert_eq!(Balances::free_balance(4), 10 - expected_deposit); assert_noop!( - Bounties::award_bounty(Origin::signed(1), 0, 3), + Bounties::award_bounty(RuntimeOrigin::signed(1), 0, 3), Error::::RequireCurator ); - assert_ok!(Bounties::award_bounty(Origin::signed(4), 0, 3)); + assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(4), 0, 3)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -724,14 +746,18 @@ fn award_and_claim_bounty_works() { } ); - assert_noop!(Bounties::claim_bounty(Origin::signed(1), 0), Error::::Premature); + assert_noop!(Bounties::claim_bounty(RuntimeOrigin::signed(1), 0), Error::::Premature); System::set_block_number(5); >::on_initialize(5); - assert_ok!(Balances::transfer(Origin::signed(0), Bounties::bounty_account_id(0), 10)); + assert_ok!(Balances::transfer( + RuntimeOrigin::signed(0), + Bounties::bounty_account_id(0), + 10 + )); - assert_ok!(Bounties::claim_bounty(Origin::signed(1), 0)); + assert_ok!(Bounties::claim_bounty(RuntimeOrigin::signed(1), 0)); assert_eq!( last_event(), @@ -754,17 +780,17 @@ fn claim_handles_high_fee() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&4, 30); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 49)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 49)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); - assert_ok!(Bounties::award_bounty(Origin::signed(4), 0, 3)); + assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(4), 0, 3)); System::set_block_number(5); >::on_initialize(5); @@ -773,7 +799,7 @@ fn claim_handles_high_fee() { let res = Balances::slash(&Bounties::bounty_account_id(0), 10); assert_eq!(res.0.peek(), 10); - assert_ok!(Bounties::claim_bounty(Origin::signed(1), 0)); + assert_ok!(Bounties::claim_bounty(RuntimeOrigin::signed(1), 0)); assert_eq!( last_event(), @@ -796,14 +822,18 @@ fn cancel_and_refund() { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Balances::transfer(Origin::signed(0), Bounties::bounty_account_id(0), 10)); + assert_ok!(Balances::transfer( + RuntimeOrigin::signed(0), + Bounties::bounty_account_id(0), + 10 + )); assert_eq!( Bounties::bounties(0).unwrap(), @@ -819,9 +849,9 @@ fn cancel_and_refund() { assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 60); - assert_noop!(Bounties::close_bounty(Origin::signed(0), 0), BadOrigin); + assert_noop!(Bounties::close_bounty(RuntimeOrigin::signed(0), 0), BadOrigin); - assert_ok!(Bounties::close_bounty(Origin::root(), 0)); + assert_ok!(Bounties::close_bounty(RuntimeOrigin::root(), 0)); // `- 25 + 10` assert_eq!(Treasury::pot(), 85); @@ -833,27 +863,30 @@ fn award_and_cancel() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 0, 10)); - assert_ok!(Bounties::accept_curator(Origin::signed(0), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 0, 10)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(0), 0)); assert_eq!(Balances::free_balance(0), 95); assert_eq!(Balances::reserved_balance(0), 5); - assert_ok!(Bounties::award_bounty(Origin::signed(0), 0, 3)); + assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(0), 0, 3)); // Cannot close bounty directly when payout is happening... - assert_noop!(Bounties::close_bounty(Origin::root(), 0), Error::::PendingPayout); + assert_noop!( + Bounties::close_bounty(RuntimeOrigin::root(), 0), + Error::::PendingPayout + ); // Instead unassign the curator to slash them and then close. - assert_ok!(Bounties::unassign_curator(Origin::root(), 0)); - assert_ok!(Bounties::close_bounty(Origin::root(), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::root(), 0)); + assert_ok!(Bounties::close_bounty(RuntimeOrigin::root(), 0)); assert_eq!(last_event(), BountiesEvent::BountyCanceled { index: 0 }); @@ -873,15 +906,15 @@ fn expire_and_unassign() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 1, 10)); - assert_ok!(Bounties::accept_curator(Origin::signed(1), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 1, 10)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(1), 0)); assert_eq!(Balances::free_balance(1), 93); assert_eq!(Balances::reserved_balance(1), 5); @@ -889,12 +922,15 @@ fn expire_and_unassign() { System::set_block_number(22); >::on_initialize(22); - assert_noop!(Bounties::unassign_curator(Origin::signed(0), 0), Error::::Premature); + assert_noop!( + Bounties::unassign_curator(RuntimeOrigin::signed(0), 0), + Error::::Premature + ); System::set_block_number(23); >::on_initialize(23); - assert_ok!(Bounties::unassign_curator(Origin::signed(0), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(0), 0)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -919,20 +955,20 @@ fn extend_expiry() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); assert_noop!( - Bounties::extend_bounty_expiry(Origin::signed(1), 0, Vec::new()), + Bounties::extend_bounty_expiry(RuntimeOrigin::signed(1), 0, Vec::new()), Error::::UnexpectedStatus ); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 10)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 10)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); assert_eq!(Balances::free_balance(4), 5); assert_eq!(Balances::reserved_balance(4), 5); @@ -941,10 +977,10 @@ fn extend_expiry() { >::on_initialize(10); assert_noop!( - Bounties::extend_bounty_expiry(Origin::signed(0), 0, Vec::new()), + Bounties::extend_bounty_expiry(RuntimeOrigin::signed(0), 0, Vec::new()), Error::::RequireCurator ); - assert_ok!(Bounties::extend_bounty_expiry(Origin::signed(4), 0, Vec::new())); + assert_ok!(Bounties::extend_bounty_expiry(RuntimeOrigin::signed(4), 0, Vec::new())); assert_eq!( Bounties::bounties(0).unwrap(), @@ -958,7 +994,7 @@ fn extend_expiry() { } ); - assert_ok!(Bounties::extend_bounty_expiry(Origin::signed(4), 0, Vec::new())); + assert_ok!(Bounties::extend_bounty_expiry(RuntimeOrigin::signed(4), 0, Vec::new())); assert_eq!( Bounties::bounties(0).unwrap(), @@ -975,8 +1011,11 @@ fn extend_expiry() { System::set_block_number(25); >::on_initialize(25); - assert_noop!(Bounties::unassign_curator(Origin::signed(0), 0), Error::::Premature); - assert_ok!(Bounties::unassign_curator(Origin::signed(4), 0)); + assert_noop!( + Bounties::unassign_curator(RuntimeOrigin::signed(0), 0), + Error::::Premature + ); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(4), 0)); assert_eq!(Balances::free_balance(4), 10); // not slashed assert_eq!(Balances::reserved_balance(4), 0); @@ -1049,14 +1088,14 @@ fn unassign_curator_self() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 1, 10)); - assert_ok!(Bounties::accept_curator(Origin::signed(1), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 1, 10)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(1), 0)); assert_eq!(Balances::free_balance(1), 93); assert_eq!(Balances::reserved_balance(1), 5); @@ -1064,7 +1103,7 @@ fn unassign_curator_self() { System::set_block_number(8); >::on_initialize(8); - assert_ok!(Bounties::unassign_curator(Origin::signed(1), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(1), 0)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -1097,14 +1136,14 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&user, 100); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), bounty_index, user, fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(user), bounty_index)); let expected_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!(Balances::free_balance(&user), 100 - expected_deposit); @@ -1119,14 +1158,14 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&user, 100); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); System::set_block_number(4); >::on_initialize(4); - assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), bounty_index, user, fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(user), bounty_index)); let expected_deposit = CuratorDepositMin::get(); assert_eq!(Balances::free_balance(&user), 100 - expected_deposit); @@ -1143,14 +1182,14 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&user, starting_balance); Balances::make_free_balance_be(&0, starting_balance); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); System::set_block_number(6); >::on_initialize(6); - assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), bounty_index, user, fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(user), bounty_index)); let expected_deposit = CuratorDepositMax::get(); assert_eq!(Balances::free_balance(&user), starting_balance - expected_deposit); @@ -1170,8 +1209,8 @@ fn approve_bounty_works_second_instance() { assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); assert_eq!(Balances::free_balance(&Treasury1::account_id()), 201); - assert_ok!(Bounties1::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties1::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties1::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties1::approve_bounty(RuntimeOrigin::root(), 0)); >::on_initialize(2); >::on_initialize(2); diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index c9dbc8742c56a..67983b15f4579 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -71,7 +71,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -211,19 +211,19 @@ fn add_child_bounty() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); let fee = 8; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // This verifies that the accept curator logic took a deposit. let expected_deposit = CuratorDepositMultiplier::get() * fee; @@ -234,7 +234,7 @@ fn add_child_bounty() { // Acc-4 is the parent curator. // Call from invalid origin & check for error "RequireCurator". assert_noop!( - ChildBounties::add_child_bounty(Origin::signed(0), 0, 10, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty(RuntimeOrigin::signed(0), 0, 10, b"12345-p1".to_vec()), BountiesError::RequireCurator, ); @@ -246,17 +246,22 @@ fn add_child_bounty() { assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); assert_noop!( - ChildBounties::add_child_bounty(Origin::signed(4), 0, 50, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty(RuntimeOrigin::signed(4), 0, 50, b"12345-p1".to_vec()), pallet_balances::Error::::KeepAlive, ); assert_noop!( - ChildBounties::add_child_bounty(Origin::signed(4), 0, 100, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty(RuntimeOrigin::signed(4), 0, 100, b"12345-p1".to_vec()), Error::::InsufficientBountyBalance, ); // Add child-bounty with valid value, which can be funded by parent bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); // Check for the event child-bounty added. assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); @@ -299,16 +304,16 @@ fn child_bounty_assign_curator() { Balances::make_free_balance_be(&4, 101); Balances::make_free_balance_be(&8, 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); let fee = 4; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Bounty account status before adding child-bounty. assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); @@ -322,7 +327,12 @@ fn child_bounty_assign_curator() { // Add child-bounty. // Acc-4 is the parent curator & make sure enough deposit. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); @@ -335,7 +345,7 @@ fn child_bounty_assign_curator() { assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); let fee = 6u64; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), @@ -353,11 +363,11 @@ fn child_bounty_assign_curator() { assert_eq!(Balances::reserved_balance(4), expected_deposit); assert_noop!( - ChildBounties::accept_curator(Origin::signed(3), 0, 0), + ChildBounties::accept_curator(RuntimeOrigin::signed(3), 0, 0), BountiesError::RequireCurator, ); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; @@ -403,34 +413,39 @@ fn award_claim_child_bounty() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose and accept curator for child-bounty. let fee = 8; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); // Award child-bounty. // Test for non child-bounty curator. assert_noop!( - ChildBounties::award_child_bounty(Origin::signed(3), 0, 0, 7), + ChildBounties::award_child_bounty(RuntimeOrigin::signed(3), 0, 0, 7), BountiesError::RequireCurator, ); - assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + assert_ok!(ChildBounties::award_child_bounty(RuntimeOrigin::signed(8), 0, 0, 7)); let expected_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( @@ -451,13 +466,13 @@ fn award_claim_child_bounty() { // Claim child-bounty. // Test for Premature condition. assert_noop!( - ChildBounties::claim_child_bounty(Origin::signed(7), 0, 0), + ChildBounties::claim_child_bounty(RuntimeOrigin::signed(7), 0, 0), BountiesError::Premature ); System::set_block_number(9); - assert_ok!(ChildBounties::claim_child_bounty(Origin::signed(7), 0, 0)); + assert_ok!(ChildBounties::claim_child_bounty(RuntimeOrigin::signed(7), 0, 0)); // Ensure child-bounty curator is paid with curator fee & deposit refund. assert_eq!(Balances::free_balance(8), 101 + fee); @@ -489,19 +504,24 @@ fn close_child_bounty_added() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); @@ -509,11 +529,11 @@ fn close_child_bounty_added() { // Close child-bounty. // Wrong origin. - assert_noop!(ChildBounties::close_child_bounty(Origin::signed(7), 0, 0), BadOrigin); - assert_noop!(ChildBounties::close_child_bounty(Origin::signed(8), 0, 0), BadOrigin); + assert_noop!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(7), 0, 0), BadOrigin); + assert_noop!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(8), 0, 0), BadOrigin); // Correct origin - parent curator. - assert_ok!(ChildBounties::close_child_bounty(Origin::signed(4), 0, 0)); + assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0)); // Check the child-bounty count. assert_eq!(ChildBounties::parent_child_bounties(0), 0); @@ -541,28 +561,33 @@ fn close_child_bounty_active() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose and accept curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, 2)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); // Close child-bounty in active state. - assert_ok!(ChildBounties::close_child_bounty(Origin::signed(4), 0, 0)); + assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0)); // Check the child-bounty count. assert_eq!(ChildBounties::parent_child_bounties(0), 0); @@ -594,33 +619,38 @@ fn close_child_bounty_pending() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); let parent_fee = 6; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, parent_fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, parent_fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose and accept curator for child-bounty. let child_fee = 4; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, child_fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, child_fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); let expected_child_deposit = CuratorDepositMin::get(); - assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + assert_ok!(ChildBounties::award_child_bounty(RuntimeOrigin::signed(8), 0, 0, 7)); // Close child-bounty in pending_payout state. assert_noop!( - ChildBounties::close_child_bounty(Origin::signed(4), 0, 0), + ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0), BountiesError::PendingPayout ); @@ -650,25 +680,30 @@ fn child_bounty_added_unassign_curator() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Unassign curator in added state. assert_noop!( - ChildBounties::unassign_curator(Origin::signed(4), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(4), 0, 0), BountiesError::UnexpectedStatus ); }); @@ -687,24 +722,29 @@ fn child_bounty_curator_proposed_unassign_curator() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, 2)); assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), @@ -718,10 +758,10 @@ fn child_bounty_curator_proposed_unassign_curator() { ); // Random account cannot unassign the curator when in proposed state. - assert_noop!(ChildBounties::unassign_curator(Origin::signed(99), 0, 0), BadOrigin); + assert_noop!(ChildBounties::unassign_curator(RuntimeOrigin::signed(99), 0, 0), BadOrigin); // Unassign curator. - assert_ok!(ChildBounties::unassign_curator(Origin::signed(4), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(4), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -759,18 +799,23 @@ fn child_bounty_active_unassign_curator() { Balances::make_free_balance_be(&7, 101); // Child-bounty curator 2. Balances::make_free_balance_be(&8, 101); // Child-bounty curator 3. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Create Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); System::set_block_number(3); @@ -778,8 +823,8 @@ fn child_bounty_active_unassign_curator() { // Propose and accept curator for child-bounty. let fee = 6; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( @@ -797,7 +842,7 @@ fn child_bounty_active_unassign_curator() { >::on_initialize(4); // Unassign curator - from reject origin. - assert_ok!(ChildBounties::unassign_curator(Origin::root(), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::root(), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -817,8 +862,8 @@ fn child_bounty_active_unassign_curator() { // Propose and accept curator for child-bounty again. let fee = 2; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 7, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(7), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 7, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(7), 0, 0)); let expected_child_deposit = CuratorDepositMin::get(); assert_eq!( @@ -836,7 +881,7 @@ fn child_bounty_active_unassign_curator() { >::on_initialize(5); // Unassign curator again - from parent curator. - assert_ok!(ChildBounties::unassign_curator(Origin::signed(4), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(4), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -855,8 +900,8 @@ fn child_bounty_active_unassign_curator() { assert_eq!(Balances::reserved_balance(7), 0); // slashed // Propose and accept curator for child-bounty again. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 6, 2)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(6), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 6, 2)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(6), 0, 0)); assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), @@ -873,7 +918,7 @@ fn child_bounty_active_unassign_curator() { >::on_initialize(6); // Unassign curator again - from child-bounty curator. - assert_ok!(ChildBounties::unassign_curator(Origin::signed(6), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(6), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -893,8 +938,8 @@ fn child_bounty_active_unassign_curator() { // Propose and accept curator for child-bounty one last time. let fee = 2; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 6, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(6), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 6, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(6), 0, 0)); let expected_child_deposit = CuratorDepositMin::get(); assert_eq!( @@ -914,7 +959,7 @@ fn child_bounty_active_unassign_curator() { // Unassign curator again - from non curator; non reject origin; some random guy. // Bounty update period is not yet complete. assert_noop!( - ChildBounties::unassign_curator(Origin::signed(3), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0), BountiesError::Premature ); @@ -922,7 +967,7 @@ fn child_bounty_active_unassign_curator() { >::on_initialize(20); // Unassign child curator from random account after inactivity. - assert_ok!(ChildBounties::unassign_curator(Origin::signed(3), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -960,17 +1005,22 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { Balances::make_free_balance_be(&7, 101); // Child-bounty curator 2. Balances::make_free_balance_be(&8, 101); // Child-bounty curator 3. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Create Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); System::set_block_number(3); @@ -978,8 +1028,8 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { // Propose and accept curator for child-bounty. let fee = 8; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( @@ -997,7 +1047,7 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { >::on_initialize(4); // Unassign parent bounty curator. - assert_ok!(Bounties::unassign_curator(Origin::root(), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::root(), 0)); System::set_block_number(5); >::on_initialize(5); @@ -1005,12 +1055,12 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { // Try unassign child-bounty curator - from non curator; non reject // origin; some random guy. Bounty update period is not yet complete. assert_noop!( - ChildBounties::unassign_curator(Origin::signed(3), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0), Error::::ParentBountyNotActive ); // Unassign curator - from reject origin. - assert_ok!(ChildBounties::unassign_curator(Origin::root(), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::root(), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -1032,16 +1082,16 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { >::on_initialize(6); // Propose and accept curator for parent-bounty again. - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 5, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(5), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 5, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(5), 0)); System::set_block_number(7); >::on_initialize(7); // Propose and accept curator for child-bounty again. let fee = 2; - assert_ok!(ChildBounties::propose_curator(Origin::signed(5), 0, 0, 7, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(7), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(5), 0, 0, 7, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(7), 0, 0)); let expected_deposit = CuratorDepositMin::get(); assert_eq!( @@ -1059,18 +1109,18 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { >::on_initialize(8); assert_noop!( - ChildBounties::unassign_curator(Origin::signed(3), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0), BountiesError::Premature ); // Unassign parent bounty curator again. - assert_ok!(Bounties::unassign_curator(Origin::signed(5), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(5), 0)); System::set_block_number(9); >::on_initialize(9); // Unassign curator again - from parent curator. - assert_ok!(ChildBounties::unassign_curator(Origin::signed(7), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(7), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -1103,24 +1153,29 @@ fn close_parent_with_child_bounty() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); // Try add child-bounty. // Should fail, parent bounty not active yet. assert_noop!( - ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty(RuntimeOrigin::signed(4), 0, 10, b"12345-p1".to_vec()), Error::::ParentBountyNotActive ); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); System::set_block_number(4); @@ -1129,21 +1184,21 @@ fn close_parent_with_child_bounty() { // Try close parent-bounty. // Child bounty active, can't close parent. assert_noop!( - Bounties::close_bounty(Origin::root(), 0), + Bounties::close_bounty(RuntimeOrigin::root(), 0), BountiesError::HasActiveChildBounty ); System::set_block_number(2); // Close child-bounty. - assert_ok!(ChildBounties::close_child_bounty(Origin::root(), 0, 0)); + assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::root(), 0, 0)); // Check the child-bounty count. assert_eq!(ChildBounties::parent_child_bounties(0), 0); // Try close parent-bounty again. // Should pass this time. - assert_ok!(Bounties::close_bounty(Origin::root(), 0)); + assert_ok!(Bounties::close_bounty(RuntimeOrigin::root(), 0)); }); } @@ -1162,17 +1217,22 @@ fn children_curator_fee_calculation_test() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); System::set_block_number(4); @@ -1181,13 +1241,13 @@ fn children_curator_fee_calculation_test() { let fee = 6; // Propose curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); // Check curator fee added to the sum. assert_eq!(ChildBounties::children_curator_fees(0), fee); // Accept curator for child-bounty. - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); // Award child-bounty. - assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + assert_ok!(ChildBounties::award_child_bounty(RuntimeOrigin::signed(8), 0, 0, 7)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; @@ -1209,18 +1269,18 @@ fn children_curator_fee_calculation_test() { System::set_block_number(9); // Claim child-bounty. - assert_ok!(ChildBounties::claim_child_bounty(Origin::signed(7), 0, 0)); + assert_ok!(ChildBounties::claim_child_bounty(RuntimeOrigin::signed(7), 0, 0)); // Check the child-bounty count. assert_eq!(ChildBounties::parent_child_bounties(0), 0); // Award the parent bounty. - assert_ok!(Bounties::award_bounty(Origin::signed(4), 0, 9)); + assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(4), 0, 9)); System::set_block_number(15); // Claim the parent bounty. - assert_ok!(Bounties::claim_bounty(Origin::signed(9), 0)); + assert_ok!(Bounties::claim_bounty(RuntimeOrigin::signed(9), 0)); // Ensure parent-bounty curator received correctly reduced fee. assert_eq!(Balances::free_balance(4), 101 + 6 - fee); // 101 + 6 - 2 @@ -1247,22 +1307,22 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&Treasury::account_id(), parent_value * 3); Balances::make_free_balance_be(&parent_curator, parent_fee * 100); assert_ok!(Bounties::propose_bounty( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_value, b"12345".to_vec() )); - assert_ok!(Bounties::approve_bounty(Origin::root(), parent_index)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), parent_index)); System::set_block_number(2); >::on_initialize(2); assert_ok!(Bounties::propose_curator( - Origin::root(), + RuntimeOrigin::root(), parent_index, parent_curator, parent_fee )); - assert_ok!(Bounties::accept_curator(Origin::signed(parent_curator), parent_index)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(parent_curator), parent_index)); // Now we can start creating some child bounties. // Case 1: Parent and child curator are not the same. @@ -1275,7 +1335,7 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&child_curator, starting_balance); assert_ok!(ChildBounties::add_child_bounty( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_value, b"12345-p1".to_vec() @@ -1283,14 +1343,14 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(3); >::on_initialize(3); assert_ok!(ChildBounties::propose_curator( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_index, child_curator, child_fee )); assert_ok!(ChildBounties::accept_curator( - Origin::signed(child_curator), + RuntimeOrigin::signed(child_curator), parent_index, child_index )); @@ -1310,7 +1370,7 @@ fn accept_curator_handles_different_deposit_calculations() { let reserved_before = Balances::reserved_balance(&parent_curator); assert_ok!(ChildBounties::add_child_bounty( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_value, b"12345-p1".to_vec() @@ -1318,14 +1378,14 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(4); >::on_initialize(4); assert_ok!(ChildBounties::propose_curator( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_index, child_curator, child_fee )); assert_ok!(ChildBounties::accept_curator( - Origin::signed(child_curator), + RuntimeOrigin::signed(child_curator), parent_index, child_index )); @@ -1343,7 +1403,7 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&child_curator, starting_balance); assert_ok!(ChildBounties::add_child_bounty( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_value, b"12345-p1".to_vec() @@ -1351,14 +1411,14 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(5); >::on_initialize(5); assert_ok!(ChildBounties::propose_curator( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_index, child_curator, child_fee )); assert_ok!(ChildBounties::accept_curator( - Origin::signed(child_curator), + RuntimeOrigin::signed(child_curator), parent_index, child_index )); @@ -1379,7 +1439,7 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&child_curator, starting_balance); assert_ok!(ChildBounties::add_child_bounty( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_value, b"12345-p1".to_vec() @@ -1387,14 +1447,14 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(5); >::on_initialize(5); assert_ok!(ChildBounties::propose_curator( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_index, child_curator, child_fee )); assert_ok!(ChildBounties::accept_curator( - Origin::signed(child_curator), + RuntimeOrigin::signed(child_curator), parent_index, child_index )); diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 49da641e3e204..e934924033552 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -181,12 +181,14 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The outer origin type. - type Origin: From>; + type RuntimeOrigin: From>; /// The outer call dispatch type. type Proposal: Parameter - + Dispatchable>::Origin, PostInfo = PostDispatchInfo> - + From> + + Dispatchable< + RuntimeOrigin = >::RuntimeOrigin, + PostInfo = PostDispatchInfo, + > + From> + GetDispatchInfo; /// The outer event type. diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 13b9a24f7889d..19c54e0493c7b 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -64,7 +64,7 @@ mod mock_democracy { pub trait Config: frame_system::Config + Sized { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type ExternalMajorityOrigin: EnsureOrigin; + type ExternalMajorityOrigin: EnsureOrigin; } #[pallet::call] @@ -98,7 +98,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -120,7 +120,7 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } impl Config for Test { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type MotionDuration = ConstU64<3>; @@ -130,7 +130,7 @@ impl Config for Test { type WeightInfo = (); } impl Config for Test { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type MotionDuration = ConstU64<3>; @@ -144,7 +144,7 @@ impl mock_democracy::Config for Test { type ExternalMajorityOrigin = EnsureProportionAtLeast; } impl Config for Test { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type MotionDuration = ConstU64<3>; @@ -200,22 +200,28 @@ fn close_works() { let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); System::set_block_number(3); assert_noop!( - Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len), + Collective::close(RuntimeOrigin::signed(4), hash, 0, proposal_weight, proposal_len), Error::::TooEarly ); System::set_block_number(4); - assert_ok!(Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(4), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), @@ -267,17 +273,17 @@ fn proposal_weight_limit_works_on_approve() { // Set 1 as prime voter Prime::::set(Some(1)); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); // With 1's prime vote, this should pass System::set_block_number(4); assert_noop!( Collective::close( - Origin::signed(4), + RuntimeOrigin::signed(4), hash, 0, proposal_weight - Weight::from_ref_time(100), @@ -285,7 +291,13 @@ fn proposal_weight_limit_works_on_approve() { ), Error::::WrongProposalWeight ); - assert_ok!(Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(4), + hash, + 0, + proposal_weight, + proposal_len + )); }) } @@ -302,7 +314,7 @@ fn proposal_weight_limit_ignored_on_disapprove() { let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len @@ -310,7 +322,7 @@ fn proposal_weight_limit_ignored_on_disapprove() { // No votes, this proposal wont pass System::set_block_number(4); assert_ok!(Collective::close( - Origin::signed(4), + RuntimeOrigin::signed(4), hash, 0, proposal_weight - Weight::from_ref_time(100), @@ -327,23 +339,29 @@ fn close_with_prime_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::set_members( - Origin::root(), + RuntimeOrigin::root(), vec![1, 2, 3], Some(3), MaxMembers::get() )); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); System::set_block_number(4); - assert_ok!(Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(4), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), @@ -389,23 +407,29 @@ fn close_with_voting_prime_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::set_members( - Origin::root(), + RuntimeOrigin::root(), vec![1, 2, 3], Some(1), MaxMembers::get() )); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); System::set_block_number(4); - assert_ok!(Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(4), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), @@ -453,25 +477,25 @@ fn close_with_no_prime_but_majority_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(CollectiveMajority::set_members( - Origin::root(), + RuntimeOrigin::root(), vec![1, 2, 3, 4, 5], Some(5), MaxMembers::get() )); assert_ok!(CollectiveMajority::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 5, Box::new(proposal.clone()), proposal_len )); - assert_ok!(CollectiveMajority::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(CollectiveMajority::vote(Origin::signed(2), hash, 0, true)); - assert_ok!(CollectiveMajority::vote(Origin::signed(3), hash, 0, true)); + assert_ok!(CollectiveMajority::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(CollectiveMajority::vote(RuntimeOrigin::signed(2), hash, 0, true)); + assert_ok!(CollectiveMajority::vote(RuntimeOrigin::signed(3), hash, 0, true)); System::set_block_number(4); assert_ok!(CollectiveMajority::close( - Origin::signed(4), + RuntimeOrigin::signed(4), hash, 0, proposal_weight, @@ -533,13 +557,13 @@ fn removal_of_old_voters_votes_works() { let hash = BlakeTwo256::hash_of(&proposal); let end = 4; assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![1, 2], nays: vec![], end }) @@ -554,13 +578,13 @@ fn removal_of_old_voters_votes_works() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::propose( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(2), hash, 1, true)); - assert_ok!(Collective::vote(Origin::signed(3), hash, 1, false)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 1, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(3), hash, 1, false)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![3], end }) @@ -581,18 +605,23 @@ fn removal_of_old_voters_votes_works_with_set_members() { let hash = BlakeTwo256::hash_of(&proposal); let end = 4; assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![1, 2], nays: vec![], end }) ); - assert_ok!(Collective::set_members(Origin::root(), vec![2, 3, 4], None, MaxMembers::get())); + assert_ok!(Collective::set_members( + RuntimeOrigin::root(), + vec![2, 3, 4], + None, + MaxMembers::get() + )); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![2], nays: vec![], end }) @@ -602,18 +631,23 @@ fn removal_of_old_voters_votes_works_with_set_members() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::propose( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(2), hash, 1, true)); - assert_ok!(Collective::vote(Origin::signed(3), hash, 1, false)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 1, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(3), hash, 1, false)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![3], end }) ); - assert_ok!(Collective::set_members(Origin::root(), vec![2, 4], None, MaxMembers::get())); + assert_ok!(Collective::set_members( + RuntimeOrigin::root(), + vec![2, 4], + None, + MaxMembers::get() + )); assert_eq!( Collective::voting(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![], end }) @@ -629,7 +663,7 @@ fn propose_works() { let hash = proposal.blake2_256().into(); let end = 4; assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len @@ -660,7 +694,7 @@ fn limit_active_proposals() { let proposal = make_proposal(i as u64); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len @@ -669,7 +703,12 @@ fn limit_active_proposals() { let proposal = make_proposal(MaxProposals::get() as u64 + 1); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); assert_noop!( - Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()), proposal_len), + Collective::propose( + RuntimeOrigin::signed(1), + 3, + Box::new(proposal.clone()), + proposal_len + ), Error::::TooManyProposals ); }) @@ -684,7 +723,12 @@ fn correct_validate_and_get_proposal() { old_count: MaxMembers::get(), }); let length = proposal.encode().len() as u32; - assert_ok!(Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()), length)); + assert_ok!(Collective::propose( + RuntimeOrigin::signed(1), + 3, + Box::new(proposal.clone()), + length + )); let hash = BlakeTwo256::hash_of(&proposal); let weight = proposal.get_dispatch_info().weight; @@ -722,7 +766,12 @@ fn motions_ignoring_non_collective_proposals_works() { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); assert_noop!( - Collective::propose(Origin::signed(42), 3, Box::new(proposal.clone()), proposal_len), + Collective::propose( + RuntimeOrigin::signed(42), + 3, + Box::new(proposal.clone()), + proposal_len + ), Error::::NotMember ); }); @@ -735,13 +784,13 @@ fn motions_ignoring_non_collective_votes_works() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); assert_noop!( - Collective::vote(Origin::signed(42), hash, 0, true), + Collective::vote(RuntimeOrigin::signed(42), hash, 0, true), Error::::NotMember, ); }); @@ -755,13 +804,13 @@ fn motions_ignoring_bad_index_collective_vote_works() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); assert_noop!( - Collective::vote(Origin::signed(2), hash, 1, true), + Collective::vote(RuntimeOrigin::signed(2), hash, 1, true), Error::::WrongIndex, ); }); @@ -775,7 +824,7 @@ fn motions_vote_after_works() { let hash: H256 = proposal.blake2_256().into(); let end = 4; assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len @@ -786,25 +835,25 @@ fn motions_vote_after_works() { Some(Votes { index: 0, threshold: 2, ayes: vec![], nays: vec![], end }) ); // Cast first aye vote. - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 2, ayes: vec![1], nays: vec![], end }) ); // Try to cast a duplicate aye vote. assert_noop!( - Collective::vote(Origin::signed(1), hash, 0, true), + Collective::vote(RuntimeOrigin::signed(1), hash, 0, true), Error::::DuplicateVote, ); // Cast a nay vote. - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, false)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, false)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 2, ayes: vec![], nays: vec![1], end }) ); // Try to cast a duplicate nay vote. assert_noop!( - Collective::vote(Origin::signed(1), hash, 0, false), + Collective::vote(RuntimeOrigin::signed(1), hash, 0, false), Error::::DuplicateVote, ); @@ -844,7 +893,7 @@ fn motions_all_first_vote_free_works() { let hash: H256 = proposal.blake2_256().into(); let end = 4; assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len, @@ -856,40 +905,40 @@ fn motions_all_first_vote_free_works() { // For the motion, acc 2's first vote, expecting Ok with Pays::No. let vote_rval: DispatchResultWithPostInfo = - Collective::vote(Origin::signed(2), hash, 0, true); + Collective::vote(RuntimeOrigin::signed(2), hash, 0, true); assert_eq!(vote_rval.unwrap().pays_fee, Pays::No); // Duplicate vote, expecting error with Pays::Yes. let vote_rval: DispatchResultWithPostInfo = - Collective::vote(Origin::signed(2), hash, 0, true); + Collective::vote(RuntimeOrigin::signed(2), hash, 0, true); assert_eq!(vote_rval.unwrap_err().post_info.pays_fee, Pays::Yes); // Modifying vote, expecting ok with Pays::Yes. let vote_rval: DispatchResultWithPostInfo = - Collective::vote(Origin::signed(2), hash, 0, false); + Collective::vote(RuntimeOrigin::signed(2), hash, 0, false); assert_eq!(vote_rval.unwrap().pays_fee, Pays::Yes); // For the motion, acc 3's first vote, expecting Ok with Pays::No. let vote_rval: DispatchResultWithPostInfo = - Collective::vote(Origin::signed(3), hash, 0, true); + Collective::vote(RuntimeOrigin::signed(3), hash, 0, true); assert_eq!(vote_rval.unwrap().pays_fee, Pays::No); // acc 3 modify the vote, expecting Ok with Pays::Yes. let vote_rval: DispatchResultWithPostInfo = - Collective::vote(Origin::signed(3), hash, 0, false); + Collective::vote(RuntimeOrigin::signed(3), hash, 0, false); assert_eq!(vote_rval.unwrap().pays_fee, Pays::Yes); // Test close() Extrincis | Check DispatchResultWithPostInfo with Pay Info let proposal_weight = proposal.get_dispatch_info().weight; let close_rval: DispatchResultWithPostInfo = - Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len); + Collective::close(RuntimeOrigin::signed(2), hash, 0, proposal_weight, proposal_len); assert_eq!(close_rval.unwrap().pays_fee, Pays::No); // trying to close the proposal, which is already closed. // Expecting error "ProposalMissing" with Pays::Yes let close_rval: DispatchResultWithPostInfo = - Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len); + Collective::close(RuntimeOrigin::signed(2), hash, 0, proposal_weight, proposal_len); assert_eq!(close_rval.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -902,16 +951,22 @@ fn motions_reproposing_disapproved_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, false)); - assert_ok!(Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, false)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!(*Collective::proposals(), vec![]); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len @@ -933,14 +988,20 @@ fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { // // Failed to execute with only 2 yes votes. assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); - assert_ok!(Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), vec![ @@ -981,15 +1042,21 @@ fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { // Executed with 3 yes votes. assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 1, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 1, true)); - assert_ok!(Collective::vote(Origin::signed(3), hash, 1, true)); - assert_ok!(Collective::close(Origin::signed(2), hash, 1, proposal_weight, proposal_len)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 1, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 1, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(3), hash, 1, true)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 1, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), vec![ @@ -1046,14 +1113,20 @@ fn motions_disapproval_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, false)); - assert_ok!(Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, false)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), @@ -1099,14 +1172,20 @@ fn motions_approval_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); - assert_ok!(Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), @@ -1154,7 +1233,7 @@ fn motion_with_no_votes_closes_with_disapproval() { let proposal_weight = proposal.get_dispatch_info().weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len @@ -1172,7 +1251,7 @@ fn motion_with_no_votes_closes_with_disapproval() { // Closing the motion too early is not possible because it has neither // an approving or disapproving simple majority due to the lack of votes. assert_noop!( - Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len), + Collective::close(RuntimeOrigin::signed(2), hash, 0, proposal_weight, proposal_len), Error::::TooEarly ); @@ -1180,7 +1259,13 @@ fn motion_with_no_votes_closes_with_disapproval() { let closing_block = System::block_number() + MotionDuration::get(); System::set_block_number(closing_block); // we can successfully close the motion. - assert_ok!(Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 0, + proposal_weight, + proposal_len + )); // Events show that the close ended in a disapproval. assert_eq!( @@ -1208,28 +1293,28 @@ fn close_disapprove_does_not_care_about_weight_or_len() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); // First we make the proposal succeed - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); // It will not close with bad weight/len information assert_noop!( - Collective::close(Origin::signed(2), hash, 0, Weight::zero(), 0), + Collective::close(RuntimeOrigin::signed(2), hash, 0, Weight::zero(), 0), Error::::WrongProposalLength, ); assert_noop!( - Collective::close(Origin::signed(2), hash, 0, Weight::zero(), proposal_len), + Collective::close(RuntimeOrigin::signed(2), hash, 0, Weight::zero(), proposal_len), Error::::WrongProposalWeight, ); // Now we make the proposal fail - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, false)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, false)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, false)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, false)); // It can close even if the weight/len information is bad - assert_ok!(Collective::close(Origin::signed(2), hash, 0, Weight::zero(), 0)); + assert_ok!(Collective::close(RuntimeOrigin::signed(2), hash, 0, Weight::zero(), 0)); }) } @@ -1240,16 +1325,16 @@ fn disapprove_proposal_works() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); // Proposal would normally succeed - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); // But Root can disapprove and remove it anyway - assert_ok!(Collective::disapprove_proposal(Origin::root(), hash)); + assert_ok!(Collective::disapprove_proposal(RuntimeOrigin::root(), hash)); assert_eq!( System::events(), vec![ diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 0fbf821b2e284..2b5cf6353256c 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1306,7 +1306,7 @@ where } fn call_runtime(&self, call: ::RuntimeCall) -> DispatchResultWithPostInfo { - let mut origin: T::Origin = RawOrigin::Signed(self.address().clone()).into(); + let mut origin: T::RuntimeOrigin = RawOrigin::Signed(self.address().clone()).into(); origin.add_filter(T::CallFilter::contains); call.dispatch(origin) } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 842fa02f34529..abe91a9046ce2 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -246,7 +246,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The overarching call type. - type RuntimeCall: Dispatchable + type RuntimeCall: Dispatchable + GetDispatchInfo + codec::Decode + IsType<::RuntimeCall>; diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index d5f4df161b723..12029abd59e46 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -277,7 +277,7 @@ impl frame_system::Config for Test { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -489,7 +489,7 @@ fn calling_plain_account_fails() { let base_cost = <::WeightInfo as WeightInfo>::call(); assert_eq!( - Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, None, Vec::new()), + Contracts::call(RuntimeOrigin::signed(ALICE), BOB, 0, GAS_LIMIT, None, Vec::new()), Err(DispatchErrorWithPostInfo { error: Error::::ContractNotFound.into(), post_info: PostDispatchInfo { @@ -512,14 +512,14 @@ fn instantiate_and_call_and_deposit_event() { // We determine the storage deposit limit after uploading because it depends on ALICEs free // balance which is changed by uploading a module. - assert_ok!(Contracts::upload_code(Origin::signed(ALICE), wasm, None)); + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, None)); // Drop previous events initialize_block(2); // Check at the end to get hash on error easily assert_ok!(Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), value, GAS_LIMIT, None, @@ -603,7 +603,7 @@ fn deposit_event_max_value_limit() { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 30_000, GAS_LIMIT, None, @@ -615,7 +615,7 @@ fn deposit_event_max_value_limit() { // Call contract with allowed storage value. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT * 2, // we are copying a huge buffer, @@ -626,7 +626,7 @@ fn deposit_event_max_value_limit() { // Call contract with too large a storage value. assert_err_ignore_postinfo!( Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr, 0, GAS_LIMIT, @@ -646,7 +646,7 @@ fn run_out_of_gas() { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100 * min_balance, GAS_LIMIT, None, @@ -660,7 +660,7 @@ fn run_out_of_gas() { // loops forever. assert_err_ignore_postinfo!( Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr, // newly created account 0, Weight::from_ref_time(1_000_000_000_000), @@ -680,12 +680,12 @@ fn instantiate_unique_trie_id() { ExtBuilder::default().existential_deposit(500).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); - Contracts::upload_code(Origin::signed(ALICE), wasm, None).unwrap(); + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, None).unwrap(); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Instantiate the contract and store its trie id for later comparison. assert_ok!(Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -698,7 +698,7 @@ fn instantiate_unique_trie_id() { // Try to instantiate it again without termination should yield an error. assert_err_ignore_postinfo!( Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -711,7 +711,7 @@ fn instantiate_unique_trie_id() { // Terminate the contract. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -721,7 +721,7 @@ fn instantiate_unique_trie_id() { // Re-Instantiate after termination. assert_ok!(Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -743,7 +743,7 @@ fn storage_max_value_limit() { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 30_000, GAS_LIMIT, None, @@ -756,7 +756,7 @@ fn storage_max_value_limit() { // Call contract with allowed storage value. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT * 2, // we are copying a huge buffer @@ -767,7 +767,7 @@ fn storage_max_value_limit() { // Call contract with too large a storage value. assert_err_ignore_postinfo!( Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr, 0, GAS_LIMIT, @@ -792,7 +792,7 @@ fn deploy_and_call_other_contract() { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -801,7 +801,7 @@ fn deploy_and_call_other_contract() { vec![], )); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -816,7 +816,7 @@ fn deploy_and_call_other_contract() { // Call BOB contract, which attempts to instantiate and call the callee contract and // makes various assertions on the results from those calls. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), caller_addr.clone(), 0, GAS_LIMIT, @@ -917,7 +917,7 @@ fn delegate_call() { // Instantiate the 'caller' assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 300_000, GAS_LIMIT, None, @@ -927,13 +927,13 @@ fn delegate_call() { )); // Only upload 'callee' code assert_ok!(Contracts::upload_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), callee_wasm, Some(codec::Compact(100_000)), )); assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), caller_addr.clone(), 1337, GAS_LIMIT, @@ -951,7 +951,7 @@ fn cannot_self_destruct_through_draning() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 1_000, GAS_LIMIT, None, @@ -967,7 +967,7 @@ fn cannot_self_destruct_through_draning() { // Call BOB which makes it send all funds to the zero address // The contract code asserts that the transfer was successful assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -992,7 +992,7 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -1009,7 +1009,7 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { // Create 100 bytes of storage with a price of per byte assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1021,7 +1021,7 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { // because the refund removes the reserved existential deposit. This should not happen. DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 500); assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1045,7 +1045,7 @@ fn cannot_self_destruct_by_refund_after_slash() { let min_balance = ::Currency::minimum_balance(); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -1057,7 +1057,7 @@ fn cannot_self_destruct_by_refund_after_slash() { // create 100 more reserved balance assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1075,7 +1075,7 @@ fn cannot_self_destruct_by_refund_after_slash() { // trigger a refund of 50 which would bring the contract below min when actually refunded assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1131,7 +1131,7 @@ fn cannot_self_destruct_while_live() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -1147,7 +1147,14 @@ fn cannot_self_destruct_while_live() { // Call BOB with input data, forcing it make a recursive call to itself to // self-destruct, resulting in a trap. assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![0],), + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![0], + ), Error::::ContractTrapped, ); @@ -1165,7 +1172,7 @@ fn self_destruct_works() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -1183,7 +1190,7 @@ fn self_destruct_works() { // Call BOB without input data which triggers termination. assert_matches!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), + Contracts::call(RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), Ok(_) ); @@ -1258,7 +1265,7 @@ fn destroy_contract_and_transfer_funds() { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 200_000, GAS_LIMIT, None, @@ -1270,7 +1277,7 @@ fn destroy_contract_and_transfer_funds() { // This deploys the BOB contract, which in turn deploys the CHARLIE contract during // construction. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 200_000, GAS_LIMIT, None, @@ -1286,7 +1293,7 @@ fn destroy_contract_and_transfer_funds() { // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr_bob, 0, GAS_LIMIT, @@ -1308,7 +1315,7 @@ fn cannot_self_destruct_in_constructor() { // Fail to instantiate the BOB because the contructor calls seal_terminate. assert_err_ignore_postinfo!( Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -1330,7 +1337,7 @@ fn crypto_hashes() { // Instantiate the CRYPTO_HASHES contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -1379,7 +1386,7 @@ fn transfer_return_code() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1418,7 +1425,7 @@ fn call_return_code() { let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1444,7 +1451,7 @@ fn call_return_code() { assert_return_code!(result, RuntimeReturnCode::NotCallable); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(CHARLIE), + RuntimeOrigin::signed(CHARLIE), min_balance * 100, GAS_LIMIT, None, @@ -1545,7 +1552,7 @@ fn instantiate_return_code() { let callee_hash = callee_hash.as_ref().to_vec(); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1555,7 +1562,7 @@ fn instantiate_return_code() { ),); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1645,7 +1652,7 @@ fn disabled_chain_extension_wont_deploy() { TestExtension::disable(); assert_err_ignore_postinfo!( Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 3 * min_balance, GAS_LIMIT, None, @@ -1665,7 +1672,7 @@ fn disabled_chain_extension_errors_on_call() { let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1676,7 +1683,7 @@ fn disabled_chain_extension_errors_on_call() { let addr = Contracts::contract_address(&ALICE, &hash, &[]); TestExtension::disable(); assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), + Contracts::call(RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), Error::::NoChainExtension, ); }); @@ -1689,7 +1696,7 @@ fn chain_extension_works() { let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1792,7 +1799,7 @@ fn chain_extension_works() { // We set the MSB part to 2 (instead of 0) which routes the request into the third extension assert_err_ignore_postinfo!( Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1811,7 +1818,7 @@ fn chain_extension_temp_storage_works() { let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1845,7 +1852,7 @@ fn lazy_removal_works() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1863,7 +1870,7 @@ fn lazy_removal_works() { // Terminate the contract assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1914,7 +1921,7 @@ fn lazy_batch_removal_works() { for i in 0..3u8 { assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1933,7 +1940,7 @@ fn lazy_batch_removal_works() { // Terminate the contract. Contract info should be gone, but value should be still there // as the lazy removal did not run, yet. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1976,7 +1983,7 @@ fn lazy_removal_partial_remove_works() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2003,7 +2010,7 @@ fn lazy_removal_partial_remove_works() { // Terminate the contract assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -2088,7 +2095,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2106,7 +2113,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { // Terminate the contract assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -2156,7 +2163,7 @@ fn lazy_removal_does_not_use_all_weight() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2189,7 +2196,7 @@ fn lazy_removal_does_not_use_all_weight() { // Terminate the contract assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -2236,7 +2243,7 @@ fn deletion_queue_full() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2252,7 +2259,7 @@ fn deletion_queue_full() { // Terminate the contract should fail assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), + Contracts::call(RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), Error::::DeletionQueueFull, ); @@ -2270,7 +2277,7 @@ fn refcounter() { // Create two contracts with the same code and check that they do in fact share it. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2279,7 +2286,7 @@ fn refcounter() { vec![0], )); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2291,7 +2298,7 @@ fn refcounter() { // Sharing should also work with the usual instantiate call assert_ok!(Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2307,18 +2314,39 @@ fn refcounter() { let addr2 = Contracts::contract_address(&ALICE, &code_hash, &[2]); // Terminating one contract should decrement the refcount - assert_ok!(Contracts::call(Origin::signed(ALICE), addr0, 0, GAS_LIMIT, None, vec![])); + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr0, + 0, + GAS_LIMIT, + None, + vec![] + )); assert_refcount!(code_hash, 2); // remove another one - assert_ok!(Contracts::call(Origin::signed(ALICE), addr1, 0, GAS_LIMIT, None, vec![])); + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr1, + 0, + GAS_LIMIT, + None, + vec![] + )); assert_refcount!(code_hash, 1); // Pristine code should still be there crate::PristineCode::::get(code_hash).unwrap(); // remove the last contract - assert_ok!(Contracts::call(Origin::signed(ALICE), addr2, 0, GAS_LIMIT, None, vec![])); + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr2, + 0, + GAS_LIMIT, + None, + vec![] + )); assert_refcount!(code_hash, 0); // refcount is `0` but code should still exists because it needs to be removed manually @@ -2337,7 +2365,7 @@ fn reinstrument_does_charge() { let code_len = wasm.len() as u32; assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2386,7 +2414,7 @@ fn debug_message_works() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 30_000, GAS_LIMIT, None, @@ -2409,7 +2437,7 @@ fn debug_message_logging_disabled() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 30_000, GAS_LIMIT, None, @@ -2422,7 +2450,7 @@ fn debug_message_logging_disabled() { let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![], false); assert_matches!(result.result, Ok(_)); // the dispatchables always run without debugging - assert_ok!(Contracts::call(Origin::signed(ALICE), addr, 0, GAS_LIMIT, None, vec![])); + assert_ok!(Contracts::call(RuntimeOrigin::signed(ALICE), addr, 0, GAS_LIMIT, None, vec![])); assert!(result.debug_message.is_empty()); }); } @@ -2434,7 +2462,7 @@ fn debug_message_invalid_utf8() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 30_000, GAS_LIMIT, None, @@ -2458,7 +2486,7 @@ fn gas_estimation_nested_call_fixed_limit() { let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2469,7 +2497,7 @@ fn gas_estimation_nested_call_fixed_limit() { let addr_caller = Contracts::contract_address(&ALICE, &caller_hash, &[0]); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2527,7 +2555,7 @@ fn gas_estimation_call_runtime() { let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2538,7 +2566,7 @@ fn gas_estimation_call_runtime() { let addr_caller = Contracts::contract_address(&ALICE, &caller_hash, &[0]); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2595,7 +2623,7 @@ fn ecdsa_recover() { // Instantiate the ecdsa_recover contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -2649,7 +2677,7 @@ fn upload_code_works() { assert!(!>::contains_key(code_hash)); assert_ok!(Contracts::upload_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000)) )); @@ -2687,7 +2715,7 @@ fn upload_code_limit_too_low() { initialize_block(2); assert_noop!( - Contracts::upload_code(Origin::signed(ALICE), wasm, Some(codec::Compact(100))), + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(100))), >::StorageDepositLimitExhausted, ); @@ -2706,7 +2734,7 @@ fn upload_code_not_enough_balance() { initialize_block(2); assert_noop!( - Contracts::upload_code(Origin::signed(ALICE), wasm, Some(codec::Compact(1_000))), + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000))), >::StorageDepositNotEnoughFunds, ); @@ -2725,13 +2753,13 @@ fn remove_code_works() { initialize_block(2); assert_ok!(Contracts::upload_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000)) )); assert!(>::contains_key(code_hash)); - assert_ok!(Contracts::remove_code(Origin::signed(ALICE), code_hash)); + assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash)); assert!(!>::contains_key(code_hash)); assert_eq!( @@ -2779,13 +2807,13 @@ fn remove_code_wrong_origin() { initialize_block(2); assert_ok!(Contracts::upload_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000)) )); assert_noop!( - Contracts::remove_code(Origin::signed(BOB), code_hash), + Contracts::remove_code(RuntimeOrigin::signed(BOB), code_hash), sp_runtime::traits::BadOrigin, ); @@ -2818,7 +2846,7 @@ fn remove_code_in_use() { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -2831,7 +2859,7 @@ fn remove_code_in_use() { initialize_block(2); assert_noop!( - Contracts::remove_code(Origin::signed(ALICE), code_hash), + Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), >::CodeInUse, ); @@ -2850,7 +2878,7 @@ fn remove_code_not_found() { initialize_block(2); assert_noop!( - Contracts::remove_code(Origin::signed(ALICE), code_hash), + Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), >::CodeNotFound, ); @@ -2870,7 +2898,7 @@ fn instantiate_with_zero_balance_works() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -2963,7 +2991,7 @@ fn instantiate_with_below_existential_deposit_works() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 50, GAS_LIMIT, None, @@ -3061,7 +3089,7 @@ fn storage_deposit_works() { let mut deposit = ::Currency::minimum_balance(); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -3076,7 +3104,7 @@ fn storage_deposit_works() { // Create storage assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 42, GAS_LIMIT, @@ -3090,7 +3118,7 @@ fn storage_deposit_works() { // Add more storage (but also remove some) assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -3103,7 +3131,7 @@ fn storage_deposit_works() { // Remove more storage (but also add some) assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -3210,7 +3238,7 @@ fn set_code_extrinsic() { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -3220,7 +3248,7 @@ fn set_code_extrinsic() { )); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - assert_ok!(Contracts::upload_code(Origin::signed(ALICE), new_wasm, None,)); + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), new_wasm, None,)); // Drop previous events initialize_block(2); @@ -3231,7 +3259,7 @@ fn set_code_extrinsic() { // only root can execute this extrinsic assert_noop!( - Contracts::set_code(Origin::signed(ALICE), addr.clone(), new_code_hash), + Contracts::set_code(RuntimeOrigin::signed(ALICE), addr.clone(), new_code_hash), sp_runtime::traits::BadOrigin, ); assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); @@ -3241,7 +3269,7 @@ fn set_code_extrinsic() { // contract must exist assert_noop!( - Contracts::set_code(Origin::root(), BOB, new_code_hash), + Contracts::set_code(RuntimeOrigin::root(), BOB, new_code_hash), >::ContractNotFound, ); assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); @@ -3251,7 +3279,7 @@ fn set_code_extrinsic() { // new code hash must exist assert_noop!( - Contracts::set_code(Origin::root(), addr.clone(), Default::default()), + Contracts::set_code(RuntimeOrigin::root(), addr.clone(), Default::default()), >::CodeNotFound, ); assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); @@ -3260,7 +3288,7 @@ fn set_code_extrinsic() { assert_eq!(System::events(), vec![],); // successful call - assert_ok!(Contracts::set_code(Origin::root(), addr.clone(), new_code_hash)); + assert_ok!(Contracts::set_code(RuntimeOrigin::root(), addr.clone(), new_code_hash)); assert_eq!(>::get(&addr).unwrap().code_hash, new_code_hash); assert_refcount!(&code_hash, 0); assert_refcount!(&new_code_hash, 1); @@ -3287,7 +3315,7 @@ fn call_after_killed_account_needs_funding() { let min_balance = ::Currency::minimum_balance(); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 700, GAS_LIMIT, None, @@ -3312,7 +3340,7 @@ fn call_after_killed_account_needs_funding() { // account in order to send balance there. assert_err_ignore_postinfo!( Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), min_balance - 1, GAS_LIMIT, @@ -3324,7 +3352,7 @@ fn call_after_killed_account_needs_funding() { // Sending zero should work as it does not do a transfer assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -3334,7 +3362,7 @@ fn call_after_killed_account_needs_funding() { // Sending minimum balance should work assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), min_balance, GAS_LIMIT, @@ -3416,12 +3444,12 @@ fn contract_reverted() { let input = (flags.bits(), buffer).encode(); // We just upload the code for later use - assert_ok!(Contracts::upload_code(Origin::signed(ALICE), wasm.clone(), None)); + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm.clone(), None)); // Calling extrinsic: revert leads to an error assert_err_ignore_postinfo!( Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -3435,7 +3463,7 @@ fn contract_reverted() { // Calling extrinsic: revert leads to an error assert_err_ignore_postinfo!( Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -3483,7 +3511,14 @@ fn contract_reverted() { // Calling extrinsic: revert leads to an error assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, input.clone()), + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + input.clone() + ), >::ContractReverted, ); @@ -3503,7 +3538,7 @@ fn code_rejected_error_works() { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_noop!( - Contracts::upload_code(Origin::signed(ALICE), wasm.clone(), None), + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm.clone(), None), >::CodeRejected, ); @@ -3537,7 +3572,7 @@ fn set_code_hash() { // Instantiate the 'caller' assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 300_000, GAS_LIMIT, None, @@ -3546,7 +3581,7 @@ fn set_code_hash() { vec![], )); // upload new code - assert_ok!(Contracts::upload_code(Origin::signed(ALICE), new_wasm.clone(), None)); + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), new_wasm.clone(), None)); System::reset_events(); diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index 7a97a46086398..7a3f80442014a 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -65,7 +65,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -269,28 +269,28 @@ fn basic_stuff() { #[test] fn basic_voting_works() { new_test_ext().execute_with(|| { - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(2, 5))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(2, 5))); assert_eq!(tally(3), Tally::from_parts(10, 0, 2)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(2, 5))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(2, 5))); assert_eq!(tally(3), Tally::from_parts(0, 10, 0)); assert_eq!(Balances::usable_balance(1), 8); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(5, 1))); assert_eq!(tally(3), Tally::from_parts(5, 0, 5)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(5, 1))); assert_eq!(tally(3), Tally::from_parts(0, 5, 0)); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0))); assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(10, 0))); assert_eq!(tally(3), Tally::from_parts(0, 1, 0)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::remove_vote(Origin::signed(1), None, 3)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); - assert_ok!(Voting::unlock(Origin::signed(1), class(3), 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -298,28 +298,28 @@ fn basic_voting_works() { #[test] fn voting_balance_gets_locked() { new_test_ext().execute_with(|| { - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(2, 5))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(2, 5))); assert_eq!(tally(3), Tally::from_parts(10, 0, 2)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(2, 5))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(2, 5))); assert_eq!(tally(3), Tally::from_parts(0, 10, 0)); assert_eq!(Balances::usable_balance(1), 8); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(5, 1))); assert_eq!(tally(3), Tally::from_parts(5, 0, 5)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(5, 1))); assert_eq!(tally(3), Tally::from_parts(0, 5, 0)); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0))); assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(10, 0))); assert_eq!(tally(3), Tally::from_parts(0, 1, 0)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::remove_vote(Origin::signed(1), None, 3)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); - assert_ok!(Voting::unlock(Origin::signed(1), class(3), 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -327,12 +327,12 @@ fn voting_balance_gets_locked() { #[test] fn successful_but_zero_conviction_vote_balance_can_be_unlocked() { new_test_ext().execute_with(|| { - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(1, 1))); - assert_ok!(Voting::vote(Origin::signed(2), 3, nay(20, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(1, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 3, nay(20, 0))); let c = class(3); Polls::set(vec![(3, Completed(3, false))].into_iter().collect()); - assert_ok!(Voting::remove_vote(Origin::signed(2), Some(c), 3)); - assert_ok!(Voting::unlock(Origin::signed(2), c, 2)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(2), Some(c), 3)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(2), c, 2)); assert_eq!(Balances::usable_balance(2), 20); }); } @@ -340,12 +340,12 @@ fn successful_but_zero_conviction_vote_balance_can_be_unlocked() { #[test] fn unsuccessful_conviction_vote_balance_can_be_unlocked() { new_test_ext().execute_with(|| { - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(1, 1))); - assert_ok!(Voting::vote(Origin::signed(2), 3, nay(20, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(1, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 3, nay(20, 0))); let c = class(3); Polls::set(vec![(3, Completed(3, false))].into_iter().collect()); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(c), 3)); - assert_ok!(Voting::unlock(Origin::signed(1), c, 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(c), 3)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), c, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -354,17 +354,17 @@ fn unsuccessful_conviction_vote_balance_can_be_unlocked() { fn successful_conviction_vote_balance_stays_locked_for_correct_time() { new_test_ext().execute_with(|| { for i in 1..=5 { - assert_ok!(Voting::vote(Origin::signed(i), 3, aye(10, i as u8))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(i), 3, aye(10, i as u8))); } let c = class(3); Polls::set(vec![(3, Completed(3, true))].into_iter().collect()); for i in 1..=5 { - assert_ok!(Voting::remove_vote(Origin::signed(i), Some(c), 3)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(i), Some(c), 3)); } for block in 1..=(3 + 5 * 3) { run_to(block); for i in 1..=5 { - assert_ok!(Voting::unlock(Origin::signed(i), c, i)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(i), c, i)); let expired = block >= (3 << (i - 1)) + 3; assert_eq!(Balances::usable_balance(i), i * 10 - if expired { 0 } else { 10 }); } @@ -385,20 +385,20 @@ fn classwise_delegation_works() { .into_iter() .collect(), ); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); - assert_ok!(Voting::delegate(Origin::signed(1), 1, 3, Conviction::Locked1x, 5)); - assert_ok!(Voting::delegate(Origin::signed(1), 2, 4, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 1, 3, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 2, 4, Conviction::Locked1x, 5)); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::vote(Origin::signed(2), 0, aye(10, 0))); - assert_ok!(Voting::vote(Origin::signed(2), 1, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(2), 2, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(3), 0, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(3), 1, aye(10, 0))); - assert_ok!(Voting::vote(Origin::signed(3), 2, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(4), 0, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(4), 1, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(4), 2, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 0, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 1, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 2, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(3), 0, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(3), 1, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(3), 2, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(4), 0, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(4), 1, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(4), 2, aye(10, 0))); // 4 hasn't voted yet assert_eq!( @@ -414,7 +414,7 @@ fn classwise_delegation_works() { ); // 4 votes nay to 3. - assert_ok!(Voting::vote(Origin::signed(4), 3, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(4), 3, nay(10, 0))); assert_eq!( Polls::get(), vec![ @@ -428,8 +428,8 @@ fn classwise_delegation_works() { ); // Redelegate for class 2 to account 3. - assert_ok!(Voting::undelegate(Origin::signed(1), 2)); - assert_ok!(Voting::delegate(Origin::signed(1), 2, 3, Conviction::Locked1x, 5)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 2)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 2, 3, Conviction::Locked1x, 5)); assert_eq!( Polls::get(), vec![ @@ -443,12 +443,12 @@ fn classwise_delegation_works() { ); // Redelegating with a lower lock does not forget previous lock and updates correctly. - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::undelegate(Origin::signed(1), 1)); - assert_ok!(Voting::undelegate(Origin::signed(1), 2)); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 3)); - assert_ok!(Voting::delegate(Origin::signed(1), 1, 3, Conviction::Locked1x, 3)); - assert_ok!(Voting::delegate(Origin::signed(1), 2, 4, Conviction::Locked1x, 3)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 1)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 2)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 3)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 1, 3, Conviction::Locked1x, 3)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 2, 4, Conviction::Locked1x, 3)); assert_eq!( Polls::get(), vec![ @@ -462,24 +462,24 @@ fn classwise_delegation_works() { ); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); // unlock does nothing since the delegation already took place. assert_eq!(Balances::usable_balance(1), 5); // Redelegating with higher amount extends previous lock. - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 6)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 6)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 4); - assert_ok!(Voting::undelegate(Origin::signed(1), 1)); - assert_ok!(Voting::delegate(Origin::signed(1), 1, 3, Conviction::Locked1x, 7)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 1)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 1, 3, Conviction::Locked1x, 7)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); assert_eq!(Balances::usable_balance(1), 3); - assert_ok!(Voting::undelegate(Origin::signed(1), 2)); - assert_ok!(Voting::delegate(Origin::signed(1), 2, 4, Conviction::Locked1x, 8)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 2)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 2, 4, Conviction::Locked1x, 8)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 2); assert_eq!( Polls::get(), @@ -499,14 +499,14 @@ fn classwise_delegation_works() { fn redelegation_after_vote_ending_should_keep_lock() { new_test_ext().execute_with(|| { Polls::set(vec![(0, Ongoing(Tally::new(0), 0))].into_iter().collect()); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); - assert_ok!(Voting::vote(Origin::signed(2), 0, aye(10, 1))); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 0, aye(10, 1))); Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 3, Conviction::Locked1x, 3)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 3, Conviction::Locked1x, 3)); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 5); }); } @@ -523,9 +523,9 @@ fn lock_amalgamation_valid_with_multiple_removed_votes() { .into_iter() .collect(), ); - assert_ok!(Voting::vote(Origin::signed(1), 0, aye(5, 1))); - assert_ok!(Voting::vote(Origin::signed(1), 1, aye(10, 1))); - assert_ok!(Voting::vote(Origin::signed(1), 2, aye(5, 2))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 0, aye(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 1, aye(10, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 2, aye(5, 2))); assert_eq!(Balances::usable_balance(1), 0); Polls::set( @@ -533,28 +533,28 @@ fn lock_amalgamation_valid_with_multiple_removed_votes() { .into_iter() .collect(), ); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 0)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 2)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 2)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert!(Balances::usable_balance(1) <= 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -562,25 +562,25 @@ fn lock_amalgamation_valid_with_multiple_removed_votes() { #[test] fn lock_amalgamation_valid_with_multiple_delegations() { new_test_ext().execute_with(|| { - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 10)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked2x, 5)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 10)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked2x, 5)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert!(Balances::usable_balance(1) <= 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -589,32 +589,32 @@ fn lock_amalgamation_valid_with_multiple_delegations() { fn lock_amalgamation_valid_with_move_roundtrip_to_delegation() { new_test_ext().execute_with(|| { Polls::set(vec![(0, Ongoing(Tally::new(0), 0))].into_iter().collect()); - assert_ok!(Voting::vote(Origin::signed(1), 0, aye(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 0, aye(5, 1))); Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 0)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 10)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 10)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); Polls::set(vec![(1, Ongoing(Tally::new(0), 0))].into_iter().collect()); - assert_ok!(Voting::vote(Origin::signed(1), 1, aye(5, 2))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 1, aye(5, 2))); Polls::set(vec![(1, Completed(1, true))].into_iter().collect()); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 1)); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert!(Balances::usable_balance(1) <= 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -622,33 +622,33 @@ fn lock_amalgamation_valid_with_move_roundtrip_to_delegation() { #[test] fn lock_amalgamation_valid_with_move_roundtrip_to_casting() { new_test_ext().execute_with(|| { - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 5); Polls::set(vec![(0, Ongoing(Tally::new(0), 0))].into_iter().collect()); - assert_ok!(Voting::vote(Origin::signed(1), 0, aye(10, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 0, aye(10, 1))); Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 0)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked2x, 10)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked2x, 10)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert!(Balances::usable_balance(1) <= 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -656,30 +656,30 @@ fn lock_amalgamation_valid_with_move_roundtrip_to_casting() { #[test] fn lock_aggregation_over_different_classes_with_delegation_works() { new_test_ext().execute_with(|| { - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); - assert_ok!(Voting::delegate(Origin::signed(1), 1, 2, Conviction::Locked2x, 5)); - assert_ok!(Voting::delegate(Origin::signed(1), 2, 2, Conviction::Locked1x, 10)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 1, 2, Conviction::Locked2x, 5)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 2, 2, Conviction::Locked1x, 10)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::undelegate(Origin::signed(1), 1)); - assert_ok!(Voting::undelegate(Origin::signed(1), 2)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 1)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 2)); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -696,34 +696,34 @@ fn lock_aggregation_over_different_classes_with_casting_works() { .into_iter() .collect(), ); - assert_ok!(Voting::vote(Origin::signed(1), 0, aye(5, 1))); - assert_ok!(Voting::vote(Origin::signed(1), 1, aye(10, 1))); - assert_ok!(Voting::vote(Origin::signed(1), 2, aye(5, 2))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 0, aye(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 1, aye(10, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 2, aye(5, 2))); Polls::set( vec![(0, Completed(1, true)), (1, Completed(1, true)), (2, Completed(1, true))] .into_iter() .collect(), ); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(1), 1)); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(2), 2)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 0)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(1), 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(2), 2)); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -731,21 +731,30 @@ fn lock_aggregation_over_different_classes_with_casting_works() { #[test] fn errors_with_vote_work() { new_test_ext().execute_with(|| { - assert_noop!(Voting::vote(Origin::signed(1), 0, aye(10, 0)), Error::::NotOngoing); - assert_noop!(Voting::vote(Origin::signed(1), 1, aye(10, 0)), Error::::NotOngoing); - assert_noop!(Voting::vote(Origin::signed(1), 2, aye(10, 0)), Error::::NotOngoing); assert_noop!( - Voting::vote(Origin::signed(1), 3, aye(11, 0)), + Voting::vote(RuntimeOrigin::signed(1), 0, aye(10, 0)), + Error::::NotOngoing + ); + assert_noop!( + Voting::vote(RuntimeOrigin::signed(1), 1, aye(10, 0)), + Error::::NotOngoing + ); + assert_noop!( + Voting::vote(RuntimeOrigin::signed(1), 2, aye(10, 0)), + Error::::NotOngoing + ); + assert_noop!( + Voting::vote(RuntimeOrigin::signed(1), 3, aye(11, 0)), Error::::InsufficientFunds ); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::None, 10)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::None, 10)); assert_noop!( - Voting::vote(Origin::signed(1), 3, aye(10, 0)), + Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0)), Error::::AlreadyDelegating ); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); Polls::set( vec![ (0, Ongoing(Tally::new(0), 0)), @@ -756,11 +765,11 @@ fn errors_with_vote_work() { .into_iter() .collect(), ); - assert_ok!(Voting::vote(Origin::signed(1), 0, aye(10, 0))); - assert_ok!(Voting::vote(Origin::signed(1), 1, aye(10, 0))); - assert_ok!(Voting::vote(Origin::signed(1), 2, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 0, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 1, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 2, aye(10, 0))); assert_noop!( - Voting::vote(Origin::signed(1), 3, aye(10, 0)), + Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0)), Error::::MaxVotesReached ); }); @@ -770,21 +779,21 @@ fn errors_with_vote_work() { fn errors_with_delegating_work() { new_test_ext().execute_with(|| { assert_noop!( - Voting::delegate(Origin::signed(1), 0, 2, Conviction::None, 11), + Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::None, 11), Error::::InsufficientFunds ); assert_noop!( - Voting::delegate(Origin::signed(1), 3, 2, Conviction::None, 10), + Voting::delegate(RuntimeOrigin::signed(1), 3, 2, Conviction::None, 10), Error::::BadClass ); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0))); assert_noop!( - Voting::delegate(Origin::signed(1), 0, 2, Conviction::None, 10), + Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::None, 10), Error::::AlreadyVoting ); - assert_noop!(Voting::undelegate(Origin::signed(1), 0), Error::::NotDelegating); + assert_noop!(Voting::undelegate(RuntimeOrigin::signed(1), 0), Error::::NotDelegating); }); } @@ -792,31 +801,37 @@ fn errors_with_delegating_work() { fn remove_other_vote_works() { new_test_ext().execute_with(|| { assert_noop!( - Voting::remove_other_vote(Origin::signed(2), 1, 0, 3), + Voting::remove_other_vote(RuntimeOrigin::signed(2), 1, 0, 3), Error::::NotVoter ); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 2))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 2))); assert_noop!( - Voting::remove_other_vote(Origin::signed(2), 1, 0, 3), + Voting::remove_other_vote(RuntimeOrigin::signed(2), 1, 0, 3), Error::::NoPermission ); Polls::set(vec![(3, Completed(1, true))].into_iter().collect()); run_to(6); assert_noop!( - Voting::remove_other_vote(Origin::signed(2), 1, 0, 3), + Voting::remove_other_vote(RuntimeOrigin::signed(2), 1, 0, 3), Error::::NoPermissionYet ); run_to(7); - assert_ok!(Voting::remove_other_vote(Origin::signed(2), 1, 0, 3)); + assert_ok!(Voting::remove_other_vote(RuntimeOrigin::signed(2), 1, 0, 3)); }); } #[test] fn errors_with_remove_vote_work() { new_test_ext().execute_with(|| { - assert_noop!(Voting::remove_vote(Origin::signed(1), Some(0), 3), Error::::NotVoter); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 2))); + assert_noop!( + Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 3), + Error::::NotVoter + ); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 2))); Polls::set(vec![(3, Completed(1, true))].into_iter().collect()); - assert_noop!(Voting::remove_vote(Origin::signed(1), None, 3), Error::::ClassNeeded); + assert_noop!( + Voting::remove_vote(RuntimeOrigin::signed(1), None, 3), + Error::::ClassNeeded + ); }); } diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index ab4075bc82fc5..ab7ee3331e319 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -198,7 +198,7 @@ benchmarks! { let origin = T::CancellationOrigin::successful_origin(); let referendum_index = add_referendum::(0)?; assert_ok!(Democracy::::referendum_status(referendum_index)); - }: _(origin, referendum_index) + }: _(origin, referendum_index) verify { // Referendum has been canceled assert_noop!( @@ -225,7 +225,7 @@ benchmarks! { // Add a referendum of our proposal. let referendum_index = add_referendum::(0)?; assert_ok!(Democracy::::referendum_status(referendum_index)); - }: _(origin, hash, Some(referendum_index)) + }: _(origin, hash, Some(referendum_index)) verify { // Referendum has been canceled assert_noop!( @@ -250,7 +250,7 @@ benchmarks! { proposal_hash, (T::BlockNumber::zero(), addresses), ); - }: _(origin, proposal_hash) + }: _(origin, proposal_hash) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -259,7 +259,7 @@ benchmarks! { external_propose_majority { let origin = T::ExternalMajorityOrigin::successful_origin(); let proposal_hash = T::Hashing::hash_of(&0); - }: _(origin, proposal_hash) + }: _(origin, proposal_hash) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -268,7 +268,7 @@ benchmarks! { external_propose_default { let origin = T::ExternalDefaultOrigin::successful_origin(); let proposal_hash = T::Hashing::hash_of(&0); - }: _(origin, proposal_hash) + }: _(origin, proposal_hash) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -283,7 +283,7 @@ benchmarks! { let origin_fast_track = T::FastTrackOrigin::successful_origin(); let voting_period = T::FastTrackVotingPeriod::get(); let delay = 0u32; - }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) + }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) verify { assert_eq!(Democracy::::referendum_count(), 1, "referendum not created") } @@ -306,7 +306,7 @@ benchmarks! { let origin = T::VetoOrigin::successful_origin(); ensure!(NextExternal::::get().is_some(), "no external proposal"); - }: _(origin, proposal_hash) + }: _(origin, proposal_hash) verify { assert!(NextExternal::::get().is_none()); let (_, new_vetoers) = >::get(&proposal_hash).ok_or("no blacklist")?; @@ -322,7 +322,7 @@ benchmarks! { } let cancel_origin = T::CancelProposalOrigin::successful_origin(); - }: _(cancel_origin, 0) + }: _(cancel_origin, 0) cancel_referendum { let referendum_index = add_referendum::(0)?; diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index f6696065bfc87..3c1be19103998 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -253,7 +253,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + Sized { - type Proposal: Parameter + Dispatchable + From>; + type Proposal: Parameter + + Dispatchable + + From>; type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Currency type for this pallet. @@ -289,25 +291,25 @@ pub mod pallet { /// Origin from which the next tabled referendum may be forced. This is a normal /// "super-majority-required" referendum. - type ExternalOrigin: EnsureOrigin; + type ExternalOrigin: EnsureOrigin; /// Origin from which the next tabled referendum may be forced; this allows for the tabling /// of a majority-carries referendum. - type ExternalMajorityOrigin: EnsureOrigin; + type ExternalMajorityOrigin: EnsureOrigin; /// Origin from which the next tabled referendum may be forced; this allows for the tabling /// of a negative-turnout-bias (default-carries) referendum. - type ExternalDefaultOrigin: EnsureOrigin; + type ExternalDefaultOrigin: EnsureOrigin; /// Origin from which the next majority-carries (or more permissive) referendum may be /// tabled to vote according to the `FastTrackVotingPeriod` asynchronously in a similar /// manner to the emergency origin. It retains its threshold method. - type FastTrackOrigin: EnsureOrigin; + type FastTrackOrigin: EnsureOrigin; /// Origin from which the next majority-carries (or more permissive) referendum may be /// tabled to vote immediately and asynchronously in a similar manner to the emergency /// origin. It retains its threshold method. - type InstantOrigin: EnsureOrigin; + type InstantOrigin: EnsureOrigin; /// Indicator for whether an emergency origin is even allowed to happen. Some chains may /// want to set this permanently to `false`, others may want to condition it on things such @@ -320,13 +322,13 @@ pub mod pallet { type FastTrackVotingPeriod: Get; /// Origin from which any referendum may be cancelled in an emergency. - type CancellationOrigin: EnsureOrigin; + type CancellationOrigin: EnsureOrigin; /// Origin from which proposals may be blacklisted. - type BlacklistOrigin: EnsureOrigin; + type BlacklistOrigin: EnsureOrigin; /// Origin from which a proposal may be cancelled and its backers slashed. - type CancelProposalOrigin: EnsureOrigin; + type CancelProposalOrigin: EnsureOrigin; /// Origin for anyone able to veto proposals. /// @@ -334,7 +336,7 @@ pub mod pallet { /// /// The number of Vetoers for a proposal must be small, extrinsics are weighted according to /// [MAX_VETOERS](./const.MAX_VETOERS.html) - type VetoOrigin: EnsureOrigin; + type VetoOrigin: EnsureOrigin; /// Period in blocks where an external proposal may not be re-submitted after being vetoed. #[pallet::constant] @@ -345,7 +347,7 @@ pub mod pallet { type PreimageByteDeposit: Get>; /// An origin that can provide a preimage using operational extrinsics. - type OperationalPreimageOrigin: EnsureOrigin; + type OperationalPreimageOrigin: EnsureOrigin; /// Handler for the unbalanced reduction when slashing a preimage deposit. type Slash: OnUnbalanced>; diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index e3ed046813e23..17b35ee3c38cd 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -85,7 +85,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -111,7 +111,7 @@ parameter_types! { } impl pallet_scheduler::Config for Test { type RuntimeEvent = RuntimeEvent; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type PalletsOrigin = OriginCaller; type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; @@ -240,7 +240,7 @@ fn set_balance_proposal_hash(value: u64) -> H256 { fn set_balance_proposal_hash_and_note(value: u64) -> H256 { let p = set_balance_proposal(value); let h = BlakeTwo256::hash(&p[..]); - match Democracy::note_preimage(Origin::signed(6), p) { + match Democracy::note_preimage(RuntimeOrigin::signed(6), p) { Ok(_) => (), Err(x) if x == Error::::DuplicatePreimage.into() => (), Err(x) => panic!("{:?}", x), @@ -249,11 +249,11 @@ fn set_balance_proposal_hash_and_note(value: u64) -> H256 { } fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult { - Democracy::propose(Origin::signed(who), set_balance_proposal_hash(value), delay) + Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal_hash(value), delay) } fn propose_set_balance_and_note(who: u64, value: u64, delay: u64) -> DispatchResult { - Democracy::propose(Origin::signed(who), set_balance_proposal_hash_and_note(value), delay) + Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal_hash_and_note(value), delay) } fn next_block() { diff --git a/frame/democracy/src/tests/cancellation.rs b/frame/democracy/src/tests/cancellation.rs index 9035e17c5c80b..b98e51aa3d4d1 100644 --- a/frame/democracy/src/tests/cancellation.rs +++ b/frame/democracy/src/tests/cancellation.rs @@ -28,8 +28,8 @@ fn cancel_referendum_should_work() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - assert_ok!(Democracy::cancel_referendum(Origin::root(), r.into())); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); + assert_ok!(Democracy::cancel_referendum(RuntimeOrigin::root(), r.into())); assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); @@ -51,14 +51,17 @@ fn cancel_queued_should_work() { // start of 2 => next referendum scheduled. fast_forward_to(2); - assert_ok!(Democracy::vote(Origin::signed(1), 0, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1))); fast_forward_to(4); assert!(pallet_scheduler::Agenda::::get(6)[0].is_some()); - assert_noop!(Democracy::cancel_queued(Origin::root(), 1), Error::::ProposalMissing); - assert_ok!(Democracy::cancel_queued(Origin::root(), 0)); + assert_noop!( + Democracy::cancel_queued(RuntimeOrigin::root(), 1), + Error::::ProposalMissing + ); + assert_ok!(Democracy::cancel_queued(RuntimeOrigin::root(), 0)); assert!(pallet_scheduler::Agenda::::get(6)[0].is_none()); }); } @@ -75,8 +78,8 @@ fn emergency_cancel_should_work() { ); assert!(Democracy::referendum_status(r).is_ok()); - assert_noop!(Democracy::emergency_cancel(Origin::signed(3), r), BadOrigin); - assert_ok!(Democracy::emergency_cancel(Origin::signed(4), r)); + assert_noop!(Democracy::emergency_cancel(RuntimeOrigin::signed(3), r), BadOrigin); + assert_ok!(Democracy::emergency_cancel(RuntimeOrigin::signed(4), r)); assert!(Democracy::referendum_info(r).is_none()); // some time later... @@ -89,7 +92,7 @@ fn emergency_cancel_should_work() { ); assert!(Democracy::referendum_status(r).is_ok()); assert_noop!( - Democracy::emergency_cancel(Origin::signed(4), r), + Democracy::emergency_cancel(RuntimeOrigin::signed(4), r), Error::::AlreadyCanceled, ); }); diff --git a/frame/democracy/src/tests/delegation.rs b/frame/democracy/src/tests/delegation.rs index 3551ca8f91123..4c5ee79286055 100644 --- a/frame/democracy/src/tests/delegation.rs +++ b/frame/democracy/src/tests/delegation.rs @@ -29,33 +29,33 @@ fn single_proposal_should_work_with_delegation() { fast_forward_to(2); // Delegate first vote. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 20)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); let r = 0; - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_eq!(tally(r), Tally { ayes: 3, nays: 0, turnout: 30 }); // Delegate a second vote. - assert_ok!(Democracy::delegate(Origin::signed(3), 1, Conviction::None, 30)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 1, Conviction::None, 30)); assert_eq!(tally(r), Tally { ayes: 6, nays: 0, turnout: 60 }); // Reduce first vote. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 10)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 10)); assert_eq!(tally(r), Tally { ayes: 5, nays: 0, turnout: 50 }); // Second vote delegates to first; we don't do tiered delegation, so it doesn't get used. - assert_ok!(Democracy::delegate(Origin::signed(3), 2, Conviction::None, 30)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 2, Conviction::None, 30)); assert_eq!(tally(r), Tally { ayes: 2, nays: 0, turnout: 20 }); // Main voter cancels their vote - assert_ok!(Democracy::remove_vote(Origin::signed(1), r)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(1), r)); assert_eq!(tally(r), Tally { ayes: 0, nays: 0, turnout: 0 }); // First delegator delegates half funds with conviction; nothing changes yet. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked1x, 10)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked1x, 10)); assert_eq!(tally(r), Tally { ayes: 0, nays: 0, turnout: 0 }); // Main voter reinstates their vote - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_eq!(tally(r), Tally { ayes: 11, nays: 0, turnout: 20 }); }); } @@ -64,7 +64,7 @@ fn single_proposal_should_work_with_delegation() { fn self_delegation_not_allowed() { new_test_ext().execute_with(|| { assert_noop!( - Democracy::delegate(Origin::signed(1), 1, Conviction::None, 10), + Democracy::delegate(RuntimeOrigin::signed(1), 1, Conviction::None, 10), Error::::Nonsense, ); }); @@ -80,14 +80,14 @@ fn cyclic_delegation_should_unwind() { fast_forward_to(2); // Check behavior with cycle. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 20)); - assert_ok!(Democracy::delegate(Origin::signed(3), 2, Conviction::None, 30)); - assert_ok!(Democracy::delegate(Origin::signed(1), 3, Conviction::None, 10)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 2, Conviction::None, 30)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(1), 3, Conviction::None, 10)); let r = 0; - assert_ok!(Democracy::undelegate(Origin::signed(3))); - assert_ok!(Democracy::vote(Origin::signed(3), r, aye(3))); - assert_ok!(Democracy::undelegate(Origin::signed(1))); - assert_ok!(Democracy::vote(Origin::signed(1), r, nay(1))); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(3))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(3), r, aye(3))); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(1))); // Delegated vote is counted. assert_eq!(tally(r), Tally { ayes: 3, nays: 3, turnout: 60 }); @@ -105,13 +105,13 @@ fn single_proposal_should_work_with_vote_and_delegation() { fast_forward_to(2); let r = 0; - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - assert_ok!(Democracy::vote(Origin::signed(2), r, nay(2))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, nay(2))); assert_eq!(tally(r), Tally { ayes: 1, nays: 2, turnout: 30 }); // Delegate vote. - assert_ok!(Democracy::remove_vote(Origin::signed(2), r)); - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 20)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(2), r)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); // Delegated vote replaces the explicit vote. assert_eq!(tally(r), Tally { ayes: 3, nays: 0, turnout: 30 }); }); @@ -125,12 +125,12 @@ fn single_proposal_should_work_with_undelegation() { assert_ok!(propose_set_balance_and_note(1, 2, 1)); // Delegate and undelegate vote. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 20)); - assert_ok!(Democracy::undelegate(Origin::signed(2))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(2))); fast_forward_to(2); let r = 0; - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); // Delegated vote is not counted. assert_eq!(tally(r), Tally { ayes: 1, nays: 0, turnout: 10 }); @@ -143,11 +143,11 @@ fn single_proposal_should_work_with_delegation_and_vote() { new_test_ext().execute_with(|| { let r = begin_referendum(); // Delegate, undelegate and vote. - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 20)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); assert_eq!(tally(r), Tally { ayes: 3, nays: 0, turnout: 30 }); - assert_ok!(Democracy::undelegate(Origin::signed(2))); - assert_ok!(Democracy::vote(Origin::signed(2), r, aye(2))); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(2))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(2))); // Delegated vote is not counted. assert_eq!(tally(r), Tally { ayes: 3, nays: 0, turnout: 30 }); }); @@ -159,8 +159,8 @@ fn conviction_should_be_honored_in_delegation() { new_test_ext().execute_with(|| { let r = begin_referendum(); // Delegate and vote. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked6x, 20)); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); // Delegated vote is huge. assert_eq!(tally(r), Tally { ayes: 121, nays: 0, turnout: 30 }); }); @@ -171,8 +171,12 @@ fn split_vote_delegation_should_be_ignored() { // If transactor voted, delegated vote is overwritten. new_test_ext().execute_with(|| { let r = begin_referendum(); - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked6x, 20)); - assert_ok!(Democracy::vote(Origin::signed(1), r, AccountVote::Split { aye: 10, nay: 0 })); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20)); + assert_ok!(Democracy::vote( + RuntimeOrigin::signed(1), + r, + AccountVote::Split { aye: 10, nay: 0 } + )); // Delegated vote is huge. assert_eq!(tally(r), Tally { ayes: 1, nays: 0, turnout: 10 }); }); @@ -184,8 +188,8 @@ fn redelegation_keeps_lock() { new_test_ext().execute_with(|| { let r = begin_referendum(); // Delegate and vote. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked6x, 20)); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); // Delegated vote is huge. assert_eq!(tally(r), Tally { ayes: 121, nays: 0, turnout: 30 }); @@ -196,14 +200,14 @@ fn redelegation_keeps_lock() { assert_eq!(VotingOf::::get(2).prior(), &prior_lock); // Delegate someone else at a lower conviction and amount - assert_ok!(Democracy::delegate(Origin::signed(2), 3, Conviction::None, 10)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 3, Conviction::None, 10)); // 6x prior should appear w/ locked balance. prior_lock.accumulate(98, 20); assert_eq!(VotingOf::::get(2).prior(), &prior_lock); assert_eq!(VotingOf::::get(2).locked_balance(), 20); // Unlock shouldn't work - assert_ok!(Democracy::unlock(Origin::signed(2), 2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(2), 2)); assert_eq!(VotingOf::::get(2).prior(), &prior_lock); assert_eq!(VotingOf::::get(2).locked_balance(), 20); @@ -211,7 +215,7 @@ fn redelegation_keeps_lock() { // Now unlock can remove the prior lock and reduce the locked amount. assert_eq!(VotingOf::::get(2).prior(), &prior_lock); - assert_ok!(Democracy::unlock(Origin::signed(2), 2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(2), 2)); assert_eq!(VotingOf::::get(2).prior(), &vote::PriorLock::default()); assert_eq!(VotingOf::::get(2).locked_balance(), 10); }); diff --git a/frame/democracy/src/tests/external_proposing.rs b/frame/democracy/src/tests/external_proposing.rs index 6ac34a38723ce..fda555b9c3459 100644 --- a/frame/democracy/src/tests/external_proposing.rs +++ b/frame/democracy/src/tests/external_proposing.rs @@ -24,53 +24,56 @@ fn veto_external_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(Democracy::external_propose( - Origin::signed(2), + RuntimeOrigin::signed(2), set_balance_proposal_hash_and_note(2), )); assert!(>::exists()); let h = set_balance_proposal_hash_and_note(2); - assert_ok!(Democracy::veto_external(Origin::signed(3), h)); + assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h)); // cancelled. assert!(!>::exists()); // fails - same proposal can't be resubmitted. assert_noop!( - Democracy::external_propose(Origin::signed(2), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),), Error::::ProposalBlacklisted ); fast_forward_to(1); // fails as we're still in cooloff period. assert_noop!( - Democracy::external_propose(Origin::signed(2), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),), Error::::ProposalBlacklisted ); fast_forward_to(2); // works; as we're out of the cooloff period. assert_ok!(Democracy::external_propose( - Origin::signed(2), + RuntimeOrigin::signed(2), set_balance_proposal_hash_and_note(2), )); assert!(>::exists()); // 3 can't veto the same thing twice. - assert_noop!(Democracy::veto_external(Origin::signed(3), h), Error::::AlreadyVetoed); + assert_noop!( + Democracy::veto_external(RuntimeOrigin::signed(3), h), + Error::::AlreadyVetoed + ); // 4 vetoes. - assert_ok!(Democracy::veto_external(Origin::signed(4), h)); + assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(4), h)); // cancelled again. assert!(!>::exists()); fast_forward_to(3); // same proposal fails as we're still in cooloff assert_noop!( - Democracy::external_propose(Origin::signed(2), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),), Error::::ProposalBlacklisted ); // different proposal works fine. assert_ok!(Democracy::external_propose( - Origin::signed(2), + RuntimeOrigin::signed(2), set_balance_proposal_hash_and_note(3), )); }); @@ -82,18 +85,21 @@ fn external_blacklisting_should_work() { System::set_block_number(0); assert_ok!(Democracy::external_propose( - Origin::signed(2), + RuntimeOrigin::signed(2), set_balance_proposal_hash_and_note(2), )); let hash = set_balance_proposal_hash(2); - assert_ok!(Democracy::blacklist(Origin::root(), hash, None)); + assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None)); fast_forward_to(2); assert_noop!(Democracy::referendum_status(0), Error::::ReferendumInvalid); assert_noop!( - Democracy::external_propose(Origin::signed(2), set_balance_proposal_hash_and_note(2),), + Democracy::external_propose( + RuntimeOrigin::signed(2), + set_balance_proposal_hash_and_note(2), + ), Error::::ProposalBlacklisted, ); }); @@ -104,15 +110,15 @@ fn external_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!( - Democracy::external_propose(Origin::signed(1), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(1), set_balance_proposal_hash(2),), BadOrigin, ); assert_ok!(Democracy::external_propose( - Origin::signed(2), + RuntimeOrigin::signed(2), set_balance_proposal_hash_and_note(2), )); assert_noop!( - Democracy::external_propose(Origin::signed(2), set_balance_proposal_hash(1),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(1),), Error::::DuplicateProposal ); fast_forward_to(2); @@ -134,11 +140,14 @@ fn external_majority_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!( - Democracy::external_propose_majority(Origin::signed(1), set_balance_proposal_hash(2)), + Democracy::external_propose_majority( + RuntimeOrigin::signed(1), + set_balance_proposal_hash(2) + ), BadOrigin, ); assert_ok!(Democracy::external_propose_majority( - Origin::signed(3), + RuntimeOrigin::signed(3), set_balance_proposal_hash_and_note(2) )); fast_forward_to(2); @@ -160,11 +169,14 @@ fn external_default_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!( - Democracy::external_propose_default(Origin::signed(3), set_balance_proposal_hash(2)), + Democracy::external_propose_default( + RuntimeOrigin::signed(3), + set_balance_proposal_hash(2) + ), BadOrigin, ); assert_ok!(Democracy::external_propose_default( - Origin::signed(1), + RuntimeOrigin::signed(1), set_balance_proposal_hash_and_note(2) )); fast_forward_to(2); @@ -186,7 +198,7 @@ fn external_and_public_interleaving_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(Democracy::external_propose( - Origin::signed(2), + RuntimeOrigin::signed(2), set_balance_proposal_hash_and_note(1), )); assert_ok!(propose_set_balance_and_note(6, 2, 2)); @@ -206,7 +218,7 @@ fn external_and_public_interleaving_works() { ); // replenish external assert_ok!(Democracy::external_propose( - Origin::signed(2), + RuntimeOrigin::signed(2), set_balance_proposal_hash_and_note(3), )); @@ -240,7 +252,7 @@ fn external_and_public_interleaving_works() { ); // replenish external assert_ok!(Democracy::external_propose( - Origin::signed(2), + RuntimeOrigin::signed(2), set_balance_proposal_hash_and_note(5), )); @@ -259,7 +271,7 @@ fn external_and_public_interleaving_works() { ); // replenish both assert_ok!(Democracy::external_propose( - Origin::signed(2), + RuntimeOrigin::signed(2), set_balance_proposal_hash_and_note(7), )); assert_ok!(propose_set_balance_and_note(6, 4, 2)); @@ -281,7 +293,7 @@ fn external_and_public_interleaving_works() { assert_ok!(propose_set_balance_and_note(6, 6, 2)); // cancel external let h = set_balance_proposal_hash_and_note(7); - assert_ok!(Democracy::veto_external(Origin::signed(3), h)); + assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h)); fast_forward_to(12); diff --git a/frame/democracy/src/tests/fast_tracking.rs b/frame/democracy/src/tests/fast_tracking.rs index caf83c6d46120..8fef985c8561c 100644 --- a/frame/democracy/src/tests/fast_tracking.rs +++ b/frame/democracy/src/tests/fast_tracking.rs @@ -25,15 +25,15 @@ fn fast_track_referendum_works() { System::set_block_number(0); let h = set_balance_proposal_hash_and_note(2); assert_noop!( - Democracy::fast_track(Origin::signed(5), h, 3, 2), + Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2), Error::::ProposalMissing ); assert_ok!(Democracy::external_propose_majority( - Origin::signed(3), + RuntimeOrigin::signed(3), set_balance_proposal_hash_and_note(2) )); - assert_noop!(Democracy::fast_track(Origin::signed(1), h, 3, 2), BadOrigin); - assert_ok!(Democracy::fast_track(Origin::signed(5), h, 2, 0)); + assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin); + assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 2, 0)); assert_eq!( Democracy::referendum_status(0), Ok(ReferendumStatus { @@ -53,25 +53,25 @@ fn instant_referendum_works() { System::set_block_number(0); let h = set_balance_proposal_hash_and_note(2); assert_noop!( - Democracy::fast_track(Origin::signed(5), h, 3, 2), + Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2), Error::::ProposalMissing ); assert_ok!(Democracy::external_propose_majority( - Origin::signed(3), + RuntimeOrigin::signed(3), set_balance_proposal_hash_and_note(2) )); - assert_noop!(Democracy::fast_track(Origin::signed(1), h, 3, 2), BadOrigin); - assert_noop!(Democracy::fast_track(Origin::signed(5), h, 1, 0), BadOrigin); + assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin); + assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 1, 0), BadOrigin); assert_noop!( - Democracy::fast_track(Origin::signed(6), h, 1, 0), + Democracy::fast_track(RuntimeOrigin::signed(6), h, 1, 0), Error::::InstantNotAllowed ); INSTANT_ALLOWED.with(|v| *v.borrow_mut() = true); assert_noop!( - Democracy::fast_track(Origin::signed(6), h, 0, 0), + Democracy::fast_track(RuntimeOrigin::signed(6), h, 0, 0), Error::::VotingPeriodLow ); - assert_ok!(Democracy::fast_track(Origin::signed(6), h, 1, 0)); + assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(6), h, 1, 0)); assert_eq!( Democracy::referendum_status(0), Ok(ReferendumStatus { @@ -102,13 +102,13 @@ fn instant_next_block_referendum_backed() { // propose with majority origin assert_ok!(Democracy::external_propose_majority( - Origin::signed(majority_origin_id), + RuntimeOrigin::signed(majority_origin_id), proposal_hash )); // fast track with instant origin and voting period pointing to the next block assert_ok!(Democracy::fast_track( - Origin::signed(instant_origin_id), + RuntimeOrigin::signed(instant_origin_id), proposal_hash, voting_period, delay @@ -145,11 +145,11 @@ fn fast_track_referendum_fails_when_no_simple_majority() { System::set_block_number(0); let h = set_balance_proposal_hash_and_note(2); assert_ok!(Democracy::external_propose( - Origin::signed(2), + RuntimeOrigin::signed(2), set_balance_proposal_hash_and_note(2) )); assert_noop!( - Democracy::fast_track(Origin::signed(5), h, 3, 2), + Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2), Error::::NotSimpleMajority ); }); diff --git a/frame/democracy/src/tests/lock_voting.rs b/frame/democracy/src/tests/lock_voting.rs index 0718734367314..de1137f03fd38 100644 --- a/frame/democracy/src/tests/lock_voting.rs +++ b/frame/democracy/src/tests/lock_voting.rs @@ -47,11 +47,11 @@ fn lock_voting_should_work() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, nay(5, 10))); - assert_ok!(Democracy::vote(Origin::signed(2), r, aye(4, 20))); - assert_ok!(Democracy::vote(Origin::signed(3), r, aye(3, 30))); - assert_ok!(Democracy::vote(Origin::signed(4), r, aye(2, 40))); - assert_ok!(Democracy::vote(Origin::signed(5), r, nay(1, 50))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(5, 10))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(4, 20))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(3), r, aye(3, 30))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(4), r, aye(2, 40))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, nay(1, 50))); assert_eq!(tally(r), Tally { ayes: 250, nays: 100, turnout: 150 }); // All balances are currently locked. @@ -62,20 +62,20 @@ fn lock_voting_should_work() { fast_forward_to(2); // Referendum passed; 1 and 5 didn't get their way and can now reap and unlock. - assert_ok!(Democracy::remove_vote(Origin::signed(1), r)); - assert_ok!(Democracy::unlock(Origin::signed(1), 1)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(1), r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 1)); // Anyone can reap and unlock anyone else's in this context. - assert_ok!(Democracy::remove_other_vote(Origin::signed(2), 5, r)); - assert_ok!(Democracy::unlock(Origin::signed(2), 5)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(2), 5, r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(2), 5)); // 2, 3, 4 got their way with the vote, so they cannot be reaped by others. assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 2, r), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 2, r), Error::::NoPermission ); // However, they can be unvoted by the owner, though it will make no difference to the lock. - assert_ok!(Democracy::remove_vote(Origin::signed(2), r)); - assert_ok!(Democracy::unlock(Origin::signed(2), 2)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(2), r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(2), 2)); assert_eq!(Balances::locks(1), vec![]); assert_eq!(Balances::locks(2), vec![the_lock(20)]); @@ -87,35 +87,35 @@ fn lock_voting_should_work() { fast_forward_to(7); // No change yet... assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 4, r), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 4, r), Error::::NoPermission ); - assert_ok!(Democracy::unlock(Origin::signed(1), 4)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 4)); assert_eq!(Balances::locks(4), vec![the_lock(40)]); fast_forward_to(8); // 4 should now be able to reap and unlock - assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 4, r)); - assert_ok!(Democracy::unlock(Origin::signed(1), 4)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(1), 4, r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 4)); assert_eq!(Balances::locks(4), vec![]); fast_forward_to(13); assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 3, r), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 3, r), Error::::NoPermission ); - assert_ok!(Democracy::unlock(Origin::signed(1), 3)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 3)); assert_eq!(Balances::locks(3), vec![the_lock(30)]); fast_forward_to(14); - assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 3, r)); - assert_ok!(Democracy::unlock(Origin::signed(1), 3)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(1), 3, r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 3)); assert_eq!(Balances::locks(3), vec![]); // 2 doesn't need to reap_vote here because it was already done before. fast_forward_to(25); - assert_ok!(Democracy::unlock(Origin::signed(1), 2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 2)); assert_eq!(Balances::locks(2), vec![the_lock(20)]); fast_forward_to(26); - assert_ok!(Democracy::unlock(Origin::signed(1), 2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 2)); assert_eq!(Balances::locks(2), vec![]); }); } @@ -130,13 +130,13 @@ fn no_locks_without_conviction_should_work() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(0, 10))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(0, 10))); fast_forward_to(2); assert_eq!(Balances::free_balance(42), 2); - assert_ok!(Democracy::remove_other_vote(Origin::signed(2), 1, r)); - assert_ok!(Democracy::unlock(Origin::signed(2), 1)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(2), 1, r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(2), 1)); assert_eq!(Balances::locks(1), vec![]); }); } @@ -150,11 +150,11 @@ fn lock_voting_should_work_with_delegation() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, nay(5, 10))); - assert_ok!(Democracy::vote(Origin::signed(2), r, aye(4, 20))); - assert_ok!(Democracy::vote(Origin::signed(3), r, aye(3, 30))); - assert_ok!(Democracy::delegate(Origin::signed(4), 2, Conviction::Locked2x, 40)); - assert_ok!(Democracy::vote(Origin::signed(5), r, nay(1, 50))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(5, 10))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(4, 20))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(3), r, aye(3, 30))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(4), 2, Conviction::Locked2x, 40)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, nay(1, 50))); assert_eq!(tally(r), Tally { ayes: 250, nays: 100, turnout: 150 }); @@ -173,7 +173,7 @@ fn setup_three_referenda() -> (u32, u32, u32) { VoteThreshold::SimpleMajority, 0, ); - assert_ok!(Democracy::vote(Origin::signed(5), r1, aye(4, 10))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r1, aye(4, 10))); let r2 = Democracy::inject_referendum( 2, @@ -181,7 +181,7 @@ fn setup_three_referenda() -> (u32, u32, u32) { VoteThreshold::SimpleMajority, 0, ); - assert_ok!(Democracy::vote(Origin::signed(5), r2, aye(3, 20))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r2, aye(3, 20))); let r3 = Democracy::inject_referendum( 2, @@ -189,7 +189,7 @@ fn setup_three_referenda() -> (u32, u32, u32) { VoteThreshold::SimpleMajority, 0, ); - assert_ok!(Democracy::vote(Origin::signed(5), r3, aye(2, 50))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r3, aye(2, 50))); fast_forward_to(2); @@ -206,36 +206,36 @@ fn prior_lockvotes_should_be_enforced() { fast_forward_to(7); assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 5, r.2), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.2), Error::::NoPermission ); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(50)]); fast_forward_to(8); - assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 5, r.2)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); fast_forward_to(13); assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 5, r.1), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.1), Error::::NoPermission ); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); fast_forward_to(14); - assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 5, r.1)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.1)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); fast_forward_to(25); assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 5, r.0), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.0), Error::::NoPermission ); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); fast_forward_to(26); - assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 5, r.0)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.0)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } @@ -249,27 +249,27 @@ fn single_consolidation_of_lockvotes_should_work_as_before() { // r.2 locked 50 until 2 + 2 * 3 = #8 fast_forward_to(7); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.2)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(50)]); fast_forward_to(8); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); fast_forward_to(13); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.1)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.1)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); fast_forward_to(14); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); fast_forward_to(25); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.0)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.0)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); fast_forward_to(26); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } @@ -282,20 +282,20 @@ fn multi_consolidation_of_lockvotes_should_be_conservative() { // r.1 locked 20 until 2 + 4 * 3 = #14 // r.2 locked 50 until 2 + 2 * 3 = #8 - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.2)); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.1)); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.0)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.2)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.1)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.0)); fast_forward_to(8); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 20); fast_forward_to(14); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); fast_forward_to(26); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } @@ -310,32 +310,32 @@ fn locks_should_persist_from_voting_to_delegation() { VoteThreshold::SimpleMajority, 0, ); - assert_ok!(Democracy::vote(Origin::signed(5), r, aye(4, 10))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, aye(4, 10))); fast_forward_to(2); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r)); // locked 10 until #26. - assert_ok!(Democracy::delegate(Origin::signed(5), 1, Conviction::Locked3x, 20)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(5), 1, Conviction::Locked3x, 20)); // locked 20. assert!(Balances::locks(5)[0].amount == 20); - assert_ok!(Democracy::undelegate(Origin::signed(5))); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(5))); // locked 20 until #14 fast_forward_to(13); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount == 20); fast_forward_to(14); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); fast_forward_to(25); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); fast_forward_to(26); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } @@ -344,8 +344,8 @@ fn locks_should_persist_from_voting_to_delegation() { fn locks_should_persist_from_delegation_to_voting() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(Democracy::delegate(Origin::signed(5), 1, Conviction::Locked5x, 5)); - assert_ok!(Democracy::undelegate(Origin::signed(5))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(5), 1, Conviction::Locked5x, 5)); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(5))); // locked 5 until 16 * 3 = #48 let r = setup_three_referenda(); @@ -353,24 +353,24 @@ fn locks_should_persist_from_delegation_to_voting() { // r.1 locked 20 until 2 + 4 * 3 = #14 // r.2 locked 50 until 2 + 2 * 3 = #8 - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.2)); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.1)); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.0)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.2)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.1)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.0)); fast_forward_to(8); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 20); fast_forward_to(14); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); fast_forward_to(26); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 5); fast_forward_to(48); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } diff --git a/frame/democracy/src/tests/preimage.rs b/frame/democracy/src/tests/preimage.rs index 21303c8eddae3..39536eab8009b 100644 --- a/frame/democracy/src/tests/preimage.rs +++ b/frame/democracy/src/tests/preimage.rs @@ -28,7 +28,7 @@ fn missing_preimage_should_fail() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); next_block(); next_block(); @@ -44,9 +44,9 @@ fn preimage_deposit_should_be_required_and_returned() { PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 100); assert_noop!( if operational { - Democracy::note_preimage_operational(Origin::signed(6), vec![0; 500]) + Democracy::note_preimage_operational(RuntimeOrigin::signed(6), vec![0; 500]) } else { - Democracy::note_preimage(Origin::signed(6), vec![0; 500]) + Democracy::note_preimage(RuntimeOrigin::signed(6), vec![0; 500]) }, BalancesError::::InsufficientBalance, ); @@ -58,7 +58,7 @@ fn preimage_deposit_should_be_required_and_returned() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_eq!(Balances::reserved_balance(6), 12); @@ -76,21 +76,25 @@ fn preimage_deposit_should_be_reapable_earlier_by_owner() { new_test_ext_execute_with_cond(|operational| { PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); assert_ok!(if operational { - Democracy::note_preimage_operational(Origin::signed(6), set_balance_proposal(2)) + Democracy::note_preimage_operational(RuntimeOrigin::signed(6), set_balance_proposal(2)) } else { - Democracy::note_preimage(Origin::signed(6), set_balance_proposal(2)) + Democracy::note_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2)) }); assert_eq!(Balances::reserved_balance(6), 12); next_block(); assert_noop!( - Democracy::reap_preimage(Origin::signed(6), set_balance_proposal_hash(2), u32::MAX), + Democracy::reap_preimage( + RuntimeOrigin::signed(6), + set_balance_proposal_hash(2), + u32::MAX + ), Error::::TooEarly ); next_block(); assert_ok!(Democracy::reap_preimage( - Origin::signed(6), + RuntimeOrigin::signed(6), set_balance_proposal_hash(2), u32::MAX )); @@ -104,15 +108,19 @@ fn preimage_deposit_should_be_reapable_earlier_by_owner() { fn preimage_deposit_should_be_reapable() { new_test_ext_execute_with_cond(|operational| { assert_noop!( - Democracy::reap_preimage(Origin::signed(5), set_balance_proposal_hash(2), u32::MAX), + Democracy::reap_preimage( + RuntimeOrigin::signed(5), + set_balance_proposal_hash(2), + u32::MAX + ), Error::::PreimageMissing ); PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); assert_ok!(if operational { - Democracy::note_preimage_operational(Origin::signed(6), set_balance_proposal(2)) + Democracy::note_preimage_operational(RuntimeOrigin::signed(6), set_balance_proposal(2)) } else { - Democracy::note_preimage(Origin::signed(6), set_balance_proposal(2)) + Democracy::note_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2)) }); assert_eq!(Balances::reserved_balance(6), 12); @@ -120,13 +128,17 @@ fn preimage_deposit_should_be_reapable() { next_block(); next_block(); assert_noop!( - Democracy::reap_preimage(Origin::signed(5), set_balance_proposal_hash(2), u32::MAX), + Democracy::reap_preimage( + RuntimeOrigin::signed(5), + set_balance_proposal_hash(2), + u32::MAX + ), Error::::TooEarly ); next_block(); assert_ok!(Democracy::reap_preimage( - Origin::signed(5), + RuntimeOrigin::signed(5), set_balance_proposal_hash(2), u32::MAX )); @@ -147,16 +159,16 @@ fn noting_imminent_preimage_for_free_should_work() { VoteThreshold::SuperMajorityApprove, 1, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_noop!( if operational { Democracy::note_imminent_preimage_operational( - Origin::signed(6), + RuntimeOrigin::signed(6), set_balance_proposal(2), ) } else { - Democracy::note_imminent_preimage(Origin::signed(6), set_balance_proposal(2)) + Democracy::note_imminent_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2)) }, Error::::NotImminent ); @@ -164,7 +176,10 @@ fn noting_imminent_preimage_for_free_should_work() { next_block(); // Now we're in the dispatch queue it's all good. - assert_ok!(Democracy::note_imminent_preimage(Origin::signed(6), set_balance_proposal(2))); + assert_ok!(Democracy::note_imminent_preimage( + RuntimeOrigin::signed(6), + set_balance_proposal(2) + )); next_block(); @@ -177,11 +192,11 @@ fn reaping_imminent_preimage_should_fail() { new_test_ext().execute_with(|| { let h = set_balance_proposal_hash_and_note(2); let r = Democracy::inject_referendum(3, h, VoteThreshold::SuperMajorityApprove, 1); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); next_block(); next_block(); assert_noop!( - Democracy::reap_preimage(Origin::signed(6), h, u32::MAX), + Democracy::reap_preimage(RuntimeOrigin::signed(6), h, u32::MAX), Error::::Imminent ); }); @@ -198,21 +213,24 @@ fn note_imminent_preimage_can_only_be_successful_once() { VoteThreshold::SuperMajorityApprove, 1, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); next_block(); // First time works - assert_ok!(Democracy::note_imminent_preimage(Origin::signed(6), set_balance_proposal(2))); + assert_ok!(Democracy::note_imminent_preimage( + RuntimeOrigin::signed(6), + set_balance_proposal(2) + )); // Second time fails assert_noop!( - Democracy::note_imminent_preimage(Origin::signed(6), set_balance_proposal(2)), + Democracy::note_imminent_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2)), Error::::DuplicatePreimage ); // Fails from any user assert_noop!( - Democracy::note_imminent_preimage(Origin::signed(5), set_balance_proposal(2)), + Democracy::note_imminent_preimage(RuntimeOrigin::signed(5), set_balance_proposal(2)), Error::::DuplicatePreimage ); }); diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs index 65e5466857dc1..c52533e46ccc5 100644 --- a/frame/democracy/src/tests/public_proposals.rs +++ b/frame/democracy/src/tests/public_proposals.rs @@ -35,10 +35,10 @@ fn backing_for_should_work() { fn deposit_for_proposals_should_be_taken() { new_test_ext().execute_with(|| { assert_ok!(propose_set_balance_and_note(1, 2, 5)); - assert_ok!(Democracy::second(Origin::signed(2), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0, u32::MAX)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); assert_eq!(Balances::free_balance(1), 5); assert_eq!(Balances::free_balance(2), 15); assert_eq!(Balances::free_balance(5), 35); @@ -49,10 +49,10 @@ fn deposit_for_proposals_should_be_taken() { fn deposit_for_proposals_should_be_returned() { new_test_ext().execute_with(|| { assert_ok!(propose_set_balance_and_note(1, 2, 5)); - assert_ok!(Democracy::second(Origin::signed(2), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0, u32::MAX)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); fast_forward_to(3); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 20); @@ -79,7 +79,7 @@ fn poor_seconder_should_not_work() { new_test_ext().execute_with(|| { assert_ok!(propose_set_balance_and_note(2, 2, 11)); assert_noop!( - Democracy::second(Origin::signed(1), 0, u32::MAX), + Democracy::second(RuntimeOrigin::signed(1), 0, u32::MAX), BalancesError::::InsufficientBalance ); }); @@ -89,7 +89,10 @@ fn poor_seconder_should_not_work() { fn invalid_seconds_upper_bound_should_not_work() { new_test_ext().execute_with(|| { assert_ok!(propose_set_balance_and_note(1, 2, 5)); - assert_noop!(Democracy::second(Origin::signed(2), 0, 0), Error::::WrongUpperBound); + assert_noop!( + Democracy::second(RuntimeOrigin::signed(2), 0, 0), + Error::::WrongUpperBound + ); }); } @@ -98,8 +101,8 @@ fn cancel_proposal_should_work() { new_test_ext().execute_with(|| { assert_ok!(propose_set_balance_and_note(1, 2, 2)); assert_ok!(propose_set_balance_and_note(1, 4, 4)); - assert_noop!(Democracy::cancel_proposal(Origin::signed(1), 0), BadOrigin); - assert_ok!(Democracy::cancel_proposal(Origin::root(), 0)); + assert_noop!(Democracy::cancel_proposal(RuntimeOrigin::signed(1), 0), BadOrigin); + assert_ok!(Democracy::cancel_proposal(RuntimeOrigin::root(), 0)); System::assert_last_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); assert_eq!(Democracy::backing_for(0), None); assert_eq!(Democracy::backing_for(1), Some(4)); @@ -115,8 +118,8 @@ fn blacklisting_should_work() { assert_ok!(propose_set_balance_and_note(1, 2, 2)); assert_ok!(propose_set_balance_and_note(1, 4, 4)); - assert_noop!(Democracy::blacklist(Origin::signed(1), hash, None), BadOrigin); - assert_ok!(Democracy::blacklist(Origin::root(), hash, None)); + assert_noop!(Democracy::blacklist(RuntimeOrigin::signed(1), hash, None), BadOrigin); + assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None)); assert_eq!(Democracy::backing_for(0), None); assert_eq!(Democracy::backing_for(1), Some(4)); @@ -127,7 +130,7 @@ fn blacklisting_should_work() { let hash = set_balance_proposal_hash(4); assert_ok!(Democracy::referendum_status(0)); - assert_ok!(Democracy::blacklist(Origin::root(), hash, Some(0))); + assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, Some(0))); assert_noop!(Democracy::referendum_status(0), Error::::ReferendumInvalid); }); } @@ -140,10 +143,10 @@ fn runners_up_should_come_after() { assert_ok!(propose_set_balance_and_note(1, 4, 4)); assert_ok!(propose_set_balance_and_note(1, 3, 3)); fast_forward_to(2); - assert_ok!(Democracy::vote(Origin::signed(1), 0, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1))); fast_forward_to(4); - assert_ok!(Democracy::vote(Origin::signed(1), 1, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 1, aye(1))); fast_forward_to(6); - assert_ok!(Democracy::vote(Origin::signed(1), 2, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 2, aye(1))); }); } diff --git a/frame/democracy/src/tests/scheduling.rs b/frame/democracy/src/tests/scheduling.rs index d28f24d76bb5b..4b5fe8dd9c1c3 100644 --- a/frame/democracy/src/tests/scheduling.rs +++ b/frame/democracy/src/tests/scheduling.rs @@ -28,7 +28,7 @@ fn simple_passing_should_work() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_eq!(tally(r), Tally { ayes: 1, nays: 0, turnout: 10 }); assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); @@ -47,7 +47,7 @@ fn simple_failing_should_work() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, nay(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(1))); assert_eq!(tally(r), Tally { ayes: 0, nays: 1, turnout: 10 }); next_block(); @@ -73,13 +73,13 @@ fn ooo_inject_referendums_should_work() { 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r2, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r2, aye(1))); assert_eq!(tally(r2), Tally { ayes: 1, nays: 0, turnout: 10 }); next_block(); assert_eq!(Balances::free_balance(42), 2); - assert_ok!(Democracy::vote(Origin::signed(1), r1, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r1, aye(1))); assert_eq!(tally(r1), Tally { ayes: 1, nays: 0, turnout: 10 }); next_block(); @@ -96,12 +96,12 @@ fn delayed_enactment_should_work() { VoteThreshold::SuperMajorityApprove, 1, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - assert_ok!(Democracy::vote(Origin::signed(2), r, aye(2))); - assert_ok!(Democracy::vote(Origin::signed(3), r, aye(3))); - assert_ok!(Democracy::vote(Origin::signed(4), r, aye(4))); - assert_ok!(Democracy::vote(Origin::signed(5), r, aye(5))); - assert_ok!(Democracy::vote(Origin::signed(6), r, aye(6))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(2))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(3), r, aye(3))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(4), r, aye(4))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, aye(5))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, aye(6))); assert_eq!(tally(r), Tally { ayes: 21, nays: 0, turnout: 210 }); @@ -134,10 +134,10 @@ fn lowest_unbaked_should_be_sensible() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r1, aye(1))); - assert_ok!(Democracy::vote(Origin::signed(1), r2, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r1, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r2, aye(1))); // r3 is canceled - assert_ok!(Democracy::cancel_referendum(Origin::root(), r3.into())); + assert_ok!(Democracy::cancel_referendum(RuntimeOrigin::root(), r3.into())); assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); diff --git a/frame/democracy/src/tests/voting.rs b/frame/democracy/src/tests/voting.rs index d4fceaf0ee489..59d0cd6bc50ef 100644 --- a/frame/democracy/src/tests/voting.rs +++ b/frame/democracy/src/tests/voting.rs @@ -24,7 +24,7 @@ fn overvoting_should_fail() { new_test_ext().execute_with(|| { let r = begin_referendum(); assert_noop!( - Democracy::vote(Origin::signed(1), r, aye(2)), + Democracy::vote(RuntimeOrigin::signed(1), r, aye(2)), Error::::InsufficientFunds ); }); @@ -35,9 +35,12 @@ fn split_voting_should_work() { new_test_ext().execute_with(|| { let r = begin_referendum(); let v = AccountVote::Split { aye: 40, nay: 20 }; - assert_noop!(Democracy::vote(Origin::signed(5), r, v), Error::::InsufficientFunds); + assert_noop!( + Democracy::vote(RuntimeOrigin::signed(5), r, v), + Error::::InsufficientFunds + ); let v = AccountVote::Split { aye: 30, nay: 20 }; - assert_ok!(Democracy::vote(Origin::signed(5), r, v)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, v)); assert_eq!(tally(r), Tally { ayes: 3, nays: 2, turnout: 50 }); }); @@ -48,10 +51,10 @@ fn split_vote_cancellation_should_work() { new_test_ext().execute_with(|| { let r = begin_referendum(); let v = AccountVote::Split { aye: 30, nay: 20 }; - assert_ok!(Democracy::vote(Origin::signed(5), r, v)); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, v)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r)); assert_eq!(tally(r), Tally { ayes: 0, nays: 0, turnout: 0 }); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } @@ -66,7 +69,7 @@ fn single_proposal_should_work() { // start of 2 => next referendum scheduled. fast_forward_to(2); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_eq!(Democracy::referendum_count(), 1); assert_eq!( @@ -108,12 +111,12 @@ fn controversial_voting_should_work() { 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, big_aye(1))); - assert_ok!(Democracy::vote(Origin::signed(2), r, big_nay(2))); - assert_ok!(Democracy::vote(Origin::signed(3), r, big_nay(3))); - assert_ok!(Democracy::vote(Origin::signed(4), r, big_aye(4))); - assert_ok!(Democracy::vote(Origin::signed(5), r, big_nay(5))); - assert_ok!(Democracy::vote(Origin::signed(6), r, big_aye(6))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, big_aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, big_nay(2))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(3), r, big_nay(3))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(4), r, big_aye(4))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, big_nay(5))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, big_aye(6))); assert_eq!(tally(r), Tally { ayes: 110, nays: 100, turnout: 210 }); @@ -133,8 +136,8 @@ fn controversial_low_turnout_voting_should_work() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(5), r, big_nay(5))); - assert_ok!(Democracy::vote(Origin::signed(6), r, big_aye(6))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, big_nay(5))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, big_aye(6))); assert_eq!(tally(r), Tally { ayes: 60, nays: 50, turnout: 110 }); @@ -157,9 +160,9 @@ fn passing_low_turnout_voting_should_work() { VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(4), r, big_aye(4))); - assert_ok!(Democracy::vote(Origin::signed(5), r, big_nay(5))); - assert_ok!(Democracy::vote(Origin::signed(6), r, big_aye(6))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(4), r, big_aye(4))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, big_nay(5))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, big_aye(6))); assert_eq!(tally(r), Tally { ayes: 100, nays: 50, turnout: 150 }); next_block(); diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 1188e3353bc96..3c9b15dabb053 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -700,7 +700,7 @@ pub mod pallet { /// Origin that can control this pallet. Note that any action taken by this origin (such) /// as providing an emergency solution is not checked. Thus, it must be a trusted origin. - type ForceOrigin: EnsureOrigin; + type ForceOrigin: EnsureOrigin; /// The configuration of benchmarking. type BenchmarkingConfig: BenchmarkingConfig; @@ -1828,7 +1828,7 @@ mod tests { use crate::{ mock::{ multi_phase_events, raw_solution, roll_to, AccountId, ExtBuilder, MockWeightInfo, - MockedWeightInfo, MultiPhase, Origin, Runtime, SignedMaxSubmissions, System, + MockedWeightInfo, MultiPhase, Runtime, RuntimeOrigin, SignedMaxSubmissions, System, TargetIndex, Targets, }, Phase, @@ -2030,7 +2030,10 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(crate::mock::Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit( + crate::mock::RuntimeOrigin::signed(99), + Box::new(solution) + )); } // an unexpected call to elect. @@ -2057,7 +2060,10 @@ mod tests { assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); - assert_ok!(MultiPhase::submit(crate::mock::Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit( + crate::mock::RuntimeOrigin::signed(99), + Box::new(solution) + )); roll_to(30); assert_ok!(MultiPhase::elect()); @@ -2098,7 +2104,7 @@ mod tests { // ensure this solution is valid. assert!(MultiPhase::queued_solution().is_none()); assert_ok!(MultiPhase::submit_unsigned( - crate::mock::Origin::none(), + crate::mock::RuntimeOrigin::none(), Box::new(solution), witness )); @@ -2176,12 +2182,12 @@ mod tests { // no single account can trigger this assert_noop!( - MultiPhase::governance_fallback(Origin::signed(99), None, None), + MultiPhase::governance_fallback(RuntimeOrigin::signed(99), None, None), DispatchError::BadOrigin ); // only root can - assert_ok!(MultiPhase::governance_fallback(Origin::root(), None, None)); + assert_ok!(MultiPhase::governance_fallback(RuntimeOrigin::root(), None, None)); // something is queued now assert!(MultiPhase::queued_solution().is_some()); // next election call with fix everything.; diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index efe9d8ea587cb..d7affc14564f5 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -199,7 +199,7 @@ pub fn witness() -> SolutionOrSnapshotSize { impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index b9abfdfba14fb..1cf071e6796f1 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -529,7 +529,7 @@ mod tests { use crate::{ mock::{ balances, raw_solution, roll_to, Balances, ExtBuilder, MockedWeightInfo, MultiPhase, - Origin, Runtime, SignedMaxRefunds, SignedMaxSubmissions, SignedMaxWeight, + Runtime, RuntimeOrigin, SignedMaxRefunds, SignedMaxSubmissions, SignedMaxWeight, }, Error, Perbill, Phase, }; @@ -546,7 +546,7 @@ mod tests { let solution = raw_solution(); assert_noop!( - MultiPhase::submit(Origin::signed(10), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(10), Box::new(solution)), Error::::PreDispatchEarlySubmission, ); }) @@ -561,7 +561,7 @@ mod tests { let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); assert_eq!(MultiPhase::signed_submissions().iter().next().unwrap().deposit, 5); @@ -577,7 +577,7 @@ mod tests { let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); assert!(MultiPhase::finalize_signed_phase()); @@ -597,7 +597,7 @@ mod tests { // make the solution invalid. solution.score.minimal_stake += 1; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); // no good solution was stored. @@ -618,11 +618,11 @@ mod tests { assert_eq!(balances(&999), (100, 0)); // submit as correct. - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution.clone()))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution.clone()))); // make the solution invalid and weaker. solution.score.minimal_stake -= 1; - assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(999), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); assert_eq!(balances(&999), (95, 5)); @@ -648,7 +648,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } // weaker. @@ -658,7 +658,7 @@ mod tests { }; assert_noop!( - MultiPhase::submit(Origin::signed(99), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution)), Error::::SignedQueueFull, ); }) @@ -679,7 +679,7 @@ mod tests { let mut solution = raw_solution(); solution.score.minimal_stake -= s as u128; - assert_ok!(MultiPhase::submit(Origin::signed(account), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(account), Box::new(solution))); assert_eq!(balances(&account), (95, 5)); } @@ -719,7 +719,7 @@ mod tests { }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); // This is 10% better, so does not meet the 20% threshold and is therefore rejected. solution = RawSolution { @@ -732,7 +732,7 @@ mod tests { }; assert_noop!( - MultiPhase::submit(Origin::signed(99), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution)), Error::::SignedQueueFull, ); @@ -746,7 +746,7 @@ mod tests { ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); }) } @@ -764,7 +764,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(account), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(account), Box::new(solution))); assert_eq!(balances(&account), (95, 5)); } @@ -781,7 +781,7 @@ mod tests { score: ElectionScore { minimal_stake: 20, ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(999), Box::new(solution))); // the one with score 5 was rejected, the new one inserted. assert_eq!( @@ -809,14 +809,14 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } let solution = RawSolution { score: ElectionScore { minimal_stake: 4, ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); assert_eq!( MultiPhase::signed_submissions() @@ -831,7 +831,7 @@ mod tests { score: ElectionScore { minimal_stake: 5, ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); // the one with score 5 was rejected, the new one inserted. assert_eq!( @@ -856,7 +856,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } assert_eq!(balances(&99).1, 2 * 5); @@ -867,7 +867,7 @@ mod tests { score: ElectionScore { minimal_stake: 20, ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(999), Box::new(solution))); // got one bond back. assert_eq!(balances(&99).1, 2 * 4); @@ -886,7 +886,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + i).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } assert_eq!( MultiPhase::signed_submissions() @@ -902,7 +902,7 @@ mod tests { ..Default::default() }; assert_noop!( - MultiPhase::submit(Origin::signed(99), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution)), Error::::SignedQueueFull, ); }) @@ -924,18 +924,18 @@ mod tests { let solution = raw_solution(); // submit a correct one. - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution.clone()))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution.clone()))); // make the solution invalidly better and submit. This ought to be slashed. let mut solution_999 = solution.clone(); solution_999.score.minimal_stake += 1; - assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution_999))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(999), Box::new(solution_999))); // make the solution invalidly worse and submit. This ought to be suppressed and // returned. let mut solution_9999 = solution.clone(); solution_9999.score.minimal_stake -= 1; - assert_ok!(MultiPhase::submit(Origin::signed(9999), Box::new(solution_9999))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(9999), Box::new(solution_9999))); assert_eq!( MultiPhase::signed_submissions().iter().map(|x| x.who).collect::>(), @@ -975,14 +975,14 @@ mod tests { assert_eq!(raw.solution.voter_count(), 5); assert_eq!(::SignedMaxWeight::get(), Weight::from_ref_time(40)); - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(raw.clone()))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(raw.clone()))); ::set(Weight::from_ref_time(30)); // note: resubmitting the same solution is technically okay as long as the queue has // space. assert_noop!( - MultiPhase::submit(Origin::signed(99), Box::new(raw)), + MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(raw)), Error::::SignedTooMuchWeight, ); }) @@ -998,7 +998,7 @@ mod tests { assert_eq!(balances(&123), (0, 0)); assert_noop!( - MultiPhase::submit(Origin::signed(123), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(123), Box::new(solution)), Error::::SignedCannotPayDeposit, ); @@ -1020,7 +1020,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } // this solution has a higher score than any in the queue @@ -1034,7 +1034,7 @@ mod tests { assert_eq!(balances(&123), (0, 0)); assert_noop!( - MultiPhase::submit(Origin::signed(123), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(123), Box::new(solution)), Error::::SignedCannotPayDeposit, ); @@ -1063,7 +1063,7 @@ mod tests { let solution = raw_solution(); // submit a correct one. - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); // _some_ good solution was stored. assert!(MultiPhase::finalize_signed_phase()); diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 7dadd320abdf8..cf8df237bafb0 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -856,7 +856,7 @@ mod tests { use crate::{ mock::{ roll_to, roll_to_with_ocw, trim_helpers, witness, BlockNumber, ExtBuilder, Extrinsic, - MinerMaxWeight, MultiPhase, Origin, Runtime, RuntimeCall as OuterCall, System, + MinerMaxWeight, MultiPhase, Runtime, RuntimeCall as OuterCall, RuntimeOrigin, System, TestNposSolution, TrimHelpers, UnsignedPhase, }, CurrentPhase, InvalidTransaction, Phase, QueuedSolution, TransactionSource, @@ -1071,7 +1071,7 @@ mod tests { witness: witness(), }; let outer_call: OuterCall = call.into(); - let _ = outer_call.dispatch(Origin::none()); + let _ = outer_call.dispatch(RuntimeOrigin::none()); }) } @@ -1097,7 +1097,7 @@ mod tests { witness: correct_witness, }; let outer_call: OuterCall = call.into(); - let _ = outer_call.dispatch(Origin::none()); + let _ = outer_call.dispatch(RuntimeOrigin::none()); }) } @@ -1116,7 +1116,11 @@ mod tests { // ensure this solution is valid. assert!(MultiPhase::queued_solution().is_none()); - assert_ok!(MultiPhase::submit_unsigned(Origin::none(), Box::new(solution), witness)); + assert_ok!(MultiPhase::submit_unsigned( + RuntimeOrigin::none(), + Box::new(solution), + witness + )); assert!(MultiPhase::queued_solution().is_some()); }) } @@ -1215,7 +1219,7 @@ mod tests { let solution = RawSolution { solution: raw, score, round: MultiPhase::round() }; assert_ok!(MultiPhase::unsigned_pre_dispatch_checks(&solution)); assert_ok!(MultiPhase::submit_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(solution), witness )); @@ -1276,7 +1280,7 @@ mod tests { // and it is fine assert_ok!(MultiPhase::unsigned_pre_dispatch_checks(&solution)); assert_ok!(MultiPhase::submit_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(solution), witness )); diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 05bbd11e1ae9d..e477499f3c927 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -211,7 +211,7 @@ mod tests { impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountId; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 18210513f8ab6..0616087d975e8 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1182,7 +1182,7 @@ mod tests { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -1486,11 +1486,11 @@ mod tests { ensure_members_has_approval_stake(); } - fn submit_candidacy(origin: Origin) -> sp_runtime::DispatchResult { + fn submit_candidacy(origin: RuntimeOrigin) -> sp_runtime::DispatchResult { Elections::submit_candidacy(origin, Elections::candidates().len() as u32) } - fn vote(origin: Origin, votes: Vec, stake: u64) -> DispatchResultWithPostInfo { + fn vote(origin: RuntimeOrigin, votes: Vec, stake: u64) -> DispatchResultWithPostInfo { // historical note: helper function was created in a period of time in which the API of vote // call was changing. Currently it is a wrapper for the original call and does not do much. // Nonetheless, totally harmless. @@ -1572,8 +1572,8 @@ mod tests { Voter { stake: 20u64, votes: vec![2], deposit: 0 } ); - assert_ok!(Elections::remove_voter(Origin::signed(1))); - assert_ok!(Elections::remove_voter(Origin::signed(2))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(1))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(2))); assert_eq!(Elections::voting(1), Default::default()); assert_eq!(Elections::voting(2), Default::default()); @@ -1666,7 +1666,7 @@ mod tests { assert!(Elections::is_candidate(&2).is_err()); assert_eq!(balances(&1), (10, 0)); - assert_ok!(submit_candidacy(Origin::signed(1))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(1))); assert_eq!(balances(&1), (7, 3)); assert_eq!(candidate_ids(), vec![1]); @@ -1675,7 +1675,7 @@ mod tests { assert!(Elections::is_candidate(&2).is_err()); assert_eq!(balances(&2), (20, 0)); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); assert_eq!(balances(&2), (17, 3)); assert_eq!(candidate_ids(), vec![1, 2]); @@ -1692,15 +1692,15 @@ mod tests { #[test] fn updating_candidacy_bond_works() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); assert_eq!(Elections::candidates(), vec![(5, 3)]); // a runtime upgrade changes the bond. CANDIDACY_BOND.with(|v| *v.borrow_mut() = 4); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); assert_eq!(Elections::candidates(), vec![(4, 4), (5, 3)]); // once elected, they each hold their candidacy bond, no more. @@ -1724,13 +1724,13 @@ mod tests { ExtBuilder::default().build_and_execute(|| { assert_eq!(candidate_ids(), Vec::::new()); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); assert_eq!(candidate_ids(), vec![3]); - assert_ok!(submit_candidacy(Origin::signed(1))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(1))); assert_eq!(candidate_ids(), vec![1, 3]); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); assert_eq!(candidate_ids(), vec![1, 2, 3]); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); assert_eq!(candidate_ids(), vec![1, 2, 3, 4]); }); } @@ -1739,9 +1739,12 @@ mod tests { fn dupe_candidate_submission_should_not_work() { ExtBuilder::default().build_and_execute(|| { assert_eq!(candidate_ids(), Vec::::new()); - assert_ok!(submit_candidacy(Origin::signed(1))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(1))); assert_eq!(candidate_ids(), vec![1]); - assert_noop!(submit_candidacy(Origin::signed(1)), Error::::DuplicatedCandidate); + assert_noop!( + submit_candidacy(RuntimeOrigin::signed(1)), + Error::::DuplicatedCandidate + ); }); } @@ -1749,8 +1752,8 @@ mod tests { fn member_candidacy_submission_should_not_work() { // critically important to make sure that outgoing candidates and losers are not mixed up. ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -1759,19 +1762,19 @@ mod tests { assert!(Elections::runners_up().is_empty()); assert!(candidate_ids().is_empty()); - assert_noop!(submit_candidacy(Origin::signed(5)), Error::::MemberSubmit); + assert_noop!(submit_candidacy(RuntimeOrigin::signed(5)), Error::::MemberSubmit); }); } #[test] fn runner_candidate_submission_should_not_work() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(2), vec![5, 4], 20)); - assert_ok!(vote(Origin::signed(1), vec![3], 10)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5, 4], 20)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![3], 10)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -1779,7 +1782,7 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert_eq!(runners_up_ids(), vec![3]); - assert_noop!(submit_candidacy(Origin::signed(3)), Error::::RunnerUpSubmit); + assert_noop!(submit_candidacy(RuntimeOrigin::signed(3)), Error::::RunnerUpSubmit); }); } @@ -1788,7 +1791,7 @@ mod tests { ExtBuilder::default().build_and_execute(|| { assert_eq!(candidate_ids(), Vec::::new()); assert_noop!( - submit_candidacy(Origin::signed(7)), + submit_candidacy(RuntimeOrigin::signed(7)), Error::::InsufficientCandidateFunds, ); }); @@ -1800,8 +1803,8 @@ mod tests { assert_eq!(candidate_ids(), Vec::::new()); assert_eq!(balances(&2), (20, 0)); - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); assert_eq!(balances(&2), (18, 2)); assert_eq!(has_lock(&2), 18); @@ -1814,8 +1817,8 @@ mod tests { assert_eq!(candidate_ids(), Vec::::new()); assert_eq!(balances(&2), (20, 0)); - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(2), vec![5], 12)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 12)); assert_eq!(balances(&2), (18, 2)); assert_eq!(has_lock(&2), 12); @@ -1827,9 +1830,9 @@ mod tests { ExtBuilder::default().build_and_execute(|| { assert_eq!(balances(&2), (20, 0)); - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); // User only locks up to their free balance. assert_eq!(balances(&2), (18, 2)); @@ -1837,7 +1840,7 @@ mod tests { assert_eq!(locked_stake_of(&2), 18); // can update; different stake; different lock and reserve. - assert_ok!(vote(Origin::signed(2), vec![5, 4], 15)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5, 4], 15)); assert_eq!(balances(&2), (18, 2)); assert_eq!(has_lock(&2), 15); assert_eq!(locked_stake_of(&2), 15); @@ -1847,10 +1850,10 @@ mod tests { #[test] fn updated_voting_bond_works() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); assert_eq!(balances(&2), (20, 0)); - assert_ok!(vote(Origin::signed(2), vec![5], 5)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 5)); assert_eq!(balances(&2), (18, 2)); assert_eq!(voter_deposit(&2), 2); @@ -1860,11 +1863,11 @@ mod tests { // proof that bond changed. assert_eq!(balances(&1), (10, 0)); - assert_ok!(vote(Origin::signed(1), vec![5], 5)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![5], 5)); assert_eq!(balances(&1), (9, 1)); assert_eq!(voter_deposit(&1), 1); - assert_ok!(Elections::remove_voter(Origin::signed(2))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(2))); assert_eq!(balances(&2), (20, 0)); }) } @@ -1874,11 +1877,11 @@ mod tests { ExtBuilder::default().voter_bond_factor(1).build_and_execute(|| { assert_eq!(balances(&2), (20, 0)); - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); // initial vote. - assert_ok!(vote(Origin::signed(2), vec![5], 10)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 10)); // 2 + 1 assert_eq!(balances(&2), (17, 3)); @@ -1887,7 +1890,7 @@ mod tests { assert_eq!(locked_stake_of(&2), 10); // can update; different stake; different lock and reserve. - assert_ok!(vote(Origin::signed(2), vec![5, 4], 15)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5, 4], 15)); // 2 + 2 assert_eq!(balances(&2), (16, 4)); assert_eq!(Elections::voting(&2).deposit, 4); @@ -1895,7 +1898,7 @@ mod tests { assert_eq!(locked_stake_of(&2), 15); // stay at two votes with different stake. - assert_ok!(vote(Origin::signed(2), vec![5, 3], 18)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5, 3], 18)); // 2 + 2 assert_eq!(balances(&2), (16, 4)); assert_eq!(Elections::voting(&2).deposit, 4); @@ -1903,7 +1906,7 @@ mod tests { assert_eq!(locked_stake_of(&2), 16); // back to 1 vote. - assert_ok!(vote(Origin::signed(2), vec![4], 12)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4], 12)); // 2 + 1 assert_eq!(balances(&2), (17, 3)); assert_eq!(Elections::voting(&2).deposit, 3); @@ -1915,17 +1918,17 @@ mod tests { #[test] fn cannot_vote_for_no_candidate() { ExtBuilder::default().build_and_execute(|| { - assert_noop!(vote(Origin::signed(2), vec![], 20), Error::::NoVotes); + assert_noop!(vote(RuntimeOrigin::signed(2), vec![], 20), Error::::NoVotes); }); } #[test] fn can_vote_for_old_members_even_when_no_new_candidates() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_ok!(vote(Origin::signed(2), vec![4, 5], 20)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4, 5], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -1933,22 +1936,22 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert!(candidate_ids().is_empty()); - assert_ok!(vote(Origin::signed(3), vec![4, 5], 10)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![4, 5], 10)); }); } #[test] fn prime_works() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(1), vec![4, 3], 10)); - assert_ok!(vote(Origin::signed(2), vec![4], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![4, 3], 10)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -1956,7 +1959,7 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert!(candidate_ids().is_empty()); - assert_ok!(vote(Origin::signed(3), vec![4, 5], 10)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![4, 5], 10)); assert_eq!(PRIME.with(|p| *p.borrow()), Some(4)); }); } @@ -1964,17 +1967,20 @@ mod tests { #[test] fn prime_votes_for_exiting_members_are_removed() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(1), vec![4, 3], 10)); - assert_ok!(vote(Origin::signed(2), vec![4], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![4, 3], 10)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Candidate(3))); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(4), + Renouncing::Candidate(3) + )); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -1989,18 +1995,18 @@ mod tests { #[test] fn prime_is_kept_if_other_members_leave() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![4, 5]); assert_eq!(PRIME.with(|p| *p.borrow()), Some(5)); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Member)); + assert_ok!(Elections::renounce_candidacy(RuntimeOrigin::signed(4), Renouncing::Member)); assert_eq!(members_ids(), vec![5]); assert_eq!(PRIME.with(|p| *p.borrow()), Some(5)); @@ -2010,18 +2016,18 @@ mod tests { #[test] fn prime_is_gone_if_renouncing() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![4, 5]); assert_eq!(PRIME.with(|p| *p.borrow()), Some(5)); - assert_ok!(Elections::renounce_candidacy(Origin::signed(5), Renouncing::Member)); + assert_ok!(Elections::renounce_candidacy(RuntimeOrigin::signed(5), Renouncing::Member)); assert_eq!(members_ids(), vec![4]); assert_eq!(PRIME.with(|p| *p.borrow()), None); @@ -2035,29 +2041,29 @@ mod tests { .balance_factor(10) .build_and_execute(|| { // when we have only candidates - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); assert_noop!( // content of the vote is irrelevant. - vote(Origin::signed(1), vec![9, 99, 999, 9999], 5), + vote(RuntimeOrigin::signed(1), vec![9, 99, 999, 9999], 5), Error::::TooManyVotes, ); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); // now we have 2 members, 1 runner-up, and 1 new candidate - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(1), vec![9, 99, 999, 9999], 5)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![9, 99, 999, 9999], 5)); assert_noop!( - vote(Origin::signed(1), vec![9, 99, 999, 9_999, 99_999], 5), + vote(RuntimeOrigin::signed(1), vec![9, 99, 999, 9_999, 99_999], 5), Error::::TooManyVotes, ); }); @@ -2066,23 +2072,23 @@ mod tests { #[test] fn cannot_vote_for_less_than_ed() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_noop!(vote(Origin::signed(2), vec![4], 1), Error::::LowBalance); + assert_noop!(vote(RuntimeOrigin::signed(2), vec![4], 1), Error::::LowBalance); }) } #[test] fn can_vote_for_more_than_free_balance_but_moot() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); // User has 100 free and 50 reserved. - assert_ok!(Balances::set_balance(Origin::root(), 2, 100, 50)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 100, 50)); // User tries to vote with 150 tokens. - assert_ok!(vote(Origin::signed(2), vec![4, 5], 150)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4, 5], 150)); // We truncate to only their free balance, after reserving additional for voting. assert_eq!(locked_stake_of(&2), 98); assert_eq!(has_lock(&2), 98); @@ -2092,10 +2098,10 @@ mod tests { #[test] fn remove_voter_should_work() { ExtBuilder::default().voter_bond(8).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); - assert_ok!(vote(Origin::signed(3), vec![5], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![5], 30)); assert_eq_uvec!(all_voters(), vec![2, 3]); assert_eq!(balances(&2), (12, 8)); @@ -2105,7 +2111,7 @@ mod tests { assert_eq!(votes_of(&2), vec![5]); assert_eq!(votes_of(&3), vec![5]); - assert_ok!(Elections::remove_voter(Origin::signed(2))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(2))); assert_eq_uvec!(all_voters(), vec![3]); assert!(votes_of(&2).is_empty()); @@ -2119,35 +2125,41 @@ mod tests { #[test] fn non_voter_remove_should_not_work() { ExtBuilder::default().build_and_execute(|| { - assert_noop!(Elections::remove_voter(Origin::signed(3)), Error::::MustBeVoter); + assert_noop!( + Elections::remove_voter(RuntimeOrigin::signed(3)), + Error::::MustBeVoter + ); }); } #[test] fn dupe_remove_should_fail() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); - assert_ok!(Elections::remove_voter(Origin::signed(2))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(2))); assert!(all_voters().is_empty()); - assert_noop!(Elections::remove_voter(Origin::signed(2)), Error::::MustBeVoter); + assert_noop!( + Elections::remove_voter(RuntimeOrigin::signed(2)), + Error::::MustBeVoter + ); }); } #[test] fn removed_voter_should_not_be_counted() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); - assert_ok!(Elections::remove_voter(Origin::signed(4))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(4))); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2159,13 +2171,13 @@ mod tests { #[test] fn simple_voting_rounds_should_work() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); - assert_ok!(vote(Origin::signed(4), vec![4], 15)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 15)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); assert_eq_uvec!(all_voters(), vec![2, 3, 4]); @@ -2209,11 +2221,11 @@ mod tests { #[test] fn all_outgoing() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2225,8 +2237,8 @@ mod tests { assert_eq!(members_and_stake(), vec![(4, 35), (5, 45)]); assert_eq!(runners_up_and_stake(), vec![]); - assert_ok!(Elections::remove_voter(Origin::signed(5))); - assert_ok!(Elections::remove_voter(Origin::signed(4))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(5))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(4))); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2244,11 +2256,11 @@ mod tests { #[test] fn defunct_voter_will_be_counted() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); // This guy's vote is pointless for this round. - assert_ok!(vote(Origin::signed(3), vec![4], 30)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![4], 30)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2257,7 +2269,7 @@ mod tests { assert_eq!(Elections::election_rounds(), 1); // but now it has a valid target. - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2272,15 +2284,15 @@ mod tests { #[test] fn only_desired_seats_are_chosen() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2293,8 +2305,8 @@ mod tests { #[test] fn phragmen_should_not_self_vote() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2312,15 +2324,15 @@ mod tests { #[test] fn runners_up_should_be_kept() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![3], 20)); - assert_ok!(vote(Origin::signed(3), vec![2], 30)); - assert_ok!(vote(Origin::signed(4), vec![5], 40)); - assert_ok!(vote(Origin::signed(5), vec![4], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![3], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![2], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![5], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![4], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2339,22 +2351,22 @@ mod tests { #[test] fn runners_up_should_be_next_candidates() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_and_stake(), vec![(4, 35), (5, 45)]); assert_eq!(runners_up_and_stake(), vec![(2, 15), (3, 25)]); - assert_ok!(vote(Origin::signed(5), vec![5], 10)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 10)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2367,13 +2379,13 @@ mod tests { #[test] fn runners_up_lose_bond_once_outgoing() { ExtBuilder::default().desired_runners_up(1).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2381,8 +2393,8 @@ mod tests { assert_eq!(runners_up_ids(), vec![2]); assert_eq!(balances(&2), (15, 5)); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2397,17 +2409,17 @@ mod tests { ExtBuilder::default().build_and_execute(|| { assert_eq!(balances(&5), (50, 0)); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); assert_eq!(balances(&5), (47, 3)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); assert_eq!(balances(&5), (45, 5)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![5]); - assert_ok!(Elections::remove_voter(Origin::signed(5))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(5))); assert_eq!(balances(&5), (47, 3)); System::set_block_number(10); @@ -2421,10 +2433,10 @@ mod tests { #[test] fn candidates_lose_the_bond_when_outgoing() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(4), vec![5], 40)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![5], 40)); assert_eq!(balances(&5), (47, 3)); assert_eq!(balances(&3), (27, 3)); @@ -2444,11 +2456,11 @@ mod tests { #[test] fn current_members_are_always_next_candidate() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2456,13 +2468,13 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert_eq!(Elections::election_rounds(), 1); - assert_ok!(submit_candidacy(Origin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); - assert_ok!(Elections::remove_voter(Origin::signed(4))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(4))); // 5 will persist as candidates despite not being in the list. assert_eq!(candidate_ids(), vec![2, 3]); @@ -2480,15 +2492,15 @@ mod tests { // what I mean by uninterrupted: // given no input or stimulants the same members are re-elected. ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); let check_at_block = |b: u32| { System::set_block_number(b.into()); @@ -2513,11 +2525,11 @@ mod tests { #[test] fn remove_members_triggers_election() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2525,10 +2537,10 @@ mod tests { assert_eq!(Elections::election_rounds(), 1); // a new candidate - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); - assert_ok!(Elections::remove_member(Origin::root(), 4, true, true)); + assert_ok!(Elections::remove_member(RuntimeOrigin::root(), 4, true, true)); assert_eq!(balances(&4), (35, 2)); // slashed assert_eq!(Elections::election_rounds(), 2); // new election round @@ -2539,14 +2551,14 @@ mod tests { #[test] fn seats_should_be_released_when_no_vote() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(2), vec![3], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![3], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); assert_eq!(>::decode_len().unwrap(), 3); @@ -2557,10 +2569,10 @@ mod tests { assert_eq!(members_ids(), vec![3, 5]); assert_eq!(Elections::election_rounds(), 1); - assert_ok!(Elections::remove_voter(Origin::signed(2))); - assert_ok!(Elections::remove_voter(Origin::signed(3))); - assert_ok!(Elections::remove_voter(Origin::signed(4))); - assert_ok!(Elections::remove_voter(Origin::signed(5))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(2))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(3))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(4))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(5))); // meanwhile, no one cares to become a candidate again. System::set_block_number(10); @@ -2573,29 +2585,29 @@ mod tests { #[test] fn incoming_outgoing_are_reported() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![4, 5]); - assert_ok!(submit_candidacy(Origin::signed(1))); - assert_ok!(submit_candidacy(Origin::signed(2))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(1))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); // 5 will change their vote and becomes an `outgoing` - assert_ok!(vote(Origin::signed(5), vec![4], 8)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![4], 8)); // 4 will stay in the set - assert_ok!(vote(Origin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); // 3 will become a winner - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); // these two are losers. - assert_ok!(vote(Origin::signed(2), vec![2], 20)); - assert_ok!(vote(Origin::signed(1), vec![1], 10)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![1], 10)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2620,12 +2632,12 @@ mod tests { #[test] fn invalid_votes_are_moot() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![10], 50)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![10], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2638,15 +2650,15 @@ mod tests { #[test] fn members_are_sorted_based_on_id_runners_on_merit() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![3], 20)); - assert_ok!(vote(Origin::signed(3), vec![2], 30)); - assert_ok!(vote(Origin::signed(4), vec![5], 40)); - assert_ok!(vote(Origin::signed(5), vec![4], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![3], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![2], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![5], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![4], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2660,19 +2672,19 @@ mod tests { #[test] fn runner_up_replacement_maintains_members_order() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![2], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![2], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![2, 4]); - assert_ok!(Elections::remove_member(Origin::root(), 2, true, false)); + assert_ok!(Elections::remove_member(RuntimeOrigin::root(), 2, true, false)); assert_eq!(members_ids(), vec![4, 5]); }); } @@ -2680,15 +2692,15 @@ mod tests { #[test] fn can_renounce_candidacy_member_with_runners_bond_is_refunded() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2696,7 +2708,7 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert_eq!(runners_up_ids(), vec![2, 3]); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Member)); + assert_ok!(Elections::renounce_candidacy(RuntimeOrigin::signed(4), Renouncing::Member)); assert_eq!(balances(&4), (38, 2)); // 2 is voting bond. assert_eq!(members_ids(), vec![3, 5]); @@ -2707,11 +2719,11 @@ mod tests { #[test] fn can_renounce_candidacy_member_without_runners_bond_is_refunded() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2719,7 +2731,7 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert!(runners_up_ids().is_empty()); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Member)); + assert_ok!(Elections::renounce_candidacy(RuntimeOrigin::signed(4), Renouncing::Member)); assert_eq!(balances(&4), (38, 2)); // 2 is voting bond. // no replacement @@ -2731,15 +2743,15 @@ mod tests { #[test] fn can_renounce_candidacy_runner_up() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(5), vec![4], 50)); - assert_ok!(vote(Origin::signed(4), vec![5], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![4], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![5], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2747,7 +2759,10 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert_eq!(runners_up_ids(), vec![2, 3]); - assert_ok!(Elections::renounce_candidacy(Origin::signed(3), Renouncing::RunnerUp)); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(3), + Renouncing::RunnerUp + )); assert_eq!(balances(&3), (28, 2)); // 2 is voting bond. assert_eq!(members_ids(), vec![4, 5]); @@ -2758,22 +2773,25 @@ mod tests { #[test] fn runner_up_replacement_works_when_out_of_order() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![2], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![2], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![2, 4]); assert_eq!(runners_up_ids(), vec![5, 3]); - assert_ok!(Elections::renounce_candidacy(Origin::signed(3), Renouncing::RunnerUp)); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(3), + Renouncing::RunnerUp + )); assert_eq!(members_ids(), vec![2, 4]); assert_eq!(runners_up_ids(), vec![5]); }); @@ -2782,11 +2800,14 @@ mod tests { #[test] fn can_renounce_candidacy_candidate() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); assert_eq!(balances(&5), (47, 3)); assert_eq!(candidate_ids(), vec![5]); - assert_ok!(Elections::renounce_candidacy(Origin::signed(5), Renouncing::Candidate(1))); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(5), + Renouncing::Candidate(1) + )); assert_eq!(balances(&5), (50, 0)); assert!(candidate_ids().is_empty()); }) @@ -2796,15 +2817,15 @@ mod tests { fn wrong_renounce_candidacy_should_fail() { ExtBuilder::default().build_and_execute(|| { assert_noop!( - Elections::renounce_candidacy(Origin::signed(5), Renouncing::Candidate(0)), + Elections::renounce_candidacy(RuntimeOrigin::signed(5), Renouncing::Candidate(0)), Error::::InvalidRenouncing, ); assert_noop!( - Elections::renounce_candidacy(Origin::signed(5), Renouncing::Member), + Elections::renounce_candidacy(RuntimeOrigin::signed(5), Renouncing::Member), Error::::InvalidRenouncing, ); assert_noop!( - Elections::renounce_candidacy(Origin::signed(5), Renouncing::RunnerUp), + Elections::renounce_candidacy(RuntimeOrigin::signed(5), Renouncing::RunnerUp), Error::::InvalidRenouncing, ); }) @@ -2813,13 +2834,13 @@ mod tests { #[test] fn non_member_renounce_member_should_fail() { ExtBuilder::default().desired_runners_up(1).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2828,7 +2849,7 @@ mod tests { assert_eq!(runners_up_ids(), vec![3]); assert_noop!( - Elections::renounce_candidacy(Origin::signed(3), Renouncing::Member), + Elections::renounce_candidacy(RuntimeOrigin::signed(3), Renouncing::Member), Error::::InvalidRenouncing, ); }) @@ -2837,13 +2858,13 @@ mod tests { #[test] fn non_runner_up_renounce_runner_up_should_fail() { ExtBuilder::default().desired_runners_up(1).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2852,7 +2873,7 @@ mod tests { assert_eq!(runners_up_ids(), vec![3]); assert_noop!( - Elections::renounce_candidacy(Origin::signed(4), Renouncing::RunnerUp), + Elections::renounce_candidacy(RuntimeOrigin::signed(4), Renouncing::RunnerUp), Error::::InvalidRenouncing, ); }) @@ -2861,27 +2882,33 @@ mod tests { #[test] fn wrong_candidate_count_renounce_should_fail() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); assert_noop!( - Elections::renounce_candidacy(Origin::signed(4), Renouncing::Candidate(2)), + Elections::renounce_candidacy(RuntimeOrigin::signed(4), Renouncing::Candidate(2)), Error::::InvalidWitnessData, ); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Candidate(3))); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(4), + Renouncing::Candidate(3) + )); }) } #[test] fn renounce_candidacy_count_can_overestimate() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); // while we have only 3 candidates. - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Candidate(4))); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(4), + Renouncing::Candidate(4) + )); }) } @@ -2891,13 +2918,13 @@ mod tests { .desired_runners_up(2) .desired_members(1) .build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 5)); - assert_ok!(vote(Origin::signed(3), vec![3], 15)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 5)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 15)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2905,8 +2932,8 @@ mod tests { assert_eq!(members_ids(), vec![5]); assert_eq!(runners_up_ids(), vec![4, 3]); - assert_ok!(submit_candidacy(Origin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![2], 10)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 10)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2927,13 +2954,13 @@ mod tests { .desired_runners_up(2) .desired_members(1) .build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2946,8 +2973,8 @@ mod tests { assert_eq!(balances(&2), (15, 5)); // this guy will shift everyone down. - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2970,13 +2997,13 @@ mod tests { .desired_runners_up(2) .desired_members(1) .build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2989,8 +3016,8 @@ mod tests { assert_eq!(balances(&2), (15, 5)); // swap some votes. - assert_ok!(vote(Origin::signed(4), vec![2], 40)); - assert_ok!(vote(Origin::signed(2), vec![4], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![2], 40)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4], 20)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -3010,13 +3037,13 @@ mod tests { #[test] fn remove_and_replace_member_works() { let setup = || { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -3037,7 +3064,10 @@ mod tests { // member removed, no replacement found. ExtBuilder::default().desired_runners_up(1).build_and_execute(|| { setup(); - assert_ok!(Elections::renounce_candidacy(Origin::signed(3), Renouncing::RunnerUp)); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(3), + Renouncing::RunnerUp + )); assert_eq!(Elections::remove_and_replace_member(&4, false), Ok(false)); assert_eq!(members_ids(), vec![5]); @@ -3060,15 +3090,15 @@ mod tests { .build_and_execute(|| { assert_eq!(Elections::candidates().len(), 0); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); assert_eq!(Elections::candidates().len(), 3); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -3086,15 +3116,15 @@ mod tests { .build_and_execute(|| { assert_eq!(Elections::candidates().len(), 0); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); assert_eq!(Elections::candidates().len(), 3); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -3112,15 +3142,15 @@ mod tests { .build_and_execute(|| { assert_eq!(Elections::candidates().len(), 0); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); assert_eq!(Elections::candidates().len(), 3); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -3135,17 +3165,17 @@ mod tests { #[test] fn dupe_vote_is_moot() { ExtBuilder::default().desired_members(1).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); - assert_ok!(submit_candidacy(Origin::signed(1))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(1))); // all these duplicate votes will not cause 2 to win. - assert_ok!(vote(Origin::signed(1), vec![2, 2, 2, 2], 5)); - assert_ok!(vote(Origin::signed(2), vec![2, 2, 2, 2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![2, 2, 2, 2], 5)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2, 2, 2, 2], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -3157,24 +3187,33 @@ mod tests { #[test] fn remove_defunct_voter_works() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); // defunct - assert_ok!(vote(Origin::signed(5), vec![5, 4], 5)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5, 4], 5)); // defunct - assert_ok!(vote(Origin::signed(4), vec![4], 5)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 5)); // ok - assert_ok!(vote(Origin::signed(3), vec![3], 5)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 5)); // ok - assert_ok!(vote(Origin::signed(2), vec![3, 4], 5)); - - assert_ok!(Elections::renounce_candidacy(Origin::signed(5), Renouncing::Candidate(3))); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Candidate(2))); - assert_ok!(Elections::renounce_candidacy(Origin::signed(3), Renouncing::Candidate(1))); - - assert_ok!(Elections::clean_defunct_voters(Origin::root(), 4, 2)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![3, 4], 5)); + + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(5), + Renouncing::Candidate(3) + )); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(4), + Renouncing::Candidate(2) + )); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(3), + Renouncing::Candidate(1) + )); + + assert_ok!(Elections::clean_defunct_voters(RuntimeOrigin::root(), 4, 2)); }) } } diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index caa2d825262db..f754348782cec 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -655,7 +655,7 @@ pub mod pallet { impl Pallet { // Add public immutables and private mutables. #[allow(dead_code)] - fn accumulate_foo(origin: T::Origin, increase_by: T::Balance) -> DispatchResult { + fn accumulate_foo(origin: T::RuntimeOrigin, increase_by: T::Balance) -> DispatchResult { let _sender = ensure_signed(origin)?; let prev = >::get(); diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 793cb4287f505..db4787eaa0faa 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -60,7 +60,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -128,12 +128,12 @@ fn it_works_for_optional_value() { assert_eq!(Example::dummy(), Some(val1)); // Check that accumulate works when we have Some value in Dummy already. - assert_ok!(Example::accumulate_dummy(Origin::signed(1), val2)); + assert_ok!(Example::accumulate_dummy(RuntimeOrigin::signed(1), val2)); assert_eq!(Example::dummy(), Some(val1 + val2)); // Check that accumulate works when we Dummy has None in it. >::on_initialize(2); - assert_ok!(Example::accumulate_dummy(Origin::signed(1), val1)); + assert_ok!(Example::accumulate_dummy(RuntimeOrigin::signed(1), val1)); assert_eq!(Example::dummy(), Some(val1 + val2 + val1)); }); } @@ -142,7 +142,7 @@ fn it_works_for_optional_value() { fn it_works_for_default_value() { new_test_ext().execute_with(|| { assert_eq!(Example::foo(), 24); - assert_ok!(Example::accumulate_foo(Origin::signed(1), 1)); + assert_ok!(Example::accumulate_foo(RuntimeOrigin::signed(1), 1)); assert_eq!(Example::foo(), 25); }); } @@ -151,7 +151,7 @@ fn it_works_for_default_value() { fn set_dummy_works() { new_test_ext().execute_with(|| { let test_val = 133; - assert_ok!(Example::set_dummy(Origin::root(), test_val.into())); + assert_ok!(Example::set_dummy(RuntimeOrigin::root(), test_val.into())); assert_eq!(Example::dummy(), Some(test_val)); }); } diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 2c189935ac19d..72c001fd6e6cc 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -60,7 +60,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; @@ -134,10 +134,10 @@ fn it_aggregates_the_price() { sp_io::TestExternalities::default().execute_with(|| { assert_eq!(Example::average_price(), None); - assert_ok!(Example::submit_price(Origin::signed(test_pub()), 27)); + assert_ok!(Example::submit_price(RuntimeOrigin::signed(test_pub()), 27)); assert_eq!(Example::average_price(), Some(27)); - assert_ok!(Example::submit_price(Origin::signed(test_pub()), 43)); + assert_ok!(Example::submit_price(RuntimeOrigin::signed(test_pub()), 43)); assert_eq!(Example::average_price(), Some(35)); }); } diff --git a/frame/examples/parallel/src/tests.rs b/frame/examples/parallel/src/tests.rs index 80c8213fdfb1c..fdef24a39ae36 100644 --- a/frame/examples/parallel/src/tests.rs +++ b/frame/examples/parallel/src/tests.rs @@ -45,7 +45,7 @@ parameter_types! { impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type PalletInfo = PalletInfo; type Index = u64; @@ -76,8 +76,8 @@ fn test_pub(n: u8) -> sp_core::sr25519::Public { sp_core::sr25519::Public::from_raw([n; 32]) } -fn test_origin(n: u8) -> Origin { - Origin::signed(test_pub(n)) +fn test_origin(n: u8) -> RuntimeOrigin { + RuntimeOrigin::signed(test_pub(n)) } #[test] @@ -103,7 +103,7 @@ fn it_can_enlist() { }, ]; - Example::enlist_participants(Origin::signed(test_pub(1)), participants) + Example::enlist_participants(RuntimeOrigin::signed(test_pub(1)), participants) .expect("Failed to enlist"); assert_eq!(Example::participants().len(), 2); diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 88cefb17c2895..4926384e42018 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -138,7 +138,7 @@ use sp_std::{marker::PhantomData, prelude::*}; pub type CheckedOf = >::Checked; pub type CallOf = as Applyable>::Call; -pub type OriginOf = as Dispatchable>::Origin; +pub type OriginOf = as Dispatchable>::RuntimeOrigin; /// Main entry point for certain runtime actions as e.g. `execute_block`. /// @@ -789,7 +789,7 @@ mod tests { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type RuntimeCall = RuntimeCall; type BlockNumber = u64; diff --git a/frame/gilt/src/benchmarking.rs b/frame/gilt/src/benchmarking.rs index 3df08372f499b..1767a8da4def0 100644 --- a/frame/gilt/src/benchmarking.rs +++ b/frame/gilt/src/benchmarking.rs @@ -77,7 +77,7 @@ benchmarks! { set_target { let origin = T::AdminOrigin::successful_origin(); - }: _(origin, Default::default()) + }: _(origin, Default::default()) verify {} thaw { diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index 157aa8284f2f1..28a0f5fd56e67 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -116,7 +116,7 @@ pub mod pallet { + MaxEncodedLen; /// Origin required for setting the target proportion to be under gilt. - type AdminOrigin: EnsureOrigin; + type AdminOrigin: EnsureOrigin; /// Unbalanced handler to account for funds created (in case of a higher total issuance over /// freezing period). diff --git a/frame/gilt/src/mock.rs b/frame/gilt/src/mock.rs index a9cca0ff22780..e1cdf6507ef58 100644 --- a/frame/gilt/src/mock.rs +++ b/frame/gilt/src/mock.rs @@ -49,7 +49,7 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/frame/gilt/src/tests.rs b/frame/gilt/src/tests.rs index 486601b5b2f21..2ac369dd3b8b3 100644 --- a/frame/gilt/src/tests.rs +++ b/frame/gilt/src/tests.rs @@ -49,8 +49,8 @@ fn set_target_works() { new_test_ext().execute_with(|| { run_to_block(1); let e = DispatchError::BadOrigin; - assert_noop!(Gilt::set_target(Origin::signed(2), Perquintill::from_percent(50)), e); - assert_ok!(Gilt::set_target(Origin::signed(1), Perquintill::from_percent(50))); + assert_noop!(Gilt::set_target(RuntimeOrigin::signed(2), Perquintill::from_percent(50)), e); + assert_ok!(Gilt::set_target(RuntimeOrigin::signed(1), Perquintill::from_percent(50))); assert_eq!( ActiveTotal::::get(), @@ -68,13 +68,19 @@ fn set_target_works() { fn place_bid_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_noop!(Gilt::place_bid(Origin::signed(1), 1, 2), Error::::AmountTooSmall); assert_noop!( - Gilt::place_bid(Origin::signed(1), 101, 2), + Gilt::place_bid(RuntimeOrigin::signed(1), 1, 2), + Error::::AmountTooSmall + ); + assert_noop!( + Gilt::place_bid(RuntimeOrigin::signed(1), 101, 2), BalancesError::::InsufficientBalance ); - assert_noop!(Gilt::place_bid(Origin::signed(1), 10, 4), Error::::DurationTooBig); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); + assert_noop!( + Gilt::place_bid(RuntimeOrigin::signed(1), 10, 4), + Error::::DurationTooBig + ); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); assert_eq!(Balances::reserved_balance(1), 10); assert_eq!(Queues::::get(2), vec![GiltBid { amount: 10, who: 1 }]); assert_eq!(QueueTotals::::get(), vec![(0, 0), (1, 10), (0, 0)]); @@ -85,16 +91,16 @@ fn place_bid_works() { fn place_bid_queuing_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 20, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 5, 2)); - assert_noop!(Gilt::place_bid(Origin::signed(1), 5, 2), Error::::BidTooLow); - assert_ok!(Gilt::place_bid(Origin::signed(1), 15, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 20, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 5, 2)); + assert_noop!(Gilt::place_bid(RuntimeOrigin::signed(1), 5, 2), Error::::BidTooLow); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 15, 2)); assert_eq!(Balances::reserved_balance(1), 45); - assert_ok!(Gilt::place_bid(Origin::signed(1), 25, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 25, 2)); assert_eq!(Balances::reserved_balance(1), 60); - assert_noop!(Gilt::place_bid(Origin::signed(1), 10, 2), Error::::BidTooLow); + assert_noop!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2), Error::::BidTooLow); assert_eq!( Queues::::get(2), vec![ @@ -111,11 +117,11 @@ fn place_bid_queuing_works() { fn place_bid_fails_when_queue_full() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(3), 10, 2)); - assert_noop!(Gilt::place_bid(Origin::signed(4), 10, 2), Error::::BidTooLow); - assert_ok!(Gilt::place_bid(Origin::signed(4), 10, 3)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(3), 10, 2)); + assert_noop!(Gilt::place_bid(RuntimeOrigin::signed(4), 10, 2), Error::::BidTooLow); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(4), 10, 3)); }); } @@ -123,11 +129,11 @@ fn place_bid_fails_when_queue_full() { fn multiple_place_bids_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 3)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 3)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 10, 2)); assert_eq!(Balances::reserved_balance(1), 40); assert_eq!(Balances::reserved_balance(2), 10); @@ -149,9 +155,9 @@ fn multiple_place_bids_works() { fn retract_single_item_queue_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::retract_bid(Origin::signed(1), 10, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 1)); assert_eq!(Balances::reserved_balance(1), 10); assert_eq!(Queues::::get(1), vec![]); @@ -164,12 +170,12 @@ fn retract_single_item_queue_works() { fn retract_with_other_and_duplicate_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 10, 2)); - assert_ok!(Gilt::retract_bid(Origin::signed(1), 10, 2)); + assert_ok!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 2)); assert_eq!(Balances::reserved_balance(1), 20); assert_eq!(Balances::reserved_balance(2), 10); assert_eq!(Queues::::get(1), vec![GiltBid { amount: 10, who: 1 },]); @@ -185,11 +191,11 @@ fn retract_with_other_and_duplicate_works() { fn retract_non_existent_item_fails() { new_test_ext().execute_with(|| { run_to_block(1); - assert_noop!(Gilt::retract_bid(Origin::signed(1), 10, 1), Error::::NotFound); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 1)); - assert_noop!(Gilt::retract_bid(Origin::signed(1), 20, 1), Error::::NotFound); - assert_noop!(Gilt::retract_bid(Origin::signed(1), 10, 2), Error::::NotFound); - assert_noop!(Gilt::retract_bid(Origin::signed(2), 10, 1), Error::::NotFound); + assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 1), Error::::NotFound); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(1), 20, 1), Error::::NotFound); + assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 2), Error::::NotFound); + assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(2), 10, 1), Error::::NotFound); }); } @@ -197,8 +203,8 @@ fn retract_non_existent_item_fails() { fn basic_enlarge_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 40, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 2)); Gilt::enlarge(40, 2); // Takes 2/2, then stopped because it reaches its max amount @@ -228,10 +234,10 @@ fn basic_enlarge_works() { fn enlarge_respects_bids_limit() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 40, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(3), 40, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(4), 40, 3)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(3), 40, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(4), 40, 3)); Gilt::enlarge(100, 2); // Should have taken 4/3 and 2/2, then stopped because it's only allowed 2. @@ -269,7 +275,7 @@ fn enlarge_respects_bids_limit() { fn enlarge_respects_amount_limit_and_will_split() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 80, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 80, 1)); Gilt::enlarge(40, 2); // Takes 2/2, then stopped because it reaches its max amount @@ -296,14 +302,14 @@ fn enlarge_respects_amount_limit_and_will_split() { fn basic_thaw_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); Gilt::enlarge(40, 1); run_to_block(3); - assert_noop!(Gilt::thaw(Origin::signed(1), 0), Error::::NotExpired); + assert_noop!(Gilt::thaw(RuntimeOrigin::signed(1), 0), Error::::NotExpired); run_to_block(4); - assert_noop!(Gilt::thaw(Origin::signed(1), 1), Error::::Unknown); - assert_noop!(Gilt::thaw(Origin::signed(2), 0), Error::::NotOwner); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); + assert_noop!(Gilt::thaw(RuntimeOrigin::signed(1), 1), Error::::Unknown); + assert_noop!(Gilt::thaw(RuntimeOrigin::signed(2), 0), Error::::NotOwner); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); assert_eq!( ActiveTotal::::get(), @@ -324,7 +330,7 @@ fn basic_thaw_works() { fn thaw_when_issuance_higher_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 100, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 100, 1)); Gilt::enlarge(100, 1); // Everybody else's balances goes up by 50% @@ -333,7 +339,7 @@ fn thaw_when_issuance_higher_works() { Balances::make_free_balance_be(&4, 150); run_to_block(4); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); assert_eq!(Balances::free_balance(1), 150); assert_eq!(Balances::reserved_balance(1), 0); @@ -347,16 +353,16 @@ fn thaw_with_ignored_issuance_works() { // Give account zero some balance. Balances::make_free_balance_be(&0, 200); - assert_ok!(Gilt::place_bid(Origin::signed(1), 100, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 100, 1)); Gilt::enlarge(100, 1); // Account zero transfers 50 into everyone else's accounts. - assert_ok!(Balances::transfer(Origin::signed(0), 2, 50)); - assert_ok!(Balances::transfer(Origin::signed(0), 3, 50)); - assert_ok!(Balances::transfer(Origin::signed(0), 4, 50)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 2, 50)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 3, 50)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 4, 50)); run_to_block(4); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); // Account zero changes have been ignored. assert_eq!(Balances::free_balance(1), 150); @@ -368,7 +374,7 @@ fn thaw_with_ignored_issuance_works() { fn thaw_when_issuance_lower_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 100, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 100, 1)); Gilt::enlarge(100, 1); // Everybody else's balances goes down by 25% @@ -377,7 +383,7 @@ fn thaw_when_issuance_lower_works() { Balances::make_free_balance_be(&4, 75); run_to_block(4); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); assert_eq!(Balances::free_balance(1), 75); assert_eq!(Balances::reserved_balance(1), 0); @@ -388,9 +394,9 @@ fn thaw_when_issuance_lower_works() { fn multiple_thaws_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 60, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 50, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 60, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 50, 1)); Gilt::enlarge(200, 3); // Double everyone's free balances. @@ -399,9 +405,9 @@ fn multiple_thaws_works() { Balances::make_free_balance_be(&4, 200); run_to_block(4); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); - assert_ok!(Gilt::thaw(Origin::signed(1), 1)); - assert_ok!(Gilt::thaw(Origin::signed(2), 2)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 1)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(2), 2)); assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(2), 200); @@ -412,9 +418,9 @@ fn multiple_thaws_works() { fn multiple_thaws_works_in_alternative_thaw_order() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 60, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 50, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 60, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 50, 1)); Gilt::enlarge(200, 3); // Double everyone's free balances. @@ -423,9 +429,9 @@ fn multiple_thaws_works_in_alternative_thaw_order() { Balances::make_free_balance_be(&4, 200); run_to_block(4); - assert_ok!(Gilt::thaw(Origin::signed(2), 2)); - assert_ok!(Gilt::thaw(Origin::signed(1), 1)); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(2), 2)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 1)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(2), 200); @@ -436,12 +442,12 @@ fn multiple_thaws_works_in_alternative_thaw_order() { fn enlargement_to_target_works() { new_test_ext().execute_with(|| { run_to_block(2); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 40, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 40, 3)); - assert_ok!(Gilt::place_bid(Origin::signed(3), 40, 3)); - assert_ok!(Gilt::set_target(Origin::signed(1), Perquintill::from_percent(40))); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 3)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(3), 40, 3)); + assert_ok!(Gilt::set_target(RuntimeOrigin::signed(1), Perquintill::from_percent(40))); run_to_block(3); assert_eq!(Queues::::get(1), vec![GiltBid { amount: 40, who: 1 },]); @@ -540,7 +546,7 @@ fn enlargement_to_target_works() { ); // Set target a bit higher to use up the remaining bid. - assert_ok!(Gilt::set_target(Origin::signed(1), Perquintill::from_percent(60))); + assert_ok!(Gilt::set_target(RuntimeOrigin::signed(1), Perquintill::from_percent(60))); run_to_block(10); // Two new gilts should have been issued to 1 & 2 for 40 each & duration of 2. diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 19caf0766a3e0..a26000c0f7f2c 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -79,7 +79,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index baf71dfff71dc..775eda58c03e0 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -359,7 +359,7 @@ fn report_equivocation_current_set_works() { // report the equivocation and the tx should be dispatched successfully assert_ok!(Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ),); @@ -437,7 +437,7 @@ fn report_equivocation_old_set_works() { // report the equivocation using the key ownership proof generated on // the old set, the tx should be dispatched successfully assert_ok!(Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ),); @@ -500,7 +500,7 @@ fn report_equivocation_invalid_set_id() { // the call for reporting the equivocation should error assert_err!( Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ), @@ -541,7 +541,7 @@ fn report_equivocation_invalid_session() { // proof from the previous set, the session should be invalid. assert_err!( Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ), @@ -586,7 +586,7 @@ fn report_equivocation_invalid_key_owner_proof() { // proof for a different key than the one in the equivocation proof. assert_err!( Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), invalid_key_owner_proof, ), @@ -617,7 +617,7 @@ fn report_equivocation_invalid_equivocation_proof() { let assert_invalid_equivocation_proof = |equivocation_proof| { assert_err!( Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof.clone(), ), @@ -723,7 +723,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() { // we submit the report Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) @@ -861,7 +861,7 @@ fn valid_equivocation_reports_dont_pay_fees() { // report the equivocation. let post_info = Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof.clone()), key_owner_proof.clone(), ) @@ -875,7 +875,7 @@ fn valid_equivocation_reports_dont_pay_fees() { // report the equivocation again which is invalid now since it is // duplicate. let post_info = Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 7ab5d416eb533..c66658b92b0d2 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -123,7 +123,7 @@ benchmarks! { ensure!(Registrars::::get().len() as u32 == r, "Registrars not set up correctly."); let origin = T::RegistrarOrigin::successful_origin(); let account = T::Lookup::unlookup(account("registrar", r + 1, SEED)); - }: _(origin, account) + }: _(origin, account) verify { ensure!(Registrars::::get().len() as u32 == r + 1, "Registrars not added."); } @@ -135,7 +135,7 @@ benchmarks! { // The target user let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - let caller_origin: ::Origin = RawOrigin::Signed(caller.clone()).into(); + let caller_origin: ::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); // Add an initial identity @@ -193,7 +193,7 @@ benchmarks! { clear_identity { let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller.clone())); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); let caller_lookup = ::unlookup(caller.clone()); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -208,7 +208,7 @@ benchmarks! { // Create their main identity with x additional fields let info = create_identity_info::(x); let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller.clone())); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); Identity::::set_identity(caller_origin.clone(), Box::new(info.clone()))?; // User requests judgement from all the registrars, and they approve @@ -237,7 +237,7 @@ benchmarks! { // Create their main identity with x additional fields let info = create_identity_info::(x); let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller)); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller)); Identity::::set_identity(caller_origin, Box::new(info))?; }; }: _(RawOrigin::Signed(caller.clone()), r - 1, 10u32.into()) @@ -247,7 +247,7 @@ benchmarks! { cancel_request { let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller.clone())); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; @@ -255,7 +255,7 @@ benchmarks! { // Create their main identity with x additional fields let info = create_identity_info::(x); let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller)); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller)); Identity::::set_identity(caller_origin, Box::new(info))?; }; @@ -323,7 +323,7 @@ benchmarks! { provide_judgement { // The user let user: T::AccountId = account("user", r, SEED); - let user_origin = ::Origin::from(RawOrigin::Signed(user.clone())); + let user_origin = ::RuntimeOrigin::from(RawOrigin::Signed(user.clone())); let user_lookup = ::unlookup(user.clone()); let _ = T::Currency::make_free_balance_be(&user, BalanceOf::::max_value()); @@ -352,7 +352,7 @@ benchmarks! { let x in 1 .. T::MaxAdditionalFields::get(); let target: T::AccountId = account("target", 0, SEED); - let target_origin: ::Origin = RawOrigin::Signed(target.clone()).into(); + let target_origin: ::RuntimeOrigin = RawOrigin::Signed(target.clone()).into(); let target_lookup = T::Lookup::unlookup(target.clone()); let _ = T::Currency::make_free_balance_be(&target, BalanceOf::::max_value()); @@ -373,7 +373,7 @@ benchmarks! { } ensure!(IdentityOf::::contains_key(&target), "Identity not set"); let origin = T::ForceOrigin::successful_origin(); - }: _(origin, target_lookup) + }: _(origin, target_lookup) verify { ensure!(!IdentityOf::::contains_key(&target), "Identity not removed"); } diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index c4f35a06e830a..8b22ecedaec19 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -142,10 +142,10 @@ pub mod pallet { type Slashed: OnUnbalanced>; /// The origin which may forcibly set or remove a name. Root can always do this. - type ForceOrigin: EnsureOrigin; + type ForceOrigin: EnsureOrigin; /// The origin which may add or remove registrars. Root can always do this. - type RegistrarOrigin: EnsureOrigin; + type RegistrarOrigin: EnsureOrigin; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 0fb5d4587af16..747d1e9f27106 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -56,7 +56,7 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -148,41 +148,44 @@ fn editing_subaccounts_should_work() { new_test_ext().execute_with(|| { let data = |x| Data::Raw(vec![x; 1].try_into().unwrap()); - assert_noop!(Identity::add_sub(Origin::signed(10), 20, data(1)), Error::::NoIdentity); + assert_noop!( + Identity::add_sub(RuntimeOrigin::signed(10), 20, data(1)), + Error::::NoIdentity + ); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); // first sub account - assert_ok!(Identity::add_sub(Origin::signed(10), 1, data(1))); + assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 1, data(1))); assert_eq!(SuperOf::::get(1), Some((10, data(1)))); assert_eq!(Balances::free_balance(10), 80); // second sub account - assert_ok!(Identity::add_sub(Origin::signed(10), 2, data(2))); + assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 2, data(2))); assert_eq!(SuperOf::::get(1), Some((10, data(1)))); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); assert_eq!(Balances::free_balance(10), 70); // third sub account is too many assert_noop!( - Identity::add_sub(Origin::signed(10), 3, data(3)), + Identity::add_sub(RuntimeOrigin::signed(10), 3, data(3)), Error::::TooManySubAccounts ); // rename first sub account - assert_ok!(Identity::rename_sub(Origin::signed(10), 1, data(11))); + assert_ok!(Identity::rename_sub(RuntimeOrigin::signed(10), 1, data(11))); assert_eq!(SuperOf::::get(1), Some((10, data(11)))); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); assert_eq!(Balances::free_balance(10), 70); // remove first sub account - assert_ok!(Identity::remove_sub(Origin::signed(10), 1)); + assert_ok!(Identity::remove_sub(RuntimeOrigin::signed(10), 1)); assert_eq!(SuperOf::::get(1), None); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); assert_eq!(Balances::free_balance(10), 80); // add third sub account - assert_ok!(Identity::add_sub(Origin::signed(10), 3, data(3))); + assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 3, data(3))); assert_eq!(SuperOf::::get(1), None); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); assert_eq!(SuperOf::::get(3), Some((10, data(3)))); @@ -195,27 +198,27 @@ fn resolving_subaccount_ownership_works() { new_test_ext().execute_with(|| { let data = |x| Data::Raw(vec![x; 1].try_into().unwrap()); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); - assert_ok!(Identity::set_identity(Origin::signed(20), Box::new(twenty()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(20), Box::new(twenty()))); // 10 claims 1 as a subaccount - assert_ok!(Identity::add_sub(Origin::signed(10), 1, data(1))); + assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 1, data(1))); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(10), 80); assert_eq!(Balances::reserved_balance(10), 20); // 20 cannot claim 1 now assert_noop!( - Identity::add_sub(Origin::signed(20), 1, data(1)), + Identity::add_sub(RuntimeOrigin::signed(20), 1, data(1)), Error::::AlreadyClaimed ); // 1 wants to be with 20 so it quits from 10 - assert_ok!(Identity::quit_sub(Origin::signed(1))); + assert_ok!(Identity::quit_sub(RuntimeOrigin::signed(1))); // 1 gets the 10 that 10 paid. assert_eq!(Balances::free_balance(1), 20); assert_eq!(Balances::free_balance(10), 80); assert_eq!(Balances::reserved_balance(10), 10); // 20 can claim 1 now - assert_ok!(Identity::add_sub(Origin::signed(20), 1, data(1))); + assert_ok!(Identity::add_sub(RuntimeOrigin::signed(20), 1, data(1))); }); } @@ -232,10 +235,10 @@ fn trailing_zeros_decodes_into_default_data() { #[test] fn adding_registrar_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); let fields = IdentityFields(IdentityField::Display | IdentityField::Legal); - assert_ok!(Identity::set_fields(Origin::signed(3), 0, fields)); + assert_ok!(Identity::set_fields(RuntimeOrigin::signed(3), 0, fields)); assert_eq!( Identity::registrars(), vec![Some(RegistrarInfo { account: 3, fee: 10, fields })] @@ -247,11 +250,11 @@ fn adding_registrar_should_work() { fn amount_of_registrars_is_limited() { new_test_ext().execute_with(|| { for i in 1..MaxRegistrars::get() + 1 { - assert_ok!(Identity::add_registrar(Origin::signed(1), i as u64)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), i as u64)); } let last_registrar = MaxRegistrars::get() as u64 + 1; assert_noop!( - Identity::add_registrar(Origin::signed(1), last_registrar), + Identity::add_registrar(RuntimeOrigin::signed(1), last_registrar), Error::::TooManyRegistrars ); }); @@ -260,18 +263,18 @@ fn amount_of_registrars_is_limited() { #[test] fn registration_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); let mut three_fields = ten(); three_fields.additional.try_push(Default::default()).unwrap(); three_fields.additional.try_push(Default::default()).unwrap(); assert_eq!(three_fields.additional.try_push(Default::default()), Err(())); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_eq!(Identity::identity(10).unwrap().info, ten()); assert_eq!(Balances::free_balance(10), 90); - assert_ok!(Identity::clear_identity(Origin::signed(10))); + assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10))); assert_eq!(Balances::free_balance(10), 100); - assert_noop!(Identity::clear_identity(Origin::signed(10)), Error::::NotNamed); + assert_noop!(Identity::clear_identity(RuntimeOrigin::signed(10)), Error::::NotNamed); }); } @@ -280,7 +283,7 @@ fn uninvited_judgement_should_work() { new_test_ext().execute_with(|| { assert_noop!( Identity::provide_judgement( - Origin::signed(3), + RuntimeOrigin::signed(3), 0, 10, Judgement::Reasonable, @@ -289,10 +292,10 @@ fn uninvited_judgement_should_work() { Error::::InvalidIndex ); - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); assert_noop!( Identity::provide_judgement( - Origin::signed(3), + RuntimeOrigin::signed(3), 0, 10, Judgement::Reasonable, @@ -301,10 +304,10 @@ fn uninvited_judgement_should_work() { Error::::InvalidTarget ); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_noop!( Identity::provide_judgement( - Origin::signed(3), + RuntimeOrigin::signed(3), 0, 10, Judgement::Reasonable, @@ -317,7 +320,7 @@ fn uninvited_judgement_should_work() { assert_noop!( Identity::provide_judgement( - Origin::signed(10), + RuntimeOrigin::signed(10), 0, 10, Judgement::Reasonable, @@ -327,7 +330,7 @@ fn uninvited_judgement_should_work() { ); assert_noop!( Identity::provide_judgement( - Origin::signed(3), + RuntimeOrigin::signed(3), 0, 10, Judgement::FeePaid(1), @@ -337,7 +340,7 @@ fn uninvited_judgement_should_work() { ); assert_ok!(Identity::provide_judgement( - Origin::signed(3), + RuntimeOrigin::signed(3), 0, 10, Judgement::Reasonable, @@ -350,16 +353,16 @@ fn uninvited_judgement_should_work() { #[test] fn clearing_judgement_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_ok!(Identity::provide_judgement( - Origin::signed(3), + RuntimeOrigin::signed(3), 0, 10, Judgement::Reasonable, BlakeTwo256::hash_of(&ten()) )); - assert_ok!(Identity::clear_identity(Origin::signed(10))); + assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10))); assert_eq!(Identity::identity(10), None); }); } @@ -367,12 +370,15 @@ fn clearing_judgement_should_work() { #[test] fn killing_slashing_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); - assert_noop!(Identity::kill_identity(Origin::signed(1), 10), BadOrigin); - assert_ok!(Identity::kill_identity(Origin::signed(2), 10)); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_noop!(Identity::kill_identity(RuntimeOrigin::signed(1), 10), BadOrigin); + assert_ok!(Identity::kill_identity(RuntimeOrigin::signed(2), 10)); assert_eq!(Identity::identity(10), None); assert_eq!(Balances::free_balance(10), 90); - assert_noop!(Identity::kill_identity(Origin::signed(2), 10), Error::::NotNamed); + assert_noop!( + Identity::kill_identity(RuntimeOrigin::signed(2), 10), + Error::::NotNamed + ); }); } @@ -380,17 +386,20 @@ fn killing_slashing_should_work() { fn setting_subaccounts_should_work() { new_test_ext().execute_with(|| { let mut subs = vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))]; - assert_noop!(Identity::set_subs(Origin::signed(10), subs.clone()), Error::::NotFound); + assert_noop!( + Identity::set_subs(RuntimeOrigin::signed(10), subs.clone()), + Error::::NotFound + ); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); - assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone())); assert_eq!(Balances::free_balance(10), 80); assert_eq!(Identity::subs_of(10), (10, vec![20].try_into().unwrap())); assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1].try_into().unwrap())))); // push another item and re-set it. subs.push((30, Data::Raw(vec![50; 1].try_into().unwrap()))); - assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); + assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone())); assert_eq!(Balances::free_balance(10), 70); assert_eq!(Identity::subs_of(10), (20, vec![20, 30].try_into().unwrap())); assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1].try_into().unwrap())))); @@ -398,7 +407,7 @@ fn setting_subaccounts_should_work() { // switch out one of the items and re-set. subs[0] = (40, Data::Raw(vec![60; 1].try_into().unwrap())); - assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); + assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone())); assert_eq!(Balances::free_balance(10), 70); // no change in the balance assert_eq!(Identity::subs_of(10), (20, vec![40, 30].try_into().unwrap())); assert_eq!(Identity::super_of(20), None); @@ -406,7 +415,7 @@ fn setting_subaccounts_should_work() { assert_eq!(Identity::super_of(40), Some((10, Data::Raw(vec![60; 1].try_into().unwrap())))); // clear - assert_ok!(Identity::set_subs(Origin::signed(10), vec![])); + assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), vec![])); assert_eq!(Balances::free_balance(10), 90); assert_eq!(Identity::subs_of(10), (0, BoundedVec::default())); assert_eq!(Identity::super_of(30), None); @@ -414,7 +423,7 @@ fn setting_subaccounts_should_work() { subs.push((20, Data::Raw(vec![40; 1].try_into().unwrap()))); assert_noop!( - Identity::set_subs(Origin::signed(10), subs.clone()), + Identity::set_subs(RuntimeOrigin::signed(10), subs.clone()), Error::::TooManySubAccounts ); }); @@ -423,12 +432,12 @@ fn setting_subaccounts_should_work() { #[test] fn clearing_account_should_remove_subaccounts_and_refund() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_ok!(Identity::set_subs( - Origin::signed(10), + RuntimeOrigin::signed(10), vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))] )); - assert_ok!(Identity::clear_identity(Origin::signed(10))); + assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10))); assert_eq!(Balances::free_balance(10), 100); assert!(Identity::super_of(20).is_none()); }); @@ -437,12 +446,12 @@ fn clearing_account_should_remove_subaccounts_and_refund() { #[test] fn killing_account_should_remove_subaccounts_and_not_refund() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_ok!(Identity::set_subs( - Origin::signed(10), + RuntimeOrigin::signed(10), vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))] )); - assert_ok!(Identity::kill_identity(Origin::signed(2), 10)); + assert_ok!(Identity::kill_identity(RuntimeOrigin::signed(2), 10)); assert_eq!(Balances::free_balance(10), 80); assert!(Identity::super_of(20).is_none()); }); @@ -451,24 +460,30 @@ fn killing_account_should_remove_subaccounts_and_not_refund() { #[test] fn cancelling_requested_judgement_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); - assert_noop!(Identity::cancel_request(Origin::signed(10), 0), Error::::NoIdentity); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); - assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); - assert_ok!(Identity::cancel_request(Origin::signed(10), 0)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); + assert_noop!( + Identity::cancel_request(RuntimeOrigin::signed(10), 0), + Error::::NoIdentity + ); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); + assert_ok!(Identity::cancel_request(RuntimeOrigin::signed(10), 0)); assert_eq!(Balances::free_balance(10), 90); - assert_noop!(Identity::cancel_request(Origin::signed(10), 0), Error::::NotFound); + assert_noop!( + Identity::cancel_request(RuntimeOrigin::signed(10), 0), + Error::::NotFound + ); assert_ok!(Identity::provide_judgement( - Origin::signed(3), + RuntimeOrigin::signed(3), 0, 10, Judgement::Reasonable, BlakeTwo256::hash_of(&ten()) )); assert_noop!( - Identity::cancel_request(Origin::signed(10), 0), + Identity::cancel_request(RuntimeOrigin::signed(10), 0), Error::::JudgementGiven ); }); @@ -477,24 +492,24 @@ fn cancelling_requested_judgement_should_work() { #[test] fn requesting_judgement_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_noop!( - Identity::request_judgement(Origin::signed(10), 0, 9), + Identity::request_judgement(RuntimeOrigin::signed(10), 0, 9), Error::::FeeChanged ); - assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); + assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); // 10 for the judgement request, 10 for the identity. assert_eq!(Balances::free_balance(10), 80); // Re-requesting won't work as we already paid. assert_noop!( - Identity::request_judgement(Origin::signed(10), 0, 10), + Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10), Error::::StickyJudgement ); assert_ok!(Identity::provide_judgement( - Origin::signed(3), + RuntimeOrigin::signed(3), 0, 10, Judgement::Erroneous, @@ -505,33 +520,33 @@ fn requesting_judgement_should_work() { // Re-requesting still won't work as it's erroneous. assert_noop!( - Identity::request_judgement(Origin::signed(10), 0, 10), + Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10), Error::::StickyJudgement ); // Requesting from a second registrar still works. - assert_ok!(Identity::add_registrar(Origin::signed(1), 4)); - assert_ok!(Identity::request_judgement(Origin::signed(10), 1, 10)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 4)); + assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 1, 10)); // Re-requesting after the judgement has been reduced works. assert_ok!(Identity::provide_judgement( - Origin::signed(3), + RuntimeOrigin::signed(3), 0, 10, Judgement::OutOfDate, BlakeTwo256::hash_of(&ten()) )); - assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); + assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); }); } #[test] fn field_deposit_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); assert_ok!(Identity::set_identity( - Origin::signed(10), + RuntimeOrigin::signed(10), Box::new(IdentityInfo { additional: vec![ ( @@ -555,23 +570,23 @@ fn field_deposit_should_work() { #[test] fn setting_account_id_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); // account 4 cannot change the first registrar's identity since it's owned by 3. assert_noop!( - Identity::set_account_id(Origin::signed(4), 0, 3), + Identity::set_account_id(RuntimeOrigin::signed(4), 0, 3), Error::::InvalidIndex ); // account 3 can, because that's the registrar's current account. - assert_ok!(Identity::set_account_id(Origin::signed(3), 0, 4)); + assert_ok!(Identity::set_account_id(RuntimeOrigin::signed(3), 0, 4)); // account 4 can now, because that's their new ID. - assert_ok!(Identity::set_account_id(Origin::signed(4), 0, 3)); + assert_ok!(Identity::set_account_id(RuntimeOrigin::signed(4), 0, 3)); }); } #[test] fn test_has_identity() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert!(Identity::has_identity(&10, IdentityField::Display as u64)); assert!(Identity::has_identity(&10, IdentityField::Legal as u64)); assert!(Identity::has_identity( diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index a193843a3d661..5782e1a615b8e 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -111,7 +111,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { result.execute_with(|| { for i in 1..=6 { System::inc_providers(&i); - assert_eq!(Session::set_keys(Origin::signed(i), (i - 1).into(), vec![]), Ok(())); + assert_eq!(Session::set_keys(RuntimeOrigin::signed(i), (i - 1).into(), vec![]), Ok(())); } }); result @@ -127,7 +127,7 @@ impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index e6154a634f4a4..366119278d836 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -141,7 +141,7 @@ fn heartbeat( "invalid validators len", e @ _ => <&'static str>::from(e), })?; - ImOnline::heartbeat(Origin::none(), heartbeat, signature) + ImOnline::heartbeat(RuntimeOrigin::none(), heartbeat, signature) } #[test] diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index 255080f345eee..fd2e9fff16885 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -52,7 +52,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/frame/indices/src/tests.rs b/frame/indices/src/tests.rs index 4e6c59703ca36..bed6cfffaa825 100644 --- a/frame/indices/src/tests.rs +++ b/frame/indices/src/tests.rs @@ -104,7 +104,7 @@ fn transfer_index_on_accounts_should_work() { fn force_transfer_index_on_preowned_should_work() { new_test_ext().execute_with(|| { assert_ok!(Indices::claim(Some(1).into(), 0)); - assert_ok!(Indices::force_transfer(Origin::root(), Id(3), 0, false)); + assert_ok!(Indices::force_transfer(RuntimeOrigin::root(), Id(3), 0, false)); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::reserved_balance(3), 0); assert_eq!(Indices::lookup_index(0), Some(3)); @@ -114,7 +114,7 @@ fn force_transfer_index_on_preowned_should_work() { #[test] fn force_transfer_index_on_free_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Indices::force_transfer(Origin::root(), Id(3), 0, false)); + assert_ok!(Indices::force_transfer(RuntimeOrigin::root(), Id(3), 0, false)); assert_eq!(Balances::reserved_balance(3), 0); assert_eq!(Indices::lookup_index(0), Some(3)); }); diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index 1c850e66f9c6e..fba722a07fabd 100644 --- a/frame/lottery/src/benchmarking.rs +++ b/frame/lottery/src/benchmarking.rs @@ -78,7 +78,7 @@ benchmarks! { let calls = vec![frame_system::Call::::remark { remark: vec![] }.into(); n as usize]; let origin = T::ManagerOrigin::successful_origin(); assert!(CallIndices::::get().is_empty()); - }: _(origin, calls) + }: _(origin, calls) verify { if !n.is_zero() { assert!(!CallIndices::::get().is_empty()); @@ -90,7 +90,7 @@ benchmarks! { let end = 10u32.into(); let payout = 5u32.into(); let origin = T::ManagerOrigin::successful_origin(); - }: _(origin, price, end, payout, true) + }: _(origin, price, end, payout, true) verify { assert!(crate::Lottery::::get().is_some()); } @@ -99,7 +99,7 @@ benchmarks! { setup_lottery::(true)?; assert_eq!(crate::Lottery::::get().unwrap().repeat, true); let origin = T::ManagerOrigin::successful_origin(); - }: _(origin) + }: _(origin) verify { assert_eq!(crate::Lottery::::get().unwrap().repeat, false); } diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index 505dd1bb98caa..c501a30ef5f4a 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -135,7 +135,7 @@ pub mod pallet { /// A dispatchable call. type RuntimeCall: Parameter - + Dispatchable + + Dispatchable + GetDispatchInfo + From>; @@ -149,7 +149,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The manager origin. - type ManagerOrigin: EnsureOrigin; + type ManagerOrigin: EnsureOrigin; /// The max number of calls available in a single lottery. #[pallet::constant] diff --git a/frame/lottery/src/mock.rs b/frame/lottery/src/mock.rs index b521b83e7ce2b..1977da5959d39 100644 --- a/frame/lottery/src/mock.rs +++ b/frame/lottery/src/mock.rs @@ -57,7 +57,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type RuntimeCall = RuntimeCall; type BlockNumber = u64; diff --git a/frame/lottery/src/tests.rs b/frame/lottery/src/tests.rs index ff3111b52db77..0eaf080564008 100644 --- a/frame/lottery/src/tests.rs +++ b/frame/lottery/src/tests.rs @@ -20,8 +20,8 @@ use super::*; use frame_support::{assert_noop, assert_ok, assert_storage_noop}; use mock::{ - new_test_ext, run_to_block, Balances, BalancesCall, Lottery, Origin, RuntimeCall, SystemCall, - Test, + new_test_ext, run_to_block, Balances, BalancesCall, Lottery, RuntimeCall, RuntimeOrigin, + SystemCall, Test, }; use pallet_balances::Error as BalancesError; use sp_runtime::traits::BadOrigin; @@ -49,15 +49,15 @@ fn basic_end_to_end_works() { ]; // Set calls for the lottery - assert_ok!(Lottery::set_calls(Origin::root(), calls)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls)); // Start lottery, it repeats - assert_ok!(Lottery::start_lottery(Origin::root(), price, length, delay, true)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, true)); assert!(crate::Lottery::::get().is_some()); assert_eq!(Balances::free_balance(&1), 100); let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 20 })); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); // 20 from the transfer, 10 from buying a ticket assert_eq!(Balances::free_balance(&1), 100 - 20 - 10); assert_eq!(Participants::::get(&1).1.len(), 1); @@ -66,14 +66,14 @@ fn basic_end_to_end_works() { assert_eq!(Tickets::::get(0), Some(1)); // More ticket purchases - assert_ok!(Lottery::buy_ticket(Origin::signed(2), call.clone())); - assert_ok!(Lottery::buy_ticket(Origin::signed(3), call.clone())); - assert_ok!(Lottery::buy_ticket(Origin::signed(4), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(3), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(4), call.clone())); assert_eq!(TicketsCount::::get(), 4); // Go to end run_to_block(20); - assert_ok!(Lottery::buy_ticket(Origin::signed(5), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(5), call.clone())); // Ticket isn't bought assert_eq!(TicketsCount::::get(), 4); @@ -100,15 +100,15 @@ fn stop_repeat_works() { let delay = 5; // Set no calls for the lottery. - assert_ok!(Lottery::set_calls(Origin::root(), vec![])); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), vec![])); // Start lottery, it repeats. - assert_ok!(Lottery::start_lottery(Origin::root(), price, length, delay, true)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, true)); // Non-manager fails to `stop_repeat`. - assert_noop!(Lottery::stop_repeat(Origin::signed(1)), DispatchError::BadOrigin); + assert_noop!(Lottery::stop_repeat(RuntimeOrigin::signed(1)), DispatchError::BadOrigin); // Manager can `stop_repeat`, even twice. - assert_ok!(Lottery::stop_repeat(Origin::root())); - assert_ok!(Lottery::stop_repeat(Origin::root())); + assert_ok!(Lottery::stop_repeat(RuntimeOrigin::root())); + assert_ok!(Lottery::stop_repeat(RuntimeOrigin::root())); // Lottery still exists. assert!(crate::Lottery::::get().is_some()); @@ -132,7 +132,7 @@ fn set_calls_works() { RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; - assert_ok!(Lottery::set_calls(Origin::root(), calls)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls)); assert!(CallIndices::::exists()); let too_many_calls = vec![ @@ -142,12 +142,12 @@ fn set_calls_works() { ]; assert_noop!( - Lottery::set_calls(Origin::root(), too_many_calls), + Lottery::set_calls(RuntimeOrigin::root(), too_many_calls), Error::::TooManyCalls, ); // Clear calls - assert_ok!(Lottery::set_calls(Origin::root(), vec![])); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), vec![])); assert!(CallIndices::::get().is_empty()); }); } @@ -182,16 +182,16 @@ fn start_lottery_works() { // Setup ignores bad origin assert_noop!( - Lottery::start_lottery(Origin::signed(1), price, length, delay, false), + Lottery::start_lottery(RuntimeOrigin::signed(1), price, length, delay, false), BadOrigin, ); // All good - assert_ok!(Lottery::start_lottery(Origin::root(), price, length, delay, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, false)); // Can't open another one if lottery is already present assert_noop!( - Lottery::start_lottery(Origin::root(), price, length, delay, false), + Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, false), Error::::InProgress, ); }); @@ -205,7 +205,7 @@ fn buy_ticket_works_as_simple_passthrough() { // No lottery set up let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 20 })); // This is just a basic transfer then - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); assert_eq!(Balances::free_balance(&1), 100 - 20); assert_eq!(TicketsCount::::get(), 0); @@ -214,11 +214,11 @@ fn buy_ticket_works_as_simple_passthrough() { RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; - assert_ok!(Lottery::set_calls(Origin::root(), calls)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls)); // Ticket price of 60 would kill the user's account - assert_ok!(Lottery::start_lottery(Origin::root(), 60, 10, 5, false)); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 60, 10, 5, false)); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); assert_eq!(Balances::free_balance(&1), 100 - 20 - 20); assert_eq!(TicketsCount::::get(), 0); @@ -226,7 +226,7 @@ fn buy_ticket_works_as_simple_passthrough() { let fail_call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 1000 })); assert_noop!( - Lottery::buy_ticket(Origin::signed(1), fail_call), + Lottery::buy_ticket(RuntimeOrigin::signed(1), fail_call), BalancesError::::InsufficientBalance, ); @@ -235,17 +235,17 @@ fn buy_ticket_works_as_simple_passthrough() { dest: 0, value: 0, })); - assert_noop!(Lottery::buy_ticket(Origin::signed(1), bad_origin_call), BadOrigin,); + assert_noop!(Lottery::buy_ticket(RuntimeOrigin::signed(1), bad_origin_call), BadOrigin,); // User can call other txs, but doesn't get a ticket let remark_call = Box::new(RuntimeCall::System(SystemCall::remark { remark: b"hello, world!".to_vec() })); - assert_ok!(Lottery::buy_ticket(Origin::signed(2), remark_call)); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), remark_call)); assert_eq!(TicketsCount::::get(), 0); let successful_call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 1 })); - assert_ok!(Lottery::buy_ticket(Origin::signed(2), successful_call)); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), successful_call)); assert_eq!(TicketsCount::::get(), 1); }); } @@ -258,40 +258,40 @@ fn buy_ticket_works() { RuntimeCall::System(SystemCall::remark { remark: vec![] }), RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; - assert_ok!(Lottery::set_calls(Origin::root(), calls)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls)); // Can't buy ticket before start let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 1 })); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); assert_eq!(TicketsCount::::get(), 0); // Start lottery - assert_ok!(Lottery::start_lottery(Origin::root(), 1, 20, 5, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 20, 5, false)); // Go to start, buy ticket for transfer run_to_block(5); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call)); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call)); assert_eq!(TicketsCount::::get(), 1); // Can't buy another of the same ticket (even if call is slightly changed) let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 3, value: 30 })); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call)); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call)); assert_eq!(TicketsCount::::get(), 1); // Buy ticket for remark let call = Box::new(RuntimeCall::System(SystemCall::remark { remark: b"hello, world!".to_vec() })); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); assert_eq!(TicketsCount::::get(), 2); // Go to end, can't buy tickets anymore run_to_block(20); - assert_ok!(Lottery::buy_ticket(Origin::signed(2), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), call.clone())); assert_eq!(TicketsCount::::get(), 2); // Go to payout, can't buy tickets when there is no lottery open run_to_block(25); - assert_ok!(Lottery::buy_ticket(Origin::signed(2), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), call.clone())); assert_eq!(TicketsCount::::get(), 0); assert_eq!(LotteryIndex::::get(), 1); }); @@ -303,8 +303,8 @@ fn buy_ticket_works() { fn do_buy_ticket_already_participating() { new_test_ext().execute_with(|| { let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); - assert_ok!(Lottery::start_lottery(Origin::root(), 1, 10, 10, false)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 10, 10, false)); // Buying once works. assert_ok!(Lottery::do_buy_ticket(&1, &calls[0])); @@ -318,15 +318,15 @@ fn do_buy_ticket_already_participating() { fn buy_ticket_already_participating() { new_test_ext().execute_with(|| { let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); - assert_ok!(Lottery::start_lottery(Origin::root(), 1, 10, 10, false)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 10, 10, false)); // Buying once works. let call = Box::new(calls[0].clone()); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); // Buying the same ticket again returns Ok, but changes nothing. - assert_storage_noop!(Lottery::buy_ticket(Origin::signed(1), call).unwrap()); + assert_storage_noop!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call).unwrap()); // Exactly one ticket exists. assert_eq!(TicketsCount::::get(), 1); @@ -338,13 +338,13 @@ fn buy_ticket_already_participating() { fn buy_ticket_insufficient_balance() { new_test_ext().execute_with(|| { let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); // Price set to 100. - assert_ok!(Lottery::start_lottery(Origin::root(), 100, 10, 10, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 100, 10, 10, false)); let call = Box::new(calls[0].clone()); // Buying a ticket returns Ok, but changes nothing. - assert_storage_noop!(Lottery::buy_ticket(Origin::signed(1), call).unwrap()); + assert_storage_noop!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call).unwrap()); assert!(TicketsCount::::get().is_zero()); }); } @@ -353,9 +353,9 @@ fn buy_ticket_insufficient_balance() { fn do_buy_ticket_insufficient_balance() { new_test_ext().execute_with(|| { let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); // Price set to 101. - assert_ok!(Lottery::start_lottery(Origin::root(), 101, 10, 10, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 101, 10, 10, false)); // Buying fails with InsufficientBalance. assert_noop!( @@ -370,9 +370,9 @@ fn do_buy_ticket_insufficient_balance() { fn do_buy_ticket_keep_alive() { new_test_ext().execute_with(|| { let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); // Price set to 100. - assert_ok!(Lottery::start_lottery(Origin::root(), 100, 10, 10, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 100, 10, 10, false)); // Buying fails with KeepAlive. assert_noop!(Lottery::do_buy_ticket(&1, &calls[0]), BalancesError::::KeepAlive); @@ -388,9 +388,9 @@ fn no_participants_works() { let delay = 5; // Set no calls for the lottery. - assert_ok!(Lottery::set_calls(Origin::root(), vec![])); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), vec![])); // Start lottery. - assert_ok!(Lottery::start_lottery(Origin::root(), 10, length, delay, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 10, length, delay, false)); // End the lottery, no one wins. run_to_block(length + delay); @@ -405,7 +405,7 @@ fn start_lottery_will_create_account() { let delay = 5; assert_eq!(Balances::total_balance(&Lottery::account_id()), 0); - assert_ok!(Lottery::start_lottery(Origin::root(), price, length, delay, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, false)); assert_eq!(Balances::total_balance(&Lottery::account_id()), 1); }); } @@ -422,12 +422,12 @@ fn choose_ticket_trivial_cases() { fn choose_account_one_participant() { new_test_ext().execute_with(|| { let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); - assert_ok!(Lottery::start_lottery(Origin::root(), 10, 10, 10, false)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 10, 10, 10, false)); let call = Box::new(calls[0].clone()); // Buy one ticket with account 1. - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call)); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call)); // Account 1 is always the winner. assert_eq!(Lottery::choose_account().unwrap(), 1); }); diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index a3f79ab2052e9..af2f2ddcf42f0 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -59,19 +59,19 @@ pub mod pallet { + IsType<::RuntimeEvent>; /// Required origin for adding a member (though can always be Root). - type AddOrigin: EnsureOrigin; + type AddOrigin: EnsureOrigin; /// Required origin for removing a member (though can always be Root). - type RemoveOrigin: EnsureOrigin; + type RemoveOrigin: EnsureOrigin; /// Required origin for adding and removing a member in a single action. - type SwapOrigin: EnsureOrigin; + type SwapOrigin: EnsureOrigin; /// Required origin for resetting membership. - type ResetOrigin: EnsureOrigin; + type ResetOrigin: EnsureOrigin; /// Required origin for setting or resetting the prime member. - type PrimeOrigin: EnsureOrigin; + type PrimeOrigin: EnsureOrigin; /// The receiver of the signal for when the membership has been initialized. This happens /// pre-genesis and will usually be the same as `MembershipChanged`. If you need to do @@ -543,7 +543,7 @@ mod tests { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -647,13 +647,16 @@ mod tests { #[test] fn prime_member_works() { new_test_ext().execute_with(|| { - assert_noop!(Membership::set_prime(Origin::signed(4), 20), BadOrigin); - assert_noop!(Membership::set_prime(Origin::signed(5), 15), Error::::NotMember); - assert_ok!(Membership::set_prime(Origin::signed(5), 20)); + assert_noop!(Membership::set_prime(RuntimeOrigin::signed(4), 20), BadOrigin); + assert_noop!( + Membership::set_prime(RuntimeOrigin::signed(5), 15), + Error::::NotMember + ); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 20)); assert_eq!(Membership::prime(), Some(20)); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); - assert_ok!(Membership::clear_prime(Origin::signed(5))); + assert_ok!(Membership::clear_prime(RuntimeOrigin::signed(5))); assert_eq!(Membership::prime(), None); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); }); @@ -662,12 +665,12 @@ mod tests { #[test] fn add_member_works() { new_test_ext().execute_with(|| { - assert_noop!(Membership::add_member(Origin::signed(5), 15), BadOrigin); + assert_noop!(Membership::add_member(RuntimeOrigin::signed(5), 15), BadOrigin); assert_noop!( - Membership::add_member(Origin::signed(1), 10), + Membership::add_member(RuntimeOrigin::signed(1), 10), Error::::AlreadyMember ); - assert_ok!(Membership::add_member(Origin::signed(1), 15)); + assert_ok!(Membership::add_member(RuntimeOrigin::signed(1), 15)); assert_eq!(Membership::members(), vec![10, 15, 20, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); }); @@ -676,13 +679,13 @@ mod tests { #[test] fn remove_member_works() { new_test_ext().execute_with(|| { - assert_noop!(Membership::remove_member(Origin::signed(5), 20), BadOrigin); + assert_noop!(Membership::remove_member(RuntimeOrigin::signed(5), 20), BadOrigin); assert_noop!( - Membership::remove_member(Origin::signed(2), 15), + Membership::remove_member(RuntimeOrigin::signed(2), 15), Error::::NotMember ); - assert_ok!(Membership::set_prime(Origin::signed(5), 20)); - assert_ok!(Membership::remove_member(Origin::signed(2), 20)); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 20)); + assert_ok!(Membership::remove_member(RuntimeOrigin::signed(2), 20)); assert_eq!(Membership::members(), vec![10, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), None); @@ -693,24 +696,24 @@ mod tests { #[test] fn swap_member_works() { new_test_ext().execute_with(|| { - assert_noop!(Membership::swap_member(Origin::signed(5), 10, 25), BadOrigin); + assert_noop!(Membership::swap_member(RuntimeOrigin::signed(5), 10, 25), BadOrigin); assert_noop!( - Membership::swap_member(Origin::signed(3), 15, 25), + Membership::swap_member(RuntimeOrigin::signed(3), 15, 25), Error::::NotMember ); assert_noop!( - Membership::swap_member(Origin::signed(3), 10, 30), + Membership::swap_member(RuntimeOrigin::signed(3), 10, 30), Error::::AlreadyMember ); - assert_ok!(Membership::set_prime(Origin::signed(5), 20)); - assert_ok!(Membership::swap_member(Origin::signed(3), 20, 20)); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 20)); + assert_ok!(Membership::swap_member(RuntimeOrigin::signed(3), 20, 20)); assert_eq!(Membership::members(), vec![10, 20, 30]); assert_eq!(Membership::prime(), Some(20)); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); - assert_ok!(Membership::set_prime(Origin::signed(5), 10)); - assert_ok!(Membership::swap_member(Origin::signed(3), 10, 25)); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 10)); + assert_ok!(Membership::swap_member(RuntimeOrigin::signed(3), 10, 25)); assert_eq!(Membership::members(), vec![20, 25, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), None); @@ -721,7 +724,7 @@ mod tests { #[test] fn swap_member_works_that_does_not_change_order() { new_test_ext().execute_with(|| { - assert_ok!(Membership::swap_member(Origin::signed(3), 10, 5)); + assert_ok!(Membership::swap_member(RuntimeOrigin::signed(3), 10, 5)); assert_eq!(Membership::members(), vec![5, 20, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); }); @@ -730,16 +733,16 @@ mod tests { #[test] fn change_key_works() { new_test_ext().execute_with(|| { - assert_ok!(Membership::set_prime(Origin::signed(5), 10)); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 10)); assert_noop!( - Membership::change_key(Origin::signed(3), 25), + Membership::change_key(RuntimeOrigin::signed(3), 25), Error::::NotMember ); assert_noop!( - Membership::change_key(Origin::signed(10), 20), + Membership::change_key(RuntimeOrigin::signed(10), 20), Error::::AlreadyMember ); - assert_ok!(Membership::change_key(Origin::signed(10), 40)); + assert_ok!(Membership::change_key(RuntimeOrigin::signed(10), 40)); assert_eq!(Membership::members(), vec![20, 30, 40]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), Some(40)); @@ -750,7 +753,7 @@ mod tests { #[test] fn change_key_works_that_does_not_change_order() { new_test_ext().execute_with(|| { - assert_ok!(Membership::change_key(Origin::signed(10), 5)); + assert_ok!(Membership::change_key(RuntimeOrigin::signed(10), 5)); assert_eq!(Membership::members(), vec![5, 20, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); }); @@ -759,19 +762,19 @@ mod tests { #[test] fn reset_members_works() { new_test_ext().execute_with(|| { - assert_ok!(Membership::set_prime(Origin::signed(5), 20)); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 20)); assert_noop!( - Membership::reset_members(Origin::signed(1), bounded_vec![20, 40, 30]), + Membership::reset_members(RuntimeOrigin::signed(1), bounded_vec![20, 40, 30]), BadOrigin ); - assert_ok!(Membership::reset_members(Origin::signed(4), vec![20, 40, 30])); + assert_ok!(Membership::reset_members(RuntimeOrigin::signed(4), vec![20, 40, 30])); assert_eq!(Membership::members(), vec![20, 30, 40]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), Some(20)); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); - assert_ok!(Membership::reset_members(Origin::signed(4), vec![10, 40, 30])); + assert_ok!(Membership::reset_members(RuntimeOrigin::signed(4), vec![10, 40, 30])); assert_eq!(Membership::members(), vec![10, 30, 40]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), None); diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index abaa7b106d539..16f0922633088 100644 --- a/frame/merkle-mountain-range/src/mock.rs +++ b/frame/merkle-mountain-range/src/mock.rs @@ -47,7 +47,7 @@ frame_support::construct_runtime!( impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 0c7e931e5ea2e..3bdb47ffc4568 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -122,7 +122,7 @@ pub mod pallet { /// The overarching call type. type RuntimeCall: Parameter - + Dispatchable + + Dispatchable + GetDispatchInfo + From>; diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index 7eb9a9c3aae32..b24a06f454368 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -57,7 +57,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -138,15 +138,15 @@ fn call_transfer(dest: u64, value: u64) -> RuntimeCall { fn multisig_deposit_is_taken_and_returned() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; let data = call.encode(); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -158,7 +158,7 @@ fn multisig_deposit_is_taken_and_returned() { assert_eq!(Balances::reserved_balance(1), 3); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -175,16 +175,16 @@ fn multisig_deposit_is_taken_and_returned() { fn multisig_deposit_is_taken_and_returned_with_call_storage() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -196,7 +196,7 @@ fn multisig_deposit_is_taken_and_returned_with_call_storage() { assert_eq!(Balances::reserved_balance(1), 5); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -212,9 +212,9 @@ fn multisig_deposit_is_taken_and_returned_with_call_storage() { fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 3); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; @@ -222,7 +222,7 @@ fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() { let hash = blake2_256(&data); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -233,7 +233,7 @@ fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() { assert_eq!(Balances::reserved_balance(1), 4); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -247,7 +247,7 @@ fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() { assert_eq!(Balances::reserved_balance(1), 4); assert_ok!(Multisig::approve_as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 3, vec![1, 2], Some(now()), @@ -267,7 +267,7 @@ fn cancel_multisig_returns_deposit() { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -275,7 +275,7 @@ fn cancel_multisig_returns_deposit() { Weight::zero() )); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -284,7 +284,7 @@ fn cancel_multisig_returns_deposit() { )); assert_eq!(Balances::free_balance(1), 6); assert_eq!(Balances::reserved_balance(1), 4); - assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash)); + assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash)); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::reserved_balance(1), 0); }); @@ -294,16 +294,16 @@ fn cancel_multisig_returns_deposit() { fn timepoint_checking_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_noop!( Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -314,7 +314,7 @@ fn timepoint_checking_works() { ); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -324,7 +324,7 @@ fn timepoint_checking_works() { assert_noop!( Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], None, @@ -337,7 +337,7 @@ fn timepoint_checking_works() { let later = Timepoint { index: 1, ..now() }; assert_noop!( Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(later), @@ -354,16 +354,16 @@ fn timepoint_checking_works() { fn multisig_2_of_3_works_with_call_storing() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -374,7 +374,7 @@ fn multisig_2_of_3_works_with_call_storing() { assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -389,16 +389,16 @@ fn multisig_2_of_3_works_with_call_storing() { fn multisig_2_of_3_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -408,7 +408,7 @@ fn multisig_2_of_3_works() { assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -424,16 +424,16 @@ fn multisig_2_of_3_works() { fn multisig_3_of_3_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 3); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -441,7 +441,7 @@ fn multisig_3_of_3_works() { Weight::zero() )); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -451,7 +451,7 @@ fn multisig_3_of_3_works() { assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 3, vec![1, 2], Some(now()), @@ -469,7 +469,7 @@ fn cancel_multisig_works() { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -477,7 +477,7 @@ fn cancel_multisig_works() { Weight::zero() )); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -485,10 +485,10 @@ fn cancel_multisig_works() { Weight::zero() )); assert_noop!( - Multisig::cancel_as_multi(Origin::signed(2), 3, vec![1, 3], now(), hash), + Multisig::cancel_as_multi(RuntimeOrigin::signed(2), 3, vec![1, 3], now(), hash), Error::::NotOwner, ); - assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash),); + assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash),); }); } @@ -498,7 +498,7 @@ fn cancel_multisig_with_call_storage_works() { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -508,7 +508,7 @@ fn cancel_multisig_with_call_storage_works() { )); assert_eq!(Balances::free_balance(1), 4); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -516,10 +516,10 @@ fn cancel_multisig_with_call_storage_works() { Weight::zero() )); assert_noop!( - Multisig::cancel_as_multi(Origin::signed(2), 3, vec![1, 3], now(), hash), + Multisig::cancel_as_multi(RuntimeOrigin::signed(2), 3, vec![1, 3], now(), hash), Error::::NotOwner, ); - assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash),); + assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash),); assert_eq!(Balances::free_balance(1), 10); }); } @@ -530,7 +530,7 @@ fn cancel_multisig_with_alt_call_storage_works() { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -539,7 +539,7 @@ fn cancel_multisig_with_alt_call_storage_works() { )); assert_eq!(Balances::free_balance(1), 6); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -548,7 +548,7 @@ fn cancel_multisig_with_alt_call_storage_works() { Weight::zero() )); assert_eq!(Balances::free_balance(2), 8); - assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash)); + assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash)); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); }); @@ -558,15 +558,15 @@ fn cancel_multisig_with_alt_call_storage_works() { fn multisig_2_of_3_as_multi_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; let data = call.encode(); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -577,7 +577,7 @@ fn multisig_2_of_3_as_multi_works() { assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -593,9 +593,9 @@ fn multisig_2_of_3_as_multi_works() { fn multisig_2_of_3_as_multi_with_many_calls_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call1 = call_transfer(6, 10); let call1_weight = call1.get_dispatch_info().weight; @@ -605,7 +605,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { let data2 = call2.encode(); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -614,7 +614,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { Weight::zero() )); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], None, @@ -623,7 +623,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { Weight::zero() )); assert_ok!(Multisig::as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 2, vec![1, 2], Some(now()), @@ -632,7 +632,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { call1_weight )); assert_ok!(Multisig::as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 2, vec![1, 2], Some(now()), @@ -650,16 +650,16 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { fn multisig_2_of_3_cannot_reissue_same_call() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 10); let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -668,7 +668,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { Weight::zero() )); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -679,7 +679,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { assert_eq!(Balances::free_balance(multi), 5); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -688,7 +688,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { Weight::zero() )); assert_ok!(Multisig::as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 2, vec![1, 2], Some(now()), @@ -717,7 +717,7 @@ fn minimum_threshold_check_works() { let call = call_transfer(6, 15).encode(); assert_noop!( Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 0, vec![2], None, @@ -729,7 +729,7 @@ fn minimum_threshold_check_works() { ); assert_noop!( Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 1, vec![2], None, @@ -748,7 +748,7 @@ fn too_many_signatories_fails() { let call = call_transfer(6, 15).encode(); assert_noop!( Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3, 4], None, @@ -767,7 +767,7 @@ fn duplicate_approvals_are_ignored() { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -776,7 +776,7 @@ fn duplicate_approvals_are_ignored() { )); assert_noop!( Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], Some(now()), @@ -786,7 +786,7 @@ fn duplicate_approvals_are_ignored() { Error::::AlreadyApproved, ); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -795,7 +795,7 @@ fn duplicate_approvals_are_ignored() { )); assert_noop!( Multisig::approve_as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 2, vec![1, 2], Some(now()), @@ -811,15 +811,15 @@ fn duplicate_approvals_are_ignored() { fn multisig_1_of_3_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 1); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_noop!( Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 1, vec![2, 3], None, @@ -830,7 +830,7 @@ fn multisig_1_of_3_works() { ); assert_noop!( Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 1, vec![2, 3], None, @@ -841,7 +841,11 @@ fn multisig_1_of_3_works() { Error::::MinimumThreshold, ); let boxed_call = Box::new(call_transfer(6, 15)); - assert_ok!(Multisig::as_multi_threshold_1(Origin::signed(1), vec![2, 3], boxed_call)); + assert_ok!(Multisig::as_multi_threshold_1( + RuntimeOrigin::signed(1), + vec![2, 3], + boxed_call + )); assert_eq!(Balances::free_balance(6), 15); }); @@ -852,7 +856,7 @@ fn multisig_filters() { new_test_ext().execute_with(|| { let call = Box::new(RuntimeCall::System(frame_system::Call::set_code { code: vec![] })); assert_noop!( - Multisig::as_multi_threshold_1(Origin::signed(1), vec![2], call.clone()), + Multisig::as_multi_threshold_1(RuntimeOrigin::signed(1), vec![2], call.clone()), DispatchError::from(frame_system::Error::::CallFiltered), ); }); @@ -862,14 +866,14 @@ fn multisig_filters() { fn weight_check_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let data = call.encode(); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -881,7 +885,7 @@ fn weight_check_works() { assert_noop!( Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -901,16 +905,16 @@ fn multisig_handles_no_preimage_after_all_approve() { // the call will go through. new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 3); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; let data = call.encode(); let hash = blake2_256(&data); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -918,7 +922,7 @@ fn multisig_handles_no_preimage_after_all_approve() { Weight::zero() )); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -926,7 +930,7 @@ fn multisig_handles_no_preimage_after_all_approve() { Weight::zero() )); assert_ok!(Multisig::approve_as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 3, vec![1, 2], Some(now()), @@ -936,7 +940,7 @@ fn multisig_handles_no_preimage_after_all_approve() { assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 3, vec![1, 2], Some(now()), diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 0ab9a509a568f..953cf39cd12db 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -71,7 +71,7 @@ pub mod pallet { type Slashed: OnUnbalanced>; /// The origin which may forcibly set or remove a name. Root can always do this. - type ForceOrigin: EnsureOrigin; + type ForceOrigin: EnsureOrigin; /// The minimum length a name may be. #[pallet::constant] @@ -280,7 +280,7 @@ mod tests { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -338,9 +338,9 @@ mod tests { #[test] fn kill_name_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); + assert_ok!(Nicks::set_name(RuntimeOrigin::signed(2), b"Dave".to_vec())); assert_eq!(Balances::total_balance(&2), 10); - assert_ok!(Nicks::kill_name(Origin::signed(1), 2)); + assert_ok!(Nicks::kill_name(RuntimeOrigin::signed(1), 2)); assert_eq!(Balances::total_balance(&2), 8); assert_eq!(>::get(2), None); }); @@ -350,17 +350,21 @@ mod tests { fn force_name_should_work() { new_test_ext().execute_with(|| { assert_noop!( - Nicks::set_name(Origin::signed(2), b"Dr. David Brubeck, III".to_vec()), + Nicks::set_name(RuntimeOrigin::signed(2), b"Dr. David Brubeck, III".to_vec()), Error::::TooLong, ); - assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); + assert_ok!(Nicks::set_name(RuntimeOrigin::signed(2), b"Dave".to_vec())); assert_eq!(Balances::reserved_balance(2), 2); assert_noop!( - Nicks::force_name(Origin::signed(1), 2, b"Dr. David Brubeck, III".to_vec()), + Nicks::force_name(RuntimeOrigin::signed(1), 2, b"Dr. David Brubeck, III".to_vec()), Error::::TooLong, ); - assert_ok!(Nicks::force_name(Origin::signed(1), 2, b"Dr. Brubeck, III".to_vec())); + assert_ok!(Nicks::force_name( + RuntimeOrigin::signed(1), + 2, + b"Dr. Brubeck, III".to_vec() + )); assert_eq!(Balances::reserved_balance(2), 2); let (name, amount) = >::get(2).unwrap(); assert_eq!(name, b"Dr. Brubeck, III".to_vec()); @@ -371,17 +375,17 @@ mod tests { #[test] fn normal_operation_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Nicks::set_name(Origin::signed(1), b"Gav".to_vec())); + assert_ok!(Nicks::set_name(RuntimeOrigin::signed(1), b"Gav".to_vec())); assert_eq!(Balances::reserved_balance(1), 2); assert_eq!(Balances::free_balance(1), 8); assert_eq!(>::get(1).unwrap().0, b"Gav".to_vec()); - assert_ok!(Nicks::set_name(Origin::signed(1), b"Gavin".to_vec())); + assert_ok!(Nicks::set_name(RuntimeOrigin::signed(1), b"Gavin".to_vec())); assert_eq!(Balances::reserved_balance(1), 2); assert_eq!(Balances::free_balance(1), 8); assert_eq!(>::get(1).unwrap().0, b"Gavin".to_vec()); - assert_ok!(Nicks::clear_name(Origin::signed(1))); + assert_ok!(Nicks::clear_name(RuntimeOrigin::signed(1))); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::free_balance(1), 10); }); @@ -390,24 +394,27 @@ mod tests { #[test] fn error_catching_should_work() { new_test_ext().execute_with(|| { - assert_noop!(Nicks::clear_name(Origin::signed(1)), Error::::Unnamed); + assert_noop!(Nicks::clear_name(RuntimeOrigin::signed(1)), Error::::Unnamed); assert_noop!( - Nicks::set_name(Origin::signed(3), b"Dave".to_vec()), + Nicks::set_name(RuntimeOrigin::signed(3), b"Dave".to_vec()), pallet_balances::Error::::InsufficientBalance ); assert_noop!( - Nicks::set_name(Origin::signed(1), b"Ga".to_vec()), + Nicks::set_name(RuntimeOrigin::signed(1), b"Ga".to_vec()), Error::::TooShort ); assert_noop!( - Nicks::set_name(Origin::signed(1), b"Gavin James Wood, Esquire".to_vec()), + Nicks::set_name(RuntimeOrigin::signed(1), b"Gavin James Wood, Esquire".to_vec()), Error::::TooLong ); - assert_ok!(Nicks::set_name(Origin::signed(1), b"Dave".to_vec())); - assert_noop!(Nicks::kill_name(Origin::signed(2), 1), BadOrigin); - assert_noop!(Nicks::force_name(Origin::signed(2), 1, b"Whatever".to_vec()), BadOrigin); + assert_ok!(Nicks::set_name(RuntimeOrigin::signed(1), b"Dave".to_vec())); + assert_noop!(Nicks::kill_name(RuntimeOrigin::signed(2), 1), BadOrigin); + assert_noop!( + Nicks::force_name(RuntimeOrigin::signed(2), 1, b"Whatever".to_vec()), + BadOrigin + ); }); } } diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 42f1fcf7b55e6..638a96eb3321a 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -78,16 +78,16 @@ pub mod pallet { type MaxPeerIdLength: Get; /// The origin which can add a well known node. - type AddOrigin: EnsureOrigin; + type AddOrigin: EnsureOrigin; /// The origin which can remove a well known node. - type RemoveOrigin: EnsureOrigin; + type RemoveOrigin: EnsureOrigin; /// The origin which can swap the well known nodes. - type SwapOrigin: EnsureOrigin; + type SwapOrigin: EnsureOrigin; /// The origin which can reset the well known nodes. - type ResetOrigin: EnsureOrigin; + type ResetOrigin: EnsureOrigin; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; diff --git a/frame/node-authorization/src/mock.rs b/frame/node-authorization/src/mock.rs index 448f8cef80e28..fcf7ff0189332 100644 --- a/frame/node-authorization/src/mock.rs +++ b/frame/node-authorization/src/mock.rs @@ -52,7 +52,7 @@ impl frame_system::Config for Test { type DbWeight = (); type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/frame/node-authorization/src/tests.rs b/frame/node-authorization/src/tests.rs index ba78d14912133..d9db09db4f46f 100644 --- a/frame/node-authorization/src/tests.rs +++ b/frame/node-authorization/src/tests.rs @@ -26,19 +26,27 @@ use sp_runtime::traits::BadOrigin; fn add_well_known_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(2), test_node(15), 15), + NodeAuthorization::add_well_known_node(RuntimeOrigin::signed(2), test_node(15), 15), BadOrigin ); assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(1), PeerId(vec![1, 2, 3]), 15), + NodeAuthorization::add_well_known_node( + RuntimeOrigin::signed(1), + PeerId(vec![1, 2, 3]), + 15 + ), Error::::PeerIdTooLong ); assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(20), 20), + NodeAuthorization::add_well_known_node(RuntimeOrigin::signed(1), test_node(20), 20), Error::::AlreadyJoined ); - assert_ok!(NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(15), 15)); + assert_ok!(NodeAuthorization::add_well_known_node( + RuntimeOrigin::signed(1), + test_node(15), + 15 + )); assert_eq!( WellKnownNodes::::get(), BTreeSet::from_iter(vec![test_node(10), test_node(15), test_node(20), test_node(30)]) @@ -49,7 +57,7 @@ fn add_well_known_node_works() { assert_eq!(Owners::::get(test_node(15)), Some(15)); assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(25), 25), + NodeAuthorization::add_well_known_node(RuntimeOrigin::signed(1), test_node(25), 25), Error::::TooManyNodes ); }); @@ -59,15 +67,18 @@ fn add_well_known_node_works() { fn remove_well_known_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::remove_well_known_node(Origin::signed(3), test_node(20)), + NodeAuthorization::remove_well_known_node(RuntimeOrigin::signed(3), test_node(20)), BadOrigin ); assert_noop!( - NodeAuthorization::remove_well_known_node(Origin::signed(2), PeerId(vec![1, 2, 3])), + NodeAuthorization::remove_well_known_node( + RuntimeOrigin::signed(2), + PeerId(vec![1, 2, 3]) + ), Error::::PeerIdTooLong ); assert_noop!( - NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(40)), + NodeAuthorization::remove_well_known_node(RuntimeOrigin::signed(2), test_node(40)), Error::::NotExist ); @@ -77,7 +88,10 @@ fn remove_well_known_node_works() { ); assert!(AdditionalConnections::::contains_key(test_node(20))); - assert_ok!(NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(20))); + assert_ok!(NodeAuthorization::remove_well_known_node( + RuntimeOrigin::signed(2), + test_node(20) + )); assert_eq!( WellKnownNodes::::get(), BTreeSet::from_iter(vec![test_node(10), test_node(30)]) @@ -91,12 +105,16 @@ fn remove_well_known_node_works() { fn swap_well_known_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::swap_well_known_node(Origin::signed(4), test_node(20), test_node(5)), + NodeAuthorization::swap_well_known_node( + RuntimeOrigin::signed(4), + test_node(20), + test_node(5) + ), BadOrigin ); assert_noop!( NodeAuthorization::swap_well_known_node( - Origin::signed(3), + RuntimeOrigin::signed(3), PeerId(vec![1, 2, 3]), test_node(20) ), @@ -104,7 +122,7 @@ fn swap_well_known_node_works() { ); assert_noop!( NodeAuthorization::swap_well_known_node( - Origin::signed(3), + RuntimeOrigin::signed(3), test_node(20), PeerId(vec![1, 2, 3]) ), @@ -112,7 +130,7 @@ fn swap_well_known_node_works() { ); assert_ok!(NodeAuthorization::swap_well_known_node( - Origin::signed(3), + RuntimeOrigin::signed(3), test_node(20), test_node(20) )); @@ -122,12 +140,16 @@ fn swap_well_known_node_works() { ); assert_noop!( - NodeAuthorization::swap_well_known_node(Origin::signed(3), test_node(15), test_node(5)), + NodeAuthorization::swap_well_known_node( + RuntimeOrigin::signed(3), + test_node(15), + test_node(5) + ), Error::::NotExist ); assert_noop!( NodeAuthorization::swap_well_known_node( - Origin::signed(3), + RuntimeOrigin::signed(3), test_node(20), test_node(30) ), @@ -139,7 +161,7 @@ fn swap_well_known_node_works() { BTreeSet::from_iter(vec![test_node(15)]), ); assert_ok!(NodeAuthorization::swap_well_known_node( - Origin::signed(3), + RuntimeOrigin::signed(3), test_node(20), test_node(5) )); @@ -162,14 +184,14 @@ fn reset_well_known_nodes_works() { new_test_ext().execute_with(|| { assert_noop!( NodeAuthorization::reset_well_known_nodes( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![(test_node(15), 15), (test_node(5), 5), (test_node(20), 20)] ), BadOrigin ); assert_noop!( NodeAuthorization::reset_well_known_nodes( - Origin::signed(4), + RuntimeOrigin::signed(4), vec![ (test_node(15), 15), (test_node(5), 5), @@ -181,7 +203,7 @@ fn reset_well_known_nodes_works() { ); assert_ok!(NodeAuthorization::reset_well_known_nodes( - Origin::signed(4), + RuntimeOrigin::signed(4), vec![(test_node(15), 15), (test_node(5), 5), (test_node(20), 20)] )); assert_eq!( @@ -198,15 +220,15 @@ fn reset_well_known_nodes_works() { fn claim_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::claim_node(Origin::signed(1), PeerId(vec![1, 2, 3])), + NodeAuthorization::claim_node(RuntimeOrigin::signed(1), PeerId(vec![1, 2, 3])), Error::::PeerIdTooLong ); assert_noop!( - NodeAuthorization::claim_node(Origin::signed(1), test_node(20)), + NodeAuthorization::claim_node(RuntimeOrigin::signed(1), test_node(20)), Error::::AlreadyClaimed ); - assert_ok!(NodeAuthorization::claim_node(Origin::signed(15), test_node(15))); + assert_ok!(NodeAuthorization::claim_node(RuntimeOrigin::signed(15), test_node(15))); assert_eq!(Owners::::get(test_node(15)), Some(15)); }); } @@ -215,21 +237,21 @@ fn claim_node_works() { fn remove_claim_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(15), PeerId(vec![1, 2, 3])), + NodeAuthorization::remove_claim(RuntimeOrigin::signed(15), PeerId(vec![1, 2, 3])), Error::::PeerIdTooLong ); assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(15), test_node(15)), + NodeAuthorization::remove_claim(RuntimeOrigin::signed(15), test_node(15)), Error::::NotClaimed ); assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(15), test_node(20)), + NodeAuthorization::remove_claim(RuntimeOrigin::signed(15), test_node(20)), Error::::NotOwner ); assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(20), test_node(20)), + NodeAuthorization::remove_claim(RuntimeOrigin::signed(20), test_node(20)), Error::::PermissionDenied ); @@ -238,7 +260,7 @@ fn remove_claim_works() { test_node(15), BTreeSet::from_iter(vec![test_node(20)]), ); - assert_ok!(NodeAuthorization::remove_claim(Origin::signed(15), test_node(15))); + assert_ok!(NodeAuthorization::remove_claim(RuntimeOrigin::signed(15), test_node(15))); assert!(!Owners::::contains_key(test_node(15))); assert!(!AdditionalConnections::::contains_key(test_node(15))); }); @@ -248,20 +270,20 @@ fn remove_claim_works() { fn transfer_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::transfer_node(Origin::signed(15), PeerId(vec![1, 2, 3]), 10), + NodeAuthorization::transfer_node(RuntimeOrigin::signed(15), PeerId(vec![1, 2, 3]), 10), Error::::PeerIdTooLong ); assert_noop!( - NodeAuthorization::transfer_node(Origin::signed(15), test_node(15), 10), + NodeAuthorization::transfer_node(RuntimeOrigin::signed(15), test_node(15), 10), Error::::NotClaimed ); assert_noop!( - NodeAuthorization::transfer_node(Origin::signed(15), test_node(20), 10), + NodeAuthorization::transfer_node(RuntimeOrigin::signed(15), test_node(20), 10), Error::::NotOwner ); - assert_ok!(NodeAuthorization::transfer_node(Origin::signed(20), test_node(20), 15)); + assert_ok!(NodeAuthorization::transfer_node(RuntimeOrigin::signed(20), test_node(20), 15)); assert_eq!(Owners::::get(test_node(20)), Some(15)); }); } @@ -271,7 +293,7 @@ fn add_connections_works() { new_test_ext().execute_with(|| { assert_noop!( NodeAuthorization::add_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), PeerId(vec![1, 2, 3]), vec![test_node(5)] ), @@ -279,7 +301,7 @@ fn add_connections_works() { ); assert_noop!( NodeAuthorization::add_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), test_node(15), vec![test_node(5)] ), @@ -288,7 +310,7 @@ fn add_connections_works() { assert_noop!( NodeAuthorization::add_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), test_node(20), vec![test_node(5)] ), @@ -296,7 +318,7 @@ fn add_connections_works() { ); assert_ok!(NodeAuthorization::add_connections( - Origin::signed(20), + RuntimeOrigin::signed(20), test_node(20), vec![test_node(15), test_node(5), test_node(25), test_node(20)] )); @@ -312,7 +334,7 @@ fn remove_connections_works() { new_test_ext().execute_with(|| { assert_noop!( NodeAuthorization::remove_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), PeerId(vec![1, 2, 3]), vec![test_node(5)] ), @@ -320,7 +342,7 @@ fn remove_connections_works() { ); assert_noop!( NodeAuthorization::remove_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), test_node(15), vec![test_node(5)] ), @@ -329,7 +351,7 @@ fn remove_connections_works() { assert_noop!( NodeAuthorization::remove_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), test_node(20), vec![test_node(5)] ), @@ -341,7 +363,7 @@ fn remove_connections_works() { BTreeSet::from_iter(vec![test_node(5), test_node(15), test_node(25)]), ); assert_ok!(NodeAuthorization::remove_connections( - Origin::signed(20), + RuntimeOrigin::signed(20), test_node(20), vec![test_node(15), test_node(5)] )); diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 18b081367d135..040a9fa8e828e 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -26,7 +26,7 @@ mod mock; use frame_benchmarking::{account, frame_support::traits::Currency, vec, whitelist_account, Vec}; use frame_election_provider_support::SortedListProvider; use frame_support::{assert_ok, ensure, traits::Get}; -use frame_system::RawOrigin as Origin; +use frame_system::RawOrigin as RuntimeOrigin; use pallet_nomination_pools::{ BalanceOf, BondExtra, BondedPoolInner, BondedPools, ConfigOp, MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, Pallet as Pools, @@ -80,7 +80,7 @@ fn create_pool_account( let pool_creator_lookup = T::Lookup::unlookup(pool_creator.clone()); Pools::::create( - Origin::Signed(pool_creator.clone()).into(), + RuntimeOrigin::Signed(pool_creator.clone()).into(), balance, pool_creator_lookup.clone(), pool_creator_lookup.clone(), @@ -203,7 +203,7 @@ impl ListScenario { maybe_pool.as_mut().map(|pool| pool.points -= amount) }); - Pools::::join(Origin::Signed(joiner.clone()).into(), amount, 1).unwrap(); + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), amount, 1).unwrap(); // check that the vote weight is still the same as the original bonded let weight_of = pallet_staking::Pallet::::weight_of_fn(); @@ -236,7 +236,7 @@ frame_benchmarking::benchmarks! { = create_funded_user_with_balance::("joiner", 0, joiner_free); whitelist_account!(joiner); - }: _(Origin::Signed(joiner.clone()), max_additional, 1) + }: _(RuntimeOrigin::Signed(joiner.clone()), max_additional, 1) verify { assert_eq!(CurrencyOf::::free_balance(&joiner), joiner_free - max_additional); assert_eq!( @@ -252,7 +252,7 @@ frame_benchmarking::benchmarks! { // creator of the src pool will bond-extra, bumping itself to dest bag. - }: bond_extra(Origin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) + }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) verify { assert!( T::StakingInterface::active_stake(&scenario.origin1).unwrap() >= @@ -270,7 +270,7 @@ frame_benchmarking::benchmarks! { assert!(extra >= CurrencyOf::::minimum_balance()); CurrencyOf::::deposit_creating(&reward_account1, extra); - }: bond_extra(Origin::Signed(scenario.creator1.clone()), BondExtra::Rewards) + }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::Rewards) verify { assert!( T::StakingInterface::active_stake(&scenario.origin1).unwrap() >= @@ -294,7 +294,7 @@ frame_benchmarking::benchmarks! { ); whitelist_account!(depositor); - }:_(Origin::Signed(depositor.clone())) + }:_(RuntimeOrigin::Signed(depositor.clone())) verify { assert_eq!( CurrencyOf::::free_balance(&depositor), @@ -318,7 +318,7 @@ frame_benchmarking::benchmarks! { let member_id_lookup = T::Lookup::unlookup(member_id.clone()); let all_points = PoolMembers::::get(&member_id).unwrap().points; whitelist_account!(member_id); - }: _(Origin::Signed(member_id.clone()), member_id_lookup, all_points) + }: _(RuntimeOrigin::Signed(member_id.clone()), member_id_lookup, all_points) verify { let bonded_after = T::StakingInterface::active_stake(&scenario.origin1).unwrap(); // We at least went down to the destination bag @@ -346,7 +346,7 @@ frame_benchmarking::benchmarks! { // Add a new member let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); - Pools::::join(Origin::Signed(joiner.clone()).into(), min_join_bond, 1) + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) .unwrap(); // Sanity check join worked @@ -357,7 +357,7 @@ frame_benchmarking::benchmarks! { assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); // Unbond the new member - Pools::::fully_unbond(Origin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); + Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); // Sanity check that unbond worked assert_eq!( @@ -371,7 +371,7 @@ frame_benchmarking::benchmarks! { // Add `s` count of slashing spans to storage. pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); whitelist_account!(pool_account); - }: _(Origin::Signed(pool_account.clone()), 1, s) + }: _(RuntimeOrigin::Signed(pool_account.clone()), 1, s) verify { // The joiners funds didn't change assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); @@ -389,7 +389,7 @@ frame_benchmarking::benchmarks! { let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); let joiner_lookup = T::Lookup::unlookup(joiner.clone()); - Pools::::join(Origin::Signed(joiner.clone()).into(), min_join_bond, 1) + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) .unwrap(); // Sanity check join worked @@ -401,7 +401,7 @@ frame_benchmarking::benchmarks! { // Unbond the new member pallet_staking::CurrentEra::::put(0); - Pools::::fully_unbond(Origin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); + Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); // Sanity check that unbond worked assert_eq!( @@ -415,7 +415,7 @@ frame_benchmarking::benchmarks! { pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); whitelist_account!(joiner); - }: withdraw_unbonded(Origin::Signed(joiner.clone()), joiner_lookup, s) + }: withdraw_unbonded(RuntimeOrigin::Signed(joiner.clone()), joiner_lookup, s) verify { assert_eq!( CurrencyOf::::free_balance(&joiner), @@ -448,7 +448,7 @@ frame_benchmarking::benchmarks! { // up when unbonding. let reward_account = Pools::::create_reward_account(1); assert!(frame_system::Account::::contains_key(&reward_account)); - Pools::::fully_unbond(Origin::Signed(depositor.clone()).into(), depositor.clone()).unwrap(); + Pools::::fully_unbond(RuntimeOrigin::Signed(depositor.clone()).into(), depositor.clone()).unwrap(); // Sanity check that unbond worked assert_eq!( @@ -473,7 +473,7 @@ frame_benchmarking::benchmarks! { assert!(frame_system::Account::::contains_key(&reward_account)); whitelist_account!(depositor); - }: withdraw_unbonded(Origin::Signed(depositor.clone()), depositor_lookup, s) + }: withdraw_unbonded(RuntimeOrigin::Signed(depositor.clone()), depositor_lookup, s) verify { // Pool removal worked assert!(!pallet_staking::Ledger::::contains_key(&pool_account)); @@ -506,7 +506,7 @@ frame_benchmarking::benchmarks! { whitelist_account!(depositor); }: _( - Origin::Signed(depositor.clone()), + RuntimeOrigin::Signed(depositor.clone()), min_create_bond, depositor_lookup.clone(), depositor_lookup.clone(), @@ -550,7 +550,7 @@ frame_benchmarking::benchmarks! { .collect(); whitelist_account!(depositor); - }:_(Origin::Signed(depositor.clone()), 1, validators) + }:_(RuntimeOrigin::Signed(depositor.clone()), 1, validators) verify { assert_eq!(RewardPools::::count(), 1); assert_eq!(BondedPools::::count(), 1); @@ -586,7 +586,7 @@ frame_benchmarking::benchmarks! { let caller = account("caller", 0, USER_SEED); whitelist_account!(caller); - }:_(Origin::Signed(caller), 1, PoolState::Destroying) + }:_(RuntimeOrigin::Signed(caller), 1, PoolState::Destroying) verify { assert_eq!(BondedPools::::get(1).unwrap().state, PoolState::Destroying); } @@ -601,14 +601,14 @@ frame_benchmarking::benchmarks! { let metadata: Vec = (0..n).map(|_| 42).collect(); whitelist_account!(depositor); - }:_(Origin::Signed(depositor), 1, metadata.clone()) + }:_(RuntimeOrigin::Signed(depositor), 1, metadata.clone()) verify { assert_eq!(Metadata::::get(&1), metadata); } set_configs { }:_( - Origin::Root, + RuntimeOrigin::Root, ConfigOp::Set(BalanceOf::::max_value()), ConfigOp::Set(BalanceOf::::max_value()), ConfigOp::Set(u32::MAX), @@ -627,7 +627,7 @@ frame_benchmarking::benchmarks! { let (root, _) = create_pool_account::(0, min_create_bond::() * 2u32.into()); let random: T::AccountId = account("but is anything really random in computers..?", 0, USER_SEED); }:_( - Origin::Signed(root.clone()), + RuntimeOrigin::Signed(root.clone()), first_id, ConfigOp::Set(random.clone()), ConfigOp::Set(random.clone()), @@ -653,11 +653,11 @@ frame_benchmarking::benchmarks! { .map(|i| account("stash", USER_SEED, i)) .collect(); - assert_ok!(Pools::::nominate(Origin::Signed(depositor.clone()).into(), 1, validators)); + assert_ok!(Pools::::nominate(RuntimeOrigin::Signed(depositor.clone()).into(), 1, validators)); assert!(T::StakingInterface::nominations(Pools::::create_bonded_account(1)).is_some()); whitelist_account!(depositor); - }:_(Origin::Signed(depositor.clone()), 1) + }:_(RuntimeOrigin::Signed(depositor.clone()), 1) verify { assert!(T::StakingInterface::nominations(Pools::::create_bonded_account(1)).is_none()); } diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 2dcac34d39a11..7841686114dfd 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -33,7 +33,7 @@ impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index 4d78f2fa76c96..b73141c95f72c 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -119,7 +119,7 @@ pub mod v2 { ExtBuilder::default().build_and_execute(|| { let join = |x| { Balances::make_free_balance_be(&x, Balances::minimum_balance() + 10); - frame_support::assert_ok!(Pools::join(Origin::signed(x), 10, 1)); + frame_support::assert_ok!(Pools::join(RuntimeOrigin::signed(x), 10, 1)); }; assert_eq!(BondedPool::::get(1).unwrap().points, 10); diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 13df09c47fa92..1b3372dae56ee 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -128,7 +128,7 @@ impl sp_staking::StakingInterface for StakingMock { impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; @@ -291,7 +291,7 @@ impl ExtBuilder { let amount_to_bond = Pools::depositor_min_bond(); Balances::make_free_balance_be(&10, amount_to_bond * 5); assert_ok!(Pools::create(RawOrigin::Signed(10).into(), amount_to_bond, 900, 901, 902)); - assert_ok!(Pools::set_metadata(Origin::signed(900), 1, vec![1, 1])); + assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(900), 1, vec![1, 1])); let last_pool = LastPoolId::::get(); for (account_id, bonded) in self.members { Balances::make_free_balance_be(&account_id, bonded * 2); @@ -353,7 +353,7 @@ pub fn fully_unbond_permissioned(member: AccountId) -> DispatchResult { let points = PoolMembers::::get(&member) .map(|d| d.active_points()) .unwrap_or_default(); - Pools::unbond(Origin::signed(member), member, points) + Pools::unbond(RuntimeOrigin::signed(member), member, points) } #[cfg(test)] diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index bcc735a9cef99..7b8d14164d63f 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -443,7 +443,7 @@ mod join { assert!(!PoolMembers::::contains_key(&11)); // When - assert_ok!(Pools::join(Origin::signed(11), 2, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(11), 2, 1)); // Then @@ -471,7 +471,7 @@ mod join { assert!(!PoolMembers::::contains_key(&12)); // When - assert_ok!(Pools::join(Origin::signed(12), 12, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(12), 12, 1)); // Then assert_eq!( @@ -494,15 +494,21 @@ mod join { assert_eq!(PoolMembers::::get(&10).unwrap().pool_id, 1); assert_noop!( - Pools::join(Origin::signed(10), 420, 123), + Pools::join(RuntimeOrigin::signed(10), 420, 123), Error::::AccountBelongsToOtherPool ); - assert_noop!(Pools::join(Origin::signed(11), 420, 123), Error::::PoolNotFound); + assert_noop!( + Pools::join(RuntimeOrigin::signed(11), 420, 123), + Error::::PoolNotFound + ); // Force the pools bonded balance to 0, simulating a 100% slash StakingMock::set_bonded_balance(Pools::create_bonded_account(1), 0); - assert_noop!(Pools::join(Origin::signed(11), 420, 1), Error::::OverflowRisk); + assert_noop!( + Pools::join(RuntimeOrigin::signed(11), 420, 1), + Error::::OverflowRisk + ); // Given a mocked bonded pool BondedPool:: { @@ -527,27 +533,33 @@ mod join { Pools::create_bonded_account(123), max_points_to_balance, ); - assert_noop!(Pools::join(Origin::signed(11), 420, 123), Error::::OverflowRisk); + assert_noop!( + Pools::join(RuntimeOrigin::signed(11), 420, 123), + Error::::OverflowRisk + ); StakingMock::set_bonded_balance( Pools::create_bonded_account(123), Balance::MAX / max_points_to_balance, ); // Balance needs to be gt Balance::MAX / `MaxPointsToBalance` - assert_noop!(Pools::join(Origin::signed(11), 5, 123), Error::::OverflowRisk); + assert_noop!( + Pools::join(RuntimeOrigin::signed(11), 5, 123), + Error::::OverflowRisk + ); StakingMock::set_bonded_balance(Pools::create_bonded_account(1), max_points_to_balance); // Cannot join a pool that isn't open unsafe_set_state(123, PoolState::Blocked); assert_noop!( - Pools::join(Origin::signed(11), max_points_to_balance, 123), + Pools::join(RuntimeOrigin::signed(11), max_points_to_balance, 123), Error::::NotOpen ); unsafe_set_state(123, PoolState::Destroying); assert_noop!( - Pools::join(Origin::signed(11), max_points_to_balance, 123), + Pools::join(RuntimeOrigin::signed(11), max_points_to_balance, 123), Error::::NotOpen ); @@ -556,7 +568,7 @@ mod join { // Then assert_noop!( - Pools::join(Origin::signed(11), 99, 123), + Pools::join(RuntimeOrigin::signed(11), 99, 123), Error::::MinimumBondNotMet ); }); @@ -578,7 +590,7 @@ mod join { }, } .put(); - let _ = Pools::join(Origin::signed(11), 420, 123); + let _ = Pools::join(RuntimeOrigin::signed(11), 420, 123); }); } @@ -591,7 +603,7 @@ mod join { let account = i + 100; Balances::make_free_balance_be(&account, 100 + Balances::minimum_balance()); - assert_ok!(Pools::join(Origin::signed(account), 100, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(account), 100, 1)); } Balances::make_free_balance_be(&103, 100 + Balances::minimum_balance()); @@ -608,7 +620,7 @@ mod join { ); assert_noop!( - Pools::join(Origin::signed(103), 100, 1), + Pools::join(RuntimeOrigin::signed(103), 100, 1), Error::::MaxPoolMembers ); @@ -617,7 +629,7 @@ mod join { assert_eq!(MaxPoolMembers::::get(), Some(4)); Balances::make_free_balance_be(&104, 100 + Balances::minimum_balance()); - assert_ok!(Pools::create(Origin::signed(104), 100, 104, 104, 104)); + assert_ok!(Pools::create(RuntimeOrigin::signed(104), 100, 104, 104, 104)); let pool_account = BondedPools::::iter() .find(|(_, bonded_pool)| bonded_pool.roles.depositor == 104) @@ -634,7 +646,7 @@ mod join { ); assert_noop!( - Pools::join(Origin::signed(103), 100, pool_account), + Pools::join(RuntimeOrigin::signed(103), 100, pool_account), Error::::MaxPoolMembers ); }); @@ -692,7 +704,7 @@ mod claim_payout { let _ = pool_events_since_last_call(); // When - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then assert_eq!( @@ -708,7 +720,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 90); // When - assert_ok!(Pools::claim_payout(Origin::signed(40))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(40))); // Then assert_eq!( @@ -721,7 +733,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 50); // When - assert_ok!(Pools::claim_payout(Origin::signed(50))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(50))); // Then assert_eq!( @@ -737,7 +749,7 @@ mod claim_payout { assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); // When - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then assert_eq!( @@ -750,7 +762,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 45); // When - assert_ok!(Pools::claim_payout(Origin::signed(40))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(40))); // Then assert_eq!( @@ -767,7 +779,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 75); // When - assert_ok!(Pools::claim_payout(Origin::signed(50))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(50))); // Then assert_eq!( @@ -780,7 +792,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); // When - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then assert_eq!( @@ -797,7 +809,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 420); // When - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then assert_eq!( @@ -816,7 +828,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 400); // When - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then assert_eq!( @@ -829,7 +841,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 398); // When - assert_ok!(Pools::claim_payout(Origin::signed(40))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(40))); // Then assert_eq!( @@ -842,7 +854,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 210); // When - assert_ok!(Pools::claim_payout(Origin::signed(50))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(50))); // Then assert_eq!( @@ -862,7 +874,10 @@ mod claim_payout { // fully unbond the member. assert_ok!(fully_unbond_permissioned(11)); - assert_noop!(Pools::claim_payout(Origin::signed(11)), Error::::FullyUnbonding); + assert_noop!( + Pools::claim_payout(RuntimeOrigin::signed(11)), + Error::::FullyUnbonding + ); assert_eq!( pool_events_since_last_call(), @@ -1141,14 +1156,14 @@ mod claim_payout { // 20 joins afterwards. Balances::make_free_balance_be(&20, Balances::minimum_balance() + 10); - assert_ok!(Pools::join(Origin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); // reward by another 20 Balances::mutate_account(&default_reward_account(), |f| f.free += 20).unwrap(); // 10 should claim 10 + 10, 20 should claim 20 / 2. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), vec![ @@ -1163,8 +1178,8 @@ mod claim_payout { // any upcoming rewards are shared equally. Balances::mutate_account(&default_reward_account(), |f| f.free += 20).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1184,13 +1199,13 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 3).unwrap(); Balances::make_free_balance_be(&20, Balances::minimum_balance() + 10); - assert_ok!(Pools::join(Origin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); Balances::mutate_account(&default_reward_account(), |f| f.free += 6).unwrap(); // 10 should claim 3, 20 should claim 3 + 3. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1206,8 +1221,8 @@ mod claim_payout { // any upcoming rewards are shared equally. Balances::mutate_account(&default_reward_account(), |f| f.free += 8).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1220,8 +1235,8 @@ mod claim_payout { // uneven upcoming rewards are shared equally, rounded down. Balances::mutate_account(&default_reward_account(), |f| f.free += 7).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1241,19 +1256,19 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); Balances::make_free_balance_be(&20, ed + 10); - assert_ok!(Pools::join(Origin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); Balances::make_free_balance_be(&30, ed + 10); - assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); // 10 should claim 10, 20 should claim nothing. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1271,9 +1286,9 @@ mod claim_payout { // any upcoming rewards are shared equally. Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1297,7 +1312,7 @@ mod claim_payout { assert_eq!(Pools::pending_rewards(20), None); Balances::make_free_balance_be(&20, ed + 10); - assert_ok!(Pools::join(Origin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); assert_eq!(Pools::pending_rewards(10), Some(30)); assert_eq!(Pools::pending_rewards(20), Some(0)); @@ -1309,7 +1324,7 @@ mod claim_payout { assert_eq!(Pools::pending_rewards(30), None); Balances::make_free_balance_be(&30, ed + 10); - assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); assert_eq!(Pools::pending_rewards(10), Some(30 + 50)); assert_eq!(Pools::pending_rewards(20), Some(50)); @@ -1322,17 +1337,17 @@ mod claim_payout { assert_eq!(Pools::pending_rewards(30), Some(20)); // 10 should claim 10, 20 should claim nothing. - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!(Pools::pending_rewards(10), Some(0)); assert_eq!(Pools::pending_rewards(20), Some(50 + 20)); assert_eq!(Pools::pending_rewards(30), Some(20)); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!(Pools::pending_rewards(10), Some(0)); assert_eq!(Pools::pending_rewards(20), Some(0)); assert_eq!(Pools::pending_rewards(30), Some(20)); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!(Pools::pending_rewards(10), Some(0)); assert_eq!(Pools::pending_rewards(20), Some(0)); assert_eq!(Pools::pending_rewards(30), Some(0)); @@ -1345,16 +1360,16 @@ mod claim_payout { let ed = Balances::minimum_balance(); Balances::make_free_balance_be(&20, ed + 20); - assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); Balances::make_free_balance_be(&30, ed + 20); - assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); // everyone claims. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1370,14 +1385,14 @@ mod claim_payout { ); // 30 now bumps itself to be like 20. - assert_ok!(Pools::bond_extra(Origin::signed(30), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(30), BondExtra::FreeBalance(10))); // more rewards come in. Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1397,13 +1412,13 @@ mod claim_payout { let ed = Balances::minimum_balance(); Balances::make_free_balance_be(&20, ed + 20); - assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); // everyone claims. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1417,13 +1432,13 @@ mod claim_payout { ); // 20 unbonds to be equal to 10 (10 points each). - assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); // more rewards come in. Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1442,16 +1457,16 @@ mod claim_payout { let ed = Balances::minimum_balance(); Balances::make_free_balance_be(&20, ed + 20); - assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); Balances::make_free_balance_be(&30, ed + 20); - assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); // 10 gets 10, 20 gets 20, 30 gets 10 Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); // some claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1469,8 +1484,8 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 80).unwrap(); // some claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1484,8 +1499,8 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 80).unwrap(); // some claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1496,7 +1511,7 @@ mod claim_payout { ); // now 30 claims all at once - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1511,13 +1526,13 @@ mod claim_payout { let ed = Balances::minimum_balance(); Balances::make_free_balance_be(&20, ed + 200); - assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); // 10 gets 10, 20 gets 20, 30 gets 10 Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); // some claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), @@ -1533,11 +1548,11 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); // and 20 bonds more -- they should not have more share of this reward. - assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::FreeBalance(10))); // everyone claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1553,8 +1568,8 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); // everyone claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1584,7 +1599,7 @@ mod claim_payout { // create pool 2 Balances::make_free_balance_be(&20, 100); - assert_ok!(Pools::create(Origin::signed(20), 10, 20, 20, 20)); + assert_ok!(Pools::create(RuntimeOrigin::signed(20), 10, 20, 20, 20)); // has no impact -- initial let (member_20, _, reward_pool_20) = Pools::get_member_with_pools(&20).unwrap(); @@ -1600,7 +1615,7 @@ mod claim_payout { // create pool 3 Balances::make_free_balance_be(&30, 100); - assert_ok!(Pools::create(Origin::signed(30), 10, 30, 30, 30)); + assert_ok!(Pools::create(RuntimeOrigin::signed(30), 10, 30, 30, 30)); // reward counter is still the same. let (member_30, _, reward_pool_30) = Pools::get_member_with_pools(&30).unwrap(); @@ -1616,7 +1631,7 @@ mod claim_payout { assert_eq!(member_30.last_recorded_reward_counter, 0.into()); // and 30 can claim the reward now. - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1640,7 +1655,7 @@ mod claim_payout { MaxPoolMembersPerPool::::set(None); let join = |x, y| { Balances::make_free_balance_be(&x, y + Balances::minimum_balance()); - assert_ok!(Pools::join(Origin::signed(x), y, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(x), y, 1)); }; { @@ -1722,7 +1737,10 @@ mod claim_payout { // 10 bonds extra without any rewards. { - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra( + RuntimeOrigin::signed(10), + BondExtra::FreeBalance(10) + )); let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); assert_eq!(member.last_recorded_reward_counter, 0.into()); assert_eq!(reward_pool.last_recorded_total_payouts, 0); @@ -1734,7 +1752,10 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); { - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra( + RuntimeOrigin::signed(10), + BondExtra::FreeBalance(10) + )); let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); // explanation: before bond_extra takes place, there is 40 points and 30 balance in // the system, RewardCounter is therefore 7.5 @@ -1748,7 +1769,10 @@ mod claim_payout { // 20 bonds extra again, without further rewards. { - assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra( + RuntimeOrigin::signed(20), + BondExtra::FreeBalance(10) + )); let (member, _, reward_pool) = Pools::get_member_with_pools(&20).unwrap(); assert_eq!(member.last_recorded_reward_counter, RewardCounter::from_float(0.75)); assert_eq!( @@ -1786,7 +1810,7 @@ mod claim_payout { // 10 cashes it out, and bonds it. { - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); // there is 30 points and 30 reward points in the system RC is 1. assert_eq!(member.last_recorded_reward_counter, 1.into()); @@ -1803,7 +1827,7 @@ mod claim_payout { // 20 re-bonds it. { - assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::Rewards)); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::Rewards)); let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); assert_eq!(member.last_recorded_reward_counter, 1.into()); assert_eq!(reward_pool.total_rewards_claimed, 30); @@ -1843,7 +1867,7 @@ mod claim_payout { // 20 unbonds without any rewards. { - assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); let (member, _, reward_pool) = Pools::get_member_with_pools(&20).unwrap(); assert_eq!(member.last_recorded_reward_counter, 0.into()); assert_eq!(reward_pool.last_recorded_total_payouts, 0); @@ -1855,7 +1879,7 @@ mod claim_payout { // and 30 also unbonds half. { - assert_ok!(Pools::unbond(Origin::signed(30), 30, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(30), 30, 10)); let (member, _, reward_pool) = Pools::get_member_with_pools(&30).unwrap(); // 30 reward in the system, and 40 points before this unbond to collect it, // RewardCounter is 3/4. @@ -1872,7 +1896,7 @@ mod claim_payout { // 30 unbonds again, not change this time. { - assert_ok!(Pools::unbond(Origin::signed(30), 30, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(30), 30, 5)); let (member, _, reward_pool) = Pools::get_member_with_pools(&30).unwrap(); assert_eq!( member.last_recorded_reward_counter, @@ -1887,7 +1911,7 @@ mod claim_payout { // 20 unbonds again, not change this time, just collecting their reward. { - assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); let (member, _, reward_pool) = Pools::get_member_with_pools(&20).unwrap(); assert_eq!( member.last_recorded_reward_counter, @@ -1901,7 +1925,7 @@ mod claim_payout { } // trigger 10's reward as well to see all of the payouts. - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), @@ -1937,8 +1961,8 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); // everyone claims - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); // some dust (1) remains in the reward account. assert_eq!( @@ -1953,15 +1977,15 @@ mod claim_payout { ); // start dismantling the pool. - assert_ok!(Pools::set_state(Origin::signed(902), 1, PoolState::Destroying)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(902), 1, PoolState::Destroying)); assert_ok!(fully_unbond_permissioned(20)); CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); assert_ok!(fully_unbond_permissioned(10)); CurrentEra::set(6); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( pool_events_since_last_call(), @@ -2000,10 +2024,10 @@ mod claim_payout { .unwrap(); // everyone claims - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); - assert_ok!(Pools::claim_payout(Origin::signed(21))); - assert_ok!(Pools::claim_payout(Origin::signed(22))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(21))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(22))); assert_eq!( pool_events_since_last_call(), @@ -2057,18 +2081,18 @@ mod unbond { .add_members(vec![(20, 20)]) .build_and_execute(|| { // can unbond to above limit - assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 15); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 5); // cannot go to below 10: assert_noop!( - Pools::unbond(Origin::signed(20), 20, 10), + Pools::unbond(RuntimeOrigin::signed(20), 20, 10), Error::::MinimumBondNotMet ); // but can go to 0 - assert_ok!(Pools::unbond(Origin::signed(20), 20, 15)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 15)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 0); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 20); }) @@ -2089,23 +2113,23 @@ mod unbond { // cannot be kicked to above the limit. assert_noop!( - Pools::unbond(Origin::signed(kicker), 20, 5), + Pools::unbond(RuntimeOrigin::signed(kicker), 20, 5), Error::::PartialUnbondNotAllowedPermissionlessly ); // cannot go to below 10: assert_noop!( - Pools::unbond(Origin::signed(kicker), 20, 15), + Pools::unbond(RuntimeOrigin::signed(kicker), 20, 15), Error::::PartialUnbondNotAllowedPermissionlessly ); // but they themselves can do an unbond - assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 2)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 18); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 2); // can be kicked to 0. - assert_ok!(Pools::unbond(Origin::signed(kicker), 20, 18)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(kicker), 20, 18)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 0); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 20); }) @@ -2126,23 +2150,23 @@ mod unbond { // cannot be kicked to above the limit. assert_noop!( - Pools::unbond(Origin::signed(random), 20, 5), + Pools::unbond(RuntimeOrigin::signed(random), 20, 5), Error::::PartialUnbondNotAllowedPermissionlessly ); // cannot go to below 10: assert_noop!( - Pools::unbond(Origin::signed(random), 20, 15), + Pools::unbond(RuntimeOrigin::signed(random), 20, 15), Error::::PartialUnbondNotAllowedPermissionlessly ); // but they themselves can do an unbond - assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 2)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 18); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 2); // but can go to 0 - assert_ok!(Pools::unbond(Origin::signed(random), 20, 18)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(random), 20, 18)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 0); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 20); }) @@ -2155,19 +2179,25 @@ mod unbond { // - depositor cannot unbond to below limit or 0 ExtBuilder::default().min_join_bond(10).build_and_execute(|| { // give the depositor some extra funds. - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); // can unbond to above the limit. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 5)); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 15); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 5); // cannot go to below 10: - assert_noop!(Pools::unbond(Origin::signed(10), 10, 10), Error::::MinimumBondNotMet); + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 10), + Error::::MinimumBondNotMet + ); // cannot go to 0 either. - assert_noop!(Pools::unbond(Origin::signed(10), 10, 15), Error::::MinimumBondNotMet); + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 15), + Error::::MinimumBondNotMet + ); }) } @@ -2177,7 +2207,7 @@ mod unbond { // - depositor can never be kicked. ExtBuilder::default().min_join_bond(10).build_and_execute(|| { // give the depositor some extra funds. - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); // set the stage @@ -2186,24 +2216,27 @@ mod unbond { // cannot be kicked to above limit. assert_noop!( - Pools::unbond(Origin::signed(kicker), 10, 5), + Pools::unbond(RuntimeOrigin::signed(kicker), 10, 5), Error::::PartialUnbondNotAllowedPermissionlessly ); // or below the limit assert_noop!( - Pools::unbond(Origin::signed(kicker), 10, 15), + Pools::unbond(RuntimeOrigin::signed(kicker), 10, 15), Error::::PartialUnbondNotAllowedPermissionlessly ); // or 0. assert_noop!( - Pools::unbond(Origin::signed(kicker), 10, 20), + Pools::unbond(RuntimeOrigin::signed(kicker), 10, 20), Error::::DoesNotHavePermission ); // they themselves cannot do it either - assert_noop!(Pools::unbond(Origin::signed(10), 10, 20), Error::::MinimumBondNotMet); + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 20), + Error::::MinimumBondNotMet + ); }) } @@ -2212,7 +2245,7 @@ mod unbond { // depositor can never be permissionlessly unbonded. ExtBuilder::default().min_join_bond(10).build_and_execute(|| { // give the depositor some extra funds. - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); // set the stage @@ -2221,24 +2254,24 @@ mod unbond { // cannot be kicked to above limit. assert_noop!( - Pools::unbond(Origin::signed(random), 10, 5), + Pools::unbond(RuntimeOrigin::signed(random), 10, 5), Error::::PartialUnbondNotAllowedPermissionlessly ); // or below the limit assert_noop!( - Pools::unbond(Origin::signed(random), 10, 15), + Pools::unbond(RuntimeOrigin::signed(random), 10, 15), Error::::PartialUnbondNotAllowedPermissionlessly ); // or 0. assert_noop!( - Pools::unbond(Origin::signed(random), 10, 20), + Pools::unbond(RuntimeOrigin::signed(random), 10, 20), Error::::DoesNotHavePermission ); // they themselves can do it in this case though. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 20)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20)); }) } @@ -2251,26 +2284,29 @@ mod unbond { .add_members(vec![(20, 20)]) .build_and_execute(|| { // give the depositor some extra funds. - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra( + RuntimeOrigin::signed(10), + BondExtra::FreeBalance(10) + )); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); // set the stage unsafe_set_state(1, PoolState::Destroying); // can go above the limit - assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 5)); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 15); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 5); // but not below the limit assert_noop!( - Pools::unbond(Origin::signed(10), 10, 10), + Pools::unbond(RuntimeOrigin::signed(10), 10, 10), Error::::MinimumBondNotMet ); // and certainly not zero assert_noop!( - Pools::unbond(Origin::signed(10), 10, 15), + Pools::unbond(RuntimeOrigin::signed(10), 10, 15), Error::::MinimumBondNotMet ); }) @@ -2284,22 +2320,25 @@ mod unbond { // - depositor can unbond to 0 if last and destroying. ExtBuilder::default().min_join_bond(10).build_and_execute(|| { // give the depositor some extra funds. - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); // set the stage unsafe_set_state(1, PoolState::Destroying); // can unbond to above the limit. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 5)); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 15); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 5); // still cannot go to below limit - assert_noop!(Pools::unbond(Origin::signed(10), 10, 10), Error::::MinimumBondNotMet); + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 10), + Error::::MinimumBondNotMet + ); // can go to 0 too. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 15)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 15)); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 0); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 20); }) @@ -2426,8 +2465,8 @@ mod unbond { // When CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 40, 0)); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 550, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 40, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 550, 0)); assert_ok!(fully_unbond_permissioned(10)); // Then @@ -2525,12 +2564,12 @@ mod unbond { // When the nominator tries to kick, then its a noop assert_noop!( - Pools::fully_unbond(Origin::signed(901), 100), + Pools::fully_unbond(RuntimeOrigin::signed(901), 100), Error::::NotKickerOrDestroying ); // When the root kicks then its ok - assert_ok!(Pools::fully_unbond(Origin::signed(900), 100)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(900), 100)); assert_eq!( pool_events_since_last_call(), @@ -2550,7 +2589,7 @@ mod unbond { ); // When the state toggler kicks then its ok - assert_ok!(Pools::fully_unbond(Origin::signed(902), 200)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(902), 200)); assert_eq!( pool_events_since_last_call(), @@ -2601,13 +2640,13 @@ mod unbond { // A permissionless unbond attempt errors assert_noop!( - Pools::fully_unbond(Origin::signed(420), 100), + Pools::fully_unbond(RuntimeOrigin::signed(420), 100), Error::::NotKickerOrDestroying ); // permissionless unbond must be full assert_noop!( - Pools::unbond(Origin::signed(420), 100, 80), + Pools::unbond(RuntimeOrigin::signed(420), 100, 80), Error::::PartialUnbondNotAllowedPermissionlessly, ); @@ -2616,12 +2655,12 @@ mod unbond { // The depositor cannot be fully unbonded until they are the last member assert_noop!( - Pools::fully_unbond(Origin::signed(10), 10), + Pools::fully_unbond(RuntimeOrigin::signed(10), 10), Error::::MinimumBondNotMet, ); // Any account can unbond a member that is not the depositor - assert_ok!(Pools::fully_unbond(Origin::signed(420), 100)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(420), 100)); assert_eq!( pool_events_since_last_call(), @@ -2635,7 +2674,7 @@ mod unbond { // still permissionless unbond must be full assert_noop!( - Pools::unbond(Origin::signed(420), 100, 80), + Pools::unbond(RuntimeOrigin::signed(420), 100, 80), Error::::PartialUnbondNotAllowedPermissionlessly, ); @@ -2644,7 +2683,7 @@ mod unbond { // The depositor cannot be unbonded assert_noop!( - Pools::fully_unbond(Origin::signed(420), 10), + Pools::fully_unbond(RuntimeOrigin::signed(420), 10), Error::::DoesNotHavePermission ); @@ -2653,27 +2692,27 @@ mod unbond { // The depositor cannot be unbonded yet. assert_noop!( - Pools::fully_unbond(Origin::signed(420), 10), + Pools::fully_unbond(RuntimeOrigin::signed(420), 10), Error::::DoesNotHavePermission, ); // but when everyone is unbonded it can.. CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 100, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 100, 0)); // still permissionless unbond must be full. assert_noop!( - Pools::unbond(Origin::signed(420), 10, 5), + Pools::unbond(RuntimeOrigin::signed(420), 10, 5), Error::::PartialUnbondNotAllowedPermissionlessly, ); // depositor can never be unbonded permissionlessly . assert_noop!( - Pools::fully_unbond(Origin::signed(420), 10), + Pools::fully_unbond(RuntimeOrigin::signed(420), 10), Error::::DoesNotHavePermission ); // but depositor itself can do it. - assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(10), 10)); assert_eq!(BondedPools::::get(1).unwrap().points, 0); assert_eq!( @@ -2696,7 +2735,7 @@ mod unbond { fn unbond_errors_correctly() { ExtBuilder::default().build_and_execute(|| { assert_noop!( - Pools::fully_unbond(Origin::signed(11), 11), + Pools::fully_unbond(RuntimeOrigin::signed(11), 11), Error::::PoolMemberNotFound ); @@ -2704,7 +2743,7 @@ mod unbond { let member = PoolMember { pool_id: 2, points: 10, ..Default::default() }; PoolMembers::::insert(11, member); - let _ = Pools::fully_unbond(Origin::signed(11), 11); + let _ = Pools::fully_unbond(RuntimeOrigin::signed(11), 11); }); } @@ -2726,7 +2765,7 @@ mod unbond { } .put(); - let _ = Pools::fully_unbond(Origin::signed(11), 11); + let _ = Pools::fully_unbond(RuntimeOrigin::signed(11), 11); }); } @@ -2756,7 +2795,7 @@ mod unbond { unsafe_set_state(1, PoolState::Destroying); // when: casual unbond - assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 1)); // then assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 9); @@ -2785,7 +2824,7 @@ mod unbond { ); // when: casual further unbond, same era. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 5)); // then assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 4); @@ -2811,7 +2850,7 @@ mod unbond { // when: casual further unbond, next era. CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 1)); // then assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 3); @@ -2839,14 +2878,14 @@ mod unbond { // when: unbonding more than our active: error assert_noop!( frame_support::storage::with_storage_layer(|| Pools::unbond( - Origin::signed(10), + RuntimeOrigin::signed(10), 10, 5 )), Error::::MinimumBondNotMet ); // instead: - assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 3)); // then assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 0); @@ -2879,9 +2918,9 @@ mod unbond { MaxUnbonding::set(2); // given - assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 2)); CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 3)); assert_eq!( PoolMembers::::get(20).unwrap().unbonding_eras, member_unbonding_eras!(3 => 2, 4 => 3) @@ -2891,7 +2930,7 @@ mod unbond { CurrentEra::set(2); assert_noop!( frame_support::storage::with_storage_layer(|| Pools::unbond( - Origin::signed(20), + RuntimeOrigin::signed(20), 20, 4 )), @@ -2900,7 +2939,7 @@ mod unbond { // when MaxUnbonding::set(3); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 1)); assert_eq!( PoolMembers::::get(20).unwrap().unbonding_eras, @@ -2933,13 +2972,13 @@ mod unbond { assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 0); // can unbond a bit.. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 3)); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 7); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 3); // but not less than 2 assert_noop!( - Pools::unbond(Origin::signed(10), 10, 6), + Pools::unbond(RuntimeOrigin::signed(10), 10, 6), Error::::MinimumBondNotMet ); @@ -2967,7 +3006,7 @@ mod unbond { // cannot unbond even 7, because the value of shares is now less. assert_noop!( - Pools::unbond(Origin::signed(10), 10, 7), + Pools::unbond(RuntimeOrigin::signed(10), 10, 7), Error::::MinimumBondNotMet ); }); @@ -2985,7 +3024,7 @@ mod unbond { 4 * Balances::minimum_balance(), ); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 2)); assert_eq!( pool_events_since_last_call(), vec![ @@ -3004,7 +3043,7 @@ mod unbond { 4 * Balances::minimum_balance(), ); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 3)); assert_eq!( pool_events_since_last_call(), vec![ @@ -3020,7 +3059,7 @@ mod unbond { 4 * Balances::minimum_balance(), ); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); assert_eq!( pool_events_since_last_call(), vec![ @@ -3051,7 +3090,7 @@ mod pool_withdraw_unbonded { assert_eq!(Balances::free_balance(&default_bonded_account()), 10); // When - assert_ok!(Pools::pool_withdraw_unbonded(Origin::signed(10), 1, 0)); + assert_ok!(Pools::pool_withdraw_unbonded(RuntimeOrigin::signed(10), 1, 0)); // Then there unbonding balance is no longer locked assert_eq!(StakingMock::active_stake(&default_bonded_account()), Some(5)); @@ -3075,8 +3114,8 @@ mod withdraw_unbonded { // Given assert_eq!(StakingMock::bonding_duration(), 3); - assert_ok!(Pools::fully_unbond(Origin::signed(550), 550)); - assert_ok!(Pools::fully_unbond(Origin::signed(40), 40)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(550), 550)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(40), 40)); assert_eq!(Balances::free_balance(&default_bonded_account()), 600); let mut current_era = 1; @@ -3151,7 +3190,7 @@ mod withdraw_unbonded { ); // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(550), 550, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(550), 550, 0)); // Then assert_eq!( @@ -3171,7 +3210,7 @@ mod withdraw_unbonded { ); // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(40), 40, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(40), 40, 0)); // Then assert_eq!( @@ -3199,7 +3238,7 @@ mod withdraw_unbonded { CurrentEra::set(current_era); // when - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( pool_events_since_last_call(), vec![ @@ -3271,7 +3310,7 @@ mod withdraw_unbonded { CurrentEra::set(StakingMock::bonding_duration()); // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(40), 40, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(40), 40, 0)); // Then assert_eq!( @@ -3292,7 +3331,7 @@ mod withdraw_unbonded { ); // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(550), 550, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(550), 550, 0)); // Then assert_eq!( @@ -3321,11 +3360,11 @@ mod withdraw_unbonded { CurrentEra::set(CurrentEra::get() + 3); // set metadata to check that it's being removed on dissolve - assert_ok!(Pools::set_metadata(Origin::signed(900), 1, vec![1, 1])); + assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(900), 1, vec![1, 1])); assert!(Metadata::::contains_key(1)); // when - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // then assert_eq!(Balances::free_balance(&10), 10 + 35); @@ -3361,7 +3400,7 @@ mod withdraw_unbonded { assert_eq!(Balances::free_balance(&10), 35); assert_eq!(Balances::free_balance(&default_bonded_account()), 10); unsafe_set_state(1, PoolState::Destroying); - assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(10), 10)); // Simulate a slash that is not accounted for in the sub pools. Balances::make_free_balance_be(&default_bonded_account(), 5); @@ -3374,7 +3413,7 @@ mod withdraw_unbonded { CurrentEra::set(0 + 3); // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // Then assert_eq!(Balances::free_balance(10), 10 + 35); @@ -3393,7 +3432,7 @@ mod withdraw_unbonded { SubPoolsStorage::::insert(1, sub_pools.clone()); assert_noop!( - Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0), Error::::PoolMemberNotFound ); @@ -3406,7 +3445,7 @@ mod withdraw_unbonded { // We are still in the bonding duration assert_noop!( - Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0), Error::::CannotWithdrawAny ); @@ -3423,8 +3462,8 @@ mod withdraw_unbonded { .add_members(vec![(100, 100), (200, 200)]) .build_and_execute(|| { // Given - assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); - assert_ok!(Pools::fully_unbond(Origin::signed(200), 200)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(100), 100)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(200), 200)); assert_eq!( BondedPool::::get(1).unwrap(), BondedPool { @@ -3441,7 +3480,7 @@ mod withdraw_unbonded { // Cannot kick when pool is open assert_noop!( - Pools::withdraw_unbonded(Origin::signed(902), 100, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(902), 100, 0), Error::::NotKickerOrDestroying ); assert_eq!( @@ -3473,15 +3512,15 @@ mod withdraw_unbonded { // Cannot kick as a nominator assert_noop!( - Pools::withdraw_unbonded(Origin::signed(901), 100, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(901), 100, 0), Error::::NotKickerOrDestroying ); // Can kick as root - assert_ok!(Pools::withdraw_unbonded(Origin::signed(900), 100, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(900), 100, 0)); // Can kick as state toggler - assert_ok!(Pools::withdraw_unbonded(Origin::signed(900), 200, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(900), 200, 0)); assert_eq!(Balances::free_balance(100), 100 + 100); assert_eq!(Balances::free_balance(200), 200 + 200); @@ -3504,7 +3543,7 @@ mod withdraw_unbonded { fn withdraw_unbonded_destroying_permissionless() { ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { // Given - assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(100), 100)); assert_eq!( BondedPool::::get(1).unwrap(), BondedPool { @@ -3522,7 +3561,7 @@ mod withdraw_unbonded { // Cannot permissionlessly withdraw assert_noop!( - Pools::fully_unbond(Origin::signed(420), 100), + Pools::fully_unbond(RuntimeOrigin::signed(420), 100), Error::::NotKickerOrDestroying ); @@ -3530,7 +3569,7 @@ mod withdraw_unbonded { unsafe_set_state(1, PoolState::Destroying); // Can permissionlesly withdraw a member that is not the depositor - assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 100, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(420), 100, 0)); assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default(),); assert_eq!(Balances::free_balance(100), 100 + 100); @@ -3552,13 +3591,13 @@ mod withdraw_unbonded { #[test] fn partial_withdraw_unbonded_depositor() { ExtBuilder::default().ed(1).build_and_execute(|| { - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); unsafe_set_state(1, PoolState::Destroying); // given - assert_ok!(Pools::unbond(Origin::signed(10), 10, 6)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 6)); CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 1)); assert_eq!( PoolMembers::::get(10).unwrap().unbonding_eras, member_unbonding_eras!(3 => 6, 4 => 1) @@ -3589,13 +3628,13 @@ mod withdraw_unbonded { // when CurrentEra::set(2); assert_noop!( - Pools::withdraw_unbonded(Origin::signed(10), 10, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0), Error::::CannotWithdrawAny ); // when CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // then assert_eq!( @@ -3618,7 +3657,7 @@ mod withdraw_unbonded { // when CurrentEra::set(4); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // then assert_eq!( @@ -3633,7 +3672,7 @@ mod withdraw_unbonded { // when repeating: assert_noop!( - Pools::withdraw_unbonded(Origin::signed(10), 10, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0), Error::::CannotWithdrawAny ); }); @@ -3643,9 +3682,9 @@ mod withdraw_unbonded { fn partial_withdraw_unbonded_non_depositor() { ExtBuilder::default().add_members(vec![(11, 10)]).build_and_execute(|| { // given - assert_ok!(Pools::unbond(Origin::signed(11), 11, 6)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(11), 11, 6)); CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(11), 11, 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(11), 11, 1)); assert_eq!( PoolMembers::::get(11).unwrap().unbonding_eras, member_unbonding_eras!(3 => 6, 4 => 1) @@ -3676,13 +3715,13 @@ mod withdraw_unbonded { // when CurrentEra::set(2); assert_noop!( - Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0), Error::::CannotWithdrawAny ); // when CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(11), 11, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0)); // then assert_eq!( @@ -3705,7 +3744,7 @@ mod withdraw_unbonded { // when CurrentEra::set(4); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(11), 11, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0)); // then assert_eq!( @@ -3720,7 +3759,7 @@ mod withdraw_unbonded { // when repeating: assert_noop!( - Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0), Error::::CannotWithdrawAny ); }); @@ -3730,7 +3769,7 @@ mod withdraw_unbonded { fn full_multi_step_withdrawing_non_depositor() { ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { // given - assert_ok!(Pools::unbond(Origin::signed(100), 100, 75)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(100), 100, 75)); assert_eq!( PoolMembers::::get(100).unwrap().unbonding_eras, member_unbonding_eras!(3 => 75) @@ -3738,20 +3777,20 @@ mod withdraw_unbonded { // progress one era and unbond the leftover. CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(100), 100, 25)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(100), 100, 25)); assert_eq!( PoolMembers::::get(100).unwrap().unbonding_eras, member_unbonding_eras!(3 => 75, 4 => 25) ); assert_noop!( - Pools::withdraw_unbonded(Origin::signed(100), 100, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(100), 100, 0), Error::::CannotWithdrawAny ); // now the 75 should be free. CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(100), 100, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(100), 100, 0)); assert_eq!( pool_events_since_last_call(), vec![ @@ -3770,7 +3809,7 @@ mod withdraw_unbonded { // the 25 should be free now, and the member removed. CurrentEra::set(4); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(100), 100, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(100), 100, 0)); assert_eq!( pool_events_since_last_call(), vec![ @@ -3793,8 +3832,8 @@ mod withdraw_unbonded { System::reset_events(); // when - assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); - assert_ok!(Pools::unbond(Origin::signed(30), 30, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(30), 30, 5)); // then member-local unbonding is pretty much in sync with the global pools. assert_eq!( @@ -3824,7 +3863,7 @@ mod withdraw_unbonded { // when CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); // then still member-local unbonding is pretty much in sync with the global pools. assert_eq!( @@ -3848,7 +3887,7 @@ mod withdraw_unbonded { // when CurrentEra::set(2); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); // then still member-local unbonding is pretty much in sync with the global pools. assert_eq!( @@ -3873,7 +3912,7 @@ mod withdraw_unbonded { // when CurrentEra::set(5); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); // then assert_eq!( @@ -3900,7 +3939,7 @@ mod withdraw_unbonded { // now we start withdrawing unlocked bonds. // when - assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); // then assert_eq!( PoolMembers::::get(20).unwrap().unbonding_eras, @@ -3922,7 +3961,7 @@ mod withdraw_unbonded { ); // when - assert_ok!(Pools::withdraw_unbonded(Origin::signed(30), 30, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(30), 30, 0)); // then assert_eq!( PoolMembers::::get(30).unwrap().unbonding_eras, @@ -3950,14 +3989,14 @@ mod withdraw_unbonded { ExtBuilder::default().ed(1).build_and_execute(|| { // depositor now has 20, they can unbond to 10. assert_eq!(Pools::depositor_min_bond(), 10); - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); // now they can. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 7)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 7)); // progress one era and unbond the leftover. CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 3)); assert_eq!( PoolMembers::::get(10).unwrap().unbonding_eras, @@ -3966,27 +4005,27 @@ mod withdraw_unbonded { // they can't unbond to a value below 10 other than 0.. assert_noop!( - Pools::unbond(Origin::signed(10), 10, 5), + Pools::unbond(RuntimeOrigin::signed(10), 10, 5), Error::::MinimumBondNotMet ); // but not even full, because they pool is not yet destroying. assert_noop!( - Pools::unbond(Origin::signed(10), 10, 10), + Pools::unbond(RuntimeOrigin::signed(10), 10, 10), Error::::MinimumBondNotMet ); // but now they can. unsafe_set_state(1, PoolState::Destroying); assert_noop!( - Pools::unbond(Origin::signed(10), 10, 5), + Pools::unbond(RuntimeOrigin::signed(10), 10, 5), Error::::MinimumBondNotMet ); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); // now the 7 should be free. CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( pool_events_since_last_call(), @@ -4007,7 +4046,7 @@ mod withdraw_unbonded { // the 13 should be free now, and the member removed. CurrentEra::set(4); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( pool_events_since_last_call(), @@ -4039,7 +4078,7 @@ mod create { Balances::make_free_balance_be(&11, StakingMock::minimum_bond() + ed); assert_ok!(Pools::create( - Origin::signed(11), + RuntimeOrigin::signed(11), StakingMock::minimum_bond(), 123, 456, @@ -4097,7 +4136,7 @@ mod create { fn create_errors_correctly() { ExtBuilder::default().with_check(0).build_and_execute(|| { assert_noop!( - Pools::create(Origin::signed(10), 420, 123, 456, 789), + Pools::create(RuntimeOrigin::signed(10), 420, 123, 456, 789), Error::::AccountBelongsToOtherPool ); @@ -4107,7 +4146,7 @@ mod create { // Then assert_noop!( - Pools::create(Origin::signed(11), 9, 123, 456, 789), + Pools::create(RuntimeOrigin::signed(11), 9, 123, 456, 789), Error::::MinimumBondNotMet ); @@ -4116,7 +4155,7 @@ mod create { // Then assert_noop!( - Pools::create(Origin::signed(11), 19, 123, 456, 789), + Pools::create(RuntimeOrigin::signed(11), 19, 123, 456, 789), Error::::MinimumBondNotMet ); @@ -4136,7 +4175,7 @@ mod create { // Then assert_noop!( - Pools::create(Origin::signed(11), 20, 123, 456, 789), + Pools::create(RuntimeOrigin::signed(11), 20, 123, 456, 789), Error::::MaxPools ); @@ -4153,7 +4192,10 @@ mod create { nominator: 11, state_toggler: 11, }); - assert_noop!(create.dispatch(Origin::signed(11)), Error::::MaxPoolMembers); + assert_noop!( + create.dispatch(RuntimeOrigin::signed(11)), + Error::::MaxPoolMembers + ); }); } } @@ -4166,27 +4208,27 @@ mod nominate { ExtBuilder::default().build_and_execute(|| { // Depositor can't nominate assert_noop!( - Pools::nominate(Origin::signed(10), 1, vec![21]), + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![21]), Error::::NotNominator ); // State toggler can't nominate assert_noop!( - Pools::nominate(Origin::signed(902), 1, vec![21]), + Pools::nominate(RuntimeOrigin::signed(902), 1, vec![21]), Error::::NotNominator ); // Root can nominate - assert_ok!(Pools::nominate(Origin::signed(900), 1, vec![21])); + assert_ok!(Pools::nominate(RuntimeOrigin::signed(900), 1, vec![21])); assert_eq!(Nominations::get().unwrap(), vec![21]); // Nominator can nominate - assert_ok!(Pools::nominate(Origin::signed(901), 1, vec![31])); + assert_ok!(Pools::nominate(RuntimeOrigin::signed(901), 1, vec![31])); assert_eq!(Nominations::get().unwrap(), vec![31]); // Can't nominate for a pool that doesn't exist assert_noop!( - Pools::nominate(Origin::signed(902), 123, vec![21]), + Pools::nominate(RuntimeOrigin::signed(902), 123, vec![21]), Error::::PoolNotFound ); }); @@ -4204,16 +4246,16 @@ mod set_state { // Only the root and state toggler can change the state when the pool is ok to be open. assert_noop!( - Pools::set_state(Origin::signed(10), 1, PoolState::Blocked), + Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Blocked), Error::::CanNotChangeState ); assert_noop!( - Pools::set_state(Origin::signed(901), 1, PoolState::Blocked), + Pools::set_state(RuntimeOrigin::signed(901), 1, PoolState::Blocked), Error::::CanNotChangeState ); // Root can change state - assert_ok!(Pools::set_state(Origin::signed(900), 1, PoolState::Blocked)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(900), 1, PoolState::Blocked)); assert_eq!( pool_events_since_last_call(), @@ -4227,16 +4269,16 @@ mod set_state { assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Blocked); // State toggler can change state - assert_ok!(Pools::set_state(Origin::signed(902), 1, PoolState::Destroying)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(902), 1, PoolState::Destroying)); assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); // If the pool is destroying, then no one can set state assert_noop!( - Pools::set_state(Origin::signed(900), 1, PoolState::Blocked), + Pools::set_state(RuntimeOrigin::signed(900), 1, PoolState::Blocked), Error::::CanNotChangeState ); assert_noop!( - Pools::set_state(Origin::signed(902), 1, PoolState::Blocked), + Pools::set_state(RuntimeOrigin::signed(902), 1, PoolState::Blocked), Error::::CanNotChangeState ); @@ -4248,7 +4290,7 @@ mod set_state { bonded_pool.points = 100; bonded_pool.put(); // When - assert_ok!(Pools::set_state(Origin::signed(11), 1, PoolState::Destroying)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Destroying)); // Then assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); @@ -4256,7 +4298,7 @@ mod set_state { Balances::make_free_balance_be(&default_bonded_account(), Balance::max_value() / 10); unsafe_set_state(1, PoolState::Open); // When - assert_ok!(Pools::set_state(Origin::signed(11), 1, PoolState::Destroying)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Destroying)); // Then assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); @@ -4264,7 +4306,7 @@ mod set_state { // isn't destroying unsafe_set_state(1, PoolState::Open); assert_noop!( - Pools::set_state(Origin::signed(11), 1, PoolState::Blocked), + Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Blocked), Error::::CanNotChangeState ); @@ -4287,28 +4329,28 @@ mod set_metadata { fn set_metadata_works() { ExtBuilder::default().build_and_execute(|| { // Root can set metadata - assert_ok!(Pools::set_metadata(Origin::signed(900), 1, vec![1, 1])); + assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(900), 1, vec![1, 1])); assert_eq!(Metadata::::get(1), vec![1, 1]); // State toggler can set metadata - assert_ok!(Pools::set_metadata(Origin::signed(902), 1, vec![2, 2])); + assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(902), 1, vec![2, 2])); assert_eq!(Metadata::::get(1), vec![2, 2]); // Depositor can't set metadata assert_noop!( - Pools::set_metadata(Origin::signed(10), 1, vec![3, 3]), + Pools::set_metadata(RuntimeOrigin::signed(10), 1, vec![3, 3]), Error::::DoesNotHavePermission ); // Nominator can't set metadata assert_noop!( - Pools::set_metadata(Origin::signed(901), 1, vec![3, 3]), + Pools::set_metadata(RuntimeOrigin::signed(901), 1, vec![3, 3]), Error::::DoesNotHavePermission ); // Metadata cannot be longer than `MaxMetadataLen` assert_noop!( - Pools::set_metadata(Origin::signed(900), 1, vec![1, 1, 1]), + Pools::set_metadata(RuntimeOrigin::signed(900), 1, vec![1, 1, 1]), Error::::MetadataExceedsMaxLen ); }); @@ -4323,7 +4365,7 @@ mod set_configs { ExtBuilder::default().build_and_execute(|| { // Setting works assert_ok!(Pools::set_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Set(1 as Balance), ConfigOp::Set(2 as Balance), ConfigOp::Set(3u32), @@ -4338,7 +4380,7 @@ mod set_configs { // Noop does nothing assert_storage_noop!(assert_ok!(Pools::set_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, @@ -4348,7 +4390,7 @@ mod set_configs { // Removing works assert_ok!(Pools::set_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, @@ -4380,7 +4422,7 @@ mod bond_extra { assert_eq!(Balances::free_balance(10), 100); // when - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); // then assert_eq!(Balances::free_balance(10), 90); @@ -4397,7 +4439,7 @@ mod bond_extra { ); // when - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(20))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(20))); // then assert_eq!(Balances::free_balance(10), 70); @@ -4426,7 +4468,7 @@ mod bond_extra { assert_eq!(Balances::free_balance(10), 35); // when - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::Rewards)); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards)); // then assert_eq!(Balances::free_balance(10), 35); @@ -4469,7 +4511,7 @@ mod bond_extra { assert_eq!(Balances::free_balance(20), 20); // when - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::Rewards)); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards)); // then assert_eq!(Balances::free_balance(10), 35); @@ -4478,7 +4520,7 @@ mod bond_extra { assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 1); // when - assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::Rewards)); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::Rewards)); // then assert_eq!(Balances::free_balance(20), 20); @@ -4522,7 +4564,7 @@ mod update_roles { // non-existent pools assert_noop!( Pools::update_roles( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, ConfigOp::Set(5), ConfigOp::Set(6), @@ -4534,7 +4576,7 @@ mod update_roles { // depositor cannot change roles. assert_noop!( Pools::update_roles( - Origin::signed(1), + RuntimeOrigin::signed(1), 1, ConfigOp::Set(5), ConfigOp::Set(6), @@ -4546,7 +4588,7 @@ mod update_roles { // nominator cannot change roles. assert_noop!( Pools::update_roles( - Origin::signed(901), + RuntimeOrigin::signed(901), 1, ConfigOp::Set(5), ConfigOp::Set(6), @@ -4557,7 +4599,7 @@ mod update_roles { // state-toggler assert_noop!( Pools::update_roles( - Origin::signed(902), + RuntimeOrigin::signed(902), 1, ConfigOp::Set(5), ConfigOp::Set(6), @@ -4568,7 +4610,7 @@ mod update_roles { // but root can assert_ok!(Pools::update_roles( - Origin::signed(900), + RuntimeOrigin::signed(900), 1, ConfigOp::Set(5), ConfigOp::Set(6), @@ -4599,7 +4641,7 @@ mod update_roles { // also root origin can assert_ok!(Pools::update_roles( - Origin::root(), + RuntimeOrigin::root(), 1, ConfigOp::Set(1), ConfigOp::Set(2), @@ -4626,7 +4668,7 @@ mod update_roles { // Noop works assert_ok!(Pools::update_roles( - Origin::root(), + RuntimeOrigin::root(), 1, ConfigOp::Set(11), ConfigOp::Noop, @@ -4654,7 +4696,7 @@ mod update_roles { // Remove works assert_ok!(Pools::update_roles( - Origin::root(), + RuntimeOrigin::root(), 1, ConfigOp::Set(69), ConfigOp::Remove, @@ -4730,7 +4772,7 @@ mod reward_counter_precision { // tad bit less. cannot be paid out. assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += expected_smallest_reward - 1)); - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!(pool_events_since_last_call(), vec![]); // revert it. @@ -4740,7 +4782,7 @@ mod reward_counter_precision { // tad bit more. can be claimed. assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += expected_smallest_reward + 1)); - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), vec![Event::PaidOut { member: 10, pool_id: 1, payout: 1173 }] @@ -4776,7 +4818,7 @@ mod reward_counter_precision { // some whale now joins with the other half ot the total issuance. This will bloat all // the calculation regarding current reward counter. Balances::make_free_balance_be(&20, pool_bond * 2); - assert_ok!(Pools::join(Origin::signed(20), pool_bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), pool_bond, 1)); assert_eq!( pool_events_since_last_call(), @@ -4788,8 +4830,8 @@ mod reward_counter_precision { }] ); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -4798,12 +4840,12 @@ mod reward_counter_precision { // now let a small member join with 10 DOTs. Balances::make_free_balance_be(&30, 20 * DOT); - assert_ok!(Pools::join(Origin::signed(30), 10 * DOT, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10 * DOT, 1)); // and give a reasonably small reward to the pool. assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += DOT)); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), vec![ @@ -4841,7 +4883,10 @@ mod reward_counter_precision { // set to zero. In other tests that we want to assert a scenario won't fail, we should // also set the reward counters to some large value. Balances::make_free_balance_be(&20, pool_bond * 2); - assert_err!(Pools::join(Origin::signed(20), pool_bond, 1), Error::::OverflowRisk); + assert_err!( + Pools::join(RuntimeOrigin::signed(20), pool_bond, 1), + Error::::OverflowRisk + ); }) } @@ -4867,7 +4912,7 @@ mod reward_counter_precision { // and have a tiny fish join the pool as well.. Balances::make_free_balance_be(&20, 20 * DOT); - assert_ok!(Pools::join(Origin::signed(20), 10 * DOT, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10 * DOT, 1)); // earn some small rewards assert_ok!( @@ -4876,7 +4921,7 @@ mod reward_counter_precision { // no point in claiming for 20 (nonetheless, it should be harmless) assert!(pending_rewards(20).unwrap().is_zero()); - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), vec![ @@ -4896,7 +4941,7 @@ mod reward_counter_precision { Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) ); assert!(pending_rewards(20).unwrap().is_zero()); - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), vec![Event::PaidOut { member: 10, pool_id: 1, payout: 10000000 }] @@ -4907,8 +4952,8 @@ mod reward_counter_precision { Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) ); assert_eq!(pending_rewards(20).unwrap(), 1); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), vec![ @@ -4941,7 +4986,7 @@ mod reward_counter_precision { // and have a tiny fish join the pool as well.. Balances::make_free_balance_be(&20, 20 * DOT); - assert_ok!(Pools::join(Origin::signed(20), 10 * DOT, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10 * DOT, 1)); // earn some small rewards assert_ok!( @@ -4951,8 +4996,8 @@ mod reward_counter_precision { // if 20 claims now, their reward counter should stay the same, so that they have a // chance of claiming this if they let it accumulate. Also see // `if_small_member_waits_long_enough_they_will_earn_rewards` - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), vec![ @@ -4998,7 +5043,7 @@ mod fuzz_test { const REWARD_AGENT_ACCOUNT: AccountId = 42; /// Grab random accounts, either known ones, or new ones. - fn random_signed_origin(rng: &mut R) -> (Origin, AccountId) { + fn random_signed_origin(rng: &mut R) -> (RuntimeOrigin, AccountId) { let count = PoolMembers::::count(); if rng.gen::() && count > 0 { // take an existing account. @@ -5011,11 +5056,11 @@ mod fuzz_test { let acc = if candidate == REWARD_AGENT_ACCOUNT { rng.gen::() } else { candidate }; - (Origin::signed(acc), acc) + (RuntimeOrigin::signed(acc), acc) } else { // create a new account let acc = rng.gen::(); - (Origin::signed(acc), acc) + (RuntimeOrigin::signed(acc), acc) } } @@ -5036,7 +5081,7 @@ mod fuzz_test { BondedPools::::iter_keys().collect::>().choose(&mut rng).map(|x| *x) } - fn random_call(mut rng: &mut R) -> (crate::pallet::Call, Origin) { + fn random_call(mut rng: &mut R) -> (crate::pallet::Call, RuntimeOrigin) { let op = rng.gen::(); let mut op_count = as frame_support::dispatch::GetCallName>::get_call_names() @@ -5133,7 +5178,7 @@ mod fuzz_test { } let pool_id = LastPoolId::::get(); let amount = 10 * ExistentialDeposit::get(); - let origin = Origin::signed(self.who); + let origin = RuntimeOrigin::signed(self.who); let _ = Balances::deposit_creating(&self.who, 10 * amount); self.pool_id = Some(pool_id); log::info!(target: "reward-agent", "🤖 reward agent joining in {} with {}", pool_id, amount); @@ -5148,7 +5193,7 @@ mod fuzz_test { return } let pre = Balances::free_balance(&42); - let origin = Origin::signed(42); + let origin = RuntimeOrigin::signed(42); assert_ok!(PoolsCall::::claim_payout {}.dispatch_bypass_filter(origin)); let post = Balances::free_balance(&42); diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs index 8c6ecae937063..7d848e98174b4 100644 --- a/frame/nomination-pools/test-staking/src/lib.rs +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -35,11 +35,11 @@ fn pool_lifecycle_e2e() { assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. - assert_ok!(Pools::create(Origin::signed(10), 50, 10, 10, 10)); + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); // have the pool nominate. - assert_ok!(Pools::nominate(Origin::signed(10), 1, vec![1, 2, 3])); + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 50),]); assert_eq!( @@ -51,8 +51,8 @@ fn pool_lifecycle_e2e() { ); // have two members join - assert_ok!(Pools::join(Origin::signed(20), 10, 1)); - assert_ok!(Pools::join(Origin::signed(21), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); assert_eq!( staking_events_since_last_call(), @@ -67,17 +67,17 @@ fn pool_lifecycle_e2e() { ); // pool goes into destroying - assert_ok!(Pools::set_state(Origin::signed(10), 1, PoolState::Destroying)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); // depositor cannot unbond yet. assert_noop!( - Pools::unbond(Origin::signed(10), 10, 50), + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), PoolsError::::MinimumBondNotMet, ); // now the members want to unbond. - assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); - assert_ok!(Pools::unbond(Origin::signed(21), 21, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); assert_eq!(PoolMembers::::get(20).unwrap().points, 0); @@ -102,14 +102,14 @@ fn pool_lifecycle_e2e() { // depositor cannot still unbond assert_noop!( - Pools::unbond(Origin::signed(10), 10, 50), + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), PoolsError::::MinimumBondNotMet, ); for e in 1..BondingDuration::get() { CurrentEra::::set(Some(e)); assert_noop!( - Pools::withdraw_unbonded(Origin::signed(20), 20, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0), PoolsError::::CannotWithdrawAny ); } @@ -119,13 +119,13 @@ fn pool_lifecycle_e2e() { // depositor cannot still unbond assert_noop!( - Pools::unbond(Origin::signed(10), 10, 50), + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), PoolsError::::MinimumBondNotMet, ); // but members can now withdraw. - assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(21), 21, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); assert!(PoolMembers::::get(20).is_none()); assert!(PoolMembers::::get(21).is_none()); @@ -146,12 +146,12 @@ fn pool_lifecycle_e2e() { // as soon as all members have left, the depositor can try to unbond, but since the // min-nominator intention is set, they must chill first. assert_noop!( - Pools::unbond(Origin::signed(10), 10, 50), + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), pallet_staking::Error::::InsufficientBond ); - assert_ok!(Pools::chill(Origin::signed(10), 1)); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 50)); + assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); assert_eq!( staking_events_since_last_call(), @@ -164,7 +164,7 @@ fn pool_lifecycle_e2e() { // waiting another bonding duration: CurrentEra::::set(Some(BondingDuration::get() * 2)); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 1)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); // pools is fully destroyed now. assert_eq!( @@ -190,7 +190,7 @@ fn pool_slash_e2e() { assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. - assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); @@ -205,8 +205,8 @@ fn pool_slash_e2e() { assert_eq!(Payee::::get(POOL1_BONDED), RewardDestination::Account(POOL1_REWARD)); // have two members join - assert_ok!(Pools::join(Origin::signed(20), 20, 1)); - assert_ok!(Pools::join(Origin::signed(21), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 20, 1)); assert_eq!( staking_events_since_last_call(), @@ -224,8 +224,8 @@ fn pool_slash_e2e() { CurrentEra::::set(Some(1)); // 20 / 80 of the total funds are unlocked, and safe from any further slash. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 10)); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); assert_eq!( staking_events_since_last_call(), @@ -246,9 +246,9 @@ fn pool_slash_e2e() { // note: depositor cannot fully unbond at this point. // these funds will still get slashed. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 10)); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); - assert_ok!(Pools::unbond(Origin::signed(21), 21, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); assert_eq!( staking_events_since_last_call(), @@ -290,7 +290,7 @@ fn pool_slash_e2e() { ); CurrentEra::::set(Some(3)); - assert_ok!(Pools::unbond(Origin::signed(21), 21, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); assert_eq!( PoolMembers::::get(21).unwrap(), @@ -310,8 +310,8 @@ fn pool_slash_e2e() { // now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free. CurrentEra::::set(Some(6)); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(21), 21, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); assert_eq!( pool_events_since_last_call(), @@ -331,8 +331,8 @@ fn pool_slash_e2e() { ); // now, finally, we can unbond the depositor further than their current limit. - assert_ok!(Pools::set_state(Origin::signed(10), 1, PoolState::Destroying)); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 20)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20)); assert_eq!( staking_events_since_last_call(), @@ -357,7 +357,7 @@ fn pool_slash_e2e() { } ); // withdraw the depositor, they should lose 12 balance in total due to slash. - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( staking_events_since_last_call(), @@ -385,7 +385,7 @@ fn pool_slash_proportional() { assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. - assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); @@ -399,9 +399,9 @@ fn pool_slash_proportional() { // have two members join let bond = 20; - assert_ok!(Pools::join(Origin::signed(20), bond, 1)); - assert_ok!(Pools::join(Origin::signed(21), bond, 1)); - assert_ok!(Pools::join(Origin::signed(22), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(22), bond, 1)); assert_eq!( staking_events_since_last_call(), @@ -424,7 +424,7 @@ fn pool_slash_proportional() { CurrentEra::::set(Some(99)); // and unbond - assert_ok!(Pools::unbond(Origin::signed(20), 20, bond)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); assert_eq!( staking_events_since_last_call(), @@ -442,7 +442,7 @@ fn pool_slash_proportional() { ); CurrentEra::::set(Some(100)); - assert_ok!(Pools::unbond(Origin::signed(21), 21, bond)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond)); assert_eq!( staking_events_since_last_call(), vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] @@ -459,7 +459,7 @@ fn pool_slash_proportional() { ); CurrentEra::::set(Some(101)); - assert_ok!(Pools::unbond(Origin::signed(22), 22, bond)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond)); assert_eq!( staking_events_since_last_call(), vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] @@ -516,7 +516,7 @@ fn pool_slash_non_proportional_only_bonded_pool() { assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. - assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); assert_eq!( pool_events_since_last_call(), @@ -528,7 +528,7 @@ fn pool_slash_non_proportional_only_bonded_pool() { // have two members join let bond = 20; - assert_ok!(Pools::join(Origin::signed(20), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); assert_eq!( staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, bond)] @@ -540,7 +540,7 @@ fn pool_slash_non_proportional_only_bonded_pool() { // progress and unbond. CurrentEra::::set(Some(99)); - assert_ok!(Pools::unbond(Origin::signed(20), 20, bond)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); assert_eq!( staking_events_since_last_call(), vec![StakingEvent::Unbonded(POOL1_BONDED, bond)] @@ -589,7 +589,7 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. - assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); assert_eq!( pool_events_since_last_call(), @@ -601,7 +601,7 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { // have two members join let bond = 20; - assert_ok!(Pools::join(Origin::signed(20), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); assert_eq!( staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, bond)] @@ -613,7 +613,7 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { // progress and unbond. CurrentEra::::set(Some(99)); - assert_ok!(Pools::unbond(Origin::signed(20), 20, bond)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); assert_eq!( staking_events_since_last_call(), vec![StakingEvent::Unbonded(POOL1_BONDED, bond)] diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index cb63ad04d1a38..39111b7f813c7 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -43,7 +43,7 @@ impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; @@ -227,7 +227,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // set some limit for nominations. assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), pallet_staking::ConfigOp::Set(10), // minimum nominator bond pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 43c248a09a0b8..c6d8589870f52 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -50,7 +50,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 5b07aab5bd85e..31dac8d51d3b1 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -92,7 +92,7 @@ impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); type DbWeight = RocksDbWeight; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index e0d7e9614abbc..3c7be9db573f4 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -72,7 +72,7 @@ benchmarks! { let s in 0 .. T::MaxSize::get(); let (preimage, hash) = sized_preimage_and_hash::(s); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: note_preimage(T::ManagerOrigin::successful_origin(), preimage) + }: note_preimage(T::ManagerOrigin::successful_origin(), preimage) verify { assert!(Preimage::::have_preimage(&hash)); } @@ -91,7 +91,7 @@ benchmarks! { unnote_no_deposit_preimage { let (preimage, hash) = preimage_and_hash::(); assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: unnote_preimage(T::ManagerOrigin::successful_origin(), hash) + }: unnote_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert!(!Preimage::::have_preimage(&hash)); } @@ -102,7 +102,7 @@ benchmarks! { let noter = funded_account::("noter", 0); whitelist_account!(noter); assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter).into(), preimage)); - }: _(T::ManagerOrigin::successful_origin(), hash) + }: _(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); } @@ -110,14 +110,14 @@ benchmarks! { request_no_deposit_preimage { let (preimage, hash) = preimage_and_hash::(); assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); } // Cheap request - the preimage is not yet noted, so deposit to unreserve. request_unnoted_preimage { let (_, hash) = preimage_and_hash::(); - }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); } @@ -125,7 +125,7 @@ benchmarks! { request_requested_preimage { let (_, hash) = preimage_and_hash::(); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(2))); } @@ -135,7 +135,7 @@ benchmarks! { let (preimage, hash) = preimage_and_hash::(); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: _(T::ManagerOrigin::successful_origin(), hash) + }: _(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), None); } @@ -143,7 +143,7 @@ benchmarks! { unrequest_unnoted_preimage { let (_, hash) = preimage_and_hash::(); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) + }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), None); } @@ -152,7 +152,7 @@ benchmarks! { let (_, hash) = preimage_and_hash::(); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) + }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); } diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 749e5924cc885..90f5ac175f540 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -86,7 +86,7 @@ pub mod pallet { /// An origin that can request a preimage be placed on-chain without a deposit or fee, or /// manage existing preimages. - type ManagerOrigin: EnsureOrigin; + type ManagerOrigin: EnsureOrigin; /// Max size allowed for a preimage. type MaxSize: Get; @@ -191,7 +191,9 @@ pub mod pallet { impl Pallet { /// Ensure that the origin is either the `ManagerOrigin` or a signed origin. - fn ensure_signed_or_manager(origin: T::Origin) -> Result, BadOrigin> { + fn ensure_signed_or_manager( + origin: T::RuntimeOrigin, + ) -> Result, BadOrigin> { if T::ManagerOrigin::ensure_origin(origin.clone()).is_ok() { return Ok(None) } diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index 75e8767f3e59f..e12598a35b4bb 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -57,7 +57,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = RocksDbWeight; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/frame/preimage/src/tests.rs b/frame/preimage/src/tests.rs index 721bb128de239..e6b64ae16dd8c 100644 --- a/frame/preimage/src/tests.rs +++ b/frame/preimage/src/tests.rs @@ -26,7 +26,7 @@ use pallet_balances::Error as BalancesError; #[test] fn user_note_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_eq!(Balances::reserved_balance(2), 3); assert_eq!(Balances::free_balance(2), 97); @@ -35,11 +35,11 @@ fn user_note_preimage_works() { assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); assert_noop!( - Preimage::note_preimage(Origin::signed(2), vec![1]), + Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]), Error::::AlreadyNoted ); assert_noop!( - Preimage::note_preimage(Origin::signed(0), vec![2]), + Preimage::note_preimage(RuntimeOrigin::signed(0), vec![2]), BalancesError::::InsufficientBalance ); }); @@ -48,7 +48,7 @@ fn user_note_preimage_works() { #[test] fn manager_note_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::free_balance(1), 100); @@ -57,7 +57,7 @@ fn manager_note_preimage_works() { assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); assert_noop!( - Preimage::note_preimage(Origin::signed(1), vec![1]), + Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]), Error::::AlreadyNoted ); }); @@ -66,19 +66,19 @@ fn manager_note_preimage_works() { #[test] fn user_unnote_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_noop!( - Preimage::unnote_preimage(Origin::signed(3), hashed([1])), + Preimage::unnote_preimage(RuntimeOrigin::signed(3), hashed([1])), Error::::NotAuthorized ); assert_noop!( - Preimage::unnote_preimage(Origin::signed(2), hashed([2])), + Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([2])), Error::::NotNoted ); - assert_ok!(Preimage::unnote_preimage(Origin::signed(2), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); assert_noop!( - Preimage::unnote_preimage(Origin::signed(2), hashed([1])), + Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])), Error::::NotNoted ); @@ -91,10 +91,10 @@ fn user_unnote_preimage_works() { #[test] fn manager_unnote_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); - assert_ok!(Preimage::unnote_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_noop!( - Preimage::unnote_preimage(Origin::signed(1), hashed([1])), + Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])), Error::::NotNoted ); @@ -107,17 +107,17 @@ fn manager_unnote_preimage_works() { #[test] fn manager_unnote_user_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_noop!( - Preimage::unnote_preimage(Origin::signed(3), hashed([1])), + Preimage::unnote_preimage(RuntimeOrigin::signed(3), hashed([1])), Error::::NotAuthorized ); assert_noop!( - Preimage::unnote_preimage(Origin::signed(2), hashed([2])), + Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([2])), Error::::NotNoted ); - assert_ok!(Preimage::unnote_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1]))); let h = hashed([1]); assert!(!Preimage::have_preimage(&h)); @@ -128,10 +128,10 @@ fn manager_unnote_user_preimage_works() { #[test] fn requested_then_noted_preimage_cannot_be_unnoted() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_noop!( - Preimage::unnote_preimage(Origin::signed(1), hashed([1])), + Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])), Error::::Requested ); @@ -144,16 +144,16 @@ fn requested_then_noted_preimage_cannot_be_unnoted() { #[test] fn request_note_order_makes_no_difference() { let one_way = new_test_ext().execute_with(|| { - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), ) }); new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); let other_way = ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), @@ -165,8 +165,8 @@ fn request_note_order_makes_no_difference() { #[test] fn requested_then_user_noted_preimage_is_free() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_eq!(Balances::reserved_balance(2), 0); assert_eq!(Balances::free_balance(2), 100); @@ -179,16 +179,16 @@ fn requested_then_user_noted_preimage_is_free() { #[test] fn request_user_note_order_makes_no_difference() { let one_way = new_test_ext().execute_with(|| { - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), ) }); new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); let other_way = ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), @@ -200,20 +200,20 @@ fn request_user_note_order_makes_no_difference() { #[test] fn unrequest_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_noop!( - Preimage::unrequest_preimage(Origin::signed(1), hashed([2])), + Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([2])), Error::::NotRequested ); - assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert!(Preimage::have_preimage(&hashed([1]))); - assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_noop!( - Preimage::unrequest_preimage(Origin::signed(1), hashed([1])), + Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])), Error::::NotRequested ); }); @@ -222,10 +222,10 @@ fn unrequest_preimage_works() { #[test] fn user_noted_then_requested_preimage_is_refunded_once_only() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1; 3])); - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1; 3])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1]))); // Still have reserve from `vec[1; 3]`. assert_eq!(Balances::reserved_balance(2), 5); assert_eq!(Balances::free_balance(2), 95); diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index dcc19e85085f8..af96069397255 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -113,7 +113,7 @@ pub mod pallet { /// The overarching call type. type RuntimeCall: Parameter - + Dispatchable + + Dispatchable + GetDispatchInfo + From> + IsSubType> @@ -819,7 +819,7 @@ impl Pallet { call: ::RuntimeCall, ) { // This is a freshly authenticated new account, the origin restrictions doesn't apply. - let mut origin: T::Origin = frame_system::RawOrigin::Signed(real).into(); + let mut origin: T::RuntimeOrigin = frame_system::RawOrigin::Signed(real).into(); origin.add_filter(move |c: &::RuntimeCall| { let c = ::RuntimeCall::from_ref(c); // We make sure the proxy call does access this pallet to change modify proxies. diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 0025b1510526e..3ed80107e0702 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -61,7 +61,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -204,7 +204,7 @@ fn call_transfer(dest: u64, value: u64) -> RuntimeCall { #[test] fn announcement_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); System::assert_last_event( ProxyEvent::ProxyAdded { delegator: 1, @@ -214,10 +214,10 @@ fn announcement_works() { } .into(), ); - assert_ok!(Proxy::add_proxy(Origin::signed(2), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); assert_eq!(Balances::reserved_balance(3), 0); - assert_ok!(Proxy::announce(Origin::signed(3), 1, [1; 32].into())); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, [1; 32].into())); let announcements = Announcements::::get(3); assert_eq!( announcements.0, @@ -225,7 +225,7 @@ fn announcement_works() { ); assert_eq!(Balances::reserved_balance(3), announcements.1); - assert_ok!(Proxy::announce(Origin::signed(3), 2, [2; 32].into())); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, [2; 32].into())); let announcements = Announcements::::get(3); assert_eq!( announcements.0, @@ -236,20 +236,23 @@ fn announcement_works() { ); assert_eq!(Balances::reserved_balance(3), announcements.1); - assert_noop!(Proxy::announce(Origin::signed(3), 2, [3; 32].into()), Error::::TooMany); + assert_noop!( + Proxy::announce(RuntimeOrigin::signed(3), 2, [3; 32].into()), + Error::::TooMany + ); }); } #[test] fn remove_announcement_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::add_proxy(Origin::signed(2), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::announce(Origin::signed(3), 1, [1; 32].into())); - assert_ok!(Proxy::announce(Origin::signed(3), 2, [2; 32].into())); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, [1; 32].into())); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, [2; 32].into())); let e = Error::::NotFound; - assert_noop!(Proxy::remove_announcement(Origin::signed(3), 1, [0; 32].into()), e); - assert_ok!(Proxy::remove_announcement(Origin::signed(3), 1, [1; 32].into())); + assert_noop!(Proxy::remove_announcement(RuntimeOrigin::signed(3), 1, [0; 32].into()), e); + assert_ok!(Proxy::remove_announcement(RuntimeOrigin::signed(3), 1, [1; 32].into())); let announcements = Announcements::::get(3); assert_eq!( announcements.0, @@ -262,15 +265,15 @@ fn remove_announcement_works() { #[test] fn reject_announcement_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::add_proxy(Origin::signed(2), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::announce(Origin::signed(3), 1, [1; 32].into())); - assert_ok!(Proxy::announce(Origin::signed(3), 2, [2; 32].into())); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, [1; 32].into())); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, [2; 32].into())); let e = Error::::NotFound; - assert_noop!(Proxy::reject_announcement(Origin::signed(1), 3, [0; 32].into()), e); + assert_noop!(Proxy::reject_announcement(RuntimeOrigin::signed(1), 3, [0; 32].into()), e); let e = Error::::NotFound; - assert_noop!(Proxy::reject_announcement(Origin::signed(4), 3, [1; 32].into()), e); - assert_ok!(Proxy::reject_announcement(Origin::signed(1), 3, [1; 32].into())); + assert_noop!(Proxy::reject_announcement(RuntimeOrigin::signed(4), 3, [1; 32].into()), e); + assert_ok!(Proxy::reject_announcement(RuntimeOrigin::signed(1), 3, [1; 32].into())); let announcements = Announcements::::get(3); assert_eq!( announcements.0, @@ -283,41 +286,44 @@ fn reject_announcement_works() { #[test] fn announcer_must_be_proxy() { new_test_ext().execute_with(|| { - assert_noop!(Proxy::announce(Origin::signed(2), 1, H256::zero()), Error::::NotProxy); + assert_noop!( + Proxy::announce(RuntimeOrigin::signed(2), 1, H256::zero()), + Error::::NotProxy + ); }); } #[test] fn delayed_requires_pre_announcement() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 2, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 1)); let call = Box::new(call_transfer(6, 1)); let e = Error::::Unannounced; - assert_noop!(Proxy::proxy(Origin::signed(2), 1, None, call.clone()), e); + assert_noop!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone()), e); let e = Error::::Unannounced; - assert_noop!(Proxy::proxy_announced(Origin::signed(0), 2, 1, None, call.clone()), e); + assert_noop!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 2, 1, None, call.clone()), e); let call_hash = BlakeTwo256::hash_of(&call); - assert_ok!(Proxy::announce(Origin::signed(2), 1, call_hash)); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(2), 1, call_hash)); system::Pallet::::set_block_number(2); - assert_ok!(Proxy::proxy_announced(Origin::signed(0), 2, 1, None, call.clone())); + assert_ok!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 2, 1, None, call.clone())); }); } #[test] fn proxy_announced_removes_announcement_and_returns_deposit() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::add_proxy(Origin::signed(2), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); let call = Box::new(call_transfer(6, 1)); let call_hash = BlakeTwo256::hash_of(&call); - assert_ok!(Proxy::announce(Origin::signed(3), 1, call_hash)); - assert_ok!(Proxy::announce(Origin::signed(3), 2, call_hash)); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, call_hash)); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, call_hash)); // Too early to execute announced call let e = Error::::Unannounced; - assert_noop!(Proxy::proxy_announced(Origin::signed(0), 3, 1, None, call.clone()), e); + assert_noop!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 3, 1, None, call.clone()), e); system::Pallet::::set_block_number(2); - assert_ok!(Proxy::proxy_announced(Origin::signed(0), 3, 1, None, call.clone())); + assert_ok!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 3, 1, None, call.clone())); let announcements = Announcements::::get(3); assert_eq!(announcements.0, vec![Announcement { real: 2, call_hash, height: 1 }]); assert_eq!(Balances::reserved_balance(3), announcements.1); @@ -328,16 +334,16 @@ fn proxy_announced_removes_announcement_and_returns_deposit() { fn filtering_works() { new_test_ext().execute_with(|| { assert!(Balances::mutate_account(&1, |a| a.free = 1000).is_ok()); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 2, ProxyType::Any, 0)); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::JustTransfer, 0)); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 4, ProxyType::JustUtility, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::JustTransfer, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 4, ProxyType::JustUtility, 0)); let call = Box::new(call_transfer(6, 1)); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); @@ -350,28 +356,28 @@ fn filtering_works() { index: 0, call: inner.clone(), })); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { calls: vec![*inner] })); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchCompleted.into(), ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchInterrupted { index: 0, error: SystemError::CallFiltered.into() } .into(), @@ -384,16 +390,16 @@ fn filtering_works() { 0, ))); let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { calls: vec![*inner] })); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchCompleted.into(), ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchInterrupted { index: 0, error: SystemError::CallFiltered.into() } .into(), @@ -401,15 +407,15 @@ fn filtering_works() { ]); let call = Box::new(RuntimeCall::Proxy(ProxyCall::remove_proxies {})); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); expect_events(vec![ BalancesEvent::::Unreserved { who: 1, amount: 5 }.into(), ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), @@ -420,27 +426,27 @@ fn filtering_works() { #[test] fn add_remove_proxies_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 2, ProxyType::Any, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); assert_noop!( - Proxy::add_proxy(Origin::signed(1), 2, ProxyType::Any, 0), + Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0), Error::::Duplicate ); assert_eq!(Balances::reserved_balance(1), 2); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 2, ProxyType::JustTransfer, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::JustTransfer, 0)); assert_eq!(Balances::reserved_balance(1), 3); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 0)); assert_eq!(Balances::reserved_balance(1), 4); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 4, ProxyType::JustUtility, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 4, ProxyType::JustUtility, 0)); assert_eq!(Balances::reserved_balance(1), 5); assert_noop!( - Proxy::add_proxy(Origin::signed(1), 4, ProxyType::Any, 0), + Proxy::add_proxy(RuntimeOrigin::signed(1), 4, ProxyType::Any, 0), Error::::TooMany ); assert_noop!( - Proxy::remove_proxy(Origin::signed(1), 3, ProxyType::JustTransfer, 0), + Proxy::remove_proxy(RuntimeOrigin::signed(1), 3, ProxyType::JustTransfer, 0), Error::::NotFound ); - assert_ok!(Proxy::remove_proxy(Origin::signed(1), 4, ProxyType::JustUtility, 0)); + assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 4, ProxyType::JustUtility, 0)); System::assert_last_event( ProxyEvent::ProxyRemoved { delegator: 1, @@ -451,7 +457,7 @@ fn add_remove_proxies_works() { .into(), ); assert_eq!(Balances::reserved_balance(1), 4); - assert_ok!(Proxy::remove_proxy(Origin::signed(1), 3, ProxyType::Any, 0)); + assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 0)); assert_eq!(Balances::reserved_balance(1), 3); System::assert_last_event( ProxyEvent::ProxyRemoved { @@ -462,7 +468,7 @@ fn add_remove_proxies_works() { } .into(), ); - assert_ok!(Proxy::remove_proxy(Origin::signed(1), 2, ProxyType::Any, 0)); + assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); assert_eq!(Balances::reserved_balance(1), 2); System::assert_last_event( ProxyEvent::ProxyRemoved { @@ -473,7 +479,7 @@ fn add_remove_proxies_works() { } .into(), ); - assert_ok!(Proxy::remove_proxy(Origin::signed(1), 2, ProxyType::JustTransfer, 0)); + assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 2, ProxyType::JustTransfer, 0)); assert_eq!(Balances::reserved_balance(1), 0); System::assert_last_event( ProxyEvent::ProxyRemoved { @@ -485,7 +491,7 @@ fn add_remove_proxies_works() { .into(), ); assert_noop!( - Proxy::add_proxy(Origin::signed(1), 1, ProxyType::Any, 0), + Proxy::add_proxy(RuntimeOrigin::signed(1), 1, ProxyType::Any, 0), Error::::NoSelfProxy ); }); @@ -494,10 +500,10 @@ fn add_remove_proxies_works() { #[test] fn cannot_add_proxy_without_balance() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(5), 3, ProxyType::Any, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(5), 3, ProxyType::Any, 0)); assert_eq!(Balances::reserved_balance(5), 2); assert_noop!( - Proxy::add_proxy(Origin::signed(5), 4, ProxyType::Any, 0), + Proxy::add_proxy(RuntimeOrigin::signed(5), 4, ProxyType::Any, 0), BalancesError::::InsufficientBalance ); }); @@ -506,24 +512,24 @@ fn cannot_add_proxy_without_balance() { #[test] fn proxying_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 2, ProxyType::JustTransfer, 0)); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::JustTransfer, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 0)); let call = Box::new(call_transfer(6, 1)); assert_noop!( - Proxy::proxy(Origin::signed(4), 1, None, call.clone()), + Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone()), Error::::NotProxy ); assert_noop!( - Proxy::proxy(Origin::signed(2), 1, Some(ProxyType::Any), call.clone()), + Proxy::proxy(RuntimeOrigin::signed(2), 1, Some(ProxyType::Any), call.clone()), Error::::NotProxy ); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 1); let call = Box::new(RuntimeCall::System(SystemCall::set_code { code: vec![] })); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); @@ -533,11 +539,11 @@ fn proxying_works() { value: 1, })); assert_ok!(RuntimeCall::Proxy(super::Call::new_call_variant_proxy(1, None, call.clone())) - .dispatch(Origin::signed(2))); + .dispatch(RuntimeOrigin::signed(2))); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 2); }); @@ -546,7 +552,7 @@ fn proxying_works() { #[test] fn anonymous_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 0)); + assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); let anon = Proxy::anonymous_account(&1, &ProxyType::Any, 0, None); System::assert_last_event( ProxyEvent::AnonymousCreated { @@ -559,23 +565,23 @@ fn anonymous_works() { ); // other calls to anonymous allowed as long as they're not exactly the same. - assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::JustTransfer, 0, 0)); - assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 1)); + assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::JustTransfer, 0, 0)); + assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::Any, 0, 1)); let anon2 = Proxy::anonymous_account(&2, &ProxyType::Any, 0, None); - assert_ok!(Proxy::anonymous(Origin::signed(2), ProxyType::Any, 0, 0)); + assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(2), ProxyType::Any, 0, 0)); assert_noop!( - Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 0), + Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0), Error::::Duplicate ); System::set_extrinsic_index(1); - assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 0)); + assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); System::set_extrinsic_index(0); System::set_block_number(2); - assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 0)); + assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); let call = Box::new(call_transfer(6, 1)); - assert_ok!(Balances::transfer(Origin::signed(3), anon, 5)); - assert_ok!(Proxy::proxy(Origin::signed(1), anon, None, call)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), anon, 5)); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call)); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 1); @@ -586,18 +592,18 @@ fn anonymous_works() { 1, 0, ))); - assert_ok!(Proxy::proxy(Origin::signed(2), anon2, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), anon2, None, call.clone())); let de = DispatchError::from(Error::::NoPermission).stripped(); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Err(de) }.into()); assert_noop!( - Proxy::kill_anonymous(Origin::signed(1), 1, ProxyType::Any, 0, 1, 0), + Proxy::kill_anonymous(RuntimeOrigin::signed(1), 1, ProxyType::Any, 0, 1, 0), Error::::NoPermission ); assert_eq!(Balances::free_balance(1), 0); - assert_ok!(Proxy::proxy(Origin::signed(1), anon, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call.clone())); assert_eq!(Balances::free_balance(1), 2); assert_noop!( - Proxy::proxy(Origin::signed(1), anon, None, call.clone()), + Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call.clone()), Error::::NotProxy ); }); diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index bd86cc0d4029d..be970ba2a8422 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -197,7 +197,7 @@ mod tests { type BlockWeights = (); type BlockLength = BlockLength; type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 44b942d000012..bdd5d26373980 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -241,12 +241,12 @@ impl, I: 'static> GetMaxVoters for Pallet { /// Guard to ensure that the given origin is a member of the collective. The rank of the member is /// the `Success` value. pub struct EnsureRanked(PhantomData<(T, I)>); -impl, I: 'static, const MIN_RANK: u16> EnsureOrigin +impl, I: 'static, const MIN_RANK: u16> EnsureOrigin for EnsureRanked { type Success = Rank; - fn try_origin(o: T::Origin) -> Result { + fn try_origin(o: T::RuntimeOrigin) -> Result { let who = frame_system::EnsureSigned::try_origin(o)?; match Members::::get(&who) { Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok(rank), @@ -255,13 +255,13 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin } #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { + fn try_successful_origin() -> Result { let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::Origin { + fn successful_origin() -> T::RuntimeOrigin { match Self::try_successful_origin() { Ok(o) => o, Err(()) => { @@ -277,12 +277,12 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin /// Guard to ensure that the given origin is a member of the collective. The account ID of the /// member is the `Success` value. pub struct EnsureMember(PhantomData<(T, I)>); -impl, I: 'static, const MIN_RANK: u16> EnsureOrigin +impl, I: 'static, const MIN_RANK: u16> EnsureOrigin for EnsureMember { type Success = T::AccountId; - fn try_origin(o: T::Origin) -> Result { + fn try_origin(o: T::RuntimeOrigin) -> Result { let who = frame_system::EnsureSigned::try_origin(o)?; match Members::::get(&who) { Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok(who), @@ -291,13 +291,13 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin } #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { + fn try_successful_origin() -> Result { let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::Origin { + fn successful_origin() -> T::RuntimeOrigin { match Self::try_successful_origin() { Ok(o) => o, Err(()) => { @@ -313,12 +313,12 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin /// Guard to ensure that the given origin is a member of the collective. The pair of including both /// the account ID and the rank of the member is the `Success` value. pub struct EnsureRankedMember(PhantomData<(T, I)>); -impl, I: 'static, const MIN_RANK: u16> EnsureOrigin +impl, I: 'static, const MIN_RANK: u16> EnsureOrigin for EnsureRankedMember { type Success = (T::AccountId, Rank); - fn try_origin(o: T::Origin) -> Result { + fn try_origin(o: T::RuntimeOrigin) -> Result { let who = frame_system::EnsureSigned::try_origin(o)?; match Members::::get(&who) { Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok((who, rank)), @@ -327,13 +327,13 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin } #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { + fn try_successful_origin() -> Result { let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::Origin { + fn successful_origin() -> T::RuntimeOrigin { match Self::try_successful_origin() { Ok(o) => o, Err(()) => { @@ -367,11 +367,11 @@ pub mod pallet { /// The origin required to add or promote a mmember. The success value indicates the /// maximum rank *to which* the promotion may be. - type PromoteOrigin: EnsureOrigin; + type PromoteOrigin: EnsureOrigin; /// The origin required to demote or remove a member. The success value indicates the /// maximum rank *from which* the demotion/removal may be. - type DemoteOrigin: EnsureOrigin; + type DemoteOrigin: EnsureOrigin; /// The polling system used for our voting. type Polls: Polling, Votes = Votes, Moment = Self::BlockNumber>; diff --git a/frame/ranked-collective/src/tests.rs b/frame/ranked-collective/src/tests.rs index 25413b490483c..68bb79f3d07f7 100644 --- a/frame/ranked-collective/src/tests.rs +++ b/frame/ranked-collective/src/tests.rs @@ -58,7 +58,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -239,10 +239,10 @@ fn basic_stuff() { #[test] fn member_lifecycle_works() { new_test_ext().execute_with(|| { - assert_ok!(Club::add_member(Origin::root(), 1)); - assert_ok!(Club::promote_member(Origin::root(), 1)); - assert_ok!(Club::demote_member(Origin::root(), 1)); - assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 0); assert_eq!(member_count(1), 0); }); @@ -251,29 +251,29 @@ fn member_lifecycle_works() { #[test] fn add_remove_works() { new_test_ext().execute_with(|| { - assert_noop!(Club::add_member(Origin::signed(1), 1), DispatchError::BadOrigin); - assert_ok!(Club::add_member(Origin::root(), 1)); + assert_noop!(Club::add_member(RuntimeOrigin::signed(1), 1), DispatchError::BadOrigin); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); - assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 0); - assert_ok!(Club::add_member(Origin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); - assert_ok!(Club::add_member(Origin::root(), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); assert_eq!(member_count(0), 2); - assert_ok!(Club::add_member(Origin::root(), 3)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 3)); assert_eq!(member_count(0), 3); - assert_ok!(Club::demote_member(Origin::root(), 3)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 3)); assert_eq!(member_count(0), 2); - assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); - assert_ok!(Club::demote_member(Origin::root(), 2)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 2)); assert_eq!(member_count(0), 0); }); } @@ -281,29 +281,29 @@ fn add_remove_works() { #[test] fn promote_demote_works() { new_test_ext().execute_with(|| { - assert_noop!(Club::add_member(Origin::signed(1), 1), DispatchError::BadOrigin); - assert_ok!(Club::add_member(Origin::root(), 1)); + assert_noop!(Club::add_member(RuntimeOrigin::signed(1), 1), DispatchError::BadOrigin); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); assert_eq!(member_count(1), 0); - assert_ok!(Club::add_member(Origin::root(), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); assert_eq!(member_count(0), 2); assert_eq!(member_count(1), 0); - assert_ok!(Club::promote_member(Origin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 2); assert_eq!(member_count(1), 1); - assert_ok!(Club::promote_member(Origin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); assert_eq!(member_count(0), 2); assert_eq!(member_count(1), 2); - assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 2); assert_eq!(member_count(1), 1); - assert_noop!(Club::demote_member(Origin::signed(1), 1), DispatchError::BadOrigin); - assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_noop!(Club::demote_member(RuntimeOrigin::signed(1), 1), DispatchError::BadOrigin); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); assert_eq!(member_count(1), 1); }); @@ -312,88 +312,100 @@ fn promote_demote_works() { #[test] fn promote_demote_by_rank_works() { new_test_ext().execute_with(|| { - assert_ok!(Club::add_member(Origin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); for _ in 0..7 { - assert_ok!(Club::promote_member(Origin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); } // #1 can add #2 and promote to rank 1 - assert_ok!(Club::add_member(Origin::signed(1), 2)); - assert_ok!(Club::promote_member(Origin::signed(1), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(1), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(1), 2)); // #2 as rank 1 cannot do anything privileged - assert_noop!(Club::add_member(Origin::signed(2), 3), BadOrigin); + assert_noop!(Club::add_member(RuntimeOrigin::signed(2), 3), BadOrigin); - assert_ok!(Club::promote_member(Origin::signed(1), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(1), 2)); // #2 as rank 2 can add #3. - assert_ok!(Club::add_member(Origin::signed(2), 3)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(2), 3)); // #2 as rank 2 cannot promote #3 to rank 1 - assert_noop!(Club::promote_member(Origin::signed(2), 3), Error::::NoPermission); + assert_noop!( + Club::promote_member(RuntimeOrigin::signed(2), 3), + Error::::NoPermission + ); // #1 as rank 7 can promote #2 only up to rank 5 and once there cannot demote them. - assert_ok!(Club::promote_member(Origin::signed(1), 2)); - assert_ok!(Club::promote_member(Origin::signed(1), 2)); - assert_ok!(Club::promote_member(Origin::signed(1), 2)); - assert_noop!(Club::promote_member(Origin::signed(1), 2), Error::::NoPermission); - assert_noop!(Club::demote_member(Origin::signed(1), 2), Error::::NoPermission); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(1), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(1), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(1), 2)); + assert_noop!( + Club::promote_member(RuntimeOrigin::signed(1), 2), + Error::::NoPermission + ); + assert_noop!(Club::demote_member(RuntimeOrigin::signed(1), 2), Error::::NoPermission); // #2 as rank 5 can promote #3 only up to rank 3 and once there cannot demote them. - assert_ok!(Club::promote_member(Origin::signed(2), 3)); - assert_ok!(Club::promote_member(Origin::signed(2), 3)); - assert_ok!(Club::promote_member(Origin::signed(2), 3)); - assert_noop!(Club::promote_member(Origin::signed(2), 3), Error::::NoPermission); - assert_noop!(Club::demote_member(Origin::signed(2), 3), Error::::NoPermission); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(2), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(2), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(2), 3)); + assert_noop!( + Club::promote_member(RuntimeOrigin::signed(2), 3), + Error::::NoPermission + ); + assert_noop!(Club::demote_member(RuntimeOrigin::signed(2), 3), Error::::NoPermission); // #2 can add #4 & #5 as rank 0 and #6 & #7 as rank 1. - assert_ok!(Club::add_member(Origin::signed(2), 4)); - assert_ok!(Club::add_member(Origin::signed(2), 5)); - assert_ok!(Club::add_member(Origin::signed(2), 6)); - assert_ok!(Club::promote_member(Origin::signed(2), 6)); - assert_ok!(Club::add_member(Origin::signed(2), 7)); - assert_ok!(Club::promote_member(Origin::signed(2), 7)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(2), 4)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(2), 5)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(2), 6)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(2), 6)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(2), 7)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(2), 7)); // #3 as rank 3 can demote/remove #4 & #5 but not #6 & #7 - assert_ok!(Club::demote_member(Origin::signed(3), 4)); - assert_ok!(Club::remove_member(Origin::signed(3), 5, 0)); - assert_noop!(Club::demote_member(Origin::signed(3), 6), Error::::NoPermission); - assert_noop!(Club::remove_member(Origin::signed(3), 7, 1), Error::::NoPermission); + assert_ok!(Club::demote_member(RuntimeOrigin::signed(3), 4)); + assert_ok!(Club::remove_member(RuntimeOrigin::signed(3), 5, 0)); + assert_noop!(Club::demote_member(RuntimeOrigin::signed(3), 6), Error::::NoPermission); + assert_noop!( + Club::remove_member(RuntimeOrigin::signed(3), 7, 1), + Error::::NoPermission + ); // #2 as rank 5 can demote/remove #6 & #7 - assert_ok!(Club::demote_member(Origin::signed(2), 6)); - assert_ok!(Club::remove_member(Origin::signed(2), 7, 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::signed(2), 6)); + assert_ok!(Club::remove_member(RuntimeOrigin::signed(2), 7, 1)); }); } #[test] fn voting_works() { new_test_ext().execute_with(|| { - assert_ok!(Club::add_member(Origin::root(), 0)); - assert_ok!(Club::add_member(Origin::root(), 1)); - assert_ok!(Club::promote_member(Origin::root(), 1)); - assert_ok!(Club::add_member(Origin::root(), 2)); - assert_ok!(Club::promote_member(Origin::root(), 2)); - assert_ok!(Club::promote_member(Origin::root(), 2)); - assert_ok!(Club::add_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - - assert_noop!(Club::vote(Origin::signed(0), 3, true), Error::::RankTooLow); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 0)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + + assert_noop!(Club::vote(RuntimeOrigin::signed(0), 3, true), Error::::RankTooLow); assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); - assert_ok!(Club::vote(Origin::signed(1), 3, true)); + assert_ok!(Club::vote(RuntimeOrigin::signed(1), 3, true)); assert_eq!(tally(3), Tally::from_parts(1, 1, 0)); - assert_ok!(Club::vote(Origin::signed(1), 3, false)); + assert_ok!(Club::vote(RuntimeOrigin::signed(1), 3, false)); assert_eq!(tally(3), Tally::from_parts(0, 0, 1)); - assert_ok!(Club::vote(Origin::signed(2), 3, true)); + assert_ok!(Club::vote(RuntimeOrigin::signed(2), 3, true)); assert_eq!(tally(3), Tally::from_parts(1, 3, 1)); - assert_ok!(Club::vote(Origin::signed(2), 3, false)); + assert_ok!(Club::vote(RuntimeOrigin::signed(2), 3, false)); assert_eq!(tally(3), Tally::from_parts(0, 0, 4)); - assert_ok!(Club::vote(Origin::signed(3), 3, true)); + assert_ok!(Club::vote(RuntimeOrigin::signed(3), 3, true)); assert_eq!(tally(3), Tally::from_parts(1, 6, 4)); - assert_ok!(Club::vote(Origin::signed(3), 3, false)); + assert_ok!(Club::vote(RuntimeOrigin::signed(3), 3, false)); assert_eq!(tally(3), Tally::from_parts(0, 0, 10)); }); } @@ -401,59 +413,78 @@ fn voting_works() { #[test] fn cleanup_works() { new_test_ext().execute_with(|| { - assert_ok!(Club::add_member(Origin::root(), 1)); - assert_ok!(Club::promote_member(Origin::root(), 1)); - assert_ok!(Club::add_member(Origin::root(), 2)); - assert_ok!(Club::promote_member(Origin::root(), 2)); - assert_ok!(Club::add_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - - assert_ok!(Club::vote(Origin::signed(1), 3, true)); - assert_ok!(Club::vote(Origin::signed(2), 3, false)); - assert_ok!(Club::vote(Origin::signed(3), 3, true)); - - assert_noop!(Club::cleanup_poll(Origin::signed(4), 3, 10), Error::::Ongoing); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + + assert_ok!(Club::vote(RuntimeOrigin::signed(1), 3, true)); + assert_ok!(Club::vote(RuntimeOrigin::signed(2), 3, false)); + assert_ok!(Club::vote(RuntimeOrigin::signed(3), 3, true)); + + assert_noop!(Club::cleanup_poll(RuntimeOrigin::signed(4), 3, 10), Error::::Ongoing); Polls::set( vec![(1, Completed(1, true)), (2, Completed(2, false)), (3, Completed(3, true))] .into_iter() .collect(), ); - assert_ok!(Club::cleanup_poll(Origin::signed(4), 3, 10)); + assert_ok!(Club::cleanup_poll(RuntimeOrigin::signed(4), 3, 10)); // NOTE: This will fail until #10016 is merged. - // assert_noop!(Club::cleanup_poll(Origin::signed(4), 3, 10), Error::::NoneRemaining); + // assert_noop!(Club::cleanup_poll(RuntimeOrigin::signed(4), 3, 10), + // Error::::NoneRemaining); }); } #[test] fn ensure_ranked_works() { new_test_ext().execute_with(|| { - assert_ok!(Club::add_member(Origin::root(), 1)); - assert_ok!(Club::promote_member(Origin::root(), 1)); - assert_ok!(Club::add_member(Origin::root(), 2)); - assert_ok!(Club::promote_member(Origin::root(), 2)); - assert_ok!(Club::promote_member(Origin::root(), 2)); - assert_ok!(Club::add_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); use frame_support::traits::OriginTrait; type Rank1 = EnsureRanked; type Rank2 = EnsureRanked; type Rank3 = EnsureRanked; type Rank4 = EnsureRanked; - assert_eq!(Rank1::try_origin(Origin::signed(1)).unwrap(), 1); - assert_eq!(Rank1::try_origin(Origin::signed(2)).unwrap(), 2); - assert_eq!(Rank1::try_origin(Origin::signed(3)).unwrap(), 3); - assert_eq!(Rank2::try_origin(Origin::signed(1)).unwrap_err().as_signed().unwrap(), 1); - assert_eq!(Rank2::try_origin(Origin::signed(2)).unwrap(), 2); - assert_eq!(Rank2::try_origin(Origin::signed(3)).unwrap(), 3); - assert_eq!(Rank3::try_origin(Origin::signed(1)).unwrap_err().as_signed().unwrap(), 1); - assert_eq!(Rank3::try_origin(Origin::signed(2)).unwrap_err().as_signed().unwrap(), 2); - assert_eq!(Rank3::try_origin(Origin::signed(3)).unwrap(), 3); - assert_eq!(Rank4::try_origin(Origin::signed(1)).unwrap_err().as_signed().unwrap(), 1); - assert_eq!(Rank4::try_origin(Origin::signed(2)).unwrap_err().as_signed().unwrap(), 2); - assert_eq!(Rank4::try_origin(Origin::signed(3)).unwrap_err().as_signed().unwrap(), 3); + assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(1)).unwrap(), 1); + assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2); + assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); + assert_eq!( + Rank2::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(), + 1 + ); + assert_eq!(Rank2::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2); + assert_eq!(Rank2::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); + assert_eq!( + Rank3::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(), + 1 + ); + assert_eq!( + Rank3::try_origin(RuntimeOrigin::signed(2)).unwrap_err().as_signed().unwrap(), + 2 + ); + assert_eq!(Rank3::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); + assert_eq!( + Rank4::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(), + 1 + ); + assert_eq!( + Rank4::try_origin(RuntimeOrigin::signed(2)).unwrap_err().as_signed().unwrap(), + 2 + ); + assert_eq!( + Rank4::try_origin(RuntimeOrigin::signed(3)).unwrap_err().as_signed().unwrap(), + 3 + ); }); } diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index 7b85c119e68c5..0b6b7b0f51d9a 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -232,7 +232,7 @@ pub mod pallet { /// The overarching call type. type RuntimeCall: Parameter - + Dispatchable + + Dispatchable + GetDispatchInfo + From>; diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 6496ceb253b77..2a29390fdd20f 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -55,7 +55,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/frame/recovery/src/tests.rs b/frame/recovery/src/tests.rs index a3f19e5a61bc8..b037a8110147d 100644 --- a/frame/recovery/src/tests.rs +++ b/frame/recovery/src/tests.rs @@ -20,8 +20,8 @@ use super::*; use frame_support::{assert_noop, assert_ok, bounded_vec, traits::Currency}; use mock::{ - new_test_ext, run_to_block, Balances, BalancesCall, MaxFriends, Origin, Recovery, RecoveryCall, - RuntimeCall, Test, + new_test_ext, run_to_block, Balances, BalancesCall, MaxFriends, Recovery, RecoveryCall, + RuntimeCall, RuntimeOrigin, Test, }; use sp_runtime::traits::BadOrigin; @@ -41,12 +41,12 @@ fn basic_setup_works() { fn set_recovered_works() { new_test_ext().execute_with(|| { // Not accessible by a normal user - assert_noop!(Recovery::set_recovered(Origin::signed(1), 5, 1), BadOrigin); + assert_noop!(Recovery::set_recovered(RuntimeOrigin::signed(1), 5, 1), BadOrigin); // Root can set a recovered account though - assert_ok!(Recovery::set_recovered(Origin::root(), 5, 1)); + assert_ok!(Recovery::set_recovered(RuntimeOrigin::root(), 5, 1)); // Account 1 should now be able to make a call through account 5 let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 1, value: 100 })); - assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); + assert_ok!(Recovery::as_recovered(RuntimeOrigin::signed(1), 5, call)); // Account 1 has successfully drained the funds from account 5 assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(5), 0); @@ -60,38 +60,46 @@ fn recovery_life_cycle_works() { let threshold = 3; let delay_period = 10; // Account 5 sets up a recovery configuration on their account - assert_ok!(Recovery::create_recovery(Origin::signed(5), friends, threshold, delay_period)); + assert_ok!(Recovery::create_recovery( + RuntimeOrigin::signed(5), + friends, + threshold, + delay_period + )); // Some time has passed, and the user lost their keys! run_to_block(10); // Using account 1, the user begins the recovery process to recover the lost account - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Off chain, the user contacts their friends and asks them to vouch for the recovery // attempt - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(4), 5, 1)); // We met the threshold, lets try to recover the account...? - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::DelayPeriod); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::DelayPeriod + ); // We need to wait at least the delay_period number of blocks before we can recover run_to_block(20); - assert_ok!(Recovery::claim_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::claim_recovery(RuntimeOrigin::signed(1), 5)); // Account 1 can use account 5 to close the active recovery process, claiming the deposited // funds used to initiate the recovery process into account 5. let call = Box::new(RuntimeCall::Recovery(RecoveryCall::close_recovery { rescuer: 1 })); - assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); + assert_ok!(Recovery::as_recovered(RuntimeOrigin::signed(1), 5, call)); // Account 1 can then use account 5 to remove the recovery configuration, claiming the // deposited funds used to create the recovery configuration into account 5. let call = Box::new(RuntimeCall::Recovery(RecoveryCall::remove_recovery {})); - assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); + assert_ok!(Recovery::as_recovered(RuntimeOrigin::signed(1), 5, call)); // Account 1 should now be able to make a call through account 5 to get all of their funds assert_eq!(Balances::free_balance(5), 110); let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 1, value: 110 })); - assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); + assert_ok!(Recovery::as_recovered(RuntimeOrigin::signed(1), 5, call)); // All funds have been fully recovered! assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(5), 0); // Remove the proxy link. - assert_ok!(Recovery::cancel_recovered(Origin::signed(1), 5)); + assert_ok!(Recovery::cancel_recovered(RuntimeOrigin::signed(1), 5)); // All storage items are removed from the module assert!(!>::contains_key(&5, &1)); @@ -107,38 +115,52 @@ fn malicious_recovery_fails() { let threshold = 3; let delay_period = 10; // Account 5 sets up a recovery configuration on their account - assert_ok!(Recovery::create_recovery(Origin::signed(5), friends, threshold, delay_period)); + assert_ok!(Recovery::create_recovery( + RuntimeOrigin::signed(5), + friends, + threshold, + delay_period + )); // Some time has passed, and account 1 wants to try and attack this account! run_to_block(10); // Using account 1, the malicious user begins the recovery process on account 5 - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Off chain, the user **tricks** their friends and asks them to vouch for the recovery - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); // shame on you - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 1)); // shame on you - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(4), 5, 1)); // shame on you // We met the threshold, lets try to recover the account...? - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::DelayPeriod); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::DelayPeriod + ); // Account 1 needs to wait... run_to_block(19); // One more block to wait! - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::DelayPeriod); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::DelayPeriod + ); // Account 5 checks their account every `delay_period` and notices the malicious attack! // Account 5 can close the recovery process before account 1 can claim it - assert_ok!(Recovery::close_recovery(Origin::signed(5), 1)); + assert_ok!(Recovery::close_recovery(RuntimeOrigin::signed(5), 1)); // By doing so, account 5 has now claimed the deposit originally reserved by account 1 assert_eq!(Balances::total_balance(&1), 90); // Thanks for the free money! assert_eq!(Balances::total_balance(&5), 110); // The recovery process has been closed, so account 1 can't make the claim run_to_block(20); - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::NotStarted); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::NotStarted + ); // Account 5 can remove their recovery config and pick some better friends - assert_ok!(Recovery::remove_recovery(Origin::signed(5))); + assert_ok!(Recovery::remove_recovery(RuntimeOrigin::signed(5))); assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), vec![22, 33, 44], threshold, delay_period @@ -151,23 +173,23 @@ fn create_recovery_handles_basic_errors() { new_test_ext().execute_with(|| { // No friends assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![], 1, 0), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![], 1, 0), Error::::NotEnoughFriends ); // Zero threshold assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![2], 0, 0), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![2], 0, 0), Error::::ZeroThreshold ); // Threshold greater than friends length assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![2, 3, 4], 4, 0), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![2, 3, 4], 4, 0), Error::::NotEnoughFriends ); // Too many friends assert_noop!( Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), vec![1; (MaxFriends::get() + 1) as usize], 1, 0 @@ -176,18 +198,18 @@ fn create_recovery_handles_basic_errors() { ); // Unsorted friends assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![3, 2, 4], 3, 0), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![3, 2, 4], 3, 0), Error::::NotSorted ); // Duplicate friends assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![2, 2, 4], 3, 0), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![2, 2, 4], 3, 0), Error::::NotSorted ); // Already configured - assert_ok!(Recovery::create_recovery(Origin::signed(5), vec![2, 3, 4], 3, 10)); + assert_ok!(Recovery::create_recovery(RuntimeOrigin::signed(5), vec![2, 3, 4], 3, 10)); assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![2, 3, 4], 3, 10), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![2, 3, 4], 3, 10), Error::::AlreadyRecoverable ); }); @@ -201,7 +223,7 @@ fn create_recovery_works() { let delay_period = 10; // Account 5 sets up a recovery configuration on their account assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period @@ -225,7 +247,7 @@ fn initiate_recovery_handles_basic_errors() { new_test_ext().execute_with(|| { // No recovery process set up for the account assert_noop!( - Recovery::initiate_recovery(Origin::signed(1), 5), + Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5), Error::::NotRecoverable ); // Create a recovery process for next test @@ -233,15 +255,15 @@ fn initiate_recovery_handles_basic_errors() { let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); // Same user cannot recover same account twice - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); assert_noop!( - Recovery::initiate_recovery(Origin::signed(1), 5), + Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5), Error::::AlreadyStarted ); // No double deposit @@ -257,13 +279,13 @@ fn initiate_recovery_works() { let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); // Recovery can be initiated - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Deposit is reserved assert_eq!(Balances::reserved_balance(1), 10); // Recovery status object is created correctly @@ -271,7 +293,7 @@ fn initiate_recovery_works() { ActiveRecovery { created: 0, deposit: 10, friends: Default::default() }; assert_eq!(>::get(&5, &1), Some(recovery_status)); // Multiple users can attempt to recover the same account - assert_ok!(Recovery::initiate_recovery(Origin::signed(2), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(2), 5)); }); } @@ -280,7 +302,7 @@ fn vouch_recovery_handles_basic_errors() { new_test_ext().execute_with(|| { // Cannot vouch for non-recoverable account assert_noop!( - Recovery::vouch_recovery(Origin::signed(2), 5, 1), + Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1), Error::::NotRecoverable ); // Create a recovery process for next tests @@ -288,21 +310,27 @@ fn vouch_recovery_handles_basic_errors() { let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); // Cannot vouch a recovery process that has not started - assert_noop!(Recovery::vouch_recovery(Origin::signed(2), 5, 1), Error::::NotStarted); + assert_noop!( + Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1), + Error::::NotStarted + ); // Initiate a recovery process - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Cannot vouch if you are not a friend - assert_noop!(Recovery::vouch_recovery(Origin::signed(22), 5, 1), Error::::NotFriend); + assert_noop!( + Recovery::vouch_recovery(RuntimeOrigin::signed(22), 5, 1), + Error::::NotFriend + ); // Cannot vouch twice - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); assert_noop!( - Recovery::vouch_recovery(Origin::signed(2), 5, 1), + Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1), Error::::AlreadyVouched ); }); @@ -316,17 +344,17 @@ fn vouch_recovery_works() { let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Vouching works - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); // Handles out of order vouches - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(4), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 1)); // Final recovery status object is updated correctly let recovery_status = ActiveRecovery { created: 0, deposit: 10, friends: bounded_vec![2, 3, 4] }; @@ -338,28 +366,40 @@ fn vouch_recovery_works() { fn claim_recovery_handles_basic_errors() { new_test_ext().execute_with(|| { // Cannot claim a non-recoverable account - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::NotRecoverable); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::NotRecoverable + ); // Create a recovery process for the test let friends = vec![2, 3, 4]; let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); // Cannot claim an account which has not started the recovery process - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::NotStarted); - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::NotStarted + ); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Cannot claim an account which has not passed the delay period - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::DelayPeriod); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::DelayPeriod + ); run_to_block(11); // Cannot claim an account which has not passed the threshold number of votes - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 1)); // Only 2/3 is not good enough - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::Threshold); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::Threshold + ); }); } @@ -371,32 +411,32 @@ fn claim_recovery_works() { let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(4), 5, 1)); run_to_block(11); // Account can be recovered. - assert_ok!(Recovery::claim_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::claim_recovery(RuntimeOrigin::signed(1), 5)); // Recovered storage item is correctly created assert_eq!(>::get(&1), Some(5)); // Account could be re-recovered in the case that the recoverer account also gets lost. - assert_ok!(Recovery::initiate_recovery(Origin::signed(4), 5)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 4)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 4)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 4)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(4), 5)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 4)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 4)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(4), 5, 4)); run_to_block(21); // Account is re-recovered. - assert_ok!(Recovery::claim_recovery(Origin::signed(4), 5)); + assert_ok!(Recovery::claim_recovery(RuntimeOrigin::signed(4), 5)); // Recovered storage item is correctly updated assert_eq!(>::get(&4), Some(5)); }); @@ -406,7 +446,10 @@ fn claim_recovery_works() { fn close_recovery_handles_basic_errors() { new_test_ext().execute_with(|| { // Cannot close a non-active recovery - assert_noop!(Recovery::close_recovery(Origin::signed(5), 1), Error::::NotStarted); + assert_noop!( + Recovery::close_recovery(RuntimeOrigin::signed(5), 1), + Error::::NotStarted + ); }); } @@ -414,26 +457,35 @@ fn close_recovery_handles_basic_errors() { fn remove_recovery_works() { new_test_ext().execute_with(|| { // Cannot remove an unrecoverable account - assert_noop!(Recovery::remove_recovery(Origin::signed(5)), Error::::NotRecoverable); + assert_noop!( + Recovery::remove_recovery(RuntimeOrigin::signed(5)), + Error::::NotRecoverable + ); // Create and initiate a recovery process for the test let friends = vec![2, 3, 4]; let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); - assert_ok!(Recovery::initiate_recovery(Origin::signed(2), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(2), 5)); // Cannot remove a recovery when there are active recoveries. - assert_noop!(Recovery::remove_recovery(Origin::signed(5)), Error::::StillActive); - assert_ok!(Recovery::close_recovery(Origin::signed(5), 1)); + assert_noop!( + Recovery::remove_recovery(RuntimeOrigin::signed(5)), + Error::::StillActive + ); + assert_ok!(Recovery::close_recovery(RuntimeOrigin::signed(5), 1)); // Still need to remove one more! - assert_noop!(Recovery::remove_recovery(Origin::signed(5)), Error::::StillActive); - assert_ok!(Recovery::close_recovery(Origin::signed(5), 2)); + assert_noop!( + Recovery::remove_recovery(RuntimeOrigin::signed(5)), + Error::::StillActive + ); + assert_ok!(Recovery::close_recovery(RuntimeOrigin::signed(5), 2)); // Finally removed - assert_ok!(Recovery::remove_recovery(Origin::signed(5))); + assert_ok!(Recovery::remove_recovery(RuntimeOrigin::signed(5))); }); } diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 2116d56f4647b..45ec894e2c2c0 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -42,8 +42,8 @@ fn funded_account, I: 'static>(name: &'static str, index: u32) -> T caller } -fn create_referendum, I: 'static>() -> (T::Origin, ReferendumIndex) { - let origin: T::Origin = T::SubmitOrigin::successful_origin(); +fn create_referendum, I: 'static>() -> (T::RuntimeOrigin, ReferendumIndex) { + let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin(); if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); whitelist_account!(caller); @@ -188,12 +188,12 @@ fn is_not_confirming, I: 'static>(index: ReferendumIndex) -> bool { benchmarks_instance_pallet! { submit { - let origin: T::Origin = T::SubmitOrigin::successful_origin(); + let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin(); if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); whitelist_account!(caller); } - }: _( + }: _( origin, Box::new(RawOrigin::Root.into()), T::Hashing::hash_of(&0), @@ -205,7 +205,7 @@ benchmarks_instance_pallet! { place_decision_deposit_preparing { let (origin, index) = create_referendum::(); - }: place_decision_deposit(origin, index) + }: place_decision_deposit(origin, index) verify { assert!(Referenda::::ensure_ongoing(index).unwrap().decision_deposit.is_some()); } @@ -213,7 +213,7 @@ benchmarks_instance_pallet! { place_decision_deposit_queued { let (origin, index) = create_referendum::(); fill_queue::(index, 1, 90); - }: place_decision_deposit(origin, index) + }: place_decision_deposit(origin, index) verify { let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); @@ -226,7 +226,7 @@ benchmarks_instance_pallet! { let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); - }: place_decision_deposit(origin, index) + }: place_decision_deposit(origin, index) verify { assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); @@ -236,7 +236,7 @@ benchmarks_instance_pallet! { let (origin, index) = create_referendum::(); skip_prepare_period::(index); make_passing::(index); - }: place_decision_deposit(origin, index) + }: place_decision_deposit(origin, index) verify { assert!(is_confirming::(index)); } @@ -244,7 +244,7 @@ benchmarks_instance_pallet! { place_decision_deposit_failing { let (origin, index) = create_referendum::(); skip_prepare_period::(index); - }: place_decision_deposit(origin, index) + }: place_decision_deposit(origin, index) verify { assert!(is_not_confirming::(index)); } @@ -253,7 +253,7 @@ benchmarks_instance_pallet! { let (origin, index) = create_referendum::(); place_deposit::(index); assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); - }: _(origin, index) + }: _(origin, index) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, _, None))); } @@ -261,7 +261,7 @@ benchmarks_instance_pallet! { cancel { let (_origin, index) = create_referendum::(); place_deposit::(index); - }: _(T::CancelOrigin::successful_origin(), index) + }: _(T::CancelOrigin::successful_origin(), index) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(..))); } @@ -269,7 +269,7 @@ benchmarks_instance_pallet! { kill { let (_origin, index) = create_referendum::(); place_deposit::(index); - }: _(T::KillOrigin::successful_origin(), index) + }: _(T::KillOrigin::successful_origin(), index) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Killed(..))); } diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index a2a5aae4e617b..739f0dbc30ed4 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -147,7 +147,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + Sized { // System level stuff. - type RuntimeCall: Parameter + Dispatchable + From>; + type RuntimeCall: Parameter + + Dispatchable + + From>; type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. @@ -168,11 +170,11 @@ pub mod pallet { type Currency: ReservableCurrency; // Origins and unbalances. /// Origin from which proposals may be submitted. - type SubmitOrigin: EnsureOrigin; + type SubmitOrigin: EnsureOrigin; /// Origin from which any vote may be cancelled. - type CancelOrigin: EnsureOrigin; + type CancelOrigin: EnsureOrigin; /// Origin from which any vote may be killed. - type KillOrigin: EnsureOrigin; + type KillOrigin: EnsureOrigin; /// Handler for the unbalanced reduction when slashing a preimage deposit. type Slash: OnUnbalanced>; /// The counting type for votes. Usually just balance. @@ -217,7 +219,7 @@ pub mod pallet { > + TracksInfo< BalanceOf, Self::BlockNumber, - Origin = ::PalletsOrigin, + RuntimeOrigin = ::PalletsOrigin, >; } diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 70ca304eed3cb..920e529bf05ca 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -71,7 +71,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -103,7 +103,7 @@ impl pallet_preimage::Config for Test { } impl pallet_scheduler::Config for Test { type RuntimeEvent = RuntimeEvent; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type PalletsOrigin = OriginCaller; type RuntimeCall = RuntimeCall; type MaximumWeight = MaxWeight; @@ -148,7 +148,7 @@ impl SortedMembers for OneToFive { pub struct TestTracksInfo; impl TracksInfo for TestTracksInfo { type Id = u8; - type Origin = ::PalletsOrigin; + type RuntimeOrigin = ::PalletsOrigin; fn tracks() -> &'static [(Self::Id, TrackInfo)] { static DATA: [(u8, TrackInfo); 2] = [ ( @@ -198,7 +198,7 @@ impl TracksInfo for TestTracksInfo { ]; &DATA[..] } - fn track_for(id: &Self::Origin) -> Result { + fn track_for(id: &Self::RuntimeOrigin) -> Result { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { match system_origin { frame_system::RawOrigin::Root => Ok(0), @@ -319,7 +319,7 @@ pub fn set_balance_proposal_hash(value: u64) -> H256 { #[allow(dead_code)] pub fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult { Referenda::submit( - Origin::signed(who), + RuntimeOrigin::signed(who), Box::new(frame_system::RawOrigin::Root.into()), set_balance_proposal_hash(value), DispatchTime::After(delay), @@ -447,12 +447,12 @@ pub enum RefState { impl RefState { pub fn create(self) -> ReferendumIndex { assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(frame_support::dispatch::RawOrigin::Root.into()), set_balance_proposal_hash(1), DispatchTime::At(10), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); if matches!(self, RefState::Confirming { immediate: true }) { set_tally(0, 100, 0); } diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index 69cd62f79159a..778d00e516693 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -42,14 +42,14 @@ fn basic_happy_path_works() { new_test_ext().execute_with(|| { // #1: submit assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), set_balance_proposal_hash(1), DispatchTime::At(10), )); assert_eq!(Balances::reserved_balance(&1), 2); assert_eq!(ReferendumCount::::get(), 1); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); run_to(4); assert_eq!(DecidingCount::::get(0), 0); run_to(5); @@ -63,7 +63,7 @@ fn basic_happy_path_works() { run_to(9); // #8: Should be confirmed & ended. assert_eq!(approved_since(0), 9); - assert_ok!(Referenda::refund_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(2), 0)); run_to(12); // #9: Should not yet be enacted. assert_eq!(Balances::free_balance(&42), 0); @@ -78,7 +78,7 @@ fn insta_confirm_then_kill_works() { new_test_ext().execute_with(|| { let r = Confirming { immediate: true }.create(); run_to(6); - assert_ok!(Referenda::kill(Origin::root(), r)); + assert_ok!(Referenda::kill(RuntimeOrigin::root(), r)); assert_eq!(killed_since(r), 6); }); } @@ -173,24 +173,24 @@ fn queueing_works() { new_test_ext().execute_with(|| { // Submit a proposal into a track with a queue len of 1. assert_ok!(Referenda::submit( - Origin::signed(5), + RuntimeOrigin::signed(5), Box::new(RawOrigin::Root.into()), set_balance_proposal_hash(0), DispatchTime::After(0), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(5), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(5), 0)); run_to(2); // Submit 3 more proposals into the same queue. for i in 1..=4 { assert_ok!(Referenda::submit( - Origin::signed(i), + RuntimeOrigin::signed(i), Box::new(RawOrigin::Root.into()), set_balance_proposal_hash(i), DispatchTime::After(0), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(i), i as u32)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(i), i as u32)); // TODO: decision deposit after some initial votes with a non-highest voted coming // first. } @@ -214,7 +214,7 @@ fn queueing_works() { println!("{:?}", Vec::<_>::from(TrackQueue::::get(0))); // Cancel the first. - assert_ok!(Referenda::cancel(Origin::signed(4), 0)); + assert_ok!(Referenda::cancel(RuntimeOrigin::signed(4), 0)); assert_eq!(cancelled_since(0), 6); // The other with the most approvals (#4) should be being decided. @@ -270,7 +270,7 @@ fn auto_timeout_should_happen_with_nothing_but_submit() { new_test_ext().execute_with(|| { // #1: submit assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), set_balance_proposal_hash(1), DispatchTime::At(20), @@ -290,20 +290,20 @@ fn auto_timeout_should_happen_with_nothing_but_submit() { fn tracks_are_distinguished() { new_test_ext().execute_with(|| { assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), set_balance_proposal_hash(1), DispatchTime::At(10), )); assert_ok!(Referenda::submit( - Origin::signed(2), + RuntimeOrigin::signed(2), Box::new(RawOrigin::None.into()), set_balance_proposal_hash(2), DispatchTime::At(20), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(3), 0)); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(4), 1)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(3), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(4), 1)); let mut i = ReferendumInfoFor::::iter().collect::>(); i.sort_by_key(|x| x.0); @@ -354,7 +354,7 @@ fn submit_errors_work() { // No track for Signed origins. assert_noop!( Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Signed(2).into()), h, DispatchTime::At(10), @@ -365,7 +365,7 @@ fn submit_errors_work() { // No funds for deposit assert_noop!( Referenda::submit( - Origin::signed(10), + RuntimeOrigin::signed(10), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), @@ -379,21 +379,21 @@ fn submit_errors_work() { fn decision_deposit_errors_work() { new_test_ext().execute_with(|| { let e = Error::::NotOngoing; - assert_noop!(Referenda::place_decision_deposit(Origin::signed(2), 0), e); + assert_noop!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0), e); let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); let e = BalancesError::::InsufficientBalance; - assert_noop!(Referenda::place_decision_deposit(Origin::signed(10), 0), e); + assert_noop!(Referenda::place_decision_deposit(RuntimeOrigin::signed(10), 0), e); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); let e = Error::::HasDeposit; - assert_noop!(Referenda::place_decision_deposit(Origin::signed(2), 0), e); + assert_noop!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0), e); }); } @@ -401,24 +401,24 @@ fn decision_deposit_errors_work() { fn refund_deposit_works() { new_test_ext().execute_with(|| { let e = Error::::BadReferendum; - assert_noop!(Referenda::refund_decision_deposit(Origin::signed(1), 0), e); + assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(1), 0), e); let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); let e = Error::::NoDeposit; - assert_noop!(Referenda::refund_decision_deposit(Origin::signed(2), 0), e); + assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(2), 0), e); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); let e = Error::::Unfinished; - assert_noop!(Referenda::refund_decision_deposit(Origin::signed(3), 0), e); + assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(3), 0), e); run_to(11); - assert_ok!(Referenda::refund_decision_deposit(Origin::signed(3), 0)); + assert_ok!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(3), 0)); }); } @@ -427,16 +427,16 @@ fn cancel_works() { new_test_ext().execute_with(|| { let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); run_to(8); - assert_ok!(Referenda::cancel(Origin::signed(4), 0)); - assert_ok!(Referenda::refund_decision_deposit(Origin::signed(3), 0)); + assert_ok!(Referenda::cancel(RuntimeOrigin::signed(4), 0)); + assert_ok!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(3), 0)); assert_eq!(cancelled_since(0), 8); }); } @@ -446,16 +446,16 @@ fn cancel_errors_works() { new_test_ext().execute_with(|| { let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); - assert_noop!(Referenda::cancel(Origin::signed(1), 0), BadOrigin); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); + assert_noop!(Referenda::cancel(RuntimeOrigin::signed(1), 0), BadOrigin); run_to(11); - assert_noop!(Referenda::cancel(Origin::signed(4), 0), Error::::NotOngoing); + assert_noop!(Referenda::cancel(RuntimeOrigin::signed(4), 0), Error::::NotOngoing); }); } @@ -464,17 +464,17 @@ fn kill_works() { new_test_ext().execute_with(|| { let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); run_to(8); - assert_ok!(Referenda::kill(Origin::root(), 0)); + assert_ok!(Referenda::kill(RuntimeOrigin::root(), 0)); let e = Error::::NoDeposit; - assert_noop!(Referenda::refund_decision_deposit(Origin::signed(3), 0), e); + assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(3), 0), e); assert_eq!(killed_since(0), 8); }); } @@ -484,16 +484,16 @@ fn kill_errors_works() { new_test_ext().execute_with(|| { let h = set_balance_proposal_hash(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); - assert_noop!(Referenda::kill(Origin::signed(4), 0), BadOrigin); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); + assert_noop!(Referenda::kill(RuntimeOrigin::signed(4), 0), BadOrigin); run_to(11); - assert_noop!(Referenda::kill(Origin::root(), 0), Error::::NotOngoing); + assert_noop!(Referenda::kill(RuntimeOrigin::root(), 0), Error::::NotOngoing); }); } diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 984bd0642d959..a6311e5f925be 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -33,7 +33,8 @@ pub type NegativeImbalanceOf = <>::Currency as Currency< pub type CallOf = >::RuntimeCall; pub type VotesOf = >::Votes; pub type TallyOf = >::Tally; -pub type PalletsOriginOf = <::Origin as OriginTrait>::PalletsOrigin; +pub type PalletsOriginOf = + <::RuntimeOrigin as OriginTrait>::PalletsOrigin; pub type ReferendumInfoOf = ReferendumInfo< TrackIdOf, PalletsOriginOf, @@ -139,13 +140,13 @@ pub trait TracksInfo { type Id: Copy + Parameter + Ord + PartialOrd + Send + Sync + 'static + MaxEncodedLen; /// The origin type from which a track is implied. - type Origin; + type RuntimeOrigin; /// Return the array of known tracks and their information. fn tracks() -> &'static [(Self::Id, TrackInfo)]; /// Determine the voting track for the given `origin`. - fn track_for(origin: &Self::Origin) -> Result; + fn track_for(origin: &Self::RuntimeOrigin) -> Result; /// Return the track info for track `id`, by default this just looks it up in `Self::tracks()`. fn info(id: Self::Id) -> Option<&'static TrackInfo> { @@ -157,7 +158,7 @@ pub trait TracksInfo { #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ReferendumStatus< TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, - Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, @@ -168,7 +169,7 @@ pub struct ReferendumStatus< /// The track of this referendum. pub(crate) track: TrackId, /// The origin for this referendum. - pub(crate) origin: Origin, + pub(crate) origin: RuntimeOrigin, /// The hash of the proposal up for referendum. pub(crate) proposal_hash: Hash, /// The time the proposal should be scheduled for enactment. @@ -194,7 +195,7 @@ pub struct ReferendumStatus< #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum ReferendumInfo< TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, - Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Moment: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, @@ -204,7 +205,16 @@ pub enum ReferendumInfo< > { /// Referendum has been submitted and is being voted on. Ongoing( - ReferendumStatus, + ReferendumStatus< + TrackId, + RuntimeOrigin, + Moment, + Hash, + Balance, + Tally, + AccountId, + ScheduleAddress, + >, ), /// Referendum finished with approval. Submission deposit is held. Approved(Moment, Deposit, Option>), @@ -220,14 +230,14 @@ pub enum ReferendumInfo< impl< TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, - Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, - > ReferendumInfo + > ReferendumInfo { /// Take the Decision Deposit from `self`, if there is one. Returns an `Err` if `self` is not /// in a valid state for the Decision Deposit to be refunded. diff --git a/frame/remark/src/mock.rs b/frame/remark/src/mock.rs index 6ce7115345e57..22467796cf37b 100644 --- a/frame/remark/src/mock.rs +++ b/frame/remark/src/mock.rs @@ -45,7 +45,7 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index fbd59555b5ebc..9397c66170425 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -31,7 +31,7 @@ use frame_system::Pallet as System; const BLOCK_NUMBER: u32 = 2; -type SystemOrigin = ::Origin; +type SystemOrigin = ::RuntimeOrigin; /// Add `n` named items to the schedule. /// diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 7e9b8e1b92fb7..143fa37a9261d 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -202,17 +202,19 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The aggregated origin which the dispatch will take. - type Origin: OriginTrait + type RuntimeOrigin: OriginTrait + From - + IsType<::Origin>; + + IsType<::RuntimeOrigin>; /// The caller origin, overarching type of all pallets origins. type PalletsOrigin: From> + Codec + Clone + Eq + TypeInfo; /// The aggregated call type. type RuntimeCall: Parameter - + Dispatchable::Origin, PostInfo = PostDispatchInfo> - + GetDispatchInfo + + Dispatchable< + RuntimeOrigin = ::RuntimeOrigin, + PostInfo = PostDispatchInfo, + > + GetDispatchInfo + From>; /// The maximum weight that may be scheduled per block for any dispatchables of less @@ -221,7 +223,7 @@ pub mod pallet { type MaximumWeight: Get; /// Required origin to schedule or cancel calls. - type ScheduleOrigin: EnsureOrigin<::Origin>; + type ScheduleOrigin: EnsureOrigin<::RuntimeOrigin>; /// Compare the privileges of origins. /// @@ -354,9 +356,10 @@ pub mod pallet { let periodic = s.maybe_periodic.is_some(); let call_weight = call.get_dispatch_info().weight; let mut item_weight = T::WeightInfo::item(periodic, named, Some(resolved)); - let origin = - <::Origin as From>::from(s.origin.clone()) - .into(); + let origin = <::RuntimeOrigin as From>::from( + s.origin.clone(), + ) + .into(); if ensure_signed(origin).is_ok() { // Weights of Signed dispatches expect their signing account to be whitelisted. item_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); @@ -431,7 +434,7 @@ pub mod pallet { call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_schedule( DispatchTime::At(when), maybe_periodic, @@ -446,7 +449,7 @@ pub mod pallet { #[pallet::weight(::WeightInfo::cancel(T::MaxScheduledPerBlock::get()))] pub fn cancel(origin: OriginFor, when: T::BlockNumber, index: u32) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_cancel(Some(origin.caller().clone()), (when, index))?; Ok(()) } @@ -462,7 +465,7 @@ pub mod pallet { call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_schedule_named( id, DispatchTime::At(when), @@ -478,7 +481,7 @@ pub mod pallet { #[pallet::weight(::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))] pub fn cancel_named(origin: OriginFor, id: Vec) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_cancel_named(Some(origin.caller().clone()), id)?; Ok(()) } @@ -497,7 +500,7 @@ pub mod pallet { call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_schedule( DispatchTime::After(after), maybe_periodic, @@ -523,7 +526,7 @@ pub mod pallet { call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_schedule_named( id, DispatchTime::After(after), diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 6460d0f4c1cd1..6f6667590a6c3 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -70,7 +70,7 @@ pub mod logger { #[pallet::call] impl Pallet where - ::Origin: OriginTrait, + ::RuntimeOrigin: OriginTrait, { #[pallet::weight(*weight)] pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { @@ -125,7 +125,7 @@ impl system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = RocksDbWeight; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; @@ -169,7 +169,7 @@ impl pallet_preimage::Config for Test { impl Config for Test { type RuntimeEvent = RuntimeEvent; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type PalletsOrigin = OriginCaller; type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index f1168e6e9d26f..f6db70ae42d49 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -52,7 +52,7 @@ fn scheduling_with_preimages_works() { RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); let hash = ::Hashing::hash_of(&call); let hashed = MaybeHashed::Hash(hash); - assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); assert!(Preimage::preimage_requested(&hash)); run_to_block(3); @@ -82,7 +82,7 @@ fn scheduling_with_preimage_postpones_correctly() { assert!(logger::log().is_empty()); // Register preimage. - assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); run_to_block(5); // #5 empty since postponement is 2 blocks. @@ -619,14 +619,21 @@ fn root_calls_works() { RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) .into(), ); - assert_ok!(Scheduler::schedule_named(Origin::root(), 1u32.encode(), 4, None, 127, call,)); - assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); + assert_ok!(Scheduler::schedule_named( + RuntimeOrigin::root(), + 1u32.encode(), + 4, + None, + 127, + call, + )); + assert_ok!(Scheduler::schedule(RuntimeOrigin::root(), 4, None, 127, call2)); run_to_block(3); // Scheduled calls are in the agenda. assert_eq!(Agenda::::get(4).len(), 2); assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(Origin::root(), 1u32.encode())); - assert_ok!(Scheduler::cancel(Origin::root(), 4, 1)); + assert_ok!(Scheduler::cancel_named(RuntimeOrigin::root(), 1u32.encode())); + assert_ok!(Scheduler::cancel(RuntimeOrigin::root(), 4, 1)); // Scheduled calls are made NONE, so should not effect state run_to_block(100); assert!(logger::log().is_empty()); @@ -651,17 +658,17 @@ fn fails_to_schedule_task_in_the_past() { .into(), ); assert_err!( - Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call1), + Scheduler::schedule_named(RuntimeOrigin::root(), 1u32.encode(), 2, None, 127, call1), Error::::TargetBlockNumberInPast, ); assert_err!( - Scheduler::schedule(Origin::root(), 2, None, 127, call2), + Scheduler::schedule(RuntimeOrigin::root(), 2, None, 127, call2), Error::::TargetBlockNumberInPast, ); assert_err!( - Scheduler::schedule(Origin::root(), 3, None, 127, call3), + Scheduler::schedule(RuntimeOrigin::root(), 3, None, 127, call3), Error::::TargetBlockNumberInPast, ); }); diff --git a/frame/scored-pool/README.md b/frame/scored-pool/README.md index 56c6af916ecd0..455bae24e7951 100644 --- a/frame/scored-pool/README.md +++ b/frame/scored-pool/README.md @@ -58,7 +58,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let _ = >::submit_candidacy( - T::Origin::from(Some(who.clone()).into()) + T::RuntimeOrigin::from(Some(who.clone()).into()) ); Ok(()) } diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index c9ba30df80b8b..a015c1c568153 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -75,7 +75,7 @@ //! let who = ensure_signed(origin)?; //! //! let _ = >::submit_candidacy( -//! T::Origin::from(Some(who.clone()).into()) +//! T::RuntimeOrigin::from(Some(who.clone()).into()) //! ); //! Ok(()) //! } @@ -183,13 +183,13 @@ pub mod pallet { type MembershipChanged: ChangeMembers; /// Allows a configurable origin type to set a score to a candidate in the pool. - type ScoreOrigin: EnsureOrigin; + type ScoreOrigin: EnsureOrigin; /// Required origin for removing a member (though can always be Root). /// Configurable origin which enables removing an entity. If the entity /// is part of the `Members` it is immediately replaced by the next /// highest scoring candidate, if available. - type KickOrigin: EnsureOrigin; + type KickOrigin: EnsureOrigin; } #[pallet::event] diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index 20fa47baf639f..d6f653b32ad2d 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -61,7 +61,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/frame/scored-pool/src/tests.rs b/frame/scored-pool/src/tests.rs index 1a68891be0f50..8f4daff47cc44 100644 --- a/frame/scored-pool/src/tests.rs +++ b/frame/scored-pool/src/tests.rs @@ -41,11 +41,11 @@ fn query_membership_works() { fn submit_candidacy_must_not_work() { new_test_ext().execute_with(|| { assert_noop!( - ScoredPool::submit_candidacy(Origin::signed(99)), + ScoredPool::submit_candidacy(RuntimeOrigin::signed(99)), pallet_balances::Error::::InsufficientBalance, ); assert_noop!( - ScoredPool::submit_candidacy(Origin::signed(40)), + ScoredPool::submit_candidacy(RuntimeOrigin::signed(40)), Error::::AlreadyInPool ); }); @@ -58,7 +58,7 @@ fn submit_candidacy_works() { let who = 15; // when - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); assert_eq!(fetch_from_pool(15), Some((who, None))); // then @@ -72,11 +72,11 @@ fn scoring_works() { // given let who = 15; let score = 99; - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); // when let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, score)); + assert_ok!(ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), who, index, score)); // then assert_eq!(fetch_from_pool(who), Some((who, Some(score)))); @@ -93,7 +93,7 @@ fn scoring_same_element_with_same_score_works() { let score = 2; // when - assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, score)); + assert_ok!(ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), who, index, score)); // then assert_eq!(fetch_from_pool(who), Some((who, Some(score)))); @@ -109,7 +109,7 @@ fn kicking_works_only_for_authorized() { new_test_ext().execute_with(|| { let who = 40; let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_noop!(ScoredPool::kick(Origin::signed(99), who, index), BadOrigin); + assert_noop!(ScoredPool::kick(RuntimeOrigin::signed(99), who, index), BadOrigin); }); } @@ -123,7 +123,7 @@ fn kicking_works() { // when let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::kick(Origin::signed(KickOrigin::get()), who, index)); + assert_ok!(ScoredPool::kick(RuntimeOrigin::signed(KickOrigin::get()), who, index)); // then assert_eq!(find_in_pool(who), None); @@ -138,14 +138,14 @@ fn unscored_entities_must_not_be_used_for_filling_members() { new_test_ext().execute_with(|| { // given // we submit a candidacy, score will be `None` - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(15))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(15))); // when // we remove every scored member ScoredPool::pool().into_iter().for_each(|(who, score)| { if let Some(_) = score { let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::kick(Origin::signed(KickOrigin::get()), who, index)); + assert_ok!(ScoredPool::kick(RuntimeOrigin::signed(KickOrigin::get()), who, index)); } }); @@ -161,9 +161,9 @@ fn refreshing_works() { new_test_ext().execute_with(|| { // given let who = 15; - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, 99)); + assert_ok!(ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), who, index, 99)); // when ScoredPool::refresh_members(ScoredPool::pool(), ChangeReceiver::MembershipChanged); @@ -179,9 +179,9 @@ fn refreshing_happens_every_period() { new_test_ext().execute_with(|| { // given System::set_block_number(1); - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(15))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(15))); let index = find_in_pool(15).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), 15, index, 99)); + assert_ok!(ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), 15, index, 99)); assert_eq!(ScoredPool::members(), vec![20, 40]); // when @@ -200,7 +200,7 @@ fn withdraw_candidacy_must_only_work_for_members() { let who = 77; let index = 0; assert_noop!( - ScoredPool::withdraw_candidacy(Origin::signed(who), index), + ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), index), Error::::WrongAccountIndex ); }); @@ -212,15 +212,15 @@ fn oob_index_should_abort() { let who = 40; let oob_index = ScoredPool::pool().len() as u32; assert_noop!( - ScoredPool::withdraw_candidacy(Origin::signed(who), oob_index), + ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), oob_index), Error::::InvalidIndex ); assert_noop!( - ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, oob_index, 99), + ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), who, oob_index, 99), Error::::InvalidIndex ); assert_noop!( - ScoredPool::kick(Origin::signed(KickOrigin::get()), who, oob_index), + ScoredPool::kick(RuntimeOrigin::signed(KickOrigin::get()), who, oob_index), Error::::InvalidIndex ); }); @@ -232,15 +232,15 @@ fn index_mismatches_should_abort() { let who = 40; let index = 3; assert_noop!( - ScoredPool::withdraw_candidacy(Origin::signed(who), index), + ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), index), Error::::WrongAccountIndex ); assert_noop!( - ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, 99), + ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), who, index, 99), Error::::WrongAccountIndex ); assert_noop!( - ScoredPool::kick(Origin::signed(KickOrigin::get()), who, index), + ScoredPool::kick(RuntimeOrigin::signed(KickOrigin::get()), who, index), Error::::WrongAccountIndex ); }); @@ -254,7 +254,7 @@ fn withdraw_unscored_candidacy_must_work() { // when let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::withdraw_candidacy(Origin::signed(who), index)); + assert_ok!(ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), index)); // then assert_eq!(fetch_from_pool(5), None); @@ -270,7 +270,7 @@ fn withdraw_scored_candidacy_must_work() { // when let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::withdraw_candidacy(Origin::signed(who), index)); + assert_ok!(ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), index)); // then assert_eq!(fetch_from_pool(who), None); @@ -286,12 +286,12 @@ fn candidacy_resubmitting_works() { let who = 15; // when - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); assert_eq!(ScoredPool::candidate_exists(who), true); let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::withdraw_candidacy(Origin::signed(who), index)); + assert_ok!(ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), index)); assert_eq!(ScoredPool::candidate_exists(who), false); - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); // then assert_eq!(ScoredPool::candidate_exists(who), true); @@ -303,13 +303,18 @@ fn pool_candidates_exceeded() { new_test_ext().execute_with(|| { for i in [1, 2, 3, 4, 6] { let who = i as u64; - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, 99)); + assert_ok!(ScoredPool::score( + RuntimeOrigin::signed(ScoreOrigin::get()), + who, + index, + 99 + )); } assert_noop!( - ScoredPool::submit_candidacy(Origin::signed(8)), + ScoredPool::submit_candidacy(RuntimeOrigin::signed(8)), Error::::TooManyMembers ); }); diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index de2f4ae23f423..60b17213d2f1c 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -52,7 +52,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index f6d9e65c1e0b0..aa13eacba9564 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -248,7 +248,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index 7947a8a670b5a..43809cc3a9de0 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -21,8 +21,8 @@ use super::*; use crate::mock::{ authorities, before_session_end_called, force_new_session, new_test_ext, reset_before_session_end_called, session_changed, set_next_validators, set_session_length, - Origin, PreUpgradeMockSessionKeys, Session, SessionChanged, System, Test, TestSessionChanged, - TestValidatorIdOf, + PreUpgradeMockSessionKeys, RuntimeOrigin, Session, SessionChanged, System, Test, + TestSessionChanged, TestValidatorIdOf, }; use codec::Decode; @@ -67,7 +67,7 @@ fn keys_cleared_on_kill() { assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); assert!(System::is_provider_required(&1)); - assert_ok!(Session::purge_keys(Origin::signed(1))); + assert_ok!(Session::purge_keys(RuntimeOrigin::signed(1))); assert!(!System::is_provider_required(&1)); assert_eq!(Session::load_keys(&1), None); @@ -87,8 +87,8 @@ fn purge_keys_works_for_stash_id() { let id = DUMMY; assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); - assert_ok!(Session::purge_keys(Origin::signed(10))); - assert_ok!(Session::purge_keys(Origin::signed(2))); + assert_ok!(Session::purge_keys(RuntimeOrigin::signed(10))); + assert_ok!(Session::purge_keys(RuntimeOrigin::signed(2))); assert_eq!(Session::load_keys(&10), None); assert_eq!(Session::load_keys(&20), None); @@ -128,7 +128,7 @@ fn authorities_should_track_validators() { reset_before_session_end_called(); set_next_validators(vec![1, 2, 4]); - assert_ok!(Session::set_keys(Origin::signed(4), UintAuthorityId(4).into(), vec![])); + assert_ok!(Session::set_keys(RuntimeOrigin::signed(4), UintAuthorityId(4).into(), vec![])); force_new_session(); initialize_block(3); assert_eq!( @@ -194,7 +194,7 @@ fn session_change_should_work() { // Block 3: Set new key for validator 2; no visible change. initialize_block(3); - assert_ok!(Session::set_keys(Origin::signed(2), UintAuthorityId(5).into(), vec![])); + assert_ok!(Session::set_keys(RuntimeOrigin::signed(2), UintAuthorityId(5).into(), vec![])); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); // Block 4: Session rollover; no visible change. @@ -219,13 +219,13 @@ fn duplicates_are_not_allowed() { System::set_block_number(1); Session::on_initialize(1); assert_noop!( - Session::set_keys(Origin::signed(4), UintAuthorityId(1).into(), vec![]), + Session::set_keys(RuntimeOrigin::signed(4), UintAuthorityId(1).into(), vec![]), Error::::DuplicatedKey, ); - assert_ok!(Session::set_keys(Origin::signed(1), UintAuthorityId(10).into(), vec![])); + assert_ok!(Session::set_keys(RuntimeOrigin::signed(1), UintAuthorityId(10).into(), vec![])); // is fine now that 1 has migrated off. - assert_ok!(Session::set_keys(Origin::signed(4), UintAuthorityId(1).into(), vec![])); + assert_ok!(Session::set_keys(RuntimeOrigin::signed(4), UintAuthorityId(1).into(), vec![])); }); } @@ -268,7 +268,7 @@ fn session_changed_flag_works() { assert!(before_session_end_called()); reset_before_session_end_called(); - assert_ok!(Session::set_keys(Origin::signed(2), UintAuthorityId(5).into(), vec![])); + assert_ok!(Session::set_keys(RuntimeOrigin::signed(2), UintAuthorityId(5).into(), vec![])); force_new_session(); initialize_block(6); assert!(!session_changed()); @@ -276,7 +276,11 @@ fn session_changed_flag_works() { reset_before_session_end_called(); // changing the keys of a validator leads to change. - assert_ok!(Session::set_keys(Origin::signed(69), UintAuthorityId(69).into(), vec![])); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(69), + UintAuthorityId(69).into(), + vec![] + )); force_new_session(); initialize_block(7); assert!(session_changed()); @@ -355,7 +359,7 @@ fn session_keys_generate_output_works_as_set_keys_input() { new_test_ext().execute_with(|| { let new_keys = mock::MockSessionKeys::generate(None); assert_ok!(Session::set_keys( - Origin::signed(2), + RuntimeOrigin::signed(2), ::Keys::decode(&mut &new_keys[..]).expect("Decode keys"), vec![], )); diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 122dedabbcf0d..73a09490ea579 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -421,10 +421,10 @@ pub mod pallet { type MaxLockDuration: Get; /// The origin that is allowed to call `found`. - type FounderSetOrigin: EnsureOrigin; + type FounderSetOrigin: EnsureOrigin; /// The origin that is allowed to make suspension judgements. - type SuspensionJudgementOrigin: EnsureOrigin; + type SuspensionJudgementOrigin: EnsureOrigin; /// The number of blocks between membership challenges. #[pallet::constant] @@ -1268,19 +1268,19 @@ pub mod pallet { /// Simple ensure origin struct to filter for the founder account. pub struct EnsureFounder(sp_std::marker::PhantomData); -impl EnsureOrigin for EnsureFounder { +impl EnsureOrigin for EnsureFounder { type Success = T::AccountId; - fn try_origin(o: T::Origin) -> Result { + fn try_origin(o: T::RuntimeOrigin) -> Result { o.into().and_then(|o| match (o, Founder::::get()) { (frame_system::RawOrigin::Signed(ref who), Some(ref f)) if who == f => Ok(who.clone()), - (r, _) => Err(T::Origin::from(r)), + (r, _) => Err(T::RuntimeOrigin::from(r)), }) } #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { + fn try_successful_origin() -> Result { let founder = Founder::::get().ok_or(())?; - Ok(T::Origin::from(frame_system::RawOrigin::Signed(founder))) + Ok(T::RuntimeOrigin::from(frame_system::RawOrigin::Signed(founder))) } } diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 1d9eebdda65ce..0b1b93aeae761 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -63,7 +63,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/frame/society/src/tests.rs b/frame/society/src/tests.rs index d394ddc9011b0..864735aa10cca 100644 --- a/frame/society/src/tests.rs +++ b/frame/society/src/tests.rs @@ -33,9 +33,9 @@ fn founding_works() { assert_eq!(Society::pot(), 0); // Account 1 is set as the founder origin // Account 5 cannot start a society - assert_noop!(Society::found(Origin::signed(5), 20, 100, vec![]), BadOrigin); + assert_noop!(Society::found(RuntimeOrigin::signed(5), 20, 100, vec![]), BadOrigin); // Account 1 can start a society, where 10 is the founding member - assert_ok!(Society::found(Origin::signed(1), 10, 100, b"be cool".to_vec())); + assert_ok!(Society::found(RuntimeOrigin::signed(1), 10, 100, b"be cool".to_vec())); // Society members only include 10 assert_eq!(Society::members(), vec![10]); // 10 is the head of the society @@ -51,7 +51,7 @@ fn founding_works() { assert_eq!(Society::pot(), 1000); // Cannot start another society assert_noop!( - Society::found(Origin::signed(1), 20, 100, vec![]), + Society::found(RuntimeOrigin::signed(1), 20, 100, vec![]), Error::::AlreadyFounded ); }); @@ -61,22 +61,22 @@ fn founding_works() { fn unfounding_works() { EnvBuilder::new().with_max_members(0).with_members(vec![]).execute(|| { // Account 1 sets the founder... - assert_ok!(Society::found(Origin::signed(1), 10, 100, vec![])); + assert_ok!(Society::found(RuntimeOrigin::signed(1), 10, 100, vec![])); // Account 2 cannot unfound it as it's not the founder. - assert_noop!(Society::unfound(Origin::signed(2)), Error::::NotFounder); + assert_noop!(Society::unfound(RuntimeOrigin::signed(2)), Error::::NotFounder); // Account 10 can, though. - assert_ok!(Society::unfound(Origin::signed(10))); + assert_ok!(Society::unfound(RuntimeOrigin::signed(10))); // 1 sets the founder to 20 this time - assert_ok!(Society::found(Origin::signed(1), 20, 100, vec![])); + assert_ok!(Society::found(RuntimeOrigin::signed(1), 20, 100, vec![])); // Bring in a new member... - assert_ok!(Society::bid(Origin::signed(10), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(10), 0)); run_to_block(4); - assert_ok!(Society::vote(Origin::signed(20), 10, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(20), 10, true)); run_to_block(8); // Unfounding won't work now, even though it's from 20. - assert_noop!(Society::unfound(Origin::signed(20)), Error::::NotHead); + assert_noop!(Society::unfound(RuntimeOrigin::signed(20)), Error::::NotHead); }); } @@ -85,7 +85,7 @@ fn basic_new_member_works() { EnvBuilder::new().execute(|| { assert_eq!(Balances::free_balance(20), 50); // Bid causes Candidate Deposit to be reserved. - assert_ok!(Society::bid(Origin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); assert_eq!(Balances::free_balance(20), 25); assert_eq!(Balances::reserved_balance(20), 25); // Rotate period every 4 blocks @@ -93,7 +93,7 @@ fn basic_new_member_works() { // 20 is now a candidate assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); // 10 (a member) can vote for the candidate - assert_ok!(Society::vote(Origin::signed(10), 20, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, true)); // Rotate period every 4 blocks run_to_block(8); // 20 is now a member of the society @@ -108,10 +108,10 @@ fn basic_new_member_works() { fn bidding_works() { EnvBuilder::new().execute(|| { // Users make bids of various amounts - assert_ok!(Society::bid(Origin::signed(60), 1900)); - assert_ok!(Society::bid(Origin::signed(50), 500)); - assert_ok!(Society::bid(Origin::signed(40), 400)); - assert_ok!(Society::bid(Origin::signed(30), 300)); + assert_ok!(Society::bid(RuntimeOrigin::signed(60), 1900)); + assert_ok!(Society::bid(RuntimeOrigin::signed(50), 500)); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 400)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 300)); // Rotate period run_to_block(4); // Pot is 1000 after "PeriodSpend" @@ -126,8 +126,8 @@ fn bidding_works() { ] ); // A member votes for these candidates to join the society - assert_ok!(Society::vote(Origin::signed(10), 30, true)); - assert_ok!(Society::vote(Origin::signed(10), 40, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 30, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 40, true)); run_to_block(8); // Candidates become members after a period rotation assert_eq!(Society::members(), vec![10, 30, 40]); @@ -137,7 +137,7 @@ fn bidding_works() { // Left over from the original bids is 50 who satisfies the condition of bid less than pot. assert_eq!(Society::candidates(), vec![create_bid(500, 50, BidKind::Deposit(25))]); // 40, now a member, can vote for 50 - assert_ok!(Society::vote(Origin::signed(40), 50, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(40), 50, true)); run_to_block(12); // 50 is now a member assert_eq!(Society::members(), vec![10, 30, 40, 50]); @@ -146,8 +146,8 @@ fn bidding_works() { assert_eq!(Balances::free_balance(Society::account_id()), 8_800); // No more candidates satisfy the requirements assert_eq!(Society::candidates(), vec![]); - assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around - // Next period + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(10), true)); // Keep defender around + // Next period run_to_block(16); // Same members assert_eq!(Society::members(), vec![10, 30, 40, 50]); @@ -158,7 +158,7 @@ fn bidding_works() { // Candidate 60 now qualifies based on the increased pot size. assert_eq!(Society::candidates(), vec![create_bid(1900, 60, BidKind::Deposit(25))]); // Candidate 60 is voted in. - assert_ok!(Society::vote(Origin::signed(50), 60, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(50), 60, true)); run_to_block(20); // 60 joins as a member assert_eq!(Society::members(), vec![10, 30, 40, 50, 60]); @@ -172,15 +172,15 @@ fn bidding_works() { fn unbidding_works() { EnvBuilder::new().execute(|| { // 20 and 30 make bids - assert_ok!(Society::bid(Origin::signed(20), 1000)); - assert_ok!(Society::bid(Origin::signed(30), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 1000)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 0)); // Balances are reserved assert_eq!(Balances::free_balance(30), 25); assert_eq!(Balances::reserved_balance(30), 25); // Must know right position to unbid + cannot unbid someone else - assert_noop!(Society::unbid(Origin::signed(30), 1), Error::::BadPosition); + assert_noop!(Society::unbid(RuntimeOrigin::signed(30), 1), Error::::BadPosition); // Can unbid themselves with the right position - assert_ok!(Society::unbid(Origin::signed(30), 0)); + assert_ok!(Society::unbid(RuntimeOrigin::signed(30), 0)); // Balance is returned assert_eq!(Balances::free_balance(30), 50); assert_eq!(Balances::reserved_balance(30), 0); @@ -195,15 +195,15 @@ fn payout_works() { EnvBuilder::new().execute(|| { // Original balance of 50 assert_eq!(Balances::free_balance(20), 50); - assert_ok!(Society::bid(Origin::signed(20), 1000)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 1000)); run_to_block(4); - assert_ok!(Society::vote(Origin::signed(10), 20, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, true)); run_to_block(8); // payout not ready - assert_noop!(Society::payout(Origin::signed(20)), Error::::NoPayout); + assert_noop!(Society::payout(RuntimeOrigin::signed(20)), Error::::NoPayout); run_to_block(9); // payout should be here - assert_ok!(Society::payout(Origin::signed(20))); + assert_ok!(Society::payout(RuntimeOrigin::signed(20))); assert_eq!(Balances::free_balance(20), 1050); }); } @@ -212,7 +212,7 @@ fn payout_works() { fn basic_new_member_skeptic_works() { EnvBuilder::new().execute(|| { assert_eq!(Strikes::::get(10), 0); - assert_ok!(Society::bid(Origin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); run_to_block(8); @@ -227,14 +227,14 @@ fn basic_new_member_reject_works() { // Starting Balance assert_eq!(Balances::free_balance(20), 50); // 20 makes a bid - assert_ok!(Society::bid(Origin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); assert_eq!(Balances::free_balance(20), 25); assert_eq!(Balances::reserved_balance(20), 25); // Rotation Period run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); // We say no - assert_ok!(Society::vote(Origin::signed(10), 20, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, false)); run_to_block(8); // User is not added as member assert_eq!(Society::members(), vec![10]); @@ -248,19 +248,19 @@ fn basic_new_member_reject_works() { fn slash_payout_works() { EnvBuilder::new().execute(|| { assert_eq!(Balances::free_balance(20), 50); - assert_ok!(Society::bid(Origin::signed(20), 1000)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 1000)); run_to_block(4); - assert_ok!(Society::vote(Origin::signed(10), 20, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, true)); run_to_block(8); // payout in queue assert_eq!(Payouts::::get(20), vec![(9, 1000)]); - assert_noop!(Society::payout(Origin::signed(20)), Error::::NoPayout); + assert_noop!(Society::payout(RuntimeOrigin::signed(20)), Error::::NoPayout); // slash payout assert_eq!(Society::slash_payout(&20, 500), 500); assert_eq!(Payouts::::get(20), vec![(9, 500)]); run_to_block(9); // payout should be here, but 500 less - assert_ok!(Society::payout(Origin::signed(20))); + assert_ok!(Society::payout(RuntimeOrigin::signed(20))); assert_eq!(Balances::free_balance(20), 550); }); } @@ -295,10 +295,10 @@ fn suspended_member_life_cycle_works() { assert_eq!(>::get(20), false); // Let's suspend account 20 by giving them 2 strikes by not voting - assert_ok!(Society::bid(Origin::signed(30), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 0)); run_to_block(8); assert_eq!(Strikes::::get(20), 1); - assert_ok!(Society::bid(Origin::signed(40), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 0)); run_to_block(16); // Strike 2 is accumulated, and 20 is suspended :( @@ -307,14 +307,17 @@ fn suspended_member_life_cycle_works() { // Suspended members cannot get payout Society::bump_payout(&20, 10, 100); - assert_noop!(Society::payout(Origin::signed(20)), Error::::NotMember); + assert_noop!(Society::payout(RuntimeOrigin::signed(20)), Error::::NotMember); // Normal people cannot make judgement - assert_noop!(Society::judge_suspended_member(Origin::signed(20), 20, true), BadOrigin); + assert_noop!( + Society::judge_suspended_member(RuntimeOrigin::signed(20), 20, true), + BadOrigin + ); // Suspension judgment origin can judge thee // Suspension judgement origin forgives the suspended member - assert_ok!(Society::judge_suspended_member(Origin::signed(2), 20, true)); + assert_ok!(Society::judge_suspended_member(RuntimeOrigin::signed(2), 20, true)); assert_eq!(>::get(20), false); assert_eq!(>::get(), vec![10, 20]); @@ -322,7 +325,7 @@ fn suspended_member_life_cycle_works() { Society::suspend_member(&20); assert_eq!(>::get(20), true); // Suspension judgement origin does not forgive the suspended member - assert_ok!(Society::judge_suspended_member(Origin::signed(2), 20, false)); + assert_ok!(Society::judge_suspended_member(RuntimeOrigin::signed(2), 20, false)); // Cleaned up assert_eq!(>::get(20), false); assert_eq!(>::get(), vec![10]); @@ -337,14 +340,14 @@ fn suspended_candidate_rejected_works() { assert_eq!(Balances::free_balance(20), 50); assert_eq!(Balances::free_balance(Society::account_id()), 10000); // 20 makes a bid - assert_ok!(Society::bid(Origin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); assert_eq!(Balances::free_balance(20), 25); assert_eq!(Balances::reserved_balance(20), 25); // Rotation Period run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); // We say no - assert_ok!(Society::vote(Origin::signed(10), 20, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, false)); run_to_block(8); // User is not added as member assert_eq!(Society::members(), vec![10]); @@ -354,18 +357,22 @@ fn suspended_candidate_rejected_works() { // Normal user cannot make judgement on suspended candidate assert_noop!( - Society::judge_suspended_candidate(Origin::signed(20), 20, Judgement::Approve), + Society::judge_suspended_candidate(RuntimeOrigin::signed(20), 20, Judgement::Approve), BadOrigin ); // Suspension judgement origin makes no direct judgement - assert_ok!(Society::judge_suspended_candidate(Origin::signed(2), 20, Judgement::Rebid)); + assert_ok!(Society::judge_suspended_candidate( + RuntimeOrigin::signed(2), + 20, + Judgement::Rebid + )); // They are placed back in bid pool, repeat suspension process // Rotation Period run_to_block(12); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); // We say no - assert_ok!(Society::vote(Origin::signed(10), 20, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, false)); run_to_block(16); // User is not added as member assert_eq!(Society::members(), vec![10]); @@ -374,7 +381,11 @@ fn suspended_candidate_rejected_works() { assert_eq!(Society::suspended_candidate(20).is_some(), true); // Suspension judgement origin rejects the candidate - assert_ok!(Society::judge_suspended_candidate(Origin::signed(2), 20, Judgement::Reject)); + assert_ok!(Society::judge_suspended_candidate( + RuntimeOrigin::signed(2), + 20, + Judgement::Reject + )); // User is slashed assert_eq!(Balances::free_balance(20), 25); assert_eq!(Balances::reserved_balance(20), 0); @@ -392,13 +403,16 @@ fn vouch_works() { // 10 is the only member assert_eq!(Society::members(), vec![10]); // A non-member cannot vouch - assert_noop!(Society::vouch(Origin::signed(1), 20, 1000, 100), Error::::NotMember); + assert_noop!( + Society::vouch(RuntimeOrigin::signed(1), 20, 1000, 100), + Error::::NotMember + ); // A member can though - assert_ok!(Society::vouch(Origin::signed(10), 20, 1000, 100)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 20, 1000, 100)); assert_eq!(>::get(10), Some(VouchingStatus::Vouching)); // A member cannot vouch twice at the same time assert_noop!( - Society::vouch(Origin::signed(10), 30, 100, 0), + Society::vouch(RuntimeOrigin::signed(10), 30, 100, 0), Error::::AlreadyVouching ); // Vouching creates the right kind of bid @@ -407,7 +421,7 @@ fn vouch_works() { run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(1000, 20, BidKind::Vouch(10, 100))]); // Vote yes - assert_ok!(Society::vote(Origin::signed(10), 20, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, true)); // Vouched user can win run_to_block(8); assert_eq!(Society::members(), vec![10, 20]); @@ -426,14 +440,14 @@ fn voucher_cannot_win_more_than_bid() { // 10 is the only member assert_eq!(Society::members(), vec![10]); // 10 vouches, but asks for more than the bid - assert_ok!(Society::vouch(Origin::signed(10), 20, 100, 1000)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 20, 100, 1000)); // Vouching creates the right kind of bid assert_eq!(>::get(), vec![create_bid(100, 20, BidKind::Vouch(10, 1000))]); // Vouched user can become candidate run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(100, 20, BidKind::Vouch(10, 1000))]); // Vote yes - assert_ok!(Society::vote(Origin::signed(10), 20, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, true)); // Vouched user can win run_to_block(8); assert_eq!(Society::members(), vec![10, 20]); @@ -450,25 +464,25 @@ fn unvouch_works() { // 10 is the only member assert_eq!(Society::members(), vec![10]); // 10 vouches for 20 - assert_ok!(Society::vouch(Origin::signed(10), 20, 100, 0)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 20, 100, 0)); // 20 has a bid assert_eq!(>::get(), vec![create_bid(100, 20, BidKind::Vouch(10, 0))]); // 10 is vouched assert_eq!(>::get(10), Some(VouchingStatus::Vouching)); // To unvouch, you must know the right bid position - assert_noop!(Society::unvouch(Origin::signed(10), 2), Error::::BadPosition); + assert_noop!(Society::unvouch(RuntimeOrigin::signed(10), 2), Error::::BadPosition); // 10 can unvouch with the right position - assert_ok!(Society::unvouch(Origin::signed(10), 0)); + assert_ok!(Society::unvouch(RuntimeOrigin::signed(10), 0)); // 20 no longer has a bid assert_eq!(>::get(), vec![]); // 10 is no longer vouching assert_eq!(>::get(10), None); // Cannot unvouch after they become candidate - assert_ok!(Society::vouch(Origin::signed(10), 20, 100, 0)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 20, 100, 0)); run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(100, 20, BidKind::Vouch(10, 0))]); - assert_noop!(Society::unvouch(Origin::signed(10), 0), Error::::BadPosition); + assert_noop!(Society::unvouch(RuntimeOrigin::signed(10), 0), Error::::BadPosition); // 10 is still vouching until candidate is approved or rejected assert_eq!(>::get(10), Some(VouchingStatus::Vouching)); run_to_block(8); @@ -478,18 +492,22 @@ fn unvouch_works() { // User is stuck vouching until judgement origin resolves suspended candidate assert_eq!(>::get(10), Some(VouchingStatus::Vouching)); // Judge denies candidate - assert_ok!(Society::judge_suspended_candidate(Origin::signed(2), 20, Judgement::Reject)); + assert_ok!(Society::judge_suspended_candidate( + RuntimeOrigin::signed(2), + 20, + Judgement::Reject + )); // 10 is banned from vouching assert_eq!(>::get(10), Some(VouchingStatus::Banned)); assert_eq!(Society::members(), vec![10]); // 10 cannot vouch again assert_noop!( - Society::vouch(Origin::signed(10), 30, 100, 0), + Society::vouch(RuntimeOrigin::signed(10), 30, 100, 0), Error::::AlreadyVouching ); // 10 cannot unvouch either, so they are banned forever. - assert_noop!(Society::unvouch(Origin::signed(10), 0), Error::::NotVouching); + assert_noop!(Society::unvouch(RuntimeOrigin::signed(10), 0), Error::::NotVouching); }); } @@ -499,13 +517,13 @@ fn unbid_vouch_works() { // 10 is the only member assert_eq!(Society::members(), vec![10]); // 10 vouches for 20 - assert_ok!(Society::vouch(Origin::signed(10), 20, 100, 0)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 20, 100, 0)); // 20 has a bid assert_eq!(>::get(), vec![create_bid(100, 20, BidKind::Vouch(10, 0))]); // 10 is vouched assert_eq!(>::get(10), Some(VouchingStatus::Vouching)); // 20 doesn't want to be a member and can unbid themselves. - assert_ok!(Society::unbid(Origin::signed(20), 0)); + assert_ok!(Society::unbid(RuntimeOrigin::signed(20), 0)); // Everything is cleaned up assert_eq!(>::get(10), None); assert_eq!(>::get(), vec![]); @@ -520,22 +538,22 @@ fn founder_and_head_cannot_be_removed() { assert_eq!(Society::founder(), Some(10)); assert_eq!(Society::head(), Some(10)); // 10 can still accumulate strikes - assert_ok!(Society::bid(Origin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); run_to_block(8); assert_eq!(Strikes::::get(10), 1); - assert_ok!(Society::bid(Origin::signed(30), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 0)); run_to_block(16); assert_eq!(Strikes::::get(10), 2); // Awkwardly they can obtain more than MAX_STRIKES... - assert_ok!(Society::bid(Origin::signed(40), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 0)); run_to_block(24); assert_eq!(Strikes::::get(10), 3); // Replace the head - assert_ok!(Society::bid(Origin::signed(50), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(50), 0)); run_to_block(28); - assert_ok!(Society::vote(Origin::signed(10), 50, true)); - assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 50, true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(10), true)); // Keep defender around run_to_block(32); assert_eq!(Society::members(), vec![10, 50]); assert_eq!(Society::head(), Some(50)); @@ -543,29 +561,29 @@ fn founder_and_head_cannot_be_removed() { assert_eq!(Society::founder(), Some(10)); // 50 can still accumulate strikes - assert_ok!(Society::bid(Origin::signed(60), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(60), 0)); run_to_block(40); assert_eq!(Strikes::::get(50), 1); - assert_ok!(Society::bid(Origin::signed(70), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(70), 0)); run_to_block(48); assert_eq!(Strikes::::get(50), 2); // Replace the head - assert_ok!(Society::bid(Origin::signed(80), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(80), 0)); run_to_block(52); - assert_ok!(Society::vote(Origin::signed(10), 80, true)); - assert_ok!(Society::vote(Origin::signed(50), 80, true)); - assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 80, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(50), 80, true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(10), true)); // Keep defender around run_to_block(56); assert_eq!(Society::members(), vec![10, 50, 80]); assert_eq!(Society::head(), Some(80)); assert_eq!(Society::founder(), Some(10)); // 50 can now be suspended for strikes - assert_ok!(Society::bid(Origin::signed(90), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(90), 0)); run_to_block(60); // The candidate is rejected, so voting approve will give a strike - assert_ok!(Society::vote(Origin::signed(50), 90, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(50), 90, true)); run_to_block(64); assert_eq!(Strikes::::get(50), 0); assert_eq!(>::get(50), true); @@ -592,19 +610,22 @@ fn challenges_work() { run_to_block(8); assert_eq!(Society::defender(), Some(30)); // They can always free vote for themselves - assert_ok!(Society::defender_vote(Origin::signed(30), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(30), true)); // If no one else votes, nothing happens run_to_block(16); assert_eq!(Society::members(), vec![10, 20, 30, 40]); // New challenge period assert_eq!(Society::defender(), Some(30)); // Non-member cannot challenge - assert_noop!(Society::defender_vote(Origin::signed(1), true), Error::::NotMember); + assert_noop!( + Society::defender_vote(RuntimeOrigin::signed(1), true), + Error::::NotMember + ); // 3 people say accept, 1 reject - assert_ok!(Society::defender_vote(Origin::signed(10), true)); - assert_ok!(Society::defender_vote(Origin::signed(20), true)); - assert_ok!(Society::defender_vote(Origin::signed(30), true)); - assert_ok!(Society::defender_vote(Origin::signed(40), false)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(10), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(20), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(30), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(40), false)); run_to_block(24); // 20 survives assert_eq!(Society::members(), vec![10, 20, 30, 40]); @@ -616,10 +637,10 @@ fn challenges_work() { // One more time assert_eq!(Society::defender(), Some(30)); // 2 people say accept, 2 reject - assert_ok!(Society::defender_vote(Origin::signed(10), true)); - assert_ok!(Society::defender_vote(Origin::signed(20), true)); - assert_ok!(Society::defender_vote(Origin::signed(30), false)); - assert_ok!(Society::defender_vote(Origin::signed(40), false)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(10), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(20), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(30), false)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(40), false)); run_to_block(32); // 20 is suspended assert_eq!(Society::members(), vec![10, 20, 40]); @@ -653,12 +674,12 @@ fn bad_vote_slash_works() { assert_eq!(>::get(30), vec![(5, 100)]); assert_eq!(>::get(40), vec![(5, 100)]); // Create a new bid - assert_ok!(Society::bid(Origin::signed(50), 1000)); + assert_ok!(Society::bid(RuntimeOrigin::signed(50), 1000)); run_to_block(4); - assert_ok!(Society::vote(Origin::signed(10), 50, false)); - assert_ok!(Society::vote(Origin::signed(20), 50, true)); - assert_ok!(Society::vote(Origin::signed(30), 50, false)); - assert_ok!(Society::vote(Origin::signed(40), 50, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 50, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(20), 50, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(30), 50, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(40), 50, false)); run_to_block(8); // Wrong voter gained a strike assert_eq!(>::get(10), 0); @@ -677,15 +698,15 @@ fn bad_vote_slash_works() { fn user_cannot_bid_twice() { EnvBuilder::new().execute(|| { // Cannot bid twice - assert_ok!(Society::bid(Origin::signed(20), 100)); - assert_noop!(Society::bid(Origin::signed(20), 100), Error::::AlreadyBid); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 100)); + assert_noop!(Society::bid(RuntimeOrigin::signed(20), 100), Error::::AlreadyBid); // Cannot bid when vouched - assert_ok!(Society::vouch(Origin::signed(10), 30, 100, 100)); - assert_noop!(Society::bid(Origin::signed(30), 100), Error::::AlreadyBid); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 30, 100, 100)); + assert_noop!(Society::bid(RuntimeOrigin::signed(30), 100), Error::::AlreadyBid); // Cannot vouch when already bid assert_ok!(Society::add_member(&50)); assert_noop!( - Society::vouch(Origin::signed(50), 20, 100, 100), + Society::vouch(RuntimeOrigin::signed(50), 20, 100, 100), Error::::AlreadyBid ); }); @@ -697,7 +718,7 @@ fn vouching_handles_removed_member_with_bid() { // Add a member assert_ok!(Society::add_member(&20)); // Have that member vouch for a user - assert_ok!(Society::vouch(Origin::signed(20), 30, 1000, 100)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(20), 30, 1000, 100)); // That user is now a bid and the member is vouching assert_eq!(>::get(), vec![create_bid(1000, 30, BidKind::Vouch(20, 100))]); assert_eq!(>::get(20), Some(VouchingStatus::Vouching)); @@ -708,7 +729,7 @@ fn vouching_handles_removed_member_with_bid() { assert_eq!(>::get(), vec![create_bid(1000, 30, BidKind::Vouch(20, 100))]); assert_eq!(>::get(20), Some(VouchingStatus::Vouching)); // Remove member - assert_ok!(Society::judge_suspended_member(Origin::signed(2), 20, false)); + assert_ok!(Society::judge_suspended_member(RuntimeOrigin::signed(2), 20, false)); // Bid is removed, vouching status is removed assert_eq!(>::get(), vec![]); assert_eq!(>::get(20), None); @@ -721,7 +742,7 @@ fn vouching_handles_removed_member_with_candidate() { // Add a member assert_ok!(Society::add_member(&20)); // Have that member vouch for a user - assert_ok!(Society::vouch(Origin::signed(20), 30, 1000, 100)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(20), 30, 1000, 100)); // That user is now a bid and the member is vouching assert_eq!(>::get(), vec![create_bid(1000, 30, BidKind::Vouch(20, 100))]); assert_eq!(>::get(20), Some(VouchingStatus::Vouching)); @@ -735,12 +756,12 @@ fn vouching_handles_removed_member_with_candidate() { assert_eq!(Society::candidates(), vec![create_bid(1000, 30, BidKind::Vouch(20, 100))]); assert_eq!(>::get(20), Some(VouchingStatus::Vouching)); // Remove member - assert_ok!(Society::judge_suspended_member(Origin::signed(2), 20, false)); + assert_ok!(Society::judge_suspended_member(RuntimeOrigin::signed(2), 20, false)); // Vouching status is removed, but candidate is still in the queue assert_eq!(>::get(20), None); assert_eq!(Society::candidates(), vec![create_bid(1000, 30, BidKind::Vouch(20, 100))]); // Candidate wins - assert_ok!(Society::vote(Origin::signed(10), 30, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 30, true)); run_to_block(8); assert_eq!(Society::members(), vec![10, 30]); // Payout does not go to removed member @@ -753,16 +774,19 @@ fn vouching_handles_removed_member_with_candidate() { fn votes_are_working() { EnvBuilder::new().execute(|| { // Users make bids of various amounts - assert_ok!(Society::bid(Origin::signed(50), 500)); - assert_ok!(Society::bid(Origin::signed(40), 400)); - assert_ok!(Society::bid(Origin::signed(30), 300)); + assert_ok!(Society::bid(RuntimeOrigin::signed(50), 500)); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 400)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 300)); // Rotate period run_to_block(4); // A member votes for these candidates to join the society - assert_ok!(Society::vote(Origin::signed(10), 30, true)); - assert_ok!(Society::vote(Origin::signed(10), 40, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 30, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 40, true)); // You cannot vote for a non-candidate - assert_noop!(Society::vote(Origin::signed(10), 50, true), Error::::NotCandidate); + assert_noop!( + Society::vote(RuntimeOrigin::signed(10), 50, true), + Error::::NotCandidate + ); // Votes are stored assert_eq!(>::get(30, 10), Some(Vote::Approve)); assert_eq!(>::get(40, 10), Some(Vote::Approve)); @@ -784,7 +808,7 @@ fn max_limits_work() { for i in (100..1110).rev() { // Give them some funds let _ = Balances::make_free_balance_be(&(i as u128), 1000); - assert_ok!(Society::bid(Origin::signed(i as u128), i)); + assert_ok!(Society::bid(RuntimeOrigin::signed(i as u128), i)); } let bids = >::get(); // Length is 1000 @@ -810,7 +834,7 @@ fn max_limits_work() { // Fill up members with suspended candidates from the first rotation for i in 100..104 { assert_ok!(Society::judge_suspended_candidate( - Origin::signed(2), + RuntimeOrigin::signed(2), i, Judgement::Approve )); @@ -821,9 +845,9 @@ fn max_limits_work() { // However, a fringe scenario allows for in-progress candidates to increase the membership // pool, but it has no real after-effects. for i in Society::members().iter() { - assert_ok!(Society::vote(Origin::signed(*i), 110, true)); - assert_ok!(Society::vote(Origin::signed(*i), 111, true)); - assert_ok!(Society::vote(Origin::signed(*i), 112, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(*i), 110, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(*i), 111, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(*i), 112, true)); } // Rotate period run_to_block(12); @@ -832,7 +856,7 @@ fn max_limits_work() { // No candidates because full assert_eq!(Society::candidates().len(), 0); // Increase member limit - assert_ok!(Society::set_max_members(Origin::root(), 200)); + assert_ok!(Society::set_max_members(RuntimeOrigin::root(), 200)); // Rotate period run_to_block(16); // Candidates are back! @@ -847,11 +871,11 @@ fn zero_bid_works() { // * That zero bid is placed as head when accepted. EnvBuilder::new().execute(|| { // Users make bids of various amounts - assert_ok!(Society::bid(Origin::signed(60), 400)); - assert_ok!(Society::bid(Origin::signed(50), 300)); - assert_ok!(Society::bid(Origin::signed(30), 0)); - assert_ok!(Society::bid(Origin::signed(20), 0)); - assert_ok!(Society::bid(Origin::signed(40), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(60), 400)); + assert_ok!(Society::bid(RuntimeOrigin::signed(50), 300)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 0)); // Rotate period run_to_block(4); @@ -872,9 +896,9 @@ fn zero_bid_works() { vec![create_bid(0, 20, BidKind::Deposit(25)), create_bid(0, 40, BidKind::Deposit(25)),] ); // A member votes for these candidates to join the society - assert_ok!(Society::vote(Origin::signed(10), 30, true)); - assert_ok!(Society::vote(Origin::signed(10), 50, true)); - assert_ok!(Society::vote(Origin::signed(10), 60, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 30, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 50, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 60, true)); run_to_block(8); // Candidates become members after a period rotation assert_eq!(Society::members(), vec![10, 30, 50, 60]); @@ -892,7 +916,7 @@ fn bids_ordered_correctly() { for j in 0..5 { // Give them some funds let _ = Balances::make_free_balance_be(&(100 + (i * 5 + j) as u128), 1000); - assert_ok!(Society::bid(Origin::signed(100 + (i * 5 + j) as u128), j)); + assert_ok!(Society::bid(RuntimeOrigin::signed(100 + (i * 5 + j) as u128), j)); } } diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index a79eac3c4dc46..c270b5933e647 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -953,7 +953,7 @@ benchmarks! { #[cfg(test)] mod tests { use super::*; - use crate::mock::{Balances, ExtBuilder, Origin, Staking, Test}; + use crate::mock::{Balances, ExtBuilder, RuntimeOrigin, Staking, Test}; use frame_support::assert_ok; #[test] @@ -1000,7 +1000,11 @@ mod tests { let current_era = CurrentEra::::get().unwrap(); let original_free_balance = Balances::free_balance(&validator_stash); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), validator_stash, current_era)); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + validator_stash, + current_era + )); let new_free_balance = Balances::free_balance(&validator_stash); assert!(original_free_balance < new_free_balance); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 5980e6b40d15d..5682184929a5b 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -131,7 +131,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = RocksDbWeight; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; @@ -660,13 +660,22 @@ pub(crate) fn current_era() -> EraIndex { pub(crate) fn bond(stash: AccountId, ctrl: AccountId, val: Balance) { let _ = Balances::make_free_balance_be(&stash, val); let _ = Balances::make_free_balance_be(&ctrl, val); - assert_ok!(Staking::bond(Origin::signed(stash), ctrl, val, RewardDestination::Controller)); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(stash), + ctrl, + val, + RewardDestination::Controller + )); } pub(crate) fn bond_validator(stash: AccountId, ctrl: AccountId, val: Balance) { bond(stash, ctrl, val); - assert_ok!(Staking::validate(Origin::signed(ctrl), ValidatorPrefs::default())); - assert_ok!(Session::set_keys(Origin::signed(ctrl), SessionKeys { other: ctrl.into() }, vec![])); + assert_ok!(Staking::validate(RuntimeOrigin::signed(ctrl), ValidatorPrefs::default())); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(ctrl), + SessionKeys { other: ctrl.into() }, + vec![] + )); } pub(crate) fn bond_nominator( @@ -676,7 +685,7 @@ pub(crate) fn bond_nominator( target: Vec, ) { bond(stash, ctrl, val); - assert_ok!(Staking::nominate(Origin::signed(ctrl), target)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(ctrl), target)); } /// Progress to the given block, triggering session and era changes as we progress. @@ -846,7 +855,7 @@ pub(crate) fn make_all_reward_payment(era: EraIndex) { // reward validators for validator_controller in validators_with_reward.iter().filter_map(Staking::bonded) { let ledger = >::get(&validator_controller).unwrap(); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), ledger.stash, era)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), ledger.stash, era)); } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index b8a457beb5eae..49f53efbb08b0 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -155,7 +155,7 @@ pub mod pallet { type SlashDeferDuration: Get; /// The origin which can cancel a deferred slash. Root can always do this. - type SlashCancelOrigin: EnsureOrigin; + type SlashCancelOrigin: EnsureOrigin; /// Interface for interacting with a session pallet. type SessionInterface: SessionInterface; @@ -608,18 +608,18 @@ pub mod pallet { "Stash does not have enough balance to bond." ); frame_support::assert_ok!(>::bond( - T::Origin::from(Some(stash.clone()).into()), + T::RuntimeOrigin::from(Some(stash.clone()).into()), T::Lookup::unlookup(controller.clone()), balance, RewardDestination::Staked, )); frame_support::assert_ok!(match status { crate::StakerStatus::Validator => >::validate( - T::Origin::from(Some(controller.clone()).into()), + T::RuntimeOrigin::from(Some(controller.clone()).into()), Default::default(), ), crate::StakerStatus::Nominator(votes) => >::nominate( - T::Origin::from(Some(controller.clone()).into()), + T::RuntimeOrigin::from(Some(controller.clone()).into()), votes.iter().map(|l| T::Lookup::unlookup(l.clone())).collect(), ), _ => Ok(()), @@ -1476,7 +1476,7 @@ pub mod pallet { /// Needed to report an accurate weight for the dispatch. Trusted by `Root` to report an /// accurate number. /// - /// Origin must be root. + /// RuntimeOrigin must be root. /// /// # /// - E: Number of history depths removed, i.e. 10 -> 7 = 3 @@ -1593,7 +1593,7 @@ pub mod pallet { /// * `min_commission`: The minimum amount of commission that each validators must maintain. /// This is checked only upon calling `validate`. Existing validators are not affected. /// - /// Origin must be Root to call this function. + /// RuntimeOrigin must be Root to call this function. /// /// NOTE: Existing nominators and validators will not be affected by this update. /// to kick people under the new limits, `chill_other` should be called. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 85badfac769af..cc2b37d2ba910 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -44,7 +44,7 @@ fn set_staking_configs_works() { ExtBuilder::default().build_and_execute(|| { // setting works assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Set(1_500), ConfigOp::Set(2_000), ConfigOp::Set(10), @@ -61,7 +61,7 @@ fn set_staking_configs_works() { // noop does nothing assert_storage_noop!(assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, @@ -72,7 +72,7 @@ fn set_staking_configs_works() { // removing works assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, @@ -98,22 +98,22 @@ fn force_unstake_works() { add_slash(&11); // Cant transfer assert_noop!( - Balances::transfer(Origin::signed(11), 1, 10), + Balances::transfer(RuntimeOrigin::signed(11), 1, 10), BalancesError::::LiquidityRestrictions ); // Force unstake requires root. - assert_noop!(Staking::force_unstake(Origin::signed(11), 11, 2), BadOrigin); + assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2), BadOrigin); // Force unstake needs correct number of slashing spans (for weight calculation) assert_noop!( - Staking::force_unstake(Origin::root(), 11, 0), + Staking::force_unstake(RuntimeOrigin::root(), 11, 0), Error::::IncorrectSlashingSpans ); // We now force them to unstake - assert_ok!(Staking::force_unstake(Origin::root(), 11, 2)); + assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 11, 2)); // No longer bonded. assert_eq!(Staking::bonded(&11), None); // Transfer works. - assert_ok!(Balances::transfer(Origin::signed(11), 1, 10)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(11), 1, 10)); }); } @@ -235,19 +235,19 @@ fn change_controller_works() { assert_eq!(Staking::bonded(&11), Some(10)); // 10 can control 11 who is initially a validator. - assert_ok!(Staking::chill(Origin::signed(10))); + assert_ok!(Staking::chill(RuntimeOrigin::signed(10))); // change controller - assert_ok!(Staking::set_controller(Origin::signed(11), 5)); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(11), 5)); assert_eq!(Staking::bonded(&11), Some(5)); mock::start_active_era(1); // 10 is no longer in control. assert_noop!( - Staking::validate(Origin::signed(10), ValidatorPrefs::default()), + Staking::validate(RuntimeOrigin::signed(10), ValidatorPrefs::default()), Error::::NotController, ); - assert_ok!(Staking::validate(Origin::signed(5), ValidatorPrefs::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(5), ValidatorPrefs::default())); }) } @@ -382,9 +382,13 @@ fn staking_should_work() { // --- Block 2: start_session(2); // add a new candidate for being a validator. account 3 controlled by 4. - assert_ok!(Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); - assert_ok!(Session::set_keys(Origin::signed(4), SessionKeys { other: 4.into() }, vec![])); + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 1500, RewardDestination::Controller)); + assert_ok!(Staking::validate(RuntimeOrigin::signed(4), ValidatorPrefs::default())); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(4), + SessionKeys { other: 4.into() }, + vec![] + )); // No effects will be seen so far. assert_eq_uvec!(validator_controllers(), vec![20, 10]); @@ -408,7 +412,7 @@ fn staking_should_work() { assert_eq_uvec!(validator_controllers(), vec![20, 4]); // --- Block 6: Unstake 4 as a validator, freeing up the balance stashed in 3 // 4 will chill - Staking::chill(Origin::signed(4)).unwrap(); + Staking::chill(RuntimeOrigin::signed(4)).unwrap(); // --- Block 7: nothing. 4 is still there. start_session(7); @@ -447,20 +451,20 @@ fn blocking_and_kicking_works() { .build_and_execute(|| { // block validator 10/11 assert_ok!(Staking::validate( - Origin::signed(10), + RuntimeOrigin::signed(10), ValidatorPrefs { blocked: true, ..Default::default() } )); // attempt to nominate from 100/101... - assert_ok!(Staking::nominate(Origin::signed(100), vec![11])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(100), vec![11])); // should have worked since we're already nominated them assert_eq!(Nominators::::get(&101).unwrap().targets, vec![11]); // kick the nominator - assert_ok!(Staking::kick(Origin::signed(10), vec![101])); + assert_ok!(Staking::kick(RuntimeOrigin::signed(10), vec![101])); // should have been kicked now assert!(Nominators::::get(&101).unwrap().targets.is_empty()); // attempt to nominate from 100/101... assert_noop!( - Staking::nominate(Origin::signed(100), vec![11]), + Staking::nominate(RuntimeOrigin::signed(100), vec![11]), Error::::BadTarget ); }); @@ -506,7 +510,7 @@ fn no_candidate_emergency_condition() { ::MinimumValidatorCount::put(10); // try to chill - let res = Staking::chill(Origin::signed(10)); + let res = Staking::chill(RuntimeOrigin::signed(10)); assert_ok!(res); let current_era = CurrentEra::::get(); @@ -542,14 +546,26 @@ fn nominating_and_rewards_should_work() { assert_eq_uvec!(validator_controllers(), vec![40, 20]); // re-validate with 11 and 31. - assert_ok!(Staking::validate(Origin::signed(10), Default::default())); - assert_ok!(Staking::validate(Origin::signed(30), Default::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(10), Default::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(30), Default::default())); // Set payee to controller. - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(40), RewardDestination::Controller)); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(10), + RewardDestination::Controller + )); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(20), + RewardDestination::Controller + )); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(30), + RewardDestination::Controller + )); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(40), + RewardDestination::Controller + )); // give the man some money let initial_balance = 1000; @@ -558,11 +574,21 @@ fn nominating_and_rewards_should_work() { } // bond two account pairs and state interest in nomination. - assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(1), + 2, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11, 21, 31])); - assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(3), + 4, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![11, 21, 41])); // the total reward for era 0 let total_payout_0 = current_total_payout_for_duration(reward_time_per_era()); @@ -714,20 +740,28 @@ fn double_staking_should_fail() { let arbitrary_value = 5; // 2 = controller, 1 stashed => ok assert_ok!(Staking::bond( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, arbitrary_value, RewardDestination::default() )); // 4 = not used so far, 1 stashed => not allowed. assert_noop!( - Staking::bond(Origin::signed(1), 4, arbitrary_value, RewardDestination::default()), + Staking::bond( + RuntimeOrigin::signed(1), + 4, + arbitrary_value, + RewardDestination::default() + ), Error::::AlreadyBonded, ); // 1 = stashed => attempting to nominate should fail. - assert_noop!(Staking::nominate(Origin::signed(1), vec![1]), Error::::NotController); + assert_noop!( + Staking::nominate(RuntimeOrigin::signed(1), vec![1]), + Error::::NotController + ); // 2 = controller => nominating should work. - assert_ok!(Staking::nominate(Origin::signed(2), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![1])); }); } @@ -740,14 +774,19 @@ fn double_controlling_should_fail() { let arbitrary_value = 5; // 2 = controller, 1 stashed => ok assert_ok!(Staking::bond( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, arbitrary_value, RewardDestination::default(), )); // 2 = controller, 3 stashed (Note that 2 is reused.) => no-op assert_noop!( - Staking::bond(Origin::signed(3), 2, arbitrary_value, RewardDestination::default()), + Staking::bond( + RuntimeOrigin::signed(3), + 2, + arbitrary_value, + RewardDestination::default() + ), Error::::AlreadyPaired, ); }); @@ -913,14 +952,14 @@ fn cannot_transfer_staked_balance() { assert_eq!(Staking::eras_stakers(active_era(), 11).total, 1000); // Confirm account 11 cannot transfer as a result assert_noop!( - Balances::transfer(Origin::signed(11), 20, 1), + Balances::transfer(RuntimeOrigin::signed(11), 20, 1), BalancesError::::LiquidityRestrictions ); // Give account 11 extra free balance let _ = Balances::make_free_balance_be(&11, 10000); // Confirm that account 11 can now transfer some balance - assert_ok!(Balances::transfer(Origin::signed(11), 20, 1)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(11), 20, 1)); }); } @@ -938,10 +977,10 @@ fn cannot_transfer_staked_balance_2() { assert_eq!(Staking::eras_stakers(active_era(), 21).total, 1000); // Confirm account 21 can transfer at most 1000 assert_noop!( - Balances::transfer(Origin::signed(21), 20, 1001), + Balances::transfer(RuntimeOrigin::signed(21), 20, 1001), BalancesError::::LiquidityRestrictions ); - assert_ok!(Balances::transfer(Origin::signed(21), 20, 1000)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(21), 20, 1000)); }); } @@ -1133,7 +1172,7 @@ fn bond_extra_works() { let _ = Balances::make_free_balance_be(&11, 1000000); // Call the bond_extra function from controller, add only 100 - assert_ok!(Staking::bond_extra(Origin::signed(11), 100)); + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 100)); // There should be 100 more `total` and `active` in the ledger assert_eq!( Staking::ledger(&10), @@ -1147,7 +1186,7 @@ fn bond_extra_works() { ); // Call the bond_extra function with a large number, should handle it - assert_ok!(Staking::bond_extra(Origin::signed(11), Balance::max_value())); + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), Balance::max_value())); // The full amount of the funds should now be in the total and active assert_eq!( Staking::ledger(&10), @@ -1172,7 +1211,7 @@ fn bond_extra_and_withdraw_unbonded_works() { // * Once the unbonding period is done, it can actually take the funds out of the stash. ExtBuilder::default().nominate(false).build_and_execute(|| { // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(10), RewardDestination::Controller)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1203,7 +1242,7 @@ fn bond_extra_and_withdraw_unbonded_works() { ); // deposit the extra 100 units - Staking::bond_extra(Origin::signed(11), 100).unwrap(); + Staking::bond_extra(RuntimeOrigin::signed(11), 100).unwrap(); assert_eq!( Staking::ledger(&10), @@ -1243,7 +1282,7 @@ fn bond_extra_and_withdraw_unbonded_works() { ); // Unbond almost all of the funds in stash. - Staking::unbond(Origin::signed(10), 1000).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 1000).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1256,7 +1295,7 @@ fn bond_extra_and_withdraw_unbonded_works() { ); // Attempting to free the balances now will fail. 2 eras need to pass. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0)); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1272,7 +1311,7 @@ fn bond_extra_and_withdraw_unbonded_works() { mock::start_active_era(3); // nothing yet - assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0)); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1287,7 +1326,7 @@ fn bond_extra_and_withdraw_unbonded_works() { // trigger next era. mock::start_active_era(5); - assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0)); // Now the value is free and the staking ledger is updated. assert_eq!( Staking::ledger(&10), @@ -1311,7 +1350,7 @@ fn too_many_unbond_calls_should_not_work() { // There is only 1 chunk per era, so we need to be in a new era to create a chunk. current_era = i as u32; mock::start_active_era(current_era); - assert_ok!(Staking::unbond(Origin::signed(10), 1)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); } current_era += 1; @@ -1319,24 +1358,24 @@ fn too_many_unbond_calls_should_not_work() { // This chunk is locked at `current_era` through `current_era + 2` (because BondingDuration // == 3). - assert_ok!(Staking::unbond(Origin::signed(10), 1)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); assert_eq!( Staking::ledger(&10).unwrap().unlocking.len(), MaxUnlockingChunks::get() as usize ); // can't do more. - assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::::NoMoreChunks); + assert_noop!(Staking::unbond(RuntimeOrigin::signed(10), 1), Error::::NoMoreChunks); current_era += 2; mock::start_active_era(current_era); - assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::::NoMoreChunks); + assert_noop!(Staking::unbond(RuntimeOrigin::signed(10), 1), Error::::NoMoreChunks); // free up everything except the most recently added chunk. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0)); assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 1); // Can add again. - assert_ok!(Staking::unbond(Origin::signed(10), 1)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 2); }) } @@ -1350,7 +1389,7 @@ fn rebond_works() { // * it can re-bond a portion of the funds scheduled to unlock. ExtBuilder::default().nominate(false).build_and_execute(|| { // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(10), RewardDestination::Controller)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1374,10 +1413,10 @@ fn rebond_works() { assert_eq!(active_era(), 2); // Try to rebond some funds. We get an error since no fund is unbonded. - assert_noop!(Staking::rebond(Origin::signed(10), 500), Error::::NoUnlockChunk); + assert_noop!(Staking::rebond(RuntimeOrigin::signed(10), 500), Error::::NoUnlockChunk); // Unbond almost all of the funds in stash. - Staking::unbond(Origin::signed(10), 900).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 900).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1390,7 +1429,7 @@ fn rebond_works() { ); // Re-bond all the funds unbonded. - Staking::rebond(Origin::signed(10), 900).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 900).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1403,7 +1442,7 @@ fn rebond_works() { ); // Unbond almost all of the funds in stash. - Staking::unbond(Origin::signed(10), 900).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 900).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1416,7 +1455,7 @@ fn rebond_works() { ); // Re-bond part of the funds unbonded. - Staking::rebond(Origin::signed(10), 500).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 500).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1429,7 +1468,7 @@ fn rebond_works() { ); // Re-bond the remainder of the funds unbonded. - Staking::rebond(Origin::signed(10), 500).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 500).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1442,9 +1481,9 @@ fn rebond_works() { ); // Unbond parts of the funds in stash. - Staking::unbond(Origin::signed(10), 300).unwrap(); - Staking::unbond(Origin::signed(10), 300).unwrap(); - Staking::unbond(Origin::signed(10), 300).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 300).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 300).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 300).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1457,7 +1496,7 @@ fn rebond_works() { ); // Re-bond part of the funds unbonded. - Staking::rebond(Origin::signed(10), 500).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 500).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1476,7 +1515,7 @@ fn rebond_is_fifo() { // Rebond should proceed by reversing the most recent bond operations. ExtBuilder::default().nominate(false).build_and_execute(|| { // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(10), RewardDestination::Controller)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1499,7 +1538,7 @@ fn rebond_is_fifo() { mock::start_active_era(2); // Unbond some of the funds in stash. - Staking::unbond(Origin::signed(10), 400).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 400).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1514,7 +1553,7 @@ fn rebond_is_fifo() { mock::start_active_era(3); // Unbond more of the funds in stash. - Staking::unbond(Origin::signed(10), 300).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 300).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1532,7 +1571,7 @@ fn rebond_is_fifo() { mock::start_active_era(4); // Unbond yet more of the funds in stash. - Staking::unbond(Origin::signed(10), 200).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 200).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1549,7 +1588,7 @@ fn rebond_is_fifo() { ); // Re-bond half of the unbonding funds. - Staking::rebond(Origin::signed(10), 400).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 400).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1572,7 +1611,7 @@ fn rebond_emits_right_value_in_event() { // and the rebond event emits the actual value rebonded. ExtBuilder::default().nominate(false).build_and_execute(|| { // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(10), RewardDestination::Controller)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1581,7 +1620,7 @@ fn rebond_emits_right_value_in_event() { mock::start_active_era(1); // Unbond almost all of the funds in stash. - Staking::unbond(Origin::signed(10), 900).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 900).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1594,7 +1633,7 @@ fn rebond_emits_right_value_in_event() { ); // Re-bond less than the total - Staking::rebond(Origin::signed(10), 100).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 100).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1609,7 +1648,7 @@ fn rebond_emits_right_value_in_event() { assert_eq!(*staking_events().last().unwrap(), Event::Bonded(11, 100)); // Re-bond way more than available - Staking::rebond(Origin::signed(10), 100_000).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 100_000).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1699,11 +1738,14 @@ fn reap_stash_works() { // stash is not reapable assert_noop!( - Staking::reap_stash(Origin::signed(20), 11, 0), + Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0), Error::::FundedTarget ); // controller or any other account is not reapable - assert_noop!(Staking::reap_stash(Origin::signed(20), 10, 0), Error::::NotStash); + assert_noop!( + Staking::reap_stash(RuntimeOrigin::signed(20), 10, 0), + Error::::NotStash + ); // no easy way to cause an account to go below ED, we tweak their staking ledger // instead. @@ -1719,7 +1761,7 @@ fn reap_stash_works() { ); // reap-able - assert_ok!(Staking::reap_stash(Origin::signed(20), 11, 0)); + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); // then assert!(!>::contains_key(&10)); @@ -1736,7 +1778,10 @@ fn switching_roles() { ExtBuilder::default().nominate(false).build_and_execute(|| { // Reset reward destination for i in &[10, 20] { - assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(*i), + RewardDestination::Controller + )); } assert_eq_uvec!(validator_controllers(), vec![20, 10]); @@ -1747,16 +1792,20 @@ fn switching_roles() { } // add 2 nominators - assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 5])); + assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 2, 2000, RewardDestination::Controller)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11, 5])); - assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 1])); + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 500, RewardDestination::Controller)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![21, 1])); // add a new validator candidate - assert_ok!(Staking::bond(Origin::signed(5), 6, 1000, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(6), ValidatorPrefs::default())); - assert_ok!(Session::set_keys(Origin::signed(6), SessionKeys { other: 6.into() }, vec![])); + assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 6, 1000, RewardDestination::Controller)); + assert_ok!(Staking::validate(RuntimeOrigin::signed(6), ValidatorPrefs::default())); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(6), + SessionKeys { other: 6.into() }, + vec![] + )); mock::start_active_era(1); @@ -1764,8 +1813,12 @@ fn switching_roles() { assert_eq_uvec!(validator_controllers(), vec![6, 10]); // 2 decides to be a validator. Consequences: - assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); - assert_ok!(Session::set_keys(Origin::signed(2), SessionKeys { other: 2.into() }, vec![])); + assert_ok!(Staking::validate(RuntimeOrigin::signed(2), ValidatorPrefs::default())); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(2), + SessionKeys { other: 2.into() }, + vec![] + )); // new stakes: // 10: 1000 self vote // 20: 1000 self vote + 250 vote @@ -1817,15 +1870,20 @@ fn bond_with_no_staked_value() { .build_and_execute(|| { // Can't bond with 1 assert_noop!( - Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller), + Staking::bond(RuntimeOrigin::signed(1), 2, 1, RewardDestination::Controller), Error::::InsufficientBond, ); // bonded with absolute minimum value possible. - assert_ok!(Staking::bond(Origin::signed(1), 2, 5, RewardDestination::Controller)); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(1), + 2, + 5, + RewardDestination::Controller + )); assert_eq!(Balances::locks(&1)[0].amount, 5); // unbonding even 1 will cause all to be unbonded. - assert_ok!(Staking::unbond(Origin::signed(2), 1)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(2), 1)); assert_eq!( Staking::ledger(2), Some(StakingLedger { @@ -1841,14 +1899,14 @@ fn bond_with_no_staked_value() { mock::start_active_era(2); // not yet removed. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(2), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(2), 0)); assert!(Staking::ledger(2).is_some()); assert_eq!(Balances::locks(&1)[0].amount, 5); mock::start_active_era(3); // poof. Account 1 is removed from the staking system. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(2), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(2), 0)); assert!(Staking::ledger(2).is_none()); assert_eq!(Balances::locks(&1).len(), 0); }); @@ -1862,16 +1920,24 @@ fn bond_with_little_staked_value_bounded() { .minimum_validator_count(1) .build_and_execute(|| { // setup - assert_ok!(Staking::chill(Origin::signed(30))); - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(30))); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(10), + RewardDestination::Controller + )); let init_balance_2 = Balances::free_balance(&2); let init_balance_10 = Balances::free_balance(&10); // Stingy validator. - assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(1), + 2, + 1, + RewardDestination::Controller + )); + assert_ok!(Staking::validate(RuntimeOrigin::signed(2), ValidatorPrefs::default())); assert_ok!(Session::set_keys( - Origin::signed(2), + RuntimeOrigin::signed(2), SessionKeys { other: 2.into() }, vec![] )); @@ -1944,11 +2010,21 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { let _ = Balances::make_free_balance_be(i, initial_balance); } - assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21, 31])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(1), + 2, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11, 11, 11, 21, 31])); - assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(3), + 4, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![21, 31])); // winners should be 21 and 31. Otherwise this election is taking duplicates into // account. @@ -1989,11 +2065,21 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { let _ = Balances::make_free_balance_be(i, initial_balance); } - assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(1), + 2, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11, 11, 11, 21])); - assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![21])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(3), + 4, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![21])); // winners should be 21 and 11. let supports = ::ElectionProvider::elect().unwrap(); @@ -2025,8 +2111,8 @@ fn phragmen_should_not_overflow() { // This is the maximum value that we can have as the outcome of CurrencyToVote. type Votes = u64; - let _ = Staking::chill(Origin::signed(10)); - let _ = Staking::chill(Origin::signed(20)); + let _ = Staking::chill(RuntimeOrigin::signed(10)); + let _ = Staking::chill(RuntimeOrigin::signed(20)); bond_validator(3, 2, Votes::max_value() as Balance); bond_validator(5, 4, Votes::max_value() as Balance); @@ -2067,7 +2153,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { ErasStakers::::insert(0, 11, &exposure); ErasStakersClipped::::insert(0, 11, exposure); ErasValidatorReward::::insert(0, stake); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 0)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); // Set staker @@ -2075,7 +2161,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { let _ = Balances::make_free_balance_be(&2, stake); // only slashes out of bonded stake are applied. without this line, it is 0. - Staking::bond(Origin::signed(2), 20000, stake - 1, RewardDestination::default()).unwrap(); + Staking::bond(RuntimeOrigin::signed(2), 20000, stake - 1, RewardDestination::default()) + .unwrap(); // Override exposure of 11 ErasStakers::::insert( 0, @@ -2151,7 +2238,7 @@ fn unbonded_balance_is_not_slashable() { // total amount staked is slashable. assert_eq!(Staking::slashable_balance_of(&11), 1000); - assert_ok!(Staking::unbond(Origin::signed(10), 800)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 800)); // only the active portion. assert_eq!(Staking::slashable_balance_of(&11), 200); @@ -2207,7 +2294,7 @@ fn offence_forces_new_era() { #[test] fn offence_ensures_new_era_without_clobbering() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(Staking::force_new_era_always(Origin::root())); + assert_ok!(Staking::force_new_era_always(RuntimeOrigin::root())); assert_eq!(Staking::force_era(), Forcing::ForceAlways); on_offence_now( @@ -2288,7 +2375,7 @@ fn slash_in_old_span_does_not_deselect() { mock::start_active_era(2); - Staking::validate(Origin::signed(10), Default::default()).unwrap(); + Staking::validate(RuntimeOrigin::signed(10), Default::default()).unwrap(); assert_eq!(Staking::force_era(), Forcing::NotForcing); assert!(>::contains_key(11)); assert!(!Session::validators().contains(&11)); @@ -2547,10 +2634,10 @@ fn garbage_collection_after_slashing() { // reap_stash respects num_slashing_spans so that weight is accurate assert_noop!( - Staking::reap_stash(Origin::signed(20), 11, 0), + Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0), Error::::IncorrectSlashingSpans ); - assert_ok!(Staking::reap_stash(Origin::signed(20), 11, 2)); + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 2)); assert!(::SlashingSpans::get(&11).is_none()); assert_eq!(::SpanSlash::get(&(11, 0)).amount(), &0); @@ -2713,7 +2800,7 @@ fn slashes_are_summed_across_spans() { assert_eq!(Balances::free_balance(21), 1900); // 21 has been force-chilled. re-signal intent to validate. - Staking::validate(Origin::signed(20), Default::default()).unwrap(); + Staking::validate(RuntimeOrigin::signed(20), Default::default()).unwrap(); mock::start_active_era(4); @@ -2832,8 +2919,8 @@ fn retroactive_deferred_slashes_one_before() { // unbond at slash era. mock::start_active_era(2); - assert_ok!(Staking::chill(Origin::signed(10))); - assert_ok!(Staking::unbond(Origin::signed(10), 100)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(10))); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 100)); mock::start_active_era(3); on_offence_in_era( @@ -2865,7 +2952,7 @@ fn retroactive_deferred_slashes_one_before() { // their ledger has already been slashed. assert_eq!(Staking::ledger(10).unwrap().total, 900); - assert_ok!(Staking::unbond(Origin::signed(10), 1000)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1000)); assert_eq!(Staking::ledger(10).unwrap().total, 900); }) } @@ -2891,8 +2978,8 @@ fn staker_cannot_bail_deferred_slash() { ); // now we chill - assert_ok!(Staking::chill(Origin::signed(100))); - assert_ok!(Staking::unbond(Origin::signed(100), 500)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(100))); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(100), 500)); assert_eq!(Staking::current_era().unwrap(), 1); assert_eq!(active_era(), 1); @@ -2927,7 +3014,9 @@ fn staker_cannot_bail_deferred_slash() { assert_eq!(active_era(), 3); // and cannot yet unbond: - assert_storage_noop!(assert!(Staking::withdraw_unbonded(Origin::signed(100), 0).is_ok())); + assert_storage_noop!(assert!( + Staking::withdraw_unbonded(RuntimeOrigin::signed(100), 0).is_ok() + )); assert_eq!( Ledger::::get(100).unwrap().unlocking.into_inner(), vec![UnlockChunk { era: 4u32, value: 500 as Balance }], @@ -2976,12 +3065,12 @@ fn remove_deferred() { // fails if empty assert_noop!( - Staking::cancel_deferred_slash(Origin::root(), 1, vec![]), + Staking::cancel_deferred_slash(RuntimeOrigin::root(), 1, vec![]), Error::::EmptyTargets ); // cancel one of them. - assert_ok!(Staking::cancel_deferred_slash(Origin::root(), 4, vec![0])); + assert_ok!(Staking::cancel_deferred_slash(RuntimeOrigin::root(), 4, vec![0])); assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); @@ -3062,21 +3151,21 @@ fn remove_multi_deferred() { // fails if list is not sorted assert_noop!( - Staking::cancel_deferred_slash(Origin::root(), 1, vec![2, 0, 4]), + Staking::cancel_deferred_slash(RuntimeOrigin::root(), 1, vec![2, 0, 4]), Error::::NotSortedAndUnique ); // fails if list is not unique assert_noop!( - Staking::cancel_deferred_slash(Origin::root(), 1, vec![0, 2, 2]), + Staking::cancel_deferred_slash(RuntimeOrigin::root(), 1, vec![0, 2, 2]), Error::::NotSortedAndUnique ); // fails if bad index assert_noop!( - Staking::cancel_deferred_slash(Origin::root(), 1, vec![1, 2, 3, 4, 5]), + Staking::cancel_deferred_slash(RuntimeOrigin::root(), 1, vec![1, 2, 3, 4, 5]), Error::::InvalidSlashIndex ); - assert_ok!(Staking::cancel_deferred_slash(Origin::root(), 4, vec![0, 2, 4])); + assert_ok!(Staking::cancel_deferred_slash(RuntimeOrigin::root(), 4, vec![0, 2, 4])); let slashes = ::UnappliedSlashes::get(&4); assert_eq!(slashes.len(), 2); @@ -3126,7 +3215,7 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert!(nominations.submitted_in < last_slash); // actually re-bond the slashed validator - assert_ok!(Staking::validate(Origin::signed(10), Default::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(10), Default::default())); mock::start_active_era(2); let exposure_11 = Staking::eras_stakers(active_era(), &11); @@ -3353,19 +3442,19 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // Last kept is 1: assert!(current_era - Staking::history_depth() == 1); assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 0), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0), // Fail: Era out of history Error::::InvalidEraToReward.with_weight(err_weight) ); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 2)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2)); assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 2), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2), // Fail: Double claim Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, active_era), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, active_era), // Fail: Era not finished yet Error::::InvalidEraToReward.with_weight(err_weight) ); @@ -3486,12 +3575,12 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( let balance = 10_000 + i as Balance; Balances::make_free_balance_be(&stash, balance); assert_ok!(Staking::bond( - Origin::signed(stash), + RuntimeOrigin::signed(stash), controller, balance, RewardDestination::Stash )); - assert_ok!(Staking::nominate(Origin::signed(controller), vec![11])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![11])); } mock::start_active_era(1); @@ -3519,16 +3608,16 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( fn set_history_depth_works() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(10); - Staking::set_history_depth(Origin::root(), 20, 0).unwrap(); + Staking::set_history_depth(RuntimeOrigin::root(), 20, 0).unwrap(); assert!(::ErasTotalStake::contains_key(10 - 4)); assert!(::ErasTotalStake::contains_key(10 - 5)); - Staking::set_history_depth(Origin::root(), 4, 0).unwrap(); + Staking::set_history_depth(RuntimeOrigin::root(), 4, 0).unwrap(); assert!(::ErasTotalStake::contains_key(10 - 4)); assert!(!::ErasTotalStake::contains_key(10 - 5)); - Staking::set_history_depth(Origin::root(), 3, 0).unwrap(); + Staking::set_history_depth(RuntimeOrigin::root(), 3, 0).unwrap(); assert!(!::ErasTotalStake::contains_key(10 - 4)); assert!(!::ErasTotalStake::contains_key(10 - 5)); - Staking::set_history_depth(Origin::root(), 8, 0).unwrap(); + Staking::set_history_depth(RuntimeOrigin::root(), 8, 0).unwrap(); assert!(!::ErasTotalStake::contains_key(10 - 4)); assert!(!::ErasTotalStake::contains_key(10 - 5)); }); @@ -3570,7 +3659,7 @@ fn test_payout_stakers() { let pre_payout_total_issuance = Balances::total_issuance(); RewardOnUnbalanceWasCalled::set(false); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); assert_eq_error_rate!( Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out, @@ -3611,7 +3700,7 @@ fn test_payout_stakers() { mock::start_active_era(i); RewardOnUnbalanceWasCalled::set(false); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, i - 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, i - 1)); assert_eq_error_rate!( Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out, @@ -3640,8 +3729,8 @@ fn test_payout_stakers() { } // We clean it up as history passes - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 15)); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 98)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 15)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 98)); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -3654,9 +3743,9 @@ fn test_payout_stakers() { ); // Out of order claims works. - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 69)); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 23)); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 42)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 69)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 23)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 42)); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -3696,12 +3785,12 @@ fn payout_stakers_handles_basic_errors() { // Wrong Era, too big assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 2), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2), Error::::InvalidEraToReward.with_weight(err_weight) ); // Wrong Staker assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 10, 1), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 10, 1), Error::::NotStash.with_weight(err_weight) ); @@ -3714,23 +3803,23 @@ fn payout_stakers_handles_basic_errors() { // We are at era 99, with history depth of 84 // We should be able to payout era 15 through 98 (84 total eras), but not 14 or 99. assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 14), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 14), Error::::InvalidEraToReward.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 99), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 99), Error::::InvalidEraToReward.with_weight(err_weight) ); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 15)); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 98)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 15)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 98)); // Can't claim again assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 15), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 15), Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 98), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 98), Error::::AlreadyClaimed.with_weight(err_weight) ); }); @@ -3780,7 +3869,7 @@ fn payout_stakers_handles_weight_refund() { // Collect payouts when there are no nominators let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 1 }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(20)); + let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), zero_nom_payouts_weight); @@ -3793,7 +3882,7 @@ fn payout_stakers_handles_weight_refund() { // Collect payouts for an era where the validator did not receive any points. let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 2 }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(20)); + let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), zero_nom_payouts_weight); @@ -3806,7 +3895,7 @@ fn payout_stakers_handles_weight_refund() { // Collect payouts when the validator has `half_max_nom_rewarded` nominators. let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 3 }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(20)); + let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), half_max_nom_rewarded_weight); @@ -3829,14 +3918,14 @@ fn payout_stakers_handles_weight_refund() { // Collect payouts when the validator had `half_max_nom_rewarded` nominators. let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(20)); + let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), max_nom_rewarded_weight); // Try and collect payouts for an era that has already been collected. let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(20)); + let result = call.dispatch(RuntimeOrigin::signed(20)); assert!(result.is_err()); // When there is an error the consumed weight == weight when there are 0 nominator payouts. assert_eq!(extract_actual_weight(&result, &info), zero_nom_payouts_weight); @@ -3965,7 +4054,7 @@ fn payout_creates_controller() { bond_nominator(1234, 1337, 100, vec![11]); // kill controller - assert_ok!(Balances::transfer(Origin::signed(1337), 1234, 100)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1337), 1234, 100)); assert_eq!(Balances::free_balance(1337), 0); mock::start_active_era(1); @@ -3973,7 +4062,7 @@ fn payout_creates_controller() { // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); // Controller is created assert!(Balances::free_balance(1337) > 0); @@ -3991,7 +4080,7 @@ fn payout_to_any_account_works() { bond_nominator(1234, 1337, 100, vec![11]); // Update payout location - assert_ok!(Staking::set_payee(Origin::signed(1337), RewardDestination::Account(42))); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(1337), RewardDestination::Account(42))); // Reward Destination account doesn't exist assert_eq!(Balances::free_balance(42), 0); @@ -4001,7 +4090,7 @@ fn payout_to_any_account_works() { // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); // Payment is successful assert!(Balances::free_balance(42) > 0); @@ -4129,8 +4218,8 @@ fn cannot_rebond_to_lower_than_ed() { ); // unbond all of it. must be chilled first. - assert_ok!(Staking::chill(Origin::signed(20))); - assert_ok!(Staking::unbond(Origin::signed(20), 10 * 1000)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(20))); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(20), 10 * 1000)); assert_eq!( Staking::ledger(&20).unwrap(), StakingLedger { @@ -4143,7 +4232,10 @@ fn cannot_rebond_to_lower_than_ed() { ); // now bond a wee bit more - assert_noop!(Staking::rebond(Origin::signed(20), 5), Error::::InsufficientBond); + assert_noop!( + Staking::rebond(RuntimeOrigin::signed(20), 5), + Error::::InsufficientBond + ); }) } @@ -4166,8 +4258,8 @@ fn cannot_bond_extra_to_lower_than_ed() { ); // unbond all of it. must be chilled first. - assert_ok!(Staking::chill(Origin::signed(20))); - assert_ok!(Staking::unbond(Origin::signed(20), 10 * 1000)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(20))); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(20), 10 * 1000)); assert_eq!( Staking::ledger(&20).unwrap(), StakingLedger { @@ -4181,7 +4273,7 @@ fn cannot_bond_extra_to_lower_than_ed() { // now bond a wee bit more assert_noop!( - Staking::bond_extra(Origin::signed(21), 5), + Staking::bond_extra(RuntimeOrigin::signed(21), 5), Error::::InsufficientBond, ); }) @@ -4207,9 +4299,9 @@ fn do_not_die_when_active_is_ed() { ); // when unbond all of it except ed. - assert_ok!(Staking::unbond(Origin::signed(20), 999 * ed)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(20), 999 * ed)); start_active_era(3); - assert_ok!(Staking::withdraw_unbonded(Origin::signed(20), 100)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(20), 100)); // then assert_eq!( @@ -4312,7 +4404,7 @@ mod election_data_provider { ); // resubmit and it is back - assert_ok!(Staking::nominate(Origin::signed(100), vec![11, 21])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(100), vec![11, 21])); assert_eq!( ::electing_voters(None) .unwrap() @@ -4470,13 +4562,13 @@ mod election_data_provider { assert_eq!(staking_events().len(), 3); assert_eq!(*staking_events().last().unwrap(), Event::StakersElected); - Staking::force_no_eras(Origin::root()).unwrap(); + Staking::force_no_eras(RuntimeOrigin::root()).unwrap(); assert_eq!(Staking::next_election_prediction(System::block_number()), u64::MAX); - Staking::force_new_era_always(Origin::root()).unwrap(); + Staking::force_new_era_always(RuntimeOrigin::root()).unwrap(); assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5); - Staking::force_new_era(Origin::root()).unwrap(); + Staking::force_new_era(RuntimeOrigin::root()).unwrap(); assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5); // Do a fail election @@ -4526,40 +4618,51 @@ fn min_bond_checks_work() { .min_validator_bond(1_500) .build_and_execute(|| { // 500 is not enough for any role - assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller)); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(3), + 4, + 500, + RewardDestination::Controller + )); assert_noop!( - Staking::nominate(Origin::signed(4), vec![1]), + Staking::nominate(RuntimeOrigin::signed(4), vec![1]), Error::::InsufficientBond ); assert_noop!( - Staking::validate(Origin::signed(4), ValidatorPrefs::default()), + Staking::validate(RuntimeOrigin::signed(4), ValidatorPrefs::default()), Error::::InsufficientBond, ); // 1000 is enough for nominator - assert_ok!(Staking::bond_extra(Origin::signed(3), 500)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![1])); + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(3), 500)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![1])); assert_noop!( - Staking::validate(Origin::signed(4), ValidatorPrefs::default()), + Staking::validate(RuntimeOrigin::signed(4), ValidatorPrefs::default()), Error::::InsufficientBond, ); // 1500 is enough for validator - assert_ok!(Staking::bond_extra(Origin::signed(3), 500)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![1])); - assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(3), 500)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![1])); + assert_ok!(Staking::validate(RuntimeOrigin::signed(4), ValidatorPrefs::default())); // Can't unbond anything as validator - assert_noop!(Staking::unbond(Origin::signed(4), 500), Error::::InsufficientBond); + assert_noop!( + Staking::unbond(RuntimeOrigin::signed(4), 500), + Error::::InsufficientBond + ); // Once they are a nominator, they can unbond 500 - assert_ok!(Staking::nominate(Origin::signed(4), vec![1])); - assert_ok!(Staking::unbond(Origin::signed(4), 500)); - assert_noop!(Staking::unbond(Origin::signed(4), 500), Error::::InsufficientBond); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![1])); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(4), 500)); + assert_noop!( + Staking::unbond(RuntimeOrigin::signed(4), 500), + Error::::InsufficientBond + ); // Once they are chilled they can unbond everything - assert_ok!(Staking::chill(Origin::signed(4))); - assert_ok!(Staking::unbond(Origin::signed(4), 1000)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(4))); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(4), 1000)); }) } @@ -4585,21 +4688,21 @@ fn chill_other_works() { // Nominator assert_ok!(Staking::bond( - Origin::signed(a), + RuntimeOrigin::signed(a), b, 1000, RewardDestination::Controller )); - assert_ok!(Staking::nominate(Origin::signed(b), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(b), vec![1])); // Validator assert_ok!(Staking::bond( - Origin::signed(c), + RuntimeOrigin::signed(c), d, 1500, RewardDestination::Controller )); - assert_ok!(Staking::validate(Origin::signed(d), ValidatorPrefs::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(d), ValidatorPrefs::default())); } // To chill other users, we need to: @@ -4612,17 +4715,17 @@ fn chill_other_works() { // Can't chill these users assert_noop!( - Staking::chill_other(Origin::signed(1337), 1), + Staking::chill_other(RuntimeOrigin::signed(1337), 1), Error::::CannotChillOther ); assert_noop!( - Staking::chill_other(Origin::signed(1337), 3), + Staking::chill_other(RuntimeOrigin::signed(1337), 3), Error::::CannotChillOther ); // Change the minimum bond... but no limits. assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Set(1_500), ConfigOp::Set(2_000), ConfigOp::Remove, @@ -4633,17 +4736,17 @@ fn chill_other_works() { // Still can't chill these users assert_noop!( - Staking::chill_other(Origin::signed(1337), 1), + Staking::chill_other(RuntimeOrigin::signed(1337), 1), Error::::CannotChillOther ); assert_noop!( - Staking::chill_other(Origin::signed(1337), 3), + Staking::chill_other(RuntimeOrigin::signed(1337), 3), Error::::CannotChillOther ); // Add limits, but no threshold assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Set(10), @@ -4654,17 +4757,17 @@ fn chill_other_works() { // Still can't chill these users assert_noop!( - Staking::chill_other(Origin::signed(1337), 1), + Staking::chill_other(RuntimeOrigin::signed(1337), 1), Error::::CannotChillOther ); assert_noop!( - Staking::chill_other(Origin::signed(1337), 3), + Staking::chill_other(RuntimeOrigin::signed(1337), 3), Error::::CannotChillOther ); // Add threshold, but no limits assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Remove, @@ -4675,17 +4778,17 @@ fn chill_other_works() { // Still can't chill these users assert_noop!( - Staking::chill_other(Origin::signed(1337), 1), + Staking::chill_other(RuntimeOrigin::signed(1337), 1), Error::::CannotChillOther ); assert_noop!( - Staking::chill_other(Origin::signed(1337), 3), + Staking::chill_other(RuntimeOrigin::signed(1337), 3), Error::::CannotChillOther ); // Add threshold and limits assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Set(10), @@ -4703,19 +4806,19 @@ fn chill_other_works() { for i in 6..15 { let b = 4 * i + 1; let d = 4 * i + 3; - assert_ok!(Staking::chill_other(Origin::signed(1337), b)); - assert_ok!(Staking::chill_other(Origin::signed(1337), d)); + assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), b)); + assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), d)); } // chill a nominator. Limit is not reached, not chill-able assert_eq!(Nominators::::count(), 7); assert_noop!( - Staking::chill_other(Origin::signed(1337), 1), + Staking::chill_other(RuntimeOrigin::signed(1337), 1), Error::::CannotChillOther ); // chill a validator. Limit is reached, chill-able. assert_eq!(Validators::::count(), 9); - assert_ok!(Staking::chill_other(Origin::signed(1337), 3)); + assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), 3)); }) } @@ -4730,7 +4833,7 @@ fn capped_stakers_works() { // Change the maximums let max = 10; assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Set(10), ConfigOp::Set(10), ConfigOp::Set(max), @@ -4748,7 +4851,10 @@ fn capped_stakers_works() { RewardDestination::Controller, ) .unwrap(); - assert_ok!(Staking::validate(Origin::signed(controller), ValidatorPrefs::default())); + assert_ok!(Staking::validate( + RuntimeOrigin::signed(controller), + ValidatorPrefs::default() + )); some_existing_validator = controller; } @@ -4761,7 +4867,7 @@ fn capped_stakers_works() { .unwrap(); assert_noop!( - Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default()), + Staking::validate(RuntimeOrigin::signed(last_validator), ValidatorPrefs::default()), Error::::TooManyValidators, ); @@ -4774,7 +4880,7 @@ fn capped_stakers_works() { RewardDestination::Controller, ) .unwrap(); - assert_ok!(Staking::nominate(Origin::signed(controller), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![1])); some_existing_nominator = controller; } @@ -4786,21 +4892,21 @@ fn capped_stakers_works() { ) .unwrap(); assert_noop!( - Staking::nominate(Origin::signed(last_nominator), vec![1]), + Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1]), Error::::TooManyNominators ); // Re-nominate works fine - assert_ok!(Staking::nominate(Origin::signed(some_existing_nominator), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(some_existing_nominator), vec![1])); // Re-validate works fine assert_ok!(Staking::validate( - Origin::signed(some_existing_validator), + RuntimeOrigin::signed(some_existing_validator), ValidatorPrefs::default() )); // No problem when we set to `None` again assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Remove, @@ -4808,8 +4914,11 @@ fn capped_stakers_works() { ConfigOp::Noop, ConfigOp::Noop, )); - assert_ok!(Staking::nominate(Origin::signed(last_nominator), vec![1])); - assert_ok!(Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default())); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1])); + assert_ok!(Staking::validate( + RuntimeOrigin::signed(last_validator), + ValidatorPrefs::default() + )); }) } @@ -4818,7 +4927,7 @@ fn min_commission_works() { ExtBuilder::default().build_and_execute(|| { // account 10 controls the stash from account 11 assert_ok!(Staking::validate( - Origin::signed(10), + RuntimeOrigin::signed(10), ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } )); @@ -4832,7 +4941,7 @@ fn min_commission_works() { ); assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, @@ -4844,7 +4953,7 @@ fn min_commission_works() { // can't make it less than 10 now assert_noop!( Staking::validate( - Origin::signed(10), + RuntimeOrigin::signed(10), ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } ), Error::::CommissionTooLow @@ -4852,12 +4961,12 @@ fn min_commission_works() { // can only change to higher. assert_ok!(Staking::validate( - Origin::signed(10), + RuntimeOrigin::signed(10), ValidatorPrefs { commission: Perbill::from_percent(10), blocked: false } )); assert_ok!(Staking::validate( - Origin::signed(10), + RuntimeOrigin::signed(10), ValidatorPrefs { commission: Perbill::from_percent(15), blocked: false } )); }) @@ -4940,7 +5049,7 @@ fn change_of_max_nominations() { assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 1); // now one of them can revive themselves by re-nominating to a proper value. - assert_ok!(Staking::nominate(Origin::signed(71), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(71), vec![1])); assert_eq!( Nominators::::iter() .map(|(k, n)| (k, n.targets.len())) @@ -4951,7 +5060,7 @@ fn change_of_max_nominations() { // or they can be chilled by any account. assert!(Nominators::::contains_key(101)); assert!(Nominators::::get(101).is_none()); - assert_ok!(Staking::chill_other(Origin::signed(70), 100)); + assert_ok!(Staking::chill_other(RuntimeOrigin::signed(70), 100)); assert!(!Nominators::::contains_key(101)); assert!(Nominators::::get(101).is_none()); }) @@ -4975,7 +5084,7 @@ mod sorted_list_provider { ); // when account 101 renominates - assert_ok!(Staking::nominate(Origin::signed(100), vec![41])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(100), vec![41])); // then counts don't change assert_eq!(::VoterList::count(), pre_insert_voter_count); @@ -4998,7 +5107,7 @@ mod sorted_list_provider { assert_eq!(::VoterList::iter().collect::>(), vec![11, 21, 31]); // when account 11 re-validates - assert_ok!(Staking::validate(Origin::signed(10), Default::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(10), Default::default())); // then counts don't change assert_eq!(::VoterList::count(), pre_insert_voter_count); @@ -5013,31 +5122,31 @@ fn force_apply_min_commission_works() { let prefs = |c| ValidatorPrefs { commission: Perbill::from_percent(c), blocked: false }; let validators = || Validators::::iter().collect::>(); ExtBuilder::default().build_and_execute(|| { - assert_ok!(Staking::validate(Origin::signed(30), prefs(10))); - assert_ok!(Staking::validate(Origin::signed(20), prefs(5))); + assert_ok!(Staking::validate(RuntimeOrigin::signed(30), prefs(10))); + assert_ok!(Staking::validate(RuntimeOrigin::signed(20), prefs(5))); // Given assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]); MinCommission::::set(Perbill::from_percent(5)); // When applying to a commission greater than min - assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 31)); + assert_ok!(Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 31)); // Then the commission is not changed assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]); // When applying to a commission that is equal to min - assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 21)); + assert_ok!(Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 21)); // Then the commission is not changed assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]); // When applying to a commission that is less than the min - assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 11)); + assert_ok!(Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 11)); // Then the commission is bumped to the min assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(5))]); // When applying commission to a validator that doesn't exist then storage is not altered assert_noop!( - Staking::force_apply_min_commission(Origin::signed(1), 420), + Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 420), Error::::NotStash ); }); diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 8c73f99be3aea..3f81d3c211a95 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -446,10 +446,10 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// Origin that can control the configurations of this pallet. - type ControlOrigin: frame_support::traits::EnsureOrigin; + type ControlOrigin: frame_support::traits::EnsureOrigin; /// Filter on which origin that trigger the manual migrations. - type SignedFilter: EnsureOrigin; + type SignedFilter: EnsureOrigin; /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -1084,7 +1084,7 @@ mod mock { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u32; @@ -1293,7 +1293,7 @@ mod test { // fails if the top key is too long. frame_support::assert_ok!(StateTrieMigration::continue_migrate( - Origin::signed(1), + RuntimeOrigin::signed(1), MigrationLimits { item: 50, size: 1 << 20 }, Bounded::max_value(), MigrationProcess::::get() @@ -1328,7 +1328,7 @@ mod test { // fails if the top key is too long. frame_support::assert_ok!(StateTrieMigration::continue_migrate( - Origin::signed(1), + RuntimeOrigin::signed(1), MigrationLimits { item: 50, size: 1 << 20 }, Bounded::max_value(), MigrationProcess::::get() @@ -1457,7 +1457,7 @@ mod test { // can't submit if limit is too high. frame_support::assert_err!( StateTrieMigration::continue_migrate( - Origin::signed(1), + RuntimeOrigin::signed(1), MigrationLimits { item: 5, size: sp_runtime::traits::Bounded::max_value() }, Bounded::max_value(), MigrationProcess::::get() @@ -1468,7 +1468,7 @@ mod test { // can't submit if poor. frame_support::assert_err!( StateTrieMigration::continue_migrate( - Origin::signed(2), + RuntimeOrigin::signed(2), MigrationLimits { item: 5, size: 100 }, 100, MigrationProcess::::get() @@ -1479,7 +1479,7 @@ mod test { // can't submit with bad witness. frame_support::assert_err_ignore_postinfo!( StateTrieMigration::continue_migrate( - Origin::signed(1), + RuntimeOrigin::signed(1), MigrationLimits { item: 5, size: 100 }, 100, MigrationTask { @@ -1500,7 +1500,7 @@ mod test { assert!(result.is_ok()); frame_support::assert_ok!(StateTrieMigration::continue_migrate( - Origin::signed(1), + RuntimeOrigin::signed(1), StateTrieMigration::signed_migration_max_limits().unwrap(), task.dyn_size, MigrationProcess::::get() @@ -1523,7 +1523,7 @@ mod test { let correct_witness = 3 + sp_core::storage::TRIE_VALUE_NODE_THRESHOLD * 3 + 1 + 2 + 3; new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { frame_support::assert_ok!(StateTrieMigration::migrate_custom_top( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], correct_witness, )); @@ -1536,7 +1536,7 @@ mod test { new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { // works if the witness is an overestimate frame_support::assert_ok!(StateTrieMigration::migrate_custom_top( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], correct_witness + 99, )); @@ -1551,7 +1551,7 @@ mod test { // note that we don't expect this to be a noop -- we do slash. frame_support::assert_ok!(StateTrieMigration::migrate_custom_top( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], correct_witness - 1, ),); @@ -1569,7 +1569,7 @@ mod test { fn custom_migrate_child_works() { new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { frame_support::assert_ok!(StateTrieMigration::migrate_custom_child( - Origin::signed(1), + RuntimeOrigin::signed(1), StateTrieMigration::childify("chk1"), vec![b"key1".to_vec(), b"key2".to_vec()], 55 + 66, @@ -1585,7 +1585,7 @@ mod test { // note that we don't expect this to be a noop -- we do slash. frame_support::assert_ok!(StateTrieMigration::migrate_custom_child( - Origin::signed(1), + RuntimeOrigin::signed(1), StateTrieMigration::childify("chk1"), vec![b"key1".to_vec(), b"key2".to_vec()], 999999, // wrong witness diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 69eac2c1b93c4..75d15d23c680a 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -119,7 +119,7 @@ pub mod pallet { /// A sudo-able call. type RuntimeCall: Parameter - + UnfilteredDispatchable + + UnfilteredDispatchable + GetDispatchInfo; } diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index 67c221b234de1..db2ad4d563910 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -125,7 +125,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/frame/sudo/src/tests.rs b/frame/sudo/src/tests.rs index fbf4063c992e4..ae8f198736004 100644 --- a/frame/sudo/src/tests.rs +++ b/frame/sudo/src/tests.rs @@ -20,7 +20,7 @@ use super::*; use frame_support::{assert_noop, assert_ok, weights::Weight}; use mock::{ - new_test_ext, Logger, LoggerCall, Origin, RuntimeCall, RuntimeEvent as TestEvent, Sudo, + new_test_ext, Logger, LoggerCall, RuntimeCall, RuntimeEvent as TestEvent, RuntimeOrigin, Sudo, SudoCall, System, Test, }; @@ -43,7 +43,7 @@ fn sudo_basics() { i: 42, weight: Weight::from_ref_time(1_000), })); - assert_ok!(Sudo::sudo(Origin::signed(1), call)); + assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call)); assert_eq!(Logger::i32_log(), vec![42i32]); // A privileged function should not work when `sudo` is passed a non-root `key` as `origin`. @@ -51,7 +51,7 @@ fn sudo_basics() { i: 42, weight: Weight::from_ref_time(1_000), })); - assert_noop!(Sudo::sudo(Origin::signed(2), call), Error::::RequireSudo); + assert_noop!(Sudo::sudo(RuntimeOrigin::signed(2), call), Error::::RequireSudo); }); } @@ -66,7 +66,7 @@ fn sudo_emits_events_correctly() { i: 42, weight: Weight::from_ref_time(1), })); - assert_ok!(Sudo::sudo(Origin::signed(1), call)); + assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call)); System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) })); }) } @@ -80,7 +80,7 @@ fn sudo_unchecked_weight_basics() { weight: Weight::from_ref_time(1_000), })); assert_ok!(Sudo::sudo_unchecked_weight( - Origin::signed(1), + RuntimeOrigin::signed(1), call, Weight::from_ref_time(1_000) )); @@ -92,7 +92,11 @@ fn sudo_unchecked_weight_basics() { weight: Weight::from_ref_time(1_000), })); assert_noop!( - Sudo::sudo_unchecked_weight(Origin::signed(2), call, Weight::from_ref_time(1_000)), + Sudo::sudo_unchecked_weight( + RuntimeOrigin::signed(2), + call, + Weight::from_ref_time(1_000) + ), Error::::RequireSudo, ); // `I32Log` is unchanged after unsuccessful call. @@ -122,7 +126,7 @@ fn sudo_unchecked_weight_emits_events_correctly() { weight: Weight::from_ref_time(1), })); assert_ok!(Sudo::sudo_unchecked_weight( - Origin::signed(1), + RuntimeOrigin::signed(1), call, Weight::from_ref_time(1_000) )); @@ -134,14 +138,14 @@ fn sudo_unchecked_weight_emits_events_correctly() { fn set_key_basics() { new_test_ext(1).execute_with(|| { // A root `key` can change the root `key` - assert_ok!(Sudo::set_key(Origin::signed(1), 2)); + assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2)); assert_eq!(Sudo::key(), Some(2u64)); }); new_test_ext(1).execute_with(|| { // A non-root `key` will trigger a `RequireSudo` error and a non-root `key` cannot change // the root `key`. - assert_noop!(Sudo::set_key(Origin::signed(2), 3), Error::::RequireSudo); + assert_noop!(Sudo::set_key(RuntimeOrigin::signed(2), 3), Error::::RequireSudo); }); } @@ -152,10 +156,10 @@ fn set_key_emits_events_correctly() { System::set_block_number(1); // A root `key` can change the root `key`. - assert_ok!(Sudo::set_key(Origin::signed(1), 2)); + assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2)); System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old_sudoer: Some(1) })); // Double check. - assert_ok!(Sudo::set_key(Origin::signed(2), 4)); + assert_ok!(Sudo::set_key(RuntimeOrigin::signed(2), 4)); System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old_sudoer: Some(2) })); }); } @@ -168,7 +172,7 @@ fn sudo_as_basics() { i: 42, weight: Weight::from_ref_time(1_000), })); - assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); + assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call)); assert!(Logger::i32_log().is_empty()); assert!(Logger::account_log().is_empty()); @@ -177,14 +181,14 @@ fn sudo_as_basics() { i: 42, weight: Weight::from_ref_time(1), })); - assert_noop!(Sudo::sudo_as(Origin::signed(3), 2, call), Error::::RequireSudo); + assert_noop!(Sudo::sudo_as(RuntimeOrigin::signed(3), 2, call), Error::::RequireSudo); // A non-privileged function will work when passed to `sudo_as` with the root `key`. let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::from_ref_time(1), })); - assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); + assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call)); assert_eq!(Logger::i32_log(), vec![42i32]); // The correct user makes the call within `sudo_as`. assert_eq!(Logger::account_log(), vec![2]); @@ -202,7 +206,7 @@ fn sudo_as_emits_events_correctly() { i: 42, weight: Weight::from_ref_time(1), })); - assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); + assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call)); System::assert_has_event(TestEvent::Sudo(Event::SudoAsDone { sudo_result: Ok(()) })); }); } diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index 101f0c371382f..8f07448f5785e 100644 --- a/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -162,12 +162,12 @@ pub fn expand_outer_dispatch( } } impl #scrate::dispatch::Dispatchable for RuntimeCall { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Config = RuntimeCall; type Info = #scrate::dispatch::DispatchInfo; type PostInfo = #scrate::dispatch::PostDispatchInfo; - fn dispatch(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { - if !::filter_call(&origin, &self) { + fn dispatch(self, origin: RuntimeOrigin) -> #scrate::dispatch::DispatchResultWithPostInfo { + if !::filter_call(&origin, &self) { return #scrate::sp_std::result::Result::Err( #system_path::Error::<#runtime>::CallFiltered.into() ); @@ -177,8 +177,8 @@ pub fn expand_outer_dispatch( } } impl #scrate::traits::UnfilteredDispatchable for RuntimeCall { - type Origin = Origin; - fn dispatch_bypass_filter(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { + type RuntimeOrigin = RuntimeOrigin; + fn dispatch_bypass_filter(self, origin: RuntimeOrigin) -> #scrate::dispatch::DispatchResultWithPostInfo { match self { #( #pallet_attrs diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index d234ca6415115..acbcb65a3e986 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -103,13 +103,13 @@ pub fn expand_outer_origin( /// #[doc = #doc_string] #[derive(Clone)] - pub struct Origin { + pub struct RuntimeOrigin { caller: OriginCaller, filter: #scrate::sp_std::rc::Rc::RuntimeCall) -> bool>>, } #[cfg(not(feature = "std"))] - impl #scrate::sp_std::fmt::Debug for Origin { + impl #scrate::sp_std::fmt::Debug for RuntimeOrigin { fn fmt( &self, fmt: &mut #scrate::sp_std::fmt::Formatter, @@ -119,7 +119,7 @@ pub fn expand_outer_origin( } #[cfg(feature = "std")] - impl #scrate::sp_std::fmt::Debug for Origin { + impl #scrate::sp_std::fmt::Debug for RuntimeOrigin { fn fmt( &self, fmt: &mut #scrate::sp_std::fmt::Formatter, @@ -131,7 +131,7 @@ pub fn expand_outer_origin( } } - impl #scrate::traits::OriginTrait for Origin { + impl #scrate::traits::OriginTrait for RuntimeOrigin { type Call = <#runtime as #system_path::Config>::RuntimeCall; type PalletsOrigin = OriginCaller; type AccountId = <#runtime as #system_path::Config>::AccountId; @@ -214,21 +214,21 @@ pub fn expand_outer_origin( // For backwards compatibility and ease of accessing these functions. #[allow(dead_code)] - impl Origin { + impl RuntimeOrigin { #[doc = #doc_string_none_origin] pub fn none() -> Self { - ::none() + ::none() } #[doc = #doc_string_root_origin] pub fn root() -> Self { - ::root() + ::root() } #[doc = #doc_string_signed_origin] pub fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self { - ::signed(by) + ::signed(by) } } @@ -251,7 +251,7 @@ pub fn expand_outer_origin( } } - impl From<#system_path::Origin<#runtime>> for Origin { + impl From<#system_path::Origin<#runtime>> for RuntimeOrigin { #[doc = #doc_string_runtime_origin] fn from(x: #system_path::Origin<#runtime>) -> Self { @@ -260,9 +260,9 @@ pub fn expand_outer_origin( } } - impl From for Origin { + impl From for RuntimeOrigin { fn from(x: OriginCaller) -> Self { - let mut o = Origin { + let mut o = RuntimeOrigin { caller: x, filter: #scrate::sp_std::rc::Rc::new(Box::new(|_| true)), }; @@ -273,9 +273,9 @@ pub fn expand_outer_origin( } } - impl From for #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, Origin> { + impl From for #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, RuntimeOrigin> { /// NOTE: converting to pallet origin loses the origin filter information. - fn from(val: Origin) -> Self { + fn from(val: RuntimeOrigin) -> Self { if let OriginCaller::system(l) = val.caller { Ok(l) } else { @@ -283,7 +283,7 @@ pub fn expand_outer_origin( } } } - impl From::AccountId>> for Origin { + impl From::AccountId>> for RuntimeOrigin { #[doc = #doc_string_runtime_origin_with_caller] fn from(x: Option<<#runtime as #system_path::Config>::AccountId>) -> Self { <#system_path::Origin<#runtime>>::from(x).into() @@ -374,7 +374,7 @@ fn expand_origin_pallet_conversions( } #attr - impl From<#pallet_origin> for Origin { + impl From<#pallet_origin> for RuntimeOrigin { #[doc = #doc_string] fn from(x: #pallet_origin) -> Self { let x: OriginCaller = x.into(); @@ -383,9 +383,9 @@ fn expand_origin_pallet_conversions( } #attr - impl From for #scrate::sp_std::result::Result<#pallet_origin, Origin> { + impl From for #scrate::sp_std::result::Result<#pallet_origin, RuntimeOrigin> { /// NOTE: converting to pallet origin loses the origin filter information. - fn from(val: Origin) -> Self { + fn from(val: RuntimeOrigin) -> Self { if let OriginCaller::#variant_name(l) = val.caller { Ok(l) } else { diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index d5c84fa37510d..18d5adee63ad6 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -278,10 +278,10 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { for #call_ident<#type_use_gen> #where_clause { - type Origin = #frame_system::pallet_prelude::OriginFor; + type RuntimeOrigin = #frame_system::pallet_prelude::OriginFor; fn dispatch_bypass_filter( self, - origin: Self::Origin + origin: Self::RuntimeOrigin ) -> #frame_support::dispatch::DispatchResultWithPostInfo { match self { #( diff --git a/frame/support/procedural/src/pallet/parse/mod.rs b/frame/support/procedural/src/pallet/parse/mod.rs index f1e520952d872..8b4ab154b306a 100644 --- a/frame/support/procedural/src/pallet/parse/mod.rs +++ b/frame/support/procedural/src/pallet/parse/mod.rs @@ -119,7 +119,7 @@ impl Def { let g = genesis_build::GenesisBuildDef::try_from(span, index, item)?; genesis_build = Some(g); }, - Some(PalletAttr::Origin(_)) if origin.is_none() => + Some(PalletAttr::RuntimeOrigin(_)) if origin.is_none() => origin = Some(origin::OriginDef::try_from(index, item)?), Some(PalletAttr::Inherent(_)) if inherent.is_none() => inherent = Some(inherent::InherentDef::try_from(index, item)?), @@ -394,7 +394,7 @@ enum PalletAttr { RuntimeCall(proc_macro2::Span), Error(proc_macro2::Span), RuntimeEvent(proc_macro2::Span), - Origin(proc_macro2::Span), + RuntimeOrigin(proc_macro2::Span), Inherent(proc_macro2::Span), Storage(proc_macro2::Span), GenesisConfig(proc_macro2::Span), @@ -413,7 +413,7 @@ impl PalletAttr { Self::RuntimeCall(span) => *span, Self::Error(span) => *span, Self::RuntimeEvent(span) => *span, - Self::Origin(span) => *span, + Self::RuntimeOrigin(span) => *span, Self::Inherent(span) => *span, Self::Storage(span) => *span, Self::GenesisConfig(span) => *span, @@ -447,7 +447,7 @@ impl syn::parse::Parse for PalletAttr { } else if lookahead.peek(keyword::event) { Ok(PalletAttr::RuntimeEvent(content.parse::()?.span())) } else if lookahead.peek(keyword::origin) { - Ok(PalletAttr::Origin(content.parse::()?.span())) + Ok(PalletAttr::RuntimeOrigin(content.parse::()?.span())) } else if lookahead.peek(keyword::inherent) { Ok(PalletAttr::Inherent(content.parse::()?.span())) } else if lookahead.peek(keyword::storage) { diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index cacd599fa008c..db2bc90658ee2 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -650,7 +650,7 @@ impl PaysFee for (u64, Pays) { /// # use frame_support::dispatch; /// # use frame_system::{Config, ensure_signed}; /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// /// // Private functions are dispatchable, but not available to other /// // FRAME pallets. @@ -677,7 +677,7 @@ impl PaysFee for (u64, Pays) { /// * `Module`: The struct generated by the macro, with type `Config`. /// * `Call`: The enum generated for every pallet, which implements /// [`Callable`](./dispatch/trait.Callable.html). -/// * `origin`: Alias of `T::Origin`. +/// * `origin`: Alias of `T::RuntimeOrigin`. /// * `Result`: The expected return type from pallet functions. /// /// The first parameter of dispatchable functions must always be `origin`. @@ -693,7 +693,7 @@ impl PaysFee for (u64, Pays) { /// # use frame_support::dispatch; /// # use frame_system::{Config, ensure_signed}; /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// #[weight = 0] /// fn my_long_function(origin) -> dispatch::DispatchResult { /// // Your implementation @@ -728,7 +728,7 @@ impl PaysFee for (u64, Pays) { /// # use frame_support::{weights::Weight, dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo}}; /// # use frame_system::{Config, ensure_signed}; /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// #[weight = 1_000_000] /// fn my_long_function(origin, do_expensive_calc: bool) -> DispatchResultWithPostInfo { /// ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100_000)))?; @@ -758,7 +758,7 @@ impl PaysFee for (u64, Pays) { /// # use frame_support::transactional; /// # use frame_system::Config; /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// #[weight = 0] /// #[transactional] /// fn my_short_function(origin) { @@ -779,7 +779,7 @@ impl PaysFee for (u64, Pays) { /// # use frame_support::dispatch; /// # use frame_system::{Config, ensure_signed, ensure_root}; /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// #[weight = 0] /// fn my_privileged_function(origin) -> dispatch::DispatchResult { /// ensure_root(origin)?; @@ -819,7 +819,7 @@ impl PaysFee for (u64, Pays) { /// pub trait Config: frame_system::Config {} /// /// decl_module! { -/// pub struct Module, I: Instance = DefaultInstance> for enum Call where origin: T::Origin { +/// pub struct Module, I: Instance = DefaultInstance> for enum Call where origin: T::RuntimeOrigin { /// // Your implementation /// } /// } @@ -831,7 +831,7 @@ impl PaysFee for (u64, Pays) { /// /// ## Where clause /// -/// Besides the default `origin: T::Origin`, you can also pass other bounds to the module +/// Besides the default `origin: T::RuntimeOrigin`, you can also pass other bounds to the module /// declaration. This where bound will be replicated to all types generated by this macro. The /// chaining of multiple trait bounds with `+` is not supported. If multiple bounds for one type are /// required, it needs to be split up into multiple bounds. @@ -844,7 +844,7 @@ impl PaysFee for (u64, Pays) { /// pub trait Config: system::Config where Self::AccountId: From {} /// /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin, T::AccountId: From { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin, T::AccountId: From { /// // Your implementation /// } /// } @@ -1885,7 +1885,7 @@ macro_rules! decl_module { ) ); }; - // Ignore any ident which is not `origin` with type `T::Origin`. + // Ignore any ident which is not `origin` with type `T::RuntimeOrigin`. (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> @@ -1906,7 +1906,7 @@ macro_rules! decl_module { $(#[weight = $weight:expr])? $(#[$fn_attr:meta])* $fn_vis:vis fn $fn_name:ident( - $origin:ident : T::Origin $( , $( #[$codec_attr:ident] )* $param_name:ident : $param:ty )* $(,)? + $origin:ident : T::RuntimeOrigin $( , $( #[$codec_attr:ident] )* $param_name:ident : $param:ty )* $(,)? ) $( -> $result:ty )* { $( $impl:tt )* } $($rest:tt)* ) => { @@ -2906,8 +2906,8 @@ macro_rules! decl_module { impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::traits::UnfilteredDispatchable for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { - type Origin = $origin_type; - fn dispatch_bypass_filter(self, _origin: Self::Origin) -> $crate::dispatch::DispatchResultWithPostInfo { + type RuntimeOrigin = $origin_type; + fn dispatch_bypass_filter(self, _origin: Self::RuntimeOrigin) -> $crate::dispatch::DispatchResultWithPostInfo { match self { $( $call_type::$fn_name { $( $param_name ),* } => { @@ -3200,7 +3200,7 @@ mod tests { type AccountId; type RuntimeCall; type BaseCallFilter; - type Origin: crate::traits::OriginTrait; + type RuntimeOrigin: crate::traits::OriginTrait; type BlockNumber: Into; type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; @@ -3212,7 +3212,7 @@ mod tests { } decl_module! { - pub struct Module for enum Call where origin: T::Origin, system = system, T::AccountId: From { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system = system, T::AccountId: From { /// Hi, this is a comment. #[weight = 0] fn aux_0(_origin) -> DispatchResult { unreachable!() } @@ -3347,7 +3347,7 @@ mod tests { } impl system::Config for TraitImpl { - type Origin = OuterOrigin; + type RuntimeOrigin = OuterOrigin; type AccountId = u32; type RuntimeCall = (); type BaseCallFilter = frame_support::traits::Everything; @@ -3500,7 +3500,7 @@ mod weight_tests { use sp_weights::RuntimeDbWeight; pub trait Config: 'static { - type Origin; + type RuntimeOrigin; type Balance; type BlockNumber; type DbWeight: Get; @@ -3517,7 +3517,7 @@ mod weight_tests { } impl Config for TraitImpl { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type Balance = u32; type DbWeight = DbWeight; @@ -3525,7 +3525,7 @@ mod weight_tests { } decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { // no arguments, fixed weight #[weight = 1000] fn f00(_origin) { unimplemented!(); } diff --git a/frame/support/src/error.rs b/frame/support/src/error.rs index 0ffe4334e2e30..337bd75895c2c 100644 --- a/frame/support/src/error.rs +++ b/frame/support/src/error.rs @@ -51,7 +51,7 @@ pub use sp_runtime::traits::{BadOrigin, LookupError}; /// // exported in the metadata. /// /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// type Error = MyError; /// /// #[weight = 0] diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 31b95de5f413d..57f29e592b242 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -845,7 +845,7 @@ pub mod tests { pub trait Config: 'static { type BlockNumber: Codec + EncodeLike + Default + TypeInfo; - type Origin; + type RuntimeOrigin; type PalletInfo: crate::traits::PalletInfo; type DbWeight: crate::traits::Get; } @@ -856,7 +856,7 @@ pub mod tests { use super::Config; decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } } @@ -888,7 +888,7 @@ pub mod tests { impl Config for Test { type BlockNumber = u32; - type Origin = u32; + type RuntimeOrigin = u32; type PalletInfo = PanicPalletInfo; type DbWeight = (); } diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index 4ffe32651a9cc..c95dcee9d7e5c 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -512,14 +512,14 @@ mod test_iterators { use codec::{Decode, Encode}; pub trait Config: 'static { - type Origin; + type RuntimeOrigin; type BlockNumber; type PalletInfo: crate::traits::PalletInfo; type DbWeight: crate::traits::Get; } crate::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } #[derive(PartialEq, Eq, Clone, Encode, Decode)] diff --git a/frame/support/src/storage/generator/map.rs b/frame/support/src/storage/generator/map.rs index d190145ea4c00..f6c8eaa270bb3 100644 --- a/frame/support/src/storage/generator/map.rs +++ b/frame/support/src/storage/generator/map.rs @@ -354,14 +354,14 @@ mod test_iterators { use codec::{Decode, Encode}; pub trait Config: 'static { - type Origin; + type RuntimeOrigin; type BlockNumber; type PalletInfo: crate::traits::PalletInfo; type DbWeight: crate::traits::Get; } crate::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } #[derive(PartialEq, Eq, Clone, Encode, Decode)] diff --git a/frame/support/src/storage/generator/mod.rs b/frame/support/src/storage/generator/mod.rs index ca893f44b3cb0..334e9b9e24e86 100644 --- a/frame/support/src/storage/generator/mod.rs +++ b/frame/support/src/storage/generator/mod.rs @@ -47,21 +47,21 @@ mod tests { struct Runtime; pub trait Config: 'static { - type Origin; + type RuntimeOrigin; type BlockNumber; type PalletInfo: crate::traits::PalletInfo; type DbWeight: crate::traits::Get; } impl Config for Runtime { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = crate::tests::PanicPalletInfo; type DbWeight = (); } decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } crate::decl_storage! { diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index f1d0f9a5f0801..79f3d72044e28 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -460,14 +460,14 @@ mod test_iterators { use codec::{Decode, Encode}; pub trait Config: 'static { - type Origin; + type RuntimeOrigin; type BlockNumber; type PalletInfo: crate::traits::PalletInfo; type DbWeight: crate::traits::Get; } crate::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } #[derive(PartialEq, Eq, Clone, Encode, Decode)] diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index afc819aa454e5..c0e7e32a5529e 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -229,14 +229,14 @@ impl< /// Implemented for pallet dispatchable type by `decl_module` and for runtime dispatchable by /// `construct_runtime`. pub trait UnfilteredDispatchable { - /// The origin type of the runtime, (i.e. `frame_system::Config::Origin`). - type Origin; + /// The origin type of the runtime, (i.e. `frame_system::Config::RuntimeOrigin`). + type RuntimeOrigin; /// Dispatch this call but do not check the filter in origin. - fn dispatch_bypass_filter(self, origin: Self::Origin) -> DispatchResultWithPostInfo; + fn dispatch_bypass_filter(self, origin: Self::RuntimeOrigin) -> DispatchResultWithPostInfo; } -/// Methods available on `frame_system::Config::Origin`. +/// Methods available on `frame_system::Config::RuntimeOrigin`. pub trait OriginTrait: Sized { /// Runtime call type, as in `frame_system::Config::Call` type Call; diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 39ebbb78321d6..0dbbbd9e2a553 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -132,7 +132,7 @@ pub mod v1 { use super::*; /// A type that can be used as a scheduler. - pub trait Anon { + pub trait Anon { /// An address which can be used for removing a scheduled task. type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo + MaxEncodedLen; @@ -143,7 +143,7 @@ pub mod v1 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: Call, ) -> Result; @@ -177,7 +177,7 @@ pub mod v1 { } /// A type that can be used as a scheduler. - pub trait Named { + pub trait Named { /// An address which can be used for removing a scheduled task. type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug + MaxEncodedLen; @@ -189,7 +189,7 @@ pub mod v1 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: Call, ) -> Result; @@ -215,9 +215,9 @@ pub mod v1 { fn next_dispatch_time(id: Vec) -> Result; } - impl Anon for T + impl Anon for T where - T: v2::Anon, + T: v2::Anon, { type Address = T::Address; @@ -225,7 +225,7 @@ pub mod v1 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: Call, ) -> Result { let c = MaybeHashed::::Value(call); @@ -248,9 +248,9 @@ pub mod v1 { } } - impl Named for T + impl Named for T where - T: v2::Named, + T: v2::Named, { type Address = T::Address; @@ -259,7 +259,7 @@ pub mod v1 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: Call, ) -> Result { let c = MaybeHashed::::Value(call); @@ -287,7 +287,7 @@ pub mod v2 { use super::*; /// A type that can be used as a scheduler. - pub trait Anon { + pub trait Anon { /// An address which can be used for removing a scheduled task. type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo + MaxEncodedLen; /// A means of expressing a call by the hash of its encoded data. @@ -300,7 +300,7 @@ pub mod v2 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: MaybeHashed, ) -> Result; @@ -334,7 +334,7 @@ pub mod v2 { } /// A type that can be used as a scheduler. - pub trait Named { + pub trait Named { /// An address which can be used for removing a scheduled task. type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug + MaxEncodedLen; /// A means of expressing a call by the hash of its encoded data. @@ -348,7 +348,7 @@ pub mod v2 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: MaybeHashed, ) -> Result; diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index 6e4d2363b2f7c..b46f6c48a6d99 100644 --- a/frame/support/test/compile_pass/src/lib.rs +++ b/frame/support/test/compile_pass/src/lib.rs @@ -65,7 +65,7 @@ impl frame_system::Config for Runtime { type BlockHashCount = ConstU64<2400>; type Version = Version; type AccountData = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type BlockNumber = BlockNumber; type AccountId = AccountId; type RuntimeEvent = RuntimeEvent; diff --git a/frame/support/test/src/lib.rs b/frame/support/test/src/lib.rs index dd3fbd1f3020d..0ceeed42ff982 100644 --- a/frame/support/test/src/lib.rs +++ b/frame/support/test/src/lib.rs @@ -25,7 +25,7 @@ /// The configuration trait pub trait Config: 'static { /// The runtime origin type. - type Origin: codec::Codec + codec::EncodeLike + Default + scale_info::TypeInfo; + type RuntimeOrigin: codec::Codec + codec::EncodeLike + Default + scale_info::TypeInfo; /// The block number type. type BlockNumber: codec::Codec + codec::EncodeLike + Default + scale_info::TypeInfo; /// The information about the pallet setup in the runtime. @@ -36,7 +36,7 @@ pub trait Config: 'static { frame_support::decl_module! { /// Some test module - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } /// A PalletInfo implementation which just panics. diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 4306314b4c005..b1ace12936241 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -49,7 +49,7 @@ mod module1 { frame_support::decl_module! { pub struct Module, I: Instance = DefaultInstance> for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -89,7 +89,7 @@ mod module2 { frame_support::decl_module! { pub struct Module for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -134,7 +134,7 @@ mod nested { frame_support::decl_module! { pub struct Module for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -180,7 +180,7 @@ pub mod module3 { frame_support::decl_module! { pub struct Module for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -247,7 +247,7 @@ fn test_pub() -> AccountId { impl system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Hash = H256; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type BlockNumber = BlockNumber; type AccountId = AccountId; type RuntimeEvent = RuntimeEvent; diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs index fd6b51db07672..2ca9676406579 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs @@ -12,7 +12,7 @@ impl test_pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs b/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs index 706d444f23590..5691549c20f34 100644 --- a/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs +++ b/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs @@ -8,7 +8,7 @@ mod pallet_old { } decl_module! { - pub struct Module for enum Call where origin: T::Origin {} + pub struct Module for enum Call where origin: T::RuntimeOrigin {} } } diff --git a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs index f73c611d29686..b7ccadb5e3e58 100644 --- a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs +++ b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs @@ -46,7 +46,7 @@ impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs index f90af88d23a9b..abe5c4cfeb343 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs @@ -21,7 +21,7 @@ impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs index 60d4b166c41fd..9a6ac5c6251fb 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs @@ -21,7 +21,7 @@ impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs index 5f7beed686339..4facf85e280c0 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs @@ -21,7 +21,7 @@ impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs index fb866c161ccb8..322fa2c297285 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs @@ -21,7 +21,7 @@ impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs index 26ca5d6eb4cb0..55cd5b545d6ba 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs @@ -21,7 +21,7 @@ impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr index c692cd61bae8b..b93a2a92911ea 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr @@ -46,39 +46,6 @@ help: if you import `Origin`, refer to it directly 58 - } | -error[E0412]: cannot find type `Origin` in module `pallet` - --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 - | -49 | / construct_runtime! { -50 | | pub enum Runtime where -51 | | Block = Block, -52 | | NodeBlock = Block, -... | -57 | | } -58 | | } - | |_^ not found in `pallet` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use crate::Origin; - | -1 | use frame_system::Origin; - | -help: if you import `Origin`, refer to it directly - | -49 - construct_runtime! { -50 - pub enum Runtime where -51 - Block = Block, -52 - NodeBlock = Block, -53 - UncheckedExtrinsic = UncheckedExtrinsic -54 - { -55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, -56 - Pallet: pallet::{Pallet, Origin}, -57 - } -58 - } - | - error[E0282]: type annotations needed --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 | diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs index 81c040c660451..0cf305a7dc055 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs @@ -21,7 +21,7 @@ impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs index cc7c1ff219d8b..0f662b96e2b13 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs @@ -1,5 +1,5 @@ frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { fn integrity_test() {} fn integrity_test() {} diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr index 880695d9b77e2..47ff1c8af8cd2 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr @@ -2,7 +2,7 @@ error: `integrity_test` can only be passed once as input. --> tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs:1:1 | 1 | / frame_support::decl_module! { -2 | | pub struct Module for enum Call where origin: T::Origin, system=self { +2 | | pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { 3 | | fn integrity_test() {} 4 | | 5 | | fn integrity_test() {} diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs index 18aaec12c5f39..ea0746b1c501c 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs @@ -1,5 +1,5 @@ frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { fn on_initialize() -> Weight { 0 } diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr index 369be77b8d249..bfefadee99403 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr @@ -2,7 +2,7 @@ error: `on_initialize` can only be passed once as input. --> $DIR/reserved_keyword_two_times_on_initialize.rs:1:1 | 1 | / frame_support::decl_module! { -2 | | pub struct Module for enum Call where origin: T::Origin, system=self { +2 | | pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { 3 | | fn on_initialize() -> Weight { 4 | | 0 ... | diff --git a/frame/support/test/tests/decl_storage.rs b/frame/support/test/tests/decl_storage.rs index 7ce43cd5d44d1..a4e420eb454b6 100644 --- a/frame/support/test/tests/decl_storage.rs +++ b/frame/support/test/tests/decl_storage.rs @@ -23,7 +23,7 @@ mod tests { use sp_io::TestExternalities; frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } pub trait Config: frame_support_test::Config { @@ -94,7 +94,7 @@ mod tests { struct TraitImpl {} impl frame_support_test::Config for TraitImpl { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); @@ -617,7 +617,7 @@ mod test2 { pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } type PairOf = (T, T); @@ -639,7 +639,7 @@ mod test2 { struct TraitImpl {} impl frame_support_test::Config for TraitImpl { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); @@ -695,7 +695,7 @@ mod test3 { pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage! { trait Store for Module as Test { @@ -708,7 +708,7 @@ mod test3 { struct TraitImpl {} impl frame_support_test::Config for TraitImpl { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); @@ -726,7 +726,7 @@ mod test_append_and_len { pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } #[derive(PartialEq, Eq, Clone, Encode, Decode, scale_info::TypeInfo)] @@ -753,7 +753,7 @@ mod test_append_and_len { struct Test {} impl frame_support_test::Config for Test { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); diff --git a/frame/support/test/tests/decl_storage_ui/config_duplicate.rs b/frame/support/test/tests/decl_storage_ui/config_duplicate.rs index db2cdbdc65492..af74823f64ca6 100644 --- a/frame/support/test/tests/decl_storage_ui/config_duplicate.rs +++ b/frame/support/test/tests/decl_storage_ui/config_duplicate.rs @@ -18,7 +18,7 @@ pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage!{ diff --git a/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs b/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs index b804bf8980383..8805effd9e725 100644 --- a/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs +++ b/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs @@ -18,7 +18,7 @@ pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage!{ diff --git a/frame/support/test/tests/decl_storage_ui/get_duplicate.rs b/frame/support/test/tests/decl_storage_ui/get_duplicate.rs index bc03ff6b4a4f9..5e05887110537 100644 --- a/frame/support/test/tests/decl_storage_ui/get_duplicate.rs +++ b/frame/support/test/tests/decl_storage_ui/get_duplicate.rs @@ -18,7 +18,7 @@ pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage!{ diff --git a/frame/support/test/tests/final_keys.rs b/frame/support/test/tests/final_keys.rs index c1723c6ad7a1b..a7ad88c801001 100644 --- a/frame/support/test/tests/final_keys.rs +++ b/frame/support/test/tests/final_keys.rs @@ -28,7 +28,7 @@ mod no_instance { pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage! { @@ -53,7 +53,7 @@ mod instance { frame_support::decl_module! { pub struct Module, I: Instance = DefaultInstance> - for enum Call where origin: T::Origin, system=frame_support_test {} + for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage! { diff --git a/frame/support/test/tests/genesisconfig.rs b/frame/support/test/tests/genesisconfig.rs index 367c7236d0158..f0094b3188ae1 100644 --- a/frame/support/test/tests/genesisconfig.rs +++ b/frame/support/test/tests/genesisconfig.rs @@ -18,7 +18,7 @@ pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage! { @@ -31,7 +31,7 @@ struct Test; impl frame_support_test::Config for Test { type BlockNumber = u32; - type Origin = (); + type RuntimeOrigin = (); type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); } diff --git a/frame/support/test/tests/instance.rs b/frame/support/test/tests/instance.rs index c9eebdaff6bc4..043959b67ee6e 100644 --- a/frame/support/test/tests/instance.rs +++ b/frame/support/test/tests/instance.rs @@ -51,14 +51,14 @@ mod module1 { ::BlockNumber: From, { type RuntimeEvent: From> + Into<::RuntimeEvent>; - type Origin: From>; + type RuntimeOrigin: From>; type SomeParameter: Get; type GenericType: Default + Clone + Codec + EncodeLike + TypeInfo; } frame_support::decl_module! { pub struct Module, I: Instance> for enum Call where - origin: ::Origin, + origin: ::RuntimeOrigin, system = system, T::BlockNumber: From { @@ -155,14 +155,14 @@ mod module2 { pub trait Config: system::Config { type Amount: Parameter + Default; type RuntimeEvent: From> + Into<::RuntimeEvent>; - type Origin: From>; + type RuntimeOrigin: From>; } impl, I: Instance> Currency for Module {} frame_support::decl_module! { pub struct Module, I: Instance=DefaultInstance> for enum Call where - origin: ::Origin, + origin: ::RuntimeOrigin, system = system { fn deposit_event() = default; @@ -228,41 +228,41 @@ mod module3 { } frame_support::decl_module! { - pub struct Module for enum Call where origin: ::Origin, system=system {} + pub struct Module for enum Call where origin: ::RuntimeOrigin, system=system {} } } impl module1::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type SomeParameter = ConstU32<100>; type GenericType = u32; } impl module1::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type SomeParameter = ConstU32<100>; type GenericType = u32; } impl module2::Config for Runtime { type Amount = u16; type RuntimeEvent = RuntimeEvent; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; } impl module2::Config for Runtime { type Amount = u32; type RuntimeEvent = RuntimeEvent; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; } impl module2::Config for Runtime { type Amount = u32; type RuntimeEvent = RuntimeEvent; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; } impl module2::Config for Runtime { type Amount = u64; type RuntimeEvent = RuntimeEvent; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; } impl module3::Config for Runtime { type Currency = Module2_2; @@ -277,7 +277,7 @@ pub type Index = u64; impl system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Hash = H256; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type BlockNumber = BlockNumber; type AccountId = AccountId; type RuntimeEvent = RuntimeEvent; diff --git a/frame/support/test/tests/issue2219.rs b/frame/support/test/tests/issue2219.rs index 0b24a6aa89828..5d24d54165c1f 100644 --- a/frame/support/test/tests/issue2219.rs +++ b/frame/support/test/tests/issue2219.rs @@ -86,7 +86,7 @@ mod module { pub trait Config: system::Config + TypeInfo {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=system {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=system {} } #[derive(Encode, Decode, Copy, Clone, Serialize, Deserialize)] @@ -160,7 +160,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -80,7 +80,7 @@ pub mod module { frame_support::decl_module! { pub struct Module for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -146,7 +146,7 @@ impl Contains for BaseCallFilter { impl system::Config for RuntimeOriginTest { type BaseCallFilter = BaseCallFilter; type Hash = H256; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type BlockNumber = BlockNumber; type AccountId = u32; type RuntimeEvent = RuntimeEvent; @@ -178,40 +178,40 @@ fn origin_default_filter() { let accepted_call = nested::module::Call::fail {}.into(); let rejected_call = module::Call::fail {}.into(); - assert_eq!(Origin::root().filter_call(&accepted_call), true); - assert_eq!(Origin::root().filter_call(&rejected_call), true); - assert_eq!(Origin::none().filter_call(&accepted_call), true); - assert_eq!(Origin::none().filter_call(&rejected_call), false); - assert_eq!(Origin::signed(0).filter_call(&accepted_call), true); - assert_eq!(Origin::signed(0).filter_call(&rejected_call), false); - assert_eq!(Origin::from(Some(0)).filter_call(&accepted_call), true); - assert_eq!(Origin::from(Some(0)).filter_call(&rejected_call), false); - assert_eq!(Origin::from(None).filter_call(&accepted_call), true); - assert_eq!(Origin::from(None).filter_call(&rejected_call), false); - assert_eq!(Origin::from(nested::module::Origin).filter_call(&accepted_call), true); - assert_eq!(Origin::from(nested::module::Origin).filter_call(&rejected_call), false); - - let mut origin = Origin::from(Some(0)); + assert_eq!(RuntimeOrigin::root().filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::root().filter_call(&rejected_call), true); + assert_eq!(RuntimeOrigin::none().filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::none().filter_call(&rejected_call), false); + assert_eq!(RuntimeOrigin::signed(0).filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::signed(0).filter_call(&rejected_call), false); + assert_eq!(RuntimeOrigin::from(Some(0)).filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::from(Some(0)).filter_call(&rejected_call), false); + assert_eq!(RuntimeOrigin::from(None).filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::from(None).filter_call(&rejected_call), false); + assert_eq!(RuntimeOrigin::from(nested::module::Origin).filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::from(nested::module::Origin).filter_call(&rejected_call), false); + + let mut origin = RuntimeOrigin::from(Some(0)); origin.add_filter(|c| matches!(c, RuntimeCall::Module(_))); assert_eq!(origin.filter_call(&accepted_call), false); assert_eq!(origin.filter_call(&rejected_call), false); // Now test for root origin and filters: - let mut origin = Origin::from(Some(0)); - origin.set_caller_from(Origin::root()); + let mut origin = RuntimeOrigin::from(Some(0)); + origin.set_caller_from(RuntimeOrigin::root()); assert!(matches!(origin.caller, OriginCaller::system(system::RawOrigin::Root))); // Root origin bypass all filter. assert_eq!(origin.filter_call(&accepted_call), true); assert_eq!(origin.filter_call(&rejected_call), true); - origin.set_caller_from(Origin::from(Some(0))); + origin.set_caller_from(RuntimeOrigin::from(Some(0))); // Back to another signed origin, the filtered are now effective again assert_eq!(origin.filter_call(&accepted_call), true); assert_eq!(origin.filter_call(&rejected_call), false); - origin.set_caller_from(Origin::root()); + origin.set_caller_from(RuntimeOrigin::root()); origin.reset_filter(); // Root origin bypass all filter, even when they are reset. diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 4304aa1533a8b..05c1f14601862 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -552,8 +552,10 @@ pub mod pallet2 { #[frame_support::pallet] pub mod pallet3 { #[pallet::config] - pub trait Config: frame_system::Config::Origin> { - type Origin; + pub trait Config: + frame_system::Config::RuntimeOrigin> + { + type RuntimeOrigin; } #[pallet::pallet] @@ -578,7 +580,7 @@ frame_support::parameter_types!( impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; @@ -618,7 +620,7 @@ impl pallet4::Config for Runtime {} #[cfg(feature = "frame-feature-testing")] impl pallet3::Config for Runtime { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; } pub type Header = sp_runtime::generic::Header; diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index 2342f25fb98b9..398137d644ee4 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -70,7 +70,7 @@ mod pallet_old { ); decl_module! { - pub struct Module for enum Call where origin: T::Origin { + pub struct Module for enum Call where origin: T::RuntimeOrigin { type Error = Error; fn deposit_event() = default; const SomeConst: T::Balance = T::SomeConst::get(); @@ -226,7 +226,7 @@ pub mod pallet { impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index b89ab410621e5..e8b5fe9fa33d4 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -56,7 +56,7 @@ mod pallet_old { decl_module! { pub struct Module, I: Instance = DefaultInstance> for enum Call - where origin: T::Origin + where origin: T::RuntimeOrigin { type Error = Error; fn deposit_event() = default; @@ -210,7 +210,7 @@ impl frame_system::Config for Runtime { type BlockLength = (); type DbWeight = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 3bbbc559ff9b8..7e05e2ecf783b 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -286,7 +286,7 @@ pub mod pallet2 { impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; diff --git a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs index 788e852ba58e9..0066420566fe8 100644 --- a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs +++ b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs @@ -43,7 +43,7 @@ frame_support::decl_error!( ); frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin { + pub struct Module for enum Call where origin: T::RuntimeOrigin { fn deposit_event() = default; type Error = Error; const Foo: u32 = u32::MAX; @@ -126,7 +126,7 @@ mod tests { impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = sp_core::H256; diff --git a/frame/support/test/tests/storage_layers.rs b/frame/support/test/tests/storage_layers.rs index a3e512302fe4f..6fbbb8ac67bd7 100644 --- a/frame/support/test/tests/storage_layers.rs +++ b/frame/support/test/tests/storage_layers.rs @@ -59,7 +59,7 @@ pub mod decl_pallet { pub trait Config: frame_system::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin { + pub struct Module for enum Call where origin: T::RuntimeOrigin { #[weight = 0] pub fn set_value(_origin, value: u32) { DeclValue::put(value); @@ -86,7 +86,7 @@ impl frame_system::Config for Runtime { type BlockLength = (); type DbWeight = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; @@ -256,11 +256,11 @@ fn storage_layer_in_pallet_call() { TestExternalities::default().execute_with(|| { use sp_runtime::traits::Dispatchable; let call1 = RuntimeCall::MyPallet(pallet::Call::set_value { value: 2 }); - assert_ok!(call1.dispatch(Origin::signed(0))); + assert_ok!(call1.dispatch(RuntimeOrigin::signed(0))); assert_eq!(Value::::get(), 2); let call2 = RuntimeCall::MyPallet(pallet::Call::set_value { value: 1 }); - assert_noop!(call2.dispatch(Origin::signed(0)), Error::::Revert); + assert_noop!(call2.dispatch(RuntimeOrigin::signed(0)), Error::::Revert); }); } @@ -271,12 +271,15 @@ fn storage_layer_in_decl_pallet_call() { use sp_runtime::traits::Dispatchable; let call1 = RuntimeCall::DeclPallet(decl_pallet::Call::set_value { value: 2 }); - assert_ok!(call1.dispatch(Origin::signed(0))); + assert_ok!(call1.dispatch(RuntimeOrigin::signed(0))); assert_eq!(decl_pallet::DeclValue::get(), 2); let call2 = RuntimeCall::DeclPallet(decl_pallet::Call::set_value { value: 1 }); - assert_noop!(call2.dispatch(Origin::signed(0)), "Revert!"); + assert_noop!(call2.dispatch(RuntimeOrigin::signed(0)), "Revert!"); // Calling the function directly also works with storage layers. - assert_noop!(decl_pallet::Module::::set_value(Origin::signed(1), 1), "Revert!"); + assert_noop!( + decl_pallet::Module::::set_value(RuntimeOrigin::signed(1), 1), + "Revert!" + ); }); } diff --git a/frame/support/test/tests/storage_transaction.rs b/frame/support/test/tests/storage_transaction.rs index 9e597969d6c89..6fedd75019e37 100644 --- a/frame/support/test/tests/storage_transaction.rs +++ b/frame/support/test/tests/storage_transaction.rs @@ -31,7 +31,7 @@ use sp_std::result; pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test { #[weight = 0] #[transactional] fn value_commits(_origin, v: u32) { @@ -57,7 +57,7 @@ frame_support::decl_storage! { struct Runtime; impl frame_support_test::Config for Runtime { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); diff --git a/frame/support/test/tests/system.rs b/frame/support/test/tests/system.rs index 9736c74dc236d..eff41242917a0 100644 --- a/frame/support/test/tests/system.rs +++ b/frame/support/test/tests/system.rs @@ -22,7 +22,7 @@ use frame_support::{ }; pub trait Config: 'static + Eq + Clone { - type Origin: Into, Self::Origin>> + type RuntimeOrigin: Into, Self::RuntimeOrigin>> + From>; type BaseCallFilter: frame_support::traits::Contains; @@ -36,7 +36,7 @@ pub trait Config: 'static + Eq + Clone { } frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { #[weight = 0] fn noop(_origin) {} } diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index 03d3a65812d56..0881b81eaca7d 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -76,7 +76,7 @@ impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = BlockLength; type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/system/benchmarking/src/mock.rs b/frame/system/benchmarking/src/mock.rs index 1c0a7efa03735..a7f28ca30fe87 100644 --- a/frame/system/benchmarking/src/mock.rs +++ b/frame/system/benchmarking/src/mock.rs @@ -43,7 +43,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; type RuntimeCall = RuntimeCall; diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index f60e3e7349d6b..36360f8fae2c2 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -215,8 +215,8 @@ pub mod pallet { #[pallet::constant] type BlockLength: Get; - /// The `Origin` type used by dispatchable calls. - type Origin: Into, Self::Origin>> + /// The `RuntimeOrigin` type used by dispatchable calls. + type RuntimeOrigin: Into, Self::RuntimeOrigin>> + From> + Clone + OriginTrait; @@ -1701,7 +1701,7 @@ pub mod pallet_prelude { pub use crate::{ensure_none, ensure_root, ensure_signed, ensure_signed_or_root}; /// Type alias for the `Origin` associated type of system config. - pub type OriginFor = ::Origin; + pub type OriginFor = ::RuntimeOrigin; /// Type alias for the `BlockNumber` associated type of system config. pub type BlockNumberFor = ::BlockNumber; diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index fdaaceaf8abe0..1c0511787eb76 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -93,7 +93,7 @@ impl Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index b6fdda8d9cbe2..92563f4ad1747 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -20,7 +20,7 @@ use frame_support::{ assert_noop, assert_ok, dispatch::{Pays, PostDispatchInfo, WithPostDispatchInfo}, }; -use mock::{Origin, *}; +use mock::{RuntimeOrigin, *}; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, Header}, @@ -29,8 +29,8 @@ use sp_runtime::{ #[test] fn origin_works() { - let o = Origin::from(RawOrigin::::Signed(1u64)); - let x: Result, Origin> = o.into(); + let o = RuntimeOrigin::from(RawOrigin::::Signed(1u64)); + let x: Result, RuntimeOrigin> = o.into(); assert_eq!(x.unwrap(), RawOrigin::::Signed(1u64)); } @@ -638,16 +638,16 @@ fn ensure_signed_stuff_works() { } } - let signed_origin = Origin::signed(0u64); + let signed_origin = RuntimeOrigin::signed(0u64); assert_ok!(EnsureSigned::try_origin(signed_origin.clone())); assert_ok!(EnsureSignedBy::::try_origin(signed_origin)); #[cfg(feature = "runtime-benchmarks")] { - let successful_origin: Origin = EnsureSigned::successful_origin(); + let successful_origin: RuntimeOrigin = EnsureSigned::successful_origin(); assert_ok!(EnsureSigned::try_origin(successful_origin)); - let successful_origin: Origin = EnsureSignedBy::::successful_origin(); + let successful_origin: RuntimeOrigin = EnsureSignedBy::::successful_origin(); assert_ok!(EnsureSignedBy::::try_origin(successful_origin)); } } diff --git a/frame/timestamp/src/mock.rs b/frame/timestamp/src/mock.rs index 7d3da0e8a0b83..2208510f24fe5 100644 --- a/frame/timestamp/src/mock.rs +++ b/frame/timestamp/src/mock.rs @@ -55,7 +55,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/timestamp/src/tests.rs b/frame/timestamp/src/tests.rs index ef9fd6e39d4b5..6a76fbc4820e6 100644 --- a/frame/timestamp/src/tests.rs +++ b/frame/timestamp/src/tests.rs @@ -24,7 +24,7 @@ use frame_support::assert_ok; fn timestamp_works() { new_test_ext().execute_with(|| { crate::Now::::put(46); - assert_ok!(Timestamp::set(Origin::none(), 69)); + assert_ok!(Timestamp::set(RuntimeOrigin::none(), 69)); assert_eq!(Timestamp::now(), 69); assert_eq!(Some(69), get_captured_moment()); }); @@ -35,7 +35,7 @@ fn timestamp_works() { fn double_timestamp_should_fail() { new_test_ext().execute_with(|| { Timestamp::set_timestamp(42); - assert_ok!(Timestamp::set(Origin::none(), 69)); + assert_ok!(Timestamp::set(RuntimeOrigin::none(), 69)); }); } @@ -46,6 +46,6 @@ fn double_timestamp_should_fail() { fn block_period_minimum_enforced() { new_test_ext().execute_with(|| { crate::Now::::put(44); - let _ = Timestamp::set(Origin::none(), 46); + let _ = Timestamp::set(RuntimeOrigin::none(), 46); }); } diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 4956e2a095688..312424e5799ec 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -197,7 +197,7 @@ benchmarks_instance_pallet! { let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary)); ensure!(Tips::::contains_key(hash), "tip does not exist"); let reject_origin = T::RejectOrigin::successful_origin(); - }: _(reject_origin, hash) + }: _(reject_origin, hash) impl_benchmark_test_suite!(TipsMod, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index 9b721bd77a8bc..cb0b4458c7fba 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -65,7 +65,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -230,9 +230,9 @@ fn tip_hash() -> H256 { fn tip_new_cannot_be_used_twice() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10)); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 10)); assert_noop!( - Tips::tip_new(Origin::signed(11), b"awesome.dot".to_vec(), 3, 10), + Tips::tip_new(RuntimeOrigin::signed(11), b"awesome.dot".to_vec(), 3, 10), Error::::AlreadyKnown ); }); @@ -242,23 +242,23 @@ fn tip_new_cannot_be_used_twice() { fn report_awesome_and_tip_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + assert_ok!(Tips::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 3)); assert_eq!(Balances::reserved_balance(0), 12); assert_eq!(Balances::free_balance(0), 88); // other reports don't count. assert_noop!( - Tips::report_awesome(Origin::signed(1), b"awesome.dot".to_vec(), 3), + Tips::report_awesome(RuntimeOrigin::signed(1), b"awesome.dot".to_vec(), 3), Error::::AlreadyKnown ); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(10), h, 10)); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips::tip(Origin::signed(12), h, 10)); - assert_noop!(Tips::tip(Origin::signed(9), h, 10), BadOrigin); + assert_ok!(Tips::tip(RuntimeOrigin::signed(10), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10)); + assert_noop!(Tips::tip(RuntimeOrigin::signed(9), h, 10), BadOrigin); System::set_block_number(2); - assert_ok!(Tips::close_tip(Origin::signed(100), h.into())); + assert_ok!(Tips::close_tip(RuntimeOrigin::signed(100), h.into())); assert_eq!(Balances::reserved_balance(0), 0); assert_eq!(Balances::free_balance(0), 102); assert_eq!(Balances::free_balance(3), 8); @@ -269,15 +269,15 @@ fn report_awesome_and_tip_works() { fn report_awesome_from_beneficiary_and_tip_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 0)); + assert_ok!(Tips::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 0)); assert_eq!(Balances::reserved_balance(0), 12); assert_eq!(Balances::free_balance(0), 88); let h = BlakeTwo256::hash_of(&(BlakeTwo256::hash(b"awesome.dot"), 0u128)); - assert_ok!(Tips::tip(Origin::signed(10), h, 10)); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips::tip(Origin::signed(12), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(10), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10)); System::set_block_number(2); - assert_ok!(Tips::close_tip(Origin::signed(100), h.into())); + assert_ok!(Tips::close_tip(RuntimeOrigin::signed(100), h.into())); assert_eq!(Balances::reserved_balance(0), 0); assert_eq!(Balances::free_balance(0), 110); }); @@ -291,30 +291,33 @@ fn close_tip_works() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10)); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 10)); let h = tip_hash(); assert_eq!(last_event(), TipEvent::NewTip { tip_hash: h }); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); - assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::::StillOpen); + assert_noop!(Tips::close_tip(RuntimeOrigin::signed(0), h.into()), Error::::StillOpen); - assert_ok!(Tips::tip(Origin::signed(12), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10)); assert_eq!(last_event(), TipEvent::TipClosing { tip_hash: h }); - assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::::Premature); + assert_noop!(Tips::close_tip(RuntimeOrigin::signed(0), h.into()), Error::::Premature); System::set_block_number(2); - assert_noop!(Tips::close_tip(Origin::none(), h.into()), BadOrigin); - assert_ok!(Tips::close_tip(Origin::signed(0), h.into())); + assert_noop!(Tips::close_tip(RuntimeOrigin::none(), h.into()), BadOrigin); + assert_ok!(Tips::close_tip(RuntimeOrigin::signed(0), h.into())); assert_eq!(Balances::free_balance(3), 10); assert_eq!(last_event(), TipEvent::TipClosed { tip_hash: h, who: 3, payout: 10 }); - assert_noop!(Tips::close_tip(Origin::signed(100), h.into()), Error::::UnknownTip); + assert_noop!( + Tips::close_tip(RuntimeOrigin::signed(100), h.into()), + Error::::UnknownTip + ); }); } @@ -328,7 +331,7 @@ fn slash_tip_works() { assert_eq!(Balances::reserved_balance(0), 0); assert_eq!(Balances::free_balance(0), 100); - assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + assert_ok!(Tips::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 3)); assert_eq!(Balances::reserved_balance(0), 12); assert_eq!(Balances::free_balance(0), 88); @@ -337,10 +340,10 @@ fn slash_tip_works() { assert_eq!(last_event(), TipEvent::NewTip { tip_hash: h }); // can't remove from any origin - assert_noop!(Tips::slash_tip(Origin::signed(0), h), BadOrigin); + assert_noop!(Tips::slash_tip(RuntimeOrigin::signed(0), h), BadOrigin); // can remove from root. - assert_ok!(Tips::slash_tip(Origin::root(), h)); + assert_ok!(Tips::slash_tip(RuntimeOrigin::root(), h)); assert_eq!(last_event(), TipEvent::TipSlashed { tip_hash: h, finder: 0, deposit: 12 }); // tipper slashed @@ -354,26 +357,32 @@ fn retract_tip_works() { new_test_ext().execute_with(|| { // with report awesome Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + assert_ok!(Tips::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 3)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(10), h, 10)); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips::tip(Origin::signed(12), h, 10)); - assert_noop!(Tips::retract_tip(Origin::signed(10), h), Error::::NotFinder); - assert_ok!(Tips::retract_tip(Origin::signed(0), h)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(10), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10)); + assert_noop!(Tips::retract_tip(RuntimeOrigin::signed(10), h), Error::::NotFinder); + assert_ok!(Tips::retract_tip(RuntimeOrigin::signed(0), h)); System::set_block_number(2); - assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::::UnknownTip); + assert_noop!( + Tips::close_tip(RuntimeOrigin::signed(0), h.into()), + Error::::UnknownTip + ); // with tip new Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10)); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 10)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips::tip(Origin::signed(12), h, 10)); - assert_noop!(Tips::retract_tip(Origin::signed(0), h), Error::::NotFinder); - assert_ok!(Tips::retract_tip(Origin::signed(10), h)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10)); + assert_noop!(Tips::retract_tip(RuntimeOrigin::signed(0), h), Error::::NotFinder); + assert_ok!(Tips::retract_tip(RuntimeOrigin::signed(10), h)); System::set_block_number(2); - assert_noop!(Tips::close_tip(Origin::signed(10), h.into()), Error::::UnknownTip); + assert_noop!( + Tips::close_tip(RuntimeOrigin::signed(10), h.into()), + Error::::UnknownTip + ); }); } @@ -381,12 +390,12 @@ fn retract_tip_works() { fn tip_median_calculation_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 0)); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 0)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips::tip(Origin::signed(12), h, 1000000)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 1000000)); System::set_block_number(2); - assert_ok!(Tips::close_tip(Origin::signed(0), h.into())); + assert_ok!(Tips::close_tip(RuntimeOrigin::signed(0), h.into())); assert_eq!(Balances::free_balance(3), 10); }); } @@ -395,17 +404,17 @@ fn tip_median_calculation_works() { fn tip_changing_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10000)); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 10000)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(11), h, 10000)); - assert_ok!(Tips::tip(Origin::signed(12), h, 10000)); - assert_ok!(Tips::tip(Origin::signed(13), h, 0)); - assert_ok!(Tips::tip(Origin::signed(14), h, 0)); - assert_ok!(Tips::tip(Origin::signed(12), h, 1000)); - assert_ok!(Tips::tip(Origin::signed(11), h, 100)); - assert_ok!(Tips::tip(Origin::signed(10), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10000)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10000)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(13), h, 0)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(14), h, 0)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 1000)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 100)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(10), h, 10)); System::set_block_number(2); - assert_ok!(Tips::close_tip(Origin::signed(0), h.into())); + assert_ok!(Tips::close_tip(RuntimeOrigin::signed(0), h.into())); assert_eq!(Balances::free_balance(3), 10); }); } @@ -582,24 +591,24 @@ fn report_awesome_and_tip_works_second_instance() { assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); assert_eq!(Balances::free_balance(&Treasury1::account_id()), 201); - assert_ok!(Tips1::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + assert_ok!(Tips1::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 3)); // duplicate report in tips1 reports don't count. assert_noop!( - Tips1::report_awesome(Origin::signed(1), b"awesome.dot".to_vec(), 3), + Tips1::report_awesome(RuntimeOrigin::signed(1), b"awesome.dot".to_vec(), 3), Error::::AlreadyKnown ); // but tips is separate - assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + assert_ok!(Tips::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 3)); let h = tip_hash(); - assert_ok!(Tips1::tip(Origin::signed(10), h, 10)); - assert_ok!(Tips1::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips1::tip(Origin::signed(12), h, 10)); - assert_noop!(Tips1::tip(Origin::signed(9), h, 10), BadOrigin); + assert_ok!(Tips1::tip(RuntimeOrigin::signed(10), h, 10)); + assert_ok!(Tips1::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips1::tip(RuntimeOrigin::signed(12), h, 10)); + assert_noop!(Tips1::tip(RuntimeOrigin::signed(9), h, 10), BadOrigin); System::set_block_number(2); - assert_ok!(Tips1::close_tip(Origin::signed(100), h.into())); + assert_ok!(Tips1::close_tip(RuntimeOrigin::signed(100), h.into())); // Treasury 1 unchanged assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); // Treasury 2 gave the funds diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index 1f6113aabdddd..cdf7d17898145 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -87,7 +87,7 @@ impl frame_system::Config for Runtime { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -338,7 +338,7 @@ fn transaction_payment_in_asset_possible() { let asset_id = 1; let min_balance = 2; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -391,7 +391,7 @@ fn transaction_payment_without_fee() { let asset_id = 1; let min_balance = 2; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -444,7 +444,7 @@ fn asset_transaction_payment_with_tip_and_refund() { let asset_id = 1; let min_balance = 2; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -496,7 +496,7 @@ fn payment_from_account_with_only_assets() { let asset_id = 1; let min_balance = 2; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -555,7 +555,7 @@ fn payment_only_with_existing_sufficient_asset() { // create the non-sufficient asset let min_balance = 2; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ false, /* is_sufficient */ @@ -580,7 +580,7 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { let asset_id = 1; let min_balance = 1; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -645,7 +645,7 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { let asset_id = 1; let min_balance = 100; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -702,7 +702,7 @@ fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { let asset_id = 1; let min_balance = 100; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 0447ea6bfd99d..1ad6a2b3b3b6f 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -906,7 +906,7 @@ mod tests { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index e623079ac863b..07144c5617113 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -95,7 +95,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// A dispatchable call. type RuntimeCall: Parameter - + Dispatchable + + Dispatchable + GetDispatchInfo + From>; /// The currency trait. diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs index 1cb725e63e83b..8764b16c31d8d 100644 --- a/frame/transaction-storage/src/mock.rs +++ b/frame/transaction-storage/src/mock.rs @@ -51,7 +51,7 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; @@ -116,7 +116,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pub fn run_to_block(n: u64, f: impl Fn() -> Option) { while System::block_number() < n { if let Some(proof) = f() { - TransactionStorage::check_proof(Origin::none(), proof).unwrap(); + TransactionStorage::check_proof(RuntimeOrigin::none(), proof).unwrap(); } TransactionStorage::on_finalize(System::block_number()); System::on_finalize(System::block_number()); diff --git a/frame/transaction-storage/src/tests.rs b/frame/transaction-storage/src/tests.rs index 4f5ce1c4b654d..01b71a7851ac3 100644 --- a/frame/transaction-storage/src/tests.rs +++ b/frame/transaction-storage/src/tests.rs @@ -95,7 +95,7 @@ fn checks_proof() { let proof = build_proof(parent_hash.as_ref(), vec![vec![0u8; MAX_DATA_SIZE as usize]]).unwrap(); assert_noop!( - TransactionStorage::::check_proof(Origin::none(), proof,), + TransactionStorage::::check_proof(RuntimeOrigin::none(), proof,), Error::::UnexpectedProof, ); run_to_block(11, || None); @@ -103,13 +103,13 @@ fn checks_proof() { let invalid_proof = build_proof(parent_hash.as_ref(), vec![vec![0u8; 1000]]).unwrap(); assert_noop!( - TransactionStorage::::check_proof(Origin::none(), invalid_proof,), + TransactionStorage::::check_proof(RuntimeOrigin::none(), invalid_proof,), Error::::InvalidProof, ); let proof = build_proof(parent_hash.as_ref(), vec![vec![0u8; MAX_DATA_SIZE as usize]]).unwrap(); - assert_ok!(TransactionStorage::::check_proof(Origin::none(), proof)); + assert_ok!(TransactionStorage::::check_proof(RuntimeOrigin::none(), proof)); }); } diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index b3787e2063c45..d718a5fb89521 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -100,7 +100,7 @@ benchmarks_instance_pallet! { )?; let proposal_id = Treasury::::proposal_count() - 1; let reject_origin = T::RejectOrigin::successful_origin(); - }: _(reject_origin, proposal_id) + }: _(reject_origin, proposal_id) approve_proposal { let p in 0 .. T::MaxApprovals::get() - 1; @@ -113,7 +113,7 @@ benchmarks_instance_pallet! { )?; let proposal_id = Treasury::::proposal_count() - 1; let approve_origin = T::ApproveOrigin::successful_origin(); - }: _(approve_origin, proposal_id) + }: _(approve_origin, proposal_id) remove_approval { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); @@ -125,7 +125,7 @@ benchmarks_instance_pallet! { let proposal_id = Treasury::::proposal_count() - 1; Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; let reject_origin = T::RejectOrigin::successful_origin(); - }: _(reject_origin, proposal_id) + }: _(reject_origin, proposal_id) on_initialize_proposals { let p in 0 .. T::MaxApprovals::get(); diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index bebbcda2effb6..21b4d2b769c8b 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -149,10 +149,10 @@ pub mod pallet { type Currency: Currency + ReservableCurrency; /// Origin from which approvals must come. - type ApproveOrigin: EnsureOrigin; + type ApproveOrigin: EnsureOrigin; /// Origin from which rejections must come. - type RejectOrigin: EnsureOrigin; + type RejectOrigin: EnsureOrigin; /// The overarching event type. type RuntimeEvent: From> @@ -204,7 +204,7 @@ pub mod pallet { /// The origin required for approving spends from the treasury outside of the proposal /// process. The `Success` value is the maximum amount that this origin is allowed to /// spend at a time. - type SpendOrigin: EnsureOrigin>; + type SpendOrigin: EnsureOrigin>; } /// Number of proposals that have been made. diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index af77b419d67d2..9cfe147ec4ce4 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -60,7 +60,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type RuntimeCall = RuntimeCall; @@ -98,21 +98,21 @@ parameter_types! { pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); } pub struct TestSpendOrigin; -impl frame_support::traits::EnsureOrigin for TestSpendOrigin { +impl frame_support::traits::EnsureOrigin for TestSpendOrigin { type Success = u64; - fn try_origin(o: Origin) -> Result { - Result::, Origin>::from(o).and_then(|o| match o { + fn try_origin(o: RuntimeOrigin) -> Result { + Result::, RuntimeOrigin>::from(o).and_then(|o| match o { frame_system::RawOrigin::Root => Ok(u64::max_value()), frame_system::RawOrigin::Signed(10) => Ok(5), frame_system::RawOrigin::Signed(11) => Ok(10), frame_system::RawOrigin::Signed(12) => Ok(20), frame_system::RawOrigin::Signed(13) => Ok(50), - r => Err(Origin::from(r)), + r => Err(RuntimeOrigin::from(r)), }) } #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - Ok(Origin::root()) + fn try_successful_origin() -> Result { + Ok(RuntimeOrigin::root()) } } @@ -158,21 +158,21 @@ fn genesis_config_works() { #[test] fn spend_origin_permissioning_works() { new_test_ext().execute_with(|| { - assert_noop!(Treasury::spend(Origin::signed(1), 1, 1), BadOrigin); + assert_noop!(Treasury::spend(RuntimeOrigin::signed(1), 1, 1), BadOrigin); assert_noop!( - Treasury::spend(Origin::signed(10), 6, 1), + Treasury::spend(RuntimeOrigin::signed(10), 6, 1), Error::::InsufficientPermission ); assert_noop!( - Treasury::spend(Origin::signed(11), 11, 1), + Treasury::spend(RuntimeOrigin::signed(11), 11, 1), Error::::InsufficientPermission ); assert_noop!( - Treasury::spend(Origin::signed(12), 21, 1), + Treasury::spend(RuntimeOrigin::signed(12), 21, 1), Error::::InsufficientPermission ); assert_noop!( - Treasury::spend(Origin::signed(13), 51, 1), + Treasury::spend(RuntimeOrigin::signed(13), 51, 1), Error::::InsufficientPermission ); }); @@ -183,13 +183,13 @@ fn spend_origin_works() { new_test_ext().execute_with(|| { // Check that accumulate works when we have Some value in Dummy already. Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(Origin::signed(11), 10, 6)); - assert_ok!(Treasury::spend(Origin::signed(12), 20, 6)); - assert_ok!(Treasury::spend(Origin::signed(13), 50, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(11), 10, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(12), 20, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(13), 50, 6)); >::on_initialize(1); assert_eq!(Balances::free_balance(6), 0); @@ -212,7 +212,7 @@ fn minting_works() { #[test] fn spend_proposal_takes_min_deposit() { new_test_ext().execute_with(|| { - assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3)); assert_eq!(Balances::free_balance(0), 99); assert_eq!(Balances::reserved_balance(0), 1); }); @@ -221,7 +221,7 @@ fn spend_proposal_takes_min_deposit() { #[test] fn spend_proposal_takes_proportional_deposit() { new_test_ext().execute_with(|| { - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); assert_eq!(Balances::free_balance(0), 95); assert_eq!(Balances::reserved_balance(0), 5); }); @@ -231,7 +231,7 @@ fn spend_proposal_takes_proportional_deposit() { fn spend_proposal_fails_when_proposer_poor() { new_test_ext().execute_with(|| { assert_noop!( - Treasury::propose_spend(Origin::signed(2), 100, 3), + Treasury::propose_spend(RuntimeOrigin::signed(2), 100, 3), Error::::InsufficientProposersBalance, ); }); @@ -242,8 +242,8 @@ fn accepted_spend_proposal_ignored_outside_spend_period() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(1); assert_eq!(Balances::free_balance(3), 0); @@ -269,8 +269,8 @@ fn rejected_spend_proposal_ignored_on_spend_period() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Balances::free_balance(3), 0); @@ -283,23 +283,32 @@ fn reject_already_rejected_spend_proposal_fails() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); - assert_noop!(Treasury::reject_proposal(Origin::root(), 0), Error::::InvalidIndex); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); + assert_noop!( + Treasury::reject_proposal(RuntimeOrigin::root(), 0), + Error::::InvalidIndex + ); }); } #[test] fn reject_non_existent_spend_proposal_fails() { new_test_ext().execute_with(|| { - assert_noop!(Treasury::reject_proposal(Origin::root(), 0), Error::::InvalidIndex); + assert_noop!( + Treasury::reject_proposal(RuntimeOrigin::root(), 0), + Error::::InvalidIndex + ); }); } #[test] fn accept_non_existent_spend_proposal_fails() { new_test_ext().execute_with(|| { - assert_noop!(Treasury::approve_proposal(Origin::root(), 0), Error::::InvalidIndex); + assert_noop!( + Treasury::approve_proposal(RuntimeOrigin::root(), 0), + Error::::InvalidIndex + ); }); } @@ -308,9 +317,12 @@ fn accept_already_rejected_spend_proposal_fails() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); - assert_noop!(Treasury::approve_proposal(Origin::root(), 0), Error::::InvalidIndex); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); + assert_noop!( + Treasury::approve_proposal(RuntimeOrigin::root(), 0), + Error::::InvalidIndex + ); }); } @@ -320,8 +332,8 @@ fn accepted_spend_proposal_enacted_on_spend_period() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Balances::free_balance(3), 100); @@ -335,8 +347,8 @@ fn pot_underflow_should_not_diminish() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 150, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 150, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed @@ -357,14 +369,14 @@ fn treasury_account_doesnt_get_deleted() { assert_eq!(Treasury::pot(), 100); let treasury_balance = Balances::free_balance(&Treasury::account_id()); - assert_ok!(Treasury::propose_spend(Origin::signed(0), treasury_balance, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), treasury_balance, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed - assert_ok!(Treasury::propose_spend(Origin::signed(0), Treasury::pot(), 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 1)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), Treasury::pot(), 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 1)); >::on_initialize(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied @@ -387,10 +399,10 @@ fn inexistent_account_works() { assert_eq!(Balances::free_balance(Treasury::account_id()), 0); // Account does not exist assert_eq!(Treasury::pot(), 0); // Pot is empty - assert_ok!(Treasury::propose_spend(Origin::signed(0), 99, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 1)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 99, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 1)); >::on_initialize(2); assert_eq!(Treasury::pot(), 0); // Pot hasn't changed assert_eq!(Balances::free_balance(3), 0); // Balance of `3` hasn't changed @@ -432,14 +444,14 @@ fn max_approvals_limited() { Balances::make_free_balance_be(&0, u64::MAX); for _ in 0..::MaxApprovals::get() { - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); } // One too many will fail - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); assert_noop!( - Treasury::approve_proposal(Origin::root(), 0), + Treasury::approve_proposal(RuntimeOrigin::root(), 0), Error::::TooManyApprovals ); }); @@ -450,14 +462,14 @@ fn remove_already_removed_approval_fails() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); assert_eq!(Treasury::approvals(), vec![0]); - assert_ok!(Treasury::remove_approval(Origin::root(), 0)); + assert_ok!(Treasury::remove_approval(RuntimeOrigin::root(), 0)); assert_eq!(Treasury::approvals(), vec![]); assert_noop!( - Treasury::remove_approval(Origin::root(), 0), + Treasury::remove_approval(RuntimeOrigin::root(), 0), Error::::ProposalNotApproved ); }); diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index b02a10270dd7d..d519eedd2787f 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -105,12 +105,12 @@ pub mod pallet { /// The origin which may forcibly create or destroy an item or otherwise alter privileged /// attributes. - type ForceOrigin: EnsureOrigin; + type ForceOrigin: EnsureOrigin; /// Standard collection creation is only allowed if the origin attempting it and the /// collection are in this set. type CreateOrigin: EnsureOriginWithArg< - Self::Origin, + Self::RuntimeOrigin, Self::CollectionId, Success = Self::AccountId, >; diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index 6808c48007a92..d6ed5cc5cc23e 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -49,7 +49,7 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 5ac677758316a..7af54ddbb188c 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -92,14 +92,14 @@ fn basic_setup_works() { #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); assert_eq!(collections(), vec![(1, 0)]); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); assert_eq!(items(), vec![(1, 0, 42)]); - assert_ok!(Uniques::force_create(Origin::root(), 1, 2, true)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 1, 2, true)); assert_eq!(collections(), vec![(1, 0), (2, 1)]); - assert_ok!(Uniques::mint(Origin::signed(2), 1, 69, 1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(2), 1, 69, 1)); assert_eq!(items(), vec![(1, 0, 42), (1, 1, 69)]); }); } @@ -108,32 +108,37 @@ fn basic_minting_should_work() { fn lifecycle_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); + assert_ok!(Uniques::create(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::reserved_balance(&1), 2); assert_eq!(collections(), vec![(1, 0)]); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0, 0], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0, 0], + false + )); assert_eq!(Balances::reserved_balance(&1), 5); assert!(CollectionMetadataOf::::contains_key(0)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 10)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 10)); assert_eq!(Balances::reserved_balance(&1), 6); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 69, 20)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 69, 20)); assert_eq!(Balances::reserved_balance(&1), 7); assert_eq!(items(), vec![(10, 0, 42), (20, 0, 69)]); assert_eq!(Collection::::get(0).unwrap().items, 2); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![42, 42], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![42, 42], false)); assert_eq!(Balances::reserved_balance(&1), 10); assert!(ItemMetadataOf::::contains_key(0, 42)); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![69, 69], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 69, bvec![69, 69], false)); assert_eq!(Balances::reserved_balance(&1), 13); assert!(ItemMetadataOf::::contains_key(0, 69)); let w = Collection::::get(0).unwrap().destroy_witness(); assert_eq!(w.items, 2); assert_eq!(w.item_metadatas, 2); - assert_ok!(Uniques::destroy(Origin::signed(1), 0, w)); + assert_ok!(Uniques::destroy(RuntimeOrigin::signed(1), 0, w)); assert_eq!(Balances::reserved_balance(&1), 0); assert!(!Collection::::contains_key(0)); @@ -151,19 +156,19 @@ fn lifecycle_should_work() { fn destroy_with_bad_witness_should_not_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); + assert_ok!(Uniques::create(RuntimeOrigin::signed(1), 0, 1)); let w = Collection::::get(0).unwrap().destroy_witness(); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); - assert_noop!(Uniques::destroy(Origin::signed(1), 0, w), Error::::BadWitness); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); + assert_noop!(Uniques::destroy(RuntimeOrigin::signed(1), 0, w), Error::::BadWitness); }); } #[test] fn mint_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); assert_eq!(Uniques::owner(0, 42).unwrap(), 1); assert_eq!(collections(), vec![(1, 0)]); assert_eq!(items(), vec![(1, 0, 42)]); @@ -173,54 +178,66 @@ fn mint_should_work() { #[test] fn transfer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 3)); assert_eq!(items(), vec![(3, 0, 42)]); - assert_noop!(Uniques::transfer(Origin::signed(2), 0, 42, 4), Error::::NoPermission); + assert_noop!( + Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 4), + Error::::NoPermission + ); - assert_ok!(Uniques::approve_transfer(Origin::signed(3), 0, 42, 2)); - assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 4)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(3), 0, 42, 2)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 4)); }); } #[test] fn freezing_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); - assert_ok!(Uniques::freeze(Origin::signed(1), 0, 42)); - assert_noop!(Uniques::transfer(Origin::signed(1), 0, 42, 2), Error::::Frozen); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::freeze(RuntimeOrigin::signed(1), 0, 42)); + assert_noop!(Uniques::transfer(RuntimeOrigin::signed(1), 0, 42, 2), Error::::Frozen); - assert_ok!(Uniques::thaw(Origin::signed(1), 0, 42)); - assert_ok!(Uniques::freeze_collection(Origin::signed(1), 0)); - assert_noop!(Uniques::transfer(Origin::signed(1), 0, 42, 2), Error::::Frozen); + assert_ok!(Uniques::thaw(RuntimeOrigin::signed(1), 0, 42)); + assert_ok!(Uniques::freeze_collection(RuntimeOrigin::signed(1), 0)); + assert_noop!(Uniques::transfer(RuntimeOrigin::signed(1), 0, 42, 2), Error::::Frozen); - assert_ok!(Uniques::thaw_collection(Origin::signed(1), 0)); - assert_ok!(Uniques::transfer(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::thaw_collection(RuntimeOrigin::signed(1), 0)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(1), 0, 42, 2)); }); } #[test] fn origin_guards_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); Balances::make_free_balance_be(&2, 100); - assert_ok!(Uniques::set_accept_ownership(Origin::signed(2), Some(0))); + assert_ok!(Uniques::set_accept_ownership(RuntimeOrigin::signed(2), Some(0))); + assert_noop!( + Uniques::transfer_ownership(RuntimeOrigin::signed(2), 0, 2), + Error::::NoPermission + ); + assert_noop!( + Uniques::set_team(RuntimeOrigin::signed(2), 0, 2, 2, 2), + Error::::NoPermission + ); + assert_noop!(Uniques::freeze(RuntimeOrigin::signed(2), 0, 42), Error::::NoPermission); + assert_noop!(Uniques::thaw(RuntimeOrigin::signed(2), 0, 42), Error::::NoPermission); + assert_noop!( + Uniques::mint(RuntimeOrigin::signed(2), 0, 69, 2), + Error::::NoPermission + ); assert_noop!( - Uniques::transfer_ownership(Origin::signed(2), 0, 2), + Uniques::burn(RuntimeOrigin::signed(2), 0, 42, None), Error::::NoPermission ); - assert_noop!(Uniques::set_team(Origin::signed(2), 0, 2, 2, 2), Error::::NoPermission); - assert_noop!(Uniques::freeze(Origin::signed(2), 0, 42), Error::::NoPermission); - assert_noop!(Uniques::thaw(Origin::signed(2), 0, 42), Error::::NoPermission); - assert_noop!(Uniques::mint(Origin::signed(2), 0, 69, 2), Error::::NoPermission); - assert_noop!(Uniques::burn(Origin::signed(2), 0, 42, None), Error::::NoPermission); let w = Collection::::get(0).unwrap().destroy_witness(); - assert_noop!(Uniques::destroy(Origin::signed(2), 0, w), Error::::NoPermission); + assert_noop!(Uniques::destroy(RuntimeOrigin::signed(2), 0, w), Error::::NoPermission); }); } @@ -230,14 +247,14 @@ fn transfer_owner_should_work() { Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); Balances::make_free_balance_be(&3, 100); - assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); + assert_ok!(Uniques::create(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(collections(), vec![(1, 0)]); assert_noop!( - Uniques::transfer_ownership(Origin::signed(1), 0, 2), + Uniques::transfer_ownership(RuntimeOrigin::signed(1), 0, 2), Error::::Unaccepted ); - assert_ok!(Uniques::set_accept_ownership(Origin::signed(2), Some(0))); - assert_ok!(Uniques::transfer_ownership(Origin::signed(1), 0, 2)); + assert_ok!(Uniques::set_accept_ownership(RuntimeOrigin::signed(2), Some(0))); + assert_ok!(Uniques::transfer_ownership(RuntimeOrigin::signed(1), 0, 2)); assert_eq!(collections(), vec![(2, 0)]); assert_eq!(Balances::total_balance(&1), 98); @@ -245,18 +262,23 @@ fn transfer_owner_should_work() { assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Balances::reserved_balance(&2), 2); - assert_ok!(Uniques::set_accept_ownership(Origin::signed(1), Some(0))); + assert_ok!(Uniques::set_accept_ownership(RuntimeOrigin::signed(1), Some(0))); assert_noop!( - Uniques::transfer_ownership(Origin::signed(1), 0, 1), + Uniques::transfer_ownership(RuntimeOrigin::signed(1), 0, 1), Error::::NoPermission ); // Mint and set metadata now and make sure that deposit gets transferred back. - assert_ok!(Uniques::set_collection_metadata(Origin::signed(2), 0, bvec![0u8; 20], false)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); - assert_ok!(Uniques::set_metadata(Origin::signed(2), 0, 42, bvec![0u8; 20], false)); - assert_ok!(Uniques::set_accept_ownership(Origin::signed(3), Some(0))); - assert_ok!(Uniques::transfer_ownership(Origin::signed(2), 0, 3)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(2), + 0, + bvec![0u8; 20], + false + )); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(2), 0, 42, bvec![0u8; 20], false)); + assert_ok!(Uniques::set_accept_ownership(RuntimeOrigin::signed(3), Some(0))); + assert_ok!(Uniques::transfer_ownership(RuntimeOrigin::signed(2), 0, 3)); assert_eq!(collections(), vec![(3, 0)]); assert_eq!(Balances::total_balance(&2), 57); assert_eq!(Balances::total_balance(&3), 145); @@ -266,7 +288,7 @@ fn transfer_owner_should_work() { // 2's acceptence from before is reset when it became owner, so it cannot be transfered // without a fresh acceptance. assert_noop!( - Uniques::transfer_ownership(Origin::signed(3), 0, 2), + Uniques::transfer_ownership(RuntimeOrigin::signed(3), 0, 2), Error::::Unaccepted ); }); @@ -275,14 +297,14 @@ fn transfer_owner_should_work() { #[test] fn set_team_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4)); - - assert_ok!(Uniques::mint(Origin::signed(2), 0, 42, 2)); - assert_ok!(Uniques::freeze(Origin::signed(4), 0, 42)); - assert_ok!(Uniques::thaw(Origin::signed(3), 0, 42)); - assert_ok!(Uniques::transfer(Origin::signed(3), 0, 42, 3)); - assert_ok!(Uniques::burn(Origin::signed(3), 0, 42, None)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); + + assert_ok!(Uniques::mint(RuntimeOrigin::signed(2), 0, 42, 2)); + assert_ok!(Uniques::freeze(RuntimeOrigin::signed(4), 0, 42)); + assert_ok!(Uniques::thaw(RuntimeOrigin::signed(3), 0, 42)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(3), 0, 42, 3)); + assert_ok!(Uniques::burn(RuntimeOrigin::signed(3), 0, 42, None)); }); } @@ -291,59 +313,89 @@ fn set_collection_metadata_should_work() { new_test_ext().execute_with(|| { // Cannot add metadata to unknown item assert_noop!( - Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 20], false), + Uniques::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 20], false), Error::::UnknownCollection, ); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); // Cannot add metadata to unowned item assert_noop!( - Uniques::set_collection_metadata(Origin::signed(2), 0, bvec![0u8; 20], false), + Uniques::set_collection_metadata(RuntimeOrigin::signed(2), 0, bvec![0u8; 20], false), Error::::NoPermission, ); // Successfully add metadata and take deposit Balances::make_free_balance_be(&1, 30); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 20], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0u8; 20], + false + )); assert_eq!(Balances::free_balance(&1), 9); assert!(CollectionMetadataOf::::contains_key(0)); // Force origin works, too. - assert_ok!(Uniques::set_collection_metadata(Origin::root(), 0, bvec![0u8; 18], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::root(), + 0, + bvec![0u8; 18], + false + )); // Update deposit - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 15], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0u8; 15], + false + )); assert_eq!(Balances::free_balance(&1), 14); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 25], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0u8; 25], + false + )); assert_eq!(Balances::free_balance(&1), 4); // Cannot over-reserve assert_noop!( - Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 40], false), + Uniques::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 40], false), BalancesError::::InsufficientBalance, ); // Can't set or clear metadata once frozen - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 15], true)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0u8; 15], + true + )); assert_noop!( - Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 15], false), + Uniques::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 15], false), Error::::Frozen, ); assert_noop!( - Uniques::clear_collection_metadata(Origin::signed(1), 0), + Uniques::clear_collection_metadata(RuntimeOrigin::signed(1), 0), Error::::Frozen ); // Clear Metadata - assert_ok!(Uniques::set_collection_metadata(Origin::root(), 0, bvec![0u8; 15], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::root(), + 0, + bvec![0u8; 15], + false + )); assert_noop!( - Uniques::clear_collection_metadata(Origin::signed(2), 0), + Uniques::clear_collection_metadata(RuntimeOrigin::signed(2), 0), Error::::NoPermission ); assert_noop!( - Uniques::clear_collection_metadata(Origin::signed(1), 1), + Uniques::clear_collection_metadata(RuntimeOrigin::signed(1), 1), Error::::UnknownCollection ); - assert_ok!(Uniques::clear_collection_metadata(Origin::signed(1), 0)); + assert_ok!(Uniques::clear_collection_metadata(RuntimeOrigin::signed(1), 0)); assert!(!CollectionMetadataOf::::contains_key(0)); }); } @@ -354,53 +406,56 @@ fn set_item_metadata_should_work() { Balances::make_free_balance_be(&1, 30); // Cannot add metadata to unknown item - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); // Cannot add metadata to unowned item assert_noop!( - Uniques::set_metadata(Origin::signed(2), 0, 42, bvec![0u8; 20], false), + Uniques::set_metadata(RuntimeOrigin::signed(2), 0, 42, bvec![0u8; 20], false), Error::::NoPermission, ); // Successfully add metadata and take deposit - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 20], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 20], false)); assert_eq!(Balances::free_balance(&1), 8); assert!(ItemMetadataOf::::contains_key(0, 42)); // Force origin works, too. - assert_ok!(Uniques::set_metadata(Origin::root(), 0, 42, bvec![0u8; 18], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::root(), 0, 42, bvec![0u8; 18], false)); // Update deposit - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 15], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15], false)); assert_eq!(Balances::free_balance(&1), 13); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 25], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 25], false)); assert_eq!(Balances::free_balance(&1), 3); // Cannot over-reserve assert_noop!( - Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 40], false), + Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 40], false), BalancesError::::InsufficientBalance, ); // Can't set or clear metadata once frozen - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 15], true)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15], true)); assert_noop!( - Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 15], false), + Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15], false), Error::::Frozen, ); - assert_noop!(Uniques::clear_metadata(Origin::signed(1), 0, 42), Error::::Frozen); + assert_noop!( + Uniques::clear_metadata(RuntimeOrigin::signed(1), 0, 42), + Error::::Frozen + ); // Clear Metadata - assert_ok!(Uniques::set_metadata(Origin::root(), 0, 42, bvec![0u8; 15], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::root(), 0, 42, bvec![0u8; 15], false)); assert_noop!( - Uniques::clear_metadata(Origin::signed(2), 0, 42), + Uniques::clear_metadata(RuntimeOrigin::signed(2), 0, 42), Error::::NoPermission ); assert_noop!( - Uniques::clear_metadata(Origin::signed(1), 1, 42), + Uniques::clear_metadata(RuntimeOrigin::signed(1), 1, 42), Error::::UnknownCollection ); - assert_ok!(Uniques::clear_metadata(Origin::signed(1), 0, 42)); + assert_ok!(Uniques::clear_metadata(RuntimeOrigin::signed(1), 0, 42)); assert!(!ItemMetadataOf::::contains_key(0, 42)); }); } @@ -410,11 +465,23 @@ fn set_attribute_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0])); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![0])); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![1], bvec![0])); + assert_ok!(Uniques::set_attribute(RuntimeOrigin::signed(1), 0, None, bvec![0], bvec![0])); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + bvec![0], + bvec![0] + )); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + bvec![1], + bvec![0] + )); assert_eq!( attributes(0), vec![ @@ -425,7 +492,13 @@ fn set_attribute_should_work() { ); assert_eq!(Balances::reserved_balance(1), 9); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0; 10])); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + None, + bvec![0], + bvec![0; 10] + )); assert_eq!( attributes(0), vec![ @@ -436,7 +509,7 @@ fn set_attribute_should_work() { ); assert_eq!(Balances::reserved_balance(1), 18); - assert_ok!(Uniques::clear_attribute(Origin::signed(1), 0, Some(0), bvec![1])); + assert_ok!(Uniques::clear_attribute(RuntimeOrigin::signed(1), 0, Some(0), bvec![1])); assert_eq!( attributes(0), vec![(None, bvec![0], bvec![0; 10]), (Some(0), bvec![0], bvec![0]),] @@ -444,7 +517,7 @@ fn set_attribute_should_work() { assert_eq!(Balances::reserved_balance(1), 15); let w = Collection::::get(0).unwrap().destroy_witness(); - assert_ok!(Uniques::destroy(Origin::signed(1), 0, w)); + assert_ok!(Uniques::destroy(RuntimeOrigin::signed(1), 0, w)); assert_eq!(attributes(0), vec![]); assert_eq!(Balances::reserved_balance(1), 0); }); @@ -455,11 +528,23 @@ fn set_attribute_should_respect_freeze() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0])); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![0])); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(1), bvec![0], bvec![0])); + assert_ok!(Uniques::set_attribute(RuntimeOrigin::signed(1), 0, None, bvec![0], bvec![0])); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + bvec![0], + bvec![0] + )); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(1), + bvec![0], + bvec![0] + )); assert_eq!( attributes(0), vec![ @@ -470,15 +555,33 @@ fn set_attribute_should_respect_freeze() { ); assert_eq!(Balances::reserved_balance(1), 9); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![], true)); + assert_ok!(Uniques::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![], true)); let e = Error::::Frozen; - assert_noop!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0]), e); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![1])); + assert_noop!( + Uniques::set_attribute(RuntimeOrigin::signed(1), 0, None, bvec![0], bvec![0]), + e + ); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + bvec![0], + bvec![1] + )); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 0, bvec![], true)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 0, bvec![], true)); let e = Error::::Frozen; - assert_noop!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![1]), e); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(1), bvec![0], bvec![1])); + assert_noop!( + Uniques::set_attribute(RuntimeOrigin::signed(1), 0, Some(0), bvec![0], bvec![1]), + e + ); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(1), + bvec![0], + bvec![1] + )); }); } @@ -487,32 +590,42 @@ fn force_item_status_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 69, 2)); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0; 20], false)); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0; 20], false)); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![0; 20], false)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 69, 2)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0; 20], + false + )); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0; 20], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 69, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 65); // force item status to be free holding - assert_ok!(Uniques::force_item_status(Origin::root(), 0, 1, 1, 1, 1, true, false)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 142, 1)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 169, 2)); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 142, bvec![0; 20], false)); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 169, bvec![0; 20], false)); + assert_ok!(Uniques::force_item_status(RuntimeOrigin::root(), 0, 1, 1, 1, 1, true, false)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 142, 1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 169, 2)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 142, bvec![0; 20], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 169, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 65); - assert_ok!(Uniques::redeposit(Origin::signed(1), 0, bvec![0, 42, 50, 69, 100])); + assert_ok!(Uniques::redeposit(RuntimeOrigin::signed(1), 0, bvec![0, 42, 50, 69, 100])); assert_eq!(Balances::reserved_balance(1), 63); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0; 20], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 42); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![0; 20], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 69, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 21); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0; 20], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0; 20], + false + )); assert_eq!(Balances::reserved_balance(1), 0); }); } @@ -521,23 +634,29 @@ fn force_item_status_should_work() { fn burn_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); - assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); + assert_ok!(Uniques::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); assert_noop!( - Uniques::burn(Origin::signed(5), 0, 42, Some(5)), + Uniques::burn(RuntimeOrigin::signed(5), 0, 42, Some(5)), Error::::UnknownCollection ); - assert_ok!(Uniques::mint(Origin::signed(2), 0, 42, 5)); - assert_ok!(Uniques::mint(Origin::signed(2), 0, 69, 5)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(2), 0, 42, 5)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(2), 0, 69, 5)); assert_eq!(Balances::reserved_balance(1), 2); - assert_noop!(Uniques::burn(Origin::signed(0), 0, 42, None), Error::::NoPermission); - assert_noop!(Uniques::burn(Origin::signed(5), 0, 42, Some(6)), Error::::WrongOwner); + assert_noop!( + Uniques::burn(RuntimeOrigin::signed(0), 0, 42, None), + Error::::NoPermission + ); + assert_noop!( + Uniques::burn(RuntimeOrigin::signed(5), 0, 42, Some(6)), + Error::::WrongOwner + ); - assert_ok!(Uniques::burn(Origin::signed(5), 0, 42, Some(5))); - assert_ok!(Uniques::burn(Origin::signed(3), 0, 69, Some(5))); + assert_ok!(Uniques::burn(RuntimeOrigin::signed(5), 0, 42, Some(5))); + assert_ok!(Uniques::burn(RuntimeOrigin::signed(3), 0, 69, Some(5))); assert_eq!(Balances::reserved_balance(1), 0); }); } @@ -545,31 +664,37 @@ fn burn_works() { #[test] fn approval_lifecycle_works() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); - assert_ok!(Uniques::transfer(Origin::signed(3), 0, 42, 4)); - assert_noop!(Uniques::transfer(Origin::signed(3), 0, 42, 3), Error::::NoPermission); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(3), 0, 42, 4)); + assert_noop!( + Uniques::transfer(RuntimeOrigin::signed(3), 0, 42, 3), + Error::::NoPermission + ); assert!(Item::::get(0, 42).unwrap().approved.is_none()); - assert_ok!(Uniques::approve_transfer(Origin::signed(4), 0, 42, 2)); - assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 2)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(4), 0, 42, 2)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 2)); }); } #[test] fn approved_account_gets_reset_after_transfer() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); - assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 5)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 5)); // this shouldn't work because we have just transfered the item to another account. - assert_noop!(Uniques::transfer(Origin::signed(3), 0, 42, 4), Error::::NoPermission); + assert_noop!( + Uniques::transfer(RuntimeOrigin::signed(3), 0, 42, 4), + Error::::NoPermission + ); // The new owner can transfer fine: - assert_ok!(Uniques::transfer(Origin::signed(5), 0, 42, 6)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(5), 0, 42, 6)); }); } @@ -581,47 +706,50 @@ fn approved_account_gets_reset_after_buy_item() { Balances::make_free_balance_be(&2, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, item, 1)); - assert_ok!(Uniques::approve_transfer(Origin::signed(1), 0, item, 5)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, item, 1)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(1), 0, item, 5)); - assert_ok!(Uniques::set_price(Origin::signed(1), 0, item, Some(price), None)); + assert_ok!(Uniques::set_price(RuntimeOrigin::signed(1), 0, item, Some(price), None)); - assert_ok!(Uniques::buy_item(Origin::signed(2), 0, item, price)); + assert_ok!(Uniques::buy_item(RuntimeOrigin::signed(2), 0, item, price)); // this shouldn't work because the item has been bough and the approved account should be // reset. - assert_noop!(Uniques::transfer(Origin::signed(5), 0, item, 4), Error::::NoPermission); + assert_noop!( + Uniques::transfer(RuntimeOrigin::signed(5), 0, item, 4), + Error::::NoPermission + ); }); } #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); assert_noop!( - Uniques::cancel_approval(Origin::signed(2), 1, 42, None), + Uniques::cancel_approval(RuntimeOrigin::signed(2), 1, 42, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::signed(2), 0, 43, None), + Uniques::cancel_approval(RuntimeOrigin::signed(2), 0, 43, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::signed(3), 0, 42, None), + Uniques::cancel_approval(RuntimeOrigin::signed(3), 0, 42, None), Error::::NoPermission ); assert_noop!( - Uniques::cancel_approval(Origin::signed(2), 0, 42, Some(4)), + Uniques::cancel_approval(RuntimeOrigin::signed(2), 0, 42, Some(4)), Error::::WrongDelegate ); - assert_ok!(Uniques::cancel_approval(Origin::signed(2), 0, 42, Some(3))); + assert_ok!(Uniques::cancel_approval(RuntimeOrigin::signed(2), 0, 42, Some(3))); assert_noop!( - Uniques::cancel_approval(Origin::signed(2), 0, 42, None), + Uniques::cancel_approval(RuntimeOrigin::signed(2), 0, 42, None), Error::::NoDelegate ); }); @@ -630,26 +758,26 @@ fn cancel_approval_works() { #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); assert_noop!( - Uniques::cancel_approval(Origin::signed(1), 1, 42, None), + Uniques::cancel_approval(RuntimeOrigin::signed(1), 1, 42, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::signed(1), 0, 43, None), + Uniques::cancel_approval(RuntimeOrigin::signed(1), 0, 43, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::signed(1), 0, 42, Some(4)), + Uniques::cancel_approval(RuntimeOrigin::signed(1), 0, 42, Some(4)), Error::::WrongDelegate ); - assert_ok!(Uniques::cancel_approval(Origin::signed(1), 0, 42, Some(3))); + assert_ok!(Uniques::cancel_approval(RuntimeOrigin::signed(1), 0, 42, Some(3))); assert_noop!( - Uniques::cancel_approval(Origin::signed(1), 0, 42, None), + Uniques::cancel_approval(RuntimeOrigin::signed(1), 0, 42, None), Error::::NoDelegate ); }); @@ -658,26 +786,26 @@ fn cancel_approval_works_with_admin() { #[test] fn cancel_approval_works_with_force() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); assert_noop!( - Uniques::cancel_approval(Origin::root(), 1, 42, None), + Uniques::cancel_approval(RuntimeOrigin::root(), 1, 42, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::root(), 0, 43, None), + Uniques::cancel_approval(RuntimeOrigin::root(), 0, 43, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::root(), 0, 42, Some(4)), + Uniques::cancel_approval(RuntimeOrigin::root(), 0, 42, Some(4)), Error::::WrongDelegate ); - assert_ok!(Uniques::cancel_approval(Origin::root(), 0, 42, Some(3))); + assert_ok!(Uniques::cancel_approval(RuntimeOrigin::root(), 0, 42, Some(3))); assert_noop!( - Uniques::cancel_approval(Origin::root(), 0, 42, None), + Uniques::cancel_approval(RuntimeOrigin::root(), 0, 42, None), Error::::NoDelegate ); }); @@ -691,11 +819,11 @@ fn max_supply_should_work() { let max_supply = 2; // validate set_collection_max_supply - assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), collection_id, user_id, true)); assert!(!CollectionMaxSupply::::contains_key(collection_id)); assert_ok!(Uniques::set_collection_max_supply( - Origin::signed(user_id), + RuntimeOrigin::signed(user_id), collection_id, max_supply )); @@ -708,7 +836,7 @@ fn max_supply_should_work() { assert_noop!( Uniques::set_collection_max_supply( - Origin::signed(user_id), + RuntimeOrigin::signed(user_id), collection_id, max_supply + 1 ), @@ -716,16 +844,16 @@ fn max_supply_should_work() { ); // validate we can't mint more to max supply - assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, 0, user_id)); - assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, 1, user_id)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_id), collection_id, 0, user_id)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_id), collection_id, 1, user_id)); assert_noop!( - Uniques::mint(Origin::signed(user_id), collection_id, 2, user_id), + Uniques::mint(RuntimeOrigin::signed(user_id), collection_id, 2, user_id), Error::::MaxSupplyReached ); // validate we remove the CollectionMaxSupply record when we destroy the collection assert_ok!(Uniques::destroy( - Origin::signed(user_id), + RuntimeOrigin::signed(user_id), collection_id, Collection::::get(collection_id).unwrap().destroy_witness() )); @@ -741,13 +869,13 @@ fn set_price_should_work() { let item_1 = 1; let item_2 = 2; - assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), collection_id, user_id, true)); - assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_1, user_id)); - assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_2, user_id)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_id), collection_id, item_1, user_id)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_id), collection_id, item_2, user_id)); assert_ok!(Uniques::set_price( - Origin::signed(user_id), + RuntimeOrigin::signed(user_id), collection_id, item_1, Some(1), @@ -755,7 +883,7 @@ fn set_price_should_work() { )); assert_ok!(Uniques::set_price( - Origin::signed(user_id), + RuntimeOrigin::signed(user_id), collection_id, item_2, Some(2), @@ -778,7 +906,13 @@ fn set_price_should_work() { })); // validate we can unset the price - assert_ok!(Uniques::set_price(Origin::signed(user_id), collection_id, item_2, None, None)); + assert_ok!(Uniques::set_price( + RuntimeOrigin::signed(user_id), + collection_id, + item_2, + None, + None + )); assert!(events().contains(&Event::::ItemPriceRemoved { collection: collection_id, item: item_2 @@ -805,14 +939,14 @@ fn buy_item_should_work() { Balances::make_free_balance_be(&user_2, initial_balance); Balances::make_free_balance_be(&user_3, initial_balance); - assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_1, true)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), collection_id, user_1, true)); - assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_1, user_1)); - assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_2, user_1)); - assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_3, user_1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_1), collection_id, item_1, user_1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_1), collection_id, item_2, user_1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_1), collection_id, item_3, user_1)); assert_ok!(Uniques::set_price( - Origin::signed(user_1), + RuntimeOrigin::signed(user_1), collection_id, item_1, Some(price_1), @@ -820,7 +954,7 @@ fn buy_item_should_work() { )); assert_ok!(Uniques::set_price( - Origin::signed(user_1), + RuntimeOrigin::signed(user_1), collection_id, item_2, Some(price_2), @@ -829,12 +963,17 @@ fn buy_item_should_work() { // can't buy for less assert_noop!( - Uniques::buy_item(Origin::signed(user_2), collection_id, item_1, 1), + Uniques::buy_item(RuntimeOrigin::signed(user_2), collection_id, item_1, 1), Error::::BidTooLow ); // pass the higher price to validate it will still deduct correctly - assert_ok!(Uniques::buy_item(Origin::signed(user_2), collection_id, item_1, price_1 + 1,)); + assert_ok!(Uniques::buy_item( + RuntimeOrigin::signed(user_2), + collection_id, + item_1, + price_1 + 1, + )); // validate the new owner & balances let item = Item::::get(collection_id, item_1).unwrap(); @@ -844,18 +983,23 @@ fn buy_item_should_work() { // can't buy from yourself assert_noop!( - Uniques::buy_item(Origin::signed(user_1), collection_id, item_2, price_2), + Uniques::buy_item(RuntimeOrigin::signed(user_1), collection_id, item_2, price_2), Error::::NoPermission ); // can't buy when the item is listed for a specific buyer assert_noop!( - Uniques::buy_item(Origin::signed(user_2), collection_id, item_2, price_2), + Uniques::buy_item(RuntimeOrigin::signed(user_2), collection_id, item_2, price_2), Error::::NoPermission ); // can buy when I'm a whitelisted buyer - assert_ok!(Uniques::buy_item(Origin::signed(user_3), collection_id, item_2, price_2,)); + assert_ok!(Uniques::buy_item( + RuntimeOrigin::signed(user_3), + collection_id, + item_2, + price_2, + )); assert!(events().contains(&Event::::ItemBought { collection: collection_id, @@ -870,14 +1014,14 @@ fn buy_item_should_work() { // can't buy when item is not for sale assert_noop!( - Uniques::buy_item(Origin::signed(user_2), collection_id, item_3, price_2), + Uniques::buy_item(RuntimeOrigin::signed(user_2), collection_id, item_3, price_2), Error::::NotForSale ); // ensure we can't buy an item when the collection or an item is frozen { assert_ok!(Uniques::set_price( - Origin::signed(user_1), + RuntimeOrigin::signed(user_1), collection_id, item_3, Some(price_1), @@ -885,26 +1029,32 @@ fn buy_item_should_work() { )); // freeze collection - assert_ok!(Uniques::freeze_collection(Origin::signed(user_1), collection_id)); + assert_ok!(Uniques::freeze_collection(RuntimeOrigin::signed(user_1), collection_id)); let buy_item_call = mock::RuntimeCall::Uniques(crate::Call::::buy_item { collection: collection_id, item: item_3, bid_price: price_1, }); - assert_noop!(buy_item_call.dispatch(Origin::signed(user_2)), Error::::Frozen); + assert_noop!( + buy_item_call.dispatch(RuntimeOrigin::signed(user_2)), + Error::::Frozen + ); - assert_ok!(Uniques::thaw_collection(Origin::signed(user_1), collection_id)); + assert_ok!(Uniques::thaw_collection(RuntimeOrigin::signed(user_1), collection_id)); // freeze item - assert_ok!(Uniques::freeze(Origin::signed(user_1), collection_id, item_3)); + assert_ok!(Uniques::freeze(RuntimeOrigin::signed(user_1), collection_id, item_3)); let buy_item_call = mock::RuntimeCall::Uniques(crate::Call::::buy_item { collection: collection_id, item: item_3, bid_price: price_1, }); - assert_noop!(buy_item_call.dispatch(Origin::signed(user_2)), Error::::Frozen); + assert_noop!( + buy_item_call.dispatch(RuntimeOrigin::signed(user_2)), + Error::::Frozen + ); } }); } diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index c29eded25aa5b..07bc14951cb3b 100644 --- a/frame/utility/src/benchmarking.rs +++ b/frame/utility/src/benchmarking.rs @@ -30,7 +30,7 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { } benchmarks! { - where_clause { where ::PalletsOrigin: Clone } + where_clause { where ::PalletsOrigin: Clone } batch { let c in 0 .. 1000; let mut calls: Vec<::RuntimeCall> = Vec::new(); @@ -68,8 +68,8 @@ benchmarks! { dispatch_as { let caller = account("caller", SEED, SEED); let call = Box::new(frame_system::Call::remark { remark: vec![] }.into()); - let origin: T::Origin = RawOrigin::Signed(caller).into(); - let pallets_origin: ::PalletsOrigin = origin.caller().clone(); + let origin: T::RuntimeOrigin = RawOrigin::Signed(caller).into(); + let pallets_origin: ::PalletsOrigin = origin.caller().clone(); let pallets_origin = Into::::into(pallets_origin); }: _(RawOrigin::Root, Box::new(pallets_origin), call) diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 08fb34ed9e3c1..bc19b5625a71a 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -87,17 +87,17 @@ pub mod pallet { /// The overarching call type. type RuntimeCall: Parameter - + Dispatchable + + Dispatchable + GetDispatchInfo + From> - + UnfilteredDispatchable + + UnfilteredDispatchable + IsSubType> + IsType<::RuntimeCall>; /// The caller origin, overarching type of all pallets origins. type PalletsOrigin: Parameter + - Into<::Origin> + - IsType<<::Origin as frame_support::traits::OriginTrait>::PalletsOrigin>; + Into<::RuntimeOrigin> + + IsType<<::RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 93b80672f55e2..65d9c966ebdfd 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -106,7 +106,7 @@ impl frame_system::Config for Test { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -199,12 +199,16 @@ fn call_foobar(err: bool, start_weight: Weight, end_weight: Option) -> R fn as_derivative_works() { new_test_ext().execute_with(|| { let sub_1_0 = Utility::derivative_account_id(1, 0); - assert_ok!(Balances::transfer(Origin::signed(1), sub_1_0, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), sub_1_0, 5)); assert_err_ignore_postinfo!( - Utility::as_derivative(Origin::signed(1), 1, Box::new(call_transfer(6, 3)),), + Utility::as_derivative(RuntimeOrigin::signed(1), 1, Box::new(call_transfer(6, 3)),), BalancesError::::InsufficientBalance ); - assert_ok!(Utility::as_derivative(Origin::signed(1), 0, Box::new(call_transfer(2, 3)),)); + assert_ok!(Utility::as_derivative( + RuntimeOrigin::signed(1), + 0, + Box::new(call_transfer(2, 3)), + )); assert_eq!(Balances::free_balance(sub_1_0), 2); assert_eq!(Balances::free_balance(2), 13); }); @@ -224,7 +228,7 @@ fn as_derivative_handles_weight_refund() { call: Box::new(inner_call), }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), info.weight); @@ -235,7 +239,7 @@ fn as_derivative_handles_weight_refund() { call: Box::new(inner_call), }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); // Diff is refunded assert_eq!(extract_actual_weight(&result, &info), info.weight - diff); @@ -247,7 +251,7 @@ fn as_derivative_handles_weight_refund() { call: Box::new(inner_call), }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_noop!( result, DispatchErrorWithPostInfo { @@ -267,7 +271,7 @@ fn as_derivative_handles_weight_refund() { call: Box::new(inner_call), }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_noop!( result, DispatchErrorWithPostInfo { @@ -287,7 +291,7 @@ fn as_derivative_filters() { new_test_ext().execute_with(|| { assert_err_ignore_postinfo!( Utility::as_derivative( - Origin::signed(1), + RuntimeOrigin::signed(1), 1, Box::new(RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { dest: 2, @@ -310,7 +314,7 @@ fn batch_with_root_works() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::batch( - Origin::root(), + RuntimeOrigin::root(), vec![ RuntimeCall::Balances(BalancesCall::force_transfer { source: 1, @@ -337,7 +341,7 @@ fn batch_with_signed_works() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::batch( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![call_transfer(2, 5), call_transfer(2, 5)] ),); assert_eq!(Balances::free_balance(1), 0); @@ -349,7 +353,7 @@ fn batch_with_signed_works() { fn batch_with_signed_filters() { new_test_ext().execute_with(|| { assert_ok!(Utility::batch( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { dest: 2, value: 1 @@ -371,7 +375,7 @@ fn batch_early_exit_works() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::batch( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![call_transfer(2, 5), call_transfer(2, 10), call_transfer(2, 5),] ),); assert_eq!(Balances::free_balance(1), 5); @@ -409,7 +413,7 @@ fn batch_handles_weight_refund() { let batch_calls = vec![inner_call; batch_len as usize]; let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), info.weight); @@ -418,7 +422,7 @@ fn batch_handles_weight_refund() { let batch_calls = vec![inner_call; batch_len as usize]; let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); // Diff is refunded assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); @@ -429,7 +433,7 @@ fn batch_handles_weight_refund() { let batch_calls = vec![good_call, bad_call]; let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); System::assert_last_event( utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), @@ -444,7 +448,7 @@ fn batch_handles_weight_refund() { let batch_len = batch_calls.len() as u64; let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); System::assert_last_event( utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), @@ -457,7 +461,7 @@ fn batch_handles_weight_refund() { let batch_calls = vec![good_call, bad_call.clone(), bad_call]; let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); System::assert_last_event( utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), @@ -476,7 +480,7 @@ fn batch_all_works() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::batch_all( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![call_transfer(2, 5), call_transfer(2, 5)] ),); assert_eq!(Balances::free_balance(1), 0); @@ -496,7 +500,7 @@ fn batch_all_revert() { calls: vec![call_transfer(2, 5), call_transfer(2, 10), call_transfer(2, 5)], }); assert_noop!( - batch_all_calls.dispatch(Origin::signed(1)), + batch_all_calls.dispatch(RuntimeOrigin::signed(1)), DispatchErrorWithPostInfo { post_info: PostDispatchInfo { actual_weight: Some( @@ -525,7 +529,7 @@ fn batch_all_handles_weight_refund() { let batch_calls = vec![inner_call; batch_len as usize]; let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), info.weight); @@ -534,7 +538,7 @@ fn batch_all_handles_weight_refund() { let batch_calls = vec![inner_call; batch_len as usize]; let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); // Diff is refunded assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); @@ -545,7 +549,7 @@ fn batch_all_handles_weight_refund() { let batch_calls = vec![good_call, bad_call]; let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); // No weight is refunded assert_eq!(extract_actual_weight(&result, &info), info.weight); @@ -557,7 +561,7 @@ fn batch_all_handles_weight_refund() { let batch_len = batch_calls.len() as u64; let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); @@ -567,7 +571,7 @@ fn batch_all_handles_weight_refund() { let batch_calls = vec![good_call, bad_call.clone(), bad_call]; let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); assert_eq!( extract_actual_weight(&result, &info), @@ -590,7 +594,7 @@ fn batch_all_does_not_nest() { assert_eq!(Balances::free_balance(2), 10); // A nested batch_all call will not pass the filter, and fail with `BadOrigin`. assert_noop!( - Utility::batch_all(Origin::signed(1), vec![batch_all.clone()]), + Utility::batch_all(RuntimeOrigin::signed(1), vec![batch_all.clone()]), DispatchErrorWithPostInfo { post_info: PostDispatchInfo { actual_weight: Some(::WeightInfo::batch_all(1) + info.weight), @@ -606,7 +610,7 @@ fn batch_all_does_not_nest() { let batch_nested = RuntimeCall::Utility(UtilityCall::batch { calls: vec![batch_all] }); // Batch will end with `Ok`, but does not actually execute as we can see from the event // and balances. - assert_ok!(Utility::batch_all(Origin::signed(1), vec![batch_nested])); + assert_ok!(Utility::batch_all(RuntimeOrigin::signed(1), vec![batch_nested])); System::assert_has_event( utility::Event::BatchInterrupted { index: 0, @@ -623,8 +627,14 @@ fn batch_all_does_not_nest() { fn batch_limit() { new_test_ext().execute_with(|| { let calls = vec![RuntimeCall::System(SystemCall::remark { remark: vec![] }); 40_000]; - assert_noop!(Utility::batch(Origin::signed(1), calls.clone()), Error::::TooManyCalls); - assert_noop!(Utility::batch_all(Origin::signed(1), calls), Error::::TooManyCalls); + assert_noop!( + Utility::batch(RuntimeOrigin::signed(1), calls.clone()), + Error::::TooManyCalls + ); + assert_noop!( + Utility::batch_all(RuntimeOrigin::signed(1), calls), + Error::::TooManyCalls + ); }); } @@ -634,7 +644,7 @@ fn force_batch_works() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::force_batch( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![ call_transfer(2, 5), call_foobar(true, Weight::from_ref_time(75), None), @@ -650,12 +660,12 @@ fn force_batch_works() { assert_eq!(Balances::free_balance(2), 20); assert_ok!(Utility::force_batch( - Origin::signed(2), + RuntimeOrigin::signed(2), vec![call_transfer(1, 5), call_transfer(1, 5),] ),); System::assert_last_event(utility::Event::BatchCompleted.into()); - assert_ok!(Utility::force_batch(Origin::signed(1), vec![call_transfer(2, 50),]),); + assert_ok!(Utility::force_batch(RuntimeOrigin::signed(1), vec![call_transfer(2, 50),]),); System::assert_last_event(utility::Event::BatchCompletedWithErrors.into()); }); } diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index cc4a3523459d7..c4e520b37c8c8 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -67,7 +67,7 @@ impl frame_system::Config for Test { type OnNewAccount = (); type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type PalletInfo = PalletInfo; type SS58Prefix = (); type SystemWeightInfo = (); diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index 9e55d38fd8140..e0a758b2ddfdf 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -33,7 +33,7 @@ benchmarks! { whitelist_call { let origin = T::WhitelistOrigin::successful_origin(); let call_hash = Default::default(); - }: _(origin, call_hash) + }: _(origin, call_hash) verify { ensure!( WhitelistedCall::::contains_key(call_hash), @@ -50,7 +50,7 @@ benchmarks! { let call_hash = Default::default(); Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); - }: _(origin, call_hash) + }: _(origin, call_hash) verify { ensure!( !WhitelistedCall::::contains_key(call_hash), @@ -82,7 +82,7 @@ benchmarks! { let encoded_call = encoded_call.try_into().expect("encoded_call must be small enough"); T::PreimageProvider::note_preimage(encoded_call); - }: _(origin, call_hash, call_weight) + }: _(origin, call_hash, call_weight) verify { ensure!( !WhitelistedCall::::contains_key(call_hash), @@ -105,7 +105,7 @@ benchmarks! { Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); - }: _(origin, Box::new(call)) + }: _(origin, Box::new(call)) verify { ensure!( !WhitelistedCall::::contains_key(call_hash), diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index c5621a239f3a6..55d5c42b8f4bc 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -66,7 +66,7 @@ pub mod pallet { /// The overarching call type. type RuntimeCall: IsType<::RuntimeCall> - + Dispatchable + + Dispatchable + GetDispatchInfo + FullCodec + TypeInfo @@ -74,10 +74,10 @@ pub mod pallet { + Parameter; /// Required origin for whitelisting a call. - type WhitelistOrigin: EnsureOrigin; + type WhitelistOrigin: EnsureOrigin; /// Required origin for dispatching whitelisted call with root origin. - type DispatchWhitelistedOrigin: EnsureOrigin; + type DispatchWhitelistedOrigin: EnsureOrigin; /// The handler of pre-images. // NOTE: recipient is only needed for benchmarks. diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs index b6eac316bc113..44aea86be6f19 100644 --- a/frame/whitelist/src/mock.rs +++ b/frame/whitelist/src/mock.rs @@ -58,7 +58,7 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/frame/whitelist/src/tests.rs b/frame/whitelist/src/tests.rs index ebb111149fd42..fd6558e83f30e 100644 --- a/frame/whitelist/src/tests.rs +++ b/frame/whitelist/src/tests.rs @@ -32,35 +32,35 @@ fn test_whitelist_call_and_remove() { let call_hash = ::Hashing::hash(&encoded_call[..]); assert_noop!( - Whitelist::remove_whitelisted_call(Origin::root(), call_hash), + Whitelist::remove_whitelisted_call(RuntimeOrigin::root(), call_hash), crate::Error::::CallIsNotWhitelisted, ); assert_noop!( - Whitelist::whitelist_call(Origin::signed(1), call_hash), + Whitelist::whitelist_call(RuntimeOrigin::signed(1), call_hash), DispatchError::BadOrigin, ); - assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); assert!(Preimage::preimage_requested(&call_hash)); assert_noop!( - Whitelist::whitelist_call(Origin::root(), call_hash), + Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash), crate::Error::::CallAlreadyWhitelisted, ); assert_noop!( - Whitelist::remove_whitelisted_call(Origin::signed(1), call_hash), + Whitelist::remove_whitelisted_call(RuntimeOrigin::signed(1), call_hash), DispatchError::BadOrigin, ); - assert_ok!(Whitelist::remove_whitelisted_call(Origin::root(), call_hash)); + assert_ok!(Whitelist::remove_whitelisted_call(RuntimeOrigin::root(), call_hash)); assert!(!Preimage::preimage_requested(&call_hash)); assert_noop!( - Whitelist::remove_whitelisted_call(Origin::root(), call_hash), + Whitelist::remove_whitelisted_call(RuntimeOrigin::root(), call_hash), crate::Error::::CallIsNotWhitelisted, ); }); @@ -75,41 +75,45 @@ fn test_whitelist_call_and_execute() { let call_hash = ::Hashing::hash(&encoded_call[..]); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), crate::Error::::CallIsNotWhitelisted, ); - assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::signed(1), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call(RuntimeOrigin::signed(1), call_hash, call_weight), DispatchError::BadOrigin, ); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), crate::Error::::UnavailablePreImage, ); - assert_ok!(Preimage::note_preimage(Origin::root(), encoded_call)); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::root(), encoded_call)); assert!(Preimage::preimage_requested(&call_hash)); assert_noop!( Whitelist::dispatch_whitelisted_call( - Origin::root(), + RuntimeOrigin::root(), call_hash, call_weight - Weight::from_ref_time(1) ), crate::Error::::InvalidCallWeightWitness, ); - assert_ok!(Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight)); + assert_ok!(Whitelist::dispatch_whitelisted_call( + RuntimeOrigin::root(), + call_hash, + call_weight + )); assert!(!Preimage::preimage_requested(&call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), crate::Error::::CallIsNotWhitelisted, ); }); @@ -126,10 +130,14 @@ fn test_whitelist_call_and_execute_failing_call() { let encoded_call = call.encode(); let call_hash = ::Hashing::hash(&encoded_call[..]); - assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); - assert_ok!(Preimage::note_preimage(Origin::root(), encoded_call)); + assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::root(), encoded_call)); assert!(Preimage::preimage_requested(&call_hash)); - assert_ok!(Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight)); + assert_ok!(Whitelist::dispatch_whitelisted_call( + RuntimeOrigin::root(), + call_hash, + call_weight + )); assert!(!Preimage::preimage_requested(&call_hash)); }); } @@ -142,18 +150,18 @@ fn test_whitelist_call_and_execute_without_note_preimage() { })); let call_hash = ::Hashing::hash_of(&call); - assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); assert!(Preimage::preimage_requested(&call_hash)); assert_ok!(Whitelist::dispatch_whitelisted_call_with_preimage( - Origin::root(), + RuntimeOrigin::root(), call.clone() )); assert!(!Preimage::preimage_requested(&call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call_with_preimage(Origin::root(), call), + Whitelist::dispatch_whitelisted_call_with_preimage(RuntimeOrigin::root(), call), crate::Error::::CallIsNotWhitelisted, ); }); @@ -171,11 +179,11 @@ fn test_whitelist_call_and_execute_decode_consumes_all() { let call_hash = ::Hashing::hash(&call[..]); - assert_ok!(Preimage::note_preimage(Origin::root(), call)); - assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::root(), call)); + assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), crate::Error::::UndecodableCall, ); }); diff --git a/primitives/runtime/src/generic/checked_extrinsic.rs b/primitives/runtime/src/generic/checked_extrinsic.rs index 5d6c657a68977..fd7745c6031ff 100644 --- a/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/primitives/runtime/src/generic/checked_extrinsic.rs @@ -39,12 +39,13 @@ pub struct CheckedExtrinsic { pub function: Call, } -impl traits::Applyable for CheckedExtrinsic +impl traits::Applyable + for CheckedExtrinsic where AccountId: Member + MaybeDisplay, - Call: Member + Dispatchable, + Call: Member + Dispatchable, Extra: SignedExtension, - Origin: From>, + RuntimeOrigin: From>, { type Call = Call; @@ -78,7 +79,7 @@ where U::pre_dispatch(&self.function)?; (None, None) }; - let res = self.function.dispatch(Origin::from(maybe_who)); + let res = self.function.dispatch(RuntimeOrigin::from(maybe_who)); let post_info = match res { Ok(info) => info, Err(err) => err.post_info, diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index 003fa62c9e088..d16a37e6a2059 100644 --- a/primitives/runtime/src/testing.rs +++ b/primitives/runtime/src/testing.rs @@ -358,8 +358,15 @@ where impl Applyable for TestXt where - Call: - 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Dispatchable, + Call: 'static + + Sized + + Send + + Sync + + Clone + + Eq + + Codec + + Debug + + Dispatchable, Extra: SignedExtension, Origin: From>, { diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 495dfa66c5462..1c48b1933431d 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1018,7 +1018,7 @@ pub trait Dispatchable { /// Every function call from your runtime has an origin, which specifies where the extrinsic was /// generated from. In the case of a signed extrinsic (transaction), the origin contains an /// identifier for the caller. The origin can be empty in the case of an inherent extrinsic. - type Origin; + type RuntimeOrigin; /// ... type Config; /// An opaque set of information attached to the transaction. This could be constructed anywhere @@ -1029,7 +1029,8 @@ pub trait Dispatchable { /// with information about a `Dispatchable` that is ownly known post dispatch. type PostInfo: Eq + PartialEq + Clone + Copy + Encode + Decode + Printable; /// Actually dispatch this call and return the result of it. - fn dispatch(self, origin: Self::Origin) -> crate::DispatchResultWithInfo; + fn dispatch(self, origin: Self::RuntimeOrigin) + -> crate::DispatchResultWithInfo; } /// Shortcut to reference the `Info` type of a `Dispatchable`. @@ -1038,11 +1039,14 @@ pub type DispatchInfoOf = ::Info; pub type PostDispatchInfoOf = ::PostInfo; impl Dispatchable for () { - type Origin = (); + type RuntimeOrigin = (); type Config = (); type Info = (); type PostInfo = (); - fn dispatch(self, _origin: Self::Origin) -> crate::DispatchResultWithInfo { + fn dispatch( + self, + _origin: Self::RuntimeOrigin, + ) -> crate::DispatchResultWithInfo { panic!("This implementation should not be used for actual dispatch."); } } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 4ed159fd7e2ed..5601de632eae3 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -233,11 +233,14 @@ impl ExtrinsicT for Extrinsic { } impl sp_runtime::traits::Dispatchable for Extrinsic { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Config = (); type Info = (); type PostInfo = (); - fn dispatch(self, _origin: Self::Origin) -> sp_runtime::DispatchResultWithInfo { + fn dispatch( + self, + _origin: Self::RuntimeOrigin, + ) -> sp_runtime::DispatchResultWithInfo { panic!("This implementation should not be used for actual dispatch."); } } @@ -441,22 +444,22 @@ impl GetRuntimeBlockType for Runtime { } #[derive(Clone, RuntimeDebug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -pub struct Origin; +pub struct RuntimeOrigin; -impl From> for Origin { +impl From> for RuntimeOrigin { fn from(_o: frame_system::Origin) -> Self { unimplemented!("Not required in tests!") } } -impl From for Result, Origin> { - fn from(_origin: Origin) -> Result, Origin> { +impl From for Result, RuntimeOrigin> { + fn from(_origin: RuntimeOrigin) -> Result, RuntimeOrigin> { unimplemented!("Not required in tests!") } } -impl frame_support::traits::OriginTrait for Origin { +impl frame_support::traits::OriginTrait for RuntimeOrigin { type Call = ::RuntimeCall; - type PalletsOrigin = Origin; + type PalletsOrigin = RuntimeOrigin; type AccountId = ::AccountId; fn add_filter(&mut self, _filter: impl Fn(&Self::Call) -> bool + 'static) { @@ -584,7 +587,7 @@ impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = Extrinsic; type Index = u64; type BlockNumber = u64; diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 45a6f66416d8c..0cb3e7d70f6df 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -40,7 +40,7 @@ const NONCE_OF: &[u8] = b"nonce:"; const BALANCE_OF: &[u8] = b"balance:"; decl_module! { - pub struct Module for enum Call where origin: T::Origin {} + pub struct Module for enum Call where origin: T::RuntimeOrigin {} } decl_storage! { diff --git a/utils/frame/rpc/support/src/lib.rs b/utils/frame/rpc/support/src/lib.rs index 2ee007c84f0aa..ad90c24167587 100644 --- a/utils/frame/rpc/support/src/lib.rs +++ b/utils/frame/rpc/support/src/lib.rs @@ -47,7 +47,7 @@ use sp_storage::{StorageData, StorageKey}; /// # struct TestRuntime; /// # /// # decl_module! { -/// # pub struct Module for enum Call where origin: T::Origin {} +/// # pub struct Module for enum Call where origin: T::RuntimeOrigin {} /// # } /// # /// pub type Loc = (i64, i64, i64); From 409167ef427e1b1b32a0cb9c05117e8fe73a7b1a Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Wed, 21 Sep 2022 14:12:20 +0800 Subject: [PATCH 1183/1472] Use `array-bytes` for All Array/Bytes/Hex Operations (#12190) * Use `array-bytes` for All Array/Bytes/Hex Operations Signed-off-by: Xavier Lau * Reorder * Self Review * Format * Fix Tests * Bump `array-bytes` * Optimize large test res Signed-off-by: Xavier Lau Co-authored-by: parity-processbot <> --- Cargo.lock | 76 +++++------ bin/node-template/runtime/Cargo.toml | 2 - bin/node/bench/Cargo.toml | 2 +- bin/node/bench/src/generator.rs | 6 +- bin/node/cli/Cargo.toml | 2 +- bin/node/cli/src/chain_spec.rs | 56 ++++---- bin/node/runtime/Cargo.toml | 2 - client/beefy/Cargo.toml | 2 +- client/beefy/src/lib.rs | 5 +- client/beefy/src/tests.rs | 2 +- client/cli/Cargo.toml | 2 +- client/cli/src/commands/generate_node_key.rs | 4 +- client/cli/src/commands/inspect_key.rs | 8 +- client/cli/src/commands/inspect_node_key.rs | 3 +- client/cli/src/commands/sign.rs | 2 +- client/cli/src/commands/utils.rs | 15 +-- client/cli/src/commands/vanity.rs | 4 +- client/cli/src/commands/verify.rs | 4 +- client/cli/src/error.rs | 10 +- client/cli/src/params/node_key_params.rs | 2 +- client/executor/Cargo.toml | 2 +- client/executor/src/integration_tests/mod.rs | 35 ++--- client/finality-grandpa/Cargo.toml | 2 +- .../finality-grandpa/src/communication/mod.rs | 5 +- .../src/communication/tests.rs | 2 +- client/keystore/Cargo.toml | 2 +- client/keystore/src/local.rs | 8 +- client/network/Cargo.toml | 2 +- client/network/light/Cargo.toml | 2 +- .../light/src/light_client_requests.rs | 5 +- client/network/src/config.rs | 2 +- client/network/src/protocol.rs | 9 +- client/network/src/transactions.rs | 5 +- client/network/sync/Cargo.toml | 2 +- .../network/sync/src/block_request_handler.rs | 5 +- .../network/sync/src/state_request_handler.rs | 5 +- .../network/sync/src/warp_request_handler.rs | 5 +- client/offchain/Cargo.toml | 2 +- client/offchain/src/api.rs | 16 +-- client/service/test/Cargo.toml | 3 +- client/service/test/src/client/mod.rs | 35 ++--- client/transaction-pool/Cargo.toml | 2 +- client/transaction-pool/tests/pool.rs | 2 +- frame/alliance/Cargo.toml | 6 +- frame/beefy-mmr/Cargo.toml | 6 +- frame/beefy-mmr/primitives/Cargo.toml | 7 +- frame/beefy-mmr/primitives/src/lib.rs | 82 +++++++---- frame/beefy-mmr/src/tests.rs | 54 ++++---- frame/benchmarking/Cargo.toml | 2 +- frame/benchmarking/src/lib.rs | 8 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/src/exec.rs | 10 +- frame/contracts/src/wasm/mod.rs | 27 ++-- frame/executive/Cargo.toml | 2 +- frame/executive/src/lib.rs | 31 +++-- frame/merkle-mountain-range/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 4 +- frame/transaction-storage/src/benchmarking.rs | 127 +++++++++--------- primitives/beefy/Cargo.toml | 3 +- primitives/beefy/src/commitment.rs | 71 ++-------- primitives/beefy/src/witness.rs | 14 +- .../beefy/test-res/large-raw-commitment | Bin 0 -> 44638 bytes primitives/core/Cargo.toml | 7 +- primitives/core/src/crypto.rs | 12 +- primitives/core/src/ecdsa.rs | 29 ++-- primitives/core/src/ed25519.rs | 29 ++-- primitives/core/src/sr25519.rs | 52 +++---- primitives/merkle-mountain-range/Cargo.toml | 2 +- primitives/merkle-mountain-range/src/lib.rs | 11 +- primitives/state-machine/Cargo.toml | 2 +- primitives/state-machine/src/basic.rs | 8 +- .../src/overlayed_changes/mod.rs | 8 +- primitives/state-machine/src/testing.rs | 6 +- primitives/trie/Cargo.toml | 2 +- primitives/trie/src/lib.rs | 27 ++-- test-utils/client/Cargo.toml | 2 +- test-utils/client/src/lib.rs | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../frame/benchmarking-cli/src/block/bench.rs | 4 +- 79 files changed, 520 insertions(+), 510 deletions(-) create mode 100644 primitives/beefy/test-res/large-raw-commitment diff --git a/Cargo.lock b/Cargo.lock index d04f82f4bbecc..5791c8762d955 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,6 +112,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "698b65a961a9d730fb45b6b0327e20207810c9f61ee421b082b27ba003f49e2b" +[[package]] +name = "array-bytes" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a913633b0c922e6b745072795f50d90ebea78ba31a57e2ac8c2fc7b50950949" + [[package]] name = "arrayref" version = "0.3.6" @@ -446,12 +452,12 @@ dependencies = [ name = "beefy-gadget" version = "4.0.0-dev" dependencies = [ + "array-bytes", "async-trait", "beefy-primitives", "fnv", "futures", "futures-timer", - "hex", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -513,10 +519,9 @@ dependencies = [ name = "beefy-merkle-tree" version = "4.0.0-dev" dependencies = [ + "array-bytes", "beefy-primitives", "env_logger", - "hex", - "hex-literal", "log", "sp-api", "tiny-keccak", @@ -526,8 +531,7 @@ dependencies = [ name = "beefy-primitives" version = "4.0.0-dev" dependencies = [ - "hex", - "hex-literal", + "array-bytes", "parity-scale-codec", "scale-info", "sp-api", @@ -2112,9 +2116,9 @@ dependencies = [ name = "frame-benchmarking" version = "4.0.0-dev" dependencies = [ + "array-bytes", "frame-support", "frame-system", - "hex-literal", "linregress", "log", "parity-scale-codec", @@ -2138,6 +2142,7 @@ name = "frame-benchmarking-cli" version = "4.0.0-dev" dependencies = [ "Inflector", + "array-bytes", "chrono", "clap 3.1.18", "comfy-table", @@ -2147,7 +2152,6 @@ dependencies = [ "gethostname", "handlebars", "hash-db", - "hex", "itertools", "kvdb", "lazy_static", @@ -2238,10 +2242,10 @@ dependencies = [ name = "frame-executive" version = "4.0.0-dev" dependencies = [ + "array-bytes", "frame-support", "frame-system", "frame-try-runtime", - "hex-literal", "pallet-balances", "pallet-transaction-payment", "parity-scale-codec", @@ -2854,12 +2858,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex-literal" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" - [[package]] name = "hex_fmt" version = "0.3.0" @@ -3355,7 +3353,6 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", "log", "node-primitives", "pallet-alliance", @@ -4637,12 +4634,12 @@ dependencies = [ name = "node-bench" version = "0.9.0-dev" dependencies = [ + "array-bytes", "clap 3.1.18", "derive_more", "fs_extra", "futures", "hash-db", - "hex", "kitchensink-runtime", "kvdb", "kvdb-rocksdb", @@ -4674,6 +4671,7 @@ dependencies = [ name = "node-cli" version = "3.0.0-dev" dependencies = [ + "array-bytes", "assert_cmd", "async-std", "clap 3.1.18", @@ -4683,7 +4681,6 @@ dependencies = [ "frame-system", "frame-system-rpc-runtime-api", "futures", - "hex-literal", "jsonrpsee", "kitchensink-runtime", "log", @@ -4912,7 +4909,6 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", "pallet-aura", "pallet-balances", "pallet-grandpa", @@ -5181,11 +5177,10 @@ dependencies = [ name = "pallet-alliance" version = "4.0.0-dev" dependencies = [ + "array-bytes", "frame-benchmarking", "frame-support", "frame-system", - "hex", - "hex-literal", "log", "pallet-balances", "pallet-collective", @@ -5416,12 +5411,11 @@ dependencies = [ name = "pallet-beefy-mmr" version = "4.0.0-dev" dependencies = [ + "array-bytes", "beefy-merkle-tree", "beefy-primitives", "frame-support", "frame-system", - "hex", - "hex-literal", "log", "pallet-beefy", "pallet-mmr", @@ -5493,13 +5487,13 @@ dependencies = [ name = "pallet-contracts" version = "4.0.0-dev" dependencies = [ + "array-bytes", "assert_matches", "bitflags", "env_logger", "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", "impl-trait-for-tuples", "log", "pallet-balances", @@ -5860,12 +5854,12 @@ dependencies = [ name = "pallet-mmr" version = "4.0.0-dev" dependencies = [ + "array-bytes", "ckb-merkle-mountain-range", "env_logger", "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", "itertools", "parity-scale-codec", "scale-info", @@ -6453,10 +6447,10 @@ dependencies = [ name = "pallet-transaction-storage" version = "4.0.0-dev" dependencies = [ + "array-bytes", "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", "log", "pallet-balances", "parity-scale-codec", @@ -7897,11 +7891,11 @@ dependencies = [ name = "sc-cli" version = "0.10.0-dev" dependencies = [ + "array-bytes", "chrono", "clap 3.1.18", "fdlimit", "futures", - "hex", "libp2p", "log", "names", @@ -8243,9 +8237,9 @@ dependencies = [ name = "sc-executor" version = "0.10.0-dev" dependencies = [ + "array-bytes", "criterion", "env_logger", - "hex-literal", "lazy_static", "lru", "num_cpus", @@ -8339,6 +8333,7 @@ name = "sc-finality-grandpa" version = "0.10.0-dev" dependencies = [ "ahash", + "array-bytes", "assert_matches", "async-trait", "dyn-clone", @@ -8346,7 +8341,6 @@ dependencies = [ "fork-tree", "futures", "futures-timer", - "hex", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -8427,8 +8421,8 @@ dependencies = [ name = "sc-keystore" version = "4.0.0-dev" dependencies = [ + "array-bytes", "async-trait", - "hex", "parking_lot 0.12.1", "serde_json", "sp-application-crypto", @@ -8442,6 +8436,7 @@ dependencies = [ name = "sc-network" version = "0.10.0-dev" dependencies = [ + "array-bytes", "assert_matches", "async-std", "async-trait", @@ -8454,7 +8449,6 @@ dependencies = [ "fork-tree", "futures", "futures-timer", - "hex", "ip_network", "libp2p", "linked-hash-map", @@ -8565,8 +8559,8 @@ dependencies = [ name = "sc-network-light" version = "0.10.0-dev" dependencies = [ + "array-bytes", "futures", - "hex", "libp2p", "log", "parity-scale-codec", @@ -8585,9 +8579,9 @@ dependencies = [ name = "sc-network-sync" version = "0.10.0-dev" dependencies = [ + "array-bytes", "fork-tree", "futures", - "hex", "libp2p", "log", "lru", @@ -8647,11 +8641,11 @@ dependencies = [ name = "sc-offchain" version = "4.0.0-dev" dependencies = [ + "array-bytes", "bytes", "fnv", "futures", "futures-timer", - "hex", "hyper", "hyper-rustls", "lazy_static", @@ -8875,10 +8869,9 @@ dependencies = [ name = "sc-service-test" version = "2.0.0" dependencies = [ + "array-bytes", "fdlimit", "futures", - "hex", - "hex-literal", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -9019,11 +9012,11 @@ dependencies = [ name = "sc-transaction-pool" version = "4.0.0-dev" dependencies = [ + "array-bytes", "assert_matches", "criterion", "futures", "futures-timer", - "hex", "linked-hash-map", "log", "parity-scale-codec", @@ -9761,6 +9754,7 @@ dependencies = [ name = "sp-core" version = "6.0.0" dependencies = [ + "array-bytes", "base58", "bitflags", "blake2", @@ -9771,8 +9765,6 @@ dependencies = [ "futures", "hash-db", "hash256-std-hasher", - "hex", - "hex-literal", "impl-serde", "lazy_static", "libsecp256k1", @@ -9953,7 +9945,7 @@ dependencies = [ name = "sp-mmr-primitives" version = "4.0.0-dev" dependencies = [ - "hex-literal", + "array-bytes", "log", "parity-scale-codec", "serde", @@ -10171,9 +10163,9 @@ dependencies = [ name = "sp-state-machine" version = "0.12.0" dependencies = [ + "array-bytes", "assert_matches", "hash-db", - "hex-literal", "log", "num-traits", "parity-scale-codec", @@ -10288,10 +10280,10 @@ name = "sp-trie" version = "6.0.0" dependencies = [ "ahash", + "array-bytes", "criterion", "hash-db", "hashbrown 0.12.3", - "hex-literal", "lazy_static", "lru", "memory-db", @@ -10594,9 +10586,9 @@ dependencies = [ name = "substrate-test-client" version = "2.0.1" dependencies = [ + "array-bytes", "async-trait", "futures", - "hex", "parity-scale-codec", "sc-client-api", "sc-client-db", diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index c6c4b2ea911ec..45ab4939e311c 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -46,7 +46,6 @@ pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", default-fe # Used for runtime benchmarking frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/benchmarking", optional = true } frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system/benchmarking", optional = true } -hex-literal = { version = "0.3.4", optional = true } # Local Dependencies pallet-template = { version = "4.0.0-dev", default-features = false, path = "../pallets/template" } @@ -93,7 +92,6 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", - "hex-literal", "pallet-balances/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-template/runtime-benchmarks", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 878c5d07c8e78..a9c367ae8aa3d 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/paritytech/substrate/" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +array-bytes = "4.1" clap = { version = "3.1.18", features = ["derive"] } log = "0.4.17" node-primitives = { version = "2.0.0", path = "../primitives" } @@ -34,7 +35,6 @@ sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } hash-db = "0.15.2" tempfile = "3.1.0" fs_extra = "1" -hex = "0.4.0" rand = { version = "0.7.2", features = ["small_rng"] } lazy_static = "1.4.0" parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } diff --git a/bin/node/bench/src/generator.rs b/bin/node/bench/src/generator.rs index 863928c719429..76bd3a3240c51 100644 --- a/bin/node/bench/src/generator.rs +++ b/bin/node/bench/src/generator.rs @@ -37,8 +37,10 @@ pub fn generate_trie( let (db, overlay) = { let mut overlay = HashMap::new(); overlay.insert( - hex::decode("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314") - .expect("null key is valid"), + array_bytes::hex2bytes( + "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + ) + .expect("null key is valid"), Some(vec![0]), ); let mut trie = SimpleTrie { db, overlay: &mut overlay }; diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index a435945168e0d..edb434e3c04e3 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -34,12 +34,12 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies +array-bytes = "4.1" clap = { version = "3.1.18", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } jsonrpsee = { version = "0.15.1", features = ["server"] } futures = "0.3.21" -hex-literal = "0.3.4" log = "0.4.17" rand = "0.8" diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 77e2f73dd6e18..8d74f2bde0f44 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -19,7 +19,6 @@ //! Substrate chain configurations. use grandpa_primitives::AuthorityId as GrandpaId; -use hex_literal::hex; use kitchensink_runtime::{ constants::currency::*, wasm_binary_unwrap, AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, Block, CouncilConfig, DemocracyConfig, ElectionsConfig, GrandpaConfig, @@ -98,84 +97,83 @@ fn staging_testnet_config_genesis() -> GenesisConfig { )> = vec![ ( // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy - hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].into(), + array_bytes::hex_n_into_unchecked("9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"), // 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq - hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].into(), + array_bytes::hex_n_into_unchecked("781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"), // 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC - hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"] + array_bytes::hex2array_unchecked("9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332") .unchecked_into(), // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 - hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"] + array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106") .unchecked_into(), // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 - hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"] + array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106") .unchecked_into(), // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 - hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"] + array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106") .unchecked_into(), ), ( // 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2 - hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].into(), + array_bytes::hex_n_into_unchecked("68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"), // 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF - hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].into(), + array_bytes::hex_n_into_unchecked("c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"), // 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE - hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"] + array_bytes::hex2array_unchecked("7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f") .unchecked_into(), // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ - hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"] + array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e") .unchecked_into(), // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ - hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"] + array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e") .unchecked_into(), // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ - hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"] + array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e") .unchecked_into(), ), ( // 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp - hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].into(), + array_bytes::hex_n_into_unchecked("547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"), // 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9 - hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].into(), + array_bytes::hex_n_into_unchecked("9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"), // 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d - hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"] + array_bytes::hex2array_unchecked("5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440") .unchecked_into(), // 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH - hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"] + array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a") .unchecked_into(), // 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH - hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"] + array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a") .unchecked_into(), // 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH - hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"] + array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a") .unchecked_into(), ), ( // 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9 - hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].into(), + array_bytes::hex_n_into_unchecked("f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"), // 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn - hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].into(), + array_bytes::hex_n_into_unchecked("66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"), // 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4 - hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"] + array_bytes::hex2array_unchecked("3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef") .unchecked_into(), // 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x - hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"] + array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378") .unchecked_into(), // 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x - hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"] + array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378") .unchecked_into(), // 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x - hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"] + array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378") .unchecked_into(), ), ]; // generated with secret: subkey inspect "$secret"/fir - let root_key: AccountId = hex![ + let root_key: AccountId = array_bytes::hex_n_into_unchecked( // 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo - "9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809" - ] - .into(); + "9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809", + ); let endowed_accounts: Vec = vec![root_key.clone()]; diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 6a81c16780240..d52b1aaccfcfa 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -21,7 +21,6 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } static_assertions = "1.1.0" -hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } # primitives @@ -252,7 +251,6 @@ runtime-benchmarks = [ "pallet-vesting/runtime-benchmarks", "pallet-whitelist/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", - "hex-literal", ] try-runtime = [ "frame-try-runtime", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 5cc2952e26ba5..47a3be859cbbb 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -9,12 +9,12 @@ description = "BEEFY Client gadget for substrate" homepage = "https://substrate.io" [dependencies] +array-bytes = "4.1" async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } fnv = "1.0.6" futures = "0.3" futures-timer = "3.0.1" -hex = "0.4.2" log = "0.4" parking_lot = "0.12.1" thiserror = "1.0" diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index cdb7fca10320d..41eeec43d64bd 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -69,9 +69,10 @@ pub(crate) mod beefy_protocol_name { genesis_hash: &Hash, chain_spec: &Box, ) -> ProtocolName { + let genesis_hash = genesis_hash.as_ref(); let chain_prefix = match chain_spec.fork_id() { - Some(fork_id) => format!("/{}/{}", hex::encode(genesis_hash), fork_id), - None => format!("/{}", hex::encode(genesis_hash)), + Some(fork_id) => format!("/{}/{}", array_bytes::bytes2hex("", genesis_hash), fork_id), + None => format!("/{}", array_bytes::bytes2hex("", genesis_hash)), }; format!("{}{}", chain_prefix, NAME).into() } diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index e0058e5238d6a..26c85592ecb85 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -99,7 +99,7 @@ fn beefy_protocol_name() { // Create protocol name using random genesis hash. let genesis_hash = H256::random(); - let expected = format!("/{}/beefy/1", hex::encode(genesis_hash)); + let expected = format!("/{}/beefy/1", array_bytes::bytes2hex("", genesis_hash.as_ref())); let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); assert_eq!(proto_name.to_string(), expected); diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 50d110d40eabd..e5cd6167596c0 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -13,11 +13,11 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" chrono = "0.4.10" clap = { version = "3.1.18", features = ["derive"] } fdlimit = "0.2.1" futures = "0.3.21" -hex = "0.4.2" libp2p = "0.46.1" log = "0.4.17" names = { version = "0.13.0", default-features = false } diff --git a/client/cli/src/commands/generate_node_key.rs b/client/cli/src/commands/generate_node_key.rs index 6b2f12531458c..3afd99d60a123 100644 --- a/client/cli/src/commands/generate_node_key.rs +++ b/client/cli/src/commands/generate_node_key.rs @@ -57,7 +57,7 @@ impl GenerateNodeKeyCmd { let file_data = if self.bin { secret.as_ref().to_owned() } else { - hex::encode(secret.as_ref()).into_bytes() + array_bytes::bytes2hex("", secret.as_ref()).into_bytes() }; match &self.file { @@ -85,6 +85,6 @@ mod tests { assert!(generate.run().is_ok()); let mut buf = String::new(); assert!(file.read_to_string(&mut buf).is_ok()); - assert!(hex::decode(buf).is_ok()); + assert!(array_bytes::hex2bytes(&buf).is_ok()); } } diff --git a/client/cli/src/commands/inspect_key.rs b/client/cli/src/commands/inspect_key.rs index 14bb059503df9..59f105dc52a5c 100644 --- a/client/cli/src/commands/inspect_key.rs +++ b/client/cli/src/commands/inspect_key.rs @@ -127,7 +127,7 @@ fn expect_public_from_phrase( ) -> Result<(), Error> { let secret_uri = SecretUri::from_str(suri).map_err(|e| format!("{:?}", e))?; let expected_public = if let Some(public) = expect_public.strip_prefix("0x") { - let hex_public = hex::decode(&public) + let hex_public = array_bytes::hex2bytes(public) .map_err(|_| format!("Invalid expected public key hex: `{}`", expect_public))?; Pair::Public::try_from(&hex_public) .map_err(|_| format!("Invalid expected public key: `{}`", expect_public))? @@ -208,7 +208,7 @@ mod tests { .expect("Valid") .0 .public(); - let valid_public_hex = format!("0x{}", hex::encode(valid_public.as_slice())); + let valid_public_hex = array_bytes::bytes2hex("0x", valid_public.as_slice()); let valid_accountid = format!("{}", valid_public.into_account()); // It should fail with the invalid public key @@ -226,7 +226,7 @@ mod tests { .0 .public(); let valid_public_hex_with_password = - format!("0x{}", hex::encode(&valid_public_with_password.as_slice())); + array_bytes::bytes2hex("0x", valid_public_with_password.as_slice()); let valid_accountid_with_password = format!("{}", &valid_public_with_password.into_account()); @@ -248,7 +248,7 @@ mod tests { .0 .public(); let valid_public_hex_with_password_and_derivation = - format!("0x{}", hex::encode(&valid_public_with_password_and_derivation.as_slice())); + array_bytes::bytes2hex("0x", valid_public_with_password_and_derivation.as_slice()); // They should still be valid, because we check the base secret key. check_cmd(&seed_with_password_and_derivation, &valid_public_hex_with_password, true); diff --git a/client/cli/src/commands/inspect_node_key.rs b/client/cli/src/commands/inspect_node_key.rs index e1617c1d085df..a9dff9c760d33 100644 --- a/client/cli/src/commands/inspect_node_key.rs +++ b/client/cli/src/commands/inspect_node_key.rs @@ -66,7 +66,8 @@ impl InspectNodeKeyCmd { if !self.bin { // With hex input, give to the user a bit of tolerance about whitespaces let keyhex = String::from_utf8_lossy(&file_data); - file_data = hex::decode(keyhex.trim()).map_err(|_| "failed to decode secret as hex")?; + file_data = array_bytes::hex2bytes(keyhex.trim()) + .map_err(|_| "failed to decode secret as hex")?; } let secret = diff --git a/client/cli/src/commands/sign.rs b/client/cli/src/commands/sign.rs index e0a5fce353ef4..7d93390326717 100644 --- a/client/cli/src/commands/sign.rs +++ b/client/cli/src/commands/sign.rs @@ -70,7 +70,7 @@ fn sign( message: Vec, ) -> error::Result { let pair = utils::pair_from_suri::

(suri, password)?; - Ok(hex::encode(pair.sign(&message))) + Ok(array_bytes::bytes2hex("", pair.sign(&message).as_ref())) } #[cfg(test)] diff --git a/client/cli/src/commands/utils.rs b/client/cli/src/commands/utils.rs index 95849065471b4..1ce2b23221691 100644 --- a/client/cli/src/commands/utils.rs +++ b/client/cli/src/commands/utils.rs @@ -203,7 +203,7 @@ where Pair: sp_core::Pair, Pair::Public: Into, { - let public = decode_hex(public_str)?; + let public = array_bytes::hex2bytes(public_str)?; let public_key = Pair::Public::try_from(&public) .map_err(|_| "Failed to construct public key from given hex")?; @@ -273,26 +273,17 @@ where format!("0x{}", HexDisplay::from(&public_key.into().into_account().as_ref())) } -/// helper method for decoding hex -pub fn decode_hex>(message: T) -> Result, Error> { - let mut message = message.as_ref(); - if message[..2] == [b'0', b'x'] { - message = &message[2..] - } - Ok(hex::decode(message)?) -} - /// checks if message is Some, otherwise reads message from stdin and optionally decodes hex pub fn read_message(msg: Option<&String>, should_decode: bool) -> Result, Error> { let mut message = vec![]; match msg { Some(m) => { - message = decode_hex(m)?; + message = array_bytes::hex2bytes(m.as_str())?; }, None => { std::io::stdin().lock().read_to_end(&mut message)?; if should_decode { - message = decode_hex(&message)?; + message = array_bytes::hex2bytes(array_bytes::hex_bytes2hex_str(&message)?)?; } }, } diff --git a/client/cli/src/commands/vanity.rs b/client/cli/src/commands/vanity.rs index 6a1bf77f6c8b0..289dc1705c3a3 100644 --- a/client/cli/src/commands/vanity.rs +++ b/client/cli/src/commands/vanity.rs @@ -178,7 +178,7 @@ mod tests { #[test] fn test_generation_with_single_char() { let seed = generate_key::("ab", default_ss58_version()).unwrap(); - assert!(sr25519::Pair::from_seed_slice(&hex::decode(&seed[2..]).unwrap()) + assert!(sr25519::Pair::from_seed_slice(&array_bytes::hex2bytes_unchecked(&seed)) .unwrap() .public() .to_ss58check() @@ -190,7 +190,7 @@ mod tests { let seed = generate_key::("ab", Ss58AddressFormatRegistry::PolkadotAccount.into()) .unwrap(); - assert!(sr25519::Pair::from_seed_slice(&hex::decode(&seed[2..]).unwrap()) + assert!(sr25519::Pair::from_seed_slice(&array_bytes::hex2bytes_unchecked(&seed)) .unwrap() .public() .to_ss58check_with_version(Ss58AddressFormatRegistry::PolkadotAccount.into()) diff --git a/client/cli/src/commands/verify.rs b/client/cli/src/commands/verify.rs index b004a948a7a48..6389cdbde2c17 100644 --- a/client/cli/src/commands/verify.rs +++ b/client/cli/src/commands/verify.rs @@ -55,7 +55,7 @@ impl VerifyCmd { /// Run the command pub fn run(&self) -> error::Result<()> { let message = utils::read_message(self.message.as_ref(), self.hex)?; - let sig_data = utils::decode_hex(&self.sig)?; + let sig_data = array_bytes::hex2bytes(&self.sig)?; let uri = utils::read_uri(self.uri.as_ref())?; let uri = if let Some(uri) = uri.strip_prefix("0x") { uri } else { &uri }; @@ -71,7 +71,7 @@ where let signature = Pair::Signature::try_from(&sig_data).map_err(|_| error::Error::SignatureFormatInvalid)?; - let pubkey = if let Ok(pubkey_vec) = hex::decode(uri) { + let pubkey = if let Ok(pubkey_vec) = array_bytes::hex2bytes(uri) { Pair::Public::from_slice(pubkey_vec.as_slice()) .map_err(|_| error::Error::KeyFormatInvalid)? } else { diff --git a/client/cli/src/error.rs b/client/cli/src/error.rs index f38a95e0115f1..a0f843e73bf53 100644 --- a/client/cli/src/error.rs +++ b/client/cli/src/error.rs @@ -69,8 +69,8 @@ pub enum Error { #[error("Key storage issue encountered")] KeyStorage(#[from] sc_keystore::Error), - #[error("Invalid hexadecimal string data")] - HexDataConversion(#[from] hex::FromHexError), + #[error("Invalid hexadecimal string data, {0:?}")] + HexDataConversion(array_bytes::Error), /// Application specific error chain sequence forwarder. #[error(transparent)] @@ -97,3 +97,9 @@ impl From for Error { Error::InvalidUri(e) } } + +impl From for Error { + fn from(e: array_bytes::Error) -> Error { + Error::HexDataConversion(e) + } +} diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index d51b6143ed393..00ce9e8027aab 100644 --- a/client/cli/src/params/node_key_params.rs +++ b/client/cli/src/params/node_key_params.rs @@ -176,7 +176,7 @@ mod tests { let file = tmp.path().join("mysecret").to_path_buf(); let key = ed25519::SecretKey::generate(); - fs::write(&file, hex::encode(key.as_ref())).expect("Writes secret key"); + fs::write(&file, array_bytes::bytes2hex("", key.as_ref())).expect("Writes secret key"); check_key(file.clone(), &key); fs::write(&file, &key).expect("Writes secret key"); diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 2fe7e822b36c3..264db0e89b1c8 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -37,8 +37,8 @@ sp-version = { version = "5.0.0", path = "../../primitives/version" } sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } [dev-dependencies] +array-bytes = "4.1" wat = "1.0" -hex-literal = "0.3.4" sc-runtime-test = { version = "2.0.0", path = "runtime-test" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 25280f856f2a5..9ffb7f502f5c6 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -21,7 +21,6 @@ mod linux; mod sandbox; use codec::{Decode, Encode}; -use hex_literal::hex; use sc_executor_common::{error::Error, runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; use sc_runtime_test::wasm_binary_unwrap; use sp_core::{ @@ -391,16 +390,18 @@ fn sha2_256_should_work(wasm_method: WasmExecutionMethod) { let mut ext = ext.ext(); assert_eq!( call_in_wasm("test_sha2_256", &[0], wasm_method, &mut ext,).unwrap(), - hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") - .to_vec() - .encode(), + array_bytes::hex2bytes_unchecked( + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ) + .encode(), ); assert_eq!( call_in_wasm("test_sha2_256", &b"Hello world!".to_vec().encode(), wasm_method, &mut ext,) .unwrap(), - hex!("c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a") - .to_vec() - .encode(), + array_bytes::hex2bytes_unchecked( + "c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a" + ) + .encode(), ); } @@ -410,16 +411,18 @@ fn twox_256_should_work(wasm_method: WasmExecutionMethod) { let mut ext = ext.ext(); assert_eq!( call_in_wasm("test_twox_256", &[0], wasm_method, &mut ext,).unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a") - .to_vec() - .encode(), + array_bytes::hex2bytes_unchecked( + "99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a" + ) + .encode(), ); assert_eq!( call_in_wasm("test_twox_256", &b"Hello world!".to_vec().encode(), wasm_method, &mut ext,) .unwrap(), - hex!("b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74") - .to_vec() - .encode(), + array_bytes::hex2bytes_unchecked( + "b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74" + ) + .encode(), ); } @@ -429,12 +432,12 @@ fn twox_128_should_work(wasm_method: WasmExecutionMethod) { let mut ext = ext.ext(); assert_eq!( call_in_wasm("test_twox_128", &[0], wasm_method, &mut ext,).unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd5").to_vec().encode(), + array_bytes::hex2bytes_unchecked("99e9d85137db46ef4bbea33613baafd5").encode(), ); assert_eq!( call_in_wasm("test_twox_128", &b"Hello world!".to_vec().encode(), wasm_method, &mut ext,) .unwrap(), - hex!("b27dfd7f223f177f2a13647b533599af").to_vec().encode(), + array_bytes::hex2bytes_unchecked("b27dfd7f223f177f2a13647b533599af").encode(), ); } @@ -704,7 +707,7 @@ fn parallel_execution(wasm_method: WasmExecutionMethod) { &[0], ) .unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd5").to_vec().encode(), + array_bytes::hex2bytes_unchecked("99e9d85137db46ef4bbea33613baafd5").encode() ); }) }) diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 5950b108ca4ab..83c6051946aff 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ahash = "0.7.6" +array-bytes = "4.1" async-trait = "0.1.57" dyn-clone = "1.0" finality-grandpa = { version = "0.16.0", features = ["derive-codec"] } futures = "0.3.21" futures-timer = "3.0.1" -hex = "0.4.2" log = "0.4.17" parity-scale-codec = { version = "3.0.0", features = ["derive"] } parking_lot = "0.12.1" diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index d211c10ae62be..12cb2601f4c26 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -83,9 +83,10 @@ pub mod grandpa_protocol_name { genesis_hash: &Hash, chain_spec: &Box, ) -> ProtocolName { + let genesis_hash = genesis_hash.as_ref(); let chain_prefix = match chain_spec.fork_id() { - Some(fork_id) => format!("/{}/{}", hex::encode(genesis_hash), fork_id), - None => format!("/{}", hex::encode(genesis_hash)), + Some(fork_id) => format!("/{}/{}", array_bytes::bytes2hex("", genesis_hash), fork_id), + None => format!("/{}", array_bytes::bytes2hex("", genesis_hash)), }; format!("{}{}", chain_prefix, NAME).into() } diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index 1f607e8d68c02..b73f6cdecdd4f 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -646,7 +646,7 @@ fn grandpa_protocol_name() { // Create protocol name using random genesis hash. let genesis_hash = sp_core::H256::random(); - let expected = format!("/{}/grandpa/1", hex::encode(genesis_hash)); + let expected = format!("/{}/grandpa/1", array_bytes::bytes2hex("", genesis_hash.as_ref())); let proto_name = grandpa_protocol_name::standard_name(&genesis_hash, &chain_spec); assert_eq!(proto_name.to_string(), expected); diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 9b7afba759c60..ff963f9d446f6 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -14,8 +14,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" async-trait = "0.1.57" -hex = "0.4.0" parking_lot = "0.12.1" serde_json = "1.0.85" thiserror = "1.0" diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 19be6715ffe3f..54ff6a5b164a8 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -512,8 +512,8 @@ impl KeystoreInner { /// Returns `None` if the keystore only exists in-memory and there isn't any path to provide. fn key_file_path(&self, public: &[u8], key_type: KeyTypeId) -> Option { let mut buf = self.path.as_ref()?.clone(); - let key_type = hex::encode(key_type.0); - let key = hex::encode(public); + let key_type = array_bytes::bytes2hex("", &key_type.0); + let key = array_bytes::bytes2hex("", public); buf.push(key_type + key.as_str()); Some(buf) } @@ -534,7 +534,7 @@ impl KeystoreInner { // skip directories and non-unicode file names (hex is unicode) if let Some(name) = path.file_name().and_then(|n| n.to_str()) { - match hex::decode(name) { + match array_bytes::hex2bytes(name) { Ok(ref hex) if hex.len() > 4 => { if hex[0..4] != id.0 { continue @@ -739,7 +739,7 @@ mod tests { let temp_dir = TempDir::new().unwrap(); let store = LocalKeystore::open(temp_dir.path(), None).unwrap(); - let file_name = temp_dir.path().join(hex::encode(&SR25519.0[..2])); + let file_name = temp_dir.path().join(array_bytes::bytes2hex("", &SR25519.0[..2])); fs::write(file_name, "test").expect("Invalid file is written"); assert!(SyncCryptoStore::sr25519_public_keys(&store, SR25519).is_empty()); diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index ae115220d6843..e96749df40aa2 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -14,6 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" async-trait = "0.1" asynchronous-codec = "0.6" bitflags = "1.3.2" @@ -24,7 +25,6 @@ either = "1.5.3" fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" -hex = "0.4.0" ip_network = "0.4.1" libp2p = "0.46.1" linked_hash_set = "0.1.3" diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index c1a0fb4759320..c2a77c3b577ba 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -17,11 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.10" [dependencies] +array-bytes = "4.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -hex = "0.4.0" libp2p = "0.46.1" log = "0.4.16" prost = "0.10" diff --git a/client/network/light/src/light_client_requests.rs b/client/network/light/src/light_client_requests.rs index b58426cf15992..61b549d0f0984 100644 --- a/client/network/light/src/light_client_requests.rs +++ b/client/network/light/src/light_client_requests.rs @@ -27,10 +27,11 @@ use std::time::Duration; /// Generate the light client protocol name from the genesis hash and fork id. fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + let genesis_hash = genesis_hash.as_ref(); if let Some(fork_id) = fork_id { - format!("/{}/{}/light/2", hex::encode(genesis_hash), fork_id) + format!("/{}/{}/light/2", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { - format!("/{}/light/2", hex::encode(genesis_hash)) + format!("/{}/light/2", array_bytes::bytes2hex("", genesis_hash)) } } diff --git a/client/network/src/config.rs b/client/network/src/config.rs index d7ca8b48a7c88..202a628884d79 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -585,7 +585,7 @@ impl NodeKeyConfig { f, |mut b| match String::from_utf8(b.to_vec()).ok().and_then(|s| { if s.len() == 64 { - hex::decode(&s).ok() + array_bytes::hex2bytes(&s).ok() } else { None } diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 17187f2d63c1c..c7a3cf4b2160f 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -369,10 +369,15 @@ where let block_announces_protocol = { let genesis_hash = chain.hash(0u32.into()).ok().flatten().expect("Genesis block exists; qed"); + let genesis_hash = genesis_hash.as_ref(); if let Some(fork_id) = fork_id { - format!("/{}/{}/block-announces/1", hex::encode(genesis_hash), fork_id) + format!( + "/{}/{}/block-announces/1", + array_bytes::bytes2hex("", genesis_hash), + fork_id + ) } else { - format!("/{}/block-announces/1", hex::encode(genesis_hash)) + format!("/{}/block-announces/1", array_bytes::bytes2hex("", genesis_hash)) } }; diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 1cf532f33ddc6..da4547aefeab3 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -143,10 +143,11 @@ impl TransactionsHandlerPrototype { genesis_hash: Hash, fork_id: Option, ) -> Self { + let genesis_hash = genesis_hash.as_ref(); let protocol_name = if let Some(fork_id) = fork_id { - format!("/{}/{}/transactions/1", hex::encode(genesis_hash), fork_id) + format!("/{}/{}/transactions/1", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { - format!("/{}/transactions/1", hex::encode(genesis_hash)) + format!("/{}/transactions/1", array_bytes::bytes2hex("", genesis_hash)) }; let legacy_protocol_name = format!("/{}/transactions/1", protocol_id.as_ref()); diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 7c8f8adafd214..269214aeff3f7 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -17,11 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.10" [dependencies] +array-bytes = "4.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -hex = "0.4.0" libp2p = "0.46.1" log = "0.4.17" lru = "0.7.5" diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index cc61be2b57256..a6b39591e7945 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -80,10 +80,11 @@ pub fn generate_protocol_config>( /// Generate the block protocol name from the genesis hash and fork id. fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + let genesis_hash = genesis_hash.as_ref(); if let Some(fork_id) = fork_id { - format!("/{}/{}/sync/2", hex::encode(genesis_hash), fork_id) + format!("/{}/{}/sync/2", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { - format!("/{}/sync/2", hex::encode(genesis_hash)) + format!("/{}/sync/2", array_bytes::bytes2hex("", genesis_hash)) } } diff --git a/client/network/sync/src/state_request_handler.rs b/client/network/sync/src/state_request_handler.rs index 6cf6482a44f8b..abbbcad2e378f 100644 --- a/client/network/sync/src/state_request_handler.rs +++ b/client/network/sync/src/state_request_handler.rs @@ -69,10 +69,11 @@ pub fn generate_protocol_config>( /// Generate the state protocol name from the genesis hash and fork id. fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + let genesis_hash = genesis_hash.as_ref(); if let Some(fork_id) = fork_id { - format!("/{}/{}/state/2", hex::encode(genesis_hash), fork_id) + format!("/{}/{}/state/2", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { - format!("/{}/state/2", hex::encode(genesis_hash)) + format!("/{}/state/2", array_bytes::bytes2hex("", genesis_hash)) } } diff --git a/client/network/sync/src/warp_request_handler.rs b/client/network/sync/src/warp_request_handler.rs index 394bc68449099..e675bf45cad91 100644 --- a/client/network/sync/src/warp_request_handler.rs +++ b/client/network/sync/src/warp_request_handler.rs @@ -54,10 +54,11 @@ pub fn generate_request_response_config>( /// Generate the grandpa warp sync protocol name from the genesi hash and fork id. fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + let genesis_hash = genesis_hash.as_ref(); if let Some(fork_id) = fork_id { - format!("/{}/{}/sync/warp", hex::encode(genesis_hash), fork_id) + format!("/{}/{}/sync/warp", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { - format!("/{}/sync/warp", hex::encode(genesis_hash)) + format!("/{}/sync/warp", array_bytes::bytes2hex("", genesis_hash)) } } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index ff97f29961155..5ebb21406efbf 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -13,12 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" bytes = "1.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" -hex = "0.4" hyper = { version = "0.14.16", features = ["stream", "http2"] } hyper-rustls = { version = "0.23.0", features = ["http2"] } libp2p = { version = "0.46.1", default-features = false } diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 6d6c52c989c34..7d3dd8302f343 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -79,8 +79,8 @@ impl offchain::DbExternalities for Db { tracing::debug!( target: "offchain-worker::storage", ?kind, - key = ?hex::encode(key), - value = ?hex::encode(value), + key = ?array_bytes::bytes2hex("", key), + value = ?array_bytes::bytes2hex("", value), "Write", ); match kind { @@ -93,7 +93,7 @@ impl offchain::DbExternalities for Db { tracing::debug!( target: "offchain-worker::storage", ?kind, - key = ?hex::encode(key), + key = ?array_bytes::bytes2hex("", key), "Clear", ); match kind { @@ -112,9 +112,9 @@ impl offchain::DbExternalities for Db { tracing::debug!( target: "offchain-worker::storage", ?kind, - key = ?hex::encode(key), - new_value = ?hex::encode(new_value), - old_value = ?old_value.as_ref().map(hex::encode), + key = ?array_bytes::bytes2hex("", key), + new_value = ?array_bytes::bytes2hex("", new_value), + old_value = ?old_value.as_ref().map(|s| array_bytes::bytes2hex("", s)), "CAS", ); match kind { @@ -132,8 +132,8 @@ impl offchain::DbExternalities for Db { tracing::debug!( target: "offchain-worker::storage", ?kind, - key = ?hex::encode(key), - result = ?result.as_ref().map(hex::encode), + key = ?array_bytes::bytes2hex("", key), + result = ?result.as_ref().map(|s| array_bytes::bytes2hex("", s)), "Read", ); result diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 92df5381c202b..1f934a6e5355f 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -12,10 +12,9 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" fdlimit = "0.2.1" futures = "0.3.21" -hex = "0.4" -hex-literal = "0.3.4" log = "0.4.17" parity-scale-codec = "3.0.0" parking_lot = "0.12.1" diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index f02b1321d2922..cb648664b4006 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -17,7 +17,6 @@ // along with this program. If not, see . use futures::executor::block_on; -use hex_literal::hex; use parity_scale_codec::{Decode, Encode, Joiner}; use sc_block_builder::BlockBuilderProvider; use sc_client_api::{ @@ -155,7 +154,9 @@ fn block1(genesis_hash: Hash, backend: &InMemoryBackend) -> (Vec = client @@ -1604,25 +1605,29 @@ fn storage_keys_iter_prefix_and_start_key_works() { .collect(); assert_eq!( res, - [child_root.clone(), hex!("3a636f6465").to_vec(), hex!("3a686561707061676573").to_vec(),] + [ + child_root.clone(), + array_bytes::hex2bytes_unchecked("3a636f6465"), + array_bytes::hex2bytes_unchecked("3a686561707061676573"), + ] ); let res: Vec<_> = client .storage_keys_iter( &BlockId::Number(0), Some(&prefix), - Some(&StorageKey(hex!("3a636f6465").to_vec())), + Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))), ) .unwrap() .map(|x| x.0) .collect(); - assert_eq!(res, [hex!("3a686561707061676573").to_vec()]); + assert_eq!(res, [array_bytes::hex2bytes_unchecked("3a686561707061676573")]); let res: Vec<_> = client .storage_keys_iter( &BlockId::Number(0), Some(&prefix), - Some(&StorageKey(hex!("3a686561707061676573").to_vec())), + Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a686561707061676573"))), ) .unwrap() .map(|x| x.0) @@ -1653,13 +1658,13 @@ fn storage_keys_iter_prefix_and_start_key_works() { fn storage_keys_iter_works() { let client = substrate_test_runtime_client::new(); - let prefix = StorageKey(hex!("").to_vec()); + let prefix = StorageKey(array_bytes::hex2bytes_unchecked("")); let res: Vec<_> = client .storage_keys_iter(&BlockId::Number(0), Some(&prefix), None) .unwrap() .take(8) - .map(|x| hex::encode(&x.0)) + .map(|x| array_bytes::bytes2hex("", &x.0)) .collect(); assert_eq!( res, @@ -1679,11 +1684,11 @@ fn storage_keys_iter_works() { .storage_keys_iter( &BlockId::Number(0), Some(&prefix), - Some(&StorageKey(hex!("3a636f6465").to_vec())), + Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))), ) .unwrap() .take(7) - .map(|x| hex::encode(&x.0)) + .map(|x| array_bytes::bytes2hex("", &x.0)) .collect(); assert_eq!( res, @@ -1702,13 +1707,13 @@ fn storage_keys_iter_works() { .storage_keys_iter( &BlockId::Number(0), Some(&prefix), - Some(&StorageKey( - hex!("79c07e2b1d2e2abfd4855b936617eeff5e0621c4869aa60c02be9adcc98a0d1d").to_vec(), - )), + Some(&StorageKey(array_bytes::hex2bytes_unchecked( + "79c07e2b1d2e2abfd4855b936617eeff5e0621c4869aa60c02be9adcc98a0d1d", + ))), ) .unwrap() .take(5) - .map(|x| hex::encode(x.0)) + .map(|x| array_bytes::bytes2hex("", &x.0)) .collect(); assert_eq!( res, diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 9aa05694b6619..cd7cb297e8c4a 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -34,9 +34,9 @@ sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } [dev-dependencies] +array-bytes = "4.1" assert_matches = "1.3.0" criterion = "0.3" -hex = "0.4" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 17c2cfa8a1e06..f04a27cf81e1d 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -880,7 +880,7 @@ fn should_not_accept_old_signatures() { // generated with schnorrkel 0.1.1 from `_bytes` let old_singature = sp_core::sr25519::Signature::try_from( - &hex::decode( + &array_bytes::hex2bytes( "c427eb672e8c441c86d31f1a81b22b43102058e9ce237cabe9897ea5099ffd426\ cd1c6a1f4f2869c3df57901d36bedcb295657adb3a4355add86ed234eb83108", ) diff --git a/frame/alliance/Cargo.toml b/frame/alliance/Cargo.toml index 24e047091009b..399822a2215f5 100644 --- a/frame/alliance/Cargo.toml +++ b/frame/alliance/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -hex = { version = "0.4", default-features = false, features = ["alloc"], optional = true } +array-bytes = { version = "4.1", optional = true } sha2 = { version = "0.10.1", default-features = false, optional = true } log = { version = "0.4.14", default-features = false } @@ -33,7 +33,7 @@ pallet-identity = { version = "4.0.0-dev", path = "../identity", default-feature pallet-collective = { version = "4.0.0-dev", path = "../collective", default-features = false, optional = true } [dev-dependencies] -hex-literal = "0.3.1" +array-bytes = "4.1" sha2 = "0.10.1" pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-collective = { version = "4.0.0-dev", path = "../collective" } @@ -55,7 +55,7 @@ std = [ "pallet-identity/std", ] runtime-benchmarks = [ - "hex", + "array-bytes", "sha2", "frame-benchmarking/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index e8366943c85b0..62fabd387a167 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -9,8 +9,8 @@ repository = "https://github.com/paritytech/substrate" homepage = "https://substrate.io" [dependencies] +array-bytes = { version = "4.1", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex = { version = "0.4", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } @@ -27,18 +27,18 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -hex-literal = "0.3" +array-bytes = "4.1" sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } [features] default = ["std"] std = [ + "array-bytes", "beefy-merkle-tree/std", "beefy-primitives/std", "codec/std", "frame-support/std", "frame-system/std", - "hex", "log/std", "pallet-beefy/std", "pallet-mmr/std", diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/frame/beefy-mmr/primitives/Cargo.toml index f30a418def042..1aa2573c7f680 100644 --- a/frame/beefy-mmr/primitives/Cargo.toml +++ b/frame/beefy-mmr/primitives/Cargo.toml @@ -9,7 +9,7 @@ description = "A no-std/Substrate compatible library to construct binary merkle homepage = "https://substrate.io" [dependencies] -hex = { version = "0.4", default-features = false, optional = true } +array-bytes = { version = "4.1", optional = true } log = { version = "0.4", default-features = false, optional = true } tiny-keccak = { version = "2.0.2", features = ["keccak"], optional = true } @@ -17,12 +17,11 @@ beefy-primitives = { version = "4.0.0-dev", default-features = false, path = ".. sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } [dev-dependencies] +array-bytes = "4.1" env_logger = "0.9" -hex = "0.4" -hex-literal = "0.3" [features] -debug = ["hex", "hex/std", "log"] +debug = ["array-bytes", "log"] default = ["debug", "keccak", "std"] keccak = ["tiny-keccak"] std = [ diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/frame/beefy-mmr/primitives/src/lib.rs index 664fd18199dd0..38831d7914715 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/frame/beefy-mmr/primitives/src/lib.rs @@ -235,7 +235,11 @@ where #[cfg(feature = "debug")] log::debug!( "[merkle_proof] Proof: {:?}", - collect_proof.proof.iter().map(hex::encode).collect::>() + collect_proof + .proof + .iter() + .map(|s| array_bytes::bytes2hex("", s)) + .collect::>() ); MerkleProof { root, proof: collect_proof.proof, number_of_leaves, leaf_index, leaf } @@ -308,10 +312,10 @@ where #[cfg(feature = "debug")] log::debug!( "[verify_proof]: (a, b) {:?}, {:?} => {:?} ({:?}) hash", - hex::encode(a), - hex::encode(b), - hex::encode(hash), - hex::encode(combined) + array_bytes::bytes2hex("", &a), + array_bytes::bytes2hex("", &b), + array_bytes::bytes2hex("", &hash), + array_bytes::bytes2hex("", &combined) ); position /= 2; width = ((width - 1) / 2) + 1; @@ -348,7 +352,11 @@ where visitor.visit(index, &a, &b); #[cfg(feature = "debug")] - log::debug!(" {:?}\n {:?}", a.as_ref().map(hex::encode), b.as_ref().map(hex::encode)); + log::debug!( + " {:?}\n {:?}", + a.as_ref().map(|s| array_bytes::bytes2hex("", s)), + b.as_ref().map(|s| array_bytes::bytes2hex("", s)) + ); index += 2; match (a, b) { @@ -369,7 +377,7 @@ where #[cfg(feature = "debug")] log::debug!( "[merkelize_row] Next: {:?}", - next.iter().map(hex::encode).collect::>() + next.iter().map(|s| array_bytes::bytes2hex("", s)).collect::>() ); return Err(next) }, @@ -395,7 +403,6 @@ sp_api::decl_runtime_apis! { #[cfg(test)] mod tests { use super::*; - use hex_literal::hex; #[test] fn should_generate_empty_root() { @@ -408,7 +415,7 @@ mod tests { // then assert_eq!( - hex::encode(&out), + array_bytes::bytes2hex("", &out), "0000000000000000000000000000000000000000000000000000000000000000" ); } @@ -417,14 +424,16 @@ mod tests { fn should_generate_single_root() { // given let _ = env_logger::try_init(); - let data = vec![hex!("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b")]; + let data = vec![array_bytes::hex2array_unchecked::<20>( + "E04CC55ebEE1cBCE552f250e85c57B70B2E2625b", + )]; // when let out = merkle_root::(data); // then assert_eq!( - hex::encode(&out), + array_bytes::bytes2hex("", &out), "aeb47a269393297f4b0a3c9c9cfd00c7a4195255274cf39d83dabc2fcc9ff3d7" ); } @@ -434,8 +443,8 @@ mod tests { // given let _ = env_logger::try_init(); let data = vec![ - hex!("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b"), - hex!("25451A4de12dcCc2D166922fA938E900fCc4ED24"), + array_bytes::hex2array_unchecked::<20>("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b"), + array_bytes::hex2array_unchecked::<20>("25451A4de12dcCc2D166922fA938E900fCc4ED24"), ]; // when @@ -443,7 +452,7 @@ mod tests { // then assert_eq!( - hex::encode(&out), + array_bytes::bytes2hex("", &out), "697ea2a8fe5b03468548a7a413424a6292ab44a82a6f5cc594c3fa7dda7ce402" ); } @@ -452,7 +461,7 @@ mod tests { fn should_generate_root_complex() { let _ = env_logger::try_init(); let test = |root, data| { - assert_eq!(hex::encode(&merkle_root::(data)), root); + assert_eq!(array_bytes::bytes2hex("", &merkle_root::(data)), root); }; test( @@ -511,11 +520,19 @@ mod tests { )); // then - assert_eq!(hex::encode(proof0.root), hex::encode(proof1.root)); - assert_eq!(hex::encode(proof2.root), hex::encode(proof1.root)); + assert_eq!( + array_bytes::bytes2hex("", &proof0.root), + array_bytes::bytes2hex("", &proof1.root) + ); + assert_eq!( + array_bytes::bytes2hex("", &proof2.root), + array_bytes::bytes2hex("", &proof1.root) + ); assert!(!verify_proof::( - &hex!("fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239"), + &array_bytes::hex2array_unchecked( + "fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239" + ), proof0.proof, data.len(), proof0.leaf_index, @@ -779,17 +796,19 @@ mod tests { "0xA4cDc98593CE52d01Fe5Ca47CB3dA5320e0D7592", "0xc26B34D375533fFc4c5276282Fa5D660F3d8cbcB", ]; - let root = hex!("72b0acd7c302a84f1f6b6cefe0ba7194b7398afb440e1b44a9dbbe270394ca53"); + let root = array_bytes::hex2array_unchecked( + "72b0acd7c302a84f1f6b6cefe0ba7194b7398afb440e1b44a9dbbe270394ca53", + ); let data = addresses .into_iter() - .map(|address| hex::decode(&address[2..]).unwrap()) + .map(|address| array_bytes::hex2bytes_unchecked(&address)) .collect::>(); for l in 0..data.len() { // when let proof = merkle_proof::(data.clone(), l); - assert_eq!(hex::encode(&proof.root), hex::encode(&root)); + assert_eq!(array_bytes::bytes2hex("", &proof.root), array_bytes::bytes2hex("", &root)); assert_eq!(proof.leaf_index, l); assert_eq!(&proof.leaf, &data[l]); @@ -810,14 +829,25 @@ mod tests { MerkleProof { root, proof: vec![ - hex!("340bcb1d49b2d82802ddbcf5b85043edb3427b65d09d7f758fbc76932ad2da2f"), - hex!("ba0580e5bd530bc93d61276df7969fb5b4ae8f1864b4a28c280249575198ff1f"), - hex!("d02609d2bbdb28aa25f58b85afec937d5a4c85d37925bce6d0cf802f9d76ba79"), - hex!("ae3f8991955ed884613b0a5f40295902eea0e0abe5858fc520b72959bc016d4e"), + array_bytes::hex2array_unchecked( + "340bcb1d49b2d82802ddbcf5b85043edb3427b65d09d7f758fbc76932ad2da2f" + ), + array_bytes::hex2array_unchecked( + "ba0580e5bd530bc93d61276df7969fb5b4ae8f1864b4a28c280249575198ff1f" + ), + array_bytes::hex2array_unchecked( + "d02609d2bbdb28aa25f58b85afec937d5a4c85d37925bce6d0cf802f9d76ba79" + ), + array_bytes::hex2array_unchecked( + "ae3f8991955ed884613b0a5f40295902eea0e0abe5858fc520b72959bc016d4e" + ), ], number_of_leaves: data.len(), leaf_index: data.len() - 1, - leaf: hex!("c26B34D375533fFc4c5276282Fa5D660F3d8cbcB").to_vec(), + leaf: array_bytes::hex2array_unchecked::<20>( + "c26B34D375533fFc4c5276282Fa5D660F3d8cbcB" + ) + .to_vec(), } ); } diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index eaa50004ae848..b9851d9eef6cb 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -22,7 +22,6 @@ use beefy_primitives::{ ValidatorSet, }; use codec::{Decode, Encode}; -use hex_literal::hex; use sp_core::H256; use sp_io::TestExternalities; @@ -70,9 +69,9 @@ fn should_contain_mmr_digest() { beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap() )), - beefy_log(ConsensusLog::MmrRoot( - hex!("95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc").into() - )) + beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( + "95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc" + ))) ] ); @@ -85,15 +84,15 @@ fn should_contain_mmr_digest() { beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap() )), - beefy_log(ConsensusLog::MmrRoot( - hex!("95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc").into() - )), + beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( + "95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc" + ))), beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4)], 2).unwrap() )), - beefy_log(ConsensusLog::MmrRoot( - hex!("a73271a0974f1e67d6e9b8dd58e506177a2e556519a330796721e98279a753e2").into() - )), + beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( + "a73271a0974f1e67d6e9b8dd58e506177a2e556519a330796721e98279a753e2" + ))), ] ); }); @@ -120,11 +119,13 @@ fn should_contain_valid_leaf_data() { beefy_next_authority_set: BeefyNextAuthoritySet { id: 2, len: 2, - root: hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5") - .into(), + root: array_bytes::hex_n_into_unchecked( + "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5" + ) }, - leaf_extra: hex!("55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648") - .to_vec(), + leaf_extra: array_bytes::hex2bytes_unchecked( + "55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648" + ) } ); @@ -143,11 +144,13 @@ fn should_contain_valid_leaf_data() { beefy_next_authority_set: BeefyNextAuthoritySet { id: 3, len: 2, - root: hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5") - .into(), + root: array_bytes::hex_n_into_unchecked( + "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5" + ) }, - leaf_extra: hex!("55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648") - .to_vec() + leaf_extra: array_bytes::hex2bytes_unchecked( + "55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648" + ) } ); } @@ -161,8 +164,9 @@ fn should_update_authorities() { // check current authority set assert_eq!(0, auth_set.id); assert_eq!(2, auth_set.len); - let want: H256 = - hex!("176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96").into(); + let want = array_bytes::hex_n_into_unchecked::( + "176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96", + ); assert_eq!(want, auth_set.root); // next authority set should have same validators but different id @@ -180,8 +184,9 @@ fn should_update_authorities() { assert_eq!(1, auth_set.id); // check next auth set assert_eq!(2, next_auth_set.id); - let want: H256 = - hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5").into(); + let want = array_bytes::hex_n_into_unchecked::( + "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5", + ); assert_eq!(2, next_auth_set.len); assert_eq!(want, next_auth_set.root); @@ -195,8 +200,9 @@ fn should_update_authorities() { assert_eq!(2, auth_set.id); // check next auth set assert_eq!(3, next_auth_set.id); - let want: H256 = - hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5").into(); + let want = array_bytes::hex_n_into_unchecked::( + "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5", + ); assert_eq!(2, next_auth_set.len); assert_eq!(want, next_auth_set.root); }); diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 49603915ca6da..61aa2b9b900c6 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -31,7 +31,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives sp-storage = { version = "6.0.0", default-features = false, path = "../../primitives/storage" } [dev-dependencies] -hex-literal = "0.3.4" +array-bytes = "4.1" rusty-fork = { version = "0.3.0", default-features = false } sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 4401fb059f90b..a221eccb82c85 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -1695,13 +1695,13 @@ pub fn show_benchmark_debug_info( /// use frame_benchmarking::TrackedStorageKey; /// let whitelist: Vec = vec![ /// // Block Number -/// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), +/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"), /// // Total Issuance -/// hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), +/// array_bytes::hex_into_unchecked("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80"), /// // Execution Phase -/// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), +/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a"), /// // Event Count -/// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), +/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850"), /// ]; /// ``` /// diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index e9a90504d7db7..30fbad680ebe5 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -45,9 +45,9 @@ sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../p sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] +array-bytes = "4.1" assert_matches = "1" env_logger = "0.9" -hex-literal = "0.3" pretty_assertions = "1" wat = "1" diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 2b5cf6353256c..38b47a915cddc 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1379,7 +1379,6 @@ mod tests { use codec::{Decode, Encode}; use frame_support::{assert_err, assert_ok, parameter_types}; use frame_system::{EventRecord, Phase}; - use hex_literal::hex; use pallet_contracts_primitives::ReturnFlags; use pretty_assertions::assert_eq; use sp_core::Bytes; @@ -3210,13 +3209,12 @@ mod tests { #[test] fn ecdsa_to_eth_address_returns_proper_value() { let bob_ch = MockLoader::insert(Call, |ctx, _| { - let pubkey_compressed: [u8; 33] = - hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91")[..] - .try_into() - .unwrap(); + let pubkey_compressed = array_bytes::hex2array_unchecked( + "028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91", + ); assert_eq!( ctx.ext.ecdsa_to_eth_address(&pubkey_compressed).unwrap(), - hex!("09231da7b19A016f9e576d23B16277062F4d46A8")[..] + array_bytes::hex2array_unchecked::<20>("09231da7b19A016f9e576d23B16277062F4d46A8") ); exec_success() }); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 085bc5a8c6423..126a37e9401ec 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -275,7 +275,6 @@ mod tests { }; use assert_matches::assert_matches; use frame_support::{assert_ok, dispatch::DispatchResultWithPostInfo, weights::Weight}; - use hex_literal::hex; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pretty_assertions::assert_eq; use sp_core::{Bytes, H256}; @@ -1828,10 +1827,9 @@ mod tests { output, ExecReturnValue { flags: ReturnFlags::empty(), - data: Bytes( - hex!("000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F") - .to_vec() - ), + data: array_bytes::hex_into_unchecked( + "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F" + ) }, ); } @@ -1901,7 +1899,9 @@ mod tests { flags: ReturnFlags::empty(), data: Bytes( ( - hex!("000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"), + array_bytes::hex2array_unchecked::<32>( + "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F" + ), 42u64, ) .encode() @@ -2110,7 +2110,7 @@ mod tests { fn seal_return_with_success_status() { let output = execute( CODE_RETURN_WITH_DATA, - hex!("00000000445566778899").to_vec(), + array_bytes::hex2bytes_unchecked("00000000445566778899"), MockExt::default(), ) .unwrap(); @@ -2119,7 +2119,7 @@ mod tests { output, ExecReturnValue { flags: ReturnFlags::empty(), - data: Bytes(hex!("445566778899").to_vec()), + data: Bytes(array_bytes::hex2bytes_unchecked("445566778899")), } ); assert!(!output.did_revert()); @@ -2127,15 +2127,18 @@ mod tests { #[test] fn return_with_revert_status() { - let output = - execute(CODE_RETURN_WITH_DATA, hex!("010000005566778899").to_vec(), MockExt::default()) - .unwrap(); + let output = execute( + CODE_RETURN_WITH_DATA, + array_bytes::hex2bytes_unchecked("010000005566778899"), + MockExt::default(), + ) + .unwrap(); assert_eq!( output, ExecReturnValue { flags: ReturnFlags::REVERT, - data: Bytes(hex!("5566778899").to_vec()), + data: Bytes(array_bytes::hex2bytes_unchecked("5566778899")), } ); assert!(output.did_revert()); diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 1ae22ddbb0260..cd5c793ee2ee0 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -27,7 +27,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives sp-tracing = { version = "5.0.0", default-features = false, path = "../../primitives/tracing" } [dev-dependencies] -hex-literal = "0.3.4" +array-bytes = "4.1" pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } sp-core = { version = "6.0.0", path = "../../primitives/core" } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 4926384e42018..01b71aab745d5 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -602,8 +602,6 @@ where mod tests { use super::*; - use hex_literal::hex; - use sp_core::H256; use sp_runtime::{ generic::{DigestItem, Era}, @@ -947,11 +945,15 @@ mod tests { fn block_import_works() { block_import_works_inner( new_test_ext_v0(1), - hex!("1039e1a4bd0cf5deefe65f313577e70169c41c7773d6acf31ca8d671397559f5").into(), + array_bytes::hex_n_into_unchecked( + "1039e1a4bd0cf5deefe65f313577e70169c41c7773d6acf31ca8d671397559f5", + ), ); block_import_works_inner( new_test_ext(1), - hex!("75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5").into(), + array_bytes::hex_n_into_unchecked( + "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5", + ), ); } fn block_import_works_inner(mut ext: sp_io::TestExternalities, state_root: H256) { @@ -961,10 +963,9 @@ mod tests { parent_hash: [69u8; 32].into(), number: 1, state_root, - extrinsics_root: hex!( - "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" - ) - .into(), + extrinsics_root: array_bytes::hex_n_into_unchecked( + "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + ), digest: Digest { logs: vec![] }, }, extrinsics: vec![], @@ -981,10 +982,9 @@ mod tests { parent_hash: [69u8; 32].into(), number: 1, state_root: [0u8; 32].into(), - extrinsics_root: hex!( - "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" - ) - .into(), + extrinsics_root: array_bytes::hex_n_into_unchecked( + "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + ), digest: Digest { logs: vec![] }, }, extrinsics: vec![], @@ -1000,10 +1000,9 @@ mod tests { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!( - "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5" - ) - .into(), + state_root: array_bytes::hex_n_into_unchecked( + "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5", + ), extrinsics_root: [0u8; 32].into(), digest: Digest { logs: vec![] }, }, diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 43d7d6ba2eed7..91ec19d731094 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -25,8 +25,8 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] +array-bytes = "4.1" env_logger = "0.9" -hex-literal = "0.3" itertools = "0.10.3" [features] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 61b71b000a616..a6e177af1853d 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = { version = "4.1", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -hex-literal = { version = "0.3.4", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } @@ -34,7 +34,7 @@ sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = true, [features] default = ["std"] -runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "hex-literal"] +runtime-benchmarks = ["array-bytes", "frame-benchmarking/runtime-benchmarks"] std = [ "log/std", "frame-benchmarking?/std", diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs index cab4c92317bb5..c7fbd00fb565d 100644 --- a/frame/transaction-storage/src/benchmarking.rs +++ b/frame/transaction-storage/src/benchmarking.rs @@ -40,67 +40,68 @@ use crate::Pallet as TransactionStorage; // build_proof(hash.as_slice(), transactions).unwrap().encode() // ``` // while hardforcing target chunk key in `build_proof` to [22, 21, 1, 0]. -const PROOF: &[u8] = &hex_literal::hex!( - " - 0104000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000 - 00000000000000000000000000000000000000000000000000000000000014cd0780ffff8030 - 2eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba0080302eb0a6d2 - f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15 - f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1 - 004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e304 - 8cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697 - eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a - 30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302e - b0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b - 834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e7 - 29d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c10046 - 57e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf2 - 06d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb1 - 53f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba - bd058077778010fd81bc1359802f0b871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de - 808da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff338ad7120b0256c28380221ce17f - 19117affa96e077905fe48a99723a065969c638593b7d9ab57b538438010fd81bc1359802f0b - 871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de808da338e6b722f7bf2051901bd5bc - cee5e71d5cf6b1faff338ad7120b0256c283008010fd81bc1359802f0b871aeb95e4410a8ec9 - 2b93af10ea767a2027cf4734e8de808da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff - 338ad7120b0256c28380221ce17f19117affa96e077905fe48a99723a065969c638593b7d9ab - 57b538438010fd81bc1359802f0b871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de80 - 8da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff338ad7120b0256c28380221ce17f19 - 117affa96e077905fe48a99723a065969c638593b7d9ab57b53843cd0780ffff804509f59593 - fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c00804509f59593fd47b1a9 - 7189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba6 - 5a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0 - 346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f983 - 6e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf89 - 1a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c8045 - 09f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd - 47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189 - 127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a56 - 49cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb03466 - 37f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e15 - 5eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a93 - 9c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939ccd0780ff - ff8078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e - 776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea - 05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f - 015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d - 06feafa3610fc44a5b2ef543cb81008078916e776c64ccea05e958559f015c082d9d06feafa3 - 610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b - 2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb81 - 8078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e77 - 6c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05 - e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f01 - 5c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06 - feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610f - c44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef5 - 43cb811044010000 - " -); +const PROOF: &str = "\ + 0104000000000000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000000000000000\ + 00000000000000000000000000000000000000000000000000000000000014cd0780ffff8030\ + 2eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba0080302eb0a6d2\ + f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15\ + f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1\ + 004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e304\ + 8cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697\ + eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a\ + 30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302e\ + b0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b\ + 834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e7\ + 29d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c10046\ + 57e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf2\ + 06d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb1\ + 53f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba\ + bd058077778010fd81bc1359802f0b871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de\ + 808da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff338ad7120b0256c28380221ce17f\ + 19117affa96e077905fe48a99723a065969c638593b7d9ab57b538438010fd81bc1359802f0b\ + 871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de808da338e6b722f7bf2051901bd5bc\ + cee5e71d5cf6b1faff338ad7120b0256c283008010fd81bc1359802f0b871aeb95e4410a8ec9\ + 2b93af10ea767a2027cf4734e8de808da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff\ + 338ad7120b0256c28380221ce17f19117affa96e077905fe48a99723a065969c638593b7d9ab\ + 57b538438010fd81bc1359802f0b871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de80\ + 8da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff338ad7120b0256c28380221ce17f19\ + 117affa96e077905fe48a99723a065969c638593b7d9ab57b53843cd0780ffff804509f59593\ + fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c00804509f59593fd47b1a9\ + 7189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba6\ + 5a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0\ + 346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f983\ + 6e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf89\ + 1a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c8045\ + 09f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd\ + 47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189\ + 127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a56\ + 49cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb03466\ + 37f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e15\ + 5eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a93\ + 9c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939ccd0780ff\ + ff8078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e\ + 776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea\ + 05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f\ + 015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d\ + 06feafa3610fc44a5b2ef543cb81008078916e776c64ccea05e958559f015c082d9d06feafa3\ + 610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b\ + 2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb81\ + 8078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e77\ + 6c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05\ + e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f01\ + 5c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06\ + feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610f\ + c44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef5\ + 43cb811044010000\ +"; +fn proof() -> Vec { + array_bytes::hex2bytes_unchecked(PROOF) +} type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -159,8 +160,8 @@ benchmarks! { )?; } run_to_block::(StoragePeriod::::get() + T::BlockNumber::one()); - let mut encoded_proof = PROOF; - let proof = TransactionStorageProof::decode(&mut encoded_proof).unwrap(); + let encoded_proof = proof(); + let proof = TransactionStorageProof::decode(&mut &*encoded_proof).unwrap(); }: check_proof(RawOrigin::None, proof) verify { assert_last_event::(Event::ProofChecked.into()); diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 320a30770ab42..1c1afde36ce5c 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -22,8 +22,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] -hex = "0.4.3" -hex-literal = "0.3" +array-bytes = "4.1" sp-keystore = { version = "0.12.0", path = "../keystore" } [features] diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index ddf58474e77a0..4880d4b69ab01 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -301,7 +301,6 @@ impl From> for VersionedFinalityProof { #[cfg(test)] mod tests { - use sp_core::{keccak_256, Pair}; use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr}; @@ -314,6 +313,8 @@ mod tests { type TestSignedCommitment = SignedCommitment; type TestVersionedFinalityProof = VersionedFinalityProof; + const LARGE_RAW_COMMITMENT: &[u8] = include_bytes!("../test-res/large-raw-commitment"); + // The mock signatures are equivalent to the ones produced by the BEEFY keystore fn mock_signatures() -> (crypto::Signature, crypto::Signature) { let store: SyncCryptoStorePtr = KeyStore::new().into(); @@ -351,7 +352,7 @@ mod tests { assert_eq!(decoded, Ok(commitment)); assert_eq!( encoded, - hex_literal::hex!( + array_bytes::hex2bytes_unchecked( "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000" ) ); @@ -379,12 +380,14 @@ mod tests { assert_eq!(decoded, Ok(signed)); assert_eq!( encoded, - hex_literal::hex!( - "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000 - 04300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746 - cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba012d6e1f8105c337a86cdd9a - aacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b - 6a0046395a71681be3d0c2a00" + array_bytes::hex2bytes_unchecked( + "\ + 046d68343048656c6c6f20576f726c64210500000000000000000000000000000000000000000000000\ + 4300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746c\ + c321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba012d6e1f8105c337a86cdd9aa\ + acdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6\ + a0046395a71681be3d0c2a00\ + " ) ); } @@ -481,56 +484,6 @@ mod tests { // then assert_eq!(decoded, Ok(signed)); - assert_eq!( - encoded, - hex_literal::hex!( - "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000 - 05020000000000000000000000000000000000000000000000000000000000000000000000000000000 - 000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - fffffffffff0000040000b10a558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed - 4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad812 - 79df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d1 - 0dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2 - ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01 - 558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e9 - 9a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72 - d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bc - b7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc3 - 21f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc9855 - 80e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0 - c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da - 8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279d - f0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd - 3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac8 - 0a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558 - 455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a8 - 30e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d94 - 8d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb78 - 16f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f - 2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e - 4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33 - c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da848 - 0c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df07 - 95cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd - 68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a0 - 9abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455 - ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e - 314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1 - 107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f - 9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f231 - 9a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb - 75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86 - e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c7 - 46cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795c - c985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68c - e3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09ab - ed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad8 - 1279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314 - d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107 - b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba - 01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01" - ) - ); + assert_eq!(encoded, LARGE_RAW_COMMITMENT); } } diff --git a/primitives/beefy/src/witness.rs b/primitives/beefy/src/witness.rs index aae0608150534..cebfc3de85049 100644 --- a/primitives/beefy/src/witness.rs +++ b/primitives/beefy/src/witness.rs @@ -148,12 +148,14 @@ mod tests { assert_eq!(decoded, Ok(witness)); assert_eq!( encoded, - hex_literal::hex!( - "046d683048656c6c6f20576f726c642105000000000000000000000000000000000000000000000010 - 0000010110000001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c - 746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a86 - cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bc - a2324b6a0046395a71681be3d0c2a00" + array_bytes::hex2bytes_unchecked( + "\ + 046d683048656c6c6f20576f726c642105000000000000000000000000000000000000000000000010\ + 0000010110000001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c\ + 746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a8\ + 6cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487b\ + ca2324b6a0046395a71681be3d0c2a00\ + " ) ); } diff --git a/primitives/beefy/test-res/large-raw-commitment b/primitives/beefy/test-res/large-raw-commitment new file mode 100644 index 0000000000000000000000000000000000000000..d5dbbe402a88e734367395e5af0305f5a47a0872 GIT binary patch literal 44638 zcmeI)F-t;G7zW^@=#W%8gtJb8lR;zccL^uSp_~*Pt_adlGzHavP;nQep($tzT#6_V zC+DVyK-!$@58T!5x#JxiMDIQ4JMa5sx}C#n)Q;m`>9p66Tjgv>zOw1$`$>26f19{M z$b|5itKZfiZuZBktFyPe#%}HDyuXa*h3m>|Zfp8;GKsb?;#v9kVAvc?s$YBaoyAAz z^Y~?UbpJhizbvkwQ$E0V;CJA^;CbMg=)K_GXnkOfWSwZOY` + AsRef<[u8]> + Public + Derive> Ss58Codec for T { let cap = SS58_REGEX.captures(s).ok_or(PublicError::InvalidFormat)?; let s = cap.name("ss58").map(|r| r.as_str()).unwrap_or(DEV_ADDRESS); let addr = if let Some(stripped) = s.strip_prefix("0x") { - let d = hex::decode(stripped).map_err(|_| PublicError::InvalidFormat)?; + let d = array_bytes::hex2bytes(stripped).map_err(|_| PublicError::InvalidFormat)?; Self::from_slice(&d).map_err(|()| PublicError::BadLength)? } else { Self::from_ss58check(s)? @@ -614,10 +614,7 @@ impl sp_std::str::FromStr for AccountId32 { fn from_str(s: &str) -> Result { let hex_or_ss58_without_prefix = s.trim_start_matches("0x"); if hex_or_ss58_without_prefix.len() == 64 { - let mut bytes = [0u8; 32]; - hex::decode_to_slice(hex_or_ss58_without_prefix, &mut bytes) - .map_err(|_| "invalid hex address.") - .map(|_| Self::from(bytes)) + array_bytes::hex_n_into(hex_or_ss58_without_prefix).map_err(|_| "invalid hex address.") } else { Self::from_ss58check(s).map_err(|_| "invalid ss58 address.") } @@ -943,7 +940,7 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { password_override.or_else(|| password.as_ref().map(|p| p.expose_secret().as_str())); let (root, seed) = if let Some(stripped) = phrase.expose_secret().strip_prefix("0x") { - hex::decode(stripped) + array_bytes::hex2bytes(stripped) .ok() .and_then(|seed_vec| { let mut seed = Self::Seed::default(); @@ -1127,7 +1124,6 @@ pub mod key_types { mod tests { use super::*; use crate::DeriveJunction; - use hex_literal::hex; #[derive(Clone, Eq, PartialEq, Debug)] enum TestPair { @@ -1269,7 +1265,7 @@ mod tests { fn interpret_std_seed_should_work() { assert_eq!( TestPair::from_string("0x0123456789abcdef", None), - Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned())) + Ok(TestPair::Seed(array_bytes::hex2bytes_unchecked("0123456789abcdef"))) ); } diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index d56f65fd289e7..ca6b800625bc2 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -229,7 +229,7 @@ impl Serialize for Signature { where S: Serializer, { - serializer.serialize_str(&hex::encode(self)) + serializer.serialize_str(&array_bytes::bytes2hex("", self.as_ref())) } } @@ -239,7 +239,7 @@ impl<'de> Deserialize<'de> for Signature { where D: Deserializer<'de>, { - let signature_hex = hex::decode(&String::deserialize(deserializer)?) + let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; Signature::try_from(signature_hex.as_ref()) .map_err(|e| de::Error::custom(format!("{:?}", e))) @@ -597,7 +597,6 @@ mod test { set_default_ss58_version, PublicError, Ss58AddressFormat, Ss58AddressFormatRegistry, DEV_PHRASE, }; - use hex_literal::hex; use serde_json; #[test] @@ -612,31 +611,35 @@ mod test { #[test] fn seed_and_derive_should_work() { - let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + ); let pair = Pair::from_seed(&seed); assert_eq!(pair.seed(), seed); let path = vec![DeriveJunction::Hard([0u8; 32])]; let derived = pair.derive(path.into_iter(), None).ok().unwrap(); assert_eq!( derived.0.seed(), - hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61") + array_bytes::hex2array_unchecked::<32>( + "b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61" + ) ); } #[test] fn test_vector_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let public = pair.public(); assert_eq!( public, Public::from_full( - &hex!("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4")[..], + &array_bytes::hex2bytes_unchecked("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4"), ).unwrap(), ); let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00"); + let signature = array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00"); let signature = Signature::from_raw(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -653,11 +656,11 @@ mod test { assert_eq!( public, Public::from_full( - &hex!("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4")[..], + &array_bytes::hex2bytes_unchecked("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4"), ).unwrap(), ); let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00"); + let signature = array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00"); let signature = Signature::from_raw(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -680,10 +683,10 @@ mod test { assert_eq!( public, Public::from_full( - &hex!("5676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba995840f3de562156558efbfdac3f16af0065e5f66795f4dd8262a228ef8c6d813")[..], + &array_bytes::hex2bytes_unchecked("5676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba995840f3de562156558efbfdac3f16af0065e5f66795f4dd8262a228ef8c6d813"), ).unwrap(), ); - let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let message = array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); let signature = pair.sign(&message[..]); println!("Correct signature: {:?}", signature); assert!(Pair::verify(&signature, &message[..], &public)); diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 0553cf4843df5..e85eb87c9fd83 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -228,7 +228,7 @@ impl Serialize for Signature { where S: Serializer, { - serializer.serialize_str(&hex::encode(self)) + serializer.serialize_str(&array_bytes::bytes2hex("", self.as_ref())) } } @@ -238,7 +238,7 @@ impl<'de> Deserialize<'de> for Signature { where D: Deserializer<'de>, { - let signature_hex = hex::decode(&String::deserialize(deserializer)?) + let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; Signature::try_from(signature_hex.as_ref()) .map_err(|e| de::Error::custom(format!("{:?}", e))) @@ -551,7 +551,6 @@ impl CryptoType for Pair { mod test { use super::*; use crate::crypto::DEV_PHRASE; - use hex_literal::hex; use serde_json; #[test] @@ -566,31 +565,35 @@ mod test { #[test] fn seed_and_derive_should_work() { - let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + ); let pair = Pair::from_seed(&seed); assert_eq!(pair.seed(), seed); let path = vec![DeriveJunction::Hard([0u8; 32])]; let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; assert_eq!( derived.seed(), - hex!("ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c") + array_bytes::hex2array_unchecked::<32>( + "ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c" + ) ); } #[test] fn test_vector_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let public = pair.public(); assert_eq!( public, - Public::from_raw(hex!( + Public::from_raw(array_bytes::hex2array_unchecked( "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a" )) ); let message = b""; - let signature = hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"); + let signature = array_bytes::hex2array_unchecked("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"); let signature = Signature::from_raw(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -606,12 +609,12 @@ mod test { let public = pair.public(); assert_eq!( public, - Public::from_raw(hex!( + Public::from_raw(array_bytes::hex2array_unchecked( "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a" )) ); let message = b""; - let signature = hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"); + let signature = array_bytes::hex2array_unchecked("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"); let signature = Signature::from_raw(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -633,11 +636,11 @@ mod test { let public = pair.public(); assert_eq!( public, - Public::from_raw(hex!( + Public::from_raw(array_bytes::hex2array_unchecked( "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee" )) ); - let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let message = array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); let signature = pair.sign(&message[..]); println!("Correct signature: {:?}", signature); assert!(Pair::verify(&signature, &message[..], &public)); diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index ef033c2099b5f..9064fb7427393 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -233,7 +233,7 @@ impl Serialize for Signature { where S: Serializer, { - serializer.serialize_str(&hex::encode(self)) + serializer.serialize_str(&array_bytes::bytes2hex("", self.as_ref())) } } @@ -243,7 +243,7 @@ impl<'de> Deserialize<'de> for Signature { where D: Deserializer<'de>, { - let signature_hex = hex::decode(&String::deserialize(deserializer)?) + let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; Signature::try_from(signature_hex.as_ref()) .map_err(|e| de::Error::custom(format!("{:?}", e))) @@ -664,7 +664,6 @@ pub fn verify_batch( mod compatibility_test { use super::*; use crate::crypto::DEV_PHRASE; - use hex_literal::hex; // NOTE: tests to ensure addresses that are created with the `0.1.x` version (pre-audit) are // still functional. @@ -673,7 +672,9 @@ mod compatibility_test { fn derive_soft_known_pair_should_work() { let pair = Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None).unwrap(); // known address of DEV_PHRASE with 1.1 - let known = hex!("d6c71059dbbe9ad2b0ed3f289738b800836eb425544ce694825285b958ca755e"); + let known = array_bytes::hex2bytes_unchecked( + "d6c71059dbbe9ad2b0ed3f289738b800836eb425544ce694825285b958ca755e", + ); assert_eq!(pair.public().to_raw_vec(), known); } @@ -681,17 +682,19 @@ mod compatibility_test { fn derive_hard_known_pair_should_work() { let pair = Pair::from_string(&format!("{}//Alice", DEV_PHRASE), None).unwrap(); // known address of DEV_PHRASE with 1.1 - let known = hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"); + let known = array_bytes::hex2bytes_unchecked( + "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", + ); assert_eq!(pair.public().to_raw_vec(), known); } #[test] fn verify_known_old_message_should_work() { - let public = Public::from_raw(hex!( - "b4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918" + let public = Public::from_raw(array_bytes::hex2array_unchecked( + "b4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918", )); // signature generated by the 1.1 version with the same ^^ public key. - let signature = Signature::from_raw(hex!( + let signature = Signature::from_raw(array_bytes::hex2array_unchecked( "5a9755f069939f45d96aaf125cf5ce7ba1db998686f87f2fb3cbdea922078741a73891ba265f70c31436e18a9acd14d189d73c12317ab6c313285cd938453202" )); let message = b"Verifying that I am the owner of 5G9hQLdsKQswNPgB499DeA5PkFBbgkLPJWkkS6FAM6xGQ8xD. Hash: 221455a3\n"; @@ -704,7 +707,6 @@ mod compatibility_test { mod test { use super::*; use crate::crypto::{Ss58Codec, DEV_ADDRESS, DEV_PHRASE}; - use hex_literal::hex; use serde_json; #[test] @@ -745,8 +747,8 @@ mod test { #[test] fn derive_soft_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let derive_1 = pair.derive(Some(DeriveJunction::soft(1)).into_iter(), None).unwrap().0; let derive_1b = pair.derive(Some(DeriveJunction::soft(1)).into_iter(), None).unwrap().0; @@ -757,8 +759,8 @@ mod test { #[test] fn derive_hard_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let derive_1 = pair.derive(Some(DeriveJunction::hard(1)).into_iter(), None).unwrap().0; let derive_1b = pair.derive(Some(DeriveJunction::hard(1)).into_iter(), None).unwrap().0; @@ -769,8 +771,8 @@ mod test { #[test] fn derive_soft_public_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let path = Some(DeriveJunction::soft(1)); let pair_1 = pair.derive(path.into_iter(), None).unwrap().0; @@ -780,8 +782,8 @@ mod test { #[test] fn derive_hard_public_should_fail() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let path = Some(DeriveJunction::hard(1)); assert!(pair.public().derive(path.into_iter()).is_none()); @@ -789,13 +791,13 @@ mod test { #[test] fn sr_test_vector_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let public = pair.public(); assert_eq!( public, - Public::from_raw(hex!( + Public::from_raw(array_bytes::hex2array_unchecked( "44a996beb1eef7bdcab976ab6d2ca26104834164ecf28fb375600576fcc6eb0f" )) ); @@ -840,11 +842,11 @@ mod test { let public = pair.public(); assert_eq!( public, - Public::from_raw(hex!( + Public::from_raw(array_bytes::hex2array_unchecked( "741c08a06f41c596608f6774259bd9043304adfa5d3eea62760bd9be97634d63" )) ); - let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let message = array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); let signature = pair.sign(&message[..]); assert!(Pair::verify(&signature, &message[..], &public)); } @@ -865,11 +867,11 @@ mod test { // schnorrkel-js. // // This is to make sure that the wasm library is compatible. - let pk = Pair::from_seed(&hex!( - "0000000000000000000000000000000000000000000000000000000000000000" + let pk = Pair::from_seed(&array_bytes::hex2array_unchecked( + "0000000000000000000000000000000000000000000000000000000000000000", )); let public = pk.public(); - let js_signature = Signature::from_raw(hex!( + let js_signature = Signature::from_raw(array_bytes::hex2array_unchecked( "28a854d54903e056f89581c691c1f7d2ff39f8f896c9e9c22475e60902cc2b3547199e0e91fa32902028f2ca2355e8cdd16cfe19ba5e8b658c94aa80f3b81a00" )); assert!(Pair::verify_deprecated(&js_signature, b"SUBSTRATE", &public)); diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index 2be3f592b2b20..e7e203942e845 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -22,7 +22,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] -hex-literal = "0.3" +array-bytes = "4.1" [features] default = ["std"] diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 8a2e901aefddf..29a7e3d1a6fb6 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -535,11 +535,16 @@ mod tests { cases.into_iter().map(Result::<_, codec::Error>::Ok).collect::>() ); // check encoding correctness - assert_eq!(&encoded[0], &hex_literal::hex!("00343048656c6c6f20576f726c6421")); + assert_eq!( + &encoded[0], + &array_bytes::hex2bytes_unchecked("00343048656c6c6f20576f726c6421") + ); assert_eq!( encoded[1].as_slice(), - hex_literal::hex!("01c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd") - .as_ref() + array_bytes::hex2bytes_unchecked( + "01c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd" + ) + .as_slice() ); } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 5de6eb7112eea..860bca2a9de18 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -31,7 +31,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-trie = { version = "6.0.0", default-features = false, path = "../trie" } [dev-dependencies] -hex-literal = "0.3.4" +array-bytes = "4.1" pretty_assertions = "1.2.1" rand = "0.7.2" sp-runtime = { version = "6.0.0", path = "../runtime" } diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index 236a515a2412d..fdc50e3f8f207 100644 --- a/primitives/state-machine/src/basic.rs +++ b/primitives/state-machine/src/basic.rs @@ -356,7 +356,6 @@ impl sp_externalities::ExtensionStore for BasicExternalities { #[cfg(test)] mod tests { use super::*; - use hex_literal::hex; use sp_core::{ map, storage::{well_known_keys::CODE, Storage, StorageChild}, @@ -368,10 +367,11 @@ mod tests { ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec()); - const ROOT: [u8; 32] = - hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa"); + let root = array_bytes::hex2bytes_unchecked( + "39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa", + ); - assert_eq!(&ext.storage_root(StateVersion::default())[..], &ROOT); + assert_eq!(&ext.storage_root(StateVersion::default())[..], &root); } #[test] diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index 001b4b656c34e..ef5c02d2ec1fa 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -743,7 +743,6 @@ impl<'a> OverlayedExtensions<'a> { mod tests { use super::*; use crate::{ext::Ext, InMemoryBackend}; - use hex_literal::hex; use sp_core::{traits::Externalities, Blake2Hasher}; use std::collections::BTreeMap; @@ -870,10 +869,11 @@ mod tests { let mut cache = StorageTransactionCache::default(); let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); - const ROOT: [u8; 32] = - hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa"); + let root = array_bytes::hex2bytes_unchecked( + "39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa", + ); - assert_eq!(&ext.storage_root(state_version)[..], &ROOT); + assert_eq!(&ext.storage_root(state_version)[..], &root); } #[test] diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index 46b7573d9d1a6..e94d34b5560cd 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -334,7 +334,6 @@ where #[cfg(test)] mod tests { use super::*; - use hex_literal::hex; use sp_core::{storage::ChildInfo, traits::Externalities, H256}; use sp_runtime::traits::BlakeTwo256; @@ -346,8 +345,9 @@ mod tests { ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec()); - let root = - H256::from(hex!("ed4d8c799d996add422395a6abd7545491d40bd838d738afafa1b8a4de625489")); + let root = array_bytes::hex_n_into_unchecked::( + "ed4d8c799d996add422395a6abd7545491d40bd838d738afafa1b8a4de625489", + ); assert_eq!(H256::from_slice(ext.storage_root(Default::default()).as_slice()), root); } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 291615c9354c1..6d2d57b590e6a 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -36,8 +36,8 @@ sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] +array-bytes = "4.1" criterion = "0.3.3" -hex-literal = "0.3.4" trie-bench = "0.31.0" trie-standardmap = "0.15.2" sp-runtime = { version = "6.0.0", path = "../runtime" } diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index fafa2a2891ce4..c2ab12dbee14c 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -542,7 +542,6 @@ mod tests { use super::*; use codec::{Compact, Decode, Encode}; use hash_db::{HashDB, Hasher}; - use hex_literal::hex; use sp_core::Blake2Hasher; use trie_db::{DBValue, NodeCodec as NodeCodecT, Trie, TrieMut}; use trie_standardmap::{Alphabet, StandardMap, ValueMode}; @@ -845,8 +844,14 @@ mod tests { } fn iterator_works_inner() { let pairs = vec![ - (hex!("0103000000000000000464").to_vec(), hex!("0400000000").to_vec()), - (hex!("0103000000000000000469").to_vec(), hex!("0401000000").to_vec()), + ( + array_bytes::hex2bytes_unchecked("0103000000000000000464"), + array_bytes::hex2bytes_unchecked("0400000000"), + ), + ( + array_bytes::hex2bytes_unchecked("0103000000000000000469"), + array_bytes::hex2bytes_unchecked("0401000000"), + ), ]; let mut mdb = MemoryDB::default(); @@ -859,7 +864,7 @@ mod tests { let mut iter_pairs = Vec::new(); for pair in iter { let (key, value) = pair.unwrap(); - iter_pairs.push((key, value.to_vec())); + iter_pairs.push((key, value)); } assert_eq!(pairs, iter_pairs); @@ -868,15 +873,15 @@ mod tests { #[test] fn proof_non_inclusion_works() { let pairs = vec![ - (hex!("0102").to_vec(), hex!("01").to_vec()), - (hex!("0203").to_vec(), hex!("0405").to_vec()), + (array_bytes::hex2bytes_unchecked("0102"), array_bytes::hex2bytes_unchecked("01")), + (array_bytes::hex2bytes_unchecked("0203"), array_bytes::hex2bytes_unchecked("0405")), ]; let mut memdb = MemoryDB::default(); let mut root = Default::default(); populate_trie::(&mut memdb, &mut root, &pairs); - let non_included_key: Vec = hex!("0909").to_vec(); + let non_included_key: Vec = array_bytes::hex2bytes_unchecked("0909"); let proof = generate_trie_proof::(&memdb, root, &[non_included_key.clone()]) .unwrap(); @@ -893,7 +898,7 @@ mod tests { assert!(verify_trie_proof::>( &root, &proof, - &[(non_included_key, Some(hex!("1010").to_vec()))], + &[(non_included_key, Some(array_bytes::hex2bytes_unchecked("1010")))], ) .is_err()); } @@ -901,8 +906,8 @@ mod tests { #[test] fn proof_inclusion_works() { let pairs = vec![ - (hex!("0102").to_vec(), hex!("01").to_vec()), - (hex!("0203").to_vec(), hex!("0405").to_vec()), + (array_bytes::hex2bytes_unchecked("0102"), array_bytes::hex2bytes_unchecked("01")), + (array_bytes::hex2bytes_unchecked("0203"), array_bytes::hex2bytes_unchecked("0405")), ]; let mut memdb = MemoryDB::default(); @@ -932,7 +937,7 @@ mod tests { assert!(verify_trie_proof::( &root, &proof, - &[(hex!("4242").to_vec(), Some(pairs[0].1.clone()))] + &[(array_bytes::hex2bytes_unchecked("4242"), Some(pairs[0].1.clone()))] ) .is_err()); diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index f8a1f437d45e1..fcac37441ba98 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -12,10 +12,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -hex = "0.4" serde = "1.0.136" serde_json = "1.0.85" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 3115be58425e6..be4549c9957c0 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -346,7 +346,7 @@ impl RpcHandlersExt for RpcHandlers { "params": ["0x{}"], "id": 0 }}"#, - hex::encode(extrinsic.encode()) + array_bytes::bytes2hex("", &extrinsic.encode()) )) .await .expect("valid JSON-RPC request object; qed"); diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 9e5cb12070af9..108d0d338c2b3 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -13,13 +13,13 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" chrono = "0.4" clap = { version = "3.1.18", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } comfy-table = { version = "6.0.0", default-features = false } handlebars = "4.2.2" hash-db = "0.15.2" -hex = "0.4.3" Inflector = "0.11.4" itertools = "0.10.3" kvdb = "0.11.0" diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index 36215c8a0586d..32282b314b804 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -131,7 +131,9 @@ where fn consumed_weight(&self, block: &BlockId) -> Result { // Hard-coded key for System::BlockWeight. It could also be passed in as argument // for the benchmark, but I think this should work as well. - let hash = hex::decode("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96")?; + let hash = array_bytes::hex2bytes( + "26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96", + )?; let key = StorageKey(hash); let mut raw_weight = &self From 4e53bdc85f240162e554bb2b22461822ef38af76 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Wed, 21 Sep 2022 10:57:02 +0200 Subject: [PATCH 1184/1472] Bound staking storage items (#12230) * replace pallet level unboundedness to individual storage items * bound structs * bounding history depth * defensive error * use the era history depth from config * clean up history depth from storage in v11 * keep the name HistoryDepth for the new configuration value * use u32 for history depth in node runtime * improve doc comments * add HistoryDepth to mock runtimes with pallet-staking * rustfmt * refactor and doc improve * apply re-benchmarked weight for staking * pr feedback improvements * test for claimed rewards following the expected bounds * refactor test to calculate first and last reward era programmatically * verify previous eras cannot be claimed * add migration v12 * ".git/.scripts/bench-bot.sh" pallet dev pallet_staking * fix compiler error * corrupting history depth does not lead to catastrophic issue * fix new line * remove unused import * fmt * add test to document scenario where history depth is reduced without migration * fmt * Update frame/staking/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/staking/src/migrations.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * doc for all storage items bounded by HistoryDepth * Update frame/staking/src/pallet/mod.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/staking/src/tests.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * pr feedback fixes * Update frame/staking/src/tests.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * remove extra checks * fix merge * fmt Co-authored-by: command-bot <> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: kianenigma --- bin/node/runtime/src/lib.rs | 2 + frame/babe/src/mock.rs | 1 + frame/grandpa/src/mock.rs | 1 + .../nomination-pools/benchmarking/src/mock.rs | 1 + .../nomination-pools/test-staking/src/mock.rs | 1 + frame/offences/benchmarking/src/mock.rs | 1 + frame/session/benchmarking/src/mock.rs | 1 + frame/staking/src/benchmarking.rs | 21 +- frame/staking/src/lib.rs | 38 +- frame/staking/src/migrations.rs | 52 +- frame/staking/src/mock.rs | 2 + frame/staking/src/pallet/impls.rs | 25 +- frame/staking/src/pallet/mod.rs | 109 ++-- frame/staking/src/slashing.rs | 4 +- frame/staking/src/tests.rs | 348 ++++++++--- frame/staking/src/weights.rs | 545 +++++++++--------- 16 files changed, 669 insertions(+), 483 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 21ed23d6244a5..0d8f00550ed1a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -535,6 +535,7 @@ parameter_types! { pub const MaxNominatorRewardedPerValidator: u32 = 256; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub OffchainRepeat: BlockNumber = 5; + pub HistoryDepth: u32 = 84; } pub struct StakingBenchmarkingConfig; @@ -572,6 +573,7 @@ impl pallet_staking::Config for Runtime { // This a placeholder, to be introduced in the next PR as an instance of bags-list type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = HistoryDepth; type OnStakerSlash = NominationPools; type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 8264cd11ddc88..46aeabe743fe2 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -204,6 +204,7 @@ impl pallet_staking::Config for Test { type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index a26000c0f7f2c..573a74d2bfae8 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -208,6 +208,7 @@ impl pallet_staking::Config for Test { type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 7841686114dfd..0f617f0bf6f4b 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -115,6 +115,7 @@ impl pallet_staking::Config for Runtime { type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type OnStakerSlash = Pools; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 39111b7f813c7..8c04e40d71df4 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -129,6 +129,7 @@ impl pallet_staking::Config for Runtime { type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type OnStakerSlash = Pools; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index c6d8589870f52..c4c1d2aca8d07 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -182,6 +182,7 @@ impl pallet_staking::Config for Test { type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 60b17213d2f1c..f86ddfeedc08b 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -174,6 +174,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; type OnStakerSlash = (); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index c270b5933e647..1ea05bba3b579 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -660,25 +660,6 @@ benchmarks! { assert!(original_bonded < new_bonded); } - set_history_depth { - let e in 1 .. 100; - HistoryDepth::::put(e); - CurrentEra::::put(e); - let dummy = || -> T::AccountId { codec::Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap() }; - for i in 0 .. e { - >::insert(i, dummy(), Exposure::>::default()); - >::insert(i, dummy(), Exposure::>::default()); - >::insert(i, dummy(), ValidatorPrefs::default()); - >::insert(i, BalanceOf::::one()); - >::insert(i, EraRewardPoints::::default()); - >::insert(i, BalanceOf::::one()); - ErasStartSessionIndex::::insert(i, i); - } - }: _(RawOrigin::Root, EraIndex::zero(), u32::MAX) - verify { - assert_eq!(HistoryDepth::::get(), 0); - } - reap_stash { let s in 1 .. MAX_SPANS; // clean up any existing state. @@ -698,7 +679,7 @@ benchmarks! { active: T::Currency::minimum_balance() - One::one(), total: T::Currency::minimum_balance() - One::one(), unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), }; Ledger::::insert(&controller, l); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 4ff9e99306727..56fcb1965bc13 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -299,12 +299,12 @@ pub mod weights; mod pallet; -use codec::{Decode, Encode, HasCompact}; +use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ parameter_types, traits::{Currency, Defensive, Get}, weights::Weight, - BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, + BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -354,7 +354,7 @@ parameter_types! { } /// Information regarding the active era (era in used in session). -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ActiveEraInfo { /// Index of era. pub index: EraIndex, @@ -395,7 +395,7 @@ pub enum StakerStatus { } /// A destination account for payment. -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum RewardDestination { /// Pay into the stash account, increasing the amount at stake accordingly. Staked, @@ -416,7 +416,7 @@ impl Default for RewardDestination { } /// Preference of what happens regarding validation. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default, MaxEncodedLen)] pub struct ValidatorPrefs { /// Reward that validator takes up-front; only the rest is split between themselves and /// nominators. @@ -429,8 +429,8 @@ pub struct ValidatorPrefs { } /// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct UnlockChunk { +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct UnlockChunk { /// Amount of funds to be unlocked. #[codec(compact)] value: Balance, @@ -440,7 +440,16 @@ pub struct UnlockChunk { } /// The ledger of a (bonded) stash. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo)] +#[derive( + PartialEqNoBound, + EqNoBound, + CloneNoBound, + Encode, + Decode, + RuntimeDebugNoBound, + TypeInfo, + MaxEncodedLen, +)] #[scale_info(skip_type_params(T))] pub struct StakingLedger { /// The stash account whose balance is actually locked and at stake. @@ -459,7 +468,7 @@ pub struct StakingLedger { pub unlocking: BoundedVec>, MaxUnlockingChunks>, /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. - pub claimed_rewards: Vec, + pub claimed_rewards: BoundedVec, } impl StakingLedger { @@ -470,7 +479,7 @@ impl StakingLedger { total: Zero::zero(), active: Zero::zero(), unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), } } @@ -676,7 +685,9 @@ impl StakingLedger { } /// A record of the nominations made by a specific account. -#[derive(PartialEqNoBound, EqNoBound, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo)] +#[derive( + PartialEqNoBound, EqNoBound, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen, +)] #[codec(mel_bound())] #[scale_info(skip_type_params(T))] pub struct Nominations { @@ -850,7 +861,7 @@ impl VoterBagsList + V12_0_0, // remove `HistoryDepth`. } impl Default for Releases { diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 427570e5cf14f..f47545af694cf 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -20,6 +20,53 @@ use super::*; use frame_election_provider_support::SortedListProvider; use frame_support::traits::OnRuntimeUpgrade; +pub mod v12 { + use super::*; + use frame_support::{pallet_prelude::ValueQuery, storage_alias}; + + #[storage_alias] + type HistoryDepth = StorageValue, u32, ValueQuery>; + + /// Clean up `HistoryDepth` from storage. + /// + /// We will be depending on the configurable value of `HistoryDepth` post + /// this release. + pub struct MigrateToV12(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV12 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + frame_support::ensure!( + T::HistoryDepth::get() == HistoryDepth::::get(), + "Provided value of HistoryDepth should be same as the existing storage value" + ); + + Ok(Default::default()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + if StorageVersion::::get() == Releases::V11_0_0 { + HistoryDepth::::kill(); + StorageVersion::::put(Releases::V12_0_0); + + log!(info, "v12 applied successfully"); + T::DbWeight::get().reads_writes(1, 2) + } else { + log!(warn, "Skipping v12, should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + frame_support::ensure!( + StorageVersion::::get() == crate::Releases::V12_0_0, + "v12 not applied" + ); + Ok(()) + } + } +} + pub mod v11 { use super::*; use frame_support::{ @@ -82,11 +129,6 @@ pub mod v11 { #[cfg(feature = "try-runtime")] fn post_upgrade(_state: Vec) -> Result<(), &'static str> { - frame_support::ensure!( - StorageVersion::::get() == crate::Releases::V11_0_0, - "wrong version after the upgrade" - ); - let old_pallet_name = N::get(); let new_pallet_name =

::name(); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 5682184929a5b..385087f9bec41 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -236,6 +236,7 @@ const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub static MaxNominations: u32 = 16; + pub static HistoryDepth: u32 = 80; pub static RewardOnUnbalanceWasCalled: bool = false; pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); } @@ -301,6 +302,7 @@ impl crate::pallet::pallet::Config for Test { type VoterList = VoterBagsList; type TargetList = UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = HistoryDepth; type OnStakerSlash = OnStakerSlashMock; type BenchmarkingConfig = TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 62faaaf68ef62..abb8649169fdd 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -25,8 +25,8 @@ use frame_support::{ dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ - Currency, CurrencyToVote, Defensive, EstimateNextNewSession, Get, Imbalance, - LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, + Currency, CurrencyToVote, Defensive, DefensiveResult, EstimateNextNewSession, Get, + Imbalance, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, }, weights::Weight, }; @@ -101,7 +101,7 @@ impl Pallet { Error::::InvalidEraToReward .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) })?; - let history_depth = Self::history_depth(); + let history_depth = T::HistoryDepth::get(); ensure!( era <= current_era && era >= current_era.saturating_sub(history_depth), Error::::InvalidEraToReward @@ -123,11 +123,18 @@ impl Pallet { ledger .claimed_rewards .retain(|&x| x >= current_era.saturating_sub(history_depth)); + match ledger.claimed_rewards.binary_search(&era) { Ok(_) => return Err(Error::::AlreadyClaimed .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))), - Err(pos) => ledger.claimed_rewards.insert(pos, era), + Err(pos) => ledger + .claimed_rewards + .try_insert(pos, era) + // Since we retain era entries in `claimed_rewards` only upto + // `HistoryDepth`, following bound is always expected to be + // satisfied. + .defensive_map_err(|_| Error::::BoundNotMet)?, } let exposure = >::get(&era, &ledger.stash); @@ -417,7 +424,7 @@ impl Pallet { ErasStartSessionIndex::::insert(&new_planned_era, &start_session_index); // Clean old era information. - if let Some(old_era) = new_planned_era.checked_sub(Self::history_depth() + 1) { + if let Some(old_era) = new_planned_era.checked_sub(T::HistoryDepth::get() + 1) { Self::clear_era_information(old_era); } @@ -966,7 +973,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), }, ); @@ -984,7 +991,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), }, ); Self::do_add_validator( @@ -1025,7 +1032,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), }, ); Self::do_add_validator( @@ -1046,7 +1053,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), }, ); Self::do_add_nominator( diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 49f53efbb08b0..d113c0bb2243c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -22,10 +22,12 @@ use frame_support::{ dispatch::Codec, pallet_prelude::*, traits::{ - Currency, CurrencyToVote, Defensive, DefensiveSaturating, EnsureOrigin, - EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, UnixTime, + Currency, CurrencyToVote, Defensive, DefensiveResult, DefensiveSaturating, EnsureOrigin, + EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, TryCollect, + UnixTime, }, weights::Weight, + BoundedVec, }; use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; use sp_runtime::{ @@ -58,7 +60,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); /// Possible operations on the configuration values of this pallet. @@ -124,6 +125,28 @@ pub mod pallet { #[pallet::constant] type MaxNominations: Get; + /// Number of eras to keep in history. + /// + /// Following information is kept for eras in `[current_era - + /// HistoryDepth, current_era]`: `ErasStakers`, `ErasStakersClipped`, + /// `ErasValidatorPrefs`, `ErasValidatorReward`, `ErasRewardPoints`, + /// `ErasTotalStake`, `ErasStartSessionIndex`, + /// `StakingLedger.claimed_rewards`. + /// + /// Must be more than the number of eras delayed by session. + /// I.e. active era must always be in history. I.e. `active_era > + /// current_era - history_depth` must be guaranteed. + /// + /// If migrating an existing pallet from storage value to config value, + /// this should be set to same value or greater as in storage. + /// + /// Note: `HistoryDepth` is used as the upper bound for the `BoundedVec` + /// item `StakingLedger.claimed_rewards`. Setting this value lower than + /// the existing value can lead to inconsistencies and will need to be + /// handled properly in a migration. + #[pallet::constant] + type HistoryDepth: Get; + /// Tokens have been minted and are unused for validator-reward. /// See [Era payout](./index.html#era-payout). type RewardRemainder: OnUnbalanced>; @@ -230,22 +253,6 @@ pub mod pallet { type WeightInfo: WeightInfo; } - #[pallet::type_value] - pub(crate) fn HistoryDepthOnEmpty() -> u32 { - 84u32 - } - - /// Number of eras to keep in history. - /// - /// Information is kept for eras in `[current_era - history_depth; current_era]`. - /// - /// Must be more than the number of eras delayed by session otherwise. I.e. active era must - /// always be in history. I.e. `active_era > current_era - history_depth` must be - /// guaranteed. - #[pallet::storage] - #[pallet::getter(fn history_depth)] - pub(crate) type HistoryDepth = StorageValue<_, u32, ValueQuery, HistoryDepthOnEmpty>; - /// The ideal number of staking participants. #[pallet::storage] #[pallet::getter(fn validator_count)] @@ -261,6 +268,7 @@ pub mod pallet { /// invulnerables) and restricted to testnets. #[pallet::storage] #[pallet::getter(fn invulnerables)] + #[pallet::unbounded] pub type Invulnerables = StorageValue<_, Vec, ValueQuery>; /// Map from all locked "stash" accounts to the controller account. @@ -364,6 +372,7 @@ pub mod pallet { /// If stakers hasn't been set or has been removed then empty exposure is returned. #[pallet::storage] #[pallet::getter(fn eras_stakers)] + #[pallet::unbounded] pub type ErasStakers = StorageDoubleMap< _, Twox64Concat, @@ -386,6 +395,7 @@ pub mod pallet { /// Is it removed after `HISTORY_DEPTH` eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. #[pallet::storage] + #[pallet::unbounded] #[pallet::getter(fn eras_stakers_clipped)] pub type ErasStakersClipped = StorageDoubleMap< _, @@ -425,6 +435,7 @@ pub mod pallet { /// Rewards for the last `HISTORY_DEPTH` eras. /// If reward hasn't been set or has been removed then 0 reward is returned. #[pallet::storage] + #[pallet::unbounded] #[pallet::getter(fn eras_reward_points)] pub type ErasRewardPoints = StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints, ValueQuery>; @@ -456,6 +467,7 @@ pub mod pallet { /// All unapplied slashes that are queued for later. #[pallet::storage] + #[pallet::unbounded] pub type UnappliedSlashes = StorageMap< _, Twox64Concat, @@ -469,6 +481,7 @@ pub mod pallet { /// Must contains information for eras for the range: /// `[active_era - bounding_duration; active_era]` #[pallet::storage] + #[pallet::unbounded] pub(crate) type BondedEras = StorageValue<_, Vec<(EraIndex, SessionIndex)>, ValueQuery>; @@ -491,6 +504,7 @@ pub mod pallet { /// Slashing spans for stash accounts. #[pallet::storage] + #[pallet::unbounded] pub(crate) type SlashingSpans = StorageMap<_, Twox64Concat, T::AccountId, slashing::SlashingSpans>; @@ -522,6 +536,7 @@ pub mod pallet { /// whether a given validator has previously offended using binary search. It gets cleared when /// the era ends. #[pallet::storage] + #[pallet::unbounded] #[pallet::getter(fn offending_validators)] pub type OffendingValidators = StorageValue<_, Vec<(u32, bool)>, ValueQuery>; @@ -540,7 +555,6 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { - pub history_depth: u32, pub validator_count: u32, pub minimum_validator_count: u32, pub invulnerables: Vec, @@ -559,7 +573,6 @@ pub mod pallet { impl Default for GenesisConfig { fn default() -> Self { GenesisConfig { - history_depth: 84u32, validator_count: Default::default(), minimum_validator_count: Default::default(), invulnerables: Default::default(), @@ -578,7 +591,6 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - HistoryDepth::::put(self.history_depth); ValidatorCount::::put(self.validator_count); MinimumValidatorCount::::put(self.minimum_validator_count); Invulnerables::::put(&self.invulnerables); @@ -729,6 +741,8 @@ pub mod pallet { TooManyValidators, /// Commission is too low. Must be at least `MinCommission`. CommissionTooLow, + /// Some bound is not met. + BoundNotMet, } #[pallet::hooks] @@ -830,7 +844,7 @@ pub mod pallet { >::insert(&stash, payee); let current_era = CurrentEra::::get().unwrap_or(0); - let history_depth = Self::history_depth(); + let history_depth = T::HistoryDepth::get(); let last_reward_era = current_era.saturating_sub(history_depth); let stash_balance = T::Currency::free_balance(&stash); @@ -841,7 +855,12 @@ pub mod pallet { total: value, active: value, unlocking: Default::default(), - claimed_rewards: (last_reward_era..current_era).collect(), + claimed_rewards: (last_reward_era..current_era) + .try_collect() + // Since last_reward_era is calculated as `current_era - + // HistoryDepth`, following bound is always expected to be + // satisfied. + .defensive_map_err(|_| Error::::BoundNotMet)?, }; Self::update_ledger(&controller, &item); Ok(()) @@ -1466,48 +1485,6 @@ pub mod pallet { Ok(Some(T::WeightInfo::rebond(removed_chunks)).into()) } - /// Set `HistoryDepth` value. This function will delete any history information - /// when `HistoryDepth` is reduced. - /// - /// Parameters: - /// - `new_history_depth`: The new history depth you would like to set. - /// - `era_items_deleted`: The number of items that will be deleted by this dispatch. This - /// should report all the storage items that will be deleted by clearing old era history. - /// Needed to report an accurate weight for the dispatch. Trusted by `Root` to report an - /// accurate number. - /// - /// RuntimeOrigin must be root. - /// - /// # - /// - E: Number of history depths removed, i.e. 10 -> 7 = 3 - /// - Weight: O(E) - /// - DB Weight: - /// - Reads: Current Era, History Depth - /// - Writes: History Depth - /// - Clear Prefix Each: Era Stakers, EraStakersClipped, ErasValidatorPrefs - /// - Writes Each: ErasValidatorReward, ErasRewardPoints, ErasTotalStake, - /// ErasStartSessionIndex - /// # - #[pallet::weight(T::WeightInfo::set_history_depth(*_era_items_deleted))] - pub fn set_history_depth( - origin: OriginFor, - #[pallet::compact] new_history_depth: EraIndex, - #[pallet::compact] _era_items_deleted: u32, - ) -> DispatchResult { - ensure_root(origin)?; - if let Some(current_era) = Self::current_era() { - HistoryDepth::::mutate(|history_depth| { - let last_kept = current_era.saturating_sub(*history_depth); - let new_last_kept = current_era.saturating_sub(new_history_depth); - for era_index in last_kept..new_last_kept { - Self::clear_era_information(era_index); - } - *history_depth = new_history_depth - }) - } - Ok(()) - } - /// Remove all data structures concerning a staker/stash once it is at a state where it can /// be considered `dust` in the staking system. The requirements are: /// diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 7372c4390f816..f3272a25fab5c 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -53,7 +53,7 @@ use crate::{ BalanceOf, Config, Error, Exposure, NegativeImbalanceOf, Pallet, Perbill, SessionInterface, Store, UnappliedSlash, }; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, traits::{Currency, Defensive, Get, Imbalance, OnUnbalanced}, @@ -182,7 +182,7 @@ impl SlashingSpans { } /// A slashing-span record for a particular stash. -#[derive(Encode, Decode, Default, TypeInfo)] +#[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)] pub(crate) struct SpanRecord { slashed: Balance, paid_out: Balance, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index cc2b37d2ba910..6798a78030f9e 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -148,14 +148,14 @@ fn basic_setup_works() { // Account 10 controls the stash from account 11, which is 100 * balance_factor units assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { + Staking::ledger(&10).unwrap(), + StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![] - }) + claimed_rewards: bounded_vec![], + } ); // Account 20 controls the stash from account 21, which is 200 * balance_factor units assert_eq!( @@ -165,7 +165,7 @@ fn basic_setup_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }) ); // Account 1 does not control any stash @@ -188,7 +188,7 @@ fn basic_setup_works() { total: 500, active: 500, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }) ); assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); @@ -433,7 +433,7 @@ fn staking_should_work() { total: 1500, active: 1500, unlocking: Default::default(), - claimed_rewards: vec![0], + claimed_rewards: bounded_vec![0], }) ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 @@ -1022,7 +1022,7 @@ fn reward_destination_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1045,7 +1045,7 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: vec![0], + claimed_rewards: bounded_vec![0], }) ); @@ -1073,7 +1073,7 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: vec![0, 1], + claimed_rewards: bounded_vec![0, 1], }) ); @@ -1102,7 +1102,7 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: vec![0, 1, 2], + claimed_rewards: bounded_vec![0, 1, 2], }) ); // Check that amount in staked account is NOT increased. @@ -1164,7 +1164,7 @@ fn bond_extra_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1181,7 +1181,7 @@ fn bond_extra_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1195,7 +1195,7 @@ fn bond_extra_works() { total: 1000000, active: 1000000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); }); @@ -1233,7 +1233,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); assert_eq!( @@ -1251,7 +1251,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Exposure is a snapshot! only updated after the next era update. @@ -1272,7 +1272,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Exposure is now updated. @@ -1290,7 +1290,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }), ); @@ -1303,7 +1303,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }), ); @@ -1319,7 +1319,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }), ); @@ -1335,7 +1335,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 100, active: 100, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }), ); }) @@ -1405,7 +1405,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1424,7 +1424,7 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 2 + 3 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1437,7 +1437,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1450,7 +1450,7 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1463,7 +1463,7 @@ fn rebond_works() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1476,7 +1476,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1491,7 +1491,7 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1504,7 +1504,7 @@ fn rebond_works() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); }) @@ -1531,7 +1531,7 @@ fn rebond_is_fifo() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1546,7 +1546,7 @@ fn rebond_is_fifo() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 2 + 3 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1564,7 +1564,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 300, era: 3 + 3 }, ], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1583,7 +1583,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 300, era: 3 + 3 }, UnlockChunk { value: 200, era: 4 + 3 }, ], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1599,7 +1599,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 100, era: 3 + 3 }, ], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); }) @@ -1628,7 +1628,7 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 1 + 3 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1641,7 +1641,7 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 200, unlocking: bounded_vec![UnlockChunk { value: 800, era: 1 + 3 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Event emitted should be correct @@ -1656,7 +1656,7 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Event emitted should be correct, only 800 @@ -1692,7 +1692,7 @@ fn reward_to_stake_works() { total: 69, active: 69, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }, ); @@ -1756,7 +1756,7 @@ fn reap_stash_works() { total: 5, active: 5, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }, ); @@ -1891,7 +1891,7 @@ fn bond_with_no_staked_value() { active: 0, total: 5, unlocking: bounded_vec![UnlockChunk { value: 5, era: 3 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -2990,7 +2990,7 @@ fn staker_cannot_bail_deferred_slash() { active: 0, total: 500, stash: 101, - claimed_rewards: Default::default(), + claimed_rewards: bounded_vec![], unlocking: bounded_vec![UnlockChunk { era: 4u32, value: 500 }], } ); @@ -3397,7 +3397,7 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // * double claim of one era fails ExtBuilder::default().nominate(true).build_and_execute(|| { // Consumed weight for all payout_stakers dispatches that fail - let err_weight = weights::SubstrateWeight::::payout_stakers_alive_staked(0); + let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); let init_balance_10 = Balances::total_balance(&10); let init_balance_100 = Balances::total_balance(&100); @@ -3432,7 +3432,7 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { assert!(total_payout_2 != total_payout_0); assert!(total_payout_2 != total_payout_1); - mock::start_active_era(Staking::history_depth() + 1); + mock::start_active_era(HistoryDepth::get() + 1); let active_era = active_era(); @@ -3440,7 +3440,7 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { let current_era = Staking::current_era().unwrap(); // Last kept is 1: - assert!(current_era - Staking::history_depth() == 1); + assert!(current_era - HistoryDepth::get() == 1); assert_noop!( Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0), // Fail: Era out of history @@ -3604,25 +3604,6 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( }); } -#[test] -fn set_history_depth_works() { - ExtBuilder::default().build_and_execute(|| { - mock::start_active_era(10); - Staking::set_history_depth(RuntimeOrigin::root(), 20, 0).unwrap(); - assert!(::ErasTotalStake::contains_key(10 - 4)); - assert!(::ErasTotalStake::contains_key(10 - 5)); - Staking::set_history_depth(RuntimeOrigin::root(), 4, 0).unwrap(); - assert!(::ErasTotalStake::contains_key(10 - 4)); - assert!(!::ErasTotalStake::contains_key(10 - 5)); - Staking::set_history_depth(RuntimeOrigin::root(), 3, 0).unwrap(); - assert!(!::ErasTotalStake::contains_key(10 - 4)); - assert!(!::ErasTotalStake::contains_key(10 - 5)); - Staking::set_history_depth(RuntimeOrigin::root(), 8, 0).unwrap(); - assert!(!::ErasTotalStake::contains_key(10 - 4)); - assert!(!::ErasTotalStake::contains_key(10 - 5)); - }); -} - #[test] fn test_payout_stakers() { // Test that payout_stakers work in general, including that only the top @@ -3686,7 +3667,7 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![1] + claimed_rewards: bounded_vec![1] }) ); @@ -3717,11 +3698,15 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (1..=14).collect() + claimed_rewards: (1..=14).collect::>().try_into().unwrap() }) ); - for i in 16..100 { + let last_era = 99; + let history_depth = HistoryDepth::get(); + let expected_last_reward_era = last_era - 1; + let expected_start_reward_era = last_era - history_depth; + for i in 16..=last_era { Staking::reward_by_ids(vec![(11, 1)]); // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); @@ -3729,8 +3714,16 @@ fn test_payout_stakers() { } // We clean it up as history passes - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 15)); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 98)); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_start_reward_era + )); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era + )); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -3738,7 +3731,7 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![15, 98] + claimed_rewards: bounded_vec![expected_start_reward_era, expected_last_reward_era] }) ); @@ -3753,7 +3746,13 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![15, 23, 42, 69, 98] + claimed_rewards: bounded_vec![ + expected_start_reward_era, + 23, + 42, + 69, + expected_last_reward_era + ] }) ); }); @@ -3764,7 +3763,7 @@ fn payout_stakers_handles_basic_errors() { // Here we will test payouts handle all errors. ExtBuilder::default().has_stakers(false).build_and_execute(|| { // Consumed weight for all payout_stakers dispatches that fail - let err_weight = weights::SubstrateWeight::::payout_stakers_alive_staked(0); + let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); // Same setup as the test above let balance = 1000; @@ -3794,32 +3793,47 @@ fn payout_stakers_handles_basic_errors() { Error::::NotStash.with_weight(err_weight) ); - for i in 3..100 { + let last_era = 99; + for i in 3..=last_era { Staking::reward_by_ids(vec![(11, 1)]); // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(i); } - // We are at era 99, with history depth of 84 - // We should be able to payout era 15 through 98 (84 total eras), but not 14 or 99. + + let history_depth = HistoryDepth::get(); + let expected_last_reward_era = last_era - 1; + let expected_start_reward_era = last_era - history_depth; + + // We are at era last_era=99. Given history_depth=80, we should be able + // to payout era starting from expected_start_reward_era=19 through + // expected_last_reward_era=98 (80 total eras), but not 18 or 99. assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 14), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era - 1), Error::::InvalidEraToReward.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 99), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era + 1), Error::::InvalidEraToReward.with_weight(err_weight) ); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 15)); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 98)); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_start_reward_era + )); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era + )); // Can't claim again assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 15), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era), Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 98), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era), Error::::AlreadyClaimed.with_weight(err_weight) ); }); @@ -3944,7 +3958,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); mock::start_active_era(5); @@ -3956,10 +3970,14 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (0..5).collect(), + claimed_rewards: (0..5).collect::>().try_into().unwrap(), }) ); - mock::start_active_era(99); + + // make sure only era upto history depth is stored + let current_era = 99; + let last_reward_era = 99 - HistoryDepth::get(); + mock::start_active_era(current_era); bond_validator(13, 12, 1000); assert_eq!( Staking::ledger(&12), @@ -3968,7 +3986,10 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (15..99).collect(), + claimed_rewards: (last_reward_era..current_era) + .collect::>() + .try_into() + .unwrap(), }) ); }); @@ -4213,7 +4234,7 @@ fn cannot_rebond_to_lower_than_ed() { total: 10 * 1000, active: 10 * 1000, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); @@ -4227,7 +4248,7 @@ fn cannot_rebond_to_lower_than_ed() { total: 10 * 1000, active: 0, unlocking: bounded_vec![UnlockChunk { value: 10 * 1000, era: 3 }], - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); @@ -4253,7 +4274,7 @@ fn cannot_bond_extra_to_lower_than_ed() { total: 10 * 1000, active: 10 * 1000, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); @@ -4267,7 +4288,7 @@ fn cannot_bond_extra_to_lower_than_ed() { total: 10 * 1000, active: 0, unlocking: bounded_vec![UnlockChunk { value: 10 * 1000, era: 3 }], - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); @@ -4294,7 +4315,7 @@ fn do_not_die_when_active_is_ed() { total: 1000 * ed, active: 1000 * ed, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); @@ -4311,7 +4332,7 @@ fn do_not_die_when_active_is_ed() { total: ed, active: ed, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); }) @@ -5162,7 +5183,7 @@ fn proportional_slash_stop_slashing_if_remaining_zero() { active: 20, // we have some chunks, but they are not affected. unlocking: bounded_vec![c(1, 10), c(2, 10)], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }; assert_eq!(BondingDuration::get(), 3); @@ -5180,7 +5201,7 @@ fn proportional_ledger_slash_works() { total: 10, active: 10, unlocking: bounded_vec![], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }; assert_eq!(BondingDuration::get(), 3); @@ -5396,3 +5417,146 @@ fn proportional_ledger_slash_works() { BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 0)]) ); } + +#[test] +fn pre_bonding_era_cannot_be_claimed() { + // Verifies initial conditions of mock + ExtBuilder::default().nominate(false).build_and_execute(|| { + let history_depth = HistoryDepth::get(); + // jump to some era above history_depth + let mut current_era = history_depth + 10; + let last_reward_era = current_era - 1; + let start_reward_era = current_era - history_depth; + + // put some money in stash=3 and controller=4. + for i in 3..5 { + let _ = Balances::make_free_balance_be(&i, 2000); + } + + mock::start_active_era(current_era); + + // add a new candidate for being a validator. account 3 controlled by 4. + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 1500, RewardDestination::Controller)); + + let claimed_rewards: BoundedVec<_, _> = + (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); + assert_eq!( + Staking::ledger(&4).unwrap(), + StakingLedger { + stash: 3, + total: 1500, + active: 1500, + unlocking: Default::default(), + claimed_rewards, + } + ); + + // start next era + current_era = current_era + 1; + mock::start_active_era(current_era); + + // claiming reward for last era in which validator was active works + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1)); + + // consumed weight for all payout_stakers dispatches that fail + let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); + // cannot claim rewards for an era before bonding occured as it is + // already marked as claimed. + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 2), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + // decoding will fail now since Staking Ledger is in corrupt state + HistoryDepth::set(history_depth - 1); + assert_eq!(Staking::ledger(&4), None); + + // make sure stakers still cannot claim rewards that they are not meant to + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 2), + Error::::NotController + ); + + // fix the corrupted state for post conditions check + HistoryDepth::set(history_depth); + }); +} + +#[test] +fn reducing_history_depth_without_migration() { + // Verifies initial conditions of mock + ExtBuilder::default().nominate(false).build_and_execute(|| { + let original_history_depth = HistoryDepth::get(); + let mut current_era = original_history_depth + 10; + let last_reward_era = current_era - 1; + let start_reward_era = current_era - original_history_depth; + + // put some money in (stash, controller)=(3,4),(5,6). + for i in 3..7 { + let _ = Balances::make_free_balance_be(&i, 2000); + } + + // start current era + mock::start_active_era(current_era); + + // add a new candidate for being a staker. account 3 controlled by 4. + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 1500, RewardDestination::Controller)); + + // all previous era before the bonding action should be marked as + // claimed. + let claimed_rewards: BoundedVec<_, _> = + (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); + assert_eq!( + Staking::ledger(&4).unwrap(), + StakingLedger { + stash: 3, + total: 1500, + active: 1500, + unlocking: Default::default(), + claimed_rewards, + } + ); + + // next era + current_era = current_era + 1; + mock::start_active_era(current_era); + + // claiming reward for last era in which validator was active works + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1)); + + // next era + current_era = current_era + 1; + mock::start_active_era(current_era); + + // history_depth reduced without migration + let history_depth = original_history_depth - 1; + HistoryDepth::set(history_depth); + // claiming reward does not work anymore + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1), + Error::::NotController + ); + + // new stakers can still bond + assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 6, 1200, RewardDestination::Controller)); + + // new staking ledgers created will be bounded by the current history depth + let last_reward_era = current_era - 1; + let start_reward_era = current_era - history_depth; + let claimed_rewards: BoundedVec<_, _> = + (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); + assert_eq!( + Staking::ledger(&6).unwrap(), + StakingLedger { + stash: 5, + total: 1200, + active: 1200, + unlocking: Default::default(), + claimed_rewards, + } + ); + + // fix the corrupted state for post conditions check + HistoryDepth::set(original_history_depth); + }); +} diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 09c2d8b5de113..5070232365d3e 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,22 +18,24 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-09-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_staking // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --pallet=pallet_staking +// --chain=dev // --output=./frame/staking/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -65,7 +67,6 @@ pub trait WeightInfo { fn payout_stakers_dead_controller(n: u32, ) -> Weight; fn payout_stakers_alive_staked(n: u32, ) -> Weight; fn rebond(l: u32, ) -> Weight; - fn set_history_depth(e: u32, ) -> Weight; fn reap_stash(s: u32, ) -> Weight; fn new_era(v: u32, n: u32, ) -> Weight; fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight; @@ -82,21 +83,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - Weight::from_ref_time(43_992_000 as u64) - .saturating_add(T::DbWeight::get().reads(5 as u64)) + Weight::from_ref_time(52_281_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - Weight::from_ref_time(75_827_000 as u64) + Weight::from_ref_time(89_748_000 as u64) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(7 as u64)) } @@ -106,11 +106,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListBags (r:2 w:2) fn unbond() -> Weight { - Weight::from_ref_time(81_075_000 as u64) + Weight::from_ref_time(94_782_000 as u64) .saturating_add(T::DbWeight::get().reads(12 as u64)) .saturating_add(T::DbWeight::get().writes(8 as u64)) } @@ -118,10 +118,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(35_763_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(57_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(44_499_000 as u64) + // Standard Error: 387 + .saturating_add(Weight::from_ref_time(72_726 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -132,14 +133,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - Weight::from_ref_time(66_938_000 as u64) + /// The range of component `s` is `[0, 100]`. + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + Weight::from_ref_time(83_230_000 as u64) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(10_289 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(13 as u64)) .saturating_add(T::DbWeight::get().writes(11 as u64)) } @@ -150,23 +154,25 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxValidatorsCount (r:1 w:0) // Storage: Staking Nominators (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:1 w:1) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - Weight::from_ref_time(52_943_000 as u64) + Weight::from_ref_time(64_430_000 as u64) .saturating_add(T::DbWeight::get().reads(11 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) + /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - Weight::from_ref_time(23_264_000 as u64) - // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(8_006_000 as u64).saturating_mul(k as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) + Weight::from_ref_time(42_030_000 as u64) + // Standard Error: 5_873 + .saturating_add(Weight::from_ref_time(6_747_156 as u64).saturating_mul(k as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(k as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Staking Ledger (r:1 w:0) @@ -176,15 +182,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) + /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(56_596_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(3_644_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(12 as u64)) + Weight::from_ref_time(70_834_000 as u64) + // Standard Error: 4_405 + .saturating_add(Weight::from_ref_time(2_583_120 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(13 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -192,53 +199,54 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(51_117_000 as u64) + Weight::from_ref_time(63_328_000 as u64) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - Weight::from_ref_time(11_223_000 as u64) + Weight::from_ref_time(17_763_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - Weight::from_ref_time(19_826_000 as u64) + Weight::from_ref_time(26_163_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - Weight::from_ref_time(3_789_000 as u64) + Weight::from_ref_time(4_842_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - Weight::from_ref_time(3_793_000 as u64) + Weight::from_ref_time(4_974_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - Weight::from_ref_time(3_802_000 as u64) + Weight::from_ref_time(5_039_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - Weight::from_ref_time(3_762_000 as u64) + Weight::from_ref_time(4_950_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Invulnerables (r:0 w:1) + /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - Weight::from_ref_time(4_318_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(10_000 as u64).saturating_mul(v as u64)) + Weight::from_ref_time(5_150_000 as u64) + // Standard Error: 30 + .saturating_add(Weight::from_ref_time(10_540 as u64).saturating_mul(v as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) @@ -246,32 +254,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) + /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - Weight::from_ref_time(65_265_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_029_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(76_282_000 as u64) + // Standard Error: 2_397 + .saturating_add(Weight::from_ref_time(1_137_934 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(11 as u64)) - .saturating_add(T::DbWeight::get().writes(12 as u64)) + .saturating_add(T::DbWeight::get().writes(11 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Staking UnappliedSlashes (r:1 w:1) + /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - Weight::from_ref_time(903_312_000 as u64) - // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(4_968_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(93_690_000 as u64) + // Standard Error: 43_203 + .saturating_add(Weight::from_ref_time(6_149_862 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:2 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -280,17 +289,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasValidatorPrefs (r:1 w:0) // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) + /// The range of component `n` is `[1, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - Weight::from_ref_time(87_569_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(24_232_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(10 as u64)) + Weight::from_ref_time(151_647_000 as u64) + // Standard Error: 8_237 + .saturating_add(Weight::from_ref_time(21_296_415 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(12 as u64)) .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:2 w:0) // Storage: Staking Ledger (r:2 w:2) @@ -300,45 +309,30 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) + /// The range of component `n` is `[1, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - Weight::from_ref_time(98_839_000 as u64) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(34_480_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(11 as u64)) + Weight::from_ref_time(197_310_000 as u64) + // Standard Error: 13_818 + .saturating_add(Weight::from_ref_time(30_053_043 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(15 as u64)) .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(n as u64))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListBags (r:2 w:2) + /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - Weight::from_ref_time(74_865_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(64_000 as u64).saturating_mul(l as u64)) + Weight::from_ref_time(89_469_000 as u64) + // Standard Error: 1_197 + .saturating_add(Weight::from_ref_time(74_212 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(9 as u64)) .saturating_add(T::DbWeight::get().writes(8 as u64)) } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:1) - // Storage: Staking ErasStakersClipped (r:0 w:2) - // Storage: Staking ErasValidatorPrefs (r:0 w:2) - // Storage: Staking ErasValidatorReward (r:0 w:1) - // Storage: Staking ErasRewardPoints (r:0 w:1) - // Storage: Staking ErasStakers (r:0 w:2) - // Storage: Staking ErasTotalStake (r:0 w:1) - // Storage: Staking ErasStartSessionIndex (r:0 w:1) - fn set_history_depth(e: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 62_000 - .saturating_add(Weight::from_ref_time(22_829_000 as u64).saturating_mul(e as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(e as u64))) - } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) @@ -346,24 +340,25 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) + /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - Weight::from_ref_time(70_933_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_021_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(88_333_000 as u64) + // Standard Error: 1_567 + .saturating_add(Weight::from_ref_time(1_101_099 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(12 as u64)) + .saturating_add(T::DbWeight::get().writes(13 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } - // Storage: BagsList CounterForListNodes (r:1 w:0) + // Storage: VoterBagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:101 w:0) + // Storage: VoterBagsList ListBags (r:200 w:0) + // Storage: VoterBagsList ListNodes (r:101 w:0) // Storage: Staking Nominators (r:101 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking Bonded (r:101 w:0) @@ -372,52 +367,54 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ValidatorCount (r:1 w:0) // Storage: Staking MinimumValidatorCount (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:1) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasStakersClipped (r:0 w:1) // Storage: Staking ErasValidatorPrefs (r:0 w:1) // Storage: Staking ErasStakers (r:0 w:1) // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) + /// The range of component `v` is `[1, 10]`. + /// The range of component `n` is `[1, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 897_000 - .saturating_add(Weight::from_ref_time(213_100_000 as u64).saturating_mul(v as u64)) - // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(31_123_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(208 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(v as u64))) + Weight::from_ref_time(572_530_000 as u64) + // Standard Error: 3_166_542 + .saturating_add(Weight::from_ref_time(101_354_358 as u64).saturating_mul(v as u64)) + // Standard Error: 315_238 + .saturating_add(Weight::from_ref_time(15_565_319 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(261 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(v as u64))) .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(v as u64))) } - // Storage: BagsList CounterForListNodes (r:1 w:0) + // Storage: VoterBagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) - // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:1500 w:0) + // Storage: VoterBagsList ListBags (r:200 w:0) + // Storage: VoterBagsList ListNodes (r:1500 w:0) // Storage: Staking Nominators (r:1500 w:0) // Storage: Staking Validators (r:500 w:0) // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) - fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(23_745_000 as u64).saturating_mul(v as u64)) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(22_497_000 as u64).saturating_mul(n as u64)) - // Standard Error: 3_968_000 - .saturating_add(Weight::from_ref_time(20_676_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(202 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(v as u64))) - .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + /// The range of component `v` is `[500, 1000]`. + /// The range of component `n` is `[500, 1000]`. + /// The range of component `s` is `[1, 20]`. + fn get_npos_voters(v: u32, n: u32, _s: u32, ) -> Weight { + Weight::from_ref_time(24_930_788_000 as u64) + // Standard Error: 266_386 + .saturating_add(Weight::from_ref_time(6_687_552 as u64).saturating_mul(v as u64)) + // Standard Error: 266_386 + .saturating_add(Weight::from_ref_time(6_839_134 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6722 as u64)) + .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(v as u64))) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) } + // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:501 w:0) + /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 36_000 - .saturating_add(Weight::from_ref_time(8_097_000 as u64).saturating_mul(v as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + Weight::from_ref_time(4_864_727_000 as u64) + // Standard Error: 54_240 + .saturating_add(Weight::from_ref_time(3_319_738 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(502 as u64)) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -426,7 +423,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - Weight::from_ref_time(7_041_000 as u64) + Weight::from_ref_time(10_141_000 as u64) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:0 w:1) @@ -436,7 +433,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - Weight::from_ref_time(6_495_000 as u64) + Weight::from_ref_time(8_993_000 as u64) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) @@ -446,18 +443,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForNominators (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - Weight::from_ref_time(62_014_000 as u64) + Weight::from_ref_time(79_082_000 as u64) .saturating_add(T::DbWeight::get().reads(11 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - Weight::from_ref_time(12_814_000 as u64) + Weight::from_ref_time(19_265_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -468,21 +465,20 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - Weight::from_ref_time(43_992_000 as u64) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) + Weight::from_ref_time(52_281_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - Weight::from_ref_time(75_827_000 as u64) + Weight::from_ref_time(89_748_000 as u64) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(7 as u64)) } @@ -492,11 +488,11 @@ impl WeightInfo for () { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListBags (r:2 w:2) fn unbond() -> Weight { - Weight::from_ref_time(81_075_000 as u64) + Weight::from_ref_time(94_782_000 as u64) .saturating_add(RocksDbWeight::get().reads(12 as u64)) .saturating_add(RocksDbWeight::get().writes(8 as u64)) } @@ -504,10 +500,11 @@ impl WeightInfo for () { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(35_763_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(57_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(44_499_000 as u64) + // Standard Error: 387 + .saturating_add(Weight::from_ref_time(72_726 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -518,14 +515,17 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - Weight::from_ref_time(66_938_000 as u64) + /// The range of component `s` is `[0, 100]`. + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + Weight::from_ref_time(83_230_000 as u64) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(10_289 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(13 as u64)) .saturating_add(RocksDbWeight::get().writes(11 as u64)) } @@ -536,23 +536,25 @@ impl WeightInfo for () { // Storage: Staking MaxValidatorsCount (r:1 w:0) // Storage: Staking Nominators (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:1 w:1) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - Weight::from_ref_time(52_943_000 as u64) + Weight::from_ref_time(64_430_000 as u64) .saturating_add(RocksDbWeight::get().reads(11 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) + /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - Weight::from_ref_time(23_264_000 as u64) - // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(8_006_000 as u64).saturating_mul(k as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) + Weight::from_ref_time(42_030_000 as u64) + // Standard Error: 5_873 + .saturating_add(Weight::from_ref_time(6_747_156 as u64).saturating_mul(k as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(k as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Staking Ledger (r:1 w:0) @@ -562,15 +564,16 @@ impl WeightInfo for () { // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) + /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(56_596_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(3_644_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) + Weight::from_ref_time(70_834_000 as u64) + // Standard Error: 4_405 + .saturating_add(Weight::from_ref_time(2_583_120 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(13 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -578,53 +581,54 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(51_117_000 as u64) + Weight::from_ref_time(63_328_000 as u64) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - Weight::from_ref_time(11_223_000 as u64) + Weight::from_ref_time(17_763_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - Weight::from_ref_time(19_826_000 as u64) + Weight::from_ref_time(26_163_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - Weight::from_ref_time(3_789_000 as u64) + Weight::from_ref_time(4_842_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - Weight::from_ref_time(3_793_000 as u64) + Weight::from_ref_time(4_974_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - Weight::from_ref_time(3_802_000 as u64) + Weight::from_ref_time(5_039_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - Weight::from_ref_time(3_762_000 as u64) + Weight::from_ref_time(4_950_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Invulnerables (r:0 w:1) + /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - Weight::from_ref_time(4_318_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(10_000 as u64).saturating_mul(v as u64)) + Weight::from_ref_time(5_150_000 as u64) + // Standard Error: 30 + .saturating_add(Weight::from_ref_time(10_540 as u64).saturating_mul(v as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) @@ -632,32 +636,33 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) + /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - Weight::from_ref_time(65_265_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_029_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(76_282_000 as u64) + // Standard Error: 2_397 + .saturating_add(Weight::from_ref_time(1_137_934 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(11 as u64)) - .saturating_add(RocksDbWeight::get().writes(12 as u64)) + .saturating_add(RocksDbWeight::get().writes(11 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Staking UnappliedSlashes (r:1 w:1) + /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - Weight::from_ref_time(903_312_000 as u64) - // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(4_968_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(93_690_000 as u64) + // Standard Error: 43_203 + .saturating_add(Weight::from_ref_time(6_149_862 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:2 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -666,17 +671,17 @@ impl WeightInfo for () { // Storage: Staking ErasValidatorPrefs (r:1 w:0) // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) + /// The range of component `n` is `[1, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - Weight::from_ref_time(87_569_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(24_232_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(10 as u64)) + Weight::from_ref_time(151_647_000 as u64) + // Standard Error: 8_237 + .saturating_add(Weight::from_ref_time(21_296_415 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(12 as u64)) .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:2 w:0) // Storage: Staking Ledger (r:2 w:2) @@ -686,45 +691,30 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) + /// The range of component `n` is `[1, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - Weight::from_ref_time(98_839_000 as u64) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(34_480_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(11 as u64)) + Weight::from_ref_time(197_310_000 as u64) + // Standard Error: 13_818 + .saturating_add(Weight::from_ref_time(30_053_043 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(15 as u64)) .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(n as u64))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListBags (r:2 w:2) + /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - Weight::from_ref_time(74_865_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(64_000 as u64).saturating_mul(l as u64)) + Weight::from_ref_time(89_469_000 as u64) + // Standard Error: 1_197 + .saturating_add(Weight::from_ref_time(74_212 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(9 as u64)) .saturating_add(RocksDbWeight::get().writes(8 as u64)) } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:1) - // Storage: Staking ErasStakersClipped (r:0 w:2) - // Storage: Staking ErasValidatorPrefs (r:0 w:2) - // Storage: Staking ErasValidatorReward (r:0 w:1) - // Storage: Staking ErasRewardPoints (r:0 w:1) - // Storage: Staking ErasStakers (r:0 w:2) - // Storage: Staking ErasTotalStake (r:0 w:1) - // Storage: Staking ErasStartSessionIndex (r:0 w:1) - fn set_history_depth(e: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 62_000 - .saturating_add(Weight::from_ref_time(22_829_000 as u64).saturating_mul(e as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(e as u64))) - } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) @@ -732,24 +722,25 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) + /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - Weight::from_ref_time(70_933_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_021_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(88_333_000 as u64) + // Standard Error: 1_567 + .saturating_add(Weight::from_ref_time(1_101_099 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().writes(12 as u64)) + .saturating_add(RocksDbWeight::get().writes(13 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } - // Storage: BagsList CounterForListNodes (r:1 w:0) + // Storage: VoterBagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:101 w:0) + // Storage: VoterBagsList ListBags (r:200 w:0) + // Storage: VoterBagsList ListNodes (r:101 w:0) // Storage: Staking Nominators (r:101 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking Bonded (r:101 w:0) @@ -758,52 +749,54 @@ impl WeightInfo for () { // Storage: Staking ValidatorCount (r:1 w:0) // Storage: Staking MinimumValidatorCount (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:1) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasStakersClipped (r:0 w:1) // Storage: Staking ErasValidatorPrefs (r:0 w:1) // Storage: Staking ErasStakers (r:0 w:1) // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) + /// The range of component `v` is `[1, 10]`. + /// The range of component `n` is `[1, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 897_000 - .saturating_add(Weight::from_ref_time(213_100_000 as u64).saturating_mul(v as u64)) - // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(31_123_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(208 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(v as u64))) + Weight::from_ref_time(572_530_000 as u64) + // Standard Error: 3_166_542 + .saturating_add(Weight::from_ref_time(101_354_358 as u64).saturating_mul(v as u64)) + // Standard Error: 315_238 + .saturating_add(Weight::from_ref_time(15_565_319 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(261 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(v as u64))) .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(v as u64))) } - // Storage: BagsList CounterForListNodes (r:1 w:0) + // Storage: VoterBagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) - // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:1500 w:0) + // Storage: VoterBagsList ListBags (r:200 w:0) + // Storage: VoterBagsList ListNodes (r:1500 w:0) // Storage: Staking Nominators (r:1500 w:0) // Storage: Staking Validators (r:500 w:0) // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) - fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(23_745_000 as u64).saturating_mul(v as u64)) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(22_497_000 as u64).saturating_mul(n as u64)) - // Standard Error: 3_968_000 - .saturating_add(Weight::from_ref_time(20_676_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(202 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(v as u64))) - .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + /// The range of component `v` is `[500, 1000]`. + /// The range of component `n` is `[500, 1000]`. + /// The range of component `s` is `[1, 20]`. + fn get_npos_voters(v: u32, n: u32, _s: u32, ) -> Weight { + Weight::from_ref_time(24_930_788_000 as u64) + // Standard Error: 266_386 + .saturating_add(Weight::from_ref_time(6_687_552 as u64).saturating_mul(v as u64)) + // Standard Error: 266_386 + .saturating_add(Weight::from_ref_time(6_839_134 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6722 as u64)) + .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(v as u64))) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) } + // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:501 w:0) + /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 36_000 - .saturating_add(Weight::from_ref_time(8_097_000 as u64).saturating_mul(v as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + Weight::from_ref_time(4_864_727_000 as u64) + // Standard Error: 54_240 + .saturating_add(Weight::from_ref_time(3_319_738 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(502 as u64)) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -812,7 +805,7 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - Weight::from_ref_time(7_041_000 as u64) + Weight::from_ref_time(10_141_000 as u64) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:0 w:1) @@ -822,7 +815,7 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - Weight::from_ref_time(6_495_000 as u64) + Weight::from_ref_time(8_993_000 as u64) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) @@ -832,18 +825,18 @@ impl WeightInfo for () { // Storage: Staking CounterForNominators (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - Weight::from_ref_time(62_014_000 as u64) + Weight::from_ref_time(79_082_000 as u64) .saturating_add(RocksDbWeight::get().reads(11 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - Weight::from_ref_time(12_814_000 as u64) + Weight::from_ref_time(19_265_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } From 9df7ac80f367e396135afb94150bdafbce88e094 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 21 Sep 2022 11:42:12 +0200 Subject: [PATCH 1185/1472] Introduce 'intermediate_insert' method to hide implementation details (#12215) Renaming from 'intermediate_take' to 'intermediate_remove' --- bin/node/cli/src/service.rs | 8 ++++---- client/consensus/babe/src/lib.rs | 17 +++++++---------- client/consensus/babe/src/tests.rs | 6 ++---- client/consensus/common/src/block_import.rs | 15 ++++++++++----- .../consensus/manual-seal/src/consensus/babe.rs | 13 ++++--------- client/consensus/pow/src/lib.rs | 13 ++++--------- client/consensus/pow/src/worker.rs | 6 +----- 7 files changed, 32 insertions(+), 46 deletions(-) diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index c058e22fa7a97..f2b4feb58075f 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -587,7 +587,7 @@ mod tests { RuntimeAppPublic, }; use sp_timestamp; - use std::{borrow::Cow, sync::Arc}; + use std::sync::Arc; type AccountPublic = ::Signer; @@ -733,9 +733,9 @@ mod tests { let mut params = BlockImportParams::new(BlockOrigin::File, new_header); params.post_digests.push(item); params.body = Some(new_body); - params.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, + params.insert_intermediate( + INTERMEDIATE_KEY, + BabeIntermediate:: { epoch_descriptor }, ); params.fork_choice = Some(ForkChoiceStrategy::LongestChain); diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index eca6654f6e4dc..aef4785b7bb81 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -67,7 +67,6 @@ #![warn(missing_docs)] use std::{ - borrow::Cow, collections::{HashMap, HashSet}, future::Future, pin::Pin, @@ -857,10 +856,8 @@ where import_block.body = Some(body); import_block.state_action = StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes(storage_changes)); - import_block.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, - ); + import_block + .insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); Ok(import_block) } @@ -1272,9 +1269,9 @@ where block.header = pre_header; block.post_digests.push(verified_info.seal); - block.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, + block.insert_intermediate( + INTERMEDIATE_KEY, + BabeIntermediate:: { epoch_descriptor }, ); block.post_hash = Some(hash); @@ -1426,7 +1423,7 @@ where match self.client.status(BlockId::Hash(hash)) { Ok(sp_blockchain::BlockStatus::InChain) => { // When re-importing existing block strip away intermediates. - let _ = block.take_intermediate::>(INTERMEDIATE_KEY); + let _ = block.remove_intermediate::>(INTERMEDIATE_KEY); block.fork_choice = Some(ForkChoiceStrategy::Custom(false)); return self.inner.import_block(block, new_cache).await.map_err(Into::into) }, @@ -1495,7 +1492,7 @@ where }; let intermediate = - block.take_intermediate::>(INTERMEDIATE_KEY)?; + block.remove_intermediate::>(INTERMEDIATE_KEY)?; let epoch_descriptor = intermediate.epoch_descriptor; let first_in_epoch = parent_slot < epoch_descriptor.start_slot(); diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index ab3805138482c..a3467e0020200 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -642,10 +642,8 @@ fn propose_and_import_block( let mut import = BlockImportParams::new(BlockOrigin::Own, block.header); import.post_digests.push(seal); import.body = Some(block.extrinsics); - import.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, - ); + import + .insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); import.fork_choice = Some(ForkChoiceStrategy::LongestChain); let import_result = block_on(block_import.import_block(import, Default::default())).unwrap(); diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index b8fc815cc5c5c..f888176addd2d 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -294,18 +294,23 @@ impl BlockImportParams { } } - /// Take intermediate by given key, and remove it from the processing list. - pub fn take_intermediate(&mut self, key: &[u8]) -> Result, Error> { + /// Insert intermediate by given key. + pub fn insert_intermediate(&mut self, key: &'static [u8], value: T) { + self.intermediates.insert(Cow::from(key), Box::new(value)); + } + + /// Remove and return intermediate by given key. + pub fn remove_intermediate(&mut self, key: &[u8]) -> Result { let (k, v) = self.intermediates.remove_entry(key).ok_or(Error::NoIntermediate)?; - v.downcast::().map_err(|v| { + v.downcast::().map(|v| *v).map_err(|v| { self.intermediates.insert(k, v); Error::InvalidIntermediate }) } /// Get a reference to a given intermediate. - pub fn intermediate(&self, key: &[u8]) -> Result<&T, Error> { + pub fn get_intermediate(&self, key: &[u8]) -> Result<&T, Error> { self.intermediates .get(key) .ok_or(Error::NoIntermediate)? @@ -314,7 +319,7 @@ impl BlockImportParams { } /// Get a mutable reference to a given intermediate. - pub fn intermediate_mut(&mut self, key: &[u8]) -> Result<&mut T, Error> { + pub fn get_intermediate_mut(&mut self, key: &[u8]) -> Result<&mut T, Error> { self.intermediates .get_mut(key) .ok_or(Error::NoIntermediate)? diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 300a96695c90a..206f5163a13cd 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -30,7 +30,7 @@ use sc_consensus_epochs::{ descendent_query, EpochHeader, SharedEpochChanges, ViableEpochDescriptor, }; use sp_keystore::SyncCryptoStorePtr; -use std::{borrow::Cow, marker::PhantomData, sync::Arc}; +use std::{marker::PhantomData, sync::Arc}; use sc_consensus::{BlockImportParams, ForkChoiceStrategy, Verifier}; use sp_api::{ProvideRuntimeApi, TransactionFor}; @@ -125,10 +125,8 @@ where // drop the lock drop(epoch_changes); - import_params.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, - ); + import_params + .insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); Ok((import_params, None)) } @@ -315,10 +313,7 @@ where }; } - params.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, - ); + params.insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); Ok(()) } diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 9b3ef501d2396..dcf069d617bab 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -65,10 +65,7 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT}, RuntimeString, }; -use std::{ - borrow::Cow, cmp::Ordering, collections::HashMap, marker::PhantomData, sync::Arc, - time::Duration, -}; +use std::{cmp::Ordering, collections::HashMap, marker::PhantomData, sync::Arc, time::Duration}; #[derive(Debug, thiserror::Error)] pub enum Error { @@ -358,8 +355,8 @@ where let inner_seal = fetch_seal::(block.post_digests.last(), block.header.hash())?; - let intermediate = - block.take_intermediate::>(INTERMEDIATE_KEY)?; + let intermediate = block + .remove_intermediate::>(INTERMEDIATE_KEY)?; let difficulty = match intermediate.difficulty { Some(difficulty) => difficulty, @@ -455,9 +452,7 @@ where let intermediate = PowIntermediate:: { difficulty: None }; block.header = checked_header; block.post_digests.push(seal); - block - .intermediates - .insert(Cow::from(INTERMEDIATE_KEY), Box::new(intermediate) as Box<_>); + block.insert_intermediate(INTERMEDIATE_KEY, intermediate); block.post_hash = Some(hash); Ok((block, None)) diff --git a/client/consensus/pow/src/worker.rs b/client/consensus/pow/src/worker.rs index 750e78cd9a038..a00da6e7022fb 100644 --- a/client/consensus/pow/src/worker.rs +++ b/client/consensus/pow/src/worker.rs @@ -32,7 +32,6 @@ use sp_runtime::{ DigestItem, }; use std::{ - borrow::Cow, collections::HashMap, pin::Pin, sync::{ @@ -212,10 +211,7 @@ where let intermediate = PowIntermediate:: { difficulty: Some(build.metadata.difficulty), }; - - import_block - .intermediates - .insert(Cow::from(INTERMEDIATE_KEY), Box::new(intermediate) as Box<_>); + import_block.insert_intermediate(INTERMEDIATE_KEY, intermediate); let header = import_block.post_header(); let mut block_import = self.block_import.lock(); From ae4ba19c12e4fad5368558b2c49688256b15c9ba Mon Sep 17 00:00:00 2001 From: Koute Date: Wed, 21 Sep 2022 19:21:01 +0900 Subject: [PATCH 1186/1472] Bump `wasmtime` to 1.0.0 (#12317) --- Cargo.lock | 120 ++++++++++++++------------- client/executor/wasmtime/Cargo.toml | 5 +- primitives/wasm-interface/Cargo.toml | 2 +- 3 files changed, 65 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5791c8762d955..5521e91de895d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1153,11 +1153,11 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.87.1" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f91425bea5a5ac6d76b788477064944a7e21f0e240fd93f6f368a774a3efdd1" +checksum = "b27bbd3e6c422cf6282b047bcdd51ecd9ca9f3497a3be0132ffa08e509b824b0" dependencies = [ - "cranelift-entity 0.87.1", + "cranelift-entity 0.88.0", ] [[package]] @@ -1179,14 +1179,16 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.87.1" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b83b4bbf7bc96db77b7b5b5e41fafc4001536e9f0cbfd702ed7d4d8f848dc06" +checksum = "872f5d4557a411b087bd731df6347c142ae1004e6467a144a7e33662e5715a01" dependencies = [ - "cranelift-bforest 0.87.1", - "cranelift-codegen-meta 0.87.1", - "cranelift-codegen-shared 0.87.1", - "cranelift-entity 0.87.1", + "arrayvec 0.7.2", + "bumpalo", + "cranelift-bforest 0.88.0", + "cranelift-codegen-meta 0.88.0", + "cranelift-codegen-shared 0.88.0", + "cranelift-entity 0.88.0", "cranelift-isle", "gimli 0.26.1", "log", @@ -1207,11 +1209,11 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.87.1" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da02e8fff048c381b313a3dfef4deb2343976fb6d7acc8e7d9c86d4c93e3fa06" +checksum = "21b49fdebb29c62c1fc4da1eeebd609e9d530ecde24a9876def546275f73a244" dependencies = [ - "cranelift-codegen-shared 0.87.1", + "cranelift-codegen-shared 0.88.0", ] [[package]] @@ -1222,9 +1224,9 @@ checksum = "9dabb5fe66e04d4652e434195b45ae65b5c8172d520247b8f66d8df42b2b45dc" [[package]] name = "cranelift-codegen-shared" -version = "0.87.1" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9abc2a06e8fc29e36660ebbc9e2503e18a051057072acbb1e75e7f7cf19cb95e" +checksum = "5fc0c091e2db055d4d7f6b7cec2d2ead286bcfaea3357c6a52c2a2613a8cb5ac" [[package]] name = "cranelift-entity" @@ -1234,9 +1236,9 @@ checksum = "3329733e4d4b8e91c809efcaa4faee80bf66f20164e3dd16d707346bd3494799" [[package]] name = "cranelift-entity" -version = "0.87.1" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeced7874890fc25d85cacc5e626c4d67931c7c25aad1c2ad521684744c1ff5c" +checksum = "354a9597be87996c9b278655e68b8447f65dd907256855ad773864edee8d985c" dependencies = [ "serde", ] @@ -1255,11 +1257,11 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.87.1" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1d301ccad6fce05d9c9793d433d225fafdd57661b98d268d8d162e9291ff2e" +checksum = "0cd8dd3fb8b82c772f4172e87ae1677b971676fffa7c4e3398e3047e650a266b" dependencies = [ - "cranelift-codegen 0.87.1", + "cranelift-codegen 0.88.0", "log", "smallvec", "target-lexicon", @@ -1267,34 +1269,34 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.87.1" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7b100db19320848986b4df1da19501dbddeb706a799f502222f72f889b0fab" +checksum = "b82527802b1f7d8da288adc28f1dc97ea52943f5871c041213f7b5035ac698a7" [[package]] name = "cranelift-native" -version = "0.87.1" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be18d8b976cddc822e52343f328b7593d26dd2f1aeadd90da071596a210d524" +checksum = "c30ba8b910f1be023af0c39109cb28a8809734942a6b3eecbf2de8993052ea5e" dependencies = [ - "cranelift-codegen 0.87.1", + "cranelift-codegen 0.88.0", "libc", "target-lexicon", ] [[package]] name = "cranelift-wasm" -version = "0.87.1" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9e48bb632a2e189b38a9fa89fa5a6eea687a5a4c613bbef7c2b7522c3ad0e0" +checksum = "776a8916d201894aca9637a20814f1e11abc62acd5cfbe0b4eb2e63922756971" dependencies = [ - "cranelift-codegen 0.87.1", - "cranelift-entity 0.87.1", - "cranelift-frontend 0.87.1", + "cranelift-codegen 0.88.0", + "cranelift-entity 0.88.0", + "cranelift-frontend 0.88.0", "itertools", "log", "smallvec", - "wasmparser 0.88.0", + "wasmparser 0.89.1", "wasmtime-types", ] @@ -11858,18 +11860,18 @@ checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" [[package]] name = "wasmparser" -version = "0.88.0" +version = "0.89.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8cf7dd82407fe68161bedcd57fde15596f32ebf6e9b3bdbf3ae1da20e38e5e" +checksum = "ab5d3e08b13876f96dd55608d03cd4883a0545884932d5adf11925876c96daef" dependencies = [ "indexmap", ] [[package]] name = "wasmtime" -version = "0.40.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a020a3f6587fa7a7d98a021156177735ebb07212a6239a85ab5f14b2f728508f" +checksum = "8a10dc9784d8c3a33c970e3939180424955f08af2e7f20368ec02685a0e8f065" dependencies = [ "anyhow", "bincode", @@ -11884,7 +11886,7 @@ dependencies = [ "rayon", "serde", "target-lexicon", - "wasmparser 0.88.0", + "wasmparser 0.89.1", "wasmtime-cache", "wasmtime-cranelift", "wasmtime-environ", @@ -11895,18 +11897,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "0.40.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed4ada1fdd4d9a2aa37be652abcc31ae3188ad0efcefb4571ef4f785be2d777" +checksum = "ee4dbdc6daf68528cad1275ac91e3f51848ce9824385facc94c759f529decdf8" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "wasmtime-cache" -version = "0.40.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96a03a5732ef39b83943d9d72de8ac2d58623d3bfaaea4d9a92aea5fcd9acf5" +checksum = "9f507f3fa1ee1b2f9a83644e2514242b1dfe580782c0eb042f1ef70255bc4ffe" dependencies = [ "anyhow", "base64", @@ -11924,14 +11926,14 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "0.40.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc59c28fe895112db09e262fb9c483f9e7b82c78a82a6ded69567ccc0e9795b" +checksum = "8f03cf79d982fc68e94ba0bea6a300a3b94621c4eb9705eece0a4f06b235a3b5" dependencies = [ "anyhow", - "cranelift-codegen 0.87.1", - "cranelift-entity 0.87.1", - "cranelift-frontend 0.87.1", + "cranelift-codegen 0.88.0", + "cranelift-entity 0.88.0", + "cranelift-frontend 0.88.0", "cranelift-native", "cranelift-wasm", "gimli 0.26.1", @@ -11939,18 +11941,18 @@ dependencies = [ "object 0.29.0", "target-lexicon", "thiserror", - "wasmparser 0.88.0", + "wasmparser 0.89.1", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.40.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11086e573d2635a45ac0d44697a8e4586e058cf1b190f76bea466ca2ec36c30a" +checksum = "5c587c62e91c5499df62012b87b88890d0eb470b2ffecc5964e9da967b70c77c" dependencies = [ "anyhow", - "cranelift-entity 0.87.1", + "cranelift-entity 0.88.0", "gimli 0.26.1", "indexmap", "log", @@ -11958,15 +11960,15 @@ dependencies = [ "serde", "target-lexicon", "thiserror", - "wasmparser 0.88.0", + "wasmparser 0.89.1", "wasmtime-types", ] [[package]] name = "wasmtime-jit" -version = "0.40.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5444a78b74144718633f8642eccd7c4858f4c6f0c98ae6a3668998adf177ba2" +checksum = "047839b5dabeae5424a078c19b8cc897e5943a7fadc69e3d888b9c9a897666b3" dependencies = [ "addr2line", "anyhow", @@ -11989,9 +11991,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" -version = "0.40.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2bf6a667d2a29b2b0ed42bcf7564f00c595d92c24acb4d241c7c4d950b1910c" +checksum = "b299569abf6f99b7b8e020afaf84a700e8636c6a42e242069267322cd5818235" dependencies = [ "object 0.29.0", "once_cell", @@ -12000,9 +12002,9 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "0.40.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee064ce7b563cc201cdf3bb1cc4b233f386d8c57a96e55f4c4afe6103f4bd6a1" +checksum = "ae79e0515160bd5abee5df50a16c4eb8db9f71b530fc988ae1d9ce34dcb8dd01" dependencies = [ "anyhow", "cc", @@ -12025,14 +12027,14 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "0.40.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e104bd9e625181d53ead85910bbc0863aa5f0c6ef96836fe9a5cc65da11b69" +checksum = "790cf43ee8e2d5dad1780af30f00d7a972b74725fb1e4f90c28d62733819b185" dependencies = [ - "cranelift-entity 0.87.1", + "cranelift-entity 0.88.0", "serde", "thiserror", - "wasmparser 0.88.0", + "wasmparser 0.89.1", ] [[package]] diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 94ad25bdc948c..fc6d5db14aa1d 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -21,7 +21,7 @@ parity-wasm = "0.45" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! -wasmtime = { version = "0.40.1", default-features = false, features = [ +wasmtime = { version = "1.0.0", default-features = false, features = [ "cache", "cranelift", "jitdump", @@ -35,7 +35,8 @@ sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime- sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-wasm-interface = { version = "6.0.0", features = ["wasmtime"], path = "../../../primitives/wasm-interface" } -# Here we include the rustix crate used by wasmtime just to enable its 'use-libc' flag. +# Here we include the rustix crate in the exactly same semver-compatible version as used by +# wasmtime and enable its 'use-libc' flag. # # By default rustix directly calls the appropriate syscalls completely bypassing libc; # this doesn't have any actual benefits for us besides making it harder to debug memory diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 05ccad88ec37a..d61c74f20222c 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } wasmi = { version = "0.13", optional = true } -wasmtime = { version = "0.40.1", default-features = false, optional = true } +wasmtime = { version = "1.0.0", default-features = false, optional = true } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] From be976154078ae8df932802f32350bfaff78a1e57 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 21 Sep 2022 13:08:56 +0200 Subject: [PATCH 1187/1472] Format templates and fix `--steps` default value (#12286) * Cleaup imports Signed-off-by: Oliver Tale-Yazdi * Format template Signed-off-by: Oliver Tale-Yazdi * Set steps min value to two Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- .../benchmarking-cli/src/overhead/weights.hbs | 21 ++++++++++++++----- .../frame/benchmarking-cli/src/pallet/mod.rs | 2 +- .../benchmarking-cli/src/pallet/template.hbs | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index 86b2c0b0e0cdb..8d1a369372721 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -39,7 +39,6 @@ parameter_types! { #[cfg(test)] mod test_weights { - use super::*; use sp_weights::constants; /// Checks that the weight exists and is sane. @@ -51,14 +50,26 @@ mod test_weights { {{#if (eq short_name "block")}} // At least 100 µs. - assert!(w.ref_time() >= 100u64 * constants::WEIGHT_PER_MICROS.ref_time(), "Weight should be at least 100 µs."); + assert!( + w.ref_time() >= 100u64 * constants::WEIGHT_PER_MICROS.ref_time(), + "Weight should be at least 100 µs." + ); // At most 50 ms. - assert!(w.ref_time() <= 50u64 * constants::WEIGHT_PER_MILLIS.ref_time(), "Weight should be at most 50 ms."); + assert!( + w.ref_time() <= 50u64 * constants::WEIGHT_PER_MILLIS.ref_time(), + "Weight should be at most 50 ms." + ); {{else}} // At least 10 µs. - assert!(w.ref_time() >= 10u64 * constants::WEIGHT_PER_MICROS.ref_time(), "Weight should be at least 10 µs."); + assert!( + w.ref_time() >= 10u64 * constants::WEIGHT_PER_MICROS.ref_time(), + "Weight should be at least 10 µs." + ); // At most 1 ms. - assert!(w.ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Weight should be at most 1 ms."); + assert!( + w.ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + "Weight should be at most 1 ms." + ); {{/if}} } } diff --git a/utils/frame/benchmarking-cli/src/pallet/mod.rs b/utils/frame/benchmarking-cli/src/pallet/mod.rs index 7beaf321a2927..b8c1f7b905c0c 100644 --- a/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -43,7 +43,7 @@ pub struct PalletCmd { pub extrinsic: Option, /// Select how many samples we should take across the variable components. - #[clap(short, long, default_value = "1")] + #[clap(short, long, default_value = "2")] pub steps: u32, /// Indicates lowest values for each of the component ranges. diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index 6e016c47ef010..fbe435edf8fc3 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -15,7 +15,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight}}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; /// Weight functions for `{{pallet}}`. From 493b58bd4a475080d428ce47193ee9ea9757a808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 21 Sep 2022 19:31:22 +0200 Subject: [PATCH 1188/1472] Make automatic storage deposits resistant against changing deposit prices (#12083) * Require `FixedPointOperand` for Balances * Delay deposit calculation * Make refunds pro rata of consumed storage * Add storage migration * Fix clippy * Add liquidity checks * Fixe delayed deposit limit enforcement * Defer charges * Import Vec * Add try-runtime hooks for migration * Fix warning * Adapt to new OnRuntimeUpgrade trait * Apply suggestions from code review Co-authored-by: Sasha Gryaznov * fmt * Apply suggestions from code review Co-authored-by: Sasha Gryaznov * More suggestions from code review Co-authored-by: Sasha Gryaznov --- bin/node/runtime/src/lib.rs | 1 + frame/balances/src/lib.rs | 5 +- .../fixtures/create_storage_and_call.wat | 55 ++ frame/contracts/src/benchmarking/mod.rs | 18 +- frame/contracts/src/exec.rs | 23 +- frame/contracts/src/lib.rs | 33 +- frame/contracts/src/migration.rs | 198 ++++++- frame/contracts/src/storage.rs | 51 +- frame/contracts/src/storage/meter.rs | 495 ++++++++++-------- frame/contracts/src/tests.rs | 386 ++++++++++++-- frame/contracts/src/wasm/prepare.rs | 2 +- frame/support/src/traits/tokens/currency.rs | 4 +- 12 files changed, 958 insertions(+), 313 deletions(-) create mode 100644 frame/contracts/fixtures/create_storage_and_call.wat diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0d8f00550ed1a..d6a9798b4d9ca 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1706,6 +1706,7 @@ pub type Executive = frame_executive::Executive< type Migrations = ( pallet_nomination_pools::migration::v2::MigrateToV2, pallet_alliance::migration::Migration, + pallet_contracts::Migration, ); /// MMR helper types. diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 82d6f87dbde1a..4014efdd26e4e 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -185,7 +185,7 @@ use sp_runtime::{ AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedSub, MaybeSerializeDeserialize, Saturating, StaticLookup, Zero, }, - ArithmeticError, DispatchError, RuntimeDebug, + ArithmeticError, DispatchError, FixedPointOperand, RuntimeDebug, }; use sp_std::{cmp, fmt::Debug, mem, ops::BitOr, prelude::*, result}; pub use weights::WeightInfo; @@ -212,7 +212,8 @@ pub mod pallet { + MaybeSerializeDeserialize + Debug + MaxEncodedLen - + TypeInfo; + + TypeInfo + + FixedPointOperand; /// Handler for the unbalanced reduction when removing a dust account. type DustRemoval: OnUnbalanced>; diff --git a/frame/contracts/fixtures/create_storage_and_call.wat b/frame/contracts/fixtures/create_storage_and_call.wat new file mode 100644 index 0000000000000..2a1e53f7ce08a --- /dev/null +++ b/frame/contracts/fixtures/create_storage_and_call.wat @@ -0,0 +1,55 @@ +;; This calls another contract as passed as its account id. It also creates some storage. +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) + (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "deploy")) + + (func (export "call") + ;; store length of input buffer + (i32.store (i32.const 0) (i32.const 512)) + + ;; copy input at address 4 + (call $seal_input (i32.const 4) (i32.const 0)) + + ;; create 4 byte of storage before calling + (call $seal_set_storage + (i32.const 0) ;; Pointer to storage key + (i32.const 0) ;; Pointer to value + (i32.const 4) ;; Size of value + ) + + ;; call passed contract + (call $assert (i32.eqz + (call $seal_call + (i32.const 0) ;; No flags + (i32.const 8) ;; Pointer to "callee" address. + (i64.const 0) ;; How much gas to devote for the execution. 0 = all. + (i32.const 512) ;; Pointer to the buffer with value to transfer + (i32.const 4) ;; Pointer to input data buffer address + (i32.const 4) ;; Length of input data buffer + (i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + ) + )) + + ;; create 8 byte of storage after calling + ;; item of 12 bytes because we override 4 bytes + (call $seal_set_storage + (i32.const 0) ;; Pointer to storage key + (i32.const 0) ;; Pointer to value + (i32.const 12) ;; Size of value + ) + ) +) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 4a987fd8dde78..186ac6f63503e 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -87,7 +87,7 @@ where module: WasmModule, data: Vec, ) -> Result, &'static str> { - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); T::Currency::make_free_balance_be(&caller, caller_funding::()); let salt = vec![0xff]; let addr = Contracts::::contract_address(&caller, &module.hash, &salt); @@ -257,7 +257,7 @@ benchmarks! { let instance = Contract::::with_caller( whitelisted_caller(), WasmModule::sized(c, Location::Deploy), vec![], )?; - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); let origin = RawOrigin::Signed(instance.caller.clone()); let callee = instance.addr; }: call(origin, callee, value, Weight::MAX, None, vec![]) @@ -280,7 +280,7 @@ benchmarks! { let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let s in 0 .. code::max_pages::() * 64 * 1024; let salt = vec![42u8; s as usize]; - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); @@ -307,7 +307,7 @@ benchmarks! { instantiate { let s in 0 .. code::max_pages::() * 64 * 1024; let salt = vec![42u8; s as usize]; - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::dummy(); @@ -338,7 +338,7 @@ benchmarks! { let instance = Contract::::with_caller( whitelisted_caller(), WasmModule::dummy(), vec![], )?; - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); let origin = RawOrigin::Signed(instance.caller.clone()); let callee = instance.addr.clone(); let before = T::Currency::free_balance(&instance.account_id); @@ -767,13 +767,13 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into()); - assert_eq!(T::Currency::free_balance(&instance.account_id), T::Currency::minimum_balance()); + assert_eq!(T::Currency::free_balance(&instance.account_id), Pallet::::min_balance()); assert_ne!(T::Currency::reserved_balance(&instance.account_id), 0u32.into()); }: call(origin, instance.addr.clone(), 0u32.into(), Weight::MAX, None, vec![]) verify { if r > 0 { assert_eq!(T::Currency::total_balance(&instance.account_id), 0u32.into()); - assert_eq!(T::Currency::total_balance(&beneficiary), T::Currency::minimum_balance()); + assert_eq!(T::Currency::total_balance(&beneficiary), Pallet::::min_balance()); } } @@ -1469,7 +1469,7 @@ benchmarks! { .collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); let account_bytes = accounts.iter().flat_map(|x| x.encode()).collect(); - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); assert!(value > 0u32.into()); let value_bytes = value.encode(); let value_len = value_bytes.len(); @@ -1705,7 +1705,7 @@ benchmarks! { let hash_len = hashes.get(0).map(|x| x.encode().len()).unwrap_or(0); let hashes_bytes = hashes.iter().flat_map(|x| x.encode()).collect::>(); let hashes_len = hashes_bytes.len(); - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); assert!(value > 0u32.into()); let value_bytes = value.encode(); let value_len = value_bytes.len(); diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 38b47a915cddc..6260dd41de707 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -813,6 +813,15 @@ where return Ok(output) } + // Storage limit is enforced as late as possible (when the last frame returns) so that + // the ordering of storage accesses does not matter. + if self.frames.is_empty() { + let frame = &mut self.first_frame; + frame.contract_info.load(&frame.account_id); + let contract = frame.contract_info.as_contract(); + frame.nested_storage.enforce_limit(contract)?; + } + let frame = self.top_frame(); let account_id = &frame.account_id; match (entry_point, delegated_code_hash) { @@ -911,12 +920,7 @@ where // it was invalidated. frame.contract_info.load(account_id); let mut contract = frame.contract_info.into_contract(); - prev.nested_storage.absorb( - frame.nested_storage, - &self.origin, - account_id, - contract.as_mut(), - ); + prev.nested_storage.absorb(frame.nested_storage, account_id, contract.as_mut()); // In case the contract wasn't terminated we need to persist changes made to it. if let Some(contract) = contract { @@ -954,7 +958,6 @@ where let mut contract = self.first_frame.contract_info.as_contract(); self.storage_meter.absorb( mem::take(&mut self.first_frame.nested_storage), - &self.origin, &self.first_frame.account_id, contract.as_deref_mut(), ); @@ -2354,10 +2357,10 @@ mod tests { let code_bob = MockLoader::insert(Call, |ctx, _| { if ctx.input_data[0] == 0 { let info = ctx.ext.contract_info(); - assert_eq!(info.storage_deposit, 0); - info.storage_deposit = 42; + assert_eq!(info.storage_byte_deposit, 0); + info.storage_byte_deposit = 42; assert_eq!(ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], true), exec_trapped()); - assert_eq!(ctx.ext.contract_info().storage_deposit, 42); + assert_eq!(ctx.ext.contract_info().storage_byte_deposit, 42); } exec_success() }); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index abe91a9046ce2..fc44e4507ca00 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -87,12 +87,12 @@ mod gas; mod benchmarking; mod exec; +mod migration; mod schedule; mod storage; mod wasm; pub mod chain_extension; -pub mod migration; pub mod weights; #[cfg(test)] @@ -109,7 +109,10 @@ use codec::{Encode, HasCompact}; use frame_support::{ dispatch::{DispatchClass, Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, ensure, - traits::{ConstU32, Contains, Currency, Get, Randomness, ReservableCurrency, Time}, + traits::{ + tokens::fungible::Inspect, ConstU32, Contains, Currency, Get, Randomness, + ReservableCurrency, Time, + }, weights::Weight, BoundedVec, WeakBoundedVec, }; @@ -126,6 +129,7 @@ use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; pub use crate::{ exec::{Frame, VarSizedKey as StorageKey}, + migration::Migration, pallet::*, schedule::{HostFnWeights, InstructionWeights, Limits, Schedule}, }; @@ -225,7 +229,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(8); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -236,11 +240,12 @@ pub mod pallet { /// The time implementation used to supply timestamps to contracts through `seal_now`. type Time: Time; - /// The generator used to supply randomness to contracts through `seal_random`. + /// The generator used to supply randomness to contracts through `seal_random` type Randomness: Randomness; /// The currency in which fees are paid and contract balances are held. - type Currency: ReservableCurrency; + type Currency: ReservableCurrency + + Inspect>; /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -1036,7 +1041,7 @@ where }; let schedule = T::Schedule::get(); let result = ExecStack::>::run_call( - origin, + origin.clone(), dest, &mut gas_meter, &mut storage_meter, @@ -1045,7 +1050,11 @@ where data, debug_message, ); - InternalCallOutput { result, gas_meter, storage_deposit: storage_meter.into_deposit() } + InternalCallOutput { + result, + gas_meter, + storage_deposit: storage_meter.into_deposit(&origin), + } } /// Internal function that does the actual instantiation. @@ -1089,7 +1098,7 @@ where value.saturating_add(extra_deposit), )?; let result = ExecStack::>::run_instantiate( - origin, + origin.clone(), executable, &mut gas_meter, &mut storage_meter, @@ -1100,17 +1109,23 @@ where debug_message, ); storage_deposit = storage_meter - .into_deposit() + .into_deposit(&origin) .saturating_add(&StorageDeposit::Charge(extra_deposit)); result }; InternalInstantiateOutput { result: try_exec(), gas_meter, storage_deposit } } + /// Deposit a pallet contracts event. Handles the conversion to the overarching event type. fn deposit_event(topics: Vec, event: Event) { >::deposit_event_indexed( &topics, ::RuntimeEvent::from(event).into(), ) } + + /// Return the existential deposit of [`Config::Currency`]. + fn min_balance() -> BalanceOf { + >>::minimum_balance() + } } diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 0db285e81a91f..5ea821aac7682 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -18,37 +18,80 @@ use crate::{BalanceOf, CodeHash, Config, Pallet, TrieId, Weight}; use codec::{Decode, Encode}; use frame_support::{ - codec, pallet_prelude::*, storage::migration, storage_alias, traits::Get, Identity, - Twox64Concat, + codec, + pallet_prelude::*, + storage::migration, + storage_alias, + traits::{Get, OnRuntimeUpgrade}, + Identity, Twox64Concat, }; +use sp_runtime::traits::Saturating; use sp_std::{marker::PhantomData, prelude::*}; -/// Wrapper for all migrations of this pallet, based on `StorageVersion`. -pub fn migrate() -> Weight { - let version = StorageVersion::get::>(); - let mut weight = Weight::zero(); +/// Performs all necessary migrations based on `StorageVersion`. +pub struct Migration(PhantomData); +impl OnRuntimeUpgrade for Migration { + fn on_runtime_upgrade() -> Weight { + let version = StorageVersion::get::>(); + let mut weight = Weight::zero(); - if version < 4 { - weight = weight.saturating_add(v4::migrate::()); - StorageVersion::new(4).put::>(); - } + if version < 4 { + weight = weight.saturating_add(v4::migrate::()); + StorageVersion::new(4).put::>(); + } - if version < 5 { - weight = weight.saturating_add(v5::migrate::()); - StorageVersion::new(5).put::>(); - } + if version < 5 { + weight = weight.saturating_add(v5::migrate::()); + StorageVersion::new(5).put::>(); + } + + if version < 6 { + weight = weight.saturating_add(v6::migrate::()); + StorageVersion::new(6).put::>(); + } + + if version < 7 { + weight = weight.saturating_add(v7::migrate::()); + StorageVersion::new(7).put::>(); + } + + if version < 8 { + weight = weight.saturating_add(v8::migrate::()); + StorageVersion::new(8).put::>(); + } - if version < 6 { - weight = weight.saturating_add(v6::migrate::()); - StorageVersion::new(6).put::>(); + weight } - if version < 7 { - weight = weight.saturating_add(v7::migrate::()); - StorageVersion::new(7).put::>(); + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + let version = StorageVersion::get::>(); + + if version < 7 { + return Ok(vec![]) + } + + if version < 8 { + v8::pre_upgrade::()?; + } + + Ok(vec![]) } - weight + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + let version = StorageVersion::get::>(); + + if version < 7 { + return Ok(()) + } + + if version < 8 { + v8::post_upgrade::()?; + } + + Ok(()) + } } /// V4: `Schedule` is changed to be a config item rather than an in-storage value. @@ -185,9 +228,9 @@ mod v6 { #[derive(Encode, Decode)] pub struct RawContractInfo { - trie_id: TrieId, - code_hash: CodeHash, - storage_deposit: Balance, + pub trie_id: TrieId, + pub code_hash: CodeHash, + pub storage_deposit: Balance, } #[derive(Encode, Decode)] @@ -199,7 +242,7 @@ mod v6 { refcount: u64, } - type ContractInfo = RawContractInfo, BalanceOf>; + pub type ContractInfo = RawContractInfo, BalanceOf>; #[storage_alias] type ContractInfoOf = StorageMap< @@ -266,3 +309,108 @@ mod v7 { T::DbWeight::get().reads_writes(1, 2) } } + +/// Update `ContractInfo` with new fields that track storage deposits. +mod v8 { + use super::*; + use sp_io::default_child_storage as child; + use v6::ContractInfo as OldContractInfo; + + #[derive(Encode, Decode)] + struct ContractInfo { + trie_id: TrieId, + code_hash: CodeHash, + storage_bytes: u32, + storage_items: u32, + storage_byte_deposit: BalanceOf, + storage_item_deposit: BalanceOf, + storage_base_deposit: BalanceOf, + } + + #[storage_alias] + type ContractInfoOf = + StorageMap, Twox64Concat, ::AccountId, V>; + + pub fn migrate() -> Weight { + let mut weight = Weight::zero(); + + >>::translate_values(|old: OldContractInfo| { + // Count storage items of this contract + let mut storage_bytes = 0u32; + let mut storage_items = 0u32; + let mut key = Vec::new(); + while let Some(next) = child::next_key(&old.trie_id, &key) { + key = next; + let mut val_out = []; + let len = child::read(&old.trie_id, &key, &mut val_out, 0) + .expect("The loop conditions checks for existence of the key; qed"); + storage_bytes.saturating_accrue(len); + storage_items.saturating_accrue(1); + } + + let storage_byte_deposit = + T::DepositPerByte::get().saturating_mul(storage_bytes.into()); + let storage_item_deposit = + T::DepositPerItem::get().saturating_mul(storage_items.into()); + let storage_base_deposit = old + .storage_deposit + .saturating_sub(storage_byte_deposit) + .saturating_sub(storage_item_deposit); + + // Reads: One read for each storage item plus the contract info itself. + // Writes: Only the new contract info. + weight = weight + .saturating_add(T::DbWeight::get().reads_writes(u64::from(storage_items) + 1, 1)); + + Some(ContractInfo { + trie_id: old.trie_id, + code_hash: old.code_hash, + storage_bytes, + storage_items, + storage_byte_deposit, + storage_item_deposit, + storage_base_deposit, + }) + }); + + weight + } + + #[cfg(feature = "try-runtime")] + pub fn pre_upgrade() -> Result<(), &'static str> { + use frame_support::traits::ReservableCurrency; + for (key, value) in ContractInfoOf::>::iter() { + let reserved = T::Currency::reserved_balance(&key); + ensure!(reserved >= value.storage_deposit, "Reserved balance out of sync."); + } + Ok(()) + } + + #[cfg(feature = "try-runtime")] + pub fn post_upgrade() -> Result<(), &'static str> { + use frame_support::traits::ReservableCurrency; + for (key, value) in ContractInfoOf::>::iter() { + let reserved = T::Currency::reserved_balance(&key); + let stored = value + .storage_base_deposit + .saturating_add(value.storage_byte_deposit) + .saturating_add(value.storage_item_deposit); + ensure!(reserved >= stored, "Reserved balance out of sync."); + + let mut storage_bytes = 0u32; + let mut storage_items = 0u32; + let mut key = Vec::new(); + while let Some(next) = child::next_key(&value.trie_id, &key) { + key = next; + let mut val_out = []; + let len = child::read(&value.trie_id, &key, &mut val_out, 0) + .expect("The loop conditions checks for existence of the key; qed"); + storage_bytes.saturating_accrue(len); + storage_items.saturating_accrue(1); + } + ensure!(storage_bytes == value.storage_bytes, "Storage bytes do not match.",); + ensure!(storage_items == value.storage_items, "Storage items do not match.",); + } + Ok(()) + } +} diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index ec49a6325c125..c3fc0840d8649 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -34,31 +34,51 @@ use scale_info::TypeInfo; use sp_core::crypto::UncheckedFrom; use sp_io::KillStorageResult; use sp_runtime::{ - traits::{Hash, Zero}, + traits::{Hash, Saturating, Zero}, RuntimeDebug, }; use sp_std::{marker::PhantomData, prelude::*}; -pub type ContractInfo = RawContractInfo, BalanceOf>; - /// Information for managing an account and its sub trie abstraction. /// This is the required info to cache for an account. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct RawContractInfo { +#[scale_info(skip_type_params(T))] +pub struct ContractInfo { /// Unique ID for the subtree encoded as a bytes vector. pub trie_id: TrieId, /// The code associated with a given account. - pub code_hash: CodeHash, - /// The amount of balance that is currently deposited to pay for consumed storage. - pub storage_deposit: Balance, + pub code_hash: CodeHash, + /// How many bytes of storage are accumulated in this contract's child trie. + pub storage_bytes: u32, + /// How many items of storage are accumulated in this contract's child trie. + pub storage_items: u32, + /// This records to how much deposit the accumulated `storage_bytes` amount to. + pub storage_byte_deposit: BalanceOf, + /// This records to how much deposit the accumulated `storage_items` amount to. + pub storage_item_deposit: BalanceOf, + /// This records how much deposit is put down in order to pay for the contract itself. + /// + /// We need to store this information separately so it is not used when calculating any refunds + /// since the base deposit can only ever be refunded on contract termination. + pub storage_base_deposit: BalanceOf, } -impl RawContractInfo { +impl ContractInfo { /// Associated child trie unique id is built from the hash part of the trie id. #[cfg(test)] pub fn child_trie_info(&self) -> ChildInfo { child_trie_info(&self.trie_id[..]) } + + /// The deposit paying for the accumulated storage generated within the contract's child trie. + pub fn extra_deposit(&self) -> BalanceOf { + self.storage_byte_deposit.saturating_add(self.storage_item_deposit) + } + + /// Same as [`Self::extra_deposit`] but including the base deposit. + pub fn total_deposit(&self) -> BalanceOf { + self.extra_deposit().saturating_add(self.storage_base_deposit) + } } /// Associated child trie unique id is built from the hash part of the trie id. @@ -178,7 +198,7 @@ where }, (None, None) => (), } - storage_meter.charge(&diff)?; + storage_meter.charge(&diff); } match &new_value { @@ -200,14 +220,21 @@ where pub fn new_contract( account: &AccountIdOf, trie_id: TrieId, - ch: CodeHash, + code_hash: CodeHash, ) -> Result, DispatchError> { if >::contains_key(account) { return Err(Error::::DuplicateContract.into()) } - let contract = - ContractInfo:: { code_hash: ch, trie_id, storage_deposit: >::zero() }; + let contract = ContractInfo:: { + code_hash, + trie_id, + storage_bytes: 0, + storage_items: 0, + storage_byte_deposit: Zero::zero(), + storage_item_deposit: Zero::zero(), + storage_base_deposit: Zero::zero(), + }; Ok(contract) } diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index d89208812bcac..0a63eb42b86cb 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -17,17 +17,24 @@ //! This module contains functions to meter the storage deposit. -use crate::{storage::ContractInfo, BalanceOf, Config, Error}; +use crate::{storage::ContractInfo, BalanceOf, Config, Error, Inspect, Pallet}; use codec::Encode; use frame_support::{ dispatch::DispatchError, - traits::{tokens::BalanceStatus, Currency, ExistenceRequirement, Get, ReservableCurrency}, - DefaultNoBound, + ensure, + traits::{ + tokens::{BalanceStatus, WithdrawConsequence}, + Currency, ExistenceRequirement, Get, ReservableCurrency, + }, + DefaultNoBound, RuntimeDebugNoBound, }; use pallet_contracts_primitives::StorageDeposit as Deposit; use sp_core::crypto::UncheckedFrom; -use sp_runtime::traits::{Saturating, Zero}; -use sp_std::marker::PhantomData; +use sp_runtime::{ + traits::{Saturating, Zero}, + FixedPointNumber, FixedU128, +}; +use sp_std::{marker::PhantomData, vec::Vec}; /// Deposit that uses the native currency's balance type. pub type DepositOf = Deposit>; @@ -99,22 +106,25 @@ impl State for Root {} impl State for Nested {} /// A type that allows the metering of consumed or freed storage of a single contract call stack. -#[derive(DefaultNoBound)] -pub struct RawMeter, S: State> { +#[derive(DefaultNoBound, RuntimeDebugNoBound)] +pub struct RawMeter { /// The limit of how much balance this meter is allowed to consume. limit: BalanceOf, /// The amount of balance that was used in this meter and all of its already absorbed children. total_deposit: DepositOf, - /// The amount of balance that was used in this meter alone. - own_deposit: DepositOf, - /// Only when a contract was terminated we allow it to drop below the minimum balance. - terminated: bool, + /// The amount of storage changes that were recorded in this meter alone. + own_contribution: Contribution, + /// List of charges that should be applied at the end of a contract stack execution. + /// + /// We only have one charge per contract hence the size of this vector is + /// limited by the maximum call depth. + charges: Vec>, /// Type parameters are only used in impls. _phantom: PhantomData<(E, S)>, } /// This type is used to describe a storage change when charging from the meter. -#[derive(Default)] +#[derive(Default, RuntimeDebugNoBound)] pub struct Diff { /// How many bytes were added to storage. pub bytes_added: u32, @@ -124,43 +134,120 @@ pub struct Diff { pub items_added: u32, /// How many storage items were removed from storage. pub items_removed: u32, - /// If set to true the derived deposit will always a `Charge` larger than the - /// the existential deposit. - pub require_ed: bool, } impl Diff { - /// Calculate how much of a charge or refund results from applying the diff. - pub fn to_deposit(&self) -> DepositOf { - let mut deposit = Deposit::default(); + /// Calculate how much of a charge or refund results from applying the diff and store it + /// in the passed `info` if any. + /// + /// # Note + /// + /// In case `None` is passed for `info` only charges are calculated. This is because refunds + /// are calculated pro rata of the existing storage within a contract and hence need extract + /// this information from the passed `info`. + pub fn update_contract(&self, info: Option<&mut ContractInfo>) -> DepositOf { let per_byte = T::DepositPerByte::get(); let per_item = T::DepositPerItem::get(); + let bytes_added = self.bytes_added.saturating_sub(self.bytes_removed); + let items_added = self.items_added.saturating_sub(self.items_removed); + let mut bytes_deposit = Deposit::Charge(per_byte.saturating_mul((bytes_added).into())); + let mut items_deposit = Deposit::Charge(per_item.saturating_mul((items_added).into())); + + // Without any contract info we can only calculate diffs which add storage + let info = if let Some(info) = info { + info + } else { + debug_assert_eq!(self.bytes_removed, 0); + debug_assert_eq!(self.items_removed, 0); + return bytes_deposit.saturating_add(&items_deposit) + }; - if self.bytes_added > self.bytes_removed { - deposit = deposit.saturating_add(&Deposit::Charge( - per_byte.saturating_mul((self.bytes_added - self.bytes_removed).into()), - )); - } else if self.bytes_removed > self.bytes_added { - deposit = deposit.saturating_add(&Deposit::Refund( - per_byte.saturating_mul((self.bytes_removed - self.bytes_added).into()), - )); + // Refunds are calculated pro rata based on the accumulated storage within the contract + let bytes_removed = self.bytes_removed.saturating_sub(self.bytes_added); + let items_removed = self.items_removed.saturating_sub(self.items_added); + let ratio = FixedU128::checked_from_rational(bytes_removed, info.storage_bytes) + .unwrap_or_default() + .min(FixedU128::from_u32(1)); + bytes_deposit = bytes_deposit + .saturating_add(&Deposit::Refund(ratio.saturating_mul_int(info.storage_byte_deposit))); + let ratio = FixedU128::checked_from_rational(items_removed, info.storage_items) + .unwrap_or_default() + .min(FixedU128::from_u32(1)); + items_deposit = items_deposit + .saturating_add(&Deposit::Refund(ratio.saturating_mul_int(info.storage_item_deposit))); + + // We need to update the contract info structure with the new deposits + info.storage_bytes = + info.storage_bytes.saturating_add(bytes_added).saturating_sub(bytes_removed); + info.storage_items = + info.storage_items.saturating_add(items_added).saturating_sub(items_removed); + match &bytes_deposit { + Deposit::Charge(amount) => + info.storage_byte_deposit = info.storage_byte_deposit.saturating_add(*amount), + Deposit::Refund(amount) => + info.storage_byte_deposit = info.storage_byte_deposit.saturating_sub(*amount), } + match &items_deposit { + Deposit::Charge(amount) => + info.storage_item_deposit = info.storage_item_deposit.saturating_add(*amount), + Deposit::Refund(amount) => + info.storage_item_deposit = info.storage_item_deposit.saturating_sub(*amount), + } + + bytes_deposit.saturating_add(&items_deposit) + } +} - if self.items_added > self.items_removed { - deposit = deposit.saturating_add(&Deposit::Charge( - per_item.saturating_mul((self.items_added - self.items_removed).into()), - )); - } else if self.items_removed > self.items_added { - deposit = deposit.saturating_add(&Deposit::Refund( - per_item.saturating_mul((self.items_removed - self.items_added).into()), - )); +impl Diff { + fn saturating_add(&self, rhs: &Self) -> Self { + Self { + bytes_added: self.bytes_added.saturating_add(rhs.bytes_added), + bytes_removed: self.bytes_removed.saturating_add(rhs.bytes_removed), + items_added: self.items_added.saturating_add(rhs.items_added), + items_removed: self.items_removed.saturating_add(rhs.items_removed), } + } +} + +/// Records information to charge or refund a plain account. +/// +/// All the charges are deferred to the end of a whole call stack. Reason is that by doing +/// this we can do all the refunds before doing any charge. This way a plain account can use +/// more deposit than it has balance as along as it is covered by a refund. This +/// essentially makes the order of storage changes irrelevant with regard to the deposit system. +#[derive(RuntimeDebugNoBound, Clone)] +struct Charge { + contract: T::AccountId, + amount: DepositOf, + terminated: bool, +} + +/// Records the storage changes of a storage meter. +#[derive(RuntimeDebugNoBound)] +enum Contribution { + /// The contract the meter belongs to is alive and accumulates changes using a [`Diff`]. + Alive(Diff), + /// The meter was checked against its limit using [`RawMeter::enforce_limit`] at the end of + /// its execution. In this process the [`Diff`] was converted into a [`Deposit`]. + Checked(DepositOf), + /// The contract was terminated. In this process the [`Diff`] was converted into a [`Deposit`] + /// in order to calculate the refund. + Terminated(DepositOf), +} - if self.require_ed { - deposit = deposit.max(Deposit::Charge(T::Currency::minimum_balance())) +impl Contribution { + /// See [`Diff::update_contract`]. + fn update_contract(&self, info: Option<&mut ContractInfo>) -> DepositOf { + match self { + Self::Alive(diff) => diff.update_contract::(info), + Self::Terminated(deposit) | Self::Checked(deposit) => deposit.clone(), } + } +} - deposit +impl Default for Contribution { + fn default() -> Self { + Self::Alive(Default::default()) } } @@ -178,6 +265,7 @@ where /// usage for this sub call separately. This is necessary because we want to exchange balance /// with the current contract we are interacting with. pub fn nested(&self) -> RawMeter { + debug_assert!(self.is_alive()); RawMeter { limit: self.available(), ..Default::default() } } @@ -192,45 +280,28 @@ where /// /// # Parameters /// - /// `absorbed`: The child storage meter that should be absorbed. - /// `origin`: The origin that spawned the original root meter. - /// `contract`: The contract that this sub call belongs to. - /// `info`: The info of the contract in question. `None` if the contract was terminated. + /// - `absorbed`: The child storage meter that should be absorbed. + /// - `origin`: The origin that spawned the original root meter. + /// - `contract`: The contract that this sub call belongs to. + /// - `info`: The info of the contract in question. `None` if the contract was terminated. pub fn absorb( &mut self, - mut absorbed: RawMeter, - origin: &T::AccountId, + absorbed: RawMeter, contract: &T::AccountId, info: Option<&mut ContractInfo>, ) { - // Absorbing from an existing (non terminated) contract. - if let Some(info) = info { - match &mut absorbed.own_deposit { - Deposit::Charge(amount) => - info.storage_deposit = info.storage_deposit.saturating_add(*amount), - Deposit::Refund(amount) => { - // We need to make sure to never refund more than what was deposited and - // still leave the existential deposit inside the contract's account. - // This case can happen when costs change due to a runtime upgrade where - // increased costs could remove an account due to refunds. - let amount = { - let corrected_amount = (*amount).min( - info.storage_deposit.saturating_sub(T::Currency::minimum_balance()), - ); - let correction = (*amount).saturating_sub(corrected_amount); - absorbed.total_deposit = - absorbed.total_deposit.saturating_sub(&Deposit::Refund(correction)); - *amount = corrected_amount; - corrected_amount - }; - info.storage_deposit = info.storage_deposit.saturating_sub(amount); - }, - } - } - - self.total_deposit = self.total_deposit.saturating_add(&absorbed.total_deposit); - if !absorbed.own_deposit.is_zero() { - E::charge(origin, contract, &absorbed.own_deposit, absorbed.terminated); + let own_deposit = absorbed.own_contribution.update_contract(info); + self.total_deposit = self + .total_deposit + .saturating_add(&absorbed.total_deposit) + .saturating_add(&own_deposit); + if !own_deposit.is_zero() { + self.charges.extend_from_slice(&absorbed.charges); + self.charges.push(Charge { + contract: contract.clone(), + amount: own_deposit, + terminated: absorbed.is_terminated(), + }); } } @@ -238,6 +309,16 @@ where fn available(&self) -> BalanceOf { self.total_deposit.available(&self.limit) } + + /// True if the contract is alive. + fn is_alive(&self) -> bool { + matches!(self.own_contribution, Contribution::Alive(_)) + } + + /// True if the contract is terminated. + fn is_terminated(&self) -> bool { + matches!(self.own_contribution, Contribution::Terminated(_)) + } } /// Functions that only apply to the root state. @@ -260,11 +341,18 @@ where } /// The total amount of deposit that should change hands as result of the execution - /// that this meter was passed into. + /// that this meter was passed into. This will also perform all the charges accumulated + /// in the whole contract stack. /// /// This drops the root meter in order to make sure it is only called when the whole /// execution did finish. - pub fn into_deposit(self) -> DepositOf { + pub fn into_deposit(self, origin: &T::AccountId) -> DepositOf { + for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Refund(_))) { + E::charge(origin, &charge.contract, &charge.amount, charge.terminated); + } + for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Charge(_))) { + E::charge(origin, &charge.contract, &charge.amount, charge.terminated); + } self.total_deposit } } @@ -277,18 +365,12 @@ where E: Ext, { /// Try to charge the `diff` from the meter. Fails if this would exceed the original limit. - pub fn charge(&mut self, diff: &Diff) -> Result, DispatchError> { - debug_assert!(!self.terminated); - let deposit = diff.to_deposit::(); - let total_deposit = self.total_deposit.saturating_add(&deposit); - if let Deposit::Charge(amount) = total_deposit { - if amount > self.limit { - return Err(>::StorageDepositLimitExhausted.into()) - } - } - self.total_deposit = total_deposit; - self.own_deposit = self.own_deposit.saturating_add(&deposit); - Ok(deposit) + pub fn charge(&mut self, diff: &Diff) { + debug_assert!(self.is_alive()); + match &mut self.own_contribution { + Contribution::Alive(own) => *own = own.saturating_add(diff), + _ => panic!("Charge is never called after termination; qed"), + }; } /// Charge from `origin` a storage deposit for contract instantiation. @@ -300,25 +382,22 @@ where contract: &T::AccountId, info: &mut ContractInfo, ) -> Result, DispatchError> { - debug_assert!(!self.terminated); - let deposit = Diff { - bytes_added: info.encoded_size() as u32, - items_added: 1, - require_ed: true, - ..Default::default() + debug_assert!(self.is_alive()); + let mut deposit = + Diff { bytes_added: info.encoded_size() as u32, items_added: 1, ..Default::default() } + .update_contract::(None); + + // Instantiate needs to transfer the minimum balance at least in order to pull the + // contract's account into existence. + deposit = deposit.max(Deposit::Charge(Pallet::::min_balance())); + if deposit.charge_or_zero() > self.limit { + return Err(>::StorageDepositLimitExhausted.into()) } - .to_deposit::(); - debug_assert!(matches!(deposit, Deposit::Charge(_))); - // We do not increase `own_deposit` because this will be charged later when the contract - // execution does conclude. - let total_deposit = self.total_deposit.saturating_add(&deposit); - if let Deposit::Charge(amount) = &total_deposit { - if amount > &self.limit { - return Err(>::StorageDepositLimitExhausted.into()) - } - } - info.storage_deposit = info.storage_deposit.saturating_add(deposit.charge_or_zero()); - self.total_deposit = total_deposit; + + // We do not increase `own_contribution` because this will be charged later when the + // contract execution does conclude and hence would lead to a double charge. + self.total_deposit = deposit.clone(); + info.storage_base_deposit = deposit.charge_or_zero(); if !deposit.is_zero() { // We need to charge immediately so that the account is created before the `value` // is transferred from the caller to the contract. @@ -331,34 +410,55 @@ where /// /// This will manipulate the meter so that all storage deposit accumulated in /// `contract_info` will be refunded to the `origin` of the meter. - pub fn terminate(&mut self, contract_info: &ContractInfo) { - debug_assert!(!self.terminated); - let refund = Deposit::Refund(contract_info.storage_deposit); - - // The deposit for `own_deposit` isn't persisted into the contract info until the current - // frame is dropped. This means that whatever changes were introduced during the - // current frame are dicarded when terminating. - self.total_deposit = - self.total_deposit.saturating_add(&refund).saturating_sub(&self.own_deposit); - self.own_deposit = refund; - self.terminated = true; + pub fn terminate(&mut self, info: &ContractInfo) { + debug_assert!(self.is_alive()); + self.own_contribution = Contribution::Terminated(Deposit::Refund(info.total_deposit())); + } + + /// [`Self::charge`] does not enforce the storage limit since we want to do this check as late + /// as possible to allow later refunds to offset earlier charges. + /// + /// # Note + /// + /// We only need to call this **once** for every call stack and not for every cross contract + /// call. Hence this is only called when the last call frame returns. + pub fn enforce_limit( + &mut self, + info: Option<&mut ContractInfo>, + ) -> Result<(), DispatchError> { + let deposit = self.own_contribution.update_contract(info); + let total_deposit = self.total_deposit.saturating_add(&deposit); + // We don't want to override a `Terminated` with a `Checked`. + if self.is_alive() { + self.own_contribution = Contribution::Checked(deposit); + } + if let Deposit::Charge(amount) = total_deposit { + if amount > self.limit { + return Err(>::StorageDepositLimitExhausted.into()) + } + } + Ok(()) } } -impl Ext for ReservingExt { +impl Ext for ReservingExt +where + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]>, +{ fn check_limit( origin: &T::AccountId, limit: Option>, min_leftover: BalanceOf, ) -> Result, DispatchError> { - let max = T::Currency::free_balance(origin) - .saturating_sub(T::Currency::minimum_balance()) - .saturating_sub(min_leftover); - match limit { - Some(limit) if limit <= max => Ok(limit), - None => Ok(max), - _ => Err(>::StorageDepositNotEnoughFunds.into()), - } + let max = T::Currency::reducible_balance(origin, true).saturating_sub(min_leftover); + let limit = limit.unwrap_or(max); + ensure!( + limit <= max && + matches!(T::Currency::can_withdraw(origin, limit), WithdrawConsequence::Success), + >::StorageDepositNotEnoughFunds, + ); + Ok(limit) } fn charge( @@ -393,6 +493,9 @@ impl Ext for ReservingExt { "Failed to transfer storage deposit {:?} from origin {:?} to contract {:?}: {:?}", amount, origin, contract, err, ); + if cfg!(debug_assertions) { + panic!("Unable to collect storage deposit. This is a bug."); + } } }, // For `Refund(_)` no error happen because the initial value transfer from the @@ -411,7 +514,7 @@ impl Ext for ReservingExt { // refund because we consider this unexpected behaviour. *amount.min( &T::Currency::reserved_balance(contract) - .saturating_sub(T::Currency::minimum_balance()), + .saturating_sub(Pallet::::min_balance()), ) }; let result = @@ -422,6 +525,9 @@ impl Ext for ReservingExt { "Failed to repatriate storage deposit {:?} from contract {:?} to origin {:?}: {:?}", amount, contract, origin, result, ); + if cfg!(debug_assertions) { + panic!("Unable to refund storage deposit. This is a bug."); + } } }, }; @@ -513,14 +619,26 @@ mod tests { TestExtTestValue::mutate(|ext| ext.clear()) } - fn new_info(deposit: BalanceOf) -> ContractInfo { + #[derive(Default)] + struct StorageInfo { + bytes: u32, + items: u32, + bytes_deposit: BalanceOf, + items_deposit: BalanceOf, + } + + fn new_info(info: StorageInfo) -> ContractInfo { use crate::storage::Storage; use sp_runtime::traits::Hash; ContractInfo:: { trie_id: >::generate_trie_id(&ALICE, 42), code_hash: ::Hashing::hash(b"42"), - storage_deposit: deposit, + storage_bytes: info.bytes, + storage_items: info.items, + storage_byte_deposit: info.bytes_deposit, + storage_item_deposit: info.items_deposit, + storage_base_deposit: Default::default(), } } @@ -548,8 +666,8 @@ mod tests { // an empty charge does not create a `Charge` entry let mut nested0 = meter.nested(); - nested0.charge(&Default::default()).unwrap(); - meter.absorb(nested0, &ALICE, &BOB, None); + nested0.charge(&Default::default()); + meter.absorb(nested0, &BOB, None); assert_eq!( TestExtTestValue::get(), @@ -560,79 +678,49 @@ mod tests { ) } - #[test] - fn existential_deposit_works() { - clear_ext(); - - let mut meter = TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); - assert_eq!(meter.available(), 1_000); - - // a `Refund` will be turned into a `Charge(ed)` which is intended behaviour - let mut nested0 = meter.nested(); - nested0.charge(&Diff { require_ed: true, ..Default::default() }).unwrap(); - nested0 - .charge(&Diff { bytes_removed: 1, require_ed: true, ..Default::default() }) - .unwrap(); - meter.absorb(nested0, &ALICE, &BOB, None); - - assert_eq!( - TestExtTestValue::get(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - charges: vec![Charge { - origin: ALICE, - contract: BOB, - amount: Deposit::Charge(::Currency::minimum_balance() * 2), - terminated: false, - }] - } - ) - } - #[test] fn charging_works() { clear_ext(); - let min_balance = ::Currency::minimum_balance(); - - let mut meter = TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); - assert_eq!(meter.available(), 1_000); + let mut meter = TestMeter::new(&ALICE, Some(100), 0).unwrap(); + assert_eq!(meter.available(), 100); - let mut nested0_info = new_info(100); + let mut nested0_info = + new_info(StorageInfo { bytes: 100, items: 5, bytes_deposit: 100, items_deposit: 10 }); let mut nested0 = meter.nested(); - nested0 - .charge(&Diff { - bytes_added: 10, - bytes_removed: 5, - items_added: 1, - items_removed: 2, - ..Default::default() - }) - .unwrap(); - nested0.charge(&Diff { bytes_removed: 1, ..Default::default() }).unwrap(); + nested0.charge(&Diff { + bytes_added: 108, + bytes_removed: 5, + items_added: 1, + items_removed: 2, + }); + nested0.charge(&Diff { bytes_removed: 99, ..Default::default() }); - let mut nested1_info = new_info(50); + let mut nested1_info = + new_info(StorageInfo { bytes: 100, items: 10, bytes_deposit: 100, items_deposit: 20 }); let mut nested1 = nested0.nested(); - nested1.charge(&Diff { items_removed: 5, ..Default::default() }).unwrap(); - nested0.absorb(nested1, &ALICE, &CHARLIE, Some(&mut nested1_info)); + nested1.charge(&Diff { items_removed: 5, ..Default::default() }); + nested0.absorb(nested1, &CHARLIE, Some(&mut nested1_info)); - // Trying to refund more than is available in the contract will cap the charge - // to (deposit_in_contract - ed). - let mut nested2_info = new_info(5); + let mut nested2_info = + new_info(StorageInfo { bytes: 100, items: 7, bytes_deposit: 100, items_deposit: 20 }); let mut nested2 = nested0.nested(); - nested2.charge(&Diff { bytes_removed: 7, ..Default::default() }).unwrap(); - nested0.absorb(nested2, &ALICE, &CHARLIE, Some(&mut nested2_info)); + nested2.charge(&Diff { items_removed: 7, ..Default::default() }); + nested0.absorb(nested2, &CHARLIE, Some(&mut nested2_info)); + + nested0.enforce_limit(Some(&mut nested0_info)).unwrap(); + meter.absorb(nested0, &BOB, Some(&mut nested0_info)); - meter.absorb(nested0, &ALICE, &BOB, Some(&mut nested0_info)); + meter.into_deposit(&ALICE); - assert_eq!(nested0_info.storage_deposit, 102); - assert_eq!(nested1_info.storage_deposit, 40); - assert_eq!(nested2_info.storage_deposit, min_balance); + assert_eq!(nested0_info.extra_deposit(), 112); + assert_eq!(nested1_info.extra_deposit(), 110); + assert_eq!(nested2_info.extra_deposit(), 100); assert_eq!( TestExtTestValue::get(), TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + limit_checks: vec![LimitCheck { origin: ALICE, limit: 100, min_leftover: 0 }], charges: vec![ Charge { origin: ALICE, @@ -643,7 +731,7 @@ mod tests { Charge { origin: ALICE, contract: CHARLIE, - amount: Deposit::Refund(4), + amount: Deposit::Refund(20), terminated: false }, Charge { @@ -665,26 +753,25 @@ mod tests { assert_eq!(meter.available(), 1_000); let mut nested0 = meter.nested(); - nested0 - .charge(&Diff { - bytes_added: 5, - bytes_removed: 1, - items_added: 3, - items_removed: 1, - ..Default::default() - }) - .unwrap(); - nested0.charge(&Diff { items_added: 2, ..Default::default() }).unwrap(); - - let nested1_info = new_info(400); + nested0.charge(&Diff { + bytes_added: 5, + bytes_removed: 1, + items_added: 3, + items_removed: 1, + }); + nested0.charge(&Diff { items_added: 2, ..Default::default() }); + + let mut nested1_info = + new_info(StorageInfo { bytes: 100, items: 10, bytes_deposit: 100, items_deposit: 20 }); let mut nested1 = nested0.nested(); - nested1.charge(&Diff { items_removed: 5, ..Default::default() }).unwrap(); - nested1.charge(&Diff { bytes_added: 20, ..Default::default() }).unwrap(); + nested1.charge(&Diff { items_removed: 5, ..Default::default() }); + nested1.charge(&Diff { bytes_added: 20, ..Default::default() }); nested1.terminate(&nested1_info); - nested0.absorb(nested1, &ALICE, &CHARLIE, None); + nested0.enforce_limit(Some(&mut nested1_info)).unwrap(); + nested0.absorb(nested1, &CHARLIE, None); - meter.absorb(nested0, &ALICE, &BOB, None); - drop(meter); + meter.absorb(nested0, &BOB, None); + meter.into_deposit(&ALICE); assert_eq!( TestExtTestValue::get(), @@ -694,7 +781,7 @@ mod tests { Charge { origin: ALICE, contract: CHARLIE, - amount: Deposit::Refund(400), + amount: Deposit::Refund(120), terminated: true }, Charge { diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 12029abd59e46..a56e4f5564845 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -23,6 +23,7 @@ use crate::{ }, exec::{FixSizedKey, Frame}, storage::Storage, + tests::test_utils::{get_contract, get_contract_checked}, wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, @@ -36,8 +37,8 @@ use frame_support::{ parameter_types, storage::child, traits::{ - BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, OnIdle, OnInitialize, - ReservableCurrency, + BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, LockableCurrency, OnIdle, + OnInitialize, ReservableCurrency, WithdrawReasons, }, weights::{constants::WEIGHT_PER_SECOND, Weight}, }; @@ -76,7 +77,9 @@ frame_support::construct_runtime!( #[macro_use] pub mod test_utils { use super::{Balances, Hash, SysConfig, Test}; - use crate::{exec::AccountIdOf, storage::Storage, CodeHash, Config, ContractInfoOf, Nonce}; + use crate::{ + exec::AccountIdOf, storage::Storage, CodeHash, Config, ContractInfo, ContractInfoOf, Nonce, + }; use codec::Encode; use frame_support::traits::Currency; @@ -97,6 +100,12 @@ pub mod test_utils { pub fn get_balance(who: &AccountIdOf) -> u64 { Balances::free_balance(who) } + pub fn get_contract(addr: &AccountIdOf) -> ContractInfo { + get_contract_checked(addr).unwrap() + } + pub fn get_contract_checked(addr: &AccountIdOf) -> Option> { + ContractInfoOf::::get(addr) + } pub fn hash(s: &S) -> <::Hashing as Hash>::Output { <::Hashing as Hash>::hash_of(s) } @@ -105,6 +114,7 @@ pub mod test_utils { assert_eq!(u32::from_le_bytes($x.data[..].try_into().unwrap()), $y as u32); }}; } + macro_rules! assert_refcount { ( $code_hash:expr , $should:expr $(,)? ) => {{ let is = crate::OwnerInfoOf::::get($code_hash).map(|m| m.refcount()).unwrap(); @@ -693,7 +703,7 @@ fn instantiate_unique_trie_id() { vec![], vec![], )); - let trie_id = ContractInfoOf::::get(&addr).unwrap().trie_id; + let trie_id = get_contract(&addr).trie_id; // Try to instantiate it again without termination should yield an error. assert_err_ignore_postinfo!( @@ -731,7 +741,7 @@ fn instantiate_unique_trie_id() { )); // Trie ids shouldn't match or we might have a collision - assert_ne!(trie_id, ContractInfoOf::::get(&addr).unwrap().trie_id); + assert_ne!(trie_id, get_contract(&addr).trie_id); }); } @@ -752,7 +762,7 @@ fn storage_max_value_limit() { vec![], )); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - ContractInfoOf::::get(&addr).unwrap(); + get_contract(&addr); // Call contract with allowed storage value. assert_ok!(Contracts::call( @@ -962,7 +972,7 @@ fn cannot_self_destruct_through_draning() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); // Call BOB which makes it send all funds to the zero address // The contract code asserts that the transfer was successful @@ -1003,11 +1013,11 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated and has the minimum balance - let info = ContractInfoOf::::get(&addr).unwrap(); - assert_eq!(info.storage_deposit, min_balance); + assert_eq!(get_contract(&addr).total_deposit(), min_balance); + assert_eq!(get_contract(&addr).extra_deposit(), 0); assert_eq!(::Currency::total_balance(&addr), min_balance); - // Create 100 bytes of storage with a price of per byte + // Create 100 bytes of storage with a price of per byte and a single storage item of price 2 assert_ok!(Contracts::call( RuntimeOrigin::signed(ALICE), addr.clone(), @@ -1016,9 +1026,10 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { None, 100u32.to_le_bytes().to_vec() )); + assert_eq!(get_contract(&addr).total_deposit(), min_balance + 102); - // Increase the byte price and trigger a refund. This could potentially destroy the account - // because the refund removes the reserved existential deposit. This should not happen. + // Increase the byte price and trigger a refund. This should not have any influence because + // the removal is pro rata and exactly those 100 bytes should have been removed. DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 500); assert_ok!(Contracts::call( RuntimeOrigin::signed(ALICE), @@ -1032,8 +1043,9 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { // Make sure the account wasn't removed by the refund assert_eq!( ::Currency::total_balance(&addr), - ::Currency::minimum_balance(), + get_contract(&addr).total_deposit(), ); + assert_eq!(get_contract(&addr).extra_deposit(), 2,); }); } @@ -1086,9 +1098,6 @@ fn cannot_self_destruct_by_refund_after_slash() { // Make sure the account kept the minimum balance and was not destroyed assert_eq!(::Currency::total_balance(&addr), min_balance); - // even though it was not charged it is still substracted from the storage deposit tracker - assert_eq!(ContractInfoOf::::get(&addr).unwrap().storage_deposit, 550); - assert_eq!( System::events(), vec![ @@ -1142,7 +1151,7 @@ fn cannot_self_destruct_while_live() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); // Call BOB with input data, forcing it make a recursive call to itself to // self-destruct, resulting in a trap. @@ -1159,7 +1168,7 @@ fn cannot_self_destruct_while_live() { ); // Check that BOB is still there. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); }); } @@ -1183,7 +1192,7 @@ fn self_destruct_works() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); // Drop all previous events initialize_block(2); @@ -1198,7 +1207,7 @@ fn self_destruct_works() { assert_refcount!(&code_hash, 0); // Check that account is gone - assert!(ContractInfoOf::::get(&addr).is_none()); + assert!(get_contract_checked(&addr).is_none()); assert_eq!(Balances::total_balance(&addr), 0); // check that the beneficiary (django) got remaining balance @@ -1289,7 +1298,7 @@ fn destroy_contract_and_transfer_funds() { let addr_charlie = Contracts::contract_address(&addr_bob, &callee_code_hash, &[0x47, 0x11]); // Check that the CHARLIE contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr_charlie), Some(_)); + get_contract(&addr_charlie); // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. assert_ok!(Contracts::call( @@ -1302,7 +1311,7 @@ fn destroy_contract_and_transfer_funds() { )); // Check that CHARLIE has moved on to the great beyond (ie. died). - assert!(ContractInfoOf::::get(&addr_charlie).is_none()); + assert!(get_contract_checked(&addr_charlie).is_none()); }); } @@ -1862,7 +1871,7 @@ fn lazy_removal_works() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap(); + let info = get_contract(&addr); let trie = &info.child_trie_info(); // Put value into the contracts child trie @@ -1931,7 +1940,7 @@ fn lazy_batch_removal_works() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[i]); - let info = >::get(&addr).unwrap(); + let info = get_contract(&addr); let trie = &info.child_trie_info(); // Put value into the contracts child trie @@ -1993,7 +2002,7 @@ fn lazy_removal_partial_remove_works() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap(); + let info = get_contract(&addr); // Put value into the contracts child trie for val in &vals { @@ -2105,7 +2114,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap(); + let info = get_contract(&addr); let trie = &info.child_trie_info(); // Put value into the contracts child trie @@ -2173,7 +2182,7 @@ fn lazy_removal_does_not_use_all_weight() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap(); + let info = get_contract(&addr); let (weight_per_key, max_keys) = Storage::::deletion_budget(1, weight_limit); // We create a contract with one less storage item than we can remove within the limit @@ -2264,7 +2273,7 @@ fn deletion_queue_full() { ); // Contract should exist because removal failed - >::get(&addr).unwrap(); + get_contract(&addr); }); } @@ -2909,7 +2918,7 @@ fn instantiate_with_zero_balance_works() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); // Make sure the account exists even though no free balance was send assert_eq!(::Currency::free_balance(&addr), 0,); @@ -3002,7 +3011,7 @@ fn instantiate_with_below_existential_deposit_works() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); // Make sure the account exists even though no free balance was send assert_eq!(::Currency::free_balance(&addr), 50,); @@ -3114,7 +3123,7 @@ fn storage_deposit_works() { // 4 is for creating 2 storage items let charged0 = 4 + 1_000 + 5_000; deposit += charged0; - assert_eq!(>::get(&addr).unwrap().storage_deposit, deposit); + assert_eq!(get_contract(&addr).total_deposit(), deposit); // Add more storage (but also remove some) assert_ok!(Contracts::call( @@ -3127,7 +3136,7 @@ fn storage_deposit_works() { )); let charged1 = 1_000 - 100; deposit += charged1; - assert_eq!(>::get(&addr).unwrap().storage_deposit, deposit); + assert_eq!(get_contract(&addr).total_deposit(), deposit); // Remove more storage (but also add some) assert_ok!(Contracts::call( @@ -3138,9 +3147,10 @@ fn storage_deposit_works() { None, (2_100u32, 900u32).encode(), )); - let refunded0 = 4_000 - 100; + // -1 for numeric instability + let refunded0 = 4_000 - 100 - 1; deposit -= refunded0; - assert_eq!(>::get(&addr).unwrap().storage_deposit, deposit); + assert_eq!(get_contract(&addr).total_deposit(), deposit); assert_eq!( System::events(), @@ -3253,7 +3263,7 @@ fn set_code_extrinsic() { // Drop previous events initialize_block(2); - assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); @@ -3262,7 +3272,7 @@ fn set_code_extrinsic() { Contracts::set_code(RuntimeOrigin::signed(ALICE), addr.clone(), new_code_hash), sp_runtime::traits::BadOrigin, ); - assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); assert_eq!(System::events(), vec![],); @@ -3272,7 +3282,7 @@ fn set_code_extrinsic() { Contracts::set_code(RuntimeOrigin::root(), BOB, new_code_hash), >::ContractNotFound, ); - assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); assert_eq!(System::events(), vec![],); @@ -3282,14 +3292,14 @@ fn set_code_extrinsic() { Contracts::set_code(RuntimeOrigin::root(), addr.clone(), Default::default()), >::CodeNotFound, ); - assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); assert_eq!(System::events(), vec![],); // successful call assert_ok!(Contracts::set_code(RuntimeOrigin::root(), addr.clone(), new_code_hash)); - assert_eq!(>::get(&addr).unwrap().code_hash, new_code_hash); + assert_eq!(get_contract(&addr).code_hash, new_code_hash); assert_refcount!(&code_hash, 0); assert_refcount!(&new_code_hash, 1); assert_eq!( @@ -3639,3 +3649,301 @@ fn set_code_hash() { ); }); } + +#[test] +fn storage_deposit_limit_is_enforced() { + let (wasm, code_hash) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let min_balance = ::Currency::minimum_balance(); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the BOB contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), min_balance); + assert_eq!(::Currency::total_balance(&addr), min_balance); + + // Create 100 bytes of storage with a price of per byte + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(1)), + 100u32.to_le_bytes().to_vec() + ), + >::StorageDepositLimitExhausted, + ); + }); +} + +#[test] +fn storage_deposit_limit_is_enforced_late() { + let (wasm_caller, code_hash_caller) = + compile_module::("create_storage_and_call").unwrap(); + let (wasm_callee, code_hash_callee) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm_caller, + vec![], + vec![], + )); + let addr_caller = Contracts::contract_address(&ALICE, &code_hash_caller, &[]); + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm_callee, + vec![], + vec![], + )); + let addr_callee = Contracts::contract_address(&ALICE, &code_hash_callee, &[]); + + // Create 100 bytes of storage with a price of per byte + // This is 100 Balance + 2 Balance for the item + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_callee.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(102)), + 100u32.to_le_bytes().to_vec() + )); + + // We do not remove any storage but require 14 bytes of storage for the new + // storage created in the immediate contract. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(5)), + 100u32 + .to_le_bytes() + .as_ref() + .iter() + .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) + .cloned() + .collect(), + ), + >::StorageDepositLimitExhausted, + ); + + // Allow for the additional 14 bytes but demand an additional byte in the callee contract. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(14)), + 101u32 + .to_le_bytes() + .as_ref() + .iter() + .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) + .cloned() + .collect(), + ), + >::StorageDepositLimitExhausted, + ); + + // Refund in the callee contract but not enough to cover the 14 balance required by the + // caller. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(0)), + 87u32 + .to_le_bytes() + .as_ref() + .iter() + .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) + .cloned() + .collect(), + ), + >::StorageDepositLimitExhausted, + ); + + let _ = Balances::make_free_balance_be(&ALICE, 1_000); + + // Send more than the sender has balance. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(50)), + 1_200u32 + .to_le_bytes() + .as_ref() + .iter() + .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) + .cloned() + .collect(), + ), + >::StorageDepositLimitExhausted, + ); + + // Same as above but allow for the additional balance. + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(1)), + 87u32 + .to_le_bytes() + .as_ref() + .iter() + .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) + .cloned() + .collect(), + )); + }); +} + +#[test] +fn deposit_limit_honors_liquidity_restrictions() { + let (wasm, code_hash) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let _ = Balances::deposit_creating(&BOB, 1_000); + let min_balance = ::Currency::minimum_balance(); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), min_balance); + assert_eq!(::Currency::total_balance(&addr), min_balance); + + // check that the lock ins honored + Balances::set_lock([0; 8], &BOB, 1_000, WithdrawReasons::TRANSFER); + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(BOB), + addr.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(200)), + 100u32.to_le_bytes().to_vec() + ), + >::StorageDepositNotEnoughFunds, + ); + assert_eq!(Balances::free_balance(&BOB), 1_000); + }); +} + +#[test] +fn deposit_limit_honors_existential_deposit() { + let (wasm, code_hash) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let _ = Balances::deposit_creating(&BOB, 1_000); + let min_balance = ::Currency::minimum_balance(); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), min_balance); + assert_eq!(::Currency::total_balance(&addr), min_balance); + + // check that the deposit can't bring the account below the existential deposit + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(BOB), + addr.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(900)), + 100u32.to_le_bytes().to_vec() + ), + >::StorageDepositNotEnoughFunds, + ); + assert_eq!(Balances::free_balance(&BOB), 1_000); + }); +} + +#[test] +fn deposit_limit_honors_min_leftover() { + let (wasm, code_hash) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let _ = Balances::deposit_creating(&BOB, 1_000); + let min_balance = ::Currency::minimum_balance(); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), min_balance); + assert_eq!(::Currency::total_balance(&addr), min_balance); + + // check that the minumum leftover (value send) is considered + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(BOB), + addr.clone(), + 400, + GAS_LIMIT, + Some(codec::Compact(500)), + 100u32.to_le_bytes().to_vec() + ), + >::StorageDepositNotEnoughFunds, + ); + assert_eq!(Balances::free_balance(&BOB), 1_000); + }); +} diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 9c130b562c275..e8873f604c9c7 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -426,7 +426,7 @@ fn do_preparation( .saturating_add(original_code_len) .saturating_add(>::max_encoded_len()) as u32; let deposit = Diff { bytes_added, items_added: 3, ..Default::default() } - .to_deposit::() + .update_contract::(None) .charge_or_zero(); module.owner_info = Some(OwnerInfo { owner, deposit, refcount: 0 }); diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index 9a1634fd89313..d0beb66d34923 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -26,7 +26,7 @@ use crate::{ traits::Get, }; use codec::MaxEncodedLen; -use sp_runtime::traits::MaybeSerializeDeserialize; +use sp_runtime::{traits::MaybeSerializeDeserialize, FixedPointOperand}; use sp_std::fmt::Debug; mod reservable; @@ -37,7 +37,7 @@ pub use lockable::{LockIdentifier, LockableCurrency, VestingSchedule}; /// Abstraction over a fungible assets system. pub trait Currency { /// The balance of an account. - type Balance: Balance + MaybeSerializeDeserialize + Debug + MaxEncodedLen; + type Balance: Balance + MaybeSerializeDeserialize + Debug + MaxEncodedLen + FixedPointOperand; /// The opaque token type for an imbalance. This is returned by unbalanced operations /// and must be dealt with. It may be dropped but cannot be cloned. From 1253de628bcb5d70b7ac7dd2d8c7b40abb751a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 22 Sep 2022 09:41:16 +0200 Subject: [PATCH 1189/1472] pallet-utility: Disallow none origin (#12321) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: André Silva --- frame/utility/src/lib.rs | 6 +++--- frame/utility/src/tests.rs | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index bc19b5625a71a..819314f3d8454 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -203,7 +203,7 @@ pub mod pallet { origin: OriginFor, calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { - let is_root = ensure_root(origin.clone()).is_ok(); + let is_root = ensure_signed_or_root(origin.clone())?.is_none(); let calls_len = calls.len(); ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); @@ -319,7 +319,7 @@ pub mod pallet { origin: OriginFor, calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { - let is_root = ensure_root(origin.clone()).is_ok(); + let is_root = ensure_signed_or_root(origin.clone())?.is_none(); let calls_len = calls.len(); ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); @@ -426,7 +426,7 @@ pub mod pallet { origin: OriginFor, calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { - let is_root = ensure_root(origin.clone()).is_ok(); + let is_root = ensure_signed_or_root(origin.clone())?.is_none(); let calls_len = calls.len(); ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 65d9c966ebdfd..ebd8dda81adbc 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -25,6 +25,7 @@ use crate as utility; use frame_support::{ assert_err_ignore_postinfo, assert_noop, assert_ok, dispatch::{DispatchError, DispatchErrorWithPostInfo, Dispatchable, Pays}, + error::BadOrigin, parameter_types, storage, traits::{ConstU32, ConstU64, Contains}, weights::Weight, @@ -651,7 +652,7 @@ fn force_batch_works() { call_transfer(2, 10), call_transfer(2, 5), ] - ),); + )); System::assert_last_event(utility::Event::BatchCompletedWithErrors.into()); System::assert_has_event( utility::Event::ItemFailed { error: DispatchError::Other("") }.into(), @@ -662,10 +663,19 @@ fn force_batch_works() { assert_ok!(Utility::force_batch( RuntimeOrigin::signed(2), vec![call_transfer(1, 5), call_transfer(1, 5),] - ),); + )); System::assert_last_event(utility::Event::BatchCompleted.into()); assert_ok!(Utility::force_batch(RuntimeOrigin::signed(1), vec![call_transfer(2, 50),]),); System::assert_last_event(utility::Event::BatchCompletedWithErrors.into()); }); } + +#[test] +fn none_origin_does_not_work() { + new_test_ext().execute_with(|| { + assert_noop!(Utility::force_batch(RuntimeOrigin::none(), vec![]), BadOrigin); + assert_noop!(Utility::batch(RuntimeOrigin::none(), vec![]), BadOrigin); + assert_noop!(Utility::batch_all(RuntimeOrigin::none(), vec![]), BadOrigin); + }) +} From cc4d5cc8654d280f03a13421669ba03632e14aa7 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Thu, 22 Sep 2022 16:53:51 +0800 Subject: [PATCH 1190/1472] Migrate remaining old decl_* macros to the new pallet attribute macros (#12271) * Migrate remaining old decl_* macros to the new pallet attribute macros Signed-off-by: koushiro * Apply review suggestions Signed-off-by: koushiro * Apply review suggestions Signed-off-by: koushiro * use pallet::storage * Fix dev rpc test Signed-off-by: koushiro * Fix service tests Signed-off-by: koushiro Signed-off-by: koushiro --- Cargo.lock | 2 + client/rpc/src/dev/tests.rs | 4 +- client/service/test/src/client/mod.rs | 9 ++- frame/benchmarking/src/tests.rs | 8 +- frame/benchmarking/src/tests_instance.rs | 83 ++++++++++---------- test-utils/runtime/src/genesismap.rs | 12 +-- test-utils/runtime/src/lib.rs | 2 + test-utils/runtime/src/system.rs | 97 ++++++++++++++++-------- utils/frame/rpc/support/Cargo.toml | 2 + utils/frame/rpc/support/src/lib.rs | 94 ++++++++++++++++++----- 10 files changed, 206 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5521e91de895d..5172c3d02861d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10522,6 +10522,8 @@ dependencies = [ "sc-rpc-api", "scale-info", "serde", + "sp-core", + "sp-runtime", "sp-storage", "tokio", ] diff --git a/client/rpc/src/dev/tests.rs b/client/rpc/src/dev/tests.rs index f3b18690d0972..816f3cdfe6025 100644 --- a/client/rpc/src/dev/tests.rs +++ b/client/rpc/src/dev/tests.rs @@ -43,8 +43,8 @@ async fn block_stats_work() { .await .unwrap(), Some(BlockStats { - witness_len: 597, - witness_compact_len: 500, + witness_len: 630, + witness_compact_len: 534, block_len: 99, num_extrinsics: 0, }), diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index cb648664b4006..2ab1415f8ca31 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1663,7 +1663,7 @@ fn storage_keys_iter_works() { let res: Vec<_> = client .storage_keys_iter(&BlockId::Number(0), Some(&prefix), None) .unwrap() - .take(8) + .take(9) .map(|x| array_bytes::bytes2hex("", &x.0)) .collect(); assert_eq!( @@ -1675,6 +1675,7 @@ fn storage_keys_iter_works() { "1a560ecfd2a62c2b8521ef149d0804eb621050e3988ed97dca55f0d7c3e6aa34", "1d66850d32002979d67dd29dc583af5b2ae2a1f71c1f35ad90fff122be7a3824", "237498b98d8803334286e9f0483ef513098dd3c1c22ca21c4dc155b4ef6cc204", + "26aa394eea5630e07c48ae0c9558cef75e0621c4869aa60c02be9adcc98a0d1d", "29b9db10ec5bf7907d8f74b5e60aa8140c4fbdd8127a1ee5600cb98e5ec01729", "3a636f6465", ] @@ -1699,7 +1700,7 @@ fn storage_keys_iter_works() { "5c2d5fda66373dabf970e4fb13d277ce91c5233473321129d32b5a8085fa8133", "6644b9b8bc315888ac8e41a7968dc2b4141a5403c58acdf70b7e8f7e07bf5081", "66484000ed3f75c95fc7b03f39c20ca1e1011e5999278247d3b2f5e3c3273808", - "79c07e2b1d2e2abfd4855b936617eeff5e0621c4869aa60c02be9adcc98a0d1d", + "7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa", ] ); @@ -1708,7 +1709,7 @@ fn storage_keys_iter_works() { &BlockId::Number(0), Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked( - "79c07e2b1d2e2abfd4855b936617eeff5e0621c4869aa60c02be9adcc98a0d1d", + "7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa", ))), ) .unwrap() @@ -1718,11 +1719,11 @@ fn storage_keys_iter_works() { assert_eq!( res, [ - "7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa", "811ecfaadcf5f2ee1d67393247e2f71a1662d433e8ce7ff89fb0d4aa9561820b", "a93d74caa7ec34ea1b04ce1e5c090245f867d333f0f88278a451e45299654dc5", "a9ee1403384afbfc13f13be91ff70bfac057436212e53b9733914382ac942892", "cf722c0832b5231d35e29f319ff27389f5032bfc7bfc3ba5ed7839f2042fb99f", + "e3b47b6c84c0493481f97c5197d2554f", ] ); } diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index 3bbd06ea64f84..88a7d6d0286b2 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -36,7 +36,7 @@ mod pallet_test { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); + pub struct Pallet(PhantomData); #[pallet::config] pub trait Config: frame_system::Config { @@ -46,21 +46,21 @@ mod pallet_test { } #[pallet::storage] - #[pallet::getter(fn heartbeat_after)] + #[pallet::getter(fn value)] pub(crate) type Value = StorageValue<_, u32, OptionQuery>; #[pallet::call] impl Pallet { #[pallet::weight(0)] pub fn set_value(origin: OriginFor, n: u32) -> DispatchResult { - let _sender = frame_system::ensure_signed(origin)?; + let _sender = ensure_signed(origin)?; Value::::put(n); Ok(()) } #[pallet::weight(0)] pub fn dummy(origin: OriginFor, _n: u32) -> DispatchResult { - let _sender = frame_system::ensure_none(origin)?; + let _sender = ensure_none(origin)?; Ok(()) } diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index 1fb122f031a76..7e1cd48840687 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -28,48 +28,52 @@ use sp_runtime::{ }; use sp_std::prelude::*; +#[frame_support::pallet] mod pallet_test { - use frame_support::pallet_prelude::Get; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; - frame_support::decl_storage! { - trait Store for Module, I: Instance = DefaultInstance> as Test where - ::OtherEvent: Into<>::RuntimeEvent> - { - pub Value get(fn value): Option; - } - } - - frame_support::decl_module! { - pub struct Module, I: Instance = DefaultInstance> for enum Call where - origin: T::RuntimeOrigin, ::OtherEvent: Into<>::RuntimeEvent> - { - #[weight = 0] - fn set_value(origin, n: u32) -> frame_support::dispatch::DispatchResult { - let _sender = frame_system::ensure_signed(origin)?; - Value::::put(n); - Ok(()) - } - - #[weight = 0] - fn dummy(origin, _n: u32) -> frame_support::dispatch::DispatchResult { - let _sender = frame_system::ensure_none(origin)?; - Ok(()) - } - } - } + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData<(T, I)>); pub trait OtherConfig { type OtherEvent; } - pub trait Config: frame_system::Config + OtherConfig - where - Self::OtherEvent: Into<>::RuntimeEvent>, - { - type RuntimeEvent; + #[pallet::config] + pub trait Config: frame_system::Config + OtherConfig { + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; type LowerBound: Get; type UpperBound: Get; } + + #[pallet::storage] + #[pallet::getter(fn value)] + pub(crate) type Value, I: 'static = ()> = StorageValue<_, u32, OptionQuery>; + + #[pallet::event] + pub enum Event, I: 'static = ()> {} + + #[pallet::call] + impl, I: 'static> Pallet + where + ::OtherEvent: Into<>::RuntimeEvent>, + { + #[pallet::weight(0)] + pub fn set_value(origin: OriginFor, n: u32) -> DispatchResult { + let _sender = ensure_signed(origin)?; + Value::::put(n); + Ok(()) + } + + #[pallet::weight(0)] + pub fn dummy(origin: OriginFor, _n: u32) -> DispatchResult { + let _sender = ensure_none(origin)?; + Ok(()) + } + } } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -82,7 +86,7 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - TestPallet: pallet_test::{Pallet, Call, Storage}, + TestPallet: pallet_test::{Pallet, Call, Storage, Event}, } ); @@ -90,18 +94,18 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; - type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); + type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -110,7 +114,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet_test::Config for Test { @@ -130,15 +134,14 @@ fn new_test_ext() -> sp_io::TestExternalities { mod benchmarks { use super::pallet_test::{self, Value}; use crate::account; - use frame_support::{ensure, StorageValue}; + use frame_support::ensure; use frame_system::RawOrigin; use sp_std::prelude::*; // Additional used internally by the benchmark macro. use super::pallet_test::{Call, Config, Pallet}; - use frame_support::traits::Instance; - crate::benchmarks_instance! { + crate::benchmarks_instance_pallet! { where_clause { where ::OtherEvent: Clone @@ -151,7 +154,7 @@ mod benchmarks { let caller = account::("caller", 0, 0); }: _ (RawOrigin::Signed(caller), b.into()) verify { - assert_eq!(Value::::get(), Some(b)); + assert_eq!(Value::::get(), Some(b)); } other_name { diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index 3ece5165e1757..42706730eb9ac 100644 --- a/test-utils/runtime/src/genesismap.rs +++ b/test-utils/runtime/src/genesismap.rs @@ -17,8 +17,9 @@ //! Tool for creating the genesis block. -use super::{system, wasm_binary_unwrap, AccountId, AuthorityId}; +use super::{system, wasm_binary_unwrap, AccountId, AuthorityId, Runtime}; use codec::{Encode, Joiner, KeyedVec}; +use frame_support::traits::GenesisBuild; use sc_service::client::genesis; use sp_core::{ map, @@ -80,10 +81,11 @@ impl GenesisConfig { // Assimilate the system genesis config. let mut storage = Storage { top: map, children_default: self.extra_storage.children_default.clone() }; - let config = system::GenesisConfig { authorities: self.authorities.clone() }; - config - .assimilate_storage(&mut storage) - .expect("Adding `system::GensisConfig` to the genesis"); + >::assimilate_storage( + &system::GenesisConfig { authorities: self.authorities.clone() }, + &mut storage, + ) + .expect("Adding `system::GensisConfig` to the genesis"); storage } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 5601de632eae3..a64e3f25ef041 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -610,6 +610,8 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } +impl system::Config for Runtime {} + impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 0cb3e7d70f6df..6e33d5c25fe6f 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -19,11 +19,11 @@ //! and depositing logs. use crate::{ - AccountId, AuthorityId, Block, BlockNumber, Digest, Extrinsic, Header, Transfer, H256 as Hash, + AccountId, AuthorityId, Block, BlockNumber, Digest, Extrinsic, Header, Runtime, Transfer, + H256 as Hash, }; use codec::{Decode, Encode, KeyedVec}; -use frame_support::{decl_module, decl_storage, storage}; -use frame_system::Config; +use frame_support::storage; use sp_core::storage::well_known_keys; use sp_io::{hashing::blake2_256, storage::root as storage_root, trie}; use sp_runtime::{ @@ -39,19 +39,51 @@ use sp_std::prelude::*; const NONCE_OF: &[u8] = b"nonce:"; const BALANCE_OF: &[u8] = b"balance:"; -decl_module! { - pub struct Module for enum Call where origin: T::RuntimeOrigin {} -} +pub use self::pallet::*; + +#[frame_support::pallet] +mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::storage] + pub type ExtrinsicData = StorageMap<_, Blake2_128Concat, u32, Vec, ValueQuery>; + + // The current block number being processed. Set by `execute_block`. + #[pallet::storage] + pub type Number = StorageValue<_, BlockNumber, OptionQuery>; -decl_storage! { - trait Store for Module as TestRuntime { - ExtrinsicData: map hasher(blake2_128_concat) u32 => Vec; - // The current block number being processed. Set by `execute_block`. - Number get(fn number): Option; - ParentHash get(fn parent_hash): Hash; - NewAuthorities get(fn new_authorities): Option>; - StorageDigest get(fn storage_digest): Option; - Authorities get(fn authorities) config(): Vec; + #[pallet::storage] + pub type ParentHash = StorageValue<_, Hash, ValueQuery>; + + #[pallet::storage] + pub type NewAuthorities = StorageValue<_, Vec, OptionQuery>; + + #[pallet::storage] + pub type StorageDigest = StorageValue<_, Digest, OptionQuery>; + + #[pallet::storage] + pub type Authorities = StorageValue<_, Vec, ValueQuery>; + + #[pallet::genesis_config] + #[cfg_attr(feature = "std", derive(Default))] + pub struct GenesisConfig { + pub authorities: Vec, + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + >::put(self.authorities.clone()); + } } } @@ -69,9 +101,9 @@ pub fn nonce_of(who: AccountId) -> u64 { pub fn initialize_block(header: &Header) { // populate environment. - ::put(&header.number); - ::put(&header.parent_hash); - ::put(header.digest()); + >::put(&header.number); + >::put(&header.parent_hash); + >::put(header.digest()); storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &0u32); // try to read something that depends on current header digest @@ -82,15 +114,15 @@ pub fn initialize_block(header: &Header) { } pub fn authorities() -> Vec { - Authorities::get() + >::get() } pub fn get_block_number() -> Option { - Number::get() + >::get() } pub fn take_block_number() -> Option { - Number::take() + >::take() } #[derive(Copy, Clone)] @@ -124,8 +156,8 @@ fn execute_block_with_state_root_handler(block: &mut Block, mode: Mode) -> Heade header.state_root = new_header.state_root; } else { info_expect_equal_hash(&new_header.state_root, &header.state_root); - assert!( - new_header.state_root == header.state_root, + assert_eq!( + new_header.state_root, header.state_root, "Storage root must match that calculated.", ); } @@ -134,8 +166,8 @@ fn execute_block_with_state_root_handler(block: &mut Block, mode: Mode) -> Heade header.extrinsics_root = new_header.extrinsics_root; } else { info_expect_equal_hash(&new_header.extrinsics_root, &header.extrinsics_root); - assert!( - new_header.extrinsics_root == header.extrinsics_root, + assert_eq!( + new_header.extrinsics_root, header.extrinsics_root, "Transaction trie root must be valid.", ); } @@ -187,7 +219,7 @@ pub fn execute_transaction(utx: Extrinsic) -> ApplyExtrinsicResult { let extrinsic_index: u32 = storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX).unwrap_or_default(); let result = execute_transaction_backend(&utx, extrinsic_index); - ExtrinsicData::insert(extrinsic_index, utx.encode()); + >::insert(extrinsic_index, utx.encode()); storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(extrinsic_index + 1)); result } @@ -196,13 +228,14 @@ pub fn execute_transaction(utx: Extrinsic) -> ApplyExtrinsicResult { pub fn finalize_block() -> Header { use sp_core::storage::StateVersion; let extrinsic_index: u32 = storage::unhashed::take(well_known_keys::EXTRINSIC_INDEX).unwrap(); - let txs: Vec<_> = (0..extrinsic_index).map(ExtrinsicData::take).collect(); + let txs: Vec<_> = (0..extrinsic_index).map(>::take).collect(); let extrinsics_root = trie::blake2_256_ordered_root(txs, StateVersion::V0); - let number = ::take().expect("Number is set by `initialize_block`"); - let parent_hash = ::take(); - let mut digest = ::take().expect("StorageDigest is set by `initialize_block`"); + let number = >::take().expect("Number is set by `initialize_block`"); + let parent_hash = >::take(); + let mut digest = + >::take().expect("StorageDigest is set by `initialize_block`"); - let o_new_authorities = ::take(); + let o_new_authorities = >::take(); // This MUST come after all changes to storage are done. Otherwise we will fail the // “Storage root does not match that calculated” assertion. @@ -280,7 +313,7 @@ fn execute_store(data: Vec) -> ApplyExtrinsicResult { } fn execute_new_authorities_backend(new_authorities: &[AuthorityId]) -> ApplyExtrinsicResult { - NewAuthorities::put(new_authorities.to_vec()); + >::put(new_authorities.to_vec()); Ok(Ok(())) } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 2104774bd2605..38e40a33d9c7f 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -27,4 +27,6 @@ sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } scale-info = "2.1.1" jsonrpsee = { version = "0.15.1", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.17.0" +sp-core = { version = "6.0.0", path = "../../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } diff --git a/utils/frame/rpc/support/src/lib.rs b/utils/frame/rpc/support/src/lib.rs index ad90c24167587..fdf6fe0be8172 100644 --- a/utils/frame/rpc/support/src/lib.rs +++ b/utils/frame/rpc/support/src/lib.rs @@ -34,50 +34,104 @@ use sp_storage::{StorageData, StorageKey}; /// # use jsonrpsee::core::Error as RpcError; /// # use jsonrpsee::ws_client::WsClientBuilder; /// # use codec::Encode; -/// # use frame_support::{decl_storage, decl_module}; +/// # use frame_support::{construct_runtime, traits::ConstU32}; /// # use substrate_frame_rpc_support::StorageQuery; -/// # use frame_system::Config; /// # use sc_rpc_api::state::StateApiClient; +/// # use sp_runtime::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; /// # -/// # // Hash would normally be ::Hash, but we don't have -/// # // frame_system::Config implemented for TestRuntime. Here we just pretend. -/// # type Hash = (); +/// # construct_runtime!( +/// # pub enum TestRuntime where +/// # Block = frame_system::mocking::MockBlock, +/// # NodeBlock = frame_system::mocking::MockBlock, +/// # UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic, +/// # { +/// # System: frame_system::{Pallet, Call, Config, Storage, Event}, +/// # Test: pallet_test::{Pallet, Storage}, +/// # } +/// # ); /// # +/// # type Hash = sp_core::H256; /// # -/// # struct TestRuntime; -/// # -/// # decl_module! { -/// # pub struct Module for enum Call where origin: T::RuntimeOrigin {} +/// # impl frame_system::Config for TestRuntime { +/// # type BaseCallFilter = (); +/// # type BlockWeights = (); +/// # type BlockLength = (); +/// # type RuntimeOrigin = RuntimeOrigin; +/// # type RuntimeCall = RuntimeCall; +/// # type Index = u64; +/// # type BlockNumber = u64; +/// # type Hash = Hash; +/// # type Hashing = BlakeTwo256; +/// # type AccountId = u64; +/// # type Lookup = IdentityLookup; +/// # type Header = Header; +/// # type RuntimeEvent = RuntimeEvent; +/// # type BlockHashCount = (); +/// # type DbWeight = (); +/// # type Version = (); +/// # type PalletInfo = PalletInfo; +/// # type AccountData = (); +/// # type OnNewAccount = (); +/// # type OnKilledAccount = (); +/// # type SystemWeightInfo = (); +/// # type SS58Prefix = (); +/// # type OnSetCode = (); +/// # type MaxConsumers = ConstU32<16>; /// # } /// # +/// # impl pallet_test::Config for TestRuntime {} +/// # +/// /// pub type Loc = (i64, i64, i64); /// pub type Block = u8; /// /// // Note that all fields are marked pub. -/// decl_storage! { -/// trait Store for Module as TestRuntime { -/// pub LastActionId: u64; -/// pub Voxels: map hasher(blake2_128_concat) Loc => Block; -/// pub Actions: map hasher(blake2_128_concat) u64 => Loc; -/// pub Prefab: double_map hasher(blake2_128_concat) u128, hasher(blake2_128_concat) (i8, i8, i8) => Block; -/// } +/// pub use self::pallet_test::*; +/// +/// #[frame_support::pallet] +/// mod pallet_test { +/// use super::*; +/// use frame_support::pallet_prelude::*; +/// +/// #[pallet::pallet] +/// #[pallet::generate_store(pub(super) trait Store)] +/// pub struct Pallet(PhantomData); +/// +/// #[pallet::config] +/// pub trait Config: frame_system::Config {} +/// +/// #[pallet::storage] +/// pub type LastActionId = StorageValue<_, u64, ValueQuery>; +/// +/// #[pallet::storage] +/// pub type Voxels = StorageMap<_, Blake2_128Concat, Loc, Block>; +/// +/// #[pallet::storage] +/// pub type Actions = StorageMap<_, Blake2_128Concat, u64, Loc>; +/// +/// #[pallet::storage] +/// pub type Prefab = StorageDoubleMap< +/// _, +/// Blake2_128Concat, u128, +/// Blake2_128Concat, (i8, i8, i8), Block +/// >; /// } /// /// #[tokio::main] /// async fn main() -> Result<(), RpcError> { /// let cl = WsClientBuilder::default().build("ws://[::1]:9944").await?; /// -/// let q = StorageQuery::value::(); +/// let q = StorageQuery::value::>(); /// let hash = None::; /// let _: Option = q.get(&cl, hash).await?; /// -/// let q = StorageQuery::map::((0, 0, 0)); +/// let q = StorageQuery::map::, _>((0, 0, 0)); /// let _: Option = q.get(&cl, hash).await?; /// -/// let q = StorageQuery::map::(12); +/// let q = StorageQuery::map::, _>(12); /// let _: Option = q.get(&cl, hash).await?; /// -/// let q = StorageQuery::double_map::(3, (0, 0, 0)); +/// let q = StorageQuery::double_map::, _, _>(3, (0, 0, 0)); /// let _: Option = q.get(&cl, hash).await?; /// /// Ok(()) From 1f720c11b90d45bba0c4ddad60d3b9a27ca85441 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 22 Sep 2022 10:15:31 -0400 Subject: [PATCH 1191/1472] Rename anonymous to pure proxy (#12283) * rename anon to pure proxy * remove old weight comments * fix merge * Update frame/proxy/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * fn pure -> fn create_pure Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- docs/CHANGELOG.md | 2 +- frame/proxy/src/benchmarking.rs | 24 +++---- frame/proxy/src/lib.rs | 109 +++++++++----------------------- frame/proxy/src/tests.rs | 30 ++++----- frame/proxy/src/weights.rs | 12 ++-- 5 files changed, 64 insertions(+), 113 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c867a245739ff..25f8e582c78fc 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -360,7 +360,7 @@ Runtime ------- * Introduce stacked filtering (#6273) -* Allow "anonymous" proxied accounts (#6236) +* Allow "pure" proxied accounts (#6236) * Allow over-weight collective proposals to be closed (#6163) * Fix Election when ForceNone V1 (#6166) diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index f7e440d1f7d6f..58c0cb73011df 100644 --- a/frame/proxy/src/benchmarking.rs +++ b/frame/proxy/src/benchmarking.rs @@ -98,7 +98,7 @@ benchmarks! { let a in 0 .. T::MaxPending::get() - 1; let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; // In this case the caller is the "target" proxy - let caller: T::AccountId = account("anonymous", 0, SEED); + let caller: T::AccountId = account("pure", 0, SEED); let delegate: T::AccountId = account("target", p - 1, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); T::Currency::make_free_balance_be(&delegate, BalanceOf::::max_value() / 2u32.into()); @@ -218,7 +218,7 @@ benchmarks! { assert_eq!(proxies.len() as u32, 0); } - anonymous { + create_pure { let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); }: _( @@ -228,22 +228,22 @@ benchmarks! { 0 ) verify { - let anon_account = Pallet::::anonymous_account(&caller, &T::ProxyType::default(), 0, None); - assert_last_event::(Event::AnonymousCreated { - anonymous: anon_account, + let pure_account = Pallet::::pure_account(&caller, &T::ProxyType::default(), 0, None); + assert_last_event::(Event::PureCreated { + pure: pure_account, who: caller, proxy_type: T::ProxyType::default(), disambiguation_index: 0, }.into()); } - kill_anonymous { + kill_pure { let p in 0 .. (T::MaxProxies::get() - 2); let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - Pallet::::anonymous( + Pallet::::create_pure( RawOrigin::Signed(whitelisted_caller()).into(), T::ProxyType::default(), T::BlockNumber::zero(), @@ -251,13 +251,13 @@ benchmarks! { )?; let height = system::Pallet::::block_number(); let ext_index = system::Pallet::::extrinsic_index().unwrap_or(0); - let anon = Pallet::::anonymous_account(&caller, &T::ProxyType::default(), 0, None); + let pure_account = Pallet::::pure_account(&caller, &T::ProxyType::default(), 0, None); - add_proxies::(p, Some(anon.clone()))?; - ensure!(Proxies::::contains_key(&anon), "anon proxy not created"); - }: _(RawOrigin::Signed(anon.clone()), caller_lookup, T::ProxyType::default(), 0, height, ext_index) + add_proxies::(p, Some(pure_account.clone()))?; + ensure!(Proxies::::contains_key(&pure_account), "pure proxy not created"); + }: _(RawOrigin::Signed(pure_account.clone()), caller_lookup, T::ProxyType::default(), 0, height, ext_index) verify { - assert!(!Proxies::::contains_key(&anon)); + assert!(!Proxies::::contains_key(&pure_account)); } impl_benchmark_test_suite!(Proxy, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index af96069397255..5c07a2b012243 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -191,10 +191,6 @@ pub mod pallet { /// - `real`: The account that the proxy will make a call on behalf of. /// - `force_proxy_type`: Specify the exact proxy type to be used and checked for this call. /// - `call`: The call to be made by the `real` account. - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # #[pallet::weight({ let di = call.get_dispatch_info(); (T::WeightInfo::proxy(T::MaxProxies::get()) @@ -228,10 +224,6 @@ pub mod pallet { /// - `proxy_type`: The permissions allowed for this proxy account. /// - `delay`: The announcement period required of the initial proxy. Will generally be /// zero. - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # #[pallet::weight(T::WeightInfo::add_proxy(T::MaxProxies::get()))] pub fn add_proxy( origin: OriginFor, @@ -251,10 +243,6 @@ pub mod pallet { /// Parameters: /// - `proxy`: The account that the `caller` would like to remove as a proxy. /// - `proxy_type`: The permissions currently enabled for the removed proxy account. - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # #[pallet::weight(T::WeightInfo::remove_proxy(T::MaxProxies::get()))] pub fn remove_proxy( origin: OriginFor, @@ -271,12 +259,8 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_. /// - /// WARNING: This may be called on accounts created by `anonymous`, however if done, then + /// WARNING: This may be called on accounts created by `pure`, however if done, then /// the unreserved fees will be inaccessible. **All access to this account will be lost.** - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # #[pallet::weight(T::WeightInfo::remove_proxies(T::MaxProxies::get()))] pub fn remove_proxies(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -304,13 +288,8 @@ pub mod pallet { /// same sender, with the same parameters. /// /// Fails if there are insufficient funds to pay for deposit. - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # - /// TODO: Might be over counting 1 read - #[pallet::weight(T::WeightInfo::anonymous(T::MaxProxies::get()))] - pub fn anonymous( + #[pallet::weight(T::WeightInfo::create_pure(T::MaxProxies::get()))] + pub fn create_pure( origin: OriginFor, proxy_type: T::ProxyType, delay: T::BlockNumber, @@ -318,8 +297,8 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; - let anonymous = Self::anonymous_account(&who, &proxy_type, index, None); - ensure!(!Proxies::::contains_key(&anonymous), Error::::Duplicate); + let pure = Self::pure_account(&who, &proxy_type, index, None); + ensure!(!Proxies::::contains_key(&pure), Error::::Duplicate); let proxy_def = ProxyDefinition { delegate: who.clone(), proxy_type: proxy_type.clone(), delay }; @@ -329,9 +308,9 @@ pub mod pallet { let deposit = T::ProxyDepositBase::get() + T::ProxyDepositFactor::get(); T::Currency::reserve(&who, deposit)?; - Proxies::::insert(&anonymous, (bounded_proxies, deposit)); - Self::deposit_event(Event::AnonymousCreated { - anonymous, + Proxies::::insert(&pure, (bounded_proxies, deposit)); + Self::deposit_event(Event::PureCreated { + pure, who, proxy_type, disambiguation_index: index, @@ -340,28 +319,24 @@ pub mod pallet { Ok(()) } - /// Removes a previously spawned anonymous proxy. + /// Removes a previously spawned pure proxy. /// /// WARNING: **All access to this account will be lost.** Any funds held in it will be /// inaccessible. /// /// Requires a `Signed` origin, and the sender account must have been created by a call to - /// `anonymous` with corresponding parameters. - /// - /// - `spawner`: The account that originally called `anonymous` to create this account. - /// - `index`: The disambiguation index originally passed to `anonymous`. Probably `0`. - /// - `proxy_type`: The proxy type originally passed to `anonymous`. - /// - `height`: The height of the chain when the call to `anonymous` was processed. - /// - `ext_index`: The extrinsic index in which the call to `anonymous` was processed. - /// - /// Fails with `NoPermission` in case the caller is not a previously created anonymous - /// account whose `anonymous` call has corresponding parameters. - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # - #[pallet::weight(T::WeightInfo::kill_anonymous(T::MaxProxies::get()))] - pub fn kill_anonymous( + /// `pure` with corresponding parameters. + /// + /// - `spawner`: The account that originally called `pure` to create this account. + /// - `index`: The disambiguation index originally passed to `pure`. Probably `0`. + /// - `proxy_type`: The proxy type originally passed to `pure`. + /// - `height`: The height of the chain when the call to `pure` was processed. + /// - `ext_index`: The extrinsic index in which the call to `pure` was processed. + /// + /// Fails with `NoPermission` in case the caller is not a previously created pure + /// account whose `pure` call has corresponding parameters. + #[pallet::weight(T::WeightInfo::kill_pure(T::MaxProxies::get()))] + pub fn kill_pure( origin: OriginFor, spawner: AccountIdLookupOf, proxy_type: T::ProxyType, @@ -373,7 +348,7 @@ pub mod pallet { let spawner = T::Lookup::lookup(spawner)?; let when = (height, ext_index); - let proxy = Self::anonymous_account(&spawner, &proxy_type, index, Some(when)); + let proxy = Self::pure_account(&spawner, &proxy_type, index, Some(when)); ensure!(proxy == who, Error::::NoPermission); let (_, deposit) = Proxies::::take(&who); @@ -397,12 +372,6 @@ pub mod pallet { /// Parameters: /// - `real`: The account that the proxy will make a call on behalf of. /// - `call_hash`: The hash of the call to be made by the `real` account. - /// - /// # - /// Weight is a function of: - /// - A: the number of announcements made. - /// - P: the number of proxies the user has. - /// # #[pallet::weight(T::WeightInfo::announce(T::MaxPending::get(), T::MaxProxies::get()))] pub fn announce( origin: OriginFor, @@ -452,12 +421,6 @@ pub mod pallet { /// Parameters: /// - `real`: The account that the proxy will make a call on behalf of. /// - `call_hash`: The hash of the call to be made by the `real` account. - /// - /// # - /// Weight is a function of: - /// - A: the number of announcements made. - /// - P: the number of proxies the user has. - /// # #[pallet::weight(T::WeightInfo::remove_announcement( T::MaxPending::get(), T::MaxProxies::get() @@ -484,12 +447,6 @@ pub mod pallet { /// Parameters: /// - `delegate`: The account that previously announced the call. /// - `call_hash`: The hash of the call to be made. - /// - /// # - /// Weight is a function of: - /// - A: the number of announcements made. - /// - P: the number of proxies the user has. - /// # #[pallet::weight(T::WeightInfo::reject_announcement( T::MaxPending::get(), T::MaxProxies::get() @@ -519,12 +476,6 @@ pub mod pallet { /// - `real`: The account that the proxy will make a call on behalf of. /// - `force_proxy_type`: Specify the exact proxy type to be used and checked for this call. /// - `call`: The call to be made by the `real` account. - /// - /// # - /// Weight is a function of: - /// - A: the number of announcements made. - /// - P: the number of proxies the user has. - /// # #[pallet::weight({ let di = call.get_dispatch_info(); (T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get()) @@ -565,10 +516,10 @@ pub mod pallet { pub enum Event { /// A proxy was executed correctly, with the given. ProxyExecuted { result: DispatchResult }, - /// Anonymous account has been created by new proxy with given + /// A pure account has been created by new proxy with given /// disambiguation index and proxy type. - AnonymousCreated { - anonymous: T::AccountId, + PureCreated { + pure: T::AccountId, who: T::AccountId, proxy_type: T::ProxyType, disambiguation_index: u16, @@ -642,7 +593,7 @@ pub mod pallet { } impl Pallet { - /// Calculate the address of an anonymous account. + /// Calculate the address of an pure account. /// /// - `who`: The spawner account. /// - `proxy_type`: The type of the proxy that the sender will be registered as over the @@ -651,9 +602,9 @@ impl Pallet { /// - `index`: A disambiguation index, in case this is called multiple times in the same /// transaction (e.g. with `utility::batch`). Unless you're using `batch` you probably just /// want to use `0`. - /// - `maybe_when`: The block height and extrinsic index of when the anonymous account was + /// - `maybe_when`: The block height and extrinsic index of when the pure account was /// created. None to use current block height and extrinsic index. - pub fn anonymous_account( + pub fn pure_account( who: &T::AccountId, proxy_type: &T::ProxyType, index: u16, @@ -830,9 +781,9 @@ impl Pallet { Some(Call::remove_proxy { ref proxy_type, .. }) if !def.proxy_type.is_superset(proxy_type) => false, - // Proxy call cannot remove all proxies or kill anonymous proxies unless it has full + // Proxy call cannot remove all proxies or kill pure proxies unless it has full // permissions. - Some(Call::remove_proxies { .. }) | Some(Call::kill_anonymous { .. }) + Some(Call::remove_proxies { .. }) | Some(Call::kill_pure { .. }) if def.proxy_type != T::ProxyType::default() => false, _ => def.proxy_type.filter(c), diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 3ed80107e0702..17bc7bcb92ee1 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -550,13 +550,13 @@ fn proxying_works() { } #[test] -fn anonymous_works() { +fn pure_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); - let anon = Proxy::anonymous_account(&1, &ProxyType::Any, 0, None); + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); + let anon = Proxy::pure_account(&1, &ProxyType::Any, 0, None); System::assert_last_event( - ProxyEvent::AnonymousCreated { - anonymous: anon, + ProxyEvent::PureCreated { + pure: anon, who: 1, proxy_type: ProxyType::Any, disambiguation_index: 0, @@ -564,20 +564,20 @@ fn anonymous_works() { .into(), ); - // other calls to anonymous allowed as long as they're not exactly the same. - assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::JustTransfer, 0, 0)); - assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::Any, 0, 1)); - let anon2 = Proxy::anonymous_account(&2, &ProxyType::Any, 0, None); - assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(2), ProxyType::Any, 0, 0)); + // other calls to pure allowed as long as they're not exactly the same. + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::JustTransfer, 0, 0)); + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 1)); + let anon2 = Proxy::pure_account(&2, &ProxyType::Any, 0, None); + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(2), ProxyType::Any, 0, 0)); assert_noop!( - Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0), + Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0), Error::::Duplicate ); System::set_extrinsic_index(1); - assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); System::set_extrinsic_index(0); System::set_block_number(2); - assert_ok!(Proxy::anonymous(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); let call = Box::new(call_transfer(6, 1)); assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), anon, 5)); @@ -585,7 +585,7 @@ fn anonymous_works() { System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 1); - let call = Box::new(RuntimeCall::Proxy(ProxyCall::new_call_variant_kill_anonymous( + let call = Box::new(RuntimeCall::Proxy(ProxyCall::new_call_variant_kill_pure( 1, ProxyType::Any, 0, @@ -596,7 +596,7 @@ fn anonymous_works() { let de = DispatchError::from(Error::::NoPermission).stripped(); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Err(de) }.into()); assert_noop!( - Proxy::kill_anonymous(RuntimeOrigin::signed(1), 1, ProxyType::Any, 0, 1, 0), + Proxy::kill_pure(RuntimeOrigin::signed(1), 1, ProxyType::Any, 0, 1, 0), Error::::NoPermission ); assert_eq!(Balances::free_balance(1), 0); diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 2d409d977f875..25457d52f4391 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -52,8 +52,8 @@ pub trait WeightInfo { fn add_proxy(p: u32, ) -> Weight; fn remove_proxy(p: u32, ) -> Weight; fn remove_proxies(p: u32, ) -> Weight; - fn anonymous(p: u32, ) -> Weight; - fn kill_anonymous(p: u32, ) -> Weight; + fn create_pure(p: u32, ) -> Weight; + fn kill_pure(p: u32, ) -> Weight; } /// Weights for pallet_proxy using the Substrate node and recommended hardware. @@ -138,7 +138,7 @@ impl WeightInfo for SubstrateWeight { } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) - fn anonymous(p: u32, ) -> Weight { + fn create_pure(p: u32, ) -> Weight { Weight::from_ref_time(31_077_000 as u64) // Standard Error: 3_000 .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(p as u64)) @@ -146,7 +146,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) - fn kill_anonymous(p: u32, ) -> Weight { + fn kill_pure(p: u32, ) -> Weight { Weight::from_ref_time(24_657_000 as u64) // Standard Error: 2_000 .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(p as u64)) @@ -236,7 +236,7 @@ impl WeightInfo for () { } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) - fn anonymous(p: u32, ) -> Weight { + fn create_pure(p: u32, ) -> Weight { Weight::from_ref_time(31_077_000 as u64) // Standard Error: 3_000 .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(p as u64)) @@ -244,7 +244,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) - fn kill_anonymous(p: u32, ) -> Weight { + fn kill_pure(p: u32, ) -> Weight { Weight::from_ref_time(24_657_000 as u64) // Standard Error: 2_000 .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(p as u64)) From bffd6a3007e0163cff7458559105028a4d2031a0 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 23 Sep 2022 10:36:33 +0100 Subject: [PATCH 1192/1472] Fast Unstake Pallet (#12129) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add failing test for itamar * an ugly example of fast unstake * Revert "add failing test for itamar" This reverts commit bdd139989cb4dfa8cc6cc6b5ee470a711df32d25. * fast unstake wip * clean it up a bit * some comments * on_idle logic * fix * comment * new working version, checks all pass, looking good * some notes * add mock boilerplate * more boilerplate * simplify the weight stuff * ExtBuilder for pools * fmt * rm bags-list, simplify setup_works * mock + tests boilerplate * make some benchmarks work * mock boilerplate * tests boilerplate * run_to_block works * add Error enums * add test * note * make UnstakeRequest fields pub * some tests * fix origin * fmt * add fast_unstake_events_since_last_call * text * rewrite some benchmes and fix them -- the outcome is still strange * Fix weights * cleanup * Update frame/election-provider-support/solution-type/src/single_page.rs * fix build * Fix pools tests * iterate teset + mock * test unfinished * cleanup and add some tests * add test successful_multi_queue * comment * rm Head check * add TODO * complete successful_multi_queue * + test early_exit * fix a lot of things above the beautiful atlantic ocean 🌊 * seemingly it is finished now * Fix build * ".git/.scripts/fmt.sh" 1 * Fix slashing amount as well * better docs * abstract types * rm use * import * Update frame/nomination-pools/benchmarking/src/lib.rs Co-authored-by: Nitwit <47109040+nitwit69@users.noreply.github.com> * Update frame/fast-unstake/src/types.rs Co-authored-by: Nitwit <47109040+nitwit69@users.noreply.github.com> * Fix build * fmt * Update frame/fast-unstake/src/lib.rs Co-authored-by: Keith Yeung * make bounded * feedback from code review with Ankan * Update frame/fast-unstake/src/lib.rs Co-authored-by: Roman Useinov * Update frame/fast-unstake/src/lib.rs Co-authored-by: Roman Useinov * Update frame/fast-unstake/src/lib.rs Co-authored-by: Roman Useinov * Update frame/fast-unstake/src/lib.rs Co-authored-by: Roman Useinov * Update frame/fast-unstake/src/lib.rs Co-authored-by: Roman Useinov * Update frame/fast-unstake/src/lib.rs Co-authored-by: Roman Useinov * Update frame/fast-unstake/src/lib.rs Co-authored-by: Roman Useinov * Update frame/fast-unstake/src/lib.rs Co-authored-by: Roman Useinov * Update frame/fast-unstake/src/lib.rs Co-authored-by: Roman Useinov * Update frame/fast-unstake/src/mock.rs * update to master * some final review comments * fmt * fix clippy * remove unused * ".git/.scripts/fmt.sh" 1 * make it all build again * fmt * undo fishy change Co-authored-by: Ross Bulat Co-authored-by: command-bot <> Co-authored-by: Nitwit <47109040+nitwit69@users.noreply.github.com> Co-authored-by: Keith Yeung Co-authored-by: Roman Useinov --- Cargo.lock | 26 + Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 9 + .../election-provider-multi-phase/src/lib.rs | 11 + .../election-provider-multi-phase/src/mock.rs | 4 + frame/election-provider-support/src/lib.rs | 9 +- .../election-provider-support/src/onchain.rs | 8 + frame/fast-unstake/Cargo.toml | 70 ++ frame/fast-unstake/src/benchmarking.rs | 228 ++++ frame/fast-unstake/src/lib.rs | 505 ++++++++ frame/fast-unstake/src/mock.rs | 387 ++++++ frame/fast-unstake/src/tests.rs | 1036 +++++++++++++++++ frame/fast-unstake/src/types.rs | 119 ++ frame/fast-unstake/src/weights.rs | 210 ++++ .../nomination-pools/benchmarking/src/lib.rs | 36 +- frame/nomination-pools/src/lib.rs | 3 +- frame/nomination-pools/src/tests.rs | 2 +- frame/staking/src/lib.rs | 2 +- frame/staking/src/pallet/impls.rs | 4 +- frame/staking/src/pallet/mod.rs | 5 +- 21 files changed, 2650 insertions(+), 29 deletions(-) create mode 100644 frame/fast-unstake/Cargo.toml create mode 100644 frame/fast-unstake/src/benchmarking.rs create mode 100644 frame/fast-unstake/src/lib.rs create mode 100644 frame/fast-unstake/src/mock.rs create mode 100644 frame/fast-unstake/src/tests.rs create mode 100644 frame/fast-unstake/src/types.rs create mode 100644 frame/fast-unstake/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 5172c3d02861d..d1349ce488fa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3376,6 +3376,7 @@ dependencies = [ "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", + "pallet-fast-unstake", "pallet-gilt", "pallet-grandpa", "pallet-identity", @@ -5718,6 +5719,31 @@ dependencies = [ "sp-tasks", ] +[[package]] +name = "pallet-fast-unstake" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "pallet-nomination-pools", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", + "sp-tracing", + "substrate-test-utils", +] + [[package]] name = "pallet-gilt" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 48a31940fd3bf..018355df6c9fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,6 +90,7 @@ members = [ "frame/contracts/rpc/runtime-api", "frame/conviction-voting", "frame/democracy", + "frame/fast-unstake", "frame/try-runtime", "frame/election-provider-multi-phase", "frame/election-provider-support", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index d52b1aaccfcfa..e722024231651 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -68,6 +68,7 @@ pallet-democracy = { version = "4.0.0-dev", default-features = false, path = ".. pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" } pallet-election-provider-support-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-support/benchmarking", optional = true } pallet-elections-phragmen = { version = "5.0.0-dev", default-features = false, path = "../../../frame/elections-phragmen" } +pallet-fast-unstake = { version = "4.0.0-dev", default-features = false, path = "../../../frame/fast-unstake" } pallet-gilt = { version = "4.0.0-dev", default-features = false, path = "../../../frame/gilt" } pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../../frame/grandpa" } pallet-im-online = { version = "4.0.0-dev", default-features = false, path = "../../../frame/im-online" } @@ -142,6 +143,7 @@ std = [ "pallet-conviction-voting/std", "pallet-democracy/std", "pallet-elections-phragmen/std", + "pallet-fast-unstake/std", "frame-executive/std", "pallet-gilt/std", "pallet-grandpa/std", @@ -220,6 +222,7 @@ runtime-benchmarks = [ "pallet-election-provider-multi-phase/runtime-benchmarks", "pallet-election-provider-support-benchmarking/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", + "pallet-fast-unstake/runtime-benchmarks", "pallet-gilt/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-identity/runtime-benchmarks", @@ -272,6 +275,7 @@ try-runtime = [ "pallet-democracy/try-runtime", "pallet-election-provider-multi-phase/try-runtime", "pallet-elections-phragmen/try-runtime", + "pallet-fast-unstake/try-runtime", "pallet-gilt/try-runtime", "pallet-grandpa/try-runtime", "pallet-im-online/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index d6a9798b4d9ca..8ed5f1c847f5e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -579,6 +579,13 @@ impl pallet_staking::Config for Runtime { type BenchmarkingConfig = StakingBenchmarkingConfig; } +impl pallet_fast_unstake::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SlashPerEra = ConstU128<{ DOLLARS }>; + type ControlOrigin = frame_system::EnsureRoot; + type WeightInfo = (); +} + parameter_types! { // phase durations. 1/4 of the last session for each. pub const SignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 4; @@ -1655,6 +1662,7 @@ construct_runtime!( NominationPools: pallet_nomination_pools, RankedPolls: pallet_referenda::, RankedCollective: pallet_ranked_collective, + FastUnstake: pallet_fast_unstake, } ); @@ -1741,6 +1749,7 @@ mod benches { [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [pallet_election_provider_support_benchmarking, EPSBench::] [pallet_elections_phragmen, Elections] + [pallet_fast_unstake, FastUnstake] [pallet_gilt, Gilt] [pallet_grandpa, Grandpa] [pallet_identity, Identity] diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 3c9b15dabb053..05353e5a3ac61 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -318,6 +318,10 @@ impl ElectionProvider for NoFallback { type DataProvider = T::DataProvider; type Error = &'static str; + fn ongoing() -> bool { + false + } + fn elect() -> Result, Self::Error> { // Do nothing, this will enable the emergency phase. Err("NoFallback.") @@ -1598,6 +1602,13 @@ impl ElectionProvider for Pallet { type Error = ElectionError; type DataProvider = T::DataProvider; + fn ongoing() -> bool { + match Self::current_phase() { + Phase::Off => false, + _ => true, + } + } + fn elect() -> Result, Self::Error> { match Self::do_elect() { Ok(supports) => { diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index d7affc14564f5..34aa2e1bbfc58 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -303,6 +303,10 @@ impl ElectionProvider for MockFallback { type Error = &'static str; type DataProvider = StakingMock; + fn ongoing() -> bool { + false + } + fn elect() -> Result, Self::Error> { Self::elect_with_bounds(Bounded::max_value(), Bounded::max_value()) } diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 9f60411435da0..0bf62bd8c35cd 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -136,7 +136,7 @@ //! type BlockNumber = BlockNumber; //! type Error = &'static str; //! type DataProvider = T::DataProvider; -//! +//! fn ongoing() -> bool { false } //! fn elect() -> Result, Self::Error> { //! Self::DataProvider::electable_targets(None) //! .map_err(|_| "failed to elect") @@ -370,6 +370,9 @@ pub trait ElectionProvider { BlockNumber = Self::BlockNumber, >; + /// Indicate if this election provider is currently ongoing an asynchronous election or not. + fn ongoing() -> bool; + /// Elect a new set of winners, without specifying any bounds on the amount of data fetched from /// [`Self::DataProvider`]. An implementation could nonetheless impose its own custom limits. /// @@ -420,6 +423,10 @@ where fn elect() -> Result, Self::Error> { Err(" cannot do anything.") } + + fn ongoing() -> bool { + false + } } /// A utility trait for something to implement `ElectionDataProvider` in a sensible way. diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index e477499f3c927..10c3519d03df6 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -138,6 +138,10 @@ impl ElectionProvider for UnboundedExecution { type Error = Error; type DataProvider = T::DataProvider; + fn ongoing() -> bool { + false + } + fn elect() -> Result, Self::Error> { // This should not be called if not in `std` mode (and therefore neither in genesis nor in // testing) @@ -167,6 +171,10 @@ impl ElectionProvider for BoundedExecution { type Error = Error; type DataProvider = T::DataProvider; + fn ongoing() -> bool { + false + } + fn elect() -> Result, Self::Error> { elect_with::(Some(T::VotersBound::get() as usize), Some(T::TargetsBound::get() as usize)) } diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml new file mode 100644 index 0000000000000..1fa118dba4a8d --- /dev/null +++ b/frame/fast-unstake/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "pallet-fast-unstake" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Unlicense" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME fast unstake pallet" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } + +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } + +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-staking = { default-features = false, path = "../../primitives/staking" } + +pallet-balances = { default-features = false, path = "../balances" } +pallet-timestamp = { default-features = false, path = "../timestamp" } +pallet-staking = { default-features = false, path = "../staking" } +pallet-nomination-pools = { default-features = false, path = "../nomination-pools" } +frame-election-provider-support = { default-features = false, path = "../election-provider-support" } + +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } + +[dev-dependencies] +pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } + +[features] +default = ["std"] +std = [ + "codec/std", + "log/std", + "scale-info/std", + + "frame-support/std", + "frame-system/std", + + "sp-io/std", + "sp-staking/std", + "sp-runtime/std", + "sp-std/std", + + "pallet-staking/std", + "pallet-nomination-pools/std", + "pallet-balances/std", + "pallet-timestamp/std", + "frame-election-provider-support/std", + + "frame-benchmarking/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs new file mode 100644 index 0000000000000..68a3da0d40af3 --- /dev/null +++ b/frame/fast-unstake/src/benchmarking.rs @@ -0,0 +1,228 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmarking for pallet-fast-unstake. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::{types::*, Pallet as FastUnstake, *}; +use frame_benchmarking::{benchmarks, whitelist_account}; +use frame_support::{ + assert_ok, + traits::{Currency, EnsureOrigin, Get, Hooks}, +}; +use frame_system::RawOrigin; +use pallet_nomination_pools::{Pallet as Pools, PoolId}; +use pallet_staking::Pallet as Staking; +use sp_runtime::traits::{StaticLookup, Zero}; +use sp_staking::EraIndex; +use sp_std::prelude::*; + +const USER_SEED: u32 = 0; +const DEFAULT_BACKER_PER_VALIDATOR: u32 = 128; +const MAX_VALIDATORS: u32 = 128; + +type CurrencyOf = ::Currency; + +fn l( + who: T::AccountId, +) -> <::Lookup as StaticLookup>::Source { + T::Lookup::unlookup(who) +} + +fn create_unexposed_nominator() -> T::AccountId { + let account = frame_benchmarking::account::("nominator_42", 0, USER_SEED); + fund_and_bond_account::(&account); + account +} + +fn fund_and_bond_account(account: &T::AccountId) { + let stake = CurrencyOf::::minimum_balance() * 100u32.into(); + CurrencyOf::::make_free_balance_be(&account, stake * 10u32.into()); + + let account_lookup = l::(account.clone()); + // bond and nominate ourselves, this will guarantee that we are not backing anyone. + assert_ok!(Staking::::bond( + RawOrigin::Signed(account.clone()).into(), + account_lookup.clone(), + stake, + pallet_staking::RewardDestination::Controller, + )); + assert_ok!(Staking::::nominate( + RawOrigin::Signed(account.clone()).into(), + vec![account_lookup] + )); +} + +pub(crate) fn fast_unstake_events() -> Vec> { + frame_system::Pallet::::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| ::RuntimeEvent::from(e).try_into().ok()) + .collect::>() +} + +fn setup_pool() -> PoolId { + let depositor = frame_benchmarking::account::("depositor_42", 0, USER_SEED); + let depositor_lookup = l::(depositor.clone()); + + let stake = Pools::::depositor_min_bond(); + CurrencyOf::::make_free_balance_be(&depositor, stake * 10u32.into()); + + Pools::::create( + RawOrigin::Signed(depositor.clone()).into(), + stake, + depositor_lookup.clone(), + depositor_lookup.clone(), + depositor_lookup, + ) + .unwrap(); + + pallet_nomination_pools::LastPoolId::::get() +} + +fn setup_staking(v: u32, until: EraIndex) { + let ed = CurrencyOf::::minimum_balance(); + + log!(debug, "registering {} validators and {} eras.", v, until); + + // our validators don't actually need to registered in staking -- just generate `v` random + // accounts. + let validators = (0..v) + .map(|x| frame_benchmarking::account::("validator", x, USER_SEED)) + .collect::>(); + + for era in 0..=until { + let others = (0..DEFAULT_BACKER_PER_VALIDATOR) + .map(|s| { + let who = frame_benchmarking::account::("nominator", era, s); + let value = ed; + pallet_staking::IndividualExposure { who, value } + }) + .collect::>(); + let exposure = + pallet_staking::Exposure { total: Default::default(), own: Default::default(), others }; + validators.iter().for_each(|v| { + Staking::::add_era_stakers(era, v.clone(), exposure.clone()); + }); + } +} + +fn on_idle_full_block() { + let remaining_weight = ::BlockWeights::get().max_block; + FastUnstake::::on_idle(Zero::zero(), remaining_weight); +} + +benchmarks! { + // on_idle, we we don't check anyone, but fully unbond and move them to another pool. + on_idle_unstake { + let who = create_unexposed_nominator::(); + let pool_id = setup_pool::(); + assert_ok!(FastUnstake::::register_fast_unstake( + RawOrigin::Signed(who.clone()).into(), + Some(pool_id) + )); + ErasToCheckPerBlock::::put(1); + + // run on_idle once. This will check era 0. + assert_eq!(Head::::get(), None); + on_idle_full_block::(); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { stash: who.clone(), checked: vec![0].try_into().unwrap(), maybe_pool_id: Some(pool_id) }) + ); + } + : { + on_idle_full_block::(); + } + verify { + assert!(matches!( + fast_unstake_events::().last(), + Some(Event::Unstaked { .. }) + )); + } + + // on_idle, when we check some number of eras, + on_idle_check { + // number of eras multiplied by validators in that era. + let x in (::BondingDuration::get() * 1) .. (::BondingDuration::get() * MAX_VALIDATORS); + + let v = x / ::BondingDuration::get(); + let u = ::BondingDuration::get(); + + ErasToCheckPerBlock::::put(u); + pallet_staking::CurrentEra::::put(u); + + // setup staking with v validators and u eras of data (0..=u) + setup_staking::(v, u); + let who = create_unexposed_nominator::(); + assert_ok!(FastUnstake::::register_fast_unstake( + RawOrigin::Signed(who.clone()).into(), + None, + )); + + // no one is queued thus far. + assert_eq!(Head::::get(), None); + } + : { + on_idle_full_block::(); + } + verify { + let checked: frame_support::BoundedVec<_, _> = (1..=u).rev().collect::>().try_into().unwrap(); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { stash: who.clone(), checked, maybe_pool_id: None }) + ); + assert!(matches!( + fast_unstake_events::().last(), + Some(Event::Checking { .. }) + )); + } + + register_fast_unstake { + let who = create_unexposed_nominator::(); + whitelist_account!(who); + assert_eq!(Queue::::count(), 0); + + } + :_(RawOrigin::Signed(who.clone()), None) + verify { + assert_eq!(Queue::::count(), 1); + } + + deregister { + let who = create_unexposed_nominator::(); + assert_ok!(FastUnstake::::register_fast_unstake( + RawOrigin::Signed(who.clone()).into(), + None + )); + assert_eq!(Queue::::count(), 1); + whitelist_account!(who); + } + :_(RawOrigin::Signed(who.clone())) + verify { + assert_eq!(Queue::::count(), 0); + } + + control { + let origin = ::ControlOrigin::successful_origin(); + } + : _(origin, 128) + verify {} + + impl_benchmark_test_suite!(Pallet, crate::mock::ExtBuilder::default().build(), crate::mock::Runtime) +} diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs new file mode 100644 index 0000000000000..51416808f48c8 --- /dev/null +++ b/frame/fast-unstake/src/lib.rs @@ -0,0 +1,505 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A pallet that's designed to JUST do the following: +//! +//! If a nominator is not exposed in any `ErasStakers` (i.e. "has not actively backed any +//! validators in the last `BondingDuration` days"), then they can register themselves in this +//! pallet, unstake faster than having to wait an entire bonding duration, and potentially move +//! into a nomination pool. +//! +//! Appearing in the exposure of a validator means being exposed equal to that validator from the +//! point of view of the staking system. This usually means earning rewards with the validator, and +//! also being at the risk of slashing with the validator. This is equivalent to the "Active +//! Nominator" role explained in the +//! [February Staking Update](https://polkadot.network/blog/staking-update-february-2022/). +//! +//! This pallet works off the basis of `on_idle`, meaning that it provides no guarantee about when +//! it will succeed, if at all. Moreover, the queue implementation is unordered. In case of +//! congestion, no FIFO ordering is provided. +//! +//! Stakers who are certain about NOT being exposed can register themselves with +//! [`Call::register_fast_unstake`]. This will chill, and fully unbond the staker, and place them in +//! the queue to be checked. +//! +//! Once queued, but not being actively processed, stakers can withdraw their request via +//! [`Call::deregister`]. +//! +//! Once queued, a staker wishing to unbond can perform no further action in pallet-staking. This is +//! to prevent them from accidentally exposing themselves behind a validator etc. +//! +//! Once processed, if successful, no additional fee for the checking process is taken, and the +//! staker is instantly unbonded. Optionally, if they have asked to join a pool, their *entire* +//! stake is joined into their pool of choice. +//! +//! If unsuccessful, meaning that the staker was exposed sometime in the last `BondingDuration` eras +//! they will end up being slashed for the amount of wasted work they have inflicted on the chian. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +// NOTE: enable benchmarking in tests as well. +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +mod types; +pub mod weights; + +pub const LOG_TARGET: &'static str = "runtime::fast-unstake"; + +// syntactic sugar for logging. +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: crate::LOG_TARGET, + concat!("[{:?}] 💨 ", $patter), >::block_number() $(, $values)* + ) + }; +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use crate::types::*; + use frame_election_provider_support::ElectionProvider; + use frame_support::pallet_prelude::*; + use frame_system::{pallet_prelude::*, RawOrigin}; + use pallet_nomination_pools::PoolId; + use pallet_staking::Pallet as Staking; + use sp_runtime::{ + traits::{Saturating, Zero}, + DispatchResult, + }; + use sp_staking::EraIndex; + use sp_std::{prelude::*, vec::Vec}; + use weights::WeightInfo; + + #[derive(scale_info::TypeInfo, codec::Encode, codec::Decode, codec::MaxEncodedLen)] + #[codec(mel_bound(T: Config))] + #[scale_info(skip_type_params(T))] + pub struct MaxChecking(sp_std::marker::PhantomData); + impl frame_support::traits::Get for MaxChecking { + fn get() -> u32 { + ::BondingDuration::get() + 1 + } + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: + frame_system::Config + + pallet_staking::Config< + CurrencyBalance = ::CurrencyBalance, + > + pallet_nomination_pools::Config + { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent> + + TryInto>; + + /// The amount of balance slashed per each era that was wastefully checked. + /// + /// A reasonable value could be `runtime_weight_to_fee(weight_per_era_check)`. + type SlashPerEra: Get>; + + /// The origin that can control this pallet. + type ControlOrigin: frame_support::traits::EnsureOrigin; + + /// The weight information of this pallet. + type WeightInfo: WeightInfo; + } + + /// The current "head of the queue" being unstaked. + #[pallet::storage] + pub type Head = + StorageValue<_, UnstakeRequest>, OptionQuery>; + + /// The map of all accounts wishing to be unstaked. + /// + /// Points the `AccountId` wishing to unstake to the optional `PoolId` they wish to join + /// thereafter. + #[pallet::storage] + pub type Queue = CountedStorageMap<_, Twox64Concat, T::AccountId, Option>; + + /// Number of eras to check per block. + /// + /// If set to 0, this pallet does absolutely nothing. + /// + /// Based on the amount of weight available at `on_idle`, up to this many eras of a single + /// nominator might be checked. + #[pallet::storage] + pub type ErasToCheckPerBlock = StorageValue<_, u32, ValueQuery>; + + /// The events of this pallet. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A staker was unstaked. + Unstaked { stash: T::AccountId, maybe_pool_id: Option, result: DispatchResult }, + /// A staker was slashed for requesting fast-unstake whilst being exposed. + Slashed { stash: T::AccountId, amount: BalanceOf }, + /// A staker was partially checked for the given eras, but the process did not finish. + Checking { stash: T::AccountId, eras: Vec }, + /// Some internal error happened while migrating stash. They are removed as head as a + /// consequence. + Errored { stash: T::AccountId }, + /// An internal error happened. Operations will be paused now. + InternalError, + } + + #[pallet::error] + #[cfg_attr(test, derive(PartialEq))] + pub enum Error { + /// The provided Controller account was not found. + /// + /// This means that the given account is not bonded. + NotController, + /// The bonded account has already been queued. + AlreadyQueued, + /// The bonded account has active unlocking chunks. + NotFullyBonded, + /// The provided un-staker is not in the `Queue`. + NotQueued, + /// The provided un-staker is already in Head, and cannot deregister. + AlreadyHead, + } + + #[pallet::hooks] + impl Hooks for Pallet { + fn on_idle(_: T::BlockNumber, remaining_weight: Weight) -> Weight { + if remaining_weight.any_lt(T::DbWeight::get().reads(2)) { + return Weight::from_ref_time(0) + } + + Self::do_on_idle(remaining_weight) + } + } + + #[pallet::call] + impl Pallet { + /// Register oneself for fast-unstake. + /// + /// The dispatch origin of this call must be signed by the controller account, similar to + /// `staking::unbond`. + /// + /// The stash associated with the origin must have no ongoing unlocking chunks. If + /// successful, this will fully unbond and chill the stash. Then, it will enqueue the stash + /// to be checked in further blocks. + /// + /// If by the time this is called, the stash is actually eligible for fast-unstake, then + /// they are guaranteed to remain eligible, because the call will chill them as well. + /// + /// If the check works, the entire staking data is removed, i.e. the stash is fully + /// unstaked, and they potentially join a pool with their entire bonded stake. + /// + /// If the check fails, the stash remains chilled and waiting for being unbonded as in with + /// the normal staking system, but they lose part of their unbonding chunks due to consuming + /// the chain's resources. + #[pallet::weight(::WeightInfo::register_fast_unstake())] + pub fn register_fast_unstake( + origin: OriginFor, + maybe_pool_id: Option, + ) -> DispatchResult { + let ctrl = ensure_signed(origin)?; + + let ledger = + pallet_staking::Ledger::::get(&ctrl).ok_or(Error::::NotController)?; + ensure!(!Queue::::contains_key(&ledger.stash), Error::::AlreadyQueued); + ensure!( + Head::::get().map_or(true, |UnstakeRequest { stash, .. }| stash != ledger.stash), + Error::::AlreadyHead + ); + // second part of the && is defensive. + ensure!( + ledger.active == ledger.total && ledger.unlocking.is_empty(), + Error::::NotFullyBonded + ); + + // chill and fully unstake. + Staking::::chill(RawOrigin::Signed(ctrl.clone()).into())?; + Staking::::unbond(RawOrigin::Signed(ctrl).into(), ledger.total)?; + + // enqueue them. + Queue::::insert(ledger.stash, maybe_pool_id); + Ok(()) + } + + /// Deregister oneself from the fast-unstake (also cancels joining the pool if that was + /// supplied on `register_fast_unstake` . + /// + /// This is useful if one is registered, they are still waiting, and they change their mind. + /// + /// Note that the associated stash is still fully unbonded and chilled as a consequence of + /// calling `register_fast_unstake`. This should probably be followed by a call to + /// `Staking::rebond`. + #[pallet::weight(::WeightInfo::deregister())] + pub fn deregister(origin: OriginFor) -> DispatchResult { + let ctrl = ensure_signed(origin)?; + let stash = pallet_staking::Ledger::::get(&ctrl) + .map(|l| l.stash) + .ok_or(Error::::NotController)?; + ensure!(Queue::::contains_key(&stash), Error::::NotQueued); + ensure!( + Head::::get().map_or(true, |UnstakeRequest { stash, .. }| stash != stash), + Error::::AlreadyHead + ); + Queue::::remove(stash); + Ok(()) + } + + /// Control the operation of this pallet. + /// + /// Dispatch origin must be signed by the [`Config::ControlOrigin`]. + #[pallet::weight(::WeightInfo::control())] + pub fn control(origin: OriginFor, unchecked_eras_to_check: EraIndex) -> DispatchResult { + let _ = T::ControlOrigin::ensure_origin(origin)?; + ErasToCheckPerBlock::::put(unchecked_eras_to_check); + Ok(()) + } + } + + impl Pallet { + /// process up to `remaining_weight`. + /// + /// Returns the actual weight consumed. + /// + /// Written for readability in mind, not efficiency. For example: + /// + /// 1. We assume this is only ever called once per `on_idle`. This is because we know that + /// in all use cases, even a single nominator cannot be unbonded in a single call. Multiple + /// calls to this function are thus not needed. + /// + /// 2. We will only mark a staker as unstaked if at the beginning of a check cycle, they are + /// found out to have no eras to check. At the end of a check cycle, even if they are fully + /// checked, we don't finish the process. + pub(crate) fn do_on_idle(remaining_weight: Weight) -> Weight { + let mut eras_to_check_per_block = ErasToCheckPerBlock::::get(); + if eras_to_check_per_block.is_zero() { + return T::DbWeight::get().reads(1) + } + + // NOTE: here we're assuming that the number of validators has only ever increased, + // meaning that the number of exposures to check is either this per era, or less. + let validator_count = pallet_staking::ValidatorCount::::get(); + + // determine the number of eras to check. This is based on both `ErasToCheckPerBlock` + // and `remaining_weight` passed on to us from the runtime executive. + let max_weight = |v, u| { + ::WeightInfo::on_idle_check(v * u) + .max(::WeightInfo::on_idle_unstake()) + }; + while max_weight(validator_count, eras_to_check_per_block).any_gt(remaining_weight) { + eras_to_check_per_block.saturating_dec(); + if eras_to_check_per_block.is_zero() { + log!(debug, "early existing because eras_to_check_per_block is zero"); + return T::DbWeight::get().reads(2) + } + } + + if ::ElectionProvider::ongoing() { + // NOTE: we assume `ongoing` does not consume any weight. + // there is an ongoing election -- we better not do anything. Imagine someone is not + // exposed anywhere in the last era, and the snapshot for the election is already + // taken. In this time period, we don't want to accidentally unstake them. + return T::DbWeight::get().reads(2) + } + + let UnstakeRequest { stash, mut checked, maybe_pool_id } = match Head::::take() + .or_else(|| { + // NOTE: there is no order guarantees in `Queue`. + Queue::::drain() + .map(|(stash, maybe_pool_id)| UnstakeRequest { + stash, + maybe_pool_id, + checked: Default::default(), + }) + .next() + }) { + None => { + // There's no `Head` and nothing in the `Queue`, nothing to do here. + return T::DbWeight::get().reads(4) + }, + Some(head) => head, + }; + + log!( + debug, + "checking {:?}, eras_to_check_per_block = {:?}, remaining_weight = {:?}", + stash, + eras_to_check_per_block, + remaining_weight + ); + + // the range that we're allowed to check in this round. + let current_era = pallet_staking::CurrentEra::::get().unwrap_or_default(); + let bonding_duration = ::BondingDuration::get(); + // prune all the old eras that we don't care about. This will help us keep the bound + // of `checked`. + checked.retain(|e| *e >= current_era.saturating_sub(bonding_duration)); + let unchecked_eras_to_check = { + // get the last available `bonding_duration` eras up to current era in reverse + // order. + let total_check_range = (current_era.saturating_sub(bonding_duration)..= + current_era) + .rev() + .collect::>(); + debug_assert!( + total_check_range.len() <= (bonding_duration + 1) as usize, + "{:?}", + total_check_range + ); + + // remove eras that have already been checked, take a maximum of + // eras_to_check_per_block. + total_check_range + .into_iter() + .filter(|e| !checked.contains(e)) + .take(eras_to_check_per_block as usize) + .collect::>() + }; + + log!( + debug, + "{} eras to check: {:?}", + unchecked_eras_to_check.len(), + unchecked_eras_to_check + ); + + if unchecked_eras_to_check.is_empty() { + // `stash` is not exposed in any era now -- we can let go of them now. + let num_slashing_spans = Staking::::slashing_spans(&stash).iter().count() as u32; + + let ctrl = match pallet_staking::Bonded::::get(&stash) { + Some(ctrl) => ctrl, + None => { + Self::deposit_event(Event::::Errored { stash }); + return ::WeightInfo::on_idle_unstake() + }, + }; + + let ledger = match pallet_staking::Ledger::::get(ctrl) { + Some(ledger) => ledger, + None => { + Self::deposit_event(Event::::Errored { stash }); + return ::WeightInfo::on_idle_unstake() + }, + }; + + let unstake_result = pallet_staking::Pallet::::force_unstake( + RawOrigin::Root.into(), + stash.clone(), + num_slashing_spans, + ); + + let pool_stake_result = if let Some(pool_id) = maybe_pool_id { + pallet_nomination_pools::Pallet::::join( + RawOrigin::Signed(stash.clone()).into(), + ledger.total, + pool_id, + ) + } else { + Ok(()) + }; + + let result = unstake_result.and(pool_stake_result); + log!( + info, + "unstaked {:?}, maybe_pool {:?}, outcome: {:?}", + stash, + maybe_pool_id, + result + ); + + Self::deposit_event(Event::::Unstaked { stash, maybe_pool_id, result }); + ::WeightInfo::on_idle_unstake() + } else { + // eras remaining to be checked. + let mut eras_checked = 0u32; + let is_exposed = unchecked_eras_to_check.iter().any(|e| { + eras_checked.saturating_inc(); + Self::is_exposed_in_era(&stash, e) + }); + + log!( + debug, + "checked {:?} eras, exposed? {}, (v: {:?}, u: {:?})", + eras_checked, + is_exposed, + validator_count, + unchecked_eras_to_check.len() + ); + + // NOTE: you can be extremely unlucky and get slashed here: You are not exposed in + // the last 28 eras, have registered yourself to be unstaked, midway being checked, + // you are exposed. + if is_exposed { + let amount = T::SlashPerEra::get() + .saturating_mul(eras_checked.saturating_add(checked.len() as u32).into()); + pallet_staking::slashing::do_slash::( + &stash, + amount, + &mut Default::default(), + &mut Default::default(), + current_era, + ); + log!(info, "slashed {:?} by {:?}", stash, amount); + Self::deposit_event(Event::::Slashed { stash, amount }); + } else { + // Not exposed in these eras. + match checked.try_extend(unchecked_eras_to_check.clone().into_iter()) { + Ok(_) => { + Head::::put(UnstakeRequest { + stash: stash.clone(), + checked, + maybe_pool_id, + }); + Self::deposit_event(Event::::Checking { + stash, + eras: unchecked_eras_to_check, + }); + }, + Err(_) => { + // don't put the head back in -- there is an internal error in the + // pallet. + frame_support::defensive!("`checked is pruned via retain above`"); + ErasToCheckPerBlock::::put(0); + Self::deposit_event(Event::::InternalError); + }, + } + } + + ::WeightInfo::on_idle_check(validator_count * eras_checked) + } + } + + /// Checks whether an account `staker` has been exposed in an era. + fn is_exposed_in_era(staker: &T::AccountId, era: &EraIndex) -> bool { + pallet_staking::ErasStakers::::iter_prefix(era).any(|(validator, exposures)| { + validator == *staker || exposures.others.iter().any(|i| i.who == *staker) + }) + } + } +} diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs new file mode 100644 index 0000000000000..b9cf16e18e8d1 --- /dev/null +++ b/frame/fast-unstake/src/mock.rs @@ -0,0 +1,387 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{self as fast_unstake}; +use frame_support::{ + assert_ok, + pallet_prelude::*, + parameter_types, + traits::{ConstU64, ConstU8, Currency}, + weights::constants::WEIGHT_PER_SECOND, + PalletId, +}; +use sp_runtime::{ + traits::{Convert, IdentityLookup}, + FixedU128, +}; + +use frame_system::RawOrigin; +use pallet_staking::{Exposure, IndividualExposure, StakerStatus}; +use sp_std::prelude::*; + +pub type AccountId = u128; +pub type AccountIndex = u32; +pub type BlockNumber = u64; +pub type Balance = u128; +pub type T = Runtime; + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(2u64 * WEIGHT_PER_SECOND); +} + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = BlockWeights; + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = AccountIndex; + type BlockNumber = BlockNumber; + type RuntimeCall = RuntimeCall; + type Hash = sp_core::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = sp_runtime::testing::Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +parameter_types! { + pub static ExistentialDeposit: Balance = 1; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = ConstU32<128>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} + +pallet_staking_reward_curve::build! { + const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + +parameter_types! { + pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; + pub static BondingDuration: u32 = 3; + pub static CurrentEra: u32 = 0; + pub static Ongoing: bool = false; +} + +pub struct MockElection; +impl frame_election_provider_support::ElectionProvider for MockElection { + type AccountId = AccountId; + type BlockNumber = BlockNumber; + type DataProvider = Staking; + type Error = (); + + fn ongoing() -> bool { + Ongoing::get() + } + + fn elect() -> Result, Self::Error> { + Err(()) + } +} + +impl pallet_staking::Config for Runtime { + type MaxNominations = ConstU32<16>; + type Currency = Balances; + type CurrencyBalance = Balance; + type UnixTime = pallet_timestamp::Pallet; + type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; + type RewardRemainder = (); + type RuntimeEvent = RuntimeEvent; + type Slash = (); + type Reward = (); + type SessionsPerEra = (); + type SlashDeferDuration = (); + type SlashCancelOrigin = frame_system::EnsureRoot; + type BondingDuration = BondingDuration; + type SessionInterface = (); + type EraPayout = pallet_staking::ConvertCurve; + type NextNewSession = (); + type HistoryDepth = ConstU32<84>; + type MaxNominatorRewardedPerValidator = ConstU32<64>; + type OffendingValidatorsThreshold = (); + type ElectionProvider = MockElection; + type GenesisElectionProvider = Self::ElectionProvider; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; + type MaxUnlockingChunks = ConstU32<32>; + type OnStakerSlash = Pools; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type WeightInfo = (); +} + +pub struct BalanceToU256; +impl Convert for BalanceToU256 { + fn convert(n: Balance) -> sp_core::U256 { + n.into() + } +} + +pub struct U256ToBalance; +impl Convert for U256ToBalance { + fn convert(n: sp_core::U256) -> Balance { + n.try_into().unwrap() + } +} + +parameter_types! { + pub const PostUnbondingPoolsWindow: u32 = 10; + pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); + pub static MaxMetadataLen: u32 = 10; + pub static CheckLevel: u8 = 255; +} + +impl pallet_nomination_pools::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type Currency = Balances; + type CurrencyBalance = Balance; + type RewardCounter = FixedU128; + type BalanceToU256 = BalanceToU256; + type U256ToBalance = U256ToBalance; + type StakingInterface = Staking; + type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; + type MaxMetadataLen = MaxMetadataLen; + type MaxUnbonding = ConstU32<8>; + type MaxPointsToBalance = ConstU8<10>; + type PalletId = PoolsPalletId; +} + +parameter_types! { + pub static SlashPerEra: u32 = 100; +} + +impl fast_unstake::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SlashPerEra = SlashPerEra; + type ControlOrigin = frame_system::EnsureRoot; + type WeightInfo = (); +} + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Staking: pallet_staking, + Pools: pallet_nomination_pools, + FastUnstake: fast_unstake, + } +); + +parameter_types! { + static FastUnstakeEvents: u32 = 0; +} + +pub(crate) fn fast_unstake_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::FastUnstake(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = FastUnstakeEvents::get(); + FastUnstakeEvents::set(events.len() as u32); + events.into_iter().skip(already_seen as usize).collect() +} + +pub struct ExtBuilder { + exposed_nominators: Vec<(AccountId, AccountId, Balance)>, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + exposed_nominators: vec![ + (1, 2, 100), + (3, 4, 100), + (5, 6, 100), + (7, 8, 100), + (9, 10, 100), + ], + } + } +} + +pub(crate) const VALIDATORS_PER_ERA: AccountId = 32; +pub(crate) const VALIDATOR_PREFIX: AccountId = 100; +pub(crate) const NOMINATORS_PER_VALIDATOR_PER_ERA: AccountId = 4; +pub(crate) const NOMINATOR_PREFIX: AccountId = 1000; + +impl ExtBuilder { + pub(crate) fn register_stakers_for_era(era: u32) { + // validators are prefixed with 100 and nominators with 1000 to prevent conflict. Make sure + // all the other accounts used in tests are below 100. Also ensure here that we don't + // overlap. + assert!(VALIDATOR_PREFIX + VALIDATORS_PER_ERA < NOMINATOR_PREFIX); + + (VALIDATOR_PREFIX..VALIDATOR_PREFIX + VALIDATORS_PER_ERA) + .map(|v| { + // for the sake of sanity, let's register this taker as an actual validator. + let others = (NOMINATOR_PREFIX.. + (NOMINATOR_PREFIX + NOMINATORS_PER_VALIDATOR_PER_ERA)) + .map(|n| IndividualExposure { who: n, value: 0 as Balance }) + .collect::>(); + (v, Exposure { total: 0, own: 0, others }) + }) + .for_each(|(validator, exposure)| { + pallet_staking::ErasStakers::::insert(era, validator, exposure); + }); + } + + pub(crate) fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut storage = + frame_system::GenesisConfig::default().build_storage::().unwrap(); + + // create one default pool. + let _ = pallet_nomination_pools::GenesisConfig:: { ..Default::default() } + .assimilate_storage(&mut storage); + + let validators_range = VALIDATOR_PREFIX..VALIDATOR_PREFIX + VALIDATORS_PER_ERA; + let nominators_range = + NOMINATOR_PREFIX..NOMINATOR_PREFIX + NOMINATORS_PER_VALIDATOR_PER_ERA; + + let _ = pallet_balances::GenesisConfig:: { + balances: self + .exposed_nominators + .clone() + .into_iter() + .map(|(stash, _, balance)| (stash, balance * 2)) + .chain( + self.exposed_nominators + .clone() + .into_iter() + .map(|(_, ctrl, balance)| (ctrl, balance * 2)), + ) + .chain(validators_range.clone().map(|x| (x, 100))) + .chain(nominators_range.clone().map(|x| (x, 100))) + .collect::>(), + } + .assimilate_storage(&mut storage); + + let _ = pallet_staking::GenesisConfig:: { + stakers: self + .exposed_nominators + .into_iter() + .map(|(x, y, z)| (x, y, z, pallet_staking::StakerStatus::Nominator(vec![42]))) + .chain(validators_range.map(|x| (x, x, 100, StakerStatus::Validator))) + .chain(nominators_range.map(|x| (x, x, 100, StakerStatus::Nominator(vec![x])))) + .collect::>(), + ..Default::default() + } + .assimilate_storage(&mut storage); + + let mut ext = sp_io::TestExternalities::from(storage); + + ext.execute_with(|| { + // for events to be deposited. + frame_system::Pallet::::set_block_number(1); + + for era in 0..=(BondingDuration::get()) { + Self::register_stakers_for_era(era); + } + + // because we read this value as a measure of how many validators we have. + pallet_staking::ValidatorCount::::put(VALIDATORS_PER_ERA as u32); + + // make a pool + let amount_to_bond = Pools::depositor_min_bond(); + Balances::make_free_balance_be(&10, amount_to_bond * 5); + assert_ok!(Pools::create(RawOrigin::Signed(10).into(), amount_to_bond, 900, 901, 902)); + }); + ext + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(|| { + test(); + }) + } +} + +pub(crate) fn run_to_block(n: u64, on_idle: bool) { + let current_block = System::block_number(); + assert!(n > current_block); + while System::block_number() < n { + Balances::on_finalize(System::block_number()); + Staking::on_finalize(System::block_number()); + Pools::on_finalize(System::block_number()); + FastUnstake::on_finalize(System::block_number()); + + System::set_block_number(System::block_number() + 1); + + Balances::on_initialize(System::block_number()); + Staking::on_initialize(System::block_number()); + Pools::on_initialize(System::block_number()); + FastUnstake::on_initialize(System::block_number()); + if on_idle { + FastUnstake::on_idle(System::block_number(), BlockWeights::get().max_block); + } + } +} + +pub(crate) fn next_block(on_idle: bool) { + let current = System::block_number(); + run_to_block(current + 1, on_idle); +} + +pub fn assert_unstaked(stash: &AccountId) { + assert!(!pallet_staking::Bonded::::contains_key(stash)); + assert!(!pallet_staking::Payee::::contains_key(stash)); + assert!(!pallet_staking::Validators::::contains_key(stash)); + assert!(!pallet_staking::Nominators::::contains_key(stash)); +} diff --git a/frame/fast-unstake/src/tests.rs b/frame/fast-unstake/src/tests.rs new file mode 100644 index 0000000000000..a51c1acdf06eb --- /dev/null +++ b/frame/fast-unstake/src/tests.rs @@ -0,0 +1,1036 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for pallet-fast-unstake. + +use super::*; +use crate::{mock::*, types::*, weights::WeightInfo, Event}; +use frame_support::{assert_noop, assert_ok, bounded_vec, pallet_prelude::*, traits::Currency}; +use pallet_nomination_pools::{BondedPools, LastPoolId, RewardPools}; +use pallet_staking::{CurrentEra, IndividualExposure, RewardDestination}; + +use sp_runtime::{traits::BadOrigin, DispatchError, ModuleError}; +use sp_staking::StakingInterface; + +#[test] +fn test_setup_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(BondedPools::::count(), 1); + assert_eq!(RewardPools::::count(), 1); + assert_eq!(Staking::bonding_duration(), 3); + let last_pool = LastPoolId::::get(); + assert_eq!(last_pool, 1); + }); +} + +#[test] +fn register_works() { + ExtBuilder::default().build_and_execute(|| { + // Controller account registers for fast unstake. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + // Ensure stash is in the queue. + assert_ne!(Queue::::get(1), None); + }); +} + +#[test] +fn cannot_register_if_not_bonded() { + ExtBuilder::default().build_and_execute(|| { + // Mint accounts 1 and 2 with 200 tokens. + for _ in 1..2 { + let _ = Balances::make_free_balance_be(&1, 200); + } + // Attempt to fast unstake. + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1), Some(1_u32)), + Error::::NotController + ); + }); +} + +#[test] +fn cannot_register_if_in_queue() { + ExtBuilder::default().build_and_execute(|| { + // Insert some Queue item + Queue::::insert(1, Some(1_u32)); + // Cannot re-register, already in queue + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32)), + Error::::AlreadyQueued + ); + }); +} + +#[test] +fn cannot_register_if_head() { + ExtBuilder::default().build_and_execute(|| { + // Insert some Head item for stash + Head::::put(UnstakeRequest { stash: 1, checked: bounded_vec![], maybe_pool_id: None }); + // Controller attempts to regsiter + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32)), + Error::::AlreadyHead + ); + }); +} + +#[test] +fn cannot_register_if_has_unlocking_chunks() { + ExtBuilder::default().build_and_execute(|| { + // Start unbonding half of staked tokens + assert_ok!(Staking::unbond(RuntimeOrigin::signed(2), 50_u128)); + // Cannot register for fast unstake with unlock chunks active + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32)), + Error::::NotFullyBonded + ); + }); +} + +#[test] +fn deregister_works() { + ExtBuilder::default().build_and_execute(|| { + // Controller account registers for fast unstake. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + // Controller then changes mind and deregisters. + assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(2))); + // Ensure stash no longer exists in the queue. + assert_eq!(Queue::::get(1), None); + }); +} + +#[test] +fn cannot_deregister_if_not_controller() { + ExtBuilder::default().build_and_execute(|| { + // Controller account registers for fast unstake. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + // Stash tries to deregister. + assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(1)), Error::::NotController); + }); +} + +#[test] +fn cannot_deregister_if_not_queued() { + ExtBuilder::default().build_and_execute(|| { + // Controller tries to deregister without first registering + assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(2)), Error::::NotQueued); + }); +} + +#[test] +fn cannot_deregister_already_head() { + ExtBuilder::default().build_and_execute(|| { + // Controller attempts to register, should fail + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + // Insert some Head item for stash. + Head::::put(UnstakeRequest { stash: 1, checked: bounded_vec![], maybe_pool_id: None }); + // Controller attempts to deregister + assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(2)), Error::::AlreadyHead); + }); +} + +#[test] +fn control_works() { + ExtBuilder::default().build_and_execute(|| { + // account with control (root) origin wants to only check 1 era per block. + assert_ok!(FastUnstake::control(RuntimeOrigin::root(), 1_u32)); + }); +} + +#[test] +fn control_must_be_control_origin() { + ExtBuilder::default().build_and_execute(|| { + // account without control (root) origin wants to only check 1 era per block. + assert_noop!(FastUnstake::control(RuntimeOrigin::signed(1), 1_u32), BadOrigin); + }); +} + +mod on_idle { + use super::*; + + #[test] + fn early_exit() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // set up Queue item + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1))); + assert_eq!(Queue::::get(1), Some(Some(1))); + + // call on_idle with no remaining weight + FastUnstake::on_idle(System::block_number(), Weight::from_ref_time(0)); + + // assert nothing changed in Queue and Head + assert_eq!(Head::::get(), None); + assert_eq!(Queue::::get(1), Some(Some(1))); + }); + } + + #[test] + fn respects_weight() { + ExtBuilder::default().build_and_execute(|| { + // we want to check all eras in one block... + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // given + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1))); + assert_eq!(Queue::::get(1), Some(Some(1))); + + assert_eq!(Queue::::count(), 1); + assert_eq!(Head::::get(), None); + + // when: call fast unstake with not enough weight to process the whole thing, just one + // era. + let remaining_weight = ::WeightInfo::on_idle_check( + pallet_staking::ValidatorCount::::get() * 1, + ); + assert_eq!(FastUnstake::on_idle(0, remaining_weight), remaining_weight); + + // then + assert_eq!( + fast_unstake_events_since_last_call(), + vec![Event::Checking { stash: 1, eras: vec![3] }] + ); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3], maybe_pool_id: Some(1) }) + ); + + // when: another 1 era. + let remaining_weight = ::WeightInfo::on_idle_check( + pallet_staking::ValidatorCount::::get() * 1, + ); + assert_eq!(FastUnstake::on_idle(0, remaining_weight), remaining_weight); + + // then: + assert_eq!( + fast_unstake_events_since_last_call(), + vec![Event::Checking { stash: 1, eras: bounded_vec![2] }] + ); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2], + maybe_pool_id: Some(1) + }) + ); + + // when: then 5 eras, we only need 2 more. + let remaining_weight = ::WeightInfo::on_idle_check( + pallet_staking::ValidatorCount::::get() * 5, + ); + assert_eq!( + FastUnstake::on_idle(0, remaining_weight), + // note the amount of weight consumed: 2 eras worth of weight. + ::WeightInfo::on_idle_check( + pallet_staking::ValidatorCount::::get() * 2, + ) + ); + + // then: + assert_eq!( + fast_unstake_events_since_last_call(), + vec![Event::Checking { stash: 1, eras: vec![1, 0] }] + ); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 1, 0], + maybe_pool_id: Some(1) + }) + ); + + // when: not enough weight to unstake: + let remaining_weight = + ::WeightInfo::on_idle_unstake() - Weight::from_ref_time(1); + assert_eq!(FastUnstake::on_idle(0, remaining_weight), Weight::from_ref_time(0)); + + // then nothing happens: + assert_eq!(fast_unstake_events_since_last_call(), vec![]); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 1, 0], + maybe_pool_id: Some(1) + }) + ); + + // when: enough weight to get over at least one iteration: then we are unblocked and can + // unstake. + let remaining_weight = ::WeightInfo::on_idle_check( + pallet_staking::ValidatorCount::::get() * 1, + ); + assert_eq!( + FastUnstake::on_idle(0, remaining_weight), + ::WeightInfo::on_idle_unstake() + ); + + // then we finish the unbonding: + assert_eq!( + fast_unstake_events_since_last_call(), + vec![Event::Unstaked { stash: 1, maybe_pool_id: Some(1), result: Ok(()) }] + ); + assert_eq!(Head::::get(), None,); + + assert_unstaked(&1); + }); + } + + #[test] + fn if_head_not_set_one_random_fetched_from_queue() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // given + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4), None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(6), None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(8), None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(10), None)); + + assert_eq!(Queue::::count(), 5); + assert_eq!(Head::::get(), None); + + // when + next_block(true); + + // then + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 1, 0], + maybe_pool_id: None + }) + ); + assert_eq!(Queue::::count(), 4); + + // when + next_block(true); + + // then + assert_eq!(Head::::get(), None,); + assert_eq!(Queue::::count(), 4); + + // when + next_block(true); + + // then + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 5, + checked: bounded_vec![3, 2, 1, 0], + maybe_pool_id: None + }), + ); + assert_eq!(Queue::::count(), 3); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, maybe_pool_id: None, result: Ok(()) }, + Event::Checking { stash: 5, eras: vec![3, 2, 1, 0] } + ] + ); + }); + } + + #[test] + fn successful_multi_queue() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // register multi accounts for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1))); + assert_eq!(Queue::::get(1), Some(Some(1))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4), Some(1))); + assert_eq!(Queue::::get(3), Some(Some(1))); + + // assert 2 queue items are in Queue & None in Head to start with + assert_eq!(Queue::::count(), 2); + assert_eq!(Head::::get(), None); + + // process on idle and check eras for next Queue item + next_block(true); + + // process on idle & let go of current Head + next_block(true); + + // confirm Head / Queue items remaining + assert_eq!(Queue::::count(), 1); + assert_eq!(Head::::get(), None); + + // process on idle and check eras for next Queue item + next_block(true); + + // process on idle & let go of current Head + next_block(true); + + // Head & Queue should now be empty + assert_eq!(Head::::get(), None); + assert_eq!(Queue::::count(), 0); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, maybe_pool_id: Some(1), result: Ok(()) }, + Event::Checking { stash: 3, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 3, maybe_pool_id: Some(1), result: Ok(()) }, + ] + ); + + assert_unstaked(&1); + assert_unstaked(&3); + }); + } + + #[test] + fn successful_unstake_without_pool_join() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), None)); + assert_eq!(Queue::::get(1), Some(None)); + + // process on idle + next_block(true); + + // assert queue item has been moved to head + assert_eq!(Queue::::get(1), None); + + // assert head item present + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 1, 0], + maybe_pool_id: None + }) + ); + + next_block(true); + assert_eq!(Head::::get(), None,); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, maybe_pool_id: None, result: Ok(()) } + ] + ); + assert_unstaked(&1); + }); + } + + #[test] + fn successful_unstake_joining_bad_pool() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(0))); + assert_eq!(Queue::::get(1), Some(Some(0))); + + // process on idle + next_block(true); + + // assert queue item has been moved to head + assert_eq!(Queue::::get(1), None); + + // assert head item present + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 1, 0], + maybe_pool_id: Some(0) + }) + ); + + next_block(true); + assert_eq!(Head::::get(), None,); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { + stash: 1, + maybe_pool_id: Some(0), + result: Err(DispatchError::Module(ModuleError { + index: 4, + error: [0, 0, 0, 0], + message: None + })) + } + ] + ); + assert_unstaked(&1); + }); + } + + #[test] + fn successful_unstake_all_eras_per_block() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + assert_eq!(Queue::::get(1), Some(Some(1))); + + // process on idle + next_block(true); + + // assert queue item has been moved to head + assert_eq!(Queue::::get(1), None); + + // assert head item present + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 1, 0], + maybe_pool_id: Some(1) + }) + ); + + next_block(true); + assert_eq!(Head::::get(), None,); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, maybe_pool_id: Some(1), result: Ok(()) } + ] + ); + assert_unstaked(&1); + assert!(pallet_nomination_pools::PoolMembers::::contains_key(&1)); + }); + } + + #[test] + fn successful_unstake_one_era_per_block() { + ExtBuilder::default().build_and_execute(|| { + // put 1 era per block + ErasToCheckPerBlock::::put(1); + CurrentEra::::put(BondingDuration::get()); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + assert_eq!(Queue::::get(1), Some(Some(1))); + + // process on idle + next_block(true); + + // assert queue item has been moved to head + assert_eq!(Queue::::get(1), None); + + // assert head item present + assert_eq!( + Head::::get(), + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3], maybe_pool_id: Some(1) }) + ); + + next_block(true); + + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2], + maybe_pool_id: Some(1) + }) + ); + + next_block(true); + + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 1], + maybe_pool_id: Some(1) + }) + ); + + next_block(true); + + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 1, 0], + maybe_pool_id: Some(1) + }) + ); + + next_block(true); + + assert_eq!(Head::::get(), None,); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3] }, + Event::Checking { stash: 1, eras: vec![2] }, + Event::Checking { stash: 1, eras: vec![1] }, + Event::Checking { stash: 1, eras: vec![0] }, + Event::Unstaked { stash: 1, maybe_pool_id: Some(1), result: Ok(()) } + ] + ); + assert_unstaked(&1); + assert!(pallet_nomination_pools::PoolMembers::::contains_key(&1)); + }); + } + + #[test] + fn old_checked_era_pruned() { + // the only scenario where checked era pruning (checked.retain) comes handy is a follows: + // the whole vector is full and at capacity and in the next call we are ready to unstake, + // but then a new era happens. + ExtBuilder::default().build_and_execute(|| { + // given + ErasToCheckPerBlock::::put(1); + CurrentEra::::put(BondingDuration::get()); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), None)); + assert_eq!(Queue::::get(1), Some(None)); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3], maybe_pool_id: None }) + ); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2], maybe_pool_id: None }) + ); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 1], + maybe_pool_id: None + }) + ); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 1, 0], + maybe_pool_id: None + }) + ); + + // when: a new era happens right before one is free. + CurrentEra::::put(CurrentEra::::get().unwrap() + 1); + ExtBuilder::register_stakers_for_era(CurrentEra::::get().unwrap()); + + // then + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + // note era 0 is pruned to keep the vector length sane. + checked: bounded_vec![3, 2, 1, 4], + maybe_pool_id: None + }) + ); + + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3] }, + Event::Checking { stash: 1, eras: vec![2] }, + Event::Checking { stash: 1, eras: vec![1] }, + Event::Checking { stash: 1, eras: vec![0] }, + Event::Checking { stash: 1, eras: vec![4] }, + Event::Unstaked { stash: 1, maybe_pool_id: None, result: Ok(()) } + ] + ); + assert_unstaked(&1); + }); + } + + #[test] + fn unstake_paused_mid_election() { + ExtBuilder::default().build_and_execute(|| { + // give: put 1 era per block + ErasToCheckPerBlock::::put(1); + CurrentEra::::put(BondingDuration::get()); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + + // process 2 blocks + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3], maybe_pool_id: Some(1) }) + ); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2], + maybe_pool_id: Some(1) + }) + ); + + // when + Ongoing::set(true); + + // then nothing changes + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2], + maybe_pool_id: Some(1) + }) + ); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2], + maybe_pool_id: Some(1) + }) + ); + + // then we register a new era. + Ongoing::set(false); + CurrentEra::::put(CurrentEra::::get().unwrap() + 1); + ExtBuilder::register_stakers_for_era(CurrentEra::::get().unwrap()); + + // then we can progress again, but notice that the new era that had to be checked. + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 4], + maybe_pool_id: Some(1) + }) + ); + + // progress to end + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + checked: bounded_vec![3, 2, 4, 1], + maybe_pool_id: Some(1) + }) + ); + + // but notice that we don't care about era 0 instead anymore! we're done. + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3] }, + Event::Checking { stash: 1, eras: vec![2] }, + Event::Checking { stash: 1, eras: vec![4] }, + Event::Checking { stash: 1, eras: vec![1] }, + Event::Unstaked { stash: 1, maybe_pool_id: Some(1), result: Ok(()) } + ] + ); + + assert_unstaked(&1); + assert!(pallet_nomination_pools::PoolMembers::::contains_key(&1)); + }); + } + + #[test] + fn exposed_nominator_cannot_unstake() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + SlashPerEra::set(7); + CurrentEra::::put(BondingDuration::get()); + + // create an exposed nominator in era 1 + let exposed = 666 as AccountId; + pallet_staking::ErasStakers::::mutate(1, VALIDATORS_PER_ERA, |expo| { + expo.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); + }); + Balances::make_free_balance_be(&exposed, 100); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(exposed), + exposed, + 10, + RewardDestination::Staked + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed])); + + // register the exposed one. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed), None)); + + // a few blocks later, we realize they are slashed + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: exposed, + checked: bounded_vec![3], + maybe_pool_id: None + }) + ); + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: exposed, + checked: bounded_vec![3, 2], + maybe_pool_id: None + }) + ); + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + // we slash them by 21, since we checked 3 eras in total (3, 2, 1). + vec![ + Event::Checking { stash: exposed, eras: vec![3] }, + Event::Checking { stash: exposed, eras: vec![2] }, + Event::Slashed { stash: exposed, amount: 3 * 7 } + ] + ); + }); + } + + #[test] + fn exposed_nominator_cannot_unstake_multi_check() { + ExtBuilder::default().build_and_execute(|| { + // same as the previous check, but we check 2 eras per block, and we make the exposed be + // exposed in era 0, so that it is detected halfway in a check era. + ErasToCheckPerBlock::::put(2); + SlashPerEra::set(7); + CurrentEra::::put(BondingDuration::get()); + + // create an exposed nominator in era 1 + let exposed = 666 as AccountId; + pallet_staking::ErasStakers::::mutate(0, VALIDATORS_PER_ERA, |expo| { + expo.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); + }); + Balances::make_free_balance_be(&exposed, 100); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(exposed), + exposed, + 10, + RewardDestination::Staked + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed])); + + // register the exposed one. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed), None)); + + // a few blocks later, we realize they are slashed + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: exposed, + checked: bounded_vec![3, 2], + maybe_pool_id: None + }) + ); + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + // we slash them by 28, since we checked 4 eras in total. + vec![ + Event::Checking { stash: exposed, eras: vec![3, 2] }, + Event::Slashed { stash: exposed, amount: 4 * 7 } + ] + ); + }); + } + + #[test] + fn validators_cannot_bail() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // a validator switches role and register... + assert_ok!(Staking::nominate( + RuntimeOrigin::signed(VALIDATOR_PREFIX), + vec![VALIDATOR_PREFIX] + )); + assert_ok!(FastUnstake::register_fast_unstake( + RuntimeOrigin::signed(VALIDATOR_PREFIX), + None + )); + + // but they indeed are exposed! + assert!(pallet_staking::ErasStakers::::contains_key( + BondingDuration::get() - 1, + VALIDATOR_PREFIX + )); + + // process a block, this validator is exposed and has been slashed. + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![Event::Slashed { stash: 100, amount: 100 }] + ); + }); + } + + #[test] + fn unexposed_validator_can_fast_unstake() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // create a new validator that 100% not exposed. + Balances::make_free_balance_be(&42, 100); + assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 42, 10, RewardDestination::Staked)); + assert_ok!(Staking::validate(RuntimeOrigin::signed(42), Default::default())); + + // let them register: + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(42), None)); + + // 2 block's enough to unstake them. + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 42, + checked: bounded_vec![3, 2, 1, 0], + maybe_pool_id: None + }) + ); + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 42, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 42, maybe_pool_id: None, result: Ok(()) } + ] + ); + }); + } +} + +mod signed_extension { + use super::*; + use sp_runtime::traits::SignedExtension; + + const STAKING_CALL: crate::mock::RuntimeCall = + crate::mock::RuntimeCall::Staking(pallet_staking::Call::::chill {}); + + #[test] + fn does_nothing_if_not_queued() { + ExtBuilder::default().build_and_execute(|| { + assert!(PreventStakingOpsIfUnbonding::::new() + .pre_dispatch(&1, &STAKING_CALL, &Default::default(), Default::default()) + .is_ok()); + }) + } + + #[test] + fn prevents_queued() { + ExtBuilder::default().build_and_execute(|| { + // given: stash for 2 is 1. + // when + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), None)); + + // then + // stash can't. + assert!(PreventStakingOpsIfUnbonding::::new() + .pre_dispatch(&1, &STAKING_CALL, &Default::default(), Default::default()) + .is_err()); + + // controller can't. + assert!(PreventStakingOpsIfUnbonding::::new() + .pre_dispatch(&2, &STAKING_CALL, &Default::default(), Default::default()) + .is_err()); + }) + } + + #[test] + fn prevents_head_stash() { + ExtBuilder::default().build_and_execute(|| { + // given: stash for 2 is 1. + // when + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), None)); + + ErasToCheckPerBlock::::put(1); + CurrentEra::::put(BondingDuration::get()); + next_block(true); + + assert_eq!( + Head::::get(), + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3], maybe_pool_id: None }) + ); + + // then + // stash can't + assert!(PreventStakingOpsIfUnbonding::::new() + .pre_dispatch(&2, &STAKING_CALL, &Default::default(), Default::default()) + .is_err()); + + // controller can't + assert!(PreventStakingOpsIfUnbonding::::new() + .pre_dispatch(&1, &STAKING_CALL, &Default::default(), Default::default()) + .is_err()); + }) + } +} diff --git a/frame/fast-unstake/src/types.rs b/frame/fast-unstake/src/types.rs new file mode 100644 index 0000000000000..ae8702e56a842 --- /dev/null +++ b/frame/fast-unstake/src/types.rs @@ -0,0 +1,119 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Types used in the Fast Unstake pallet. + +use crate::*; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + traits::{Currency, Get, IsSubType}, + BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, +}; +use pallet_nomination_pools::PoolId; +use scale_info::TypeInfo; +use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidityError}; +use sp_staking::EraIndex; +use sp_std::{fmt::Debug, prelude::*}; + +pub type BalanceOf = <::Currency as Currency< + ::AccountId, +>>::Balance; + +/// An unstake request. +#[derive( + Encode, Decode, EqNoBound, PartialEqNoBound, Clone, TypeInfo, RuntimeDebugNoBound, MaxEncodedLen, +)] +pub struct UnstakeRequest> { + /// Their stash account. + pub(crate) stash: AccountId, + /// The list of eras for which they have been checked. + pub(crate) checked: BoundedVec, + /// The pool they wish to join, if any. + pub(crate) maybe_pool_id: Option, +} + +#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo, RuntimeDebugNoBound)] +#[scale_info(skip_type_params(T))] +pub struct PreventStakingOpsIfUnbonding(sp_std::marker::PhantomData); + +#[cfg(test)] +impl PreventStakingOpsIfUnbonding { + pub fn new() -> Self { + Self(Default::default()) + } +} + +impl sp_runtime::traits::SignedExtension + for PreventStakingOpsIfUnbonding +where + ::RuntimeCall: IsSubType>, +{ + type AccountId = T::AccountId; + type Call = ::RuntimeCall; + type AdditionalSigned = (); + type Pre = (); + const IDENTIFIER: &'static str = "PreventStakingOpsIfUnbonding"; + + fn additional_signed(&self) -> Result { + Ok(()) + } + + fn pre_dispatch( + self, + // NOTE: we want to prevent this stash-controller pair from doing anything in the + // staking system as long as they are registered here. + stash_or_controller: &Self::AccountId, + call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, + _len: usize, + ) -> Result { + // we don't check this in the tx-pool as it requires a storage read. + if >>::is_sub_type(call).is_some() { + let check_stash = |stash: &T::AccountId| { + if Queue::::contains_key(&stash) || + Head::::get().map_or(false, |u| &u.stash == stash) + { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } else { + Ok(()) + } + }; + match ( + // mapped from controller. + pallet_staking::Ledger::::get(&stash_or_controller), + // mapped from stash. + pallet_staking::Bonded::::get(&stash_or_controller), + ) { + (Some(ledger), None) => { + // it is a controller. + check_stash(&ledger.stash) + }, + (_, Some(_)) => { + // it's a stash. + let stash = stash_or_controller; + check_stash(stash) + }, + (None, None) => { + // They are not a staker -- let them execute. + Ok(()) + }, + } + } else { + Ok(()) + } + } +} diff --git a/frame/fast-unstake/src/weights.rs b/frame/fast-unstake/src/weights.rs new file mode 100644 index 0000000000000..04857d0dcc865 --- /dev/null +++ b/frame/fast-unstake/src/weights.rs @@ -0,0 +1,210 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_fast_unstake +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-09-07, STEPS: `10`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `Kians-MacBook-Pro-2.local`, CPU: `` +//! EXECUTION: Some(Native), WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// target/release/substrate +// benchmark +// pallet +// --steps=10 +// --repeat=1 +// --pallet=pallet_fast_unstake +// --extrinsic=* +// --execution=native +// --output +// weight.rs +// --template +// ./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_fast_unstake. +pub trait WeightInfo { + fn on_idle_unstake() -> Weight; + fn on_idle_check(x: u32, ) -> Weight; + fn register_fast_unstake() -> Weight; + fn deregister() -> Weight; + fn control() -> Weight; +} + +/// Weights for pallet_fast_unstake using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + // Storage: Staking ValidatorCount (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + // Storage: FastUnstake Head (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: Staking Bonded (r:2 w:1) + // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:0) + // Storage: System Account (r:3 w:2) + // Storage: Balances Locks (r:2 w:2) + // Storage: NominationPools MinJoinBond (r:1 w:0) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + // Storage: NominationPools MaxPoolMembers (r:1 w:0) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + // Storage: BagsList ListNodes (r:1 w:0) + // Storage: Staking Payee (r:0 w:1) + fn on_idle_unstake() -> Weight { + Weight::from_ref_time(102_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(25 as u64)) + .saturating_add(T::DbWeight::get().writes(13 as u64)) + } + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + // Storage: Staking ValidatorCount (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + // Storage: FastUnstake Head (r:1 w:1) + // Storage: FastUnstake Queue (r:2 w:1) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakers (r:1344 w:0) + /// The range of component `x` is `[672, 86016]`. + fn on_idle_check(x: u32, ) -> Weight { + Weight::from_ref_time(0 as u64) + // Standard Error: 244_000 + .saturating_add(Weight::from_ref_time(13_913_000 as u64).saturating_mul(x as u64)) + .saturating_add(T::DbWeight::get().reads(585 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(x as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Nominators (r:1 w:1) + // Storage: FastUnstake Queue (r:1 w:1) + // Storage: FastUnstake Head (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:1 w:1) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + fn register_fast_unstake() -> Weight { + Weight::from_ref_time(57_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(12 as u64)) + .saturating_add(T::DbWeight::get().writes(9 as u64)) + } + // Storage: Staking Ledger (r:1 w:0) + // Storage: FastUnstake Queue (r:1 w:1) + // Storage: FastUnstake Head (r:1 w:0) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + fn deregister() -> Weight { + Weight::from_ref_time(15_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + } + // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) + fn control() -> Weight { + Weight::from_ref_time(3_000_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + // Storage: Staking ValidatorCount (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + // Storage: FastUnstake Head (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: Staking Bonded (r:2 w:1) + // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:0) + // Storage: System Account (r:3 w:2) + // Storage: Balances Locks (r:2 w:2) + // Storage: NominationPools MinJoinBond (r:1 w:0) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + // Storage: NominationPools MaxPoolMembers (r:1 w:0) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + // Storage: BagsList ListNodes (r:1 w:0) + // Storage: Staking Payee (r:0 w:1) + fn on_idle_unstake() -> Weight { + Weight::from_ref_time(102_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(25 as u64)) + .saturating_add(RocksDbWeight::get().writes(13 as u64)) + } + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + // Storage: Staking ValidatorCount (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + // Storage: FastUnstake Head (r:1 w:1) + // Storage: FastUnstake Queue (r:2 w:1) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakers (r:1344 w:0) + /// The range of component `x` is `[672, 86016]`. + fn on_idle_check(x: u32, ) -> Weight { + Weight::from_ref_time(0 as u64) + // Standard Error: 244_000 + .saturating_add(Weight::from_ref_time(13_913_000 as u64).saturating_mul(x as u64)) + .saturating_add(RocksDbWeight::get().reads(585 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(x as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Nominators (r:1 w:1) + // Storage: FastUnstake Queue (r:1 w:1) + // Storage: FastUnstake Head (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:1 w:1) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + fn register_fast_unstake() -> Weight { + Weight::from_ref_time(57_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(12 as u64)) + .saturating_add(RocksDbWeight::get().writes(9 as u64)) + } + // Storage: Staking Ledger (r:1 w:0) + // Storage: FastUnstake Queue (r:1 w:1) + // Storage: FastUnstake Head (r:1 w:0) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + fn deregister() -> Weight { + Weight::from_ref_time(15_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + } + // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) + fn control() -> Weight { + Weight::from_ref_time(3_000_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } +} diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 040a9fa8e828e..c31bcb1546ecd 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -52,12 +52,6 @@ pub trait Config: pub struct Pallet(Pools); -fn min_create_bond() -> BalanceOf { - MinCreateBond::::get() - .max(T::StakingInterface::minimum_bond()) - .max(CurrencyOf::::minimum_balance()) -} - fn create_funded_user_with_balance( string: &'static str, n: u32, @@ -220,7 +214,7 @@ impl ListScenario { frame_benchmarking::benchmarks! { join { - let origin_weight = min_create_bond::() * 2u32.into(); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); // setup the worst case list scenario. let scenario = ListScenario::::new(origin_weight, true)?; @@ -246,7 +240,7 @@ frame_benchmarking::benchmarks! { } bond_extra_transfer { - let origin_weight = min_create_bond::() * 2u32.into(); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let scenario = ListScenario::::new(origin_weight, true)?; let extra = scenario.dest_weight - origin_weight; @@ -261,7 +255,7 @@ frame_benchmarking::benchmarks! { } bond_extra_reward { - let origin_weight = min_create_bond::() * 2u32.into(); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let scenario = ListScenario::::new(origin_weight, true)?; let extra = (scenario.dest_weight - origin_weight).max(CurrencyOf::::minimum_balance()); @@ -279,7 +273,7 @@ frame_benchmarking::benchmarks! { } claim_payout { - let origin_weight = min_create_bond::() * 2u32.into(); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let ed = CurrencyOf::::minimum_balance(); let (depositor, pool_account) = create_pool_account::(0, origin_weight); let reward_account = Pools::::create_reward_account(1); @@ -309,7 +303,7 @@ frame_benchmarking::benchmarks! { unbond { // The weight the nominator will start at. The value used here is expected to be // significantly higher than the first position in a list (e.g. the first bag threshold). - let origin_weight = min_create_bond::() * 200u32.into(); + let origin_weight = Pools::::depositor_min_bond() * 200u32.into(); let scenario = ListScenario::::new(origin_weight, false)?; let amount = origin_weight - scenario.dest_weight; @@ -340,7 +334,7 @@ frame_benchmarking::benchmarks! { pool_withdraw_unbonded { let s in 0 .. MAX_SPANS; - let min_create_bond = min_create_bond::(); + let min_create_bond = Pools::::depositor_min_bond(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); // Add a new member @@ -382,7 +376,7 @@ frame_benchmarking::benchmarks! { withdraw_unbonded_update { let s in 0 .. MAX_SPANS; - let min_create_bond = min_create_bond::(); + let min_create_bond = Pools::::depositor_min_bond(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); // Add a new member @@ -428,7 +422,7 @@ frame_benchmarking::benchmarks! { withdraw_unbonded_kill { let s in 0 .. MAX_SPANS; - let min_create_bond = min_create_bond::(); + let min_create_bond = Pools::::depositor_min_bond(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); let depositor_lookup = T::Lookup::unlookup(depositor.clone()); @@ -493,14 +487,14 @@ frame_benchmarking::benchmarks! { } create { - let min_create_bond = min_create_bond::(); + let min_create_bond = Pools::::depositor_min_bond(); let depositor: T::AccountId = account("depositor", USER_SEED, 0); let depositor_lookup = T::Lookup::unlookup(depositor.clone()); // Give the depositor some balance to bond CurrencyOf::::make_free_balance_be(&depositor, min_create_bond * 2u32.into()); - // Make sure no pools exist as a pre-condition for our verify checks + // Make sure no Pools exist at a pre-condition for our verify checks assert_eq!(RewardPools::::count(), 0); assert_eq!(BondedPools::::count(), 0); @@ -540,7 +534,7 @@ frame_benchmarking::benchmarks! { let n in 1 .. T::MaxNominations::get(); // Create a pool - let min_create_bond = min_create_bond::() * 2u32.into(); + let min_create_bond = Pools::::depositor_min_bond() * 2u32.into(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); // Create some accounts to nominate. For the sake of benchmarking they don't need to be @@ -577,7 +571,7 @@ frame_benchmarking::benchmarks! { set_state { // Create a pool - let min_create_bond = min_create_bond::(); + let min_create_bond = Pools::::depositor_min_bond(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); BondedPools::::mutate(&1, |maybe_pool| { // Force the pool into an invalid state @@ -595,7 +589,7 @@ frame_benchmarking::benchmarks! { let n in 1 .. ::MaxMetadataLen::get(); // Create a pool - let (depositor, pool_account) = create_pool_account::(0, min_create_bond::() * 2u32.into()); + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into()); // Create metadata of the max possible size let metadata: Vec = (0..n).map(|_| 42).collect(); @@ -624,7 +618,7 @@ frame_benchmarking::benchmarks! { update_roles { let first_id = pallet_nomination_pools::LastPoolId::::get() + 1; - let (root, _) = create_pool_account::(0, min_create_bond::() * 2u32.into()); + let (root, _) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into()); let random: T::AccountId = account("but is anything really random in computers..?", 0, USER_SEED); }:_( RuntimeOrigin::Signed(root.clone()), @@ -646,7 +640,7 @@ frame_benchmarking::benchmarks! { chill { // Create a pool - let (depositor, pool_account) = create_pool_account::(0, min_create_bond::() * 2u32.into()); + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into()); // Nominate with the pool. let validators: Vec<_> = (0..T::MaxNominations::get()) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index dfe4bf1931068..28d10ce573401 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2184,10 +2184,11 @@ impl Pallet { /// /// It is essentially `max { MinNominatorBond, MinCreateBond, MinJoinBond }`, where the former /// is coming from the staking pallet and the latter two are configured in this pallet. - fn depositor_min_bond() -> BalanceOf { + pub fn depositor_min_bond() -> BalanceOf { T::StakingInterface::minimum_bond() .max(MinCreateBond::::get()) .max(MinJoinBond::::get()) + .max(T::Currency::minimum_balance()) } /// Remove everything related to the given bonded pool. /// diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 7b8d14164d63f..5074a7ffa695a 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -2771,7 +2771,7 @@ mod unbond { #[test] fn partial_unbond_era_tracking() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().ed(1).build_and_execute(|| { // to make the depositor capable of withdrawing. StakingMinBond::set(1); MinCreateBond::::set(1); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 56fcb1965bc13..df568d6b596ba 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -563,7 +563,7 @@ impl StakingLedger { /// /// This calls `Config::OnStakerSlash::on_slash` with information as to how the slash was /// applied. - fn slash( + pub fn slash( &mut self, slash_amount: BalanceOf, minimum_balance: BalanceOf, diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index abb8649169fdd..399f50aaed865 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -653,10 +653,10 @@ impl Pallet { #[cfg(feature = "runtime-benchmarks")] pub fn add_era_stakers( current_era: EraIndex, - controller: T::AccountId, + stash: T::AccountId, exposure: Exposure>, ) { - >::insert(¤t_era, &controller, &exposure); + >::insert(¤t_era, &stash, &exposure); } #[cfg(feature = "runtime-benchmarks")] diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index d113c0bb2243c..4db3870c62d8b 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -504,6 +504,7 @@ pub mod pallet { /// Slashing spans for stash accounts. #[pallet::storage] + #[pallet::getter(fn slashing_spans)] #[pallet::unbounded] pub(crate) type SlashingSpans = StorageMap<_, Twox64Concat, T::AccountId, slashing::SlashingSpans>; @@ -656,8 +657,8 @@ pub mod pallet { EraPaid(EraIndex, BalanceOf, BalanceOf), /// The nominator has been rewarded by this amount. \[stash, amount\] Rewarded(T::AccountId, BalanceOf), - /// One validator (and its nominators) has been slashed by the given amount. - /// \[validator, amount\] + /// One staker (and potentially its nominators) has been slashed by the given amount. + /// \[staker, amount\] Slashed(T::AccountId, BalanceOf), /// An old slashing report from a prior era was discarded because it could /// not be processed. \[session_index\] From 397da2753081b3cbe4cbb0893f17b4188f0d5997 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 23 Sep 2022 12:42:36 +0200 Subject: [PATCH 1193/1472] bench: Use `_` instead of `::` in auto-generated file names (#12332) * Replace :: with _ in auto-generated file names Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi --- frame/benchmarking/README.md | 2 +- .../benchmarking-cli/src/pallet/command.rs | 15 ++++++------ .../benchmarking-cli/src/pallet/writer.rs | 24 ++++++++++++++----- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/frame/benchmarking/README.md b/frame/benchmarking/README.md index 6316cd5903c8b..76673c5f69b33 100644 --- a/frame/benchmarking/README.md +++ b/frame/benchmarking/README.md @@ -185,7 +185,7 @@ Then you can run a benchmark like so: ``` This will output a file `pallet_name.rs` which implements the `WeightInfo` trait you should include -in your pallet. Each blockchain should generate their own benchmark file with their custom +in your pallet. Double colons `::` will be replaced with a `_` in the output name if you specify a directory. Each blockchain should generate their own benchmark file with their custom implementation of the `WeightInfo` trait. This means that you will be able to use these modular Substrate pallets while still keeping your network safe for your specific configuration and requirements. diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 0fc7cc4d783f7..6870ec386d23d 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -228,7 +228,7 @@ impl PalletCmd { let mut component_ranges = HashMap::<(Vec, Vec), Vec>::new(); for (pallet, extrinsic, components) in benchmarks_to_run { - log::info!( + println!( "Starting benchmark: {}::{}", String::from_utf8(pallet.clone()).expect("Encoded from String; qed"), String::from_utf8(extrinsic.clone()).expect("Encoded from String; qed"), @@ -376,7 +376,7 @@ impl PalletCmd { if let Ok(elapsed) = timer.elapsed() { if elapsed >= time::Duration::from_secs(5) { timer = time::SystemTime::now(); - log::info!( + println!( "Running Benchmark: {}.{}({} args) {}/{} {}/{}", String::from_utf8(pallet.clone()) .expect("Encoded from String; qed"), @@ -398,16 +398,17 @@ impl PalletCmd { // are together. let batches: Vec = combine_batches(batches, batches_db); - // Create the weights.rs file. - if let Some(output_path) = &self.output { - writer::write_results(&batches, &storage_info, &component_ranges, output_path, self)?; - } - // Jsonify the result and write it to a file or stdout if desired. if !self.jsonify(&batches)? { // Print the summary only if `jsonify` did not write to stdout. self.print_summary(&batches, &storage_info) } + + // Create the weights.rs file. + if let Some(output_path) = &self.output { + writer::write_results(&batches, &storage_info, &component_ranges, output_path, self)?; + } + Ok(()) } diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index a601c09eb5033..cd52ffc329d1c 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -24,6 +24,7 @@ use std::{ }; use inflector::Inflector; +use itertools::Itertools; use serde::Serialize; use crate::{pallet::command::ComponentRange, shared::UnderscoreHelper, PalletCmd}; @@ -314,18 +315,21 @@ pub(crate) fn write_results( // Organize results by pallet into a JSON map let all_results = map_results(batches, storage_info, component_ranges, &analysis_choice)?; + let mut created_files = Vec::new(); + for ((pallet, instance), results) in all_results.iter() { let mut file_path = path.clone(); // If a user only specified a directory... if file_path.is_dir() { + // Start with "path/to/pallet_name". + let mut file_name = pallet.clone(); // Check if there might be multiple instances benchmarked. if all_results.keys().any(|(p, i)| p == pallet && i != instance) { - // Create new file: "path/to/pallet_name_instance_name.rs". - file_path.push(pallet.clone() + "_" + instance.to_snake_case().as_str()); - } else { - // Create new file: "path/to/pallet_name.rs". - file_path.push(pallet.clone()); + // Append "_instance_name". + file_name = format!("{}_{}", file_name, instance.to_snake_case()); } + // "mod::pallet_name.rs" becomes "mod_pallet_name.rs". + file_path.push(file_name.replace("::", "_")); file_path.set_extension("rs"); } @@ -342,10 +346,18 @@ pub(crate) fn write_results( benchmarks: results.clone(), }; - let mut output_file = fs::File::create(file_path)?; + let mut output_file = fs::File::create(&file_path)?; handlebars .render_template_to_write(&template, &hbs_data, &mut output_file) .map_err(|e| io_error(&e.to_string()))?; + println!("Created file: {:?}", &file_path); + created_files.push(file_path); + } + + for file in created_files.iter().duplicates() { + // This can happen when there are multiple instances of a pallet deployed + // and `--output` forces the output of all instances into the same file. + println!("Multiple benchmarks were written to the same file: {:?}.", file); } Ok(()) } From 8161ee1aa1ccd122150e40a8aef23df3d0a16d02 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Fri, 23 Sep 2022 16:30:55 +0200 Subject: [PATCH 1194/1472] [Feature] Sequential migration execution for try-runtime (#12319) * [Feature] Sequential migration execution for try-runtime * remove unused * guards * reinstate encode/decode * proper feature gate * proper test feature gate * Update frame/support/src/traits/hooks.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/src/traits/hooks.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fix tests * redo Tuple tests * Update frame/support/src/traits/hooks.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * use parameter_types for testing * lint fix * Update frame/support/src/traits/hooks.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * Update frame/support/src/traits/hooks.rs Co-authored-by: Oliver Tale-Yazdi * eloquent feature gate * redo tests * more fixes * properly handle pre/post errors * remove some tests and fix the others * add format import * import fix * more import fixes Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- frame/executive/src/lib.rs | 8 -- frame/support/src/traits/hooks.rs | 169 +++++++++++++++++++----------- 2 files changed, 106 insertions(+), 71 deletions(-) diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 01b71aab745d5..a41c82da5757c 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -287,15 +287,7 @@ where /// /// This should only be used for testing. pub fn try_runtime_upgrade() -> Result { - // ensure both `pre_upgrade` and `post_upgrade` won't change the storage root - let state = { - let _guard = frame_support::StorageNoopGuard::default(); - <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::pre_upgrade().unwrap() - }; let weight = Self::execute_on_runtime_upgrade(); - let _guard = frame_support::StorageNoopGuard::default(); - <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::post_upgrade(state) - .unwrap(); Ok(weight) } } diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index eb1106e4c383f..3415682c0b382 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -22,7 +22,7 @@ use impl_trait_for_tuples::impl_for_tuples; use sp_runtime::traits::AtLeast32BitUnsigned; use sp_std::prelude::*; -#[cfg(feature = "try-runtime")] +#[cfg(all(feature = "try-runtime", test))] use codec::{Decode, Encode}; /// The block initialization trait. @@ -165,6 +165,7 @@ pub trait OnRuntimeUpgrade { #[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnRuntimeUpgrade for Tuple { + #[cfg(not(feature = "try-runtime"))] fn on_runtime_upgrade() -> Weight { let mut weight = Weight::zero(); for_tuples!( #( weight = weight.saturating_add(Tuple::on_runtime_upgrade()); )* ); @@ -172,20 +173,42 @@ impl OnRuntimeUpgrade for Tuple { } #[cfg(feature = "try-runtime")] + /// We are executing pre- and post-checks sequentially in order to be able to test several + /// consecutive migrations for the same pallet without errors. Therefore pre and post upgrade + /// hooks for tuples are a noop. + fn on_runtime_upgrade() -> Weight { + use scale_info::prelude::format; + + let mut weight = Weight::zero(); + // migration index in the tuple, start with 1 for better readability + let mut i = 1; + for_tuples!( #( + let _guard = frame_support::StorageNoopGuard::default(); + // we want to panic if any checks fail right here right now. + let state = Tuple::pre_upgrade().expect(&format!("PreUpgrade failed for migration #{}", i)); + drop(_guard); + + weight = weight.saturating_add(Tuple::on_runtime_upgrade()); + + let _guard = frame_support::StorageNoopGuard::default(); + // we want to panic if any checks fail right here right now. + Tuple::post_upgrade(state).expect(&format!("PostUpgrade failed for migration #{}", i)); + drop(_guard); + + i += 1; + )* ); + weight + } + + #[cfg(feature = "try-runtime")] + /// noop fn pre_upgrade() -> Result, &'static str> { - let mut state: Vec> = Vec::default(); - for_tuples!( #( state.push(Tuple::pre_upgrade()?); )* ); - Ok(state.encode()) + Ok(Vec::new()) } #[cfg(feature = "try-runtime")] - fn post_upgrade(state: Vec) -> Result<(), &'static str> { - let state: Vec> = Decode::decode(&mut state.as_slice()) - .expect("the state parameter should be the same as pre_upgrade generated"); - let mut state_iter = state.into_iter(); - for_tuples!( #( Tuple::post_upgrade( - state_iter.next().expect("the state parameter should be the same as pre_upgrade generated") - )?; )* ); + /// noop + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { Ok(()) } } @@ -342,7 +365,9 @@ mod tests { #[test] fn on_initialize_and_on_runtime_upgrade_weight_merge_works() { + use sp_io::TestExternalities; struct Test; + impl OnInitialize for Test { fn on_initialize(_n: u8) -> Weight { Weight::from_ref_time(10) @@ -354,8 +379,10 @@ mod tests { } } - assert_eq!(<(Test, Test)>::on_initialize(0), Weight::from_ref_time(20)); - assert_eq!(<(Test, Test)>::on_runtime_upgrade(), Weight::from_ref_time(40)); + TestExternalities::default().execute_with(|| { + assert_eq!(<(Test, Test)>::on_initialize(0), Weight::from_ref_time(20)); + assert_eq!(<(Test, Test)>::on_runtime_upgrade(), Weight::from_ref_time(40)); + }); } #[test] @@ -416,91 +443,107 @@ mod tests { #[cfg(feature = "try-runtime")] #[test] + #[allow(dead_code)] fn on_runtime_upgrade_tuple() { + use frame_support::parameter_types; + use sp_io::TestExternalities; + struct Test1; struct Test2; struct Test3; + parameter_types! { + static Test1Assertions: u8 = 0; + static Test2Assertions: u8 = 0; + static Test3Assertions: u8 = 0; + static EnableSequentialTest: bool = false; + static SequentialAssertions: u8 = 0; + } + impl OnRuntimeUpgrade for Test1 { fn pre_upgrade() -> Result, &'static str> { Ok("Test1".encode()) } fn post_upgrade(state: Vec) -> Result<(), &'static str> { let s: String = Decode::decode(&mut state.as_slice()).unwrap(); + Test1Assertions::mutate(|val| *val += 1); + if EnableSequentialTest::get() { + SequentialAssertions::mutate(|val| *val += 1); + } assert_eq!(s, "Test1"); Ok(()) } } + impl OnRuntimeUpgrade for Test2 { fn pre_upgrade() -> Result, &'static str> { Ok(100u32.encode()) } fn post_upgrade(state: Vec) -> Result<(), &'static str> { let s: u32 = Decode::decode(&mut state.as_slice()).unwrap(); + Test2Assertions::mutate(|val| *val += 1); + if EnableSequentialTest::get() { + assert_eq!(SequentialAssertions::get(), 1); + SequentialAssertions::mutate(|val| *val += 1); + } assert_eq!(s, 100); Ok(()) } } + impl OnRuntimeUpgrade for Test3 { fn pre_upgrade() -> Result, &'static str> { Ok(true.encode()) } fn post_upgrade(state: Vec) -> Result<(), &'static str> { let s: bool = Decode::decode(&mut state.as_slice()).unwrap(); + Test3Assertions::mutate(|val| *val += 1); + if EnableSequentialTest::get() { + assert_eq!(SequentialAssertions::get(), 2); + SequentialAssertions::mutate(|val| *val += 1); + } assert_eq!(s, true); Ok(()) } } - type TestEmpty = (); - let origin_state = ::pre_upgrade().unwrap(); - let states: Vec> = Decode::decode(&mut origin_state.as_slice()).unwrap(); - assert!(states.is_empty()); - ::post_upgrade(origin_state).unwrap(); - - type Test1Tuple = (Test1,); - let origin_state = ::pre_upgrade().unwrap(); - let states: Vec> = Decode::decode(&mut origin_state.as_slice()).unwrap(); - assert_eq!(states.len(), 1); - assert_eq!( - ::decode(&mut states[0].as_slice()).unwrap(), - "Test1".to_owned() - ); - ::post_upgrade(origin_state).unwrap(); - - type Test123 = (Test1, Test2, Test3); - let origin_state = ::pre_upgrade().unwrap(); - let states: Vec> = Decode::decode(&mut origin_state.as_slice()).unwrap(); - assert_eq!( - ::decode(&mut states[0].as_slice()).unwrap(), - "Test1".to_owned() - ); - assert_eq!(::decode(&mut states[1].as_slice()).unwrap(), 100u32); - assert_eq!(::decode(&mut states[2].as_slice()).unwrap(), true); - ::post_upgrade(origin_state).unwrap(); - - type Test321 = (Test3, Test2, Test1); - let origin_state = ::pre_upgrade().unwrap(); - let states: Vec> = Decode::decode(&mut origin_state.as_slice()).unwrap(); - assert_eq!(::decode(&mut states[0].as_slice()).unwrap(), true); - assert_eq!(::decode(&mut states[1].as_slice()).unwrap(), 100u32); - assert_eq!( - ::decode(&mut states[2].as_slice()).unwrap(), - "Test1".to_owned() - ); - ::post_upgrade(origin_state).unwrap(); - - type TestNested123 = (Test1, (Test2, Test3)); - let origin_state = ::pre_upgrade().unwrap(); - let states: Vec> = Decode::decode(&mut origin_state.as_slice()).unwrap(); - assert_eq!( - ::decode(&mut states[0].as_slice()).unwrap(), - "Test1".to_owned() - ); - // nested state for (Test2, Test3) - let nested_states: Vec> = Decode::decode(&mut states[1].as_slice()).unwrap(); - assert_eq!(::decode(&mut nested_states[0].as_slice()).unwrap(), 100u32); - assert_eq!(::decode(&mut nested_states[1].as_slice()).unwrap(), true); - ::post_upgrade(origin_state).unwrap(); + TestExternalities::default().execute_with(|| { + type TestEmpty = (); + let origin_state = ::pre_upgrade().unwrap(); + assert!(origin_state.is_empty()); + ::post_upgrade(origin_state).unwrap(); + + type Test1Tuple = (Test1,); + let origin_state = ::pre_upgrade().unwrap(); + assert!(origin_state.is_empty()); + ::post_upgrade(origin_state).unwrap(); + assert_eq!(Test1Assertions::get(), 0); + ::on_runtime_upgrade(); + assert_eq!(Test1Assertions::take(), 1); + + type Test321 = (Test3, Test2, Test1); + ::on_runtime_upgrade(); + assert_eq!(Test1Assertions::take(), 1); + assert_eq!(Test2Assertions::take(), 1); + assert_eq!(Test3Assertions::take(), 1); + + // enable sequential tests + EnableSequentialTest::mutate(|val| *val = true); + + type Test123 = (Test1, Test2, Test3); + ::on_runtime_upgrade(); + assert_eq!(Test1Assertions::take(), 1); + assert_eq!(Test2Assertions::take(), 1); + assert_eq!(Test3Assertions::take(), 1); + + // reset assertions + SequentialAssertions::take(); + + type TestNested123 = (Test1, (Test2, Test3)); + ::on_runtime_upgrade(); + assert_eq!(Test1Assertions::take(), 1); + assert_eq!(Test2Assertions::take(), 1); + assert_eq!(Test3Assertions::take(), 1); + }); } } From b34936a38731c7f70536f7ce2502024d0d573424 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Fri, 23 Sep 2022 16:42:24 +0200 Subject: [PATCH 1195/1472] [Fix] parameter_types! dead code errors (#12340) * [Fix] parameter_types! dead code errors * mark the whole impl allow(unused) --- frame/support/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 57f29e592b242..51aa05261dac3 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -361,9 +361,9 @@ macro_rules! parameter_types { } }; (IMPL_STORAGE $name:ident, $type:ty, $value:expr $(, $ty_params:ident)*) => { + #[allow(unused)] impl< $($ty_params),* > $name< $($ty_params),* > { /// Returns the key for this parameter type. - #[allow(unused)] pub fn key() -> [u8; 16] { $crate::sp_core_hashing_proc_macro::twox_128!(b":", $name, b":") } @@ -372,7 +372,6 @@ macro_rules! parameter_types { /// /// This needs to be executed in an externalities provided /// environment. - #[allow(unused)] pub fn set(value: &$type) { $crate::storage::unhashed::put(&Self::key(), value); } @@ -448,6 +447,7 @@ macro_rules! parameter_types_impl_thread_local { } /// Mutate the internal value in place. + #[allow(unused)] pub fn mutate R>(mutate: F) -> R{ let mut current = Self::get(); let result = mutate(&mut current); @@ -456,6 +456,7 @@ macro_rules! parameter_types_impl_thread_local { } /// Get current value and replace with initial value of the parameter type. + #[allow(unused)] pub fn take() -> $type { let current = Self::get(); Self::set($value); From ffcd5232a89b556dcf558db429c6c3d9a020cc27 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 23 Sep 2022 19:51:57 +0200 Subject: [PATCH 1196/1472] Independence of Slot-based algorithms from system Timestamp (#12224) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove timestamp from SlotInfo * Expose as millis instead of secs * Nits * Fix test after field removal * Yet another test fix * On the fly timestamp computation * Removed slot timestamp from logs * Removed reference to timestamp from slots subsystem * Slot based algorithm tests do not require timstamp inherent anymore * Remove junk files * Further tests cleanup * Trigger pipeline * Apply code suggestions * Trigger pipeline Co-authored-by: André Silva --- Cargo.lock | 1 - bin/node-template/node/src/service.rs | 4 +- bin/node/cli/src/service.rs | 4 +- client/consensus/aura/src/lib.rs | 26 ++++++------- client/consensus/babe/src/tests.rs | 22 +++++------ client/consensus/slots/Cargo.toml | 1 - client/consensus/slots/src/lib.rs | 56 +++++++++------------------ client/consensus/slots/src/slots.rs | 14 +------ primitives/timestamp/src/lib.rs | 25 ++++++------ 9 files changed, 56 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d1349ce488fa7..74784eb9a6c24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8246,7 +8246,6 @@ dependencies = [ "sp-inherents", "sp-runtime", "sp-state-machine", - "sp-timestamp", "substrate-test-runtime-client", "thiserror", ] diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index caa01761636df..6ec9a33749a69 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -126,7 +126,7 @@ pub fn new_partial( slot_duration, ); - Ok((timestamp, slot)) + Ok((slot, timestamp)) }, spawner: &task_manager.spawn_essential_handle(), registry: config.prometheus_registry(), @@ -269,7 +269,7 @@ pub fn new_full(mut config: Configuration) -> Result slot_duration, ); - Ok((timestamp, slot)) + Ok((slot, timestamp)) }, force_authoring, backoff_authoring_blocks, diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index f2b4feb58075f..a3098eac6402f 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -223,7 +223,7 @@ pub fn new_partial( let uncles = sp_authorship::InherentDataProvider::<::Header>::check_inherents(); - Ok((timestamp, slot, uncles)) + Ok((slot, timestamp, uncles)) }, &task_manager.spawn_essential_handle(), config.prometheus_registry(), @@ -453,7 +453,7 @@ pub fn new_full_base( &parent, )?; - Ok((timestamp, slot, uncles, storage_proof)) + Ok((slot, timestamp, uncles, storage_proof)) } }, force_authoring, diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 0bdc663815051..c538200bb315c 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -569,7 +569,7 @@ mod tests { traits::{Block as BlockT, Header as _}, Digest, }; - use sp_timestamp::InherentDataProvider as TimestampInherentDataProvider; + use sp_timestamp::Timestamp; use std::{ task::Poll, time::{Duration, Instant}, @@ -579,6 +579,8 @@ mod tests { TestClient, }; + const SLOT_DURATION_MS: u64 = 1000; + type Error = sp_blockchain::Error; struct DummyFactory(Arc); @@ -619,8 +621,6 @@ mod tests { } } - const SLOT_DURATION: u64 = 1000; - type AuraVerifier = import_queue::AuraVerifier< PeersFullClient, AuthorityPair, @@ -628,7 +628,7 @@ mod tests { dyn CreateInherentDataProviders< TestBlock, (), - InherentDataProviders = (TimestampInherentDataProvider, InherentDataProvider), + InherentDataProviders = (InherentDataProvider,), >, >, >; @@ -648,17 +648,15 @@ mod tests { let client = client.as_client(); let slot_duration = slot_duration(&*client).expect("slot duration available"); - assert_eq!(slot_duration.as_millis() as u64, SLOT_DURATION); + assert_eq!(slot_duration.as_millis() as u64, SLOT_DURATION_MS); import_queue::AuraVerifier::new( client, Box::new(|_, _| async { - let timestamp = TimestampInherentDataProvider::from_system_time(); let slot = InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - SlotDuration::from_millis(6000), + Timestamp::current(), + SlotDuration::from_millis(SLOT_DURATION_MS), ); - - Ok((timestamp, slot)) + Ok((slot,)) }), CheckForEquivocation::Yes, None, @@ -736,13 +734,12 @@ mod tests { sync_oracle: DummyOracle, justification_sync_link: (), create_inherent_data_providers: |_, _| async { - let timestamp = TimestampInherentDataProvider::from_system_time(); let slot = InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - SlotDuration::from_millis(6000), + Timestamp::current(), + SlotDuration::from_millis(SLOT_DURATION_MS), ); - Ok((timestamp, slot)) + Ok((slot,)) }, force_authoring: false, backoff_authoring_blocks: Some( @@ -875,7 +872,6 @@ mod tests { let res = executor::block_on(worker.on_slot(SlotInfo { slot: 0.into(), - timestamp: 0.into(), ends_at: Instant::now() + Duration::from_secs(100), inherent_data: InherentData::new(), duration: Duration::from_millis(1000), diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index a3467e0020200..58f5e7b8eb6d4 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -43,7 +43,7 @@ use sp_runtime::{ generic::{Digest, DigestItem}, traits::Block as BlockT, }; -use sp_timestamp::InherentDataProvider as TimestampInherentDataProvider; +use sp_timestamp::Timestamp; use std::{cell::RefCell, task::Poll, time::Duration}; type Item = DigestItem; @@ -68,6 +68,8 @@ type Mutator = Arc; type BabeBlockImport = PanickingBlockImport>>; +const SLOT_DURATION_MS: u64 = 1000; + #[derive(Clone)] struct DummyFactory { client: Arc, @@ -239,7 +241,7 @@ pub struct TestVerifier { dyn CreateInherentDataProviders< TestBlock, (), - InherentDataProviders = (TimestampInherentDataProvider, InherentDataProvider), + InherentDataProviders = (InherentDataProvider,), >, >, >, @@ -321,13 +323,11 @@ impl TestNetFactory for BabeTestNet { client: client.clone(), select_chain: longest_chain, create_inherent_data_providers: Box::new(|_, _| async { - let timestamp = TimestampInherentDataProvider::from_system_time(); let slot = InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - SlotDuration::from_millis(6000), + Timestamp::current(), + SlotDuration::from_millis(SLOT_DURATION_MS), ); - - Ok((timestamp, slot)) + Ok((slot,)) }), config: data.link.config.clone(), epoch_changes: data.link.epoch_changes.clone(), @@ -433,13 +433,11 @@ fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static env: environ, sync_oracle: DummyOracle, create_inherent_data_providers: Box::new(|_, _| async { - let timestamp = TimestampInherentDataProvider::from_system_time(); let slot = InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - SlotDuration::from_millis(6000), + Timestamp::current(), + SlotDuration::from_millis(SLOT_DURATION_MS), ); - - Ok((timestamp, slot)) + Ok((slot,)) }), force_authoring: false, backoff_authoring_blocks: Some(BackoffAuthoringOnFinalizedHeadLagging::default()), diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 208e31971257d..fae499ad7c7c6 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -31,7 +31,6 @@ sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } -sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index b9f8c03f2ac88..7c5d5d4a73bc1 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -42,7 +42,6 @@ use sp_consensus::{Proposal, Proposer, SelectChain, SyncOracle}; use sp_consensus_slots::{Slot, SlotDuration}; use sp_inherents::CreateInherentDataProviders; use sp_runtime::traits::{Block as BlockT, HashFor, Header as HeaderT}; -use sp_timestamp::Timestamp; use std::{fmt::Debug, ops::Deref, time::Duration}; /// The changes that need to applied to the storage to create the state for a block. @@ -252,7 +251,7 @@ pub trait SimpleSlotWorker { where Self: Sync, { - let (timestamp, slot) = (slot_info.timestamp, slot_info.slot); + let slot = slot_info.slot; let telemetry = self.telemetry(); let logging_target = self.logging_target(); @@ -316,23 +315,14 @@ pub trait SimpleSlotWorker { return None } - debug!( - target: logging_target, - "Starting authorship at slot {}; timestamp = {}", slot, *timestamp, - ); + debug!(target: logging_target, "Starting authorship at slot: {slot}"); - telemetry!( - telemetry; - CONSENSUS_DEBUG; - "slots.starting_authorship"; - "slot_num" => *slot, - "timestamp" => *timestamp, - ); + telemetry!(telemetry; CONSENSUS_DEBUG; "slots.starting_authorship"; "slot_num" => slot); let proposer = match self.proposer(&slot_info.chain_head).await { Ok(p) => p, Err(err) => { - warn!(target: logging_target, "Unable to author block in slot {:?}: {}", slot, err,); + warn!(target: logging_target, "Unable to author block in slot {slot:?}: {err}"); telemetry!( telemetry; @@ -440,44 +430,35 @@ impl + Send + Sync, B: BlockT> /// Slot specific extension that the inherent data provider needs to implement. pub trait InherentDataProviderExt { - /// The current timestamp that will be found in the - /// [`InherentData`](`sp_inherents::InherentData`). - fn timestamp(&self) -> Timestamp; - /// The current slot that will be found in the [`InherentData`](`sp_inherents::InherentData`). fn slot(&self) -> Slot; } /// Small macro for implementing `InherentDataProviderExt` for inherent data provider tuple. macro_rules! impl_inherent_data_provider_ext_tuple { - ( T, S $(, $TN:ident)* $( , )?) => { - impl InherentDataProviderExt for (T, S, $($TN),*) + ( S $(, $TN:ident)* $( , )?) => { + impl InherentDataProviderExt for (S, $($TN),*) where - T: Deref, S: Deref, { - fn timestamp(&self) -> Timestamp { - *self.0.deref() - } - fn slot(&self) -> Slot { - *self.1.deref() + *self.0.deref() } } } } -impl_inherent_data_provider_ext_tuple!(T, S); -impl_inherent_data_provider_ext_tuple!(T, S, A); -impl_inherent_data_provider_ext_tuple!(T, S, A, B); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F, G); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F, G, H); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F, G, H, I); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F, G, H, I, J); +impl_inherent_data_provider_ext_tuple!(S); +impl_inherent_data_provider_ext_tuple!(S, A); +impl_inherent_data_provider_ext_tuple!(S, A, B); +impl_inherent_data_provider_ext_tuple!(S, A, B, C); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E, F); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E, F, G); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E, F, G, H); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E, F, G, H, I); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E, F, G, H, I, J); /// Start a new slot worker. /// @@ -806,7 +787,6 @@ mod test { super::slots::SlotInfo { slot: slot.into(), duration: SLOT_DURATION, - timestamp: Default::default(), inherent_data: Default::default(), ends_at: Instant::now() + SLOT_DURATION, chain_head: Header::new( diff --git a/client/consensus/slots/src/slots.rs b/client/consensus/slots/src/slots.rs index accf24b6b4e78..f3dc485a8e819 100644 --- a/client/consensus/slots/src/slots.rs +++ b/client/consensus/slots/src/slots.rs @@ -50,8 +50,6 @@ pub fn time_until_next_slot(slot_duration: Duration) -> Duration { pub struct SlotInfo { /// The slot number as found in the inherent data. pub slot: Slot, - /// Current timestamp as found in the inherent data. - pub timestamp: sp_timestamp::Timestamp, /// The instant at which the slot ends. pub ends_at: Instant, /// The inherent data. @@ -72,7 +70,6 @@ impl SlotInfo { /// `ends_at` is calculated using `timestamp` and `duration`. pub fn new( slot: Slot, - timestamp: sp_timestamp::Timestamp, inherent_data: InherentData, duration: Duration, chain_head: B::Header, @@ -80,7 +77,6 @@ impl SlotInfo { ) -> Self { Self { slot, - timestamp, inherent_data, duration, chain_head, @@ -175,7 +171,6 @@ where ); } - let timestamp = inherent_data_providers.timestamp(); let slot = inherent_data_providers.slot(); let inherent_data = inherent_data_providers.create_inherent_data()?; @@ -183,14 +178,7 @@ where if slot > self.last_slot { self.last_slot = slot; - break Ok(SlotInfo::new( - slot, - timestamp, - inherent_data, - self.slot_duration, - chain_head, - None, - )) + break Ok(SlotInfo::new(slot, inherent_data, self.slot_duration, chain_head, None)) } } } diff --git a/primitives/timestamp/src/lib.rs b/primitives/timestamp/src/lib.rs index b98a87c37f69d..d88b1839babe6 100644 --- a/primitives/timestamp/src/lib.rs +++ b/primitives/timestamp/src/lib.rs @@ -56,6 +56,17 @@ impl Timestamp { pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(Self) } + + /// The current timestamp using the system time. + #[cfg(feature = "std")] + pub fn current() -> Self { + use std::time::SystemTime; + + let now = SystemTime::now(); + now.duration_since(SystemTime::UNIX_EPOCH) + .expect("Current time is always after unix epoch; qed") + .into() + } } impl sp_std::ops::Deref for Timestamp { @@ -165,18 +176,6 @@ impl TimestampInherentData for InherentData { } } -/// The current timestamp using the system time. -/// -/// This timestamp is the time since the UNIX epoch. -#[cfg(feature = "std")] -fn current_timestamp() -> std::time::Duration { - use std::time::SystemTime; - - let now = SystemTime::now(); - now.duration_since(SystemTime::UNIX_EPOCH) - .expect("Current time is always after unix epoch; qed") -} - /// Provide duration since unix epoch in millisecond for timestamp inherent. #[cfg(feature = "std")] pub struct InherentDataProvider { @@ -190,7 +189,7 @@ impl InherentDataProvider { pub fn from_system_time() -> Self { Self { max_drift: std::time::Duration::from_secs(60).into(), - timestamp: current_timestamp().into(), + timestamp: Timestamp::current(), } } From fb779212ca6b59bd158d72deeab2502cb9670cca Mon Sep 17 00:00:00 2001 From: Frederik Gartenmeister Date: Sat, 24 Sep 2022 08:59:44 +0200 Subject: [PATCH 1197/1472] Const impls of base arithmetics for `Weights` with `u64` (#12322) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Const impls * Adding explainatory comments * Update primitives/weights/src/weight_v2.rs Doc comment suggestions Co-authored-by: Bastian Köcher * Update primitives/weights/src/weight_v2.rs Doc comment suggestions Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- primitives/weights/src/weight_v2.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index a4e4da4f8a7b3..af0f469ebaaeb 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -160,6 +160,34 @@ impl Weight { Self { ref_time: 0 } } + /// Constant version of Add with u64. + /// + /// Is only overflow safe when evaluated at compile-time. + pub const fn add(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time + scalar } + } + + /// Constant version of Sub with u64. + /// + /// Is only overflow safe when evaluated at compile-time. + pub const fn sub(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time - scalar } + } + + /// Constant version of Div with u64. + /// + /// Is only overflow safe when evaluated at compile-time. + pub const fn div(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time / scalar } + } + + /// Constant version of Mul with u64. + /// + /// Is only overflow safe when evaluated at compile-time. + pub const fn mul(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time * scalar } + } + /// Returns true if any of `self`'s constituent weights is strictly greater than that of the /// `other`'s, otherwise returns false. pub const fn any_gt(self, other: Self) -> bool { From 9476d2157a0d266677dee144a8a7bc44a6b821e1 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sat, 24 Sep 2022 17:17:44 +0200 Subject: [PATCH 1198/1472] Add base-weight to `System::Extrinsic*` events (#12329) * Add base-weight to events Signed-off-by: Oliver Tale-Yazdi * Fix test Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- bin/node/executor/tests/basic.rs | 13 +- frame/system/src/extensions/check_weight.rs | 12 +- frame/system/src/lib.rs | 8 +- frame/system/src/mock.rs | 1 + frame/system/src/tests.rs | 312 +++++++++++--------- 5 files changed, 198 insertions(+), 148 deletions(-) diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 99a9b83596acf..fc4e138faafc2 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -311,10 +311,19 @@ fn full_native_block_import_works() { let mut alice_last_known_balance: Balance = Default::default(); let mut fees = t.execute_with(|| transfer_fee(&xt())); - let transfer_weight = default_transfer_call().get_dispatch_info().weight; + let transfer_weight = default_transfer_call().get_dispatch_info().weight.saturating_add( + ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic, + ); let timestamp_weight = pallet_timestamp::Call::set:: { now: Default::default() } .get_dispatch_info() - .weight; + .weight + .saturating_add( + ::BlockWeights::get() + .get(DispatchClass::Mandatory) + .base_extrinsic, + ); executor_call(&mut t, "Core_execute_block", &block1.0, true).0.unwrap(); diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index 466231b8455ec..15a88913cd337 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -342,7 +342,7 @@ mod tests { .get(DispatchClass::Operational) .max_total .unwrap_or_else(|| weights.max_block); - let base_weight = weights.get(DispatchClass::Normal).base_extrinsic; + let base_weight = weights.get(DispatchClass::Operational).base_extrinsic; let weight = operational_limit - base_weight; let okay = @@ -378,11 +378,11 @@ mod tests { // Max normal is 768 (75%) // 10 is taken for block execution weight // So normal extrinsic can be 758 weight (-5 for base extrinsic weight) - // And Operational can be 256 to produce a full block (-5 for base) + // And Operational can be 246 to produce a full block (-10 for base) let max_normal = DispatchInfo { weight: Weight::from_ref_time(753), ..Default::default() }; let rest_operational = DispatchInfo { - weight: Weight::from_ref_time(251), + weight: Weight::from_ref_time(246), class: DispatchClass::Operational, ..Default::default() }; @@ -406,7 +406,7 @@ mod tests { let max_normal = DispatchInfo { weight: Weight::from_ref_time(753), ..Default::default() }; let rest_operational = DispatchInfo { - weight: Weight::from_ref_time(251), + weight: Weight::from_ref_time(246), class: DispatchClass::Operational, ..Default::default() }; @@ -414,7 +414,7 @@ mod tests { let len = 0_usize; assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); - // Extra 15 here from block execution + base extrinsic weight + // Extra 20 here from block execution + base extrinsic weight assert_eq!(System::block_weight().total(), Weight::from_ref_time(266)); assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); assert_eq!(block_weight_limit(), Weight::from_ref_time(1024)); @@ -433,7 +433,7 @@ mod tests { ..Default::default() }; let dispatch_operational = DispatchInfo { - weight: Weight::from_ref_time(251), + weight: Weight::from_ref_time(246), class: DispatchClass::Operational, ..Default::default() }; diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 36360f8fae2c2..dc74157da79de 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1509,9 +1509,15 @@ impl Pallet { } /// To be called immediately after an extrinsic has been applied. + /// + /// Emits an `ExtrinsicSuccess` or `ExtrinsicFailed` event depending on the outcome. + /// The emitted event contains the post-dispatch corrected weight including + /// the base-weight for its dispatch class. pub fn note_applied_extrinsic(r: &DispatchResultWithPostInfo, mut info: DispatchInfo) { - info.weight = extract_actual_weight(r, &info); + info.weight = extract_actual_weight(r, &info) + .saturating_add(T::BlockWeights::get().get(info.class).base_extrinsic); info.pays_fee = extract_actual_pays_fee(r, &info); + Self::deposit_event(match r { Ok(_) => Event::ExtrinsicSuccess { dispatch_info: info }, Err(err) => { diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index 1c0511787eb76..b6fc121612050 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -67,6 +67,7 @@ parameter_types! { weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAX_BLOCK_WEIGHT); }) .for_class(DispatchClass::Operational, |weights| { + weights.base_extrinsic = Weight::from_ref_time(10); weights.max_total = Some(MAX_BLOCK_WEIGHT); weights.reserved = Some( MAX_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAX_BLOCK_WEIGHT diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index 92563f4ad1747..c42131c450228 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -169,6 +169,10 @@ fn deposit_event_should_work() { }] ); + let normal_base = ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + System::reset_events(); System::initialize(&2, &[0u8; 32].into(), &Default::default()); System::deposit_event(SysEvent::NewAccount { account: 32 }); @@ -194,14 +198,17 @@ fn deposit_event_should_work() { }, EventRecord { phase: Phase::ApplyExtrinsic(0), - event: SysEvent::ExtrinsicSuccess { dispatch_info: Default::default() }.into(), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { weight: normal_base, ..Default::default() } + } + .into(), topics: vec![] }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: Default::default() + dispatch_info: DispatchInfo { weight: normal_base, ..Default::default() } } .into(), topics: vec![] @@ -223,6 +230,9 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::note_finished_initialize(); + let normal_base = ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; let pre_info = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; System::note_applied_extrinsic(&Ok(Some(300).into()), pre_info); System::note_applied_extrinsic(&Ok(Some(1000).into()), pre_info); @@ -267,144 +277,168 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { }), pre_info, ); + // Also works for operational. + let operational_base = ::BlockWeights::get() + .get(DispatchClass::Operational) + .base_extrinsic; + assert!(normal_base != operational_base, "Test pre-condition violated"); + let pre_info = DispatchInfo { + weight: Weight::from_ref_time(1000), + class: DispatchClass::Operational, + ..Default::default() + }; + System::note_applied_extrinsic(&Ok(Some(300).into()), pre_info); - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(300), - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(1), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(2), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(3), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - pays_fee: Pays::Yes, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(4), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - pays_fee: Pays::No, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(5), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - pays_fee: Pays::No, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(6), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(500), - pays_fee: Pays::No, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(7), - event: SysEvent::ExtrinsicFailed { - dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(999), - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(8), - event: SysEvent::ExtrinsicFailed { - dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - pays_fee: Pays::Yes, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(9), - event: SysEvent::ExtrinsicFailed { - dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(800), - pays_fee: Pays::Yes, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(10), - event: SysEvent::ExtrinsicFailed { - dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(800), - pays_fee: Pays::No, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - ] - ); + let got = System::events(); + let want = vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(300).saturating_add(normal_base), + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(2), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(3), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + pays_fee: Pays::Yes, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(4), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(5), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(6), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(500).saturating_add(normal_base), + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(7), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(999).saturating_add(normal_base), + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(8), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + pays_fee: Pays::Yes, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(9), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(800).saturating_add(normal_base), + pays_fee: Pays::Yes, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(10), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(800).saturating_add(normal_base), + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(11), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(300).saturating_add(operational_base), + class: DispatchClass::Operational, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + ]; + for (i, event) in want.into_iter().enumerate() { + assert_eq!(got[i], event, "Event mismatch at index {}", i); + } }); } From d0214e7c77de639d60301d682ced7e155def15da Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Sat, 24 Sep 2022 21:32:35 +0200 Subject: [PATCH 1199/1472] re add the migration checks for staking (#12330) Co-authored-by: parity-processbot <> --- frame/staking/src/migrations.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index f47545af694cf..8f37ae30dd056 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -35,6 +35,11 @@ pub mod v12 { impl OnRuntimeUpgrade for MigrateToV12 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { + frame_support::ensure!( + StorageVersion::::get() == Releases::V11_0_0, + "Expected v11 before upgrading to v12" + ); + frame_support::ensure!( T::HistoryDepth::get() == HistoryDepth::::get(), "Provided value of HistoryDepth should be same as the existing storage value" @@ -129,6 +134,11 @@ pub mod v11 { #[cfg(feature = "try-runtime")] fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + frame_support::ensure!( + StorageVersion::::get() == crate::Releases::V11_0_0, + "wrong version after the upgrade" + ); + let old_pallet_name = N::get(); let new_pallet_name =

::name(); From 4219b3ab45ff2201eb8aecbbb444f9ae055f528e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Sun, 25 Sep 2022 11:24:35 +0200 Subject: [PATCH 1200/1472] Allow specifying immediate finalize for `manual-seal` (#12106) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Theißen --- client/consensus/manual-seal/src/lib.rs | 54 +++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index c5dd169e281f2..4672e7275a56b 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -247,6 +247,60 @@ pub async fn run_instant_seal( .await } +/// Runs the background authorship task for the instant seal engine. +/// instant-seal creates a new block for every transaction imported into +/// the transaction pool. +/// +/// This function will finalize the block immediately as well. If you don't +/// want this behavior use `run_instant_seal` instead. +pub async fn run_instant_seal_and_finalize( + InstantSealParams { + block_import, + env, + client, + pool, + select_chain, + consensus_data_provider, + create_inherent_data_providers, + }: InstantSealParams, +) where + B: BlockT + 'static, + BI: BlockImport> + + Send + + Sync + + 'static, + C: HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, + CB: ClientBackend + 'static, + E: Environment + 'static, + E::Proposer: Proposer>, + SC: SelectChain + 'static, + TransactionFor: 'static, + TP: TransactionPool, + CIDP: CreateInherentDataProviders, + P: Send + Sync + 'static, +{ + // Creates and finalizes blocks as soon as transactions are imported + // into the transaction pool. + let commands_stream = pool.import_notification_stream().map(|_| EngineCommand::SealNewBlock { + create_empty: false, + finalize: true, + parent_hash: None, + sender: None, + }); + + run_manual_seal(ManualSealParams { + block_import, + env, + client, + pool, + commands_stream, + select_chain, + consensus_data_provider, + create_inherent_data_providers, + }) + .await +} + #[cfg(test)] mod tests { use super::*; From badc92ac20dbf006595a6af9418da9942527cbd7 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Sun, 25 Sep 2022 23:22:54 +0200 Subject: [PATCH 1201/1472] Removed OuterCall alias & doc fixes (#12349) --- frame/alliance/src/lib.rs | 2 +- frame/collective/src/lib.rs | 6 +++--- .../election-provider-multi-phase/src/unsigned.rs | 14 +++++++------- frame/multisig/src/benchmarking.rs | 2 +- frame/ranked-collective/src/lib.rs | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 82c7e21dba3af..2ef6718538122 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -243,7 +243,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The outer call dispatch type. + /// The runtime call dispatch type. type Proposal: Parameter + Dispatchable + From> diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index e934924033552..ae68ae2fe3e16 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -180,10 +180,10 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { - /// The outer origin type. + /// The runtime origin type. type RuntimeOrigin: From>; - /// The outer call dispatch type. + /// The runtime call dispatch type. type Proposal: Parameter + Dispatchable< RuntimeOrigin = >::RuntimeOrigin, @@ -191,7 +191,7 @@ pub mod pallet { > + From> + GetDispatchInfo; - /// The outer event type. + /// The runtime event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index cf8df237bafb0..833f80c90d13e 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -856,7 +856,7 @@ mod tests { use crate::{ mock::{ roll_to, roll_to_with_ocw, trim_helpers, witness, BlockNumber, ExtBuilder, Extrinsic, - MinerMaxWeight, MultiPhase, Runtime, RuntimeCall as OuterCall, RuntimeOrigin, System, + MinerMaxWeight, MultiPhase, Runtime, RuntimeCall, RuntimeOrigin, System, TestNposSolution, TrimHelpers, UnsignedPhase, }, CurrentPhase, InvalidTransaction, Phase, QueuedSolution, TransactionSource, @@ -1070,8 +1070,8 @@ mod tests { raw_solution: Box::new(solution.clone()), witness: witness(), }; - let outer_call: OuterCall = call.into(); - let _ = outer_call.dispatch(RuntimeOrigin::none()); + let runtime_call: RuntimeCall = call.into(); + let _ = runtime_call.dispatch(RuntimeOrigin::none()); }) } @@ -1096,8 +1096,8 @@ mod tests { raw_solution: Box::new(solution.clone()), witness: correct_witness, }; - let outer_call: OuterCall = call.into(); - let _ = outer_call.dispatch(RuntimeOrigin::none()); + let runtime_call: RuntimeCall = call.into(); + let _ = runtime_call.dispatch(RuntimeOrigin::none()); }) } @@ -1560,7 +1560,7 @@ mod tests { let encoded = pool.read().transactions[0].clone(); let extrinsic: Extrinsic = codec::Decode::decode(&mut &*encoded).unwrap(); let call = extrinsic.call; - assert!(matches!(call, OuterCall::MultiPhase(Call::submit_unsigned { .. }))); + assert!(matches!(call, RuntimeCall::MultiPhase(Call::submit_unsigned { .. }))); }) } @@ -1577,7 +1577,7 @@ mod tests { let encoded = pool.read().transactions[0].clone(); let extrinsic = Extrinsic::decode(&mut &*encoded).unwrap(); let call = match extrinsic.call { - OuterCall::MultiPhase(call @ Call::submit_unsigned { .. }) => call, + RuntimeCall::MultiPhase(call @ Call::submit_unsigned { .. }) => call, _ => panic!("bad call: unexpected submission"), }; diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index 8d0651002305b..c0b0097b07236 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -41,7 +41,7 @@ fn setup_multi( signatories.push(signatory); } signatories.sort(); - // Must first convert to outer call type. + // Must first convert to runtime call type. let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![0; z as usize] }.into(); let call_data = OpaqueCall::::from_encoded(call.encode()); diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index bdd5d26373980..fa3a473fe7d73 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -361,7 +361,7 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; - /// The outer event type. + /// The runtime event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; From fbd7e5aa99e20b7019576ecf598bca2d7019cddd Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 26 Sep 2022 08:05:05 +0200 Subject: [PATCH 1202/1472] [Enhancement] Remove optional Pool subscription from fast-unstake (#12344) * [Enhancement] Remove optional Pool subscription from fast-unstake * remove nomination-pools pallet dependency * fixes * more fixes * more fixes * more fixes --- Cargo.lock | 1 - frame/fast-unstake/Cargo.toml | 2 - frame/fast-unstake/src/benchmarking.rs | 30 +-- frame/fast-unstake/src/lib.rs | 95 ++------ frame/fast-unstake/src/mock.rs | 50 +--- frame/fast-unstake/src/tests.rs | 302 +++++++------------------ frame/fast-unstake/src/types.rs | 3 - 7 files changed, 105 insertions(+), 378 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74784eb9a6c24..6ea79a120361e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5729,7 +5729,6 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "pallet-nomination-pools", "pallet-staking", "pallet-staking-reward-curve", "pallet-timestamp", diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml index 1fa118dba4a8d..69aeaff35993c 100644 --- a/frame/fast-unstake/Cargo.toml +++ b/frame/fast-unstake/Cargo.toml @@ -28,7 +28,6 @@ sp-staking = { default-features = false, path = "../../primitives/staking" } pallet-balances = { default-features = false, path = "../balances" } pallet-timestamp = { default-features = false, path = "../timestamp" } pallet-staking = { default-features = false, path = "../staking" } -pallet-nomination-pools = { default-features = false, path = "../nomination-pools" } frame-election-provider-support = { default-features = false, path = "../election-provider-support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } @@ -55,7 +54,6 @@ std = [ "sp-std/std", "pallet-staking/std", - "pallet-nomination-pools/std", "pallet-balances/std", "pallet-timestamp/std", "frame-election-provider-support/std", diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs index 68a3da0d40af3..5690d5ce6f29f 100644 --- a/frame/fast-unstake/src/benchmarking.rs +++ b/frame/fast-unstake/src/benchmarking.rs @@ -26,7 +26,6 @@ use frame_support::{ traits::{Currency, EnsureOrigin, Get, Hooks}, }; use frame_system::RawOrigin; -use pallet_nomination_pools::{Pallet as Pools, PoolId}; use pallet_staking::Pallet as Staking; use sp_runtime::traits::{StaticLookup, Zero}; use sp_staking::EraIndex; @@ -76,25 +75,6 @@ pub(crate) fn fast_unstake_events() -> Vec> { .collect::>() } -fn setup_pool() -> PoolId { - let depositor = frame_benchmarking::account::("depositor_42", 0, USER_SEED); - let depositor_lookup = l::(depositor.clone()); - - let stake = Pools::::depositor_min_bond(); - CurrencyOf::::make_free_balance_be(&depositor, stake * 10u32.into()); - - Pools::::create( - RawOrigin::Signed(depositor.clone()).into(), - stake, - depositor_lookup.clone(), - depositor_lookup.clone(), - depositor_lookup, - ) - .unwrap(); - - pallet_nomination_pools::LastPoolId::::get() -} - fn setup_staking(v: u32, until: EraIndex) { let ed = CurrencyOf::::minimum_balance(); @@ -131,10 +111,8 @@ benchmarks! { // on_idle, we we don't check anyone, but fully unbond and move them to another pool. on_idle_unstake { let who = create_unexposed_nominator::(); - let pool_id = setup_pool::(); assert_ok!(FastUnstake::::register_fast_unstake( RawOrigin::Signed(who.clone()).into(), - Some(pool_id) )); ErasToCheckPerBlock::::put(1); @@ -143,7 +121,7 @@ benchmarks! { on_idle_full_block::(); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: who.clone(), checked: vec![0].try_into().unwrap(), maybe_pool_id: Some(pool_id) }) + Some(UnstakeRequest { stash: who.clone(), checked: vec![0].try_into().unwrap() }) ); } : { @@ -172,7 +150,6 @@ benchmarks! { let who = create_unexposed_nominator::(); assert_ok!(FastUnstake::::register_fast_unstake( RawOrigin::Signed(who.clone()).into(), - None, )); // no one is queued thus far. @@ -185,7 +162,7 @@ benchmarks! { let checked: frame_support::BoundedVec<_, _> = (1..=u).rev().collect::>().try_into().unwrap(); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: who.clone(), checked, maybe_pool_id: None }) + Some(UnstakeRequest { stash: who.clone(), checked }) ); assert!(matches!( fast_unstake_events::().last(), @@ -199,7 +176,7 @@ benchmarks! { assert_eq!(Queue::::count(), 0); } - :_(RawOrigin::Signed(who.clone()), None) + :_(RawOrigin::Signed(who.clone())) verify { assert_eq!(Queue::::count(), 1); } @@ -208,7 +185,6 @@ benchmarks! { let who = create_unexposed_nominator::(); assert_ok!(FastUnstake::::register_fast_unstake( RawOrigin::Signed(who.clone()).into(), - None )); assert_eq!(Queue::::count(), 1); whitelist_account!(who); diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 51416808f48c8..5acc9940debf1 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -19,8 +19,7 @@ //! //! If a nominator is not exposed in any `ErasStakers` (i.e. "has not actively backed any //! validators in the last `BondingDuration` days"), then they can register themselves in this -//! pallet, unstake faster than having to wait an entire bonding duration, and potentially move -//! into a nomination pool. +//! pallet, unstake faster than having to wait an entire bonding duration. //! //! Appearing in the exposure of a validator means being exposed equal to that validator from the //! point of view of the staking system. This usually means earning rewards with the validator, and @@ -43,8 +42,7 @@ //! to prevent them from accidentally exposing themselves behind a validator etc. //! //! Once processed, if successful, no additional fee for the checking process is taken, and the -//! staker is instantly unbonded. Optionally, if they have asked to join a pool, their *entire* -//! stake is joined into their pool of choice. +//! staker is instantly unbonded. //! //! If unsuccessful, meaning that the staker was exposed sometime in the last `BondingDuration` eras //! they will end up being slashed for the amount of wasted work they have inflicted on the chian. @@ -85,7 +83,6 @@ pub mod pallet { use frame_election_provider_support::ElectionProvider; use frame_support::pallet_prelude::*; use frame_system::{pallet_prelude::*, RawOrigin}; - use pallet_nomination_pools::PoolId; use pallet_staking::Pallet as Staking; use sp_runtime::{ traits::{Saturating, Zero}, @@ -109,12 +106,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: - frame_system::Config - + pallet_staking::Config< - CurrencyBalance = ::CurrencyBalance, - > + pallet_nomination_pools::Config - { + pub trait Config: frame_system::Config + pallet_staking::Config { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent> @@ -139,10 +131,9 @@ pub mod pallet { /// The map of all accounts wishing to be unstaked. /// - /// Points the `AccountId` wishing to unstake to the optional `PoolId` they wish to join - /// thereafter. + /// Keeps track of `AccountId` wishing to unstake. #[pallet::storage] - pub type Queue = CountedStorageMap<_, Twox64Concat, T::AccountId, Option>; + pub type Queue = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>; /// Number of eras to check per block. /// @@ -158,7 +149,7 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// A staker was unstaked. - Unstaked { stash: T::AccountId, maybe_pool_id: Option, result: DispatchResult }, + Unstaked { stash: T::AccountId, result: DispatchResult }, /// A staker was slashed for requesting fast-unstake whilst being exposed. Slashed { stash: T::AccountId, amount: BalanceOf }, /// A staker was partially checked for the given eras, but the process did not finish. @@ -213,16 +204,13 @@ pub mod pallet { /// they are guaranteed to remain eligible, because the call will chill them as well. /// /// If the check works, the entire staking data is removed, i.e. the stash is fully - /// unstaked, and they potentially join a pool with their entire bonded stake. + /// unstaked. /// /// If the check fails, the stash remains chilled and waiting for being unbonded as in with /// the normal staking system, but they lose part of their unbonding chunks due to consuming /// the chain's resources. #[pallet::weight(::WeightInfo::register_fast_unstake())] - pub fn register_fast_unstake( - origin: OriginFor, - maybe_pool_id: Option, - ) -> DispatchResult { + pub fn register_fast_unstake(origin: OriginFor) -> DispatchResult { let ctrl = ensure_signed(origin)?; let ledger = @@ -243,12 +231,11 @@ pub mod pallet { Staking::::unbond(RawOrigin::Signed(ctrl).into(), ledger.total)?; // enqueue them. - Queue::::insert(ledger.stash, maybe_pool_id); + Queue::::insert(ledger.stash, ()); Ok(()) } - /// Deregister oneself from the fast-unstake (also cancels joining the pool if that was - /// supplied on `register_fast_unstake` . + /// Deregister oneself from the fast-unstake. /// /// This is useful if one is registered, they are still waiting, and they change their mind. /// @@ -327,17 +314,12 @@ pub mod pallet { return T::DbWeight::get().reads(2) } - let UnstakeRequest { stash, mut checked, maybe_pool_id } = match Head::::take() - .or_else(|| { - // NOTE: there is no order guarantees in `Queue`. - Queue::::drain() - .map(|(stash, maybe_pool_id)| UnstakeRequest { - stash, - maybe_pool_id, - checked: Default::default(), - }) - .next() - }) { + let UnstakeRequest { stash, mut checked } = match Head::::take().or_else(|| { + // NOTE: there is no order guarantees in `Queue`. + Queue::::drain() + .map(|(stash, _)| UnstakeRequest { stash, checked: Default::default() }) + .next() + }) { None => { // There's no `Head` and nothing in the `Queue`, nothing to do here. return T::DbWeight::get().reads(4) @@ -392,48 +374,15 @@ pub mod pallet { // `stash` is not exposed in any era now -- we can let go of them now. let num_slashing_spans = Staking::::slashing_spans(&stash).iter().count() as u32; - let ctrl = match pallet_staking::Bonded::::get(&stash) { - Some(ctrl) => ctrl, - None => { - Self::deposit_event(Event::::Errored { stash }); - return ::WeightInfo::on_idle_unstake() - }, - }; - - let ledger = match pallet_staking::Ledger::::get(ctrl) { - Some(ledger) => ledger, - None => { - Self::deposit_event(Event::::Errored { stash }); - return ::WeightInfo::on_idle_unstake() - }, - }; - - let unstake_result = pallet_staking::Pallet::::force_unstake( + let result = pallet_staking::Pallet::::force_unstake( RawOrigin::Root.into(), stash.clone(), num_slashing_spans, ); - let pool_stake_result = if let Some(pool_id) = maybe_pool_id { - pallet_nomination_pools::Pallet::::join( - RawOrigin::Signed(stash.clone()).into(), - ledger.total, - pool_id, - ) - } else { - Ok(()) - }; + log!(info, "unstaked {:?}, outcome: {:?}", stash, result); - let result = unstake_result.and(pool_stake_result); - log!( - info, - "unstaked {:?}, maybe_pool {:?}, outcome: {:?}", - stash, - maybe_pool_id, - result - ); - - Self::deposit_event(Event::::Unstaked { stash, maybe_pool_id, result }); + Self::deposit_event(Event::::Unstaked { stash, result }); ::WeightInfo::on_idle_unstake() } else { // eras remaining to be checked. @@ -471,11 +420,7 @@ pub mod pallet { // Not exposed in these eras. match checked.try_extend(unchecked_eras_to_check.clone().into_iter()) { Ok(_) => { - Head::::put(UnstakeRequest { - stash: stash.clone(), - checked, - maybe_pool_id, - }); + Head::::put(UnstakeRequest { stash: stash.clone(), checked }); Self::deposit_event(Event::::Checking { stash, eras: unchecked_eras_to_check, diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index b9cf16e18e8d1..62f343709e245 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -17,19 +17,10 @@ use crate::{self as fast_unstake}; use frame_support::{ - assert_ok, - pallet_prelude::*, - parameter_types, - traits::{ConstU64, ConstU8, Currency}, - weights::constants::WEIGHT_PER_SECOND, - PalletId, -}; -use sp_runtime::{ - traits::{Convert, IdentityLookup}, - FixedU128, + pallet_prelude::*, parameter_types, traits::ConstU64, weights::constants::WEIGHT_PER_SECOND, }; +use sp_runtime::traits::{Convert, IdentityLookup}; -use frame_system::RawOrigin; use pallet_staking::{Exposure, IndividualExposure, StakerStatus}; use sp_std::prelude::*; @@ -153,7 +144,7 @@ impl pallet_staking::Config for Runtime { type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; - type OnStakerSlash = Pools; + type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } @@ -172,29 +163,6 @@ impl Convert for U256ToBalance { } } -parameter_types! { - pub const PostUnbondingPoolsWindow: u32 = 10; - pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); - pub static MaxMetadataLen: u32 = 10; - pub static CheckLevel: u8 = 255; -} - -impl pallet_nomination_pools::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type Currency = Balances; - type CurrencyBalance = Balance; - type RewardCounter = FixedU128; - type BalanceToU256 = BalanceToU256; - type U256ToBalance = U256ToBalance; - type StakingInterface = Staking; - type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; - type MaxMetadataLen = MaxMetadataLen; - type MaxUnbonding = ConstU32<8>; - type MaxPointsToBalance = ConstU8<10>; - type PalletId = PoolsPalletId; -} - parameter_types! { pub static SlashPerEra: u32 = 100; } @@ -218,7 +186,6 @@ frame_support::construct_runtime!( Timestamp: pallet_timestamp, Balances: pallet_balances, Staking: pallet_staking, - Pools: pallet_nomination_pools, FastUnstake: fast_unstake, } ); @@ -287,10 +254,6 @@ impl ExtBuilder { let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); - // create one default pool. - let _ = pallet_nomination_pools::GenesisConfig:: { ..Default::default() } - .assimilate_storage(&mut storage); - let validators_range = VALIDATOR_PREFIX..VALIDATOR_PREFIX + VALIDATORS_PER_ERA; let nominators_range = NOMINATOR_PREFIX..NOMINATOR_PREFIX + NOMINATORS_PER_VALIDATOR_PER_ERA; @@ -337,11 +300,6 @@ impl ExtBuilder { // because we read this value as a measure of how many validators we have. pallet_staking::ValidatorCount::::put(VALIDATORS_PER_ERA as u32); - - // make a pool - let amount_to_bond = Pools::depositor_min_bond(); - Balances::make_free_balance_be(&10, amount_to_bond * 5); - assert_ok!(Pools::create(RawOrigin::Signed(10).into(), amount_to_bond, 900, 901, 902)); }); ext } @@ -359,14 +317,12 @@ pub(crate) fn run_to_block(n: u64, on_idle: bool) { while System::block_number() < n { Balances::on_finalize(System::block_number()); Staking::on_finalize(System::block_number()); - Pools::on_finalize(System::block_number()); FastUnstake::on_finalize(System::block_number()); System::set_block_number(System::block_number() + 1); Balances::on_initialize(System::block_number()); Staking::on_initialize(System::block_number()); - Pools::on_initialize(System::block_number()); FastUnstake::on_initialize(System::block_number()); if on_idle { FastUnstake::on_idle(System::block_number(), BlockWeights::get().max_block); diff --git a/frame/fast-unstake/src/tests.rs b/frame/fast-unstake/src/tests.rs index a51c1acdf06eb..5586443ce797c 100644 --- a/frame/fast-unstake/src/tests.rs +++ b/frame/fast-unstake/src/tests.rs @@ -20,20 +20,15 @@ use super::*; use crate::{mock::*, types::*, weights::WeightInfo, Event}; use frame_support::{assert_noop, assert_ok, bounded_vec, pallet_prelude::*, traits::Currency}; -use pallet_nomination_pools::{BondedPools, LastPoolId, RewardPools}; use pallet_staking::{CurrentEra, IndividualExposure, RewardDestination}; -use sp_runtime::{traits::BadOrigin, DispatchError, ModuleError}; +use sp_runtime::traits::BadOrigin; use sp_staking::StakingInterface; #[test] fn test_setup_works() { ExtBuilder::default().build_and_execute(|| { - assert_eq!(BondedPools::::count(), 1); - assert_eq!(RewardPools::::count(), 1); assert_eq!(Staking::bonding_duration(), 3); - let last_pool = LastPoolId::::get(); - assert_eq!(last_pool, 1); }); } @@ -41,7 +36,7 @@ fn test_setup_works() { fn register_works() { ExtBuilder::default().build_and_execute(|| { // Controller account registers for fast unstake. - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); // Ensure stash is in the queue. assert_ne!(Queue::::get(1), None); }); @@ -56,7 +51,7 @@ fn cannot_register_if_not_bonded() { } // Attempt to fast unstake. assert_noop!( - FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1), Some(1_u32)), + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1)), Error::::NotController ); }); @@ -66,10 +61,10 @@ fn cannot_register_if_not_bonded() { fn cannot_register_if_in_queue() { ExtBuilder::default().build_and_execute(|| { // Insert some Queue item - Queue::::insert(1, Some(1_u32)); + Queue::::insert(1, ()); // Cannot re-register, already in queue assert_noop!( - FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32)), + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), Error::::AlreadyQueued ); }); @@ -79,10 +74,10 @@ fn cannot_register_if_in_queue() { fn cannot_register_if_head() { ExtBuilder::default().build_and_execute(|| { // Insert some Head item for stash - Head::::put(UnstakeRequest { stash: 1, checked: bounded_vec![], maybe_pool_id: None }); + Head::::put(UnstakeRequest { stash: 1, checked: bounded_vec![] }); // Controller attempts to regsiter assert_noop!( - FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32)), + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), Error::::AlreadyHead ); }); @@ -95,7 +90,7 @@ fn cannot_register_if_has_unlocking_chunks() { assert_ok!(Staking::unbond(RuntimeOrigin::signed(2), 50_u128)); // Cannot register for fast unstake with unlock chunks active assert_noop!( - FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32)), + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), Error::::NotFullyBonded ); }); @@ -105,7 +100,7 @@ fn cannot_register_if_has_unlocking_chunks() { fn deregister_works() { ExtBuilder::default().build_and_execute(|| { // Controller account registers for fast unstake. - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); // Controller then changes mind and deregisters. assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(2))); // Ensure stash no longer exists in the queue. @@ -117,7 +112,7 @@ fn deregister_works() { fn cannot_deregister_if_not_controller() { ExtBuilder::default().build_and_execute(|| { // Controller account registers for fast unstake. - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); // Stash tries to deregister. assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(1)), Error::::NotController); }); @@ -135,9 +130,9 @@ fn cannot_deregister_if_not_queued() { fn cannot_deregister_already_head() { ExtBuilder::default().build_and_execute(|| { // Controller attempts to register, should fail - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); // Insert some Head item for stash. - Head::::put(UnstakeRequest { stash: 1, checked: bounded_vec![], maybe_pool_id: None }); + Head::::put(UnstakeRequest { stash: 1, checked: bounded_vec![] }); // Controller attempts to deregister assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(2)), Error::::AlreadyHead); }); @@ -169,15 +164,15 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // set up Queue item - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1))); - assert_eq!(Queue::::get(1), Some(Some(1))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(())); // call on_idle with no remaining weight FastUnstake::on_idle(System::block_number(), Weight::from_ref_time(0)); // assert nothing changed in Queue and Head assert_eq!(Head::::get(), None); - assert_eq!(Queue::::get(1), Some(Some(1))); + assert_eq!(Queue::::get(1), Some(())); }); } @@ -189,8 +184,8 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // given - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1))); - assert_eq!(Queue::::get(1), Some(Some(1))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(())); assert_eq!(Queue::::count(), 1); assert_eq!(Head::::get(), None); @@ -209,7 +204,7 @@ mod on_idle { ); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3], maybe_pool_id: Some(1) }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3] }) ); // when: another 1 era. @@ -225,11 +220,7 @@ mod on_idle { ); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) ); // when: then 5 eras, we only need 2 more. @@ -251,11 +242,7 @@ mod on_idle { ); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 1, 0], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) ); // when: not enough weight to unstake: @@ -267,11 +254,7 @@ mod on_idle { assert_eq!(fast_unstake_events_since_last_call(), vec![]); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 1, 0], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) ); // when: enough weight to get over at least one iteration: then we are unblocked and can @@ -287,7 +270,7 @@ mod on_idle { // then we finish the unbonding: assert_eq!( fast_unstake_events_since_last_call(), - vec![Event::Unstaked { stash: 1, maybe_pool_id: Some(1), result: Ok(()) }] + vec![Event::Unstaked { stash: 1, result: Ok(()) }] ); assert_eq!(Head::::get(), None,); @@ -302,11 +285,11 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // given - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), None)); - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4), None)); - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(6), None)); - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(8), None)); - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(10), None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(6))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(8))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(10))); assert_eq!(Queue::::count(), 5); assert_eq!(Head::::get(), None); @@ -317,11 +300,7 @@ mod on_idle { // then assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 1, 0], - maybe_pool_id: None - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) ); assert_eq!(Queue::::count(), 4); @@ -338,11 +317,7 @@ mod on_idle { // then assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 5, - checked: bounded_vec![3, 2, 1, 0], - maybe_pool_id: None - }), + Some(UnstakeRequest { stash: 5, checked: bounded_vec![3, 2, 1, 0] }), ); assert_eq!(Queue::::count(), 3); @@ -350,7 +325,7 @@ mod on_idle { fast_unstake_events_since_last_call(), vec![ Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, - Event::Unstaked { stash: 1, maybe_pool_id: None, result: Ok(()) }, + Event::Unstaked { stash: 1, result: Ok(()) }, Event::Checking { stash: 5, eras: vec![3, 2, 1, 0] } ] ); @@ -364,10 +339,10 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // register multi accounts for fast unstake - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1))); - assert_eq!(Queue::::get(1), Some(Some(1))); - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4), Some(1))); - assert_eq!(Queue::::get(3), Some(Some(1))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(())); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); + assert_eq!(Queue::::get(3), Some(())); // assert 2 queue items are in Queue & None in Head to start with assert_eq!(Queue::::count(), 2); @@ -397,9 +372,9 @@ mod on_idle { fast_unstake_events_since_last_call(), vec![ Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, - Event::Unstaked { stash: 1, maybe_pool_id: Some(1), result: Ok(()) }, + Event::Unstaked { stash: 1, result: Ok(()) }, Event::Checking { stash: 3, eras: vec![3, 2, 1, 0] }, - Event::Unstaked { stash: 3, maybe_pool_id: Some(1), result: Ok(()) }, + Event::Unstaked { stash: 3, result: Ok(()) }, ] ); @@ -409,14 +384,14 @@ mod on_idle { } #[test] - fn successful_unstake_without_pool_join() { + fn successful_unstake() { ExtBuilder::default().build_and_execute(|| { ErasToCheckPerBlock::::put(BondingDuration::get() + 1); CurrentEra::::put(BondingDuration::get()); // register for fast unstake - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), None)); - assert_eq!(Queue::::get(1), Some(None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(())); // process on idle next_block(true); @@ -427,11 +402,7 @@ mod on_idle { // assert head item present assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 1, 0], - maybe_pool_id: None - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) ); next_block(true); @@ -441,55 +412,7 @@ mod on_idle { fast_unstake_events_since_last_call(), vec![ Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, - Event::Unstaked { stash: 1, maybe_pool_id: None, result: Ok(()) } - ] - ); - assert_unstaked(&1); - }); - } - - #[test] - fn successful_unstake_joining_bad_pool() { - ExtBuilder::default().build_and_execute(|| { - ErasToCheckPerBlock::::put(BondingDuration::get() + 1); - CurrentEra::::put(BondingDuration::get()); - - // register for fast unstake - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(0))); - assert_eq!(Queue::::get(1), Some(Some(0))); - - // process on idle - next_block(true); - - // assert queue item has been moved to head - assert_eq!(Queue::::get(1), None); - - // assert head item present - assert_eq!( - Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 1, 0], - maybe_pool_id: Some(0) - }) - ); - - next_block(true); - assert_eq!(Head::::get(), None,); - - assert_eq!( - fast_unstake_events_since_last_call(), - vec![ - Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, - Event::Unstaked { - stash: 1, - maybe_pool_id: Some(0), - result: Err(DispatchError::Module(ModuleError { - index: 4, - error: [0, 0, 0, 0], - message: None - })) - } + Event::Unstaked { stash: 1, result: Ok(()) } ] ); assert_unstaked(&1); @@ -503,8 +426,8 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // register for fast unstake - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); - assert_eq!(Queue::::get(1), Some(Some(1))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(())); // process on idle next_block(true); @@ -515,11 +438,7 @@ mod on_idle { // assert head item present assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 1, 0], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) ); next_block(true); @@ -529,11 +448,10 @@ mod on_idle { fast_unstake_events_since_last_call(), vec![ Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, - Event::Unstaked { stash: 1, maybe_pool_id: Some(1), result: Ok(()) } + Event::Unstaked { stash: 1, result: Ok(()) } ] ); assert_unstaked(&1); - assert!(pallet_nomination_pools::PoolMembers::::contains_key(&1)); }); } @@ -545,8 +463,8 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // register for fast unstake - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); - assert_eq!(Queue::::get(1), Some(Some(1))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(())); // process on idle next_block(true); @@ -557,40 +475,28 @@ mod on_idle { // assert head item present assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3], maybe_pool_id: Some(1) }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3] }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 1], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1] }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 1, 0], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) ); next_block(true); @@ -604,11 +510,10 @@ mod on_idle { Event::Checking { stash: 1, eras: vec![2] }, Event::Checking { stash: 1, eras: vec![1] }, Event::Checking { stash: 1, eras: vec![0] }, - Event::Unstaked { stash: 1, maybe_pool_id: Some(1), result: Ok(()) } + Event::Unstaked { stash: 1, result: Ok(()) } ] ); assert_unstaked(&1); - assert!(pallet_nomination_pools::PoolMembers::::contains_key(&1)); }); } @@ -623,39 +528,31 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // register for fast unstake - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), None)); - assert_eq!(Queue::::get(1), Some(None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(())); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3], maybe_pool_id: None }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3] }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2], maybe_pool_id: None }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 1], - maybe_pool_id: None - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1] }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 1, 0], - maybe_pool_id: None - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) ); // when: a new era happens right before one is free. @@ -670,7 +567,6 @@ mod on_idle { stash: 1, // note era 0 is pruned to keep the vector length sane. checked: bounded_vec![3, 2, 1, 4], - maybe_pool_id: None }) ); @@ -685,7 +581,7 @@ mod on_idle { Event::Checking { stash: 1, eras: vec![1] }, Event::Checking { stash: 1, eras: vec![0] }, Event::Checking { stash: 1, eras: vec![4] }, - Event::Unstaked { stash: 1, maybe_pool_id: None, result: Ok(()) } + Event::Unstaked { stash: 1, result: Ok(()) } ] ); assert_unstaked(&1); @@ -700,23 +596,19 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // register for fast unstake - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), Some(1_u32))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); // process 2 blocks next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3], maybe_pool_id: Some(1) }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3] }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) ); // when @@ -726,21 +618,13 @@ mod on_idle { next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) ); // then we register a new era. @@ -752,22 +636,14 @@ mod on_idle { next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 4], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 4] }) ); // progress to end next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 1, - checked: bounded_vec![3, 2, 4, 1], - maybe_pool_id: Some(1) - }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 4, 1] }) ); // but notice that we don't care about era 0 instead anymore! we're done. @@ -781,12 +657,11 @@ mod on_idle { Event::Checking { stash: 1, eras: vec![2] }, Event::Checking { stash: 1, eras: vec![4] }, Event::Checking { stash: 1, eras: vec![1] }, - Event::Unstaked { stash: 1, maybe_pool_id: Some(1), result: Ok(()) } + Event::Unstaked { stash: 1, result: Ok(()) } ] ); assert_unstaked(&1); - assert!(pallet_nomination_pools::PoolMembers::::contains_key(&1)); }); } @@ -812,26 +687,18 @@ mod on_idle { assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed])); // register the exposed one. - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed), None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed))); // a few blocks later, we realize they are slashed next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: exposed, - checked: bounded_vec![3], - maybe_pool_id: None - }) + Some(UnstakeRequest { stash: exposed, checked: bounded_vec![3] }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: exposed, - checked: bounded_vec![3, 2], - maybe_pool_id: None - }) + Some(UnstakeRequest { stash: exposed, checked: bounded_vec![3, 2] }) ); next_block(true); assert_eq!(Head::::get(), None); @@ -872,17 +739,13 @@ mod on_idle { assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed])); // register the exposed one. - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed), None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed))); // a few blocks later, we realize they are slashed next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: exposed, - checked: bounded_vec![3, 2], - maybe_pool_id: None - }) + Some(UnstakeRequest { stash: exposed, checked: bounded_vec![3, 2] }) ); next_block(true); assert_eq!(Head::::get(), None); @@ -909,10 +772,7 @@ mod on_idle { RuntimeOrigin::signed(VALIDATOR_PREFIX), vec![VALIDATOR_PREFIX] )); - assert_ok!(FastUnstake::register_fast_unstake( - RuntimeOrigin::signed(VALIDATOR_PREFIX), - None - )); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(VALIDATOR_PREFIX))); // but they indeed are exposed! assert!(pallet_staking::ErasStakers::::contains_key( @@ -943,17 +803,13 @@ mod on_idle { assert_ok!(Staking::validate(RuntimeOrigin::signed(42), Default::default())); // let them register: - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(42), None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(42))); // 2 block's enough to unstake them. next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { - stash: 42, - checked: bounded_vec![3, 2, 1, 0], - maybe_pool_id: None - }) + Some(UnstakeRequest { stash: 42, checked: bounded_vec![3, 2, 1, 0] }) ); next_block(true); assert_eq!(Head::::get(), None); @@ -962,7 +818,7 @@ mod on_idle { fast_unstake_events_since_last_call(), vec![ Event::Checking { stash: 42, eras: vec![3, 2, 1, 0] }, - Event::Unstaked { stash: 42, maybe_pool_id: None, result: Ok(()) } + Event::Unstaked { stash: 42, result: Ok(()) } ] ); }); @@ -990,7 +846,7 @@ mod signed_extension { ExtBuilder::default().build_and_execute(|| { // given: stash for 2 is 1. // when - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); // then // stash can't. @@ -1010,7 +866,7 @@ mod signed_extension { ExtBuilder::default().build_and_execute(|| { // given: stash for 2 is 1. // when - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2), None)); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); ErasToCheckPerBlock::::put(1); CurrentEra::::put(BondingDuration::get()); @@ -1018,7 +874,7 @@ mod signed_extension { assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3], maybe_pool_id: None }) + Some(UnstakeRequest { stash: 1, checked: bounded_vec![3] }) ); // then diff --git a/frame/fast-unstake/src/types.rs b/frame/fast-unstake/src/types.rs index ae8702e56a842..e8d538dce4802 100644 --- a/frame/fast-unstake/src/types.rs +++ b/frame/fast-unstake/src/types.rs @@ -23,7 +23,6 @@ use frame_support::{ traits::{Currency, Get, IsSubType}, BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; -use pallet_nomination_pools::PoolId; use scale_info::TypeInfo; use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidityError}; use sp_staking::EraIndex; @@ -42,8 +41,6 @@ pub struct UnstakeRequest, - /// The pool they wish to join, if any. - pub(crate) maybe_pool_id: Option, } #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo, RuntimeDebugNoBound)] From a0ec652e341f694f182a3c5fcc80d4c3fb280003 Mon Sep 17 00:00:00 2001 From: ZhiYong Date: Mon, 26 Sep 2022 15:46:59 +0800 Subject: [PATCH 1203/1472] Remove discarded blocks and states from database by default (#11983) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 1.Add pruning param "canonical" in sc-cli. 2.Make PruningMode's default value to ArchiveCanonical. * Update tests in sc-state-db. * Update tests in sc-state-db. * 1.Add a new value `AllWithNonFinalized` in `enum BlocksPruning` which Corresponds to `blocks_pruning 0` in CLI . 2.Change value `All` to `AllFinalized` in `enum BlocksPruning` and make it to keep full finalized block history. * Make some corresponding adjustments based on the content in the conversation. * Update client/db/src/lib.rs Co-authored-by: Bastian Köcher * Apply suggestions from code review. * 1.Change `blocks_pruning` to be like `state_pruning` . * Fmt and add some doc. * Update client/cli/src/params/pruning_params.rs Co-authored-by: Bastian Köcher * Update client/cli/src/params/pruning_params.rs Co-authored-by: Bastian Köcher * Update doc. * Change `new_test_with_tx_storage` to take `BlocksPruning`. * Fmt Co-authored-by: Bastian Köcher --- bin/node/cli/benches/block_production.rs | 2 +- bin/node/cli/benches/transaction_pool.rs | 2 +- bin/node/testing/src/bench.rs | 2 +- client/cli/src/config.rs | 4 +- client/cli/src/params/pruning_params.rs | 31 +++- client/db/benches/state_access.rs | 2 +- client/db/src/lib.rs | 215 +++++++++++++++++++---- client/service/test/src/client/mod.rs | 4 +- client/service/test/src/lib.rs | 2 +- test-utils/client/src/lib.rs | 5 +- 10 files changed, 211 insertions(+), 58 deletions(-) diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 0a734fa447448..4fcebb123d9e3 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -74,7 +74,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, trie_cache_maximum_size: Some(64 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepAll, chain_spec: spec, wasm_method: WasmExecutionMethod::Compiled { instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index e6084fba8242a..a8839642ddc26 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -68,7 +68,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, trie_cache_maximum_size: Some(64 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepAll, chain_spec: spec, wasm_method: WasmExecutionMethod::Interpreted, // NOTE: we enforce the use of the native runtime to make the errors more debuggable diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 7980cc102fb38..59f1fa94c9b20 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -392,7 +392,7 @@ impl BenchDb { trie_cache_maximum_size: Some(16 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), source: database_type.into_settings(dir.into()), - blocks_pruning: sc_client_db::BlocksPruning::All, + blocks_pruning: sc_client_db::BlocksPruning::KeepAll, }; let task_executor = TaskExecutor::new(); diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index bc5941914de89..fad2ec7bc4a93 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -251,11 +251,11 @@ pub trait CliConfiguration: Sized { /// Get the block pruning mode. /// /// By default this is retrieved from `block_pruning` if it is available. Otherwise its - /// `BlocksPruning::All`. + /// `BlocksPruning::KeepFinalized`. fn blocks_pruning(&self) -> Result { self.pruning_params() .map(|x| x.blocks_pruning()) - .unwrap_or_else(|| Ok(BlocksPruning::All)) + .unwrap_or_else(|| Ok(BlocksPruning::KeepFinalized)) } /// Get the chain ID (string). diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index 34a0982e63d95..b764e4722e94d 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -30,13 +30,16 @@ pub struct PruningParams { /// or for all of the canonical blocks (i.e 'archive-canonical'). #[clap(alias = "pruning", long, value_name = "PRUNING_MODE")] pub state_pruning: Option, - /// Specify the number of finalized blocks to keep in the database. + /// Specify the blocks pruning mode, a number of blocks to keep or 'archive'. /// - /// Default is to keep all blocks. + /// Default is to keep all finalized blocks. + /// otherwise, all blocks can be kept (i.e 'archive'), + /// or for all canonical blocks (i.e 'archive-canonical'), + /// or for the last N blocks (i.e a number). /// /// NOTE: only finalized blocks are subject for removal! #[clap(alias = "keep-blocks", long, value_name = "COUNT")] - pub blocks_pruning: Option, + pub blocks_pruning: Option, } impl PruningParams { @@ -46,9 +49,12 @@ impl PruningParams { .as_ref() .map(|s| match s.as_str() { "archive" => Ok(PruningMode::ArchiveAll), + "archive-canonical" => Ok(PruningMode::ArchiveCanonical), bc => bc .parse() - .map_err(|_| error::Error::Input("Invalid pruning mode specified".to_string())) + .map_err(|_| { + error::Error::Input("Invalid state pruning mode specified".to_string()) + }) .map(PruningMode::blocks_pruning), }) .transpose() @@ -56,9 +62,18 @@ impl PruningParams { /// Get the block pruning value from the parameters pub fn blocks_pruning(&self) -> error::Result { - Ok(match self.blocks_pruning { - Some(n) => BlocksPruning::Some(n), - None => BlocksPruning::All, - }) + match self.blocks_pruning.as_ref() { + Some(bp) => match bp.as_str() { + "archive" => Ok(BlocksPruning::KeepAll), + "archive-canonical" => Ok(BlocksPruning::KeepFinalized), + bc => bc + .parse() + .map_err(|_| { + error::Error::Input("Invalid blocks pruning mode specified".to_string()) + }) + .map(BlocksPruning::Some), + }, + None => Ok(BlocksPruning::KeepFinalized), + } } } diff --git a/client/db/benches/state_access.rs b/client/db/benches/state_access.rs index 78aed7858e342..714dda82d61b7 100644 --- a/client/db/benches/state_access.rs +++ b/client/db/benches/state_access.rs @@ -122,7 +122,7 @@ fn create_backend(config: BenchmarkConfig, temp_dir: &TempDir) -> Backend trie_cache_maximum_size, state_pruning: Some(PruningMode::ArchiveAll), source: DatabaseSource::ParityDb { path }, - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepAll, }; Backend::new(settings, 100).expect("Creates backend") diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 79ef7e9b6625d..32c4c9ef85ed9 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -320,10 +320,12 @@ pub struct DatabaseSettings { } /// Block pruning settings. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum BlocksPruning { - /// Keep full block history. - All, + /// Keep full block history, of every block that was ever imported. + KeepAll, + /// Keep full finalized block history. + KeepFinalized, /// Keep N recent finalized blocks. Some(u32), } @@ -1061,19 +1063,27 @@ impl Backend { /// Create new memory-backed client backend for tests. #[cfg(any(test, feature = "test-helpers"))] pub fn new_test(blocks_pruning: u32, canonicalization_delay: u64) -> Self { - Self::new_test_with_tx_storage(blocks_pruning, canonicalization_delay) + Self::new_test_with_tx_storage(BlocksPruning::Some(blocks_pruning), canonicalization_delay) } /// Create new memory-backed client backend for tests. #[cfg(any(test, feature = "test-helpers"))] - pub fn new_test_with_tx_storage(blocks_pruning: u32, canonicalization_delay: u64) -> Self { + pub fn new_test_with_tx_storage( + blocks_pruning: BlocksPruning, + canonicalization_delay: u64, + ) -> Self { let db = kvdb_memorydb::create(crate::utils::NUM_COLUMNS); let db = sp_database::as_database(db); + let state_pruning = match blocks_pruning { + BlocksPruning::KeepAll => PruningMode::ArchiveAll, + BlocksPruning::KeepFinalized => PruningMode::ArchiveCanonical, + BlocksPruning::Some(n) => PruningMode::blocks_pruning(n), + }; let db_setting = DatabaseSettings { trie_cache_maximum_size: Some(16 * 1024 * 1024), - state_pruning: Some(PruningMode::blocks_pruning(blocks_pruning)), + state_pruning: Some(state_pruning), source: DatabaseSource::Custom { db, require_create_flag: true }, - blocks_pruning: BlocksPruning::Some(blocks_pruning), + blocks_pruning, }; Self::new(db_setting, canonicalization_delay).expect("failed to create test-db") @@ -1707,32 +1717,47 @@ impl Backend { finalized: NumberFor, displaced: &FinalizationOutcome>, ) -> ClientResult<()> { - if let BlocksPruning::Some(blocks_pruning) = self.blocks_pruning { - // Always keep the last finalized block - let keep = std::cmp::max(blocks_pruning, 1); - if finalized >= keep.into() { - let number = finalized.saturating_sub(keep.into()); - self.prune_block(transaction, BlockId::::number(number))?; - } + match self.blocks_pruning { + BlocksPruning::KeepAll => {}, + BlocksPruning::Some(blocks_pruning) => { + // Always keep the last finalized block + let keep = std::cmp::max(blocks_pruning, 1); + if finalized >= keep.into() { + let number = finalized.saturating_sub(keep.into()); + self.prune_block(transaction, BlockId::::number(number))?; + } + self.prune_displaced_branches(transaction, finalized, displaced)?; + }, + BlocksPruning::KeepFinalized => { + self.prune_displaced_branches(transaction, finalized, displaced)?; + }, + } + Ok(()) + } - // Also discard all blocks from displaced branches - for h in displaced.leaves() { - let mut number = finalized; - let mut hash = *h; - // Follow displaced chains back until we reach a finalized block. - // Since leaves are discarded due to finality, they can't have parents - // that are canonical, but not yet finalized. So we stop deleting as soon as - // we reach canonical chain. - while self.blockchain.hash(number)? != Some(hash) { - let id = BlockId::::hash(hash); - match self.blockchain.header(id)? { - Some(header) => { - self.prune_block(transaction, id)?; - number = header.number().saturating_sub(One::one()); - hash = *header.parent_hash(); - }, - None => break, - } + fn prune_displaced_branches( + &self, + transaction: &mut Transaction, + finalized: NumberFor, + displaced: &FinalizationOutcome>, + ) -> ClientResult<()> { + // Discard all blocks from displaced branches + for h in displaced.leaves() { + let mut number = finalized; + let mut hash = *h; + // Follow displaced chains back until we reach a finalized block. + // Since leaves are discarded due to finality, they can't have parents + // that are canonical, but not yet finalized. So we stop deleting as soon as + // we reach canonical chain. + while self.blockchain.hash(number)? != Some(hash) { + let id = BlockId::::hash(hash); + match self.blockchain.header(id)? { + Some(header) => { + self.prune_block(transaction, id)?; + number = header.number().saturating_sub(One::one()); + hash = *header.parent_hash(); + }, + None => break, } } } @@ -1752,6 +1777,13 @@ impl Backend { columns::BODY, id, )?; + utils::remove_from_db( + transaction, + &*self.storage.db, + columns::KEY_LOOKUP, + columns::JUSTIFICATIONS, + id, + )?; if let Some(index) = read_db(&*self.storage.db, columns::KEY_LOOKUP, columns::BODY_INDEX, id)? { @@ -2506,7 +2538,7 @@ pub(crate) mod tests { trie_cache_maximum_size: Some(16 * 1024 * 1024), state_pruning: Some(PruningMode::blocks_pruning(1)), source: DatabaseSource::Custom { db: backing, require_create_flag: false }, - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepFinalized, }, 0, ) @@ -3176,7 +3208,7 @@ pub(crate) mod tests { #[test] fn prune_blocks_on_finalize() { - let backend = Backend::::new_test_with_tx_storage(2, 0); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 0); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); for i in 0..5 { @@ -3210,9 +3242,114 @@ pub(crate) mod tests { assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); } + #[test] + fn prune_blocks_on_finalize_in_keep_all() { + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::KeepAll, 0); + let mut blocks = Vec::new(); + let mut prev_hash = Default::default(); + for i in 0..5 { + let hash = insert_block( + &backend, + i, + prev_hash, + None, + Default::default(), + vec![i.into()], + None, + ) + .unwrap(); + blocks.push(hash); + prev_hash = hash; + } + + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + for i in 1..3 { + op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); + } + backend.commit_operation(op).unwrap(); + + let bc = backend.blockchain(); + assert_eq!(Some(vec![0.into()]), bc.body(BlockId::hash(blocks[0])).unwrap()); + assert_eq!(Some(vec![1.into()]), bc.body(BlockId::hash(blocks[1])).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(blocks[2])).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); + } + + #[test] + fn prune_blocks_on_finalize_with_fork_in_keep_all() { + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::KeepAll, 10); + let mut blocks = Vec::new(); + let mut prev_hash = Default::default(); + for i in 0..5 { + let hash = insert_block( + &backend, + i, + prev_hash, + None, + Default::default(), + vec![i.into()], + None, + ) + .unwrap(); + blocks.push(hash); + prev_hash = hash; + } + + // insert a fork at block 2 + let fork_hash_root = insert_block( + &backend, + 2, + blocks[1], + None, + sp_core::H256::random(), + vec![2.into()], + None, + ) + .unwrap(); + insert_block( + &backend, + 3, + fork_hash_root, + None, + H256::random(), + vec![3.into(), 11.into()], + None, + ) + .unwrap(); + + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + op.mark_head(BlockId::Hash(blocks[4])).unwrap(); + backend.commit_operation(op).unwrap(); + + let bc = backend.blockchain(); + assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(fork_hash_root)).unwrap()); + + for i in 1..5 { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Hash(blocks[i])).unwrap(); + op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); + backend.commit_operation(op).unwrap(); + } + + assert_eq!(Some(vec![0.into()]), bc.body(BlockId::hash(blocks[0])).unwrap()); + assert_eq!(Some(vec![1.into()]), bc.body(BlockId::hash(blocks[1])).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(blocks[2])).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); + + assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(fork_hash_root)).unwrap()); + assert_eq!(bc.info().best_number, 4); + for i in 0..5 { + assert!(bc.hash(i).unwrap().is_some()); + } + } + #[test] fn prune_blocks_on_finalize_with_fork() { - let backend = Backend::::new_test_with_tx_storage(2, 10); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); for i in 0..5 { @@ -3273,7 +3410,7 @@ pub(crate) mod tests { #[test] fn indexed_data_block_body() { - let backend = Backend::::new_test_with_tx_storage(1, 10); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); let x0 = ExtrinsicWrapper::from(0u64).encode(); let x1 = ExtrinsicWrapper::from(1u64).encode(); @@ -3315,7 +3452,7 @@ pub(crate) mod tests { #[test] fn index_invalid_size() { - let backend = Backend::::new_test_with_tx_storage(1, 10); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); let x0 = ExtrinsicWrapper::from(0u64).encode(); let x1 = ExtrinsicWrapper::from(1u64).encode(); @@ -3350,7 +3487,7 @@ pub(crate) mod tests { #[test] fn renew_transaction_storage() { - let backend = Backend::::new_test_with_tx_storage(2, 10); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); let x1 = ExtrinsicWrapper::from(0u64).encode(); @@ -3397,7 +3534,7 @@ pub(crate) mod tests { #[test] fn remove_leaf_block_works() { - let backend = Backend::::new_test_with_tx_storage(2, 10); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); for i in 0..2 { diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 2ab1415f8ca31..e0f47110d9046 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1200,7 +1200,7 @@ fn doesnt_import_blocks_that_revert_finality() { DatabaseSettings { trie_cache_maximum_size: Some(1 << 20), state_pruning: Some(PruningMode::ArchiveAll), - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepAll, source: DatabaseSource::RocksDb { path: tmp.path().into(), cache_size: 1024 }, }, u64::MAX, @@ -1426,7 +1426,7 @@ fn returns_status_for_pruned_blocks() { DatabaseSettings { trie_cache_maximum_size: Some(1 << 20), state_pruning: Some(PruningMode::blocks_pruning(1)), - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepFinalized, source: DatabaseSource::RocksDb { path: tmp.path().into(), cache_size: 1024 }, }, u64::MAX, diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 11c1cbaf7afb1..23245d46cba10 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -237,7 +237,7 @@ fn node_config< database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, trie_cache_maximum_size: Some(16 * 1024 * 1024), state_pruning: Default::default(), - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepFinalized, chain_spec: Box::new((*spec).clone()), wasm_method: sc_service::config::WasmExecutionMethod::Interpreted, wasm_runtime_overrides: Default::default(), diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index be4549c9957c0..d3e71f0ad28d6 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -26,7 +26,7 @@ pub use sc_client_api::{ execution_extensions::{ExecutionExtensions, ExecutionStrategies}, BadBlocks, ForkBlocks, }; -pub use sc_client_db::{self, Backend}; +pub use sc_client_db::{self, Backend, BlocksPruning}; pub use sc_executor::{self, NativeElseWasmExecutor, WasmExecutionMethod}; pub use sc_service::{client, RpcHandlers}; pub use sp_consensus; @@ -102,7 +102,8 @@ impl /// Create new `TestClientBuilder` with default backend and storage chain mode pub fn with_tx_storage(blocks_pruning: u32) -> Self { - let backend = Arc::new(Backend::new_test_with_tx_storage(blocks_pruning, 0)); + let backend = + Arc::new(Backend::new_test_with_tx_storage(BlocksPruning::Some(blocks_pruning), 0)); Self::with_backend(backend) } } From 0dbeaa0e98e78a848046a815f979bfce67f98c6d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 26 Sep 2022 12:08:34 +0100 Subject: [PATCH 1204/1472] re-export weight file for fast-unstsake pallet (#12352) --- frame/fast-unstake/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 5acc9940debf1..9bfb29f8457fa 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -90,7 +90,7 @@ pub mod pallet { }; use sp_staking::EraIndex; use sp_std::{prelude::*, vec::Vec}; - use weights::WeightInfo; + pub use weights::WeightInfo; #[derive(scale_info::TypeInfo, codec::Encode, codec::Decode, codec::MaxEncodedLen)] #[codec(mel_bound(T: Config))] From f360c87073cb5f59b7b55cfbfef5d91a40d1a217 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Mon, 26 Sep 2022 15:10:09 +0300 Subject: [PATCH 1205/1472] Move transactions protocol to its own crate (#12264) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move transaction protocol to its own crate * Update Cargo.lock * Fix binaries * Update client/network/transactions/src/lib.rs Co-authored-by: Dmitry Markin * Update client/service/src/builder.rs Co-authored-by: Bastian Köcher * Apply review comments * Revert one change and apply cargo-fmt * Remove Transaction from Message * Add array-bytes * trigger CI * Add comment about codec index Co-authored-by: Dmitry Markin Co-authored-by: Bastian Köcher --- Cargo.lock | 24 ++ bin/node-template/node/src/service.rs | 3 +- bin/node/cli/src/service.rs | 3 +- client/beefy/Cargo.toml | 1 + client/beefy/src/lib.rs | 4 +- client/cli/Cargo.toml | 1 + client/cli/src/params/network_params.rs | 5 +- client/finality-grandpa/src/lib.rs | 8 +- client/network/common/Cargo.toml | 3 + client/network/common/src/config.rs | 128 +++++++++++ client/network/{ => common}/src/error.rs | 3 +- client/network/common/src/lib.rs | 8 + client/network/common/src/service.rs | 29 --- client/network/{ => common}/src/utils.rs | 0 client/network/src/config.rs | 209 +----------------- client/network/src/discovery.rs | 3 +- client/network/src/lib.rs | 13 +- client/network/src/peer_info.rs | 2 +- client/network/src/protocol.rs | 13 +- client/network/src/protocol/message.rs | 10 +- client/network/src/service.rs | 77 ++----- client/network/src/service/tests.rs | 56 ++--- client/network/test/src/lib.rs | 14 +- client/network/transactions/Cargo.toml | 28 +++ client/network/transactions/src/config.rs | 98 ++++++++ .../src/lib.rs} | 108 ++++----- client/service/Cargo.toml | 1 + client/service/src/builder.rs | 62 ++++-- client/service/src/config.rs | 6 +- client/service/src/error.rs | 3 +- client/service/src/lib.rs | 7 +- client/service/test/src/lib.rs | 7 +- 32 files changed, 466 insertions(+), 471 deletions(-) rename client/network/{ => common}/src/error.rs (96%) rename client/network/{ => common}/src/utils.rs (100%) create mode 100644 client/network/transactions/Cargo.toml create mode 100644 client/network/transactions/src/config.rs rename client/network/{src/transactions.rs => transactions/src/lib.rs} (84%) diff --git a/Cargo.lock b/Cargo.lock index 6ea79a120361e..a9a0eef551179 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -468,6 +468,7 @@ dependencies = [ "sc-finality-grandpa", "sc-keystore", "sc-network", + "sc-network-common", "sc-network-gossip", "sc-network-test", "sc-utils", @@ -7934,6 +7935,7 @@ dependencies = [ "sc-client-db", "sc-keystore", "sc-network", + "sc-network-common", "sc-service", "sc-telemetry", "sc-tracing", @@ -8547,7 +8549,9 @@ dependencies = [ "bitflags", "bytes", "futures", + "futures-timer", "libp2p", + "linked_hash_set", "parity-scale-codec", "prost-build 0.10.4", "sc-consensus", @@ -8558,6 +8562,7 @@ dependencies = [ "sp-consensus", "sp-finality-grandpa", "sp-runtime", + "substrate-prometheus-endpoint", "thiserror", ] @@ -8663,6 +8668,24 @@ dependencies = [ "substrate-test-runtime-client", ] +[[package]] +name = "sc-network-transactions" +version = "0.10.0-dev" +dependencies = [ + "array-bytes", + "futures", + "hex", + "libp2p", + "log", + "parity-scale-codec", + "pin-project", + "sc-network-common", + "sc-peerset", + "sp-consensus", + "sp-runtime", + "substrate-prometheus-endpoint", +] + [[package]] name = "sc-offchain" version = "4.0.0-dev" @@ -8851,6 +8874,7 @@ dependencies = [ "sc-network-common", "sc-network-light", "sc-network-sync", + "sc-network-transactions", "sc-offchain", "sc-rpc", "sc-rpc-server", diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 6ec9a33749a69..96de6e17f3bfd 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -191,7 +191,7 @@ pub fn new_full(mut config: Configuration) -> Result Vec::default(), )); - let (network, system_rpc_tx, network_starter) = + let (network, system_rpc_tx, tx_handler_controller, network_starter) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, client: client.clone(), @@ -238,6 +238,7 @@ pub fn new_full(mut config: Configuration) -> Result rpc_builder: rpc_extensions_builder, backend, system_rpc_tx, + tx_handler_controller, config, telemetry: telemetry.as_mut(), })?; diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index a3098eac6402f..6c29f0c08ee13 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -354,7 +354,7 @@ pub fn new_full_base( Vec::default(), )); - let (network, system_rpc_tx, network_starter) = + let (network, system_rpc_tx, tx_handler_controller, network_starter) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, client: client.clone(), @@ -392,6 +392,7 @@ pub fn new_full_base( transaction_pool: transaction_pool.clone(), task_manager: &mut task_manager, system_rpc_tx, + tx_handler_controller, telemetry: telemetry.as_mut(), })?; diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 47a3be859cbbb..a125d4c8d4f07 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -27,6 +27,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../../client/finality-grandpa" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 41eeec43d64bd..ad527b2929585 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -83,8 +83,8 @@ pub(crate) mod beefy_protocol_name { /// For standard protocol name see [`beefy_protocol_name::standard_name`]. pub fn beefy_peers_set_config( protocol_name: ProtocolName, -) -> sc_network::config::NonDefaultSetConfig { - let mut cfg = sc_network::config::NonDefaultSetConfig::new(protocol_name, 1024 * 1024); +) -> sc_network_common::config::NonDefaultSetConfig { + let mut cfg = sc_network_common::config::NonDefaultSetConfig::new(protocol_name, 1024 * 1024); cfg.allow_non_reserved(25, 25); cfg.add_fallback_names(beefy_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect()); diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index e5cd6167596c0..37a8fd2e0b64d 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -34,6 +34,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../db" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../service" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 74c2db92c3215..0450b5f0e2566 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -19,11 +19,10 @@ use crate::{arg_enums::SyncMode, params::node_key_params::NodeKeyParams}; use clap::Args; use sc_network::{ - config::{ - NetworkConfiguration, NodeKeyConfig, NonReservedPeerMode, SetConfig, TransportConfig, - }, + config::{NetworkConfiguration, NodeKeyConfig}, multiaddr::Protocol, }; +use sc_network_common::config::{NonReservedPeerMode, SetConfig, TransportConfig}; use sc_service::{ config::{Multiaddr, MultiaddrWithPeerId}, ChainSpec, ChainType, diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 7e47b70bd6b98..d5c05fea78aa2 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -688,18 +688,18 @@ pub struct GrandpaParams { /// For standard protocol name see [`crate::protocol_standard_name`]. pub fn grandpa_peers_set_config( protocol_name: ProtocolName, -) -> sc_network::config::NonDefaultSetConfig { +) -> sc_network_common::config::NonDefaultSetConfig { use communication::grandpa_protocol_name; - sc_network::config::NonDefaultSetConfig { + sc_network_common::config::NonDefaultSetConfig { notifications_protocol: protocol_name, fallback_names: grandpa_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect(), // Notifications reach ~256kiB in size at the time of writing on Kusama and Polkadot. max_notification_size: 1024 * 1024, - set_config: sc_network::config::SetConfig { + set_config: sc_network_common::config::SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), - non_reserved_mode: sc_network::config::NonReservedPeerMode::Deny, + non_reserved_mode: sc_network_common::config::NonReservedPeerMode::Deny, }, } } diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 47d43e8b4b03f..1ee7b15538366 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -24,7 +24,10 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" +futures-timer = "3.0.2" libp2p = "0.46.1" +linked_hash_set = "0.1.3" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } smallvec = "1.8.0" sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } diff --git a/client/network/common/src/config.rs b/client/network/common/src/config.rs index 8b7e045780d7d..fb23cd0174922 100644 --- a/client/network/common/src/config.rs +++ b/client/network/common/src/config.rs @@ -18,6 +18,8 @@ //! Configuration of the networking layer. +use crate::protocol; + use libp2p::{multiaddr, Multiaddr, PeerId}; use std::{fmt, str, str::FromStr}; @@ -171,3 +173,129 @@ impl From for ParseErr { Self::MultiaddrParse(err) } } + +/// Configuration for a set of nodes. +#[derive(Clone, Debug)] +pub struct SetConfig { + /// Maximum allowed number of incoming substreams related to this set. + pub in_peers: u32, + /// Number of outgoing substreams related to this set that we're trying to maintain. + pub out_peers: u32, + /// List of reserved node addresses. + pub reserved_nodes: Vec, + /// Whether nodes that aren't in [`SetConfig::reserved_nodes`] are accepted or automatically + /// refused. + pub non_reserved_mode: NonReservedPeerMode, +} + +impl Default for SetConfig { + fn default() -> Self { + Self { + in_peers: 25, + out_peers: 75, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Accept, + } + } +} + +/// Extension to [`SetConfig`] for sets that aren't the default set. +/// +/// > **Note**: As new fields might be added in the future, please consider using the `new` method +/// > and modifiers instead of creating this struct manually. +#[derive(Clone, Debug)] +pub struct NonDefaultSetConfig { + /// Name of the notifications protocols of this set. A substream on this set will be + /// considered established once this protocol is open. + /// + /// > **Note**: This field isn't present for the default set, as this is handled internally + /// > by the networking code. + pub notifications_protocol: protocol::ProtocolName, + /// If the remote reports that it doesn't support the protocol indicated in the + /// `notifications_protocol` field, then each of these fallback names will be tried one by + /// one. + /// + /// If a fallback is used, it will be reported in + /// `sc_network::protocol::event::Event::NotificationStreamOpened::negotiated_fallback` + pub fallback_names: Vec, + /// Maximum allowed size of single notifications. + pub max_notification_size: u64, + /// Base configuration. + pub set_config: SetConfig, +} + +impl NonDefaultSetConfig { + /// Creates a new [`NonDefaultSetConfig`]. Zero slots and accepts only reserved nodes. + pub fn new(notifications_protocol: protocol::ProtocolName, max_notification_size: u64) -> Self { + Self { + notifications_protocol, + max_notification_size, + fallback_names: Vec::new(), + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + } + } + + /// Modifies the configuration to allow non-reserved nodes. + pub fn allow_non_reserved(&mut self, in_peers: u32, out_peers: u32) { + self.set_config.in_peers = in_peers; + self.set_config.out_peers = out_peers; + self.set_config.non_reserved_mode = NonReservedPeerMode::Accept; + } + + /// Add a node to the list of reserved nodes. + pub fn add_reserved(&mut self, peer: MultiaddrWithPeerId) { + self.set_config.reserved_nodes.push(peer); + } + + /// Add a list of protocol names used for backward compatibility. + /// + /// See the explanations in [`NonDefaultSetConfig::fallback_names`]. + pub fn add_fallback_names(&mut self, fallback_names: Vec) { + self.fallback_names.extend(fallback_names); + } +} + +/// Configuration for the transport layer. +#[derive(Clone, Debug)] +pub enum TransportConfig { + /// Normal transport mode. + Normal { + /// If true, the network will use mDNS to discover other libp2p nodes on the local network + /// and connect to them if they support the same chain. + enable_mdns: bool, + + /// If true, allow connecting to private IPv4 addresses (as defined in + /// [RFC1918](https://tools.ietf.org/html/rfc1918)). Irrelevant for addresses that have + /// been passed in `::sc_network::config::NetworkConfiguration::boot_nodes`. + allow_private_ipv4: bool, + }, + + /// Only allow connections within the same process. + /// Only addresses of the form `/memory/...` will be supported. + MemoryOnly, +} + +/// The policy for connections to non-reserved peers. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum NonReservedPeerMode { + /// Accept them. This is the default. + Accept, + /// Deny them. + Deny, +} + +impl NonReservedPeerMode { + /// Attempt to parse the peer mode from a string. + pub fn parse(s: &str) -> Option { + match s { + "accept" => Some(Self::Accept), + "deny" => Some(Self::Deny), + _ => None, + } + } +} diff --git a/client/network/src/error.rs b/client/network/common/src/error.rs similarity index 96% rename from client/network/src/error.rs rename to client/network/common/src/error.rs index b4287ffbd55db..4326b1af52836 100644 --- a/client/network/src/error.rs +++ b/client/network/common/src/error.rs @@ -18,9 +18,8 @@ //! Substrate network possible errors. -use crate::config::TransportConfig; +use crate::{config::TransportConfig, protocol::ProtocolName}; use libp2p::{Multiaddr, PeerId}; -use sc_network_common::protocol::ProtocolName; use std::fmt; diff --git a/client/network/common/src/lib.rs b/client/network/common/src/lib.rs index 3a30d24900199..36e67f11e5cff 100644 --- a/client/network/common/src/lib.rs +++ b/client/network/common/src/lib.rs @@ -19,8 +19,16 @@ //! Common data structures of the networking layer. pub mod config; +pub mod error; pub mod message; pub mod protocol; pub mod request_responses; pub mod service; pub mod sync; +pub mod utils; + +/// Minimum Requirements for a Hash within Networking +pub trait ExHashT: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static {} + +impl ExHashT for T where T: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static +{} diff --git a/client/network/common/src/service.rs b/client/network/common/src/service.rs index 88583832e4c38..aa4967ba51700 100644 --- a/client/network/common/src/service.rs +++ b/client/network/common/src/service.rs @@ -604,35 +604,6 @@ where } } -/// Provides ability to propagate transactions over the network. -pub trait NetworkTransaction { - /// You may call this when new transactions are imported by the transaction pool. - /// - /// All transactions will be fetched from the `TransactionPool` that was passed at - /// initialization as part of the configuration and propagated to peers. - fn trigger_repropagate(&self); - - /// You must call when new transaction is imported by the transaction pool. - /// - /// This transaction will be fetched from the `TransactionPool` that was passed at - /// initialization as part of the configuration and propagated to peers. - fn propagate_transaction(&self, hash: H); -} - -impl NetworkTransaction for Arc -where - T: ?Sized, - T: NetworkTransaction, -{ - fn trigger_repropagate(&self) { - T::trigger_repropagate(self) - } - - fn propagate_transaction(&self, hash: H) { - T::propagate_transaction(self, hash) - } -} - /// Provides ability to announce blocks to the network. pub trait NetworkBlock { /// Make sure an important block is propagated to peers. diff --git a/client/network/src/utils.rs b/client/network/common/src/utils.rs similarity index 100% rename from client/network/src/utils.rs rename to client/network/common/src/utils.rs diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 202a628884d79..b2adfa81d065b 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -27,24 +27,24 @@ pub use sc_network_common::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, sync::warp::WarpSyncProvider, + ExHashT, }; pub use libp2p::{build_multiaddr, core::PublicKey, identity}; -use crate::ExHashT; - use core::{fmt, iter}; -use futures::future; use libp2p::{ identity::{ed25519, Keypair}, multiaddr, Multiaddr, }; use prometheus_endpoint::Registry; use sc_consensus::ImportQueue; -use sc_network_common::{config::MultiaddrWithPeerId, protocol::ProtocolName, sync::ChainSync}; +use sc_network_common::{ + config::{MultiaddrWithPeerId, NonDefaultSetConfig, SetConfig, TransportConfig}, + sync::ChainSync, +}; use sp_runtime::traits::Block as BlockT; use std::{ - collections::HashMap, error::Error, fs, future::Future, @@ -52,16 +52,14 @@ use std::{ net::Ipv4Addr, path::{Path, PathBuf}, pin::Pin, - str, sync::Arc, }; use zeroize::Zeroize; /// Network initialization parameters. -pub struct Params +pub struct Params where B: BlockT + 'static, - H: ExHashT, { /// Assigned role for our node (full, light, ...). pub role: Role, @@ -70,21 +68,12 @@ where /// default. pub executor: Option + Send>>) + Send>>, - /// How to spawn the background task dedicated to the transactions handler. - pub transactions_handler_executor: Box + Send>>) + Send>, - /// Network layer configuration. pub network_config: NetworkConfiguration, /// Client that contains the blockchain. pub chain: Arc, - /// Pool of transactions. - /// - /// The network worker will fetch transactions from this object in order to propagate them on - /// the network. - pub transaction_pool: Arc>, - /// Legacy name of the protocol to use on the wire. Should be different for each chain. pub protocol_id: ProtocolId, @@ -166,66 +155,6 @@ impl fmt::Display for Role { } } -/// Result of the transaction import. -#[derive(Clone, Copy, Debug)] -pub enum TransactionImport { - /// Transaction is good but already known by the transaction pool. - KnownGood, - /// Transaction is good and not yet known. - NewGood, - /// Transaction is invalid. - Bad, - /// Transaction import was not performed. - None, -} - -/// Future resolving to transaction import result. -pub type TransactionImportFuture = Pin + Send>>; - -/// Transaction pool interface -pub trait TransactionPool: Send + Sync { - /// Get transactions from the pool that are ready to be propagated. - fn transactions(&self) -> Vec<(H, B::Extrinsic)>; - /// Get hash of transaction. - fn hash_of(&self, transaction: &B::Extrinsic) -> H; - /// Import a transaction into the pool. - /// - /// This will return future. - fn import(&self, transaction: B::Extrinsic) -> TransactionImportFuture; - /// Notify the pool about transactions broadcast. - fn on_broadcasted(&self, propagations: HashMap>); - /// Get transaction by hash. - fn transaction(&self, hash: &H) -> Option; -} - -/// Dummy implementation of the [`TransactionPool`] trait for a transaction pool that is always -/// empty and discards all incoming transactions. -/// -/// Requires the "hash" type to implement the `Default` trait. -/// -/// Useful for testing purposes. -pub struct EmptyTransactionPool; - -impl TransactionPool for EmptyTransactionPool { - fn transactions(&self) -> Vec<(H, B::Extrinsic)> { - Vec::new() - } - - fn hash_of(&self, _transaction: &B::Extrinsic) -> H { - Default::default() - } - - fn import(&self, _transaction: B::Extrinsic) -> TransactionImportFuture { - Box::pin(future::ready(TransactionImport::KnownGood)) - } - - fn on_broadcasted(&self, _: HashMap>) {} - - fn transaction(&self, _h: &H) -> Option { - None - } -} - /// Sync operation mode. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum SyncMode { @@ -394,132 +323,6 @@ impl NetworkConfiguration { } } -/// Configuration for a set of nodes. -#[derive(Clone, Debug)] -pub struct SetConfig { - /// Maximum allowed number of incoming substreams related to this set. - pub in_peers: u32, - /// Number of outgoing substreams related to this set that we're trying to maintain. - pub out_peers: u32, - /// List of reserved node addresses. - pub reserved_nodes: Vec, - /// Whether nodes that aren't in [`SetConfig::reserved_nodes`] are accepted or automatically - /// refused. - pub non_reserved_mode: NonReservedPeerMode, -} - -impl Default for SetConfig { - fn default() -> Self { - Self { - in_peers: 25, - out_peers: 75, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Accept, - } - } -} - -/// Extension to [`SetConfig`] for sets that aren't the default set. -/// -/// > **Note**: As new fields might be added in the future, please consider using the `new` method -/// > and modifiers instead of creating this struct manually. -#[derive(Clone, Debug)] -pub struct NonDefaultSetConfig { - /// Name of the notifications protocols of this set. A substream on this set will be - /// considered established once this protocol is open. - /// - /// > **Note**: This field isn't present for the default set, as this is handled internally - /// > by the networking code. - pub notifications_protocol: ProtocolName, - /// If the remote reports that it doesn't support the protocol indicated in the - /// `notifications_protocol` field, then each of these fallback names will be tried one by - /// one. - /// - /// If a fallback is used, it will be reported in - /// [`crate::Event::NotificationStreamOpened::negotiated_fallback`]. - pub fallback_names: Vec, - /// Maximum allowed size of single notifications. - pub max_notification_size: u64, - /// Base configuration. - pub set_config: SetConfig, -} - -impl NonDefaultSetConfig { - /// Creates a new [`NonDefaultSetConfig`]. Zero slots and accepts only reserved nodes. - pub fn new(notifications_protocol: ProtocolName, max_notification_size: u64) -> Self { - Self { - notifications_protocol, - max_notification_size, - fallback_names: Vec::new(), - set_config: SetConfig { - in_peers: 0, - out_peers: 0, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Deny, - }, - } - } - - /// Modifies the configuration to allow non-reserved nodes. - pub fn allow_non_reserved(&mut self, in_peers: u32, out_peers: u32) { - self.set_config.in_peers = in_peers; - self.set_config.out_peers = out_peers; - self.set_config.non_reserved_mode = NonReservedPeerMode::Accept; - } - - /// Add a node to the list of reserved nodes. - pub fn add_reserved(&mut self, peer: MultiaddrWithPeerId) { - self.set_config.reserved_nodes.push(peer); - } - - /// Add a list of protocol names used for backward compatibility. - /// - /// See the explanations in [`NonDefaultSetConfig::fallback_names`]. - pub fn add_fallback_names(&mut self, fallback_names: Vec) { - self.fallback_names.extend(fallback_names); - } -} - -/// Configuration for the transport layer. -#[derive(Clone, Debug)] -pub enum TransportConfig { - /// Normal transport mode. - Normal { - /// If true, the network will use mDNS to discover other libp2p nodes on the local network - /// and connect to them if they support the same chain. - enable_mdns: bool, - - /// If true, allow connecting to private IPv4 addresses (as defined in - /// [RFC1918](https://tools.ietf.org/html/rfc1918)). Irrelevant for addresses that have - /// been passed in [`NetworkConfiguration::boot_nodes`]. - allow_private_ipv4: bool, - }, - - /// Only allow connections within the same process. - /// Only addresses of the form `/memory/...` will be supported. - MemoryOnly, -} - -/// The policy for connections to non-reserved peers. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum NonReservedPeerMode { - /// Accept them. This is the default. - Accept, - /// Deny them. - Deny, -} - -impl NonReservedPeerMode { - /// Attempt to parse the peer mode from a string. - pub fn parse(s: &str) -> Option { - match s { - "accept" => Some(Self::Accept), - "deny" => Some(Self::Deny), - _ => None, - } - } -} - /// The configuration of a node's secret key, describing the type of key /// and how it is obtained. A node's identity keypair is the result of /// the evaluation of the node key configuration. diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index ab93662968dc2..8422e34485125 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -46,7 +46,6 @@ //! active mechanism that asks nodes for the addresses they are listening on. Whenever we learn //! of a node's address, you must call `add_self_reported_address`. -use crate::utils::LruHashSet; use futures::prelude::*; use futures_timer::Delay; use ip_network::IpNetwork; @@ -72,7 +71,7 @@ use libp2p::{ }, }; use log::{debug, error, info, trace, warn}; -use sc_network_common::config::ProtocolId; +use sc_network_common::{config::ProtocolId, utils::LruHashSet}; use sp_core::hexdisplay::HexDisplay; use std::{ cmp, diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 320104d0f9554..d17f47328b804 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -251,12 +251,9 @@ mod protocol; mod request_responses; mod service; mod transport; -mod utils; pub mod config; -pub mod error; pub mod network_state; -pub mod transactions; #[doc(inline)] pub use libp2p::{multiaddr, Multiaddr, PeerId}; @@ -269,8 +266,8 @@ pub use sc_network_common::{ request_responses::{IfDisconnected, RequestFailure}, service::{ KademliaKey, NetworkBlock, NetworkDHTProvider, NetworkRequest, NetworkSigner, - NetworkStateInfo, NetworkStatus, NetworkStatusProvider, NetworkSyncForkRequest, - NetworkTransaction, Signature, SigningError, + NetworkStateInfo, NetworkStatus, NetworkStatusProvider, NetworkSyncForkRequest, Signature, + SigningError, }, sync::{ warp::{WarpSyncPhase, WarpSyncProgress}, @@ -295,9 +292,3 @@ const MAX_CONNECTIONS_PER_PEER: usize = 2; /// The maximum number of concurrent established connections that were incoming. const MAX_CONNECTIONS_ESTABLISHED_INCOMING: u32 = 10_000; - -/// Minimum Requirements for a Hash within Networking -pub trait ExHashT: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static {} - -impl ExHashT for T where T: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static -{} diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index d668cb25ea455..c62c2ea1c5d98 100644 --- a/client/network/src/peer_info.rs +++ b/client/network/src/peer_info.rs @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::utils::interval; use fnv::FnvHashMap; use futures::prelude::*; use libp2p::{ @@ -33,6 +32,7 @@ use libp2p::{ Multiaddr, }; use log::{debug, error, trace}; +use sc_network_common::utils::interval; use smallvec::SmallVec; use std::{ collections::hash_map::Entry, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index c7a3cf4b2160f..fbf651de9d49a 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -16,10 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{ - config, error, - utils::{interval, LruHashSet}, -}; +use crate::config; use bytes::Bytes; use codec::{Decode, DecodeAll, Encode}; @@ -45,7 +42,8 @@ use sc_consensus::import_queue::{ BlockImportError, BlockImportStatus, IncomingBlock, RuntimeOrigin, }; use sc_network_common::{ - config::ProtocolId, + config::{NonReservedPeerMode, ProtocolId}, + error, protocol::ProtocolName, request_responses::RequestFailure, sync::{ @@ -57,6 +55,7 @@ use sc_network_common::{ OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PollBlockAnnounceValidation, SyncStatus, }, + utils::{interval, LruHashSet}, }; use sp_arithmetic::traits::SaturatedConversion; use sp_consensus::BlockOrigin; @@ -341,7 +340,7 @@ where bootnodes, reserved_nodes: default_sets_reserved.clone(), reserved_only: network_config.default_peers_set.non_reserved_mode == - config::NonReservedPeerMode::Deny, + NonReservedPeerMode::Deny, }); for set_cfg in &network_config.extra_sets { @@ -352,7 +351,7 @@ where } let reserved_only = - set_cfg.set_config.non_reserved_mode == config::NonReservedPeerMode::Deny; + set_cfg.set_config.non_reserved_mode == NonReservedPeerMode::Deny; sets.push(sc_peerset::SetConfig { in_peers: set_cfg.set_config.in_peers, diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index 50c4a264a5f95..3e1281753b82c 100644 --- a/client/network/src/protocol/message.rs +++ b/client/network/src/protocol/message.rs @@ -36,9 +36,6 @@ pub type Message = generic::Message< ::Extrinsic, >; -/// A set of transactions. -pub type Transactions = Vec; - /// Remote call response. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct RemoteCallResponse { @@ -59,7 +56,7 @@ pub struct RemoteReadResponse { /// Generic types. pub mod generic { - use super::{RemoteCallResponse, RemoteReadResponse, Transactions}; + use super::{RemoteCallResponse, RemoteReadResponse}; use bitflags::bitflags; use codec::{Decode, Encode, Input, Output}; use sc_client_api::StorageProof; @@ -146,9 +143,10 @@ pub mod generic { BlockResponse(BlockResponse), /// Block announce. BlockAnnounce(BlockAnnounce

), - /// Transactions. - Transactions(Transactions), /// Consensus protocol message. + // NOTE: index is incremented by 1 due to transaction-related + // message that was removed + #[codec(index = 6)] Consensus(ConsensusMessage), /// Remote method call request. RemoteCallRequest(RemoteCallRequest), diff --git a/client/network/src/service.rs b/client/network/src/service.rs index dceb57d9e695c..180482e75ece2 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -29,9 +29,8 @@ use crate::{ behaviour::{self, Behaviour, BehaviourOut}, - config::{Params, TransportConfig}, + config::Params, discovery::DiscoveryConfig, - error::Error, network_state::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, @@ -39,7 +38,7 @@ use crate::{ self, message::generic::Roles, NotificationsSink, NotifsHandlerError, PeerInfo, Protocol, Ready, }, - transactions, transport, ExHashT, ReputationChange, + transport, ReputationChange, }; use codec::Encode as _; @@ -60,7 +59,8 @@ use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; use sc_network_common::{ - config::MultiaddrWithPeerId, + config::{MultiaddrWithPeerId, TransportConfig}, + error::Error, protocol::{ event::{DhtEvent, Event}, ProtocolName, @@ -73,6 +73,7 @@ use sc_network_common::{ NotificationSenderReady as NotificationSenderReadyT, Signature, SigningError, }, sync::{SyncState, SyncStatus}, + ExHashT, }; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; @@ -101,7 +102,7 @@ mod out_events; mod tests; pub use libp2p::identity::{error::DecodingError, Keypair, PublicKey}; -use sc_network_common::service::{NetworkBlock, NetworkRequest, NetworkTransaction}; +use sc_network_common::service::{NetworkBlock, NetworkRequest}; /// Substrate network service. Handles network IO and manages connectivity. pub struct NetworkService { @@ -121,7 +122,7 @@ pub struct NetworkService { /// nodes it should be connected to or not. peerset: PeersetHandle, /// Channel that sends messages to the actual worker. - to_worker: TracingUnboundedSender>, + to_worker: TracingUnboundedSender>, /// For each peer and protocol combination, an object that allows sending notifications to /// that peer. Updated by the [`NetworkWorker`]. peers_notifications_sinks: Arc>>, @@ -144,7 +145,7 @@ where /// Returns a `NetworkWorker` that implements `Future` and must be regularly polled in order /// for the network processing to advance. From it, you can extract a `NetworkService` using /// `worker.service()`. The `NetworkService` can be shared through the codebase. - pub fn new(mut params: Params) -> Result { + pub fn new(mut params: Params) -> Result { // Private and public keys configuration. let local_identity = params.network_config.node_key.clone().into_keypair()?; let local_public = local_identity.public(); @@ -215,21 +216,6 @@ where fs::create_dir_all(path)?; } - let transactions_handler_proto = transactions::TransactionsHandlerPrototype::new( - params.protocol_id.clone(), - params - .chain - .hash(0u32.into()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), - params.fork_id.clone(), - ); - params - .network_config - .extra_sets - .insert(0, transactions_handler_proto.set_config()); - info!( target: "sub-libp2p", "🏷 Local node identity is: {}", @@ -244,11 +230,8 @@ where params.protocol_id.clone(), ¶ms.fork_id, ¶ms.network_config, - iter::once(Vec::new()) - .chain( - (0..params.network_config.extra_sets.len() - 1) - .map(|_| default_notif_handshake_message.clone()), - ) + (0..params.network_config.extra_sets.len()) + .map(|_| default_notif_handshake_message.clone()) .collect(), params.metrics_registry.as_ref(), params.chain_sync, @@ -465,13 +448,6 @@ where _marker: PhantomData, }); - let (tx_handler, tx_handler_controller) = transactions_handler_proto.build( - service.clone(), - params.transaction_pool, - params.metrics_registry.as_ref(), - )?; - (params.transactions_handler_executor)(tx_handler.run().boxed()); - Ok(NetworkWorker { external_addresses, num_connected, @@ -482,9 +458,9 @@ where from_service, event_streams: out_events::OutChannels::new(params.metrics_registry.as_ref())?, peers_notifications_sinks, - tx_handler_controller, metrics, boot_node_ids, + _marker: Default::default(), }) } @@ -1149,20 +1125,6 @@ where } } -impl NetworkTransaction for NetworkService -where - B: BlockT + 'static, - H: ExHashT, -{ - fn trigger_repropagate(&self) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::PropagateTransactions); - } - - fn propagate_transaction(&self, hash: H) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::PropagateTransaction(hash)); - } -} - impl NetworkBlock> for NetworkService where B: BlockT + 'static, @@ -1249,9 +1211,7 @@ impl<'a> NotificationSenderReadyT for NotificationSenderReady<'a> { /// Messages sent from the `NetworkService` to the `NetworkWorker`. /// /// Each entry corresponds to a method of `NetworkService`. -enum ServiceToWorkerMsg { - PropagateTransaction(H), - PropagateTransactions, +enum ServiceToWorkerMsg { RequestJustification(B::Hash, NumberFor), ClearJustificationRequests, AnnounceBlock(B::Hash, Option>), @@ -1309,7 +1269,7 @@ where /// The import queue that was passed at initialization. import_queue: Box>, /// Messages from the [`NetworkService`] that must be processed. - from_service: TracingUnboundedReceiver>, + from_service: TracingUnboundedReceiver>, /// Senders for events that happen on the network. event_streams: out_events::OutChannels, /// Prometheus network metrics. @@ -1319,8 +1279,9 @@ where /// For each peer and protocol combination, an object that allows sending notifications to /// that peer. Shared with the [`NetworkService`]. peers_notifications_sinks: Arc>>, - /// Controller for the handler of incoming and outgoing transactions. - tx_handler_controller: transactions::TransactionsHandlerController, + /// Marker to pin the `H` generic. Serves no purpose except to not break backwards + /// compatibility. + _marker: PhantomData, } impl Future for NetworkWorker @@ -1376,10 +1337,6 @@ where .behaviour_mut() .user_protocol_mut() .clear_justification_requests(), - ServiceToWorkerMsg::PropagateTransaction(hash) => - this.tx_handler_controller.propagate_transaction(hash), - ServiceToWorkerMsg::PropagateTransactions => - this.tx_handler_controller.propagate_transactions(), ServiceToWorkerMsg::GetValue(key) => this.network_service.behaviour_mut().get_value(key), ServiceToWorkerMsg::PutValue(key, value) => @@ -1922,8 +1879,6 @@ where SyncState::Downloading => true, }; - this.tx_handler_controller.set_gossip_enabled(!is_major_syncing); - this.is_major_syncing.store(is_major_syncing, Ordering::Relaxed); if let Some(metrics) = this.metrics.as_ref() { diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index a9505c5341c3d..c8f137f79c6dc 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -21,7 +21,7 @@ use crate::{config, NetworkService, NetworkWorker}; use futures::prelude::*; use libp2p::PeerId; use sc_network_common::{ - config::{MultiaddrWithPeerId, ProtocolId}, + config::{MultiaddrWithPeerId, NonDefaultSetConfig, ProtocolId, SetConfig, TransportConfig}, protocol::event::Event, service::{NetworkEventStream, NetworkNotification, NetworkPeers, NetworkStateInfo}, }; @@ -135,12 +135,8 @@ fn build_test_full_node( let worker = NetworkWorker::new(config::Params { role: config::Role::Full, executor: None, - transactions_handler_executor: Box::new(|task| { - async_std::task::spawn(task); - }), network_config, chain: client.clone(), - transaction_pool: Arc::new(config::EmptyTransactionPool), protocol_id, fork_id, import_queue, @@ -178,23 +174,23 @@ fn build_nodes_one_proto() -> ( let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let (node1, events_stream1) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, set_config: Default::default(), }], listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); let (node2, events_stream2) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, - set_config: config::SetConfig { + set_config: SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, peer_id: node1.local_peer_id(), @@ -203,7 +199,7 @@ fn build_nodes_one_proto() -> ( }, }], listen_addresses: vec![], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); @@ -368,13 +364,13 @@ fn lots_of_incoming_peers_works() { let (main_node, _) = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, - set_config: config::SetConfig { in_peers: u32::MAX, ..Default::default() }, + set_config: SetConfig { in_peers: u32::MAX, ..Default::default() }, }], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); @@ -387,11 +383,11 @@ fn lots_of_incoming_peers_works() { for _ in 0..32 { let (_dialing_node, event_stream) = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![], - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, - set_config: config::SetConfig { + set_config: SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr.clone(), peer_id: main_node_peer_id, @@ -399,7 +395,7 @@ fn lots_of_incoming_peers_works() { ..Default::default() }, }], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); @@ -504,23 +500,23 @@ fn fallback_name_working() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let (node1, mut events_stream1) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: NEW_PROTOCOL_NAME.into(), fallback_names: vec![PROTOCOL_NAME.into()], max_notification_size: 1024 * 1024, set_config: Default::default(), }], listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); let (_, mut events_stream2) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, - set_config: config::SetConfig { + set_config: SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, peer_id: node1.local_peer_id(), @@ -529,7 +525,7 @@ fn fallback_name_working() { }, }], listen_addresses: vec![], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); @@ -572,7 +568,7 @@ fn ensure_listen_addresses_consistent_with_transport_memory() { let _ = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) }); } @@ -599,7 +595,7 @@ fn ensure_boot_node_addresses_consistent_with_transport_memory() { let _ = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, boot_nodes: vec![boot_node], ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) }); @@ -632,11 +628,8 @@ fn ensure_reserved_node_addresses_consistent_with_transport_memory() { let _ = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, - default_peers_set: config::SetConfig { - reserved_nodes: vec![reserved_node], - ..Default::default() - }, + transport: TransportConfig::MemoryOnly, + default_peers_set: SetConfig { reserved_nodes: vec![reserved_node], ..Default::default() }, ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) }); } @@ -652,10 +645,7 @@ fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { let _ = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - default_peers_set: config::SetConfig { - reserved_nodes: vec![reserved_node], - ..Default::default() - }, + default_peers_set: SetConfig { reserved_nodes: vec![reserved_node], ..Default::default() }, ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) }); } @@ -668,7 +658,7 @@ fn ensure_public_addresses_consistent_with_transport_memory() { let _ = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, public_addresses: vec![public_address], ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) }); diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index e78b91a4e04ee..2f6b788e368b3 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -47,16 +47,14 @@ use sc_consensus::{ ForkChoiceStrategy, ImportResult, JustificationImport, JustificationSyncLink, LongestChain, Verifier, }; -pub use sc_network::config::EmptyTransactionPool; use sc_network::{ - config::{ - NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, Role, SyncMode, - TransportConfig, - }, + config::{NetworkConfiguration, Role, SyncMode}, Multiaddr, NetworkService, NetworkWorker, }; use sc_network_common::{ - config::{MultiaddrWithPeerId, ProtocolId}, + config::{ + MultiaddrWithPeerId, NonDefaultSetConfig, NonReservedPeerMode, ProtocolId, TransportConfig, + }, protocol::ProtocolName, service::{NetworkBlock, NetworkStateInfo, NetworkSyncForkRequest}, sync::warp::{AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider}, @@ -879,12 +877,8 @@ where let network = NetworkWorker::new(sc_network::config::Params { role: if config.is_authority { Role::Authority } else { Role::Full }, executor: None, - transactions_handler_executor: Box::new(|task| { - async_std::task::spawn(task); - }), network_config, chain: client.clone(), - transaction_pool: Arc::new(EmptyTransactionPool), protocol_id, fork_id, import_queue, diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml new file mode 100644 index 0000000000000..5578bb2c7191e --- /dev/null +++ b/client/network/transactions/Cargo.toml @@ -0,0 +1,28 @@ +[package] +description = "Substrate transaction protocol" +name = "sc-network-transactions" +version = "0.10.0-dev" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +documentation = "https://docs.rs/sc-network-transactions" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +array-bytes = "4.1" +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +futures = "0.3.21" +hex = "0.4.0" +libp2p = "0.46.1" +log = "0.4.17" +pin-project = "1.0.10" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } +sc-network-common = { version = "0.10.0-dev", path = "../common" } +sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } diff --git a/client/network/transactions/src/config.rs b/client/network/transactions/src/config.rs new file mode 100644 index 0000000000000..abb8cccd301ac --- /dev/null +++ b/client/network/transactions/src/config.rs @@ -0,0 +1,98 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Configuration of the transaction protocol + +use futures::prelude::*; +use sc_network_common::ExHashT; +use sp_runtime::traits::Block as BlockT; +use std::{collections::HashMap, future::Future, pin::Pin, time}; + +/// Interval at which we propagate transactions; +pub(crate) const PROPAGATE_TIMEOUT: time::Duration = time::Duration::from_millis(2900); + +/// Maximum number of known transaction hashes to keep for a peer. +/// +/// This should be approx. 2 blocks full of transactions for the network to function properly. +pub(crate) const MAX_KNOWN_TRANSACTIONS: usize = 10240; // ~300kb per peer + overhead. + +/// Maximum allowed size for a transactions notification. +pub(crate) const MAX_TRANSACTIONS_SIZE: u64 = 16 * 1024 * 1024; + +/// Maximum number of transaction validation request we keep at any moment. +pub(crate) const MAX_PENDING_TRANSACTIONS: usize = 8192; + +/// Result of the transaction import. +#[derive(Clone, Copy, Debug)] +pub enum TransactionImport { + /// Transaction is good but already known by the transaction pool. + KnownGood, + /// Transaction is good and not yet known. + NewGood, + /// Transaction is invalid. + Bad, + /// Transaction import was not performed. + None, +} + +/// Future resolving to transaction import result. +pub type TransactionImportFuture = Pin + Send>>; + +/// Transaction pool interface +pub trait TransactionPool: Send + Sync { + /// Get transactions from the pool that are ready to be propagated. + fn transactions(&self) -> Vec<(H, B::Extrinsic)>; + /// Get hash of transaction. + fn hash_of(&self, transaction: &B::Extrinsic) -> H; + /// Import a transaction into the pool. + /// + /// This will return future. + fn import(&self, transaction: B::Extrinsic) -> TransactionImportFuture; + /// Notify the pool about transactions broadcast. + fn on_broadcasted(&self, propagations: HashMap>); + /// Get transaction by hash. + fn transaction(&self, hash: &H) -> Option; +} + +/// Dummy implementation of the [`TransactionPool`] trait for a transaction pool that is always +/// empty and discards all incoming transactions. +/// +/// Requires the "hash" type to implement the `Default` trait. +/// +/// Useful for testing purposes. +pub struct EmptyTransactionPool; + +impl TransactionPool for EmptyTransactionPool { + fn transactions(&self) -> Vec<(H, B::Extrinsic)> { + Vec::new() + } + + fn hash_of(&self, _transaction: &B::Extrinsic) -> H { + Default::default() + } + + fn import(&self, _transaction: B::Extrinsic) -> TransactionImportFuture { + Box::pin(future::ready(TransactionImport::KnownGood)) + } + + fn on_broadcasted(&self, _: HashMap>) {} + + fn transaction(&self, _h: &H) -> Option { + None + } +} diff --git a/client/network/src/transactions.rs b/client/network/transactions/src/lib.rs similarity index 84% rename from client/network/src/transactions.rs rename to client/network/transactions/src/lib.rs index da4547aefeab3..b75bd411b39c4 100644 --- a/client/network/src/transactions.rs +++ b/client/network/transactions/src/lib.rs @@ -26,27 +26,22 @@ //! - Use [`TransactionsHandlerPrototype::build`] then [`TransactionsHandler::run`] to obtain a //! `Future` that processes transactions. -use crate::{ - config::{self, TransactionImport, TransactionImportFuture, TransactionPool}, - error, - protocol::message, - service::NetworkService, - utils::{interval, LruHashSet}, - ExHashT, -}; - +use crate::config::*; use codec::{Decode, Encode}; use futures::{channel::mpsc, prelude::*, stream::FuturesUnordered}; use libp2p::{multiaddr, PeerId}; use log::{debug, trace, warn}; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network_common::{ - config::ProtocolId, + config::{NonDefaultSetConfig, NonReservedPeerMode, ProtocolId, SetConfig}, + error, protocol::{ event::{Event, ObservedRole}, ProtocolName, }, service::{NetworkEventStream, NetworkNotification, NetworkPeers}, + utils::{interval, LruHashSet}, + ExHashT, }; use sp_runtime::traits::Block as BlockT; use std::{ @@ -54,27 +49,14 @@ use std::{ iter, num::NonZeroUsize, pin::Pin, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, + sync::Arc, task::Poll, - time, }; -/// Interval at which we propagate transactions; -const PROPAGATE_TIMEOUT: time::Duration = time::Duration::from_millis(2900); - -/// Maximum number of known transaction hashes to keep for a peer. -/// -/// This should be approx. 2 blocks full of transactions for the network to function properly. -const MAX_KNOWN_TRANSACTIONS: usize = 10240; // ~300kb per peer + overhead. +pub mod config; -/// Maximum allowed size for a transactions notification. -const MAX_TRANSACTIONS_SIZE: u64 = 16 * 1024 * 1024; - -/// Maximum number of transaction validation request we keep at any moment. -const MAX_PENDING_TRANSACTIONS: usize = 8192; +/// A set of transactions. +pub type Transactions = Vec; mod rep { use sc_peerset::ReputationChange as Rep; @@ -141,7 +123,7 @@ impl TransactionsHandlerPrototype { pub fn new>( protocol_id: ProtocolId, genesis_hash: Hash, - fork_id: Option, + fork_id: Option<&str>, ) -> Self { let genesis_hash = genesis_hash.as_ref(); let protocol_name = if let Some(fork_id) = fork_id { @@ -158,16 +140,16 @@ impl TransactionsHandlerPrototype { } /// Returns the configuration of the set to put in the network configuration. - pub fn set_config(&self) -> config::NonDefaultSetConfig { - config::NonDefaultSetConfig { + pub fn set_config(&self) -> NonDefaultSetConfig { + NonDefaultSetConfig { notifications_protocol: self.protocol_name.clone(), fallback_names: self.fallback_protocol_names.clone(), max_notification_size: MAX_TRANSACTIONS_SIZE, - set_config: config::SetConfig { + set_config: SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), - non_reserved_mode: config::NonReservedPeerMode::Deny, + non_reserved_mode: NonReservedPeerMode::Deny, }, } } @@ -176,23 +158,25 @@ impl TransactionsHandlerPrototype { /// the behaviour of the handler while it's running. /// /// Important: the transactions handler is initially disabled and doesn't gossip transactions. - /// You must call [`TransactionsHandlerController::set_gossip_enabled`] to enable it. - pub fn build( + /// Gossiping is enabled when major syncing is done. + pub fn build< + B: BlockT + 'static, + H: ExHashT, + S: NetworkPeers + NetworkEventStream + NetworkNotification + sp_consensus::SyncOracle, + >( self, - service: Arc>, + service: S, transaction_pool: Arc>, metrics_registry: Option<&Registry>, - ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { + ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { let event_stream = service.event_stream("transactions-handler"); let (to_handler, from_controller) = mpsc::unbounded(); - let gossip_enabled = Arc::new(AtomicBool::new(false)); let handler = TransactionsHandler { protocol_name: self.protocol_name, propagate_timeout: Box::pin(interval(PROPAGATE_TIMEOUT)), pending_transactions: FuturesUnordered::new(), pending_transactions_peers: HashMap::new(), - gossip_enabled: gossip_enabled.clone(), service, event_stream, peers: HashMap::new(), @@ -205,7 +189,7 @@ impl TransactionsHandlerPrototype { }, }; - let controller = TransactionsHandlerController { to_handler, gossip_enabled }; + let controller = TransactionsHandlerController { to_handler }; Ok((handler, controller)) } @@ -214,15 +198,9 @@ impl TransactionsHandlerPrototype { /// Controls the behaviour of a [`TransactionsHandler`] it is connected to. pub struct TransactionsHandlerController { to_handler: mpsc::UnboundedSender>, - gossip_enabled: Arc, } impl TransactionsHandlerController { - /// Controls whether transactions are being gossiped on the network. - pub fn set_gossip_enabled(&mut self, enabled: bool) { - self.gossip_enabled.store(enabled, Ordering::Relaxed); - } - /// You may call this when new transactions are imported by the transaction pool. /// /// All transactions will be fetched from the `TransactionPool` that was passed at @@ -246,7 +224,11 @@ enum ToHandler { } /// Handler for transactions. Call [`TransactionsHandler::run`] to start the processing. -pub struct TransactionsHandler { +pub struct TransactionsHandler< + B: BlockT + 'static, + H: ExHashT, + S: NetworkPeers + NetworkEventStream + NetworkNotification + sp_consensus::SyncOracle, +> { protocol_name: ProtocolName, /// Interval at which we call `propagate_transactions`. propagate_timeout: Pin + Send>>, @@ -258,13 +240,12 @@ pub struct TransactionsHandler { /// multiple times concurrently. pending_transactions_peers: HashMap>, /// Network service to use to send messages and manage peers. - service: Arc>, + service: S, /// Stream of networking events. event_stream: Pin + Send>>, // All connected peers peers: HashMap>, transaction_pool: Arc>, - gossip_enabled: Arc, from_controller: mpsc::UnboundedReceiver>, /// Prometheus metrics. metrics: Option, @@ -278,7 +259,12 @@ struct Peer { role: ObservedRole, } -impl TransactionsHandler { +impl TransactionsHandler +where + B: BlockT + 'static, + H: ExHashT, + S: NetworkPeers + NetworkEventStream + NetworkNotification + sp_consensus::SyncOracle, +{ /// Turns the [`TransactionsHandler`] into a future that should run forever and not be /// interrupted. pub async fn run(mut self) { @@ -360,9 +346,9 @@ impl TransactionsHandler { continue } - if let Ok(m) = as Decode>::decode( - &mut message.as_ref(), - ) { + if let Ok(m) = + as Decode>::decode(&mut message.as_ref()) + { self.on_transactions(remote, m); } else { warn!(target: "sub-libp2p", "Failed to decode transactions list"); @@ -376,10 +362,10 @@ impl TransactionsHandler { } /// Called when peer sends us new transactions - fn on_transactions(&mut self, who: PeerId, transactions: message::Transactions) { - // Accept transactions only when enabled - if !self.gossip_enabled.load(Ordering::Relaxed) { - trace!(target: "sync", "{} Ignoring transactions while disabled", who); + fn on_transactions(&mut self, who: PeerId, transactions: Transactions) { + // Accept transactions only when node is not major syncing + if self.service.is_major_syncing() { + trace!(target: "sync", "{} Ignoring transactions while major syncing", who); return } @@ -428,10 +414,11 @@ impl TransactionsHandler { /// Propagate one transaction. pub fn propagate_transaction(&mut self, hash: &H) { - // Accept transactions only when enabled - if !self.gossip_enabled.load(Ordering::Relaxed) { + // Accept transactions only when node is not major syncing + if self.service.is_major_syncing() { return } + debug!(target: "sync", "Propagating transaction [{:?}]", hash); if let Some(transaction) = self.transaction_pool.transaction(hash) { let propagated_to = self.do_propagate_transactions(&[(hash.clone(), transaction)]); @@ -479,10 +466,11 @@ impl TransactionsHandler { /// Call when we must propagate ready transactions to peers. fn propagate_transactions(&mut self) { - // Accept transactions only when enabled - if !self.gossip_enabled.load(Ordering::Relaxed) { + // Accept transactions only when node is not major syncing + if self.service.is_major_syncing() { return } + debug!(target: "sync", "Propagating transactions"); let transactions = self.transaction_pool.transactions(); let propagated_to = self.do_propagate_transactions(&transactions); diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 3c574ef13c8e6..e46c65cf018f5 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -56,6 +56,7 @@ sc-network-bitswap = { version = "0.10.0-dev", path = "../network/bitswap" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-network-light = { version = "0.10.0-dev", path = "../network/light" } sc-network-sync = { version = "0.10.0-dev", path = "../network/sync" } +sc-network-transactions = { version = "0.10.0-dev", path = "../network/transactions" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 5a2f4cf978b41..dfd532a14c172 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -40,7 +40,7 @@ use sc_keystore::LocalKeystore; use sc_network::{config::SyncMode, NetworkService}; use sc_network_bitswap::BitswapRequestHandler; use sc_network_common::{ - service::{NetworkStateInfo, NetworkStatusProvider, NetworkTransaction}, + service::{NetworkStateInfo, NetworkStatusProvider}, sync::warp::WarpSyncProvider, }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; @@ -326,7 +326,6 @@ where pub trait SpawnTaskNetwork: sc_offchain::NetworkProvider + NetworkStateInfo - + NetworkTransaction + NetworkStatusProvider + Send + Sync @@ -339,7 +338,6 @@ where Block: BlockT, T: sc_offchain::NetworkProvider + NetworkStateInfo - + NetworkTransaction + NetworkStatusProvider + Send + Sync @@ -368,6 +366,9 @@ pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> { pub network: Arc>, /// A Sender for RPC requests. pub system_rpc_tx: TracingUnboundedSender>, + /// Controller for transactions handlers + pub tx_handler_controller: + sc_network_transactions::TransactionsHandlerController<::Hash>, /// Telemetry instance for this node. pub telemetry: Option<&'a mut Telemetry>, } @@ -446,6 +447,7 @@ where rpc_builder, network, system_rpc_tx, + tx_handler_controller, telemetry, } = params; @@ -481,7 +483,11 @@ where spawn_handle.spawn( "on-transaction-imported", Some("transaction-pool"), - transaction_notifications(transaction_pool.clone(), network.clone(), telemetry.clone()), + transaction_notifications( + transaction_pool.clone(), + tx_handler_controller, + telemetry.clone(), + ), ); // Prometheus metrics. @@ -544,20 +550,21 @@ where Ok(rpc_handlers) } -async fn transaction_notifications( +async fn transaction_notifications( transaction_pool: Arc, - network: Network, + tx_handler_controller: sc_network_transactions::TransactionsHandlerController< + ::Hash, + >, telemetry: Option, ) where Block: BlockT, ExPool: MaintainedTransactionPool::Hash>, - Network: NetworkTransaction<::Hash> + Send + Sync, { // transaction notifications transaction_pool .import_notification_stream() .for_each(move |hash| { - network.propagate_transaction(hash); + tx_handler_controller.propagate_transaction(hash); let status = transaction_pool.status(); telemetry!( telemetry; @@ -719,6 +726,7 @@ pub fn build_network( ( Arc::Hash>>, TracingUnboundedSender>, + sc_network_transactions::TransactionsHandlerController<::Hash>, NetworkStarter, ), Error, @@ -761,9 +769,6 @@ where } } - let transaction_pool_adapter = - Arc::new(TransactionPoolAdapter { pool: transaction_pool, client: client.clone() }); - let protocol_id = config.protocol_id(); let block_announce_validator = if let Some(f) = block_announce_validator_builder { @@ -845,7 +850,7 @@ where protocol_config })); - let network_params = sc_network::config::Params { + let mut network_params = sc_network::config::Params { role: config.role.clone(), executor: { let spawn_handle = Clone::clone(&spawn_handle); @@ -853,16 +858,9 @@ where spawn_handle.spawn("libp2p-node", Some("networking"), fut); })) }, - transactions_handler_executor: { - let spawn_handle = Clone::clone(&spawn_handle); - Box::new(move |fut| { - spawn_handle.spawn("network-transactions-handler", Some("networking"), fut); - }) - }, network_config: config.network.clone(), chain: client.clone(), - transaction_pool: transaction_pool_adapter as _, - protocol_id, + protocol_id: protocol_id.clone(), fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), import_queue: Box::new(import_queue), chain_sync: Box::new(chain_sync), @@ -877,10 +875,32 @@ where .collect::>(), }; + // crate transactions protocol and add it to the list of supported protocols of `network_params` + let transactions_handler_proto = sc_network_transactions::TransactionsHandlerPrototype::new( + protocol_id.clone(), + client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + config.chain_spec.fork_id(), + ); + network_params + .network_config + .extra_sets + .insert(0, transactions_handler_proto.set_config()); + let has_bootnodes = !network_params.network_config.boot_nodes.is_empty(); let network_mut = sc_network::NetworkWorker::new(network_params)?; let network = network_mut.service().clone(); + let (tx_handler, tx_handler_controller) = transactions_handler_proto.build( + network.clone(), + Arc::new(TransactionPoolAdapter { pool: transaction_pool, client: client.clone() }), + config.prometheus_config.as_ref().map(|config| &config.registry), + )?; + spawn_handle.spawn("network-transactions-handler", Some("networking"), tx_handler.run()); + let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc"); let future = build_network_future( @@ -928,7 +948,7 @@ where future.await }); - Ok((network, system_rpc_tx, NetworkStarter(network_start_tx))) + Ok((network, system_rpc_tx, tx_handler_controller, NetworkStarter(network_start_tx))) } /// Object used to start the network. diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 44153e3b914f3..bca0697bcbd08 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -24,13 +24,11 @@ pub use sc_executor::WasmExecutionMethod; #[cfg(feature = "wasmtime")] pub use sc_executor::WasmtimeInstantiationStrategy; pub use sc_network::{ - config::{ - NetworkConfiguration, NodeKeyConfig, NonDefaultSetConfig, Role, SetConfig, TransportConfig, - }, + config::{NetworkConfiguration, NodeKeyConfig, Role}, Multiaddr, }; pub use sc_network_common::{ - config::{MultiaddrWithPeerId, ProtocolId}, + config::{MultiaddrWithPeerId, NonDefaultSetConfig, ProtocolId, SetConfig, TransportConfig}, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, diff --git a/client/service/src/error.rs b/client/service/src/error.rs index 0d702c7f37b98..001a83922d776 100644 --- a/client/service/src/error.rs +++ b/client/service/src/error.rs @@ -19,7 +19,6 @@ //! Errors that can occur during the service operation. use sc_keystore; -use sc_network; use sp_blockchain; use sp_consensus; @@ -41,7 +40,7 @@ pub enum Error { Consensus(#[from] sp_consensus::Error), #[error(transparent)] - Network(#[from] sc_network::error::Error), + Network(#[from] sc_network_common::error::Error), #[error(transparent)] Keystore(#[from] sc_keystore::Error), diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 19358c1e5bc4c..091b4bbe9fe5f 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -72,7 +72,7 @@ pub use sc_chain_spec::{ pub use sc_consensus::ImportQueue; pub use sc_executor::NativeExecutionDispatch; #[doc(hidden)] -pub use sc_network::config::{TransactionImport, TransactionImportFuture}; +pub use sc_network_transactions::config::{TransactionImport, TransactionImportFuture}; pub use sc_rpc::{ RandomIntegerSubscriptionId, RandomStringSubscriptionId, RpcSubscriptionIdProvider, }; @@ -148,7 +148,7 @@ async fn build_network_future< + Send + Sync + 'static, - H: sc_network::ExHashT, + H: sc_network_common::ExHashT, >( role: Role, mut network: sc_network::NetworkWorker, @@ -415,7 +415,8 @@ where .collect() } -impl sc_network::config::TransactionPool for TransactionPoolAdapter +impl sc_network_transactions::config::TransactionPool + for TransactionPoolAdapter where C: HeaderBackend + BlockBackend diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 23245d46cba10..5d29d34a3cbf2 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -22,12 +22,9 @@ use futures::{task::Poll, Future, TryFutureExt as _}; use log::{debug, info}; use parking_lot::Mutex; use sc_client_api::{Backend, CallExecutor}; -use sc_network::{ - config::{NetworkConfiguration, TransportConfig}, - multiaddr, -}; +use sc_network::{config::NetworkConfiguration, multiaddr}; use sc_network_common::{ - config::MultiaddrWithPeerId, + config::{MultiaddrWithPeerId, TransportConfig}, service::{NetworkBlock, NetworkPeers, NetworkStateInfo}, }; use sc_service::{ From 519fbaae886e2773b37363970433d36cbb47d853 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 27 Sep 2022 08:08:14 +0100 Subject: [PATCH 1206/1472] =?UTF-8?q?export=20more=20types=20from=20fast-u?= =?UTF-8?q?ntsake=20=F0=9F=A4=A6=E2=80=8D=E2=99=82=EF=B8=8F=20(#12353)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * export more types from fast-untsake 🤦‍♂️ * make non-test * fmt --- frame/fast-unstake/src/lib.rs | 3 ++- frame/fast-unstake/src/types.rs | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 9bfb29f8457fa..7fbac8560ea6c 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -60,7 +60,7 @@ mod tests; // NOTE: enable benchmarking in tests as well. #[cfg(feature = "runtime-benchmarks")] mod benchmarking; -mod types; +pub mod types; pub mod weights; pub const LOG_TARGET: &'static str = "runtime::fast-unstake"; @@ -90,6 +90,7 @@ pub mod pallet { }; use sp_staking::EraIndex; use sp_std::{prelude::*, vec::Vec}; + pub use types::PreventStakingOpsIfUnbonding; pub use weights::WeightInfo; #[derive(scale_info::TypeInfo, codec::Encode, codec::Decode, codec::MaxEncodedLen)] diff --git a/frame/fast-unstake/src/types.rs b/frame/fast-unstake/src/types.rs index e8d538dce4802..2ddb8dca27e9e 100644 --- a/frame/fast-unstake/src/types.rs +++ b/frame/fast-unstake/src/types.rs @@ -47,7 +47,6 @@ pub struct UnstakeRequest(sp_std::marker::PhantomData); -#[cfg(test)] impl PreventStakingOpsIfUnbonding { pub fn new() -> Self { Self(Default::default()) From 1763ff2273c4649fa969167503951371141a0272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 27 Sep 2022 11:37:45 +0200 Subject: [PATCH 1207/1472] Fix compilation on 1.66 nightly (#12363) --- primitives/state-machine/src/trie_backend_essence.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index dda7b51ab08c6..cd2a71163e2ee 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -178,7 +178,10 @@ impl, H: Hasher, C: AsLocalTrieCache> TrieBackendEss ) -> R { let storage_root = storage_root.unwrap_or_else(|| self.root); let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder()); - let recorder = recorder.as_mut().map(|r| r as _); + let recorder = match recorder.as_mut() { + Some(recorder) => Some(recorder as &mut dyn TrieRecorder), + None => None, + }; let mut cache = self .trie_node_cache @@ -216,7 +219,10 @@ impl, H: Hasher, C: AsLocalTrieCache> TrieBackendEss ) -> (Option, R), ) -> R { let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder()); - let recorder = recorder.as_mut().map(|r| r as _); + let recorder = match recorder.as_mut() { + Some(recorder) => Some(recorder as &mut dyn TrieRecorder), + None => None, + }; let result = if let Some(local_cache) = self.trie_node_cache.as_ref() { let mut cache = local_cache.as_local_trie_cache().as_trie_db_mut_cache(); From edca89177318580878bf11c0d49586ceea23909b Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 27 Sep 2022 13:16:30 +0200 Subject: [PATCH 1208/1472] Relax Slots-based engines from Epochs (#12360) Remove Epochs reference from slots subsystem --- client/consensus/aura/src/lib.rs | 14 ++++++------- client/consensus/babe/src/lib.rs | 12 ++++------- client/consensus/slots/src/lib.rs | 35 +++++++++++++++---------------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index c538200bb315c..a0eed6e35310e 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -257,7 +257,7 @@ pub fn build_aura_worker( SyncOracle = SO, JustificationSyncLink = L, Claim = P::Public, - EpochData = Vec>, + AuxData = Vec>, > where B: BlockT, @@ -330,7 +330,7 @@ where Pin> + Send + 'static>>; type Proposer = E::Proposer; type Claim = P::Public; - type EpochData = Vec>; + type AuxData = Vec>; fn logging_target(&self) -> &'static str { "aura" @@ -340,15 +340,15 @@ where &mut self.block_import } - fn epoch_data( + fn aux_data( &self, header: &B::Header, _slot: Slot, - ) -> Result { + ) -> Result { authorities(self.client.as_ref(), &BlockId::Hash(header.hash())) } - fn authorities_len(&self, epoch_data: &Self::EpochData) -> Option { + fn authorities_len(&self, epoch_data: &Self::AuxData) -> Option { Some(epoch_data.len()) } @@ -356,7 +356,7 @@ where &self, _header: &B::Header, slot: Slot, - epoch_data: &Self::EpochData, + epoch_data: &Self::AuxData, ) -> Option { let expected_author = slot_author::

= <

::Block as BlockT>::Extrinsi pub type TransactionStatusStreamFor

= TransactionStatusStream, BlockHash

>; /// Transaction type for a local pool. pub type LocalTransactionFor

= <

::Block as BlockT>::Extrinsic; +/// Transaction's index within the block in which it was included. +pub type TxIndex = usize; /// Typical future type used in transaction pool api. pub type PoolFuture = std::pin::Pin> + Send>>; @@ -362,3 +367,52 @@ impl OffchainSubmitTransaction for TP }) } } + +/// Wrapper functions to keep the API backwards compatible over the wire for the old RPC spec. +mod v1_compatible { + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + pub fn serialize(data: &(H, usize), serializer: S) -> Result + where + S: Serializer, + H: Serialize, + { + let (hash, _) = data; + serde::Serialize::serialize(&hash, serializer) + } + + pub fn deserialize<'de, D, H>(deserializer: D) -> Result<(H, usize), D::Error> + where + D: Deserializer<'de>, + H: Deserialize<'de>, + { + let hash: H = serde::Deserialize::deserialize(deserializer)?; + Ok((hash, 0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tx_status_compatibility() { + let event: TransactionStatus = TransactionStatus::InBlock((1, 2)); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"inBlock":1}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionStatus = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, TransactionStatus::InBlock((1, 0))); + + let event: TransactionStatus = TransactionStatus::Finalized((1, 2)); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"finalized":1}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionStatus = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, TransactionStatus::Finalized((1, 0))); + } +} diff --git a/client/transaction-pool/src/graph/listener.rs b/client/transaction-pool/src/graph/listener.rs index d4f42b32fdbb8..776749abf2d5d 100644 --- a/client/transaction-pool/src/graph/listener.rs +++ b/client/transaction-pool/src/graph/listener.rs @@ -104,13 +104,18 @@ impl Listener { /// Transaction was pruned from the pool. pub fn pruned(&mut self, block_hash: BlockHash, tx: &H) { debug!(target: "txpool", "[{:?}] Pruned at {:?}", tx, block_hash); - self.fire(tx, |s| s.in_block(block_hash)); - self.finality_watchers.entry(block_hash).or_insert(vec![]).push(tx.clone()); + // Get the transactions included in the given block hash. + let txs = self.finality_watchers.entry(block_hash).or_insert(vec![]); + txs.push(tx.clone()); + // Current transaction is the last one included. + let tx_index = txs.len() - 1; + + self.fire(tx, |watcher| watcher.in_block(block_hash, tx_index)); while self.finality_watchers.len() > MAX_FINALITY_WATCHERS { if let Some((hash, txs)) = self.finality_watchers.pop_front() { for tx in txs { - self.fire(&tx, |s| s.finality_timeout(hash)); + self.fire(&tx, |watcher| watcher.finality_timeout(hash)); } } } @@ -120,7 +125,7 @@ impl Listener { pub fn retracted(&mut self, block_hash: BlockHash) { if let Some(hashes) = self.finality_watchers.remove(&block_hash) { for hash in hashes { - self.fire(&hash, |s| s.retracted(block_hash)) + self.fire(&hash, |watcher| watcher.retracted(block_hash)) } } } @@ -128,9 +133,9 @@ impl Listener { /// Notify all watchers that transactions have been finalized pub fn finalized(&mut self, block_hash: BlockHash) { if let Some(hashes) = self.finality_watchers.remove(&block_hash) { - for hash in hashes { + for (tx_index, hash) in hashes.into_iter().enumerate() { log::debug!(target: "txpool", "[{:?}] Sent finalization event (block {:?})", hash, block_hash); - self.fire(&hash, |s| s.finalized(block_hash)) + self.fire(&hash, |watcher| watcher.finalized(block_hash, tx_index)) } } } diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 19acbddbe7843..108ae791e37b3 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -770,7 +770,7 @@ mod tests { assert_eq!(stream.next(), Some(TransactionStatus::Ready)); assert_eq!( stream.next(), - Some(TransactionStatus::InBlock(H256::from_low_u64_be(2).into())), + Some(TransactionStatus::InBlock((H256::from_low_u64_be(2).into(), 0))), ); } @@ -803,7 +803,7 @@ mod tests { assert_eq!(stream.next(), Some(TransactionStatus::Ready)); assert_eq!( stream.next(), - Some(TransactionStatus::InBlock(H256::from_low_u64_be(2).into())), + Some(TransactionStatus::InBlock((H256::from_low_u64_be(2).into(), 0))), ); } diff --git a/client/transaction-pool/src/graph/watcher.rs b/client/transaction-pool/src/graph/watcher.rs index 8cd78cfc78240..0613300c8684b 100644 --- a/client/transaction-pool/src/graph/watcher.rs +++ b/client/transaction-pool/src/graph/watcher.rs @@ -84,13 +84,13 @@ impl Sender { } /// Extrinsic has been included in block with given hash. - pub fn in_block(&mut self, hash: BH) { - self.send(TransactionStatus::InBlock(hash)); + pub fn in_block(&mut self, hash: BH, index: usize) { + self.send(TransactionStatus::InBlock((hash, index))); } /// Extrinsic has been finalized by a finality gadget. - pub fn finalized(&mut self, hash: BH) { - self.send(TransactionStatus::Finalized(hash)); + pub fn finalized(&mut self, hash: BH, index: usize) { + self.send(TransactionStatus::Finalized((hash, index))); self.is_finalized = true; } diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index f04a27cf81e1d..be75523c1230f 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -328,7 +328,7 @@ fn should_revalidate_across_many_blocks() { block_on( watcher1 - .take_while(|s| future::ready(*s != TransactionStatus::InBlock(block_hash))) + .take_while(|s| future::ready(*s != TransactionStatus::InBlock((block_hash, 0)))) .collect::>(), ); @@ -398,24 +398,24 @@ fn should_push_watchers_during_maintenance() { futures::executor::block_on_stream(watcher0).collect::>(), vec![ TransactionStatus::Ready, - TransactionStatus::InBlock(header_hash), - TransactionStatus::Finalized(header_hash) + TransactionStatus::InBlock((header_hash, 0)), + TransactionStatus::Finalized((header_hash, 0)) ], ); assert_eq!( futures::executor::block_on_stream(watcher1).collect::>(), vec![ TransactionStatus::Ready, - TransactionStatus::InBlock(header_hash), - TransactionStatus::Finalized(header_hash) + TransactionStatus::InBlock((header_hash, 1)), + TransactionStatus::Finalized((header_hash, 1)) ], ); assert_eq!( futures::executor::block_on_stream(watcher2).collect::>(), vec![ TransactionStatus::Ready, - TransactionStatus::InBlock(header_hash), - TransactionStatus::Finalized(header_hash) + TransactionStatus::InBlock((header_hash, 2)), + TransactionStatus::Finalized((header_hash, 2)) ], ); } @@ -450,8 +450,8 @@ fn finalization() { let mut stream = futures::executor::block_on_stream(watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((header.hash(), 0)))); assert_eq!(stream.next(), None); } @@ -573,30 +573,31 @@ fn fork_aware_finalization() { for (canon_watcher, h) in canon_watchers { let mut stream = futures::executor::block_on_stream(canon_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(h))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(h))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((h, 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((h, 0)))); assert_eq!(stream.next(), None); } { let mut stream = futures::executor::block_on_stream(from_dave_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(c2))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((c2, 0)))); assert_eq!(stream.next(), Some(TransactionStatus::Retracted(c2))); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(e1))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(e1))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((e1, 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((e1, 0)))); assert_eq!(stream.next(), None); } { let mut stream = futures::executor::block_on_stream(from_bob_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(d2))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((d2, 0)))); assert_eq!(stream.next(), Some(TransactionStatus::Retracted(d2))); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(e1))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(e1))); + // In block e1 we submitted: [dave, bob] xts in this order. + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((e1, 1)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((e1, 1)))); assert_eq!(stream.next(), None); } } @@ -646,10 +647,10 @@ fn prune_and_retract_tx_at_same_time() { { let mut stream = futures::executor::block_on_stream(watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1, 0)))); assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1))); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2, 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b2, 0)))); assert_eq!(stream.next(), None); } } From 60be7b8d03b8dc4a15080bddcefb1a9b20598d6a Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 11 Oct 2022 15:56:18 +0200 Subject: [PATCH 1257/1472] Remove the unused light client requests (#12470) * Remove the unused light client requests * Add comment about new ids --- .../src/light_client_requests/handler.rs | 4 -- .../network/light/src/schema/light.v1.proto | 51 +------------------ 2 files changed, 2 insertions(+), 53 deletions(-) diff --git a/client/network/light/src/light_client_requests/handler.rs b/client/network/light/src/light_client_requests/handler.rs index 5efdc3ff6a18b..9dc02eb9ff291 100644 --- a/client/network/light/src/light_client_requests/handler.rs +++ b/client/network/light/src/light_client_requests/handler.rs @@ -151,12 +151,8 @@ where self.on_remote_call_request(&peer, r)?, Some(schema::v1::light::request::Request::RemoteReadRequest(r)) => self.on_remote_read_request(&peer, r)?, - Some(schema::v1::light::request::Request::RemoteHeaderRequest(_r)) => - return Err(HandleRequestError::BadRequest("Not supported.")), Some(schema::v1::light::request::Request::RemoteReadChildRequest(r)) => self.on_remote_read_child_request(&peer, r)?, - Some(schema::v1::light::request::Request::RemoteChangesRequest(_r)) => - return Err(HandleRequestError::BadRequest("Not supported.")), None => return Err(HandleRequestError::BadRequest("Remote request without request data.")), }; diff --git a/client/network/light/src/schema/light.v1.proto b/client/network/light/src/schema/light.v1.proto index 9b5d47719dc28..1df5466e21988 100644 --- a/client/network/light/src/schema/light.v1.proto +++ b/client/network/light/src/schema/light.v1.proto @@ -17,9 +17,8 @@ message Request { oneof request { RemoteCallRequest remote_call_request = 1; RemoteReadRequest remote_read_request = 2; - RemoteHeaderRequest remote_header_request = 3; RemoteReadChildRequest remote_read_child_request = 4; - RemoteChangesRequest remote_changes_request = 5; + // Note: ids 3 and 5 were used in the past. It would be preferable to not re-use them. } } @@ -28,8 +27,7 @@ message Response { oneof response { RemoteCallResponse remote_call_response = 1; RemoteReadResponse remote_read_response = 2; - RemoteHeaderResponse remote_header_response = 3; - RemoteChangesResponse remote_changes_response = 4; + // Note: ids 3 and 4 were used in the past. It would be preferable to not re-use them. } } @@ -73,48 +71,3 @@ message RemoteReadChildRequest { // Storage keys. repeated bytes keys = 6; } - -// Remote header request. -message RemoteHeaderRequest { - // Block number to request header for. - bytes block = 2; -} - -// Remote header response. -message RemoteHeaderResponse { - // Header. None if proof generation has failed (e.g. header is unknown). - bytes header = 2; // optional - // Header proof. - bytes proof = 3; -} - -/// Remote changes request. -message RemoteChangesRequest { - // Hash of the first block of the range (including first) where changes are requested. - bytes first = 2; - // Hash of the last block of the range (including last) where changes are requested. - bytes last = 3; - // Hash of the first block for which the requester has the changes trie root. All other - // affected roots must be proved. - bytes min = 4; - // Hash of the last block that we can use when querying changes. - bytes max = 5; - // Storage child node key which changes are requested. - bytes storage_key = 6; // optional - // Storage key which changes are requested. - bytes key = 7; -} - -// Remote changes response. -message RemoteChangesResponse { - // Proof has been generated using block with this number as a max block. Should be - // less than or equal to the RemoteChangesRequest::max block number. - bytes max = 2; - // Changes proof. - repeated bytes proof = 3; - // Changes tries roots missing on the requester' node. - repeated Pair roots = 4; - // Missing changes tries roots proof. - bytes roots_proof = 5; -} - From 6072b90096102767076b24da840d1e1ccf1baabc Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Tue, 11 Oct 2022 18:25:12 +0300 Subject: [PATCH 1258/1472] Fix flaky service test (#12472) Sometimes `NotificationStreamOpenened` would be received for the other protocol before `SyncConnected` was received so when the connection was closed, an incorrect event was read from the event stream. --- client/network/common/src/config.rs | 4 ++++ client/network/src/service/tests.rs | 26 ++++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/client/network/common/src/config.rs b/client/network/common/src/config.rs index e4a7f04c8d6e8..96c7c11ec2696 100644 --- a/client/network/common/src/config.rs +++ b/client/network/common/src/config.rs @@ -244,6 +244,10 @@ pub struct NonDefaultSetConfig { /// `sc_network::protocol::event::Event::NotificationStreamOpened::negotiated_fallback` pub fallback_names: Vec, /// Handshake of the protocol + /// + /// NOTE: Currently custom handshakes are not fully supported. See issue #5685 for more + /// details. This field is temporarily used to allow moving the hardcoded block announcement + /// protocol out of `protocol.rs`. pub handshake: Option, /// Maximum allowed size of single notifications. pub max_notification_size: u64, diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 7c651c675b83e..b656d7a7c0ddc 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -637,19 +637,21 @@ async fn disconnect_sync_peer_using_block_announcement_protocol_name() { ..config::NetworkConfiguration::new_local() }); - loop { - match events_stream1.next().await.unwrap() { - Event::NotificationStreamOpened { .. } => break, - _ => {}, - }; + async fn wait_for_events(stream: &mut (impl Stream + std::marker::Unpin)) { + let mut notif_received = false; + let mut sync_received = false; + + while !notif_received || !sync_received { + match stream.next().await.unwrap() { + Event::NotificationStreamOpened { .. } => notif_received = true, + Event::SyncConnected { .. } => sync_received = true, + _ => {}, + }; + } } - loop { - match events_stream2.next().await.unwrap() { - Event::NotificationStreamOpened { .. } => break, - _ => {}, - }; - } + wait_for_events(&mut events_stream1).await; + wait_for_events(&mut events_stream2).await; // disconnect peer using `PROTOCOL_NAME`, verify `NotificationStreamClosed` event is emitted node2.disconnect_peer(node1.local_peer_id(), PROTOCOL_NAME.into()); @@ -659,7 +661,7 @@ async fn disconnect_sync_peer_using_block_announcement_protocol_name() { )); let _ = events_stream2.next().await; // ignore the reopen event - // now disconnect using the block announcement protocol, verify that `SyncDisconnected` is + // now disconnect using `BLOCK_ANNOUNCE_PROTO_NAME`, verify that `SyncDisconnected` is // emitted node2.disconnect_peer(node1.local_peer_id(), BLOCK_ANNOUNCE_PROTO_NAME.into()); assert!(std::matches!(events_stream2.next().await, Some(Event::SyncDisconnected { .. }))); From 1bf2e6db6ccc0f9d872cddf9e3254227d100f2bf Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 12 Oct 2022 00:35:54 +0800 Subject: [PATCH 1259/1472] Rename `from_components` to `from_parts` (#12473) * Rename `from_components` to `from_parts` * Fixes * Spelling --- frame/contracts/src/gas.rs | 2 +- frame/election-provider-multi-phase/src/mock.rs | 2 +- frame/system/src/limits.rs | 2 +- primitives/weights/src/weight_v2.rs | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index d0076652dd6d4..c0cc2db2aa3eb 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -109,7 +109,7 @@ where pub fn nested(&mut self, amount: Weight) -> Result { // NOTE that it is ok to allocate all available gas since it still ensured // by `charge` that it doesn't reach zero. - let amount = Weight::from_components( + let amount = Weight::from_parts( if amount.ref_time().is_zero() { self.gas_left().ref_time() } else { diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 2615d863c91e0..6a638c8d2a2e1 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -239,7 +239,7 @@ parameter_types! { pub const ExistentialDeposit: u64 = 1; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights ::with_sensible_defaults( - Weight::from_components(2u64 * constants::WEIGHT_PER_SECOND.ref_time(), u64::MAX), + Weight::from_parts(2u64 * constants::WEIGHT_PER_SECOND.ref_time(), u64::MAX), NORMAL_DISPATCH_RATIO, ); } diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index 07ad240afe159..eb95b699eba32 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -208,7 +208,7 @@ pub struct BlockWeights { impl Default for BlockWeights { fn default() -> Self { Self::with_sensible_defaults( - Weight::from_components(constants::WEIGHT_PER_SECOND.ref_time(), u64::MAX), + Weight::from_parts(constants::WEIGHT_PER_SECOND.ref_time(), u64::MAX), DEFAULT_NORMAL_RATIO, ) } diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index 8596a782c1fa7..2933d80099dd7 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -112,8 +112,8 @@ impl Weight { Self { ref_time: 0, proof_size } } - /// Construct [`Weight`] with weight components, namely reference time and storage size weights. - pub const fn from_components(ref_time: u64, proof_size: u64) -> Self { + /// Construct [`Weight`] from weight parts, namely reference time and proof size weights. + pub const fn from_parts(ref_time: u64, proof_size: u64) -> Self { Self { ref_time, proof_size } } @@ -455,8 +455,8 @@ mod tests { #[test] fn is_zero_works() { assert!(Weight::zero().is_zero()); - assert!(!Weight::from_components(1, 0).is_zero()); - assert!(!Weight::from_components(0, 1).is_zero()); + assert!(!Weight::from_parts(1, 0).is_zero()); + assert!(!Weight::from_parts(0, 1).is_zero()); assert!(!Weight::MAX.is_zero()); } } From ccc8f6cc3debf7276cbdff78c7a906be6221ca35 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 11 Oct 2022 14:41:43 -0400 Subject: [PATCH 1260/1472] Avoid Unstable Sort (#12455) * dont use unstable sort * remove comment * add clippy rule --- .cargo/config.toml | 5 +++-- bin/node/bench/src/core.rs | 2 +- client/rpc-servers/src/lib.rs | 2 +- frame/benchmarking/src/analysis.rs | 4 ++-- frame/contracts/src/wasm/runtime.rs | 6 +----- frame/election-provider-multi-phase/src/mock.rs | 2 +- frame/examples/basic/src/benchmarking.rs | 2 +- primitives/npos-elections/fuzzer/src/common.rs | 6 +++--- utils/frame/benchmarking-cli/src/shared/stats.rs | 2 +- 9 files changed, 14 insertions(+), 17 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 5355758f7a4fa..66b28b3485d86 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -18,14 +18,15 @@ rustflags = [ "-Aclippy::borrowed-box", # Reasonable to fix this one "-Aclippy::too-many-arguments", # (Turning this on would lead to) "-Aclippy::unnecessary_cast", # Types may change - "-Aclippy::identity-op", # One case where we do 0 + + "-Aclippy::identity-op", # One case where we do 0 + "-Aclippy::useless_conversion", # Types may change "-Aclippy::unit_arg", # styalistic. "-Aclippy::option-map-unit-fn", # styalistic - "-Aclippy::bind_instead_of_map", # styalistic + "-Aclippy::bind_instead_of_map", # styalistic "-Aclippy::erasing_op", # E.g. 0 * DOLLARS "-Aclippy::eq_op", # In tests we test equality. "-Aclippy::while_immutable_condition", # false positives "-Aclippy::needless_option_as_deref", # false positives "-Aclippy::derivable_impls", # false positives + "-Aclippy::stable_sort_primitive", # prefer stable sort ] diff --git a/bin/node/bench/src/core.rs b/bin/node/bench/src/core.rs index 3b3060a888349..b6ad3ecd80068 100644 --- a/bin/node/bench/src/core.rs +++ b/bin/node/bench/src/core.rs @@ -132,7 +132,7 @@ pub fn run_benchmark(benchmark: Box, mode: Mode) -> Be durations.push(duration.as_nanos()); } - durations.sort_unstable(); + durations.sort(); let raw_average = (durations.iter().sum::() / (durations.len() as u128)) as u64; let average = (durations.iter().skip(10).take(30).sum::() / 30) as u64; diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 0e2aca0dcc829..7eb825e169bfa 100644 --- a/client/rpc-servers/src/lib.rs +++ b/client/rpc-servers/src/lib.rs @@ -198,7 +198,7 @@ fn format_allowed_hosts(addrs: &[SocketAddr]) -> Vec { fn build_rpc_api(mut rpc_api: RpcModule) -> RpcModule { let mut available_methods = rpc_api.method_names().collect::>(); - available_methods.sort_unstable(); + available_methods.sort(); rpc_api .register_method("rpc_methods", move |_, _| { diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index 9ba2ea657bab0..a736cdc203182 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -181,7 +181,7 @@ impl Analysis { }) .collect(); - values.sort_unstable(); + values.sort(); let mid = values.len() / 2; Some(Self { @@ -311,7 +311,7 @@ impl Analysis { } for (_, rs) in results.iter_mut() { - rs.sort_unstable(); + rs.sort(); let ql = rs.len() / 4; *rs = rs[ql..rs.len() - ql].to_vec(); } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 3296492994071..6d7e6bcf69e5f 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -1976,11 +1976,7 @@ pub mod env { data_len: u32, ) -> Result<(), TrapReason> { fn has_duplicates(items: &mut Vec) -> bool { - // # Warning - // - // Unstable sorts are non-deterministic across architectures. The usage here is OK - // because we are rejecting duplicates which removes the non determinism. - items.sort_unstable(); + items.sort(); // Find any two consecutive equal elements. items.windows(2).any(|w| match &w { &[a, b] => a == b, diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 6a638c8d2a2e1..e04e0bf474caf 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -155,7 +155,7 @@ pub fn trim_helpers() -> TrimHelpers { seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None).unwrap(); // sort by decreasing order of stake - assignments.sort_unstable_by_key(|assignment| { + assignments.sort_by_key(|assignment| { std::cmp::Reverse(stakes.get(&assignment.who).cloned().unwrap_or_default()) }); diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index 4d1659af46460..87d65a0bfa5b6 100644 --- a/frame/examples/basic/src/benchmarking.rs +++ b/frame/examples/basic/src/benchmarking.rs @@ -63,7 +63,7 @@ benchmarks! { } }: { // The benchmark execution phase could also be a closure with custom code - m.sort_unstable(); + m.sort(); } // This line generates test cases for benchmarking, and could be run by: diff --git a/primitives/npos-elections/fuzzer/src/common.rs b/primitives/npos-elections/fuzzer/src/common.rs index e5853f28c4929..ad9bd43f9bce0 100644 --- a/primitives/npos-elections/fuzzer/src/common.rs +++ b/primitives/npos-elections/fuzzer/src/common.rs @@ -80,7 +80,7 @@ pub fn generate_random_npos_inputs( } candidates.push(id); } - candidates.sort_unstable(); + candidates.sort(); candidates.dedup(); assert_eq!(candidates.len(), candidate_count); @@ -99,11 +99,11 @@ pub fn generate_random_npos_inputs( let mut chosen_candidates = Vec::with_capacity(n_candidates_chosen); chosen_candidates.extend(candidates.choose_multiple(&mut rng, n_candidates_chosen)); - chosen_candidates.sort_unstable(); + chosen_candidates.sort(); voters.push((id, vote_weight, chosen_candidates)); } - voters.sort_unstable(); + voters.sort(); voters.dedup_by_key(|(id, _weight, _chosen_candidates)| *id); assert_eq!(voters.len(), voter_count); diff --git a/utils/frame/benchmarking-cli/src/shared/stats.rs b/utils/frame/benchmarking-cli/src/shared/stats.rs index 3234d5f2f94f7..ffae4a17724f8 100644 --- a/utils/frame/benchmarking-cli/src/shared/stats.rs +++ b/utils/frame/benchmarking-cli/src/shared/stats.rs @@ -112,7 +112,7 @@ impl Stats { /// Returns the specified percentile for the given data. /// This is best effort since it ignores the interpolation case. fn percentile(mut xs: Vec, p: f64) -> u64 { - xs.sort_unstable(); + xs.sort(); let index = (xs.len() as f64 * p).ceil() as usize - 1; xs[index.clamp(0, xs.len() - 1)] } From 94b731c4f7059662232fa7b5bdc5a64b17d69252 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 11 Oct 2022 22:20:13 +0200 Subject: [PATCH 1261/1472] Finalized block event triggers tx maintanance (#12305) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * finalized block event triggers tx maintanance * tx-pool: enactment helper introduced * tx-pool: ChainApi: added tree_route method * enactment logic implemented + tests Signed-off-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> * Some additional tests * minor improvements * trigger CI job * fix compilation errors ChainApi::tree_route return type changed to Result>, as some implementations (tests) are not required to provide this tree route. * formatting * trait removed * implementation slightly simplified (thanks to @koute) * get rid of Arc<> in EnactmentState return value * minor improvement * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Apply suggestions from code review * comment updated + formatting * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Davide Galassi * formatting * finalization notification bug fix + new test case + log::warn message when finalized block is being retracted by new event * added error message on tree_route failure * Apply suggestions from code review Co-authored-by: Bastian Köcher * use provided tree_route in Finalized event * Option removed from ChainApi::tree_route * doc added, test and logs improved * handle_enactment aligned with original implementation * use async-await * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Bastian Köcher * formatting + warn->debug * compilation error fix * enactment_state initializers added * enactment_state: Option removed * manual-seal: compilation & tests fix * manual-seal: tests fixed * tests cleanup * another compilation error fixed * TreeRoute::new added * get rid of pub hack * one more test added * formatting * TreeRoute::new doc added + formatting * Apply suggestions from code review Co-authored-by: Davide Galassi * (bool,Option) simplified to Option * log message improved * yet another review suggestions applied * get rid of hash in handle_enactment * Apply suggestions from code review Co-authored-by: Bastian Köcher * Update client/transaction-pool/src/lib.rs Co-authored-by: Bastian Köcher * minor corrections * EnactmentState moved to new file * File header corrected * error formatting aligned with codebase * Apply suggestions from code review Co-authored-by: Bastian Köcher * remove commented code * small nits Signed-off-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Davide Galassi Co-authored-by: Bastian Köcher Co-authored-by: André Silva --- Cargo.lock | 2 + client/consensus/manual-seal/src/lib.rs | 28 +- client/transaction-pool/Cargo.toml | 1 + client/transaction-pool/api/Cargo.toml | 1 + client/transaction-pool/api/src/lib.rs | 4 +- client/transaction-pool/benches/basics.rs | 8 + client/transaction-pool/src/api.rs | 30 +- .../transaction-pool/src/enactment_state.rs | 579 ++++++++++++++++ client/transaction-pool/src/graph/pool.rs | 8 + client/transaction-pool/src/lib.rs | 346 +++++----- client/transaction-pool/src/tests.rs | 9 + client/transaction-pool/tests/pool.rs | 624 +++++++++++++++++- primitives/blockchain/src/header_metadata.rs | 7 + .../runtime/transaction-pool/src/lib.rs | 10 +- 14 files changed, 1466 insertions(+), 191 deletions(-) create mode 100644 client/transaction-pool/src/enactment_state.rs diff --git a/Cargo.lock b/Cargo.lock index 04b90dfffba1e..d29023f330ce1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9044,6 +9044,7 @@ version = "4.0.0-dev" dependencies = [ "array-bytes", "assert_matches", + "async-trait", "criterion", "futures", "futures-timer", @@ -9075,6 +9076,7 @@ dependencies = [ name = "sc-transaction-pool-api" version = "4.0.0-dev" dependencies = [ + "async-trait", "futures", "log", "serde", diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index 4672e7275a56b..09ab139b91c73 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -305,9 +305,8 @@ pub async fn run_instant_seal_and_finalize( mod tests { use super::*; use sc_basic_authorship::ProposerFactory; - use sc_client_api::BlockBackend; use sc_consensus::ImportedAux; - use sc_transaction_pool::{BasicPool, Options, RevalidationType}; + use sc_transaction_pool::{BasicPool, FullChainApi, Options, RevalidationType}; use sc_transaction_pool_api::{MaintainedTransactionPool, TransactionPool, TransactionSource}; use sp_inherents::InherentData; use sp_runtime::generic::{BlockId, Digest, DigestItem}; @@ -359,6 +358,7 @@ mod tests { let (client, select_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); + let genesis_hash = client.header(&BlockId::Number(0)).unwrap().unwrap().hash(); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -367,6 +367,8 @@ mod tests { RevalidationType::Full, spawner.clone(), 0, + genesis_hash, + genesis_hash, )); let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); // this test checks that blocks are created as soon as transactions are imported into the @@ -429,6 +431,7 @@ mod tests { let (client, select_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); + let genesis_hash = client.header(&BlockId::Number(0)).unwrap().unwrap().hash(); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -437,6 +440,8 @@ mod tests { RevalidationType::Full, spawner.clone(), 0, + genesis_hash, + genesis_hash, )); let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); // this test checks that blocks are created as soon as an engine command is sent over the @@ -505,8 +510,13 @@ mod tests { let builder = TestClientBuilder::new(); let (client, select_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); - let pool_api = api(); + let pool_api = Arc::new(FullChainApi::new( + client.clone(), + None, + &sp_core::testing::TaskExecutor::new(), + )); let spawner = sp_core::testing::TaskExecutor::new(); + let genesis_hash = client.header(&BlockId::Number(0)).unwrap().unwrap().hash(); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -515,6 +525,8 @@ mod tests { RevalidationType::Full, spawner.clone(), 0, + genesis_hash, + genesis_hash, )); let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); // this test checks that blocks are created as soon as an engine command is sent over the @@ -550,7 +562,6 @@ mod tests { .await .unwrap(); let created_block = rx.await.unwrap().unwrap(); - pool_api.increment_nonce(Alice.into()); // assert that the background task returns ok assert_eq!( @@ -566,8 +577,7 @@ mod tests { } } ); - let block = client.block(&BlockId::Number(1)).unwrap().unwrap().block; - pool_api.add_block(block, true); + assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Alice, 1)).await.is_ok()); let header = client.header(&BlockId::Number(1)).expect("db error").expect("imported above"); @@ -588,9 +598,6 @@ mod tests { .await .is_ok()); assert_matches::assert_matches!(rx1.await.expect("should be no error receiving"), Ok(_)); - let block = client.block(&BlockId::Number(2)).unwrap().unwrap().block; - pool_api.add_block(block, true); - pool_api.increment_nonce(Alice.into()); assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Bob, 0)).await.is_ok()); let (tx2, rx2) = futures::channel::oneshot::channel(); @@ -614,6 +621,7 @@ mod tests { let (client, select_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); + let genesis_hash = client.header(&BlockId::Number(0)).unwrap().unwrap().hash(); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -622,6 +630,8 @@ mod tests { RevalidationType::Full, spawner.clone(), 0, + genesis_hash, + genesis_hash, )); let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 5e005f5523ae8..0bdfb623e6c14 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -13,6 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" futures-timer = "3.0.2" diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 1ab0f32bc8bad..366d0eb99b945 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -9,6 +9,7 @@ repository = "https://github.com/paritytech/substrate/" description = "Transaction pool client facing API." [dependencies] +async-trait = "0.1.57" futures = "0.3.21" log = "0.4.17" serde = { version = "1.0.136", features = ["derive"] } diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index c0a94516ffc97..c1e49ad07d7b1 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -21,6 +21,7 @@ pub mod error; +use async_trait::async_trait; use futures::{Future, Stream}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp_runtime::{ @@ -303,9 +304,10 @@ pub enum ChainEvent { } /// Trait for transaction pool maintenance. +#[async_trait] pub trait MaintainedTransactionPool: TransactionPool { /// Perform maintenance - fn maintain(&self, event: ChainEvent) -> Pin + Send>>; + async fn maintain(&self, event: ChainEvent); } /// Transaction pool interface for submitting local transactions that exposes a diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index a7991269439ce..2632f8fb6aab5 100644 --- a/client/transaction-pool/benches/basics.rs +++ b/client/transaction-pool/benches/basics.rs @@ -121,6 +121,14 @@ impl ChainApi for TestApi { ) -> Result::Header>, Self::Error> { Ok(None) } + + fn tree_route( + &self, + _from: ::Hash, + _to: ::Hash, + ) -> Result, Self::Error> { + unimplemented!() + } } fn uxt(transfer: Transfer) -> Extrinsic { diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index 4710c96b003cd..110647b8cb3b0 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -30,6 +30,7 @@ use std::{marker::PhantomData, pin::Pin, sync::Arc}; use prometheus_endpoint::Registry as PrometheusRegistry; use sc_client_api::{blockchain::HeaderBackend, BlockBackend}; use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_blockchain::{HeaderMetadata, TreeRoute}; use sp_core::traits::SpawnEssentialNamed; use sp_runtime::{ generic::BlockId, @@ -111,8 +112,11 @@ impl FullChainApi { impl graph::ChainApi for FullChainApi where Block: BlockT, - Client: - ProvideRuntimeApi + BlockBackend + BlockIdTo + HeaderBackend, + Client: ProvideRuntimeApi + + BlockBackend + + BlockIdTo + + HeaderBackend + + HeaderMetadata, Client: Send + Sync + 'static, Client::Api: TaggedTransactionQueue, { @@ -190,6 +194,14 @@ where ) -> Result::Header>, Self::Error> { self.client.header(*at).map_err(Into::into) } + + fn tree_route( + &self, + from: ::Hash, + to: ::Hash, + ) -> Result, Self::Error> { + sp_blockchain::tree_route::(&*self.client, from, to).map_err(Into::into) + } } /// Helper function to validate a transaction using a full chain API. @@ -202,8 +214,11 @@ fn validate_transaction_blocking( ) -> error::Result where Block: BlockT, - Client: - ProvideRuntimeApi + BlockBackend + BlockIdTo + HeaderBackend, + Client: ProvideRuntimeApi + + BlockBackend + + BlockIdTo + + HeaderBackend + + HeaderMetadata, Client: Send + Sync + 'static, Client::Api: TaggedTransactionQueue, { @@ -264,8 +279,11 @@ where impl FullChainApi where Block: BlockT, - Client: - ProvideRuntimeApi + BlockBackend + BlockIdTo + HeaderBackend, + Client: ProvideRuntimeApi + + BlockBackend + + BlockIdTo + + HeaderBackend + + HeaderMetadata, Client: Send + Sync + 'static, Client::Api: TaggedTransactionQueue, { diff --git a/client/transaction-pool/src/enactment_state.rs b/client/transaction-pool/src/enactment_state.rs new file mode 100644 index 0000000000000..242b557dfbbbd --- /dev/null +++ b/client/transaction-pool/src/enactment_state.rs @@ -0,0 +1,579 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate transaction pool implementation. + +use sc_transaction_pool_api::ChainEvent; +use sp_blockchain::TreeRoute; +use sp_runtime::traits::Block as BlockT; + +/// Helper struct for keeping track of the current state of processed new best +/// block and finalized events. The main purpose of keeping track of this state +/// is to figure out if a transaction pool enactment is needed or not. +/// +/// Given the following chain: +/// +/// B1-C1-D1-E1 +/// / +/// A +/// \ +/// B2-C2-D2-E2 +/// +/// Some scenarios and expected behavior for sequence of `NewBestBlock` (`nbb`) and `Finalized` +/// (`f`) events: +/// +/// - `nbb(C1)`, `f(C1)` -> false (enactment was already performed in `nbb(C1))` +/// - `f(C1)`, `nbb(C1)` -> false (enactment was already performed in `f(C1))` +/// - `f(C1)`, `nbb(D2)` -> false (enactment was already performed in `f(C1)`, +/// we should not retract finalized block) +/// - `f(C1)`, `f(C2)`, `nbb(C1)` -> false +/// - `nbb(C1)`, `nbb(C2)` -> true (switching fork is OK) +/// - `nbb(B1)`, `nbb(B2)` -> true +/// - `nbb(B1)`, `nbb(C1)`, `f(C1)` -> false (enactment was already performed in `nbb(B1)`) +/// - `nbb(C1)`, `f(B1)` -> false (enactment was already performed in `nbb(B2)`) +pub struct EnactmentState +where + Block: BlockT, +{ + recent_best_block: Block::Hash, + recent_finalized_block: Block::Hash, +} + +impl EnactmentState +where + Block: BlockT, +{ + /// Returns a new `EnactmentState` initialized with the given parameters. + pub fn new(recent_best_block: Block::Hash, recent_finalized_block: Block::Hash) -> Self { + EnactmentState { recent_best_block, recent_finalized_block } + } + + /// Returns the recently finalized block. + pub fn recent_finalized_block(&self) -> Block::Hash { + self.recent_finalized_block + } + + /// Updates the state according to the given `ChainEvent`, returning + /// `Some(tree_route)` with a tree route including the blocks that need to + /// be enacted/retracted. If no enactment is needed then `None` is returned. + pub fn update( + &mut self, + event: &ChainEvent, + tree_route: &F, + ) -> Result>, String> + where + F: Fn(Block::Hash, Block::Hash) -> Result, String>, + { + let (new_hash, finalized) = match event { + ChainEvent::NewBestBlock { hash, .. } => (*hash, false), + ChainEvent::Finalized { hash, .. } => (*hash, true), + }; + + // block was already finalized + if self.recent_finalized_block == new_hash { + log::debug!(target: "txpool", "handle_enactment: block already finalized"); + return Ok(None) + } + + // compute actual tree route from best_block to notified block, and use + // it instead of tree_route provided with event + let tree_route = tree_route(self.recent_best_block, new_hash)?; + + log::debug!( + target: "txpool", + "resolve hash:{:?} finalized:{:?} tree_route:{:?} best_block:{:?} finalized_block:{:?}", + new_hash, finalized, tree_route, self.recent_best_block, self.recent_finalized_block + ); + + // check if recently finalized block is on retracted path. this could be + // happening if we first received a finalization event and then a new + // best event for some old stale best head. + if tree_route.retracted().iter().any(|x| x.hash == self.recent_finalized_block) { + log::debug!( + target: "txpool", + "Recently finalized block {} would be retracted by ChainEvent {}, skipping", + self.recent_finalized_block, new_hash + ); + return Ok(None) + } + + if finalized { + self.recent_finalized_block = new_hash; + + // if there are no enacted blocks in best_block -> hash tree_route, + // it means that block being finalized was already enacted (this + // case also covers best_block == new_hash), recent_best_block + // remains valid. + if tree_route.enacted().is_empty() { + log::trace!( + target: "txpool", + "handle_enactment: no newly enacted blocks since recent best block" + ); + return Ok(None) + } + + // otherwise enacted finalized block becomes best block... + } + + self.recent_best_block = new_hash; + + Ok(Some(tree_route)) + } +} + +#[cfg(test)] +mod enactment_state_tests { + use super::EnactmentState; + use sc_transaction_pool_api::ChainEvent; + use sp_blockchain::{HashAndNumber, TreeRoute}; + use std::sync::Arc; + use substrate_test_runtime_client::runtime::{Block, Hash}; + + // some helpers for convenient blocks' hash naming + fn a() -> HashAndNumber { + HashAndNumber { number: 1, hash: Hash::from([0xAA; 32]) } + } + fn b1() -> HashAndNumber { + HashAndNumber { number: 2, hash: Hash::from([0xB1; 32]) } + } + fn c1() -> HashAndNumber { + HashAndNumber { number: 3, hash: Hash::from([0xC1; 32]) } + } + fn d1() -> HashAndNumber { + HashAndNumber { number: 4, hash: Hash::from([0xD1; 32]) } + } + fn e1() -> HashAndNumber { + HashAndNumber { number: 5, hash: Hash::from([0xE1; 32]) } + } + fn b2() -> HashAndNumber { + HashAndNumber { number: 2, hash: Hash::from([0xB2; 32]) } + } + fn c2() -> HashAndNumber { + HashAndNumber { number: 3, hash: Hash::from([0xC2; 32]) } + } + fn d2() -> HashAndNumber { + HashAndNumber { number: 4, hash: Hash::from([0xD2; 32]) } + } + fn e2() -> HashAndNumber { + HashAndNumber { number: 5, hash: Hash::from([0xE2; 32]) } + } + + /// mock tree_route computing function for simple two-forks chain + fn tree_route(from: Hash, to: Hash) -> Result, String> { + let chain = vec![e1(), d1(), c1(), b1(), a(), b2(), c2(), d2(), e2()]; + let pivot = 4_usize; + + let from = chain + .iter() + .position(|bn| bn.hash == from) + .ok_or("existing block should be given")?; + let to = chain + .iter() + .position(|bn| bn.hash == to) + .ok_or("existing block should be given")?; + + // B1-C1-D1-E1 + // / + // A + // \ + // B2-C2-D2-E2 + // + // [E1 D1 C1 B1 A B2 C2 D2 E2] + + let vec: Vec> = if from < to { + chain.into_iter().skip(from).take(to - from + 1).collect() + } else { + chain.into_iter().skip(to).take(from - to + 1).rev().collect() + }; + + let pivot = if from <= pivot && to <= pivot { + if from < to { + to - from + } else { + 0 + } + } else if from >= pivot && to >= pivot { + if from < to { + 0 + } else { + from - to + } + } else { + if from < to { + pivot - from + } else { + from - pivot + } + }; + + Ok(TreeRoute::new(vec, pivot)) + } + + mod mock_tree_route_tests { + use super::*; + + /// asserts that tree routes are equal + fn assert_treeroute_eq(expected: TreeRoute, result: TreeRoute) { + assert_eq!(result.common_block().hash, expected.common_block().hash); + assert_eq!(result.enacted().len(), expected.enacted().len()); + assert_eq!(result.retracted().len(), expected.retracted().len()); + assert!(result + .enacted() + .iter() + .zip(expected.enacted().iter()) + .all(|(a, b)| a.hash == b.hash)); + assert!(result + .retracted() + .iter() + .zip(expected.retracted().iter()) + .all(|(a, b)| a.hash == b.hash)); + } + + // some tests for mock tree_route function + #[test] + fn tree_route_mock_test_01() { + let result = tree_route(b1().hash, a().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b1(), a()], 1); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_02() { + let result = tree_route(a().hash, b1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![a(), b1()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_03() { + let result = tree_route(a().hash, c2().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![a(), b2(), c2()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_04() { + let result = tree_route(e2().hash, a().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![e2(), d2(), c2(), b2(), a()], 4); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_05() { + let result = tree_route(d1().hash, b1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![d1(), c1(), b1()], 2); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_06() { + let result = tree_route(d2().hash, b2().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![d2(), c2(), b2()], 2); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_07() { + let result = tree_route(b1().hash, d1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b1(), c1(), d1()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_08() { + let result = tree_route(b2().hash, d2().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b2(), c2(), d2()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_09() { + let result = tree_route(e2().hash, e1().hash).expect("tree route exists"); + let expected = + TreeRoute::new(vec![e2(), d2(), c2(), b2(), a(), b1(), c1(), d1(), e1()], 4); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_10() { + let result = tree_route(e1().hash, e2().hash).expect("tree route exists"); + let expected = + TreeRoute::new(vec![e1(), d1(), c1(), b1(), a(), b2(), c2(), d2(), e2()], 4); + assert_treeroute_eq(result, expected); + } + #[test] + fn tree_route_mock_test_11() { + let result = tree_route(b1().hash, c2().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b1(), a(), b2(), c2()], 1); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_12() { + let result = tree_route(d2().hash, b1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![d2(), c2(), b2(), a(), b1()], 3); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_13() { + let result = tree_route(c2().hash, e1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![c2(), b2(), a(), b1(), c1(), d1(), e1()], 2); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_14() { + let result = tree_route(b1().hash, b1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b1()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_15() { + let result = tree_route(b2().hash, b2().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b2()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_16() { + let result = tree_route(a().hash, a().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![a()], 0); + assert_treeroute_eq(result, expected); + } + } + + fn trigger_new_best_block( + state: &mut EnactmentState, + from: HashAndNumber, + acted_on: HashAndNumber, + ) -> bool { + let (from, acted_on) = (from.hash, acted_on.hash); + + let event_tree_route = tree_route(from, acted_on).expect("Tree route exists"); + + state + .update( + &ChainEvent::NewBestBlock { + hash: acted_on, + tree_route: Some(Arc::new(event_tree_route)), + }, + &tree_route, + ) + .unwrap() + .is_some() + } + + fn trigger_finalized( + state: &mut EnactmentState, + from: HashAndNumber, + acted_on: HashAndNumber, + ) -> bool { + let (from, acted_on) = (from.hash, acted_on.hash); + + let v = tree_route(from, acted_on) + .expect("Tree route exists") + .enacted() + .iter() + .map(|h| h.hash) + .collect::>(); + + state + .update(&ChainEvent::Finalized { hash: acted_on, tree_route: v.into() }, &tree_route) + .unwrap() + .is_some() + } + + fn assert_es_eq( + es: &EnactmentState, + expected_best_block: HashAndNumber, + expected_finalized_block: HashAndNumber, + ) { + assert_eq!(es.recent_best_block, expected_best_block.hash); + assert_eq!(es.recent_finalized_block, expected_finalized_block.hash); + } + + #[test] + fn test_enactment_helper() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // B1-C1-D1-E1 + // / + // A + // \ + // B2-C2-D2-E2 + + let result = trigger_new_best_block(&mut es, a(), d1()); + assert!(result); + assert_es_eq(&es, d1(), a()); + + let result = trigger_new_best_block(&mut es, d1(), e1()); + assert!(result); + assert_es_eq(&es, e1(), a()); + + let result = trigger_finalized(&mut es, a(), d2()); + assert!(result); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_new_best_block(&mut es, d2(), e1()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_finalized(&mut es, a(), b2()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_finalized(&mut es, a(), b1()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_new_best_block(&mut es, a(), d2()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_finalized(&mut es, a(), d2()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_new_best_block(&mut es, a(), c2()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_new_best_block(&mut es, a(), c1()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_new_best_block(&mut es, d2(), e2()); + assert!(result); + assert_es_eq(&es, e2(), d2()); + + let result = trigger_finalized(&mut es, d2(), e2()); + assert_eq!(result, false); + assert_es_eq(&es, e2(), e2()); + } + + #[test] + fn test_enactment_helper_2() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // A-B1-C1-D1-E1 + + let result = trigger_new_best_block(&mut es, a(), b1()); + assert!(result); + assert_es_eq(&es, b1(), a()); + + let result = trigger_new_best_block(&mut es, b1(), c1()); + assert!(result); + assert_es_eq(&es, c1(), a()); + + let result = trigger_new_best_block(&mut es, c1(), d1()); + assert!(result); + assert_es_eq(&es, d1(), a()); + + let result = trigger_new_best_block(&mut es, d1(), e1()); + assert!(result); + assert_es_eq(&es, e1(), a()); + + let result = trigger_finalized(&mut es, a(), c1()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), c1()); + + let result = trigger_finalized(&mut es, c1(), e1()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), e1()); + } + + #[test] + fn test_enactment_helper_3() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // A-B1-C1-D1-E1 + + let result = trigger_new_best_block(&mut es, a(), e1()); + assert!(result); + assert_es_eq(&es, e1(), a()); + + let result = trigger_finalized(&mut es, a(), b1()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), b1()); + } + + #[test] + fn test_enactment_helper_4() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // A-B1-C1-D1-E1 + + let result = trigger_finalized(&mut es, a(), e1()); + assert!(result); + assert_es_eq(&es, e1(), e1()); + + let result = trigger_finalized(&mut es, e1(), b1()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), e1()); + } + + #[test] + fn test_enactment_helper_5() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // B1-C1-D1-E1 + // / + // A + // \ + // B2-C2-D2-E2 + + let result = trigger_finalized(&mut es, a(), e1()); + assert!(result); + assert_es_eq(&es, e1(), e1()); + + let result = trigger_finalized(&mut es, e1(), e2()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), e1()); + } + + #[test] + fn test_enactment_helper_6() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // A-B1-C1-D1-E1 + + let result = trigger_new_best_block(&mut es, a(), b1()); + assert!(result); + assert_es_eq(&es, b1(), a()); + + let result = trigger_finalized(&mut es, a(), d1()); + assert!(result); + assert_es_eq(&es, d1(), d1()); + + let result = trigger_new_best_block(&mut es, a(), e1()); + assert!(result); + assert_es_eq(&es, e1(), d1()); + + let result = trigger_new_best_block(&mut es, a(), c1()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), d1()); + } +} diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 108ae791e37b3..9afceffe8dddf 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -20,6 +20,7 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; use futures::{channel::mpsc::Receiver, Future}; use sc_transaction_pool_api::error; +use sp_blockchain::TreeRoute; use sp_runtime::{ generic::BlockId, traits::{self, Block as BlockT, SaturatedConversion}, @@ -97,6 +98,13 @@ pub trait ChainApi: Send + Sync { &self, at: &BlockId, ) -> Result::Header>, Self::Error>; + + /// Compute a tree-route between two blocks. See [`TreeRoute`] for more details. + fn tree_route( + &self, + from: ::Hash, + to: ::Hash, + ) -> Result, Self::Error>; } /// Pool configuration options. diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 7b9ce9d6047c0..410ab662e3601 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -23,6 +23,7 @@ #![warn(unused_extern_crates)] mod api; +mod enactment_state; pub mod error; mod graph; mod metrics; @@ -31,6 +32,8 @@ mod revalidation; mod tests; pub use crate::api::FullChainApi; +use async_trait::async_trait; +use enactment_state::EnactmentState; use futures::{ channel::oneshot, future::{self, ready}, @@ -62,6 +65,8 @@ use std::time::Instant; use crate::metrics::MetricsLink as PrometheusMetrics; use prometheus_endpoint::Registry as PrometheusRegistry; +use sp_blockchain::{HashAndNumber, TreeRoute}; + type BoxedReadyIterator = Box>> + Send>; @@ -85,6 +90,7 @@ where revalidation_queue: Arc>, ready_poll: Arc, Block>>>, metrics: PrometheusMetrics, + enactment_state: Arc>>, } struct ReadyPoll { @@ -163,7 +169,11 @@ where PoolApi: graph::ChainApi + 'static, { /// Create new basic transaction pool with provided api, for tests. - pub fn new_test(pool_api: Arc) -> (Self, Pin + Send>>) { + pub fn new_test( + pool_api: Arc, + best_block_hash: Block::Hash, + finalized_hash: Block::Hash, + ) -> (Self, Pin + Send>>) { let pool = Arc::new(graph::Pool::new(Default::default(), true.into(), pool_api.clone())); let (revalidation_queue, background_task) = revalidation::RevalidationQueue::new_background(pool_api.clone(), pool.clone()); @@ -175,6 +185,10 @@ where revalidation_strategy: Arc::new(Mutex::new(RevalidationStrategy::Always)), ready_poll: Default::default(), metrics: Default::default(), + enactment_state: Arc::new(Mutex::new(EnactmentState::new( + best_block_hash, + finalized_hash, + ))), }, background_task, ) @@ -190,6 +204,8 @@ where revalidation_type: RevalidationType, spawner: impl SpawnEssentialNamed, best_block_number: NumberFor, + best_block_hash: Block::Hash, + finalized_hash: Block::Hash, ) -> Self { let pool = Arc::new(graph::Pool::new(options, is_validator, pool_api.clone())); let (revalidation_queue, background_task) = match revalidation_type { @@ -217,6 +233,10 @@ where })), ready_poll: Arc::new(Mutex::new(ReadyPoll::new(best_block_number))), metrics: PrometheusMetrics::new(prometheus), + enactment_state: Arc::new(Mutex::new(EnactmentState::new( + best_block_hash, + finalized_hash, + ))), } } @@ -358,6 +378,7 @@ where + sp_runtime::traits::BlockIdTo + sc_client_api::ExecutorProvider + sc_client_api::UsageProvider + + sp_blockchain::HeaderMetadata + Send + Sync + 'static, @@ -380,6 +401,8 @@ where RevalidationType::Full, spawner, client.usage_info().chain.best_number, + client.usage_info().chain.best_hash, + client.usage_info().chain.finalized_hash, )); // make transaction pool available for off-chain runtime calls. @@ -396,7 +419,8 @@ where Client: sp_api::ProvideRuntimeApi + sc_client_api::BlockBackend + sc_client_api::blockchain::HeaderBackend - + sp_runtime::traits::BlockIdTo, + + sp_runtime::traits::BlockIdTo + + sp_blockchain::HeaderMetadata, Client: Send + Sync + 'static, Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, { @@ -563,166 +587,190 @@ async fn prune_known_txs_for_block MaintainedTransactionPool for BasicPool +impl BasicPool where Block: BlockT, PoolApi: 'static + graph::ChainApi, { - fn maintain(&self, event: ChainEvent) -> Pin + Send>> { - match event { - ChainEvent::NewBestBlock { hash, tree_route } => { - let pool = self.pool.clone(); - let api = self.api.clone(); - - let id = BlockId::hash(hash); - let block_number = match api.block_id_to_number(&id) { - Ok(Some(number)) => number, - _ => { - log::trace!( + /// Handles enactment and retraction of blocks, prunes stale transactions + /// (that have already been enacted) and resubmits transactions that were + /// retracted. + async fn handle_enactment(&self, tree_route: TreeRoute) { + log::trace!(target: "txpool", "handle_enactment tree_route: {tree_route:?}"); + let pool = self.pool.clone(); + let api = self.api.clone(); + + let (hash, block_number) = match tree_route.last() { + Some(HashAndNumber { hash, number }) => (hash, number), + None => { + log::warn!( + target: "txpool", + "Skipping ChainEvent - no last block in tree route {:?}", + tree_route, + ); + return + }, + }; + + let next_action = self.revalidation_strategy.lock().next( + *block_number, + Some(std::time::Duration::from_secs(60)), + Some(20u32.into()), + ); + + // We keep track of everything we prune so that later we won't add + // transactions with those hashes from the retracted blocks. + let mut pruned_log = HashSet::>::new(); + + // If there is a tree route, we use this to prune known tx based on the enacted + // blocks. Before pruning enacted transactions, we inform the listeners about + // retracted blocks and their transactions. This order is important, because + // if we enact and retract the same transaction at the same time, we want to + // send first the retract and than the prune event. + for retracted in tree_route.retracted() { + // notify txs awaiting finality that it has been retracted + pool.validated_pool().on_block_retracted(retracted.hash); + } + + future::join_all( + tree_route + .enacted() + .iter() + .map(|h| prune_known_txs_for_block(BlockId::Hash(h.hash), &*api, &*pool)), + ) + .await + .into_iter() + .for_each(|enacted_log| { + pruned_log.extend(enacted_log); + }); + + self.metrics + .report(|metrics| metrics.block_transactions_pruned.inc_by(pruned_log.len() as u64)); + + if next_action.resubmit { + let mut resubmit_transactions = Vec::new(); + + for retracted in tree_route.retracted() { + let hash = retracted.hash; + + let block_transactions = api + .block_body(&BlockId::hash(hash)) + .await + .unwrap_or_else(|e| { + log::warn!("Failed to fetch block body: {}", e); + None + }) + .unwrap_or_default() + .into_iter() + .filter(|tx| tx.is_signed().unwrap_or(true)); + + let mut resubmitted_to_report = 0; + + resubmit_transactions.extend(block_transactions.into_iter().filter(|tx| { + let tx_hash = pool.hash_of(tx); + let contains = pruned_log.contains(&tx_hash); + + // need to count all transactions, not just filtered, here + resubmitted_to_report += 1; + + if !contains { + log::debug!( target: "txpool", - "Skipping chain event - no number for that block {:?}", - id, + "[{:?}]: Resubmitting from retracted block {:?}", + tx_hash, + hash, ); - return Box::pin(ready(())) - }, - }; - - let next_action = self.revalidation_strategy.lock().next( - block_number, - Some(std::time::Duration::from_secs(60)), - Some(20u32.into()), - ); - let revalidation_strategy = self.revalidation_strategy.clone(); - let revalidation_queue = self.revalidation_queue.clone(); - let ready_poll = self.ready_poll.clone(); - let metrics = self.metrics.clone(); - - async move { - // We keep track of everything we prune so that later we won't add - // transactions with those hashes from the retracted blocks. - let mut pruned_log = HashSet::>::new(); - - // If there is a tree route, we use this to prune known tx based on the enacted - // blocks. Before pruning enacted transactions, we inform the listeners about - // retracted blocks and their transactions. This order is important, because - // if we enact and retract the same transaction at the same time, we want to - // send first the retract and than the prune event. - if let Some(ref tree_route) = tree_route { - for retracted in tree_route.retracted() { - // notify txs awaiting finality that it has been retracted - pool.validated_pool().on_block_retracted(retracted.hash); - } - - future::join_all(tree_route.enacted().iter().map(|h| { - prune_known_txs_for_block(BlockId::Hash(h.hash), &*api, &*pool) - })) - .await - .into_iter() - .for_each(|enacted_log| { - pruned_log.extend(enacted_log); - }) } + !contains + })); - pruned_log.extend(prune_known_txs_for_block(id, &*api, &*pool).await); - - metrics.report(|metrics| { - metrics.block_transactions_pruned.inc_by(pruned_log.len() as u64) - }); - - if let (true, Some(tree_route)) = (next_action.resubmit, tree_route) { - let mut resubmit_transactions = Vec::new(); - - for retracted in tree_route.retracted() { - let hash = retracted.hash; - - let block_transactions = api - .block_body(&BlockId::hash(hash)) - .await - .unwrap_or_else(|e| { - log::warn!("Failed to fetch block body: {}", e); - None - }) - .unwrap_or_default() - .into_iter() - .filter(|tx| tx.is_signed().unwrap_or(true)); - - let mut resubmitted_to_report = 0; - - resubmit_transactions.extend(block_transactions.into_iter().filter( - |tx| { - let tx_hash = pool.hash_of(tx); - let contains = pruned_log.contains(&tx_hash); - - // need to count all transactions, not just filtered, here - resubmitted_to_report += 1; - - if !contains { - log::debug!( - target: "txpool", - "[{:?}]: Resubmitting from retracted block {:?}", - tx_hash, - hash, - ); - } - !contains - }, - )); - - metrics.report(|metrics| { - metrics.block_transactions_resubmitted.inc_by(resubmitted_to_report) - }); - } - - if let Err(e) = pool - .resubmit_at( - &id, - // These transactions are coming from retracted blocks, we should - // simply consider them external. - TransactionSource::External, - resubmit_transactions, - ) - .await - { - log::debug!( - target: "txpool", - "[{:?}] Error re-submitting transactions: {}", - id, - e, - ) - } - } + self.metrics.report(|metrics| { + metrics.block_transactions_resubmitted.inc_by(resubmitted_to_report) + }); + } - let extra_pool = pool.clone(); - // After #5200 lands, this arguably might be moved to the - // handler of "all blocks notification". - ready_poll.lock().trigger(block_number, move || { - Box::new(extra_pool.validated_pool().ready()) - }); + if let Err(e) = pool + .resubmit_at( + &BlockId::Hash(*hash), + // These transactions are coming from retracted blocks, we should + // simply consider them external. + TransactionSource::External, + resubmit_transactions, + ) + .await + { + log::debug!( + target: "txpool", + "[{:?}] Error re-submitting transactions: {}", + hash, + e, + ) + } + } - if next_action.revalidate { - let hashes = pool.validated_pool().ready().map(|tx| tx.hash).collect(); - revalidation_queue.revalidate_later(block_number, hashes).await; + let extra_pool = pool.clone(); + // After #5200 lands, this arguably might be moved to the + // handler of "all blocks notification". + self.ready_poll + .lock() + .trigger(*block_number, move || Box::new(extra_pool.validated_pool().ready())); - revalidation_strategy.lock().clear(); - } - } - .boxed() + if next_action.revalidate { + let hashes = pool.validated_pool().ready().map(|tx| tx.hash).collect(); + self.revalidation_queue.revalidate_later(*block_number, hashes).await; + + self.revalidation_strategy.lock().clear(); + } + } +} + +#[async_trait] +impl MaintainedTransactionPool for BasicPool +where + Block: BlockT, + PoolApi: 'static + graph::ChainApi, +{ + async fn maintain(&self, event: ChainEvent) { + let prev_finalized_block = self.enactment_state.lock().recent_finalized_block(); + let compute_tree_route = |from, to| -> Result, String> { + match self.api.tree_route(from, to) { + Ok(tree_route) => Ok(tree_route), + Err(e) => + return Err(format!( + "Error occurred while computing tree_route from {from:?} to {to:?}: {e}" + )), + } + }; + + let result = self.enactment_state.lock().update(&event, &compute_tree_route); + + match result { + Err(msg) => { + log::warn!(target: "txpool", "{msg}"); + return }, - ChainEvent::Finalized { hash, tree_route } => { - let pool = self.pool.clone(); - async move { - for hash in tree_route.iter().chain(&[hash]) { - if let Err(e) = pool.validated_pool().on_block_finalized(*hash).await { - log::warn!( - target: "txpool", - "Error [{}] occurred while attempting to notify watchers of finalization {}", - e, hash - ) - } - } - } - .boxed() + Ok(None) => {}, + Ok(Some(tree_route)) => { + self.handle_enactment(tree_route).await; }, + }; + + if let ChainEvent::Finalized { hash, tree_route } = event { + log::trace!( + target: "txpool", + "on-finalized enacted: {tree_route:?}, previously finalized: \ + {prev_finalized_block:?}", + ); + + for hash in tree_route.iter().chain(std::iter::once(&hash)) { + if let Err(e) = self.pool.validated_pool().on_block_finalized(*hash).await { + log::warn!( + target: "txpool", + "Error occurred while attempting to notify watchers about finalization {}: {}", + hash, e + ) + } + } } } } diff --git a/client/transaction-pool/src/tests.rs b/client/transaction-pool/src/tests.rs index 79142e16a1b36..ce2c7872e32bb 100644 --- a/client/transaction-pool/src/tests.rs +++ b/client/transaction-pool/src/tests.rs @@ -22,6 +22,7 @@ use crate::graph::{BlockHash, ChainApi, ExtrinsicFor, NumberFor, Pool}; use codec::Encode; use parking_lot::Mutex; use sc_transaction_pool_api::error; +use sp_blockchain::TreeRoute; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Hash}, @@ -173,6 +174,14 @@ impl ChainApi for TestApi { ) -> Result::Header>, Self::Error> { Ok(None) } + + fn tree_route( + &self, + _from: ::Hash, + _to: ::Hash, + ) -> Result, Self::Error> { + unimplemented!() + } } pub(crate) fn uxt(transfer: Transfer) -> Extrinsic { diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index be75523c1230f..5590051768e9a 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -30,13 +30,14 @@ use sc_transaction_pool::*; use sc_transaction_pool_api::{ ChainEvent, MaintainedTransactionPool, TransactionPool, TransactionStatus, }; +use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use sp_runtime::{ generic::BlockId, traits::Block as _, transaction_validity::{InvalidTransaction, TransactionSource, ValidTransaction}, }; -use std::{collections::BTreeSet, sync::Arc}; +use std::{collections::BTreeSet, pin::Pin, sync::Arc}; use substrate_test_runtime_client::{ runtime::{Block, Extrinsic, Hash, Header, Index, Transfer}, AccountKeyring::*, @@ -50,13 +51,32 @@ fn pool() -> Pool { fn maintained_pool() -> (BasicPool, Arc, futures::executor::ThreadPool) { let api = Arc::new(TestApi::with_alice_nonce(209)); - let (pool, background_task) = BasicPool::new_test(api.clone()); + let (pool, background_task) = create_basic_pool_with_genesis(api.clone()); let thread_pool = futures::executor::ThreadPool::new().unwrap(); thread_pool.spawn_ok(background_task); (pool, api, thread_pool) } +fn create_basic_pool_with_genesis( + test_api: Arc, +) -> (BasicPool, Pin + Send>>) { + let genesis_hash = { + test_api + .chain() + .read() + .block_by_number + .get(&0) + .map(|blocks| blocks[0].0.header.hash()) + .expect("there is block 0. qed") + }; + BasicPool::new_test(test_api, genesis_hash, genesis_hash) +} + +fn create_basic_pool(test_api: TestApi) -> BasicPool { + create_basic_pool_with_genesis(Arc::from(test_api)).0 +} + const SOURCE: TransactionSource = TransactionSource::External; #[test] @@ -436,7 +456,7 @@ fn finalization() { let xt = uxt(Alice, 209); let api = TestApi::with_alice_nonce(209); api.push_block(1, vec![], true); - let (pool, _background) = BasicPool::new_test(api.into()); + let pool = create_basic_pool(api); let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())) .expect("1. Imported"); pool.api().push_block(2, vec![xt.clone()], true); @@ -459,9 +479,9 @@ fn finalization() { fn fork_aware_finalization() { let api = TestApi::empty(); // starting block A1 (last finalized.) - api.push_block(1, vec![], true); + let a_header = api.push_block(1, vec![], true); - let (pool, _background) = BasicPool::new_test(api.into()); + let pool = create_basic_pool(api); let mut canon_watchers = vec![]; let from_alice = uxt(Alice, 1); @@ -476,10 +496,13 @@ fn fork_aware_finalization() { let from_dave_watcher; let from_bob_watcher; let b1; + let c1; let d1; let c2; let d2; + block_on(pool.maintain(block_event(a_header))); + // block B1 { let watcher = @@ -489,6 +512,7 @@ fn fork_aware_finalization() { canon_watchers.push((watcher, header.hash())); assert_eq!(pool.status().ready, 1); + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; b1 = header.hash(); block_on(pool.maintain(event)); @@ -504,6 +528,7 @@ fn fork_aware_finalization() { block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_dave.clone())) .expect("1. Imported"); assert_eq!(pool.status().ready, 1); + log::trace!(target:"txpool", ">> C2: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; c2 = header.hash(); block_on(pool.maintain(event)); @@ -518,6 +543,7 @@ fn fork_aware_finalization() { assert_eq!(pool.status().ready, 1); let header = pool.api().push_block_with_parent(c2, vec![from_bob.clone()], true); + log::trace!(target:"txpool", ">> D2: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; d2 = header.hash(); block_on(pool.maintain(event)); @@ -530,8 +556,9 @@ fn fork_aware_finalization() { block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_charlie.clone())) .expect("1.Imported"); assert_eq!(pool.status().ready, 1); - let header = pool.api().push_block(3, vec![from_charlie.clone()], true); - + let header = pool.api().push_block_with_parent(b1, vec![from_charlie.clone()], true); + log::trace!(target:"txpool", ">> C1: {:?} {:?}", header.hash(), header); + c1 = header.hash(); canon_watchers.push((watcher, header.hash())); let event = block_event_with_retracted(header.clone(), d2, pool.api()); block_on(pool.maintain(event)); @@ -547,11 +574,12 @@ fn fork_aware_finalization() { let w = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())) .expect("1. Imported"); assert_eq!(pool.status().ready, 3); - let header = pool.api().push_block(4, vec![xt.clone()], true); + let header = pool.api().push_block_with_parent(c1, vec![xt.clone()], true); + log::trace!(target:"txpool", ">> D1: {:?} {:?}", header.hash(), header); + d1 = header.hash(); canon_watchers.push((w, header.hash())); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; - d1 = header.hash(); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 2); let event = ChainEvent::Finalized { hash: d1, tree_route: Arc::from(vec![]) }; @@ -560,9 +588,10 @@ fn fork_aware_finalization() { let e1; - // block e1 + // block E1 { - let header = pool.api().push_block(5, vec![from_dave, from_bob], true); + let header = pool.api().push_block_with_parent(d1, vec![from_dave, from_bob], true); + log::trace!(target:"txpool", ">> E1: {:?} {:?}", header.hash(), header); e1 = header.hash(); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; block_on(pool.maintain(event)); @@ -610,7 +639,7 @@ fn prune_and_retract_tx_at_same_time() { // starting block A1 (last finalized.) api.push_block(1, vec![], true); - let (pool, _background) = BasicPool::new_test(api.into()); + let pool = create_basic_pool(api); let from_alice = uxt(Alice, 1); pool.api().increment_nonce(Alice.into()); @@ -676,7 +705,7 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() { // starting block A1 (last finalized.) api.push_block(1, vec![], true); - let (pool, _background) = BasicPool::new_test(api.into()); + let pool = create_basic_pool(api); let tx0 = uxt(Alice, 1); let tx1 = uxt(Dave, 2); @@ -721,7 +750,7 @@ fn resubmit_from_retracted_fork() { // starting block A1 (last finalized.) api.push_block(1, vec![], true); - let (pool, _background) = BasicPool::new_test(api.into()); + let pool = create_basic_pool(api); let tx0 = uxt(Alice, 1); let tx1 = uxt(Dave, 2); @@ -866,13 +895,14 @@ fn ready_set_should_eventually_resolve_when_block_update_arrives() { #[test] fn should_not_accept_old_signatures() { let client = Arc::new(substrate_test_runtime_client::new()); - + let best_hash = client.info().best_hash; + let finalized_hash = client.info().finalized_hash; let pool = Arc::new( - BasicPool::new_test(Arc::new(FullChainApi::new( - client, - None, - &sp_core::testing::TaskExecutor::new(), - ))) + BasicPool::new_test( + Arc::new(FullChainApi::new(client, None, &sp_core::testing::TaskExecutor::new())), + best_hash, + finalized_hash, + ) .0, ); @@ -908,12 +938,19 @@ fn should_not_accept_old_signatures() { fn import_notification_to_pool_maintain_works() { let mut client = Arc::new(substrate_test_runtime_client::new()); + let best_hash = client.info().best_hash; + let finalized_hash = client.info().finalized_hash; + let pool = Arc::new( - BasicPool::new_test(Arc::new(FullChainApi::new( - client.clone(), - None, - &sp_core::testing::TaskExecutor::new(), - ))) + BasicPool::new_test( + Arc::new(FullChainApi::new( + client.clone(), + None, + &sp_core::testing::TaskExecutor::new(), + )), + best_hash, + finalized_hash, + ) .0, ); @@ -998,3 +1035,540 @@ fn stale_transactions_are_pruned() { assert_eq!(pool.status().future, 0); assert_eq!(pool.status().ready, 0); } + +#[test] +fn finalized_only_handled_correctly() { + sp_tracing::try_init_simple(); + let xt = uxt(Alice, 209); + + let (pool, api, _guard) = maintained_pool(); + + let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone())) + .expect("1. Imported"); + assert_eq!(pool.status().ready, 1); + + let header = api.push_block(1, vec![xt], false); + + let event = + ChainEvent::Finalized { hash: header.clone().hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + + assert_eq!(pool.status().ready, 0); + + { + let mut stream = futures::executor::block_on_stream(watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(header.clone().hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(header.hash()))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn best_block_after_finalized_handled_correctly() { + sp_tracing::try_init_simple(); + let xt = uxt(Alice, 209); + + let (pool, api, _guard) = maintained_pool(); + + let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone())) + .expect("1. Imported"); + assert_eq!(pool.status().ready, 1); + + let header = api.push_block(1, vec![xt], true); + + let event = + ChainEvent::Finalized { hash: header.clone().hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + block_on(pool.maintain(block_event(header.clone()))); + + assert_eq!(pool.status().ready, 0); + + { + let mut stream = futures::executor::block_on_stream(watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(header.clone().hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(header.hash()))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn switching_fork_with_finalized_works() { + sp_tracing::try_init_simple(); + let api = TestApi::empty(); + // starting block A1 (last finalized.) + let a_header = api.push_block(1, vec![], true); + + let pool = create_basic_pool(api); + + let from_alice = uxt(Alice, 1); + let from_bob = uxt(Bob, 2); + pool.api().increment_nonce(Alice.into()); + pool.api().increment_nonce(Bob.into()); + + let from_alice_watcher; + let from_bob_watcher; + let b1_header; + let b2_header; + + // block B1 + { + from_alice_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + assert_eq!(pool.status().ready, 1); + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); + b1_header = header; + } + + // block B2 + { + from_bob_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) + .expect("1. Imported"); + let header = pool.api().push_block_with_parent( + a_header.hash(), + vec![from_alice.clone(), from_bob.clone()], + true, + ); + assert_eq!(pool.status().ready, 2); + + log::trace!(target:"txpool", ">> B2: {:?} {:?}", header.hash(), header); + b2_header = header; + } + + { + let event = ChainEvent::NewBestBlock { hash: b1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 1); + } + + { + let event = ChainEvent::Finalized { hash: b2_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + let mut stream = futures::executor::block_on_stream(from_alice_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2_header.hash()))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_bob_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2_header.hash()))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn switching_fork_multiple_times_works() { + sp_tracing::try_init_simple(); + let api = TestApi::empty(); + // starting block A1 (last finalized.) + let a_header = api.push_block(1, vec![], true); + + let pool = create_basic_pool(api); + + let from_alice = uxt(Alice, 1); + let from_bob = uxt(Bob, 2); + pool.api().increment_nonce(Alice.into()); + pool.api().increment_nonce(Bob.into()); + + let from_alice_watcher; + let from_bob_watcher; + let b1_header; + let b2_header; + + // block B1 + { + from_alice_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + assert_eq!(pool.status().ready, 1); + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); + b1_header = header; + } + + // block B2 + { + from_bob_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) + .expect("1. Imported"); + let header = pool.api().push_block_with_parent( + a_header.hash(), + vec![from_alice.clone(), from_bob.clone()], + true, + ); + assert_eq!(pool.status().ready, 2); + + log::trace!(target:"txpool", ">> B2: {:?} {:?}", header.hash(), header); + b2_header = header; + } + + { + // phase-0 + let event = ChainEvent::NewBestBlock { hash: b1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 1); + } + + { + // phase-1 + let event = block_event_with_retracted(b2_header.clone(), b1_header.hash(), pool.api()); + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 0); + } + + { + // phase-2 + let event = block_event_with_retracted(b1_header.clone(), b2_header.hash(), pool.api()); + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 1); + } + + { + // phase-3 + let event = ChainEvent::Finalized { hash: b2_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + let mut stream = futures::executor::block_on_stream(from_alice_watcher); + //phase-0 + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); + //phase-1 + assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); + //phase-2 + assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); + //phase-3 + assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2_header.hash()))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_bob_watcher); + //phase-1 + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); + //phase-2 + assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + //phase-3 + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2_header.hash()))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn two_blocks_delayed_finalization_works() { + sp_tracing::try_init_simple(); + let api = TestApi::empty(); + // starting block A1 (last finalized.) + let a_header = api.push_block(1, vec![], true); + + let pool = create_basic_pool(api); + + let from_alice = uxt(Alice, 1); + let from_bob = uxt(Bob, 2); + let from_charlie = uxt(Charlie, 3); + pool.api().increment_nonce(Alice.into()); + pool.api().increment_nonce(Bob.into()); + pool.api().increment_nonce(Charlie.into()); + + let from_alice_watcher; + let from_bob_watcher; + let from_charlie_watcher; + let b1_header; + let c1_header; + let d1_header; + + // block B1 + { + from_alice_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + assert_eq!(pool.status().ready, 1); + + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); + b1_header = header; + } + + // block C1 + { + from_bob_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); + assert_eq!(pool.status().ready, 2); + + log::trace!(target:"txpool", ">> C1: {:?} {:?}", header.hash(), header); + c1_header = header; + } + + // block D1 + { + from_charlie_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_charlie.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(c1_header.hash(), vec![from_charlie.clone()], true); + assert_eq!(pool.status().ready, 3); + + log::trace!(target:"txpool", ">> D1: {:?} {:?}", header.hash(), header); + d1_header = header; + } + + { + let event = ChainEvent::Finalized { hash: a_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 3); + } + + { + let event = ChainEvent::NewBestBlock { hash: d1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 0); + } + + { + let event = ChainEvent::Finalized { + hash: c1_header.hash(), + tree_route: Arc::from(vec![b1_header.hash()]), + }; + block_on(pool.maintain(event)); + } + + // this is to collect events from_charlie_watcher and make sure nothing was retracted + { + let event = ChainEvent::Finalized { hash: d1_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + let mut stream = futures::executor::block_on_stream(from_alice_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b1_header.hash()))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_bob_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(c1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(c1_header.hash()))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_charlie_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(d1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(d1_header.hash()))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn delayed_finalization_does_not_retract() { + sp_tracing::try_init_simple(); + let api = TestApi::empty(); + // starting block A1 (last finalized.) + let a_header = api.push_block(1, vec![], true); + + let pool = create_basic_pool(api); + + let from_alice = uxt(Alice, 1); + let from_bob = uxt(Bob, 2); + pool.api().increment_nonce(Alice.into()); + pool.api().increment_nonce(Bob.into()); + + let from_alice_watcher; + let from_bob_watcher; + let b1_header; + let c1_header; + + // block B1 + { + from_alice_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + assert_eq!(pool.status().ready, 1); + + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); + b1_header = header; + } + + // block C1 + { + from_bob_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); + assert_eq!(pool.status().ready, 2); + + log::trace!(target:"txpool", ">> C1: {:?} {:?}", header.hash(), header); + c1_header = header; + } + + { + // phase-0 + let event = ChainEvent::NewBestBlock { hash: b1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 1); + } + + { + // phase-1 + let event = ChainEvent::NewBestBlock { hash: c1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 0); + } + + { + // phase-2 + let event = ChainEvent::Finalized { hash: b1_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + // phase-3 + let event = ChainEvent::Finalized { hash: c1_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + let mut stream = futures::executor::block_on_stream(from_alice_watcher); + //phase-0 + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); + //phase-2 + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b1_header.hash()))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_bob_watcher); + //phase-0 + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + //phase-1 + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(c1_header.hash()))); + //phase-3 + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(c1_header.hash()))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn best_block_after_finalization_does_not_retract() { + sp_tracing::try_init_simple(); + let api = TestApi::empty(); + // starting block A1 (last finalized.) + let a_header = api.push_block(1, vec![], true); + + let pool = create_basic_pool(api); + + let from_alice = uxt(Alice, 1); + let from_bob = uxt(Bob, 2); + pool.api().increment_nonce(Alice.into()); + pool.api().increment_nonce(Bob.into()); + + let from_alice_watcher; + let from_bob_watcher; + let b1_header; + let c1_header; + + // block B1 + { + from_alice_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + assert_eq!(pool.status().ready, 1); + + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); + b1_header = header; + } + + // block C1 + { + from_bob_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); + assert_eq!(pool.status().ready, 2); + + log::trace!(target:"txpool", ">> C1: {:?} {:?}", header.hash(), header); + c1_header = header; + } + + { + let event = ChainEvent::Finalized { hash: a_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + let event = ChainEvent::Finalized { + hash: c1_header.hash(), + tree_route: Arc::from(vec![a_header.hash(), b1_header.hash()]), + }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 0); + } + + { + let event = ChainEvent::NewBestBlock { hash: b1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + } + + { + let mut stream = futures::executor::block_on_stream(from_alice_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b1_header.hash()))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_bob_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock(c1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized(c1_header.hash()))); + assert_eq!(stream.next(), None); + } +} diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index 46477a75b8a1f..0ced264d5c786 100644 --- a/primitives/blockchain/src/header_metadata.rs +++ b/primitives/blockchain/src/header_metadata.rs @@ -176,6 +176,13 @@ pub struct TreeRoute { } impl TreeRoute { + /// Creates a new `TreeRoute`. + /// + /// It is required that `pivot >= route.len()`, otherwise it may panics. + pub fn new(route: Vec>, pivot: usize) -> Self { + TreeRoute { route, pivot } + } + /// Get a slice of all retracted blocks in reverse order (towards common ancestor). pub fn retracted(&self) -> &[HashAndNumber] { &self.route[..self.pivot] diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index 4008427623499..dc8be78aa7397 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -22,7 +22,7 @@ use codec::Encode; use futures::future::ready; use parking_lot::RwLock; -use sp_blockchain::CachedHeaderMetadata; +use sp_blockchain::{CachedHeaderMetadata, TreeRoute}; use sp_runtime::{ generic::{self, BlockId}, traits::{ @@ -335,6 +335,14 @@ impl sc_transaction_pool::ChainApi for TestApi { self.chain.read().block_by_hash.get(hash).map(|b| b.header().clone()), }) } + + fn tree_route( + &self, + from: ::Hash, + to: ::Hash, + ) -> Result, Self::Error> { + sp_blockchain::tree_route::(self, from, to).map_err(Into::into) + } } impl sp_blockchain::HeaderMetadata for TestApi { From 88db102213b06be4a25e17d195589c57cd4ed435 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 12 Oct 2022 10:06:22 +0200 Subject: [PATCH 1262/1472] tx-pool: failing tests fixed (#12481) --- client/transaction-pool/tests/pool.rs | 62 +++++++++++++-------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 5590051768e9a..27891432753a4 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -1058,8 +1058,8 @@ fn finalized_only_handled_correctly() { { let mut stream = futures::executor::block_on_stream(watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(header.clone().hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((header.clone().hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((header.hash(), 0)))); assert_eq!(stream.next(), None); } } @@ -1087,8 +1087,8 @@ fn best_block_after_finalized_handled_correctly() { { let mut stream = futures::executor::block_on_stream(watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(header.clone().hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((header.clone().hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((header.hash(), 0)))); assert_eq!(stream.next(), None); } } @@ -1155,18 +1155,18 @@ fn switching_fork_with_finalized_works() { { let mut stream = futures::executor::block_on_stream(from_alice_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b2_header.hash(), 0)))); assert_eq!(stream.next(), None); } { let mut stream = futures::executor::block_on_stream(from_bob_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 1)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b2_header.hash(), 1)))); assert_eq!(stream.next(), None); } } @@ -1250,17 +1250,17 @@ fn switching_fork_multiple_times_works() { let mut stream = futures::executor::block_on_stream(from_alice_watcher); //phase-0 assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); //phase-1 assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 0)))); //phase-2 assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b2_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); //phase-3 assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b2_header.hash(), 0)))); assert_eq!(stream.next(), None); } @@ -1268,13 +1268,13 @@ fn switching_fork_multiple_times_works() { let mut stream = futures::executor::block_on_stream(from_bob_watcher); //phase-1 assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 1)))); //phase-2 assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b2_header.hash()))); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); //phase-3 - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 1)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b2_header.hash(), 1)))); assert_eq!(stream.next(), None); } } @@ -1373,24 +1373,24 @@ fn two_blocks_delayed_finalization_works() { { let mut stream = futures::executor::block_on_stream(from_alice_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b1_header.hash(), 0)))); assert_eq!(stream.next(), None); } { let mut stream = futures::executor::block_on_stream(from_bob_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(c1_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(c1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((c1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((c1_header.hash(), 0)))); assert_eq!(stream.next(), None); } { let mut stream = futures::executor::block_on_stream(from_charlie_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(d1_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(d1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((d1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((d1_header.hash(), 0)))); assert_eq!(stream.next(), None); } } @@ -1472,9 +1472,9 @@ fn delayed_finalization_does_not_retract() { let mut stream = futures::executor::block_on_stream(from_alice_watcher); //phase-0 assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); //phase-2 - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b1_header.hash(), 0)))); assert_eq!(stream.next(), None); } @@ -1483,9 +1483,9 @@ fn delayed_finalization_does_not_retract() { //phase-0 assert_eq!(stream.next(), Some(TransactionStatus::Ready)); //phase-1 - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(c1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((c1_header.hash(), 0)))); //phase-3 - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(c1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((c1_header.hash(), 0)))); assert_eq!(stream.next(), None); } } @@ -1559,16 +1559,16 @@ fn best_block_after_finalization_does_not_retract() { { let mut stream = futures::executor::block_on_stream(from_alice_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b1_header.hash(), 0)))); assert_eq!(stream.next(), None); } { let mut stream = futures::executor::block_on_stream(from_bob_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(c1_header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(c1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((c1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((c1_header.hash(), 0)))); assert_eq!(stream.next(), None); } } From 06a9f0a5da9681287f8a1c7b53497921238ece81 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 12 Oct 2022 15:01:54 +0200 Subject: [PATCH 1263/1472] Clarify the "direction" field of block requests (#12438) --- client/network/sync/src/schema/api.v1.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/client/network/sync/src/schema/api.v1.proto b/client/network/sync/src/schema/api.v1.proto index 203b157470a58..1490f61a41ddd 100644 --- a/client/network/sync/src/schema/api.v1.proto +++ b/client/network/sync/src/schema/api.v1.proto @@ -24,6 +24,7 @@ message BlockRequest { bytes number = 3; } // Sequence direction. + // If missing, should be interpreted as "Ascending". Direction direction = 5; // Maximum number of blocks to return. An implementation defined maximum is used when unspecified. uint32 max_blocks = 6; // optional From f8a0b7a9569f9554db157ec9cc6b6a08dadc6eb6 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 12 Oct 2022 18:10:31 +0200 Subject: [PATCH 1264/1472] BlockId::Number refactor: trivial changes to BlockId::Hash (#12471) * Trivial BlockId::Number => Hash * missed BlockId::Hash added --- client/consensus/aura/src/lib.rs | 2 +- client/db/benches/state_access.rs | 2 +- test-utils/runtime/src/lib.rs | 6 +++--- utils/frame/benchmarking-cli/src/storage/cmd.rs | 2 +- utils/frame/benchmarking-cli/src/storage/read.rs | 2 +- utils/frame/benchmarking-cli/src/storage/write.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index a0eed6e35310e..734cecca9b30b 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -769,7 +769,7 @@ mod tests { assert_eq!(client.chain_info().best_number, 0); assert_eq!( - authorities(&client, &BlockId::Number(0)).unwrap(), + authorities(&client, &BlockId::Hash(client.chain_info().best_hash)).unwrap(), vec![ Keyring::Alice.public().into(), Keyring::Bob.public().into(), diff --git a/client/db/benches/state_access.rs b/client/db/benches/state_access.rs index 714dda82d61b7..4f4c10bcc8f53 100644 --- a/client/db/benches/state_access.rs +++ b/client/db/benches/state_access.rs @@ -84,7 +84,7 @@ fn insert_blocks(db: &Backend, storage: Vec<(Vec, Vec)>) -> H256 .map(|(k, v)| (k.clone(), Some(v.clone()))) .collect::>(); - let (state_root, tx) = db.state_at(BlockId::Number(number - 1)).unwrap().storage_root( + let (state_root, tx) = db.state_at(BlockId::Hash(parent_hash)).unwrap().storage_root( changes.iter().map(|(k, v)| (k.as_slice(), v.as_deref())), StateVersion::V1, ); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 3db0e5510057b..8bda4ea602428 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -1340,7 +1340,7 @@ mod tests { .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .set_heap_pages(8) .build(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); // Try to allocate 1024k of memory on heap. This is going to fail since it is twice larger // than the heap. @@ -1369,7 +1369,7 @@ mod tests { let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); runtime_api.test_storage(&block_id).unwrap(); } @@ -1396,7 +1396,7 @@ mod tests { let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); runtime_api.test_witness(&block_id, proof, root).unwrap(); } diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index 1d91e8f0b0517..a4c4188dfe073 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -191,7 +191,7 @@ impl StorageCmd { B: BlockT + Debug, BA: ClientBackend, { - let block = BlockId::Number(client.usage_info().chain.best_number); + let block = BlockId::Hash(client.usage_info().chain.best_hash); let empty_prefix = StorageKey(Vec::new()); let mut keys = client.storage_keys(&block, &empty_prefix)?; let (mut rng, _) = new_rng(None); diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs index cba318f87ea98..5e8a310ea5c5a 100644 --- a/utils/frame/benchmarking-cli/src/storage/read.rs +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -41,7 +41,7 @@ impl StorageCmd { <::Header as HeaderT>::Number: From, { let mut record = BenchRecord::default(); - let block = BlockId::Number(client.usage_info().chain.best_number); + let block = BlockId::Hash(client.usage_info().chain.best_hash); info!("Preparing keys from block {}", block); // Load all keys and randomly shuffle them. diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index 9a3821a7095f8..0ef2a2f9ae113 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -57,7 +57,7 @@ impl StorageCmd { // Store the time that it took to write each value. let mut record = BenchRecord::default(); - let block = BlockId::Number(client.usage_info().chain.best_number); + let block = BlockId::Hash(client.usage_info().chain.best_hash); let header = client.header(block)?.ok_or("Header not found")?; let original_root = *header.state_root(); let trie = DbStateBuilder::::new(storage.clone(), original_root).build(); From b324e511771b4e2d809d8319b98f3e36083c9ee2 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 12 Oct 2022 12:32:10 -0400 Subject: [PATCH 1265/1472] Dont use benchmark range on constant functions (#12456) * dont use benchmark range on constant function * update weights * fix * new weights * Update frame/examples/basic/src/benchmarking.rs Co-authored-by: parity-processbot <> --- frame/examples/basic/src/benchmarking.rs | 17 +++--- frame/examples/basic/src/lib.rs | 2 +- frame/examples/basic/src/weights.rs | 78 +++++++++++------------- 3 files changed, 46 insertions(+), 51 deletions(-) diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index 87d65a0bfa5b6..13f069c23e27b 100644 --- a/frame/examples/basic/src/benchmarking.rs +++ b/frame/examples/basic/src/benchmarking.rs @@ -34,25 +34,26 @@ use frame_system::RawOrigin; // Details on using the benchmarks macro can be seen at: // https://paritytech.github.io/substrate/master/frame_benchmarking/trait.Benchmarking.html#tymethod.benchmarks benchmarks! { - // This will measure the execution time of `set_dummy` for b in [0..1000] range. + // This will measure the execution time of `set_dummy`. set_dummy_benchmark { - // This is the benchmark setup phase - let b in 0 .. 1000; - }: set_dummy(RawOrigin::Root, b.into()) // The execution phase is just running `set_dummy` extrinsic call + // This is the benchmark setup phase. + // `set_dummy` is a constant time function, hence we hard-code some random value here. + let value = 1000u32.into(); + }: set_dummy(RawOrigin::Root, value) // The execution phase is just running `set_dummy` extrinsic call verify { // This is the optional benchmark verification phase, asserting certain states. - assert_eq!(Pallet::::dummy(), Some(b.into())) + assert_eq!(Pallet::::dummy(), Some(value)) } - // This will measure the execution time of `accumulate_dummy` for b in [0..1000] range. + // This will measure the execution time of `accumulate_dummy`. // The benchmark execution phase is shorthanded. When the name of the benchmark case is the same // as the extrinsic call. `_(...)` is used to represent the extrinsic name. // The benchmark verification phase is omitted. accumulate_dummy { - let b in 0 .. 1000; + let value = 1000u32.into(); // The caller account is whitelisted for DB reads/write by the benchmarking macro. let caller: T::AccountId = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), b.into()) + }: _(RawOrigin::Signed(caller), value) // This will measure the execution time of sorting a vector. sort_vector { diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index f754348782cec..256529421caae 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -498,7 +498,7 @@ pub mod pallet { // The weight for this extrinsic we rely on the auto-generated `WeightInfo` from the // benchmark toolchain. #[pallet::weight( - ::WeightInfo::accumulate_dummy((*increase_by).saturated_into()) + ::WeightInfo::accumulate_dummy() )] pub fn accumulate_dummy(origin: OriginFor, increase_by: T::Balance) -> DispatchResult { // This is a public call, so we ensure that the origin is some signed account. diff --git a/frame/examples/basic/src/weights.rs b/frame/examples/basic/src/weights.rs index 986648b4302bc..a69f0824eac11 100644 --- a/frame/examples/basic/src/weights.rs +++ b/frame/examples/basic/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,34 +17,26 @@ //! Autogenerated weights for pallet_example_basic //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-03-15, STEPS: `[100, ]`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-10-09, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `Shawns-MacBook-Pro.local`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/release/substrate // benchmark -// --chain -// dev -// --execution -// wasm -// --wasm-execution -// compiled -// --pallet -// pallet_example_basic -// --extrinsic -// * -// --steps -// 100 -// --repeat -// 10 -// --raw -// --output -// ./ +// pallet +// --chain=dev +// --execution=wasm +// --wasm-execution=compiled +// --pallet=pallet_example_basic +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --output=./ // --template // ./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -54,48 +46,50 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_example_basic. pub trait WeightInfo { - fn set_dummy_benchmark(b: u32, ) -> Weight; - fn accumulate_dummy(b: u32, ) -> Weight; + fn set_dummy_benchmark() -> Weight; + fn accumulate_dummy() -> Weight; fn sort_vector(x: u32, ) -> Weight; } /// Weights for pallet_example_basic using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - fn set_dummy_benchmark(b: u32, ) -> Weight { - Weight::from_ref_time(5_834_000 as u64) - .saturating_add(Weight::from_ref_time(24_000 as u64).saturating_mul(b as u64)) + // Storage: BasicExample Dummy (r:0 w:1) + fn set_dummy_benchmark() -> Weight { + Weight::from_ref_time(19_000_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } - fn accumulate_dummy(b: u32, ) -> Weight { - Weight::from_ref_time(51_353_000 as u64) - .saturating_add(Weight::from_ref_time(14_000 as u64).saturating_mul(b as u64)) + // Storage: BasicExample Dummy (r:1 w:1) + fn accumulate_dummy() -> Weight { + Weight::from_ref_time(18_000_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } + /// The range of component `x` is `[0, 10000]`. fn sort_vector(x: u32, ) -> Weight { - Weight::from_ref_time(2_569_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(x as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(520 as u64).saturating_mul(x as u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - fn set_dummy_benchmark(b: u32, ) -> Weight { - Weight::from_ref_time(5_834_000 as u64) - .saturating_add(Weight::from_ref_time(24_000 as u64).saturating_mul(b as u64)) + // Storage: BasicExample Dummy (r:0 w:1) + fn set_dummy_benchmark() -> Weight { + Weight::from_ref_time(19_000_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } - fn accumulate_dummy(b: u32, ) -> Weight { - Weight::from_ref_time(51_353_000 as u64) - .saturating_add(Weight::from_ref_time(14_000 as u64).saturating_mul(b as u64)) + // Storage: BasicExample Dummy (r:1 w:1) + fn accumulate_dummy() -> Weight { + Weight::from_ref_time(18_000_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } + /// The range of component `x` is `[0, 10000]`. fn sort_vector(x: u32, ) -> Weight { - Weight::from_ref_time(2_569_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(x as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(520 as u64).saturating_mul(x as u64)) } } From 94941a892e9c625124afa8f3b28aedc5a6274059 Mon Sep 17 00:00:00 2001 From: Dmitrii Markin Date: Thu, 13 Oct 2022 12:24:31 +0300 Subject: [PATCH 1266/1472] Punish peers for duplicate GRANDPA neighbor messages (#12462) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Decrease peer reputation for duplicate GRANDPA neighbor messages. * Fix comparison * Fix update_peer_state() validity condition * Add negative test * Rework update_peer_state() validity condition, add tests * update_peer_state() validity condition: invert comparison * Split InvalidViewChange and DuplicateNeighborMessage misbehaviors * Enforce rate-limiting of duplicate GRANDPA neighbor packets * Update client/finality-grandpa/src/communication/gossip.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Make rolling clock back in a test safer Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- .../src/communication/gossip.rs | 151 +++++++++++++----- .../finality-grandpa/src/communication/mod.rs | 8 +- .../src/communication/periodic.rs | 17 +- 3 files changed, 124 insertions(+), 52 deletions(-) diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 1ba5e0da33c96..218b4b668c10f 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -35,7 +35,8 @@ //! impolite to send messages about r+1 or later. "future-round" messages can //! be dropped and ignored. //! -//! It is impolite to send a neighbor packet which moves backwards in protocol state. +//! It is impolite to send a neighbor packet which moves backwards or does not progress +//! protocol state. //! //! This is beneficial if it conveys some progress in the protocol state of the peer. //! @@ -97,7 +98,7 @@ use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnbound use sp_finality_grandpa::AuthorityId; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; -use super::{benefit, cost, Round, SetId}; +use super::{benefit, cost, Round, SetId, NEIGHBOR_REBROADCAST_PERIOD}; use crate::{environment, CatchUp, CompactCommit, SignedMessage}; use std::{ @@ -148,14 +149,15 @@ enum Consider { /// A view of protocol state. #[derive(Debug)] struct View { - round: Round, // the current round we are at. - set_id: SetId, // the current voter set id. - last_commit: Option, // commit-finalized block height, if any. + round: Round, // the current round we are at. + set_id: SetId, // the current voter set id. + last_commit: Option, // commit-finalized block height, if any. + last_update: Option, // last time we heard from peer, used for spamming detection. } impl Default for View { fn default() -> Self { - View { round: Round(1), set_id: SetId(0), last_commit: None } + View { round: Round(1), set_id: SetId(0), last_commit: None, last_update: None } } } @@ -225,7 +227,12 @@ impl LocalView { /// Converts the local view to a `View` discarding round and set id /// information about the last commit. fn as_view(&self) -> View<&N> { - View { round: self.round, set_id: self.set_id, last_commit: self.last_commit_height() } + View { + round: self.round, + set_id: self.set_id, + last_commit: self.last_commit_height(), + last_update: None, + } } /// Update the set ID. implies a reset to round 1. @@ -417,6 +424,8 @@ pub(super) struct FullCatchUpMessage { pub(super) enum Misbehavior { // invalid neighbor message, considering the last one. InvalidViewChange, + // duplicate neighbor message. + DuplicateNeighborMessage, // could not decode neighbor message. bytes-length of the packet. UndecodablePacket(i32), // Bad catch up message (invalid signatures). @@ -438,6 +447,7 @@ impl Misbehavior { match *self { InvalidViewChange => cost::INVALID_VIEW_CHANGE, + DuplicateNeighborMessage => cost::DUPLICATE_NEIGHBOR_MESSAGE, UndecodablePacket(bytes) => ReputationChange::new( bytes.saturating_mul(cost::PER_UNDECODABLE_BYTE), "Grandpa: Bad packet", @@ -488,20 +498,22 @@ struct Peers { second_stage_peers: HashSet, /// The randomly picked set of `LUCKY_PEERS` light clients we'll gossip commit messages to. lucky_light_peers: HashSet, + /// Neighbor packet rebroadcast period --- we reduce the reputation of peers sending duplicate + /// packets too often. + neighbor_rebroadcast_period: Duration, } -impl Default for Peers { - fn default() -> Self { +impl Peers { + fn new(neighbor_rebroadcast_period: Duration) -> Self { Peers { inner: Default::default(), first_stage_peers: Default::default(), second_stage_peers: Default::default(), lucky_light_peers: Default::default(), + neighbor_rebroadcast_period, } } -} -impl Peers { fn new_peer(&mut self, who: PeerId, role: ObservedRole) { match role { ObservedRole::Authority if self.first_stage_peers.len() < LUCKY_PEERS => { @@ -547,10 +559,23 @@ impl Peers { return Err(Misbehavior::InvalidViewChange) } + let now = Instant::now(); + let duplicate_packet = (update.set_id, update.round, Some(&update.commit_finalized_height)) == + (peer.view.set_id, peer.view.round, peer.view.last_commit.as_ref()); + + if duplicate_packet { + if let Some(last_update) = peer.view.last_update { + if now < last_update + self.neighbor_rebroadcast_period / 2 { + return Err(Misbehavior::DuplicateNeighborMessage) + } + } + } + peer.view = View { round: update.round, set_id: update.set_id, last_commit: Some(update.commit_finalized_height), + last_update: Some(now), }; trace!(target: "afg", "Peer {} updated view. Now at {:?}, {:?}", @@ -748,7 +773,7 @@ impl Inner { Inner { local_view: None, - peers: Peers::default(), + peers: Peers::new(NEIGHBOR_REBROADCAST_PERIOD), live_topics: KeepTopics::new(), next_rebroadcast: Instant::now() + REBROADCAST_AFTER, authorities: Vec::new(), @@ -758,13 +783,16 @@ impl Inner { } } - /// Note a round in the current set has started. + /// Note a round in the current set has started. Does nothing if the last + /// call to the function was with the same `round`. fn note_round(&mut self, round: Round) -> MaybeMessage { { let local_view = match self.local_view { None => return None, Some(ref mut v) => if v.round == round { + // Do not send neighbor packets out if `round` has not changed --- + // such behavior is punishable. return None } else { v @@ -803,6 +831,8 @@ impl Inner { ); self.authorities = authorities; } + // Do not send neighbor packets out if the `set_id` has not changed --- + // such behavior is punishable. return None } else { v @@ -816,7 +846,9 @@ impl Inner { self.multicast_neighbor_packet() } - /// Note that we've imported a commit finalizing a given block. + /// Note that we've imported a commit finalizing a given block. Does nothing if the last + /// call to the function was with the same or higher `finalized` number. + /// `set_id` & `round` are the ones the commit message is from. fn note_commit_finalized( &mut self, round: Round, @@ -1357,6 +1389,8 @@ impl GossipValidator { } /// Note that we've imported a commit finalizing a given block. + /// `set_id` & `round` are the ones the commit message is from and not necessarily + /// the latest set ID & round started. pub(super) fn note_commit_finalized( &self, round: Round, @@ -1647,11 +1681,12 @@ pub(super) struct PeerReport { #[cfg(test)] mod tests { - use super::{environment::SharedVoterSetState, *}; + use super::{super::NEIGHBOR_REBROADCAST_PERIOD, environment::SharedVoterSetState, *}; use crate::communication; use sc_network::config::Role; use sc_network_gossip::Validator as GossipValidatorT; use sp_core::{crypto::UncheckedFrom, H256}; + use std::time::Instant; use substrate_test_runtime_client::runtime::{Block, Header}; // some random config (not really needed) @@ -1684,7 +1719,12 @@ mod tests { #[test] fn view_vote_rules() { - let view = View { round: Round(100), set_id: SetId(1), last_commit: Some(1000u64) }; + let view = View { + round: Round(100), + set_id: SetId(1), + last_commit: Some(1000u64), + last_update: None, + }; assert_eq!(view.consider_vote(Round(98), SetId(1)), Consider::RejectPast); assert_eq!(view.consider_vote(Round(1), SetId(0)), Consider::RejectPast); @@ -1701,7 +1741,12 @@ mod tests { #[test] fn view_global_message_rules() { - let view = View { round: Round(100), set_id: SetId(2), last_commit: Some(1000u64) }; + let view = View { + round: Round(100), + set_id: SetId(2), + last_commit: Some(1000u64), + last_update: None, + }; assert_eq!(view.consider_global(SetId(3), 1), Consider::RejectFuture); assert_eq!(view.consider_global(SetId(3), 1000), Consider::RejectFuture); @@ -1719,7 +1764,7 @@ mod tests { #[test] fn unknown_peer_cannot_be_updated() { - let mut peers = Peers::default(); + let mut peers = Peers::new(NEIGHBOR_REBROADCAST_PERIOD); let id = PeerId::random(); let update = @@ -1750,27 +1795,35 @@ mod tests { let update4 = NeighborPacket { round: Round(3), set_id: SetId(11), commit_finalized_height: 80 }; - let mut peers = Peers::default(); + // Use shorter rebroadcast period to safely roll the clock back in the last test + // and don't hit the system boot time on systems with unsigned time. + const SHORT_NEIGHBOR_REBROADCAST_PERIOD: Duration = Duration::from_secs(1); + let mut peers = Peers::new(SHORT_NEIGHBOR_REBROADCAST_PERIOD); let id = PeerId::random(); peers.new_peer(id, ObservedRole::Authority); - let mut check_update = move |update: NeighborPacket<_>| { + let check_update = |peers: &mut Peers<_>, update: NeighborPacket<_>| { let view = peers.update_peer_state(&id, update.clone()).unwrap().unwrap(); assert_eq!(view.round, update.round); assert_eq!(view.set_id, update.set_id); assert_eq!(view.last_commit, Some(update.commit_finalized_height)); }; - check_update(update1); - check_update(update2); - check_update(update3); - check_update(update4); + check_update(&mut peers, update1); + check_update(&mut peers, update2); + check_update(&mut peers, update3); + check_update(&mut peers, update4.clone()); + + // Allow duplicate neighbor packets if enough time has passed. + peers.inner.get_mut(&id).unwrap().view.last_update = + Some(Instant::now() - SHORT_NEIGHBOR_REBROADCAST_PERIOD); + check_update(&mut peers, update4); } #[test] fn invalid_view_change() { - let mut peers = Peers::default(); + let mut peers = Peers::new(NEIGHBOR_REBROADCAST_PERIOD); let id = PeerId::random(); peers.new_peer(id, ObservedRole::Authority); @@ -1783,29 +1836,41 @@ mod tests { .unwrap() .unwrap(); - let mut check_update = move |update: NeighborPacket<_>| { + let mut check_update = move |update: NeighborPacket<_>, misbehavior| { let err = peers.update_peer_state(&id, update.clone()).unwrap_err(); - assert_eq!(err, Misbehavior::InvalidViewChange); + assert_eq!(err, misbehavior); }; // round moves backwards. - check_update(NeighborPacket { - round: Round(9), - set_id: SetId(10), - commit_finalized_height: 10, - }); - // commit finalized height moves backwards. - check_update(NeighborPacket { - round: Round(10), - set_id: SetId(10), - commit_finalized_height: 9, - }); + check_update( + NeighborPacket { round: Round(9), set_id: SetId(10), commit_finalized_height: 10 }, + Misbehavior::InvalidViewChange, + ); // set ID moves backwards. - check_update(NeighborPacket { - round: Round(10), - set_id: SetId(9), - commit_finalized_height: 10, - }); + check_update( + NeighborPacket { round: Round(10), set_id: SetId(9), commit_finalized_height: 10 }, + Misbehavior::InvalidViewChange, + ); + // commit finalized height moves backwards. + check_update( + NeighborPacket { round: Round(10), set_id: SetId(10), commit_finalized_height: 9 }, + Misbehavior::InvalidViewChange, + ); + // duplicate packet without grace period. + check_update( + NeighborPacket { round: Round(10), set_id: SetId(10), commit_finalized_height: 10 }, + Misbehavior::DuplicateNeighborMessage, + ); + // commit finalized height moves backwards while round moves forward. + check_update( + NeighborPacket { round: Round(11), set_id: SetId(10), commit_finalized_height: 9 }, + Misbehavior::InvalidViewChange, + ); + // commit finalized height moves backwards while set ID moves forward. + check_update( + NeighborPacket { round: Round(10), set_id: SetId(11), commit_finalized_height: 9 }, + Misbehavior::InvalidViewChange, + ); } #[test] diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 12cb2601f4c26..75a7697812c6c 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -37,6 +37,7 @@ use std::{ pin::Pin, sync::Arc, task::{Context, Poll}, + time::Duration, }; use finality_grandpa::{ @@ -68,6 +69,9 @@ mod periodic; #[cfg(test)] pub(crate) mod tests; +// How often to rebroadcast neighbor packets, in cases where no new packets are created. +pub(crate) const NEIGHBOR_REBROADCAST_PERIOD: Duration = Duration::from_secs(2 * 60); + pub mod grandpa_protocol_name { use sc_chain_spec::ChainSpec; use sc_network_common::protocol::ProtocolName; @@ -103,6 +107,8 @@ mod cost { pub(super) const UNKNOWN_VOTER: Rep = Rep::new(-150, "Grandpa: Unknown voter"); pub(super) const INVALID_VIEW_CHANGE: Rep = Rep::new(-500, "Grandpa: Invalid view change"); + pub(super) const DUPLICATE_NEIGHBOR_MESSAGE: Rep = + Rep::new(-500, "Grandpa: Duplicate neighbor message without grace period"); pub(super) const PER_UNDECODABLE_BYTE: i32 = -5; pub(super) const PER_SIGNATURE_CHECKED: i32 = -25; pub(super) const PER_BLOCK_LOADED: i32 = -10; @@ -279,7 +285,7 @@ impl> NetworkBridge { } let (neighbor_packet_worker, neighbor_packet_sender) = - periodic::NeighborPacketWorker::new(); + periodic::NeighborPacketWorker::new(NEIGHBOR_REBROADCAST_PERIOD); NetworkBridge { service, diff --git a/client/finality-grandpa/src/communication/periodic.rs b/client/finality-grandpa/src/communication/periodic.rs index e6d63beafc362..c001796b5ca5d 100644 --- a/client/finality-grandpa/src/communication/periodic.rs +++ b/client/finality-grandpa/src/communication/periodic.rs @@ -32,9 +32,6 @@ use super::gossip::{GossipMessage, NeighborPacket}; use sc_network::PeerId; use sp_runtime::traits::{Block as BlockT, NumberFor}; -// How often to rebroadcast, in cases where no new packets are created. -const REBROADCAST_AFTER: Duration = Duration::from_secs(2 * 60); - /// A sender used to send neighbor packets to a background job. #[derive(Clone)] pub(super) struct NeighborPacketSender( @@ -60,6 +57,7 @@ impl NeighborPacketSender { /// implementation). Periodically it sends out the last packet in cases where no new ones arrive. pub(super) struct NeighborPacketWorker { last: Option<(Vec, NeighborPacket>)>, + rebroadcast_period: Duration, delay: Delay, rx: TracingUnboundedReceiver<(Vec, NeighborPacket>)>, } @@ -67,13 +65,16 @@ pub(super) struct NeighborPacketWorker { impl Unpin for NeighborPacketWorker {} impl NeighborPacketWorker { - pub(super) fn new() -> (Self, NeighborPacketSender) { + pub(super) fn new(rebroadcast_period: Duration) -> (Self, NeighborPacketSender) { let (tx, rx) = tracing_unbounded::<(Vec, NeighborPacket>)>( "mpsc_grandpa_neighbor_packet_worker", ); - let delay = Delay::new(REBROADCAST_AFTER); + let delay = Delay::new(rebroadcast_period); - (NeighborPacketWorker { last: None, delay, rx }, NeighborPacketSender(tx)) + ( + NeighborPacketWorker { last: None, rebroadcast_period, delay, rx }, + NeighborPacketSender(tx), + ) } } @@ -85,7 +86,7 @@ impl Stream for NeighborPacketWorker { match this.rx.poll_next_unpin(cx) { Poll::Ready(None) => return Poll::Ready(None), Poll::Ready(Some((to, packet))) => { - this.delay.reset(REBROADCAST_AFTER); + this.delay.reset(this.rebroadcast_period); this.last = Some((to.clone(), packet.clone())); return Poll::Ready(Some((to, GossipMessage::::from(packet)))) @@ -98,7 +99,7 @@ impl Stream for NeighborPacketWorker { // Getting this far here implies that the timer fired. - this.delay.reset(REBROADCAST_AFTER); + this.delay.reset(this.rebroadcast_period); // Make sure the underlying task is scheduled for wake-up. // From 983b6b0e5d93a3f7d99d8b3d3a8bb398af3ec045 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Thu, 13 Oct 2022 12:37:09 +0300 Subject: [PATCH 1267/1472] Introduce mockable `ChainSync` object for testing (#12480) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Introduce mockable `ChainSync` object for testing `mockall` allows to mock `ChainSync` and to verify that the calls made to `ChaiSync` are firstly executed at all, that they're executed in correct order and with correct parameters. This allows to verify, e.g., that delegating calls directly to `ChainSync` from `NetworkService` still calls the correct functions with correct arguments even if `Protocol` middleman is removed. * Add Cargo.lock * Fix tests * Update client/network/Cargo.toml Co-authored-by: Bastian Köcher * Update Cargo.lock * Fix clippy and documentation Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> --- Cargo.lock | 58 +++ client/network/common/src/sync.rs | 14 +- client/network/src/protocol.rs | 2 +- client/network/src/service.rs | 2 + client/network/src/service/chainsync_tests.rs | 339 ++++++++++++++++++ client/network/sync/Cargo.toml | 1 + client/network/sync/src/lib.rs | 35 +- client/network/sync/src/mock.rs | 118 ++++++ 8 files changed, 546 insertions(+), 23 deletions(-) create mode 100644 client/network/src/service/chainsync_tests.rs create mode 100644 client/network/sync/src/mock.rs diff --git a/Cargo.lock b/Cargo.lock index d29023f330ce1..062195c70f8ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1717,6 +1717,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[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" @@ -2093,6 +2099,15 @@ dependencies = [ "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" @@ -2116,6 +2131,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fragile" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85dcb89d2b10c5f6133de2efd8c11959ce9dbb46a2f7a4cab208c4eeda6ce1ab" + [[package]] name = "frame-benchmarking" version = "4.0.0-dev" @@ -4395,6 +4416,33 @@ dependencies = [ "windows-sys 0.36.1", ] +[[package]] +name = "mockall" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2be9a9090bc1cac2930688fa9478092a64c6a92ddc6ae0692d46b37d9cab709" +dependencies = [ + "cfg-if 1.0.0", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d702a0530a0141cf4ed147cf5ec7be6f2c187d4e37fcbefc39cf34116bfe8f" +dependencies = [ + "cfg-if 1.0.0", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "more-asserts" version = "0.2.1" @@ -4970,6 +5018,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "num-bigint" version = "0.2.6" @@ -6942,8 +6996,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c143348f141cc87aab5b950021bac6145d0e5ae754b0591de23244cee42c9308" dependencies = [ "difflib", + "float-cmp", "itertools", + "normalize-line-endings", "predicates-core", + "regex", ] [[package]] @@ -8586,6 +8643,7 @@ dependencies = [ "libp2p", "log", "lru", + "mockall", "parity-scale-codec", "prost 0.11.0", "prost-build 0.11.1", diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index 020b2c9efa4c7..d3603c6792c84 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -269,12 +269,14 @@ pub trait ChainSync: Send { ); /// Get an iterator over all scheduled justification requests. - fn justification_requests( - &mut self, - ) -> Box)> + '_>; + fn justification_requests<'a>( + &'a mut self, + ) -> Box)> + 'a>; /// Get an iterator over all block requests of all peers. - fn block_requests(&mut self) -> Box)> + '_>; + fn block_requests<'a>( + &'a mut self, + ) -> Box)> + 'a>; /// Get a state request, if any. fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)>; @@ -359,9 +361,9 @@ pub trait ChainSync: Send { /// /// If [`PollBlockAnnounceValidation::ImportHeader`] is returned, then the caller MUST try to /// import passed header (call `on_block_data`). The network request isn't sent in this case. - fn poll_block_announce_validation( + fn poll_block_announce_validation<'a>( &mut self, - cx: &mut std::task::Context, + cx: &mut std::task::Context<'a>, ) -> Poll>; /// Call when a peer has disconnected. diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 325e044527efa..c3def8adc6cfe 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -1440,7 +1440,7 @@ where for (id, request) in self .chain_sync .block_requests() - .map(|(peer_id, request)| (*peer_id, request)) + .map(|(peer_id, request)| (peer_id, request)) .collect::>() { let event = diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 28e479b702779..25916041285a3 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -92,6 +92,8 @@ use std::{ pub use behaviour::{InboundFailure, OutboundFailure, ResponseFailure}; +#[cfg(test)] +mod chainsync_tests; mod metrics; mod out_events; #[cfg(test)] diff --git a/client/network/src/service/chainsync_tests.rs b/client/network/src/service/chainsync_tests.rs new file mode 100644 index 0000000000000..ca44c65d267f4 --- /dev/null +++ b/client/network/src/service/chainsync_tests.rs @@ -0,0 +1,339 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{config, NetworkWorker}; + +use futures::prelude::*; +use libp2p::PeerId; +use sc_block_builder::BlockBuilderProvider; +use sc_client_api::{BlockBackend, HeaderBackend}; +use sc_consensus::JustificationSyncLink; +use sc_network_common::{ + config::{ + NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, + TransportConfig, + }, + protocol::role::Roles, + service::NetworkSyncForkRequest, + sync::{message::BlockAnnouncesHandshake, ChainSync as ChainSyncT, SyncState, SyncStatus}, +}; +use sc_network_light::light_client_requests::handler::LightClientRequestHandler; +use sc_network_sync::{ + block_request_handler::BlockRequestHandler, mock::MockChainSync, + state_request_handler::StateRequestHandler, +}; +use sp_core::H256; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Header as _, Zero}, +}; +use std::{iter, sync::Arc, task::Poll}; +use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; + +type TestNetworkWorker = NetworkWorker< + substrate_test_runtime_client::runtime::Block, + substrate_test_runtime_client::runtime::Hash, + substrate_test_runtime_client::TestClient, +>; + +const BLOCK_ANNOUNCE_PROTO_NAME: &str = "/block-announces"; +const PROTOCOL_NAME: &str = "/foo"; + +fn make_network( + chain_sync: Box>, + client: Arc, +) -> (TestNetworkWorker, Arc) { + let network_config = config::NetworkConfiguration { + extra_sets: vec![NonDefaultSetConfig { + notifications_protocol: PROTOCOL_NAME.into(), + fallback_names: Vec::new(), + max_notification_size: 1024 * 1024, + handshake: None, + set_config: Default::default(), + }], + listen_addresses: vec![config::build_multiaddr![Memory(rand::random::())]], + transport: TransportConfig::MemoryOnly, + ..config::NetworkConfiguration::new_local() + }; + + #[derive(Clone)] + struct PassThroughVerifier(bool); + + #[async_trait::async_trait] + impl sc_consensus::Verifier for PassThroughVerifier { + async fn verify( + &mut self, + mut block: sc_consensus::BlockImportParams, + ) -> Result< + ( + sc_consensus::BlockImportParams, + Option)>>, + ), + String, + > { + let maybe_keys = block + .header + .digest() + .log(|l| { + l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"aura")) + .or_else(|| { + l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus( + b"babe", + )) + }) + }) + .map(|blob| { + vec![(sp_blockchain::well_known_cache_keys::AUTHORITIES, blob.to_vec())] + }); + + block.finalized = self.0; + block.fork_choice = Some(sc_consensus::ForkChoiceStrategy::LongestChain); + Ok((block, maybe_keys)) + } + } + + let import_queue = Box::new(sc_consensus::BasicQueue::new( + PassThroughVerifier(false), + Box::new(client.clone()), + None, + &sp_core::testing::TaskExecutor::new(), + None, + )); + + let protocol_id = ProtocolId::from("/test-protocol-name"); + + let fork_id = Some(String::from("test-fork-id")); + + let block_request_protocol_config = { + let (handler, protocol_config) = + BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); + async_std::task::spawn(handler.run().boxed()); + protocol_config + }; + + let state_request_protocol_config = { + let (handler, protocol_config) = + StateRequestHandler::new(&protocol_id, None, client.clone(), 50); + async_std::task::spawn(handler.run().boxed()); + protocol_config + }; + + let light_client_request_protocol_config = { + let (handler, protocol_config) = + LightClientRequestHandler::new(&protocol_id, None, client.clone()); + async_std::task::spawn(handler.run().boxed()); + protocol_config + }; + + let block_announce_config = NonDefaultSetConfig { + notifications_protocol: BLOCK_ANNOUNCE_PROTO_NAME.into(), + fallback_names: vec![], + max_notification_size: 1024 * 1024, + handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::< + substrate_test_runtime_client::runtime::Block, + >::build( + Roles::from(&config::Role::Full), + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ))), + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + }; + + let worker = NetworkWorker::new(config::Params { + block_announce_config, + role: config::Role::Full, + executor: None, + network_config, + chain: client.clone(), + protocol_id, + fork_id, + import_queue, + chain_sync, + metrics_registry: None, + block_request_protocol_config, + state_request_protocol_config, + light_client_request_protocol_config, + warp_sync_protocol_config: None, + request_response_protocol_configs: Vec::new(), + }) + .unwrap(); + + (worker, client) +} + +fn set_default_expecations_no_peers( + chain_sync: &mut MockChainSync, +) { + chain_sync.expect_block_requests().returning(|| Box::new(iter::empty())); + chain_sync.expect_state_request().returning(|| None); + chain_sync.expect_justification_requests().returning(|| Box::new(iter::empty())); + chain_sync.expect_warp_sync_request().returning(|| None); + chain_sync.expect_poll_block_announce_validation().returning(|_| Poll::Pending); + chain_sync.expect_status().returning(|| SyncStatus { + state: SyncState::Idle, + best_seen_block: None, + num_peers: 0u32, + queued_blocks: 0u32, + state_sync: None, + warp_sync: None, + }); +} + +#[async_std::test] +async fn normal_network_poll_no_peers() { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + let mut chain_sync = + Box::new(MockChainSync::::new()); + set_default_expecations_no_peers(&mut chain_sync); + + let (mut network, _) = make_network(chain_sync, client); + + // poll the network once + futures::future::poll_fn(|cx| { + let _ = network.poll_unpin(cx); + Poll::Ready(()) + }) + .await; +} + +#[async_std::test] +async fn request_justification() { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + let mut chain_sync = + Box::new(MockChainSync::::new()); + + let hash = H256::random(); + let number = 1337u64; + + chain_sync + .expect_request_justification() + .withf(move |in_hash, in_number| &hash == in_hash && &number == in_number) + .once() + .returning(|_, _| ()); + + set_default_expecations_no_peers(&mut chain_sync); + let (mut network, _) = make_network(chain_sync, client); + + // send "request justifiction" message and poll the network + network.service().request_justification(&hash, number); + + futures::future::poll_fn(|cx| { + let _ = network.poll_unpin(cx); + Poll::Ready(()) + }) + .await; +} + +#[async_std::test] +async fn clear_justification_requests(&mut self) { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + let mut chain_sync = + Box::new(MockChainSync::::new()); + + chain_sync.expect_clear_justification_requests().once().returning(|| ()); + + set_default_expecations_no_peers(&mut chain_sync); + let (mut network, _) = make_network(chain_sync, client); + + // send "request justifiction" message and poll the network + network.service().clear_justification_requests(); + + futures::future::poll_fn(|cx| { + let _ = network.poll_unpin(cx); + Poll::Ready(()) + }) + .await; +} + +#[async_std::test] +async fn set_sync_fork_request() { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + let mut chain_sync = + Box::new(MockChainSync::::new()); + + let hash = H256::random(); + let number = 1337u64; + let peers = (0..3).map(|_| PeerId::random()).collect::>(); + let copy_peers = peers.clone(); + + chain_sync + .expect_set_sync_fork_request() + .withf(move |in_peers, in_hash, in_number| { + &peers == in_peers && &hash == in_hash && &number == in_number + }) + .once() + .returning(|_, _, _| ()); + + set_default_expecations_no_peers(&mut chain_sync); + let (mut network, _) = make_network(chain_sync, client); + + // send "set sync fork request" message and poll the network + network.service().set_sync_fork_request(copy_peers, hash, number); + + futures::future::poll_fn(|cx| { + let _ = network.poll_unpin(cx); + Poll::Ready(()) + }) + .await; +} + +#[async_std::test] +async fn on_block_finalized() { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + let mut chain_sync = + Box::new(MockChainSync::::new()); + + let at = client.header(&BlockId::Hash(client.info().best_hash)).unwrap().unwrap().hash(); + let block = client + .new_block_at(&BlockId::Hash(at), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + let header = block.header.clone(); + let block_number = *header.number(); + let hash = block.hash(); + + chain_sync + .expect_on_block_finalized() + .withf(move |in_hash, in_number| &hash == in_hash && &block_number == in_number) + .once() + .returning(|_, _| ()); + + set_default_expecations_no_peers(&mut chain_sync); + let (mut network, _) = make_network(chain_sync, client); + + // send "set sync fork request" message and poll the network + network.on_block_finalized(hash, header); + + futures::future::poll_fn(|cx| { + let _ = network.poll_unpin(cx); + Poll::Ready(()) + }) + .await; +} diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 24d418f7233d7..9d032f5cca96c 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -25,6 +25,7 @@ futures = "0.3.21" libp2p = "0.46.1" log = "0.4.17" lru = "0.7.5" +mockall = "0.11.2" prost = "0.11" smallvec = "1.8.0" thiserror = "1.0" diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 280e530eca9a9..84998c747b3cc 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -30,6 +30,7 @@ pub mod block_request_handler; pub mod blocks; +pub mod mock; mod schema; pub mod state; pub mod state_request_handler; @@ -643,9 +644,9 @@ where .extend(peers); } - fn justification_requests( - &mut self, - ) -> Box)> + '_> { + fn justification_requests<'a>( + &'a mut self, + ) -> Box)> + 'a> { let peers = &mut self.peers; let mut matcher = self.extra_justifications.matcher(); Box::new(std::iter::from_fn(move || { @@ -670,7 +671,9 @@ where })) } - fn block_requests(&mut self) -> Box)> + '_> { + fn block_requests<'a>( + &'a mut self, + ) -> Box)> + 'a> { if self.mode == SyncMode::Warp { return Box::new(std::iter::once(self.warp_target_block_request()).flatten()) } @@ -695,8 +698,8 @@ where let allowed_requests = self.allowed_requests.take(); let max_parallel = if major_sync { 1 } else { self.max_parallel_downloads }; let gap_sync = &mut self.gap_sync; - let iter = self.peers.iter_mut().filter_map(move |(id, peer)| { - if !peer.state.is_available() || !allowed_requests.contains(id) { + let iter = self.peers.iter_mut().filter_map(move |(&id, peer)| { + if !peer.state.is_available() || !allowed_requests.contains(&id) { return None } @@ -725,7 +728,7 @@ where }; Some((id, ancestry_request::(current))) } else if let Some((range, req)) = peer_block_request( - id, + &id, peer, blocks, attrs, @@ -744,7 +747,7 @@ where ); Some((id, req)) } else if let Some((hash, req)) = - fork_sync_request(id, fork_targets, best_queued, last_finalized, attrs, |hash| { + fork_sync_request(&id, fork_targets, best_queued, last_finalized, attrs, |hash| { if queue.contains(hash) { BlockStatus::Queued } else { @@ -756,7 +759,7 @@ where Some((id, req)) } else if let Some((range, req)) = gap_sync.as_mut().and_then(|sync| { peer_gap_block_request( - id, + &id, peer, &mut sync.blocks, attrs, @@ -2216,7 +2219,7 @@ where } /// Generate block request for downloading of the target block body during warp sync. - fn warp_target_block_request(&mut self) -> Option<(&PeerId, BlockRequest)> { + fn warp_target_block_request(&mut self) -> Option<(PeerId, BlockRequest)> { if let Some(sync) = &self.warp_sync { if self.allowed_requests.is_empty() || sync.is_complete() || @@ -2234,7 +2237,7 @@ where trace!(target: "sync", "New warp target block request for {}", id); peer.state = PeerSyncState::DownloadingWarpTargetBlock; self.allowed_requests.clear(); - return Some((id, request)) + return Some((*id, request)) } } } @@ -2482,7 +2485,7 @@ fn fork_sync_request( true }); for (hash, r) in targets { - if !r.peers.contains(id) { + if !r.peers.contains(&id) { continue } // Download the fork only if it is behind or not too far ahead our tip of the chain @@ -2740,7 +2743,7 @@ mod test { // we wil send block requests to these peers // for these blocks we don't know about - assert!(sync.block_requests().all(|(p, _)| { *p == peer_id1 || *p == peer_id2 })); + assert!(sync.block_requests().all(|(p, _)| { p == peer_id1 || p == peer_id2 })); // add a new peer at a known block sync.new_peer(peer_id3, b1_hash, b1_number).unwrap(); @@ -2835,7 +2838,7 @@ mod test { log::trace!(target: "sync", "Requests: {:?}", requests); assert_eq!(1, requests.len()); - assert_eq!(peer, requests[0].0); + assert_eq!(*peer, requests[0].0); let request = requests[0].1.clone(); @@ -3065,9 +3068,9 @@ mod test { send_block_announce(best_block.header().clone(), &peer_id2, &mut sync); let (peer1_req, peer2_req) = sync.block_requests().fold((None, None), |res, req| { - if req.0 == &peer_id1 { + if req.0 == peer_id1 { (Some(req.1), res.1) - } else if req.0 == &peer_id2 { + } else if req.0 == peer_id2 { (res.0, Some(req.1)) } else { panic!("Unexpected req: {:?}", req) diff --git a/client/network/sync/src/mock.rs b/client/network/sync/src/mock.rs new file mode 100644 index 0000000000000..2a3b059f735b2 --- /dev/null +++ b/client/network/sync/src/mock.rs @@ -0,0 +1,118 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Contains a mock implementation of `ChainSync` that can be used +//! for testing calls made to `ChainSync`. + +use futures::task::Poll; +use libp2p::PeerId; +use sc_consensus::{BlockImportError, BlockImportStatus}; +use sc_network_common::sync::{ + message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}, + warp::{EncodedProof, WarpProofRequest}, + BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, OnStateData, + OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, + PollBlockAnnounceValidation, SyncStatus, +}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +mockall::mock! { + pub ChainSync {} + + impl ChainSyncT for ChainSync { + fn peer_info(&self, who: &PeerId) -> Option>; + fn status(&self) -> SyncStatus; + fn num_sync_requests(&self) -> usize; + fn num_downloaded_blocks(&self) -> usize; + fn num_peers(&self) -> usize; + fn new_peer( + &mut self, + who: PeerId, + best_hash: Block::Hash, + best_number: NumberFor, + ) -> Result>, BadPeer>; + fn update_chain_info(&mut self, best_hash: &Block::Hash, best_number: NumberFor); + fn request_justification(&mut self, hash: &Block::Hash, number: NumberFor); + fn clear_justification_requests(&mut self); + fn set_sync_fork_request( + &mut self, + peers: Vec, + hash: &Block::Hash, + number: NumberFor, + ); + fn justification_requests<'a>( + &'a mut self, + ) -> Box)> + 'a>; + fn block_requests<'a>(&'a mut self) -> Box)> + 'a>; + fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)>; + fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)>; + fn on_block_data( + &mut self, + who: &PeerId, + request: Option>, + response: BlockResponse, + ) -> Result, BadPeer>; + fn on_state_data( + &mut self, + who: &PeerId, + response: OpaqueStateResponse, + ) -> Result, BadPeer>; + fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer>; + fn on_block_justification( + &mut self, + who: PeerId, + response: BlockResponse, + ) -> Result, BadPeer>; + fn on_blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, Block::Hash)>, + ) -> Box), BadPeer>>>; + fn on_justification_import( + &mut self, + hash: Block::Hash, + number: NumberFor, + success: bool, + ); + fn on_block_finalized(&mut self, hash: &Block::Hash, number: NumberFor); + fn push_block_announce_validation( + &mut self, + who: PeerId, + hash: Block::Hash, + announce: BlockAnnounce, + is_best: bool, + ); + fn poll_block_announce_validation<'a>( + &mut self, + cx: &mut std::task::Context<'a>, + ) -> Poll>; + fn peer_disconnected(&mut self, who: &PeerId) -> Option>; + fn metrics(&self) -> Metrics; + fn create_opaque_block_request(&self, request: &BlockRequest) -> OpaqueBlockRequest; + fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String>; + fn decode_block_response(&self, response: &[u8]) -> Result; + fn block_response_into_blocks( + &self, + request: &BlockRequest, + response: OpaqueBlockResponse, + ) -> Result>, String>; + fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String>; + fn decode_state_response(&self, response: &[u8]) -> Result; + } +} From 1f39c9029eb83e9432d86877f0694f643b7dd968 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Thu, 13 Oct 2022 12:13:56 +0200 Subject: [PATCH 1268/1472] pallet-mmr: RPC API and Runtime API work with block numbers (#12345) * pallet-mmr: RPC API works with block_numbers * fixes * update rpc * fmt * final touches in the rpc * temporary fix * fix * fmt * docs * Update lib.rs * use NumberFor * validate input * update runtime * convert block_number to u64 * small edit * update runtime api * test fix * runtime fix * update test function * fmt * fix nits * remove block_num_to_leaf_index from runtime api * Update frame/merkle-mountain-range/src/lib.rs Co-authored-by: Robert Hambrock * fix tests * get the code to compile after merge * get the tests to compile * fix in tests? * fix test * Update frame/merkle-mountain-range/src/tests.rs Co-authored-by: Adrian Catangiu * Update frame/merkle-mountain-range/src/lib.rs Co-authored-by: Adrian Catangiu * Update primitives/merkle-mountain-range/src/lib.rs Co-authored-by: Adrian Catangiu * fix errors & nits * change block_num_to_leaf_index * don't make any assumptions * Update frame/merkle-mountain-range/src/tests.rs Co-authored-by: Adrian Catangiu * Update frame/merkle-mountain-range/src/tests.rs Co-authored-by: Adrian Catangiu * Update frame/merkle-mountain-range/src/tests.rs Co-authored-by: Adrian Catangiu * fix * small fix * use best_known_block_number * best_known_block_number instead of leaves_count * more readable? * remove warning * Update frame/merkle-mountain-range/src/lib.rs Co-authored-by: Robert Hambrock * simplify * update docs * nits * fmt & fix * merge fixes * fix * small fix * docs & nit fixes * Nit fixes * remove leaf_indices_to_block_numbers() * fmt Co-authored-by: Robert Hambrock Co-authored-by: Adrian Catangiu --- bin/node/rpc/src/lib.rs | 6 +- bin/node/runtime/src/lib.rs | 20 +++-- client/beefy/src/lib.rs | 4 +- client/beefy/src/tests.rs | 16 ++-- client/beefy/src/worker.rs | 2 +- frame/merkle-mountain-range/rpc/src/lib.rs | 59 +++++++-------- frame/merkle-mountain-range/src/lib.rs | 56 +++++++++++--- frame/merkle-mountain-range/src/tests.rs | 81 +++++++++++---------- primitives/beefy/src/mmr.rs | 6 +- primitives/merkle-mountain-range/src/lib.rs | 23 +++--- 10 files changed, 160 insertions(+), 113 deletions(-) diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 94e01619c6e63..8596fe23321ba 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -108,7 +108,11 @@ where + Send + 'static, C::Api: substrate_frame_rpc_system::AccountNonceApi, - C::Api: pallet_mmr_rpc::MmrRuntimeApi::Hash>, + C::Api: pallet_mmr_rpc::MmrRuntimeApi< + Block, + ::Hash, + BlockNumber, + >, C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, C::Api: BabeApi, C::Api: BlockBuilder, diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 142173621036d..f137b36eff036 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2016,11 +2016,15 @@ impl_runtime_apis! { } } - impl pallet_mmr::primitives::MmrApi for Runtime { - fn generate_proof(leaf_index: pallet_mmr::primitives::LeafIndex) + impl pallet_mmr::primitives::MmrApi< + Block, + mmr::Hash, + BlockNumber, + > for Runtime { + fn generate_proof(block_number: BlockNumber) -> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof), mmr::Error> { - Mmr::generate_batch_proof(vec![leaf_index]).and_then(|(leaves, proof)| + Mmr::generate_batch_proof(vec![block_number]).and_then(|(leaves, proof)| Ok(( mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]), mmr::BatchProof::into_single_leaf_proof(proof)? @@ -2052,9 +2056,9 @@ impl_runtime_apis! { } fn generate_batch_proof( - leaf_indices: Vec, + block_numbers: Vec, ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { - Mmr::generate_batch_proof(leaf_indices).map(|(leaves, proof)| { + Mmr::generate_batch_proof(block_numbers).map(|(leaves, proof)| { ( leaves .into_iter() @@ -2066,10 +2070,10 @@ impl_runtime_apis! { } fn generate_historical_batch_proof( - leaf_indices: Vec, - leaves_count: pallet_mmr::primitives::LeafIndex, + block_numbers: Vec, + best_known_block_number: BlockNumber, ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { - Mmr::generate_historical_batch_proof(leaf_indices, leaves_count).map( + Mmr::generate_historical_batch_proof(block_numbers, best_known_block_number).map( |(leaves, proof)| { ( leaves diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 1c61cac072207..441f6e4248117 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -24,7 +24,7 @@ use sc_consensus::BlockImport; use sc_network::ProtocolName; use sc_network_common::service::NetworkRequest; use sc_network_gossip::Network as GossipNetwork; -use sp_api::ProvideRuntimeApi; +use sp_api::{NumberFor, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_keystore::SyncCryptoStorePtr; @@ -200,7 +200,7 @@ where C: Client + BlockBackend, P: PayloadProvider, R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi, + R::Api: BeefyApi + MmrApi>, N: GossipNetwork + NetworkRequest + SyncOracle + Send + Sync + 'static, { let BeefyParams { diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 24cf89acd5734..89be1cac4f886 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -43,9 +43,7 @@ use beefy_primitives::{ KEY_TYPE as BeefyKeyType, }; use sc_network::{config::RequestResponseConfig, ProtocolName}; -use sp_mmr_primitives::{ - BatchProof, EncodableOpaqueLeaf, Error as MmrError, LeafIndex, MmrApi, Proof, -}; +use sp_mmr_primitives::{BatchProof, EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; @@ -247,8 +245,8 @@ macro_rules! create_test_api { } } - impl MmrApi for RuntimeApi { - fn generate_proof(_leaf_index: LeafIndex) + impl MmrApi> for RuntimeApi { + fn generate_proof(_block_number: u64) -> Result<(EncodableOpaqueLeaf, Proof), MmrError> { unimplemented!() } @@ -270,13 +268,13 @@ macro_rules! create_test_api { Ok($mmr_root) } - fn generate_batch_proof(_leaf_indices: Vec) -> Result<(Vec, BatchProof), MmrError> { + fn generate_batch_proof(_block_numbers: Vec) -> Result<(Vec, BatchProof), MmrError> { unimplemented!() } fn generate_historical_batch_proof( - _leaf_indices: Vec, - _leaves_count: LeafIndex + _block_numbers: Vec, + _best_known_block_number: u64 ) -> Result<(Vec, BatchProof), MmrError> { unimplemented!() } @@ -349,7 +347,7 @@ fn initialize_beefy( ) -> impl Future where API: ProvideRuntimeApi + Default + Sync + Send, - API::Api: BeefyApi + MmrApi, + API::Api: BeefyApi + MmrApi>, { let tasks = FuturesUnordered::new(); diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index a21807c8ee875..4381081f74ebd 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -252,7 +252,7 @@ where C: Client, P: PayloadProvider, R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi, + R::Api: BeefyApi + MmrApi>, N: NetworkEventStream + NetworkRequest + SyncOracle + Send + Sync + Clone + 'static, { /// Return a new BEEFY worker instance. diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index e939ff8ae7cd0..ffc7ac2da56bf 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -30,10 +30,10 @@ use jsonrpsee::{ }; use serde::{Deserialize, Serialize}; -use sp_api::ProvideRuntimeApi; +use sp_api::{NumberFor, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::Bytes; -use sp_mmr_primitives::{BatchProof, Error as MmrError, LeafIndex, Proof}; +use sp_mmr_primitives::{BatchProof, Error as MmrError, Proof}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; @@ -96,11 +96,11 @@ impl LeafBatchProof { /// MMR RPC methods. #[rpc(client, server)] -pub trait MmrApi { - /// Generate MMR proof for given leaf index. +pub trait MmrApi { + /// Generate MMR proof for given block number. /// /// This method calls into a runtime with MMR pallet included and attempts to generate - /// MMR proof for leaf at given `leaf_index`. + /// MMR proof for a block with a specified `block_number`. /// Optionally, a block hash at which the runtime should be queried can be specified. /// /// Returns the (full) leaf itself and a proof for this leaf (compact encoding, i.e. hash of @@ -108,49 +108,49 @@ pub trait MmrApi { #[method(name = "mmr_generateProof")] fn generate_proof( &self, - leaf_index: LeafIndex, + block_number: BlockNumber, at: Option, ) -> RpcResult>; - /// Generate MMR proof for the given leaf indices. + /// Generate MMR proof for the given block numbers. /// /// This method calls into a runtime with MMR pallet included and attempts to generate - /// MMR proof for a set of leaves at the given `leaf_indices`. + /// MMR proof for a set of blocks with the specific `block_numbers`. /// Optionally, a block hash at which the runtime should be queried can be specified. /// /// Returns the leaves and a proof for these leaves (compact encoding, i.e. hash of /// the leaves). Both parameters are SCALE-encoded. /// The order of entries in the `leaves` field of the returned struct - /// is the same as the order of the entries in `leaf_indices` supplied + /// is the same as the order of the entries in `block_numbers` supplied #[method(name = "mmr_generateBatchProof")] fn generate_batch_proof( &self, - leaf_indices: Vec, + block_numbers: Vec, at: Option, ) -> RpcResult>; - /// Generate a MMR proof for the given `leaf_indices` of the MMR that had `leaves_count` leaves. + /// Generate a MMR proof for the given `block_numbers` given the `best_known_block_number`. /// /// This method calls into a runtime with MMR pallet included and attempts to generate - /// a MMR proof for the set of leaves at the given `leaf_indices` with MMR fixed to the state - /// with exactly `leaves_count` leaves. `leaves_count` must be larger than all `leaf_indices` - /// for the function to succeed. + /// a MMR proof for the set of blocks that have the given `block_numbers` with MMR given the + /// `best_known_block_number`. `best_known_block_number` must be larger than all the + /// `block_numbers` for the function to succeed. /// /// Optionally, a block hash at which the runtime should be queried can be specified. /// Note that specifying the block hash isn't super-useful here, unless you're generating /// proof using non-finalized blocks where there are several competing forks. That's because - /// MMR state will be fixed to the state with `leaves_count`, which already points to some - /// historical block. + /// MMR state will be fixed to the state with `best_known_block_number`, which already points to + /// some historical block. /// /// Returns the leaves and a proof for these leaves (compact encoding, i.e. hash of /// the leaves). Both parameters are SCALE-encoded. /// The order of entries in the `leaves` field of the returned struct - /// is the same as the order of the entries in `leaf_indices` supplied + /// is the same as the order of the entries in `block_numbers` supplied #[method(name = "mmr_generateHistoricalBatchProof")] fn generate_historical_batch_proof( &self, - leaf_indices: Vec, - leaves_count: LeafIndex, + block_numbers: Vec, + best_known_block_number: BlockNumber, at: Option, ) -> RpcResult>; } @@ -169,16 +169,17 @@ impl Mmr { } #[async_trait] -impl MmrApiServer<::Hash> for Mmr +impl MmrApiServer<::Hash, NumberFor> + for Mmr where Block: BlockT, Client: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - Client::Api: MmrRuntimeApi, + Client::Api: MmrRuntimeApi>, MmrHash: Codec + Send + Sync + 'static, { fn generate_proof( &self, - leaf_index: LeafIndex, + block_number: NumberFor, at: Option<::Hash>, ) -> RpcResult> { let api = self.client.runtime_api(); @@ -188,7 +189,7 @@ where .generate_proof_with_context( &BlockId::hash(block_hash), sp_core::ExecutionContext::OffchainCall(None), - leaf_index, + block_number, ) .map_err(runtime_error_into_rpc_error)? .map_err(mmr_error_into_rpc_error)?; @@ -198,7 +199,7 @@ where fn generate_batch_proof( &self, - leaf_indices: Vec, + block_numbers: Vec>, at: Option<::Hash>, ) -> RpcResult::Hash>> { let api = self.client.runtime_api(); @@ -210,7 +211,7 @@ where .generate_batch_proof_with_context( &BlockId::hash(block_hash), sp_core::ExecutionContext::OffchainCall(None), - leaf_indices, + block_numbers, ) .map_err(runtime_error_into_rpc_error)? .map_err(mmr_error_into_rpc_error)?; @@ -220,8 +221,8 @@ where fn generate_historical_batch_proof( &self, - leaf_indices: Vec, - leaves_count: LeafIndex, + block_numbers: Vec>, + best_known_block_number: NumberFor, at: Option<::Hash>, ) -> RpcResult::Hash>> { let api = self.client.runtime_api(); @@ -233,8 +234,8 @@ where .generate_historical_batch_proof_with_context( &BlockId::hash(block_hash), sp_core::ExecutionContext::OffchainCall(None), - leaf_indices, - leaves_count, + block_numbers, + best_known_block_number, ) .map_err(runtime_error_into_rpc_error)? .map_err(mmr_error_into_rpc_error)?; diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 8b4f2b60bc198..ad3ce340496e8 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -59,7 +59,7 @@ use codec::Encode; use frame_support::weights::Weight; use sp_runtime::{ - traits::{self, One, Saturating}, + traits::{self, CheckedSub, One, Saturating}, SaturatedConversion, }; @@ -318,37 +318,73 @@ impl, I: 'static> Pallet { .saturating_add(leaf_index.saturated_into()) } - /// Generate a MMR proof for the given `leaf_indices`. + /// Convert a `block_num` into a leaf index. + fn block_num_to_leaf_index(block_num: T::BlockNumber) -> Result + where + T: frame_system::Config, + { + // leaf_idx = (leaves_count - 1) - (current_block_num - block_num); + let best_block_num = >::block_number(); + let blocks_diff = best_block_num.checked_sub(&block_num).ok_or_else(|| { + primitives::Error::BlockNumToLeafIndex + .log_debug("The provided block_number is greater than the best block number.") + })?; + let blocks_diff_as_leaf_idx = blocks_diff.try_into().map_err(|_| { + primitives::Error::BlockNumToLeafIndex + .log_debug("The `blocks_diff` couldn't be converted to `LeafIndex`.") + })?; + + let leaf_idx = Self::mmr_leaves() + .checked_sub(1) + .and_then(|last_leaf_idx| last_leaf_idx.checked_sub(blocks_diff_as_leaf_idx)) + .ok_or_else(|| { + primitives::Error::BlockNumToLeafIndex + .log_debug("There aren't enough leaves in the chain.") + })?; + Ok(leaf_idx) + } + + /// Generate a MMR proof for the given `block_numbers`. /// /// Note this method can only be used from an off-chain context /// (Offchain Worker or Runtime API call), since it requires /// all the leaves to be present. /// It may return an error or panic if used incorrectly. pub fn generate_batch_proof( - leaf_indices: Vec, + block_numbers: Vec, ) -> Result< (Vec>, primitives::BatchProof<>::Hash>), primitives::Error, > { - Self::generate_historical_batch_proof(leaf_indices, Self::mmr_leaves()) + Self::generate_historical_batch_proof( + block_numbers, + >::block_number(), + ) } - /// Generate a MMR proof for the given `leaf_indices` for the MMR of `leaves_count` size. + /// Generate a MMR proof for the given `block_numbers` given the `best_known_block_number`. /// /// Note this method can only be used from an off-chain context /// (Offchain Worker or Runtime API call), since it requires /// all the leaves to be present. /// It may return an error or panic if used incorrectly. pub fn generate_historical_batch_proof( - leaf_indices: Vec, - leaves_count: LeafIndex, + block_numbers: Vec, + best_known_block_number: T::BlockNumber, ) -> Result< (Vec>, primitives::BatchProof<>::Hash>), primitives::Error, > { - if leaves_count > Self::mmr_leaves() { - return Err(Error::InvalidLeavesCount) - } + let leaves_count = + Self::block_num_to_leaf_index(best_known_block_number)?.saturating_add(1); + + // we need to translate the block_numbers into leaf indices. + let leaf_indices = block_numbers + .iter() + .map(|block_num| -> Result { + Self::block_num_to_leaf_index(*block_num) + }) + .collect::, _>>()?; let mmr: ModuleMmr = mmr::Mmr::new(leaves_count); mmr.generate_batch_proof(leaf_indices) diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index bcb775ba02819..a63a433029295 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -235,22 +235,21 @@ fn should_generate_proofs_correctly() { // to retrieve full leaf data. register_offchain_ext(&mut ext); ext.execute_with(|| { - // when generate proofs for all leaves - let proofs = (0_u64..crate::NumberOfLeaves::::get()) + let best_block_number = frame_system::Pallet::::block_number(); + // when generate proofs for all leaves. + let proofs = (1_u64..=best_block_number) .into_iter() - .map(|leaf_index| { - crate::Pallet::::generate_batch_proof(vec![leaf_index]).unwrap() - }) + .map(|block_num| crate::Pallet::::generate_batch_proof(vec![block_num]).unwrap()) .collect::>(); // when generate historical proofs for all leaves - let historical_proofs = (0_u64..crate::NumberOfLeaves::::get()) + let historical_proofs = (1_u64..best_block_number) .into_iter() - .map(|leaf_index| { + .map(|block_num| { let mut proofs = vec![]; - for leaves_count in leaf_index + 1..=num_blocks { + for leaves_count in block_num..=num_blocks { proofs.push( crate::Pallet::::generate_historical_batch_proof( - vec![leaf_index], + vec![block_num], leaves_count, ) .unwrap(), @@ -321,7 +320,7 @@ fn should_generate_proofs_correctly() { leaf_count: 3, items: vec![hex( "672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854" - ),], + )], } ) ); @@ -352,6 +351,7 @@ fn should_generate_proofs_correctly() { assert_eq!( proofs[4], ( + // NOTE: the leaf index is equivalent to the block number(in this case 5) - 1 vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], BatchProof { leaf_indices: vec![4], @@ -393,7 +393,7 @@ fn should_generate_proofs_correctly() { } ) ); - assert_eq!(historical_proofs[6][0], proofs[6]); + assert_eq!(historical_proofs[5][1], proofs[5]); }); } @@ -410,11 +410,12 @@ fn should_generate_batch_proof_correctly() { register_offchain_ext(&mut ext); ext.execute_with(|| { // when generate proofs for a batch of leaves - let (.., proof) = crate::Pallet::::generate_batch_proof(vec![0, 4, 5]).unwrap(); + let (.., proof) = crate::Pallet::::generate_batch_proof(vec![1, 5, 6]).unwrap(); // then assert_eq!( proof, BatchProof { + // the leaf indices are equivalent to the above specified block numbers - 1. leaf_indices: vec![0, 4, 5], leaf_count: 7, items: vec![ @@ -427,7 +428,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::::generate_historical_batch_proof(vec![0, 4, 5], 6).unwrap(); + crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], 6).unwrap(); // then assert_eq!( historical_proof, @@ -443,7 +444,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::::generate_historical_batch_proof(vec![0, 4, 5], 7).unwrap(); + crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], 7).unwrap(); // then assert_eq!(historical_proof, proof); }); @@ -500,15 +501,15 @@ fn should_verify() { fn should_verify_batch_proofs() { fn generate_and_verify_batch_proof( ext: &mut sp_io::TestExternalities, - leaf_indices: &Vec, + block_numbers: &Vec, blocks_to_add: usize, ) { let (leaves, proof) = ext.execute_with(|| { - crate::Pallet::::generate_batch_proof(leaf_indices.to_vec()).unwrap() + crate::Pallet::::generate_batch_proof(block_numbers.to_vec()).unwrap() }); let mmr_size = ext.execute_with(|| crate::Pallet::::mmr_leaves()); - let min_mmr_size = leaf_indices.iter().max().unwrap() + 1; + let min_mmr_size = block_numbers.iter().max().unwrap() + 1; // generate historical proofs for all possible mmr sizes, // lower bound being index of highest leaf to be proven @@ -516,7 +517,7 @@ fn should_verify_batch_proofs() { .map(|mmr_size| { ext.execute_with(|| { crate::Pallet::::generate_historical_batch_proof( - leaf_indices.to_vec(), + block_numbers.to_vec(), mmr_size, ) .unwrap() @@ -546,39 +547,41 @@ fn should_verify_batch_proofs() { // to retrieve full leaf data when generating proofs register_offchain_ext(&mut ext); - // verify that up to n=10, valid proofs are generated for all possible leaf combinations - for n in 0..10 { + // verify that up to n=10, valid proofs are generated for all possible block number + // combinations. + for n in 1..=10 { ext.execute_with(|| new_block()); ext.persist_offchain_overlay(); - // generate powerset (skipping empty set) of all possible leaf combinations for mmr size n - let leaves_set: Vec> = (0..=n).into_iter().powerset().skip(1).collect(); + // generate powerset (skipping empty set) of all possible block number combinations for mmr + // size n. + let blocks_set: Vec> = (1..=n).into_iter().powerset().skip(1).collect(); - leaves_set.iter().for_each(|leaves_subset| { - generate_and_verify_batch_proof(&mut ext, leaves_subset, 0); + blocks_set.iter().for_each(|blocks_subset| { + generate_and_verify_batch_proof(&mut ext, &blocks_subset, 0); ext.persist_offchain_overlay(); }); } - // verify that up to n=15, valid proofs are generated for all possible 2-leaf combinations - for n in 10..15 { - // (MMR Leafs) + // verify that up to n=15, valid proofs are generated for all possible 2-block number + // combinations. + for n in 11..=15 { ext.execute_with(|| new_block()); ext.persist_offchain_overlay(); - // generate all possible 2-leaf combinations for mmr size n - let leaves_set: Vec> = (0..=n).into_iter().combinations(2).collect(); + // generate all possible 2-block number combinations for mmr size n. + let blocks_set: Vec> = (1..=n).into_iter().combinations(2).collect(); - leaves_set.iter().for_each(|leaves_subset| { - generate_and_verify_batch_proof(&mut ext, leaves_subset, 0); + blocks_set.iter().for_each(|blocks_subset| { + generate_and_verify_batch_proof(&mut ext, &blocks_subset, 0); ext.persist_offchain_overlay(); }); } - generate_and_verify_batch_proof(&mut ext, &vec![7, 11], 20); + generate_and_verify_batch_proof(&mut ext, &vec![8, 12], 20); ext.execute_with(|| add_blocks(1000)); ext.persist_offchain_overlay(); - generate_and_verify_batch_proof(&mut ext, &vec![7, 11, 100, 800], 100); + generate_and_verify_batch_proof(&mut ext, &vec![8, 12, 100, 800], 100); } #[test] @@ -650,11 +653,11 @@ fn should_verify_batch_proof_statelessly() { register_offchain_ext(&mut ext); let (leaves, proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![0, 4, 5]).unwrap() + crate::Pallet::::generate_batch_proof(vec![1, 4, 5]).unwrap() }); let (historical_leaves, historical_proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![0, 4, 5], 6).unwrap() + crate::Pallet::::generate_historical_batch_proof(vec![1, 4, 5], 6).unwrap() }); // Verify proof without relying on any on-chain data. @@ -920,7 +923,7 @@ fn should_verify_canonicalized() { // Generate proofs for some blocks. let (leaves, proofs) = - ext.execute_with(|| crate::Pallet::::generate_batch_proof(vec![0, 4, 5, 7]).unwrap()); + ext.execute_with(|| crate::Pallet::::generate_batch_proof(vec![1, 4, 5, 7]).unwrap()); // Verify all previously generated proofs. ext.execute_with(|| { assert_eq!(crate::Pallet::::verify_leaves(leaves, proofs), Ok(())); @@ -953,19 +956,19 @@ fn does_not_panic_when_generating_historical_proofs() { // when leaf index is invalid assert_eq!( crate::Pallet::::generate_historical_batch_proof(vec![10], 7), - Err(Error::LeafNotFound), + Err(Error::BlockNumToLeafIndex), ); // when leaves count is invalid assert_eq!( crate::Pallet::::generate_historical_batch_proof(vec![3], 100), - Err(Error::InvalidLeavesCount), + Err(Error::BlockNumToLeafIndex), ); // when both leaf index and leaves count are invalid assert_eq!( crate::Pallet::::generate_historical_batch_proof(vec![10], 100), - Err(Error::InvalidLeavesCount), + Err(Error::BlockNumToLeafIndex), ); }); } diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index b479d979f13f3..0edb8babd608e 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -142,7 +142,7 @@ pub use mmr_root_provider::MmrRootProvider; mod mmr_root_provider { use super::*; use crate::{known_payloads, payload::PayloadProvider, Payload}; - use sp_api::ProvideRuntimeApi; + use sp_api::{NumberFor, ProvideRuntimeApi}; use sp_mmr_primitives::MmrApi; use sp_runtime::generic::BlockId; use sp_std::{marker::PhantomData, sync::Arc}; @@ -159,7 +159,7 @@ mod mmr_root_provider { where B: Block, R: ProvideRuntimeApi, - R::Api: MmrApi, + R::Api: MmrApi>, { /// Create new BEEFY Payload provider with MMR Root as payload. pub fn new(runtime: Arc) -> Self { @@ -182,7 +182,7 @@ mod mmr_root_provider { where B: Block, R: ProvideRuntimeApi, - R::Api: MmrApi, + R::Api: MmrApi>, { fn payload(&self, header: &B::Header) -> Option { self.mmr_root_from_digest_or_runtime(header).map(|mmr_root| { diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 7a26cae839ea9..06bc1f4bffe84 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -387,6 +387,8 @@ impl Proof { /// Merkle Mountain Range operation error. #[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] pub enum Error { + /// Error during translation of a block number into a leaf index. + BlockNumToLeafIndex, /// Error while pushing new node. Push, /// Error getting the new root. @@ -403,8 +405,8 @@ pub enum Error { PalletNotIncluded, /// Cannot find the requested leaf index InvalidLeafIndex, - /// The provided leaves count is larger than the actual leaves count. - InvalidLeavesCount, + /// The provided best know block number is invalid. + InvalidBestKnownBlock, } impl Error { @@ -434,9 +436,9 @@ impl Error { sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. - pub trait MmrApi { - /// Generate MMR proof for a leaf under given index. - fn generate_proof(leaf_index: LeafIndex) -> Result<(EncodableOpaqueLeaf, Proof), Error>; + pub trait MmrApi { + /// Generate MMR proof for a block with a specified `block_number`. + fn generate_proof(block_number: BlockNumber) -> Result<(EncodableOpaqueLeaf, Proof), Error>; /// Verify MMR proof against on-chain MMR. /// @@ -457,14 +459,13 @@ sp_api::decl_runtime_apis! { /// Return the on-chain MMR root hash. fn mmr_root() -> Result; - /// Generate MMR proof for a series of leaves under given indices. - fn generate_batch_proof(leaf_indices: Vec) - -> Result<(Vec, BatchProof), Error>; + /// Generate MMR proof for a series of blocks with the specified block numbers. + fn generate_batch_proof(block_numbers: Vec) -> Result<(Vec, BatchProof), Error>; - /// Generate MMR proof for a series of leaves under given indices, using MMR at given `leaves_count` size. + /// Generate MMR proof for a series of `block_numbers`, given the `best_known_block_number`. fn generate_historical_batch_proof( - leaf_indices: Vec, - leaves_count: LeafIndex + block_numbers: Vec, + best_known_block_number: BlockNumber ) -> Result<(Vec, BatchProof), Error>; /// Verify MMR proof against on-chain MMR for a batch of leaves. From fd00b14932d37bee06371325269c163bf80d1d16 Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 13 Oct 2022 19:31:00 +0900 Subject: [PATCH 1269/1472] Enable the `wasmtime`-based WASM executor by default (#12486) --- client/cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 37a8fd2e0b64d..66742e14789ef 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -51,6 +51,6 @@ sp-version = { version = "5.0.0", path = "../../primitives/version" } tempfile = "3.1.0" [features] -default = ["rocksdb"] +default = ["rocksdb", "wasmtime"] rocksdb = ["sc-client-db/rocksdb"] wasmtime = ["sc-service/wasmtime"] From 6e04e48f36e1839532d566a4dcad3c57b4be939d Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 13 Oct 2022 15:22:57 +0200 Subject: [PATCH 1270/1472] Trivial BlockId::Number => Hash (#12490) --- primitives/api/test/benches/bench.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/primitives/api/test/benches/bench.rs b/primitives/api/test/benches/bench.rs index 2682c91f94106..2445a5c07f09e 100644 --- a/primitives/api/test/benches/bench.rs +++ b/primitives/api/test/benches/bench.rs @@ -27,14 +27,14 @@ fn sp_api_benchmark(c: &mut Criterion) { c.bench_function("add one with same runtime api", |b| { let client = substrate_test_runtime_client::new(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); b.iter(|| runtime_api.benchmark_add_one(&block_id, &1)) }); c.bench_function("add one with recreating runtime api", |b| { let client = substrate_test_runtime_client::new(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); b.iter(|| client.runtime_api().benchmark_add_one(&block_id, &1)) }); @@ -42,7 +42,7 @@ fn sp_api_benchmark(c: &mut Criterion) { c.bench_function("vector add one with same runtime api", |b| { let client = substrate_test_runtime_client::new(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); let data = vec![0; 1000]; b.iter_with_large_drop(|| runtime_api.benchmark_vector_add_one(&block_id, &data)) @@ -50,7 +50,7 @@ fn sp_api_benchmark(c: &mut Criterion) { c.bench_function("vector add one with recreating runtime api", |b| { let client = substrate_test_runtime_client::new(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); let data = vec![0; 1000]; b.iter_with_large_drop(|| client.runtime_api().benchmark_vector_add_one(&block_id, &data)) @@ -60,7 +60,7 @@ fn sp_api_benchmark(c: &mut Criterion) { let client = TestClientBuilder::new() .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); b.iter(|| client.runtime_api().benchmark_indirect_call(&block_id).unwrap()) }); @@ -68,7 +68,7 @@ fn sp_api_benchmark(c: &mut Criterion) { let client = TestClientBuilder::new() .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); b.iter(|| client.runtime_api().benchmark_direct_call(&block_id).unwrap()) }); } From f3139874cb50f9028ecba9bdbd3004e7f3f228f5 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Fri, 14 Oct 2022 11:27:32 +0200 Subject: [PATCH 1271/1472] BlockId removal: refactor: Backend::state_at (#12488) * Minor naming improved * BlockId removal refactor: Backend::state_at * formatting --- bin/node/bench/src/import.rs | 9 +++- client/api/src/backend.rs | 4 +- client/api/src/in_mem.rs | 21 ++++---- .../basic-authorship/src/basic_authorship.rs | 2 +- client/block-builder/src/lib.rs | 5 +- client/db/benches/state_access.rs | 10 ++-- client/db/src/lib.rs | 48 ++++++------------ client/service/src/client/call_executor.rs | 21 ++++---- client/service/src/client/client.rs | 49 ++++++++++++------- client/service/test/src/client/mod.rs | 26 ++++++---- primitives/blockchain/src/backend.rs | 4 +- .../rpc/state-trie-migration-rpc/src/lib.rs | 6 +-- 12 files changed, 105 insertions(+), 100 deletions(-) diff --git a/bin/node/bench/src/import.rs b/bin/node/bench/src/import.rs index 47f630eb68700..26f9391800ceb 100644 --- a/bin/node/bench/src/import.rs +++ b/bin/node/bench/src/import.rs @@ -34,7 +34,7 @@ use std::borrow::Cow; use node_primitives::Block; use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile}; -use sc_client_api::backend::Backend; +use sc_client_api::{backend::Backend, HeaderBackend}; use sp_runtime::generic::BlockId; use sp_state_machine::InspectState; @@ -127,10 +127,15 @@ impl core::Benchmark for ImportBenchmark { context.import_block(self.block.clone()); let elapsed = start.elapsed(); + let hash = context + .client + .expect_block_hash_from_id(&BlockId::number(1)) + .expect("Block 1 was imported; qed"); + // Sanity checks. context .client - .state_at(&BlockId::number(1)) + .state_at(&hash) .expect("state_at failed for block#1") .inspect_state(|| { match self.block_type { diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index bcc7a9bff3b2d..0e94d28b75dd5 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -505,11 +505,11 @@ pub trait Backend: AuxStore + Send + Sync { /// Returns true if state for given block is available. fn have_state_at(&self, hash: &Block::Hash, _number: NumberFor) -> bool { - self.state_at(BlockId::Hash(*hash)).is_ok() + self.state_at(hash).is_ok() } /// Returns state backend with post-state of given block. - fn state_at(&self, block: BlockId) -> sp_blockchain::Result; + fn state_at(&self, hash: &Block::Hash) -> sp_blockchain::Result; /// Attempts to revert the chain by `n` blocks. If `revert_finalized` is set it will attempt to /// revert past any finalized block, this is unsafe and can potentially leave the node in an diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 9000f62aa6cc3..9cea1883bdcdc 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -686,7 +686,7 @@ where type OffchainStorage = OffchainStorage; fn begin_operation(&self) -> sp_blockchain::Result { - let old_state = self.state_at(BlockId::Hash(Default::default()))?; + let old_state = self.state_at(&Default::default())?; Ok(BlockImportOperation { pending_block: None, old_state, @@ -702,7 +702,8 @@ where operation: &mut Self::BlockImportOperation, block: BlockId, ) -> sp_blockchain::Result<()> { - operation.old_state = self.state_at(block)?; + let hash = self.blockchain.expect_block_hash_from_id(&block)?; + operation.old_state = self.state_at(&hash)?; Ok(()) } @@ -768,16 +769,16 @@ where None } - fn state_at(&self, block: BlockId) -> sp_blockchain::Result { - match block { - BlockId::Hash(h) if h == Default::default() => return Ok(Self::State::default()), - _ => {}, + fn state_at(&self, hash: &Block::Hash) -> sp_blockchain::Result { + if *hash == Default::default() { + return Ok(Self::State::default()) } - self.blockchain - .id(block) - .and_then(|id| self.states.read().get(&id).cloned()) - .ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", block))) + self.states + .read() + .get(hash) + .cloned() + .ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", hash))) } fn revert( diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index f5ccd9023a3db..da98ccab9cb07 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -736,7 +736,7 @@ mod tests { let api = client.runtime_api(); api.execute_block(&block_id, proposal.block).unwrap(); - let state = backend.state_at(block_id).unwrap(); + let state = backend.state_at(&genesis_hash).unwrap(); let storage_changes = api.into_storage_changes(&state, genesis_hash).unwrap(); diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index 803e9c1e8bf26..cd5e62e264200 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -258,12 +258,11 @@ where let proof = self.api.extract_proof(); - let state = self.backend.state_at(self.block_id)?; - let parent_hash = self.parent_hash; + let state = self.backend.state_at(&self.parent_hash)?; let storage_changes = self .api - .into_storage_changes(&state, parent_hash) + .into_storage_changes(&state, self.parent_hash) .map_err(sp_blockchain::Error::StorageChanges)?; Ok(BuiltBlock { diff --git a/client/db/benches/state_access.rs b/client/db/benches/state_access.rs index 4f4c10bcc8f53..912a9b028f638 100644 --- a/client/db/benches/state_access.rs +++ b/client/db/benches/state_access.rs @@ -84,7 +84,7 @@ fn insert_blocks(db: &Backend, storage: Vec<(Vec, Vec)>) -> H256 .map(|(k, v)| (k.clone(), Some(v.clone()))) .collect::>(); - let (state_root, tx) = db.state_at(BlockId::Hash(parent_hash)).unwrap().storage_root( + let (state_root, tx) = db.state_at(&parent_hash).unwrap().storage_root( changes.iter().map(|(k, v)| (k.as_slice(), v.as_deref())), StateVersion::V1, ); @@ -176,7 +176,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + || backend.state_at(&block_hash).expect("Creates state"), |state| { for key in keys.iter().cycle().take(keys.len() * multiplier) { let _ = state.storage(&key).expect("Doesn't fail").unwrap(); @@ -214,7 +214,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + || backend.state_at(&block_hash).expect("Creates state"), |state| { for key in keys.iter().take(1).cycle().take(multiplier) { let _ = state.storage(&key).expect("Doesn't fail").unwrap(); @@ -252,7 +252,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + || backend.state_at(&block_hash).expect("Creates state"), |state| { for key in keys.iter().take(1).cycle().take(multiplier) { let _ = state.storage_hash(&key).expect("Doesn't fail").unwrap(); @@ -290,7 +290,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + || backend.state_at(&block_hash).expect("Creates state"), |state| { let _ = state .storage_hash(sp_core::storage::well_known_keys::CODE) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 32c4c9ef85ed9..ae777ad154f6d 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1963,10 +1963,11 @@ impl sc_client_api::backend::Backend for Backend { operation: &mut Self::BlockImportOperation, block: BlockId, ) -> ClientResult<()> { + let hash = self.blockchain.expect_block_hash_from_id(&block)?; if block.is_pre_genesis() { operation.old_state = self.empty_state()?; } else { - operation.old_state = self.state_at(block)?; + operation.old_state = self.state_at(&hash)?; } operation.commit_state = true; @@ -2302,15 +2303,8 @@ impl sc_client_api::backend::Backend for Backend { &self.blockchain } - fn state_at(&self, block: BlockId) -> ClientResult { - use sc_client_api::blockchain::HeaderBackend as BcHeaderBackend; - - let is_genesis = match &block { - BlockId::Number(n) if n.is_zero() => true, - BlockId::Hash(h) if h == &self.blockchain.meta.read().genesis_hash => true, - _ => false, - }; - if is_genesis { + fn state_at(&self, hash: &Block::Hash) -> ClientResult { + if hash == &self.blockchain.meta.read().genesis_hash { if let Some(genesis_state) = &*self.genesis_state.read() { let root = genesis_state.root; let db_state = DbStateBuilder::::new(genesis_state.clone(), root) @@ -2322,14 +2316,7 @@ impl sc_client_api::backend::Backend for Backend { } } - let hash = match block { - BlockId::Hash(h) => h, - BlockId::Number(n) => self.blockchain.hash(n)?.ok_or_else(|| { - sp_blockchain::Error::UnknownBlock(format!("Unknown block number {}", n)) - })?, - }; - - match self.blockchain.header_metadata(hash) { + match self.blockchain.header_metadata(*hash) { Ok(ref hdr) => { let hint = || { sc_state_db::NodeDb::get(self.storage.as_ref(), hdr.state_root.as_ref()) @@ -2337,7 +2324,7 @@ impl sc_client_api::backend::Backend for Backend { .is_some() }; if let Ok(()) = - self.storage.state_db.pin(&hash, hdr.number.saturated_into::(), hint) + self.storage.state_db.pin(hash, hdr.number.saturated_into::(), hint) { let root = hdr.state_root; let db_state = DbStateBuilder::::new(self.storage.clone(), root) @@ -2345,12 +2332,12 @@ impl sc_client_api::backend::Backend for Backend { self.shared_trie_cache.as_ref().map(|c| c.local_cache()), ) .build(); - let state = RefTrackingState::new(db_state, self.storage.clone(), Some(hash)); - Ok(RecordStatsState::new(state, Some(hash), self.state_usage.clone())) + let state = RefTrackingState::new(db_state, self.storage.clone(), Some(*hash)); + Ok(RecordStatsState::new(state, Some(*hash), self.state_usage.clone())) } else { Err(sp_blockchain::Error::UnknownBlock(format!( "State already discarded for {:?}", - block + hash ))) } }, @@ -2588,7 +2575,7 @@ pub(crate) mod tests { db.commit_operation(op).unwrap(); - let state = db.state_at(BlockId::Number(0)).unwrap(); + let state = db.state_at(&hash).unwrap(); assert_eq!(state.storage(&[1, 3, 5]).unwrap(), Some(vec![2, 4, 6])); assert_eq!(state.storage(&[1, 2, 3]).unwrap(), Some(vec![9, 9, 9])); @@ -2623,7 +2610,8 @@ pub(crate) mod tests { db.commit_operation(op).unwrap(); - let state = db.state_at(BlockId::Number(1)).unwrap(); + let hash = db.blockchain().expect_block_hash_from_id(&BlockId::Number(1)).unwrap(); + let state = db.state_at(&hash).unwrap(); assert_eq!(state.storage(&[1, 3, 5]).unwrap(), None); assert_eq!(state.storage(&[1, 2, 3]).unwrap(), Some(vec![9, 9, 9])); @@ -3139,11 +3127,7 @@ pub(crate) mod tests { hash }; - let block0_hash = backend - .state_at(BlockId::Hash(hash0)) - .unwrap() - .storage_hash(&b"test"[..]) - .unwrap(); + let block0_hash = backend.state_at(&hash0).unwrap().storage_hash(&b"test"[..]).unwrap(); let hash1 = { let mut op = backend.begin_operation().unwrap(); @@ -3182,11 +3166,7 @@ pub(crate) mod tests { backend.commit_operation(op).unwrap(); } - let block1_hash = backend - .state_at(BlockId::Hash(hash1)) - .unwrap() - .storage_hash(&b"test"[..]) - .unwrap(); + let block1_hash = backend.state_at(&hash1).unwrap().storage_hash(&b"test"[..]).unwrap(); assert_ne!(block0_hash, block1_hash); } diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index e39436ec641d7..8ab332a24be78 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -147,17 +147,14 @@ where extensions: Option, ) -> sp_blockchain::Result> { let mut changes = OverlayedChanges::default(); - let state = self.backend.state_at(*at)?; + let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + let state = self.backend.state_at(&at_hash)?; let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; let runtime_code = self.check_override(runtime_code, at)?; - let at_hash = self.backend.blockchain().block_hash_from_id(at)?.ok_or_else(|| { - sp_blockchain::Error::UnknownBlock(format!("Could not find block hash for {:?}", at)) - })?; - let mut sm = StateMachine::new( &state, &mut changes, @@ -195,14 +192,11 @@ where { let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut()); - let state = self.backend.state_at(*at)?; + let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + let state = self.backend.state_at(&at_hash)?; let changes = &mut *changes.borrow_mut(); - let at_hash = self.backend.blockchain().block_hash_from_id(at)?.ok_or_else(|| { - sp_blockchain::Error::UnknownBlock(format!("Could not find block hash for {:?}", at)) - })?; - // It is important to extract the runtime code here before we create the proof // recorder to not record it. We also need to fetch the runtime code from `state` to // make sure we use the caching layers. @@ -255,7 +249,9 @@ where fn runtime_version(&self, id: &BlockId) -> sp_blockchain::Result { let mut overlay = OverlayedChanges::default(); - let state = self.backend.state_at(*id)?; + + let at_hash = self.backend.blockchain().expect_block_hash_from_id(id)?; + let state = self.backend.state_at(&at_hash)?; let mut cache = StorageTransactionCache::::default(); let mut ext = Ext::new(&mut overlay, &mut cache, &state, None); let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); @@ -272,7 +268,8 @@ where method: &str, call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)> { - let state = self.backend.state_at(*at)?; + let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + let state = self.backend.state_at(&at_hash)?; let trie_backend = state.as_trie_backend(); diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 27561046c3481..e2fd5cda1d2f0 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -414,8 +414,8 @@ where } /// Get a reference to the state at a given block. - pub fn state_at(&self, block: &BlockId) -> sp_blockchain::Result { - self.backend.state_at(*block) + pub fn state_at(&self, hash: &Block::Hash) -> sp_blockchain::Result { + self.backend.state_at(hash) } /// Get the code at a given block. @@ -813,7 +813,7 @@ where Block::new(import_block.header.clone(), body.clone()), )?; - let state = self.backend.state_at(at)?; + let state = self.backend.state_at(parent_hash)?; let gen_storage_changes = runtime_api .into_storage_changes(&state, *parent_hash) .map_err(sp_blockchain::Error::Storage)?; @@ -1154,7 +1154,9 @@ where id: &BlockId, keys: &mut dyn Iterator, ) -> sp_blockchain::Result { - self.state_at(id).and_then(|state| prove_read(state, keys).map_err(Into::into)) + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + self.state_at(&hash) + .and_then(|state| prove_read(state, keys).map_err(Into::into)) } fn read_child_proof( @@ -1163,7 +1165,8 @@ where child_info: &ChildInfo, keys: &mut dyn Iterator, ) -> sp_blockchain::Result { - self.state_at(id) + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + self.state_at(&hash) .and_then(|state| prove_child_read(state, child_info, keys).map_err(Into::into)) } @@ -1182,7 +1185,8 @@ where start_key: &[Vec], size_limit: usize, ) -> sp_blockchain::Result<(CompactProof, u32)> { - let state = self.state_at(id)?; + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + let state = self.state_at(&hash)?; // this is a read proof, using version V0 or V1 is equivalent. let root = state.storage_root(std::iter::empty(), StateVersion::V0).0; @@ -1204,7 +1208,8 @@ where if start_key.len() > MAX_NESTED_TRIE_DEPTH { return Err(Error::Backend("Invalid start key.".to_string())) } - let state = self.state_at(id)?; + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + let state = self.state_at(&hash)?; let child_info = |storage_key: &Vec| -> sp_blockchain::Result { let storage_key = PrefixedStorageKey::new_ref(storage_key); match ChildType::from_prefixed_key(storage_key) { @@ -1400,7 +1405,8 @@ where id: &BlockId, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { - let keys = self.state_at(id)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + let keys = self.state_at(&hash)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); Ok(keys) } @@ -1409,7 +1415,8 @@ where id: &BlockId, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { - let state = self.state_at(id)?; + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + let state = self.state_at(&hash)?; let keys = state .keys(&key_prefix.0) .into_iter() @@ -1427,7 +1434,8 @@ where prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result> { - let state = self.state_at(id)?; + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + let state = self.state_at(&hash)?; let start_key = start_key.or(prefix).map(|key| key.0.clone()).unwrap_or_else(Vec::new); Ok(KeyIterator::new(state, prefix, start_key)) } @@ -1439,7 +1447,8 @@ where prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result> { - let state = self.state_at(id)?; + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + let state = self.state_at(&hash)?; let start_key = start_key.or(prefix).map(|key| key.0.clone()).unwrap_or_else(Vec::new); Ok(KeyIterator::new_child(state, child_info, prefix, start_key)) } @@ -1449,8 +1458,9 @@ where id: &BlockId, key: &StorageKey, ) -> sp_blockchain::Result> { + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; Ok(self - .state_at(id)? + .state_at(&hash)? .storage(&key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? .map(StorageData)) @@ -1461,7 +1471,8 @@ where id: &BlockId, key: &StorageKey, ) -> sp_blockchain::Result> { - self.state_at(id)? + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + self.state_at(&hash)? .storage_hash(&key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } @@ -1472,8 +1483,9 @@ where child_info: &ChildInfo, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; let keys = self - .state_at(id)? + .state_at(&hash)? .child_keys(child_info, &key_prefix.0) .into_iter() .map(StorageKey) @@ -1487,8 +1499,9 @@ where child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; Ok(self - .state_at(id)? + .state_at(&hash)? .child_storage(child_info, &key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? .map(StorageData)) @@ -1500,7 +1513,8 @@ where child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { - self.state_at(id)? + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + self.state_at(&hash)? .child_storage_hash(child_info, &key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } @@ -1681,7 +1695,8 @@ where } fn state_at(&self, at: &BlockId) -> Result { - self.state_at(at).map_err(Into::into) + let hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + self.state_at(&hash).map_err(Into::into) } } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index e0f47110d9046..c6ac1fc7d73d9 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -20,7 +20,7 @@ use futures::executor::block_on; use parity_scale_codec::{Decode, Encode, Joiner}; use sc_block_builder::BlockBuilderProvider; use sc_client_api::{ - in_mem, BlockBackend, BlockchainEvents, FinalityNotifications, StorageProvider, + in_mem, BlockBackend, BlockchainEvents, FinalityNotifications, HeaderBackend, StorageProvider, }; use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, DatabaseSource, PruningMode}; use sc_consensus::{ @@ -338,11 +338,15 @@ fn block_builder_works_with_transactions() { let block = builder.build().unwrap().block; block_on(client.import(BlockOrigin::Own, block)).unwrap(); + let hash0 = client + .expect_block_hash_from_id(&BlockId::Number(0)) + .expect("block 0 was just imported. qed"); + let hash1 = client + .expect_block_hash_from_id(&BlockId::Number(1)) + .expect("block 1 was just imported. qed"); + assert_eq!(client.chain_info().best_number, 1); - assert_ne!( - client.state_at(&BlockId::Number(1)).unwrap().pairs(), - client.state_at(&BlockId::Number(0)).unwrap().pairs() - ); + assert_ne!(client.state_at(&hash1).unwrap().pairs(), client.state_at(&hash0).unwrap().pairs()); assert_eq!( client .runtime_api() @@ -392,11 +396,15 @@ fn block_builder_does_not_include_invalid() { let block = builder.build().unwrap().block; block_on(client.import(BlockOrigin::Own, block)).unwrap(); + let hash0 = client + .expect_block_hash_from_id(&BlockId::Number(0)) + .expect("block 0 was just imported. qed"); + let hash1 = client + .expect_block_hash_from_id(&BlockId::Number(1)) + .expect("block 1 was just imported. qed"); + assert_eq!(client.chain_info().best_number, 1); - assert_ne!( - client.state_at(&BlockId::Number(1)).unwrap().pairs(), - client.state_at(&BlockId::Number(0)).unwrap().pairs() - ); + assert_ne!(client.state_at(&hash1).unwrap().pairs(), client.state_at(&hash0).unwrap().pairs()); assert_eq!(client.body(&BlockId::Number(1)).unwrap().unwrap().len(), 1) } diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index f80c6d0269116..79c05aec8adca 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -78,8 +78,8 @@ pub trait HeaderBackend: Send + Sync { /// Convert an arbitrary block ID into a block hash. Returns `UnknownBlock` error if block is /// not found. fn expect_block_hash_from_id(&self, id: &BlockId) -> Result { - self.block_hash_from_id(id).and_then(|n| { - n.ok_or_else(|| Error::UnknownBlock(format!("Expect block hash from id: {}", id))) + self.block_hash_from_id(id).and_then(|h| { + h.ok_or_else(|| Error::UnknownBlock(format!("Expect block hash from id: {}", id))) }) } } diff --git a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index f9a57206ece4d..c3d3ec816f97e 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -24,7 +24,7 @@ use jsonrpsee::{ }; use sc_rpc_api::DenyUnsafe; use serde::{Deserialize, Serialize}; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use std::sync::Arc; use sp_core::{ @@ -144,8 +144,8 @@ where fn call(&self, at: Option<::Hash>) -> RpcResult { self.deny_unsafe.check_if_safe()?; - let block_id = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - let state = self.backend.state_at(block_id).map_err(error_into_rpc_err)?; + let hash = at.unwrap_or_else(|| self.client.info().best_hash); + let state = self.backend.state_at(&hash).map_err(error_into_rpc_err)?; let (top, child) = migration_status(&state).map_err(error_into_rpc_err)?; Ok(MigrationStatusResult { From 0ee03277c33b6334ddba7434e014fa637dcb6107 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 14 Oct 2022 13:26:13 +0200 Subject: [PATCH 1272/1472] Try-runtime CLI fix weight parsing (#12491) Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 1 + utils/frame/try-runtime/cli/Cargo.toml | 1 + .../try-runtime/cli/src/commands/follow_chain.rs | 5 +++-- .../cli/src/commands/on_runtime_upgrade.rs | 14 ++++++++------ 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 062195c70f8ab..032886b9945e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11356,6 +11356,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-version", + "sp-weights", "tokio", "zstd", ] diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 56ead30644d86..956eaff745335 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -31,6 +31,7 @@ sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../../primitives/state-machine" } sp-version = { version = "5.0.0", path = "../../../../primitives/version" } +sp-weights = { version = "4.0.0", path = "../../../../primitives/weights" } frame-try-runtime = { path = "../../../../frame/try-runtime" } [dev-dependencies] diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index 88866b538169b..fb5345827858a 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -33,6 +33,7 @@ use sc_service::Configuration; use serde::de::DeserializeOwned; use sp_core::H256; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use sp_weights::Weight; use std::{collections::VecDeque, fmt::Debug, str::FromStr}; const SUB: &str = "chain_subscribeFinalizedHeads"; @@ -294,8 +295,8 @@ where full_extensions(), )?; - let consumed_weight = ::decode(&mut &*encoded_result) - .map_err(|e| format!("failed to decode output: {:?}", e))?; + let consumed_weight = ::decode(&mut &*encoded_result) + .map_err(|e| format!("failed to decode weight: {:?}", e))?; let storage_changes = changes .drain_storage_changes( diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 5055e4fb34581..1d7d876a4aa92 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -21,6 +21,7 @@ use parity_scale_codec::Decode; use sc_executor::NativeExecutionDispatch; use sc_service::Configuration; use sp_runtime::traits::{Block as BlockT, NumberFor}; +use sp_weights::Weight; use crate::{ build_executor, ensure_matching_spec, extract_code, local_spec, state_machine_call_with_proof, @@ -78,14 +79,15 @@ where Default::default(), // we don't really need any extensions here. )?; - let (weight, total_weight) = <(u64, u64) as Decode>::decode(&mut &*encoded_result) - .map_err(|e| format!("failed to decode output: {:?}", e))?; + let (weight, total_weight) = <(Weight, Weight) as Decode>::decode(&mut &*encoded_result) + .map_err(|e| format!("failed to decode weight: {:?}", e))?; log::info!( target: LOG_TARGET, - "TryRuntime_on_runtime_upgrade executed without errors. Consumed weight = {}, total weight = {} ({})", - weight, - total_weight, - weight as f64 / total_weight.max(1) as f64 + "TryRuntime_on_runtime_upgrade executed without errors. Consumed weight = ({} ps, {} byte), total weight = ({} ps, {} byte) ({:.2} %, {:.2} %).", + weight.ref_time(), weight.proof_size(), + total_weight.ref_time(), total_weight.proof_size(), + (weight.ref_time() as f64 / total_weight.ref_time().max(1) as f64) * 100.0, + (weight.proof_size() as f64 / total_weight.proof_size().max(1) as f64) * 100.0, ); Ok(()) From 6f453b5c2b6d7479189da06fd03e403b95503bdd Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 17 Oct 2022 14:27:24 +0800 Subject: [PATCH 1273/1472] Export fn code_hash (#12479) Co-authored-by: parity-processbot <> --- frame/contracts/src/lib.rs | 5 +++++ frame/contracts/src/storage.rs | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 794b172cc6282..d48a71b85e9fe 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -1031,6 +1031,11 @@ where T::AddressGenerator::generate_address(deploying_address, code_hash, salt) } + /// Returns the code hash of the contract specified by `account` ID. + pub fn code_hash(account: &AccountIdOf) -> Option> { + Storage::::code_hash(account) + } + /// Store code for benchmarks which does not check nor instrument the code. #[cfg(feature = "runtime-benchmarks")] fn store_code_raw( diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index cf10c3225c920..c7644e696196f 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -328,7 +328,6 @@ where } /// Returns the code hash of the contract specified by `account` ID. - #[cfg(test)] pub fn code_hash(account: &AccountIdOf) -> Option> { >::get(account).map(|i| i.code_hash) } From 30a7a5b4b71f23971742684889f9fdec5f5854a9 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Mon, 17 Oct 2022 10:25:25 +0300 Subject: [PATCH 1274/1472] Introduce `ChainSyncInterface` (#12489) * Introduce `ChainSyncInterface` `ChainSyncInterface` provides an asynchronous interface for other subsystems to submit calls to `ChainSync`. This allows `NetworkService` to delegate calls to `ChainSync` while still providing the same API for other subsystems (for now). This makes it possible to move the syncing code in piecemeal fashion out of `protocol.rs` as the calls are just forwarded to `ChainSync`. * Apply review comments * Fix tests --- Cargo.lock | 2 + client/network/common/src/sync.rs | 10 ++++ client/network/src/config.rs | 4 ++ client/network/src/lib.rs | 12 ++++ client/network/src/protocol.rs | 19 ++---- client/network/src/service.rs | 13 ++-- client/network/src/service/chainsync_tests.rs | 56 ++++++++++++++---- client/network/src/service/tests.rs | 3 +- client/network/sync/Cargo.toml | 2 + client/network/sync/src/lib.rs | 45 ++++++++++---- client/network/sync/src/mock.rs | 4 ++ client/network/sync/src/service/chain_sync.rs | 58 ++++++++++++++++++ client/network/sync/src/service/mock.rs | 31 ++++++++++ client/network/sync/src/service/mod.rs | 22 +++++++ client/network/sync/src/tests.rs | 59 +++++++++++++++++++ client/network/test/src/lib.rs | 3 +- client/service/src/builder.rs | 3 +- 17 files changed, 301 insertions(+), 45 deletions(-) create mode 100644 client/network/sync/src/service/chain_sync.rs create mode 100644 client/network/sync/src/service/mock.rs create mode 100644 client/network/sync/src/service/mod.rs create mode 100644 client/network/sync/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 032886b9945e2..7f49ff75561db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8638,6 +8638,7 @@ name = "sc-network-sync" version = "0.10.0-dev" dependencies = [ "array-bytes", + "async-std", "fork-tree", "futures", "libp2p", @@ -8653,6 +8654,7 @@ dependencies = [ "sc-consensus", "sc-network-common", "sc-peerset", + "sc-utils", "smallvec", "sp-arithmetic", "sp-blockchain", diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index d3603c6792c84..aa761e66ebf68 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -395,4 +395,14 @@ pub trait ChainSync: Send { /// Decode implementation-specific state response. fn decode_state_response(&self, response: &[u8]) -> Result; + + /// Advance the state of `ChainSync` + /// + /// Internally calls [`ChainSync::poll_block_announce_validation()`] and + /// this function should be polled until it returns [`Poll::Pending`] to + /// consume all pending events. + fn poll( + &mut self, + cx: &mut std::task::Context, + ) -> Poll>; } diff --git a/client/network/src/config.rs b/client/network/src/config.rs index db3e8f0b98a33..dcd7c7d8ad6de 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -33,6 +33,7 @@ pub use sc_network_common::{ pub use libp2p::{build_multiaddr, core::PublicKey, identity}; +use crate::ChainSyncInterface; use core::{fmt, iter}; use libp2p::{ identity::{ed25519, Keypair}, @@ -91,6 +92,9 @@ where /// Instance of chain sync implementation. pub chain_sync: Box>, + /// Interface that can be used to delegate syncing-related function calls to `ChainSync` + pub chain_sync_service: Box>, + /// Registry for recording prometheus metrics to. pub metrics_registry: Option, diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 27f2a938154fe..f3faa44ee6dbd 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -279,6 +279,7 @@ pub use service::{ DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, NotificationSenderReady, OutboundFailure, PublicKey, }; +use sp_runtime::traits::{Block as BlockT, NumberFor}; pub use sc_peerset::ReputationChange; @@ -293,3 +294,14 @@ const MAX_CONNECTIONS_PER_PEER: usize = 2; /// The maximum number of concurrent established connections that were incoming. const MAX_CONNECTIONS_ESTABLISHED_INCOMING: u32 = 10_000; + +/// Abstraction over syncing-related services +pub trait ChainSyncInterface: + NetworkSyncForkRequest> + Send + Sync +{ +} + +impl ChainSyncInterface for T where + T: NetworkSyncForkRequest> + Send + Sync +{ +} diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index c3def8adc6cfe..a04dba79f7fd2 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -947,18 +947,6 @@ where self.chain_sync.clear_justification_requests(); } - /// Request syncing for the given block from given set of peers. - /// Uses `protocol` to queue a new block download request and tries to dispatch all pending - /// requests. - pub fn set_sync_fork_request( - &mut self, - peers: Vec, - hash: &B::Hash, - number: NumberFor, - ) { - self.chain_sync.set_sync_fork_request(peers, hash, number) - } - /// A batch of blocks have been processed, with or without errors. /// Call this when a batch of blocks have been processed by the importqueue, with or without /// errors. @@ -1461,8 +1449,11 @@ where self.pending_messages.push_back(event); } - // Check if there is any block announcement validation finished. - while let Poll::Ready(result) = self.chain_sync.poll_block_announce_validation(cx) { + // Advance the state of `ChainSync` + // + // Process any received requests received from `NetworkService` and + // check if there is any block announcement validation finished. + while let Poll::Ready(result) = self.chain_sync.poll(cx) { match self.process_block_announce_validation_result(result) { CustomMessageOutcome::None => {}, outcome => self.pending_messages.push_back(outcome), diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 25916041285a3..d1f428cc292c3 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -35,7 +35,7 @@ use crate::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, protocol::{self, NotificationsSink, NotifsHandlerError, PeerInfo, Protocol, Ready}, - transport, ReputationChange, + transport, ChainSyncInterface, ReputationChange, }; use futures::{channel::oneshot, prelude::*}; @@ -121,6 +121,8 @@ pub struct NetworkService { peerset: PeersetHandle, /// Channel that sends messages to the actual worker. to_worker: TracingUnboundedSender>, + /// Interface that can be used to delegate calls to `ChainSync` + chain_sync_service: Box>, /// For each peer and protocol combination, an object that allows sending notifications to /// that peer. Updated by the [`NetworkWorker`]. peers_notifications_sinks: Arc>>, @@ -433,6 +435,7 @@ where local_peer_id, local_identity, to_worker, + chain_sync_service: params.chain_sync_service, peers_notifications_sinks: peers_notifications_sinks.clone(), notifications_sizes_metric: metrics .as_ref() @@ -814,7 +817,7 @@ where /// a stale fork missing. /// Passing empty `peers` set effectively removes the sync request. fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::SyncFork(peers, hash, number)); + self.chain_sync_service.set_sync_fork_request(peers, hash, number); } } @@ -1219,7 +1222,6 @@ enum ServiceToWorkerMsg { RemoveSetReserved(ProtocolName, PeerId), AddToPeersSet(ProtocolName, PeerId), RemoveFromPeersSet(ProtocolName, PeerId), - SyncFork(Vec, B::Hash, NumberFor), EventStream(out_events::Sender), Request { target: PeerId, @@ -1380,11 +1382,6 @@ where .behaviour_mut() .user_protocol_mut() .remove_from_peers_set(protocol, peer_id), - ServiceToWorkerMsg::SyncFork(peer_ids, hash, number) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .set_sync_fork_request(peer_ids, &hash, number), ServiceToWorkerMsg::EventStream(sender) => this.event_streams.push(sender), ServiceToWorkerMsg::Request { target, diff --git a/client/network/src/service/chainsync_tests.rs b/client/network/src/service/chainsync_tests.rs index ca44c65d267f4..27c0588a67200 100644 --- a/client/network/src/service/chainsync_tests.rs +++ b/client/network/src/service/chainsync_tests.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{config, NetworkWorker}; +use crate::{config, ChainSyncInterface, NetworkWorker}; use futures::prelude::*; use libp2p::PeerId; @@ -35,7 +35,7 @@ use sc_network_common::{ use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ block_request_handler::BlockRequestHandler, mock::MockChainSync, - state_request_handler::StateRequestHandler, + service::mock::MockChainSyncInterface, state_request_handler::StateRequestHandler, }; use sp_core::H256; use sp_runtime::{ @@ -56,6 +56,7 @@ const PROTOCOL_NAME: &str = "/foo"; fn make_network( chain_sync: Box>, + chain_sync_service: Box>, client: Arc, ) -> (TestNetworkWorker, Arc) { let network_config = config::NetworkConfiguration { @@ -174,6 +175,7 @@ fn make_network( fork_id, import_queue, chain_sync, + chain_sync_service, metrics_registry: None, block_request_protocol_config, state_request_protocol_config, @@ -193,7 +195,7 @@ fn set_default_expecations_no_peers( chain_sync.expect_state_request().returning(|| None); chain_sync.expect_justification_requests().returning(|| Box::new(iter::empty())); chain_sync.expect_warp_sync_request().returning(|| None); - chain_sync.expect_poll_block_announce_validation().returning(|_| Poll::Pending); + chain_sync.expect_poll().returning(|_| Poll::Pending); chain_sync.expect_status().returning(|| SyncStatus { state: SyncState::Idle, best_seen_block: None, @@ -207,11 +209,18 @@ fn set_default_expecations_no_peers( #[async_std::test] async fn normal_network_poll_no_peers() { let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + + // build `ChainSync` and set default expectations for it let mut chain_sync = Box::new(MockChainSync::::new()); set_default_expecations_no_peers(&mut chain_sync); - let (mut network, _) = make_network(chain_sync, client); + // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be + // called) + let chain_sync_service = + Box::new(MockChainSyncInterface::::new()); + + let (mut network, _) = make_network(chain_sync, chain_sync_service, client); // poll the network once futures::future::poll_fn(|cx| { @@ -224,6 +233,13 @@ async fn normal_network_poll_no_peers() { #[async_std::test] async fn request_justification() { let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + + // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be + // called) + let chain_sync_service = + Box::new(MockChainSyncInterface::::new()); + + // build `ChainSync` and verify that call to `request_justification()` is made let mut chain_sync = Box::new(MockChainSync::::new()); @@ -237,7 +253,7 @@ async fn request_justification() { .returning(|_, _| ()); set_default_expecations_no_peers(&mut chain_sync); - let (mut network, _) = make_network(chain_sync, client); + let (mut network, _) = make_network(chain_sync, chain_sync_service, client); // send "request justifiction" message and poll the network network.service().request_justification(&hash, number); @@ -252,13 +268,20 @@ async fn request_justification() { #[async_std::test] async fn clear_justification_requests(&mut self) { let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + + // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be + // called) + let chain_sync_service = + Box::new(MockChainSyncInterface::::new()); + + // build `ChainSync` and verify that call to `clear_justification_requests()` is made let mut chain_sync = Box::new(MockChainSync::::new()); chain_sync.expect_clear_justification_requests().once().returning(|| ()); set_default_expecations_no_peers(&mut chain_sync); - let (mut network, _) = make_network(chain_sync, client); + let (mut network, _) = make_network(chain_sync, chain_sync_service, client); // send "request justifiction" message and poll the network network.service().clear_justification_requests(); @@ -273,15 +296,23 @@ async fn clear_justification_requests(&mut self) { #[async_std::test] async fn set_sync_fork_request() { let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + + // build `ChainSync` and set default expectations for it let mut chain_sync = Box::new(MockChainSync::::new()); + set_default_expecations_no_peers(&mut chain_sync); + + // build `ChainSyncInterface` provider and verify that the `set_sync_fork_request()` + // call is delegated to `ChainSyncInterface` (which eventually forwards it to `ChainSync`) + let mut chain_sync_service = + MockChainSyncInterface::::new(); let hash = H256::random(); let number = 1337u64; let peers = (0..3).map(|_| PeerId::random()).collect::>(); let copy_peers = peers.clone(); - chain_sync + chain_sync_service .expect_set_sync_fork_request() .withf(move |in_peers, in_hash, in_number| { &peers == in_peers && &hash == in_hash && &number == in_number @@ -289,8 +320,7 @@ async fn set_sync_fork_request() { .once() .returning(|_, _, _| ()); - set_default_expecations_no_peers(&mut chain_sync); - let (mut network, _) = make_network(chain_sync, client); + let (mut network, _) = make_network(chain_sync, Box::new(chain_sync_service), client); // send "set sync fork request" message and poll the network network.service().set_sync_fork_request(copy_peers, hash, number); @@ -305,6 +335,12 @@ async fn set_sync_fork_request() { #[async_std::test] async fn on_block_finalized() { let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be + // called) + let chain_sync_service = + Box::new(MockChainSyncInterface::::new()); + + // build `ChainSync` and verify that call to `on_block_finalized()` is made let mut chain_sync = Box::new(MockChainSync::::new()); @@ -326,7 +362,7 @@ async fn on_block_finalized() { .returning(|_, _| ()); set_default_expecations_no_peers(&mut chain_sync); - let (mut network, _) = make_network(chain_sync, client); + let (mut network, _) = make_network(chain_sync, chain_sync_service, client); // send "set sync fork request" message and poll the network network.on_block_finalized(hash, header); diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index b656d7a7c0ddc..4a0ef4611da6e 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -124,7 +124,7 @@ fn build_test_full_node( protocol_config }; - let chain_sync = ChainSync::new( + let (chain_sync, chain_sync_service) = ChainSync::new( match network_config.sync_mode { config::SyncMode::Full => sc_network_common::sync::SyncMode::Full, config::SyncMode::Fast { skip_proofs, storage_chain_mode } => @@ -172,6 +172,7 @@ fn build_test_full_node( fork_id, import_queue, chain_sync: Box::new(chain_sync), + chain_sync_service, metrics_registry: None, block_request_protocol_config, state_request_protocol_config, diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 9d032f5cca96c..323b70e9c22a4 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -34,6 +34,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-network-common = { version = "0.10.0-dev", path = "../common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } +sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } @@ -42,6 +43,7 @@ sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/final sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [dev-dependencies] +async-std = { version = "1.11.0", features = ["attributes"] } quickcheck = { version = "1.0.3", default-features = false } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-test-primitives = { version = "2.0.0", path = "../../../primitives/test-primitives" } diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 84998c747b3cc..64d9d4d668eb3 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -32,14 +32,18 @@ pub mod block_request_handler; pub mod blocks; pub mod mock; mod schema; +pub mod service; pub mod state; pub mod state_request_handler; +#[cfg(test)] +mod tests; pub mod warp; pub mod warp_request_handler; use crate::{ blocks::BlockCollection, schema::v1::{StateRequest, StateResponse}, + service::chain_sync::{ChainSyncInterfaceHandle, ToServiceCommand}, state::StateSync, warp::{WarpProofImportResult, WarpSync}, }; @@ -67,6 +71,7 @@ use sc_network_common::{ PollBlockAnnounceValidation, SyncMode, SyncState, SyncStatus, }, }; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; use sp_arithmetic::traits::Saturating; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; use sp_consensus::{ @@ -264,6 +269,8 @@ pub struct ChainSync { import_existing: bool, /// Gap download process. gap_sync: Option>, + /// Channel for receiving service commands + service_rx: TracingUnboundedReceiver>, } /// All the data we have about a Peer that we are trying to sync with @@ -1725,6 +1732,21 @@ where Ok(OpaqueStateResponse(Box::new(response))) } + + fn poll( + &mut self, + cx: &mut std::task::Context, + ) -> Poll> { + while let Poll::Ready(Some(event)) = self.service_rx.poll_next_unpin(cx) { + match event { + ToServiceCommand::SetSyncForkRequest(peers, hash, number) => { + self.set_sync_fork_request(peers, &hash, number); + }, + } + } + + self.poll_block_announce_validation(cx) + } } impl ChainSync @@ -1746,7 +1768,9 @@ where block_announce_validator: Box + Send>, max_parallel_downloads: u32, warp_sync_provider: Option>>, - ) -> Result { + ) -> Result<(Self, Box>), ClientError> { + let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync"); + let mut sync = Self { client, peers: HashMap::new(), @@ -1768,9 +1792,10 @@ where warp_sync_provider, import_existing: false, gap_sync: None, + service_rx, }; sync.reset_sync_start_point()?; - Ok(sync) + Ok((sync, Box::new(ChainSyncInterfaceHandle::new(tx)))) } /// Returns the best seen block number if we don't have that block yet, `None` otherwise. @@ -2664,7 +2689,7 @@ mod test { let block_announce_validator = Box::new(DefaultBlockAnnounceValidator); let peer_id = PeerId::random(); - let mut sync = + let (mut sync, _) = ChainSync::new(SyncMode::Full, client.clone(), block_announce_validator, 1, None) .unwrap(); @@ -2712,7 +2737,7 @@ mod test { #[test] fn restart_doesnt_affect_peers_downloading_finality_data() { let mut client = Arc::new(TestClientBuilder::new().build()); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -2879,7 +2904,7 @@ mod test { let mut client = Arc::new(TestClientBuilder::new().build()); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -2994,7 +3019,7 @@ mod test { let mut client = Arc::new(TestClientBuilder::new().build()); let info = client.info(); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -3137,7 +3162,7 @@ mod test { let info = client.info(); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -3268,7 +3293,7 @@ mod test { let info = client.info(); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -3399,7 +3424,7 @@ mod test { let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..3).map(|_| build_block(&mut client, None, false)).collect::>(); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -3432,7 +3457,7 @@ mod test { let empty_client = Arc::new(TestClientBuilder::new().build()); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, empty_client.clone(), Box::new(DefaultBlockAnnounceValidator), diff --git a/client/network/sync/src/mock.rs b/client/network/sync/src/mock.rs index 2a3b059f735b2..fbb54bd5e998d 100644 --- a/client/network/sync/src/mock.rs +++ b/client/network/sync/src/mock.rs @@ -114,5 +114,9 @@ mockall::mock! { ) -> Result>, String>; fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String>; fn decode_state_response(&self, response: &[u8]) -> Result; + fn poll<'a>( + &mut self, + cx: &mut std::task::Context<'a>, + ) -> Poll>; } } diff --git a/client/network/sync/src/service/chain_sync.rs b/client/network/sync/src/service/chain_sync.rs new file mode 100644 index 0000000000000..cf07c65ee3109 --- /dev/null +++ b/client/network/sync/src/service/chain_sync.rs @@ -0,0 +1,58 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use libp2p::PeerId; +use sc_network_common::service::NetworkSyncForkRequest; +use sc_utils::mpsc::TracingUnboundedSender; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +/// Commands send to `ChainSync` +#[derive(Debug)] +pub enum ToServiceCommand { + SetSyncForkRequest(Vec, B::Hash, NumberFor), +} + +/// Handle for communicating with `ChainSync` asynchronously +pub struct ChainSyncInterfaceHandle { + tx: TracingUnboundedSender>, +} + +impl ChainSyncInterfaceHandle { + /// Create new handle + pub fn new(tx: TracingUnboundedSender>) -> Self { + Self { tx } + } +} + +impl NetworkSyncForkRequest> + for ChainSyncInterfaceHandle +{ + /// Configure an explicit fork sync request. + /// + /// Note that this function should not be used for recent blocks. + /// Sync should be able to download all the recent forks normally. + /// `set_sync_fork_request` should only be used if external code detects that there's + /// a stale fork missing. + /// + /// Passing empty `peers` set effectively removes the sync request. + fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor) { + let _ = self + .tx + .unbounded_send(ToServiceCommand::SetSyncForkRequest(peers, hash, number)); + } +} diff --git a/client/network/sync/src/service/mock.rs b/client/network/sync/src/service/mock.rs new file mode 100644 index 0000000000000..e283907b392d1 --- /dev/null +++ b/client/network/sync/src/service/mock.rs @@ -0,0 +1,31 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use libp2p::PeerId; +use sc_network_common::service::NetworkSyncForkRequest; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +mockall::mock! { + pub ChainSyncInterface {} + + impl NetworkSyncForkRequest> + for ChainSyncInterface + { + fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor); + } +} diff --git a/client/network/sync/src/service/mod.rs b/client/network/sync/src/service/mod.rs new file mode 100644 index 0000000000000..d64d9bbd1b01f --- /dev/null +++ b/client/network/sync/src/service/mod.rs @@ -0,0 +1,22 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! `ChainSync`-related service code + +pub mod chain_sync; +pub mod mock; diff --git a/client/network/sync/src/tests.rs b/client/network/sync/src/tests.rs new file mode 100644 index 0000000000000..47483c4ac440d --- /dev/null +++ b/client/network/sync/src/tests.rs @@ -0,0 +1,59 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{ChainSync, ForkTarget}; + +use libp2p::PeerId; +use sc_network_common::{service::NetworkSyncForkRequest, sync::ChainSync as ChainSyncT}; +use sp_consensus::block_validation::DefaultBlockAnnounceValidator; +use sp_core::H256; +use std::{sync::Arc, task::Poll}; +use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; + +// verify that the fork target map is empty, then submit a new sync fork request, +// poll `ChainSync` and verify that a new sync fork request has been registered +#[async_std::test] +async fn delegate_to_chainsync() { + let (mut chain_sync, chain_sync_service) = ChainSync::new( + sc_network_common::sync::SyncMode::Full, + Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0), + Box::new(DefaultBlockAnnounceValidator), + 1u32, + None, + ) + .unwrap(); + + let hash = H256::random(); + let in_number = 1337u64; + let peers = (0..3).map(|_| PeerId::random()).collect::>(); + + assert!(chain_sync.fork_targets.is_empty()); + chain_sync_service.set_sync_fork_request(peers, hash, in_number); + + futures::future::poll_fn(|cx| { + let _ = chain_sync.poll(cx); + Poll::Ready(()) + }) + .await; + + if let Some(ForkTarget { number, .. }) = chain_sync.fork_targets.get(&hash) { + assert_eq!(number, &in_number); + } else { + panic!("expected to contain `ForkTarget`"); + } +} diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index a7c58631dc0f7..d4bee77b54aff 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -864,7 +864,7 @@ where let block_announce_validator = config .block_announce_validator .unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)); - let chain_sync = ChainSync::new( + let (chain_sync, chain_sync_service) = ChainSync::new( match network_config.sync_mode { SyncMode::Full => sc_network_common::sync::SyncMode::Full, SyncMode::Fast { skip_proofs, storage_chain_mode } => @@ -902,6 +902,7 @@ where fork_id, import_queue, chain_sync: Box::new(chain_sync), + chain_sync_service, metrics_registry: None, block_announce_config, block_request_protocol_config, diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 987198d4b7f48..1a16268839054 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -844,7 +844,7 @@ where protocol_config }; - let chain_sync = ChainSync::new( + let (chain_sync, chain_sync_service) = ChainSync::new( match config.network.sync_mode { SyncMode::Full => sc_network_common::sync::SyncMode::Full, SyncMode::Fast { skip_proofs, storage_chain_mode } => @@ -889,6 +889,7 @@ where fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), import_queue: Box::new(import_queue), chain_sync: Box::new(chain_sync), + chain_sync_service, metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_announce_config, block_request_protocol_config, From 951f0754543b4efbefff52b979c8e258064d9ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 17 Oct 2022 10:20:51 +0200 Subject: [PATCH 1275/1472] sp-api: Remove invalid unsafe trait bounds (#12502) The runtime api implementation contained invalid unsafe trait bounds. `Sync` was never correct there and `Send` should have not been "force implemented". --- client/beefy/src/import.rs | 2 +- .../api/proc-macro/src/decl_runtime_apis.rs | 2 +- .../api/proc-macro/src/impl_runtime_apis.rs | 15 ++------------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index 89a4517334189..0ed50d0ec8c98 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -78,7 +78,7 @@ where Block: BlockT, BE: Backend, Runtime: ProvideRuntimeApi, - Runtime::Api: BeefyApi + Send + Sync, + Runtime::Api: BeefyApi + Send, { fn decode_and_verify( &self, diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index aac4491720c34..8d46047dbda5a 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -535,7 +535,7 @@ impl<'a> Fold for ToClientSideDecl<'a> { if is_core_trait { // Add all the supertraits we want to have for `Core`. - input.supertraits = parse_quote!('static + Send + Sync); + input.supertraits = parse_quote!('static + Send); } else { // Add the `Core` runtime api as super trait. let crate_ = &self.crate_; diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index 7a26ead0f586a..c3f4e36655d22 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -211,19 +211,6 @@ fn generate_runtime_api_base_structures() -> Result { recorder: std::option::Option<#crate_::ProofRecorder>, } - // `RuntimeApi` itself is not threadsafe. However, an instance is only available in a - // `ApiRef` object and `ApiRef` also has an associated lifetime. This lifetimes makes it - // impossible to move `RuntimeApi` into another thread. - #[cfg(any(feature = "std", test))] - unsafe impl> Send - for RuntimeApiImpl - {} - - #[cfg(any(feature = "std", test))] - unsafe impl> Sync - for RuntimeApiImpl - {} - #[cfg(any(feature = "std", test))] impl> #crate_::ApiExt for RuntimeApiImpl @@ -515,6 +502,8 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { #crate_::StateBackend<#crate_::HashFor<__SR_API_BLOCK__>> }); + where_clause.predicates.push(parse_quote! { &'static RuntimeApiImplCall: Send }); + // Require that all types used in the function signatures are unwind safe. extract_all_signature_types(&input.items).iter().for_each(|i| { where_clause.predicates.push(parse_quote! { From 273e264b27dbfdae4074b790e934d80097e7e0c0 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 17 Oct 2022 12:09:47 +0300 Subject: [PATCH 1276/1472] pallet-mmr: fix offchain db for sync from zero (#12498) * pallet-mmr: cosmetic improvements * pallet-mmr: fix offchain storage for initial sync * address review comments * pallet-mmr: change offchain fork-resistant key to `(prefix, pos, parent_hash)` Do this so that both canon and fork-resitant keys have the same `(prefix, pos).encode()` prefix. Might be useful in the future if we'd be able to to "get" offchain db entries using key prefixes as well. Signed-off-by: acatangiu Signed-off-by: acatangiu --- frame/beefy-mmr/src/tests.rs | 8 +- frame/merkle-mountain-range/src/lib.rs | 95 ++++++++++++------ .../merkle-mountain-range/src/mmr/storage.rs | 97 +++++++++++-------- frame/merkle-mountain-range/src/tests.rs | 71 +++++++------- 4 files changed, 163 insertions(+), 108 deletions(-) diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index b9851d9eef6cb..1826331f59e53 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -100,8 +100,8 @@ fn should_contain_mmr_digest() { #[test] fn should_contain_valid_leaf_data() { - fn node_offchain_key(parent_hash: H256, pos: usize) -> Vec { - (::INDEXING_PREFIX, parent_hash, pos as u64).encode() + fn node_offchain_key(pos: usize, parent_hash: H256) -> Vec { + (::INDEXING_PREFIX, pos as u64, parent_hash).encode() } let mut ext = new_test_ext(vec![1, 2, 3, 4]); @@ -110,7 +110,7 @@ fn should_contain_valid_leaf_data() { >::parent_hash() }); - let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(parent_hash, 0)); + let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(0, parent_hash)); assert_eq!( mmr_leaf, MmrLeaf { @@ -135,7 +135,7 @@ fn should_contain_valid_leaf_data() { >::parent_hash() }); - let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(parent_hash, 1)); + let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(1, parent_hash)); assert_eq!( mmr_leaf, MmrLeaf { diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index ad3ce340496e8..92ab8702b65c0 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -57,9 +57,9 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::Encode; -use frame_support::weights::Weight; +use frame_support::{log, traits::Get, weights::Weight}; use sp_runtime::{ - traits::{self, CheckedSub, One, Saturating}, + traits::{self, CheckedSub, One, Saturating, UniqueSaturatedInto}, SaturatedConversion, }; @@ -103,6 +103,15 @@ pub trait WeightInfo { fn on_initialize(peaks: NodeIndex) -> Weight; } +/// A MMR specific to the pallet. +type ModuleMmr = mmr::Mmr>; + +/// Leaf data. +type LeafOf = <>::LeafData as primitives::LeafDataProvider>::LeafData; + +/// Hashing used for the pallet. +pub(crate) type HashingOf = >::Hashing; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -166,7 +175,7 @@ pub mod pallet { /// Note that the leaf at each block MUST be unique. You may want to include a block hash or /// block number as an easiest way to ensure that. /// Also note that the leaf added by each block is expected to only reference data coming - /// from ancestor blocks (leaves are saved offchain using `(parent_hash, pos)` key to be + /// from ancestor blocks (leaves are saved offchain using `(pos, parent_hash)` key to be /// fork-resistant, as such conflicts could only happen on 1-block deep forks, which means /// two forks with identical line of ancestors compete to write the same offchain key, but /// that's fine as long as leaves only contain data coming from ancestors - conflicting @@ -212,12 +221,22 @@ pub mod pallet { let leaves = Self::mmr_leaves(); let peaks_before = mmr::utils::NodesUtils::new(leaves).number_of_peaks(); let data = T::LeafData::leaf_data(); + // append new leaf to MMR let mut mmr: ModuleMmr = mmr::Mmr::new(leaves); - mmr.push(data).expect("MMR push never fails."); - - // update the size - let (leaves, root) = mmr.finalize().expect("MMR finalize never fails."); + // MMR push never fails, but better safe than sorry. + if mmr.push(data).is_none() { + log::error!(target: "runtime::mmr", "MMR push failed"); + return T::WeightInfo::on_initialize(peaks_before) + } + // Update the size, `mmr.finalize()` should also never fail. + let (leaves, root) = match mmr.finalize() { + Ok((leaves, root)) => (leaves, root), + Err(e) => { + log::error!(target: "runtime::mmr", "MMR finalize failed: {:?}", e); + return T::WeightInfo::on_initialize(peaks_before) + }, + }; >::on_new_root(&root); >::put(leaves); @@ -230,21 +249,35 @@ pub mod pallet { fn offchain_worker(n: T::BlockNumber) { use mmr::storage::{OffchainStorage, Storage}; - // MMR pallet uses offchain storage to hold full MMR and leaves. - // The leaves are saved under fork-unique keys `(parent_hash, pos)`. - // MMR Runtime depends on `frame_system::block_hash(block_num)` mappings to find - // parent hashes for particular nodes or leaves. - // This MMR offchain worker function moves a rolling window of the same size - // as `frame_system::block_hash` map, where nodes/leaves added by blocks that are just + // The MMR nodes can be found in offchain db under either: + // - fork-unique keys `(prefix, pos, parent_hash)`, or, + // - "canonical" keys `(prefix, pos)`, + // depending on how many blocks in the past the node at position `pos` was + // added to the MMR. + // + // For the fork-unique keys, the MMR pallet depends on + // `frame_system::block_hash(parent_num)` mappings to find the relevant parent block + // hashes, so it is limited by `frame_system::BlockHashCount` in terms of how many + // historical forks it can track. Nodes added to MMR by block `N` can be found in + // offchain db at: + // - fork-unique keys `(prefix, pos, parent_hash)` when (`N` >= `latest_block` - + // `frame_system::BlockHashCount`); + // - "canonical" keys `(prefix, pos)` when (`N` < `latest_block` - + // `frame_system::BlockHashCount`); + // + // The offchain worker is responsible for maintaining the nodes' positions in + // offchain db as the chain progresses by moving a rolling window of the same size as + // `frame_system::block_hash` map, where nodes/leaves added by blocks that are just // about to exit the window are "canonicalized" so that their offchain key no longer - // depends on `parent_hash` therefore on access to `frame_system::block_hash`. + // depends on `parent_hash`. // // This approach works to eliminate fork-induced leaf collisions in offchain db, // under the assumption that no fork will be deeper than `frame_system::BlockHashCount` - // blocks (2400 blocks on Polkadot, Kusama, Rococo, etc): - // entries pertaining to block `N` where `N < current-2400` are moved to a key based - // solely on block number. The only way to have collisions is if two competing forks - // are deeper than 2400 blocks and they both "canonicalize" their view of block `N`. + // blocks: + // entries pertaining to block `N` where `N < current-BlockHashCount` are moved to a + // key based solely on block number. The only way to have collisions is if two + // competing forks are deeper than `frame_system::BlockHashCount` blocks and they + // both "canonicalize" their view of block `N` // Once a block is canonicalized, all MMR entries pertaining to sibling blocks from // other forks are pruned from offchain db. Storage::>::canonicalize_and_prune(n); @@ -252,15 +285,6 @@ pub mod pallet { } } -/// A MMR specific to the pallet. -type ModuleMmr = mmr::Mmr>; - -/// Leaf data. -type LeafOf = <>::LeafData as primitives::LeafDataProvider>::LeafData; - -/// Hashing used for the pallet. -pub(crate) type HashingOf = >::Hashing; - /// Stateless MMR proof verification for batch of leaves. /// /// This function can be used to verify received MMR [primitives::BatchProof] (`proof`) @@ -290,19 +314,32 @@ impl, I: 'static> Pallet { /// /// This combination makes the offchain (key,value) entry resilient to chain forks. fn node_offchain_key( - parent_hash: ::Hash, pos: NodeIndex, + parent_hash: ::Hash, ) -> sp_std::prelude::Vec { - (T::INDEXING_PREFIX, parent_hash, pos).encode() + (T::INDEXING_PREFIX, pos, parent_hash).encode() } /// Build canonical offchain key for node `pos` in MMR. /// /// Used for nodes added by now finalized blocks. + /// Never read keys using `node_canon_offchain_key` unless you sure that + /// there's no `node_offchain_key` key in the storage. fn node_canon_offchain_key(pos: NodeIndex) -> sp_std::prelude::Vec { (T::INDEXING_PREFIX, pos).encode() } + /// Return size of rolling window of leaves saved in offchain under fork-unique keys. + /// + /// Leaves outside this window are canonicalized. + /// Window size is `frame_system::BlockHashCount - 1` to make sure fork-unique keys + /// can be built using `frame_system::block_hash` map. + fn offchain_canonicalization_window() -> LeafIndex { + let window_size: LeafIndex = + ::BlockHashCount::get().unique_saturated_into(); + window_size.saturating_sub(1) + } + /// Provide the parent number for the block that added `leaf_index` to the MMR. fn leaf_index_to_parent_block_num( leaf_index: LeafIndex, diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index 8b623edf56957..870ce81226bd2 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -18,11 +18,10 @@ //! A MMR storage implementations. use codec::Encode; -use frame_support::traits::Get; +use frame_support::log::{debug, error, trace}; use mmr_lib::helper; use sp_core::offchain::StorageKind; use sp_io::{offchain, offchain_index}; -use sp_runtime::traits::UniqueSaturatedInto; use sp_std::iter::Peekable; #[cfg(not(feature = "std"))] use sp_std::prelude::*; @@ -133,15 +132,14 @@ where // Effectively move a rolling window of fork-unique leaves. Once out of the window, leaves // are "canonicalized" in offchain by moving them under `Pallet::node_canon_offchain_key`. let leaves = NumberOfLeaves::::get(); - let window_size = - ::BlockHashCount::get().unique_saturated_into(); + let window_size = Pallet::::offchain_canonicalization_window(); if leaves >= window_size { // Move the rolling window towards the end of `block_num->hash` mappings available // in the runtime: we "canonicalize" the leaf at the end, let to_canon_leaf = leaves.saturating_sub(window_size); // and all the nodes added by that leaf. let to_canon_nodes = NodesUtils::right_branch_ending_in_leaf(to_canon_leaf); - frame_support::log::debug!( + debug!( target: "runtime::mmr::offchain", "Nodes to canon for leaf {}: {:?}", to_canon_leaf, to_canon_nodes ); @@ -149,7 +147,7 @@ where let to_canon_block_num = Pallet::::leaf_index_to_parent_block_num(to_canon_leaf, leaves); // Only entries under this hash (retrieved from state on current canon fork) are to be - // persisted. All other entries added by same block number will be cleared. + // persisted. All entries added by same block number on other forks will be cleared. let to_canon_hash = >::block_hash(to_canon_block_num); Self::canonicalize_nodes_for_hash(&to_canon_nodes, to_canon_hash); @@ -159,7 +157,7 @@ where Self::prune_nodes_for_forks(&to_canon_nodes, forks); }) .unwrap_or_else(|| { - frame_support::log::error!( + error!( target: "runtime::mmr::offchain", "Offchain: could not prune: no entry in pruning map for block {:?}", to_canon_block_num @@ -171,8 +169,8 @@ where fn prune_nodes_for_forks(nodes: &[NodeIndex], forks: Vec<::Hash>) { for hash in forks { for pos in nodes { - let key = Pallet::::node_offchain_key(hash, *pos); - frame_support::log::debug!( + let key = Pallet::::node_offchain_key(*pos, hash); + debug!( target: "runtime::mmr::offchain", "Clear elem at pos {} with key {:?}", pos, key @@ -187,19 +185,19 @@ where to_canon_hash: ::Hash, ) { for pos in to_canon_nodes { - let key = Pallet::::node_offchain_key(to_canon_hash, *pos); + let key = Pallet::::node_offchain_key(*pos, to_canon_hash); // Retrieve the element from Off-chain DB under fork-aware key. if let Some(elem) = offchain::local_storage_get(StorageKind::PERSISTENT, &key) { let canon_key = Pallet::::node_canon_offchain_key(*pos); // Add under new canon key. offchain::local_storage_set(StorageKind::PERSISTENT, &canon_key, &elem); - frame_support::log::debug!( + debug!( target: "runtime::mmr::offchain", "Moved elem at pos {} from key {:?} to canon key {:?}", pos, key, canon_key ); } else { - frame_support::log::error!( + error!( target: "runtime::mmr::offchain", "Could not canonicalize elem at pos {} using key {:?}", pos, key @@ -220,21 +218,18 @@ where // Find out which leaf added node `pos` in the MMR. let ancestor_leaf_idx = NodesUtils::leaf_index_that_added_node(pos); - let window_size = - ::BlockHashCount::get().unique_saturated_into(); + let window_size = Pallet::::offchain_canonicalization_window(); // Leaves older than this window should have been canonicalized. if leaves.saturating_sub(ancestor_leaf_idx) > window_size { let key = Pallet::::node_canon_offchain_key(pos); - frame_support::log::debug!( + debug!( target: "runtime::mmr::offchain", "offchain db get {}: leaf idx {:?}, key {:?}", pos, ancestor_leaf_idx, key ); // Just for safety, to easily handle runtime upgrades where any of the window params // change and maybe we mess up storage migration, // return _if and only if_ node is found (in normal conditions it's always found), - if let Some(elem) = - sp_io::offchain::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) - { + if let Some(elem) = sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) { return Ok(codec::Decode::decode(&mut &*elem).ok()) } // BUT if we DID MESS UP, fall through to searching node using fork-specific key. @@ -244,20 +239,20 @@ where let ancestor_parent_block_num = Pallet::::leaf_index_to_parent_block_num(ancestor_leaf_idx, leaves); let ancestor_parent_hash = >::block_hash(ancestor_parent_block_num); - let key = Pallet::::node_offchain_key(ancestor_parent_hash, pos); - frame_support::log::debug!( + let key = Pallet::::node_offchain_key(pos, ancestor_parent_hash); + debug!( target: "runtime::mmr::offchain", "offchain db get {}: leaf idx {:?}, hash {:?}, key {:?}", pos, ancestor_leaf_idx, ancestor_parent_hash, key ); // Retrieve the element from Off-chain DB. - Ok(sp_io::offchain::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) + Ok(sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) .or_else(|| { // Again, this is just us being extra paranoid. // We get here only if we mess up a storage migration for a runtime upgrades where // say the window is increased, and for a little while following the upgrade there's // leaves inside new 'window' that had been already canonicalized before upgrade. let key = Pallet::::node_canon_offchain_key(pos); - sp_io::offchain::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) + sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) }) .and_then(|v| codec::Decode::decode(&mut &*v).ok())) } @@ -282,9 +277,8 @@ where return Ok(()) } - frame_support::log::trace!( - target: "runtime::mmr", - "elems: {:?}", + trace!( + target: "runtime::mmr", "elems: {:?}", elems.iter().map(|elem| elem.hash()).collect::>() ); @@ -309,25 +303,12 @@ where // in offchain DB to avoid DB collisions and overwrites in case of forks. let parent_hash = >::parent_hash(); for elem in elems { - // For now we store this leaf offchain keyed by `(parent_hash, node_index)` - // to make it fork-resistant. - // Offchain worker task will "canonicalize" it `frame_system::BlockHashCount` blocks - // later when we are not worried about forks anymore (highly unlikely to have a fork - // in the chain that deep). - // "Canonicalization" in this case means moving this leaf under a new key based - // only on the leaf's `node_index`. - let key = Pallet::::node_offchain_key(parent_hash, node_index); - frame_support::log::debug!( - target: "runtime::mmr::offchain", "offchain db set: pos {} parent_hash {:?} key {:?}", - node_index, parent_hash, key - ); - // Indexing API is used to store the full node content (both leaf and inner). - elem.using_encoded(|elem| offchain_index::set(&key, elem)); - // On-chain we are going to only store new peaks. if peaks_to_store.next_if_eq(&node_index).is_some() { >::insert(node_index, elem.hash()); } + // We are storing full node off-chain (using indexing API). + Self::store_to_offchain(node_index, parent_hash, &elem); // Increase the indices. if let Node::Data(..) = elem { @@ -348,6 +329,38 @@ where } } +impl Storage +where + T: Config, + I: 'static, + L: primitives::FullLeaf, +{ + fn store_to_offchain( + pos: NodeIndex, + parent_hash: ::Hash, + node: &NodeOf, + ) { + let encoded_node = node.encode(); + // We store this leaf offchain keyed by `(parent_hash, node_index)` to make it + // fork-resistant. Offchain worker task will "canonicalize" it + // `frame_system::BlockHashCount` blocks later, when we are not worried about forks anymore + // (multi-era-deep forks should not happen). + let key = Pallet::::node_offchain_key(pos, parent_hash); + debug!( + target: "runtime::mmr::offchain", "offchain db set: pos {} parent_hash {:?} key {:?}", + pos, parent_hash, key + ); + // Indexing API is used to store the full node content. + offchain_index::set(&key, &encoded_node); + // We also directly save the full node under the "canonical" key. + // This is superfluous for the normal case - this entry will possibly be overwritten + // by forks, and will also be overwritten by "offchain_worker canonicalization". + // But it is required for blocks imported during initial sync where none of the above apply + // (`offchain_worker` doesn't run for initial sync blocks). + offchain_index::set(&Pallet::::node_canon_offchain_key(pos), &encoded_node); + } +} + fn peaks_to_prune_and_store( old_size: NodeIndex, new_size: NodeIndex, @@ -356,8 +369,8 @@ fn peaks_to_prune_and_store( // both collections may share a common prefix. let peaks_before = if old_size == 0 { vec![] } else { helper::get_peaks(old_size) }; let peaks_after = helper::get_peaks(new_size); - frame_support::log::trace!(target: "runtime::mmr", "peaks_before: {:?}", peaks_before); - frame_support::log::trace!(target: "runtime::mmr", "peaks_after: {:?}", peaks_after); + trace!(target: "runtime::mmr", "peaks_before: {:?}", peaks_before); + trace!(target: "runtime::mmr", "peaks_after: {:?}", peaks_after); let mut peaks_before = peaks_before.into_iter().peekable(); let mut peaks_after = peaks_after.into_iter().peekable(); diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index a63a433029295..dbbdc12c8e1d5 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -169,25 +169,22 @@ fn should_append_to_mmr_when_on_initialize_is_called() { ext.persist_offchain_overlay(); let offchain_db = ext.offchain_db(); - assert_eq!( - offchain_db.get(&MMR::node_offchain_key(parent_b1, 0)).map(decode_node), - Some(mmr::Node::Data(((0, H256::repeat_byte(1)), LeafData::new(1),))) - ); - assert_eq!( - offchain_db.get(&MMR::node_offchain_key(parent_b2, 1)).map(decode_node), - Some(mmr::Node::Data(((1, H256::repeat_byte(2)), LeafData::new(2),))) - ); - assert_eq!( - offchain_db.get(&MMR::node_offchain_key(parent_b2, 2)).map(decode_node), - Some(mmr::Node::Hash(hex( - "672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854" - ))) - ); - assert_eq!(offchain_db.get(&MMR::node_offchain_key(parent_b2, 3)), None); - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(0)), None); - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(1)), None); - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(2)), None); + let expected = Some(mmr::Node::Data(((0, H256::repeat_byte(1)), LeafData::new(1)))); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(0, parent_b1)).map(decode_node), expected); + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(0)).map(decode_node), expected); + + let expected = Some(mmr::Node::Data(((1, H256::repeat_byte(2)), LeafData::new(2)))); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(1, parent_b2)).map(decode_node), expected); + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(1)).map(decode_node), expected); + + let expected = Some(mmr::Node::Hash(hex( + "672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854", + ))); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(2, parent_b2)).map(decode_node), expected); + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(2)).map(decode_node), expected); + + assert_eq!(offchain_db.get(&MMR::node_offchain_key(3, parent_b2)), None); assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(3)), None); } @@ -815,16 +812,20 @@ fn should_canonicalize_offchain() { let parent_num: BlockNumber = (block_num - 1).into(); let leaf_index = u64::from(block_num - 1); let pos = helper::leaf_index_to_pos(leaf_index.into()); - // not canon, - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(pos)), None); let parent_hash = >::block_hash(parent_num); - // but available in fork-proof storage. + // Available in offchain db under both fork-proof key and canon key. + // We'll later check it is pruned from fork-proof key. + let expected = Some(mmr::Node::Data(( + (leaf_index, H256::repeat_byte(u8::try_from(block_num).unwrap())), + LeafData::new(block_num.into()), + ))); assert_eq!( - offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)).map(decode_node), - Some(mmr::Node::Data(( - (leaf_index, H256::repeat_byte(u8::try_from(block_num).unwrap())), - LeafData::new(block_num.into()), - ))) + offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), + expected + ); + assert_eq!( + offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)).map(decode_node), + expected ); } @@ -835,12 +836,16 @@ fn should_canonicalize_offchain() { let verify = |pos: NodeIndex, leaf_index: LeafIndex, expected: H256| { let parent_num: BlockNumber = leaf_index.try_into().unwrap(); let parent_hash = >::block_hash(parent_num); - // not canon, - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(pos)), None); - // but available in fork-proof storage. + // Available in offchain db under both fork-proof key and canon key. + // We'll later check it is pruned from fork-proof key. + let expected = Some(mmr::Node::Hash(expected)); assert_eq!( - offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)).map(decode_node), - Some(mmr::Node::Hash(expected)) + offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), + expected + ); + assert_eq!( + offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)).map(decode_node), + expected ); }; verify(2, 1, hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854")); @@ -867,7 +872,7 @@ fn should_canonicalize_offchain() { let parent_num: BlockNumber = (block_num - 1).into(); let parent_hash = >::block_hash(parent_num); // no longer available in fork-proof storage (was pruned), - assert_eq!(offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)), None); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)), None); // but available using canon key. assert_eq!( offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), @@ -886,7 +891,7 @@ fn should_canonicalize_offchain() { let parent_num: BlockNumber = leaf_index.try_into().unwrap(); let parent_hash = >::block_hash(parent_num); // no longer available in fork-proof storage (was pruned), - assert_eq!(offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)), None); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)), None); // but available using canon key. assert_eq!( offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), From acacb53f92c3da09ccad403a679f0668cc2c6e0c Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 17 Oct 2022 12:45:42 +0200 Subject: [PATCH 1277/1472] Fix: typo (#12505) Fix: typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d7e6650290fba..02f8a7591acc5 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Then try out one of the [tutorials](https://docs.substrate.io/tutorials/). ## Community & Support Join the highly active and supportive community on the [Susbstrate Stack Exchange](https://substrate.stackexchange.com/) to ask questions about use and problems you run into using this software. -Please do report bugs and [isssues here](https://github.com/paritytech/substrate/issues) for anything you suspect requires action in the source. +Please do report bugs and [issues here](https://github.com/paritytech/substrate/issues) for anything you suspect requires action in the source. ## Contributions & Code of Conduct From 444cf9d87bba1071c3d1d82d21ac7419dd3953e4 Mon Sep 17 00:00:00 2001 From: Dmitrii Markin Date: Mon, 17 Oct 2022 14:02:37 +0300 Subject: [PATCH 1278/1472] Upgrade libp2p to 0.49.0 (#12256) * cargo upgrade libp2p * Get rid of `NetworkBehaviourEventProcess` in handling of `CustomMessageOutcome` * Get rid of `NetworkBehaviourEventProcess` in handling of `request_responses::Event` * Get rid of `NetworkBehaviourEventProcess` in handling of `peer_info::PeerInfoEvent` * Get rid of `NetworkBehaviourEventProcess` in handling of `DiscoveryOut` * Get rid of `poll()` method in `Bahaviour` * minor: comments * Upgrade libp2p to 0.49.0 (unreleased) * Support multiple Kad protocol names * Make borrow checker happy * minor: wording * Make substrate build with libp2p-0.49.0 * rustfmt * Get rid of MdnsWrapper * Resolve deprecation warnings * Fix documentation * Apply suggestions from code review: fix typos Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com> * Apply suggestion: simplify kad protocol name matching Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com> --- Cargo.lock | 651 +++++++----------------- client/authority-discovery/Cargo.toml | 2 +- client/authority-discovery/src/tests.rs | 5 +- client/cli/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/bitswap/Cargo.toml | 2 +- client/network/common/Cargo.toml | 2 +- client/network/light/Cargo.toml | 2 +- client/network/src/behaviour.rs | 352 +++++-------- client/network/src/config.rs | 7 +- client/network/src/discovery.rs | 151 +++--- client/network/src/peer_info.rs | 7 +- client/network/src/service.rs | 154 +++++- client/network/sync/Cargo.toml | 2 +- client/network/test/Cargo.toml | 2 +- client/network/transactions/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- 21 files changed, 526 insertions(+), 829 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f49ff75561db..103436dcfca4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,30 +29,30 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aead" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3e798aa0c8239776f54415bc06f3d74b1850f3f830b45c35cfc80556973f70" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" dependencies = [ "generic-array 0.14.4", ] [[package]] name = "aes" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495ee669413bfbe9e8cace80f4d3d78e6d8c8d99579f97fb93bde351b185f2d4" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures 0.1.5", + "cpufeatures", "opaque-debug 0.3.0", ] [[package]] name = "aes-gcm" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a930fd487faaa92a30afa92cc9dd1526a5cff67124abbbb1c617ce070f4dcf" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" dependencies = [ "aead", "aes", @@ -307,9 +307,9 @@ dependencies = [ [[package]] name = "async-std-resolver" -version = "0.21.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2f8a4a203be3325981310ab243a28e6e4ea55b6519bffce05d41ab60e09ad8" +checksum = "6ba50e24d9ee0a8950d3d03fc6d0dd10aa14b5de3b101949b4e160f7fee7c723" dependencies = [ "async-std", "async-trait", @@ -545,12 +545,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "bimap" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50ae17cabbc8a38a1e3e4c1a6a664e9a09672dc14d0896fa8d865d3a5a446b07" - [[package]] name = "bincode" version = "1.3.3" @@ -657,7 +651,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding 0.1.5", + "block-padding", "byte-tools", "byteorder", "generic-array 0.12.4", @@ -669,7 +663,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding 0.2.1", "generic-array 0.14.4", ] @@ -691,12 +684,6 @@ 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.0.2" @@ -893,21 +880,21 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chacha20" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b72a433d0cf2aef113ba70f62634c56fddb0f244e6377185c56a7cadbd8f91" +checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures 0.2.1", + "cpufeatures", "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b84ed6d1d5f7aa9bdde921a5090e0ca4d934d250ea3b402a5fab3a994e28a2a" +checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ "aead", "chacha20", @@ -1044,15 +1031,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "cmake" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b858541263efe664aead4a5209a4ae5c5d2811167d4ed4ee0944503f8d2089" -dependencies = [ - "cc", -] - [[package]] name = "comfy-table" version = "6.0.0" @@ -1120,15 +1098,6 @@ dependencies = [ "glob", ] -[[package]] -name = "cpufeatures" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" -dependencies = [ - "libc", -] - [[package]] name = "cpufeatures" version = "0.2.1" @@ -1482,17 +1451,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "cuckoofilter" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b810a8449931679f64cd7eef1bbd0fa315801b6d5d9cdc1ace2804d6529eee18" -dependencies = [ - "byteorder", - "fnv", - "rand 0.7.3", -] - [[package]] name = "curve25519-dalek" version = "2.1.2" @@ -1863,9 +1821,9 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck", "proc-macro2", @@ -2692,9 +2650,9 @@ dependencies = [ [[package]] name = "ghash" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b442c439366184de619215247d24e908912b175e824a530253845ac4c251a5c1" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" dependencies = [ "opaque-debug 0.3.0", "polyval", @@ -2871,12 +2829,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex_fmt" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" - [[package]] name = "hmac" version = "0.8.1" @@ -3038,9 +2990,9 @@ dependencies = [ [[package]] name = "if-watch" -version = "1.0.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8f4a3c3d4c89351ca83e120c1c00b27df945d38e05695668c9d4b4f7bc52f3" +checksum = "065c008e570a43c00de6aed9714035e5ea6a498c255323db9091722af6ee67dd" dependencies = [ "async-io", "core-foundation", @@ -3547,9 +3499,9 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libp2p" -version = "0.46.1" +version = "0.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81327106887e42d004fbdab1fef93675be2e2e07c1b95fce45e2cc813485611d" +checksum = "ec878fda12ebec479186b3914ebc48ff180fa4c51847e11a1a68bf65249e02c1" dependencies = [ "bytes", "futures", @@ -3557,12 +3509,8 @@ dependencies = [ "getrandom 0.2.3", "instant", "lazy_static", - "libp2p-autonat", "libp2p-core", - "libp2p-deflate", "libp2p-dns", - "libp2p-floodsub", - "libp2p-gossipsub", "libp2p-identify", "libp2p-kad", "libp2p-mdns", @@ -3570,49 +3518,24 @@ dependencies = [ "libp2p-mplex", "libp2p-noise", "libp2p-ping", - "libp2p-plaintext", - "libp2p-pnet", - "libp2p-relay", - "libp2p-rendezvous", "libp2p-request-response", "libp2p-swarm", "libp2p-swarm-derive", "libp2p-tcp", - "libp2p-uds", "libp2p-wasm-ext", "libp2p-websocket", "libp2p-yamux", "multiaddr", "parking_lot 0.12.1", "pin-project", - "rand 0.7.3", "smallvec", ] -[[package]] -name = "libp2p-autonat" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4decc51f3573653a9f4ecacb31b1b922dd20c25a6322bb15318ec04287ec46f9" -dependencies = [ - "async-trait", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-request-response", - "libp2p-swarm", - "log", - "prost 0.10.3", - "prost-build 0.10.4", - "rand 0.8.5", -] - [[package]] name = "libp2p-core" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf9b94cefab7599b2d3dff2f93bee218c6621d68590b23ede4485813cbcece6" +checksum = "799676bb0807c788065e57551c6527d461ad572162b0519d1958946ff9e0539d" dependencies = [ "asn1_der", "bs58", @@ -3623,17 +3546,15 @@ dependencies = [ "futures-timer", "instant", "lazy_static", - "libsecp256k1", "log", "multiaddr", "multihash", "multistream-select", "parking_lot 0.12.1", "pin-project", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "rand 0.8.5", - "ring", "rw-stream-sink", "sha2 0.10.2", "smallvec", @@ -3643,22 +3564,11 @@ dependencies = [ "zeroize", ] -[[package]] -name = "libp2p-deflate" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0183dc2a3da1fbbf85e5b6cf51217f55b14f5daea0c455a9536eef646bfec71" -dependencies = [ - "flate2", - "futures", - "libp2p-core", -] - [[package]] name = "libp2p-dns" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbf54723250fa5d521383be789bf60efdabe6bacfb443f87da261019a49b4b5" +checksum = "2322c9fb40d99101def6a01612ee30500c89abbbecb6297b3cd252903a4c1720" dependencies = [ "async-std-resolver", "futures", @@ -3669,57 +3579,11 @@ dependencies = [ "trust-dns-resolver", ] -[[package]] -name = "libp2p-floodsub" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a4b6ffd53e355775d24b76f583fdda54b3284806f678499b57913adb94f231" -dependencies = [ - "cuckoofilter", - "fnv", - "futures", - "libp2p-core", - "libp2p-swarm", - "log", - "prost 0.10.3", - "prost-build 0.10.4", - "rand 0.7.3", - "smallvec", -] - -[[package]] -name = "libp2p-gossipsub" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b4b888cfbeb1f5551acd3aa1366e01bf88ede26cc3c4645d0d2d004d5ca7b0" -dependencies = [ - "asynchronous-codec", - "base64", - "byteorder", - "bytes", - "fnv", - "futures", - "hex_fmt", - "instant", - "libp2p-core", - "libp2p-swarm", - "log", - "prometheus-client", - "prost 0.10.3", - "prost-build 0.10.4", - "rand 0.7.3", - "regex", - "sha2 0.10.2", - "smallvec", - "unsigned-varint", - "wasm-timer", -] - [[package]] name = "libp2p-identify" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50b585518f8efd06f93ac2f976bd672e17cdac794644b3117edd078e96bda06" +checksum = "dcf9a121f699e8719bda2e6e9e9b6ddafc6cff4602471d6481c1067930ccb29b" dependencies = [ "asynchronous-codec", "futures", @@ -3727,9 +3591,9 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "lru", - "prost 0.10.3", - "prost-build 0.10.4", + "lru 0.8.1", + "prost", + "prost-build", "prost-codec", "smallvec", "thiserror", @@ -3738,9 +3602,9 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.38.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740862893bb5f06ac24acc9d49bdeadc3a5e52e51818a30a25c1f3519da2c851" +checksum = "6721c200e2021f6c3fab8b6cf0272ead8912d871610ee194ebd628cecf428f22" dependencies = [ "arrayvec 0.7.2", "asynchronous-codec", @@ -3753,9 +3617,9 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost 0.10.3", - "prost-build 0.10.4", - "rand 0.7.3", + "prost", + "prost-build", + "rand 0.8.5", "sha2 0.10.2", "smallvec", "thiserror", @@ -3766,16 +3630,15 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.38.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e5e5919509603281033fd16306c61df7a4428ce274b67af5e14b07de5cdcb2" +checksum = "761704e727f7d68d58d7bc2231eafae5fc1b9814de24290f126df09d4bd37a15" dependencies = [ "async-io", "data-encoding", "dns-parser", "futures", "if-watch", - "lazy_static", "libp2p-core", "libp2p-swarm", "log", @@ -3787,25 +3650,23 @@ dependencies = [ [[package]] name = "libp2p-metrics" -version = "0.7.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8aff4a1abef42328fbb30b17c853fff9be986dc39af17ee39f9c5f755c5e0c" +checksum = "9ee31b08e78b7b8bfd1c4204a9dd8a87b4fcdf6dafc57eb51701c1c264a81cb9" dependencies = [ "libp2p-core", - "libp2p-gossipsub", "libp2p-identify", "libp2p-kad", "libp2p-ping", - "libp2p-relay", "libp2p-swarm", "prometheus-client", ] [[package]] name = "libp2p-mplex" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61fd1b20638ec209c5075dfb2e8ce6a7ea4ec3cd3ad7b77f7a477c06d53322e2" +checksum = "692664acfd98652de739a8acbb0a0d670f1d67190a49be6b4395e22c37337d89" dependencies = [ "asynchronous-codec", "bytes", @@ -3814,16 +3675,16 @@ dependencies = [ "log", "nohash-hasher", "parking_lot 0.12.1", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "unsigned-varint", ] [[package]] name = "libp2p-noise" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "762408cb5d84b49a600422d7f9a42c18012d8da6ebcd570f9a4a4290ba41fb6f" +checksum = "048155686bd81fe6cb5efdef0c6290f25ad32a0a42e8f4f72625cf6a505a206f" dependencies = [ "bytes", "curve25519-dalek 3.0.2", @@ -3831,8 +3692,8 @@ dependencies = [ "lazy_static", "libp2p-core", "log", - "prost 0.10.3", - "prost-build 0.10.4", + "prost", + "prost-build", "rand 0.8.5", "sha2 0.10.2", "snow", @@ -3843,105 +3704,25 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100a6934ae1dbf8a693a4e7dd1d730fd60b774dafc45688ed63b554497c6c925" -dependencies = [ - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-swarm", - "log", - "rand 0.7.3", - "void", -] - -[[package]] -name = "libp2p-plaintext" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be27bf0820a6238a4e06365b096d428271cce85a129cf16f2fe9eb1610c4df86" -dependencies = [ - "asynchronous-codec", - "bytes", - "futures", - "libp2p-core", - "log", - "prost 0.10.3", - "prost-build 0.10.4", - "unsigned-varint", - "void", -] - -[[package]] -name = "libp2p-pnet" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" -dependencies = [ - "futures", - "log", - "pin-project", - "rand 0.7.3", - "salsa20", - "sha3 0.9.1", -] - -[[package]] -name = "libp2p-relay" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4931547ee0cce03971ccc1733ff05bb0c4349fd89120a39e9861e2bbe18843c3" -dependencies = [ - "asynchronous-codec", - "bytes", - "either", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-swarm", - "log", - "pin-project", - "prost 0.10.3", - "prost-build 0.10.4", - "prost-codec", - "rand 0.8.5", - "smallvec", - "static_assertions", - "thiserror", - "void", -] - -[[package]] -name = "libp2p-rendezvous" -version = "0.7.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9511c9672ba33284838e349623319c8cad2d18cfad243ae46c6b7e8a2982ea4e" +checksum = "7228b9318d34689521349a86eb39a3c3a802c9efc99a0568062ffb80913e3f91" dependencies = [ - "asynchronous-codec", - "bimap", "futures", "futures-timer", "instant", "libp2p-core", "libp2p-swarm", "log", - "prost 0.10.3", - "prost-build 0.10.4", "rand 0.8.5", - "sha2 0.10.2", - "thiserror", - "unsigned-varint", "void", ] [[package]] name = "libp2p-request-response" -version = "0.19.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "508a189e2795d892c8f5c1fa1e9e0b1845d32d7b0b249dbf7b05b18811361843" +checksum = "8827af16a017b65311a410bb626205a9ad92ec0473967618425039fa5231adc1" dependencies = [ "async-trait", "bytes", @@ -3950,16 +3731,16 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "unsigned-varint", ] [[package]] name = "libp2p-swarm" -version = "0.37.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ac5be6c2de2d1ff3f7693fda6faf8a827b1f3e808202277783fea9f527d114" +checksum = "46d13df7c37807965d82930c0e4b04a659efcb6cca237373b206043db5398ecf" dependencies = [ "either", "fnv", @@ -3969,7 +3750,7 @@ dependencies = [ "libp2p-core", "log", "pin-project", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "thiserror", "void", @@ -3977,48 +3758,36 @@ dependencies = [ [[package]] name = "libp2p-swarm-derive" -version = "0.28.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f54a64b6957249e0ce782f8abf41d97f69330d02bf229f0672d864f0650cc76" +checksum = "a0eddc4497a8b5a506013c40e8189864f9c3a00db2b25671f428ae9007f3ba32" dependencies = [ + "heck", "quote", "syn", ] [[package]] name = "libp2p-tcp" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a6771dc19aa3c65d6af9a8c65222bfc8fcd446630ddca487acd161fa6096f3b" +checksum = "9839d96761491c6d3e238e70554b856956fca0ab60feb9de2cd08eed4473fa92" dependencies = [ "async-io", "futures", "futures-timer", "if-watch", - "ipnet", "libc", "libp2p-core", "log", "socket2", ] -[[package]] -name = "libp2p-uds" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d125e3e5f0d58f3c6ac21815b20cf4b6a88b8db9dc26368ea821838f4161fd4d" -dependencies = [ - "async-std", - "futures", - "libp2p-core", - "log", -] - [[package]] name = "libp2p-wasm-ext" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec894790eec3c1608f8d1a8a0bdf0dbeb79ed4de2dce964222011c2896dfa05a" +checksum = "a17b5b8e7a73e379e47b1b77f8a82c4721e97eca01abcd18e9cd91a23ca6ce97" dependencies = [ "futures", "js-sys", @@ -4030,9 +3799,9 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.36.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9808e57e81be76ff841c106b4c5974fb4d41a233a7bdd2afbf1687ac6def3818" +checksum = "3758ae6f89b2531a24b6d9f5776bda6a626b60a57600d7185d43dfa75ca5ecc4" dependencies = [ "either", "futures", @@ -4049,12 +3818,13 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.38.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6dea686217a06072033dc025631932810e2f6ad784e4fafa42e27d311c7a81c" +checksum = "30f079097a21ad017fc8139460630286f02488c8c13b26affb46623aa20d8845" dependencies = [ "futures", "libp2p-core", + "log", "parking_lot 0.12.1", "thiserror", "yamux", @@ -4233,6 +4003,15 @@ dependencies = [ "hashbrown 0.11.2", ] +[[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-cache" version = "0.1.2" @@ -4491,7 +4270,7 @@ dependencies = [ "digest 0.10.3", "multihash-derive", "sha2 0.10.2", - "sha3 0.10.0", + "sha3", "unsigned-varint", ] @@ -4517,9 +4296,9 @@ checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" [[package]] name = "multistream-select" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "363a84be6453a70e63513660f4894ef815daf88e3356bffcda9ca27d810ce83b" +checksum = "9bc41247ec209813e2fd414d6e16b9d94297dacf3cd613fa6ef09cd4d9755c10" dependencies = [ "bytes", "futures", @@ -4581,9 +4360,9 @@ dependencies = [ [[package]] name = "netlink-packet-route" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733ea73609acfd7fa7ddadfb7bf709b0471668c456ad9513685af543a06342b2" +checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" dependencies = [ "anyhow", "bitflags", @@ -4607,23 +4386,24 @@ dependencies = [ [[package]] name = "netlink-proto" -version = "0.9.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8785b8141e8432aa45fceb922a7e876d7da3fad37fa7e7ec702ace3aa0826b" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" dependencies = [ "bytes", "futures", "log", "netlink-packet-core", "netlink-sys", + "thiserror", "tokio", ] [[package]] name = "netlink-sys" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c9f9547a08241bee7b6558b9b98e1f290d187de8b7cfca2bbb4937bcaa8f8" +checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027" dependencies = [ "async-io", "bytes", @@ -4634,9 +4414,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.22.3" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ "bitflags", "cc", @@ -4647,15 +4427,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.23.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" dependencies = [ "bitflags", - "cc", "cfg-if 1.0.0", "libc", - "memoffset", ] [[package]] @@ -5197,15 +4975,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "owning_ref" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -dependencies = [ - "stable_deref_trait", -] - [[package]] name = "pallet-alliance" version = "4.0.0-dev" @@ -6962,23 +6731,23 @@ dependencies = [ [[package]] name = "poly1305" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fcffab1f78ebbdf4b93b68c1ffebc24037eedf271edaca795732b24e5e4e349" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ - "cpufeatures 0.1.5", + "cpufeatures", "opaque-debug 0.3.0", "universal-hash", ] [[package]] name = "polyval" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ba6a405ef63530d6cb12802014b22f9c5751bd17cdcddbe9e46d5c8ae83287" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ "cfg-if 1.0.0", - "cpufeatures 0.1.5", + "cpufeatures", "opaque-debug 0.3.0", "universal-hash", ] @@ -7109,37 +6878,27 @@ dependencies = [ [[package]] name = "prometheus-client" -version = "0.16.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1abe0255c04d15f571427a2d1e00099016506cf3297b53853acd2b7eb87825" +checksum = "3c473049631c233933d6286c88bbb7be30e62ec534cf99a9ae0079211f7fa603" dependencies = [ "dtoa", "itoa 1.0.1", - "owning_ref", + "parking_lot 0.12.1", "prometheus-client-derive-text-encode", ] [[package]] name = "prometheus-client-derive-text-encode" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8e12d01b9d66ad9eb4529c57666b6263fc1993cb30261d83ead658fdd932652" +checksum = "66a455fbcb954c1a7decf3c586e860fd7889cddf4b8e164be736dbac95a953cd" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "prost" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc03e116981ff7d8da8e5c220e374587b98d294af7ba7dd7fda761158f00086f" -dependencies = [ - "bytes", - "prost-derive 0.10.1", -] - [[package]] name = "prost" version = "0.11.0" @@ -7147,29 +6906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "399c3c31cdec40583bb68f0b18403400d01ec4289c383aa047560439952c4dd7" dependencies = [ "bytes", - "prost-derive 0.11.0", -] - -[[package]] -name = "prost-build" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae5a4388762d5815a9fc0dea33c56b021cdc8dde0c55e0c9ca57197254b0cab" -dependencies = [ - "bytes", - "cfg-if 1.0.0", - "cmake", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prost 0.10.3", - "prost-types 0.10.1", - "regex", - "tempfile", - "which", + "prost-derive", ] [[package]] @@ -7185,8 +6922,8 @@ dependencies = [ "log", "multimap", "petgraph", - "prost 0.11.0", - "prost-types 0.11.1", + "prost", + "prost-types", "regex", "tempfile", "which", @@ -7194,30 +6931,17 @@ dependencies = [ [[package]] name = "prost-codec" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00af1e92c33b4813cc79fda3f2dbf56af5169709be0202df730e9ebc3e4cd007" +checksum = "011ae9ff8359df7915f97302d591cdd9e0e27fbd5a4ddc5bd13b71079bb20987" dependencies = [ "asynchronous-codec", "bytes", - "prost 0.10.3", + "prost", "thiserror", "unsigned-varint", ] -[[package]] -name = "prost-derive" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "prost-derive" version = "0.11.0" @@ -7231,16 +6955,6 @@ dependencies = [ "syn", ] -[[package]] -name = "prost-types" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" -dependencies = [ - "bytes", - "prost 0.10.3", -] - [[package]] name = "prost-types" version = "0.11.1" @@ -7248,7 +6962,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dfaa718ad76a44b3415e6c4d53b17c8f99160dcb3a99b10470fce8ad43f6e3e" dependencies = [ "bytes", - "prost 0.11.0", + "prost", ] [[package]] @@ -7679,16 +7393,16 @@ dependencies = [ [[package]] name = "rtnetlink" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f54290e54521dac3de4149d83ddf9f62a359b3cc93bcb494a794a41e6f4744b" +checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" dependencies = [ "async-global-executor", "futures", "log", "netlink-packet-route", "netlink-proto", - "nix 0.22.3", + "nix 0.24.2", "thiserror", ] @@ -7818,15 +7532,6 @@ dependencies = [ "rustc_version 0.2.3", ] -[[package]] -name = "salsa20" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0fbb5f676da676c260ba276a8f43a8dc67cf02d1438423aeb1c677a7212686" -dependencies = [ - "cipher", -] - [[package]] name = "same-file" version = "1.0.6" @@ -7857,8 +7562,8 @@ dependencies = [ "libp2p", "log", "parity-scale-codec", - "prost 0.11.0", - "prost-build 0.11.1", + "prost", + "prost-build", "quickcheck", "rand 0.7.3", "sc-client-api", @@ -8296,7 +8001,7 @@ dependencies = [ "criterion", "env_logger", "lazy_static", - "lru", + "lru 0.7.5", "num_cpus", "parity-scale-codec", "parking_lot 0.12.1", @@ -8509,11 +8214,11 @@ dependencies = [ "linked-hash-map", "linked_hash_set", "log", - "lru", + "lru 0.7.5", "parity-scale-codec", "parking_lot 0.12.1", "pin-project", - "prost 0.11.0", + "prost", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8550,8 +8255,8 @@ dependencies = [ "futures", "libp2p", "log", - "prost 0.11.0", - "prost-build 0.11.1", + "prost", + "prost-build", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -8580,7 +8285,7 @@ dependencies = [ "libp2p", "linked_hash_set", "parity-scale-codec", - "prost-build 0.11.1", + "prost-build", "sc-consensus", "sc-peerset", "serde", @@ -8603,7 +8308,7 @@ dependencies = [ "futures-timer", "libp2p", "log", - "lru", + "lru 0.7.5", "quickcheck", "sc-network-common", "sc-peerset", @@ -8622,8 +8327,8 @@ dependencies = [ "libp2p", "log", "parity-scale-codec", - "prost 0.11.0", - "prost-build 0.11.1", + "prost", + "prost-build", "sc-client-api", "sc-network-common", "sc-peerset", @@ -8643,11 +8348,11 @@ dependencies = [ "futures", "libp2p", "log", - "lru", + "lru 0.7.5", "mockall", "parity-scale-codec", - "prost 0.11.0", - "prost-build 0.11.1", + "prost", + "prost-build", "quickcheck", "sc-block-builder", "sc-client-api", @@ -9435,7 +9140,7 @@ checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpufeatures 0.2.1", + "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -9447,22 +9152,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ "cfg-if 1.0.0", - "cpufeatures 0.2.1", + "cpufeatures", "digest 0.10.3", ] -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug 0.3.0", -] - [[package]] name = "sha3" version = "0.10.0" @@ -9738,7 +9431,7 @@ version = "4.0.0-dev" dependencies = [ "futures", "log", - "lru", + "lru 0.7.5", "parity-scale-codec", "parking_lot 0.12.1", "sp-api", @@ -9900,7 +9593,7 @@ dependencies = [ "byteorder", "digest 0.10.3", "sha2 0.10.2", - "sha3 0.10.0", + "sha3", "sp-std", "twox-hash", ] @@ -10379,7 +10072,7 @@ dependencies = [ "hash-db", "hashbrown 0.12.3", "lazy_static", - "lru", + "lru 0.7.5", "memory-db", "nohash-hasher", "parity-scale-codec", @@ -11289,9 +10982,9 @@ dependencies = [ [[package]] name = "trust-dns-proto" -version = "0.21.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" dependencies = [ "async-trait", "cfg-if 1.0.0", @@ -11303,30 +10996,30 @@ dependencies = [ "idna", "ipnet", "lazy_static", - "log", "rand 0.8.5", "smallvec", "thiserror", "tinyvec", + "tracing", "url", ] [[package]] name = "trust-dns-resolver" -version = "0.21.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" dependencies = [ "cfg-if 1.0.0", "futures-util", "ipconfig", "lazy_static", - "log", "lru-cache", "parking_lot 0.12.1", "resolv-conf", "smallvec", "thiserror", + "tracing", "trust-dns-proto", ] @@ -11468,9 +11161,9 @@ checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "universal-hash" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" dependencies = [ "generic-array 0.14.4", "subtle", @@ -12237,15 +11930,15 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.29.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac7fef12f4b59cd0a29339406cc9203ab44e440ddff6b3f5a41455349fa9cf3" +checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" dependencies = [ - "windows_aarch64_msvc 0.29.0", - "windows_i686_gnu 0.29.0", - "windows_i686_msvc 0.29.0", - "windows_x86_64_gnu 0.29.0", - "windows_x86_64_msvc 0.29.0", + "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]] @@ -12276,15 +11969,15 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" [[package]] name = "windows_aarch64_msvc" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" [[package]] name = "windows_aarch64_msvc" @@ -12294,15 +11987,15 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_i686_gnu" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" [[package]] name = "windows_i686_gnu" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" [[package]] name = "windows_i686_gnu" @@ -12312,15 +12005,15 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_msvc" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" [[package]] name = "windows_i686_msvc" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" [[package]] name = "windows_i686_msvc" @@ -12330,15 +12023,15 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_x86_64_gnu" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" [[package]] name = "windows_x86_64_gnu" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" [[package]] name = "windows_x86_64_gnu" @@ -12348,15 +12041,15 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_msvc" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" [[package]] name = "windows_x86_64_msvc" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" [[package]] name = "windows_x86_64_msvc" @@ -12384,9 +12077,9 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc614d95359fd7afc321b66d2107ede58b246b844cf5d8a0adcca413e439f088" +checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" dependencies = [ "curve25519-dalek 3.0.2", "rand_core 0.5.1", @@ -12395,9 +12088,9 @@ dependencies = [ [[package]] name = "yamux" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0608f53c1dc0bad505d03a34bbd49fbf2ad7b51eb036123e896365532745a1" +checksum = "e5d9ba232399af1783a58d8eb26f6b5006fbefe2dc9ef36bd283324792d03ea5" dependencies = [ "futures", "log", diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 37377cdc6dde3..91c977d90a660 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" -libp2p = { version = "0.46.1", default-features = false, features = ["kad"] } +libp2p = { version = "0.49.0", default-features = false, features = ["kad"] } log = "0.4.17" prost = "0.11" rand = "0.7.2" diff --git a/client/authority-discovery/src/tests.rs b/client/authority-discovery/src/tests.rs index 334b2638ca58c..208440b7ab1ea 100644 --- a/client/authority-discovery/src/tests.rs +++ b/client/authority-discovery/src/tests.rs @@ -91,10 +91,7 @@ fn cryptos_are_compatible() { let libp2p_public = libp2p_secret.public(); let sp_core_secret = { - let libp2p_ed_secret = match libp2p_secret.clone() { - libp2p::identity::Keypair::Ed25519(x) => x, - _ => panic!("generate_ed25519 should have generated an Ed25519 key ¯\\_(ツ)_/¯"), - }; + let libp2p::identity::Keypair::Ed25519(libp2p_ed_secret) = libp2p_secret.clone(); sp_core::ed25519::Pair::from_seed_slice(&libp2p_ed_secret.secret().as_ref()).unwrap() }; let sp_core_public = sp_core_secret.public(); diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 66742e14789ef..88568509c8709 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -18,7 +18,7 @@ chrono = "0.4.10" clap = { version = "3.1.18", features = ["derive"] } fdlimit = "0.2.1" futures = "0.3.21" -libp2p = "0.46.1" +libp2p = "0.49.0" log = "0.4.17" names = { version = "0.13.0", default-features = false } parity-scale-codec = "3.0.0" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 180ad7c38008d..d5745665a79fd 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.57" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" -libp2p = { version = "0.46.1", default-features = false } +libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" parking_lot = "0.12.1" serde = { version = "1.0", features = ["derive"] } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 8ecf2b9cec787..e84013fbfe436 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] ahash = "0.7.6" futures = "0.3.21" futures-timer = "3.0.1" -libp2p = { version = "0.46.1", default-features = false } +libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" lru = "0.7.5" tracing = "0.1.29" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 99e6c9e708e7f..9c2833ec00908 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -26,7 +26,7 @@ fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" ip_network = "0.4.1" -libp2p = "0.46.1" +libp2p = { version = "0.49.0", features = ["async-std", "dns", "identify", "kad", "mdns-async-io", "mplex", "noise", "ping", "tcp", "yamux"] } linked_hash_set = "0.1.3" linked-hash-map = "0.5.4" log = "0.4.17" diff --git a/client/network/bitswap/Cargo.toml b/client/network/bitswap/Cargo.toml index 9fa34aab17dfb..f60e21b4429fb 100644 --- a/client/network/bitswap/Cargo.toml +++ b/client/network/bitswap/Cargo.toml @@ -19,7 +19,7 @@ prost-build = "0.11" [dependencies] cid = "0.8.6" futures = "0.3.21" -libp2p = "0.46.1" +libp2p = "0.49.0" log = "0.4.17" prost = "0.11" thiserror = "1.0" diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 0e9801ec79e63..48d83a59c742b 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -25,7 +25,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ ] } futures = "0.3.21" futures-timer = "3.0.2" -libp2p = "0.46.1" +libp2p = { version = "0.49.0", features = [ "request-response", "kad" ] } linked_hash_set = "0.1.3" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } smallvec = "1.8.0" diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index a1a5dcf85eb5d..cd3be390d48c8 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -libp2p = "0.46.1" +libp2p = "0.49.0" log = "0.4.16" prost = "0.11" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index b31f36eb46692..fa130fb4baacd 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -24,18 +24,13 @@ use crate::{ }; use bytes::Bytes; -use codec::Encode; use futures::channel::oneshot; use libp2p::{ core::{Multiaddr, PeerId, PublicKey}, - identify::IdentifyInfo, + identify::Info as IdentifyInfo, kad::record, - swarm::{ - NetworkBehaviour, NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters, - }, NetworkBehaviour, }; -use log::debug; use sc_consensus::import_queue::{IncomingBlock, RuntimeOrigin}; use sc_network_common::{ @@ -46,26 +41,22 @@ use sc_network_common::{ ProtocolName, }, request_responses::{IfDisconnected, ProtocolConfig, RequestFailure}, + sync::{warp::WarpProofRequest, OpaqueBlockRequest, OpaqueStateRequest}, }; -use sc_peerset::PeersetHandle; +use sc_peerset::{PeersetHandle, ReputationChange}; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use sp_runtime::{ traits::{Block as BlockT, NumberFor}, Justifications, }; -use std::{ - collections::{HashSet, VecDeque}, - iter, - task::{Context, Poll}, - time::Duration, -}; +use std::{collections::HashSet, time::Duration}; pub use crate::request_responses::{InboundFailure, OutboundFailure, RequestId, ResponseFailure}; /// General behaviour of the network. Combines all protocols together. #[derive(NetworkBehaviour)] -#[behaviour(out_event = "BehaviourOut", poll_method = "poll", event_process = true)] +#[behaviour(out_event = "BehaviourOut")] pub struct Behaviour where B: BlockT, @@ -80,25 +71,6 @@ where discovery: DiscoveryBehaviour, /// Generic request-response protocols. request_responses: request_responses::RequestResponsesBehaviour, - - /// Queue of events to produce for the outside. - #[behaviour(ignore)] - events: VecDeque>, - - /// Protocol name used to send out block requests via - /// [`request_responses::RequestResponsesBehaviour`]. - #[behaviour(ignore)] - block_request_protocol_name: String, - - /// Protocol name used to send out state requests via - /// [`request_responses::RequestResponsesBehaviour`]. - #[behaviour(ignore)] - state_request_protocol_name: String, - - /// Protocol name used to send out warp sync requests via - /// [`request_responses::RequestResponsesBehaviour`]. - #[behaviour(ignore)] - warp_sync_protocol_name: Option, } /// Event generated by `Behaviour`. @@ -107,7 +79,7 @@ pub enum BehaviourOut { JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), /// Started a random iterative Kademlia discovery query. - RandomKademliaStarted(ProtocolId), + RandomKademliaStarted(Vec), /// We have received a request from a peer and answered it. /// @@ -136,6 +108,12 @@ pub enum BehaviourOut { result: Result<(), RequestFailure>, }, + /// A request protocol handler issued reputation changes for the given peer. + ReputationChanges { + peer: PeerId, + changes: Vec, + }, + /// Opened a substream with the given node with the given notifications protocol. /// /// The protocol is always one of the notification protocols that have been registered. @@ -186,15 +164,60 @@ pub enum BehaviourOut { messages: Vec<(ProtocolName, Bytes)>, }, + /// A new block request must be emitted. + BlockRequest { + /// Node we send the request to. + target: PeerId, + /// Opaque implementation-specific block request. + request: OpaqueBlockRequest, + /// One-shot channel to receive the response. + pending_response: oneshot::Sender, RequestFailure>>, + }, + + /// A new state request must be emitted. + StateRequest { + /// Node we send the request to. + target: PeerId, + /// Opaque implementation-specific state request. + request: OpaqueStateRequest, + /// One-shot channel to receive the response. + pending_response: oneshot::Sender, RequestFailure>>, + }, + + /// A new warp sync request must be emitted. + WarpSyncRequest { + /// Node we send the request to. + target: PeerId, + /// Warp sync request. + request: WarpProofRequest, + /// One-shot channel to receive the response. + pending_response: oneshot::Sender, RequestFailure>>, + }, + /// Now connected to a new peer for syncing purposes. SyncConnected(PeerId), /// No longer connected to a peer for syncing purposes. SyncDisconnected(PeerId), + /// We have obtained identity information from a peer, including the addresses it is listening + /// on. + PeerIdentify { + /// Id of the peer that has been identified. + peer_id: PeerId, + /// Information about the peer. + info: IdentifyInfo, + }, + + /// We have learned about the existence of a node on the default set. + Discovered(PeerId), + /// Events generated by a DHT as a response to get_value or put_value requests as well as the /// request duration. Dht(DhtEvent, Duration), + + /// Ignored event generated by lower layers. + None, } impl Behaviour @@ -216,17 +239,9 @@ where mut request_response_protocols: Vec, peerset: PeersetHandle, ) -> Result { - // Extract protocol name and add to `request_response_protocols`. - let block_request_protocol_name = block_request_protocol_config.name.to_string(); - let state_request_protocol_name = state_request_protocol_config.name.to_string(); - let warp_sync_protocol_name = match warp_sync_protocol_config { - Some(config) => { - let name = config.name.to_string(); - request_response_protocols.push(config); - Some(name) - }, - None => None, - }; + if let Some(config) = warp_sync_protocol_config { + request_response_protocols.push(config); + } request_response_protocols.push(block_request_protocol_config); request_response_protocols.push(state_request_protocol_config); request_response_protocols.push(light_client_request_protocol_config); @@ -239,10 +254,6 @@ where request_response_protocols.into_iter(), peerset, )?, - events: VecDeque::new(), - block_request_protocol_name, - state_request_protocol_name, - warp_sync_protocol_name, }) } @@ -310,6 +321,17 @@ where &mut self.substrate } + /// Add a self-reported address of a remote peer to the k-buckets of the supported + /// DHTs (`supported_protocols`). + pub fn add_self_reported_address_to_dht( + &mut self, + peer_id: &PeerId, + supported_protocols: &[impl AsRef<[u8]>], + addr: Multiaddr, + ) { + self.discovery.add_self_reported_address(peer_id, supported_protocols, addr); + } + /// Start querying a record from the DHT. Will later produce either a `ValueFound` or a /// `ValueNotFound` event. pub fn get_value(&mut self, key: record::Key) { @@ -333,221 +355,91 @@ fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole { } } -impl NetworkBehaviourEventProcess> for Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn inject_event(&mut self, event: CustomMessageOutcome) { +impl From> for BehaviourOut { + fn from(event: CustomMessageOutcome) -> Self { match event { CustomMessageOutcome::BlockImport(origin, blocks) => - self.events.push_back(BehaviourOut::BlockImport(origin, blocks)), - CustomMessageOutcome::JustificationImport(origin, hash, nb, justification) => self - .events - .push_back(BehaviourOut::JustificationImport(origin, hash, nb, justification)), - CustomMessageOutcome::BlockRequest { target, request, pending_response } => { - match self.substrate.encode_block_request(&request) { - Ok(data) => { - self.request_responses.send_request( - &target, - &self.block_request_protocol_name, - data, - pending_response, - IfDisconnected::ImmediateError, - ); - }, - Err(err) => { - log::warn!( - target: "sync", - "Failed to encode block request {:?}: {:?}", - request, err - ); - }, - } - }, - CustomMessageOutcome::StateRequest { target, request, pending_response } => { - match self.substrate.encode_state_request(&request) { - Ok(data) => { - self.request_responses.send_request( - &target, - &self.state_request_protocol_name, - data, - pending_response, - IfDisconnected::ImmediateError, - ); - }, - Err(err) => { - log::warn!( - target: "sync", - "Failed to encode state request {:?}: {:?}", - request, err - ); - }, - } - }, + BehaviourOut::BlockImport(origin, blocks), + CustomMessageOutcome::JustificationImport(origin, hash, nb, justification) => + BehaviourOut::JustificationImport(origin, hash, nb, justification), + CustomMessageOutcome::BlockRequest { target, request, pending_response } => + BehaviourOut::BlockRequest { target, request, pending_response }, + CustomMessageOutcome::StateRequest { target, request, pending_response } => + BehaviourOut::StateRequest { target, request, pending_response }, CustomMessageOutcome::WarpSyncRequest { target, request, pending_response } => - match &self.warp_sync_protocol_name { - Some(name) => self.request_responses.send_request( - &target, - name, - request.encode(), - pending_response, - IfDisconnected::ImmediateError, - ), - None => { - log::warn!( - target: "sync", - "Trying to send warp sync request when no protocol is configured {:?}", - request, - ); - }, - }, + BehaviourOut::WarpSyncRequest { target, request, pending_response }, CustomMessageOutcome::NotificationStreamOpened { remote, protocol, negotiated_fallback, roles, notifications_sink, - } => { - self.events.push_back(BehaviourOut::NotificationStreamOpened { - remote, - protocol, - negotiated_fallback, - role: reported_roles_to_observed_role(roles), - notifications_sink, - }); - }, - CustomMessageOutcome::NotificationStreamReplaced { + } => BehaviourOut::NotificationStreamOpened { remote, protocol, + negotiated_fallback, + role: reported_roles_to_observed_role(roles), notifications_sink, - } => self.events.push_back(BehaviourOut::NotificationStreamReplaced { + }, + CustomMessageOutcome::NotificationStreamReplaced { remote, protocol, notifications_sink, - }), - CustomMessageOutcome::NotificationStreamClosed { remote, protocol } => self - .events - .push_back(BehaviourOut::NotificationStreamClosed { remote, protocol }), - CustomMessageOutcome::NotificationsReceived { remote, messages } => { - self.events.push_back(BehaviourOut::NotificationsReceived { remote, messages }); - }, - CustomMessageOutcome::PeerNewBest(_peer_id, _number) => {}, - CustomMessageOutcome::SyncConnected(peer_id) => - self.events.push_back(BehaviourOut::SyncConnected(peer_id)), + } => BehaviourOut::NotificationStreamReplaced { remote, protocol, notifications_sink }, + CustomMessageOutcome::NotificationStreamClosed { remote, protocol } => + BehaviourOut::NotificationStreamClosed { remote, protocol }, + CustomMessageOutcome::NotificationsReceived { remote, messages } => + BehaviourOut::NotificationsReceived { remote, messages }, + CustomMessageOutcome::PeerNewBest(_peer_id, _number) => BehaviourOut::None, + CustomMessageOutcome::SyncConnected(peer_id) => BehaviourOut::SyncConnected(peer_id), CustomMessageOutcome::SyncDisconnected(peer_id) => - self.events.push_back(BehaviourOut::SyncDisconnected(peer_id)), - CustomMessageOutcome::None => {}, + BehaviourOut::SyncDisconnected(peer_id), + CustomMessageOutcome::None => BehaviourOut::None, } } } -impl NetworkBehaviourEventProcess for Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn inject_event(&mut self, event: request_responses::Event) { +impl From for BehaviourOut { + fn from(event: request_responses::Event) -> Self { match event { - request_responses::Event::InboundRequest { peer, protocol, result } => { - self.events.push_back(BehaviourOut::InboundRequest { peer, protocol, result }); - }, - request_responses::Event::RequestFinished { peer, protocol, duration, result } => { - self.events.push_back(BehaviourOut::RequestFinished { - peer, - protocol, - duration, - result, - }); - }, + request_responses::Event::InboundRequest { peer, protocol, result } => + BehaviourOut::InboundRequest { peer, protocol, result }, + request_responses::Event::RequestFinished { peer, protocol, duration, result } => + BehaviourOut::RequestFinished { peer, protocol, duration, result }, request_responses::Event::ReputationChanges { peer, changes } => - for change in changes { - self.substrate.report_peer(peer, change); - }, + BehaviourOut::ReputationChanges { peer, changes }, } } } -impl NetworkBehaviourEventProcess for Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn inject_event(&mut self, event: peer_info::PeerInfoEvent) { - let peer_info::PeerInfoEvent::Identified { - peer_id, - info: IdentifyInfo { protocol_version, agent_version, mut listen_addrs, protocols, .. }, - } = event; - - if listen_addrs.len() > 30 { - debug!( - target: "sub-libp2p", - "Node {:?} has reported more than 30 addresses; it is identified by {:?} and {:?}", - peer_id, protocol_version, agent_version - ); - listen_addrs.truncate(30); - } - - for addr in listen_addrs { - self.discovery.add_self_reported_address(&peer_id, protocols.iter(), addr); - } - self.substrate.add_default_set_discovered_nodes(iter::once(peer_id)); +impl From for BehaviourOut { + fn from(event: peer_info::PeerInfoEvent) -> Self { + let peer_info::PeerInfoEvent::Identified { peer_id, info } = event; + BehaviourOut::PeerIdentify { peer_id, info } } } -impl NetworkBehaviourEventProcess for Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn inject_event(&mut self, out: DiscoveryOut) { - match out { +impl From for BehaviourOut { + fn from(event: DiscoveryOut) -> Self { + match event { DiscoveryOut::UnroutablePeer(_peer_id) => { // Obtaining and reporting listen addresses for unroutable peers back // to Kademlia is handled by the `Identify` protocol, part of the - // `PeerInfoBehaviour`. See the `NetworkBehaviourEventProcess` - // implementation for `PeerInfoEvent`. - }, - DiscoveryOut::Discovered(peer_id) => { - self.substrate.add_default_set_discovered_nodes(iter::once(peer_id)); - }, - DiscoveryOut::ValueFound(results, duration) => { - self.events - .push_back(BehaviourOut::Dht(DhtEvent::ValueFound(results), duration)); - }, - DiscoveryOut::ValueNotFound(key, duration) => { - self.events.push_back(BehaviourOut::Dht(DhtEvent::ValueNotFound(key), duration)); - }, - DiscoveryOut::ValuePut(key, duration) => { - self.events.push_back(BehaviourOut::Dht(DhtEvent::ValuePut(key), duration)); - }, - DiscoveryOut::ValuePutFailed(key, duration) => { - self.events - .push_back(BehaviourOut::Dht(DhtEvent::ValuePutFailed(key), duration)); + // `PeerInfoBehaviour`. See the `From` + // implementation. + BehaviourOut::None }, + DiscoveryOut::Discovered(peer_id) => BehaviourOut::Discovered(peer_id), + DiscoveryOut::ValueFound(results, duration) => + BehaviourOut::Dht(DhtEvent::ValueFound(results), duration), + DiscoveryOut::ValueNotFound(key, duration) => + BehaviourOut::Dht(DhtEvent::ValueNotFound(key), duration), + DiscoveryOut::ValuePut(key, duration) => + BehaviourOut::Dht(DhtEvent::ValuePut(key), duration), + DiscoveryOut::ValuePutFailed(key, duration) => + BehaviourOut::Dht(DhtEvent::ValuePutFailed(key), duration), DiscoveryOut::RandomKademliaStarted(protocols) => - for protocol in protocols { - self.events.push_back(BehaviourOut::RandomKademliaStarted(protocol)); - }, - } - } -} - -impl Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn poll( - &mut self, - _cx: &mut Context, - _: &mut impl PollParameters, - ) -> Poll, ::ConnectionHandler>> - { - if let Some(event) = self.events.pop_front() { - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event)) + BehaviourOut::RandomKademliaStarted(protocols), } - - Poll::Pending } } diff --git a/client/network/src/config.rs b/client/network/src/config.rs index dcd7c7d8ad6de..14f7e8ffbf76a 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -455,11 +455,8 @@ mod tests { } fn secret_bytes(kp: &Keypair) -> Vec { - match kp { - Keypair::Ed25519(p) => p.secret().as_ref().iter().cloned().collect(), - Keypair::Secp256k1(p) => p.secret().to_bytes().to_vec(), - _ => panic!("Unexpected keypair."), - } + let Keypair::Ed25519(p) = kp; + p.secret().as_ref().iter().cloned().collect() } #[test] diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 8422e34485125..da4dec70b29ab 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -198,7 +198,7 @@ impl DiscoveryConfig { let proto_name = protocol_name_from_protocol_id(&protocol_id); let mut config = KademliaConfig::default(); - config.set_protocol_name(proto_name); + config.set_protocol_names(std::iter::once(proto_name.into()).collect()); // By default Kademlia attempts to insert all peers into its routing table once a // dialing attempt succeeds. In order to control which peer is added, disable the // auto-insertion and instead add peers manually. @@ -232,9 +232,15 @@ impl DiscoveryConfig { allow_private_ipv4, discovery_only_if_under_num, mdns: if enable_mdns { - MdnsWrapper::Instantiating(Mdns::new(MdnsConfig::default()).boxed()) + match Mdns::new(MdnsConfig::default()) { + Ok(mdns) => Some(mdns), + Err(err) => { + warn!(target: "sub-libp2p", "Failed to initialize mDNS: {:?}", err); + None + }, + } } else { - MdnsWrapper::Disabled + None }, allow_non_globals_in_dht, known_external_addresses: LruHashSet::new( @@ -256,7 +262,7 @@ pub struct DiscoveryBehaviour { /// Kademlia requests and answers. kademlias: HashMap>, /// Discovers nodes on the local network. - mdns: MdnsWrapper, + mdns: Option, /// Stream that fires when we need to perform the next random Kademlia query. `None` if /// random walking is disabled. next_kad_random_query: Option, @@ -320,7 +326,7 @@ impl DiscoveryBehaviour { pub fn add_self_reported_address( &mut self, peer_id: &PeerId, - supported_protocols: impl Iterator>, + supported_protocols: &[impl AsRef<[u8]>], addr: Multiaddr, ) { if !self.allow_non_globals_in_dht && !self.can_add_to_dht(&addr) { @@ -329,17 +335,18 @@ impl DiscoveryBehaviour { } let mut added = false; - for protocol in supported_protocols { - for kademlia in self.kademlias.values_mut() { - if protocol.as_ref() == kademlia.protocol_name() { - trace!( - target: "sub-libp2p", - "Adding self-reported address {} from {} to Kademlia DHT {}.", - addr, peer_id, String::from_utf8_lossy(kademlia.protocol_name()), - ); - kademlia.add_address(peer_id, addr.clone()); - added = true; - } + for kademlia in self.kademlias.values_mut() { + if let Some(matching_protocol) = supported_protocols + .iter() + .find(|p| kademlia.protocol_names().iter().any(|k| k.as_ref() == p.as_ref())) + { + trace!( + target: "sub-libp2p", + "Adding self-reported address {} from {} to Kademlia DHT {}.", + addr, peer_id, String::from_utf8_lossy(matching_protocol.as_ref()), + ); + kademlia.add_address(peer_id, addr.clone()); + added = true; } } @@ -532,7 +539,9 @@ impl NetworkBehaviour for DiscoveryBehaviour { list_to_filter.extend(k.addresses_of_peer(peer_id)) } - list_to_filter.extend(self.mdns.addresses_of_peer(peer_id)); + if let Some(ref mut mdns) = self.mdns { + list_to_filter.extend(mdns.addresses_of_peer(peer_id)); + } if !self.allow_private_ipv4 { list_to_filter.retain(|addr| match addr.iter().next() { @@ -913,36 +922,38 @@ impl NetworkBehaviour for DiscoveryBehaviour { } // Poll mDNS. - while let Poll::Ready(ev) = self.mdns.poll(cx, params) { - match ev { - NetworkBehaviourAction::GenerateEvent(event) => match event { - MdnsEvent::Discovered(list) => { - if self.num_connections >= self.discovery_only_if_under_num { - continue - } - - self.pending_events - .extend(list.map(|(peer_id, _)| DiscoveryOut::Discovered(peer_id))); - if let Some(ev) = self.pending_events.pop_front() { - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) - } + if let Some(ref mut mdns) = self.mdns { + while let Poll::Ready(ev) = mdns.poll(cx, params) { + match ev { + NetworkBehaviourAction::GenerateEvent(event) => match event { + MdnsEvent::Discovered(list) => { + if self.num_connections >= self.discovery_only_if_under_num { + continue + } + + self.pending_events + .extend(list.map(|(peer_id, _)| DiscoveryOut::Discovered(peer_id))); + if let Some(ev) = self.pending_events.pop_front() { + return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) + } + }, + MdnsEvent::Expired(_) => {}, + }, + NetworkBehaviourAction::Dial { .. } => { + unreachable!("mDNS never dials!"); }, - MdnsEvent::Expired(_) => {}, - }, - NetworkBehaviourAction::Dial { .. } => { - unreachable!("mDNS never dials!"); - }, - NetworkBehaviourAction::NotifyHandler { event, .. } => match event {}, /* `event` is an enum with no variant */ - NetworkBehaviourAction::ReportObservedAddr { address, score } => - return Poll::Ready(NetworkBehaviourAction::ReportObservedAddr { - address, - score, - }), - NetworkBehaviourAction::CloseConnection { peer_id, connection } => - return Poll::Ready(NetworkBehaviourAction::CloseConnection { - peer_id, - connection, - }), + NetworkBehaviourAction::NotifyHandler { event, .. } => match event {}, /* `event` is an enum with no variant */ + NetworkBehaviourAction::ReportObservedAddr { address, score } => + return Poll::Ready(NetworkBehaviourAction::ReportObservedAddr { + address, + score, + }), + NetworkBehaviourAction::CloseConnection { peer_id, connection } => + return Poll::Ready(NetworkBehaviourAction::CloseConnection { + peer_id, + connection, + }), + } } } @@ -959,45 +970,6 @@ fn protocol_name_from_protocol_id(id: &ProtocolId) -> Vec { v } -/// [`Mdns::new`] returns a future. Instead of forcing [`DiscoveryConfig::finish`] and all its -/// callers to be async, lazily instantiate [`Mdns`]. -enum MdnsWrapper { - Instantiating(futures::future::BoxFuture<'static, std::io::Result>), - Ready(Mdns), - Disabled, -} - -impl MdnsWrapper { - fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { - match self { - Self::Instantiating(_) => Vec::new(), - Self::Ready(mdns) => mdns.addresses_of_peer(peer_id), - Self::Disabled => Vec::new(), - } - } - - fn poll( - &mut self, - cx: &mut Context<'_>, - params: &mut impl PollParameters, - ) -> Poll::ConnectionHandler>> { - loop { - match self { - Self::Instantiating(fut) => - *self = match futures::ready!(fut.as_mut().poll(cx)) { - Ok(mdns) => Self::Ready(mdns), - Err(err) => { - warn!(target: "sub-libp2p", "Failed to initialize mDNS: {:?}", err); - Self::Disabled - }, - }, - Self::Ready(mdns) => return mdns.poll(cx, params), - Self::Disabled => return Poll::Pending, - } - } - } -} - #[cfg(test)] mod tests { use super::{protocol_name_from_protocol_id, DiscoveryConfig, DiscoveryOut}; @@ -1100,8 +1072,7 @@ mod tests { .behaviour_mut() .add_self_reported_address( &other, - [protocol_name_from_protocol_id(&protocol_id)] - .iter(), + &[protocol_name_from_protocol_id(&protocol_id)], addr, ); @@ -1156,7 +1127,7 @@ mod tests { // Add remote peer with unsupported protocol. discovery.add_self_reported_address( &remote_peer_id, - [protocol_name_from_protocol_id(&unsupported_protocol_id)].iter(), + &[protocol_name_from_protocol_id(&unsupported_protocol_id)], remote_addr.clone(), ); @@ -1173,7 +1144,7 @@ mod tests { // Add remote peer with supported protocol. discovery.add_self_reported_address( &remote_peer_id, - [protocol_name_from_protocol_id(&supported_protocol_id)].iter(), + &[protocol_name_from_protocol_id(&supported_protocol_id)], remote_addr.clone(), ); @@ -1212,7 +1183,7 @@ mod tests { // Add remote peer with `protocol_a` only. discovery.add_self_reported_address( &remote_peer_id, - [protocol_name_from_protocol_id(&protocol_a)].iter(), + &[protocol_name_from_protocol_id(&protocol_a)], remote_addr.clone(), ); diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index c62c2ea1c5d98..e04d006f50501 100644 --- a/client/network/src/peer_info.rs +++ b/client/network/src/peer_info.rs @@ -23,8 +23,11 @@ use libp2p::{ connection::ConnectionId, either::EitherOutput, transport::ListenerId, ConnectedPoint, PeerId, PublicKey, }, - identify::{Identify, IdentifyConfig, IdentifyEvent, IdentifyInfo}, - ping::{Ping, PingConfig, PingEvent, PingSuccess}, + identify::{ + Behaviour as Identify, Config as IdentifyConfig, Event as IdentifyEvent, + Info as IdentifyInfo, + }, + ping::{Behaviour as Ping, Config as PingConfig, Event as PingEvent, Success as PingSuccess}, swarm::{ ConnectionHandler, IntoConnectionHandler, IntoConnectionHandlerSelect, NetworkBehaviour, NetworkBehaviourAction, PollParameters, diff --git a/client/network/src/service.rs b/client/network/src/service.rs index d1f428cc292c3..f95e67df142b0 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -38,9 +38,11 @@ use crate::{ transport, ChainSyncInterface, ReputationChange, }; +use codec::Encode; use futures::{channel::oneshot, prelude::*}; use libp2p::{ core::{either::EitherError, upgrade, ConnectedPoint, Executor}, + identify::Info as IdentifyInfo, kad::record::Key as KademliaKey, multiaddr, ping::Failure as PingFailure, @@ -264,6 +266,11 @@ where let num_connected = Arc::new(AtomicUsize::new(0)); let is_major_syncing = Arc::new(AtomicBool::new(false)); + let block_request_protocol_name = params.block_request_protocol_config.name.clone(); + let state_request_protocol_name = params.state_request_protocol_config.name.clone(); + let warp_sync_protocol_name = + params.warp_sync_protocol_config.as_ref().map(|c| c.name.clone()); + // Build the swarm. let (mut swarm, bandwidth): (Swarm>, _) = { let user_agent = format!( @@ -455,6 +462,9 @@ where peers_notifications_sinks, metrics, boot_node_ids, + block_request_protocol_name, + state_request_protocol_name, + warp_sync_protocol_name, _marker: Default::default(), }) } @@ -1273,6 +1283,15 @@ where /// For each peer and protocol combination, an object that allows sending notifications to /// that peer. Shared with the [`NetworkService`]. peers_notifications_sinks: Arc>>, + /// Protocol name used to send out block requests via + /// [`crate::request_responses::RequestResponsesBehaviour`]. + block_request_protocol_name: ProtocolName, + /// Protocol name used to send out state requests via + /// [`crate::request_responses::RequestResponsesBehaviour`]. + state_request_protocol_name: ProtocolName, + /// Protocol name used to send out warp sync requests via + /// [`crate::request_responses::RequestResponsesBehaviour`]. + warp_sync_protocol_name: Option, /// Marker to pin the `H` generic. Serves no purpose except to not break backwards /// compatibility. _marker: PhantomData, @@ -1451,6 +1470,84 @@ where } this.import_queue.import_justifications(origin, hash, nb, justifications); }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::BlockRequest { + target, + request, + pending_response, + })) => { + match this + .network_service + .behaviour() + .user_protocol() + .encode_block_request(&request) + { + Ok(data) => { + this.network_service.behaviour_mut().send_request( + &target, + &this.block_request_protocol_name, + data, + pending_response, + IfDisconnected::ImmediateError, + ); + }, + Err(err) => { + log::warn!( + target: "sync", + "Failed to encode block request {:?}: {:?}", + request, err + ); + }, + } + }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::StateRequest { + target, + request, + pending_response, + })) => { + match this + .network_service + .behaviour() + .user_protocol() + .encode_state_request(&request) + { + Ok(data) => { + this.network_service.behaviour_mut().send_request( + &target, + &this.state_request_protocol_name, + data, + pending_response, + IfDisconnected::ImmediateError, + ); + }, + Err(err) => { + log::warn!( + target: "sync", + "Failed to encode state request {:?}: {:?}", + request, err + ); + }, + } + }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::WarpSyncRequest { + target, + request, + pending_response, + })) => match &this.warp_sync_protocol_name { + Some(name) => this.network_service.behaviour_mut().send_request( + &target, + &name, + request.encode(), + pending_response, + IfDisconnected::ImmediateError, + ), + None => { + log::warn!( + target: "sync", + "Trying to send warp sync request when no protocol is configured {:?}", + request, + ); + }, + }, Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::InboundRequest { protocol, result, @@ -1526,14 +1623,58 @@ where }, } }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::ReputationChanges { + peer, + changes, + })) => + for change in changes { + this.network_service.behaviour().user_protocol().report_peer(peer, change); + }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::PeerIdentify { + peer_id, + info: + IdentifyInfo { + protocol_version, + agent_version, + mut listen_addrs, + protocols, + .. + }, + })) => { + if listen_addrs.len() > 30 { + debug!( + target: "sub-libp2p", + "Node {:?} has reported more than 30 addresses; it is identified by {:?} and {:?}", + peer_id, protocol_version, agent_version + ); + listen_addrs.truncate(30); + } + for addr in listen_addrs { + this.network_service + .behaviour_mut() + .add_self_reported_address_to_dht(&peer_id, &protocols, addr); + } + this.network_service + .behaviour_mut() + .user_protocol_mut() + .add_default_set_discovered_nodes(iter::once(peer_id)); + }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::Discovered(peer_id))) => { + this.network_service + .behaviour_mut() + .user_protocol_mut() + .add_default_set_discovered_nodes(iter::once(peer_id)); + }, Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::RandomKademliaStarted( - protocol, + protocols, ))) => if let Some(metrics) = this.metrics.as_ref() { - metrics - .kademlia_random_queries_total - .with_label_values(&[protocol.as_ref()]) - .inc(); + for protocol in protocols { + metrics + .kademlia_random_queries_total + .with_label_values(&[protocol.as_ref()]) + .inc(); + } }, Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::NotificationStreamOpened { remote, @@ -1654,6 +1795,9 @@ where this.event_streams.send(Event::Dht(event)); }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::None)) => { + // Ignored event from lower layers. + }, Poll::Ready(SwarmEvent::ConnectionEstablished { peer_id, endpoint, diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 323b70e9c22a4..441b02fb22b8a 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -libp2p = "0.46.1" +libp2p = "0.49.0" log = "0.4.17" lru = "0.7.5" mockall = "0.11.2" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 990129229a40f..30a57bc1b5171 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -17,7 +17,7 @@ async-std = "1.11.0" async-trait = "0.1.57" futures = "0.3.21" futures-timer = "3.0.1" -libp2p = { version = "0.46.1", default-features = false } +libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" parking_lot = "0.12.1" rand = "0.7.2" diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml index 3b60497d42b9b..d92c07cd461a8 100644 --- a/client/network/transactions/Cargo.toml +++ b/client/network/transactions/Cargo.toml @@ -18,7 +18,7 @@ array-bytes = "4.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" hex = "0.4.0" -libp2p = "0.46.1" +libp2p = "0.49.0" log = "0.4.17" pin-project = "1.0.12" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 5ebb21406efbf..1e8c802496453 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -21,7 +21,7 @@ futures = "0.3.21" futures-timer = "3.0.2" hyper = { version = "0.14.16", features = ["stream", "http2"] } hyper-rustls = { version = "0.23.0", features = ["http2"] } -libp2p = { version = "0.46.1", default-features = false } +libp2p = { version = "0.49.0", default-features = false } num_cpus = "1.13" once_cell = "1.8" parking_lot = "0.12.1" diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index d3d6e267f1768..ade2bc3d78d03 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" -libp2p = { version = "0.46.1", default-features = false } +libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" serde_json = "1.0.85" wasm-timer = "0.2" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 0be1268e13d43..f8c6f281546db 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = "0.4.19" futures = "0.3.21" -libp2p = { version = "0.46.1", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } +libp2p = { version = "0.49.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.17" parking_lot = "0.12.1" pin-project = "1.0.12" From ed2466e376af406eb4e56906cdd843f791b1fd98 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Mon, 17 Oct 2022 18:44:42 +0200 Subject: [PATCH 1279/1472] Execute try-state at end of each test to ensure pallet data integrity (#12453) * execute try-state at end of tests * run post condition only with try runtime * Revert "run post condition only with try runtime" This reverts commit 7db0ecf7eaa2ee5afa5a995487b73d023ba3bcd9. * voterlist contains validators as well * fmt * simplify * fmt Co-authored-by: parity-processbot <> --- frame/staking/src/mock.rs | 108 ++---------------------------- frame/staking/src/pallet/impls.rs | 5 +- 2 files changed, 7 insertions(+), 106 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 3a9351ef4a271..24e5aa97160ee 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -18,9 +18,7 @@ //! Test utilities use crate::{self as pallet_staking, *}; -use frame_election_provider_support::{ - onchain, SequentialPhragmen, SortedListProvider, VoteWeight, -}; +use frame_election_provider_support::{onchain, SequentialPhragmen, VoteWeight}; use frame_support::{ assert_ok, parameter_types, traits::{ @@ -548,108 +546,10 @@ impl ExtBuilder { sp_tracing::try_init_simple(); let mut ext = self.build(); ext.execute_with(test); - ext.execute_with(post_conditions); - } -} - -fn post_conditions() { - check_nominators(); - check_exposures(); - check_ledgers(); - check_count(); -} - -fn check_count() { - let nominator_count = Nominators::::iter_keys().count() as u32; - let validator_count = Validators::::iter().count() as u32; - assert_eq!(nominator_count, Nominators::::count()); - assert_eq!(validator_count, Validators::::count()); - - // the voters that the `VoterList` list is storing for us. - let external_voters = ::VoterList::count(); - assert_eq!(external_voters, nominator_count + validator_count); -} - -fn check_ledgers() { - // check the ledger of all stakers. - Bonded::::iter().for_each(|(_, ctrl)| assert_ledger_consistent(ctrl)) -} - -fn check_exposures() { - // a check per validator to ensure the exposure struct is always sane. - let era = active_era(); - ErasStakers::::iter_prefix_values(era).for_each(|expo| { - assert_eq!( - expo.total as u128, - expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::(), - "wrong total exposure.", - ); - }) -} - -fn check_nominators() { - // a check per nominator to ensure their entire stake is correctly distributed. Will only kick- - // in if the nomination was submitted before the current era. - let era = active_era(); - >::iter() - .filter_map( - |(nominator, nomination)| { - if nomination.submitted_in > era { - Some(nominator) - } else { - None - } - }, - ) - .for_each(|nominator| { - // must be bonded. - assert_is_stash(nominator); - let mut sum = 0; - Session::validators() - .iter() - .map(|v| Staking::eras_stakers(era, v)) - .for_each(|e| { - let individual = - e.others.iter().filter(|e| e.who == nominator).collect::>(); - let len = individual.len(); - match len { - 0 => { /* not supporting this validator at all. */ }, - 1 => sum += individual[0].value, - _ => panic!("nominator cannot back a validator more than once."), - }; - }); - - let nominator_stake = Staking::slashable_balance_of(&nominator); - // a nominator cannot over-spend. - assert!( - nominator_stake >= sum, - "failed: Nominator({}) stake({}) >= sum divided({})", - nominator, - nominator_stake, - sum, - ); - - let diff = nominator_stake - sum; - assert!(diff < 100); + ext.execute_with(|| { + Staking::do_try_state(System::block_number()).unwrap(); }); -} - -fn assert_is_stash(acc: AccountId) { - assert!(Staking::bonded(&acc).is_some(), "Not a stash."); -} - -fn assert_ledger_consistent(ctrl: AccountId) { - // ensures ledger.total == ledger.active + sum(ledger.unlocking). - let ledger = Staking::ledger(ctrl).expect("Not a controller."); - let real_total: Balance = ledger.unlocking.iter().fold(ledger.active, |a, c| a + c.value); - assert_eq!(real_total, ledger.total); - assert!( - ledger.active >= Balances::minimum_balance() || ledger.active == 0, - "{}: active ledger amount ({}) must be greater than ED {}", - ctrl, - ledger.active, - Balances::minimum_balance() - ); + } } pub(crate) fn active_era() -> EraIndex { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 6da27da362b53..4ef064229693c 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1552,11 +1552,12 @@ impl StakingInterface for Pallet { } } -#[cfg(feature = "try-runtime")] +#[cfg(any(test, feature = "try-runtime"))] impl Pallet { pub(crate) fn do_try_state(_: BlockNumberFor) -> Result<(), &'static str> { ensure!( - T::VoterList::iter().all(|x| >::contains_key(&x)), + T::VoterList::iter() + .all(|x| >::contains_key(&x) || >::contains_key(&x)), "VoterList contains non-nominators" ); T::VoterList::try_state()?; From e8a4408c53ae2a1a0ef6cb2f7b603887a231c16f Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 18 Oct 2022 08:52:46 +0200 Subject: [PATCH 1280/1472] Bump clap to 4.0.x and adjust to best practices (#12381) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump clap to 3.2.22 * Replace `from_os_str` with `value_parser` * Replace `from_str` and `try_from_str` with `value_parser` * Move possible_values to the new format * Remove unwanted print * Add missing match branch * Update clap to 4.0.9 and make it compile * Replace deprecated `clap` macro with `command` and `value` * Move remaining `clap` attributes to `arg` * Remove no-op value_parsers * Adjust value_parser for state_version * Remove "deprecated" feature flag and bump to 4.0.11 * Improve range Co-authored-by: Bastian Köcher * Apply suggestions * Trigger CI * Fix unused error warning * Fix doc errors * Fix ArgGroup naming conflict * Change default_value to default_value_t * Use 1.. instead of 0.. Co-authored-by: Bastian Köcher --- Cargo.lock | 60 ++++----- bin/node-template/node/Cargo.toml | 2 +- bin/node-template/node/src/cli.rs | 6 +- bin/node/bench/Cargo.toml | 2 +- bin/node/bench/src/main.rs | 10 +- bin/node/cli/Cargo.toml | 6 +- bin/node/cli/build.rs | 2 +- bin/node/cli/src/cli.rs | 10 +- bin/node/inspect/Cargo.toml | 2 +- bin/node/inspect/src/cli.rs | 4 +- bin/utils/chain-spec-builder/Cargo.toml | 2 +- bin/utils/chain-spec-builder/src/main.rs | 22 ++-- bin/utils/subkey/Cargo.toml | 2 +- bin/utils/subkey/src/lib.rs | 2 +- client/cli/Cargo.toml | 2 +- client/cli/src/arg_enums.rs | 120 +++++++++--------- client/cli/src/commands/build_spec_cmd.rs | 4 +- client/cli/src/commands/check_block_cmd.rs | 4 +- client/cli/src/commands/export_blocks_cmd.rs | 8 +- client/cli/src/commands/export_state_cmd.rs | 2 +- client/cli/src/commands/generate.rs | 4 +- client/cli/src/commands/generate_node_key.rs | 6 +- client/cli/src/commands/import_blocks_cmd.rs | 6 +- client/cli/src/commands/insert_key.rs | 8 +- client/cli/src/commands/inspect_key.rs | 6 +- client/cli/src/commands/inspect_node_key.rs | 8 +- client/cli/src/commands/purge_chain_cmd.rs | 2 +- client/cli/src/commands/revert_cmd.rs | 2 +- client/cli/src/commands/run_cmd.rs | 80 ++++++------ client/cli/src/commands/sign.rs | 8 +- client/cli/src/commands/vanity.rs | 4 +- client/cli/src/commands/verify.rs | 6 +- client/cli/src/lib.rs | 18 +-- client/cli/src/params/database_params.rs | 10 +- client/cli/src/params/import_params.rs | 40 +++--- client/cli/src/params/keystore_params.rs | 17 ++- client/cli/src/params/mod.rs | 22 +++- client/cli/src/params/network_params.rs | 38 +++--- client/cli/src/params/node_key_params.rs | 8 +- .../cli/src/params/offchain_worker_params.rs | 8 +- client/cli/src/params/pruning_params.rs | 4 +- client/cli/src/params/shared_params.rs | 18 +-- .../cli/src/params/transaction_pool_params.rs | 6 +- .../solution-type/fuzzer/Cargo.toml | 2 +- primitives/npos-elections/fuzzer/Cargo.toml | 4 +- .../npos-elections/fuzzer/src/phragmen_pjr.rs | 8 +- primitives/storage/src/lib.rs | 11 ++ scripts/ci/node-template-release/Cargo.toml | 2 +- scripts/ci/node-template-release/src/main.rs | 4 +- utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../frame/benchmarking-cli/src/block/bench.rs | 6 +- utils/frame/benchmarking-cli/src/block/cmd.rs | 2 +- .../benchmarking-cli/src/extrinsic/bench.rs | 6 +- .../benchmarking-cli/src/extrinsic/cmd.rs | 8 +- .../frame/benchmarking-cli/src/machine/mod.rs | 12 +- .../benchmarking-cli/src/overhead/cmd.rs | 4 +- .../frame/benchmarking-cli/src/pallet/mod.rs | 62 ++++----- .../frame/benchmarking-cli/src/shared/mod.rs | 8 +- .../src/shared/weight_params.rs | 8 +- .../frame/benchmarking-cli/src/storage/cmd.rs | 22 ++-- utils/frame/frame-utilities-cli/Cargo.toml | 2 +- .../frame-utilities-cli/src/pallet_id.rs | 13 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- .../generate-bags/node-runtime/src/main.rs | 6 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- .../cli/src/commands/execute_block.rs | 18 ++- .../cli/src/commands/follow_chain.rs | 8 +- .../cli/src/commands/offchain_worker.rs | 14 +- .../cli/src/commands/on_runtime_upgrade.rs | 2 +- utils/frame/try-runtime/cli/src/lib.rs | 38 +++--- 70 files changed, 434 insertions(+), 443 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 103436dcfca4e..2c1b427f0a2e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -908,7 +908,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 3.1.18", + "clap 4.0.11", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -979,41 +979,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags", - "textwrap 0.11.0", + "textwrap", "unicode-width", ] [[package]] name = "clap" -version = "3.1.18" +version = "4.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" +checksum = "4ed45cc2c62a3eff523e718d8576ba762c83a3146151093283ac62ae11933a73" dependencies = [ "atty", "bitflags", "clap_derive", "clap_lex", - "indexmap", - "lazy_static", + "once_cell", "strsim", "termcolor", - "textwrap 0.15.0", ] [[package]] name = "clap_complete" -version = "3.0.2" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a394f7ec0715b42a4e52b294984c27c9a61f77c8d82f7774c5198350be143f19" +checksum = "11cba7abac9b56dfe2f035098cdb3a43946f276e6db83b72c4e692343f9aab9a" dependencies = [ - "clap 3.1.18", + "clap 4.0.11", ] [[package]] name = "clap_derive" -version = "3.1.18" +version = "4.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" +checksum = "db342ce9fda24fb191e2ed4e102055a4d381c1086a06630174cd8da8d5d917ce" dependencies = [ "heck", "proc-macro-error", @@ -1024,9 +1022,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" dependencies = [ "os_str_bytes", ] @@ -2127,7 +2125,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 3.1.18", + "clap 4.0.11", "comfy-table", "frame-benchmarking", "frame-support", @@ -2208,7 +2206,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 3.1.18", + "clap 4.0.11", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -4441,7 +4439,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 3.1.18", + "clap 4.0.11", "derive_more", "fs_extra", "futures", @@ -4480,7 +4478,7 @@ dependencies = [ "array-bytes", "assert_cmd", "async-std", - "clap 3.1.18", + "clap 4.0.11", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4597,7 +4595,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 3.1.18", + "clap 4.0.11", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4656,7 +4654,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 3.1.18", + "clap 4.0.11", "generate-bags", "kitchensink-runtime", ] @@ -4665,7 +4663,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 3.1.18", + "clap 4.0.11", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -6855,9 +6853,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" dependencies = [ "unicode-ident", ] @@ -7653,7 +7651,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 3.1.18", + "clap 4.0.11", "fdlimit", "futures", "libp2p", @@ -9762,7 +9760,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 3.1.18", + "clap 4.0.11", "honggfuzz", "parity-scale-codec", "rand 0.8.5", @@ -10259,7 +10257,7 @@ dependencies = [ name = "subkey" version = "2.0.2" dependencies = [ - "clap 3.1.18", + "clap 4.0.11", "sc-cli", ] @@ -10287,7 +10285,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 3.1.18", + "clap 4.0.11", "frame-support", "frame-system", "sc-cli", @@ -10617,12 +10615,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "textwrap" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" - [[package]] name = "thiserror" version = "1.0.30" @@ -11033,7 +11025,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ - "clap 3.1.18", + "clap 4.0.11", "frame-try-runtime", "jsonrpsee", "log", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index dc1d3caa8b75d..c60018e14969c 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] name = "node-template" [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } sp-core = { version = "6.0.0", path = "../../../primitives/core" } diff --git a/bin/node-template/node/src/cli.rs b/bin/node-template/node/src/cli.rs index 4ab4d34210c98..dd610477ac469 100644 --- a/bin/node-template/node/src/cli.rs +++ b/bin/node-template/node/src/cli.rs @@ -2,7 +2,7 @@ use sc_cli::RunCmd; #[derive(Debug, clap::Parser)] pub struct Cli { - #[clap(subcommand)] + #[command(subcommand)] pub subcommand: Option, #[clap(flatten)] @@ -12,7 +12,7 @@ pub struct Cli { #[derive(Debug, clap::Subcommand)] pub enum Subcommand { /// Key management cli utilities - #[clap(subcommand)] + #[command(subcommand)] Key(sc_cli::KeySubcommand), /// Build a chain specification. @@ -37,7 +37,7 @@ pub enum Subcommand { Revert(sc_cli::RevertCmd), /// Sub-commands concerned with benchmarking. - #[clap(subcommand)] + #[command(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), /// Try some command against runtime state. diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 42953da837100..54a1d4900c60b 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" [dependencies] array-bytes = "4.1" -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } log = "0.4.17" node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } diff --git a/bin/node/bench/src/main.rs b/bin/node/bench/src/main.rs index d97c7af26535b..8a5d99640eb1b 100644 --- a/bin/node/bench/src/main.rs +++ b/bin/node/bench/src/main.rs @@ -43,18 +43,18 @@ use crate::{ }; #[derive(Debug, Parser)] -#[clap(name = "node-bench", about = "Node integration benchmarks")] +#[command(name = "node-bench", about = "Node integration benchmarks")] struct Opt { /// Show list of all available benchmarks. /// /// Will output ("name", "path"). Benchmarks can then be filtered by path. - #[clap(short, long)] + #[arg(short, long)] list: bool, /// Machine readable json output. /// /// This also suppresses all regular output (except to stderr) - #[clap(short, long)] + #[arg(short, long)] json: bool, /// Filter benchmarks. @@ -63,7 +63,7 @@ struct Opt { filter: Option, /// Number of transactions for block import with `custom` size. - #[clap(long)] + #[arg(long)] transactions: Option, /// Mode @@ -72,7 +72,7 @@ struct Opt { /// /// "profile" mode adds pauses between measurable runs, /// so that actual interval can be selected in the profiler of choice. - #[clap(short, long, default_value = "regular")] + #[arg(short, long, default_value = "regular")] mode: BenchmarkMode, } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index edb434e3c04e3..25e7ef095ed3e 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -35,7 +35,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies array-bytes = "4.1" -clap = { version = "3.1.18", features = ["derive"], optional = true } +clap = { version = "4.0.9", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } jsonrpsee = { version = "0.15.1", features = ["server"] } @@ -136,8 +136,8 @@ remote-externalities = { path = "../../../utils/frame/remote-externalities" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } [build-dependencies] -clap = { version = "3.1.18", optional = true } -clap_complete = { version = "3.0", optional = true } +clap = { version = "4.0.9", optional = true } +clap_complete = { version = "4.0.2", optional = true } node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } frame-benchmarking-cli = { version = "4.0.0-dev", optional = true, path = "../../../utils/frame/benchmarking-cli" } substrate-build-script-utils = { version = "3.0.0", optional = true, path = "../../../utils/build-script-utils" } diff --git a/bin/node/cli/build.rs b/bin/node/cli/build.rs index 6a3d13dda6a00..e8142b297f1b2 100644 --- a/bin/node/cli/build.rs +++ b/bin/node/cli/build.rs @@ -25,7 +25,7 @@ fn main() { mod cli { include!("src/cli.rs"); - use clap::{ArgEnum, CommandFactory}; + use clap::{CommandFactory, ValueEnum}; use clap_complete::{generate_to, Shell}; use std::{env, fs, path::Path}; use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 5b2977599bab0..bb7f8a4c60aa9 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -20,7 +20,7 @@ #[derive(Debug, clap::Parser)] pub struct Cli { /// Possible subcommand with parameters. - #[clap(subcommand)] + #[command(subcommand)] pub subcommand: Option, #[allow(missing_docs)] @@ -34,7 +34,7 @@ pub struct Cli { /// /// The results are then printed out in the logs, and also sent as part of /// telemetry, if telemetry is enabled. - #[clap(long)] + #[arg(long)] pub no_hardware_benchmarks: bool, } @@ -42,7 +42,7 @@ pub struct Cli { #[derive(Debug, clap::Subcommand)] pub enum Subcommand { /// The custom inspect subcommmand for decoding blocks and extrinsics. - #[clap( + #[command( name = "inspect", about = "Decode given block or extrinsic using current native runtime." )] @@ -50,7 +50,7 @@ pub enum Subcommand { /// Sub-commands concerned with benchmarking. /// The pallet benchmarking moved to the `pallet` sub-command. - #[clap(subcommand)] + #[command(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), /// Try some command against runtime state. @@ -62,7 +62,7 @@ pub enum Subcommand { TryRuntime, /// Key management cli utilities - #[clap(subcommand)] + #[command(subcommand)] Key(sc_cli::KeySubcommand), /// Verify a signature for a message, provided on STDIN, with a given (public or secret) key. diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index ede96a76206ce..b7eccf9c36bd2 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } thiserror = "1.0" sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/bin/node/inspect/src/cli.rs b/bin/node/inspect/src/cli.rs index cc1f232e1fe0f..fa6344ac346e9 100644 --- a/bin/node/inspect/src/cli.rs +++ b/bin/node/inspect/src/cli.rs @@ -46,7 +46,7 @@ pub enum InspectSubCmd { /// Can be either a block hash (no 0x prefix) or a number to retrieve existing block, /// or a 0x-prefixed bytes hex string, representing SCALE encoding of /// a block. - #[clap(value_name = "HASH or NUMBER or BYTES")] + #[arg(value_name = "HASH or NUMBER or BYTES")] input: String, }, /// Decode extrinsic with native version of runtime and print out the details. @@ -56,7 +56,7 @@ pub enum InspectSubCmd { /// Can be either a block hash (no 0x prefix) or number and the index, in the form /// of `{block}:{index}` or a 0x-prefixed bytes hex string, /// representing SCALE encoding of an extrinsic. - #[clap(value_name = "BLOCK:INDEX or BYTES")] + #[arg(value_name = "BLOCK:INDEX or BYTES")] input: String, }, } diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index e3deb54ea8ac9..dc53dc08ec6af 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } rand = "0.8" node-cli = { version = "3.0.0-dev", path = "../../node/cli" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index 641416154115b..7dfcaed773f40 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -37,51 +37,51 @@ use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; /// A utility to easily create a testnet chain spec definition with a given set /// of authorities and endowed accounts and/or generate random accounts. #[derive(Parser)] -#[clap(rename_all = "kebab-case")] +#[command(rename_all = "kebab-case")] enum ChainSpecBuilder { /// Create a new chain spec with the given authorities, endowed and sudo /// accounts. New { /// Authority key seed. - #[clap(long, short, required = true)] + #[arg(long, short, required = true)] authority_seeds: Vec, /// Active nominators (SS58 format), each backing a random subset of the aforementioned /// authorities. - #[clap(long, short, default_value = "0")] + #[arg(long, short, default_value = "0")] nominator_accounts: Vec, /// Endowed account address (SS58 format). - #[clap(long, short)] + #[arg(long, short)] endowed_accounts: Vec, /// Sudo account address (SS58 format). - #[clap(long, short)] + #[arg(long, short)] sudo_account: String, /// The path where the chain spec should be saved. - #[clap(long, short, default_value = "./chain_spec.json")] + #[arg(long, short, default_value = "./chain_spec.json")] chain_spec_path: PathBuf, }, /// Create a new chain spec with the given number of authorities and endowed /// accounts. Random keys will be generated as required. Generate { /// The number of authorities. - #[clap(long, short)] + #[arg(long, short)] authorities: usize, /// The number of nominators backing the aforementioned authorities. /// /// Will nominate a random subset of `authorities`. - #[clap(long, short, default_value = "0")] + #[arg(long, short, default_value_t = 0)] nominators: usize, /// The number of endowed accounts. - #[clap(long, short, default_value = "0")] + #[arg(long, short, default_value_t = 0)] endowed: usize, /// The path where the chain spec should be saved. - #[clap(long, short, default_value = "./chain_spec.json")] + #[arg(long, short, default_value = "./chain_spec.json")] chain_spec_path: PathBuf, /// Path to use when saving generated keystores for each authority. /// /// At this path, a new folder will be created for each authority's /// keystore named `auth-$i` where `i` is the authority index, i.e. /// `auth-0`, `auth-1`, etc. - #[clap(long, short)] + #[arg(long, short)] keystore_path: Option, }, } diff --git a/bin/utils/subkey/Cargo.toml b/bin/utils/subkey/Cargo.toml index 4c4e47e702be6..77c323821a508 100644 --- a/bin/utils/subkey/Cargo.toml +++ b/bin/utils/subkey/Cargo.toml @@ -17,5 +17,5 @@ path = "src/main.rs" name = "subkey" [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/bin/utils/subkey/src/lib.rs b/bin/utils/subkey/src/lib.rs index 6773ba822340f..280b90848fbf5 100644 --- a/bin/utils/subkey/src/lib.rs +++ b/bin/utils/subkey/src/lib.rs @@ -23,7 +23,7 @@ use sc_cli::{ }; #[derive(Debug, Parser)] -#[clap( +#[command( name = "subkey", author = "Parity Team ", about = "Utility for generating and restoring with Substrate keys", diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 88568509c8709..04824859ce8ab 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "4.1" chrono = "0.4.10" -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive", "string"] } fdlimit = "0.2.1" futures = "0.3.21" libp2p = "0.49.0" diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index 283fef985dfb9..d761c854a6f0d 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -16,13 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Definitions of [`ArgEnum`] types. +//! Definitions of [`ValueEnum`] types. -use clap::ArgEnum; +use clap::{builder::PossibleValue, ValueEnum}; /// The instantiation strategy to use in compiled mode. -#[derive(Debug, Clone, Copy, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Clone, Copy, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum WasmtimeInstantiationStrategy { /// Pool the instances to avoid initializing everything from scratch /// on each instantiation. Use copy-on-write memory when possible. @@ -59,20 +59,22 @@ pub enum WasmExecutionMethod { Compiled, } -impl std::fmt::Display for WasmExecutionMethod { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Interpreted => write!(f, "Interpreted"), - Self::Compiled => write!(f, "Compiled"), +const INTERPRETED_NAME: &str = "interpreted-i-know-what-i-do"; + +impl clap::ValueEnum for WasmExecutionMethod { + /// All possible argument values, in display order. + fn value_variants<'a>() -> &'a [Self] { + let variants = &[Self::Interpreted, Self::Compiled]; + if cfg!(feature = "wasmtime") { + variants + } else { + &variants[..1] } } -} - -impl std::str::FromStr for WasmExecutionMethod { - type Err = String; - fn from_str(s: &str) -> Result { - if s.eq_ignore_ascii_case("interpreted-i-know-what-i-do") { + /// Parse an argument into `Self`. + fn from_str(s: &str, _: bool) -> Result { + if s.eq_ignore_ascii_case(INTERPRETED_NAME) { Ok(Self::Interpreted) } else if s.eq_ignore_ascii_case("compiled") { #[cfg(feature = "wasmtime")] @@ -84,19 +86,29 @@ impl std::str::FromStr for WasmExecutionMethod { Err("`Compiled` variant requires the `wasmtime` feature to be enabled".into()) } } else { - Err(format!("Unknown variant `{}`, known variants: {:?}", s, Self::variants())) + Err(format!("Unknown variant `{}`", s)) + } + } + + /// The canonical argument value. + /// + /// The value is `None` for skipped variants. + fn to_possible_value(&self) -> Option { + match self { + #[cfg(feature = "wasmtime")] + WasmExecutionMethod::Compiled => Some(PossibleValue::new("compiled")), + #[cfg(not(feature = "wasmtime"))] + WasmExecutionMethod::Compiled => None, + WasmExecutionMethod::Interpreted => Some(PossibleValue::new(INTERPRETED_NAME)), } } } -impl WasmExecutionMethod { - /// Returns all the variants of this enum to be shown in the cli. - pub fn variants() -> &'static [&'static str] { - let variants = &["interpreted-i-know-what-i-do", "compiled"]; - if cfg!(feature = "wasmtime") { - variants - } else { - &variants[..1] +impl std::fmt::Display for WasmExecutionMethod { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Interpreted => write!(f, "Interpreted"), + Self::Compiled => write!(f, "Compiled"), } } } @@ -133,15 +145,15 @@ pub fn execution_method_from_cli( /// The default [`WasmExecutionMethod`]. #[cfg(feature = "wasmtime")] -pub const DEFAULT_WASM_EXECUTION_METHOD: &str = "compiled"; +pub const DEFAULT_WASM_EXECUTION_METHOD: WasmExecutionMethod = WasmExecutionMethod::Compiled; /// The default [`WasmExecutionMethod`]. #[cfg(not(feature = "wasmtime"))] -pub const DEFAULT_WASM_EXECUTION_METHOD: &str = "interpreted-i-know-what-i-do"; +pub const DEFAULT_WASM_EXECUTION_METHOD: WasmExecutionMethod = WasmExecutionMethod::Interpreted; #[allow(missing_docs)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum TracingReceiver { /// Output the tracing records using the log. Log, @@ -156,16 +168,16 @@ impl Into for TracingReceiver { } /// The type of the node key. -#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum NodeKeyType { /// Use ed25519. Ed25519, } /// The crypto scheme to use. -#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum CryptoScheme { /// Use ed25519. Ed25519, @@ -176,8 +188,8 @@ pub enum CryptoScheme { } /// The type of the output format. -#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum OutputType { /// Output as json. Json, @@ -186,8 +198,8 @@ pub enum OutputType { } /// How to execute blocks -#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum ExecutionStrategy { /// Execute with native build (if available, WebAssembly otherwise). Native, @@ -212,8 +224,8 @@ impl Into for ExecutionStrategy { /// Available RPC methods. #[allow(missing_docs)] -#[derive(Debug, Copy, Clone, PartialEq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum RpcMethods { /// Expose every RPC method only when RPC is listening on `localhost`, /// otherwise serve only safe RPC methods. @@ -235,7 +247,8 @@ impl Into for RpcMethods { } /// Database backend -#[derive(Debug, Clone, PartialEq, Copy)] +#[derive(Debug, Clone, PartialEq, Copy, clap::ValueEnum)] +#[value(rename_all = "lower")] pub enum Database { /// Facebooks RocksDB #[cfg(feature = "rocksdb")] @@ -246,29 +259,10 @@ pub enum Database { /// instance of ParityDb Auto, /// ParityDb. + #[value(name = "paritydb-experimental")] ParityDbDeprecated, } -impl std::str::FromStr for Database { - type Err = String; - - fn from_str(s: &str) -> Result { - #[cfg(feature = "rocksdb")] - if s.eq_ignore_ascii_case("rocksdb") { - return Ok(Self::RocksDb) - } - if s.eq_ignore_ascii_case("paritydb-experimental") { - return Ok(Self::ParityDbDeprecated) - } else if s.eq_ignore_ascii_case("paritydb") { - return Ok(Self::ParityDb) - } else if s.eq_ignore_ascii_case("auto") { - Ok(Self::Auto) - } else { - Err(format!("Unknown variant `{}`, known variants: {:?}", s, Self::variants())) - } - } -} - impl Database { /// Returns all the variants of this enum to be shown in the cli. pub const fn variants() -> &'static [&'static str] { @@ -284,8 +278,8 @@ impl Database { /// Whether off-chain workers are enabled. #[allow(missing_docs)] -#[derive(Debug, Clone, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Clone, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum OffchainWorkerEnabled { /// Always have offchain worker enabled. Always, @@ -296,8 +290,8 @@ pub enum OffchainWorkerEnabled { } /// Syncing mode. -#[derive(Debug, Clone, Copy, ArgEnum, PartialEq)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Clone, Copy, ValueEnum, PartialEq)] +#[value(rename_all = "kebab-case")] pub enum SyncMode { /// Full sync. Download end verify all blocks. Full, diff --git a/client/cli/src/commands/build_spec_cmd.rs b/client/cli/src/commands/build_spec_cmd.rs index 3196a3e7b915f..5ab3ce9e88a09 100644 --- a/client/cli/src/commands/build_spec_cmd.rs +++ b/client/cli/src/commands/build_spec_cmd.rs @@ -34,14 +34,14 @@ use std::io::Write; #[derive(Debug, Clone, Parser)] pub struct BuildSpecCmd { /// Force raw genesis storage output. - #[clap(long)] + #[arg(long)] pub raw: bool, /// Disable adding the default bootnode to the specification. /// /// By default the `/ip4/127.0.0.1/tcp/30333/p2p/NODE_PEER_ID` bootnode is added to the /// specification when no bootnode exists. - #[clap(long)] + #[arg(long)] pub disable_default_bootnode: bool, #[allow(missing_docs)] diff --git a/client/cli/src/commands/check_block_cmd.rs b/client/cli/src/commands/check_block_cmd.rs index b7e69b1360a0a..3e25eab2c4350 100644 --- a/client/cli/src/commands/check_block_cmd.rs +++ b/client/cli/src/commands/check_block_cmd.rs @@ -30,13 +30,13 @@ use std::{fmt::Debug, str::FromStr, sync::Arc}; #[derive(Debug, Clone, Parser)] pub struct CheckBlockCmd { /// Block hash or number - #[clap(value_name = "HASH or NUMBER")] + #[arg(value_name = "HASH or NUMBER")] pub input: BlockNumberOrHash, /// The default number of 64KB pages to ever allocate for Wasm execution. /// /// Don't alter this unless you know what you're doing. - #[clap(long, value_name = "COUNT")] + #[arg(long, value_name = "COUNT")] pub default_heap_pages: Option, #[allow(missing_docs)] diff --git a/client/cli/src/commands/export_blocks_cmd.rs b/client/cli/src/commands/export_blocks_cmd.rs index ff35b5a51fcad..e2f83200e511c 100644 --- a/client/cli/src/commands/export_blocks_cmd.rs +++ b/client/cli/src/commands/export_blocks_cmd.rs @@ -32,23 +32,23 @@ use std::{fmt::Debug, fs, io, path::PathBuf, str::FromStr, sync::Arc}; #[derive(Debug, Clone, Parser)] pub struct ExportBlocksCmd { /// Output file name or stdout if unspecified. - #[clap(parse(from_os_str))] + #[arg()] pub output: Option, /// Specify starting block number. /// /// Default is 1. - #[clap(long, value_name = "BLOCK")] + #[arg(long, value_name = "BLOCK")] pub from: Option, /// Specify last block number. /// /// Default is best block. - #[clap(long, value_name = "BLOCK")] + #[arg(long, value_name = "BLOCK")] pub to: Option, /// Use binary output rather than JSON. - #[clap(long)] + #[arg(long)] pub binary: bool, #[allow(missing_docs)] diff --git a/client/cli/src/commands/export_state_cmd.rs b/client/cli/src/commands/export_state_cmd.rs index b76724caf0fef..63aa12213b3da 100644 --- a/client/cli/src/commands/export_state_cmd.rs +++ b/client/cli/src/commands/export_state_cmd.rs @@ -32,7 +32,7 @@ use std::{fmt::Debug, io::Write, str::FromStr, sync::Arc}; #[derive(Debug, Clone, Parser)] pub struct ExportStateCmd { /// Block hash or number. - #[clap(value_name = "HASH or NUMBER")] + #[arg(value_name = "HASH or NUMBER")] pub input: Option, #[allow(missing_docs)] diff --git a/client/cli/src/commands/generate.rs b/client/cli/src/commands/generate.rs index 5b1b708f8669c..461cb98bc2e51 100644 --- a/client/cli/src/commands/generate.rs +++ b/client/cli/src/commands/generate.rs @@ -25,10 +25,10 @@ use clap::Parser; /// The `generate` command #[derive(Debug, Clone, Parser)] -#[clap(name = "generate", about = "Generate a random account")] +#[command(name = "generate", about = "Generate a random account")] pub struct GenerateCmd { /// The number of words in the phrase to generate. One of 12 (default), 15, 18, 21 and 24. - #[clap(short = 'w', long, value_name = "WORDS")] + #[arg(short = 'w', long, value_name = "WORDS")] words: Option, #[allow(missing_docs)] diff --git a/client/cli/src/commands/generate_node_key.rs b/client/cli/src/commands/generate_node_key.rs index 3afd99d60a123..e84b4a71d6d72 100644 --- a/client/cli/src/commands/generate_node_key.rs +++ b/client/cli/src/commands/generate_node_key.rs @@ -28,7 +28,7 @@ use std::{ /// The `generate-node-key` command #[derive(Debug, Parser)] -#[clap( +#[command( name = "generate-node-key", about = "Generate a random node key, write it to a file or stdout \ and write the corresponding peer-id to stderr" @@ -37,13 +37,13 @@ pub struct GenerateNodeKeyCmd { /// Name of file to save secret key to. /// /// If not given, the secret key is printed to stdout. - #[clap(long)] + #[arg(long)] file: Option, /// The output is in raw binary format. /// /// If not given, the output is written as an hex encoded string. - #[clap(long)] + #[arg(long)] bin: bool, } diff --git a/client/cli/src/commands/import_blocks_cmd.rs b/client/cli/src/commands/import_blocks_cmd.rs index 749824834bf7b..debc697242ddd 100644 --- a/client/cli/src/commands/import_blocks_cmd.rs +++ b/client/cli/src/commands/import_blocks_cmd.rs @@ -37,17 +37,17 @@ use std::{ #[derive(Debug, Parser)] pub struct ImportBlocksCmd { /// Input file or stdin if unspecified. - #[clap(parse(from_os_str))] + #[arg()] pub input: Option, /// The default number of 64KB pages to ever allocate for Wasm execution. /// /// Don't alter this unless you know what you're doing. - #[clap(long, value_name = "COUNT")] + #[arg(long, value_name = "COUNT")] pub default_heap_pages: Option, /// Try importing blocks from binary format rather than JSON. - #[clap(long)] + #[arg(long)] pub binary: bool, #[allow(missing_docs)] diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index 5029ecd29248c..7d66a680df8c0 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -29,16 +29,16 @@ use std::sync::Arc; /// The `insert` command #[derive(Debug, Clone, Parser)] -#[clap(name = "insert", about = "Insert a key to the keystore of a node.")] +#[command(name = "insert", about = "Insert a key to the keystore of a node.")] pub struct InsertKeyCmd { /// The secret key URI. /// If the value is a file, the file content is used as URI. /// If not given, you will be prompted for the URI. - #[clap(long)] + #[arg(long)] suri: Option, /// Key type, examples: "gran", or "imon" - #[clap(long)] + #[arg(long)] key_type: String, #[allow(missing_docs)] @@ -50,7 +50,7 @@ pub struct InsertKeyCmd { pub keystore_params: KeystoreParams, /// The cryptography scheme that should be used to generate the key out of the given URI. - #[clap(long, value_name = "SCHEME", arg_enum, ignore_case = true)] + #[arg(long, value_name = "SCHEME", value_enum, ignore_case = true)] pub scheme: CryptoScheme, } diff --git a/client/cli/src/commands/inspect_key.rs b/client/cli/src/commands/inspect_key.rs index 59f105dc52a5c..369fd10926dce 100644 --- a/client/cli/src/commands/inspect_key.rs +++ b/client/cli/src/commands/inspect_key.rs @@ -27,7 +27,7 @@ use std::str::FromStr; /// The `inspect` command #[derive(Debug, Parser)] -#[clap( +#[command( name = "inspect", about = "Gets a public key and a SS58 address from the provided Secret URI" )] @@ -44,7 +44,7 @@ pub struct InspectKeyCmd { uri: Option, /// Is the given `uri` a hex encoded public key? - #[clap(long)] + #[arg(long)] public: bool, #[allow(missing_docs)] @@ -72,7 +72,7 @@ pub struct InspectKeyCmd { /// /// If there is no derivation in `--uri`, the public key will be checked against the public key /// of `--uri` directly. - #[clap(long, conflicts_with = "public")] + #[arg(long, conflicts_with = "public")] pub expect_public: Option, } diff --git a/client/cli/src/commands/inspect_node_key.rs b/client/cli/src/commands/inspect_node_key.rs index a9dff9c760d33..9300007cb6bf2 100644 --- a/client/cli/src/commands/inspect_node_key.rs +++ b/client/cli/src/commands/inspect_node_key.rs @@ -28,7 +28,7 @@ use std::{ /// The `inspect-node-key` command #[derive(Debug, Parser)] -#[clap( +#[command( name = "inspect-node-key", about = "Load a node key from a file or stdin and print the corresponding peer-id." )] @@ -36,18 +36,18 @@ pub struct InspectNodeKeyCmd { /// Name of file to read the secret key from. /// /// If not given, the secret key is read from stdin (up to EOF). - #[clap(long)] + #[arg(long)] file: Option, /// The input is in raw binary format. /// /// If not given, the input is read as an hex encoded string. - #[clap(long)] + #[arg(long)] bin: bool, /// This argument is deprecated and has no effect for this command. #[deprecated(note = "Network identifier is not used for node-key inspection")] - #[clap(short = 'n', long = "network", value_name = "NETWORK", ignore_case = true)] + #[arg(short = 'n', long = "network", value_name = "NETWORK", ignore_case = true)] pub network_scheme: Option, } diff --git a/client/cli/src/commands/purge_chain_cmd.rs b/client/cli/src/commands/purge_chain_cmd.rs index b89487a18f779..9a3aeee50e944 100644 --- a/client/cli/src/commands/purge_chain_cmd.rs +++ b/client/cli/src/commands/purge_chain_cmd.rs @@ -33,7 +33,7 @@ use std::{ #[derive(Debug, Clone, Parser)] pub struct PurgeChainCmd { /// Skip interactive prompt by answering yes automatically. - #[clap(short = 'y')] + #[arg(short = 'y')] pub yes: bool, #[allow(missing_docs)] diff --git a/client/cli/src/commands/revert_cmd.rs b/client/cli/src/commands/revert_cmd.rs index f65e348b37b89..8477630cf9404 100644 --- a/client/cli/src/commands/revert_cmd.rs +++ b/client/cli/src/commands/revert_cmd.rs @@ -31,7 +31,7 @@ use std::{fmt::Debug, str::FromStr, sync::Arc}; #[derive(Debug, Parser)] pub struct RevertCmd { /// Number of blocks to revert. - #[clap(default_value = "256")] + #[arg(default_value = "256")] pub num: GenericNumber, #[allow(missing_docs)] diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 11cfb9d0ff651..35181d83f805f 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -42,12 +42,12 @@ pub struct RunCmd { /// The node will be started with the authority role and actively /// participate in any consensus task that it can (e.g. depending on /// availability of local keys). - #[clap(long)] + #[arg(long)] pub validator: bool, /// Disable GRANDPA voter when running in validator mode, otherwise disable the GRANDPA /// observer. - #[clap(long)] + #[arg(long)] pub no_grandpa: bool, /// Listen to all RPC interfaces. @@ -56,13 +56,13 @@ pub struct RunCmd { /// proxy server to filter out dangerous methods. More details: /// . /// Use `--unsafe-rpc-external` to suppress the warning if you understand the risks. - #[clap(long)] + #[arg(long)] pub rpc_external: bool, /// Listen to all RPC interfaces. /// /// Same as `--rpc-external`. - #[clap(long)] + #[arg(long)] pub unsafe_rpc_external: bool, /// RPC methods to expose. @@ -71,12 +71,12 @@ pub struct RunCmd { /// - `safe`: Exposes only a safe subset of RPC methods, denying unsafe RPC methods. /// - `auto`: Acts as `safe` if RPC is served externally, e.g. when `--{rpc,ws}-external` is /// passed, otherwise acts as `unsafe`. - #[clap( + #[arg( long, value_name = "METHOD SET", - arg_enum, + value_enum, ignore_case = true, - default_value = "auto", + default_value_t = RpcMethods::Auto, verbatim_doc_comment )] pub rpc_methods: RpcMethods, @@ -87,59 +87,59 @@ pub struct RunCmd { /// proxy server to filter out dangerous methods. More details: /// . /// Use `--unsafe-ws-external` to suppress the warning if you understand the risks. - #[clap(long)] + #[arg(long)] pub ws_external: bool, /// Listen to all Websocket interfaces. /// /// Same as `--ws-external` but doesn't warn you about it. - #[clap(long)] + #[arg(long)] pub unsafe_ws_external: bool, /// DEPRECATED, this has no affect anymore. Use `rpc_max_request_size` or /// `rpc_max_response_size` instead. - #[clap(long)] + #[arg(long)] pub rpc_max_payload: Option, /// Set the the maximum RPC request payload size for both HTTP and WS in megabytes. /// Default is 15MiB. - #[clap(long)] + #[arg(long)] pub rpc_max_request_size: Option, /// Set the the maximum RPC response payload size for both HTTP and WS in megabytes. /// Default is 15MiB. - #[clap(long)] + #[arg(long)] pub rpc_max_response_size: Option, /// Set the the maximum concurrent subscriptions per connection. /// Default is 1024. - #[clap(long)] + #[arg(long)] pub rpc_max_subscriptions_per_connection: Option, /// Expose Prometheus exporter on all interfaces. /// /// Default is local. - #[clap(long)] + #[arg(long)] pub prometheus_external: bool, /// DEPRECATED, IPC support has been removed. - #[clap(long, value_name = "PATH")] + #[arg(long, value_name = "PATH")] pub ipc_path: Option, /// Specify HTTP RPC server TCP port. - #[clap(long, value_name = "PORT")] + #[arg(long, value_name = "PORT")] pub rpc_port: Option, /// Specify WebSockets RPC server TCP port. - #[clap(long, value_name = "PORT")] + #[arg(long, value_name = "PORT")] pub ws_port: Option, /// Maximum number of WS RPC server connections. - #[clap(long, value_name = "COUNT")] + #[arg(long, value_name = "COUNT")] pub ws_max_connections: Option, /// DEPRECATED, this has no affect anymore. Use `rpc_max_response_size` instead. - #[clap(long)] + #[arg(long)] pub ws_max_out_buffer_capacity: Option, /// Specify browser Origins allowed to access the HTTP & WS RPC servers. @@ -148,29 +148,29 @@ pub struct RunCmd { /// value). Value of `all` will disable origin validation. Default is to /// allow localhost and origins. When running in /// --dev mode the default is to allow all origins. - #[clap(long, value_name = "ORIGINS", parse(from_str = parse_cors))] + #[arg(long, value_name = "ORIGINS", value_parser = parse_cors)] pub rpc_cors: Option, /// Specify Prometheus exporter TCP Port. - #[clap(long, value_name = "PORT")] + #[arg(long, value_name = "PORT")] pub prometheus_port: Option, /// Do not expose a Prometheus exporter endpoint. /// /// Prometheus metric endpoint is enabled by default. - #[clap(long)] + #[arg(long)] pub no_prometheus: bool, /// The human-readable name for this node. /// /// The node name will be reported to the telemetry server, if enabled. - #[clap(long, value_name = "NAME")] + #[arg(long, value_name = "NAME")] pub name: Option, /// Disable connecting to the Substrate telemetry server. /// /// Telemetry is on by default on global chains. - #[clap(long)] + #[arg(long)] pub no_telemetry: bool, /// The URL of the telemetry server to connect to. @@ -179,7 +179,7 @@ pub struct RunCmd { /// telemetry endpoints. Verbosity levels range from 0-9, with 0 denoting /// the least verbosity. /// Expected format is 'URL VERBOSITY', e.g. `--telemetry-url 'wss://foo/bar 0'`. - #[clap(long = "telemetry-url", value_name = "URL VERBOSITY", parse(try_from_str = parse_telemetry_endpoints))] + #[arg(long = "telemetry-url", value_name = "URL VERBOSITY", value_parser = parse_telemetry_endpoints)] pub telemetry_endpoints: Vec<(String, u8)>, #[allow(missing_docs)] @@ -203,40 +203,40 @@ pub struct RunCmd { pub pool_config: TransactionPoolParams, /// Shortcut for `--name Alice --validator` with session keys for `Alice` added to keystore. - #[clap(long, conflicts_with_all = &["bob", "charlie", "dave", "eve", "ferdie", "one", "two"])] + #[arg(long, conflicts_with_all = &["bob", "charlie", "dave", "eve", "ferdie", "one", "two"])] pub alice: bool, /// Shortcut for `--name Bob --validator` with session keys for `Bob` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "charlie", "dave", "eve", "ferdie", "one", "two"])] + #[arg(long, conflicts_with_all = &["alice", "charlie", "dave", "eve", "ferdie", "one", "two"])] pub bob: bool, /// Shortcut for `--name Charlie --validator` with session keys for `Charlie` added to /// keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "dave", "eve", "ferdie", "one", "two"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "dave", "eve", "ferdie", "one", "two"])] pub charlie: bool, /// Shortcut for `--name Dave --validator` with session keys for `Dave` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "eve", "ferdie", "one", "two"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "eve", "ferdie", "one", "two"])] pub dave: bool, /// Shortcut for `--name Eve --validator` with session keys for `Eve` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "ferdie", "one", "two"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "ferdie", "one", "two"])] pub eve: bool, /// Shortcut for `--name Ferdie --validator` with session keys for `Ferdie` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "one", "two"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "one", "two"])] pub ferdie: bool, /// Shortcut for `--name One --validator` with session keys for `One` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "two"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "two"])] pub one: bool, /// Shortcut for `--name Two --validator` with session keys for `Two` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "one"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "one"])] pub two: bool, /// Enable authoring even when offline. - #[clap(long)] + #[arg(long)] pub force_authoring: bool, #[allow(missing_docs)] @@ -246,11 +246,11 @@ pub struct RunCmd { /// The size of the instances cache for each runtime. /// /// The default value is 8 and the values higher than 256 are ignored. - #[clap(long)] + #[arg(long)] pub max_runtime_instances: Option, /// Maximum number of different runtimes that can be cached. - #[clap(long, default_value = "2")] + #[arg(long, default_value_t = 2)] pub runtime_cache_size: u8, /// Run a temporary node. @@ -262,7 +262,7 @@ pub struct RunCmd { /// which includes: database, node key and keystore. /// /// When `--dev` is given and no explicit `--base-path`, this option is implied. - #[clap(long, conflicts_with = "base-path")] + #[arg(long, conflicts_with = "base_path")] pub tmp: bool, } @@ -597,7 +597,7 @@ impl From for Option> { } /// Parse cors origins. -fn parse_cors(s: &str) -> Cors { +fn parse_cors(s: &str) -> Result { let mut is_all = false; let mut origins = Vec::new(); for part in s.split(',') { @@ -611,9 +611,9 @@ fn parse_cors(s: &str) -> Cors { } if is_all { - Cors::All + Ok(Cors::All) } else { - Cors::List(origins) + Ok(Cors::List(origins)) } } diff --git a/client/cli/src/commands/sign.rs b/client/cli/src/commands/sign.rs index 7d93390326717..2c3ff3a1575fd 100644 --- a/client/cli/src/commands/sign.rs +++ b/client/cli/src/commands/sign.rs @@ -23,21 +23,21 @@ use sp_core::crypto::SecretString; /// The `sign` command #[derive(Debug, Clone, Parser)] -#[clap(name = "sign", about = "Sign a message, with a given (secret) key")] +#[command(name = "sign", about = "Sign a message, with a given (secret) key")] pub struct SignCmd { /// The secret key URI. /// If the value is a file, the file content is used as URI. /// If not given, you will be prompted for the URI. - #[clap(long)] + #[arg(long)] suri: Option, /// Message to sign, if not provided you will be prompted to /// pass the message via STDIN - #[clap(long)] + #[arg(long)] message: Option, /// The message on STDIN is hex-encoded data - #[clap(long)] + #[arg(long)] hex: bool, #[allow(missing_docs)] diff --git a/client/cli/src/commands/vanity.rs b/client/cli/src/commands/vanity.rs index 289dc1705c3a3..ae0007ac7964d 100644 --- a/client/cli/src/commands/vanity.rs +++ b/client/cli/src/commands/vanity.rs @@ -29,10 +29,10 @@ use utils::print_from_uri; /// The `vanity` command #[derive(Debug, Clone, Parser)] -#[clap(name = "vanity", about = "Generate a seed that provides a vanity address")] +#[command(name = "vanity", about = "Generate a seed that provides a vanity address")] pub struct VanityCmd { /// Desired pattern - #[clap(long, parse(try_from_str = assert_non_empty_string))] + #[arg(long, value_parser = assert_non_empty_string)] pattern: String, #[allow(missing_docs)] diff --git a/client/cli/src/commands/verify.rs b/client/cli/src/commands/verify.rs index 6389cdbde2c17..82554fbf268fa 100644 --- a/client/cli/src/commands/verify.rs +++ b/client/cli/src/commands/verify.rs @@ -24,7 +24,7 @@ use sp_core::crypto::{ByteArray, Ss58Codec}; /// The `verify` command #[derive(Debug, Clone, Parser)] -#[clap( +#[command( name = "verify", about = "Verify a signature for a message, provided on STDIN, with a given (public or secret) key" )] @@ -39,11 +39,11 @@ pub struct VerifyCmd { /// Message to verify, if not provided you will be prompted to /// pass the message via STDIN - #[clap(long)] + #[arg(long)] message: Option, /// The message on STDIN is hex-encoded data - #[clap(long)] + #[arg(long)] hex: bool, #[allow(missing_docs)] diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index e01befbef41a2..b6d0d47e52c1f 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -129,9 +129,9 @@ pub trait SubstrateCli: Sized { let about = Self::description(); let app = app .name(name) - .author(author.as_str()) - .about(about.as_str()) - .version(full_version.as_str()) + .author(author) + .about(about) + .version(full_version) .propagate_version(true) .args_conflicts_with_subcommands(true) .subcommand_negates_reqs(true); @@ -153,9 +153,9 @@ pub trait SubstrateCli: Sized { /// /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are /// used. It will return a [`clap::Error`], where the [`clap::Error::kind`] is a - /// [`clap::ErrorKind::DisplayHelp`] or [`clap::ErrorKind::DisplayVersion`] respectively. - /// You must call [`clap::Error::exit`] or perform a [`std::process::exit`]. - fn try_from_iter(iter: I) -> clap::Result + /// [`clap::error::ErrorKind::DisplayHelp`] or [`clap::error::ErrorKind::DisplayVersion`] + /// respectively. You must call [`clap::Error::exit`] or perform a [`std::process::exit`]. + fn try_from_iter(iter: I) -> clap::error::Result where Self: Parser + Sized, I: IntoIterator, @@ -169,11 +169,7 @@ pub trait SubstrateCli: Sized { let name = Self::executable_name(); let author = Self::author(); let about = Self::description(); - let app = app - .name(name) - .author(author.as_str()) - .about(about.as_str()) - .version(full_version.as_str()); + let app = app.name(name).author(author).about(about).version(full_version); let matches = app.try_get_matches_from(iter)?; diff --git a/client/cli/src/params/database_params.rs b/client/cli/src/params/database_params.rs index e954b8cc3bc20..3c9ae09e9ab42 100644 --- a/client/cli/src/params/database_params.rs +++ b/client/cli/src/params/database_params.rs @@ -23,17 +23,11 @@ use clap::Args; #[derive(Debug, Clone, PartialEq, Args)] pub struct DatabaseParams { /// Select database backend to use. - #[clap( - long, - alias = "db", - value_name = "DB", - ignore_case = true, - possible_values = Database::variants(), - )] + #[arg(long, alias = "db", value_name = "DB", value_enum)] pub database: Option, /// Limit the memory the database cache can use. - #[clap(long = "db-cache", value_name = "MiB")] + #[arg(long = "db-cache", value_name = "MiB")] pub database_cache_size: Option, } diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index 3cd9fd83bd31b..b7ccbf1c8ed55 100644 --- a/client/cli/src/params/import_params.rs +++ b/client/cli/src/params/import_params.rs @@ -42,12 +42,12 @@ pub struct ImportParams { pub database_params: DatabaseParams, /// Method for executing Wasm runtime code. - #[clap( + #[arg( long = "wasm-execution", value_name = "METHOD", - possible_values = WasmExecutionMethod::variants(), + value_enum, ignore_case = true, - default_value = DEFAULT_WASM_EXECUTION_METHOD, + default_value_t = DEFAULT_WASM_EXECUTION_METHOD, )] pub wasm_method: WasmExecutionMethod, @@ -64,18 +64,18 @@ pub struct ImportParams { /// The `legacy-instance-reuse` strategy is deprecated and will /// be removed in the future. It should only be used in case of /// issues with the default instantiation strategy. - #[clap( + #[arg( long, value_name = "STRATEGY", default_value_t = DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, - arg_enum, + value_enum, )] pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, /// Specify the path where local WASM runtimes are stored. /// /// These runtimes will override on-chain runtimes when the version matches. - #[clap(long, value_name = "PATH", parse(from_os_str))] + #[arg(long, value_name = "PATH")] pub wasm_runtime_overrides: Option, #[allow(missing_docs)] @@ -85,13 +85,13 @@ pub struct ImportParams { /// Specify the state cache size. /// /// Providing `0` will disable the cache. - #[clap(long, value_name = "Bytes", default_value = "67108864")] + #[arg(long, value_name = "Bytes", default_value_t = 67108864)] pub trie_cache_size: usize, /// DEPRECATED /// /// Switch to `--trie-cache-size`. - #[clap(long)] + #[arg(long)] state_cache_size: Option, } @@ -156,39 +156,39 @@ impl ImportParams { pub struct ExecutionStrategiesParams { /// The means of execution used when calling into the runtime for importing blocks as /// part of an initial sync. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_syncing: Option, /// The means of execution used when calling into the runtime for general block import /// (including locally authored blocks). - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_import_block: Option, /// The means of execution used when calling into the runtime while constructing blocks. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_block_construction: Option, /// The means of execution used when calling into the runtime while using an off-chain worker. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_offchain_worker: Option, /// The means of execution used when calling into the runtime while not syncing, importing or /// constructing blocks. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_other: Option, /// The execution strategy that should be used by all execution contexts. - #[clap( + #[arg( long, value_name = "STRATEGY", - arg_enum, + value_enum, ignore_case = true, conflicts_with_all = &[ - "execution-other", - "execution-offchain-worker", - "execution-block-construction", - "execution-import-block", - "execution-syncing", + "execution_other", + "execution_offchain_worker", + "execution_block_construction", + "execution_import_block", + "execution_syncing", ] )] pub execution: Option, diff --git a/client/cli/src/params/keystore_params.rs b/client/cli/src/params/keystore_params.rs index 386d1791dd805..d6c3c35d82418 100644 --- a/client/cli/src/params/keystore_params.rs +++ b/client/cli/src/params/keystore_params.rs @@ -32,32 +32,31 @@ const DEFAULT_KEYSTORE_CONFIG_PATH: &str = "keystore"; #[derive(Debug, Clone, Args)] pub struct KeystoreParams { /// Specify custom URIs to connect to for keystore-services - #[clap(long)] + #[arg(long)] pub keystore_uri: Option, /// Specify custom keystore path. - #[clap(long, value_name = "PATH", parse(from_os_str))] + #[arg(long, value_name = "PATH")] pub keystore_path: Option, /// Use interactive shell for entering the password used by the keystore. - #[clap(long, conflicts_with_all = &["password", "password-filename"])] + #[arg(long, conflicts_with_all = &["password", "password_filename"])] pub password_interactive: bool, /// Password used by the keystore. This allows appending an extra user-defined secret to the /// seed. - #[clap( + #[arg( long, - parse(try_from_str = secret_string_from_str), - conflicts_with_all = &["password-interactive", "password-filename"] + value_parser = secret_string_from_str, + conflicts_with_all = &["password_interactive", "password_filename"] )] pub password: Option, /// File that contains the password used by the keystore. - #[clap( + #[arg( long, value_name = "PATH", - parse(from_os_str), - conflicts_with_all = &["password-interactive", "password"] + conflicts_with_all = &["password_interactive", "password"] )] pub password_filename: Option, } diff --git a/client/cli/src/params/mod.rs b/client/cli/src/params/mod.rs index 9fccce606b4e4..3197deb101bcc 100644 --- a/client/cli/src/params/mod.rs +++ b/client/cli/src/params/mod.rs @@ -27,7 +27,7 @@ mod transaction_pool_params; use crate::arg_enums::{CryptoScheme, OutputType}; use clap::Args; -use sp_core::crypto::Ss58AddressFormat; +use sp_core::crypto::{Ss58AddressFormat, Ss58AddressFormatRegistry}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor}, @@ -40,6 +40,17 @@ pub use crate::params::{ transaction_pool_params::*, }; +/// Parse Ss58AddressFormat +pub fn parse_ss58_address_format(x: &str) -> Result { + match Ss58AddressFormatRegistry::try_from(x) { + Ok(format_registry) => Ok(format_registry.into()), + Err(_) => Err(format!( + "Unable to parse variant. Known variants: {:?}", + Ss58AddressFormat::all_names() + )), + } +} + /// Wrapper type of `String` that holds an unsigned integer of arbitrary size, formatted as a /// decimal. #[derive(Debug, Clone)] @@ -118,7 +129,7 @@ impl BlockNumberOrHash { #[derive(Debug, Clone, Args)] pub struct CryptoSchemeFlag { /// cryptography scheme - #[clap(long, value_name = "SCHEME", arg_enum, ignore_case = true, default_value = "sr25519")] + #[arg(long, value_name = "SCHEME", value_enum, ignore_case = true, default_value_t = CryptoScheme::Sr25519)] pub scheme: CryptoScheme, } @@ -126,7 +137,7 @@ pub struct CryptoSchemeFlag { #[derive(Debug, Clone, Args)] pub struct OutputTypeFlag { /// output format - #[clap(long, value_name = "FORMAT", arg_enum, ignore_case = true, default_value = "text")] + #[arg(long, value_name = "FORMAT", value_enum, ignore_case = true, default_value_t = OutputType::Text)] pub output_type: OutputType, } @@ -134,13 +145,12 @@ pub struct OutputTypeFlag { #[derive(Debug, Clone, Args)] pub struct NetworkSchemeFlag { /// network address format - #[clap( + #[arg( short = 'n', long, value_name = "NETWORK", - possible_values = &Ss58AddressFormat::all_names()[..], ignore_case = true, - parse(try_from_str = Ss58AddressFormat::try_from), + value_parser = parse_ss58_address_format, )] pub network: Option, } diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 0450b5f0e2566..39f98b3573933 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -33,11 +33,11 @@ use std::{borrow::Cow, path::PathBuf}; #[derive(Debug, Clone, Args)] pub struct NetworkParams { /// Specify a list of bootnodes. - #[clap(long, value_name = "ADDR", multiple_values(true))] + #[arg(long, value_name = "ADDR", num_args = 1..)] pub bootnodes: Vec, /// Specify a list of reserved node addresses. - #[clap(long, value_name = "ADDR", multiple_values(true))] + #[arg(long, value_name = "ADDR", num_args = 1..)] pub reserved_nodes: Vec, /// Whether to only synchronize the chain with reserved nodes. @@ -48,12 +48,12 @@ pub struct NetworkParams { /// In particular, if you are a validator your node might still connect to other /// validator nodes and collator nodes regardless of whether they are defined as /// reserved nodes. - #[clap(long)] + #[arg(long)] pub reserved_only: bool, /// The public address that other nodes will use to connect to it. /// This can be used if there's a proxy in front of this node. - #[clap(long, value_name = "PUBLIC_ADDR", multiple_values(true))] + #[arg(long, value_name = "PUBLIC_ADDR", num_args = 1..)] pub public_addr: Vec, /// Listen on this multiaddress. @@ -61,49 +61,49 @@ pub struct NetworkParams { /// By default: /// If `--validator` is passed: `/ip4/0.0.0.0/tcp/` and `/ip6/[::]/tcp/`. /// Otherwise: `/ip4/0.0.0.0/tcp//ws` and `/ip6/[::]/tcp//ws`. - #[clap(long, value_name = "LISTEN_ADDR", multiple_values(true))] + #[arg(long, value_name = "LISTEN_ADDR", num_args = 1..)] pub listen_addr: Vec, /// Specify p2p protocol TCP port. - #[clap(long, value_name = "PORT", conflicts_with_all = &[ "listen-addr" ])] + #[arg(long, value_name = "PORT", conflicts_with_all = &[ "listen_addr" ])] pub port: Option, /// Always forbid connecting to private IPv4 addresses (as specified in /// [RFC1918](https://tools.ietf.org/html/rfc1918)), unless the address was passed with /// `--reserved-nodes` or `--bootnodes`. Enabled by default for chains marked as "live" in /// their chain specifications. - #[clap(long, conflicts_with_all = &["allow-private-ipv4"])] + #[arg(long, conflicts_with_all = &["allow_private_ipv4"])] pub no_private_ipv4: bool, /// Always accept connecting to private IPv4 addresses (as specified in /// [RFC1918](https://tools.ietf.org/html/rfc1918)). Enabled by default for chains marked as /// "local" in their chain specifications, or when `--dev` is passed. - #[clap(long, conflicts_with_all = &["no-private-ipv4"])] + #[arg(long, conflicts_with_all = &["no_private_ipv4"])] pub allow_private_ipv4: bool, /// Specify the number of outgoing connections we're trying to maintain. - #[clap(long, value_name = "COUNT", default_value = "25")] + #[arg(long, value_name = "COUNT", default_value_t = 25)] pub out_peers: u32, /// Maximum number of inbound full nodes peers. - #[clap(long, value_name = "COUNT", default_value = "25")] + #[arg(long, value_name = "COUNT", default_value_t = 25)] pub in_peers: u32, /// Maximum number of inbound light nodes peers. - #[clap(long, value_name = "COUNT", default_value = "100")] + #[arg(long, value_name = "COUNT", default_value_t = 100)] pub in_peers_light: u32, /// Disable mDNS discovery. /// /// By default, the network will use mDNS to discover other nodes on the /// local network. This disables it. Automatically implied when using --dev. - #[clap(long)] + #[arg(long)] pub no_mdns: bool, /// Maximum number of peers from which to ask for the same blocks in parallel. /// /// This allows downloading announced blocks from multiple peers. Decrease to save /// traffic and risk increased latency. - #[clap(long, value_name = "COUNT", default_value = "5")] + #[arg(long, value_name = "COUNT", default_value_t = 5)] pub max_parallel_downloads: u32, #[allow(missing_docs)] @@ -114,7 +114,7 @@ pub struct NetworkParams { /// /// By default this option is `true` for `--dev` or when the chain type is /// `Local`/`Development` and false otherwise. - #[clap(long)] + #[arg(long)] pub discover_local: bool, /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in @@ -122,11 +122,11 @@ pub struct NetworkParams { /// /// See the S/Kademlia paper for more information on the high level design as well as its /// security improvements. - #[clap(long)] + #[arg(long)] pub kademlia_disjoint_query_paths: bool, /// Join the IPFS network and serve transactions over bitswap protocol. - #[clap(long)] + #[arg(long)] pub ipfs_server: bool, /// Blockchain syncing mode. @@ -135,11 +135,11 @@ pub struct NetworkParams { /// - `fast`: Download blocks and the latest state only. /// - `fast-unsafe`: Same as `fast`, but skip downloading state proofs. /// - `warp`: Download the latest state and proof. - #[clap( + #[arg( long, - arg_enum, + value_enum, value_name = "SYNC_MODE", - default_value = "full", + default_value_t = SyncMode::Full, ignore_case = true, verbatim_doc_comment )] diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index 00ce9e8027aab..2346455c26a37 100644 --- a/client/cli/src/params/node_key_params.rs +++ b/client/cli/src/params/node_key_params.rs @@ -46,7 +46,7 @@ pub struct NodeKeyParams { /// WARNING: Secrets provided as command-line arguments are easily exposed. /// Use of this option should be limited to development and testing. To use /// an externally managed secret key, use `--node-key-file` instead. - #[clap(long, value_name = "KEY")] + #[arg(long, value_name = "KEY")] pub node_key: Option, /// The type of secret key to use for libp2p networking. @@ -66,7 +66,7 @@ pub struct NodeKeyParams { /// /// The node's secret key determines the corresponding public key and hence the /// node's peer ID in the context of libp2p. - #[clap(long, value_name = "TYPE", arg_enum, ignore_case = true, default_value = "ed25519")] + #[arg(long, value_name = "TYPE", value_enum, ignore_case = true, default_value_t = NodeKeyType::Ed25519)] pub node_key_type: NodeKeyType, /// The file from which to read the node's secret key to use for libp2p networking. @@ -79,7 +79,7 @@ pub struct NodeKeyParams { /// /// If the file does not exist, it is created with a newly generated secret key of /// the chosen type. - #[clap(long, value_name = "FILE")] + #[arg(long, value_name = "FILE")] pub node_key_file: Option, } @@ -122,7 +122,7 @@ fn parse_ed25519_secret(hex: &str) -> error::Result, /// Specify the blocks pruning mode, a number of blocks to keep or 'archive'. /// @@ -38,7 +38,7 @@ pub struct PruningParams { /// or for the last N blocks (i.e a number). /// /// NOTE: only finalized blocks are subject for removal! - #[clap(alias = "keep-blocks", long, value_name = "COUNT")] + #[arg(alias = "keep-blocks", long, value_name = "COUNT")] pub blocks_pruning: Option, } diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 4a8fc4bcfffdd..6c03ac2c4ec23 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -28,25 +28,25 @@ pub struct SharedParams { /// /// It can be one of the predefined ones (dev, local, or staging) or it can be a path to a file /// with the chainspec (such as one exported by the `build-spec` subcommand). - #[clap(long, value_name = "CHAIN_SPEC")] + #[arg(long, value_name = "CHAIN_SPEC")] pub chain: Option, /// Specify the development chain. /// /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, /// `--alice`, and `--tmp` flags, unless explicitly overridden. - #[clap(long, conflicts_with_all = &["chain"])] + #[arg(long, conflicts_with_all = &["chain"])] pub dev: bool, /// Specify custom base path. - #[clap(long, short = 'd', value_name = "PATH", parse(from_os_str))] + #[arg(long, short = 'd', value_name = "PATH")] pub base_path: Option, /// Sets a custom logging filter. Syntax is =, e.g. -lsync=debug. /// /// Log levels (least to most verbose) are error, warn, info, debug, and trace. /// By default, all targets log `info`. The global log level can be set with -l. - #[clap(short = 'l', long, value_name = "LOG_PATTERN", multiple_values(true))] + #[arg(short = 'l', long, value_name = "LOG_PATTERN", num_args = 1..)] pub log: Vec, /// Enable detailed log output. @@ -54,11 +54,11 @@ pub struct SharedParams { /// This includes displaying the log target, log level and thread name. /// /// This is automatically enabled when something is logged with any higher level than `info`. - #[clap(long)] + #[arg(long)] pub detailed_log_output: bool, /// Disable log color output. - #[clap(long)] + #[arg(long)] pub disable_log_color: bool, /// Enable feature to dynamically update and reload the log filter. @@ -68,15 +68,15 @@ pub struct SharedParams { /// /// The `system_addLogFilter` and `system_resetLogFilter` RPCs will have no effect with this /// option not being set. - #[clap(long)] + #[arg(long)] pub enable_log_reloading: bool, /// Sets a custom profiling filter. Syntax is the same as for logging: = - #[clap(long, value_name = "TARGETS")] + #[arg(long, value_name = "TARGETS")] pub tracing_targets: Option, /// Receiver to process tracing messages. - #[clap(long, value_name = "RECEIVER", arg_enum, ignore_case = true, default_value = "log")] + #[arg(long, value_name = "RECEIVER", value_enum, ignore_case = true, default_value_t = TracingReceiver::Log)] pub tracing_receiver: TracingReceiver, } diff --git a/client/cli/src/params/transaction_pool_params.rs b/client/cli/src/params/transaction_pool_params.rs index 6429dfec3f908..6b3a2d8a97a01 100644 --- a/client/cli/src/params/transaction_pool_params.rs +++ b/client/cli/src/params/transaction_pool_params.rs @@ -23,15 +23,15 @@ use sc_service::config::TransactionPoolOptions; #[derive(Debug, Clone, Args)] pub struct TransactionPoolParams { /// Maximum number of transactions in the transaction pool. - #[clap(long, value_name = "COUNT", default_value = "8192")] + #[arg(long, value_name = "COUNT", default_value_t = 8192)] pub pool_limit: usize, /// Maximum number of kilobytes of all transactions stored in the pool. - #[clap(long, value_name = "COUNT", default_value = "20480")] + #[arg(long, value_name = "COUNT", default_value_t = 20480)] pub pool_kbytes: usize, /// How long a transaction is banned for, if it is considered invalid. Defaults to 1800s. - #[clap(long, value_name = "SECONDS")] + #[arg(long, value_name = "SECONDS")] pub tx_ban_seconds: Option, } diff --git a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 10f82cd316851..2cc620452586d 100644 --- a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index a200d5c41ee35..293a17624820b 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -14,7 +14,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } @@ -36,4 +36,4 @@ path = "src/phragmms_balancing.rs" [[bin]] name = "phragmen_pjr" -path = "src/phragmen_pjr.rs" \ No newline at end of file +path = "src/phragmen_pjr.rs" diff --git a/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs b/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs index 2396fdfa3b40e..0401249a3df1d 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs @@ -68,18 +68,18 @@ fn main() { #[cfg(not(fuzzing))] #[derive(Debug, Parser)] -#[clap(author, version, about)] +#[command(author, version, about)] struct Opt { /// How many candidates participate in this election - #[clap(short, long)] + #[arg(short, long)] candidates: Option, /// How many voters participate in this election - #[clap(short, long)] + #[arg(short, long)] voters: Option, /// Random seed to use in this election - #[clap(long)] + #[arg(long)] seed: Option, } diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index 9c046bf9d2dd1..79c1012196bde 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -19,6 +19,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +use core::fmt::Display; + #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_debug_derive::RuntimeDebug; @@ -412,6 +414,15 @@ pub enum StateVersion { V1 = 1, } +impl Display for StateVersion { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + StateVersion::V0 => f.write_str("0"), + StateVersion::V1 => f.write_str("1"), + } + } +} + impl Default for StateVersion { fn default() -> Self { StateVersion::V1 diff --git a/scripts/ci/node-template-release/Cargo.toml b/scripts/ci/node-template-release/Cargo.toml index 8871a04e19b16..0800b17536453 100644 --- a/scripts/ci/node-template-release/Cargo.toml +++ b/scripts/ci/node-template-release/Cargo.toml @@ -10,7 +10,7 @@ homepage = "https://substrate.io" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.0", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } flate2 = "1.0" fs_extra = "1" git2 = "0.8" diff --git a/scripts/ci/node-template-release/src/main.rs b/scripts/ci/node-template-release/src/main.rs index 62e9b66715768..91a7e865458cf 100644 --- a/scripts/ci/node-template-release/src/main.rs +++ b/scripts/ci/node-template-release/src/main.rs @@ -29,10 +29,10 @@ type CargoToml = HashMap; #[derive(Parser)] struct Options { /// The path to the `node-template` source. - #[clap(parse(from_os_str))] + #[arg()] node_template: PathBuf, /// The path where to output the generated `tar.gz` file. - #[clap(parse(from_os_str))] + #[arg()] output: PathBuf, } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 8eedcb870a3d0..ea908bf0336bf 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "4.1" chrono = "0.4" -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } comfy-table = { version = "6.0.0", default-features = false } handlebars = "4.2.2" diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index 32282b314b804..318c58de8a553 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -43,15 +43,15 @@ const LOG_TARGET: &'static str = "benchmark::block::weight"; #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] pub struct BenchmarkParams { /// Number of the first block to consider. - #[clap(long)] + #[arg(long)] pub from: u32, /// Last block number to consider. - #[clap(long)] + #[arg(long)] pub to: u32, /// Number of times that the benchmark should be repeated for each block. - #[clap(long, default_value = "10")] + #[arg(long, default_value_t = 10)] pub repeat: u32, } diff --git a/utils/frame/benchmarking-cli/src/block/cmd.rs b/utils/frame/benchmarking-cli/src/block/cmd.rs index 14cbb1b438686..f5f7e15a316b3 100644 --- a/utils/frame/benchmarking-cli/src/block/cmd.rs +++ b/utils/frame/benchmarking-cli/src/block/cmd.rs @@ -71,7 +71,7 @@ pub struct BlockCmd { /// Enable the Trie cache. /// /// This should only be used for performance analysis and not for final results. - #[clap(long)] + #[arg(long)] pub enable_trie_cache: bool, } diff --git a/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index 5dcf05956d42c..2a86c10e7ad27 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -43,17 +43,17 @@ use crate::shared::{StatSelect, Stats}; #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] pub struct BenchmarkParams { /// Rounds of warmups before measuring. - #[clap(long, default_value = "10")] + #[arg(long, default_value_t = 10)] pub warmup: u32, /// How many times the benchmark should be repeated. - #[clap(long, default_value = "100")] + #[arg(long, default_value_t = 100)] pub repeat: u32, /// Maximal number of extrinsics that should be put into a block. /// /// Only useful for debugging. - #[clap(long)] + #[arg(long)] pub max_ext_per_block: Option, } diff --git a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs index 339d6126bcd09..b95cd6b5c2e42 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs @@ -62,21 +62,21 @@ pub struct ExtrinsicParams { /// List all available pallets and extrinsics. /// /// The format is CSV with header `pallet, extrinsic`. - #[clap(long)] + #[arg(long)] pub list: bool, /// Pallet name of the extrinsic to benchmark. - #[clap(long, value_name = "PALLET", required_unless_present = "list")] + #[arg(long, value_name = "PALLET", required_unless_present = "list")] pub pallet: Option, /// Extrinsic to benchmark. - #[clap(long, value_name = "EXTRINSIC", required_unless_present = "list")] + #[arg(long, value_name = "EXTRINSIC", required_unless_present = "list")] pub extrinsic: Option, /// Enable the Trie cache. /// /// This should only be used for performance analysis and not for final results. - #[clap(long)] + #[arg(long)] pub enable_trie_cache: bool, } diff --git a/utils/frame/benchmarking-cli/src/machine/mod.rs b/utils/frame/benchmarking-cli/src/machine/mod.rs index 5f27c71983905..a19db671f3cd1 100644 --- a/utils/frame/benchmarking-cli/src/machine/mod.rs +++ b/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -53,30 +53,30 @@ pub struct MachineCmd { /// Do not return an error if any check fails. /// /// Should only be used for debugging. - #[clap(long)] + #[arg(long)] pub allow_fail: bool, /// Set a fault tolerance for passing a requirement. /// /// 10% means that the test would pass even when only 90% score was archived. /// Can be used to mitigate outliers of the benchmarks. - #[clap(long, default_value = "10.0", value_name = "PERCENT")] + #[arg(long, default_value_t = 10.0, value_name = "PERCENT")] pub tolerance: f64, /// Time limit for the verification benchmark. - #[clap(long, default_value = "5.0", value_name = "SECONDS")] + #[arg(long, default_value_t = 5.0, value_name = "SECONDS")] pub verify_duration: f32, /// Time limit for the hash function benchmark. - #[clap(long, default_value = "5.0", value_name = "SECONDS")] + #[arg(long, default_value_t = 5.0, value_name = "SECONDS")] pub hash_duration: f32, /// Time limit for the memory benchmark. - #[clap(long, default_value = "5.0", value_name = "SECONDS")] + #[arg(long, default_value_t = 5.0, value_name = "SECONDS")] pub memory_duration: f32, /// Time limit for each disk benchmark. - #[clap(long, default_value = "5.0", value_name = "SECONDS")] + #[arg(long, default_value_t = 5.0, value_name = "SECONDS")] pub disk_duration: f32, } diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 93b0e7c472647..74c1e7efc24d4 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -73,13 +73,13 @@ pub struct OverheadParams { /// Add a header to the generated weight output file. /// /// Good for adding LICENSE headers. - #[clap(long, value_name = "PATH")] + #[arg(long, value_name = "PATH")] pub header: Option, /// Enable the Trie cache. /// /// This should only be used for performance analysis and not for final results. - #[clap(long)] + #[arg(long)] pub enable_trie_cache: bool, } diff --git a/utils/frame/benchmarking-cli/src/pallet/mod.rs b/utils/frame/benchmarking-cli/src/pallet/mod.rs index 0e698c4e73910..b10f531bc0aed 100644 --- a/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -27,69 +27,69 @@ use std::{fmt::Debug, path::PathBuf}; // Add a more relaxed parsing for pallet names by allowing pallet directory names with `-` to be // used like crate names with `_` -fn parse_pallet_name(pallet: &str) -> String { - pallet.replace("-", "_") +fn parse_pallet_name(pallet: &str) -> std::result::Result { + Ok(pallet.replace("-", "_")) } /// Benchmark the extrinsic weight of FRAME Pallets. #[derive(Debug, clap::Parser)] pub struct PalletCmd { /// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`). - #[clap(short, long, parse(from_str = parse_pallet_name), required_unless_present_any = ["list", "json-input"])] + #[arg(short, long, value_parser = parse_pallet_name, required_unless_present_any = ["list", "json_input"])] pub pallet: Option, /// Select an extrinsic inside the pallet to benchmark, or `*` for all. - #[clap(short, long, required_unless_present_any = ["list", "json-input"])] + #[arg(short, long, required_unless_present_any = ["list", "json_input"])] pub extrinsic: Option, /// Select how many samples we should take across the variable components. - #[clap(short, long, default_value = "2")] + #[arg(short, long, default_value_t = 2)] pub steps: u32, /// Indicates lowest values for each of the component ranges. - #[clap(long = "low", use_value_delimiter = true)] + #[arg(long = "low", value_delimiter = ',')] pub lowest_range_values: Vec, /// Indicates highest values for each of the component ranges. - #[clap(long = "high", use_value_delimiter = true)] + #[arg(long = "high", value_delimiter = ',')] pub highest_range_values: Vec, /// Select how many repetitions of this benchmark should run from within the wasm. - #[clap(short, long, default_value = "1")] + #[arg(short, long, default_value_t = 1)] pub repeat: u32, /// Select how many repetitions of this benchmark should run from the client. /// /// NOTE: Using this alone may give slower results, but will afford you maximum Wasm memory. - #[clap(long, default_value = "1")] + #[arg(long, default_value_t = 1)] pub external_repeat: u32, /// Print the raw results in JSON format. - #[clap(long = "json")] + #[arg(long = "json")] pub json_output: bool, /// Write the raw results in JSON format into the given file. - #[clap(long, conflicts_with = "json-output")] + #[arg(long, conflicts_with = "json_output")] pub json_file: Option, /// Don't print the median-slopes linear regression analysis. - #[clap(long)] + #[arg(long)] pub no_median_slopes: bool, /// Don't print the min-squares linear regression analysis. - #[clap(long)] + #[arg(long)] pub no_min_squares: bool, /// Output the benchmarks to a Rust file at the given path. - #[clap(long)] + #[arg(long)] pub output: Option, /// Add a header file to your outputted benchmarks. - #[clap(long)] + #[arg(long)] pub header: Option, /// Path to Handlebars template file used for outputting benchmark results. (Optional) - #[clap(long)] + #[arg(long)] pub template: Option, #[allow(missing_docs)] @@ -100,25 +100,25 @@ pub struct PalletCmd { /// * min-squares (default) /// * median-slopes /// * max (max of min squares and median slopes for each value) - #[clap(long)] + #[arg(long)] pub output_analysis: Option, /// Set the heap pages while running benchmarks. If not set, the default value from the client /// is used. - #[clap(long)] + #[arg(long)] pub heap_pages: Option, /// Disable verification logic when running benchmarks. - #[clap(long)] + #[arg(long)] pub no_verify: bool, /// Display and run extra benchmarks that would otherwise not be needed for weight /// construction. - #[clap(long)] + #[arg(long)] pub extra: bool, /// Estimate PoV size. - #[clap(long)] + #[arg(long)] pub record_proof: bool, #[allow(missing_docs)] @@ -126,50 +126,50 @@ pub struct PalletCmd { pub shared_params: sc_cli::SharedParams, /// The execution strategy that should be used for benchmarks. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution: Option, /// Method for executing Wasm runtime code. - #[clap( + #[arg( long = "wasm-execution", value_name = "METHOD", - possible_values = WasmExecutionMethod::variants(), + value_enum, ignore_case = true, - default_value = DEFAULT_WASM_EXECUTION_METHOD, + default_value_t = DEFAULT_WASM_EXECUTION_METHOD, )] pub wasm_method: WasmExecutionMethod, /// The WASM instantiation method to use. /// /// Only has an effect when `wasm-execution` is set to `compiled`. - #[clap( + #[arg( long = "wasm-instantiation-strategy", value_name = "STRATEGY", default_value_t = DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, - arg_enum, + value_enum, )] pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, /// Limit the memory the database cache can use. - #[clap(long = "db-cache", value_name = "MiB", default_value = "1024")] + #[arg(long = "db-cache", value_name = "MiB", default_value_t = 1024)] pub database_cache_size: u32, /// List the benchmarks that match your query rather than running them. /// /// When nothing is provided, we list all benchmarks. - #[clap(long)] + #[arg(long)] pub list: bool, /// If enabled, the storage info is not displayed in the output next to the analysis. /// /// This is independent of the storage info appearing in the *output file*. Use a Handlebar /// template for that purpose. - #[clap(long)] + #[arg(long)] pub no_storage_info: bool, /// A path to a `.json` file with existing benchmark results generated with `--json` or /// `--json-file`. When specified the benchmarks are not actually executed, and the data for /// the analysis is read from this file. - #[clap(long)] + #[arg(long)] pub json_input: Option, } diff --git a/utils/frame/benchmarking-cli/src/shared/mod.rs b/utils/frame/benchmarking-cli/src/shared/mod.rs index 33189792c4008..ea5415f33f020 100644 --- a/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -95,22 +95,22 @@ pub fn check_build_profile() -> Result<(), String> { /// Parameters to configure how the host info will be determined. #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] -#[clap(rename_all = "kebab-case")] +#[command(rename_all = "kebab-case")] pub struct HostInfoParams { /// Manually override the hostname to use. - #[clap(long)] + #[arg(long)] pub hostname_override: Option, /// Specify a fallback hostname if no-one could be detected automatically. /// /// Note: This only exists to make the `hostname` function infallible. - #[clap(long, default_value = "")] + #[arg(long, default_value = "")] pub hostname_fallback: String, /// Specify a fallback CPU name if no-one could be detected automatically. /// /// Note: This only exists to make the `cpuname` function infallible. - #[clap(long, default_value = "")] + #[arg(long, default_value = "")] pub cpuname_fallback: String, } diff --git a/utils/frame/benchmarking-cli/src/shared/weight_params.rs b/utils/frame/benchmarking-cli/src/shared/weight_params.rs index 4dd80cd41ff3d..030bbfa00d468 100644 --- a/utils/frame/benchmarking-cli/src/shared/weight_params.rs +++ b/utils/frame/benchmarking-cli/src/shared/weight_params.rs @@ -31,23 +31,23 @@ pub struct WeightParams { /// File or directory to write the *weight* files to. /// /// For Substrate this should be `frame/support/src/weights`. - #[clap(long)] + #[arg(long)] pub weight_path: Option, /// Select a specific metric to calculate the final weight output. - #[clap(long = "metric", default_value = "average")] + #[arg(long = "metric", default_value = "average")] pub weight_metric: StatSelect, /// Multiply the resulting weight with the given factor. Must be positive. /// /// Is applied before `weight_add`. - #[clap(long = "mul", default_value = "1")] + #[arg(long = "mul", default_value_t = 1.0)] pub weight_mul: f64, /// Add the given offset to the resulting weight. /// /// Is applied after `weight_mul`. - #[clap(long = "add", default_value = "0")] + #[arg(long = "add", default_value_t = 0)] pub weight_add: u64, } diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index a4c4188dfe073..86041d9517de6 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -68,54 +68,54 @@ pub struct StorageParams { pub hostinfo: HostInfoParams, /// Skip the `read` benchmark. - #[clap(long)] + #[arg(long)] pub skip_read: bool, /// Skip the `write` benchmark. - #[clap(long)] + #[arg(long)] pub skip_write: bool, /// Specify the Handlebars template to use for outputting benchmark results. - #[clap(long)] + #[arg(long)] pub template_path: Option, /// Add a header to the generated weight output file. /// /// Good for adding LICENSE headers. - #[clap(long, value_name = "PATH")] + #[arg(long, value_name = "PATH")] pub header: Option, /// Path to write the raw 'read' results in JSON format to. Can be a file or directory. - #[clap(long)] + #[arg(long)] pub json_read_path: Option, /// Path to write the raw 'write' results in JSON format to. Can be a file or directory. - #[clap(long)] + #[arg(long)] pub json_write_path: Option, /// Rounds of warmups before measuring. - #[clap(long, default_value = "1")] + #[arg(long, default_value_t = 1)] pub warmups: u32, /// The `StateVersion` to use. Substrate `--dev` should use `V1` and Polkadot `V0`. /// Selecting the wrong version can corrupt the DB. - #[clap(long, possible_values = ["0", "1"])] + #[arg(long, value_parser = clap::value_parser!(u8).range(0..=1))] pub state_version: u8, /// Trie cache size in bytes. /// /// Providing `0` will disable the cache. - #[clap(long, value_name = "Bytes", default_value = "67108864")] + #[arg(long, value_name = "Bytes", default_value_t = 67108864)] pub trie_cache_size: usize, /// Enable the Trie cache. /// /// This should only be used for performance analysis and not for final results. - #[clap(long)] + #[arg(long)] pub enable_trie_cache: bool, /// Include child trees in benchmark. - #[clap(long)] + #[arg(long)] pub include_child_trees: bool, } diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index f01e2f1a5d51f..89e9ee79db214 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/utils/frame/frame-utilities-cli/src/pallet_id.rs b/utils/frame/frame-utilities-cli/src/pallet_id.rs index 4ad82a01c2433..2a80e3a3d312d 100644 --- a/utils/frame/frame-utilities-cli/src/pallet_id.rs +++ b/utils/frame/frame-utilities-cli/src/pallet_id.rs @@ -28,31 +28,30 @@ use sp_runtime::traits::AccountIdConversion; /// The `palletid` command #[derive(Debug, Parser)] -#[clap(name = "palletid", about = "Inspect a module ID address")] +#[command(name = "palletid", about = "Inspect a module ID address")] pub struct PalletIdCmd { /// The module ID used to derive the account id: String, /// network address format - #[clap( + #[arg( long, value_name = "NETWORK", - possible_values = &Ss58AddressFormat::all_names()[..], - parse(try_from_str = Ss58AddressFormat::try_from), + value_parser = sc_cli::parse_ss58_address_format, ignore_case = true, )] pub network: Option, #[allow(missing_docs)] - #[clap(flatten)] + #[command(flatten)] pub output_scheme: OutputTypeFlag, #[allow(missing_docs)] - #[clap(flatten)] + #[command(flatten)] pub crypto_scheme: CryptoSchemeFlag, #[allow(missing_docs)] - #[clap(flatten)] + #[command(flatten)] pub keystore_params: KeystoreParams, } diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml index 5af7dd78a08e8..6cc14a0595501 100644 --- a/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -14,4 +14,4 @@ kitchensink-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runt generate-bags = { version = "4.0.0-dev", path = "../" } # third-party -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } diff --git a/utils/frame/generate-bags/node-runtime/src/main.rs b/utils/frame/generate-bags/node-runtime/src/main.rs index 5ea1262d95d34..27e51b205f8ce 100644 --- a/utils/frame/generate-bags/node-runtime/src/main.rs +++ b/utils/frame/generate-bags/node-runtime/src/main.rs @@ -25,19 +25,19 @@ use std::path::PathBuf; // #[clap(author, version, about)] struct Opt { /// How many bags to generate. - #[clap(long, default_value = "200")] + #[arg(long, default_value_t = 200)] n_bags: usize, /// Where to write the output. output: PathBuf, /// The total issuance of the currency used to create `VoteWeight`. - #[clap(short, long)] + #[arg(short, long)] total_issuance: u128, /// The minimum account balance (i.e. existential deposit) for the currency used to create /// `VoteWeight`. - #[clap(short, long)] + #[arg(short, long)] minimum_balance: u128, } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 956eaff745335..8a9d5a5f8979a 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } log = "0.4.17" parity-scale-codec = "3.0.0" serde = "1.0.136" diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index 0c8b968d1b4b1..df8c51b5a92d4 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -33,11 +33,11 @@ use std::{fmt::Debug, str::FromStr}; #[derive(Debug, Clone, clap::Parser)] pub struct ExecuteBlockCmd { /// Overwrite the wasm code in state or not. - #[clap(long)] + #[arg(long)] overwrite_wasm_code: bool, /// If set the state root check is disabled. - #[clap(long)] + #[arg(long)] no_state_root_check: bool, /// Which try-state targets to execute when running this command. @@ -49,17 +49,16 @@ pub struct ExecuteBlockCmd { /// `Staking, System`). /// - `rr-[x]` where `[x]` is a number. Then, the given number of pallets are checked in a /// round-robin fashion. - #[clap(long, default_value = "none")] + #[arg(long, default_value = "none")] try_state: frame_try_runtime::TryStateSelect, /// The block hash at which to fetch the block. /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::at` is. Only use this (with care) when combined with a snapshot. - #[clap( + #[arg( long, - multiple_values = false, - parse(try_from_str = crate::parse::hash) + value_parser = crate::parse::hash )] block_at: Option, @@ -67,10 +66,9 @@ pub struct ExecuteBlockCmd { /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::uri` is. Only use this (with care) when combined with a snapshot. - #[clap( + #[arg( long, - multiple_values = false, - parse(try_from_str = crate::parse::url) + value_parser = crate::parse::url )] block_ws_uri: Option, @@ -79,7 +77,7 @@ pub struct ExecuteBlockCmd { /// For this command only, if the `live` is used, then state of the parent block is fetched. /// /// If `block_at` is provided, then the [`State::Live::at`] is being ignored. - #[clap(subcommand)] + #[command(subcommand)] state: State, } diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index fb5345827858a..df6d40b2b8ab1 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -43,11 +43,11 @@ const UN_SUB: &str = "chain_unsubscribeFinalizedHeads"; #[derive(Debug, Clone, clap::Parser)] pub struct FollowChainCmd { /// The url to connect to. - #[clap(short, long, parse(try_from_str = parse::url))] + #[arg(short, long, value_parser = parse::url)] uri: String, /// If set, then the state root check is enabled. - #[clap(long)] + #[arg(long)] state_root_check: bool, /// Which try-state targets to execute when running this command. @@ -59,11 +59,11 @@ pub struct FollowChainCmd { /// `Staking, System`). /// - `rr-[x]` where `[x]` is a number. Then, the given number of pallets are checked in a /// round-robin fashion. - #[clap(long, default_value = "none")] + #[arg(long, default_value = "none")] try_state: frame_try_runtime::TryStateSelect, /// If present, a single connection to a node will be kept and reused for fetching blocks. - #[clap(long)] + #[arg(long)] keep_connection: bool, } diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index b0404fff18135..6f48d1f8f68a7 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -31,17 +31,16 @@ use std::{fmt::Debug, str::FromStr}; #[derive(Debug, Clone, clap::Parser)] pub struct OffchainWorkerCmd { /// Overwrite the wasm code in state or not. - #[clap(long)] + #[arg(long)] overwrite_wasm_code: bool, /// The block hash at which to fetch the header. /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::at` is. Only use this (with care) when combined with a snapshot. - #[clap( + #[arg( long, - multiple_values = false, - parse(try_from_str = parse::hash) + value_parser = parse::hash )] header_at: Option, @@ -49,15 +48,14 @@ pub struct OffchainWorkerCmd { /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::uri` is. Only use this (with care) when combined with a snapshot. - #[clap( + #[arg( long, - multiple_values = false, - parse(try_from_str = parse::url) + value_parser = parse::url )] header_ws_uri: Option, /// The state type to use. - #[clap(subcommand)] + #[command(subcommand)] pub state: State, } diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 1d7d876a4aa92..5e11123526532 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -32,7 +32,7 @@ use crate::{ #[derive(Debug, Clone, clap::Parser)] pub struct OnRuntimeUpgradeCmd { /// The state type to use. - #[clap(subcommand)] + #[command(subcommand)] pub state: State, } diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index b8a2779d57e19..9034f356a9f67 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -385,6 +385,7 @@ pub enum Command { /// Shared parameters of the `try-runtime` commands #[derive(Debug, Clone, clap::Parser)] +#[group(skip)] pub struct SharedParams { /// Shared parameters of substrate cli. #[allow(missing_docs)] @@ -392,41 +393,41 @@ pub struct SharedParams { pub shared_params: sc_cli::SharedParams, /// The execution strategy that should be used. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true, default_value = "wasm")] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true, default_value_t = ExecutionStrategy::Wasm)] pub execution: ExecutionStrategy, /// Type of wasm execution used. - #[clap( + #[arg( long = "wasm-execution", value_name = "METHOD", - possible_values = WasmExecutionMethod::variants(), + value_enum, ignore_case = true, - default_value = DEFAULT_WASM_EXECUTION_METHOD, + default_value_t = DEFAULT_WASM_EXECUTION_METHOD, )] pub wasm_method: WasmExecutionMethod, /// The WASM instantiation method to use. /// /// Only has an effect when `wasm-execution` is set to `compiled`. - #[clap( + #[arg( long = "wasm-instantiation-strategy", value_name = "STRATEGY", default_value_t = DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, - arg_enum, + value_enum, )] pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, /// The number of 64KB pages to allocate for Wasm execution. Defaults to /// [`sc_service::Configuration.default_heap_pages`]. - #[clap(long)] + #[arg(long)] pub heap_pages: Option, /// When enabled, the spec check will not panic, and instead only show a warning. - #[clap(long)] + #[arg(long)] pub no_spec_check_panic: bool, /// State version that is used by the chain. - #[clap(long, default_value = "1", parse(try_from_str = parse::state_version))] + #[arg(long, default_value_t = StateVersion::V1, value_parser = parse::state_version)] pub state_version: StateVersion, } @@ -438,7 +439,7 @@ pub struct TryRuntimeCmd { #[clap(flatten)] pub shared: SharedParams, - #[clap(subcommand)] + #[command(subcommand)] pub command: Command, } @@ -449,17 +450,17 @@ pub enum State { /// /// This can be crated by passing a value to [`State::Live::snapshot_path`]. Snap { - #[clap(short, long)] + #[arg(short, long)] snapshot_path: PathBuf, }, /// Use a live chain as the source of runtime state. Live { /// The url to connect to. - #[clap( + #[arg( short, long, - parse(try_from_str = parse::url), + value_parser = parse::url, )] uri: String, @@ -467,21 +468,20 @@ pub enum State { /// /// If non provided, then the latest finalized head is used. This is particularly useful /// for [`Command::OnRuntimeUpgrade`]. - #[clap( + #[arg( short, long, - multiple_values = false, - parse(try_from_str = parse::hash), + value_parser = parse::hash, )] at: Option, /// An optional state snapshot file to WRITE to. Not written if set to `None`. - #[clap(short, long)] + #[arg(short, long)] snapshot_path: Option, /// A pallet to scrape. Can be provided multiple times. If empty, entire chain state will /// be scraped. - #[clap(short, long, multiple_values = true)] + #[arg(short, long, num_args = 1..)] pallet: Vec, /// Fetch the child-keys as well. @@ -489,7 +489,7 @@ pub enum State { /// Default is `false`, if specific `--pallets` are specified, `true` otherwise. In other /// words, if you scrape the whole state the child tree data is included out of the box. /// Otherwise, it must be enabled explicitly using this flag. - #[clap(long)] + #[arg(long)] child_tree: bool, }, } From b9a555d6331bf74e0880ba075814d8d90ae9e1e3 Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Tue, 18 Oct 2022 08:28:07 +0100 Subject: [PATCH 1281/1472] implement storage decode length for BTreeSet (#12503) * implement storage decode length for BTreeSet * Orderly moving of things around * include test for append and decode_len * fix cargo clippy issue --- frame/support/src/storage/mod.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index b70436785af12..333f4382557b1 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -27,7 +27,7 @@ use crate::{ use codec::{Decode, Encode, EncodeLike, FullCodec, FullEncode}; use sp_core::storage::ChildInfo; use sp_runtime::generic::{Digest, DigestItem}; -use sp_std::{marker::PhantomData, prelude::*}; +use sp_std::{collections::btree_set::BTreeSet, marker::PhantomData, prelude::*}; pub use self::{ transactional::{ @@ -1303,6 +1303,7 @@ mod private { impl Sealed for WeakBoundedVec {} impl Sealed for bounded_btree_map::BoundedBTreeMap {} impl Sealed for bounded_btree_set::BoundedBTreeSet {} + impl Sealed for BTreeSet {} macro_rules! impl_sealed_for_tuple { ($($elem:ident),+) => { @@ -1335,6 +1336,9 @@ mod private { impl StorageAppend for Vec {} impl StorageDecodeLength for Vec {} +impl StorageAppend for BTreeSet {} +impl StorageDecodeLength for BTreeSet {} + /// We abuse the fact that SCALE does not put any marker into the encoding, i.e. we only encode the /// internal vec and we can append to this vec. We have a test that ensures that if the `Digest` /// format ever changes, we need to remove this here. @@ -1832,4 +1836,22 @@ mod test { ); }); } + + #[crate::storage_alias] + type FooSet = StorageValue>; + + #[test] + fn btree_set_append_and_decode_len_works() { + TestExternalities::default().execute_with(|| { + let btree = BTreeSet::from([1, 2, 3]); + FooSet::put(btree); + + FooSet::append(4); + FooSet::append(5); + FooSet::append(6); + FooSet::append(7); + + assert_eq!(FooSet::decode_len().unwrap(), 7); + }); + } } From 415648d87848dfa02955e3bea73f55503b852bc1 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 18 Oct 2022 10:46:25 +0200 Subject: [PATCH 1282/1472] Decrease default --out-peers from 25 to 15 (#12434) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- client/cli/src/params/network_params.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 39f98b3573933..5580dea45bde6 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -82,12 +82,13 @@ pub struct NetworkParams { pub allow_private_ipv4: bool, /// Specify the number of outgoing connections we're trying to maintain. - #[arg(long, value_name = "COUNT", default_value_t = 25)] + #[arg(long, value_name = "COUNT", default_value_t = 15)] pub out_peers: u32, /// Maximum number of inbound full nodes peers. #[arg(long, value_name = "COUNT", default_value_t = 25)] pub in_peers: u32, + /// Maximum number of inbound light nodes peers. #[arg(long, value_name = "COUNT", default_value_t = 100)] pub in_peers_light: u32, From 4c45673d92678c85732b06a7cd47da5c056484c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 18 Oct 2022 12:07:02 +0200 Subject: [PATCH 1283/1472] Prepare for latest clippy (nightly 09-10-2022) (#12466) --- client/api/src/in_mem.rs | 2 +- client/consensus/slots/src/lib.rs | 2 +- client/db/src/bench.rs | 2 +- client/db/src/lib.rs | 2 +- client/network/sync/src/lib.rs | 3 +-- client/state-db/src/pruning.rs | 2 +- client/transaction-pool/src/graph/pool.rs | 6 +++--- frame/transaction-payment/src/lib.rs | 8 ++++---- primitives/runtime/src/generic/era.rs | 4 ++-- primitives/runtime/src/offchain/storage_lock.rs | 14 ++++++-------- primitives/state-machine/src/in_memory_backend.rs | 4 ++-- .../state-machine/src/overlayed_changes/mod.rs | 2 +- primitives/trie/src/recorder.rs | 2 +- test-utils/runtime/client/src/lib.rs | 2 +- utils/frame/benchmarking-cli/src/pallet/command.rs | 5 ++--- 15 files changed, 28 insertions(+), 32 deletions(-) diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 9cea1883bdcdc..99efdd3bf1d22 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -516,7 +516,7 @@ where ) -> sp_blockchain::Result { check_genesis_storage(&storage)?; - let child_delta = storage.children_default.iter().map(|(_storage_key, child_content)| { + let child_delta = storage.children_default.values().map(|child_content| { ( &child_content.child_info, child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))), diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 6225bbbda1745..90bfef6c1609c 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -1118,7 +1118,7 @@ mod test { // But lets assert all distances, which we expect to grow linearly until `max_interval + 1` let expected_intervals: Vec<_> = - (0..497).map(|i| (i / 2).max(1).min(expected_distance)).collect(); + (0..497).map(|i| (i / 2).clamp(1, expected_distance)).collect(); assert_eq!(intervals, expected_intervals); } diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index b1f4e3b6c0af5..13d91fff0b555 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -116,7 +116,7 @@ impl BenchmarkingState { state.add_whitelist_to_tracker(); state.reopen()?; - let child_delta = genesis.children_default.iter().map(|(_storage_key, child_content)| { + let child_delta = genesis.children_default.values().map(|child_content| { ( &child_content.child_info, child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))), diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index ae777ad154f6d..1a80c16c4e59d 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -798,7 +798,7 @@ impl BlockImportOperation { return Err(sp_blockchain::Error::InvalidState) } - let child_delta = storage.children_default.iter().map(|(_storage_key, child_content)| { + let child_delta = storage.children_default.values().map(|child_content| { ( &child_content.child_info, child_content.data.iter().map(|(k, v)| (&k[..], Some(&v[..]))), diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 64d9d4d668eb3..e9c2b24b2ba95 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -1444,8 +1444,7 @@ where if let SyncMode::LightState { skip_proofs, .. } = &self.mode { if self.state_sync.is_none() && !self.peers.is_empty() && self.queue_blocks.is_empty() { // Finalized a recent block. - let mut heads: Vec<_> = - self.peers.iter().map(|(_, peer)| peer.best_number).collect(); + let mut heads: Vec<_> = self.peers.values().map(|peer| peer.best_number).collect(); heads.sort(); let median = heads[heads.len() / 2]; if number + STATE_SYNC_FINALITY_THRESHOLD.saturated_into() >= median { diff --git a/client/state-db/src/pruning.rs b/client/state-db/src/pruning.rs index 2c23110910495..50a46def59541 100644 --- a/client/state-db/src/pruning.rs +++ b/client/state-db/src/pruning.rs @@ -117,7 +117,7 @@ impl DeathRowQueue { window_size: u32, ) -> Result, Error> { // limit the cache capacity from 1 to `DEFAULT_MAX_BLOCK_CONSTRAINT` - let cache_capacity = window_size.max(1).min(DEFAULT_MAX_BLOCK_CONSTRAINT) as usize; + let cache_capacity = window_size.clamp(1, DEFAULT_MAX_BLOCK_CONSTRAINT) as usize; let mut cache = VecDeque::with_capacity(cache_capacity); trace!(target: "state-db", "Reading pruning journal for the database-backed queue. Pending #{}", base); // Load block from db diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 9afceffe8dddf..d311e0d0c8f2f 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -168,7 +168,7 @@ impl Pool { ) -> Result, B::Error>>, B::Error> { let xts = xts.into_iter().map(|xt| (source, xt)); let validated_transactions = self.verify(at, xts, CheckBannedBeforeVerify::Yes).await?; - Ok(self.validated_pool.submit(validated_transactions.into_iter().map(|(_, tx)| tx))) + Ok(self.validated_pool.submit(validated_transactions.into_values())) } /// Resubmit the given extrinsics to the pool. @@ -182,7 +182,7 @@ impl Pool { ) -> Result, B::Error>>, B::Error> { let xts = xts.into_iter().map(|xt| (source, xt)); let validated_transactions = self.verify(at, xts, CheckBannedBeforeVerify::No).await?; - Ok(self.validated_pool.submit(validated_transactions.into_iter().map(|(_, tx)| tx))) + Ok(self.validated_pool.submit(validated_transactions.into_values())) } /// Imports one unverified extrinsic to the pool @@ -349,7 +349,7 @@ impl Pool { at, known_imported_hashes, pruned_hashes, - reverified_transactions.into_iter().map(|(_, xt)| xt).collect(), + reverified_transactions.into_values().collect(), ) } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index ce85bf93a90a7..5027db41ec098 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -228,11 +228,11 @@ where if positive { let excess = first_term.saturating_add(second_term).saturating_mul(previous); - previous.saturating_add(excess).max(min_multiplier).min(max_multiplier) + previous.saturating_add(excess).clamp(min_multiplier, max_multiplier) } else { // Defensive-only: first_term > second_term. Safe subtraction. let negative = first_term.saturating_sub(second_term).saturating_mul(previous); - previous.saturating_sub(negative).max(min_multiplier).min(max_multiplier) + previous.saturating_sub(negative).clamp(min_multiplier, max_multiplier) } } } @@ -713,8 +713,8 @@ where let max_block_weight = max_block_weight.ref_time(); let info_weight = info.weight.ref_time(); - let bounded_weight = info_weight.max(1).min(max_block_weight); - let bounded_length = (len as u64).max(1).min(max_block_length); + let bounded_weight = info_weight.clamp(1, max_block_weight); + let bounded_length = (len as u64).clamp(1, max_block_length); let max_tx_per_block_weight = max_block_weight / bounded_weight; let max_tx_per_block_length = max_block_length / bounded_length; diff --git a/primitives/runtime/src/generic/era.rs b/primitives/runtime/src/generic/era.rs index 2ca50b12b2e1f..b26545fb8404e 100644 --- a/primitives/runtime/src/generic/era.rs +++ b/primitives/runtime/src/generic/era.rs @@ -63,7 +63,7 @@ impl Era { /// does not exceed `BlockHashCount` parameter passed to `system` module, since that /// prunes old blocks and renders transactions immediately invalid. pub fn mortal(period: u64, current: u64) -> Self { - let period = period.checked_next_power_of_two().unwrap_or(1 << 16).max(4).min(1 << 16); + let period = period.checked_next_power_of_two().unwrap_or(1 << 16).clamp(4, 1 << 16); let phase = current % period; let quantize_factor = (period >> 12).max(1); let quantized_phase = phase / quantize_factor * quantize_factor; @@ -105,7 +105,7 @@ impl Encode for Era { Self::Immortal => output.push_byte(0), Self::Mortal(period, phase) => { let quantize_factor = (*period as u64 >> 12).max(1); - let encoded = (period.trailing_zeros() - 1).max(1).min(15) as u16 | + let encoded = (period.trailing_zeros() - 1).clamp(1, 15) as u16 | ((phase / quantize_factor) << 4) as u16; encoded.encode_to(output); }, diff --git a/primitives/runtime/src/offchain/storage_lock.rs b/primitives/runtime/src/offchain/storage_lock.rs index 4ea9030745296..47325743bd2f3 100644 --- a/primitives/runtime/src/offchain/storage_lock.rs +++ b/primitives/runtime/src/offchain/storage_lock.rs @@ -77,8 +77,8 @@ const STORAGE_LOCK_DEFAULT_EXPIRY_DURATION: Duration = Duration::from_millis(20_ const STORAGE_LOCK_DEFAULT_EXPIRY_BLOCKS: u32 = 4; /// Time between checks if the lock is still being held in milliseconds. -const STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MIN: Duration = Duration::from_millis(100); -const STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX: Duration = Duration::from_millis(10); +const STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MIN: Duration = Duration::from_millis(10); +const STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX: Duration = Duration::from_millis(100); /// Lockable item for use with a persisted storage lock. /// @@ -137,10 +137,9 @@ impl Lockable for Time { let remainder: Duration = now.diff(deadline); // do not snooze the full duration, but instead snooze max 100ms // it might get unlocked in another thread - use core::cmp::{max, min}; - let snooze = max( - min(remainder, STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX), + let snooze = remainder.clamp( STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MIN, + STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX, ); sp_io::offchain::sleep_until(now.add(snooze)); } @@ -239,10 +238,9 @@ impl Lockable for BlockAndTime { fn snooze(deadline: &Self::Deadline) { let now = offchain::timestamp(); let remainder: Duration = now.diff(&(deadline.timestamp)); - use core::cmp::{max, min}; - let snooze = max( - min(remainder, STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX), + let snooze = remainder.clamp( STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MIN, + STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX, ); sp_io::offchain::sleep_until(now.add(snooze)); } diff --git a/primitives/state-machine/src/in_memory_backend.rs b/primitives/state-machine/src/in_memory_backend.rs index e205e83e85572..06714fb41405a 100644 --- a/primitives/state-machine/src/in_memory_backend.rs +++ b/primitives/state-machine/src/in_memory_backend.rs @@ -157,8 +157,8 @@ where fn from((inners, state_version): (Storage, StateVersion)) -> Self { let mut inner: HashMap, BTreeMap> = inners .children_default - .into_iter() - .map(|(_k, c)| (Some(c.child_info), c.data)) + .into_values() + .map(|c| (Some(c.child_info), c.data)) .collect(); inner.insert(None, inners.top); (inner, state_version).into() diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index ef5c02d2ec1fa..9eb26d52f79f8 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -474,7 +474,7 @@ impl OverlayedChanges { pub fn children( &self, ) -> impl Iterator, &ChildInfo)> { - self.children.iter().map(|(_, v)| (v.0.changes(), &v.1)) + self.children.values().map(|v| (v.0.changes(), &v.1)) } /// Get an iterator over all top changes as been by the current transaction. diff --git a/primitives/trie/src/recorder.rs b/primitives/trie/src/recorder.rs index 5599ad1c36904..6fbf698592a31 100644 --- a/primitives/trie/src/recorder.rs +++ b/primitives/trie/src/recorder.rs @@ -109,7 +109,7 @@ impl Recorder { /// Returns the [`StorageProof`]. pub fn to_storage_proof(&self) -> StorageProof { let recorder = self.inner.lock(); - StorageProof::new(recorder.accessed_nodes.iter().map(|(_, v)| v.clone())) + StorageProof::new(recorder.accessed_nodes.values().cloned()) } /// Returns the estimated encoded size of the proof. diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index fe0fef3516671..99d4e1163e272 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -134,7 +134,7 @@ impl substrate_test_client::GenesisInit for GenesisParameters { .insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.clone()); } - let child_roots = storage.children_default.iter().map(|(_sk, child_content)| { + let child_roots = storage.children_default.values().map(|child_content| { let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( child_content.data.clone().into_iter().collect(), diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index daf4aa74e1394..6e413bdf7e2c5 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -268,9 +268,8 @@ impl PalletCmd { for s in 0..self.steps { // This is the value we will be testing for component `name` - let component_value = ((lowest as f32 + step_size * s as f32) as u32) - .min(highest) - .max(lowest); + let component_value = + ((lowest as f32 + step_size * s as f32) as u32).clamp(lowest, highest); // Select the max value for all the other components. let c: Vec<(BenchmarkParameter, u32)> = components From 281bcd44fca0ff2471bddba3195a88801874dfdb Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Tue, 18 Oct 2022 13:15:40 +0300 Subject: [PATCH 1284/1472] derive Serialize/Deserialize for BeefyAuthoritySet (#12516) --- Cargo.lock | 1 + primitives/beefy/Cargo.toml | 2 ++ primitives/beefy/src/mmr.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 2c1b427f0a2e2..7ea4e3e5c048e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -535,6 +535,7 @@ dependencies = [ "array-bytes", "parity-scale-codec", "scale-info", + "serde", "sp-api", "sp-application-crypto", "sp-core", diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index f85e2edf4f442..22e41b5130abb 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } @@ -32,6 +33,7 @@ default = ["std"] std = [ "codec/std", "scale-info/std", + "serde", "sp-api/std", "sp-application-crypto/std", "sp-core/std", diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 0edb8babd608e..78ceef0b6b396 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -101,6 +101,7 @@ impl MmrLeafVersion { /// Details of a BEEFY authority set. #[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct BeefyAuthoritySet { /// Id of the set. /// From e34b840b8818856a5bb8dbfe91d5b8a918e44fb8 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 18 Oct 2022 14:52:04 +0200 Subject: [PATCH 1285/1472] BlockId removal: refactor: StorageProvider (#12510) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BlockId removal: refactor: StorageProvider It changes the arguments of `Backend::StorageProvider` trait from: block: `BlockId` to: hash: `&Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) * Apply suggestions from code review Co-authored-by: Bastian Köcher * Update client/api/src/backend.rs Co-authored-by: Dmitrii Markin * GrandpaBlockImport::current_set_id reworked * ExportStateCmd reworked * trigger CI job * trigger CI job Co-authored-by: Bastian Köcher Co-authored-by: Dmitrii Markin --- client/api/src/backend.rs | 44 ++++++++--------- client/cli/src/commands/export_state_cmd.rs | 10 ++-- client/finality-grandpa/src/import.rs | 12 +++-- client/rpc/src/state/state_full.rs | 36 ++++++-------- .../service/src/chain_ops/export_raw_state.rs | 15 ++---- client/service/src/client/client.rs | 48 ++++++++----------- client/service/test/src/client/mod.rs | 20 ++++---- .../frame/benchmarking-cli/src/block/bench.rs | 10 ++-- utils/frame/benchmarking-cli/src/block/cmd.rs | 4 +- .../frame/benchmarking-cli/src/storage/cmd.rs | 6 +-- .../benchmarking-cli/src/storage/read.rs | 17 +++---- .../benchmarking-cli/src/storage/write.rs | 10 ++-- 12 files changed, 112 insertions(+), 120 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 0e94d28b75dd5..f358385acd708 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -357,77 +357,77 @@ where /// Provides acess to storage primitives pub trait StorageProvider> { - /// Given a `BlockId` and a key, return the value under the key in that block. + /// Given a block's `Hash` and a key, return the value under the key in that block. fn storage( &self, - id: &BlockId, + hash: &Block::Hash, key: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` and a key prefix, return the matching storage keys in that block. + /// Given a block's `Hash` and a key prefix, return the matching storage keys in that block. fn storage_keys( &self, - id: &BlockId, + hash: &Block::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` and a key, return the value under the hash in that block. + /// Given a block's `Hash` and a key, return the value under the hash in that block. fn storage_hash( &self, - id: &BlockId, + hash: &Block::Hash, key: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` and a key prefix, return the matching child storage keys and values in - /// that block. + /// Given a block's `Hash` and a key prefix, return the matching child storage keys and values + /// in that block. fn storage_pairs( &self, - id: &BlockId, + hash: &Block::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` and a key prefix, return a `KeyIterator` iterates matching storage keys in - /// that block. + /// Given a block's `Hash` and a key prefix, return a `KeyIterator` iterates matching storage + /// keys in that block. fn storage_keys_iter<'a>( &self, - id: &BlockId, + hash: &Block::Hash, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result>; - /// Given a `BlockId`, a key and a child storage key, return the value under the key in that - /// block. + /// Given a block's `Hash`, a key and a child storage key, return the value under the key in + /// that block. fn child_storage( &self, - id: &BlockId, + hash: &Block::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId`, a key prefix, and a child storage key, return the matching child storage - /// keys. + /// Given a block's `Hash`, a key prefix, and a child storage key, return the matching child + /// storage keys. fn child_storage_keys( &self, - id: &BlockId, + hash: &Block::Hash, child_info: &ChildInfo, key_prefix: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` and a key `prefix` and a child storage key, + /// Given a block's `Hash` and a key `prefix` and a child storage key, /// return a `KeyIterator` that iterates matching storage keys in that block. fn child_storage_keys_iter<'a>( &self, - id: &BlockId, + hash: &Block::Hash, child_info: ChildInfo, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result>; - /// Given a `BlockId`, a key and a child storage key, return the hash under the key in that + /// Given a block's `Hash`, a key and a child storage key, return the hash under the key in that /// block. fn child_storage_hash( &self, - id: &BlockId, + hash: &Block::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result>; diff --git a/client/cli/src/commands/export_state_cmd.rs b/client/cli/src/commands/export_state_cmd.rs index 63aa12213b3da..1bcf21f388a62 100644 --- a/client/cli/src/commands/export_state_cmd.rs +++ b/client/cli/src/commands/export_state_cmd.rs @@ -23,7 +23,7 @@ use crate::{ }; use clap::Parser; use log::info; -use sc_client_api::{StorageProvider, UsageProvider}; +use sc_client_api::{HeaderBackend, StorageProvider, UsageProvider}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::{fmt::Debug, io::Write, str::FromStr, sync::Arc}; @@ -57,7 +57,7 @@ impl ExportStateCmd { ) -> error::Result<()> where B: BlockT, - C: UsageProvider + StorageProvider, + C: UsageProvider + StorageProvider + HeaderBackend, BA: sc_client_api::backend::Backend, B::Hash: FromStr, ::Err: Debug, @@ -65,7 +65,11 @@ impl ExportStateCmd { { info!("Exporting raw state..."); let block_id = self.input.as_ref().map(|b| b.parse()).transpose()?; - let raw_state = sc_service::chain_ops::export_raw_state(client, block_id)?; + let hash = match block_id { + Some(id) => client.expect_block_hash_from_id(&id)?, + None => client.usage_info().chain.best_hash, + }; + let raw_state = sc_service::chain_ops::export_raw_state(client, &hash)?; input_spec.set_storage(raw_state); info!("Generating new chain spec..."); diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index b5a0d7be70f19..d0a66888ec072 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -424,13 +424,15 @@ where } /// Read current set id form a given state. - fn current_set_id(&self, id: &BlockId) -> Result { + fn current_set_id(&self, hash: &Block::Hash) -> Result { + let id = &BlockId::hash(*hash); let runtime_version = self.inner.runtime_api().version(id).map_err(|e| { ConsensusError::ClientImport(format!( "Unable to retrieve current runtime version. {}", e )) })?; + if runtime_version .api_version(&>::ID) .map_or(false, |v| v < 3) @@ -439,7 +441,8 @@ where // This code may be removed once warp sync to an old runtime is no longer needed. for prefix in ["GrandpaFinality", "Grandpa"] { let k = [twox_128(prefix.as_bytes()), twox_128(b"CurrentSetId")].concat(); - if let Ok(Some(id)) = self.inner.storage(id, &sc_client_api::StorageKey(k.to_vec())) + if let Ok(Some(id)) = + self.inner.storage(hash, &sc_client_api::StorageKey(k.to_vec())) { if let Ok(id) = SetId::decode(&mut id.0.as_ref()) { return Ok(id) @@ -472,13 +475,12 @@ where // finality proofs and that the state is correct and final. // So we can read the authority list and set id from the state. self.authority_set_hard_forks.clear(); - let block_id = BlockId::hash(hash); let authorities = self .inner .runtime_api() - .grandpa_authorities(&block_id) + .grandpa_authorities(&BlockId::hash(hash)) .map_err(|e| ConsensusError::ClientImport(e.to_string()))?; - let set_id = self.current_set_id(&block_id)?; + let set_id = self.current_set_id(&hash)?; let authority_set = AuthoritySet::new( authorities.clone(), set_id, diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 42ba70b0af7e7..d6ab93f7680b0 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -145,10 +145,9 @@ where ) -> Result<()> { for block_hash in &range.hashes { let mut block_changes = StorageChangeSet { block: *block_hash, changes: Vec::new() }; - let id = BlockId::hash(*block_hash); for key in keys { let (has_changed, data) = { - let curr_data = self.client.storage(&id, key).map_err(client_err)?; + let curr_data = self.client.storage(block_hash, key).map_err(client_err)?; match last_values.get(key) { Some(prev_data) => (curr_data != *prev_data, curr_data), None => (true, curr_data), @@ -214,7 +213,7 @@ where prefix: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage_keys(&BlockId::Hash(block), &prefix)) + .and_then(|block| self.client.storage_keys(&block, &prefix)) .map_err(client_err) } @@ -224,7 +223,7 @@ where prefix: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage_pairs(&BlockId::Hash(block), &prefix)) + .and_then(|block| self.client.storage_pairs(&block, &prefix)) .map_err(client_err) } @@ -237,11 +236,7 @@ where ) -> std::result::Result, Error> { self.block_or_best(block) .and_then(|block| { - self.client.storage_keys_iter( - &BlockId::Hash(block), - prefix.as_ref(), - start_key.as_ref(), - ) + self.client.storage_keys_iter(&block, prefix.as_ref(), start_key.as_ref()) }) .map(|iter| iter.take(count as usize).collect()) .map_err(client_err) @@ -253,7 +248,7 @@ where key: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage(&BlockId::Hash(block), &key)) + .and_then(|block| self.client.storage(&block, &key)) .map_err(client_err) } @@ -267,14 +262,14 @@ where Err(e) => return Err(client_err(e)), }; - match self.client.storage(&BlockId::Hash(block), &key) { + match self.client.storage(&block, &key) { Ok(Some(d)) => return Ok(Some(d.0.len() as u64)), Err(e) => return Err(client_err(e)), Ok(None) => {}, } self.client - .storage_pairs(&BlockId::Hash(block), &key) + .storage_pairs(&block, &key) .map(|kv| { let item_sum = kv.iter().map(|(_, v)| v.0.len() as u64).sum::(); if item_sum > 0 { @@ -292,7 +287,7 @@ where key: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage_hash(&BlockId::Hash(block), &key)) + .and_then(|block| self.client.storage_hash(&block, &key)) .map_err(client_err) } @@ -418,7 +413,7 @@ where let changes = keys .into_iter() .map(|key| { - let v = self.client.storage(&BlockId::Hash(block), &key).ok().flatten(); + let v = self.client.storage(&block, &key).ok().flatten(); (key, v) }) .collect(); @@ -522,7 +517,7 @@ where ChildInfo::new_default(storage_key), None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; - self.client.child_storage_keys(&BlockId::Hash(block), &child_info, &prefix) + self.client.child_storage_keys(&block, &child_info, &prefix) }) .map_err(client_err) } @@ -543,7 +538,7 @@ where None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; self.client.child_storage_keys_iter( - &BlockId::Hash(block), + &block, child_info, prefix.as_ref(), start_key.as_ref(), @@ -566,7 +561,7 @@ where ChildInfo::new_default(storage_key), None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; - self.client.child_storage(&BlockId::Hash(block), &child_info, &key) + self.client.child_storage(&block, &child_info, &key) }) .map_err(client_err) } @@ -589,10 +584,7 @@ where keys.into_iter() .map(move |key| { - client - .clone() - .child_storage(&BlockId::Hash(block), &child_info, &key) - .map_err(client_err) + client.clone().child_storage(&block, &child_info, &key).map_err(client_err) }) .collect() } @@ -610,7 +602,7 @@ where ChildInfo::new_default(storage_key), None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; - self.client.child_storage_hash(&BlockId::Hash(block), &child_info, &key) + self.client.child_storage_hash(&block, &child_info, &key) }) .map_err(client_err) } diff --git a/client/service/src/chain_ops/export_raw_state.rs b/client/service/src/chain_ops/export_raw_state.rs index ffe91d0d7355e..04dba387de908 100644 --- a/client/service/src/chain_ops/export_raw_state.rs +++ b/client/service/src/chain_ops/export_raw_state.rs @@ -19,25 +19,20 @@ use crate::error::Error; use sc_client_api::{StorageProvider, UsageProvider}; use sp_core::storage::{well_known_keys, ChildInfo, Storage, StorageChild, StorageKey, StorageMap}; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use std::{collections::HashMap, sync::Arc}; /// Export the raw state at the given `block`. If `block` is `None`, the /// best block will be used. -pub fn export_raw_state( - client: Arc, - block: Option>, -) -> Result +pub fn export_raw_state(client: Arc, hash: &B::Hash) -> Result where C: UsageProvider + StorageProvider, B: BlockT, BA: sc_client_api::backend::Backend, { - let block = block.unwrap_or_else(|| BlockId::Hash(client.usage_info().chain.best_hash)); - let empty_key = StorageKey(Vec::new()); - let mut top_storage = client.storage_pairs(&block, &empty_key)?; + let mut top_storage = client.storage_pairs(hash, &empty_key)?; let mut children_default = HashMap::new(); // Remove all default child storage roots from the top storage and collect the child storage @@ -52,10 +47,10 @@ where StorageKey(key.0[well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.len()..].to_vec()); let child_info = ChildInfo::new_default(&key.0); - let keys = client.child_storage_keys(&block, &child_info, &empty_key)?; + let keys = client.child_storage_keys(hash, &child_info, &empty_key)?; let mut pairs = StorageMap::new(); keys.into_iter().try_for_each(|k| { - if let Some(value) = client.child_storage(&block, &child_info, &k)? { + if let Some(value) = client.child_storage(hash, &child_info, &k)? { pairs.insert(k.0, value.0); } diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index e2fd5cda1d2f0..a7851af446b95 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -420,7 +420,8 @@ where /// Get the code at a given block. pub fn code_at(&self, id: &BlockId) -> sp_blockchain::Result> { - Ok(StorageProvider::storage(self, id, &StorageKey(well_known_keys::CODE.to_vec()))? + let hash = self.backend.blockchain().expect_block_hash_from_id(id)?; + Ok(StorageProvider::storage(self, &hash, &StorageKey(well_known_keys::CODE.to_vec()))? .expect( "None is returned if there's no value stored for the given key;\ ':code' key is always defined; qed", @@ -1402,21 +1403,19 @@ where { fn storage_keys( &self, - id: &BlockId, + hash: &Block::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; - let keys = self.state_at(&hash)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); + let keys = self.state_at(hash)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); Ok(keys) } fn storage_pairs( &self, - id: &BlockId, + hash: &::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; - let state = self.state_at(&hash)?; + let state = self.state_at(hash)?; let keys = state .keys(&key_prefix.0) .into_iter() @@ -1430,37 +1429,34 @@ where fn storage_keys_iter<'a>( &self, - id: &BlockId, + hash: &::Hash, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result> { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; - let state = self.state_at(&hash)?; + let state = self.state_at(hash)?; let start_key = start_key.or(prefix).map(|key| key.0.clone()).unwrap_or_else(Vec::new); Ok(KeyIterator::new(state, prefix, start_key)) } fn child_storage_keys_iter<'a>( &self, - id: &BlockId, + hash: &::Hash, child_info: ChildInfo, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result> { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; - let state = self.state_at(&hash)?; + let state = self.state_at(hash)?; let start_key = start_key.or(prefix).map(|key| key.0.clone()).unwrap_or_else(Vec::new); Ok(KeyIterator::new_child(state, child_info, prefix, start_key)) } fn storage( &self, - id: &BlockId, + hash: &Block::Hash, key: &StorageKey, ) -> sp_blockchain::Result> { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; Ok(self - .state_at(&hash)? + .state_at(hash)? .storage(&key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? .map(StorageData)) @@ -1468,24 +1464,22 @@ where fn storage_hash( &self, - id: &BlockId, + hash: &::Hash, key: &StorageKey, ) -> sp_blockchain::Result> { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; - self.state_at(&hash)? + self.state_at(hash)? .storage_hash(&key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } fn child_storage_keys( &self, - id: &BlockId, + hash: &::Hash, child_info: &ChildInfo, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; let keys = self - .state_at(&hash)? + .state_at(hash)? .child_keys(child_info, &key_prefix.0) .into_iter() .map(StorageKey) @@ -1495,13 +1489,12 @@ where fn child_storage( &self, - id: &BlockId, + hash: &::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; Ok(self - .state_at(&hash)? + .state_at(hash)? .child_storage(child_info, &key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? .map(StorageData)) @@ -1509,12 +1502,11 @@ where fn child_storage_hash( &self, - id: &BlockId, + hash: &::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; - self.state_at(&hash)? + self.state_at(hash)? .child_storage_hash(child_info, &key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index c6ac1fc7d73d9..4a5b56bd14006 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1602,12 +1602,14 @@ fn storage_keys_iter_prefix_and_start_key_works() { .add_extra_child_storage(&child_info, b"third".to_vec(), vec![0u8; 32]) .build(); + let block_hash = client.info().best_hash; + let child_root = b":child_storage:default:child".to_vec(); let prefix = StorageKey(array_bytes::hex2bytes_unchecked("3a")); let child_prefix = StorageKey(b"sec".to_vec()); let res: Vec<_> = client - .storage_keys_iter(&BlockId::Number(0), Some(&prefix), None) + .storage_keys_iter(&block_hash, Some(&prefix), None) .unwrap() .map(|x| x.0) .collect(); @@ -1622,7 +1624,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { let res: Vec<_> = client .storage_keys_iter( - &BlockId::Number(0), + &block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))), ) @@ -1633,7 +1635,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { let res: Vec<_> = client .storage_keys_iter( - &BlockId::Number(0), + &block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a686561707061676573"))), ) @@ -1643,7 +1645,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { assert_eq!(res, Vec::>::new()); let res: Vec<_> = client - .child_storage_keys_iter(&BlockId::Number(0), child_info.clone(), Some(&child_prefix), None) + .child_storage_keys_iter(&block_hash, child_info.clone(), Some(&child_prefix), None) .unwrap() .map(|x| x.0) .collect(); @@ -1651,7 +1653,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { let res: Vec<_> = client .child_storage_keys_iter( - &BlockId::Number(0), + &block_hash, child_info, None, Some(&StorageKey(b"second".to_vec())), @@ -1666,10 +1668,12 @@ fn storage_keys_iter_prefix_and_start_key_works() { fn storage_keys_iter_works() { let client = substrate_test_runtime_client::new(); + let block_hash = client.info().best_hash; + let prefix = StorageKey(array_bytes::hex2bytes_unchecked("")); let res: Vec<_> = client - .storage_keys_iter(&BlockId::Number(0), Some(&prefix), None) + .storage_keys_iter(&block_hash, Some(&prefix), None) .unwrap() .take(9) .map(|x| array_bytes::bytes2hex("", &x.0)) @@ -1691,7 +1695,7 @@ fn storage_keys_iter_works() { let res: Vec<_> = client .storage_keys_iter( - &BlockId::Number(0), + &block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))), ) @@ -1714,7 +1718,7 @@ fn storage_keys_iter_works() { let res: Vec<_> = client .storage_keys_iter( - &BlockId::Number(0), + &block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked( "7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa", diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index 318c58de8a553..47cd047e158d0 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -22,7 +22,9 @@ use frame_support::weights::constants::WEIGHT_PER_NANOS; use frame_system::ConsumedWeight; use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; use sc_cli::{Error, Result}; -use sc_client_api::{Backend as ClientBackend, BlockBackend, StorageProvider, UsageProvider}; +use sc_client_api::{ + Backend as ClientBackend, BlockBackend, HeaderBackend, StorageProvider, UsageProvider, +}; use sp_api::{ApiExt, Core, HeaderT, ProvideRuntimeApi}; use sp_blockchain::Error::RuntimeApiError; use sp_runtime::{generic::BlockId, traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; @@ -73,7 +75,8 @@ where + ProvideRuntimeApi + StorageProvider + UsageProvider - + BlockBackend, + + BlockBackend + + HeaderBackend, C::Api: ApiExt + BlockBuilderApi, { /// Returns a new [`Self`] from the arguments. @@ -136,9 +139,10 @@ where )?; let key = StorageKey(hash); + let block_hash = self.client.expect_block_hash_from_id(block)?; let mut raw_weight = &self .client - .storage(&block, &key)? + .storage(&block_hash, &key)? .ok_or(format!("Could not find System::BlockWeight for block: {}", block))? .0[..]; diff --git a/utils/frame/benchmarking-cli/src/block/cmd.rs b/utils/frame/benchmarking-cli/src/block/cmd.rs index f5f7e15a316b3..8bac04110f7ab 100644 --- a/utils/frame/benchmarking-cli/src/block/cmd.rs +++ b/utils/frame/benchmarking-cli/src/block/cmd.rs @@ -22,6 +22,7 @@ use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; use sc_client_api::{Backend as ClientBackend, BlockBackend, StorageProvider, UsageProvider}; use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_blockchain::HeaderBackend; use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; use clap::Parser; @@ -87,7 +88,8 @@ impl BlockCmd { + BlockBackend + ProvideRuntimeApi + StorageProvider - + UsageProvider, + + UsageProvider + + HeaderBackend, C::Api: ApiExt + BlockBuilderApi, { // Put everything in the benchmark type to have the generic types handy. diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index 86041d9517de6..32fd5da7f95f0 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -191,9 +191,9 @@ impl StorageCmd { B: BlockT + Debug, BA: ClientBackend, { - let block = BlockId::Hash(client.usage_info().chain.best_hash); + let hash = client.usage_info().chain.best_hash; let empty_prefix = StorageKey(Vec::new()); - let mut keys = client.storage_keys(&block, &empty_prefix)?; + let mut keys = client.storage_keys(&hash, &empty_prefix)?; let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); @@ -201,7 +201,7 @@ impl StorageCmd { info!("Warmup round {}/{}", i + 1, self.params.warmups); for key in keys.as_slice() { let _ = client - .storage(&block, &key) + .storage(&hash, &key) .expect("Checked above to exist") .ok_or("Value unexpectedly empty"); } diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs index 5e8a310ea5c5a..2df7e697039e8 100644 --- a/utils/frame/benchmarking-cli/src/storage/read.rs +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -18,10 +18,7 @@ use sc_cli::Result; use sc_client_api::{Backend as ClientBackend, StorageProvider, UsageProvider}; use sp_core::storage::StorageKey; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT}, -}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use log::info; use rand::prelude::*; @@ -41,12 +38,12 @@ impl StorageCmd { <::Header as HeaderT>::Number: From, { let mut record = BenchRecord::default(); - let block = BlockId::Hash(client.usage_info().chain.best_hash); + let best_hash = client.usage_info().chain.best_hash; - info!("Preparing keys from block {}", block); + info!("Preparing keys from block {}", best_hash); // Load all keys and randomly shuffle them. let empty_prefix = StorageKey(Vec::new()); - let mut keys = client.storage_keys(&block, &empty_prefix)?; + let mut keys = client.storage_keys(&best_hash, &empty_prefix)?; let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); @@ -58,7 +55,7 @@ impl StorageCmd { match (self.params.include_child_trees, self.is_child_key(key.clone().0)) { (true, Some(info)) => { // child tree key - let child_keys = client.child_storage_keys(&block, &info, &empty_prefix)?; + let child_keys = client.child_storage_keys(&best_hash, &info, &empty_prefix)?; for ck in child_keys { child_nodes.push((ck.clone(), info.clone())); } @@ -67,7 +64,7 @@ impl StorageCmd { // regular key let start = Instant::now(); let v = client - .storage(&block, &key) + .storage(&best_hash, &key) .expect("Checked above to exist") .ok_or("Value unexpectedly empty")?; record.append(v.0.len(), start.elapsed())?; @@ -82,7 +79,7 @@ impl StorageCmd { for (key, info) in child_nodes.as_slice() { let start = Instant::now(); let v = client - .child_storage(&block, info, key) + .child_storage(&best_hash, info, key) .expect("Checked above to exist") .ok_or("Value unexpectedly empty")?; record.append(v.0.len(), start.elapsed())?; diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index 0ef2a2f9ae113..2ee37a5619136 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -57,12 +57,12 @@ impl StorageCmd { // Store the time that it took to write each value. let mut record = BenchRecord::default(); - let block = BlockId::Hash(client.usage_info().chain.best_hash); - let header = client.header(block)?.ok_or("Header not found")?; + let best_hash = client.usage_info().chain.best_hash; + let header = client.header(BlockId::Hash(best_hash))?.ok_or("Header not found")?; let original_root = *header.state_root(); let trie = DbStateBuilder::::new(storage.clone(), original_root).build(); - info!("Preparing keys from block {}", block); + info!("Preparing keys from block {}", best_hash); // Load all KV pairs and randomly shuffle them. let mut kvs = trie.pairs(); let (mut rng, _) = new_rng(None); @@ -77,7 +77,7 @@ impl StorageCmd { match (self.params.include_child_trees, self.is_child_key(k.to_vec())) { (true, Some(info)) => { let child_keys = - client.child_storage_keys_iter(&block, info.clone(), None, None)?; + client.child_storage_keys_iter(&best_hash, info.clone(), None, None)?; for ck in child_keys { child_nodes.push((ck.clone(), info.clone())); } @@ -124,7 +124,7 @@ impl StorageCmd { for (key, info) in child_nodes { if let Some(original_v) = client - .child_storage(&block, &info.clone(), &key) + .child_storage(&best_hash, &info.clone(), &key) .expect("Checked above to exist") { let mut new_v = vec![0; original_v.0.len()]; From 487ac5cf3958380a15b5edc599c13ddbb62e76b1 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 18 Oct 2022 17:41:19 +0200 Subject: [PATCH 1286/1472] Use `ArgAction::Set` for enable-offchain-indexing flag (#12521) * Use ArgAction::Set for enable-offchain-indexing * Provide default value for `enable-offchain-indexing` --- client/cli/src/params/offchain_worker_params.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cli/src/params/offchain_worker_params.rs b/client/cli/src/params/offchain_worker_params.rs index 8cff48fad600c..a660320fde255 100644 --- a/client/cli/src/params/offchain_worker_params.rs +++ b/client/cli/src/params/offchain_worker_params.rs @@ -23,7 +23,7 @@ //! targeted at handling input parameter parsing providing //! a reasonable abstraction. -use clap::Args; +use clap::{ArgAction, Args}; use sc_network::config::Role; use sc_service::config::OffchainWorkerConfig; @@ -48,7 +48,7 @@ pub struct OffchainWorkerParams { /// /// Enables a runtime to write directly to a offchain workers /// DB during block import. - #[arg(long = "enable-offchain-indexing", value_name = "ENABLE_OFFCHAIN_INDEXING")] + #[arg(long = "enable-offchain-indexing", value_name = "ENABLE_OFFCHAIN_INDEXING", default_value_t = false, action = ArgAction::Set)] pub indexing_enabled: bool, } From 49734dd1d72a00b9d3b87ba397661a63e0e17af3 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 18 Oct 2022 18:39:19 +0200 Subject: [PATCH 1287/1472] frame/utils: introduce `substrate-rpc-client` crate for RPC utils (#12212) * hack together a PoC * Update utils/frame/rpc-utils/Cargo.toml Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update utils/frame/rpc-utils/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * rpc_utils -> substrate_rpc_client * try runtime: remove keep connection * make CI happy * cargo fmt * fix ci * update lock file * fix * fix Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: kianenigma --- Cargo.lock | 20 +- Cargo.toml | 1 + bin/node/cli/Cargo.toml | 2 +- bin/node/cli/tests/common.rs | 9 +- frame/bags-list/remote-tests/src/migration.rs | 11 +- frame/bags-list/remote-tests/src/snapshot.rs | 12 +- frame/bags-list/remote-tests/src/try_state.rs | 11 +- frame/state-trie-migration/src/lib.rs | 11 +- utils/frame/remote-externalities/Cargo.toml | 4 +- utils/frame/remote-externalities/src/lib.rs | 137 ++++----- .../frame/remote-externalities/src/rpc_api.rs | 149 ---------- utils/frame/rpc/client/Cargo.toml | 25 ++ utils/frame/rpc/client/src/lib.rs | 265 ++++++++++++++++++ utils/frame/try-runtime/cli/Cargo.toml | 2 +- .../cli/src/commands/execute_block.rs | 20 +- .../cli/src/commands/follow_chain.rs | 236 ++-------------- .../cli/src/commands/offchain_worker.rs | 9 +- .../cli/src/commands/on_runtime_upgrade.rs | 1 + utils/frame/try-runtime/cli/src/lib.rs | 9 +- 19 files changed, 437 insertions(+), 497 deletions(-) delete mode 100644 utils/frame/remote-externalities/src/rpc_api.rs create mode 100644 utils/frame/rpc/client/Cargo.toml create mode 100644 utils/frame/rpc/client/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 7ea4e3e5c048e..397846693e907 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4503,7 +4503,6 @@ dependencies = [ "platforms", "rand 0.8.5", "regex", - "remote-externalities", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", @@ -4551,6 +4550,7 @@ dependencies = [ "sp-trie", "substrate-build-script-utils", "substrate-frame-cli", + "substrate-rpc-client", "tempfile", "tokio", "try-runtime-cli", @@ -7278,7 +7278,6 @@ version = "0.10.0-dev" dependencies = [ "env_logger", "frame-support", - "jsonrpsee", "log", "pallet-elections-phragmen", "parity-scale-codec", @@ -7288,6 +7287,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-version", + "substrate-rpc-client", "tokio", ] @@ -10349,6 +10349,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "substrate-rpc-client" +version = "0.10.0-dev" +dependencies = [ + "async-trait", + "jsonrpsee", + "log", + "sc-rpc-api", + "serde", + "sp-core", + "sp-runtime", + "tokio", +] + [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" @@ -11028,7 +11042,6 @@ version = "0.10.0-dev" dependencies = [ "clap 4.0.11", "frame-try-runtime", - "jsonrpsee", "log", "parity-scale-codec", "remote-externalities", @@ -11045,6 +11058,7 @@ dependencies = [ "sp-state-machine", "sp-version", "sp-weights", + "substrate-rpc-client", "tokio", "zstd", ] diff --git a/Cargo.toml b/Cargo.toml index e203cbbee7e0d..d3c801fc2c7be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -232,6 +232,7 @@ members = [ "utils/frame/rpc/system", "utils/frame/generate-bags", "utils/frame/generate-bags/node-runtime", + "utils/frame/rpc/client", "utils/prometheus", "utils/wasm-builder", ] diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 25e7ef095ed3e..4bf991f49320c 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -132,7 +132,7 @@ soketto = "0.7.1" criterion = { version = "0.3.5", features = ["async_tokio"] } tokio = { version = "1.17.0", features = ["macros", "time", "parking_lot"] } wait-timeout = "0.2" -remote-externalities = { path = "../../../utils/frame/remote-externalities" } +substrate-rpc-client = { path = "../../../utils/frame/rpc/client" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } [build-dependencies] diff --git a/bin/node/cli/tests/common.rs b/bin/node/cli/tests/common.rs index 3b83f4339611d..358c09779d59a 100644 --- a/bin/node/cli/tests/common.rs +++ b/bin/node/cli/tests/common.rs @@ -23,8 +23,7 @@ use nix::{ sys::signal::{kill, Signal::SIGINT}, unistd::Pid, }; -use node_primitives::Block; -use remote_externalities::rpc_api::RpcService; +use node_primitives::{Hash, Header}; use std::{ io::{BufRead, BufReader, Read}, ops::{Deref, DerefMut}, @@ -69,12 +68,14 @@ pub async fn wait_n_finalized_blocks( /// Wait for at least n blocks to be finalized from a specified node pub async fn wait_n_finalized_blocks_from(n: usize, url: &str) { + use substrate_rpc_client::{ws_client, ChainApi}; + let mut built_blocks = std::collections::HashSet::new(); let mut interval = tokio::time::interval(Duration::from_secs(2)); - let rpc_service = RpcService::new(url, false).await.unwrap(); + let rpc = ws_client(url).await.unwrap(); loop { - if let Ok(block) = rpc_service.get_finalized_head::().await { + if let Ok(block) = ChainApi::<(), Hash, Header, ()>::finalized_head(&rpc).await { built_blocks.insert(block); if built_blocks.len() > n { break diff --git a/frame/bags-list/remote-tests/src/migration.rs b/frame/bags-list/remote-tests/src/migration.rs index 675dfbe072670..b013472b4c90e 100644 --- a/frame/bags-list/remote-tests/src/migration.rs +++ b/frame/bags-list/remote-tests/src/migration.rs @@ -24,14 +24,15 @@ use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; /// Test voter bags migration. `currency_unit` is the number of planks per the the runtimes `UNITS` /// (i.e. number of decimal places per DOT, KSM etc) -pub async fn execute< - Runtime: RuntimeT, - Block: BlockT + DeserializeOwned, ->( +pub async fn execute( currency_unit: u64, currency_name: &'static str, ws_url: String, -) { +) where + Runtime: RuntimeT, + Block: BlockT, + Block::Header: DeserializeOwned, +{ let mut ext = Builder::::new() .mode(Mode::Online(OnlineConfig { transport: ws_url.to_string().into(), diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index 655de10c4af9b..cfe065924bd92 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -22,14 +22,12 @@ use remote_externalities::{Builder, Mode, OnlineConfig}; use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; /// Execute create a snapshot from pallet-staking. -pub async fn execute< +pub async fn execute(voter_limit: Option, currency_unit: u64, ws_url: String) +where Runtime: crate::RuntimeT, - Block: BlockT + DeserializeOwned, ->( - voter_limit: Option, - currency_unit: u64, - ws_url: String, -) { + Block: BlockT, + Block::Header: DeserializeOwned, +{ use frame_support::storage::generator::StorageMap; let mut ext = Builder::::new() diff --git a/frame/bags-list/remote-tests/src/try_state.rs b/frame/bags-list/remote-tests/src/try_state.rs index 9817ef4ceb9e4..d3fb63f045a64 100644 --- a/frame/bags-list/remote-tests/src/try_state.rs +++ b/frame/bags-list/remote-tests/src/try_state.rs @@ -25,14 +25,15 @@ use remote_externalities::{Builder, Mode, OnlineConfig}; use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; /// Execute the sanity check of the bags-list. -pub async fn execute< - Runtime: crate::RuntimeT, - Block: BlockT + DeserializeOwned, ->( +pub async fn execute( currency_unit: u64, currency_name: &'static str, ws_url: String, -) { +) where + Runtime: crate::RuntimeT, + Block: BlockT, + Block::Header: DeserializeOwned, +{ let mut ext = Builder::::new() .mode(Mode::Online(OnlineConfig { transport: ws_url.to_string().into(), diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 3f81d3c211a95..5255d4f6f3800 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -1640,13 +1640,12 @@ pub(crate) mod remote_tests { /// /// This will print some very useful statistics, make sure [`crate::LOG_TARGET`] is enabled. #[allow(dead_code)] - pub(crate) async fn run_with_limits< + pub(crate) async fn run_with_limits(limits: MigrationLimits, mode: Mode) + where Runtime: crate::Config, - Block: BlockT + serde::de::DeserializeOwned, - >( - limits: MigrationLimits, - mode: Mode, - ) { + Block: BlockT, + Block::Header: serde::de::DeserializeOwned, + { let mut ext = remote_externalities::Builder::::new() .mode(mode) .state_version(sp_core::storage::StateVersion::V0) diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 3121157df68d8..3d7471bf4d680 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" -description = "An externalities provided environemnt that can load itself from remote nodes or cache files" +description = "An externalities provided environment that can load itself from remote nodes or cached files" readme = "README.md" [package.metadata.docs.rs] @@ -15,7 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } env_logger = "0.9" -jsonrpsee = { version = "0.15.1", features = ["ws-client", "macros"] } log = "0.4.17" serde = "1.0.136" serde_json = "1.0" @@ -24,6 +23,7 @@ sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-io = { version = "6.0.0", path = "../../../primitives/io" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-version = { version = "5.0.0", path = "../../../primitives/version" } +substrate-rpc-client = { path = "../rpc/client" } [dev-dependencies] tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 83481e745f5ee..86cfc767bf3b5 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -22,13 +22,6 @@ use codec::{Decode, Encode}; -use jsonrpsee::{ - core::{client::ClientT, Error as RpcError}, - proc_macros::rpc, - rpc_params, - ws_client::{WsClient, WsClientBuilder}, -}; - use log::*; use serde::de::DeserializeOwned; use sp_core::{ @@ -46,8 +39,7 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; - -pub mod rpc_api; +use substrate_rpc_client::{rpc_params, ws_client, ChainApi, ClientT, StateApi, WsClient}; type KeyValue = (StorageKey, StorageData); type TopKeyValues = Vec; @@ -58,40 +50,6 @@ const DEFAULT_TARGET: &str = "wss://rpc.polkadot.io:443"; const BATCH_SIZE: usize = 1000; const PAGE: u32 = 1000; -#[rpc(client)] -pub trait RpcApi { - #[method(name = "childstate_getKeys")] - fn child_get_keys( - &self, - child_key: PrefixedStorageKey, - prefix: StorageKey, - hash: Option, - ) -> Result, RpcError>; - - #[method(name = "childstate_getStorage")] - fn child_get_storage( - &self, - child_key: PrefixedStorageKey, - prefix: StorageKey, - hash: Option, - ) -> Result; - - #[method(name = "state_getStorage")] - fn get_storage(&self, prefix: StorageKey, hash: Option) -> Result; - - #[method(name = "state_getKeysPaged")] - fn get_keys_paged( - &self, - prefix: Option, - count: u32, - start_key: Option, - hash: Option, - ) -> Result, RpcError>; - - #[method(name = "chain_getFinalizedHead")] - fn finalized_head(&self) -> Result; -} - /// The execution mode. #[derive(Clone)] pub enum Mode { @@ -140,14 +98,10 @@ impl Transport { if let Self::Uri(uri) = self { log::debug!(target: LOG_TARGET, "initializing remote client to {:?}", uri); - let ws_client = WsClientBuilder::default() - .max_request_body_size(u32::MAX) - .build(&uri) - .await - .map_err(|e| { - log::error!(target: LOG_TARGET, "error: {:?}", e); - "failed to build ws client" - })?; + let ws_client = ws_client(uri).await.map_err(|e| { + log::error!(target: LOG_TARGET, "error: {:?}", e); + "failed to build ws client" + })?; *self = Self::RemoteClient(Arc::new(ws_client)) } @@ -258,7 +212,7 @@ pub struct Builder { // NOTE: ideally we would use `DefaultNoBound` here, but not worth bringing in frame-support for // that. -impl Default for Builder { +impl Default for Builder { fn default() -> Self { Self { mode: Default::default(), @@ -272,7 +226,7 @@ impl Default for Builder { } // Mode methods -impl Builder { +impl Builder { fn as_online(&self) -> &OnlineConfig { match &self.mode { Mode::Online(config) => config, @@ -291,26 +245,38 @@ impl Builder { } // RPC methods -impl Builder { +impl Builder +where + B::Hash: DeserializeOwned, + B::Header: DeserializeOwned, +{ async fn rpc_get_storage( &self, key: StorageKey, maybe_at: Option, ) -> Result { trace!(target: LOG_TARGET, "rpc: get_storage"); - self.as_online().rpc_client().get_storage(key, maybe_at).await.map_err(|e| { - error!(target: LOG_TARGET, "Error = {:?}", e); - "rpc get_storage failed." - }) + match self.as_online().rpc_client().storage(key, maybe_at).await { + Ok(Some(res)) => Ok(res), + Ok(None) => Err("get_storage not found"), + Err(e) => { + error!(target: LOG_TARGET, "Error = {:?}", e); + Err("rpc get_storage failed.") + }, + } } /// Get the latest finalized head. async fn rpc_get_head(&self) -> Result { trace!(target: LOG_TARGET, "rpc: finalized_head"); - self.as_online().rpc_client().finalized_head().await.map_err(|e| { - error!(target: LOG_TARGET, "Error = {:?}", e); - "rpc finalized_head failed." - }) + + // sadly this pretty much unreadable... + ChainApi::<(), _, B::Header, ()>::finalized_head(self.as_online().rpc_client()) + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Error = {:?}", e); + "rpc finalized_head failed." + }) } /// Get all the keys at `prefix` at `hash` using the paged, safe RPC methods. @@ -325,7 +291,7 @@ impl Builder { let page = self .as_online() .rpc_client() - .get_keys_paged(Some(prefix.clone()), PAGE, last_key.clone(), Some(at)) + .storage_keys_paged(Some(prefix.clone()), PAGE, last_key.clone(), Some(at)) .await .map_err(|e| { error!(target: LOG_TARGET, "Error = {:?}", e); @@ -471,19 +437,19 @@ impl Builder { child_prefix: StorageKey, at: B::Hash, ) -> Result, &'static str> { - let child_keys = self - .as_online() - .rpc_client() - .child_get_keys( - PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), - child_prefix, - Some(at), - ) - .await - .map_err(|e| { - error!(target: LOG_TARGET, "Error = {:?}", e); - "rpc child_get_keys failed." - })?; + // This is deprecated and will generate a warning which causes the CI to fail. + #[allow(warnings)] + let child_keys = substrate_rpc_client::ChildStateApi::storage_keys( + self.as_online().rpc_client(), + PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), + child_prefix, + Some(at), + ) + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Error = {:?}", e); + "rpc child_get_keys failed." + })?; debug!( target: LOG_TARGET, @@ -497,7 +463,11 @@ impl Builder { } // Internal methods -impl Builder { +impl Builder +where + B::Hash: DeserializeOwned, + B::Header: DeserializeOwned, +{ /// Save the given data to the top keys snapshot. fn save_top_snapshot(&self, data: &[KeyValue], path: &PathBuf) -> Result<(), &'static str> { let mut path = path.clone(); @@ -726,12 +696,13 @@ impl Builder { let child_kv = match self.mode.clone() { Mode::Online(_) => self.load_child_remote_and_maybe_save(&top_kv).await?, - Mode::OfflineOrElseOnline(offline_config, _) => + Mode::OfflineOrElseOnline(offline_config, _) => { if let Ok(kv) = self.load_child_snapshot(&offline_config.state_snapshot.path) { kv } else { self.load_child_remote_and_maybe_save(&top_kv).await? - }, + } + }, Mode::Offline(ref config) => self .load_child_snapshot(&config.state_snapshot.path) .map_err(|why| { @@ -749,7 +720,7 @@ impl Builder { } // Public methods -impl Builder { +impl Builder { /// Create a new builder. pub fn new() -> Self { Default::default() @@ -824,7 +795,13 @@ impl Builder { } self } +} +// Public methods +impl Builder +where + B::Header: DeserializeOwned, +{ /// Build the test externalities. pub async fn build(self) -> Result { let state_version = self.state_version; diff --git a/utils/frame/remote-externalities/src/rpc_api.rs b/utils/frame/remote-externalities/src/rpc_api.rs deleted file mode 100644 index 3ea30a30221a2..0000000000000 --- a/utils/frame/remote-externalities/src/rpc_api.rs +++ /dev/null @@ -1,149 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! WS RPC API for one off RPC calls to a substrate node. -// TODO: Consolidate one off RPC calls https://github.com/paritytech/substrate/issues/8988 - -use jsonrpsee::{ - core::client::{Client, ClientT}, - rpc_params, - types::ParamsSer, - ws_client::{WsClient, WsClientBuilder}, -}; -use serde::de::DeserializeOwned; -use sp_runtime::{generic::SignedBlock, traits::Block as BlockT}; -use std::sync::Arc; - -enum RpcCall { - GetHeader, - GetFinalizedHead, - GetBlock, - GetRuntimeVersion, -} - -impl RpcCall { - fn as_str(&self) -> &'static str { - match self { - RpcCall::GetHeader => "chain_getHeader", - RpcCall::GetFinalizedHead => "chain_getFinalizedHead", - RpcCall::GetBlock => "chain_getBlock", - RpcCall::GetRuntimeVersion => "state_getRuntimeVersion", - } - } -} - -/// General purpose method for making RPC calls. -async fn make_request<'a, T: DeserializeOwned>( - client: &Arc, - call: RpcCall, - params: Option>, -) -> Result { - client - .request::(call.as_str(), params) - .await - .map_err(|e| format!("{} request failed: {:?}", call.as_str(), e)) -} - -enum ConnectionPolicy { - Reuse(Arc), - Reconnect, -} - -/// Simple RPC service that is capable of keeping the connection. -/// -/// Service will connect to `uri` for the first time already during initialization. -/// -/// Be careful with reusing the connection in a multithreaded environment. -pub struct RpcService { - uri: String, - policy: ConnectionPolicy, -} - -impl RpcService { - /// Creates a new RPC service. If `keep_connection`, then connects to `uri` right away. - pub async fn new>(uri: S, keep_connection: bool) -> Result { - let policy = if keep_connection { - ConnectionPolicy::Reuse(Arc::new(Self::build_client(uri.as_ref()).await?)) - } else { - ConnectionPolicy::Reconnect - }; - Ok(Self { uri: uri.as_ref().to_string(), policy }) - } - - /// Returns the address at which requests are sent. - pub fn uri(&self) -> String { - self.uri.clone() - } - - /// Build a websocket client that connects to `self.uri`. - async fn build_client>(uri: S) -> Result { - WsClientBuilder::default() - .max_request_body_size(u32::MAX) - .build(uri) - .await - .map_err(|e| format!("`WsClientBuilder` failed to build: {:?}", e)) - } - - /// Generic method for making RPC requests. - async fn make_request<'a, T: DeserializeOwned>( - &self, - call: RpcCall, - params: Option>, - ) -> Result { - match self.policy { - // `self.keep_connection` must have been `true`. - ConnectionPolicy::Reuse(ref client) => make_request(client, call, params).await, - ConnectionPolicy::Reconnect => { - let client = Arc::new(Self::build_client(&self.uri).await?); - make_request(&client, call, params).await - }, - } - } - - /// Get the header of the block identified by `at`. - pub async fn get_header(&self, at: Block::Hash) -> Result - where - Block: BlockT, - Block::Header: DeserializeOwned, - { - self.make_request(RpcCall::GetHeader, rpc_params!(at)).await - } - - /// Get the finalized head. - pub async fn get_finalized_head(&self) -> Result { - self.make_request(RpcCall::GetFinalizedHead, None).await - } - - /// Get the signed block identified by `at`. - pub async fn get_block( - &self, - at: Block::Hash, - ) -> Result { - Ok(self - .make_request::>(RpcCall::GetBlock, rpc_params!(at)) - .await? - .block) - } - - /// Get the runtime version of a given chain. - pub async fn get_runtime_version( - &self, - at: Option, - ) -> Result { - self.make_request(RpcCall::GetRuntimeVersion, rpc_params!(at)).await - } -} diff --git a/utils/frame/rpc/client/Cargo.toml b/utils/frame/rpc/client/Cargo.toml new file mode 100644 index 0000000000000..80aa60f199f1f --- /dev/null +++ b/utils/frame/rpc/client/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "substrate-rpc-client" +version = "0.10.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Shared JSON-RPC client" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +jsonrpsee = { version = "0.15.1", features = ["ws-client"] } +sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } +async-trait = "0.1.57" +serde = "1" +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +log = "0.4" + +[dev-dependencies] +tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread", "sync"] } +sp-core = { path = "../../../../primitives/core" } \ No newline at end of file diff --git a/utils/frame/rpc/client/src/lib.rs b/utils/frame/rpc/client/src/lib.rs new file mode 100644 index 0000000000000..254cc193c0e67 --- /dev/null +++ b/utils/frame/rpc/client/src/lib.rs @@ -0,0 +1,265 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Shared JSON-RPC client related code and abstractions. +//! +//! It exposes a `WebSocket JSON-RPC` client that implements the RPC interface in [`sc-rpc-api`] +//! along with some abstractions. +//! +//! ## Usage +//! +//! ```no_run +//! # use substrate_rpc_client::{ws_client, StateApi}; +//! # use sp_core::{H256, storage::StorageKey}; +//! +//! #[tokio::main] +//! async fn main() { +//! +//! let client = ws_client("ws://127.0.0.1:9944").await.unwrap(); +//! client.storage(StorageKey(vec![]), Some(H256::zero())).await.unwrap(); +//! +//! // if all type params are not known you need to provide type params +//! StateApi::::storage(&client, StorageKey(vec![]), None).await.unwrap(); +//! } +//! ``` + +use async_trait::async_trait; +use serde::de::DeserializeOwned; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; +use std::collections::VecDeque; + +pub use jsonrpsee::{ + core::client::{ClientT, Subscription, SubscriptionClientT}, + rpc_params, + ws_client::{WsClient, WsClientBuilder}, +}; +pub use sc_rpc_api::{ + author::AuthorApiClient as AuthorApi, chain::ChainApiClient as ChainApi, + child_state::ChildStateApiClient as ChildStateApi, dev::DevApiClient as DevApi, + offchain::OffchainApiClient as OffchainApi, state::StateApiClient as StateApi, + system::SystemApiClient as SystemApi, +}; + +/// Create a new `WebSocket` connection with shared settings. +pub async fn ws_client(uri: impl AsRef) -> Result { + WsClientBuilder::default() + .max_request_body_size(u32::MAX) + .request_timeout(std::time::Duration::from_secs(60 * 10)) + .connection_timeout(std::time::Duration::from_secs(60)) + .max_notifs_per_subscription(1024) + .build(uri) + .await + .map_err(|e| format!("`WsClientBuilder` failed to build: {:?}", e)) +} + +/// Abstraction over RPC calling for headers. +#[async_trait] +pub trait HeaderProvider +where + Block::Header: HeaderT, +{ + /// Awaits for the header of the block with hash `hash`. + async fn get_header(&self, hash: Block::Hash) -> Block::Header; +} + +#[async_trait] +impl HeaderProvider for WsClient +where + Block::Header: DeserializeOwned, +{ + async fn get_header(&self, hash: Block::Hash) -> Block::Header { + ChainApi::<(), Block::Hash, Block::Header, ()>::header(self, Some(hash)) + .await + .unwrap() + .unwrap() + } +} + +/// Abstraction over RPC subscription for finalized headers. +#[async_trait] +pub trait HeaderSubscription +where + Block::Header: HeaderT, +{ + /// Await for the next finalized header from the subscription. + /// + /// Returns `None` if either the subscription has been closed or there was an error when reading + /// an object from the client. + async fn next_header(&mut self) -> Option; +} + +#[async_trait] +impl HeaderSubscription for Subscription +where + Block::Header: DeserializeOwned, +{ + async fn next_header(&mut self) -> Option { + match self.next().await { + Some(Ok(header)) => Some(header), + None => { + log::warn!("subscription closed"); + None + }, + Some(Err(why)) => { + log::warn!("subscription returned error: {:?}. Probably decoding has failed.", why); + None + }, + } + } +} + +/// Stream of all finalized headers. +/// +/// Returned headers are guaranteed to be ordered. There are no missing headers (even if some of +/// them lack justification). +pub struct FinalizedHeaders< + 'a, + Block: BlockT, + HP: HeaderProvider, + HS: HeaderSubscription, +> { + header_provider: &'a HP, + subscription: HS, + fetched_headers: VecDeque, + last_returned: Option<::Hash>, +} + +impl<'a, Block: BlockT, HP: HeaderProvider, HS: HeaderSubscription> + FinalizedHeaders<'a, Block, HP, HS> +where + ::Header: DeserializeOwned, +{ + pub fn new(header_provider: &'a HP, subscription: HS) -> Self { + Self { + header_provider, + subscription, + fetched_headers: VecDeque::new(), + last_returned: None, + } + } + + /// Reads next finalized header from the subscription. If some headers (without justification) + /// have been skipped, fetches them as well. Returns number of headers that have been fetched. + /// + /// All fetched headers are stored in `self.fetched_headers`. + async fn fetch(&mut self) -> usize { + let last_finalized = match self.subscription.next_header().await { + Some(header) => header, + None => return 0, + }; + + self.fetched_headers.push_front(last_finalized.clone()); + + let mut last_finalized_parent = *last_finalized.parent_hash(); + let last_returned = self.last_returned.unwrap_or(last_finalized_parent); + + while last_finalized_parent != last_returned { + let parent_header = self.header_provider.get_header(last_finalized_parent).await; + self.fetched_headers.push_front(parent_header.clone()); + last_finalized_parent = *parent_header.parent_hash(); + } + + self.fetched_headers.len() + } + + /// Get the next finalized header. + pub async fn next(&mut self) -> Option { + if self.fetched_headers.is_empty() { + self.fetch().await; + } + + if let Some(header) = self.fetched_headers.pop_front() { + self.last_returned = Some(header.hash()); + Some(header) + } else { + None + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_runtime::testing::{Block as TBlock, ExtrinsicWrapper, Header, H256}; + use std::sync::Arc; + use tokio::sync::Mutex; + + type Block = TBlock>; + type BlockNumber = u64; + type Hash = H256; + + struct MockHeaderProvider(pub Arc>>); + + fn headers() -> Vec

{ + let mut headers = vec![Header::new_from_number(0)]; + for n in 1..11 { + headers.push(Header { + parent_hash: headers.last().unwrap().hash(), + ..Header::new_from_number(n) + }) + } + headers + } + + #[async_trait] + impl HeaderProvider for MockHeaderProvider { + async fn get_header(&self, _hash: Hash) -> Header { + let height = self.0.lock().await.pop_front().unwrap(); + headers()[height as usize].clone() + } + } + + struct MockHeaderSubscription(pub VecDeque); + + #[async_trait] + impl HeaderSubscription for MockHeaderSubscription { + async fn next_header(&mut self) -> Option
{ + self.0.pop_front().map(|h| headers()[h as usize].clone()) + } + } + + #[tokio::test] + async fn finalized_headers_works_when_every_block_comes_from_subscription() { + let heights = vec![4, 5, 6, 7]; + + let provider = MockHeaderProvider(Default::default()); + let subscription = MockHeaderSubscription(heights.clone().into()); + let mut headers = FinalizedHeaders::new(&provider, subscription); + + for h in heights { + assert_eq!(h, headers.next().await.unwrap().number); + } + assert_eq!(None, headers.next().await); + } + + #[tokio::test] + async fn finalized_headers_come_from_subscription_and_provider_if_in_need() { + let all_heights = 3..11; + let heights_in_subscription = vec![3, 4, 6, 10]; + // Consecutive headers will be requested in the reversed order. + let heights_not_in_subscription = vec![5, 9, 8, 7]; + + let provider = MockHeaderProvider(Arc::new(Mutex::new(heights_not_in_subscription.into()))); + let subscription = MockHeaderSubscription(heights_in_subscription.into()); + let mut headers = FinalizedHeaders::new(&provider, subscription); + + for h in all_heights { + assert_eq!(h, headers.next().await.unwrap().number); + } + assert_eq!(None, headers.next().await); + } +} diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 8a9d5a5f8979a..24d64d4aa4373 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -19,7 +19,6 @@ parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = { version = "0.11.2", default-features = false } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } -jsonrpsee = { version = "0.15.1", default-features = false, features = ["ws-client"] } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } @@ -33,6 +32,7 @@ sp-state-machine = { version = "0.12.0", path = "../../../../primitives/state-ma sp-version = { version = "5.0.0", path = "../../../../primitives/version" } sp-weights = { version = "4.0.0", path = "../../../../primitives/weights" } frame-try-runtime = { path = "../../../../frame/try-runtime" } +substrate-rpc-client = { path = "../../rpc/client" } [dev-dependencies] tokio = "1.17.0" diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index df8c51b5a92d4..56d88b9cb8919 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -20,11 +20,11 @@ use crate::{ state_machine_call_with_proof, SharedParams, State, LOG_TARGET, }; use parity_scale_codec::Encode; -use remote_externalities::rpc_api; use sc_service::{Configuration, NativeExecutionDispatch}; use sp_core::storage::well_known_keys; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use std::{fmt::Debug, str::FromStr}; +use substrate_rpc_client::{ws_client, ChainApi}; /// Configurations of the [`Command::ExecuteBlock`]. /// @@ -84,10 +84,11 @@ pub struct ExecuteBlockCmd { impl ExecuteBlockCmd { async fn block_at(&self, ws_uri: String) -> sc_cli::Result where - Block::Hash: FromStr, + Block::Hash: FromStr + serde::de::DeserializeOwned, ::Err: Debug, + Block::Header: serde::de::DeserializeOwned, { - let rpc_service = rpc_api::RpcService::new(ws_uri, false).await?; + let rpc = ws_client(&ws_uri).await?; match (&self.block_at, &self.state) { (Some(block_at), State::Snap { .. }) => hash_of::(block_at), @@ -100,7 +101,9 @@ impl ExecuteBlockCmd { target: LOG_TARGET, "No --block-at or --at provided, using the latest finalized block instead" ); - rpc_service.get_finalized_head::().await.map_err(Into::into) + ChainApi::<(), Block::Hash, Block::Header, ()>::finalized_head(&rpc) + .await + .map_err(|e| e.to_string().into()) }, (None, State::Live { at: Some(at), .. }) => hash_of::(at), _ => { @@ -137,6 +140,8 @@ where Block: BlockT + serde::de::DeserializeOwned, Block::Hash: FromStr, ::Err: Debug, + Block::Hash: serde::de::DeserializeOwned, + Block::Header: serde::de::DeserializeOwned, NumberFor: FromStr, as FromStr>::Err: Debug, ExecDispatch: NativeExecutionDispatch + 'static, @@ -146,8 +151,11 @@ where let block_ws_uri = command.block_ws_uri::(); let block_at = command.block_at::(block_ws_uri.clone()).await?; - let rpc_service = rpc_api::RpcService::new(block_ws_uri.clone(), false).await?; - let block: Block = rpc_service.get_block::(block_at).await?; + let rpc = ws_client(&block_ws_uri).await?; + let block: Block = ChainApi::<(), Block::Hash, Block::Header, _>::block(&rpc, Some(block_at)) + .await + .unwrap() + .unwrap(); let parent_hash = block.header().parent_hash(); log::info!( target: LOG_TARGET, diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index df6d40b2b8ab1..1cc371c8f22fd 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -19,22 +19,15 @@ use crate::{ build_executor, ensure_matching_spec, extract_code, full_extensions, local_spec, parse, state_machine_call_with_proof, SharedParams, LOG_TARGET, }; -use jsonrpsee::{ - core::{ - async_trait, - client::{Client, Subscription, SubscriptionClientT}, - }, - ws_client::WsClientBuilder, -}; use parity_scale_codec::{Decode, Encode}; -use remote_externalities::{rpc_api::RpcService, Builder, Mode, OnlineConfig}; +use remote_externalities::{Builder, Mode, OnlineConfig}; use sc_executor::NativeExecutionDispatch; use sc_service::Configuration; -use serde::de::DeserializeOwned; +use serde::{de::DeserializeOwned, Serialize}; use sp_core::H256; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; -use sp_weights::Weight; -use std::{collections::VecDeque, fmt::Debug, str::FromStr}; +use std::{fmt::Debug, str::FromStr}; +use substrate_rpc_client::{ws_client, ChainApi, FinalizedHeaders, Subscription, WsClient}; const SUB: &str = "chain_subscribeFinalizedHeads"; const UN_SUB: &str = "chain_unsubscribeFinalizedHeads"; @@ -71,144 +64,19 @@ pub struct FollowChainCmd { /// /// Returns a pair `(client, subscription)` - `subscription` alone will be useless, because it /// relies on the related alive `client`. -async fn start_subscribing( +async fn start_subscribing( url: &str, -) -> sc_cli::Result<(Client, Subscription
)> { - let client = WsClientBuilder::default() - .connection_timeout(std::time::Duration::new(20, 0)) - .max_notifs_per_subscription(1024) - .max_request_body_size(u32::MAX) - .build(url) - .await - .map_err(|e| sc_cli::Error::Application(e.into()))?; +) -> sc_cli::Result<(WsClient, Subscription
)> { + let client = ws_client(url).await.map_err(|e| sc_cli::Error::Application(e.into()))?; log::info!(target: LOG_TARGET, "subscribing to {:?} / {:?}", SUB, UN_SUB); - let sub = client - .subscribe(SUB, None, UN_SUB) + let sub = ChainApi::<(), (), Header, ()>::subscribe_finalized_heads(&client) .await .map_err(|e| sc_cli::Error::Application(e.into()))?; Ok((client, sub)) } -/// Abstraction over RPC calling for headers. -#[async_trait] -trait HeaderProvider -where - Block::Header: HeaderT, -{ - /// Awaits for the header of the block with hash `hash`. - async fn get_header(&self, hash: Block::Hash) -> Block::Header; -} - -#[async_trait] -impl HeaderProvider for RpcService -where - Block::Header: DeserializeOwned, -{ - async fn get_header(&self, hash: Block::Hash) -> Block::Header { - self.get_header::(hash).await.unwrap() - } -} - -/// Abstraction over RPC subscription for finalized headers. -#[async_trait] -trait HeaderSubscription -where - Block::Header: HeaderT, -{ - /// Await for the next finalized header from the subscription. - /// - /// Returns `None` if either the subscription has been closed or there was an error when reading - /// an object from the client. - async fn next_header(&mut self) -> Option; -} - -#[async_trait] -impl HeaderSubscription for Subscription -where - Block::Header: DeserializeOwned, -{ - async fn next_header(&mut self) -> Option { - match self.next().await { - Some(Ok(header)) => Some(header), - None => { - log::warn!("subscription closed"); - None - }, - Some(Err(why)) => { - log::warn!("subscription returned error: {:?}. Probably decoding has failed.", why); - None - }, - } - } -} - -/// Stream of all finalized headers. -/// -/// Returned headers are guaranteed to be ordered. There are no missing headers (even if some of -/// them lack justification). -struct FinalizedHeaders<'a, Block: BlockT, HP: HeaderProvider, HS: HeaderSubscription> -{ - header_provider: &'a HP, - subscription: HS, - fetched_headers: VecDeque, - last_returned: Option<::Hash>, -} - -impl<'a, Block: BlockT, HP: HeaderProvider, HS: HeaderSubscription> - FinalizedHeaders<'a, Block, HP, HS> -where - ::Header: DeserializeOwned, -{ - pub fn new(header_provider: &'a HP, subscription: HS) -> Self { - Self { - header_provider, - subscription, - fetched_headers: VecDeque::new(), - last_returned: None, - } - } - - /// Reads next finalized header from the subscription. If some headers (without justification) - /// have been skipped, fetches them as well. Returns number of headers that have been fetched. - /// - /// All fetched headers are stored in `self.fetched_headers`. - async fn fetch(&mut self) -> usize { - let last_finalized = match self.subscription.next_header().await { - Some(header) => header, - None => return 0, - }; - - self.fetched_headers.push_front(last_finalized.clone()); - - let mut last_finalized_parent = *last_finalized.parent_hash(); - let last_returned = self.last_returned.unwrap_or(last_finalized_parent); - - while last_finalized_parent != last_returned { - let parent_header = self.header_provider.get_header(last_finalized_parent).await; - self.fetched_headers.push_front(parent_header.clone()); - last_finalized_parent = *parent_header.parent_hash(); - } - - self.fetched_headers.len() - } - - /// Get the next finalized header. - pub async fn next(&mut self) -> Option { - if self.fetched_headers.is_empty() { - self.fetch().await; - } - - if let Some(header) = self.fetched_headers.pop_front() { - self.last_returned = Some(header.hash()); - Some(header) - } else { - None - } - } -} - pub(crate) async fn follow_chain( shared: SharedParams, command: FollowChainCmd, @@ -224,22 +92,23 @@ where ExecDispatch: NativeExecutionDispatch + 'static, { let mut maybe_state_ext = None; - let (_client, subscription) = start_subscribing::(&command.uri).await?; + let (rpc, subscription) = start_subscribing::(&command.uri).await?; let (code_key, code) = extract_code(&config.chain_spec)?; let executor = build_executor::(&shared, &config); let execution = shared.execution; - let rpc_service = RpcService::new(&command.uri, command.keep_connection).await?; - - let mut finalized_headers: FinalizedHeaders> = - FinalizedHeaders::new(&rpc_service, subscription); + let mut finalized_headers: FinalizedHeaders = + FinalizedHeaders::new(&rpc, subscription); while let Some(header) = finalized_headers.next().await { let hash = header.hash(); let number = header.number(); - let block = rpc_service.get_block::(hash).await.unwrap(); + let block: Block = ChainApi::<(), Block::Hash, Block::Header, _>::block(&rpc, Some(hash)) + .await + .unwrap() + .unwrap(); log::debug!( target: LOG_TARGET, @@ -295,7 +164,7 @@ where full_extensions(), )?; - let consumed_weight = ::decode(&mut &*encoded_result) + let consumed_weight = ::decode(&mut &*encoded_result) .map_err(|e| format!("failed to decode weight: {:?}", e))?; let storage_changes = changes @@ -326,76 +195,3 @@ where log::error!(target: LOG_TARGET, "ws subscription must have terminated."); Ok(()) } - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::testing::{Block as TBlock, ExtrinsicWrapper, Header}; - use std::sync::Arc; - use tokio::sync::Mutex; - - type Block = TBlock>; - type BlockNumber = u64; - type Hash = H256; - - struct MockHeaderProvider(pub Arc>>); - - fn headers() -> Vec
{ - let mut headers = vec![Header::new_from_number(0)]; - for n in 1..11 { - headers.push(Header { - parent_hash: headers.last().unwrap().hash(), - ..Header::new_from_number(n) - }) - } - headers - } - - #[async_trait] - impl HeaderProvider for MockHeaderProvider { - async fn get_header(&self, _hash: Hash) -> Header { - let height = self.0.lock().await.pop_front().unwrap(); - headers()[height as usize].clone() - } - } - - struct MockHeaderSubscription(pub VecDeque); - - #[async_trait] - impl HeaderSubscription for MockHeaderSubscription { - async fn next_header(&mut self) -> Option
{ - self.0.pop_front().map(|h| headers()[h as usize].clone()) - } - } - - #[tokio::test] - async fn finalized_headers_works_when_every_block_comes_from_subscription() { - let heights = vec![4, 5, 6, 7]; - - let provider = MockHeaderProvider(Default::default()); - let subscription = MockHeaderSubscription(heights.clone().into()); - let mut headers = FinalizedHeaders::new(&provider, subscription); - - for h in heights { - assert_eq!(h, headers.next().await.unwrap().number); - } - assert_eq!(None, headers.next().await); - } - - #[tokio::test] - async fn finalized_headers_come_from_subscription_and_provider_if_in_need() { - let all_heights = 3..11; - let heights_in_subscription = vec![3, 4, 6, 10]; - // Consecutive headers will be requested in the reversed order. - let heights_not_in_subscription = vec![5, 9, 8, 7]; - - let provider = MockHeaderProvider(Arc::new(Mutex::new(heights_not_in_subscription.into()))); - let subscription = MockHeaderSubscription(heights_in_subscription.into()); - let mut headers = FinalizedHeaders::new(&provider, subscription); - - for h in all_heights { - assert_eq!(h, headers.next().await.unwrap().number); - } - assert_eq!(None, headers.next().await); - } -} diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index 6f48d1f8f68a7..8d2585372b4a8 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -20,12 +20,12 @@ use crate::{ parse, state_machine_call, SharedParams, State, LOG_TARGET, }; use parity_scale_codec::Encode; -use remote_externalities::rpc_api; use sc_executor::NativeExecutionDispatch; use sc_service::Configuration; use sp_core::storage::well_known_keys; use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; use std::{fmt::Debug, str::FromStr}; +use substrate_rpc_client::{ws_client, ChainApi}; /// Configurations of the [`Command::OffchainWorker`]. #[derive(Debug, Clone, clap::Parser)] @@ -117,8 +117,11 @@ where let header_at = command.header_at::()?; let header_ws_uri = command.header_ws_uri::(); - let rpc_service = rpc_api::RpcService::new(header_ws_uri.clone(), false).await?; - let header = rpc_service.get_header::(header_at).await?; + let rpc = ws_client(&header_ws_uri).await?; + let header = ChainApi::<(), Block::Hash, Block::Header, ()>::header(&rpc, Some(header_at)) + .await + .unwrap() + .unwrap(); log::info!( target: LOG_TARGET, "fetched header from {:?}, block number: {:?}", diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 5e11123526532..fba34ddfb5060 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -45,6 +45,7 @@ where Block: BlockT + serde::de::DeserializeOwned, Block::Hash: FromStr, ::Err: Debug, + Block::Header: serde::de::DeserializeOwned, NumberFor: FromStr, as FromStr>::Err: Debug, ExecDispatch: NativeExecutionDispatch + 'static, diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 9034f356a9f67..0732c8618fc15 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -267,8 +267,7 @@ use parity_scale_codec::Decode; use remote_externalities::{ - rpc_api::RpcService, Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, - TestExternalities, + Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, TestExternalities, }; use sc_chain_spec::ChainSpec; use sc_cli::{ @@ -297,6 +296,7 @@ use sp_runtime::{ use sp_state_machine::{OverlayedChanges, StateMachine, TrieBackendBuilder}; use sp_version::StateVersion; use std::{fmt::Debug, path::PathBuf, str::FromStr}; +use substrate_rpc_client::{ws_client, StateApi}; mod commands; pub(crate) mod parse; @@ -633,9 +633,8 @@ pub(crate) async fn ensure_matching_spec( expected_spec_version: u32, relaxed: bool, ) { - let rpc_service = RpcService::new(uri.clone(), false).await.unwrap(); - match rpc_service - .get_runtime_version::(None) + let rpc = ws_client(&uri).await.unwrap(); + match StateApi::::runtime_version(&rpc, None) .await .map(|version| (String::from(version.spec_name.clone()), version.spec_version)) .map(|(spec_name, spec_version)| (spec_name.to_lowercase(), spec_version)) From e791929a7b95b10f80ae0340bebd21de1e6bcf08 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 19 Oct 2022 12:13:57 +0200 Subject: [PATCH 1288/1472] BlockId removal: refactor: ProofProvider (#12519) * BlockId removal: refactor: ProofProvider It changes the arguments of methods of `ProofProvider` trait from: block: `BlockId` to: hash: `&Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) * LightClientRequestHandler: excessive BlockIdTo bound removed * imports cleanup * formatting * args tyeps cleanup --- client/api/src/proof_provider.rs | 16 ++-- .../src/light_client_requests/handler.rs | 76 +++++++++---------- .../network/sync/src/state_request_handler.rs | 6 +- client/rpc/src/state/state_full.rs | 4 +- client/service/src/client/client.rs | 22 +++--- 5 files changed, 57 insertions(+), 67 deletions(-) diff --git a/client/api/src/proof_provider.rs b/client/api/src/proof_provider.rs index 3aad4af1befb5..4ddbf883b83f2 100644 --- a/client/api/src/proof_provider.rs +++ b/client/api/src/proof_provider.rs @@ -18,7 +18,7 @@ //! Proof utilities use crate::{CompactProof, StorageProof}; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use sp_state_machine::{KeyValueStates, KeyValueStorageLevel}; use sp_storage::ChildInfo; @@ -27,7 +27,7 @@ pub trait ProofProvider { /// Reads storage value at a given block + key, returning read proof. fn read_proof( &self, - id: &BlockId, + hash: &Block::Hash, keys: &mut dyn Iterator, ) -> sp_blockchain::Result; @@ -35,7 +35,7 @@ pub trait ProofProvider { /// read proof. fn read_child_proof( &self, - id: &BlockId, + hash: &Block::Hash, child_info: &ChildInfo, keys: &mut dyn Iterator, ) -> sp_blockchain::Result; @@ -46,12 +46,12 @@ pub trait ProofProvider { /// No changes are made. fn execution_proof( &self, - id: &BlockId, + hash: &Block::Hash, method: &str, call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)>; - /// Given a `BlockId` iterate over all storage values starting at `start_keys`. + /// Given a `Hash` iterate over all storage values starting at `start_keys`. /// Last `start_keys` element contains last accessed key value. /// With multiple `start_keys`, first `start_keys` element is /// the current storage key of of the last accessed child trie. @@ -61,12 +61,12 @@ pub trait ProofProvider { /// Returns combined proof and the numbers of collected keys. fn read_proof_collection( &self, - id: &BlockId, + hash: &Block::Hash, start_keys: &[Vec], size_limit: usize, ) -> sp_blockchain::Result<(CompactProof, u32)>; - /// Given a `BlockId` iterate over all storage values starting at `start_key`. + /// Given a `Hash` iterate over all storage values starting at `start_key`. /// Returns collected keys and values. /// Returns the collected keys values content of the top trie followed by the /// collected keys values of child tries. @@ -76,7 +76,7 @@ pub trait ProofProvider { /// end. fn storage_collection( &self, - id: &BlockId, + hash: &Block::Hash, start_key: &[Vec], size_limit: usize, ) -> sp_blockchain::Result>; diff --git a/client/network/light/src/light_client_requests/handler.rs b/client/network/light/src/light_client_requests/handler.rs index 9dc02eb9ff291..7156545fbd9aa 100644 --- a/client/network/light/src/light_client_requests/handler.rs +++ b/client/network/light/src/light_client_requests/handler.rs @@ -38,7 +38,7 @@ use sp_core::{ hexdisplay::HexDisplay, storage::{ChildInfo, ChildType, PrefixedStorageKey}, }; -use sp_runtime::{generic::BlockId, traits::Block}; +use sp_runtime::traits::Block; use std::{marker::PhantomData, sync::Arc}; const LOG_TARGET: &str = "light-client-request-handler"; @@ -172,26 +172,22 @@ where let block = Decode::decode(&mut request.block.as_ref())?; - let response = - match self - .client - .execution_proof(&BlockId::Hash(block), &request.method, &request.data) - { - Ok((_, proof)) => { - let r = schema::v1::light::RemoteCallResponse { proof: proof.encode() }; - Some(schema::v1::light::response::Response::RemoteCallResponse(r)) - }, - Err(e) => { - trace!( - "remote call request from {} ({} at {:?}) failed with: {}", - peer, - request.method, - request.block, - e, - ); - None - }, - }; + let response = match self.client.execution_proof(&block, &request.method, &request.data) { + Ok((_, proof)) => { + let r = schema::v1::light::RemoteCallResponse { proof: proof.encode() }; + Some(schema::v1::light::response::Response::RemoteCallResponse(r)) + }, + Err(e) => { + trace!( + "remote call request from {} ({} at {:?}) failed with: {}", + peer, + request.method, + request.block, + e, + ); + None + }, + }; Ok(schema::v1::light::Response { response }) } @@ -215,25 +211,23 @@ where let block = Decode::decode(&mut request.block.as_ref())?; - let response = match self - .client - .read_proof(&BlockId::Hash(block), &mut request.keys.iter().map(AsRef::as_ref)) - { - Ok(proof) => { - let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; - Some(schema::v1::light::response::Response::RemoteReadResponse(r)) - }, - Err(error) => { - trace!( - "remote read request from {} ({} at {:?}) failed with: {}", - peer, - fmt_keys(request.keys.first(), request.keys.last()), - request.block, - error, - ); - None - }, - }; + let response = + match self.client.read_proof(&block, &mut request.keys.iter().map(AsRef::as_ref)) { + Ok(proof) => { + let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; + Some(schema::v1::light::response::Response::RemoteReadResponse(r)) + }, + Err(error) => { + trace!( + "remote read request from {} ({} at {:?}) failed with: {}", + peer, + fmt_keys(request.keys.first(), request.keys.last()), + request.block, + error, + ); + None + }, + }; Ok(schema::v1::light::Response { response }) } @@ -265,7 +259,7 @@ where }; let response = match child_info.and_then(|child_info| { self.client.read_child_proof( - &BlockId::Hash(block), + &block, &child_info, &mut request.keys.iter().map(AsRef::as_ref), ) diff --git a/client/network/sync/src/state_request_handler.rs b/client/network/sync/src/state_request_handler.rs index abbbcad2e378f..0a369c998dbd7 100644 --- a/client/network/sync/src/state_request_handler.rs +++ b/client/network/sync/src/state_request_handler.rs @@ -32,7 +32,7 @@ use sc_network_common::{ config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, }; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use std::{ hash::{Hash, Hasher}, sync::Arc, @@ -205,14 +205,14 @@ where if !request.no_proof { let (proof, _count) = self.client.read_proof_collection( - &BlockId::hash(block), + &block, request.start.as_slice(), MAX_RESPONSE_BYTES, )?; response.proof = proof.encode(); } else { let entries = self.client.storage_collection( - &BlockId::hash(block), + &block, request.start.as_slice(), MAX_RESPONSE_BYTES, )?; diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index d6ab93f7680b0..44e7d03bc1a0e 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -345,7 +345,7 @@ where self.block_or_best(block) .and_then(|block| { self.client - .read_proof(&BlockId::Hash(block), &mut keys.iter().map(|key| key.0.as_ref())) + .read_proof(&block, &mut keys.iter().map(|key| key.0.as_ref())) .map(|proof| proof.iter_nodes().map(|node| node.into()).collect()) .map(|proof| ReadProof { at: block, proof }) }) @@ -494,7 +494,7 @@ where }; self.client .read_child_proof( - &BlockId::Hash(block), + &block, &child_info, &mut keys.iter().map(|key| key.0.as_ref()), ) diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index a7851af446b95..a12b7177db47c 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1152,42 +1152,39 @@ where { fn read_proof( &self, - id: &BlockId, + hash: &Block::Hash, keys: &mut dyn Iterator, ) -> sp_blockchain::Result { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; - self.state_at(&hash) + self.state_at(hash) .and_then(|state| prove_read(state, keys).map_err(Into::into)) } fn read_child_proof( &self, - id: &BlockId, + hash: &Block::Hash, child_info: &ChildInfo, keys: &mut dyn Iterator, ) -> sp_blockchain::Result { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; - self.state_at(&hash) + self.state_at(hash) .and_then(|state| prove_child_read(state, child_info, keys).map_err(Into::into)) } fn execution_proof( &self, - id: &BlockId, + hash: &Block::Hash, method: &str, call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)> { - self.executor.prove_execution(id, method, call_data) + self.executor.prove_execution(&BlockId::Hash(*hash), method, call_data) } fn read_proof_collection( &self, - id: &BlockId, + hash: &Block::Hash, start_key: &[Vec], size_limit: usize, ) -> sp_blockchain::Result<(CompactProof, u32)> { - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; - let state = self.state_at(&hash)?; + let state = self.state_at(hash)?; // this is a read proof, using version V0 or V1 is equivalent. let root = state.storage_root(std::iter::empty(), StateVersion::V0).0; @@ -1202,14 +1199,13 @@ where fn storage_collection( &self, - id: &BlockId, + hash: &Block::Hash, start_key: &[Vec], size_limit: usize, ) -> sp_blockchain::Result> { if start_key.len() > MAX_NESTED_TRIE_DEPTH { return Err(Error::Backend("Invalid start key.".to_string())) } - let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; let state = self.state_at(&hash)?; let child_info = |storage_key: &Vec| -> sp_blockchain::Result { let storage_key = PrefixedStorageKey::new_ref(storage_key); From 07e1b6d72747f3cde49e85e4ff68ff158daebe16 Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Wed, 19 Oct 2022 14:29:20 +0100 Subject: [PATCH 1289/1472] registrar: Avoid freebies in provide_judgement (#12465) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * evaluate repatriate reserved error in pallet identity * fix benchmarks * add repatriate reserved error test * benchmark fix * undo lock * include balance to use for benchmarks * rename test * Update frame/identity/src/benchmarking.rs * Update frame/identity/src/benchmarking.rs Co-authored-by: Bastian Köcher --- frame/identity/src/benchmarking.rs | 19 ++++++++++++++++--- frame/identity/src/lib.rs | 7 +++++-- frame/identity/src/tests.rs | 25 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index c628387a4d22e..3584eb954b399 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -144,9 +144,14 @@ benchmarks! { // User requests judgement from all the registrars, and they approve for i in 0..r { + let registrar: T::AccountId = account("registrar", i, SEED); + let registrar_lookup = T::Lookup::unlookup(registrar.clone()); + let balance_to_use = T::Currency::minimum_balance() * 10u32.into(); + let _ = T::Currency::make_free_balance_be(®istrar, balance_to_use); + Identity::::request_judgement(caller_origin.clone(), i, 10u32.into())?; Identity::::provide_judgement( - RawOrigin::Signed(account("registrar", i, SEED)).into(), + RawOrigin::Signed(registrar).into(), i, caller_lookup.clone(), Judgement::Reasonable, @@ -213,9 +218,13 @@ benchmarks! { // User requests judgement from all the registrars, and they approve for i in 0..r { + let registrar: T::AccountId = account("registrar", i, SEED); + let balance_to_use = T::Currency::minimum_balance() * 10u32.into(); + let _ = T::Currency::make_free_balance_be(®istrar, balance_to_use); + Identity::::request_judgement(caller_origin.clone(), i, 10u32.into())?; Identity::::provide_judgement( - RawOrigin::Signed(account("registrar", i, SEED)).into(), + RawOrigin::Signed(registrar).into(), i, caller_lookup.clone(), Judgement::Reasonable, @@ -362,9 +371,13 @@ benchmarks! { // User requests judgement from all the registrars, and they approve for i in 0..r { + let registrar: T::AccountId = account("registrar", i, SEED); + let balance_to_use = T::Currency::minimum_balance() * 10u32.into(); + let _ = T::Currency::make_free_balance_be(®istrar, balance_to_use); + Identity::::request_judgement(target_origin.clone(), i, 10u32.into())?; Identity::::provide_judgement( - RawOrigin::Signed(account("registrar", i, SEED)).into(), + RawOrigin::Signed(registrar).into(), i, target_lookup.clone(), Judgement::Reasonable, diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 8b22ecedaec19..95f5a84d8abb7 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -238,6 +238,8 @@ pub mod pallet { NotOwned, /// The provided judgement was for a different identity. JudgementForDifferentIdentity, + /// Error that occurs when there is an issue paying for judgement. + JudgementPaymentFailed, } #[pallet::event] @@ -788,12 +790,13 @@ pub mod pallet { match id.judgements.binary_search_by_key(®_index, |x| x.0) { Ok(position) => { if let Judgement::FeePaid(fee) = id.judgements[position].1 { - let _ = T::Currency::repatriate_reserved( + T::Currency::repatriate_reserved( &target, &sender, fee, BalanceStatus::Free, - ); + ) + .map_err(|_| Error::::JudgementPaymentFailed)?; } id.judgements[position] = item }, diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 20628da50937a..6b0006971f0e6 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -540,6 +540,31 @@ fn requesting_judgement_should_work() { }); } +#[test] +fn provide_judgement_should_return_judgement_payment_failed_error() { + new_test_ext().execute_with(|| { + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); + // 10 for the judgement request, 10 for the identity. + assert_eq!(Balances::free_balance(10), 80); + + // This forces judgement payment failed error + Balances::make_free_balance_be(&3, 0); + assert_noop!( + Identity::provide_judgement( + RuntimeOrigin::signed(3), + 0, + 10, + Judgement::Erroneous, + BlakeTwo256::hash_of(&ten()) + ), + Error::::JudgementPaymentFailed + ); + }); +} + #[test] fn field_deposit_should_work() { new_test_ext().execute_with(|| { From 076be6d28cbe3acea5a67d668f1cf545d5c13064 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 19 Oct 2022 21:05:27 +0100 Subject: [PATCH 1290/1472] EPM: allow duplicate submissions (#12237) * allow for duplicate signed submissions * Fix a bunch of things, seems all good now * fmt * Fix * Update frame/election-provider-multi-phase/src/signed.rs Co-authored-by: Niklas Adolfsson * Update frame/election-provider-multi-phase/src/signed.rs Co-authored-by: Niklas Adolfsson * add migratin * fmt * comment typo * some review comments * fix bench Co-authored-by: Niklas Adolfsson Co-authored-by: Ross Bulat --- .../src/benchmarking.rs | 17 +- .../election-provider-multi-phase/src/lib.rs | 12 +- .../src/migrations.rs | 78 +++++ .../election-provider-multi-phase/src/mock.rs | 6 + .../src/signed.rs | 284 ++++++++++++------ 5 files changed, 293 insertions(+), 104 deletions(-) create mode 100644 frame/election-provider-multi-phase/src/migrations.rs diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index a8195df7305ff..a0fd0a9a0512f 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -320,21 +320,14 @@ frame_benchmarking::benchmarks! { } submit { - // the solution will be worse than all of them meaning the score need to be checked against - // ~ log2(c) - let solution = RawSolution { - score: ElectionScore { minimal_stake: 10_000_000u128 - 1, ..Default::default() }, - ..Default::default() - }; - + // the queue is full and the solution is only better than the worse. >::create_snapshot().map_err(<&str>::from)?; MultiPhase::::on_initialize_open_signed(); >::put(1); let mut signed_submissions = SignedSubmissions::::get(); - // Insert `max - 1` submissions because the call to `submit` will insert another - // submission and the score is worse then the previous scores. + // Insert `max` submissions for i in 0..(T::SignedMaxSubmissions::get() - 1) { let raw_solution = RawSolution { score: ElectionScore { minimal_stake: 10_000_000u128 + (i as u128), ..Default::default() }, @@ -350,6 +343,12 @@ frame_benchmarking::benchmarks! { } signed_submissions.put(); + // this score will eject the weakest one. + let solution = RawSolution { + score: ElectionScore { minimal_stake: 10_000_000u128 + 1, ..Default::default() }, + ..Default::default() + }; + let caller = frame_benchmarking::whitelisted_caller(); let deposit = MultiPhase::::deposit_for( &solution, diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 3dc6161bb202a..3e5a6d12f575c 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -267,6 +267,7 @@ pub mod helpers; const LOG_TARGET: &str = "runtime::election-provider"; +pub mod migrations; pub mod signed; pub mod unsigned; pub mod weights; @@ -1265,8 +1266,8 @@ pub mod pallet { #[pallet::storage] pub type SignedSubmissionNextIndex = StorageValue<_, u32, ValueQuery>; - /// A sorted, bounded set of `(score, index)`, where each `index` points to a value in - /// `SignedSubmissions`. + /// A sorted, bounded vector of `(score, block_number, index)`, where each `index` points to a + /// value in `SignedSubmissions`. /// /// We never need to process more than a single signed submission at a time. Signed submissions /// can be quite large, so we're willing to pay the cost of multiple database accesses to access @@ -1296,9 +1297,14 @@ pub mod pallet { #[pallet::getter(fn minimum_untrusted_score)] pub type MinimumUntrustedScore = StorageValue<_, ElectionScore>; + /// The current storage version. + /// + /// v1: https://github.com/paritytech/substrate/pull/12237/ + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData); } diff --git a/frame/election-provider-multi-phase/src/migrations.rs b/frame/election-provider-multi-phase/src/migrations.rs new file mode 100644 index 0000000000000..77efe0d0c5e92 --- /dev/null +++ b/frame/election-provider-multi-phase/src/migrations.rs @@ -0,0 +1,78 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod v1 { + use frame_support::{ + storage::unhashed, + traits::{Defensive, GetStorageVersion, OnRuntimeUpgrade}, + BoundedVec, + }; + use sp_std::collections::btree_map::BTreeMap; + + use crate::*; + pub struct MigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); + + log!( + info, + "Running migration with current storage version {:?} / onchain {:?}", + current, + onchain + ); + + if current == 1 && onchain == 0 { + if SignedSubmissionIndices::::exists() { + // This needs to be tested at a both a block height where this value exists, and + // when it doesn't. + let now = frame_system::Pallet::::block_number(); + let map = unhashed::get::>( + &SignedSubmissionIndices::::hashed_key(), + ) + .defensive_unwrap_or_default(); + let vector = map + .into_iter() + .map(|(score, index)| (score, now, index)) + .collect::>(); + + log!( + debug, + "{:?} SignedSubmissionIndices read from storage (max: {:?})", + vector.len(), + T::SignedMaxSubmissions::get() + ); + + // defensive-only, assuming a constant `SignedMaxSubmissions`. + let bounded = BoundedVec::<_, _>::truncate_from(vector); + SignedSubmissionIndices::::put(bounded); + + log!(info, "SignedSubmissionIndices existed and got migrated"); + } else { + log!(info, "SignedSubmissionIndices did NOT exist."); + } + + current.put::>(); + T::DbWeight::get().reads_writes(2, 1) + } else { + log!(info, "Migration did not execute. This probably should be removed"); + T::DbWeight::get().reads(1) + } + } + } +} diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index e04e0bf474caf..f645886d78899 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -571,6 +571,12 @@ impl ExtBuilder { balances: vec![ // bunch of account for submitting stuff only. (99, 100), + (100, 100), + (101, 100), + (102, 100), + (103, 100), + (104, 100), + (105, 100), (999, 100), (9999, 100), ], diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 175c92757f35e..cda87dd6c839a 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -24,11 +24,11 @@ use crate::{ }; use codec::{Decode, Encode, HasCompact}; use frame_election_provider_support::NposSolution; -use frame_support::{ - storage::bounded_btree_map::BoundedBTreeMap, - traits::{defensive_prelude::*, Currency, Get, OnUnbalanced, ReservableCurrency}, +use frame_support::traits::{ + defensive_prelude::*, Currency, Get, OnUnbalanced, ReservableCurrency, }; use sp_arithmetic::traits::SaturatedConversion; +use sp_core::bounded::BoundedVec; use sp_npos_elections::ElectionScore; use sp_runtime::{ traits::{Saturating, Zero}, @@ -37,7 +37,6 @@ use sp_runtime::{ use sp_std::{ cmp::Ordering, collections::{btree_map::BTreeMap, btree_set::BTreeSet}, - ops::Deref, vec::Vec, }; @@ -99,8 +98,12 @@ pub type SignedSubmissionOf = SignedSubmission< <::MinerConfig as MinerConfig>::Solution, >; -pub type SubmissionIndicesOf = - BoundedBTreeMap::SignedMaxSubmissions>; +/// Always sorted vector of a score, submitted at the given block number, which can be found at the +/// given index (`u32`) of the `SignedSubmissionsMap`. +pub type SubmissionIndicesOf = BoundedVec< + (ElectionScore, ::BlockNumber, u32), + ::SignedMaxSubmissions, +>; /// Outcome of [`SignedSubmissions::insert`]. pub enum InsertResult { @@ -126,6 +129,16 @@ pub struct SignedSubmissions { } impl SignedSubmissions { + /// `true` if the structure is empty. + pub fn is_empty(&self) -> bool { + self.indices.is_empty() + } + + /// Get the length of submitted solutions. + pub fn len(&self) -> usize { + self.indices.len() + } + /// Get the signed submissions from storage. pub fn get() -> Self { let submissions = SignedSubmissions { @@ -134,10 +147,12 @@ impl SignedSubmissions { insertion_overlay: BTreeMap::new(), deletion_overlay: BTreeSet::new(), }; + // validate that the stored state is sane debug_assert!(submissions .indices - .values() + .iter() + .map(|(_, _, index)| index) .copied() .max() .map_or(true, |max_idx| submissions.next_idx > max_idx,)); @@ -155,7 +170,8 @@ impl SignedSubmissions { .map_or(true, |max_idx| self.next_idx > max_idx,)); debug_assert!(self .indices - .values() + .iter() + .map(|(_, _, index)| index) .copied() .max() .map_or(true, |max_idx| self.next_idx > max_idx,)); @@ -174,9 +190,9 @@ impl SignedSubmissions { /// Get the submission at a particular index. fn get_submission(&self, index: u32) -> Option> { if self.deletion_overlay.contains(&index) { - // Note: can't actually remove the item from the insertion overlay (if present) - // because we don't want to use `&mut self` here. There may be some kind of - // `RefCell` optimization possible here in the future. + // Note: can't actually remove the item from the insertion overlay (if present) because + // we don't want to use `&mut self` here. There may be some kind of `RefCell` + // optimization possible here in the future. None } else { self.insertion_overlay @@ -188,27 +204,30 @@ impl SignedSubmissions { /// Perform three operations: /// - /// - Remove a submission (identified by score) - /// - Insert a new submission (identified by score and insertion index) - /// - Return the submission which was removed. - /// - /// Note: in the case that `weakest_score` is not present in `self.indices`, this will return - /// `None` without inserting the new submission and without further notice. + /// - Remove the solution at the given position of `self.indices`. + /// - Insert a new submission (identified by score and insertion index), if provided. + /// - Return the submission which was removed, if any. /// - /// Note: this does not enforce any ordering relation between the submission removed and that - /// inserted. + /// The call site must ensure that `remove_pos` is a valid index. If otherwise, `None` is + /// silently returned. /// /// Note: this doesn't insert into `insertion_overlay`, the optional new insertion must be - /// inserted into `insertion_overlay` to keep the variable `self` in a valid state. + /// inserted into `insertion_overlay` to keep the variable `self` in a valid state. fn swap_out_submission( &mut self, - remove_score: ElectionScore, - insert: Option<(ElectionScore, u32)>, + remove_pos: usize, + insert: Option<(ElectionScore, T::BlockNumber, u32)>, ) -> Option> { - let remove_index = self.indices.remove(&remove_score)?; - if let Some((insert_score, insert_idx)) = insert { + if remove_pos >= self.indices.len() { + return None + } + + // safe: index was just checked in the line above. + let (_, _, remove_index) = self.indices.remove(remove_pos); + + if let Some((insert_score, block_number, insert_idx)) = insert { self.indices - .try_insert(insert_score, insert_idx) + .try_push((insert_score, block_number, insert_idx)) .expect("just removed an item, we must be under capacity; qed"); } @@ -222,20 +241,17 @@ impl SignedSubmissions { }) } + /// Remove the signed submission with the highest score from the set. + pub fn pop_last(&mut self) -> Option> { + let best_index = self.indices.len().checked_sub(1)?; + self.swap_out_submission(best_index, None) + } + /// Iterate through the set of signed submissions in order of increasing score. pub fn iter(&self) -> impl '_ + Iterator> { - self.indices.iter().filter_map(move |(_score, &idx)| { - let maybe_submission = self.get_submission(idx); - if maybe_submission.is_none() { - log!( - error, - "SignedSubmissions internal state is invalid (idx {}); \ - there is a logic error in code handling signed solution submissions", - idx, - ) - } - maybe_submission - }) + self.indices + .iter() + .filter_map(move |(_score, _bn, idx)| self.get_submission(*idx).defensive()) } /// Empty the set of signed submissions, returning an iterator of signed submissions in @@ -283,68 +299,54 @@ impl SignedSubmissions { /// to `is_score_better`, we do not change anything. pub fn insert(&mut self, submission: SignedSubmissionOf) -> InsertResult { // verify the expectation that we never reuse an index - debug_assert!(!self.indices.values().any(|&idx| idx == self.next_idx)); - - let weakest = match self.indices.try_insert(submission.raw_solution.score, self.next_idx) { - Ok(Some(prev_idx)) => { - // a submission of equal score was already present in the set; - // no point editing the actual backing map as we know that the newer solution can't - // be better than the old. However, we do need to put the old value back. - self.indices - .try_insert(submission.raw_solution.score, prev_idx) - .expect("didn't change the map size; qed"); - return InsertResult::NotInserted - }, - Ok(None) => { - // successfully inserted into the set; no need to take out weakest member - None - }, - Err((insert_score, insert_idx)) => { - // could not insert into the set because it is full. - // note that we short-circuit return here in case the iteration produces `None`. - // If there wasn't a weakest entry to remove, then there must be a capacity of 0, - // which means that we can't meaningfully proceed. - let weakest_score = match self.indices.iter().next() { + debug_assert!(!self.indices.iter().map(|(_, _, x)| x).any(|&idx| idx == self.next_idx)); + let block_number = frame_system::Pallet::::block_number(); + + let maybe_weakest = match self.indices.try_push(( + submission.raw_solution.score, + block_number, + self.next_idx, + )) { + Ok(_) => None, + Err(_) => { + // the queue is full -- if this is better, insert it. + let weakest_score = match self.indices.iter().next().defensive() { None => return InsertResult::NotInserted, - Some((score, _)) => *score, + Some((score, _, _)) => *score, }; let threshold = T::BetterSignedThreshold::get(); // if we haven't improved on the weakest score, don't change anything. - if !insert_score.strict_threshold_better(weakest_score, threshold) { + if !submission.raw_solution.score.strict_threshold_better(weakest_score, threshold) + { return InsertResult::NotInserted } - self.swap_out_submission(weakest_score, Some((insert_score, insert_idx))) + self.swap_out_submission( + 0, // swap out the worse one, which is always index 0. + Some((submission.raw_solution.score, block_number, self.next_idx)), + ) }, }; + // this is the ONLY place that we insert, and we sort post insertion. If scores are the + // same, we sort based on reverse of submission block number. + self.indices + .sort_by(|(score1, bn1, _), (score2, bn2, _)| match score1.cmp(score2) { + Ordering::Equal => bn1.cmp(&bn2).reverse(), + x => x, + }); + // we've taken out the weakest, so update the storage map and the next index debug_assert!(!self.insertion_overlay.contains_key(&self.next_idx)); self.insertion_overlay.insert(self.next_idx, submission); debug_assert!(!self.deletion_overlay.contains(&self.next_idx)); self.next_idx += 1; - match weakest { + match maybe_weakest { Some(weakest) => InsertResult::InsertedEjecting(weakest), None => InsertResult::Inserted, } } - - /// Remove the signed submission with the highest score from the set. - pub fn pop_last(&mut self) -> Option> { - let (score, _) = self.indices.iter().rev().next()?; - // deref in advance to prevent mutable-immutable borrow conflict - let score = *score; - self.swap_out_submission(score, None) - } -} - -impl Deref for SignedSubmissions { - type Target = SubmissionIndicesOf; - - fn deref(&self) -> &Self::Target { - &self.indices - } } impl Pallet { @@ -379,6 +381,12 @@ impl Pallet { Self::snapshot_metadata().unwrap_or_default(); while let Some(best) = all_submissions.pop_last() { + log!( + debug, + "finalized_signed: trying to verify from {:?} score {:?}", + best.who, + best.raw_solution.score + ); let SignedSubmission { raw_solution, who, deposit, call_fee } = best; let active_voters = raw_solution.solution.voter_count() as u32; let feasibility_weight = { @@ -386,6 +394,7 @@ impl Pallet { let desired_targets = Self::desired_targets().defensive_unwrap_or_default(); T::WeightInfo::feasibility_check(voters, targets, active_voters, desired_targets) }; + // the feasibility check itself has some weight weight = weight.saturating_add(feasibility_weight); match Self::feasibility_check(raw_solution, ElectionCompute::Signed) { @@ -397,12 +406,14 @@ impl Pallet { call_fee, ); found_solution = true; + log!(debug, "finalized_signed: found a valid solution"); weight = weight .saturating_add(T::WeightInfo::finalize_signed_phase_accept_solution()); break }, Err(_) => { + log!(warn, "finalized_signed: invalid signed submission found, slashing."); Self::finalize_signed_phase_reject_solution(&who, deposit); weight = weight .saturating_add(T::WeightInfo::finalize_signed_phase_reject_solution()); @@ -526,14 +537,7 @@ impl Pallet { #[cfg(test)] mod tests { use super::*; - use crate::{ - mock::{ - balances, multi_phase_events, raw_solution, roll_to, roll_to_signed, Balances, - ExtBuilder, MockedWeightInfo, MultiPhase, Runtime, RuntimeOrigin, SignedMaxRefunds, - SignedMaxSubmissions, SignedMaxWeight, - }, - Error, Event, Perbill, Phase, - }; + use crate::{mock::*, ElectionCompute, Error, Event, Perbill, Phase}; use frame_support::{assert_noop, assert_ok, assert_storage_noop}; #[test] @@ -868,8 +872,8 @@ mod tests { } #[test] - fn replace_weakest_works() { - ExtBuilder::default().build_and_execute(|| { + fn replace_weakest_by_score_works() { + ExtBuilder::default().signed_max_submission(3).build_and_execute(|| { roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); @@ -893,7 +897,7 @@ mod tests { .iter() .map(|s| s.raw_solution.score.minimal_stake) .collect::>(), - vec![4, 6, 7, 8, 9], + vec![4, 6, 7], ); // better. @@ -909,7 +913,7 @@ mod tests { .iter() .map(|s| s.raw_solution.score.minimal_stake) .collect::>(), - vec![5, 6, 7, 8, 9], + vec![5, 6, 7], ); }) } @@ -946,7 +950,8 @@ mod tests { } #[test] - fn equally_good_solution_is_not_accepted() { + fn equally_good_solution_is_not_accepted_when_queue_full() { + // because in ordering of solutions, an older solution has higher priority and should stay. ExtBuilder::default().signed_max_submission(3).build_and_execute(|| { roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); @@ -958,6 +963,7 @@ mod tests { }; assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } + assert_eq!( MultiPhase::signed_submissions() .iter() @@ -978,6 +984,99 @@ mod tests { }) } + #[test] + fn equally_good_solution_is_accepted_when_queue_not_full() { + // because in ordering of solutions, an older solution has higher priority and should stay. + ExtBuilder::default().signed_max_submission(3).build_and_execute(|| { + roll_to(15); + assert!(MultiPhase::current_phase().is_signed()); + + let solution = RawSolution { + score: ElectionScore { minimal_stake: 5, ..Default::default() }, + ..Default::default() + }; + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); + + assert_eq!( + MultiPhase::signed_submissions() + .iter() + .map(|s| (s.who, s.raw_solution.score.minimal_stake,)) + .collect::>(), + vec![(99, 5)] + ); + + roll_to(16); + let solution = RawSolution { + score: ElectionScore { minimal_stake: 5, ..Default::default() }, + ..Default::default() + }; + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(999), Box::new(solution))); + + assert_eq!( + MultiPhase::signed_submissions() + .iter() + .map(|s| (s.who, s.raw_solution.score.minimal_stake,)) + .collect::>(), + vec![(999, 5), (99, 5)] + ); + + let solution = RawSolution { + score: ElectionScore { minimal_stake: 6, ..Default::default() }, + ..Default::default() + }; + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(9999), Box::new(solution))); + + assert_eq!( + MultiPhase::signed_submissions() + .iter() + .map(|s| (s.who, s.raw_solution.score.minimal_stake,)) + .collect::>(), + vec![(999, 5), (99, 5), (9999, 6)] + ); + }) + } + + #[test] + fn all_equal_score() { + // because in ordering of solutions, an older solution has higher priority and should stay. + ExtBuilder::default().signed_max_submission(3).build_and_execute(|| { + roll_to(15); + assert!(MultiPhase::current_phase().is_signed()); + + for i in 0..SignedMaxSubmissions::get() { + roll_to((15 + i).into()); + let solution = raw_solution(); + assert_ok!(MultiPhase::submit( + RuntimeOrigin::signed(100 + i as AccountId), + Box::new(solution) + )); + } + + assert_eq!( + MultiPhase::signed_submissions() + .iter() + .map(|s| (s.who, s.raw_solution.score.minimal_stake)) + .collect::>(), + vec![(102, 40), (101, 40), (100, 40)] + ); + + roll_to(25); + + // The first one that will actually get verified is the last one. + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Rewarded { account: 100, value: 7 }, + Event::UnsignedPhaseStarted { round: 1 } + ] + ); + }) + } + #[test] fn all_in_one_signed_submission_scenario() { // a combination of: @@ -991,6 +1090,7 @@ mod tests { assert_eq!(balances(&99), (100, 0)); assert_eq!(balances(&999), (100, 0)); assert_eq!(balances(&9999), (100, 0)); + let solution = raw_solution(); // submit a correct one. From c11b2621e6e0e20263a230b783d68820370f9ee1 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 19 Oct 2022 22:55:20 +0200 Subject: [PATCH 1291/1472] CI check against Rust feature bleed (#12341) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CI check for rust feature bleed Signed-off-by: Oliver Tale-Yazdi * Cargo not available Signed-off-by: Oliver Tale-Yazdi * Handle missing programs Signed-off-by: Oliver Tale-Yazdi * Check for deps Signed-off-by: Oliver Tale-Yazdi * Add doc Signed-off-by: Oliver Tale-Yazdi * Use correct CI image Signed-off-by: Oliver Tale-Yazdi * Remove --offline Signed-off-by: Oliver Tale-Yazdi * Install cargo-workspaces Signed-off-by: Oliver Tale-Yazdi * Remove cargo-workspaces dep Signed-off-by: Oliver Tale-Yazdi * Fix try-runtime feature Signed-off-by: Oliver Tale-Yazdi * Fix features Signed-off-by: Oliver Tale-Yazdi * Fix features Signed-off-by: Oliver Tale-Yazdi * Fix more features... Signed-off-by: Oliver Tale-Yazdi * Use pipeline-script Signed-off-by: Oliver Tale-Yazdi * 🤡 Signed-off-by: Oliver Tale-Yazdi * Make stupid change to test the CI Signed-off-by: Oliver Tale-Yazdi * This reverts commit ad2746aa117fa7cb473521113a9bec89aaf26484. * Use correct branch Signed-off-by: Oliver Tale-Yazdi * Allow failure Signed-off-by: Oliver Tale-Yazdi * Make stupid change to test the CI Signed-off-by: Oliver Tale-Yazdi * Revert "Make stupid change to test the CI" This reverts commit 16ec00e1675c7ec57c988315549ff71e832a3093. Signed-off-by: Oliver Tale-Yazdi --- bin/node-template/node/Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- frame/executive/Cargo.toml | 2 +- .../procedural/src/pallet/expand/genesis_build.rs | 2 +- frame/try-runtime/Cargo.toml | 5 ++++- frame/try-runtime/src/lib.rs | 1 + scripts/ci/gitlab/pipeline/check.yml | 14 +++++++++++++- utils/frame/try-runtime/cli/Cargo.toml | 7 ++++++- utils/frame/try-runtime/cli/src/lib.rs | 2 ++ 11 files changed, 32 insertions(+), 9 deletions(-) diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index c60018e14969c..d94955f722605 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -75,4 +75,4 @@ runtime-benchmarks = [ ] # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. -try-runtime = ["node-template-runtime/try-runtime", "try-runtime-cli"] +try-runtime = ["node-template-runtime/try-runtime", "try-runtime-cli/try-runtime"] diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 45ab4939e311c..139264657f89d 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -99,7 +99,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", ] try-runtime = [ - "frame-try-runtime", + "frame-try-runtime/try-runtime", "frame-executive/try-runtime", "frame-system/try-runtime", "frame-support/try-runtime", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 4bf991f49320c..07208abdd089b 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -165,7 +165,7 @@ runtime-benchmarks = [ ] # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. -try-runtime = ["kitchensink-runtime/try-runtime", "try-runtime-cli"] +try-runtime = ["kitchensink-runtime/try-runtime", "try-runtime-cli/try-runtime"] [[bench]] name = "transaction_pool" diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 6940e968e28e7..39364961d57e2 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -254,7 +254,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", ] try-runtime = [ - "frame-try-runtime", + "frame-try-runtime/try-runtime", "frame-executive/try-runtime", "frame-system/try-runtime", "frame-support/try-runtime", diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index cd5c793ee2ee0..f6f5175d63bb9 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -49,4 +49,4 @@ std = [ "sp-std/std", "sp-tracing/std", ] -try-runtime = ["frame-support/try-runtime", "frame-try-runtime" ] +try-runtime = ["frame-support/try-runtime", "frame-try-runtime/try-runtime" ] diff --git a/frame/support/procedural/src/pallet/expand/genesis_build.rs b/frame/support/procedural/src/pallet/expand/genesis_build.rs index 53d0695e5f971..d19476779011b 100644 --- a/frame/support/procedural/src/pallet/expand/genesis_build.rs +++ b/frame/support/procedural/src/pallet/expand/genesis_build.rs @@ -19,7 +19,7 @@ use crate::pallet::Def; /// /// * implement the trait `sp_runtime::BuildModuleGenesisStorage` -/// * add #[cfg(features = "std")] to GenesisBuild implementation. +/// * add #[cfg(feature = "std")] to GenesisBuild implementation. pub fn expand_genesis_build(def: &mut Def) -> proc_macro2::TokenStream { let genesis_config = if let Some(genesis_config) = &def.genesis_config { genesis_config diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index dd77c0438d71f..51b6f91784594 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"]} -frame-support = { version = "4.0.0-dev", default-features = false, features = [ "try-runtime" ], path = "../support" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -28,3 +28,6 @@ std = [ "sp-runtime/std", "sp-std/std", ] +try-runtime = [ + "frame-support/try-runtime", +] diff --git a/frame/try-runtime/src/lib.rs b/frame/try-runtime/src/lib.rs index 7fec92712cd19..ed1247bd8e6f2 100644 --- a/frame/try-runtime/src/lib.rs +++ b/frame/try-runtime/src/lib.rs @@ -18,6 +18,7 @@ //! Supporting types for try-runtime, testing and dry-running commands. #![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "try-runtime")] pub use frame_support::traits::TryStateSelect; use frame_support::weights::Weight; diff --git a/scripts/ci/gitlab/pipeline/check.yml b/scripts/ci/gitlab/pipeline/check.yml index 3166e13313f2a..878c46f32e850 100644 --- a/scripts/ci/gitlab/pipeline/check.yml +++ b/scripts/ci/gitlab/pipeline/check.yml @@ -35,6 +35,19 @@ test-dependency-rules: script: - ./scripts/ci/gitlab/ensure-deps.sh +test-rust-features: + stage: check + extends: + - .kubernetes-env + - .test-refs-no-trigger-prs-only + allow_failure: true + script: + - git clone + --depth=1 + --branch="$PIPELINE_SCRIPTS_TAG" + https://github.com/paritytech/pipeline-scripts + - bash ./pipeline-scripts/rust-features.sh . + test-prometheus-alerting-rules: stage: check extends: .kubernetes-env @@ -51,4 +64,3 @@ test-prometheus-alerting-rules: - promtool check rules ./scripts/ci/monitoring/alerting-rules/alerting-rules.yaml - cat ./scripts/ci/monitoring/alerting-rules/alerting-rules.yaml | promtool test rules ./scripts/ci/monitoring/alerting-rules/alerting-rule-tests.yaml - diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 24d64d4aa4373..c7191b7eb7f5f 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -31,8 +31,13 @@ sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../../primitives/state-machine" } sp-version = { version = "5.0.0", path = "../../../../primitives/version" } sp-weights = { version = "4.0.0", path = "../../../../primitives/weights" } -frame-try-runtime = { path = "../../../../frame/try-runtime" } +frame-try-runtime = { optional = true, path = "../../../../frame/try-runtime" } substrate-rpc-client = { path = "../../rpc/client" } [dev-dependencies] tokio = "1.17.0" + +[features] +try-runtime = [ + "frame-try-runtime/try-runtime", +] diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 0732c8618fc15..f54354342bf28 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -265,6 +265,8 @@ //! -s snap \ //! ``` +#![cfg(feature = "try-runtime")] + use parity_scale_codec::Decode; use remote_externalities::{ Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, TestExternalities, From 2eb8ad273eeabea380fce00c10893ac788b1cbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 20 Oct 2022 00:34:03 +0200 Subject: [PATCH 1292/1472] contracts: Decrease the interation count on slow benchmarks (#12526) * Decrease amount of benchmark iterations for long slow ones * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts Co-authored-by: command-bot <> --- frame/contracts/src/benchmarking/mod.rs | 12 +- frame/contracts/src/weights.rs | 1525 ++++++++++++----------- 2 files changed, 772 insertions(+), 765 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 186ac6f63503e..86c7d2df674c7 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1890,7 +1890,7 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. seal_hash_sha2_256 { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( "seal_hash_sha2_256", r * API_BENCHMARK_BATCH_SIZE, 0, ), vec![])?; @@ -1908,7 +1908,7 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. seal_hash_keccak_256 { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( "seal_hash_keccak_256", r * API_BENCHMARK_BATCH_SIZE, 0, ), vec![])?; @@ -1926,7 +1926,7 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. seal_hash_blake2_256 { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( "seal_hash_blake2_256", r * API_BENCHMARK_BATCH_SIZE, 0, ), vec![])?; @@ -1944,7 +1944,7 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. seal_hash_blake2_128 { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( "seal_hash_blake2_128", r * API_BENCHMARK_BATCH_SIZE, 0, ), vec![])?; @@ -1963,7 +1963,7 @@ benchmarks! { // Only calling the function itself with valid arguments. // It generates different private keys and signatures for the message "Hello world". seal_ecdsa_recover { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. 1; let message_hash = sp_io::hashing::blake2_256("Hello world".as_bytes()); let key_type = sp_core::crypto::KeyTypeId(*b"code"); @@ -2011,7 +2011,7 @@ benchmarks! { // Only calling the function itself for the list of // generated different ECDSA keys. seal_ecdsa_to_eth_address { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. 1; let key_type = sp_core::crypto::KeyTypeId(*b"code"); let pub_keys_bytes = (0..r * API_BENCHMARK_BATCH_SIZE) .map(|_| { diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 4e4a6b6e6a2b7..46c86b670a7fe 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -32,6 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json // --pallet=pallet_contracts // --chain=dev // --output=./frame/contracts/src/weights.rs @@ -166,15 +167,15 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(3_089_000 as u64) + Weight::from_ref_time(3_108_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(13_917_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(k as u64)) + Weight::from_ref_time(15_377_000 as u64) + // Standard Error: 414 + .saturating_add(Weight::from_ref_time(892_761 as u64).saturating_mul(k as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -182,19 +183,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(14_172_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_301_000 as u64).saturating_mul(q as u64)) + Weight::from_ref_time(3_127_000 as u64) + // Standard Error: 3_813 + .saturating_add(Weight::from_ref_time(1_379_402 as u64).saturating_mul(q as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(21_644_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(22_849_000 as u64) + // Standard Error: 26 + .saturating_add(Weight::from_ref_time(45_513 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -205,9 +205,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(234_349_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(258_275_000 as u64) + // Standard Error: 30 + .saturating_add(Weight::from_ref_time(45_885 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -222,11 +222,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(294_077_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(c as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(2_115_889_000 as u64) + // Standard Error: 323 + .saturating_add(Weight::from_ref_time(89_541 as u64).saturating_mul(c as u64)) + // Standard Error: 19 + .saturating_add(Weight::from_ref_time(664 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(9 as u64)) } @@ -239,9 +239,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(199_028_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(211_349_000 as u64) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(1_532 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(7 as u64)) } @@ -251,7 +251,7 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(176_247_000 as u64) + Weight::from_ref_time(181_771_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -261,9 +261,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(54_917_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(55_917_000 as u64) + // Standard Error: 25 + .saturating_add(Weight::from_ref_time(46_148 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -272,7 +272,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(37_611_000 as u64) + Weight::from_ref_time(37_966_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -280,7 +280,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(40_121_000 as u64) + Weight::from_ref_time(40_963_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -291,9 +291,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(241_129_000 as u64) - // Standard Error: 54_000 - .saturating_add(Weight::from_ref_time(35_413_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_526_000 as u64) + // Standard Error: 29_505 + .saturating_add(Weight::from_ref_time(35_107_467 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -304,9 +304,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(189_418_000 as u64) - // Standard Error: 419_000 - .saturating_add(Weight::from_ref_time(207_107_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(253_782_000 as u64) + // Standard Error: 256_004 + .saturating_add(Weight::from_ref_time(201_621_188 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -318,9 +318,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(203_928_000 as u64) - // Standard Error: 439_000 - .saturating_add(Weight::from_ref_time(268_983_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(249_892_000 as u64) + // Standard Error: 234_750 + .saturating_add(Weight::from_ref_time(258_209_168 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -332,9 +332,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(243_800_000 as u64) - // Standard Error: 40_000 - .saturating_add(Weight::from_ref_time(38_797_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(248_674_000 as u64) + // Standard Error: 23_962 + .saturating_add(Weight::from_ref_time(38_319_695 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -345,9 +345,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(239_667_000 as u64) - // Standard Error: 27_000 - .saturating_add(Weight::from_ref_time(15_826_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_345_000 as u64) + // Standard Error: 15_429 + .saturating_add(Weight::from_ref_time(14_751_125 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -358,9 +358,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(241_116_000 as u64) - // Standard Error: 41_000 - .saturating_add(Weight::from_ref_time(35_402_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_045_000 as u64) + // Standard Error: 25_949 + .saturating_add(Weight::from_ref_time(35_001_004 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -371,9 +371,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(240_515_000 as u64) - // Standard Error: 50_000 - .saturating_add(Weight::from_ref_time(35_144_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_176_000 as u64) + // Standard Error: 24_500 + .saturating_add(Weight::from_ref_time(34_447_506 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -384,10 +384,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(244_087_000 as u64) - // Standard Error: 87_000 - .saturating_add(Weight::from_ref_time(110_236_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) + Weight::from_ref_time(247_278_000 as u64) + // Standard Error: 48_613 + .saturating_add(Weight::from_ref_time(108_381_432 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -397,9 +397,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(241_774_000 as u64) - // Standard Error: 50_000 - .saturating_add(Weight::from_ref_time(35_216_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(246_996_000 as u64) + // Standard Error: 24_585 + .saturating_add(Weight::from_ref_time(34_615_777 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -410,9 +410,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(241_146_000 as u64) - // Standard Error: 54_000 - .saturating_add(Weight::from_ref_time(35_101_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_207_000 as u64) + // Standard Error: 30_691 + .saturating_add(Weight::from_ref_time(34_626_552 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -423,9 +423,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(244_096_000 as u64) - // Standard Error: 55_000 - .saturating_add(Weight::from_ref_time(34_612_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_538_000 as u64) + // Standard Error: 27_128 + .saturating_add(Weight::from_ref_time(34_277_292 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -436,9 +436,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(242_978_000 as u64) - // Standard Error: 53_000 - .saturating_add(Weight::from_ref_time(34_780_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_398_000 as u64) + // Standard Error: 28_375 + .saturating_add(Weight::from_ref_time(34_573_437 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -450,10 +450,10 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(246_175_000 as u64) - // Standard Error: 86_000 - .saturating_add(Weight::from_ref_time(99_827_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) + Weight::from_ref_time(247_732_000 as u64) + // Standard Error: 42_671 + .saturating_add(Weight::from_ref_time(123_110_886 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -463,9 +463,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(168_655_000 as u64) - // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(15_635_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(170_547_000 as u64) + // Standard Error: 9_163 + .saturating_add(Weight::from_ref_time(15_589_088 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -476,9 +476,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(239_729_000 as u64) - // Standard Error: 52_000 - .saturating_add(Weight::from_ref_time(33_477_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_264_000 as u64) + // Standard Error: 23_913 + .saturating_add(Weight::from_ref_time(32_753_431 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -489,9 +489,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(296_718_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_616_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(282_721_000 as u64) + // Standard Error: 1_978 + .saturating_add(Weight::from_ref_time(9_625_699 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -502,9 +502,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - Weight::from_ref_time(237_666_000 as u64) - // Standard Error: 497_000 - .saturating_add(Weight::from_ref_time(2_090_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_356_000 as u64) + // Standard Error: 184_002 + .saturating_add(Weight::from_ref_time(2_423_400 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -515,9 +515,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(239_842_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(246_157_000 as u64) + // Standard Error: 324 + .saturating_add(Weight::from_ref_time(188_687 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -530,9 +530,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(240_563_000 as u64) - // Standard Error: 519_000 - .saturating_add(Weight::from_ref_time(52_855_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_356_000 as u64) + // Standard Error: 232_552 + .saturating_add(Weight::from_ref_time(55_027_099 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -546,10 +546,10 @@ impl WeightInfo for SubstrateWeight { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(248_136_000 as u64) - // Standard Error: 94_000 - .saturating_add(Weight::from_ref_time(137_406_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) + Weight::from_ref_time(247_069_000 as u64) + // Standard Error: 59_538 + .saturating_add(Weight::from_ref_time(128_858_347 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -559,9 +559,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(253_433_000 as u64) - // Standard Error: 105_000 - .saturating_add(Weight::from_ref_time(242_337_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_659_000 as u64) + // Standard Error: 70_677 + .saturating_add(Weight::from_ref_time(239_930_533 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -573,11 +573,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(478_106_000 as u64) - // Standard Error: 557_000 - .saturating_add(Weight::from_ref_time(176_325_000 as u64).saturating_mul(t as u64)) - // Standard Error: 153_000 - .saturating_add(Weight::from_ref_time(67_413_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(1_198_350_000 as u64) + // Standard Error: 2_049_556 + .saturating_add(Weight::from_ref_time(70_072_141 as u64).saturating_mul(t as u64)) + // Standard Error: 496_378 + .saturating_add(Weight::from_ref_time(35_566_752 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -590,18 +590,18 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(172_751_000 as u64) - // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(26_536_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(177_240_000 as u64) + // Standard Error: 18_991 + .saturating_add(Weight::from_ref_time(26_377_453 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(196_276_000 as u64) - // Standard Error: 428_000 - .saturating_add(Weight::from_ref_time(416_783_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_795_000 as u64) + // Standard Error: 349_627 + .saturating_add(Weight::from_ref_time(411_421_066 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -610,53 +610,53 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(532_439_000 as u64) - // Standard Error: 1_323_000 - .saturating_add(Weight::from_ref_time(93_843_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(52 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(50 as u64)) - .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(405_147_000 as u64) + // Standard Error: 1_074_466 + .saturating_add(Weight::from_ref_time(120_331_835 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(6 as u64)) + .saturating_add(T::DbWeight::get().writes((15 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(511_358_000 as u64) - // Standard Error: 1_144_000 - .saturating_add(Weight::from_ref_time(68_754_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(52 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(50 as u64)) - .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(403_403_000 as u64) + // Standard Error: 890_083 + .saturating_add(Weight::from_ref_time(88_023_518 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(6 as u64)) + .saturating_add(T::DbWeight::get().writes((15 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(204_133_000 as u64) - // Standard Error: 498_000 - .saturating_add(Weight::from_ref_time(406_798_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) + Weight::from_ref_time(247_929_000 as u64) + // Standard Error: 311_780 + .saturating_add(Weight::from_ref_time(400_904_526 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(489_339_000 as u64) - // Standard Error: 1_269_000 - .saturating_add(Weight::from_ref_time(70_700_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(51 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(49 as u64)) - .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(372_378_000 as u64) + // Standard Error: 1_007_061 + .saturating_add(Weight::from_ref_time(92_326_546 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes((15 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(211_344_000 as u64) - // Standard Error: 399_000 - .saturating_add(Weight::from_ref_time(330_244_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(250_165_000 as u64) + // Standard Error: 300_205 + .saturating_add(Weight::from_ref_time(339_092_950 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -664,19 +664,19 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(449_353_000 as u64) - // Standard Error: 1_027_000 - .saturating_add(Weight::from_ref_time(153_022_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(51 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(352_873_000 as u64) + // Standard Error: 908_425 + .saturating_add(Weight::from_ref_time(176_951_688 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(216_197_000 as u64) - // Standard Error: 341_000 - .saturating_add(Weight::from_ref_time(305_401_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(248_980_000 as u64) + // Standard Error: 295_923 + .saturating_add(Weight::from_ref_time(306_145_709 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -684,34 +684,34 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(423_033_000 as u64) - // Standard Error: 878_000 - .saturating_add(Weight::from_ref_time(61_940_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(51 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(340_418_000 as u64) + // Standard Error: 749_537 + .saturating_add(Weight::from_ref_time(80_040_174 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(204_244_000 as u64) - // Standard Error: 448_000 - .saturating_add(Weight::from_ref_time(429_399_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) + Weight::from_ref_time(250_254_000 as u64) + // Standard Error: 328_900 + .saturating_add(Weight::from_ref_time(424_144_552 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(516_945_000 as u64) - // Standard Error: 1_412_000 - .saturating_add(Weight::from_ref_time(162_098_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(52 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(49 as u64)) - .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(377_849_000 as u64) + // Standard Error: 1_130_582 + .saturating_add(Weight::from_ref_time(188_240_273 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(5 as u64)) + .saturating_add(T::DbWeight::get().writes((15 as u64).saturating_mul(n as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -720,12 +720,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(170_412_000 as u64) - // Standard Error: 761_000 - .saturating_add(Weight::from_ref_time(1_367_307_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) + Weight::from_ref_time(249_701_000 as u64) + // Standard Error: 449_896 + .saturating_add(Weight::from_ref_time(1_370_712_846 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) @@ -735,10 +735,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 9_269_000 - .saturating_add(Weight::from_ref_time(17_505_281_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) + Weight::from_ref_time(251_015_000 as u64) + // Standard Error: 7_081_378 + .saturating_add(Weight::from_ref_time(17_258_935_295 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((160 as u64).saturating_mul(r as u64))) @@ -750,11 +750,13 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 8_780_000 - .saturating_add(Weight::from_ref_time(17_368_867_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads((158 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes((79 as u64).saturating_mul(r as u64))) + Weight::from_ref_time(250_660_000 as u64) + // Standard Error: 6_402_989 + .saturating_add(Weight::from_ref_time(17_044_780_887 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().reads((150 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((75 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -764,11 +766,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(11_076_579_000 as u64) - // Standard Error: 6_568_000 - .saturating_add(Weight::from_ref_time(1_158_818_000 as u64).saturating_mul(t as u64)) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(9_731_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(11_920_718_000 as u64) + // Standard Error: 11_123_062 + .saturating_add(Weight::from_ref_time(642_326_761 as u64).saturating_mul(t as u64)) + // Standard Error: 9_490 + .saturating_add(Weight::from_ref_time(8_845_752 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(167 as u64)) .saturating_add(T::DbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(163 as u64)) @@ -783,12 +785,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 24_125_000 - .saturating_add(Weight::from_ref_time(22_830_521_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) + Weight::from_ref_time(253_804_000 as u64) + // Standard Error: 19_742_198 + .saturating_add(Weight::from_ref_time(22_250_412_835 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((400 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((400 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:81 w:81) @@ -801,9 +803,9 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(13_739_440_000 as u64) - // Standard Error: 79_000 - .saturating_add(Weight::from_ref_time(126_148_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(13_921_591_000 as u64) + // Standard Error: 22_601 + .saturating_add(Weight::from_ref_time(125_945_348 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(249 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(247 as u64)) @@ -814,11 +816,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(241_753_000 as u64) - // Standard Error: 60_000 - .saturating_add(Weight::from_ref_time(55_067_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_842_000 as u64) + // Standard Error: 219_853 + .saturating_add(Weight::from_ref_time(58_013_100 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -829,9 +831,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(320_367_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(305_607_000 as u64) + // Standard Error: 71_234 + .saturating_add(Weight::from_ref_time(323_093_184 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -840,11 +842,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(239_849_000 as u64) - // Standard Error: 80_000 - .saturating_add(Weight::from_ref_time(67_626_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_351_000 as u64) + // Standard Error: 271_656 + .saturating_add(Weight::from_ref_time(74_344_000 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -855,9 +857,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 106_000 - .saturating_add(Weight::from_ref_time(247_771_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(315_626_000 as u64) + // Standard Error: 56_955 + .saturating_add(Weight::from_ref_time(246_316_261 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -866,11 +868,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(242_162_000 as u64) - // Standard Error: 58_000 - .saturating_add(Weight::from_ref_time(45_169_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(246_887_000 as u64) + // Standard Error: 286_822 + .saturating_add(Weight::from_ref_time(52_242_599 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -881,9 +883,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(97_479_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(294_818_000 as u64) + // Standard Error: 52_394 + .saturating_add(Weight::from_ref_time(96_353_967 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -892,11 +894,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(240_072_000 as u64) - // Standard Error: 53_000 - .saturating_add(Weight::from_ref_time(44_847_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(245_334_000 as u64) + // Standard Error: 303_979 + .saturating_add(Weight::from_ref_time(50_180_800 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -907,9 +909,9 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(97_432_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(288_995_000 as u64) + // Standard Error: 51_161 + .saturating_add(Weight::from_ref_time(96_331_905 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -918,11 +920,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(374_614_000 as u64) - // Standard Error: 634_000 - .saturating_add(Weight::from_ref_time(2_968_637_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(249_935_000 as u64) + // Standard Error: 662_188 + .saturating_add(Weight::from_ref_time(3_025_889_600 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -931,11 +933,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(249_022_000 as u64) - // Standard Error: 408_000 - .saturating_add(Weight::from_ref_time(2_062_013_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(248_094_000 as u64) + // Standard Error: 535_446 + .saturating_add(Weight::from_ref_time(2_086_979_500 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -947,317 +949,319 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 1_536_000 - .saturating_add(Weight::from_ref_time(1_099_219_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads((158 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes((158 as u64).saturating_mul(r as u64))) + Weight::from_ref_time(248_254_000 as u64) + // Standard Error: 1_340_955 + .saturating_add(Weight::from_ref_time(1_065_939_603 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().reads((150 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((150 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(70_276_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(933_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_705_000 as u64) + // Standard Error: 7_175 + .saturating_add(Weight::from_ref_time(983_586 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(70_309_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(2_977_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_659_000 as u64) + // Standard Error: 1_140 + .saturating_add(Weight::from_ref_time(3_004_307 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(71_165_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_686_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_621_000 as u64) + // Standard Error: 2_871 + .saturating_add(Weight::from_ref_time(2_715_451 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(69_872_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_374_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_459_000 as u64) + // Standard Error: 3_284 + .saturating_add(Weight::from_ref_time(2_581_283 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_891_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_629_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_558_000 as u64) + // Standard Error: 2_509 + .saturating_add(Weight::from_ref_time(2_906_689 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(69_747_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_639_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_407_000 as u64) + // Standard Error: 1_697 + .saturating_add(Weight::from_ref_time(1_702_534 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_262_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_142_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_477_000 as u64) + // Standard Error: 1_733 + .saturating_add(Weight::from_ref_time(2_192_641 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(68_808_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_342_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_424_000 as u64) + // Standard Error: 2_096 + .saturating_add(Weight::from_ref_time(2_435_708 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(73_245_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(3_000 as u64).saturating_mul(e as u64)) + Weight::from_ref_time(72_883_000 as u64) + // Standard Error: 209 + .saturating_add(Weight::from_ref_time(6_874 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(71_308_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(7_333_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_422_000 as u64) + // Standard Error: 5_030 + .saturating_add(Weight::from_ref_time(7_638_087 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(83_967_000 as u64) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(9_205_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(83_136_000 as u64) + // Standard Error: 7_751 + .saturating_add(Weight::from_ref_time(9_543_944 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(93_600_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(546_000 as u64).saturating_mul(p as u64)) + Weight::from_ref_time(93_281_000 as u64) + // Standard Error: 1_967 + .saturating_add(Weight::from_ref_time(596_591 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(70_449_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_052_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_702_000 as u64) + // Standard Error: 1_112 + .saturating_add(Weight::from_ref_time(1_094_685 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(70_326_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(998_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_720_000 as u64) + // Standard Error: 1_768 + .saturating_add(Weight::from_ref_time(1_045_163 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(70_525_000 as u64) + Weight::from_ref_time(69_716_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_467_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_541_622 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(73_703_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_495_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_315_000 as u64) + // Standard Error: 1_081 + .saturating_add(Weight::from_ref_time(1_646_437 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(73_578_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_546_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_256_000 as u64) + // Standard Error: 1_749 + .saturating_add(Weight::from_ref_time(1_664_891 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(70_379_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(934_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_616_000 as u64) + // Standard Error: 1_303 + .saturating_add(Weight::from_ref_time(1_017_254 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(71_069_000 as u64) - // Standard Error: 114_000 - .saturating_add(Weight::from_ref_time(182_540_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_943_000 as u64) + // Standard Error: 120_139 + .saturating_add(Weight::from_ref_time(183_262_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(70_188_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_953_000 as u64) + // Standard Error: 2_591 + .saturating_add(Weight::from_ref_time(1_458_584 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(69_970_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_366_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_439_000 as u64) + // Standard Error: 1_822 + .saturating_add(Weight::from_ref_time(1_486_431 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(70_352_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_366_000 as u64) + // Standard Error: 2_674 + .saturating_add(Weight::from_ref_time(1_506_755 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(70_229_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_354_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_386_000 as u64) + // Standard Error: 3_040 + .saturating_add(Weight::from_ref_time(1_509_928 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(70_202_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_432_000 as u64) + // Standard Error: 1_875 + .saturating_add(Weight::from_ref_time(1_439_336 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(70_065_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_488_000 as u64) + // Standard Error: 1_654 + .saturating_add(Weight::from_ref_time(1_429_318 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(70_252_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_414_000 as u64) + // Standard Error: 2_773 + .saturating_add(Weight::from_ref_time(1_499_116 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(70_049_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_823_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_427_000 as u64) + // Standard Error: 2_404 + .saturating_add(Weight::from_ref_time(1_969_697 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(70_519_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_815_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_793_000 as u64) + // Standard Error: 1_765 + .saturating_add(Weight::from_ref_time(1_924_169 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(69_953_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_834_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_551_000 as u64) + // Standard Error: 3_955 + .saturating_add(Weight::from_ref_time(1_988_825 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(70_299_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_818_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_510_000 as u64) + // Standard Error: 3_797 + .saturating_add(Weight::from_ref_time(1_976_317 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(70_141_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_399_000 as u64) + // Standard Error: 3_255 + .saturating_add(Weight::from_ref_time(1_975_054 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(70_209_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_827_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_425_000 as u64) + // Standard Error: 1_738 + .saturating_add(Weight::from_ref_time(1_959_864 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(69_980_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_831_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_514_000 as u64) + // Standard Error: 9_227 + .saturating_add(Weight::from_ref_time(1_984_750 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(70_022_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_829_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_415_000 as u64) + // Standard Error: 2_052 + .saturating_add(Weight::from_ref_time(1_967_146 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(70_030_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_348_000 as u64) + // Standard Error: 3_647 + .saturating_add(Weight::from_ref_time(1_996_141 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(70_170_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_833_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_448_000 as u64) + // Standard Error: 1_960 + .saturating_add(Weight::from_ref_time(1_956_889 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(69_895_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_443_000 as u64) + // Standard Error: 20_301 + .saturating_add(Weight::from_ref_time(2_072_285 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(69_932_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_830_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_458_000 as u64) + // Standard Error: 3_210 + .saturating_add(Weight::from_ref_time(1_970_367 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(70_091_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_429_000 as u64) + // Standard Error: 3_475 + .saturating_add(Weight::from_ref_time(1_977_800 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(70_025_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_556_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_414_000 as u64) + // Standard Error: 2_659 + .saturating_add(Weight::from_ref_time(2_797_503 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(71_910_000 as u64) - // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(2_290_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_460_000 as u64) + // Standard Error: 2_399 + .saturating_add(Weight::from_ref_time(2_646_574 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(70_268_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_550_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_441_000 as u64) + // Standard Error: 2_179 + .saturating_add(Weight::from_ref_time(2_860_283 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(70_126_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_340_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_401_000 as u64) + // Standard Error: 2_639 + .saturating_add(Weight::from_ref_time(2_582_137 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(70_381_000 as u64) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_426_000 as u64) + // Standard Error: 2_379 + .saturating_add(Weight::from_ref_time(1_986_578 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(70_095_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_599_000 as u64) + // Standard Error: 2_918 + .saturating_add(Weight::from_ref_time(1_991_834 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(70_471_000 as u64) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(1_836_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_142_000 as u64) + // Standard Error: 2_659 + .saturating_add(Weight::from_ref_time(1_948_956 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(70_302_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_407_000 as u64) + // Standard Error: 4_100 + .saturating_add(Weight::from_ref_time(2_030_715 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(70_097_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_534_000 as u64) + // Standard Error: 2_305 + .saturating_add(Weight::from_ref_time(1_989_346 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(70_166_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_845_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_432_000 as u64) + // Standard Error: 2_747 + .saturating_add(Weight::from_ref_time(2_002_548 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(69_630_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_879_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_465_000 as u64) + // Standard Error: 9_644 + .saturating_add(Weight::from_ref_time(2_045_830 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(70_101_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_861_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_435_000 as u64) + // Standard Error: 2_271 + .saturating_add(Weight::from_ref_time(2_001_986 as u64).saturating_mul(r as u64)) } } @@ -1265,15 +1269,15 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(3_089_000 as u64) + Weight::from_ref_time(3_108_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(13_917_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(k as u64)) + Weight::from_ref_time(15_377_000 as u64) + // Standard Error: 414 + .saturating_add(Weight::from_ref_time(892_761 as u64).saturating_mul(k as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -1281,19 +1285,18 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(14_172_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_301_000 as u64).saturating_mul(q as u64)) + Weight::from_ref_time(3_127_000 as u64) + // Standard Error: 3_813 + .saturating_add(Weight::from_ref_time(1_379_402 as u64).saturating_mul(q as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(21_644_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(22_849_000 as u64) + // Standard Error: 26 + .saturating_add(Weight::from_ref_time(45_513 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1304,9 +1307,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(234_349_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(258_275_000 as u64) + // Standard Error: 30 + .saturating_add(Weight::from_ref_time(45_885 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1321,11 +1324,11 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(294_077_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(c as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(2_115_889_000 as u64) + // Standard Error: 323 + .saturating_add(Weight::from_ref_time(89_541 as u64).saturating_mul(c as u64)) + // Standard Error: 19 + .saturating_add(Weight::from_ref_time(664 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(9 as u64)) } @@ -1338,9 +1341,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(199_028_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(211_349_000 as u64) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(1_532 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(7 as u64)) } @@ -1350,7 +1353,7 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(176_247_000 as u64) + Weight::from_ref_time(181_771_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1360,9 +1363,9 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(54_917_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(55_917_000 as u64) + // Standard Error: 25 + .saturating_add(Weight::from_ref_time(46_148 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1371,7 +1374,7 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(37_611_000 as u64) + Weight::from_ref_time(37_966_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1379,7 +1382,7 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(40_121_000 as u64) + Weight::from_ref_time(40_963_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -1390,9 +1393,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(241_129_000 as u64) - // Standard Error: 54_000 - .saturating_add(Weight::from_ref_time(35_413_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_526_000 as u64) + // Standard Error: 29_505 + .saturating_add(Weight::from_ref_time(35_107_467 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1403,9 +1406,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(189_418_000 as u64) - // Standard Error: 419_000 - .saturating_add(Weight::from_ref_time(207_107_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(253_782_000 as u64) + // Standard Error: 256_004 + .saturating_add(Weight::from_ref_time(201_621_188 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1417,9 +1420,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(203_928_000 as u64) - // Standard Error: 439_000 - .saturating_add(Weight::from_ref_time(268_983_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(249_892_000 as u64) + // Standard Error: 234_750 + .saturating_add(Weight::from_ref_time(258_209_168 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1431,9 +1434,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(243_800_000 as u64) - // Standard Error: 40_000 - .saturating_add(Weight::from_ref_time(38_797_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(248_674_000 as u64) + // Standard Error: 23_962 + .saturating_add(Weight::from_ref_time(38_319_695 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1444,9 +1447,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(239_667_000 as u64) - // Standard Error: 27_000 - .saturating_add(Weight::from_ref_time(15_826_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_345_000 as u64) + // Standard Error: 15_429 + .saturating_add(Weight::from_ref_time(14_751_125 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1457,9 +1460,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(241_116_000 as u64) - // Standard Error: 41_000 - .saturating_add(Weight::from_ref_time(35_402_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_045_000 as u64) + // Standard Error: 25_949 + .saturating_add(Weight::from_ref_time(35_001_004 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1470,9 +1473,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(240_515_000 as u64) - // Standard Error: 50_000 - .saturating_add(Weight::from_ref_time(35_144_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_176_000 as u64) + // Standard Error: 24_500 + .saturating_add(Weight::from_ref_time(34_447_506 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1483,10 +1486,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(244_087_000 as u64) - // Standard Error: 87_000 - .saturating_add(Weight::from_ref_time(110_236_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) + Weight::from_ref_time(247_278_000 as u64) + // Standard Error: 48_613 + .saturating_add(Weight::from_ref_time(108_381_432 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -1496,9 +1499,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(241_774_000 as u64) - // Standard Error: 50_000 - .saturating_add(Weight::from_ref_time(35_216_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(246_996_000 as u64) + // Standard Error: 24_585 + .saturating_add(Weight::from_ref_time(34_615_777 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1509,9 +1512,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(241_146_000 as u64) - // Standard Error: 54_000 - .saturating_add(Weight::from_ref_time(35_101_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_207_000 as u64) + // Standard Error: 30_691 + .saturating_add(Weight::from_ref_time(34_626_552 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1522,9 +1525,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(244_096_000 as u64) - // Standard Error: 55_000 - .saturating_add(Weight::from_ref_time(34_612_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_538_000 as u64) + // Standard Error: 27_128 + .saturating_add(Weight::from_ref_time(34_277_292 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1535,9 +1538,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(242_978_000 as u64) - // Standard Error: 53_000 - .saturating_add(Weight::from_ref_time(34_780_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_398_000 as u64) + // Standard Error: 28_375 + .saturating_add(Weight::from_ref_time(34_573_437 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1549,10 +1552,10 @@ impl WeightInfo for () { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(246_175_000 as u64) - // Standard Error: 86_000 - .saturating_add(Weight::from_ref_time(99_827_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) + Weight::from_ref_time(247_732_000 as u64) + // Standard Error: 42_671 + .saturating_add(Weight::from_ref_time(123_110_886 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -1562,9 +1565,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(168_655_000 as u64) - // Standard Error: 16_000 - .saturating_add(Weight::from_ref_time(15_635_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(170_547_000 as u64) + // Standard Error: 9_163 + .saturating_add(Weight::from_ref_time(15_589_088 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1575,9 +1578,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(239_729_000 as u64) - // Standard Error: 52_000 - .saturating_add(Weight::from_ref_time(33_477_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_264_000 as u64) + // Standard Error: 23_913 + .saturating_add(Weight::from_ref_time(32_753_431 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1588,9 +1591,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(296_718_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_616_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(282_721_000 as u64) + // Standard Error: 1_978 + .saturating_add(Weight::from_ref_time(9_625_699 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1601,9 +1604,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - Weight::from_ref_time(237_666_000 as u64) - // Standard Error: 497_000 - .saturating_add(Weight::from_ref_time(2_090_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_356_000 as u64) + // Standard Error: 184_002 + .saturating_add(Weight::from_ref_time(2_423_400 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1614,9 +1617,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(239_842_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(246_157_000 as u64) + // Standard Error: 324 + .saturating_add(Weight::from_ref_time(188_687 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1629,9 +1632,9 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(240_563_000 as u64) - // Standard Error: 519_000 - .saturating_add(Weight::from_ref_time(52_855_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_356_000 as u64) + // Standard Error: 232_552 + .saturating_add(Weight::from_ref_time(55_027_099 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1645,10 +1648,10 @@ impl WeightInfo for () { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(248_136_000 as u64) - // Standard Error: 94_000 - .saturating_add(Weight::from_ref_time(137_406_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) + Weight::from_ref_time(247_069_000 as u64) + // Standard Error: 59_538 + .saturating_add(Weight::from_ref_time(128_858_347 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -1658,9 +1661,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(253_433_000 as u64) - // Standard Error: 105_000 - .saturating_add(Weight::from_ref_time(242_337_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(244_659_000 as u64) + // Standard Error: 70_677 + .saturating_add(Weight::from_ref_time(239_930_533 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1672,11 +1675,11 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(478_106_000 as u64) - // Standard Error: 557_000 - .saturating_add(Weight::from_ref_time(176_325_000 as u64).saturating_mul(t as u64)) - // Standard Error: 153_000 - .saturating_add(Weight::from_ref_time(67_413_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(1_198_350_000 as u64) + // Standard Error: 2_049_556 + .saturating_add(Weight::from_ref_time(70_072_141 as u64).saturating_mul(t as u64)) + // Standard Error: 496_378 + .saturating_add(Weight::from_ref_time(35_566_752 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1689,18 +1692,18 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(172_751_000 as u64) - // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(26_536_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(177_240_000 as u64) + // Standard Error: 18_991 + .saturating_add(Weight::from_ref_time(26_377_453 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(196_276_000 as u64) - // Standard Error: 428_000 - .saturating_add(Weight::from_ref_time(416_783_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_795_000 as u64) + // Standard Error: 349_627 + .saturating_add(Weight::from_ref_time(411_421_066 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1709,53 +1712,53 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(532_439_000 as u64) - // Standard Error: 1_323_000 - .saturating_add(Weight::from_ref_time(93_843_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(52 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(50 as u64)) - .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(405_147_000 as u64) + // Standard Error: 1_074_466 + .saturating_add(Weight::from_ref_time(120_331_835 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) + .saturating_add(RocksDbWeight::get().writes((15 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(511_358_000 as u64) - // Standard Error: 1_144_000 - .saturating_add(Weight::from_ref_time(68_754_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(52 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(50 as u64)) - .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(403_403_000 as u64) + // Standard Error: 890_083 + .saturating_add(Weight::from_ref_time(88_023_518 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) + .saturating_add(RocksDbWeight::get().writes((15 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(204_133_000 as u64) - // Standard Error: 498_000 - .saturating_add(Weight::from_ref_time(406_798_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) + Weight::from_ref_time(247_929_000 as u64) + // Standard Error: 311_780 + .saturating_add(Weight::from_ref_time(400_904_526 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(489_339_000 as u64) - // Standard Error: 1_269_000 - .saturating_add(Weight::from_ref_time(70_700_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(51 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(49 as u64)) - .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(372_378_000 as u64) + // Standard Error: 1_007_061 + .saturating_add(Weight::from_ref_time(92_326_546 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes((15 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(211_344_000 as u64) - // Standard Error: 399_000 - .saturating_add(Weight::from_ref_time(330_244_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(250_165_000 as u64) + // Standard Error: 300_205 + .saturating_add(Weight::from_ref_time(339_092_950 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1763,19 +1766,19 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(449_353_000 as u64) - // Standard Error: 1_027_000 - .saturating_add(Weight::from_ref_time(153_022_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(51 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(352_873_000 as u64) + // Standard Error: 908_425 + .saturating_add(Weight::from_ref_time(176_951_688 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(216_197_000 as u64) - // Standard Error: 341_000 - .saturating_add(Weight::from_ref_time(305_401_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(248_980_000 as u64) + // Standard Error: 295_923 + .saturating_add(Weight::from_ref_time(306_145_709 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1783,34 +1786,34 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(423_033_000 as u64) - // Standard Error: 878_000 - .saturating_add(Weight::from_ref_time(61_940_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(51 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(340_418_000 as u64) + // Standard Error: 749_537 + .saturating_add(Weight::from_ref_time(80_040_174 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(204_244_000 as u64) - // Standard Error: 448_000 - .saturating_add(Weight::from_ref_time(429_399_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) + Weight::from_ref_time(250_254_000 as u64) + // Standard Error: 328_900 + .saturating_add(Weight::from_ref_time(424_144_552 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(516_945_000 as u64) - // Standard Error: 1_412_000 - .saturating_add(Weight::from_ref_time(162_098_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(52 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(49 as u64)) - .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(377_849_000 as u64) + // Standard Error: 1_130_582 + .saturating_add(Weight::from_ref_time(188_240_273 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) + .saturating_add(RocksDbWeight::get().writes((15 as u64).saturating_mul(n as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1819,12 +1822,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(170_412_000 as u64) - // Standard Error: 761_000 - .saturating_add(Weight::from_ref_time(1_367_307_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) + Weight::from_ref_time(249_701_000 as u64) + // Standard Error: 449_896 + .saturating_add(Weight::from_ref_time(1_370_712_846 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) @@ -1834,10 +1837,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 9_269_000 - .saturating_add(Weight::from_ref_time(17_505_281_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) + Weight::from_ref_time(251_015_000 as u64) + // Standard Error: 7_081_378 + .saturating_add(Weight::from_ref_time(17_258_935_295 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((160 as u64).saturating_mul(r as u64))) @@ -1849,11 +1852,13 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 8_780_000 - .saturating_add(Weight::from_ref_time(17_368_867_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads((158 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes((79 as u64).saturating_mul(r as u64))) + Weight::from_ref_time(250_660_000 as u64) + // Standard Error: 6_402_989 + .saturating_add(Weight::from_ref_time(17_044_780_887 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().reads((150 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((75 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -1863,11 +1868,11 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(11_076_579_000 as u64) - // Standard Error: 6_568_000 - .saturating_add(Weight::from_ref_time(1_158_818_000 as u64).saturating_mul(t as u64)) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(9_731_000 as u64).saturating_mul(c as u64)) + Weight::from_ref_time(11_920_718_000 as u64) + // Standard Error: 11_123_062 + .saturating_add(Weight::from_ref_time(642_326_761 as u64).saturating_mul(t as u64)) + // Standard Error: 9_490 + .saturating_add(Weight::from_ref_time(8_845_752 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(167 as u64)) .saturating_add(RocksDbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(163 as u64)) @@ -1882,12 +1887,12 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 24_125_000 - .saturating_add(Weight::from_ref_time(22_830_521_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) + Weight::from_ref_time(253_804_000 as u64) + // Standard Error: 19_742_198 + .saturating_add(Weight::from_ref_time(22_250_412_835 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((400 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((400 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:81 w:81) @@ -1900,9 +1905,9 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(13_739_440_000 as u64) - // Standard Error: 79_000 - .saturating_add(Weight::from_ref_time(126_148_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(13_921_591_000 as u64) + // Standard Error: 22_601 + .saturating_add(Weight::from_ref_time(125_945_348 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(249 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(247 as u64)) @@ -1913,11 +1918,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(241_753_000 as u64) - // Standard Error: 60_000 - .saturating_add(Weight::from_ref_time(55_067_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_842_000 as u64) + // Standard Error: 219_853 + .saturating_add(Weight::from_ref_time(58_013_100 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1928,9 +1933,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(320_367_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(305_607_000 as u64) + // Standard Error: 71_234 + .saturating_add(Weight::from_ref_time(323_093_184 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1939,11 +1944,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(239_849_000 as u64) - // Standard Error: 80_000 - .saturating_add(Weight::from_ref_time(67_626_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(247_351_000 as u64) + // Standard Error: 271_656 + .saturating_add(Weight::from_ref_time(74_344_000 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1954,9 +1959,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 106_000 - .saturating_add(Weight::from_ref_time(247_771_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(315_626_000 as u64) + // Standard Error: 56_955 + .saturating_add(Weight::from_ref_time(246_316_261 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1965,11 +1970,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(242_162_000 as u64) - // Standard Error: 58_000 - .saturating_add(Weight::from_ref_time(45_169_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(246_887_000 as u64) + // Standard Error: 286_822 + .saturating_add(Weight::from_ref_time(52_242_599 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1980,9 +1985,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(97_479_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(294_818_000 as u64) + // Standard Error: 52_394 + .saturating_add(Weight::from_ref_time(96_353_967 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1991,11 +1996,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(240_072_000 as u64) - // Standard Error: 53_000 - .saturating_add(Weight::from_ref_time(44_847_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(245_334_000 as u64) + // Standard Error: 303_979 + .saturating_add(Weight::from_ref_time(50_180_800 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2006,9 +2011,9 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(97_432_000 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(288_995_000 as u64) + // Standard Error: 51_161 + .saturating_add(Weight::from_ref_time(96_331_905 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2017,11 +2022,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(374_614_000 as u64) - // Standard Error: 634_000 - .saturating_add(Weight::from_ref_time(2_968_637_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(249_935_000 as u64) + // Standard Error: 662_188 + .saturating_add(Weight::from_ref_time(3_025_889_600 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2030,11 +2035,11 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System EventTopics (r:2 w:2) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(249_022_000 as u64) - // Standard Error: 408_000 - .saturating_add(Weight::from_ref_time(2_062_013_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(248_094_000 as u64) + // Standard Error: 535_446 + .saturating_add(Weight::from_ref_time(2_086_979_500 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2046,316 +2051,318 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 1_536_000 - .saturating_add(Weight::from_ref_time(1_099_219_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads((158 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes((158 as u64).saturating_mul(r as u64))) + Weight::from_ref_time(248_254_000 as u64) + // Standard Error: 1_340_955 + .saturating_add(Weight::from_ref_time(1_065_939_603 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().reads((150 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((150 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(70_276_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(933_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_705_000 as u64) + // Standard Error: 7_175 + .saturating_add(Weight::from_ref_time(983_586 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(70_309_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(2_977_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_659_000 as u64) + // Standard Error: 1_140 + .saturating_add(Weight::from_ref_time(3_004_307 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(71_165_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_686_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_621_000 as u64) + // Standard Error: 2_871 + .saturating_add(Weight::from_ref_time(2_715_451 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(69_872_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_374_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_459_000 as u64) + // Standard Error: 3_284 + .saturating_add(Weight::from_ref_time(2_581_283 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_891_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_629_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_558_000 as u64) + // Standard Error: 2_509 + .saturating_add(Weight::from_ref_time(2_906_689 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(69_747_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_639_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_407_000 as u64) + // Standard Error: 1_697 + .saturating_add(Weight::from_ref_time(1_702_534 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_262_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_142_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_477_000 as u64) + // Standard Error: 1_733 + .saturating_add(Weight::from_ref_time(2_192_641 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(68_808_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_342_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_424_000 as u64) + // Standard Error: 2_096 + .saturating_add(Weight::from_ref_time(2_435_708 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(73_245_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(3_000 as u64).saturating_mul(e as u64)) + Weight::from_ref_time(72_883_000 as u64) + // Standard Error: 209 + .saturating_add(Weight::from_ref_time(6_874 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(71_308_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(7_333_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_422_000 as u64) + // Standard Error: 5_030 + .saturating_add(Weight::from_ref_time(7_638_087 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(83_967_000 as u64) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(9_205_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(83_136_000 as u64) + // Standard Error: 7_751 + .saturating_add(Weight::from_ref_time(9_543_944 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(93_600_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(546_000 as u64).saturating_mul(p as u64)) + Weight::from_ref_time(93_281_000 as u64) + // Standard Error: 1_967 + .saturating_add(Weight::from_ref_time(596_591 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(70_449_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_052_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_702_000 as u64) + // Standard Error: 1_112 + .saturating_add(Weight::from_ref_time(1_094_685 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(70_326_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(998_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_720_000 as u64) + // Standard Error: 1_768 + .saturating_add(Weight::from_ref_time(1_045_163 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(70_525_000 as u64) + Weight::from_ref_time(69_716_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_467_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_541_622 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(73_703_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_495_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_315_000 as u64) + // Standard Error: 1_081 + .saturating_add(Weight::from_ref_time(1_646_437 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(73_578_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_546_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(72_256_000 as u64) + // Standard Error: 1_749 + .saturating_add(Weight::from_ref_time(1_664_891 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(70_379_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(934_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_616_000 as u64) + // Standard Error: 1_303 + .saturating_add(Weight::from_ref_time(1_017_254 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(71_069_000 as u64) - // Standard Error: 114_000 - .saturating_add(Weight::from_ref_time(182_540_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_943_000 as u64) + // Standard Error: 120_139 + .saturating_add(Weight::from_ref_time(183_262_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(70_188_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_953_000 as u64) + // Standard Error: 2_591 + .saturating_add(Weight::from_ref_time(1_458_584 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(69_970_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_366_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_439_000 as u64) + // Standard Error: 1_822 + .saturating_add(Weight::from_ref_time(1_486_431 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(70_352_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_366_000 as u64) + // Standard Error: 2_674 + .saturating_add(Weight::from_ref_time(1_506_755 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(70_229_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_354_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_386_000 as u64) + // Standard Error: 3_040 + .saturating_add(Weight::from_ref_time(1_509_928 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(70_202_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_432_000 as u64) + // Standard Error: 1_875 + .saturating_add(Weight::from_ref_time(1_439_336 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(70_065_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_488_000 as u64) + // Standard Error: 1_654 + .saturating_add(Weight::from_ref_time(1_429_318 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(70_252_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_414_000 as u64) + // Standard Error: 2_773 + .saturating_add(Weight::from_ref_time(1_499_116 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(70_049_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_823_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_427_000 as u64) + // Standard Error: 2_404 + .saturating_add(Weight::from_ref_time(1_969_697 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(70_519_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_815_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_793_000 as u64) + // Standard Error: 1_765 + .saturating_add(Weight::from_ref_time(1_924_169 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(69_953_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_834_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_551_000 as u64) + // Standard Error: 3_955 + .saturating_add(Weight::from_ref_time(1_988_825 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(70_299_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_818_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_510_000 as u64) + // Standard Error: 3_797 + .saturating_add(Weight::from_ref_time(1_976_317 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(70_141_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_399_000 as u64) + // Standard Error: 3_255 + .saturating_add(Weight::from_ref_time(1_975_054 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(70_209_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_827_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_425_000 as u64) + // Standard Error: 1_738 + .saturating_add(Weight::from_ref_time(1_959_864 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(69_980_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_831_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_514_000 as u64) + // Standard Error: 9_227 + .saturating_add(Weight::from_ref_time(1_984_750 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(70_022_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_829_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_415_000 as u64) + // Standard Error: 2_052 + .saturating_add(Weight::from_ref_time(1_967_146 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(70_030_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_348_000 as u64) + // Standard Error: 3_647 + .saturating_add(Weight::from_ref_time(1_996_141 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(70_170_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_833_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_448_000 as u64) + // Standard Error: 1_960 + .saturating_add(Weight::from_ref_time(1_956_889 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(69_895_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_443_000 as u64) + // Standard Error: 20_301 + .saturating_add(Weight::from_ref_time(2_072_285 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(69_932_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_830_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_458_000 as u64) + // Standard Error: 3_210 + .saturating_add(Weight::from_ref_time(1_970_367 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(70_091_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_429_000 as u64) + // Standard Error: 3_475 + .saturating_add(Weight::from_ref_time(1_977_800 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(70_025_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_556_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_414_000 as u64) + // Standard Error: 2_659 + .saturating_add(Weight::from_ref_time(2_797_503 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(71_910_000 as u64) - // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(2_290_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_460_000 as u64) + // Standard Error: 2_399 + .saturating_add(Weight::from_ref_time(2_646_574 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(70_268_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_550_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_441_000 as u64) + // Standard Error: 2_179 + .saturating_add(Weight::from_ref_time(2_860_283 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(70_126_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_340_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_401_000 as u64) + // Standard Error: 2_639 + .saturating_add(Weight::from_ref_time(2_582_137 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(70_381_000 as u64) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_426_000 as u64) + // Standard Error: 2_379 + .saturating_add(Weight::from_ref_time(1_986_578 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(70_095_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_599_000 as u64) + // Standard Error: 2_918 + .saturating_add(Weight::from_ref_time(1_991_834 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(70_471_000 as u64) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(1_836_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_142_000 as u64) + // Standard Error: 2_659 + .saturating_add(Weight::from_ref_time(1_948_956 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(70_302_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_407_000 as u64) + // Standard Error: 4_100 + .saturating_add(Weight::from_ref_time(2_030_715 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(70_097_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_534_000 as u64) + // Standard Error: 2_305 + .saturating_add(Weight::from_ref_time(1_989_346 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(70_166_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_845_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_432_000 as u64) + // Standard Error: 2_747 + .saturating_add(Weight::from_ref_time(2_002_548 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(69_630_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_879_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_465_000 as u64) + // Standard Error: 9_644 + .saturating_add(Weight::from_ref_time(2_045_830 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(70_101_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_861_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_435_000 as u64) + // Standard Error: 2_271 + .saturating_add(Weight::from_ref_time(2_001_986 as u64).saturating_mul(r as u64)) } } From f5ed51def33950ac24709eb11940790ca446421d Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 20 Oct 2022 08:44:04 +0200 Subject: [PATCH 1293/1472] BlockId removal: refactor: Finalizer (#12528) * BlockId removal: refactor: Finalizer It changes the arguments of methods of `Finalizer` trait from: block: `BlockId` to: hash: `&Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) * minor corrections * failing test corrected * minor rework --- client/api/src/backend.rs | 4 +- client/beefy/src/tests.rs | 70 ++++++++----------- client/beefy/src/worker.rs | 8 +-- client/consensus/babe/src/tests.rs | 10 +-- .../manual-seal/src/finalize_block.rs | 4 +- client/finality-grandpa/src/environment.rs | 2 +- client/finality-grandpa/src/finality_proof.rs | 5 +- client/finality-grandpa/src/tests.rs | 14 +++- client/finality-grandpa/src/warp_proof.rs | 7 +- client/network/sync/src/lib.rs | 8 +-- client/network/test/src/lib.rs | 6 +- client/network/test/src/sync.rs | 42 ++++++----- client/rpc/src/chain/tests.rs | 8 ++- client/service/src/client/client.rs | 23 +++--- client/service/test/src/client/mod.rs | 12 ++-- test-utils/client/src/client_ext.rs | 8 +-- 16 files changed, 113 insertions(+), 118 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index f358385acd708..5b4acb0be8bda 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -252,7 +252,7 @@ pub trait Finalizer> { fn apply_finality( &self, operation: &mut ClientImportOperation, - id: BlockId, + block: &Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()>; @@ -272,7 +272,7 @@ pub trait Finalizer> { /// while performing major synchronization work. fn finalize_block( &self, - id: BlockId, + block: &Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()>; diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 89be1cac4f886..d280e4f08a531 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -509,14 +509,10 @@ fn finalize_block_and_wait_for_beefy( let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); for block in finalize_targets { - let finalize = BlockId::number(*block); peers.clone().for_each(|(index, _)| { - net.lock() - .peer(index) - .client() - .as_client() - .finalize_block(finalize, None) - .unwrap(); + let client = net.lock().peer(index).client().as_client(); + let finalize = client.expect_block_hash_from_id(&BlockId::number(*block)).unwrap(); + client.finalize_block(&finalize, None).unwrap(); }) } @@ -604,9 +600,15 @@ fn lagging_validators() { ); // Alice finalizes #25, Bob lags behind - let finalize = BlockId::number(25); + let finalize = net + .lock() + .peer(0) + .client() + .as_client() + .expect_block_hash_from_id(&BlockId::number(25)) + .unwrap(); let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); + net.lock().peer(0).client().as_client().finalize_block(&finalize, None).unwrap(); // verify nothing gets finalized by BEEFY let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); @@ -614,7 +616,7 @@ fn lagging_validators() { // Bob catches up and also finalizes #25 let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); + net.lock().peer(1).client().as_client().finalize_block(&finalize, None).unwrap(); // expected beefy finalizes block #17 from diff-power-of-two wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[23, 24, 25]); wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[23, 24, 25]); @@ -628,8 +630,14 @@ fn lagging_validators() { // Alice finalizes session-boundary mandatory block #60, Bob lags behind let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - let finalize = BlockId::number(60); - net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); + let finalize = net + .lock() + .peer(0) + .client() + .as_client() + .expect_block_hash_from_id(&BlockId::number(60)) + .unwrap(); + net.lock().peer(0).client().as_client().finalize_block(&finalize, None).unwrap(); // verify nothing gets finalized by BEEFY let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); @@ -637,7 +645,7 @@ fn lagging_validators() { // Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60) let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); - net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); + net.lock().peer(1).client().as_client().finalize_block(&finalize, None).unwrap(); // verify beefy skips intermediary votes, and successfully finalizes mandatory block #60 wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]); wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[60]); @@ -681,24 +689,16 @@ fn correct_beefy_payload() { get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); // now 2 good validators and 1 bad one are voting - net.lock() + let hashof11 = net + .lock() .peer(0) .client() .as_client() - .finalize_block(BlockId::number(11), None) - .unwrap(); - net.lock() - .peer(1) - .client() - .as_client() - .finalize_block(BlockId::number(11), None) - .unwrap(); - net.lock() - .peer(3) - .client() - .as_client() - .finalize_block(BlockId::number(11), None) + .expect_block_hash_from_id(&BlockId::number(11)) .unwrap(); + net.lock().peer(0).client().as_client().finalize_block(&hashof11, None).unwrap(); + net.lock().peer(1).client().as_client().finalize_block(&hashof11, None).unwrap(); + net.lock().peer(3).client().as_client().finalize_block(&hashof11, None).unwrap(); // verify consensus is _not_ reached let timeout = Some(Duration::from_millis(250)); @@ -708,12 +708,7 @@ fn correct_beefy_payload() { // 3rd good validator catches up and votes as well let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); - net.lock() - .peer(2) - .client() - .as_client() - .finalize_block(BlockId::number(11), None) - .unwrap(); + net.lock().peer(2).client().as_client().finalize_block(&hashof11, None).unwrap(); // verify consensus is reached wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[11]); @@ -923,12 +918,9 @@ fn on_demand_beefy_justification_sync() { let (dave_best_blocks, _) = get_beefy_streams(&mut net.lock(), [(dave_index, BeefyKeyring::Dave)].into_iter()); - net.lock() - .peer(dave_index) - .client() - .as_client() - .finalize_block(BlockId::number(1), None) - .unwrap(); + let client = net.lock().peer(dave_index).client().as_client(); + let hashof1 = client.expect_block_hash_from_id(&BlockId::number(1)).unwrap(); + client.finalize_block(&hashof1, None).unwrap(); // Give Dave task some cpu cycles to process the finality notification, run_for(Duration::from_millis(100), &net, &mut runtime); // freshly spun up Dave now needs to listen for gossip to figure out the state of his peers. diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 4381081f74ebd..6efebd131d6da 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -1506,11 +1506,9 @@ pub(crate) mod tests { // push 15 blocks with `AuthorityChange` digests every 10 blocks net.generate_blocks_and_sync(15, 10, &validator_set, false); // finalize 13 without justifications - net.peer(0) - .client() - .as_client() - .finalize_block(BlockId::number(13), None) - .unwrap(); + let hashof13 = + backend.blockchain().expect_block_hash_from_id(&BlockId::Number(13)).unwrap(); + net.peer(0).client().as_client().finalize_block(&hashof13, None).unwrap(); // Test initialization at session boundary. { diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 58f5e7b8eb6d4..24185dbce6795 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -820,7 +820,7 @@ fn revert_not_allowed_for_finalized() { let canon = propose_and_import_blocks_wrap(BlockId::Number(0), 3); // Finalize best block - client.finalize_block(BlockId::Hash(canon[2]), None, false).unwrap(); + client.finalize_block(&canon[2], None, false).unwrap(); // Revert canon chain to last finalized block revert(client.clone(), backend, 100).expect("revert should work for baked test scenario"); @@ -882,7 +882,7 @@ fn importing_epoch_change_block_prunes_tree() { // We finalize block #13 from the canon chain, so on the next epoch // change the tree should be pruned, to not contain F (#7). - client.finalize_block(BlockId::Hash(canon_hashes[12]), None, false).unwrap(); + client.finalize_block(&canon_hashes[12], None, false).unwrap(); propose_and_import_blocks_wrap(BlockId::Hash(client.chain_info().best_hash), 7); // at this point no hashes from the first fork must exist on the tree @@ -909,7 +909,7 @@ fn importing_epoch_change_block_prunes_tree() { .any(|h| fork_3.contains(h)),); // finalizing block #25 from the canon chain should prune out the second fork - client.finalize_block(BlockId::Hash(canon_hashes[24]), None, false).unwrap(); + client.finalize_block(&canon_hashes[24], None, false).unwrap(); propose_and_import_blocks_wrap(BlockId::Hash(client.chain_info().best_hash), 8); // at this point no hashes from the second fork must exist on the tree @@ -1049,7 +1049,7 @@ fn obsolete_blocks_aux_data_cleanup() { assert!(aux_data_check(&fork3_hashes, true)); // Finalize A3 - client.finalize_block(BlockId::Number(3), None, true).unwrap(); + client.finalize_block(&fork1_hashes[2], None, true).unwrap(); // Wiped: A1, A2 assert!(aux_data_check(&fork1_hashes[..2], false)); @@ -1060,7 +1060,7 @@ fn obsolete_blocks_aux_data_cleanup() { // Present C4, C5 assert!(aux_data_check(&fork3_hashes, true)); - client.finalize_block(BlockId::Number(4), None, true).unwrap(); + client.finalize_block(&fork1_hashes[3], None, true).unwrap(); // Wiped: A3 assert!(aux_data_check(&fork1_hashes[2..3], false)); diff --git a/client/consensus/manual-seal/src/finalize_block.rs b/client/consensus/manual-seal/src/finalize_block.rs index d134ce7734571..e11353e2da611 100644 --- a/client/consensus/manual-seal/src/finalize_block.rs +++ b/client/consensus/manual-seal/src/finalize_block.rs @@ -20,7 +20,7 @@ use crate::rpc; use sc_client_api::backend::{Backend as ClientBackend, Finalizer}; -use sp_runtime::{generic::BlockId, traits::Block as BlockT, Justification}; +use sp_runtime::{traits::Block as BlockT, Justification}; use std::{marker::PhantomData, sync::Arc}; /// params for block finalization. @@ -46,7 +46,7 @@ where { let FinalizeBlockParams { hash, mut sender, justification, finalizer, .. } = params; - match finalizer.finalize_block(BlockId::Hash(hash), justification, true) { + match finalizer.finalize_block(&hash, justification, true) { Err(e) => { log::warn!("Failed to finalize block {}", e); rpc::send_result(&mut sender, Err(e.into())) diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 3d708a95f41cb..60720494a9f9a 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -1352,7 +1352,7 @@ where // ideally some handle to a synchronization oracle would be used // to avoid unconditionally notifying. client - .apply_finality(import_op, BlockId::Hash(hash), persisted_justification, true) + .apply_finality(import_op, &hash, persisted_justification, true) .map_err(|e| { warn!(target: "afg", "Error applying finality to block {:?}: {}", (hash, number), e); e diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index e7578fa669463..a7042e26b1a71 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -309,7 +309,8 @@ mod tests { } for block in to_finalize { - client.finalize_block(BlockId::Number(*block), None).unwrap(); + let hash = blocks[*block as usize - 1].hash(); + client.finalize_block(&hash, None).unwrap(); } (client, backend, blocks) } @@ -489,7 +490,7 @@ mod tests { let grandpa_just8 = GrandpaJustification::from_commit(&client, round, commit).unwrap(); client - .finalize_block(BlockId::Number(8), Some((ID, grandpa_just8.encode().clone()))) + .finalize_block(&block8.hash(), Some((ID, grandpa_just8.encode().clone()))) .unwrap(); // Authority set change at block 8, so the justification stored there will be used in the diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index b1e46be5cabde..c04754411af1a 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -1457,7 +1457,12 @@ fn grandpa_environment_respects_voting_rules() { ); // we finalize block 19 with block 21 being the best block - peer.client().finalize_block(BlockId::Number(19), None, false).unwrap(); + let hashof19 = peer + .client() + .as_client() + .expect_block_hash_from_id(&BlockId::Number(19)) + .unwrap(); + peer.client().finalize_block(&hashof19, None, false).unwrap(); // the 3/4 environment should propose block 21 for voting assert_eq!( @@ -1479,7 +1484,12 @@ fn grandpa_environment_respects_voting_rules() { ); // we finalize block 21 with block 21 being the best block - peer.client().finalize_block(BlockId::Number(21), None, false).unwrap(); + let hashof21 = peer + .client() + .as_client() + .expect_block_hash_from_id(&BlockId::Number(21)) + .unwrap(); + peer.client().finalize_block(&hashof21, None, false).unwrap(); // even though the default environment will always try to not vote on the // best block, there's a hard rule that we can't cast any votes lower than diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index a31a0a8b91908..10d02f790a0dc 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -327,7 +327,7 @@ mod tests { use sp_consensus::BlockOrigin; use sp_finality_grandpa::GRANDPA_ENGINE_ID; use sp_keyring::Ed25519Keyring; - use sp_runtime::{generic::BlockId, traits::Header as _}; + use sp_runtime::traits::Header as _; use std::sync::Arc; use substrate_test_runtime_client::{ ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, TestClientBuilder, @@ -412,10 +412,7 @@ mod tests { let justification = GrandpaJustification::from_commit(&client, 42, commit).unwrap(); client - .finalize_block( - BlockId::Hash(target_hash), - Some((GRANDPA_ENGINE_ID, justification.encode())), - ) + .finalize_block(&target_hash, Some((GRANDPA_ENGINE_ID, justification.encode()))) .unwrap(); authority_set_changes.push((current_set_id, n)); diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index e9c2b24b2ba95..76d7d624be523 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -3172,9 +3172,7 @@ mod test { let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); let just = (*b"TEST", Vec::new()); - client - .finalize_block(BlockId::Hash(finalized_block.hash()), Some(just)) - .unwrap(); + client.finalize_block(&finalized_block.hash(), Some(just)).unwrap(); sync.update_chain_info(&info.best_hash, info.best_number); let peer_id1 = PeerId::random(); @@ -3303,9 +3301,7 @@ mod test { let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); let just = (*b"TEST", Vec::new()); - client - .finalize_block(BlockId::Hash(finalized_block.hash()), Some(just)) - .unwrap(); + client.finalize_block(&finalized_block.hash(), Some(just)).unwrap(); sync.update_chain_info(&info.best_hash, info.best_number); let peer_id1 = PeerId::random(); diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index d4bee77b54aff..5460cc7d52461 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -190,11 +190,11 @@ impl PeersClient { pub fn finalize_block( &self, - id: BlockId, + hash: &::Hash, justification: Option, notify: bool, ) -> ClientResult<()> { - self.client.finalize_block(id, justification, notify) + self.client.finalize_block(hash, justification, notify) } } @@ -1113,7 +1113,7 @@ impl JustificationImport for ForceFinalized { justification: Justification, ) -> Result<(), Self::Error> { self.0 - .finalize_block(BlockId::Hash(hash), Some(justification), true) + .finalize_block(&hash, Some(justification), true) .map_err(|_| ConsensusError::InvalidJustification) } } diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index 6115e0e3b2c86..399062a88d269 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -251,18 +251,22 @@ fn sync_justifications() { assert_eq!(net.peer(1).client().justifications(&BlockId::Number(10)).unwrap(), None); // we finalize block #10, #15 and #20 for peer 0 with a justification + let backend = net.peer(0).client().as_backend(); + let hashof10 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(10)).unwrap(); + let hashof15 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(15)).unwrap(); + let hashof20 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(20)).unwrap(); let just = (*b"FRNK", Vec::new()); net.peer(0) .client() - .finalize_block(BlockId::Number(10), Some(just.clone()), true) + .finalize_block(&hashof10, Some(just.clone()), true) .unwrap(); net.peer(0) .client() - .finalize_block(BlockId::Number(15), Some(just.clone()), true) + .finalize_block(&hashof15, Some(just.clone()), true) .unwrap(); net.peer(0) .client() - .finalize_block(BlockId::Number(20), Some(just.clone()), true) + .finalize_block(&hashof20, Some(just.clone()), true) .unwrap(); let h1 = net.peer(1).client().header(&BlockId::Number(10)).unwrap().unwrap(); @@ -309,10 +313,7 @@ fn sync_justifications_across_forks() { net.block_until_sync(); let just = (*b"FRNK", Vec::new()); - net.peer(0) - .client() - .finalize_block(BlockId::Hash(f1_best), Some(just), true) - .unwrap(); + net.peer(0).client().finalize_block(&f1_best, Some(just), true).unwrap(); net.peer(1).request_justification(&f1_best, 10); net.peer(1).request_justification(&f2_best, 11); @@ -655,14 +656,8 @@ fn can_sync_to_peers_with_wrong_common_block() { // both peers re-org to the same fork without notifying each other let just = Some((*b"FRNK", Vec::new())); - net.peer(0) - .client() - .finalize_block(BlockId::Hash(fork_hash), just.clone(), true) - .unwrap(); - net.peer(1) - .client() - .finalize_block(BlockId::Hash(fork_hash), just, true) - .unwrap(); + net.peer(0).client().finalize_block(&fork_hash, just.clone(), true).unwrap(); + net.peer(1).client().finalize_block(&fork_hash, just, true).unwrap(); let final_hash = net.peer(0).push_blocks(1, false); net.block_until_sync(); @@ -976,10 +971,17 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { assert_eq!(1, net.peer(0).num_peers()); } + let hashof10 = net + .peer(0) + .client() + .as_backend() + .blockchain() + .expect_block_hash_from_id(&BlockId::Number(10)) + .unwrap(); // Finalize the block and make the justification available. net.peer(0) .client() - .finalize_block(BlockId::Number(10), Some((*b"FRNK", Vec::new())), true) + .finalize_block(&hashof10, Some((*b"FRNK", Vec::new())), true) .unwrap(); block_on(futures::future::poll_fn::<(), _>(|cx| { @@ -1100,10 +1102,14 @@ fn syncs_state() { assert!(!net.peer(1).client().has_state_at(&BlockId::Number(64))); let just = (*b"FRNK", Vec::new()); - net.peer(1) + let hashof60 = net + .peer(0) .client() - .finalize_block(BlockId::Number(60), Some(just), true) + .as_backend() + .blockchain() + .expect_block_hash_from_id(&BlockId::Number(60)) .unwrap(); + net.peer(1).client().finalize_block(&hashof60, Some(just), true).unwrap(); // Wait for state sync. block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); diff --git a/client/rpc/src/chain/tests.rs b/client/rpc/src/chain/tests.rs index 7d12458511cfd..a41d8e41b8fa7 100644 --- a/client/rpc/src/chain/tests.rs +++ b/client/rpc/src/chain/tests.rs @@ -198,6 +198,7 @@ async fn should_return_finalized_hash() { // import new block let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_hash = block.hash(); client.import(BlockOrigin::Own, block).await.unwrap(); // no finalization yet @@ -205,9 +206,9 @@ async fn should_return_finalized_hash() { assert_eq!(res, client.genesis_hash()); // finalize - client.finalize_block(BlockId::number(1), None).unwrap(); + client.finalize_block(&block_hash, None).unwrap(); let res: H256 = api.call("chain_getFinalizedHead", EmptyParams::new()).await.unwrap(); - assert_eq!(res, client.block_hash(1).unwrap().unwrap()); + assert_eq!(res, block_hash); } #[tokio::test] @@ -232,8 +233,9 @@ async fn test_head_subscription(method: &str) { let api = new_full(client.clone(), test_executor()).into_rpc(); let sub = api.subscribe(method, EmptyParams::new()).await.unwrap(); let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_hash = block.hash(); client.import(BlockOrigin::Own, block).await.unwrap(); - client.finalize_block(BlockId::number(1), None).unwrap(); + client.finalize_block(&block_hash, None).unwrap(); sub }; diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index a12b7177db47c..5d73ef4911dcb 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1845,29 +1845,22 @@ where fn apply_finality( &self, operation: &mut ClientImportOperation, - id: BlockId, + hash: &Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()> { let last_best = self.backend.blockchain().info().best_hash; - let to_finalize_hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; - self.apply_finality_with_block_hash( - operation, - to_finalize_hash, - justification, - last_best, - notify, - ) + self.apply_finality_with_block_hash(operation, *hash, justification, last_best, notify) } fn finalize_block( &self, - id: BlockId, + hash: &Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()> { self.lock_import_and_run(|operation| { - self.apply_finality(operation, id, justification, notify) + self.apply_finality(operation, hash, justification, notify) }) } } @@ -1881,20 +1874,20 @@ where fn apply_finality( &self, operation: &mut ClientImportOperation, - id: BlockId, + hash: &Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()> { - (**self).apply_finality(operation, id, justification, notify) + (**self).apply_finality(operation, hash, justification, notify) } fn finalize_block( &self, - id: BlockId, + hash: &Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()> { - (**self).finalize_block(id, justification, notify) + (**self).finalize_block(hash, justification, notify) } } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 4a5b56bd14006..9937c436a33ff 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -867,7 +867,7 @@ fn import_with_justification() { .unwrap() .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); - client.finalize_block(BlockId::hash(a2.hash()), None).unwrap(); + client.finalize_block(&a2.hash(), None).unwrap(); // A2 -> A3 let justification = Justifications::from((TEST_ENGINE_ID, vec![1, 2, 3])); @@ -996,7 +996,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { // we finalize block B1 which is on a different branch from current best // which should trigger a re-org. - ClientExt::finalize_block(&client, BlockId::Hash(b1.hash()), None).unwrap(); + ClientExt::finalize_block(&client, &b1.hash(), None).unwrap(); // B1 should now be the latest finalized assert_eq!(client.chain_info().finalized_hash, b1.hash()); @@ -1020,7 +1020,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { assert_eq!(client.chain_info().best_hash, b3.hash()); - ClientExt::finalize_block(&client, BlockId::Hash(b3.hash()), None).unwrap(); + ClientExt::finalize_block(&client, &b3.hash(), None).unwrap(); finality_notification_check(&mut finality_notifications, &[b1.hash()], &[]); finality_notification_check(&mut finality_notifications, &[b2.hash(), b3.hash()], &[a2.hash()]); @@ -1118,7 +1118,7 @@ fn finality_notifications_content() { // Postpone import to test behavior of import of finalized block. - ClientExt::finalize_block(&client, BlockId::Hash(a2.hash()), None).unwrap(); + ClientExt::finalize_block(&client, &a2.hash(), None).unwrap(); // Import and finalize D4 block_on(client.import_as_final(BlockOrigin::Own, d4.clone())).unwrap(); @@ -1274,7 +1274,7 @@ fn doesnt_import_blocks_that_revert_finality() { // we will finalize A2 which should make it impossible to import a new // B3 at the same height but that doesn't include it - ClientExt::finalize_block(&client, BlockId::Hash(a2.hash()), None).unwrap(); + ClientExt::finalize_block(&client, &a2.hash(), None).unwrap(); let import_err = block_on(client.import(BlockOrigin::Own, b3)).err().unwrap(); let expected_err = @@ -1309,7 +1309,7 @@ fn doesnt_import_blocks_that_revert_finality() { .unwrap() .block; block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); - ClientExt::finalize_block(&client, BlockId::Hash(a3.hash()), None).unwrap(); + ClientExt::finalize_block(&client, &a3.hash(), None).unwrap(); finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[]); diff --git a/test-utils/client/src/client_ext.rs b/test-utils/client/src/client_ext.rs index f2b99a5b355f0..dd416b9102fc0 100644 --- a/test-utils/client/src/client_ext.rs +++ b/test-utils/client/src/client_ext.rs @@ -22,14 +22,14 @@ use sc_client_api::{backend::Finalizer, client::BlockBackend}; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy}; use sc_service::client::Client; use sp_consensus::{BlockOrigin, Error as ConsensusError}; -use sp_runtime::{generic::BlockId, traits::Block as BlockT, Justification, Justifications}; +use sp_runtime::{traits::Block as BlockT, Justification, Justifications}; /// Extension trait for a test client. pub trait ClientExt: Sized { /// Finalize a block. fn finalize_block( &self, - id: BlockId, + hash: &Block::Hash, justification: Option, ) -> sp_blockchain::Result<()>; @@ -75,10 +75,10 @@ where { fn finalize_block( &self, - id: BlockId, + hash: &Block::Hash, justification: Option, ) -> sp_blockchain::Result<()> { - Finalizer::finalize_block(self, id, justification, true) + Finalizer::finalize_block(self, hash, justification, true) } fn genesis_hash(&self) -> ::Hash { From 967080b44e0709ef48cf1096abe47ce731d7e670 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 20 Oct 2022 17:50:59 +0200 Subject: [PATCH 1294/1472] BlockId removal: refactor: BlockImportOperation+Bknd::finalize_block (#12535) * BlockId removal: refactor: BlockImportOperation+Bknd::finalize_block It changes the arguments of methods of `BlockImportOperation` trait from: block: `BlockId` to: hash: `&Block::Hash` `Backend::finalize_block` was also changed. This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) * Review suggestion applied thx to @davxy * trigger CI job --- client/api/src/backend.rs | 8 +-- client/api/src/in_mem.rs | 35 +++++------ client/beefy/src/worker.rs | 6 +- client/db/src/lib.rs | 97 +++++++++++++++-------------- client/service/src/client/client.rs | 6 +- 5 files changed, 75 insertions(+), 77 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 5b4acb0be8bda..864a9af5685d8 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -216,13 +216,13 @@ pub trait BlockImportOperation { /// Mark a block as finalized. fn mark_finalized( &mut self, - id: BlockId, + hash: &Block::Hash, justification: Option, ) -> sp_blockchain::Result<()>; /// Mark a block as new head. If both block import and set head are specified, set head /// overrides block import's best block rule. - fn mark_head(&mut self, id: BlockId) -> sp_blockchain::Result<()>; + fn mark_head(&mut self, hash: &Block::Hash) -> sp_blockchain::Result<()>; /// Add a transaction index operation. fn update_transaction_index(&mut self, index: Vec) @@ -476,12 +476,12 @@ pub trait Backend: AuxStore + Send + Sync { transaction: Self::BlockImportOperation, ) -> sp_blockchain::Result<()>; - /// Finalize block with given Id. + /// Finalize block with given `hash`. /// /// This should only be called if the parent of the given block has been finalized. fn finalize_block( &self, - block: BlockId, + hash: &Block::Hash, justification: Option, ) -> sp_blockchain::Result<()>; diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 99efdd3bf1d22..1cb61ba1a0b0a 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -223,10 +223,10 @@ impl Blockchain { } /// Set an existing block as head. - pub fn set_head(&self, id: BlockId) -> sp_blockchain::Result<()> { + pub fn set_head(&self, hash: Block::Hash) -> sp_blockchain::Result<()> { let header = self - .header(id)? - .ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", id)))?; + .header(BlockId::Hash(hash))? + .ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", hash)))?; self.apply_head(&header) } @@ -271,21 +271,16 @@ impl Blockchain { fn finalize_header( &self, - id: BlockId, + block: &Block::Hash, justification: Option, ) -> sp_blockchain::Result<()> { - let hash = match self.header(id)? { - Some(h) => h.hash(), - None => return Err(sp_blockchain::Error::UnknownBlock(format!("{}", id))), - }; - let mut storage = self.storage.write(); - storage.finalized_hash = hash; + storage.finalized_hash = *block; if justification.is_some() { let block = storage .blocks - .get_mut(&hash) + .get_mut(block) .expect("hash was fetched from a block in the db; qed"); let block_justifications = match block { @@ -500,8 +495,8 @@ pub struct BlockImportOperation { new_state: Option<> as StateBackend>>::Transaction>, aux: Vec<(Vec, Option>)>, - finalized_blocks: Vec<(BlockId, Option)>, - set_head: Option>, + finalized_blocks: Vec<(Block::Hash, Option)>, + set_head: Option, } impl BlockImportOperation @@ -605,16 +600,16 @@ where fn mark_finalized( &mut self, - block: BlockId, + hash: &Block::Hash, justification: Option, ) -> sp_blockchain::Result<()> { - self.finalized_blocks.push((block, justification)); + self.finalized_blocks.push((*hash, justification)); Ok(()) } - fn mark_head(&mut self, block: BlockId) -> sp_blockchain::Result<()> { + fn mark_head(&mut self, hash: &Block::Hash) -> sp_blockchain::Result<()> { assert!(self.pending_block.is_none(), "Only one set block per operation is allowed"); - self.set_head = Some(block); + self.set_head = Some(*hash); Ok(()) } @@ -710,7 +705,7 @@ where fn commit_operation(&self, operation: Self::BlockImportOperation) -> sp_blockchain::Result<()> { if !operation.finalized_blocks.is_empty() { for (block, justification) in operation.finalized_blocks { - self.blockchain.finalize_header(block, justification)?; + self.blockchain.finalize_header(&block, justification)?; } } @@ -743,10 +738,10 @@ where fn finalize_block( &self, - block: BlockId, + hash: &Block::Hash, justification: Option, ) -> sp_blockchain::Result<()> { - self.blockchain.finalize_header(block, justification) + self.blockchain.finalize_header(hash, justification) } fn append_justification( diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 6efebd131d6da..9b331b73ed093 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -1371,8 +1371,10 @@ pub(crate) mod tests { let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); net.peer(0).push_blocks(2, false); // finalize 1 and 2 without justifications - backend.finalize_block(BlockId::number(1), None).unwrap(); - backend.finalize_block(BlockId::number(2), None).unwrap(); + let hashof1 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(1)).unwrap(); + let hashof2 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(2)).unwrap(); + backend.finalize_block(&hashof1, None).unwrap(); + backend.finalize_block(&hashof2, None).unwrap(); let justif = create_finality_proof(2); // create new session at block #2 diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 1a80c16c4e59d..14ebafa01bec1 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -756,8 +756,8 @@ pub struct BlockImportOperation { offchain_storage_updates: OffchainChangesCollection, pending_block: Option>, aux_ops: Vec<(Vec, Option>)>, - finalized_blocks: Vec<(BlockId, Option)>, - set_head: Option>, + finalized_blocks: Vec<(Block::Hash, Option)>, + set_head: Option, commit_state: bool, index_ops: Vec, } @@ -897,16 +897,16 @@ impl sc_client_api::backend::BlockImportOperation fn mark_finalized( &mut self, - block: BlockId, + block: &Block::Hash, justification: Option, ) -> ClientResult<()> { - self.finalized_blocks.push((block, justification)); + self.finalized_blocks.push((*block, justification)); Ok(()) } - fn mark_head(&mut self, block: BlockId) -> ClientResult<()> { + fn mark_head(&mut self, hash: &Block::Hash) -> ClientResult<()> { assert!(self.set_head.is_none(), "Only one set head per operation is allowed"); - self.set_head = Some(block); + self.set_head = Some(*hash); Ok(()) } @@ -1351,8 +1351,7 @@ impl Backend { (meta.best_number, meta.finalized_hash, meta.finalized_number, meta.block_gap) }; - for (block, justification) in operation.finalized_blocks { - let block_hash = self.blockchain.expect_block_hash_from_id(&block)?; + for (block_hash, justification) in operation.finalized_blocks { let block_header = self.blockchain.expect_header(BlockId::Hash(block_hash))?; meta_updates.push(self.finalize_block_with_transaction( &mut transaction, @@ -1624,9 +1623,10 @@ impl Backend { }; if let Some(set_head) = operation.set_head { - if let Some(header) = - sc_client_api::blockchain::HeaderBackend::header(&self.blockchain, set_head)? - { + if let Some(header) = sc_client_api::blockchain::HeaderBackend::header( + &self.blockchain, + BlockId::Hash(set_head), + )? { let number = header.number(); let hash = header.hash(); @@ -1992,17 +1992,16 @@ impl sc_client_api::backend::Backend for Backend { fn finalize_block( &self, - block: BlockId, + hash: &Block::Hash, justification: Option, ) -> ClientResult<()> { let mut transaction = Transaction::new(); - let hash = self.blockchain.expect_block_hash_from_id(&block)?; - let header = self.blockchain.expect_header(block)?; + let header = self.blockchain.expect_header(BlockId::Hash(*hash))?; let mut displaced = None; let m = self.finalize_block_with_transaction( &mut transaction, - &hash, + hash, &header, None, justification, @@ -2605,13 +2604,12 @@ pub(crate) mod tests { header.state_root = root.into(); op.update_storage(storage, Vec::new()).unwrap(); - op.set_block_data(header, Some(vec![]), None, None, NewBlockState::Best) + op.set_block_data(header.clone(), Some(vec![]), None, None, NewBlockState::Best) .unwrap(); db.commit_operation(op).unwrap(); - let hash = db.blockchain().expect_block_hash_from_id(&BlockId::Number(1)).unwrap(); - let state = db.state_at(&hash).unwrap(); + let state = db.state_at(&header.hash()).unwrap(); assert_eq!(state.storage(&[1, 3, 5]).unwrap(), None); assert_eq!(state.storage(&[1, 2, 3]).unwrap(), Some(vec![9, 9, 9])); @@ -2665,7 +2663,7 @@ pub(crate) mod tests { hash }; - let hash = { + let hashof1 = { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Number(0)).unwrap(); let mut header = Header { @@ -2702,12 +2700,12 @@ pub(crate) mod tests { hash }; - let hash = { + let hashof2 = { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Number(1)).unwrap(); let mut header = Header { number: 2, - parent_hash: hash, + parent_hash: hashof1, state_root: Default::default(), digest: Default::default(), extrinsics_root: Default::default(), @@ -2736,12 +2734,12 @@ pub(crate) mod tests { hash }; - { + let hashof3 = { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Number(2)).unwrap(); let mut header = Header { number: 3, - parent_hash: hash, + parent_hash: hashof2, state_root: Default::default(), digest: Default::default(), extrinsics_root: Default::default(), @@ -2754,6 +2752,7 @@ pub(crate) mod tests { .storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y))), state_version) .0 .into(); + let hash = header.hash(); op.set_block_data(header, Some(vec![]), None, None, NewBlockState::Best) .unwrap(); @@ -2764,11 +2763,12 @@ pub(crate) mod tests { .db .get(columns::STATE, &sp_trie::prefixed_key::(&key, EMPTY_PREFIX)) .is_none()); - } + hash + }; - backend.finalize_block(BlockId::Number(1), None).unwrap(); - backend.finalize_block(BlockId::Number(2), None).unwrap(); - backend.finalize_block(BlockId::Number(3), None).unwrap(); + backend.finalize_block(&hashof1, None).unwrap(); + backend.finalize_block(&hashof2, None).unwrap(); + backend.finalize_block(&hashof3, None).unwrap(); assert!(backend .storage .db @@ -2991,8 +2991,8 @@ pub(crate) mod tests { vec![block2_a, block2_b, block2_c, block1_c] ); - backend.finalize_block(BlockId::hash(block1_a), None).unwrap(); - backend.finalize_block(BlockId::hash(block2_a), None).unwrap(); + backend.finalize_block(&block1_a, None).unwrap(); + backend.finalize_block(&block2_a, None).unwrap(); // leaves at same height stay. Leaves at lower heights pruned. assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a, block2_b, block2_c]); @@ -3016,10 +3016,10 @@ pub(crate) mod tests { let backend = Backend::::new_test(10, 10); let block0 = insert_header(&backend, 0, Default::default(), None, Default::default()); - let _ = insert_header(&backend, 1, block0, None, Default::default()); + let block1 = insert_header(&backend, 1, block0, None, Default::default()); let justification = Some((CONS0_ENGINE_ID, vec![1, 2, 3])); - backend.finalize_block(BlockId::Number(1), justification.clone()).unwrap(); + backend.finalize_block(&block1, justification.clone()).unwrap(); assert_eq!( backend.blockchain().justifications(BlockId::Number(1)).unwrap(), @@ -3034,10 +3034,10 @@ pub(crate) mod tests { let backend = Backend::::new_test(10, 10); let block0 = insert_header(&backend, 0, Default::default(), None, Default::default()); - let _ = insert_header(&backend, 1, block0, None, Default::default()); + let block1 = insert_header(&backend, 1, block0, None, Default::default()); let just0 = (CONS0_ENGINE_ID, vec![1, 2, 3]); - backend.finalize_block(BlockId::Number(1), Some(just0.clone().into())).unwrap(); + backend.finalize_block(&block1, Some(just0.clone().into())).unwrap(); let just1 = (CONS1_ENGINE_ID, vec![4, 5]); backend.append_justification(BlockId::Number(1), just1.clone()).unwrap(); @@ -3071,15 +3071,15 @@ pub(crate) mod tests { { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(block0)).unwrap(); - op.mark_finalized(BlockId::Hash(block1), None).unwrap(); - op.mark_finalized(BlockId::Hash(block2), None).unwrap(); + op.mark_finalized(&block1, None).unwrap(); + op.mark_finalized(&block2, None).unwrap(); backend.commit_operation(op).unwrap(); } { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(block2)).unwrap(); - op.mark_finalized(BlockId::Hash(block3), None).unwrap(); - op.mark_finalized(BlockId::Hash(block4), None).unwrap(); + op.mark_finalized(&block3, None).unwrap(); + op.mark_finalized(&block4, None).unwrap(); backend.commit_operation(op).unwrap(); } } @@ -3181,7 +3181,7 @@ pub(crate) mod tests { { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(block0)).unwrap(); - op.mark_finalized(BlockId::Hash(block2), None).unwrap(); + op.mark_finalized(&block2, None).unwrap(); backend.commit_operation(op).unwrap_err(); } } @@ -3210,7 +3210,7 @@ pub(crate) mod tests { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); for i in 1..5 { - op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); + op.mark_finalized(&blocks[i], None).unwrap(); } backend.commit_operation(op).unwrap(); } @@ -3245,7 +3245,7 @@ pub(crate) mod tests { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); for i in 1..3 { - op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); + op.mark_finalized(&blocks[i], None).unwrap(); } backend.commit_operation(op).unwrap(); @@ -3301,7 +3301,7 @@ pub(crate) mod tests { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); - op.mark_head(BlockId::Hash(blocks[4])).unwrap(); + op.mark_head(&blocks[4]).unwrap(); backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); @@ -3310,7 +3310,7 @@ pub(crate) mod tests { for i in 1..5 { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(blocks[i])).unwrap(); - op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); + op.mark_finalized(&blocks[i], None).unwrap(); backend.commit_operation(op).unwrap(); } @@ -3370,13 +3370,13 @@ pub(crate) mod tests { .unwrap(); let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); - op.mark_head(BlockId::Hash(blocks[4])).unwrap(); + op.mark_head(&blocks[4]).unwrap(); backend.commit_operation(op).unwrap(); for i in 1..5 { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); - op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); + op.mark_finalized(&blocks[i], None).unwrap(); backend.commit_operation(op).unwrap(); } @@ -3423,8 +3423,9 @@ pub(crate) mod tests { assert_eq!(bc.indexed_transaction(&x1_hash).unwrap().unwrap(), &x1[1..]); // Push one more blocks and make sure block is pruned and transaction index is cleared. - insert_block(&backend, 1, hash, None, Default::default(), vec![], None).unwrap(); - backend.finalize_block(BlockId::Number(1), None).unwrap(); + let block1 = + insert_block(&backend, 1, hash, None, Default::default(), vec![], None).unwrap(); + backend.finalize_block(&block1, None).unwrap(); assert_eq!(bc.body(BlockId::Number(0)).unwrap(), None); assert_eq!(bc.indexed_transaction(&x0_hash).unwrap(), None); assert_eq!(bc.indexed_transaction(&x1_hash).unwrap(), None); @@ -3501,7 +3502,7 @@ pub(crate) mod tests { for i in 1..10 { let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); - op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); + op.mark_finalized(&blocks[i], None).unwrap(); backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); if i < 6 { @@ -3676,7 +3677,7 @@ pub(crate) mod tests { let block1_a = insert_header(&backend, 1, block0, None, Default::default()); let block2_a = insert_header(&backend, 2, block1_a, None, Default::default()); - backend.finalize_block(BlockId::hash(block1_a), None).unwrap(); + backend.finalize_block(&block1_a, None).unwrap(); assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a]); // Insert a fork prior to finalization point. Leave should not be created. diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 5d73ef4911dcb..b18c6d226706b 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -878,17 +878,17 @@ where // plugable we cannot make a better choice here. usages that need // an accurate "best" block need to go through `SelectChain` // instead. - operation.op.mark_head(BlockId::Hash(block))?; + operation.op.mark_head(&block)?; } let enacted = route_from_finalized.enacted(); assert!(enacted.len() > 0); for finalize_new in &enacted[..enacted.len() - 1] { - operation.op.mark_finalized(BlockId::Hash(finalize_new.hash), None)?; + operation.op.mark_finalized(&finalize_new.hash, None)?; } assert_eq!(enacted.last().map(|e| e.hash), Some(block)); - operation.op.mark_finalized(BlockId::Hash(block), justification)?; + operation.op.mark_finalized(&block, justification)?; if notify { let finalized = From ab09d4471bae3873b949734998aca9f1aea3f835 Mon Sep 17 00:00:00 2001 From: Dmitrii Markin Date: Thu, 20 Oct 2022 19:30:01 +0300 Subject: [PATCH 1295/1472] Remove multiple DHTs support from `Discovery` (#12524) --- client/network/src/behaviour.rs | 21 +- client/network/src/discovery.rs | 682 ++++++++++---------------- client/network/src/service.rs | 32 +- client/network/src/service/metrics.rs | 35 +- 4 files changed, 297 insertions(+), 473 deletions(-) diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index fa130fb4baacd..2e646956e9d8c 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -34,7 +34,6 @@ use libp2p::{ use sc_consensus::import_queue::{IncomingBlock, RuntimeOrigin}; use sc_network_common::{ - config::ProtocolId, protocol::{ event::DhtEvent, role::{ObservedRole, Roles}, @@ -79,7 +78,7 @@ pub enum BehaviourOut { JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), /// Started a random iterative Kademlia discovery query. - RandomKademliaStarted(Vec), + RandomKademliaStarted, /// We have received a request from a peer and answered it. /// @@ -267,25 +266,20 @@ where self.discovery.add_known_address(peer_id, addr) } - /// Returns the number of nodes in each Kademlia kbucket for each Kademlia instance. + /// Returns the number of nodes in each Kademlia kbucket. /// - /// Identifies Kademlia instances by their [`ProtocolId`] and kbuckets by the base 2 logarithm - /// of their lower bound. - pub fn num_entries_per_kbucket( - &mut self, - ) -> impl ExactSizeIterator)> { + /// Identifies kbuckets by the base 2 logarithm of their lower bound. + pub fn num_entries_per_kbucket(&mut self) -> Option> { self.discovery.num_entries_per_kbucket() } /// Returns the number of records in the Kademlia record stores. - pub fn num_kademlia_records(&mut self) -> impl ExactSizeIterator { + pub fn num_kademlia_records(&mut self) -> Option { self.discovery.num_kademlia_records() } /// Returns the total size in bytes of all the records in the Kademlia record stores. - pub fn kademlia_records_total_size( - &mut self, - ) -> impl ExactSizeIterator { + pub fn kademlia_records_total_size(&mut self) -> Option { self.discovery.kademlia_records_total_size() } @@ -438,8 +432,7 @@ impl From for BehaviourOut { BehaviourOut::Dht(DhtEvent::ValuePut(key), duration), DiscoveryOut::ValuePutFailed(key, duration) => BehaviourOut::Dht(DhtEvent::ValuePutFailed(key), duration), - DiscoveryOut::RandomKademliaStarted(protocols) => - BehaviourOut::RandomKademliaStarted(protocols), + DiscoveryOut::RandomKademliaStarted => BehaviourOut::RandomKademliaStarted, } } } diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index da4dec70b29ab..712c3af97f58e 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -66,11 +66,12 @@ use libp2p::{ mdns::{Mdns, MdnsConfig, MdnsEvent}, multiaddr::Protocol, swarm::{ - handler::multi::IntoMultiHandler, ConnectionHandler, DialError, IntoConnectionHandler, - NetworkBehaviour, NetworkBehaviourAction, PollParameters, + behaviour::toggle::{Toggle, ToggleIntoConnectionHandler}, + ConnectionHandler, DialError, IntoConnectionHandler, NetworkBehaviour, + NetworkBehaviourAction, PollParameters, }, }; -use log::{debug, error, info, trace, warn}; +use log::{debug, info, trace, warn}; use sc_network_common::{config::ProtocolId, utils::LruHashSet}; use sp_core::hexdisplay::HexDisplay; use std::{ @@ -89,8 +90,8 @@ const MAX_KNOWN_EXTERNAL_ADDRESSES: usize = 32; /// `DiscoveryBehaviour` configuration. /// -/// Note: In order to discover nodes or load and store values via Kademlia one has to add at least -/// one protocol via [`DiscoveryConfig::add_protocol`]. +/// Note: In order to discover nodes or load and store values via Kademlia one has to add +/// Kademlia protocol via [`DiscoveryConfig::with_kademlia`]. pub struct DiscoveryConfig { local_peer_id: PeerId, permanent_addresses: Vec<(PeerId, Multiaddr)>, @@ -100,7 +101,7 @@ pub struct DiscoveryConfig { discovery_only_if_under_num: u64, enable_mdns: bool, kademlia_disjoint_query_paths: bool, - protocol_ids: HashSet, + kademlia_protocol_id: Option, } impl DiscoveryConfig { @@ -115,7 +116,7 @@ impl DiscoveryConfig { discovery_only_if_under_num: std::u64::MAX, enable_mdns: false, kademlia_disjoint_query_paths: false, - protocol_ids: HashSet::new(), + kademlia_protocol_id: None, } } @@ -160,13 +161,8 @@ impl DiscoveryConfig { } /// Add discovery via Kademlia for the given protocol. - pub fn add_protocol(&mut self, id: ProtocolId) -> &mut Self { - if self.protocol_ids.contains(&id) { - warn!(target: "sub-libp2p", "Discovery already registered for protocol {:?}", id); - return self - } - - self.protocol_ids.insert(id); + pub fn with_kademlia(&mut self, id: ProtocolId) -> &mut Self { + self.kademlia_protocol_id = Some(id); self } @@ -189,37 +185,34 @@ impl DiscoveryConfig { discovery_only_if_under_num, enable_mdns, kademlia_disjoint_query_paths, - protocol_ids, + kademlia_protocol_id, } = self; - let kademlias = protocol_ids - .into_iter() - .map(|protocol_id| { - let proto_name = protocol_name_from_protocol_id(&protocol_id); + let kademlia = kademlia_protocol_id.map(|protocol_id| { + let proto_name = protocol_name_from_protocol_id(&protocol_id); - let mut config = KademliaConfig::default(); - config.set_protocol_names(std::iter::once(proto_name.into()).collect()); - // By default Kademlia attempts to insert all peers into its routing table once a - // dialing attempt succeeds. In order to control which peer is added, disable the - // auto-insertion and instead add peers manually. - config.set_kbucket_inserts(KademliaBucketInserts::Manual); - config.disjoint_query_paths(kademlia_disjoint_query_paths); + let mut config = KademliaConfig::default(); + config.set_protocol_names(std::iter::once(proto_name.into()).collect()); + // By default Kademlia attempts to insert all peers into its routing table once a + // dialing attempt succeeds. In order to control which peer is added, disable the + // auto-insertion and instead add peers manually. + config.set_kbucket_inserts(KademliaBucketInserts::Manual); + config.disjoint_query_paths(kademlia_disjoint_query_paths); - let store = MemoryStore::new(local_peer_id); - let mut kad = Kademlia::with_config(local_peer_id, store, config); + let store = MemoryStore::new(local_peer_id); + let mut kad = Kademlia::with_config(local_peer_id, store, config); - for (peer_id, addr) in &permanent_addresses { - kad.add_address(peer_id, addr.clone()); - } + for (peer_id, addr) in &permanent_addresses { + kad.add_address(peer_id, addr.clone()); + } - (protocol_id, kad) - }) - .collect(); + kad + }); DiscoveryBehaviour { permanent_addresses, ephemeral_addresses: HashMap::new(), - kademlias, + kademlia: Toggle::from(kademlia), next_kad_random_query: if dht_random_walk { Some(Delay::new(Duration::new(0, 0))) } else { @@ -259,8 +252,9 @@ pub struct DiscoveryBehaviour { /// Same as `permanent_addresses`, except that addresses that fail to reach a peer are /// removed. ephemeral_addresses: HashMap>, - /// Kademlia requests and answers. - kademlias: HashMap>, + /// Kademlia requests and answers. Even though it's wrapped in `Toggle`, currently + /// it's always enabled in `NetworkWorker::new()`. + kademlia: Toggle>, /// Discovers nodes on the local network. mdns: Option, /// Stream that fires when we need to perform the next random Kademlia query. `None` if @@ -289,7 +283,7 @@ impl DiscoveryBehaviour { /// Returns the list of nodes that we know exist in the network. pub fn known_peers(&mut self) -> HashSet { let mut peers = HashSet::new(); - for k in self.kademlias.values_mut() { + if let Some(k) = self.kademlia.as_mut() { for b in k.kbuckets() { for e in b.iter() { if !peers.contains(e.node.key.preimage()) { @@ -309,7 +303,7 @@ impl DiscoveryBehaviour { pub fn add_known_address(&mut self, peer_id: PeerId, addr: Multiaddr) { let addrs_list = self.ephemeral_addresses.entry(peer_id).or_default(); if !addrs_list.iter().any(|a| *a == addr) { - for k in self.kademlias.values_mut() { + if let Some(k) = self.kademlia.as_mut() { k.add_address(&peer_id, addr.clone()); } @@ -318,8 +312,8 @@ impl DiscoveryBehaviour { } } - /// Add a self-reported address of a remote peer to the k-buckets of the supported - /// DHTs (`supported_protocols`). + /// Add a self-reported address of a remote peer to the k-buckets of the DHT + /// if it has compatible `supported_protocols`. /// /// **Note**: It is important that you call this method. The discovery mechanism will not /// automatically add connecting peers to the Kademlia k-buckets. @@ -329,13 +323,15 @@ impl DiscoveryBehaviour { supported_protocols: &[impl AsRef<[u8]>], addr: Multiaddr, ) { - if !self.allow_non_globals_in_dht && !self.can_add_to_dht(&addr) { - trace!(target: "sub-libp2p", "Ignoring self-reported non-global address {} from {}.", addr, peer_id); - return - } + if let Some(kademlia) = self.kademlia.as_mut() { + if !self.allow_non_globals_in_dht && !Self::can_add_to_dht(&addr) { + trace!( + target: "sub-libp2p", + "Ignoring self-reported non-global address {} from {}.", addr, peer_id + ); + return + } - let mut added = false; - for kademlia in self.kademlias.values_mut() { if let Some(matching_protocol) = supported_protocols .iter() .find(|p| kademlia.protocol_names().iter().any(|k| k.as_ref() == p.as_ref())) @@ -346,24 +342,21 @@ impl DiscoveryBehaviour { addr, peer_id, String::from_utf8_lossy(matching_protocol.as_ref()), ); kademlia.add_address(peer_id, addr.clone()); - added = true; + } else { + trace!( + target: "sub-libp2p", + "Ignoring self-reported address {} from {} as remote node is not part of the \ + Kademlia DHT supported by the local node.", addr, peer_id, + ); } } - - if !added { - trace!( - target: "sub-libp2p", - "Ignoring self-reported address {} from {} as remote node is not part of any \ - Kademlia DHTs supported by the local node.", addr, peer_id, - ); - } } /// Start fetching a record from the DHT. /// /// A corresponding `ValueFound` or `ValueNotFound` event will later be generated. pub fn get_value(&mut self, key: record::Key) { - for k in self.kademlias.values_mut() { + if let Some(k) = self.kademlia.as_mut() { k.get_record(key.clone(), Quorum::One); } } @@ -373,7 +366,7 @@ impl DiscoveryBehaviour { /// /// A corresponding `ValuePut` or `ValuePutFailed` event will later be generated. pub fn put_value(&mut self, key: record::Key, value: Vec) { - for k in self.kademlias.values_mut() { + if let Some(k) = self.kademlia.as_mut() { if let Err(e) = k.put_record(Record::new(key.clone(), value.clone()), Quorum::All) { warn!(target: "sub-libp2p", "Libp2p => Failed to put record: {:?}", e); self.pending_events @@ -386,37 +379,27 @@ impl DiscoveryBehaviour { /// /// Identifies Kademlia instances by their [`ProtocolId`] and kbuckets by the base 2 logarithm /// of their lower bound. - pub fn num_entries_per_kbucket( - &mut self, - ) -> impl ExactSizeIterator)> { - self.kademlias.iter_mut().map(|(id, kad)| { - let buckets = kad - .kbuckets() + pub fn num_entries_per_kbucket(&mut self) -> Option> { + self.kademlia.as_mut().map(|kad| { + kad.kbuckets() .map(|bucket| (bucket.range().0.ilog2().unwrap_or(0), bucket.iter().count())) - .collect(); - (id, buckets) + .collect() }) } /// Returns the number of records in the Kademlia record stores. - pub fn num_kademlia_records(&mut self) -> impl ExactSizeIterator { + pub fn num_kademlia_records(&mut self) -> Option { // Note that this code is ok only because we use a `MemoryStore`. - self.kademlias.iter_mut().map(|(id, kad)| { - let num = kad.store_mut().records().count(); - (id, num) - }) + self.kademlia.as_mut().map(|kad| kad.store_mut().records().count()) } /// Returns the total size in bytes of all the records in the Kademlia record stores. - pub fn kademlia_records_total_size( - &mut self, - ) -> impl ExactSizeIterator { + pub fn kademlia_records_total_size(&mut self) -> Option { // Note that this code is ok only because we use a `MemoryStore`. If the records were // for example stored on disk, this would load every single one of them every single time. - self.kademlias.iter_mut().map(|(id, kad)| { - let size = kad.store_mut().records().fold(0, |tot, rec| tot + rec.value.len()); - (id, size) - }) + self.kademlia + .as_mut() + .map(|kad| kad.store_mut().records().fold(0, |tot, rec| tot + rec.value.len())) } /// Can the given `Multiaddr` be put into the DHT? @@ -425,7 +408,7 @@ impl DiscoveryBehaviour { // NB: Currently all DNS names are allowed and no check for TLD suffixes is done // because the set of valid domains is highly dynamic and would require frequent // updates, for example by utilising publicsuffix.org or IANA. - pub fn can_add_to_dht(&self, addr: &Multiaddr) -> bool { + pub fn can_add_to_dht(addr: &Multiaddr) -> bool { let ip = match addr.iter().next() { Some(Protocol::Ip4(ip)) => IpNetwork::from(ip), Some(Protocol::Ip6(ip)) => IpNetwork::from(ip), @@ -435,29 +418,6 @@ impl DiscoveryBehaviour { }; ip.is_global() } - - fn new_handler_with_replacement( - &mut self, - pid: ProtocolId, - handler: KademliaHandlerProto, - ) -> ::ConnectionHandler { - let mut handlers: HashMap<_, _> = self - .kademlias - .iter_mut() - .map(|(p, k)| (p.clone(), NetworkBehaviour::new_handler(k))) - .collect(); - - if let Some(h) = handlers.get_mut(&pid) { - *h = handler - } - - IntoMultiHandler::try_from_iter(handlers).expect( - "There can be at most one handler per `ProtocolId` and protocol names contain the \ - `ProtocolId` so no two protocol names in `self.kademlias` can be equal which is the \ - only error `try_from_iter` can return, therefore this call is guaranteed to succeed; \ - qed", - ) - } } /// Event generated by the `DiscoveryBehaviour`. @@ -498,28 +458,18 @@ pub enum DiscoveryOut { /// Returning the corresponding key as well as the request duration. ValuePutFailed(record::Key, Duration), - /// Started a random Kademlia query for each DHT identified by the given `ProtocolId`s. + /// Started a random Kademlia query. /// /// Only happens if [`DiscoveryConfig::with_dht_random_walk`] has been configured to `true`. - RandomKademliaStarted(Vec), + RandomKademliaStarted, } impl NetworkBehaviour for DiscoveryBehaviour { - type ConnectionHandler = IntoMultiHandler>; + type ConnectionHandler = ToggleIntoConnectionHandler>; type OutEvent = DiscoveryOut; fn new_handler(&mut self) -> Self::ConnectionHandler { - let iter = self - .kademlias - .iter_mut() - .map(|(p, k)| (p.clone(), NetworkBehaviour::new_handler(k))); - - IntoMultiHandler::try_from_iter(iter).expect( - "There can be at most one handler per `ProtocolId` and protocol names contain the \ - `ProtocolId` so no two protocol names in `self.kademlias` can be equal which is the \ - only error `try_from_iter` can return, therefore this call is guaranteed to succeed; \ - qed", - ) + self.kademlia.new_handler() } fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { @@ -534,10 +484,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { } { - let mut list_to_filter = Vec::new(); - for k in self.kademlias.values_mut() { - list_to_filter.extend(k.addresses_of_peer(peer_id)) - } + let mut list_to_filter = self.kademlia.addresses_of_peer(peer_id); if let Some(ref mut mdns) = self.mdns { list_to_filter.extend(mdns.addresses_of_peer(peer_id)); @@ -566,9 +513,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { old: &ConnectedPoint, new: &ConnectedPoint, ) { - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_address_change(k, peer_id, connection_id, old, new); - } + self.kademlia.inject_address_change(peer_id, connection_id, old, new) } fn inject_connection_established( @@ -580,16 +525,13 @@ impl NetworkBehaviour for DiscoveryBehaviour { other_established: usize, ) { self.num_connections += 1; - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_connection_established( - k, - peer_id, - conn, - endpoint, - failed_addresses, - other_established, - ) - } + self.kademlia.inject_connection_established( + peer_id, + conn, + endpoint, + failed_addresses, + other_established, + ) } fn inject_connection_closed( @@ -601,23 +543,19 @@ impl NetworkBehaviour for DiscoveryBehaviour { remaining_established: usize, ) { self.num_connections -= 1; - for (pid, event) in handler.into_iter() { - if let Some(kad) = self.kademlias.get_mut(&pid) { - kad.inject_connection_closed(peer_id, conn, endpoint, event, remaining_established) - } else { - error!( - target: "sub-libp2p", - "inject_connection_closed: no kademlia instance registered for protocol {:?}", - pid, - ) - } - } + self.kademlia.inject_connection_closed( + peer_id, + conn, + endpoint, + handler, + remaining_established, + ) } fn inject_dial_failure( &mut self, peer_id: Option, - _: Self::ConnectionHandler, + handler: Self::ConnectionHandler, error: &DialError, ) { if let Some(peer_id) = peer_id { @@ -630,32 +568,22 @@ impl NetworkBehaviour for DiscoveryBehaviour { } } - for k in self.kademlias.values_mut() { - let handler = k.new_handler(); - NetworkBehaviour::inject_dial_failure(k, peer_id, handler, error); - } + self.kademlia.inject_dial_failure(peer_id, handler, error) } fn inject_event( &mut self, peer_id: PeerId, connection: ConnectionId, - (pid, event): <::Handler as ConnectionHandler>::OutEvent, + event: <::Handler as ConnectionHandler>::OutEvent, ) { - if let Some(kad) = self.kademlias.get_mut(&pid) { - return kad.inject_event(peer_id, connection, event) - } - error!( - target: "sub-libp2p", - "inject_node_event: no kademlia instance registered for protocol {:?}", - pid, - ) + self.kademlia.inject_event(peer_id, connection, event) } fn inject_new_external_addr(&mut self, addr: &Multiaddr) { let new_addr = addr.clone().with(Protocol::P2p(self.local_peer_id.into())); - if self.can_add_to_dht(addr) { + if Self::can_add_to_dht(addr) { // NOTE: we might re-discover the same address multiple times // in which case we just want to refrain from logging. if self.known_external_addresses.insert(new_addr.clone()) { @@ -667,36 +595,26 @@ impl NetworkBehaviour for DiscoveryBehaviour { } } - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_new_external_addr(k, addr) - } + self.kademlia.inject_new_external_addr(addr) } fn inject_expired_external_addr(&mut self, addr: &Multiaddr) { // We intentionally don't remove the element from `known_external_addresses` in order // to not print the log line again. - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_expired_external_addr(k, addr) - } + self.kademlia.inject_expired_external_addr(addr) } fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_expired_listen_addr(k, id, addr) - } + self.kademlia.inject_expired_listen_addr(id, addr) } fn inject_new_listener(&mut self, id: ListenerId) { - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_new_listener(k, id) - } + self.kademlia.inject_new_listener(id) } fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_new_listen_addr(k, id, addr) - } + self.kademlia.inject_new_listen_addr(id, addr) } fn inject_listen_failure(&mut self, _: &Multiaddr, _: &Multiaddr, _: Self::ConnectionHandler) { @@ -704,15 +622,11 @@ impl NetworkBehaviour for DiscoveryBehaviour { } fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) { - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_listener_error(k, id, err) - } + self.kademlia.inject_listener_error(id, err) } fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &io::Error>) { - for k in self.kademlias.values_mut() { - NetworkBehaviour::inject_listener_closed(k, id, reason) - } + self.kademlia.inject_listener_closed(id, reason) } fn poll( @@ -726,198 +640,189 @@ impl NetworkBehaviour for DiscoveryBehaviour { } // Poll the stream that fires when we need to start a random Kademlia query. - if let Some(next_kad_random_query) = self.next_kad_random_query.as_mut() { - while next_kad_random_query.poll_unpin(cx).is_ready() { - let actually_started = if self.num_connections < self.discovery_only_if_under_num { - let random_peer_id = PeerId::random(); - debug!( - target: "sub-libp2p", - "Libp2p <= Starting random Kademlia request for {:?}", - random_peer_id, - ); - for k in self.kademlias.values_mut() { - k.get_closest_peers(random_peer_id); + if let Some(kademlia) = self.kademlia.as_mut() { + if let Some(next_kad_random_query) = self.next_kad_random_query.as_mut() { + while next_kad_random_query.poll_unpin(cx).is_ready() { + let actually_started = + if self.num_connections < self.discovery_only_if_under_num { + let random_peer_id = PeerId::random(); + debug!( + target: "sub-libp2p", + "Libp2p <= Starting random Kademlia request for {:?}", + random_peer_id, + ); + kademlia.get_closest_peers(random_peer_id); + true + } else { + debug!( + target: "sub-libp2p", + "Kademlia paused due to high number of connections ({})", + self.num_connections + ); + false + }; + + // Schedule the next random query with exponentially increasing delay, + // capped at 60 seconds. + *next_kad_random_query = Delay::new(self.duration_to_next_kad); + self.duration_to_next_kad = + cmp::min(self.duration_to_next_kad * 2, Duration::from_secs(60)); + + if actually_started { + let ev = DiscoveryOut::RandomKademliaStarted; + return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) } - true - } else { - debug!( - target: "sub-libp2p", - "Kademlia paused due to high number of connections ({})", - self.num_connections - ); - false - }; - - // Schedule the next random query with exponentially increasing delay, - // capped at 60 seconds. - *next_kad_random_query = Delay::new(self.duration_to_next_kad); - self.duration_to_next_kad = - cmp::min(self.duration_to_next_kad * 2, Duration::from_secs(60)); - - if actually_started { - let ev = DiscoveryOut::RandomKademliaStarted( - self.kademlias.keys().cloned().collect(), - ); - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) } } } - // Poll Kademlias. - for (pid, kademlia) in &mut self.kademlias { - while let Poll::Ready(ev) = kademlia.poll(cx, params) { - match ev { - NetworkBehaviourAction::GenerateEvent(ev) => match ev { - KademliaEvent::RoutingUpdated { peer, .. } => { - let ev = DiscoveryOut::Discovered(peer); - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) - }, - KademliaEvent::UnroutablePeer { peer, .. } => { - let ev = DiscoveryOut::UnroutablePeer(peer); - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) - }, - KademliaEvent::RoutablePeer { peer, .. } => { - let ev = DiscoveryOut::Discovered(peer); - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) - }, - KademliaEvent::PendingRoutablePeer { .. } | - KademliaEvent::InboundRequest { .. } => { - // We are not interested in this event at the moment. + while let Poll::Ready(ev) = self.kademlia.poll(cx, params) { + match ev { + NetworkBehaviourAction::GenerateEvent(ev) => match ev { + KademliaEvent::RoutingUpdated { peer, .. } => { + let ev = DiscoveryOut::Discovered(peer); + return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) + }, + KademliaEvent::UnroutablePeer { peer, .. } => { + let ev = DiscoveryOut::UnroutablePeer(peer); + return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) + }, + KademliaEvent::RoutablePeer { peer, .. } => { + let ev = DiscoveryOut::Discovered(peer); + return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) + }, + KademliaEvent::PendingRoutablePeer { .. } | + KademliaEvent::InboundRequest { .. } => { + // We are not interested in this event at the moment. + }, + KademliaEvent::OutboundQueryCompleted { + result: QueryResult::GetClosestPeers(res), + .. + } => match res { + Err(GetClosestPeersError::Timeout { key, peers }) => { + debug!( + target: "sub-libp2p", + "Libp2p => Query for {:?} timed out with {} results", + HexDisplay::from(&key), peers.len(), + ); }, - KademliaEvent::OutboundQueryCompleted { - result: QueryResult::GetClosestPeers(res), - .. - } => match res { - Err(GetClosestPeersError::Timeout { key, peers }) => { + Ok(ok) => { + trace!( + target: "sub-libp2p", + "Libp2p => Query for {:?} yielded {:?} results", + HexDisplay::from(&ok.key), ok.peers.len(), + ); + if ok.peers.is_empty() && self.num_connections != 0 { debug!( target: "sub-libp2p", - "Libp2p => Query for {:?} timed out with {} results", - HexDisplay::from(&key), peers.len(), + "Libp2p => Random Kademlia query has yielded empty results", ); - }, + } + }, + }, + KademliaEvent::OutboundQueryCompleted { + result: QueryResult::GetRecord(res), + stats, + .. + } => { + let ev = match res { Ok(ok) => { + let results = ok + .records + .into_iter() + .map(|r| (r.record.key, r.record.value)) + .collect(); + + DiscoveryOut::ValueFound( + results, + stats.duration().unwrap_or_default(), + ) + }, + Err(e @ libp2p::kad::GetRecordError::NotFound { .. }) => { trace!( target: "sub-libp2p", - "Libp2p => Query for {:?} yielded {:?} results", - HexDisplay::from(&ok.key), ok.peers.len(), + "Libp2p => Failed to get record: {:?}", + e, ); - if ok.peers.is_empty() && self.num_connections != 0 { - debug!( - target: "sub-libp2p", - "Libp2p => Random Kademlia query has yielded empty results", - ); - } + DiscoveryOut::ValueNotFound( + e.into_key(), + stats.duration().unwrap_or_default(), + ) }, - }, - KademliaEvent::OutboundQueryCompleted { - result: QueryResult::GetRecord(res), - stats, - .. - } => { - let ev = match res { - Ok(ok) => { - let results = ok - .records - .into_iter() - .map(|r| (r.record.key, r.record.value)) - .collect(); - - DiscoveryOut::ValueFound( - results, - stats.duration().unwrap_or_default(), - ) - }, - Err(e @ libp2p::kad::GetRecordError::NotFound { .. }) => { - trace!( - target: "sub-libp2p", - "Libp2p => Failed to get record: {:?}", - e, - ); - DiscoveryOut::ValueNotFound( - e.into_key(), - stats.duration().unwrap_or_default(), - ) - }, - Err(e) => { - debug!( - target: "sub-libp2p", - "Libp2p => Failed to get record: {:?}", - e, - ); - DiscoveryOut::ValueNotFound( - e.into_key(), - stats.duration().unwrap_or_default(), - ) - }, - }; - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) - }, - KademliaEvent::OutboundQueryCompleted { - result: QueryResult::PutRecord(res), - stats, - .. - } => { - let ev = match res { - Ok(ok) => DiscoveryOut::ValuePut( - ok.key, + Err(e) => { + debug!( + target: "sub-libp2p", + "Libp2p => Failed to get record: {:?}", + e, + ); + DiscoveryOut::ValueNotFound( + e.into_key(), stats.duration().unwrap_or_default(), - ), - Err(e) => { - debug!( - target: "sub-libp2p", - "Libp2p => Failed to put record: {:?}", - e, - ); - DiscoveryOut::ValuePutFailed( - e.into_key(), - stats.duration().unwrap_or_default(), - ) - }, - }; - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) - }, - KademliaEvent::OutboundQueryCompleted { - result: QueryResult::RepublishRecord(res), - .. - } => match res { - Ok(ok) => debug!( - target: "sub-libp2p", - "Libp2p => Record republished: {:?}", - ok.key, - ), - Err(e) => debug!( - target: "sub-libp2p", - "Libp2p => Republishing of record {:?} failed with: {:?}", - e.key(), e, - ), - }, - // We never start any other type of query. - KademliaEvent::OutboundQueryCompleted { result: e, .. } => { - warn!(target: "sub-libp2p", "Libp2p => Unhandled Kademlia event: {:?}", e) - }, + ) + }, + }; + return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) }, - NetworkBehaviourAction::Dial { opts, handler } => { - let pid = pid.clone(); - let handler = self.new_handler_with_replacement(pid, handler); - return Poll::Ready(NetworkBehaviourAction::Dial { opts, handler }) + KademliaEvent::OutboundQueryCompleted { + result: QueryResult::PutRecord(res), + stats, + .. + } => { + let ev = match res { + Ok(ok) => + DiscoveryOut::ValuePut(ok.key, stats.duration().unwrap_or_default()), + Err(e) => { + debug!( + target: "sub-libp2p", + "Libp2p => Failed to put record: {:?}", + e, + ); + DiscoveryOut::ValuePutFailed( + e.into_key(), + stats.duration().unwrap_or_default(), + ) + }, + }; + return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) }, - NetworkBehaviourAction::NotifyHandler { peer_id, handler, event } => - return Poll::Ready(NetworkBehaviourAction::NotifyHandler { - peer_id, - handler, - event: (pid.clone(), event), - }), - NetworkBehaviourAction::ReportObservedAddr { address, score } => - return Poll::Ready(NetworkBehaviourAction::ReportObservedAddr { - address, - score, - }), - NetworkBehaviourAction::CloseConnection { peer_id, connection } => - return Poll::Ready(NetworkBehaviourAction::CloseConnection { - peer_id, - connection, - }), - } + KademliaEvent::OutboundQueryCompleted { + result: QueryResult::RepublishRecord(res), + .. + } => match res { + Ok(ok) => debug!( + target: "sub-libp2p", + "Libp2p => Record republished: {:?}", + ok.key, + ), + Err(e) => debug!( + target: "sub-libp2p", + "Libp2p => Republishing of record {:?} failed with: {:?}", + e.key(), e, + ), + }, + // We never start any other type of query. + KademliaEvent::OutboundQueryCompleted { result: e, .. } => { + warn!(target: "sub-libp2p", "Libp2p => Unhandled Kademlia event: {:?}", e) + }, + }, + NetworkBehaviourAction::Dial { opts, handler } => + return Poll::Ready(NetworkBehaviourAction::Dial { opts, handler }), + NetworkBehaviourAction::NotifyHandler { peer_id, handler, event } => + return Poll::Ready(NetworkBehaviourAction::NotifyHandler { + peer_id, + handler, + event, + }), + NetworkBehaviourAction::ReportObservedAddr { address, score } => + return Poll::Ready(NetworkBehaviourAction::ReportObservedAddr { + address, + score, + }), + NetworkBehaviourAction::CloseConnection { peer_id, connection } => + return Poll::Ready(NetworkBehaviourAction::CloseConnection { + peer_id, + connection, + }), } } @@ -1014,7 +919,7 @@ mod tests { .allow_private_ipv4(true) .allow_non_globals_in_dht(true) .discovery_limit(50) - .add_protocol(protocol_id.clone()); + .with_kademlia(protocol_id.clone()); config.finish() }; @@ -1078,7 +983,7 @@ mod tests { to_discover[swarm_n].remove(&other); }, - DiscoveryOut::RandomKademliaStarted(_) => {}, + DiscoveryOut::RandomKademliaStarted => {}, e => { panic!("Unexpected event: {:?}", e) }, @@ -1117,7 +1022,7 @@ mod tests { .allow_private_ipv4(true) .allow_non_globals_in_dht(true) .discovery_limit(50) - .add_protocol(supported_protocol_id.clone()); + .with_kademlia(supported_protocol_id.clone()); config.finish() }; @@ -1131,7 +1036,8 @@ mod tests { remote_addr.clone(), ); - for kademlia in discovery.kademlias.values_mut() { + { + let kademlia = discovery.kademlia.as_mut().unwrap(); assert!( kademlia .kbucket(remote_peer_id) @@ -1148,66 +1054,14 @@ mod tests { remote_addr.clone(), ); - for kademlia in discovery.kademlias.values_mut() { - assert_eq!( - 1, - kademlia - .kbucket(remote_peer_id) - .expect("Remote peer id not to be equal to local peer id.") - .num_entries(), - "Expect peer with supported protocol to be added." - ); - } - } - - #[test] - fn discovery_adds_peer_to_kademlia_of_same_protocol_only() { - let protocol_a = ProtocolId::from("a"); - let protocol_b = ProtocolId::from("b"); - - let mut discovery = { - let keypair = Keypair::generate_ed25519(); - let mut config = DiscoveryConfig::new(keypair.public()); - config - .allow_private_ipv4(true) - .allow_non_globals_in_dht(true) - .discovery_limit(50) - .add_protocol(protocol_a.clone()) - .add_protocol(protocol_b.clone()); - config.finish() - }; - - let remote_peer_id = PeerId::random(); - let remote_addr: Multiaddr = format!("/memory/{}", rand::random::()).parse().unwrap(); - - // Add remote peer with `protocol_a` only. - discovery.add_self_reported_address( - &remote_peer_id, - &[protocol_name_from_protocol_id(&protocol_a)], - remote_addr.clone(), - ); - + let kademlia = discovery.kademlia.as_mut().unwrap(); assert_eq!( 1, - discovery - .kademlias - .get_mut(&protocol_a) - .expect("Kademlia instance to exist.") + kademlia .kbucket(remote_peer_id) .expect("Remote peer id not to be equal to local peer id.") .num_entries(), - "Expected remote peer to be added to `protocol_a` Kademlia instance.", - ); - - assert!( - discovery - .kademlias - .get_mut(&protocol_b) - .expect("Kademlia instance to exist.") - .kbucket(remote_peer_id) - .expect("Remote peer id not to be equal to local peer id.") - .is_empty(), - "Expected remote peer not to be added to `protocol_b` Kademlia instance.", + "Expect peer with supported protocol to be added." ); } } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index f95e67df142b0..d24a1543c56fe 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -284,7 +284,7 @@ where config.discovery_limit( u64::from(params.network_config.default_peers_set.out_peers) + 15, ); - config.add_protocol(params.protocol_id.clone()); + config.with_kademlia(params.protocol_id.clone()); config.with_dht_random_walk(params.network_config.enable_dht_random_walk); config.allow_non_globals_in_dht(params.network_config.allow_non_globals_in_dht); config.use_kademlia_disjoint_query_paths( @@ -1665,16 +1665,9 @@ where .user_protocol_mut() .add_default_set_discovered_nodes(iter::once(peer_id)); }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::RandomKademliaStarted( - protocols, - ))) => + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::RandomKademliaStarted)) => if let Some(metrics) = this.metrics.as_ref() { - for protocol in protocols { - metrics - .kademlia_random_queries_total - .with_label_values(&[protocol.as_ref()]) - .inc(); - } + metrics.kademlia_random_queries_total.inc(); }, Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::NotificationStreamOpened { remote, @@ -2015,28 +2008,21 @@ where this.is_major_syncing.store(is_major_syncing, Ordering::Relaxed); if let Some(metrics) = this.metrics.as_ref() { - for (proto, buckets) in this.network_service.behaviour_mut().num_entries_per_kbucket() { + if let Some(buckets) = this.network_service.behaviour_mut().num_entries_per_kbucket() { for (lower_ilog2_bucket_bound, num_entries) in buckets { metrics .kbuckets_num_nodes - .with_label_values(&[proto.as_ref(), &lower_ilog2_bucket_bound.to_string()]) + .with_label_values(&[&lower_ilog2_bucket_bound.to_string()]) .set(num_entries as u64); } } - for (proto, num_entries) in this.network_service.behaviour_mut().num_kademlia_records() - { - metrics - .kademlia_records_count - .with_label_values(&[proto.as_ref()]) - .set(num_entries as u64); + if let Some(num_entries) = this.network_service.behaviour_mut().num_kademlia_records() { + metrics.kademlia_records_count.set(num_entries as u64); } - for (proto, num_entries) in + if let Some(num_entries) = this.network_service.behaviour_mut().kademlia_records_total_size() { - metrics - .kademlia_records_sizes_total - .with_label_values(&[proto.as_ref()]) - .set(num_entries as u64); + metrics.kademlia_records_sizes_total.set(num_entries as u64); } metrics .peerset_num_discovered diff --git a/client/network/src/service/metrics.rs b/client/network/src/service/metrics.rs index 4b63df00b8d66..db1b6f7f6500d 100644 --- a/client/network/src/service/metrics.rs +++ b/client/network/src/service/metrics.rs @@ -59,9 +59,9 @@ pub struct Metrics { pub incoming_connections_total: Counter, pub issued_light_requests: Counter, pub kademlia_query_duration: HistogramVec, - pub kademlia_random_queries_total: CounterVec, - pub kademlia_records_count: GaugeVec, - pub kademlia_records_sizes_total: GaugeVec, + pub kademlia_random_queries_total: Counter, + pub kademlia_records_count: Gauge, + pub kademlia_records_sizes_total: Gauge, pub kbuckets_num_nodes: GaugeVec, pub listeners_local_addresses: Gauge, pub listeners_errors_total: Counter, @@ -138,33 +138,24 @@ impl Metrics { }, &["type"] )?, registry)?, - kademlia_random_queries_total: prometheus::register(CounterVec::new( - Opts::new( - "substrate_sub_libp2p_kademlia_random_queries_total", - "Number of random Kademlia queries started" - ), - &["protocol"] + kademlia_random_queries_total: prometheus::register(Counter::new( + "substrate_sub_libp2p_kademlia_random_queries_total", + "Number of random Kademlia queries started", )?, registry)?, - kademlia_records_count: prometheus::register(GaugeVec::new( - Opts::new( - "substrate_sub_libp2p_kademlia_records_count", - "Number of records in the Kademlia records store" - ), - &["protocol"] + kademlia_records_count: prometheus::register(Gauge::new( + "substrate_sub_libp2p_kademlia_records_count", + "Number of records in the Kademlia records store", )?, registry)?, - kademlia_records_sizes_total: prometheus::register(GaugeVec::new( - Opts::new( - "substrate_sub_libp2p_kademlia_records_sizes_total", - "Total size of all the records in the Kademlia records store" - ), - &["protocol"] + kademlia_records_sizes_total: prometheus::register(Gauge::new( + "substrate_sub_libp2p_kademlia_records_sizes_total", + "Total size of all the records in the Kademlia records store", )?, registry)?, kbuckets_num_nodes: prometheus::register(GaugeVec::new( Opts::new( "substrate_sub_libp2p_kbuckets_num_nodes", "Number of nodes per kbucket per Kademlia instance" ), - &["protocol", "lower_ilog2_bucket_bound"] + &["lower_ilog2_bucket_bound"] )?, registry)?, listeners_local_addresses: prometheus::register(Gauge::new( "substrate_sub_libp2p_listeners_local_addresses", From 460b64ba83473e218e39b266876f1693ae179231 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 20 Oct 2022 20:57:00 +0200 Subject: [PATCH 1296/1472] CI: Enable debug assertions in Wasmer sandbox test (#12540) * CI: Enable debug assertions in Wasmer sandbox test Signed-off-by: Oliver Tale-Yazdi * Fix feature dependant import Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/support/test/tests/construct_runtime_ui.rs | 6 ++---- scripts/ci/gitlab/pipeline/test.yml | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frame/support/test/tests/construct_runtime_ui.rs b/frame/support/test/tests/construct_runtime_ui.rs index 38aa780766835..42fd87ca95c0e 100644 --- a/frame/support/test/tests/construct_runtime_ui.rs +++ b/frame/support/test/tests/construct_runtime_ui.rs @@ -15,19 +15,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::env; - #[rustversion::attr(not(stable), ignore)] #[cfg(not(feature = "disable-ui-tests"))] #[test] fn ui() { // Only run the ui tests when `RUN_UI_TESTS` is set. - if env::var("RUN_UI_TESTS").is_err() { + if std::env::var("RUN_UI_TESTS").is_err() { return } // As trybuild is using `cargo check`, we don't need the real WASM binaries. - env::set_var("SKIP_WASM_BUILD", "1"); + std::env::set_var("SKIP_WASM_BUILD", "1"); let t = trybuild::TestCases::new(); t.compile_fail("tests/construct_runtime_ui/*.rs"); diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index e85ab85afe6ed..b405cfa1eb3a4 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -394,6 +394,10 @@ test-wasmer-sandbox: - .docker-env - .test-refs-wasmer-sandbox variables: + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUST_BACKTRACE: 1 + WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" CI_JOB_NAME: "test-wasmer-sandbox" parallel: 3 script: From 1125011be165fca564fb78c8a50124537a1f4d0e Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 21 Oct 2022 05:07:52 +0900 Subject: [PATCH 1297/1472] Force base weights to be the minimum only when the intercept is negative (#12482) * Force base weights to be the minimum only when the intercept is negative; emit minimum execution times * Add an `assert` making sure the intercept is zero when it's supposed to be zero * Fix template Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/bench-bot.sh" pallet dev pallet_assets * ".git/.scripts/bench-bot.sh" pallet dev pallet_uniques Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- .maintain/frame-weight-template.hbs | 2 + frame/assets/src/weights.rs | 213 +++++++++++------- frame/benchmarking/src/analysis.rs | 62 +++-- frame/uniques/src/weights.rs | 199 ++++++++++------ .../benchmarking-cli/src/pallet/template.hbs | 1 + .../benchmarking-cli/src/pallet/writer.rs | 3 + 6 files changed, 314 insertions(+), 166 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index b0244fbdab85b..96731770ff2ea 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -64,6 +64,7 @@ impl WeightInfo for SubstrateWeight { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { + // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} @@ -99,6 +100,7 @@ impl WeightInfo for () { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { + // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index cba78f12c218c..c260da70e3480 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -18,22 +18,25 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_assets // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_assets +// --chain=dev // --output=./frame/assets/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -74,13 +77,15 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - Weight::from_ref_time(27_167_000 as u64) + // Minimum execution time: 32_200 nanoseconds. + Weight::from_ref_time(32_739_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - Weight::from_ref_time(15_473_000 as u64) + // Minimum execution time: 19_192 nanoseconds. + Weight::from_ref_time(19_615_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -89,14 +94,16 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:5000 w:5000) // Storage: Assets Metadata (r:1 w:0) // Storage: Assets Approvals (r:501 w:500) + /// The range of component `c` is `[0, 5000]`. + /// The range of component `s` is `[0, 5000]`. + /// The range of component `a` is `[0, 500]`. fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(c as u64)) - // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(19_333_000 as u64).saturating_mul(s as u64)) - // Standard Error: 375_000 - .saturating_add(Weight::from_ref_time(17_046_000 as u64).saturating_mul(a as u64)) + // Minimum execution time: 75_299_531 nanoseconds. + Weight::from_ref_time(75_567_795_000 as u64) + // Standard Error: 126_181 + .saturating_add(Weight::from_ref_time(8_378_363 as u64).saturating_mul(c as u64)) + // Standard Error: 126_181 + .saturating_add(Weight::from_ref_time(10_950_076 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(c as u64))) .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) @@ -109,14 +116,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - Weight::from_ref_time(30_819_000 as u64) + // Minimum execution time: 35_066 nanoseconds. + Weight::from_ref_time(36_217_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - Weight::from_ref_time(35_212_000 as u64) + // Minimum execution time: 44_915 nanoseconds. + Weight::from_ref_time(45_807_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -124,7 +133,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(47_401_000 as u64) + // Minimum execution time: 57_245 nanoseconds. + Weight::from_ref_time(58_179_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -132,7 +142,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(42_300_000 as u64) + // Minimum execution time: 47_028 nanoseconds. + Weight::from_ref_time(47_571_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -140,93 +151,108 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - Weight::from_ref_time(47_946_000 as u64) + // Minimum execution time: 57_069 nanoseconds. + Weight::from_ref_time(58_245_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - Weight::from_ref_time(21_670_000 as u64) + // Minimum execution time: 26_823 nanoseconds. + Weight::from_ref_time(27_689_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - Weight::from_ref_time(21_503_000 as u64) + // Minimum execution time: 26_984 nanoseconds. + Weight::from_ref_time(27_591_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - Weight::from_ref_time(18_158_000 as u64) + // Minimum execution time: 23_803 nanoseconds. + Weight::from_ref_time(24_269_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - Weight::from_ref_time(18_525_000 as u64) + // Minimum execution time: 22_977 nanoseconds. + Weight::from_ref_time(23_527_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - Weight::from_ref_time(19_858_000 as u64) + // Minimum execution time: 23_815 nanoseconds. + Weight::from_ref_time(24_597_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(18_045_000 as u64) + // Minimum execution time: 22_691 nanoseconds. + Weight::from_ref_time(23_173_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn set_metadata(n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_395_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(n as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn set_metadata(_n: u32, _s: u32, ) -> Weight { + // Minimum execution time: 40_675 nanoseconds. + Weight::from_ref_time(42_869_113 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(32_893_000 as u64) + // Minimum execution time: 42_361 nanoseconds. + Weight::from_ref_time(42_912_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(19_586_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(s as u64)) + /// 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 { + // Minimum execution time: 22_998 nanoseconds. + Weight::from_ref_time(23_844_675 as u64) + // Standard Error: 506 + .saturating_add(Weight::from_ref_time(2_874 as u64).saturating_mul(n as u64)) + // Standard Error: 506 + .saturating_add(Weight::from_ref_time(3_817 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - Weight::from_ref_time(32_478_000 as u64) + // Minimum execution time: 42_305 nanoseconds. + Weight::from_ref_time(42_678_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - Weight::from_ref_time(17_143_000 as u64) + // Minimum execution time: 22_052 nanoseconds. + Weight::from_ref_time(22_610_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(36_389_000 as u64) + // Minimum execution time: 44_900 nanoseconds. + Weight::from_ref_time(46_032_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -235,21 +261,24 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - Weight::from_ref_time(61_854_000 as u64) + // Minimum execution time: 72_261 nanoseconds. + Weight::from_ref_time(73_186_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(36_759_000 as u64) + // Minimum execution time: 47_268 nanoseconds. + Weight::from_ref_time(47_712_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - Weight::from_ref_time(37_753_000 as u64) + // Minimum execution time: 47_363 nanoseconds. + Weight::from_ref_time(48_696_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -259,13 +288,15 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - Weight::from_ref_time(27_167_000 as u64) + // Minimum execution time: 32_200 nanoseconds. + Weight::from_ref_time(32_739_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - Weight::from_ref_time(15_473_000 as u64) + // Minimum execution time: 19_192 nanoseconds. + Weight::from_ref_time(19_615_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -274,14 +305,16 @@ impl WeightInfo for () { // Storage: System Account (r:5000 w:5000) // Storage: Assets Metadata (r:1 w:0) // Storage: Assets Approvals (r:501 w:500) + /// The range of component `c` is `[0, 5000]`. + /// The range of component `s` is `[0, 5000]`. + /// The range of component `a` is `[0, 500]`. fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(c as u64)) - // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(19_333_000 as u64).saturating_mul(s as u64)) - // Standard Error: 375_000 - .saturating_add(Weight::from_ref_time(17_046_000 as u64).saturating_mul(a as u64)) + // Minimum execution time: 75_299_531 nanoseconds. + Weight::from_ref_time(75_567_795_000 as u64) + // Standard Error: 126_181 + .saturating_add(Weight::from_ref_time(8_378_363 as u64).saturating_mul(c as u64)) + // Standard Error: 126_181 + .saturating_add(Weight::from_ref_time(10_950_076 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(c as u64))) .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) @@ -294,14 +327,16 @@ impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - Weight::from_ref_time(30_819_000 as u64) + // Minimum execution time: 35_066 nanoseconds. + Weight::from_ref_time(36_217_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - Weight::from_ref_time(35_212_000 as u64) + // Minimum execution time: 44_915 nanoseconds. + Weight::from_ref_time(45_807_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -309,7 +344,8 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(47_401_000 as u64) + // Minimum execution time: 57_245 nanoseconds. + Weight::from_ref_time(58_179_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -317,7 +353,8 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(42_300_000 as u64) + // Minimum execution time: 47_028 nanoseconds. + Weight::from_ref_time(47_571_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -325,93 +362,108 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - Weight::from_ref_time(47_946_000 as u64) + // Minimum execution time: 57_069 nanoseconds. + Weight::from_ref_time(58_245_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - Weight::from_ref_time(21_670_000 as u64) + // Minimum execution time: 26_823 nanoseconds. + Weight::from_ref_time(27_689_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - Weight::from_ref_time(21_503_000 as u64) + // Minimum execution time: 26_984 nanoseconds. + Weight::from_ref_time(27_591_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - Weight::from_ref_time(18_158_000 as u64) + // Minimum execution time: 23_803 nanoseconds. + Weight::from_ref_time(24_269_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - Weight::from_ref_time(18_525_000 as u64) + // Minimum execution time: 22_977 nanoseconds. + Weight::from_ref_time(23_527_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - Weight::from_ref_time(19_858_000 as u64) + // Minimum execution time: 23_815 nanoseconds. + Weight::from_ref_time(24_597_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(18_045_000 as u64) + // Minimum execution time: 22_691 nanoseconds. + Weight::from_ref_time(23_173_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn set_metadata(n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_395_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(n as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn set_metadata(_n: u32, _s: u32, ) -> Weight { + // Minimum execution time: 40_675 nanoseconds. + Weight::from_ref_time(42_869_113 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(32_893_000 as u64) + // Minimum execution time: 42_361 nanoseconds. + Weight::from_ref_time(42_912_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(19_586_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(s as u64)) + /// 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 { + // Minimum execution time: 22_998 nanoseconds. + Weight::from_ref_time(23_844_675 as u64) + // Standard Error: 506 + .saturating_add(Weight::from_ref_time(2_874 as u64).saturating_mul(n as u64)) + // Standard Error: 506 + .saturating_add(Weight::from_ref_time(3_817 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - Weight::from_ref_time(32_478_000 as u64) + // Minimum execution time: 42_305 nanoseconds. + Weight::from_ref_time(42_678_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - Weight::from_ref_time(17_143_000 as u64) + // Minimum execution time: 22_052 nanoseconds. + Weight::from_ref_time(22_610_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(36_389_000 as u64) + // Minimum execution time: 44_900 nanoseconds. + Weight::from_ref_time(46_032_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -420,21 +472,24 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - Weight::from_ref_time(61_854_000 as u64) + // Minimum execution time: 72_261 nanoseconds. + Weight::from_ref_time(73_186_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(36_759_000 as u64) + // Minimum execution time: 47_268 nanoseconds. + Weight::from_ref_time(47_712_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - Weight::from_ref_time(37_753_000 as u64) + // Minimum execution time: 47_363 nanoseconds. + Weight::from_ref_time(48_696_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index a736cdc203182..db8ee599ef731 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -26,6 +26,7 @@ pub struct Analysis { pub names: Vec, pub value_dists: Option, u128, u128)>>, pub errors: Option>, + pub minimum: u128, selector: BenchmarkSelector, } @@ -49,7 +50,10 @@ fn mul_1000_into_u128(value: f64) -> u128 { impl BenchmarkSelector { fn scale_and_cast_weight(self, value: f64, round_up: bool) -> u128 { if let BenchmarkSelector::ExtrinsicTime = self { - mul_1000_into_u128(value) + // We add a very slight bias here to counteract the numerical imprecision of the linear + // regression where due to rounding issues it can emit a number like `2999999.999999998` + // which we most certainly always want to round up instead of truncating. + mul_1000_into_u128(value + 0.000_000_005) } else { if round_up { (value + 0.5) as u128 @@ -74,6 +78,24 @@ impl BenchmarkSelector { value } } + + fn get_value(self, result: &BenchmarkResult) -> u128 { + match self { + BenchmarkSelector::ExtrinsicTime => result.extrinsic_time, + BenchmarkSelector::StorageRootTime => result.storage_root_time, + BenchmarkSelector::Reads => result.reads.into(), + BenchmarkSelector::Writes => result.writes.into(), + BenchmarkSelector::ProofSize => result.proof_size.into(), + } + } + + fn get_minimum(self, results: &[BenchmarkResult]) -> u128 { + results + .iter() + .map(|result| self.get_value(result)) + .min() + .expect("results cannot be empty") + } } #[derive(Debug)] @@ -109,8 +131,8 @@ impl TryFrom> for AnalysisChoice { } fn raw_linear_regression( - xs: Vec, - ys: Vec, + xs: &[f64], + ys: &[f64], x_vars: usize, with_intercept: bool, ) -> Option<(f64, Vec, Vec)> { @@ -147,6 +169,14 @@ fn linear_regression( mut ys: Vec, x_vars: usize, ) -> Option<(f64, Vec, Vec)> { + let (intercept, params, errors) = raw_linear_regression(&xs, &ys, x_vars, true)?; + if intercept > 0.0 { + return Some((intercept, params, errors[1..].to_vec())) + } + + // The intercept is negative. + // The weights must be always positive, so we can't have that. + let mut min = ys[0]; for &value in &ys { if value < min { @@ -158,8 +188,9 @@ fn linear_regression( *value -= min; } - let (intercept, params, errors) = raw_linear_regression(xs, ys, x_vars, false)?; - Some((intercept + min, params, errors[1..].to_vec())) + let (intercept, params, errors) = raw_linear_regression(&xs, &ys, x_vars, false)?; + assert!(intercept.abs() <= 0.0001); + Some((min, params, errors[1..].to_vec())) } impl Analysis { @@ -190,6 +221,7 @@ impl Analysis { names: Vec::new(), value_dists: None, errors: None, + minimum: selector.get_minimum(&r), selector, }) } @@ -289,6 +321,7 @@ impl Analysis { names: results.into_iter().map(|x| x.0).collect::>(), value_dists: None, errors: None, + minimum: selector.get_minimum(&r), selector, }) } @@ -361,6 +394,7 @@ impl Analysis { .map(|value| selector.scale_and_cast_weight(value, false)) .collect(), ), + minimum: selector.get_minimum(&r), selector, }) } @@ -392,8 +426,9 @@ impl Analysis { let names = median_slopes.names; let value_dists = min_squares.value_dists; let errors = min_squares.errors; + let minimum = selector.get_minimum(&r); - Some(Self { base, slopes, names, value_dists, errors, selector }) + Some(Self { base, slopes, names, value_dists, errors, selector, minimum }) } } @@ -533,8 +568,7 @@ mod tests { 16.0, 17.0, 18.0, 19.0, 20.0, ]; - let (intercept, params, errors) = - raw_linear_regression(xs.clone(), ys.clone(), 1, true).unwrap(); + let (intercept, params, errors) = raw_linear_regression(&xs, &ys, 1, true).unwrap(); assert_eq!(intercept as i64, -2712997); assert_eq!(params.len(), 1); assert_eq!(params[0] as i64, 34444926); @@ -688,15 +722,15 @@ mod tests { let extrinsic_time = Analysis::min_squares_iqr(&data, BenchmarkSelector::ExtrinsicTime).unwrap(); - assert_eq!(extrinsic_time.base, 11_500_000_000); - assert_eq!(extrinsic_time.slopes, vec![630635838, 23699421]); + assert_eq!(extrinsic_time.base, 10_000_000_000); + assert_eq!(extrinsic_time.slopes, vec![1000000000, 100000000]); let reads = Analysis::min_squares_iqr(&data, BenchmarkSelector::Reads).unwrap(); - assert_eq!(reads.base, 3); + assert_eq!(reads.base, 2); assert_eq!(reads.slopes, vec![1, 0]); let writes = Analysis::min_squares_iqr(&data, BenchmarkSelector::Writes).unwrap(); - assert_eq!(writes.base, 2); + assert_eq!(writes.base, 0); assert_eq!(writes.slopes, vec![0, 2]); } @@ -711,7 +745,7 @@ mod tests { let extrinsic_time = Analysis::min_squares_iqr(&data, BenchmarkSelector::ExtrinsicTime).unwrap(); - assert_eq!(extrinsic_time.base, 2_000_000_000); - assert_eq!(extrinsic_time.slopes, vec![4_000_000_000]); + assert_eq!(extrinsic_time.base, 3_000_000_000); + assert_eq!(extrinsic_time.slopes, vec![3_000_000_000]); } } diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index c7a8a2f6baa0f..a134b68d093b6 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,12 +18,12 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-07-13, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `test-bench-bot`, CPU: `Intel(R) Xeon(R) CPU @ 3.10GHz` +//! DATE: 2022-10-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet // --steps=50 @@ -32,6 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json // --pallet=pallet_uniques // --chain=dev // --output=./frame/uniques/src/weights.rs @@ -80,14 +81,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(33_075_000 as u64) + // Minimum execution time: 32_901 nanoseconds. + Weight::from_ref_time(33_628_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - Weight::from_ref_time(19_528_000 as u64) + // Minimum execution time: 21_633 nanoseconds. + Weight::from_ref_time(22_380_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -103,13 +106,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(13_639_000 as u64).saturating_mul(n as u64)) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_393_000 as u64).saturating_mul(m as u64)) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_217_000 as u64).saturating_mul(a as u64)) + // Minimum execution time: 2_429_508 nanoseconds. + Weight::from_ref_time(2_446_263_000 as u64) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(8_477_090 as u64).saturating_mul(n as u64)) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(314_268 as u64).saturating_mul(m as u64)) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(249_624 as u64).saturating_mul(a as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -122,7 +126,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - Weight::from_ref_time(42_146_000 as u64) + // Minimum execution time: 41_938 nanoseconds. + Weight::from_ref_time(42_814_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -131,7 +136,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - Weight::from_ref_time(42_960_000 as u64) + // Minimum execution time: 43_593 nanoseconds. + Weight::from_ref_time(44_420_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -140,17 +146,19 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - Weight::from_ref_time(33_025_000 as u64) + // Minimum execution time: 34_037 nanoseconds. + Weight::from_ref_time(34_848_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:100 w:100) + // Storage: Uniques Asset (r:102 w:102) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 24_000 - .saturating_add(Weight::from_ref_time(15_540_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 23_295 nanoseconds. + Weight::from_ref_time(23_482_000 as u64) + // Standard Error: 9_490 + .saturating_add(Weight::from_ref_time(10_899_320 as u64).saturating_mul(i as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(i as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -159,26 +167,30 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - Weight::from_ref_time(25_194_000 as u64) + // Minimum execution time: 27_005 nanoseconds. + Weight::from_ref_time(27_344_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - Weight::from_ref_time(25_397_000 as u64) + // Minimum execution time: 26_815 nanoseconds. + Weight::from_ref_time(27_400_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - Weight::from_ref_time(19_278_000 as u64) + // Minimum execution time: 21_988 nanoseconds. + Weight::from_ref_time(22_596_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - Weight::from_ref_time(19_304_000 as u64) + // Minimum execution time: 21_886 nanoseconds. + Weight::from_ref_time(22_617_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -186,20 +198,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - Weight::from_ref_time(28_615_000 as u64) + // Minimum execution time: 30_241 nanoseconds. + Weight::from_ref_time(30_677_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(19_943_000 as u64) + // Minimum execution time: 23_011 nanoseconds. + Weight::from_ref_time(23_796_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - Weight::from_ref_time(22_583_000 as u64) + // Minimum execution time: 25_739 nanoseconds. + Weight::from_ref_time(26_572_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -207,7 +222,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - Weight::from_ref_time(47_520_000 as u64) + // Minimum execution time: 48_486 nanoseconds. + Weight::from_ref_time(49_029_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -215,69 +231,79 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - Weight::from_ref_time(45_316_000 as u64) + // Minimum execution time: 47_408 nanoseconds. + Weight::from_ref_time(48_753_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - Weight::from_ref_time(38_391_000 as u64) + // Minimum execution time: 40_085 nanoseconds. + Weight::from_ref_time(40_625_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(38_023_000 as u64) + // Minimum execution time: 40_546 nanoseconds. + Weight::from_ref_time(41_113_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - Weight::from_ref_time(37_398_000 as u64) + // Minimum execution time: 39_902 nanoseconds. + Weight::from_ref_time(40_599_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - Weight::from_ref_time(35_621_000 as u64) + // Minimum execution time: 37_597 nanoseconds. + Weight::from_ref_time(37_964_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(25_856_000 as u64) + // Minimum execution time: 28_719 nanoseconds. + Weight::from_ref_time(29_213_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(26_098_000 as u64) + // Minimum execution time: 27_608 nanoseconds. + Weight::from_ref_time(28_096_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - Weight::from_ref_time(24_076_000 as u64) + // Minimum execution time: 25_568 nanoseconds. + Weight::from_ref_time(26_098_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - Weight::from_ref_time(22_035_000 as u64) + // Minimum execution time: 24_521 nanoseconds. + Weight::from_ref_time(25_062_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - Weight::from_ref_time(22_534_000 as u64) + // Minimum execution time: 25_337 nanoseconds. + Weight::from_ref_time(25_902_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -286,7 +312,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - Weight::from_ref_time(45_272_000 as u64) + // Minimum execution time: 46_736 nanoseconds. + Weight::from_ref_time(47_264_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -297,14 +324,16 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(33_075_000 as u64) + // Minimum execution time: 32_901 nanoseconds. + Weight::from_ref_time(33_628_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - Weight::from_ref_time(19_528_000 as u64) + // Minimum execution time: 21_633 nanoseconds. + Weight::from_ref_time(22_380_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -320,13 +349,14 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(13_639_000 as u64).saturating_mul(n as u64)) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_393_000 as u64).saturating_mul(m as u64)) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_217_000 as u64).saturating_mul(a as u64)) + // Minimum execution time: 2_429_508 nanoseconds. + Weight::from_ref_time(2_446_263_000 as u64) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(8_477_090 as u64).saturating_mul(n as u64)) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(314_268 as u64).saturating_mul(m as u64)) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(249_624 as u64).saturating_mul(a as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -339,7 +369,8 @@ impl WeightInfo for () { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - Weight::from_ref_time(42_146_000 as u64) + // Minimum execution time: 41_938 nanoseconds. + Weight::from_ref_time(42_814_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -348,7 +379,8 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - Weight::from_ref_time(42_960_000 as u64) + // Minimum execution time: 43_593 nanoseconds. + Weight::from_ref_time(44_420_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -357,17 +389,19 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - Weight::from_ref_time(33_025_000 as u64) + // Minimum execution time: 34_037 nanoseconds. + Weight::from_ref_time(34_848_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:100 w:100) + // Storage: Uniques Asset (r:102 w:102) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 24_000 - .saturating_add(Weight::from_ref_time(15_540_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 23_295 nanoseconds. + Weight::from_ref_time(23_482_000 as u64) + // Standard Error: 9_490 + .saturating_add(Weight::from_ref_time(10_899_320 as u64).saturating_mul(i as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(i as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) @@ -376,26 +410,30 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - Weight::from_ref_time(25_194_000 as u64) + // Minimum execution time: 27_005 nanoseconds. + Weight::from_ref_time(27_344_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - Weight::from_ref_time(25_397_000 as u64) + // Minimum execution time: 26_815 nanoseconds. + Weight::from_ref_time(27_400_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - Weight::from_ref_time(19_278_000 as u64) + // Minimum execution time: 21_988 nanoseconds. + Weight::from_ref_time(22_596_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - Weight::from_ref_time(19_304_000 as u64) + // Minimum execution time: 21_886 nanoseconds. + Weight::from_ref_time(22_617_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -403,20 +441,23 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - Weight::from_ref_time(28_615_000 as u64) + // Minimum execution time: 30_241 nanoseconds. + Weight::from_ref_time(30_677_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(19_943_000 as u64) + // Minimum execution time: 23_011 nanoseconds. + Weight::from_ref_time(23_796_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - Weight::from_ref_time(22_583_000 as u64) + // Minimum execution time: 25_739 nanoseconds. + Weight::from_ref_time(26_572_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -424,7 +465,8 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - Weight::from_ref_time(47_520_000 as u64) + // Minimum execution time: 48_486 nanoseconds. + Weight::from_ref_time(49_029_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -432,69 +474,79 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - Weight::from_ref_time(45_316_000 as u64) + // Minimum execution time: 47_408 nanoseconds. + Weight::from_ref_time(48_753_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - Weight::from_ref_time(38_391_000 as u64) + // Minimum execution time: 40_085 nanoseconds. + Weight::from_ref_time(40_625_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(38_023_000 as u64) + // Minimum execution time: 40_546 nanoseconds. + Weight::from_ref_time(41_113_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - Weight::from_ref_time(37_398_000 as u64) + // Minimum execution time: 39_902 nanoseconds. + Weight::from_ref_time(40_599_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - Weight::from_ref_time(35_621_000 as u64) + // Minimum execution time: 37_597 nanoseconds. + Weight::from_ref_time(37_964_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(25_856_000 as u64) + // Minimum execution time: 28_719 nanoseconds. + Weight::from_ref_time(29_213_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(26_098_000 as u64) + // Minimum execution time: 27_608 nanoseconds. + Weight::from_ref_time(28_096_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - Weight::from_ref_time(24_076_000 as u64) + // Minimum execution time: 25_568 nanoseconds. + Weight::from_ref_time(26_098_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - Weight::from_ref_time(22_035_000 as u64) + // Minimum execution time: 24_521 nanoseconds. + Weight::from_ref_time(25_062_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - Weight::from_ref_time(22_534_000 as u64) + // Minimum execution time: 25_337 nanoseconds. + Weight::from_ref_time(25_902_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -503,7 +555,8 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - Weight::from_ref_time(45_272_000 as u64) + // Minimum execution time: 46_736 nanoseconds. + Weight::from_ref_time(47_264_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index fbe435edf8fc3..7e2e0688d654f 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -33,6 +33,7 @@ impl {{pallet}}::WeightInfo for WeightInfo { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { + // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index cd52ffc329d1c..a52bbcd229cb1 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -69,6 +69,8 @@ struct BenchmarkData { component_writes: Vec, component_ranges: Vec, comments: Vec, + #[serde(serialize_with = "string_serialize")] + min_execution_time: u128, } // This forwards some specific metadata from the `PalletCmd` @@ -257,6 +259,7 @@ fn get_benchmark_data( component_writes: used_writes, component_ranges, comments, + min_execution_time: extrinsic_time.minimum, } } From a8a8394b855fd988fc879ee0dfea9cdab98f5f86 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 20 Oct 2022 23:06:12 +0200 Subject: [PATCH 1298/1472] Add `DefensiveTruncateFrom` (#12515) * Add DefensiveTruncateFrom Signed-off-by: Oliver Tale-Yazdi * Add tests Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * Map_err in preimage Signed-off-by: Oliver Tale-Yazdi * Map_err in beefy Signed-off-by: Oliver Tale-Yazdi * Make test dependant in debug-assertions Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- frame/beefy/src/lib.rs | 3 +- frame/preimage/src/lib.rs | 1 + frame/support/src/traits.rs | 9 ++- frame/support/src/traits/misc.rs | 89 ++++++++++++++++++++++ primitives/core/src/bounded/bounded_vec.rs | 73 +++++++++++++++++- 5 files changed, 168 insertions(+), 7 deletions(-) diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index fce531d3f5dd7..305b158124b67 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -159,7 +159,8 @@ impl Pallet { } let bounded_authorities = - BoundedSlice::::try_from(authorities.as_slice())?; + BoundedSlice::::try_from(authorities.as_slice()) + .map_err(|_| ())?; let id = 0; >::put(bounded_authorities); diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index e899d3643dbbf..6549832c11f5d 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -342,6 +342,7 @@ impl Pallet { fn insert(hash: &T::Hash, preimage: Cow<[u8]>) -> Result<(), ()> { BoundedSlice::>::try_from(preimage.as_ref()) + .map_err(|_| ()) .map(|s| PreimageFor::::insert((hash, s.len() as u32), s)) } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 302d3354dae5e..2b6c5efee10bb 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -56,10 +56,11 @@ mod misc; pub use misc::{ defensive_prelude::{self, *}, Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, - ConstU32, ConstU64, ConstU8, DefensiveSaturating, EnsureInherentsAreFirst, EqualPrivilegeOnly, - EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, - IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, - SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime, WrapperKeepOpaque, WrapperOpaque, + ConstU32, ConstU64, ConstU8, DefensiveSaturating, DefensiveTruncateFrom, + EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, + GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, + OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, TypedGet, + UnixTime, WrapperKeepOpaque, WrapperOpaque, }; #[allow(deprecated)] pub use misc::{PreimageProvider, PreimageRecipient}; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 5a976478fa7c4..1297956b2f64e 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -22,6 +22,7 @@ use codec::{CompactLen, Decode, DecodeLimit, Encode, EncodeLike, Input, MaxEncod use impl_trait_for_tuples::impl_for_tuples; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; use sp_arithmetic::traits::{CheckedAdd, CheckedMul, CheckedSub, Saturating}; +use sp_core::bounded::bounded_vec::TruncateFrom; #[doc(hidden)] pub use sp_runtime::traits::{ ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, ConstU32, @@ -369,6 +370,43 @@ impl DefensiveSaturating f } } +/// Construct an object by defensively truncating an input if the `TryFrom` conversion fails. +pub trait DefensiveTruncateFrom { + /// Use `TryFrom` first and defensively fall back to truncating otherwise. + /// + /// # Example + /// + /// ``` + /// use frame_support::{BoundedVec, traits::DefensiveTruncateFrom}; + /// use sp_runtime::traits::ConstU32; + /// + /// let unbound = vec![1, 2]; + /// let bound = BoundedVec::>::defensive_truncate_from(unbound); + /// + /// assert_eq!(bound, vec![1, 2]); + /// ``` + fn defensive_truncate_from(unbound: T) -> Self; +} + +impl DefensiveTruncateFrom for T +where + // NOTE: We use the fact that `BoundedVec` and + // `BoundedSlice` use `Self` as error type. We could also + // require a `Clone` bound and use `unbound.clone()` in the + // error case. + T: TruncateFrom + TryFrom, +{ + fn defensive_truncate_from(unbound: U) -> Self { + unbound.try_into().map_or_else( + |err| { + defensive!("DefensiveTruncateFrom truncating"); + T::truncate_from(err) + }, + |bound| bound, + ) + } +} + /// Anything that can have a `::len()` method. pub trait Len { /// Return the length of data type. @@ -950,8 +988,59 @@ impl PreimageRecipient for () { #[cfg(test)] mod test { use super::*; + use sp_core::bounded::{BoundedSlice, BoundedVec}; use sp_std::marker::PhantomData; + #[test] + #[cfg(not(debug_assertions))] + fn defensive_truncating_from_vec_defensive_works() { + let unbound = vec![1u32, 2]; + let bound = BoundedVec::>::defensive_truncate_from(unbound); + assert_eq!(bound, vec![1u32]); + } + + #[test] + #[cfg(not(debug_assertions))] + fn defensive_truncating_from_slice_defensive_works() { + let unbound = &[1u32, 2]; + let bound = BoundedSlice::>::defensive_truncate_from(unbound); + assert_eq!(bound, &[1u32][..]); + } + + #[test] + #[cfg(debug_assertions)] + #[should_panic( + expected = "Defensive failure has been triggered!: \"DefensiveTruncateFrom truncating\"" + )] + fn defensive_truncating_from_vec_defensive_panics() { + let unbound = vec![1u32, 2]; + let _ = BoundedVec::>::defensive_truncate_from(unbound); + } + + #[test] + #[cfg(debug_assertions)] + #[should_panic( + expected = "Defensive failure has been triggered!: \"DefensiveTruncateFrom truncating\"" + )] + fn defensive_truncating_from_slice_defensive_panics() { + let unbound = &[1u32, 2]; + let _ = BoundedSlice::>::defensive_truncate_from(unbound); + } + + #[test] + fn defensive_truncate_from_vec_works() { + let unbound = vec![1u32, 2, 3]; + let bound = BoundedVec::>::defensive_truncate_from(unbound.clone()); + assert_eq!(bound, unbound); + } + + #[test] + fn defensive_truncate_from_slice_works() { + let unbound = [1u32, 2, 3]; + let bound = BoundedSlice::>::defensive_truncate_from(&unbound); + assert_eq!(bound, &unbound[..]); + } + #[derive(Encode, Decode)] enum NestedType { Nested(Box), diff --git a/primitives/core/src/bounded/bounded_vec.rs b/primitives/core/src/bounded/bounded_vec.rs index 1832e43e8646c..2f39f3340ce50 100644 --- a/primitives/core/src/bounded/bounded_vec.rs +++ b/primitives/core/src/bounded/bounded_vec.rs @@ -47,6 +47,12 @@ pub struct BoundedVec( #[cfg_attr(feature = "std", serde(skip_serializing))] PhantomData, ); +/// Create an object through truncation. +pub trait TruncateFrom { + /// Create an object through truncation. + fn truncate_from(unbound: T) -> Self; +} + #[cfg(feature = "std")] impl<'de, T, S: Get> Deserialize<'de> for BoundedVec where @@ -234,12 +240,12 @@ impl<'a, T: Ord, Bound: Get> Ord for BoundedSlice<'a, T, Bound> { } impl<'a, T, S: Get> TryFrom<&'a [T]> for BoundedSlice<'a, T, S> { - type Error = (); + type Error = &'a [T]; fn try_from(t: &'a [T]) -> Result { if t.len() <= S::get() as usize { Ok(BoundedSlice(t, PhantomData)) } else { - Err(()) + Err(t) } } } @@ -250,12 +256,28 @@ impl<'a, T, S> From> for &'a [T] { } } +impl<'a, T, S: Get> TruncateFrom<&'a [T]> for BoundedSlice<'a, T, S> { + fn truncate_from(unbound: &'a [T]) -> Self { + BoundedSlice::::truncate_from(unbound) + } +} + impl<'a, T, S> Clone for BoundedSlice<'a, T, S> { fn clone(&self) -> Self { BoundedSlice(self.0, PhantomData) } } +impl<'a, T, S> sp_std::fmt::Debug for BoundedSlice<'a, T, S> +where + &'a [T]: sp_std::fmt::Debug, + S: Get, +{ + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + f.debug_tuple("BoundedSlice").field(&self.0).field(&S::get()).finish() + } +} + // Since a reference `&T` is always `Copy`, so is `BoundedSlice<'a, T, S>`. impl<'a, T, S> Copy for BoundedSlice<'a, T, S> {} @@ -692,6 +714,12 @@ impl> TryFrom> for BoundedVec { } } +impl> TruncateFrom> for BoundedVec { + fn truncate_from(unbound: Vec) -> Self { + BoundedVec::::truncate_from(unbound) + } +} + // It is okay to give a non-mutable reference of the inner vec to anyone. impl AsRef> for BoundedVec { fn as_ref(&self) -> &Vec { @@ -809,6 +837,12 @@ where } } +impl<'a, T: PartialEq, S: Get> PartialEq<&'a [T]> for BoundedSlice<'a, T, S> { + fn eq(&self, other: &&'a [T]) -> bool { + &self.0 == other + } +} + impl> PartialEq> for BoundedVec { fn eq(&self, other: &Vec) -> bool { &self.0 == other @@ -1219,6 +1253,18 @@ pub mod test { assert!(b2.is_err()); } + #[test] + fn bounded_vec_debug_works() { + let bound = BoundedVec::>::truncate_from(vec![1, 2, 3]); + assert_eq!(format!("{:?}", bound), "BoundedVec([1, 2, 3], 5)"); + } + + #[test] + fn bounded_slice_debug_works() { + let bound = BoundedSlice::>::truncate_from(&[1, 2, 3]); + assert_eq!(format!("{:?}", bound), "BoundedSlice([1, 2, 3], 5)"); + } + #[test] fn bounded_vec_sort_by_key_works() { let mut v: BoundedVec> = bounded_vec![-5, 4, 1, -3, 2]; @@ -1226,4 +1272,27 @@ pub mod test { v.sort_by_key(|k| k.abs()); assert_eq!(v, vec![1, 2, -3, 4, -5]); } + + #[test] + fn bounded_vec_truncate_from_works() { + let unbound = vec![1, 2, 3, 4, 5]; + let bound = BoundedVec::>::truncate_from(unbound.clone()); + assert_eq!(bound, vec![1, 2, 3]); + } + + #[test] + fn bounded_slice_truncate_from_works() { + let unbound = [1, 2, 3, 4, 5]; + let bound = BoundedSlice::>::truncate_from(&unbound); + assert_eq!(bound, &[1, 2, 3][..]); + } + + #[test] + fn bounded_slice_partialeq_slice_works() { + let unbound = [1, 2, 3]; + let bound = BoundedSlice::>::truncate_from(&unbound); + + assert_eq!(bound, &unbound[..]); + assert!(bound == &unbound[..]); + } } From ac176294e647f0eabd0970537567bf37ded00360 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Fri, 21 Oct 2022 09:39:23 +0300 Subject: [PATCH 1299/1472] Refactor service tests in `sc-network` (#12517) * Refactor service tests in `sc-network` Create a separate directory for the tests and move common network instantion related code to `mod.rs` from where it can be used by both service and chainsync tests. Use the builder pattern when creating the `TestNetwork` object to reduce code duplication between the test files. * Update client/network/src/service/tests/mod.rs Co-authored-by: Dmitrii Markin Co-authored-by: Dmitrii Markin Co-authored-by: parity-processbot <> --- client/network/src/service.rs | 2 - .../chain_sync.rs} | 205 +------ client/network/src/service/tests/mod.rs | 297 ++++++++++ .../service/{tests.rs => tests/service.rs} | 511 ++++++------------ 4 files changed, 500 insertions(+), 515 deletions(-) rename client/network/src/service/{chainsync_tests.rs => tests/chain_sync.rs} (52%) create mode 100644 client/network/src/service/tests/mod.rs rename client/network/src/service/{tests.rs => tests/service.rs} (56%) diff --git a/client/network/src/service.rs b/client/network/src/service.rs index d24a1543c56fe..8dfd46f24a731 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -94,8 +94,6 @@ use std::{ pub use behaviour::{InboundFailure, OutboundFailure, ResponseFailure}; -#[cfg(test)] -mod chainsync_tests; mod metrics; mod out_events; #[cfg(test)] diff --git a/client/network/src/service/chainsync_tests.rs b/client/network/src/service/tests/chain_sync.rs similarity index 52% rename from client/network/src/service/chainsync_tests.rs rename to client/network/src/service/tests/chain_sync.rs index 27c0588a67200..7ff8c589d8550 100644 --- a/client/network/src/service/chainsync_tests.rs +++ b/client/network/src/service/tests/chain_sync.rs @@ -16,178 +16,26 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{config, ChainSyncInterface, NetworkWorker}; +use crate::service::tests::TestNetworkBuilder; use futures::prelude::*; use libp2p::PeerId; use sc_block_builder::BlockBuilderProvider; -use sc_client_api::{BlockBackend, HeaderBackend}; +use sc_client_api::HeaderBackend; use sc_consensus::JustificationSyncLink; use sc_network_common::{ - config::{ - NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, - TransportConfig, - }, - protocol::role::Roles, service::NetworkSyncForkRequest, - sync::{message::BlockAnnouncesHandshake, ChainSync as ChainSyncT, SyncState, SyncStatus}, -}; -use sc_network_light::light_client_requests::handler::LightClientRequestHandler; -use sc_network_sync::{ - block_request_handler::BlockRequestHandler, mock::MockChainSync, - service::mock::MockChainSyncInterface, state_request_handler::StateRequestHandler, + sync::{SyncState, SyncStatus}, }; +use sc_network_sync::{mock::MockChainSync, service::mock::MockChainSyncInterface}; use sp_core::H256; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, Header as _, Zero}, + traits::{Block as BlockT, Header as _}, }; use std::{iter, sync::Arc, task::Poll}; use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; -type TestNetworkWorker = NetworkWorker< - substrate_test_runtime_client::runtime::Block, - substrate_test_runtime_client::runtime::Hash, - substrate_test_runtime_client::TestClient, ->; - -const BLOCK_ANNOUNCE_PROTO_NAME: &str = "/block-announces"; -const PROTOCOL_NAME: &str = "/foo"; - -fn make_network( - chain_sync: Box>, - chain_sync_service: Box>, - client: Arc, -) -> (TestNetworkWorker, Arc) { - let network_config = config::NetworkConfiguration { - extra_sets: vec![NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME.into(), - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: Default::default(), - }], - listen_addresses: vec![config::build_multiaddr![Memory(rand::random::())]], - transport: TransportConfig::MemoryOnly, - ..config::NetworkConfiguration::new_local() - }; - - #[derive(Clone)] - struct PassThroughVerifier(bool); - - #[async_trait::async_trait] - impl sc_consensus::Verifier for PassThroughVerifier { - async fn verify( - &mut self, - mut block: sc_consensus::BlockImportParams, - ) -> Result< - ( - sc_consensus::BlockImportParams, - Option)>>, - ), - String, - > { - let maybe_keys = block - .header - .digest() - .log(|l| { - l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"aura")) - .or_else(|| { - l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus( - b"babe", - )) - }) - }) - .map(|blob| { - vec![(sp_blockchain::well_known_cache_keys::AUTHORITIES, blob.to_vec())] - }); - - block.finalized = self.0; - block.fork_choice = Some(sc_consensus::ForkChoiceStrategy::LongestChain); - Ok((block, maybe_keys)) - } - } - - let import_queue = Box::new(sc_consensus::BasicQueue::new( - PassThroughVerifier(false), - Box::new(client.clone()), - None, - &sp_core::testing::TaskExecutor::new(), - None, - )); - - let protocol_id = ProtocolId::from("/test-protocol-name"); - - let fork_id = Some(String::from("test-fork-id")); - - let block_request_protocol_config = { - let (handler, protocol_config) = - BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); - async_std::task::spawn(handler.run().boxed()); - protocol_config - }; - - let state_request_protocol_config = { - let (handler, protocol_config) = - StateRequestHandler::new(&protocol_id, None, client.clone(), 50); - async_std::task::spawn(handler.run().boxed()); - protocol_config - }; - - let light_client_request_protocol_config = { - let (handler, protocol_config) = - LightClientRequestHandler::new(&protocol_id, None, client.clone()); - async_std::task::spawn(handler.run().boxed()); - protocol_config - }; - - let block_announce_config = NonDefaultSetConfig { - notifications_protocol: BLOCK_ANNOUNCE_PROTO_NAME.into(), - fallback_names: vec![], - max_notification_size: 1024 * 1024, - handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::< - substrate_test_runtime_client::runtime::Block, - >::build( - Roles::from(&config::Role::Full), - client.info().best_number, - client.info().best_hash, - client - .block_hash(Zero::zero()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), - ))), - set_config: SetConfig { - in_peers: 0, - out_peers: 0, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Deny, - }, - }; - - let worker = NetworkWorker::new(config::Params { - block_announce_config, - role: config::Role::Full, - executor: None, - network_config, - chain: client.clone(), - protocol_id, - fork_id, - import_queue, - chain_sync, - chain_sync_service, - metrics_registry: None, - block_request_protocol_config, - state_request_protocol_config, - light_client_request_protocol_config, - warp_sync_protocol_config: None, - request_response_protocol_configs: Vec::new(), - }) - .unwrap(); - - (worker, client) -} - fn set_default_expecations_no_peers( chain_sync: &mut MockChainSync, ) { @@ -208,8 +56,6 @@ fn set_default_expecations_no_peers( #[async_std::test] async fn normal_network_poll_no_peers() { - let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); - // build `ChainSync` and set default expectations for it let mut chain_sync = Box::new(MockChainSync::::new()); @@ -220,11 +66,13 @@ async fn normal_network_poll_no_peers() { let chain_sync_service = Box::new(MockChainSyncInterface::::new()); - let (mut network, _) = make_network(chain_sync, chain_sync_service, client); + let mut network = TestNetworkBuilder::new() + .with_chain_sync((chain_sync, chain_sync_service)) + .build(); // poll the network once futures::future::poll_fn(|cx| { - let _ = network.poll_unpin(cx); + let _ = network.network().poll_unpin(cx); Poll::Ready(()) }) .await; @@ -232,8 +80,6 @@ async fn normal_network_poll_no_peers() { #[async_std::test] async fn request_justification() { - let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); - // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be // called) let chain_sync_service = @@ -253,22 +99,22 @@ async fn request_justification() { .returning(|_, _| ()); set_default_expecations_no_peers(&mut chain_sync); - let (mut network, _) = make_network(chain_sync, chain_sync_service, client); + let mut network = TestNetworkBuilder::new() + .with_chain_sync((chain_sync, chain_sync_service)) + .build(); // send "request justifiction" message and poll the network network.service().request_justification(&hash, number); futures::future::poll_fn(|cx| { - let _ = network.poll_unpin(cx); + let _ = network.network().poll_unpin(cx); Poll::Ready(()) }) .await; } #[async_std::test] -async fn clear_justification_requests(&mut self) { - let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); - +async fn clear_justification_requests() { // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be // called) let chain_sync_service = @@ -281,13 +127,15 @@ async fn clear_justification_requests(&mut self) { chain_sync.expect_clear_justification_requests().once().returning(|| ()); set_default_expecations_no_peers(&mut chain_sync); - let (mut network, _) = make_network(chain_sync, chain_sync_service, client); + let mut network = TestNetworkBuilder::new() + .with_chain_sync((chain_sync, chain_sync_service)) + .build(); // send "request justifiction" message and poll the network network.service().clear_justification_requests(); futures::future::poll_fn(|cx| { - let _ = network.poll_unpin(cx); + let _ = network.network().poll_unpin(cx); Poll::Ready(()) }) .await; @@ -295,8 +143,6 @@ async fn clear_justification_requests(&mut self) { #[async_std::test] async fn set_sync_fork_request() { - let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); - // build `ChainSync` and set default expectations for it let mut chain_sync = Box::new(MockChainSync::::new()); @@ -320,13 +166,15 @@ async fn set_sync_fork_request() { .once() .returning(|_, _, _| ()); - let (mut network, _) = make_network(chain_sync, Box::new(chain_sync_service), client); + let mut network = TestNetworkBuilder::new() + .with_chain_sync((chain_sync, Box::new(chain_sync_service))) + .build(); // send "set sync fork request" message and poll the network network.service().set_sync_fork_request(copy_peers, hash, number); futures::future::poll_fn(|cx| { - let _ = network.poll_unpin(cx); + let _ = network.network().poll_unpin(cx); Poll::Ready(()) }) .await; @@ -362,13 +210,16 @@ async fn on_block_finalized() { .returning(|_, _| ()); set_default_expecations_no_peers(&mut chain_sync); - let (mut network, _) = make_network(chain_sync, chain_sync_service, client); + let mut network = TestNetworkBuilder::new() + .with_client(client) + .with_chain_sync((chain_sync, chain_sync_service)) + .build(); // send "set sync fork request" message and poll the network - network.on_block_finalized(hash, header); + network.network().on_block_finalized(hash, header); futures::future::poll_fn(|cx| { - let _ = network.poll_unpin(cx); + let _ = network.network().poll_unpin(cx); Poll::Ready(()) }) .await; diff --git a/client/network/src/service/tests/mod.rs b/client/network/src/service/tests/mod.rs new file mode 100644 index 0000000000000..f829d9d43090f --- /dev/null +++ b/client/network/src/service/tests/mod.rs @@ -0,0 +1,297 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{config, ChainSyncInterface, NetworkService, NetworkWorker}; + +use futures::prelude::*; +use libp2p::Multiaddr; +use sc_client_api::{BlockBackend, HeaderBackend}; +use sc_consensus::ImportQueue; +use sc_network_common::{ + config::{ + NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, + TransportConfig, + }, + protocol::{event::Event, role::Roles}, + service::NetworkEventStream, + sync::{message::BlockAnnouncesHandshake, ChainSync as ChainSyncT}, +}; +use sc_network_light::light_client_requests::handler::LightClientRequestHandler; +use sc_network_sync::{ + block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler, + ChainSync, +}; +use sp_runtime::traits::{Block as BlockT, Header as _, Zero}; +use std::sync::Arc; +use substrate_test_runtime_client::{ + runtime::{Block as TestBlock, Hash as TestHash}, + TestClient, TestClientBuilder, TestClientBuilderExt as _, +}; + +#[cfg(test)] +mod chain_sync; +#[cfg(test)] +mod service; + +type TestNetworkWorker = NetworkWorker; +type TestNetworkService = NetworkService; + +const BLOCK_ANNOUNCE_PROTO_NAME: &str = "/block-announces"; +const PROTOCOL_NAME: &str = "/foo"; + +struct TestNetwork { + network: TestNetworkWorker, +} + +impl TestNetwork { + pub fn new(network: TestNetworkWorker) -> Self { + Self { network } + } + + pub fn service(&self) -> &Arc { + &self.network.service() + } + + pub fn network(&mut self) -> &mut TestNetworkWorker { + &mut self.network + } + + pub fn start_network( + self, + ) -> (Arc, (impl Stream + std::marker::Unpin)) { + let worker = self.network; + let service = worker.service().clone(); + let event_stream = service.event_stream("test"); + + async_std::task::spawn(async move { + futures::pin_mut!(worker); + let _ = worker.await; + }); + + (service, event_stream) + } +} + +struct TestNetworkBuilder { + import_queue: Option>>, + client: Option>, + listen_addresses: Vec, + set_config: Option, + chain_sync: Option<(Box>, Box>)>, + config: Option, +} + +impl TestNetworkBuilder { + pub fn new() -> Self { + Self { + import_queue: None, + client: None, + listen_addresses: Vec::new(), + set_config: None, + chain_sync: None, + config: None, + } + } + + pub fn with_client(mut self, client: Arc) -> Self { + self.client = Some(client); + self + } + + pub fn with_config(mut self, config: config::NetworkConfiguration) -> Self { + self.config = Some(config); + self + } + + pub fn with_listen_addresses(mut self, addresses: Vec) -> Self { + self.listen_addresses = addresses; + self + } + + pub fn with_set_config(mut self, set_config: SetConfig) -> Self { + self.set_config = Some(set_config); + self + } + + pub fn with_chain_sync( + mut self, + chain_sync: (Box>, Box>), + ) -> Self { + self.chain_sync = Some(chain_sync); + self + } + + pub fn build(mut self) -> TestNetwork { + let client = self.client.as_mut().map_or( + Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0), + |v| v.clone(), + ); + + let network_config = self.config.unwrap_or(config::NetworkConfiguration { + extra_sets: vec![NonDefaultSetConfig { + notifications_protocol: PROTOCOL_NAME.into(), + fallback_names: Vec::new(), + max_notification_size: 1024 * 1024, + handshake: None, + set_config: self.set_config.unwrap_or_default(), + }], + listen_addresses: self.listen_addresses, + transport: TransportConfig::MemoryOnly, + ..config::NetworkConfiguration::new_local() + }); + + #[derive(Clone)] + struct PassThroughVerifier(bool); + + #[async_trait::async_trait] + impl sc_consensus::Verifier for PassThroughVerifier { + async fn verify( + &mut self, + mut block: sc_consensus::BlockImportParams, + ) -> Result< + ( + sc_consensus::BlockImportParams, + Option)>>, + ), + String, + > { + let maybe_keys = block + .header + .digest() + .log(|l| { + l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"aura")) + .or_else(|| { + l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus( + b"babe", + )) + }) + }) + .map(|blob| { + vec![(sp_blockchain::well_known_cache_keys::AUTHORITIES, blob.to_vec())] + }); + + block.finalized = self.0; + block.fork_choice = Some(sc_consensus::ForkChoiceStrategy::LongestChain); + Ok((block, maybe_keys)) + } + } + + let import_queue = self.import_queue.unwrap_or(Box::new(sc_consensus::BasicQueue::new( + PassThroughVerifier(false), + Box::new(client.clone()), + None, + &sp_core::testing::TaskExecutor::new(), + None, + ))); + + let (chain_sync, chain_sync_service) = self.chain_sync.unwrap_or({ + let (chain_sync, chain_sync_service) = ChainSync::new( + match network_config.sync_mode { + config::SyncMode::Full => sc_network_common::sync::SyncMode::Full, + config::SyncMode::Fast { skip_proofs, storage_chain_mode } => + sc_network_common::sync::SyncMode::LightState { + skip_proofs, + storage_chain_mode, + }, + config::SyncMode::Warp => sc_network_common::sync::SyncMode::Warp, + }, + client.clone(), + Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), + network_config.max_parallel_downloads, + None, + ) + .unwrap(); + + (Box::new(chain_sync), chain_sync_service) + }); + + let protocol_id = ProtocolId::from("test-protocol-name"); + let fork_id = Some(String::from("test-fork-id")); + + let block_request_protocol_config = { + let (handler, protocol_config) = + BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); + async_std::task::spawn(handler.run().boxed()); + protocol_config + }; + + let state_request_protocol_config = { + let (handler, protocol_config) = + StateRequestHandler::new(&protocol_id, None, client.clone(), 50); + async_std::task::spawn(handler.run().boxed()); + protocol_config + }; + + let light_client_request_protocol_config = { + let (handler, protocol_config) = + LightClientRequestHandler::new(&protocol_id, None, client.clone()); + async_std::task::spawn(handler.run().boxed()); + protocol_config + }; + + let block_announce_config = NonDefaultSetConfig { + notifications_protocol: BLOCK_ANNOUNCE_PROTO_NAME.into(), + fallback_names: vec![], + max_notification_size: 1024 * 1024, + handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::< + substrate_test_runtime_client::runtime::Block, + >::build( + Roles::from(&config::Role::Full), + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ))), + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + }; + + let worker = NetworkWorker::< + substrate_test_runtime_client::runtime::Block, + substrate_test_runtime_client::runtime::Hash, + substrate_test_runtime_client::TestClient, + >::new(config::Params { + block_announce_config, + role: config::Role::Full, + executor: None, + network_config, + chain: client.clone(), + protocol_id, + fork_id, + import_queue, + chain_sync, + chain_sync_service, + metrics_registry: None, + block_request_protocol_config, + state_request_protocol_config, + light_client_request_protocol_config, + warp_sync_protocol_config: None, + request_response_protocol_configs: Vec::new(), + }) + .unwrap(); + + TestNetwork::new(worker) + } +} diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests/service.rs similarity index 56% rename from client/network/src/service/tests.rs rename to client/network/src/service/tests/service.rs index 4a0ef4611da6e..90945fdcef2cf 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests/service.rs @@ -16,183 +16,22 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{config, NetworkService, NetworkWorker}; +use crate::{config, service::tests::TestNetworkBuilder, NetworkService}; use futures::prelude::*; use libp2p::PeerId; -use sc_client_api::{BlockBackend, HeaderBackend}; use sc_network_common::{ - config::{ - MultiaddrWithPeerId, NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, - ProtocolId, SetConfig, TransportConfig, - }, - protocol::{event::Event, role::Roles}, - service::{NetworkEventStream, NetworkNotification, NetworkPeers, NetworkStateInfo}, - sync::message::BlockAnnouncesHandshake, + config::{MultiaddrWithPeerId, NonDefaultSetConfig, SetConfig, TransportConfig}, + protocol::event::Event, + service::{NetworkNotification, NetworkPeers, NetworkStateInfo}, }; -use sc_network_light::light_client_requests::handler::LightClientRequestHandler; -use sc_network_sync::{ - block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler, - ChainSync, -}; -use sp_consensus::block_validation::DefaultBlockAnnounceValidator; -use sp_runtime::traits::{Block as BlockT, Header as _, Zero}; use std::{sync::Arc, time::Duration}; -use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; type TestNetworkService = NetworkService< substrate_test_runtime_client::runtime::Block, substrate_test_runtime_client::runtime::Hash, >; -/// Builds a full node to be used for testing. Returns the node service and its associated events -/// stream. -/// -/// > **Note**: We return the events stream in order to not possibly lose events between the -/// > construction of the service and the moment the events stream is grabbed. -fn build_test_full_node( - network_config: config::NetworkConfiguration, -) -> (Arc, impl Stream) { - let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); - - #[derive(Clone)] - struct PassThroughVerifier(bool); - - #[async_trait::async_trait] - impl sc_consensus::Verifier for PassThroughVerifier { - async fn verify( - &mut self, - mut block: sc_consensus::BlockImportParams, - ) -> Result< - ( - sc_consensus::BlockImportParams, - Option)>>, - ), - String, - > { - let maybe_keys = block - .header - .digest() - .log(|l| { - l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"aura")) - .or_else(|| { - l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus( - b"babe", - )) - }) - }) - .map(|blob| { - vec![(sp_blockchain::well_known_cache_keys::AUTHORITIES, blob.to_vec())] - }); - - block.finalized = self.0; - block.fork_choice = Some(sc_consensus::ForkChoiceStrategy::LongestChain); - Ok((block, maybe_keys)) - } - } - - let import_queue = Box::new(sc_consensus::BasicQueue::new( - PassThroughVerifier(false), - Box::new(client.clone()), - None, - &sp_core::testing::TaskExecutor::new(), - None, - )); - - let protocol_id = ProtocolId::from("/test-protocol-name"); - - let fork_id = Some(String::from("test-fork-id")); - - let block_request_protocol_config = { - let (handler, protocol_config) = - BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); - async_std::task::spawn(handler.run().boxed()); - protocol_config - }; - - let state_request_protocol_config = { - let (handler, protocol_config) = - StateRequestHandler::new(&protocol_id, None, client.clone(), 50); - async_std::task::spawn(handler.run().boxed()); - protocol_config - }; - - let light_client_request_protocol_config = { - let (handler, protocol_config) = - LightClientRequestHandler::new(&protocol_id, None, client.clone()); - async_std::task::spawn(handler.run().boxed()); - protocol_config - }; - - let (chain_sync, chain_sync_service) = ChainSync::new( - match network_config.sync_mode { - config::SyncMode::Full => sc_network_common::sync::SyncMode::Full, - config::SyncMode::Fast { skip_proofs, storage_chain_mode } => - sc_network_common::sync::SyncMode::LightState { skip_proofs, storage_chain_mode }, - config::SyncMode::Warp => sc_network_common::sync::SyncMode::Warp, - }, - client.clone(), - Box::new(DefaultBlockAnnounceValidator), - network_config.max_parallel_downloads, - None, - ) - .unwrap(); - - let block_announce_config = NonDefaultSetConfig { - notifications_protocol: BLOCK_ANNOUNCE_PROTO_NAME.into(), - fallback_names: vec![], - max_notification_size: 1024 * 1024, - handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::< - substrate_test_runtime_client::runtime::Block, - >::build( - Roles::from(&config::Role::Full), - client.info().best_number, - client.info().best_hash, - client - .block_hash(Zero::zero()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), - ))), - set_config: SetConfig { - in_peers: 0, - out_peers: 0, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Deny, - }, - }; - - let worker = NetworkWorker::new(config::Params { - block_announce_config, - role: config::Role::Full, - executor: None, - network_config, - chain: client.clone(), - protocol_id, - fork_id, - import_queue, - chain_sync: Box::new(chain_sync), - chain_sync_service, - metrics_registry: None, - block_request_protocol_config, - state_request_protocol_config, - light_client_request_protocol_config, - warp_sync_protocol_config: None, - request_response_protocol_configs: Vec::new(), - }) - .unwrap(); - - let service = worker.service().clone(); - let event_stream = service.event_stream("test"); - - async_std::task::spawn(async move { - futures::pin_mut!(worker); - let _ = worker.await; - }); - - (service, event_stream) -} - const BLOCK_ANNOUNCE_PROTO_NAME: &str = "/block-announces"; const PROTOCOL_NAME: &str = "/foo"; @@ -206,37 +45,21 @@ fn build_nodes_one_proto() -> ( ) { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (node1, events_stream1) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME.into(), - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: Default::default(), - }], - listen_addresses: vec![listen_addr.clone()], - transport: TransportConfig::MemoryOnly, - ..config::NetworkConfiguration::new_local() - }); + let (node1, events_stream1) = TestNetworkBuilder::new() + .with_listen_addresses(vec![listen_addr.clone()]) + .build() + .start_network(); - let (node2, events_stream2) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME.into(), - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: SetConfig { - reserved_nodes: vec![MultiaddrWithPeerId { - multiaddr: listen_addr, - peer_id: node1.local_peer_id(), - }], - ..Default::default() - }, - }], - listen_addresses: vec![], - transport: TransportConfig::MemoryOnly, - ..config::NetworkConfiguration::new_local() - }); + let (node2, events_stream2) = TestNetworkBuilder::new() + .with_set_config(SetConfig { + reserved_nodes: vec![MultiaddrWithPeerId { + multiaddr: listen_addr, + peer_id: node1.local_peer_id(), + }], + ..Default::default() + }) + .build() + .start_network(); (node1, events_stream1, node2, events_stream2) } @@ -393,22 +216,15 @@ fn notifications_state_consistent() { }); } -#[test] -fn lots_of_incoming_peers_works() { +#[async_std::test] +async fn lots_of_incoming_peers_works() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (main_node, _) = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![listen_addr.clone()], - extra_sets: vec![NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME.into(), - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: SetConfig { in_peers: u32::MAX, ..Default::default() }, - }], - transport: TransportConfig::MemoryOnly, - ..config::NetworkConfiguration::new_local() - }); + let (main_node, _) = TestNetworkBuilder::new() + .with_listen_addresses(vec![listen_addr.clone()]) + .with_set_config(SetConfig { in_peers: u32::MAX, ..Default::default() }) + .build() + .start_network(); let main_node_peer_id = main_node.local_peer_id(); @@ -417,24 +233,16 @@ fn lots_of_incoming_peers_works() { let mut background_tasks_to_wait = Vec::new(); for _ in 0..32 { - let (_dialing_node, event_stream) = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![], - extra_sets: vec![NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME.into(), - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: SetConfig { - reserved_nodes: vec![MultiaddrWithPeerId { - multiaddr: listen_addr.clone(), - peer_id: main_node_peer_id, - }], - ..Default::default() - }, - }], - transport: TransportConfig::MemoryOnly, - ..config::NetworkConfiguration::new_local() - }); + let (_dialing_node, event_stream) = TestNetworkBuilder::new() + .with_set_config(SetConfig { + reserved_nodes: vec![MultiaddrWithPeerId { + multiaddr: listen_addr.clone(), + peer_id: main_node_peer_id, + }], + ..Default::default() + }) + .build() + .start_network(); background_tasks_to_wait.push(async_std::task::spawn(async move { // Create a dummy timer that will "never" fire, and that will be overwritten when we @@ -469,7 +277,7 @@ fn lots_of_incoming_peers_works() { })); } - futures::executor::block_on(async move { future::join_all(background_tasks_to_wait).await }); + future::join_all(background_tasks_to_wait).await; } #[test] @@ -531,42 +339,35 @@ fn notifications_back_pressure() { fn fallback_name_working() { // Node 1 supports the protocols "new" and "old". Node 2 only supports "old". Checks whether // they can connect. - const NEW_PROTOCOL_NAME: &str = "/new-shiny-protocol-that-isnt-PROTOCOL_NAME"; let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - - let (node1, mut events_stream1) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![NonDefaultSetConfig { - notifications_protocol: NEW_PROTOCOL_NAME.into(), - fallback_names: vec![PROTOCOL_NAME.into()], - max_notification_size: 1024 * 1024, - handshake: None, - set_config: Default::default(), - }], - listen_addresses: vec![listen_addr.clone()], - transport: TransportConfig::MemoryOnly, - ..config::NetworkConfiguration::new_local() - }); - - let (_, mut events_stream2) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME.into(), - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: SetConfig { - reserved_nodes: vec![MultiaddrWithPeerId { - multiaddr: listen_addr, - peer_id: node1.local_peer_id(), - }], - ..Default::default() - }, - }], - listen_addresses: vec![], - transport: TransportConfig::MemoryOnly, - ..config::NetworkConfiguration::new_local() - }); + let (node1, mut events_stream1) = TestNetworkBuilder::new() + .with_config(config::NetworkConfiguration { + extra_sets: vec![NonDefaultSetConfig { + notifications_protocol: NEW_PROTOCOL_NAME.into(), + fallback_names: vec![PROTOCOL_NAME.into()], + max_notification_size: 1024 * 1024, + handshake: None, + set_config: Default::default(), + }], + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + ..config::NetworkConfiguration::new_local() + }) + .build() + .start_network(); + + let (_, mut events_stream2) = TestNetworkBuilder::new() + .with_set_config(SetConfig { + reserved_nodes: vec![MultiaddrWithPeerId { + multiaddr: listen_addr, + peer_id: node1.local_peer_id(), + }], + ..Default::default() + }) + .build() + .start_network(); let receiver = async_std::task::spawn(async move { // Wait for the `NotificationStreamOpened`. @@ -604,39 +405,7 @@ fn fallback_name_working() { // protocol name and verify that `SyncDisconnected` event is emitted #[async_std::test] async fn disconnect_sync_peer_using_block_announcement_protocol_name() { - let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - - let (node1, mut events_stream1) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME.into(), - fallback_names: vec![], - max_notification_size: 1024 * 1024, - handshake: None, - set_config: Default::default(), - }], - listen_addresses: vec![listen_addr.clone()], - transport: TransportConfig::MemoryOnly, - ..config::NetworkConfiguration::new_local() - }); - - let (node2, mut events_stream2) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME.into(), - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: SetConfig { - reserved_nodes: vec![MultiaddrWithPeerId { - multiaddr: listen_addr, - peer_id: node1.local_peer_id(), - }], - ..Default::default() - }, - }], - listen_addresses: vec![], - transport: TransportConfig::MemoryOnly, - ..config::NetworkConfiguration::new_local() - }); + let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); async fn wait_for_events(stream: &mut (impl Stream + std::marker::Unpin)) { let mut notif_received = false; @@ -673,11 +442,19 @@ async fn disconnect_sync_peer_using_block_announcement_protocol_name() { fn ensure_listen_addresses_consistent_with_transport_memory() { let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)]; - let _ = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![listen_addr.clone()], - transport: TransportConfig::MemoryOnly, - ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) - }); + let _ = TestNetworkBuilder::new() + .with_config(config::NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + ..config::NetworkConfiguration::new( + "test-node", + "test-client", + Default::default(), + None, + ) + }) + .build() + .start_network(); } #[test] @@ -685,10 +462,18 @@ fn ensure_listen_addresses_consistent_with_transport_memory() { fn ensure_listen_addresses_consistent_with_transport_not_memory() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let _ = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![listen_addr.clone()], - ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) - }); + let _ = TestNetworkBuilder::new() + .with_config(config::NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + ..config::NetworkConfiguration::new( + "test-node", + "test-client", + Default::default(), + None, + ) + }) + .build() + .start_network(); } #[test] @@ -700,12 +485,20 @@ fn ensure_boot_node_addresses_consistent_with_transport_memory() { peer_id: PeerId::random(), }; - let _ = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![listen_addr.clone()], - transport: TransportConfig::MemoryOnly, - boot_nodes: vec![boot_node], - ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) - }); + let _ = TestNetworkBuilder::new() + .with_config(config::NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + boot_nodes: vec![boot_node], + ..config::NetworkConfiguration::new( + "test-node", + "test-client", + Default::default(), + None, + ) + }) + .build() + .start_network(); } #[test] @@ -717,11 +510,19 @@ fn ensure_boot_node_addresses_consistent_with_transport_not_memory() { peer_id: PeerId::random(), }; - let _ = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![listen_addr.clone()], - boot_nodes: vec![boot_node], - ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) - }); + let _ = TestNetworkBuilder::new() + .with_config(config::NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + boot_nodes: vec![boot_node], + ..config::NetworkConfiguration::new( + "test-node", + "test-client", + Default::default(), + None, + ) + }) + .build() + .start_network(); } #[test] @@ -733,12 +534,23 @@ fn ensure_reserved_node_addresses_consistent_with_transport_memory() { peer_id: PeerId::random(), }; - let _ = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![listen_addr.clone()], - transport: TransportConfig::MemoryOnly, - default_peers_set: SetConfig { reserved_nodes: vec![reserved_node], ..Default::default() }, - ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) - }); + let _ = TestNetworkBuilder::new() + .with_config(config::NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + default_peers_set: SetConfig { + reserved_nodes: vec![reserved_node], + ..Default::default() + }, + ..config::NetworkConfiguration::new( + "test-node", + "test-client", + Default::default(), + None, + ) + }) + .build() + .start_network(); } #[test] @@ -750,11 +562,22 @@ fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { peer_id: PeerId::random(), }; - let _ = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![listen_addr.clone()], - default_peers_set: SetConfig { reserved_nodes: vec![reserved_node], ..Default::default() }, - ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) - }); + let _ = TestNetworkBuilder::new() + .with_config(config::NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + default_peers_set: SetConfig { + reserved_nodes: vec![reserved_node], + ..Default::default() + }, + ..config::NetworkConfiguration::new( + "test-node", + "test-client", + Default::default(), + None, + ) + }) + .build() + .start_network(); } #[test] @@ -763,12 +586,20 @@ fn ensure_public_addresses_consistent_with_transport_memory() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let public_address = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)]; - let _ = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![listen_addr.clone()], - transport: TransportConfig::MemoryOnly, - public_addresses: vec![public_address], - ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) - }); + let _ = TestNetworkBuilder::new() + .with_config(config::NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + public_addresses: vec![public_address], + ..config::NetworkConfiguration::new( + "test-node", + "test-client", + Default::default(), + None, + ) + }) + .build() + .start_network(); } #[test] @@ -777,9 +608,17 @@ fn ensure_public_addresses_consistent_with_transport_not_memory() { let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)]; let public_address = config::build_multiaddr![Memory(rand::random::())]; - let _ = build_test_full_node(config::NetworkConfiguration { - listen_addresses: vec![listen_addr.clone()], - public_addresses: vec![public_address], - ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) - }); + let _ = TestNetworkBuilder::new() + .with_config(config::NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + public_addresses: vec![public_address], + ..config::NetworkConfiguration::new( + "test-node", + "test-client", + Default::default(), + None, + ) + }) + .build() + .start_network(); } From e45883548b8fafc9dcea41ee6585634412462072 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 21 Oct 2022 16:38:53 +0300 Subject: [PATCH 1300/1472] Actually fix major sync detection (#12114) * Actually fix major sync detection * Introduce `SyncState::Importing` state * Add target to SyncState enum variants and add `is_major_syncing` method on it * Remove unnecessary duplicated `best_seen_block` from `SyncState` struct * Revert "Remove unnecessary duplicated `best_seen_block` from `SyncState` struct" This reverts commit bb8abd458c939881c049f69d59f3acba47c97c5c. * Add missing `websocket` feature to `libp2p` Co-authored-by: parity-processbot <> --- client/informant/src/display.rs | 63 +++++++++++++--------------- client/network/Cargo.toml | 2 +- client/network/common/src/service.rs | 2 +- client/network/common/src/sync.rs | 15 +++++-- client/network/src/service.rs | 14 ++++--- client/network/sync/src/lib.rs | 37 ++++++++-------- 6 files changed, 71 insertions(+), 62 deletions(-) diff --git a/client/informant/src/display.rs b/client/informant/src/display.rs index 0441011b0ec42..3d585a9985134 100644 --- a/client/informant/src/display.rs +++ b/client/informant/src/display.rs @@ -93,42 +93,37 @@ impl InformantDisplay { (diff_bytes_inbound, diff_bytes_outbound) }; - let (level, status, target) = match ( - net_status.sync_state, - net_status.best_seen_block, - net_status.state_sync, - net_status.warp_sync, - ) { - ( - _, - _, - _, - Some(WarpSyncProgress { phase: WarpSyncPhase::DownloadingBlocks(n), .. }), - ) => ("⏩", "Block history".into(), format!(", #{}", n)), - (_, _, _, Some(warp)) => ( - "⏩", - "Warping".into(), - format!( - ", {}, {:.2} Mib", - warp.phase, - (warp.total_bytes as f32) / (1024f32 * 1024f32) + let (level, status, target) = + match (net_status.sync_state, net_status.state_sync, net_status.warp_sync) { + ( + _, + _, + Some(WarpSyncProgress { phase: WarpSyncPhase::DownloadingBlocks(n), .. }), + ) => ("⏩", "Block history".into(), format!(", #{}", n)), + (_, _, Some(warp)) => ( + "⏩", + "Warping".into(), + format!( + ", {}, {:.2} Mib", + warp.phase, + (warp.total_bytes as f32) / (1024f32 * 1024f32) + ), ), - ), - (_, _, Some(state), _) => ( - "⚙️ ", - "Downloading state".into(), - format!( - ", {}%, {:.2} Mib", - state.percentage, - (state.size as f32) / (1024f32 * 1024f32) + (_, Some(state), _) => ( + "⚙️ ", + "Downloading state".into(), + format!( + ", {}%, {:.2} Mib", + state.percentage, + (state.size as f32) / (1024f32 * 1024f32) + ), ), - ), - (SyncState::Idle, _, _, _) => ("💤", "Idle".into(), "".into()), - (SyncState::Downloading, None, _, _) => - ("⚙️ ", format!("Preparing{}", speed), "".into()), - (SyncState::Downloading, Some(n), None, _) => - ("⚙️ ", format!("Syncing{}", speed), format!(", target=#{}", n)), - }; + (SyncState::Idle, _, _) => ("💤", "Idle".into(), "".into()), + (SyncState::Downloading { target }, _, _) => + ("⚙️ ", format!("Syncing{}", speed), format!(", target=#{target}")), + (SyncState::Importing { target }, _, _) => + ("⚙️ ", format!("Preparing{}", speed), format!(", target=#{target}")), + }; if self.format.enable_color { info!( diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 9c2833ec00908..81b684af433d2 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -26,7 +26,7 @@ fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" ip_network = "0.4.1" -libp2p = { version = "0.49.0", features = ["async-std", "dns", "identify", "kad", "mdns-async-io", "mplex", "noise", "ping", "tcp", "yamux"] } +libp2p = { version = "0.49.0", features = ["async-std", "dns", "identify", "kad", "mdns-async-io", "mplex", "noise", "ping", "tcp", "yamux", "websocket"] } linked_hash_set = "0.1.3" linked-hash-map = "0.5.4" log = "0.4.17" diff --git a/client/network/common/src/service.rs b/client/network/common/src/service.rs index aa4967ba51700..54d254eac384f 100644 --- a/client/network/common/src/service.rs +++ b/client/network/common/src/service.rs @@ -98,7 +98,7 @@ where #[derive(Clone)] pub struct NetworkStatus { /// Current global sync state. - pub sync_state: SyncState, + pub sync_state: SyncState>, /// Target sync block number. pub best_seen_block: Option>, /// Number of peers participating in syncing. diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index aa761e66ebf68..dd216b2a5295a 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -44,11 +44,20 @@ pub struct PeerInfo { /// Reported sync state. #[derive(Clone, Eq, PartialEq, Debug)] -pub enum SyncState { +pub enum SyncState { /// Initial sync is complete, keep-up sync is active. Idle, /// Actively catching up with the chain. - Downloading, + Downloading { target: BlockNumber }, + /// All blocks are downloaded and are being imported. + Importing { target: BlockNumber }, +} + +impl SyncState { + /// Are we actively catching up with the chain? + pub fn is_major_syncing(&self) -> bool { + !matches!(self, SyncState::Idle) + } } /// Reported state download progress. @@ -64,7 +73,7 @@ pub struct StateDownloadProgress { #[derive(Clone)] pub struct SyncStatus { /// Current global sync state. - pub state: SyncState, + pub state: SyncState>, /// Target sync block number. pub best_seen_block: Option>, /// Number of peers participating in syncing. diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 8dfd46f24a731..89dc2ff4405b2 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -70,7 +70,7 @@ use sc_network_common::{ NotificationSender as NotificationSenderT, NotificationSenderError, NotificationSenderReady as NotificationSenderReadyT, Signature, SigningError, }, - sync::{SyncState, SyncStatus}, + sync::SyncStatus, ExHashT, }; use sc_peerset::PeersetHandle; @@ -1997,11 +1997,13 @@ where *this.external_addresses.lock() = external_addresses; } - let is_major_syncing = - match this.network_service.behaviour_mut().user_protocol_mut().sync_state().state { - SyncState::Idle => false, - SyncState::Downloading => true, - }; + let is_major_syncing = this + .network_service + .behaviour_mut() + .user_protocol_mut() + .sync_state() + .state + .is_major_syncing(); this.is_major_syncing.store(is_major_syncing, Ordering::Relaxed); diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 76d7d624be523..63f63f7188cfe 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -410,13 +410,21 @@ where /// Returns the current sync status. fn status(&self) -> SyncStatus { - let best_seen = self.best_seen(); - let sync_state = if let Some(n) = best_seen { + let median_seen = self.median_seen(); + let best_seen_block = + median_seen.and_then(|median| (median > self.best_queued_number).then_some(median)); + let sync_state = if let Some(target) = median_seen { // A chain is classified as downloading if the provided best block is - // more than `MAJOR_SYNC_BLOCKS` behind the best block. + // more than `MAJOR_SYNC_BLOCKS` behind the best block or as importing + // if the same can be said about queued blocks. let best_block = self.client.info().best_number; - if n > best_block && n - best_block > MAJOR_SYNC_BLOCKS.into() { - SyncState::Downloading + if target > best_block && target - best_block > MAJOR_SYNC_BLOCKS.into() { + // If target is not queued, we're downloading, otherwise importing. + if target > self.best_queued_number { + SyncState::Downloading { target } + } else { + SyncState::Importing { target } + } } else { SyncState::Idle } @@ -437,7 +445,7 @@ where SyncStatus { state: sync_state, - best_seen_block: best_seen, + best_seen_block, num_peers: self.peers.len() as u32, queued_blocks: self.queue_blocks.len() as u32, state_sync: self.state_sync.as_ref().map(|s| s.progress()), @@ -693,7 +701,7 @@ where trace!(target: "sync", "Too many blocks in the queue."); return Box::new(std::iter::empty()) } - let major_sync = self.status().state == SyncState::Downloading; + let is_major_syncing = self.status().state.is_major_syncing(); let attrs = self.required_block_attributes(); let blocks = &mut self.blocks; let fork_targets = &mut self.fork_targets; @@ -703,7 +711,7 @@ where let client = &self.client; let queue = &self.queue_blocks; let allowed_requests = self.allowed_requests.take(); - let max_parallel = if major_sync { 1 } else { self.max_parallel_downloads }; + let max_parallel = if is_major_syncing { 1 } else { self.max_parallel_downloads }; let gap_sync = &mut self.gap_sync; let iter = self.peers.iter_mut().filter_map(move |(&id, peer)| { if !peer.state.is_available() || !allowed_requests.contains(&id) { @@ -1797,8 +1805,8 @@ where Ok((sync, Box::new(ChainSyncInterfaceHandle::new(tx)))) } - /// Returns the best seen block number if we don't have that block yet, `None` otherwise. - fn best_seen(&self) -> Option> { + /// Returns the median seen block number. + fn median_seen(&self) -> Option> { let mut best_seens = self.peers.values().map(|p| p.best_number).collect::>(); if best_seens.is_empty() { @@ -1807,12 +1815,7 @@ where let middle = best_seens.len() / 2; // Not the "perfect median" when we have an even number of peers. - let median = *best_seens.select_nth_unstable(middle).1; - if median > self.best_queued_number { - Some(median) - } else { - None - } + Some(*best_seens.select_nth_unstable(middle).1) } } @@ -1854,7 +1857,7 @@ where ); } - let origin = if !gap && self.status().state != SyncState::Downloading { + let origin = if !gap && !self.status().state.is_major_syncing() { BlockOrigin::NetworkBroadcast } else { BlockOrigin::NetworkInitialSync From 1802a115e8480fd7a4654d45c85b58c2189c508a Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Fri, 21 Oct 2022 17:05:51 +0200 Subject: [PATCH 1301/1472] BlockId removal: refactor: Backend::begin_state_operation (#12541) It changes the arguments of `Backend::begin_state_operation` from: block: `BlockId` to: hash: `&Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) --- client/api/src/backend.rs | 2 +- client/api/src/in_mem.rs | 5 +- client/db/benches/state_access.rs | 3 +- client/db/src/lib.rs | 73 ++++++++++++----------------- client/service/src/client/client.rs | 3 +- 5 files changed, 35 insertions(+), 51 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 864a9af5685d8..77a9da3535655 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -467,7 +467,7 @@ pub trait Backend: AuxStore + Send + Sync { fn begin_state_operation( &self, operation: &mut Self::BlockImportOperation, - block: BlockId, + block: &Block::Hash, ) -> sp_blockchain::Result<()>; /// Commit block insertion. diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 1cb61ba1a0b0a..29f7eade9fa6f 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -695,10 +695,9 @@ where fn begin_state_operation( &self, operation: &mut Self::BlockImportOperation, - block: BlockId, + block: &Block::Hash, ) -> sp_blockchain::Result<()> { - let hash = self.blockchain.expect_block_hash_from_id(&block)?; - operation.old_state = self.state_at(&hash)?; + operation.old_state = self.state_at(block)?; Ok(()) } diff --git a/client/db/benches/state_access.rs b/client/db/benches/state_access.rs index 912a9b028f638..ccceae1f5b419 100644 --- a/client/db/benches/state_access.rs +++ b/client/db/benches/state_access.rs @@ -22,7 +22,6 @@ use sc_client_api::{Backend as _, BlockImportOperation, NewBlockState, StateBack use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, DatabaseSource, PruningMode}; use sp_core::H256; use sp_runtime::{ - generic::BlockId, testing::{Block as RawBlock, ExtrinsicWrapper, Header}, StateVersion, Storage, }; @@ -67,7 +66,7 @@ fn insert_blocks(db: &Backend, storage: Vec<(Vec, Vec)>) -> H256 for i in 0..10 { let mut op = db.begin_operation().unwrap(); - db.begin_state_operation(&mut op, BlockId::Hash(parent_hash)).unwrap(); + db.begin_state_operation(&mut op, &parent_hash).unwrap(); let mut header = Header { number, diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 14ebafa01bec1..e212b382716f1 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1961,13 +1961,12 @@ impl sc_client_api::backend::Backend for Backend { fn begin_state_operation( &self, operation: &mut Self::BlockImportOperation, - block: BlockId, + block: &Block::Hash, ) -> ClientResult<()> { - let hash = self.blockchain.expect_block_hash_from_id(&block)?; - if block.is_pre_genesis() { + if *block == Default::default() { operation.old_state = self.empty_state()?; } else { - operation.old_state = self.state_at(&hash)?; + operation.old_state = self.state_at(block)?; } operation.commit_state = true; @@ -2442,13 +2441,9 @@ pub(crate) mod tests { }; let header_hash = header.hash(); - let block_id = if number == 0 { - BlockId::Hash(Default::default()) - } else { - BlockId::Number(number - 1) - }; + let block_hash = if number == 0 { Default::default() } else { parent_hash }; let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, block_id).unwrap(); + backend.begin_state_operation(&mut op, &block_hash).unwrap(); op.set_block_data(header, Some(body), None, None, NewBlockState::Best).unwrap(); if let Some(index) = transaction_index { op.update_transaction_index(index).unwrap(); @@ -2489,21 +2484,17 @@ pub(crate) mod tests { assert!(db.blockchain().hash(i).unwrap().is_none()); { - let id = if i == 0 { - BlockId::Hash(Default::default()) + let hash = if i == 0 { + Default::default() } else { - BlockId::Number(i - 1) + db.blockchain.hash(i - 1).unwrap().unwrap() }; let mut op = db.begin_operation().unwrap(); - db.begin_state_operation(&mut op, id).unwrap(); + db.begin_state_operation(&mut op, &hash).unwrap(); let header = Header { number: i, - parent_hash: if i == 0 { - Default::default() - } else { - db.blockchain.hash(i - 1).unwrap().unwrap() - }, + parent_hash: hash, state_root: Default::default(), digest: Default::default(), extrinsics_root: Default::default(), @@ -2585,7 +2576,7 @@ pub(crate) mod tests { { let mut op = db.begin_operation().unwrap(); - db.begin_state_operation(&mut op, BlockId::Number(0)).unwrap(); + db.begin_state_operation(&mut op, &hash).unwrap(); let mut header = Header { number: 1, parent_hash: hash, @@ -2626,9 +2617,7 @@ pub(crate) mod tests { let hash = { let mut op = backend.begin_operation().unwrap(); - backend - .begin_state_operation(&mut op, BlockId::Hash(Default::default())) - .unwrap(); + backend.begin_state_operation(&mut op, &Default::default()).unwrap(); let mut header = Header { number: 0, parent_hash: Default::default(), @@ -2665,7 +2654,7 @@ pub(crate) mod tests { let hashof1 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Number(0)).unwrap(); + backend.begin_state_operation(&mut op, &hash).unwrap(); let mut header = Header { number: 1, parent_hash: hash, @@ -2702,7 +2691,7 @@ pub(crate) mod tests { let hashof2 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Number(1)).unwrap(); + backend.begin_state_operation(&mut op, &hashof1).unwrap(); let mut header = Header { number: 2, parent_hash: hashof1, @@ -2736,7 +2725,7 @@ pub(crate) mod tests { let hashof3 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Number(2)).unwrap(); + backend.begin_state_operation(&mut op, &hashof2).unwrap(); let mut header = Header { number: 3, parent_hash: hashof2, @@ -3070,14 +3059,14 @@ pub(crate) mod tests { let block4 = insert_header(&backend, 4, block3, None, Default::default()); { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(block0)).unwrap(); + backend.begin_state_operation(&mut op, &block0).unwrap(); op.mark_finalized(&block1, None).unwrap(); op.mark_finalized(&block2, None).unwrap(); backend.commit_operation(op).unwrap(); } { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(block2)).unwrap(); + backend.begin_state_operation(&mut op, &block2).unwrap(); op.mark_finalized(&block3, None).unwrap(); op.mark_finalized(&block4, None).unwrap(); backend.commit_operation(op).unwrap(); @@ -3091,9 +3080,7 @@ pub(crate) mod tests { let hash0 = { let mut op = backend.begin_operation().unwrap(); - backend - .begin_state_operation(&mut op, BlockId::Hash(Default::default())) - .unwrap(); + backend.begin_state_operation(&mut op, &Default::default()).unwrap(); let mut header = Header { number: 0, parent_hash: Default::default(), @@ -3131,7 +3118,7 @@ pub(crate) mod tests { let hash1 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Number(0)).unwrap(); + backend.begin_state_operation(&mut op, &hash0).unwrap(); let mut header = Header { number: 1, parent_hash: hash0, @@ -3180,7 +3167,7 @@ pub(crate) mod tests { let block2 = insert_header(&backend, 2, block1, None, Default::default()); { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(block0)).unwrap(); + backend.begin_state_operation(&mut op, &block0).unwrap(); op.mark_finalized(&block2, None).unwrap(); backend.commit_operation(op).unwrap_err(); } @@ -3208,7 +3195,7 @@ pub(crate) mod tests { { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); for i in 1..5 { op.mark_finalized(&blocks[i], None).unwrap(); } @@ -3243,7 +3230,7 @@ pub(crate) mod tests { } let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); for i in 1..3 { op.mark_finalized(&blocks[i], None).unwrap(); } @@ -3300,7 +3287,7 @@ pub(crate) mod tests { .unwrap(); let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); op.mark_head(&blocks[4]).unwrap(); backend.commit_operation(op).unwrap(); @@ -3309,7 +3296,7 @@ pub(crate) mod tests { for i in 1..5 { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(blocks[i])).unwrap(); + backend.begin_state_operation(&mut op, &blocks[i]).unwrap(); op.mark_finalized(&blocks[i], None).unwrap(); backend.commit_operation(op).unwrap(); } @@ -3369,13 +3356,13 @@ pub(crate) mod tests { ) .unwrap(); let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); op.mark_head(&blocks[4]).unwrap(); backend.commit_operation(op).unwrap(); for i in 1..5 { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); op.mark_finalized(&blocks[i], None).unwrap(); backend.commit_operation(op).unwrap(); } @@ -3501,7 +3488,7 @@ pub(crate) mod tests { for i in 1..10 { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); op.mark_finalized(&blocks[i], None).unwrap(); backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); @@ -3701,7 +3688,7 @@ pub(crate) mod tests { let block3 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Number(1)).unwrap(); + backend.begin_state_operation(&mut op, &block1).unwrap(); let header = Header { number: 3, parent_hash: block2, @@ -3720,7 +3707,7 @@ pub(crate) mod tests { let block4 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(block2)).unwrap(); + backend.begin_state_operation(&mut op, &block2).unwrap(); let header = Header { number: 4, parent_hash: block3, @@ -3739,7 +3726,7 @@ pub(crate) mod tests { let block3_fork = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, BlockId::Hash(block2)).unwrap(); + backend.begin_state_operation(&mut op, &block2).unwrap(); let header = Header { number: 3, parent_hash: block2, diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index b18c6d226706b..c0414a3bebc42 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -586,8 +586,7 @@ where Some(storage_changes) => { let storage_changes = match storage_changes { sc_consensus::StorageChanges::Changes(storage_changes) => { - self.backend - .begin_state_operation(&mut operation.op, BlockId::Hash(parent_hash))?; + self.backend.begin_state_operation(&mut operation.op, &parent_hash)?; let (main_sc, child_sc, offchain_sc, tx, _, tx_index) = storage_changes.into_inner(); From c7a86c24b74ef19fda9805ad4f71c15d5016d402 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Fri, 21 Oct 2022 17:46:25 -0400 Subject: [PATCH 1302/1472] use headers on templates (#12546) --- .maintain/frame-weight-template.hbs | 18 +----------------- scripts/run_all_benchmarks.sh | 2 ++ 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 96731770ff2ea..360279129980f 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -1,20 +1,4 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +{{header}} //! Autogenerated weights for {{pallet}} //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} diff --git a/scripts/run_all_benchmarks.sh b/scripts/run_all_benchmarks.sh index 9aac58be45029..dd5d2e182baf2 100755 --- a/scripts/run_all_benchmarks.sh +++ b/scripts/run_all_benchmarks.sh @@ -121,6 +121,7 @@ for PALLET in "${PALLETS[@]}"; do --wasm-execution=compiled \ --heap-pages=4096 \ --output="$WEIGHT_FILE" \ + --header="./HEADER-APACHE2" \ --template=./.maintain/frame-weight-template.hbs 2>&1 ) if [ $? -ne 0 ]; then @@ -137,6 +138,7 @@ OUTPUT=$( --execution=wasm \ --wasm-execution=compiled \ --weight-path="./frame/support/src/weights/" \ + --header="./HEADER-APACHE2" \ --warmup=10 \ --repeat=100 2>&1 ) From 4d29da2156d587a6b8e4efbe10e412efaedbbd4e Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Sat, 22 Oct 2022 15:36:26 +0300 Subject: [PATCH 1303/1472] Make `NetworkService` callable for `ChainSync` (#12542) Introduce a middleware called `NetworkServiceProvider` which the `ChainSync` can use to communicate with `NetworkService`. `ChainSync` is given a `NetworkServiceHandle` which it uses to call `NetworkServiceProvider` which then dispatches the calls to `NetworkService` on behalf of `ChainSync`. This change will allow `ChainSync` to disconnect and report peers and in the future it'll be possible to send requests and notifications through the `NetworkServiceProvider`. `NetworkServiceProvider` is needed only until the `ChainSync` object has been removed from `Protocol`. After that, a normal `NetworkService` handle can be passed onto `ChainSync` and these changes can be deprecated. Co-authored-by: parity-processbot <> --- .../network/src/service/tests/chain_sync.rs | 182 +++++++++++++++++- client/network/src/service/tests/mod.rs | 28 ++- client/network/sync/src/lib.rs | 41 +++- client/network/sync/src/service/mock.rs | 48 ++++- client/network/sync/src/service/mod.rs | 1 + client/network/sync/src/service/network.rs | 128 ++++++++++++ client/network/sync/src/tests.rs | 4 +- client/network/test/src/lib.rs | 12 +- client/service/src/builder.rs | 12 +- 9 files changed, 443 insertions(+), 13 deletions(-) create mode 100644 client/network/sync/src/service/network.rs diff --git a/client/network/src/service/tests/chain_sync.rs b/client/network/src/service/tests/chain_sync.rs index 7ff8c589d8550..21149459413f4 100644 --- a/client/network/src/service/tests/chain_sync.rs +++ b/client/network/src/service/tests/chain_sync.rs @@ -16,7 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::service::tests::TestNetworkBuilder; +use crate::{ + config, + service::tests::{TestNetworkBuilder, BLOCK_ANNOUNCE_PROTO_NAME}, +}; use futures::prelude::*; use libp2p::PeerId; @@ -24,16 +27,23 @@ use sc_block_builder::BlockBuilderProvider; use sc_client_api::HeaderBackend; use sc_consensus::JustificationSyncLink; use sc_network_common::{ + config::{MultiaddrWithPeerId, SetConfig}, + protocol::event::Event, service::NetworkSyncForkRequest, sync::{SyncState, SyncStatus}, }; -use sc_network_sync::{mock::MockChainSync, service::mock::MockChainSyncInterface}; +use sc_network_sync::{mock::MockChainSync, service::mock::MockChainSyncInterface, ChainSync}; use sp_core::H256; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header as _}, }; -use std::{iter, sync::Arc, task::Poll}; +use std::{ + iter, + sync::{Arc, RwLock}, + task::Poll, + time::Duration, +}; use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; fn set_default_expecations_no_peers( @@ -224,3 +234,169 @@ async fn on_block_finalized() { }) .await; } + +// report from mock import queue that importing a justification was not successful +// and verify that connection to the peer is closed +#[async_std::test] +async fn invalid_justification_imported() { + struct DummyImportQueue( + Arc< + RwLock< + Option<( + PeerId, + substrate_test_runtime_client::runtime::Hash, + sp_runtime::traits::NumberFor, + )>, + >, + >, + ); + + impl sc_consensus::ImportQueue for DummyImportQueue { + fn import_blocks( + &mut self, + _origin: sp_consensus::BlockOrigin, + _blocks: Vec< + sc_consensus::IncomingBlock, + >, + ) { + } + + fn import_justifications( + &mut self, + _who: sc_consensus::import_queue::RuntimeOrigin, + _hash: substrate_test_runtime_client::runtime::Hash, + _number: sp_runtime::traits::NumberFor, + _justifications: sp_runtime::Justifications, + ) { + } + + fn poll_actions( + &mut self, + _cx: &mut futures::task::Context, + link: &mut dyn sc_consensus::Link, + ) { + if let Some((peer, hash, number)) = *self.0.read().unwrap() { + link.justification_imported(peer, &hash, number, false); + } + } + } + + let justification_info = Arc::new(RwLock::new(None)); + let listen_addr = config::build_multiaddr![Memory(rand::random::())]; + + let (service1, mut event_stream1) = TestNetworkBuilder::new() + .with_import_queue(Box::new(DummyImportQueue(justification_info.clone()))) + .with_listen_addresses(vec![listen_addr.clone()]) + .build() + .start_network(); + + let (service2, mut event_stream2) = TestNetworkBuilder::new() + .with_set_config(SetConfig { + reserved_nodes: vec![MultiaddrWithPeerId { + multiaddr: listen_addr, + peer_id: service1.local_peer_id, + }], + ..Default::default() + }) + .build() + .start_network(); + + async fn wait_for_events(stream: &mut (impl Stream + std::marker::Unpin)) { + let mut notif_received = false; + let mut sync_received = false; + while !notif_received || !sync_received { + match stream.next().await.unwrap() { + Event::NotificationStreamOpened { .. } => notif_received = true, + Event::SyncConnected { .. } => sync_received = true, + _ => {}, + }; + } + } + + wait_for_events(&mut event_stream1).await; + wait_for_events(&mut event_stream2).await; + + { + let mut info = justification_info.write().unwrap(); + *info = Some((service2.local_peer_id, H256::random(), 1337u64)); + } + + let wait_disconnection = async { + while !std::matches!(event_stream1.next().await, Some(Event::SyncDisconnected { .. })) {} + }; + + if async_std::future::timeout(Duration::from_secs(5), wait_disconnection) + .await + .is_err() + { + panic!("did not receive disconnection event in time"); + } +} + +#[async_std::test] +async fn disconnect_peer_using_chain_sync_handle() { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + let listen_addr = config::build_multiaddr![Memory(rand::random::())]; + + let (chain_sync_network_provider, chain_sync_network_handle) = + sc_network_sync::service::network::NetworkServiceProvider::new(); + let handle_clone = chain_sync_network_handle.clone(); + + let (chain_sync, chain_sync_service) = ChainSync::new( + sc_network_common::sync::SyncMode::Full, + client.clone(), + Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), + 1u32, + None, + chain_sync_network_handle.clone(), + ) + .unwrap(); + + let (node1, mut event_stream1) = TestNetworkBuilder::new() + .with_listen_addresses(vec![listen_addr.clone()]) + .with_chain_sync((Box::new(chain_sync), chain_sync_service)) + .with_chain_sync_network((chain_sync_network_provider, chain_sync_network_handle)) + .with_client(client.clone()) + .build() + .start_network(); + + let (node2, mut event_stream2) = TestNetworkBuilder::new() + .with_set_config(SetConfig { + reserved_nodes: vec![MultiaddrWithPeerId { + multiaddr: listen_addr, + peer_id: node1.local_peer_id, + }], + ..Default::default() + }) + .with_client(client.clone()) + .build() + .start_network(); + + async fn wait_for_events(stream: &mut (impl Stream + std::marker::Unpin)) { + let mut notif_received = false; + let mut sync_received = false; + while !notif_received || !sync_received { + match stream.next().await.unwrap() { + Event::NotificationStreamOpened { .. } => notif_received = true, + Event::SyncConnected { .. } => sync_received = true, + _ => {}, + }; + } + } + + wait_for_events(&mut event_stream1).await; + wait_for_events(&mut event_stream2).await; + + handle_clone.disconnect_peer(node2.local_peer_id, BLOCK_ANNOUNCE_PROTO_NAME.into()); + + let wait_disconnection = async { + while !std::matches!(event_stream1.next().await, Some(Event::SyncDisconnected { .. })) {} + }; + + if async_std::future::timeout(Duration::from_secs(5), wait_disconnection) + .await + .is_err() + { + panic!("did not receive disconnection event in time"); + } +} diff --git a/client/network/src/service/tests/mod.rs b/client/network/src/service/tests/mod.rs index f829d9d43090f..ef25616a07b0d 100644 --- a/client/network/src/service/tests/mod.rs +++ b/client/network/src/service/tests/mod.rs @@ -33,7 +33,9 @@ use sc_network_common::{ }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ - block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler, + block_request_handler::BlockRequestHandler, + service::network::{NetworkServiceHandle, NetworkServiceProvider}, + state_request_handler::StateRequestHandler, ChainSync, }; use sp_runtime::traits::{Block as BlockT, Header as _, Zero}; @@ -93,6 +95,7 @@ struct TestNetworkBuilder { listen_addresses: Vec, set_config: Option, chain_sync: Option<(Box>, Box>)>, + chain_sync_network: Option<(NetworkServiceProvider, NetworkServiceHandle)>, config: Option, } @@ -104,6 +107,7 @@ impl TestNetworkBuilder { listen_addresses: Vec::new(), set_config: None, chain_sync: None, + chain_sync_network: None, config: None, } } @@ -136,6 +140,19 @@ impl TestNetworkBuilder { self } + pub fn with_chain_sync_network( + mut self, + chain_sync_network: (NetworkServiceProvider, NetworkServiceHandle), + ) -> Self { + self.chain_sync_network = Some(chain_sync_network); + self + } + + pub fn with_import_queue(mut self, import_queue: Box>) -> Self { + self.import_queue = Some(import_queue); + self + } + pub fn build(mut self) -> TestNetwork { let client = self.client.as_mut().map_or( Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0), @@ -199,6 +216,9 @@ impl TestNetworkBuilder { None, ))); + let (chain_sync_network_provider, chain_sync_network_handle) = + self.chain_sync_network.unwrap_or(NetworkServiceProvider::new()); + let (chain_sync, chain_sync_service) = self.chain_sync.unwrap_or({ let (chain_sync, chain_sync_service) = ChainSync::new( match network_config.sync_mode { @@ -214,6 +234,7 @@ impl TestNetworkBuilder { Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), network_config.max_parallel_downloads, None, + chain_sync_network_handle, ) .unwrap(); @@ -292,6 +313,11 @@ impl TestNetworkBuilder { }) .unwrap(); + let service = worker.service().clone(); + async_std::task::spawn(async move { + let _ = chain_sync_network_provider.run(service).await; + }); + TestNetwork::new(worker) } } diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 63f63f7188cfe..f369bdb47e1c6 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -271,6 +271,8 @@ pub struct ChainSync { gap_sync: Option>, /// Channel for receiving service commands service_rx: TracingUnboundedReceiver>, + /// Handle for communicating with `NetworkService` + _network_service: service::network::NetworkServiceHandle, } /// All the data we have about a Peer that we are trying to sync with @@ -1775,6 +1777,7 @@ where block_announce_validator: Box + Send>, max_parallel_downloads: u32, warp_sync_provider: Option>>, + _network_service: service::network::NetworkServiceHandle, ) -> Result<(Self, Box>), ClientError> { let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync"); @@ -1800,6 +1803,7 @@ where import_existing: false, gap_sync: None, service_rx, + _network_service, }; sync.reset_sync_start_point()?; Ok((sync, Box::new(ChainSyncInterfaceHandle::new(tx)))) @@ -2670,6 +2674,7 @@ fn validate_blocks( #[cfg(test)] mod test { use super::*; + use crate::service::network::NetworkServiceProvider; use futures::{executor::block_on, future::poll_fn}; use sc_block_builder::BlockBuilderProvider; use sc_network_common::sync::message::{BlockData, BlockState, FromBlock}; @@ -2691,9 +2696,17 @@ mod test { let block_announce_validator = Box::new(DefaultBlockAnnounceValidator); let peer_id = PeerId::random(); - let (mut sync, _) = - ChainSync::new(SyncMode::Full, client.clone(), block_announce_validator, 1, None) - .unwrap(); + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); + let (mut sync, _) = ChainSync::new( + SyncMode::Full, + client.clone(), + block_announce_validator, + 1, + None, + chain_sync_network_handle, + ) + .unwrap(); let (a1_hash, a1_number) = { let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; @@ -2739,12 +2752,16 @@ mod test { #[test] fn restart_doesnt_affect_peers_downloading_finality_data() { let mut client = Arc::new(TestClientBuilder::new().build()); + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), 1, None, + chain_sync_network_handle, ) .unwrap(); @@ -2905,6 +2922,8 @@ mod test { sp_tracing::try_init_simple(); let mut client = Arc::new(TestClientBuilder::new().build()); + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); let (mut sync, _) = ChainSync::new( SyncMode::Full, @@ -2912,6 +2931,7 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 5, None, + chain_sync_network_handle, ) .unwrap(); @@ -3019,6 +3039,8 @@ mod test { }; let mut client = Arc::new(TestClientBuilder::new().build()); + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); let info = client.info(); let (mut sync, _) = ChainSync::new( @@ -3027,6 +3049,7 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 5, None, + chain_sync_network_handle, ) .unwrap(); @@ -3140,6 +3163,8 @@ mod test { fn can_sync_huge_fork() { sp_tracing::try_init_simple(); + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 4) .map(|_| build_block(&mut client, None, false)) @@ -3170,6 +3195,7 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 5, None, + chain_sync_network_handle, ) .unwrap(); @@ -3269,6 +3295,8 @@ mod test { fn syncs_fork_without_duplicate_requests() { sp_tracing::try_init_simple(); + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..MAX_BLOCKS_TO_LOOK_BACKWARDS * 4) .map(|_| build_block(&mut client, None, false)) @@ -3299,6 +3327,7 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 5, None, + chain_sync_network_handle, ) .unwrap(); @@ -3419,6 +3448,8 @@ mod test { #[test] fn removes_target_fork_on_disconnect() { sp_tracing::try_init_simple(); + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..3).map(|_| build_block(&mut client, None, false)).collect::>(); @@ -3428,6 +3459,7 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 1, None, + chain_sync_network_handle, ) .unwrap(); @@ -3450,6 +3482,8 @@ mod test { #[test] fn can_import_response_with_missing_blocks() { sp_tracing::try_init_simple(); + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); let mut client2 = Arc::new(TestClientBuilder::new().build()); let blocks = (0..4).map(|_| build_block(&mut client2, None, false)).collect::>(); @@ -3461,6 +3495,7 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 1, None, + chain_sync_network_handle, ) .unwrap(); diff --git a/client/network/sync/src/service/mock.rs b/client/network/sync/src/service/mock.rs index e283907b392d1..c146e1ec07b48 100644 --- a/client/network/sync/src/service/mock.rs +++ b/client/network/sync/src/service/mock.rs @@ -16,10 +16,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use libp2p::PeerId; -use sc_network_common::service::NetworkSyncForkRequest; +use sc_network_common::service::{NetworkPeers, NetworkSyncForkRequest}; use sp_runtime::traits::{Block as BlockT, NumberFor}; +pub use libp2p::{identity::error::SigningError, kad::record::Key as KademliaKey}; +use libp2p::{Multiaddr, PeerId}; +use sc_network_common::{config::MultiaddrWithPeerId, protocol::ProtocolName}; +use sc_peerset::ReputationChange; +use std::collections::HashSet; + mockall::mock! { pub ChainSyncInterface {} @@ -29,3 +34,42 @@ mockall::mock! { fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor); } } + +mockall::mock! { + pub NetworkServiceHandle {} +} + +// Mocked `Network` for `ChainSync`-related tests +mockall::mock! { + pub Network {} + + impl NetworkPeers for Network { + fn set_authorized_peers(&self, peers: HashSet); + fn set_authorized_only(&self, reserved_only: bool); + fn add_known_address(&self, peer_id: PeerId, addr: Multiaddr); + fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange); + fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName); + fn accept_unreserved_peers(&self); + fn deny_unreserved_peers(&self); + fn add_reserved_peer(&self, peer: MultiaddrWithPeerId) -> Result<(), String>; + fn remove_reserved_peer(&self, peer_id: PeerId); + fn set_reserved_peers( + &self, + protocol: ProtocolName, + peers: HashSet, + ) -> Result<(), String>; + fn add_peers_to_reserved_set( + &self, + protocol: ProtocolName, + peers: HashSet, + ) -> Result<(), String>; + fn remove_peers_from_reserved_set(&self, protocol: ProtocolName, peers: Vec); + fn add_to_peers_set( + &self, + protocol: ProtocolName, + peers: HashSet, + ) -> Result<(), String>; + fn remove_from_peers_set(&self, protocol: ProtocolName, peers: Vec); + fn sync_num_connected(&self) -> usize; + } +} diff --git a/client/network/sync/src/service/mod.rs b/client/network/sync/src/service/mod.rs index d64d9bbd1b01f..692aa26985458 100644 --- a/client/network/sync/src/service/mod.rs +++ b/client/network/sync/src/service/mod.rs @@ -20,3 +20,4 @@ pub mod chain_sync; pub mod mock; +pub mod network; diff --git a/client/network/sync/src/service/network.rs b/client/network/sync/src/service/network.rs new file mode 100644 index 0000000000000..44ed177661264 --- /dev/null +++ b/client/network/sync/src/service/network.rs @@ -0,0 +1,128 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use futures::StreamExt; +use libp2p::PeerId; +use sc_network_common::{protocol::ProtocolName, service::NetworkPeers}; +use sc_peerset::ReputationChange; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; +use std::sync::Arc; + +/// Network-related services required by `sc-network-sync` +pub trait Network: NetworkPeers {} + +impl Network for T where T: NetworkPeers {} + +/// Network service provider for `ChainSync` +/// +/// It runs as an asynchronous task and listens to commands coming from `ChainSync` and +/// calls the `NetworkService` on its behalf. +pub struct NetworkServiceProvider { + rx: TracingUnboundedReceiver, +} + +/// Commands that `ChainSync` wishes to send to `NetworkService` +pub enum ToServiceCommand { + /// Call `NetworkPeers::disconnect_peer()` + DisconnectPeer(PeerId, ProtocolName), + + /// Call `NetworkPeers::report_peer()` + ReportPeer(PeerId, ReputationChange), +} + +/// Handle that is (temporarily) passed to `ChainSync` so it can +/// communicate with `NetworkService` through `SyncingEngine` +#[derive(Clone)] +pub struct NetworkServiceHandle { + tx: TracingUnboundedSender, +} + +impl NetworkServiceHandle { + /// Create new service handle + pub fn new(tx: TracingUnboundedSender) -> NetworkServiceHandle { + Self { tx } + } + + /// Report peer + pub fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { + let _ = self.tx.unbounded_send(ToServiceCommand::ReportPeer(who, cost_benefit)); + } + + /// Disconnect peer + pub fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { + let _ = self.tx.unbounded_send(ToServiceCommand::DisconnectPeer(who, protocol)); + } +} + +impl NetworkServiceProvider { + /// Create new `NetworkServiceProvider` + pub fn new() -> (Self, NetworkServiceHandle) { + let (tx, rx) = tracing_unbounded("mpsc_network_service_provider"); + + (Self { rx }, NetworkServiceHandle::new(tx)) + } + + /// Run the `NetworkServiceProvider` + pub async fn run(mut self, service: Arc) { + while let Some(inner) = self.rx.next().await { + match inner { + ToServiceCommand::DisconnectPeer(peer, protocol_name) => + service.disconnect_peer(peer, protocol_name), + ToServiceCommand::ReportPeer(peer, reputation_change) => + service.report_peer(peer, reputation_change), + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::service::mock::MockNetwork; + + // typical pattern in `Protocol` code where peer is disconnected + // and then reported + #[async_std::test] + async fn disconnect_and_report_peer() { + let (provider, handle) = NetworkServiceProvider::new(); + + let peer = PeerId::random(); + let proto = ProtocolName::from("test-protocol"); + let proto_clone = proto.clone(); + let change = sc_peerset::ReputationChange::new_fatal("test-change"); + + let mut mock_network = MockNetwork::new(); + mock_network + .expect_disconnect_peer() + .withf(move |in_peer, in_proto| &peer == in_peer && &proto == in_proto) + .once() + .returning(|_, _| ()); + mock_network + .expect_report_peer() + .withf(move |in_peer, in_change| &peer == in_peer && &change == in_change) + .once() + .returning(|_, _| ()); + + async_std::task::spawn(async move { + provider.run(Arc::new(mock_network)).await; + }); + + handle.disconnect_peer(peer, proto_clone); + handle.report_peer(peer, change); + } +} diff --git a/client/network/sync/src/tests.rs b/client/network/sync/src/tests.rs index 47483c4ac440d..479c78bfdea97 100644 --- a/client/network/sync/src/tests.rs +++ b/client/network/sync/src/tests.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{ChainSync, ForkTarget}; +use crate::{service::network::NetworkServiceProvider, ChainSync, ForkTarget}; use libp2p::PeerId; use sc_network_common::{service::NetworkSyncForkRequest, sync::ChainSync as ChainSyncT}; @@ -29,12 +29,14 @@ use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _ // poll `ChainSync` and verify that a new sync fork request has been registered #[async_std::test] async fn delegate_to_chainsync() { + let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let (mut chain_sync, chain_sync_service) = ChainSync::new( sc_network_common::sync::SyncMode::Full, Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0), Box::new(DefaultBlockAnnounceValidator), 1u32, None, + chain_sync_network_handle, ) .unwrap(); diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 5460cc7d52461..c9b99fbc6af10 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -61,8 +61,8 @@ use sc_network_common::{ }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ - block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler, - warp_request_handler, ChainSync, + block_request_handler::BlockRequestHandler, service::network::NetworkServiceProvider, + state_request_handler::StateRequestHandler, warp_request_handler, ChainSync, }; use sc_service::client::Client; use sp_blockchain::{ @@ -864,6 +864,8 @@ where let block_announce_validator = config .block_announce_validator .unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)); + let (chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); let (chain_sync, chain_sync_service) = ChainSync::new( match network_config.sync_mode { SyncMode::Full => sc_network_common::sync::SyncMode::Full, @@ -878,6 +880,7 @@ where block_announce_validator, network_config.max_parallel_downloads, Some(warp_sync), + chain_sync_network_handle, ) .unwrap(); let block_announce_config = chain_sync.get_block_announce_proto_config( @@ -915,6 +918,11 @@ where trace!(target: "test_network", "Peer identifier: {}", network.service().local_peer_id()); + let service = network.service().clone(); + async_std::task::spawn(async move { + chain_sync_network_provider.run(service).await; + }); + self.mut_peers(move |peers| { for peer in peers.iter_mut() { peer.network diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 1a16268839054..3cb064ec814c5 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -46,7 +46,8 @@ use sc_network_common::{ }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ - block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler, + block_request_handler::BlockRequestHandler, service::network::NetworkServiceProvider, + state_request_handler::StateRequestHandler, warp_request_handler::RequestHandler as WarpSyncRequestHandler, ChainSync, }; use sc_rpc::{ @@ -844,6 +845,7 @@ where protocol_config }; + let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let (chain_sync, chain_sync_service) = ChainSync::new( match config.network.sync_mode { SyncMode::Full => sc_network_common::sync::SyncMode::Full, @@ -855,7 +857,9 @@ where block_announce_validator, config.network.max_parallel_downloads, warp_sync_provider, + chain_sync_network_handle, )?; + let block_announce_config = chain_sync.get_block_announce_proto_config( protocol_id.clone(), &config.chain_spec.fork_id().map(ToOwned::to_owned), @@ -926,7 +930,13 @@ where Arc::new(TransactionPoolAdapter { pool: transaction_pool, client: client.clone() }), config.prometheus_config.as_ref().map(|config| &config.registry), )?; + spawn_handle.spawn("network-transactions-handler", Some("networking"), tx_handler.run()); + spawn_handle.spawn( + "chain-sync-network-service-provider", + Some("networking"), + chain_sync_network_provider.run(network.clone()), + ); let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc"); From 3bbdba405d42d7023eeb297efb03a3ec4ccf9563 Mon Sep 17 00:00:00 2001 From: Dmitrii Markin Date: Mon, 24 Oct 2022 14:47:58 +0300 Subject: [PATCH 1304/1472] Base Kademlia protocol name on genesis hash and fork ID (#12545) --- client/network/src/discovery.rs | 132 +++++++++++++++++++++++--------- client/network/src/service.rs | 10 ++- 2 files changed, 104 insertions(+), 38 deletions(-) diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 712c3af97f58e..00fc78061293d 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -46,6 +46,7 @@ //! active mechanism that asks nodes for the addresses they are listening on. Whenever we learn //! of a node's address, you must call `add_self_reported_address`. +use array_bytes::bytes2hex; use futures::prelude::*; use futures_timer::Delay; use ip_network::IpNetwork; @@ -101,7 +102,7 @@ pub struct DiscoveryConfig { discovery_only_if_under_num: u64, enable_mdns: bool, kademlia_disjoint_query_paths: bool, - kademlia_protocol_id: Option, + kademlia_protocols: Vec>, } impl DiscoveryConfig { @@ -116,7 +117,7 @@ impl DiscoveryConfig { discovery_only_if_under_num: std::u64::MAX, enable_mdns: false, kademlia_disjoint_query_paths: false, - kademlia_protocol_id: None, + kademlia_protocols: Vec::new(), } } @@ -161,9 +162,18 @@ impl DiscoveryConfig { } /// Add discovery via Kademlia for the given protocol. - pub fn with_kademlia(&mut self, id: ProtocolId) -> &mut Self { - self.kademlia_protocol_id = Some(id); - + /// + /// Currently accepts `protocol_id`. This should be removed once all the nodes + /// are upgraded to genesis hash- and fork ID-based Kademlia protocol name. + pub fn with_kademlia>( + &mut self, + genesis_hash: Hash, + fork_id: Option<&str>, + protocol_id: &ProtocolId, + ) -> &mut Self { + self.kademlia_protocols = Vec::new(); + self.kademlia_protocols.push(kademlia_protocol_name(genesis_hash, fork_id)); + self.kademlia_protocols.push(legacy_kademlia_protocol_name(protocol_id)); self } @@ -185,14 +195,12 @@ impl DiscoveryConfig { discovery_only_if_under_num, enable_mdns, kademlia_disjoint_query_paths, - kademlia_protocol_id, + kademlia_protocols, } = self; - let kademlia = kademlia_protocol_id.map(|protocol_id| { - let proto_name = protocol_name_from_protocol_id(&protocol_id); - + let kademlia = if !kademlia_protocols.is_empty() { let mut config = KademliaConfig::default(); - config.set_protocol_names(std::iter::once(proto_name.into()).collect()); + config.set_protocol_names(kademlia_protocols.into_iter().map(Into::into).collect()); // By default Kademlia attempts to insert all peers into its routing table once a // dialing attempt succeeds. In order to control which peer is added, disable the // auto-insertion and instead add peers manually. @@ -206,8 +214,10 @@ impl DiscoveryConfig { kad.add_address(peer_id, addr.clone()); } - kad - }); + Some(kad) + } else { + None + }; DiscoveryBehaviour { permanent_addresses, @@ -866,35 +876,50 @@ impl NetworkBehaviour for DiscoveryBehaviour { } } -// NB: If this protocol name derivation is changed, check if -// `DiscoveryBehaviour::new_handler` is still correct. -fn protocol_name_from_protocol_id(id: &ProtocolId) -> Vec { +/// Legacy (fallback) Kademlia protocol name based on `protocol_id`. +fn legacy_kademlia_protocol_name(id: &ProtocolId) -> Vec { let mut v = vec![b'/']; v.extend_from_slice(id.as_ref().as_bytes()); v.extend_from_slice(b"/kad"); v } +/// Kademlia protocol name based on `genesis_hash` and `fork_id`. +fn kademlia_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> Vec { + let genesis_hash_hex = bytes2hex("", genesis_hash.as_ref()); + if let Some(fork_id) = fork_id { + format!("/{}/{}/kad", genesis_hash_hex, fork_id).as_bytes().into() + } else { + format!("/{}/kad", genesis_hash_hex).as_bytes().into() + } +} + #[cfg(test)] mod tests { - use super::{protocol_name_from_protocol_id, DiscoveryConfig, DiscoveryOut}; + use super::{ + kademlia_protocol_name, legacy_kademlia_protocol_name, DiscoveryConfig, DiscoveryOut, + }; use futures::prelude::*; use libp2p::{ core::{ transport::{MemoryTransport, Transport}, upgrade, }, - identity::Keypair, + identity::{ed25519, Keypair}, noise, swarm::{Swarm, SwarmEvent}, - yamux, Multiaddr, PeerId, + yamux, Multiaddr, }; use sc_network_common::config::ProtocolId; + use sp_core::hash::H256; use std::{collections::HashSet, task::Poll}; #[test] fn discovery_working() { let mut first_swarm_peer_id_and_addr = None; + + let genesis_hash = H256::from_low_u64_be(1); + let fork_id = Some("test-fork-id"); let protocol_id = ProtocolId::from("dot"); // Build swarms whose behaviour is `DiscoveryBehaviour`, each aware of @@ -919,7 +944,7 @@ mod tests { .allow_private_ipv4(true) .allow_non_globals_in_dht(true) .discovery_limit(50) - .with_kademlia(protocol_id.clone()); + .with_kademlia(genesis_hash, fork_id, &protocol_id); config.finish() }; @@ -972,12 +997,19 @@ mod tests { } }) .unwrap(); + // Test both genesis hash-based and legacy + // protocol names. + let protocol_name = if swarm_n % 2 == 0 { + kademlia_protocol_name(genesis_hash, fork_id) + } else { + legacy_kademlia_protocol_name(&protocol_id) + }; swarms[swarm_n] .0 .behaviour_mut() .add_self_reported_address( &other, - &[protocol_name_from_protocol_id(&protocol_id)], + &[protocol_name], addr, ); @@ -1012,6 +1044,8 @@ mod tests { #[test] fn discovery_ignores_peers_with_unknown_protocols() { + let supported_genesis_hash = H256::from_low_u64_be(1); + let unsupported_genesis_hash = H256::from_low_u64_be(2); let supported_protocol_id = ProtocolId::from("a"); let unsupported_protocol_id = ProtocolId::from("b"); @@ -1022,19 +1056,34 @@ mod tests { .allow_private_ipv4(true) .allow_non_globals_in_dht(true) .discovery_limit(50) - .with_kademlia(supported_protocol_id.clone()); + .with_kademlia(supported_genesis_hash, None, &supported_protocol_id); config.finish() }; - let remote_peer_id = PeerId::random(); - let remote_addr: Multiaddr = format!("/memory/{}", rand::random::()).parse().unwrap(); + let predictable_peer_id = |bytes: &[u8; 32]| { + Keypair::Ed25519(ed25519::Keypair::from( + ed25519::SecretKey::from_bytes(bytes.to_owned()).unwrap(), + )) + .public() + .to_peer_id() + }; + + let remote_peer_id = predictable_peer_id(b"00000000000000000000000000000001"); + let remote_addr: Multiaddr = "/memory/1".parse().unwrap(); + let another_peer_id = predictable_peer_id(b"00000000000000000000000000000002"); + let another_addr: Multiaddr = "/memory/2".parse().unwrap(); - // Add remote peer with unsupported protocol. + // Try adding remote peers with unsupported protocols. discovery.add_self_reported_address( &remote_peer_id, - &[protocol_name_from_protocol_id(&unsupported_protocol_id)], + &[kademlia_protocol_name(unsupported_genesis_hash, None)], remote_addr.clone(), ); + discovery.add_self_reported_address( + &another_peer_id, + &[legacy_kademlia_protocol_name(&unsupported_protocol_id)], + another_addr.clone(), + ); { let kademlia = discovery.kademlia.as_mut().unwrap(); @@ -1045,23 +1094,34 @@ mod tests { .is_empty(), "Expect peer with unsupported protocol not to be added." ); + assert!( + kademlia + .kbucket(another_peer_id) + .expect("Remote peer id not to be equal to local peer id.") + .is_empty(), + "Expect peer with unsupported protocol not to be added." + ); } - // Add remote peer with supported protocol. + // Add remote peers with supported protocols. discovery.add_self_reported_address( &remote_peer_id, - &[protocol_name_from_protocol_id(&supported_protocol_id)], + &[kademlia_protocol_name(supported_genesis_hash, None)], remote_addr.clone(), ); - - let kademlia = discovery.kademlia.as_mut().unwrap(); - assert_eq!( - 1, - kademlia - .kbucket(remote_peer_id) - .expect("Remote peer id not to be equal to local peer id.") - .num_entries(), - "Expect peer with supported protocol to be added." + discovery.add_self_reported_address( + &another_peer_id, + &[legacy_kademlia_protocol_name(&supported_protocol_id)], + another_addr.clone(), ); + + { + let kademlia = discovery.kademlia.as_mut().unwrap(); + assert_eq!( + 2, + kademlia.kbuckets().fold(0, |acc, bucket| acc + bucket.num_entries()), + "Expect peers with supported protocol to be added." + ); + } } } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 89dc2ff4405b2..5ffd36007f530 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -76,7 +76,7 @@ use sc_network_common::{ use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::HeaderBackend; -use sp_runtime::traits::{Block as BlockT, NumberFor}; +use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; use std::{ cmp, collections::{HashMap, HashSet}, @@ -282,7 +282,13 @@ where config.discovery_limit( u64::from(params.network_config.default_peers_set.out_peers) + 15, ); - config.with_kademlia(params.protocol_id.clone()); + let genesis_hash = params + .chain + .hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"); + config.with_kademlia(genesis_hash, params.fork_id.as_deref(), ¶ms.protocol_id); config.with_dht_random_walk(params.network_config.enable_dht_random_walk); config.allow_non_globals_in_dht(params.network_config.allow_non_globals_in_dht); config.use_kademlia_disjoint_query_paths( From 433a6f725c56403d09ecde838c5509059df92e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Mon, 24 Oct 2022 19:48:04 +0200 Subject: [PATCH 1305/1472] contracts: Allow indeterministic instructions off-chain (#12469) * Allow indetermistic instructions off-chain * Apply suggestions from code review Co-authored-by: Sasha Gryaznov * fmt Co-authored-by: Sasha Gryaznov --- bin/node/runtime/src/lib.rs | 35 +- frame/contracts/README.md | 29 +- .../fixtures/delegate_call_simple.wat | 50 ++ .../contracts/fixtures/float_instruction.wat | 11 + frame/contracts/src/benchmarking/code.rs | 4 +- frame/contracts/src/benchmarking/mod.rs | 6 +- frame/contracts/src/exec.rs | 82 ++- frame/contracts/src/lib.rs | 39 +- frame/contracts/src/migration.rs | 197 ++++--- frame/contracts/src/schedule.rs | 23 +- frame/contracts/src/tests.rs | 545 ++++++++++++++++-- frame/contracts/src/wasm/code_cache.rs | 2 +- frame/contracts/src/wasm/mod.rs | 41 +- frame/contracts/src/wasm/prepare.rs | 30 +- frame/contracts/src/wasm/runtime.rs | 1 + 15 files changed, 926 insertions(+), 169 deletions(-) create mode 100644 frame/contracts/fixtures/delegate_call_simple.wat create mode 100644 frame/contracts/fixtures/float_instruction.wat diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f137b36eff036..5ba89e6595e72 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1959,7 +1959,16 @@ impl_runtime_apis! { input_data: Vec, ) -> pallet_contracts_primitives::ContractExecResult { let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); - Contracts::bare_call(origin, dest, value, gas_limit, storage_deposit_limit, input_data, true) + Contracts::bare_call( + origin, + dest, + value, + gas_limit, + storage_deposit_limit, + input_data, + true, + pallet_contracts::Determinism::Deterministic, + ) } fn instantiate( @@ -1973,23 +1982,41 @@ impl_runtime_apis! { ) -> pallet_contracts_primitives::ContractInstantiateResult { let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); - Contracts::bare_instantiate(origin, value, gas_limit, storage_deposit_limit, code, data, salt, true) + Contracts::bare_instantiate( + origin, + value, + gas_limit, + storage_deposit_limit, + code, + data, + salt, + true + ) } fn upload_code( origin: AccountId, code: Vec, storage_deposit_limit: Option, + determinism: pallet_contracts::Determinism, ) -> pallet_contracts_primitives::CodeUploadResult { - Contracts::bare_upload_code(origin, code, storage_deposit_limit) + Contracts::bare_upload_code( + origin, + code, + storage_deposit_limit, + determinism, + ) } fn get_storage( address: AccountId, key: Vec, ) -> pallet_contracts_primitives::GetStorageResult { - Contracts::get_storage(address, key) + Contracts::get_storage( + address, + key + ) } } diff --git a/frame/contracts/README.md b/frame/contracts/README.md index bd5e58d89d1ce..18d16889a3fe8 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -37,12 +37,37 @@ changes still persist. One gas is equivalent to one [weight](https://docs.substrate.io/v3/runtime/weights-and-fees) which is defined as one picosecond of execution time on the runtime's reference machine. -### Notable Scenarios +### Revert Behaviour -Contract call failures are not always cascading. When failures occur in a sub-call, they do not "bubble up", +Contract call failures are not cascading. When failures occur in a sub-call, they do not "bubble up", and the call will only revert at the specific contract level. For example, if contract A calls contract B, and B fails, A can decide how to handle that failure, either proceeding or reverting A's changes. +### Offchain Execution + +In general, a contract execution needs to be deterministic so that all nodes come to the same +conclusion when executing it. To that end we disallow any instructions that could cause +indeterminism. Most notable are any floating point arithmetic. That said, sometimes contracts +are executed off-chain and hence are not subject to consensus. If code is only executed by a +single node and implicitly trusted by other actors is such a case. Trusted execution environments +come to mind. To that end we allow the execution of indeterminstic code for offchain usages +with the following constraints: + +1. No contract can ever be instantiated from an indeterministic code. The only way to execute +the code is to use a delegate call from a deterministic contract. +2. The code that wants to use this feature needs to depend on `pallet-contracts` and use `bare_call` +directly. This makes sure that by default `pallet-contracts` does not expose any indeterminism. + +## How to use + +When setting up the `Schedule` for your runtime make sure to set `InstructionWeights::fallback` +to a non zero value. The default is `0` and prevents the upload of any non deterministic code. + +An indeterministic code can be deployed on-chain by passing `Determinism::AllowIndeterministic` +to `upload_code`. A determinstic contract can then delegate call into it if and only if it +is ran by using `bare_call` and passing `Determinism::AllowIndeterministic` to it. **Never use +this argument when the contract is called from an on-chain transaction.** + ## Interface ### Dispatchable functions diff --git a/frame/contracts/fixtures/delegate_call_simple.wat b/frame/contracts/fixtures/delegate_call_simple.wat new file mode 100644 index 0000000000000..24ae5a13e33e5 --- /dev/null +++ b/frame/contracts/fixtures/delegate_call_simple.wat @@ -0,0 +1,50 @@ +;; Just delegate call into the passed code hash and assert success. +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 3 3)) + + ;; [0, 32) buffer where input is copied + + ;; [32, 36) size of the input buffer + (data (i32.const 32) "\20") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + ;; Reading "callee" code_hash + (call $seal_input (i32.const 0) (i32.const 32)) + + ;; assert input size == 32 + (call $assert + (i32.eq + (i32.load (i32.const 32)) + (i32.const 32) + ) + ) + + ;; Delegate call into passed code hash + (call $assert + (i32.eq + (call $seal_delegate_call + (i32.const 0) ;; Set no call flags + (i32.const 0) ;; Pointer to "callee" code_hash. + (i32.const 0) ;; Input is ignored + (i32.const 0) ;; Length of the input + (i32.const 4294967295) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + ) + (i32.const 0) + ) + ) + ) + + (func (export "deploy")) +) diff --git a/frame/contracts/fixtures/float_instruction.wat b/frame/contracts/fixtures/float_instruction.wat new file mode 100644 index 0000000000000..c19b5c12cdcec --- /dev/null +++ b/frame/contracts/fixtures/float_instruction.wat @@ -0,0 +1,11 @@ +;; Module that contains a float instruction which is illegal in deterministic mode +(module + (func (export "call") + f32.const 1 + drop + ) + (func (export "deploy") + f32.const 2 + drop + ) +) diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 32ee2dbf93914..b14b107f34c90 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -24,7 +24,7 @@ //! we define this simple definition of a contract that can be passed to `create_code` that //! compiles it down into a `WasmModule` that can be used as a contract's code. -use crate::Config; +use crate::{Config, Determinism}; use frame_support::traits::Get; use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::Hash; @@ -554,7 +554,7 @@ where fn inject_gas_metering(module: Module) -> Module { let schedule = T::Schedule::get(); - let gas_rules = schedule.rules(&module); + let gas_rules = schedule.rules(&module, Determinism::Deterministic); wasm_instrument::gas_metering::inject(module, &gas_rules, "seal0").unwrap() } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 86c7d2df674c7..a952eeb2cbd3a 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -371,7 +371,7 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); let origin = RawOrigin::Signed(caller.clone()); - }: _(origin, code, None) + }: _(origin, code, None, Determinism::Deterministic) verify { // uploading the code reserves some balance in the callers account assert!(T::Currency::reserved_balance(&caller) > 0u32.into()); @@ -386,7 +386,7 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::dummy(); let origin = RawOrigin::Signed(caller.clone()); - let uploaded = >::bare_upload_code(caller.clone(), code, None)?; + let uploaded = >::bare_upload_code(caller.clone(), code, None, Determinism::Deterministic)?; assert_eq!(uploaded.code_hash, hash); assert_eq!(uploaded.deposit, T::Currency::reserved_balance(&caller)); assert!(>::code_exists(&hash)); @@ -2894,6 +2894,7 @@ benchmarks! { None, data, false, + Determinism::Deterministic, ) .result?; } @@ -2941,6 +2942,7 @@ benchmarks! { None, data, false, + Determinism::Deterministic, ) .result?; } diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index bf35410d0bd4b..7955f076b84c4 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -18,7 +18,7 @@ use crate::{ gas::GasMeter, storage::{self, Storage, WriteOutcome}, - BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Error, Event, Nonce, + BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Determinism, Error, Event, Nonce, Pallet as Contracts, Schedule, }; use frame_support::{ @@ -355,6 +355,9 @@ pub trait Executable: Sized { /// Size of the instrumented code in bytes. fn code_len(&self) -> u32; + + /// The code does not contain any instructions which could lead to indeterminism. + fn is_deterministic(&self) -> bool; } /// The complete call stack of a contract execution. @@ -395,6 +398,8 @@ pub struct Stack<'a, T: Config, E> { /// All the bytes added to this field should be valid UTF-8. The buffer has no defined /// structure and is intended to be shown to users as-is for debugging purposes. debug_message: Option<&'a mut Vec>, + /// The determinism requirement of this call stack. + determinism: Determinism, /// No executable is held by the struct but influences its behaviour. _phantom: PhantomData, } @@ -601,6 +606,7 @@ where value: BalanceOf, input_data: Vec, debug_message: Option<&'a mut Vec>, + determinism: Determinism, ) -> Result { let (mut stack, executable) = Self::new( FrameArgs::Call { dest, cached_info: None, delegated_call: None }, @@ -610,6 +616,7 @@ where schedule, value, debug_message, + determinism, )?; stack.run(executable, input_data) } @@ -648,6 +655,7 @@ where schedule, value, debug_message, + Determinism::Deterministic, )?; let account_id = stack.top_frame().account_id.clone(); stack.run(executable, input_data).map(|ret| (account_id, ret)) @@ -662,9 +670,17 @@ where schedule: &'a Schedule, value: BalanceOf, debug_message: Option<&'a mut Vec>, + determinism: Determinism, ) -> Result<(Self, E), ExecError> { - let (first_frame, executable, nonce) = - Self::new_frame(args, value, gas_meter, storage_meter, Weight::zero(), schedule)?; + let (first_frame, executable, nonce) = Self::new_frame( + args, + value, + gas_meter, + storage_meter, + Weight::zero(), + schedule, + determinism, + )?; let stack = Self { origin, schedule, @@ -676,6 +692,7 @@ where first_frame, frames: Default::default(), debug_message, + determinism, _phantom: Default::default(), }; @@ -693,6 +710,7 @@ where storage_meter: &mut storage::meter::GenericMeter, gas_limit: Weight, schedule: &Schedule, + determinism: Determinism, ) -> Result<(Frame, E, Option), ExecError> { let (account_id, contract_info, executable, delegate_caller, entry_point, nonce) = match frame_args { @@ -729,6 +747,15 @@ where }, }; + // `AllowIndeterminism` will only be ever set in case of off-chain execution. + // Instantiations are never allowed even when executing off-chain. + if !(executable.is_deterministic() || + (matches!(determinism, Determinism::AllowIndeterminism) && + matches!(entry_point, ExportedFunction::Call))) + { + return Err(Error::::Indeterministic.into()) + } + let frame = Frame { delegate_caller, value_transferred, @@ -775,6 +802,7 @@ where nested_storage, gas_limit, self.schedule, + self.determinism, )?; self.frames.push(frame); Ok(executable) @@ -1328,15 +1356,18 @@ where } fn set_code_hash(&mut self, hash: CodeHash) -> Result<(), DispatchError> { + let frame = top_frame_mut!(self); + if !E::from_storage(hash, self.schedule, &mut frame.nested_gas)?.is_deterministic() { + return Err(>::Indeterministic.into()) + } E::add_user(hash)?; - let top_frame = self.top_frame_mut(); - let prev_hash = top_frame.contract_info().code_hash; + let prev_hash = frame.contract_info().code_hash; E::remove_user(prev_hash); - top_frame.contract_info().code_hash = hash; + frame.contract_info().code_hash = hash; Contracts::::deposit_event( - vec![T::Hashing::hash_of(&top_frame.account_id), hash, prev_hash], + vec![T::Hashing::hash_of(&frame.account_id), hash, prev_hash], Event::ContractCodeUpdated { - contract: top_frame.account_id.clone(), + contract: frame.account_id.clone(), new_code_hash: hash, old_code_hash: prev_hash, }, @@ -1513,6 +1544,10 @@ mod tests { fn code_len(&self) -> u32 { 0 } + + fn is_deterministic(&self) -> bool { + true + } } fn exec_success() -> ExecResult { @@ -1551,6 +1586,7 @@ mod tests { value, vec![], None, + Determinism::Deterministic, ), Ok(_) ); @@ -1604,6 +1640,7 @@ mod tests { value, vec![], None, + Determinism::Deterministic, ) .unwrap(); @@ -1645,6 +1682,7 @@ mod tests { value, vec![], None, + Determinism::Deterministic, ) .unwrap(); @@ -1680,6 +1718,7 @@ mod tests { 55, vec![], None, + Determinism::Deterministic, ) .unwrap(); @@ -1731,6 +1770,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic, ); let output = result.unwrap(); @@ -1763,6 +1803,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic, ); let output = result.unwrap(); @@ -1793,6 +1834,7 @@ mod tests { 0, vec![1, 2, 3, 4], None, + Determinism::Deterministic, ); assert_matches!(result, Ok(_)); }); @@ -1873,6 +1915,7 @@ mod tests { value, vec![], None, + Determinism::Deterministic, ); assert_matches!(result, Ok(_)); @@ -1918,6 +1961,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic, ); assert_matches!(result, Ok(_)); @@ -1951,6 +1995,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic, ); assert_matches!(result, Ok(_)); }); @@ -1980,6 +2025,7 @@ mod tests { 0, vec![0], None, + Determinism::Deterministic, ); assert_matches!(result, Ok(_)); }); @@ -2007,6 +2053,7 @@ mod tests { 0, vec![0], None, + Determinism::Deterministic, ); assert_matches!(result, Ok(_)); }); @@ -2042,6 +2089,7 @@ mod tests { 0, vec![0], None, + Determinism::Deterministic, ); assert_matches!(result, Ok(_)); }); @@ -2077,6 +2125,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic, ); assert_matches!(result, Ok(_)); @@ -2235,6 +2284,7 @@ mod tests { min_balance * 10, vec![], None, + Determinism::Deterministic, ), Ok(_) ); @@ -2299,6 +2349,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic, ), Ok(_) ); @@ -2384,6 +2435,7 @@ mod tests { 0, vec![0], None, + Determinism::Deterministic, ); assert_matches!(result, Ok(_)); }); @@ -2450,6 +2502,7 @@ mod tests { 0, vec![], Some(&mut debug_buffer), + Determinism::Deterministic, ) .unwrap(); }); @@ -2483,6 +2536,7 @@ mod tests { 0, vec![], Some(&mut debug_buffer), + Determinism::Deterministic, ); assert!(result.is_err()); }); @@ -2516,6 +2570,7 @@ mod tests { 0, CHARLIE.encode(), None, + Determinism::Deterministic )); // Calling into oneself fails @@ -2529,6 +2584,7 @@ mod tests { 0, BOB.encode(), None, + Determinism::Deterministic ) .map_err(|e| e.error), >::ReentranceDenied, @@ -2567,6 +2623,7 @@ mod tests { 0, vec![0], None, + Determinism::Deterministic ) .map_err(|e| e.error), >::ReentranceDenied, @@ -2601,6 +2658,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic, ) .unwrap(); @@ -2683,6 +2741,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic, ) .unwrap(); @@ -2886,6 +2945,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic )); }); } @@ -3012,6 +3072,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic )); }); } @@ -3047,6 +3108,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic )); }); } @@ -3082,6 +3144,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic )); }); } @@ -3143,6 +3206,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic )); }); } @@ -3204,6 +3268,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic )); }); } @@ -3235,6 +3300,7 @@ mod tests { 0, vec![], None, + Determinism::Deterministic, ); assert_matches!(result, Ok(_)); }); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index d48a71b85e9fe..b2eb0439d6ced 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -132,6 +132,7 @@ pub use crate::{ migration::Migration, pallet::*, schedule::{HostFnWeights, InstructionWeights, Limits, Schedule}, + wasm::Determinism, }; type CodeHash = ::Hash; @@ -206,7 +207,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(8); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(9); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -456,6 +457,10 @@ pub mod pallet { /// the in storage version to the current /// [`InstructionWeights::version`](InstructionWeights). /// + /// - `determinism`: If this is set to any other value but [`Determinism::Deterministic`] + /// then the only way to use this code is to delegate call into it from an offchain + /// execution. Set to [`Determinism::Deterministic`] if in doubt. + /// /// # Note /// /// Anyone can instantiate a contract from any uploaded code and thus prevent its removal. @@ -467,9 +472,11 @@ pub mod pallet { origin: OriginFor, code: Vec, storage_deposit_limit: Option< as codec::HasCompact>::Type>, + determinism: Determinism, ) -> DispatchResult { let origin = ensure_signed(origin)?; - Self::bare_upload_code(origin, code, storage_deposit_limit.map(Into::into)).map(|_| ()) + Self::bare_upload_code(origin, code, storage_deposit_limit.map(Into::into), determinism) + .map(|_| ()) } /// Remove the code stored under `code_hash` and refund the deposit to its owner. @@ -562,6 +569,7 @@ pub mod pallet { storage_deposit_limit.map(Into::into), data, None, + Determinism::Deterministic, ); if let Ok(retval) = &output.result { if retval.did_revert() { @@ -825,6 +833,8 @@ pub mod pallet { /// A more detailed error can be found on the node console if debug messages are enabled /// or in the debug buffer which is returned to RPC clients. CodeRejected, + /// An indetermistic code was used in a context where this is not permitted. + Indeterministic, } /// A mapping from an original code hash to the original code, untouched by instrumentation. @@ -921,6 +931,7 @@ where storage_deposit_limit: Option>, data: Vec, debug: bool, + determinism: Determinism, ) -> ContractExecResult> { let mut debug_message = if debug { Some(Vec::new()) } else { None }; let output = Self::internal_call( @@ -931,6 +942,7 @@ where storage_deposit_limit, data, debug_message.as_mut(), + determinism, ); ContractExecResult { result: output.result.map_err(|r| r.error), @@ -994,10 +1006,11 @@ where origin: T::AccountId, code: Vec, storage_deposit_limit: Option>, + determinism: Determinism, ) -> CodeUploadResult, BalanceOf> { let schedule = T::Schedule::get(); - let module = - PrefabWasmModule::from_code(code, &schedule, origin).map_err(|(err, _)| err)?; + let module = PrefabWasmModule::from_code(code, &schedule, origin, determinism) + .map_err(|(err, _)| err)?; let deposit = module.open_deposit(); if let Some(storage_deposit_limit) = storage_deposit_limit { ensure!(storage_deposit_limit >= deposit, >::StorageDepositLimitExhausted); @@ -1067,6 +1080,7 @@ where storage_deposit_limit: Option>, data: Vec, debug_message: Option<&mut Vec>, + determinism: Determinism, ) -> InternalCallOutput { let mut gas_meter = GasMeter::new(gas_limit); let mut storage_meter = match StorageMeter::new(&origin, storage_deposit_limit, value) { @@ -1088,6 +1102,7 @@ where value, data, debug_message, + determinism, ); InternalCallOutput { result, @@ -1115,11 +1130,16 @@ where let schedule = T::Schedule::get(); let (extra_deposit, executable) = match code { Code::Upload(binary) => { - let executable = PrefabWasmModule::from_code(binary, &schedule, origin.clone()) - .map_err(|(err, msg)| { - debug_message.as_mut().map(|buffer| buffer.extend(msg.as_bytes())); - err - })?; + let executable = PrefabWasmModule::from_code( + binary, + &schedule, + origin.clone(), + Determinism::Deterministic, + ) + .map_err(|(err, msg)| { + debug_message.as_mut().map(|buffer| buffer.extend(msg.as_bytes())); + err + })?; // The open deposit will be charged during execution when the // uploaded module does not already exist. This deposit is not part of the // storage meter because it is not transferred to the contract but @@ -1218,6 +1238,7 @@ sp_api::decl_runtime_apis! { origin: AccountId, code: Vec, storage_deposit_limit: Option, + determinism: Determinism, ) -> CodeUploadResult; /// Query a given storage key in a given contract. diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 5ea821aac7682..aa04d8b9b1084 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -32,65 +32,54 @@ use sp_std::{marker::PhantomData, prelude::*}; pub struct Migration(PhantomData); impl OnRuntimeUpgrade for Migration { fn on_runtime_upgrade() -> Weight { - let version = StorageVersion::get::>(); + let version = >::on_chain_storage_version(); let mut weight = Weight::zero(); if version < 4 { - weight = weight.saturating_add(v4::migrate::()); - StorageVersion::new(4).put::>(); + v4::migrate::(&mut weight); } if version < 5 { - weight = weight.saturating_add(v5::migrate::()); - StorageVersion::new(5).put::>(); + v5::migrate::(&mut weight); } if version < 6 { - weight = weight.saturating_add(v6::migrate::()); - StorageVersion::new(6).put::>(); + v6::migrate::(&mut weight); } if version < 7 { - weight = weight.saturating_add(v7::migrate::()); - StorageVersion::new(7).put::>(); + v7::migrate::(&mut weight); } if version < 8 { - weight = weight.saturating_add(v8::migrate::()); - StorageVersion::new(8).put::>(); + v8::migrate::(&mut weight); } + if version < 9 { + v9::migrate::(&mut weight); + } + + StorageVersion::new(9).put::>(); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + weight } #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { - let version = StorageVersion::get::>(); - - if version < 7 { - return Ok(vec![]) - } + let version = >::on_chain_storage_version(); - if version < 8 { + if version == 8 { v8::pre_upgrade::()?; } - Ok(vec![]) + Ok(version.encode()) } #[cfg(feature = "try-runtime")] - fn post_upgrade(_state: Vec) -> Result<(), &'static str> { - let version = StorageVersion::get::>(); - - if version < 7 { - return Ok(()) - } - - if version < 8 { - v8::post_upgrade::()?; - } - - Ok(()) + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let version = Decode::decode(&mut state.as_ref()).map_err(|_| "Cannot decode version")?; + post_checks::post_upgrade::(version) } } @@ -98,10 +87,10 @@ impl OnRuntimeUpgrade for Migration { mod v4 { use super::*; - pub fn migrate() -> Weight { + pub fn migrate(weight: &mut Weight) { #[allow(deprecated)] migration::remove_storage_prefix(>::name().as_bytes(), b"CurrentSchedule", b""); - T::DbWeight::get().writes(1) + weight.saturating_accrue(T::DbWeight::get().writes(1)); } } @@ -169,11 +158,9 @@ mod v5 { #[storage_alias] type DeletionQueue = StorageValue, Vec>; - pub fn migrate() -> Weight { - let mut weight = Weight::zero(); - + pub fn migrate(weight: &mut Weight) { >::translate(|_key, old: OldContractInfo| { - weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); match old { OldContractInfo::Alive(old) => Some(ContractInfo:: { trie_id: old.trie_id, @@ -185,12 +172,10 @@ mod v5 { }); DeletionQueue::::translate(|old: Option>| { - weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); old.map(|old| old.into_iter().map(|o| DeletedContract { trie_id: o.trie_id }).collect()) }) .ok(); - - weight } } @@ -214,14 +199,14 @@ mod v6 { } #[derive(Encode, Decode)] - struct PrefabWasmModule { + pub struct PrefabWasmModule { #[codec(compact)] - instruction_weights_version: u32, + pub instruction_weights_version: u32, #[codec(compact)] - initial: u32, + pub initial: u32, #[codec(compact)] - maximum: u32, - code: Vec, + pub maximum: u32, + pub code: Vec, } use v5::ContractInfo as OldContractInfo; @@ -258,11 +243,9 @@ mod v6 { #[storage_alias] type OwnerInfoOf = StorageMap, Identity, CodeHash, OwnerInfo>; - pub fn migrate() -> Weight { - let mut weight = Weight::zero(); - + pub fn migrate(weight: &mut Weight) { >::translate(|_key, old: OldContractInfo| { - weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); Some(ContractInfo:: { trie_id: old.trie_id, code_hash: old.code_hash, @@ -274,7 +257,7 @@ mod v6 { .expect("Infinite input; no dead input space; qed"); >::translate(|key, old: OldPrefabWasmModule| { - weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); >::insert( key, OwnerInfo { @@ -290,8 +273,6 @@ mod v6 { code: old.code, }) }); - - weight } } @@ -299,14 +280,14 @@ mod v6 { mod v7 { use super::*; - pub fn migrate() -> Weight { + pub fn migrate(weight: &mut Weight) { #[storage_alias] type AccountCounter = StorageValue, u64, ValueQuery>; #[storage_alias] type Nonce = StorageValue, u64, ValueQuery>; Nonce::::set(AccountCounter::::take()); - T::DbWeight::get().reads_writes(1, 2) + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)) } } @@ -317,23 +298,21 @@ mod v8 { use v6::ContractInfo as OldContractInfo; #[derive(Encode, Decode)] - struct ContractInfo { - trie_id: TrieId, - code_hash: CodeHash, - storage_bytes: u32, - storage_items: u32, - storage_byte_deposit: BalanceOf, - storage_item_deposit: BalanceOf, - storage_base_deposit: BalanceOf, + pub struct ContractInfo { + pub trie_id: TrieId, + pub code_hash: CodeHash, + pub storage_bytes: u32, + pub storage_items: u32, + pub storage_byte_deposit: BalanceOf, + pub storage_item_deposit: BalanceOf, + pub storage_base_deposit: BalanceOf, } #[storage_alias] type ContractInfoOf = StorageMap, Twox64Concat, ::AccountId, V>; - pub fn migrate() -> Weight { - let mut weight = Weight::zero(); - + pub fn migrate(weight: &mut Weight) { >>::translate_values(|old: OldContractInfo| { // Count storage items of this contract let mut storage_bytes = 0u32; @@ -359,8 +338,9 @@ mod v8 { // Reads: One read for each storage item plus the contract info itself. // Writes: Only the new contract info. - weight = weight - .saturating_add(T::DbWeight::get().reads_writes(u64::from(storage_items) + 1, 1)); + weight.saturating_accrue( + T::DbWeight::get().reads_writes(u64::from(storage_items) + 1, 1), + ); Some(ContractInfo { trie_id: old.trie_id, @@ -372,8 +352,6 @@ mod v8 { storage_base_deposit, }) }); - - weight } #[cfg(feature = "try-runtime")] @@ -385,9 +363,78 @@ mod v8 { } Ok(()) } +} - #[cfg(feature = "try-runtime")] - pub fn post_upgrade() -> Result<(), &'static str> { +/// Update `CodeStorage` with the new `determinism` field. +mod v9 { + use super::*; + use crate::Determinism; + use v6::PrefabWasmModule as OldPrefabWasmModule; + + #[derive(Encode, Decode)] + pub struct PrefabWasmModule { + #[codec(compact)] + pub instruction_weights_version: u32, + #[codec(compact)] + pub initial: u32, + #[codec(compact)] + pub maximum: u32, + pub code: Vec, + pub determinism: Determinism, + } + + #[storage_alias] + type CodeStorage = StorageMap, Identity, CodeHash, PrefabWasmModule>; + + pub fn migrate(weight: &mut Weight) { + >::translate_values(|old: OldPrefabWasmModule| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(PrefabWasmModule { + instruction_weights_version: old.instruction_weights_version, + initial: old.initial, + maximum: old.maximum, + code: old.code, + determinism: Determinism::Deterministic, + }) + }); + } +} + +// Post checks always need to be run against the latest storage version. This is why we +// do not scope them in the per version modules. They always need to be ported to the latest +// version. +#[cfg(feature = "try-runtime")] +mod post_checks { + use super::*; + use crate::Determinism; + use sp_io::default_child_storage as child; + use v8::ContractInfo; + use v9::PrefabWasmModule; + + #[storage_alias] + type CodeStorage = StorageMap, Identity, CodeHash, PrefabWasmModule>; + + #[storage_alias] + type ContractInfoOf = + StorageMap, Twox64Concat, ::AccountId, V>; + + pub fn post_upgrade(old_version: StorageVersion) -> Result<(), &'static str> { + if old_version < 7 { + return Ok(()) + } + + if old_version < 8 { + v8::()?; + } + + if old_version < 9 { + v9::()?; + } + + Ok(()) + } + + fn v8() -> Result<(), &'static str> { use frame_support::traits::ReservableCurrency; for (key, value) in ContractInfoOf::>::iter() { let reserved = T::Currency::reserved_balance(&key); @@ -413,4 +460,14 @@ mod v8 { } Ok(()) } + + fn v9() -> Result<(), &'static str> { + for value in CodeStorage::::iter_values() { + ensure!( + value.determinism == Determinism::Deterministic, + "All pre-existing codes need to be deterministic." + ); + } + Ok(()) + } } diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 790b74106860a..535517e756c61 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -18,7 +18,7 @@ //! This module contains the cost schedule and supporting code that constructs a //! sane default schedule from a `WeightInfo` implementation. -use crate::{weights::WeightInfo, Config}; +use crate::{wasm::Determinism, weights::WeightInfo, Config}; use codec::{Decode, Encode}; use frame_support::DefaultNoBound; @@ -193,6 +193,13 @@ pub struct InstructionWeights { /// Changes to other parts of the schedule should not increment the version in /// order to avoid unnecessary re-instrumentations. pub version: u32, + /// Weight to be used for instructions which don't have benchmarks assigned. + /// + /// This weight is used whenever a code is uploaded with [`Determinism::AllowIndeterminism`] + /// and an instruction (usually a float instruction) is encountered. This weight is **not** + /// used if a contract is uploaded with [`Determinism::Deterministic`]. If this field is set to + /// `0` (the default) only deterministic codes are allowed to be uploaded. + pub fallback: u32, pub i64const: u32, pub i64load: u32, pub i64store: u32, @@ -526,6 +533,7 @@ impl Default for InstructionWeights { let max_pages = Limits::default().memory_pages; Self { version: 3, + fallback: 0, i64const: cost_instr!(instr_i64const, 1), i64load: cost_instr!(instr_i64load, 2), i64store: cost_instr!(instr_i64store, 2), @@ -659,10 +667,15 @@ impl Default for HostFnWeights { struct ScheduleRules<'a, T: Config> { schedule: &'a Schedule, params: Vec, + determinism: Determinism, } impl Schedule { - pub(crate) fn rules(&self, module: &elements::Module) -> impl gas_metering::Rules + '_ { + pub(crate) fn rules( + &self, + module: &elements::Module, + determinism: Determinism, + ) -> impl gas_metering::Rules + '_ { ScheduleRules { schedule: self, params: module @@ -674,6 +687,7 @@ impl Schedule { func.params().len() as u32 }) .collect(), + determinism, } } } @@ -756,7 +770,10 @@ impl<'a, T: Config> gas_metering::Rules for ScheduleRules<'a, T> { I32Rotr | I64Rotr => w.i64rotr, // Returning None makes the gas instrumentation fail which we intend for - // unsupported or unknown instructions. + // unsupported or unknown instructions. Offchain we might allow indeterminism and hence + // use the fallback weight for those instructions. + _ if matches!(self.determinism, Determinism::AllowIndeterminism) && w.fallback > 0 => + w.fallback, _ => return None, }; Some(weight) diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 6a2144840143a..bc2ee31681d7f 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -24,7 +24,7 @@ use crate::{ exec::{FixSizedKey, Frame}, storage::Storage, tests::test_utils::{get_contract, get_contract_checked}, - wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode}, + wasm::{Determinism, PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, DeletionQueue, Error, Pallet, Schedule, @@ -340,6 +340,7 @@ parameter_types! { // We want stack height to be always enabled for tests so that this // instrumentation path is always tested implicitly. schedule.limits.stack_height = Some(512); + schedule.instruction_weights.fallback = 1; schedule }; pub static DepositPerByte: BalanceOf = 1; @@ -522,7 +523,12 @@ fn instantiate_and_call_and_deposit_event() { // We determine the storage deposit limit after uploading because it depends on ALICEs free // balance which is changed by uploading a module. - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, None)); + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm, + None, + Determinism::Deterministic + )); // Drop previous events initialize_block(2); @@ -690,7 +696,13 @@ fn instantiate_unique_trie_id() { ExtBuilder::default().existential_deposit(500).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); - Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, None).unwrap(); + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm, + None, + Determinism::Deterministic, + ) + .unwrap(); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Instantiate the contract and store its trie id for later comparison. @@ -940,6 +952,7 @@ fn delegate_call() { RuntimeOrigin::signed(ALICE), callee_wasm, Some(codec::Compact(100_000)), + Determinism::Deterministic, )); assert_ok!(Contracts::call( @@ -1376,10 +1389,18 @@ fn crypto_hashes() { // We offset data in the contract tables by 1. let mut params = vec![(n + 1) as u8]; params.extend_from_slice(input); - let result = - >::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, params, false) - .result - .unwrap(); + let result = >::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + params, + false, + Determinism::Deterministic, + ) + .result + .unwrap(); assert!(!result.did_revert()); let expected = hash_fn(input.as_ref()); assert_eq!(&result.data[..*expected_size], &*expected); @@ -1407,9 +1428,18 @@ fn transfer_return_code() { // Contract has only the minimal balance so any transfer will fail. Balances::make_free_balance_be(&addr, min_balance); - let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![], false) - .result - .unwrap(); + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![], + false, + Determinism::Deterministic, + ) + .result + .unwrap(); assert_return_code!(result, RuntimeReturnCode::TransferFailed); // Contract has enough total balance in order to not go below the min balance @@ -1417,9 +1447,18 @@ fn transfer_return_code() { // the transfer still fails. Balances::make_free_balance_be(&addr, min_balance + 100); Balances::reserve(&addr, min_balance + 100).unwrap(); - let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, None, vec![], false) - .result - .unwrap(); + let result = Contracts::bare_call( + ALICE, + addr, + 0, + GAS_LIMIT, + None, + vec![], + false, + Determinism::Deterministic, + ) + .result + .unwrap(); assert_return_code!(result, RuntimeReturnCode::TransferFailed); }); } @@ -1454,6 +1493,7 @@ fn call_return_code() { None, AsRef::<[u8]>::as_ref(&DJANGO).to_vec(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1484,6 +1524,7 @@ fn call_return_code() { .cloned() .collect(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1506,6 +1547,7 @@ fn call_return_code() { .cloned() .collect(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1525,6 +1567,7 @@ fn call_return_code() { .cloned() .collect(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1543,6 +1586,7 @@ fn call_return_code() { .cloned() .collect(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1591,6 +1635,7 @@ fn instantiate_return_code() { None, callee_hash.clone(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1609,6 +1654,7 @@ fn instantiate_return_code() { None, callee_hash.clone(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1616,10 +1662,18 @@ fn instantiate_return_code() { // Contract has enough balance but the passed code hash is invalid Balances::make_free_balance_be(&addr, min_balance + 10_000); - let result = - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![0; 33], false) - .result - .unwrap(); + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![0; 33], + false, + Determinism::Deterministic, + ) + .result + .unwrap(); assert_return_code!(result, RuntimeReturnCode::CodeNotFound); // Contract has enough balance but callee reverts because "1" is passed. @@ -1631,6 +1685,7 @@ fn instantiate_return_code() { None, callee_hash.iter().chain(&1u32.to_le_bytes()).cloned().collect(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1645,6 +1700,7 @@ fn instantiate_return_code() { None, callee_hash.iter().chain(&2u32.to_le_bytes()).cloned().collect(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1717,8 +1773,16 @@ fn chain_extension_works() { // 0 = read input buffer and pass it through as output let input: Vec = ExtensionInput { extension_id: 0, func_id: 0, extra: &[99] }.into(); - let result = - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false); + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + input.clone(), + false, + Determinism::Deterministic, + ); assert_eq!(TestExtension::last_seen_buffer(), input); assert_eq!(result.result.unwrap().data, input); @@ -1731,6 +1795,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1746,6 +1811,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 0, func_id: 2, extra: &[0] }.into(), false, + Determinism::Deterministic, ); assert_ok!(result.result); let gas_consumed = result.gas_consumed; @@ -1757,6 +1823,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 0, func_id: 2, extra: &[42] }.into(), false, + Determinism::Deterministic, ); assert_ok!(result.result); assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 42); @@ -1768,6 +1835,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 0, func_id: 2, extra: &[95] }.into(), false, + Determinism::Deterministic, ); assert_ok!(result.result); assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 95); @@ -1781,6 +1849,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1798,6 +1867,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 1, func_id: 0, extra: &[] }.into(), false, + Determinism::Deterministic, ) .result .unwrap(); @@ -1847,8 +1917,17 @@ fn chain_extension_temp_storage_works() { ); assert_ok!( - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false) - .result + Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + input.clone(), + false, + Determinism::Deterministic + ) + .result ); }) } @@ -2387,12 +2466,28 @@ fn reinstrument_does_charge() { // Call the contract two times without reinstrument - let result0 = - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); + let result0 = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + zero.clone(), + false, + Determinism::Deterministic, + ); assert!(!result0.result.unwrap().did_revert()); - let result1 = - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); + let result1 = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + zero.clone(), + false, + Determinism::Deterministic, + ); assert!(!result1.result.unwrap().did_revert()); // They should match because both where called with the same schedule. @@ -2405,8 +2500,16 @@ fn reinstrument_does_charge() { }); // This call should trigger reinstrumentation - let result2 = - Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); + let result2 = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + zero.clone(), + false, + Determinism::Deterministic, + ); assert!(!result2.result.unwrap().did_revert()); assert!(result2.gas_consumed.ref_time() > result1.gas_consumed.ref_time()); assert_eq!( @@ -2433,7 +2536,16 @@ fn debug_message_works() { vec![], ),); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, None, vec![], true); + let result = Contracts::bare_call( + ALICE, + addr, + 0, + GAS_LIMIT, + None, + vec![], + true, + Determinism::Deterministic, + ); assert_matches!(result.result, Ok(_)); assert_eq!(std::str::from_utf8(&result.debug_message).unwrap(), "Hello World!"); @@ -2457,7 +2569,16 @@ fn debug_message_logging_disabled() { ),); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // disable logging by passing `false` - let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![], false); + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![], + false, + Determinism::Deterministic, + ); assert_matches!(result.result, Ok(_)); // the dispatchables always run without debugging assert_ok!(Contracts::call(RuntimeOrigin::signed(ALICE), addr, 0, GAS_LIMIT, None, vec![])); @@ -2481,7 +2602,16 @@ fn debug_message_invalid_utf8() { vec![], ),); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, None, vec![], true); + let result = Contracts::bare_call( + ALICE, + addr, + 0, + GAS_LIMIT, + None, + vec![], + true, + Determinism::Deterministic, + ); assert_err!(result.result, >::DebugMessageInvalidUTF8); }); } @@ -2532,6 +2662,7 @@ fn gas_estimation_nested_call_fixed_limit() { None, input.clone(), false, + Determinism::Deterministic, ); assert_ok!(&result.result); @@ -2548,6 +2679,7 @@ fn gas_estimation_nested_call_fixed_limit() { Some(result.storage_deposit.charge_or_zero()), input, false, + Determinism::Deterministic, ) .result ); @@ -2604,6 +2736,7 @@ fn gas_estimation_call_runtime() { None, call.encode(), false, + Determinism::Deterministic, ); // contract encodes the result of the dispatch runtime let outcome = u32::decode(&mut result.result.unwrap().data.as_ref()).unwrap(); @@ -2620,6 +2753,7 @@ fn gas_estimation_call_runtime() { None, call.encode(), false, + Determinism::Deterministic, ) .result ); @@ -2668,10 +2802,18 @@ fn ecdsa_recover() { params.extend_from_slice(&signature); params.extend_from_slice(&message_hash); assert!(params.len() == 65 + 32); - let result = - >::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, params, false) - .result - .unwrap(); + let result = >::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + params, + false, + Determinism::Deterministic, + ) + .result + .unwrap(); assert!(!result.did_revert()); assert_eq!(result.data, EXPECTED_COMPRESSED_PUBLIC_KEY); }) @@ -2691,7 +2833,8 @@ fn upload_code_works() { assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), wasm, - Some(codec::Compact(1_000)) + Some(codec::Compact(1_000)), + Determinism::Deterministic, )); assert!(>::contains_key(code_hash)); @@ -2702,7 +2845,7 @@ fn upload_code_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 240, + amount: 241, }), topics: vec![], }, @@ -2727,7 +2870,12 @@ fn upload_code_limit_too_low() { initialize_block(2); assert_noop!( - Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(100))), + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm, + Some(codec::Compact(100)), + Determinism::Deterministic + ), >::StorageDepositLimitExhausted, ); @@ -2746,7 +2894,12 @@ fn upload_code_not_enough_balance() { initialize_block(2); assert_noop!( - Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000))), + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm, + Some(codec::Compact(1_000)), + Determinism::Deterministic + ), >::StorageDepositNotEnoughFunds, ); @@ -2767,7 +2920,8 @@ fn remove_code_works() { assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), wasm, - Some(codec::Compact(1_000)) + Some(codec::Compact(1_000)), + Determinism::Deterministic, )); assert!(>::contains_key(code_hash)); @@ -2781,7 +2935,7 @@ fn remove_code_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 240, + amount: 241, }), topics: vec![], }, @@ -2794,7 +2948,7 @@ fn remove_code_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Unreserved { who: ALICE, - amount: 240, + amount: 241, }), topics: vec![], }, @@ -2821,7 +2975,8 @@ fn remove_code_wrong_origin() { assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), wasm, - Some(codec::Compact(1_000)) + Some(codec::Compact(1_000)), + Determinism::Deterministic, )); assert_noop!( @@ -2836,7 +2991,7 @@ fn remove_code_wrong_origin() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 240, + amount: 241, }), topics: vec![], }, @@ -2969,7 +3124,7 @@ fn instantiate_with_zero_balance_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 240, + amount: 241, }), topics: vec![], }, @@ -3071,7 +3226,7 @@ fn instantiate_with_below_existential_deposit_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 240, + amount: 241, }), topics: vec![], }, @@ -3261,7 +3416,12 @@ fn set_code_extrinsic() { )); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), new_wasm, None,)); + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + new_wasm, + None, + Determinism::Deterministic + )); // Drop previous events initialize_block(2); @@ -3457,7 +3617,12 @@ fn contract_reverted() { let input = (flags.bits(), buffer).encode(); // We just upload the code for later use - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm.clone(), None)); + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm.clone(), + None, + Determinism::Deterministic + )); // Calling extrinsic: revert leads to an error assert_err_ignore_postinfo!( @@ -3536,9 +3701,18 @@ fn contract_reverted() { ); // Calling directly: revert leads to success but the flags indicate the error - let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input, false) - .result - .unwrap(); + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + input, + false, + Determinism::Deterministic, + ) + .result + .unwrap(); assert_eq!(result.flags, flags); assert_eq!(result.data, buffer); }); @@ -3551,7 +3725,12 @@ fn code_rejected_error_works() { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_noop!( - Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm.clone(), None), + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm.clone(), + None, + Determinism::Deterministic + ), >::CodeRejected, ); @@ -3594,7 +3773,12 @@ fn set_code_hash() { vec![], )); // upload new code - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), new_wasm.clone(), None)); + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + new_wasm.clone(), + None, + Determinism::Deterministic + )); System::reset_events(); @@ -3607,16 +3791,25 @@ fn set_code_hash() { None, new_code_hash.as_ref().to_vec(), true, + Determinism::Deterministic, ) .result .unwrap(); assert_return_code!(result, 1); // Second calls new contract code that returns 2 - let result = - Contracts::bare_call(ALICE, contract_addr.clone(), 0, GAS_LIMIT, None, vec![], true) - .result - .unwrap(); + let result = Contracts::bare_call( + ALICE, + contract_addr.clone(), + 0, + GAS_LIMIT, + None, + vec![], + true, + Determinism::Deterministic, + ) + .result + .unwrap(); assert_return_code!(result, 2); // Checking for the last event only @@ -3950,3 +4143,243 @@ fn deposit_limit_honors_min_leftover() { assert_eq!(Balances::free_balance(&BOB), 1_000); }); } + +#[test] +fn cannot_instantiate_indeterministic_code() { + let (wasm, code_hash) = compile_module::("float_instruction").unwrap(); + let (caller_wasm, _) = compile_module::("instantiate_return_code").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Try to instantiate directly from code + assert_err_ignore_postinfo!( + Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm.clone(), + vec![], + vec![], + ), + >::CodeRejected, + ); + assert_err!( + Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(wasm.clone()), + vec![], + vec![], + false, + ) + .result, + >::CodeRejected, + ); + + // Try to upload a non deterministic code as deterministic + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm.clone(), + None, + Determinism::Deterministic + ), + >::CodeRejected, + ); + + // Try to instantiate from already stored indeterministic code hash + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm, + None, + Determinism::AllowIndeterminism, + )); + assert_err_ignore_postinfo!( + Contracts::instantiate( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + code_hash, + vec![], + vec![], + ), + >::Indeterministic, + ); + assert_err!( + Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Existing(code_hash), + vec![], + vec![], + false, + ) + .result, + >::Indeterministic, + ); + + // Deploy contract which instantiates another contract + let addr = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(caller_wasm), + vec![], + vec![], + false, + ) + .result + .unwrap() + .account_id; + + // Try to instantiate `code_hash` from another contract in deterministic mode + assert_err!( + >::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + code_hash.encode(), + false, + Determinism::Deterministic, + ) + .result, + >::Indeterministic, + ); + + // Instantiations are not allowed even in non determinism mode + assert_err!( + >::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + code_hash.encode(), + false, + Determinism::AllowIndeterminism, + ) + .result, + >::Indeterministic, + ); + }); +} + +#[test] +fn cannot_set_code_indeterministic_code() { + let (wasm, code_hash) = compile_module::("float_instruction").unwrap(); + let (caller_wasm, _) = compile_module::("set_code_hash").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Put the non deterministic contract on-chain + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm, + None, + Determinism::AllowIndeterminism, + )); + + // Create the contract that will call `seal_set_code_hash` + let caller_addr = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(caller_wasm), + vec![], + vec![], + false, + ) + .result + .unwrap() + .account_id; + + // We do not allow to set the code hash to a non determinstic wasm + assert_err!( + >::bare_call( + ALICE, + caller_addr.clone(), + 0, + GAS_LIMIT, + None, + code_hash.encode(), + false, + Determinism::AllowIndeterminism, + ) + .result, + >::Indeterministic, + ); + }); +} + +#[test] +fn delegate_call_indeterministic_code() { + let (wasm, code_hash) = compile_module::("float_instruction").unwrap(); + let (caller_wasm, _) = compile_module::("delegate_call_simple").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Put the non deterministic contract on-chain + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm, + None, + Determinism::AllowIndeterminism, + )); + + // Create the contract that will call `seal_delegate_call` + let caller_addr = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(caller_wasm), + vec![], + vec![], + false, + ) + .result + .unwrap() + .account_id; + + // The delegate call will fail in deterministic mode + assert_err!( + >::bare_call( + ALICE, + caller_addr.clone(), + 0, + GAS_LIMIT, + None, + code_hash.encode(), + false, + Determinism::Deterministic, + ) + .result, + >::Indeterministic, + ); + + // The delegate call will work on non deterministic mode + assert_ok!( + >::bare_call( + ALICE, + caller_addr.clone(), + 0, + GAS_LIMIT, + None, + code_hash.encode(), + false, + Determinism::AllowIndeterminism, + ) + .result + ); + }); +} diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 09e51d981360b..3ede6db6db5a1 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -201,7 +201,7 @@ pub fn reinstrument( // as the contract is already deployed and every change in size would be the result // of changes in the instrumentation algorithm controlled by the chain authors. prefab_module.code = WeakBoundedVec::force_from( - prepare::reinstrument_contract::(&original_code, schedule) + prepare::reinstrument_contract::(&original_code, schedule, prefab_module.determinism) .map_err(|_| >::CodeRejected)?, Some("Contract exceeds limit after re-instrumentation."), ); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index b341ae3bd155d..053729730e679 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -37,6 +37,7 @@ use crate::{ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::dispatch::{DispatchError, DispatchResult}; use sp_core::crypto::UncheckedFrom; +use sp_runtime::RuntimeDebug; use sp_sandbox::{SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory}; use sp_std::prelude::*; #[cfg(test)] @@ -66,6 +67,10 @@ pub struct PrefabWasmModule { maximum: u32, /// Code instrumented with the latest schedule. code: RelaxedCodeVec, + /// A code that might contain non deterministic features and is therefore never allowed + /// to be run on chain. Specifically this code can never be instantiated into a contract + /// and can just be used through a delegate call. + determinism: Determinism, /// The uninstrumented, pristine version of the code. /// /// It is not stored because the pristine code has its own storage item. The value @@ -102,6 +107,27 @@ pub struct OwnerInfo { refcount: u64, } +/// Defines the required determinism level of a wasm blob when either running or uploading code. +#[derive( + Clone, Copy, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen, RuntimeDebug, PartialEq, Eq, +)] +pub enum Determinism { + /// The execution should be deterministic and hence no indeterministic instructions are + /// allowed. + /// + /// Dispatchables always use this mode in order to make on-chain execution deterministic. + Deterministic, + /// Allow calling or uploading an indeterministic code. + /// + /// This is only possible when calling into `pallet-contracts` directly via + /// [`crate::Pallet::bare_call`]. + /// + /// # Note + /// + /// **Never** use this mode for on-chain execution. + AllowIndeterminism, +} + impl ExportedFunction { /// The wasm export name for the function. fn identifier(&self) -> &str { @@ -124,11 +150,13 @@ where original_code: Vec, schedule: &Schedule, owner: AccountIdOf, + determinism: Determinism, ) -> Result { let module = prepare::prepare_contract( original_code.try_into().map_err(|_| (>::CodeTooLarge.into(), ""))?, schedule, owner, + determinism, )?; Ok(module) } @@ -258,6 +286,10 @@ where fn code_len(&self) -> u32 { self.code.len() as u32 } + + fn is_deterministic(&self) -> bool { + matches!(self.determinism, Determinism::Deterministic) + } } #[cfg(test)] @@ -551,8 +583,13 @@ mod tests { fn execute>(wat: &str, input_data: Vec, mut ext: E) -> ExecResult { let wasm = wat::parse_str(wat).unwrap(); let schedule = crate::Schedule::default(); - let executable = - PrefabWasmModule::<::T>::from_code(wasm, &schedule, ALICE).unwrap(); + let executable = PrefabWasmModule::<::T>::from_code( + wasm, + &schedule, + ALICE, + Determinism::Deterministic, + ) + .unwrap(); executable.execute(ext.borrow_mut(), &ExportedFunction::Call, input_data) } diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index e8873f604c9c7..3e6b9eee96680 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -22,7 +22,7 @@ use crate::{ chain_extension::ChainExtension, storage::meter::Diff, - wasm::{env_def::ImportSatisfyCheck, OwnerInfo, PrefabWasmModule}, + wasm::{env_def::ImportSatisfyCheck, Determinism, OwnerInfo, PrefabWasmModule}, AccountIdOf, CodeVec, Config, Error, Schedule, }; use codec::{Encode, MaxEncodedLen}; @@ -182,8 +182,8 @@ impl<'a, T: Config> ContractModule<'a, T> { Ok(()) } - fn inject_gas_metering(self) -> Result { - let gas_rules = self.schedule.rules(&self.module); + fn inject_gas_metering(self, determinism: Determinism) -> Result { + let gas_rules = self.schedule.rules(&self.module, determinism); let contract_module = wasm_instrument::gas_metering::inject(self.module, &gas_rules, "seal0") .map_err(|_| "gas instrumentation failed")?; @@ -369,6 +369,7 @@ fn get_memory_limits( fn check_and_instrument( original_code: &[u8], schedule: &Schedule, + determinism: Determinism, ) -> Result<(Vec, (u32, u32)), &'static str> { let result = (|| { let contract_module = ContractModule::new(original_code, schedule)?; @@ -376,17 +377,20 @@ fn check_and_instrument( contract_module.ensure_no_internal_memory()?; contract_module.ensure_table_size_limit(schedule.limits.table_size)?; contract_module.ensure_global_variable_limit(schedule.limits.globals)?; - contract_module.ensure_no_floating_types()?; contract_module.ensure_parameter_limit(schedule.limits.parameters)?; contract_module.ensure_br_table_size_limit(schedule.limits.br_table_size)?; + if matches!(determinism, Determinism::Deterministic) { + contract_module.ensure_no_floating_types()?; + } + // We disallow importing `gas` function here since it is treated as implementation detail. let disallowed_imports = [b"gas".as_ref()]; let memory_limits = get_memory_limits(contract_module.scan_imports::(&disallowed_imports)?, schedule)?; let code = contract_module - .inject_gas_metering()? + .inject_gas_metering(determinism)? .inject_stack_height_metering()? .into_wasm_code()?; @@ -404,9 +408,11 @@ fn do_preparation( original_code: CodeVec, schedule: &Schedule, owner: AccountIdOf, + determinism: Determinism, ) -> Result, (DispatchError, &'static str)> { - let (code, (initial, maximum)) = check_and_instrument::(original_code.as_ref(), schedule) - .map_err(|msg| (>::CodeRejected.into(), msg))?; + let (code, (initial, maximum)) = + check_and_instrument::(original_code.as_ref(), schedule, determinism) + .map_err(|msg| (>::CodeRejected.into(), msg))?; let original_code_len = original_code.len(); let mut module = PrefabWasmModule { @@ -414,6 +420,7 @@ fn do_preparation( initial, maximum, code: code.try_into().map_err(|_| (>::CodeTooLarge.into(), ""))?, + determinism, code_hash: T::Hashing::hash(&original_code), original_code: Some(original_code), owner_info: None, @@ -449,8 +456,9 @@ pub fn prepare_contract( original_code: CodeVec, schedule: &Schedule, owner: AccountIdOf, + determinism: Determinism, ) -> Result, (DispatchError, &'static str)> { - do_preparation::(original_code, schedule, owner) + do_preparation::(original_code, schedule, owner, determinism) } /// The same as [`prepare_contract`] but without constructing a new [`PrefabWasmModule`] @@ -461,8 +469,9 @@ pub fn prepare_contract( pub fn reinstrument_contract( original_code: &[u8], schedule: &Schedule, + determinism: Determinism, ) -> Result, &'static str> { - Ok(check_and_instrument::(original_code, schedule)?.0) + Ok(check_and_instrument::(original_code, schedule, determinism)?.0) } /// Alternate (possibly unsafe) preparation functions used only for benchmarking. @@ -495,6 +504,7 @@ pub mod benchmarking { maximum: memory_limits.1, code_hash: T::Hashing::hash(&original_code), original_code: Some(original_code.try_into().map_err(|_| "Original code too large")?), + determinism: Determinism::Deterministic, code: contract_module .into_wasm_code()? .try_into() @@ -572,7 +582,7 @@ mod tests { }, .. Default::default() }; - let r = do_preparation::(wasm, &schedule, ALICE); + let r = do_preparation::(wasm, &schedule, ALICE, Determinism::Deterministic); assert_matches::assert_matches!(r.map_err(|(_, msg)| msg), $($expected)*); } }; diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 6d7e6bcf69e5f..281cc30c4f053 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -2384,6 +2384,7 @@ pub mod env { /// 2. Contracts using this API can't be assumed as having deterministic addresses. Said another /// way, when using this API you lose the guarantee that an address always identifies a specific /// code hash. + /// /// 3. If a contract calls into itself after changing its code the new call would use /// the new code. However, if the original caller panics after returning from the sub call it /// would revert the changes made by `seal_set_code_hash` and the next caller would use From 3d6043afca80941bf05ca5681c6e9bbdff1e80ad Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 24 Oct 2022 19:55:25 +0200 Subject: [PATCH 1306/1472] Normalize keystore type and its usage across tests (#12553) * Normalize keystore type and usage across tests * Extract peer index from array index --- Cargo.lock | 3 +- client/beefy/src/tests.rs | 4 +-- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/src/tests.rs | 48 ++++++++++++++-------------- client/finality-grandpa/Cargo.toml | 6 +--- client/finality-grandpa/src/tests.rs | 38 +++++++--------------- 6 files changed, 41 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 397846693e907..6a5b562d0a791 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7846,6 +7846,7 @@ dependencies = [ "sp-core", "sp-inherents", "sp-io", + "sp-keyring", "sp-keystore", "sp-runtime", "sp-timestamp", @@ -7853,7 +7854,6 @@ dependencies = [ "sp-version", "substrate-prometheus-endpoint", "substrate-test-runtime-client", - "tempfile", "thiserror", ] @@ -8130,7 +8130,6 @@ dependencies = [ "sp-tracing", "substrate-prometheus-endpoint", "substrate-test-runtime-client", - "tempfile", "thiserror", "tokio", ] diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index d280e4f08a531..f0647d7b142e6 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -29,12 +29,12 @@ use sc_consensus::{ BlockImport, BlockImportParams, BoxJustificationImport, ForkChoiceStrategy, ImportResult, ImportedAux, }; -use sc_keystore::LocalKeystore; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, PeersFullClient, TestNetFactory, }; use sc_utils::notification::NotificationReceiver; +use sp_keystore::testing::KeyStore as TestKeystore; use beefy_primitives::{ crypto::{AuthorityId, Signature}, @@ -333,7 +333,7 @@ pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { } pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> SyncCryptoStorePtr { - let keystore = Arc::new(LocalKeystore::in_memory()); + let keystore = Arc::new(TestKeystore::new()); SyncCryptoStore::ecdsa_generate_new(&*keystore, BeefyKeyType, Some(&authority.to_seed())) .expect("Creates authority key"); keystore diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index e559ec165a793..54da2d6e49e39 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -54,8 +54,8 @@ sp-version = { version = "5.0.0", path = "../../../primitives/version" } [dev-dependencies] rand_chacha = "0.2.2" -tempfile = "3.1.0" sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } +sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 24185dbce6795..abffcb0a2b4c3 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -28,7 +28,6 @@ use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; use sc_client_api::{backend::TransactionFor, BlockchainEvents, Finalizer}; use sc_consensus::{BoxBlockImport, BoxJustificationImport}; use sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging; -use sc_keystore::LocalKeystore; use sc_network_test::{Block as TestBlock, *}; use sp_application_crypto::key_types::BABE; use sp_consensus::{DisableProofRecording, NoNetwork as DummyOracle, Proposal}; @@ -38,7 +37,11 @@ use sp_consensus_babe::{ }; use sp_consensus_slots::SlotDuration; use sp_core::crypto::Pair; -use sp_keystore::{vrf::make_transcript as transcript_from_data, SyncCryptoStore}; +use sp_keyring::Sr25519Keyring; +use sp_keystore::{ + testing::KeyStore as TestKeyStore, vrf::make_transcript as transcript_from_data, + SyncCryptoStore, +}; use sp_runtime::{ generic::{Digest, DigestItem}, traits::Block as BlockT, @@ -363,6 +366,13 @@ fn rejects_empty_block() { }) } +fn create_keystore(authority: Sr25519Keyring) -> SyncCryptoStorePtr { + let keystore = Arc::new(TestKeyStore::new()); + SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some(&authority.to_seed())) + .expect("Generates authority key"); + keystore +} + fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static) { sp_tracing::try_init_simple(); let mutator = Arc::new(mutator) as Mutator; @@ -370,25 +380,19 @@ fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static MUTATOR.with(|m| *m.borrow_mut() = mutator.clone()); let net = BabeTestNet::new(3); - let peers = &[(0, "//Alice"), (1, "//Bob"), (2, "//Charlie")]; + let peers = [Sr25519Keyring::Alice, Sr25519Keyring::Bob, Sr25519Keyring::Charlie]; let net = Arc::new(Mutex::new(net)); let mut import_notifications = Vec::new(); let mut babe_futures = Vec::new(); - let mut keystore_paths = Vec::new(); - for (peer_id, seed) in peers { + for (peer_id, auth_id) in peers.iter().enumerate() { let mut net = net.lock(); - let peer = net.peer(*peer_id); + let peer = net.peer(peer_id); let client = peer.client().as_client(); let select_chain = peer.select_chain().expect("Full client has select_chain"); - let keystore_path = tempfile::tempdir().expect("Creates keystore path"); - let keystore: SyncCryptoStorePtr = - Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore")); - SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some(seed)) - .expect("Generates authority key"); - keystore_paths.push(keystore_path); + let keystore = create_keystore(*auth_id); let mut got_own = false; let mut got_other = false; @@ -536,16 +540,14 @@ fn sig_is_not_pre_digest() { #[test] fn can_author_block() { sp_tracing::try_init_simple(); - let keystore_path = tempfile::tempdir().expect("Creates keystore path"); - let keystore: SyncCryptoStorePtr = - Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore")); - let public = SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some("//Alice")) - .expect("Generates authority pair"); + + let authority = Sr25519Keyring::Alice; + let keystore = create_keystore(authority); let mut i = 0; let epoch = Epoch { start_slot: 0.into(), - authorities: vec![(public.into(), 1)], + authorities: vec![(authority.public().into(), 1)], randomness: [0; 32], epoch_index: 1, duration: 100, @@ -967,15 +969,13 @@ fn verify_slots_are_strictly_increasing() { #[test] fn babe_transcript_generation_match() { sp_tracing::try_init_simple(); - let keystore_path = tempfile::tempdir().expect("Creates keystore path"); - let keystore: SyncCryptoStorePtr = - Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore")); - let public = SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some("//Alice")) - .expect("Generates authority pair"); + + let authority = Sr25519Keyring::Alice; + let _keystore = create_keystore(authority); let epoch = Epoch { start_slot: 0.into(), - authorities: vec![(public.into(), 1)], + authorities: vec![(authority.public().into(), 1)], randomness: [0; 32], epoch_index: 1, duration: 100, diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 83c6051946aff..288e579d8da29 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -51,12 +51,8 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3.0" -finality-grandpa = { version = "0.16.0", features = [ - "derive-codec", - "test-helpers", -] } +finality-grandpa = { version = "0.16.0", features = ["derive-codec", "test-helpers"] } serde = "1.0.136" -tempfile = "3.1.0" tokio = "1.17.0" sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-test = { version = "0.8.0", path = "../network/test" } diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index c04754411af1a..39379e69c9157 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -41,7 +41,7 @@ use sp_finality_grandpa::{ AuthorityList, EquivocationProof, GrandpaApi, OpaqueKeyOwnershipProof, GRANDPA_ENGINE_ID, }; use sp_keyring::Ed25519Keyring; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{testing::KeyStore as TestKeyStore, SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ codec::Encode, generic::{BlockId, DigestItem}, @@ -59,7 +59,6 @@ use authorities::AuthoritySet; use communication::grandpa_protocol_name; use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; use sc_consensus::LongestChain; -use sc_keystore::LocalKeystore; use sp_application_crypto::key_types::GRANDPA; type TestLinkHalf = @@ -213,14 +212,11 @@ fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { keys.iter().map(|&key| key.public().into()).map(|id| (id, 1)).collect() } -fn create_keystore(authority: Ed25519Keyring) -> (SyncCryptoStorePtr, tempfile::TempDir) { - let keystore_path = tempfile::tempdir().expect("Creates keystore path"); - let keystore = - Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore")); +fn create_keystore(authority: Ed25519Keyring) -> SyncCryptoStorePtr { + let keystore = Arc::new(TestKeyStore::new()); SyncCryptoStore::ed25519_generate_new(&*keystore, GRANDPA, Some(&authority.to_seed())) .expect("Creates authority key"); - - (keystore, keystore_path) + keystore } fn block_until_complete( @@ -243,7 +239,7 @@ fn initialize_grandpa( let voters = stream::FuturesUnordered::new(); for (peer_id, key) in peers.iter().enumerate() { - let (keystore, _) = create_keystore(*key); + let keystore = create_keystore(*key); let (net_service, link) = { // temporary needed for some reason @@ -480,11 +476,9 @@ fn transition_3_voters_twice_1_full_observer() { let mut runtime = Runtime::new().unwrap(); - let mut keystore_paths = Vec::new(); let mut voters = Vec::new(); for (peer_id, local_key) in all_peers.clone().into_iter().enumerate() { - let (keystore, keystore_path) = create_keystore(local_key); - keystore_paths.push(keystore_path); + let keystore = create_keystore(local_key); let (net_service, link) = { let net = net.lock(); @@ -934,7 +928,6 @@ fn voter_persists_its_votes() { sp_tracing::try_init_simple(); let mut runtime = Runtime::new().unwrap(); - let mut keystore_paths = Vec::new(); // we have two authorities but we'll only be running the voter for alice // we are going to be listening for the prevotes it casts @@ -947,11 +940,7 @@ fn voter_persists_its_votes() { // create the communication layer for bob, but don't start any // voter. instead we'll listen for the prevote that alice casts // and cast our own manually - let bob_keystore = { - let (keystore, keystore_path) = create_keystore(peers[1]); - keystore_paths.push(keystore_path); - keystore - }; + let bob_keystore = create_keystore(peers[1]); let bob_network = { let config = Config { gossip_duration: TEST_GOSSIP_DURATION, @@ -984,7 +973,7 @@ fn voter_persists_its_votes() { // spawn two voters for alice. // half-way through the test, we stop one and start the other. let (alice_voter1, abort) = future::abortable({ - let (keystore, _) = create_keystore(peers[0]); + let keystore = create_keystore(peers[0]); let (net_service, link) = { // temporary needed for some reason @@ -1018,7 +1007,7 @@ fn voter_persists_its_votes() { peers: &[Ed25519Keyring], net: Arc>, ) -> impl Future + Send { - let (keystore, _) = create_keystore(peers[0]); + let keystore = create_keystore(peers[0]); let mut net = net.lock(); // we add a new peer to the test network and we'll use @@ -1266,8 +1255,6 @@ fn voter_catches_up_to_latest_round_when_behind() { Box::pin(run_grandpa_voter(grandpa_params).expect("all in order with client and network")) }; - let mut keystore_paths = Vec::new(); - // spawn authorities for (peer_id, key) in peers.iter().enumerate() { let (client, link) = { @@ -1284,8 +1271,7 @@ fn voter_catches_up_to_latest_round_when_behind() { .for_each(move |_| future::ready(())), ); - let (keystore, keystore_path) = create_keystore(*key); - keystore_paths.push(keystore_path); + let keystore = create_keystore(*key); let voter = voter(Some(keystore), peer_id, link, net.clone()); @@ -1515,7 +1501,7 @@ fn grandpa_environment_never_overwrites_round_voter_state() { let network_service = peer.network_service().clone(); let link = peer.data.lock().take().unwrap(); - let (keystore, _keystore_path) = create_keystore(peers[0]); + let keystore = create_keystore(peers[0]); let environment = test_environment(&link, Some(keystore), network_service.clone(), ()); let round_state = || finality_grandpa::round::State::genesis(Default::default()); @@ -1715,7 +1701,7 @@ fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { let peer = net.peer(0); let network_service = peer.network_service().clone(); let link = peer.data.lock().take().unwrap(); - let (keystore, _keystore_path) = create_keystore(alice); + let keystore = create_keystore(alice); test_environment(&link, Some(keystore), network_service.clone(), ()) }; From d6953869a5ab579d25551008eeb580c9efd649a9 Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Mon, 24 Oct 2022 20:10:18 +0200 Subject: [PATCH 1307/1472] Update template pallet to latest enum syntax (#12552) --- bin/node-template/pallets/template/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index 0b55d7ae86fcf..28d36ac2c6321 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -45,7 +45,7 @@ pub mod pallet { pub enum Event { /// Event documentation should end with an array that provides descriptive names for event /// parameters. [something, who] - SomethingStored(u32, T::AccountId), + SomethingStored { something: u32, who: T::AccountId }, } // Errors inform users that something went wrong. @@ -75,7 +75,7 @@ pub mod pallet { >::put(something); // Emit an event. - Self::deposit_event(Event::SomethingStored(something, who)); + Self::deposit_event(Event::SomethingStored { something, who }); // Return a successful DispatchResultWithPostInfo Ok(()) } From f2bc08a3071a91b71fec63cf2b22c707411cec0e Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 25 Oct 2022 15:04:32 +0800 Subject: [PATCH 1308/1472] feat: generalize some functions in sp-trie (#12376) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add to_memory_db to StorageProof * feat: add iter method and generalize iter_nodes * fmt * feat: generalize `encode_compact` like `decode_compact`, add to_compact_proof to StorageProof * fix to_compact_proof * improve by suggestions * improve by suggestions Co-authored-by: Bastian Köcher --- client/rpc/src/state/state_full.rs | 4 +- client/service/src/client/client.rs | 4 +- primitives/state-machine/src/lib.rs | 8 +-- primitives/state-machine/src/trie_backend.rs | 2 +- primitives/trie/src/lib.rs | 4 +- primitives/trie/src/storage_proof.rs | 63 ++++++++++++-------- primitives/trie/src/trie_codec.rs | 16 ++--- 7 files changed, 56 insertions(+), 45 deletions(-) diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 44e7d03bc1a0e..7fc7f840a9daf 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -346,7 +346,7 @@ where .and_then(|block| { self.client .read_proof(&block, &mut keys.iter().map(|key| key.0.as_ref())) - .map(|proof| proof.iter_nodes().map(|node| node.into()).collect()) + .map(|proof| proof.into_iter_nodes().map(|node| node.into()).collect()) .map(|proof| ReadProof { at: block, proof }) }) .map_err(client_err) @@ -498,7 +498,7 @@ where &child_info, &mut keys.iter().map(|key| key.0.as_ref()), ) - .map(|proof| proof.iter_nodes().map(|node| node.into()).collect()) + .map(|proof| proof.into_iter_nodes().map(|node| node.into()).collect()) .map(|proof| ReadProof { at: block, proof }) }) .map_err(client_err) diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index c0414a3bebc42..e4909b89e3f16 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1190,8 +1190,8 @@ where let (proof, count) = prove_range_read_with_child_with_size::<_, HashFor>( state, size_limit, start_key, )?; - // This is read proof only, we can use either LayoutV0 or LayoutV1. - let proof = sp_trie::encode_compact::>>(proof, root) + let proof = proof + .into_compact_proof::>(root) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?; Ok((proof, count)) } diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 4126aea478d5b..1f106593ede34 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -1939,13 +1939,13 @@ mod tests { let (proof, count) = prove_range_read_with_size(remote_backend, None, None, 0, None).unwrap(); // Always contains at least some nodes. - assert_eq!(proof.into_memory_db::().drain().len(), 3); + assert_eq!(proof.to_memory_db::().drain().len(), 3); assert_eq!(count, 1); let remote_backend = trie_backend::tests::test_trie(state_version, None, None); let (proof, count) = prove_range_read_with_size(remote_backend, None, None, 800, Some(&[])).unwrap(); - assert_eq!(proof.clone().into_memory_db::().drain().len(), 9); + assert_eq!(proof.to_memory_db::().drain().len(), 9); assert_eq!(count, 85); let (results, completed) = read_range_proof_check::( remote_root, @@ -1968,7 +1968,7 @@ mod tests { let remote_backend = trie_backend::tests::test_trie(state_version, None, None); let (proof, count) = prove_range_read_with_size(remote_backend, None, None, 50000, Some(&[])).unwrap(); - assert_eq!(proof.clone().into_memory_db::().drain().len(), 11); + assert_eq!(proof.to_memory_db::().drain().len(), 11); assert_eq!(count, 132); let (results, completed) = read_range_proof_check::(remote_root, proof, None, None, None, None) @@ -2053,7 +2053,7 @@ mod tests { ) .unwrap(); // Always contains at least some nodes. - assert!(proof.clone().into_memory_db::().drain().len() > 0); + assert!(proof.to_memory_db::().drain().len() > 0); assert!(count < 3); // when doing child we include parent and first child key. let (result, completed_depth) = read_range_proof_check_with_child::( diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index 447c276a6049c..20bb2c592e925 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -980,7 +980,7 @@ pub mod tests { let proof = backend.extract_proof().unwrap(); let mut nodes = Vec::new(); - for node in proof.iter_nodes() { + for node in proof.into_iter_nodes() { let hash = BlakeTwo256::hash(&node); // Only insert the node/value that contains the important data. if hash != value_hash { diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index c2ab12dbee14c..f40ed4d9b53a5 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -57,10 +57,10 @@ pub use trie_db::{ pub use trie_stream::TrieStream; /// substrate trie layout -pub struct LayoutV0(sp_std::marker::PhantomData); +pub struct LayoutV0(PhantomData); /// substrate trie layout, with external value nodes. -pub struct LayoutV1(sp_std::marker::PhantomData); +pub struct LayoutV1(PhantomData); impl TrieLayout for LayoutV0 where diff --git a/primitives/trie/src/storage_proof.rs b/primitives/trie/src/storage_proof.rs index 8fdb04ee20ed0..5351e8de6fd82 100644 --- a/primitives/trie/src/storage_proof.rs +++ b/primitives/trie/src/storage_proof.rs @@ -18,7 +18,11 @@ use codec::{Decode, Encode}; use hash_db::{HashDB, Hasher}; use scale_info::TypeInfo; -use sp_std::{collections::btree_set::BTreeSet, iter::IntoIterator, vec::Vec}; +use sp_std::{ + collections::btree_set::BTreeSet, + iter::{DoubleEndedIterator, IntoIterator}, + vec::Vec, +}; // Note that `LayoutV1` usage here (proof compaction) is compatible // with `LayoutV0`. use crate::LayoutV1 as Layout; @@ -54,10 +58,16 @@ impl StorageProof { self.trie_nodes.is_empty() } + /// Convert into an iterator over encoded trie nodes in lexicographical order constructed + /// from the proof. + pub fn into_iter_nodes(self) -> impl Sized + DoubleEndedIterator> { + self.trie_nodes.into_iter() + } + /// Create an iterator over encoded trie nodes in lexicographical order constructed /// from the proof. - pub fn iter_nodes(self) -> StorageProofNodeIterator { - StorageProofNodeIterator::new(self) + pub fn iter_nodes(&self) -> impl Sized + DoubleEndedIterator> { + self.trie_nodes.iter() } /// Convert into plain node vector. @@ -70,14 +80,19 @@ impl StorageProof { self.into() } + /// Creates a [`MemoryDB`](crate::MemoryDB) from `Self` reference. + pub fn to_memory_db(&self) -> crate::MemoryDB { + self.into() + } + /// Merges multiple storage proofs covering potentially different sets of keys into one proof /// covering all keys. The merged proof output may be smaller than the aggregate size of the /// input proofs due to deduplication of trie nodes. pub fn merge(proofs: impl IntoIterator) -> Self { let trie_nodes = proofs .into_iter() - .flat_map(|proof| proof.iter_nodes()) - .collect::>() + .flat_map(|proof| proof.into_iter_nodes()) + .collect::>() .into_iter() .collect(); @@ -89,7 +104,17 @@ impl StorageProof { self, root: H::Out, ) -> Result>> { - crate::encode_compact::>(self, root) + let db = self.into_memory_db(); + crate::encode_compact::, crate::MemoryDB>(&db, &root) + } + + /// Encode as a compact proof with default trie layout. + pub fn to_compact_proof( + &self, + root: H::Out, + ) -> Result>> { + let db = self.to_memory_db(); + crate::encode_compact::, crate::MemoryDB>(&db, &root) } /// Returns the estimated encoded size of the compact proof. @@ -106,6 +131,12 @@ impl StorageProof { impl From for crate::MemoryDB { fn from(proof: StorageProof) -> Self { + From::from(&proof) + } +} + +impl From<&StorageProof> for crate::MemoryDB { + fn from(proof: &StorageProof) -> Self { let mut db = crate::MemoryDB::default(); proof.iter_nodes().for_each(|n| { db.insert(crate::EMPTY_PREFIX, &n); @@ -169,23 +200,3 @@ impl CompactProof { Ok((db, root)) } } - -/// An iterator over trie nodes constructed from a storage proof. The nodes are not guaranteed to -/// be traversed in any particular order. -pub struct StorageProofNodeIterator { - inner: > as IntoIterator>::IntoIter, -} - -impl StorageProofNodeIterator { - fn new(proof: StorageProof) -> Self { - StorageProofNodeIterator { inner: proof.trie_nodes.into_iter() } - } -} - -impl Iterator for StorageProofNodeIterator { - type Item = Vec; - - fn next(&mut self) -> Option { - self.inner.next() - } -} diff --git a/primitives/trie/src/trie_codec.rs b/primitives/trie/src/trie_codec.rs index 949f9a6e284eb..d5ae9a43fb1eb 100644 --- a/primitives/trie/src/trie_codec.rs +++ b/primitives/trie/src/trie_codec.rs @@ -20,7 +20,7 @@ //! This uses compact proof from trie crate and extends //! it to substrate specific layout and child trie system. -use crate::{CompactProof, HashDBT, StorageProof, TrieConfiguration, TrieHash, EMPTY_PREFIX}; +use crate::{CompactProof, HashDBT, TrieConfiguration, TrieHash, EMPTY_PREFIX}; use sp_std::{boxed::Box, vec::Vec}; use trie_db::{CError, Trie}; @@ -149,17 +149,17 @@ where /// Then parse all child trie root and compress main trie content first /// then all child trie contents. /// Child trie are ordered by the order of their roots in the top trie. -pub fn encode_compact( - proof: StorageProof, - root: TrieHash, +pub fn encode_compact( + partial_db: &DB, + root: &TrieHash, ) -> Result, CError>> where L: TrieConfiguration, + DB: HashDBT + hash_db::HashDBRef, { let mut child_tries = Vec::new(); - let partial_db = proof.into_memory_db(); let mut compact_proof = { - let trie = crate::TrieDBBuilder::::new(&partial_db, &root).build(); + let trie = crate::TrieDBBuilder::::new(partial_db, root).build(); let mut iter = trie.iter()?; @@ -191,13 +191,13 @@ where }; for child_root in child_tries { - if !HashDBT::::contains(&partial_db, &child_root, EMPTY_PREFIX) { + if !HashDBT::::contains(partial_db, &child_root, EMPTY_PREFIX) { // child proof are allowed to be missing (unused root can be included // due to trie structure modification). continue } - let trie = crate::TrieDBBuilder::::new(&partial_db, &child_root).build(); + let trie = crate::TrieDBBuilder::::new(partial_db, &child_root).build(); let child_proof = trie_db::encode_compact::(&trie)?; compact_proof.extend(child_proof); From 65a870ab4a7fff46a307eacc0ae3a8f7f0f61f5e Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 25 Oct 2022 14:34:20 -0400 Subject: [PATCH 1309/1472] Make Multisig Pallet Bounded (#12457) * Bounded multisig * just use u32 Co-authored-by: parity-processbot <> --- bin/node/runtime/src/lib.rs | 2 +- frame/multisig/src/benchmarking.rs | 12 +++++------ frame/multisig/src/lib.rs | 32 ++++++++++++++++++++---------- frame/multisig/src/tests.rs | 4 ++-- frame/utility/src/tests.rs | 2 +- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 5ba89e6595e72..a23fe64c90628 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -249,7 +249,7 @@ impl pallet_multisig::Config for Runtime { type Currency = Balances; type DepositBase = DepositBase; type DepositFactor = DepositFactor; - type MaxSignatories = ConstU16<100>; + type MaxSignatories = ConstU32<100>; type WeightInfo = pallet_multisig::weights::SubstrateWeight; } diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index d949414e31cb3..d5faf9ae8ac1a 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -69,7 +69,7 @@ benchmarks! { as_multi_create { // Signatories, need at least 2 total people - let s in 2 .. T::MaxSignatories::get() as u32; + let s in 2 .. T::MaxSignatories::get(); // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; @@ -86,7 +86,7 @@ benchmarks! { as_multi_approve { // Signatories, need at least 3 people (so we don't complete the multisig) - let s in 3 .. T::MaxSignatories::get() as u32; + let s in 3 .. T::MaxSignatories::get(); // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; @@ -110,7 +110,7 @@ benchmarks! { as_multi_complete { // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get() as u32; + let s in 2 .. T::MaxSignatories::get(); // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; @@ -141,7 +141,7 @@ benchmarks! { approve_as_multi_create { // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get() as u32; + let s in 2 .. T::MaxSignatories::get(); // Transaction Length, not a component let z = 10_000; let (mut signatories, call) = setup_multi::(s, z)?; @@ -159,7 +159,7 @@ benchmarks! { approve_as_multi_approve { // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get() as u32; + let s in 2 .. T::MaxSignatories::get(); // Transaction Length, not a component let z = 10_000; let (mut signatories, call) = setup_multi::(s, z)?; @@ -190,7 +190,7 @@ benchmarks! { cancel_as_multi { // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get() as u32; + let s in 2 .. T::MaxSignatories::get(); // Transaction Length, not a component let z = 10_000; let (mut signatories, call) = setup_multi::(s, z)?; diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index e3031cc830209..34d9124f9b69e 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -51,7 +51,7 @@ pub mod migrations; mod tests; pub mod weights; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::{ DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo, @@ -60,7 +60,7 @@ use frame_support::{ ensure, traits::{Currency, Get, ReservableCurrency}, weights::Weight, - RuntimeDebug, + BoundedVec, RuntimeDebug, }; use frame_system::{self as system, RawOrigin}; use scale_info::TypeInfo; @@ -94,7 +94,9 @@ type BalanceOf = /// A global extrinsic index, formed as the extrinsic index within a block, together with that /// block's height. This allows a transaction in which a multisig operation of a particular /// composite was created to be uniquely identified. -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo)] +#[derive( + Copy, Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] pub struct Timepoint { /// The height of the chain at the point in time. height: BlockNumber, @@ -103,8 +105,12 @@ pub struct Timepoint { } /// An open multisig operation. -#[derive(Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo)] -pub struct Multisig { +#[derive(Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(MaxApprovals))] +pub struct Multisig +where + MaxApprovals: Get, +{ /// The extrinsic when the multisig operation was opened. when: Timepoint, /// The amount held in reserve of the `depositor`, to be returned once the operation ends. @@ -112,7 +118,7 @@ pub struct Multisig { /// The account who opened it (i.e. the first to approve it). depositor: AccountId, /// The approvals achieved so far, including the depositor. Always sorted. - approvals: Vec, + approvals: BoundedVec, } type CallHash = [u8; 32]; @@ -159,7 +165,7 @@ pub mod pallet { /// The maximum amount of signatories allowed in the multisig. #[pallet::constant] - type MaxSignatories: Get; + type MaxSignatories: Get; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -170,7 +176,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); @@ -182,7 +187,7 @@ pub mod pallet { T::AccountId, Blake2_128Concat, [u8; 32], - Multisig, T::AccountId>, + Multisig, T::AccountId, T::MaxSignatories>, >; #[pallet::error] @@ -601,7 +606,9 @@ impl Pallet { if let Some(pos) = maybe_pos { // Record approval. - m.approvals.insert(pos, who.clone()); + m.approvals + .try_insert(pos, who.clone()) + .map_err(|_| Error::::TooManySignatories)?; >::insert(&id, call_hash, m); Self::deposit_event(Event::MultisigApproval { approving: who, @@ -629,6 +636,9 @@ impl Pallet { T::Currency::reserve(&who, deposit)?; + let initial_approvals = + vec![who.clone()].try_into().map_err(|_| Error::::TooManySignatories)?; + >::insert( &id, call_hash, @@ -636,7 +646,7 @@ impl Pallet { when: Self::timepoint(), deposit, depositor: who.clone(), - approvals: vec![who.clone()], + approvals: initial_approvals, }, ); Self::deposit_event(Event::NewMultisig { approving: who, multisig: id, call_hash }); diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index f753b6f386c56..206e566cf4cb6 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -24,7 +24,7 @@ use super::*; use crate as pallet_multisig; use frame_support::{ assert_noop, assert_ok, parameter_types, - traits::{ConstU16, ConstU32, ConstU64, Contains}, + traits::{ConstU32, ConstU64, Contains}, }; use sp_core::H256; use sp_runtime::{ @@ -107,7 +107,7 @@ impl Config for Test { type Currency = Balances; type DepositBase = ConstU64<1>; type DepositFactor = ConstU64<1>; - type MaxSignatories = ConstU16<3>; + type MaxSignatories = ConstU32<3>; type WeightInfo = (); } diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index ebd8dda81adbc..81cec1c295c30 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -143,7 +143,7 @@ impl pallet_balances::Config for Test { parameter_types! { pub const MultisigDepositBase: u64 = 1; pub const MultisigDepositFactor: u64 = 1; - pub const MaxSignatories: u16 = 3; + pub const MaxSignatories: u32 = 3; } impl example::Config for Test {} From 759148506b6460a0ae6d2422d7b56b6452f0b114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=A4=E7=8B=90=E4=B8=80=E5=86=B2?= <43949039+anonymousGiga@users.noreply.github.com> Date: Wed, 26 Oct 2022 16:43:48 +0800 Subject: [PATCH 1310/1472] Fix error during build: failed to run custom build command for sc-network-bitswap (#12494) --- client/network/bitswap/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/network/bitswap/build.rs b/client/network/bitswap/build.rs index bd6222d546851..671277230a774 100644 --- a/client/network/bitswap/build.rs +++ b/client/network/bitswap/build.rs @@ -1,4 +1,4 @@ -const PROTOS: &[&str] = &["bitswap.v1.2.0.proto"]; +const PROTOS: &[&str] = &["src/schema/bitswap.v1.2.0.proto"]; fn main() { prost_build::compile_protos(PROTOS, &["src/schema"]).unwrap(); From 696bdc67af5fd83aca318263dbd405593b043ba3 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 26 Oct 2022 23:08:30 +0200 Subject: [PATCH 1311/1472] Update `pallet-multisig` benches (#12558) * Typo Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/bench-bot.sh" pallet dev pallet_multisig * remove functions * ".git/.scripts/bench-bot.sh" pallet dev pallet_multisig Signed-off-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> Co-authored-by: Shawn Tabrizi --- frame/multisig/src/lib.rs | 2 - frame/multisig/src/weights.rs | 249 ++++++++++++--------------- frame/transaction-payment/src/lib.rs | 2 +- frame/utility/src/lib.rs | 2 +- 4 files changed, 110 insertions(+), 145 deletions(-) diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 34d9124f9b69e..ae4efb76335a0 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -370,7 +370,6 @@ pub mod pallet { let z = call.using_encoded(|d| d.len()) as u32; T::WeightInfo::as_multi_create(s, z) - .max(T::WeightInfo::as_multi_create_store(s, z)) .max(T::WeightInfo::as_multi_approve(s, z)) .max(T::WeightInfo::as_multi_complete(s, z)) .saturating_add(*max_weight) @@ -434,7 +433,6 @@ pub mod pallet { T::WeightInfo::approve_as_multi_create(s) .max(T::WeightInfo::approve_as_multi_approve(s)) - .max(T::WeightInfo::approve_as_multi_complete(s)) .saturating_add(*max_weight) })] pub fn approve_as_multi( diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index d8d576775408a..de403b4d249e4 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,22 +18,26 @@ //! Autogenerated weights for pallet_multisig //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_multisig // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_multisig +// --chain=dev +// --header=./HEADER-APACHE2 // --output=./frame/multisig/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -46,213 +50,176 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn as_multi_threshold_1(z: u32, ) -> Weight; fn as_multi_create(s: u32, z: u32, ) -> Weight; - fn as_multi_create_store(s: u32, z: u32, ) -> Weight; fn as_multi_approve(s: u32, z: u32, ) -> Weight; - fn as_multi_approve_store(s: u32, z: u32, ) -> Weight; fn as_multi_complete(s: u32, z: u32, ) -> Weight; fn approve_as_multi_create(s: u32, ) -> Weight; fn approve_as_multi_approve(s: u32, ) -> Weight; - fn approve_as_multi_complete(s: u32, ) -> Weight; fn cancel_as_multi(s: u32, ) -> Weight; } /// Weights for pallet_multisig using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - fn as_multi_threshold_1(_z: u32, ) -> Weight { - Weight::from_ref_time(17_537_000 as u64) + /// The range of component `z` is `[0, 10000]`. + fn as_multi_threshold_1(z: u32, ) -> Weight { + // Minimum execution time: 20_283 nanoseconds. + Weight::from_ref_time(20_861_089 as u64) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(583 as u64).saturating_mul(z as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(36_535_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(99_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + // Minimum execution time: 52_699 nanoseconds. + Weight::from_ref_time(40_874_603 as u64) + // Standard Error: 546 + .saturating_add(Weight::from_ref_time(131_727 as u64).saturating_mul(s as u64)) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(1_537 as u64).saturating_mul(z as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) - fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_918_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(95_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) + /// The range of component `s` is `[3, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(25_524_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(94_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + // Minimum execution time: 39_843 nanoseconds. + Weight::from_ref_time(28_912_325 as u64) + // Standard Error: 734 + .saturating_add(Weight::from_ref_time(125_761 as u64).saturating_mul(s as u64)) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_542 as u64).saturating_mul(z as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_923_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(91_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(45_877_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(146_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 54_980 nanoseconds. + Weight::from_ref_time(42_087_213 as u64) + // Standard Error: 786 + .saturating_add(Weight::from_ref_time(153_935 as u64).saturating_mul(s as u64)) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_545 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { - Weight::from_ref_time(34_309_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 37_802 nanoseconds. + Weight::from_ref_time(39_933_623 as u64) + // Standard Error: 1_059 + .saturating_add(Weight::from_ref_time(121_891 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:0) + /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { - Weight::from_ref_time(22_848_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 25_738 nanoseconds. + Weight::from_ref_time(27_676_766 as u64) + // Standard Error: 710 + .saturating_add(Weight::from_ref_time(125_733 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - // Storage: System Account (r:1 w:1) - fn approve_as_multi_complete(s: u32, ) -> Weight { - Weight::from_ref_time(63_239_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(161_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) + /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { - Weight::from_ref_time(51_254_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(118_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 36_591 nanoseconds. + Weight::from_ref_time(38_707_543 as u64) + // Standard Error: 881 + .saturating_add(Weight::from_ref_time(126_198 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - fn as_multi_threshold_1(_z: u32, ) -> Weight { - Weight::from_ref_time(17_537_000 as u64) + /// The range of component `z` is `[0, 10000]`. + fn as_multi_threshold_1(z: u32, ) -> Weight { + // Minimum execution time: 20_283 nanoseconds. + Weight::from_ref_time(20_861_089 as u64) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(583 as u64).saturating_mul(z as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(36_535_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(99_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + // Minimum execution time: 52_699 nanoseconds. + Weight::from_ref_time(40_874_603 as u64) + // Standard Error: 546 + .saturating_add(Weight::from_ref_time(131_727 as u64).saturating_mul(s as u64)) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(1_537 as u64).saturating_mul(z as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) - fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_918_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(95_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) + /// The range of component `s` is `[3, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(25_524_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(94_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + // Minimum execution time: 39_843 nanoseconds. + Weight::from_ref_time(28_912_325 as u64) + // Standard Error: 734 + .saturating_add(Weight::from_ref_time(125_761 as u64).saturating_mul(s as u64)) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_542 as u64).saturating_mul(z as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_923_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(91_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(45_877_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(146_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 54_980 nanoseconds. + Weight::from_ref_time(42_087_213 as u64) + // Standard Error: 786 + .saturating_add(Weight::from_ref_time(153_935 as u64).saturating_mul(s as u64)) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_545 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { - Weight::from_ref_time(34_309_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 37_802 nanoseconds. + Weight::from_ref_time(39_933_623 as u64) + // Standard Error: 1_059 + .saturating_add(Weight::from_ref_time(121_891 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:0) + /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { - Weight::from_ref_time(22_848_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 25_738 nanoseconds. + Weight::from_ref_time(27_676_766 as u64) + // Standard Error: 710 + .saturating_add(Weight::from_ref_time(125_733 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - // Storage: System Account (r:1 w:1) - fn approve_as_multi_complete(s: u32, ) -> Weight { - Weight::from_ref_time(63_239_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(161_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) + /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { - Weight::from_ref_time(51_254_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(118_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 36_591 nanoseconds. + Weight::from_ref_time(38_707_543 as u64) + // Standard Error: 881 + .saturating_add(Weight::from_ref_time(126_198 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 5027db41ec098..ce747fa6bd85c 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -658,7 +658,7 @@ where Self(fee) } - /// Returns the tip as being choosen by the transaction sender. + /// Returns the tip as being chosen by the transaction sender. pub fn tip(&self) -> BalanceOf { self.0 } diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 9ae89097a9bc3..544add1da68d3 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -124,7 +124,7 @@ pub mod pallet { // Align the call size to 1KB. As we are currently compiling the runtime for native/wasm // the `size_of` of the `Call` can be different. To ensure that this don't leads to // mismatches between native/wasm or to different metadata for the same runtime, we - // algin the call size. The value is choosen big enough to hopefully never reach it. + // algin the call size. The value is chosen big enough to hopefully never reach it. const CALL_ALIGN: u32 = 1024; #[pallet::extra_constants] From 676e35fdfdd2526a2df29efd41e6642046f2ddee Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 27 Oct 2022 10:54:07 +0200 Subject: [PATCH 1312/1472] [ci] cargo-check-benches against different base branches (#12557) --- scripts/ci/gitlab/pipeline/test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index b405cfa1eb3a4..8baebb39be6dc 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -68,10 +68,12 @@ cargo-check-benches: - !reference [.rusty-cachier, before_script] - !reference [.pipeline-stopper-vars, script] # merges in the master branch on PRs + - | + export BASE=$(curl -s -H "Authorization: Bearer ${GITHUB_PR_TOKEN}" https://api.github.com/repos/paritytech/substrate/pulls/${$CI_COMMIT_REF_NAME} | jq .base.ref) - if [ $CI_COMMIT_REF_NAME != "master" ]; then - git fetch origin +master:master; + git fetch origin +${BASE}:${BASE}; git fetch origin +$CI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME; - git checkout master; + git checkout ${BASE}; git config user.email "ci@gitlab.parity.io"; git merge $CI_COMMIT_REF_NAME --verbose --no-edit; fi From 6195ef41946017ec860d2d8ad58f9bc18b5797bf Mon Sep 17 00:00:00 2001 From: Malte Kliemann Date: Thu, 27 Oct 2022 17:23:04 +0200 Subject: [PATCH 1313/1472] Fix typo (#12571) --- frame/membership/README.md | 4 ++-- frame/membership/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/membership/README.md b/frame/membership/README.md index a769be497050e..3499a3f864e48 100644 --- a/frame/membership/README.md +++ b/frame/membership/README.md @@ -1,6 +1,6 @@ # Membership Module -Allows control of membership of a set of `AccountId`s, useful for managing membership of of a +Allows control of membership of a set of `AccountId`s, useful for managing membership of a collective. A prime member may be set. -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index af2f2ddcf42f0..4191bbcc5d86e 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -17,7 +17,7 @@ //! # Membership Module //! -//! Allows control of membership of a set of `AccountId`s, useful for managing membership of of a +//! Allows control of membership of a set of `AccountId`s, useful for managing membership of a //! collective. A prime member may be set // Ensure we're `no_std` when compiling for Wasm. From 83ed732cf34820724240f86e5ac7597552411c53 Mon Sep 17 00:00:00 2001 From: Mrisho Lukamba <69342343+MrishoLukamba@users.noreply.github.com> Date: Fri, 28 Oct 2022 15:16:18 +0300 Subject: [PATCH 1314/1472] replaced println with log Closes #12338 (#12348) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * replaced println with log Closes #12338 * fixed println * Apply suggestions from code review Co-authored-by: Bastian Köcher * Update utils/frame/benchmarking-cli/src/pallet/command.rs * Apply suggestions from code review * ".git/.scripts/fmt.sh" 1 Co-authored-by: Shawn Tabrizi Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- utils/frame/benchmarking-cli/src/pallet/command.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 6e413bdf7e2c5..242f0e685290f 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -40,6 +40,9 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_state_machine::StateMachine; use std::{collections::HashMap, fmt::Debug, fs, sync::Arc, time}; +/// Logging target +const LOG_TARGET: &'static str = "frame::benchmark::pallet"; + /// The inclusive range of a component. #[derive(Serialize, Debug, Clone, Eq, PartialEq)] pub(crate) struct ComponentRange { @@ -242,7 +245,8 @@ impl PalletCmd { let mut component_ranges = HashMap::<(Vec, Vec), Vec>::new(); for (pallet, extrinsic, components) in benchmarks_to_run { - println!( + log::info!( + target: LOG_TARGET, "Starting benchmark: {}::{}", String::from_utf8(pallet.clone()).expect("Encoded from String; qed"), String::from_utf8(extrinsic.clone()).expect("Encoded from String; qed"), @@ -402,7 +406,9 @@ impl PalletCmd { if let Ok(elapsed) = timer.elapsed() { if elapsed >= time::Duration::from_secs(5) { timer = time::SystemTime::now(); - println!( + + log::info!( + target: LOG_TARGET, "Running Benchmark: {}.{}({} args) {}/{} {}/{}", String::from_utf8(pallet.clone()) .expect("Encoded from String; qed"), @@ -492,7 +498,7 @@ impl PalletCmd { if let Some(path) = &self.json_file { fs::write(path, json)?; } else { - println!("{}", json); + print!("{json}"); return Ok(true) } } From 4e1e17cccd499dfe49e8c1bed01957953aa4c839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 28 Oct 2022 15:25:49 +0200 Subject: [PATCH 1315/1472] Aura: Adds some compatibility mode to support old chains (#12492) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Aura: Adds some compatibility mode to support old chains In https://github.com/paritytech/substrate/pull/9132 we changed the way how we get the authorities from the runtime. Before this mentioned pr we would call `initialize_block` before calling the authorities runtime function. The problem with this was that when you have a block X that would switch the authority set, it would already be signed by an authority of the new set. This was wrong, as a block should only be signed by the current authority set. As this change is a hard fork, this pr brings back the possibility for users that have a chain running with this old logic to upgrade. They will need to use: ``` CompatibilityMode::UseInitializeBlock { until: some_block_in_the_future } ``` Using this compatibility mode will make the node behave like the old nodes, aka calling `initialize_block` before doing the actual runtime call to `authorities`. Then when the given `until` block is being build/imported the node switches to the new behaviour of not calling `initialize_block` before. This is a hard fork, so the `until` block should be chosen wisely as a point where all nodes in the network have upgraded. * Fixes * Make docs ready * Update client/consensus/aura/src/lib.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Update client/consensus/aura/src/lib.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Update client/consensus/aura/src/lib.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * FMT Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- bin/node-template/node/src/service.rs | 2 + client/consensus/aura/src/import_queue.rs | 84 ++++++++-------- client/consensus/aura/src/lib.rs | 115 +++++++++++++++++++--- client/service/src/client/client.rs | 2 +- primitives/consensus/aura/src/lib.rs | 2 +- 5 files changed, 147 insertions(+), 58 deletions(-) diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 96de6e17f3bfd..ee8464688c79c 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -132,6 +132,7 @@ pub fn new_partial( registry: config.prometheus_registry(), check_for_equivocation: Default::default(), telemetry: telemetry.as_ref().map(|x| x.handle()), + compatibility_mode: Default::default(), })?; Ok(sc_service::PartialComponents { @@ -280,6 +281,7 @@ pub fn new_full(mut config: Configuration) -> Result block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32), max_block_proposal_slot_portion: None, telemetry: telemetry.as_ref().map(|x| x.handle()), + compatibility_mode: Default::default(), }, )?; diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 90f15fef1b34b..b17feae45897e 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -18,7 +18,9 @@ //! Module implementing the logic for verifying and importing AuRa blocks. -use crate::{aura_err, authorities, find_pre_digest, slot_author, AuthorityId, Error}; +use crate::{ + aura_err, authorities, find_pre_digest, slot_author, AuthorityId, CompatibilityMode, Error, +}; use codec::{Codec, Decode, Encode}; use log::{debug, info, trace}; use prometheus_endpoint::Registry; @@ -31,21 +33,15 @@ use sc_consensus_slots::{check_equivocation, CheckedHeader, InherentDataProvider use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_TRACE}; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_block_builder::BlockBuilder as BlockBuilderApi; -use sp_blockchain::{ - well_known_cache_keys::{self, Id as CacheKeyId}, - HeaderBackend, -}; +use sp_blockchain::{well_known_cache_keys::Id as CacheKeyId, HeaderBackend}; use sp_consensus::Error as ConsensusError; -use sp_consensus_aura::{ - digests::CompatibleDigestItem, inherents::AuraInherentData, AuraApi, ConsensusLog, - AURA_ENGINE_ID, -}; +use sp_consensus_aura::{digests::CompatibleDigestItem, inherents::AuraInherentData, AuraApi}; use sp_consensus_slots::Slot; use sp_core::{crypto::Pair, ExecutionContext}; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider as _}; use sp_runtime::{ - generic::{BlockId, OpaqueDigestItemId}, - traits::{Block as BlockT, Header}, + generic::BlockId, + traits::{Block as BlockT, Header, NumberFor}, DigestItem, }; use std::{fmt::Debug, hash::Hash, marker::PhantomData, sync::Arc}; @@ -109,32 +105,35 @@ where } /// A verifier for Aura blocks. -pub struct AuraVerifier { +pub struct AuraVerifier { client: Arc, phantom: PhantomData

, create_inherent_data_providers: CIDP, check_for_equivocation: CheckForEquivocation, telemetry: Option, + compatibility_mode: CompatibilityMode, } -impl AuraVerifier { +impl AuraVerifier { pub(crate) fn new( client: Arc, create_inherent_data_providers: CIDP, check_for_equivocation: CheckForEquivocation, telemetry: Option, + compatibility_mode: CompatibilityMode, ) -> Self { Self { client, create_inherent_data_providers, check_for_equivocation, telemetry, + compatibility_mode, phantom: PhantomData, } } } -impl AuraVerifier +impl AuraVerifier where P: Send + Sync + 'static, CIDP: Send, @@ -172,9 +171,9 @@ where } #[async_trait::async_trait] -impl Verifier for AuraVerifier +impl Verifier for AuraVerifier> where - C: ProvideRuntimeApi + Send + Sync + sc_client_api::backend::AuxStore + BlockOf, + C: ProvideRuntimeApi + Send + Sync + sc_client_api::backend::AuxStore, C::Api: BlockBuilderApi + AuraApi> + ApiExt, P: Pair + Send + Sync + 'static, P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + 'static, @@ -188,8 +187,13 @@ where ) -> Result<(BlockImportParams, Option)>>), String> { let hash = block.header.hash(); let parent_hash = *block.header.parent_hash(); - let authorities = authorities(self.client.as_ref(), &BlockId::Hash(parent_hash)) - .map_err(|e| format!("Could not fetch authorities at {:?}: {}", parent_hash, e))?; + let authorities = authorities( + self.client.as_ref(), + parent_hash, + *block.header.number(), + &self.compatibility_mode, + ) + .map_err(|e| format!("Could not fetch authorities at {:?}: {}", parent_hash, e))?; let create_inherent_data_providers = self .create_inherent_data_providers @@ -259,28 +263,12 @@ where "pre_header" => ?pre_header, ); - // Look for an authorities-change log. - let maybe_keys = pre_header - .digest() - .logs() - .iter() - .filter_map(|l| { - l.try_to::>>(OpaqueDigestItemId::Consensus( - &AURA_ENGINE_ID, - )) - }) - .find_map(|l| match l { - ConsensusLog::AuthoritiesChange(a) => - Some(vec![(well_known_cache_keys::AUTHORITIES, a.encode())]), - _ => None, - }); - block.header = pre_header; block.post_digests.push(seal); block.fork_choice = Some(ForkChoiceStrategy::LongestChain); block.post_hash = Some(hash); - Ok((block, maybe_keys)) + Ok((block, None)) }, CheckedHeader::Deferred(a, b) => { debug!(target: "aura", "Checking {:?} failed; {:?}, {:?}.", hash, a, b); @@ -323,7 +311,7 @@ impl Default for CheckForEquivocation { } /// Parameters of [`import_queue`]. -pub struct ImportQueueParams<'a, Block, I, C, S, CIDP> { +pub struct ImportQueueParams<'a, Block: BlockT, I, C, S, CIDP> { /// The block import to use. pub block_import: I, /// The justification import. @@ -340,6 +328,10 @@ pub struct ImportQueueParams<'a, Block, I, C, S, CIDP> { pub check_for_equivocation: CheckForEquivocation, /// Telemetry instance used to report telemetry metrics. pub telemetry: Option, + /// Compatibility mode that should be used. + /// + /// If in doubt, use `Default::default()`. + pub compatibility_mode: CompatibilityMode>, } /// Start an import queue for the Aura consensus algorithm. @@ -353,6 +345,7 @@ pub fn import_queue( registry, check_for_equivocation, telemetry, + compatibility_mode, }: ImportQueueParams, ) -> Result, sp_consensus::Error> where @@ -377,18 +370,19 @@ where CIDP: CreateInherentDataProviders + Sync + Send + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { - let verifier = build_verifier::(BuildVerifierParams { + let verifier = build_verifier::(BuildVerifierParams { client, create_inherent_data_providers, check_for_equivocation, telemetry, + compatibility_mode, }); Ok(BasicQueue::new(verifier, Box::new(block_import), justification_import, spawner, registry)) } /// Parameters of [`build_verifier`]. -pub struct BuildVerifierParams { +pub struct BuildVerifierParams { /// The client to interact with the chain. pub client: Arc, /// Something that can create the inherent data providers. @@ -397,21 +391,27 @@ pub struct BuildVerifierParams { pub check_for_equivocation: CheckForEquivocation, /// Telemetry instance used to report telemetry metrics. pub telemetry: Option, + /// Compatibility mode that should be used. + /// + /// If in doubt, use `Default::default()`. + pub compatibility_mode: CompatibilityMode, } /// Build the [`AuraVerifier`] -pub fn build_verifier( +pub fn build_verifier( BuildVerifierParams { client, create_inherent_data_providers, check_for_equivocation, telemetry, - }: BuildVerifierParams, -) -> AuraVerifier { - AuraVerifier::<_, P, _>::new( + compatibility_mode, + }: BuildVerifierParams, +) -> AuraVerifier { + AuraVerifier::<_, P, _, _>::new( client, create_inherent_data_providers, check_for_equivocation, telemetry, + compatibility_mode, ) } diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 734cecca9b30b..50a02726cf56a 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -44,7 +44,7 @@ use sc_consensus_slots::{ SlotInfo, StorageChanges, }; use sc_telemetry::TelemetryHandle; -use sp_api::ProvideRuntimeApi; +use sp_api::{Core, ProvideRuntimeApi}; use sp_application_crypto::{AppKey, AppPublic}; use sp_blockchain::{HeaderBackend, Result as CResult}; use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain}; @@ -74,6 +74,43 @@ pub use sp_consensus_aura::{ type AuthorityId

=

::Public; +/// Run `AURA` in a compatibility mode. +/// +/// This is required for when the chain was launched and later there +/// was a consensus breaking change. +#[derive(Debug, Clone)] +pub enum CompatibilityMode { + /// Don't use any compatibility mode. + None, + /// Call `initialize_block` before doing any runtime calls. + /// + /// Previously the node would execute `initialize_block` before fetchting the authorities + /// from the runtime. This behaviour changed in: + /// + /// By calling `initialize_block` before fetching the authorities, on a block that + /// would enact a new validator set, the block would already be build/sealed by an + /// authority of the new set. With this mode disabled (the default) a block that enacts a new + /// set isn't sealed/built by an authority of the new set, however to make new nodes be able to + /// sync old chains this compatibility mode exists. + UseInitializeBlock { + /// The block number until this compatibility mode should be executed. The first runtime + /// call in the context of the `until` block (importing it/building it) will disable the + /// compatibility mode (i.e. at `until` the default rules will apply). When enabling this + /// compatibility mode the `until` block should be a future block on which all nodes will + /// have upgraded to a release that includes the updated compatibility mode configuration. + /// At `until` block there will be a hard fork when the authority set changes, between the + /// old nodes (running with `initialize_block`, i.e. without the compatibility mode + /// configuration) and the new nodes. + until: N, + }, +} + +impl Default for CompatibilityMode { + fn default() -> Self { + Self::None + } +} + /// Get the slot duration for Aura. pub fn slot_duration(client: &C) -> CResult where @@ -106,7 +143,7 @@ fn slot_author(slot: Slot, authorities: &[AuthorityId

]) -> Option<&A } /// Parameters of [`start_aura`]. -pub struct StartAuraParams { +pub struct StartAuraParams { /// The duration of a slot. pub slot_duration: SlotDuration, /// The client to interact with the chain. @@ -140,6 +177,10 @@ pub struct StartAuraParams { pub max_block_proposal_slot_portion: Option, /// Telemetry instance used to report telemetry metrics. pub telemetry: Option, + /// Compatibility mode that should be used. + /// + /// If in doubt, use `Default::default()`. + pub compatibility_mode: CompatibilityMode, } /// Start the aura worker. The returned future should be run in a futures executor. @@ -159,7 +200,8 @@ pub fn start_aura( block_proposal_slot_portion, max_block_proposal_slot_portion, telemetry, - }: StartAuraParams, + compatibility_mode, + }: StartAuraParams>, ) -> Result, sp_consensus::Error> where P: Pair + Send + Sync, @@ -191,6 +233,7 @@ where telemetry, block_proposal_slot_portion, max_block_proposal_slot_portion, + compatibility_mode, }); Ok(sc_consensus_slots::start_slot_worker( @@ -203,7 +246,7 @@ where } /// Parameters of [`build_aura_worker`]. -pub struct BuildAuraWorkerParams { +pub struct BuildAuraWorkerParams { /// The client to interact with the chain. pub client: Arc, /// The block import. @@ -231,6 +274,10 @@ pub struct BuildAuraWorkerParams { pub max_block_proposal_slot_portion: Option, /// Telemetry instance used to report telemetry metrics. pub telemetry: Option, + /// Compatibility mode that should be used. + /// + /// If in doubt, use `Default::default()`. + pub compatibility_mode: CompatibilityMode, } /// Build the aura worker. @@ -249,7 +296,8 @@ pub fn build_aura_worker( max_block_proposal_slot_portion, telemetry, force_authoring, - }: BuildAuraWorkerParams, + compatibility_mode, + }: BuildAuraWorkerParams>, ) -> impl sc_consensus_slots::SimpleSlotWorker< B, Proposer = PF::Proposer, @@ -286,11 +334,12 @@ where telemetry, block_proposal_slot_portion, max_block_proposal_slot_portion, + compatibility_mode, _key_type: PhantomData::

, } } -struct AuraWorker { +struct AuraWorker { client: Arc, block_import: I, env: E, @@ -302,12 +351,13 @@ struct AuraWorker { block_proposal_slot_portion: SlotProportion, max_block_proposal_slot_portion: Option, telemetry: Option, + compatibility_mode: CompatibilityMode, _key_type: PhantomData

, } #[async_trait::async_trait] impl sc_consensus_slots::SimpleSlotWorker - for AuraWorker + for AuraWorker> where B: BlockT, C: ProvideRuntimeApi + BlockOf + HeaderBackend + Sync, @@ -345,7 +395,12 @@ where header: &B::Header, _slot: Slot, ) -> Result { - authorities(self.client.as_ref(), &BlockId::Hash(header.hash())) + authorities( + self.client.as_ref(), + header.hash(), + *header.number() + 1u32.into(), + &self.compatibility_mode, + ) } fn authorities_len(&self, epoch_data: &Self::AuxData) -> Option { @@ -535,16 +590,42 @@ pub fn find_pre_digest(header: &B::Header) -> Resul pre_digest.ok_or_else(|| aura_err(Error::NoDigestFound)) } -fn authorities(client: &C, at: &BlockId) -> Result, ConsensusError> +fn authorities( + client: &C, + parent_hash: B::Hash, + context_block_number: NumberFor, + compatibility_mode: &CompatibilityMode>, +) -> Result, ConsensusError> where A: Codec + Debug, B: BlockT, - C: ProvideRuntimeApi + BlockOf, + C: ProvideRuntimeApi, C::Api: AuraApi, { - client - .runtime_api() - .authorities(at) + let runtime_api = client.runtime_api(); + + match compatibility_mode { + CompatibilityMode::None => {}, + // Use `initialize_block` until we hit the block that should disable the mode. + CompatibilityMode::UseInitializeBlock { until } => + if *until > context_block_number { + runtime_api + .initialize_block( + &BlockId::Hash(parent_hash), + &B::Header::new( + context_block_number, + Default::default(), + Default::default(), + parent_hash, + Default::default(), + ), + ) + .map_err(|_| sp_consensus::Error::InvalidAuthoritiesSet)?; + }, + } + + runtime_api + .authorities(&BlockId::Hash(parent_hash)) .ok() .ok_or(sp_consensus::Error::InvalidAuthoritiesSet) } @@ -631,6 +712,7 @@ mod tests { InherentDataProviders = (InherentDataProvider,), >, >, + u64, >; type AuraPeer = Peer<(), PeersClient>; @@ -660,6 +742,7 @@ mod tests { }), CheckForEquivocation::Yes, None, + CompatibilityMode::None, ) } @@ -749,6 +832,7 @@ mod tests { block_proposal_slot_portion: SlotProportion::new(0.5), max_block_proposal_slot_portion: None, telemetry: None, + compatibility_mode: CompatibilityMode::None, }) .expect("Starts aura"), ); @@ -769,7 +853,8 @@ mod tests { assert_eq!(client.chain_info().best_number, 0); assert_eq!( - authorities(&client, &BlockId::Hash(client.chain_info().best_hash)).unwrap(), + authorities(&client, client.chain_info().best_hash, 1, &CompatibilityMode::None) + .unwrap(), vec![ Keyring::Alice.public().into(), Keyring::Bob.public().into(), @@ -814,6 +899,7 @@ mod tests { _key_type: PhantomData::, block_proposal_slot_portion: SlotProportion::new(0.5), max_block_proposal_slot_portion: None, + compatibility_mode: Default::default(), }; let head = Header::new( @@ -866,6 +952,7 @@ mod tests { _key_type: PhantomData::, block_proposal_slot_portion: SlotProportion::new(0.5), max_block_proposal_slot_portion: None, + compatibility_mode: Default::default(), }; let head = client.header(&BlockId::Number(0)).unwrap().unwrap(); diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index e4909b89e3f16..eb946436671e4 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -641,7 +641,7 @@ where if state_root != *import_headers.post().state_root() { // State root mismatch when importing state. This should not happen in // safe fast sync mode, but may happen in unsafe mode. - warn!("Error imporing state: State root mismatch."); + warn!("Error importing state: State root mismatch."); return Err(Error::InvalidStateRoot) } None diff --git a/primitives/consensus/aura/src/lib.rs b/primitives/consensus/aura/src/lib.rs index 3e47adf0bf92f..2c6a97b934137 100644 --- a/primitives/consensus/aura/src/lib.rs +++ b/primitives/consensus/aura/src/lib.rs @@ -89,7 +89,7 @@ sp_api::decl_runtime_apis! { /// Currently, only the value provided by this type at genesis will be used. fn slot_duration() -> SlotDuration; - // Return the current set of authorities. + /// Return the current set of authorities. fn authorities() -> Vec; } } From c4d36065764ee23aeb3ccd181c4b6ecea8d2447a Mon Sep 17 00:00:00 2001 From: clangenb <37865735+clangenb@users.noreply.github.com> Date: Fri, 28 Oct 2022 15:38:25 +0200 Subject: [PATCH 1316/1472] bump ed25519-zebra; fixes `full_crypto` feature flag in `no_std` (#12576) --- Cargo.lock | 6 +++--- primitives/core/Cargo.toml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a5b562d0a791..c42772e793e41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1782,15 +1782,15 @@ dependencies = [ [[package]] name = "ed25519-zebra" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" dependencies = [ "curve25519-dalek 3.0.2", + "hashbrown 0.12.3", "hex", "rand_core 0.6.2", "sha2 0.9.8", - "thiserror", "zeroize", ] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index b7bc6dfdce496..dcb61b33f347f 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -48,7 +48,7 @@ bitflags = "1.3" # full crypto array-bytes = { version = "4.1", optional = true } -ed25519-zebra = { version = "3.0.0", default-features = false, optional = true} +ed25519-zebra = { version = "3.1.0", default-features = false, optional = true } blake2 = { version = "0.10.4", default-features = false, optional = true } schnorrkel = { version = "0.9.1", features = [ "preaudit_deprecated", @@ -99,7 +99,7 @@ std = [ "serde", "blake2/std", "array-bytes", - "ed25519-zebra", + "ed25519-zebra/std", "base58", "substrate-bip39", "tiny-bip39", From 547e856831650525bbd4372fb659fcefd6ddf1d8 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Fri, 28 Oct 2022 17:18:09 +0200 Subject: [PATCH 1317/1472] Utility: add more tests for batch/batchAll/forceBatch (#12506) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Utility: add more tests for batch/batchAll/forceBatch * remove unnecessary * batch works with council * add more tests * better call examples * shorter code * Update frame/utility/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/utility/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/utility/src/lib.rs Co-authored-by: Bastian Köcher * update TestBaseCallFilter * fix * fix? * fix Co-authored-by: Bastian Köcher --- Cargo.lock | 2 + frame/utility/Cargo.toml | 2 + frame/utility/src/lib.rs | 18 +-- frame/utility/src/tests.rs | 221 ++++++++++++++++++++++++++++++++++++- 4 files changed, 232 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c42772e793e41..cbf02a3fa6a50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6327,6 +6327,8 @@ dependencies = [ "frame-support", "frame-system", "pallet-balances", + "pallet-collective", + "pallet-timestamp", "parity-scale-codec", "scale-info", "sp-core", diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index cbe2892d72dc7..ac4f52c6bb9f3 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -25,6 +25,8 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } +pallet-collective = { version = "4.0.0-dev", path = "../collective" } +pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 544add1da68d3..41710be930b90 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -164,13 +164,13 @@ pub mod pallet { impl Pallet { /// Send a batch of dispatch calls. /// - /// May be called from any origin. + /// May be called from any origin except `None`. /// /// - `calls`: The calls to be dispatched from the same origin. The number of call must not /// exceed the constant: `batched_calls_limit` (available in constant metadata). /// - /// If origin is root then call are dispatch without checking origin filter. (This includes - /// bypassing `frame_system::Config::BaseCallFilter`). + /// If origin is root then the calls are dispatched without checking origin filter. (This + /// includes bypassing `frame_system::Config::BaseCallFilter`). /// /// # /// - Complexity: O(C) where C is the number of calls to be batched. @@ -291,13 +291,13 @@ pub mod pallet { /// Send a batch of dispatch calls and atomically execute them. /// The whole transaction will rollback and fail if any of the calls failed. /// - /// May be called from any origin. + /// May be called from any origin except `None`. /// /// - `calls`: The calls to be dispatched from the same origin. The number of call must not /// exceed the constant: `batched_calls_limit` (available in constant metadata). /// - /// If origin is root then call are dispatch without checking origin filter. (This includes - /// bypassing `frame_system::Config::BaseCallFilter`). + /// If origin is root then the calls are dispatched without checking origin filter. (This + /// includes bypassing `frame_system::Config::BaseCallFilter`). /// /// # /// - Complexity: O(C) where C is the number of calls to be batched. @@ -403,13 +403,13 @@ pub mod pallet { /// Send a batch of dispatch calls. /// Unlike `batch`, it allows errors and won't interrupt. /// - /// May be called from any origin. + /// May be called from any origin except `None`. /// /// - `calls`: The calls to be dispatched from the same origin. The number of call must not /// exceed the constant: `batched_calls_limit` (available in constant metadata). /// - /// If origin is root then call are dispatch without checking origin filter. (This includes - /// bypassing `frame_system::Config::BaseCallFilter`). + /// If origin is root then the calls are dispatch without checking origin filter. (This + /// includes bypassing `frame_system::Config::BaseCallFilter`). /// /// # /// - Complexity: O(C) where C is the number of calls to be batched. diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 81cec1c295c30..c374f5ae21099 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -27,15 +27,18 @@ use frame_support::{ dispatch::{DispatchError, DispatchErrorWithPostInfo, Dispatchable, Pays}, error::BadOrigin, parameter_types, storage, - traits::{ConstU32, ConstU64, Contains}, + traits::{ConstU32, ConstU64, Contains, GenesisBuild}, weights::Weight, }; +use pallet_collective::{EnsureProportionAtLeast, Instance1}; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, Hash, IdentityLookup}, }; +type BlockNumber = u64; + // example module to test behaviors. #[frame_support::pallet] pub mod example { @@ -82,6 +85,42 @@ pub mod example { } } +mod mock_democracy { + pub use pallet::*; + #[frame_support::pallet] + pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + Sized { + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + type ExternalMajorityOrigin: EnsureOrigin; + } + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + pub fn external_propose_majority(origin: OriginFor) -> DispatchResult { + T::ExternalMajorityOrigin::ensure_origin(origin)?; + Self::deposit_event(Event::::ExternalProposed); + Ok(()) + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + ExternalProposed, + } + } +} + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -92,9 +131,12 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, + Timestamp: pallet_timestamp::{Call, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Council: pallet_collective::, Utility: utility::{Pallet, Call, Event}, Example: example::{Pallet, Call}, + Democracy: mock_democracy::{Pallet, Call, Event}, } ); @@ -140,10 +182,34 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); } + +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<3>; + type WeightInfo = (); +} + +const MOTION_DURATION_IN_BLOCKS: BlockNumber = 3; parameter_types! { pub const MultisigDepositBase: u64 = 1; pub const MultisigDepositFactor: u64 = 1; pub const MaxSignatories: u32 = 3; + pub const MotionDuration: BlockNumber = MOTION_DURATION_IN_BLOCKS; + pub const MaxProposals: u32 = 100; + pub const MaxMembers: u32 = 100; +} + +type CouncilCollective = pallet_collective::Instance1; +impl pallet_collective::Config for Test { + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type MotionDuration = MotionDuration; + type MaxProposals = MaxProposals; + type MaxMembers = MaxMembers; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type WeightInfo = (); } impl example::Config for Test {} @@ -159,10 +225,16 @@ impl Contains for TestBaseCallFilter { RuntimeCall::System(frame_system::Call::remark { .. }) => true, // For tests RuntimeCall::Example(_) => true, + // For council origin tests. + RuntimeCall::Democracy(_) => true, _ => false, } } } +impl mock_democracy::Config for Test { + type RuntimeEvent = RuntimeEvent; + type ExternalMajorityOrigin = EnsureProportionAtLeast; +} impl Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -175,6 +247,7 @@ type UtilityCall = crate::Call; use frame_system::Call as SystemCall; use pallet_balances::{Call as BalancesCall, Error as BalancesError}; +use pallet_timestamp::Call as TimestampCall; pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); @@ -183,6 +256,14 @@ pub fn new_test_ext() -> sp_io::TestExternalities { } .assimilate_storage(&mut t) .unwrap(); + + pallet_collective::GenesisConfig:: { + members: vec![1, 2, 3], + phantom: Default::default(), + } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext @@ -679,3 +760,139 @@ fn none_origin_does_not_work() { assert_noop!(Utility::batch_all(RuntimeOrigin::none(), vec![]), BadOrigin); }) } + +#[test] +fn batch_doesnt_work_with_inherents() { + new_test_ext().execute_with(|| { + // fails because inherents expect the origin to be none. + assert_ok!(Utility::batch( + RuntimeOrigin::signed(1), + vec![RuntimeCall::Timestamp(TimestampCall::set { now: 42 }),] + )); + System::assert_last_event( + utility::Event::BatchInterrupted { + index: 0, + error: frame_system::Error::::CallFiltered.into(), + } + .into(), + ); + }) +} + +#[test] +fn force_batch_doesnt_work_with_inherents() { + new_test_ext().execute_with(|| { + // fails because inherents expect the origin to be none. + assert_ok!(Utility::force_batch( + RuntimeOrigin::root(), + vec![RuntimeCall::Timestamp(TimestampCall::set { now: 42 }),] + )); + System::assert_last_event(utility::Event::BatchCompletedWithErrors.into()); + }) +} + +#[test] +fn batch_all_doesnt_work_with_inherents() { + new_test_ext().execute_with(|| { + let batch_all = RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![RuntimeCall::Timestamp(TimestampCall::set { now: 42 })], + }); + let info = batch_all.get_dispatch_info(); + + // fails because inherents expect the origin to be none. + assert_noop!( + batch_all.dispatch(RuntimeOrigin::signed(1)), + DispatchErrorWithPostInfo { + post_info: PostDispatchInfo { + actual_weight: Some(info.weight), + pays_fee: Pays::Yes + }, + error: frame_system::Error::::CallFiltered.into(), + } + ); + }) +} + +#[test] +fn batch_works_with_council_origin() { + new_test_ext().execute_with(|| { + let proposal = RuntimeCall::Utility(UtilityCall::batch { + calls: vec![RuntimeCall::Democracy(mock_democracy::Call::external_propose_majority {})], + }); + let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); + let proposal_weight = proposal.get_dispatch_info().weight; + let hash = BlakeTwo256::hash_of(&proposal); + + assert_ok!(Council::propose( + RuntimeOrigin::signed(1), + 3, + Box::new(proposal.clone()), + proposal_len + )); + + assert_ok!(Council::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Council::vote(RuntimeOrigin::signed(2), hash, 0, true)); + assert_ok!(Council::vote(RuntimeOrigin::signed(3), hash, 0, true)); + + System::set_block_number(4); + assert_ok!(Council::close( + RuntimeOrigin::signed(4), + hash, + 0, + proposal_weight, + proposal_len + )); + + System::assert_last_event(RuntimeEvent::Council(pallet_collective::Event::Executed { + proposal_hash: hash, + result: Ok(()), + })); + }) +} + +#[test] +fn force_batch_works_with_council_origin() { + new_test_ext().execute_with(|| { + let proposal = RuntimeCall::Utility(UtilityCall::force_batch { + calls: vec![RuntimeCall::Democracy(mock_democracy::Call::external_propose_majority {})], + }); + let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); + let proposal_weight = proposal.get_dispatch_info().weight; + let hash = BlakeTwo256::hash_of(&proposal); + + assert_ok!(Council::propose( + RuntimeOrigin::signed(1), + 3, + Box::new(proposal.clone()), + proposal_len + )); + + assert_ok!(Council::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Council::vote(RuntimeOrigin::signed(2), hash, 0, true)); + assert_ok!(Council::vote(RuntimeOrigin::signed(3), hash, 0, true)); + + System::set_block_number(4); + assert_ok!(Council::close( + RuntimeOrigin::signed(4), + hash, + 0, + proposal_weight, + proposal_len + )); + + System::assert_last_event(RuntimeEvent::Council(pallet_collective::Event::Executed { + proposal_hash: hash, + result: Ok(()), + })); + }) +} + +#[test] +fn batch_all_works_with_council_origin() { + new_test_ext().execute_with(|| { + assert_ok!(Utility::batch_all( + RuntimeOrigin::from(pallet_collective::RawOrigin::Members(3, 3)), + vec![RuntimeCall::Democracy(mock_democracy::Call::external_propose_majority {})] + )); + }) +} From be259234bfee056bef970ac372e04a74411c5224 Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 28 Oct 2022 22:39:59 +0200 Subject: [PATCH 1318/1472] Treat near-zero intercept values as zero when calculating weights (#12573) * Treat near-zero intercept values as zero when calculating weights * Simplify comparison Co-authored-by: Oliver Tale-Yazdi * Update contract weights Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/benchmarking/src/analysis.rs | 20 +- frame/contracts/src/weights.rs | 1708 ++++++++++++++++------------ 2 files changed, 987 insertions(+), 741 deletions(-) diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index db8ee599ef731..0b77a92347d03 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -170,7 +170,8 @@ fn linear_regression( x_vars: usize, ) -> Option<(f64, Vec, Vec)> { let (intercept, params, errors) = raw_linear_regression(&xs, &ys, x_vars, true)?; - if intercept > 0.0 { + if intercept >= -0.0001 { + // The intercept is positive, or is effectively zero. return Some((intercept, params, errors[1..].to_vec())) } @@ -748,4 +749,21 @@ mod tests { assert_eq!(extrinsic_time.base, 3_000_000_000); assert_eq!(extrinsic_time.slopes, vec![3_000_000_000]); } + + #[test] + fn intercept_of_a_little_under_zero_is_rounded_up_to_zero() { + // Analytically this should result in an intercept of 0, but + // due to numerical imprecision this will generate an intercept + // equal to roughly -0.0000000000000004440892098500626 + let data = vec![ + benchmark_result(vec![(BenchmarkParameter::n, 1)], 2, 0, 0, 0), + benchmark_result(vec![(BenchmarkParameter::n, 2)], 4, 0, 0, 0), + benchmark_result(vec![(BenchmarkParameter::n, 3)], 6, 0, 0, 0), + ]; + + let extrinsic_time = + Analysis::min_squares_iqr(&data, BenchmarkSelector::ExtrinsicTime).unwrap(); + assert_eq!(extrinsic_time.base, 0); + assert_eq!(extrinsic_time.slopes, vec![2000]); + } } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 46c86b670a7fe..c42cc41a0bd9c 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,25 +18,25 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-10-28, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet-contracts // --extrinsic=* +// --heap-pages=4096 // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_contracts -// --chain=dev -// --output=./frame/contracts/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --output=frame/contracts/src/weights.rs +// --header=HEADER-APACHE2 +// --template=.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -167,15 +167,17 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(3_108_000 as u64) + // Minimum execution time: 2_904 nanoseconds. + Weight::from_ref_time(3_036_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(15_377_000 as u64) - // Standard Error: 414 - .saturating_add(Weight::from_ref_time(892_761 as u64).saturating_mul(k as u64)) + // Minimum execution time: 14_553 nanoseconds. + Weight::from_ref_time(14_161_469 as u64) + // Standard Error: 593 + .saturating_add(Weight::from_ref_time(894_982 as u64).saturating_mul(k as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -183,18 +185,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(3_127_000 as u64) - // Standard Error: 3_813 - .saturating_add(Weight::from_ref_time(1_379_402 as u64).saturating_mul(q as u64)) + // Minimum execution time: 3_121 nanoseconds. + Weight::from_ref_time(14_262_977 as u64) + // Standard Error: 3_272 + .saturating_add(Weight::from_ref_time(1_232_597 as u64).saturating_mul(q as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(22_849_000 as u64) - // Standard Error: 26 - .saturating_add(Weight::from_ref_time(45_513 as u64).saturating_mul(c as u64)) + // Minimum execution time: 28_625 nanoseconds. + Weight::from_ref_time(31_685_032 as u64) + // Standard Error: 57 + .saturating_add(Weight::from_ref_time(44_024 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -205,9 +210,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(258_275_000 as u64) - // Standard Error: 30 - .saturating_add(Weight::from_ref_time(45_885 as u64).saturating_mul(c as u64)) + // Minimum execution time: 355_167 nanoseconds. + Weight::from_ref_time(330_201_049 as u64) + // Standard Error: 64 + .saturating_add(Weight::from_ref_time(45_952 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -222,11 +228,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(2_115_889_000 as u64) - // Standard Error: 323 - .saturating_add(Weight::from_ref_time(89_541 as u64).saturating_mul(c as u64)) - // Standard Error: 19 - .saturating_add(Weight::from_ref_time(664 as u64).saturating_mul(s as u64)) + // Minimum execution time: 2_165_939 nanoseconds. + Weight::from_ref_time(346_673_842 as u64) + // Standard Error: 73 + .saturating_add(Weight::from_ref_time(107_020 as u64).saturating_mul(c as u64)) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(1_754 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(9 as u64)) } @@ -239,9 +246,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(211_349_000 as u64) + // Minimum execution time: 262_523 nanoseconds. + Weight::from_ref_time(255_633_789 as u64) // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_532 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_485 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(7 as u64)) } @@ -251,7 +259,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(181_771_000 as u64) + // Minimum execution time: 233_124 nanoseconds. + Weight::from_ref_time(233_826_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -261,9 +270,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(55_917_000 as u64) - // Standard Error: 25 - .saturating_add(Weight::from_ref_time(46_148 as u64).saturating_mul(c as u64)) + // Minimum execution time: 61_170 nanoseconds. + Weight::from_ref_time(61_653_502 as u64) + // Standard Error: 47 + .saturating_add(Weight::from_ref_time(45_553 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -272,7 +282,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(37_966_000 as u64) + // Minimum execution time: 37_278 nanoseconds. + Weight::from_ref_time(37_822_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -280,7 +291,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(40_963_000 as u64) + // Minimum execution time: 40_329 nanoseconds. + Weight::from_ref_time(41_017_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -291,9 +303,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(247_526_000 as u64) - // Standard Error: 29_505 - .saturating_add(Weight::from_ref_time(35_107_467 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_717 nanoseconds. + Weight::from_ref_time(347_610_656 as u64) + // Standard Error: 37_159 + .saturating_add(Weight::from_ref_time(35_506_783 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -304,9 +317,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(253_782_000 as u64) - // Standard Error: 256_004 - .saturating_add(Weight::from_ref_time(201_621_188 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_158 nanoseconds. + Weight::from_ref_time(289_982_824 as u64) + // Standard Error: 426_543 + .saturating_add(Weight::from_ref_time(202_123_887 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -318,9 +332,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(249_892_000 as u64) - // Standard Error: 234_750 - .saturating_add(Weight::from_ref_time(258_209_168 as u64).saturating_mul(r as u64)) + // Minimum execution time: 349_141 nanoseconds. + Weight::from_ref_time(297_477_406 as u64) + // Standard Error: 403_411 + .saturating_add(Weight::from_ref_time(258_999_975 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -332,9 +347,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(248_674_000 as u64) - // Standard Error: 23_962 - .saturating_add(Weight::from_ref_time(38_319_695 as u64).saturating_mul(r as u64)) + // Minimum execution time: 347_419 nanoseconds. + Weight::from_ref_time(350_048_279 as u64) + // Standard Error: 22_511 + .saturating_add(Weight::from_ref_time(38_799_515 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -345,9 +361,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(244_345_000 as u64) - // Standard Error: 15_429 - .saturating_add(Weight::from_ref_time(14_751_125 as u64).saturating_mul(r as u64)) + // Minimum execution time: 341_634 nanoseconds. + Weight::from_ref_time(344_394_100 as u64) + // Standard Error: 12_563 + .saturating_add(Weight::from_ref_time(14_529_298 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -358,9 +375,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(247_045_000 as u64) - // Standard Error: 25_949 - .saturating_add(Weight::from_ref_time(35_001_004 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_246 nanoseconds. + Weight::from_ref_time(349_406_095 as u64) + // Standard Error: 28_842 + .saturating_add(Weight::from_ref_time(35_066_080 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -371,9 +389,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(247_176_000 as u64) - // Standard Error: 24_500 - .saturating_add(Weight::from_ref_time(34_447_506 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_003 nanoseconds. + Weight::from_ref_time(349_076_713 as u64) + // Standard Error: 30_507 + .saturating_add(Weight::from_ref_time(34_662_539 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -384,10 +403,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(247_278_000 as u64) - // Standard Error: 48_613 - .saturating_add(Weight::from_ref_time(108_381_432 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) + // Minimum execution time: 346_063 nanoseconds. + Weight::from_ref_time(350_054_605 as u64) + // Standard Error: 68_711 + .saturating_add(Weight::from_ref_time(107_584_776 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -397,9 +417,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(246_996_000 as u64) - // Standard Error: 24_585 - .saturating_add(Weight::from_ref_time(34_615_777 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_057 nanoseconds. + Weight::from_ref_time(349_489_403 as u64) + // Standard Error: 38_116 + .saturating_add(Weight::from_ref_time(34_750_791 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -410,9 +431,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(247_207_000 as u64) - // Standard Error: 30_691 - .saturating_add(Weight::from_ref_time(34_626_552 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_722 nanoseconds. + Weight::from_ref_time(348_659_357 as u64) + // Standard Error: 33_077 + .saturating_add(Weight::from_ref_time(34_845_216 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -423,9 +445,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(247_538_000 as u64) - // Standard Error: 27_128 - .saturating_add(Weight::from_ref_time(34_277_292 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_805 nanoseconds. + Weight::from_ref_time(347_579_287 as u64) + // Standard Error: 28_498 + .saturating_add(Weight::from_ref_time(34_529_480 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -436,9 +459,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(247_398_000 as u64) - // Standard Error: 28_375 - .saturating_add(Weight::from_ref_time(34_573_437 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_943 nanoseconds. + Weight::from_ref_time(348_941_819 as u64) + // Standard Error: 32_278 + .saturating_add(Weight::from_ref_time(34_580_817 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -450,10 +474,11 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(247_732_000 as u64) - // Standard Error: 42_671 - .saturating_add(Weight::from_ref_time(123_110_886 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) + // Minimum execution time: 345_753 nanoseconds. + Weight::from_ref_time(354_733_779 as u64) + // Standard Error: 71_767 + .saturating_add(Weight::from_ref_time(105_098_275 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -463,9 +488,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(170_547_000 as u64) - // Standard Error: 9_163 - .saturating_add(Weight::from_ref_time(15_589_088 as u64).saturating_mul(r as u64)) + // Minimum execution time: 222_866 nanoseconds. + Weight::from_ref_time(226_212_157 as u64) + // Standard Error: 17_326 + .saturating_add(Weight::from_ref_time(15_544_104 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -476,9 +502,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(247_264_000 as u64) - // Standard Error: 23_913 - .saturating_add(Weight::from_ref_time(32_753_431 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_704 nanoseconds. + Weight::from_ref_time(348_160_999 as u64) + // Standard Error: 31_560 + .saturating_add(Weight::from_ref_time(32_888_428 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -489,9 +516,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(282_721_000 as u64) - // Standard Error: 1_978 - .saturating_add(Weight::from_ref_time(9_625_699 as u64).saturating_mul(n as u64)) + // Minimum execution time: 380_814 nanoseconds. + Weight::from_ref_time(403_973_055 as u64) + // Standard Error: 2_690 + .saturating_add(Weight::from_ref_time(9_597_443 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -502,9 +530,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - Weight::from_ref_time(244_356_000 as u64) - // Standard Error: 184_002 - .saturating_add(Weight::from_ref_time(2_423_400 as u64).saturating_mul(r as u64)) + // Minimum execution time: 340_930 nanoseconds. + Weight::from_ref_time(342_218_828 as u64) + // Standard Error: 80_578 + .saturating_add(Weight::from_ref_time(1_547_971 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -515,9 +544,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(246_157_000 as u64) - // Standard Error: 324 - .saturating_add(Weight::from_ref_time(188_687 as u64).saturating_mul(n as u64)) + // Minimum execution time: 343_035 nanoseconds. + Weight::from_ref_time(345_347_882 as u64) + // Standard Error: 509 + .saturating_add(Weight::from_ref_time(228_526 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -530,9 +560,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(247_356_000 as u64) - // Standard Error: 232_552 - .saturating_add(Weight::from_ref_time(55_027_099 as u64).saturating_mul(r as u64)) + // Minimum execution time: 344_997 nanoseconds. + Weight::from_ref_time(346_431_655 as u64) + // Standard Error: 79_924 + .saturating_add(Weight::from_ref_time(53_530_044 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -546,10 +577,11 @@ impl WeightInfo for SubstrateWeight { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(247_069_000 as u64) - // Standard Error: 59_538 - .saturating_add(Weight::from_ref_time(128_858_347 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) + // Minimum execution time: 345_926 nanoseconds. + Weight::from_ref_time(351_620_774 as u64) + // Standard Error: 69_858 + .saturating_add(Weight::from_ref_time(130_846_895 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -559,9 +591,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(244_659_000 as u64) - // Standard Error: 70_677 - .saturating_add(Weight::from_ref_time(239_930_533 as u64).saturating_mul(r as u64)) + // Minimum execution time: 341_582 nanoseconds. + Weight::from_ref_time(353_141_157 as u64) + // Standard Error: 99_764 + .saturating_add(Weight::from_ref_time(231_149_152 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -573,11 +606,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(1_198_350_000 as u64) - // Standard Error: 2_049_556 - .saturating_add(Weight::from_ref_time(70_072_141 as u64).saturating_mul(t as u64)) - // Standard Error: 496_378 - .saturating_add(Weight::from_ref_time(35_566_752 as u64).saturating_mul(n as u64)) + // Minimum execution time: 1_269_467 nanoseconds. + Weight::from_ref_time(566_371_969 as u64) + // Standard Error: 435_714 + .saturating_add(Weight::from_ref_time(180_441_805 as u64).saturating_mul(t as u64)) + // Standard Error: 119_668 + .saturating_add(Weight::from_ref_time(70_111_002 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -590,18 +624,20 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(177_240_000 as u64) - // Standard Error: 18_991 - .saturating_add(Weight::from_ref_time(26_377_453 as u64).saturating_mul(r as u64)) + // Minimum execution time: 231_528 nanoseconds. + Weight::from_ref_time(235_676_870 as u64) + // Standard Error: 20_851 + .saturating_add(Weight::from_ref_time(26_215_920 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(247_795_000 as u64) - // Standard Error: 349_627 - .saturating_add(Weight::from_ref_time(411_421_066 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_509 nanoseconds. + Weight::from_ref_time(301_173_874 as u64) + // Standard Error: 436_884 + .saturating_add(Weight::from_ref_time(415_194_325 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -610,31 +646,34 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(405_147_000 as u64) - // Standard Error: 1_074_466 - .saturating_add(Weight::from_ref_time(120_331_835 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(6 as u64)) - .saturating_add(T::DbWeight::get().writes((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 500_452 nanoseconds. + Weight::from_ref_time(641_506_544 as u64) + // Standard Error: 1_308_973 + .saturating_add(Weight::from_ref_time(98_769_541 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(52 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(50 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(403_403_000 as u64) - // Standard Error: 890_083 - .saturating_add(Weight::from_ref_time(88_023_518 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(6 as u64)) - .saturating_add(T::DbWeight::get().writes((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 500_941 nanoseconds. + Weight::from_ref_time(610_446_049 as u64) + // Standard Error: 1_018_173 + .saturating_add(Weight::from_ref_time(65_568_627 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(49 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(247_929_000 as u64) - // Standard Error: 311_780 - .saturating_add(Weight::from_ref_time(400_904_526 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_820 nanoseconds. + Weight::from_ref_time(302_335_076 as u64) + // Standard Error: 472_676 + .saturating_add(Weight::from_ref_time(395_286_593 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -643,20 +682,22 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(372_378_000 as u64) - // Standard Error: 1_007_061 - .saturating_add(Weight::from_ref_time(92_326_546 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) - .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 457_830 nanoseconds. + Weight::from_ref_time(582_524_868 as u64) + // Standard Error: 1_161_813 + .saturating_add(Weight::from_ref_time(67_291_419 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(48 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(250_165_000 as u64) - // Standard Error: 300_205 - .saturating_add(Weight::from_ref_time(339_092_950 as u64).saturating_mul(r as u64)) + // Minimum execution time: 348_249 nanoseconds. + Weight::from_ref_time(317_329_583 as u64) + // Standard Error: 400_112 + .saturating_add(Weight::from_ref_time(331_362_971 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -664,19 +705,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(352_873_000 as u64) - // Standard Error: 908_425 - .saturating_add(Weight::from_ref_time(176_951_688 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 446_902 nanoseconds. + Weight::from_ref_time(556_989_117 as u64) + // Standard Error: 1_029_959 + .saturating_add(Weight::from_ref_time(159_623_361 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(248_980_000 as u64) - // Standard Error: 295_923 - .saturating_add(Weight::from_ref_time(306_145_709 as u64).saturating_mul(r as u64)) + // Minimum execution time: 347_064 nanoseconds. + Weight::from_ref_time(316_879_171 as u64) + // Standard Error: 355_083 + .saturating_add(Weight::from_ref_time(304_763_264 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -684,19 +727,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(340_418_000 as u64) - // Standard Error: 749_537 - .saturating_add(Weight::from_ref_time(80_040_174 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) - .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 435_275 nanoseconds. + Weight::from_ref_time(527_900_488 as u64) + // Standard Error: 872_763 + .saturating_add(Weight::from_ref_time(60_604_211 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(250_254_000 as u64) - // Standard Error: 328_900 - .saturating_add(Weight::from_ref_time(424_144_552 as u64).saturating_mul(r as u64)) + // Minimum execution time: 348_671 nanoseconds. + Weight::from_ref_time(306_307_186 as u64) + // Standard Error: 438_525 + .saturating_add(Weight::from_ref_time(422_575_502 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -705,13 +750,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(377_849_000 as u64) - // Standard Error: 1_130_582 - .saturating_add(Weight::from_ref_time(188_240_273 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().reads((15 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(5 as u64)) - .saturating_add(T::DbWeight::get().writes((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 470_344 nanoseconds. + Weight::from_ref_time(613_380_073 as u64) + // Standard Error: 1_333_864 + .saturating_add(Weight::from_ref_time(164_398_286 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(48 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -720,12 +766,13 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(249_701_000 as u64) - // Standard Error: 449_896 - .saturating_add(Weight::from_ref_time(1_370_712_846 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) + // Minimum execution time: 348_312 nanoseconds. + Weight::from_ref_time(303_017_886 as u64) + // Standard Error: 568_589 + .saturating_add(Weight::from_ref_time(1_351_508_682 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) @@ -735,10 +782,11 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - Weight::from_ref_time(251_015_000 as u64) - // Standard Error: 7_081_378 - .saturating_add(Weight::from_ref_time(17_258_935_295 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) + // Minimum execution time: 348_997 nanoseconds. + Weight::from_ref_time(349_975_000 as u64) + // Standard Error: 5_689_469 + .saturating_add(Weight::from_ref_time(24_991_501_544 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((160 as u64).saturating_mul(r as u64))) @@ -750,9 +798,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - Weight::from_ref_time(250_660_000 as u64) - // Standard Error: 6_402_989 - .saturating_add(Weight::from_ref_time(17_044_780_887 as u64).saturating_mul(r as u64)) + // Minimum execution time: 348_751 nanoseconds. + Weight::from_ref_time(349_330_000 as u64) + // Standard Error: 7_125_421 + .saturating_add(Weight::from_ref_time(24_917_646_052 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((150 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -766,11 +815,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(11_920_718_000 as u64) - // Standard Error: 11_123_062 - .saturating_add(Weight::from_ref_time(642_326_761 as u64).saturating_mul(t as u64)) - // Standard Error: 9_490 - .saturating_add(Weight::from_ref_time(8_845_752 as u64).saturating_mul(c as u64)) + // Minimum execution time: 16_275_711 nanoseconds. + Weight::from_ref_time(15_203_241_602 as u64) + // Standard Error: 3_582_276 + .saturating_add(Weight::from_ref_time(1_179_848_168 as u64).saturating_mul(t as u64)) + // Standard Error: 5_371 + .saturating_add(Weight::from_ref_time(9_712_484 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(167 as u64)) .saturating_add(T::DbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(163 as u64)) @@ -785,12 +835,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - Weight::from_ref_time(253_804_000 as u64) - // Standard Error: 19_742_198 - .saturating_add(Weight::from_ref_time(22_250_412_835 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) + // Minimum execution time: 353_168 nanoseconds. + Weight::from_ref_time(353_901_000 as u64) + // Standard Error: 18_701_989 + .saturating_add(Weight::from_ref_time(30_028_672_644 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().reads((400 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) .saturating_add(T::DbWeight::get().writes((400 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:81 w:81) @@ -803,9 +854,10 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(13_921_591_000 as u64) - // Standard Error: 22_601 - .saturating_add(Weight::from_ref_time(125_945_348 as u64).saturating_mul(s as u64)) + // Minimum execution time: 18_226_984 nanoseconds. + Weight::from_ref_time(18_032_466_983 as u64) + // Standard Error: 75_544 + .saturating_add(Weight::from_ref_time(121_087_538 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(249 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(247 as u64)) @@ -818,9 +870,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(247_842_000 as u64) - // Standard Error: 219_853 - .saturating_add(Weight::from_ref_time(58_013_100 as u64).saturating_mul(r as u64)) + // Minimum execution time: 344_334 nanoseconds. + Weight::from_ref_time(345_939_404 as u64) + // Standard Error: 98_994 + .saturating_add(Weight::from_ref_time(58_015_295 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -831,9 +884,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(305_607_000 as u64) - // Standard Error: 71_234 - .saturating_add(Weight::from_ref_time(323_093_184 as u64).saturating_mul(n as u64)) + // Minimum execution time: 402_492 nanoseconds. + Weight::from_ref_time(402_789_000 as u64) + // Standard Error: 54_174 + .saturating_add(Weight::from_ref_time(324_036_889 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -844,9 +898,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(247_351_000 as u64) - // Standard Error: 271_656 - .saturating_add(Weight::from_ref_time(74_344_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 343_493 nanoseconds. + Weight::from_ref_time(345_116_214 as u64) + // Standard Error: 90_515 + .saturating_add(Weight::from_ref_time(71_282_485 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -857,9 +912,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(315_626_000 as u64) - // Standard Error: 56_955 - .saturating_add(Weight::from_ref_time(246_316_261 as u64).saturating_mul(n as u64)) + // Minimum execution time: 415_650 nanoseconds. + Weight::from_ref_time(415_894_000 as u64) + // Standard Error: 58_077 + .saturating_add(Weight::from_ref_time(248_416_317 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -870,9 +926,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(246_887_000 as u64) - // Standard Error: 286_822 - .saturating_add(Weight::from_ref_time(52_242_599 as u64).saturating_mul(r as u64)) + // Minimum execution time: 343_890 nanoseconds. + Weight::from_ref_time(345_542_924 as u64) + // Standard Error: 87_564 + .saturating_add(Weight::from_ref_time(47_361_375 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -883,9 +940,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(294_818_000 as u64) - // Standard Error: 52_394 - .saturating_add(Weight::from_ref_time(96_353_967 as u64).saturating_mul(n as u64)) + // Minimum execution time: 391_629 nanoseconds. + Weight::from_ref_time(392_793_000 as u64) + // Standard Error: 51_120 + .saturating_add(Weight::from_ref_time(99_288_467 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -896,9 +954,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(245_334_000 as u64) - // Standard Error: 303_979 - .saturating_add(Weight::from_ref_time(50_180_800 as u64).saturating_mul(r as u64)) + // Minimum execution time: 341_701 nanoseconds. + Weight::from_ref_time(343_318_489 as u64) + // Standard Error: 103_756 + .saturating_add(Weight::from_ref_time(47_301_910 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -909,9 +968,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(288_995_000 as u64) - // Standard Error: 51_161 - .saturating_add(Weight::from_ref_time(96_331_905 as u64).saturating_mul(n as u64)) + // Minimum execution time: 389_898 nanoseconds. + Weight::from_ref_time(390_489_000 as u64) + // Standard Error: 52_301 + .saturating_add(Weight::from_ref_time(99_344_068 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -922,9 +982,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(249_935_000 as u64) - // Standard Error: 662_188 - .saturating_add(Weight::from_ref_time(3_025_889_600 as u64).saturating_mul(r as u64)) + // Minimum execution time: 348_789 nanoseconds. + Weight::from_ref_time(350_451_620 as u64) + // Standard Error: 195_939 + .saturating_add(Weight::from_ref_time(2_962_830_479 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -935,9 +996,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(248_094_000 as u64) - // Standard Error: 535_446 - .saturating_add(Weight::from_ref_time(2_086_979_500 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_537 nanoseconds. + Weight::from_ref_time(347_926_836 as u64) + // Standard Error: 110_557 + .saturating_add(Weight::from_ref_time(2_058_656_763 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -949,319 +1011,371 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(248_254_000 as u64) - // Standard Error: 1_340_955 - .saturating_add(Weight::from_ref_time(1_065_939_603 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_672 nanoseconds. + Weight::from_ref_time(347_628_000 as u64) + // Standard Error: 2_742_329 + .saturating_add(Weight::from_ref_time(1_370_383_386 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((150 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().reads((225 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((150 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(70_705_000 as u64) - // Standard Error: 7_175 - .saturating_add(Weight::from_ref_time(983_586 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_029 nanoseconds. + Weight::from_ref_time(118_800_774 as u64) + // Standard Error: 4_234 + .saturating_add(Weight::from_ref_time(866_719 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(69_659_000 as u64) - // Standard Error: 1_140 - .saturating_add(Weight::from_ref_time(3_004_307 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_145 nanoseconds. + Weight::from_ref_time(118_644_813 as u64) + // Standard Error: 2_692 + .saturating_add(Weight::from_ref_time(2_874_276 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(69_621_000 as u64) - // Standard Error: 2_871 - .saturating_add(Weight::from_ref_time(2_715_451 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_142 nanoseconds. + Weight::from_ref_time(118_474_161 as u64) + // Standard Error: 6_997 + .saturating_add(Weight::from_ref_time(2_769_076 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(69_459_000 as u64) - // Standard Error: 3_284 - .saturating_add(Weight::from_ref_time(2_581_283 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_020 nanoseconds. + Weight::from_ref_time(118_499_103 as u64) + // Standard Error: 1_266 + .saturating_add(Weight::from_ref_time(2_351_397 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_558_000 as u64) - // Standard Error: 2_509 - .saturating_add(Weight::from_ref_time(2_906_689 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_008 nanoseconds. + Weight::from_ref_time(118_398_803 as u64) + // Standard Error: 750 + .saturating_add(Weight::from_ref_time(2_480_061 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(69_407_000 as u64) - // Standard Error: 1_697 - .saturating_add(Weight::from_ref_time(1_702_534 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_046 nanoseconds. + Weight::from_ref_time(118_332_903 as u64) + // Standard Error: 234 + .saturating_add(Weight::from_ref_time(1_426_355 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_477_000 as u64) - // Standard Error: 1_733 - .saturating_add(Weight::from_ref_time(2_192_641 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_998 nanoseconds. + Weight::from_ref_time(117_910_870 as u64) + // Standard Error: 4_629 + .saturating_add(Weight::from_ref_time(1_992_697 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(69_424_000 as u64) - // Standard Error: 2_096 - .saturating_add(Weight::from_ref_time(2_435_708 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_998 nanoseconds. + Weight::from_ref_time(118_059_139 as u64) + // Standard Error: 1_985 + .saturating_add(Weight::from_ref_time(2_164_252 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(72_883_000 as u64) - // Standard Error: 209 - .saturating_add(Weight::from_ref_time(6_874 as u64).saturating_mul(e as u64)) + // Minimum execution time: 121_282 nanoseconds. + Weight::from_ref_time(121_483_289 as u64) + // Standard Error: 57 + .saturating_add(Weight::from_ref_time(4_013 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(69_422_000 as u64) - // Standard Error: 5_030 - .saturating_add(Weight::from_ref_time(7_638_087 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_128 nanoseconds. + Weight::from_ref_time(118_869_764 as u64) + // Standard Error: 8_890 + .saturating_add(Weight::from_ref_time(6_496_684 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(83_136_000 as u64) - // Standard Error: 7_751 - .saturating_add(Weight::from_ref_time(9_543_944 as u64).saturating_mul(r as u64)) + // Minimum execution time: 131_764 nanoseconds. + Weight::from_ref_time(133_009_514 as u64) + // Standard Error: 9_697 + .saturating_add(Weight::from_ref_time(8_310_784 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(93_281_000 as u64) - // Standard Error: 1_967 - .saturating_add(Weight::from_ref_time(596_591 as u64).saturating_mul(p as u64)) + // Minimum execution time: 141_100 nanoseconds. + Weight::from_ref_time(142_282_540 as u64) + // Standard Error: 867 + .saturating_add(Weight::from_ref_time(536_814 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(69_702_000 as u64) - // Standard Error: 1_112 - .saturating_add(Weight::from_ref_time(1_094_685 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_535 nanoseconds. + Weight::from_ref_time(119_017_162 as u64) + // Standard Error: 1_175 + .saturating_add(Weight::from_ref_time(911_141 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(69_720_000 as u64) - // Standard Error: 1_768 - .saturating_add(Weight::from_ref_time(1_045_163 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_472 nanoseconds. + Weight::from_ref_time(118_790_737 as u64) + // Standard Error: 758 + .saturating_add(Weight::from_ref_time(962_148 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(69_716_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_541_622 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_551 nanoseconds. + Weight::from_ref_time(119_070_827 as u64) + // Standard Error: 2_411 + .saturating_add(Weight::from_ref_time(1_367_622 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(72_315_000 as u64) - // Standard Error: 1_081 - .saturating_add(Weight::from_ref_time(1_646_437 as u64).saturating_mul(r as u64)) + // Minimum execution time: 120_958 nanoseconds. + Weight::from_ref_time(121_649_052 as u64) + // Standard Error: 1_557 + .saturating_add(Weight::from_ref_time(1_447_477 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(72_256_000 as u64) - // Standard Error: 1_749 - .saturating_add(Weight::from_ref_time(1_664_891 as u64).saturating_mul(r as u64)) + // Minimum execution time: 120_866 nanoseconds. + Weight::from_ref_time(121_040_400 as u64) + // Standard Error: 6_203 + .saturating_add(Weight::from_ref_time(1_548_715 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(69_616_000 as u64) - // Standard Error: 1_303 - .saturating_add(Weight::from_ref_time(1_017_254 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_076 nanoseconds. + Weight::from_ref_time(118_381_010 as u64) + // Standard Error: 1_814 + .saturating_add(Weight::from_ref_time(938_699 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(70_943_000 as u64) - // Standard Error: 120_139 - .saturating_add(Weight::from_ref_time(183_262_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_030 nanoseconds. + Weight::from_ref_time(120_331_261 as u64) + // Standard Error: 333_364 + .saturating_add(Weight::from_ref_time(227_636_638 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(70_953_000 as u64) - // Standard Error: 2_591 - .saturating_add(Weight::from_ref_time(1_458_584 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_056 nanoseconds. + Weight::from_ref_time(118_554_799 as u64) + // Standard Error: 1_269 + .saturating_add(Weight::from_ref_time(1_331_717 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(69_439_000 as u64) - // Standard Error: 1_822 - .saturating_add(Weight::from_ref_time(1_486_431 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_009 nanoseconds. + Weight::from_ref_time(118_678_537 as u64) + // Standard Error: 1_699 + .saturating_add(Weight::from_ref_time(1_328_153 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(69_366_000 as u64) - // Standard Error: 2_674 - .saturating_add(Weight::from_ref_time(1_506_755 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_031 nanoseconds. + Weight::from_ref_time(118_478_616 as u64) + // Standard Error: 1_533 + .saturating_add(Weight::from_ref_time(1_335_254 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(69_386_000 as u64) - // Standard Error: 3_040 - .saturating_add(Weight::from_ref_time(1_509_928 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_910 nanoseconds. + Weight::from_ref_time(118_471_672 as u64) + // Standard Error: 1_275 + .saturating_add(Weight::from_ref_time(1_345_140 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(69_432_000 as u64) - // Standard Error: 1_875 - .saturating_add(Weight::from_ref_time(1_439_336 as u64).saturating_mul(r as u64)) + // Minimum execution time: 119_504 nanoseconds. + Weight::from_ref_time(118_940_207 as u64) + // Standard Error: 2_512 + .saturating_add(Weight::from_ref_time(1_307_954 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(69_488_000 as u64) - // Standard Error: 1_654 - .saturating_add(Weight::from_ref_time(1_429_318 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_009 nanoseconds. + Weight::from_ref_time(118_366_251 as u64) + // Standard Error: 1_116 + .saturating_add(Weight::from_ref_time(1_322_232 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(69_414_000 as u64) - // Standard Error: 2_773 - .saturating_add(Weight::from_ref_time(1_499_116 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_020 nanoseconds. + Weight::from_ref_time(118_222_792 as u64) + // Standard Error: 1_973 + .saturating_add(Weight::from_ref_time(1_336_896 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(69_427_000 as u64) - // Standard Error: 2_404 - .saturating_add(Weight::from_ref_time(1_969_697 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_038 nanoseconds. + Weight::from_ref_time(118_757_016 as u64) + // Standard Error: 7_932 + .saturating_add(Weight::from_ref_time(1_867_807 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(70_793_000 as u64) - // Standard Error: 1_765 - .saturating_add(Weight::from_ref_time(1_924_169 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_041 nanoseconds. + Weight::from_ref_time(118_717_403 as u64) + // Standard Error: 8_010 + .saturating_add(Weight::from_ref_time(1_868_876 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(69_551_000 as u64) - // Standard Error: 3_955 - .saturating_add(Weight::from_ref_time(1_988_825 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_057 nanoseconds. + Weight::from_ref_time(118_560_106 as u64) + // Standard Error: 1_362 + .saturating_add(Weight::from_ref_time(1_869_820 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(69_510_000 as u64) - // Standard Error: 3_797 - .saturating_add(Weight::from_ref_time(1_976_317 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_045 nanoseconds. + Weight::from_ref_time(118_318_194 as u64) + // Standard Error: 179 + .saturating_add(Weight::from_ref_time(1_873_670 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(69_399_000 as u64) - // Standard Error: 3_255 - .saturating_add(Weight::from_ref_time(1_975_054 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_000 nanoseconds. + Weight::from_ref_time(118_520_606 as u64) + // Standard Error: 3_656 + .saturating_add(Weight::from_ref_time(1_870_762 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(69_425_000 as u64) - // Standard Error: 1_738 - .saturating_add(Weight::from_ref_time(1_959_864 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_035 nanoseconds. + Weight::from_ref_time(118_464_151 as u64) + // Standard Error: 1_073 + .saturating_add(Weight::from_ref_time(1_870_309 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(69_514_000 as u64) - // Standard Error: 9_227 - .saturating_add(Weight::from_ref_time(1_984_750 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_071 nanoseconds. + Weight::from_ref_time(118_470_365 as u64) + // Standard Error: 1_224 + .saturating_add(Weight::from_ref_time(1_870_522 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(69_415_000 as u64) - // Standard Error: 2_052 - .saturating_add(Weight::from_ref_time(1_967_146 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_032 nanoseconds. + Weight::from_ref_time(118_407_669 as u64) + // Standard Error: 769 + .saturating_add(Weight::from_ref_time(1_883_635 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(69_348_000 as u64) - // Standard Error: 3_647 - .saturating_add(Weight::from_ref_time(1_996_141 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_044 nanoseconds. + Weight::from_ref_time(118_324_106 as u64) + // Standard Error: 523 + .saturating_add(Weight::from_ref_time(1_874_728 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(69_448_000 as u64) - // Standard Error: 1_960 - .saturating_add(Weight::from_ref_time(1_956_889 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_111 nanoseconds. + Weight::from_ref_time(118_538_748 as u64) + // Standard Error: 3_498 + .saturating_add(Weight::from_ref_time(1_868_932 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(69_443_000 as u64) - // Standard Error: 20_301 - .saturating_add(Weight::from_ref_time(2_072_285 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_060 nanoseconds. + Weight::from_ref_time(118_421_175 as u64) + // Standard Error: 962 + .saturating_add(Weight::from_ref_time(1_850_713 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(69_458_000 as u64) - // Standard Error: 3_210 - .saturating_add(Weight::from_ref_time(1_970_367 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_050 nanoseconds. + Weight::from_ref_time(118_774_937 as u64) + // Standard Error: 1_717 + .saturating_add(Weight::from_ref_time(1_838_127 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(69_429_000 as u64) - // Standard Error: 3_475 - .saturating_add(Weight::from_ref_time(1_977_800 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_997 nanoseconds. + Weight::from_ref_time(118_626_785 as u64) + // Standard Error: 1_382 + .saturating_add(Weight::from_ref_time(1_842_530 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(69_414_000 as u64) - // Standard Error: 2_659 - .saturating_add(Weight::from_ref_time(2_797_503 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_064 nanoseconds. + Weight::from_ref_time(118_404_203 as u64) + // Standard Error: 2_437 + .saturating_add(Weight::from_ref_time(2_489_569 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(69_460_000 as u64) - // Standard Error: 2_399 - .saturating_add(Weight::from_ref_time(2_646_574 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_949 nanoseconds. + Weight::from_ref_time(118_525_228 as u64) + // Standard Error: 2_231 + .saturating_add(Weight::from_ref_time(2_453_863 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(69_441_000 as u64) - // Standard Error: 2_179 - .saturating_add(Weight::from_ref_time(2_860_283 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_032 nanoseconds. + Weight::from_ref_time(118_311_431 as u64) + // Standard Error: 175 + .saturating_add(Weight::from_ref_time(2_532_745 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(69_401_000 as u64) - // Standard Error: 2_639 - .saturating_add(Weight::from_ref_time(2_582_137 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_987 nanoseconds. + Weight::from_ref_time(118_573_115 as u64) + // Standard Error: 1_814 + .saturating_add(Weight::from_ref_time(2_438_519 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(69_426_000 as u64) - // Standard Error: 2_379 - .saturating_add(Weight::from_ref_time(1_986_578 as u64).saturating_mul(r as u64)) + // Minimum execution time: 120_001 nanoseconds. + Weight::from_ref_time(118_527_518 as u64) + // Standard Error: 1_040 + .saturating_add(Weight::from_ref_time(1_874_359 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(69_599_000 as u64) - // Standard Error: 2_918 - .saturating_add(Weight::from_ref_time(1_991_834 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_051 nanoseconds. + Weight::from_ref_time(118_315_649 as u64) + // Standard Error: 163 + .saturating_add(Weight::from_ref_time(1_851_162 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(71_142_000 as u64) - // Standard Error: 2_659 - .saturating_add(Weight::from_ref_time(1_948_956 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_038 nanoseconds. + Weight::from_ref_time(118_558_677 as u64) + // Standard Error: 2_258 + .saturating_add(Weight::from_ref_time(1_845_713 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(69_407_000 as u64) - // Standard Error: 4_100 - .saturating_add(Weight::from_ref_time(2_030_715 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_985 nanoseconds. + Weight::from_ref_time(118_660_597 as u64) + // Standard Error: 5_893 + .saturating_add(Weight::from_ref_time(1_887_423 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(69_534_000 as u64) - // Standard Error: 2_305 - .saturating_add(Weight::from_ref_time(1_989_346 as u64).saturating_mul(r as u64)) + // Minimum execution time: 120_101 nanoseconds. + Weight::from_ref_time(118_522_424 as u64) + // Standard Error: 1_094 + .saturating_add(Weight::from_ref_time(1_867_495 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(69_432_000 as u64) - // Standard Error: 2_747 - .saturating_add(Weight::from_ref_time(2_002_548 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_068 nanoseconds. + Weight::from_ref_time(119_012_941 as u64) + // Standard Error: 9_129 + .saturating_add(Weight::from_ref_time(1_877_850 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(69_465_000 as u64) - // Standard Error: 9_644 - .saturating_add(Weight::from_ref_time(2_045_830 as u64).saturating_mul(r as u64)) + // Minimum execution time: 120_105 nanoseconds. + Weight::from_ref_time(118_559_474 as u64) + // Standard Error: 2_055 + .saturating_add(Weight::from_ref_time(1_868_662 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(69_435_000 as u64) - // Standard Error: 2_271 - .saturating_add(Weight::from_ref_time(2_001_986 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_004 nanoseconds. + Weight::from_ref_time(118_370_466 as u64) + // Standard Error: 818 + .saturating_add(Weight::from_ref_time(1_873_459 as u64).saturating_mul(r as u64)) } } @@ -1269,15 +1383,17 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(3_108_000 as u64) + // Minimum execution time: 2_904 nanoseconds. + Weight::from_ref_time(3_036_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(15_377_000 as u64) - // Standard Error: 414 - .saturating_add(Weight::from_ref_time(892_761 as u64).saturating_mul(k as u64)) + // Minimum execution time: 14_553 nanoseconds. + Weight::from_ref_time(14_161_469 as u64) + // Standard Error: 593 + .saturating_add(Weight::from_ref_time(894_982 as u64).saturating_mul(k as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -1285,18 +1401,21 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(3_127_000 as u64) - // Standard Error: 3_813 - .saturating_add(Weight::from_ref_time(1_379_402 as u64).saturating_mul(q as u64)) + // Minimum execution time: 3_121 nanoseconds. + Weight::from_ref_time(14_262_977 as u64) + // Standard Error: 3_272 + .saturating_add(Weight::from_ref_time(1_232_597 as u64).saturating_mul(q as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(22_849_000 as u64) - // Standard Error: 26 - .saturating_add(Weight::from_ref_time(45_513 as u64).saturating_mul(c as u64)) + // Minimum execution time: 28_625 nanoseconds. + Weight::from_ref_time(31_685_032 as u64) + // Standard Error: 57 + .saturating_add(Weight::from_ref_time(44_024 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1307,9 +1426,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(258_275_000 as u64) - // Standard Error: 30 - .saturating_add(Weight::from_ref_time(45_885 as u64).saturating_mul(c as u64)) + // Minimum execution time: 355_167 nanoseconds. + Weight::from_ref_time(330_201_049 as u64) + // Standard Error: 64 + .saturating_add(Weight::from_ref_time(45_952 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1324,11 +1444,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(2_115_889_000 as u64) - // Standard Error: 323 - .saturating_add(Weight::from_ref_time(89_541 as u64).saturating_mul(c as u64)) - // Standard Error: 19 - .saturating_add(Weight::from_ref_time(664 as u64).saturating_mul(s as u64)) + // Minimum execution time: 2_165_939 nanoseconds. + Weight::from_ref_time(346_673_842 as u64) + // Standard Error: 73 + .saturating_add(Weight::from_ref_time(107_020 as u64).saturating_mul(c as u64)) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(1_754 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(9 as u64)) } @@ -1341,9 +1462,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(211_349_000 as u64) + // Minimum execution time: 262_523 nanoseconds. + Weight::from_ref_time(255_633_789 as u64) // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_532 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_485 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(7 as u64)) } @@ -1353,7 +1475,8 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(181_771_000 as u64) + // Minimum execution time: 233_124 nanoseconds. + Weight::from_ref_time(233_826_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1363,9 +1486,10 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(55_917_000 as u64) - // Standard Error: 25 - .saturating_add(Weight::from_ref_time(46_148 as u64).saturating_mul(c as u64)) + // Minimum execution time: 61_170 nanoseconds. + Weight::from_ref_time(61_653_502 as u64) + // Standard Error: 47 + .saturating_add(Weight::from_ref_time(45_553 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1374,7 +1498,8 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(37_966_000 as u64) + // Minimum execution time: 37_278 nanoseconds. + Weight::from_ref_time(37_822_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1382,7 +1507,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(40_963_000 as u64) + // Minimum execution time: 40_329 nanoseconds. + Weight::from_ref_time(41_017_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -1393,9 +1519,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(247_526_000 as u64) - // Standard Error: 29_505 - .saturating_add(Weight::from_ref_time(35_107_467 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_717 nanoseconds. + Weight::from_ref_time(347_610_656 as u64) + // Standard Error: 37_159 + .saturating_add(Weight::from_ref_time(35_506_783 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1406,9 +1533,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(253_782_000 as u64) - // Standard Error: 256_004 - .saturating_add(Weight::from_ref_time(201_621_188 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_158 nanoseconds. + Weight::from_ref_time(289_982_824 as u64) + // Standard Error: 426_543 + .saturating_add(Weight::from_ref_time(202_123_887 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1420,9 +1548,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(249_892_000 as u64) - // Standard Error: 234_750 - .saturating_add(Weight::from_ref_time(258_209_168 as u64).saturating_mul(r as u64)) + // Minimum execution time: 349_141 nanoseconds. + Weight::from_ref_time(297_477_406 as u64) + // Standard Error: 403_411 + .saturating_add(Weight::from_ref_time(258_999_975 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1434,9 +1563,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(248_674_000 as u64) - // Standard Error: 23_962 - .saturating_add(Weight::from_ref_time(38_319_695 as u64).saturating_mul(r as u64)) + // Minimum execution time: 347_419 nanoseconds. + Weight::from_ref_time(350_048_279 as u64) + // Standard Error: 22_511 + .saturating_add(Weight::from_ref_time(38_799_515 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1447,9 +1577,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(244_345_000 as u64) - // Standard Error: 15_429 - .saturating_add(Weight::from_ref_time(14_751_125 as u64).saturating_mul(r as u64)) + // Minimum execution time: 341_634 nanoseconds. + Weight::from_ref_time(344_394_100 as u64) + // Standard Error: 12_563 + .saturating_add(Weight::from_ref_time(14_529_298 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1460,9 +1591,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(247_045_000 as u64) - // Standard Error: 25_949 - .saturating_add(Weight::from_ref_time(35_001_004 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_246 nanoseconds. + Weight::from_ref_time(349_406_095 as u64) + // Standard Error: 28_842 + .saturating_add(Weight::from_ref_time(35_066_080 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1473,9 +1605,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(247_176_000 as u64) - // Standard Error: 24_500 - .saturating_add(Weight::from_ref_time(34_447_506 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_003 nanoseconds. + Weight::from_ref_time(349_076_713 as u64) + // Standard Error: 30_507 + .saturating_add(Weight::from_ref_time(34_662_539 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1486,10 +1619,11 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(247_278_000 as u64) - // Standard Error: 48_613 - .saturating_add(Weight::from_ref_time(108_381_432 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) + // Minimum execution time: 346_063 nanoseconds. + Weight::from_ref_time(350_054_605 as u64) + // Standard Error: 68_711 + .saturating_add(Weight::from_ref_time(107_584_776 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -1499,9 +1633,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(246_996_000 as u64) - // Standard Error: 24_585 - .saturating_add(Weight::from_ref_time(34_615_777 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_057 nanoseconds. + Weight::from_ref_time(349_489_403 as u64) + // Standard Error: 38_116 + .saturating_add(Weight::from_ref_time(34_750_791 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1512,9 +1647,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(247_207_000 as u64) - // Standard Error: 30_691 - .saturating_add(Weight::from_ref_time(34_626_552 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_722 nanoseconds. + Weight::from_ref_time(348_659_357 as u64) + // Standard Error: 33_077 + .saturating_add(Weight::from_ref_time(34_845_216 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1525,9 +1661,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(247_538_000 as u64) - // Standard Error: 27_128 - .saturating_add(Weight::from_ref_time(34_277_292 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_805 nanoseconds. + Weight::from_ref_time(347_579_287 as u64) + // Standard Error: 28_498 + .saturating_add(Weight::from_ref_time(34_529_480 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1538,9 +1675,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(247_398_000 as u64) - // Standard Error: 28_375 - .saturating_add(Weight::from_ref_time(34_573_437 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_943 nanoseconds. + Weight::from_ref_time(348_941_819 as u64) + // Standard Error: 32_278 + .saturating_add(Weight::from_ref_time(34_580_817 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1552,10 +1690,11 @@ impl WeightInfo for () { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(247_732_000 as u64) - // Standard Error: 42_671 - .saturating_add(Weight::from_ref_time(123_110_886 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) + // Minimum execution time: 345_753 nanoseconds. + Weight::from_ref_time(354_733_779 as u64) + // Standard Error: 71_767 + .saturating_add(Weight::from_ref_time(105_098_275 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -1565,9 +1704,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(170_547_000 as u64) - // Standard Error: 9_163 - .saturating_add(Weight::from_ref_time(15_589_088 as u64).saturating_mul(r as u64)) + // Minimum execution time: 222_866 nanoseconds. + Weight::from_ref_time(226_212_157 as u64) + // Standard Error: 17_326 + .saturating_add(Weight::from_ref_time(15_544_104 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1578,9 +1718,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(247_264_000 as u64) - // Standard Error: 23_913 - .saturating_add(Weight::from_ref_time(32_753_431 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_704 nanoseconds. + Weight::from_ref_time(348_160_999 as u64) + // Standard Error: 31_560 + .saturating_add(Weight::from_ref_time(32_888_428 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1591,9 +1732,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(282_721_000 as u64) - // Standard Error: 1_978 - .saturating_add(Weight::from_ref_time(9_625_699 as u64).saturating_mul(n as u64)) + // Minimum execution time: 380_814 nanoseconds. + Weight::from_ref_time(403_973_055 as u64) + // Standard Error: 2_690 + .saturating_add(Weight::from_ref_time(9_597_443 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1604,9 +1746,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - Weight::from_ref_time(244_356_000 as u64) - // Standard Error: 184_002 - .saturating_add(Weight::from_ref_time(2_423_400 as u64).saturating_mul(r as u64)) + // Minimum execution time: 340_930 nanoseconds. + Weight::from_ref_time(342_218_828 as u64) + // Standard Error: 80_578 + .saturating_add(Weight::from_ref_time(1_547_971 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1617,9 +1760,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(246_157_000 as u64) - // Standard Error: 324 - .saturating_add(Weight::from_ref_time(188_687 as u64).saturating_mul(n as u64)) + // Minimum execution time: 343_035 nanoseconds. + Weight::from_ref_time(345_347_882 as u64) + // Standard Error: 509 + .saturating_add(Weight::from_ref_time(228_526 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1632,9 +1776,10 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(247_356_000 as u64) - // Standard Error: 232_552 - .saturating_add(Weight::from_ref_time(55_027_099 as u64).saturating_mul(r as u64)) + // Minimum execution time: 344_997 nanoseconds. + Weight::from_ref_time(346_431_655 as u64) + // Standard Error: 79_924 + .saturating_add(Weight::from_ref_time(53_530_044 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1648,10 +1793,11 @@ impl WeightInfo for () { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(247_069_000 as u64) - // Standard Error: 59_538 - .saturating_add(Weight::from_ref_time(128_858_347 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) + // Minimum execution time: 345_926 nanoseconds. + Weight::from_ref_time(351_620_774 as u64) + // Standard Error: 69_858 + .saturating_add(Weight::from_ref_time(130_846_895 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) @@ -1661,9 +1807,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(244_659_000 as u64) - // Standard Error: 70_677 - .saturating_add(Weight::from_ref_time(239_930_533 as u64).saturating_mul(r as u64)) + // Minimum execution time: 341_582 nanoseconds. + Weight::from_ref_time(353_141_157 as u64) + // Standard Error: 99_764 + .saturating_add(Weight::from_ref_time(231_149_152 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1675,11 +1822,12 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(1_198_350_000 as u64) - // Standard Error: 2_049_556 - .saturating_add(Weight::from_ref_time(70_072_141 as u64).saturating_mul(t as u64)) - // Standard Error: 496_378 - .saturating_add(Weight::from_ref_time(35_566_752 as u64).saturating_mul(n as u64)) + // Minimum execution time: 1_269_467 nanoseconds. + Weight::from_ref_time(566_371_969 as u64) + // Standard Error: 435_714 + .saturating_add(Weight::from_ref_time(180_441_805 as u64).saturating_mul(t as u64)) + // Standard Error: 119_668 + .saturating_add(Weight::from_ref_time(70_111_002 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1692,18 +1840,20 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(177_240_000 as u64) - // Standard Error: 18_991 - .saturating_add(Weight::from_ref_time(26_377_453 as u64).saturating_mul(r as u64)) + // Minimum execution time: 231_528 nanoseconds. + Weight::from_ref_time(235_676_870 as u64) + // Standard Error: 20_851 + .saturating_add(Weight::from_ref_time(26_215_920 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(247_795_000 as u64) - // Standard Error: 349_627 - .saturating_add(Weight::from_ref_time(411_421_066 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_509 nanoseconds. + Weight::from_ref_time(301_173_874 as u64) + // Standard Error: 436_884 + .saturating_add(Weight::from_ref_time(415_194_325 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1712,31 +1862,34 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(405_147_000 as u64) - // Standard Error: 1_074_466 - .saturating_add(Weight::from_ref_time(120_331_835 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) - .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) - .saturating_add(RocksDbWeight::get().writes((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 500_452 nanoseconds. + Weight::from_ref_time(641_506_544 as u64) + // Standard Error: 1_308_973 + .saturating_add(Weight::from_ref_time(98_769_541 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(52 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(50 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(403_403_000 as u64) - // Standard Error: 890_083 - .saturating_add(Weight::from_ref_time(88_023_518 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) - .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) - .saturating_add(RocksDbWeight::get().writes((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 500_941 nanoseconds. + Weight::from_ref_time(610_446_049 as u64) + // Standard Error: 1_018_173 + .saturating_add(Weight::from_ref_time(65_568_627 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(49 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(247_929_000 as u64) - // Standard Error: 311_780 - .saturating_add(Weight::from_ref_time(400_904_526 as u64).saturating_mul(r as u64)) + // Minimum execution time: 345_820 nanoseconds. + Weight::from_ref_time(302_335_076 as u64) + // Standard Error: 472_676 + .saturating_add(Weight::from_ref_time(395_286_593 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1745,20 +1898,22 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(372_378_000 as u64) - // Standard Error: 1_007_061 - .saturating_add(Weight::from_ref_time(92_326_546 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) - .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 457_830 nanoseconds. + Weight::from_ref_time(582_524_868 as u64) + // Standard Error: 1_161_813 + .saturating_add(Weight::from_ref_time(67_291_419 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(48 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(250_165_000 as u64) - // Standard Error: 300_205 - .saturating_add(Weight::from_ref_time(339_092_950 as u64).saturating_mul(r as u64)) + // Minimum execution time: 348_249 nanoseconds. + Weight::from_ref_time(317_329_583 as u64) + // Standard Error: 400_112 + .saturating_add(Weight::from_ref_time(331_362_971 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1766,19 +1921,21 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(352_873_000 as u64) - // Standard Error: 908_425 - .saturating_add(Weight::from_ref_time(176_951_688 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) - .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 446_902 nanoseconds. + Weight::from_ref_time(556_989_117 as u64) + // Standard Error: 1_029_959 + .saturating_add(Weight::from_ref_time(159_623_361 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(248_980_000 as u64) - // Standard Error: 295_923 - .saturating_add(Weight::from_ref_time(306_145_709 as u64).saturating_mul(r as u64)) + // Minimum execution time: 347_064 nanoseconds. + Weight::from_ref_time(316_879_171 as u64) + // Standard Error: 355_083 + .saturating_add(Weight::from_ref_time(304_763_264 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1786,19 +1943,21 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(340_418_000 as u64) - // Standard Error: 749_537 - .saturating_add(Weight::from_ref_time(80_040_174 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) - .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 435_275 nanoseconds. + Weight::from_ref_time(527_900_488 as u64) + // Standard Error: 872_763 + .saturating_add(Weight::from_ref_time(60_604_211 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(250_254_000 as u64) - // Standard Error: 328_900 - .saturating_add(Weight::from_ref_time(424_144_552 as u64).saturating_mul(r as u64)) + // Minimum execution time: 348_671 nanoseconds. + Weight::from_ref_time(306_307_186 as u64) + // Standard Error: 438_525 + .saturating_add(Weight::from_ref_time(422_575_502 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1807,13 +1966,14 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(377_849_000 as u64) - // Standard Error: 1_130_582 - .saturating_add(Weight::from_ref_time(188_240_273 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) - .saturating_add(RocksDbWeight::get().reads((15 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) - .saturating_add(RocksDbWeight::get().writes((15 as u64).saturating_mul(n as u64))) + // Minimum execution time: 470_344 nanoseconds. + Weight::from_ref_time(613_380_073 as u64) + // Standard Error: 1_333_864 + .saturating_add(Weight::from_ref_time(164_398_286 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(48 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1822,12 +1982,13 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(249_701_000 as u64) - // Standard Error: 449_896 - .saturating_add(Weight::from_ref_time(1_370_712_846 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) + // Minimum execution time: 348_312 nanoseconds. + Weight::from_ref_time(303_017_886 as u64) + // Standard Error: 568_589 + .saturating_add(Weight::from_ref_time(1_351_508_682 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) @@ -1837,10 +1998,11 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - Weight::from_ref_time(251_015_000 as u64) - // Standard Error: 7_081_378 - .saturating_add(Weight::from_ref_time(17_258_935_295 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) + // Minimum execution time: 348_997 nanoseconds. + Weight::from_ref_time(349_975_000 as u64) + // Standard Error: 5_689_469 + .saturating_add(Weight::from_ref_time(24_991_501_544 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((160 as u64).saturating_mul(r as u64))) @@ -1852,9 +2014,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - Weight::from_ref_time(250_660_000 as u64) - // Standard Error: 6_402_989 - .saturating_add(Weight::from_ref_time(17_044_780_887 as u64).saturating_mul(r as u64)) + // Minimum execution time: 348_751 nanoseconds. + Weight::from_ref_time(349_330_000 as u64) + // Standard Error: 7_125_421 + .saturating_add(Weight::from_ref_time(24_917_646_052 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((150 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1868,11 +2031,12 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(11_920_718_000 as u64) - // Standard Error: 11_123_062 - .saturating_add(Weight::from_ref_time(642_326_761 as u64).saturating_mul(t as u64)) - // Standard Error: 9_490 - .saturating_add(Weight::from_ref_time(8_845_752 as u64).saturating_mul(c as u64)) + // Minimum execution time: 16_275_711 nanoseconds. + Weight::from_ref_time(15_203_241_602 as u64) + // Standard Error: 3_582_276 + .saturating_add(Weight::from_ref_time(1_179_848_168 as u64).saturating_mul(t as u64)) + // Standard Error: 5_371 + .saturating_add(Weight::from_ref_time(9_712_484 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(167 as u64)) .saturating_add(RocksDbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(163 as u64)) @@ -1887,12 +2051,13 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - Weight::from_ref_time(253_804_000 as u64) - // Standard Error: 19_742_198 - .saturating_add(Weight::from_ref_time(22_250_412_835 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) + // Minimum execution time: 353_168 nanoseconds. + Weight::from_ref_time(353_901_000 as u64) + // Standard Error: 18_701_989 + .saturating_add(Weight::from_ref_time(30_028_672_644 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().reads((400 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) .saturating_add(RocksDbWeight::get().writes((400 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:81 w:81) @@ -1905,9 +2070,10 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(13_921_591_000 as u64) - // Standard Error: 22_601 - .saturating_add(Weight::from_ref_time(125_945_348 as u64).saturating_mul(s as u64)) + // Minimum execution time: 18_226_984 nanoseconds. + Weight::from_ref_time(18_032_466_983 as u64) + // Standard Error: 75_544 + .saturating_add(Weight::from_ref_time(121_087_538 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(249 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(247 as u64)) @@ -1920,9 +2086,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(247_842_000 as u64) - // Standard Error: 219_853 - .saturating_add(Weight::from_ref_time(58_013_100 as u64).saturating_mul(r as u64)) + // Minimum execution time: 344_334 nanoseconds. + Weight::from_ref_time(345_939_404 as u64) + // Standard Error: 98_994 + .saturating_add(Weight::from_ref_time(58_015_295 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1933,9 +2100,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(305_607_000 as u64) - // Standard Error: 71_234 - .saturating_add(Weight::from_ref_time(323_093_184 as u64).saturating_mul(n as u64)) + // Minimum execution time: 402_492 nanoseconds. + Weight::from_ref_time(402_789_000 as u64) + // Standard Error: 54_174 + .saturating_add(Weight::from_ref_time(324_036_889 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1946,9 +2114,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(247_351_000 as u64) - // Standard Error: 271_656 - .saturating_add(Weight::from_ref_time(74_344_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 343_493 nanoseconds. + Weight::from_ref_time(345_116_214 as u64) + // Standard Error: 90_515 + .saturating_add(Weight::from_ref_time(71_282_485 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1959,9 +2128,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(315_626_000 as u64) - // Standard Error: 56_955 - .saturating_add(Weight::from_ref_time(246_316_261 as u64).saturating_mul(n as u64)) + // Minimum execution time: 415_650 nanoseconds. + Weight::from_ref_time(415_894_000 as u64) + // Standard Error: 58_077 + .saturating_add(Weight::from_ref_time(248_416_317 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1972,9 +2142,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(246_887_000 as u64) - // Standard Error: 286_822 - .saturating_add(Weight::from_ref_time(52_242_599 as u64).saturating_mul(r as u64)) + // Minimum execution time: 343_890 nanoseconds. + Weight::from_ref_time(345_542_924 as u64) + // Standard Error: 87_564 + .saturating_add(Weight::from_ref_time(47_361_375 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1985,9 +2156,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(294_818_000 as u64) - // Standard Error: 52_394 - .saturating_add(Weight::from_ref_time(96_353_967 as u64).saturating_mul(n as u64)) + // Minimum execution time: 391_629 nanoseconds. + Weight::from_ref_time(392_793_000 as u64) + // Standard Error: 51_120 + .saturating_add(Weight::from_ref_time(99_288_467 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1998,9 +2170,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(245_334_000 as u64) - // Standard Error: 303_979 - .saturating_add(Weight::from_ref_time(50_180_800 as u64).saturating_mul(r as u64)) + // Minimum execution time: 341_701 nanoseconds. + Weight::from_ref_time(343_318_489 as u64) + // Standard Error: 103_756 + .saturating_add(Weight::from_ref_time(47_301_910 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2011,9 +2184,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(288_995_000 as u64) - // Standard Error: 51_161 - .saturating_add(Weight::from_ref_time(96_331_905 as u64).saturating_mul(n as u64)) + // Minimum execution time: 389_898 nanoseconds. + Weight::from_ref_time(390_489_000 as u64) + // Standard Error: 52_301 + .saturating_add(Weight::from_ref_time(99_344_068 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2024,9 +2198,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(249_935_000 as u64) - // Standard Error: 662_188 - .saturating_add(Weight::from_ref_time(3_025_889_600 as u64).saturating_mul(r as u64)) + // Minimum execution time: 348_789 nanoseconds. + Weight::from_ref_time(350_451_620 as u64) + // Standard Error: 195_939 + .saturating_add(Weight::from_ref_time(2_962_830_479 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2037,9 +2212,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(248_094_000 as u64) - // Standard Error: 535_446 - .saturating_add(Weight::from_ref_time(2_086_979_500 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_537 nanoseconds. + Weight::from_ref_time(347_926_836 as u64) + // Standard Error: 110_557 + .saturating_add(Weight::from_ref_time(2_058_656_763 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2051,318 +2227,370 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(248_254_000 as u64) - // Standard Error: 1_340_955 - .saturating_add(Weight::from_ref_time(1_065_939_603 as u64).saturating_mul(r as u64)) + // Minimum execution time: 346_672 nanoseconds. + Weight::from_ref_time(347_628_000 as u64) + // Standard Error: 2_742_329 + .saturating_add(Weight::from_ref_time(1_370_383_386 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((150 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().reads((225 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((150 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(70_705_000 as u64) - // Standard Error: 7_175 - .saturating_add(Weight::from_ref_time(983_586 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_029 nanoseconds. + Weight::from_ref_time(118_800_774 as u64) + // Standard Error: 4_234 + .saturating_add(Weight::from_ref_time(866_719 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(69_659_000 as u64) - // Standard Error: 1_140 - .saturating_add(Weight::from_ref_time(3_004_307 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_145 nanoseconds. + Weight::from_ref_time(118_644_813 as u64) + // Standard Error: 2_692 + .saturating_add(Weight::from_ref_time(2_874_276 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(69_621_000 as u64) - // Standard Error: 2_871 - .saturating_add(Weight::from_ref_time(2_715_451 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_142 nanoseconds. + Weight::from_ref_time(118_474_161 as u64) + // Standard Error: 6_997 + .saturating_add(Weight::from_ref_time(2_769_076 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(69_459_000 as u64) - // Standard Error: 3_284 - .saturating_add(Weight::from_ref_time(2_581_283 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_020 nanoseconds. + Weight::from_ref_time(118_499_103 as u64) + // Standard Error: 1_266 + .saturating_add(Weight::from_ref_time(2_351_397 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_558_000 as u64) - // Standard Error: 2_509 - .saturating_add(Weight::from_ref_time(2_906_689 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_008 nanoseconds. + Weight::from_ref_time(118_398_803 as u64) + // Standard Error: 750 + .saturating_add(Weight::from_ref_time(2_480_061 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(69_407_000 as u64) - // Standard Error: 1_697 - .saturating_add(Weight::from_ref_time(1_702_534 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_046 nanoseconds. + Weight::from_ref_time(118_332_903 as u64) + // Standard Error: 234 + .saturating_add(Weight::from_ref_time(1_426_355 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(69_477_000 as u64) - // Standard Error: 1_733 - .saturating_add(Weight::from_ref_time(2_192_641 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_998 nanoseconds. + Weight::from_ref_time(117_910_870 as u64) + // Standard Error: 4_629 + .saturating_add(Weight::from_ref_time(1_992_697 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(69_424_000 as u64) - // Standard Error: 2_096 - .saturating_add(Weight::from_ref_time(2_435_708 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_998 nanoseconds. + Weight::from_ref_time(118_059_139 as u64) + // Standard Error: 1_985 + .saturating_add(Weight::from_ref_time(2_164_252 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(72_883_000 as u64) - // Standard Error: 209 - .saturating_add(Weight::from_ref_time(6_874 as u64).saturating_mul(e as u64)) + // Minimum execution time: 121_282 nanoseconds. + Weight::from_ref_time(121_483_289 as u64) + // Standard Error: 57 + .saturating_add(Weight::from_ref_time(4_013 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(69_422_000 as u64) - // Standard Error: 5_030 - .saturating_add(Weight::from_ref_time(7_638_087 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_128 nanoseconds. + Weight::from_ref_time(118_869_764 as u64) + // Standard Error: 8_890 + .saturating_add(Weight::from_ref_time(6_496_684 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(83_136_000 as u64) - // Standard Error: 7_751 - .saturating_add(Weight::from_ref_time(9_543_944 as u64).saturating_mul(r as u64)) + // Minimum execution time: 131_764 nanoseconds. + Weight::from_ref_time(133_009_514 as u64) + // Standard Error: 9_697 + .saturating_add(Weight::from_ref_time(8_310_784 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(93_281_000 as u64) - // Standard Error: 1_967 - .saturating_add(Weight::from_ref_time(596_591 as u64).saturating_mul(p as u64)) + // Minimum execution time: 141_100 nanoseconds. + Weight::from_ref_time(142_282_540 as u64) + // Standard Error: 867 + .saturating_add(Weight::from_ref_time(536_814 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(69_702_000 as u64) - // Standard Error: 1_112 - .saturating_add(Weight::from_ref_time(1_094_685 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_535 nanoseconds. + Weight::from_ref_time(119_017_162 as u64) + // Standard Error: 1_175 + .saturating_add(Weight::from_ref_time(911_141 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(69_720_000 as u64) - // Standard Error: 1_768 - .saturating_add(Weight::from_ref_time(1_045_163 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_472 nanoseconds. + Weight::from_ref_time(118_790_737 as u64) + // Standard Error: 758 + .saturating_add(Weight::from_ref_time(962_148 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(69_716_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_541_622 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_551 nanoseconds. + Weight::from_ref_time(119_070_827 as u64) + // Standard Error: 2_411 + .saturating_add(Weight::from_ref_time(1_367_622 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(72_315_000 as u64) - // Standard Error: 1_081 - .saturating_add(Weight::from_ref_time(1_646_437 as u64).saturating_mul(r as u64)) + // Minimum execution time: 120_958 nanoseconds. + Weight::from_ref_time(121_649_052 as u64) + // Standard Error: 1_557 + .saturating_add(Weight::from_ref_time(1_447_477 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(72_256_000 as u64) - // Standard Error: 1_749 - .saturating_add(Weight::from_ref_time(1_664_891 as u64).saturating_mul(r as u64)) + // Minimum execution time: 120_866 nanoseconds. + Weight::from_ref_time(121_040_400 as u64) + // Standard Error: 6_203 + .saturating_add(Weight::from_ref_time(1_548_715 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(69_616_000 as u64) - // Standard Error: 1_303 - .saturating_add(Weight::from_ref_time(1_017_254 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_076 nanoseconds. + Weight::from_ref_time(118_381_010 as u64) + // Standard Error: 1_814 + .saturating_add(Weight::from_ref_time(938_699 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(70_943_000 as u64) - // Standard Error: 120_139 - .saturating_add(Weight::from_ref_time(183_262_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_030 nanoseconds. + Weight::from_ref_time(120_331_261 as u64) + // Standard Error: 333_364 + .saturating_add(Weight::from_ref_time(227_636_638 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(70_953_000 as u64) - // Standard Error: 2_591 - .saturating_add(Weight::from_ref_time(1_458_584 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_056 nanoseconds. + Weight::from_ref_time(118_554_799 as u64) + // Standard Error: 1_269 + .saturating_add(Weight::from_ref_time(1_331_717 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(69_439_000 as u64) - // Standard Error: 1_822 - .saturating_add(Weight::from_ref_time(1_486_431 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_009 nanoseconds. + Weight::from_ref_time(118_678_537 as u64) + // Standard Error: 1_699 + .saturating_add(Weight::from_ref_time(1_328_153 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(69_366_000 as u64) - // Standard Error: 2_674 - .saturating_add(Weight::from_ref_time(1_506_755 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_031 nanoseconds. + Weight::from_ref_time(118_478_616 as u64) + // Standard Error: 1_533 + .saturating_add(Weight::from_ref_time(1_335_254 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(69_386_000 as u64) - // Standard Error: 3_040 - .saturating_add(Weight::from_ref_time(1_509_928 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_910 nanoseconds. + Weight::from_ref_time(118_471_672 as u64) + // Standard Error: 1_275 + .saturating_add(Weight::from_ref_time(1_345_140 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(69_432_000 as u64) - // Standard Error: 1_875 - .saturating_add(Weight::from_ref_time(1_439_336 as u64).saturating_mul(r as u64)) + // Minimum execution time: 119_504 nanoseconds. + Weight::from_ref_time(118_940_207 as u64) + // Standard Error: 2_512 + .saturating_add(Weight::from_ref_time(1_307_954 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(69_488_000 as u64) - // Standard Error: 1_654 - .saturating_add(Weight::from_ref_time(1_429_318 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_009 nanoseconds. + Weight::from_ref_time(118_366_251 as u64) + // Standard Error: 1_116 + .saturating_add(Weight::from_ref_time(1_322_232 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(69_414_000 as u64) - // Standard Error: 2_773 - .saturating_add(Weight::from_ref_time(1_499_116 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_020 nanoseconds. + Weight::from_ref_time(118_222_792 as u64) + // Standard Error: 1_973 + .saturating_add(Weight::from_ref_time(1_336_896 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(69_427_000 as u64) - // Standard Error: 2_404 - .saturating_add(Weight::from_ref_time(1_969_697 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_038 nanoseconds. + Weight::from_ref_time(118_757_016 as u64) + // Standard Error: 7_932 + .saturating_add(Weight::from_ref_time(1_867_807 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(70_793_000 as u64) - // Standard Error: 1_765 - .saturating_add(Weight::from_ref_time(1_924_169 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_041 nanoseconds. + Weight::from_ref_time(118_717_403 as u64) + // Standard Error: 8_010 + .saturating_add(Weight::from_ref_time(1_868_876 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(69_551_000 as u64) - // Standard Error: 3_955 - .saturating_add(Weight::from_ref_time(1_988_825 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_057 nanoseconds. + Weight::from_ref_time(118_560_106 as u64) + // Standard Error: 1_362 + .saturating_add(Weight::from_ref_time(1_869_820 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(69_510_000 as u64) - // Standard Error: 3_797 - .saturating_add(Weight::from_ref_time(1_976_317 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_045 nanoseconds. + Weight::from_ref_time(118_318_194 as u64) + // Standard Error: 179 + .saturating_add(Weight::from_ref_time(1_873_670 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(69_399_000 as u64) - // Standard Error: 3_255 - .saturating_add(Weight::from_ref_time(1_975_054 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_000 nanoseconds. + Weight::from_ref_time(118_520_606 as u64) + // Standard Error: 3_656 + .saturating_add(Weight::from_ref_time(1_870_762 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(69_425_000 as u64) - // Standard Error: 1_738 - .saturating_add(Weight::from_ref_time(1_959_864 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_035 nanoseconds. + Weight::from_ref_time(118_464_151 as u64) + // Standard Error: 1_073 + .saturating_add(Weight::from_ref_time(1_870_309 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(69_514_000 as u64) - // Standard Error: 9_227 - .saturating_add(Weight::from_ref_time(1_984_750 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_071 nanoseconds. + Weight::from_ref_time(118_470_365 as u64) + // Standard Error: 1_224 + .saturating_add(Weight::from_ref_time(1_870_522 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(69_415_000 as u64) - // Standard Error: 2_052 - .saturating_add(Weight::from_ref_time(1_967_146 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_032 nanoseconds. + Weight::from_ref_time(118_407_669 as u64) + // Standard Error: 769 + .saturating_add(Weight::from_ref_time(1_883_635 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(69_348_000 as u64) - // Standard Error: 3_647 - .saturating_add(Weight::from_ref_time(1_996_141 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_044 nanoseconds. + Weight::from_ref_time(118_324_106 as u64) + // Standard Error: 523 + .saturating_add(Weight::from_ref_time(1_874_728 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(69_448_000 as u64) - // Standard Error: 1_960 - .saturating_add(Weight::from_ref_time(1_956_889 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_111 nanoseconds. + Weight::from_ref_time(118_538_748 as u64) + // Standard Error: 3_498 + .saturating_add(Weight::from_ref_time(1_868_932 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(69_443_000 as u64) - // Standard Error: 20_301 - .saturating_add(Weight::from_ref_time(2_072_285 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_060 nanoseconds. + Weight::from_ref_time(118_421_175 as u64) + // Standard Error: 962 + .saturating_add(Weight::from_ref_time(1_850_713 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(69_458_000 as u64) - // Standard Error: 3_210 - .saturating_add(Weight::from_ref_time(1_970_367 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_050 nanoseconds. + Weight::from_ref_time(118_774_937 as u64) + // Standard Error: 1_717 + .saturating_add(Weight::from_ref_time(1_838_127 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(69_429_000 as u64) - // Standard Error: 3_475 - .saturating_add(Weight::from_ref_time(1_977_800 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_997 nanoseconds. + Weight::from_ref_time(118_626_785 as u64) + // Standard Error: 1_382 + .saturating_add(Weight::from_ref_time(1_842_530 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(69_414_000 as u64) - // Standard Error: 2_659 - .saturating_add(Weight::from_ref_time(2_797_503 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_064 nanoseconds. + Weight::from_ref_time(118_404_203 as u64) + // Standard Error: 2_437 + .saturating_add(Weight::from_ref_time(2_489_569 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(69_460_000 as u64) - // Standard Error: 2_399 - .saturating_add(Weight::from_ref_time(2_646_574 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_949 nanoseconds. + Weight::from_ref_time(118_525_228 as u64) + // Standard Error: 2_231 + .saturating_add(Weight::from_ref_time(2_453_863 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(69_441_000 as u64) - // Standard Error: 2_179 - .saturating_add(Weight::from_ref_time(2_860_283 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_032 nanoseconds. + Weight::from_ref_time(118_311_431 as u64) + // Standard Error: 175 + .saturating_add(Weight::from_ref_time(2_532_745 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(69_401_000 as u64) - // Standard Error: 2_639 - .saturating_add(Weight::from_ref_time(2_582_137 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_987 nanoseconds. + Weight::from_ref_time(118_573_115 as u64) + // Standard Error: 1_814 + .saturating_add(Weight::from_ref_time(2_438_519 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(69_426_000 as u64) - // Standard Error: 2_379 - .saturating_add(Weight::from_ref_time(1_986_578 as u64).saturating_mul(r as u64)) + // Minimum execution time: 120_001 nanoseconds. + Weight::from_ref_time(118_527_518 as u64) + // Standard Error: 1_040 + .saturating_add(Weight::from_ref_time(1_874_359 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(69_599_000 as u64) - // Standard Error: 2_918 - .saturating_add(Weight::from_ref_time(1_991_834 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_051 nanoseconds. + Weight::from_ref_time(118_315_649 as u64) + // Standard Error: 163 + .saturating_add(Weight::from_ref_time(1_851_162 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(71_142_000 as u64) - // Standard Error: 2_659 - .saturating_add(Weight::from_ref_time(1_948_956 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_038 nanoseconds. + Weight::from_ref_time(118_558_677 as u64) + // Standard Error: 2_258 + .saturating_add(Weight::from_ref_time(1_845_713 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(69_407_000 as u64) - // Standard Error: 4_100 - .saturating_add(Weight::from_ref_time(2_030_715 as u64).saturating_mul(r as u64)) + // Minimum execution time: 117_985 nanoseconds. + Weight::from_ref_time(118_660_597 as u64) + // Standard Error: 5_893 + .saturating_add(Weight::from_ref_time(1_887_423 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(69_534_000 as u64) - // Standard Error: 2_305 - .saturating_add(Weight::from_ref_time(1_989_346 as u64).saturating_mul(r as u64)) + // Minimum execution time: 120_101 nanoseconds. + Weight::from_ref_time(118_522_424 as u64) + // Standard Error: 1_094 + .saturating_add(Weight::from_ref_time(1_867_495 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(69_432_000 as u64) - // Standard Error: 2_747 - .saturating_add(Weight::from_ref_time(2_002_548 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_068 nanoseconds. + Weight::from_ref_time(119_012_941 as u64) + // Standard Error: 9_129 + .saturating_add(Weight::from_ref_time(1_877_850 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(69_465_000 as u64) - // Standard Error: 9_644 - .saturating_add(Weight::from_ref_time(2_045_830 as u64).saturating_mul(r as u64)) + // Minimum execution time: 120_105 nanoseconds. + Weight::from_ref_time(118_559_474 as u64) + // Standard Error: 2_055 + .saturating_add(Weight::from_ref_time(1_868_662 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(69_435_000 as u64) - // Standard Error: 2_271 - .saturating_add(Weight::from_ref_time(2_001_986 as u64).saturating_mul(r as u64)) + // Minimum execution time: 118_004 nanoseconds. + Weight::from_ref_time(118_370_466 as u64) + // Standard Error: 818 + .saturating_add(Weight::from_ref_time(1_873_459 as u64).saturating_mul(r as u64)) } } From e8cbc1e87ed84b1abf3176326a90cff991534b30 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Sat, 29 Oct 2022 11:22:58 +0200 Subject: [PATCH 1319/1472] =?UTF-8?q?[Enhancement]=20Convert=20fast-unstak?= =?UTF-8?q?e=20to=20use=20StakingInterface,=20decouplin=E2=80=A6=20(#12424?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Enhancement] Convert fast-unstake to use StakingInterface, decoupling it from Staking * Update primitives/staking/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update primitives/staking/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fix validator comment * remove todo * ideas from Kian (#12474) Co-authored-by: kianenigma * Rename StakingInterface -> Staking for nomination-pools * Staking fixes * StakingInterface changes * fix fast-unstake * fix nomination-pools * Fix fast-unstake tests * Fix benches for fast-unstake * fix is_unbonding * fix nomination pools * fix node code * add mock comments * fix imports * remove todo * more fixes * more fixes * bench fixes * more fixes * more fixes * import fix * more fixes * more bench fix * refix * refix * Update primitives/staking/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * is_unbonding returns a result * fix * review fixes * more review fixes * more fixes * more fixes * Update frame/fast-unstake/src/benchmarking.rs Co-authored-by: Squirrel * remove redundant CurrencyBalance from nom-pools * remove CB * rephrase * Apply suggestions from code review * Update frame/nomination-pools/src/tests.rs * finish damn renamed * clippy fix * fix Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: kianenigma Co-authored-by: parity-processbot <> Co-authored-by: Squirrel --- bin/node/runtime/src/lib.rs | 6 +- frame/fast-unstake/Cargo.toml | 13 +- frame/fast-unstake/src/benchmarking.rs | 40 ++--- frame/fast-unstake/src/lib.rs | 85 +++++------ frame/fast-unstake/src/mock.rs | 3 +- frame/fast-unstake/src/tests.rs | 14 +- frame/fast-unstake/src/types.rs | 7 +- .../nomination-pools/benchmarking/src/lib.rs | 54 ++++--- .../nomination-pools/benchmarking/src/mock.rs | 3 +- frame/nomination-pools/src/lib.rs | 79 ++++------ frame/nomination-pools/src/mock.rs | 93 ++++++++---- frame/nomination-pools/src/tests.rs | 29 ++-- .../nomination-pools/test-staking/src/mock.rs | 3 +- frame/staking/src/pallet/impls.rs | 107 +++++++++---- frame/staking/src/pallet/mod.rs | 2 +- primitives/staking/src/lib.rs | 141 ++++++++++++------ 16 files changed, 373 insertions(+), 306 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index a23fe64c90628..d49312bd6fe3f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -585,7 +585,8 @@ impl pallet_fast_unstake::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ControlOrigin = frame_system::EnsureRoot; type Deposit = ConstU128<{ DOLLARS }>; - type DepositCurrency = Balances; + type Currency = Balances; + type Staking = Staking; type WeightInfo = (); } @@ -773,11 +774,10 @@ impl pallet_nomination_pools::Config for Runtime { type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type CurrencyBalance = Balance; type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakingInterface = pallet_staking::Pallet; + type Staking = Staking; type PostUnbondingPoolsWindow = PostUnbondPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml index 69aeaff35993c..ea1abeb0b48c5 100644 --- a/frame/fast-unstake/Cargo.toml +++ b/frame/fast-unstake/Cargo.toml @@ -24,10 +24,6 @@ sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-staking = { default-features = false, path = "../../primitives/staking" } - -pallet-balances = { default-features = false, path = "../balances" } -pallet-timestamp = { default-features = false, path = "../timestamp" } -pallet-staking = { default-features = false, path = "../staking" } frame-election-provider-support = { default-features = false, path = "../election-provider-support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } @@ -37,6 +33,10 @@ pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +pallet-staking = { path = "../staking" } +pallet-balances = { path = "../balances" } +pallet-timestamp = { path = "../timestamp" } + [features] default = ["std"] @@ -53,9 +53,6 @@ std = [ "sp-runtime/std", "sp-std/std", - "pallet-staking/std", - "pallet-balances/std", - "pallet-timestamp/std", "frame-election-provider-support/std", "frame-benchmarking/std", @@ -63,6 +60,6 @@ std = [ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-staking/runtime-benchmarks", + "sp-staking/runtime-benchmarks" ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs index 8770cc6b64c0d..762a59c96bcfa 100644 --- a/frame/fast-unstake/src/benchmarking.rs +++ b/frame/fast-unstake/src/benchmarking.rs @@ -26,22 +26,15 @@ use frame_support::{ traits::{Currency, EnsureOrigin, Get, Hooks}, }; use frame_system::RawOrigin; -use pallet_staking::Pallet as Staking; -use sp_runtime::traits::{StaticLookup, Zero}; -use sp_staking::EraIndex; +use sp_runtime::traits::Zero; +use sp_staking::{EraIndex, StakingInterface}; use sp_std::prelude::*; const USER_SEED: u32 = 0; const DEFAULT_BACKER_PER_VALIDATOR: u32 = 128; const MAX_VALIDATORS: u32 = 128; -type CurrencyOf = ::Currency; - -fn l( - who: T::AccountId, -) -> <::Lookup as StaticLookup>::Source { - T::Lookup::unlookup(who) -} +type CurrencyOf = ::Currency; fn create_unexposed_nominator() -> T::AccountId { let account = frame_benchmarking::account::("nominator_42", 0, USER_SEED); @@ -53,18 +46,9 @@ fn fund_and_bond_account(account: &T::AccountId) { let stake = CurrencyOf::::minimum_balance() * 100u32.into(); CurrencyOf::::make_free_balance_be(&account, stake * 10u32.into()); - let account_lookup = l::(account.clone()); // bond and nominate ourselves, this will guarantee that we are not backing anyone. - assert_ok!(Staking::::bond( - RawOrigin::Signed(account.clone()).into(), - account_lookup.clone(), - stake, - pallet_staking::RewardDestination::Controller, - )); - assert_ok!(Staking::::nominate( - RawOrigin::Signed(account.clone()).into(), - vec![account_lookup] - )); + assert_ok!(T::Staking::bond(account, stake, account)); + assert_ok!(T::Staking::nominate(account, vec![account.clone()])); } pub(crate) fn fast_unstake_events() -> Vec> { @@ -91,13 +75,11 @@ fn setup_staking(v: u32, until: EraIndex) { .map(|s| { let who = frame_benchmarking::account::("nominator", era, s); let value = ed; - pallet_staking::IndividualExposure { who, value } + (who, value) }) .collect::>(); - let exposure = - pallet_staking::Exposure { total: Default::default(), own: Default::default(), others }; validators.iter().for_each(|v| { - Staking::::add_era_stakers(era, v.clone(), exposure.clone()); + T::Staking::add_era_stakers(&era, &v, others.clone()); }); } } @@ -137,13 +119,13 @@ benchmarks! { // on_idle, when we check some number of eras, on_idle_check { // number of eras multiplied by validators in that era. - let x in (::BondingDuration::get() * 1) .. (::BondingDuration::get() * MAX_VALIDATORS); + let x in (T::Staking::bonding_duration() * 1) .. (T::Staking::bonding_duration() * MAX_VALIDATORS); - let v = x / ::BondingDuration::get(); - let u = ::BondingDuration::get(); + let u = T::Staking::bonding_duration(); + let v = x / u; ErasToCheckPerBlock::::put(u); - pallet_staking::CurrentEra::::put(u); + T::Staking::set_current_era(u); // setup staking with v validators and u eras of data (0..=u) setup_staking::(v, u); diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 8fdb7a79dd537..0477bb251aa00 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -80,18 +80,16 @@ macro_rules! log { pub mod pallet { use super::*; use crate::types::*; - use frame_election_provider_support::ElectionProviderBase; use frame_support::{ pallet_prelude::*, traits::{Defensive, ReservableCurrency}, }; - use frame_system::{pallet_prelude::*, RawOrigin}; - use pallet_staking::Pallet as Staking; + use frame_system::pallet_prelude::*; use sp_runtime::{ traits::{Saturating, Zero}, DispatchResult, }; - use sp_staking::EraIndex; + use sp_staking::{EraIndex, StakingInterface}; use sp_std::{prelude::*, vec::Vec}; pub use weights::WeightInfo; @@ -101,7 +99,7 @@ pub mod pallet { pub struct MaxChecking(sp_std::marker::PhantomData); impl frame_support::traits::Get for MaxChecking { fn get() -> u32 { - ::BondingDuration::get() + 1 + T::Staking::bonding_duration() + 1 } } @@ -109,14 +107,14 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + pallet_staking::Config { + pub trait Config: frame_system::Config { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent> + TryInto>; /// The currency used for deposits. - type DepositCurrency: ReservableCurrency>; + type Currency: ReservableCurrency; /// Deposit to take for unstaking, to make sure we're able to slash the it in order to cover /// the costs of resources on unsuccessful unstake. @@ -125,6 +123,9 @@ pub mod pallet { /// The origin that can control this pallet. type ControlOrigin: frame_support::traits::EnsureOrigin; + /// The access to staking functionality. + type Staking: StakingInterface, AccountId = Self::AccountId>; + /// The weight information of this pallet. type WeightInfo: WeightInfo; } @@ -221,28 +222,25 @@ pub mod pallet { let ctrl = ensure_signed(origin)?; ensure!(ErasToCheckPerBlock::::get() != 0, >::CallNotAllowed); - - let ledger = - pallet_staking::Ledger::::get(&ctrl).ok_or(Error::::NotController)?; - ensure!(!Queue::::contains_key(&ledger.stash), Error::::AlreadyQueued); + let stash_account = + T::Staking::stash_by_ctrl(&ctrl).map_err(|_| Error::::NotController)?; + ensure!(!Queue::::contains_key(&stash_account), Error::::AlreadyQueued); ensure!( - Head::::get().map_or(true, |UnstakeRequest { stash, .. }| stash != ledger.stash), + Head::::get() + .map_or(true, |UnstakeRequest { stash, .. }| stash_account != stash), Error::::AlreadyHead ); - // second part of the && is defensive. - ensure!( - ledger.active == ledger.total && ledger.unlocking.is_empty(), - Error::::NotFullyBonded - ); + + ensure!(!T::Staking::is_unbonding(&stash_account)?, Error::::NotFullyBonded); // chill and fully unstake. - Staking::::chill(RawOrigin::Signed(ctrl.clone()).into())?; - Staking::::unbond(RawOrigin::Signed(ctrl).into(), ledger.total)?; + T::Staking::chill(&stash_account)?; + T::Staking::fully_unbond(&stash_account)?; - T::DepositCurrency::reserve(&ledger.stash, T::Deposit::get())?; + T::Currency::reserve(&stash_account, T::Deposit::get())?; // enqueue them. - Queue::::insert(ledger.stash, T::Deposit::get()); + Queue::::insert(stash_account, T::Deposit::get()); Ok(()) } @@ -259,18 +257,18 @@ pub mod pallet { ensure!(ErasToCheckPerBlock::::get() != 0, >::CallNotAllowed); - let stash = pallet_staking::Ledger::::get(&ctrl) - .map(|l| l.stash) - .ok_or(Error::::NotController)?; - ensure!(Queue::::contains_key(&stash), Error::::NotQueued); + let stash_account = + T::Staking::stash_by_ctrl(&ctrl).map_err(|_| Error::::NotController)?; + ensure!(Queue::::contains_key(&stash_account), Error::::NotQueued); ensure!( - Head::::get().map_or(true, |UnstakeRequest { stash, .. }| stash != stash), + Head::::get() + .map_or(true, |UnstakeRequest { stash, .. }| stash_account != stash), Error::::AlreadyHead ); - let deposit = Queue::::take(stash.clone()); + let deposit = Queue::::take(stash_account.clone()); if let Some(deposit) = deposit.defensive() { - let remaining = T::DepositCurrency::unreserve(&stash, deposit); + let remaining = T::Currency::unreserve(&stash_account, deposit); if !remaining.is_zero() { frame_support::defensive!("`not enough balance to unreserve`"); ErasToCheckPerBlock::::put(0); @@ -314,7 +312,7 @@ pub mod pallet { // NOTE: here we're assuming that the number of validators has only ever increased, // meaning that the number of exposures to check is either this per era, or less. - let validator_count = pallet_staking::ValidatorCount::::get(); + let validator_count = T::Staking::desired_validator_count(); // determine the number of eras to check. This is based on both `ErasToCheckPerBlock` // and `remaining_weight` passed on to us from the runtime executive. @@ -330,8 +328,7 @@ pub mod pallet { } } - if <::ElectionProvider as ElectionProviderBase>::ongoing() - { + if T::Staking::election_ongoing() { // NOTE: we assume `ongoing` does not consume any weight. // there is an ongoing election -- we better not do anything. Imagine someone is not // exposed anywhere in the last era, and the snapshot for the election is already @@ -366,8 +363,8 @@ pub mod pallet { ); // the range that we're allowed to check in this round. - let current_era = pallet_staking::CurrentEra::::get().unwrap_or_default(); - let bonding_duration = ::BondingDuration::get(); + let current_era = T::Staking::current_era(); + let bonding_duration = T::Staking::bonding_duration(); // prune all the old eras that we don't care about. This will help us keep the bound // of `checked`. checked.retain(|e| *e >= current_era.saturating_sub(bonding_duration)); @@ -401,16 +398,9 @@ pub mod pallet { ); if unchecked_eras_to_check.is_empty() { - // `stash` is not exposed in any era now -- we can let go of them now. - let num_slashing_spans = Staking::::slashing_spans(&stash).iter().count() as u32; + let result = T::Staking::force_unstake(stash.clone()); - let result = pallet_staking::Pallet::::force_unstake( - RawOrigin::Root.into(), - stash.clone(), - num_slashing_spans, - ); - - let remaining = T::DepositCurrency::unreserve(&stash, deposit); + let remaining = T::Currency::unreserve(&stash, deposit); if !remaining.is_zero() { frame_support::defensive!("`not enough balance to unreserve`"); ErasToCheckPerBlock::::put(0); @@ -426,7 +416,7 @@ pub mod pallet { let mut eras_checked = 0u32; let is_exposed = unchecked_eras_to_check.iter().any(|e| { eras_checked.saturating_inc(); - Self::is_exposed_in_era(&stash, e) + T::Staking::is_exposed_in_era(&stash, e) }); log!( @@ -442,7 +432,7 @@ pub mod pallet { // the last 28 eras, have registered yourself to be unstaked, midway being checked, // you are exposed. if is_exposed { - T::DepositCurrency::slash_reserved(&stash, deposit); + T::Currency::slash_reserved(&stash, deposit); log!(info, "slashed {:?} by {:?}", stash, deposit); Self::deposit_event(Event::::Slashed { stash, amount: deposit }); } else { @@ -472,12 +462,5 @@ pub mod pallet { ::WeightInfo::on_idle_check(validator_count * eras_checked) } } - - /// Checks whether an account `staker` has been exposed in an era. - fn is_exposed_in_era(staker: &T::AccountId, era: &EraIndex) -> bool { - pallet_staking::ErasStakers::::iter_prefix(era).any(|(validator, exposures)| { - validator == *staker || exposures.others.iter().any(|i| i.who == *staker) - }) - } } } diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index 71fc2d4ba905a..87e89d90d6304 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -174,7 +174,8 @@ parameter_types! { impl fast_unstake::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Deposit = DepositAmount; - type DepositCurrency = Balances; + type Currency = Balances; + type Staking = Staking; type ControlOrigin = frame_system::EnsureRoot; type WeightInfo = (); } diff --git a/frame/fast-unstake/src/tests.rs b/frame/fast-unstake/src/tests.rs index 6e617fd992028..18a9d59e9da66 100644 --- a/frame/fast-unstake/src/tests.rs +++ b/frame/fast-unstake/src/tests.rs @@ -48,7 +48,7 @@ fn register_insufficient_funds_fails() { use pallet_balances::Error as BalancesError; ExtBuilder::default().build_and_execute(|| { ErasToCheckPerBlock::::put(1); - ::DepositCurrency::make_free_balance_be(&1, 3); + ::Currency::make_free_balance_be(&1, 3); // Controller account registers for fast unstake. assert_noop!( @@ -138,15 +138,15 @@ fn deregister_works() { ExtBuilder::default().build_and_execute(|| { ErasToCheckPerBlock::::put(1); - assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + assert_eq!(::Currency::reserved_balance(&1), 0); // Controller account registers for fast unstake. assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(::DepositCurrency::reserved_balance(&1), DepositAmount::get()); + assert_eq!(::Currency::reserved_balance(&1), DepositAmount::get()); // Controller then changes mind and deregisters. assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(2))); - assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + assert_eq!(::Currency::reserved_balance(&1), 0); // Ensure stash no longer exists in the queue. assert_eq!(Queue::::get(1), None); @@ -363,7 +363,7 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // given - assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + assert_eq!(::Currency::reserved_balance(&1), 0); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); @@ -371,7 +371,7 @@ mod on_idle { assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(8))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(10))); - assert_eq!(::DepositCurrency::reserved_balance(&1), DepositAmount::get()); + assert_eq!(::Currency::reserved_balance(&1), DepositAmount::get()); assert_eq!(Queue::::count(), 5); assert_eq!(Head::::get(), None); @@ -411,7 +411,7 @@ mod on_idle { ); assert_eq!(Queue::::count(), 3); - assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + assert_eq!(::Currency::reserved_balance(&1), 0); assert_eq!( fast_unstake_events_since_last_call(), diff --git a/frame/fast-unstake/src/types.rs b/frame/fast-unstake/src/types.rs index 08b9ab4326eb2..460c9fa4354e5 100644 --- a/frame/fast-unstake/src/types.rs +++ b/frame/fast-unstake/src/types.rs @@ -17,6 +17,7 @@ //! Types used in the Fast Unstake pallet. +use crate::Config; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ traits::{Currency, Get}, @@ -26,10 +27,8 @@ use scale_info::TypeInfo; use sp_staking::EraIndex; use sp_std::{fmt::Debug, prelude::*}; -pub type BalanceOf = <::Currency as Currency< - ::AccountId, ->>::Balance; - +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; /// An unstake request. #[derive( Encode, Decode, EqNoBound, PartialEqNoBound, Clone, TypeInfo, RuntimeDebugNoBound, MaxEncodedLen, diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index c31bcb1546ecd..9b063539152b7 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -133,15 +133,15 @@ impl ListScenario { // Create accounts with the origin weight let (pool_creator1, pool_origin1) = create_pool_account::(USER_SEED + 1, origin_weight); - T::StakingInterface::nominate( - pool_origin1.clone(), + T::Staking::nominate( + &pool_origin1, // NOTE: these don't really need to be validators. vec![account("random_validator", 0, USER_SEED)], )?; let (_, pool_origin2) = create_pool_account::(USER_SEED + 2, origin_weight); - T::StakingInterface::nominate( - pool_origin2.clone(), + T::Staking::nominate( + &pool_origin2, vec![account("random_validator", 0, USER_SEED)].clone(), )?; @@ -156,10 +156,7 @@ impl ListScenario { // Create an account with the worst case destination weight let (_, pool_dest1) = create_pool_account::(USER_SEED + 3, dest_weight); - T::StakingInterface::nominate( - pool_dest1.clone(), - vec![account("random_validator", 0, USER_SEED)], - )?; + T::Staking::nominate(&pool_dest1, vec![account("random_validator", 0, USER_SEED)])?; let weight_of = pallet_staking::Pallet::::weight_of_fn(); assert_eq!(vote_to_balance::(weight_of(&pool_origin1)).unwrap(), origin_weight); @@ -185,12 +182,11 @@ impl ListScenario { self.origin1_member = Some(joiner.clone()); CurrencyOf::::make_free_balance_be(&joiner, amount * 2u32.into()); - let original_bonded = T::StakingInterface::active_stake(&self.origin1).unwrap(); + let original_bonded = T::Staking::active_stake(&self.origin1).unwrap(); // Unbond `amount` from the underlying pool account so when the member joins // we will maintain `current_bonded`. - T::StakingInterface::unbond(self.origin1.clone(), amount) - .expect("the pool was created in `Self::new`."); + T::Staking::unbond(&self.origin1, amount).expect("the pool was created in `Self::new`."); // Account pool points for the unbonded balance. BondedPools::::mutate(&1, |maybe_pool| { @@ -219,7 +215,7 @@ frame_benchmarking::benchmarks! { // setup the worst case list scenario. let scenario = ListScenario::::new(origin_weight, true)?; assert_eq!( - T::StakingInterface::active_stake(&scenario.origin1).unwrap(), + T::Staking::active_stake(&scenario.origin1).unwrap(), origin_weight ); @@ -234,7 +230,7 @@ frame_benchmarking::benchmarks! { verify { assert_eq!(CurrencyOf::::free_balance(&joiner), joiner_free - max_additional); assert_eq!( - T::StakingInterface::active_stake(&scenario.origin1).unwrap(), + T::Staking::active_stake(&scenario.origin1).unwrap(), scenario.dest_weight ); } @@ -249,7 +245,7 @@ frame_benchmarking::benchmarks! { }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) verify { assert!( - T::StakingInterface::active_stake(&scenario.origin1).unwrap() >= + T::Staking::active_stake(&scenario.origin1).unwrap() >= scenario.dest_weight ); } @@ -267,7 +263,7 @@ frame_benchmarking::benchmarks! { }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::Rewards) verify { assert!( - T::StakingInterface::active_stake(&scenario.origin1).unwrap() >= + T::Staking::active_stake(&scenario.origin1).unwrap() >= scenario.dest_weight ); } @@ -314,7 +310,7 @@ frame_benchmarking::benchmarks! { whitelist_account!(member_id); }: _(RuntimeOrigin::Signed(member_id.clone()), member_id_lookup, all_points) verify { - let bonded_after = T::StakingInterface::active_stake(&scenario.origin1).unwrap(); + let bonded_after = T::Staking::active_stake(&scenario.origin1).unwrap(); // We at least went down to the destination bag assert!(bonded_after <= scenario.dest_weight); let member = PoolMembers::::get( @@ -323,7 +319,7 @@ frame_benchmarking::benchmarks! { .unwrap(); assert_eq!( member.unbonding_eras.keys().cloned().collect::>(), - vec![0 + T::StakingInterface::bonding_duration()] + vec![0 + T::Staking::bonding_duration()] ); assert_eq!( member.unbonding_eras.values().cloned().collect::>(), @@ -345,7 +341,7 @@ frame_benchmarking::benchmarks! { // Sanity check join worked assert_eq!( - T::StakingInterface::active_stake(&pool_account).unwrap(), + T::Staking::active_stake(&pool_account).unwrap(), min_create_bond + min_join_bond ); assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); @@ -355,7 +351,7 @@ frame_benchmarking::benchmarks! { // Sanity check that unbond worked assert_eq!( - T::StakingInterface::active_stake(&pool_account).unwrap(), + T::Staking::active_stake(&pool_account).unwrap(), min_create_bond ); assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); @@ -388,7 +384,7 @@ frame_benchmarking::benchmarks! { // Sanity check join worked assert_eq!( - T::StakingInterface::active_stake(&pool_account).unwrap(), + T::Staking::active_stake(&pool_account).unwrap(), min_create_bond + min_join_bond ); assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); @@ -399,7 +395,7 @@ frame_benchmarking::benchmarks! { // Sanity check that unbond worked assert_eq!( - T::StakingInterface::active_stake(&pool_account).unwrap(), + T::Staking::active_stake(&pool_account).unwrap(), min_create_bond ); assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); @@ -446,7 +442,7 @@ frame_benchmarking::benchmarks! { // Sanity check that unbond worked assert_eq!( - T::StakingInterface::active_stake(&pool_account).unwrap(), + T::Staking::active_stake(&pool_account).unwrap(), Zero::zero() ); assert_eq!( @@ -525,8 +521,8 @@ frame_benchmarking::benchmarks! { } ); assert_eq!( - T::StakingInterface::active_stake(&Pools::::create_bonded_account(1)), - Some(min_create_bond) + T::Staking::active_stake(&Pools::::create_bonded_account(1)), + Ok(min_create_bond) ); } @@ -564,8 +560,8 @@ frame_benchmarking::benchmarks! { } ); assert_eq!( - T::StakingInterface::active_stake(&Pools::::create_bonded_account(1)), - Some(min_create_bond) + T::Staking::active_stake(&Pools::::create_bonded_account(1)), + Ok(min_create_bond) ); } @@ -647,13 +643,13 @@ frame_benchmarking::benchmarks! { .map(|i| account("stash", USER_SEED, i)) .collect(); - assert_ok!(Pools::::nominate(RuntimeOrigin::Signed(depositor.clone()).into(), 1, validators)); - assert!(T::StakingInterface::nominations(Pools::::create_bonded_account(1)).is_some()); + assert_ok!(T::Staking::nominate(&pool_account, validators)); + assert!(T::Staking::nominations(Pools::::create_bonded_account(1)).is_some()); whitelist_account!(depositor); }:_(RuntimeOrigin::Signed(depositor.clone()), 1) verify { - assert!(T::StakingInterface::nominations(Pools::::create_bonded_account(1)).is_none()); + assert!(T::Staking::nominations(Pools::::create_bonded_account(1)).is_none()); } impl_benchmark_test_suite!( diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 0f617f0bf6f4b..db01989f2b563 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -157,11 +157,10 @@ impl pallet_nomination_pools::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; - type CurrencyBalance = Balance; type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakingInterface = Staking; + type Staking = Staking; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 9e77adaeee677..5173b2e7e7d21 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -286,7 +286,7 @@ use sp_runtime::{ AccountIdConversion, Bounded, CheckedAdd, CheckedSub, Convert, Saturating, StaticLookup, Zero, }, - FixedPointNumber, FixedPointOperand, + FixedPointNumber, }; use sp_staking::{EraIndex, OnStakerSlash, StakingInterface}; use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec}; @@ -417,7 +417,7 @@ impl PoolMember { /// /// This is derived from the ratio of points in the pool to which the member belongs to. /// Might return different values based on the pool state for the same member and points. - fn active_balance(&self) -> BalanceOf { + fn active_stake(&self) -> BalanceOf { if let Some(pool) = BondedPool::::get(self.pool_id).defensive() { pool.points_to_balance(self.points) } else { @@ -623,7 +623,7 @@ impl BondedPool { /// This is often used for bonding and issuing new funds into the pool. fn balance_to_point(&self, new_funds: BalanceOf) -> BalanceOf { let bonded_balance = - T::StakingInterface::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); + T::Staking::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); Pallet::::balance_to_point(bonded_balance, self.points, new_funds) } @@ -632,7 +632,7 @@ impl BondedPool { /// This is often used for unbonding. fn points_to_balance(&self, points: BalanceOf) -> BalanceOf { let bonded_balance = - T::StakingInterface::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); + T::Staking::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); Pallet::::point_to_balance(bonded_balance, self.points, points) } @@ -683,7 +683,7 @@ impl BondedPool { fn transferrable_balance(&self) -> BalanceOf { let account = self.bonded_account(); T::Currency::free_balance(&account) - .saturating_sub(T::StakingInterface::active_stake(&account).unwrap_or_default()) + .saturating_sub(T::Staking::active_stake(&account).unwrap_or_default()) } fn is_root(&self, who: &T::AccountId) -> bool { @@ -738,7 +738,7 @@ impl BondedPool { ensure!(!self.is_destroying(), Error::::CanNotChangeState); let bonded_balance = - T::StakingInterface::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); + T::Staking::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); ensure!(!bonded_balance.is_zero(), Error::::OverflowRisk); let points_to_balance_ratio_floor = self @@ -791,7 +791,7 @@ impl BondedPool { target_member.active_points().saturating_sub(unbonding_points); let mut target_member_after_unbond = (*target_member).clone(); target_member_after_unbond.points = new_depositor_points; - target_member_after_unbond.active_balance() + target_member_after_unbond.active_stake() }; // any partial unbonding is only ever allowed if this unbond is permissioned. @@ -862,8 +862,8 @@ impl BondedPool { /// Bond exactly `amount` from `who`'s funds into this pool. /// - /// If the bond type is `Create`, `StakingInterface::bond` is called, and `who` - /// is allowed to be killed. Otherwise, `StakingInterface::bond_extra` is called and `who` + /// If the bond type is `Create`, `Staking::bond` is called, and `who` + /// is allowed to be killed. Otherwise, `Staking::bond_extra` is called and `who` /// cannot be killed. /// /// Returns `Ok(points_issues)`, `Err` otherwise. @@ -889,16 +889,11 @@ impl BondedPool { let points_issued = self.issue(amount); match ty { - BondType::Create => T::StakingInterface::bond( - bonded_account.clone(), - bonded_account, - amount, - self.reward_account(), - )?, + BondType::Create => T::Staking::bond(&bonded_account, amount, &self.reward_account())?, // The pool should always be created in such a way its in a state to bond extra, but if // the active balance is slashed below the minimum bonded or the account cannot be // found, we exit early. - BondType::Later => T::StakingInterface::bond_extra(bonded_account, amount)?, + BondType::Later => T::Staking::bond_extra(&bonded_account, amount)?, } Ok(points_issued) @@ -1129,7 +1124,7 @@ impl Get for TotalUnbondingPools { // NOTE: this may be dangerous in the scenario bonding_duration gets decreased because // we would no longer be able to decode `UnbondingPoolsWithEra`, which uses // `TotalUnbondingPools` as the bound - T::StakingInterface::bonding_duration() + T::PostUnbondingPoolsWindow::get() + T::Staking::bonding_duration() + T::PostUnbondingPoolsWindow::get() } } @@ -1138,7 +1133,6 @@ pub mod pallet { use super::*; use frame_support::traits::StorageVersion; use frame_system::{ensure_signed, pallet_prelude::*}; - use sp_runtime::traits::CheckedAdd; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); @@ -1157,20 +1151,7 @@ pub mod pallet { type WeightInfo: weights::WeightInfo; /// The nominating balance. - type Currency: Currency; - - /// Sadly needed to bound it to `FixedPointOperand`. - // The only alternative is to sprinkle a `where BalanceOf: FixedPointOperand` in roughly - // a million places, so we prefer doing this. - type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned - + codec::FullCodec - + MaybeSerializeDeserialize - + sp_std::fmt::Debug - + Default - + FixedPointOperand - + CheckedAdd - + TypeInfo - + MaxEncodedLen; + type Currency: Currency; /// The type that is used for reward counter. /// @@ -1212,10 +1193,7 @@ pub mod pallet { type U256ToBalance: Convert>; /// The interface for nominating. - type StakingInterface: StakingInterface< - Balance = BalanceOf, - AccountId = Self::AccountId, - >; + type Staking: StakingInterface, AccountId = Self::AccountId>; /// The amount of eras a `SubPools::with_era` pool can exist before it gets merged into the /// `SubPools::no_era` pool. In other words, this is the amount of eras a member will be @@ -1650,12 +1628,12 @@ pub mod pallet { let _ = reward_pool.update_records(bonded_pool.id, bonded_pool.points)?; let _ = Self::do_reward_payout(&who, &mut member, &mut bonded_pool, &mut reward_pool)?; - let current_era = T::StakingInterface::current_era(); - let unbond_era = T::StakingInterface::bonding_duration().saturating_add(current_era); + let current_era = T::Staking::current_era(); + let unbond_era = T::Staking::bonding_duration().saturating_add(current_era); // Unbond in the actual underlying nominator. let unbonding_balance = bonded_pool.dissolve(unbonding_points); - T::StakingInterface::unbond(bonded_pool.bonded_account(), unbonding_balance)?; + T::Staking::unbond(&bonded_pool.bonded_account(), unbonding_balance)?; // Note that we lazily create the unbonding pools here if they don't already exist let mut sub_pools = SubPoolsStorage::::get(member.pool_id) @@ -1718,7 +1696,7 @@ pub mod pallet { // For now we only allow a pool to withdraw unbonded if its not destroying. If the pool // is destroying then `withdraw_unbonded` can be used. ensure!(pool.state != PoolState::Destroying, Error::::NotDestroying); - T::StakingInterface::withdraw_unbonded(pool.bonded_account(), num_slashing_spans)?; + T::Staking::withdraw_unbonded(pool.bonded_account(), num_slashing_spans)?; Ok(()) } @@ -1754,7 +1732,7 @@ pub mod pallet { let member_account = T::Lookup::lookup(member_account)?; let mut member = PoolMembers::::get(&member_account).ok_or(Error::::PoolMemberNotFound)?; - let current_era = T::StakingInterface::current_era(); + let current_era = T::Staking::current_era(); let bonded_pool = BondedPool::::get(member.pool_id) .defensive_ok_or::>(DefensiveError::PoolNotFound.into())?; @@ -1769,10 +1747,8 @@ pub mod pallet { // Before calculate the `balance_to_unbond`, with call withdraw unbonded to ensure the // `transferrable_balance` is correct. - let stash_killed = T::StakingInterface::withdraw_unbonded( - bonded_pool.bonded_account(), - num_slashing_spans, - )?; + let stash_killed = + T::Staking::withdraw_unbonded(bonded_pool.bonded_account(), num_slashing_spans)?; // defensive-only: the depositor puts enough funds into the stash so that it will only // be destroyed when they are leaving. @@ -1960,7 +1936,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); - T::StakingInterface::nominate(bonded_pool.bonded_account(), validators) + T::Staking::nominate(&bonded_pool.bonded_account(), validators) } /// Set a new state for the pool. @@ -2132,7 +2108,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); - T::StakingInterface::chill(bonded_pool.bonded_account()) + T::Staking::chill(&bonded_pool.bonded_account()) } } @@ -2149,7 +2125,7 @@ pub mod pallet { "Minimum points to balance ratio must be greater than 0" ); assert!( - T::StakingInterface::bonding_duration() < TotalUnbondingPools::::get(), + T::Staking::bonding_duration() < TotalUnbondingPools::::get(), "There must be more unbonding pools then the bonding duration / so a slash can be applied to relevant unboding pools. (We assume / the bonding duration > slash deffer duration.", @@ -2185,7 +2161,7 @@ impl Pallet { /// It is essentially `max { MinNominatorBond, MinCreateBond, MinJoinBond }`, where the former /// is coming from the staking pallet and the latter two are configured in this pallet. pub fn depositor_min_bond() -> BalanceOf { - T::StakingInterface::minimum_bond() + T::Staking::minimum_nominator_bond() .max(MinCreateBond::::get()) .max(MinJoinBond::::get()) .max(T::Currency::minimum_balance()) @@ -2212,7 +2188,7 @@ impl Pallet { debug_assert_eq!(frame_system::Pallet::::consumers(&reward_account), 0); debug_assert_eq!(frame_system::Pallet::::consumers(&bonded_account), 0); debug_assert_eq!( - T::StakingInterface::total_stake(&bonded_account).unwrap_or_default(), + T::Staking::total_stake(&bonded_account).unwrap_or_default(), Zero::zero() ); @@ -2487,8 +2463,7 @@ impl Pallet { let subs = SubPoolsStorage::::get(pool_id).unwrap_or_default(); let sum_unbonding_balance = subs.sum_unbonding_balance(); - let bonded_balance = - T::StakingInterface::active_stake(&pool_account).unwrap_or_default(); + let bonded_balance = T::Staking::active_stake(&pool_account).unwrap_or_default(); let total_balance = T::Currency::total_balance(&pool_account); assert!( diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 1b3372dae56ee..e1af456e31fd4 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -3,6 +3,7 @@ use crate::{self as pools}; use frame_support::{assert_ok, parameter_types, PalletId}; use frame_system::RawOrigin; use sp_runtime::FixedU128; +use sp_staking::Stake; pub type BlockNumber = u64; pub type AccountId = u128; @@ -47,10 +48,17 @@ impl sp_staking::StakingInterface for StakingMock { type Balance = Balance; type AccountId = AccountId; - fn minimum_bond() -> Self::Balance { + fn minimum_nominator_bond() -> Self::Balance { + StakingMinBond::get() + } + fn minimum_validator_bond() -> Self::Balance { StakingMinBond::get() } + fn desired_validator_count() -> u32 { + unimplemented!("method currently not used in testing") + } + fn current_era() -> EraIndex { CurrentEra::get() } @@ -59,39 +67,24 @@ impl sp_staking::StakingInterface for StakingMock { BondingDuration::get() } - fn active_stake(who: &Self::AccountId) -> Option { - BondedBalanceMap::get().get(who).map(|v| *v) - } - - fn total_stake(who: &Self::AccountId) -> Option { - match ( - UnbondingBalanceMap::get().get(who).map(|v| *v), - BondedBalanceMap::get().get(who).map(|v| *v), - ) { - (None, None) => None, - (Some(v), None) | (None, Some(v)) => Some(v), - (Some(a), Some(b)) => Some(a + b), - } - } - - fn bond_extra(who: Self::AccountId, extra: Self::Balance) -> DispatchResult { + fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { let mut x = BondedBalanceMap::get(); - x.get_mut(&who).map(|v| *v += extra); + x.get_mut(who).map(|v| *v += extra); BondedBalanceMap::set(&x); Ok(()) } - fn unbond(who: Self::AccountId, amount: Self::Balance) -> DispatchResult { + fn unbond(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult { let mut x = BondedBalanceMap::get(); - *x.get_mut(&who).unwrap() = x.get_mut(&who).unwrap().saturating_sub(amount); + *x.get_mut(who).unwrap() = x.get_mut(who).unwrap().saturating_sub(amount); BondedBalanceMap::set(&x); let mut y = UnbondingBalanceMap::get(); - *y.entry(who).or_insert(Self::Balance::zero()) += amount; + *y.entry(*who).or_insert(Self::Balance::zero()) += amount; UnbondingBalanceMap::set(&y); Ok(()) } - fn chill(_: Self::AccountId) -> sp_runtime::DispatchResult { + fn chill(_: &Self::AccountId) -> sp_runtime::DispatchResult { Ok(()) } @@ -104,17 +97,12 @@ impl sp_staking::StakingInterface for StakingMock { Ok(UnbondingBalanceMap::get().is_empty() && BondedBalanceMap::get().is_empty()) } - fn bond( - stash: Self::AccountId, - _: Self::AccountId, - value: Self::Balance, - _: Self::AccountId, - ) -> DispatchResult { - StakingMock::set_bonded_balance(stash, value); + fn bond(stash: &Self::AccountId, value: Self::Balance, _: &Self::AccountId) -> DispatchResult { + StakingMock::set_bonded_balance(*stash, value); Ok(()) } - fn nominate(_: Self::AccountId, nominations: Vec) -> DispatchResult { + fn nominate(_: &Self::AccountId, nominations: Vec) -> DispatchResult { Nominations::set(&Some(nominations)); Ok(()) } @@ -123,6 +111,48 @@ impl sp_staking::StakingInterface for StakingMock { fn nominations(_: Self::AccountId) -> Option> { Nominations::get() } + + fn stash_by_ctrl(_controller: &Self::AccountId) -> Result { + unimplemented!("method currently not used in testing") + } + + fn stake(who: &Self::AccountId) -> Result, DispatchError> { + match ( + UnbondingBalanceMap::get().get(who).map(|v| *v), + BondedBalanceMap::get().get(who).map(|v| *v), + ) { + (None, None) => Err(DispatchError::Other("balance not found")), + (Some(v), None) => Ok(Stake { total: v, active: 0, stash: *who }), + (None, Some(v)) => Ok(Stake { total: v, active: v, stash: *who }), + (Some(a), Some(b)) => Ok(Stake { total: a + b, active: b, stash: *who }), + } + } + + fn election_ongoing() -> bool { + unimplemented!("method currently not used in testing") + } + + fn force_unstake(_who: Self::AccountId) -> sp_runtime::DispatchResult { + unimplemented!("method currently not used in testing") + } + + fn is_exposed_in_era(_who: &Self::AccountId, _era: &EraIndex) -> bool { + unimplemented!("method currently not used in testing") + } + + #[cfg(feature = "runtime-benchmarks")] + fn add_era_stakers( + _current_era: &EraIndex, + _stash: &Self::AccountId, + _exposures: Vec<(Self::AccountId, Self::Balance)>, + ) { + unimplemented!("method currently not used in testing") + } + + #[cfg(feature = "runtime-benchmarks")] + fn set_current_era(_era: EraIndex) { + unimplemented!("method currently not used in testing") + } } impl frame_system::Config for Runtime { @@ -192,11 +222,10 @@ impl pools::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; - type CurrencyBalance = Balance; type RewardCounter = RewardCounter; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakingInterface = StakingMock; + type Staking = StakingMock; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type PalletId = PoolsPalletId; type MaxMetadataLen = MaxMetadataLen; diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 5074a7ffa695a..0c909b68152bb 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -3083,18 +3083,18 @@ mod pool_withdraw_unbonded { fn pool_withdraw_unbonded_works() { ExtBuilder::default().build_and_execute(|| { // Given 10 unbond'ed directly against the pool account - assert_ok!(StakingMock::unbond(default_bonded_account(), 5)); + assert_ok!(StakingMock::unbond(&default_bonded_account(), 5)); // and the pool account only has 10 balance - assert_eq!(StakingMock::active_stake(&default_bonded_account()), Some(5)); - assert_eq!(StakingMock::total_stake(&default_bonded_account()), Some(10)); + assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(5)); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(10)); assert_eq!(Balances::free_balance(&default_bonded_account()), 10); // When assert_ok!(Pools::pool_withdraw_unbonded(RuntimeOrigin::signed(10), 1, 0)); // Then there unbonding balance is no longer locked - assert_eq!(StakingMock::active_stake(&default_bonded_account()), Some(5)); - assert_eq!(StakingMock::total_stake(&default_bonded_account()), Some(5)); + assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(5)); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(5)); assert_eq!(Balances::free_balance(&default_bonded_account()), 10); }); } @@ -3270,7 +3270,7 @@ mod withdraw_unbonded { // current bond is 600, we slash it all to 300. StakingMock::set_bonded_balance(default_bonded_account(), 300); Balances::make_free_balance_be(&default_bonded_account(), 300); - assert_eq!(StakingMock::total_stake(&default_bonded_account()), Some(300)); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(300)); assert_ok!(fully_unbond_permissioned(40)); assert_ok!(fully_unbond_permissioned(550)); @@ -4074,12 +4074,15 @@ mod create { assert!(!BondedPools::::contains_key(2)); assert!(!RewardPools::::contains_key(2)); assert!(!PoolMembers::::contains_key(11)); - assert_eq!(StakingMock::active_stake(&next_pool_stash), None); + assert_err!( + StakingMock::active_stake(&next_pool_stash), + DispatchError::Other("balance not found") + ); - Balances::make_free_balance_be(&11, StakingMock::minimum_bond() + ed); + Balances::make_free_balance_be(&11, StakingMock::minimum_nominator_bond() + ed); assert_ok!(Pools::create( RuntimeOrigin::signed(11), - StakingMock::minimum_bond(), + StakingMock::minimum_nominator_bond(), 123, 456, 789 @@ -4090,7 +4093,7 @@ mod create { PoolMembers::::get(11).unwrap(), PoolMember { pool_id: 2, - points: StakingMock::minimum_bond(), + points: StakingMock::minimum_nominator_bond(), ..Default::default() } ); @@ -4099,7 +4102,7 @@ mod create { BondedPool { id: 2, inner: BondedPoolInner { - points: StakingMock::minimum_bond(), + points: StakingMock::minimum_nominator_bond(), member_counter: 1, state: PoolState::Open, roles: PoolRoles { @@ -4113,7 +4116,7 @@ mod create { ); assert_eq!( StakingMock::active_stake(&next_pool_stash).unwrap(), - StakingMock::minimum_bond() + StakingMock::minimum_nominator_bond() ); assert_eq!( RewardPools::::get(2).unwrap(), @@ -4142,7 +4145,7 @@ mod create { // Given assert_eq!(MinCreateBond::::get(), 2); - assert_eq!(StakingMock::minimum_bond(), 10); + assert_eq!(StakingMock::minimum_nominator_bond(), 10); // Then assert_noop!( diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 8c04e40d71df4..5758b884e348d 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -171,11 +171,10 @@ impl pallet_nomination_pools::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; - type CurrencyBalance = Balance; type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakingInterface = Staking; + type Staking = Staking; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 4ef064229693c..a9e9899b9761a 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -18,8 +18,8 @@ //! Implementations for the Staking FRAME Pallet. use frame_election_provider_support::{ - data_provider, ElectionDataProvider, ElectionProvider, ScoreProvider, SortedListProvider, - Supports, VoteWeight, VoterOf, + data_provider, ElectionDataProvider, ElectionProvider, ElectionProviderBase, ScoreProvider, + SortedListProvider, Supports, VoteWeight, VoterOf, }; use frame_support::{ dispatch::WithPostDispatchInfo, @@ -38,7 +38,7 @@ use sp_runtime::{ }; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - EraIndex, SessionIndex, StakingInterface, + EraIndex, SessionIndex, Stake, StakingInterface, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -1482,14 +1482,44 @@ impl SortedListProvider for UseNominatorsAndValidatorsM } } +// NOTE: in this entire impl block, the assumption is that `who` is a stash account. impl StakingInterface for Pallet { type AccountId = T::AccountId; type Balance = BalanceOf; - fn minimum_bond() -> Self::Balance { + fn minimum_nominator_bond() -> Self::Balance { MinNominatorBond::::get() } + fn minimum_validator_bond() -> Self::Balance { + MinValidatorBond::::get() + } + + fn desired_validator_count() -> u32 { + ValidatorCount::::get() + } + + fn election_ongoing() -> bool { + ::ongoing() + } + + fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { + let num_slashing_spans = Self::slashing_spans(&who).iter().count() as u32; + Self::force_unstake(RawOrigin::Root.into(), who.clone(), num_slashing_spans) + } + + fn stash_by_ctrl(controller: &Self::AccountId) -> Result { + Self::ledger(controller) + .map(|l| l.stash) + .ok_or(Error::::NotController.into()) + } + + fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { + ErasStakers::::iter_prefix(era).any(|(validator, exposures)| { + validator == *who || exposures.others.iter().any(|i| i.who == *who) + }) + } + fn bonding_duration() -> EraIndex { T::BondingDuration::get() } @@ -1498,58 +1528,81 @@ impl StakingInterface for Pallet { Self::current_era().unwrap_or(Zero::zero()) } - fn active_stake(controller: &Self::AccountId) -> Option { - Self::ledger(controller).map(|l| l.active) - } - - fn total_stake(controller: &Self::AccountId) -> Option { - Self::ledger(controller).map(|l| l.total) + fn stake(who: &Self::AccountId) -> Result, DispatchError> { + Self::bonded(who) + .and_then(|c| Self::ledger(c)) + .map(|l| Stake { stash: l.stash, total: l.total, active: l.active }) + .ok_or(Error::::NotStash.into()) } - fn bond_extra(stash: Self::AccountId, extra: Self::Balance) -> DispatchResult { - Self::bond_extra(RawOrigin::Signed(stash).into(), extra) + fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { + Self::bond_extra(RawOrigin::Signed(who.clone()).into(), extra) } - fn unbond(controller: Self::AccountId, value: Self::Balance) -> DispatchResult { - Self::unbond(RawOrigin::Signed(controller).into(), value) + fn unbond(who: &Self::AccountId, value: Self::Balance) -> DispatchResult { + let ctrl = Self::bonded(who).ok_or(Error::::NotStash)?; + Self::unbond(RawOrigin::Signed(ctrl).into(), value) } - fn chill(controller: Self::AccountId) -> DispatchResult { - Self::chill(RawOrigin::Signed(controller).into()) + fn chill(who: &Self::AccountId) -> DispatchResult { + // defensive-only: any account bonded via this interface has the stash set as the + // controller, but we have to be sure. Same comment anywhere else that we read this. + let ctrl = Self::bonded(who).ok_or(Error::::NotStash)?; + Self::chill(RawOrigin::Signed(ctrl).into()) } fn withdraw_unbonded( - controller: Self::AccountId, + who: Self::AccountId, num_slashing_spans: u32, ) -> Result { - Self::withdraw_unbonded(RawOrigin::Signed(controller.clone()).into(), num_slashing_spans) - .map(|_| !Ledger::::contains_key(&controller)) + let ctrl = Self::bonded(who).ok_or(Error::::NotStash)?; + Self::withdraw_unbonded(RawOrigin::Signed(ctrl.clone()).into(), num_slashing_spans) + .map(|_| !Ledger::::contains_key(&ctrl)) .map_err(|with_post| with_post.error) } fn bond( - stash: Self::AccountId, - controller: Self::AccountId, + who: &Self::AccountId, value: Self::Balance, - payee: Self::AccountId, + payee: &Self::AccountId, ) -> DispatchResult { Self::bond( - RawOrigin::Signed(stash).into(), - T::Lookup::unlookup(controller), + RawOrigin::Signed(who.clone()).into(), + T::Lookup::unlookup(who.clone()), value, - RewardDestination::Account(payee), + RewardDestination::Account(payee.clone()), ) } - fn nominate(controller: Self::AccountId, targets: Vec) -> DispatchResult { + fn nominate(who: &Self::AccountId, targets: Vec) -> DispatchResult { + let ctrl = Self::bonded(who).ok_or(Error::::NotStash)?; let targets = targets.into_iter().map(T::Lookup::unlookup).collect::>(); - Self::nominate(RawOrigin::Signed(controller).into(), targets) + Self::nominate(RawOrigin::Signed(ctrl).into(), targets) } #[cfg(feature = "runtime-benchmarks")] fn nominations(who: Self::AccountId) -> Option> { Nominators::::get(who).map(|n| n.targets.into_inner()) } + + #[cfg(feature = "runtime-benchmarks")] + fn add_era_stakers( + current_era: &EraIndex, + stash: &T::AccountId, + exposures: Vec<(Self::AccountId, Self::Balance)>, + ) { + let others = exposures + .iter() + .map(|(who, value)| IndividualExposure { who: who.clone(), value: value.clone() }) + .collect::>(); + let exposure = Exposure { total: Default::default(), own: Default::default(), others }; + Self::add_era_stakers(current_era.clone(), stash.clone(), exposure) + } + + #[cfg(feature = "runtime-benchmarks")] + fn set_current_era(era: EraIndex) { + CurrentEra::::put(era); + } } #[cfg(any(test, feature = "try-runtime"))] diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 560c3b6ed830c..df90873ab2e59 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -262,7 +262,7 @@ pub mod pallet { type WeightInfo: WeightInfo; } - /// The ideal number of staking participants. + /// The ideal number of active validators. #[pallet::storage] #[pallet::getter(fn validator_count)] pub type ValidatorCount = StorageValue<_, u32, ValueQuery>; diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index 5a3e97b4d5274..703f0abe80458 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -19,8 +19,9 @@ //! A crate which contains primitives that are useful for implementation that uses staking //! approaches in general. Definitions related to sessions, slashing, etc go here. + use sp_runtime::{DispatchError, DispatchResult}; -use sp_std::collections::btree_map::BTreeMap; +use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; pub mod offence; @@ -54,25 +55,55 @@ impl OnStakerSlash for () { } } -/// Trait for communication with the staking pallet. +/// A struct that reflects stake that an account has in the staking system. Provides a set of +/// methods to operate on it's properties. Aimed at making `StakingInterface` more concise. +pub struct Stake { + /// The stash account whose balance is actually locked and at stake. + pub stash: T::AccountId, + /// The total stake that `stash` has in the staking system. This includes the + /// `active` stake, and any funds currently in the process of unbonding via + /// [`StakingInterface::unbond`]. + /// + /// # Note + /// + /// This is only guaranteed to reflect the amount locked by the staking system. If there are + /// non-staking locks on the bonded pair's balance this amount is going to be larger in + /// reality. + pub total: T::Balance, + /// The total amount of the stash's balance that will be at stake in any forthcoming + /// rounds. + pub active: T::Balance, +} + +/// A generic representation of a staking implementation. +/// +/// This interface uses the terminology of NPoS, but it is aims to be generic enough to cover other +/// implementations as well. pub trait StakingInterface { /// Balance type used by the staking system. - type Balance; + type Balance: PartialEq; /// AccountId type used by the staking system type AccountId; - /// The minimum amount required to bond in order to be a nominator. This does not necessarily - /// mean the nomination will be counted in an election, but instead just enough to be stored as - /// a nominator. In other words, this is the minimum amount to register the intention to - /// nominate. - fn minimum_bond() -> Self::Balance; + /// The minimum amount required to bond in order to set nomination intentions. This does not + /// necessarily mean the nomination will be counted in an election, but instead just enough to + /// be stored as a nominator. In other words, this is the minimum amount to register the + /// intention to nominate. + fn minimum_nominator_bond() -> Self::Balance; - /// Number of eras that staked funds must remain bonded for. + /// The minimum amount required to bond in order to set validation intentions. + fn minimum_validator_bond() -> Self::Balance; + + /// Return a stash account that is controlled by a `controller`. /// - /// # Note + /// ## Note /// - /// This must be strictly greater than the staking systems slash deffer duration. + /// The controller abstraction is not permanent and might go away. Avoid using this as much as + /// possible. + fn stash_by_ctrl(controller: &Self::AccountId) -> Result; + + /// Number of eras that staked funds must remain bonded for. fn bonding_duration() -> EraIndex; /// The current era index. @@ -80,41 +111,39 @@ pub trait StakingInterface { /// This should be the latest planned era that the staking system knows about. fn current_era() -> EraIndex; - /// The amount of active stake that `stash` has in the staking system. - fn active_stake(stash: &Self::AccountId) -> Option; + /// Returns the stake of `who`. + fn stake(who: &Self::AccountId) -> Result, DispatchError>; - /// The total stake that `stash` has in the staking system. This includes the - /// [`Self::active_stake`], and any funds currently in the process of unbonding via - /// [`Self::unbond`]. - /// - /// # Note - /// - /// This is only guaranteed to reflect the amount locked by the staking system. If there are - /// non-staking locks on the bonded pair's balance this may not be accurate. - fn total_stake(stash: &Self::AccountId) -> Option; + fn total_stake(who: &Self::AccountId) -> Result { + Self::stake(who).map(|s| s.total) + } - /// Bond (lock) `value` of `stash`'s balance. `controller` will be set as the account - /// controlling `stash`. This creates what is referred to as "bonded pair". - fn bond( - stash: Self::AccountId, - controller: Self::AccountId, - value: Self::Balance, - payee: Self::AccountId, - ) -> DispatchResult; - - /// Have `controller` nominate `validators`. - fn nominate( - controller: Self::AccountId, - validators: sp_std::vec::Vec, - ) -> DispatchResult; - - /// Chill `stash`. - fn chill(controller: Self::AccountId) -> DispatchResult; - - /// Bond some extra amount in the _Stash_'s free balance against the active bonded balance of - /// the account. The amount extra actually bonded will never be more than the _Stash_'s free + fn active_stake(who: &Self::AccountId) -> Result { + Self::stake(who).map(|s| s.active) + } + + fn is_unbonding(who: &Self::AccountId) -> Result { + Self::stake(who).map(|s| s.active != s.total) + } + + fn fully_unbond(who: &Self::AccountId) -> DispatchResult { + Self::unbond(who, Self::stake(who)?.active) + } + + /// Bond (lock) `value` of `who`'s balance, while forwarding any rewards to `payee`. + fn bond(who: &Self::AccountId, value: Self::Balance, payee: &Self::AccountId) + -> DispatchResult; + + /// Have `who` nominate `validators`. + fn nominate(who: &Self::AccountId, validators: Vec) -> DispatchResult; + + /// Chill `who`. + fn chill(who: &Self::AccountId) -> DispatchResult; + + /// Bond some extra amount in `who`'s free balance against the active bonded balance of + /// the account. The amount extra actually bonded will never be more than `who`'s free /// balance. - fn bond_extra(stash: Self::AccountId, extra: Self::Balance) -> DispatchResult; + fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult; /// Schedule a portion of the active bonded balance to be unlocked at era /// [Self::current_era] + [`Self::bonding_duration`]. @@ -125,7 +154,7 @@ pub trait StakingInterface { /// The amount of times this can be successfully called is limited based on how many distinct /// eras funds are schedule to unlock in. Calling [`Self::withdraw_unbonded`] after some unlock /// schedules have reached their unlocking era should allow more calls to this function. - fn unbond(stash: Self::AccountId, value: Self::Balance) -> DispatchResult; + fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult; /// Unlock any funds schedule to unlock before or at the current era. /// @@ -135,7 +164,29 @@ pub trait StakingInterface { num_slashing_spans: u32, ) -> Result; + /// The ideal number of active validators. + fn desired_validator_count() -> u32; + + /// Whether or not there is an ongoing election. + fn election_ongoing() -> bool; + + /// Force a current staker to become completely unstaked, immediately. + fn force_unstake(who: Self::AccountId) -> DispatchResult; + + /// Checks whether an account `staker` has been exposed in an era. + fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool; + /// Get the nominations of a stash, if they are a nominator, `None` otherwise. #[cfg(feature = "runtime-benchmarks")] - fn nominations(who: Self::AccountId) -> Option>; + fn nominations(who: Self::AccountId) -> Option>; + + #[cfg(feature = "runtime-benchmarks")] + fn add_era_stakers( + current_era: &EraIndex, + stash: &Self::AccountId, + exposures: Vec<(Self::AccountId, Self::Balance)>, + ); + + #[cfg(feature = "runtime-benchmarks")] + fn set_current_era(era: EraIndex); } From 21a7f8ee05017c8ae895fb722df92d985ed6fd21 Mon Sep 17 00:00:00 2001 From: Doordashcon Date: Sat, 29 Oct 2022 15:57:16 +0100 Subject: [PATCH 1320/1472] nomination-pools: allow pool-ids to be reused (#12407) * initial * logic check * do_create * cargo fmt * fixes * ensure_signed * update * cargo fmt * remove unused import --- frame/nomination-pools/src/lib.rs | 159 +++++++++++++++++----------- frame/nomination-pools/src/tests.rs | 38 +++++++ 2 files changed, 137 insertions(+), 60 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 5173b2e7e7d21..3661a7f70b48a 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -28,7 +28,7 @@ //! //! ## Key terms //! -//! * pool id: A unique identifier of each pool. Set to u12 +//! * pool id: A unique identifier of each pool. Set to u32. //! * bonded pool: Tracks the distribution of actively staked funds. See [`BondedPool`] and //! [`BondedPoolInner`]. //! * reward pool: Tracks rewards earned by actively staked funds. See [`RewardPool`] and @@ -47,7 +47,7 @@ //! exactly the same rules and conditions as a normal staker. Its bond increases or decreases as //! members join, it can `nominate` or `chill`, and might not even earn staking rewards if it is //! not nominating proper validators. -//! * reward account: A similar key-less account, that is set as the `Payee` account fo the bonded +//! * reward account: A similar key-less account, that is set as the `Payee` account for the bonded //! account for all staking rewards. //! //! ## Usage @@ -1429,6 +1429,10 @@ pub mod pallet { Defensive(DefensiveError), /// Partial unbonding now allowed permissionlessly. PartialUnbondNotAllowedPermissionlessly, + /// Pool id currently in use. + PoolIdInUse, + /// Pool id provided is not correct/usable. + InvalidPoolId, } #[derive(Encode, Decode, PartialEq, TypeInfo, frame_support::PalletError, RuntimeDebug)] @@ -1850,73 +1854,38 @@ pub mod pallet { nominator: AccountIdLookupOf, state_toggler: AccountIdLookupOf, ) -> DispatchResult { - let who = ensure_signed(origin)?; - let root = T::Lookup::lookup(root)?; - let nominator = T::Lookup::lookup(nominator)?; - let state_toggler = T::Lookup::lookup(state_toggler)?; - - ensure!(amount >= Pallet::::depositor_min_bond(), Error::::MinimumBondNotMet); - ensure!( - MaxPools::::get() - .map_or(true, |max_pools| BondedPools::::count() < max_pools), - Error::::MaxPools - ); - ensure!(!PoolMembers::::contains_key(&who), Error::::AccountBelongsToOtherPool); + let depositor = ensure_signed(origin)?; let pool_id = LastPoolId::::try_mutate::<_, Error, _>(|id| { *id = id.checked_add(1).ok_or(Error::::OverflowRisk)?; Ok(*id) })?; - let mut bonded_pool = BondedPool::::new( - pool_id, - PoolRoles { - root: Some(root), - nominator: Some(nominator), - state_toggler: Some(state_toggler), - depositor: who.clone(), - }, - ); - - bonded_pool.try_inc_members()?; - let points = bonded_pool.try_bond_funds(&who, amount, BondType::Create)?; - T::Currency::transfer( - &who, - &bonded_pool.reward_account(), - T::Currency::minimum_balance(), - ExistenceRequirement::AllowDeath, - )?; + Self::do_create(depositor, amount, root, nominator, state_toggler, pool_id) + } - PoolMembers::::insert( - who.clone(), - PoolMember:: { - pool_id, - points, - last_recorded_reward_counter: Zero::zero(), - unbonding_eras: Default::default(), - }, - ); - RewardPools::::insert( - pool_id, - RewardPool:: { - last_recorded_reward_counter: Zero::zero(), - last_recorded_total_payouts: Zero::zero(), - total_rewards_claimed: Zero::zero(), - }, - ); - ReversePoolIdLookup::::insert(bonded_pool.bonded_account(), pool_id); + /// Create a new delegation pool with a previously used pool id + /// + /// # Arguments + /// + /// same as `create` with the inclusion of + /// * `pool_id` - `A valid PoolId. + #[pallet::weight(T::WeightInfo::create())] + #[transactional] + pub fn create_with_pool_id( + origin: OriginFor, + #[pallet::compact] amount: BalanceOf, + root: AccountIdLookupOf, + nominator: AccountIdLookupOf, + state_toggler: AccountIdLookupOf, + pool_id: PoolId, + ) -> DispatchResult { + let depositor = ensure_signed(origin)?; - Self::deposit_event(Event::::Created { depositor: who.clone(), pool_id }); + ensure!(!BondedPools::::contains_key(pool_id), Error::::PoolIdInUse); + ensure!(pool_id < LastPoolId::::get(), Error::::InvalidPoolId); - Self::deposit_event(Event::::Bonded { - member: who, - pool_id, - bonded: amount, - joined: true, - }); - bonded_pool.put(); - - Ok(()) + Self::do_create(depositor, amount, root, nominator, state_toggler, pool_id) } /// Nominate on behalf of the pool. @@ -2340,6 +2309,76 @@ impl Pallet { Ok(pending_rewards) } + fn do_create( + who: T::AccountId, + amount: BalanceOf, + root: AccountIdLookupOf, + nominator: AccountIdLookupOf, + state_toggler: AccountIdLookupOf, + pool_id: PoolId, + ) -> DispatchResult { + let root = T::Lookup::lookup(root)?; + let nominator = T::Lookup::lookup(nominator)?; + let state_toggler = T::Lookup::lookup(state_toggler)?; + + ensure!(amount >= Pallet::::depositor_min_bond(), Error::::MinimumBondNotMet); + ensure!( + MaxPools::::get().map_or(true, |max_pools| BondedPools::::count() < max_pools), + Error::::MaxPools + ); + ensure!(!PoolMembers::::contains_key(&who), Error::::AccountBelongsToOtherPool); + let mut bonded_pool = BondedPool::::new( + pool_id, + PoolRoles { + root: Some(root), + nominator: Some(nominator), + state_toggler: Some(state_toggler), + depositor: who.clone(), + }, + ); + + bonded_pool.try_inc_members()?; + let points = bonded_pool.try_bond_funds(&who, amount, BondType::Create)?; + + T::Currency::transfer( + &who, + &bonded_pool.reward_account(), + T::Currency::minimum_balance(), + ExistenceRequirement::AllowDeath, + )?; + + PoolMembers::::insert( + who.clone(), + PoolMember:: { + pool_id, + points, + last_recorded_reward_counter: Zero::zero(), + unbonding_eras: Default::default(), + }, + ); + RewardPools::::insert( + pool_id, + RewardPool:: { + last_recorded_reward_counter: Zero::zero(), + last_recorded_total_payouts: Zero::zero(), + total_rewards_claimed: Zero::zero(), + }, + ); + ReversePoolIdLookup::::insert(bonded_pool.bonded_account(), pool_id); + + Self::deposit_event(Event::::Created { depositor: who.clone(), pool_id }); + + Self::deposit_event(Event::::Bonded { + member: who, + pool_id, + bonded: amount, + joined: true, + }); + bonded_pool.put(); + + Ok(()) + } + /// Ensure the correctness of the state of this pallet. /// /// This should be valid before or after each state transition of this pallet. diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 0c909b68152bb..17fee7cc8dda3 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -4201,6 +4201,44 @@ mod create { ); }); } + + #[test] + fn create_with_pool_id_works() { + ExtBuilder::default().build_and_execute(|| { + let ed = Balances::minimum_balance(); + + Balances::make_free_balance_be(&11, StakingMock::minimum_bond() + ed); + assert_ok!(Pools::create( + RuntimeOrigin::signed(11), + StakingMock::minimum_bond(), + 123, + 456, + 789 + )); + + assert_eq!(Balances::free_balance(&11), 0); + // delete the initial pool created, then pool_Id `1` will be free + + assert_noop!( + Pools::create_with_pool_id(RuntimeOrigin::signed(12), 20, 234, 654, 783, 1), + Error::::PoolIdInUse + ); + + assert_noop!( + Pools::create_with_pool_id(RuntimeOrigin::signed(12), 20, 234, 654, 783, 3), + Error::::InvalidPoolId + ); + + // start dismantling the pool. + assert_ok!(Pools::set_state(RuntimeOrigin::signed(902), 1, PoolState::Destroying)); + assert_ok!(fully_unbond_permissioned(10)); + + CurrentEra::set(3); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 10)); + + assert_ok!(Pools::create_with_pool_id(RuntimeOrigin::signed(10), 20, 234, 654, 783, 1)); + }); + } } mod nominate { From 0e33b4e9a3deb0a3637f0c618c6c8ac24f36c0d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Sun, 30 Oct 2022 11:09:47 +0100 Subject: [PATCH 1321/1472] WIP: Replace `wasm-gc` with `wasm-opt` (#12280) * Use wasm-opt on runtime * Optimize for size * Simplify fn compact_wasm_file * Run a lighter pass for non production builds * Disable optimizations and keep name section * Update wasm-opt * Remove dward sections * Update wasm-opt * Update wasm-opt --- Cargo.lock | 164 +++++++++++++++++++------ utils/wasm-builder/Cargo.toml | 2 +- utils/wasm-builder/src/wasm_project.rs | 55 ++++----- 3 files changed, 150 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbf02a3fa6a50..b87f45508dfc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.38" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" [[package]] name = "approx" @@ -836,9 +836,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.71" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" dependencies = [ "jobserver", ] @@ -1030,6 +1030,16 @@ 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 = "comfy-table" version = "6.0.0" @@ -1489,6 +1499,50 @@ dependencies = [ "zeroize", ] +[[package]] +name = "cxx" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "darling" version = "0.13.0" @@ -3904,6 +3958,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + [[package]] name = "linked-hash-map" version = "0.5.4" @@ -6451,15 +6514,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "parity-wasm" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ad52817c4d343339b3bc2e26861bd21478eda0b7509acf83505727000512ac" -dependencies = [ - "byteorder", -] - [[package]] name = "parity-wasm" version = "0.45.0" @@ -7237,9 +7291,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.5" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -7258,9 +7312,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "region" @@ -8074,7 +8128,7 @@ dependencies = [ "log", "once_cell", "parity-scale-codec", - "parity-wasm 0.45.0", + "parity-wasm", "paste 1.0.6", "rustix", "sc-allocator", @@ -8924,6 +8978,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "sct" version = "0.7.0" @@ -10095,7 +10155,7 @@ version = "5.0.0" dependencies = [ "impl-serde", "parity-scale-codec", - "parity-wasm 0.45.0", + "parity-wasm", "scale-info", "serde", "sp-core-hashing-proc-macro", @@ -10534,7 +10594,7 @@ dependencies = [ "tempfile", "toml", "walkdir", - "wasm-gc-api", + "wasm-opt", ] [[package]] @@ -10633,18 +10693,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -11092,7 +11152,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "digest 0.10.3", "rand 0.8.5", "static_assertions", @@ -11368,23 +11428,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c279e376c7a8e8752a8f1eaa35b7b0bee6bb9fb0cdacfa97cc3f1f289c87e2b4" [[package]] -name = "wasm-gc-api" -version = "0.1.11" +name = "wasm-instrument" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c32691b6c7e6c14e7f8fd55361a9088b507aa49620fcd06c09b3a1082186b9" +checksum = "aa1dafb3e60065305741e83db35c6c2584bb3725b692b5b66148a38d72ace6cd" dependencies = [ - "log", - "parity-wasm 0.32.0", - "rustc-demangle", + "parity-wasm", ] [[package]] -name = "wasm-instrument" -version = "0.3.0" +name = "wasm-opt" +version = "0.110.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa1dafb3e60065305741e83db35c6c2584bb3725b692b5b66148a38d72ace6cd" +checksum = "b68e8037b4daf711393f4be2056246d12d975651b14d581520ad5d1f19219cec" dependencies = [ - "parity-wasm 0.45.0", + "anyhow", + "libc", + "strum", + "strum_macros", + "tempfile", + "thiserror", + "wasm-opt-cxx-sys", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-cxx-sys" +version = "0.110.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91adbad477e97bba3fbd21dd7bfb594e7ad5ceb9169ab1c93ab9cb0ada636b6f" +dependencies = [ + "anyhow", + "cxx", + "cxx-build", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-sys" +version = "0.110.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4fa5a322a4e6ac22fd141f498d56afbdbf9df5debeac32380d2dcaa3e06941" +dependencies = [ + "anyhow", + "cc", + "cxx", + "cxx-build", + "regex", ] [[package]] @@ -11621,7 +11711,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc13b3c219ca9aafeec59150d80d89851df02e0061bc357b4d66fc55a8d38787" dependencies = [ - "parity-wasm 0.45.0", + "parity-wasm", "wasmi-validation", "wasmi_core", ] @@ -11632,7 +11722,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ff416ad1ff0c42e5a926ed5d5fab74c0f098749aa0ad8b2a34b982ce0e867b" dependencies = [ - "parity-wasm 0.45.0", + "parity-wasm", ] [[package]] diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index ac0ba5dbdb85a..46c5929969fbb 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -20,6 +20,6 @@ strum = { version = "0.24.1", features = ["derive"] } tempfile = "3.1.0" toml = "0.5.4" walkdir = "2.3.2" -wasm-gc-api = "0.1.11" sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } filetime = "0.2.16" +wasm-opt = "0.110" \ No newline at end of file diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 197c1d1b220bb..07219676413fc 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -656,50 +656,39 @@ fn compact_wasm_file( project: &Path, profile: Profile, cargo_manifest: &Path, - wasm_binary_name: Option, + out_name: Option, ) -> (Option, Option, WasmBinaryBloaty) { - let default_wasm_binary_name = get_wasm_binary_name(cargo_manifest); - let wasm_file = project + let default_out_name = get_wasm_binary_name(cargo_manifest); + let out_name = out_name.unwrap_or_else(|| default_out_name.clone()); + let in_path = project .join("target/wasm32-unknown-unknown") .join(profile.directory()) - .join(format!("{}.wasm", default_wasm_binary_name)); - - let wasm_compact_file = if profile.wants_compact() { - let wasm_compact_file = project.join(format!( - "{}.compact.wasm", - wasm_binary_name.clone().unwrap_or_else(|| default_wasm_binary_name.clone()), - )); - wasm_gc::garbage_collect_file(&wasm_file, &wasm_compact_file) + .join(format!("{}.wasm", default_out_name)); + + let (wasm_compact_path, wasm_compact_compressed_path) = if profile.wants_compact() { + let wasm_compact_path = project.join(format!("{}.compact.wasm", out_name,)); + wasm_opt::OptimizationOptions::new_opt_level_0() + .mvp_features_only() + .debug_info(true) + .add_pass(wasm_opt::Pass::StripDwarf) + .run(&in_path, &wasm_compact_path) .expect("Failed to compact generated WASM binary."); - Some(WasmBinary(wasm_compact_file)) - } else { - None - }; - - let wasm_compact_compressed_file = wasm_compact_file.as_ref().and_then(|compact_binary| { - let file_name = - wasm_binary_name.clone().unwrap_or_else(|| default_wasm_binary_name.clone()); - let wasm_compact_compressed_file = - project.join(format!("{}.compact.compressed.wasm", file_name)); - - if compress_wasm(&compact_binary.0, &wasm_compact_compressed_file) { - Some(WasmBinary(wasm_compact_compressed_file)) + let wasm_compact_compressed_path = + project.join(format!("{}.compact.compressed.wasm", out_name)); + if compress_wasm(&wasm_compact_path, &wasm_compact_compressed_path) { + (Some(WasmBinary(wasm_compact_path)), Some(WasmBinary(wasm_compact_compressed_path))) } else { - None + (Some(WasmBinary(wasm_compact_path)), None) } - }); - - let bloaty_file_name = if let Some(name) = wasm_binary_name { - format!("{}.wasm", name) } else { - format!("{}.wasm", default_wasm_binary_name) + (None, None) }; - let bloaty_file = project.join(bloaty_file_name); - fs::copy(wasm_file, &bloaty_file).expect("Copying the bloaty file to the project dir."); + let bloaty_path = project.join(format!("{}.wasm", out_name)); + fs::copy(in_path, &bloaty_path).expect("Copying the bloaty file to the project dir."); - (wasm_compact_file, wasm_compact_compressed_file, WasmBinaryBloaty(bloaty_file)) + (wasm_compact_path, wasm_compact_compressed_path, WasmBinaryBloaty(bloaty_path)) } fn compress_wasm(wasm_binary_path: &Path, compressed_binary_out_path: &Path) -> bool { From 5fbd2a333491f34cbb5e77ba1135293b9ff58eac Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sun, 30 Oct 2022 17:00:26 +0100 Subject: [PATCH 1322/1472] Use minimum_nominator_bond instead of nominator_bond (#12585) Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/nomination-pools/src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 17fee7cc8dda3..aadd4871d737e 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -4207,10 +4207,10 @@ mod create { ExtBuilder::default().build_and_execute(|| { let ed = Balances::minimum_balance(); - Balances::make_free_balance_be(&11, StakingMock::minimum_bond() + ed); + Balances::make_free_balance_be(&11, StakingMock::minimum_nominator_bond() + ed); assert_ok!(Pools::create( RuntimeOrigin::signed(11), - StakingMock::minimum_bond(), + StakingMock::minimum_nominator_bond(), 123, 456, 789 From 5ae005c244295d23586c93da43148b2bc826b137 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Sun, 30 Oct 2022 18:58:29 +0100 Subject: [PATCH 1323/1472] BlockId removal: refactor: Backend::append_justification (#12551) * BlockId removal: refactor: Backend::append_justification It changes the arguments of `Backend::append_justification` from: block: `BlockId` to: hash: `&Block::Hash` This PR is part of `BlockId::Number` refactoring analysis (paritytech/substrate#11292) * Error message improved Co-authored-by: Adrian Catangiu * single error message in beefy::finalize * println removed Co-authored-by: Adrian Catangiu --- client/api/src/backend.rs | 5 ++--- client/api/src/in_mem.rs | 20 ++++++++++---------- client/beefy/src/worker.rs | 32 +++++++++++++++++++------------- client/db/src/lib.rs | 15 +++++++-------- 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 77a9da3535655..df9c92b626ecc 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -27,7 +27,6 @@ use sp_blockchain; use sp_consensus::BlockOrigin; use sp_core::offchain::OffchainStorage; use sp_runtime::{ - generic::BlockId, traits::{Block as BlockT, HashFor, NumberFor}, Justification, Justifications, StateVersion, Storage, }; @@ -485,12 +484,12 @@ pub trait Backend: AuxStore + Send + Sync { justification: Option, ) -> sp_blockchain::Result<()>; - /// Append justification to the block with the given Id. + /// Append justification to the block with the given `hash`. /// /// This should only be called for blocks that are already finalized. fn append_justification( &self, - block: BlockId, + hash: &Block::Hash, justification: Justification, ) -> sp_blockchain::Result<()>; diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 29f7eade9fa6f..4028b99d6fb37 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -295,10 +295,9 @@ impl Blockchain { fn append_justification( &self, - id: BlockId, + hash: &Block::Hash, justification: Justification, ) -> sp_blockchain::Result<()> { - let hash = self.expect_block_hash_from_id(&id)?; let mut storage = self.storage.write(); let block = storage @@ -745,10 +744,10 @@ where fn append_justification( &self, - block: BlockId, + hash: &Block::Hash, justification: Justification, ) -> sp_blockchain::Result<()> { - self.blockchain.append_justification(block, justification) + self.blockchain.append_justification(hash, justification) } fn blockchain(&self) -> &Self::Blockchain { @@ -865,26 +864,27 @@ mod tests { fn append_and_retrieve_justifications() { let blockchain = test_blockchain(); let last_finalized = blockchain.last_finalized().unwrap(); - let block = BlockId::Hash(last_finalized); - blockchain.append_justification(block, (ID2, vec![4])).unwrap(); + blockchain.append_justification(&last_finalized, (ID2, vec![4])).unwrap(); let justifications = { let mut just = Justifications::from((ID1, vec![3])); just.append((ID2, vec![4])); just }; - assert_eq!(blockchain.justifications(block).unwrap(), Some(justifications)); + assert_eq!( + blockchain.justifications(BlockId::Hash(last_finalized)).unwrap(), + Some(justifications) + ); } #[test] fn store_duplicate_justifications_is_forbidden() { let blockchain = test_blockchain(); let last_finalized = blockchain.last_finalized().unwrap(); - let block = BlockId::Hash(last_finalized); - blockchain.append_justification(block, (ID2, vec![0])).unwrap(); + blockchain.append_justification(&last_finalized, (ID2, vec![0])).unwrap(); assert!(matches!( - blockchain.append_justification(block, (ID2, vec![1])), + blockchain.append_justification(&last_finalized, (ID2, vec![1])), Err(sp_blockchain::Error::BadJustification(_)), )); } diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 9b331b73ed093..305b92d696975 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -500,20 +500,22 @@ where self.on_demand_justifications.cancel_requests_older_than(block_num); - if let Err(e) = self.backend.append_justification( - BlockId::Number(block_num), - (BEEFY_ENGINE_ID, finality_proof.encode()), - ) { + if let Err(e) = self + .backend + .blockchain() + .expect_block_hash_from_id(&BlockId::Number(block_num)) + .and_then(|hash| { + self.links + .to_rpc_best_block_sender + .notify(|| Ok::<_, ()>(hash)) + .expect("forwards closure result; the closure always returns Ok; qed."); + + self.backend + .append_justification(&hash, (BEEFY_ENGINE_ID, finality_proof.encode())) + }) { error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, finality_proof); } - self.backend.blockchain().hash(block_num).ok().flatten().map(|hash| { - self.links - .to_rpc_best_block_sender - .notify(|| Ok::<_, ()>(hash)) - .expect("forwards closure result; the closure always returns Ok; qed.") - }); - self.links .to_rpc_justif_sender .notify(|| Ok::<_, ()>(finality_proof)) @@ -1546,8 +1548,10 @@ pub(crate) mod tests { commitment, signatures: vec![None], }); + let hashof10 = + backend.blockchain().expect_block_hash_from_id(&BlockId::Number(10)).unwrap(); backend - .append_justification(BlockId::Number(10), (BEEFY_ENGINE_ID, justif.encode())) + .append_justification(&hashof10, (BEEFY_ENGINE_ID, justif.encode())) .unwrap(); // initialize voter at block 13, expect rounds initialized at last beefy finalized 10 @@ -1580,8 +1584,10 @@ pub(crate) mod tests { commitment, signatures: vec![None], }); + let hashof12 = + backend.blockchain().expect_block_hash_from_id(&BlockId::Number(12)).unwrap(); backend - .append_justification(BlockId::Number(12), (BEEFY_ENGINE_ID, justif.encode())) + .append_justification(&hashof12, (BEEFY_ENGINE_ID, justif.encode())) .unwrap(); // initialize voter at block 13, expect rounds initialized at last beefy finalized 12 diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index e212b382716f1..4a7159208c2c8 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -2013,12 +2013,11 @@ impl sc_client_api::backend::Backend for Backend { fn append_justification( &self, - block: BlockId, + hash: &Block::Hash, justification: Justification, ) -> ClientResult<()> { let mut transaction: Transaction = Transaction::new(); - let hash = self.blockchain.expect_block_hash_from_id(&block)?; - let header = self.blockchain.expect_header(block)?; + let header = self.blockchain.expect_header(BlockId::Hash(*hash))?; let number = *header.number(); // Check if the block is finalized first. @@ -2027,13 +2026,13 @@ impl sc_client_api::backend::Backend for Backend { // We can do a quick check first, before doing a proper but more expensive check if number > self.blockchain.info().finalized_number || - (hash != last_finalized && !is_descendent_of(&hash, &last_finalized)?) + (*hash != last_finalized && !is_descendent_of(hash, &last_finalized)?) { return Err(ClientError::NotInFinalizedChain) } let justifications = if let Some(mut stored_justifications) = - self.blockchain.justifications(block)? + self.blockchain.justifications(BlockId::Hash(*hash))? { if !stored_justifications.append(justification) { return Err(ClientError::BadJustification("Duplicate consensus engine ID".into())) @@ -2045,7 +2044,7 @@ impl sc_client_api::backend::Backend for Backend { transaction.set_from_vec( columns::JUSTIFICATIONS, - &utils::number_and_hash_to_lookup_key(number, hash)?, + &utils::number_and_hash_to_lookup_key(number, *hash)?, justifications.encode(), ); @@ -3029,11 +3028,11 @@ pub(crate) mod tests { backend.finalize_block(&block1, Some(just0.clone().into())).unwrap(); let just1 = (CONS1_ENGINE_ID, vec![4, 5]); - backend.append_justification(BlockId::Number(1), just1.clone()).unwrap(); + backend.append_justification(&block1, just1.clone()).unwrap(); let just2 = (CONS1_ENGINE_ID, vec![6, 7]); assert!(matches!( - backend.append_justification(BlockId::Number(1), just2), + backend.append_justification(&block1, just2), Err(ClientError::BadJustification(_)) )); From 70351393fd632317124f35ab8b24ef7134e08864 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Mon, 31 Oct 2022 12:20:29 +0100 Subject: [PATCH 1324/1472] fix some typos (#12584) --- frame/conviction-voting/src/lib.rs | 12 ++++++------ frame/conviction-voting/src/vote.rs | 2 +- frame/ranked-collective/src/lib.rs | 10 +++++----- frame/referenda/src/lib.rs | 6 +++--- frame/referenda/src/types.rs | 4 ++-- frame/whitelist/src/lib.rs | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index b876a9354ee59..3ecc6e56be94e 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -121,8 +121,8 @@ pub mod pallet { /// The maximum number of concurrent votes an account may have. /// - /// Also used to compute weight, an overly large value can - /// lead to extrinsic with large weight estimation: see `delegate` for instance. + /// Also used to compute weight, an overly large value can lead to extrinsics with large + /// weight estimation: see `delegate` for instance. #[pallet::constant] type MaxVotes: Get; @@ -261,7 +261,7 @@ pub mod pallet { /// Undelegate the voting power of the sending account for a particular class of polls. /// /// Tokens may be unlocked following once an amount of time consistent with the lock period - /// of the conviction with which the delegation was issued. + /// of the conviction with which the delegation was issued has passed. /// /// The dispatch origin of this call must be _Signed_ and the signing account must be /// currently delegating. @@ -284,7 +284,7 @@ pub mod pallet { Ok(Some(T::WeightInfo::undelegate(votes)).into()) } - /// Remove the lock caused prior voting/delegating which has expired within a particluar + /// Remove the lock caused by prior voting/delegating which has expired within a particular /// class. /// /// The dispatch origin of this call must be _Signed_. @@ -475,7 +475,7 @@ impl, I: 'static> Pallet { }) } - /// Return the number of votes for `who` + /// Return the number of votes for `who`. fn increase_upstream_delegation( who: &T::AccountId, class: &ClassOf, @@ -503,7 +503,7 @@ impl, I: 'static> Pallet { }) } - /// Return the number of votes for `who` + /// Return the number of votes for `who`. fn reduce_upstream_delegation( who: &T::AccountId, class: &ClassOf, diff --git a/frame/conviction-voting/src/vote.rs b/frame/conviction-voting/src/vote.rs index a0b17ab4de39d..a8e012b6c97a1 100644 --- a/frame/conviction-voting/src/vote.rs +++ b/frame/conviction-voting/src/vote.rs @@ -233,7 +233,7 @@ where AsMut::>::as_mut(self).rejig(now); } - /// The amount of this account's balance that much currently be locked due to voting. + /// The amount of this account's balance that must currently be locked due to voting. pub fn locked_balance(&self) -> Balance { match self { Voting::Casting(Casting { votes, prior, .. }) => diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 111c5f70efdfa..33aed2704918c 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -21,7 +21,7 @@ //! systems such as the Referenda pallet. Members each have a rank, with zero being the lowest. //! There is no complexity limitation on either the number of members at a rank or the number of //! ranks in the system thus allowing potentially public membership. A member of at least a given -//! rank can be selected at random in O(1) time, allowing for various games to constructed using +//! rank can be selected at random in O(1) time, allowing for various games to be constructed using //! this as a primitive. Members may only be promoted and demoted by one rank at a time, however //! all operations (save one) are O(1) in complexity. The only operation which is not O(1) is the //! `remove_member` since they must be removed from all ranks from the present down to zero. @@ -33,7 +33,7 @@ //! //! Two `Config` trait items control these "rank privileges": `MinRankOfClass` and `VoteWeight`. //! The first controls which ranks are allowed to vote on a particular class of poll. The second -//! controls the weight of a vote given the voters rank compared to the minimum rank of the poll. +//! controls the weight of a vote given the voter's rank compared to the minimum rank of the poll. //! //! An origin control, `EnsureRank`, ensures that the origin is a member of the collective of at //! least a particular rank. @@ -310,8 +310,8 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin(PhantomData<(T, I)>); impl, I: 'static, const MIN_RANK: u16> EnsureOrigin for EnsureRankedMember @@ -430,7 +430,7 @@ pub mod pallet { pub enum Event, I: 'static = ()> { /// A member `who` has been added. MemberAdded { who: T::AccountId }, - /// The member `who`'s rank has been changed to the given `rank`. + /// The member `who`se rank has been changed to the given `rank`. RankChanged { who: T::AccountId, rank: Rank }, /// The member `who` of given `rank` has been removed from the collective. MemberRemoved { who: T::AccountId, rank: Rank }, diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 1bdc19d49c414..d060c3db3fa70 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -249,7 +249,7 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { - /// A referendum has being submitted. + /// A referendum has been submitted. Submitted { /// Index of the referendum. index: ReferendumIndex, @@ -352,7 +352,7 @@ pub mod pallet { HasDeposit, /// The track identifier given was invalid. BadTrack, - /// There are already a full complement of referendums in progress for this track. + /// There are already a full complement of referenda in progress for this track. Full, /// The queue of the track is empty. QueueEmpty, @@ -908,7 +908,7 @@ impl, I: 'static> Pallet { /// /// In terms of storage, every call to it is expected to access: /// - The scheduler, either to insert, remove or alter an entry; - /// - `TrackQueue`, which should be a `BoundedVec` with a low limit (8-16). + /// - `TrackQueue`, which should be a `BoundedVec` with a low limit (8-16); /// - `DecidingCount`. /// /// Both of the two storage items will only have as many items as there are different tracks, diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 2ce93cb6adc3c..48db0847edf2e 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -178,7 +178,7 @@ pub struct ReferendumStatus< pub(crate) proposal: Call, /// The time the proposal should be scheduled for enactment. pub(crate) enactment: DispatchTime, - /// The time of submission. Once `UndecidingTimeout` passes, it may be closed by anyone if it + /// The time of submission. Once `UndecidingTimeout` passes, it may be closed by anyone if /// `deciding` is `None`. pub(crate) submitted: Moment, /// The deposit reserved for the submission of this referendum. @@ -224,7 +224,7 @@ pub enum ReferendumInfo< Approved(Moment, Deposit, Option>), /// Referendum finished with rejection. Submission deposit is held. Rejected(Moment, Deposit, Option>), - /// Referendum finished with cancelation. Submission deposit is held. + /// Referendum finished with cancellation. Submission deposit is held. Cancelled(Moment, Deposit, Option>), /// Referendum finished and was never decided. Submission deposit is held. TimedOut(Moment, Deposit, Option>), diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index 55d5c42b8f4bc..be5fdf9e472b3 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -26,8 +26,8 @@ //! and allow another configurable origin: [`Config::DispatchWhitelistedOrigin`] to dispatch them //! with the root origin. //! -//! In the meantime the call corresponding to the hash must have been submitted to the to the -//! pre-image handler [`PreimageProvider`]. +//! In the meantime the call corresponding to the hash must have been submitted to the pre-image +//! handler [`PreimageProvider`]. #![cfg_attr(not(feature = "std"), no_std)] From 07a6332886f3bd030a49586ba5f825fc3a4d1851 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 31 Oct 2022 12:43:36 +0100 Subject: [PATCH 1325/1472] Added test for Client::block (#12590) --- client/service/test/src/client/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 9937c436a33ff..329bffae03e7b 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1128,6 +1128,14 @@ fn finality_notifications_content() { assert!(finality_notifications.try_next().is_err()); } +#[test] +fn get_block_by_bad_block_hash_returns_none() { + let client = substrate_test_runtime_client::new(); + + let hash = H256::from_low_u64_be(5); + assert!(client.block(&BlockId::Hash(hash)).unwrap().is_none()); +} + #[test] fn get_header_by_block_number_doesnt_panic() { let client = substrate_test_runtime_client::new(); From 0d64ba4268106fffe430d41b541c1aeedd4f8da5 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 31 Oct 2022 17:41:01 +0200 Subject: [PATCH 1326/1472] client/beefy: fix incorrect BEEFY justifications import test (#12593) Signed-off-by: Adrian Catangiu --- client/beefy/src/tests.rs | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index f0647d7b142e6..b0a1433fafec6 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -755,10 +755,16 @@ fn beefy_importing_blocks() { block_on(block_import.import_block(params(block, None), HashMap::new())).unwrap(), ImportResult::AlreadyInChain ); - // Verify no justifications present: + // Verify no BEEFY justifications present: { // none in backend, - assert!(full_client.justifications(&block_id).unwrap().is_none()); + assert_eq!( + full_client + .justifications(&block_id) + .unwrap() + .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), + None + ); // and none sent to BEEFY worker. block_on(poll_fn(move |cx| { assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); @@ -787,11 +793,18 @@ fn beefy_importing_blocks() { ..Default::default() }), ); - // Verify justification successfully imported: + // Verify BEEFY justification successfully imported: { - // available in backend, - assert!(full_client.justifications(&BlockId::Number(block_num)).unwrap().is_some()); - // and also sent to BEEFY worker. + // still not in backend (worker is responsible for appending to backend), + assert_eq!( + full_client + .justifications(&block_id) + .unwrap() + .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), + None + ); + // but sent to BEEFY worker + // (worker will append it to backend when all previous mandatory justifs are there as well). block_on(poll_fn(move |cx| { match justif_recv.poll_next_unpin(cx) { Poll::Ready(Some(_justification)) => (), @@ -823,10 +836,16 @@ fn beefy_importing_blocks() { ..Default::default() }), ); - // Verify bad justifications was not imported: + // Verify bad BEEFY justifications was not imported: { // none in backend, - assert!(full_client.justifications(&block_id).unwrap().is_none()); + assert_eq!( + full_client + .justifications(&BlockId::Number(block_num)) + .unwrap() + .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), + None + ); // and none sent to BEEFY worker. block_on(poll_fn(move |cx| { assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); From ea71267aeb2b627d7a65a16ea6c12d1923d5564a Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 1 Nov 2022 17:24:09 +0100 Subject: [PATCH 1327/1472] BlockId removal: refactor: Backend::body (#12587) It changes the arguments of `Backend::body` method from: `BlockId` to: `&Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) Co-authored-by: parity-processbot <> --- bin/node/inspect/src/lib.rs | 5 +- client/api/src/client.rs | 2 +- client/api/src/in_mem.rs | 15 +++-- client/db/src/lib.rs | 60 +++++++++++-------- .../network/sync/src/block_request_handler.rs | 2 +- client/network/test/src/lib.rs | 2 +- client/service/src/client/client.rs | 22 ++++--- client/service/test/src/client/mod.rs | 11 ++-- client/tracing/src/block/mod.rs | 2 +- client/transaction-pool/benches/basics.rs | 2 +- client/transaction-pool/src/api.rs | 4 +- client/transaction-pool/src/graph/pool.rs | 4 +- client/transaction-pool/src/lib.rs | 18 +++--- client/transaction-pool/src/tests.rs | 2 +- primitives/blockchain/src/backend.rs | 2 +- .../runtime/transaction-pool/src/lib.rs | 14 ++--- 16 files changed, 93 insertions(+), 74 deletions(-) diff --git a/bin/node/inspect/src/lib.rs b/bin/node/inspect/src/lib.rs index aacae0ff7a0d9..1e44cec914995 100644 --- a/bin/node/inspect/src/lib.rs +++ b/bin/node/inspect/src/lib.rs @@ -140,10 +140,11 @@ impl> Inspector BlockAddress::Bytes(bytes) => TBlock::decode(&mut &*bytes)?, BlockAddress::Number(number) => { let id = BlockId::number(number); + let hash = self.chain.expect_block_hash_from_id(&id)?; let not_found = format!("Could not find block {:?}", id); let body = self .chain - .block_body(&id)? + .block_body(&hash)? .ok_or_else(|| Error::NotFound(not_found.clone()))?; let header = self.chain.header(id)?.ok_or_else(|| Error::NotFound(not_found.clone()))?; @@ -154,7 +155,7 @@ impl> Inspector let not_found = format!("Could not find block {:?}", id); let body = self .chain - .block_body(&id)? + .block_body(&hash)? .ok_or_else(|| Error::NotFound(not_found.clone()))?; let header = self.chain.header(id)?.ok_or_else(|| Error::NotFound(not_found.clone()))?; diff --git a/client/api/src/client.rs b/client/api/src/client.rs index b809e0ee61032..670c1711db948 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -110,7 +110,7 @@ pub trait BlockBackend { /// Get block body by ID. Returns `None` if the body is not stored. fn block_body( &self, - id: &BlockId, + hash: &Block::Hash, ) -> sp_blockchain::Result::Extrinsic>>>; /// Get all indexed transactions for a block, diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 4028b99d6fb37..7b0e6f7b72575 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -405,15 +405,14 @@ impl HeaderMetadata for Blockchain { impl blockchain::Backend for Blockchain { fn body( &self, - id: BlockId, + hash: &Block::Hash, ) -> sp_blockchain::Result::Extrinsic>>> { - Ok(self.id(id).and_then(|hash| { - self.storage - .read() - .blocks - .get(&hash) - .and_then(|b| b.extrinsics().map(|x| x.to_vec())) - })) + Ok(self + .storage + .read() + .blocks + .get(hash) + .and_then(|b| b.extrinsics().map(|x| x.to_vec()))) } fn justifications(&self, id: BlockId) -> sp_blockchain::Result> { diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 4a7159208c2c8..9d9a8d268dd81 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -577,8 +577,10 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha } impl sc_client_api::blockchain::Backend for BlockchainDb { - fn body(&self, id: BlockId) -> ClientResult>> { - if let Some(body) = read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY, id)? { + fn body(&self, hash: &Block::Hash) -> ClientResult>> { + if let Some(body) = + read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY, BlockId::Hash::(*hash))? + { // Plain body match Decode::decode(&mut &body[..]) { Ok(body) => return Ok(Some(body)), @@ -590,7 +592,12 @@ impl sc_client_api::blockchain::Backend for BlockchainDb(*hash), + )? { match Vec::>::decode(&mut &index[..]) { Ok(index) => { let mut body = Vec::new(); @@ -3201,11 +3208,11 @@ pub(crate) mod tests { backend.commit_operation(op).unwrap(); } let bc = backend.blockchain(); - assert_eq!(None, bc.body(BlockId::hash(blocks[0])).unwrap()); - assert_eq!(None, bc.body(BlockId::hash(blocks[1])).unwrap()); - assert_eq!(None, bc.body(BlockId::hash(blocks[2])).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); + assert_eq!(None, bc.body(&blocks[0]).unwrap()); + assert_eq!(None, bc.body(&blocks[1]).unwrap()); + assert_eq!(None, bc.body(&blocks[2]).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(&blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(&blocks[4]).unwrap()); } #[test] @@ -3236,11 +3243,11 @@ pub(crate) mod tests { backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); - assert_eq!(Some(vec![0.into()]), bc.body(BlockId::hash(blocks[0])).unwrap()); - assert_eq!(Some(vec![1.into()]), bc.body(BlockId::hash(blocks[1])).unwrap()); - assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(blocks[2])).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); + assert_eq!(Some(vec![0.into()]), bc.body(&blocks[0]).unwrap()); + assert_eq!(Some(vec![1.into()]), bc.body(&blocks[1]).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(&blocks[2]).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(&blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(&blocks[4]).unwrap()); } #[test] @@ -3291,7 +3298,7 @@ pub(crate) mod tests { backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); - assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(fork_hash_root)).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(&fork_hash_root).unwrap()); for i in 1..5 { let mut op = backend.begin_operation().unwrap(); @@ -3300,13 +3307,13 @@ pub(crate) mod tests { backend.commit_operation(op).unwrap(); } - assert_eq!(Some(vec![0.into()]), bc.body(BlockId::hash(blocks[0])).unwrap()); - assert_eq!(Some(vec![1.into()]), bc.body(BlockId::hash(blocks[1])).unwrap()); - assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(blocks[2])).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); + assert_eq!(Some(vec![0.into()]), bc.body(&blocks[0]).unwrap()); + assert_eq!(Some(vec![1.into()]), bc.body(&blocks[1]).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(&blocks[2]).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(&blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(&blocks[4]).unwrap()); - assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(fork_hash_root)).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(&fork_hash_root).unwrap()); assert_eq!(bc.info().best_number, 4); for i in 0..5 { assert!(bc.hash(i).unwrap().is_some()); @@ -3367,11 +3374,11 @@ pub(crate) mod tests { } let bc = backend.blockchain(); - assert_eq!(None, bc.body(BlockId::hash(blocks[0])).unwrap()); - assert_eq!(None, bc.body(BlockId::hash(blocks[1])).unwrap()); - assert_eq!(None, bc.body(BlockId::hash(blocks[2])).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); + assert_eq!(None, bc.body(&blocks[0]).unwrap()); + assert_eq!(None, bc.body(&blocks[1]).unwrap()); + assert_eq!(None, bc.body(&blocks[2]).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(&blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(&blocks[4]).unwrap()); } #[test] @@ -3408,11 +3415,12 @@ pub(crate) mod tests { assert_eq!(bc.indexed_transaction(&x0_hash).unwrap().unwrap(), &x0[1..]); assert_eq!(bc.indexed_transaction(&x1_hash).unwrap().unwrap(), &x1[1..]); + let hashof0 = bc.info().genesis_hash; // Push one more blocks and make sure block is pruned and transaction index is cleared. let block1 = insert_block(&backend, 1, hash, None, Default::default(), vec![], None).unwrap(); backend.finalize_block(&block1, None).unwrap(); - assert_eq!(bc.body(BlockId::Number(0)).unwrap(), None); + assert_eq!(bc.body(&hashof0).unwrap(), None); assert_eq!(bc.indexed_transaction(&x0_hash).unwrap(), None); assert_eq!(bc.indexed_transaction(&x1_hash).unwrap(), None); } diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index a6b39591e7945..dbde5fc5d8c22 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -364,7 +364,7 @@ where }; let body = if get_body { - match self.client.block_body(&BlockId::Hash(hash))? { + match self.client.block_body(&hash)? { Some(mut extrinsics) => extrinsics.iter_mut().map(|extrinsic| extrinsic.encode()).collect(), None => { diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index c9b99fbc6af10..a6d73b53efdf0 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -542,7 +542,7 @@ where pub fn has_body(&self, hash: &H256) -> bool { self.backend .as_ref() - .map(|backend| backend.blockchain().body(BlockId::hash(*hash)).unwrap().is_some()) + .map(|backend| backend.blockchain().body(hash).unwrap().is_some()) .unwrap_or(false) } } diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index eb946436671e4..b5ab06a0318c5 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1053,9 +1053,9 @@ where /// Get block body by id. pub fn body( &self, - id: &BlockId, + hash: &Block::Hash, ) -> sp_blockchain::Result::Extrinsic>>> { - self.backend.blockchain().body(*id) + self.backend.blockchain().body(hash) } /// Gets the uncles of the block with `target_hash` going back `max_generation` ancestors. @@ -1939,16 +1939,22 @@ where { fn block_body( &self, - id: &BlockId, + hash: &Block::Hash, ) -> sp_blockchain::Result::Extrinsic>>> { - self.body(id) + self.body(hash) } fn block(&self, id: &BlockId) -> sp_blockchain::Result>> { - Ok(match (self.header(id)?, self.body(id)?, self.justifications(id)?) { - (Some(header), Some(extrinsics), justifications) => - Some(SignedBlock { block: Block::new(header, extrinsics), justifications }), - _ => None, + Ok(match self.header(id)? { + Some(header) => { + let hash = header.hash(); + match (self.body(&hash)?, self.justifications(id)?) { + (Some(extrinsics), justifications) => + Some(SignedBlock { block: Block::new(header, extrinsics), justifications }), + _ => None, + } + }, + None => None, }) } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 329bffae03e7b..b9aec421802c9 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -396,16 +396,19 @@ fn block_builder_does_not_include_invalid() { let block = builder.build().unwrap().block; block_on(client.import(BlockOrigin::Own, block)).unwrap(); - let hash0 = client + let hashof0 = client .expect_block_hash_from_id(&BlockId::Number(0)) .expect("block 0 was just imported. qed"); - let hash1 = client + let hashof1 = client .expect_block_hash_from_id(&BlockId::Number(1)) .expect("block 1 was just imported. qed"); assert_eq!(client.chain_info().best_number, 1); - assert_ne!(client.state_at(&hash1).unwrap().pairs(), client.state_at(&hash0).unwrap().pairs()); - assert_eq!(client.body(&BlockId::Number(1)).unwrap().unwrap().len(), 1) + assert_ne!( + client.state_at(&hashof1).unwrap().pairs(), + client.state_at(&hashof0).unwrap().pairs() + ); + assert_eq!(client.body(&hashof1).unwrap().unwrap().len(), 1) } #[test] diff --git a/client/tracing/src/block/mod.rs b/client/tracing/src/block/mod.rs index 2a034f06ce8a8..ee524f5f72902 100644 --- a/client/tracing/src/block/mod.rs +++ b/client/tracing/src/block/mod.rs @@ -225,7 +225,7 @@ where .ok_or_else(|| Error::MissingBlockComponent("Header not found".to_string()))?; let extrinsics = self .client - .block_body(&id) + .block_body(&self.block) .map_err(Error::InvalidBlockId)? .ok_or_else(|| Error::MissingBlockComponent("Extrinsics not found".to_string()))?; tracing::debug!(target: "state_tracing", "Found {} extrinsics", extrinsics.len()); diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index 2632f8fb6aab5..bc6f2f7d5e947 100644 --- a/client/transaction-pool/benches/basics.rs +++ b/client/transaction-pool/benches/basics.rs @@ -111,7 +111,7 @@ impl ChainApi for TestApi { (blake2_256(&encoded).into(), encoded.len()) } - fn block_body(&self, _id: &BlockId) -> Self::BodyFuture { + fn block_body(&self, _id: &::Hash) -> Self::BodyFuture { ready(Ok(None)) } diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index 110647b8cb3b0..f162a02ddb643 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -126,8 +126,8 @@ where Pin> + Send>>; type BodyFuture = Ready::Extrinsic>>>>; - fn block_body(&self, id: &BlockId) -> Self::BodyFuture { - ready(self.client.block_body(id).map_err(error::Error::from)) + fn block_body(&self, hash: &Block::Hash) -> Self::BodyFuture { + ready(self.client.block_body(hash).map_err(error::Error::from)) } fn validate_transaction( diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index d311e0d0c8f2f..99119ac8fa8ab 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -90,8 +90,8 @@ pub trait ChainApi: Send + Sync { /// Returns hash and encoding length of the extrinsic. fn hash_and_length(&self, uxt: &ExtrinsicFor) -> (ExtrinsicHash, usize); - /// Returns a block body given the block id. - fn block_body(&self, at: &BlockId) -> Self::BodyFuture; + /// Returns a block body given the block. + fn block_body(&self, at: &::Hash) -> Self::BodyFuture; /// Returns a block header given the block id. fn block_header( diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 410ab662e3601..9e0a2e74bf421 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -550,12 +550,12 @@ impl RevalidationStatus { /// Prune the known txs for the given block. async fn prune_known_txs_for_block>( - block_id: BlockId, + block_hash: &Block::Hash, api: &Api, pool: &graph::Pool, ) -> Vec> { let extrinsics = api - .block_body(&block_id) + .block_body(&block_hash) .await .unwrap_or_else(|e| { log::warn!("Prune known transactions: error request: {}", e); @@ -567,19 +567,21 @@ async fn prune_known_txs_for_block h, Ok(None) => { - log::debug!(target: "txpool", "Could not find header for {:?}.", block_id); + log::debug!(target: "txpool", "Could not find header for {:?}.", block_hash); return hashes }, Err(e) => { - log::debug!(target: "txpool", "Error retrieving header for {:?}: {}", block_id, e); + log::debug!(target: "txpool", "Error retrieving header for {:?}: {}", block_hash, e); return hashes }, }; - if let Err(e) = pool.prune(&block_id, &BlockId::hash(*header.parent_hash()), &extrinsics).await + if let Err(e) = pool + .prune(&BlockId::Hash(*block_hash), &BlockId::hash(*header.parent_hash()), &extrinsics) + .await { log::error!("Cannot prune known in the pool: {}", e); } @@ -636,7 +638,7 @@ where tree_route .enacted() .iter() - .map(|h| prune_known_txs_for_block(BlockId::Hash(h.hash), &*api, &*pool)), + .map(|h| prune_known_txs_for_block(&h.hash, &*api, &*pool)), ) .await .into_iter() @@ -654,7 +656,7 @@ where let hash = retracted.hash; let block_transactions = api - .block_body(&BlockId::hash(hash)) + .block_body(&hash) .await .unwrap_or_else(|e| { log::warn!("Failed to fetch block body: {}", e); diff --git a/client/transaction-pool/src/tests.rs b/client/transaction-pool/src/tests.rs index ce2c7872e32bb..8775dfb6e9e88 100644 --- a/client/transaction-pool/src/tests.rs +++ b/client/transaction-pool/src/tests.rs @@ -164,7 +164,7 @@ impl ChainApi for TestApi { (Hashing::hash(&encoded), len) } - fn block_body(&self, _id: &BlockId) -> Self::BodyFuture { + fn block_body(&self, _id: &::Hash) -> Self::BodyFuture { futures::future::ready(Ok(None)) } diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index 79c05aec8adca..610ceb0cf9323 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -89,7 +89,7 @@ pub trait Backend: HeaderBackend + HeaderMetadata { /// Get block body. Returns `None` if block is not found. - fn body(&self, id: BlockId) -> Result::Extrinsic>>>; + fn body(&self, hash: &Block::Hash) -> Result::Extrinsic>>>; /// Get block justifications. Returns `None` if no justification exists. fn justifications(&self, id: BlockId) -> Result>; /// Get last finalized block hash. diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index dc8be78aa7397..e2d6efccea424 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -315,13 +315,13 @@ impl sc_transaction_pool::ChainApi for TestApi { Self::hash_and_length_inner(ex) } - fn block_body(&self, id: &BlockId) -> Self::BodyFuture { - futures::future::ready(Ok(match id { - BlockId::Number(num) => - self.chain.read().block_by_number.get(num).map(|b| b[0].0.extrinsics().to_vec()), - BlockId::Hash(hash) => - self.chain.read().block_by_hash.get(hash).map(|b| b.extrinsics().to_vec()), - })) + fn block_body(&self, hash: &::Hash) -> Self::BodyFuture { + futures::future::ready(Ok(self + .chain + .read() + .block_by_hash + .get(hash) + .map(|b| b.extrinsics().to_vec()))) } fn block_header( From 8fb4138d73ad88a19331c30c36ba91796c5846e1 Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Wed, 2 Nov 2022 02:10:43 +0300 Subject: [PATCH 1328/1472] fix: construct_runtime multiple features (#12594) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: construct_runtime multiple features * Update frame/support/procedural/src/construct_runtime/mod.rs Co-authored-by: Bastian Köcher --- .../procedural/src/construct_runtime/mod.rs | 3 +- frame/support/test/Cargo.toml | 1 + frame/support/test/tests/pallet.rs | 102 ++++++++++++++++-- scripts/ci/gitlab/pipeline/test.yml | 1 + 4 files changed, 95 insertions(+), 12 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 73d0d54343eb9..9e22037a6782e 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -389,8 +389,9 @@ fn decl_all_pallets<'a>( (attr, names) } else { let test_cfg = features.remove("test").then_some(quote!(test)).into_iter(); + let disabled_features = all_features.difference(&features); let features = features.iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #features),* ))]); + let attr = quote!(#[cfg(all( #(#test_cfg,)* #(feature = #features,)* #(not(feature = #disabled_features)),* ))]); (attr, names) } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index d7d3bfc98f3d7..471dba8df44e2 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -51,6 +51,7 @@ try-runtime = ["frame-support/try-runtime"] # Only CI runs with this feature enabled. This feature is for testing stuff related to the FRAME macros # in conjunction with rust features. frame-feature-testing = [] +frame-feature-testing-2 = [] # Disable ui tests disable-ui-tests = [] no-metadata-docs = ["frame-support/no-metadata-docs"] diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 05c1f14601862..0fd32dad2242a 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -574,6 +574,20 @@ pub mod pallet4 { impl Pallet {} } +/// Test that the supertrait check works when we pass some parameter to the `frame_system::Config`. +#[frame_support::pallet] +pub mod pallet5 { + #[pallet::config] + pub trait Config: + frame_system::Config::RuntimeOrigin> + { + type RuntimeOrigin; + } + + #[pallet::pallet] + pub struct Pallet(_); +} + frame_support::parameter_types!( pub const MyGetParam3: u32 = 12; ); @@ -623,6 +637,11 @@ impl pallet3::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; } +#[cfg(feature = "frame-feature-testing-2")] +impl pallet5::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; +} + pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; @@ -640,6 +659,9 @@ frame_support::construct_runtime!( #[cfg(feature = "frame-feature-testing")] Example3: pallet3, Example4: pallet4 use_parts { Call }, + + #[cfg(feature = "frame-feature-testing-2")] + Example5: pallet5, } ); @@ -1175,7 +1197,13 @@ fn migrate_from_pallet_version_to_storage_version() { AllPalletsWithSystem, >(&db_weight); - let pallet_num = if cfg!(feature = "frame-feature-testing") { 5 } else { 4 }; + let mut pallet_num = 4; + if cfg!(feature = "frame-feature-testing") { + pallet_num += 1; + }; + if cfg!(feature = "frame-feature-testing-2") { + pallet_num += 1; + }; // `pallet_num` pallets, 2 writes and every write costs 5 weight. assert_eq!(Weight::from_ref_time(pallet_num * 2 * 5), weight); @@ -1512,6 +1540,16 @@ fn metadata() { constants: vec![], error: None, }, + #[cfg(feature = "frame-feature-testing-2")] + PalletMetadata { + index: 5, + name: "Example5", + storage: None, + calls: None, + event: None, + constants: vec![], + error: None, + }, ]; let empty_doc = pallets[0].event.as_ref().unwrap().ty.type_info().docs().is_empty() && @@ -1753,42 +1791,68 @@ fn assert_type_all_pallets_reversed_with_system_first_is_correct() { // Just ensure the 2 types are same. #[allow(deprecated)] fn _a(_t: AllPalletsReversedWithSystemFirst) {} - #[cfg(not(feature = "frame-feature-testing"))] + #[cfg(all(not(feature = "frame-feature-testing"), not(feature = "frame-feature-testing-2")))] fn _b(t: (System, Example4, Example2, Example)) { _a(t) } - #[cfg(feature = "frame-feature-testing")] + #[cfg(all(feature = "frame-feature-testing", not(feature = "frame-feature-testing-2")))] fn _b(t: (System, Example4, Example3, Example2, Example)) { _a(t) } + + #[cfg(all(not(feature = "frame-feature-testing"), feature = "frame-feature-testing-2"))] + fn _b(t: (System, Example5, Example4, Example2, Example)) { + _a(t) + } + + #[cfg(all(feature = "frame-feature-testing", feature = "frame-feature-testing-2"))] + fn _b(t: (System, Example5, Example4, Example3, Example2, Example)) { + _a(t) + } } #[test] fn assert_type_all_pallets_with_system_is_correct() { // Just ensure the 2 types are same. fn _a(_t: AllPalletsWithSystem) {} - #[cfg(not(feature = "frame-feature-testing"))] + #[cfg(all(not(feature = "frame-feature-testing"), not(feature = "frame-feature-testing-2")))] fn _b(t: (System, Example, Example2, Example4)) { _a(t) } - #[cfg(feature = "frame-feature-testing")] + #[cfg(all(feature = "frame-feature-testing", not(feature = "frame-feature-testing-2")))] fn _b(t: (System, Example, Example2, Example3, Example4)) { _a(t) } + #[cfg(all(not(feature = "frame-feature-testing"), feature = "frame-feature-testing-2"))] + fn _b(t: (System, Example, Example2, Example4, Example5)) { + _a(t) + } + #[cfg(all(feature = "frame-feature-testing", feature = "frame-feature-testing-2"))] + fn _b(t: (System, Example, Example2, Example3, Example4, Example5)) { + _a(t) + } } #[test] fn assert_type_all_pallets_without_system_is_correct() { // Just ensure the 2 types are same. fn _a(_t: AllPalletsWithoutSystem) {} - #[cfg(not(feature = "frame-feature-testing"))] + #[cfg(all(not(feature = "frame-feature-testing"), not(feature = "frame-feature-testing-2")))] fn _b(t: (Example, Example2, Example4)) { _a(t) } - #[cfg(feature = "frame-feature-testing")] + #[cfg(all(feature = "frame-feature-testing", not(feature = "frame-feature-testing-2")))] fn _b(t: (Example, Example2, Example3, Example4)) { _a(t) } + #[cfg(all(not(feature = "frame-feature-testing"), feature = "frame-feature-testing-2"))] + fn _b(t: (Example, Example2, Example4, Example5)) { + _a(t) + } + #[cfg(all(feature = "frame-feature-testing", feature = "frame-feature-testing-2"))] + fn _b(t: (Example, Example2, Example3, Example4, Example5)) { + _a(t) + } } #[test] @@ -1796,14 +1860,22 @@ fn assert_type_all_pallets_with_system_reversed_is_correct() { // Just ensure the 2 types are same. #[allow(deprecated)] fn _a(_t: AllPalletsWithSystemReversed) {} - #[cfg(not(feature = "frame-feature-testing"))] + #[cfg(all(not(feature = "frame-feature-testing"), not(feature = "frame-feature-testing-2")))] fn _b(t: (Example4, Example2, Example, System)) { _a(t) } - #[cfg(feature = "frame-feature-testing")] + #[cfg(all(feature = "frame-feature-testing", not(feature = "frame-feature-testing-2")))] fn _b(t: (Example4, Example3, Example2, Example, System)) { _a(t) } + #[cfg(all(not(feature = "frame-feature-testing"), feature = "frame-feature-testing-2"))] + fn _b(t: (Example5, Example4, Example2, Example, System)) { + _a(t) + } + #[cfg(all(feature = "frame-feature-testing", feature = "frame-feature-testing-2"))] + fn _b(t: (Example5, Example4, Example3, Example2, Example, System)) { + _a(t) + } } #[test] @@ -1811,14 +1883,22 @@ fn assert_type_all_pallets_without_system_reversed_is_correct() { // Just ensure the 2 types are same. #[allow(deprecated)] fn _a(_t: AllPalletsWithoutSystemReversed) {} - #[cfg(not(feature = "frame-feature-testing"))] + #[cfg(all(not(feature = "frame-feature-testing"), not(feature = "frame-feature-testing-2")))] fn _b(t: (Example4, Example2, Example)) { _a(t) } - #[cfg(feature = "frame-feature-testing")] + #[cfg(all(feature = "frame-feature-testing", not(feature = "frame-feature-testing-2")))] fn _b(t: (Example4, Example3, Example2, Example)) { _a(t) } + #[cfg(all(not(feature = "frame-feature-testing"), feature = "frame-feature-testing-2"))] + fn _b(t: (Example5, Example4, Example2, Example)) { + _a(t) + } + #[cfg(all(feature = "frame-feature-testing", feature = "frame-feature-testing-2"))] + fn _b(t: (Example5, Example4, Example3, Example2, Example)) { + _a(t) + } } #[test] diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 8baebb39be6dc..4f523738b151c 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -254,6 +254,7 @@ test-frame-support: script: - rusty-cachier snapshot create - time cargo test --locked -p frame-support-test --features=frame-feature-testing,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec + - time cargo test --locked -p frame-support-test --features=frame-feature-testing,frame-feature-testing-2,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout - rusty-cachier cache upload From 5683513310f44eb2dc8026cd79b189b196a5982a Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 2 Nov 2022 22:56:48 +1300 Subject: [PATCH 1329/1472] Fix fungible unbalanced trait (#12569) * Fix fungible unbalanced trait * Add simple decrease_balance test Signed-off-by: Oliver Tale-Yazdi * Fix decrease_balance_at_most * Fix decrease_balance_at_most in fungibles * Rename free_balanceto balance_on_free * Use reducible_balance instead of balance_on_free Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/balances/src/lib.rs | 12 +- frame/balances/src/tests.rs | 160 +++++++++++++++++- .../src/traits/tokens/fungible/balanced.rs | 7 +- .../src/traits/tokens/fungibles/balanced.rs | 7 +- 4 files changed, 175 insertions(+), 11 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 4014efdd26e4e..67976cbaf06ac 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -1149,15 +1149,19 @@ impl, I: 'static> fungible::Transfer for Pallet impl, I: 'static> fungible::Unbalanced for Pallet { fn set_balance(who: &T::AccountId, amount: Self::Balance) -> DispatchResult { - Self::mutate_account(who, |account| { - account.free = amount; + Self::mutate_account(who, |account| -> DispatchResult { + // fungibles::Unbalanced::decrease_balance didn't check account.reserved + // free = new_balance - reserved + account.free = + amount.checked_sub(&account.reserved).ok_or(ArithmeticError::Underflow)?; Self::deposit_event(Event::BalanceSet { who: who.clone(), free: account.free, reserved: account.reserved, }); - })?; - Ok(()) + + Ok(()) + })? } fn set_total_issuance(amount: Self::Balance) { diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index faf53e16cb028..83944caf9f7ff 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -24,7 +24,7 @@ macro_rules! decl_tests { ($test:ty, $ext_builder:ty, $existential_deposit:expr) => { use crate::*; - use sp_runtime::{ArithmeticError, FixedPointNumber, traits::{SignedExtension, BadOrigin}}; + use sp_runtime::{ArithmeticError, TokenError, FixedPointNumber, traits::{SignedExtension, BadOrigin}}; use frame_support::{ assert_noop, assert_storage_noop, assert_ok, assert_err, traits::{ @@ -1298,5 +1298,163 @@ macro_rules! decl_tests { assert_eq!(Balances::reserved_balance(&1337), 42); }); } + + #[test] + fn fungible_unbalanced_trait_set_balance_works() { + <$ext_builder>::default().build().execute_with(|| { + assert_eq!(>::balance(&1337), 0); + assert_ok!(>::set_balance(&1337, 100)); + assert_eq!(>::balance(&1337), 100); + + assert_ok!(Balances::reserve(&1337, 60)); + assert_eq!(Balances::free_balance(1337) , 40); + assert_eq!(Balances::reserved_balance(1337), 60); + + assert_noop!(>::set_balance(&1337, 0), ArithmeticError::Underflow); + + assert_ok!(>::set_balance(&1337, 60)); + assert_eq!(Balances::free_balance(1337) , 0); + assert_eq!(Balances::reserved_balance(1337), 60); + }); + } + + #[test] + fn fungible_unbalanced_trait_set_total_issuance_works() { + <$ext_builder>::default().build().execute_with(|| { + assert_eq!(>::total_issuance(), 0); + >::set_total_issuance(100); + assert_eq!(>::total_issuance(), 100); + }); + } + + #[test] + fn fungible_unbalanced_trait_decrease_balance_simple_works() { + <$ext_builder>::default().build().execute_with(|| { + // An Account that starts at 100 + assert_ok!(>::set_balance(&1337, 100)); + // and reserves 50 + assert_ok!(Balances::reserve(&1337, 50)); + // and is decreased by 20 + assert_ok!(>::decrease_balance(&1337, 20)); + // should end up at 80. + assert_eq!(>::balance(&1337), 80); + }); + } + + #[test] + fn fungible_unbalanced_trait_decrease_balance_works() { + <$ext_builder>::default().build().execute_with(|| { + assert_ok!(>::set_balance(&1337, 100)); + assert_eq!(>::balance(&1337), 100); + + assert_noop!( + >::decrease_balance(&1337, 101), + TokenError::NoFunds + ); + assert_eq!( + >::decrease_balance(&1337, 100), + Ok(100) + ); + assert_eq!(>::balance(&1337), 0); + + // free: 40, reserved: 60 + assert_ok!(>::set_balance(&1337, 100)); + assert_ok!(Balances::reserve(&1337, 60)); + assert_eq!(Balances::free_balance(1337) , 40); + assert_eq!(Balances::reserved_balance(1337), 60); + assert_noop!( + >::decrease_balance(&1337, 41), + TokenError::NoFunds + ); + assert_eq!( + >::decrease_balance(&1337, 40), + Ok(40) + ); + assert_eq!(>::balance(&1337), 60); + assert_eq!(Balances::free_balance(1337), 0); + assert_eq!(Balances::reserved_balance(1337), 60); + }); + } + + #[test] + fn fungible_unbalanced_trait_decrease_balance_at_most_works() { + <$ext_builder>::default().build().execute_with(|| { + assert_ok!(>::set_balance(&1337, 100)); + assert_eq!(>::balance(&1337), 100); + + assert_eq!( + >::decrease_balance_at_most(&1337, 101), + 100 + ); + assert_eq!(>::balance(&1337), 0); + + assert_ok!(>::set_balance(&1337, 100)); + assert_eq!( + >::decrease_balance_at_most(&1337, 100), + 100 + ); + assert_eq!(>::balance(&1337), 0); + + // free: 40, reserved: 60 + assert_ok!(>::set_balance(&1337, 100)); + assert_ok!(Balances::reserve(&1337, 60)); + assert_eq!(Balances::free_balance(1337) , 40); + assert_eq!(Balances::reserved_balance(1337), 60); + assert_eq!( + >::decrease_balance_at_most(&1337, 0), + 0 + ); + assert_eq!(Balances::free_balance(1337) , 40); + assert_eq!(Balances::reserved_balance(1337), 60); + assert_eq!( + >::decrease_balance_at_most(&1337, 10), + 10 + ); + assert_eq!(Balances::free_balance(1337), 30); + assert_eq!( + >::decrease_balance_at_most(&1337, 200), + 30 + ); + assert_eq!(>::balance(&1337), 60); + assert_eq!(Balances::free_balance(1337), 0); + assert_eq!(Balances::reserved_balance(1337), 60); + }); + } + + #[test] + fn fungible_unbalanced_trait_increase_balance_works() { + <$ext_builder>::default().build().execute_with(|| { + assert_noop!( + >::increase_balance(&1337, 0), + TokenError::BelowMinimum + ); + assert_eq!( + >::increase_balance(&1337, 1), + Ok(1) + ); + assert_noop!( + >::increase_balance(&1337, u64::MAX), + ArithmeticError::Overflow + ); + }); + } + + #[test] + fn fungible_unbalanced_trait_increase_balance_at_most_works() { + <$ext_builder>::default().build().execute_with(|| { + assert_eq!( + >::increase_balance_at_most(&1337, 0), + 0 + ); + assert_eq!( + >::increase_balance_at_most(&1337, 1), + 1 + ); + assert_eq!( + >::increase_balance_at_most(&1337, u64::MAX), + u64::MAX - 1 + ); + }); + } } } diff --git a/frame/support/src/traits/tokens/fungible/balanced.rs b/frame/support/src/traits/tokens/fungible/balanced.rs index ed9c3a1afa480..0e75ccc22d050 100644 --- a/frame/support/src/traits/tokens/fungible/balanced.rs +++ b/frame/support/src/traits/tokens/fungible/balanced.rs @@ -164,7 +164,7 @@ pub trait Unbalanced: Inspect { amount: Self::Balance, ) -> Result { let old_balance = Self::balance(who); - let (mut new_balance, mut amount) = if old_balance < amount { + let (mut new_balance, mut amount) = if Self::reducible_balance(who, false) < amount { return Err(TokenError::NoFunds.into()) } else { (old_balance - amount, amount) @@ -186,8 +186,9 @@ pub trait Unbalanced: Inspect { /// Return the imbalance by which the account was reduced. fn decrease_balance_at_most(who: &AccountId, amount: Self::Balance) -> Self::Balance { let old_balance = Self::balance(who); - let (mut new_balance, mut amount) = if old_balance < amount { - (Zero::zero(), old_balance) + let old_free_balance = Self::reducible_balance(who, false); + let (mut new_balance, mut amount) = if old_free_balance < amount { + (old_balance.saturating_sub(old_free_balance), old_free_balance) } else { (old_balance - amount, amount) }; diff --git a/frame/support/src/traits/tokens/fungibles/balanced.rs b/frame/support/src/traits/tokens/fungibles/balanced.rs index a870168e4db91..9e50ff834a874 100644 --- a/frame/support/src/traits/tokens/fungibles/balanced.rs +++ b/frame/support/src/traits/tokens/fungibles/balanced.rs @@ -185,7 +185,7 @@ pub trait Unbalanced: Inspect { amount: Self::Balance, ) -> Result { let old_balance = Self::balance(asset, who); - let (mut new_balance, mut amount) = if old_balance < amount { + let (mut new_balance, mut amount) = if Self::reducible_balance(asset, who, false) < amount { return Err(TokenError::NoFunds.into()) } else { (old_balance - amount, amount) @@ -211,8 +211,9 @@ pub trait Unbalanced: Inspect { amount: Self::Balance, ) -> Self::Balance { let old_balance = Self::balance(asset, who); - let (mut new_balance, mut amount) = if old_balance < amount { - (Zero::zero(), old_balance) + let old_free_balance = Self::reducible_balance(asset, who, false); + let (mut new_balance, mut amount) = if old_free_balance < amount { + (old_balance.saturating_sub(old_free_balance), old_free_balance) } else { (old_balance - amount, amount) }; From 2216f8cdaaa0ee92938675523e14c4d1a856dad0 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 2 Nov 2022 14:39:28 +0100 Subject: [PATCH 1330/1472] [ci] allow fail skip-if-draft job (#12604) --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e6f26cbfd5cf7..9053e39eb59bf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -210,6 +210,7 @@ skip-if-draft: - echo "Ref is ${CI_COMMIT_REF_NAME}" - echo "pipeline source is ${CI_PIPELINE_SOURCE}" - ./scripts/ci/gitlab/skip_if_draft.sh + allow_failure: true include: # check jobs From 1f17288074b389091c4242c54be8b8a7fdc4b39b Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 2 Nov 2022 23:15:33 +0100 Subject: [PATCH 1331/1472] BlockId removal: refactor: Backend::justifications (#12602) * BlockId removal: refactor: Backend::justifications It changes the arguments of `Backend::justifications` method from: `BlockId` to: `&Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) * trigger CI job * trigger CI job * bug fix * match -> if Co-authored-by: Adrian Catangiu Co-authored-by: Adrian Catangiu --- client/api/src/client.rs | 2 +- client/api/src/in_mem.rs | 13 ++---- .../incoming_requests_handler.rs | 21 +++++---- client/beefy/src/tests.rs | 10 +++-- client/beefy/src/worker.rs | 4 +- client/db/src/lib.rs | 18 ++++---- client/finality-grandpa/src/finality_proof.rs | 6 ++- client/finality-grandpa/src/tests.rs | 40 +++++------------ client/finality-grandpa/src/warp_proof.rs | 2 +- .../network/sync/src/block_request_handler.rs | 7 +-- client/network/test/src/block_import.rs | 2 +- client/network/test/src/lib.rs | 7 ++- client/network/test/src/sync.rs | 45 ++++++++++--------- client/service/src/client/client.rs | 6 +-- client/service/test/src/client/mod.rs | 6 +-- primitives/blockchain/src/backend.rs | 2 +- 16 files changed, 89 insertions(+), 102 deletions(-) diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 670c1711db948..d0053afeba97b 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -131,7 +131,7 @@ pub trait BlockBackend { -> sp_blockchain::Result; /// Get block justifications for the block with the given id. - fn justifications(&self, id: &BlockId) -> sp_blockchain::Result>; + fn justifications(&self, hash: &Block::Hash) -> sp_blockchain::Result>; /// Get block hash by number. fn block_hash(&self, number: NumberFor) -> sp_blockchain::Result>; diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 7b0e6f7b72575..6f33695fe4bf4 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -415,10 +415,8 @@ impl blockchain::Backend for Blockchain { .and_then(|b| b.extrinsics().map(|x| x.to_vec()))) } - fn justifications(&self, id: BlockId) -> sp_blockchain::Result> { - Ok(self.id(id).and_then(|hash| { - self.storage.read().blocks.get(&hash).and_then(|b| b.justifications().cloned()) - })) + fn justifications(&self, hash: &Block::Hash) -> sp_blockchain::Result> { + Ok(self.storage.read().blocks.get(&hash).and_then(|b| b.justifications().cloned())) } fn last_finalized(&self) -> sp_blockchain::Result { @@ -816,7 +814,7 @@ pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> { #[cfg(test)] mod tests { use crate::{in_mem::Blockchain, NewBlockState}; - use sp_api::{BlockId, HeaderT}; + use sp_api::HeaderT; use sp_blockchain::Backend; use sp_runtime::{ConsensusEngineId, Justifications}; use substrate_test_runtime::{Block, Header, H256}; @@ -870,10 +868,7 @@ mod tests { just.append((ID2, vec![4])); just }; - assert_eq!( - blockchain.justifications(BlockId::Hash(last_finalized)).unwrap(), - Some(justifications) - ); + assert_eq!(blockchain.justifications(&last_finalized).unwrap(), Some(justifications)); } #[test] diff --git a/client/beefy/src/communication/request_response/incoming_requests_handler.rs b/client/beefy/src/communication/request_response/incoming_requests_handler.rs index c0910a60fba3b..3affbbe870ad7 100644 --- a/client/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/client/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -26,7 +26,7 @@ use log::{debug, trace}; use sc_client_api::BlockBackend; use sc_network::{config as netconfig, config::RequestResponseConfig, PeerId, ReputationChange}; use sc_network_common::protocol::ProtocolName; -use sp_runtime::{generic::BlockId, traits::Block}; +use sp_runtime::traits::Block; use std::{marker::PhantomData, sync::Arc}; use crate::communication::request_response::{ @@ -149,13 +149,18 @@ where fn handle_request(&self, request: IncomingRequest) -> Result<(), Error> { // TODO (issue #12293): validate `request` and change peer reputation for invalid requests. - let maybe_encoded_proof = self - .client - .justifications(&BlockId::Number(request.payload.begin)) - .map_err(Error::Client)? - .and_then(|justifs| justifs.get(BEEFY_ENGINE_ID).cloned()) - // No BEEFY justification present. - .ok_or(()); + let maybe_encoded_proof = if let Some(hash) = + self.client.block_hash(request.payload.begin).map_err(Error::Client)? + { + self.client + .justifications(&hash) + .map_err(Error::Client)? + .and_then(|justifs| justifs.get(BEEFY_ENGINE_ID).cloned()) + // No BEEFY justification present. + .ok_or(()) + } else { + Err(()) + }; request .pending_response diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index b0a1433fafec6..62d8a45f4471c 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -741,9 +741,9 @@ fn beefy_importing_blocks() { let full_client = client.as_client(); let parent_id = BlockId::Number(0); - let block_id = BlockId::Number(1); let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); let block = builder.build().unwrap().block; + let hashof1 = block.header.hash(); // Import without justifications. let mut justif_recv = justif_stream.subscribe(); @@ -760,7 +760,7 @@ fn beefy_importing_blocks() { // none in backend, assert_eq!( full_client - .justifications(&block_id) + .justifications(&hashof1) .unwrap() .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), None @@ -784,6 +784,7 @@ fn beefy_importing_blocks() { let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); let block = builder.build().unwrap().block; + let hashof2 = block.header.hash(); let mut justif_recv = justif_stream.subscribe(); assert_eq!( block_on(block_import.import_block(params(block, justif), HashMap::new())).unwrap(), @@ -798,7 +799,7 @@ fn beefy_importing_blocks() { // still not in backend (worker is responsible for appending to backend), assert_eq!( full_client - .justifications(&block_id) + .justifications(&hashof2) .unwrap() .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), None @@ -826,6 +827,7 @@ fn beefy_importing_blocks() { let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); let block = builder.build().unwrap().block; + let hashof3 = block.header.hash(); let mut justif_recv = justif_stream.subscribe(); assert_eq!( block_on(block_import.import_block(params(block, justif), HashMap::new())).unwrap(), @@ -841,7 +843,7 @@ fn beefy_importing_blocks() { // none in backend, assert_eq!( full_client - .justifications(&BlockId::Number(block_num)) + .justifications(&hashof3) .unwrap() .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), None diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 305b92d696975..ea9e0d0c33999 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -709,7 +709,7 @@ where // a BEEFY justification, or at this session's boundary; voter will resume from there. loop { if let Some(true) = blockchain - .justifications(BlockId::hash(header.hash())) + .justifications(&header.hash()) .ok() .flatten() .map(|justifs| justifs.get(BEEFY_ENGINE_ID).is_some()) @@ -1401,7 +1401,7 @@ pub(crate) mod tests { })); // check BEEFY justifications are also appended to backend - let justifs = backend.blockchain().justifications(BlockId::number(2)).unwrap().unwrap(); + let justifs = backend.blockchain().justifications(&hashof2).unwrap().unwrap(); assert!(justifs.get(BEEFY_ENGINE_ID).is_some()) } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 9d9a8d268dd81..af45e7c961fd3 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -642,8 +642,13 @@ impl sc_client_api::blockchain::Backend for BlockchainDb) -> ClientResult> { - match read_db(&*self.db, columns::KEY_LOOKUP, columns::JUSTIFICATIONS, id)? { + fn justifications(&self, hash: &Block::Hash) -> ClientResult> { + match read_db( + &*self.db, + columns::KEY_LOOKUP, + columns::JUSTIFICATIONS, + BlockId::::Hash(*hash), + )? { Some(justifications) => match Decode::decode(&mut &justifications[..]) { Ok(justifications) => Ok(Some(justifications)), Err(err) => @@ -2039,7 +2044,7 @@ impl sc_client_api::backend::Backend for Backend { } let justifications = if let Some(mut stored_justifications) = - self.blockchain.justifications(BlockId::Hash(*hash))? + self.blockchain.justifications(hash)? { if !stored_justifications.append(justification) { return Err(ClientError::BadJustification("Duplicate consensus engine ID".into())) @@ -3017,7 +3022,7 @@ pub(crate) mod tests { backend.finalize_block(&block1, justification.clone()).unwrap(); assert_eq!( - backend.blockchain().justifications(BlockId::Number(1)).unwrap(), + backend.blockchain().justifications(&block1).unwrap(), justification.map(Justifications::from), ); } @@ -3048,10 +3053,7 @@ pub(crate) mod tests { just.append(just1); just }; - assert_eq!( - backend.blockchain().justifications(BlockId::Number(1)).unwrap(), - Some(justifications), - ); + assert_eq!(backend.blockchain().justifications(&block1).unwrap(), Some(justifications),); } #[test] diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index a7042e26b1a71..3070581350662 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -183,10 +183,12 @@ where } }, AuthoritySetChangeId::Set(_, last_block_for_set) => { - let last_block_for_set_id = BlockId::Number(last_block_for_set); + let last_block_for_set_id = backend + .blockchain() + .expect_block_hash_from_id(&BlockId::Number(last_block_for_set))?; let justification = if let Some(grandpa_justification) = backend .blockchain() - .justifications(last_block_for_set_id)? + .justifications(&last_block_for_set_id)? .and_then(|justifications| justifications.into_justification(GRANDPA_ENGINE_ID)) { grandpa_justification diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 39379e69c9157..d2db1feea0fef 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -363,9 +363,11 @@ fn finalize_3_voters_no_observers() { runtime.spawn(initialize_grandpa(&mut net, peers)); net.peer(0).push_blocks(20, false); net.block_until_sync(); + let hashof20 = net.peer(0).client().info().best_hash; for i in 0..3 { assert_eq!(net.peer(i).client().info().best_number, 20, "Peer #{} failed to sync", i); + assert_eq!(net.peer(i).client().info().best_hash, hashof20, "Peer #{} failed to sync", i); } let net = Arc::new(Mutex::new(net)); @@ -373,12 +375,7 @@ fn finalize_3_voters_no_observers() { // normally there's no justification for finalized blocks assert!( - net.lock() - .peer(0) - .client() - .justifications(&BlockId::Number(20)) - .unwrap() - .is_none(), + net.lock().peer(0).client().justifications(&hashof20).unwrap().is_none(), "Extra justification for block#1", ); } @@ -616,19 +613,15 @@ fn justification_is_generated_periodically() { net.peer(0).push_blocks(32, false); net.block_until_sync(); + let hashof32 = net.peer(0).client().info().best_hash; + let net = Arc::new(Mutex::new(net)); run_to_completion(&mut runtime, 32, net.clone(), peers); // when block#32 (justification_period) is finalized, justification // is required => generated for i in 0..3 { - assert!(net - .lock() - .peer(i) - .client() - .justifications(&BlockId::Number(32)) - .unwrap() - .is_some()); + assert!(net.lock().peer(i).client().justifications(&hashof32).unwrap().is_some()); } } @@ -648,7 +641,7 @@ fn sync_justifications_on_change_blocks() { net.peer(0).push_blocks(20, false); // at block 21 we do add a transition which is instant - net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| { + let hashof21 = net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| { let mut block = builder.build().unwrap().block; add_scheduled_change( &mut block, @@ -672,25 +665,12 @@ fn sync_justifications_on_change_blocks() { // the first 3 peers are grandpa voters and therefore have already finalized // block 21 and stored a justification for i in 0..3 { - assert!(net - .lock() - .peer(i) - .client() - .justifications(&BlockId::Number(21)) - .unwrap() - .is_some()); + assert!(net.lock().peer(i).client().justifications(&hashof21).unwrap().is_some()); } // the last peer should get the justification by syncing from other peers futures::executor::block_on(futures::future::poll_fn(move |cx| { - if net - .lock() - .peer(3) - .client() - .justifications(&BlockId::Number(21)) - .unwrap() - .is_none() - { + if net.lock().peer(3).client().justifications(&hashof21).unwrap().is_none() { net.lock().poll(cx); Poll::Pending } else { @@ -1686,7 +1666,7 @@ fn imports_justification_for_regular_blocks_on_import() { ); // the justification should be imported and available from the client - assert!(client.justifications(&BlockId::Hash(block_hash)).unwrap().is_some()); + assert!(client.justifications(&block_hash).unwrap().is_some()); } #[test] diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index 10d02f790a0dc..786dfacf8b0b9 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -130,7 +130,7 @@ impl WarpSyncProof { } let justification = blockchain - .justifications(BlockId::Number(*last_block))? + .justifications(&header.hash())? .and_then(|just| just.into_justification(GRANDPA_ENGINE_ID)) .expect( "header is last in set and contains standard change signal; \ diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index dbde5fc5d8c22..08b8cffa38714 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -331,11 +331,8 @@ where let number = *header.number(); let hash = header.hash(); let parent_hash = *header.parent_hash(); - let justifications = if get_justification { - self.client.justifications(&BlockId::Hash(hash))? - } else { - None - }; + let justifications = + if get_justification { self.client.justifications(&hash)? } else { None }; let (justifications, justification, is_empty_justification) = if support_multiple_justifications { diff --git a/client/network/test/src/block_import.rs b/client/network/test/src/block_import.rs index a2bd5276c31d6..a1d42f1e60440 100644 --- a/client/network/test/src/block_import.rs +++ b/client/network/test/src/block_import.rs @@ -40,7 +40,7 @@ fn prepare_good_block() -> (TestClient, Hash, u64, PeerId, IncomingBlock) let (hash, number) = (client.block_hash(1).unwrap().unwrap(), 1); let header = client.header(&BlockId::Number(1)).unwrap(); - let justifications = client.justifications(&BlockId::Number(1)).unwrap(); + let justifications = client.justifications(&hash).unwrap(); let peer_id = PeerId::random(); ( client, diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index a6d73b53efdf0..f348d5cf94c43 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -176,8 +176,11 @@ impl PeersClient { self.backend.have_state_at(&header.hash(), *header.number()) } - pub fn justifications(&self, block: &BlockId) -> ClientResult> { - self.client.justifications(block) + pub fn justifications( + &self, + hash: &::Hash, + ) -> ClientResult> { + self.client.justifications(hash) } pub fn finality_notification_stream(&self) -> FinalityNotifications { diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index 399062a88d269..9ae3014e497ce 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -246,15 +246,16 @@ fn sync_justifications() { net.peer(0).push_blocks(20, false); net.block_until_sync(); - // there's currently no justification for block #10 - assert_eq!(net.peer(0).client().justifications(&BlockId::Number(10)).unwrap(), None); - assert_eq!(net.peer(1).client().justifications(&BlockId::Number(10)).unwrap(), None); - - // we finalize block #10, #15 and #20 for peer 0 with a justification let backend = net.peer(0).client().as_backend(); let hashof10 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(10)).unwrap(); let hashof15 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(15)).unwrap(); let hashof20 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(20)).unwrap(); + + // there's currently no justification for block #10 + assert_eq!(net.peer(0).client().justifications(&hashof10).unwrap(), None); + assert_eq!(net.peer(1).client().justifications(&hashof10).unwrap(), None); + + // we finalize block #10, #15 and #20 for peer 0 with a justification let just = (*b"FRNK", Vec::new()); net.peer(0) .client() @@ -269,25 +270,25 @@ fn sync_justifications() { .finalize_block(&hashof20, Some(just.clone()), true) .unwrap(); - let h1 = net.peer(1).client().header(&BlockId::Number(10)).unwrap().unwrap(); - let h2 = net.peer(1).client().header(&BlockId::Number(15)).unwrap().unwrap(); - let h3 = net.peer(1).client().header(&BlockId::Number(20)).unwrap().unwrap(); + let hashof10 = net.peer(1).client().header(&BlockId::Number(10)).unwrap().unwrap().hash(); + let hashof15 = net.peer(1).client().header(&BlockId::Number(15)).unwrap().unwrap().hash(); + let hashof20 = net.peer(1).client().header(&BlockId::Number(20)).unwrap().unwrap().hash(); // peer 1 should get the justifications from the network - net.peer(1).request_justification(&h1.hash().into(), 10); - net.peer(1).request_justification(&h2.hash().into(), 15); - net.peer(1).request_justification(&h3.hash().into(), 20); + net.peer(1).request_justification(&hashof10, 10); + net.peer(1).request_justification(&hashof15, 15); + net.peer(1).request_justification(&hashof20, 20); block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - for height in (10..21).step_by(5) { - if net.peer(0).client().justifications(&BlockId::Number(height)).unwrap() != + for hash in [hashof10, hashof15, hashof20] { + if net.peer(0).client().justifications(&hash).unwrap() != Some(Justifications::from((*b"FRNK", Vec::new()))) { return Poll::Pending } - if net.peer(1).client().justifications(&BlockId::Number(height)).unwrap() != + if net.peer(1).client().justifications(&hash).unwrap() != Some(Justifications::from((*b"FRNK", Vec::new()))) { return Poll::Pending @@ -321,9 +322,9 @@ fn sync_justifications_across_forks() { block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(0).client().justifications(&BlockId::Number(10)).unwrap() == + if net.peer(0).client().justifications(&f1_best).unwrap() == Some(Justifications::from((*b"FRNK", Vec::new()))) && - net.peer(1).client().justifications(&BlockId::Number(10)).unwrap() == + net.peer(1).client().justifications(&f1_best).unwrap() == Some(Justifications::from((*b"FRNK", Vec::new()))) { Poll::Ready(()) @@ -952,14 +953,14 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { net.peer(0).push_blocks(10, false); net.block_until_sync(); - // there's currently no justification for block #10 - assert_eq!(net.peer(0).client().justifications(&BlockId::Number(10)).unwrap(), None); - assert_eq!(net.peer(1).client().justifications(&BlockId::Number(10)).unwrap(), None); + let hashof10 = net.peer(1).client().header(&BlockId::Number(10)).unwrap().unwrap().hash(); - let h1 = net.peer(1).client().header(&BlockId::Number(10)).unwrap().unwrap(); + // there's currently no justification for block #10 + assert_eq!(net.peer(0).client().justifications(&hashof10).unwrap(), None); + assert_eq!(net.peer(1).client().justifications(&hashof10).unwrap(), None); // Let's assume block 10 was finalized, but we still need the justification from the network. - net.peer(1).request_justification(&h1.hash().into(), 10); + net.peer(1).request_justification(&hashof10, 10); // Let's build some more blocks and wait always for the network to have synced them for _ in 0..5 { @@ -987,7 +988,7 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(1).client().justifications(&BlockId::Number(10)).unwrap() != + if net.peer(1).client().justifications(&hashof10).unwrap() != Some(Justifications::from((*b"FRNK", Vec::new()))) { return Poll::Pending diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index b5ab06a0318c5..6d463f337aabc 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1948,7 +1948,7 @@ where Ok(match self.header(id)? { Some(header) => { let hash = header.hash(); - match (self.body(&hash)?, self.justifications(id)?) { + match (self.body(&hash)?, self.justifications(&hash)?) { (Some(extrinsics), justifications) => Some(SignedBlock { block: Block::new(header, extrinsics), justifications }), _ => None, @@ -1962,8 +1962,8 @@ where Client::block_status(self, id) } - fn justifications(&self, id: &BlockId) -> sp_blockchain::Result> { - self.backend.blockchain().justifications(*id) + fn justifications(&self, hash: &Block::Hash) -> sp_blockchain::Result> { + self.backend.blockchain().justifications(hash) } fn block_hash(&self, number: NumberFor) -> sp_blockchain::Result> { diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index b9aec421802c9..c60ff4dd09d7b 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -884,11 +884,11 @@ fn import_with_justification() { assert_eq!(client.chain_info().finalized_hash, a3.hash()); - assert_eq!(client.justifications(&BlockId::Hash(a3.hash())).unwrap(), Some(justification)); + assert_eq!(client.justifications(&a3.hash()).unwrap(), Some(justification)); - assert_eq!(client.justifications(&BlockId::Hash(a1.hash())).unwrap(), None); + assert_eq!(client.justifications(&a1.hash()).unwrap(), None); - assert_eq!(client.justifications(&BlockId::Hash(a2.hash())).unwrap(), None); + assert_eq!(client.justifications(&a2.hash()).unwrap(), None); finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[]); finality_notification_check(&mut finality_notifications, &[a3.hash()], &[]); diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index 610ceb0cf9323..e5764354e90f3 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -91,7 +91,7 @@ pub trait Backend: /// Get block body. Returns `None` if block is not found. fn body(&self, hash: &Block::Hash) -> Result::Extrinsic>>>; /// Get block justifications. Returns `None` if no justification exists. - fn justifications(&self, id: BlockId) -> Result>; + fn justifications(&self, hash: &Block::Hash) -> Result>; /// Get last finalized block hash. fn last_finalized(&self) -> Result; From c7147ce4d3f8b43fe8c3875f0216739c6901c1e4 Mon Sep 17 00:00:00 2001 From: benluelo <57334811+benluelo@users.noreply.github.com> Date: Wed, 2 Nov 2022 19:31:04 -0400 Subject: [PATCH 1332/1472] use associated iterator types for InspectEnumerable (#12389) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * use associated iterator types for InspectEnumerable * Update frame/uniques/src/impl_nonfungibles.rs Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher --- .../support/src/traits/tokens/nonfungible.rs | 18 +++++++++++---- .../support/src/traits/tokens/nonfungibles.rs | 17 ++++++++++---- frame/uniques/src/impl_nonfungibles.rs | 23 ++++++++++++------- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/frame/support/src/traits/tokens/nonfungible.rs b/frame/support/src/traits/tokens/nonfungible.rs index fe0d2e729930e..46ca573131127 100644 --- a/frame/support/src/traits/tokens/nonfungible.rs +++ b/frame/support/src/traits/tokens/nonfungible.rs @@ -65,11 +65,16 @@ pub trait Inspect { /// Interface for enumerating items in existence or owned by a given account over a collection /// of NFTs. pub trait InspectEnumerable: Inspect { + /// The iterator type for [`Self::items`]. + type ItemsIterator: Iterator; + /// The iterator type for [`Self::owned`]. + type OwnedIterator: Iterator; + /// Returns an iterator of the items within a `collection` in existence. - fn items() -> Box>; + fn items() -> Self::ItemsIterator; /// Returns an iterator of the items of all collections owned by `who`. - fn owned(who: &AccountId) -> Box>; + fn owned(who: &AccountId) -> Self::OwnedIterator; } /// Trait for providing an interface for NFT-like items which may be minted, burned and/or have @@ -149,10 +154,15 @@ impl< AccountId, > InspectEnumerable for ItemOf { - fn items() -> Box> { + type ItemsIterator = >::ItemsIterator; + type OwnedIterator = + >::OwnedInCollectionIterator; + + fn items() -> Self::ItemsIterator { >::items(&A::get()) } - fn owned(who: &AccountId) -> Box> { + + fn owned(who: &AccountId) -> Self::OwnedIterator { >::owned_in_collection(&A::get(), who) } } diff --git a/frame/support/src/traits/tokens/nonfungibles.rs b/frame/support/src/traits/tokens/nonfungibles.rs index d043a87ce7c10..ac007b5a67f1d 100644 --- a/frame/support/src/traits/tokens/nonfungibles.rs +++ b/frame/support/src/traits/tokens/nonfungibles.rs @@ -105,20 +105,29 @@ pub trait Inspect { /// Interface for enumerating items in existence or owned by a given account over many collections /// of NFTs. pub trait InspectEnumerable: Inspect { + /// The iterator type for [`Self::collections`]. + type CollectionsIterator: Iterator; + /// The iterator type for [`Self::items`]. + type ItemsIterator: Iterator; + /// The iterator type for [`Self::owned`]. + type OwnedIterator: Iterator; + /// The iterator type for [`Self::owned_in_collection`]. + type OwnedInCollectionIterator: Iterator; + /// Returns an iterator of the collections in existence. - fn collections() -> Box>; + fn collections() -> Self::CollectionsIterator; /// Returns an iterator of the items of a `collection` in existence. - fn items(collection: &Self::CollectionId) -> Box>; + fn items(collection: &Self::CollectionId) -> Self::ItemsIterator; /// Returns an iterator of the items of all collections owned by `who`. - fn owned(who: &AccountId) -> Box>; + fn owned(who: &AccountId) -> Self::OwnedIterator; /// Returns an iterator of the items of `collection` owned by `who`. fn owned_in_collection( collection: &Self::CollectionId, who: &AccountId, - ) -> Box>; + ) -> Self::OwnedInCollectionIterator; } /// Trait for providing the ability to create collections of nonfungible items. diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index cead6f562ab58..75d193ad19605 100644 --- a/frame/uniques/src/impl_nonfungibles.rs +++ b/frame/uniques/src/impl_nonfungibles.rs @@ -19,6 +19,7 @@ use super::*; use frame_support::{ + storage::KeyPrefixIterator, traits::{tokens::nonfungibles::*, Get}, BoundedSlice, }; @@ -155,25 +156,31 @@ impl, I: 'static> Transfer for Pallet { } impl, I: 'static> InspectEnumerable for Pallet { + type CollectionsIterator = KeyPrefixIterator<>::CollectionId>; + type ItemsIterator = KeyPrefixIterator<>::ItemId>; + type OwnedIterator = + KeyPrefixIterator<(>::CollectionId, >::ItemId)>; + type OwnedInCollectionIterator = KeyPrefixIterator<>::ItemId>; + /// Returns an iterator of the collections in existence. /// /// NOTE: iterating this list invokes a storage read per item. - fn collections() -> Box> { - Box::new(CollectionMetadataOf::::iter_keys()) + fn collections() -> Self::CollectionsIterator { + CollectionMetadataOf::::iter_keys() } /// Returns an iterator of the items of a `collection` in existence. /// /// NOTE: iterating this list invokes a storage read per item. - fn items(collection: &Self::CollectionId) -> Box> { - Box::new(ItemMetadataOf::::iter_key_prefix(collection)) + fn items(collection: &Self::CollectionId) -> Self::ItemsIterator { + ItemMetadataOf::::iter_key_prefix(collection) } /// Returns an iterator of the items of all collections owned by `who`. /// /// NOTE: iterating this list invokes a storage read per item. - fn owned(who: &T::AccountId) -> Box> { - Box::new(Account::::iter_key_prefix((who,))) + fn owned(who: &T::AccountId) -> Self::OwnedIterator { + Account::::iter_key_prefix((who,)) } /// Returns an iterator of the items of `collection` owned by `who`. @@ -182,7 +189,7 @@ impl, I: 'static> InspectEnumerable for Pallet fn owned_in_collection( collection: &Self::CollectionId, who: &T::AccountId, - ) -> Box> { - Box::new(Account::::iter_key_prefix((who, collection))) + ) -> Self::OwnedInCollectionIterator { + Account::::iter_key_prefix((who, collection)) } } From a88f75eb54414405ffa785072d38548793f0009e Mon Sep 17 00:00:00 2001 From: benluelo <57334811+benluelo@users.noreply.github.com> Date: Thu, 3 Nov 2022 07:20:13 -0400 Subject: [PATCH 1333/1472] Add map and try_map methods (#12581) Co-authored-by: parity-processbot <> --- .../core/src/bounded/bounded_btree_map.rs | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/primitives/core/src/bounded/bounded_btree_map.rs b/primitives/core/src/bounded/bounded_btree_map.rs index 32f8d85ca795b..d2c148d6de9c5 100644 --- a/primitives/core/src/bounded/bounded_btree_map.rs +++ b/primitives/core/src/bounded/bounded_btree_map.rs @@ -168,6 +168,37 @@ where pub fn iter_mut(&mut self) -> sp_std::collections::btree_map::IterMut { self.0.iter_mut() } + + /// Consume the map, applying `f` to each of it's values and returning a new map. + pub fn map(self, mut f: F) -> BoundedBTreeMap + where + F: FnMut((&K, V)) -> T, + { + BoundedBTreeMap::::unchecked_from( + self.0 + .into_iter() + .map(|(k, v)| { + let t = f((&k, v)); + (k, t) + }) + .collect(), + ) + } + + /// Consume the map, applying `f` to each of it's values as long as it returns successfully. If + /// an `Err(E)` is ever encountered, the mapping is short circuited and the error is returned; + /// otherwise, a new map is returned in the contained `Ok` value. + pub fn try_map(self, mut f: F) -> Result, E> + where + F: FnMut((&K, V)) -> Result, + { + Ok(BoundedBTreeMap::::unchecked_from( + self.0 + .into_iter() + .map(|(k, v)| (f((&k, v)).map(|t| (k, t)))) + .collect::, _>>()?, + )) + } } impl Default for BoundedBTreeMap @@ -537,4 +568,58 @@ pub mod test { assert_eq!(b1, b2); } + + #[test] + fn map_retains_size() { + let b1 = boundedmap_from_keys::>(&[1, 2]); + let b2 = b1.clone(); + + assert_eq!(b1.len(), b2.map(|(_, _)| 5_u32).len()); + } + + #[test] + fn map_maps_properly() { + let b1: BoundedBTreeMap> = + [1, 2, 3, 4].into_iter().map(|k| (k, k * 2)).try_collect().unwrap(); + let b2: BoundedBTreeMap> = + [1, 2, 3, 4].into_iter().map(|k| (k, k)).try_collect().unwrap(); + + assert_eq!(b1, b2.map(|(_, v)| v * 2)); + } + + #[test] + fn try_map_retains_size() { + let b1 = boundedmap_from_keys::>(&[1, 2]); + let b2 = b1.clone(); + + assert_eq!(b1.len(), b2.try_map::<_, (), _>(|(_, _)| Ok(5_u32)).unwrap().len()); + } + + #[test] + fn try_map_maps_properly() { + let b1: BoundedBTreeMap> = + [1, 2, 3, 4].into_iter().map(|k| (k, k * 2)).try_collect().unwrap(); + let b2: BoundedBTreeMap> = + [1, 2, 3, 4].into_iter().map(|k| (k, k)).try_collect().unwrap(); + + assert_eq!(b1, b2.try_map::<_, (), _>(|(_, v)| Ok(v * 2)).unwrap()); + } + + #[test] + fn try_map_short_circuit() { + let b1: BoundedBTreeMap> = + [1, 2, 3, 4].into_iter().map(|k| (k, k)).try_collect().unwrap(); + + assert_eq!(Err("overflow"), b1.try_map(|(_, v)| v.checked_mul(100).ok_or("overflow"))); + } + + #[test] + fn try_map_ok() { + let b1: BoundedBTreeMap> = + [1, 2, 3, 4].into_iter().map(|k| (k, k)).try_collect().unwrap(); + let b2: BoundedBTreeMap> = + [1, 2, 3, 4].into_iter().map(|k| (k, (k as u16) * 100)).try_collect().unwrap(); + + assert_eq!(Ok(b2), b1.try_map(|(_, v)| (v as u16).checked_mul(100_u16).ok_or("overflow"))); + } } From 265e3f12a2937fe4f71280b3652471627609d04f Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Thu, 3 Nov 2022 18:23:05 +0200 Subject: [PATCH 1334/1472] stabilize 4 storage host funcs (#12611) --- frame/contracts/src/benchmarking/mod.rs | 18 ++-- frame/contracts/src/wasm/mod.rs | 135 +----------------------- frame/contracts/src/wasm/runtime.rs | 8 +- 3 files changed, 17 insertions(+), 144 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index a952eeb2cbd3a..5465e720dc197 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -919,7 +919,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal2", name: "set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -967,7 +967,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal2", name: "set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -1015,7 +1015,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal2", name: "set_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -1067,7 +1067,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal1", name: "clear_storage", params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -1114,7 +1114,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal1", name: "clear_storage", params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -1162,7 +1162,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal1", name: "get_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -1216,7 +1216,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal1", name: "get_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -1271,7 +1271,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal1", name: "contains_storage", params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -1318,7 +1318,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal1", name: "contains_storage", params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 053729730e679..9a094ad4f7da0 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -896,73 +896,12 @@ mod tests { } #[test] - #[cfg(not(feature = "unstable-interface"))] fn contains_storage_works() { const CODE: &str = r#" (module (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "seal0" "seal_contains_storage" (func $seal_contains_storage (param i32) (result i32))) - (import "env" "memory" (memory 1 1)) - - ;; [0, 4) size of input buffer (32 bytes as we copy the key here) - (data (i32.const 0) "\20") - - ;; [4, 36) input buffer - ;; [36, inf) output buffer - - (func (export "call") - ;; Receive key - (call $seal_input - (i32.const 4) ;; Pointer to the input buffer - (i32.const 0) ;; Size of the length buffer - ) - - ;; Load the return value into the output buffer - (i32.store (i32.const 36) - (call $seal_contains_storage - (i32.const 4) ;; The pointer to the storage key to fetch - ) - ) - - ;; Return the contents of the buffer - (call $seal_return - (i32.const 0) ;; flags - (i32.const 36) ;; output buffer ptr - (i32.const 4) ;; result is integer (4 bytes) - ) - ) - - (func (export "deploy")) -) -"#; - - let mut ext = MockExt::default(); - - ext.storage.insert(vec![1u8; 32], vec![42u8]); - ext.storage.insert(vec![2u8; 32], vec![]); - - // value does not exist -> sentinel value returned - let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); - - // value did exist -> success - let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1,); - - // value did exist -> success (zero sized type) - let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0,); - } - - #[test] - #[cfg(feature = "unstable-interface")] - fn contains_storage_works() { - const CODE: &str = r#" -(module - (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "__unstable__" "contains_storage" (func $contains_storage (param i32 i32) (result i32))) + (import "seal1" "contains_storage" (func $contains_storage (param i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) @@ -2357,76 +2296,12 @@ mod tests { } #[test] - #[cfg(not(feature = "unstable-interface"))] fn set_storage_works() { const CODE: &str = r#" (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "seal1" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32) (result i32))) - (import "env" "memory" (memory 1 1)) - - ;; 0x1000 = 4k in little endian - ;; size of input buffer - (data (i32.const 0) "\00\10") - - (func (export "call") - ;; Receive (key ++ value_to_write) - (call $seal_input - (i32.const 4) ;; Pointer to the input buffer - (i32.const 0) ;; Size of the length buffer - ) - ;; Store the passed value to the passed key and store result to memory - (i32.store (i32.const 0) - (call $seal_set_storage - (i32.const 4) ;; key_ptr - (i32.const 36) ;; value_ptr - (i32.sub ;; value_len (input_size - key_size) - (i32.load (i32.const 0)) - (i32.const 32) - ) - ) - ) - (call $seal_return - (i32.const 0) ;; flags - (i32.const 0) ;; pointer to returned value - (i32.const 4) ;; length of returned value - ) - ) - - (func (export "deploy")) -) -"#; - - let mut ext = MockExt::default(); - - // value did not exist before -> sentinel returned - let input = ([1u8; 32], [42u8, 48]).encode(); - let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); - assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[42u8, 48]); - - // value do exist -> length of old value returned - let input = ([1u8; 32], [0u8; 0]).encode(); - let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 2); - assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[0u8; 0]); - - // value do exist -> length of old value returned (test for zero sized val) - let input = ([1u8; 32], [99u8]).encode(); - let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); - assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[99u8]); - } - - #[test] - #[cfg(feature = "unstable-interface")] - fn set_storage_works() { - const CODE: &str = r#" -(module - (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "__unstable__" "set_storage" (func $set_storage (param i32 i32 i32 i32) (result i32))) + (import "seal2" "set_storage" (func $set_storage (param i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 4) size of input buffer @@ -2491,13 +2366,12 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn get_storage_works() { const CODE: &str = r#" (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "__unstable__" "get_storage" (func $get_storage (param i32 i32 i32 i32) (result i32))) + (import "seal1" "get_storage" (func $get_storage (param i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 4) size of input buffer (160 bytes as we copy the key+len here) @@ -2585,13 +2459,12 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn clear_storage_works() { const CODE: &str = r#" (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "__unstable__" "clear_storage" (func $clear_storage (param i32 i32) (result i32))) + (import "seal1" "clear_storage" (func $clear_storage (param i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; size of input buffer diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 281cc30c4f053..50947962c0631 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -1021,7 +1021,7 @@ pub mod env { /// /// Returns the size of the pre-existing value at the specified key if any. Otherwise /// `SENTINEL` is returned as a sentinel value. - #[unstable] + #[version(2)] #[prefixed_alias] fn set_storage( ctx: Runtime, @@ -1053,7 +1053,7 @@ pub mod env { /// /// Returns the size of the pre-existing value at the specified key if any. Otherwise /// `SENTINEL` is returned as a sentinel value. - #[unstable] + #[version(1)] #[prefixed_alias] fn clear_storage(ctx: Runtime, key_ptr: u32, key_len: u32) -> Result { ctx.clear_storage(KeyType::Variable(key_len), key_ptr) @@ -1102,7 +1102,7 @@ pub mod env { /// # Errors /// /// `ReturnCode::KeyNotFound` - #[unstable] + #[version(1)] #[prefixed_alias] fn get_storage( ctx: Runtime, @@ -1145,7 +1145,7 @@ pub mod env { /// /// Returns the size of the pre-existing value at the specified key if any. Otherwise /// `SENTINEL` is returned as a sentinel value. - #[unstable] + #[version(1)] #[prefixed_alias] fn contains_storage(ctx: Runtime, key_ptr: u32, key_len: u32) -> Result { ctx.contains_storage(KeyType::Variable(key_len), key_ptr) From a4ebc278492d131f9c0bc9f7e393ca748e30d1b4 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Thu, 3 Nov 2022 17:52:57 +0100 Subject: [PATCH 1335/1472] Collective benchmark respects DefaultVote configuration (#12612) * Collective benchmark respects DefaultVote configuration * ".git/.scripts/bench-bot.sh" pallet dev pallet_collective Co-authored-by: command-bot <> --- frame/collective/src/benchmarking.rs | 10 + frame/collective/src/weights.rs | 300 ++++++++++++++++----------- 2 files changed, 192 insertions(+), 118 deletions(-) diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index fcebacf5762e7..4e8bf094ef9d6 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -489,9 +489,19 @@ benchmarks_instance_pallet! { let index = p - 1; // Have almost everyone vote aye on last proposal, while keeping it from passing. // A few abstainers will be the nay votes needed to fail the vote. + let mut yes_votes: MemberCount = 0; for j in 2 .. m - 1 { let voter = &members[j as usize]; let approve = true; + yes_votes += 1; + // vote aye till a prime nay vote keeps the proposal disapproved. + if <>::DefaultVote as DefaultVote>::default_vote( + Some(false), + yes_votes, + 0, + m,) { + break; + } Collective::::vote( SystemOrigin::Signed(voter.clone()).into(), last_hash, diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index 50029046230af..c7237911da6ab 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,22 +18,26 @@ //! Autogenerated weights for pallet_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_collective // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_collective +// --chain=dev +// --header=./HEADER-APACHE2 // --output=./frame/collective/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -61,38 +65,46 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Council Members (r:1 w:1) // Storage: Council Proposals (r:1 w:0) - // Storage: Council Voting (r:100 w:100) // Storage: Council Prime (r:0 w:1) - fn set_members(m: u32, n: u32, p: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(10_280_000 as u64).saturating_mul(m as u64)) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(126_000 as u64).saturating_mul(n as u64)) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(13_310_000 as u64).saturating_mul(p as u64)) + // Storage: Council Voting (r:100 w:100) + /// The range of component `m` is `[0, 100]`. + /// The range of component `n` is `[0, 100]`. + /// The range of component `p` is `[0, 100]`. + fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { + // Minimum execution time: 18_852 nanoseconds. + Weight::from_ref_time(19_138_000 as u64) + // Standard Error: 65_564 + .saturating_add(Weight::from_ref_time(5_276_957 as u64).saturating_mul(m as u64)) + // Standard Error: 65_564 + .saturating_add(Weight::from_ref_time(7_655_866 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(p as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(p as u64))) } // Storage: Council Members (r:1 w:0) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { - Weight::from_ref_time(16_819_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 23_081 nanoseconds. + Weight::from_ref_time(22_608_754 as u64) + // Standard Error: 35 + .saturating_add(Weight::from_ref_time(1_722 as u64).saturating_mul(b as u64)) + // Standard Error: 370 + .saturating_add(Weight::from_ref_time(23_442 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { - Weight::from_ref_time(18_849_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 25_477 nanoseconds. + Weight::from_ref_time(25_478_243 as u64) + // Standard Error: 47 + .saturating_add(Weight::from_ref_time(1_346 as u64).saturating_mul(b as u64)) + // Standard Error: 493 + .saturating_add(Weight::from_ref_time(27_323 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) } // Storage: Council Members (r:1 w:0) @@ -100,23 +112,29 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[2, 100]`. + /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(22_204_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(8_000 as u64).saturating_mul(b as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(49_000 as u64).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(180_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 33_037 nanoseconds. + Weight::from_ref_time(29_297_056 as u64) + // Standard Error: 180 + .saturating_add(Weight::from_ref_time(5_899 as u64).saturating_mul(b as u64)) + // Standard Error: 1_884 + .saturating_add(Weight::from_ref_time(33_511 as u64).saturating_mul(m as u64)) + // Standard Error: 1_860 + .saturating_add(Weight::from_ref_time(195_416 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) + /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { - Weight::from_ref_time(30_941_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 35_284 nanoseconds. + Weight::from_ref_time(38_865_202 as u64) + // Standard Error: 2_322 + .saturating_add(Weight::from_ref_time(53_753 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -124,12 +142,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Members (r:1 w:0) // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(32_485_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(39_000 as u64).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 35_773 nanoseconds. + Weight::from_ref_time(36_651_208 as u64) + // Standard Error: 1_142 + .saturating_add(Weight::from_ref_time(27_095 as u64).saturating_mul(m as u64)) + // Standard Error: 1_114 + .saturating_add(Weight::from_ref_time(169_747 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -137,14 +158,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_487_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(b as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(66_000 as u64).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(157_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 46_290 nanoseconds. + Weight::from_ref_time(46_176_864 as u64) + // Standard Error: 147 + .saturating_add(Weight::from_ref_time(2_318 as u64).saturating_mul(b as u64)) + // Standard Error: 1_560 + .saturating_add(Weight::from_ref_time(31_428 as u64).saturating_mul(m as u64)) + // Standard Error: 1_520 + .saturating_add(Weight::from_ref_time(171_822 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -153,12 +178,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Prime (r:1 w:0) // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_494_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(58_000 as u64).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 38_421 nanoseconds. + Weight::from_ref_time(40_586_165 as u64) + // Standard Error: 1_853 + .saturating_add(Weight::from_ref_time(20_063 as u64).saturating_mul(m as u64)) + // Standard Error: 1_807 + .saturating_add(Weight::from_ref_time(151_494 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -167,24 +195,30 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Prime (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(36_566_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(b as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(63_000 as u64).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 48_281 nanoseconds. + Weight::from_ref_time(47_511_499 as u64) + // Standard Error: 135 + .saturating_add(Weight::from_ref_time(1_900 as u64).saturating_mul(b as u64)) + // Standard Error: 1_429 + .saturating_add(Weight::from_ref_time(37_612 as u64).saturating_mul(m as u64)) + // Standard Error: 1_393 + .saturating_add(Weight::from_ref_time(180_682 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Council Proposals (r:1 w:1) // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) + /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(20_159_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 22_534 nanoseconds. + Weight::from_ref_time(25_722_688 as u64) + // Standard Error: 1_622 + .saturating_add(Weight::from_ref_time(166_308 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -194,38 +228,46 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Council Members (r:1 w:1) // Storage: Council Proposals (r:1 w:0) - // Storage: Council Voting (r:100 w:100) // Storage: Council Prime (r:0 w:1) - fn set_members(m: u32, n: u32, p: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(10_280_000 as u64).saturating_mul(m as u64)) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(126_000 as u64).saturating_mul(n as u64)) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(13_310_000 as u64).saturating_mul(p as u64)) + // Storage: Council Voting (r:100 w:100) + /// The range of component `m` is `[0, 100]`. + /// The range of component `n` is `[0, 100]`. + /// The range of component `p` is `[0, 100]`. + fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { + // Minimum execution time: 18_852 nanoseconds. + Weight::from_ref_time(19_138_000 as u64) + // Standard Error: 65_564 + .saturating_add(Weight::from_ref_time(5_276_957 as u64).saturating_mul(m as u64)) + // Standard Error: 65_564 + .saturating_add(Weight::from_ref_time(7_655_866 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(p as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(p as u64))) } // Storage: Council Members (r:1 w:0) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { - Weight::from_ref_time(16_819_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 23_081 nanoseconds. + Weight::from_ref_time(22_608_754 as u64) + // Standard Error: 35 + .saturating_add(Weight::from_ref_time(1_722 as u64).saturating_mul(b as u64)) + // Standard Error: 370 + .saturating_add(Weight::from_ref_time(23_442 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:0) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { - Weight::from_ref_time(18_849_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 25_477 nanoseconds. + Weight::from_ref_time(25_478_243 as u64) + // Standard Error: 47 + .saturating_add(Weight::from_ref_time(1_346 as u64).saturating_mul(b as u64)) + // Standard Error: 493 + .saturating_add(Weight::from_ref_time(27_323 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) } // Storage: Council Members (r:1 w:0) @@ -233,23 +275,29 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalCount (r:1 w:1) // Storage: Council Voting (r:0 w:1) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[2, 100]`. + /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(22_204_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(8_000 as u64).saturating_mul(b as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(49_000 as u64).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(180_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 33_037 nanoseconds. + Weight::from_ref_time(29_297_056 as u64) + // Standard Error: 180 + .saturating_add(Weight::from_ref_time(5_899 as u64).saturating_mul(b as u64)) + // Standard Error: 1_884 + .saturating_add(Weight::from_ref_time(33_511 as u64).saturating_mul(m as u64)) + // Standard Error: 1_860 + .saturating_add(Weight::from_ref_time(195_416 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Council Members (r:1 w:0) // Storage: Council Voting (r:1 w:1) + /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { - Weight::from_ref_time(30_941_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 35_284 nanoseconds. + Weight::from_ref_time(38_865_202 as u64) + // Standard Error: 2_322 + .saturating_add(Weight::from_ref_time(53_753 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -257,12 +305,15 @@ impl WeightInfo for () { // Storage: Council Members (r:1 w:0) // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(32_485_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(39_000 as u64).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 35_773 nanoseconds. + Weight::from_ref_time(36_651_208 as u64) + // Standard Error: 1_142 + .saturating_add(Weight::from_ref_time(27_095 as u64).saturating_mul(m as u64)) + // Standard Error: 1_114 + .saturating_add(Weight::from_ref_time(169_747 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -270,14 +321,18 @@ impl WeightInfo for () { // Storage: Council Members (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_487_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(b as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(66_000 as u64).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(157_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 46_290 nanoseconds. + Weight::from_ref_time(46_176_864 as u64) + // Standard Error: 147 + .saturating_add(Weight::from_ref_time(2_318 as u64).saturating_mul(b as u64)) + // Standard Error: 1_560 + .saturating_add(Weight::from_ref_time(31_428 as u64).saturating_mul(m as u64)) + // Standard Error: 1_520 + .saturating_add(Weight::from_ref_time(171_822 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -286,12 +341,15 @@ impl WeightInfo for () { // Storage: Council Prime (r:1 w:0) // Storage: Council Proposals (r:1 w:1) // Storage: Council ProposalOf (r:0 w:1) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_494_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(58_000 as u64).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 38_421 nanoseconds. + Weight::from_ref_time(40_586_165 as u64) + // Standard Error: 1_853 + .saturating_add(Weight::from_ref_time(20_063 as u64).saturating_mul(m as u64)) + // Standard Error: 1_807 + .saturating_add(Weight::from_ref_time(151_494 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -300,24 +358,30 @@ impl WeightInfo for () { // Storage: Council Prime (r:1 w:0) // Storage: Council ProposalOf (r:1 w:1) // Storage: Council Proposals (r:1 w:1) + /// The range of component `b` is `[1, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_ref_time(36_566_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(b as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(63_000 as u64).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 48_281 nanoseconds. + Weight::from_ref_time(47_511_499 as u64) + // Standard Error: 135 + .saturating_add(Weight::from_ref_time(1_900 as u64).saturating_mul(b as u64)) + // Standard Error: 1_429 + .saturating_add(Weight::from_ref_time(37_612 as u64).saturating_mul(m as u64)) + // Standard Error: 1_393 + .saturating_add(Weight::from_ref_time(180_682 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Council Proposals (r:1 w:1) // Storage: Council Voting (r:0 w:1) // Storage: Council ProposalOf (r:0 w:1) + /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(20_159_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 22_534 nanoseconds. + Weight::from_ref_time(25_722_688 as u64) + // Standard Error: 1_622 + .saturating_add(Weight::from_ref_time(166_308 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } From 87f3fdea8f227d33322c439d45a9e1796637e972 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 3 Nov 2022 17:57:10 +0100 Subject: [PATCH 1336/1472] BlockId removal: refactor: Backend::block_indexed_body (#12609) * BlockId removal: refactor: Backend::block_indexed_body It changes the arguments of `Backend::block_indexed_body` method from: `BlockId` to: `&Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) * trigger CI job --- client/api/src/client.rs | 6 ++---- client/api/src/in_mem.rs | 2 +- client/db/src/lib.rs | 9 +++++++-- client/network/sync/src/block_request_handler.rs | 2 +- client/service/src/client/client.rs | 16 +++++++++++++--- primitives/blockchain/src/backend.rs | 2 +- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/client/api/src/client.rs b/client/api/src/client.rs index d0053afeba97b..a07198abfe8d6 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -118,10 +118,8 @@ pub trait BlockBackend { /// /// Note that this will only fetch transactions /// that are indexed by the runtime with `storage_index_transaction`. - fn block_indexed_body( - &self, - id: &BlockId, - ) -> sp_blockchain::Result>>>; + fn block_indexed_body(&self, hash: &Block::Hash) + -> sp_blockchain::Result>>>; /// Get full block by id. fn block(&self, id: &BlockId) -> sp_blockchain::Result>>; diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 6f33695fe4bf4..26364f28acca2 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -451,7 +451,7 @@ impl blockchain::Backend for Blockchain { fn block_indexed_body( &self, - _id: BlockId, + _hash: &Block::Hash, ) -> sp_blockchain::Result>>> { unimplemented!("Not supported by the in-mem backend.") } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index af45e7c961fd3..0138df36a38fb 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -694,8 +694,13 @@ impl sc_client_api::blockchain::Backend for BlockchainDb) -> ClientResult>>> { - let body = match read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY_INDEX, id)? { + fn block_indexed_body(&self, hash: &Block::Hash) -> ClientResult>>> { + let body = match read_db( + &*self.db, + columns::KEY_LOOKUP, + columns::BODY_INDEX, + BlockId::::Hash(*hash), + )? { Some(body) => body, None => return Ok(None), }; diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index 08b8cffa38714..5eba1d52dc68c 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -374,7 +374,7 @@ where }; let indexed_body = if get_indexed_body { - match self.client.block_indexed_body(&BlockId::Hash(hash))? { + match self.client.block_indexed_body(&hash)? { Some(transactions) => transactions, None => { log::trace!( diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 6d463f337aabc..a4890f2fcf06f 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1980,9 +1980,9 @@ where fn block_indexed_body( &self, - id: &BlockId, + hash: &Block::Hash, ) -> sp_blockchain::Result>>> { - self.backend.blockchain().block_indexed_body(*id) + self.backend.blockchain().block_indexed_body(hash) } fn requires_full_sync(&self) -> bool { @@ -2073,9 +2073,19 @@ where &self, number: NumberFor, ) -> Result>>, sp_transaction_storage_proof::Error> { + let hash = match self + .backend + .blockchain() + .block_hash_from_id(&BlockId::Number(number)) + .map_err(|e| sp_transaction_storage_proof::Error::Application(Box::new(e)))? + { + Some(hash) => hash, + None => return Ok(None), + }; + self.backend .blockchain() - .block_indexed_body(BlockId::number(number)) + .block_indexed_body(&hash) .map_err(|e| sp_transaction_storage_proof::Error::Application(Box::new(e))) } diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index e5764354e90f3..fdb56020661b4 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -238,7 +238,7 @@ pub trait Backend: Ok(self.indexed_transaction(hash)?.is_some()) } - fn block_indexed_body(&self, id: BlockId) -> Result>>>; + fn block_indexed_body(&self, hash: &Block::Hash) -> Result>>>; } /// Blockchain info From 564cdeb9026a556133cab6ff20a6f7426e24b38e Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Thu, 3 Nov 2022 20:51:18 +0100 Subject: [PATCH 1337/1472] Introduce DefensiveMin and DefensiveMax (#12554) * traits for defensive min and defensive max * defensive min and strict min with tests * defensive max and strict max with tests * include docs * implement partial ord on defensive min and max * Update frame/support/src/traits/misc.rs Co-authored-by: Oliver Tale-Yazdi * wrap lines * Fix traits Signed-off-by: Oliver Tale-Yazdi * Update frame/support/src/traits/misc.rs * Update frame/support/src/traits/misc.rs Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- frame/support/src/traits.rs | 10 +- frame/support/src/traits/misc.rs | 176 +++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 5 deletions(-) diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 2b6c5efee10bb..f09b715a970ad 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -56,11 +56,11 @@ mod misc; pub use misc::{ defensive_prelude::{self, *}, Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, - ConstU32, ConstU64, ConstU8, DefensiveSaturating, DefensiveTruncateFrom, - EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, - GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, - OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, TypedGet, - UnixTime, WrapperKeepOpaque, WrapperOpaque, + ConstU32, ConstU64, ConstU8, DefensiveMax, DefensiveMin, DefensiveSaturating, + DefensiveTruncateFrom, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, + ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, + Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, + TryCollect, TryDrop, TypedGet, UnixTime, WrapperKeepOpaque, WrapperOpaque, }; #[allow(deprecated)] pub use misc::{PreimageProvider, PreimageRecipient}; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 1297956b2f64e..ce8faaaf37c3d 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -407,6 +407,134 @@ where } } +/// Defensively calculates the minimum of two values. +/// +/// Can be used in contexts where we assume the receiver value to be (strictly) smaller. +pub trait DefensiveMin { + /// Returns the minimum and defensively checks that `self` is not larger than `other`. + /// + /// # Example + /// + /// ``` + /// use frame_support::traits::DefensiveMin; + /// // min(3, 4) is 3. + /// assert_eq!(3, 3_u32.defensive_min(4_u32)); + /// // min(4, 4) is 4. + /// assert_eq!(4, 4_u32.defensive_min(4_u32)); + /// ``` + /// + /// ```should_panic + /// use frame_support::traits::DefensiveMin; + /// // min(4, 3) panics. + /// 4_u32.defensive_min(3_u32); + /// ``` + fn defensive_min(self, other: T) -> Self; + + /// Returns the minimum and defensively checks that `self` is smaller than `other`. + /// + /// # Example + /// + /// ``` + /// use frame_support::traits::DefensiveMin; + /// // min(3, 4) is 3. + /// assert_eq!(3, 3_u32.defensive_strict_min(4_u32)); + /// ``` + /// + /// ```should_panic + /// use frame_support::traits::DefensiveMin; + /// // min(4, 4) panics. + /// 4_u32.defensive_strict_min(4_u32); + /// ``` + fn defensive_strict_min(self, other: T) -> Self; +} + +impl DefensiveMin for T +where + T: sp_std::cmp::PartialOrd, +{ + fn defensive_min(self, other: T) -> Self { + if self <= other { + self + } else { + defensive!("DefensiveMin"); + other + } + } + + fn defensive_strict_min(self, other: T) -> Self { + if self < other { + self + } else { + defensive!("DefensiveMin strict"); + other + } + } +} + +/// Defensively calculates the maximum of two values. +/// +/// Can be used in contexts where we assume the receiver value to be (strictly) larger. +pub trait DefensiveMax { + /// Returns the maximum and defensively asserts that `other` is not larger than `self`. + /// + /// # Example + /// + /// ``` + /// use frame_support::traits::DefensiveMax; + /// // max(4, 3) is 4. + /// assert_eq!(4, 4_u32.defensive_max(3_u32)); + /// // max(4, 4) is 4. + /// assert_eq!(4, 4_u32.defensive_max(4_u32)); + /// ``` + /// + /// ```should_panic + /// use frame_support::traits::DefensiveMax; + /// // max(4, 5) panics. + /// 4_u32.defensive_max(5_u32); + /// ``` + fn defensive_max(self, other: T) -> Self; + + /// Returns the maximum and defensively asserts that `other` is smaller than `self`. + /// + /// # Example + /// + /// ``` + /// use frame_support::traits::DefensiveMax; + /// // y(4, 3) is 4. + /// assert_eq!(4, 4_u32.defensive_strict_max(3_u32)); + /// ``` + /// + /// ```should_panic + /// use frame_support::traits::DefensiveMax; + /// // max(4, 4) panics. + /// 4_u32.defensive_strict_max(4_u32); + /// ``` + fn defensive_strict_max(self, other: T) -> Self; +} + +impl DefensiveMax for T +where + T: sp_std::cmp::PartialOrd, +{ + fn defensive_max(self, other: T) -> Self { + if self >= other { + self + } else { + defensive!("DefensiveMax"); + other + } + } + + fn defensive_strict_max(self, other: T) -> Self { + if self > other { + self + } else { + defensive!("DefensiveMax strict"); + other + } + } +} + /// Anything that can have a `::len()` method. pub trait Len { /// Return the length of data type. @@ -1109,4 +1237,52 @@ mod test { let data = decoded.encode(); WrapperOpaque::::decode(&mut &data[..]).unwrap(); } + + #[test] + fn defensive_min_works() { + assert_eq!(10, 10_u32.defensive_min(11_u32)); + assert_eq!(10, 10_u32.defensive_min(10_u32)); + } + + #[test] + #[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMin\"")] + fn defensive_min_panics() { + 10_u32.defensive_min(9_u32); + } + + #[test] + fn defensive_strict_min_works() { + assert_eq!(10, 10_u32.defensive_strict_min(11_u32)); + assert_eq!(9, 9_u32.defensive_strict_min(10_u32)); + } + + #[test] + #[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMin strict\"")] + fn defensive_strict_min_panics() { + 9_u32.defensive_strict_min(9_u32); + } + + #[test] + fn defensive_max_works() { + assert_eq!(11, 11_u32.defensive_max(10_u32)); + assert_eq!(10, 10_u32.defensive_max(10_u32)); + } + + #[test] + #[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMax\"")] + fn defensive_max_panics() { + 9_u32.defensive_max(10_u32); + } + + #[test] + fn defensive_strict_max_works() { + assert_eq!(11, 11_u32.defensive_strict_max(10_u32)); + assert_eq!(10, 10_u32.defensive_strict_max(9_u32)); + } + + #[test] + #[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMax strict\"")] + fn defensive_strict_max_panics() { + 9_u32.defensive_strict_max(9_u32); + } } From b2a914c09739478c63d318f6b294901a3290e548 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Fri, 4 Nov 2022 07:08:24 +0800 Subject: [PATCH 1338/1472] pallet-sudo: add `CheckOnlySudoAccount` signed extension (#12496) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * pallet-sudo: add `CheckSudoKey` signed extension Signed-off-by: koushiro * Rename CheckSudoKey => CheckOnlySudo Signed-off-by: koushiro * Rename extension name and Add some docs * Apply review suggestions * Update frame/sudo/src/extension.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * Update frame/sudo/src/extension.rs Signed-off-by: koushiro Co-authored-by: Bastian Köcher Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> --- frame/sudo/src/extension.rs | 107 ++++++++++++++++++++++++++++++++++++ frame/sudo/src/lib.rs | 11 +++- 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 frame/sudo/src/extension.rs diff --git a/frame/sudo/src/extension.rs b/frame/sudo/src/extension.rs new file mode 100644 index 0000000000000..068fa2ed928d5 --- /dev/null +++ b/frame/sudo/src/extension.rs @@ -0,0 +1,107 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{Config, Pallet}; +use codec::{Decode, Encode}; +use frame_support::{dispatch::DispatchInfo, ensure}; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{DispatchInfoOf, Dispatchable, SignedExtension}, + transaction_validity::{ + InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError, + UnknownTransaction, ValidTransaction, + }, +}; +use sp_std::{fmt, marker::PhantomData}; + +/// Ensure that signed transactions are only valid if they are signed by sudo account. +/// +/// In the initial phase of a chain without any tokens you can not prevent accounts from sending +/// transactions. +/// These transactions would enter the transaction pool as the succeed the validation, but would +/// fail on applying them as they are not allowed/disabled/whatever. This would be some huge dos +/// vector to any kind of chain. This extension solves the dos vector by preventing any kind of +/// transaction entering the pool as long as it is not signed by the sudo account. +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct CheckOnlySudoAccount(PhantomData); + +impl Default for CheckOnlySudoAccount { + fn default() -> Self { + Self(Default::default()) + } +} + +impl fmt::Debug for CheckOnlySudoAccount { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CheckOnlySudoAccount") + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +impl CheckOnlySudoAccount { + /// Creates new `SignedExtension` to check sudo key. + pub fn new() -> Self { + Self::default() + } +} + +impl SignedExtension for CheckOnlySudoAccount +where + ::RuntimeCall: Dispatchable, +{ + const IDENTIFIER: &'static str = "CheckOnlySudoAccount"; + type AccountId = T::AccountId; + type Call = ::RuntimeCall; + type AdditionalSigned = (); + type Pre = (); + + fn additional_signed(&self) -> Result { + Ok(()) + } + + fn validate( + &self, + who: &Self::AccountId, + _call: &Self::Call, + info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + let sudo_key: T::AccountId = >::key().ok_or(UnknownTransaction::CannotLookup)?; + ensure!(*who == sudo_key, InvalidTransaction::BadSigner); + + Ok(ValidTransaction { + priority: info.weight.ref_time() as TransactionPriority, + ..Default::default() + }) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) + } +} diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 75d15d23c680a..c18ced8911193 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -59,7 +59,7 @@ //! use frame_system::pallet_prelude::*; //! //! #[pallet::pallet] -//! pub struct Pallet(_); +//! pub struct Pallet(PhantomData); //! //! #[pallet::config] //! pub trait Config: frame_system::Config {} @@ -79,6 +79,13 @@ //! # fn main() {} //! ``` //! +//! ### Signed Extension +//! +//! The Sudo pallet defines the following extension: +//! +//! - [`CheckOnlySudoAccount`]: Ensures that the signed transactions are only valid if they are +//! signed by sudo account. +//! //! ## Genesis Config //! //! The Sudo pallet depends on the [`GenesisConfig`]. @@ -97,11 +104,13 @@ use sp_std::prelude::*; use frame_support::{dispatch::GetDispatchInfo, traits::UnfilteredDispatchable}; +mod extension; #[cfg(test)] mod mock; #[cfg(test)] mod tests; +pub use extension::CheckOnlySudoAccount; pub use pallet::*; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; From 6bd2eac1c230bfed1e58a8e2bad03d5bacf54b60 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Fri, 4 Nov 2022 18:13:57 +0100 Subject: [PATCH 1339/1472] Move Throughput into `sc-sysinfo` (#12368) * move Throughput to sc-sysinfo * replace u64 * fix in tests * change Throughput * refactored Throughput * fixes * moved tests & fixes * custom serializer * note * fix serializer * forgot to remove * deserialize * functioning deserialization :) * try to make clipply happy * Serialize as function * test HwBench * rename * fix serialization * deserialize as function * unused import * move serialize/deserialize * don't serialize none * remove nonsense * remove nonsense comment :P * fixes * remove all the todos * return enum * fixes * fix nit * improve docs & readability * Update client/sysinfo/src/sysinfo.rs Co-authored-by: Oliver Tale-Yazdi * fix all the nits * rename * fix * Update client/sysinfo/src/sysinfo.rs Co-authored-by: Oliver Tale-Yazdi * remove unit from serialization * Update utils/frame/benchmarking-cli/src/machine/hardware.rs Co-authored-by: Oliver Tale-Yazdi --- Cargo.lock | 2 + client/sysinfo/Cargo.toml | 3 + client/sysinfo/src/lib.rs | 19 +- client/sysinfo/src/sysinfo.rs | 187 +++++++++++++++--- utils/frame/benchmarking-cli/Cargo.toml | 1 + .../benchmarking-cli/src/machine/hardware.rs | 129 ++++-------- .../frame/benchmarking-cli/src/machine/mod.rs | 19 +- .../src/machine/reference_hardware.json | 20 +- 8 files changed, 236 insertions(+), 144 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b87f45508dfc9..48af2ffe4d88f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2216,6 +2216,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-state-machine", + "sp-std", "sp-storage", "sp-trie", "tempfile", @@ -8796,6 +8797,7 @@ dependencies = [ "serde_json", "sp-core", "sp-io", + "sp-runtime", "sp-std", ] diff --git a/client/sysinfo/Cargo.toml b/client/sysinfo/Cargo.toml index 1e96f69a92dfe..882cbd96c1c5f 100644 --- a/client/sysinfo/Cargo.toml +++ b/client/sysinfo/Cargo.toml @@ -26,3 +26,6 @@ sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sp-core = { version = "6.0.0", path = "../../primitives/core" } sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-std = { version = "4.0.0", path = "../../primitives/std" } + +[dev-dependencies] +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } diff --git a/client/sysinfo/src/lib.rs b/client/sysinfo/src/lib.rs index be63fefe9ecd1..372c7c1a6d219 100644 --- a/client/sysinfo/src/lib.rs +++ b/client/sysinfo/src/lib.rs @@ -29,6 +29,7 @@ mod sysinfo_linux; pub use sysinfo::{ benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes, benchmark_memory, benchmark_sr25519_verify, gather_hwbench, gather_sysinfo, + serialize_throughput, serialize_throughput_option, Throughput, }; /// The operating system part of the current target triplet. @@ -44,13 +45,23 @@ pub const TARGET_ENV: &str = include_str!(concat!(env!("OUT_DIR"), "/target_env. #[derive(Clone, Debug, serde::Serialize)] pub struct HwBench { /// The CPU speed, as measured in how many MB/s it can hash using the BLAKE2b-256 hash. - pub cpu_hashrate_score: u64, + #[serde(serialize_with = "serialize_throughput")] + pub cpu_hashrate_score: Throughput, /// Memory bandwidth in MB/s, calculated by measuring the throughput of `memcpy`. - pub memory_memcpy_score: u64, + #[serde(serialize_with = "serialize_throughput")] + pub memory_memcpy_score: Throughput, /// Sequential disk write speed in MB/s. - pub disk_sequential_write_score: Option, + #[serde( + serialize_with = "serialize_throughput_option", + skip_serializing_if = "Option::is_none" + )] + pub disk_sequential_write_score: Option, /// Random disk write speed in MB/s. - pub disk_random_write_score: Option, + #[serde( + serialize_with = "serialize_throughput_option", + skip_serializing_if = "Option::is_none" + )] + pub disk_random_write_score: Option, } /// Limit the execution time of a benchmark. diff --git a/client/sysinfo/src/sysinfo.rs b/client/sysinfo/src/sysinfo.rs index fc347c1cc2eb3..c66a6f6a62aed 100644 --- a/client/sysinfo/src/sysinfo.rs +++ b/client/sysinfo/src/sysinfo.rs @@ -21,9 +21,10 @@ use crate::{ExecutionLimit, HwBench}; use sc_telemetry::SysInfo; use sp_core::{sr25519, Pair}; use sp_io::crypto::sr25519_verify; -use sp_std::prelude::*; +use sp_std::{fmt, prelude::*}; use rand::{seq::SliceRandom, Rng, RngCore}; +use serde::Serializer; use std::{ fs::File, io::{Seek, SeekFrom, Write}, @@ -32,6 +33,110 @@ use std::{ time::{Duration, Instant}, }; +/// The unit in which the [`Throughput`] (bytes per second) is denoted. +pub enum Unit { + GiBs, + MiBs, + KiBs, +} + +impl fmt::Display for Unit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Unit::GiBs => "GiBs", + Unit::MiBs => "MiBs", + Unit::KiBs => "KiBs", + }) + } +} + +/// Throughput as measured in bytes per second. +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub struct Throughput(f64); + +const KIBIBYTE: f64 = (1 << 10) as f64; +const MEBIBYTE: f64 = (1 << 20) as f64; +const GIBIBYTE: f64 = (1 << 30) as f64; + +impl Throughput { + /// Construct [`Self`] from kibibyte/s. + pub fn from_kibs(kibs: f64) -> Throughput { + Throughput(kibs * KIBIBYTE) + } + + /// Construct [`Self`] from mebibyte/s. + pub fn from_mibs(mibs: f64) -> Throughput { + Throughput(mibs * MEBIBYTE) + } + + /// Construct [`Self`] from gibibyte/s. + pub fn from_gibs(gibs: f64) -> Throughput { + Throughput(gibs * GIBIBYTE) + } + + /// [`Self`] as number of byte/s. + pub fn as_bytes(&self) -> f64 { + self.0 + } + + /// [`Self`] as number of kibibyte/s. + pub fn as_kibs(&self) -> f64 { + self.0 / KIBIBYTE + } + + /// [`Self`] as number of mebibyte/s. + pub fn as_mibs(&self) -> f64 { + self.0 / MEBIBYTE + } + + /// [`Self`] as number of gibibyte/s. + pub fn as_gibs(&self) -> f64 { + self.0 / GIBIBYTE + } + + /// Normalizes [`Self`] to use the largest unit possible. + pub fn normalize(&self) -> (f64, Unit) { + let bs = self.0; + + if bs >= GIBIBYTE { + (self.as_gibs(), Unit::GiBs) + } else if bs >= MEBIBYTE { + (self.as_mibs(), Unit::MiBs) + } else { + (self.as_kibs(), Unit::KiBs) + } + } +} + +impl fmt::Display for Throughput { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (value, unit) = self.normalize(); + write!(f, "{:.2?} {}", value, unit) + } +} + +/// Serializes `Throughput` and uses MiBs as the unit. +pub fn serialize_throughput(throughput: &Throughput, serializer: S) -> Result +where + S: Serializer, +{ + serializer.serialize_u64(throughput.as_mibs() as u64) +} + +/// Serializes `Option` and uses MiBs as the unit. +pub fn serialize_throughput_option( + maybe_throughput: &Option, + serializer: S, +) -> Result +where + S: Serializer, +{ + if let Some(throughput) = maybe_throughput { + return serializer.serialize_some(&(throughput.as_mibs() as u64)) + } + serializer.serialize_none() +} + #[inline(always)] pub(crate) fn benchmark( name: &str, @@ -39,7 +144,7 @@ pub(crate) fn benchmark( max_iterations: usize, max_duration: Duration, mut run: impl FnMut() -> Result<(), E>, -) -> Result { +) -> Result { // Run the benchmark once as a warmup to get the code into the L1 cache. run()?; @@ -58,9 +163,9 @@ pub(crate) fn benchmark( } } - let score = ((size * count) as f64 / elapsed.as_secs_f64()) / (1024.0 * 1024.0); + let score = Throughput::from_kibs((size * count) as f64 / (elapsed.as_secs_f64() * 1024.0)); log::trace!( - "Calculated {} of {:.2}MB/s in {} iterations in {}ms", + "Calculated {} of {} in {} iterations in {}ms", name, score, count, @@ -120,14 +225,14 @@ fn clobber_value(input: &mut T) { pub const DEFAULT_CPU_EXECUTION_LIMIT: ExecutionLimit = ExecutionLimit::Both { max_iterations: 4 * 1024, max_duration: Duration::from_millis(100) }; -// This benchmarks the CPU speed as measured by calculating BLAKE2b-256 hashes, in MB/s. -pub fn benchmark_cpu(limit: ExecutionLimit) -> f64 { +// This benchmarks the CPU speed as measured by calculating BLAKE2b-256 hashes, in bytes per second. +pub fn benchmark_cpu(limit: ExecutionLimit) -> Throughput { // In general the results of this benchmark are somewhat sensitive to how much - // data we hash at the time. The smaller this is the *less* MB/s we can hash, - // the bigger this is the *more* MB/s we can hash, up until a certain point + // data we hash at the time. The smaller this is the *less* B/s we can hash, + // the bigger this is the *more* B/s we can hash, up until a certain point // where we can achieve roughly ~100% of what the hasher can do. If we'd plot // this on a graph with the number of bytes we want to hash on the X axis - // and the speed in MB/s on the Y axis then we'd essentially see it grow + // and the speed in B/s on the Y axis then we'd essentially see it grow // logarithmically. // // In practice however we might not always have enough data to hit the maximum @@ -156,12 +261,12 @@ pub fn benchmark_cpu(limit: ExecutionLimit) -> f64 { pub const DEFAULT_MEMORY_EXECUTION_LIMIT: ExecutionLimit = ExecutionLimit::Both { max_iterations: 32, max_duration: Duration::from_millis(100) }; -// This benchmarks the effective `memcpy` memory bandwidth available in MB/s. +// This benchmarks the effective `memcpy` memory bandwidth available in bytes per second. // // It doesn't technically measure the absolute maximum memory bandwidth available, // but that's fine, because real code most of the time isn't optimized to take // advantage of the full memory bandwidth either. -pub fn benchmark_memory(limit: ExecutionLimit) -> f64 { +pub fn benchmark_memory(limit: ExecutionLimit) -> Throughput { // Ideally this should be at least as big as the CPU's L3 cache, // and it should be big enough so that the `memcpy` takes enough // time to be actually measurable. @@ -253,7 +358,7 @@ pub const DEFAULT_DISK_EXECUTION_LIMIT: ExecutionLimit = pub fn benchmark_disk_sequential_writes( limit: ExecutionLimit, directory: &Path, -) -> Result { +) -> Result { const SIZE: usize = 64 * 1024 * 1024; let buffer = random_data(SIZE); @@ -295,7 +400,7 @@ pub fn benchmark_disk_sequential_writes( pub fn benchmark_disk_random_writes( limit: ExecutionLimit, directory: &Path, -) -> Result { +) -> Result { const SIZE: usize = 64 * 1024 * 1024; let buffer = random_data(SIZE); @@ -360,9 +465,9 @@ pub fn benchmark_disk_random_writes( /// Benchmarks the verification speed of sr25519 signatures. /// -/// Returns the throughput in MB/s by convention. +/// Returns the throughput in B/s by convention. /// The values are rather small (0.4-0.8) so it is advised to convert them into KB/s. -pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> f64 { +pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> Throughput { const INPUT_SIZE: usize = 32; const ITERATION_SIZE: usize = 2048; let pair = sr25519::Pair::from_string("//Alice", None).unwrap(); @@ -402,8 +507,8 @@ pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> f64 { pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { #[allow(unused_mut)] let mut hwbench = HwBench { - cpu_hashrate_score: benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT) as u64, - memory_memcpy_score: benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT) as u64, + cpu_hashrate_score: benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT), + memory_memcpy_score: benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT), disk_sequential_write_score: None, disk_random_write_score: None, }; @@ -412,7 +517,7 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { hwbench.disk_sequential_write_score = match benchmark_disk_sequential_writes(DEFAULT_DISK_EXECUTION_LIMIT, scratch_directory) { - Ok(score) => Some(score as u64), + Ok(score) => Some(score), Err(error) => { log::warn!("Failed to run the sequential write disk benchmark: {}", error); None @@ -421,7 +526,7 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { hwbench.disk_random_write_score = match benchmark_disk_random_writes(DEFAULT_DISK_EXECUTION_LIMIT, scratch_directory) { - Ok(score) => Some(score as u64), + Ok(score) => Some(score), Err(error) => { log::warn!("Failed to run the random write disk benchmark: {}", error); None @@ -435,6 +540,7 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { #[cfg(test)] mod tests { use super::*; + use sp_runtime::assert_eq_error_rate_float; #[cfg(target_os = "linux")] #[test] @@ -450,19 +556,19 @@ mod tests { #[test] fn test_benchmark_cpu() { - assert!(benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT) > 0.0); + assert!(benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT) > Throughput::from_mibs(0.0)); } #[test] fn test_benchmark_memory() { - assert!(benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT) > 0.0); + assert!(benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT) > Throughput::from_mibs(0.0)); } #[test] fn test_benchmark_disk_sequential_writes() { assert!( benchmark_disk_sequential_writes(DEFAULT_DISK_EXECUTION_LIMIT, "./".as_ref()).unwrap() > - 0.0 + Throughput::from_mibs(0.0) ); } @@ -470,12 +576,45 @@ mod tests { fn test_benchmark_disk_random_writes() { assert!( benchmark_disk_random_writes(DEFAULT_DISK_EXECUTION_LIMIT, "./".as_ref()).unwrap() > - 0.0 + Throughput::from_mibs(0.0) ); } #[test] fn test_benchmark_sr25519_verify() { - assert!(benchmark_sr25519_verify(ExecutionLimit::MaxIterations(1)) > 0.0); + assert!( + benchmark_sr25519_verify(ExecutionLimit::MaxIterations(1)) > Throughput::from_mibs(0.0) + ); + } + + /// Test the [`Throughput`]. + #[test] + fn throughput_works() { + /// Float precision. + const EPS: f64 = 0.1; + let gib = Throughput::from_gibs(14.324); + + assert_eq_error_rate_float!(14.324, gib.as_gibs(), EPS); + assert_eq_error_rate_float!(14667.776, gib.as_mibs(), EPS); + assert_eq_error_rate_float!(14667.776 * 1024.0, gib.as_kibs(), EPS); + assert_eq!("14.32 GiBs", gib.to_string()); + + let mib = Throughput::from_mibs(1029.0); + assert_eq!("1.00 GiBs", mib.to_string()); + } + + /// Test the [`HwBench`] serialization. + #[test] + fn hwbench_serialize_works() { + let hwbench = HwBench { + cpu_hashrate_score: Throughput::from_gibs(1.32), + memory_memcpy_score: Throughput::from_kibs(9342.432), + disk_sequential_write_score: Some(Throughput::from_kibs(4332.12)), + disk_random_write_score: None, + }; + + let serialized = serde_json::to_string(&hwbench).unwrap(); + // Throughput from all of the benchmarks should be converted to MiBs. + assert_eq!(serialized, "{\"cpu_hashrate_score\":1351,\"memory_memcpy_score\":9,\"disk_sequential_write_score\":4}"); } } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index ea908bf0336bf..a2d548f1fa5cd 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -54,6 +54,7 @@ sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } +sp-std = { version = "4.0.0", path = "../../../primitives/std" } sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } gethostname = "0.2.3" diff --git a/utils/frame/benchmarking-cli/src/machine/hardware.rs b/utils/frame/benchmarking-cli/src/machine/hardware.rs index 97960de99c4bf..50c88ec74646c 100644 --- a/utils/frame/benchmarking-cli/src/machine/hardware.rs +++ b/utils/frame/benchmarking-cli/src/machine/hardware.rs @@ -18,8 +18,40 @@ //! Contains types to define hardware requirements. use lazy_static::lazy_static; -use serde::{Deserialize, Serialize}; -use std::fmt; +use sc_sysinfo::Throughput; +use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; +use sp_std::{fmt, fmt::Formatter}; + +/// Serializes throughput into MiBs and represents it as `f64`. +fn serialize_throughput_as_f64(throughput: &Throughput, serializer: S) -> Result +where + S: Serializer, +{ + serializer.serialize_f64(throughput.as_mibs()) +} + +struct ThroughputVisitor; +impl<'de> Visitor<'de> for ThroughputVisitor { + type Value = Throughput; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("A value that is a f64.") + } + + fn visit_f64(self, value: f64) -> Result + where + E: serde::de::Error, + { + Ok(Throughput::from_mibs(value)) + } +} + +fn deserialize_throughput<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + Ok(deserializer.deserialize_f64(ThroughputVisitor))? +} lazy_static! { /// The hardware requirements as measured on reference hardware. @@ -45,6 +77,10 @@ pub struct Requirement { /// The metric to measure. pub metric: Metric, /// The minimal throughput that needs to be archived for this requirement. + #[serde( + serialize_with = "serialize_throughput_as_f64", + deserialize_with = "deserialize_throughput" + )] pub minimum: Throughput, } @@ -65,17 +101,6 @@ pub enum Metric { DiskRndWrite, } -/// Throughput as measured in bytes per second. -#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)] -pub enum Throughput { - /// KiB/s - KiBs(f64), - /// MiB/s - MiBs(f64), - /// GiB/s - GiBs(f64), -} - impl Metric { /// The category of the metric. pub fn category(&self) -> &'static str { @@ -98,70 +123,9 @@ impl Metric { } } -const KIBIBYTE: f64 = 1024.0; - -impl Throughput { - /// The unit of the metric. - pub fn unit(&self) -> &'static str { - match self { - Self::KiBs(_) => "KiB/s", - Self::MiBs(_) => "MiB/s", - Self::GiBs(_) => "GiB/s", - } - } - - /// [`Self`] as number of byte/s. - pub fn to_bs(&self) -> f64 { - self.to_kibs() * KIBIBYTE - } - - /// [`Self`] as number of kibibyte/s. - pub fn to_kibs(&self) -> f64 { - self.to_mibs() * KIBIBYTE - } - - /// [`Self`] as number of mebibyte/s. - pub fn to_mibs(&self) -> f64 { - self.to_gibs() * KIBIBYTE - } - - /// [`Self`] as number of gibibyte/s. - pub fn to_gibs(&self) -> f64 { - match self { - Self::KiBs(k) => *k / (KIBIBYTE * KIBIBYTE), - Self::MiBs(m) => *m / KIBIBYTE, - Self::GiBs(g) => *g, - } - } - - /// Normalizes [`Self`] to use the larges unit possible. - pub fn normalize(&self) -> Self { - let bs = self.to_bs(); - - if bs >= KIBIBYTE * KIBIBYTE * KIBIBYTE { - Self::GiBs(self.to_gibs()) - } else if bs >= KIBIBYTE * KIBIBYTE { - Self::MiBs(self.to_mibs()) - } else { - Self::KiBs(self.to_kibs()) - } - } -} - -impl fmt::Display for Throughput { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let normalized = self.normalize(); - match normalized { - Self::KiBs(s) | Self::MiBs(s) | Self::GiBs(s) => - write!(f, "{:.2?} {}", s, normalized.unit()), - } - } -} - #[cfg(test)] mod tests { use super::*; - use sp_runtime::assert_eq_error_rate_float; /// `SUBSTRATE_REFERENCE_HARDWARE` can be en- and decoded. #[test] @@ -171,21 +135,4 @@ mod tests { assert_eq!(decoded, SUBSTRATE_REFERENCE_HARDWARE.clone()); } - - /// Test the [`Throughput`]. - #[test] - fn throughput_works() { - /// Float precision. - const EPS: f64 = 0.1; - let gib = Throughput::GiBs(14.324); - - assert_eq_error_rate_float!(14.324, gib.to_gibs(), EPS); - assert_eq_error_rate_float!(14667.776, gib.to_mibs(), EPS); - assert_eq_error_rate_float!(14667.776 * 1024.0, gib.to_kibs(), EPS); - assert_eq!("14.32 GiB/s", gib.to_string()); - assert_eq!("14.32 GiB/s", gib.normalize().to_string()); - - let mib = Throughput::MiBs(1029.0); - assert_eq!("1.00 GiB/s", mib.to_string()); - } } diff --git a/utils/frame/benchmarking-cli/src/machine/mod.rs b/utils/frame/benchmarking-cli/src/machine/mod.rs index a19db671f3cd1..82b4e5be7358e 100644 --- a/utils/frame/benchmarking-cli/src/machine/mod.rs +++ b/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -30,11 +30,11 @@ use sc_cli::{CliConfiguration, Result, SharedParams}; use sc_service::Configuration; use sc_sysinfo::{ benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes, - benchmark_memory, benchmark_sr25519_verify, ExecutionLimit, + benchmark_memory, benchmark_sr25519_verify, ExecutionLimit, Throughput, }; use crate::shared::check_build_profile; -pub use hardware::{Metric, Requirement, Requirements, Throughput, SUBSTRATE_REFERENCE_HARDWARE}; +pub use hardware::{Metric, Requirement, Requirements, SUBSTRATE_REFERENCE_HARDWARE}; /// Command to benchmark the hardware. /// @@ -128,8 +128,9 @@ impl MachineCmd { /// Benchmarks a specific metric of the hardware and judges the resulting score. fn run_benchmark(&self, requirement: &Requirement, dir: &Path) -> Result { // Dispatch the concrete function from `sc-sysinfo`. + let score = self.measure(&requirement.metric, dir)?; - let rel_score = score.to_bs() / requirement.minimum.to_bs(); + let rel_score = score.as_bytes() / requirement.minimum.as_bytes(); // Sanity check if the result is off by factor >100x. if rel_score >= 100.0 || rel_score <= 0.01 { @@ -147,13 +148,11 @@ impl MachineCmd { let memory_limit = ExecutionLimit::from_secs_f32(self.memory_duration); let score = match metric { - Metric::Blake2256 => Throughput::MiBs(benchmark_cpu(hash_limit) as f64), - Metric::Sr25519Verify => Throughput::MiBs(benchmark_sr25519_verify(verify_limit)), - Metric::MemCopy => Throughput::MiBs(benchmark_memory(memory_limit) as f64), - Metric::DiskSeqWrite => - Throughput::MiBs(benchmark_disk_sequential_writes(disk_limit, dir)? as f64), - Metric::DiskRndWrite => - Throughput::MiBs(benchmark_disk_random_writes(disk_limit, dir)? as f64), + Metric::Blake2256 => benchmark_cpu(hash_limit), + Metric::Sr25519Verify => benchmark_sr25519_verify(verify_limit), + Metric::MemCopy => benchmark_memory(memory_limit), + Metric::DiskSeqWrite => benchmark_disk_sequential_writes(disk_limit, dir)?, + Metric::DiskRndWrite => benchmark_disk_random_writes(disk_limit, dir)?, }; Ok(score) } diff --git a/utils/frame/benchmarking-cli/src/machine/reference_hardware.json b/utils/frame/benchmarking-cli/src/machine/reference_hardware.json index 12645df8391e7..2a451d31403f1 100644 --- a/utils/frame/benchmarking-cli/src/machine/reference_hardware.json +++ b/utils/frame/benchmarking-cli/src/machine/reference_hardware.json @@ -1,32 +1,22 @@ [ { "metric": "Blake2256", - "minimum": { - "MiBs": 1029.0 - } + "minimum": 1029.0 }, { "metric": "Sr25519Verify", - "minimum": { - "KiBs": 666.0 - } + "minimum": 0.650391 }, { "metric": "MemCopy", - "minimum": { - "GiBs": 14.323 - } + "minimum": 14666.752 }, { "metric": "DiskSeqWrite", - "minimum": { - "MiBs": 450.0 - } + "minimum": 450.0 }, { "metric": "DiskRndWrite", - "minimum": { - "MiBs": 200.0 - } + "minimum": 200.0 } ] From 3cd6db7907bd0efc9e4299b168196d97651dfc25 Mon Sep 17 00:00:00 2001 From: shekohex Date: Sat, 5 Nov 2022 13:39:29 +0200 Subject: [PATCH 1340/1472] Bump `k256` from `0.10.4` to `0.11.4` (#12085) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump `k256` from `0.10.4` to `0.11.4` * Update Cargo.lock * Update Co-authored-by: Bastian Köcher Co-authored-by: Oliver Tale-Yazdi --- Cargo.lock | 75 +++++++++++++++++++++++----------------- frame/support/Cargo.toml | 2 +- 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48af2ffe4d88f..510161e225732 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1062,9 +1062,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" +checksum = "722e23542a15cea1f65d4a1419c4cfd7a26706c70871a13a04238ca3f40f1661" [[package]] name = "constant_time_eq" @@ -1379,9 +1379,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.3.2" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +checksum = "9f2b443d17d49dad5ef0ede301c3179cc923b8822f3393b4d2c28c269dd4a122" dependencies = [ "generic-array 0.14.4", "rand_core 0.6.2", @@ -1606,11 +1606,12 @@ dependencies = [ [[package]] name = "der" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" dependencies = [ "const-oid", + "zeroize", ] [[package]] @@ -1801,9 +1802,9 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.13.4" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +checksum = "85789ce7dfbd0f0624c07ef653a08bb2ebf43d3e16531361f46d36dd54334fed" dependencies = [ "der", "elliptic-curve", @@ -1856,13 +1857,14 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "elliptic-curve" -version = "0.11.12" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ "base16ct", "crypto-bigint", "der", + "digest 0.10.3", "ff", "generic-array 0.14.4", "group", @@ -2032,9 +2034,9 @@ dependencies = [ [[package]] name = "ff" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2958d04124b9f27f175eaeb9a9f383d026098aa837eadd8ba22c11f13a05b9e" +checksum = "df689201f395c6b90dfe87127685f8dbfc083a5e779e613575d8bd7314300c3e" dependencies = [ "rand_core 0.6.2", "subtle", @@ -2781,9 +2783,9 @@ dependencies = [ [[package]] name = "group" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +checksum = "7391856def869c1c81063a03457c676fbcd419709c3dfb33d8d319de484b154d" dependencies = [ "ff", "rand_core 0.6.2", @@ -2903,6 +2905,15 @@ dependencies = [ "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.3", +] + [[package]] name = "hmac-drbg" version = "0.3.0" @@ -3333,14 +3344,14 @@ dependencies = [ [[package]] name = "k256" -version = "0.10.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +checksum = "3636d281d46c3b64182eb3a0a42b7b483191a2ecc3f05301fa67403f7c9bc949" dependencies = [ "cfg-if 1.0.0", "ecdsa", "elliptic-curve", - "sec1", + "sha2 0.10.2", ] [[package]] @@ -6723,13 +6734,12 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs8" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ "der", "spki", - "zeroize", ] [[package]] @@ -7378,12 +7388,12 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +checksum = "88c86280f057430a52f4861551b092a01b419b8eacefc7c995eacb9dc132fe32" dependencies = [ "crypto-bigint", - "hmac 0.11.0", + "hmac 0.12.1", "zeroize", ] @@ -9004,10 +9014,11 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "sec1" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ + "base16ct", "der", "generic-array 0.14.4", "pkcs8", @@ -9264,11 +9275,11 @@ dependencies = [ [[package]] name = "signature" -version = "1.4.0" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +checksum = "deb766570a2825fa972bceff0d195727876a9cdf2460ab2e52d455dc2de47fd9" dependencies = [ - "digest 0.9.0", + "digest 0.10.3", "rand_core 0.6.2", ] @@ -10213,9 +10224,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spki" -version = "0.5.4" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", "der", @@ -12202,9 +12213,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.4.3" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" dependencies = [ "zeroize_derive", ] diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index be9cb1f1bf316..5af1dc26c1b49 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -37,7 +37,7 @@ impl-trait-for-tuples = "0.2.2" smallvec = "1.8.0" log = { version = "0.4.17", default-features = false } sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } -k256 = { version = "0.10.4", default-features = false, features = ["ecdsa"] } +k256 = { version = "0.11.5", default-features = false, features = ["ecdsa"] } [dev-dependencies] serde_json = "1.0.85" From cafbb668d2e57ede83f11f59d8bf291aa8d0c765 Mon Sep 17 00:00:00 2001 From: cheme Date: Sat, 5 Nov 2022 23:26:12 +0100 Subject: [PATCH 1341/1472] Guard some invalid node for proof decoding. (#12417) * Guard some invalid node for proof decoding. * only forbid bitmap with no children. * change format * scale error. * small test Co-authored-by: parity-processbot <> --- primitives/trie/src/lib.rs | 11 +++++++++++ primitives/trie/src/node_codec.rs | 9 +++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index f40ed4d9b53a5..5634d96d58356 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -986,4 +986,15 @@ mod tests { assert_eq!(first_storage_root, second_storage_root); } + + #[test] + fn node_with_no_children_fail_decoding() { + let branch = NodeCodec::::branch_node_nibbled( + b"some_partial".iter().copied(), + 24, + vec![None; 16].into_iter(), + Some(trie_db::node::Value::Inline(b"value"[..].into())), + ); + assert!(NodeCodec::::decode(branch.as_slice()).is_err()); + } } diff --git a/primitives/trie/src/node_codec.rs b/primitives/trie/src/node_codec.rs index 4b3e69adb7041..0202b1c6ba7d2 100644 --- a/primitives/trie/src/node_codec.rs +++ b/primitives/trie/src/node_codec.rs @@ -304,8 +304,13 @@ const BITMAP_LENGTH: usize = 2; pub(crate) struct Bitmap(u16); impl Bitmap { - pub fn decode(mut data: &[u8]) -> Result { - Ok(Bitmap(u16::decode(&mut data)?)) + pub fn decode(data: &[u8]) -> Result { + let value = u16::decode(&mut &data[..])?; + if value == 0 { + Err("Bitmap without a child.".into()) + } else { + Ok(Bitmap(value)) + } } pub fn value_at(&self, i: usize) -> bool { From 30b7e62e3b00cc7b6eaaa9548c8936c3b8b6e3d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Nov 2022 10:17:53 +0000 Subject: [PATCH 1342/1472] Bump regex from 1.5.5 to 1.6.0 (#12117) Bumps [regex](https://github.com/rust-lang/regex) from 1.5.5 to 1.6.0. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.5.5...1.6.0) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: parity-processbot <> --- bin/node/cli/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/panic-handler/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 07208abdd089b..ffd40aac1caa0 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -125,7 +125,7 @@ tempfile = "3.1.0" assert_cmd = "2.0.2" nix = "0.23" serde_json = "1.0" -regex = "1.5.5" +regex = "1.6.0" platforms = "2.0" async-std = { version = "1.11.0", features = ["attributes"] } soketto = "0.7.1" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 04824859ce8ab..f749b9b5b0c4a 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -23,7 +23,7 @@ log = "0.4.17" names = { version = "0.13.0", default-features = false } parity-scale-codec = "3.0.0" rand = "0.7.3" -regex = "1.5.5" +regex = "1.6.0" rpassword = "7.0.0" serde = "1.0.136" serde_json = "1.0.85" diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 264db0e89b1c8..bda2992392707 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -47,7 +47,7 @@ sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/may sc-tracing = { version = "4.0.0-dev", path = "../tracing" } tracing-subscriber = "0.2.19" paste = "1.0" -regex = "1.5.5" +regex = "1.6.0" criterion = "0.3" env_logger = "0.9" num_cpus = "1.13.1" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 8bc5d770c9c5a..43fa2d4e52e8a 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -21,7 +21,7 @@ libc = "0.2.121" log = { version = "0.4.17" } once_cell = "1.8.0" parking_lot = "0.12.1" -regex = "1.5.5" +regex = "1.6.0" rustc-hash = "1.1.0" serde = "1.0.136" thiserror = "1.0.30" diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index dcb61b33f347f..12cc9e2f0b60f 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -30,7 +30,7 @@ base58 = { version = "0.2.0", optional = true } rand = { version = "0.7.3", optional = true, features = ["small_rng"] } substrate-bip39 = { version = "0.4.4", optional = true } tiny-bip39 = { version = "0.8.2", optional = true } -regex = { version = "1.5.4", optional = true } +regex = { version = "1.6.0", optional = true } num-traits = { version = "0.2.8", default-features = false } zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml index bd429fd0e8af7..19f76dddbab22 100644 --- a/primitives/panic-handler/Cargo.toml +++ b/primitives/panic-handler/Cargo.toml @@ -16,4 +16,4 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] backtrace = "0.3.64" lazy_static = "1.4.0" -regex = "1.5.5" +regex = "1.6.0" From 409e6f9044f320d70f68fde11274b76ab0228c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 7 Nov 2022 14:01:23 +0100 Subject: [PATCH 1343/1472] Make `--db` case insensitive again (#12630) This was broken in the switch to Clap v4. --- client/cli/src/params/database_params.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cli/src/params/database_params.rs b/client/cli/src/params/database_params.rs index 3c9ae09e9ab42..fdd3622580a6d 100644 --- a/client/cli/src/params/database_params.rs +++ b/client/cli/src/params/database_params.rs @@ -23,7 +23,7 @@ use clap::Args; #[derive(Debug, Clone, PartialEq, Args)] pub struct DatabaseParams { /// Select database backend to use. - #[arg(long, alias = "db", value_name = "DB", value_enum)] + #[arg(long, alias = "db", value_name = "DB", ignore_case = true, value_enum)] pub database: Option, /// Limit the memory the database cache can use. From 247ff88c4ff1f7242c66487f00ad5117ae3e1ee7 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 7 Nov 2022 21:12:26 +0100 Subject: [PATCH 1344/1472] txpool: enactment state forced update (#12632) * txpool: enactment state forced update When `tree_route` computation fails, we still need to update the `enactment_state` to be aligned with last known finalized/best block. We do not execute enactment phase of maintain procedure, but we do update the state. * error -> debug * test added --- .../transaction-pool/src/enactment_state.rs | 28 +++++++++++++++++++ client/transaction-pool/src/lib.rs | 4 +-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/client/transaction-pool/src/enactment_state.rs b/client/transaction-pool/src/enactment_state.rs index 242b557dfbbbd..b347de824fa12 100644 --- a/client/transaction-pool/src/enactment_state.rs +++ b/client/transaction-pool/src/enactment_state.rs @@ -134,6 +134,16 @@ where Ok(Some(tree_route)) } + + /// Forces update of the state according to the given `ChainEvent`. Intended to be used as a + /// fallback when tree_route cannot be computed. + pub fn force_update(&mut self, event: &ChainEvent) { + match event { + ChainEvent::NewBestBlock { hash, .. } => self.recent_best_block = *hash, + ChainEvent::Finalized { hash, .. } => self.recent_finalized_block = *hash, + }; + log::debug!(target: "txpool", "forced update: {:?}, {:?}", self.recent_best_block, self.recent_finalized_block); + } } #[cfg(test)] @@ -576,4 +586,22 @@ mod enactment_state_tests { assert_eq!(result, false); assert_es_eq(&es, e1(), d1()); } + + #[test] + fn test_enactment_forced_update_best_block() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + es.force_update(&ChainEvent::NewBestBlock { hash: b1().hash, tree_route: None }); + assert_es_eq(&es, b1(), a()); + } + + #[test] + fn test_enactment_forced_update_finalize() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + es.force_update(&ChainEvent::Finalized { hash: b1().hash, tree_route: Arc::from([]) }); + assert_es_eq(&es, a(), b1()); + } } diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 9e0a2e74bf421..e66c780a5ed8f 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -748,8 +748,8 @@ where match result { Err(msg) => { - log::warn!(target: "txpool", "{msg}"); - return + log::debug!(target: "txpool", "{msg}"); + self.enactment_state.lock().force_update(&event); }, Ok(None) => {}, Ok(Some(tree_route)) => { From ee9c3859c6a1644419f5472aaec432bd7f9d66a0 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 7 Nov 2022 16:40:55 -0500 Subject: [PATCH 1345/1472] Add pallet dev mode (#12536) * stub for construct_dev_runtime! * revert * stub for dev_mode proc macro * preliminary docs for pallet::dev_mode (attribute) proc macro * add dev_mode to pallet_macros module * add docs item for dev_mode to frame_support * parsing of #[pallet(dev_mode)] * strip out dev_mode stub since it will be an arg for pallet instead * make pallet Def struct aware of dev mode * WIP * revert changes to call.rs * pass dev_mode to pallet parsing code * auto-specify default weights when in dev mode if not specified * add proof / expect for syn::parse in dev mode weight processing * set all storages to unbounded when in dev mode * just use 0 Co-authored-by: Shawn Tabrizi * add invalid pallet arg test * add passing dev mode pallet test * add test confirming that dev mode features only work in dev mode * cargo fmt + clean up * bump CI * fix pallet ui test * add docs for dev mode * add warning about using dev mode in production circumstances * remove comment about no other attributes being supported * fix unneeded assignment * make warning more explicit * more explicit warning about using dev mode in production * simpler assignment for dev_mode boolean Co-authored-by: Oliver Tale-Yazdi * add note about MEL requirement Co-authored-by: Oliver Tale-Yazdi * add comment specifying why weights can be omitted in example Co-authored-by: Oliver Tale-Yazdi * tweak wording of comments * bump ci Co-authored-by: Shawn Tabrizi Co-authored-by: Oliver Tale-Yazdi --- frame/support/procedural/src/lib.rs | 28 +++++++++++++++ frame/support/procedural/src/pallet/mod.rs | 22 ++++++++---- .../procedural/src/pallet/parse/call.rs | 9 +++++ .../procedural/src/pallet/parse/mod.rs | 8 +++-- .../procedural/src/pallet/parse/storage.rs | 5 ++- frame/support/src/lib.rs | 30 ++++++++++++++++ .../tests/pallet_ui/attr_non_empty.stderr | 4 +-- .../tests/pallet_ui/dev_mode_without_arg.rs | 33 +++++++++++++++++ .../pallet_ui/dev_mode_without_arg.stderr | 11 ++++++ .../dev_mode_without_arg_max_encoded_len.rs | 34 ++++++++++++++++++ ...ev_mode_without_arg_max_encoded_len.stderr | 17 +++++++++ .../tests/pallet_ui/pallet_invalid_arg.rs | 4 +++ .../tests/pallet_ui/pallet_invalid_arg.stderr | 5 +++ .../tests/pallet_ui/pass/dev_mode_valid.rs | 35 +++++++++++++++++++ 14 files changed, 233 insertions(+), 12 deletions(-) create mode 100644 frame/support/test/tests/pallet_ui/dev_mode_without_arg.rs create mode 100644 frame/support/test/tests/pallet_ui/dev_mode_without_arg.stderr create mode 100644 frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs create mode 100644 frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr create mode 100644 frame/support/test/tests/pallet_ui/pallet_invalid_arg.rs create mode 100644 frame/support/test/tests/pallet_ui/pallet_invalid_arg.stderr create mode 100644 frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index ccff5488c93be..cd30946ae7855 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -445,6 +445,34 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { /// pallet. Otherwise it implements `StorageInfoTrait` for the pallet using the /// `PartialStorageInfoTrait` implementation of storages. /// +/// ## Dev Mode (`#[pallet(dev_mode)]`) +/// +/// Specifying the argument `dev_mode` will allow you to enable dev mode for a pallet. The aim +/// of dev mode is to loosen some of the restrictions and requirements placed on production +/// pallets for easy tinkering and development. Dev mode pallets should not be used in +/// production. Enabling dev mode has the following effects: +/// +/// * Weights no longer need to be specified on every `#[pallet::call]` declaration. By default, dev +/// mode pallets will assume a weight of zero (`0`) if a weight is not specified. This is +/// equivalent to specifying `#[weight(0)]` on all calls that do not specify a weight. +/// * All storages are marked as unbounded, meaning you do not need to implement `MaxEncodedLen` on +/// storage types. This is equivalent to specifying `#[pallet::unbounded]` on all storage type +/// definitions. +/// +/// Note that the `dev_mode` argument can only be supplied to the `#[pallet]` or +/// `#[frame_support::pallet]` attribute macro that encloses your pallet module. This argument +/// cannot be specified anywhere else, including but not limited to the `#[pallet::pallet]` +/// attribute macro. +/// +///

+/// WARNING:
+/// You should not deploy or use dev mode pallets in production. Doing so can break your chain
+/// and therefore should never be done. Once you are done tinkering, you should remove the
+/// 'dev_mode' argument from your #[pallet] declaration and fix any compile errors before
+/// attempting to use your pallet in a production scenario.
+/// 
+/// /// See `frame_support::pallet` docs for more info. #[proc_macro_attribute] pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream { diff --git a/frame/support/procedural/src/pallet/mod.rs b/frame/support/procedural/src/pallet/mod.rs index ff9f122867746..3f85be81c1f7d 100644 --- a/frame/support/procedural/src/pallet/mod.rs +++ b/frame/support/procedural/src/pallet/mod.rs @@ -31,20 +31,30 @@ mod parse; pub use parse::Def; use syn::spanned::Spanned; +mod keyword { + syn::custom_keyword!(dev_mode); +} + pub fn pallet( attr: proc_macro::TokenStream, item: proc_macro::TokenStream, ) -> proc_macro::TokenStream { + let mut dev_mode = false; if !attr.is_empty() { - let msg = - "Invalid pallet macro call: expected no attributes, e.g. macro call must be just \ - `#[frame_support::pallet]` or `#[pallet]`"; - let span = proc_macro2::TokenStream::from(attr).span(); - return syn::Error::new(span, msg).to_compile_error().into() + if let Ok(_) = syn::parse::(attr.clone()) { + dev_mode = true; + } else { + let msg = "Invalid pallet macro call: unexpected attribute. Macro call must be \ + bare, such as `#[frame_support::pallet]` or `#[pallet]`, or must specify the \ + `dev_mode` attribute, such as `#[frame_support::pallet(dev_mode)]` or \ + #[pallet(dev_mode)]."; + let span = proc_macro2::TokenStream::from(attr).span(); + return syn::Error::new(span, msg).to_compile_error().into() + } } let item = syn::parse_macro_input!(item as syn::ItemMod); - match parse::Def::try_from(item) { + match parse::Def::try_from(item, dev_mode) { Ok(def) => expand::expand(def).into(), Err(e) => e.to_compile_error().into(), } diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index f7b2c9544d831..fbca9a52c767c 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -144,6 +144,7 @@ impl CallDef { attr_span: proc_macro2::Span, index: usize, item: &mut syn::Item, + dev_mode: bool, ) -> syn::Result { let item_impl = if let syn::Item::Impl(item) = item { item @@ -213,6 +214,14 @@ impl CallDef { }, ); + if weight_attrs.is_empty() && dev_mode { + // inject a default O(1) weight when dev mode is enabled and no weight has + // been specified on the call + let empty_weight: syn::Expr = syn::parse(quote::quote!(0).into()) + .expect("we are parsing a quoted string; qed"); + weight_attrs.push(FunctionAttr::Weight(empty_weight)); + } + if weight_attrs.len() != 1 { let msg = if weight_attrs.is_empty() { "Invalid pallet::call, requires weight attribute i.e. `#[pallet::weight($expr)]`" diff --git a/frame/support/procedural/src/pallet/parse/mod.rs b/frame/support/procedural/src/pallet/parse/mod.rs index 8b4ab154b306a..f91159248281c 100644 --- a/frame/support/procedural/src/pallet/parse/mod.rs +++ b/frame/support/procedural/src/pallet/parse/mod.rs @@ -59,10 +59,11 @@ pub struct Def { pub type_values: Vec, pub frame_system: syn::Ident, pub frame_support: syn::Ident, + pub dev_mode: bool, } impl Def { - pub fn try_from(mut item: syn::ItemMod) -> syn::Result { + pub fn try_from(mut item: syn::ItemMod, dev_mode: bool) -> syn::Result { let frame_system = generate_crate_access_2018("frame-system")?; let frame_support = generate_crate_access_2018("frame-support")?; @@ -106,7 +107,7 @@ impl Def { hooks = Some(m); }, Some(PalletAttr::RuntimeCall(span)) if call.is_none() => - call = Some(call::CallDef::try_from(span, index, item)?), + call = Some(call::CallDef::try_from(span, index, item, dev_mode)?), Some(PalletAttr::Error(span)) if error.is_none() => error = Some(error::ErrorDef::try_from(span, index, item)?), Some(PalletAttr::RuntimeEvent(span)) if event.is_none() => @@ -124,7 +125,7 @@ impl Def { Some(PalletAttr::Inherent(_)) if inherent.is_none() => inherent = Some(inherent::InherentDef::try_from(index, item)?), Some(PalletAttr::Storage(span)) => - storages.push(storage::StorageDef::try_from(span, index, item)?), + storages.push(storage::StorageDef::try_from(span, index, item, dev_mode)?), Some(PalletAttr::ValidateUnsigned(_)) if validate_unsigned.is_none() => { let v = validate_unsigned::ValidateUnsignedDef::try_from(index, item)?; validate_unsigned = Some(v); @@ -173,6 +174,7 @@ impl Def { type_values, frame_system, frame_support, + dev_mode, }; def.check_instance_usage()?; diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index b16ff05803d98..8b551ab31d6c3 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -678,6 +678,7 @@ impl StorageDef { attr_span: proc_macro2::Span, index: usize, item: &mut syn::Item, + dev_mode: bool, ) -> syn::Result { let item = if let syn::Item::Type(item) = item { item @@ -686,9 +687,11 @@ impl StorageDef { }; let attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; - let PalletStorageAttrInfo { getter, rename_as, unbounded, whitelisted } = + let PalletStorageAttrInfo { getter, rename_as, mut unbounded, whitelisted } = PalletStorageAttrInfo::from_attrs(attrs)?; + // set all storages to be unbounded if dev_mode is enabled + unbounded |= dev_mode; let cfg_attrs = helper::get_item_cfg_attrs(&item.attrs); let instances = vec![helper::check_type_def_gen(&item.generics, item.ident.span())?]; diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 9b0ee84c34d8a..84e416e50544d 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1487,6 +1487,36 @@ pub mod pallet_prelude { /// non-instantiable pallets. For an example of an instantiable pallet, see [this /// example](#example-of-an-instantiable-pallet). /// +/// # Dev Mode (`#[pallet(dev_mode)]`) +/// +/// Specifying the argument `dev_mode` on the `#[pallet]` or `#[frame_support::pallet]` +/// attribute attached to your pallet module will allow you to enable dev mode for a pallet. +/// The aim of dev mode is to loosen some of the restrictions and requirements placed on +/// production pallets for easy tinkering and development. Dev mode pallets should not be used +/// in production. Enabling dev mode has the following effects: +/// +/// * Weights no longer need to be specified on every `#[pallet::call]` declaration. By +/// default, dev mode pallets will assume a weight of zero (`0`) if a weight is not +/// specified. This is equivalent to specifying `#[weight(0)]` on all calls that do not +/// specify a weight. +/// * All storages are marked as unbounded, meaning you do not need to implement +/// `MaxEncodedLen` on storage types. This is equivalent to specifying `#[pallet::unbounded]` +/// on all storage type definitions. +/// +/// Note that the `dev_mode` argument can only be supplied to the `#[pallet]` or +/// `#[frame_support::pallet]` attribute macro that encloses your pallet module. This argument +/// cannot be specified anywhere else, including but not limited to the `#[pallet::pallet]` +/// attribute macro. +/// +///
+/// WARNING:
+/// You should not deploy or use dev mode pallets in production. Doing so can break your chain
+/// and therefore should never be done. Once you are done tinkering, you should remove the
+/// 'dev_mode' argument from your #[pallet] declaration and fix any compile errors before
+/// attempting to use your pallet in a production scenario.
+/// 
+/// /// # Pallet struct placeholder: `#[pallet::pallet]` (mandatory) /// /// The pallet struct placeholder `#[pallet::pallet]` is mandatory and allows you to specify diff --git a/frame/support/test/tests/pallet_ui/attr_non_empty.stderr b/frame/support/test/tests/pallet_ui/attr_non_empty.stderr index 144af5a17ea5c..9eac5de35db80 100644 --- a/frame/support/test/tests/pallet_ui/attr_non_empty.stderr +++ b/frame/support/test/tests/pallet_ui/attr_non_empty.stderr @@ -1,5 +1,5 @@ -error: Invalid pallet macro call: expected no attributes, e.g. macro call must be just `#[frame_support::pallet]` or `#[pallet]` - --> $DIR/attr_non_empty.rs:1:26 +error: Invalid pallet macro call: unexpected attribute. Macro call must be bare, such as `#[frame_support::pallet]` or `#[pallet]`, or must specify the `dev_mode` attribute, such as `#[frame_support::pallet(dev_mode)]` or #[pallet(dev_mode)]. + --> tests/pallet_ui/attr_non_empty.rs:1:26 | 1 | #[frame_support::pallet [foo]] | ^^^ diff --git a/frame/support/test/tests/pallet_ui/dev_mode_without_arg.rs b/frame/support/test/tests/pallet_ui/dev_mode_without_arg.rs new file mode 100644 index 0000000000000..f044ae6d7878f --- /dev/null +++ b/frame/support/test/tests/pallet_ui/dev_mode_without_arg.rs @@ -0,0 +1,33 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + // The struct on which we build all of our Pallet logic. + #[pallet::pallet] + pub struct Pallet(_); + + // Your Pallet's configuration trait, representing custom external types and interfaces. + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::storage] + type MyStorage = StorageValue<_, Vec>; + + // Your Pallet's callable functions. + #[pallet::call] + impl Pallet { + pub fn my_call(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + } + + // Your Pallet's internal functions. + impl Pallet {} +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/dev_mode_without_arg.stderr b/frame/support/test/tests/pallet_ui/dev_mode_without_arg.stderr new file mode 100644 index 0000000000000..fac7fd77df9ae --- /dev/null +++ b/frame/support/test/tests/pallet_ui/dev_mode_without_arg.stderr @@ -0,0 +1,11 @@ +error: Invalid pallet::call, requires weight attribute i.e. `#[pallet::weight($expr)]` + --> tests/pallet_ui/dev_mode_without_arg.rs:24:7 + | +24 | pub fn my_call(_origin: OriginFor) -> DispatchResult { + | ^^ + +error[E0432]: unresolved import `pallet` + --> tests/pallet_ui/dev_mode_without_arg.rs:3:9 + | +3 | pub use pallet::*; + | ^^^^^^ help: a similar path exists: `test_pallet::pallet` diff --git a/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs new file mode 100644 index 0000000000000..f6efcc3fc3d72 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs @@ -0,0 +1,34 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + // The struct on which we build all of our Pallet logic. + #[pallet::pallet] + pub struct Pallet(_); + + // Your Pallet's configuration trait, representing custom external types and interfaces. + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::storage] + type MyStorage = StorageValue<_, Vec>; + + // Your Pallet's callable functions. + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + pub fn my_call(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + } + + // Your Pallet's internal functions. + impl Pallet {} +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr new file mode 100644 index 0000000000000..2f8d0cc761ab2 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `Vec: MaxEncodedLen` is not satisfied + --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:11:12 + | +11 | #[pallet::pallet] + | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Vec` + | + = help: the following other types implement trait `MaxEncodedLen`: + () + (TupleElement0, TupleElement1) + (TupleElement0, TupleElement1, TupleElement2) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) + and 78 others + = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageMyStorage, Vec>` diff --git a/frame/support/test/tests/pallet_ui/pallet_invalid_arg.rs b/frame/support/test/tests/pallet_ui/pallet_invalid_arg.rs new file mode 100644 index 0000000000000..1fc42f6511cfa --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pallet_invalid_arg.rs @@ -0,0 +1,4 @@ +#[frame_support::pallet(foo)] +pub mod pallet {} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/pallet_invalid_arg.stderr b/frame/support/test/tests/pallet_ui/pallet_invalid_arg.stderr new file mode 100644 index 0000000000000..234dc07f2ece3 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pallet_invalid_arg.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet macro call: unexpected attribute. Macro call must be bare, such as `#[frame_support::pallet]` or `#[pallet]`, or must specify the `dev_mode` attribute, such as `#[frame_support::pallet(dev_mode)]` or #[pallet(dev_mode)]. + --> tests/pallet_ui/pallet_invalid_arg.rs:1:25 + | +1 | #[frame_support::pallet(foo)] + | ^^^ diff --git a/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs b/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs new file mode 100644 index 0000000000000..97e0d585d0ce9 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs @@ -0,0 +1,35 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + // The struct on which we build all of our Pallet logic. + #[pallet::pallet] + pub struct Pallet(_); + + // Your Pallet's configuration trait, representing custom external types and interfaces. + #[pallet::config] + pub trait Config: frame_system::Config {} + + // The MEL requirement for bounded pallets is skipped by `dev_mode`. + #[pallet::storage] + type MyStorage = StorageValue<_, Vec>; + + // Your Pallet's callable functions. + #[pallet::call] + impl Pallet { + // No need to define a `weight` attribute here because of `dev_mode`. + pub fn my_call(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + } + + // Your Pallet's internal functions. + impl Pallet {} +} + +fn main() {} From 3a450ffe936d5c2e5dc1208abecd11cc71aefcbe Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 7 Nov 2022 22:42:16 +0100 Subject: [PATCH 1346/1472] BlockId removal: &Hash to Hash (#12626) It changes &Block::Hash argument to Block::Hash. This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) --- bin/node/bench/src/import.rs | 2 +- bin/node/inspect/src/lib.rs | 4 +- client/api/src/backend.rs | 38 +-- client/api/src/client.rs | 11 +- client/api/src/in_mem.rs | 52 +-- client/api/src/proof_provider.rs | 10 +- .../basic-authorship/src/basic_authorship.rs | 2 +- .../incoming_requests_handler.rs | 2 +- client/beefy/src/tests.rs | 26 +- client/beefy/src/worker.rs | 16 +- client/block-builder/src/lib.rs | 2 +- client/cli/src/commands/export_state_cmd.rs | 2 +- client/consensus/babe/src/tests.rs | 10 +- .../manual-seal/src/finalize_block.rs | 2 +- client/db/benches/state_access.rs | 12 +- client/db/src/lib.rs | 300 +++++++++--------- client/finality-grandpa/src/environment.rs | 2 +- client/finality-grandpa/src/finality_proof.rs | 6 +- client/finality-grandpa/src/import.rs | 6 +- client/finality-grandpa/src/tests.rs | 14 +- client/finality-grandpa/src/warp_proof.rs | 4 +- client/network/bitswap/src/lib.rs | 2 +- .../src/light_client_requests/handler.rs | 6 +- .../network/sync/src/block_request_handler.rs | 6 +- client/network/sync/src/lib.rs | 4 +- .../network/sync/src/state_request_handler.rs | 4 +- client/network/test/src/block_import.rs | 2 +- client/network/test/src/lib.rs | 14 +- client/network/test/src/sync.rs | 81 +++-- client/rpc/src/chain/tests.rs | 4 +- client/rpc/src/state/state_full.rs | 32 +- .../service/src/chain_ops/export_raw_state.rs | 2 +- client/service/src/client/call_executor.rs | 8 +- client/service/src/client/client.rs | 79 +++-- client/service/test/src/client/mod.rs | 42 +-- client/tracing/src/block/mod.rs | 2 +- client/transaction-pool/benches/basics.rs | 2 +- client/transaction-pool/src/api.rs | 2 +- client/transaction-pool/src/graph/pool.rs | 2 +- client/transaction-pool/src/lib.rs | 12 +- client/transaction-pool/src/tests.rs | 2 +- primitives/blockchain/src/backend.rs | 10 +- test-utils/client/src/client_ext.rs | 4 +- .../runtime/transaction-pool/src/lib.rs | 4 +- .../frame/benchmarking-cli/src/block/bench.rs | 2 +- .../frame/benchmarking-cli/src/storage/cmd.rs | 4 +- .../benchmarking-cli/src/storage/read.rs | 8 +- .../benchmarking-cli/src/storage/write.rs | 4 +- .../rpc/state-trie-migration-rpc/src/lib.rs | 2 +- 49 files changed, 428 insertions(+), 441 deletions(-) diff --git a/bin/node/bench/src/import.rs b/bin/node/bench/src/import.rs index 26f9391800ceb..28a322834271c 100644 --- a/bin/node/bench/src/import.rs +++ b/bin/node/bench/src/import.rs @@ -135,7 +135,7 @@ impl core::Benchmark for ImportBenchmark { // Sanity checks. context .client - .state_at(&hash) + .state_at(hash) .expect("state_at failed for block#1") .inspect_state(|| { match self.block_type { diff --git a/bin/node/inspect/src/lib.rs b/bin/node/inspect/src/lib.rs index 1e44cec914995..528dce14f46a5 100644 --- a/bin/node/inspect/src/lib.rs +++ b/bin/node/inspect/src/lib.rs @@ -144,7 +144,7 @@ impl> Inspector let not_found = format!("Could not find block {:?}", id); let body = self .chain - .block_body(&hash)? + .block_body(hash)? .ok_or_else(|| Error::NotFound(not_found.clone()))?; let header = self.chain.header(id)?.ok_or_else(|| Error::NotFound(not_found.clone()))?; @@ -155,7 +155,7 @@ impl> Inspector let not_found = format!("Could not find block {:?}", id); let body = self .chain - .block_body(&hash)? + .block_body(hash)? .ok_or_else(|| Error::NotFound(not_found.clone()))?; let header = self.chain.header(id)?.ok_or_else(|| Error::NotFound(not_found.clone()))?; diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index df9c92b626ecc..79cc0d7a16bcc 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -215,13 +215,13 @@ pub trait BlockImportOperation { /// Mark a block as finalized. fn mark_finalized( &mut self, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, ) -> sp_blockchain::Result<()>; /// Mark a block as new head. If both block import and set head are specified, set head /// overrides block import's best block rule. - fn mark_head(&mut self, hash: &Block::Hash) -> sp_blockchain::Result<()>; + fn mark_head(&mut self, hash: Block::Hash) -> sp_blockchain::Result<()>; /// Add a transaction index operation. fn update_transaction_index(&mut self, index: Vec) @@ -251,7 +251,7 @@ pub trait Finalizer> { fn apply_finality( &self, operation: &mut ClientImportOperation, - block: &Block::Hash, + block: Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()>; @@ -271,7 +271,7 @@ pub trait Finalizer> { /// while performing major synchronization work. fn finalize_block( &self, - block: &Block::Hash, + block: Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()>; @@ -359,21 +359,21 @@ pub trait StorageProvider> { /// Given a block's `Hash` and a key, return the value under the key in that block. fn storage( &self, - hash: &Block::Hash, + hash: Block::Hash, key: &StorageKey, ) -> sp_blockchain::Result>; /// Given a block's `Hash` and a key prefix, return the matching storage keys in that block. fn storage_keys( &self, - hash: &Block::Hash, + hash: Block::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result>; /// Given a block's `Hash` and a key, return the value under the hash in that block. fn storage_hash( &self, - hash: &Block::Hash, + hash: Block::Hash, key: &StorageKey, ) -> sp_blockchain::Result>; @@ -381,7 +381,7 @@ pub trait StorageProvider> { /// in that block. fn storage_pairs( &self, - hash: &Block::Hash, + hash: Block::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result>; @@ -389,7 +389,7 @@ pub trait StorageProvider> { /// keys in that block. fn storage_keys_iter<'a>( &self, - hash: &Block::Hash, + hash: Block::Hash, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result>; @@ -398,7 +398,7 @@ pub trait StorageProvider> { /// that block. fn child_storage( &self, - hash: &Block::Hash, + hash: Block::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result>; @@ -407,7 +407,7 @@ pub trait StorageProvider> { /// storage keys. fn child_storage_keys( &self, - hash: &Block::Hash, + hash: Block::Hash, child_info: &ChildInfo, key_prefix: &StorageKey, ) -> sp_blockchain::Result>; @@ -416,7 +416,7 @@ pub trait StorageProvider> { /// return a `KeyIterator` that iterates matching storage keys in that block. fn child_storage_keys_iter<'a>( &self, - hash: &Block::Hash, + hash: Block::Hash, child_info: ChildInfo, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, @@ -426,7 +426,7 @@ pub trait StorageProvider> { /// block. fn child_storage_hash( &self, - hash: &Block::Hash, + hash: Block::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result>; @@ -466,7 +466,7 @@ pub trait Backend: AuxStore + Send + Sync { fn begin_state_operation( &self, operation: &mut Self::BlockImportOperation, - block: &Block::Hash, + block: Block::Hash, ) -> sp_blockchain::Result<()>; /// Commit block insertion. @@ -480,7 +480,7 @@ pub trait Backend: AuxStore + Send + Sync { /// This should only be called if the parent of the given block has been finalized. fn finalize_block( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, ) -> sp_blockchain::Result<()>; @@ -489,7 +489,7 @@ pub trait Backend: AuxStore + Send + Sync { /// This should only be called for blocks that are already finalized. fn append_justification( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Justification, ) -> sp_blockchain::Result<()>; @@ -503,12 +503,12 @@ pub trait Backend: AuxStore + Send + Sync { fn offchain_storage(&self) -> Option; /// Returns true if state for given block is available. - fn have_state_at(&self, hash: &Block::Hash, _number: NumberFor) -> bool { + fn have_state_at(&self, hash: Block::Hash, _number: NumberFor) -> bool { self.state_at(hash).is_ok() } /// Returns state backend with post-state of given block. - fn state_at(&self, hash: &Block::Hash) -> sp_blockchain::Result; + fn state_at(&self, hash: Block::Hash) -> sp_blockchain::Result; /// Attempts to revert the chain by `n` blocks. If `revert_finalized` is set it will attempt to /// revert past any finalized block, this is unsafe and can potentially leave the node in an @@ -524,7 +524,7 @@ pub trait Backend: AuxStore + Send + Sync { ) -> sp_blockchain::Result<(NumberFor, HashSet)>; /// Discard non-best, unfinalized leaf block. - fn remove_leaf_block(&self, hash: &Block::Hash) -> sp_blockchain::Result<()>; + fn remove_leaf_block(&self, hash: Block::Hash) -> sp_blockchain::Result<()>; /// Insert auxiliary data into key-value store. fn insert_aux< diff --git a/client/api/src/client.rs b/client/api/src/client.rs index a07198abfe8d6..bb88853d23afb 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -110,7 +110,7 @@ pub trait BlockBackend { /// Get block body by ID. Returns `None` if the body is not stored. fn block_body( &self, - hash: &Block::Hash, + hash: Block::Hash, ) -> sp_blockchain::Result::Extrinsic>>>; /// Get all indexed transactions for a block, @@ -118,8 +118,7 @@ pub trait BlockBackend { /// /// Note that this will only fetch transactions /// that are indexed by the runtime with `storage_index_transaction`. - fn block_indexed_body(&self, hash: &Block::Hash) - -> sp_blockchain::Result>>>; + fn block_indexed_body(&self, hash: Block::Hash) -> sp_blockchain::Result>>>; /// Get full block by id. fn block(&self, id: &BlockId) -> sp_blockchain::Result>>; @@ -129,7 +128,7 @@ pub trait BlockBackend { -> sp_blockchain::Result; /// Get block justifications for the block with the given id. - fn justifications(&self, hash: &Block::Hash) -> sp_blockchain::Result>; + fn justifications(&self, hash: Block::Hash) -> sp_blockchain::Result>; /// Get block hash by number. fn block_hash(&self, number: NumberFor) -> sp_blockchain::Result>; @@ -138,10 +137,10 @@ pub trait BlockBackend { /// /// Note that this will only fetch transactions /// that are indexed by the runtime with `storage_index_transaction`. - fn indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result>>; + fn indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result>>; /// Check if transaction index exists. - fn has_indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result { + fn has_indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result { Ok(self.indexed_transaction(hash)?.is_some()) } diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 26364f28acca2..5a3e25ab5987b 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -271,16 +271,16 @@ impl Blockchain { fn finalize_header( &self, - block: &Block::Hash, + block: Block::Hash, justification: Option, ) -> sp_blockchain::Result<()> { let mut storage = self.storage.write(); - storage.finalized_hash = *block; + storage.finalized_hash = block; if justification.is_some() { let block = storage .blocks - .get_mut(block) + .get_mut(&block) .expect("hash was fetched from a block in the db; qed"); let block_justifications = match block { @@ -295,7 +295,7 @@ impl Blockchain { fn append_justification( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Justification, ) -> sp_blockchain::Result<()> { let mut storage = self.storage.write(); @@ -405,17 +405,17 @@ impl HeaderMetadata for Blockchain { impl blockchain::Backend for Blockchain { fn body( &self, - hash: &Block::Hash, + hash: Block::Hash, ) -> sp_blockchain::Result::Extrinsic>>> { Ok(self .storage .read() .blocks - .get(hash) + .get(&hash) .and_then(|b| b.extrinsics().map(|x| x.to_vec()))) } - fn justifications(&self, hash: &Block::Hash) -> sp_blockchain::Result> { + fn justifications(&self, hash: Block::Hash) -> sp_blockchain::Result> { Ok(self.storage.read().blocks.get(&hash).and_then(|b| b.justifications().cloned())) } @@ -445,13 +445,13 @@ impl blockchain::Backend for Blockchain { unimplemented!() } - fn indexed_transaction(&self, _hash: &Block::Hash) -> sp_blockchain::Result>> { + fn indexed_transaction(&self, _hash: Block::Hash) -> sp_blockchain::Result>> { unimplemented!("Not supported by the in-mem backend.") } fn block_indexed_body( &self, - _hash: &Block::Hash, + _hash: Block::Hash, ) -> sp_blockchain::Result>>> { unimplemented!("Not supported by the in-mem backend.") } @@ -596,16 +596,16 @@ where fn mark_finalized( &mut self, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, ) -> sp_blockchain::Result<()> { - self.finalized_blocks.push((*hash, justification)); + self.finalized_blocks.push((hash, justification)); Ok(()) } - fn mark_head(&mut self, hash: &Block::Hash) -> sp_blockchain::Result<()> { + fn mark_head(&mut self, hash: Block::Hash) -> sp_blockchain::Result<()> { assert!(self.pending_block.is_none(), "Only one set block per operation is allowed"); - self.set_head = Some(*hash); + self.set_head = Some(hash); Ok(()) } @@ -677,7 +677,7 @@ where type OffchainStorage = OffchainStorage; fn begin_operation(&self) -> sp_blockchain::Result { - let old_state = self.state_at(&Default::default())?; + let old_state = self.state_at(Default::default())?; Ok(BlockImportOperation { pending_block: None, old_state, @@ -691,7 +691,7 @@ where fn begin_state_operation( &self, operation: &mut Self::BlockImportOperation, - block: &Block::Hash, + block: Block::Hash, ) -> sp_blockchain::Result<()> { operation.old_state = self.state_at(block)?; Ok(()) @@ -700,7 +700,7 @@ where fn commit_operation(&self, operation: Self::BlockImportOperation) -> sp_blockchain::Result<()> { if !operation.finalized_blocks.is_empty() { for (block, justification) in operation.finalized_blocks { - self.blockchain.finalize_header(&block, justification)?; + self.blockchain.finalize_header(block, justification)?; } } @@ -733,7 +733,7 @@ where fn finalize_block( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, ) -> sp_blockchain::Result<()> { self.blockchain.finalize_header(hash, justification) @@ -741,7 +741,7 @@ where fn append_justification( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Justification, ) -> sp_blockchain::Result<()> { self.blockchain.append_justification(hash, justification) @@ -759,14 +759,14 @@ where None } - fn state_at(&self, hash: &Block::Hash) -> sp_blockchain::Result { - if *hash == Default::default() { + fn state_at(&self, hash: Block::Hash) -> sp_blockchain::Result { + if hash == Default::default() { return Ok(Self::State::default()) } self.states .read() - .get(hash) + .get(&hash) .cloned() .ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", hash))) } @@ -779,7 +779,7 @@ where Ok((Zero::zero(), HashSet::new())) } - fn remove_leaf_block(&self, _hash: &Block::Hash) -> sp_blockchain::Result<()> { + fn remove_leaf_block(&self, _hash: Block::Hash) -> sp_blockchain::Result<()> { Ok(()) } @@ -862,13 +862,13 @@ mod tests { let blockchain = test_blockchain(); let last_finalized = blockchain.last_finalized().unwrap(); - blockchain.append_justification(&last_finalized, (ID2, vec![4])).unwrap(); + blockchain.append_justification(last_finalized, (ID2, vec![4])).unwrap(); let justifications = { let mut just = Justifications::from((ID1, vec![3])); just.append((ID2, vec![4])); just }; - assert_eq!(blockchain.justifications(&last_finalized).unwrap(), Some(justifications)); + assert_eq!(blockchain.justifications(last_finalized).unwrap(), Some(justifications)); } #[test] @@ -876,9 +876,9 @@ mod tests { let blockchain = test_blockchain(); let last_finalized = blockchain.last_finalized().unwrap(); - blockchain.append_justification(&last_finalized, (ID2, vec![0])).unwrap(); + blockchain.append_justification(last_finalized, (ID2, vec![0])).unwrap(); assert!(matches!( - blockchain.append_justification(&last_finalized, (ID2, vec![1])), + blockchain.append_justification(last_finalized, (ID2, vec![1])), Err(sp_blockchain::Error::BadJustification(_)), )); } diff --git a/client/api/src/proof_provider.rs b/client/api/src/proof_provider.rs index 4ddbf883b83f2..01e35df1dec1c 100644 --- a/client/api/src/proof_provider.rs +++ b/client/api/src/proof_provider.rs @@ -27,7 +27,7 @@ pub trait ProofProvider { /// Reads storage value at a given block + key, returning read proof. fn read_proof( &self, - hash: &Block::Hash, + hash: Block::Hash, keys: &mut dyn Iterator, ) -> sp_blockchain::Result; @@ -35,7 +35,7 @@ pub trait ProofProvider { /// read proof. fn read_child_proof( &self, - hash: &Block::Hash, + hash: Block::Hash, child_info: &ChildInfo, keys: &mut dyn Iterator, ) -> sp_blockchain::Result; @@ -46,7 +46,7 @@ pub trait ProofProvider { /// No changes are made. fn execution_proof( &self, - hash: &Block::Hash, + hash: Block::Hash, method: &str, call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)>; @@ -61,7 +61,7 @@ pub trait ProofProvider { /// Returns combined proof and the numbers of collected keys. fn read_proof_collection( &self, - hash: &Block::Hash, + hash: Block::Hash, start_keys: &[Vec], size_limit: usize, ) -> sp_blockchain::Result<(CompactProof, u32)>; @@ -76,7 +76,7 @@ pub trait ProofProvider { /// end. fn storage_collection( &self, - hash: &Block::Hash, + hash: Block::Hash, start_key: &[Vec], size_limit: usize, ) -> sp_blockchain::Result>; diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index da98ccab9cb07..b69294bf6ccb0 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -736,7 +736,7 @@ mod tests { let api = client.runtime_api(); api.execute_block(&block_id, proposal.block).unwrap(); - let state = backend.state_at(&genesis_hash).unwrap(); + let state = backend.state_at(genesis_hash).unwrap(); let storage_changes = api.into_storage_changes(&state, genesis_hash).unwrap(); diff --git a/client/beefy/src/communication/request_response/incoming_requests_handler.rs b/client/beefy/src/communication/request_response/incoming_requests_handler.rs index 3affbbe870ad7..9f02b7162b54c 100644 --- a/client/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/client/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -153,7 +153,7 @@ where self.client.block_hash(request.payload.begin).map_err(Error::Client)? { self.client - .justifications(&hash) + .justifications(hash) .map_err(Error::Client)? .and_then(|justifs| justifs.get(BEEFY_ENGINE_ID).cloned()) // No BEEFY justification present. diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 62d8a45f4471c..2f0306209071e 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -512,7 +512,7 @@ fn finalize_block_and_wait_for_beefy( peers.clone().for_each(|(index, _)| { let client = net.lock().peer(index).client().as_client(); let finalize = client.expect_block_hash_from_id(&BlockId::number(*block)).unwrap(); - client.finalize_block(&finalize, None).unwrap(); + client.finalize_block(finalize, None).unwrap(); }) } @@ -608,7 +608,7 @@ fn lagging_validators() { .expect_block_hash_from_id(&BlockId::number(25)) .unwrap(); let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - net.lock().peer(0).client().as_client().finalize_block(&finalize, None).unwrap(); + net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); @@ -616,7 +616,7 @@ fn lagging_validators() { // Bob catches up and also finalizes #25 let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - net.lock().peer(1).client().as_client().finalize_block(&finalize, None).unwrap(); + net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); // expected beefy finalizes block #17 from diff-power-of-two wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[23, 24, 25]); wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[23, 24, 25]); @@ -637,7 +637,7 @@ fn lagging_validators() { .as_client() .expect_block_hash_from_id(&BlockId::number(60)) .unwrap(); - net.lock().peer(0).client().as_client().finalize_block(&finalize, None).unwrap(); + net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY let timeout = Some(Duration::from_millis(250)); streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout); @@ -645,7 +645,7 @@ fn lagging_validators() { // Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60) let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); - net.lock().peer(1).client().as_client().finalize_block(&finalize, None).unwrap(); + net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); // verify beefy skips intermediary votes, and successfully finalizes mandatory block #60 wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]); wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[60]); @@ -696,9 +696,9 @@ fn correct_beefy_payload() { .as_client() .expect_block_hash_from_id(&BlockId::number(11)) .unwrap(); - net.lock().peer(0).client().as_client().finalize_block(&hashof11, None).unwrap(); - net.lock().peer(1).client().as_client().finalize_block(&hashof11, None).unwrap(); - net.lock().peer(3).client().as_client().finalize_block(&hashof11, None).unwrap(); + net.lock().peer(0).client().as_client().finalize_block(hashof11, None).unwrap(); + net.lock().peer(1).client().as_client().finalize_block(hashof11, None).unwrap(); + net.lock().peer(3).client().as_client().finalize_block(hashof11, None).unwrap(); // verify consensus is _not_ reached let timeout = Some(Duration::from_millis(250)); @@ -708,7 +708,7 @@ fn correct_beefy_payload() { // 3rd good validator catches up and votes as well let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); - net.lock().peer(2).client().as_client().finalize_block(&hashof11, None).unwrap(); + net.lock().peer(2).client().as_client().finalize_block(hashof11, None).unwrap(); // verify consensus is reached wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[11]); @@ -760,7 +760,7 @@ fn beefy_importing_blocks() { // none in backend, assert_eq!( full_client - .justifications(&hashof1) + .justifications(hashof1) .unwrap() .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), None @@ -799,7 +799,7 @@ fn beefy_importing_blocks() { // still not in backend (worker is responsible for appending to backend), assert_eq!( full_client - .justifications(&hashof2) + .justifications(hashof2) .unwrap() .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), None @@ -843,7 +843,7 @@ fn beefy_importing_blocks() { // none in backend, assert_eq!( full_client - .justifications(&hashof3) + .justifications(hashof3) .unwrap() .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), None @@ -941,7 +941,7 @@ fn on_demand_beefy_justification_sync() { get_beefy_streams(&mut net.lock(), [(dave_index, BeefyKeyring::Dave)].into_iter()); let client = net.lock().peer(dave_index).client().as_client(); let hashof1 = client.expect_block_hash_from_id(&BlockId::number(1)).unwrap(); - client.finalize_block(&hashof1, None).unwrap(); + client.finalize_block(hashof1, None).unwrap(); // Give Dave task some cpu cycles to process the finality notification, run_for(Duration::from_millis(100), &net, &mut runtime); // freshly spun up Dave now needs to listen for gossip to figure out the state of his peers. diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index ea9e0d0c33999..9c14128624518 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -511,7 +511,7 @@ where .expect("forwards closure result; the closure always returns Ok; qed."); self.backend - .append_justification(&hash, (BEEFY_ENGINE_ID, finality_proof.encode())) + .append_justification(hash, (BEEFY_ENGINE_ID, finality_proof.encode())) }) { error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, finality_proof); } @@ -709,7 +709,7 @@ where // a BEEFY justification, or at this session's boundary; voter will resume from there. loop { if let Some(true) = blockchain - .justifications(&header.hash()) + .justifications(header.hash()) .ok() .flatten() .map(|justifs| justifs.get(BEEFY_ENGINE_ID).is_some()) @@ -1375,8 +1375,8 @@ pub(crate) mod tests { // finalize 1 and 2 without justifications let hashof1 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(1)).unwrap(); let hashof2 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(2)).unwrap(); - backend.finalize_block(&hashof1, None).unwrap(); - backend.finalize_block(&hashof2, None).unwrap(); + backend.finalize_block(hashof1, None).unwrap(); + backend.finalize_block(hashof2, None).unwrap(); let justif = create_finality_proof(2); // create new session at block #2 @@ -1401,7 +1401,7 @@ pub(crate) mod tests { })); // check BEEFY justifications are also appended to backend - let justifs = backend.blockchain().justifications(&hashof2).unwrap().unwrap(); + let justifs = backend.blockchain().justifications(hashof2).unwrap().unwrap(); assert!(justifs.get(BEEFY_ENGINE_ID).is_some()) } @@ -1512,7 +1512,7 @@ pub(crate) mod tests { // finalize 13 without justifications let hashof13 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(13)).unwrap(); - net.peer(0).client().as_client().finalize_block(&hashof13, None).unwrap(); + net.peer(0).client().as_client().finalize_block(hashof13, None).unwrap(); // Test initialization at session boundary. { @@ -1551,7 +1551,7 @@ pub(crate) mod tests { let hashof10 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(10)).unwrap(); backend - .append_justification(&hashof10, (BEEFY_ENGINE_ID, justif.encode())) + .append_justification(hashof10, (BEEFY_ENGINE_ID, justif.encode())) .unwrap(); // initialize voter at block 13, expect rounds initialized at last beefy finalized 10 @@ -1587,7 +1587,7 @@ pub(crate) mod tests { let hashof12 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(12)).unwrap(); backend - .append_justification(&hashof12, (BEEFY_ENGINE_ID, justif.encode())) + .append_justification(hashof12, (BEEFY_ENGINE_ID, justif.encode())) .unwrap(); // initialize voter at block 13, expect rounds initialized at last beefy finalized 12 diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index cd5e62e264200..b6c2ac3ba5d68 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -258,7 +258,7 @@ where let proof = self.api.extract_proof(); - let state = self.backend.state_at(&self.parent_hash)?; + let state = self.backend.state_at(self.parent_hash)?; let storage_changes = self .api diff --git a/client/cli/src/commands/export_state_cmd.rs b/client/cli/src/commands/export_state_cmd.rs index 1bcf21f388a62..04bce0c1d707a 100644 --- a/client/cli/src/commands/export_state_cmd.rs +++ b/client/cli/src/commands/export_state_cmd.rs @@ -69,7 +69,7 @@ impl ExportStateCmd { Some(id) => client.expect_block_hash_from_id(&id)?, None => client.usage_info().chain.best_hash, }; - let raw_state = sc_service::chain_ops::export_raw_state(client, &hash)?; + let raw_state = sc_service::chain_ops::export_raw_state(client, hash)?; input_spec.set_storage(raw_state); info!("Generating new chain spec..."); diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index abffcb0a2b4c3..ee1605f037ff4 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -822,7 +822,7 @@ fn revert_not_allowed_for_finalized() { let canon = propose_and_import_blocks_wrap(BlockId::Number(0), 3); // Finalize best block - client.finalize_block(&canon[2], None, false).unwrap(); + client.finalize_block(canon[2], None, false).unwrap(); // Revert canon chain to last finalized block revert(client.clone(), backend, 100).expect("revert should work for baked test scenario"); @@ -884,7 +884,7 @@ fn importing_epoch_change_block_prunes_tree() { // We finalize block #13 from the canon chain, so on the next epoch // change the tree should be pruned, to not contain F (#7). - client.finalize_block(&canon_hashes[12], None, false).unwrap(); + client.finalize_block(canon_hashes[12], None, false).unwrap(); propose_and_import_blocks_wrap(BlockId::Hash(client.chain_info().best_hash), 7); // at this point no hashes from the first fork must exist on the tree @@ -911,7 +911,7 @@ fn importing_epoch_change_block_prunes_tree() { .any(|h| fork_3.contains(h)),); // finalizing block #25 from the canon chain should prune out the second fork - client.finalize_block(&canon_hashes[24], None, false).unwrap(); + client.finalize_block(canon_hashes[24], None, false).unwrap(); propose_and_import_blocks_wrap(BlockId::Hash(client.chain_info().best_hash), 8); // at this point no hashes from the second fork must exist on the tree @@ -1049,7 +1049,7 @@ fn obsolete_blocks_aux_data_cleanup() { assert!(aux_data_check(&fork3_hashes, true)); // Finalize A3 - client.finalize_block(&fork1_hashes[2], None, true).unwrap(); + client.finalize_block(fork1_hashes[2], None, true).unwrap(); // Wiped: A1, A2 assert!(aux_data_check(&fork1_hashes[..2], false)); @@ -1060,7 +1060,7 @@ fn obsolete_blocks_aux_data_cleanup() { // Present C4, C5 assert!(aux_data_check(&fork3_hashes, true)); - client.finalize_block(&fork1_hashes[3], None, true).unwrap(); + client.finalize_block(fork1_hashes[3], None, true).unwrap(); // Wiped: A3 assert!(aux_data_check(&fork1_hashes[2..3], false)); diff --git a/client/consensus/manual-seal/src/finalize_block.rs b/client/consensus/manual-seal/src/finalize_block.rs index e11353e2da611..cee4d59b6d6e5 100644 --- a/client/consensus/manual-seal/src/finalize_block.rs +++ b/client/consensus/manual-seal/src/finalize_block.rs @@ -46,7 +46,7 @@ where { let FinalizeBlockParams { hash, mut sender, justification, finalizer, .. } = params; - match finalizer.finalize_block(&hash, justification, true) { + match finalizer.finalize_block(hash, justification, true) { Err(e) => { log::warn!("Failed to finalize block {}", e); rpc::send_result(&mut sender, Err(e.into())) diff --git a/client/db/benches/state_access.rs b/client/db/benches/state_access.rs index ccceae1f5b419..bab79fe7c90db 100644 --- a/client/db/benches/state_access.rs +++ b/client/db/benches/state_access.rs @@ -66,7 +66,7 @@ fn insert_blocks(db: &Backend, storage: Vec<(Vec, Vec)>) -> H256 for i in 0..10 { let mut op = db.begin_operation().unwrap(); - db.begin_state_operation(&mut op, &parent_hash).unwrap(); + db.begin_state_operation(&mut op, parent_hash).unwrap(); let mut header = Header { number, @@ -83,7 +83,7 @@ fn insert_blocks(db: &Backend, storage: Vec<(Vec, Vec)>) -> H256 .map(|(k, v)| (k.clone(), Some(v.clone()))) .collect::>(); - let (state_root, tx) = db.state_at(&parent_hash).unwrap().storage_root( + let (state_root, tx) = db.state_at(parent_hash).unwrap().storage_root( changes.iter().map(|(k, v)| (k.as_slice(), v.as_deref())), StateVersion::V1, ); @@ -175,7 +175,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(&block_hash).expect("Creates state"), + || backend.state_at(block_hash).expect("Creates state"), |state| { for key in keys.iter().cycle().take(keys.len() * multiplier) { let _ = state.storage(&key).expect("Doesn't fail").unwrap(); @@ -213,7 +213,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(&block_hash).expect("Creates state"), + || backend.state_at(block_hash).expect("Creates state"), |state| { for key in keys.iter().take(1).cycle().take(multiplier) { let _ = state.storage(&key).expect("Doesn't fail").unwrap(); @@ -251,7 +251,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(&block_hash).expect("Creates state"), + || backend.state_at(block_hash).expect("Creates state"), |state| { for key in keys.iter().take(1).cycle().take(multiplier) { let _ = state.storage_hash(&key).expect("Doesn't fail").unwrap(); @@ -289,7 +289,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(&block_hash).expect("Creates state"), + || backend.state_at(block_hash).expect("Creates state"), |state| { let _ = state .storage_hash(sp_core::storage::well_known_keys::CODE) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 0138df36a38fb..fc031e2aaba59 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -577,9 +577,9 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha } impl sc_client_api::blockchain::Backend for BlockchainDb { - fn body(&self, hash: &Block::Hash) -> ClientResult>> { + fn body(&self, hash: Block::Hash) -> ClientResult>> { if let Some(body) = - read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY, BlockId::Hash::(*hash))? + read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY, BlockId::Hash::(hash))? { // Plain body match Decode::decode(&mut &body[..]) { @@ -596,7 +596,7 @@ impl sc_client_api::blockchain::Backend for BlockchainDb(*hash), + BlockId::Hash::(hash), )? { match Vec::>::decode(&mut &index[..]) { Ok(index) => { @@ -642,12 +642,12 @@ impl sc_client_api::blockchain::Backend for BlockchainDb ClientResult> { + fn justifications(&self, hash: Block::Hash) -> ClientResult> { match read_db( &*self.db, columns::KEY_LOOKUP, columns::JUSTIFICATIONS, - BlockId::::Hash(*hash), + BlockId::::Hash(hash), )? { Some(justifications) => match Decode::decode(&mut &justifications[..]) { Ok(justifications) => Ok(Some(justifications)), @@ -686,20 +686,20 @@ impl sc_client_api::blockchain::Backend for BlockchainDb ClientResult>> { + fn indexed_transaction(&self, hash: Block::Hash) -> ClientResult>> { Ok(self.db.get(columns::TRANSACTION, hash.as_ref())) } - fn has_indexed_transaction(&self, hash: &Block::Hash) -> ClientResult { + fn has_indexed_transaction(&self, hash: Block::Hash) -> ClientResult { Ok(self.db.contains(columns::TRANSACTION, hash.as_ref())) } - fn block_indexed_body(&self, hash: &Block::Hash) -> ClientResult>>> { + fn block_indexed_body(&self, hash: Block::Hash) -> ClientResult>>> { let body = match read_db( &*self.db, columns::KEY_LOOKUP, columns::BODY_INDEX, - BlockId::::Hash(*hash), + BlockId::::Hash(hash), )? { Some(body) => body, None => return Ok(None), @@ -914,16 +914,16 @@ impl sc_client_api::backend::BlockImportOperation fn mark_finalized( &mut self, - block: &Block::Hash, + block: Block::Hash, justification: Option, ) -> ClientResult<()> { - self.finalized_blocks.push((*block, justification)); + self.finalized_blocks.push((block, justification)); Ok(()) } - fn mark_head(&mut self, hash: &Block::Hash) -> ClientResult<()> { + fn mark_head(&mut self, hash: Block::Hash) -> ClientResult<()> { assert!(self.set_head.is_none(), "Only one set head per operation is allowed"); - self.set_head = Some(*hash); + self.set_head = Some(hash); Ok(()) } @@ -1176,7 +1176,7 @@ impl Backend { info.finalized_hash != Default::default() && sc_client_api::Backend::have_state_at( &backend, - &info.finalized_hash, + info.finalized_hash, info.finalized_number, ) { backend.blockchain.update_meta(MetaUpdate { @@ -1289,7 +1289,7 @@ impl Backend { fn finalize_block_with_transaction( &self, transaction: &mut Transaction, - hash: &Block::Hash, + hash: Block::Hash, header: &Block::Header, last_finalized: Option, justification: Option, @@ -1300,7 +1300,7 @@ impl Backend { self.ensure_sequential_finalization(header, last_finalized)?; let with_state = sc_client_api::Backend::have_state_at(self, hash, number); - self.note_finalized(transaction, header, *hash, finalization_displaced, with_state)?; + self.note_finalized(transaction, header, hash, finalization_displaced, with_state)?; if let Some(justification) = justification { transaction.set_from_vec( @@ -1309,7 +1309,7 @@ impl Backend { Justifications::from(justification).encode(), ); } - Ok(MetaUpdate { hash: *hash, number, is_best: false, is_finalized: true, with_state }) + Ok(MetaUpdate { hash, number, is_best: false, is_finalized: true, with_state }) } // performs forced canonicalization with a delay after importing a non-finalized block. @@ -1340,7 +1340,7 @@ impl Backend { )) })? }; - if !sc_client_api::Backend::have_state_at(self, &hash, new_canonical.saturated_into()) { + if !sc_client_api::Backend::have_state_at(self, hash, new_canonical.saturated_into()) { return Ok(()) } @@ -1372,7 +1372,7 @@ impl Backend { let block_header = self.blockchain.expect_header(BlockId::Hash(block_hash))?; meta_updates.push(self.finalize_block_with_transaction( &mut transaction, - &block_hash, + block_hash, &block_header, Some(last_finalized_hash), justification, @@ -1703,7 +1703,7 @@ impl Backend { } transaction.set_from_vec(columns::META, meta_keys::FINALIZED_BLOCK, lookup_key); - if sc_client_api::Backend::have_state_at(self, &f_hash, f_num) && + if sc_client_api::Backend::have_state_at(self, f_hash, f_num) && self.storage .state_db .best_canonical() @@ -1978,9 +1978,9 @@ impl sc_client_api::backend::Backend for Backend { fn begin_state_operation( &self, operation: &mut Self::BlockImportOperation, - block: &Block::Hash, + block: Block::Hash, ) -> ClientResult<()> { - if *block == Default::default() { + if block == Default::default() { operation.old_state = self.empty_state()?; } else { operation.old_state = self.state_at(block)?; @@ -2008,11 +2008,11 @@ impl sc_client_api::backend::Backend for Backend { fn finalize_block( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, ) -> ClientResult<()> { let mut transaction = Transaction::new(); - let header = self.blockchain.expect_header(BlockId::Hash(*hash))?; + let header = self.blockchain.expect_header(BlockId::Hash(hash))?; let mut displaced = None; let m = self.finalize_block_with_transaction( @@ -2030,11 +2030,11 @@ impl sc_client_api::backend::Backend for Backend { fn append_justification( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Justification, ) -> ClientResult<()> { let mut transaction: Transaction = Transaction::new(); - let header = self.blockchain.expect_header(BlockId::Hash(*hash))?; + let header = self.blockchain.expect_header(BlockId::Hash(hash))?; let number = *header.number(); // Check if the block is finalized first. @@ -2043,7 +2043,7 @@ impl sc_client_api::backend::Backend for Backend { // We can do a quick check first, before doing a proper but more expensive check if number > self.blockchain.info().finalized_number || - (*hash != last_finalized && !is_descendent_of(hash, &last_finalized)?) + (hash != last_finalized && !is_descendent_of(&hash, &last_finalized)?) { return Err(ClientError::NotInFinalizedChain) } @@ -2061,7 +2061,7 @@ impl sc_client_api::backend::Backend for Backend { transaction.set_from_vec( columns::JUSTIFICATIONS, - &utils::number_and_hash_to_lookup_key(number, *hash)?, + &utils::number_and_hash_to_lookup_key(number, hash)?, justifications.encode(), ); @@ -2154,7 +2154,7 @@ impl sc_client_api::backend::Backend for Backend { let prev_hash = if prev_number == best_number { best_hash } else { *removed.parent_hash() }; - if !self.have_state_at(&prev_hash, prev_number) { + if !self.have_state_at(prev_hash, prev_number) { return Ok(c.saturated_into::>()) } @@ -2183,7 +2183,7 @@ impl sc_client_api::backend::Backend for Backend { if hash == hash_to_revert { if !number_to_revert.is_zero() && self.have_state_at( - &prev_hash, + prev_hash, number_to_revert - One::one(), ) { let lookup_key = utils::number_and_hash_to_lookup_key( @@ -2247,14 +2247,14 @@ impl sc_client_api::backend::Backend for Backend { Ok((reverted, reverted_finalized)) } - fn remove_leaf_block(&self, hash: &Block::Hash) -> ClientResult<()> { + fn remove_leaf_block(&self, hash: Block::Hash) -> ClientResult<()> { let best_hash = self.blockchain.info().best_hash; - if best_hash == *hash { + if best_hash == hash { return Err(sp_blockchain::Error::Backend(format!("Can't remove best block {:?}", hash))) } - let hdr = self.blockchain.header_metadata(*hash)?; + let hdr = self.blockchain.header_metadata(hash)?; if !self.have_state_at(hash, hdr.number) { return Err(sp_blockchain::Error::UnknownBlock(format!( "State already discarded for {:?}", @@ -2263,7 +2263,7 @@ impl sc_client_api::backend::Backend for Backend { } let mut leaves = self.blockchain.leaves.write(); - if !leaves.contains(hdr.number, *hash) { + if !leaves.contains(hdr.number, hash) { return Err(sp_blockchain::Error::Backend(format!( "Can't remove non-leaf block {:?}", hash @@ -2271,7 +2271,7 @@ impl sc_client_api::backend::Backend for Backend { } let mut transaction = Transaction::new(); - if let Some(commit) = self.storage.state_db.remove(hash) { + if let Some(commit) = self.storage.state_db.remove(&hash) { apply_state_commit(&mut transaction, commit); } transaction.remove(columns::KEY_LOOKUP, hash.as_ref()); @@ -2280,7 +2280,7 @@ impl sc_client_api::backend::Backend for Backend { .blockchain() .children(hdr.parent)? .into_iter() - .filter(|child_hash| child_hash != hash) + .filter(|child_hash| *child_hash != hash) .collect(); let parent_leaf = if children.is_empty() { children::remove_children( @@ -2301,7 +2301,7 @@ impl sc_client_api::backend::Backend for Backend { None }; - let remove_outcome = leaves.remove(*hash, hdr.number, parent_leaf); + let remove_outcome = leaves.remove(hash, hdr.number, parent_leaf); leaves.prepare_transaction(&mut transaction, columns::META, meta_keys::LEAF_PREFIX); if let Err(e) = self.storage.db.commit(transaction) { if let Some(outcome) = remove_outcome { @@ -2309,7 +2309,7 @@ impl sc_client_api::backend::Backend for Backend { } return Err(e.into()) } - self.blockchain().remove_header_metadata(*hash); + self.blockchain().remove_header_metadata(hash); Ok(()) } @@ -2317,8 +2317,8 @@ impl sc_client_api::backend::Backend for Backend { &self.blockchain } - fn state_at(&self, hash: &Block::Hash) -> ClientResult { - if hash == &self.blockchain.meta.read().genesis_hash { + fn state_at(&self, hash: Block::Hash) -> ClientResult { + if hash == self.blockchain.meta.read().genesis_hash { if let Some(genesis_state) = &*self.genesis_state.read() { let root = genesis_state.root; let db_state = DbStateBuilder::::new(genesis_state.clone(), root) @@ -2330,7 +2330,7 @@ impl sc_client_api::backend::Backend for Backend { } } - match self.blockchain.header_metadata(*hash) { + match self.blockchain.header_metadata(hash) { Ok(ref hdr) => { let hint = || { sc_state_db::NodeDb::get(self.storage.as_ref(), hdr.state_root.as_ref()) @@ -2338,7 +2338,7 @@ impl sc_client_api::backend::Backend for Backend { .is_some() }; if let Ok(()) = - self.storage.state_db.pin(hash, hdr.number.saturated_into::(), hint) + self.storage.state_db.pin(&hash, hdr.number.saturated_into::(), hint) { let root = hdr.state_root; let db_state = DbStateBuilder::::new(self.storage.clone(), root) @@ -2346,8 +2346,8 @@ impl sc_client_api::backend::Backend for Backend { self.shared_trie_cache.as_ref().map(|c| c.local_cache()), ) .build(); - let state = RefTrackingState::new(db_state, self.storage.clone(), Some(*hash)); - Ok(RecordStatsState::new(state, Some(*hash), self.state_usage.clone())) + let state = RefTrackingState::new(db_state, self.storage.clone(), Some(hash)); + Ok(RecordStatsState::new(state, Some(hash), self.state_usage.clone())) } else { Err(sp_blockchain::Error::UnknownBlock(format!( "State already discarded for {:?}", @@ -2359,9 +2359,9 @@ impl sc_client_api::backend::Backend for Backend { } } - fn have_state_at(&self, hash: &Block::Hash, number: NumberFor) -> bool { + fn have_state_at(&self, hash: Block::Hash, number: NumberFor) -> bool { if self.is_archive { - match self.blockchain.header_metadata(*hash) { + match self.blockchain.header_metadata(hash) { Ok(header) => sp_state_machine::Storage::get( self.storage.as_ref(), &header.state_root, @@ -2372,10 +2372,10 @@ impl sc_client_api::backend::Backend for Backend { _ => false, } } else { - match self.storage.state_db.is_pruned(hash, number.saturated_into::()) { + match self.storage.state_db.is_pruned(&hash, number.saturated_into::()) { IsPruned::Pruned => false, IsPruned::NotPruned => true, - IsPruned::MaybePruned => match self.blockchain.header_metadata(*hash) { + IsPruned::MaybePruned => match self.blockchain.header_metadata(hash) { Ok(header) => sp_state_machine::Storage::get( self.storage.as_ref(), &header.state_root, @@ -2459,7 +2459,7 @@ pub(crate) mod tests { let block_hash = if number == 0 { Default::default() } else { parent_hash }; let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &block_hash).unwrap(); + backend.begin_state_operation(&mut op, block_hash).unwrap(); op.set_block_data(header, Some(body), None, None, NewBlockState::Best).unwrap(); if let Some(index) = transaction_index { op.update_transaction_index(index).unwrap(); @@ -2507,7 +2507,7 @@ pub(crate) mod tests { }; let mut op = db.begin_operation().unwrap(); - db.begin_state_operation(&mut op, &hash).unwrap(); + db.begin_state_operation(&mut op, hash).unwrap(); let header = Header { number: i, parent_hash: hash, @@ -2581,7 +2581,7 @@ pub(crate) mod tests { db.commit_operation(op).unwrap(); - let state = db.state_at(&hash).unwrap(); + let state = db.state_at(hash).unwrap(); assert_eq!(state.storage(&[1, 3, 5]).unwrap(), Some(vec![2, 4, 6])); assert_eq!(state.storage(&[1, 2, 3]).unwrap(), Some(vec![9, 9, 9])); @@ -2592,7 +2592,7 @@ pub(crate) mod tests { { let mut op = db.begin_operation().unwrap(); - db.begin_state_operation(&mut op, &hash).unwrap(); + db.begin_state_operation(&mut op, hash).unwrap(); let mut header = Header { number: 1, parent_hash: hash, @@ -2616,7 +2616,7 @@ pub(crate) mod tests { db.commit_operation(op).unwrap(); - let state = db.state_at(&header.hash()).unwrap(); + let state = db.state_at(header.hash()).unwrap(); assert_eq!(state.storage(&[1, 3, 5]).unwrap(), None); assert_eq!(state.storage(&[1, 2, 3]).unwrap(), Some(vec![9, 9, 9])); @@ -2633,7 +2633,7 @@ pub(crate) mod tests { let hash = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &Default::default()).unwrap(); + backend.begin_state_operation(&mut op, Default::default()).unwrap(); let mut header = Header { number: 0, parent_hash: Default::default(), @@ -2670,7 +2670,7 @@ pub(crate) mod tests { let hashof1 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &hash).unwrap(); + backend.begin_state_operation(&mut op, hash).unwrap(); let mut header = Header { number: 1, parent_hash: hash, @@ -2707,7 +2707,7 @@ pub(crate) mod tests { let hashof2 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &hashof1).unwrap(); + backend.begin_state_operation(&mut op, hashof1).unwrap(); let mut header = Header { number: 2, parent_hash: hashof1, @@ -2741,7 +2741,7 @@ pub(crate) mod tests { let hashof3 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &hashof2).unwrap(); + backend.begin_state_operation(&mut op, hashof2).unwrap(); let mut header = Header { number: 3, parent_hash: hashof2, @@ -2771,9 +2771,9 @@ pub(crate) mod tests { hash }; - backend.finalize_block(&hashof1, None).unwrap(); - backend.finalize_block(&hashof2, None).unwrap(); - backend.finalize_block(&hashof3, None).unwrap(); + backend.finalize_block(hashof1, None).unwrap(); + backend.finalize_block(hashof2, None).unwrap(); + backend.finalize_block(hashof3, None).unwrap(); assert!(backend .storage .db @@ -2996,8 +2996,8 @@ pub(crate) mod tests { vec![block2_a, block2_b, block2_c, block1_c] ); - backend.finalize_block(&block1_a, None).unwrap(); - backend.finalize_block(&block2_a, None).unwrap(); + backend.finalize_block(block1_a, None).unwrap(); + backend.finalize_block(block2_a, None).unwrap(); // leaves at same height stay. Leaves at lower heights pruned. assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a, block2_b, block2_c]); @@ -3024,10 +3024,10 @@ pub(crate) mod tests { let block1 = insert_header(&backend, 1, block0, None, Default::default()); let justification = Some((CONS0_ENGINE_ID, vec![1, 2, 3])); - backend.finalize_block(&block1, justification.clone()).unwrap(); + backend.finalize_block(block1, justification.clone()).unwrap(); assert_eq!( - backend.blockchain().justifications(&block1).unwrap(), + backend.blockchain().justifications(block1).unwrap(), justification.map(Justifications::from), ); } @@ -3042,14 +3042,14 @@ pub(crate) mod tests { let block1 = insert_header(&backend, 1, block0, None, Default::default()); let just0 = (CONS0_ENGINE_ID, vec![1, 2, 3]); - backend.finalize_block(&block1, Some(just0.clone().into())).unwrap(); + backend.finalize_block(block1, Some(just0.clone().into())).unwrap(); let just1 = (CONS1_ENGINE_ID, vec![4, 5]); - backend.append_justification(&block1, just1.clone()).unwrap(); + backend.append_justification(block1, just1.clone()).unwrap(); let just2 = (CONS1_ENGINE_ID, vec![6, 7]); assert!(matches!( - backend.append_justification(&block1, just2), + backend.append_justification(block1, just2), Err(ClientError::BadJustification(_)) )); @@ -3058,7 +3058,7 @@ pub(crate) mod tests { just.append(just1); just }; - assert_eq!(backend.blockchain().justifications(&block1).unwrap(), Some(justifications),); + assert_eq!(backend.blockchain().justifications(block1).unwrap(), Some(justifications),); } #[test] @@ -3072,16 +3072,16 @@ pub(crate) mod tests { let block4 = insert_header(&backend, 4, block3, None, Default::default()); { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &block0).unwrap(); - op.mark_finalized(&block1, None).unwrap(); - op.mark_finalized(&block2, None).unwrap(); + backend.begin_state_operation(&mut op, block0).unwrap(); + op.mark_finalized(block1, None).unwrap(); + op.mark_finalized(block2, None).unwrap(); backend.commit_operation(op).unwrap(); } { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &block2).unwrap(); - op.mark_finalized(&block3, None).unwrap(); - op.mark_finalized(&block4, None).unwrap(); + backend.begin_state_operation(&mut op, block2).unwrap(); + op.mark_finalized(block3, None).unwrap(); + op.mark_finalized(block4, None).unwrap(); backend.commit_operation(op).unwrap(); } } @@ -3093,7 +3093,7 @@ pub(crate) mod tests { let hash0 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &Default::default()).unwrap(); + backend.begin_state_operation(&mut op, Default::default()).unwrap(); let mut header = Header { number: 0, parent_hash: Default::default(), @@ -3127,11 +3127,11 @@ pub(crate) mod tests { hash }; - let block0_hash = backend.state_at(&hash0).unwrap().storage_hash(&b"test"[..]).unwrap(); + let block0_hash = backend.state_at(hash0).unwrap().storage_hash(&b"test"[..]).unwrap(); let hash1 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &hash0).unwrap(); + backend.begin_state_operation(&mut op, hash0).unwrap(); let mut header = Header { number: 1, parent_hash: hash0, @@ -3166,7 +3166,7 @@ pub(crate) mod tests { backend.commit_operation(op).unwrap(); } - let block1_hash = backend.state_at(&hash1).unwrap().storage_hash(&b"test"[..]).unwrap(); + let block1_hash = backend.state_at(hash1).unwrap().storage_hash(&b"test"[..]).unwrap(); assert_ne!(block0_hash, block1_hash); } @@ -3180,8 +3180,8 @@ pub(crate) mod tests { let block2 = insert_header(&backend, 2, block1, None, Default::default()); { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &block0).unwrap(); - op.mark_finalized(&block2, None).unwrap(); + backend.begin_state_operation(&mut op, block0).unwrap(); + op.mark_finalized(block2, None).unwrap(); backend.commit_operation(op).unwrap_err(); } } @@ -3208,18 +3208,18 @@ pub(crate) mod tests { { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); + backend.begin_state_operation(&mut op, blocks[4]).unwrap(); for i in 1..5 { - op.mark_finalized(&blocks[i], None).unwrap(); + op.mark_finalized(blocks[i], None).unwrap(); } backend.commit_operation(op).unwrap(); } let bc = backend.blockchain(); - assert_eq!(None, bc.body(&blocks[0]).unwrap()); - assert_eq!(None, bc.body(&blocks[1]).unwrap()); - assert_eq!(None, bc.body(&blocks[2]).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(&blocks[3]).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(&blocks[4]).unwrap()); + assert_eq!(None, bc.body(blocks[0]).unwrap()); + assert_eq!(None, bc.body(blocks[1]).unwrap()); + assert_eq!(None, bc.body(blocks[2]).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); } #[test] @@ -3243,18 +3243,18 @@ pub(crate) mod tests { } let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); + backend.begin_state_operation(&mut op, blocks[4]).unwrap(); for i in 1..3 { - op.mark_finalized(&blocks[i], None).unwrap(); + op.mark_finalized(blocks[i], None).unwrap(); } backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); - assert_eq!(Some(vec![0.into()]), bc.body(&blocks[0]).unwrap()); - assert_eq!(Some(vec![1.into()]), bc.body(&blocks[1]).unwrap()); - assert_eq!(Some(vec![2.into()]), bc.body(&blocks[2]).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(&blocks[3]).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(&blocks[4]).unwrap()); + assert_eq!(Some(vec![0.into()]), bc.body(blocks[0]).unwrap()); + assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(blocks[2]).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); } #[test] @@ -3300,27 +3300,27 @@ pub(crate) mod tests { .unwrap(); let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); - op.mark_head(&blocks[4]).unwrap(); + backend.begin_state_operation(&mut op, blocks[4]).unwrap(); + op.mark_head(blocks[4]).unwrap(); backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); - assert_eq!(Some(vec![2.into()]), bc.body(&fork_hash_root).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(fork_hash_root).unwrap()); for i in 1..5 { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &blocks[i]).unwrap(); - op.mark_finalized(&blocks[i], None).unwrap(); + backend.begin_state_operation(&mut op, blocks[i]).unwrap(); + op.mark_finalized(blocks[i], None).unwrap(); backend.commit_operation(op).unwrap(); } - assert_eq!(Some(vec![0.into()]), bc.body(&blocks[0]).unwrap()); - assert_eq!(Some(vec![1.into()]), bc.body(&blocks[1]).unwrap()); - assert_eq!(Some(vec![2.into()]), bc.body(&blocks[2]).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(&blocks[3]).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(&blocks[4]).unwrap()); + assert_eq!(Some(vec![0.into()]), bc.body(blocks[0]).unwrap()); + assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(blocks[2]).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); - assert_eq!(Some(vec![2.into()]), bc.body(&fork_hash_root).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(fork_hash_root).unwrap()); assert_eq!(bc.info().best_number, 4); for i in 0..5 { assert!(bc.hash(i).unwrap().is_some()); @@ -3369,23 +3369,23 @@ pub(crate) mod tests { ) .unwrap(); let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); - op.mark_head(&blocks[4]).unwrap(); + backend.begin_state_operation(&mut op, blocks[4]).unwrap(); + op.mark_head(blocks[4]).unwrap(); backend.commit_operation(op).unwrap(); for i in 1..5 { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); - op.mark_finalized(&blocks[i], None).unwrap(); + backend.begin_state_operation(&mut op, blocks[4]).unwrap(); + op.mark_finalized(blocks[i], None).unwrap(); backend.commit_operation(op).unwrap(); } let bc = backend.blockchain(); - assert_eq!(None, bc.body(&blocks[0]).unwrap()); - assert_eq!(None, bc.body(&blocks[1]).unwrap()); - assert_eq!(None, bc.body(&blocks[2]).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(&blocks[3]).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(&blocks[4]).unwrap()); + assert_eq!(None, bc.body(blocks[0]).unwrap()); + assert_eq!(None, bc.body(blocks[1]).unwrap()); + assert_eq!(None, bc.body(blocks[2]).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); } #[test] @@ -3419,17 +3419,17 @@ pub(crate) mod tests { ) .unwrap(); let bc = backend.blockchain(); - assert_eq!(bc.indexed_transaction(&x0_hash).unwrap().unwrap(), &x0[1..]); - assert_eq!(bc.indexed_transaction(&x1_hash).unwrap().unwrap(), &x1[1..]); + assert_eq!(bc.indexed_transaction(x0_hash).unwrap().unwrap(), &x0[1..]); + assert_eq!(bc.indexed_transaction(x1_hash).unwrap().unwrap(), &x1[1..]); let hashof0 = bc.info().genesis_hash; // Push one more blocks and make sure block is pruned and transaction index is cleared. let block1 = insert_block(&backend, 1, hash, None, Default::default(), vec![], None).unwrap(); - backend.finalize_block(&block1, None).unwrap(); - assert_eq!(bc.body(&hashof0).unwrap(), None); - assert_eq!(bc.indexed_transaction(&x0_hash).unwrap(), None); - assert_eq!(bc.indexed_transaction(&x1_hash).unwrap(), None); + backend.finalize_block(block1, None).unwrap(); + assert_eq!(bc.body(hashof0).unwrap(), None); + assert_eq!(bc.indexed_transaction(x0_hash).unwrap(), None); + assert_eq!(bc.indexed_transaction(x1_hash).unwrap(), None); } #[test] @@ -3463,8 +3463,8 @@ pub(crate) mod tests { ) .unwrap(); let bc = backend.blockchain(); - assert_eq!(bc.indexed_transaction(&x0_hash).unwrap().unwrap(), &x0[..]); - assert_eq!(bc.indexed_transaction(&x1_hash).unwrap(), None); + assert_eq!(bc.indexed_transaction(x0_hash).unwrap().unwrap(), &x0[..]); + assert_eq!(bc.indexed_transaction(x1_hash).unwrap(), None); } #[test] @@ -3502,14 +3502,14 @@ pub(crate) mod tests { for i in 1..10 { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &blocks[4]).unwrap(); - op.mark_finalized(&blocks[i], None).unwrap(); + backend.begin_state_operation(&mut op, blocks[4]).unwrap(); + op.mark_finalized(blocks[i], None).unwrap(); backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); if i < 6 { - assert!(bc.indexed_transaction(&x1_hash).unwrap().is_some()); + assert!(bc.indexed_transaction(x1_hash).unwrap().is_some()); } else { - assert!(bc.indexed_transaction(&x1_hash).unwrap().is_none()); + assert!(bc.indexed_transaction(x1_hash).unwrap().is_none()); } } } @@ -3561,31 +3561,31 @@ pub(crate) mod tests { .unwrap(); assert_eq!(backend.blockchain().info().best_hash, best_hash); - assert!(backend.remove_leaf_block(&best_hash).is_err()); + assert!(backend.remove_leaf_block(best_hash).is_err()); assert_eq!(backend.blockchain().leaves().unwrap(), vec![blocks[2], blocks[3], best_hash]); assert_eq!(backend.blockchain().children(blocks[1]).unwrap(), vec![blocks[2], blocks[3]]); - assert!(backend.have_state_at(&blocks[3], 2)); + assert!(backend.have_state_at(blocks[3], 2)); assert!(backend.blockchain().header(BlockId::hash(blocks[3])).unwrap().is_some()); - backend.remove_leaf_block(&blocks[3]).unwrap(); - assert!(!backend.have_state_at(&blocks[3], 2)); + backend.remove_leaf_block(blocks[3]).unwrap(); + assert!(!backend.have_state_at(blocks[3], 2)); assert!(backend.blockchain().header(BlockId::hash(blocks[3])).unwrap().is_none()); assert_eq!(backend.blockchain().leaves().unwrap(), vec![blocks[2], best_hash]); assert_eq!(backend.blockchain().children(blocks[1]).unwrap(), vec![blocks[2]]); - assert!(backend.have_state_at(&blocks[2], 2)); + assert!(backend.have_state_at(blocks[2], 2)); assert!(backend.blockchain().header(BlockId::hash(blocks[2])).unwrap().is_some()); - backend.remove_leaf_block(&blocks[2]).unwrap(); - assert!(!backend.have_state_at(&blocks[2], 2)); + backend.remove_leaf_block(blocks[2]).unwrap(); + assert!(!backend.have_state_at(blocks[2], 2)); assert!(backend.blockchain().header(BlockId::hash(blocks[2])).unwrap().is_none()); assert_eq!(backend.blockchain().leaves().unwrap(), vec![best_hash, blocks[1]]); assert_eq!(backend.blockchain().children(blocks[1]).unwrap(), vec![]); - assert!(backend.have_state_at(&blocks[1], 1)); + assert!(backend.have_state_at(blocks[1], 1)); assert!(backend.blockchain().header(BlockId::hash(blocks[1])).unwrap().is_some()); - backend.remove_leaf_block(&blocks[1]).unwrap(); - assert!(!backend.have_state_at(&blocks[1], 1)); + backend.remove_leaf_block(blocks[1]).unwrap(); + assert!(!backend.have_state_at(blocks[1], 1)); assert!(backend.blockchain().header(BlockId::hash(blocks[1])).unwrap().is_none()); assert_eq!(backend.blockchain().leaves().unwrap(), vec![best_hash]); assert_eq!(backend.blockchain().children(blocks[0]).unwrap(), vec![best_hash]); @@ -3678,7 +3678,7 @@ pub(crate) mod tests { let block1_a = insert_header(&backend, 1, block0, None, Default::default()); let block2_a = insert_header(&backend, 2, block1_a, None, Default::default()); - backend.finalize_block(&block1_a, None).unwrap(); + backend.finalize_block(block1_a, None).unwrap(); assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a]); // Insert a fork prior to finalization point. Leave should not be created. @@ -3702,7 +3702,7 @@ pub(crate) mod tests { let block3 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &block1).unwrap(); + backend.begin_state_operation(&mut op, block1).unwrap(); let header = Header { number: 3, parent_hash: block2, @@ -3721,7 +3721,7 @@ pub(crate) mod tests { let block4 = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &block2).unwrap(); + backend.begin_state_operation(&mut op, block2).unwrap(); let header = Header { number: 4, parent_hash: block3, @@ -3740,7 +3740,7 @@ pub(crate) mod tests { let block3_fork = { let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, &block2).unwrap(); + backend.begin_state_operation(&mut op, block2).unwrap(); let header = Header { number: 3, parent_hash: block2, @@ -3757,22 +3757,22 @@ pub(crate) mod tests { header.hash() }; - assert!(backend.have_state_at(&block1, 1)); - assert!(backend.have_state_at(&block2, 2)); - assert!(backend.have_state_at(&block3, 3)); - assert!(backend.have_state_at(&block4, 4)); - assert!(backend.have_state_at(&block3_fork, 3)); + assert!(backend.have_state_at(block1, 1)); + assert!(backend.have_state_at(block2, 2)); + assert!(backend.have_state_at(block3, 3)); + assert!(backend.have_state_at(block4, 4)); + assert!(backend.have_state_at(block3_fork, 3)); assert_eq!(backend.blockchain.leaves().unwrap(), vec![block4, block3_fork]); assert_eq!(4, backend.blockchain.leaves.read().highest_leaf().unwrap().0); assert_eq!(3, backend.revert(1, false).unwrap().0); - assert!(backend.have_state_at(&block1, 1)); - assert!(!backend.have_state_at(&block2, 2)); - assert!(!backend.have_state_at(&block3, 3)); - assert!(!backend.have_state_at(&block4, 4)); - assert!(!backend.have_state_at(&block3_fork, 3)); + assert!(backend.have_state_at(block1, 1)); + assert!(!backend.have_state_at(block2, 2)); + assert!(!backend.have_state_at(block3, 3)); + assert!(!backend.have_state_at(block4, 4)); + assert!(!backend.have_state_at(block3_fork, 3)); assert_eq!(backend.blockchain.leaves().unwrap(), vec![block1]); assert_eq!(1, backend.blockchain.leaves.read().highest_leaf().unwrap().0); diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 60720494a9f9a..f235c3a86c04e 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -1352,7 +1352,7 @@ where // ideally some handle to a synchronization oracle would be used // to avoid unconditionally notifying. client - .apply_finality(import_op, &hash, persisted_justification, true) + .apply_finality(import_op, hash, persisted_justification, true) .map_err(|e| { warn!(target: "afg", "Error applying finality to block {:?}: {}", (hash, number), e); e diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index 3070581350662..453b41bc63468 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -188,7 +188,7 @@ where .expect_block_hash_from_id(&BlockId::Number(last_block_for_set))?; let justification = if let Some(grandpa_justification) = backend .blockchain() - .justifications(&last_block_for_set_id)? + .justifications(last_block_for_set_id)? .and_then(|justifications| justifications.into_justification(GRANDPA_ENGINE_ID)) { grandpa_justification @@ -312,7 +312,7 @@ mod tests { for block in to_finalize { let hash = blocks[*block as usize - 1].hash(); - client.finalize_block(&hash, None).unwrap(); + client.finalize_block(hash, None).unwrap(); } (client, backend, blocks) } @@ -492,7 +492,7 @@ mod tests { let grandpa_just8 = GrandpaJustification::from_commit(&client, round, commit).unwrap(); client - .finalize_block(&block8.hash(), Some((ID, grandpa_just8.encode().clone()))) + .finalize_block(block8.hash(), Some((ID, grandpa_just8.encode().clone()))) .unwrap(); // Authority set change at block 8, so the justification stored there will be used in the diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index d0a66888ec072..3715287eea31f 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -424,8 +424,8 @@ where } /// Read current set id form a given state. - fn current_set_id(&self, hash: &Block::Hash) -> Result { - let id = &BlockId::hash(*hash); + fn current_set_id(&self, hash: Block::Hash) -> Result { + let id = &BlockId::hash(hash); let runtime_version = self.inner.runtime_api().version(id).map_err(|e| { ConsensusError::ClientImport(format!( "Unable to retrieve current runtime version. {}", @@ -480,7 +480,7 @@ where .runtime_api() .grandpa_authorities(&BlockId::hash(hash)) .map_err(|e| ConsensusError::ClientImport(e.to_string()))?; - let set_id = self.current_set_id(&hash)?; + let set_id = self.current_set_id(hash)?; let authority_set = AuthoritySet::new( authorities.clone(), set_id, diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index d2db1feea0fef..93d20110ff5af 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -375,7 +375,7 @@ fn finalize_3_voters_no_observers() { // normally there's no justification for finalized blocks assert!( - net.lock().peer(0).client().justifications(&hashof20).unwrap().is_none(), + net.lock().peer(0).client().justifications(hashof20).unwrap().is_none(), "Extra justification for block#1", ); } @@ -621,7 +621,7 @@ fn justification_is_generated_periodically() { // when block#32 (justification_period) is finalized, justification // is required => generated for i in 0..3 { - assert!(net.lock().peer(i).client().justifications(&hashof32).unwrap().is_some()); + assert!(net.lock().peer(i).client().justifications(hashof32).unwrap().is_some()); } } @@ -665,12 +665,12 @@ fn sync_justifications_on_change_blocks() { // the first 3 peers are grandpa voters and therefore have already finalized // block 21 and stored a justification for i in 0..3 { - assert!(net.lock().peer(i).client().justifications(&hashof21).unwrap().is_some()); + assert!(net.lock().peer(i).client().justifications(hashof21).unwrap().is_some()); } // the last peer should get the justification by syncing from other peers futures::executor::block_on(futures::future::poll_fn(move |cx| { - if net.lock().peer(3).client().justifications(&hashof21).unwrap().is_none() { + if net.lock().peer(3).client().justifications(hashof21).unwrap().is_none() { net.lock().poll(cx); Poll::Pending } else { @@ -1428,7 +1428,7 @@ fn grandpa_environment_respects_voting_rules() { .as_client() .expect_block_hash_from_id(&BlockId::Number(19)) .unwrap(); - peer.client().finalize_block(&hashof19, None, false).unwrap(); + peer.client().finalize_block(hashof19, None, false).unwrap(); // the 3/4 environment should propose block 21 for voting assert_eq!( @@ -1455,7 +1455,7 @@ fn grandpa_environment_respects_voting_rules() { .as_client() .expect_block_hash_from_id(&BlockId::Number(21)) .unwrap(); - peer.client().finalize_block(&hashof21, None, false).unwrap(); + peer.client().finalize_block(hashof21, None, false).unwrap(); // even though the default environment will always try to not vote on the // best block, there's a hard rule that we can't cast any votes lower than @@ -1666,7 +1666,7 @@ fn imports_justification_for_regular_blocks_on_import() { ); // the justification should be imported and available from the client - assert!(client.justifications(&block_hash).unwrap().is_some()); + assert!(client.justifications(block_hash).unwrap().is_some()); } #[test] diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index 786dfacf8b0b9..c9f762fc7d593 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -130,7 +130,7 @@ impl WarpSyncProof { } let justification = blockchain - .justifications(&header.hash())? + .justifications(header.hash())? .and_then(|just| just.into_justification(GRANDPA_ENGINE_ID)) .expect( "header is last in set and contains standard change signal; \ @@ -412,7 +412,7 @@ mod tests { let justification = GrandpaJustification::from_commit(&client, 42, commit).unwrap(); client - .finalize_block(&target_hash, Some((GRANDPA_ENGINE_ID, justification.encode()))) + .finalize_block(target_hash, Some((GRANDPA_ENGINE_ID, justification.encode()))) .unwrap(); authority_set_changes.push((current_set_id, n)); diff --git a/client/network/bitswap/src/lib.rs b/client/network/bitswap/src/lib.rs index aba7f40ce632f..62a18b18c839d 100644 --- a/client/network/bitswap/src/lib.rs +++ b/client/network/bitswap/src/lib.rs @@ -203,7 +203,7 @@ impl BitswapRequestHandler { let mut hash = B::Hash::default(); hash.as_mut().copy_from_slice(&cid.hash().digest()[0..32]); - let transaction = match self.client.indexed_transaction(&hash) { + let transaction = match self.client.indexed_transaction(hash) { Ok(ex) => ex, Err(e) => { error!(target: LOG_TARGET, "Error retrieving transaction {}: {}", hash, e); diff --git a/client/network/light/src/light_client_requests/handler.rs b/client/network/light/src/light_client_requests/handler.rs index 7156545fbd9aa..77904c7256295 100644 --- a/client/network/light/src/light_client_requests/handler.rs +++ b/client/network/light/src/light_client_requests/handler.rs @@ -172,7 +172,7 @@ where let block = Decode::decode(&mut request.block.as_ref())?; - let response = match self.client.execution_proof(&block, &request.method, &request.data) { + let response = match self.client.execution_proof(block, &request.method, &request.data) { Ok((_, proof)) => { let r = schema::v1::light::RemoteCallResponse { proof: proof.encode() }; Some(schema::v1::light::response::Response::RemoteCallResponse(r)) @@ -212,7 +212,7 @@ where let block = Decode::decode(&mut request.block.as_ref())?; let response = - match self.client.read_proof(&block, &mut request.keys.iter().map(AsRef::as_ref)) { + match self.client.read_proof(block, &mut request.keys.iter().map(AsRef::as_ref)) { Ok(proof) => { let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; Some(schema::v1::light::response::Response::RemoteReadResponse(r)) @@ -259,7 +259,7 @@ where }; let response = match child_info.and_then(|child_info| { self.client.read_child_proof( - &block, + block, &child_info, &mut request.keys.iter().map(AsRef::as_ref), ) diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index 5eba1d52dc68c..467d898489b61 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -332,7 +332,7 @@ where let hash = header.hash(); let parent_hash = *header.parent_hash(); let justifications = - if get_justification { self.client.justifications(&hash)? } else { None }; + if get_justification { self.client.justifications(hash)? } else { None }; let (justifications, justification, is_empty_justification) = if support_multiple_justifications { @@ -361,7 +361,7 @@ where }; let body = if get_body { - match self.client.block_body(&hash)? { + match self.client.block_body(hash)? { Some(mut extrinsics) => extrinsics.iter_mut().map(|extrinsic| extrinsic.encode()).collect(), None => { @@ -374,7 +374,7 @@ where }; let indexed_body = if get_indexed_body { - match self.client.block_indexed_body(&hash)? { + match self.client.block_indexed_body(hash)? { Some(transactions) => transactions, None => { log::trace!( diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index f369bdb47e1c6..7c484835951e8 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -3201,7 +3201,7 @@ mod test { let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); let just = (*b"TEST", Vec::new()); - client.finalize_block(&finalized_block.hash(), Some(just)).unwrap(); + client.finalize_block(finalized_block.hash(), Some(just)).unwrap(); sync.update_chain_info(&info.best_hash, info.best_number); let peer_id1 = PeerId::random(); @@ -3333,7 +3333,7 @@ mod test { let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); let just = (*b"TEST", Vec::new()); - client.finalize_block(&finalized_block.hash(), Some(just)).unwrap(); + client.finalize_block(finalized_block.hash(), Some(just)).unwrap(); sync.update_chain_info(&info.best_hash, info.best_number); let peer_id1 = PeerId::random(); diff --git a/client/network/sync/src/state_request_handler.rs b/client/network/sync/src/state_request_handler.rs index 0a369c998dbd7..441400ef439b7 100644 --- a/client/network/sync/src/state_request_handler.rs +++ b/client/network/sync/src/state_request_handler.rs @@ -205,14 +205,14 @@ where if !request.no_proof { let (proof, _count) = self.client.read_proof_collection( - &block, + block, request.start.as_slice(), MAX_RESPONSE_BYTES, )?; response.proof = proof.encode(); } else { let entries = self.client.storage_collection( - &block, + block, request.start.as_slice(), MAX_RESPONSE_BYTES, )?; diff --git a/client/network/test/src/block_import.rs b/client/network/test/src/block_import.rs index a1d42f1e60440..b86f6787f30b5 100644 --- a/client/network/test/src/block_import.rs +++ b/client/network/test/src/block_import.rs @@ -40,7 +40,7 @@ fn prepare_good_block() -> (TestClient, Hash, u64, PeerId, IncomingBlock) let (hash, number) = (client.block_hash(1).unwrap().unwrap(), 1); let header = client.header(&BlockId::Number(1)).unwrap(); - let justifications = client.justifications(&hash).unwrap(); + let justifications = client.justifications(hash).unwrap(); let peer_id = PeerId::random(); ( client, diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index f348d5cf94c43..035fc0a972a59 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -173,12 +173,12 @@ impl PeersClient { Some(header) => header, None => return false, }; - self.backend.have_state_at(&header.hash(), *header.number()) + self.backend.have_state_at(header.hash(), *header.number()) } pub fn justifications( &self, - hash: &::Hash, + hash: ::Hash, ) -> ClientResult> { self.client.justifications(hash) } @@ -193,7 +193,7 @@ impl PeersClient { pub fn finalize_block( &self, - hash: &::Hash, + hash: ::Hash, justification: Option, notify: bool, ) -> ClientResult<()> { @@ -535,14 +535,14 @@ where self.verifier.failed_verifications.lock().clone() } - pub fn has_block(&self, hash: &H256) -> bool { + pub fn has_block(&self, hash: H256) -> bool { self.backend .as_ref() - .map(|backend| backend.blockchain().header(BlockId::hash(*hash)).unwrap().is_some()) + .map(|backend| backend.blockchain().header(BlockId::hash(hash)).unwrap().is_some()) .unwrap_or(false) } - pub fn has_body(&self, hash: &H256) -> bool { + pub fn has_body(&self, hash: H256) -> bool { self.backend .as_ref() .map(|backend| backend.blockchain().body(hash).unwrap().is_some()) @@ -1124,7 +1124,7 @@ impl JustificationImport for ForceFinalized { justification: Justification, ) -> Result<(), Self::Error> { self.0 - .finalize_block(&hash, Some(justification), true) + .finalize_block(hash, Some(justification), true) .map_err(|_| ConsensusError::InvalidJustification) } } diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index 9ae3014e497ce..bbba3bc6ded62 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -252,23 +252,14 @@ fn sync_justifications() { let hashof20 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(20)).unwrap(); // there's currently no justification for block #10 - assert_eq!(net.peer(0).client().justifications(&hashof10).unwrap(), None); - assert_eq!(net.peer(1).client().justifications(&hashof10).unwrap(), None); + assert_eq!(net.peer(0).client().justifications(hashof10).unwrap(), None); + assert_eq!(net.peer(1).client().justifications(hashof10).unwrap(), None); // we finalize block #10, #15 and #20 for peer 0 with a justification let just = (*b"FRNK", Vec::new()); - net.peer(0) - .client() - .finalize_block(&hashof10, Some(just.clone()), true) - .unwrap(); - net.peer(0) - .client() - .finalize_block(&hashof15, Some(just.clone()), true) - .unwrap(); - net.peer(0) - .client() - .finalize_block(&hashof20, Some(just.clone()), true) - .unwrap(); + net.peer(0).client().finalize_block(hashof10, Some(just.clone()), true).unwrap(); + net.peer(0).client().finalize_block(hashof15, Some(just.clone()), true).unwrap(); + net.peer(0).client().finalize_block(hashof20, Some(just.clone()), true).unwrap(); let hashof10 = net.peer(1).client().header(&BlockId::Number(10)).unwrap().unwrap().hash(); let hashof15 = net.peer(1).client().header(&BlockId::Number(15)).unwrap().unwrap().hash(); @@ -283,12 +274,12 @@ fn sync_justifications() { net.poll(cx); for hash in [hashof10, hashof15, hashof20] { - if net.peer(0).client().justifications(&hash).unwrap() != + if net.peer(0).client().justifications(hash).unwrap() != Some(Justifications::from((*b"FRNK", Vec::new()))) { return Poll::Pending } - if net.peer(1).client().justifications(&hash).unwrap() != + if net.peer(1).client().justifications(hash).unwrap() != Some(Justifications::from((*b"FRNK", Vec::new()))) { return Poll::Pending @@ -314,7 +305,7 @@ fn sync_justifications_across_forks() { net.block_until_sync(); let just = (*b"FRNK", Vec::new()); - net.peer(0).client().finalize_block(&f1_best, Some(just), true).unwrap(); + net.peer(0).client().finalize_block(f1_best, Some(just), true).unwrap(); net.peer(1).request_justification(&f1_best, 10); net.peer(1).request_justification(&f2_best, 11); @@ -322,9 +313,9 @@ fn sync_justifications_across_forks() { block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(0).client().justifications(&f1_best).unwrap() == + if net.peer(0).client().justifications(f1_best).unwrap() == Some(Justifications::from((*b"FRNK", Vec::new()))) && - net.peer(1).client().justifications(&f1_best).unwrap() == + net.peer(1).client().justifications(f1_best).unwrap() == Some(Justifications::from((*b"FRNK", Vec::new()))) { Poll::Ready(()) @@ -369,10 +360,10 @@ fn syncs_all_forks() { net.block_until_sync(); // Check that all peers have all of the branches. - assert!(net.peer(0).has_block(&b1)); - assert!(net.peer(0).has_block(&b2)); - assert!(net.peer(1).has_block(&b1)); - assert!(net.peer(1).has_block(&b2)); + assert!(net.peer(0).has_block(b1)); + assert!(net.peer(0).has_block(b2)); + assert!(net.peer(1).has_block(b1)); + assert!(net.peer(1).has_block(b2)); } #[test] @@ -555,7 +546,7 @@ fn syncs_header_only_forks() { net.peer(1).push_blocks(4, false); // Peer 1 will sync the small fork even though common block state is missing - while !net.peer(1).has_block(&small_hash) { + while !net.peer(1).has_block(small_hash) { net.block_until_idle(); } } @@ -657,13 +648,13 @@ fn can_sync_to_peers_with_wrong_common_block() { // both peers re-org to the same fork without notifying each other let just = Some((*b"FRNK", Vec::new())); - net.peer(0).client().finalize_block(&fork_hash, just.clone(), true).unwrap(); - net.peer(1).client().finalize_block(&fork_hash, just, true).unwrap(); + net.peer(0).client().finalize_block(fork_hash, just.clone(), true).unwrap(); + net.peer(1).client().finalize_block(fork_hash, just, true).unwrap(); let final_hash = net.peer(0).push_blocks(1, false); net.block_until_sync(); - assert!(net.peer(1).has_block(&final_hash)); + assert!(net.peer(1).has_block(final_hash)); } /// Returns `is_new_best = true` for each validated announcement. @@ -724,7 +715,7 @@ fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { ForkChoiceStrategy::Custom(false), ); - while !net.peer(2).has_block(&block_hash) { + while !net.peer(2).has_block(block_hash) { net.block_until_idle(); } } @@ -767,7 +758,7 @@ fn wait_until_deferred_block_announce_validation_is_ready() { ForkChoiceStrategy::Custom(false), ); - while !net.peer(1).has_block(&block_hash) { + while !net.peer(1).has_block(block_hash) { net.block_until_idle(); } } @@ -788,7 +779,7 @@ fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { net.block_until_idle(); // The peer should not have synced the block. - assert!(!net.peer(1).has_block(&block_hash)); + assert!(!net.peer(1).has_block(block_hash)); // Make sync protocol aware of the best block net.peer(0).network_service().new_best_block_imported(block_hash, 3); @@ -802,7 +793,7 @@ fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(2).has_block(&block_hash) { + if net.peer(2).has_block(block_hash) { Poll::Ready(()) } else { Poll::Pending @@ -810,7 +801,7 @@ fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { })); // However peer 1 should still not have the block. - assert!(!net.peer(1).has_block(&block_hash)); + assert!(!net.peer(1).has_block(block_hash)); } /// Ensures that if we as a syncing node sync to the tip while we are connected to another peer @@ -831,10 +822,10 @@ fn sync_to_tip_when_we_sync_together_with_multiple_peers() { net.block_until_connected(); net.block_until_idle(); - assert!(!net.peer(2).has_block(&block_hash)); + assert!(!net.peer(2).has_block(block_hash)); net.peer(0).network_service().new_best_block_imported(block_hash, 10_000); - while !net.peer(2).has_block(&block_hash) && !net.peer(1).has_block(&block_hash) { + while !net.peer(2).has_block(block_hash) && !net.peer(1).has_block(block_hash) { net.block_until_idle(); } } @@ -895,7 +886,7 @@ fn block_announce_data_is_propagated() { let block_hash = net.peer(0).push_blocks_at_without_announcing(BlockId::Number(0), 1, true); net.peer(0).announce_block(block_hash, Some(vec![137])); - while !net.peer(1).has_block(&block_hash) || !net.peer(2).has_block(&block_hash) { + while !net.peer(1).has_block(block_hash) || !net.peer(2).has_block(block_hash) { net.block_until_idle(); } } @@ -939,7 +930,7 @@ fn continue_to_sync_after_some_block_announcement_verifications_failed() { let block_hash = net.peer(0).push_blocks(500, true); net.block_until_sync(); - assert!(net.peer(1).has_block(&block_hash)); + assert!(net.peer(1).has_block(block_hash)); } /// When being spammed by the same request of a peer, we ban this peer. However, we should only ban @@ -956,8 +947,8 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { let hashof10 = net.peer(1).client().header(&BlockId::Number(10)).unwrap().unwrap().hash(); // there's currently no justification for block #10 - assert_eq!(net.peer(0).client().justifications(&hashof10).unwrap(), None); - assert_eq!(net.peer(1).client().justifications(&hashof10).unwrap(), None); + assert_eq!(net.peer(0).client().justifications(hashof10).unwrap(), None); + assert_eq!(net.peer(1).client().justifications(hashof10).unwrap(), None); // Let's assume block 10 was finalized, but we still need the justification from the network. net.peer(1).request_justification(&hashof10, 10); @@ -982,13 +973,13 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { // Finalize the block and make the justification available. net.peer(0) .client() - .finalize_block(&hashof10, Some((*b"FRNK", Vec::new())), true) + .finalize_block(hashof10, Some((*b"FRNK", Vec::new())), true) .unwrap(); block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(1).client().justifications(&hashof10).unwrap() != + if net.peer(1).client().justifications(hashof10).unwrap() != Some(Justifications::from((*b"FRNK", Vec::new()))) { return Poll::Pending @@ -1110,7 +1101,7 @@ fn syncs_state() { .blockchain() .expect_block_hash_from_id(&BlockId::Number(60)) .unwrap(); - net.peer(1).client().finalize_block(&hashof60, Some(just), true).unwrap(); + net.peer(1).client().finalize_block(hashof60, Some(just), true).unwrap(); // Wait for state sync. block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); @@ -1165,14 +1156,14 @@ fn syncs_indexed_blocks() { .peer(0) .client() .as_client() - .indexed_transaction(&indexed_key) + .indexed_transaction(indexed_key) .unwrap() .is_some()); assert!(net .peer(1) .client() .as_client() - .indexed_transaction(&indexed_key) + .indexed_transaction(indexed_key) .unwrap() .is_none()); @@ -1181,7 +1172,7 @@ fn syncs_indexed_blocks() { .peer(1) .client() .as_client() - .indexed_transaction(&indexed_key) + .indexed_transaction(indexed_key) .unwrap() .is_some()); } @@ -1210,7 +1201,7 @@ fn warp_sync() { // Wait for peer 1 download block history block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(3).has_body(&gap_end) && net.peer(3).has_body(&target) { + if net.peer(3).has_body(gap_end) && net.peer(3).has_body(target) { Poll::Ready(()) } else { Poll::Pending diff --git a/client/rpc/src/chain/tests.rs b/client/rpc/src/chain/tests.rs index a41d8e41b8fa7..1e6dbd5aca148 100644 --- a/client/rpc/src/chain/tests.rs +++ b/client/rpc/src/chain/tests.rs @@ -206,7 +206,7 @@ async fn should_return_finalized_hash() { assert_eq!(res, client.genesis_hash()); // finalize - client.finalize_block(&block_hash, None).unwrap(); + client.finalize_block(block_hash, None).unwrap(); let res: H256 = api.call("chain_getFinalizedHead", EmptyParams::new()).await.unwrap(); assert_eq!(res, block_hash); } @@ -235,7 +235,7 @@ async fn test_head_subscription(method: &str) { let block = client.new_block(Default::default()).unwrap().build().unwrap().block; let block_hash = block.hash(); client.import(BlockOrigin::Own, block).await.unwrap(); - client.finalize_block(&block_hash, None).unwrap(); + client.finalize_block(block_hash, None).unwrap(); sub }; diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 7fc7f840a9daf..64b6cacaad700 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -147,7 +147,7 @@ where let mut block_changes = StorageChangeSet { block: *block_hash, changes: Vec::new() }; for key in keys { let (has_changed, data) = { - let curr_data = self.client.storage(block_hash, key).map_err(client_err)?; + let curr_data = self.client.storage(*block_hash, key).map_err(client_err)?; match last_values.get(key) { Some(prev_data) => (curr_data != *prev_data, curr_data), None => (true, curr_data), @@ -213,7 +213,7 @@ where prefix: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage_keys(&block, &prefix)) + .and_then(|block| self.client.storage_keys(block, &prefix)) .map_err(client_err) } @@ -223,7 +223,7 @@ where prefix: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage_pairs(&block, &prefix)) + .and_then(|block| self.client.storage_pairs(block, &prefix)) .map_err(client_err) } @@ -236,7 +236,7 @@ where ) -> std::result::Result, Error> { self.block_or_best(block) .and_then(|block| { - self.client.storage_keys_iter(&block, prefix.as_ref(), start_key.as_ref()) + self.client.storage_keys_iter(block, prefix.as_ref(), start_key.as_ref()) }) .map(|iter| iter.take(count as usize).collect()) .map_err(client_err) @@ -248,7 +248,7 @@ where key: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage(&block, &key)) + .and_then(|block| self.client.storage(block, &key)) .map_err(client_err) } @@ -262,14 +262,14 @@ where Err(e) => return Err(client_err(e)), }; - match self.client.storage(&block, &key) { + match self.client.storage(block, &key) { Ok(Some(d)) => return Ok(Some(d.0.len() as u64)), Err(e) => return Err(client_err(e)), Ok(None) => {}, } self.client - .storage_pairs(&block, &key) + .storage_pairs(block, &key) .map(|kv| { let item_sum = kv.iter().map(|(_, v)| v.0.len() as u64).sum::(); if item_sum > 0 { @@ -287,7 +287,7 @@ where key: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage_hash(&block, &key)) + .and_then(|block| self.client.storage_hash(block, &key)) .map_err(client_err) } @@ -345,7 +345,7 @@ where self.block_or_best(block) .and_then(|block| { self.client - .read_proof(&block, &mut keys.iter().map(|key| key.0.as_ref())) + .read_proof(block, &mut keys.iter().map(|key| key.0.as_ref())) .map(|proof| proof.into_iter_nodes().map(|node| node.into()).collect()) .map(|proof| ReadProof { at: block, proof }) }) @@ -413,7 +413,7 @@ where let changes = keys .into_iter() .map(|key| { - let v = self.client.storage(&block, &key).ok().flatten(); + let v = self.client.storage(block, &key).ok().flatten(); (key, v) }) .collect(); @@ -494,7 +494,7 @@ where }; self.client .read_child_proof( - &block, + block, &child_info, &mut keys.iter().map(|key| key.0.as_ref()), ) @@ -517,7 +517,7 @@ where ChildInfo::new_default(storage_key), None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; - self.client.child_storage_keys(&block, &child_info, &prefix) + self.client.child_storage_keys(block, &child_info, &prefix) }) .map_err(client_err) } @@ -538,7 +538,7 @@ where None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; self.client.child_storage_keys_iter( - &block, + block, child_info, prefix.as_ref(), start_key.as_ref(), @@ -561,7 +561,7 @@ where ChildInfo::new_default(storage_key), None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; - self.client.child_storage(&block, &child_info, &key) + self.client.child_storage(block, &child_info, &key) }) .map_err(client_err) } @@ -584,7 +584,7 @@ where keys.into_iter() .map(move |key| { - client.clone().child_storage(&block, &child_info, &key).map_err(client_err) + client.clone().child_storage(block, &child_info, &key).map_err(client_err) }) .collect() } @@ -602,7 +602,7 @@ where ChildInfo::new_default(storage_key), None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; - self.client.child_storage_hash(&block, &child_info, &key) + self.client.child_storage_hash(block, &child_info, &key) }) .map_err(client_err) } diff --git a/client/service/src/chain_ops/export_raw_state.rs b/client/service/src/chain_ops/export_raw_state.rs index 04dba387de908..ca7a070086f45 100644 --- a/client/service/src/chain_ops/export_raw_state.rs +++ b/client/service/src/chain_ops/export_raw_state.rs @@ -25,7 +25,7 @@ use std::{collections::HashMap, sync::Arc}; /// Export the raw state at the given `block`. If `block` is `None`, the /// best block will be used. -pub fn export_raw_state(client: Arc, hash: &B::Hash) -> Result +pub fn export_raw_state(client: Arc, hash: B::Hash) -> Result where C: UsageProvider + StorageProvider, B: BlockT, diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 8ab332a24be78..a1a012dcedd9f 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -148,7 +148,7 @@ where ) -> sp_blockchain::Result> { let mut changes = OverlayedChanges::default(); let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; - let state = self.backend.state_at(&at_hash)?; + let state = self.backend.state_at(at_hash)?; let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; @@ -193,7 +193,7 @@ where let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut()); let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; - let state = self.backend.state_at(&at_hash)?; + let state = self.backend.state_at(at_hash)?; let changes = &mut *changes.borrow_mut(); @@ -251,7 +251,7 @@ where let mut overlay = OverlayedChanges::default(); let at_hash = self.backend.blockchain().expect_block_hash_from_id(id)?; - let state = self.backend.state_at(&at_hash)?; + let state = self.backend.state_at(at_hash)?; let mut cache = StorageTransactionCache::::default(); let mut ext = Ext::new(&mut overlay, &mut cache, &state, None); let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); @@ -269,7 +269,7 @@ where call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)> { let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; - let state = self.backend.state_at(&at_hash)?; + let state = self.backend.state_at(at_hash)?; let trie_backend = state.as_trie_backend(); diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index a4890f2fcf06f..438d0b7f77061 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -414,14 +414,14 @@ where } /// Get a reference to the state at a given block. - pub fn state_at(&self, hash: &Block::Hash) -> sp_blockchain::Result { + pub fn state_at(&self, hash: Block::Hash) -> sp_blockchain::Result { self.backend.state_at(hash) } /// Get the code at a given block. pub fn code_at(&self, id: &BlockId) -> sp_blockchain::Result> { let hash = self.backend.blockchain().expect_block_hash_from_id(id)?; - Ok(StorageProvider::storage(self, &hash, &StorageKey(well_known_keys::CODE.to_vec()))? + Ok(StorageProvider::storage(self, hash, &StorageKey(well_known_keys::CODE.to_vec()))? .expect( "None is returned if there's no value stored for the given key;\ ':code' key is always defined; qed", @@ -586,7 +586,7 @@ where Some(storage_changes) => { let storage_changes = match storage_changes { sc_consensus::StorageChanges::Changes(storage_changes) => { - self.backend.begin_state_operation(&mut operation.op, &parent_hash)?; + self.backend.begin_state_operation(&mut operation.op, parent_hash)?; let (main_sc, child_sc, offchain_sc, tx, _, tx_index) = storage_changes.into_inner(); @@ -813,7 +813,7 @@ where Block::new(import_block.header.clone(), body.clone()), )?; - let state = self.backend.state_at(parent_hash)?; + let state = self.backend.state_at(*parent_hash)?; let gen_storage_changes = runtime_api .into_storage_changes(&state, *parent_hash) .map_err(sp_blockchain::Error::Storage)?; @@ -877,17 +877,17 @@ where // plugable we cannot make a better choice here. usages that need // an accurate "best" block need to go through `SelectChain` // instead. - operation.op.mark_head(&block)?; + operation.op.mark_head(block)?; } let enacted = route_from_finalized.enacted(); assert!(enacted.len() > 0); for finalize_new in &enacted[..enacted.len() - 1] { - operation.op.mark_finalized(&finalize_new.hash, None)?; + operation.op.mark_finalized(finalize_new.hash, None)?; } assert_eq!(enacted.last().map(|e| e.hash), Some(block)); - operation.op.mark_finalized(&block, justification)?; + operation.op.mark_finalized(block, justification)?; if notify { let finalized = @@ -1033,7 +1033,7 @@ where }; match hash_and_number { Some((hash, number)) => - if self.backend.have_state_at(&hash, number) { + if self.backend.have_state_at(hash, number) { Ok(BlockStatus::InChainWithState) } else { Ok(BlockStatus::InChainPruned) @@ -1053,7 +1053,7 @@ where /// Get block body by id. pub fn body( &self, - hash: &Block::Hash, + hash: Block::Hash, ) -> sp_blockchain::Result::Extrinsic>>> { self.backend.blockchain().body(hash) } @@ -1151,7 +1151,7 @@ where { fn read_proof( &self, - hash: &Block::Hash, + hash: Block::Hash, keys: &mut dyn Iterator, ) -> sp_blockchain::Result { self.state_at(hash) @@ -1160,7 +1160,7 @@ where fn read_child_proof( &self, - hash: &Block::Hash, + hash: Block::Hash, child_info: &ChildInfo, keys: &mut dyn Iterator, ) -> sp_blockchain::Result { @@ -1170,16 +1170,16 @@ where fn execution_proof( &self, - hash: &Block::Hash, + hash: Block::Hash, method: &str, call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)> { - self.executor.prove_execution(&BlockId::Hash(*hash), method, call_data) + self.executor.prove_execution(&BlockId::Hash(hash), method, call_data) } fn read_proof_collection( &self, - hash: &Block::Hash, + hash: Block::Hash, start_key: &[Vec], size_limit: usize, ) -> sp_blockchain::Result<(CompactProof, u32)> { @@ -1198,14 +1198,14 @@ where fn storage_collection( &self, - hash: &Block::Hash, + hash: Block::Hash, start_key: &[Vec], size_limit: usize, ) -> sp_blockchain::Result> { if start_key.len() > MAX_NESTED_TRIE_DEPTH { return Err(Error::Backend("Invalid start key.".to_string())) } - let state = self.state_at(&hash)?; + let state = self.state_at(hash)?; let child_info = |storage_key: &Vec| -> sp_blockchain::Result { let storage_key = PrefixedStorageKey::new_ref(storage_key); match ChildType::from_prefixed_key(storage_key) { @@ -1398,7 +1398,7 @@ where { fn storage_keys( &self, - hash: &Block::Hash, + hash: Block::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { let keys = self.state_at(hash)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); @@ -1407,7 +1407,7 @@ where fn storage_pairs( &self, - hash: &::Hash, + hash: ::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { let state = self.state_at(hash)?; @@ -1424,7 +1424,7 @@ where fn storage_keys_iter<'a>( &self, - hash: &::Hash, + hash: ::Hash, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result> { @@ -1435,7 +1435,7 @@ where fn child_storage_keys_iter<'a>( &self, - hash: &::Hash, + hash: ::Hash, child_info: ChildInfo, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, @@ -1447,7 +1447,7 @@ where fn storage( &self, - hash: &Block::Hash, + hash: Block::Hash, key: &StorageKey, ) -> sp_blockchain::Result> { Ok(self @@ -1459,7 +1459,7 @@ where fn storage_hash( &self, - hash: &::Hash, + hash: ::Hash, key: &StorageKey, ) -> sp_blockchain::Result> { self.state_at(hash)? @@ -1469,7 +1469,7 @@ where fn child_storage_keys( &self, - hash: &::Hash, + hash: ::Hash, child_info: &ChildInfo, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { @@ -1484,7 +1484,7 @@ where fn child_storage( &self, - hash: &::Hash, + hash: ::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { @@ -1497,7 +1497,7 @@ where fn child_storage_hash( &self, - hash: &::Hash, + hash: ::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { @@ -1683,7 +1683,7 @@ where fn state_at(&self, at: &BlockId) -> Result { let hash = self.backend.blockchain().expect_block_hash_from_id(at)?; - self.state_at(&hash).map_err(Into::into) + self.state_at(hash).map_err(Into::into) } } @@ -1844,17 +1844,17 @@ where fn apply_finality( &self, operation: &mut ClientImportOperation, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()> { let last_best = self.backend.blockchain().info().best_hash; - self.apply_finality_with_block_hash(operation, *hash, justification, last_best, notify) + self.apply_finality_with_block_hash(operation, hash, justification, last_best, notify) } fn finalize_block( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()> { @@ -1873,7 +1873,7 @@ where fn apply_finality( &self, operation: &mut ClientImportOperation, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()> { @@ -1882,7 +1882,7 @@ where fn finalize_block( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, notify: bool, ) -> sp_blockchain::Result<()> { @@ -1939,7 +1939,7 @@ where { fn block_body( &self, - hash: &Block::Hash, + hash: Block::Hash, ) -> sp_blockchain::Result::Extrinsic>>> { self.body(hash) } @@ -1948,7 +1948,7 @@ where Ok(match self.header(id)? { Some(header) => { let hash = header.hash(); - match (self.body(&hash)?, self.justifications(&hash)?) { + match (self.body(hash)?, self.justifications(hash)?) { (Some(extrinsics), justifications) => Some(SignedBlock { block: Block::new(header, extrinsics), justifications }), _ => None, @@ -1962,7 +1962,7 @@ where Client::block_status(self, id) } - fn justifications(&self, hash: &Block::Hash) -> sp_blockchain::Result> { + fn justifications(&self, hash: Block::Hash) -> sp_blockchain::Result> { self.backend.blockchain().justifications(hash) } @@ -1970,18 +1970,15 @@ where self.backend.blockchain().hash(number) } - fn indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result>> { + fn indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result>> { self.backend.blockchain().indexed_transaction(hash) } - fn has_indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result { + fn has_indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result { self.backend.blockchain().has_indexed_transaction(hash) } - fn block_indexed_body( - &self, - hash: &Block::Hash, - ) -> sp_blockchain::Result>>> { + fn block_indexed_body(&self, hash: Block::Hash) -> sp_blockchain::Result>>> { self.backend.blockchain().block_indexed_body(hash) } @@ -2085,7 +2082,7 @@ where self.backend .blockchain() - .block_indexed_body(&hash) + .block_indexed_body(hash) .map_err(|e| sp_transaction_storage_proof::Error::Application(Box::new(e))) } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index c60ff4dd09d7b..788f119130ac0 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -346,7 +346,7 @@ fn block_builder_works_with_transactions() { .expect("block 1 was just imported. qed"); assert_eq!(client.chain_info().best_number, 1); - assert_ne!(client.state_at(&hash1).unwrap().pairs(), client.state_at(&hash0).unwrap().pairs()); + assert_ne!(client.state_at(hash1).unwrap().pairs(), client.state_at(hash0).unwrap().pairs()); assert_eq!( client .runtime_api() @@ -405,10 +405,10 @@ fn block_builder_does_not_include_invalid() { assert_eq!(client.chain_info().best_number, 1); assert_ne!( - client.state_at(&hashof1).unwrap().pairs(), - client.state_at(&hashof0).unwrap().pairs() + client.state_at(hashof1).unwrap().pairs(), + client.state_at(hashof0).unwrap().pairs() ); - assert_eq!(client.body(&hashof1).unwrap().unwrap().len(), 1) + assert_eq!(client.body(hashof1).unwrap().unwrap().len(), 1) } #[test] @@ -870,7 +870,7 @@ fn import_with_justification() { .unwrap() .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); - client.finalize_block(&a2.hash(), None).unwrap(); + client.finalize_block(a2.hash(), None).unwrap(); // A2 -> A3 let justification = Justifications::from((TEST_ENGINE_ID, vec![1, 2, 3])); @@ -884,11 +884,11 @@ fn import_with_justification() { assert_eq!(client.chain_info().finalized_hash, a3.hash()); - assert_eq!(client.justifications(&a3.hash()).unwrap(), Some(justification)); + assert_eq!(client.justifications(a3.hash()).unwrap(), Some(justification)); - assert_eq!(client.justifications(&a1.hash()).unwrap(), None); + assert_eq!(client.justifications(a1.hash()).unwrap(), None); - assert_eq!(client.justifications(&a2.hash()).unwrap(), None); + assert_eq!(client.justifications(a2.hash()).unwrap(), None); finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[]); finality_notification_check(&mut finality_notifications, &[a3.hash()], &[]); @@ -999,7 +999,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { // we finalize block B1 which is on a different branch from current best // which should trigger a re-org. - ClientExt::finalize_block(&client, &b1.hash(), None).unwrap(); + ClientExt::finalize_block(&client, b1.hash(), None).unwrap(); // B1 should now be the latest finalized assert_eq!(client.chain_info().finalized_hash, b1.hash()); @@ -1023,7 +1023,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { assert_eq!(client.chain_info().best_hash, b3.hash()); - ClientExt::finalize_block(&client, &b3.hash(), None).unwrap(); + ClientExt::finalize_block(&client, b3.hash(), None).unwrap(); finality_notification_check(&mut finality_notifications, &[b1.hash()], &[]); finality_notification_check(&mut finality_notifications, &[b2.hash(), b3.hash()], &[a2.hash()]); @@ -1121,7 +1121,7 @@ fn finality_notifications_content() { // Postpone import to test behavior of import of finalized block. - ClientExt::finalize_block(&client, &a2.hash(), None).unwrap(); + ClientExt::finalize_block(&client, a2.hash(), None).unwrap(); // Import and finalize D4 block_on(client.import_as_final(BlockOrigin::Own, d4.clone())).unwrap(); @@ -1285,7 +1285,7 @@ fn doesnt_import_blocks_that_revert_finality() { // we will finalize A2 which should make it impossible to import a new // B3 at the same height but that doesn't include it - ClientExt::finalize_block(&client, &a2.hash(), None).unwrap(); + ClientExt::finalize_block(&client, a2.hash(), None).unwrap(); let import_err = block_on(client.import(BlockOrigin::Own, b3)).err().unwrap(); let expected_err = @@ -1320,7 +1320,7 @@ fn doesnt_import_blocks_that_revert_finality() { .unwrap() .block; block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); - ClientExt::finalize_block(&client, &a3.hash(), None).unwrap(); + ClientExt::finalize_block(&client, a3.hash(), None).unwrap(); finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[]); @@ -1620,7 +1620,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { let child_prefix = StorageKey(b"sec".to_vec()); let res: Vec<_> = client - .storage_keys_iter(&block_hash, Some(&prefix), None) + .storage_keys_iter(block_hash, Some(&prefix), None) .unwrap() .map(|x| x.0) .collect(); @@ -1635,7 +1635,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { let res: Vec<_> = client .storage_keys_iter( - &block_hash, + block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))), ) @@ -1646,7 +1646,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { let res: Vec<_> = client .storage_keys_iter( - &block_hash, + block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a686561707061676573"))), ) @@ -1656,7 +1656,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { assert_eq!(res, Vec::>::new()); let res: Vec<_> = client - .child_storage_keys_iter(&block_hash, child_info.clone(), Some(&child_prefix), None) + .child_storage_keys_iter(block_hash, child_info.clone(), Some(&child_prefix), None) .unwrap() .map(|x| x.0) .collect(); @@ -1664,7 +1664,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { let res: Vec<_> = client .child_storage_keys_iter( - &block_hash, + block_hash, child_info, None, Some(&StorageKey(b"second".to_vec())), @@ -1684,7 +1684,7 @@ fn storage_keys_iter_works() { let prefix = StorageKey(array_bytes::hex2bytes_unchecked("")); let res: Vec<_> = client - .storage_keys_iter(&block_hash, Some(&prefix), None) + .storage_keys_iter(block_hash, Some(&prefix), None) .unwrap() .take(9) .map(|x| array_bytes::bytes2hex("", &x.0)) @@ -1706,7 +1706,7 @@ fn storage_keys_iter_works() { let res: Vec<_> = client .storage_keys_iter( - &block_hash, + block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))), ) @@ -1729,7 +1729,7 @@ fn storage_keys_iter_works() { let res: Vec<_> = client .storage_keys_iter( - &block_hash, + block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked( "7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa", diff --git a/client/tracing/src/block/mod.rs b/client/tracing/src/block/mod.rs index ee524f5f72902..63fd1de374cba 100644 --- a/client/tracing/src/block/mod.rs +++ b/client/tracing/src/block/mod.rs @@ -225,7 +225,7 @@ where .ok_or_else(|| Error::MissingBlockComponent("Header not found".to_string()))?; let extrinsics = self .client - .block_body(&self.block) + .block_body(self.block) .map_err(Error::InvalidBlockId)? .ok_or_else(|| Error::MissingBlockComponent("Extrinsics not found".to_string()))?; tracing::debug!(target: "state_tracing", "Found {} extrinsics", extrinsics.len()); diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index bc6f2f7d5e947..602e84b47775c 100644 --- a/client/transaction-pool/benches/basics.rs +++ b/client/transaction-pool/benches/basics.rs @@ -111,7 +111,7 @@ impl ChainApi for TestApi { (blake2_256(&encoded).into(), encoded.len()) } - fn block_body(&self, _id: &::Hash) -> Self::BodyFuture { + fn block_body(&self, _id: ::Hash) -> Self::BodyFuture { ready(Ok(None)) } diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index f162a02ddb643..c3f9b50f9482d 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -126,7 +126,7 @@ where Pin> + Send>>; type BodyFuture = Ready::Extrinsic>>>>; - fn block_body(&self, hash: &Block::Hash) -> Self::BodyFuture { + fn block_body(&self, hash: Block::Hash) -> Self::BodyFuture { ready(self.client.block_body(hash).map_err(error::Error::from)) } diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 99119ac8fa8ab..7b3a8db15982a 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -91,7 +91,7 @@ pub trait ChainApi: Send + Sync { fn hash_and_length(&self, uxt: &ExtrinsicFor) -> (ExtrinsicHash, usize); /// Returns a block body given the block. - fn block_body(&self, at: &::Hash) -> Self::BodyFuture; + fn block_body(&self, at: ::Hash) -> Self::BodyFuture; /// Returns a block header given the block id. fn block_header( diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index e66c780a5ed8f..a441bf9b2a9a0 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -550,12 +550,12 @@ impl RevalidationStatus { /// Prune the known txs for the given block. async fn prune_known_txs_for_block>( - block_hash: &Block::Hash, + block_hash: Block::Hash, api: &Api, pool: &graph::Pool, ) -> Vec> { let extrinsics = api - .block_body(&block_hash) + .block_body(block_hash) .await .unwrap_or_else(|e| { log::warn!("Prune known transactions: error request: {}", e); @@ -567,7 +567,7 @@ async fn prune_known_txs_for_block h, Ok(None) => { log::debug!(target: "txpool", "Could not find header for {:?}.", block_hash); @@ -580,7 +580,7 @@ async fn prune_known_txs_for_block::Hash) -> Self::BodyFuture { + fn block_body(&self, _id: ::Hash) -> Self::BodyFuture { futures::future::ready(Ok(None)) } diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index fdb56020661b4..dea3a7f285117 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -89,9 +89,9 @@ pub trait Backend: HeaderBackend + HeaderMetadata { /// Get block body. Returns `None` if block is not found. - fn body(&self, hash: &Block::Hash) -> Result::Extrinsic>>>; + fn body(&self, hash: Block::Hash) -> Result::Extrinsic>>>; /// Get block justifications. Returns `None` if no justification exists. - fn justifications(&self, hash: &Block::Hash) -> Result>; + fn justifications(&self, hash: Block::Hash) -> Result>; /// Get last finalized block hash. fn last_finalized(&self) -> Result; @@ -231,14 +231,14 @@ pub trait Backend: /// Get single indexed transaction by content hash. Note that this will only fetch transactions /// that are indexed by the runtime with `storage_index_transaction`. - fn indexed_transaction(&self, hash: &Block::Hash) -> Result>>; + fn indexed_transaction(&self, hash: Block::Hash) -> Result>>; /// Check if indexed transaction exists. - fn has_indexed_transaction(&self, hash: &Block::Hash) -> Result { + fn has_indexed_transaction(&self, hash: Block::Hash) -> Result { Ok(self.indexed_transaction(hash)?.is_some()) } - fn block_indexed_body(&self, hash: &Block::Hash) -> Result>>>; + fn block_indexed_body(&self, hash: Block::Hash) -> Result>>>; } /// Blockchain info diff --git a/test-utils/client/src/client_ext.rs b/test-utils/client/src/client_ext.rs index dd416b9102fc0..881c50d434264 100644 --- a/test-utils/client/src/client_ext.rs +++ b/test-utils/client/src/client_ext.rs @@ -29,7 +29,7 @@ pub trait ClientExt: Sized { /// Finalize a block. fn finalize_block( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, ) -> sp_blockchain::Result<()>; @@ -75,7 +75,7 @@ where { fn finalize_block( &self, - hash: &Block::Hash, + hash: Block::Hash, justification: Option, ) -> sp_blockchain::Result<()> { Finalizer::finalize_block(self, hash, justification, true) diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index e2d6efccea424..f8d551a6fa5bd 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -315,12 +315,12 @@ impl sc_transaction_pool::ChainApi for TestApi { Self::hash_and_length_inner(ex) } - fn block_body(&self, hash: &::Hash) -> Self::BodyFuture { + fn block_body(&self, hash: ::Hash) -> Self::BodyFuture { futures::future::ready(Ok(self .chain .read() .block_by_hash - .get(hash) + .get(&hash) .map(|b| b.extrinsics().to_vec()))) } diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index 47cd047e158d0..5a67b11f494f5 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -142,7 +142,7 @@ where let block_hash = self.client.expect_block_hash_from_id(block)?; let mut raw_weight = &self .client - .storage(&block_hash, &key)? + .storage(block_hash, &key)? .ok_or(format!("Could not find System::BlockWeight for block: {}", block))? .0[..]; diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index 32fd5da7f95f0..ce2d52e57d641 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -193,7 +193,7 @@ impl StorageCmd { { let hash = client.usage_info().chain.best_hash; let empty_prefix = StorageKey(Vec::new()); - let mut keys = client.storage_keys(&hash, &empty_prefix)?; + let mut keys = client.storage_keys(hash, &empty_prefix)?; let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); @@ -201,7 +201,7 @@ impl StorageCmd { info!("Warmup round {}/{}", i + 1, self.params.warmups); for key in keys.as_slice() { let _ = client - .storage(&hash, &key) + .storage(hash, &key) .expect("Checked above to exist") .ok_or("Value unexpectedly empty"); } diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs index 2df7e697039e8..20c41e4a5196b 100644 --- a/utils/frame/benchmarking-cli/src/storage/read.rs +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -43,7 +43,7 @@ impl StorageCmd { info!("Preparing keys from block {}", best_hash); // Load all keys and randomly shuffle them. let empty_prefix = StorageKey(Vec::new()); - let mut keys = client.storage_keys(&best_hash, &empty_prefix)?; + let mut keys = client.storage_keys(best_hash, &empty_prefix)?; let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); @@ -55,7 +55,7 @@ impl StorageCmd { match (self.params.include_child_trees, self.is_child_key(key.clone().0)) { (true, Some(info)) => { // child tree key - let child_keys = client.child_storage_keys(&best_hash, &info, &empty_prefix)?; + let child_keys = client.child_storage_keys(best_hash, &info, &empty_prefix)?; for ck in child_keys { child_nodes.push((ck.clone(), info.clone())); } @@ -64,7 +64,7 @@ impl StorageCmd { // regular key let start = Instant::now(); let v = client - .storage(&best_hash, &key) + .storage(best_hash, &key) .expect("Checked above to exist") .ok_or("Value unexpectedly empty")?; record.append(v.0.len(), start.elapsed())?; @@ -79,7 +79,7 @@ impl StorageCmd { for (key, info) in child_nodes.as_slice() { let start = Instant::now(); let v = client - .child_storage(&best_hash, info, key) + .child_storage(best_hash, info, key) .expect("Checked above to exist") .ok_or("Value unexpectedly empty")?; record.append(v.0.len(), start.elapsed())?; diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index 2ee37a5619136..55a7b60d55552 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -77,7 +77,7 @@ impl StorageCmd { match (self.params.include_child_trees, self.is_child_key(k.to_vec())) { (true, Some(info)) => { let child_keys = - client.child_storage_keys_iter(&best_hash, info.clone(), None, None)?; + client.child_storage_keys_iter(best_hash, info.clone(), None, None)?; for ck in child_keys { child_nodes.push((ck.clone(), info.clone())); } @@ -124,7 +124,7 @@ impl StorageCmd { for (key, info) in child_nodes { if let Some(original_v) = client - .child_storage(&best_hash, &info.clone(), &key) + .child_storage(best_hash, &info.clone(), &key) .expect("Checked above to exist") { let mut new_v = vec![0; original_v.0.len()]; diff --git a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index c3d3ec816f97e..ab180c7d45d5b 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -145,7 +145,7 @@ where self.deny_unsafe.check_if_safe()?; let hash = at.unwrap_or_else(|| self.client.info().best_hash); - let state = self.backend.state_at(&hash).map_err(error_into_rpc_err)?; + let state = self.backend.state_at(hash).map_err(error_into_rpc_err)?; let (top, child) = migration_status(&state).map_err(error_into_rpc_err)?; Ok(MigrationStatusResult { From 61e7ad45da3cfd805f1e85e5b1771d88105f9467 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Tue, 8 Nov 2022 00:57:29 +0200 Subject: [PATCH 1347/1472] Do not update peer information if ancestor search is in progress (#12631) * Do not update peer information if ancestor search is in progress If block announcement is received from a peer while ancestor search for that same peer is still in progress, do not update the peer's best hash and best number as that causes the ancestor search to yield different information from what was expected and can cause, for example, a fork of lower height not be be downloaded. * Block until peers are in sync --- client/network/sync/src/lib.rs | 10 +++++----- client/network/test/src/sync.rs | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 7c484835951e8..75ecb9322ca78 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -2043,17 +2043,17 @@ where return PollBlockAnnounceValidation::Nothing { is_best, who, announce } }; + if let PeerSyncState::AncestorSearch { .. } = peer.state { + trace!(target: "sync", "Peer state is ancestor search."); + return PollBlockAnnounceValidation::Nothing { is_best, who, announce } + } + if is_best { // update their best block peer.best_number = number; peer.best_hash = hash; } - if let PeerSyncState::AncestorSearch { .. } = peer.state { - trace!(target: "sync", "Peer state is ancestor search."); - return PollBlockAnnounceValidation::Nothing { is_best, who, announce } - } - // If the announced block is the best they have and is not ahead of us, our common number // is either one further ahead or it's the one they just announced, if we know about it. if is_best { diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index bbba3bc6ded62..4515677d0b1e0 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -549,6 +549,10 @@ fn syncs_header_only_forks() { while !net.peer(1).has_block(small_hash) { net.block_until_idle(); } + + net.block_until_sync(); + assert_eq!(net.peer(0).client().info().best_hash, net.peer(1).client().info().best_hash); + assert_ne!(small_hash, net.peer(0).client().info().best_hash); } #[test] From 853bd559f68b8a21a421471d3992d54b25d8619f Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 8 Nov 2022 09:07:32 +0100 Subject: [PATCH 1348/1472] Pipeline with ci image with rust 1.65 (#12628) * Pipeline with ci image with rust 1.65 * fix tests * use image with sha --- .gitlab-ci.yml | 2 +- .../no_std_genesis_config.stderr | 13 ------ .../undefined_event_part.stderr | 13 ------ .../undefined_genesis_config_part.stderr | 13 ------ .../undefined_origin_part.stderr | 13 ------ .../call_argument_invalid_bound.stderr | 2 +- .../call_argument_invalid_bound_2.stderr | 20 ++++----- .../call_argument_invalid_bound_3.stderr | 2 +- .../pallet_ui/event_field_not_member.stderr | 2 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 44 +++++++++---------- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 44 +++++++++---------- .../pallet_ui/storage_info_unsatisfied.stderr | 2 +- .../storage_info_unsatisfied_nmap.stderr | 4 +- ...reference_in_impl_runtime_apis_call.stderr | 3 +- 14 files changed, 61 insertions(+), 116 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9053e39eb59bf..f663057faaad5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,7 +47,7 @@ variables: CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux:production" + CI_IMAGE: "paritytech/ci-linux@sha256:c977b383c2033de50083fad18f6b9e698644230455e016ba708da00eb98d4683" # staging 07.11.2022 RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr index 26c0717c0ad37..d35565fb933ac 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr @@ -29,19 +29,6 @@ help: consider importing this struct | 1 | use frame_system::GenesisConfig; | -help: if you import `GenesisConfig`, refer to it directly - | -40 - construct_runtime! { -41 - pub enum Runtime where -42 - Block = Block, -43 - NodeBlock = Block, -44 - UncheckedExtrinsic = UncheckedExtrinsic -45 - { -46 - System: frame_system::{Pallet, Call, Storage, Config, Event}, -47 - Pallet: test_pallet::{Pallet, Config}, -48 - } -49 - } - | error[E0283]: type annotations needed --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index 8f2bf7be15749..ff8ecf3041bf6 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -32,16 +32,3 @@ help: consider importing this enum | 1 | use frame_system::Event; | -help: if you import `Event`, refer to it directly - | -49 - construct_runtime! { -50 - pub enum Runtime where -51 - Block = Block, -52 - NodeBlock = Block, -53 - UncheckedExtrinsic = UncheckedExtrinsic -54 - { -55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, -56 - Pallet: pallet::{Pallet, Event}, -57 - } -58 - } - | diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr index aae3aaa80c865..046369e1112b0 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr @@ -32,19 +32,6 @@ help: consider importing this struct | 1 | use frame_system::GenesisConfig; | -help: if you import `GenesisConfig`, refer to it directly - | -49 - construct_runtime! { -50 - pub enum Runtime where -51 - Block = Block, -52 - NodeBlock = Block, -53 - UncheckedExtrinsic = UncheckedExtrinsic -54 - { -55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, -56 - Pallet: pallet::{Pallet, Config}, -57 - } -58 - } - | error[E0283]: type annotations needed --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr index 1a8fe64da1758..4907053b12877 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr @@ -32,19 +32,6 @@ help: consider importing this type alias | 1 | use frame_system::Origin; | -help: if you import `Origin`, refer to it directly - | -49 - construct_runtime! { -50 - pub enum Runtime where -51 - Block = Block, -52 - NodeBlock = Block, -53 - UncheckedExtrinsic = UncheckedExtrinsic -54 - { -55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, -56 - Pallet: pallet::{Pallet, Origin}, -57 - } -58 - } - | error[E0282]: type annotations needed --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index 86e8d33c8dad1..62d8649f8af49 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -5,7 +5,7 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | ^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&::Bar` + = note: required for `&::Bar` to implement `std::fmt::Debug` = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index c6acccaaba7d4..f486c071631ea 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -5,7 +5,7 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | ^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&::Bar` + = note: required for `&::Bar` to implement `std::fmt::Debug` = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied @@ -21,23 +21,21 @@ error[E0369]: binary operation `==` cannot be applied to type `&::Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:1:1 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 | -1 | #[frame_support::pallet] - | ^----------------------- - | | - | _in this procedural macro expansion - | | +1 | / #[frame_support::pallet] 2 | | mod pallet { 3 | | use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; 4 | | use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; ... | 16 | | 17 | | #[pallet::call] - | |__________________^ the trait `WrapperTypeEncode` is not implemented for `::Bar` + | |__________________- required by a bound introduced by this call +... +20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar` | - = note: required because of the requirements on the impl of `Encode` for `::Bar` - = note: this error originates in the derive macro `frame_support::codec::Encode` which comes from the expansion of the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: required for `::Bar` to implement `Encode` error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound_2.rs:17:12 @@ -45,4 +43,4 @@ error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is 17 | #[pallet::call] | ^^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` | - = note: required because of the requirements on the impl of `Decode` for `::Bar` + = note: required for `::Bar` to implement `Decode` diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr index 4a0b2ea67c7d6..6e51bf2dbf862 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr @@ -6,7 +6,7 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `Bar` = note: add `#[derive(Debug)]` to `Bar` or manually `impl std::fmt::Debug for Bar` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Bar` + = note: required for `&Bar` to implement `std::fmt::Debug` = note: required for the cast from `&Bar` to the object type `dyn std::fmt::Debug` help: consider annotating `Bar` with `#[derive(Debug)]` | diff --git a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr index f95da9deef90a..1161f4a190231 100644 --- a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr +++ b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr @@ -17,5 +17,5 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | ^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&::Bar` + = note: required for `&::Bar` to implement `std::fmt::Debug` = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index cced83f207c41..42ef5a34e4c30 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -9,9 +9,9 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied Box Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes - = note: required because of the requirements on the impl of `Decode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `Decode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:10:12 @@ -29,9 +29,9 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> and 278 others - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:10:12 @@ -49,10 +49,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Vec bytes::bytes::Bytes and 3 others - = note: required because of the requirements on the impl of `Encode` for `Bar` - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `Encode` + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 @@ -70,8 +70,8 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D, E) (A, B, C, D, E, F) and 161 others - = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `StaticTypeInfo` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 @@ -84,9 +84,9 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied Box Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes - = note: required because of the requirements on the impl of `Decode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `Decode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 @@ -104,9 +104,9 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> and 278 others - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:21:12 @@ -124,7 +124,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Vec bytes::bytes::Bytes and 3 others - = note: required because of the requirements on the impl of `Encode` for `Bar` - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `Encode` + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index ab377e05d3901..461d63ebb0d9c 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -9,9 +9,9 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied Box Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes - = note: required because of the requirements on the impl of `Decode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `Decode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:10:12 @@ -29,9 +29,9 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> and 278 others - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:10:12 @@ -49,10 +49,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Vec bytes::bytes::Bytes and 3 others - = note: required because of the requirements on the impl of `Encode` for `Bar` - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `Encode` + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 @@ -70,8 +70,8 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D, E) (A, B, C, D, E, F) and 161 others - = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `StaticTypeInfo` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 @@ -84,9 +84,9 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied Box Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes - = note: required because of the requirements on the impl of `Decode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `Decode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 @@ -104,9 +104,9 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> and 278 others - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:21:12 @@ -124,7 +124,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Vec bytes::bytes::Bytes and 3 others - = note: required because of the requirements on the impl of `Encode` for `Bar` - = note: required because of the requirements on the impl of `FullEncode` for `Bar` - = note: required because of the requirements on the impl of `FullCodec` for `Bar` - = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `Bar` to implement `Encode` + = note: required for `Bar` to implement `FullEncode` + = note: required for `Bar` to implement `FullCodec` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index 8d3d7a71a313e..cce9fa70b3da5 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -14,4 +14,4 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) and 78 others - = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageInfoTrait` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index ebf24a1232e3c..877485dda2084 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -14,5 +14,5 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) and 78 others - = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` - = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` + = note: required for `Key` to implement `KeyGeneratorMaxEncodedLen` + = note: required for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` to implement `StorageInfoTrait` diff --git a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index 6a99dcd3a1aed..06f8226ec88bf 100644 --- a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -35,6 +35,5 @@ note: associated function defined here | ^^^^ help: consider removing the borrow | -19 - fn test(data: &u64) { -19 + fn test(data: &u64) { +19 | fn test(data: &u64) { | From 14c3ef3898802eec15a6c4a3a711e002a73fffa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 8 Nov 2022 10:04:55 +0100 Subject: [PATCH 1349/1472] `sp_trie::Recorder`: Fix recording the same key for different tries (#12636) With `StateVersion::V1` values over a certain size are not inlined and being put into the backend with their own hash. When accessing a value in the trie with a recorder, we check if the value is maybe already recorded and thus, we can check the cache. To check if a value is already recorded, we use the key of the value to differentiate them. The problem is when there are multiple tries, like multiple child tries that all have different values under the same key. Before this pull request we didn't have differentiated for which trie we already had recorded a (key, value) pair. This is now done by also taking the storage root into account in the recorder to differentiate the different (key, value) pair in the tries. --- primitives/state-machine/src/trie_backend.rs | 91 +++++++++++++++++++ .../state-machine/src/trie_backend_essence.rs | 71 ++++++++------- primitives/trie/src/cache/mod.rs | 4 +- primitives/trie/src/recorder.rs | 26 +++++- 4 files changed, 153 insertions(+), 39 deletions(-) diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index 20bb2c592e925..da4250b6ba3e1 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -1117,4 +1117,95 @@ pub mod tests { ); } } + + /// Test to ensure that recording the same `key` for different tries works as expected. + /// + /// Each trie stores a different value under the same key. The values are big enough to + /// be not inlined with `StateVersion::V1`, this is important to test the expected behavior. The + /// trie recorder is expected to differentiate key access based on the different storage roots + /// of the tries. + #[test] + fn recording_same_key_access_in_different_tries() { + recording_same_key_access_in_different_tries_inner(StateVersion::V0); + recording_same_key_access_in_different_tries_inner(StateVersion::V1); + } + fn recording_same_key_access_in_different_tries_inner(state_version: StateVersion) { + let key = b"test_key".to_vec(); + // Use some big values to ensure that we don't keep them inline + let top_trie_val = vec![1; 1024]; + let child_trie_1_val = vec![2; 1024]; + let child_trie_2_val = vec![3; 1024]; + + let child_info_1 = ChildInfo::new_default(b"sub1"); + let child_info_2 = ChildInfo::new_default(b"sub2"); + let child_info_1 = &child_info_1; + let child_info_2 = &child_info_2; + let contents = vec![ + (None, vec![(key.clone(), Some(top_trie_val.clone()))]), + (Some(child_info_1.clone()), vec![(key.clone(), Some(child_trie_1_val.clone()))]), + (Some(child_info_2.clone()), vec![(key.clone(), Some(child_trie_2_val.clone()))]), + ]; + let in_memory = new_in_mem::>(); + let in_memory = in_memory.update(contents, state_version); + let child_storage_keys = vec![child_info_1.to_owned(), child_info_2.to_owned()]; + let in_memory_root = in_memory + .full_storage_root( + std::iter::empty(), + child_storage_keys.iter().map(|k| (k, std::iter::empty())), + state_version, + ) + .0; + assert_eq!(in_memory.storage(&key).unwrap().unwrap(), top_trie_val); + assert_eq!(in_memory.child_storage(child_info_1, &key).unwrap().unwrap(), child_trie_1_val); + assert_eq!(in_memory.child_storage(child_info_2, &key).unwrap().unwrap(), child_trie_2_val); + + for cache in [Some(SharedTrieCache::new(CacheSize::Unlimited)), None] { + // Run multiple times to have a different cache conditions. + for i in 0..5 { + eprintln!("Running with cache {}, iteration {}", cache.is_some(), i); + + if let Some(cache) = &cache { + if i == 2 { + cache.reset_node_cache(); + } else if i == 3 { + cache.reset_value_cache(); + } + } + + let trie = in_memory.as_trie_backend(); + let trie_root = trie.storage_root(std::iter::empty(), state_version).0; + assert_eq!(in_memory_root, trie_root); + + let proving = TrieBackendBuilder::wrap(&trie) + .with_recorder(Recorder::default()) + .with_optional_cache(cache.as_ref().map(|c| c.local_cache())) + .build(); + assert_eq!(proving.storage(&key).unwrap().unwrap(), top_trie_val); + assert_eq!( + proving.child_storage(child_info_1, &key).unwrap().unwrap(), + child_trie_1_val + ); + assert_eq!( + proving.child_storage(child_info_2, &key).unwrap().unwrap(), + child_trie_2_val + ); + + let proof = proving.extract_proof().unwrap(); + + let proof_check = + create_proof_check_backend::(in_memory_root.into(), proof) + .unwrap(); + + assert_eq!(proof_check.storage(&key).unwrap().unwrap(), top_trie_val); + assert_eq!( + proof_check.child_storage(child_info_1, &key).unwrap().unwrap(), + child_trie_1_val + ); + assert_eq!( + proof_check.child_storage(child_info_2, &key).unwrap().unwrap(), + child_trie_2_val + ); + } + } + } } diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index cd2a71163e2ee..cdd1bb0bba055 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -177,7 +177,7 @@ impl, H: Hasher, C: AsLocalTrieCache> TrieBackendEss ) -> R, ) -> R { let storage_root = storage_root.unwrap_or_else(|| self.root); - let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder()); + let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder(storage_root)); let recorder = match recorder.as_mut() { Some(recorder) => Some(recorder as &mut dyn TrieRecorder), None => None, @@ -209,16 +209,19 @@ impl, H: Hasher, C: AsLocalTrieCache> TrieBackendEss /// This function must only be used when the operation in `callback` is /// calculating a `storage_root`. It is expected that `callback` returns /// the new storage root. This is required to register the changes in the cache - /// for the correct storage root. + /// for the correct storage root. The given `storage_root` corresponds to the root of the "old" + /// trie. If the value is not given, `self.root` is used. #[cfg(feature = "std")] fn with_recorder_and_cache_for_storage_root( &self, + storage_root: Option, callback: impl FnOnce( Option<&mut dyn TrieRecorder>, Option<&mut dyn TrieCache>>, ) -> (Option, R), ) -> R { - let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder()); + let storage_root = storage_root.unwrap_or_else(|| self.root); + let mut recorder = self.recorder.as_ref().map(|r| r.as_trie_recorder(storage_root)); let recorder = match recorder.as_mut() { Some(recorder) => Some(recorder as &mut dyn TrieRecorder), None => None, @@ -244,6 +247,7 @@ impl, H: Hasher, C: AsLocalTrieCache> TrieBackendEss #[cfg(not(feature = "std"))] fn with_recorder_and_cache_for_storage_root( &self, + _: Option, callback: impl FnOnce( Option<&mut dyn TrieRecorder>, Option<&mut dyn TrieCache>>, @@ -675,7 +679,7 @@ where ) -> (H::Out, S::Overlay) { let mut write_overlay = S::Overlay::default(); - let root = self.with_recorder_and_cache_for_storage_root(|recorder, cache| { + let root = self.with_recorder_and_cache_for_storage_root(None, |recorder, cache| { let mut eph = Ephemeral::new(self.backend_storage(), &mut write_overlay); let res = match state_version { StateVersion::V0 => delta_trie_root::, _, _, _, _, _>( @@ -719,35 +723,36 @@ where }, }; - let new_child_root = self.with_recorder_and_cache_for_storage_root(|recorder, cache| { - let mut eph = Ephemeral::new(self.backend_storage(), &mut write_overlay); - match match state_version { - StateVersion::V0 => - child_delta_trie_root::, _, _, _, _, _, _>( - child_info.keyspace(), - &mut eph, - child_root, - delta, - recorder, - cache, - ), - StateVersion::V1 => - child_delta_trie_root::, _, _, _, _, _, _>( - child_info.keyspace(), - &mut eph, - child_root, - delta, - recorder, - cache, - ), - } { - Ok(ret) => (Some(ret), ret), - Err(e) => { - warn!(target: "trie", "Failed to write to trie: {}", e); - (None, child_root) - }, - } - }); + let new_child_root = + self.with_recorder_and_cache_for_storage_root(Some(child_root), |recorder, cache| { + let mut eph = Ephemeral::new(self.backend_storage(), &mut write_overlay); + match match state_version { + StateVersion::V0 => + child_delta_trie_root::, _, _, _, _, _, _>( + child_info.keyspace(), + &mut eph, + child_root, + delta, + recorder, + cache, + ), + StateVersion::V1 => + child_delta_trie_root::, _, _, _, _, _, _>( + child_info.keyspace(), + &mut eph, + child_root, + delta, + recorder, + cache, + ), + } { + Ok(ret) => (Some(ret), ret), + Err(e) => { + warn!(target: "trie", "Failed to write to trie: {}", e); + (None, child_root) + }, + } + }); let is_default = new_child_root == default_root; diff --git a/primitives/trie/src/cache/mod.rs b/primitives/trie/src/cache/mod.rs index f6a447763a80e..85539cf626857 100644 --- a/primitives/trie/src/cache/mod.rs +++ b/primitives/trie/src/cache/mod.rs @@ -490,7 +490,7 @@ mod tests { { let mut cache = local_cache.as_trie_db_cache(root); - let mut recorder = recorder.as_trie_recorder(); + let mut recorder = recorder.as_trie_recorder(root); let trie = TrieDBBuilder::::new(&db, &root) .with_cache(&mut cache) .with_recorder(&mut recorder) @@ -538,7 +538,7 @@ mod tests { { let mut db = db.clone(); let mut cache = local_cache.as_trie_db_cache(root); - let mut recorder = recorder.as_trie_recorder(); + let mut recorder = recorder.as_trie_recorder(root); let mut trie = TrieDBMutBuilder::::from_existing(&mut db, &mut new_root) .with_cache(&mut cache) .with_recorder(&mut recorder) diff --git a/primitives/trie/src/recorder.rs b/primitives/trie/src/recorder.rs index 6fbf698592a31..bc67cfc287942 100644 --- a/primitives/trie/src/recorder.rs +++ b/primitives/trie/src/recorder.rs @@ -41,7 +41,7 @@ const LOG_TARGET: &str = "trie-recorder"; /// The internals of [`Recorder`]. struct RecorderInner { /// The keys for that we have recorded the trie nodes and if we have recorded up to the value. - recorded_keys: HashMap, RecordedForKey>, + recorded_keys: HashMap, RecordedForKey>>, /// The encoded nodes we accessed while recording. accessed_nodes: HashMap>, } @@ -80,9 +80,16 @@ impl Clone for Recorder { impl Recorder { /// Returns the recorder as [`TrieRecorder`](trie_db::TrieRecorder) compatible type. - pub fn as_trie_recorder(&self) -> impl trie_db::TrieRecorder + '_ { + /// + /// - `storage_root`: The storage root of the trie for which accesses are recorded. This is + /// important when recording access to different tries at once (like top and child tries). + pub fn as_trie_recorder( + &self, + storage_root: H::Out, + ) -> impl trie_db::TrieRecorder + '_ { TrieRecorder:: { inner: self.inner.lock(), + storage_root, encoded_size_estimation: self.encoded_size_estimation.clone(), _phantom: PhantomData, } @@ -132,6 +139,7 @@ impl Recorder { /// The [`TrieRecorder`](trie_db::TrieRecorder) implementation. struct TrieRecorder { inner: I, + storage_root: H::Out, encoded_size_estimation: Arc, _phantom: PhantomData, } @@ -191,6 +199,8 @@ impl>> trie_db::TrieRecord self.inner .recorded_keys + .entry(self.storage_root) + .or_default() .entry(full_key.to_vec()) .and_modify(|e| *e = RecordedForKey::Value) .or_insert(RecordedForKey::Value); @@ -206,6 +216,8 @@ impl>> trie_db::TrieRecord // accounted for by the recorded node that holds the hash. self.inner .recorded_keys + .entry(self.storage_root) + .or_default() .entry(full_key.to_vec()) .or_insert(RecordedForKey::Hash); }, @@ -221,6 +233,8 @@ impl>> trie_db::TrieRecord // that the value doesn't exist in the trie. self.inner .recorded_keys + .entry(self.storage_root) + .or_default() .entry(full_key.to_vec()) .and_modify(|e| *e = RecordedForKey::Value) .or_insert(RecordedForKey::Value); @@ -231,7 +245,11 @@ impl>> trie_db::TrieRecord } fn trie_nodes_recorded_for_key(&self, key: &[u8]) -> RecordedForKey { - self.inner.recorded_keys.get(key).copied().unwrap_or(RecordedForKey::None) + self.inner + .recorded_keys + .get(&self.storage_root) + .and_then(|k| k.get(key).copied()) + .unwrap_or(RecordedForKey::None) } } @@ -267,7 +285,7 @@ mod tests { let recorder = Recorder::default(); { - let mut trie_recorder = recorder.as_trie_recorder(); + let mut trie_recorder = recorder.as_trie_recorder(root); let trie = TrieDBBuilder::::new(&db, &root) .with_recorder(&mut trie_recorder) .build(); From 327180db5cb2744dcd3de354195d79ed8402d8a0 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 8 Nov 2022 11:21:43 +0100 Subject: [PATCH 1350/1472] Fix UI tests (#12642) --- .../tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr index 2f8d0cc761ab2..a5ec31a9bb4e7 100644 --- a/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr +++ b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr @@ -14,4 +14,4 @@ error[E0277]: the trait bound `Vec: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) and 78 others - = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageMyStorage, Vec>` + = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageMyStorage, Vec>` to implement `StorageInfoTrait` From a1c1286d2ca6360a16d772cc8bea2190f77f4d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 8 Nov 2022 11:33:43 +0100 Subject: [PATCH 1351/1472] `payment_queryInfo`: Make it work with `WeightV2` (#12633) * `payment_queryInfo`: Make it work with `WeighV2` The runtime api for querying the payment info depends on the `Weight` type and broke for old runtimes that still use the `WeighV1`. This pull requests fixes this by: 1. Bumping the version of the runtime api. 2. Making the node side code use the correct runtime api function depending on the version of the runtime api. 3. Make the RPC always return `WeighV1`. Users of the api should switch to `state_call` and decide based on the version of the runtime api which `Weight` type is being returned. * Fix tests * Review comment --- Cargo.lock | 2 + frame/transaction-payment/rpc/Cargo.toml | 1 + .../rpc/runtime-api/Cargo.toml | 2 + .../rpc/runtime-api/src/lib.rs | 4 ++ frame/transaction-payment/rpc/src/lib.rs | 47 +++++++++++++++---- frame/transaction-payment/src/types.rs | 15 ++++-- primitives/weights/src/lib.rs | 6 +-- 7 files changed, 61 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 510161e225732..48205d9bd86da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6326,6 +6326,7 @@ dependencies = [ "sp-core", "sp-rpc", "sp-runtime", + "sp-weights", ] [[package]] @@ -6336,6 +6337,7 @@ dependencies = [ "parity-scale-codec", "sp-api", "sp-runtime", + "sp-weights", ] [[package]] diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 16c2cc55efefb..9dd42c12c8bbf 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -21,3 +21,4 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-weights = { version = "4.0.0", path = "../../../primitives/weights" } diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 5e1cb46753524..c0b816684a2f3 100644 --- a/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -17,6 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-weights = { version = "4.0.0", default-features = false, path = "../../../../primitives/weights" } [features] default = ["std"] @@ -25,4 +26,5 @@ std = [ "pallet-transaction-payment/std", "sp-api/std", "sp-runtime/std", + "sp-weights/std", ] diff --git a/frame/transaction-payment/rpc/runtime-api/src/lib.rs b/frame/transaction-payment/rpc/runtime-api/src/lib.rs index 6944593daa57a..10fd2a9e61fc1 100644 --- a/frame/transaction-payment/rpc/runtime-api/src/lib.rs +++ b/frame/transaction-payment/rpc/runtime-api/src/lib.rs @@ -25,13 +25,17 @@ use sp_runtime::traits::MaybeDisplay; pub use pallet_transaction_payment::{FeeDetails, InclusionFee, RuntimeDispatchInfo}; sp_api::decl_runtime_apis! { + #[api_version(2)] pub trait TransactionPaymentApi where Balance: Codec + MaybeDisplay, { + #[changed_in(2)] + fn query_info(uxt: Block::Extrinsic, len: u32) -> RuntimeDispatchInfo; fn query_info(uxt: Block::Extrinsic, len: u32) -> RuntimeDispatchInfo; fn query_fee_details(uxt: Block::Extrinsic, len: u32) -> FeeDetails; } + #[api_version(2)] pub trait TransactionPaymentCallApi where Balance: Codec + MaybeDisplay, diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index 0c7e26cec0f58..19007d37963ec 100644 --- a/frame/transaction-payment/rpc/src/lib.rs +++ b/frame/transaction-payment/rpc/src/lib.rs @@ -26,7 +26,7 @@ use jsonrpsee::{ types::error::{CallError, ErrorCode, ErrorObject}, }; use pallet_transaction_payment_rpc_runtime_api::{FeeDetails, InclusionFee, RuntimeDispatchInfo}; -use sp_api::ProvideRuntimeApi; +use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::Bytes; use sp_rpc::number::NumberOrHex; @@ -82,8 +82,10 @@ impl From for i32 { } impl - TransactionPaymentApiServer<::Hash, RuntimeDispatchInfo> - for TransactionPayment + TransactionPaymentApiServer< + ::Hash, + RuntimeDispatchInfo, + > for TransactionPayment where Block: BlockT, C: ProvideRuntimeApi + HeaderBackend + Send + Sync + 'static, @@ -94,7 +96,7 @@ where &self, encoded_xt: Bytes, at: Option, - ) -> RpcResult> { + ) -> RpcResult> { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); @@ -107,14 +109,41 @@ where Some(format!("{:?}", e)), )) })?; - api.query_info(&at, uxt, encoded_len).map_err(|e| { + + fn map_err(error: impl ToString, desc: &'static str) -> CallError { CallError::Custom(ErrorObject::owned( Error::RuntimeError.into(), - "Unable to query dispatch info.", - Some(e.to_string()), + desc, + Some(error.to_string()), )) - .into() - }) + } + + let api_version = api + .api_version::>(&at) + .map_err(|e| map_err(e, "Failed to get transaction payment runtime api version"))? + .ok_or_else(|| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Transaction payment runtime api wasn't found in the runtime", + None::, + )) + })?; + + if api_version < 2 { + #[allow(deprecated)] + api.query_info_before_version_2(&at, uxt, encoded_len) + .map_err(|e| map_err(e, "Unable to query dispatch info.").into()) + } else { + let res = api + .query_info(&at, uxt, encoded_len) + .map_err(|e| map_err(e, "Unable to query dispatch info."))?; + + Ok(RuntimeDispatchInfo { + weight: sp_weights::OldWeight(res.weight.ref_time()), + class: res.class, + partial_fee: res.partial_fee, + }) + } } fn query_fee_details( diff --git a/frame/transaction-payment/src/types.rs b/frame/transaction-payment/src/types.rs index fff41ef6937f5..d1a480b64e116 100644 --- a/frame/transaction-payment/src/types.rs +++ b/frame/transaction-payment/src/types.rs @@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize}; use sp_runtime::traits::{AtLeast32BitUnsigned, Zero}; use sp_std::prelude::*; -use frame_support::{dispatch::DispatchClass, weights::Weight}; +use frame_support::dispatch::DispatchClass; /// The base fee and adjusted weight and length fees constitute the _inclusion fee_. #[derive(Encode, Decode, Clone, Eq, PartialEq)] @@ -94,9 +94,15 @@ impl FeeDetails { #[derive(Eq, PartialEq, Encode, Decode, Default)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] -#[cfg_attr(feature = "std", serde(bound(serialize = "Balance: std::fmt::Display")))] -#[cfg_attr(feature = "std", serde(bound(deserialize = "Balance: std::str::FromStr")))] -pub struct RuntimeDispatchInfo { +#[cfg_attr( + feature = "std", + serde(bound(serialize = "Balance: std::fmt::Display, Weight: Serialize")) +)] +#[cfg_attr( + feature = "std", + serde(bound(deserialize = "Balance: std::str::FromStr, Weight: Deserialize<'de>")) +)] +pub struct RuntimeDispatchInfo { /// Weight of this dispatch. pub weight: Weight, /// Class of this dispatch. @@ -131,6 +137,7 @@ mod serde_balance { #[cfg(test)] mod tests { use super::*; + use frame_support::weights::Weight; #[test] fn should_serialize_and_deserialize_properly_with_string() { diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs index e1ac7fcd4e892..954fea91e28dc 100644 --- a/primitives/weights/src/lib.rs +++ b/primitives/weights/src/lib.rs @@ -26,8 +26,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -extern crate self as sp_weights; - mod weight_v2; use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; @@ -70,6 +68,8 @@ pub mod constants { MaxEncodedLen, TypeInfo, )] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "std", serde(transparent))] pub struct OldWeight(pub u64); /// The weight of database operations that the runtime can invoke. @@ -106,7 +106,7 @@ impl RuntimeDbWeight { /// coeff_integer * x^(degree) + coeff_frac * x^(degree) /// ``` /// -/// The `negative` value encodes whether the term is added or substracted from the +/// The `negative` value encodes whether the term is added or subtracted from the /// overall polynomial result. #[derive(Clone, Encode, Decode, TypeInfo)] pub struct WeightToFeeCoefficient { From 335007ca286c964b8f64d47f20a7f4e808b76596 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 8 Nov 2022 11:58:02 +0100 Subject: [PATCH 1352/1472] State-db refactoring (#12239) * Prune discarded blocks immediately * state-db refactoring part 1 * Some renames * Get rid of pending state * Revert "Prune discarded blocks immediately" This reverts commit 790f54038b52ff379a573ed0806f38d09af098ec. * Cleanup * Make clippy happy * Minor changes --- client/db/src/lib.rs | 18 +- client/state-db/src/lib.rs | 57 +--- client/state-db/src/noncanonical.rs | 245 ++++------------ client/state-db/src/pruning.rs | 418 +++++++--------------------- 4 files changed, 181 insertions(+), 557 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index fc031e2aaba59..3bbff1625f2f9 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1994,15 +1994,15 @@ impl sc_client_api::backend::Backend for Backend { let usage = operation.old_state.usage_info(); self.state_usage.merge_sm(usage); - match self.try_commit_operation(operation) { - Ok(_) => { - self.storage.state_db.apply_pending(); - Ok(()) - }, - e @ Err(_) => { - self.storage.state_db.revert_pending(); - e - }, + if let Err(e) = self.try_commit_operation(operation) { + let state_meta_db = StateMetaDb(self.storage.db.clone()); + self.storage + .state_db + .reset(state_meta_db) + .map_err(sp_blockchain::Error::from_state_db)?; + Err(e) + } else { + Ok(()) } } diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index f21b707a489f0..01a198a1b3c1e 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -291,6 +291,7 @@ pub struct StateDbSync { non_canonical: NonCanonicalOverlay, pruning: Option>, pinned: HashMap, + ref_counting: bool, } impl @@ -311,7 +312,7 @@ impl PruningMode::ArchiveAll | PruningMode::ArchiveCanonical => None, }; - Ok(StateDbSync { mode, non_canonical, pruning, pinned: Default::default() }) + Ok(StateDbSync { mode, non_canonical, pruning, pinned: Default::default(), ref_counting }) } fn insert_block( @@ -372,9 +373,9 @@ impl match self.pruning.as_ref() { None => IsPruned::NotPruned, Some(pruning) => match pruning.have_block(hash, number) { - HaveBlock::NotHave => IsPruned::Pruned, - HaveBlock::Have => IsPruned::NotPruned, - HaveBlock::MayHave => IsPruned::MaybePruned, + HaveBlock::No => IsPruned::Pruned, + HaveBlock::Yes => IsPruned::NotPruned, + HaveBlock::Maybe => IsPruned::MaybePruned, }, } } @@ -444,9 +445,9 @@ impl let have_block = self.non_canonical.have_block(hash) || self.pruning.as_ref().map_or(false, |pruning| { match pruning.have_block(hash, number) { - HaveBlock::NotHave => false, - HaveBlock::Have => true, - HaveBlock::MayHave => hint(), + HaveBlock::No => false, + HaveBlock::Yes => true, + HaveBlock::Maybe => hint(), } }); if have_block { @@ -496,30 +497,6 @@ impl db.get(key.as_ref()).map_err(Error::Db) } - fn apply_pending(&mut self) { - self.non_canonical.apply_pending(); - if let Some(pruning) = &mut self.pruning { - pruning.apply_pending(); - } - let next_hash = self.pruning.as_mut().map(|p| p.next_hash()); - trace!( - target: "forks", - "First available: {:?} ({}), Last canon: {:?} ({}), Best forks: {:?}", - next_hash, - self.pruning.as_ref().map(|p| p.pending()).unwrap_or(0), - self.non_canonical.last_canonicalized_hash(), - self.non_canonical.last_canonicalized_block_number().unwrap_or(0), - self.non_canonical.top_level(), - ); - } - - fn revert_pending(&mut self) { - if let Some(pruning) = &mut self.pruning { - pruning.revert_pending(); - } - self.non_canonical.revert_pending(); - } - fn memory_info(&self) -> StateDbMemoryInfo { StateDbMemoryInfo { non_canonical: MemorySize::from_bytes(malloc_size(&self.non_canonical)), @@ -654,14 +631,11 @@ impl return self.db.read().is_pruned(hash, number) } - /// Apply all pending changes - pub fn apply_pending(&self) { - self.db.write().apply_pending(); - } - - /// Revert all pending changes - pub fn revert_pending(&self) { - self.db.write().revert_pending(); + /// Reset in-memory changes to the last disk-backed state. + pub fn reset(&self, db: D) -> Result<(), Error> { + let mut state_db = self.db.write(); + *state_db = StateDbSync::new(state_db.mode.clone(), state_db.ref_counting, db)?; + Ok(()) } /// Returns the current memory statistics of this instance. @@ -766,9 +740,7 @@ mod tests { ) .unwrap(), ); - state_db.apply_pending(); db.commit(&state_db.canonicalize_block(&H256::from_low_u64_be(1)).unwrap()); - state_db.apply_pending(); db.commit( &state_db .insert_block( @@ -779,11 +751,8 @@ mod tests { ) .unwrap(), ); - state_db.apply_pending(); db.commit(&state_db.canonicalize_block(&H256::from_low_u64_be(21)).unwrap()); - state_db.apply_pending(); db.commit(&state_db.canonicalize_block(&H256::from_low_u64_be(3)).unwrap()); - state_db.apply_pending(); (db, state_db) } diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index 559fc7ca023fe..3711cf7a42667 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -19,8 +19,6 @@ //! Canonicalization window. //! Maintains trees of block overlays and allows discarding trees/roots //! The overlays are added in `insert` and removed in `canonicalize`. -//! All pending changes are kept in memory until next call to `apply_pending` or -//! `revert_pending` use super::{to_meta_key, ChangeSet, CommitSet, DBValue, Error, Hash, MetaDb, StateDbError}; use codec::{Decode, Encode}; @@ -37,8 +35,6 @@ pub struct NonCanonicalOverlay { last_canonicalized: Option<(BlockHash, u64)>, levels: VecDeque>, parents: HashMap, - pending_canonicalizations: Vec, - pending_insertions: Vec, values: HashMap, // ref counted // would be deleted but kept around because block is pinned, ref counted. pinned: HashMap, @@ -229,8 +225,6 @@ impl NonCanonicalOverlay { last_canonicalized, levels, parents, - pending_canonicalizations: Default::default(), - pending_insertions: Default::default(), pinned: Default::default(), pinned_insertions: Default::default(), values, @@ -316,9 +310,8 @@ impl NonCanonicalOverlay { deleted: changeset.deleted, }; commit.meta.inserted.push((journal_key, journal_record.encode())); - trace!(target: "state-db", "Inserted uncanonicalized changeset {}.{} ({} inserted, {} deleted)", number, index, journal_record.inserted.len(), journal_record.deleted.len()); + trace!(target: "state-db", "Inserted uncanonicalized changeset {}.{} {:?} ({} inserted, {} deleted)", number, index, hash, journal_record.inserted.len(), journal_record.deleted.len()); insert_values(&mut self.values, journal_record.inserted); - self.pending_insertions.push(hash.clone()); Ok(commit) } @@ -355,24 +348,7 @@ impl NonCanonicalOverlay { } pub fn last_canonicalized_block_number(&self) -> Option { - match self.last_canonicalized.as_ref().map(|&(_, n)| n) { - Some(n) => Some(n + self.pending_canonicalizations.len() as u64), - None if !self.pending_canonicalizations.is_empty() => - Some(self.pending_canonicalizations.len() as u64), - _ => None, - } - } - - pub fn last_canonicalized_hash(&self) -> Option { - self.last_canonicalized.as_ref().map(|&(ref h, _)| h.clone()) - } - - pub fn top_level(&self) -> Vec<(BlockHash, u64)> { - let start = self.last_canonicalized_block_number().unwrap_or(0); - self.levels - .get(self.pending_canonicalizations.len()) - .map(|level| level.blocks.iter().map(|r| (r.hash.clone(), start)).collect()) - .unwrap_or_default() + self.last_canonicalized.as_ref().map(|&(_, n)| n) } /// Select a top-level root and canonicalized it. Discards all sibling subtrees and the root. @@ -384,10 +360,10 @@ impl NonCanonicalOverlay { commit: &mut CommitSet, ) -> Result { trace!(target: "state-db", "Canonicalizing {:?}", hash); - let level = self - .levels - .get(self.pending_canonicalizations.len()) - .ok_or(StateDbError::InvalidBlock)?; + let level = match self.levels.pop_front() { + Some(level) => level, + None => return Err(StateDbError::InvalidBlock), + }; let index = level .blocks .iter() @@ -396,91 +372,63 @@ impl NonCanonicalOverlay { let mut discarded_journals = Vec::new(); let mut discarded_blocks = Vec::new(); - for (i, overlay) in level.blocks.iter().enumerate() { - if i != index { + for (i, overlay) in level.blocks.into_iter().enumerate() { + let mut pinned_children = 0; + // That's the one we need to canonicalize + if i == index { + commit.data.inserted.extend(overlay.inserted.iter().map(|k| { + ( + k.clone(), + self.values + .get(k) + .expect("For each key in overlays there's a value in values") + .1 + .clone(), + ) + })); + commit.data.deleted.extend(overlay.deleted.clone()); + } else { + // Discard this overlay self.discard_journals( - self.pending_canonicalizations.len() + 1, + 0, &mut discarded_journals, &mut discarded_blocks, &overlay.hash, ); + pinned_children = discard_descendants( + &mut self.levels.as_mut_slices(), + &mut self.values, + &mut self.parents, + &self.pinned, + &mut self.pinned_insertions, + &overlay.hash, + ); + } + if self.pinned.contains_key(&overlay.hash) { + pinned_children += 1; + } + if pinned_children != 0 { + self.pinned_insertions + .insert(overlay.hash.clone(), (overlay.inserted, pinned_children)); + } else { + self.parents.remove(&overlay.hash); + discard_values(&mut self.values, overlay.inserted); } discarded_journals.push(overlay.journal_key.clone()); discarded_blocks.push(overlay.hash.clone()); } - - // get the one we need to canonicalize - let overlay = &level.blocks[index]; - commit.data.inserted.extend(overlay.inserted.iter().map(|k| { - ( - k.clone(), - self.values - .get(k) - .expect("For each key in overlays there's a value in values") - .1 - .clone(), - ) - })); - commit.data.deleted.extend(overlay.deleted.clone()); - commit.meta.deleted.append(&mut discarded_journals); - let canonicalized = - (hash.clone(), self.front_block_number() + self.pending_canonicalizations.len() as u64); + + let canonicalized = (hash.clone(), self.front_block_number()); commit .meta .inserted .push((to_meta_key(LAST_CANONICAL, &()), canonicalized.encode())); trace!(target: "state-db", "Discarding {} records", commit.meta.deleted.len()); - self.pending_canonicalizations.push(hash.clone()); - Ok(canonicalized.1) - } - fn apply_canonicalizations(&mut self) { - let last = self.pending_canonicalizations.last().cloned(); - let count = self.pending_canonicalizations.len() as u64; - for hash in self.pending_canonicalizations.drain(..) { - trace!(target: "state-db", "Post canonicalizing {:?}", hash); - let level = - self.levels.pop_front().expect("Hash validity is checked in `canonicalize`"); - let index = level - .blocks - .iter() - .position(|overlay| overlay.hash == hash) - .expect("Hash validity is checked in `canonicalize`"); - - // discard unfinalized overlays and values - for (i, overlay) in level.blocks.into_iter().enumerate() { - let mut pinned_children = if i != index { - discard_descendants( - &mut self.levels.as_mut_slices(), - &mut self.values, - &mut self.parents, - &self.pinned, - &mut self.pinned_insertions, - &overlay.hash, - ) - } else { - 0 - }; - if self.pinned.contains_key(&overlay.hash) { - pinned_children += 1; - } - if pinned_children != 0 { - self.pinned_insertions - .insert(overlay.hash.clone(), (overlay.inserted, pinned_children)); - } else { - self.parents.remove(&overlay.hash); - discard_values(&mut self.values, overlay.inserted); - } - } - } - if let Some(hash) = last { - let last_canonicalized = ( - hash, - self.last_canonicalized.as_ref().map(|(_, n)| n + count).unwrap_or(count - 1), - ); - self.last_canonicalized = Some(last_canonicalized); - } + let num = canonicalized.1; + self.last_canonicalized = Some(canonicalized); + Ok(num) } /// Get a value from the node overlay. This searches in every existing changeset. @@ -494,8 +442,7 @@ impl NonCanonicalOverlay { /// Check if the block is in the canonicalization queue. pub fn have_block(&self, hash: &BlockHash) -> bool { - (self.parents.contains_key(hash) || self.pending_insertions.contains(hash)) && - !self.pending_canonicalizations.contains(hash) + self.parents.contains_key(hash) } /// Revert a single level. Returns commit set that deletes the journal or `None` if not @@ -543,50 +490,8 @@ impl NonCanonicalOverlay { } } - fn revert_insertions(&mut self) { - self.pending_insertions.reverse(); - for hash in self.pending_insertions.drain(..) { - self.parents.remove(&hash); - // find a level. When iterating insertions backwards the hash is always last in the - // level. - let level_index = self - .levels - .iter() - .position(|level| { - level.blocks.last().expect("Hash is added in `insert` in reverse order").hash == - hash - }) - .expect("Hash is added in insert"); - - let overlay_index = self.levels[level_index].blocks.len() - 1; - let overlay = self.levels[level_index].remove(overlay_index); - discard_values(&mut self.values, overlay.inserted); - if self.levels[level_index].blocks.is_empty() { - debug_assert_eq!(level_index, self.levels.len() - 1); - self.levels.pop_back(); - } - } - } - - /// Apply all pending changes - pub fn apply_pending(&mut self) { - self.apply_canonicalizations(); - self.pending_insertions.clear(); - } - - /// Revert all pending changes - pub fn revert_pending(&mut self) { - self.pending_canonicalizations.clear(); - self.revert_insertions(); - } - /// Pin state values in memory pub fn pin(&mut self, hash: &BlockHash) { - if self.pending_insertions.contains(hash) { - // Pinning pending state is not implemented. Pending states - // won't be pruned for quite some time anyway, so it's not a big deal. - return - } let refs = self.pinned.entry(hash.clone()).or_default(); if *refs == 0 { trace!(target: "state-db-pin", "Pinned non-canon block: {:?}", hash); @@ -779,7 +684,6 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h1, &mut commit).unwrap(); db.commit(&commit); - overlay.apply_pending(); assert_eq!(overlay.levels.len(), 1); let overlay2 = NonCanonicalOverlay::::new(&db).unwrap(); @@ -806,18 +710,13 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h1, &mut commit).unwrap(); db.commit(&commit); - assert!(contains(&overlay, 5)); - assert_eq!(overlay.levels.len(), 2); - assert_eq!(overlay.parents.len(), 2); - overlay.apply_pending(); - assert_eq!(overlay.levels.len(), 1); - assert_eq!(overlay.parents.len(), 1); assert!(!contains(&overlay, 5)); assert!(contains(&overlay, 7)); + assert_eq!(overlay.levels.len(), 1); + assert_eq!(overlay.parents.len(), 1); let mut commit = CommitSet::default(); overlay.canonicalize(&h2, &mut commit).unwrap(); db.commit(&commit); - overlay.apply_pending(); assert_eq!(overlay.levels.len(), 0); assert_eq!(overlay.parents.len(), 0); assert!(db.data_eq(&make_db(&[1, 4, 6, 7, 8]))); @@ -836,13 +735,11 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h_1, &mut commit).unwrap(); db.commit(&commit); - assert!(contains(&overlay, 1)); - overlay.apply_pending(); assert!(!contains(&overlay, 1)); } #[test] - fn insert_with_pending_canonicalization() { + fn insert_and_canonicalize() { let h1 = H256::random(); let h2 = H256::random(); let h3 = H256::random(); @@ -851,13 +748,11 @@ mod tests { let changeset = make_changeset(&[], &[]); db.commit(&overlay.insert(&h1, 1, &H256::default(), changeset.clone()).unwrap()); db.commit(&overlay.insert(&h2, 2, &h1, changeset.clone()).unwrap()); - overlay.apply_pending(); let mut commit = CommitSet::default(); overlay.canonicalize(&h1, &mut commit).unwrap(); overlay.canonicalize(&h2, &mut commit).unwrap(); db.commit(&commit); db.commit(&overlay.insert(&h3, 3, &h2, changeset.clone()).unwrap()); - overlay.apply_pending(); assert_eq!(overlay.levels.len(), 1); } @@ -927,7 +822,6 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h_1, &mut commit).unwrap(); db.commit(&commit); - overlay.apply_pending(); assert_eq!(overlay.levels.len(), 2); assert_eq!(overlay.parents.len(), 6); assert!(!contains(&overlay, 1)); @@ -948,7 +842,6 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h_1_2, &mut commit).unwrap(); db.commit(&commit); - overlay.apply_pending(); assert_eq!(overlay.levels.len(), 1); assert_eq!(overlay.parents.len(), 3); assert!(!contains(&overlay, 11)); @@ -965,7 +858,6 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h_1_2_2, &mut commit).unwrap(); db.commit(&commit); - overlay.apply_pending(); assert_eq!(overlay.levels.len(), 0); assert_eq!(overlay.parents.len(), 0); assert!(db.data_eq(&make_db(&[1, 12, 122]))); @@ -994,31 +886,6 @@ mod tests { assert!(overlay.revert_one().is_none()); } - #[test] - fn revert_pending_insertion() { - let h1 = H256::random(); - let h2_1 = H256::random(); - let h2_2 = H256::random(); - let db = make_db(&[]); - let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); - let changeset1 = make_changeset(&[5, 6], &[2]); - let changeset2 = make_changeset(&[7, 8], &[5, 3]); - let changeset3 = make_changeset(&[9], &[]); - overlay.insert(&h1, 1, &H256::default(), changeset1).unwrap(); - assert!(contains(&overlay, 5)); - overlay.insert(&h2_1, 2, &h1, changeset2).unwrap(); - overlay.insert(&h2_2, 2, &h1, changeset3).unwrap(); - assert!(contains(&overlay, 7)); - assert!(contains(&overlay, 5)); - assert!(contains(&overlay, 9)); - assert_eq!(overlay.levels.len(), 2); - assert_eq!(overlay.parents.len(), 3); - overlay.revert_pending(); - assert!(!contains(&overlay, 5)); - assert_eq!(overlay.levels.len(), 0); - assert_eq!(overlay.parents.len(), 0); - } - #[test] fn keeps_pinned() { let mut db = make_db(&[]); @@ -1033,14 +900,12 @@ mod tests { let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); db.commit(&overlay.insert(&h_1, 1, &H256::default(), c_1).unwrap()); db.commit(&overlay.insert(&h_2, 1, &H256::default(), c_2).unwrap()); - overlay.apply_pending(); overlay.pin(&h_1); let mut commit = CommitSet::default(); overlay.canonicalize(&h_2, &mut commit).unwrap(); db.commit(&commit); - overlay.apply_pending(); assert!(contains(&overlay, 1)); overlay.unpin(&h_1); assert!(!contains(&overlay, 1)); @@ -1064,14 +929,12 @@ mod tests { db.commit(&overlay.insert(&h_1, 1, &H256::default(), c_1).unwrap()); db.commit(&overlay.insert(&h_2, 1, &H256::default(), c_2).unwrap()); db.commit(&overlay.insert(&h_3, 1, &H256::default(), c_3).unwrap()); - overlay.apply_pending(); overlay.pin(&h_1); let mut commit = CommitSet::default(); overlay.canonicalize(&h_3, &mut commit).unwrap(); db.commit(&commit); - overlay.apply_pending(); // 1_2 should be discarded, 1_1 is pinned assert!(contains(&overlay, 1)); overlay.unpin(&h_1); @@ -1094,14 +957,12 @@ mod tests { db.commit(&overlay.insert(&h_11, 1, &H256::default(), c_11).unwrap()); db.commit(&overlay.insert(&h_12, 1, &H256::default(), c_12).unwrap()); db.commit(&overlay.insert(&h_21, 2, &h_11, c_21).unwrap()); - overlay.apply_pending(); overlay.pin(&h_21); let mut commit = CommitSet::default(); overlay.canonicalize(&h_12, &mut commit).unwrap(); db.commit(&commit); - overlay.apply_pending(); // 1_1 and 2_1 should be both pinned assert!(contains(&overlay, 1)); overlay.unpin(&h_21); @@ -1129,12 +990,10 @@ mod tests { overlay.canonicalize(&root, &mut commit).unwrap(); overlay.canonicalize(&h2, &mut commit).unwrap(); // h11 should stay in the DB db.commit(&commit); - overlay.apply_pending(); assert_eq!(overlay.levels.len(), 1); assert!(contains(&overlay, 21)); assert!(!contains(&overlay, 11)); assert!(db.get_meta(&to_journal_key(12, 1)).unwrap().is_some()); - assert!(db.get_meta(&to_journal_key(12, 0)).unwrap().is_none()); // Restore into a new overlay and check that journaled value exists. let mut overlay = NonCanonicalOverlay::::new(&db).unwrap(); @@ -1143,7 +1002,6 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h21, &mut commit).unwrap(); // h11 should stay in the DB db.commit(&commit); - overlay.apply_pending(); assert!(!contains(&overlay, 21)); } @@ -1167,7 +1025,6 @@ mod tests { overlay.canonicalize(&root, &mut commit).unwrap(); overlay.canonicalize(&h2, &mut commit).unwrap(); // h11 should stay in the DB db.commit(&commit); - overlay.apply_pending(); // add another block at top level. It should reuse journal index 0 of previously discarded // block diff --git a/client/state-db/src/pruning.rs b/client/state-db/src/pruning.rs index 50a46def59541..458522b8119fd 100644 --- a/client/state-db/src/pruning.rs +++ b/client/state-db/src/pruning.rs @@ -29,11 +29,8 @@ use crate::{ DEFAULT_MAX_BLOCK_CONSTRAINT, }; use codec::{Decode, Encode}; -use log::{error, trace, warn}; -use std::{ - cmp, - collections::{HashMap, HashSet, VecDeque}, -}; +use log::trace; +use std::collections::{HashMap, HashSet, VecDeque}; pub(crate) const LAST_PRUNED: &[u8] = b"last_pruned"; const PRUNING_JOURNAL: &[u8] = b"pruning_journal"; @@ -44,14 +41,8 @@ pub struct RefWindow { /// A queue of blocks keep tracking keys that should be deleted for each block in the /// pruning window. queue: DeathRowQueue, - /// Block number that corresponds to the front of `death_rows`. + /// Block number that is next to be pruned. base: u64, - /// Number of call of `note_canonical` after - /// last call `apply_pending` or `revert_pending` - pending_canonicalizations: usize, - /// Number of calls of `prune_one` after - /// last call `apply_pending` or `revert_pending` - pending_prunings: usize, } /// `DeathRowQueue` used to keep track of blocks in the pruning window, there are two flavors: @@ -72,13 +63,13 @@ enum DeathRowQueue { #[ignore_malloc_size_of = "Shared data"] db: D, /// A queue of keys that should be deleted for each block in the pruning window. - /// Only caching the first fews blocks of the pruning window, blocks inside are + /// Only caching the first few blocks of the pruning window, blocks inside are /// successive and ordered by block number cache: VecDeque>, /// A soft limit of the cache's size cache_capacity: usize, - /// The number of blocks in queue that are not loaded into `cache`. - uncached_blocks: usize, + /// Last block number added to the window + last: Option, }, } @@ -99,7 +90,7 @@ impl DeathRowQueue { let record: JournalRecord = Decode::decode(&mut record.as_slice())?; trace!(target: "state-db", "Pruning journal entry {} ({} inserted, {} deleted)", block, record.inserted.len(), record.deleted.len()); - queue.import(base, record); + queue.import(base, block, record); }, None => break, } @@ -113,36 +104,30 @@ impl DeathRowQueue { fn new_db_backed( db: D, base: u64, - mut uncached_blocks: usize, + last: Option, window_size: u32, ) -> Result, Error> { // limit the cache capacity from 1 to `DEFAULT_MAX_BLOCK_CONSTRAINT` let cache_capacity = window_size.clamp(1, DEFAULT_MAX_BLOCK_CONSTRAINT) as usize; let mut cache = VecDeque::with_capacity(cache_capacity); trace!(target: "state-db", "Reading pruning journal for the database-backed queue. Pending #{}", base); - // Load block from db - DeathRowQueue::load_batch_from_db( - &db, - &mut uncached_blocks, - &mut cache, - base, - cache_capacity, - )?; - Ok(DeathRowQueue::DbBacked { db, cache, cache_capacity, uncached_blocks }) + DeathRowQueue::load_batch_from_db(&db, &mut cache, base, cache_capacity)?; + Ok(DeathRowQueue::DbBacked { db, cache, cache_capacity, last }) } /// import a new block to the back of the queue - fn import(&mut self, base: u64, journal_record: JournalRecord) { + fn import(&mut self, base: u64, num: u64, journal_record: JournalRecord) { let JournalRecord { hash, inserted, deleted } = journal_record; + trace!(target: "state-db", "Importing {}, base={}", num, base); match self { - DeathRowQueue::DbBacked { uncached_blocks, cache, cache_capacity, .. } => { - // `uncached_blocks` is zero means currently all block are loaded into `cache` - // thus if `cache` is not full, load the next block into `cache` too - if *uncached_blocks == 0 && cache.len() < *cache_capacity { + DeathRowQueue::DbBacked { cache, cache_capacity, last, .. } => { + // If the new block continues cached range and there is space, load it directly into + // cache. + if num == base + cache.len() as u64 && cache.len() < *cache_capacity { + trace!(target: "state-db", "Adding to DB backed cache {:?} (#{})", hash, num); cache.push_back(DeathRow { hash, deleted: deleted.into_iter().collect() }); - } else { - *uncached_blocks += 1; } + *last = Some(num); }, DeathRowQueue::Mem { death_rows, death_index } => { // remove all re-inserted keys from death rows @@ -168,16 +153,9 @@ impl DeathRowQueue { base: u64, ) -> Result>, Error> { match self { - DeathRowQueue::DbBacked { db, uncached_blocks, cache, cache_capacity } => { - if cache.is_empty() && *uncached_blocks != 0 { - // load more blocks from db since there are still blocks in it - DeathRowQueue::load_batch_from_db( - db, - uncached_blocks, - cache, - base, - *cache_capacity, - )?; + DeathRowQueue::DbBacked { db, cache, cache_capacity, .. } => { + if cache.is_empty() { + DeathRowQueue::load_batch_from_db(db, cache, base, *cache_capacity)?; } Ok(cache.pop_front()) }, @@ -193,113 +171,37 @@ impl DeathRowQueue { } } - /// Revert recent additions to the queue, namely remove `amount` number of blocks from the back - /// of the queue, `base` is the block number of the first block of the queue - fn revert_recent_add(&mut self, base: u64, amout: usize) { - debug_assert!(amout <= self.len()); - match self { - DeathRowQueue::DbBacked { uncached_blocks, cache, .. } => { - // remove from `uncached_blocks` if it can cover - if *uncached_blocks >= amout { - *uncached_blocks -= amout; - return - } - // reset `uncached_blocks` and remove remain blocks from `cache` - let remain = amout - *uncached_blocks; - *uncached_blocks = 0; - cache.truncate(cache.len() - remain); - }, - DeathRowQueue::Mem { death_rows, death_index } => { - // Revert recent addition to the queue - // Note that pending insertions might cause some existing deletions to be removed - // from `death_index` We don't bother to track and revert that for now. This means - // that a few nodes might end up no being deleted in case transaction fails and - // `revert_pending` is called. - death_rows.truncate(death_rows.len() - amout); - let new_max_block = death_rows.len() as u64 + base; - death_index.retain(|_, block| *block < new_max_block); - }, - } - } - - /// Load a batch of blocks from the backend database into `cache`, start from (and include) the - /// next block followe the last block of `cache`, `base` is the block number of the first block - /// of the queue + /// Load a batch of blocks from the backend database into `cache`, starting from `base` and up + /// to `base + cache_capacity` fn load_batch_from_db( db: &D, - uncached_blocks: &mut usize, cache: &mut VecDeque>, base: u64, cache_capacity: usize, ) -> Result<(), Error> { - // return if all blocks already loaded into `cache` and there are no other - // blocks in the backend database - if *uncached_blocks == 0 { - return Ok(()) - } let start = base + cache.len() as u64; - let batch_size = cmp::min(*uncached_blocks, cache_capacity); - let mut loaded = 0; + let batch_size = cache_capacity; for i in 0..batch_size as u64 { match load_death_row_from_db::(db, start + i)? { Some(row) => { cache.push_back(row); - loaded += 1; }, - // block may added to the queue but not commit into the db yet, if there are - // data missing in the db `load_death_row_from_db` should return a db error None => break, } } - *uncached_blocks -= loaded; Ok(()) } - /// Get the block in the given index of the queue, `base` is the block number of the - /// first block of the queue - fn get( - &mut self, - base: u64, - index: usize, - ) -> Result>, Error> { - match self { - DeathRowQueue::DbBacked { db, uncached_blocks, cache, cache_capacity } => { - // check if `index` target a block reside on disk - if index >= cache.len() && index < cache.len() + *uncached_blocks { - // if `index` target the next batch of `DeathRow`, load a batch from db - if index - cache.len() < cmp::min(*uncached_blocks, *cache_capacity) { - DeathRowQueue::load_batch_from_db( - db, - uncached_blocks, - cache, - base, - *cache_capacity, - )?; - } else { - // load a single `DeathRow` from db, but do not insert it to `cache` - // because `cache` is a queue of successive `DeathRow` - // NOTE: this branch should not be entered because blocks are visited - // in successive increasing order, just keeping it for robustness - return load_death_row_from_db(db, base + index as u64) - } - } - Ok(cache.get(index).cloned()) - }, - DeathRowQueue::Mem { death_rows, .. } => Ok(death_rows.get(index).cloned()), - } - } - /// Check if the block at the given `index` of the queue exist - /// it is the caller's responsibility to ensure `index` won't be out of bound + /// it is the caller's responsibility to ensure `index` won't be out of bounds fn have_block(&self, hash: &BlockHash, index: usize) -> HaveBlock { match self { DeathRowQueue::DbBacked { cache, .. } => { if cache.len() > index { (cache[index].hash == *hash).into() } else { - // the block not exist in `cache`, but it may exist in the unload - // blocks - HaveBlock::MayHave + // The block is not in the cache but it still may exist on disk. + HaveBlock::Maybe } }, DeathRowQueue::Mem { death_rows, .. } => (death_rows[index].hash == *hash).into(), @@ -307,11 +209,10 @@ impl DeathRowQueue { } /// Return the number of block in the pruning window - fn len(&self) -> usize { + fn len(&self, base: u64) -> u64 { match self { - DeathRowQueue::DbBacked { uncached_blocks, cache, .. } => - cache.len() + *uncached_blocks, - DeathRowQueue::Mem { death_rows, .. } => death_rows.len(), + DeathRowQueue::DbBacked { last, .. } => last.map_or(0, |l| l + 1 - base), + DeathRowQueue::Mem { death_rows, .. } => death_rows.len() as u64, } } @@ -326,10 +227,11 @@ impl DeathRowQueue { } #[cfg(test)] - fn get_db_backed_queue_state(&self) -> Option<(&VecDeque>, usize)> { + fn get_db_backed_queue_state( + &self, + ) -> Option<(&VecDeque>, Option)> { match self { - DeathRowQueue::DbBacked { cache, uncached_blocks, .. } => - Some((cache, *uncached_blocks)), + DeathRowQueue::DbBacked { cache, last, .. } => Some((cache, *last)), DeathRowQueue::Mem { .. } => None, } } @@ -369,20 +271,20 @@ fn to_journal_key(block: u64) -> Vec { /// The result return by `RefWindow::have_block` #[derive(Debug, PartialEq, Eq)] pub enum HaveBlock { - /// Definitely not having this block - NotHave, - /// May or may not have this block, need futher checking - MayHave, - /// Definitely having this block - Have, + /// Definitely don't have this block. + No, + /// May or may not have this block, need further checking + Maybe, + /// Definitely has this block + Yes, } impl From for HaveBlock { fn from(have: bool) -> Self { if have { - HaveBlock::Have + HaveBlock::Yes } else { - HaveBlock::NotHave + HaveBlock::No } } } @@ -409,37 +311,36 @@ impl RefWindow { let queue = if count_insertions { DeathRowQueue::new_mem(&db, base)? } else { - let unload = match last_canonicalized_number { + let last = match last_canonicalized_number { Some(last_canonicalized_number) => { debug_assert!(last_canonicalized_number + 1 >= base); - last_canonicalized_number + 1 - base + Some(last_canonicalized_number) }, // None means `LAST_CANONICAL` is never been wrote, since the pruning journals are // in the same `CommitSet` as `LAST_CANONICAL`, it means no pruning journal have // ever been committed to the db, thus set `unload` to zero - None => 0, + None => None, }; - DeathRowQueue::new_db_backed(db, base, unload as usize, window_size)? + DeathRowQueue::new_db_backed(db, base, last, window_size)? }; - Ok(RefWindow { queue, base, pending_canonicalizations: 0, pending_prunings: 0 }) + Ok(RefWindow { queue, base }) } pub fn window_size(&self) -> u64 { - (self.queue.len() - self.pending_prunings) as u64 + self.queue.len(self.base) as u64 } /// Get the hash of the next pruning block pub fn next_hash(&mut self) -> Result, Error> { - let res = match &self.queue { - DeathRowQueue::DbBacked { cache, .. } => - if self.pending_prunings < cache.len() { - cache.get(self.pending_prunings).map(|r| r.hash.clone()) - } else { - self.get(self.pending_prunings)?.map(|r| r.hash) - }, - DeathRowQueue::Mem { death_rows, .. } => - death_rows.get(self.pending_prunings).map(|r| r.hash.clone()), + let res = match &mut self.queue { + DeathRowQueue::DbBacked { db, cache, cache_capacity, .. } => { + if cache.is_empty() { + DeathRowQueue::load_batch_from_db(db, cache, self.base, *cache_capacity)?; + } + cache.front().map(|r| r.hash.clone()) + }, + DeathRowQueue::Mem { death_rows, .. } => death_rows.front().map(|r| r.hash.clone()), }; Ok(res) } @@ -448,68 +349,34 @@ impl RefWindow { 0 } - // Return the block number of the first block that not been pending pruned - pub fn pending(&self) -> u64 { - self.base + self.pending_prunings as u64 - } - fn is_empty(&self) -> bool { - self.queue.len() <= self.pending_prunings + self.window_size() == 0 } // Check if a block is in the pruning window and not be pruned yet pub fn have_block(&self, hash: &BlockHash, number: u64) -> HaveBlock { // if the queue is empty or the block number exceed the pruning window, we definitely // do not have this block - if self.is_empty() || - number < self.pending() || - number >= self.base + self.queue.len() as u64 - { - return HaveBlock::NotHave + if self.is_empty() || number < self.base || number >= self.base + self.window_size() { + return HaveBlock::No } self.queue.have_block(hash, (number - self.base) as usize) } - fn get(&mut self, index: usize) -> Result>, Error> { - if index >= self.queue.len() { - return Ok(None) - } - match self.queue.get(self.base, index)? { - None => { - if matches!(self.queue, DeathRowQueue::DbBacked { .. }) && - // whether trying to get a pending canonicalize block which may not commit to the db yet - index >= self.queue.len() - self.pending_canonicalizations - { - trace!(target: "state-db", "Trying to get a pending canonicalize block that not commit to the db yet"); - Err(Error::StateDb(StateDbError::BlockUnavailable)) - } else { - // A block of the queue is missing, this may happen if `CommitSet` are commit to - // db concurrently and calling `apply_pending/revert_pending` out of order, this - // should not happen under current implementation but keeping it as a defensive - error!(target: "state-db", "Block record is missing from the pruning window, block number {}", self.base + index as u64); - Err(Error::StateDb(StateDbError::BlockMissing)) - } - }, - s => Ok(s), - } - } - /// Prune next block. Expects at least one block in the window. Adds changes to `commit`. pub fn prune_one(&mut self, commit: &mut CommitSet) -> Result<(), Error> { - if let Some(pruned) = self.get(self.pending_prunings)? { + if let Some(pruned) = self.queue.pop_front(self.base)? { trace!(target: "state-db", "Pruning {:?} ({} deleted)", pruned.hash, pruned.deleted.len()); - let index = self.base + self.pending_prunings as u64; + let index = self.base; commit.data.deleted.extend(pruned.deleted.into_iter()); commit.meta.inserted.push((to_meta_key(LAST_PRUNED, &()), index.encode())); - commit - .meta - .deleted - .push(to_journal_key(self.base + self.pending_prunings as u64)); - self.pending_prunings += 1; + commit.meta.deleted.push(to_journal_key(self.base)); + self.base += 1; + Ok(()) } else { - warn!(target: "state-db", "Trying to prune when there's nothing to prune"); + trace!(target: "state-db", "Trying to prune when there's nothing to prune"); + Err(Error::StateDb(StateDbError::BlockUnavailable)) } - Ok(()) } /// Add a change set to the window. Creates a journal record and pushes it to `commit` @@ -519,10 +386,10 @@ impl RefWindow { number: u64, commit: &mut CommitSet, ) -> Result<(), Error> { - if self.base == 0 && self.queue.len() == 0 && number > 0 { + if self.base == 0 && self.is_empty() && number > 0 { // assume that parent was canonicalized self.base = number; - } else if (self.base + self.queue.len() as u64) != number { + } else if (self.base + self.window_size()) != number { return Err(Error::StateDb(StateDbError::InvalidBlockNumber)) } trace!(target: "state-db", "Adding to pruning window: {:?} ({} inserted, {} deleted)", hash, commit.data.inserted.len(), commit.data.deleted.len()); @@ -531,38 +398,12 @@ impl RefWindow { } else { Default::default() }; - let deleted = ::std::mem::take(&mut commit.data.deleted); + let deleted = std::mem::take(&mut commit.data.deleted); let journal_record = JournalRecord { hash: hash.clone(), inserted, deleted }; commit.meta.inserted.push((to_journal_key(number), journal_record.encode())); - self.queue.import(self.base, journal_record); - self.pending_canonicalizations += 1; + self.queue.import(self.base, number, journal_record); Ok(()) } - - /// Apply all pending changes - pub fn apply_pending(&mut self) { - self.pending_canonicalizations = 0; - for _ in 0..self.pending_prunings { - let pruned = self - .queue - .pop_front(self.base) - // NOTE: `pop_front` should not return `MetaDb::Error` because blocks are visited - // by `RefWindow::prune_one` first then `RefWindow::apply_pending` and - // `DeathRowQueue::get` should load the blocks into cache already - .expect("block must loaded in cache thus no MetaDb::Error") - .expect("pending_prunings is always < queue.len()"); - trace!(target: "state-db", "Applying pruning {:?} ({} deleted)", pruned.hash, pruned.deleted.len()); - self.base += 1; - } - self.pending_prunings = 0; - } - - /// Revert all pending changes - pub fn revert_pending(&mut self) { - self.queue.revert_recent_add(self.base, self.pending_canonicalizations); - self.pending_canonicalizations = 0; - self.pending_prunings = 0; - } } #[cfg(test)] @@ -601,13 +442,14 @@ mod tests { let mut pruning: RefWindow = RefWindow::new(db, DEFAULT_MAX_BLOCK_CONSTRAINT, true).unwrap(); let mut commit = CommitSet::default(); - pruning.prune_one(&mut commit).unwrap(); + assert_eq!( + Err(Error::StateDb(StateDbError::BlockUnavailable)), + pruning.prune_one(&mut commit) + ); assert_eq!(pruning.base, 0); let (death_rows, death_index) = pruning.queue.get_mem_queue_state().unwrap(); assert!(death_rows.is_empty()); assert!(death_index.is_empty()); - assert!(pruning.pending_prunings == 0); - assert!(pruning.pending_canonicalizations == 0); } #[test] @@ -619,9 +461,8 @@ mod tests { let hash = H256::random(); pruning.note_canonical(&hash, 0, &mut commit).unwrap(); db.commit(&commit); - assert_eq!(pruning.have_block(&hash, 0), HaveBlock::Have); - pruning.apply_pending(); - assert_eq!(pruning.have_block(&hash, 0), HaveBlock::Have); + assert_eq!(pruning.have_block(&hash, 0), HaveBlock::Yes); + assert_eq!(pruning.have_block(&hash, 0), HaveBlock::Yes); assert!(commit.data.deleted.is_empty()); let (death_rows, death_index) = pruning.queue.get_mem_queue_state().unwrap(); assert_eq!(death_rows.len(), 1); @@ -631,10 +472,9 @@ mod tests { let mut commit = CommitSet::default(); pruning.prune_one(&mut commit).unwrap(); - assert_eq!(pruning.have_block(&hash, 0), HaveBlock::NotHave); + assert_eq!(pruning.have_block(&hash, 0), HaveBlock::No); db.commit(&commit); - pruning.apply_pending(); - assert_eq!(pruning.have_block(&hash, 0), HaveBlock::NotHave); + assert_eq!(pruning.have_block(&hash, 0), HaveBlock::No); assert!(db.data_eq(&make_db(&[2, 4, 5]))); let (death_rows, death_index) = pruning.queue.get_mem_queue_state().unwrap(); assert!(death_rows.is_empty()); @@ -653,7 +493,6 @@ mod tests { let mut commit = make_commit(&[5], &[2]); pruning.note_canonical(&H256::random(), 1, &mut commit).unwrap(); db.commit(&commit); - pruning.apply_pending(); assert!(db.data_eq(&make_db(&[1, 2, 3, 4, 5]))); check_journal(&pruning, &db); @@ -661,12 +500,10 @@ mod tests { let mut commit = CommitSet::default(); pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); - pruning.apply_pending(); assert!(db.data_eq(&make_db(&[2, 3, 4, 5]))); let mut commit = CommitSet::default(); pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); - pruning.apply_pending(); assert!(db.data_eq(&make_db(&[3, 4, 5]))); assert_eq!(pruning.base, 2); } @@ -690,7 +527,6 @@ mod tests { let mut commit = CommitSet::default(); pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); - pruning.apply_pending(); assert!(db.data_eq(&make_db(&[3, 4, 5]))); assert_eq!(pruning.base, 2); } @@ -710,7 +546,6 @@ mod tests { pruning.note_canonical(&H256::random(), 2, &mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 2, 3]))); - pruning.apply_pending(); check_journal(&pruning, &db); @@ -725,7 +560,6 @@ mod tests { pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 3]))); - pruning.apply_pending(); assert_eq!(pruning.base, 3); } @@ -756,7 +590,6 @@ mod tests { pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 3]))); - pruning.apply_pending(); assert_eq!(pruning.base, 3); } @@ -775,7 +608,6 @@ mod tests { pruning.note_canonical(&H256::random(), 2, &mut commit).unwrap(); db.commit(&commit); assert!(db.data_eq(&make_db(&[1, 2, 3]))); - pruning.apply_pending(); check_journal(&pruning, &db); @@ -861,9 +693,9 @@ mod tests { let cache_capacity = DEFAULT_MAX_BLOCK_CONSTRAINT as usize; // start as an empty queue - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + let (cache, last) = pruning.queue.get_db_backed_queue_state().unwrap(); assert_eq!(cache.len(), 0); - assert_eq!(uncached_blocks, 0); + assert_eq!(last, None); // import blocks // queue size and content should match @@ -872,21 +704,19 @@ mod tests { pruning.note_canonical(&(i as u64), i as u64, &mut commit).unwrap(); push_last_canonicalized(i as u64, &mut commit); db.commit(&commit); - // block will fill in cache first - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + // blocks will fill the cache first + let (cache, last) = pruning.queue.get_db_backed_queue_state().unwrap(); if i < cache_capacity { assert_eq!(cache.len(), i + 1); - assert_eq!(uncached_blocks, 0); } else { assert_eq!(cache.len(), cache_capacity); - assert_eq!(uncached_blocks, i - cache_capacity + 1); } + assert_eq!(last, Some(i as u64)); } - pruning.apply_pending(); - assert_eq!(pruning.queue.len(), cache_capacity + 10); - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(pruning.window_size(), cache_capacity as u64 + 10); + let (cache, last) = pruning.queue.get_db_backed_queue_state().unwrap(); assert_eq!(cache.len(), cache_capacity); - assert_eq!(uncached_blocks, 10); + assert_eq!(last, Some(cache_capacity as u64 + 10 - 1)); for i in 0..cache_capacity { assert_eq!(cache[i].hash, i as u64); } @@ -897,29 +727,26 @@ mod tests { pruning .note_canonical(&(cache_capacity as u64 + 10), cache_capacity as u64 + 10, &mut commit) .unwrap(); - assert_eq!(pruning.queue.len(), cache_capacity + 11); - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(pruning.window_size(), cache_capacity as u64 + 11); + let (cache, _) = pruning.queue.get_db_backed_queue_state().unwrap(); assert_eq!(cache.len(), cache_capacity); - assert_eq!(uncached_blocks, 11); // revert the last add that no apply yet // NOTE: do not commit the previous `CommitSet` to db - pruning.revert_pending(); - assert_eq!(pruning.queue.len(), cache_capacity + 10); - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + pruning = RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, false).unwrap(); + let cache_capacity = DEFAULT_MAX_BLOCK_CONSTRAINT as usize; + assert_eq!(pruning.window_size(), cache_capacity as u64 + 10); + let (cache, _) = pruning.queue.get_db_backed_queue_state().unwrap(); assert_eq!(cache.len(), cache_capacity); - assert_eq!(uncached_blocks, 10); // remove one block from the start of the queue // block is removed from the head of cache let mut commit = CommitSet::default(); pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); - pruning.apply_pending(); - assert_eq!(pruning.queue.len(), cache_capacity + 9); - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(pruning.window_size(), cache_capacity as u64 + 9); + let (cache, _) = pruning.queue.get_db_backed_queue_state().unwrap(); assert_eq!(cache.len(), cache_capacity - 1); - assert_eq!(uncached_blocks, 10); for i in 0..(cache_capacity - 1) { assert_eq!(cache[i].hash, (i + 1) as u64); } @@ -928,10 +755,9 @@ mod tests { // `cache` is full again but the content of the queue should be the same let pruning: RefWindow = RefWindow::new(db, DEFAULT_MAX_BLOCK_CONSTRAINT, false).unwrap(); - assert_eq!(pruning.queue.len(), cache_capacity + 9); - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(pruning.window_size(), cache_capacity as u64 + 9); + let (cache, _) = pruning.queue.get_db_backed_queue_state().unwrap(); assert_eq!(cache.len(), cache_capacity); - assert_eq!(uncached_blocks, 9); for i in 0..cache_capacity { assert_eq!(cache[i].hash, (i + 1) as u64); } @@ -952,24 +778,13 @@ mod tests { db.commit(&commit); } - // the following operations won't triger loading block from db: + // the following operations won't trigger loading block from db: // - getting block in cache // - getting block not in the queue - let index = cache_capacity; - assert_eq!( - pruning.queue.get(0, index - 1).unwrap().unwrap().hash, - cache_capacity as u64 - 1 - ); - assert_eq!(pruning.queue.get(0, cache_capacity * 2 + 10).unwrap(), None); - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(pruning.next_hash().unwrap().unwrap(), 0); + let (cache, last) = pruning.queue.get_db_backed_queue_state().unwrap(); assert_eq!(cache.len(), cache_capacity); - assert_eq!(uncached_blocks, cache_capacity + 10); - - // getting a block not in cache will triger loading block from db - assert_eq!(pruning.queue.get(0, index).unwrap().unwrap().hash, cache_capacity as u64); - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); - assert_eq!(cache.len(), cache_capacity * 2); - assert_eq!(uncached_blocks, 10); + assert_eq!(last, Some(cache_capacity as u64 * 2 + 10 - 1)); // clear all block loaded in cache for _ in 0..cache_capacity * 2 { @@ -977,29 +792,22 @@ mod tests { pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); } - pruning.apply_pending(); - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + let (cache, _) = pruning.queue.get_db_backed_queue_state().unwrap(); assert!(cache.is_empty()); - assert_eq!(uncached_blocks, 10); - // getting the hash of block that not in cache will also triger loading + // getting the hash of block that not in cache will also trigger loading // the remaining blocks from db - assert_eq!( - pruning.queue.get(pruning.base, 0).unwrap().unwrap().hash, - (cache_capacity * 2) as u64 - ); - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(pruning.next_hash().unwrap().unwrap(), (cache_capacity * 2) as u64); + let (cache, _) = pruning.queue.get_db_backed_queue_state().unwrap(); assert_eq!(cache.len(), 10); - assert_eq!(uncached_blocks, 0); // load a new queue from db // `cache` should be the same let pruning: RefWindow = RefWindow::new(db, DEFAULT_MAX_BLOCK_CONSTRAINT, false).unwrap(); - assert_eq!(pruning.queue.len(), 10); - let (cache, uncached_blocks) = pruning.queue.get_db_backed_queue_state().unwrap(); + assert_eq!(pruning.window_size(), 10); + let (cache, _) = pruning.queue.get_db_backed_queue_state().unwrap(); assert_eq!(cache.len(), 10); - assert_eq!(uncached_blocks, 0); for i in 0..10 { assert_eq!(cache[i].hash, (cache_capacity * 2 + i) as u64); } @@ -1030,11 +838,8 @@ mod tests { assert_eq!(pruning.next_hash().unwrap(), Some(i)); pruning.prune_one(&mut commit).unwrap(); } - // return `BlockUnavailable` for block that did not commit to db - assert_eq!( - pruning.next_hash().unwrap_err(), - Error::StateDb(StateDbError::BlockUnavailable) - ); + // return `None` for block that did not commit to db + assert_eq!(pruning.next_hash().unwrap(), None); assert_eq!( pruning.prune_one(&mut commit).unwrap_err(), Error::StateDb(StateDbError::BlockUnavailable) @@ -1044,12 +849,5 @@ mod tests { assert_eq!(pruning.next_hash().unwrap(), Some(index)); pruning.prune_one(&mut commit).unwrap(); db.commit(&commit); - - // import a block and do not commit it to db before calling `apply_pending` - pruning - .note_canonical(&(index + 1), index + 1, &mut make_commit(&[], &[])) - .unwrap(); - pruning.apply_pending(); - assert_eq!(pruning.next_hash().unwrap_err(), Error::StateDb(StateDbError::BlockMissing)); } } From eae25c901ccd4ef5c3ceb082e3f2c66753879062 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 8 Nov 2022 14:01:47 +0100 Subject: [PATCH 1353/1472] Remove duplicate units (#12634) Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- client/sysinfo/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/sysinfo/src/lib.rs b/client/sysinfo/src/lib.rs index 372c7c1a6d219..cef5a4d210df1 100644 --- a/client/sysinfo/src/lib.rs +++ b/client/sysinfo/src/lib.rs @@ -131,14 +131,14 @@ pub fn print_sysinfo(sysinfo: &sc_telemetry::SysInfo) { /// Prints out the results of the hardware benchmarks in the logs. pub fn print_hwbench(hwbench: &HwBench) { - log::info!("🏁 CPU score: {}MB/s", hwbench.cpu_hashrate_score); - log::info!("🏁 Memory score: {}MB/s", hwbench.memory_memcpy_score); + log::info!("🏁 CPU score: {}", hwbench.cpu_hashrate_score); + log::info!("🏁 Memory score: {}", hwbench.memory_memcpy_score); if let Some(score) = hwbench.disk_sequential_write_score { - log::info!("🏁 Disk score (seq. writes): {}MB/s", score); + log::info!("🏁 Disk score (seq. writes): {}", score); } if let Some(score) = hwbench.disk_random_write_score { - log::info!("🏁 Disk score (rand. writes): {}MB/s", score); + log::info!("🏁 Disk score (rand. writes): {}", score); } } From b85f85e08dafa2935dc20d1b13af2ca36ba3ea64 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 8 Nov 2022 16:15:55 +0000 Subject: [PATCH 1354/1472] Add batching to fast-unstake pallet (#12394) * implement a brand new batch with all tests passing. * fix benchmarks as well * make benchmarks more or less work * fix migration * add some testing * Update frame/fast-unstake/src/benchmarking.rs Co-authored-by: Roman Useinov * review comments * some fixes * fix review comments * fix build * fmt * fix benchmarks * fmt * update Co-authored-by: Roman Useinov --- bin/node/runtime/src/lib.rs | 1 + frame/fast-unstake/Cargo.toml | 3 +- frame/fast-unstake/src/benchmarking.rs | 63 ++-- frame/fast-unstake/src/lib.rs | 183 ++++++---- frame/fast-unstake/src/migrations.rs | 77 ++++ frame/fast-unstake/src/mock.rs | 45 ++- frame/fast-unstake/src/tests.rs | 479 ++++++++++++++++++------- frame/fast-unstake/src/types.rs | 22 +- 8 files changed, 609 insertions(+), 264 deletions(-) create mode 100644 frame/fast-unstake/src/migrations.rs diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index d49312bd6fe3f..999b178d10c55 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -584,6 +584,7 @@ impl pallet_staking::Config for Runtime { impl pallet_fast_unstake::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ControlOrigin = frame_system::EnsureRoot; + type BatchSize = ConstU32<128>; type Deposit = ConstU128<{ DOLLARS }>; type Currency = Balances; type Staking = Staking; diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml index ea1abeb0b48c5..f14a5e7b9c20b 100644 --- a/frame/fast-unstake/Cargo.toml +++ b/frame/fast-unstake/Cargo.toml @@ -60,6 +60,7 @@ std = [ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", - "sp-staking/runtime-benchmarks" + "sp-staking/runtime-benchmarks", + "pallet-staking/runtime-benchmarks" ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs index 762a59c96bcfa..b4a5e21dcfc13 100644 --- a/frame/fast-unstake/src/benchmarking.rs +++ b/frame/fast-unstake/src/benchmarking.rs @@ -36,10 +36,15 @@ const MAX_VALIDATORS: u32 = 128; type CurrencyOf = ::Currency; -fn create_unexposed_nominator() -> T::AccountId { - let account = frame_benchmarking::account::("nominator_42", 0, USER_SEED); - fund_and_bond_account::(&account); - account +fn create_unexposed_nominators() -> Vec { + (0..T::BatchSize::get()) + .map(|i| { + let account = + frame_benchmarking::account::("unexposed_nominator", i, USER_SEED); + fund_and_bond_account::(&account); + account + }) + .collect() } fn fund_and_bond_account(account: &T::AccountId) { @@ -90,21 +95,27 @@ fn on_idle_full_block() { } benchmarks! { - // on_idle, we we don't check anyone, but fully unbond and move them to another pool. + // on_idle, we don't check anyone, but fully unbond them. on_idle_unstake { ErasToCheckPerBlock::::put(1); - let who = create_unexposed_nominator::(); - assert_ok!(FastUnstake::::register_fast_unstake( - RawOrigin::Signed(who.clone()).into(), - )); + for who in create_unexposed_nominators::() { + assert_ok!(FastUnstake::::register_fast_unstake( + RawOrigin::Signed(who.clone()).into(), + )); + } // run on_idle once. This will check era 0. assert_eq!(Head::::get(), None); on_idle_full_block::(); - assert_eq!( + + assert!(matches!( Head::::get(), - Some(UnstakeRequest { stash: who.clone(), checked: vec![0].try_into().unwrap(), deposit: T::Deposit::get() }) - ); + Some(UnstakeRequest { + checked, + stashes, + .. + }) if checked.len() == 1 && stashes.len() as u32 == T::BatchSize::get() + )); } : { on_idle_full_block::(); @@ -112,7 +123,7 @@ benchmarks! { verify { assert!(matches!( fast_unstake_events::().last(), - Some(Event::Unstaked { .. }) + Some(Event::BatchFinished) )); } @@ -129,10 +140,13 @@ benchmarks! { // setup staking with v validators and u eras of data (0..=u) setup_staking::(v, u); - let who = create_unexposed_nominator::(); - assert_ok!(FastUnstake::::register_fast_unstake( - RawOrigin::Signed(who.clone()).into(), - )); + + let stashes = create_unexposed_nominators::().into_iter().map(|s| { + assert_ok!(FastUnstake::::register_fast_unstake( + RawOrigin::Signed(s.clone()).into(), + )); + (s, T::Deposit::get()) + }).collect::>(); // no one is queued thus far. assert_eq!(Head::::get(), None); @@ -141,20 +155,19 @@ benchmarks! { on_idle_full_block::(); } verify { - let checked: frame_support::BoundedVec<_, _> = (1..=u).rev().collect::>().try_into().unwrap(); - assert_eq!( - Head::::get(), - Some(UnstakeRequest { stash: who.clone(), checked, deposit: T::Deposit::get() }) - ); + let checked = (1..=u).rev().collect::>(); + let request = Head::::get().unwrap(); + assert_eq!(checked, request.checked.into_inner()); assert!(matches!( fast_unstake_events::().last(), - Some(Event::Checking { .. }) + Some(Event::BatchChecked { .. }) )); + assert!(stashes.iter().all(|(s, _)| request.stashes.iter().find(|(ss, _)| ss == s).is_some())); } register_fast_unstake { ErasToCheckPerBlock::::put(1); - let who = create_unexposed_nominator::(); + let who = create_unexposed_nominators::().get(0).cloned().unwrap(); whitelist_account!(who); assert_eq!(Queue::::count(), 0); @@ -166,7 +179,7 @@ benchmarks! { deregister { ErasToCheckPerBlock::::put(1); - let who = create_unexposed_nominator::(); + let who = create_unexposed_nominators::().get(0).cloned().unwrap(); assert_ok!(FastUnstake::::register_fast_unstake( RawOrigin::Signed(who.clone()).into(), )); diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 0477bb251aa00..c83054189feb7 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -60,6 +60,7 @@ mod tests; // NOTE: enable benchmarking in tests as well. #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migrations; pub mod types; pub mod weights; @@ -82,7 +83,7 @@ pub mod pallet { use crate::types::*; use frame_support::{ pallet_prelude::*, - traits::{Defensive, ReservableCurrency}, + traits::{Defensive, ReservableCurrency, StorageVersion}, }; use frame_system::pallet_prelude::*; use sp_runtime::{ @@ -103,7 +104,10 @@ pub mod pallet { } } + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -123,6 +127,11 @@ pub mod pallet { /// The origin that can control this pallet. type ControlOrigin: frame_support::traits::EnsureOrigin; + /// Batch size. + /// + /// This many stashes are processed in each unstake request. + type BatchSize: Get; + /// The access to staking functionality. type Staking: StakingInterface, AccountId = Self::AccountId>; @@ -132,8 +141,7 @@ pub mod pallet { /// The current "head of the queue" being unstaked. #[pallet::storage] - pub type Head = - StorageValue<_, UnstakeRequest, BalanceOf>, OptionQuery>; + pub type Head = StorageValue<_, UnstakeRequest, OptionQuery>; /// The map of all accounts wishing to be unstaked. /// @@ -158,13 +166,18 @@ pub mod pallet { Unstaked { stash: T::AccountId, result: DispatchResult }, /// A staker was slashed for requesting fast-unstake whilst being exposed. Slashed { stash: T::AccountId, amount: BalanceOf }, - /// A staker was partially checked for the given eras, but the process did not finish. - Checking { stash: T::AccountId, eras: Vec }, /// Some internal error happened while migrating stash. They are removed as head as a /// consequence. Errored { stash: T::AccountId }, /// An internal error happened. Operations will be paused now. InternalError, + /// A batch was partially checked for the given eras, but the process did not finish. + BatchChecked { eras: Vec }, + /// A batch was terminated. + /// + /// This is always follows by a number of `Unstaked` or `Slashed` events, marking the end + /// of the batch. A new batch will be created upon next block. + BatchFinished, } #[pallet::error] @@ -225,12 +238,7 @@ pub mod pallet { let stash_account = T::Staking::stash_by_ctrl(&ctrl).map_err(|_| Error::::NotController)?; ensure!(!Queue::::contains_key(&stash_account), Error::::AlreadyQueued); - ensure!( - Head::::get() - .map_or(true, |UnstakeRequest { stash, .. }| stash_account != stash), - Error::::AlreadyHead - ); - + ensure!(!Self::is_head(&stash_account), Error::::AlreadyHead); ensure!(!T::Staking::is_unbonding(&stash_account)?, Error::::NotFullyBonded); // chill and fully unstake. @@ -260,19 +268,13 @@ pub mod pallet { let stash_account = T::Staking::stash_by_ctrl(&ctrl).map_err(|_| Error::::NotController)?; ensure!(Queue::::contains_key(&stash_account), Error::::NotQueued); - ensure!( - Head::::get() - .map_or(true, |UnstakeRequest { stash, .. }| stash_account != stash), - Error::::AlreadyHead - ); + ensure!(!Self::is_head(&stash_account), Error::::AlreadyHead); let deposit = Queue::::take(stash_account.clone()); if let Some(deposit) = deposit.defensive() { let remaining = T::Currency::unreserve(&stash_account, deposit); if !remaining.is_zero() { - frame_support::defensive!("`not enough balance to unreserve`"); - ErasToCheckPerBlock::::put(0); - Self::deposit_event(Event::::InternalError) + Self::halt("not enough balance to unreserve"); } } @@ -291,6 +293,20 @@ pub mod pallet { } impl Pallet { + /// Returns `true` if `staker` is anywhere to be found in the `head`. + pub(crate) fn is_head(staker: &T::AccountId) -> bool { + Head::::get().map_or(false, |UnstakeRequest { stashes, .. }| { + stashes.iter().any(|(stash, _)| stash == staker) + }) + } + + /// Halt the operations of this pallet. + pub(crate) fn halt(reason: &'static str) { + frame_support::defensive!(reason); + ErasToCheckPerBlock::::put(0); + Self::deposit_event(Event::::InternalError) + } + /// process up to `remaining_weight`. /// /// Returns the actual weight consumed. @@ -336,28 +352,30 @@ pub mod pallet { return T::DbWeight::get().reads(2) } - let UnstakeRequest { stash, mut checked, deposit } = - match Head::::take().or_else(|| { - // NOTE: there is no order guarantees in `Queue`. - Queue::::drain() - .map(|(stash, deposit)| UnstakeRequest { - stash, - deposit, - checked: Default::default(), - }) - .next() - }) { - None => { - // There's no `Head` and nothing in the `Queue`, nothing to do here. - return T::DbWeight::get().reads(4) - }, - Some(head) => head, - }; + let UnstakeRequest { stashes, mut checked } = match Head::::take().or_else(|| { + // NOTE: there is no order guarantees in `Queue`. + let stashes: BoundedVec<_, T::BatchSize> = Queue::::drain() + .take(T::BatchSize::get() as usize) + .collect::>() + .try_into() + .expect("take ensures bound is met; qed"); + if stashes.is_empty() { + None + } else { + Some(UnstakeRequest { stashes, checked: Default::default() }) + } + }) { + None => { + // There's no `Head` and nothing in the `Queue`, nothing to do here. + return T::DbWeight::get().reads(4) + }, + Some(head) => head, + }; log!( debug, - "checking {:?}, eras_to_check_per_block = {:?}, remaining_weight = {:?}", - stash, + "checking {:?} stashes, eras_to_check_per_block = {:?}, remaining_weight = {:?}", + stashes.len(), eras_to_check_per_block, remaining_weight ); @@ -365,9 +383,11 @@ pub mod pallet { // the range that we're allowed to check in this round. let current_era = T::Staking::current_era(); let bonding_duration = T::Staking::bonding_duration(); + // prune all the old eras that we don't care about. This will help us keep the bound // of `checked`. checked.retain(|e| *e >= current_era.saturating_sub(bonding_duration)); + let unchecked_eras_to_check = { // get the last available `bonding_duration` eras up to current era in reverse // order. @@ -397,66 +417,75 @@ pub mod pallet { unchecked_eras_to_check ); - if unchecked_eras_to_check.is_empty() { + let unstake_stash = |stash: T::AccountId, deposit| { let result = T::Staking::force_unstake(stash.clone()); - let remaining = T::Currency::unreserve(&stash, deposit); if !remaining.is_zero() { - frame_support::defensive!("`not enough balance to unreserve`"); - ErasToCheckPerBlock::::put(0); - Self::deposit_event(Event::::InternalError) + Self::halt("not enough balance to unreserve"); } else { log!(info, "unstaked {:?}, outcome: {:?}", stash, result); Self::deposit_event(Event::::Unstaked { stash, result }); } + }; - ::WeightInfo::on_idle_unstake() - } else { - // eras remaining to be checked. - let mut eras_checked = 0u32; + let check_stash = |stash, deposit, eras_checked: &mut u32| { let is_exposed = unchecked_eras_to_check.iter().any(|e| { eras_checked.saturating_inc(); T::Staking::is_exposed_in_era(&stash, e) }); - log!( - debug, - "checked {:?} eras, exposed? {}, (v: {:?}, u: {:?})", - eras_checked, - is_exposed, - validator_count, - unchecked_eras_to_check.len() - ); - - // NOTE: you can be extremely unlucky and get slashed here: You are not exposed in - // the last 28 eras, have registered yourself to be unstaked, midway being checked, - // you are exposed. if is_exposed { T::Currency::slash_reserved(&stash, deposit); log!(info, "slashed {:?} by {:?}", stash, deposit); Self::deposit_event(Event::::Slashed { stash, amount: deposit }); + false } else { - // Not exposed in these eras. - match checked.try_extend(unchecked_eras_to_check.clone().into_iter()) { - Ok(_) => { - Head::::put(UnstakeRequest { - stash: stash.clone(), - checked, - deposit, - }); - Self::deposit_event(Event::::Checking { - stash, + true + } + }; + + if unchecked_eras_to_check.is_empty() { + // `stash` is not exposed in any era now -- we can let go of them now. + stashes.into_iter().for_each(|(stash, deposit)| unstake_stash(stash, deposit)); + Self::deposit_event(Event::::BatchFinished); + ::WeightInfo::on_idle_unstake() + } else { + // eras checked so far. + let mut eras_checked = 0u32; + + let pre_length = stashes.len(); + let stashes: BoundedVec<(T::AccountId, BalanceOf), T::BatchSize> = stashes + .into_iter() + .filter(|(stash, deposit)| { + check_stash(stash.clone(), *deposit, &mut eras_checked) + }) + .collect::>() + .try_into() + .expect("filter can only lessen the length; still in bound; qed"); + let post_length = stashes.len(); + + log!( + debug, + "checked {:?} eras, pre stashes: {:?}, post: {:?}", + eras_checked, + pre_length, + post_length, + ); + + match checked.try_extend(unchecked_eras_to_check.clone().into_iter()) { + Ok(_) => + if stashes.is_empty() { + Self::deposit_event(Event::::BatchFinished); + } else { + Head::::put(UnstakeRequest { stashes, checked }); + Self::deposit_event(Event::::BatchChecked { eras: unchecked_eras_to_check, }); }, - Err(_) => { - // don't put the head back in -- there is an internal error in the - // pallet. - frame_support::defensive!("`checked is pruned via retain above`"); - ErasToCheckPerBlock::::put(0); - Self::deposit_event(Event::::InternalError); - }, - } + Err(_) => { + // don't put the head back in -- there is an internal error in the pallet. + Self::halt("checked is pruned via retain above") + }, } ::WeightInfo::on_idle_check(validator_count * eras_checked) diff --git a/frame/fast-unstake/src/migrations.rs b/frame/fast-unstake/src/migrations.rs new file mode 100644 index 0000000000000..10d8e54134785 --- /dev/null +++ b/frame/fast-unstake/src/migrations.rs @@ -0,0 +1,77 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod v1 { + use crate::{types::BalanceOf, *}; + use frame_support::{ + storage::unhashed, + traits::{Defensive, Get, GetStorageVersion, OnRuntimeUpgrade}, + weights::Weight, + }; + use sp_staking::EraIndex; + use sp_std::prelude::*; + + pub struct MigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); + + log!( + info, + "Running migration with current storage version {:?} / onchain {:?}", + current, + onchain + ); + + if current == 1 && onchain == 0 { + // if a head exists, then we put them back into the queue. + if Head::::exists() { + if let Some((stash, _, deposit)) = + unhashed::take::<(T::AccountId, Vec, BalanceOf)>( + &Head::::hashed_key(), + ) + .defensive() + { + Queue::::insert(stash, deposit); + current.put::>(); + } else { + // not much we can do here -- head is already deleted. + } + T::DbWeight::get().reads_writes(2, 3) + } else { + T::DbWeight::get().reads(2) + } + } else { + log!(info, "Migration did not execute. This probably should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + assert_eq!(Pallet::::on_chain_storage_version(), 0); + Ok(Default::default()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), &'static str> { + assert_eq!(Pallet::::on_chain_storage_version(), 1); + Ok(()) + } + } +} diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index 87e89d90d6304..bac2d9aa9c8e4 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -16,8 +16,12 @@ // limitations under the License. use crate::{self as fast_unstake}; +use frame_benchmarking::frame_support::assert_ok; use frame_support::{ - pallet_prelude::*, parameter_types, traits::ConstU64, weights::constants::WEIGHT_PER_SECOND, + pallet_prelude::*, + parameter_types, + traits::{ConstU64, Currency}, + weights::constants::WEIGHT_PER_SECOND, }; use sp_runtime::traits::{Convert, IdentityLookup}; @@ -168,15 +172,17 @@ impl Convert for U256ToBalance { } parameter_types! { - pub static DepositAmount: u128 = 7; + pub static Deposit: u128 = 7; + pub static BatchSize: u32 = 1; } impl fast_unstake::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Deposit = DepositAmount; + type Deposit = Deposit; type Currency = Balances; type Staking = Staking; type ControlOrigin = frame_system::EnsureRoot; + type BatchSize = BatchSize; type WeightInfo = (); } @@ -212,13 +218,13 @@ pub(crate) fn fast_unstake_events_since_last_call() -> Vec } pub struct ExtBuilder { - exposed_nominators: Vec<(AccountId, AccountId, Balance)>, + unexposed: Vec<(AccountId, AccountId, Balance)>, } impl Default for ExtBuilder { fn default() -> Self { Self { - exposed_nominators: vec![ + unexposed: vec![ (1, 2, 7 + 100), (3, 4, 7 + 100), (5, 6, 7 + 100), @@ -255,6 +261,11 @@ impl ExtBuilder { }); } + pub(crate) fn batch(self, size: u32) -> Self { + BatchSize::set(size); + self + } + pub(crate) fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = @@ -266,12 +277,12 @@ impl ExtBuilder { let _ = pallet_balances::GenesisConfig:: { balances: self - .exposed_nominators + .unexposed .clone() .into_iter() .map(|(stash, _, balance)| (stash, balance * 2)) .chain( - self.exposed_nominators + self.unexposed .clone() .into_iter() .map(|(_, ctrl, balance)| (ctrl, balance * 2)), @@ -284,7 +295,7 @@ impl ExtBuilder { let _ = pallet_staking::GenesisConfig:: { stakers: self - .exposed_nominators + .unexposed .into_iter() .map(|(x, y, z)| (x, y, z, pallet_staking::StakerStatus::Nominator(vec![42]))) .chain(validators_range.map(|x| (x, x, 100, StakerStatus::Validator))) @@ -307,6 +318,7 @@ impl ExtBuilder { // because we read this value as a measure of how many validators we have. pallet_staking::ValidatorCount::::put(VALIDATORS_PER_ERA as u32); }); + ext } @@ -347,3 +359,20 @@ pub fn assert_unstaked(stash: &AccountId) { assert!(!pallet_staking::Validators::::contains_key(stash)); assert!(!pallet_staking::Nominators::::contains_key(stash)); } + +pub fn create_exposed_nominator(exposed: AccountId, era: u32) { + // create an exposed nominator in era 1 + pallet_staking::ErasStakers::::mutate(era, VALIDATORS_PER_ERA, |expo| { + expo.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); + }); + Balances::make_free_balance_be(&exposed, 100); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(exposed), + exposed, + 10, + pallet_staking::RewardDestination::Staked + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed])); + // register the exposed one. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed))); +} diff --git a/frame/fast-unstake/src/tests.rs b/frame/fast-unstake/src/tests.rs index 18a9d59e9da66..522aa1d0fac28 100644 --- a/frame/fast-unstake/src/tests.rs +++ b/frame/fast-unstake/src/tests.rs @@ -20,7 +20,7 @@ use super::*; use crate::{mock::*, types::*, weights::WeightInfo, Event}; use frame_support::{assert_noop, assert_ok, bounded_vec, pallet_prelude::*, traits::Currency}; -use pallet_staking::{CurrentEra, IndividualExposure, RewardDestination}; +use pallet_staking::{CurrentEra, RewardDestination}; use sp_runtime::traits::BadOrigin; use sp_staking::StakingInterface; @@ -107,9 +107,8 @@ fn cannot_register_if_head() { ErasToCheckPerBlock::::put(1); // Insert some Head item for stash Head::::put(UnstakeRequest { - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![], - deposit: DepositAmount::get(), }); // Controller attempts to regsiter assert_noop!( @@ -142,7 +141,7 @@ fn deregister_works() { // Controller account registers for fast unstake. assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(::Currency::reserved_balance(&1), DepositAmount::get()); + assert_eq!(::Currency::reserved_balance(&1), Deposit::get()); // Controller then changes mind and deregisters. assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(2))); @@ -191,9 +190,8 @@ fn cannot_deregister_already_head() { assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); // Insert some Head item for stash. Head::::put(UnstakeRequest { - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![], - deposit: DepositAmount::get(), }); // Controller attempts to deregister assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(2)), Error::::AlreadyHead); @@ -227,14 +225,14 @@ mod on_idle { // set up Queue item assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + assert_eq!(Queue::::get(1), Some(Deposit::get())); // call on_idle with no remaining weight FastUnstake::on_idle(System::block_number(), Weight::from_ref_time(0)); // assert nothing changed in Queue and Head assert_eq!(Head::::get(), None); - assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + assert_eq!(Queue::::get(1), Some(Deposit::get())); }); } @@ -247,7 +245,7 @@ mod on_idle { // given assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + assert_eq!(Queue::::get(1), Some(Deposit::get())); assert_eq!(Queue::::count(), 1); assert_eq!(Head::::get(), None); @@ -262,13 +260,12 @@ mod on_idle { // then assert_eq!( fast_unstake_events_since_last_call(), - vec![Event::Checking { stash: 1, eras: vec![3] }] + vec![Event::BatchChecked { eras: vec![3] }] ); assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3] }) ); @@ -282,13 +279,12 @@ mod on_idle { // then: assert_eq!( fast_unstake_events_since_last_call(), - vec![Event::Checking { stash: 1, eras: bounded_vec![2] }] + vec![Event::BatchChecked { eras: bounded_vec![2] }] ); assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2] }) ); @@ -308,13 +304,12 @@ mod on_idle { // then: assert_eq!( fast_unstake_events_since_last_call(), - vec![Event::Checking { stash: 1, eras: vec![1, 0] }] + vec![Event::BatchChecked { eras: vec![1, 0] }] ); assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 1, 0] }) ); @@ -329,8 +324,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 1, 0] }) ); @@ -348,7 +342,7 @@ mod on_idle { // then we finish the unbonding: assert_eq!( fast_unstake_events_since_last_call(), - vec![Event::Unstaked { stash: 1, result: Ok(()) }] + vec![Event::Unstaked { stash: 1, result: Ok(()) }, Event::BatchFinished], ); assert_eq!(Head::::get(), None,); @@ -371,7 +365,7 @@ mod on_idle { assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(8))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(10))); - assert_eq!(::Currency::reserved_balance(&1), DepositAmount::get()); + assert_eq!(::Currency::reserved_balance(&1), Deposit::get()); assert_eq!(Queue::::count(), 5); assert_eq!(Head::::get(), None); @@ -383,8 +377,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 1, 0] }) ); @@ -404,8 +397,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 5, + stashes: bounded_vec![(5, Deposit::get())], checked: bounded_vec![3, 2, 1, 0] }), ); @@ -416,9 +408,10 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), vec![ - Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::BatchChecked { eras: vec![3, 2, 1, 0] }, Event::Unstaked { stash: 1, result: Ok(()) }, - Event::Checking { stash: 5, eras: vec![3, 2, 1, 0] } + Event::BatchFinished, + Event::BatchChecked { eras: vec![3, 2, 1, 0] } ] ); }); @@ -432,9 +425,9 @@ mod on_idle { // register multi accounts for fast unstake assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + assert_eq!(Queue::::get(1), Some(Deposit::get())); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); - assert_eq!(Queue::::get(3), Some(DepositAmount::get())); + assert_eq!(Queue::::get(3), Some(Deposit::get())); // assert 2 queue items are in Queue & None in Head to start with assert_eq!(Queue::::count(), 2); @@ -463,10 +456,12 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), vec![ - Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::BatchChecked { eras: vec![3, 2, 1, 0] }, Event::Unstaked { stash: 1, result: Ok(()) }, - Event::Checking { stash: 3, eras: vec![3, 2, 1, 0] }, + Event::BatchFinished, + Event::BatchChecked { eras: vec![3, 2, 1, 0] }, Event::Unstaked { stash: 3, result: Ok(()) }, + Event::BatchFinished, ] ); @@ -483,7 +478,7 @@ mod on_idle { // register for fast unstake assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + assert_eq!(Queue::::get(1), Some(Deposit::get())); // process on idle next_block(true); @@ -495,8 +490,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 1, 0] }) ); @@ -507,8 +501,9 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), vec![ - Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, - Event::Unstaked { stash: 1, result: Ok(()) } + Event::BatchChecked { eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, result: Ok(()) }, + Event::BatchFinished ] ); assert_unstaked(&1); @@ -525,7 +520,7 @@ mod on_idle { // register for fast unstake assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + assert_eq!(Queue::::get(1), Some(Deposit::get())); // process on idle next_block(true); @@ -537,8 +532,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 1, 0] }) ); @@ -549,8 +543,9 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), vec![ - Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, - Event::Unstaked { stash: 1, result: Ok(()) } + Event::BatchChecked { eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, result: Ok(()) }, + Event::BatchFinished ] ); assert_unstaked(&1); @@ -566,7 +561,7 @@ mod on_idle { // register for fast unstake assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + assert_eq!(Queue::::get(1), Some(Deposit::get())); // process on idle next_block(true); @@ -578,8 +573,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3] }) ); @@ -589,8 +583,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2] }) ); @@ -600,8 +593,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 1] }) ); @@ -611,8 +603,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 1, 0] }) ); @@ -624,11 +615,12 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), vec![ - Event::Checking { stash: 1, eras: vec![3] }, - Event::Checking { stash: 1, eras: vec![2] }, - Event::Checking { stash: 1, eras: vec![1] }, - Event::Checking { stash: 1, eras: vec![0] }, - Event::Unstaked { stash: 1, result: Ok(()) } + Event::BatchChecked { eras: vec![3] }, + Event::BatchChecked { eras: vec![2] }, + Event::BatchChecked { eras: vec![1] }, + Event::BatchChecked { eras: vec![0] }, + Event::Unstaked { stash: 1, result: Ok(()) }, + Event::BatchFinished ] ); assert_unstaked(&1); @@ -647,14 +639,13 @@ mod on_idle { // register for fast unstake assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + assert_eq!(Queue::::get(1), Some(Deposit::get())); next_block(true); assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3] }) ); @@ -663,8 +654,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2] }) ); @@ -673,8 +663,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 1] }) ); @@ -683,8 +672,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 1, 0] }) ); @@ -698,10 +686,9 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], // note era 0 is pruned to keep the vector length sane. checked: bounded_vec![3, 2, 1, 4], - deposit: DepositAmount::get(), }) ); @@ -711,12 +698,13 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), vec![ - Event::Checking { stash: 1, eras: vec![3] }, - Event::Checking { stash: 1, eras: vec![2] }, - Event::Checking { stash: 1, eras: vec![1] }, - Event::Checking { stash: 1, eras: vec![0] }, - Event::Checking { stash: 1, eras: vec![4] }, - Event::Unstaked { stash: 1, result: Ok(()) } + Event::BatchChecked { eras: vec![3] }, + Event::BatchChecked { eras: vec![2] }, + Event::BatchChecked { eras: vec![1] }, + Event::BatchChecked { eras: vec![0] }, + Event::BatchChecked { eras: vec![4] }, + Event::Unstaked { stash: 1, result: Ok(()) }, + Event::BatchFinished ] ); assert_unstaked(&1); @@ -738,8 +726,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3] }) ); @@ -748,8 +735,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2] }) ); @@ -762,8 +748,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2] }) ); @@ -772,8 +757,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2] }) ); @@ -788,8 +772,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 4] }) ); @@ -799,8 +782,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 1, + stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![3, 2, 4, 1] }) ); @@ -812,11 +794,12 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), vec![ - Event::Checking { stash: 1, eras: vec![3] }, - Event::Checking { stash: 1, eras: vec![2] }, - Event::Checking { stash: 1, eras: vec![4] }, - Event::Checking { stash: 1, eras: vec![1] }, - Event::Unstaked { stash: 1, result: Ok(()) } + Event::BatchChecked { eras: vec![3] }, + Event::BatchChecked { eras: vec![2] }, + Event::BatchChecked { eras: vec![4] }, + Event::BatchChecked { eras: vec![1] }, + Event::Unstaked { stash: 1, result: Ok(()) }, + Event::BatchFinished ] ); @@ -831,30 +814,15 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // create an exposed nominator in era 1 - let exposed = 666 as AccountId; - pallet_staking::ErasStakers::::mutate(1, VALIDATORS_PER_ERA, |expo| { - expo.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); - }); - Balances::make_free_balance_be(&exposed, 100); - assert_ok!(Staking::bond( - RuntimeOrigin::signed(exposed), - exposed, - 10, - RewardDestination::Staked - )); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed])); - - Balances::make_free_balance_be(&exposed, 100_000); - // register the exposed one. - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed))); + let exposed = 666; + create_exposed_nominator(exposed, 1); // a few blocks later, we realize they are slashed next_block(true); assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: exposed, + stashes: bounded_vec![(exposed, Deposit::get())], checked: bounded_vec![3] }) ); @@ -862,8 +830,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: exposed, + stashes: bounded_vec![(exposed, Deposit::get())], checked: bounded_vec![3, 2] }) ); @@ -873,9 +840,10 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), vec![ - Event::Checking { stash: exposed, eras: vec![3] }, - Event::Checking { stash: exposed, eras: vec![2] }, - Event::Slashed { stash: exposed, amount: DepositAmount::get() } + Event::BatchChecked { eras: vec![3] }, + Event::BatchChecked { eras: vec![2] }, + Event::Slashed { stash: exposed, amount: Deposit::get() }, + Event::BatchFinished ] ); }); @@ -889,30 +857,16 @@ mod on_idle { ErasToCheckPerBlock::::put(2); CurrentEra::::put(BondingDuration::get()); - // create an exposed nominator in era 1 - let exposed = 666 as AccountId; - pallet_staking::ErasStakers::::mutate(0, VALIDATORS_PER_ERA, |expo| { - expo.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); - }); - Balances::make_free_balance_be(&exposed, DepositAmount::get() + 100); - assert_ok!(Staking::bond( - RuntimeOrigin::signed(exposed), - exposed, - 10, - RewardDestination::Staked - )); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed])); - - // register the exposed one. - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed))); + // create an exposed nominator in era 0 + let exposed = 666; + create_exposed_nominator(exposed, 0); // a few blocks later, we realize they are slashed next_block(true); assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: exposed, + stashes: bounded_vec![(exposed, Deposit::get())], checked: bounded_vec![3, 2] }) ); @@ -923,8 +877,9 @@ mod on_idle { fast_unstake_events_since_last_call(), // we slash them vec![ - Event::Checking { stash: exposed, eras: vec![3, 2] }, - Event::Slashed { stash: exposed, amount: DepositAmount::get() } + Event::BatchChecked { eras: vec![3, 2] }, + Event::Slashed { stash: exposed, amount: Deposit::get() }, + Event::BatchFinished ] ); }); @@ -955,7 +910,7 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), - vec![Event::Slashed { stash: 100, amount: DepositAmount::get() }] + vec![Event::Slashed { stash: 100, amount: Deposit::get() }, Event::BatchFinished] ); }); } @@ -967,7 +922,7 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // create a new validator that 100% not exposed. - Balances::make_free_balance_be(&42, 100 + DepositAmount::get()); + Balances::make_free_balance_be(&42, 100 + Deposit::get()); assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 42, 10, RewardDestination::Staked)); assert_ok!(Staking::validate(RuntimeOrigin::signed(42), Default::default())); @@ -979,8 +934,7 @@ mod on_idle { assert_eq!( Head::::get(), Some(UnstakeRequest { - deposit: DepositAmount::get(), - stash: 42, + stashes: bounded_vec![(42, Deposit::get())], checked: bounded_vec![3, 2, 1, 0] }) ); @@ -990,8 +944,255 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), vec![ - Event::Checking { stash: 42, eras: vec![3, 2, 1, 0] }, - Event::Unstaked { stash: 42, result: Ok(()) } + Event::BatchChecked { eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 42, result: Ok(()) }, + Event::BatchFinished + ] + ); + }); + } +} + +mod batched { + use super::*; + + #[test] + fn single_block_batched_successful() { + ExtBuilder::default().batch(3).build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(6))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(8))); + + assert_eq!(Queue::::count(), 4); + assert_eq!(Head::::get(), None); + + // when + next_block(true); + + // then + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stashes: bounded_vec![ + (1, Deposit::get()), + (5, Deposit::get()), + (7, Deposit::get()) + ], + checked: bounded_vec![3, 2, 1, 0] + }) + ); + assert_eq!(Queue::::count(), 1); + + // when + next_block(true); + + // then + assert_eq!(Head::::get(), None); + assert_eq!(Queue::::count(), 1); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::BatchChecked { eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, result: Ok(()) }, + Event::Unstaked { stash: 5, result: Ok(()) }, + Event::Unstaked { stash: 7, result: Ok(()) }, + Event::BatchFinished + ] + ); + }); + } + + #[test] + fn multi_block_batched_successful() { + ExtBuilder::default().batch(3).build_and_execute(|| { + ErasToCheckPerBlock::::put(2); + CurrentEra::::put(BondingDuration::get()); + + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(6))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(8))); + + assert_eq!(Queue::::count(), 4); + assert_eq!(Head::::get(), None); + + // when + next_block(true); + + // then + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stashes: bounded_vec![ + (1, Deposit::get()), + (5, Deposit::get()), + (7, Deposit::get()) + ], + checked: bounded_vec![3, 2] + }) + ); + + // when + next_block(true); + + // then + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stashes: bounded_vec![ + (1, Deposit::get()), + (5, Deposit::get()), + (7, Deposit::get()) + ], + checked: bounded_vec![3, 2, 1, 0] + }) + ); + + // when + next_block(true); + + // then + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::BatchChecked { eras: vec![3, 2] }, + Event::BatchChecked { eras: vec![1, 0] }, + Event::Unstaked { stash: 1, result: Ok(()) }, + Event::Unstaked { stash: 5, result: Ok(()) }, + Event::Unstaked { stash: 7, result: Ok(()) }, + Event::BatchFinished + ] + ); + }); + } + + #[test] + fn multi_block_batched_some_fail() { + ExtBuilder::default().batch(4).build_and_execute(|| { + ErasToCheckPerBlock::::put(2); + CurrentEra::::put(BondingDuration::get()); + + // register two good ones. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); + create_exposed_nominator(666, 1); + create_exposed_nominator(667, 3); + + // then + assert_eq!(Queue::::count(), 4); + assert_eq!(Head::::get(), None); + + // when + next_block(true); + + // then + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stashes: bounded_vec![ + (1, Deposit::get()), + (3, Deposit::get()), + (666, Deposit::get()) + ], + checked: bounded_vec![3, 2] + }) + ); + + // when + next_block(true); + + // then + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stashes: bounded_vec![(1, Deposit::get()), (3, Deposit::get()),], + checked: bounded_vec![3, 2, 1, 0] + }) + ); + + // when + next_block(true); + + // then + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Slashed { stash: 667, amount: 7 }, + Event::BatchChecked { eras: vec![3, 2] }, + Event::Slashed { stash: 666, amount: 7 }, + Event::BatchChecked { eras: vec![1, 0] }, + Event::Unstaked { stash: 1, result: Ok(()) }, + Event::Unstaked { stash: 3, result: Ok(()) }, + Event::BatchFinished + ] + ); + }); + } + + #[test] + fn multi_block_batched_all_fail_early_exit() { + ExtBuilder::default().batch(2).build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + CurrentEra::::put(BondingDuration::get()); + + // register two bad ones. + create_exposed_nominator(666, 3); + create_exposed_nominator(667, 2); + + // then + assert_eq!(Queue::::count(), 2); + assert_eq!(Head::::get(), None); + + // when we progress a block.. + next_block(true); + + // ..and register two good ones. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); + + // then one of the bad ones is reaped. + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stashes: bounded_vec![(667, Deposit::get())], + checked: bounded_vec![3] + }) + ); + + // when we go to next block + next_block(true); + + // then the head is empty, we early terminate the batch. + assert_eq!(Head::::get(), None); + + // upon next block, we will assemble a new head. + next_block(true); + + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stashes: bounded_vec![(1, Deposit::get()), (3, Deposit::get()),], + checked: bounded_vec![3] + }) + ); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Slashed { stash: 666, amount: Deposit::get() }, + Event::BatchChecked { eras: vec![3] }, + Event::Slashed { stash: 667, amount: Deposit::get() }, + Event::BatchFinished, + Event::BatchChecked { eras: vec![3] } ] ); }); diff --git a/frame/fast-unstake/src/types.rs b/frame/fast-unstake/src/types.rs index 460c9fa4354e5..34ca6517f3168 100644 --- a/frame/fast-unstake/src/types.rs +++ b/frame/fast-unstake/src/types.rs @@ -17,15 +17,14 @@ //! Types used in the Fast Unstake pallet. -use crate::Config; +use crate::{Config, MaxChecking}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - traits::{Currency, Get}, - BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, + traits::Currency, BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use scale_info::TypeInfo; use sp_staking::EraIndex; -use sp_std::{fmt::Debug, prelude::*}; +use sp_std::prelude::*; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -33,15 +32,10 @@ pub type BalanceOf = #[derive( Encode, Decode, EqNoBound, PartialEqNoBound, Clone, TypeInfo, RuntimeDebugNoBound, MaxEncodedLen, )] -pub struct UnstakeRequest< - AccountId: Eq + PartialEq + Debug, - MaxChecked: Get, - Balance: PartialEq + Debug, -> { - /// Their stash account. - pub(crate) stash: AccountId, +#[scale_info(skip_type_params(T))] +pub struct UnstakeRequest { + /// This list of stashes being processed in this request, and their corresponding deposit. + pub(crate) stashes: BoundedVec<(T::AccountId, BalanceOf), T::BatchSize>, /// The list of eras for which they have been checked. - pub(crate) checked: BoundedVec, - /// Deposit to be slashed if the unstake was unsuccessful. - pub(crate) deposit: Balance, + pub(crate) checked: BoundedVec>, } From 14f9fb2e5ec839ae554efb898ab966fa4bb4e14d Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 8 Nov 2022 18:38:01 +0100 Subject: [PATCH 1355/1472] [ci] Use ci-linux:production image in ci (#12648) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f663057faaad5..9053e39eb59bf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,7 +47,7 @@ variables: CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux@sha256:c977b383c2033de50083fad18f6b9e698644230455e016ba708da00eb98d4683" # staging 07.11.2022 + CI_IMAGE: "paritytech/ci-linux:production" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" From b70c64d597c8446a3ab75acc6df81de2b97f32ad Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 8 Nov 2022 14:50:28 -0400 Subject: [PATCH 1356/1472] New Weights for All Pallets (#12325) * new weights for everything * fix * fmt * new batch * fmt * new batch * Update run_all_benchmarks.sh * add headers * update weights * Update lib.rs * block and extrinsic weight --- frame/alliance/src/weights.rs | 377 ++-- frame/assets/src/weights.rs | 238 +-- frame/bags-list/src/weights.rs | 55 +- frame/balances/src/weights.rs | 51 +- frame/benchmarking/src/weights.rs | 97 +- frame/bounties/src/weights.rs | 103 +- frame/child-bounties/src/weights.rs | 67 +- frame/collective/src/weights.rs | 261 ++- frame/contracts/src/weights.rs | 1804 ++++++++--------- frame/conviction-voting/src/weights.rs | 71 +- frame/democracy/src/weights.rs | 209 +- .../src/weights.rs | 181 +- frame/elections-phragmen/src/weights.rs | 151 +- frame/fast-unstake/src/weights.rs | 138 +- frame/gilt/src/weights.rs | 109 +- frame/identity/src/weights.rs | 352 ++-- frame/im-online/src/weights.rs | 35 +- frame/indices/src/weights.rs | 39 +- frame/lottery/src/weights.rs | 55 +- frame/membership/src/weights.rs | 121 +- frame/multisig/src/weights.rs | 145 +- frame/nomination-pools/src/weights.rs | 271 +-- frame/preimage/src/weights.rs | 97 +- frame/proxy/src/weights.rs | 209 +- frame/ranked-collective/src/weights.rs | 110 +- frame/recovery/src/weights.rs | 113 +- frame/referenda/src/weights.rs | 181 +- frame/remark/src/weights.rs | 25 +- frame/scheduler/src/weights.rs | 133 +- frame/session/src/weights.rs | 21 +- frame/staking/src/weights.rs | 561 ++--- frame/state-trie-migration/src/weights.rs | 61 +- frame/support/src/weights/block_weights.rs | 26 +- .../support/src/weights/extrinsic_weights.rs | 26 +- frame/system/src/weights.rs | 93 +- frame/timestamp/src/weights.rs | 21 +- frame/tips/src/weights.rs | 105 +- frame/transaction-storage/src/weights.rs | 55 +- frame/treasury/src/weights.rs | 73 +- frame/uniques/src/weights.rs | 254 +-- frame/utility/src/weights.rs | 63 +- frame/vesting/src/weights.rs | 217 +- frame/whitelist/src/weights.rs | 59 +- 43 files changed, 4169 insertions(+), 3264 deletions(-) diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 9e2ee5681aa99..29038efd2c25c 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,23 +18,24 @@ //! Autogenerated weights for pallet_alliance //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_alliance // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --pallet=pallet_alliance -// --chain=dev // --output=./frame/alliance/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -80,14 +81,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[0, 90]`. /// The range of component `p` is `[1, 100]`. - fn propose_proposed(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(34_420_000 as u64) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(145_000 as u64).saturating_mul(x as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(y as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(197_000 as u64).saturating_mul(p as u64)) + fn propose_proposed(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + // Minimum execution time: 43_720 nanoseconds. + Weight::from_ref_time(44_766_307 as u64) + // Standard Error: 2_522 + .saturating_add(Weight::from_ref_time(54_721 as u64).saturating_mul(y as u64)) + // Standard Error: 2_301 + .saturating_add(Weight::from_ref_time(173_300 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -95,10 +95,13 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Voting (r:1 w:1) /// The range of component `x` is `[3, 10]`. /// The range of component `y` is `[2, 90]`. - fn vote(_x: u32, y: u32, ) -> Weight { - Weight::from_ref_time(48_443_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(y as u64)) + fn vote(x: u32, y: u32, ) -> Weight { + // Minimum execution time: 46_984 nanoseconds. + Weight::from_ref_time(46_837_255 as u64) + // Standard Error: 32_860 + .saturating_add(Weight::from_ref_time(273_691 as u64).saturating_mul(x as u64)) + // Standard Error: 2_781 + .saturating_add(Weight::from_ref_time(126_964 as u64).saturating_mul(y as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -108,9 +111,10 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - Weight::from_ref_time(35_056_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(171_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 34_734 nanoseconds. + Weight::from_ref_time(37_652_708 as u64) + // Standard Error: 1_270 + .saturating_add(Weight::from_ref_time(183_078 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -123,13 +127,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(36_929_000 as u64) - // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(287_000 as u64).saturating_mul(x as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(105_000 as u64).saturating_mul(y as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(180_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 50_147 nanoseconds. + Weight::from_ref_time(42_719_616 as u64) + // Standard Error: 19_981 + .saturating_add(Weight::from_ref_time(188_796 as u64).saturating_mul(x as u64)) + // Standard Error: 1_947 + .saturating_add(Weight::from_ref_time(95_998 as u64).saturating_mul(y as u64)) + // Standard Error: 1_739 + .saturating_add(Weight::from_ref_time(177_837 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -142,14 +147,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(48_085_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(100_000 as u64).saturating_mul(y as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(210_000 as u64).saturating_mul(p as u64)) + fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { + // Minimum execution time: 59_495 nanoseconds. + Weight::from_ref_time(53_137_721 as u64) + // Standard Error: 138 + .saturating_add(Weight::from_ref_time(1_979 as u64).saturating_mul(b as u64)) + // Standard Error: 16_388 + .saturating_add(Weight::from_ref_time(8_198 as u64).saturating_mul(x as u64)) + // Standard Error: 1_599 + .saturating_add(Weight::from_ref_time(86_577 as u64).saturating_mul(y as u64)) + // Standard Error: 1_428 + .saturating_add(Weight::from_ref_time(215_905 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -163,11 +171,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(43_377_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(99_000 as u64).saturating_mul(y as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(190_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 52_405 nanoseconds. + Weight::from_ref_time(44_494_732 as u64) + // Standard Error: 1_759 + .saturating_add(Weight::from_ref_time(118_517 as u64).saturating_mul(y as u64)) + // Standard Error: 1_572 + .saturating_add(Weight::from_ref_time(198_256 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -181,14 +190,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_approved(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(41_417_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(67_000 as u64).saturating_mul(x as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(88_000 as u64).saturating_mul(y as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(196_000 as u64).saturating_mul(p as u64)) + fn close_approved(b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + // Minimum execution time: 52_737 nanoseconds. + Weight::from_ref_time(45_874_458 as u64) + // Standard Error: 140 + .saturating_add(Weight::from_ref_time(601 as u64).saturating_mul(b as u64)) + // Standard Error: 1_623 + .saturating_add(Weight::from_ref_time(88_372 as u64).saturating_mul(y as u64)) + // Standard Error: 1_449 + .saturating_add(Weight::from_ref_time(197_595 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -197,12 +207,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[1, 10]`. /// The range of component `y` is `[0, 90]`. /// The range of component `z` is `[0, 100]`. - fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { - Weight::from_ref_time(37_202_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(149_000 as u64).saturating_mul(y as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(120_000 as u64).saturating_mul(z as u64)) + fn init_members(x: u32, y: u32, z: u32, ) -> Weight { + // Minimum execution time: 48_821 nanoseconds. + Weight::from_ref_time(32_972_152 as u64) + // Standard Error: 17_618 + .saturating_add(Weight::from_ref_time(230_451 as u64).saturating_mul(x as u64)) + // Standard Error: 1_865 + .saturating_add(Weight::from_ref_time(172_532 as u64).saturating_mul(y as u64)) + // Standard Error: 1_682 + .saturating_add(Weight::from_ref_time(145_258 as u64).saturating_mul(z as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -216,13 +229,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[0, 100]`. /// The range of component `z` is `[0, 50]`. fn disband(x: u32, y: u32, z: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(1_447_000 as u64).saturating_mul(x as u64)) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(1_512_000 as u64).saturating_mul(y as u64)) - // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(10_760_000 as u64).saturating_mul(z as u64)) + // Minimum execution time: 256_235 nanoseconds. + Weight::from_ref_time(258_695_000 as u64) + // Standard Error: 19_643 + .saturating_add(Weight::from_ref_time(436_821 as u64).saturating_mul(x as u64)) + // Standard Error: 19_549 + .saturating_add(Weight::from_ref_time(496_858 as u64).saturating_mul(y as u64)) + // Standard Error: 39_062 + .saturating_add(Weight::from_ref_time(9_169_692 as u64).saturating_mul(z as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(x as u64))) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(y as u64))) @@ -232,18 +246,21 @@ impl WeightInfo for SubstrateWeight { } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - Weight::from_ref_time(18_101_000 as u64) + // Minimum execution time: 19_205 nanoseconds. + Weight::from_ref_time(19_502_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - Weight::from_ref_time(21_090_000 as u64) + // Minimum execution time: 22_562 nanoseconds. + Weight::from_ref_time(22_842_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - Weight::from_ref_time(22_118_000 as u64) + // Minimum execution time: 23_773 nanoseconds. + Weight::from_ref_time(24_212_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -252,14 +269,16 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - Weight::from_ref_time(53_446_000 as u64) + // Minimum execution time: 57_709 nanoseconds. + Weight::from_ref_time(59_155_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - Weight::from_ref_time(42_690_000 as u64) + // Minimum execution time: 44_576 nanoseconds. + Weight::from_ref_time(45_162_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -268,7 +287,8 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - Weight::from_ref_time(37_396_000 as u64) + // Minimum execution time: 38_913 nanoseconds. + Weight::from_ref_time(39_637_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -278,7 +298,8 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - Weight::from_ref_time(40_644_000 as u64) + // Minimum execution time: 42_947 nanoseconds. + Weight::from_ref_time(43_414_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -287,7 +308,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - Weight::from_ref_time(43_440_000 as u64) + // Minimum execution time: 46_281 nanoseconds. + Weight::from_ref_time(46_703_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -298,33 +320,36 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - Weight::from_ref_time(61_060_000 as u64) + // Minimum execution time: 65_274 nanoseconds. + Weight::from_ref_time(65_762_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) - /// The range of component `n` is `[1, 100]`. - /// The range of component `l` is `[1, 255]`. + /// The range of component `n` is `[0, 100]`. + /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_362_000 as u64).saturating_mul(n as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(l as u64)) + // Minimum execution time: 17_396 nanoseconds. + Weight::from_ref_time(17_638_000 as u64) + // Standard Error: 2_602 + .saturating_add(Weight::from_ref_time(1_286_177 as u64).saturating_mul(n as u64)) + // Standard Error: 1_019 + .saturating_add(Weight::from_ref_time(70_947 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) - /// The range of component `n` is `[1, 100]`. - /// The range of component `l` is `[1, 255]`. + /// The range of component `n` is `[0, 100]`. + /// The range of component `l` is `[0, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 147_000 - .saturating_add(Weight::from_ref_time(21_060_000 as u64).saturating_mul(n as u64)) - // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(3_683_000 as u64).saturating_mul(l as u64)) + // Minimum execution time: 17_446 nanoseconds. + Weight::from_ref_time(17_725_000 as u64) + // Standard Error: 163_579 + .saturating_add(Weight::from_ref_time(12_823_232 as u64).saturating_mul(n as u64)) + // Standard Error: 64_064 + .saturating_add(Weight::from_ref_time(496_642 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -341,14 +366,13 @@ impl WeightInfo for () { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[0, 90]`. /// The range of component `p` is `[1, 100]`. - fn propose_proposed(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(34_420_000 as u64) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(145_000 as u64).saturating_mul(x as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(y as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(197_000 as u64).saturating_mul(p as u64)) + fn propose_proposed(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + // Minimum execution time: 43_720 nanoseconds. + Weight::from_ref_time(44_766_307 as u64) + // Standard Error: 2_522 + .saturating_add(Weight::from_ref_time(54_721 as u64).saturating_mul(y as u64)) + // Standard Error: 2_301 + .saturating_add(Weight::from_ref_time(173_300 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -356,10 +380,13 @@ impl WeightInfo for () { // Storage: AllianceMotion Voting (r:1 w:1) /// The range of component `x` is `[3, 10]`. /// The range of component `y` is `[2, 90]`. - fn vote(_x: u32, y: u32, ) -> Weight { - Weight::from_ref_time(48_443_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(y as u64)) + fn vote(x: u32, y: u32, ) -> Weight { + // Minimum execution time: 46_984 nanoseconds. + Weight::from_ref_time(46_837_255 as u64) + // Standard Error: 32_860 + .saturating_add(Weight::from_ref_time(273_691 as u64).saturating_mul(x as u64)) + // Standard Error: 2_781 + .saturating_add(Weight::from_ref_time(126_964 as u64).saturating_mul(y as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -369,9 +396,10 @@ impl WeightInfo for () { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - Weight::from_ref_time(35_056_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(171_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 34_734 nanoseconds. + Weight::from_ref_time(37_652_708 as u64) + // Standard Error: 1_270 + .saturating_add(Weight::from_ref_time(183_078 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -384,13 +412,14 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(36_929_000 as u64) - // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(287_000 as u64).saturating_mul(x as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(105_000 as u64).saturating_mul(y as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(180_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 50_147 nanoseconds. + Weight::from_ref_time(42_719_616 as u64) + // Standard Error: 19_981 + .saturating_add(Weight::from_ref_time(188_796 as u64).saturating_mul(x as u64)) + // Standard Error: 1_947 + .saturating_add(Weight::from_ref_time(95_998 as u64).saturating_mul(y as u64)) + // Standard Error: 1_739 + .saturating_add(Weight::from_ref_time(177_837 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -403,14 +432,17 @@ impl WeightInfo for () { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(48_085_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(100_000 as u64).saturating_mul(y as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(210_000 as u64).saturating_mul(p as u64)) + fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { + // Minimum execution time: 59_495 nanoseconds. + Weight::from_ref_time(53_137_721 as u64) + // Standard Error: 138 + .saturating_add(Weight::from_ref_time(1_979 as u64).saturating_mul(b as u64)) + // Standard Error: 16_388 + .saturating_add(Weight::from_ref_time(8_198 as u64).saturating_mul(x as u64)) + // Standard Error: 1_599 + .saturating_add(Weight::from_ref_time(86_577 as u64).saturating_mul(y as u64)) + // Standard Error: 1_428 + .saturating_add(Weight::from_ref_time(215_905 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -424,11 +456,12 @@ impl WeightInfo for () { /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(43_377_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(99_000 as u64).saturating_mul(y as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(190_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 52_405 nanoseconds. + Weight::from_ref_time(44_494_732 as u64) + // Standard Error: 1_759 + .saturating_add(Weight::from_ref_time(118_517 as u64).saturating_mul(y as u64)) + // Standard Error: 1_572 + .saturating_add(Weight::from_ref_time(198_256 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -442,14 +475,15 @@ impl WeightInfo for () { /// The range of component `x` is `[2, 10]`. /// The range of component `y` is `[2, 90]`. /// The range of component `p` is `[1, 100]`. - fn close_approved(_b: u32, x: u32, y: u32, p: u32, ) -> Weight { - Weight::from_ref_time(41_417_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(67_000 as u64).saturating_mul(x as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(88_000 as u64).saturating_mul(y as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(196_000 as u64).saturating_mul(p as u64)) + fn close_approved(b: u32, _x: u32, y: u32, p: u32, ) -> Weight { + // Minimum execution time: 52_737 nanoseconds. + Weight::from_ref_time(45_874_458 as u64) + // Standard Error: 140 + .saturating_add(Weight::from_ref_time(601 as u64).saturating_mul(b as u64)) + // Standard Error: 1_623 + .saturating_add(Weight::from_ref_time(88_372 as u64).saturating_mul(y as u64)) + // Standard Error: 1_449 + .saturating_add(Weight::from_ref_time(197_595 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -458,12 +492,15 @@ impl WeightInfo for () { /// The range of component `x` is `[1, 10]`. /// The range of component `y` is `[0, 90]`. /// The range of component `z` is `[0, 100]`. - fn init_members(_x: u32, y: u32, z: u32, ) -> Weight { - Weight::from_ref_time(37_202_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(149_000 as u64).saturating_mul(y as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(120_000 as u64).saturating_mul(z as u64)) + fn init_members(x: u32, y: u32, z: u32, ) -> Weight { + // Minimum execution time: 48_821 nanoseconds. + Weight::from_ref_time(32_972_152 as u64) + // Standard Error: 17_618 + .saturating_add(Weight::from_ref_time(230_451 as u64).saturating_mul(x as u64)) + // Standard Error: 1_865 + .saturating_add(Weight::from_ref_time(172_532 as u64).saturating_mul(y as u64)) + // Standard Error: 1_682 + .saturating_add(Weight::from_ref_time(145_258 as u64).saturating_mul(z as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -477,13 +514,14 @@ impl WeightInfo for () { /// The range of component `y` is `[0, 100]`. /// The range of component `z` is `[0, 50]`. fn disband(x: u32, y: u32, z: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(1_447_000 as u64).saturating_mul(x as u64)) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(1_512_000 as u64).saturating_mul(y as u64)) - // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(10_760_000 as u64).saturating_mul(z as u64)) + // Minimum execution time: 256_235 nanoseconds. + Weight::from_ref_time(258_695_000 as u64) + // Standard Error: 19_643 + .saturating_add(Weight::from_ref_time(436_821 as u64).saturating_mul(x as u64)) + // Standard Error: 19_549 + .saturating_add(Weight::from_ref_time(496_858 as u64).saturating_mul(y as u64)) + // Standard Error: 39_062 + .saturating_add(Weight::from_ref_time(9_169_692 as u64).saturating_mul(z as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(x as u64))) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(y as u64))) @@ -493,18 +531,21 @@ impl WeightInfo for () { } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - Weight::from_ref_time(18_101_000 as u64) + // Minimum execution time: 19_205 nanoseconds. + Weight::from_ref_time(19_502_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - Weight::from_ref_time(21_090_000 as u64) + // Minimum execution time: 22_562 nanoseconds. + Weight::from_ref_time(22_842_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - Weight::from_ref_time(22_118_000 as u64) + // Minimum execution time: 23_773 nanoseconds. + Weight::from_ref_time(24_212_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -513,14 +554,16 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - Weight::from_ref_time(53_446_000 as u64) + // Minimum execution time: 57_709 nanoseconds. + Weight::from_ref_time(59_155_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Alliance Members (r:4 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - Weight::from_ref_time(42_690_000 as u64) + // Minimum execution time: 44_576 nanoseconds. + Weight::from_ref_time(45_162_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -529,7 +572,8 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - Weight::from_ref_time(37_396_000 as u64) + // Minimum execution time: 38_913 nanoseconds. + Weight::from_ref_time(39_637_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -539,7 +583,8 @@ impl WeightInfo for () { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - Weight::from_ref_time(40_644_000 as u64) + // Minimum execution time: 42_947 nanoseconds. + Weight::from_ref_time(43_414_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } @@ -548,7 +593,8 @@ impl WeightInfo for () { // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - Weight::from_ref_time(43_440_000 as u64) + // Minimum execution time: 46_281 nanoseconds. + Weight::from_ref_time(46_703_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -559,33 +605,36 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - Weight::from_ref_time(61_060_000 as u64) + // Minimum execution time: 65_274 nanoseconds. + Weight::from_ref_time(65_762_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) - /// The range of component `n` is `[1, 100]`. - /// The range of component `l` is `[1, 255]`. + /// The range of component `n` is `[0, 100]`. + /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_362_000 as u64).saturating_mul(n as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(l as u64)) + // Minimum execution time: 17_396 nanoseconds. + Weight::from_ref_time(17_638_000 as u64) + // Standard Error: 2_602 + .saturating_add(Weight::from_ref_time(1_286_177 as u64).saturating_mul(n as u64)) + // Standard Error: 1_019 + .saturating_add(Weight::from_ref_time(70_947 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) - /// The range of component `n` is `[1, 100]`. - /// The range of component `l` is `[1, 255]`. + /// The range of component `n` is `[0, 100]`. + /// The range of component `l` is `[0, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 147_000 - .saturating_add(Weight::from_ref_time(21_060_000 as u64).saturating_mul(n as u64)) - // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(3_683_000 as u64).saturating_mul(l as u64)) + // Minimum execution time: 17_446 nanoseconds. + Weight::from_ref_time(17_725_000 as u64) + // Standard Error: 163_579 + .saturating_add(Weight::from_ref_time(12_823_232 as u64).saturating_mul(n as u64)) + // Standard Error: 64_064 + .saturating_add(Weight::from_ref_time(496_642 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index c260da70e3480..3b29e55b306fe 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,24 +18,24 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-10-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_assets // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_assets -// --chain=dev // --output=./frame/assets/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -77,15 +77,15 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - // Minimum execution time: 32_200 nanoseconds. - Weight::from_ref_time(32_739_000 as u64) + // Minimum execution time: 33_241 nanoseconds. + Weight::from_ref_time(33_873_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - // Minimum execution time: 19_192 nanoseconds. - Weight::from_ref_time(19_615_000 as u64) + // Minimum execution time: 19_883 nanoseconds. + Weight::from_ref_time(20_651_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -98,12 +98,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 5000]`. /// The range of component `a` is `[0, 500]`. fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - // Minimum execution time: 75_299_531 nanoseconds. - Weight::from_ref_time(75_567_795_000 as u64) - // Standard Error: 126_181 - .saturating_add(Weight::from_ref_time(8_378_363 as u64).saturating_mul(c as u64)) - // Standard Error: 126_181 - .saturating_add(Weight::from_ref_time(10_950_076 as u64).saturating_mul(s as u64)) + // Minimum execution time: 76_222_544 nanoseconds. + Weight::from_ref_time(76_864_587_000 as u64) + // Standard Error: 127_086 + .saturating_add(Weight::from_ref_time(8_645_143 as u64).saturating_mul(c as u64)) + // Standard Error: 127_086 + .saturating_add(Weight::from_ref_time(11_281_301 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(c as u64))) .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) @@ -116,16 +116,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - // Minimum execution time: 35_066 nanoseconds. - Weight::from_ref_time(36_217_000 as u64) + // Minimum execution time: 36_782 nanoseconds. + Weight::from_ref_time(37_340_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - // Minimum execution time: 44_915 nanoseconds. - Weight::from_ref_time(45_807_000 as u64) + // Minimum execution time: 44_425 nanoseconds. + Weight::from_ref_time(45_485_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -133,8 +133,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - // Minimum execution time: 57_245 nanoseconds. - Weight::from_ref_time(58_179_000 as u64) + // Minimum execution time: 58_294 nanoseconds. + Weight::from_ref_time(59_447_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -142,8 +142,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - // Minimum execution time: 47_028 nanoseconds. - Weight::from_ref_time(47_571_000 as u64) + // Minimum execution time: 46_704 nanoseconds. + Weight::from_ref_time(47_521_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -151,53 +151,53 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - // Minimum execution time: 57_069 nanoseconds. - Weight::from_ref_time(58_245_000 as u64) + // Minimum execution time: 57_647 nanoseconds. + Weight::from_ref_time(58_417_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - // Minimum execution time: 26_823 nanoseconds. - Weight::from_ref_time(27_689_000 as u64) + // Minimum execution time: 26_827 nanoseconds. + Weight::from_ref_time(27_373_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - // Minimum execution time: 26_984 nanoseconds. - Weight::from_ref_time(27_591_000 as u64) + // Minimum execution time: 26_291 nanoseconds. + Weight::from_ref_time(26_854_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - // Minimum execution time: 23_803 nanoseconds. - Weight::from_ref_time(24_269_000 as u64) + // Minimum execution time: 22_694 nanoseconds. + Weight::from_ref_time(23_613_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - // Minimum execution time: 22_977 nanoseconds. - Weight::from_ref_time(23_527_000 as u64) + // Minimum execution time: 22_572 nanoseconds. + Weight::from_ref_time(24_121_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - // Minimum execution time: 23_815 nanoseconds. - Weight::from_ref_time(24_597_000 as u64) + // Minimum execution time: 23_949 nanoseconds. + Weight::from_ref_time(24_347_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - // Minimum execution time: 22_691 nanoseconds. - Weight::from_ref_time(23_173_000 as u64) + // Minimum execution time: 23_102 nanoseconds. + Weight::from_ref_time(23_518_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -205,17 +205,19 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Metadata (r:1 w:1) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(_n: u32, _s: u32, ) -> Weight { - // Minimum execution time: 40_675 nanoseconds. - Weight::from_ref_time(42_869_113 as u64) + fn set_metadata(_n: u32, s: u32, ) -> Weight { + // Minimum execution time: 41_032 nanoseconds. + Weight::from_ref_time(42_845_624 as u64) + // Standard Error: 1_274 + .saturating_add(Weight::from_ref_time(1_875 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - // Minimum execution time: 42_361 nanoseconds. - Weight::from_ref_time(42_912_000 as u64) + // Minimum execution time: 42_570 nanoseconds. + Weight::from_ref_time(42_957_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -224,35 +226,35 @@ impl WeightInfo for SubstrateWeight { /// 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 { - // Minimum execution time: 22_998 nanoseconds. - Weight::from_ref_time(23_844_675 as u64) - // Standard Error: 506 - .saturating_add(Weight::from_ref_time(2_874 as u64).saturating_mul(n as u64)) - // Standard Error: 506 - .saturating_add(Weight::from_ref_time(3_817 as u64).saturating_mul(s as u64)) + // Minimum execution time: 22_768 nanoseconds. + Weight::from_ref_time(23_868_816 as u64) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(1_602 as u64).saturating_mul(n as u64)) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(2_097 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - // Minimum execution time: 42_305 nanoseconds. - Weight::from_ref_time(42_678_000 as u64) + // Minimum execution time: 41_863 nanoseconds. + Weight::from_ref_time(42_643_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - // Minimum execution time: 22_052 nanoseconds. - Weight::from_ref_time(22_610_000 as u64) + // Minimum execution time: 21_747 nanoseconds. + Weight::from_ref_time(22_595_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - // Minimum execution time: 44_900 nanoseconds. - Weight::from_ref_time(46_032_000 as u64) + // Minimum execution time: 45_602 nanoseconds. + Weight::from_ref_time(46_004_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -261,24 +263,24 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - // Minimum execution time: 72_261 nanoseconds. - Weight::from_ref_time(73_186_000 as u64) + // Minimum execution time: 70_944 nanoseconds. + Weight::from_ref_time(71_722_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - // Minimum execution time: 47_268 nanoseconds. - Weight::from_ref_time(47_712_000 as u64) + // Minimum execution time: 46_316 nanoseconds. + Weight::from_ref_time(46_910_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - // Minimum execution time: 47_363 nanoseconds. - Weight::from_ref_time(48_696_000 as u64) + // Minimum execution time: 47_145 nanoseconds. + Weight::from_ref_time(47_611_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -288,15 +290,15 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - // Minimum execution time: 32_200 nanoseconds. - Weight::from_ref_time(32_739_000 as u64) + // Minimum execution time: 33_241 nanoseconds. + Weight::from_ref_time(33_873_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - // Minimum execution time: 19_192 nanoseconds. - Weight::from_ref_time(19_615_000 as u64) + // Minimum execution time: 19_883 nanoseconds. + Weight::from_ref_time(20_651_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -309,12 +311,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 5000]`. /// The range of component `a` is `[0, 500]`. fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - // Minimum execution time: 75_299_531 nanoseconds. - Weight::from_ref_time(75_567_795_000 as u64) - // Standard Error: 126_181 - .saturating_add(Weight::from_ref_time(8_378_363 as u64).saturating_mul(c as u64)) - // Standard Error: 126_181 - .saturating_add(Weight::from_ref_time(10_950_076 as u64).saturating_mul(s as u64)) + // Minimum execution time: 76_222_544 nanoseconds. + Weight::from_ref_time(76_864_587_000 as u64) + // Standard Error: 127_086 + .saturating_add(Weight::from_ref_time(8_645_143 as u64).saturating_mul(c as u64)) + // Standard Error: 127_086 + .saturating_add(Weight::from_ref_time(11_281_301 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(c as u64))) .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) @@ -327,16 +329,16 @@ impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - // Minimum execution time: 35_066 nanoseconds. - Weight::from_ref_time(36_217_000 as u64) + // Minimum execution time: 36_782 nanoseconds. + Weight::from_ref_time(37_340_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - // Minimum execution time: 44_915 nanoseconds. - Weight::from_ref_time(45_807_000 as u64) + // Minimum execution time: 44_425 nanoseconds. + Weight::from_ref_time(45_485_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -344,8 +346,8 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - // Minimum execution time: 57_245 nanoseconds. - Weight::from_ref_time(58_179_000 as u64) + // Minimum execution time: 58_294 nanoseconds. + Weight::from_ref_time(59_447_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -353,8 +355,8 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - // Minimum execution time: 47_028 nanoseconds. - Weight::from_ref_time(47_571_000 as u64) + // Minimum execution time: 46_704 nanoseconds. + Weight::from_ref_time(47_521_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -362,53 +364,53 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - // Minimum execution time: 57_069 nanoseconds. - Weight::from_ref_time(58_245_000 as u64) + // Minimum execution time: 57_647 nanoseconds. + Weight::from_ref_time(58_417_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - // Minimum execution time: 26_823 nanoseconds. - Weight::from_ref_time(27_689_000 as u64) + // Minimum execution time: 26_827 nanoseconds. + Weight::from_ref_time(27_373_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - // Minimum execution time: 26_984 nanoseconds. - Weight::from_ref_time(27_591_000 as u64) + // Minimum execution time: 26_291 nanoseconds. + Weight::from_ref_time(26_854_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - // Minimum execution time: 23_803 nanoseconds. - Weight::from_ref_time(24_269_000 as u64) + // Minimum execution time: 22_694 nanoseconds. + Weight::from_ref_time(23_613_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - // Minimum execution time: 22_977 nanoseconds. - Weight::from_ref_time(23_527_000 as u64) + // Minimum execution time: 22_572 nanoseconds. + Weight::from_ref_time(24_121_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - // Minimum execution time: 23_815 nanoseconds. - Weight::from_ref_time(24_597_000 as u64) + // Minimum execution time: 23_949 nanoseconds. + Weight::from_ref_time(24_347_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - // Minimum execution time: 22_691 nanoseconds. - Weight::from_ref_time(23_173_000 as u64) + // Minimum execution time: 23_102 nanoseconds. + Weight::from_ref_time(23_518_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -416,17 +418,19 @@ impl WeightInfo for () { // Storage: Assets Metadata (r:1 w:1) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(_n: u32, _s: u32, ) -> Weight { - // Minimum execution time: 40_675 nanoseconds. - Weight::from_ref_time(42_869_113 as u64) + fn set_metadata(_n: u32, s: u32, ) -> Weight { + // Minimum execution time: 41_032 nanoseconds. + Weight::from_ref_time(42_845_624 as u64) + // Standard Error: 1_274 + .saturating_add(Weight::from_ref_time(1_875 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - // Minimum execution time: 42_361 nanoseconds. - Weight::from_ref_time(42_912_000 as u64) + // Minimum execution time: 42_570 nanoseconds. + Weight::from_ref_time(42_957_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -435,35 +439,35 @@ impl WeightInfo for () { /// 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 { - // Minimum execution time: 22_998 nanoseconds. - Weight::from_ref_time(23_844_675 as u64) - // Standard Error: 506 - .saturating_add(Weight::from_ref_time(2_874 as u64).saturating_mul(n as u64)) - // Standard Error: 506 - .saturating_add(Weight::from_ref_time(3_817 as u64).saturating_mul(s as u64)) + // Minimum execution time: 22_768 nanoseconds. + Weight::from_ref_time(23_868_816 as u64) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(1_602 as u64).saturating_mul(n as u64)) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(2_097 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - // Minimum execution time: 42_305 nanoseconds. - Weight::from_ref_time(42_678_000 as u64) + // Minimum execution time: 41_863 nanoseconds. + Weight::from_ref_time(42_643_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - // Minimum execution time: 22_052 nanoseconds. - Weight::from_ref_time(22_610_000 as u64) + // Minimum execution time: 21_747 nanoseconds. + Weight::from_ref_time(22_595_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - // Minimum execution time: 44_900 nanoseconds. - Weight::from_ref_time(46_032_000 as u64) + // Minimum execution time: 45_602 nanoseconds. + Weight::from_ref_time(46_004_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -472,24 +476,24 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - // Minimum execution time: 72_261 nanoseconds. - Weight::from_ref_time(73_186_000 as u64) + // Minimum execution time: 70_944 nanoseconds. + Weight::from_ref_time(71_722_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - // Minimum execution time: 47_268 nanoseconds. - Weight::from_ref_time(47_712_000 as u64) + // Minimum execution time: 46_316 nanoseconds. + Weight::from_ref_time(46_910_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - // Minimum execution time: 47_363 nanoseconds. - Weight::from_ref_time(48_696_000 as u64) + // Minimum execution time: 47_145 nanoseconds. + Weight::from_ref_time(47_611_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index 46f001972c519..a298dc3172f79 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_bags_list //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/bags-list/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,29 +57,32 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) - // Storage: BagsList ListNodes (r:4 w:4) - // Storage: BagsList ListBags (r:1 w:1) + // Storage: VoterList ListNodes (r:4 w:4) + // Storage: VoterList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - Weight::from_ref_time(55_040_000 as u64) + // Minimum execution time: 73_553 nanoseconds. + Weight::from_ref_time(74_366_000 as u64) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - Weight::from_ref_time(53_671_000 as u64) + // Minimum execution time: 72_700 nanoseconds. + Weight::from_ref_time(73_322_000 as u64) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } - // Storage: BagsList ListNodes (r:4 w:4) + // Storage: VoterList ListNodes (r:4 w:4) // Storage: Staking Bonded (r:2 w:0) // Storage: Staking Ledger (r:2 w:0) - // Storage: BagsList CounterForListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - Weight::from_ref_time(56_410_000 as u64) + // Minimum execution time: 71_691 nanoseconds. + Weight::from_ref_time(72_798_000 as u64) .saturating_add(T::DbWeight::get().reads(10 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -86,29 +92,32 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) - // Storage: BagsList ListNodes (r:4 w:4) - // Storage: BagsList ListBags (r:1 w:1) + // Storage: VoterList ListNodes (r:4 w:4) + // Storage: VoterList ListBags (r:1 w:1) fn rebag_non_terminal() -> Weight { - Weight::from_ref_time(55_040_000 as u64) + // Minimum execution time: 73_553 nanoseconds. + Weight::from_ref_time(74_366_000 as u64) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn rebag_terminal() -> Weight { - Weight::from_ref_time(53_671_000 as u64) + // Minimum execution time: 72_700 nanoseconds. + Weight::from_ref_time(73_322_000 as u64) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } - // Storage: BagsList ListNodes (r:4 w:4) + // Storage: VoterList ListNodes (r:4 w:4) // Storage: Staking Bonded (r:2 w:0) // Storage: Staking Ledger (r:2 w:0) - // Storage: BagsList CounterForListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) fn put_in_front_of() -> Weight { - Weight::from_ref_time(56_410_000 as u64) + // Minimum execution time: 71_691 nanoseconds. + Weight::from_ref_time(72_798_000 as u64) .saturating_add(RocksDbWeight::get().reads(10 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index 42d165e61a38e..6324745fd4310 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_balances //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/balances/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -58,43 +61,50 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(41_860_000 as u64) + // Minimum execution time: 48_134 nanoseconds. + Weight::from_ref_time(48_811_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(32_760_000 as u64) + // Minimum execution time: 36_586 nanoseconds. + Weight::from_ref_time(36_966_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - Weight::from_ref_time(22_279_000 as u64) + // Minimum execution time: 28_486 nanoseconds. + Weight::from_ref_time(28_940_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - Weight::from_ref_time(25_488_000 as u64) + // Minimum execution time: 31_225 nanoseconds. + Weight::from_ref_time(31_946_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - Weight::from_ref_time(42_190_000 as u64) + // Minimum execution time: 47_347 nanoseconds. + Weight::from_ref_time(48_005_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - Weight::from_ref_time(37_789_000 as u64) + // Minimum execution time: 41_668 nanoseconds. + Weight::from_ref_time(42_232_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - Weight::from_ref_time(20_056_000 as u64) + // Minimum execution time: 23_741 nanoseconds. + Weight::from_ref_time(24_073_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -104,43 +114,50 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(41_860_000 as u64) + // Minimum execution time: 48_134 nanoseconds. + Weight::from_ref_time(48_811_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(32_760_000 as u64) + // Minimum execution time: 36_586 nanoseconds. + Weight::from_ref_time(36_966_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - Weight::from_ref_time(22_279_000 as u64) + // Minimum execution time: 28_486 nanoseconds. + Weight::from_ref_time(28_940_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - Weight::from_ref_time(25_488_000 as u64) + // Minimum execution time: 31_225 nanoseconds. + Weight::from_ref_time(31_946_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - Weight::from_ref_time(42_190_000 as u64) + // Minimum execution time: 47_347 nanoseconds. + Weight::from_ref_time(48_005_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - Weight::from_ref_time(37_789_000 as u64) + // Minimum execution time: 41_668 nanoseconds. + Weight::from_ref_time(42_232_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - Weight::from_ref_time(20_056_000 as u64) + // Minimum execution time: 23_741 nanoseconds. + Weight::from_ref_time(24_073_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index 62117a6f65b07..5e5a2e7ee343c 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for frame_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/benchmarking/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,76 +60,108 @@ pub trait WeightInfo { /// Weights for frame_benchmarking using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { + /// The range of component `i` is `[0, 1000000]`. fn addition(_i: u32, ) -> Weight { - Weight::from_ref_time(103_000 as u64) + // Minimum execution time: 108 nanoseconds. + Weight::from_ref_time(137_610 as u64) } + /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { - Weight::from_ref_time(105_000 as u64) + // Minimum execution time: 104 nanoseconds. + Weight::from_ref_time(133_508 as u64) } + /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { - Weight::from_ref_time(113_000 as u64) + // Minimum execution time: 110 nanoseconds. + Weight::from_ref_time(140_230 as u64) } + /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { - Weight::from_ref_time(102_000 as u64) + // Minimum execution time: 96 nanoseconds. + Weight::from_ref_time(136_059 as u64) } + /// The range of component `i` is `[0, 100]`. fn hashing(_i: u32, ) -> Weight { - Weight::from_ref_time(20_865_902_000 as u64) + // Minimum execution time: 21_804_747 nanoseconds. + Weight::from_ref_time(22_013_681_386 as u64) } + /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { - Weight::from_ref_time(319_000 as u64) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(47_171_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 136 nanoseconds. + Weight::from_ref_time(156_000 as u64) + // Standard Error: 4_531 + .saturating_add(Weight::from_ref_time(46_817_640 as u64).saturating_mul(i as u64)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `i` is `[0, 1000]`. fn storage_read(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_110_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 125 nanoseconds. + Weight::from_ref_time(135_000 as u64) + // Standard Error: 3_651 + .saturating_add(Weight::from_ref_time(2_021_172 as u64).saturating_mul(i as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `i` is `[0, 1000]`. fn storage_write(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(372_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 120 nanoseconds. + Weight::from_ref_time(131_000 as u64) + // Standard Error: 348 + .saturating_add(Weight::from_ref_time(377_243 as u64).saturating_mul(i as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } } // For backwards compatibility and tests impl WeightInfo for () { + /// The range of component `i` is `[0, 1000000]`. fn addition(_i: u32, ) -> Weight { - Weight::from_ref_time(103_000 as u64) + // Minimum execution time: 108 nanoseconds. + Weight::from_ref_time(137_610 as u64) } + /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { - Weight::from_ref_time(105_000 as u64) + // Minimum execution time: 104 nanoseconds. + Weight::from_ref_time(133_508 as u64) } + /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { - Weight::from_ref_time(113_000 as u64) + // Minimum execution time: 110 nanoseconds. + Weight::from_ref_time(140_230 as u64) } + /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { - Weight::from_ref_time(102_000 as u64) + // Minimum execution time: 96 nanoseconds. + Weight::from_ref_time(136_059 as u64) } + /// The range of component `i` is `[0, 100]`. fn hashing(_i: u32, ) -> Weight { - Weight::from_ref_time(20_865_902_000 as u64) + // Minimum execution time: 21_804_747 nanoseconds. + Weight::from_ref_time(22_013_681_386 as u64) } + /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { - Weight::from_ref_time(319_000 as u64) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(47_171_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 136 nanoseconds. + Weight::from_ref_time(156_000 as u64) + // Standard Error: 4_531 + .saturating_add(Weight::from_ref_time(46_817_640 as u64).saturating_mul(i as u64)) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `i` is `[0, 1000]`. fn storage_read(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(2_110_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 125 nanoseconds. + Weight::from_ref_time(135_000 as u64) + // Standard Error: 3_651 + .saturating_add(Weight::from_ref_time(2_021_172 as u64).saturating_mul(i as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) + /// The range of component `i` is `[0, 1000]`. fn storage_write(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(372_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 120 nanoseconds. + Weight::from_ref_time(131_000 as u64) + // Standard Error: 348 + .saturating_add(Weight::from_ref_time(377_243 as u64).saturating_mul(i as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 7255ece5c223a..71f4bf01899fb 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/bounties/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -64,42 +67,51 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) - fn propose_bounty(_d: u32, ) -> Weight { - Weight::from_ref_time(28_903_000 as u64) + /// The range of component `d` is `[0, 300]`. + fn propose_bounty(d: u32, ) -> Weight { + // Minimum execution time: 33_514 nanoseconds. + Weight::from_ref_time(34_906_466 as u64) + // Standard Error: 226 + .saturating_add(Weight::from_ref_time(2_241 as u64).saturating_mul(d as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - Weight::from_ref_time(10_997_000 as u64) + // Minimum execution time: 14_129 nanoseconds. + Weight::from_ref_time(14_424_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - Weight::from_ref_time(8_967_000 as u64) + // Minimum execution time: 13_675 nanoseconds. + Weight::from_ref_time(13_964_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - Weight::from_ref_time(28_665_000 as u64) + // Minimum execution time: 38_926 nanoseconds. + Weight::from_ref_time(40_183_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - Weight::from_ref_time(25_141_000 as u64) + // Minimum execution time: 33_774 nanoseconds. + Weight::from_ref_time(34_295_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - Weight::from_ref_time(21_295_000 as u64) + // Minimum execution time: 28_558 nanoseconds. + Weight::from_ref_time(29_293_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -108,7 +120,8 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - Weight::from_ref_time(67_951_000 as u64) + // Minimum execution time: 77_042 nanoseconds. + Weight::from_ref_time(77_730_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -117,7 +130,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - Weight::from_ref_time(33_654_000 as u64) + // Minimum execution time: 43_632 nanoseconds. + Weight::from_ref_time(44_196_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -126,23 +140,27 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - Weight::from_ref_time(50_582_000 as u64) + // Minimum execution time: 59_519 nanoseconds. + Weight::from_ref_time(59_967_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - Weight::from_ref_time(18_322_000 as u64) + // Minimum execution time: 25_263 nanoseconds. + Weight::from_ref_time(25_788_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Bounties BountyApprovals (r:1 w:1) - // Storage: Bounties Bounties (r:1 w:1) - // Storage: System Account (r:2 w:2) + // Storage: Bounties Bounties (r:2 w:2) + // Storage: System Account (r:4 w:4) + /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(29_233_000 as u64).saturating_mul(b as u64)) + // Minimum execution time: 8_953 nanoseconds. + Weight::from_ref_time(23_242_227 as u64) + // Standard Error: 13_187 + .saturating_add(Weight::from_ref_time(26_727_999 as u64).saturating_mul(b as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(b as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -156,42 +174,51 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) // Storage: Bounties Bounties (r:0 w:1) - fn propose_bounty(_d: u32, ) -> Weight { - Weight::from_ref_time(28_903_000 as u64) + /// The range of component `d` is `[0, 300]`. + fn propose_bounty(d: u32, ) -> Weight { + // Minimum execution time: 33_514 nanoseconds. + Weight::from_ref_time(34_906_466 as u64) + // Standard Error: 226 + .saturating_add(Weight::from_ref_time(2_241 as u64).saturating_mul(d as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - Weight::from_ref_time(10_997_000 as u64) + // Minimum execution time: 14_129 nanoseconds. + Weight::from_ref_time(14_424_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - Weight::from_ref_time(8_967_000 as u64) + // Minimum execution time: 13_675 nanoseconds. + Weight::from_ref_time(13_964_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - Weight::from_ref_time(28_665_000 as u64) + // Minimum execution time: 38_926 nanoseconds. + Weight::from_ref_time(40_183_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - Weight::from_ref_time(25_141_000 as u64) + // Minimum execution time: 33_774 nanoseconds. + Weight::from_ref_time(34_295_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - Weight::from_ref_time(21_295_000 as u64) + // Minimum execution time: 28_558 nanoseconds. + Weight::from_ref_time(29_293_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -200,7 +227,8 @@ impl WeightInfo for () { // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - Weight::from_ref_time(67_951_000 as u64) + // Minimum execution time: 77_042 nanoseconds. + Weight::from_ref_time(77_730_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -209,7 +237,8 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - Weight::from_ref_time(33_654_000 as u64) + // Minimum execution time: 43_632 nanoseconds. + Weight::from_ref_time(44_196_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -218,23 +247,27 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - Weight::from_ref_time(50_582_000 as u64) + // Minimum execution time: 59_519 nanoseconds. + Weight::from_ref_time(59_967_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - Weight::from_ref_time(18_322_000 as u64) + // Minimum execution time: 25_263 nanoseconds. + Weight::from_ref_time(25_788_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Bounties BountyApprovals (r:1 w:1) - // Storage: Bounties Bounties (r:1 w:1) - // Storage: System Account (r:2 w:2) + // Storage: Bounties Bounties (r:2 w:2) + // Storage: System Account (r:4 w:4) + /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(29_233_000 as u64).saturating_mul(b as u64)) + // Minimum execution time: 8_953 nanoseconds. + Weight::from_ref_time(23_242_227 as u64) + // Standard Error: 13_187 + .saturating_add(Weight::from_ref_time(26_727_999 as u64).saturating_mul(b as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(b as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index 564fb0ae23d15..235c84320effa 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_child_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/child-bounties/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -63,10 +66,12 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBountyCount (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) + /// The range of component `d` is `[0, 300]`. fn add_child_bounty(d: u32, ) -> Weight { - Weight::from_ref_time(51_064_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(d as u64)) + // Minimum execution time: 59_121 nanoseconds. + Weight::from_ref_time(60_212_235 as u64) + // Standard Error: 149 + .saturating_add(Weight::from_ref_time(412 as u64).saturating_mul(d as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -74,7 +79,8 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - Weight::from_ref_time(15_286_000 as u64) + // Minimum execution time: 20_785 nanoseconds. + Weight::from_ref_time(21_000_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -82,7 +88,8 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - Weight::from_ref_time(29_929_000 as u64) + // Minimum execution time: 37_874 nanoseconds. + Weight::from_ref_time(38_322_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -90,14 +97,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - Weight::from_ref_time(32_449_000 as u64) + // Minimum execution time: 43_385 nanoseconds. + Weight::from_ref_time(43_774_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - Weight::from_ref_time(23_793_000 as u64) + // Minimum execution time: 31_390 nanoseconds. + Weight::from_ref_time(31_802_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -106,7 +115,8 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - Weight::from_ref_time(67_529_000 as u64) + // Minimum execution time: 74_956 nanoseconds. + Weight::from_ref_time(75_850_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -117,7 +127,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - Weight::from_ref_time(48_436_000 as u64) + // Minimum execution time: 57_215 nanoseconds. + Weight::from_ref_time(58_285_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -128,7 +139,8 @@ impl WeightInfo for SubstrateWeight { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - Weight::from_ref_time(58_044_000 as u64) + // Minimum execution time: 67_641 nanoseconds. + Weight::from_ref_time(69_184_000 as u64) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(7 as u64)) } @@ -142,10 +154,12 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBountyCount (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) // Storage: ChildBounties ChildBounties (r:0 w:1) + /// The range of component `d` is `[0, 300]`. fn add_child_bounty(d: u32, ) -> Weight { - Weight::from_ref_time(51_064_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(d as u64)) + // Minimum execution time: 59_121 nanoseconds. + Weight::from_ref_time(60_212_235 as u64) + // Standard Error: 149 + .saturating_add(Weight::from_ref_time(412 as u64).saturating_mul(d as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -153,7 +167,8 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) fn propose_curator() -> Weight { - Weight::from_ref_time(15_286_000 as u64) + // Minimum execution time: 20_785 nanoseconds. + Weight::from_ref_time(21_000_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -161,7 +176,8 @@ impl WeightInfo for () { // Storage: ChildBounties ChildBounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - Weight::from_ref_time(29_929_000 as u64) + // Minimum execution time: 37_874 nanoseconds. + Weight::from_ref_time(38_322_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -169,14 +185,16 @@ impl WeightInfo for () { // Storage: Bounties Bounties (r:1 w:0) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - Weight::from_ref_time(32_449_000 as u64) + // Minimum execution time: 43_385 nanoseconds. + Weight::from_ref_time(43_774_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Bounties Bounties (r:1 w:0) // Storage: ChildBounties ChildBounties (r:1 w:1) fn award_child_bounty() -> Weight { - Weight::from_ref_time(23_793_000 as u64) + // Minimum execution time: 31_390 nanoseconds. + Weight::from_ref_time(31_802_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -185,7 +203,8 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn claim_child_bounty() -> Weight { - Weight::from_ref_time(67_529_000 as u64) + // Minimum execution time: 74_956 nanoseconds. + Weight::from_ref_time(75_850_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -196,7 +215,8 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_added() -> Weight { - Weight::from_ref_time(48_436_000 as u64) + // Minimum execution time: 57_215 nanoseconds. + Weight::from_ref_time(58_285_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -207,7 +227,8 @@ impl WeightInfo for () { // Storage: ChildBounties ParentChildBounties (r:1 w:1) // Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) fn close_child_bounty_active() -> Weight { - Weight::from_ref_time(58_044_000 as u64) + // Minimum execution time: 67_641 nanoseconds. + Weight::from_ref_time(69_184_000 as u64) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(7 as u64)) } diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index c7237911da6ab..052550de7bd7e 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -18,25 +18,24 @@ //! Autogenerated weights for pallet_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_collective // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_collective -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/collective/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -71,12 +70,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 100]`. /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // Minimum execution time: 18_852 nanoseconds. - Weight::from_ref_time(19_138_000 as u64) - // Standard Error: 65_564 - .saturating_add(Weight::from_ref_time(5_276_957 as u64).saturating_mul(m as u64)) - // Standard Error: 65_564 - .saturating_add(Weight::from_ref_time(7_655_866 as u64).saturating_mul(p as u64)) + // Minimum execution time: 18_895 nanoseconds. + Weight::from_ref_time(19_254_000 as u64) + // Standard Error: 63_540 + .saturating_add(Weight::from_ref_time(5_061_801 as u64).saturating_mul(m as u64)) + // Standard Error: 63_540 + .saturating_add(Weight::from_ref_time(7_588_981 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(p as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) @@ -86,12 +85,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { - // Minimum execution time: 23_081 nanoseconds. - Weight::from_ref_time(22_608_754 as u64) - // Standard Error: 35 - .saturating_add(Weight::from_ref_time(1_722 as u64).saturating_mul(b as u64)) - // Standard Error: 370 - .saturating_add(Weight::from_ref_time(23_442 as u64).saturating_mul(m as u64)) + // Minimum execution time: 24_469 nanoseconds. + Weight::from_ref_time(23_961_134 as u64) + // Standard Error: 43 + .saturating_add(Weight::from_ref_time(1_677 as u64).saturating_mul(b as u64)) + // Standard Error: 450 + .saturating_add(Weight::from_ref_time(18_645 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Council Members (r:1 w:0) @@ -99,12 +98,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { - // Minimum execution time: 25_477 nanoseconds. - Weight::from_ref_time(25_478_243 as u64) - // Standard Error: 47 - .saturating_add(Weight::from_ref_time(1_346 as u64).saturating_mul(b as u64)) - // Standard Error: 493 - .saturating_add(Weight::from_ref_time(27_323 as u64).saturating_mul(m as u64)) + // Minimum execution time: 26_476 nanoseconds. + Weight::from_ref_time(25_829_298 as u64) + // Standard Error: 49 + .saturating_add(Weight::from_ref_time(1_741 as u64).saturating_mul(b as u64)) + // Standard Error: 515 + .saturating_add(Weight::from_ref_time(29_436 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) } // Storage: Council Members (r:1 w:0) @@ -116,14 +115,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 33_037 nanoseconds. - Weight::from_ref_time(29_297_056 as u64) - // Standard Error: 180 - .saturating_add(Weight::from_ref_time(5_899 as u64).saturating_mul(b as u64)) - // Standard Error: 1_884 - .saturating_add(Weight::from_ref_time(33_511 as u64).saturating_mul(m as u64)) - // Standard Error: 1_860 - .saturating_add(Weight::from_ref_time(195_416 as u64).saturating_mul(p as u64)) + // Minimum execution time: 33_585 nanoseconds. + Weight::from_ref_time(33_092_289 as u64) + // Standard Error: 173 + .saturating_add(Weight::from_ref_time(4_266 as u64).saturating_mul(b as u64)) + // Standard Error: 1_812 + .saturating_add(Weight::from_ref_time(29_262 as u64).saturating_mul(m as u64)) + // Standard Error: 1_789 + .saturating_add(Weight::from_ref_time(181_285 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -131,10 +130,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Voting (r:1 w:1) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { - // Minimum execution time: 35_284 nanoseconds. - Weight::from_ref_time(38_865_202 as u64) - // Standard Error: 2_322 - .saturating_add(Weight::from_ref_time(53_753 as u64).saturating_mul(m as u64)) + // Minimum execution time: 36_374 nanoseconds. + Weight::from_ref_time(38_950_243 as u64) + // Standard Error: 2_583 + .saturating_add(Weight::from_ref_time(65_345 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -145,12 +144,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 35_773 nanoseconds. - Weight::from_ref_time(36_651_208 as u64) - // Standard Error: 1_142 - .saturating_add(Weight::from_ref_time(27_095 as u64).saturating_mul(m as u64)) - // Standard Error: 1_114 - .saturating_add(Weight::from_ref_time(169_747 as u64).saturating_mul(p as u64)) + // Minimum execution time: 36_066 nanoseconds. + Weight::from_ref_time(38_439_655 as u64) + // Standard Error: 1_281 + .saturating_add(Weight::from_ref_time(17_045 as u64).saturating_mul(m as u64)) + // Standard Error: 1_249 + .saturating_add(Weight::from_ref_time(164_998 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -162,14 +161,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 46_290 nanoseconds. - Weight::from_ref_time(46_176_864 as u64) - // Standard Error: 147 - .saturating_add(Weight::from_ref_time(2_318 as u64).saturating_mul(b as u64)) - // Standard Error: 1_560 - .saturating_add(Weight::from_ref_time(31_428 as u64).saturating_mul(m as u64)) - // Standard Error: 1_520 - .saturating_add(Weight::from_ref_time(171_822 as u64).saturating_mul(p as u64)) + // Minimum execution time: 47_753 nanoseconds. + Weight::from_ref_time(46_507_829 as u64) + // Standard Error: 149 + .saturating_add(Weight::from_ref_time(2_159 as u64).saturating_mul(b as u64)) + // Standard Error: 1_581 + .saturating_add(Weight::from_ref_time(37_842 as u64).saturating_mul(m as u64)) + // Standard Error: 1_541 + .saturating_add(Weight::from_ref_time(173_395 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -181,12 +180,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 38_421 nanoseconds. - Weight::from_ref_time(40_586_165 as u64) - // Standard Error: 1_853 - .saturating_add(Weight::from_ref_time(20_063 as u64).saturating_mul(m as u64)) - // Standard Error: 1_807 - .saturating_add(Weight::from_ref_time(151_494 as u64).saturating_mul(p as u64)) + // Minimum execution time: 39_416 nanoseconds. + Weight::from_ref_time(39_610_161 as u64) + // Standard Error: 1_231 + .saturating_add(Weight::from_ref_time(32_991 as u64).saturating_mul(m as u64)) + // Standard Error: 1_200 + .saturating_add(Weight::from_ref_time(170_773 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -199,14 +198,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 48_281 nanoseconds. - Weight::from_ref_time(47_511_499 as u64) - // Standard Error: 135 - .saturating_add(Weight::from_ref_time(1_900 as u64).saturating_mul(b as u64)) - // Standard Error: 1_429 - .saturating_add(Weight::from_ref_time(37_612 as u64).saturating_mul(m as u64)) - // Standard Error: 1_393 - .saturating_add(Weight::from_ref_time(180_682 as u64).saturating_mul(p as u64)) + // Minimum execution time: 49_840 nanoseconds. + Weight::from_ref_time(48_542_914 as u64) + // Standard Error: 136 + .saturating_add(Weight::from_ref_time(2_650 as u64).saturating_mul(b as u64)) + // Standard Error: 1_442 + .saturating_add(Weight::from_ref_time(37_898 as u64).saturating_mul(m as u64)) + // Standard Error: 1_406 + .saturating_add(Weight::from_ref_time(182_176 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -215,10 +214,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Council ProposalOf (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { - // Minimum execution time: 22_534 nanoseconds. - Weight::from_ref_time(25_722_688 as u64) - // Standard Error: 1_622 - .saturating_add(Weight::from_ref_time(166_308 as u64).saturating_mul(p as u64)) + // Minimum execution time: 24_199 nanoseconds. + Weight::from_ref_time(26_869_176 as u64) + // Standard Error: 1_609 + .saturating_add(Weight::from_ref_time(163_341 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -234,12 +233,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 100]`. /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // Minimum execution time: 18_852 nanoseconds. - Weight::from_ref_time(19_138_000 as u64) - // Standard Error: 65_564 - .saturating_add(Weight::from_ref_time(5_276_957 as u64).saturating_mul(m as u64)) - // Standard Error: 65_564 - .saturating_add(Weight::from_ref_time(7_655_866 as u64).saturating_mul(p as u64)) + // Minimum execution time: 18_895 nanoseconds. + Weight::from_ref_time(19_254_000 as u64) + // Standard Error: 63_540 + .saturating_add(Weight::from_ref_time(5_061_801 as u64).saturating_mul(m as u64)) + // Standard Error: 63_540 + .saturating_add(Weight::from_ref_time(7_588_981 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(p as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) @@ -249,12 +248,12 @@ impl WeightInfo for () { /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { - // Minimum execution time: 23_081 nanoseconds. - Weight::from_ref_time(22_608_754 as u64) - // Standard Error: 35 - .saturating_add(Weight::from_ref_time(1_722 as u64).saturating_mul(b as u64)) - // Standard Error: 370 - .saturating_add(Weight::from_ref_time(23_442 as u64).saturating_mul(m as u64)) + // Minimum execution time: 24_469 nanoseconds. + Weight::from_ref_time(23_961_134 as u64) + // Standard Error: 43 + .saturating_add(Weight::from_ref_time(1_677 as u64).saturating_mul(b as u64)) + // Standard Error: 450 + .saturating_add(Weight::from_ref_time(18_645 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Council Members (r:1 w:0) @@ -262,12 +261,12 @@ impl WeightInfo for () { /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { - // Minimum execution time: 25_477 nanoseconds. - Weight::from_ref_time(25_478_243 as u64) - // Standard Error: 47 - .saturating_add(Weight::from_ref_time(1_346 as u64).saturating_mul(b as u64)) - // Standard Error: 493 - .saturating_add(Weight::from_ref_time(27_323 as u64).saturating_mul(m as u64)) + // Minimum execution time: 26_476 nanoseconds. + Weight::from_ref_time(25_829_298 as u64) + // Standard Error: 49 + .saturating_add(Weight::from_ref_time(1_741 as u64).saturating_mul(b as u64)) + // Standard Error: 515 + .saturating_add(Weight::from_ref_time(29_436 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) } // Storage: Council Members (r:1 w:0) @@ -279,14 +278,14 @@ impl WeightInfo for () { /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 33_037 nanoseconds. - Weight::from_ref_time(29_297_056 as u64) - // Standard Error: 180 - .saturating_add(Weight::from_ref_time(5_899 as u64).saturating_mul(b as u64)) - // Standard Error: 1_884 - .saturating_add(Weight::from_ref_time(33_511 as u64).saturating_mul(m as u64)) - // Standard Error: 1_860 - .saturating_add(Weight::from_ref_time(195_416 as u64).saturating_mul(p as u64)) + // Minimum execution time: 33_585 nanoseconds. + Weight::from_ref_time(33_092_289 as u64) + // Standard Error: 173 + .saturating_add(Weight::from_ref_time(4_266 as u64).saturating_mul(b as u64)) + // Standard Error: 1_812 + .saturating_add(Weight::from_ref_time(29_262 as u64).saturating_mul(m as u64)) + // Standard Error: 1_789 + .saturating_add(Weight::from_ref_time(181_285 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -294,10 +293,10 @@ impl WeightInfo for () { // Storage: Council Voting (r:1 w:1) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { - // Minimum execution time: 35_284 nanoseconds. - Weight::from_ref_time(38_865_202 as u64) - // Standard Error: 2_322 - .saturating_add(Weight::from_ref_time(53_753 as u64).saturating_mul(m as u64)) + // Minimum execution time: 36_374 nanoseconds. + Weight::from_ref_time(38_950_243 as u64) + // Standard Error: 2_583 + .saturating_add(Weight::from_ref_time(65_345 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -308,12 +307,12 @@ impl WeightInfo for () { /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 35_773 nanoseconds. - Weight::from_ref_time(36_651_208 as u64) - // Standard Error: 1_142 - .saturating_add(Weight::from_ref_time(27_095 as u64).saturating_mul(m as u64)) - // Standard Error: 1_114 - .saturating_add(Weight::from_ref_time(169_747 as u64).saturating_mul(p as u64)) + // Minimum execution time: 36_066 nanoseconds. + Weight::from_ref_time(38_439_655 as u64) + // Standard Error: 1_281 + .saturating_add(Weight::from_ref_time(17_045 as u64).saturating_mul(m as u64)) + // Standard Error: 1_249 + .saturating_add(Weight::from_ref_time(164_998 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -325,14 +324,14 @@ impl WeightInfo for () { /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 46_290 nanoseconds. - Weight::from_ref_time(46_176_864 as u64) - // Standard Error: 147 - .saturating_add(Weight::from_ref_time(2_318 as u64).saturating_mul(b as u64)) - // Standard Error: 1_560 - .saturating_add(Weight::from_ref_time(31_428 as u64).saturating_mul(m as u64)) - // Standard Error: 1_520 - .saturating_add(Weight::from_ref_time(171_822 as u64).saturating_mul(p as u64)) + // Minimum execution time: 47_753 nanoseconds. + Weight::from_ref_time(46_507_829 as u64) + // Standard Error: 149 + .saturating_add(Weight::from_ref_time(2_159 as u64).saturating_mul(b as u64)) + // Standard Error: 1_581 + .saturating_add(Weight::from_ref_time(37_842 as u64).saturating_mul(m as u64)) + // Standard Error: 1_541 + .saturating_add(Weight::from_ref_time(173_395 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -344,12 +343,12 @@ impl WeightInfo for () { /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 38_421 nanoseconds. - Weight::from_ref_time(40_586_165 as u64) - // Standard Error: 1_853 - .saturating_add(Weight::from_ref_time(20_063 as u64).saturating_mul(m as u64)) - // Standard Error: 1_807 - .saturating_add(Weight::from_ref_time(151_494 as u64).saturating_mul(p as u64)) + // Minimum execution time: 39_416 nanoseconds. + Weight::from_ref_time(39_610_161 as u64) + // Standard Error: 1_231 + .saturating_add(Weight::from_ref_time(32_991 as u64).saturating_mul(m as u64)) + // Standard Error: 1_200 + .saturating_add(Weight::from_ref_time(170_773 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -362,14 +361,14 @@ impl WeightInfo for () { /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 48_281 nanoseconds. - Weight::from_ref_time(47_511_499 as u64) - // Standard Error: 135 - .saturating_add(Weight::from_ref_time(1_900 as u64).saturating_mul(b as u64)) - // Standard Error: 1_429 - .saturating_add(Weight::from_ref_time(37_612 as u64).saturating_mul(m as u64)) - // Standard Error: 1_393 - .saturating_add(Weight::from_ref_time(180_682 as u64).saturating_mul(p as u64)) + // Minimum execution time: 49_840 nanoseconds. + Weight::from_ref_time(48_542_914 as u64) + // Standard Error: 136 + .saturating_add(Weight::from_ref_time(2_650 as u64).saturating_mul(b as u64)) + // Standard Error: 1_442 + .saturating_add(Weight::from_ref_time(37_898 as u64).saturating_mul(m as u64)) + // Standard Error: 1_406 + .saturating_add(Weight::from_ref_time(182_176 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -378,10 +377,10 @@ impl WeightInfo for () { // Storage: Council ProposalOf (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { - // Minimum execution time: 22_534 nanoseconds. - Weight::from_ref_time(25_722_688 as u64) - // Standard Error: 1_622 - .saturating_add(Weight::from_ref_time(166_308 as u64).saturating_mul(p as u64)) + // Minimum execution time: 24_199 nanoseconds. + Weight::from_ref_time(26_869_176 as u64) + // Standard Error: 1_609 + .saturating_add(Weight::from_ref_time(163_341 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index c42cc41a0bd9c..8632124c0200d 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-10-28, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -29,14 +29,14 @@ // --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet-contracts +// --pallet=pallet_contracts // --extrinsic=* -// --heap-pages=4096 // --execution=wasm // --wasm-execution=compiled -// --output=frame/contracts/src/weights.rs -// --header=HEADER-APACHE2 -// --template=.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --output=./frame/contracts/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -167,17 +167,17 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - // Minimum execution time: 2_904 nanoseconds. - Weight::from_ref_time(3_036_000 as u64) + // Minimum execution time: 3_064 nanoseconds. + Weight::from_ref_time(3_236_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - // Minimum execution time: 14_553 nanoseconds. - Weight::from_ref_time(14_161_469 as u64) - // Standard Error: 593 - .saturating_add(Weight::from_ref_time(894_982 as u64).saturating_mul(k as u64)) + // Minimum execution time: 15_492 nanoseconds. + Weight::from_ref_time(14_309_233 as u64) + // Standard Error: 649 + .saturating_add(Weight::from_ref_time(930_078 as u64).saturating_mul(k as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -185,10 +185,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - // Minimum execution time: 3_121 nanoseconds. - Weight::from_ref_time(14_262_977 as u64) - // Standard Error: 3_272 - .saturating_add(Weight::from_ref_time(1_232_597 as u64).saturating_mul(q as u64)) + // Minimum execution time: 3_240 nanoseconds. + Weight::from_ref_time(15_076_559 as u64) + // Standard Error: 3_337 + .saturating_add(Weight::from_ref_time(1_244_348 as u64).saturating_mul(q as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -196,10 +196,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - // Minimum execution time: 28_625 nanoseconds. - Weight::from_ref_time(31_685_032 as u64) - // Standard Error: 57 - .saturating_add(Weight::from_ref_time(44_024 as u64).saturating_mul(c as u64)) + // Minimum execution time: 22_524 nanoseconds. + Weight::from_ref_time(19_939_078 as u64) + // Standard Error: 43 + .saturating_add(Weight::from_ref_time(43_802 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -210,10 +210,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - // Minimum execution time: 355_167 nanoseconds. - Weight::from_ref_time(330_201_049 as u64) - // Standard Error: 64 - .saturating_add(Weight::from_ref_time(45_952 as u64).saturating_mul(c as u64)) + // Minimum execution time: 261_039 nanoseconds. + Weight::from_ref_time(228_709_853 as u64) + // Standard Error: 105 + .saturating_add(Weight::from_ref_time(47_449 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -228,12 +228,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - // Minimum execution time: 2_165_939 nanoseconds. - Weight::from_ref_time(346_673_842 as u64) - // Standard Error: 73 - .saturating_add(Weight::from_ref_time(107_020 as u64).saturating_mul(c as u64)) + // Minimum execution time: 2_054_867 nanoseconds. + Weight::from_ref_time(259_090_306 as u64) + // Standard Error: 72 + .saturating_add(Weight::from_ref_time(107_519 as u64).saturating_mul(c as u64)) // Standard Error: 4 - .saturating_add(Weight::from_ref_time(1_754 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_736 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(9 as u64)) } @@ -246,10 +246,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - // Minimum execution time: 262_523 nanoseconds. - Weight::from_ref_time(255_633_789 as u64) + // Minimum execution time: 213_409 nanoseconds. + Weight::from_ref_time(205_300_495 as u64) // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_485 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_479 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(7 as u64)) } @@ -259,8 +259,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - // Minimum execution time: 233_124 nanoseconds. - Weight::from_ref_time(233_826_000 as u64) + // Minimum execution time: 183_317 nanoseconds. + Weight::from_ref_time(184_465_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -270,10 +270,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - // Minimum execution time: 61_170 nanoseconds. - Weight::from_ref_time(61_653_502 as u64) - // Standard Error: 47 - .saturating_add(Weight::from_ref_time(45_553 as u64).saturating_mul(c as u64)) + // Minimum execution time: 56_187 nanoseconds. + Weight::from_ref_time(60_636_621 as u64) + // Standard Error: 46 + .saturating_add(Weight::from_ref_time(45_734 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -282,8 +282,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - // Minimum execution time: 37_278 nanoseconds. - Weight::from_ref_time(37_822_000 as u64) + // Minimum execution time: 38_433 nanoseconds. + Weight::from_ref_time(38_917_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -291,8 +291,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - // Minimum execution time: 40_329 nanoseconds. - Weight::from_ref_time(41_017_000 as u64) + // Minimum execution time: 41_507 nanoseconds. + Weight::from_ref_time(41_938_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -303,10 +303,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - // Minimum execution time: 345_717 nanoseconds. - Weight::from_ref_time(347_610_656 as u64) - // Standard Error: 37_159 - .saturating_add(Weight::from_ref_time(35_506_783 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_628 nanoseconds. + Weight::from_ref_time(251_997_923 as u64) + // Standard Error: 26_157 + .saturating_add(Weight::from_ref_time(35_002_004 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -317,10 +317,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - // Minimum execution time: 346_158 nanoseconds. - Weight::from_ref_time(289_982_824 as u64) - // Standard Error: 426_543 - .saturating_add(Weight::from_ref_time(202_123_887 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_390 nanoseconds. + Weight::from_ref_time(193_793_052 as u64) + // Standard Error: 430_292 + .saturating_add(Weight::from_ref_time(211_029_686 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -332,10 +332,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 349_141 nanoseconds. - Weight::from_ref_time(297_477_406 as u64) - // Standard Error: 403_411 - .saturating_add(Weight::from_ref_time(258_999_975 as u64).saturating_mul(r as u64)) + // Minimum execution time: 252_469 nanoseconds. + Weight::from_ref_time(201_438_856 as u64) + // Standard Error: 420_040 + .saturating_add(Weight::from_ref_time(267_340_744 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -347,10 +347,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 347_419 nanoseconds. - Weight::from_ref_time(350_048_279 as u64) - // Standard Error: 22_511 - .saturating_add(Weight::from_ref_time(38_799_515 as u64).saturating_mul(r as u64)) + // Minimum execution time: 251_154 nanoseconds. + Weight::from_ref_time(254_831_062 as u64) + // Standard Error: 37_843 + .saturating_add(Weight::from_ref_time(38_579_567 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -361,10 +361,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - // Minimum execution time: 341_634 nanoseconds. - Weight::from_ref_time(344_394_100 as u64) - // Standard Error: 12_563 - .saturating_add(Weight::from_ref_time(14_529_298 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_875 nanoseconds. + Weight::from_ref_time(250_312_587 as u64) + // Standard Error: 17_901 + .saturating_add(Weight::from_ref_time(15_153_431 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -375,10 +375,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - // Minimum execution time: 346_246 nanoseconds. - Weight::from_ref_time(349_406_095 as u64) - // Standard Error: 28_842 - .saturating_add(Weight::from_ref_time(35_066_080 as u64).saturating_mul(r as u64)) + // Minimum execution time: 250_097 nanoseconds. + Weight::from_ref_time(252_157_442 as u64) + // Standard Error: 38_426 + .saturating_add(Weight::from_ref_time(35_084_205 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -389,10 +389,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - // Minimum execution time: 346_003 nanoseconds. - Weight::from_ref_time(349_076_713 as u64) - // Standard Error: 30_507 - .saturating_add(Weight::from_ref_time(34_662_539 as u64).saturating_mul(r as u64)) + // Minimum execution time: 250_034 nanoseconds. + Weight::from_ref_time(252_189_233 as u64) + // Standard Error: 33_081 + .saturating_add(Weight::from_ref_time(34_764_160 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -403,10 +403,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - // Minimum execution time: 346_063 nanoseconds. - Weight::from_ref_time(350_054_605 as u64) - // Standard Error: 68_711 - .saturating_add(Weight::from_ref_time(107_584_776 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_587 nanoseconds. + Weight::from_ref_time(258_565_111 as u64) + // Standard Error: 75_715 + .saturating_add(Weight::from_ref_time(109_687_486 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -417,10 +417,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - // Minimum execution time: 346_057 nanoseconds. - Weight::from_ref_time(349_489_403 as u64) - // Standard Error: 38_116 - .saturating_add(Weight::from_ref_time(34_750_791 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_735 nanoseconds. + Weight::from_ref_time(252_875_784 as u64) + // Standard Error: 42_024 + .saturating_add(Weight::from_ref_time(34_555_983 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -431,10 +431,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - // Minimum execution time: 345_722 nanoseconds. - Weight::from_ref_time(348_659_357 as u64) - // Standard Error: 33_077 - .saturating_add(Weight::from_ref_time(34_845_216 as u64).saturating_mul(r as u64)) + // Minimum execution time: 250_025 nanoseconds. + Weight::from_ref_time(255_212_046 as u64) + // Standard Error: 41_865 + .saturating_add(Weight::from_ref_time(34_332_291 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -445,10 +445,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - // Minimum execution time: 345_805 nanoseconds. - Weight::from_ref_time(347_579_287 as u64) - // Standard Error: 28_498 - .saturating_add(Weight::from_ref_time(34_529_480 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_641 nanoseconds. + Weight::from_ref_time(252_978_686 as u64) + // Standard Error: 25_820 + .saturating_add(Weight::from_ref_time(34_175_386 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -459,10 +459,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - // Minimum execution time: 345_943 nanoseconds. - Weight::from_ref_time(348_941_819 as u64) - // Standard Error: 32_278 - .saturating_add(Weight::from_ref_time(34_580_817 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_871 nanoseconds. + Weight::from_ref_time(253_237_931 as u64) + // Standard Error: 30_986 + .saturating_add(Weight::from_ref_time(34_305_155 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -474,10 +474,10 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - // Minimum execution time: 345_753 nanoseconds. - Weight::from_ref_time(354_733_779 as u64) - // Standard Error: 71_767 - .saturating_add(Weight::from_ref_time(105_098_275 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_787 nanoseconds. + Weight::from_ref_time(258_457_094 as u64) + // Standard Error: 75_835 + .saturating_add(Weight::from_ref_time(107_115_666 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -488,10 +488,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - // Minimum execution time: 222_866 nanoseconds. - Weight::from_ref_time(226_212_157 as u64) - // Standard Error: 17_326 - .saturating_add(Weight::from_ref_time(15_544_104 as u64).saturating_mul(r as u64)) + // Minimum execution time: 171_667 nanoseconds. + Weight::from_ref_time(174_687_863 as u64) + // Standard Error: 34_576 + .saturating_add(Weight::from_ref_time(15_895_674 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -502,10 +502,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - // Minimum execution time: 345_704 nanoseconds. - Weight::from_ref_time(348_160_999 as u64) - // Standard Error: 31_560 - .saturating_add(Weight::from_ref_time(32_888_428 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_610 nanoseconds. + Weight::from_ref_time(251_476_758 as u64) + // Standard Error: 39_422 + .saturating_add(Weight::from_ref_time(32_870_429 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -516,10 +516,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 380_814 nanoseconds. - Weight::from_ref_time(403_973_055 as u64) - // Standard Error: 2_690 - .saturating_add(Weight::from_ref_time(9_597_443 as u64).saturating_mul(n as u64)) + // Minimum execution time: 285_154 nanoseconds. + Weight::from_ref_time(307_768_636 as u64) + // Standard Error: 2_701 + .saturating_add(Weight::from_ref_time(9_544_122 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -530,10 +530,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - // Minimum execution time: 340_930 nanoseconds. - Weight::from_ref_time(342_218_828 as u64) - // Standard Error: 80_578 - .saturating_add(Weight::from_ref_time(1_547_971 as u64).saturating_mul(r as u64)) + // Minimum execution time: 244_810 nanoseconds. + Weight::from_ref_time(247_576_385 as u64) + // Standard Error: 80_494 + .saturating_add(Weight::from_ref_time(2_052_714 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -544,10 +544,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 343_035 nanoseconds. - Weight::from_ref_time(345_347_882 as u64) - // Standard Error: 509 - .saturating_add(Weight::from_ref_time(228_526 as u64).saturating_mul(n as u64)) + // Minimum execution time: 248_049 nanoseconds. + Weight::from_ref_time(250_148_025 as u64) + // Standard Error: 339 + .saturating_add(Weight::from_ref_time(185_344 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -560,10 +560,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - // Minimum execution time: 344_997 nanoseconds. - Weight::from_ref_time(346_431_655 as u64) - // Standard Error: 79_924 - .saturating_add(Weight::from_ref_time(53_530_044 as u64).saturating_mul(r as u64)) + // Minimum execution time: 246_620 nanoseconds. + Weight::from_ref_time(250_752_277 as u64) + // Standard Error: 84_300 + .saturating_add(Weight::from_ref_time(54_264_722 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -577,10 +577,10 @@ impl WeightInfo for SubstrateWeight { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - // Minimum execution time: 345_926 nanoseconds. - Weight::from_ref_time(351_620_774 as u64) - // Standard Error: 69_858 - .saturating_add(Weight::from_ref_time(130_846_895 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_065 nanoseconds. + Weight::from_ref_time(252_419_902 as u64) + // Standard Error: 84_223 + .saturating_add(Weight::from_ref_time(134_454_079 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -591,10 +591,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - // Minimum execution time: 341_582 nanoseconds. - Weight::from_ref_time(353_141_157 as u64) - // Standard Error: 99_764 - .saturating_add(Weight::from_ref_time(231_149_152 as u64).saturating_mul(r as u64)) + // Minimum execution time: 246_588 nanoseconds. + Weight::from_ref_time(261_525_328 as u64) + // Standard Error: 97_732 + .saturating_add(Weight::from_ref_time(235_555_878 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -606,12 +606,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - // Minimum execution time: 1_269_467 nanoseconds. - Weight::from_ref_time(566_371_969 as u64) - // Standard Error: 435_714 - .saturating_add(Weight::from_ref_time(180_441_805 as u64).saturating_mul(t as u64)) - // Standard Error: 119_668 - .saturating_add(Weight::from_ref_time(70_111_002 as u64).saturating_mul(n as u64)) + // Minimum execution time: 1_171_144 nanoseconds. + Weight::from_ref_time(490_333_337 as u64) + // Standard Error: 404_664 + .saturating_add(Weight::from_ref_time(173_683_265 as u64).saturating_mul(t as u64)) + // Standard Error: 111_140 + .saturating_add(Weight::from_ref_time(66_081_822 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -624,20 +624,20 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - // Minimum execution time: 231_528 nanoseconds. - Weight::from_ref_time(235_676_870 as u64) - // Standard Error: 20_851 - .saturating_add(Weight::from_ref_time(26_215_920 as u64).saturating_mul(r as u64)) + // Minimum execution time: 178_822 nanoseconds. + Weight::from_ref_time(181_571_518 as u64) + // Standard Error: 19_207 + .saturating_add(Weight::from_ref_time(26_784_712 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - // Minimum execution time: 346_509 nanoseconds. - Weight::from_ref_time(301_173_874 as u64) - // Standard Error: 436_884 - .saturating_add(Weight::from_ref_time(415_194_325 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_737 nanoseconds. + Weight::from_ref_time(208_095_467 as u64) + // Standard Error: 417_236 + .saturating_add(Weight::from_ref_time(430_088_574 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -646,10 +646,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - // Minimum execution time: 500_452 nanoseconds. - Weight::from_ref_time(641_506_544 as u64) - // Standard Error: 1_308_973 - .saturating_add(Weight::from_ref_time(98_769_541 as u64).saturating_mul(n as u64)) + // Minimum execution time: 400_055 nanoseconds. + Weight::from_ref_time(551_666_883 as u64) + // Standard Error: 1_379_652 + .saturating_add(Weight::from_ref_time(94_069_118 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(52 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(50 as u64)) @@ -658,10 +658,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - // Minimum execution time: 500_941 nanoseconds. - Weight::from_ref_time(610_446_049 as u64) - // Standard Error: 1_018_173 - .saturating_add(Weight::from_ref_time(65_568_627 as u64).saturating_mul(n as u64)) + // Minimum execution time: 400_370 nanoseconds. + Weight::from_ref_time(521_380_000 as u64) + // Standard Error: 1_112_618 + .saturating_add(Weight::from_ref_time(68_664_898 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(49 as u64)) @@ -670,10 +670,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - // Minimum execution time: 345_820 nanoseconds. - Weight::from_ref_time(302_335_076 as u64) - // Standard Error: 472_676 - .saturating_add(Weight::from_ref_time(395_286_593 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_711 nanoseconds. + Weight::from_ref_time(212_629_798 as u64) + // Standard Error: 378_159 + .saturating_add(Weight::from_ref_time(415_326_230 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -682,10 +682,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 457_830 nanoseconds. - Weight::from_ref_time(582_524_868 as u64) - // Standard Error: 1_161_813 - .saturating_add(Weight::from_ref_time(67_291_419 as u64).saturating_mul(n as u64)) + // Minimum execution time: 365_702 nanoseconds. + Weight::from_ref_time(499_337_686 as u64) + // Standard Error: 1_232_330 + .saturating_add(Weight::from_ref_time(70_648_878 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(48 as u64)) @@ -694,10 +694,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - // Minimum execution time: 348_249 nanoseconds. - Weight::from_ref_time(317_329_583 as u64) - // Standard Error: 400_112 - .saturating_add(Weight::from_ref_time(331_362_971 as u64).saturating_mul(r as u64)) + // Minimum execution time: 251_357 nanoseconds. + Weight::from_ref_time(220_533_580 as u64) + // Standard Error: 345_297 + .saturating_add(Weight::from_ref_time(349_413_968 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -705,10 +705,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 446_902 nanoseconds. - Weight::from_ref_time(556_989_117 as u64) - // Standard Error: 1_029_959 - .saturating_add(Weight::from_ref_time(159_623_361 as u64).saturating_mul(n as u64)) + // Minimum execution time: 354_162 nanoseconds. + Weight::from_ref_time(472_811_575 as u64) + // Standard Error: 1_109_282 + .saturating_add(Weight::from_ref_time(154_074_386 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -716,10 +716,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - // Minimum execution time: 347_064 nanoseconds. - Weight::from_ref_time(316_879_171 as u64) - // Standard Error: 355_083 - .saturating_add(Weight::from_ref_time(304_763_264 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_551 nanoseconds. + Weight::from_ref_time(219_176_526 as u64) + // Standard Error: 358_914 + .saturating_add(Weight::from_ref_time(326_009_513 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -727,10 +727,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 435_275 nanoseconds. - Weight::from_ref_time(527_900_488 as u64) - // Standard Error: 872_763 - .saturating_add(Weight::from_ref_time(60_604_211 as u64).saturating_mul(n as u64)) + // Minimum execution time: 339_149 nanoseconds. + Weight::from_ref_time(440_615_016 as u64) + // Standard Error: 954_837 + .saturating_add(Weight::from_ref_time(66_153_533 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -738,10 +738,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - // Minimum execution time: 348_671 nanoseconds. - Weight::from_ref_time(306_307_186 as u64) - // Standard Error: 438_525 - .saturating_add(Weight::from_ref_time(422_575_502 as u64).saturating_mul(r as u64)) + // Minimum execution time: 251_812 nanoseconds. + Weight::from_ref_time(209_954_069 as u64) + // Standard Error: 398_380 + .saturating_add(Weight::from_ref_time(438_573_954 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -750,10 +750,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 470_344 nanoseconds. - Weight::from_ref_time(613_380_073 as u64) - // Standard Error: 1_333_864 - .saturating_add(Weight::from_ref_time(164_398_286 as u64).saturating_mul(n as u64)) + // Minimum execution time: 374_594 nanoseconds. + Weight::from_ref_time(525_213_792 as u64) + // Standard Error: 1_378_489 + .saturating_add(Weight::from_ref_time(161_599_623 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(48 as u64)) @@ -766,10 +766,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - // Minimum execution time: 348_312 nanoseconds. - Weight::from_ref_time(303_017_886 as u64) - // Standard Error: 568_589 - .saturating_add(Weight::from_ref_time(1_351_508_682 as u64).saturating_mul(r as u64)) + // Minimum execution time: 251_379 nanoseconds. + Weight::from_ref_time(204_214_298 as u64) + // Standard Error: 662_575 + .saturating_add(Weight::from_ref_time(1_366_716_853 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -782,10 +782,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - // Minimum execution time: 348_997 nanoseconds. - Weight::from_ref_time(349_975_000 as u64) - // Standard Error: 5_689_469 - .saturating_add(Weight::from_ref_time(24_991_501_544 as u64).saturating_mul(r as u64)) + // Minimum execution time: 252_896 nanoseconds. + Weight::from_ref_time(253_811_000 as u64) + // Standard Error: 6_576_179 + .saturating_add(Weight::from_ref_time(17_254_952_849 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -798,10 +798,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - // Minimum execution time: 348_751 nanoseconds. - Weight::from_ref_time(349_330_000 as u64) - // Standard Error: 7_125_421 - .saturating_add(Weight::from_ref_time(24_917_646_052 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_312 nanoseconds. + Weight::from_ref_time(253_806_000 as u64) + // Standard Error: 6_118_873 + .saturating_add(Weight::from_ref_time(17_081_370_212 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((150 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -815,12 +815,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - // Minimum execution time: 16_275_711 nanoseconds. - Weight::from_ref_time(15_203_241_602 as u64) - // Standard Error: 3_582_276 - .saturating_add(Weight::from_ref_time(1_179_848_168 as u64).saturating_mul(t as u64)) - // Standard Error: 5_371 - .saturating_add(Weight::from_ref_time(9_712_484 as u64).saturating_mul(c as u64)) + // Minimum execution time: 12_001_522 nanoseconds. + Weight::from_ref_time(10_903_312_955 as u64) + // Standard Error: 4_301_096 + .saturating_add(Weight::from_ref_time(1_243_413_241 as u64).saturating_mul(t as u64)) + // Standard Error: 6_449 + .saturating_add(Weight::from_ref_time(9_713_655 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(167 as u64)) .saturating_add(T::DbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(163 as u64)) @@ -835,10 +835,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - // Minimum execution time: 353_168 nanoseconds. - Weight::from_ref_time(353_901_000 as u64) - // Standard Error: 18_701_989 - .saturating_add(Weight::from_ref_time(30_028_672_644 as u64).saturating_mul(r as u64)) + // Minimum execution time: 254_969 nanoseconds. + Weight::from_ref_time(255_984_000 as u64) + // Standard Error: 18_545_048 + .saturating_add(Weight::from_ref_time(22_343_189_765 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().reads((400 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(5 as u64)) @@ -854,10 +854,10 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - // Minimum execution time: 18_226_984 nanoseconds. - Weight::from_ref_time(18_032_466_983 as u64) - // Standard Error: 75_544 - .saturating_add(Weight::from_ref_time(121_087_538 as u64).saturating_mul(s as u64)) + // Minimum execution time: 14_077_497 nanoseconds. + Weight::from_ref_time(13_949_740_588 as u64) + // Standard Error: 66_631 + .saturating_add(Weight::from_ref_time(120_519_572 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(249 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(247 as u64)) @@ -870,10 +870,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - // Minimum execution time: 344_334 nanoseconds. - Weight::from_ref_time(345_939_404 as u64) - // Standard Error: 98_994 - .saturating_add(Weight::from_ref_time(58_015_295 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_445 nanoseconds. + Weight::from_ref_time(251_229_791 as u64) + // Standard Error: 88_045 + .saturating_add(Weight::from_ref_time(57_577_008 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -884,10 +884,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 402_492 nanoseconds. - Weight::from_ref_time(402_789_000 as u64) - // Standard Error: 54_174 - .saturating_add(Weight::from_ref_time(324_036_889 as u64).saturating_mul(n as u64)) + // Minimum execution time: 308_069 nanoseconds. + Weight::from_ref_time(308_971_000 as u64) + // Standard Error: 46_181 + .saturating_add(Weight::from_ref_time(321_835_684 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -898,10 +898,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - // Minimum execution time: 343_493 nanoseconds. - Weight::from_ref_time(345_116_214 as u64) - // Standard Error: 90_515 - .saturating_add(Weight::from_ref_time(71_282_485 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_107 nanoseconds. + Weight::from_ref_time(250_125_030 as u64) + // Standard Error: 88_769 + .saturating_add(Weight::from_ref_time(70_727_669 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -912,10 +912,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 415_650 nanoseconds. - Weight::from_ref_time(415_894_000 as u64) - // Standard Error: 58_077 - .saturating_add(Weight::from_ref_time(248_416_317 as u64).saturating_mul(n as u64)) + // Minimum execution time: 319_515 nanoseconds. + Weight::from_ref_time(319_784_000 as u64) + // Standard Error: 58_896 + .saturating_add(Weight::from_ref_time(246_433_962 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -926,10 +926,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - // Minimum execution time: 343_890 nanoseconds. - Weight::from_ref_time(345_542_924 as u64) - // Standard Error: 87_564 - .saturating_add(Weight::from_ref_time(47_361_375 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_887 nanoseconds. + Weight::from_ref_time(250_452_702 as u64) + // Standard Error: 140_887 + .saturating_add(Weight::from_ref_time(49_538_397 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -940,10 +940,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 391_629 nanoseconds. - Weight::from_ref_time(392_793_000 as u64) - // Standard Error: 51_120 - .saturating_add(Weight::from_ref_time(99_288_467 as u64).saturating_mul(n as u64)) + // Minimum execution time: 297_534 nanoseconds. + Weight::from_ref_time(298_249_000 as u64) + // Standard Error: 49_680 + .saturating_add(Weight::from_ref_time(99_001_103 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -954,10 +954,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - // Minimum execution time: 341_701 nanoseconds. - Weight::from_ref_time(343_318_489 as u64) - // Standard Error: 103_756 - .saturating_add(Weight::from_ref_time(47_301_910 as u64).saturating_mul(r as u64)) + // Minimum execution time: 245_926 nanoseconds. + Weight::from_ref_time(248_471_834 as u64) + // Standard Error: 101_639 + .saturating_add(Weight::from_ref_time(47_889_865 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -968,10 +968,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 389_898 nanoseconds. - Weight::from_ref_time(390_489_000 as u64) - // Standard Error: 52_301 - .saturating_add(Weight::from_ref_time(99_344_068 as u64).saturating_mul(n as u64)) + // Minimum execution time: 294_835 nanoseconds. + Weight::from_ref_time(296_328_000 as u64) + // Standard Error: 46_612 + .saturating_add(Weight::from_ref_time(98_859_152 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -982,10 +982,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - // Minimum execution time: 348_789 nanoseconds. - Weight::from_ref_time(350_451_620 as u64) - // Standard Error: 195_939 - .saturating_add(Weight::from_ref_time(2_962_830_479 as u64).saturating_mul(r as u64)) + // Minimum execution time: 251_104 nanoseconds. + Weight::from_ref_time(253_114_893 as u64) + // Standard Error: 316_740 + .saturating_add(Weight::from_ref_time(2_964_072_706 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -996,10 +996,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - // Minimum execution time: 346_537 nanoseconds. - Weight::from_ref_time(347_926_836 as u64) - // Standard Error: 110_557 - .saturating_add(Weight::from_ref_time(2_058_656_763 as u64).saturating_mul(r as u64)) + // Minimum execution time: 250_048 nanoseconds. + Weight::from_ref_time(251_774_991 as u64) + // Standard Error: 115_294 + .saturating_add(Weight::from_ref_time(2_094_245_208 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -1011,10 +1011,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 346_672 nanoseconds. - Weight::from_ref_time(347_628_000 as u64) - // Standard Error: 2_742_329 - .saturating_add(Weight::from_ref_time(1_370_383_386 as u64).saturating_mul(r as u64)) + // Minimum execution time: 250_830 nanoseconds. + Weight::from_ref_time(251_477_000 as u64) + // Standard Error: 2_727_998 + .saturating_add(Weight::from_ref_time(1_390_149_283 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((225 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -1022,360 +1022,360 @@ impl WeightInfo for SubstrateWeight { } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - // Minimum execution time: 118_029 nanoseconds. - Weight::from_ref_time(118_800_774 as u64) - // Standard Error: 4_234 - .saturating_add(Weight::from_ref_time(866_719 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_022 nanoseconds. + Weight::from_ref_time(69_707_657 as u64) + // Standard Error: 8_674 + .saturating_add(Weight::from_ref_time(887_555 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // Minimum execution time: 118_145 nanoseconds. - Weight::from_ref_time(118_644_813 as u64) - // Standard Error: 2_692 - .saturating_add(Weight::from_ref_time(2_874_276 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_491 nanoseconds. + Weight::from_ref_time(70_354_670 as u64) + // Standard Error: 1_518 + .saturating_add(Weight::from_ref_time(2_758_912 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // Minimum execution time: 118_142 nanoseconds. - Weight::from_ref_time(118_474_161 as u64) - // Standard Error: 6_997 - .saturating_add(Weight::from_ref_time(2_769_076 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_156 nanoseconds. + Weight::from_ref_time(69_917_601 as u64) + // Standard Error: 1_970 + .saturating_add(Weight::from_ref_time(2_753_174 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // Minimum execution time: 118_020 nanoseconds. - Weight::from_ref_time(118_499_103 as u64) - // Standard Error: 1_266 - .saturating_add(Weight::from_ref_time(2_351_397 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_944 nanoseconds. + Weight::from_ref_time(69_727_961 as u64) + // Standard Error: 376 + .saturating_add(Weight::from_ref_time(2_356_996 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // Minimum execution time: 118_008 nanoseconds. - Weight::from_ref_time(118_398_803 as u64) - // Standard Error: 750 - .saturating_add(Weight::from_ref_time(2_480_061 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_971 nanoseconds. + Weight::from_ref_time(69_755_949 as u64) + // Standard Error: 543 + .saturating_add(Weight::from_ref_time(2_489_510 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // Minimum execution time: 118_046 nanoseconds. - Weight::from_ref_time(118_332_903 as u64) - // Standard Error: 234 - .saturating_add(Weight::from_ref_time(1_426_355 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_061 nanoseconds. + Weight::from_ref_time(69_625_000 as u64) + // Standard Error: 486 + .saturating_add(Weight::from_ref_time(1_431_684 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // Minimum execution time: 117_998 nanoseconds. - Weight::from_ref_time(117_910_870 as u64) - // Standard Error: 4_629 - .saturating_add(Weight::from_ref_time(1_992_697 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_058 nanoseconds. + Weight::from_ref_time(69_521_790 as u64) + // Standard Error: 892 + .saturating_add(Weight::from_ref_time(1_964_054 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // Minimum execution time: 117_998 nanoseconds. - Weight::from_ref_time(118_059_139 as u64) - // Standard Error: 1_985 - .saturating_add(Weight::from_ref_time(2_164_252 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_020 nanoseconds. + Weight::from_ref_time(69_344_255 as u64) + // Standard Error: 1_408 + .saturating_add(Weight::from_ref_time(2_169_179 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - // Minimum execution time: 121_282 nanoseconds. - Weight::from_ref_time(121_483_289 as u64) - // Standard Error: 57 - .saturating_add(Weight::from_ref_time(4_013 as u64).saturating_mul(e as u64)) + // Minimum execution time: 72_366 nanoseconds. + Weight::from_ref_time(72_869_594 as u64) + // Standard Error: 73 + .saturating_add(Weight::from_ref_time(3_867 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // Minimum execution time: 118_128 nanoseconds. - Weight::from_ref_time(118_869_764 as u64) - // Standard Error: 8_890 - .saturating_add(Weight::from_ref_time(6_496_684 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_164 nanoseconds. + Weight::from_ref_time(70_269_099 as u64) + // Standard Error: 8_824 + .saturating_add(Weight::from_ref_time(6_594_634 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // Minimum execution time: 131_764 nanoseconds. - Weight::from_ref_time(133_009_514 as u64) - // Standard Error: 9_697 - .saturating_add(Weight::from_ref_time(8_310_784 as u64).saturating_mul(r as u64)) + // Minimum execution time: 83_348 nanoseconds. + Weight::from_ref_time(84_968_895 as u64) + // Standard Error: 6_305 + .saturating_add(Weight::from_ref_time(8_395_193 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - // Minimum execution time: 141_100 nanoseconds. - Weight::from_ref_time(142_282_540 as u64) - // Standard Error: 867 - .saturating_add(Weight::from_ref_time(536_814 as u64).saturating_mul(p as u64)) + // Minimum execution time: 92_358 nanoseconds. + Weight::from_ref_time(93_605_536 as u64) + // Standard Error: 2_019 + .saturating_add(Weight::from_ref_time(536_495 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // Minimum execution time: 118_535 nanoseconds. - Weight::from_ref_time(119_017_162 as u64) - // Standard Error: 1_175 - .saturating_add(Weight::from_ref_time(911_141 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_191 nanoseconds. + Weight::from_ref_time(70_407_702 as u64) + // Standard Error: 2_812 + .saturating_add(Weight::from_ref_time(901_706 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // Minimum execution time: 118_472 nanoseconds. - Weight::from_ref_time(118_790_737 as u64) - // Standard Error: 758 - .saturating_add(Weight::from_ref_time(962_148 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_230 nanoseconds. + Weight::from_ref_time(70_255_278 as u64) + // Standard Error: 1_284 + .saturating_add(Weight::from_ref_time(951_754 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // Minimum execution time: 118_551 nanoseconds. - Weight::from_ref_time(119_070_827 as u64) - // Standard Error: 2_411 - .saturating_add(Weight::from_ref_time(1_367_622 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_278 nanoseconds. + Weight::from_ref_time(70_089_139 as u64) + // Standard Error: 757 + .saturating_add(Weight::from_ref_time(1_369_185 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // Minimum execution time: 120_958 nanoseconds. - Weight::from_ref_time(121_649_052 as u64) - // Standard Error: 1_557 - .saturating_add(Weight::from_ref_time(1_447_477 as u64).saturating_mul(r as u64)) + // Minimum execution time: 72_047 nanoseconds. + Weight::from_ref_time(72_783_972 as u64) + // Standard Error: 837 + .saturating_add(Weight::from_ref_time(1_471_680 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // Minimum execution time: 120_866 nanoseconds. - Weight::from_ref_time(121_040_400 as u64) - // Standard Error: 6_203 - .saturating_add(Weight::from_ref_time(1_548_715 as u64).saturating_mul(r as u64)) + // Minimum execution time: 71_960 nanoseconds. + Weight::from_ref_time(72_745_981 as u64) + // Standard Error: 1_086 + .saturating_add(Weight::from_ref_time(1_537_741 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // Minimum execution time: 118_076 nanoseconds. - Weight::from_ref_time(118_381_010 as u64) - // Standard Error: 1_814 - .saturating_add(Weight::from_ref_time(938_699 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_221 nanoseconds. + Weight::from_ref_time(70_010_862 as u64) + // Standard Error: 1_845 + .saturating_add(Weight::from_ref_time(933_738 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // Minimum execution time: 118_030 nanoseconds. - Weight::from_ref_time(120_331_261 as u64) - // Standard Error: 333_364 - .saturating_add(Weight::from_ref_time(227_636_638 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_081 nanoseconds. + Weight::from_ref_time(71_015_495 as u64) + // Standard Error: 27_078 + .saturating_add(Weight::from_ref_time(183_899_704 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // Minimum execution time: 118_056 nanoseconds. - Weight::from_ref_time(118_554_799 as u64) - // Standard Error: 1_269 - .saturating_add(Weight::from_ref_time(1_331_717 as u64).saturating_mul(r as u64)) + // Minimum execution time: 70_589 nanoseconds. + Weight::from_ref_time(70_175_537 as u64) + // Standard Error: 1_355 + .saturating_add(Weight::from_ref_time(1_323_745 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - // Minimum execution time: 118_009 nanoseconds. - Weight::from_ref_time(118_678_537 as u64) - // Standard Error: 1_699 - .saturating_add(Weight::from_ref_time(1_328_153 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_083 nanoseconds. + Weight::from_ref_time(69_832_339 as u64) + // Standard Error: 818 + .saturating_add(Weight::from_ref_time(1_334_198 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // Minimum execution time: 118_031 nanoseconds. - Weight::from_ref_time(118_478_616 as u64) - // Standard Error: 1_533 - .saturating_add(Weight::from_ref_time(1_335_254 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_084 nanoseconds. + Weight::from_ref_time(69_802_701 as u64) + // Standard Error: 744 + .saturating_add(Weight::from_ref_time(1_334_601 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // Minimum execution time: 117_910 nanoseconds. - Weight::from_ref_time(118_471_672 as u64) - // Standard Error: 1_275 - .saturating_add(Weight::from_ref_time(1_345_140 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_052 nanoseconds. + Weight::from_ref_time(69_717_748 as u64) + // Standard Error: 571 + .saturating_add(Weight::from_ref_time(1_346_564 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // Minimum execution time: 119_504 nanoseconds. - Weight::from_ref_time(118_940_207 as u64) - // Standard Error: 2_512 - .saturating_add(Weight::from_ref_time(1_307_954 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_016 nanoseconds. + Weight::from_ref_time(69_793_413 as u64) + // Standard Error: 769 + .saturating_add(Weight::from_ref_time(1_317_502 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // Minimum execution time: 118_009 nanoseconds. - Weight::from_ref_time(118_366_251 as u64) - // Standard Error: 1_116 - .saturating_add(Weight::from_ref_time(1_322_232 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_043 nanoseconds. + Weight::from_ref_time(69_963_419 as u64) + // Standard Error: 1_117 + .saturating_add(Weight::from_ref_time(1_313_727 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // Minimum execution time: 118_020 nanoseconds. - Weight::from_ref_time(118_222_792 as u64) - // Standard Error: 1_973 - .saturating_add(Weight::from_ref_time(1_336_896 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_032 nanoseconds. + Weight::from_ref_time(69_727_577 as u64) + // Standard Error: 662 + .saturating_add(Weight::from_ref_time(1_331_088 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // Minimum execution time: 118_038 nanoseconds. - Weight::from_ref_time(118_757_016 as u64) - // Standard Error: 7_932 - .saturating_add(Weight::from_ref_time(1_867_807 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_097 nanoseconds. + Weight::from_ref_time(69_767_650 as u64) + // Standard Error: 2_056 + .saturating_add(Weight::from_ref_time(1_875_021 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // Minimum execution time: 118_041 nanoseconds. - Weight::from_ref_time(118_717_403 as u64) - // Standard Error: 8_010 - .saturating_add(Weight::from_ref_time(1_868_876 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_153 nanoseconds. + Weight::from_ref_time(69_906_946 as u64) + // Standard Error: 1_060 + .saturating_add(Weight::from_ref_time(1_867_154 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // Minimum execution time: 118_057 nanoseconds. - Weight::from_ref_time(118_560_106 as u64) - // Standard Error: 1_362 - .saturating_add(Weight::from_ref_time(1_869_820 as u64).saturating_mul(r as u64)) + // Minimum execution time: 70_380 nanoseconds. + Weight::from_ref_time(69_867_328 as u64) + // Standard Error: 778 + .saturating_add(Weight::from_ref_time(1_869_718 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // Minimum execution time: 118_045 nanoseconds. - Weight::from_ref_time(118_318_194 as u64) - // Standard Error: 179 - .saturating_add(Weight::from_ref_time(1_873_670 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_259 nanoseconds. + Weight::from_ref_time(69_695_407 as u64) + // Standard Error: 746 + .saturating_add(Weight::from_ref_time(1_874_772 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // Minimum execution time: 118_000 nanoseconds. - Weight::from_ref_time(118_520_606 as u64) - // Standard Error: 3_656 - .saturating_add(Weight::from_ref_time(1_870_762 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_986 nanoseconds. + Weight::from_ref_time(70_027_081 as u64) + // Standard Error: 1_401 + .saturating_add(Weight::from_ref_time(1_862_971 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // Minimum execution time: 118_035 nanoseconds. - Weight::from_ref_time(118_464_151 as u64) - // Standard Error: 1_073 - .saturating_add(Weight::from_ref_time(1_870_309 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_953 nanoseconds. + Weight::from_ref_time(69_798_073 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_871_888 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // Minimum execution time: 118_071 nanoseconds. - Weight::from_ref_time(118_470_365 as u64) - // Standard Error: 1_224 - .saturating_add(Weight::from_ref_time(1_870_522 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_909 nanoseconds. + Weight::from_ref_time(69_845_981 as u64) + // Standard Error: 775 + .saturating_add(Weight::from_ref_time(1_868_722 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // Minimum execution time: 118_032 nanoseconds. - Weight::from_ref_time(118_407_669 as u64) - // Standard Error: 769 - .saturating_add(Weight::from_ref_time(1_883_635 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_986 nanoseconds. + Weight::from_ref_time(69_683_189 as u64) + // Standard Error: 503 + .saturating_add(Weight::from_ref_time(1_884_715 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - // Minimum execution time: 118_044 nanoseconds. - Weight::from_ref_time(118_324_106 as u64) - // Standard Error: 523 - .saturating_add(Weight::from_ref_time(1_874_728 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_230 nanoseconds. + Weight::from_ref_time(69_765_336 as u64) + // Standard Error: 2_060 + .saturating_add(Weight::from_ref_time(1_871_848 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // Minimum execution time: 118_111 nanoseconds. - Weight::from_ref_time(118_538_748 as u64) - // Standard Error: 3_498 - .saturating_add(Weight::from_ref_time(1_868_932 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_953 nanoseconds. + Weight::from_ref_time(69_828_265 as u64) + // Standard Error: 951 + .saturating_add(Weight::from_ref_time(1_868_596 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // Minimum execution time: 118_060 nanoseconds. - Weight::from_ref_time(118_421_175 as u64) - // Standard Error: 962 - .saturating_add(Weight::from_ref_time(1_850_713 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_078 nanoseconds. + Weight::from_ref_time(69_832_768 as u64) + // Standard Error: 894 + .saturating_add(Weight::from_ref_time(1_845_786 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // Minimum execution time: 118_050 nanoseconds. - Weight::from_ref_time(118_774_937 as u64) - // Standard Error: 1_717 - .saturating_add(Weight::from_ref_time(1_838_127 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_939 nanoseconds. + Weight::from_ref_time(69_676_256 as u64) + // Standard Error: 374 + .saturating_add(Weight::from_ref_time(1_851_026 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // Minimum execution time: 117_997 nanoseconds. - Weight::from_ref_time(118_626_785 as u64) - // Standard Error: 1_382 - .saturating_add(Weight::from_ref_time(1_842_530 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_096 nanoseconds. + Weight::from_ref_time(69_914_159 as u64) + // Standard Error: 1_265 + .saturating_add(Weight::from_ref_time(1_844_489 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // Minimum execution time: 118_064 nanoseconds. - Weight::from_ref_time(118_404_203 as u64) - // Standard Error: 2_437 - .saturating_add(Weight::from_ref_time(2_489_569 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_939 nanoseconds. + Weight::from_ref_time(69_641_768 as u64) + // Standard Error: 347 + .saturating_add(Weight::from_ref_time(2_488_628 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // Minimum execution time: 117_949 nanoseconds. - Weight::from_ref_time(118_525_228 as u64) - // Standard Error: 2_231 - .saturating_add(Weight::from_ref_time(2_453_863 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_114 nanoseconds. + Weight::from_ref_time(69_844_395 as u64) + // Standard Error: 1_489 + .saturating_add(Weight::from_ref_time(2_456_310 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // Minimum execution time: 118_032 nanoseconds. - Weight::from_ref_time(118_311_431 as u64) - // Standard Error: 175 - .saturating_add(Weight::from_ref_time(2_532_745 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_082 nanoseconds. + Weight::from_ref_time(69_993_662 as u64) + // Standard Error: 1_218 + .saturating_add(Weight::from_ref_time(2_524_010 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // Minimum execution time: 117_987 nanoseconds. - Weight::from_ref_time(118_573_115 as u64) - // Standard Error: 1_814 - .saturating_add(Weight::from_ref_time(2_438_519 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_036 nanoseconds. + Weight::from_ref_time(70_095_304 as u64) + // Standard Error: 1_473 + .saturating_add(Weight::from_ref_time(2_429_659 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // Minimum execution time: 120_001 nanoseconds. - Weight::from_ref_time(118_527_518 as u64) - // Standard Error: 1_040 - .saturating_add(Weight::from_ref_time(1_874_359 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_229 nanoseconds. + Weight::from_ref_time(69_759_818 as u64) + // Standard Error: 573 + .saturating_add(Weight::from_ref_time(1_879_670 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // Minimum execution time: 118_051 nanoseconds. - Weight::from_ref_time(118_315_649 as u64) - // Standard Error: 163 - .saturating_add(Weight::from_ref_time(1_851_162 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_151 nanoseconds. + Weight::from_ref_time(69_865_948 as u64) + // Standard Error: 721 + .saturating_add(Weight::from_ref_time(1_846_734 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // Minimum execution time: 118_038 nanoseconds. - Weight::from_ref_time(118_558_677 as u64) - // Standard Error: 2_258 - .saturating_add(Weight::from_ref_time(1_845_713 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_120 nanoseconds. + Weight::from_ref_time(70_135_849 as u64) + // Standard Error: 3_443 + .saturating_add(Weight::from_ref_time(1_841_784 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // Minimum execution time: 117_985 nanoseconds. - Weight::from_ref_time(118_660_597 as u64) - // Standard Error: 5_893 - .saturating_add(Weight::from_ref_time(1_887_423 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_077 nanoseconds. + Weight::from_ref_time(69_929_746 as u64) + // Standard Error: 821 + .saturating_add(Weight::from_ref_time(1_866_348 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // Minimum execution time: 120_101 nanoseconds. - Weight::from_ref_time(118_522_424 as u64) - // Standard Error: 1_094 - .saturating_add(Weight::from_ref_time(1_867_495 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_226 nanoseconds. + Weight::from_ref_time(69_725_630 as u64) + // Standard Error: 891 + .saturating_add(Weight::from_ref_time(1_873_637 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // Minimum execution time: 118_068 nanoseconds. - Weight::from_ref_time(119_012_941 as u64) - // Standard Error: 9_129 - .saturating_add(Weight::from_ref_time(1_877_850 as u64).saturating_mul(r as u64)) + // Minimum execution time: 70_591 nanoseconds. + Weight::from_ref_time(69_939_773 as u64) + // Standard Error: 960 + .saturating_add(Weight::from_ref_time(1_867_208 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // Minimum execution time: 120_105 nanoseconds. - Weight::from_ref_time(118_559_474 as u64) - // Standard Error: 2_055 - .saturating_add(Weight::from_ref_time(1_868_662 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_187 nanoseconds. + Weight::from_ref_time(69_845_516 as u64) + // Standard Error: 781 + .saturating_add(Weight::from_ref_time(1_869_613 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // Minimum execution time: 118_004 nanoseconds. - Weight::from_ref_time(118_370_466 as u64) - // Standard Error: 818 - .saturating_add(Weight::from_ref_time(1_873_459 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_065 nanoseconds. + Weight::from_ref_time(69_950_430 as u64) + // Standard Error: 986 + .saturating_add(Weight::from_ref_time(1_867_001 as u64).saturating_mul(r as u64)) } } @@ -1383,17 +1383,17 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - // Minimum execution time: 2_904 nanoseconds. - Weight::from_ref_time(3_036_000 as u64) + // Minimum execution time: 3_064 nanoseconds. + Weight::from_ref_time(3_236_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - // Minimum execution time: 14_553 nanoseconds. - Weight::from_ref_time(14_161_469 as u64) - // Standard Error: 593 - .saturating_add(Weight::from_ref_time(894_982 as u64).saturating_mul(k as u64)) + // Minimum execution time: 15_492 nanoseconds. + Weight::from_ref_time(14_309_233 as u64) + // Standard Error: 649 + .saturating_add(Weight::from_ref_time(930_078 as u64).saturating_mul(k as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -1401,10 +1401,10 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - // Minimum execution time: 3_121 nanoseconds. - Weight::from_ref_time(14_262_977 as u64) - // Standard Error: 3_272 - .saturating_add(Weight::from_ref_time(1_232_597 as u64).saturating_mul(q as u64)) + // Minimum execution time: 3_240 nanoseconds. + Weight::from_ref_time(15_076_559 as u64) + // Standard Error: 3_337 + .saturating_add(Weight::from_ref_time(1_244_348 as u64).saturating_mul(q as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1412,10 +1412,10 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - // Minimum execution time: 28_625 nanoseconds. - Weight::from_ref_time(31_685_032 as u64) - // Standard Error: 57 - .saturating_add(Weight::from_ref_time(44_024 as u64).saturating_mul(c as u64)) + // Minimum execution time: 22_524 nanoseconds. + Weight::from_ref_time(19_939_078 as u64) + // Standard Error: 43 + .saturating_add(Weight::from_ref_time(43_802 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1426,10 +1426,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - // Minimum execution time: 355_167 nanoseconds. - Weight::from_ref_time(330_201_049 as u64) - // Standard Error: 64 - .saturating_add(Weight::from_ref_time(45_952 as u64).saturating_mul(c as u64)) + // Minimum execution time: 261_039 nanoseconds. + Weight::from_ref_time(228_709_853 as u64) + // Standard Error: 105 + .saturating_add(Weight::from_ref_time(47_449 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1444,12 +1444,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - // Minimum execution time: 2_165_939 nanoseconds. - Weight::from_ref_time(346_673_842 as u64) - // Standard Error: 73 - .saturating_add(Weight::from_ref_time(107_020 as u64).saturating_mul(c as u64)) + // Minimum execution time: 2_054_867 nanoseconds. + Weight::from_ref_time(259_090_306 as u64) + // Standard Error: 72 + .saturating_add(Weight::from_ref_time(107_519 as u64).saturating_mul(c as u64)) // Standard Error: 4 - .saturating_add(Weight::from_ref_time(1_754 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_736 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(9 as u64)) } @@ -1462,10 +1462,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - // Minimum execution time: 262_523 nanoseconds. - Weight::from_ref_time(255_633_789 as u64) + // Minimum execution time: 213_409 nanoseconds. + Weight::from_ref_time(205_300_495 as u64) // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_485 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_479 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(7 as u64)) } @@ -1475,8 +1475,8 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - // Minimum execution time: 233_124 nanoseconds. - Weight::from_ref_time(233_826_000 as u64) + // Minimum execution time: 183_317 nanoseconds. + Weight::from_ref_time(184_465_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1486,10 +1486,10 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - // Minimum execution time: 61_170 nanoseconds. - Weight::from_ref_time(61_653_502 as u64) - // Standard Error: 47 - .saturating_add(Weight::from_ref_time(45_553 as u64).saturating_mul(c as u64)) + // Minimum execution time: 56_187 nanoseconds. + Weight::from_ref_time(60_636_621 as u64) + // Standard Error: 46 + .saturating_add(Weight::from_ref_time(45_734 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1498,8 +1498,8 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - // Minimum execution time: 37_278 nanoseconds. - Weight::from_ref_time(37_822_000 as u64) + // Minimum execution time: 38_433 nanoseconds. + Weight::from_ref_time(38_917_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1507,8 +1507,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - // Minimum execution time: 40_329 nanoseconds. - Weight::from_ref_time(41_017_000 as u64) + // Minimum execution time: 41_507 nanoseconds. + Weight::from_ref_time(41_938_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -1519,10 +1519,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - // Minimum execution time: 345_717 nanoseconds. - Weight::from_ref_time(347_610_656 as u64) - // Standard Error: 37_159 - .saturating_add(Weight::from_ref_time(35_506_783 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_628 nanoseconds. + Weight::from_ref_time(251_997_923 as u64) + // Standard Error: 26_157 + .saturating_add(Weight::from_ref_time(35_002_004 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1533,10 +1533,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - // Minimum execution time: 346_158 nanoseconds. - Weight::from_ref_time(289_982_824 as u64) - // Standard Error: 426_543 - .saturating_add(Weight::from_ref_time(202_123_887 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_390 nanoseconds. + Weight::from_ref_time(193_793_052 as u64) + // Standard Error: 430_292 + .saturating_add(Weight::from_ref_time(211_029_686 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1548,10 +1548,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 349_141 nanoseconds. - Weight::from_ref_time(297_477_406 as u64) - // Standard Error: 403_411 - .saturating_add(Weight::from_ref_time(258_999_975 as u64).saturating_mul(r as u64)) + // Minimum execution time: 252_469 nanoseconds. + Weight::from_ref_time(201_438_856 as u64) + // Standard Error: 420_040 + .saturating_add(Weight::from_ref_time(267_340_744 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1563,10 +1563,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 347_419 nanoseconds. - Weight::from_ref_time(350_048_279 as u64) - // Standard Error: 22_511 - .saturating_add(Weight::from_ref_time(38_799_515 as u64).saturating_mul(r as u64)) + // Minimum execution time: 251_154 nanoseconds. + Weight::from_ref_time(254_831_062 as u64) + // Standard Error: 37_843 + .saturating_add(Weight::from_ref_time(38_579_567 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1577,10 +1577,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - // Minimum execution time: 341_634 nanoseconds. - Weight::from_ref_time(344_394_100 as u64) - // Standard Error: 12_563 - .saturating_add(Weight::from_ref_time(14_529_298 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_875 nanoseconds. + Weight::from_ref_time(250_312_587 as u64) + // Standard Error: 17_901 + .saturating_add(Weight::from_ref_time(15_153_431 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1591,10 +1591,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - // Minimum execution time: 346_246 nanoseconds. - Weight::from_ref_time(349_406_095 as u64) - // Standard Error: 28_842 - .saturating_add(Weight::from_ref_time(35_066_080 as u64).saturating_mul(r as u64)) + // Minimum execution time: 250_097 nanoseconds. + Weight::from_ref_time(252_157_442 as u64) + // Standard Error: 38_426 + .saturating_add(Weight::from_ref_time(35_084_205 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1605,10 +1605,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - // Minimum execution time: 346_003 nanoseconds. - Weight::from_ref_time(349_076_713 as u64) - // Standard Error: 30_507 - .saturating_add(Weight::from_ref_time(34_662_539 as u64).saturating_mul(r as u64)) + // Minimum execution time: 250_034 nanoseconds. + Weight::from_ref_time(252_189_233 as u64) + // Standard Error: 33_081 + .saturating_add(Weight::from_ref_time(34_764_160 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1619,10 +1619,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - // Minimum execution time: 346_063 nanoseconds. - Weight::from_ref_time(350_054_605 as u64) - // Standard Error: 68_711 - .saturating_add(Weight::from_ref_time(107_584_776 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_587 nanoseconds. + Weight::from_ref_time(258_565_111 as u64) + // Standard Error: 75_715 + .saturating_add(Weight::from_ref_time(109_687_486 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1633,10 +1633,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - // Minimum execution time: 346_057 nanoseconds. - Weight::from_ref_time(349_489_403 as u64) - // Standard Error: 38_116 - .saturating_add(Weight::from_ref_time(34_750_791 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_735 nanoseconds. + Weight::from_ref_time(252_875_784 as u64) + // Standard Error: 42_024 + .saturating_add(Weight::from_ref_time(34_555_983 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1647,10 +1647,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - // Minimum execution time: 345_722 nanoseconds. - Weight::from_ref_time(348_659_357 as u64) - // Standard Error: 33_077 - .saturating_add(Weight::from_ref_time(34_845_216 as u64).saturating_mul(r as u64)) + // Minimum execution time: 250_025 nanoseconds. + Weight::from_ref_time(255_212_046 as u64) + // Standard Error: 41_865 + .saturating_add(Weight::from_ref_time(34_332_291 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1661,10 +1661,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - // Minimum execution time: 345_805 nanoseconds. - Weight::from_ref_time(347_579_287 as u64) - // Standard Error: 28_498 - .saturating_add(Weight::from_ref_time(34_529_480 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_641 nanoseconds. + Weight::from_ref_time(252_978_686 as u64) + // Standard Error: 25_820 + .saturating_add(Weight::from_ref_time(34_175_386 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1675,10 +1675,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - // Minimum execution time: 345_943 nanoseconds. - Weight::from_ref_time(348_941_819 as u64) - // Standard Error: 32_278 - .saturating_add(Weight::from_ref_time(34_580_817 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_871 nanoseconds. + Weight::from_ref_time(253_237_931 as u64) + // Standard Error: 30_986 + .saturating_add(Weight::from_ref_time(34_305_155 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1690,10 +1690,10 @@ impl WeightInfo for () { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - // Minimum execution time: 345_753 nanoseconds. - Weight::from_ref_time(354_733_779 as u64) - // Standard Error: 71_767 - .saturating_add(Weight::from_ref_time(105_098_275 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_787 nanoseconds. + Weight::from_ref_time(258_457_094 as u64) + // Standard Error: 75_835 + .saturating_add(Weight::from_ref_time(107_115_666 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1704,10 +1704,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - // Minimum execution time: 222_866 nanoseconds. - Weight::from_ref_time(226_212_157 as u64) - // Standard Error: 17_326 - .saturating_add(Weight::from_ref_time(15_544_104 as u64).saturating_mul(r as u64)) + // Minimum execution time: 171_667 nanoseconds. + Weight::from_ref_time(174_687_863 as u64) + // Standard Error: 34_576 + .saturating_add(Weight::from_ref_time(15_895_674 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1718,10 +1718,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - // Minimum execution time: 345_704 nanoseconds. - Weight::from_ref_time(348_160_999 as u64) - // Standard Error: 31_560 - .saturating_add(Weight::from_ref_time(32_888_428 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_610 nanoseconds. + Weight::from_ref_time(251_476_758 as u64) + // Standard Error: 39_422 + .saturating_add(Weight::from_ref_time(32_870_429 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1732,10 +1732,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 380_814 nanoseconds. - Weight::from_ref_time(403_973_055 as u64) - // Standard Error: 2_690 - .saturating_add(Weight::from_ref_time(9_597_443 as u64).saturating_mul(n as u64)) + // Minimum execution time: 285_154 nanoseconds. + Weight::from_ref_time(307_768_636 as u64) + // Standard Error: 2_701 + .saturating_add(Weight::from_ref_time(9_544_122 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1746,10 +1746,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - // Minimum execution time: 340_930 nanoseconds. - Weight::from_ref_time(342_218_828 as u64) - // Standard Error: 80_578 - .saturating_add(Weight::from_ref_time(1_547_971 as u64).saturating_mul(r as u64)) + // Minimum execution time: 244_810 nanoseconds. + Weight::from_ref_time(247_576_385 as u64) + // Standard Error: 80_494 + .saturating_add(Weight::from_ref_time(2_052_714 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1760,10 +1760,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 343_035 nanoseconds. - Weight::from_ref_time(345_347_882 as u64) - // Standard Error: 509 - .saturating_add(Weight::from_ref_time(228_526 as u64).saturating_mul(n as u64)) + // Minimum execution time: 248_049 nanoseconds. + Weight::from_ref_time(250_148_025 as u64) + // Standard Error: 339 + .saturating_add(Weight::from_ref_time(185_344 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1776,10 +1776,10 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - // Minimum execution time: 344_997 nanoseconds. - Weight::from_ref_time(346_431_655 as u64) - // Standard Error: 79_924 - .saturating_add(Weight::from_ref_time(53_530_044 as u64).saturating_mul(r as u64)) + // Minimum execution time: 246_620 nanoseconds. + Weight::from_ref_time(250_752_277 as u64) + // Standard Error: 84_300 + .saturating_add(Weight::from_ref_time(54_264_722 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1793,10 +1793,10 @@ impl WeightInfo for () { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - // Minimum execution time: 345_926 nanoseconds. - Weight::from_ref_time(351_620_774 as u64) - // Standard Error: 69_858 - .saturating_add(Weight::from_ref_time(130_846_895 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_065 nanoseconds. + Weight::from_ref_time(252_419_902 as u64) + // Standard Error: 84_223 + .saturating_add(Weight::from_ref_time(134_454_079 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1807,10 +1807,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - // Minimum execution time: 341_582 nanoseconds. - Weight::from_ref_time(353_141_157 as u64) - // Standard Error: 99_764 - .saturating_add(Weight::from_ref_time(231_149_152 as u64).saturating_mul(r as u64)) + // Minimum execution time: 246_588 nanoseconds. + Weight::from_ref_time(261_525_328 as u64) + // Standard Error: 97_732 + .saturating_add(Weight::from_ref_time(235_555_878 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1822,12 +1822,12 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - // Minimum execution time: 1_269_467 nanoseconds. - Weight::from_ref_time(566_371_969 as u64) - // Standard Error: 435_714 - .saturating_add(Weight::from_ref_time(180_441_805 as u64).saturating_mul(t as u64)) - // Standard Error: 119_668 - .saturating_add(Weight::from_ref_time(70_111_002 as u64).saturating_mul(n as u64)) + // Minimum execution time: 1_171_144 nanoseconds. + Weight::from_ref_time(490_333_337 as u64) + // Standard Error: 404_664 + .saturating_add(Weight::from_ref_time(173_683_265 as u64).saturating_mul(t as u64)) + // Standard Error: 111_140 + .saturating_add(Weight::from_ref_time(66_081_822 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1840,20 +1840,20 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - // Minimum execution time: 231_528 nanoseconds. - Weight::from_ref_time(235_676_870 as u64) - // Standard Error: 20_851 - .saturating_add(Weight::from_ref_time(26_215_920 as u64).saturating_mul(r as u64)) + // Minimum execution time: 178_822 nanoseconds. + Weight::from_ref_time(181_571_518 as u64) + // Standard Error: 19_207 + .saturating_add(Weight::from_ref_time(26_784_712 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - // Minimum execution time: 346_509 nanoseconds. - Weight::from_ref_time(301_173_874 as u64) - // Standard Error: 436_884 - .saturating_add(Weight::from_ref_time(415_194_325 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_737 nanoseconds. + Weight::from_ref_time(208_095_467 as u64) + // Standard Error: 417_236 + .saturating_add(Weight::from_ref_time(430_088_574 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1862,10 +1862,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - // Minimum execution time: 500_452 nanoseconds. - Weight::from_ref_time(641_506_544 as u64) - // Standard Error: 1_308_973 - .saturating_add(Weight::from_ref_time(98_769_541 as u64).saturating_mul(n as u64)) + // Minimum execution time: 400_055 nanoseconds. + Weight::from_ref_time(551_666_883 as u64) + // Standard Error: 1_379_652 + .saturating_add(Weight::from_ref_time(94_069_118 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(52 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(50 as u64)) @@ -1874,10 +1874,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - // Minimum execution time: 500_941 nanoseconds. - Weight::from_ref_time(610_446_049 as u64) - // Standard Error: 1_018_173 - .saturating_add(Weight::from_ref_time(65_568_627 as u64).saturating_mul(n as u64)) + // Minimum execution time: 400_370 nanoseconds. + Weight::from_ref_time(521_380_000 as u64) + // Standard Error: 1_112_618 + .saturating_add(Weight::from_ref_time(68_664_898 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(49 as u64)) @@ -1886,10 +1886,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - // Minimum execution time: 345_820 nanoseconds. - Weight::from_ref_time(302_335_076 as u64) - // Standard Error: 472_676 - .saturating_add(Weight::from_ref_time(395_286_593 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_711 nanoseconds. + Weight::from_ref_time(212_629_798 as u64) + // Standard Error: 378_159 + .saturating_add(Weight::from_ref_time(415_326_230 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1898,10 +1898,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 457_830 nanoseconds. - Weight::from_ref_time(582_524_868 as u64) - // Standard Error: 1_161_813 - .saturating_add(Weight::from_ref_time(67_291_419 as u64).saturating_mul(n as u64)) + // Minimum execution time: 365_702 nanoseconds. + Weight::from_ref_time(499_337_686 as u64) + // Standard Error: 1_232_330 + .saturating_add(Weight::from_ref_time(70_648_878 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(48 as u64)) @@ -1910,10 +1910,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - // Minimum execution time: 348_249 nanoseconds. - Weight::from_ref_time(317_329_583 as u64) - // Standard Error: 400_112 - .saturating_add(Weight::from_ref_time(331_362_971 as u64).saturating_mul(r as u64)) + // Minimum execution time: 251_357 nanoseconds. + Weight::from_ref_time(220_533_580 as u64) + // Standard Error: 345_297 + .saturating_add(Weight::from_ref_time(349_413_968 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1921,10 +1921,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 446_902 nanoseconds. - Weight::from_ref_time(556_989_117 as u64) - // Standard Error: 1_029_959 - .saturating_add(Weight::from_ref_time(159_623_361 as u64).saturating_mul(n as u64)) + // Minimum execution time: 354_162 nanoseconds. + Weight::from_ref_time(472_811_575 as u64) + // Standard Error: 1_109_282 + .saturating_add(Weight::from_ref_time(154_074_386 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1932,10 +1932,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - // Minimum execution time: 347_064 nanoseconds. - Weight::from_ref_time(316_879_171 as u64) - // Standard Error: 355_083 - .saturating_add(Weight::from_ref_time(304_763_264 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_551 nanoseconds. + Weight::from_ref_time(219_176_526 as u64) + // Standard Error: 358_914 + .saturating_add(Weight::from_ref_time(326_009_513 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1943,10 +1943,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 435_275 nanoseconds. - Weight::from_ref_time(527_900_488 as u64) - // Standard Error: 872_763 - .saturating_add(Weight::from_ref_time(60_604_211 as u64).saturating_mul(n as u64)) + // Minimum execution time: 339_149 nanoseconds. + Weight::from_ref_time(440_615_016 as u64) + // Standard Error: 954_837 + .saturating_add(Weight::from_ref_time(66_153_533 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1954,10 +1954,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - // Minimum execution time: 348_671 nanoseconds. - Weight::from_ref_time(306_307_186 as u64) - // Standard Error: 438_525 - .saturating_add(Weight::from_ref_time(422_575_502 as u64).saturating_mul(r as u64)) + // Minimum execution time: 251_812 nanoseconds. + Weight::from_ref_time(209_954_069 as u64) + // Standard Error: 398_380 + .saturating_add(Weight::from_ref_time(438_573_954 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1966,10 +1966,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 470_344 nanoseconds. - Weight::from_ref_time(613_380_073 as u64) - // Standard Error: 1_333_864 - .saturating_add(Weight::from_ref_time(164_398_286 as u64).saturating_mul(n as u64)) + // Minimum execution time: 374_594 nanoseconds. + Weight::from_ref_time(525_213_792 as u64) + // Standard Error: 1_378_489 + .saturating_add(Weight::from_ref_time(161_599_623 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(48 as u64)) @@ -1982,10 +1982,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - // Minimum execution time: 348_312 nanoseconds. - Weight::from_ref_time(303_017_886 as u64) - // Standard Error: 568_589 - .saturating_add(Weight::from_ref_time(1_351_508_682 as u64).saturating_mul(r as u64)) + // Minimum execution time: 251_379 nanoseconds. + Weight::from_ref_time(204_214_298 as u64) + // Standard Error: 662_575 + .saturating_add(Weight::from_ref_time(1_366_716_853 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -1998,10 +1998,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - // Minimum execution time: 348_997 nanoseconds. - Weight::from_ref_time(349_975_000 as u64) - // Standard Error: 5_689_469 - .saturating_add(Weight::from_ref_time(24_991_501_544 as u64).saturating_mul(r as u64)) + // Minimum execution time: 252_896 nanoseconds. + Weight::from_ref_time(253_811_000 as u64) + // Standard Error: 6_576_179 + .saturating_add(Weight::from_ref_time(17_254_952_849 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -2014,10 +2014,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - // Minimum execution time: 348_751 nanoseconds. - Weight::from_ref_time(349_330_000 as u64) - // Standard Error: 7_125_421 - .saturating_add(Weight::from_ref_time(24_917_646_052 as u64).saturating_mul(r as u64)) + // Minimum execution time: 249_312 nanoseconds. + Weight::from_ref_time(253_806_000 as u64) + // Standard Error: 6_118_873 + .saturating_add(Weight::from_ref_time(17_081_370_212 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((150 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -2031,12 +2031,12 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - // Minimum execution time: 16_275_711 nanoseconds. - Weight::from_ref_time(15_203_241_602 as u64) - // Standard Error: 3_582_276 - .saturating_add(Weight::from_ref_time(1_179_848_168 as u64).saturating_mul(t as u64)) - // Standard Error: 5_371 - .saturating_add(Weight::from_ref_time(9_712_484 as u64).saturating_mul(c as u64)) + // Minimum execution time: 12_001_522 nanoseconds. + Weight::from_ref_time(10_903_312_955 as u64) + // Standard Error: 4_301_096 + .saturating_add(Weight::from_ref_time(1_243_413_241 as u64).saturating_mul(t as u64)) + // Standard Error: 6_449 + .saturating_add(Weight::from_ref_time(9_713_655 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(167 as u64)) .saturating_add(RocksDbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(163 as u64)) @@ -2051,10 +2051,10 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - // Minimum execution time: 353_168 nanoseconds. - Weight::from_ref_time(353_901_000 as u64) - // Standard Error: 18_701_989 - .saturating_add(Weight::from_ref_time(30_028_672_644 as u64).saturating_mul(r as u64)) + // Minimum execution time: 254_969 nanoseconds. + Weight::from_ref_time(255_984_000 as u64) + // Standard Error: 18_545_048 + .saturating_add(Weight::from_ref_time(22_343_189_765 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().reads((400 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(5 as u64)) @@ -2070,10 +2070,10 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - // Minimum execution time: 18_226_984 nanoseconds. - Weight::from_ref_time(18_032_466_983 as u64) - // Standard Error: 75_544 - .saturating_add(Weight::from_ref_time(121_087_538 as u64).saturating_mul(s as u64)) + // Minimum execution time: 14_077_497 nanoseconds. + Weight::from_ref_time(13_949_740_588 as u64) + // Standard Error: 66_631 + .saturating_add(Weight::from_ref_time(120_519_572 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(249 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(247 as u64)) @@ -2086,10 +2086,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - // Minimum execution time: 344_334 nanoseconds. - Weight::from_ref_time(345_939_404 as u64) - // Standard Error: 98_994 - .saturating_add(Weight::from_ref_time(58_015_295 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_445 nanoseconds. + Weight::from_ref_time(251_229_791 as u64) + // Standard Error: 88_045 + .saturating_add(Weight::from_ref_time(57_577_008 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2100,10 +2100,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 402_492 nanoseconds. - Weight::from_ref_time(402_789_000 as u64) - // Standard Error: 54_174 - .saturating_add(Weight::from_ref_time(324_036_889 as u64).saturating_mul(n as u64)) + // Minimum execution time: 308_069 nanoseconds. + Weight::from_ref_time(308_971_000 as u64) + // Standard Error: 46_181 + .saturating_add(Weight::from_ref_time(321_835_684 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2114,10 +2114,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - // Minimum execution time: 343_493 nanoseconds. - Weight::from_ref_time(345_116_214 as u64) - // Standard Error: 90_515 - .saturating_add(Weight::from_ref_time(71_282_485 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_107 nanoseconds. + Weight::from_ref_time(250_125_030 as u64) + // Standard Error: 88_769 + .saturating_add(Weight::from_ref_time(70_727_669 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2128,10 +2128,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 415_650 nanoseconds. - Weight::from_ref_time(415_894_000 as u64) - // Standard Error: 58_077 - .saturating_add(Weight::from_ref_time(248_416_317 as u64).saturating_mul(n as u64)) + // Minimum execution time: 319_515 nanoseconds. + Weight::from_ref_time(319_784_000 as u64) + // Standard Error: 58_896 + .saturating_add(Weight::from_ref_time(246_433_962 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2142,10 +2142,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - // Minimum execution time: 343_890 nanoseconds. - Weight::from_ref_time(345_542_924 as u64) - // Standard Error: 87_564 - .saturating_add(Weight::from_ref_time(47_361_375 as u64).saturating_mul(r as u64)) + // Minimum execution time: 247_887 nanoseconds. + Weight::from_ref_time(250_452_702 as u64) + // Standard Error: 140_887 + .saturating_add(Weight::from_ref_time(49_538_397 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2156,10 +2156,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 391_629 nanoseconds. - Weight::from_ref_time(392_793_000 as u64) - // Standard Error: 51_120 - .saturating_add(Weight::from_ref_time(99_288_467 as u64).saturating_mul(n as u64)) + // Minimum execution time: 297_534 nanoseconds. + Weight::from_ref_time(298_249_000 as u64) + // Standard Error: 49_680 + .saturating_add(Weight::from_ref_time(99_001_103 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2170,10 +2170,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - // Minimum execution time: 341_701 nanoseconds. - Weight::from_ref_time(343_318_489 as u64) - // Standard Error: 103_756 - .saturating_add(Weight::from_ref_time(47_301_910 as u64).saturating_mul(r as u64)) + // Minimum execution time: 245_926 nanoseconds. + Weight::from_ref_time(248_471_834 as u64) + // Standard Error: 101_639 + .saturating_add(Weight::from_ref_time(47_889_865 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2184,10 +2184,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 389_898 nanoseconds. - Weight::from_ref_time(390_489_000 as u64) - // Standard Error: 52_301 - .saturating_add(Weight::from_ref_time(99_344_068 as u64).saturating_mul(n as u64)) + // Minimum execution time: 294_835 nanoseconds. + Weight::from_ref_time(296_328_000 as u64) + // Standard Error: 46_612 + .saturating_add(Weight::from_ref_time(98_859_152 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2198,10 +2198,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - // Minimum execution time: 348_789 nanoseconds. - Weight::from_ref_time(350_451_620 as u64) - // Standard Error: 195_939 - .saturating_add(Weight::from_ref_time(2_962_830_479 as u64).saturating_mul(r as u64)) + // Minimum execution time: 251_104 nanoseconds. + Weight::from_ref_time(253_114_893 as u64) + // Standard Error: 316_740 + .saturating_add(Weight::from_ref_time(2_964_072_706 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2212,10 +2212,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - // Minimum execution time: 346_537 nanoseconds. - Weight::from_ref_time(347_926_836 as u64) - // Standard Error: 110_557 - .saturating_add(Weight::from_ref_time(2_058_656_763 as u64).saturating_mul(r as u64)) + // Minimum execution time: 250_048 nanoseconds. + Weight::from_ref_time(251_774_991 as u64) + // Standard Error: 115_294 + .saturating_add(Weight::from_ref_time(2_094_245_208 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2227,10 +2227,10 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 346_672 nanoseconds. - Weight::from_ref_time(347_628_000 as u64) - // Standard Error: 2_742_329 - .saturating_add(Weight::from_ref_time(1_370_383_386 as u64).saturating_mul(r as u64)) + // Minimum execution time: 250_830 nanoseconds. + Weight::from_ref_time(251_477_000 as u64) + // Standard Error: 2_727_998 + .saturating_add(Weight::from_ref_time(1_390_149_283 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((225 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -2238,359 +2238,359 @@ impl WeightInfo for () { } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - // Minimum execution time: 118_029 nanoseconds. - Weight::from_ref_time(118_800_774 as u64) - // Standard Error: 4_234 - .saturating_add(Weight::from_ref_time(866_719 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_022 nanoseconds. + Weight::from_ref_time(69_707_657 as u64) + // Standard Error: 8_674 + .saturating_add(Weight::from_ref_time(887_555 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // Minimum execution time: 118_145 nanoseconds. - Weight::from_ref_time(118_644_813 as u64) - // Standard Error: 2_692 - .saturating_add(Weight::from_ref_time(2_874_276 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_491 nanoseconds. + Weight::from_ref_time(70_354_670 as u64) + // Standard Error: 1_518 + .saturating_add(Weight::from_ref_time(2_758_912 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // Minimum execution time: 118_142 nanoseconds. - Weight::from_ref_time(118_474_161 as u64) - // Standard Error: 6_997 - .saturating_add(Weight::from_ref_time(2_769_076 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_156 nanoseconds. + Weight::from_ref_time(69_917_601 as u64) + // Standard Error: 1_970 + .saturating_add(Weight::from_ref_time(2_753_174 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // Minimum execution time: 118_020 nanoseconds. - Weight::from_ref_time(118_499_103 as u64) - // Standard Error: 1_266 - .saturating_add(Weight::from_ref_time(2_351_397 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_944 nanoseconds. + Weight::from_ref_time(69_727_961 as u64) + // Standard Error: 376 + .saturating_add(Weight::from_ref_time(2_356_996 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // Minimum execution time: 118_008 nanoseconds. - Weight::from_ref_time(118_398_803 as u64) - // Standard Error: 750 - .saturating_add(Weight::from_ref_time(2_480_061 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_971 nanoseconds. + Weight::from_ref_time(69_755_949 as u64) + // Standard Error: 543 + .saturating_add(Weight::from_ref_time(2_489_510 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // Minimum execution time: 118_046 nanoseconds. - Weight::from_ref_time(118_332_903 as u64) - // Standard Error: 234 - .saturating_add(Weight::from_ref_time(1_426_355 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_061 nanoseconds. + Weight::from_ref_time(69_625_000 as u64) + // Standard Error: 486 + .saturating_add(Weight::from_ref_time(1_431_684 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // Minimum execution time: 117_998 nanoseconds. - Weight::from_ref_time(117_910_870 as u64) - // Standard Error: 4_629 - .saturating_add(Weight::from_ref_time(1_992_697 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_058 nanoseconds. + Weight::from_ref_time(69_521_790 as u64) + // Standard Error: 892 + .saturating_add(Weight::from_ref_time(1_964_054 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // Minimum execution time: 117_998 nanoseconds. - Weight::from_ref_time(118_059_139 as u64) - // Standard Error: 1_985 - .saturating_add(Weight::from_ref_time(2_164_252 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_020 nanoseconds. + Weight::from_ref_time(69_344_255 as u64) + // Standard Error: 1_408 + .saturating_add(Weight::from_ref_time(2_169_179 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - // Minimum execution time: 121_282 nanoseconds. - Weight::from_ref_time(121_483_289 as u64) - // Standard Error: 57 - .saturating_add(Weight::from_ref_time(4_013 as u64).saturating_mul(e as u64)) + // Minimum execution time: 72_366 nanoseconds. + Weight::from_ref_time(72_869_594 as u64) + // Standard Error: 73 + .saturating_add(Weight::from_ref_time(3_867 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // Minimum execution time: 118_128 nanoseconds. - Weight::from_ref_time(118_869_764 as u64) - // Standard Error: 8_890 - .saturating_add(Weight::from_ref_time(6_496_684 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_164 nanoseconds. + Weight::from_ref_time(70_269_099 as u64) + // Standard Error: 8_824 + .saturating_add(Weight::from_ref_time(6_594_634 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // Minimum execution time: 131_764 nanoseconds. - Weight::from_ref_time(133_009_514 as u64) - // Standard Error: 9_697 - .saturating_add(Weight::from_ref_time(8_310_784 as u64).saturating_mul(r as u64)) + // Minimum execution time: 83_348 nanoseconds. + Weight::from_ref_time(84_968_895 as u64) + // Standard Error: 6_305 + .saturating_add(Weight::from_ref_time(8_395_193 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - // Minimum execution time: 141_100 nanoseconds. - Weight::from_ref_time(142_282_540 as u64) - // Standard Error: 867 - .saturating_add(Weight::from_ref_time(536_814 as u64).saturating_mul(p as u64)) + // Minimum execution time: 92_358 nanoseconds. + Weight::from_ref_time(93_605_536 as u64) + // Standard Error: 2_019 + .saturating_add(Weight::from_ref_time(536_495 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // Minimum execution time: 118_535 nanoseconds. - Weight::from_ref_time(119_017_162 as u64) - // Standard Error: 1_175 - .saturating_add(Weight::from_ref_time(911_141 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_191 nanoseconds. + Weight::from_ref_time(70_407_702 as u64) + // Standard Error: 2_812 + .saturating_add(Weight::from_ref_time(901_706 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // Minimum execution time: 118_472 nanoseconds. - Weight::from_ref_time(118_790_737 as u64) - // Standard Error: 758 - .saturating_add(Weight::from_ref_time(962_148 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_230 nanoseconds. + Weight::from_ref_time(70_255_278 as u64) + // Standard Error: 1_284 + .saturating_add(Weight::from_ref_time(951_754 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // Minimum execution time: 118_551 nanoseconds. - Weight::from_ref_time(119_070_827 as u64) - // Standard Error: 2_411 - .saturating_add(Weight::from_ref_time(1_367_622 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_278 nanoseconds. + Weight::from_ref_time(70_089_139 as u64) + // Standard Error: 757 + .saturating_add(Weight::from_ref_time(1_369_185 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // Minimum execution time: 120_958 nanoseconds. - Weight::from_ref_time(121_649_052 as u64) - // Standard Error: 1_557 - .saturating_add(Weight::from_ref_time(1_447_477 as u64).saturating_mul(r as u64)) + // Minimum execution time: 72_047 nanoseconds. + Weight::from_ref_time(72_783_972 as u64) + // Standard Error: 837 + .saturating_add(Weight::from_ref_time(1_471_680 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // Minimum execution time: 120_866 nanoseconds. - Weight::from_ref_time(121_040_400 as u64) - // Standard Error: 6_203 - .saturating_add(Weight::from_ref_time(1_548_715 as u64).saturating_mul(r as u64)) + // Minimum execution time: 71_960 nanoseconds. + Weight::from_ref_time(72_745_981 as u64) + // Standard Error: 1_086 + .saturating_add(Weight::from_ref_time(1_537_741 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // Minimum execution time: 118_076 nanoseconds. - Weight::from_ref_time(118_381_010 as u64) - // Standard Error: 1_814 - .saturating_add(Weight::from_ref_time(938_699 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_221 nanoseconds. + Weight::from_ref_time(70_010_862 as u64) + // Standard Error: 1_845 + .saturating_add(Weight::from_ref_time(933_738 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // Minimum execution time: 118_030 nanoseconds. - Weight::from_ref_time(120_331_261 as u64) - // Standard Error: 333_364 - .saturating_add(Weight::from_ref_time(227_636_638 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_081 nanoseconds. + Weight::from_ref_time(71_015_495 as u64) + // Standard Error: 27_078 + .saturating_add(Weight::from_ref_time(183_899_704 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // Minimum execution time: 118_056 nanoseconds. - Weight::from_ref_time(118_554_799 as u64) - // Standard Error: 1_269 - .saturating_add(Weight::from_ref_time(1_331_717 as u64).saturating_mul(r as u64)) + // Minimum execution time: 70_589 nanoseconds. + Weight::from_ref_time(70_175_537 as u64) + // Standard Error: 1_355 + .saturating_add(Weight::from_ref_time(1_323_745 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - // Minimum execution time: 118_009 nanoseconds. - Weight::from_ref_time(118_678_537 as u64) - // Standard Error: 1_699 - .saturating_add(Weight::from_ref_time(1_328_153 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_083 nanoseconds. + Weight::from_ref_time(69_832_339 as u64) + // Standard Error: 818 + .saturating_add(Weight::from_ref_time(1_334_198 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // Minimum execution time: 118_031 nanoseconds. - Weight::from_ref_time(118_478_616 as u64) - // Standard Error: 1_533 - .saturating_add(Weight::from_ref_time(1_335_254 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_084 nanoseconds. + Weight::from_ref_time(69_802_701 as u64) + // Standard Error: 744 + .saturating_add(Weight::from_ref_time(1_334_601 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // Minimum execution time: 117_910 nanoseconds. - Weight::from_ref_time(118_471_672 as u64) - // Standard Error: 1_275 - .saturating_add(Weight::from_ref_time(1_345_140 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_052 nanoseconds. + Weight::from_ref_time(69_717_748 as u64) + // Standard Error: 571 + .saturating_add(Weight::from_ref_time(1_346_564 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // Minimum execution time: 119_504 nanoseconds. - Weight::from_ref_time(118_940_207 as u64) - // Standard Error: 2_512 - .saturating_add(Weight::from_ref_time(1_307_954 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_016 nanoseconds. + Weight::from_ref_time(69_793_413 as u64) + // Standard Error: 769 + .saturating_add(Weight::from_ref_time(1_317_502 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // Minimum execution time: 118_009 nanoseconds. - Weight::from_ref_time(118_366_251 as u64) - // Standard Error: 1_116 - .saturating_add(Weight::from_ref_time(1_322_232 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_043 nanoseconds. + Weight::from_ref_time(69_963_419 as u64) + // Standard Error: 1_117 + .saturating_add(Weight::from_ref_time(1_313_727 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // Minimum execution time: 118_020 nanoseconds. - Weight::from_ref_time(118_222_792 as u64) - // Standard Error: 1_973 - .saturating_add(Weight::from_ref_time(1_336_896 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_032 nanoseconds. + Weight::from_ref_time(69_727_577 as u64) + // Standard Error: 662 + .saturating_add(Weight::from_ref_time(1_331_088 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // Minimum execution time: 118_038 nanoseconds. - Weight::from_ref_time(118_757_016 as u64) - // Standard Error: 7_932 - .saturating_add(Weight::from_ref_time(1_867_807 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_097 nanoseconds. + Weight::from_ref_time(69_767_650 as u64) + // Standard Error: 2_056 + .saturating_add(Weight::from_ref_time(1_875_021 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // Minimum execution time: 118_041 nanoseconds. - Weight::from_ref_time(118_717_403 as u64) - // Standard Error: 8_010 - .saturating_add(Weight::from_ref_time(1_868_876 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_153 nanoseconds. + Weight::from_ref_time(69_906_946 as u64) + // Standard Error: 1_060 + .saturating_add(Weight::from_ref_time(1_867_154 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // Minimum execution time: 118_057 nanoseconds. - Weight::from_ref_time(118_560_106 as u64) - // Standard Error: 1_362 - .saturating_add(Weight::from_ref_time(1_869_820 as u64).saturating_mul(r as u64)) + // Minimum execution time: 70_380 nanoseconds. + Weight::from_ref_time(69_867_328 as u64) + // Standard Error: 778 + .saturating_add(Weight::from_ref_time(1_869_718 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // Minimum execution time: 118_045 nanoseconds. - Weight::from_ref_time(118_318_194 as u64) - // Standard Error: 179 - .saturating_add(Weight::from_ref_time(1_873_670 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_259 nanoseconds. + Weight::from_ref_time(69_695_407 as u64) + // Standard Error: 746 + .saturating_add(Weight::from_ref_time(1_874_772 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // Minimum execution time: 118_000 nanoseconds. - Weight::from_ref_time(118_520_606 as u64) - // Standard Error: 3_656 - .saturating_add(Weight::from_ref_time(1_870_762 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_986 nanoseconds. + Weight::from_ref_time(70_027_081 as u64) + // Standard Error: 1_401 + .saturating_add(Weight::from_ref_time(1_862_971 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // Minimum execution time: 118_035 nanoseconds. - Weight::from_ref_time(118_464_151 as u64) - // Standard Error: 1_073 - .saturating_add(Weight::from_ref_time(1_870_309 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_953 nanoseconds. + Weight::from_ref_time(69_798_073 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_871_888 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // Minimum execution time: 118_071 nanoseconds. - Weight::from_ref_time(118_470_365 as u64) - // Standard Error: 1_224 - .saturating_add(Weight::from_ref_time(1_870_522 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_909 nanoseconds. + Weight::from_ref_time(69_845_981 as u64) + // Standard Error: 775 + .saturating_add(Weight::from_ref_time(1_868_722 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // Minimum execution time: 118_032 nanoseconds. - Weight::from_ref_time(118_407_669 as u64) - // Standard Error: 769 - .saturating_add(Weight::from_ref_time(1_883_635 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_986 nanoseconds. + Weight::from_ref_time(69_683_189 as u64) + // Standard Error: 503 + .saturating_add(Weight::from_ref_time(1_884_715 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - // Minimum execution time: 118_044 nanoseconds. - Weight::from_ref_time(118_324_106 as u64) - // Standard Error: 523 - .saturating_add(Weight::from_ref_time(1_874_728 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_230 nanoseconds. + Weight::from_ref_time(69_765_336 as u64) + // Standard Error: 2_060 + .saturating_add(Weight::from_ref_time(1_871_848 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // Minimum execution time: 118_111 nanoseconds. - Weight::from_ref_time(118_538_748 as u64) - // Standard Error: 3_498 - .saturating_add(Weight::from_ref_time(1_868_932 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_953 nanoseconds. + Weight::from_ref_time(69_828_265 as u64) + // Standard Error: 951 + .saturating_add(Weight::from_ref_time(1_868_596 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // Minimum execution time: 118_060 nanoseconds. - Weight::from_ref_time(118_421_175 as u64) - // Standard Error: 962 - .saturating_add(Weight::from_ref_time(1_850_713 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_078 nanoseconds. + Weight::from_ref_time(69_832_768 as u64) + // Standard Error: 894 + .saturating_add(Weight::from_ref_time(1_845_786 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // Minimum execution time: 118_050 nanoseconds. - Weight::from_ref_time(118_774_937 as u64) - // Standard Error: 1_717 - .saturating_add(Weight::from_ref_time(1_838_127 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_939 nanoseconds. + Weight::from_ref_time(69_676_256 as u64) + // Standard Error: 374 + .saturating_add(Weight::from_ref_time(1_851_026 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // Minimum execution time: 117_997 nanoseconds. - Weight::from_ref_time(118_626_785 as u64) - // Standard Error: 1_382 - .saturating_add(Weight::from_ref_time(1_842_530 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_096 nanoseconds. + Weight::from_ref_time(69_914_159 as u64) + // Standard Error: 1_265 + .saturating_add(Weight::from_ref_time(1_844_489 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // Minimum execution time: 118_064 nanoseconds. - Weight::from_ref_time(118_404_203 as u64) - // Standard Error: 2_437 - .saturating_add(Weight::from_ref_time(2_489_569 as u64).saturating_mul(r as u64)) + // Minimum execution time: 68_939 nanoseconds. + Weight::from_ref_time(69_641_768 as u64) + // Standard Error: 347 + .saturating_add(Weight::from_ref_time(2_488_628 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // Minimum execution time: 117_949 nanoseconds. - Weight::from_ref_time(118_525_228 as u64) - // Standard Error: 2_231 - .saturating_add(Weight::from_ref_time(2_453_863 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_114 nanoseconds. + Weight::from_ref_time(69_844_395 as u64) + // Standard Error: 1_489 + .saturating_add(Weight::from_ref_time(2_456_310 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // Minimum execution time: 118_032 nanoseconds. - Weight::from_ref_time(118_311_431 as u64) - // Standard Error: 175 - .saturating_add(Weight::from_ref_time(2_532_745 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_082 nanoseconds. + Weight::from_ref_time(69_993_662 as u64) + // Standard Error: 1_218 + .saturating_add(Weight::from_ref_time(2_524_010 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // Minimum execution time: 117_987 nanoseconds. - Weight::from_ref_time(118_573_115 as u64) - // Standard Error: 1_814 - .saturating_add(Weight::from_ref_time(2_438_519 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_036 nanoseconds. + Weight::from_ref_time(70_095_304 as u64) + // Standard Error: 1_473 + .saturating_add(Weight::from_ref_time(2_429_659 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // Minimum execution time: 120_001 nanoseconds. - Weight::from_ref_time(118_527_518 as u64) - // Standard Error: 1_040 - .saturating_add(Weight::from_ref_time(1_874_359 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_229 nanoseconds. + Weight::from_ref_time(69_759_818 as u64) + // Standard Error: 573 + .saturating_add(Weight::from_ref_time(1_879_670 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // Minimum execution time: 118_051 nanoseconds. - Weight::from_ref_time(118_315_649 as u64) - // Standard Error: 163 - .saturating_add(Weight::from_ref_time(1_851_162 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_151 nanoseconds. + Weight::from_ref_time(69_865_948 as u64) + // Standard Error: 721 + .saturating_add(Weight::from_ref_time(1_846_734 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // Minimum execution time: 118_038 nanoseconds. - Weight::from_ref_time(118_558_677 as u64) - // Standard Error: 2_258 - .saturating_add(Weight::from_ref_time(1_845_713 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_120 nanoseconds. + Weight::from_ref_time(70_135_849 as u64) + // Standard Error: 3_443 + .saturating_add(Weight::from_ref_time(1_841_784 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // Minimum execution time: 117_985 nanoseconds. - Weight::from_ref_time(118_660_597 as u64) - // Standard Error: 5_893 - .saturating_add(Weight::from_ref_time(1_887_423 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_077 nanoseconds. + Weight::from_ref_time(69_929_746 as u64) + // Standard Error: 821 + .saturating_add(Weight::from_ref_time(1_866_348 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // Minimum execution time: 120_101 nanoseconds. - Weight::from_ref_time(118_522_424 as u64) - // Standard Error: 1_094 - .saturating_add(Weight::from_ref_time(1_867_495 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_226 nanoseconds. + Weight::from_ref_time(69_725_630 as u64) + // Standard Error: 891 + .saturating_add(Weight::from_ref_time(1_873_637 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // Minimum execution time: 118_068 nanoseconds. - Weight::from_ref_time(119_012_941 as u64) - // Standard Error: 9_129 - .saturating_add(Weight::from_ref_time(1_877_850 as u64).saturating_mul(r as u64)) + // Minimum execution time: 70_591 nanoseconds. + Weight::from_ref_time(69_939_773 as u64) + // Standard Error: 960 + .saturating_add(Weight::from_ref_time(1_867_208 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // Minimum execution time: 120_105 nanoseconds. - Weight::from_ref_time(118_559_474 as u64) - // Standard Error: 2_055 - .saturating_add(Weight::from_ref_time(1_868_662 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_187 nanoseconds. + Weight::from_ref_time(69_845_516 as u64) + // Standard Error: 781 + .saturating_add(Weight::from_ref_time(1_869_613 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // Minimum execution time: 118_004 nanoseconds. - Weight::from_ref_time(118_370_466 as u64) - // Standard Error: 818 - .saturating_add(Weight::from_ref_time(1_873_459 as u64).saturating_mul(r as u64)) + // Minimum execution time: 69_065 nanoseconds. + Weight::from_ref_time(69_950_430 as u64) + // Standard Error: 986 + .saturating_add(Weight::from_ref_time(1_867_001 as u64).saturating_mul(r as u64)) } } diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index 6428d82c94c39..e50842449f88a 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_conviction_voting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/conviction-voting/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,7 +65,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_new() -> Weight { - Weight::from_ref_time(148_804_000 as u64) + // Minimum execution time: 131_633 nanoseconds. + Weight::from_ref_time(132_742_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -72,7 +76,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_existing() -> Weight { - Weight::from_ref_time(313_333_000 as u64) + // Minimum execution time: 176_240 nanoseconds. + Weight::from_ref_time(183_274_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -80,14 +85,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn remove_vote() -> Weight { - Weight::from_ref_time(300_591_000 as u64) + // Minimum execution time: 158_880 nanoseconds. + Weight::from_ref_time(164_648_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:0) fn remove_other_vote() -> Weight { - Weight::from_ref_time(53_887_000 as u64) + // Minimum execution time: 60_330 nanoseconds. + Weight::from_ref_time(61_588_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -96,10 +103,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) + /// The range of component `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(51_518_000 as u64) - // Standard Error: 83_000 - .saturating_add(Weight::from_ref_time(27_235_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 63_088 nanoseconds. + Weight::from_ref_time(67_803_536 as u64) + // Standard Error: 197_102 + .saturating_add(Weight::from_ref_time(31_557_563 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -108,10 +117,12 @@ impl WeightInfo for SubstrateWeight { // Storage: ConvictionVoting VotingFor (r:2 w:2) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) + /// The range of component `r` is `[0, 1]`. fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(37_885_000 as u64) - // Standard Error: 75_000 - .saturating_add(Weight::from_ref_time(24_395_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 45_150 nanoseconds. + Weight::from_ref_time(51_547_530 as u64) + // Standard Error: 771_127 + .saturating_add(Weight::from_ref_time(26_927_969 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) @@ -121,7 +132,8 @@ impl WeightInfo for SubstrateWeight { // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn unlock() -> Weight { - Weight::from_ref_time(67_703_000 as u64) + // Minimum execution time: 75_067 nanoseconds. + Weight::from_ref_time(76_888_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -135,7 +147,8 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_new() -> Weight { - Weight::from_ref_time(148_804_000 as u64) + // Minimum execution time: 131_633 nanoseconds. + Weight::from_ref_time(132_742_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -145,7 +158,8 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote_existing() -> Weight { - Weight::from_ref_time(313_333_000 as u64) + // Minimum execution time: 176_240 nanoseconds. + Weight::from_ref_time(183_274_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -153,14 +167,16 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn remove_vote() -> Weight { - Weight::from_ref_time(300_591_000 as u64) + // Minimum execution time: 158_880 nanoseconds. + Weight::from_ref_time(164_648_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: ConvictionVoting VotingFor (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:0) fn remove_other_vote() -> Weight { - Weight::from_ref_time(53_887_000 as u64) + // Minimum execution time: 60_330 nanoseconds. + Weight::from_ref_time(61_588_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -169,10 +185,12 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) + /// The range of component `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(51_518_000 as u64) - // Standard Error: 83_000 - .saturating_add(Weight::from_ref_time(27_235_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 63_088 nanoseconds. + Weight::from_ref_time(67_803_536 as u64) + // Standard Error: 197_102 + .saturating_add(Weight::from_ref_time(31_557_563 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -181,10 +199,12 @@ impl WeightInfo for () { // Storage: ConvictionVoting VotingFor (r:2 w:2) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) + /// The range of component `r` is `[0, 1]`. fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(37_885_000 as u64) - // Standard Error: 75_000 - .saturating_add(Weight::from_ref_time(24_395_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 45_150 nanoseconds. + Weight::from_ref_time(51_547_530 as u64) + // Standard Error: 771_127 + .saturating_add(Weight::from_ref_time(26_927_969 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) @@ -194,7 +214,8 @@ impl WeightInfo for () { // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn unlock() -> Weight { - Weight::from_ref_time(67_703_000 as u64) + // Minimum execution time: 75_067 nanoseconds. + Weight::from_ref_time(76_888_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 0a3b717938022..db3969d400b97 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,23 +18,24 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_democracy // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --pallet=pallet_democracy -// --chain=dev // --output=./frame/democracy/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -78,13 +79,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - Weight::from_ref_time(57_410_000 as u64) + // Minimum execution time: 56_868 nanoseconds. + Weight::from_ref_time(57_788_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy DepositOf (r:1 w:1) fn second() -> Weight { - Weight::from_ref_time(49_224_000 as u64) + // Minimum execution time: 49_328 nanoseconds. + Weight::from_ref_time(49_764_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -92,7 +95,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new() -> Weight { - Weight::from_ref_time(60_933_000 as u64) + // Minimum execution time: 60_323 nanoseconds. + Weight::from_ref_time(61_389_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -100,14 +104,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing() -> Weight { - Weight::from_ref_time(60_393_000 as u64) + // Minimum execution time: 60_612 nanoseconds. + Weight::from_ref_time(61_282_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - Weight::from_ref_time(24_588_000 as u64) + // Minimum execution time: 24_780 nanoseconds. + Weight::from_ref_time(25_194_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -118,39 +124,45 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Blacklist (r:0 w:1) fn blacklist() -> Weight { - Weight::from_ref_time(91_226_000 as u64) + // Minimum execution time: 85_177 nanoseconds. + Weight::from_ref_time(91_733_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose() -> Weight { - Weight::from_ref_time(18_898_000 as u64) + // Minimum execution time: 19_483 nanoseconds. + Weight::from_ref_time(19_914_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - Weight::from_ref_time(5_136_000 as u64) + // Minimum execution time: 4_963 nanoseconds. + Weight::from_ref_time(5_250_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - Weight::from_ref_time(5_243_000 as u64) + // Minimum execution time: 5_075 nanoseconds. + Weight::from_ref_time(5_187_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - Weight::from_ref_time(24_275_000 as u64) + // Minimum execution time: 23_956 nanoseconds. + Weight::from_ref_time(24_814_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external() -> Weight { - Weight::from_ref_time(30_988_000 as u64) + // Minimum execution time: 31_472 nanoseconds. + Weight::from_ref_time(31_770_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -158,13 +170,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal() -> Weight { - Weight::from_ref_time(78_515_000 as u64) + // Minimum execution time: 73_811 nanoseconds. + Weight::from_ref_time(78_943_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - Weight::from_ref_time(16_155_000 as u64) + // Minimum execution time: 16_074 nanoseconds. + Weight::from_ref_time(16_409_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy LowestUnbaked (r:1 w:1) @@ -172,9 +186,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumInfoOf (r:2 w:0) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { - Weight::from_ref_time(7_007_000 as u64) - // Standard Error: 2_686 - .saturating_add(Weight::from_ref_time(2_288_781 as u64).saturating_mul(r as u64)) + // Minimum execution time: 7_430 nanoseconds. + Weight::from_ref_time(12_086_064 as u64) + // Standard Error: 3_474 + .saturating_add(Weight::from_ref_time(2_283_457 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -187,9 +202,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumInfoOf (r:2 w:0) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - Weight::from_ref_time(9_528_000 as u64) - // Standard Error: 2_521 - .saturating_add(Weight::from_ref_time(2_291_780 as u64).saturating_mul(r as u64)) + // Minimum execution time: 9_882 nanoseconds. + Weight::from_ref_time(14_566_711 as u64) + // Standard Error: 3_354 + .saturating_add(Weight::from_ref_time(2_282_038 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -199,9 +215,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumInfoOf (r:2 w:2) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(46_787_000 as u64) - // Standard Error: 2_943 - .saturating_add(Weight::from_ref_time(3_460_194 as u64).saturating_mul(r as u64)) + // Minimum execution time: 48_840 nanoseconds. + Weight::from_ref_time(56_403_092 as u64) + // Standard Error: 6_093 + .saturating_add(Weight::from_ref_time(3_344_243 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -211,9 +228,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy ReferendumInfoOf (r:2 w:2) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(29_789_000 as u64) - // Standard Error: 2_324 - .saturating_add(Weight::from_ref_time(3_360_918 as u64).saturating_mul(r as u64)) + // Minimum execution time: 30_483 nanoseconds. + Weight::from_ref_time(32_035_405 as u64) + // Standard Error: 4_383 + .saturating_add(Weight::from_ref_time(3_347_667 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) @@ -221,7 +239,8 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - Weight::from_ref_time(6_519_000 as u64) + // Minimum execution time: 6_421 nanoseconds. + Weight::from_ref_time(6_638_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) @@ -229,9 +248,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { - Weight::from_ref_time(28_884_000 as u64) - // Standard Error: 2_631 - .saturating_add(Weight::from_ref_time(163_516 as u64).saturating_mul(r as u64)) + // Minimum execution time: 30_291 nanoseconds. + Weight::from_ref_time(37_071_950 as u64) + // Standard Error: 1_619 + .saturating_add(Weight::from_ref_time(59_302 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -240,9 +260,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { - Weight::from_ref_time(33_498_000 as u64) - // Standard Error: 622 - .saturating_add(Weight::from_ref_time(133_421 as u64).saturating_mul(r as u64)) + // Minimum execution time: 34_888 nanoseconds. + Weight::from_ref_time(36_418_789 as u64) + // Standard Error: 906 + .saturating_add(Weight::from_ref_time(109_602 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -250,9 +271,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { - Weight::from_ref_time(18_201_000 as u64) - // Standard Error: 1_007 - .saturating_add(Weight::from_ref_time(152_699 as u64).saturating_mul(r as u64)) + // Minimum execution time: 18_739 nanoseconds. + Weight::from_ref_time(21_004_077 as u64) + // Standard Error: 1_075 + .saturating_add(Weight::from_ref_time(116_457 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -260,9 +282,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy VotingOf (r:1 w:1) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { - Weight::from_ref_time(18_455_000 as u64) - // Standard Error: 951 - .saturating_add(Weight::from_ref_time(150_907 as u64).saturating_mul(r as u64)) + // Minimum execution time: 18_514 nanoseconds. + Weight::from_ref_time(21_030_667 as u64) + // Standard Error: 1_102 + .saturating_add(Weight::from_ref_time(118_039 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -275,13 +298,15 @@ impl WeightInfo for () { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - Weight::from_ref_time(57_410_000 as u64) + // Minimum execution time: 56_868 nanoseconds. + Weight::from_ref_time(57_788_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy DepositOf (r:1 w:1) fn second() -> Weight { - Weight::from_ref_time(49_224_000 as u64) + // Minimum execution time: 49_328 nanoseconds. + Weight::from_ref_time(49_764_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -289,7 +314,8 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_new() -> Weight { - Weight::from_ref_time(60_933_000 as u64) + // Minimum execution time: 60_323 nanoseconds. + Weight::from_ref_time(61_389_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -297,14 +323,16 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn vote_existing() -> Weight { - Weight::from_ref_time(60_393_000 as u64) + // Minimum execution time: 60_612 nanoseconds. + Weight::from_ref_time(61_282_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - Weight::from_ref_time(24_588_000 as u64) + // Minimum execution time: 24_780 nanoseconds. + Weight::from_ref_time(25_194_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -315,39 +343,45 @@ impl WeightInfo for () { // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Blacklist (r:0 w:1) fn blacklist() -> Weight { - Weight::from_ref_time(91_226_000 as u64) + // Minimum execution time: 85_177 nanoseconds. + Weight::from_ref_time(91_733_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) fn external_propose() -> Weight { - Weight::from_ref_time(18_898_000 as u64) + // Minimum execution time: 19_483 nanoseconds. + Weight::from_ref_time(19_914_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - Weight::from_ref_time(5_136_000 as u64) + // Minimum execution time: 4_963 nanoseconds. + Weight::from_ref_time(5_250_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - Weight::from_ref_time(5_243_000 as u64) + // Minimum execution time: 5_075 nanoseconds. + Weight::from_ref_time(5_187_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - Weight::from_ref_time(24_275_000 as u64) + // Minimum execution time: 23_956 nanoseconds. + Weight::from_ref_time(24_814_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) fn veto_external() -> Weight { - Weight::from_ref_time(30_988_000 as u64) + // Minimum execution time: 31_472 nanoseconds. + Weight::from_ref_time(31_770_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -355,13 +389,15 @@ impl WeightInfo for () { // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn cancel_proposal() -> Weight { - Weight::from_ref_time(78_515_000 as u64) + // Minimum execution time: 73_811 nanoseconds. + Weight::from_ref_time(78_943_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - Weight::from_ref_time(16_155_000 as u64) + // Minimum execution time: 16_074 nanoseconds. + Weight::from_ref_time(16_409_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy LowestUnbaked (r:1 w:1) @@ -369,9 +405,10 @@ impl WeightInfo for () { // Storage: Democracy ReferendumInfoOf (r:2 w:0) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { - Weight::from_ref_time(7_007_000 as u64) - // Standard Error: 2_686 - .saturating_add(Weight::from_ref_time(2_288_781 as u64).saturating_mul(r as u64)) + // Minimum execution time: 7_430 nanoseconds. + Weight::from_ref_time(12_086_064 as u64) + // Standard Error: 3_474 + .saturating_add(Weight::from_ref_time(2_283_457 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) @@ -384,9 +421,10 @@ impl WeightInfo for () { // Storage: Democracy ReferendumInfoOf (r:2 w:0) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - Weight::from_ref_time(9_528_000 as u64) - // Standard Error: 2_521 - .saturating_add(Weight::from_ref_time(2_291_780 as u64).saturating_mul(r as u64)) + // Minimum execution time: 9_882 nanoseconds. + Weight::from_ref_time(14_566_711 as u64) + // Standard Error: 3_354 + .saturating_add(Weight::from_ref_time(2_282_038 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) @@ -396,9 +434,10 @@ impl WeightInfo for () { // Storage: Democracy ReferendumInfoOf (r:2 w:2) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(46_787_000 as u64) - // Standard Error: 2_943 - .saturating_add(Weight::from_ref_time(3_460_194 as u64).saturating_mul(r as u64)) + // Minimum execution time: 48_840 nanoseconds. + Weight::from_ref_time(56_403_092 as u64) + // Standard Error: 6_093 + .saturating_add(Weight::from_ref_time(3_344_243 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -408,9 +447,10 @@ impl WeightInfo for () { // Storage: Democracy ReferendumInfoOf (r:2 w:2) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(29_789_000 as u64) - // Standard Error: 2_324 - .saturating_add(Weight::from_ref_time(3_360_918 as u64).saturating_mul(r as u64)) + // Minimum execution time: 30_483 nanoseconds. + Weight::from_ref_time(32_035_405 as u64) + // Standard Error: 4_383 + .saturating_add(Weight::from_ref_time(3_347_667 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) @@ -418,7 +458,8 @@ impl WeightInfo for () { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - Weight::from_ref_time(6_519_000 as u64) + // Minimum execution time: 6_421 nanoseconds. + Weight::from_ref_time(6_638_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) @@ -426,9 +467,10 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { - Weight::from_ref_time(28_884_000 as u64) - // Standard Error: 2_631 - .saturating_add(Weight::from_ref_time(163_516 as u64).saturating_mul(r as u64)) + // Minimum execution time: 30_291 nanoseconds. + Weight::from_ref_time(37_071_950 as u64) + // Standard Error: 1_619 + .saturating_add(Weight::from_ref_time(59_302 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -437,9 +479,10 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { - Weight::from_ref_time(33_498_000 as u64) - // Standard Error: 622 - .saturating_add(Weight::from_ref_time(133_421 as u64).saturating_mul(r as u64)) + // Minimum execution time: 34_888 nanoseconds. + Weight::from_ref_time(36_418_789 as u64) + // Standard Error: 906 + .saturating_add(Weight::from_ref_time(109_602 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -447,9 +490,10 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { - Weight::from_ref_time(18_201_000 as u64) - // Standard Error: 1_007 - .saturating_add(Weight::from_ref_time(152_699 as u64).saturating_mul(r as u64)) + // Minimum execution time: 18_739 nanoseconds. + Weight::from_ref_time(21_004_077 as u64) + // Standard Error: 1_075 + .saturating_add(Weight::from_ref_time(116_457 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -457,9 +501,10 @@ impl WeightInfo for () { // Storage: Democracy VotingOf (r:1 w:1) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { - Weight::from_ref_time(18_455_000 as u64) - // Standard Error: 951 - .saturating_add(Weight::from_ref_time(150_907 as u64).saturating_mul(r as u64)) + // Minimum execution time: 18_514 nanoseconds. + Weight::from_ref_time(21_030_667 as u64) + // Standard Error: 1_102 + .saturating_add(Weight::from_ref_time(118_039 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 5e5191242bd77..221fd5837f7b7 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_election_provider_multi_phase //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/election-provider-multi-phase/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -68,45 +71,51 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - Weight::from_ref_time(13_495_000 as u64) + // Minimum execution time: 17_309 nanoseconds. + Weight::from_ref_time(17_646_000 as u64) .saturating_add(T::DbWeight::get().reads(8 as u64)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - Weight::from_ref_time(14_114_000 as u64) + // Minimum execution time: 17_992 nanoseconds. + Weight::from_ref_time(18_426_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - Weight::from_ref_time(13_756_000 as u64) + // Minimum execution time: 17_340 nanoseconds. + Weight::from_ref_time(17_881_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - Weight::from_ref_time(28_467_000 as u64) + // Minimum execution time: 35_571 nanoseconds. + Weight::from_ref_time(35_989_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - Weight::from_ref_time(21_991_000 as u64) + // Minimum execution time: 27_403 nanoseconds. + Weight::from_ref_time(27_879_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - Weight::from_ref_time(3_186_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(202_000 as u64).saturating_mul(v as u64)) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(60_000 as u64).saturating_mul(t as u64)) + /// The range of component `v` is `[1000, 2000]`. + /// The range of component `t` is `[500, 1000]`. + fn create_snapshot_internal(v: u32, _t: u32, ) -> Weight { + // Minimum execution time: 571_900 nanoseconds. + Weight::from_ref_time(589_170_000 as u64) + // Standard Error: 7_123 + .saturating_add(Weight::from_ref_time(384_767 as u64).saturating_mul(v as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -118,12 +127,15 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) + /// The range of component `a` is `[500, 800]`. + /// The range of component `d` is `[200, 400]`. fn elect_queued(a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(137_653_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(640_000 as u64).saturating_mul(a as u64)) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(48_000 as u64).saturating_mul(d as u64)) + // Minimum execution time: 1_296_481 nanoseconds. + Weight::from_ref_time(1_076_121_575 as u64) + // Standard Error: 5_708 + .saturating_add(Weight::from_ref_time(474_995 as u64).saturating_mul(a as u64)) + // Standard Error: 8_556 + .saturating_add(Weight::from_ref_time(39_224 as u64).saturating_mul(d as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(8 as u64)) } @@ -134,7 +146,8 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit() -> Weight { - Weight::from_ref_time(49_313_000 as u64) + // Minimum execution time: 58_716 nanoseconds. + Weight::from_ref_time(59_480_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -145,16 +158,17 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(867_000 as u64).saturating_mul(v as u64)) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(107_000 as u64).saturating_mul(t as u64)) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(6_907_000 as u64).saturating_mul(a as u64)) - // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(1_427_000 as u64).saturating_mul(d as u64)) + /// The range of component `v` is `[1000, 2000]`. + /// The range of component `t` is `[500, 1000]`. + /// The range of component `a` is `[500, 800]`. + /// The range of component `d` is `[200, 400]`. + fn submit_unsigned(v: u32, _t: u32, a: u32, _d: u32, ) -> Weight { + // Minimum execution time: 5_540_737 nanoseconds. + Weight::from_ref_time(5_567_381_000 as u64) + // Standard Error: 18_563 + .saturating_add(Weight::from_ref_time(603_280 as u64).saturating_mul(v as u64)) + // Standard Error: 55_009 + .saturating_add(Weight::from_ref_time(3_164_053 as u64).saturating_mul(a as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -162,16 +176,17 @@ impl WeightInfo for SubstrateWeight { // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(844_000 as u64).saturating_mul(v as u64)) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(t as u64)) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(5_421_000 as u64).saturating_mul(a as u64)) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(1_167_000 as u64).saturating_mul(d as u64)) + /// The range of component `v` is `[1000, 2000]`. + /// The range of component `t` is `[500, 1000]`. + /// The range of component `a` is `[500, 800]`. + /// The range of component `d` is `[200, 400]`. + fn feasibility_check(v: u32, _t: u32, a: u32, _d: u32, ) -> Weight { + // Minimum execution time: 5_021_808 nanoseconds. + Weight::from_ref_time(5_051_856_000 as u64) + // Standard Error: 16_650 + .saturating_add(Weight::from_ref_time(683_344 as u64).saturating_mul(v as u64)) + // Standard Error: 49_342 + .saturating_add(Weight::from_ref_time(2_190_098 as u64).saturating_mul(a as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) } } @@ -187,45 +202,51 @@ impl WeightInfo for () { // Storage: Staking ForceEra (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) fn on_initialize_nothing() -> Weight { - Weight::from_ref_time(13_495_000 as u64) + // Minimum execution time: 17_309 nanoseconds. + Weight::from_ref_time(17_646_000 as u64) .saturating_add(RocksDbWeight::get().reads(8 as u64)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_signed() -> Weight { - Weight::from_ref_time(14_114_000 as u64) + // Minimum execution time: 17_992 nanoseconds. + Weight::from_ref_time(18_426_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: ElectionProviderMultiPhase Round (r:1 w:0) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) fn on_initialize_open_unsigned() -> Weight { - Weight::from_ref_time(13_756_000 as u64) + // Minimum execution time: 17_340 nanoseconds. + Weight::from_ref_time(17_881_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: System Account (r:1 w:1) // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) fn finalize_signed_phase_accept_solution() -> Weight { - Weight::from_ref_time(28_467_000 as u64) + // Minimum execution time: 35_571 nanoseconds. + Weight::from_ref_time(35_989_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: System Account (r:1 w:1) fn finalize_signed_phase_reject_solution() -> Weight { - Weight::from_ref_time(21_991_000 as u64) + // Minimum execution time: 27_403 nanoseconds. + Weight::from_ref_time(27_879_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - fn create_snapshot_internal(v: u32, t: u32, ) -> Weight { - Weight::from_ref_time(3_186_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(202_000 as u64).saturating_mul(v as u64)) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(60_000 as u64).saturating_mul(t as u64)) + /// The range of component `v` is `[1000, 2000]`. + /// The range of component `t` is `[500, 1000]`. + fn create_snapshot_internal(v: u32, _t: u32, ) -> Weight { + // Minimum execution time: 571_900 nanoseconds. + Weight::from_ref_time(589_170_000 as u64) + // Standard Error: 7_123 + .saturating_add(Weight::from_ref_time(384_767 as u64).saturating_mul(v as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -237,12 +258,15 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) + /// The range of component `a` is `[500, 800]`. + /// The range of component `d` is `[200, 400]`. fn elect_queued(a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(137_653_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(640_000 as u64).saturating_mul(a as u64)) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(48_000 as u64).saturating_mul(d as u64)) + // Minimum execution time: 1_296_481 nanoseconds. + Weight::from_ref_time(1_076_121_575 as u64) + // Standard Error: 5_708 + .saturating_add(Weight::from_ref_time(474_995 as u64).saturating_mul(a as u64)) + // Standard Error: 8_556 + .saturating_add(Weight::from_ref_time(39_224 as u64).saturating_mul(d as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(8 as u64)) } @@ -253,7 +277,8 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) fn submit() -> Weight { - Weight::from_ref_time(49_313_000 as u64) + // Minimum execution time: 58_716 nanoseconds. + Weight::from_ref_time(59_480_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -264,16 +289,17 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(867_000 as u64).saturating_mul(v as u64)) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(107_000 as u64).saturating_mul(t as u64)) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(6_907_000 as u64).saturating_mul(a as u64)) - // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(1_427_000 as u64).saturating_mul(d as u64)) + /// The range of component `v` is `[1000, 2000]`. + /// The range of component `t` is `[500, 1000]`. + /// The range of component `a` is `[500, 800]`. + /// The range of component `d` is `[200, 400]`. + fn submit_unsigned(v: u32, _t: u32, a: u32, _d: u32, ) -> Weight { + // Minimum execution time: 5_540_737 nanoseconds. + Weight::from_ref_time(5_567_381_000 as u64) + // Standard Error: 18_563 + .saturating_add(Weight::from_ref_time(603_280 as u64).saturating_mul(v as u64)) + // Standard Error: 55_009 + .saturating_add(Weight::from_ref_time(3_164_053 as u64).saturating_mul(a as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -281,16 +307,17 @@ impl WeightInfo for () { // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(844_000 as u64).saturating_mul(v as u64)) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(t as u64)) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(5_421_000 as u64).saturating_mul(a as u64)) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(1_167_000 as u64).saturating_mul(d as u64)) + /// The range of component `v` is `[1000, 2000]`. + /// The range of component `t` is `[500, 1000]`. + /// The range of component `a` is `[500, 800]`. + /// The range of component `d` is `[200, 400]`. + fn feasibility_check(v: u32, _t: u32, a: u32, _d: u32, ) -> Weight { + // Minimum execution time: 5_021_808 nanoseconds. + Weight::from_ref_time(5_051_856_000 as u64) + // Standard Error: 16_650 + .saturating_add(Weight::from_ref_time(683_344 as u64).saturating_mul(v as u64)) + // Standard Error: 49_342 + .saturating_add(Weight::from_ref_time(2_190_098 as u64).saturating_mul(a as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) } } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 52a5dedc723d4..ddc55b08750d5 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,23 +18,24 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-08-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_elections_phragmen // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --pallet=pallet_elections_phragmen -// --chain=dev // --output=./frame/elections-phragmen/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -70,9 +71,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - Weight::from_ref_time(27_011_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(214_000 as u64).saturating_mul(v as u64)) + // Minimum execution time: 38_496 nanoseconds. + Weight::from_ref_time(39_424_348 as u64) + // Standard Error: 3_547 + .saturating_add(Weight::from_ref_time(119_971 as u64).saturating_mul(v as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -83,9 +85,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - Weight::from_ref_time(40_240_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(244_000 as u64).saturating_mul(v as u64)) + // Minimum execution time: 49_459 nanoseconds. + Weight::from_ref_time(50_225_486 as u64) + // Standard Error: 3_160 + .saturating_add(Weight::from_ref_time(170_360 as u64).saturating_mul(v as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -96,16 +99,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - Weight::from_ref_time(40_394_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(217_000 as u64).saturating_mul(v as u64)) + // Minimum execution time: 48_712 nanoseconds. + Weight::from_ref_time(49_463_298 as u64) + // Standard Error: 2_678 + .saturating_add(Weight::from_ref_time(231_771 as u64).saturating_mul(v as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - Weight::from_ref_time(37_651_000 as u64) + // Minimum execution time: 48_359 nanoseconds. + Weight::from_ref_time(48_767_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -114,18 +119,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections RunnersUp (r:1 w:0) /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - Weight::from_ref_time(42_217_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(50_000 as u64).saturating_mul(c as u64)) + // Minimum execution time: 43_369 nanoseconds. + Weight::from_ref_time(49_587_113 as u64) + // Standard Error: 1_008 + .saturating_add(Weight::from_ref_time(77_752 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Elections Candidates (r:1 w:1) /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - Weight::from_ref_time(46_459_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(26_000 as u64).saturating_mul(c as u64)) + // Minimum execution time: 41_321 nanoseconds. + Weight::from_ref_time(50_803_289 as u64) + // Standard Error: 1_159 + .saturating_add(Weight::from_ref_time(57_239 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -135,18 +142,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - Weight::from_ref_time(45_189_000 as u64) + // Minimum execution time: 53_542 nanoseconds. + Weight::from_ref_time(54_481_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - Weight::from_ref_time(34_516_000 as u64) + // Minimum execution time: 41_825 nanoseconds. + Weight::from_ref_time(42_248_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Benchmark Override (r:0 w:0) fn remove_member_without_replacement() -> Weight { + // Minimum execution time: 2_000_000_000 nanoseconds. Weight::from_ref_time(2_000_000_000_000 as u64) } // Storage: Elections Members (r:1 w:1) @@ -156,7 +166,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - Weight::from_ref_time(51_838_000 as u64) + // Minimum execution time: 62_600 nanoseconds. + Weight::from_ref_time(63_152_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -167,11 +178,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:5000 w:5000) // Storage: System Account (r:5000 w:5000) /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[1, 5000]`. + /// The range of component `d` is `[0, 5000]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 76_000 - .saturating_add(Weight::from_ref_time(63_721_000 as u64).saturating_mul(v as u64)) + // Minimum execution time: 297_149_264 nanoseconds. + Weight::from_ref_time(297_898_499_000 as u64) + // Standard Error: 263_819 + .saturating_add(Weight::from_ref_time(37_914_985 as u64).saturating_mul(v as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(v as u64))) .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(v as u64))) @@ -189,14 +201,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 10000]`. /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 773_000 - .saturating_add(Weight::from_ref_time(81_534_000 as u64).saturating_mul(v as u64)) - // Standard Error: 51_000 - .saturating_add(Weight::from_ref_time(4_453_000 as u64).saturating_mul(e as u64)) + // Minimum execution time: 22_034_317 nanoseconds. + Weight::from_ref_time(22_110_020_000 as u64) + // Standard Error: 235_528 + .saturating_add(Weight::from_ref_time(25_553_585 as u64).saturating_mul(v as u64)) + // Standard Error: 15_114 + .saturating_add(Weight::from_ref_time(1_032_330 as u64).saturating_mul(e as u64)) .saturating_add(T::DbWeight::get().reads(280 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(c as u64))) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + .saturating_add(T::DbWeight::get().writes(6 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(c as u64))) } } @@ -210,9 +224,10 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - Weight::from_ref_time(27_011_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(214_000 as u64).saturating_mul(v as u64)) + // Minimum execution time: 38_496 nanoseconds. + Weight::from_ref_time(39_424_348 as u64) + // Standard Error: 3_547 + .saturating_add(Weight::from_ref_time(119_971 as u64).saturating_mul(v as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -223,9 +238,10 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - Weight::from_ref_time(40_240_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(244_000 as u64).saturating_mul(v as u64)) + // Minimum execution time: 49_459 nanoseconds. + Weight::from_ref_time(50_225_486 as u64) + // Standard Error: 3_160 + .saturating_add(Weight::from_ref_time(170_360 as u64).saturating_mul(v as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -236,16 +252,18 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - Weight::from_ref_time(40_394_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(217_000 as u64).saturating_mul(v as u64)) + // Minimum execution time: 48_712 nanoseconds. + Weight::from_ref_time(49_463_298 as u64) + // Standard Error: 2_678 + .saturating_add(Weight::from_ref_time(231_771 as u64).saturating_mul(v as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Elections Voting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) fn remove_voter() -> Weight { - Weight::from_ref_time(37_651_000 as u64) + // Minimum execution time: 48_359 nanoseconds. + Weight::from_ref_time(48_767_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -254,18 +272,20 @@ impl WeightInfo for () { // Storage: Elections RunnersUp (r:1 w:0) /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - Weight::from_ref_time(42_217_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(50_000 as u64).saturating_mul(c as u64)) + // Minimum execution time: 43_369 nanoseconds. + Weight::from_ref_time(49_587_113 as u64) + // Standard Error: 1_008 + .saturating_add(Weight::from_ref_time(77_752 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Elections Candidates (r:1 w:1) /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - Weight::from_ref_time(46_459_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(26_000 as u64).saturating_mul(c as u64)) + // Minimum execution time: 41_321 nanoseconds. + Weight::from_ref_time(50_803_289 as u64) + // Standard Error: 1_159 + .saturating_add(Weight::from_ref_time(57_239 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -275,18 +295,21 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn renounce_candidacy_members() -> Weight { - Weight::from_ref_time(45_189_000 as u64) + // Minimum execution time: 53_542 nanoseconds. + Weight::from_ref_time(54_481_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Elections RunnersUp (r:1 w:1) fn renounce_candidacy_runners_up() -> Weight { - Weight::from_ref_time(34_516_000 as u64) + // Minimum execution time: 41_825 nanoseconds. + Weight::from_ref_time(42_248_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Benchmark Override (r:0 w:0) fn remove_member_without_replacement() -> Weight { + // Minimum execution time: 2_000_000_000 nanoseconds. Weight::from_ref_time(2_000_000_000_000 as u64) } // Storage: Elections Members (r:1 w:1) @@ -296,7 +319,8 @@ impl WeightInfo for () { // Storage: Council Proposals (r:1 w:0) // Storage: Council Members (r:0 w:1) fn remove_member_with_replacement() -> Weight { - Weight::from_ref_time(51_838_000 as u64) + // Minimum execution time: 62_600 nanoseconds. + Weight::from_ref_time(63_152_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } @@ -307,11 +331,12 @@ impl WeightInfo for () { // Storage: Balances Locks (r:5000 w:5000) // Storage: System Account (r:5000 w:5000) /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[1, 5000]`. + /// The range of component `d` is `[0, 5000]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 76_000 - .saturating_add(Weight::from_ref_time(63_721_000 as u64).saturating_mul(v as u64)) + // Minimum execution time: 297_149_264 nanoseconds. + Weight::from_ref_time(297_898_499_000 as u64) + // Standard Error: 263_819 + .saturating_add(Weight::from_ref_time(37_914_985 as u64).saturating_mul(v as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(v as u64))) .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(v as u64))) @@ -329,14 +354,16 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 10000]`. /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 773_000 - .saturating_add(Weight::from_ref_time(81_534_000 as u64).saturating_mul(v as u64)) - // Standard Error: 51_000 - .saturating_add(Weight::from_ref_time(4_453_000 as u64).saturating_mul(e as u64)) + // Minimum execution time: 22_034_317 nanoseconds. + Weight::from_ref_time(22_110_020_000 as u64) + // Standard Error: 235_528 + .saturating_add(Weight::from_ref_time(25_553_585 as u64).saturating_mul(v as u64)) + // Standard Error: 15_114 + .saturating_add(Weight::from_ref_time(1_032_330 as u64).saturating_mul(e as u64)) .saturating_add(RocksDbWeight::get().reads(280 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(c as u64))) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(c as u64))) } } diff --git a/frame/fast-unstake/src/weights.rs b/frame/fast-unstake/src/weights.rs index 04857d0dcc865..6001250e8c24d 100644 --- a/frame/fast-unstake/src/weights.rs +++ b/frame/fast-unstake/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,23 +18,25 @@ //! Autogenerated weights for pallet_fast_unstake //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-07, STEPS: `10`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `Kians-MacBook-Pro-2.local`, CPU: `` -//! EXECUTION: Some(Native), WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/release/substrate +// ./target/production/substrate // benchmark // pallet -// --steps=10 -// --repeat=1 +// --chain=dev +// --steps=50 +// --repeat=20 // --pallet=pallet_fast_unstake // --extrinsic=* -// --execution=native -// --output -// weight.rs -// --template -// ./.maintain/frame-weight-template.hbs +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/fast-unstake/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -61,25 +63,18 @@ impl WeightInfo for SubstrateWeight { // Storage: FastUnstake Head (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: Staking Bonded (r:2 w:1) - // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:0) - // Storage: System Account (r:3 w:2) - // Storage: Balances Locks (r:2 w:2) - // Storage: NominationPools MinJoinBond (r:1 w:0) - // Storage: NominationPools PoolMembers (r:1 w:1) - // Storage: NominationPools BondedPools (r:1 w:1) - // Storage: NominationPools RewardPools (r:1 w:1) - // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - // Storage: NominationPools MaxPoolMembers (r:1 w:0) - // Storage: NominationPools CounterForPoolMembers (r:1 w:1) - // Storage: BagsList ListNodes (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) fn on_idle_unstake() -> Weight { - Weight::from_ref_time(102_000_000 as u64) - .saturating_add(T::DbWeight::get().reads(25 as u64)) - .saturating_add(T::DbWeight::get().writes(13 as u64)) + // Minimum execution time: 82_426 nanoseconds. + Weight::from_ref_time(83_422_000 as u64) + .saturating_add(T::DbWeight::get().reads(11 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) // Storage: Staking ValidatorCount (r:1 w:0) @@ -91,42 +86,49 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStakers (r:1344 w:0) /// The range of component `x` is `[672, 86016]`. fn on_idle_check(x: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 244_000 - .saturating_add(Weight::from_ref_time(13_913_000 as u64).saturating_mul(x as u64)) - .saturating_add(T::DbWeight::get().reads(585 as u64)) + // Minimum execution time: 13_932_777 nanoseconds. + Weight::from_ref_time(13_996_029_000 as u64) + // Standard Error: 16_878 + .saturating_add(Weight::from_ref_time(18_113_540 as u64).saturating_mul(x as u64)) + .saturating_add(T::DbWeight::get().reads(345 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(x as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) } + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking Nominators (r:1 w:1) // Storage: FastUnstake Queue (r:1 w:1) // Storage: FastUnstake Head (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: FastUnstake CounterForQueue (r:1 w:1) fn register_fast_unstake() -> Weight { - Weight::from_ref_time(57_000_000 as u64) - .saturating_add(T::DbWeight::get().reads(12 as u64)) + // Minimum execution time: 120_190 nanoseconds. + Weight::from_ref_time(121_337_000 as u64) + .saturating_add(T::DbWeight::get().reads(14 as u64)) .saturating_add(T::DbWeight::get().writes(9 as u64)) } + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) // Storage: FastUnstake Queue (r:1 w:1) // Storage: FastUnstake Head (r:1 w:0) // Storage: FastUnstake CounterForQueue (r:1 w:1) fn deregister() -> Weight { - Weight::from_ref_time(15_000_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + // Minimum execution time: 49_897 nanoseconds. + Weight::from_ref_time(50_080_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) fn control() -> Weight { - Weight::from_ref_time(3_000_000 as u64) + // Minimum execution time: 4_814 nanoseconds. + Weight::from_ref_time(4_997_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } } @@ -139,25 +141,18 @@ impl WeightInfo for () { // Storage: FastUnstake Head (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: Staking Bonded (r:2 w:1) - // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:0) - // Storage: System Account (r:3 w:2) - // Storage: Balances Locks (r:2 w:2) - // Storage: NominationPools MinJoinBond (r:1 w:0) - // Storage: NominationPools PoolMembers (r:1 w:1) - // Storage: NominationPools BondedPools (r:1 w:1) - // Storage: NominationPools RewardPools (r:1 w:1) - // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - // Storage: NominationPools MaxPoolMembers (r:1 w:0) - // Storage: NominationPools CounterForPoolMembers (r:1 w:1) - // Storage: BagsList ListNodes (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) fn on_idle_unstake() -> Weight { - Weight::from_ref_time(102_000_000 as u64) - .saturating_add(RocksDbWeight::get().reads(25 as u64)) - .saturating_add(RocksDbWeight::get().writes(13 as u64)) + // Minimum execution time: 82_426 nanoseconds. + Weight::from_ref_time(83_422_000 as u64) + .saturating_add(RocksDbWeight::get().reads(11 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) // Storage: Staking ValidatorCount (r:1 w:0) @@ -169,42 +164,49 @@ impl WeightInfo for () { // Storage: Staking ErasStakers (r:1344 w:0) /// The range of component `x` is `[672, 86016]`. fn on_idle_check(x: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 244_000 - .saturating_add(Weight::from_ref_time(13_913_000 as u64).saturating_mul(x as u64)) - .saturating_add(RocksDbWeight::get().reads(585 as u64)) + // Minimum execution time: 13_932_777 nanoseconds. + Weight::from_ref_time(13_996_029_000 as u64) + // Standard Error: 16_878 + .saturating_add(Weight::from_ref_time(18_113_540 as u64).saturating_mul(x as u64)) + .saturating_add(RocksDbWeight::get().reads(345 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(x as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking Nominators (r:1 w:1) // Storage: FastUnstake Queue (r:1 w:1) // Storage: FastUnstake Head (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: FastUnstake CounterForQueue (r:1 w:1) fn register_fast_unstake() -> Weight { - Weight::from_ref_time(57_000_000 as u64) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) + // Minimum execution time: 120_190 nanoseconds. + Weight::from_ref_time(121_337_000 as u64) + .saturating_add(RocksDbWeight::get().reads(14 as u64)) .saturating_add(RocksDbWeight::get().writes(9 as u64)) } + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) // Storage: FastUnstake Queue (r:1 w:1) // Storage: FastUnstake Head (r:1 w:0) // Storage: FastUnstake CounterForQueue (r:1 w:1) fn deregister() -> Weight { - Weight::from_ref_time(15_000_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + // Minimum execution time: 49_897 nanoseconds. + Weight::from_ref_time(50_080_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) fn control() -> Weight { - Weight::from_ref_time(3_000_000 as u64) + // Minimum execution time: 4_814 nanoseconds. + Weight::from_ref_time(4_997_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/gilt/src/weights.rs b/frame/gilt/src/weights.rs index 15eeb7c5104cd..82b199b1a6663 100644 --- a/frame/gilt/src/weights.rs +++ b/frame/gilt/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_gilt //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/gilt/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -59,67 +62,79 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) + /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { - Weight::from_ref_time(41_605_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(62_000 as u64).saturating_mul(l as u64)) + // Minimum execution time: 42_332 nanoseconds. + Weight::from_ref_time(45_584_514 as u64) + // Standard Error: 129 + .saturating_add(Weight::from_ref_time(45_727 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - Weight::from_ref_time(97_715_000 as u64) + // Minimum execution time: 85_866 nanoseconds. + Weight::from_ref_time(87_171_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) + /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { - Weight::from_ref_time(42_061_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(l as u64)) + // Minimum execution time: 44_605 nanoseconds. + Weight::from_ref_time(46_850_108 as u64) + // Standard Error: 135 + .saturating_add(Weight::from_ref_time(34_178 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - Weight::from_ref_time(5_026_000 as u64) + // Minimum execution time: 7_331 nanoseconds. + Weight::from_ref_time(7_619_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - Weight::from_ref_time(47_753_000 as u64) + // Minimum execution time: 55_143 nanoseconds. + Weight::from_ref_time(55_845_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - Weight::from_ref_time(1_663_000 as u64) + // Minimum execution time: 3_386 nanoseconds. + Weight::from_ref_time(3_461_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt Active (r:0 w:1) + // Storage: Gilt Active (r:0 w:20) + /// The range of component `b` is `[0, 1000]`. fn pursue_target_per_item(b: u32, ) -> Weight { - Weight::from_ref_time(40_797_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(4_122_000 as u64).saturating_mul(b as u64)) + // Minimum execution time: 34_156 nanoseconds. + Weight::from_ref_time(45_262_859 as u64) + // Standard Error: 1_529 + .saturating_add(Weight::from_ref_time(4_181_654 as u64).saturating_mul(b as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(b as u64))) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) - // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt Active (r:0 w:1) + // Storage: Gilt Queues (r:6 w:6) + // Storage: Gilt Active (r:0 w:6) + /// The range of component `q` is `[0, 300]`. fn pursue_target_per_queue(q: u32, ) -> Weight { - Weight::from_ref_time(14_944_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(8_135_000 as u64).saturating_mul(q as u64)) + // Minimum execution time: 33_526 nanoseconds. + Weight::from_ref_time(37_255_562 as u64) + // Standard Error: 3_611 + .saturating_add(Weight::from_ref_time(7_193_128 as u64).saturating_mul(q as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(q as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) @@ -131,67 +146,79 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) + /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { - Weight::from_ref_time(41_605_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(62_000 as u64).saturating_mul(l as u64)) + // Minimum execution time: 42_332 nanoseconds. + Weight::from_ref_time(45_584_514 as u64) + // Standard Error: 129 + .saturating_add(Weight::from_ref_time(45_727 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { - Weight::from_ref_time(97_715_000 as u64) + // Minimum execution time: 85_866 nanoseconds. + Weight::from_ref_time(87_171_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Gilt Queues (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) + /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { - Weight::from_ref_time(42_061_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(l as u64)) + // Minimum execution time: 44_605 nanoseconds. + Weight::from_ref_time(46_850_108 as u64) + // Standard Error: 135 + .saturating_add(Weight::from_ref_time(34_178 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:1) fn set_target() -> Weight { - Weight::from_ref_time(5_026_000 as u64) + // Minimum execution time: 7_331 nanoseconds. + Weight::from_ref_time(7_619_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Gilt Active (r:1 w:1) // Storage: Gilt ActiveTotal (r:1 w:1) fn thaw() -> Weight { - Weight::from_ref_time(47_753_000 as u64) + // Minimum execution time: 55_143 nanoseconds. + Weight::from_ref_time(55_845_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:0) fn pursue_target_noop() -> Weight { - Weight::from_ref_time(1_663_000 as u64) + // Minimum execution time: 3_386 nanoseconds. + Weight::from_ref_time(3_461_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt Active (r:0 w:1) + // Storage: Gilt Active (r:0 w:20) + /// The range of component `b` is `[0, 1000]`. fn pursue_target_per_item(b: u32, ) -> Weight { - Weight::from_ref_time(40_797_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(4_122_000 as u64).saturating_mul(b as u64)) + // Minimum execution time: 34_156 nanoseconds. + Weight::from_ref_time(45_262_859 as u64) + // Standard Error: 1_529 + .saturating_add(Weight::from_ref_time(4_181_654 as u64).saturating_mul(b as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(b as u64))) } // Storage: Gilt ActiveTotal (r:1 w:1) // Storage: Gilt QueueTotals (r:1 w:1) - // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt Active (r:0 w:1) + // Storage: Gilt Queues (r:6 w:6) + // Storage: Gilt Active (r:0 w:6) + /// The range of component `q` is `[0, 300]`. fn pursue_target_per_queue(q: u32, ) -> Weight { - Weight::from_ref_time(14_944_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(8_135_000 as u64).saturating_mul(q as u64)) + // Minimum execution time: 33_526 nanoseconds. + Weight::from_ref_time(37_255_562 as u64) + // Standard Error: 3_611 + .saturating_add(Weight::from_ref_time(7_193_128 as u64).saturating_mul(q as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(q as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index d65499034d74a..1f2e8f98e988b 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,11 +18,12 @@ //! Autogenerated weights for pallet_identity //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-06-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -34,6 +35,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/identity/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -69,32 +71,35 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - Weight::from_ref_time(16_649_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(241_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 20_269 nanoseconds. + Weight::from_ref_time(21_910_543 as u64) + // Standard Error: 4_604 + .saturating_add(Weight::from_ref_time(223_104 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `x` is `[0, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(31_322_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(252_000 as u64).saturating_mul(r as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(312_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 41_872 nanoseconds. + Weight::from_ref_time(40_230_216 as u64) + // Standard Error: 2_342 + .saturating_add(Weight::from_ref_time(145_168 as u64).saturating_mul(r as u64)) + // Standard Error: 457 + .saturating_add(Weight::from_ref_time(291_732 as u64).saturating_mul(x as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity SuperOf (r:1 w:1) - /// The range of component `s` is `[1, 100]`. + // Storage: Identity SuperOf (r:2 w:2) + /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { - Weight::from_ref_time(30_012_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_005_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 12_024 nanoseconds. + Weight::from_ref_time(32_550_819 as u64) + // Standard Error: 5_057 + .saturating_add(Weight::from_ref_time(2_521_245 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -102,12 +107,13 @@ impl WeightInfo for SubstrateWeight { } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity SuperOf (r:0 w:1) - /// The range of component `p` is `[1, 100]`. + // Storage: Identity SuperOf (r:0 w:2) + /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { - Weight::from_ref_time(29_623_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_100_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 12_232 nanoseconds. + Weight::from_ref_time(34_009_761 as u64) + // Standard Error: 5_047 + .saturating_add(Weight::from_ref_time(1_113_100 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(p as u64))) @@ -116,16 +122,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) /// The range of component `r` is `[1, 20]`. - /// The range of component `s` is `[1, 100]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `s` is `[0, 100]`. + /// The range of component `x` is `[0, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - Weight::from_ref_time(34_370_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(186_000 as u64).saturating_mul(r as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_114_000 as u64).saturating_mul(s as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(189_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 57_144 nanoseconds. + Weight::from_ref_time(41_559_247 as u64) + // Standard Error: 9_996 + .saturating_add(Weight::from_ref_time(146_770 as u64).saturating_mul(r as u64)) + // Standard Error: 1_952 + .saturating_add(Weight::from_ref_time(1_086_673 as u64).saturating_mul(s as u64)) + // Standard Error: 1_952 + .saturating_add(Weight::from_ref_time(162_481 as u64).saturating_mul(x as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) @@ -133,65 +140,71 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `x` is `[0, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(34_759_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(251_000 as u64).saturating_mul(r as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(340_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 44_726 nanoseconds. + Weight::from_ref_time(41_637_308 as u64) + // Standard Error: 1_907 + .saturating_add(Weight::from_ref_time(219_078 as u64).saturating_mul(r as u64)) + // Standard Error: 372 + .saturating_add(Weight::from_ref_time(309_888 as u64).saturating_mul(x as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `x` is `[0, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(32_254_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(159_000 as u64).saturating_mul(r as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(347_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 39_719 nanoseconds. + Weight::from_ref_time(38_008_751 as u64) + // Standard Error: 2_394 + .saturating_add(Weight::from_ref_time(181_870 as u64).saturating_mul(r as u64)) + // Standard Error: 467 + .saturating_add(Weight::from_ref_time(314_990 as u64).saturating_mul(x as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - Weight::from_ref_time(7_858_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(190_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 10_634 nanoseconds. + Weight::from_ref_time(11_383_704 as u64) + // Standard Error: 2_250 + .saturating_add(Weight::from_ref_time(193_094 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - Weight::from_ref_time(8_011_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(187_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 10_840 nanoseconds. + Weight::from_ref_time(11_638_740 as u64) + // Standard Error: 1_985 + .saturating_add(Weight::from_ref_time(193_016 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - Weight::from_ref_time(7_970_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(175_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 10_748 nanoseconds. + Weight::from_ref_time(11_346_901 as u64) + // Standard Error: 2_132 + .saturating_add(Weight::from_ref_time(196_630 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 19]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `x` is `[0, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(24_730_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(196_000 as u64).saturating_mul(r as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(341_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 33_682 nanoseconds. + Weight::from_ref_time(31_336_603 as u64) + // Standard Error: 3_056 + .saturating_add(Weight::from_ref_time(200_403 as u64).saturating_mul(r as u64)) + // Standard Error: 565 + .saturating_add(Weight::from_ref_time(525_142 as u64).saturating_mul(x as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -200,16 +213,17 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) /// The range of component `r` is `[1, 20]`. - /// The range of component `s` is `[1, 100]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `s` is `[0, 100]`. + /// The range of component `x` is `[0, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - Weight::from_ref_time(44_988_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(201_000 as u64).saturating_mul(r as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_126_000 as u64).saturating_mul(s as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 68_794 nanoseconds. + Weight::from_ref_time(52_114_486 as u64) + // Standard Error: 4_808 + .saturating_add(Weight::from_ref_time(153_462 as u64).saturating_mul(r as u64)) + // Standard Error: 939 + .saturating_add(Weight::from_ref_time(1_084_612 as u64).saturating_mul(s as u64)) + // Standard Error: 939 + .saturating_add(Weight::from_ref_time(170_112 as u64).saturating_mul(x as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) @@ -217,11 +231,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) - /// The range of component `s` is `[1, 99]`. + /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { - Weight::from_ref_time(36_768_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 37_914 nanoseconds. + Weight::from_ref_time(43_488_083 as u64) + // Standard Error: 1_631 + .saturating_add(Weight::from_ref_time(118_845 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -229,9 +244,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SuperOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - Weight::from_ref_time(13_474_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 16_124 nanoseconds. + Weight::from_ref_time(18_580_462 as u64) + // Standard Error: 688 + .saturating_add(Weight::from_ref_time(67_220 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -240,19 +256,21 @@ impl WeightInfo for SubstrateWeight { // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - Weight::from_ref_time(37_720_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 41_517 nanoseconds. + Weight::from_ref_time(45_123_530 as u64) + // Standard Error: 1_530 + .saturating_add(Weight::from_ref_time(105_429 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) - /// The range of component `s` is `[1, 99]`. + /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { - Weight::from_ref_time(26_848_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 30_171 nanoseconds. + Weight::from_ref_time(33_355_514 as u64) + // Standard Error: 1_286 + .saturating_add(Weight::from_ref_time(114_716 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -263,32 +281,35 @@ impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - Weight::from_ref_time(16_649_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(241_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 20_269 nanoseconds. + Weight::from_ref_time(21_910_543 as u64) + // Standard Error: 4_604 + .saturating_add(Weight::from_ref_time(223_104 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `x` is `[0, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(31_322_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(252_000 as u64).saturating_mul(r as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(312_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 41_872 nanoseconds. + Weight::from_ref_time(40_230_216 as u64) + // Standard Error: 2_342 + .saturating_add(Weight::from_ref_time(145_168 as u64).saturating_mul(r as u64)) + // Standard Error: 457 + .saturating_add(Weight::from_ref_time(291_732 as u64).saturating_mul(x as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity SuperOf (r:1 w:1) - /// The range of component `s` is `[1, 100]`. + // Storage: Identity SuperOf (r:2 w:2) + /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { - Weight::from_ref_time(30_012_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_005_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 12_024 nanoseconds. + Weight::from_ref_time(32_550_819 as u64) + // Standard Error: 5_057 + .saturating_add(Weight::from_ref_time(2_521_245 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) @@ -296,12 +317,13 @@ impl WeightInfo for () { } // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity SuperOf (r:0 w:1) - /// The range of component `p` is `[1, 100]`. + // Storage: Identity SuperOf (r:0 w:2) + /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { - Weight::from_ref_time(29_623_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_100_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 12_232 nanoseconds. + Weight::from_ref_time(34_009_761 as u64) + // Standard Error: 5_047 + .saturating_add(Weight::from_ref_time(1_113_100 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(p as u64))) @@ -310,16 +332,17 @@ impl WeightInfo for () { // Storage: Identity IdentityOf (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) /// The range of component `r` is `[1, 20]`. - /// The range of component `s` is `[1, 100]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `s` is `[0, 100]`. + /// The range of component `x` is `[0, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - Weight::from_ref_time(34_370_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(186_000 as u64).saturating_mul(r as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_114_000 as u64).saturating_mul(s as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(189_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 57_144 nanoseconds. + Weight::from_ref_time(41_559_247 as u64) + // Standard Error: 9_996 + .saturating_add(Weight::from_ref_time(146_770 as u64).saturating_mul(r as u64)) + // Standard Error: 1_952 + .saturating_add(Weight::from_ref_time(1_086_673 as u64).saturating_mul(s as u64)) + // Standard Error: 1_952 + .saturating_add(Weight::from_ref_time(162_481 as u64).saturating_mul(x as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) @@ -327,65 +350,71 @@ impl WeightInfo for () { // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `x` is `[0, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(34_759_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(251_000 as u64).saturating_mul(r as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(340_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 44_726 nanoseconds. + Weight::from_ref_time(41_637_308 as u64) + // Standard Error: 1_907 + .saturating_add(Weight::from_ref_time(219_078 as u64).saturating_mul(r as u64)) + // Standard Error: 372 + .saturating_add(Weight::from_ref_time(309_888 as u64).saturating_mul(x as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `x` is `[0, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(32_254_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(159_000 as u64).saturating_mul(r as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(347_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 39_719 nanoseconds. + Weight::from_ref_time(38_008_751 as u64) + // Standard Error: 2_394 + .saturating_add(Weight::from_ref_time(181_870 as u64).saturating_mul(r as u64)) + // Standard Error: 467 + .saturating_add(Weight::from_ref_time(314_990 as u64).saturating_mul(x as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - Weight::from_ref_time(7_858_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(190_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 10_634 nanoseconds. + Weight::from_ref_time(11_383_704 as u64) + // Standard Error: 2_250 + .saturating_add(Weight::from_ref_time(193_094 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - Weight::from_ref_time(8_011_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(187_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 10_840 nanoseconds. + Weight::from_ref_time(11_638_740 as u64) + // Standard Error: 1_985 + .saturating_add(Weight::from_ref_time(193_016 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:1) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - Weight::from_ref_time(7_970_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(175_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 10_748 nanoseconds. + Weight::from_ref_time(11_346_901 as u64) + // Standard Error: 2_132 + .saturating_add(Weight::from_ref_time(196_630 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Identity Registrars (r:1 w:0) // Storage: Identity IdentityOf (r:1 w:1) /// The range of component `r` is `[1, 19]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `x` is `[0, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - Weight::from_ref_time(24_730_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(196_000 as u64).saturating_mul(r as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(341_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 33_682 nanoseconds. + Weight::from_ref_time(31_336_603 as u64) + // Standard Error: 3_056 + .saturating_add(Weight::from_ref_time(200_403 as u64).saturating_mul(r as u64)) + // Standard Error: 565 + .saturating_add(Weight::from_ref_time(525_142 as u64).saturating_mul(x as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -394,16 +423,17 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Identity SuperOf (r:0 w:100) /// The range of component `r` is `[1, 20]`. - /// The range of component `s` is `[1, 100]`. - /// The range of component `x` is `[1, 100]`. + /// The range of component `s` is `[0, 100]`. + /// The range of component `x` is `[0, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - Weight::from_ref_time(44_988_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(201_000 as u64).saturating_mul(r as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_126_000 as u64).saturating_mul(s as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(x as u64)) + // Minimum execution time: 68_794 nanoseconds. + Weight::from_ref_time(52_114_486 as u64) + // Standard Error: 4_808 + .saturating_add(Weight::from_ref_time(153_462 as u64).saturating_mul(r as u64)) + // Standard Error: 939 + .saturating_add(Weight::from_ref_time(1_084_612 as u64).saturating_mul(s as u64)) + // Standard Error: 939 + .saturating_add(Weight::from_ref_time(170_112 as u64).saturating_mul(x as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) @@ -411,11 +441,12 @@ impl WeightInfo for () { // Storage: Identity IdentityOf (r:1 w:0) // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) - /// The range of component `s` is `[1, 99]`. + /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { - Weight::from_ref_time(36_768_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 37_914 nanoseconds. + Weight::from_ref_time(43_488_083 as u64) + // Standard Error: 1_631 + .saturating_add(Weight::from_ref_time(118_845 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -423,9 +454,10 @@ impl WeightInfo for () { // Storage: Identity SuperOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - Weight::from_ref_time(13_474_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 16_124 nanoseconds. + Weight::from_ref_time(18_580_462 as u64) + // Standard Error: 688 + .saturating_add(Weight::from_ref_time(67_220 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -434,19 +466,21 @@ impl WeightInfo for () { // Storage: Identity SubsOf (r:1 w:1) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - Weight::from_ref_time(37_720_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 41_517 nanoseconds. + Weight::from_ref_time(45_123_530 as u64) + // Standard Error: 1_530 + .saturating_add(Weight::from_ref_time(105_429 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Identity SuperOf (r:1 w:1) // Storage: Identity SubsOf (r:1 w:1) - /// The range of component `s` is `[1, 99]`. + /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { - Weight::from_ref_time(26_848_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 30_171 nanoseconds. + Weight::from_ref_time(33_355_514 as u64) + // Standard Error: 1_286 + .saturating_add(Weight::from_ref_time(114_716 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index 3d20c9a0e614c..f81db997c303d 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_im_online //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/im-online/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,12 +58,15 @@ impl WeightInfo for SubstrateWeight { // Storage: ImOnline ReceivedHeartbeats (r:1 w:1) // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) + /// The range of component `k` is `[1, 1000]`. + /// The range of component `e` is `[1, 100]`. fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - Weight::from_ref_time(79_225_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(41_000 as u64).saturating_mul(k as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(293_000 as u64).saturating_mul(e as u64)) + // Minimum execution time: 101_380 nanoseconds. + Weight::from_ref_time(82_735_670 as u64) + // Standard Error: 121 + .saturating_add(Weight::from_ref_time(21_279 as u64).saturating_mul(k as u64)) + // Standard Error: 1_222 + .saturating_add(Weight::from_ref_time(296_343 as u64).saturating_mul(e as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -73,12 +79,15 @@ impl WeightInfo for () { // Storage: ImOnline ReceivedHeartbeats (r:1 w:1) // Storage: ImOnline AuthoredBlocks (r:1 w:0) // Storage: ImOnline Keys (r:1 w:0) + /// The range of component `k` is `[1, 1000]`. + /// The range of component `e` is `[1, 100]`. fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - Weight::from_ref_time(79_225_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(41_000 as u64).saturating_mul(k as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(293_000 as u64).saturating_mul(e as u64)) + // Minimum execution time: 101_380 nanoseconds. + Weight::from_ref_time(82_735_670 as u64) + // Standard Error: 121 + .saturating_add(Weight::from_ref_time(21_279 as u64).saturating_mul(k as u64)) + // Standard Error: 1_222 + .saturating_add(Weight::from_ref_time(296_343 as u64).saturating_mul(e as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 64bfa744d9b46..7b974875cdf51 100644 --- a/frame/indices/src/weights.rs +++ b/frame/indices/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_indices //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/indices/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,33 +59,38 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - Weight::from_ref_time(25_929_000 as u64) + // Minimum execution time: 31_756 nanoseconds. + Weight::from_ref_time(32_252_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(32_627_000 as u64) + // Minimum execution time: 38_686 nanoseconds. + Weight::from_ref_time(39_402_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - Weight::from_ref_time(26_804_000 as u64) + // Minimum execution time: 33_752 nanoseconds. + Weight::from_ref_time(34_348_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - Weight::from_ref_time(27_390_000 as u64) + // Minimum execution time: 32_739 nanoseconds. + Weight::from_ref_time(33_151_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - Weight::from_ref_time(30_973_000 as u64) + // Minimum execution time: 40_369 nanoseconds. + Weight::from_ref_time(40_982_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -92,33 +100,38 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Indices Accounts (r:1 w:1) fn claim() -> Weight { - Weight::from_ref_time(25_929_000 as u64) + // Minimum execution time: 31_756 nanoseconds. + Weight::from_ref_time(32_252_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(32_627_000 as u64) + // Minimum execution time: 38_686 nanoseconds. + Weight::from_ref_time(39_402_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Indices Accounts (r:1 w:1) fn free() -> Weight { - Weight::from_ref_time(26_804_000 as u64) + // Minimum execution time: 33_752 nanoseconds. + Weight::from_ref_time(34_348_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Indices Accounts (r:1 w:1) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - Weight::from_ref_time(27_390_000 as u64) + // Minimum execution time: 32_739 nanoseconds. + Weight::from_ref_time(33_151_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Indices Accounts (r:1 w:1) fn freeze() -> Weight { - Weight::from_ref_time(30_973_000 as u64) + // Minimum execution time: 40_369 nanoseconds. + Weight::from_ref_time(40_982_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index bae2e8a89c4e5..4ced6a642781a 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_lottery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/lottery/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -63,28 +66,33 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - Weight::from_ref_time(44_706_000 as u64) + // Minimum execution time: 52_451 nanoseconds. + Weight::from_ref_time(52_843_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Lottery CallIndices (r:0 w:1) + /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { - Weight::from_ref_time(12_556_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(295_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 14_389 nanoseconds. + Weight::from_ref_time(15_700_569 as u64) + // Standard Error: 4_677 + .saturating_add(Weight::from_ref_time(296_850 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - Weight::from_ref_time(38_051_000 as u64) + // Minimum execution time: 44_814 nanoseconds. + Weight::from_ref_time(45_611_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - Weight::from_ref_time(6_910_000 as u64) + // Minimum execution time: 10_384 nanoseconds. + Weight::from_ref_time(10_727_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -94,7 +102,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - Weight::from_ref_time(53_732_000 as u64) + // Minimum execution time: 62_720 nanoseconds. + Weight::from_ref_time(63_545_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -105,7 +114,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - Weight::from_ref_time(55_868_000 as u64) + // Minimum execution time: 63_452 nanoseconds. + Weight::from_ref_time(65_010_000 as u64) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -121,28 +131,33 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - Weight::from_ref_time(44_706_000 as u64) + // Minimum execution time: 52_451 nanoseconds. + Weight::from_ref_time(52_843_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Lottery CallIndices (r:0 w:1) + /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { - Weight::from_ref_time(12_556_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(295_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 14_389 nanoseconds. + Weight::from_ref_time(15_700_569 as u64) + // Standard Error: 4_677 + .saturating_add(Weight::from_ref_time(296_850 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - Weight::from_ref_time(38_051_000 as u64) + // Minimum execution time: 44_814 nanoseconds. + Weight::from_ref_time(45_611_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - Weight::from_ref_time(6_910_000 as u64) + // Minimum execution time: 10_384 nanoseconds. + Weight::from_ref_time(10_727_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -152,7 +167,8 @@ impl WeightInfo for () { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - Weight::from_ref_time(53_732_000 as u64) + // Minimum execution time: 62_720 nanoseconds. + Weight::from_ref_time(63_545_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -163,7 +179,8 @@ impl WeightInfo for () { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - Weight::from_ref_time(55_868_000 as u64) + // Minimum execution time: 63_452 nanoseconds. + Weight::from_ref_time(65_010_000 as u64) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 4876b3d13e2e3..11574bc8fa399 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_membership //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/membership/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -60,10 +63,12 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalCommittee Proposals (r:1 w:0) // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[1, 99]`. fn add_member(m: u32, ) -> Weight { - Weight::from_ref_time(15_318_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(51_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 23_796 nanoseconds. + Weight::from_ref_time(24_829_996 as u64) + // Standard Error: 723 + .saturating_add(Weight::from_ref_time(48_467 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -72,10 +77,12 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalMembership Prime (r:1 w:0) // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[2, 100]`. fn remove_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_005_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 27_255 nanoseconds. + Weight::from_ref_time(28_234_490 as u64) + // Standard Error: 833 + .saturating_add(Weight::from_ref_time(34_894 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -84,10 +91,12 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalMembership Prime (r:1 w:0) // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[2, 100]`. fn swap_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_029_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 26_626 nanoseconds. + Weight::from_ref_time(27_989_042 as u64) + // Standard Error: 729 + .saturating_add(Weight::from_ref_time(51_567 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -96,10 +105,12 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalMembership Prime (r:1 w:0) // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[1, 100]`. fn reset_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_105_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 25_412 nanoseconds. + Weight::from_ref_time(27_713_414 as u64) + // Standard Error: 883 + .saturating_add(Weight::from_ref_time(157_085 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -108,29 +119,35 @@ impl WeightInfo for SubstrateWeight { // Storage: TechnicalMembership Prime (r:1 w:1) // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[1, 100]`. fn change_key(m: u32, ) -> Weight { - Weight::from_ref_time(18_852_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 27_122 nanoseconds. + Weight::from_ref_time(28_477_394 as u64) + // Standard Error: 801 + .saturating_add(Weight::from_ref_time(56_383 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: TechnicalMembership Members (r:1 w:0) // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[1, 100]`. fn set_prime(m: u32, ) -> Weight { - Weight::from_ref_time(4_869_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(28_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 9_368 nanoseconds. + Weight::from_ref_time(10_133_132 as u64) + // Standard Error: 366 + .saturating_add(Weight::from_ref_time(17_708 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[1, 100]`. fn clear_prime(m: u32, ) -> Weight { - Weight::from_ref_time(1_593_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 5_546 nanoseconds. + Weight::from_ref_time(5_962_740 as u64) + // Standard Error: 186 + .saturating_add(Weight::from_ref_time(2_096 as u64).saturating_mul(m as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } } @@ -141,10 +158,12 @@ impl WeightInfo for () { // Storage: TechnicalCommittee Proposals (r:1 w:0) // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[1, 99]`. fn add_member(m: u32, ) -> Weight { - Weight::from_ref_time(15_318_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(51_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 23_796 nanoseconds. + Weight::from_ref_time(24_829_996 as u64) + // Standard Error: 723 + .saturating_add(Weight::from_ref_time(48_467 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -153,10 +172,12 @@ impl WeightInfo for () { // Storage: TechnicalMembership Prime (r:1 w:0) // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[2, 100]`. fn remove_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_005_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 27_255 nanoseconds. + Weight::from_ref_time(28_234_490 as u64) + // Standard Error: 833 + .saturating_add(Weight::from_ref_time(34_894 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -165,10 +186,12 @@ impl WeightInfo for () { // Storage: TechnicalMembership Prime (r:1 w:0) // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[2, 100]`. fn swap_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_029_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 26_626 nanoseconds. + Weight::from_ref_time(27_989_042 as u64) + // Standard Error: 729 + .saturating_add(Weight::from_ref_time(51_567 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -177,10 +200,12 @@ impl WeightInfo for () { // Storage: TechnicalMembership Prime (r:1 w:0) // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[1, 100]`. fn reset_member(m: u32, ) -> Weight { - Weight::from_ref_time(18_105_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 25_412 nanoseconds. + Weight::from_ref_time(27_713_414 as u64) + // Standard Error: 883 + .saturating_add(Weight::from_ref_time(157_085 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -189,29 +214,35 @@ impl WeightInfo for () { // Storage: TechnicalMembership Prime (r:1 w:1) // Storage: TechnicalCommittee Members (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[1, 100]`. fn change_key(m: u32, ) -> Weight { - Weight::from_ref_time(18_852_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 27_122 nanoseconds. + Weight::from_ref_time(28_477_394 as u64) + // Standard Error: 801 + .saturating_add(Weight::from_ref_time(56_383 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: TechnicalMembership Members (r:1 w:0) // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[1, 100]`. fn set_prime(m: u32, ) -> Weight { - Weight::from_ref_time(4_869_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(28_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 9_368 nanoseconds. + Weight::from_ref_time(10_133_132 as u64) + // Standard Error: 366 + .saturating_add(Weight::from_ref_time(17_708 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: TechnicalMembership Prime (r:0 w:1) // Storage: TechnicalCommittee Prime (r:0 w:1) + /// The range of component `m` is `[1, 100]`. fn clear_prime(m: u32, ) -> Weight { - Weight::from_ref_time(1_593_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(m as u64)) + // Minimum execution time: 5_546 nanoseconds. + Weight::from_ref_time(5_962_740 as u64) + // Standard Error: 186 + .saturating_add(Weight::from_ref_time(2_096 as u64).saturating_mul(m as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index de403b4d249e4..1f435cb9f9087 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -18,25 +18,24 @@ //! Autogenerated weights for pallet_multisig //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-10-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_multisig // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_multisig -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/multisig/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -62,22 +61,22 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `z` is `[0, 10000]`. fn as_multi_threshold_1(z: u32, ) -> Weight { - // Minimum execution time: 20_283 nanoseconds. - Weight::from_ref_time(20_861_089 as u64) - // Standard Error: 5 - .saturating_add(Weight::from_ref_time(583 as u64).saturating_mul(z as u64)) + // Minimum execution time: 20_447 nanoseconds. + Weight::from_ref_time(20_896_236 as u64) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(568 as u64).saturating_mul(z as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 52_699 nanoseconds. - Weight::from_ref_time(40_874_603 as u64) - // Standard Error: 546 - .saturating_add(Weight::from_ref_time(131_727 as u64).saturating_mul(s as u64)) + // Minimum execution time: 54_987 nanoseconds. + Weight::from_ref_time(42_525_077 as u64) + // Standard Error: 562 + .saturating_add(Weight::from_ref_time(136_064 as u64).saturating_mul(s as u64)) // Standard Error: 5 - .saturating_add(Weight::from_ref_time(1_537 as u64).saturating_mul(z as u64)) + .saturating_add(Weight::from_ref_time(1_508 as u64).saturating_mul(z as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -85,12 +84,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 39_843 nanoseconds. - Weight::from_ref_time(28_912_325 as u64) - // Standard Error: 734 - .saturating_add(Weight::from_ref_time(125_761 as u64).saturating_mul(s as u64)) - // Standard Error: 7 - .saturating_add(Weight::from_ref_time(1_542 as u64).saturating_mul(z as u64)) + // Minimum execution time: 42_573 nanoseconds. + Weight::from_ref_time(30_585_734 as u64) + // Standard Error: 637 + .saturating_add(Weight::from_ref_time(128_012 as u64).saturating_mul(s as u64)) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(1_507 as u64).saturating_mul(z as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -99,12 +98,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 54_980 nanoseconds. - Weight::from_ref_time(42_087_213 as u64) - // Standard Error: 786 - .saturating_add(Weight::from_ref_time(153_935 as u64).saturating_mul(s as u64)) - // Standard Error: 7 - .saturating_add(Weight::from_ref_time(1_545 as u64).saturating_mul(z as u64)) + // Minimum execution time: 57_143 nanoseconds. + Weight::from_ref_time(43_921_674 as u64) + // Standard Error: 704 + .saturating_add(Weight::from_ref_time(153_474 as u64).saturating_mul(s as u64)) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(1_536 as u64).saturating_mul(z as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -112,30 +111,30 @@ impl WeightInfo for SubstrateWeight { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { - // Minimum execution time: 37_802 nanoseconds. - Weight::from_ref_time(39_933_623 as u64) - // Standard Error: 1_059 - .saturating_add(Weight::from_ref_time(121_891 as u64).saturating_mul(s as u64)) + // Minimum execution time: 39_088 nanoseconds. + Weight::from_ref_time(41_258_697 as u64) + // Standard Error: 1_038 + .saturating_add(Weight::from_ref_time(126_040 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { - // Minimum execution time: 25_738 nanoseconds. - Weight::from_ref_time(27_676_766 as u64) - // Standard Error: 710 - .saturating_add(Weight::from_ref_time(125_733 as u64).saturating_mul(s as u64)) + // Minimum execution time: 26_872 nanoseconds. + Weight::from_ref_time(28_625_218 as u64) + // Standard Error: 793 + .saturating_add(Weight::from_ref_time(128_542 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { - // Minimum execution time: 36_591 nanoseconds. - Weight::from_ref_time(38_707_543 as u64) - // Standard Error: 881 - .saturating_add(Weight::from_ref_time(126_198 as u64).saturating_mul(s as u64)) + // Minimum execution time: 37_636 nanoseconds. + Weight::from_ref_time(39_614_705 as u64) + // Standard Error: 850 + .saturating_add(Weight::from_ref_time(136_222 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -145,22 +144,22 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// The range of component `z` is `[0, 10000]`. fn as_multi_threshold_1(z: u32, ) -> Weight { - // Minimum execution time: 20_283 nanoseconds. - Weight::from_ref_time(20_861_089 as u64) - // Standard Error: 5 - .saturating_add(Weight::from_ref_time(583 as u64).saturating_mul(z as u64)) + // Minimum execution time: 20_447 nanoseconds. + Weight::from_ref_time(20_896_236 as u64) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(568 as u64).saturating_mul(z as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 52_699 nanoseconds. - Weight::from_ref_time(40_874_603 as u64) - // Standard Error: 546 - .saturating_add(Weight::from_ref_time(131_727 as u64).saturating_mul(s as u64)) + // Minimum execution time: 54_987 nanoseconds. + Weight::from_ref_time(42_525_077 as u64) + // Standard Error: 562 + .saturating_add(Weight::from_ref_time(136_064 as u64).saturating_mul(s as u64)) // Standard Error: 5 - .saturating_add(Weight::from_ref_time(1_537 as u64).saturating_mul(z as u64)) + .saturating_add(Weight::from_ref_time(1_508 as u64).saturating_mul(z as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -168,12 +167,12 @@ impl WeightInfo for () { /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 39_843 nanoseconds. - Weight::from_ref_time(28_912_325 as u64) - // Standard Error: 734 - .saturating_add(Weight::from_ref_time(125_761 as u64).saturating_mul(s as u64)) - // Standard Error: 7 - .saturating_add(Weight::from_ref_time(1_542 as u64).saturating_mul(z as u64)) + // Minimum execution time: 42_573 nanoseconds. + Weight::from_ref_time(30_585_734 as u64) + // Standard Error: 637 + .saturating_add(Weight::from_ref_time(128_012 as u64).saturating_mul(s as u64)) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(1_507 as u64).saturating_mul(z as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -182,12 +181,12 @@ impl WeightInfo for () { /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 54_980 nanoseconds. - Weight::from_ref_time(42_087_213 as u64) - // Standard Error: 786 - .saturating_add(Weight::from_ref_time(153_935 as u64).saturating_mul(s as u64)) - // Standard Error: 7 - .saturating_add(Weight::from_ref_time(1_545 as u64).saturating_mul(z as u64)) + // Minimum execution time: 57_143 nanoseconds. + Weight::from_ref_time(43_921_674 as u64) + // Standard Error: 704 + .saturating_add(Weight::from_ref_time(153_474 as u64).saturating_mul(s as u64)) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(1_536 as u64).saturating_mul(z as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -195,30 +194,30 @@ impl WeightInfo for () { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { - // Minimum execution time: 37_802 nanoseconds. - Weight::from_ref_time(39_933_623 as u64) - // Standard Error: 1_059 - .saturating_add(Weight::from_ref_time(121_891 as u64).saturating_mul(s as u64)) + // Minimum execution time: 39_088 nanoseconds. + Weight::from_ref_time(41_258_697 as u64) + // Standard Error: 1_038 + .saturating_add(Weight::from_ref_time(126_040 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { - // Minimum execution time: 25_738 nanoseconds. - Weight::from_ref_time(27_676_766 as u64) - // Standard Error: 710 - .saturating_add(Weight::from_ref_time(125_733 as u64).saturating_mul(s as u64)) + // Minimum execution time: 26_872 nanoseconds. + Weight::from_ref_time(28_625_218 as u64) + // Standard Error: 793 + .saturating_add(Weight::from_ref_time(128_542 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { - // Minimum execution time: 36_591 nanoseconds. - Weight::from_ref_time(38_707_543 as u64) - // Standard Error: 881 - .saturating_add(Weight::from_ref_time(126_198 as u64).saturating_mul(s as u64)) + // Minimum execution time: 37_636 nanoseconds. + Weight::from_ref_time(39_614_705 as u64) + // Standard Error: 850 + .saturating_add(Weight::from_ref_time(136_222 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index e20394ca668b9..1062b1749d417 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,12 +18,12 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-06-15, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,6 +35,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/nomination-pools/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -69,18 +70,19 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools MinJoinBond (r:1 w:0) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:2 w:1) // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) // Storage: NominationPools MaxPoolMembers (r:1 w:0) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) - // Storage: Staking Bonded (r:1 w:0) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn join() -> Weight { - Weight::from_ref_time(123_947_000 as u64) + // Minimum execution time: 159_948 nanoseconds. + Weight::from_ref_time(161_133_000 as u64) .saturating_add(T::DbWeight::get().reads(17 as u64)) .saturating_add(T::DbWeight::get().writes(12 as u64)) } @@ -88,13 +90,14 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:3 w:2) - // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - Weight::from_ref_time(118_236_000 as u64) + // Minimum execution time: 155_517 nanoseconds. + Weight::from_ref_time(159_101_000 as u64) .saturating_add(T::DbWeight::get().reads(14 as u64)) .saturating_add(T::DbWeight::get().writes(12 as u64)) } @@ -102,13 +105,14 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:3 w:3) - // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - Weight::from_ref_time(132_475_000 as u64) + // Minimum execution time: 172_788 nanoseconds. + Weight::from_ref_time(174_212_000 as u64) .saturating_add(T::DbWeight::get().reads(14 as u64)) .saturating_add(T::DbWeight::get().writes(13 as u64)) } @@ -117,63 +121,69 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - Weight::from_ref_time(50_299_000 as u64) + // Minimum execution time: 64_560 nanoseconds. + Weight::from_ref_time(64_950_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) // Storage: System Account (r:2 w:1) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Nominators (r:1 w:0) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - Weight::from_ref_time(121_254_000 as u64) + // Minimum execution time: 161_398 nanoseconds. + Weight::from_ref_time(162_991_000 as u64) .saturating_add(T::DbWeight::get().reads(18 as u64)) .saturating_add(T::DbWeight::get().writes(13 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - Weight::from_ref_time(41_928_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + // Minimum execution time: 66_036 nanoseconds. + Weight::from_ref_time(67_183_304 as u64) + // Standard Error: 565 + .saturating_add(Weight::from_ref_time(57_830 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools SubPoolsStorage (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(81_611_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) + // Minimum execution time: 111_156 nanoseconds. + Weight::from_ref_time(112_507_059 as u64) + // Standard Error: 655 + .saturating_add(Weight::from_ref_time(53_711 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(9 as u64)) .saturating_add(T::DbWeight::get().writes(7 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools SubPoolsStorage (r:1 w:1) - // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:0) @@ -185,29 +195,32 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: NominationPools CounterForRewardPools (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) + // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - Weight::from_ref_time(139_849_000 as u64) - .saturating_add(T::DbWeight::get().reads(19 as u64)) - .saturating_add(T::DbWeight::get().writes(16 as u64)) + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + // Minimum execution time: 168_270 nanoseconds. + Weight::from_ref_time(170_059_380 as u64) + // Standard Error: 1_506 + .saturating_add(Weight::from_ref_time(1_258 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(20 as u64)) + .saturating_add(T::DbWeight::get().writes(17 as u64)) } + // Storage: NominationPools LastPoolId (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: NominationPools MinCreateBond (r:1 w:0) // Storage: NominationPools MinJoinBond (r:1 w:0) // Storage: NominationPools MaxPools (r:1 w:0) // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) - // Storage: NominationPools LastPoolId (r:1 w:1) // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) // Storage: NominationPools MaxPoolMembers (r:1 w:0) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) // Storage: System Account (r:2 w:2) - // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: NominationPools CounterForRewardPools (r:1 w:1) @@ -216,36 +229,40 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(126_246_000 as u64) - .saturating_add(T::DbWeight::get().reads(22 as u64)) + // Minimum execution time: 146_153 nanoseconds. + Weight::from_ref_time(146_955_000 as u64) + .saturating_add(T::DbWeight::get().reads(21 as u64)) .saturating_add(T::DbWeight::get().writes(15 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking MaxNominatorsCount (r:1 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(48_829_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(2_204_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 71_380 nanoseconds. + Weight::from_ref_time(71_060_388 as u64) + // Standard Error: 2_587 + .saturating_add(Weight::from_ref_time(1_185_729 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(12 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - Weight::from_ref_time(26_761_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) + // Minimum execution time: 46_275 nanoseconds. + Weight::from_ref_time(46_689_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) @@ -253,9 +270,10 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools CounterForMetadata (r:1 w:1) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - Weight::from_ref_time(14_519_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 19_246 nanoseconds. + Weight::from_ref_time(20_415_018 as u64) + // Standard Error: 95 + .saturating_add(Weight::from_ref_time(2_040 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -265,26 +283,30 @@ impl WeightInfo for SubstrateWeight { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - Weight::from_ref_time(6_173_000 as u64) + // Minimum execution time: 9_231 nanoseconds. + Weight::from_ref_time(9_526_000 as u64) .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - Weight::from_ref_time(22_261_000 as u64) + // Minimum execution time: 31_246 nanoseconds. + Weight::from_ref_time(31_762_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(47_959_000 as u64) - .saturating_add(T::DbWeight::get().reads(8 as u64)) + // Minimum execution time: 73_812 nanoseconds. + Weight::from_ref_time(74_790_000 as u64) + .saturating_add(T::DbWeight::get().reads(9 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } } @@ -294,18 +316,19 @@ impl WeightInfo for () { // Storage: NominationPools MinJoinBond (r:1 w:0) // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:2 w:1) // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) // Storage: NominationPools MaxPoolMembers (r:1 w:0) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) - // Storage: Staking Bonded (r:1 w:0) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn join() -> Weight { - Weight::from_ref_time(123_947_000 as u64) + // Minimum execution time: 159_948 nanoseconds. + Weight::from_ref_time(161_133_000 as u64) .saturating_add(RocksDbWeight::get().reads(17 as u64)) .saturating_add(RocksDbWeight::get().writes(12 as u64)) } @@ -313,13 +336,14 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:3 w:2) - // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn bond_extra_transfer() -> Weight { - Weight::from_ref_time(118_236_000 as u64) + // Minimum execution time: 155_517 nanoseconds. + Weight::from_ref_time(159_101_000 as u64) .saturating_add(RocksDbWeight::get().reads(14 as u64)) .saturating_add(RocksDbWeight::get().writes(12 as u64)) } @@ -327,13 +351,14 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:3 w:3) - // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn bond_extra_reward() -> Weight { - Weight::from_ref_time(132_475_000 as u64) + // Minimum execution time: 172_788 nanoseconds. + Weight::from_ref_time(174_212_000 as u64) .saturating_add(RocksDbWeight::get().reads(14 as u64)) .saturating_add(RocksDbWeight::get().writes(13 as u64)) } @@ -342,63 +367,69 @@ impl WeightInfo for () { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: System Account (r:1 w:1) fn claim_payout() -> Weight { - Weight::from_ref_time(50_299_000 as u64) + // Minimum execution time: 64_560 nanoseconds. + Weight::from_ref_time(64_950_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) // Storage: System Account (r:2 w:1) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Nominators (r:1 w:0) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) // Storage: NominationPools SubPoolsStorage (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) fn unbond() -> Weight { - Weight::from_ref_time(121_254_000 as u64) + // Minimum execution time: 161_398 nanoseconds. + Weight::from_ref_time(162_991_000 as u64) .saturating_add(RocksDbWeight::get().reads(18 as u64)) .saturating_add(RocksDbWeight::get().writes(13 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - Weight::from_ref_time(41_928_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + // Minimum execution time: 66_036 nanoseconds. + Weight::from_ref_time(67_183_304 as u64) + // Standard Error: 565 + .saturating_add(Weight::from_ref_time(57_830 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools SubPoolsStorage (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(81_611_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) + // Minimum execution time: 111_156 nanoseconds. + Weight::from_ref_time(112_507_059 as u64) + // Standard Error: 655 + .saturating_add(Weight::from_ref_time(53_711 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(9 as u64)) .saturating_add(RocksDbWeight::get().writes(7 as u64)) } // Storage: NominationPools PoolMembers (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) // Storage: NominationPools BondedPools (r:1 w:1) // Storage: NominationPools SubPoolsStorage (r:1 w:1) - // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:0) @@ -410,29 +441,32 @@ impl WeightInfo for () { // Storage: NominationPools RewardPools (r:1 w:1) // Storage: NominationPools CounterForRewardPools (r:1 w:1) // Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) + // Storage: NominationPools Metadata (r:1 w:1) // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - Weight::from_ref_time(139_849_000 as u64) - .saturating_add(RocksDbWeight::get().reads(19 as u64)) - .saturating_add(RocksDbWeight::get().writes(16 as u64)) + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + // Minimum execution time: 168_270 nanoseconds. + Weight::from_ref_time(170_059_380 as u64) + // Standard Error: 1_506 + .saturating_add(Weight::from_ref_time(1_258 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(20 as u64)) + .saturating_add(RocksDbWeight::get().writes(17 as u64)) } + // Storage: NominationPools LastPoolId (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: NominationPools MinCreateBond (r:1 w:0) // Storage: NominationPools MinJoinBond (r:1 w:0) // Storage: NominationPools MaxPools (r:1 w:0) // Storage: NominationPools CounterForBondedPools (r:1 w:1) // Storage: NominationPools PoolMembers (r:1 w:1) - // Storage: NominationPools LastPoolId (r:1 w:1) // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) // Storage: NominationPools MaxPoolMembers (r:1 w:0) // Storage: NominationPools CounterForPoolMembers (r:1 w:1) // Storage: System Account (r:2 w:2) - // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: NominationPools RewardPools (r:1 w:1) // Storage: NominationPools CounterForRewardPools (r:1 w:1) @@ -441,36 +475,40 @@ impl WeightInfo for () { // Storage: NominationPools BondedPools (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(126_246_000 as u64) - .saturating_add(RocksDbWeight::get().reads(22 as u64)) + // Minimum execution time: 146_153 nanoseconds. + Weight::from_ref_time(146_955_000 as u64) + .saturating_add(RocksDbWeight::get().reads(21 as u64)) .saturating_add(RocksDbWeight::get().writes(15 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking MaxNominatorsCount (r:1 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(48_829_000 as u64) - // Standard Error: 10_000 - .saturating_add(Weight::from_ref_time(2_204_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 71_380 nanoseconds. + Weight::from_ref_time(71_060_388 as u64) + // Standard Error: 2_587 + .saturating_add(Weight::from_ref_time(1_185_729 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(12 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) fn set_state() -> Weight { - Weight::from_ref_time(26_761_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) + // Minimum execution time: 46_275 nanoseconds. + Weight::from_ref_time(46_689_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) @@ -478,9 +516,10 @@ impl WeightInfo for () { // Storage: NominationPools CounterForMetadata (r:1 w:1) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - Weight::from_ref_time(14_519_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 19_246 nanoseconds. + Weight::from_ref_time(20_415_018 as u64) + // Standard Error: 95 + .saturating_add(Weight::from_ref_time(2_040 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -490,26 +529,30 @@ impl WeightInfo for () { // Storage: NominationPools MinCreateBond (r:0 w:1) // Storage: NominationPools MaxPools (r:0 w:1) fn set_configs() -> Weight { - Weight::from_ref_time(6_173_000 as u64) + // Minimum execution time: 9_231 nanoseconds. + Weight::from_ref_time(9_526_000 as u64) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: NominationPools BondedPools (r:1 w:1) fn update_roles() -> Weight { - Weight::from_ref_time(22_261_000 as u64) + // Minimum execution time: 31_246 nanoseconds. + Weight::from_ref_time(31_762_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: NominationPools BondedPools (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(47_959_000 as u64) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) + // Minimum execution time: 73_812 nanoseconds. + Weight::from_ref_time(74_790_000 as u64) + .saturating_add(RocksDbWeight::get().reads(9 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } } diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 186c41b798c6b..e73c986891ccd 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,23 +18,24 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_preimage // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --pallet=pallet_preimage -// --chain=dev // --output=./frame/preimage/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -67,9 +68,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:0 w:1) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(32_591_000 as u64) + // Minimum execution time: 33_810 nanoseconds. + Weight::from_ref_time(34_299_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_703 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -77,9 +79,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:0 w:1) /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(23_350_000 as u64) + // Minimum execution time: 24_398 nanoseconds. + Weight::from_ref_time(24_839_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_681 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_702 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -87,66 +90,76 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:0 w:1) /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(21_436_000 as u64) + // Minimum execution time: 22_235 nanoseconds. + Weight::from_ref_time(22_473_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_703 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - Weight::from_ref_time(44_567_000 as u64) + // Minimum execution time: 43_241 nanoseconds. + Weight::from_ref_time(44_470_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - Weight::from_ref_time(30_065_000 as u64) + // Minimum execution time: 29_529 nanoseconds. + Weight::from_ref_time(30_364_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - Weight::from_ref_time(28_470_000 as u64) + // Minimum execution time: 28_914 nanoseconds. + Weight::from_ref_time(30_103_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - Weight::from_ref_time(14_601_000 as u64) + // Minimum execution time: 14_479 nanoseconds. + Weight::from_ref_time(15_244_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - Weight::from_ref_time(20_121_000 as u64) + // Minimum execution time: 20_171 nanoseconds. + Weight::from_ref_time(20_806_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - Weight::from_ref_time(9_440_000 as u64) + // Minimum execution time: 9_756 nanoseconds. + Weight::from_ref_time(10_115_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - Weight::from_ref_time(29_013_000 as u64) + // Minimum execution time: 28_379 nanoseconds. + Weight::from_ref_time(29_778_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_unnoted_preimage() -> Weight { - Weight::from_ref_time(9_223_000 as u64) + // Minimum execution time: 9_595 nanoseconds. + Weight::from_ref_time(9_888_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - Weight::from_ref_time(9_252_000 as u64) + // Minimum execution time: 9_642 nanoseconds. + Weight::from_ref_time(9_985_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -158,9 +171,10 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:0 w:1) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(32_591_000 as u64) + // Minimum execution time: 33_810 nanoseconds. + Weight::from_ref_time(34_299_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_703 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -168,9 +182,10 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:0 w:1) /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(23_350_000 as u64) + // Minimum execution time: 24_398 nanoseconds. + Weight::from_ref_time(24_839_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_681 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_702 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -178,66 +193,76 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:0 w:1) /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(21_436_000 as u64) + // Minimum execution time: 22_235 nanoseconds. + Weight::from_ref_time(22_473_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(Weight::from_ref_time(1_703 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - Weight::from_ref_time(44_567_000 as u64) + // Minimum execution time: 43_241 nanoseconds. + Weight::from_ref_time(44_470_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - Weight::from_ref_time(30_065_000 as u64) + // Minimum execution time: 29_529 nanoseconds. + Weight::from_ref_time(30_364_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - Weight::from_ref_time(28_470_000 as u64) + // Minimum execution time: 28_914 nanoseconds. + Weight::from_ref_time(30_103_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - Weight::from_ref_time(14_601_000 as u64) + // Minimum execution time: 14_479 nanoseconds. + Weight::from_ref_time(15_244_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - Weight::from_ref_time(20_121_000 as u64) + // Minimum execution time: 20_171 nanoseconds. + Weight::from_ref_time(20_806_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - Weight::from_ref_time(9_440_000 as u64) + // Minimum execution time: 9_756 nanoseconds. + Weight::from_ref_time(10_115_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - Weight::from_ref_time(29_013_000 as u64) + // Minimum execution time: 28_379 nanoseconds. + Weight::from_ref_time(29_778_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_unnoted_preimage() -> Weight { - Weight::from_ref_time(9_223_000 as u64) + // Minimum execution time: 9_595 nanoseconds. + Weight::from_ref_time(9_888_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - Weight::from_ref_time(9_252_000 as u64) + // Minimum execution time: 9_642 nanoseconds. + Weight::from_ref_time(9_985_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 25457d52f4391..706810d3402ec 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_proxy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/proxy/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -60,96 +63,120 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Proxy Proxies (r:1 w:0) + /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { - Weight::from_ref_time(17_768_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(76_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 24_285 nanoseconds. + Weight::from_ref_time(25_355_667 as u64) + // Standard Error: 1_468 + .saturating_add(Weight::from_ref_time(38_185 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(35_682_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(a as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 44_948 nanoseconds. + Weight::from_ref_time(44_762_064 as u64) + // Standard Error: 1_778 + .saturating_add(Weight::from_ref_time(118_940 as u64).saturating_mul(a as u64)) + // Standard Error: 1_837 + .saturating_add(Weight::from_ref_time(51_232 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(25_586_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(175_000 as u64).saturating_mul(a as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(18_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 31_274 nanoseconds. + Weight::from_ref_time(32_219_165 as u64) + // Standard Error: 1_832 + .saturating_add(Weight::from_ref_time(132_454 as u64).saturating_mul(a as u64)) + // Standard Error: 1_893 + .saturating_add(Weight::from_ref_time(9_077 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(25_794_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as u64).saturating_mul(a as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(13_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 31_219 nanoseconds. + Weight::from_ref_time(32_439_563 as u64) + // Standard Error: 1_829 + .saturating_add(Weight::from_ref_time(120_251 as u64).saturating_mul(a as u64)) + // Standard Error: 1_890 + .saturating_add(Weight::from_ref_time(8_689 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_002_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(163_000 as u64).saturating_mul(a as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(79_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 40_388 nanoseconds. + Weight::from_ref_time(40_718_245 as u64) + // Standard Error: 1_821 + .saturating_add(Weight::from_ref_time(129_674 as u64).saturating_mul(a as u64)) + // Standard Error: 1_882 + .saturating_add(Weight::from_ref_time(56_001 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Proxy Proxies (r:1 w:1) + /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { - Weight::from_ref_time(28_166_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(105_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 33_997 nanoseconds. + Weight::from_ref_time(34_840_036 as u64) + // Standard Error: 1_659 + .saturating_add(Weight::from_ref_time(71_349 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) + /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { - Weight::from_ref_time(28_128_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(118_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 33_900 nanoseconds. + Weight::from_ref_time(35_069_110 as u64) + // Standard Error: 1_848 + .saturating_add(Weight::from_ref_time(82_380 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) + /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { - Weight::from_ref_time(24_066_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(81_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 29_627 nanoseconds. + Weight::from_ref_time(30_641_642 as u64) + // Standard Error: 1_495 + .saturating_add(Weight::from_ref_time(51_919 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) + /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { - Weight::from_ref_time(31_077_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 37_761 nanoseconds. + Weight::from_ref_time(38_748_697 as u64) + // Standard Error: 1_594 + .saturating_add(Weight::from_ref_time(19_022 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) + /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { - Weight::from_ref_time(24_657_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 31_145 nanoseconds. + Weight::from_ref_time(31_933_568 as u64) + // Standard Error: 1_492 + .saturating_add(Weight::from_ref_time(50_250 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -158,96 +185,120 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { // Storage: Proxy Proxies (r:1 w:0) + /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { - Weight::from_ref_time(17_768_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(76_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 24_285 nanoseconds. + Weight::from_ref_time(25_355_667 as u64) + // Standard Error: 1_468 + .saturating_add(Weight::from_ref_time(38_185 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(35_682_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(158_000 as u64).saturating_mul(a as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 44_948 nanoseconds. + Weight::from_ref_time(44_762_064 as u64) + // Standard Error: 1_778 + .saturating_add(Weight::from_ref_time(118_940 as u64).saturating_mul(a as u64)) + // Standard Error: 1_837 + .saturating_add(Weight::from_ref_time(51_232 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(25_586_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(175_000 as u64).saturating_mul(a as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(18_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 31_274 nanoseconds. + Weight::from_ref_time(32_219_165 as u64) + // Standard Error: 1_832 + .saturating_add(Weight::from_ref_time(132_454 as u64).saturating_mul(a as u64)) + // Standard Error: 1_893 + .saturating_add(Weight::from_ref_time(9_077 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(25_794_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(173_000 as u64).saturating_mul(a as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(13_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 31_219 nanoseconds. + Weight::from_ref_time(32_439_563 as u64) + // Standard Error: 1_829 + .saturating_add(Weight::from_ref_time(120_251 as u64).saturating_mul(a as u64)) + // Standard Error: 1_890 + .saturating_add(Weight::from_ref_time(8_689 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Proxy Proxies (r:1 w:0) // Storage: Proxy Announcements (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { - Weight::from_ref_time(33_002_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(163_000 as u64).saturating_mul(a as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(79_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 40_388 nanoseconds. + Weight::from_ref_time(40_718_245 as u64) + // Standard Error: 1_821 + .saturating_add(Weight::from_ref_time(129_674 as u64).saturating_mul(a as u64)) + // Standard Error: 1_882 + .saturating_add(Weight::from_ref_time(56_001 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Proxy Proxies (r:1 w:1) + /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { - Weight::from_ref_time(28_166_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(105_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 33_997 nanoseconds. + Weight::from_ref_time(34_840_036 as u64) + // Standard Error: 1_659 + .saturating_add(Weight::from_ref_time(71_349 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) + /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { - Weight::from_ref_time(28_128_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(118_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 33_900 nanoseconds. + Weight::from_ref_time(35_069_110 as u64) + // Standard Error: 1_848 + .saturating_add(Weight::from_ref_time(82_380 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) + /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { - Weight::from_ref_time(24_066_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(81_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 29_627 nanoseconds. + Weight::from_ref_time(30_641_642 as u64) + // Standard Error: 1_495 + .saturating_add(Weight::from_ref_time(51_919 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) + /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { - Weight::from_ref_time(31_077_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 37_761 nanoseconds. + Weight::from_ref_time(38_748_697 as u64) + // Standard Error: 1_594 + .saturating_add(Weight::from_ref_time(19_022 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) + /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { - Weight::from_ref_time(24_657_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 31_145 nanoseconds. + Weight::from_ref_time(31_933_568 as u64) + // Standard Error: 1_492 + .saturating_add(Weight::from_ref_time(50_250 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/ranked-collective/src/weights.rs b/frame/ranked-collective/src/weights.rs index 6b6cca52316c9..c054d200452e8 100644 --- a/frame/ranked-collective/src/weights.rs +++ b/frame/ranked-collective/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,23 +18,25 @@ //! Autogenerated weights for pallet_ranked_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /Users/gav/Core/substrate/target/release/substrate +// ./target/production/substrate // benchmark // pallet -// --pallet -// pallet-ranked-collective -// --extrinsic=* // --chain=dev // --steps=50 // --repeat=20 -// --output=../../../frame/ranked-collective/src/weights.rs -// --template=../../../.maintain/frame-weight-template.hbs -// --header=../../../HEADER-APACHE2 -// --record-proof +// --pallet=pallet_ranked_collective +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/ranked-collective/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -61,7 +63,8 @@ impl WeightInfo for SubstrateWeight { // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) fn add_member() -> Weight { - Weight::from_ref_time(11_000_000 as u64) + // Minimum execution time: 24_344 nanoseconds. + Weight::from_ref_time(24_856_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -69,10 +72,12 @@ impl WeightInfo for SubstrateWeight { // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) + /// The range of component `r` is `[0, 10]`. fn remove_member(r: u32, ) -> Weight { - Weight::from_ref_time(16_855_000 as u64) - // Standard Error: 27_000 - .saturating_add(Weight::from_ref_time(8_107_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 36_881 nanoseconds. + Weight::from_ref_time(39_284_238 as u64) + // Standard Error: 16_355 + .saturating_add(Weight::from_ref_time(11_385_424 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -82,10 +87,12 @@ impl WeightInfo for SubstrateWeight { // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) + /// The range of component `r` is `[0, 10]`. fn promote_member(r: u32, ) -> Weight { - Weight::from_ref_time(11_936_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(9_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 27_444 nanoseconds. + Weight::from_ref_time(28_576_394 as u64) + // Standard Error: 4_818 + .saturating_add(Weight::from_ref_time(519_056 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -93,10 +100,12 @@ impl WeightInfo for SubstrateWeight { // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) + /// The range of component `r` is `[0, 10]`. fn demote_member(r: u32, ) -> Weight { - Weight::from_ref_time(17_582_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 36_539 nanoseconds. + Weight::from_ref_time(39_339_893 as u64) + // Standard Error: 16_526 + .saturating_add(Weight::from_ref_time(807_457 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -105,17 +114,21 @@ impl WeightInfo for SubstrateWeight { // Storage: RankedCollective Voting (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote() -> Weight { - Weight::from_ref_time(22_000_000 as u64) + // Minimum execution time: 50_548 nanoseconds. + Weight::from_ref_time(51_276_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: RankedPolls ReferendumInfoFor (r:1 w:0) - // Storage: RankedCollective Voting (r:0 w:1) + // Storage: RankedCollective VotingCleanup (r:1 w:0) + // Storage: RankedCollective Voting (r:0 w:2) + /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { - Weight::from_ref_time(6_188_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(867_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) + // Minimum execution time: 16_222 nanoseconds. + Weight::from_ref_time(22_982_955 as u64) + // Standard Error: 3_863 + .saturating_add(Weight::from_ref_time(1_074_054 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } } @@ -127,7 +140,8 @@ impl WeightInfo for () { // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) fn add_member() -> Weight { - Weight::from_ref_time(11_000_000 as u64) + // Minimum execution time: 24_344 nanoseconds. + Weight::from_ref_time(24_856_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -135,10 +149,12 @@ impl WeightInfo for () { // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) + /// The range of component `r` is `[0, 10]`. fn remove_member(r: u32, ) -> Weight { - Weight::from_ref_time(16_855_000 as u64) - // Standard Error: 27_000 - .saturating_add(Weight::from_ref_time(8_107_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 36_881 nanoseconds. + Weight::from_ref_time(39_284_238 as u64) + // Standard Error: 16_355 + .saturating_add(Weight::from_ref_time(11_385_424 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -148,10 +164,12 @@ impl WeightInfo for () { // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IndexToId (r:0 w:1) // Storage: RankedCollective IdToIndex (r:0 w:1) + /// The range of component `r` is `[0, 10]`. fn promote_member(r: u32, ) -> Weight { - Weight::from_ref_time(11_936_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(9_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 27_444 nanoseconds. + Weight::from_ref_time(28_576_394 as u64) + // Standard Error: 4_818 + .saturating_add(Weight::from_ref_time(519_056 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -159,10 +177,12 @@ impl WeightInfo for () { // Storage: RankedCollective MemberCount (r:1 w:1) // Storage: RankedCollective IdToIndex (r:1 w:1) // Storage: RankedCollective IndexToId (r:1 w:1) + /// The range of component `r` is `[0, 10]`. fn demote_member(r: u32, ) -> Weight { - Weight::from_ref_time(17_582_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 36_539 nanoseconds. + Weight::from_ref_time(39_339_893 as u64) + // Standard Error: 16_526 + .saturating_add(Weight::from_ref_time(807_457 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -171,17 +191,21 @@ impl WeightInfo for () { // Storage: RankedCollective Voting (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn vote() -> Weight { - Weight::from_ref_time(22_000_000 as u64) + // Minimum execution time: 50_548 nanoseconds. + Weight::from_ref_time(51_276_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: RankedPolls ReferendumInfoFor (r:1 w:0) - // Storage: RankedCollective Voting (r:0 w:1) + // Storage: RankedCollective VotingCleanup (r:1 w:0) + // Storage: RankedCollective Voting (r:0 w:2) + /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { - Weight::from_ref_time(6_188_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(867_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) + // Minimum execution time: 16_222 nanoseconds. + Weight::from_ref_time(22_982_955 as u64) + // Standard Error: 3_863 + .saturating_add(Weight::from_ref_time(1_074_054 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } } diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index b496f16a46b28..39a8d09a38261 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_recovery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/recovery/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -60,69 +63,83 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Recovery Proxy (r:1 w:0) fn as_recovered() -> Weight { - Weight::from_ref_time(6_579_000 as u64) + // Minimum execution time: 10_672 nanoseconds. + Weight::from_ref_time(10_946_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Recovery Proxy (r:0 w:1) fn set_recovered() -> Weight { - Weight::from_ref_time(13_402_000 as u64) + // Minimum execution time: 17_092 nanoseconds. + Weight::from_ref_time(17_660_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:1) + /// The range of component `n` is `[1, 9]`. fn create_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(28_217_000 as u64) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(172_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 32_800 nanoseconds. + Weight::from_ref_time(33_769_078 as u64) + // Standard Error: 4_075 + .saturating_add(Weight::from_ref_time(252_382 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn initiate_recovery() -> Weight { - Weight::from_ref_time(34_082_000 as u64) + // Minimum execution time: 39_224 nanoseconds. + Weight::from_ref_time(39_663_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) + /// The range of component `n` is `[1, 9]`. fn vouch_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(22_038_000 as u64) - // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(307_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 27_158 nanoseconds. + Weight::from_ref_time(28_130_506 as u64) + // Standard Error: 4_523 + .saturating_add(Weight::from_ref_time(321_436 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Proxy (r:1 w:1) + /// The range of component `n` is `[1, 9]`. fn claim_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(28_621_000 as u64) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(353_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 36_269 nanoseconds. + Weight::from_ref_time(36_966_173 as u64) + // Standard Error: 5_016 + .saturating_add(Weight::from_ref_time(223_069 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery ActiveRecoveries (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `n` is `[1, 9]`. fn close_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(33_287_000 as u64) - // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(264_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 40_213 nanoseconds. + Weight::from_ref_time(41_140_968 as u64) + // Standard Error: 3_822 + .saturating_add(Weight::from_ref_time(163_217 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Recoverable (r:1 w:1) + /// The range of component `n` is `[1, 9]`. fn remove_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(31_964_000 as u64) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(222_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 38_740 nanoseconds. + Weight::from_ref_time(39_710_400 as u64) + // Standard Error: 5_554 + .saturating_add(Weight::from_ref_time(224_200 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Recovery Proxy (r:1 w:1) fn cancel_recovered() -> Weight { - Weight::from_ref_time(12_702_000 as u64) + // Minimum execution time: 20_316 nanoseconds. + Weight::from_ref_time(20_912_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -132,69 +149,83 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Recovery Proxy (r:1 w:0) fn as_recovered() -> Weight { - Weight::from_ref_time(6_579_000 as u64) + // Minimum execution time: 10_672 nanoseconds. + Weight::from_ref_time(10_946_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Recovery Proxy (r:0 w:1) fn set_recovered() -> Weight { - Weight::from_ref_time(13_402_000 as u64) + // Minimum execution time: 17_092 nanoseconds. + Weight::from_ref_time(17_660_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:1) + /// The range of component `n` is `[1, 9]`. fn create_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(28_217_000 as u64) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(172_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 32_800 nanoseconds. + Weight::from_ref_time(33_769_078 as u64) + // Standard Error: 4_075 + .saturating_add(Weight::from_ref_time(252_382 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) fn initiate_recovery() -> Weight { - Weight::from_ref_time(34_082_000 as u64) + // Minimum execution time: 39_224 nanoseconds. + Weight::from_ref_time(39_663_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:1) + /// The range of component `n` is `[1, 9]`. fn vouch_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(22_038_000 as u64) - // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(307_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 27_158 nanoseconds. + Weight::from_ref_time(28_130_506 as u64) + // Standard Error: 4_523 + .saturating_add(Weight::from_ref_time(321_436 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery Recoverable (r:1 w:0) // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Proxy (r:1 w:1) + /// The range of component `n` is `[1, 9]`. fn claim_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(28_621_000 as u64) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(353_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 36_269 nanoseconds. + Weight::from_ref_time(36_966_173 as u64) + // Standard Error: 5_016 + .saturating_add(Weight::from_ref_time(223_069 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery ActiveRecoveries (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `n` is `[1, 9]`. fn close_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(33_287_000 as u64) - // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(264_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 40_213 nanoseconds. + Weight::from_ref_time(41_140_968 as u64) + // Standard Error: 3_822 + .saturating_add(Weight::from_ref_time(163_217 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Recovery ActiveRecoveries (r:1 w:0) // Storage: Recovery Recoverable (r:1 w:1) + /// The range of component `n` is `[1, 9]`. fn remove_recovery(n: u32, ) -> Weight { - Weight::from_ref_time(31_964_000 as u64) - // Standard Error: 13_000 - .saturating_add(Weight::from_ref_time(222_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 38_740 nanoseconds. + Weight::from_ref_time(39_710_400 as u64) + // Standard Error: 5_554 + .saturating_add(Weight::from_ref_time(224_200 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Recovery Proxy (r:1 w:1) fn cancel_recovered() -> Weight { - Weight::from_ref_time(12_702_000 as u64) + // Minimum execution time: 20_316 nanoseconds. + Weight::from_ref_time(20_912_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index 50f8aa41b30aa..d8609abb9fe80 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_referenda //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/referenda/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -80,14 +83,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - Weight::from_ref_time(34_640_000 as u64) + // Minimum execution time: 41_475 nanoseconds. + Weight::from_ref_time(42_153_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - Weight::from_ref_time(44_290_000 as u64) + // Minimum execution time: 52_291 nanoseconds. + Weight::from_ref_time(53_147_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -95,7 +100,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - Weight::from_ref_time(49_428_000 as u64) + // Minimum execution time: 57_322 nanoseconds. + Weight::from_ref_time(58_145_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -103,7 +109,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - Weight::from_ref_time(50_076_000 as u64) + // Minimum execution time: 57_170 nanoseconds. + Weight::from_ref_time(58_012_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -111,7 +118,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - Weight::from_ref_time(55_935_000 as u64) + // Minimum execution time: 67_805 nanoseconds. + Weight::from_ref_time(68_844_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -119,34 +127,39 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - Weight::from_ref_time(52_921_000 as u64) + // Minimum execution time: 63_408 nanoseconds. + Weight::from_ref_time(64_049_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - Weight::from_ref_time(29_160_000 as u64) + // Minimum execution time: 36_639 nanoseconds. + Weight::from_ref_time(37_329_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - Weight::from_ref_time(34_972_000 as u64) + // Minimum execution time: 42_442 nanoseconds. + Weight::from_ref_time(43_006_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - Weight::from_ref_time(60_620_000 as u64) + // Minimum execution time: 74_681 nanoseconds. + Weight::from_ref_time(75_567_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - Weight::from_ref_time(9_615_000 as u64) + // Minimum execution time: 14_262 nanoseconds. + Weight::from_ref_time(14_504_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -154,7 +167,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - Weight::from_ref_time(113_077_000 as u64) + // Minimum execution time: 88_618 nanoseconds. + Weight::from_ref_time(89_443_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -162,7 +176,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - Weight::from_ref_time(114_376_000 as u64) + // Minimum execution time: 89_784 nanoseconds. + Weight::from_ref_time(90_619_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -170,7 +185,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - Weight::from_ref_time(43_901_000 as u64) + // Minimum execution time: 73_179 nanoseconds. + Weight::from_ref_time(74_025_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -178,7 +194,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - Weight::from_ref_time(43_279_000 as u64) + // Minimum execution time: 73_168 nanoseconds. + Weight::from_ref_time(73_769_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -187,7 +204,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - Weight::from_ref_time(45_564_000 as u64) + // Minimum execution time: 75_027 nanoseconds. + Weight::from_ref_time(76_220_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -196,27 +214,31 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - Weight::from_ref_time(45_061_000 as u64) + // Minimum execution time: 74_815 nanoseconds. + Weight::from_ref_time(75_803_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - Weight::from_ref_time(23_757_000 as u64) + // Minimum execution time: 31_877 nanoseconds. + Weight::from_ref_time(32_236_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - Weight::from_ref_time(24_781_000 as u64) + // Minimum execution time: 33_322 nanoseconds. + Weight::from_ref_time(33_762_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - Weight::from_ref_time(18_344_000 as u64) + // Minimum execution time: 25_393 nanoseconds. + Weight::from_ref_time(25_913_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -224,7 +246,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - Weight::from_ref_time(34_752_000 as u64) + // Minimum execution time: 47_114 nanoseconds. + Weight::from_ref_time(47_586_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -232,51 +255,57 @@ impl WeightInfo for SubstrateWeight { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - Weight::from_ref_time(37_055_000 as u64) + // Minimum execution time: 48_443 nanoseconds. + Weight::from_ref_time(50_003_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - Weight::from_ref_time(31_442_000 as u64) + // Minimum execution time: 44_556 nanoseconds. + Weight::from_ref_time(45_167_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - Weight::from_ref_time(33_201_000 as u64) + // Minimum execution time: 45_474 nanoseconds. + Weight::from_ref_time(46_105_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - Weight::from_ref_time(30_047_000 as u64) + // Minimum execution time: 42_795 nanoseconds. + Weight::from_ref_time(43_123_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - Weight::from_ref_time(29_195_000 as u64) + // Minimum execution time: 41_928 nanoseconds. + Weight::from_ref_time(42_272_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) fn nudge_referendum_approved() -> Weight { - Weight::from_ref_time(50_119_000 as u64) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + // Minimum execution time: 55_186 nanoseconds. + Weight::from_ref_time(55_714_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - Weight::from_ref_time(32_203_000 as u64) + // Minimum execution time: 44_892 nanoseconds. + Weight::from_ref_time(45_353_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -288,14 +317,16 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - Weight::from_ref_time(34_640_000 as u64) + // Minimum execution time: 41_475 nanoseconds. + Weight::from_ref_time(42_153_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - Weight::from_ref_time(44_290_000 as u64) + // Minimum execution time: 52_291 nanoseconds. + Weight::from_ref_time(53_147_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -303,7 +334,8 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - Weight::from_ref_time(49_428_000 as u64) + // Minimum execution time: 57_322 nanoseconds. + Weight::from_ref_time(58_145_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -311,7 +343,8 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - Weight::from_ref_time(50_076_000 as u64) + // Minimum execution time: 57_170 nanoseconds. + Weight::from_ref_time(58_012_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -319,7 +352,8 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - Weight::from_ref_time(55_935_000 as u64) + // Minimum execution time: 67_805 nanoseconds. + Weight::from_ref_time(68_844_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -327,34 +361,39 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - Weight::from_ref_time(52_921_000 as u64) + // Minimum execution time: 63_408 nanoseconds. + Weight::from_ref_time(64_049_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - Weight::from_ref_time(29_160_000 as u64) + // Minimum execution time: 36_639 nanoseconds. + Weight::from_ref_time(37_329_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - Weight::from_ref_time(34_972_000 as u64) + // Minimum execution time: 42_442 nanoseconds. + Weight::from_ref_time(43_006_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - Weight::from_ref_time(60_620_000 as u64) + // Minimum execution time: 74_681 nanoseconds. + Weight::from_ref_time(75_567_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - Weight::from_ref_time(9_615_000 as u64) + // Minimum execution time: 14_262 nanoseconds. + Weight::from_ref_time(14_504_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -362,7 +401,8 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - Weight::from_ref_time(113_077_000 as u64) + // Minimum execution time: 88_618 nanoseconds. + Weight::from_ref_time(89_443_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -370,7 +410,8 @@ impl WeightInfo for () { // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - Weight::from_ref_time(114_376_000 as u64) + // Minimum execution time: 89_784 nanoseconds. + Weight::from_ref_time(90_619_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -378,7 +419,8 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - Weight::from_ref_time(43_901_000 as u64) + // Minimum execution time: 73_179 nanoseconds. + Weight::from_ref_time(74_025_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -386,7 +428,8 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - Weight::from_ref_time(43_279_000 as u64) + // Minimum execution time: 73_168 nanoseconds. + Weight::from_ref_time(73_769_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -395,7 +438,8 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - Weight::from_ref_time(45_564_000 as u64) + // Minimum execution time: 75_027 nanoseconds. + Weight::from_ref_time(76_220_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -404,27 +448,31 @@ impl WeightInfo for () { // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - Weight::from_ref_time(45_061_000 as u64) + // Minimum execution time: 74_815 nanoseconds. + Weight::from_ref_time(75_803_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - Weight::from_ref_time(23_757_000 as u64) + // Minimum execution time: 31_877 nanoseconds. + Weight::from_ref_time(32_236_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - Weight::from_ref_time(24_781_000 as u64) + // Minimum execution time: 33_322 nanoseconds. + Weight::from_ref_time(33_762_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - Weight::from_ref_time(18_344_000 as u64) + // Minimum execution time: 25_393 nanoseconds. + Weight::from_ref_time(25_913_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -432,7 +480,8 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - Weight::from_ref_time(34_752_000 as u64) + // Minimum execution time: 47_114 nanoseconds. + Weight::from_ref_time(47_586_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -440,51 +489,57 @@ impl WeightInfo for () { // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - Weight::from_ref_time(37_055_000 as u64) + // Minimum execution time: 48_443 nanoseconds. + Weight::from_ref_time(50_003_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - Weight::from_ref_time(31_442_000 as u64) + // Minimum execution time: 44_556 nanoseconds. + Weight::from_ref_time(45_167_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - Weight::from_ref_time(33_201_000 as u64) + // Minimum execution time: 45_474 nanoseconds. + Weight::from_ref_time(46_105_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - Weight::from_ref_time(30_047_000 as u64) + // Minimum execution time: 42_795 nanoseconds. + Weight::from_ref_time(43_123_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - Weight::from_ref_time(29_195_000 as u64) + // Minimum execution time: 41_928 nanoseconds. + Weight::from_ref_time(42_272_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) fn nudge_referendum_approved() -> Weight { - Weight::from_ref_time(50_119_000 as u64) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) + // Minimum execution time: 55_186 nanoseconds. + Weight::from_ref_time(55_714_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - Weight::from_ref_time(32_203_000 as u64) + // Minimum execution time: 44_892 nanoseconds. + Weight::from_ref_time(45_353_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index 40e9e933aab2b..0d739657c852b 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_remark //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/remark/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -51,10 +54,12 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// The range of component `l` is `[1, 1048576]`. fn store(l: u32, ) -> Weight { - Weight::from_ref_time(13_140_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(l as u64)) + // Minimum execution time: 17_017 nanoseconds. + Weight::from_ref_time(8_269_935 as u64) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(1_407 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) } } @@ -62,10 +67,12 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// The range of component `l` is `[1, 1048576]`. fn store(l: u32, ) -> Weight { - Weight::from_ref_time(13_140_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(l as u64)) + // Minimum execution time: 17_017 nanoseconds. + Weight::from_ref_time(8_269_935 as u64) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(1_407 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } } diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index cb72fe3e2fdda..5b86e7a143e7a 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,23 +18,24 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_scheduler // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --pallet=pallet_scheduler -// --chain=dev // --output=./frame/scheduler/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -65,52 +66,61 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Scheduler IncompleteSince (r:1 w:1) fn service_agendas_base() -> Weight { - Weight::from_ref_time(4_992_000 as u64) + // Minimum execution time: 5_131 nanoseconds. + Weight::from_ref_time(5_286_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Scheduler Agenda (r:1 w:1) /// The range of component `s` is `[0, 512]`. fn service_agenda_base(s: u32, ) -> Weight { - Weight::from_ref_time(4_320_000 as u64) - // Standard Error: 619 - .saturating_add(Weight::from_ref_time(336_713 as u64).saturating_mul(s as u64)) + // Minimum execution time: 4_111 nanoseconds. + Weight::from_ref_time(8_763_440 as u64) + // Standard Error: 783 + .saturating_add(Weight::from_ref_time(372_339 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } fn service_task_base() -> Weight { - Weight::from_ref_time(10_864_000 as u64) + // Minimum execution time: 10_880 nanoseconds. + Weight::from_ref_time(11_194_000 as u64) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) /// The range of component `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { - Weight::from_ref_time(24_586_000 as u64) - // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_138 as u64).saturating_mul(s as u64)) + // Minimum execution time: 25_347 nanoseconds. + Weight::from_ref_time(25_717_000 as u64) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(1_128 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:0 w:1) fn service_task_named() -> Weight { - Weight::from_ref_time(13_127_000 as u64) + // Minimum execution time: 12_894 nanoseconds. + Weight::from_ref_time(13_108_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } fn service_task_periodic() -> Weight { - Weight::from_ref_time(11_053_000 as u64) + // Minimum execution time: 10_667 nanoseconds. + Weight::from_ref_time(10_908_000 as u64) } fn execute_dispatch_signed() -> Weight { - Weight::from_ref_time(4_158_000 as u64) + // Minimum execution time: 4_124 nanoseconds. + Weight::from_ref_time(4_680_000 as u64) } fn execute_dispatch_unsigned() -> Weight { - Weight::from_ref_time(4_104_000 as u64) + // Minimum execution time: 4_156 nanoseconds. + Weight::from_ref_time(4_361_000 as u64) } // Storage: Scheduler Agenda (r:1 w:1) /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { - Weight::from_ref_time(20_074_000 as u64) - // Standard Error: 765 - .saturating_add(Weight::from_ref_time(343_285 as u64).saturating_mul(s as u64)) + // Minimum execution time: 20_504 nanoseconds. + Weight::from_ref_time(27_066_818 as u64) + // Standard Error: 1_114 + .saturating_add(Weight::from_ref_time(372_897 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -118,9 +128,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Lookup (r:0 w:1) /// The range of component `s` is `[1, 512]`. fn cancel(s: u32, ) -> Weight { - Weight::from_ref_time(21_509_000 as u64) - // Standard Error: 708 - .saturating_add(Weight::from_ref_time(323_013 as u64).saturating_mul(s as u64)) + // Minimum execution time: 21_686 nanoseconds. + Weight::from_ref_time(25_696_496 as u64) + // Standard Error: 1_261 + .saturating_add(Weight::from_ref_time(362_498 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -128,9 +139,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { - Weight::from_ref_time(22_427_000 as u64) - // Standard Error: 850 - .saturating_add(Weight::from_ref_time(357_265 as u64).saturating_mul(s as u64)) + // Minimum execution time: 23_084 nanoseconds. + Weight::from_ref_time(31_255_518 as u64) + // Standard Error: 1_258 + .saturating_add(Weight::from_ref_time(382_534 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -138,9 +150,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { - Weight::from_ref_time(22_875_000 as u64) - // Standard Error: 693 - .saturating_add(Weight::from_ref_time(336_643 as u64).saturating_mul(s as u64)) + // Minimum execution time: 23_862 nanoseconds. + Weight::from_ref_time(28_591_336 as u64) + // Standard Error: 742 + .saturating_add(Weight::from_ref_time(369_305 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -150,52 +163,61 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Scheduler IncompleteSince (r:1 w:1) fn service_agendas_base() -> Weight { - Weight::from_ref_time(4_992_000 as u64) + // Minimum execution time: 5_131 nanoseconds. + Weight::from_ref_time(5_286_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Scheduler Agenda (r:1 w:1) /// The range of component `s` is `[0, 512]`. fn service_agenda_base(s: u32, ) -> Weight { - Weight::from_ref_time(4_320_000 as u64) - // Standard Error: 619 - .saturating_add(Weight::from_ref_time(336_713 as u64).saturating_mul(s as u64)) + // Minimum execution time: 4_111 nanoseconds. + Weight::from_ref_time(8_763_440 as u64) + // Standard Error: 783 + .saturating_add(Weight::from_ref_time(372_339 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } fn service_task_base() -> Weight { - Weight::from_ref_time(10_864_000 as u64) + // Minimum execution time: 10_880 nanoseconds. + Weight::from_ref_time(11_194_000 as u64) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) /// The range of component `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { - Weight::from_ref_time(24_586_000 as u64) - // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_138 as u64).saturating_mul(s as u64)) + // Minimum execution time: 25_347 nanoseconds. + Weight::from_ref_time(25_717_000 as u64) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(1_128 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:0 w:1) fn service_task_named() -> Weight { - Weight::from_ref_time(13_127_000 as u64) + // Minimum execution time: 12_894 nanoseconds. + Weight::from_ref_time(13_108_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } fn service_task_periodic() -> Weight { - Weight::from_ref_time(11_053_000 as u64) + // Minimum execution time: 10_667 nanoseconds. + Weight::from_ref_time(10_908_000 as u64) } fn execute_dispatch_signed() -> Weight { - Weight::from_ref_time(4_158_000 as u64) + // Minimum execution time: 4_124 nanoseconds. + Weight::from_ref_time(4_680_000 as u64) } fn execute_dispatch_unsigned() -> Weight { - Weight::from_ref_time(4_104_000 as u64) + // Minimum execution time: 4_156 nanoseconds. + Weight::from_ref_time(4_361_000 as u64) } // Storage: Scheduler Agenda (r:1 w:1) /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { - Weight::from_ref_time(20_074_000 as u64) - // Standard Error: 765 - .saturating_add(Weight::from_ref_time(343_285 as u64).saturating_mul(s as u64)) + // Minimum execution time: 20_504 nanoseconds. + Weight::from_ref_time(27_066_818 as u64) + // Standard Error: 1_114 + .saturating_add(Weight::from_ref_time(372_897 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -203,9 +225,10 @@ impl WeightInfo for () { // Storage: Scheduler Lookup (r:0 w:1) /// The range of component `s` is `[1, 512]`. fn cancel(s: u32, ) -> Weight { - Weight::from_ref_time(21_509_000 as u64) - // Standard Error: 708 - .saturating_add(Weight::from_ref_time(323_013 as u64).saturating_mul(s as u64)) + // Minimum execution time: 21_686 nanoseconds. + Weight::from_ref_time(25_696_496 as u64) + // Standard Error: 1_261 + .saturating_add(Weight::from_ref_time(362_498 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -213,9 +236,10 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { - Weight::from_ref_time(22_427_000 as u64) - // Standard Error: 850 - .saturating_add(Weight::from_ref_time(357_265 as u64).saturating_mul(s as u64)) + // Minimum execution time: 23_084 nanoseconds. + Weight::from_ref_time(31_255_518 as u64) + // Standard Error: 1_258 + .saturating_add(Weight::from_ref_time(382_534 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -223,9 +247,10 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { - Weight::from_ref_time(22_875_000 as u64) - // Standard Error: 693 - .saturating_add(Weight::from_ref_time(336_643 as u64).saturating_mul(s as u64)) + // Minimum execution time: 23_862 nanoseconds. + Weight::from_ref_time(28_591_336 as u64) + // Standard Error: 742 + .saturating_add(Weight::from_ref_time(369_305 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index 6e775d3d6f47a..d29413a33dd17 100644 --- a/frame/session/src/weights.rs +++ b/frame/session/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_session //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/session/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,7 +58,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - Weight::from_ref_time(48_484_000 as u64) + // Minimum execution time: 59_046 nanoseconds. + Weight::from_ref_time(59_934_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -63,7 +67,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - Weight::from_ref_time(38_003_000 as u64) + // Minimum execution time: 48_872 nanoseconds. + Weight::from_ref_time(49_666_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -75,7 +80,8 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:4 w:4) fn set_keys() -> Weight { - Weight::from_ref_time(48_484_000 as u64) + // Minimum execution time: 59_046 nanoseconds. + Weight::from_ref_time(59_934_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } @@ -83,7 +89,8 @@ impl WeightInfo for () { // Storage: Session NextKeys (r:1 w:1) // Storage: Session KeyOwner (r:0 w:4) fn purge_keys() -> Weight { - Weight::from_ref_time(38_003_000 as u64) + // Minimum execution time: 48_872 nanoseconds. + Weight::from_ref_time(49_666_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 5070232365d3e..56374ffbc4b62 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,23 +18,24 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_staking // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --pallet=pallet_staking -// --chain=dev // --output=./frame/staking/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -86,17 +87,19 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - Weight::from_ref_time(52_281_000 as u64) + // Minimum execution time: 53_097 nanoseconds. + Weight::from_ref_time(53_708_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:3 w:3) - // Storage: VoterBagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - Weight::from_ref_time(89_748_000 as u64) + // Minimum execution time: 92_199 nanoseconds. + Weight::from_ref_time(93_541_000 as u64) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(7 as u64)) } @@ -106,11 +109,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:3 w:3) + // Storage: VoterList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterBagsList ListBags (r:2 w:2) + // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - Weight::from_ref_time(94_782_000 as u64) + // Minimum execution time: 98_227 nanoseconds. + Weight::from_ref_time(99_070_000 as u64) .saturating_add(T::DbWeight::get().reads(12 as u64)) .saturating_add(T::DbWeight::get().writes(8 as u64)) } @@ -120,9 +124,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(44_499_000 as u64) - // Standard Error: 387 - .saturating_add(Weight::from_ref_time(72_726 as u64).saturating_mul(s as u64)) + // Minimum execution time: 45_058 nanoseconds. + Weight::from_ref_time(46_592_713 as u64) + // Standard Error: 413 + .saturating_add(Weight::from_ref_time(63_036 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -133,17 +138,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - Weight::from_ref_time(83_230_000 as u64) - // Standard Error: 612 - .saturating_add(Weight::from_ref_time(10_289 as u64).saturating_mul(s as u64)) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + // Minimum execution time: 86_087 nanoseconds. + Weight::from_ref_time(87_627_894 as u64) .saturating_add(T::DbWeight::get().reads(13 as u64)) .saturating_add(T::DbWeight::get().writes(11 as u64)) } @@ -154,12 +158,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxValidatorsCount (r:1 w:0) // Storage: Staking Nominators (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterBagsList ListNodes (r:1 w:1) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - Weight::from_ref_time(64_430_000 as u64) + // Minimum execution time: 67_690 nanoseconds. + Weight::from_ref_time(68_348_000 as u64) .saturating_add(T::DbWeight::get().reads(11 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -167,12 +172,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - Weight::from_ref_time(42_030_000 as u64) - // Standard Error: 5_873 - .saturating_add(Weight::from_ref_time(6_747_156 as u64).saturating_mul(k as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) + // Minimum execution time: 43_512 nanoseconds. + Weight::from_ref_time(47_300_477 as u64) + // Standard Error: 11_609 + .saturating_add(Weight::from_ref_time(6_770_405 as u64).saturating_mul(k as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(k as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Staking Ledger (r:1 w:0) @@ -182,16 +187,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(70_834_000 as u64) - // Standard Error: 4_405 - .saturating_add(Weight::from_ref_time(2_583_120 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(13 as u64)) + // Minimum execution time: 74_296 nanoseconds. + Weight::from_ref_time(73_201_782 as u64) + // Standard Error: 5_007 + .saturating_add(Weight::from_ref_time(2_810_370 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(12 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -199,54 +205,62 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(63_328_000 as u64) + // Minimum execution time: 66_605 nanoseconds. + Weight::from_ref_time(67_279_000 as u64) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - Weight::from_ref_time(17_763_000 as u64) + // Minimum execution time: 18_897 nanoseconds. + Weight::from_ref_time(19_357_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - Weight::from_ref_time(26_163_000 as u64) + // Minimum execution time: 26_509 nanoseconds. + Weight::from_ref_time(26_961_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - Weight::from_ref_time(4_842_000 as u64) + // Minimum execution time: 5_025 nanoseconds. + Weight::from_ref_time(5_240_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - Weight::from_ref_time(4_974_000 as u64) + // Minimum execution time: 5_107 nanoseconds. + Weight::from_ref_time(5_320_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - Weight::from_ref_time(5_039_000 as u64) + // Minimum execution time: 5_094 nanoseconds. + Weight::from_ref_time(5_377_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - Weight::from_ref_time(4_950_000 as u64) + // Minimum execution time: 5_219 nanoseconds. + Weight::from_ref_time(5_434_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - Weight::from_ref_time(5_150_000 as u64) - // Standard Error: 30 - .saturating_add(Weight::from_ref_time(10_540 as u64).saturating_mul(v as u64)) + // Minimum execution time: 5_122 nanoseconds. + Weight::from_ref_time(5_977_533 as u64) + // Standard Error: 34 + .saturating_add(Weight::from_ref_time(10_205 as u64).saturating_mul(v as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) @@ -254,9 +268,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Ledger (r:0 w:1) @@ -264,72 +278,77 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - Weight::from_ref_time(76_282_000 as u64) - // Standard Error: 2_397 - .saturating_add(Weight::from_ref_time(1_137_934 as u64).saturating_mul(s as u64)) + // Minimum execution time: 80_216 nanoseconds. + Weight::from_ref_time(86_090_609 as u64) + // Standard Error: 2_006 + .saturating_add(Weight::from_ref_time(1_039_308 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(11 as u64)) - .saturating_add(T::DbWeight::get().writes(11 as u64)) + .saturating_add(T::DbWeight::get().writes(12 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - Weight::from_ref_time(93_690_000 as u64) - // Standard Error: 43_203 - .saturating_add(Weight::from_ref_time(6_149_862 as u64).saturating_mul(s as u64)) + // Minimum execution time: 92_034 nanoseconds. + Weight::from_ref_time(896_585_370 as u64) + // Standard Error: 58_231 + .saturating_add(Weight::from_ref_time(4_908_277 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) - // Storage: Staking Bonded (r:2 w:0) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking ErasStakersClipped (r:1 w:0) // Storage: Staking ErasRewardPoints (r:1 w:0) // Storage: Staking ErasValidatorPrefs (r:1 w:0) - // Storage: Staking Payee (r:2 w:0) - // Storage: System Account (r:2 w:2) - /// The range of component `n` is `[1, 256]`. + // Storage: Staking Payee (r:1 w:0) + // Storage: System Account (r:1 w:1) + /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - Weight::from_ref_time(151_647_000 as u64) - // Standard Error: 8_237 - .saturating_add(Weight::from_ref_time(21_296_415 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(12 as u64)) + // Minimum execution time: 127_936 nanoseconds. + Weight::from_ref_time(184_556_084 as u64) + // Standard Error: 26_981 + .saturating_add(Weight::from_ref_time(21_786_304 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(9 as u64)) .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) - // Storage: Staking Bonded (r:2 w:0) - // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) // Storage: Staking ErasStakersClipped (r:1 w:0) // Storage: Staking ErasRewardPoints (r:1 w:0) // Storage: Staking ErasValidatorPrefs (r:1 w:0) - // Storage: Staking Payee (r:2 w:0) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:2 w:2) - /// The range of component `n` is `[1, 256]`. + // Storage: Staking Payee (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - Weight::from_ref_time(197_310_000 as u64) - // Standard Error: 13_818 - .saturating_add(Weight::from_ref_time(30_053_043 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(15 as u64)) + // Minimum execution time: 157_778 nanoseconds. + Weight::from_ref_time(223_306_359 as u64) + // Standard Error: 27_216 + .saturating_add(Weight::from_ref_time(30_612_663 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(10 as u64)) .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(n as u64))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:3 w:3) + // Storage: VoterList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterBagsList ListBags (r:2 w:2) + // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - Weight::from_ref_time(89_469_000 as u64) - // Standard Error: 1_197 - .saturating_add(Weight::from_ref_time(74_212 as u64).saturating_mul(l as u64)) + // Minimum execution time: 92_880 nanoseconds. + Weight::from_ref_time(94_434_663 as u64) + // Standard Error: 1_734 + .saturating_add(Weight::from_ref_time(34_453 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(9 as u64)) .saturating_add(T::DbWeight::get().writes(8 as u64)) } @@ -340,25 +359,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - Weight::from_ref_time(88_333_000 as u64) - // Standard Error: 1_567 - .saturating_add(Weight::from_ref_time(1_101_099 as u64).saturating_mul(s as u64)) + // Minimum execution time: 92_334 nanoseconds. + Weight::from_ref_time(95_207_614 as u64) + // Standard Error: 1_822 + .saturating_add(Weight::from_ref_time(1_036_787 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(13 as u64)) + .saturating_add(T::DbWeight::get().writes(12 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } - // Storage: VoterBagsList CounterForListNodes (r:1 w:0) + // Storage: VoterList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: VoterBagsList ListBags (r:200 w:0) - // Storage: VoterBagsList ListNodes (r:101 w:0) + // Storage: VoterList ListBags (r:200 w:0) + // Storage: VoterList ListNodes (r:101 w:0) // Storage: Staking Nominators (r:101 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking Bonded (r:101 w:0) @@ -373,23 +393,24 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) /// The range of component `v` is `[1, 10]`. - /// The range of component `n` is `[1, 100]`. + /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - Weight::from_ref_time(572_530_000 as u64) - // Standard Error: 3_166_542 - .saturating_add(Weight::from_ref_time(101_354_358 as u64).saturating_mul(v as u64)) - // Standard Error: 315_238 - .saturating_add(Weight::from_ref_time(15_565_319 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(261 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + // Minimum execution time: 535_169 nanoseconds. + Weight::from_ref_time(548_667_000 as u64) + // Standard Error: 1_759_252 + .saturating_add(Weight::from_ref_time(58_283_319 as u64).saturating_mul(v as u64)) + // Standard Error: 175_299 + .saturating_add(Weight::from_ref_time(13_578_512 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(207 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(v as u64))) .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(v as u64))) } - // Storage: VoterBagsList CounterForListNodes (r:1 w:0) + // Storage: VoterList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) - // Storage: VoterBagsList ListBags (r:200 w:0) - // Storage: VoterBagsList ListNodes (r:1500 w:0) + // Storage: VoterList ListBags (r:200 w:0) + // Storage: VoterList ListNodes (r:1500 w:0) // Storage: Staking Nominators (r:1500 w:0) // Storage: Staking Validators (r:500 w:0) // Storage: Staking Bonded (r:1500 w:0) @@ -397,24 +418,28 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. /// The range of component `s` is `[1, 20]`. - fn get_npos_voters(v: u32, n: u32, _s: u32, ) -> Weight { - Weight::from_ref_time(24_930_788_000 as u64) - // Standard Error: 266_386 - .saturating_add(Weight::from_ref_time(6_687_552 as u64).saturating_mul(v as u64)) - // Standard Error: 266_386 - .saturating_add(Weight::from_ref_time(6_839_134 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6722 as u64)) - .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(v as u64))) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) + fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { + // Minimum execution time: 25_323_129 nanoseconds. + Weight::from_ref_time(25_471_672_000 as u64) + // Standard Error: 266_391 + .saturating_add(Weight::from_ref_time(6_665_504 as u64).saturating_mul(v as u64)) + // Standard Error: 266_391 + .saturating_add(Weight::from_ref_time(6_956_606 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(202 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(v as u64))) + .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) } // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - Weight::from_ref_time(4_864_727_000 as u64) - // Standard Error: 54_240 - .saturating_add(Weight::from_ref_time(3_319_738 as u64).saturating_mul(v as u64)) - .saturating_add(T::DbWeight::get().reads(502 as u64)) + // Minimum execution time: 4_905_036 nanoseconds. + Weight::from_ref_time(78_163_554 as u64) + // Standard Error: 23_723 + .saturating_add(Weight::from_ref_time(9_784_870 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(v as u64))) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -423,7 +448,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - Weight::from_ref_time(10_141_000 as u64) + // Minimum execution time: 10_096 nanoseconds. + Weight::from_ref_time(10_538_000 as u64) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:0 w:1) @@ -433,7 +459,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - Weight::from_ref_time(8_993_000 as u64) + // Minimum execution time: 9_045 nanoseconds. + Weight::from_ref_time(9_379_000 as u64) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) @@ -443,18 +470,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForNominators (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - Weight::from_ref_time(79_082_000 as u64) + // Minimum execution time: 81_457 nanoseconds. + Weight::from_ref_time(82_410_000 as u64) .saturating_add(T::DbWeight::get().reads(11 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - Weight::from_ref_time(19_265_000 as u64) + // Minimum execution time: 19_684 nanoseconds. + Weight::from_ref_time(20_059_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -468,17 +497,19 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - Weight::from_ref_time(52_281_000 as u64) + // Minimum execution time: 53_097 nanoseconds. + Weight::from_ref_time(53_708_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:3 w:3) - // Storage: VoterBagsList ListBags (r:2 w:2) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - Weight::from_ref_time(89_748_000 as u64) + // Minimum execution time: 92_199 nanoseconds. + Weight::from_ref_time(93_541_000 as u64) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(7 as u64)) } @@ -488,11 +519,12 @@ impl WeightInfo for () { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:3 w:3) + // Storage: VoterList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterBagsList ListBags (r:2 w:2) + // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - Weight::from_ref_time(94_782_000 as u64) + // Minimum execution time: 98_227 nanoseconds. + Weight::from_ref_time(99_070_000 as u64) .saturating_add(RocksDbWeight::get().reads(12 as u64)) .saturating_add(RocksDbWeight::get().writes(8 as u64)) } @@ -502,9 +534,10 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(44_499_000 as u64) - // Standard Error: 387 - .saturating_add(Weight::from_ref_time(72_726 as u64).saturating_mul(s as u64)) + // Minimum execution time: 45_058 nanoseconds. + Weight::from_ref_time(46_592_713 as u64) + // Standard Error: 413 + .saturating_add(Weight::from_ref_time(63_036 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -515,17 +548,16 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - Weight::from_ref_time(83_230_000 as u64) - // Standard Error: 612 - .saturating_add(Weight::from_ref_time(10_289 as u64).saturating_mul(s as u64)) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + // Minimum execution time: 86_087 nanoseconds. + Weight::from_ref_time(87_627_894 as u64) .saturating_add(RocksDbWeight::get().reads(13 as u64)) .saturating_add(RocksDbWeight::get().writes(11 as u64)) } @@ -536,12 +568,13 @@ impl WeightInfo for () { // Storage: Staking MaxValidatorsCount (r:1 w:0) // Storage: Staking Nominators (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterBagsList ListNodes (r:1 w:1) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - Weight::from_ref_time(64_430_000 as u64) + // Minimum execution time: 67_690 nanoseconds. + Weight::from_ref_time(68_348_000 as u64) .saturating_add(RocksDbWeight::get().reads(11 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } @@ -549,12 +582,12 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - Weight::from_ref_time(42_030_000 as u64) - // Standard Error: 5_873 - .saturating_add(Weight::from_ref_time(6_747_156 as u64).saturating_mul(k as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) + // Minimum execution time: 43_512 nanoseconds. + Weight::from_ref_time(47_300_477 as u64) + // Standard Error: 11_609 + .saturating_add(Weight::from_ref_time(6_770_405 as u64).saturating_mul(k as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(k as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Staking Ledger (r:1 w:0) @@ -564,16 +597,17 @@ impl WeightInfo for () { // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(70_834_000 as u64) - // Standard Error: 4_405 - .saturating_add(Weight::from_ref_time(2_583_120 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(13 as u64)) + // Minimum execution time: 74_296 nanoseconds. + Weight::from_ref_time(73_201_782 as u64) + // Standard Error: 5_007 + .saturating_add(Weight::from_ref_time(2_810_370 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(12 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -581,54 +615,62 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(63_328_000 as u64) + // Minimum execution time: 66_605 nanoseconds. + Weight::from_ref_time(67_279_000 as u64) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - Weight::from_ref_time(17_763_000 as u64) + // Minimum execution time: 18_897 nanoseconds. + Weight::from_ref_time(19_357_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - Weight::from_ref_time(26_163_000 as u64) + // Minimum execution time: 26_509 nanoseconds. + Weight::from_ref_time(26_961_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - Weight::from_ref_time(4_842_000 as u64) + // Minimum execution time: 5_025 nanoseconds. + Weight::from_ref_time(5_240_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - Weight::from_ref_time(4_974_000 as u64) + // Minimum execution time: 5_107 nanoseconds. + Weight::from_ref_time(5_320_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - Weight::from_ref_time(5_039_000 as u64) + // Minimum execution time: 5_094 nanoseconds. + Weight::from_ref_time(5_377_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - Weight::from_ref_time(4_950_000 as u64) + // Minimum execution time: 5_219 nanoseconds. + Weight::from_ref_time(5_434_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - Weight::from_ref_time(5_150_000 as u64) - // Standard Error: 30 - .saturating_add(Weight::from_ref_time(10_540 as u64).saturating_mul(v as u64)) + // Minimum execution time: 5_122 nanoseconds. + Weight::from_ref_time(5_977_533 as u64) + // Standard Error: 34 + .saturating_add(Weight::from_ref_time(10_205 as u64).saturating_mul(v as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) @@ -636,9 +678,9 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Ledger (r:0 w:1) @@ -646,72 +688,77 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - Weight::from_ref_time(76_282_000 as u64) - // Standard Error: 2_397 - .saturating_add(Weight::from_ref_time(1_137_934 as u64).saturating_mul(s as u64)) + // Minimum execution time: 80_216 nanoseconds. + Weight::from_ref_time(86_090_609 as u64) + // Standard Error: 2_006 + .saturating_add(Weight::from_ref_time(1_039_308 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(11 as u64)) - .saturating_add(RocksDbWeight::get().writes(11 as u64)) + .saturating_add(RocksDbWeight::get().writes(12 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - Weight::from_ref_time(93_690_000 as u64) - // Standard Error: 43_203 - .saturating_add(Weight::from_ref_time(6_149_862 as u64).saturating_mul(s as u64)) + // Minimum execution time: 92_034 nanoseconds. + Weight::from_ref_time(896_585_370 as u64) + // Standard Error: 58_231 + .saturating_add(Weight::from_ref_time(4_908_277 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) - // Storage: Staking Bonded (r:2 w:0) + // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking ErasStakersClipped (r:1 w:0) // Storage: Staking ErasRewardPoints (r:1 w:0) // Storage: Staking ErasValidatorPrefs (r:1 w:0) - // Storage: Staking Payee (r:2 w:0) - // Storage: System Account (r:2 w:2) - /// The range of component `n` is `[1, 256]`. + // Storage: Staking Payee (r:1 w:0) + // Storage: System Account (r:1 w:1) + /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - Weight::from_ref_time(151_647_000 as u64) - // Standard Error: 8_237 - .saturating_add(Weight::from_ref_time(21_296_415 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) + // Minimum execution time: 127_936 nanoseconds. + Weight::from_ref_time(184_556_084 as u64) + // Standard Error: 26_981 + .saturating_add(Weight::from_ref_time(21_786_304 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(9 as u64)) .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) - // Storage: Staking Bonded (r:2 w:0) - // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) // Storage: Staking ErasStakersClipped (r:1 w:0) // Storage: Staking ErasRewardPoints (r:1 w:0) // Storage: Staking ErasValidatorPrefs (r:1 w:0) - // Storage: Staking Payee (r:2 w:0) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:2 w:2) - /// The range of component `n` is `[1, 256]`. + // Storage: Staking Payee (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - Weight::from_ref_time(197_310_000 as u64) - // Standard Error: 13_818 - .saturating_add(Weight::from_ref_time(30_053_043 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(15 as u64)) + // Minimum execution time: 157_778 nanoseconds. + Weight::from_ref_time(223_306_359 as u64) + // Standard Error: 27_216 + .saturating_add(Weight::from_ref_time(30_612_663 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(10 as u64)) .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(n as u64))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:3 w:3) + // Storage: VoterList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterBagsList ListBags (r:2 w:2) + // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - Weight::from_ref_time(89_469_000 as u64) - // Standard Error: 1_197 - .saturating_add(Weight::from_ref_time(74_212 as u64).saturating_mul(l as u64)) + // Minimum execution time: 92_880 nanoseconds. + Weight::from_ref_time(94_434_663 as u64) + // Standard Error: 1_734 + .saturating_add(Weight::from_ref_time(34_453 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(9 as u64)) .saturating_add(RocksDbWeight::get().writes(8 as u64)) } @@ -722,25 +769,26 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - Weight::from_ref_time(88_333_000 as u64) - // Standard Error: 1_567 - .saturating_add(Weight::from_ref_time(1_101_099 as u64).saturating_mul(s as u64)) + // Minimum execution time: 92_334 nanoseconds. + Weight::from_ref_time(95_207_614 as u64) + // Standard Error: 1_822 + .saturating_add(Weight::from_ref_time(1_036_787 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().writes(13 as u64)) + .saturating_add(RocksDbWeight::get().writes(12 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } - // Storage: VoterBagsList CounterForListNodes (r:1 w:0) + // Storage: VoterList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: VoterBagsList ListBags (r:200 w:0) - // Storage: VoterBagsList ListNodes (r:101 w:0) + // Storage: VoterList ListBags (r:200 w:0) + // Storage: VoterList ListNodes (r:101 w:0) // Storage: Staking Nominators (r:101 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking Bonded (r:101 w:0) @@ -755,23 +803,24 @@ impl WeightInfo for () { // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) /// The range of component `v` is `[1, 10]`. - /// The range of component `n` is `[1, 100]`. + /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - Weight::from_ref_time(572_530_000 as u64) - // Standard Error: 3_166_542 - .saturating_add(Weight::from_ref_time(101_354_358 as u64).saturating_mul(v as u64)) - // Standard Error: 315_238 - .saturating_add(Weight::from_ref_time(15_565_319 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(261 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + // Minimum execution time: 535_169 nanoseconds. + Weight::from_ref_time(548_667_000 as u64) + // Standard Error: 1_759_252 + .saturating_add(Weight::from_ref_time(58_283_319 as u64).saturating_mul(v as u64)) + // Standard Error: 175_299 + .saturating_add(Weight::from_ref_time(13_578_512 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(207 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(v as u64))) .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(v as u64))) } - // Storage: VoterBagsList CounterForListNodes (r:1 w:0) + // Storage: VoterList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) - // Storage: VoterBagsList ListBags (r:200 w:0) - // Storage: VoterBagsList ListNodes (r:1500 w:0) + // Storage: VoterList ListBags (r:200 w:0) + // Storage: VoterList ListNodes (r:1500 w:0) // Storage: Staking Nominators (r:1500 w:0) // Storage: Staking Validators (r:500 w:0) // Storage: Staking Bonded (r:1500 w:0) @@ -779,24 +828,28 @@ impl WeightInfo for () { /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. /// The range of component `s` is `[1, 20]`. - fn get_npos_voters(v: u32, n: u32, _s: u32, ) -> Weight { - Weight::from_ref_time(24_930_788_000 as u64) - // Standard Error: 266_386 - .saturating_add(Weight::from_ref_time(6_687_552 as u64).saturating_mul(v as u64)) - // Standard Error: 266_386 - .saturating_add(Weight::from_ref_time(6_839_134 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(6722 as u64)) - .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(v as u64))) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) + fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { + // Minimum execution time: 25_323_129 nanoseconds. + Weight::from_ref_time(25_471_672_000 as u64) + // Standard Error: 266_391 + .saturating_add(Weight::from_ref_time(6_665_504 as u64).saturating_mul(v as u64)) + // Standard Error: 266_391 + .saturating_add(Weight::from_ref_time(6_956_606 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(202 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(v as u64))) + .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) } // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - Weight::from_ref_time(4_864_727_000 as u64) - // Standard Error: 54_240 - .saturating_add(Weight::from_ref_time(3_319_738 as u64).saturating_mul(v as u64)) - .saturating_add(RocksDbWeight::get().reads(502 as u64)) + // Minimum execution time: 4_905_036 nanoseconds. + Weight::from_ref_time(78_163_554 as u64) + // Standard Error: 23_723 + .saturating_add(Weight::from_ref_time(9_784_870 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(v as u64))) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -805,7 +858,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - Weight::from_ref_time(10_141_000 as u64) + // Minimum execution time: 10_096 nanoseconds. + Weight::from_ref_time(10_538_000 as u64) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:0 w:1) @@ -815,7 +869,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - Weight::from_ref_time(8_993_000 as u64) + // Minimum execution time: 9_045 nanoseconds. + Weight::from_ref_time(9_379_000 as u64) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) @@ -825,18 +880,20 @@ impl WeightInfo for () { // Storage: Staking CounterForNominators (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: VoterBagsList ListNodes (r:2 w:2) - // Storage: VoterBagsList ListBags (r:1 w:1) - // Storage: VoterBagsList CounterForListNodes (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - Weight::from_ref_time(79_082_000 as u64) + // Minimum execution time: 81_457 nanoseconds. + Weight::from_ref_time(82_410_000 as u64) .saturating_add(RocksDbWeight::get().reads(11 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - Weight::from_ref_time(19_265_000 as u64) + // Minimum execution time: 19_684 nanoseconds. + Weight::from_ref_time(20_059_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs index 851f4cba077c0..7414bb9038fdd 100644 --- a/frame/state-trie-migration/src/weights.rs +++ b/frame/state-trie-migration/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_state_trie_migration //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/state-trie-migration/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -59,38 +62,46 @@ impl WeightInfo for SubstrateWeight { // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) // Storage: StateTrieMigration MigrationProcess (r:1 w:1) fn continue_migrate() -> Weight { - Weight::from_ref_time(19_019_000 as u64) + // Minimum execution time: 23_874 nanoseconds. + Weight::from_ref_time(24_127_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) fn continue_migrate_wrong_witness() -> Weight { - Weight::from_ref_time(1_874_000 as u64) + // Minimum execution time: 6_119 nanoseconds. + Weight::from_ref_time(6_325_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } fn migrate_custom_top_success() -> Weight { - Weight::from_ref_time(16_381_000 as u64) + // Minimum execution time: 20_365 nanoseconds. + Weight::from_ref_time(20_790_000 as u64) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_top_fail() -> Weight { - Weight::from_ref_time(25_966_000 as u64) + // Minimum execution time: 38_979 nanoseconds. + Weight::from_ref_time(40_271_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } fn migrate_custom_child_success() -> Weight { - Weight::from_ref_time(16_712_000 as u64) + // Minimum execution time: 21_217 nanoseconds. + Weight::from_ref_time(21_526_000 as u64) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_child_fail() -> Weight { - Weight::from_ref_time(29_885_000 as u64) + // Minimum execution time: 43_853 nanoseconds. + Weight::from_ref_time(44_693_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: unknown [0x6b6579] (r:1 w:1) + /// The range of component `v` is `[1, 4194304]`. fn process_top_key(v: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(v as u64)) + // Minimum execution time: 5_575 nanoseconds. + Weight::from_ref_time(5_719_000 as u64) + // Standard Error: 3 + .saturating_add(Weight::from_ref_time(1_404 as u64).saturating_mul(v as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -101,38 +112,46 @@ impl WeightInfo for () { // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) // Storage: StateTrieMigration MigrationProcess (r:1 w:1) fn continue_migrate() -> Weight { - Weight::from_ref_time(19_019_000 as u64) + // Minimum execution time: 23_874 nanoseconds. + Weight::from_ref_time(24_127_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) fn continue_migrate_wrong_witness() -> Weight { - Weight::from_ref_time(1_874_000 as u64) + // Minimum execution time: 6_119 nanoseconds. + Weight::from_ref_time(6_325_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } fn migrate_custom_top_success() -> Weight { - Weight::from_ref_time(16_381_000 as u64) + // Minimum execution time: 20_365 nanoseconds. + Weight::from_ref_time(20_790_000 as u64) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_top_fail() -> Weight { - Weight::from_ref_time(25_966_000 as u64) + // Minimum execution time: 38_979 nanoseconds. + Weight::from_ref_time(40_271_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } fn migrate_custom_child_success() -> Weight { - Weight::from_ref_time(16_712_000 as u64) + // Minimum execution time: 21_217 nanoseconds. + Weight::from_ref_time(21_526_000 as u64) } // Storage: unknown [0x666f6f] (r:1 w:1) fn migrate_custom_child_fail() -> Weight { - Weight::from_ref_time(29_885_000 as u64) + // Minimum execution time: 43_853 nanoseconds. + Weight::from_ref_time(44_693_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: unknown [0x6b6579] (r:1 w:1) + /// The range of component `v` is `[1, 4194304]`. fn process_top_key(v: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(v as u64)) + // Minimum execution time: 5_575 nanoseconds. + Weight::from_ref_time(5_719_000 as u64) + // Standard Error: 3 + .saturating_add(Weight::from_ref_time(1_404 as u64).saturating_mul(v as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index 240b80460aa09..5c8e1f1c86e9d 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -16,12 +16,13 @@ // limitations under the License. //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24 (Y/M/D) +//! DATE: 2022-11-07 (Y/M/D) +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! //! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` //! WEIGHT-PATH: `./frame/support/src/weights/` -//! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1`, WEIGHT-ADD: `0` +//! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: // ./target/production/substrate @@ -31,6 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --weight-path=./frame/support/src/weights/ +// --header=./HEADER-APACHE2 // --warmup=10 // --repeat=100 @@ -39,19 +41,19 @@ use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; parameter_types! { /// Time to execute an empty block. - /// Calculated by multiplying the *Average* with `1` and adding `0`. + /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 5_303_128, 5_507_784 - /// Average: 5_346_284 - /// Median: 5_328_139 - /// Std-Dev: 41749.5 + /// Min, Max: 351_000, 392_617 + /// Average: 358_523 + /// Median: 359_836 + /// Std-Dev: 6698.67 /// /// Percentiles nanoseconds: - /// 99th: 5_489_273 - /// 95th: 5_433_314 - /// 75th: 5_354_812 - pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(5_346_284); + /// 99th: 390_723 + /// 95th: 365_799 + /// 75th: 361_582 + pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(358_523); } #[cfg(test)] diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 913dbc4e91fc1..1db2281dfe488 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -16,12 +16,13 @@ // limitations under the License. //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24 (Y/M/D) +//! DATE: 2022-11-07 (Y/M/D) +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! //! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` //! WEIGHT-PATH: `./frame/support/src/weights/` -//! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1`, WEIGHT-ADD: `0` +//! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: // ./target/production/substrate @@ -31,6 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --weight-path=./frame/support/src/weights/ +// --header=./HEADER-APACHE2 // --warmup=10 // --repeat=100 @@ -39,19 +41,19 @@ use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; parameter_types! { /// Time to execute a NO-OP extrinsic, for example `System::remark`. - /// Calculated by multiplying the *Average* with `1` and adding `0`. + /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 86_060, 86_999 - /// Average: 86_298 - /// Median: 86_248 - /// Std-Dev: 207.19 + /// Min, Max: 98_722, 101_420 + /// Average: 98_974 + /// Median: 98_951 + /// Std-Dev: 271.62 /// /// Percentiles nanoseconds: - /// 99th: 86_924 - /// 95th: 86_828 - /// 75th: 86_347 - pub const ExtrinsicBaseWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(86_298); + /// 99th: 99_202 + /// 95th: 99_163 + /// 75th: 99_030 + pub const ExtrinsicBaseWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(98_974); } #[cfg(test)] diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index 9080c9aad43f2..696a6a09b8f80 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,12 +18,12 @@ //! Autogenerated weights for frame_system //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-06-02, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `ci3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,6 +35,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/system/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -58,44 +59,52 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[0, 3932160]`. - fn remark(_b: u32, ) -> Weight { - Weight::from_ref_time(1_000_000 as u64) + fn remark(b: u32, ) -> Weight { + // Minimum execution time: 3_951 nanoseconds. + Weight::from_ref_time(1_307_232 as u64) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(363 as u64).saturating_mul(b as u64)) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + // Minimum execution time: 14_880 nanoseconds. + Weight::from_ref_time(15_173_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) + .saturating_add(Weight::from_ref_time(1_424 as u64).saturating_mul(b as u64)) } // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - Weight::from_ref_time(5_367_000 as u64) + // Minimum execution time: 9_819 nanoseconds. + Weight::from_ref_time(10_513_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Skipped Metadata (r:0 w:0) - /// The range of component `i` is `[1, 1000]`. + /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(603_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 4_038 nanoseconds. + Weight::from_ref_time(4_098_000 as u64) + // Standard Error: 710 + .saturating_add(Weight::from_ref_time(620_813 as u64).saturating_mul(i as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) - /// The range of component `i` is `[1, 1000]`. + /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(513_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 3_972 nanoseconds. + Weight::from_ref_time(4_082_000 as u64) + // Standard Error: 884 + .saturating_add(Weight::from_ref_time(536_923 as u64).saturating_mul(i as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) - /// The range of component `p` is `[1, 1000]`. + /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_026_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 5_703 nanoseconds. + Weight::from_ref_time(5_763_000 as u64) + // Standard Error: 1_248 + .saturating_add(Weight::from_ref_time(1_126_062 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(p as u64))) } } @@ -103,44 +112,52 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { /// The range of component `b` is `[0, 3932160]`. - fn remark(_b: u32, ) -> Weight { - Weight::from_ref_time(1_000_000 as u64) + fn remark(b: u32, ) -> Weight { + // Minimum execution time: 3_951 nanoseconds. + Weight::from_ref_time(1_307_232 as u64) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(363 as u64).saturating_mul(b as u64)) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + // Minimum execution time: 14_880 nanoseconds. + Weight::from_ref_time(15_173_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) + .saturating_add(Weight::from_ref_time(1_424 as u64).saturating_mul(b as u64)) } // Storage: System Digest (r:1 w:1) // Storage: unknown [0x3a686561707061676573] (r:0 w:1) fn set_heap_pages() -> Weight { - Weight::from_ref_time(5_367_000 as u64) + // Minimum execution time: 9_819 nanoseconds. + Weight::from_ref_time(10_513_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Skipped Metadata (r:0 w:0) - /// The range of component `i` is `[1, 1000]`. + /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(603_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 4_038 nanoseconds. + Weight::from_ref_time(4_098_000 as u64) + // Standard Error: 710 + .saturating_add(Weight::from_ref_time(620_813 as u64).saturating_mul(i as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) - /// The range of component `i` is `[1, 1000]`. + /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(513_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 3_972 nanoseconds. + Weight::from_ref_time(4_082_000 as u64) + // Standard Error: 884 + .saturating_add(Weight::from_ref_time(536_923 as u64).saturating_mul(i as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(i as u64))) } // Storage: Skipped Metadata (r:0 w:0) - /// The range of component `p` is `[1, 1000]`. + /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_026_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 5_703 nanoseconds. + Weight::from_ref_time(5_763_000 as u64) + // Standard Error: 1_248 + .saturating_add(Weight::from_ref_time(1_126_062 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(p as u64))) } } diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index d51f7c9cfe79d..52123920977da 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_timestamp //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/timestamp/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,12 +57,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - Weight::from_ref_time(8_080_000 as u64) + // Minimum execution time: 11_331 nanoseconds. + Weight::from_ref_time(11_584_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } fn on_finalize() -> Weight { - Weight::from_ref_time(2_681_000 as u64) + // Minimum execution time: 5_280 nanoseconds. + Weight::from_ref_time(5_412_000 as u64) } } @@ -68,11 +73,13 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:1) // Storage: Babe CurrentSlot (r:1 w:0) fn set() -> Weight { - Weight::from_ref_time(8_080_000 as u64) + // Minimum execution time: 11_331 nanoseconds. + Weight::from_ref_time(11_584_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } fn on_finalize() -> Weight { - Weight::from_ref_time(2_681_000 as u64) + // Minimum execution time: 5_280 nanoseconds. + Weight::from_ref_time(5_412_000 as u64) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 086b1c72b21c0..1aa3fd8fa2eb7 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_tips //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/tips/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,38 +60,46 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) + /// The range of component `r` is `[0, 300]`. fn report_awesome(r: u32, ) -> Weight { - Weight::from_ref_time(30_669_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 35_458 nanoseconds. + Weight::from_ref_time(36_920_009 as u64) + // Standard Error: 252 + .saturating_add(Weight::from_ref_time(1_835 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - Weight::from_ref_time(28_768_000 as u64) + // Minimum execution time: 34_322 nanoseconds. + Weight::from_ref_time(35_292_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) + /// The range of component `r` is `[0, 300]`. + /// The range of component `t` is `[1, 13]`. fn tip_new(r: u32, t: u32, ) -> Weight { - Weight::from_ref_time(20_385_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(r as u64)) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(166_000 as u64).saturating_mul(t as u64)) + // Minimum execution time: 26_691 nanoseconds. + Weight::from_ref_time(27_313_497 as u64) + // Standard Error: 141 + .saturating_add(Weight::from_ref_time(818 as u64).saturating_mul(r as u64)) + // Standard Error: 3_352 + .saturating_add(Weight::from_ref_time(108_557 as u64).saturating_mul(t as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) + /// The range of component `t` is `[1, 13]`. fn tip(t: u32, ) -> Weight { - Weight::from_ref_time(12_287_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(363_000 as u64).saturating_mul(t as u64)) + // Minimum execution time: 17_464 nanoseconds. + Weight::from_ref_time(17_621_090 as u64) + // Standard Error: 3_702 + .saturating_add(Weight::from_ref_time(269_919 as u64).saturating_mul(t as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -96,19 +107,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Elections Members (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) + /// The range of component `t` is `[1, 13]`. fn close_tip(t: u32, ) -> Weight { - Weight::from_ref_time(45_656_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(276_000 as u64).saturating_mul(t as u64)) + // Minimum execution time: 52_221 nanoseconds. + Weight::from_ref_time(53_168_303 as u64) + // Standard Error: 6_591 + .saturating_add(Weight::from_ref_time(243_706 as u64).saturating_mul(t as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) + /// The range of component `t` is `[1, 13]`. fn slash_tip(t: u32, ) -> Weight { - Weight::from_ref_time(18_525_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(t as u64)) + // Minimum execution time: 22_911 nanoseconds. + Weight::from_ref_time(23_750_488 as u64) + // Standard Error: 2_561 + .saturating_add(Weight::from_ref_time(12_282 as u64).saturating_mul(t as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -118,38 +133,46 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:1 w:1) + /// The range of component `r` is `[0, 300]`. fn report_awesome(r: u32, ) -> Weight { - Weight::from_ref_time(30_669_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(r as u64)) + // Minimum execution time: 35_458 nanoseconds. + Weight::from_ref_time(36_920_009 as u64) + // Standard Error: 252 + .saturating_add(Weight::from_ref_time(1_835 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) fn retract_tip() -> Weight { - Weight::from_ref_time(28_768_000 as u64) + // Minimum execution time: 34_322 nanoseconds. + Weight::from_ref_time(35_292_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Reasons (r:1 w:1) // Storage: Tips Tips (r:0 w:1) + /// The range of component `r` is `[0, 300]`. + /// The range of component `t` is `[1, 13]`. fn tip_new(r: u32, t: u32, ) -> Weight { - Weight::from_ref_time(20_385_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(r as u64)) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(166_000 as u64).saturating_mul(t as u64)) + // Minimum execution time: 26_691 nanoseconds. + Weight::from_ref_time(27_313_497 as u64) + // Standard Error: 141 + .saturating_add(Weight::from_ref_time(818 as u64).saturating_mul(r as u64)) + // Standard Error: 3_352 + .saturating_add(Weight::from_ref_time(108_557 as u64).saturating_mul(t as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Elections Members (r:1 w:0) // Storage: Tips Tips (r:1 w:1) + /// The range of component `t` is `[1, 13]`. fn tip(t: u32, ) -> Weight { - Weight::from_ref_time(12_287_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(363_000 as u64).saturating_mul(t as u64)) + // Minimum execution time: 17_464 nanoseconds. + Weight::from_ref_time(17_621_090 as u64) + // Standard Error: 3_702 + .saturating_add(Weight::from_ref_time(269_919 as u64).saturating_mul(t as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -157,19 +180,23 @@ impl WeightInfo for () { // Storage: Elections Members (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) + /// The range of component `t` is `[1, 13]`. fn close_tip(t: u32, ) -> Weight { - Weight::from_ref_time(45_656_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(276_000 as u64).saturating_mul(t as u64)) + // Minimum execution time: 52_221 nanoseconds. + Weight::from_ref_time(53_168_303 as u64) + // Standard Error: 6_591 + .saturating_add(Weight::from_ref_time(243_706 as u64).saturating_mul(t as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Tips Tips (r:1 w:1) // Storage: Tips Reasons (r:0 w:1) + /// The range of component `t` is `[1, 13]`. fn slash_tip(t: u32, ) -> Weight { - Weight::from_ref_time(18_525_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(t as u64)) + // Minimum execution time: 22_911 nanoseconds. + Weight::from_ref_time(23_750_488 as u64) + // Standard Error: 2_561 + .saturating_add(Weight::from_ref_time(12_282 as u64).saturating_mul(t as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index 6fd9b1b818df6..16d12aa75ab4d 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_transaction_storage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/transaction-storage/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,28 +55,28 @@ pub trait WeightInfo { /// Weights for pallet_transaction_storage using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: TransactionStorage MaxTransactionSize (r:1 w:0) // Storage: TransactionStorage ByteFee (r:1 w:0) // Storage: TransactionStorage EntryFee (r:1 w:0) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: TransactionStorage BlockTransactions (r:1 w:1) - // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) + /// The range of component `l` is `[1, 8388608]`. fn store(l: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(l as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) + // Minimum execution time: 46_730 nanoseconds. + Weight::from_ref_time(46_922_000 as u64) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(5_601 as u64).saturating_mul(l as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: TransactionStorage Transactions (r:1 w:0) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: TransactionStorage ByteFee (r:1 w:0) // Storage: TransactionStorage EntryFee (r:1 w:0) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: TransactionStorage BlockTransactions (r:1 w:1) - // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - Weight::from_ref_time(50_978_000 as u64) - .saturating_add(T::DbWeight::get().reads(6 as u64)) + // Minimum execution time: 56_802 nanoseconds. + Weight::from_ref_time(58_670_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: TransactionStorage ProofChecked (r:1 w:1) @@ -82,7 +85,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - Weight::from_ref_time(106_990_000 as u64) + // Minimum execution time: 74_016 nanoseconds. + Weight::from_ref_time(94_111_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -90,28 +94,28 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: TransactionStorage MaxTransactionSize (r:1 w:0) // Storage: TransactionStorage ByteFee (r:1 w:0) // Storage: TransactionStorage EntryFee (r:1 w:0) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: TransactionStorage BlockTransactions (r:1 w:1) - // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) + /// The range of component `l` is `[1, 8388608]`. fn store(l: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(l as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) + // Minimum execution time: 46_730 nanoseconds. + Weight::from_ref_time(46_922_000 as u64) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(5_601 as u64).saturating_mul(l as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: TransactionStorage Transactions (r:1 w:0) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: TransactionStorage ByteFee (r:1 w:0) // Storage: TransactionStorage EntryFee (r:1 w:0) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: TransactionStorage BlockTransactions (r:1 w:1) - // Storage: TransactionStorage MaxBlockTransactions (r:1 w:0) fn renew() -> Weight { - Weight::from_ref_time(50_978_000 as u64) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) + // Minimum execution time: 56_802 nanoseconds. + Weight::from_ref_time(58_670_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: TransactionStorage ProofChecked (r:1 w:1) @@ -120,7 +124,8 @@ impl WeightInfo for () { // Storage: System ParentHash (r:1 w:0) // Storage: TransactionStorage Transactions (r:1 w:0) fn check_proof_max() -> Weight { - Weight::from_ref_time(106_990_000 as u64) + // Minimum execution time: 74_016 nanoseconds. + Weight::from_ref_time(94_111_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index 37c62e0c18c52..3ee071ac700f1 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_treasury //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/treasury/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,39 +58,41 @@ pub trait WeightInfo { /// Weights for pallet_treasury using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Treasury ProposalCount (r:1 w:1) - // Storage: Treasury Proposals (r:0 w:1) fn spend() -> Weight { - Weight::from_ref_time(22_063_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 137 nanoseconds. + Weight::from_ref_time(153_000 as u64) } // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - Weight::from_ref_time(26_473_000 as u64) + // Minimum execution time: 31_437 nanoseconds. + Weight::from_ref_time(32_241_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - Weight::from_ref_time(29_955_000 as u64) + // Minimum execution time: 38_351 nanoseconds. + Weight::from_ref_time(38_828_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) + /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(10_786_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 11_937 nanoseconds. + Weight::from_ref_time(15_541_763 as u64) + // Standard Error: 1_036 + .saturating_add(Weight::from_ref_time(128_326 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Treasury Approvals (r:1 w:1) fn remove_approval() -> Weight { - Weight::from_ref_time(6_647_000 as u64) + // Minimum execution time: 9_611 nanoseconds. + Weight::from_ref_time(10_012_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -95,10 +100,12 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) + /// The range of component `p` is `[0, 100]`. fn on_initialize_proposals(p: u32, ) -> Weight { - Weight::from_ref_time(25_805_000 as u64) - // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(28_473_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 43_016 nanoseconds. + Weight::from_ref_time(56_538_751 as u64) + // Standard Error: 14_890 + .saturating_add(Weight::from_ref_time(26_789_120 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(p as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) @@ -108,39 +115,41 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Treasury ProposalCount (r:1 w:1) - // Storage: Treasury Proposals (r:0 w:1) fn spend() -> Weight { - Weight::from_ref_time(22_063_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 137 nanoseconds. + Weight::from_ref_time(153_000 as u64) } // Storage: Treasury ProposalCount (r:1 w:1) // Storage: Treasury Proposals (r:0 w:1) fn propose_spend() -> Weight { - Weight::from_ref_time(26_473_000 as u64) + // Minimum execution time: 31_437 nanoseconds. + Weight::from_ref_time(32_241_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Treasury Proposals (r:1 w:1) // Storage: System Account (r:1 w:1) fn reject_proposal() -> Weight { - Weight::from_ref_time(29_955_000 as u64) + // Minimum execution time: 38_351 nanoseconds. + Weight::from_ref_time(38_828_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Treasury Proposals (r:1 w:0) // Storage: Treasury Approvals (r:1 w:1) + /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(10_786_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 11_937 nanoseconds. + Weight::from_ref_time(15_541_763 as u64) + // Standard Error: 1_036 + .saturating_add(Weight::from_ref_time(128_326 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Treasury Approvals (r:1 w:1) fn remove_approval() -> Weight { - Weight::from_ref_time(6_647_000 as u64) + // Minimum execution time: 9_611 nanoseconds. + Weight::from_ref_time(10_012_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -148,10 +157,12 @@ impl WeightInfo for () { // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Treasury Proposals (r:2 w:2) // Storage: System Account (r:4 w:4) + /// The range of component `p` is `[0, 100]`. fn on_initialize_proposals(p: u32, ) -> Weight { - Weight::from_ref_time(25_805_000 as u64) - // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(28_473_000 as u64).saturating_mul(p as u64)) + // Minimum execution time: 43_016 nanoseconds. + Weight::from_ref_time(56_538_751 as u64) + // Standard Error: 14_890 + .saturating_add(Weight::from_ref_time(26_789_120 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(p as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index a134b68d093b6..8a8e1090bb718 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,24 +18,24 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-10-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_uniques // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_uniques -// --chain=dev // --output=./frame/uniques/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -81,16 +81,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - // Minimum execution time: 32_901 nanoseconds. - Weight::from_ref_time(33_628_000 as u64) + // Minimum execution time: 35_358 nanoseconds. + Weight::from_ref_time(35_935_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - // Minimum execution time: 21_633 nanoseconds. - Weight::from_ref_time(22_380_000 as u64) + // Minimum execution time: 22_767 nanoseconds. + Weight::from_ref_time(23_235_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -106,14 +106,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - // Minimum execution time: 2_429_508 nanoseconds. - Weight::from_ref_time(2_446_263_000 as u64) - // Standard Error: 28_236 - .saturating_add(Weight::from_ref_time(8_477_090 as u64).saturating_mul(n as u64)) - // Standard Error: 28_236 - .saturating_add(Weight::from_ref_time(314_268 as u64).saturating_mul(m as u64)) - // Standard Error: 28_236 - .saturating_add(Weight::from_ref_time(249_624 as u64).saturating_mul(a as u64)) + // Minimum execution time: 2_453_194 nanoseconds. + Weight::from_ref_time(2_469_109_000 as u64) + // Standard Error: 27_900 + .saturating_add(Weight::from_ref_time(8_974_176 as u64).saturating_mul(n as u64)) + // Standard Error: 27_900 + .saturating_add(Weight::from_ref_time(344_842 as u64).saturating_mul(m as u64)) + // Standard Error: 27_900 + .saturating_add(Weight::from_ref_time(185_438 as u64).saturating_mul(a as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -126,8 +126,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - // Minimum execution time: 41_938 nanoseconds. - Weight::from_ref_time(42_814_000 as u64) + // Minimum execution time: 45_115 nanoseconds. + Weight::from_ref_time(45_746_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -136,8 +136,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - // Minimum execution time: 43_593 nanoseconds. - Weight::from_ref_time(44_420_000 as u64) + // Minimum execution time: 46_447 nanoseconds. + Weight::from_ref_time(46_994_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -146,8 +146,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - // Minimum execution time: 34_037 nanoseconds. - Weight::from_ref_time(34_848_000 as u64) + // Minimum execution time: 35_953 nanoseconds. + Weight::from_ref_time(36_375_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -155,10 +155,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:102 w:102) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - // Minimum execution time: 23_295 nanoseconds. - Weight::from_ref_time(23_482_000 as u64) - // Standard Error: 9_490 - .saturating_add(Weight::from_ref_time(10_899_320 as u64).saturating_mul(i as u64)) + // Minimum execution time: 24_238 nanoseconds. + Weight::from_ref_time(24_788_000 as u64) + // Standard Error: 9_232 + .saturating_add(Weight::from_ref_time(11_322_011 as u64).saturating_mul(i as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(i as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -167,30 +167,30 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - // Minimum execution time: 27_005 nanoseconds. - Weight::from_ref_time(27_344_000 as u64) + // Minimum execution time: 28_595 nanoseconds. + Weight::from_ref_time(29_280_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - // Minimum execution time: 26_815 nanoseconds. - Weight::from_ref_time(27_400_000 as u64) + // Minimum execution time: 28_581 nanoseconds. + Weight::from_ref_time(29_038_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - // Minimum execution time: 21_988 nanoseconds. - Weight::from_ref_time(22_596_000 as u64) + // Minimum execution time: 24_298 nanoseconds. + Weight::from_ref_time(24_742_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - // Minimum execution time: 21_886 nanoseconds. - Weight::from_ref_time(22_617_000 as u64) + // Minimum execution time: 24_004 nanoseconds. + Weight::from_ref_time(24_536_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -198,23 +198,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - // Minimum execution time: 30_241 nanoseconds. - Weight::from_ref_time(30_677_000 as u64) + // Minimum execution time: 32_599 nanoseconds. + Weight::from_ref_time(33_201_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - // Minimum execution time: 23_011 nanoseconds. - Weight::from_ref_time(23_796_000 as u64) + // Minimum execution time: 25_137 nanoseconds. + Weight::from_ref_time(25_877_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - // Minimum execution time: 25_739 nanoseconds. - Weight::from_ref_time(26_572_000 as u64) + // Minimum execution time: 27_736 nanoseconds. + Weight::from_ref_time(28_279_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -222,8 +222,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - // Minimum execution time: 48_486 nanoseconds. - Weight::from_ref_time(49_029_000 as u64) + // Minimum execution time: 51_195 nanoseconds. + Weight::from_ref_time(51_674_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -231,79 +231,79 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - // Minimum execution time: 47_408 nanoseconds. - Weight::from_ref_time(48_753_000 as u64) + // Minimum execution time: 50_159 nanoseconds. + Weight::from_ref_time(51_412_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - // Minimum execution time: 40_085 nanoseconds. - Weight::from_ref_time(40_625_000 as u64) + // Minimum execution time: 42_608 nanoseconds. + Weight::from_ref_time(42_880_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - // Minimum execution time: 40_546 nanoseconds. - Weight::from_ref_time(41_113_000 as u64) + // Minimum execution time: 43_239 nanoseconds. + Weight::from_ref_time(43_752_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - // Minimum execution time: 39_902 nanoseconds. - Weight::from_ref_time(40_599_000 as u64) + // Minimum execution time: 41_224 nanoseconds. + Weight::from_ref_time(41_974_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - // Minimum execution time: 37_597 nanoseconds. - Weight::from_ref_time(37_964_000 as u64) + // Minimum execution time: 40_836 nanoseconds. + Weight::from_ref_time(41_864_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - // Minimum execution time: 28_719 nanoseconds. - Weight::from_ref_time(29_213_000 as u64) + // Minimum execution time: 29_558 nanoseconds. + Weight::from_ref_time(29_948_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - // Minimum execution time: 27_608 nanoseconds. - Weight::from_ref_time(28_096_000 as u64) + // Minimum execution time: 29_694 nanoseconds. + Weight::from_ref_time(30_156_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - // Minimum execution time: 25_568 nanoseconds. - Weight::from_ref_time(26_098_000 as u64) + // Minimum execution time: 27_819 nanoseconds. + Weight::from_ref_time(28_245_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - // Minimum execution time: 24_521 nanoseconds. - Weight::from_ref_time(25_062_000 as u64) + // Minimum execution time: 26_317 nanoseconds. + Weight::from_ref_time(26_893_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - // Minimum execution time: 25_337 nanoseconds. - Weight::from_ref_time(25_902_000 as u64) + // Minimum execution time: 26_546 nanoseconds. + Weight::from_ref_time(27_142_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -312,8 +312,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - // Minimum execution time: 46_736 nanoseconds. - Weight::from_ref_time(47_264_000 as u64) + // Minimum execution time: 49_238 nanoseconds. + Weight::from_ref_time(50_444_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -324,16 +324,16 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - // Minimum execution time: 32_901 nanoseconds. - Weight::from_ref_time(33_628_000 as u64) + // Minimum execution time: 35_358 nanoseconds. + Weight::from_ref_time(35_935_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - // Minimum execution time: 21_633 nanoseconds. - Weight::from_ref_time(22_380_000 as u64) + // Minimum execution time: 22_767 nanoseconds. + Weight::from_ref_time(23_235_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -349,14 +349,14 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - // Minimum execution time: 2_429_508 nanoseconds. - Weight::from_ref_time(2_446_263_000 as u64) - // Standard Error: 28_236 - .saturating_add(Weight::from_ref_time(8_477_090 as u64).saturating_mul(n as u64)) - // Standard Error: 28_236 - .saturating_add(Weight::from_ref_time(314_268 as u64).saturating_mul(m as u64)) - // Standard Error: 28_236 - .saturating_add(Weight::from_ref_time(249_624 as u64).saturating_mul(a as u64)) + // Minimum execution time: 2_453_194 nanoseconds. + Weight::from_ref_time(2_469_109_000 as u64) + // Standard Error: 27_900 + .saturating_add(Weight::from_ref_time(8_974_176 as u64).saturating_mul(n as u64)) + // Standard Error: 27_900 + .saturating_add(Weight::from_ref_time(344_842 as u64).saturating_mul(m as u64)) + // Standard Error: 27_900 + .saturating_add(Weight::from_ref_time(185_438 as u64).saturating_mul(a as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -369,8 +369,8 @@ impl WeightInfo for () { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - // Minimum execution time: 41_938 nanoseconds. - Weight::from_ref_time(42_814_000 as u64) + // Minimum execution time: 45_115 nanoseconds. + Weight::from_ref_time(45_746_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -379,8 +379,8 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - // Minimum execution time: 43_593 nanoseconds. - Weight::from_ref_time(44_420_000 as u64) + // Minimum execution time: 46_447 nanoseconds. + Weight::from_ref_time(46_994_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -389,8 +389,8 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - // Minimum execution time: 34_037 nanoseconds. - Weight::from_ref_time(34_848_000 as u64) + // Minimum execution time: 35_953 nanoseconds. + Weight::from_ref_time(36_375_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -398,10 +398,10 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:102 w:102) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - // Minimum execution time: 23_295 nanoseconds. - Weight::from_ref_time(23_482_000 as u64) - // Standard Error: 9_490 - .saturating_add(Weight::from_ref_time(10_899_320 as u64).saturating_mul(i as u64)) + // Minimum execution time: 24_238 nanoseconds. + Weight::from_ref_time(24_788_000 as u64) + // Standard Error: 9_232 + .saturating_add(Weight::from_ref_time(11_322_011 as u64).saturating_mul(i as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(i as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) @@ -410,30 +410,30 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - // Minimum execution time: 27_005 nanoseconds. - Weight::from_ref_time(27_344_000 as u64) + // Minimum execution time: 28_595 nanoseconds. + Weight::from_ref_time(29_280_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - // Minimum execution time: 26_815 nanoseconds. - Weight::from_ref_time(27_400_000 as u64) + // Minimum execution time: 28_581 nanoseconds. + Weight::from_ref_time(29_038_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - // Minimum execution time: 21_988 nanoseconds. - Weight::from_ref_time(22_596_000 as u64) + // Minimum execution time: 24_298 nanoseconds. + Weight::from_ref_time(24_742_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - // Minimum execution time: 21_886 nanoseconds. - Weight::from_ref_time(22_617_000 as u64) + // Minimum execution time: 24_004 nanoseconds. + Weight::from_ref_time(24_536_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -441,23 +441,23 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - // Minimum execution time: 30_241 nanoseconds. - Weight::from_ref_time(30_677_000 as u64) + // Minimum execution time: 32_599 nanoseconds. + Weight::from_ref_time(33_201_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - // Minimum execution time: 23_011 nanoseconds. - Weight::from_ref_time(23_796_000 as u64) + // Minimum execution time: 25_137 nanoseconds. + Weight::from_ref_time(25_877_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - // Minimum execution time: 25_739 nanoseconds. - Weight::from_ref_time(26_572_000 as u64) + // Minimum execution time: 27_736 nanoseconds. + Weight::from_ref_time(28_279_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -465,8 +465,8 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - // Minimum execution time: 48_486 nanoseconds. - Weight::from_ref_time(49_029_000 as u64) + // Minimum execution time: 51_195 nanoseconds. + Weight::from_ref_time(51_674_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -474,79 +474,79 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - // Minimum execution time: 47_408 nanoseconds. - Weight::from_ref_time(48_753_000 as u64) + // Minimum execution time: 50_159 nanoseconds. + Weight::from_ref_time(51_412_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - // Minimum execution time: 40_085 nanoseconds. - Weight::from_ref_time(40_625_000 as u64) + // Minimum execution time: 42_608 nanoseconds. + Weight::from_ref_time(42_880_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - // Minimum execution time: 40_546 nanoseconds. - Weight::from_ref_time(41_113_000 as u64) + // Minimum execution time: 43_239 nanoseconds. + Weight::from_ref_time(43_752_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - // Minimum execution time: 39_902 nanoseconds. - Weight::from_ref_time(40_599_000 as u64) + // Minimum execution time: 41_224 nanoseconds. + Weight::from_ref_time(41_974_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - // Minimum execution time: 37_597 nanoseconds. - Weight::from_ref_time(37_964_000 as u64) + // Minimum execution time: 40_836 nanoseconds. + Weight::from_ref_time(41_864_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - // Minimum execution time: 28_719 nanoseconds. - Weight::from_ref_time(29_213_000 as u64) + // Minimum execution time: 29_558 nanoseconds. + Weight::from_ref_time(29_948_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - // Minimum execution time: 27_608 nanoseconds. - Weight::from_ref_time(28_096_000 as u64) + // Minimum execution time: 29_694 nanoseconds. + Weight::from_ref_time(30_156_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - // Minimum execution time: 25_568 nanoseconds. - Weight::from_ref_time(26_098_000 as u64) + // Minimum execution time: 27_819 nanoseconds. + Weight::from_ref_time(28_245_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - // Minimum execution time: 24_521 nanoseconds. - Weight::from_ref_time(25_062_000 as u64) + // Minimum execution time: 26_317 nanoseconds. + Weight::from_ref_time(26_893_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - // Minimum execution time: 25_337 nanoseconds. - Weight::from_ref_time(25_902_000 as u64) + // Minimum execution time: 26_546 nanoseconds. + Weight::from_ref_time(27_142_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -555,8 +555,8 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - // Minimum execution time: 46_736 nanoseconds. - Weight::from_ref_time(47_264_000 as u64) + // Minimum execution time: 49_238 nanoseconds. + Weight::from_ref_time(50_444_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index b88319f2597c9..eac94e44b8dbf 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,12 +18,12 @@ //! Autogenerated weights for pallet_utility //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-06-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,6 +35,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./frame/utility/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -58,27 +59,32 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - Weight::from_ref_time(23_113_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_701_000 as u64).saturating_mul(c as u64)) + // Minimum execution time: 14_470 nanoseconds. + Weight::from_ref_time(17_443_346 as u64) + // Standard Error: 2_037 + .saturating_add(Weight::from_ref_time(3_510_555 as u64).saturating_mul(c as u64)) } fn as_derivative() -> Weight { - Weight::from_ref_time(4_182_000 as u64) + // Minimum execution time: 6_799 nanoseconds. + Weight::from_ref_time(6_976_000 as u64) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - Weight::from_ref_time(18_682_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_794_000 as u64).saturating_mul(c as u64)) + // Minimum execution time: 14_630 nanoseconds. + Weight::from_ref_time(24_580_656 as u64) + // Standard Error: 2_202 + .saturating_add(Weight::from_ref_time(3_584_516 as u64).saturating_mul(c as u64)) } fn dispatch_as() -> Weight { - Weight::from_ref_time(12_049_000 as u64) + // Minimum execution time: 16_597 nanoseconds. + Weight::from_ref_time(16_950_000 as u64) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - Weight::from_ref_time(19_136_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_697_000 as u64).saturating_mul(c as u64)) + // Minimum execution time: 13_885 nanoseconds. + Weight::from_ref_time(20_147_978 as u64) + // Standard Error: 2_232 + .saturating_add(Weight::from_ref_time(3_516_969 as u64).saturating_mul(c as u64)) } } @@ -86,26 +92,31 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - Weight::from_ref_time(23_113_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_701_000 as u64).saturating_mul(c as u64)) + // Minimum execution time: 14_470 nanoseconds. + Weight::from_ref_time(17_443_346 as u64) + // Standard Error: 2_037 + .saturating_add(Weight::from_ref_time(3_510_555 as u64).saturating_mul(c as u64)) } fn as_derivative() -> Weight { - Weight::from_ref_time(4_182_000 as u64) + // Minimum execution time: 6_799 nanoseconds. + Weight::from_ref_time(6_976_000 as u64) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - Weight::from_ref_time(18_682_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_794_000 as u64).saturating_mul(c as u64)) + // Minimum execution time: 14_630 nanoseconds. + Weight::from_ref_time(24_580_656 as u64) + // Standard Error: 2_202 + .saturating_add(Weight::from_ref_time(3_584_516 as u64).saturating_mul(c as u64)) } fn dispatch_as() -> Weight { - Weight::from_ref_time(12_049_000 as u64) + // Minimum execution time: 16_597 nanoseconds. + Weight::from_ref_time(16_950_000 as u64) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - Weight::from_ref_time(19_136_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(2_697_000 as u64).saturating_mul(c as u64)) + // Minimum execution time: 13_885 nanoseconds. + Weight::from_ref_time(20_147_978 as u64) + // Standard Error: 2_232 + .saturating_add(Weight::from_ref_time(3_516_969 as u64).saturating_mul(c as u64)) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index 567d2fef74130..5462445414719 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_vesting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/vesting/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -59,95 +62,119 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_978_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(82_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(88_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 45_113 nanoseconds. + Weight::from_ref_time(44_114_539 as u64) + // Standard Error: 958 + .saturating_add(Weight::from_ref_time(56_239 as u64).saturating_mul(l as u64)) + // Standard Error: 1_704 + .saturating_add(Weight::from_ref_time(64_926 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_856_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(79_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 43_918 nanoseconds. + Weight::from_ref_time(43_452_573 as u64) + // Standard Error: 984 + .saturating_add(Weight::from_ref_time(50_162 as u64).saturating_mul(l as u64)) + // Standard Error: 1_752 + .saturating_add(Weight::from_ref_time(42_080 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(33_522_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(74_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(72_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 43_603 nanoseconds. + Weight::from_ref_time(42_696_097 as u64) + // Standard Error: 996 + .saturating_add(Weight::from_ref_time(65_316 as u64).saturating_mul(l as u64)) + // Standard Error: 1_772 + .saturating_add(Weight::from_ref_time(65_862 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_558_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(61_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 43_099 nanoseconds. + Weight::from_ref_time(42_937_914 as u64) + // Standard Error: 884 + .saturating_add(Weight::from_ref_time(52_079 as u64).saturating_mul(l as u64)) + // Standard Error: 1_573 + .saturating_add(Weight::from_ref_time(36_274 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(49_260_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(l as u64)) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 59_023 nanoseconds. + Weight::from_ref_time(59_606_862 as u64) + // Standard Error: 2_078 + .saturating_add(Weight::from_ref_time(55_335 as u64).saturating_mul(l as u64)) + // Standard Error: 3_698 + .saturating_add(Weight::from_ref_time(26_743 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(49_166_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as u64).saturating_mul(l as u64)) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(43_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 58_249 nanoseconds. + Weight::from_ref_time(59_025_976 as u64) + // Standard Error: 2_078 + .saturating_add(Weight::from_ref_time(55_736 as u64).saturating_mul(l as u64)) + // Standard Error: 3_697 + .saturating_add(Weight::from_ref_time(24_903 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(34_042_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(83_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 45_279 nanoseconds. + Weight::from_ref_time(44_197_440 as u64) + // Standard Error: 946 + .saturating_add(Weight::from_ref_time(62_308 as u64).saturating_mul(l as u64)) + // Standard Error: 1_747 + .saturating_add(Weight::from_ref_time(64_473 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(33_937_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 44_925 nanoseconds. + Weight::from_ref_time(44_219_676 as u64) + // Standard Error: 889 + .saturating_add(Weight::from_ref_time(60_311 as u64).saturating_mul(l as u64)) + // Standard Error: 1_641 + .saturating_add(Weight::from_ref_time(63_095 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -157,95 +184,119 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_978_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(82_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(88_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 45_113 nanoseconds. + Weight::from_ref_time(44_114_539 as u64) + // Standard Error: 958 + .saturating_add(Weight::from_ref_time(56_239 as u64).saturating_mul(l as u64)) + // Standard Error: 1_704 + .saturating_add(Weight::from_ref_time(64_926 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_856_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(79_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 43_918 nanoseconds. + Weight::from_ref_time(43_452_573 as u64) + // Standard Error: 984 + .saturating_add(Weight::from_ref_time(50_162 as u64).saturating_mul(l as u64)) + // Standard Error: 1_752 + .saturating_add(Weight::from_ref_time(42_080 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(33_522_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(74_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(72_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 43_603 nanoseconds. + Weight::from_ref_time(42_696_097 as u64) + // Standard Error: 996 + .saturating_add(Weight::from_ref_time(65_316 as u64).saturating_mul(l as u64)) + // Standard Error: 1_772 + .saturating_add(Weight::from_ref_time(65_862 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_558_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(61_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 43_099 nanoseconds. + Weight::from_ref_time(42_937_914 as u64) + // Standard Error: 884 + .saturating_add(Weight::from_ref_time(52_079 as u64).saturating_mul(l as u64)) + // Standard Error: 1_573 + .saturating_add(Weight::from_ref_time(36_274 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(49_260_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(l as u64)) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(55_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 59_023 nanoseconds. + Weight::from_ref_time(59_606_862 as u64) + // Standard Error: 2_078 + .saturating_add(Weight::from_ref_time(55_335 as u64).saturating_mul(l as u64)) + // Standard Error: 3_698 + .saturating_add(Weight::from_ref_time(26_743 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(49_166_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(77_000 as u64).saturating_mul(l as u64)) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(43_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 58_249 nanoseconds. + Weight::from_ref_time(59_025_976 as u64) + // Standard Error: 2_078 + .saturating_add(Weight::from_ref_time(55_736 as u64).saturating_mul(l as u64)) + // Standard Error: 3_697 + .saturating_add(Weight::from_ref_time(24_903 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(34_042_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(83_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(80_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 45_279 nanoseconds. + Weight::from_ref_time(44_197_440 as u64) + // Standard Error: 946 + .saturating_add(Weight::from_ref_time(62_308 as u64).saturating_mul(l as u64)) + // Standard Error: 1_747 + .saturating_add(Weight::from_ref_time(64_473 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Vesting Vesting (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - Weight::from_ref_time(33_937_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(78_000 as u64).saturating_mul(l as u64)) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(73_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 44_925 nanoseconds. + Weight::from_ref_time(44_219_676 as u64) + // Standard Error: 889 + .saturating_add(Weight::from_ref_time(60_311 as u64).saturating_mul(l as u64)) + // Standard Error: 1_641 + .saturating_add(Weight::from_ref_time(63_095 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index ca474d5e55634..22d238d0fdd0f 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_whitelist //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -32,8 +33,10 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 // --output=./frame/whitelist/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,35 +59,38 @@ impl WeightInfo for SubstrateWeight { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - Weight::from_ref_time(20_938_000 as u64) + // Minimum execution time: 26_352 nanoseconds. + Weight::from_ref_time(26_727_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) fn remove_whitelisted_call() -> Weight { - Weight::from_ref_time(22_332_000 as u64) + // Minimum execution time: 25_536 nanoseconds. + Weight::from_ref_time(25_969_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) fn dispatch_whitelisted_call() -> Weight { - Weight::from_ref_time(5_989_917_000 as u64) + // Minimum execution time: 4_802_466 nanoseconds. + Weight::from_ref_time(4_820_197_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - Weight::from_ref_time(25_325_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 29_184 nanoseconds. + Weight::from_ref_time(30_530_970 as u64) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_496 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } } @@ -93,34 +99,37 @@ impl WeightInfo for () { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - Weight::from_ref_time(20_938_000 as u64) + // Minimum execution time: 26_352 nanoseconds. + Weight::from_ref_time(26_727_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) fn remove_whitelisted_call() -> Weight { - Weight::from_ref_time(22_332_000 as u64) + // Minimum execution time: 25_536 nanoseconds. + Weight::from_ref_time(25_969_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) fn dispatch_whitelisted_call() -> Weight { - Weight::from_ref_time(5_989_917_000 as u64) + // Minimum execution time: 4_802_466 nanoseconds. + Weight::from_ref_time(4_820_197_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - Weight::from_ref_time(25_325_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(n as u64)) + // Minimum execution time: 29_184 nanoseconds. + Weight::from_ref_time(30_530_970 as u64) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_496 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } } From a1dee7ecd2a157c490d189f0932b32aa12106857 Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 8 Nov 2022 21:24:54 +0100 Subject: [PATCH 1357/1472] Remove partial key size limit from trie codec (#12566) * remove size limit from trie codec * test previous upper limit is not enforced anymore * fmt * restore test --- primitives/trie/src/lib.rs | 16 +++++++++++++++- primitives/trie/src/node_codec.rs | 2 -- primitives/trie/src/node_header.rs | 5 +---- primitives/trie/src/trie_stream.rs | 3 +-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index 5634d96d58356..d036db7b1fecd 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -527,7 +527,6 @@ where /// Constants used into trie simplification codec. mod trie_constants { const FIRST_PREFIX: u8 = 0b_00 << 6; - pub const NIBBLE_SIZE_BOUND: usize = u16::max_value() as usize; pub const LEAF_PREFIX_MASK: u8 = 0b_01 << 6; pub const BRANCH_WITHOUT_MASK: u8 = 0b_10 << 6; pub const BRANCH_WITH_MASK: u8 = 0b_11 << 6; @@ -987,6 +986,21 @@ mod tests { assert_eq!(first_storage_root, second_storage_root); } + #[test] + fn big_key() { + let check = |keysize: usize| { + let mut memdb = PrefixedMemoryDB::::default(); + let mut root = Default::default(); + let mut t = TrieDBMutBuilder::::new(&mut memdb, &mut root).build(); + t.insert(&vec![0x01u8; keysize][..], &[0x01u8, 0x23]).unwrap(); + std::mem::drop(t); + let t = TrieDBBuilder::::new(&memdb, &root).build(); + assert_eq!(t.get(&vec![0x01u8; keysize][..]).unwrap(), Some(vec![0x01u8, 0x23])); + }; + check(u16::MAX as usize / 2); // old limit + check(u16::MAX as usize / 2 + 1); // value over old limit still works + } + #[test] fn node_with_no_children_fail_decoding() { let branch = NodeCodec::::branch_node_nibbled( diff --git a/primitives/trie/src/node_codec.rs b/primitives/trie/src/node_codec.rs index 0202b1c6ba7d2..f632320dd296d 100644 --- a/primitives/trie/src/node_codec.rs +++ b/primitives/trie/src/node_codec.rs @@ -279,8 +279,6 @@ fn partial_from_iterator_encode>( nibble_count: usize, node_kind: NodeKind, ) -> Vec { - let nibble_count = sp_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibble_count); - let mut output = Vec::with_capacity(4 + (nibble_count / nibble_ops::NIBBLE_PER_BYTE)); match node_kind { NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output), diff --git a/primitives/trie/src/node_header.rs b/primitives/trie/src/node_header.rs index c2c9510c5ac43..f3544be65b2e9 100644 --- a/primitives/trie/src/node_header.rs +++ b/primitives/trie/src/node_header.rs @@ -117,8 +117,6 @@ pub(crate) fn size_and_prefix_iterator( prefix: u8, prefix_mask: usize, ) -> impl Iterator { - let size = sp_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, size); - let max_value = 255u8 >> prefix_mask; let l1 = sp_std::cmp::min((max_value as usize).saturating_sub(1), size); let (first_byte, mut rem) = if size == l1 { @@ -165,12 +163,11 @@ fn decode_size( return Ok(result) } result -= 1; - while result <= trie_constants::NIBBLE_SIZE_BOUND { + loop { let n = input.read_byte()? as usize; if n < 255 { return Ok(result + n + 1) } result += 255; } - Ok(trie_constants::NIBBLE_SIZE_BOUND) } diff --git a/primitives/trie/src/trie_stream.rs b/primitives/trie/src/trie_stream.rs index ca798db47b552..435e6a986722e 100644 --- a/primitives/trie/src/trie_stream.rs +++ b/primitives/trie/src/trie_stream.rs @@ -54,8 +54,7 @@ fn branch_node_bit_mask(has_children: impl Iterator) -> (u8, u8) { /// Create a leaf/branch node, encoding a number of nibbles. fn fuse_nibbles_node(nibbles: &[u8], kind: NodeKind) -> impl Iterator + '_ { - let size = sp_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibbles.len()); - + let size = nibbles.len(); let iter_start = match kind { NodeKind::Leaf => size_and_prefix_iterator(size, trie_constants::LEAF_PREFIX_MASK, 2), NodeKind::BranchNoValue => From 26e53b4244e34632b401eba4281e8cd14e62087e Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 9 Nov 2022 19:42:30 +1300 Subject: [PATCH 1358/1472] Keep the same name (#12616) Co-authored-by: x --- frame/scheduler/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index b5ea0deeba9a3..3a463b5808cd1 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -277,15 +277,15 @@ pub mod pallet { /// Dispatched some task. Dispatched { task: TaskAddress, - id: Option<[u8; 32]>, + id: Option, result: DispatchResult, }, /// The call for the provided hash was not found so the task has been aborted. - CallUnavailable { task: TaskAddress, id: Option<[u8; 32]> }, + CallUnavailable { task: TaskAddress, id: Option }, /// The given task was unable to be renewed since the agenda is full at that block. - PeriodicFailed { task: TaskAddress, id: Option<[u8; 32]> }, + PeriodicFailed { task: TaskAddress, id: Option }, /// The given task can never be executed since it is overweight. - PermanentlyOverweight { task: TaskAddress, id: Option<[u8; 32]> }, + PermanentlyOverweight { task: TaskAddress, id: Option }, } #[pallet::error] From f9ebd2aeddb47d5c503205be473f522bcc2c7d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 9 Nov 2022 09:22:34 +0100 Subject: [PATCH 1359/1472] Do not finalize parent twice (#12653) If the parent block is alread finalized, we don't need to do this again. --- client/service/src/client/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 438d0b7f77061..1d896d8acd8bf 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -656,7 +656,7 @@ where // Ensure parent chain is finalized to maintain invariant that finality is called // sequentially. - if finalized && parent_exists { + if finalized && parent_exists && info.finalized_hash != parent_hash { self.apply_finality_with_block_hash( operation, parent_hash, From 846e6ea2d43dd5f40d447501138be21eb132d2e5 Mon Sep 17 00:00:00 2001 From: cheme Date: Wed, 9 Nov 2022 09:23:44 +0100 Subject: [PATCH 1360/1472] update paritydb and remove dev deps on rocksdb (#12641) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update paritydb and remove dev deps on rocksdb * feature rocksdb for node testing * feature decl in node-bench * revert change to rocksdb inclusion logic * Update bin/node/bench/Cargo.toml Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher --- Cargo.lock | 45 +++++++++++---------------------------- Cargo.toml | 1 - bin/node/bench/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- 4 files changed, 15 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48205d9bd86da..bec6b0bd976e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -601,16 +601,6 @@ 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 = "blake2b_simd" version = "1.0.0" @@ -1797,7 +1787,7 @@ checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" dependencies = [ "byteorder", "dynasm", - "memmap2 0.5.0", + "memmap2", ] [[package]] @@ -4097,9 +4087,9 @@ dependencies = [ [[package]] name = "lz4" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac20ed6991e01bf6a2e68cc73df2b389707403662a8ba89f68511fb340f724c" +checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" dependencies = [ "libc", "lz4-sys", @@ -4107,9 +4097,9 @@ dependencies = [ [[package]] name = "lz4-sys" -version = "1.9.2" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca79aa95d8b3226213ad454d328369853be3a1382d89532a854f4d69640acae" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" dependencies = [ "cc", "libc", @@ -4185,15 +4175,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "memmap2" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e3e85b970d650e2ae6d70592474087051c11c54da7f7b4949725c5735fbcc6" -dependencies = [ - "libc", -] - [[package]] name = "memmap2" version = "0.5.0" @@ -6451,19 +6432,19 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.16" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb474d0ed0836e185cb998a6b140ed1073d1fbf27d690ecf9ede8030289382c" +checksum = "3a7511a0bec4a336b5929999d02b560d2439c993cccf98c26481484e811adc43" dependencies = [ - "blake2-rfc", + "blake2", "crc32fast", "fs2", "hex", "libc", "log", "lz4", - "memmap2 0.2.1", - "parking_lot 0.11.2", + "memmap2", + "parking_lot 0.12.1", "rand 0.8.5", "snap", ] @@ -7694,7 +7675,7 @@ name = "sc-chain-spec" version = "4.0.0-dev" dependencies = [ "impl-trait-for-tuples", - "memmap2 0.5.0", + "memmap2", "parity-scale-codec", "sc-chain-spec-derive", "sc-network-common", @@ -11167,7 +11148,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "digest 0.10.3", "rand 0.8.5", "static_assertions", @@ -11615,7 +11596,7 @@ dependencies = [ "enumset", "lazy_static", "loupe", - "memmap2 0.5.0", + "memmap2", "more-asserts", "rustc-demangle", "serde", diff --git a/Cargo.toml b/Cargo.toml index d3c801fc2c7be..45aa5f9854d25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -254,7 +254,6 @@ members = [ # This list is ordered alphabetically. [profile.dev.package] blake2 = { opt-level = 3 } -blake2-rfc = { opt-level = 3 } blake2b_simd = { opt-level = 3 } chacha20poly1305 = { opt-level = 3 } cranelift-codegen = { opt-level = 3 } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 54a1d4900c60b..5fb4c418e8ae8 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -38,7 +38,7 @@ fs_extra = "1" rand = { version = "0.7.2", features = ["small_rng"] } lazy_static = "1.4.0" parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } -parity-db = { version = "0.3" } +parity-db = "0.4.2" sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } futures = { version = "0.3.21", features = ["thread-pool"] } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index b21038b77564f..c12bf933f6bb1 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -22,7 +22,7 @@ kvdb-memorydb = "0.12.0" kvdb-rocksdb = { version = "0.16.0", optional = true } linked-hash-map = "0.5.4" log = "0.4.17" -parity-db = "0.3.16" +parity-db = "0.4.2" parking_lot = "0.12.1" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } From daf72d122d183bfe3d75eefd1bc3766794e9ed06 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 9 Nov 2022 09:50:36 +0100 Subject: [PATCH 1361/1472] Epoch-Changes tree pruning was lagging by one epoch (#12567) * Remove all not required nodes from the epoch-changes tree Some outdated nodes were left there because of the predicate * Test to excercise the fix * Add a fork on genesis to the test * Fix typo in comments --- client/consensus/babe/src/tests.rs | 60 ++++++------------ client/consensus/epochs/src/lib.rs | 97 +++++++++++++++++++++++++++--- 2 files changed, 110 insertions(+), 47 deletions(-) diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index ee1605f037ff4..a2886663b2c8f 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -869,12 +869,12 @@ fn importing_epoch_change_block_prunes_tree() { // Create and import the canon chain and keep track of fork blocks (A, C, D) // from the diagram above. - let canon_hashes = propose_and_import_blocks_wrap(BlockId::Number(0), 30); + let canon = propose_and_import_blocks_wrap(BlockId::Number(0), 30); // Create the forks - let fork_1 = propose_and_import_blocks_wrap(BlockId::Hash(canon_hashes[0]), 10); - let fork_2 = propose_and_import_blocks_wrap(BlockId::Hash(canon_hashes[12]), 15); - let fork_3 = propose_and_import_blocks_wrap(BlockId::Hash(canon_hashes[18]), 10); + let fork_1 = propose_and_import_blocks_wrap(BlockId::Hash(canon[0]), 10); + let fork_2 = propose_and_import_blocks_wrap(BlockId::Hash(canon[12]), 15); + let fork_3 = propose_and_import_blocks_wrap(BlockId::Hash(canon[18]), 10); // We should be tracking a total of 9 epochs in the fork tree assert_eq!(epoch_changes.shared_data().tree().iter().count(), 9); @@ -884,51 +884,31 @@ fn importing_epoch_change_block_prunes_tree() { // We finalize block #13 from the canon chain, so on the next epoch // change the tree should be pruned, to not contain F (#7). - client.finalize_block(canon_hashes[12], None, false).unwrap(); + client.finalize_block(canon[12], None, false).unwrap(); propose_and_import_blocks_wrap(BlockId::Hash(client.chain_info().best_hash), 7); - // at this point no hashes from the first fork must exist on the tree - assert!(!epoch_changes - .shared_data() - .tree() - .iter() - .map(|(h, _, _)| h) - .any(|h| fork_1.contains(h)),); + let nodes: Vec<_> = epoch_changes.shared_data().tree().iter().map(|(h, _, _)| *h).collect(); - // but the epoch changes from the other forks must still exist - assert!(epoch_changes - .shared_data() - .tree() - .iter() - .map(|(h, _, _)| h) - .any(|h| fork_2.contains(h))); + // no hashes from the first fork must exist on the tree + assert!(!nodes.iter().any(|h| fork_1.contains(h))); - assert!(epoch_changes - .shared_data() - .tree() - .iter() - .map(|(h, _, _)| h) - .any(|h| fork_3.contains(h)),); + // but the epoch changes from the other forks must still exist + assert!(nodes.iter().any(|h| fork_2.contains(h))); + assert!(nodes.iter().any(|h| fork_3.contains(h))); // finalizing block #25 from the canon chain should prune out the second fork - client.finalize_block(canon_hashes[24], None, false).unwrap(); + client.finalize_block(canon[24], None, false).unwrap(); propose_and_import_blocks_wrap(BlockId::Hash(client.chain_info().best_hash), 8); - // at this point no hashes from the second fork must exist on the tree - assert!(!epoch_changes - .shared_data() - .tree() - .iter() - .map(|(h, _, _)| h) - .any(|h| fork_2.contains(h)),); + let nodes: Vec<_> = epoch_changes.shared_data().tree().iter().map(|(h, _, _)| *h).collect(); - // while epoch changes from the last fork should still exist - assert!(epoch_changes - .shared_data() - .tree() - .iter() - .map(|(h, _, _)| h) - .any(|h| fork_3.contains(h)),); + // no hashes from the other forks must exist on the tree + assert!(!nodes.iter().any(|h| fork_2.contains(h))); + assert!(!nodes.iter().any(|h| fork_3.contains(h))); + + // Check that we contain the nodes that we care about + assert!(nodes.iter().any(|h| *h == canon[18])); + assert!(nodes.iter().any(|h| *h == canon[24])); } #[test] diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index 2e0186495db5e..f8b6253ef2353 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -518,8 +518,8 @@ where let is_descendent_of = descendent_of_builder.build_is_descendent_of(None); let predicate = |epoch: &PersistedEpochHeader| match *epoch { - PersistedEpochHeader::Genesis(_, ref epoch_1) => slot >= epoch_1.end_slot, - PersistedEpochHeader::Regular(ref epoch_n) => slot >= epoch_n.end_slot, + PersistedEpochHeader::Genesis(ref epoch_0, _) => epoch_0.start_slot <= slot, + PersistedEpochHeader::Regular(ref epoch_n) => epoch_n.start_slot <= slot, }; // prune any epochs which could not be _live_ as of the children of the @@ -777,11 +777,6 @@ where } } - /// Return the inner fork tree. - pub fn tree(&self) -> &ForkTree> { - &self.inner - } - /// Reset to a specified pair of epochs, as if they were announced at blocks `parent_hash` and /// `hash`. pub fn reset(&mut self, parent_hash: Hash, hash: Hash, number: Number, current: E, next: E) { @@ -832,6 +827,11 @@ where self.epochs.remove(&(h, n)); }); } + + /// Return the inner fork tree (mostly useful for testing) + pub fn tree(&self) -> &ForkTree> { + &self.inner + } } /// Type alias to produce the epoch-changes tree from a block type. @@ -1114,6 +1114,89 @@ mod tests { } } + #[test] + fn prune_removes_stale_nodes() { + // +---D +-------F + // | | + // 0---A---B--(x)--C--(y)--G + // | | + // +---H +-------E + // + // Test parameters: + // - epoch duration: 100 + // + // We are going to prune the tree at: + // - 'x', a node between B and C + // - 'y', a node between C and G + + let is_descendent_of = |base: &Hash, block: &Hash| -> Result { + match (base, block) { + (b"0", _) => Ok(true), + (b"A", b) => Ok(b != b"0"), + (b"B", b) => Ok(b != b"0" && b != b"A" && b != b"D"), + (b"C", b) => Ok(b == b"F" || b == b"G" || b == b"y"), + (b"x", b) => Ok(b == b"C" || b == b"F" || b == b"G" || b == b"y"), + (b"y", b) => Ok(b == b"G"), + _ => Ok(false), + } + }; + + let mut epoch_changes = EpochChanges::new(); + + let mut import_at = |slot, hash: &Hash, number, parent_hash, parent_number| { + let make_genesis = |slot| Epoch { start_slot: slot, duration: 100 }; + // Get epoch descriptor valid for 'slot' + let epoch_descriptor = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, parent_hash, parent_number, slot) + .unwrap() + .unwrap(); + // Increment it + let next_epoch_desc = epoch_changes + .viable_epoch(&epoch_descriptor, &make_genesis) + .unwrap() + .increment(()); + // Assign it to hash/number + epoch_changes + .import(&is_descendent_of, *hash, number, *parent_hash, next_epoch_desc) + .unwrap(); + }; + + import_at(100, b"A", 10, b"0", 0); + import_at(200, b"B", 20, b"A", 10); + import_at(300, b"C", 30, b"B", 20); + import_at(200, b"D", 20, b"A", 10); + import_at(300, b"E", 30, b"B", 20); + import_at(400, b"F", 40, b"C", 30); + import_at(400, b"G", 40, b"C", 30); + import_at(100, b"H", 10, b"0", 0); + + let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect(); + nodes.sort(); + assert_eq!(nodes, vec![b"A", b"B", b"C", b"D", b"E", b"F", b"G", b"H"]); + + // Finalize block 'x' @ number 25, slot 230 + // This should prune all nodes imported by blocks with a number < 25 that are not + // ancestors of 'x' and all nodes before the one holding the epoch information + // to which 'x' belongs to (i.e. before A). + + epoch_changes.prune_finalized(&is_descendent_of, b"x", 25, 230).unwrap(); + + let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect(); + nodes.sort(); + assert_eq!(nodes, vec![b"A", b"B", b"C", b"E", b"F", b"G"]); + + // Finalize block y @ number 35, slot 330 + // This should prune all nodes imported by blocks with a number < 35 that are not + // ancestors of 'y' and all nodes before the one holding the epoch information + // to which 'y' belongs to (i.e. before B). + + epoch_changes.prune_finalized(&is_descendent_of, b"y", 35, 330).unwrap(); + + let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect(); + nodes.sort(); + assert_eq!(nodes, vec![b"B", b"C", b"F", b"G"]); + } + /// Test that ensures that the gap is not enabled when we import multiple genesis blocks. #[test] fn gap_is_not_enabled_when_multiple_genesis_epochs_are_imported() { From cbb48e5e503300817b6837d6597659ed35212e99 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Wed, 9 Nov 2022 10:11:51 +0100 Subject: [PATCH 1362/1472] Bound Election and Staking by MaxActiveValidators (#12436) * bounding election provider with kian * multi phase implement bounded election provider * election provider blanket implementation * staking compiles * fix test for election provider support * fmt * fixing epmp tests, does not compile yet * fix epmp tests * fix staking tests * fmt * fix runtime tests * fmt * remove outdated wip tags * add enum error * sort and truncate supports * comment * error when unsupported number of election winners * compiling wip after kian's suggestions * fix TODOs * remove,fix tags * ensure validator count does not exceed maxwinners * clean up * some more clean up and todos * handle too many winners * rename parameter for mock * todo * add sort and truncate rule if there are too many winners * fmt * fail, not swallow emergency result bound not met * remove too many winners resolution as it can be guaranteed to be bounded * fix benchmark * give MaxWinners more contextual name * make ready solution generic over T * kian feedback * fix stuff * Kian's way of solvign this * comment fix * fix compile * remove use of BoundedExecution * fmt * comment out failing integrity test * cap validator count increment to max winners * dont panic * add test for bad data provider * Update frame/staking/src/pallet/impls.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fix namespace conflict and add test for onchain max winners less than desired targets * defensive unwrap * early convert to bounded vec * fix syntax * fmt * fix doc * fix rustdoc * fmt * fix maxwinner count for benchmarking * add instant election for noelection * fmt * fix compile * pr feedbacks * always error at validator count exceeding max winners * add useful error message * pr comments * import fix * add checked_desired_targets * fmt * fmt * fix rust doc Co-authored-by: parity-processbot <> Co-authored-by: kianenigma Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- bin/node/runtime/src/lib.rs | 26 ++- frame/babe/src/mock.rs | 5 +- .../src/benchmarking.rs | 8 +- .../election-provider-multi-phase/src/lib.rs | 164 ++++++++-------- .../election-provider-multi-phase/src/mock.rs | 49 ++--- .../src/signed.rs | 48 ++++- frame/election-provider-support/src/lib.rs | 137 ++++++++------ .../election-provider-support/src/onchain.rs | 178 +++++++++--------- frame/fast-unstake/src/mock.rs | 9 +- frame/grandpa/src/mock.rs | 5 +- .../nomination-pools/benchmarking/src/mock.rs | 2 +- .../nomination-pools/test-staking/src/mock.rs | 2 +- frame/offences/benchmarking/src/mock.rs | 5 +- frame/root-offences/src/mock.rs | 5 +- frame/session/benchmarking/src/mock.rs | 5 +- frame/staking/src/lib.rs | 4 + frame/staking/src/mock.rs | 6 +- frame/staking/src/pallet/impls.rs | 79 +++++--- frame/staking/src/pallet/mod.rs | 55 +++++- frame/staking/src/tests.rs | 54 ++++++ primitives/npos-elections/src/lib.rs | 4 +- 21 files changed, 538 insertions(+), 312 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 999b178d10c55..d94a31422be8b 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -570,7 +570,7 @@ impl pallet_staking::Config for Runtime { type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; - type GenesisElectionProvider = onchain::UnboundedExecution; + type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; // This a placeholder, to be introduced in the next PR as an instance of bags-list type TargetList = pallet_staking::UseValidatorsMap; @@ -628,7 +628,14 @@ frame_election_provider_support::generate_solution_type!( parameter_types! { pub MaxNominations: u32 = ::LIMIT as u32; - pub MaxElectingVoters: u32 = 10_000; + pub MaxElectingVoters: u32 = 40_000; + pub MaxElectableTargets: u16 = 10_000; + // OnChain values are lower. + pub MaxOnChainElectingVoters: u32 = 5000; + pub MaxOnChainElectableTargets: u16 = 1250; + // The maximum winners that can be elected by the Election pallet which is equivalent to the + // maximum active validators the staking pallet can have. + pub MaxActiveValidators: u32 = 1000; } /// The numbers configured here could always be more than the the maximum limits of staking pallet @@ -679,11 +686,9 @@ impl onchain::Config for OnChainSeqPhragmen { >; type DataProvider = ::DataProvider; type WeightInfo = frame_election_provider_support::weights::SubstrateWeight; -} - -impl onchain::BoundedConfig for OnChainSeqPhragmen { - type VotersBound = MaxElectingVoters; - type TargetsBound = ConstU32<2_000>; + type MaxWinners = ::MaxWinners; + type VotersBound = MaxOnChainElectingVoters; + type TargetsBound = MaxOnChainElectableTargets; } impl pallet_election_provider_multi_phase::MinerConfig for Runtime { @@ -726,11 +731,12 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type SlashHandler = (); // burn slashes type RewardHandler = (); // nothing to do upon rewards type DataProvider = Staking; - type Fallback = onchain::BoundedExecution; - type GovernanceFallback = onchain::BoundedExecution; + type Fallback = onchain::OnChainExecution; + type GovernanceFallback = onchain::OnChainExecution; type Solver = SequentialPhragmen, OffchainRandomBalancing>; type ForceOrigin = EnsureRootOrHalfCouncil; - type MaxElectableTargets = ConstU16<{ u16::MAX }>; + type MaxElectableTargets = MaxElectableTargets; + type MaxWinners = MaxActiveValidators; type MaxElectingVoters = MaxElectingVoters; type BenchmarkingConfig = ElectionProviderBenchmarkConfig; type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 46aeabe743fe2..204de8aae172e 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -178,6 +178,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); + type MaxWinners = ConstU32<100>; + type VotersBound = ConstU32<{ u32::MAX }>; + type TargetsBound = ConstU32<{ u32::MAX }>; } impl pallet_staking::Config for Test { @@ -199,7 +202,7 @@ impl pallet_staking::Config for Test { type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; - type ElectionProvider = onchain::UnboundedExecution; + type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index a0fd0a9a0512f..10041f6aec07c 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -220,11 +220,7 @@ frame_benchmarking::benchmarks! { let receiver = account("receiver", 0, SEED); let initial_balance = T::Currency::minimum_balance() * 10u32.into(); T::Currency::make_free_balance_be(&receiver, initial_balance); - let ready = ReadySolution { - supports: vec![], - score: Default::default(), - compute: Default::default() - }; + let ready = Default::default(); let deposit: BalanceOf = 10u32.into(); let reward: BalanceOf = T::SignedRewardBase::get(); @@ -403,7 +399,7 @@ frame_benchmarking::benchmarks! { assert_eq!(raw_solution.solution.voter_count() as u32, a); assert_eq!(raw_solution.solution.unique_targets().len() as u32, d); }: { - assert_ok!(>::feasibility_check(raw_solution, ElectionCompute::Unsigned)); + assert!(>::feasibility_check(raw_solution, ElectionCompute::Unsigned).is_ok()); } // NOTE: this weight is not used anywhere, but the fact that it should succeed when execution in diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 3e5a6d12f575c..bc19e5143424c 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -114,8 +114,8 @@ //! If we reach the end of both phases (i.e. call to [`ElectionProvider::elect`] happens) and no //! good solution is queued, then the fallback strategy [`pallet::Config::Fallback`] is used to //! determine what needs to be done. The on-chain election is slow, and contains no balancing or -//! reduction post-processing. [`NoFallback`] does nothing and enables [`Phase::Emergency`], which -//! is a more *fail-safe* approach. +//! reduction post-processing. If [`pallet::Config::Fallback`] fails, the next phase +//! [`Phase::Emergency`] is enabled, which is a more *fail-safe* approach. //! //! ### Emergency Phase //! @@ -231,23 +231,25 @@ use codec::{Decode, Encode}; use frame_election_provider_support::{ - ElectionDataProvider, ElectionProvider, ElectionProviderBase, InstantElectionProvider, - NposSolution, + BoundedSupportsOf, ElectionDataProvider, ElectionProvider, ElectionProviderBase, + InstantElectionProvider, NposSolution, }; use frame_support::{ dispatch::DispatchClass, ensure, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, weights::Weight, + DefaultNoBound, EqNoBound, PartialEqNoBound, }; use frame_system::{ensure_none, offchain::SendTransactionTypes}; use scale_info::TypeInfo; use sp_arithmetic::{ - traits::{Bounded, CheckedAdd, Zero}, + traits::{CheckedAdd, Zero}, UpperOf, }; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, ElectionScore, EvaluateSupport, Supports, VoteWeight, + assignment_ratio_to_staked_normalized, BoundedSupports, ElectionScore, EvaluateSupport, + Supports, VoteWeight, }; use sp_runtime::{ transaction_validity::{ @@ -311,33 +313,6 @@ pub trait BenchmarkingConfig { const MAXIMUM_TARGETS: u32; } -/// A fallback implementation that transitions the pallet to the emergency phase. -pub struct NoFallback(sp_std::marker::PhantomData); - -impl ElectionProviderBase for NoFallback { - type AccountId = T::AccountId; - type BlockNumber = T::BlockNumber; - type DataProvider = T::DataProvider; - type Error = &'static str; - - fn ongoing() -> bool { - false - } -} - -impl ElectionProvider for NoFallback { - fn elect() -> Result, Self::Error> { - // Do nothing, this will enable the emergency phase. - Err("NoFallback.") - } -} - -impl InstantElectionProvider for NoFallback { - fn elect_with_bounds(_: usize, _: usize) -> Result, Self::Error> { - Err("NoFallback.") - } -} - /// Current phase of the pallet. #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] pub enum Phase { @@ -445,13 +420,23 @@ impl Default for RawSolution { } /// A checked solution, ready to be enacted. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default, TypeInfo)] -pub struct ReadySolution { +#[derive( + PartialEqNoBound, + EqNoBound, + Clone, + Encode, + Decode, + RuntimeDebug, + DefaultNoBound, + scale_info::TypeInfo, +)] +#[scale_info(skip_type_params(T))] +pub struct ReadySolution { /// The final supports of the solution. /// /// This is target-major vector, storing each winners, total backing, and each individual /// backer. - pub supports: Supports, + pub supports: BoundedSupports, /// The score of the solution. /// /// This is needed to potentially challenge the solution. @@ -465,7 +450,6 @@ pub struct ReadySolution { /// /// These are stored together because they are often accessed together. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default, TypeInfo)] -#[codec(mel_bound())] #[scale_info(skip_type_params(T))] pub struct RoundSnapshot { /// All of the voters. @@ -561,6 +545,8 @@ pub enum FeasibilityError { InvalidRound, /// Comparison against `MinimumUntrustedScore` failed. UntrustedScoreTooLow, + /// Data Provider returned too many desired targets + TooManyDesiredTargets, } impl From for FeasibilityError { @@ -574,7 +560,10 @@ pub use pallet::*; pub mod pallet { use super::*; use frame_election_provider_support::{InstantElectionProvider, NposSolver}; - use frame_support::{pallet_prelude::*, traits::EstimateCallFee}; + use frame_support::{ + pallet_prelude::*, + traits::{DefensiveResult, EstimateCallFee}, + }; use frame_system::pallet_prelude::*; #[pallet::config] @@ -674,6 +663,13 @@ pub mod pallet { #[pallet::constant] type MaxElectableTargets: Get>; + /// The maximum number of winners that can be elected by this `ElectionProvider` + /// implementation. + /// + /// Note: This must always be greater or equal to `T::DataProvider::desired_targets()`. + #[pallet::constant] + type MaxWinners: Get; + /// Handler for the slashed deposits. type SlashHandler: OnUnbalanced>; @@ -691,6 +687,7 @@ pub mod pallet { AccountId = Self::AccountId, BlockNumber = Self::BlockNumber, DataProvider = Self::DataProvider, + MaxWinners = Self::MaxWinners, >; /// Configuration of the governance-only fallback. @@ -701,6 +698,7 @@ pub mod pallet { AccountId = Self::AccountId, BlockNumber = Self::BlockNumber, DataProvider = Self::DataProvider, + MaxWinners = Self::MaxWinners, >; /// OCW election solution miner algorithm implementation. @@ -968,9 +966,11 @@ pub mod pallet { T::ForceOrigin::ensure_origin(origin)?; ensure!(Self::current_phase().is_emergency(), >::CallNotAllowed); + // bound supports with T::MaxWinners + let supports = supports.try_into().map_err(|_| Error::::TooManyWinners)?; + // Note: we don't `rotate_round` at this point; the next call to // `ElectionProvider::elect` will succeed and take care of that. - let solution = ReadySolution { supports, score: Default::default(), @@ -1073,17 +1073,20 @@ pub mod pallet { T::ForceOrigin::ensure_origin(origin)?; ensure!(Self::current_phase().is_emergency(), >::CallNotAllowed); - let maybe_max_voters = maybe_max_voters.map(|x| x as usize); - let maybe_max_targets = maybe_max_targets.map(|x| x as usize); + let supports = + T::GovernanceFallback::instant_elect(maybe_max_voters, maybe_max_targets).map_err( + |e| { + log!(error, "GovernanceFallback failed: {:?}", e); + Error::::FallbackFailed + }, + )?; - let supports = T::GovernanceFallback::elect_with_bounds( - maybe_max_voters.unwrap_or(Bounded::max_value()), - maybe_max_targets.unwrap_or(Bounded::max_value()), - ) - .map_err(|e| { - log!(error, "GovernanceFallback failed: {:?}", e); - Error::::FallbackFailed - })?; + // transform BoundedVec<_, T::GovernanceFallback::MaxWinners> into + // `BoundedVec<_, T::MaxWinners>` + let supports: BoundedVec<_, T::MaxWinners> = supports + .into_inner() + .try_into() + .defensive_map_err(|_| Error::::BoundNotMet)?; let solution = ReadySolution { supports, @@ -1154,6 +1157,10 @@ pub mod pallet { CallNotAllowed, /// The fallback failed FallbackFailed, + /// Some bound not met + BoundNotMet, + /// Submitted solution has too many winners + TooManyWinners, } #[pallet::validate_unsigned] @@ -1227,7 +1234,7 @@ pub mod pallet { /// Current best solution, signed or unsigned, queued to be returned upon `elect`. #[pallet::storage] #[pallet::getter(fn queued_solution)] - pub type QueuedSolution = StorageValue<_, ReadySolution>; + pub type QueuedSolution = StorageValue<_, ReadySolution>; /// Snapshot data of the round. /// @@ -1393,31 +1400,28 @@ impl Pallet { let targets = T::DataProvider::electable_targets(Some(target_limit)) .map_err(ElectionError::DataProvider)?; + let voters = T::DataProvider::electing_voters(Some(voter_limit)) .map_err(ElectionError::DataProvider)?; - let mut desired_targets = - T::DataProvider::desired_targets().map_err(ElectionError::DataProvider)?; - // Defensive-only. if targets.len() > target_limit || voters.len() > voter_limit { - debug_assert!(false, "Snapshot limit has not been respected."); return Err(ElectionError::DataProvider("Snapshot too big for submission.")) } - // If `desired_targets` > `targets.len()`, cap `desired_targets` to that level and emit a - // warning - let max_len = targets - .len() - .try_into() - .map_err(|_| ElectionError::DataProvider("Failed to convert usize"))?; - if desired_targets > max_len { + let mut desired_targets = + T::DataProvider::desired_targets().map_err(ElectionError::DataProvider)?; + + // If `desired_targets` > `targets.len()`, cap `desired_targets` to that + // level and emit a warning + let max_desired_targets: u32 = (targets.len() as u32).min(T::MaxWinners::get()); + if desired_targets > max_desired_targets { log!( warn, "desired_targets: {} > targets.len(): {}, capping desired_targets", desired_targets, - max_len + max_desired_targets ); - desired_targets = max_len; + desired_targets = max_desired_targets; } Ok((targets, voters, desired_targets)) @@ -1466,7 +1470,7 @@ impl Pallet { pub fn feasibility_check( raw_solution: RawSolution>, compute: ElectionCompute, - ) -> Result, FeasibilityError> { + ) -> Result, FeasibilityError> { let RawSolution { solution, score, round } = raw_solution; // First, check round. @@ -1479,6 +1483,11 @@ impl Pallet { Self::desired_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; ensure!(winners.len() as u32 == desired_targets, FeasibilityError::WrongWinnerCount); + // Fail early if targets requested by data provider exceed maximum winners supported. + ensure!( + desired_targets <= ::MaxWinners::get(), + FeasibilityError::TooManyDesiredTargets + ); // Ensure that the solution's score can pass absolute min-score. let submitted_score = raw_solution.score; @@ -1539,6 +1548,8 @@ impl Pallet { let known_score = supports.evaluate(); ensure!(known_score == score, FeasibilityError::InvalidScore); + // Size of winners in miner solution is equal to `desired_targets` <= `MaxWinners`. + let supports = supports.try_into().expect("checked desired_targets <= MaxWinners; qed"); Ok(ReadySolution { supports, compute, score }) } @@ -1558,7 +1569,7 @@ impl Pallet { Self::kill_snapshot(); } - fn do_elect() -> Result, ElectionError> { + fn do_elect() -> Result, ElectionError> { // We have to unconditionally try finalizing the signed phase here. There are only two // possibilities: // @@ -1570,13 +1581,15 @@ impl Pallet { >::take() .ok_or(ElectionError::::NothingQueued) .or_else(|_| { - ::elect() - .map(|supports| ReadySolution { - supports, - score: Default::default(), - compute: ElectionCompute::Fallback, - }) + T::Fallback::instant_elect(None, None) .map_err(|fe| ElectionError::Fallback(fe)) + .and_then(|supports| { + Ok(ReadySolution { + supports, + score: Default::default(), + compute: ElectionCompute::Fallback, + }) + }) }) .map(|ReadySolution { compute, score, supports }| { Self::deposit_event(Event::ElectionFinalized { compute, score }); @@ -1609,18 +1622,19 @@ impl ElectionProviderBase for Pallet { type AccountId = T::AccountId; type BlockNumber = T::BlockNumber; type Error = ElectionError; + type MaxWinners = T::MaxWinners; type DataProvider = T::DataProvider; +} +impl ElectionProvider for Pallet { fn ongoing() -> bool { match Self::current_phase() { Phase::Off => false, _ => true, } } -} -impl ElectionProvider for Pallet { - fn elect() -> Result, Self::Error> { + fn elect() -> Result, Self::Error> { match Self::do_elect() { Ok(supports) => { // All went okay, record the weight, put sign to be Off, clean snapshot, etc. @@ -1636,6 +1650,7 @@ impl ElectionProvider for Pallet { } } } + /// convert a DispatchError to a custom InvalidTransaction with the inner code being the error /// number. pub fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { @@ -1854,7 +1869,6 @@ mod tests { }, Phase, }; - use frame_election_provider_support::ElectionProvider; use frame_support::{assert_noop, assert_ok}; use sp_npos_elections::{BalancingConfig, Support}; diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index f645886d78899..8ab7e5bbf733d 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -19,7 +19,7 @@ use super::*; use crate::{self as multi_phase, unsigned::MinerConfig}; use frame_election_provider_support::{ data_provider, - onchain::{self, UnboundedExecution}, + onchain::{self}, ElectionDataProvider, NposSolution, SequentialPhragmen, }; pub use frame_support::{assert_noop, assert_ok, pallet_prelude::GetDefault}; @@ -297,6 +297,7 @@ parameter_types! { pub static MockWeightInfo: MockedWeightInfo = MockedWeightInfo::Real; pub static MaxElectingVoters: VoterIndex = u32::max_value(); pub static MaxElectableTargets: TargetIndex = TargetIndex::max_value(); + pub static MaxWinners: u32 = 200; pub static EpochLength: u64 = 30; pub static OnChainFallback: bool = true; @@ -308,6 +309,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen, Balancing>; type DataProvider = StakingMock; type WeightInfo = (); + type MaxWinners = MaxWinners; + type VotersBound = ConstU32<{ u32::MAX }>; + type TargetsBound = ConstU32<{ u32::MAX }>; } pub struct MockFallback; @@ -316,30 +320,19 @@ impl ElectionProviderBase for MockFallback { type BlockNumber = u64; type Error = &'static str; type DataProvider = StakingMock; - - fn ongoing() -> bool { - false - } -} -impl ElectionProvider for MockFallback { - fn elect() -> Result, Self::Error> { - Self::elect_with_bounds(Bounded::max_value(), Bounded::max_value()) - } + type MaxWinners = MaxWinners; } impl InstantElectionProvider for MockFallback { - fn elect_with_bounds( - max_voters: usize, - max_targets: usize, - ) -> Result, Self::Error> { + fn instant_elect( + max_voters: Option, + max_targets: Option, + ) -> Result, Self::Error> { if OnChainFallback::get() { - onchain::UnboundedExecution::::elect_with_bounds( - max_voters, - max_targets, - ) - .map_err(|_| "onchain::UnboundedExecution failed.") + onchain::OnChainExecution::::instant_elect(max_voters, max_targets) + .map_err(|_| "onchain::OnChainExecution failed.") } else { - super::NoFallback::::elect_with_bounds(max_voters, max_targets) + Err("NoFallback.") } } } @@ -404,10 +397,12 @@ impl crate::Config for Runtime { type WeightInfo = (); type BenchmarkingConfig = TestBenchmarkingConfig; type Fallback = MockFallback; - type GovernanceFallback = UnboundedExecution; + type GovernanceFallback = + frame_election_provider_support::onchain::OnChainExecution; type ForceOrigin = frame_system::EnsureRoot; type MaxElectingVoters = MaxElectingVoters; type MaxElectableTargets = MaxElectableTargets; + type MaxWinners = MaxWinners; type MinerConfig = Self; type Solver = SequentialPhragmen, Balancing>; } @@ -424,6 +419,8 @@ pub type Extrinsic = sp_runtime::testing::TestXt; parameter_types! { pub MaxNominations: u32 = ::LIMIT as u32; + // only used in testing to manipulate mock behaviour + pub static DataProviderAllowBadData: bool = false; } #[derive(Default)] @@ -438,7 +435,9 @@ impl ElectionDataProvider for StakingMock { fn electable_targets(maybe_max_len: Option) -> data_provider::Result> { let targets = Targets::get(); - if maybe_max_len.map_or(false, |max_len| targets.len() > max_len) { + if !DataProviderAllowBadData::get() && + maybe_max_len.map_or(false, |max_len| targets.len() > max_len) + { return Err("Targets too big") } @@ -449,8 +448,10 @@ impl ElectionDataProvider for StakingMock { maybe_max_len: Option, ) -> data_provider::Result>> { let mut voters = Voters::get(); - if let Some(max_len) = maybe_max_len { - voters.truncate(max_len) + if !DataProviderAllowBadData::get() { + if let Some(max_len) = maybe_max_len { + voters.truncate(max_len) + } } Ok(voters) diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index cda87dd6c839a..9d629ad77fd79 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -462,7 +462,7 @@ impl Pallet { /// /// Infallible pub fn finalize_signed_phase_accept_solution( - ready_solution: ReadySolution, + ready_solution: ReadySolution, who: &T::AccountId, deposit: BalanceOf, call_fee: BalanceOf, @@ -537,7 +537,7 @@ impl Pallet { #[cfg(test)] mod tests { use super::*; - use crate::{mock::*, ElectionCompute, Error, Event, Perbill, Phase}; + use crate::{mock::*, ElectionCompute, ElectionError, Error, Event, Perbill, Phase}; use frame_support::{assert_noop, assert_ok, assert_storage_noop}; #[test] @@ -557,6 +557,50 @@ mod tests { }) } + #[test] + fn data_provider_should_respect_target_limits() { + ExtBuilder::default().build_and_execute(|| { + // given a reduced expectation of maximum electable targets + MaxElectableTargets::set(2); + // and a data provider that does not respect limits + DataProviderAllowBadData::set(true); + + assert_noop!( + MultiPhase::create_snapshot(), + ElectionError::DataProvider("Snapshot too big for submission."), + ); + }) + } + + #[test] + fn data_provider_should_respect_voter_limits() { + ExtBuilder::default().build_and_execute(|| { + // given a reduced expectation of maximum electing voters + MaxElectingVoters::set(2); + // and a data provider that does not respect limits + DataProviderAllowBadData::set(true); + + assert_noop!( + MultiPhase::create_snapshot(), + ElectionError::DataProvider("Snapshot too big for submission."), + ); + }) + } + + #[test] + fn desired_targets_greater_than_max_winners() { + ExtBuilder::default().build_and_execute(|| { + // given desired_targets bigger than MaxWinners + DesiredTargets::set(4); + MaxWinners::set(3); + + let (_, _, actual_desired_targets) = MultiPhase::create_snapshot_external().unwrap(); + + // snapshot is created with min of desired_targets and MaxWinners + assert_eq!(actual_desired_targets, 3); + }) + } + #[test] fn should_pay_deposit() { ExtBuilder::default().build_and_execute(|| { diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 5ee65e102bd06..38924a18e2f54 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -82,6 +82,7 @@ //! # use frame_election_provider_support::{*, data_provider}; //! # use sp_npos_elections::{Support, Assignment}; //! # use frame_support::traits::ConstU32; +//! # use frame_support::bounded_vec; //! //! type AccountId = u64; //! type Balance = u64; @@ -137,15 +138,16 @@ //! type BlockNumber = BlockNumber; //! type Error = &'static str; //! type DataProvider = T::DataProvider; -//! fn ongoing() -> bool { false } -//! +//! type MaxWinners = ConstU32<{ u32::MAX }>; +//! //! } //! //! impl ElectionProvider for GenericElectionProvider { -//! fn elect() -> Result, Self::Error> { +//! fn ongoing() -> bool { false } +//! fn elect() -> Result, Self::Error> { //! Self::DataProvider::electable_targets(None) //! .map_err(|_| "failed to elect") -//! .map(|t| vec![(t[0], Support::default())]) +//! .map(|t| bounded_vec![(t[0], Support::default())]) //! } //! } //! } @@ -354,11 +356,7 @@ pub trait ElectionDataProvider { fn clear() {} } -/// Base trait for [`ElectionProvider`] and [`BoundedElectionProvider`]. It is -/// meant to be used only with an extension trait that adds an election -/// functionality. -/// -/// Data can be bounded or unbounded and is fetched from [`Self::DataProvider`]. +/// Base trait for types that can provide election pub trait ElectionProviderBase { /// The account identifier type. type AccountId; @@ -369,90 +367,109 @@ pub trait ElectionProviderBase { /// The error type that is returned by the provider. type Error: Debug; + /// The upper bound on election winners that can be returned. + /// + /// # WARNING + /// + /// when communicating with the data provider, one must ensure that + /// `DataProvider::desired_targets` returns a value less than this bound. An + /// implementation can chose to either return an error and/or sort and + /// truncate the output to meet this bound. + type MaxWinners: Get; + /// The data provider of the election. type DataProvider: ElectionDataProvider< AccountId = Self::AccountId, BlockNumber = Self::BlockNumber, >; - /// Indicate if this election provider is currently ongoing an asynchronous election or not. - fn ongoing() -> bool; + /// checked call to `Self::DataProvider::desired_targets()` ensuring the value never exceeds + /// [`Self::MaxWinners`]. + fn desired_targets_checked() -> data_provider::Result { + match Self::DataProvider::desired_targets() { + Ok(desired_targets) => + if desired_targets <= Self::MaxWinners::get() { + Ok(desired_targets) + } else { + Err("desired_targets should not be greater than MaxWinners") + }, + Err(e) => Err(e), + } + } } /// Elect a new set of winners, bounded by `MaxWinners`. /// -/// Returns a result in bounded, target major format, namely as -/// *BoundedVec<(AccountId, Vec), MaxWinners>*. -pub trait BoundedElectionProvider: ElectionProviderBase { - /// The upper bound on election winners. - type MaxWinners: Get; +/// It must always use [`ElectionProviderBase::DataProvider`] to fetch the data it needs. +/// +/// This election provider that could function asynchronously. This implies that this election might +/// needs data ahead of time (ergo, receives no arguments to `elect`), and might be `ongoing` at +/// times. +pub trait ElectionProvider: ElectionProviderBase { + /// Indicate if this election provider is currently ongoing an asynchronous election or not. + fn ongoing() -> bool; + /// Performs the election. This should be implemented as a self-weighing function. The /// implementor should register its appropriate weight at the end of execution with the /// system pallet directly. - fn elect() -> Result, Self::Error>; -} - -/// Same a [`BoundedElectionProvider`], but no bounds are imposed on the number -/// of winners. -/// -/// The result is returned in a target major format, namely as -///*Vec<(AccountId, Vec)>*. -pub trait ElectionProvider: ElectionProviderBase { - /// Performs the election. This should be implemented as a self-weighing - /// function, similar to [`BoundedElectionProvider::elect()`]. - fn elect() -> Result, Self::Error>; + fn elect() -> Result, Self::Error>; } -/// A sub-trait of the [`ElectionProvider`] for cases where we need to be sure -/// an election needs to happen instantly, not asynchronously. -/// -/// The same `DataProvider` is assumed to be used. +/// A (almost) marker trait that signifies an election provider as working synchronously. i.e. being +/// *instant*. /// -/// Consequently, allows for control over the amount of data that is being -/// fetched from the [`ElectionProviderBase::DataProvider`]. -pub trait InstantElectionProvider: ElectionProvider { - /// Elect a new set of winners, but unlike [`ElectionProvider::elect`] which cannot enforce - /// bounds, this trait method can enforce bounds on the amount of data provided by the - /// `DataProvider`. - /// - /// An implementing type, if itself bounded, should choose the minimum of the two bounds to - /// choose the final value of `max_voters` and `max_targets`. In other words, an implementation - /// should guarantee that `max_voter` and `max_targets` provided to this method are absolutely - /// respected. - fn elect_with_bounds( - max_voters: usize, - max_targets: usize, - ) -> Result, Self::Error>; +/// This must still use the same data provider as with [`ElectionProviderBase::DataProvider`]. +/// However, it can optionally overwrite the amount of voters and targets that are fetched from the +/// data provider at runtime via `forced_input_voters_bound` and `forced_input_target_bound`. +pub trait InstantElectionProvider: ElectionProviderBase { + fn instant_elect( + forced_input_voters_bound: Option, + forced_input_target_bound: Option, + ) -> Result, Self::Error>; } -/// An election provider to be used only for testing. -#[cfg(feature = "std")] +/// An election provider that does nothing whatsoever. pub struct NoElection(sp_std::marker::PhantomData); -#[cfg(feature = "std")] -impl ElectionProviderBase - for NoElection<(AccountId, BlockNumber, DataProvider)> +impl ElectionProviderBase + for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinners)> where DataProvider: ElectionDataProvider, + MaxWinners: Get, { type AccountId = AccountId; type BlockNumber = BlockNumber; type Error = &'static str; + type MaxWinners = MaxWinners; type DataProvider = DataProvider; +} +impl ElectionProvider + for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinners)> +where + DataProvider: ElectionDataProvider, + MaxWinners: Get, +{ fn ongoing() -> bool { false } + + fn elect() -> Result, Self::Error> { + Err("`NoElection` cannot do anything.") + } } -#[cfg(feature = "std")] -impl ElectionProvider - for NoElection<(AccountId, BlockNumber, DataProvider)> +impl InstantElectionProvider + for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinners)> where DataProvider: ElectionDataProvider, + MaxWinners: Get, { - fn elect() -> Result, Self::Error> { - Err(" cannot do anything.") + fn instant_elect( + _: Option, + _: Option, + ) -> Result, Self::Error> { + Err("`NoElection` cannot do anything.") } } @@ -650,3 +667,9 @@ pub type Voter = (AccountId, VoteWeight, BoundedVec = Voter<::AccountId, ::MaxVotesPerVoter>; + +/// Same as `BoundedSupports` but parameterized by a `ElectionProviderBase`. +pub type BoundedSupportsOf = BoundedSupports< + ::AccountId, + ::MaxWinners, +>; diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 88aa6ca7267a0..483c402fe249c 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -20,11 +20,13 @@ //! careful when using it onchain. use crate::{ - Debug, ElectionDataProvider, ElectionProvider, ElectionProviderBase, InstantElectionProvider, - NposSolver, WeightInfo, + BoundedSupportsOf, Debug, ElectionDataProvider, ElectionProvider, ElectionProviderBase, + InstantElectionProvider, NposSolver, WeightInfo, }; use frame_support::{dispatch::DispatchClass, traits::Get}; -use sp_npos_elections::*; +use sp_npos_elections::{ + assignment_ratio_to_staked_normalized, to_supports, BoundedSupports, ElectionResult, VoteWeight, +}; use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; /// Errors of the on-chain election. @@ -34,6 +36,9 @@ pub enum Error { NposElections(sp_npos_elections::Error), /// Errors from the data provider. DataProvider(&'static str), + /// Configurational error caused by `desired_targets` requested by data provider exceeding + /// `MaxWinners`. + TooManyWinners, } impl From for Error { @@ -44,65 +49,71 @@ impl From for Error { /// A simple on-chain implementation of the election provider trait. /// -/// This will accept voting data on the fly and produce the results immediately. -/// -/// The [`ElectionProvider`] implementation of this type does not impose any dynamic limits on the -/// number of voters and targets that are fetched. This could potentially make this unsuitable for -/// execution onchain. One could, however, impose bounds on it by using `BoundedExecution` using the -/// `MaxVoters` and `MaxTargets` bonds in the `BoundedConfig` trait. -/// -/// On the other hand, the [`InstantElectionProvider`] implementation does limit these inputs -/// dynamically. If you use `elect_with_bounds` along with `InstantElectionProvider`, the bound that -/// would be used is the minimum of the dynamic bounds given as arguments to `elect_with_bounds` and -/// the trait bounds (`MaxVoters` and `MaxTargets`). +/// This implements both `ElectionProvider` and `InstantElectionProvider`. /// -/// Please use `BoundedExecution` at all times except at genesis or for testing, with thoughtful -/// bounds in order to bound the potential execution time. Limit the use `UnboundedExecution` at -/// genesis or for testing, as it does not bound the inputs. However, this can be used with -/// `[InstantElectionProvider::elect_with_bounds`] that dynamically imposes limits. -pub struct BoundedExecution(PhantomData); +/// This type has some utilities to make it safe. Nonetheless, it should be used with utmost care. A +/// thoughtful value must be set as [`Config::VotersBound`] and [`Config::TargetsBound`] to ensure +/// the size of the input is sensible. +pub struct OnChainExecution(PhantomData); -/// An unbounded variant of [`BoundedExecution`]. -/// -/// ### Warning -/// -/// This can be very expensive to run frequently on-chain. Use with care. -pub struct UnboundedExecution(PhantomData); +#[deprecated(note = "use OnChainExecution, which is bounded by default")] +pub type BoundedExecution = OnChainExecution; /// Configuration trait for an onchain election execution. pub trait Config { /// Needed for weight registration. type System: frame_system::Config; + /// `NposSolver` that should be used, an example would be `PhragMMS`. type Solver: NposSolver< AccountId = ::AccountId, Error = sp_npos_elections::Error, >; + /// Something that provides the data for election. type DataProvider: ElectionDataProvider< AccountId = ::AccountId, BlockNumber = ::BlockNumber, >; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; -} -pub trait BoundedConfig: Config { - /// Bounds the number of voters. + /// Upper bound on maximum winners from electable targets. + /// + /// As noted in the documentation of [`ElectionProviderBase::MaxWinners`], this value should + /// always be more than `DataProvider::desired_target`. + type MaxWinners: Get; + + /// Bounds the number of voters, when calling into [`Config::DataProvider`]. It might be + /// overwritten in the `InstantElectionProvider` impl. type VotersBound: Get; - /// Bounds the number of targets. + + /// Bounds the number of targets, when calling into [`Config::DataProvider`]. It might be + /// overwritten in the `InstantElectionProvider` impl. type TargetsBound: Get; } -fn elect_with( +/// Same as `BoundedSupportsOf` but for `onchain::Config`. +pub type OnChainBoundedSupportsOf = BoundedSupports< + <::System as frame_system::Config>::AccountId, + ::MaxWinners, +>; + +fn elect_with_input_bounds( maybe_max_voters: Option, maybe_max_targets: Option, -) -> Result::AccountId>, Error> { +) -> Result, Error> { let voters = T::DataProvider::electing_voters(maybe_max_voters).map_err(Error::DataProvider)?; let targets = T::DataProvider::electable_targets(maybe_max_targets).map_err(Error::DataProvider)?; let desired_targets = T::DataProvider::desired_targets().map_err(Error::DataProvider)?; + if desired_targets > T::MaxWinners::get() { + // early exit + return Err(Error::TooManyWinners) + } + let voters_len = voters.len() as u32; let targets_len = targets.len() as u32; @@ -130,69 +141,43 @@ fn elect_with( DispatchClass::Mandatory, ); - Ok(to_supports(&staked)) -} - -impl ElectionProvider for UnboundedExecution { - fn elect() -> Result, Self::Error> { - // This should not be called if not in `std` mode (and therefore neither in genesis nor in - // testing) - if cfg!(not(feature = "std")) { - frame_support::log::error!( - "Please use `InstantElectionProvider` instead to provide bounds on election if not in \ - genesis or testing mode" - ); - } + // defensive: Since npos solver returns a result always bounded by `desired_targets`, this is + // never expected to happen as long as npos solver does what is expected for it to do. + let supports: OnChainBoundedSupportsOf = + to_supports(&staked).try_into().map_err(|_| Error::TooManyWinners)?; - elect_with::(None, None) - } + Ok(supports) } -impl ElectionProviderBase for UnboundedExecution { +impl ElectionProviderBase for OnChainExecution { type AccountId = ::AccountId; type BlockNumber = ::BlockNumber; type Error = Error; + type MaxWinners = T::MaxWinners; type DataProvider = T::DataProvider; - - fn ongoing() -> bool { - false - } } -impl InstantElectionProvider for UnboundedExecution { - fn elect_with_bounds( - max_voters: usize, - max_targets: usize, - ) -> Result, Self::Error> { - elect_with::(Some(max_voters), Some(max_targets)) +impl InstantElectionProvider for OnChainExecution { + fn instant_elect( + forced_input_voters_bound: Option, + forced_input_target_bound: Option, + ) -> Result, Self::Error> { + elect_with_input_bounds::( + Some(T::VotersBound::get().min(forced_input_voters_bound.unwrap_or(u32::MAX)) as usize), + Some(T::TargetsBound::get().min(forced_input_target_bound.unwrap_or(u32::MAX)) as usize), + ) } } -impl ElectionProviderBase for BoundedExecution { - type AccountId = ::AccountId; - type BlockNumber = ::BlockNumber; - type Error = Error; - type DataProvider = T::DataProvider; - +impl ElectionProvider for OnChainExecution { fn ongoing() -> bool { false } -} - -impl ElectionProvider for BoundedExecution { - fn elect() -> Result, Self::Error> { - elect_with::(Some(T::VotersBound::get() as usize), Some(T::TargetsBound::get() as usize)) - } -} -impl InstantElectionProvider for BoundedExecution { - fn elect_with_bounds( - max_voters: usize, - max_targets: usize, - ) -> Result, Self::Error> { - elect_with::( - Some(max_voters.min(T::VotersBound::get() as usize)), - Some(max_targets.min(T::TargetsBound::get() as usize)), + fn elect() -> Result, Self::Error> { + elect_with_input_bounds::( + Some(T::VotersBound::get() as usize), + Some(T::TargetsBound::get() as usize), ) } } @@ -200,8 +185,8 @@ impl InstantElectionProvider for BoundedExecution { #[cfg(test)] mod tests { use super::*; - use crate::{PhragMMS, SequentialPhragmen}; - use frame_support::traits::ConstU32; + use crate::{ElectionProvider, PhragMMS, SequentialPhragmen}; + use frame_support::{assert_noop, parameter_types, traits::ConstU32}; use sp_npos_elections::Support; use sp_runtime::Perbill; type AccountId = u64; @@ -251,14 +236,17 @@ mod tests { struct PhragmenParams; struct PhragMMSParams; + parameter_types! { + pub static MaxWinners: u32 = 10; + pub static DesiredTargets: u32 = 2; + } + impl Config for PhragmenParams { type System = Runtime; type Solver = SequentialPhragmen; type DataProvider = mock_data_provider::DataProvider; type WeightInfo = (); - } - - impl BoundedConfig for PhragmenParams { + type MaxWinners = MaxWinners; type VotersBound = ConstU32<600>; type TargetsBound = ConstU32<400>; } @@ -268,9 +256,7 @@ mod tests { type Solver = PhragMMS; type DataProvider = mock_data_provider::DataProvider; type WeightInfo = (); - } - - impl BoundedConfig for PhragMMSParams { + type MaxWinners = MaxWinners; type VotersBound = ConstU32<600>; type TargetsBound = ConstU32<400>; } @@ -299,7 +285,7 @@ mod tests { } fn desired_targets() -> data_provider::Result { - Ok(2) + Ok(DesiredTargets::get()) } fn next_election_prediction(_: BlockNumber) -> BlockNumber { @@ -312,7 +298,7 @@ mod tests { fn onchain_seq_phragmen_works() { sp_io::TestExternalities::new_empty().execute_with(|| { assert_eq!( - BoundedExecution::::elect().unwrap(), + as ElectionProvider>::elect().unwrap(), vec![ (10, Support { total: 25, voters: vec![(1, 10), (3, 15)] }), (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }) @@ -321,11 +307,25 @@ mod tests { }) } + #[test] + fn too_many_winners_when_desired_targets_exceed_max_winners() { + sp_io::TestExternalities::new_empty().execute_with(|| { + // given desired targets larger than max winners + DesiredTargets::set(10); + MaxWinners::set(9); + + assert_noop!( + as ElectionProvider>::elect(), + Error::TooManyWinners, + ); + }) + } + #[test] fn onchain_phragmms_works() { sp_io::TestExternalities::new_empty().execute_with(|| { assert_eq!( - BoundedExecution::::elect().unwrap(), + as ElectionProvider>::elect().unwrap(), vec![ (10, Support { total: 25, voters: vec![(1, 10), (3, 15)] }), (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }) diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index bac2d9aa9c8e4..d66f4ba5663d9 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -107,22 +107,23 @@ parameter_types! { pub static BondingDuration: u32 = 3; pub static CurrentEra: u32 = 0; pub static Ongoing: bool = false; + pub static MaxWinners: u32 = 100; } pub struct MockElection; impl frame_election_provider_support::ElectionProviderBase for MockElection { type AccountId = AccountId; type BlockNumber = BlockNumber; + type MaxWinners = MaxWinners; type DataProvider = Staking; type Error = (); +} +impl frame_election_provider_support::ElectionProvider for MockElection { fn ongoing() -> bool { Ongoing::get() } -} - -impl frame_election_provider_support::ElectionProvider for MockElection { - fn elect() -> Result, Self::Error> { + fn elect() -> Result, Self::Error> { Err(()) } } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 573a74d2bfae8..1a97b1345fe5d 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -182,6 +182,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); + type MaxWinners = ConstU32<100>; + type VotersBound = ConstU32<{ u32::MAX }>; + type TargetsBound = ConstU32<{ u32::MAX }>; } impl pallet_staking::Config for Test { @@ -203,7 +206,7 @@ impl pallet_staking::Config for Test { type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; - type ElectionProvider = onchain::UnboundedExecution; + type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index db01989f2b563..6959aa9783ee5 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -110,7 +110,7 @@ impl pallet_staking::Config for Runtime { type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = - frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking)>; + frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 5758b884e348d..568dec7b3a340 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -124,7 +124,7 @@ impl pallet_staking::Config for Runtime { type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = - frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking)>; + frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index c4c1d2aca8d07..e022d81c5b5bd 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -156,6 +156,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); + type MaxWinners = ConstU32<100>; + type VotersBound = ConstU32<{ u32::MAX }>; + type TargetsBound = ConstU32<{ u32::MAX }>; } impl pallet_staking::Config for Test { @@ -177,7 +180,7 @@ impl pallet_staking::Config for Test { type NextNewSession = Session; type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); - type ElectionProvider = onchain::UnboundedExecution; + type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs index 3f0a26afc1358..65bfcad4b26fc 100644 --- a/frame/root-offences/src/mock.rs +++ b/frame/root-offences/src/mock.rs @@ -145,6 +145,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); + type MaxWinners = ConstU32<100>; + type VotersBound = ConstU32<{ u32::MAX }>; + type TargetsBound = ConstU32<{ u32::MAX }>; } pub struct OnStakerSlashMock(core::marker::PhantomData); @@ -188,7 +191,7 @@ impl pallet_staking::Config for Test { type NextNewSession = Session; type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; - type ElectionProvider = onchain::UnboundedExecution; + type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index f86ddfeedc08b..2db7eb385111c 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -150,6 +150,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); + type MaxWinners = ConstU32<100>; + type VotersBound = ConstU32<{ u32::MAX }>; + type TargetsBound = ConstU32<{ u32::MAX }>; } impl pallet_staking::Config for Test { @@ -171,7 +174,7 @@ impl pallet_staking::Config for Test { type NextNewSession = Session; type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); - type ElectionProvider = onchain::UnboundedExecution; + type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; type MaxUnlockingChunks = ConstU32<32>; type HistoryDepth = ConstU32<84>; diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index a0144463540be..0f5b8e0123ab6 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -333,6 +333,10 @@ macro_rules! log { }; } +/// Maximum number of winners (aka. active validators), as defined in the election provider of this +/// pallet. +pub type MaxWinnersOf = <::ElectionProvider as frame_election_provider_support::ElectionProviderBase>::MaxWinners; + /// Counter for the number of "reward" points earned by a given validator. pub type RewardPoint = u32; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 24e5aa97160ee..16e4e5ddd7aa2 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -238,6 +238,7 @@ parameter_types! { pub static MaxUnlockingChunks: u32 = 32; pub static RewardOnUnbalanceWasCalled: bool = false; pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); + pub static MaxWinners: u32 = 100; } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -256,6 +257,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); + type MaxWinners = MaxWinners; + type VotersBound = ConstU32<{ u32::MAX }>; + type TargetsBound = ConstU32<{ u32::MAX }>; } pub struct MockReward {} @@ -295,7 +299,7 @@ impl crate::pallet::pallet::Config for Test { type NextNewSession = Session; type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; - type ElectionProvider = onchain::UnboundedExecution; + type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. type VoterList = VoterBagsList; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index a9e9899b9761a..9be01dd823104 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -18,15 +18,15 @@ //! Implementations for the Staking FRAME Pallet. use frame_election_provider_support::{ - data_provider, ElectionDataProvider, ElectionProvider, ElectionProviderBase, ScoreProvider, - SortedListProvider, Supports, VoteWeight, VoterOf, + data_provider, BoundedSupportsOf, ElectionDataProvider, ElectionProvider, ScoreProvider, + SortedListProvider, VoteWeight, VoterOf, }; use frame_support::{ dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ Currency, CurrencyToVote, Defensive, DefensiveResult, EstimateNextNewSession, Get, - Imbalance, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, + Imbalance, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, WithdrawReasons, }, weights::Weight, }; @@ -44,7 +44,7 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use crate::{ log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf, - Forcing, IndividualExposure, Nominations, PositiveImbalanceOf, RewardDestination, + Forcing, IndividualExposure, MaxWinnersOf, Nominations, PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, }; @@ -267,7 +267,10 @@ impl Pallet { } /// Plan a new session potentially trigger a new era. - fn new_session(session_index: SessionIndex, is_genesis: bool) -> Option> { + fn new_session( + session_index: SessionIndex, + is_genesis: bool, + ) -> Option>> { if let Some(current_era) = Self::current_era() { // Initial era has been set. let current_era_start_session_index = Self::eras_start_session_index(current_era) @@ -426,8 +429,11 @@ impl Pallet { /// Returns the new validator set. pub fn trigger_new_era( start_session_index: SessionIndex, - exposures: Vec<(T::AccountId, Exposure>)>, - ) -> Vec { + exposures: BoundedVec< + (T::AccountId, Exposure>), + MaxWinnersOf, + >, + ) -> BoundedVec> { // Increment or set current era. let new_planned_era = CurrentEra::::mutate(|s| { *s = Some(s.map(|s| s + 1).unwrap_or(0)); @@ -453,19 +459,26 @@ impl Pallet { pub(crate) fn try_trigger_new_era( start_session_index: SessionIndex, is_genesis: bool, - ) -> Option> { - let election_result = if is_genesis { - T::GenesisElectionProvider::elect().map_err(|e| { + ) -> Option>> { + let election_result: BoundedVec<_, MaxWinnersOf> = if is_genesis { + let result = ::elect().map_err(|e| { log!(warn, "genesis election provider failed due to {:?}", e); Self::deposit_event(Event::StakingElectionFailed); - }) + }); + + result + .ok()? + .into_inner() + .try_into() + // both bounds checked in integrity test to be equal + .defensive_unwrap_or_default() } else { - T::ElectionProvider::elect().map_err(|e| { + let result = ::elect().map_err(|e| { log!(warn, "election provider failed due to {:?}", e); Self::deposit_event(Event::StakingElectionFailed); - }) - } - .ok()?; + }); + result.ok()? + }; let exposures = Self::collect_exposures(election_result); if (exposures.len() as u32) < Self::minimum_validator_count().max(1) { @@ -502,10 +515,19 @@ impl Pallet { /// /// Store staking information for the new planned era pub fn store_stakers_info( - exposures: Vec<(T::AccountId, Exposure>)>, + exposures: BoundedVec< + (T::AccountId, Exposure>), + MaxWinnersOf, + >, new_planned_era: EraIndex, - ) -> Vec { - let elected_stashes = exposures.iter().cloned().map(|(x, _)| x).collect::>(); + ) -> BoundedVec> { + let elected_stashes: BoundedVec<_, MaxWinnersOf> = exposures + .iter() + .cloned() + .map(|(x, _)| x) + .collect::>() + .try_into() + .expect("since we only map through exposures, size of elected_stashes is always same as exposures; qed"); // Populate stakers, exposures, and the snapshot of validator prefs. let mut total_stake: BalanceOf = Zero::zero(); @@ -543,11 +565,11 @@ impl Pallet { elected_stashes } - /// Consume a set of [`Supports`] from [`sp_npos_elections`] and collect them into a + /// Consume a set of [`BoundedSupports`] from [`sp_npos_elections`] and collect them into a /// [`Exposure`]. fn collect_exposures( - supports: Supports, - ) -> Vec<(T::AccountId, Exposure>)> { + supports: BoundedSupportsOf, + ) -> BoundedVec<(T::AccountId, Exposure>), MaxWinnersOf> { let total_issuance = T::Currency::total_issuance(); let to_currency = |e: frame_election_provider_support::ExtendedBalance| { T::CurrencyToVote::to_currency(e, total_issuance) @@ -576,7 +598,8 @@ impl Pallet { let exposure = Exposure { own, others, total }; (validator, exposure) }) - .collect::)>>() + .try_collect() + .expect("we only map through support vector which cannot change the size; qed") } /// Remove all associated data of a stash account from the staking system. @@ -1085,12 +1108,12 @@ impl pallet_session::SessionManager for Pallet { fn new_session(new_index: SessionIndex) -> Option> { log!(trace, "planning new session {}", new_index); CurrentPlannedSession::::put(new_index); - Self::new_session(new_index, false) + Self::new_session(new_index, false).map(|v| v.into_inner()) } fn new_session_genesis(new_index: SessionIndex) -> Option> { log!(trace, "planning new session {} at genesis", new_index); CurrentPlannedSession::::put(new_index); - Self::new_session(new_index, true) + Self::new_session(new_index, true).map(|v| v.into_inner()) } fn start_session(start_index: SessionIndex) { log!(trace, "starting session {}", start_index); @@ -1500,7 +1523,7 @@ impl StakingInterface for Pallet { } fn election_ongoing() -> bool { - ::ongoing() + T::ElectionProvider::ongoing() } fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { @@ -1626,6 +1649,12 @@ impl Pallet { Nominators::::count() + Validators::::count(), "wrong external count" ); + + ensure!( + ValidatorCount::::get() <= + ::MaxWinners::get(), + "validator count exceeded election max winners" + ); Ok(()) } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index df90873ab2e59..8fddba2150370 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -17,7 +17,9 @@ //! Staking FRAME Pallet. -use frame_election_provider_support::{SortedListProvider, VoteWeight}; +use frame_election_provider_support::{ + ElectionProvider, ElectionProviderBase, SortedListProvider, VoteWeight, +}; use frame_support::{ dispatch::Codec, pallet_prelude::*, @@ -32,7 +34,7 @@ use frame_support::{ use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; use sp_runtime::{ traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero}, - Perbill, Percent, + ArithmeticError, Perbill, Percent, }; use sp_staking::{EraIndex, SessionIndex}; use sp_std::prelude::*; @@ -107,7 +109,7 @@ pub mod pallet { type CurrencyToVote: CurrencyToVote>; /// Something that provides the election functionality. - type ElectionProvider: frame_election_provider_support::ElectionProvider< + type ElectionProvider: ElectionProvider< AccountId = Self::AccountId, BlockNumber = Self::BlockNumber, // we only accept an election provider that has staking as data provider. @@ -115,7 +117,7 @@ pub mod pallet { >; /// Something that provides the election functionality at genesis. - type GenesisElectionProvider: frame_election_provider_support::ElectionProvider< + type GenesisElectionProvider: ElectionProvider< AccountId = Self::AccountId, BlockNumber = Self::BlockNumber, DataProvider = Pallet, @@ -646,6 +648,10 @@ pub mod pallet { ), _ => Ok(()), }); + assert!( + ValidatorCount::::get() <= + ::MaxWinners::get() + ); } // all voters are reported to the `VoterList`. @@ -743,8 +749,8 @@ pub mod pallet { /// There are too many nominators in the system. Governance needs to adjust the staking /// settings to keep things safe for the runtime. TooManyNominators, - /// There are too many validators in the system. Governance needs to adjust the staking - /// settings to keep things safe for the runtime. + /// There are too many validator candidates in the system. Governance needs to adjust the + /// staking settings to keep things safe for the runtime. TooManyValidators, /// Commission is too low. Must be at least `MinCommission`. CommissionTooLow, @@ -782,6 +788,12 @@ pub mod pallet { // and that MaxNominations is always greater than 1, since we count on this. assert!(!T::MaxNominations::get().is_zero()); + // ensure election results are always bounded with the same value + assert!( + ::MaxWinners::get() == + ::MaxWinners::get() + ); + sp_std::if_std! { sp_io::TestExternalities::new_empty().execute_with(|| assert!( @@ -1264,11 +1276,18 @@ pub mod pallet { #[pallet::compact] new: u32, ) -> DispatchResult { ensure_root(origin)?; + // ensure new validator count does not exceed maximum winners + // support by election provider. + ensure!( + new <= ::MaxWinners::get(), + Error::::TooManyValidators + ); ValidatorCount::::put(new); Ok(()) } - /// Increments the ideal number of validators. + /// Increments the ideal number of validators upto maximum of + /// `ElectionProviderBase::MaxWinners`. /// /// The dispatch origin must be Root. /// @@ -1281,11 +1300,19 @@ pub mod pallet { #[pallet::compact] additional: u32, ) -> DispatchResult { ensure_root(origin)?; - ValidatorCount::::mutate(|n| *n += additional); + let old = ValidatorCount::::get(); + let new = old.checked_add(additional).ok_or(ArithmeticError::Overflow)?; + ensure!( + new <= ::MaxWinners::get(), + Error::::TooManyValidators + ); + + ValidatorCount::::put(new); Ok(()) } - /// Scale up the ideal number of validators by a factor. + /// Scale up the ideal number of validators by a factor upto maximum of + /// `ElectionProviderBase::MaxWinners`. /// /// The dispatch origin must be Root. /// @@ -1295,7 +1322,15 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_validator_count())] pub fn scale_validator_count(origin: OriginFor, factor: Percent) -> DispatchResult { ensure_root(origin)?; - ValidatorCount::::mutate(|n| *n += factor * *n); + let old = ValidatorCount::::get(); + let new = old.checked_add(factor.mul_floor(old)).ok_or(ArithmeticError::Overflow)?; + + ensure!( + new <= ::MaxWinners::get(), + Error::::TooManyValidators + ); + + ValidatorCount::::put(new); Ok(()) } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 4812c105c0d80..6609b9087637d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -5624,3 +5624,57 @@ fn reducing_max_unlocking_chunks_abrupt() { MaxUnlockingChunks::set(2); }) } + +#[test] +fn cannot_set_unsupported_validator_count() { + ExtBuilder::default().build_and_execute(|| { + MaxWinners::set(50); + // set validator count works + assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 30)); + assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 50)); + // setting validator count above 100 does not work + assert_noop!( + Staking::set_validator_count(RuntimeOrigin::root(), 51), + Error::::TooManyValidators, + ); + }) +} + +#[test] +fn increase_validator_count_errors() { + ExtBuilder::default().build_and_execute(|| { + MaxWinners::set(50); + assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 40)); + + // increase works + assert_ok!(Staking::increase_validator_count(RuntimeOrigin::root(), 6)); + assert_eq!(ValidatorCount::::get(), 46); + + // errors + assert_noop!( + Staking::increase_validator_count(RuntimeOrigin::root(), 5), + Error::::TooManyValidators, + ); + }) +} + +#[test] +fn scale_validator_count_errors() { + ExtBuilder::default().build_and_execute(|| { + MaxWinners::set(50); + assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 20)); + + // scale value works + assert_ok!(Staking::scale_validator_count( + RuntimeOrigin::root(), + Percent::from_percent(200) + )); + assert_eq!(ValidatorCount::::get(), 40); + + // errors + assert_noop!( + Staking::scale_validator_count(RuntimeOrigin::root(), Percent::from_percent(126)), + Error::::TooManyValidators, + ); + }) +} diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 514ded67ad38b..d0c9ed18caddc 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -450,10 +450,10 @@ impl Default for Support { /// The main advantage of this is that it is encodable. pub type Supports = Vec<(A, Support)>; -/// Same as `Supports` bounded by `MaxWinners`. +/// Same as `Supports` but bounded by `B`. /// /// To note, the inner `Support` is still unbounded. -pub type BoundedSupports = BoundedVec<(A, Support), MaxWinners>; +pub type BoundedSupports = BoundedVec<(A, Support), B>; /// Linkage from a winner to their [`Support`]. /// From c460f4be081eda7cacdf30feeb65f26a44a3a1b0 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Wed, 9 Nov 2022 19:46:00 +0800 Subject: [PATCH 1363/1472] Update some dependencies to prune duplicated crates with different version (#12560) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * sc-client-babe/sp-arithmetic-fuzzer: update num-bigint and num-rational to v0.4 * update lru 0.7.5 ==> v0.8.1 * pallet-example-offchain-worker: update lite-json v0.1.3 ==> v0.2.0 * update hyper 0.14.16 ==> 0.14.20, num-fromat 0.4.0 ==> 0.4.3 * pallet-mmr: update ckb-merkle-mountain-range v0.3.2 ==> v0.5.2 * update handlebars v4.2.2 ==> v4.3.5 * `runtime_cache_size` must always be at least 1 Signed-off-by: koushiro * default cache size with .min(1) Signed-off-by: koushiro * update hyper 0.14.20 ==> 0.14.22 Signed-off-by: koushiro * update lru 0.8.0 ==> 0.8.1 Signed-off-by: koushiro * Apply suggestions from code review * Apply suggestions from code review * Fix Cargo.lock Signed-off-by: koushiro Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- Cargo.lock | 364 +++++++----------- client/consensus/babe/Cargo.toml | 9 +- client/consensus/babe/src/authorship.rs | 2 +- client/consensus/babe/src/tests.rs | 6 +- client/executor/Cargo.toml | 2 +- client/executor/src/wasm_runtime.rs | 11 +- client/network-gossip/Cargo.toml | 2 +- client/network-gossip/src/state_machine.rs | 8 +- client/network/Cargo.toml | 2 +- client/network/src/protocol.rs | 14 +- client/network/sync/Cargo.toml | 6 +- .../network/sync/src/block_request_handler.rs | 5 +- .../network/sync/src/state_request_handler.rs | 5 +- frame/examples/offchain-worker/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- frame/merkle-mountain-range/src/mmr/mod.rs | 4 +- primitives/arithmetic/fuzzer/Cargo.toml | 2 +- primitives/blockchain/Cargo.toml | 2 +- primitives/blockchain/src/header_metadata.rs | 6 +- primitives/trie/Cargo.toml | 2 +- primitives/trie/src/cache/shared_cache.rs | 2 +- utils/frame/generate-bags/Cargo.toml | 2 +- 22 files changed, 191 insertions(+), 269 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bec6b0bd976e0..d65411de0125c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,7 +42,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", "opaque-debug 0.3.0", @@ -124,15 +124,6 @@ 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" @@ -267,7 +258,7 @@ checksum = "cf2c06e30a24e8c78a3987d07f0930edf76ef35e027e7bdb063fccafdad1f60c" dependencies = [ "async-io", "blocking", - "cfg-if 1.0.0", + "cfg-if", "event-listener", "futures-lite", "libc", @@ -402,7 +393,7 @@ checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object 0.27.1", @@ -632,7 +623,7 @@ dependencies = [ "arrayref", "arrayvec 0.7.2", "cc", - "cfg-if 1.0.0", + "cfg-if", "constant_time_eq", ] @@ -851,12 +842,6 @@ 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" @@ -875,7 +860,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", "zeroize", @@ -945,11 +930,11 @@ dependencies = [ [[package]] name = "ckb-merkle-mountain-range" -version = "0.3.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f061f97d64fd1822664bdfb722f7ae5469a97b77567390f7442be5b5dc82a5b" +checksum = "56ccb671c5921be8a84686e6212ca184cb1d7c51cadcdbfcbd1cc3f042f5dfb8" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] @@ -1093,7 +1078,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44919ecaf6f99e8e737bc239408931c9a01e9a6c74814fee8242dd2506b65390" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "glob", ] @@ -1276,7 +1261,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1323,7 +1308,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -1333,7 +1318,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] @@ -1344,7 +1329,7 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", "lazy_static", "memoffset", @@ -1357,7 +1342,7 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] @@ -1671,7 +1656,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -1710,7 +1695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" dependencies = [ "byteorder", - "quick-error 1.2.3", + "quick-error", ] [[package]] @@ -2048,7 +2033,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "winapi", @@ -2095,7 +2080,7 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crc32fast", "libc", "libz-sys", @@ -2150,7 +2135,7 @@ dependencies = [ "linregress", "log", "parity-scale-codec", - "paste 1.0.6", + "paste", "rusty-fork", "scale-info", "serde", @@ -2294,7 +2279,7 @@ version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "parity-scale-codec", "scale-info", "serde", @@ -2315,7 +2300,7 @@ dependencies = [ "once_cell", "parity-scale-codec", "parity-util-mem", - "paste 1.0.6", + "paste", "pretty_assertions", "scale-info", "serde", @@ -2676,7 +2661,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", @@ -2689,7 +2674,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.10.0+wasi-snapshot-preview1", ] @@ -2809,16 +2794,16 @@ checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" [[package]] name = "handlebars" -version = "4.2.2" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d6a30320f094710245150395bc763ad23128d6a1ebbad7594dc4164b62c56b" +checksum = "433e4ab33f1213cdc25b5fa45c76881240cfe79284cf2b395e8b9e312a30a2fd" dependencies = [ "log", "pest", "pest_derive", - "quick-error 2.0.0", "serde", "serde_json", + "thiserror", ] [[package]] @@ -2945,7 +2930,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.1", + "itoa 1.0.4", ] [[package]] @@ -2961,9 +2946,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.5.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -2979,9 +2964,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.16" +version = "0.14.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" +checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" dependencies = [ "bytes", "futures-channel", @@ -2992,7 +2977,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 0.4.8", + "itoa 1.0.4", "pin-project-lite 0.2.6", "socket2", "tokio", @@ -3107,7 +3092,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -3166,9 +3151,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "jobserver" @@ -3338,7 +3323,7 @@ version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3636d281d46c3b64182eb3a0a42b7b483191a2ecc3f05301fa67403f7c9bc949" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ecdsa", "elliptic-curve", "sha2 0.10.2", @@ -3542,7 +3527,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "winapi", ] @@ -3646,7 +3631,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "lru 0.8.1", + "lru", "prost", "prost-build", "prost-codec", @@ -4002,20 +3987,20 @@ checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" [[package]] name = "lite-json" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0460d985423a026b4d9b828a7c6eed1bcf606f476322f3f9b507529686a61715" +checksum = "cd0e787ffe1153141a0f6f6d759fdf1cc34b1226e088444523812fd412a5cca2" dependencies = [ "lite-parser", ] [[package]] name = "lite-parser" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c50092e40e0ccd1bf2015a10333fde0502ff95b832b0895dc1ca0d7ac6c52f6" +checksum = "c3d5f9dc37c52d889a21fd701983d02bb6a84f852c5140a6c80ef4557f7dc29e" dependencies = [ - "paste 0.1.18", + "paste", ] [[package]] @@ -4033,7 +4018,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "value-bag", ] @@ -4058,15 +4043,6 @@ dependencies = [ "syn", ] -[[package]] -name = "lru" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32613e41de4c47ab04970c348ca7ae7382cf116625755af070b008a15516a889" -dependencies = [ - "hashbrown 0.11.2", -] - [[package]] name = "lru" version = "0.8.1" @@ -4114,12 +4090,6 @@ dependencies = [ "libc", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "match_cfg" version = "0.1.0" @@ -4256,7 +4226,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2be9a9090bc1cac2930688fa9478092a64c6a92ddc6ae0692d46b37d9cab709" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "downcast", "fragile", "lazy_static", @@ -4271,7 +4241,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86d702a0530a0141cf4ed147cf5ec7be6f2c187d4e37fcbefc39cf34116bfe8f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "proc-macro2", "quote", "syn", @@ -4373,7 +4343,7 @@ dependencies = [ "matrixmultiply", "nalgebra-macros", "num-complex", - "num-rational 0.4.0", + "num-rational", "num-traits", "rand 0.8.5", "rand_distr", @@ -4435,7 +4405,7 @@ checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e" dependencies = [ "anyhow", "byteorder", - "paste 1.0.6", + "paste", "thiserror", ] @@ -4475,7 +4445,7 @@ checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ "bitflags", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "memoffset", ] @@ -4487,7 +4457,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" dependencies = [ "bitflags", - "cfg-if 1.0.0", + "cfg-if", "libc", ] @@ -4828,12 +4798,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "nohash-hasher" version = "0.2.0" @@ -4857,17 +4821,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" -[[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-bigint" version = "0.4.3" @@ -4890,12 +4843,12 @@ dependencies = [ [[package]] name = "num-format" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465" +checksum = "54b862ff8df690cf089058c98b183676a7ed0f974cc08b426800093227cbff3b" dependencies = [ - "arrayvec 0.4.12", - "itoa 0.4.8", + "arrayvec 0.7.2", + "itoa 1.0.4", ] [[package]] @@ -4910,24 +4863,12 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" -dependencies = [ - "autocfg", - "num-bigint 0.2.6", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint 0.4.3", + "num-bigint", "num-integer", "num-traits", ] @@ -6488,7 +6429,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d32c34f4f5ca7f9196001c0aba5a1f9a5a12382c8944b8b0f90233282d1e8f8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "hashbrown 0.12.3", "impl-trait-for-tuples", "parity-util-mem-derive", @@ -6548,7 +6489,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -6562,7 +6503,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "smallvec", @@ -6571,28 +6512,9 @@ dependencies = [ [[package]] name = "paste" -version = "0.1.18" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" -dependencies = [ - "paste-impl", - "proc-macro-hack", -] - -[[package]] -name = "paste" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" - -[[package]] -name = "paste-impl" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" -dependencies = [ - "proc-macro-hack", -] +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" [[package]] name = "pbkdf2" @@ -6626,18 +6548,19 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pest" -version = "2.1.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a" dependencies = [ + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.1.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2" dependencies = [ "pest", "pest_generator", @@ -6645,9 +6568,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.1.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db" dependencies = [ "pest", "pest_meta", @@ -6658,13 +6581,13 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.1.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d" dependencies = [ - "maplit", + "once_cell", "pest", - "sha-1 0.8.2", + "sha1", ] [[package]] @@ -6767,14 +6690,15 @@ dependencies = [ [[package]] name = "polling" -version = "2.0.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" +checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2" dependencies = [ - "cfg-if 0.1.10", + "autocfg", + "cfg-if", "libc", "log", - "wepoll-sys", + "wepoll-ffi", "winapi", ] @@ -6795,7 +6719,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "opaque-debug 0.3.0", "universal-hash", @@ -6896,12 +6820,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - [[package]] name = "proc-macro2" version = "1.0.46" @@ -6917,7 +6835,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f64969ffd5dd8f39bd57a68ac53c163a095ed9d0fb707146da1b27025a3504" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fnv", "lazy_static", "memchr", @@ -6932,7 +6850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c473049631c233933d6286c88bbb7be30e62ec534cf99a9ae0079211f7fa603" dependencies = [ "dtoa", - "itoa 1.0.1", + "itoa 1.0.4", "parking_lot 0.12.1", "prometheus-client-derive-text-encode", ] @@ -7049,12 +6967,6 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quick-error" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda" - [[package]] name = "quickcheck" version = "1.0.3" @@ -7366,7 +7278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" dependencies = [ "hostname", - "quick-error 1.2.3", + "quick-error", ] [[package]] @@ -7551,7 +7463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" dependencies = [ "fnv", - "quick-error 1.2.3", + "quick-error", "tempfile", ] @@ -7867,12 +7779,11 @@ dependencies = [ "futures", "log", "merlin", - "num-bigint 0.2.6", - "num-rational 0.2.4", + "num-bigint", + "num-rational", "num-traits", "parity-scale-codec", "parking_lot 0.12.1", - "rand 0.7.3", "rand_chacha 0.2.2", "sc-block-builder", "sc-client-api", @@ -8050,11 +7961,11 @@ dependencies = [ "criterion", "env_logger", "lazy_static", - "lru 0.7.5", + "lru", "num_cpus", "parity-scale-codec", "parking_lot 0.12.1", - "paste 1.0.6", + "paste", "regex", "sc-executor-common", "sc-executor-wasmi", @@ -8117,13 +8028,13 @@ dependencies = [ name = "sc-executor-wasmtime" version = "0.10.0-dev" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "log", "once_cell", "parity-scale-codec", "parity-wasm", - "paste 1.0.6", + "paste", "rustix", "sc-allocator", "sc-executor-common", @@ -8262,7 +8173,7 @@ dependencies = [ "linked-hash-map", "linked_hash_set", "log", - "lru 0.7.5", + "lru", "parity-scale-codec", "parking_lot 0.12.1", "pin-project", @@ -8356,7 +8267,7 @@ dependencies = [ "futures-timer", "libp2p", "log", - "lru 0.7.5", + "lru", "quickcheck", "sc-network-common", "sc-peerset", @@ -8396,7 +8307,7 @@ dependencies = [ "futures", "libp2p", "log", - "lru 0.7.5", + "lru", "mockall", "parity-scale-codec", "prost", @@ -8625,7 +8536,7 @@ dependencies = [ name = "sc-runtime-test" version = "2.0.0" dependencies = [ - "paste 1.0.6", + "paste", "sp-core", "sp-io", "sp-runtime", @@ -8920,7 +8831,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8980cafbe98a7ee7a9cc16b32ebce542c77883f512d83fbf2ddc8f6a85ea74c9" dependencies = [ "bitvec", - "cfg-if 1.0.0", + "cfg-if", "derive_more", "parity-scale-codec", "scale-info-derive", @@ -9137,7 +9048,7 @@ version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ - "itoa 1.0.1", + "itoa 1.0.4", "ryu", "serde", ] @@ -9151,18 +9062,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", -] - [[package]] name = "sha-1" version = "0.9.4" @@ -9170,12 +9069,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpuid-bool", "digest 0.9.0", "opaque-debug 0.3.0", ] +[[package]] +name = "sha1" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + [[package]] name = "sha2" version = "0.8.2" @@ -9195,7 +9105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", @@ -9207,7 +9117,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.10.3", ] @@ -9275,7 +9185,7 @@ dependencies = [ "approx", "num-complex", "num-traits", - "paste 1.0.6", + "paste", ] [[package]] @@ -9342,7 +9252,7 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "sha-1 0.9.4", + "sha-1", ] [[package]] @@ -9442,7 +9352,7 @@ name = "sp-arithmetic-fuzzer" version = "2.0.0" dependencies = [ "honggfuzz", - "num-bigint 0.2.6", + "num-bigint", "primitive-types", "sp-arithmetic", ] @@ -9487,7 +9397,7 @@ version = "4.0.0-dev" dependencies = [ "futures", "log", - "lru 0.7.5", + "lru", "parity-scale-codec", "parking_lot 0.12.1", "sp-api", @@ -9865,7 +9775,7 @@ dependencies = [ "log", "parity-scale-codec", "parity-util-mem", - "paste 1.0.6", + "paste", "rand 0.7.3", "scale-info", "serde", @@ -10128,7 +10038,7 @@ dependencies = [ "hash-db", "hashbrown 0.12.3", "lazy_static", - "lru 0.7.5", + "lru", "memory-db", "nohash-hasher", "parity-scale-codec", @@ -10472,7 +10382,7 @@ version = "2.0.0" dependencies = [ "beefy-merkle-tree", "beefy-primitives", - "cfg-if 1.0.0", + "cfg-if", "frame-support", "frame-system", "frame-system-rpc-runtime-api", @@ -10661,7 +10571,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "libc", "redox_syscall", @@ -10908,7 +10818,7 @@ version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "log", "pin-project-lite 0.2.6", "tracing-attributes", @@ -11051,7 +10961,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" dependencies = [ "async-trait", - "cfg-if 1.0.0", + "cfg-if", "data-encoding", "enum-as-inner", "futures-channel", @@ -11074,7 +10984,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "futures-util", "ipconfig", "lazy_static", @@ -11148,7 +11058,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "digest 0.10.3", "rand 0.8.5", "static_assertions", @@ -11363,7 +11273,7 @@ version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e68338db6becec24d3c7977b5bf8a48be992c934b5d07177e3931f5dc9b076c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -11388,7 +11298,7 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3de431a2910c86679c34283a33f66f4e4abd7e0aec27b6669060148872aadf94" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -11494,7 +11404,7 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f727a39e7161f7438ddb8eafe571b67c576a8c2fb459f666d9053b5bba4afdea" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "indexmap", "js-sys", "loupe", @@ -11614,7 +11524,7 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccd7fdc60e252a795c849b3f78a81a134783051407e7e279c10b7019139ef8dc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "enum-iterator", "enumset", "leb128", @@ -11639,7 +11549,7 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcff0cd2c01a8de6009fd863b14ea883132a468a24f2d2ee59dc34453d3a31b5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "enum-iterator", "enumset", "leb128", @@ -11686,7 +11596,7 @@ checksum = "afdc46158517c2769f9938bc222a7d41b3bb330824196279d8aa2d667cd40641" dependencies = [ "backtrace", "cc", - "cfg-if 1.0.0", + "cfg-if", "enum-iterator", "indexmap", "libc", @@ -11730,7 +11640,7 @@ dependencies = [ "downcast-rs", "libm", "memory_units", - "num-rational 0.4.0", + "num-rational", "num-traits", ] @@ -11757,13 +11667,13 @@ checksum = "8a10dc9784d8c3a33c970e3939180424955f08af2e7f20368ec02685a0e8f065" dependencies = [ "anyhow", "bincode", - "cfg-if 1.0.0", + "cfg-if", "indexmap", "libc", "log", "object 0.29.0", "once_cell", - "paste 1.0.6", + "paste", "psm", "rayon", "serde", @@ -11783,7 +11693,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee4dbdc6daf68528cad1275ac91e3f51848ce9824385facc94c759f529decdf8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -11855,7 +11765,7 @@ dependencies = [ "addr2line", "anyhow", "bincode", - "cfg-if 1.0.0", + "cfg-if", "cpp_demangle", "gimli 0.26.1", "log", @@ -11890,14 +11800,14 @@ checksum = "ae79e0515160bd5abee5df50a16c4eb8db9f71b530fc988ae1d9ce34dcb8dd01" dependencies = [ "anyhow", "cc", - "cfg-if 1.0.0", + "cfg-if", "indexmap", "libc", "log", "mach", "memfd", "memoffset", - "paste 1.0.6", + "paste", "rand 0.8.5", "rustix", "thiserror", @@ -11967,10 +11877,10 @@ dependencies = [ ] [[package]] -name = "wepoll-sys" -version = "3.0.1" +name = "wepoll-ffi" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" dependencies = [ "cc", ] diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 54da2d6e49e39..6eefc60552388 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -15,17 +15,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.57" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ - "derive", -] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" log = "0.4.17" merlin = "2.0" -num-bigint = "0.2.3" -num-rational = "0.2.2" +num-bigint = "0.4.3" +num-rational = "0.4.1" num-traits = "0.2.8" parking_lot = "0.12.1" -rand = "0.7.2" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0" diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 896bfaeda1dc9..b39153faa6d1a 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -85,7 +85,7 @@ pub(super) fn calculate_primary_threshold( qed.", ); - ((BigUint::one() << 128) * numer / denom).to_u128().expect( + ((BigUint::one() << 128usize) * numer / denom).to_u128().expect( "returns None if the underlying value cannot be represented with 128 bits; \ we start with 2^128 which is one more than can be represented with 128 bits; \ we multiple by p which is defined in [0, 1); \ diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index a2886663b2c8f..8bef1b38b929d 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -22,8 +22,10 @@ use super::*; use authorship::claim_slot; use futures::executor::block_on; use log::debug; -use rand::RngCore; -use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; +use rand_chacha::{ + rand_core::{RngCore, SeedableRng}, + ChaChaRng, +}; use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; use sc_client_api::{backend::TransactionFor, BlockchainEvents, Finalizer}; use sc_consensus::{BoxBlockImport, BoxJustificationImport}; diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index bda2992392707..1a6c281c77ff5 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] lazy_static = "1.4.0" -lru = "0.7.5" +lru = "0.8.1" parking_lot = "0.12.1" tracing = "0.1.29" wasmi = "0.13" diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 1dee739c50f9e..991802340db61 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -32,6 +32,7 @@ use sc_executor_common::{ use sp_core::traits::{Externalities, FetchRuntimeCode, RuntimeCode}; use sp_version::RuntimeVersion; use std::{ + num::NonZeroUsize, panic::AssertUnwindSafe, path::{Path, PathBuf}, sync::Arc, @@ -179,17 +180,15 @@ impl RuntimeCache { /// for caching. /// /// `runtime_cache_size` specifies the number of different runtimes versions preserved in an - /// in-memory cache. + /// in-memory cache, must always be at least 1. pub fn new( max_runtime_instances: usize, cache_path: Option, runtime_cache_size: u8, ) -> RuntimeCache { - RuntimeCache { - runtimes: Mutex::new(LruCache::new(runtime_cache_size.into())), - max_runtime_instances, - cache_path, - } + let cap = + NonZeroUsize::new(runtime_cache_size.max(1) as usize).expect("cache size is not zero"); + RuntimeCache { runtimes: Mutex::new(LruCache::new(cap)), max_runtime_instances, cache_path } } /// Prepares a WASM module instance and executes given function for it. diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index e84013fbfe436..95c281456396d 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.21" futures-timer = "3.0.1" libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" -lru = "0.7.5" +lru = "0.8.1" tracing = "0.1.29" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 600383cf5f70d..001f2c6136a00 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -24,7 +24,7 @@ use lru::LruCache; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network_common::protocol::{role::ObservedRole, ProtocolName}; use sp_runtime::traits::{Block as BlockT, Hash, HashFor}; -use std::{collections::HashMap, iter, sync::Arc, time, time::Instant}; +use std::{collections::HashMap, iter, num::NonZeroUsize, sync::Arc, time, time::Instant}; // FIXME: Add additional spam/DoS attack protection: https://github.com/paritytech/substrate/issues/1115 // NOTE: The current value is adjusted based on largest production network deployment (Kusama) and @@ -180,7 +180,11 @@ impl ConsensusGossip { ConsensusGossip { peers: HashMap::new(), messages: Default::default(), - known_messages: LruCache::new(KNOWN_MESSAGES_CACHE_SIZE), + known_messages: { + let cap = NonZeroUsize::new(KNOWN_MESSAGES_CACHE_SIZE) + .expect("cache capacity is not zero"); + LruCache::new(cap) + }, protocol, validator, next_broadcast: Instant::now() + REBROADCAST_INTERVAL, diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 81b684af433d2..4637a2a5105e5 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -30,7 +30,7 @@ libp2p = { version = "0.49.0", features = ["async-std", "dns", "identify", "kad" linked_hash_set = "0.1.3" linked-hash-map = "0.5.4" log = "0.4.17" -lru = "0.7.5" +lru = "0.8.1" parking_lot = "0.12.1" pin-project = "1.0.12" prost = "0.11" diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index a04dba79f7fd2..63d060f423773 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -31,6 +31,7 @@ use libp2p::{ Multiaddr, PeerId, }; use log::{debug, error, info, log, trace, warn, Level}; +use lru::LruCache; use message::{generic::Message as GenericMessage, Message}; use notifications::{Notifications, NotificationsOut}; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; @@ -200,7 +201,7 @@ pub struct Protocol { /// The `PeerId`'s of all boot nodes. boot_node_ids: HashSet, /// A cache for the data that was associated to a block announcement. - block_announce_data_cache: lru::LruCache>, + block_announce_data_cache: LruCache>, } #[derive(Debug)] @@ -356,10 +357,13 @@ where ) }; - let block_announce_data_cache = lru::LruCache::new( - network_config.default_peers_set.in_peers as usize + - network_config.default_peers_set.out_peers as usize, - ); + let cache_capacity = NonZeroUsize::new( + (network_config.default_peers_set.in_peers as usize + + network_config.default_peers_set.out_peers as usize) + .max(1), + ) + .expect("cache capacity is not zero"); + let block_announce_data_cache = LruCache::new(cache_capacity); let protocol = Self { tick_timeout: Box::pin(interval(TICK_TIMEOUT)), diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 441b02fb22b8a..bcd6cf10275fe 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -18,13 +18,11 @@ prost-build = "0.11" [dependencies] array-bytes = "4.1" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ - "derive", -] } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" libp2p = "0.49.0" log = "0.4.17" -lru = "0.7.5" +lru = "0.8.1" mockall = "0.11.2" prost = "0.11" smallvec = "1.8.0" diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index 467d898489b61..b5f8b6b73bce9 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -41,6 +41,7 @@ use sp_runtime::{ use std::{ cmp::min, hash::{Hash, Hasher}, + num::NonZeroUsize, sync::Arc, time::Duration, }; @@ -164,7 +165,9 @@ where ); protocol_config.inbound_queue = Some(tx); - let seen_requests = LruCache::new(num_peer_hint * 2); + let capacity = + NonZeroUsize::new(num_peer_hint.max(1) * 2).expect("cache capacity is not zero"); + let seen_requests = LruCache::new(capacity); (Self { client, request_receiver, seen_requests }, protocol_config) } diff --git a/client/network/sync/src/state_request_handler.rs b/client/network/sync/src/state_request_handler.rs index 441400ef439b7..98f1ed34d0581 100644 --- a/client/network/sync/src/state_request_handler.rs +++ b/client/network/sync/src/state_request_handler.rs @@ -35,6 +35,7 @@ use sc_network_common::{ use sp_runtime::traits::Block as BlockT; use std::{ hash::{Hash, Hasher}, + num::NonZeroUsize, sync::Arc, time::Duration, }; @@ -144,7 +145,9 @@ where ); protocol_config.inbound_queue = Some(tx); - let seen_requests = LruCache::new(num_peer_hint * 2); + let capacity = + NonZeroUsize::new(num_peer_hint.max(1) * 2).expect("cache capacity is not zero"); + let seen_requests = LruCache::new(capacity); (Self { client, request_receiver, seen_requests }, protocol_config) } diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index e63b82757c030..bc5c0ac036021 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -lite-json = { version = "0.1", default-features = false } +lite-json = { version = "0.2.0", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 91ec19d731094..9a3ee517e7d42 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.3.2", default-features = false } +mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/merkle-mountain-range/src/mmr/mod.rs b/frame/merkle-mountain-range/src/mmr/mod.rs index 04fdfa199e72b..19fb7b34382bd 100644 --- a/frame/merkle-mountain-range/src/mmr/mod.rs +++ b/frame/merkle-mountain-range/src/mmr/mod.rs @@ -36,10 +36,10 @@ pub struct Hasher(sp_std::marker::PhantomData<(H, L)>); impl mmr_lib::Merge for Hasher { type Item = Node; - fn merge(left: &Self::Item, right: &Self::Item) -> Self::Item { + fn merge(left: &Self::Item, right: &Self::Item) -> mmr_lib::Result { let mut concat = left.hash().as_ref().to_vec(); concat.extend_from_slice(right.hash().as_ref()); - Node::Hash(::hash(&concat)) + Ok(Node::Hash(::hash(&concat))) } } diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index b1ffa746b6b63..f39e59034dcd0 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] honggfuzz = "0.5.49" -num-bigint = "0.2" +num-bigint = "0.4.3" primitive-types = "0.12.0" sp-arithmetic = { version = "5.0.0", path = ".." } diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 4d4718b4038d4..454bc4d7c1103 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } futures = "0.3.21" log = "0.4.17" -lru = "0.7.5" +lru = "0.8.1" parking_lot = "0.12.1" thiserror = "1.0.30" sp-api = { version = "4.0.0-dev", path = "../api" } diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index 0ced264d5c786..1db37b47e4d44 100644 --- a/primitives/blockchain/src/header_metadata.rs +++ b/primitives/blockchain/src/header_metadata.rs @@ -21,6 +21,7 @@ use lru::LruCache; use parking_lot::RwLock; use sp_runtime::traits::{Block as BlockT, Header, NumberFor, One}; +use std::num::NonZeroUsize; /// Set to the expected max difference between `best` and `finalized` blocks at sync. const LRU_CACHE_SIZE: usize = 5_000; @@ -239,14 +240,15 @@ pub struct HeaderMetadataCache { impl HeaderMetadataCache { /// Creates a new LRU header metadata cache with `capacity`. - pub fn new(capacity: usize) -> Self { + pub fn new(capacity: NonZeroUsize) -> Self { HeaderMetadataCache { cache: RwLock::new(LruCache::new(capacity)) } } } impl Default for HeaderMetadataCache { fn default() -> Self { - HeaderMetadataCache { cache: RwLock::new(LruCache::new(LRU_CACHE_SIZE)) } + let cap = NonZeroUsize::new(LRU_CACHE_SIZE).expect("cache capacity is not zero"); + HeaderMetadataCache { cache: RwLock::new(LruCache::new(cap)) } } } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 2636648f40387..211e071c073af 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = hashbrown = { version = "0.12.3", optional = true } hash-db = { version = "0.15.2", default-features = false } lazy_static = { version = "1.4.0", optional = true } -lru = { version = "0.7.5", optional = true } +lru = { version = "0.8.1", optional = true } memory-db = { version = "0.30.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } diff --git a/primitives/trie/src/cache/shared_cache.rs b/primitives/trie/src/cache/shared_cache.rs index abac8c9f946ca..9d4d36b83a28a 100644 --- a/primitives/trie/src/cache/shared_cache.rs +++ b/primitives/trie/src/cache/shared_cache.rs @@ -35,7 +35,7 @@ lazy_static::lazy_static! { } /// No hashing [`LruCache`]. -type NoHashingLruCache = lru::LruCache>; +type NoHashingLruCache = LruCache>; /// The shared node cache. /// diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 18f668485114b..b8ad97cc6b6fa 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -22,4 +22,4 @@ sp-io = { version = "6.0.0", path = "../../../primitives/io" } # third party chrono = { version = "0.4.19" } git2 = { version = "0.14.2", default-features = false } -num-format = { version = "0.4.0" } +num-format = "0.4.3" From a6da808575fe403ab2bd7f6cd009896cdc6fd71a Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Wed, 9 Nov 2022 15:41:32 +0100 Subject: [PATCH 1364/1472] Consolidate and deduplicate MMR API methods (#12530) * histor. batch proof: make best block arg optional * correct testing range * make generate_batch_proof stub for historical * merge generate_{historical_}batch_proof functions * merge generate_{batch_}proof functions * merge verify_{batch_}proof functions * merge verify_{batch_}proof_stateless functions * remove {Leaf}Proof Not utilized by API anymore, so superfluous. Removal consistent with prior changes to just use "batch" proof API. * rename BatchProof->Proof no need to qualify if only one universal proof type. * cleanup * expose verify_proof rpc api * document verify_proof * expose verify_proof_stateless rpc api * add optional BlockHash to mmr_root rpc api * fixup! expose verify_proof rpc api * fix documentation phrasing Co-authored-by: Adrian Catangiu * documentation grammar Co-authored-by: Adrian Catangiu * define mmr error msgs together with error enum Co-authored-by: Serban Iorga * fixup! define mmr error msgs together with error enum * map decoding errors to CallError::InvalidParams Co-authored-by: Serban Iorga * fixup! map decoding errors to CallError::InvalidParams Co-authored-by: Adrian Catangiu Co-authored-by: parity-processbot <> Co-authored-by: Serban Iorga --- Cargo.lock | 2 + bin/node/runtime/src/lib.rs | 58 +--- client/beefy/src/tests.rs | 36 +-- frame/beefy-mmr/primitives/src/lib.rs | 2 +- frame/merkle-mountain-range/rpc/Cargo.toml | 1 + frame/merkle-mountain-range/rpc/src/lib.rs | 287 +++++++++--------- frame/merkle-mountain-range/src/lib.rs | 50 ++- frame/merkle-mountain-range/src/mmr/mmr.rs | 16 +- .../merkle-mountain-range/src/mmr/storage.rs | 2 +- frame/merkle-mountain-range/src/tests.rs | 82 +++-- primitives/beefy/src/mmr.rs | 2 +- primitives/merkle-mountain-range/Cargo.toml | 1 + primitives/merkle-mountain-range/src/lib.rs | 97 ++---- 13 files changed, 249 insertions(+), 387 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d65411de0125c..a959bc42def38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5667,6 +5667,7 @@ dependencies = [ name = "pallet-mmr-rpc" version = "3.0.0" dependencies = [ + "anyhow", "jsonrpsee", "parity-scale-codec", "serde", @@ -9707,6 +9708,7 @@ dependencies = [ "sp-debug-derive", "sp-runtime", "sp-std", + "thiserror", ] [[package]] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index d94a31422be8b..270386be2bbd3 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2055,59 +2055,15 @@ impl_runtime_apis! { mmr::Hash, BlockNumber, > for Runtime { - fn generate_proof(block_number: BlockNumber) - -> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof), mmr::Error> - { - Mmr::generate_batch_proof(vec![block_number]).and_then(|(leaves, proof)| - Ok(( - mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]), - mmr::BatchProof::into_single_leaf_proof(proof)? - )) - ) - } - - fn verify_proof(leaf: mmr::EncodableOpaqueLeaf, proof: mmr::Proof) - -> Result<(), mmr::Error> - { - let leaf: mmr::Leaf = leaf - .into_opaque_leaf() - .try_decode() - .ok_or(mmr::Error::Verify)?; - Mmr::verify_leaves(vec![leaf], mmr::Proof::into_batch_proof(proof)) - } - - fn verify_proof_stateless( - root: mmr::Hash, - leaf: mmr::EncodableOpaqueLeaf, - proof: mmr::Proof - ) -> Result<(), mmr::Error> { - let node = mmr::DataOrHash::Data(leaf.into_opaque_leaf()); - pallet_mmr::verify_leaves_proof::(root, vec![node], mmr::Proof::into_batch_proof(proof)) - } - fn mmr_root() -> Result { Ok(Mmr::mmr_root()) } - fn generate_batch_proof( - block_numbers: Vec, - ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { - Mmr::generate_batch_proof(block_numbers).map(|(leaves, proof)| { - ( - leaves - .into_iter() - .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)) - .collect(), - proof, - ) - }) - } - - fn generate_historical_batch_proof( + fn generate_proof( block_numbers: Vec, - best_known_block_number: BlockNumber, - ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { - Mmr::generate_historical_batch_proof(block_numbers, best_known_block_number).map( + best_known_block_number: Option, + ) -> Result<(Vec, mmr::Proof), mmr::Error> { + Mmr::generate_proof(block_numbers, best_known_block_number).map( |(leaves, proof)| { ( leaves @@ -2120,7 +2076,7 @@ impl_runtime_apis! { ) } - fn verify_batch_proof(leaves: Vec, proof: mmr::BatchProof) + fn verify_proof(leaves: Vec, proof: mmr::Proof) -> Result<(), mmr::Error> { let leaves = leaves.into_iter().map(|leaf| @@ -2130,10 +2086,10 @@ impl_runtime_apis! { Mmr::verify_leaves(leaves, proof) } - fn verify_batch_proof_stateless( + fn verify_proof_stateless( root: mmr::Hash, leaves: Vec, - proof: mmr::BatchProof + 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) diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 2f0306209071e..1d5da4aaefba3 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -43,7 +43,7 @@ use beefy_primitives::{ KEY_TYPE as BeefyKeyType, }; use sc_network::{config::RequestResponseConfig, ProtocolName}; -use sp_mmr_primitives::{BatchProof, EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof}; +use sp_mmr_primitives::{EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; @@ -246,47 +246,25 @@ macro_rules! create_test_api { } impl MmrApi> for RuntimeApi { - fn generate_proof(_block_number: u64) - -> Result<(EncodableOpaqueLeaf, Proof), MmrError> { - unimplemented!() - } - - fn verify_proof(_leaf: EncodableOpaqueLeaf, _proof: Proof) - -> Result<(), MmrError> { - unimplemented!() - } - - fn verify_proof_stateless( - _root: MmrRootHash, - _leaf: EncodableOpaqueLeaf, - _proof: Proof - ) -> Result<(), MmrError> { - unimplemented!() - } - fn mmr_root() -> Result { Ok($mmr_root) } - fn generate_batch_proof(_block_numbers: Vec) -> Result<(Vec, BatchProof), MmrError> { - unimplemented!() - } - - fn generate_historical_batch_proof( + fn generate_proof( _block_numbers: Vec, - _best_known_block_number: u64 - ) -> Result<(Vec, BatchProof), MmrError> { + _best_known_block_number: Option + ) -> Result<(Vec, Proof), MmrError> { unimplemented!() } - fn verify_batch_proof(_leaves: Vec, _proof: BatchProof) -> Result<(), MmrError> { + fn verify_proof(_leaves: Vec, _proof: Proof) -> Result<(), MmrError> { unimplemented!() } - fn verify_batch_proof_stateless( + fn verify_proof_stateless( _root: MmrRootHash, _leaves: Vec, - _proof: BatchProof + _proof: Proof ) -> Result<(), MmrError> { unimplemented!() } diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/frame/beefy-mmr/primitives/src/lib.rs index f56be8bcafe5b..f88fb89acaaab 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/frame/beefy-mmr/primitives/src/lib.rs @@ -29,7 +29,7 @@ //! Inner nodes are created by concatenating child hashes and hashing again. The implementation //! does not perform any sorting of the input data (leaves) nor when inner nodes are created. //! -//! If the number of leaves is not even, last leave (hash of) is promoted to the upper layer. +//! If the number of leaves is not even, last leaf (hash of) is promoted to the upper layer. pub use sp_runtime::traits::Keccak256; use sp_runtime::{app_crypto::sp_core, sp_std, traits::Hash as HashT}; diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 3da6678a39bf2..eb2e1e8b53d9e 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -21,6 +21,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-mmr-primitives = { version = "4.0.0-dev", path = "../../../primitives/merkle-mountain-range" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +anyhow = "1" [dev-dependencies] serde_json = "1.0.85" diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index ffc7ac2da56bf..8476d82f3e70d 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -22,7 +22,7 @@ use std::{marker::PhantomData, sync::Arc}; -use codec::{Codec, Encode}; +use codec::{Codec, Decode, Encode}; use jsonrpsee::{ core::{async_trait, RpcResult}, proc_macros::rpc, @@ -33,58 +33,33 @@ use serde::{Deserialize, Serialize}; use sp_api::{NumberFor, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::Bytes; -use sp_mmr_primitives::{BatchProof, Error as MmrError, Proof}; +use sp_mmr_primitives::{Error as MmrError, Proof}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; const RUNTIME_ERROR: i32 = 8000; const MMR_ERROR: i32 = 8010; -const LEAF_NOT_FOUND_ERROR: i32 = MMR_ERROR + 1; -const GENERATE_PROOF_ERROR: i32 = MMR_ERROR + 2; - -/// Retrieved MMR leaf and its proof. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub struct LeafProof { - /// Block hash the proof was generated for. - pub block_hash: BlockHash, - /// SCALE-encoded leaf data. - pub leaf: Bytes, - /// SCALE-encoded proof data. See [sp_mmr_primitives::Proof]. - pub proof: Bytes, -} - -impl LeafProof { - /// Create new `LeafProof` from given concrete `leaf` and `proof`. - pub fn new(block_hash: BlockHash, leaf: Leaf, proof: Proof) -> Self - where - Leaf: Encode, - MmrHash: Encode, - { - Self { block_hash, leaf: Bytes(leaf.encode()), proof: Bytes(proof.encode()) } - } -} /// Retrieved MMR leaves and their proof. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] -pub struct LeafBatchProof { +pub struct LeavesProof { /// Block hash the proof was generated for. pub block_hash: BlockHash, /// SCALE-encoded vector of `LeafData`. pub leaves: Bytes, - /// SCALE-encoded proof data. See [sp_mmr_primitives::BatchProof]. + /// SCALE-encoded proof data. See [sp_mmr_primitives::Proof]. pub proof: Bytes, } -impl LeafBatchProof { - /// Create new `LeafBatchProof` from a given vector of `Leaf` and a - /// [sp_mmr_primitives::BatchProof]. +impl LeavesProof { + /// Create new `LeavesProof` from a given vector of `Leaf` and a + /// [sp_mmr_primitives::Proof]. pub fn new( block_hash: BlockHash, leaves: Vec, - proof: BatchProof, + proof: Proof, ) -> Self where Leaf: Encode, @@ -96,63 +71,59 @@ impl LeafBatchProof { /// MMR RPC methods. #[rpc(client, server)] -pub trait MmrApi { - /// Generate MMR proof for given block number. - /// - /// This method calls into a runtime with MMR pallet included and attempts to generate - /// MMR proof for a block with a specified `block_number`. - /// Optionally, a block hash at which the runtime should be queried can be specified. - /// - /// Returns the (full) leaf itself and a proof for this leaf (compact encoding, i.e. hash of - /// the leaf). Both parameters are SCALE-encoded. - #[method(name = "mmr_generateProof")] - fn generate_proof( - &self, - block_number: BlockNumber, - at: Option, - ) -> RpcResult>; +pub trait MmrApi { + /// Get the MMR root hash for the current best block. + #[method(name = "mmr_root")] + fn mmr_root(&self, at: Option) -> RpcResult; - /// Generate MMR proof for the given block numbers. + /// Generate an MMR proof for the given `block_numbers`. /// /// This method calls into a runtime with MMR pallet included and attempts to generate - /// MMR proof for a set of blocks with the specific `block_numbers`. - /// Optionally, a block hash at which the runtime should be queried can be specified. + /// an MMR proof for the set of blocks that have the given `block_numbers` with the MMR root at + /// `best_known_block_number`. `best_known_block_number` must be larger than all the + /// `block_numbers` for the function to succeed. + /// + /// Optionally via `at`, a block hash at which the runtime should be queried can be specified. + /// Optionally via `best_known_block_number`, the proof can be generated using the MMR's state + /// at a specific best block. Note that if `best_known_block_number` is provided, then also + /// specifying the block hash via `at` isn't super-useful here, unless you're generating proof + /// using non-finalized blocks where there are several competing forks. That's because MMR state + /// will be fixed to the state with `best_known_block_number`, which already points to + /// some historical block. /// - /// Returns the leaves and a proof for these leaves (compact encoding, i.e. hash of + /// Returns the (full) leaves and a proof for these leaves (compact encoding, i.e. hash of /// the leaves). Both parameters are SCALE-encoded. /// The order of entries in the `leaves` field of the returned struct /// is the same as the order of the entries in `block_numbers` supplied - #[method(name = "mmr_generateBatchProof")] - fn generate_batch_proof( + #[method(name = "mmr_generateProof")] + fn generate_proof( &self, block_numbers: Vec, + best_known_block_number: Option, at: Option, - ) -> RpcResult>; + ) -> RpcResult>; - /// Generate a MMR proof for the given `block_numbers` given the `best_known_block_number`. + /// Verify an MMR `proof`. /// - /// This method calls into a runtime with MMR pallet included and attempts to generate - /// a MMR proof for the set of blocks that have the given `block_numbers` with MMR given the - /// `best_known_block_number`. `best_known_block_number` must be larger than all the - /// `block_numbers` for the function to succeed. + /// This method calls into a runtime with MMR pallet included and attempts to verify + /// an MMR proof. /// - /// Optionally, a block hash at which the runtime should be queried can be specified. - /// Note that specifying the block hash isn't super-useful here, unless you're generating - /// proof using non-finalized blocks where there are several competing forks. That's because - /// MMR state will be fixed to the state with `best_known_block_number`, which already points to - /// some historical block. + /// Returns `true` if the proof is valid, else returns the verification error. + #[method(name = "mmr_verifyProof")] + fn verify_proof(&self, proof: LeavesProof) -> RpcResult; + + /// Verify an MMR `proof` statelessly given an `mmr_root`. /// - /// Returns the leaves and a proof for these leaves (compact encoding, i.e. hash of - /// the leaves). Both parameters are SCALE-encoded. - /// The order of entries in the `leaves` field of the returned struct - /// is the same as the order of the entries in `block_numbers` supplied - #[method(name = "mmr_generateHistoricalBatchProof")] - fn generate_historical_batch_proof( + /// This method calls into a runtime with MMR pallet included and attempts to verify + /// an MMR proof against a provided MMR root. + /// + /// Returns `true` if the proof is valid, else returns the verification error. + #[method(name = "mmr_verifyProofStateless")] + fn verify_proof_stateless( &self, - block_numbers: Vec, - best_known_block_number: BlockNumber, - at: Option, - ) -> RpcResult>; + mmr_root: MmrHash, + proof: LeavesProof, + ) -> RpcResult; } /// MMR RPC methods. @@ -169,7 +140,7 @@ impl Mmr { } #[async_trait] -impl MmrApiServer<::Hash, NumberFor> +impl MmrApiServer<::Hash, NumberFor, MmrHash> for Mmr where Block: BlockT, @@ -177,89 +148,102 @@ where Client::Api: MmrRuntimeApi>, MmrHash: Codec + Send + Sync + 'static, { - fn generate_proof( - &self, - block_number: NumberFor, - at: Option<::Hash>, - ) -> RpcResult> { + fn mmr_root(&self, at: Option<::Hash>) -> RpcResult { + let block_hash = at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash); let api = self.client.runtime_api(); - let block_hash = at.unwrap_or_else(|| self.client.info().best_hash); - - let (leaf, proof) = api - .generate_proof_with_context( - &BlockId::hash(block_hash), - sp_core::ExecutionContext::OffchainCall(None), - block_number, - ) + let mmr_root = api + .mmr_root(&BlockId::Hash(block_hash)) .map_err(runtime_error_into_rpc_error)? .map_err(mmr_error_into_rpc_error)?; - - Ok(LeafProof::new(block_hash, leaf, proof)) + Ok(mmr_root) } - fn generate_batch_proof( + fn generate_proof( &self, block_numbers: Vec>, + best_known_block_number: Option>, at: Option<::Hash>, - ) -> RpcResult::Hash>> { + ) -> RpcResult::Hash>> { let api = self.client.runtime_api(); let block_hash = at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. self.client.info().best_hash); let (leaves, proof) = api - .generate_batch_proof_with_context( + .generate_proof_with_context( &BlockId::hash(block_hash), sp_core::ExecutionContext::OffchainCall(None), block_numbers, + best_known_block_number, ) .map_err(runtime_error_into_rpc_error)? .map_err(mmr_error_into_rpc_error)?; - Ok(LeafBatchProof::new(block_hash, leaves, proof)) + Ok(LeavesProof::new(block_hash, leaves, proof)) + } + + fn verify_proof(&self, proof: LeavesProof<::Hash>) -> RpcResult { + let api = self.client.runtime_api(); + + let leaves = Decode::decode(&mut &proof.leaves.0[..]) + .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + + let decoded_proof = Decode::decode(&mut &proof.proof.0[..]) + .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + + api.verify_proof_with_context( + &BlockId::hash(proof.block_hash), + sp_core::ExecutionContext::OffchainCall(None), + leaves, + decoded_proof, + ) + .map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; + + Ok(true) } - fn generate_historical_batch_proof( + fn verify_proof_stateless( &self, - block_numbers: Vec>, - best_known_block_number: NumberFor, - at: Option<::Hash>, - ) -> RpcResult::Hash>> { + mmr_root: MmrHash, + proof: LeavesProof<::Hash>, + ) -> RpcResult { let api = self.client.runtime_api(); - let block_hash = at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash); - let (leaves, proof) = api - .generate_historical_batch_proof_with_context( - &BlockId::hash(block_hash), - sp_core::ExecutionContext::OffchainCall(None), - block_numbers, - best_known_block_number, - ) - .map_err(runtime_error_into_rpc_error)? - .map_err(mmr_error_into_rpc_error)?; + let leaves = Decode::decode(&mut &proof.leaves.0[..]) + .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; - Ok(LeafBatchProof::new(block_hash, leaves, proof)) + let decoded_proof = Decode::decode(&mut &proof.proof.0[..]) + .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + + api.verify_proof_stateless( + &BlockId::hash(proof.block_hash), + mmr_root, + leaves, + decoded_proof, + ) + .map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; + + Ok(true) } } -/// Converts a mmr-specific error into a [`CallError`]. +/// Converts an mmr-specific error into a [`CallError`]. fn mmr_error_into_rpc_error(err: MmrError) -> CallError { - let data = format!("{:?}", err); - match err { - MmrError::LeafNotFound => CallError::Custom(ErrorObject::owned( - LEAF_NOT_FOUND_ERROR, - "Leaf was not found", - Some(data), - )), - MmrError::GenerateProof => CallError::Custom(ErrorObject::owned( - GENERATE_PROOF_ERROR, - "Error while generating the proof", - Some(data), - )), - _ => CallError::Custom(ErrorObject::owned(MMR_ERROR, "Unexpected MMR error", Some(data))), - } + let error_code = MMR_ERROR + + match err { + MmrError::LeafNotFound => 1, + MmrError::GenerateProof => 2, + MmrError::Verify => 3, + MmrError::BlockNumToLeafIndex => 4, + MmrError::InvalidBestKnownBlock => 5, + _ => 0, + }; + + CallError::Custom(ErrorObject::owned(error_code, err.to_string(), Some(format!("{:?}", err)))) } /// Converts a runtime trap into a [`CallError`]. @@ -281,12 +265,12 @@ mod tests { // given let leaf = vec![1_u8, 2, 3, 4]; let proof = Proof { - leaf_index: 1, + leaf_indices: vec![1], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], }; - let leaf_proof = LeafProof::new(H256::repeat_byte(0), leaf, proof); + let leaf_proof = LeavesProof::new(H256::repeat_byte(0), vec![leaf], proof); // when let actual = serde_json::to_string(&leaf_proof).unwrap(); @@ -294,21 +278,22 @@ mod tests { // then assert_eq!( actual, - r#"{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","leaf":"0x1001020304","proof":"0x010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"}"# + r#"{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","leaves":"0x041001020304","proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"}"# ); } #[test] - fn should_serialize_leaf_batch_proof() { + fn should_serialize_leaves_proof() { // given - let leaf = vec![1_u8, 2, 3, 4]; - let proof = BatchProof { - leaf_indices: vec![1], + let leaf_a = vec![1_u8, 2, 3, 4]; + let leaf_b = vec![2_u8, 2, 3, 4]; + let proof = Proof { + leaf_indices: vec![1, 2], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], }; - let leaf_proof = LeafBatchProof::new(H256::repeat_byte(0), vec![leaf], proof); + let leaf_proof = LeavesProof::new(H256::repeat_byte(0), vec![leaf_a, leaf_b], proof); // when let actual = serde_json::to_string(&leaf_proof).unwrap(); @@ -316,19 +301,19 @@ mod tests { // then assert_eq!( actual, - r#"{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","leaves":"0x041001020304","proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"}"# + r#"{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","leaves":"0x0810010203041002020304","proof":"0x080100000000000000020000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"}"# ); } #[test] fn should_deserialize_leaf_proof() { // given - let expected = LeafProof { + let expected = LeavesProof { block_hash: H256::repeat_byte(0), - leaf: Bytes(vec![1_u8, 2, 3, 4].encode()), + leaves: Bytes(vec![vec![1_u8, 2, 3, 4]].encode()), proof: Bytes( Proof { - leaf_index: 1, + leaf_indices: vec![1], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], } @@ -337,10 +322,10 @@ mod tests { }; // when - let actual: LeafProof = serde_json::from_str(r#"{ + let actual: LeavesProof = serde_json::from_str(r#"{ "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "leaf":"0x1001020304", - "proof":"0x010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202" + "leaves":"0x041001020304", + "proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202" }"#).unwrap(); // then @@ -348,14 +333,14 @@ mod tests { } #[test] - fn should_deserialize_leaf_batch_proof() { + fn should_deserialize_leaves_proof() { // given - let expected = LeafBatchProof { + let expected = LeavesProof { block_hash: H256::repeat_byte(0), - leaves: Bytes(vec![vec![1_u8, 2, 3, 4]].encode()), + leaves: Bytes(vec![vec![1_u8, 2, 3, 4], vec![2_u8, 2, 3, 4]].encode()), proof: Bytes( - BatchProof { - leaf_indices: vec![1], + Proof { + leaf_indices: vec![1, 2], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], } @@ -364,10 +349,10 @@ mod tests { }; // when - let actual: LeafBatchProof = serde_json::from_str(r#"{ + let actual: LeavesProof = serde_json::from_str(r#"{ "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "leaves":"0x041001020304", - "proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202" + "leaves":"0x0810010203041002020304", + "proof":"0x080100000000000000020000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202" }"#).unwrap(); // then diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 92ab8702b65c0..a2d42417ae5dc 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -22,7 +22,7 @@ //! Details on Merkle Mountain Ranges (MMRs) can be found here: //! //! -//! The MMR pallet constructs a MMR from leaf data obtained on every block from +//! The MMR pallet constructs an MMR from leaf data obtained on every block from //! `LeafDataProvider`. MMR nodes are stored both in: //! - on-chain storage - hashes only; not full leaf content) //! - off-chain storage - via Indexing API we push full leaf content (and all internal nodes as @@ -50,7 +50,7 @@ //! //! Secondary use case is to archive historical data, but still be able to retrieve them on-demand //! if needed. For instance if parent block hashes are stored in the MMR it's possible at any point -//! in time to provide a MMR proof about some past block hash, while this data can be safely pruned +//! in time to provide an MMR proof about some past block hash, while this data can be safely pruned //! from on-chain storage. //! //! NOTE This pallet is experimental and not proven to work in production. @@ -103,7 +103,7 @@ pub trait WeightInfo { fn on_initialize(peaks: NodeIndex) -> Weight; } -/// A MMR specific to the pallet. +/// An MMR specific to the pallet. type ModuleMmr = mmr::Mmr>; /// Leaf data. @@ -287,15 +287,15 @@ pub mod pallet { /// Stateless MMR proof verification for batch of leaves. /// -/// This function can be used to verify received MMR [primitives::BatchProof] (`proof`) +/// This function can be used to verify received MMR [primitives::Proof] (`proof`) /// for given leaves set (`leaves`) against a known MMR root hash (`root`). /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the -/// [primitives::BatchProof]. +/// [primitives::Proof]. pub fn verify_leaves_proof( root: H::Output, leaves: Vec>, - proof: primitives::BatchProof, + proof: primitives::Proof, ) -> Result<(), primitives::Error> where H: traits::Hash, @@ -381,37 +381,23 @@ impl, I: 'static> Pallet { Ok(leaf_idx) } - /// Generate a MMR proof for the given `block_numbers`. + /// Generate an MMR proof for the given `block_numbers`. + /// If `best_known_block_number = Some(n)`, this generates a historical proof for + /// the chain with head at height `n`. + /// Else it generates a proof for the MMR at the current block height. /// /// Note this method can only be used from an off-chain context /// (Offchain Worker or Runtime API call), since it requires /// all the leaves to be present. /// It may return an error or panic if used incorrectly. - pub fn generate_batch_proof( + pub fn generate_proof( block_numbers: Vec, - ) -> Result< - (Vec>, primitives::BatchProof<>::Hash>), - primitives::Error, - > { - Self::generate_historical_batch_proof( - block_numbers, - >::block_number(), - ) - } + best_known_block_number: Option, + ) -> Result<(Vec>, primitives::Proof<>::Hash>), primitives::Error> { + // check whether best_known_block_number provided, else use current best block + let best_known_block_number = + best_known_block_number.unwrap_or_else(|| >::block_number()); - /// Generate a MMR proof for the given `block_numbers` given the `best_known_block_number`. - /// - /// Note this method can only be used from an off-chain context - /// (Offchain Worker or Runtime API call), since it requires - /// all the leaves to be present. - /// It may return an error or panic if used incorrectly. - pub fn generate_historical_batch_proof( - block_numbers: Vec, - best_known_block_number: T::BlockNumber, - ) -> Result< - (Vec>, primitives::BatchProof<>::Hash>), - primitives::Error, - > { let leaves_count = Self::block_num_to_leaf_index(best_known_block_number)?.saturating_add(1); @@ -424,7 +410,7 @@ impl, I: 'static> Pallet { .collect::, _>>()?; let mmr: ModuleMmr = mmr::Mmr::new(leaves_count); - mmr.generate_batch_proof(leaf_indices) + mmr.generate_proof(leaf_indices) } /// Return the on-chain MMR root hash. @@ -440,7 +426,7 @@ impl, I: 'static> Pallet { /// or the proof is invalid. pub fn verify_leaves( leaves: Vec>, - proof: primitives::BatchProof<>::Hash>, + proof: primitives::Proof<>::Hash>, ) -> Result<(), primitives::Error> { if proof.leaf_count > Self::mmr_leaves() || proof.leaf_count == 0 || diff --git a/frame/merkle-mountain-range/src/mmr/mmr.rs b/frame/merkle-mountain-range/src/mmr/mmr.rs index 44e684c1bdcac..1f5a5bdae380b 100644 --- a/frame/merkle-mountain-range/src/mmr/mmr.rs +++ b/frame/merkle-mountain-range/src/mmr/mmr.rs @@ -29,11 +29,11 @@ use sp_std::prelude::*; /// Stateless verification of the proof for a batch of leaves. /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the -/// [primitives::BatchProof] +/// [primitives::Proof] pub fn verify_leaves_proof( root: H::Output, leaves: Vec>, - proof: primitives::BatchProof, + proof: primitives::Proof, ) -> Result where H: sp_runtime::traits::Hash, @@ -60,7 +60,7 @@ where .map_err(|e| Error::Verify.log_debug(e)) } -/// A wrapper around a MMR library to expose limited functionality. +/// A wrapper around an MMR library to expose limited functionality. /// /// Available functions depend on the storage kind ([Runtime](crate::mmr::storage::RuntimeStorage) /// vs [Off-chain](crate::mmr::storage::OffchainStorage)). @@ -91,11 +91,11 @@ where /// Verify proof for a set of leaves. /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have /// the same position in both the `leaves` vector and the `leaf_indices` vector contained in the - /// [primitives::BatchProof] + /// [primitives::Proof] pub fn verify_leaves_proof( &self, leaves: Vec, - proof: primitives::BatchProof<>::Hash>, + proof: primitives::Proof<>::Hash>, ) -> Result { let p = mmr_lib::MerkleProof::, Hasher, L>>::new( self.mmr.mmr_size(), @@ -163,10 +163,10 @@ where /// /// Proof generation requires all the nodes (or their hashes) to be available in the storage. /// (i.e. you can't run the function in the pruned storage). - pub fn generate_batch_proof( + pub fn generate_proof( &self, leaf_indices: Vec, - ) -> Result<(Vec, primitives::BatchProof<>::Hash>), Error> { + ) -> Result<(Vec, primitives::Proof<>::Hash>), Error> { let positions = leaf_indices .iter() .map(|index| mmr_lib::leaf_index_to_pos(*index)) @@ -184,7 +184,7 @@ where self.mmr .gen_proof(positions) .map_err(|e| Error::GenerateProof.log_error(e)) - .map(|p| primitives::BatchProof { + .map(|p| primitives::Proof { leaf_indices, leaf_count, items: p.proof_items().iter().map(|x| x.hash()).collect(), diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index 870ce81226bd2..d16ca8cf1e5c8 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! A MMR storage implementations. +//! An MMR storage implementation. use codec::Encode; use frame_support::log::{debug, error, trace}; diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index dbbdc12c8e1d5..e47f1b3b2e63a 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -27,7 +27,7 @@ use sp_core::{ offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt}, H256, }; -use sp_mmr_primitives::{BatchProof, Compact}; +use sp_mmr_primitives::{Compact, Proof}; pub(crate) fn new_test_ext() -> sp_io::TestExternalities { frame_system::GenesisConfig::default().build_storage::().unwrap().into() @@ -236,18 +236,18 @@ fn should_generate_proofs_correctly() { // when generate proofs for all leaves. let proofs = (1_u64..=best_block_number) .into_iter() - .map(|block_num| crate::Pallet::::generate_batch_proof(vec![block_num]).unwrap()) + .map(|block_num| crate::Pallet::::generate_proof(vec![block_num], None).unwrap()) .collect::>(); // when generate historical proofs for all leaves let historical_proofs = (1_u64..best_block_number) .into_iter() .map(|block_num| { let mut proofs = vec![]; - for leaves_count in block_num..=num_blocks { + for historical_best_block in block_num..=num_blocks { proofs.push( - crate::Pallet::::generate_historical_batch_proof( + crate::Pallet::::generate_proof( vec![block_num], - leaves_count, + Some(historical_best_block), ) .unwrap(), ) @@ -261,7 +261,7 @@ fn should_generate_proofs_correctly() { proofs[0], ( vec![Compact::new(((0, H256::repeat_byte(1)).into(), LeafData::new(1).into(),))], - BatchProof { + Proof { leaf_indices: vec![0], leaf_count: 7, items: vec![ @@ -276,7 +276,7 @@ fn should_generate_proofs_correctly() { historical_proofs[0][0], ( vec![Compact::new(((0, H256::repeat_byte(1)).into(), LeafData::new(1).into(),))], - BatchProof { leaf_indices: vec![0], leaf_count: 1, items: vec![] } + Proof { leaf_indices: vec![0], leaf_count: 1, items: vec![] } ) ); @@ -292,7 +292,7 @@ fn should_generate_proofs_correctly() { proofs[2], ( vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], - BatchProof { + Proof { leaf_indices: vec![2], leaf_count: 7, items: vec![ @@ -312,7 +312,7 @@ fn should_generate_proofs_correctly() { historical_proofs[2][0], ( vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], - BatchProof { + Proof { leaf_indices: vec![2], leaf_count: 3, items: vec![hex( @@ -332,7 +332,7 @@ fn should_generate_proofs_correctly() { historical_proofs[2][2], ( vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], - BatchProof { + Proof { leaf_indices: vec![2], leaf_count: 5, items: vec![ @@ -350,7 +350,7 @@ fn should_generate_proofs_correctly() { ( // NOTE: the leaf index is equivalent to the block number(in this case 5) - 1 vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], - BatchProof { + Proof { leaf_indices: vec![4], leaf_count: 7, items: vec![ @@ -365,7 +365,7 @@ fn should_generate_proofs_correctly() { historical_proofs[4][0], ( vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], - BatchProof { + Proof { leaf_indices: vec![4], leaf_count: 5, items: vec![hex( @@ -380,7 +380,7 @@ fn should_generate_proofs_correctly() { proofs[6], ( vec![Compact::new(((6, H256::repeat_byte(7)).into(), LeafData::new(7).into(),))], - BatchProof { + Proof { leaf_indices: vec![6], leaf_count: 7, items: vec![ @@ -407,11 +407,11 @@ fn should_generate_batch_proof_correctly() { register_offchain_ext(&mut ext); ext.execute_with(|| { // when generate proofs for a batch of leaves - let (.., proof) = crate::Pallet::::generate_batch_proof(vec![1, 5, 6]).unwrap(); + let (.., proof) = crate::Pallet::::generate_proof(vec![1, 5, 6], None).unwrap(); // then assert_eq!( proof, - BatchProof { + Proof { // the leaf indices are equivalent to the above specified block numbers - 1. leaf_indices: vec![0, 4, 5], leaf_count: 7, @@ -425,11 +425,11 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], 6).unwrap(); + crate::Pallet::::generate_proof(vec![1, 5, 6], Some(6)).unwrap(); // then assert_eq!( historical_proof, - BatchProof { + Proof { leaf_indices: vec![0, 4, 5], leaf_count: 6, items: vec![ @@ -441,7 +441,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], 7).unwrap(); + crate::Pallet::::generate_proof(vec![1, 5, 6], None).unwrap(); // then assert_eq!(historical_proof, proof); }); @@ -462,15 +462,15 @@ fn should_verify() { register_offchain_ext(&mut ext); let (leaves, proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![5]).unwrap() + crate::Pallet::::generate_proof(vec![5], None).unwrap() }); let (simple_historical_leaves, simple_historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![5], 6).unwrap() + crate::Pallet::::generate_proof(vec![5], Some(6)).unwrap() }); let (advanced_historical_leaves, advanced_historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![5], 7).unwrap() + crate::Pallet::::generate_proof(vec![5], Some(7)).unwrap() }); ext.execute_with(|| { @@ -502,22 +502,18 @@ fn should_verify_batch_proofs() { blocks_to_add: usize, ) { let (leaves, proof) = ext.execute_with(|| { - crate::Pallet::::generate_batch_proof(block_numbers.to_vec()).unwrap() + crate::Pallet::::generate_proof(block_numbers.to_vec(), None).unwrap() }); - let mmr_size = ext.execute_with(|| crate::Pallet::::mmr_leaves()); - let min_mmr_size = block_numbers.iter().max().unwrap() + 1; + let max_block_number = ext.execute_with(|| frame_system::Pallet::::block_number()); + let min_block_number = block_numbers.iter().max().unwrap(); - // generate historical proofs for all possible mmr sizes, - // lower bound being index of highest leaf to be proven - let historical_proofs = (min_mmr_size..=mmr_size) - .map(|mmr_size| { + // generate all possible historical proofs for the given blocks + let historical_proofs = (*min_block_number..=max_block_number) + .map(|best_block| { ext.execute_with(|| { - crate::Pallet::::generate_historical_batch_proof( - block_numbers.to_vec(), - mmr_size, - ) - .unwrap() + crate::Pallet::::generate_proof(block_numbers.to_vec(), Some(best_block)) + .unwrap() }) }) .collect::>(); @@ -602,11 +598,11 @@ fn verification_should_be_stateless() { register_offchain_ext(&mut ext); let (leaves, proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![5]).unwrap() + crate::Pallet::::generate_proof(vec![5], None).unwrap() }); let (_, historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![5], 6).unwrap() + crate::Pallet::::generate_proof(vec![5], Some(6)).unwrap() }); // Verify proof without relying on any on-chain data. @@ -650,11 +646,11 @@ fn should_verify_batch_proof_statelessly() { register_offchain_ext(&mut ext); let (leaves, proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![1, 4, 5]).unwrap() + crate::Pallet::::generate_proof(vec![1, 4, 5], None).unwrap() }); let (historical_leaves, historical_proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![1, 4, 5], 6).unwrap() + crate::Pallet::::generate_proof(vec![1, 4, 5], Some(6)).unwrap() }); // Verify proof without relying on any on-chain data. @@ -694,7 +690,7 @@ fn should_verify_on_the_next_block_since_there_is_no_pruning_yet() { ext.execute_with(|| { // when - let (leaves, proof5) = crate::Pallet::::generate_batch_proof(vec![5]).unwrap(); + let (leaves, proof5) = crate::Pallet::::generate_proof(vec![5], None).unwrap(); new_block(); // then @@ -928,7 +924,7 @@ fn should_verify_canonicalized() { // Generate proofs for some blocks. let (leaves, proofs) = - ext.execute_with(|| crate::Pallet::::generate_batch_proof(vec![1, 4, 5, 7]).unwrap()); + ext.execute_with(|| crate::Pallet::::generate_proof(vec![1, 4, 5, 7], None).unwrap()); // Verify all previously generated proofs. ext.execute_with(|| { assert_eq!(crate::Pallet::::verify_leaves(leaves, proofs), Ok(())); @@ -936,7 +932,7 @@ fn should_verify_canonicalized() { // Generate proofs for some new blocks. let (leaves, proofs) = ext.execute_with(|| { - crate::Pallet::::generate_batch_proof(vec![block_hash_size + 7]).unwrap() + crate::Pallet::::generate_proof(vec![block_hash_size + 7], None).unwrap() }); // Add some more blocks then verify all previously generated proofs. ext.execute_with(|| { @@ -960,19 +956,19 @@ fn does_not_panic_when_generating_historical_proofs() { ext.execute_with(|| { // when leaf index is invalid assert_eq!( - crate::Pallet::::generate_historical_batch_proof(vec![10], 7), + crate::Pallet::::generate_proof(vec![10], None), Err(Error::BlockNumToLeafIndex), ); // when leaves count is invalid assert_eq!( - crate::Pallet::::generate_historical_batch_proof(vec![3], 100), + crate::Pallet::::generate_proof(vec![3], Some(100)), Err(Error::BlockNumToLeafIndex), ); // when both leaf index and leaves count are invalid assert_eq!( - crate::Pallet::::generate_historical_batch_proof(vec![10], 100), + crate::Pallet::::generate_proof(vec![10], Some(100)), Err(Error::BlockNumToLeafIndex), ); }); diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 78ceef0b6b396..549d2edbdf287 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -64,7 +64,7 @@ pub struct MmrLeaf { pub leaf_extra: ExtraData, } -/// A MMR leaf versioning scheme. +/// An MMR leaf versioning scheme. /// /// Version is a single byte that constist of two components: /// - `major` - 3 bits diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index 0be53132f3eec..e857974ba898c 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -21,6 +21,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } +thiserror = "1.0" [dev-dependencies] array-bytes = "4.1" diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 06bc1f4bffe84..d46cb73c3c5e8 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -23,9 +23,9 @@ use scale_info::TypeInfo; use sp_debug_derive::RuntimeDebug; use sp_runtime::traits; +use sp_std::fmt; #[cfg(not(feature = "std"))] use sp_std::prelude::Vec; -use sp_std::{fmt, vec}; /// A type to describe node position in the MMR (node index). pub type NodeIndex = u64; @@ -69,17 +69,6 @@ impl OnNewRoot for () { fn on_new_root(_root: &Hash) {} } -/// A MMR proof data for one of the leaves. -#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] -pub struct Proof { - /// The index of the leaf the proof is for. - pub leaf_index: LeafIndex, - /// Number of leaves in MMR, when the proof was generated. - pub leaf_count: NodeIndex, - /// Proof elements (hashes of siblings of inner nodes on the path to the leaf). - pub items: Vec, -} - /// A full leaf content stored in the offchain-db. pub trait FullLeaf: Clone + PartialEq + fmt::Debug { /// Encode the leaf either in its full or compact form. @@ -352,9 +341,9 @@ impl_leaf_data_for_tuple!(A:0, B:1, C:2); impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3); impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3, E:4); -/// A MMR proof data for a group of leaves. +/// An MMR proof data for a group of leaves. #[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] -pub struct BatchProof { +pub struct Proof { /// The indices of the leaves the proof is for. pub leaf_indices: Vec, /// Number of leaves in MMR, when the proof was generated. @@ -363,49 +352,39 @@ pub struct BatchProof { pub items: Vec, } -impl BatchProof { - /// Converts batch proof to single leaf proof - pub fn into_single_leaf_proof(proof: BatchProof) -> Result, Error> { - Ok(Proof { - leaf_index: *proof.leaf_indices.get(0).ok_or(Error::InvalidLeafIndex)?, - leaf_count: proof.leaf_count, - items: proof.items, - }) - } -} - -impl Proof { - /// Converts a single leaf proof into a batch proof - pub fn into_batch_proof(proof: Proof) -> BatchProof { - BatchProof { - leaf_indices: vec![proof.leaf_index], - leaf_count: proof.leaf_count, - items: proof.items, - } - } -} /// Merkle Mountain Range operation error. +#[cfg_attr(feature = "std", derive(thiserror::Error))] #[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] pub enum Error { /// Error during translation of a block number into a leaf index. + #[cfg_attr(feature = "std", error("Error translation block number into leaf index"))] BlockNumToLeafIndex, /// Error while pushing new node. + #[cfg_attr(feature = "std", error("Error pushing new node"))] Push, /// Error getting the new root. + #[cfg_attr(feature = "std", error("Error getting new root"))] GetRoot, - /// Error commiting changes. + /// Error committing changes. + #[cfg_attr(feature = "std", error("Error committing changes"))] Commit, /// Error during proof generation. + #[cfg_attr(feature = "std", error("Error generating proof"))] GenerateProof, /// Proof verification error. + #[cfg_attr(feature = "std", error("Invalid proof"))] Verify, /// Leaf not found in the storage. + #[cfg_attr(feature = "std", error("Leaf was not found"))] LeafNotFound, /// Mmr Pallet not included in runtime + #[cfg_attr(feature = "std", error("MMR pallet not included in runtime"))] PalletNotIncluded, /// Cannot find the requested leaf index + #[cfg_attr(feature = "std", error("Requested leaf index invalid"))] InvalidLeafIndex, /// The provided best know block number is invalid. + #[cfg_attr(feature = "std", error("Provided best known block number invalid"))] InvalidBestKnownBlock, } @@ -437,53 +416,31 @@ impl Error { sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. pub trait MmrApi { - /// Generate MMR proof for a block with a specified `block_number`. - fn generate_proof(block_number: BlockNumber) -> Result<(EncodableOpaqueLeaf, Proof), Error>; - - /// Verify MMR proof against on-chain MMR. - /// - /// Note this function will use on-chain MMR root hash and check if the proof - /// matches the hash. - /// See [Self::verify_proof_stateless] for a stateless verifier. - fn verify_proof(leaf: EncodableOpaqueLeaf, proof: Proof) -> Result<(), Error>; - - /// Verify MMR proof against given root hash. - /// - /// Note this function does not require any on-chain storage - the - /// proof is verified against given MMR root hash. - /// - /// The leaf data is expected to be encoded in its compact form. - fn verify_proof_stateless(root: Hash, leaf: EncodableOpaqueLeaf, proof: Proof) - -> Result<(), Error>; - /// Return the on-chain MMR root hash. fn mmr_root() -> Result; - /// Generate MMR proof for a series of blocks with the specified block numbers. - fn generate_batch_proof(block_numbers: Vec) -> Result<(Vec, BatchProof), Error>; - - /// Generate MMR proof for a series of `block_numbers`, given the `best_known_block_number`. - fn generate_historical_batch_proof( + /// Generate MMR proof for a series of block numbers. If `best_known_block_number = Some(n)`, + /// use historical MMR state at given block height `n`. Else, use current MMR state. + fn generate_proof( block_numbers: Vec, - best_known_block_number: BlockNumber - ) -> Result<(Vec, BatchProof), Error>; + best_known_block_number: Option + ) -> Result<(Vec, Proof), Error>; /// Verify MMR proof against on-chain MMR for a batch of leaves. /// - /// Note this function will use on-chain MMR root hash and check if the proof - /// matches the hash. + /// Note this function will use on-chain MMR root hash and check if the proof matches the hash. /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the - /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [BatchProof] - fn verify_batch_proof(leaves: Vec, proof: BatchProof) -> Result<(), Error>; + /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [Proof] + fn verify_proof(leaves: Vec, proof: Proof) -> Result<(), Error>; - /// Verify MMR proof against given root hash or a batch of leaves. + /// Verify MMR proof against given root hash for a batch of leaves. /// /// Note this function does not require any on-chain storage - the /// proof is verified against given MMR root hash. /// /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the - /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [BatchProof] - fn verify_batch_proof_stateless(root: Hash, leaves: Vec, proof: BatchProof) + /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [Proof] + fn verify_proof_stateless(root: Hash, leaves: Vec, proof: Proof) -> Result<(), Error>; } } @@ -508,7 +465,7 @@ mod tests { fn should_encode_decode_proof() { // given let proof: TestProof = Proof { - leaf_index: 5, + leaf_indices: vec![5], leaf_count: 10, items: vec![ hex("c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd"), From 970fe0fa35b88c7a8fa7a20ba3b60ac6b55699a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Nov 2022 19:31:41 +0000 Subject: [PATCH 1365/1472] Bump ss58-registry from 1.29.0 to 1.34.0 (#12659) Bumps [ss58-registry](https://github.com/paritytech/ss58-registry) from 1.29.0 to 1.34.0. - [Release notes](https://github.com/paritytech/ss58-registry/releases) - [Changelog](https://github.com/paritytech/ss58-registry/blob/main/CHANGELOG.md) - [Commits](https://github.com/paritytech/ss58-registry/compare/v1.29.0...v1.34.0) --- updated-dependencies: - dependency-name: ss58-registry dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- primitives/core/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a959bc42def38..af300dd049d9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10129,9 +10129,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.29.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0837b5d62f42082c9d56cd946495ae273a3c68083b637b9153341d5e465146d" +checksum = "37a9821878e1f13aba383aa40a86fb1b33c7265774ec91e32563cb1dd1577496" dependencies = [ "Inflector", "num-format", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 12cc9e2f0b60f..7196598056fe5 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -57,7 +57,7 @@ schnorrkel = { version = "0.9.1", features = [ libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"], optional = true } -ss58-registry = { version = "1.29.0", default-features = false } +ss58-registry = { version = "1.34.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } From 087ec5a5b2c9a960fe0f8dc658ab5b21fe8199b3 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Wed, 9 Nov 2022 20:59:40 +0100 Subject: [PATCH 1366/1472] Add `CreateOrigin` to Assets Pallet (#12586) * add CreateOrigin to Assets pallet * fix asset-tx-payment test * use AccountId > u64 in test * Update frame/assets/src/benchmarking.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> --- bin/node/runtime/src/lib.rs | 1 + frame/assets/src/benchmarking.rs | 8 +++--- frame/assets/src/lib.rs | 27 ++++++++++++------- frame/assets/src/mock.rs | 3 ++- .../asset-tx-payment/src/tests.rs | 3 ++- frame/uniques/src/lib.rs | 2 +- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 270386be2bbd3..eab40634ff241 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1438,6 +1438,7 @@ impl pallet_assets::Config for Runtime { type Balance = u128; type AssetId = u32; type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = EnsureRoot; type AssetDeposit = AssetDeposit; type AssetAccountDeposit = ConstU128; diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index ca891c2f42e4a..2bde2b0c98945 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -150,12 +150,14 @@ fn assert_event, I: 'static>(generic_event: >::Runti benchmarks_instance_pallet! { create { - let caller: T::AccountId = whitelisted_caller(); + let asset_id = Default::default(); + let origin = T::CreateOrigin::successful_origin(&asset_id); + let caller = T::CreateOrigin::ensure_origin(origin, &asset_id).unwrap(); let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, 1u32.into()) + }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup, 1u32.into()) verify { - assert_last_event::(Event::Created { asset_id: Default::default(), creator: caller.clone(), owner: caller }.into()); + assert_last_event::(Event::Created { asset_id, creator: caller.clone(), owner: caller }.into()); } force_create { diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 28743f917d323..7e7d68fa6c7dd 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -36,15 +36,15 @@ //! //! ### Terminology //! -//! * **Admin**: An account ID uniquely privileged to be able to unfreeze (thaw) an account and it's +//! * **Admin**: An account ID uniquely privileged to be able to unfreeze (thaw) an account and its //! assets, as well as forcibly transfer a particular class of assets between arbitrary accounts //! and reduce the balance of a particular class of assets of arbitrary accounts. //! * **Asset issuance/minting**: The creation of a new asset, whose total supply will belong to the -//! account that issues the asset. This is a privileged operation. +//! account designated as the beneficiary of the asset. This is a privileged operation. //! * **Asset transfer**: The reduction of the balance of an asset of one account with the //! corresponding increase in the balance of another. -//! * **Asset destruction**: The process of reduce the balance of an asset of one account. This is a -//! privileged operation. +//! * **Asset destruction**: The process of reducing the balance of an asset of one account. This is +//! a privileged operation. //! * **Fungible asset**: An asset whose units are interchangeable. //! * **Issuer**: An account ID uniquely privileged to be able to mint a particular class of assets. //! * **Freezer**: An account ID uniquely privileged to be able to freeze an account from @@ -63,12 +63,12 @@ //! //! The assets system in Substrate is designed to make the following possible: //! -//! * Issue a new assets in a permissioned or permissionless way, if permissionless, then with a +//! * Issue new assets in a permissioned or permissionless way, if permissionless, then with a //! deposit required. //! * Allow accounts to be delegated the ability to transfer assets without otherwise existing //! on-chain (*approvals*). //! * Move assets between accounts. -//! * Update the asset's total supply. +//! * Update an asset class's total supply. //! * Allow administrative activities by specially privileged accounts including freezing account //! balances and minting/burning assets. //! @@ -92,6 +92,7 @@ //! * `force_cancel_approval`: Rescind a previous approval. //! //! ### Privileged Functions +//! //! * `destroy`: Destroys an entire asset class; called by the asset class's Owner. //! * `mint`: Increases the asset balance of an account; called by the asset class's Issuer. //! * `burn`: Decreases the asset balance of an account; called by the asset class's Admin. @@ -156,7 +157,7 @@ use frame_support::{ traits::{ tokens::{fungibles, DepositConsequence, WithdrawConsequence}, BalanceStatus::Reserved, - Currency, ReservableCurrency, StoredMap, + Currency, EnsureOriginWithArg, ReservableCurrency, StoredMap, }, }; use frame_system::Config as SystemConfig; @@ -206,6 +207,14 @@ pub mod pallet { /// The currency mechanism. type Currency: ReservableCurrency; + /// Standard asset class creation is only allowed if the origin attempting it and the + /// asset class are in this set. + type CreateOrigin: EnsureOriginWithArg< + Self::RuntimeOrigin, + Self::AssetId, + Success = Self::AccountId, + >; + /// The origin which may forcibly create or destroy an asset or otherwise alter privileged /// attributes. type ForceOrigin: EnsureOrigin; @@ -485,7 +494,7 @@ pub mod pallet { /// /// This new asset class has no assets initially and its owner is the origin. /// - /// The origin must be Signed and the sender must have sufficient funds free. + /// The origin must conform to the configured `CreateOrigin` and have sufficient funds free. /// /// Funds of sender are reserved by `AssetDeposit`. /// @@ -507,7 +516,7 @@ pub mod pallet { admin: AccountIdLookupOf, min_balance: T::Balance, ) -> DispatchResult { - let owner = ensure_signed(origin)?; + let owner = T::CreateOrigin::ensure_origin(origin, &id)?; let admin = T::Lookup::lookup(admin)?; ensure!(!Asset::::contains_key(id), Error::::InUse); diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 1f105eb6b4fbc..21fb52c9cd931 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -22,7 +22,7 @@ use crate as pallet_assets; use frame_support::{ construct_runtime, parameter_types, - traits::{ConstU32, ConstU64, GenesisBuild}, + traits::{AsEnsureOriginWithArg, ConstU32, ConstU64, GenesisBuild}, }; use sp_core::H256; use sp_runtime::{ @@ -89,6 +89,7 @@ impl Config for Test { type Balance = u64; type AssetId = u32; type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; type AssetDeposit = ConstU64<1>; type AssetAccountDeposit = ConstU64<10>; diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index e775f3aa92990..cfed1c33c9b24 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -21,7 +21,7 @@ use frame_support::{ dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, pallet_prelude::*, parameter_types, - traits::{fungibles::Mutate, ConstU32, ConstU64, ConstU8, FindAuthor}, + traits::{fungibles::Mutate, AsEnsureOriginWithArg, ConstU32, ConstU64, ConstU8, FindAuthor}, weights::{Weight, WeightToFee as WeightToFeeT}, ConsensusEngineId, }; @@ -157,6 +157,7 @@ impl pallet_assets::Config for Runtime { type Balance = Balance; type AssetId = u32; type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = EnsureRoot; type AssetDeposit = ConstU64<2>; type AssetAccountDeposit = ConstU64<2>; diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index d519eedd2787f..185d8fc0c8edd 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -437,7 +437,7 @@ pub mod pallet { /// /// This new collection has no items initially and its owner is the origin. /// - /// The origin must be Signed and the sender must have sufficient funds free. + /// The origin must conform to the configured `CreateOrigin` and have sufficient funds free. /// /// `ItemDeposit` funds of sender are reserved. /// From 2badd7203b915ae80499544056b3dc5496ccd80e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 9 Nov 2022 21:30:50 +0000 Subject: [PATCH 1367/1472] `sp-runtime`: make `parity-util-mem` dependency optional (#12657) * `sp-runtime`: make `parity-util-mem` dependency optional * Use default-features = false for sp-runtime in sp-keyring * Remove parity-util-mem from sp-core * Cargo.lock * Restore default-features for keyring dependency --- Cargo.lock | 1 - primitives/core/Cargo.toml | 2 -- primitives/runtime/Cargo.toml | 2 +- primitives/runtime/src/transaction_validity.rs | 5 ++--- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af300dd049d9c..9fc220e099a5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9525,7 +9525,6 @@ dependencies = [ "merlin", "num-traits", "parity-scale-codec", - "parity-util-mem", "parking_lot 0.12.1", "primitive-types", "rand 0.7.3", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 7196598056fe5..3e8bac51289b8 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -40,7 +40,6 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } futures = { version = "0.3.21", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.30", optional = true } @@ -78,7 +77,6 @@ bench = false [features] default = ["std"] std = [ - "parity-util-mem/std", "merlin?/std", "full_crypto", "log/std", diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 01594ed69e312..8d7b5b2b93354 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -19,7 +19,7 @@ either = { version = "1.5", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"], optional = true } paste = "1.0" rand = { version = "0.7.2", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/primitives/runtime/src/transaction_validity.rs b/primitives/runtime/src/transaction_validity.rs index 7cc8b70df9f96..4646808b8c8e3 100644 --- a/primitives/runtime/src/transaction_validity.rs +++ b/primitives/runtime/src/transaction_validity.rs @@ -226,9 +226,8 @@ impl From for TransactionValidity { /// Depending on the source we might apply different validation schemes. /// For instance we can disallow specific kinds of transactions if they were not produced /// by our local node (for instance off-chain workers). -#[derive( - Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, parity_util_mem::MallocSizeOf, -)] +#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(parity_util_mem::MallocSizeOf))] pub enum TransactionSource { /// Transaction is already included in block. /// From abb217d85f4eb53e176518648ae223b4ca644f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 9 Nov 2022 23:05:13 +0100 Subject: [PATCH 1368/1472] GrandpaJustification: Feature gate `Debug` (#12664) The grandpa crate is deriving `Debug` only when the `std` feature is enabled. `RuntimeDebug` can be forced to derive `Debug` also in `no_std` and that doesn't work together. So, we should feature gate `Debug` on `no_std`. --- primitives/finality-grandpa/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index 2adfce1bea241..f1584dc673228 100644 --- a/primitives/finality-grandpa/src/lib.rs +++ b/primitives/finality-grandpa/src/lib.rs @@ -129,7 +129,8 @@ pub type CompactCommit
= grandpa::CompactCommit< /// /// This is meant to be stored in the db and passed around the network to other /// nodes, and are used by syncing nodes to prove authority set handoffs. -#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)] +#[derive(Clone, Encode, Decode, PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(Debug))] pub struct GrandpaJustification { pub round: u64, pub commit: Commit
, From 78f8f708781da6fd340ef2a1fc288060a35295ad Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 10 Nov 2022 02:34:00 +0000 Subject: [PATCH 1369/1472] More testing and fuzzing and docs for pools (#12624) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * move pools fuzzing to hongfuzz * merge more small fixes * fix all tests * Update frame/nomination-pools/fuzzer/src/call.rs Co-authored-by: Gonçalo Pestana * remove transactional * fmt * fix CI * fmt * fix build again * fix CI Co-authored-by: Gonçalo Pestana --- Cargo.lock | 33 +- Cargo.toml | 1 + frame/balances/src/lib.rs | 2 +- frame/nomination-pools/Cargo.toml | 7 +- frame/nomination-pools/fuzzer/Cargo.toml | 33 ++ frame/nomination-pools/fuzzer/src/call.rs | 353 ++++++++++++++++++++ frame/nomination-pools/src/lib.rs | 167 +++++----- frame/nomination-pools/src/mock.rs | 23 +- frame/nomination-pools/src/tests.rs | 379 +++------------------- 9 files changed, 562 insertions(+), 436 deletions(-) create mode 100644 frame/nomination-pools/fuzzer/Cargo.toml create mode 100644 frame/nomination-pools/fuzzer/src/call.rs diff --git a/Cargo.lock b/Cargo.lock index 9fc220e099a5c..a13768a64a4ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2902,13 +2902,14 @@ dependencies = [ [[package]] name = "honggfuzz" -version = "0.5.54" +version = "0.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea09577d948a98a5f59b7c891e274c4fb35ad52f67782b3d0cb53b9c05301f1" +checksum = "848e9c511092e0daa0a35a63e8e6e475a3e8f870741448b9f6028d69b142f18e" dependencies = [ "arbitrary", "lazy_static", - "memmap", + "memmap2", + "rustc_version 0.4.0", ] [[package]] @@ -4135,16 +4136,6 @@ dependencies = [ "rustix", ] -[[package]] -name = "memmap" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "memmap2" version = "0.5.0" @@ -5735,7 +5726,6 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "rand 0.8.5", "scale-info", "sp-core", "sp-io", @@ -5769,6 +5759,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-nomination-pools-fuzzer" +version = "2.0.0" +dependencies = [ + "frame-support", + "frame-system", + "honggfuzz", + "log", + "pallet-nomination-pools", + "rand 0.8.5", + "sp-io", + "sp-runtime", + "sp-tracing", +] + [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 45aa5f9854d25..4ba2663cdb409 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -116,6 +116,7 @@ members = [ "frame/preimage", "frame/proxy", "frame/nomination-pools", + "frame/nomination-pools/fuzzer", "frame/nomination-pools/benchmarking", "frame/nomination-pools/test-staking", "frame/nomination-pools/runtime-api", diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 67976cbaf06ac..d3085152eba6c 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -477,7 +477,7 @@ pub mod pallet { VestingBalance, /// Account liquidity restrictions prevent withdrawal LiquidityRestrictions, - /// Balance too low to send value + /// Balance too low to send value. InsufficientBalance, /// Value too low to create account due to existential deposit ExistentialDeposit, diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index 459ee5f440a12..2db0b234b726d 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -26,13 +26,17 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } log = { version = "0.4.0", default-features = false } +# Optional: usef for testing and/or fuzzing +pallet-balances = { version = "4.0.0-dev", path = "../balances", optional = true } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing", optional = true } + [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } -rand = { version = "0.8.5", features = ["small_rng"] } [features] default = ["std"] +fuzzing = ["pallet-balances", "sp-tracing"] std = [ "codec/std", "scale-info/std", @@ -51,4 +55,3 @@ runtime-benchmarks = [ try-runtime = [ "frame-support/try-runtime" ] -fuzz-test = [] diff --git a/frame/nomination-pools/fuzzer/Cargo.toml b/frame/nomination-pools/fuzzer/Cargo.toml new file mode 100644 index 0000000000000..7dde8733e3f60 --- /dev/null +++ b/frame/nomination-pools/fuzzer/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "pallet-nomination-pools-fuzzer" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Fuzzer for fixed point arithmetic primitives." +documentation = "https://docs.rs/sp-arithmetic-fuzzer" +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +honggfuzz = "0.5.54" + +pallet-nomination-pools = { path = "..", features = ["fuzzing"] } + +frame-system = { path = "../../system" } +frame-support = { path = "../../support" } + +sp-runtime = { path = "../../../primitives/runtime" } +sp-io = { path = "../../../primitives/io" } +sp-tracing = { path = "../../../primitives/tracing" } + +rand = { version = "0.8.5", features = ["small_rng"] } +log = "0.4.17" + +[[bin]] +name = "call" +path = "src/call.rs" diff --git a/frame/nomination-pools/fuzzer/src/call.rs b/frame/nomination-pools/fuzzer/src/call.rs new file mode 100644 index 0000000000000..b07903609e8ab --- /dev/null +++ b/frame/nomination-pools/fuzzer/src/call.rs @@ -0,0 +1,353 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Running +//! Running this fuzzer can be done with `cargo hfuzz run call`. `honggfuzz` CLI +//! options can be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads. +//! +//! # Debugging a panic +//! Once a panic is found, it can be debugged with +//! `cargo hfuzz run-debug per_thing_rational hfuzz_workspace/call/*.fuzz`. + +use frame_support::{ + assert_ok, + traits::{Currency, GetCallName, UnfilteredDispatchable}, +}; +use honggfuzz::fuzz; +use pallet_nomination_pools::{ + log, + mock::*, + pallet as pools, + pallet::{BondedPools, Call as PoolsCall, Event as PoolsEvents, PoolMembers}, + BondExtra, BondedPool, LastPoolId, MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, + MinCreateBond, MinJoinBond, PoolId, +}; +use rand::{seq::SliceRandom, Rng}; +use sp_runtime::{assert_eq_error_rate, Perquintill}; + +const ERA: BlockNumber = 1000; +const MAX_ED_MULTIPLE: Balance = 10_000; +const MIN_ED_MULTIPLE: Balance = 10; + +// not quite elegant, just to make it available in random_signed_origin. +const REWARD_AGENT_ACCOUNT: AccountId = 42; + +/// Grab random accounts, either known ones, or new ones. +fn random_signed_origin(rng: &mut R) -> (RuntimeOrigin, AccountId) { + let count = PoolMembers::::count(); + if rng.gen::() && count > 0 { + // take an existing account. + let skip = rng.gen_range(0..count as usize); + + // this is tricky: the account might be our reward agent, which we never want to be + // randomly chosen here. Try another one, or, if it is only our agent, return a random + // one nonetheless. + let candidate = PoolMembers::::iter_keys().skip(skip).take(1).next().unwrap(); + let acc = + if candidate == REWARD_AGENT_ACCOUNT { rng.gen::() } else { candidate }; + + (RuntimeOrigin::signed(acc), acc) + } else { + // create a new account + let acc = rng.gen::(); + (RuntimeOrigin::signed(acc), acc) + } +} + +fn random_ed_multiple(rng: &mut R) -> Balance { + let multiple = rng.gen_range(MIN_ED_MULTIPLE..MAX_ED_MULTIPLE); + ExistentialDeposit::get() * multiple +} + +fn fund_account(rng: &mut R, account: &AccountId) { + let target_amount = random_ed_multiple(rng); + if let Some(top_up) = target_amount.checked_sub(Balances::free_balance(account)) { + let _ = Balances::deposit_creating(account, top_up); + } + assert!(Balances::free_balance(account) >= target_amount); +} + +fn random_existing_pool(mut rng: &mut R) -> Option { + BondedPools::::iter_keys().collect::>().choose(&mut rng).map(|x| *x) +} + +fn random_call(mut rng: &mut R) -> (pools::Call, RuntimeOrigin) { + let op = rng.gen::(); + let mut op_count = as GetCallName>::get_call_names().len(); + // Exclude set_state, set_metadata, set_configs, update_roles and chill. + op_count -= 5; + + match op % op_count { + 0 => { + // join + let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); + let (origin, who) = random_signed_origin(&mut rng); + fund_account(&mut rng, &who); + let amount = random_ed_multiple(&mut rng); + (PoolsCall::::join { amount, pool_id }, origin) + }, + 1 => { + // bond_extra + let (origin, who) = random_signed_origin(&mut rng); + let extra = if rng.gen::() { + BondExtra::Rewards + } else { + fund_account(&mut rng, &who); + let amount = random_ed_multiple(&mut rng); + BondExtra::FreeBalance(amount) + }; + (PoolsCall::::bond_extra { extra }, origin) + }, + 2 => { + // claim_payout + let (origin, _) = random_signed_origin(&mut rng); + (PoolsCall::::claim_payout {}, origin) + }, + 3 => { + // unbond + let (origin, who) = random_signed_origin(&mut rng); + let amount = random_ed_multiple(&mut rng); + (PoolsCall::::unbond { member_account: who, unbonding_points: amount }, origin) + }, + 4 => { + // pool_withdraw_unbonded + let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); + let (origin, _) = random_signed_origin(&mut rng); + (PoolsCall::::pool_withdraw_unbonded { pool_id, num_slashing_spans: 0 }, origin) + }, + 5 => { + // withdraw_unbonded + let (origin, who) = random_signed_origin(&mut rng); + ( + PoolsCall::::withdraw_unbonded { member_account: who, num_slashing_spans: 0 }, + origin, + ) + }, + 6 => { + // create + let (origin, who) = random_signed_origin(&mut rng); + let amount = random_ed_multiple(&mut rng); + fund_account(&mut rng, &who); + let root = who; + let state_toggler = who; + let nominator = who; + (PoolsCall::::create { amount, root, state_toggler, nominator }, origin) + }, + 7 => { + // nominate + let (origin, _) = random_signed_origin(&mut rng); + let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); + let validators = Default::default(); + (PoolsCall::::nominate { pool_id, validators }, origin) + }, + _ => unreachable!(), + } +} + +#[derive(Default)] +struct RewardAgent { + who: AccountId, + pool_id: Option, + expected_reward: Balance, +} + +// TODO: inject some slashes into the game. +impl RewardAgent { + fn new(who: AccountId) -> Self { + Self { who, ..Default::default() } + } + + fn join(&mut self) { + if self.pool_id.is_some() { + return + } + let pool_id = LastPoolId::::get(); + let amount = 10 * ExistentialDeposit::get(); + let origin = RuntimeOrigin::signed(self.who); + let _ = Balances::deposit_creating(&self.who, 10 * amount); + self.pool_id = Some(pool_id); + log::info!(target: "reward-agent", "🤖 reward agent joining in {} with {}", pool_id, amount); + assert_ok!(PoolsCall::join:: { amount, pool_id }.dispatch_bypass_filter(origin)); + } + + fn claim_payout(&mut self) { + // 10 era later, we claim our payout. We expect our income to be roughly what we + // calculated. + if !PoolMembers::::contains_key(&self.who) { + log!(warn, "reward agent is not in the pool yet, cannot claim"); + return + } + let pre = Balances::free_balance(&42); + let origin = RuntimeOrigin::signed(42); + assert_ok!(PoolsCall::::claim_payout {}.dispatch_bypass_filter(origin)); + let post = Balances::free_balance(&42); + + let income = post - pre; + log::info!( + target: "reward-agent", "🤖 CLAIM: actual: {}, expected: {}", + income, + self.expected_reward, + ); + assert_eq_error_rate!(income, self.expected_reward, 10); + self.expected_reward = 0; + } +} + +fn main() { + let mut reward_agent = RewardAgent::new(REWARD_AGENT_ACCOUNT); + sp_tracing::try_init_simple(); + let mut ext = sp_io::TestExternalities::new_empty(); + let mut events_histogram = Vec::<(PoolsEvents, u32)>::default(); + let mut iteration = 0 as BlockNumber; + let mut ok = 0; + let mut err = 0; + + let dot: Balance = (10 as Balance).pow(10); + ExistentialDeposit::set(dot); + BondingDuration::set(8); + + ext.execute_with(|| { + MaxPoolMembers::::set(Some(10_000)); + MaxPoolMembersPerPool::::set(Some(1000)); + MaxPools::::set(Some(1_000)); + + MinCreateBond::::set(10 * ExistentialDeposit::get()); + MinJoinBond::::set(5 * ExistentialDeposit::get()); + System::set_block_number(1); + }); + + loop { + fuzz!(|seed: [u8; 32]| { + use ::rand::{rngs::SmallRng, SeedableRng}; + let mut rng = SmallRng::from_seed(seed); + + ext.execute_with(|| { + let (call, origin) = random_call(&mut rng); + let outcome = call.clone().dispatch_bypass_filter(origin.clone()); + iteration += 1; + match outcome { + Ok(_) => ok += 1, + Err(_) => err += 1, + }; + + log!( + trace, + "iteration {}, call {:?}, origin {:?}, outcome: {:?}, so far {} ok {} err", + iteration, + call, + origin, + outcome, + ok, + err, + ); + + // possibly join the reward_agent + if iteration > ERA / 2 && BondedPools::::count() > 0 { + reward_agent.join(); + } + // and possibly roughly every 4 era, trigger payout for the agent. Doing this more + // frequent is also harmless. + if rng.gen_range(0..(4 * ERA)) == 0 { + reward_agent.claim_payout(); + } + + // execute sanity checks at a fixed interval, possibly on every block. + if iteration % + (std::env::var("SANITY_CHECK_INTERVAL") + .ok() + .and_then(|x| x.parse::().ok())) + .unwrap_or(1) == 0 + { + log!(info, "running sanity checks at {}", iteration); + Pools::do_try_state(u8::MAX).unwrap(); + } + + // collect and reset events. + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| { + if let pallet_nomination_pools::mock::RuntimeEvent::Pools(inner) = e { + Some(inner) + } else { + None + } + }) + .for_each(|e| { + if let Some((_, c)) = events_histogram + .iter_mut() + .find(|(x, _)| std::mem::discriminant(x) == std::mem::discriminant(&e)) + { + *c += 1; + } else { + events_histogram.push((e, 1)) + } + }); + System::reset_events(); + + // trigger an era change, and check the status of the reward agent. + if iteration % ERA == 0 { + CurrentEra::mutate(|c| *c += 1); + BondedPools::::iter().for_each(|(id, _)| { + let amount = random_ed_multiple(&mut rng); + let _ = + Balances::deposit_creating(&Pools::create_reward_account(id), amount); + // if we just paid out the reward agent, let's calculate how much we expect + // our reward agent to have earned. + if reward_agent.pool_id.map_or(false, |mid| mid == id) { + let all_points = BondedPool::::get(id).map(|p| p.points).unwrap(); + let member_points = + PoolMembers::::get(reward_agent.who).map(|m| m.points).unwrap(); + let agent_share = Perquintill::from_rational(member_points, all_points); + log::info!( + target: "reward-agent", + "🤖 REWARD = amount = {:?}, ratio: {:?}, share {:?}", + amount, + agent_share, + agent_share * amount, + ); + reward_agent.expected_reward += agent_share * amount; + } + }); + + log!( + info, + "iteration {}, {} pools, {} members, {} ok {} err, events = {:?}", + iteration, + BondedPools::::count(), + PoolMembers::::count(), + ok, + err, + events_histogram + .iter() + .map(|(x, c)| ( + format!("{:?}", x) + .split(" ") + .map(|x| x.to_string()) + .collect::>() + .first() + .cloned() + .unwrap(), + c, + )) + .collect::>(), + ); + } + }) + }) + } +} diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 3661a7f70b48a..9ca9539b3dca8 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -24,9 +24,10 @@ //! //! * [Key terms](#key-terms) //! * [Usage](#usage) +//! * [Implementor's Guide](#implementors-guide) //! * [Design](#design) //! -//! ## Key terms +//! ## Key Terms //! //! * pool id: A unique identifier of each pool. Set to u32. //! * bonded pool: Tracks the distribution of actively staked funds. See [`BondedPool`] and @@ -88,7 +89,11 @@ //! in the aforementioned range of eras will be affected by the slash. A member is slashed pro-rata //! based on its stake relative to the total slash amount. //! -//! For design docs see the [slashing](#slashing) section. +//! Slashing does not change any single member's balance. Instead, the slash will only reduce the +//! balance associated with a particular pool. But, we never change the total *points* of a pool +//! because of slashing. Therefore, when a slash happens, the ratio of points to balance changes in +//! a pool. In other words, the value of one point, which is initially 1-to-1 against a unit of +//! balance, is now less than one balance because of the slash. //! //! ### Administration //! @@ -96,6 +101,10 @@ //! user must call [`Call::nominate`] to start nominating. [`Call::nominate`] can be called at //! anytime to update validator selection. //! +//! Similar to [`Call::nominate`], [`Call::chill`] will chill to pool in the staking system, and +//! [`Call::pool_withdraw_unbonded`] will withdraw any unbonding chunks of the pool bonded account. +//! The latter call is permissionless and can be called by anyone at any time. +//! //! To help facilitate pool administration the pool has one of three states (see [`PoolState`]): //! //! * Open: Anyone can join the pool and no members can be permissionlessly removed. @@ -121,10 +130,52 @@ //! //! 1. First, all members need to fully unbond and withdraw. If the pool state is set to //! `Destroying`, this can happen permissionlessly. -//! 2. The depositor itself fully unbonds and withdraws. Note that at this point, based on the -//! requirements of the staking system, the pool's bonded account's stake might not be able to ge -//! below a certain threshold as a nominator. At this point, the pool should `chill` itself to -//! allow the depositor to leave. +//! 2. The depositor itself fully unbonds and withdraws. +//! +//! > Note that at this point, based on the requirements of the staking system, the pool's bonded +//! > account's stake might not be able to ge below a certain threshold as a nominator. At this +//! > point, the pool should `chill` itself to allow the depositor to leave. See [`Call::chill`]. +//! +//! ## Implementor's Guide +//! +//! Some notes and common mistakes that wallets/apps wishing to implement this pallet should be +//! aware of: +//! +//! +//! ### Pool Members +//! +//! * In general, whenever a pool member changes their total point, the chain will automatically +//! claim all their pending rewards for them. This is not optional, and MUST happen for the reward +//! calculation to remain correct (see the documentation of `bond` as an example). So, make sure +//! you are warning your users about it. They might be surprised if they see that they bonded an +//! extra 100 DOTs, and now suddenly their 5.23 DOTs in pending reward is gone. It is not gone, it +//! has been paid out to you! +//! * Joining a pool implies transferring funds to the pool account. So it might be (based on which +//! wallet that you are using) that you no longer see the funds that are moved to the pool in your +//! “free balance” section. Make sure the user is aware of this, and not surprised by seeing this. +//! Also, the transfer that happens here is configured to to never accidentally destroy the sender +//! account. So to join a Pool, your sender account must remain alive with 1 DOT left in it. This +//! means, with 1 DOT as existential deposit, and 1 DOT as minimum to join a pool, you need at +//! least 2 DOT to join a pool. Consequently, if you are suggesting members to join a pool with +//! “Maximum possible value”, you must subtract 1 DOT to remain in the sender account to not +//! accidentally kill it. +//! * Points and balance are not the same! Any pool member, at any point in time, can have points in +//! either the bonded pool or any of the unbonding pools. The crucial fact is that in any of these +//! pools, the ratio of point to balance is different and might not be 1. Each pool starts with a +//! ratio of 1, but as time goes on, for reasons such as slashing, the ratio gets broken. Over +//! time, 100 points in a bonded pool can be worth 90 DOTs. Make sure you are either representing +//! points as points (not as DOTs), or even better, always display both: “You have x points in +//! pool y which is worth z DOTs”. See here and here for examples of how to calculate point to +//! balance ratio of each pool (it is almost trivial ;)) +//! +//! ### Pool Management +//! +//! * The pool will be seen from the perspective of the rest of the system as a single nominator. +//! Ergo, This nominator must always respect the `staking.minNominatorBond` limit. Similar to a +//! normal nominator, who has to first `chill` before fully unbonding, the pool must also do the +//! same. The pool’s bonded account will be fully unbonded only when the depositor wants to leave +//! and dismantle the pool. All that said, the message is: the depositor can only leave the chain +//! when they chill the pool first. //! //! ## Design //! @@ -277,14 +328,13 @@ use frame_support::{ Currency, Defensive, DefensiveOption, DefensiveResult, DefensiveSaturating, ExistenceRequirement, Get, }, - transactional, CloneNoBound, DefaultNoBound, RuntimeDebugNoBound, + DefaultNoBound, }; use scale_info::TypeInfo; use sp_core::U256; use sp_runtime::{ traits::{ - AccountIdConversion, Bounded, CheckedAdd, CheckedSub, Convert, Saturating, StaticLookup, - Zero, + AccountIdConversion, CheckedAdd, CheckedSub, Convert, Saturating, StaticLookup, Zero, }, FixedPointNumber, }; @@ -299,14 +349,14 @@ pub const LOG_TARGET: &'static str = "runtime::nomination-pools"; macro_rules! log { ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { log::$level!( - target: crate::LOG_TARGET, + target: $crate::LOG_TARGET, concat!("[{:?}] 🏊‍♂️ ", $patter), >::block_number() $(, $values)* ) }; } -#[cfg(test)] -mod mock; +#[cfg(any(test, feature = "fuzzing"))] +pub mod mock; #[cfg(test)] mod tests; @@ -322,8 +372,6 @@ pub type BalanceOf = /// Type used for unique identifier of each pool. pub type PoolId = u32; -type UnbondingPoolsWithEra = BoundedBTreeMap, TotalUnbondingPools>; - type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; pub const POINTS_TO_BALANCE_INIT_RATIO: u32 = 1; @@ -398,16 +446,12 @@ impl PoolMember { // // rc * 10^20 / 10^18 = rc * 100 // - // meaning that as long as reward_counter's value is less than 1/100th of its max capacity - // (u128::MAX_VALUE), `checked_mul_int` won't saturate. - // - // given the nature of reward counter being 'pending_rewards / pool_total_point', the only - // (unrealistic) way that super high values can be achieved is for a pool to suddenly - // receive massive rewards with a very very small amount of stake. In all normal pools, as - // the points increase, so does the rewards. Moreover, as long as rewards are not - // accumulated for astronomically large durations, - // `current_reward_counter.defensive_saturating_sub(self.last_recorded_reward_counter)` - // won't be extremely big. + // the implementation of `multiply_by_rational_with_rounding` shows that it will only fail + // if the final division is not enough to fit in u128. In other words, if `rc * 100` is more + // than u128::max. Given that RC is interpreted as reward per unit of point, and unit of + // point is equal to balance (normally), and rewards are usually a proportion of the points + // in the pool, the likelihood of rc reaching near u128::MAX is near impossible. + (current_reward_counter.defensive_saturating_sub(self.last_recorded_reward_counter)) .checked_mul_int(self.active_points()) .ok_or(Error::::OverflowRisk) @@ -417,7 +461,7 @@ impl PoolMember { /// /// This is derived from the ratio of points in the pool to which the member belongs to. /// Might return different values based on the pool state for the same member and points. - fn active_stake(&self) -> BalanceOf { + fn active_balance(&self) -> BalanceOf { if let Some(pool) = BondedPool::::get(self.pool_id).defensive() { pool.points_to_balance(self.points) } else { @@ -594,7 +638,7 @@ impl BondedPool { } /// Get [`Self`] from storage. Returns `None` if no entry for `pool_account` exists. - fn get(id: PoolId) -> Option { + pub fn get(id: PoolId) -> Option { BondedPools::::try_get(id).ok().map(|inner| Self { id, inner }) } @@ -734,7 +778,7 @@ impl BondedPool { /// Whether or not the pool is ok to be in `PoolSate::Open`. If this returns an `Err`, then the /// pool is unrecoverable and should be in the destroying state. - fn ok_to_be_open(&self, new_funds: BalanceOf) -> Result<(), DispatchError> { + fn ok_to_be_open(&self) -> Result<(), DispatchError> { ensure!(!self.is_destroying(), Error::::CanNotChangeState); let bonded_balance = @@ -755,12 +799,6 @@ impl BondedPool { points_to_balance_ratio_floor < max_points_to_balance.into(), Error::::OverflowRisk ); - // while restricting the balance to `max_points_to_balance` of max total issuance, - let next_bonded_balance = bonded_balance.saturating_add(new_funds); - ensure!( - next_bonded_balance < BalanceOf::::max_value().div(max_points_to_balance.into()), - Error::::OverflowRisk - ); // then we can be decently confident the bonding pool points will not overflow // `BalanceOf`. Note that these are just heuristics. @@ -769,9 +807,9 @@ impl BondedPool { } /// Check that the pool can accept a member with `new_funds`. - fn ok_to_join(&self, new_funds: BalanceOf) -> Result<(), DispatchError> { + fn ok_to_join(&self) -> Result<(), DispatchError> { ensure!(self.state == PoolState::Open, Error::::NotOpen); - self.ok_to_be_open(new_funds)?; + self.ok_to_be_open()?; Ok(()) } @@ -791,7 +829,7 @@ impl BondedPool { target_member.active_points().saturating_sub(unbonding_points); let mut target_member_after_unbond = (*target_member).clone(); target_member_after_unbond.points = new_depositor_points; - target_member_after_unbond.active_stake() + target_member_after_unbond.active_balance() }; // any partial unbonding is only ever allowed if this unbond is permissioned. @@ -1073,7 +1111,7 @@ pub struct SubPools { /// older then `current_era - TotalUnbondingPools`. no_era: UnbondPool, /// Map of era in which a pool becomes unbonded in => unbond pools. - with_era: UnbondingPoolsWithEra, + with_era: BoundedBTreeMap, TotalUnbondingPools>, } impl SubPools { @@ -1105,7 +1143,7 @@ impl SubPools { } /// The sum of all unbonding balance, regardless of whether they are actually unlocked or not. - #[cfg(any(feature = "try-runtime", test, debug_assertions))] + #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))] fn sum_unbonding_balance(&self) -> BalanceOf { self.no_era.balance.saturating_add( self.with_era @@ -1122,8 +1160,8 @@ pub struct TotalUnbondingPools(PhantomData); impl Get for TotalUnbondingPools { fn get() -> u32 { // NOTE: this may be dangerous in the scenario bonding_duration gets decreased because - // we would no longer be able to decode `UnbondingPoolsWithEra`, which uses - // `TotalUnbondingPools` as the bound + // we would no longer be able to decode `BoundedBTreeMap::, + // TotalUnbondingPools>`, which uses `TotalUnbondingPools` as the bound T::Staking::bonding_duration() + T::PostUnbondingPoolsWindow::get() } } @@ -1469,7 +1507,6 @@ pub mod pallet { /// `existential deposit + amount` in their account. /// * Only a pool with [`PoolState::Open`] can be joined #[pallet::weight(T::WeightInfo::join())] - #[transactional] pub fn join( origin: OriginFor, #[pallet::compact] amount: BalanceOf, @@ -1482,7 +1519,7 @@ pub mod pallet { ensure!(!PoolMembers::::contains_key(&who), Error::::AccountBelongsToOtherPool); let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; - bonded_pool.ok_to_join(amount)?; + bonded_pool.ok_to_join()?; let mut reward_pool = RewardPools::::get(pool_id) .defensive_ok_or::>(DefensiveError::RewardPoolNotFound.into())?; @@ -1530,7 +1567,6 @@ pub mod pallet { T::WeightInfo::bond_extra_transfer() .max(T::WeightInfo::bond_extra_reward()) )] - #[transactional] pub fn bond_extra(origin: OriginFor, extra: BondExtra>) -> DispatchResult { let who = ensure_signed(origin)?; let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&who)?; @@ -1538,10 +1574,6 @@ pub mod pallet { // payout related stuff: we must claim the payouts, and updated recorded payout data // before updating the bonded pool points, similar to that of `join` transaction. reward_pool.update_records(bonded_pool.id, bonded_pool.points)?; - // TODO: optimize this to not touch the free balance of `who ` at all in benchmarks. - // Currently, bonding rewards is like a batch. In the same PR, also make this function - // take a boolean argument that make it either 100% pure (no storage update), or make it - // also emit event and do the transfer. #11671 let claimed = Self::do_reward_payout(&who, &mut member, &mut bonded_pool, &mut reward_pool)?; @@ -1552,8 +1584,9 @@ pub mod pallet { (bonded_pool.try_bond_funds(&who, claimed, BondType::Later)?, claimed), }; - bonded_pool.ok_to_be_open(bonded)?; - member.points = member.points.saturating_add(points_issued); + bonded_pool.ok_to_be_open()?; + member.points = + member.points.checked_add(&points_issued).ok_or(Error::::OverflowRisk)?; Self::deposit_event(Event::::Bonded { member: who.clone(), @@ -1573,7 +1606,6 @@ pub mod pallet { /// The member will earn rewards pro rata based on the members stake vs the sum of the /// members in the pools stake. Rewards do not "expire". #[pallet::weight(T::WeightInfo::claim_payout())] - #[transactional] pub fn claim_payout(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; let (mut member, mut bonded_pool, mut reward_pool) = Self::get_member_with_pools(&who)?; @@ -1613,7 +1645,6 @@ pub mod pallet { /// there are too many unlocking chunks, the result of this call will likely be the /// `NoMoreChunks` error from the staking system. #[pallet::weight(T::WeightInfo::unbond())] - #[transactional] pub fn unbond( origin: OriginFor, member_account: AccountIdLookupOf, @@ -1689,7 +1720,6 @@ pub mod pallet { /// would probably see an error like `NoMoreChunks` emitted from the staking system when /// they attempt to unbond. #[pallet::weight(T::WeightInfo::pool_withdraw_unbonded(*num_slashing_spans))] - #[transactional] pub fn pool_withdraw_unbonded( origin: OriginFor, pool_id: PoolId, @@ -1726,7 +1756,6 @@ pub mod pallet { #[pallet::weight( T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans) )] - #[transactional] pub fn withdraw_unbonded( origin: OriginFor, member_account: AccountIdLookupOf, @@ -1749,7 +1778,7 @@ pub mod pallet { let withdrawn_points = member.withdraw_unlocked(current_era); ensure!(!withdrawn_points.is_empty(), Error::::CannotWithdrawAny); - // Before calculate the `balance_to_unbond`, with call withdraw unbonded to ensure the + // Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the // `transferrable_balance` is correct. let stash_killed = T::Staking::withdraw_unbonded(bonded_pool.bonded_account(), num_slashing_spans)?; @@ -1778,13 +1807,13 @@ pub mod pallet { accumulator.saturating_add(sub_pools.no_era.dissolve(*unlocked_points)) } }) - // A call to this function may cause the pool's stash to get dusted. If this happens - // before the last member has withdrawn, then all subsequent withdraws will be 0. - // However the unbond pools do no get updated to reflect this. In the aforementioned - // scenario, this check ensures we don't try to withdraw funds that don't exist. - // This check is also defensive in cases where the unbond pool does not update its - // balance (e.g. a bug in the slashing hook.) We gracefully proceed in order to - // ensure members can leave the pool and it can be destroyed. + // A call to this transaction may cause the pool's stash to get dusted. If this + // happens before the last member has withdrawn, then all subsequent withdraws will + // be 0. However the unbond pools do no get updated to reflect this. In the + // aforementioned scenario, this check ensures we don't try to withdraw funds that + // don't exist. This check is also defensive in cases where the unbond pool does not + // update its balance (e.g. a bug in the slashing hook.) We gracefully proceed in + // order to ensure members can leave the pool and it can be destroyed. .min(bonded_pool.transferrable_balance()); T::Currency::transfer( @@ -1846,7 +1875,6 @@ pub mod pallet { /// In addition to `amount`, the caller will transfer the existential deposit; so the caller /// needs at have at least `amount + existential_deposit` transferrable. #[pallet::weight(T::WeightInfo::create())] - #[transactional] pub fn create( origin: OriginFor, #[pallet::compact] amount: BalanceOf, @@ -1871,7 +1899,6 @@ pub mod pallet { /// same as `create` with the inclusion of /// * `pool_id` - `A valid PoolId. #[pallet::weight(T::WeightInfo::create())] - #[transactional] pub fn create_with_pool_id( origin: OriginFor, #[pallet::compact] amount: BalanceOf, @@ -1896,7 +1923,6 @@ pub mod pallet { /// This directly forward the call to the staking pallet, on behalf of the pool bonded /// account. #[pallet::weight(T::WeightInfo::nominate(validators.len() as u32))] - #[transactional] pub fn nominate( origin: OriginFor, pool_id: PoolId, @@ -1919,7 +1945,6 @@ pub mod pallet { /// 2. if the pool conditions to be open are NOT met (as described by `ok_to_be_open`), and /// then the state of the pool can be permissionlessly changed to `Destroying`. #[pallet::weight(T::WeightInfo::set_state())] - #[transactional] pub fn set_state( origin: OriginFor, pool_id: PoolId, @@ -1931,9 +1956,7 @@ pub mod pallet { if bonded_pool.can_toggle_state(&who) { bonded_pool.set_state(state); - } else if bonded_pool.ok_to_be_open(Zero::zero()).is_err() && - state == PoolState::Destroying - { + } else if bonded_pool.ok_to_be_open().is_err() && state == PoolState::Destroying { // If the pool has bad properties, then anyone can set it as destroying bonded_pool.set_state(PoolState::Destroying); } else { @@ -1950,7 +1973,6 @@ pub mod pallet { /// The dispatch origin of this call must be signed by the state toggler, or the root role /// of the pool. #[pallet::weight(T::WeightInfo::set_metadata(metadata.len() as u32))] - #[transactional] pub fn set_metadata( origin: OriginFor, pool_id: PoolId, @@ -1982,7 +2004,6 @@ pub mod pallet { /// * `max_members` - Set [`MaxPoolMembers`]. /// * `max_members_per_pool` - Set [`MaxPoolMembersPerPool`]. #[pallet::weight(T::WeightInfo::set_configs())] - #[transactional] pub fn set_configs( origin: OriginFor, min_join_bond: ConfigOp>, @@ -2019,7 +2040,6 @@ pub mod pallet { /// It emits an event, notifying UIs of the role change. This event is quite relevant to /// most pool members and they should be informed of changes to pool roles. #[pallet::weight(T::WeightInfo::update_roles())] - #[transactional] pub fn update_roles( origin: OriginFor, pool_id: PoolId, @@ -2072,7 +2092,6 @@ pub mod pallet { /// This directly forward the call to the staking pallet, on behalf of the pool bonded /// account. #[pallet::weight(T::WeightInfo::chill())] - #[transactional] pub fn chill(origin: OriginFor, pool_id: PoolId) -> DispatchResult { let who = ensure_signed(origin)?; let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; @@ -2297,6 +2316,8 @@ impl Pallet { &bonded_pool.reward_account(), &member_account, pending_rewards, + // defensive: the depositor has put existential deposit into the pool and it stays + // untouched, reward account shall not die. ExistenceRequirement::AllowDeath, )?; @@ -2414,7 +2435,7 @@ impl Pallet { /// To cater for tests that want to escape parts of these checks, this function is split into /// multiple `level`s, where the higher the level, the more checks we performs. So, /// `try_state(255)` is the strongest sanity check, and `0` performs no checks. - #[cfg(any(feature = "try-runtime", test, debug_assertions))] + #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))] pub fn do_try_state(level: u8) -> Result<(), &'static str> { if level.is_zero() { return Ok(()) diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index e1af456e31fd4..99d521df3241b 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -259,44 +259,45 @@ impl Default for ExtBuilder { } } +#[cfg_attr(feature = "fuzzing", allow(dead_code))] impl ExtBuilder { // Add members to pool 0. - pub(crate) fn add_members(mut self, members: Vec<(AccountId, Balance)>) -> Self { + pub fn add_members(mut self, members: Vec<(AccountId, Balance)>) -> Self { self.members = members; self } - pub(crate) fn ed(self, ed: Balance) -> Self { + pub fn ed(self, ed: Balance) -> Self { ExistentialDeposit::set(ed); self } - pub(crate) fn min_bond(self, min: Balance) -> Self { + pub fn min_bond(self, min: Balance) -> Self { StakingMinBond::set(min); self } - pub(crate) fn min_join_bond(self, min: Balance) -> Self { + pub fn min_join_bond(self, min: Balance) -> Self { MinJoinBondConfig::set(min); self } - pub(crate) fn with_check(self, level: u8) -> Self { + pub fn with_check(self, level: u8) -> Self { CheckLevel::set(level); self } - pub(crate) fn max_members(mut self, max: Option) -> Self { + pub fn max_members(mut self, max: Option) -> Self { self.max_members = max; self } - pub(crate) fn max_members_per_pool(mut self, max: Option) -> Self { + pub fn max_members_per_pool(mut self, max: Option) -> Self { self.max_members_per_pool = max; self } - pub(crate) fn build(self) -> sp_io::TestExternalities { + pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); @@ -339,7 +340,7 @@ impl ExtBuilder { } } -pub(crate) fn unsafe_set_state(pool_id: PoolId, state: PoolState) { +pub fn unsafe_set_state(pool_id: PoolId, state: PoolState) { BondedPools::::try_mutate(pool_id, |maybe_bonded_pool| { maybe_bonded_pool.as_mut().ok_or(()).map(|bonded_pool| { bonded_pool.state = state; @@ -354,7 +355,7 @@ parameter_types! { } /// All events of this pallet. -pub(crate) fn pool_events_since_last_call() -> Vec> { +pub fn pool_events_since_last_call() -> Vec> { let events = System::events() .into_iter() .map(|r| r.event) @@ -366,7 +367,7 @@ pub(crate) fn pool_events_since_last_call() -> Vec> { } /// All events of the `Balances` pallet. -pub(crate) fn balances_events_since_last_call() -> Vec> { +pub fn balances_events_since_last_call() -> Vec> { let events = System::events() .into_iter() .map(|r| r.event) diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index aadd4871d737e..7d5d418bbf2c8 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -25,7 +25,7 @@ macro_rules! unbonding_pools_with_era { ($($k:expr => $v:expr),* $(,)?) => {{ use sp_std::iter::{Iterator, IntoIterator}; let not_bounded: BTreeMap<_, _> = Iterator::collect(IntoIterator::into_iter([$(($k, $v),)*])); - UnbondingPoolsWithEra::try_from(not_bounded).unwrap() + BoundedBTreeMap::, TotalUnbondingPools>::try_from(not_bounded).unwrap() }}; } @@ -213,31 +213,30 @@ mod bonded_pool { // Simulate a 100% slashed pool StakingMock::set_bonded_balance(pool.bonded_account(), 0); - assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); + assert_noop!(pool.ok_to_join(), Error::::OverflowRisk); // Simulate a slashed pool at `MaxPointsToBalance` + 1 slashed pool StakingMock::set_bonded_balance( pool.bonded_account(), max_points_to_balance.saturating_add(1).into(), ); - assert_ok!(pool.ok_to_join(0)); + assert_ok!(pool.ok_to_join()); // Simulate a slashed pool at `MaxPointsToBalance` StakingMock::set_bonded_balance(pool.bonded_account(), max_points_to_balance); - assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); + assert_noop!(pool.ok_to_join(), Error::::OverflowRisk); StakingMock::set_bonded_balance( pool.bonded_account(), Balance::MAX / max_points_to_balance, ); - // New bonded balance would be over threshold of Balance type - assert_noop!(pool.ok_to_join(0), Error::::OverflowRisk); + // and a sanity check StakingMock::set_bonded_balance( pool.bonded_account(), Balance::MAX / max_points_to_balance - 1, ); - assert_ok!(pool.ok_to_join(0)); + assert_ok!(pool.ok_to_join()); }); } } @@ -437,7 +436,7 @@ mod join { roles: DEFAULT_ROLES, }, }; - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().with_check(0).build_and_execute(|| { // Given Balances::make_free_balance_be(&11, ExistentialDeposit::get() + 2); assert!(!PoolMembers::::contains_key(&11)); @@ -545,7 +544,7 @@ mod join { // Balance needs to be gt Balance::MAX / `MaxPointsToBalance` assert_noop!( Pools::join(RuntimeOrigin::signed(11), 5, 123), - Error::::OverflowRisk + pallet_balances::Error::::InsufficientBalance, ); StakingMock::set_bonded_balance(Pools::create_bonded_account(1), max_points_to_balance); @@ -4283,7 +4282,7 @@ mod set_state { fn set_state_works() { ExtBuilder::default().build_and_execute(|| { // Given - assert_ok!(BondedPool::::get(1).unwrap().ok_to_be_open(0)); + assert_ok!(BondedPool::::get(1).unwrap().ok_to_be_open()); // Only the root and state toggler can change the state when the pool is ok to be open. assert_noop!( @@ -4831,6 +4830,41 @@ mod reward_counter_precision { }) } + #[test] + fn massive_reward_in_small_pool() { + let tiny_bond = 1000 * DOT; + ExtBuilder::default().ed(DOT).min_bond(tiny_bond).build_and_execute(|| { + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10000000000000, joined: true } + ] + ); + + Balances::make_free_balance_be(&20, tiny_bond); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), tiny_bond / 2, 1)); + + // Suddenly, add a shit ton of rewards. + assert_ok!( + Balances::mutate_account(&default_reward_account(), |a| a.free += inflation(1)) + ); + + // now claim. + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Bonded { member: 20, pool_id: 1, bonded: 5000000000000, joined: true }, + Event::PaidOut { member: 10, pool_id: 1, payout: 7333333333333333333 }, + Event::PaidOut { member: 20, pool_id: 1, payout: 3666666666666666666 } + ] + ); + }) + } + #[test] fn reward_counter_calc_wont_fail_in_normal_polkadot_future() { // create a pool that has roughly half of the polkadot issuance in 10 years. @@ -5066,328 +5100,3 @@ mod reward_counter_precision { }); } } - -// NOTE: run this with debug_assertions, but in release mode. -#[cfg(feature = "fuzz-test")] -mod fuzz_test { - use super::*; - use crate::pallet::{Call as PoolsCall, Event as PoolsEvents}; - use frame_support::traits::UnfilteredDispatchable; - use rand::{seq::SliceRandom, thread_rng, Rng}; - use sp_runtime::{assert_eq_error_rate, Perquintill}; - - const ERA: BlockNumber = 1000; - const MAX_ED_MULTIPLE: Balance = 10_000; - const MIN_ED_MULTIPLE: Balance = 10; - - // not quite elegant, just to make it available in random_signed_origin. - const REWARD_AGENT_ACCOUNT: AccountId = 42; - - /// Grab random accounts, either known ones, or new ones. - fn random_signed_origin(rng: &mut R) -> (RuntimeOrigin, AccountId) { - let count = PoolMembers::::count(); - if rng.gen::() && count > 0 { - // take an existing account. - let skip = rng.gen_range(0..count as usize); - - // this is tricky: the account might be our reward agent, which we never want to be - // randomly chosen here. Try another one, or, if it is only our agent, return a random - // one nonetheless. - let candidate = PoolMembers::::iter_keys().skip(skip).take(1).next().unwrap(); - let acc = - if candidate == REWARD_AGENT_ACCOUNT { rng.gen::() } else { candidate }; - - (RuntimeOrigin::signed(acc), acc) - } else { - // create a new account - let acc = rng.gen::(); - (RuntimeOrigin::signed(acc), acc) - } - } - - fn random_ed_multiple(rng: &mut R) -> Balance { - let multiple = rng.gen_range(MIN_ED_MULTIPLE..MAX_ED_MULTIPLE); - ExistentialDeposit::get() * multiple - } - - fn fund_account(rng: &mut R, account: &AccountId) { - let target_amount = random_ed_multiple(rng); - if let Some(top_up) = target_amount.checked_sub(Balances::free_balance(account)) { - let _ = Balances::deposit_creating(account, top_up); - } - assert!(Balances::free_balance(account) >= target_amount); - } - - fn random_existing_pool(mut rng: &mut R) -> Option { - BondedPools::::iter_keys().collect::>().choose(&mut rng).map(|x| *x) - } - - fn random_call(mut rng: &mut R) -> (crate::pallet::Call, RuntimeOrigin) { - let op = rng.gen::(); - let mut op_count = - as frame_support::dispatch::GetCallName>::get_call_names() - .len(); - // Exclude set_state, set_metadata, set_configs, update_roles and chill. - op_count -= 5; - - match op % op_count { - 0 => { - // join - let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); - let (origin, who) = random_signed_origin(&mut rng); - fund_account(&mut rng, &who); - let amount = random_ed_multiple(&mut rng); - (PoolsCall::::join { amount, pool_id }, origin) - }, - 1 => { - // bond_extra - let (origin, who) = random_signed_origin(&mut rng); - let extra = if rng.gen::() { - BondExtra::Rewards - } else { - fund_account(&mut rng, &who); - let amount = random_ed_multiple(&mut rng); - BondExtra::FreeBalance(amount) - }; - (PoolsCall::::bond_extra { extra }, origin) - }, - 2 => { - // claim_payout - let (origin, _) = random_signed_origin(&mut rng); - (PoolsCall::::claim_payout {}, origin) - }, - 3 => { - // unbond - let (origin, who) = random_signed_origin(&mut rng); - let amount = random_ed_multiple(&mut rng); - (PoolsCall::::unbond { member_account: who, unbonding_points: amount }, origin) - }, - 4 => { - // pool_withdraw_unbonded - let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); - let (origin, _) = random_signed_origin(&mut rng); - (PoolsCall::::pool_withdraw_unbonded { pool_id, num_slashing_spans: 0 }, origin) - }, - 5 => { - // withdraw_unbonded - let (origin, who) = random_signed_origin(&mut rng); - ( - PoolsCall::::withdraw_unbonded { - member_account: who, - num_slashing_spans: 0, - }, - origin, - ) - }, - 6 => { - // create - let (origin, who) = random_signed_origin(&mut rng); - let amount = random_ed_multiple(&mut rng); - fund_account(&mut rng, &who); - let root = who.clone(); - let state_toggler = who.clone(); - let nominator = who.clone(); - (PoolsCall::::create { amount, root, state_toggler, nominator }, origin) - }, - 7 => { - // nominate - let (origin, _) = random_signed_origin(&mut rng); - let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); - let validators = Default::default(); - (PoolsCall::::nominate { pool_id, validators }, origin) - }, - _ => unreachable!(), - } - } - - #[derive(Default)] - struct RewardAgent { - who: AccountId, - pool_id: Option, - expected_reward: Balance, - } - - // TODO: inject some slashes into the game. - impl RewardAgent { - fn new(who: AccountId) -> Self { - Self { who, ..Default::default() } - } - - fn join(&mut self) { - if self.pool_id.is_some() { - return - } - let pool_id = LastPoolId::::get(); - let amount = 10 * ExistentialDeposit::get(); - let origin = RuntimeOrigin::signed(self.who); - let _ = Balances::deposit_creating(&self.who, 10 * amount); - self.pool_id = Some(pool_id); - log::info!(target: "reward-agent", "🤖 reward agent joining in {} with {}", pool_id, amount); - assert_ok!(PoolsCall::join:: { amount, pool_id }.dispatch_bypass_filter(origin)); - } - - fn claim_payout(&mut self) { - // 10 era later, we claim our payout. We expect our income to be roughly what we - // calculated. - if !PoolMembers::::contains_key(&self.who) { - log!(warn, "reward agent is not in the pool yet, cannot claim"); - return - } - let pre = Balances::free_balance(&42); - let origin = RuntimeOrigin::signed(42); - assert_ok!(PoolsCall::::claim_payout {}.dispatch_bypass_filter(origin)); - let post = Balances::free_balance(&42); - - let income = post - pre; - log::info!( - target: "reward-agent", "🤖 CLAIM: actual: {}, expected: {}", - income, - self.expected_reward, - ); - assert_eq_error_rate!(income, self.expected_reward, 10); - self.expected_reward = 0; - } - } - - #[test] - fn fuzz_test() { - let mut reward_agent = RewardAgent::new(42); - sp_tracing::try_init_simple(); - // NOTE: use this to get predictable (non)randomness: - // use::{rngs::SmallRng, SeedableRng}; - // let mut rng = SmallRng::from_seed([0u8; 32]); - let mut rng = thread_rng(); - let mut ext = sp_io::TestExternalities::new_empty(); - // NOTE: sadly events don't fulfill the requirements of hashmap or btreemap. - let mut events_histogram = Vec::<(PoolsEvents, u32)>::default(); - let mut iteration = 0 as BlockNumber; - let mut ok = 0; - let mut err = 0; - - ext.execute_with(|| { - MaxPoolMembers::::set(Some(10_000)); - MaxPoolMembersPerPool::::set(Some(1000)); - MaxPools::::set(Some(1_000)); - - MinCreateBond::::set(10 * ExistentialDeposit::get()); - MinJoinBond::::set(5 * ExistentialDeposit::get()); - System::set_block_number(1); - }); - - ExistentialDeposit::set(10u128.pow(12u32)); - BondingDuration::set(8); - - loop { - ext.execute_with(|| { - iteration += 1; - let (call, origin) = random_call(&mut rng); - let outcome = call.clone().dispatch_bypass_filter(origin.clone()); - - match outcome { - Ok(_) => ok += 1, - Err(_) => err += 1, - }; - - log!( - debug, - "iteration {}, call {:?}, origin {:?}, outcome: {:?}, so far {} ok {} err", - iteration, - call, - origin, - outcome, - ok, - err, - ); - - // possibly join the reward_agent - if iteration > ERA / 2 && BondedPools::::count() > 0 { - reward_agent.join(); - } - // and possibly roughly every 4 era, trigger payout for the agent. Doing this more - // frequent is also harmless. - if rng.gen_range(0..(4 * ERA)) == 0 { - reward_agent.claim_payout(); - } - - // execute sanity checks at a fixed interval, possibly on every block. - if iteration % - (std::env::var("SANITY_CHECK_INTERVAL") - .ok() - .and_then(|x| x.parse::().ok())) - .unwrap_or(1) == 0 - { - log!(info, "running sanity checks at {}", iteration); - Pools::do_try_state(u8::MAX).unwrap(); - } - - // collect and reset events. - System::events() - .into_iter() - .map(|r| r.event) - .filter_map( - |e| if let mock::Event::Pools(inner) = e { Some(inner) } else { None }, - ) - .for_each(|e| { - if let Some((_, c)) = events_histogram - .iter_mut() - .find(|(x, _)| std::mem::discriminant(x) == std::mem::discriminant(&e)) - { - *c += 1; - } else { - events_histogram.push((e, 1)) - } - }); - System::reset_events(); - - // trigger an era change, and check the status of the reward agent. - if iteration % ERA == 0 { - CurrentEra::mutate(|c| *c += 1); - BondedPools::::iter().for_each(|(id, _)| { - let amount = random_ed_multiple(&mut rng); - let _ = - Balances::deposit_creating(&Pools::create_reward_account(id), amount); - // if we just paid out the reward agent, let's calculate how much we expect - // our reward agent to have earned. - if reward_agent.pool_id.map_or(false, |mid| mid == id) { - let all_points = BondedPool::::get(id).map(|p| p.points).unwrap(); - let member_points = - PoolMembers::::get(reward_agent.who).map(|m| m.points).unwrap(); - let agent_share = Perquintill::from_rational(member_points, all_points); - log::info!( - target: "reward-agent", - "🤖 REWARD = amount = {:?}, ratio: {:?}, share {:?}", - amount, - agent_share, - agent_share * amount, - ); - reward_agent.expected_reward += agent_share * amount; - } - }); - - log!( - info, - "iteration {}, {} pools, {} members, {} ok {} err, events = {:?}", - iteration, - BondedPools::::count(), - PoolMembers::::count(), - ok, - err, - events_histogram - .iter() - .map(|(x, c)| ( - format!("{:?}", x) - .split(" ") - .map(|x| x.to_string()) - .collect::>() - .first() - .cloned() - .unwrap(), - c, - )) - .collect::>(), - ); - } - }); - } - } -} From 38a955ba4a0c967659e6c944c56c664fce0f8f23 Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 10 Nov 2022 21:23:56 +0900 Subject: [PATCH 1370/1472] Remove `sp_tasks::spawn` API and related code + host functions (#12639) * Remove `sp_tasks::spawn` API and related code * Remove `RuntimeTasks::{spawn, join}` host functions * remove unused * Remove a few more tests that I forgot to remove Co-authored-by: Shawn Tabrizi --- Cargo.lock | 30 --- Cargo.toml | 2 - client/executor/Cargo.toml | 1 - client/executor/runtime-test/Cargo.toml | 2 - client/executor/runtime-test/src/lib.rs | 37 --- client/executor/src/integration_tests/mod.rs | 27 -- client/executor/src/native_executor.rs | 167 +----------- client/executor/wasmtime/src/runtime.rs | 3 - frame/examples/parallel/Cargo.toml | 38 --- frame/examples/parallel/README.md | 7 - frame/examples/parallel/src/lib.rs | 148 ----------- frame/examples/parallel/src/tests.rs | 146 ----------- primitives/core/src/traits.rs | 6 - primitives/io/src/lib.rs | 35 +-- primitives/tasks/Cargo.toml | 36 --- primitives/tasks/README.md | 3 - primitives/tasks/src/async_externalities.rs | 212 --------------- primitives/tasks/src/lib.rs | 257 ------------------- 18 files changed, 10 insertions(+), 1147 deletions(-) delete mode 100644 frame/examples/parallel/Cargo.toml delete mode 100644 frame/examples/parallel/README.md delete mode 100644 frame/examples/parallel/src/lib.rs delete mode 100644 frame/examples/parallel/src/tests.rs delete mode 100644 primitives/tasks/Cargo.toml delete mode 100644 primitives/tasks/README.md delete mode 100644 primitives/tasks/src/async_externalities.rs delete mode 100644 primitives/tasks/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index a13768a64a4ab..f0471d019c1a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5461,21 +5461,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-example-parallel" -version = "3.0.0-dev" -dependencies = [ - "frame-support", - "frame-system", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "sp-tasks", -] - [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" @@ -7988,7 +7973,6 @@ dependencies = [ "sp-runtime", "sp-runtime-interface", "sp-state-machine", - "sp-tasks", "sp-trie", "sp-version", "sp-wasm-interface", @@ -8548,7 +8532,6 @@ dependencies = [ "sp-runtime", "sp-sandbox", "sp-std", - "sp-tasks", "substrate-wasm-builder", ] @@ -9960,19 +9943,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "sp-tasks" -version = "4.0.0-dev" -dependencies = [ - "log", - "parity-scale-codec", - "sp-core", - "sp-externalities", - "sp-io", - "sp-runtime-interface", - "sp-std", -] - [[package]] name = "sp-test-primitives" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 4ba2663cdb409..ab8fbd816b004 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,7 +98,6 @@ members = [ "frame/election-provider-support/solution-type/fuzzer", "frame/examples/basic", "frame/examples/offchain-worker", - "frame/examples/parallel", "frame/executive", "frame/gilt", "frame/grandpa", @@ -205,7 +204,6 @@ members = [ "primitives/state-machine", "primitives/std", "primitives/storage", - "primitives/tasks", "primitives/test-primitives", "primitives/timestamp", "primitives/tracing", diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 1a6c281c77ff5..e48c27dfc998e 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -31,7 +31,6 @@ sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } sp-runtime-interface = { version = "6.0.0", path = "../../primitives/runtime-interface" } -sp-tasks = { version = "4.0.0-dev", path = "../../primitives/tasks" } sp-trie = { version = "6.0.0", path = "../../primitives/trie" } sp-version = { version = "5.0.0", path = "../../primitives/version" } sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index 7a7848700c4c1..f90b2e1439a77 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -19,7 +19,6 @@ sp-io = { version = "6.0.0", default-features = false, features = ["improved_pan sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } @@ -32,5 +31,4 @@ std = [ "sp-runtime/std", "sp-sandbox/std", "sp-std/std", - "sp-tasks/std", ] diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 5a741f51c3899..0424ad418617b 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -318,24 +318,6 @@ sp_core::wasm_export_functions! { message_slice.copy_from_slice(test_message); } - fn test_spawn() { - let data = vec![1u8, 2u8]; - let data_new = sp_tasks::spawn(tasks::incrementer, data).join(); - - assert_eq!(data_new, vec![2u8, 3u8]); - } - - fn test_nested_spawn() { - let data = vec![7u8, 13u8]; - let data_new = sp_tasks::spawn(tasks::parallel_incrementer, data).join(); - - assert_eq!(data_new, vec![10u8, 16u8]); - } - - fn test_panic_in_spawned() { - sp_tasks::spawn(tasks::panicker, vec![]).join(); - } - fn test_return_i8() -> i8 { -66 } @@ -358,25 +340,6 @@ sp_core::wasm_export_functions! { } } -#[cfg(not(feature = "std"))] -mod tasks { - use sp_std::prelude::*; - - pub fn incrementer(data: Vec) -> Vec { - data.into_iter().map(|v| v + 1).collect() - } - - pub fn panicker(_: Vec) -> Vec { - panic!() - } - - pub fn parallel_incrementer(data: Vec) -> Vec { - let first = data.into_iter().map(|v| v + 2).collect::>(); - let second = sp_tasks::spawn(incrementer, first).join(); - second - } -} - /// A macro to define a test entrypoint for each available sandbox executor. macro_rules! wasm_export_sandbox_test_functions { ( diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 9ffb7f502f5c6..3217f9f96ca79 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -770,33 +770,6 @@ fn wasm_tracing_should_work(wasm_method: WasmExecutionMethod) { assert_eq!(len, 2); } -test_wasm_execution!(spawning_runtime_instance_should_work); -fn spawning_runtime_instance_should_work(wasm_method: WasmExecutionMethod) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - call_in_wasm("test_spawn", &[], wasm_method, &mut ext).unwrap(); -} - -test_wasm_execution!(spawning_runtime_instance_nested_should_work); -fn spawning_runtime_instance_nested_should_work(wasm_method: WasmExecutionMethod) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - call_in_wasm("test_nested_spawn", &[], wasm_method, &mut ext).unwrap(); -} - -test_wasm_execution!(panic_in_spawned_instance_panics_on_joining_its_result); -fn panic_in_spawned_instance_panics_on_joining_its_result(wasm_method: WasmExecutionMethod) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - let error_result = - call_in_wasm("test_panic_in_spawned", &[], wasm_method, &mut ext).unwrap_err(); - - assert!(error_result.to_string().contains("Spawned task")); -} - test_wasm_execution!(memory_is_cleared_between_invocations); fn memory_is_cleared_between_invocations(wasm_method: WasmExecutionMethod) { // This is based on the code generated by compiling a runtime *without* diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index b164b427e306d..0eabffb8c87df 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -23,24 +23,18 @@ use crate::{ }; use std::{ - collections::HashMap, marker::PhantomData, panic::{AssertUnwindSafe, UnwindSafe}, path::PathBuf, - sync::{ - atomic::{AtomicU64, Ordering}, - mpsc, Arc, - }, + sync::Arc, }; use codec::Encode; use sc_executor_common::{ runtime_blob::RuntimeBlob, - wasm_runtime::{AllocationStats, InvokeMethod, WasmInstance, WasmModule}, + wasm_runtime::{AllocationStats, WasmInstance, WasmModule}, }; -use sp_core::traits::{CodeExecutor, Externalities, RuntimeCode, RuntimeSpawn, RuntimeSpawnExt}; -use sp_externalities::ExternalitiesExt as _; -use sp_tasks::new_async_externalities; +use sp_core::traits::{CodeExecutor, Externalities, RuntimeCode}; use sp_version::{GetNativeVersion, NativeVersion, RuntimeVersion}; use sp_wasm_interface::{ExtendedHostFunctions, HostFunctions}; @@ -277,11 +271,9 @@ where let mut instance = AssertUnwindSafe(instance); let mut ext = AssertUnwindSafe(ext); - let module = AssertUnwindSafe(module); let mut allocation_stats_out = AssertUnwindSafe(allocation_stats_out); with_externalities_safe(&mut **ext, move || { - preregister_builtin_ext(module.clone()); let (result, allocation_stats) = instance.call_with_allocation_stats(export_name.into(), call_data); **allocation_stats_out = allocation_stats; @@ -349,16 +341,10 @@ where "Executing function", ); - let result = self.with_instance( - runtime_code, - ext, - |module, mut instance, _onchain_version, mut ext| { - with_externalities_safe(&mut **ext, move || { - preregister_builtin_ext(module.clone()); - instance.call_export(method, data) - }) - }, - ); + let result = + self.with_instance(runtime_code, ext, |_, mut instance, _onchain_version, mut ext| { + with_externalities_safe(&mut **ext, move || instance.call_export(method, data)) + }); (result, false) } } @@ -451,138 +437,6 @@ impl GetNativeVersion for NativeElseWasmExecutor } } -/// Helper inner struct to implement `RuntimeSpawn` extension. -pub struct RuntimeInstanceSpawn { - module: Arc, - tasks: parking_lot::Mutex>>>, - counter: AtomicU64, - scheduler: Box, -} - -impl RuntimeSpawn for RuntimeInstanceSpawn { - fn spawn_call(&self, dispatcher_ref: u32, func: u32, data: Vec) -> u64 { - let new_handle = self.counter.fetch_add(1, Ordering::Relaxed); - - let (sender, receiver) = mpsc::channel(); - self.tasks.lock().insert(new_handle, receiver); - - let module = self.module.clone(); - let scheduler = self.scheduler.clone(); - self.scheduler.spawn( - "executor-extra-runtime-instance", - None, - Box::pin(async move { - let module = AssertUnwindSafe(module); - - let async_ext = match new_async_externalities(scheduler.clone()) { - Ok(val) => val, - Err(e) => { - tracing::error!( - target: "executor", - error = %e, - "Failed to setup externalities for async context.", - ); - - // This will drop sender and receiver end will panic - return - }, - }; - - let mut async_ext = match async_ext.with_runtime_spawn(Box::new( - RuntimeInstanceSpawn::new(module.clone(), scheduler), - )) { - Ok(val) => val, - Err(e) => { - tracing::error!( - target: "executor", - error = %e, - "Failed to setup runtime extension for async externalities", - ); - - // This will drop sender and receiver end will panic - return - }, - }; - - let result = with_externalities_safe(&mut async_ext, move || { - // FIXME: Should be refactored to shared "instance factory". - // Instantiating wasm here every time is suboptimal at the moment, shared - // pool of instances should be used. - // - // https://github.com/paritytech/substrate/issues/7354 - let mut instance = match module.new_instance() { - Ok(instance) => instance, - Err(error) => { - panic!("failed to create new instance from module: {}", error) - }, - }; - - match instance - .call(InvokeMethod::TableWithWrapper { dispatcher_ref, func }, &data[..]) - { - Ok(result) => result, - Err(error) => panic!("failed to invoke instance: {}", error), - } - }); - - match result { - Ok(output) => { - let _ = sender.send(output); - }, - Err(error) => { - // If execution is panicked, the `join` in the original runtime code will - // panic as well, since the sender is dropped without sending anything. - tracing::error!(error = %error, "Call error in spawned task"); - }, - } - }), - ); - - new_handle - } - - fn join(&self, handle: u64) -> Vec { - let receiver = self.tasks.lock().remove(&handle).expect("No task for the handle"); - receiver.recv().expect("Spawned task panicked for the handle") - } -} - -impl RuntimeInstanceSpawn { - pub fn new( - module: Arc, - scheduler: Box, - ) -> Self { - Self { module, scheduler, counter: 0.into(), tasks: HashMap::new().into() } - } - - fn with_externalities_and_module( - module: Arc, - mut ext: &mut dyn Externalities, - ) -> Option { - ext.extension::() - .map(move |task_ext| Self::new(module, task_ext.clone())) - } -} - -/// Pre-registers the built-in extensions to the currently effective externalities. -/// -/// Meant to be called each time before calling into the runtime. -fn preregister_builtin_ext(module: Arc) { - sp_externalities::with_externalities(move |mut ext| { - if let Some(runtime_spawn) = - RuntimeInstanceSpawn::with_externalities_and_module(module, ext) - { - if let Err(e) = ext.register_extension(RuntimeSpawnExt(Box::new(runtime_spawn))) { - tracing::trace!( - target: "executor", - error = ?e, - "Failed to register `RuntimeSpawnExt` instance on externalities", - ) - } - } - }); -} - impl CodeExecutor for NativeElseWasmExecutor { type Error = Error; @@ -604,7 +458,7 @@ impl CodeExecutor for NativeElseWasmExecut let result = self.wasm.with_instance( runtime_code, ext, - |module, mut instance, onchain_version, mut ext| { + |_, mut instance, onchain_version, mut ext| { let onchain_version = onchain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?; @@ -632,10 +486,7 @@ impl CodeExecutor for NativeElseWasmExecut ); } - with_externalities_safe(&mut **ext, move || { - preregister_builtin_ext(module.clone()); - instance.call_export(method, data) - }) + with_externalities_safe(&mut **ext, move || instance.call_export(method, data)) } }, ); diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index e3509351022bc..5bca899648c34 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -395,9 +395,6 @@ fn common_config(semantics: &Semantics) -> std::result::Result"] -edition = "2021" -license = "Unlicense" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "FRAME example pallet using runtime worker threads" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-tasks = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/tasks" } - -[features] -default = ["std"] -std = [ - "codec/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", - "sp-tasks/std", -] -try-runtime = ["frame-support/try-runtime"] diff --git a/frame/examples/parallel/README.md b/frame/examples/parallel/README.md deleted file mode 100644 index 44b39a41507db..0000000000000 --- a/frame/examples/parallel/README.md +++ /dev/null @@ -1,7 +0,0 @@ - -# Parallel Tasks Example Pallet - -This example pallet demonstrates parallelizing validation of the enlisted participants (see -`enlist_participants` dispatch). - -**This pallet serves as an example and is not meant to be used in production.** diff --git a/frame/examples/parallel/src/lib.rs b/frame/examples/parallel/src/lib.rs deleted file mode 100644 index 3432a79638664..0000000000000 --- a/frame/examples/parallel/src/lib.rs +++ /dev/null @@ -1,148 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # Parallel Tasks Example Pallet -//! -//! This example pallet demonstrates parallelizing validation of the enlisted participants -//! (see `enlist_participants` dispatch). -//! -//! **This pallet serves as an example and is not meant to be used in production.** - -#![cfg_attr(not(feature = "std"), no_std)] - -use sp_runtime::RuntimeDebug; - -use codec::{Decode, Encode}; -use sp_std::vec::Vec; - -#[cfg(test)] -mod tests; - -pub use pallet::*; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] - pub struct Pallet(_); - - /// A public part of the pallet. - #[pallet::call] - impl Pallet { - /// Get the new event running. - #[pallet::weight(0)] - pub fn run_event(origin: OriginFor, id: Vec) -> DispatchResultWithPostInfo { - let _ = ensure_signed(origin)?; - >::kill(); - >::mutate(move |event_id| *event_id = id); - Ok(().into()) - } - - /// Submit list of participants to the current event. - /// - /// The example utilizes parallel execution by checking half of the - /// signatures in spawned task. - #[pallet::weight(0)] - pub fn enlist_participants( - origin: OriginFor, - participants: Vec, - ) -> DispatchResultWithPostInfo { - let _ = ensure_signed(origin)?; - - if validate_participants_parallel(&>::get(), &participants[..]) { - for participant in participants { - >::append(participant.account); - } - } - Ok(().into()) - } - } - - /// A vector of current participants - /// - /// To enlist someone to participate, signed payload should be - /// sent to `enlist`. - #[pallet::storage] - #[pallet::getter(fn participants)] - pub(super) type Participants = StorageValue<_, Vec>, ValueQuery>; - - /// Current event id to enlist participants to. - #[pallet::storage] - #[pallet::getter(fn get_current_event_id)] - pub(super) type CurrentEventId = StorageValue<_, Vec, ValueQuery>; -} - -/// Request to enlist participant. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, scale_info::TypeInfo)] -pub struct EnlistedParticipant { - pub account: Vec, - pub signature: Vec, -} - -impl EnlistedParticipant { - fn verify(&self, event_id: &[u8]) -> bool { - use sp_core::ByteArray; - use sp_runtime::traits::Verify; - - match sp_core::sr25519::Signature::try_from(&self.signature[..]) { - Ok(signature) => match sp_core::sr25519::Public::from_slice(self.account.as_ref()) { - Err(()) => false, - Ok(signer) => signature.verify(event_id, &signer), - }, - _ => false, - } - } -} - -fn validate_participants_parallel(event_id: &[u8], participants: &[EnlistedParticipant]) -> bool { - fn spawn_verify(data: Vec) -> Vec { - let stream = &mut &data[..]; - let event_id = Vec::::decode(stream).expect("Failed to decode"); - let participants = Vec::::decode(stream).expect("Failed to decode"); - - for participant in participants { - if !participant.verify(&event_id) { - return false.encode() - } - } - true.encode() - } - - let mut async_payload = Vec::new(); - event_id.encode_to(&mut async_payload); - participants[..participants.len() / 2].encode_to(&mut async_payload); - - let handle = sp_tasks::spawn(spawn_verify, async_payload); - let mut result = true; - - for participant in &participants[participants.len() / 2 + 1..] { - if !participant.verify(event_id) { - result = false; - break - } - } - - bool::decode(&mut &handle.join()[..]).expect("Failed to decode result") && result -} diff --git a/frame/examples/parallel/src/tests.rs b/frame/examples/parallel/src/tests.rs deleted file mode 100644 index fdef24a39ae36..0000000000000 --- a/frame/examples/parallel/src/tests.rs +++ /dev/null @@ -1,146 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::{self as pallet_example_parallel, *}; - -use frame_support::parameter_types; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, -}; - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; - -frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Example: pallet_example_parallel::{Pallet, Call, Storage}, - } -); - -parameter_types! { - pub const AvailableBlockRatio: Perbill = Perbill::one(); -} - -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type PalletInfo = PalletInfo; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = sp_core::sr25519::Public; - type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = frame_support::traits::ConstU64<250>; - type DbWeight = (); - type BlockWeights = (); - type BlockLength = (); - type Version = (); - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -impl Config for Test {} - -fn test_pub(n: u8) -> sp_core::sr25519::Public { - sp_core::sr25519::Public::from_raw([n; 32]) -} - -fn test_origin(n: u8) -> RuntimeOrigin { - RuntimeOrigin::signed(test_pub(n)) -} - -#[test] -fn it_can_enlist() { - use sp_core::Pair; - - sp_io::TestExternalities::default().execute_with(|| { - let (pair1, _) = sp_core::sr25519::Pair::generate(); - let (pair2, _) = sp_core::sr25519::Pair::generate(); - - let event_name = b"test"; - - Example::run_event(test_origin(1), event_name.to_vec()).expect("Failed to enlist"); - - let participants = vec![ - EnlistedParticipant { - account: pair1.public().to_vec(), - signature: AsRef::<[u8]>::as_ref(&pair1.sign(event_name)).to_vec(), - }, - EnlistedParticipant { - account: pair2.public().to_vec(), - signature: AsRef::<[u8]>::as_ref(&pair2.sign(event_name)).to_vec(), - }, - ]; - - Example::enlist_participants(RuntimeOrigin::signed(test_pub(1)), participants) - .expect("Failed to enlist"); - - assert_eq!(Example::participants().len(), 2); - }); -} - -#[test] -fn one_wrong_will_not_enlist_anyone() { - use sp_core::Pair; - - sp_io::TestExternalities::default().execute_with(|| { - let (pair1, _) = sp_core::sr25519::Pair::generate(); - let (pair2, _) = sp_core::sr25519::Pair::generate(); - let (pair3, _) = sp_core::sr25519::Pair::generate(); - - let event_name = b"test"; - - Example::run_event(test_origin(1), event_name.to_vec()).expect("Failed to enlist"); - - let participants = vec![ - EnlistedParticipant { - account: pair1.public().to_vec(), - signature: AsRef::<[u8]>::as_ref(&pair1.sign(event_name)).to_vec(), - }, - EnlistedParticipant { - account: pair2.public().to_vec(), - signature: AsRef::<[u8]>::as_ref(&pair2.sign(event_name)).to_vec(), - }, - // signing wrong event - EnlistedParticipant { - account: pair3.public().to_vec(), - signature: AsRef::<[u8]>::as_ref(&pair3.sign(&[])).to_vec(), - }, - ]; - - Example::enlist_participants(test_origin(1), participants).expect("Failed to enlist"); - - assert_eq!(Example::participants().len(), 0); - }); -} diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs index c5149cc48c074..c4b7f20f7e9a0 100644 --- a/primitives/core/src/traits.rs +++ b/primitives/core/src/traits.rs @@ -179,12 +179,6 @@ pub trait RuntimeSpawn: Send { fn join(&self, handle: u64) -> Vec; } -#[cfg(feature = "std")] -sp_externalities::decl_extension! { - /// Extension that supports spawning extra runtime instances in externalities. - pub struct RuntimeSpawnExt(Box); -} - /// Something that can spawn tasks (blocking and non-blocking) with an assigned name /// and optional group. #[dyn_clonable::clonable] diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 7942bafcc2a1b..33516bb0397f3 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -40,7 +40,7 @@ use sp_core::{ hexdisplay::HexDisplay, offchain::{OffchainDbExt, OffchainWorkerExt, TransactionPoolExt}, storage::ChildInfo, - traits::{RuntimeSpawnExt, TaskExecutorExt}, + traits::TaskExecutorExt, }; #[cfg(feature = "std")] use sp_keystore::{KeystoreExt, SyncCryptoStore}; @@ -1657,38 +1657,6 @@ pub trait Sandbox { } } -/// Wasm host functions for managing tasks. -/// -/// This should not be used directly. Use `sp_tasks` for running parallel tasks instead. -#[runtime_interface(wasm_only)] -pub trait RuntimeTasks { - /// Wasm host function for spawning task. - /// - /// This should not be used directly. Use `sp_tasks::spawn` instead. - fn spawn(dispatcher_ref: u32, entry: u32, payload: Vec) -> u64 { - sp_externalities::with_externalities(|mut ext| { - let runtime_spawn = ext - .extension::() - .expect("Cannot spawn without dynamic runtime dispatcher (RuntimeSpawnExt)"); - runtime_spawn.spawn_call(dispatcher_ref, entry, payload) - }) - .expect("`RuntimeTasks::spawn`: called outside of externalities context") - } - - /// Wasm host function for joining a task. - /// - /// This should not be used directly. Use `join` of `sp_tasks::spawn` result instead. - fn join(handle: u64) -> Vec { - sp_externalities::with_externalities(|mut ext| { - let runtime_spawn = ext - .extension::() - .expect("Cannot join without dynamic runtime dispatcher (RuntimeSpawnExt)"); - runtime_spawn.join(handle) - }) - .expect("`RuntimeTasks::join`: called outside of externalities context") - } -} - /// Allocator used by Substrate when executing the Wasm runtime. #[cfg(all(target_arch = "wasm32", not(feature = "std")))] struct WasmAllocator; @@ -1767,7 +1735,6 @@ pub type SubstrateHostFunctions = ( sandbox::HostFunctions, crate::trie::HostFunctions, offchain_index::HostFunctions, - runtime_tasks::HostFunctions, transaction_index::HostFunctions, ); diff --git a/primitives/tasks/Cargo.toml b/primitives/tasks/Cargo.toml deleted file mode 100644 index c37a8a66f94df..0000000000000 --- a/primitives/tasks/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "sp-tasks" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "Runtime asynchronous, pure computational tasks" -documentation = "https://docs.rs/sp-tasks" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -log = { version = "0.4.17", optional = true } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } -sp-io = { version = "6.0.0", default-features = false, path = "../io" } -sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } - -[dev-dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } - -[features] -default = ["std"] -std = [ - "log", - "sp-core/std", - "sp-externalities", - "sp-io/std", - "sp-runtime-interface/std", - "sp-std/std", -] diff --git a/primitives/tasks/README.md b/primitives/tasks/README.md deleted file mode 100644 index 1235e1bd933d4..0000000000000 --- a/primitives/tasks/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Runtime asynchronous, pure computational tasks. - -License: Apache-2.0 \ No newline at end of file diff --git a/primitives/tasks/src/async_externalities.rs b/primitives/tasks/src/async_externalities.rs deleted file mode 100644 index 008955a714b21..0000000000000 --- a/primitives/tasks/src/async_externalities.rs +++ /dev/null @@ -1,212 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Async externalities. - -use sp_core::{ - storage::{ChildInfo, StateVersion, TrackedStorageKey}, - traits::{Externalities, RuntimeSpawn, RuntimeSpawnExt, SpawnNamed, TaskExecutorExt}, -}; -use sp_externalities::{Extensions, ExternalitiesExt as _, MultiRemovalResults}; -use std::any::{Any, TypeId}; - -/// Simple state-less externalities for use in async context. -/// -/// Will panic if anything is accessing the storage. -#[derive(Debug)] -pub struct AsyncExternalities { - extensions: Extensions, -} - -/// New Async externalities. -pub fn new_async_externalities( - scheduler: Box, -) -> Result { - let mut res = AsyncExternalities { extensions: Default::default() }; - let mut ext = &mut res as &mut dyn Externalities; - ext.register_extension::(TaskExecutorExt(scheduler.clone())) - .map_err(|_| "Failed to register task executor extension.")?; - - Ok(res) -} - -impl AsyncExternalities { - /// Extend async externalities with the ability to spawn wasm instances. - pub fn with_runtime_spawn( - mut self, - runtime_ext: Box, - ) -> Result { - let mut ext = &mut self as &mut dyn Externalities; - ext.register_extension::(RuntimeSpawnExt(runtime_ext)) - .map_err(|_| "Failed to register task executor extension.")?; - - Ok(self) - } -} - -type StorageKey = Vec; - -type StorageValue = Vec; - -impl Externalities for AsyncExternalities { - fn set_offchain_storage(&mut self, _key: &[u8], _value: Option<&[u8]>) { - panic!("`set_offchain_storage`: should not be used in async externalities!") - } - - fn storage(&self, _key: &[u8]) -> Option { - panic!("`storage`: should not be used in async externalities!") - } - - fn storage_hash(&self, _key: &[u8]) -> Option> { - panic!("`storage_hash`: should not be used in async externalities!") - } - - fn child_storage(&self, _child_info: &ChildInfo, _key: &[u8]) -> Option { - panic!("`child_storage`: should not be used in async externalities!") - } - - fn child_storage_hash(&self, _child_info: &ChildInfo, _key: &[u8]) -> Option> { - panic!("`child_storage_hash`: should not be used in async externalities!") - } - - fn next_storage_key(&self, _key: &[u8]) -> Option { - panic!("`next_storage_key`: should not be used in async externalities!") - } - - fn next_child_storage_key(&self, _child_info: &ChildInfo, _key: &[u8]) -> Option { - panic!("`next_child_storage_key`: should not be used in async externalities!") - } - - fn place_storage(&mut self, _key: StorageKey, _maybe_value: Option) { - panic!("`place_storage`: should not be used in async externalities!") - } - - fn place_child_storage( - &mut self, - _child_info: &ChildInfo, - _key: StorageKey, - _value: Option, - ) { - panic!("`place_child_storage`: should not be used in async externalities!") - } - - fn kill_child_storage( - &mut self, - _child_info: &ChildInfo, - _maybe_limit: Option, - _maybe_cursor: Option<&[u8]>, - ) -> MultiRemovalResults { - panic!("`kill_child_storage`: should not be used in async externalities!") - } - - fn clear_prefix( - &mut self, - _prefix: &[u8], - _maybe_limit: Option, - _maybe_cursor: Option<&[u8]>, - ) -> MultiRemovalResults { - panic!("`clear_prefix`: should not be used in async externalities!") - } - - fn clear_child_prefix( - &mut self, - _child_info: &ChildInfo, - _prefix: &[u8], - _maybe_limit: Option, - _maybe_cursor: Option<&[u8]>, - ) -> MultiRemovalResults { - panic!("`clear_child_prefix`: should not be used in async externalities!") - } - - fn storage_append(&mut self, _key: Vec, _value: Vec) { - panic!("`storage_append`: should not be used in async externalities!") - } - - fn storage_root(&mut self, _state_version: StateVersion) -> Vec { - panic!("`storage_root`: should not be used in async externalities!") - } - - fn child_storage_root( - &mut self, - _child_info: &ChildInfo, - _state_version: StateVersion, - ) -> Vec { - panic!("`child_storage_root`: should not be used in async externalities!") - } - - fn storage_start_transaction(&mut self) { - unimplemented!("Transactions are not supported by AsyncExternalities"); - } - - fn storage_rollback_transaction(&mut self) -> Result<(), ()> { - unimplemented!("Transactions are not supported by AsyncExternalities"); - } - - fn storage_commit_transaction(&mut self) -> Result<(), ()> { - unimplemented!("Transactions are not supported by AsyncExternalities"); - } - - fn wipe(&mut self) {} - - fn commit(&mut self) {} - - fn read_write_count(&self) -> (u32, u32, u32, u32) { - unimplemented!("read_write_count is not supported in AsyncExternalities") - } - - fn reset_read_write_count(&mut self) { - unimplemented!("reset_read_write_count is not supported in AsyncExternalities") - } - - fn get_whitelist(&self) -> Vec { - unimplemented!("get_whitelist is not supported in AsyncExternalities") - } - - fn set_whitelist(&mut self, _: Vec) { - unimplemented!("set_whitelist is not supported in AsyncExternalities") - } - - fn get_read_and_written_keys(&self) -> Vec<(Vec, u32, u32, bool)> { - unimplemented!("get_read_and_written_keys is not supported in AsyncExternalities") - } -} - -impl sp_externalities::ExtensionStore for AsyncExternalities { - fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> { - self.extensions.get_mut(type_id) - } - - fn register_extension_with_type_id( - &mut self, - type_id: TypeId, - extension: Box, - ) -> Result<(), sp_externalities::Error> { - self.extensions.register_with_type_id(type_id, extension) - } - - fn deregister_extension_by_type_id( - &mut self, - type_id: TypeId, - ) -> Result<(), sp_externalities::Error> { - if self.extensions.deregister(type_id) { - Ok(()) - } else { - Err(sp_externalities::Error::ExtensionIsNotRegistered(type_id)) - } - } -} diff --git a/primitives/tasks/src/lib.rs b/primitives/tasks/src/lib.rs deleted file mode 100644 index 3711fa71a2fab..0000000000000 --- a/primitives/tasks/src/lib.rs +++ /dev/null @@ -1,257 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Runtime tasks. -//! -//! Contains runtime-usable functions for spawning parallel purely computational tasks. -//! -//! NOTE: This is experimental API. -//! NOTE: When using in actual runtime, make sure you don't produce unbounded parallelism. -//! So this is bad example to use it: -//! ```rust -//! fn my_parallel_computator(data: Vec) -> Vec { -//! unimplemented!() -//! } -//! fn test(dynamic_variable: i32) { -//! for _ in 0..dynamic_variable { sp_tasks::spawn(my_parallel_computator, vec![]); } -//! } -//! ``` -//! -//! While this is a good example: -//! ```rust -//! use codec::Encode; -//! static STATIC_VARIABLE: i32 = 4; -//! -//! fn my_parallel_computator(data: Vec) -> Vec { -//! unimplemented!() -//! } -//! -//! fn test(computation_payload: Vec) { -//! let parallel_tasks = (0..STATIC_VARIABLE).map(|idx| -//! sp_tasks::spawn(my_parallel_computator, computation_payload.chunks(10).nth(idx as _).encode()) -//! ); -//! } -//! ``` -//! -//! When allowing unbounded parallelism, malicious transactions can exploit it and partition -//! network consensus based on how much resources nodes have. - -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(feature = "std")] -mod async_externalities; - -#[cfg(feature = "std")] -pub use async_externalities::{new_async_externalities, AsyncExternalities}; - -#[cfg(feature = "std")] -mod inner { - use sp_core::traits::TaskExecutorExt; - use sp_externalities::ExternalitiesExt as _; - use std::{panic::AssertUnwindSafe, sync::mpsc}; - - /// Task handle (wasm). - /// - /// This can be `join`-ed to get (blocking) the result of - /// the spawned task execution. - #[must_use] - pub struct DataJoinHandle { - receiver: mpsc::Receiver>, - } - - impl DataJoinHandle { - /// Join handle returned by `spawn` function - pub fn join(self) -> Vec { - self.receiver - .recv() - .expect("Spawned runtime task terminated before sending result.") - } - } - - /// Spawn new runtime task (native). - pub fn spawn(entry_point: fn(Vec) -> Vec, data: Vec) -> DataJoinHandle { - let scheduler = sp_externalities::with_externalities(|mut ext| { - ext.extension::() - .expect("No task executor associated with the current context!") - .clone() - }) - .expect("Spawn called outside of externalities context!"); - - let (sender, receiver) = mpsc::channel(); - let extra_scheduler = scheduler.clone(); - scheduler.spawn( - "parallel-runtime-spawn", - Some("substrate-runtime"), - Box::pin(async move { - let result = match crate::new_async_externalities(extra_scheduler) { - Ok(mut ext) => { - let mut ext = AssertUnwindSafe(&mut ext); - match std::panic::catch_unwind(move || { - sp_externalities::set_and_run_with_externalities( - &mut **ext, - move || entry_point(data), - ) - }) { - Ok(result) => result, - Err(panic) => { - log::error!( - target: "runtime", - "Spawned task panicked: {:?}", - panic, - ); - - // This will drop sender without sending anything. - return - }, - } - }, - Err(e) => { - log::error!( - target: "runtime", - "Unable to run async task: {}", - e, - ); - - return - }, - }; - - let _ = sender.send(result); - }), - ); - - DataJoinHandle { receiver } - } -} - -#[cfg(not(feature = "std"))] -mod inner { - use core::mem; - use sp_std::prelude::*; - - /// Dispatch wrapper for wasm blob. - /// - /// Serves as trampoline to call any rust function with (Vec) -> Vec compiled - /// into the runtime. - /// - /// Function item should be provided with `func_ref`. Argument for the call - /// will be generated from bytes at `payload_ptr` with `payload_len`. - /// - /// NOTE: Since this dynamic dispatch function and the invoked function are compiled with - /// the same compiler, there should be no problem with ABI incompatibility. - extern "C" fn dispatch_wrapper( - func_ref: *const u8, - payload_ptr: *mut u8, - payload_len: u32, - ) -> u64 { - let payload_len = payload_len as usize; - let output = unsafe { - let payload = Vec::from_raw_parts(payload_ptr, payload_len, payload_len); - let ptr: fn(Vec) -> Vec = mem::transmute(func_ref); - (ptr)(payload) - }; - sp_runtime_interface::pack_ptr_and_len(output.as_ptr() as usize as _, output.len() as _) - } - - /// Spawn new runtime task (wasm). - pub fn spawn(entry_point: fn(Vec) -> Vec, payload: Vec) -> DataJoinHandle { - let func_ptr: usize = unsafe { mem::transmute(entry_point) }; - - let handle = - sp_io::runtime_tasks::spawn(dispatch_wrapper as usize as _, func_ptr as u32, payload); - DataJoinHandle { handle } - } - - /// Task handle (wasm). - /// - /// This can be `join`-ed to get (blocking) the result of - /// the spawned task execution. - #[must_use] - pub struct DataJoinHandle { - handle: u64, - } - - impl DataJoinHandle { - /// Join handle returned by `spawn` function - pub fn join(self) -> Vec { - sp_io::runtime_tasks::join(self.handle) - } - } -} - -pub use inner::{spawn, DataJoinHandle}; - -#[cfg(test)] -mod tests { - - use super::*; - - fn async_runner(mut data: Vec) -> Vec { - data.sort(); - data - } - - fn async_panicker(_data: Vec) -> Vec { - panic!("panic in async panicker!") - } - - #[test] - fn basic() { - sp_io::TestExternalities::default().execute_with(|| { - let a1 = spawn(async_runner, vec![5, 2, 1]).join(); - assert_eq!(a1, vec![1, 2, 5]); - }) - } - - #[test] - fn panicking() { - let res = sp_io::TestExternalities::default().execute_with_safe(|| { - spawn(async_panicker, vec![5, 2, 1]).join(); - }); - - assert!(res.unwrap_err().contains("Closure panicked")); - } - - #[test] - fn many_joins() { - sp_io::TestExternalities::default() - .execute_with_safe(|| { - // converges to 1 only after 1000+ steps - let mut running_val = 9780657630u64; - let mut data = vec![]; - let handles = (0..1024) - .map(|_| { - running_val = if running_val % 2 == 0 { - running_val / 2 - } else { - 3 * running_val + 1 - }; - data.push(running_val as u8); - (spawn(async_runner, data.clone()), data.clone()) - }) - .collect::>(); - - for (handle, mut data) in handles { - let result = handle.join(); - data.sort(); - - assert_eq!(result, data); - } - }) - .expect("Failed to run with externalities"); - } -} From e7cb51b325c19012cc5c269105c43717093f45b0 Mon Sep 17 00:00:00 2001 From: Jun Jiang Date: Fri, 11 Nov 2022 03:31:32 +0800 Subject: [PATCH 1371/1472] Contracts pallet: Bump Runtime API (#12677) --- frame/contracts/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index b2eb0439d6ced..52fb0190ba3a9 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -1199,6 +1199,7 @@ where sp_api::decl_runtime_apis! { /// The API used to dry-run contract interactions. + #[api_version(2)] pub trait ContractsApi where AccountId: Codec, Balance: Codec, From 112468e1faeed85c04c41cda42861b23698e1f2b Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 10 Nov 2022 22:14:15 +0100 Subject: [PATCH 1372/1472] Fix typo (#12680) --- primitives/runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 96706dd919650..3752e31cbeeb0 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -234,7 +234,7 @@ impl BuildStorage for () { /// Consensus engine unique ID. pub type ConsensusEngineId = [u8; 4]; -/// Signature verify that can work with any known signature types.. +/// Signature verify that can work with any known signature types. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Eq, PartialEq, Clone, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo)] pub enum MultiSignature { From 7763a32b4dc7ce95e2f883b97a808d03d126ae7a Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 11 Nov 2022 12:26:47 +0100 Subject: [PATCH 1373/1472] Move `WeightCounter` to `sp-weights` (#12603) * Move WeightCounter to sp_weights Signed-off-by: Oliver Tale-Yazdi * Rename to WeightMeter and test Signed-off-by: Oliver Tale-Yazdi * Fix pallet-scheduler for new usage Signed-off-by: Oliver Tale-Yazdi * Update primitives/weights/src/weight_meter.rs Co-authored-by: David * More tests for can_accrue Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * Remove defensive_accrue and fixup consumed_ratio I dont think there is a good use-case for defensive_accrue without saturation. Only in tests maybe, will remove for now until we have a use-case. Signed-off-by: Oliver Tale-Yazdi * Test Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: David Co-authored-by: Gavin Wood --- frame/scheduler/src/benchmarking.rs | 20 ++- frame/scheduler/src/lib.rs | 34 +---- primitives/weights/src/lib.rs | 4 + primitives/weights/src/weight_meter.rs | 176 +++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 39 deletions(-) create mode 100644 primitives/weights/src/weight_meter.rs diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index aaa30fd88ffda..e621c913b2386 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -122,17 +122,13 @@ fn make_origin(signed: bool) -> ::PalletsOrigin { } } -fn dummy_counter() -> WeightCounter { - WeightCounter { used: Weight::zero(), limit: Weight::MAX } -} - benchmarks! { // `service_agendas` when no work is done. service_agendas_base { let now = T::BlockNumber::from(BLOCK_NUMBER); IncompleteSince::::put(now - One::one()); }: { - Scheduler::::service_agendas(&mut dummy_counter(), now, 0); + Scheduler::::service_agendas(&mut WeightMeter::max_limit(), now, 0); } verify { assert_eq!(IncompleteSince::::get(), Some(now - One::one())); } @@ -144,7 +140,7 @@ benchmarks! { fill_schedule::(now, s)?; let mut executed = 0; }: { - Scheduler::::service_agenda(&mut dummy_counter(), &mut executed, now, now, 0); + Scheduler::::service_agenda(&mut WeightMeter::max_limit(), &mut executed, now, now, 0); } verify { assert_eq!(executed, 0); } @@ -155,7 +151,7 @@ benchmarks! { let now = BLOCK_NUMBER.into(); let task = make_task::(false, false, false, None, 0); // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + let mut counter = WeightMeter::from_limit(Weight::zero()); }: { let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); } verify { @@ -169,7 +165,7 @@ benchmarks! { let now = BLOCK_NUMBER.into(); let task = make_task::(false, false, false, Some(s), 0); // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + let mut counter = WeightMeter::from_limit(Weight::zero()); }: { let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); } verify { @@ -181,7 +177,7 @@ benchmarks! { let now = BLOCK_NUMBER.into(); let task = make_task::(false, true, false, None, 0); // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + let mut counter = WeightMeter::from_limit(Weight::zero()); }: { let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); } verify { @@ -193,7 +189,7 @@ benchmarks! { let now = BLOCK_NUMBER.into(); let task = make_task::(true, false, false, None, 0); // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + let mut counter = WeightMeter::from_limit(Weight::zero()); }: { let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); } verify { @@ -201,7 +197,7 @@ benchmarks! { // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight. execute_dispatch_signed { - let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX }; + let mut counter = WeightMeter::max_limit(); let origin = make_origin::(true); let call = T::Preimages::realize(&make_call::(None)).unwrap().0; }: { @@ -212,7 +208,7 @@ benchmarks! { // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight. execute_dispatch_unsigned { - let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX }; + let mut counter = WeightMeter::max_limit(); let origin = make_origin::(false); let call = T::Preimages::realize(&make_call::(None)).unwrap().0; }: { diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 3a463b5808cd1..78533540be98f 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -70,7 +70,7 @@ use frame_support::{ Bounded, CallerTrait, EnsureOrigin, Get, Hash as PreimageHash, IsType, OriginTrait, PalletInfoAccess, PrivilegeCmp, QueryPreimage, StorageVersion, StorePreimage, }, - weights::Weight, + weights::{Weight, WeightMeter}, }; use frame_system::{self as system}; pub use pallet::*; @@ -143,25 +143,6 @@ pub type ScheduledOf = Scheduled< ::AccountId, >; -struct WeightCounter { - used: Weight, - limit: Weight, -} -impl WeightCounter { - fn check_accrue(&mut self, w: Weight) -> bool { - let test = self.used.saturating_add(w); - if test.any_gt(self.limit) { - false - } else { - self.used = test; - true - } - } - fn can_accrue(&mut self, w: Weight) -> bool { - self.used.saturating_add(w).all_lte(self.limit) - } -} - pub(crate) trait MarginalWeightInfo: WeightInfo { fn service_task(maybe_lookup_len: Option, named: bool, periodic: bool) -> Weight { let base = Self::service_task_base(); @@ -306,10 +287,9 @@ pub mod pallet { impl Hooks> for Pallet { /// Execute the scheduled calls fn on_initialize(now: T::BlockNumber) -> Weight { - let mut weight_counter = - WeightCounter { used: Weight::zero(), limit: T::MaximumWeight::get() }; + let mut weight_counter = WeightMeter::from_limit(T::MaximumWeight::get()); Self::service_agendas(&mut weight_counter, now, u32::max_value()); - weight_counter.used + weight_counter.consumed } } @@ -933,7 +913,7 @@ use ServiceTaskError::*; impl Pallet { /// Service up to `max` agendas queue starting from earliest incompletely executed agenda. - fn service_agendas(weight: &mut WeightCounter, now: T::BlockNumber, max: u32) { + fn service_agendas(weight: &mut WeightMeter, now: T::BlockNumber, max: u32) { if !weight.check_accrue(T::WeightInfo::service_agendas_base()) { return } @@ -961,7 +941,7 @@ impl Pallet { /// Returns `true` if the agenda was fully completed, `false` if it should be revisited at a /// later block. fn service_agenda( - weight: &mut WeightCounter, + weight: &mut WeightMeter, executed: &mut u32, now: T::BlockNumber, when: T::BlockNumber, @@ -1030,7 +1010,7 @@ impl Pallet { /// - realizing the task's call which can include a preimage lookup. /// - Rescheduling the task for execution in a later agenda if periodic. fn service_task( - weight: &mut WeightCounter, + weight: &mut WeightMeter, now: T::BlockNumber, when: T::BlockNumber, agenda_index: u32, @@ -1110,7 +1090,7 @@ impl Pallet { /// NOTE: Only the weight for this function will be counted (origin lookup, dispatch and the /// call itself). fn execute_dispatch( - weight: &mut WeightCounter, + weight: &mut WeightMeter, origin: T::PalletsOrigin, call: ::RuntimeCall, ) -> Result { diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs index 954fea91e28dc..af9e730fbfefd 100644 --- a/primitives/weights/src/lib.rs +++ b/primitives/weights/src/lib.rs @@ -26,6 +26,9 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate self as sp_weights; + +mod weight_meter; mod weight_v2; use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; @@ -40,6 +43,7 @@ use sp_arithmetic::{ use sp_core::Get; use sp_debug_derive::RuntimeDebug; +pub use weight_meter::*; pub use weight_v2::*; pub mod constants { diff --git a/primitives/weights/src/weight_meter.rs b/primitives/weights/src/weight_meter.rs new file mode 100644 index 0000000000000..d03e72968bb09 --- /dev/null +++ b/primitives/weights/src/weight_meter.rs @@ -0,0 +1,176 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains the `WeightMeter` primitive to meter weight usage. + +use super::Weight; + +use sp_arithmetic::Perbill; + +/// Meters consumed weight and a hard limit for the maximal consumable weight. +/// +/// Can be used to check if enough weight for an operation is available before committing to it. +/// +/// # Example +/// +/// ```rust +/// use sp_weights::{Weight, WeightMeter}; +/// +/// // The weight is limited to (10, 0). +/// let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 0)); +/// // There is enough weight remaining for an operation with (5, 0) weight. +/// assert!(meter.check_accrue(Weight::from_parts(5, 0))); +/// // There is not enough weight remaining for an operation with (6, 0) weight. +/// assert!(!meter.check_accrue(Weight::from_parts(6, 0))); +/// ``` +#[derive(Debug, Clone)] +pub struct WeightMeter { + /// The already consumed weight. + pub consumed: Weight, + + /// The maximal consumable weight. + pub limit: Weight, +} + +impl WeightMeter { + /// Creates [`Self`] from a limit for the maximal consumable weight. + pub fn from_limit(limit: Weight) -> Self { + Self { consumed: Weight::zero(), limit } + } + + /// Creates [`Self`] with the maximal possible limit for the consumable weight. + pub fn max_limit() -> Self { + Self::from_limit(Weight::MAX) + } + + /// The remaining weight that can still be consumed. + pub fn remaining(&self) -> Weight { + self.limit.saturating_sub(self.consumed) + } + + /// The ratio of consumed weight to the limit. + /// + /// Calculates one ratio per component and returns the largest. + pub fn consumed_ratio(&self) -> Perbill { + let time = Perbill::from_rational(self.consumed.ref_time(), self.limit.ref_time()); + let pov = Perbill::from_rational(self.consumed.proof_size(), self.limit.proof_size()); + time.max(pov) + } + + /// Consume the given weight after checking that it can be consumed. Otherwise do nothing. + pub fn check_accrue(&mut self, w: Weight) -> bool { + self.consumed.checked_add(&w).map_or(false, |test| { + if test.any_gt(self.limit) { + false + } else { + self.consumed = test; + true + } + }) + } + + /// Check if the given weight can be consumed. + pub fn can_accrue(&self, w: Weight) -> bool { + self.consumed.checked_add(&w).map_or(false, |t| t.all_lte(self.limit)) + } +} + +#[cfg(test)] +mod tests { + use crate::*; + + #[test] + fn weight_meter_remaining_works() { + let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 20)); + + assert!(meter.check_accrue(Weight::from_parts(5, 0))); + assert_eq!(meter.consumed, Weight::from_parts(5, 0)); + assert_eq!(meter.remaining(), Weight::from_parts(5, 20)); + + assert!(meter.check_accrue(Weight::from_parts(2, 10))); + assert_eq!(meter.consumed, Weight::from_parts(7, 10)); + assert_eq!(meter.remaining(), Weight::from_parts(3, 10)); + + assert!(meter.check_accrue(Weight::from_parts(3, 10))); + assert_eq!(meter.consumed, Weight::from_parts(10, 20)); + assert_eq!(meter.remaining(), Weight::from_parts(0, 0)); + } + + #[test] + fn weight_meter_can_accrue_works() { + let meter = WeightMeter::from_limit(Weight::from_parts(1, 1)); + + assert!(meter.can_accrue(Weight::from_parts(0, 0))); + assert!(meter.can_accrue(Weight::from_parts(1, 1))); + assert!(!meter.can_accrue(Weight::from_parts(0, 2))); + assert!(!meter.can_accrue(Weight::from_parts(2, 0))); + assert!(!meter.can_accrue(Weight::from_parts(2, 2))); + } + + #[test] + fn weight_meter_check_accrue_works() { + let mut meter = WeightMeter::from_limit(Weight::from_parts(2, 2)); + + assert!(meter.check_accrue(Weight::from_parts(0, 0))); + assert!(meter.check_accrue(Weight::from_parts(1, 1))); + assert!(!meter.check_accrue(Weight::from_parts(0, 2))); + assert!(!meter.check_accrue(Weight::from_parts(2, 0))); + assert!(!meter.check_accrue(Weight::from_parts(2, 2))); + assert!(meter.check_accrue(Weight::from_parts(0, 1))); + assert!(meter.check_accrue(Weight::from_parts(1, 0))); + } + + #[test] + fn weight_meter_check_and_can_accrue_works() { + let mut meter = WeightMeter::max_limit(); + + assert!(meter.can_accrue(Weight::from_parts(u64::MAX, 0))); + assert!(meter.check_accrue(Weight::from_parts(u64::MAX, 0))); + + assert!(meter.can_accrue(Weight::from_parts(0, u64::MAX))); + assert!(meter.check_accrue(Weight::from_parts(0, u64::MAX))); + + assert!(!meter.can_accrue(Weight::from_parts(0, 1))); + assert!(!meter.check_accrue(Weight::from_parts(0, 1))); + + assert!(!meter.can_accrue(Weight::from_parts(1, 0))); + assert!(!meter.check_accrue(Weight::from_parts(1, 0))); + + assert!(meter.can_accrue(Weight::zero())); + assert!(meter.check_accrue(Weight::zero())); + } + + #[test] + fn consumed_ratio_works() { + let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 20)); + + assert!(meter.check_accrue(Weight::from_parts(5, 0))); + assert_eq!(meter.consumed_ratio(), Perbill::from_percent(50)); + assert!(meter.check_accrue(Weight::from_parts(0, 12))); + assert_eq!(meter.consumed_ratio(), Perbill::from_percent(60)); + + assert!(meter.check_accrue(Weight::from_parts(2, 0))); + assert_eq!(meter.consumed_ratio(), Perbill::from_percent(70)); + assert!(meter.check_accrue(Weight::from_parts(0, 4))); + assert_eq!(meter.consumed_ratio(), Perbill::from_percent(80)); + + assert!(meter.check_accrue(Weight::from_parts(3, 0))); + assert_eq!(meter.consumed_ratio(), Perbill::from_percent(100)); + assert!(meter.check_accrue(Weight::from_parts(0, 4))); + assert_eq!(meter.consumed_ratio(), Perbill::from_percent(100)); + } +} From b042ebdd1fa37010a24668a8342dad0a66b4fdf0 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Fri, 11 Nov 2022 14:22:17 +0000 Subject: [PATCH 1374/1472] Allow other pallets to check asset ids. (#12666) * Make it easier for other pallets to check asset ids. * Avoid boxing * cargo fmt --- frame/assets/src/impl_fungibles.rs | 11 ++++++++ frame/assets/src/lib.rs | 1 + frame/assets/src/tests.rs | 26 ++++++++++++++++--- frame/support/src/traits/tokens/fungibles.rs | 2 ++ .../src/traits/tokens/fungibles/enumerable.rs | 26 +++++++++++++++++++ 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 frame/support/src/traits/tokens/fungibles/enumerable.rs diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 842ee5c102c1d..5cddf23680ac2 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -283,3 +283,14 @@ impl, I: 'static> fungibles::roles::Inspect<::Ac Asset::::get(asset).map(|x| x.freezer) } } + +impl, I: 'static> fungibles::InspectEnumerable for Pallet { + type AssetsIterator = KeyPrefixIterator<>::AssetId>; + + /// Returns an iterator of the assets in existence. + /// + /// NOTE: iterating this list invokes a storage read per item. + fn asset_ids() -> Self::AssetsIterator { + Asset::::iter_keys() + } +} diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 7e7d68fa6c7dd..017db07194d09 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -154,6 +154,7 @@ use frame_support::{ dispatch::{DispatchError, DispatchResult}, ensure, pallet_prelude::DispatchResultWithPostInfo, + storage::KeyPrefixIterator, traits::{ tokens::{fungibles, DepositConsequence, WithdrawConsequence}, BalanceStatus::Reserved, diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 48cfad45a49fc..65e8b66705290 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -19,10 +19,19 @@ use super::*; use crate::{mock::*, Error}; -use frame_support::{assert_noop, assert_ok, traits::Currency}; +use frame_support::{ + assert_noop, assert_ok, + traits::{fungibles::InspectEnumerable, Currency}, +}; use pallet_balances::Error as BalancesError; use sp_runtime::{traits::ConvertInto, TokenError}; +fn asset_ids() -> Vec { + let mut s: Vec<_> = Assets::asset_ids().collect(); + s.sort(); + s +} + #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { @@ -31,6 +40,7 @@ fn basic_minting_should_work() { assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); assert_eq!(Assets::balance(0, 2), 100); + assert_eq!(asset_ids(), vec![0, 999]); }); } @@ -48,6 +58,7 @@ fn minting_too_many_insufficient_assets_fails() { Balances::make_free_balance_be(&2, 1); assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 100)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100)); + assert_eq!(asset_ids(), vec![0, 1, 2, 999]); }); } @@ -137,6 +148,7 @@ fn refunding_calls_died_hook() { assert_eq!(Asset::::get(0).unwrap().accounts, 0); assert_eq!(hooks(), vec![Hook::Died(0, 1)]); + assert_eq!(asset_ids(), vec![0, 999]); }); } @@ -162,6 +174,7 @@ fn approval_lifecycle_works() { assert_eq!(Assets::balance(0, 1), 60); assert_eq!(Assets::balance(0, 3), 40); assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(asset_ids(), vec![0, 999]); }); } @@ -352,12 +365,14 @@ fn destroy_with_bad_witness_should_not_work() { assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); let mut w = Asset::::get(0).unwrap().destroy_witness(); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); + assert_eq!(asset_ids(), vec![0, 999]); // witness too low assert_noop!(Assets::destroy(RuntimeOrigin::signed(1), 0, w), Error::::BadWitness); // witness too high is okay though w.accounts += 2; w.sufficients += 2; assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); + assert_eq!(asset_ids(), vec![999]); }); } @@ -371,10 +386,12 @@ fn destroy_should_refund_approvals() { assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 3, 50)); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 4, 50)); assert_eq!(Balances::reserved_balance(&1), 3); + assert_eq!(asset_ids(), vec![0, 999]); let w = Asset::::get(0).unwrap().destroy_witness(); assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(asset_ids(), vec![999]); // all approvals are removed assert!(Approvals::::iter().count().is_zero()) @@ -406,6 +423,7 @@ fn non_providing_should_work() { Balances::make_free_balance_be(&2, 100); assert_ok!(Assets::transfer(RuntimeOrigin::signed(0), 0, 1, 25)); assert_ok!(Assets::force_transfer(RuntimeOrigin::signed(1), 0, 0, 2, 25)); + assert_eq!(asset_ids(), vec![0, 999]); }); } @@ -498,6 +516,7 @@ fn transferring_enough_to_kill_source_when_keep_alive_should_fail() { assert_eq!(Assets::balance(0, 1), 10); assert_eq!(Assets::balance(0, 2), 90); assert!(hooks().is_empty()); + assert_eq!(asset_ids(), vec![0, 999]); }); } @@ -582,6 +601,7 @@ fn transfer_owner_should_work() { Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); + assert_eq!(asset_ids(), vec![0, 999]); assert_eq!(Balances::reserved_balance(&1), 1); @@ -1012,7 +1032,7 @@ fn balance_conversion_should_work() { assert_ok!(Assets::force_create(RuntimeOrigin::root(), id, 1, true, 10)); let not_sufficient = 23; assert_ok!(Assets::force_create(RuntimeOrigin::root(), not_sufficient, 1, false, 10)); - + assert_eq!(asset_ids(), vec![23, 42, 999]); assert_eq!( BalanceToAssetBalance::::to_asset_balance(100, 1234), Err(ConversionError::AssetMissing) @@ -1035,7 +1055,7 @@ fn balance_conversion_should_work() { #[test] fn assets_from_genesis_should_exist() { new_test_ext().execute_with(|| { - assert!(Asset::::contains_key(999)); + assert_eq!(asset_ids(), vec![999]); assert!(Metadata::::contains_key(999)); assert_eq!(Assets::balance(999, 1), 100); assert_eq!(Assets::total_supply(999), 100); diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index e4108b7f80a98..9bdd5a10d7944 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -27,6 +27,8 @@ use sp_std::vec::Vec; pub mod approvals; mod balanced; +pub mod enumerable; +pub use enumerable::InspectEnumerable; pub mod metadata; pub use balanced::{Balanced, Unbalanced}; mod imbalance; diff --git a/frame/support/src/traits/tokens/fungibles/enumerable.rs b/frame/support/src/traits/tokens/fungibles/enumerable.rs new file mode 100644 index 0000000000000..151d15b3684a5 --- /dev/null +++ b/frame/support/src/traits/tokens/fungibles/enumerable.rs @@ -0,0 +1,26 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::traits::fungibles::Inspect; + +/// Interface for enumerating assets in existence or owned by a given account. +pub trait InspectEnumerable: Inspect { + type AssetsIterator; + + /// Returns an iterator of the collections in existence. + fn asset_ids() -> Self::AssetsIterator; +} From 67e3f9b99cd10530e45d203db7df0e340307f0b0 Mon Sep 17 00:00:00 2001 From: yjh Date: Fri, 11 Nov 2022 22:25:14 +0800 Subject: [PATCH 1375/1472] derive type info for some grandpa types (#12683) --- primitives/finality-grandpa/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index f1584dc673228..f92fee4f12963 100644 --- a/primitives/finality-grandpa/src/lib.rs +++ b/primitives/finality-grandpa/src/lib.rs @@ -129,7 +129,7 @@ pub type CompactCommit
= grandpa::CompactCommit< /// /// This is meant to be stored in the db and passed around the network to other /// nodes, and are used by syncing nodes to prove authority set handoffs. -#[derive(Clone, Encode, Decode, PartialEq, Eq)] +#[derive(Clone, Encode, Decode, PartialEq, Eq, TypeInfo)] #[cfg_attr(feature = "std", derive(Debug))] pub struct GrandpaJustification { pub round: u64, @@ -139,7 +139,7 @@ pub struct GrandpaJustification { /// A scheduled change of authority set. #[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ScheduledChange { /// The new authorities after the change, along with their respective weights. pub next_authorities: AuthorityList, From e6768a3bd553ddbed12fe1a0e4a2ef8d4f8fdf52 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 11 Nov 2022 16:22:26 +0100 Subject: [PATCH 1376/1472] Safe TreeRoute constructor (#12691) * Safe TreeRoute constructor * Remove test duplicate * Better tree route error info --- client/db/src/lib.rs | 8 ++++ .../transaction-pool/src/enactment_state.rs | 42 +++++++++++-------- primitives/blockchain/src/header_metadata.rs | 14 +++++-- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 3bbff1625f2f9..305db2284b2ed 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -2796,6 +2796,14 @@ pub(crate) mod tests { let b1 = insert_header(&backend, 1, block0, None, H256::from([1; 32])); let b2 = insert_header(&backend, 2, b1, None, Default::default()); + { + let tree_route = tree_route(blockchain, a1, a1).unwrap(); + + assert_eq!(tree_route.common_block().hash, a1); + assert!(tree_route.retracted().is_empty()); + assert!(tree_route.enacted().is_empty()); + } + { let tree_route = tree_route(blockchain, a3, b2).unwrap(); diff --git a/client/transaction-pool/src/enactment_state.rs b/client/transaction-pool/src/enactment_state.rs index b347de824fa12..6aac98641cf85 100644 --- a/client/transaction-pool/src/enactment_state.rs +++ b/client/transaction-pool/src/enactment_state.rs @@ -231,14 +231,19 @@ mod enactment_state_tests { } }; - Ok(TreeRoute::new(vec, pivot)) + TreeRoute::new(vec, pivot) } mod mock_tree_route_tests { use super::*; /// asserts that tree routes are equal - fn assert_treeroute_eq(expected: TreeRoute, result: TreeRoute) { + fn assert_treeroute_eq( + expected: Result, String>, + result: Result, String>, + ) { + let expected = expected.unwrap(); + let result = result.unwrap(); assert_eq!(result.common_block().hash, expected.common_block().hash); assert_eq!(result.enacted().len(), expected.enacted().len()); assert_eq!(result.retracted().len(), expected.retracted().len()); @@ -255,65 +260,66 @@ mod enactment_state_tests { } // some tests for mock tree_route function + #[test] fn tree_route_mock_test_01() { - let result = tree_route(b1().hash, a().hash).expect("tree route exists"); + let result = tree_route(b1().hash, a().hash); let expected = TreeRoute::new(vec![b1(), a()], 1); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_02() { - let result = tree_route(a().hash, b1().hash).expect("tree route exists"); + let result = tree_route(a().hash, b1().hash); let expected = TreeRoute::new(vec![a(), b1()], 0); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_03() { - let result = tree_route(a().hash, c2().hash).expect("tree route exists"); + let result = tree_route(a().hash, c2().hash); let expected = TreeRoute::new(vec![a(), b2(), c2()], 0); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_04() { - let result = tree_route(e2().hash, a().hash).expect("tree route exists"); + let result = tree_route(e2().hash, a().hash); let expected = TreeRoute::new(vec![e2(), d2(), c2(), b2(), a()], 4); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_05() { - let result = tree_route(d1().hash, b1().hash).expect("tree route exists"); + let result = tree_route(d1().hash, b1().hash); let expected = TreeRoute::new(vec![d1(), c1(), b1()], 2); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_06() { - let result = tree_route(d2().hash, b2().hash).expect("tree route exists"); + let result = tree_route(d2().hash, b2().hash); let expected = TreeRoute::new(vec![d2(), c2(), b2()], 2); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_07() { - let result = tree_route(b1().hash, d1().hash).expect("tree route exists"); + let result = tree_route(b1().hash, d1().hash); let expected = TreeRoute::new(vec![b1(), c1(), d1()], 0); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_08() { - let result = tree_route(b2().hash, d2().hash).expect("tree route exists"); + let result = tree_route(b2().hash, d2().hash); let expected = TreeRoute::new(vec![b2(), c2(), d2()], 0); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_09() { - let result = tree_route(e2().hash, e1().hash).expect("tree route exists"); + let result = tree_route(e2().hash, e1().hash); let expected = TreeRoute::new(vec![e2(), d2(), c2(), b2(), a(), b1(), c1(), d1(), e1()], 4); assert_treeroute_eq(result, expected); @@ -321,49 +327,49 @@ mod enactment_state_tests { #[test] fn tree_route_mock_test_10() { - let result = tree_route(e1().hash, e2().hash).expect("tree route exists"); + let result = tree_route(e1().hash, e2().hash); let expected = TreeRoute::new(vec![e1(), d1(), c1(), b1(), a(), b2(), c2(), d2(), e2()], 4); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_11() { - let result = tree_route(b1().hash, c2().hash).expect("tree route exists"); + let result = tree_route(b1().hash, c2().hash); let expected = TreeRoute::new(vec![b1(), a(), b2(), c2()], 1); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_12() { - let result = tree_route(d2().hash, b1().hash).expect("tree route exists"); + let result = tree_route(d2().hash, b1().hash); let expected = TreeRoute::new(vec![d2(), c2(), b2(), a(), b1()], 3); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_13() { - let result = tree_route(c2().hash, e1().hash).expect("tree route exists"); + let result = tree_route(c2().hash, e1().hash); let expected = TreeRoute::new(vec![c2(), b2(), a(), b1(), c1(), d1(), e1()], 2); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_14() { - let result = tree_route(b1().hash, b1().hash).expect("tree route exists"); + let result = tree_route(b1().hash, b1().hash); let expected = TreeRoute::new(vec![b1()], 0); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_15() { - let result = tree_route(b2().hash, b2().hash).expect("tree route exists"); + let result = tree_route(b2().hash, b2().hash); let expected = TreeRoute::new(vec![b2()], 0); assert_treeroute_eq(result, expected); } #[test] fn tree_route_mock_test_16() { - let result = tree_route(a().hash, a().hash).expect("tree route exists"); + let result = tree_route(a().hash, a().hash); let expected = TreeRoute::new(vec![a()], 0); assert_treeroute_eq(result, expected); } diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index 1db37b47e4d44..87ac44459987e 100644 --- a/primitives/blockchain/src/header_metadata.rs +++ b/primitives/blockchain/src/header_metadata.rs @@ -179,9 +179,17 @@ pub struct TreeRoute { impl TreeRoute { /// Creates a new `TreeRoute`. /// - /// It is required that `pivot >= route.len()`, otherwise it may panics. - pub fn new(route: Vec>, pivot: usize) -> Self { - TreeRoute { route, pivot } + /// To preserve the structure safety invariats it is required that `pivot < route.len()`. + pub fn new(route: Vec>, pivot: usize) -> Result { + if pivot < route.len() { + Ok(TreeRoute { route, pivot }) + } else { + Err(format!( + "TreeRoute pivot ({}) should be less than route length ({})", + pivot, + route.len() + )) + } } /// Get a slice of all retracted blocks in reverse order (towards common ancestor). From 3e71d606b7d1e91d9c1701c0a443530eefca1a39 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Sun, 13 Nov 2022 19:48:11 +0100 Subject: [PATCH 1377/1472] New `root_testing` pallet (#12451) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move fill_block to RootOffences * docs * new pallet * new line * fix * Update frame/root-testing/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/root-testing/src/lib.rs Co-authored-by: Bastian Köcher * Update bin/node/runtime/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/root-testing/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/root-testing/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/root-testing/src/lib.rs Co-authored-by: Bastian Köcher * fixes * problem solved * revert * fix dependency * hopefully making the CI happy * ... * dummy call * remove dummy * fix warning Co-authored-by: Bastian Köcher --- Cargo.lock | 17 +++++++++-- Cargo.toml | 1 + bin/node/executor/Cargo.toml | 1 + bin/node/executor/tests/fees.rs | 6 ++-- bin/node/runtime/Cargo.toml | 3 ++ bin/node/runtime/src/lib.rs | 3 ++ frame/root-offences/Cargo.toml | 7 ++--- frame/root-offences/README.md | 2 +- frame/root-offences/src/lib.rs | 2 +- frame/root-testing/Cargo.toml | 34 +++++++++++++++++++++ frame/root-testing/README.md | 5 +++ frame/root-testing/src/lib.rs | 54 +++++++++++++++++++++++++++++++++ frame/system/src/lib.rs | 20 +----------- frame/system/src/mock.rs | 2 +- frame/utility/Cargo.toml | 1 + frame/utility/src/tests.rs | 9 ++++-- 16 files changed, 134 insertions(+), 33 deletions(-) create mode 100644 frame/root-testing/Cargo.toml create mode 100644 frame/root-testing/README.md create mode 100644 frame/root-testing/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index f0471d019c1a2..beb234518041e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3401,6 +3401,7 @@ dependencies = [ "pallet-recovery", "pallet-referenda", "pallet-remark", + "pallet-root-testing", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", @@ -4589,6 +4590,7 @@ dependencies = [ "pallet-balances", "pallet-contracts", "pallet-im-online", + "pallet-root-testing", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", @@ -5957,13 +5959,12 @@ dependencies = [ [[package]] name = "pallet-root-offences" -version = "1.0.0" +version = "1.0.0-dev" dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", "pallet-balances", - "pallet-offences", "pallet-session", "pallet-staking", "pallet-staking-reward-curve", @@ -5977,6 +5978,17 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-root-testing" +version = "1.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-runtime", +] + [[package]] name = "pallet-scheduler" version = "4.0.0-dev" @@ -6317,6 +6329,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-balances", + "pallet-root-testing", "pallet-collective", "pallet-timestamp", "parity-scale-codec", diff --git a/Cargo.toml b/Cargo.toml index ab8fbd816b004..956c106e0dc2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -135,6 +135,7 @@ members = [ "frame/state-trie-migration", "frame/sudo", "frame/root-offences", + "frame/root-testing", "frame/support", "frame/support/procedural", "frame/support/procedural/tools", diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 651e4657dde32..681eb79f0d224 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -38,6 +38,7 @@ pallet-sudo = { version = "4.0.0-dev", path = "../../../frame/sudo" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } pallet-treasury = { version = "4.0.0-dev", path = "../../../frame/treasury" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } +pallet-root-testing = { version = "1.0.0-dev", path = "../../../frame/root-testing" } sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index 6932cb2cea867..3c696d595040b 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -60,9 +60,9 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { CheckedExtrinsic { signed: Some((charlie(), signed_extra(0, 0))), function: RuntimeCall::Sudo(pallet_sudo::Call::sudo { - call: Box::new(RuntimeCall::System(frame_system::Call::fill_block { - ratio: Perbill::from_percent(60), - })), + call: Box::new(RuntimeCall::RootTesting( + pallet_root_testing::Call::fill_block { ratio: Perbill::from_percent(60) }, + )), }), }, ], diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 39364961d57e2..c45d468c59616 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -89,6 +89,7 @@ pallet-ranked-collective = { version = "4.0.0-dev", default-features = false, pa pallet-recovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/recovery" } pallet-referenda = { version = "4.0.0-dev", default-features = false, path = "../../../frame/referenda" } pallet-remark = { version = "4.0.0-dev", default-features = false, path = "../../../frame/remark" } +pallet-root-testing = { version = "1.0.0-dev", default-features = false, path = "../../../frame/root-testing" } pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = "../../../frame/session", default-features = false } pallet-session-benchmarking = { version = "4.0.0-dev", path = "../../../frame/session/benchmarking", default-features = false, optional = true } pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" } @@ -192,6 +193,7 @@ std = [ "pallet-ranked-collective/std", "pallet-referenda/std", "pallet-remark/std", + "pallet-root-testing/std", "pallet-recovery/std", "pallet-uniques/std", "pallet-vesting/std", @@ -292,6 +294,7 @@ try-runtime = [ "pallet-recovery/try-runtime", "pallet-referenda/try-runtime", "pallet-remark/try-runtime", + "pallet-root-testing/try-runtime", "pallet-session/try-runtime", "pallet-staking/try-runtime", "pallet-state-trie-migration/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index eab40634ff241..6c3a46e529727 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -909,6 +909,8 @@ impl pallet_remark::Config for Runtime { type RuntimeEvent = RuntimeEvent; } +impl pallet_root_testing::Config for Runtime {} + parameter_types! { pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; pub const VotingPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; @@ -1670,6 +1672,7 @@ construct_runtime!( ChildBounties: pallet_child_bounties, Referenda: pallet_referenda, Remark: pallet_remark, + RootTesting: pallet_root_testing, ConvictionVoting: pallet_conviction_voting, Whitelist: pallet_whitelist, AllianceMotion: pallet_collective::, diff --git a/frame/root-offences/Cargo.toml b/frame/root-offences/Cargo.toml index ea6a6527848aa..a205fc4aa6ca7 100644 --- a/frame/root-offences/Cargo.toml +++ b/frame/root-offences/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "pallet-root-offences" -version = "1.0.0" +version = "1.0.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME root offences pallet" +readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -17,11 +18,10 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = "../../frame/session", default-features = false } pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../frame/staking" } -pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../frame/offences" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } [dev-dependencies] @@ -45,7 +45,6 @@ std = [ "frame-system/std", "pallet-session/std", "pallet-staking/std", - "pallet-offences/std", "scale-info/std", "sp-runtime/std", ] diff --git a/frame/root-offences/README.md b/frame/root-offences/README.md index a2c5261b6985a..c582158721816 100644 --- a/frame/root-offences/README.md +++ b/frame/root-offences/README.md @@ -1,4 +1,4 @@ -# Sudo Offences Pallet +# Root Offences Pallet Pallet that allows the root to create an offence. diff --git a/frame/root-offences/src/lib.rs b/frame/root-offences/src/lib.rs index b4b549627f3fa..298fe0078a6a6 100644 --- a/frame/root-offences/src/lib.rs +++ b/frame/root-offences/src/lib.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Sudo Offences Pallet +//! # Root Offences Pallet //! Pallet that allows the root to create an offence. //! //! NOTE: This pallet should be used for testing purposes. diff --git a/frame/root-testing/Cargo.toml b/frame/root-testing/Cargo.toml new file mode 100644 index 0000000000000..c625d640bc289 --- /dev/null +++ b/frame/root-testing/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "pallet-root-testing" +version = "1.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME root testing pallet" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } + +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } + +[dev-dependencies] + +[features] +try-runtime = ["frame-support/try-runtime"] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-runtime/std", +] diff --git a/frame/root-testing/README.md b/frame/root-testing/README.md new file mode 100644 index 0000000000000..637430445a22f --- /dev/null +++ b/frame/root-testing/README.md @@ -0,0 +1,5 @@ +# Root Testing Pallet + +Pallet that contains extrinsics that can be usefull in testing. + +NOTE: This pallet should only be used for testing purposes and should not be used in production runtimes! \ No newline at end of file diff --git a/frame/root-testing/src/lib.rs b/frame/root-testing/src/lib.rs new file mode 100644 index 0000000000000..25d66cfac202d --- /dev/null +++ b/frame/root-testing/src/lib.rs @@ -0,0 +1,54 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Root Testing Pallet +//! +//! Pallet that contains extrinsics that can be usefull in testing. +//! +//! NOTE: This pallet should only be used for testing purposes and should not be used in production +//! runtimes! + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::dispatch::DispatchResult; +use sp_runtime::Perbill; + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + /// A dispatch that will fill the block weight up to the given ratio. + #[pallet::weight(*_ratio * T::BlockWeights::get().max_block)] + pub fn fill_block(origin: OriginFor, _ratio: Perbill) -> DispatchResult { + ensure_root(origin)?; + Ok(()) + } + } +} diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 7577d0dc6b158..477ebb97fbd95 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -75,7 +75,7 @@ use sp_runtime::{ CheckEqual, Dispatchable, Hash, Lookup, LookupError, MaybeDisplay, MaybeMallocSizeOf, MaybeSerializeDeserialize, Member, One, Saturating, SimpleBitOps, StaticLookup, Zero, }, - DispatchError, Perbill, RuntimeDebug, + DispatchError, RuntimeDebug, }; #[cfg(any(feature = "std", test))] use sp_std::map; @@ -197,7 +197,6 @@ impl, MaxOverflow: Get> ConsumerLimits for (MaxNormal, pub mod pallet { use crate::{self as frame_system, pallet_prelude::*, *}; use frame_support::pallet_prelude::*; - use sp_runtime::DispatchErrorWithPostInfo; /// System configuration trait. Implemented by runtime. #[pallet::config] @@ -370,23 +369,6 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// A dispatch that will fill the block weight up to the given ratio. - // TODO: This should only be available for testing, rather than in general usage, but - // that's not possible at present (since it's within the pallet macro). - #[pallet::weight(*_ratio * T::BlockWeights::get().max_block)] - pub fn fill_block(origin: OriginFor, _ratio: Perbill) -> DispatchResultWithPostInfo { - match ensure_root(origin) { - Ok(_) => Ok(().into()), - Err(_) => { - // roughly same as a 4 byte remark since perbill is u32. - Err(DispatchErrorWithPostInfo { - post_info: Some(T::SystemWeightInfo::remark(4u32)).into(), - error: DispatchError::BadOrigin, - }) - }, - } - } - /// Make some on-chain remark. /// /// # diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index d31a1b08667e5..fb230f66a94f7 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -24,7 +24,7 @@ use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, + BuildStorage, Perbill, }; type UncheckedExtrinsic = mocking::MockUncheckedExtrinsic; diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index ac4f52c6bb9f3..f49348338394e 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -25,6 +25,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } +pallet-root-testing = { version = "1.0.0-dev", path = "../root-testing" } pallet-collective = { version = "4.0.0-dev", path = "../collective" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } sp-core = { version = "6.0.0", path = "../../primitives/core" } diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index c374f5ae21099..848fc374619b7 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -133,6 +133,7 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Timestamp: pallet_timestamp::{Call, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + RootTesting: pallet_root_testing::{Pallet, Call, Storage}, Council: pallet_collective::, Utility: utility::{Pallet, Call, Event}, Example: example::{Pallet, Call}, @@ -183,6 +184,8 @@ impl pallet_balances::Config for Test { type WeightInfo = (); } +impl pallet_root_testing::Config for Test {} + impl pallet_timestamp::Config for Test { type Moment = u64; type OnTimestampSet = (); @@ -247,6 +250,7 @@ type UtilityCall = crate::Call; use frame_system::Call as SystemCall; use pallet_balances::{Call as BalancesCall, Error as BalancesError}; +use pallet_root_testing::Call as RootTestingCall; use pallet_timestamp::Call as TimestampCall; pub fn new_test_ext() -> sp_io::TestExternalities { @@ -469,8 +473,9 @@ fn batch_early_exit_works() { fn batch_weight_calculation_doesnt_overflow() { use sp_runtime::Perbill; new_test_ext().execute_with(|| { - let big_call = - RuntimeCall::System(SystemCall::fill_block { ratio: Perbill::from_percent(50) }); + let big_call = RuntimeCall::RootTesting(RootTestingCall::fill_block { + ratio: Perbill::from_percent(50), + }); assert_eq!(big_call.get_dispatch_info().weight, Weight::MAX / 2); // 3 * 50% saturates to 100% From 59da38b3a07b4ddf380ff9b01a5874fd883138a9 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 14 Nov 2022 15:55:57 +0100 Subject: [PATCH 1378/1472] [ci] Add DAG for build-rustdoc and check-dependent-project (#12687) * [ci] Debug ci runner * try gha * allow mac jobs fail * add dags * install protoc * fix protobuf name * fix dags * remove allow fail for mac jobs * remove gha * adjust cargo-check-macos --- scripts/ci/gitlab/pipeline/build.yml | 8 ++++++++ scripts/ci/gitlab/pipeline/test.yml | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 482d54b50f73d..2e403c10d4520 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -5,6 +5,10 @@ .check-dependent-project: stage: build + # DAG: this is artificial dependency + needs: + - job: cargo-clippy + artifacts: false extends: - .docker-env - .test-refs-no-trigger-prs-only @@ -147,6 +151,10 @@ build-rustdoc: expire_in: 7 days paths: - ./crate-docs/ + # DAG: this is artificial dependency + needs: + - job: cargo-clippy + artifacts: false script: - rusty-cachier snapshot create - time cargo +nightly doc --locked --workspace --all-features --verbose --no-deps diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 4f523738b151c..710fbe6227f46 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -414,8 +414,10 @@ cargo-check-macos: extends: .test-refs-no-trigger before_script: - !reference [.rust-info-script, script] + variables: + SKIP_WASM_BUILD: 1 script: - - SKIP_WASM_BUILD=1 time cargo check --locked --release + - time cargo check --locked --release tags: - osx From 940a458a8eaf05fdeda441dad82b2df186bf260e Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Mon, 14 Nov 2022 23:34:30 +0100 Subject: [PATCH 1379/1472] Collective: Benchmark with greater `MaxProposals` (#12454) * Collective: Benchmark with greated * fix * remove bs * id_to_remark_data * fix * remove hardcoded * clean up * simplify * questionable renaming * better variable name * better solution * no need for large length * better solution * Update frame/collective/src/benchmarking.rs Co-authored-by: Oliver Tale-Yazdi * fix * test * remove test Co-authored-by: Oliver Tale-Yazdi --- frame/collective/src/benchmarking.rs | 42 +++++++++++++--------------- frame/collective/src/tests.rs | 2 +- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index 4e8bf094ef9d6..75a724623002e 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -34,6 +34,10 @@ fn assert_last_event, I: 'static>(generic_event: >:: frame_system::Pallet::::assert_last_event(generic_event.into()); } +fn id_to_remark_data(id: u32, length: usize) -> Vec { + id.to_le_bytes().into_iter().cycle().take(length).collect() +} + benchmarks_instance_pallet! { set_members { let m in 0 .. T::MaxMembers::get(); @@ -64,9 +68,7 @@ benchmarks_instance_pallet! { let length = 100; for i in 0 .. p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = SystemCall::::remark { - remark: vec![i as u8; length] - }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(i, length) }.into(); Collective::::propose( SystemOrigin::Signed(old_members.last().unwrap().clone()).into(), threshold, @@ -105,7 +107,7 @@ benchmarks_instance_pallet! { } execute { - let b in 1 .. MAX_BYTES; + let b in 2 .. MAX_BYTES; let m in 1 .. T::MaxMembers::get(); let bytes_in_storage = b + size_of::() as u32; @@ -122,7 +124,7 @@ benchmarks_instance_pallet! { Collective::::set_members(SystemOrigin::Root.into(), members, None, T::MaxMembers::get())?; - let proposal: T::Proposal = SystemCall::::remark { remark: vec![1; b as usize] }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(1, b as usize) }.into(); }: _(SystemOrigin::Signed(caller), Box::new(proposal.clone()), bytes_in_storage) verify { @@ -135,7 +137,7 @@ benchmarks_instance_pallet! { // This tests when execution would happen immediately after proposal propose_execute { - let b in 1 .. MAX_BYTES; + let b in 2 .. MAX_BYTES; let m in 1 .. T::MaxMembers::get(); let bytes_in_storage = b + size_of::() as u32; @@ -152,7 +154,7 @@ benchmarks_instance_pallet! { Collective::::set_members(SystemOrigin::Root.into(), members, None, T::MaxMembers::get())?; - let proposal: T::Proposal = SystemCall::::remark { remark: vec![1; b as usize] }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(1, b as usize) }.into(); let threshold = 1; }: propose(SystemOrigin::Signed(caller), threshold, Box::new(proposal.clone()), bytes_in_storage) @@ -166,7 +168,7 @@ benchmarks_instance_pallet! { // This tests when proposal is created and queued as "proposed" propose_proposed { - let b in 1 .. MAX_BYTES; + let b in 2 .. MAX_BYTES; let m in 2 .. T::MaxMembers::get(); let p in 1 .. T::MaxProposals::get(); @@ -186,7 +188,7 @@ benchmarks_instance_pallet! { // Add previous proposals. for i in 0 .. p - 1 { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = SystemCall::::remark { remark: vec![i as u8; b as usize] }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(i, b as usize) }.into(); Collective::::propose( SystemOrigin::Signed(caller.clone()).into(), threshold, @@ -197,7 +199,7 @@ benchmarks_instance_pallet! { assert_eq!(Collective::::proposals().len(), (p - 1) as usize); - let proposal: T::Proposal = SystemCall::::remark { remark: vec![p as u8; b as usize] }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(p, b as usize) }.into(); }: propose(SystemOrigin::Signed(caller.clone()), threshold, Box::new(proposal.clone()), bytes_in_storage) verify { @@ -234,7 +236,7 @@ benchmarks_instance_pallet! { let mut last_hash = T::Hash::default(); for i in 0 .. p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = SystemCall::::remark { remark: vec![i as u8; b as usize] }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(i, b as usize) }.into(); Collective::::propose( SystemOrigin::Signed(proposer.clone()).into(), threshold, @@ -309,9 +311,7 @@ benchmarks_instance_pallet! { let mut last_hash = T::Hash::default(); for i in 0 .. p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = SystemCall::::remark { - remark: vec![i as u8; bytes as usize] - }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(i, bytes as usize) }.into(); Collective::::propose( SystemOrigin::Signed(proposer.clone()).into(), threshold, @@ -364,7 +364,7 @@ benchmarks_instance_pallet! { } close_early_approved { - let b in 1 .. MAX_BYTES; + let b in 2 .. MAX_BYTES; // We choose 4 as a minimum so we always trigger a vote in the voting loop (`for j in ...`) let m in 4 .. T::MaxMembers::get(); let p in 1 .. T::MaxProposals::get(); @@ -388,7 +388,7 @@ benchmarks_instance_pallet! { let mut last_hash = T::Hash::default(); for i in 0 .. p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = SystemCall::::remark { remark: vec![i as u8; b as usize] }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(i, b as usize) }.into(); Collective::::propose( SystemOrigin::Signed(caller.clone()).into(), threshold, @@ -474,9 +474,7 @@ benchmarks_instance_pallet! { let mut last_hash = T::Hash::default(); for i in 0 .. p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = SystemCall::::remark { - remark: vec![i as u8; bytes as usize] - }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(i, bytes as usize) }.into(); Collective::::propose( SystemOrigin::Signed(caller.clone()).into(), threshold, @@ -529,7 +527,7 @@ benchmarks_instance_pallet! { } close_approved { - let b in 1 .. MAX_BYTES; + let b in 2 .. MAX_BYTES; // We choose 4 as a minimum so we always trigger a vote in the voting loop (`for j in ...`) let m in 4 .. T::MaxMembers::get(); let p in 1 .. T::MaxProposals::get(); @@ -558,7 +556,7 @@ benchmarks_instance_pallet! { let mut last_hash = T::Hash::default(); for i in 0 .. p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = SystemCall::::remark { remark: vec![i as u8; b as usize] }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(i, b as usize) }.into(); Collective::::propose( SystemOrigin::Signed(caller.clone()).into(), threshold, @@ -629,7 +627,7 @@ benchmarks_instance_pallet! { let mut last_hash = T::Hash::default(); for i in 0 .. p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = SystemCall::::remark { remark: vec![i as u8; b as usize] }.into(); + let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(i, b as usize) }.into(); Collective::::propose( SystemOrigin::Signed(caller.clone()).into(), threshold, diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 19c54e0493c7b..3d1540a8c3b5c 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -89,7 +89,7 @@ pub type MaxMembers = ConstU32<100>; parameter_types! { pub const MotionDuration: u64 = 3; - pub const MaxProposals: u32 = 100; + pub const MaxProposals: u32 = 257; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); } From 65a8990695224acb02e50c4088eb82c67cf9eb41 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 15 Nov 2022 09:11:40 +0100 Subject: [PATCH 1380/1472] [ci] fix buildah for publishing docker (#12703) --- .gitlab-ci.yml | 1 + scripts/ci/gitlab/pipeline/publish.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9053e39eb59bf..75a1d54776eb6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,6 +48,7 @@ variables: DOCKER_OS: "debian:stretch" ARCH: "x86_64" CI_IMAGE: "paritytech/ci-linux:production" + BUILDAH_IMAGE: "quay.io/buildah/stable:v1.27" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 8f7a619f8b196..9d242d8fb5759 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -7,7 +7,7 @@ - .build-refs - .kubernetes-env variables: - CI_IMAGE: quay.io/buildah/stable + CI_IMAGE: $BUILDAH_IMAGE GIT_STRATEGY: none DOCKERFILE: $PRODUCT.Dockerfile IMAGE_NAME: docker.io/parity/$PRODUCT From c067438f5399c6e832aefc60c09e8087262d7b1a Mon Sep 17 00:00:00 2001 From: Amar Singh Date: Tue, 15 Nov 2022 04:37:12 -0500 Subject: [PATCH 1381/1472] Make public is_passing and ReferendumStatus (#12667) * init * clean * remove manual getter for ReferendumStatus in favor of changing pub crate to pub for ReferendumStatus DecidingStatus Deposit types * rm status getters because fields are pub now --- frame/referenda/src/lib.rs | 25 +++++++++++++++++++++++++ frame/referenda/src/types.rs | 30 +++++++++++++++--------------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index d060c3db3fa70..ba5f4aec956b1 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -701,6 +701,31 @@ impl, I: 'static> Pallet { } } + /// Returns whether the referendum is passing. + /// Referendum must be ongoing and its track must exist. + pub fn is_referendum_passing(ref_index: ReferendumIndex) -> Result { + let info = ReferendumInfoFor::::get(ref_index).ok_or(Error::::BadReferendum)?; + match info { + ReferendumInfo::Ongoing(status) => { + let track = Self::track(status.track).ok_or(Error::::NoTrack)?; + let elapsed = if let Some(deciding) = status.deciding { + frame_system::Pallet::::block_number().saturating_sub(deciding.since) + } else { + Zero::zero() + }; + Ok(Self::is_passing( + &status.tally, + elapsed, + track.decision_period, + &track.min_support, + &track.min_approval, + status.track, + )) + }, + _ => Err(Error::::NotOngoing.into()), + } + } + // Enqueue a proposal from a referendum which has presumably passed. fn schedule_enactment( index: ReferendumIndex, diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 48db0847edf2e..a97faca3bbfc2 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -101,16 +101,16 @@ impl> InsertSorted for BoundedVec { pub struct DecidingStatus { /// When this referendum began being "decided". If confirming, then the /// end will actually be delayed until the end of the confirmation period. - pub(crate) since: BlockNumber, + pub since: BlockNumber, /// If `Some`, then the referendum has entered confirmation stage and will end at /// the block number as long as it doesn't lose its approval in the meantime. - pub(crate) confirming: Option, + pub confirming: Option, } #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Deposit { - pub(crate) who: AccountId, - pub(crate) amount: Balance, + pub who: AccountId, + pub amount: Balance, } #[derive(Clone, Encode, TypeInfo)] @@ -171,28 +171,28 @@ pub struct ReferendumStatus< ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, > { /// The track of this referendum. - pub(crate) track: TrackId, + pub track: TrackId, /// The origin for this referendum. - pub(crate) origin: RuntimeOrigin, + pub origin: RuntimeOrigin, /// The hash of the proposal up for referendum. - pub(crate) proposal: Call, + pub proposal: Call, /// The time the proposal should be scheduled for enactment. - pub(crate) enactment: DispatchTime, + pub enactment: DispatchTime, /// The time of submission. Once `UndecidingTimeout` passes, it may be closed by anyone if /// `deciding` is `None`. - pub(crate) submitted: Moment, + pub submitted: Moment, /// The deposit reserved for the submission of this referendum. - pub(crate) submission_deposit: Deposit, + pub submission_deposit: Deposit, /// The deposit reserved for this referendum to be decided. - pub(crate) decision_deposit: Option>, + pub decision_deposit: Option>, /// The status of a decision being made. If `None`, it has not entered the deciding period. - pub(crate) deciding: Option>, + pub deciding: Option>, /// The current tally of votes in this referendum. - pub(crate) tally: Tally, + pub tally: Tally, /// Whether we have been placed in the queue for being decided or not. - pub(crate) in_queue: bool, + pub in_queue: bool, /// The next scheduled wake-up, if `Some`. - pub(crate) alarm: Option<(Moment, ScheduleAddress)>, + pub alarm: Option<(Moment, ScheduleAddress)>, } /// Info regarding a referendum, present or past. From a0ab42aca55e2f28f0d58fac641d1b5a3293558c Mon Sep 17 00:00:00 2001 From: Anthony Alaribe Date: Tue, 15 Nov 2022 11:59:47 +0200 Subject: [PATCH 1382/1472] Asset Pallet: Support repeated destroys to safely destroy large assets (#12310) * Support repeated destroys to safely destroy large assets * require freezing accounts before destroying * support only deleting asset as final stage when there's no assets left * pre: introduce the RemoveKeyLimit config parameter * debug_ensure empty account in the right if block * update to having separate max values for accounts and approvals * add tests and use RemoveKeyLimit constant * add useful comments to the extrinsics, and calculate returned weight * add benchmarking for start_destroy and finish destroy * push failing benchmark logic * add benchmark tests for new functions * update weights via local benchmarks * remove extra weight file * Update frame/assets/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/assets/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/assets/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * effect some changes from codereview * use NotFrozen error * remove origin checks, as anyone can complete destruction after owner has begun the process; Add live check for other extrinsics * fix comments about Origin behaviour * add AssetStatus docs * modularize logic to allow calling logic in on_idle and on_initialize hooks * introduce simple migration for assets details * reintroduce logging in the migrations * move deposit_Event out of the mutate block * Update frame/assets/src/functions.rs Co-authored-by: Muharem Ismailov * Update frame/assets/src/migration.rs Co-authored-by: Muharem Ismailov * move AssetNotLive checkout out of the mutate blocks * rename RemoveKeysLimit to RemoveItemsLimit * update docs * fix event name in benchmark * fix cargo fmt. * fix lint in benchmarking * Empty commit to trigger CI * Update frame/assets/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/assets/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/assets/src/functions.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/assets/src/functions.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/assets/src/functions.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/assets/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/assets/src/functions.rs Co-authored-by: Oliver Tale-Yazdi * effect change suggested during code review * move limit to a single location * Update frame/assets/src/functions.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * rename events * fix weight typo, using rocksdb instead of T::DbWeight. Pending generating weights * switch to using dead_account.len() * rename event in the benchmarks * empty to retrigger CI * trigger CI to check cumulus dependency * trigger CI for dependent cumulus * Update frame/assets/src/migration.rs Co-authored-by: Oliver Tale-Yazdi * move is-frozen to the assetStatus enum (#12547) * add pre and post migration hooks * update do_transfer logic to add new assert for more correct error messages * trigger CI * switch checking AssetStatus from checking Destroying state to checking live state * fix error type in tests from Frozen to AssetNotLive * trigger CI * change ensure check for fn reducible_balance() * change the error type to Error:::IncorrectStatus to be clearer * Trigger CI Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: parity-processbot <> Co-authored-by: Muharem Ismailov Co-authored-by: Oliver Tale-Yazdi --- bin/node/runtime/src/lib.rs | 1 + frame/assets/src/benchmarking.rs | 85 ++++++--- frame/assets/src/functions.rs | 171 ++++++++++++------ frame/assets/src/impl_fungibles.rs | 16 -- frame/assets/src/lib.rs | 163 +++++++++++++---- frame/assets/src/migration.rs | 122 +++++++++++++ frame/assets/src/mock.rs | 1 + frame/assets/src/tests.rs | 135 ++++++++++---- frame/assets/src/types.rs | 41 ++--- frame/assets/src/weights.rs | 119 ++++++++---- .../asset-tx-payment/src/tests.rs | 1 + 11 files changed, 626 insertions(+), 229 deletions(-) create mode 100644 frame/assets/src/migration.rs diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 6c3a46e529727..cff33e0918981 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1451,6 +1451,7 @@ impl pallet_assets::Config for Runtime { type Freezer = (); type Extra = (); type WeightInfo = pallet_assets::weights::SubstrateWeight; + type RemoveItemsLimit = ConstU32<1000>; } parameter_types! { diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 2bde2b0c98945..cf141360228e9 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -78,25 +78,6 @@ fn swap_is_sufficient, I: 'static>(s: &mut bool) { }); } -fn add_consumers, I: 'static>(minter: T::AccountId, n: u32) { - let origin = SystemOrigin::Signed(minter); - let mut s = false; - swap_is_sufficient::(&mut s); - for i in 0..n { - let target = account("consumer", i, SEED); - T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); - let target_lookup = T::Lookup::unlookup(target); - assert!(Assets::::mint( - origin.clone().into(), - Default::default(), - target_lookup, - 100u32.into() - ) - .is_ok()); - } - swap_is_sufficient::(&mut s); -} - fn add_sufficients, I: 'static>(minter: T::AccountId, n: u32) { let origin = SystemOrigin::Signed(minter); let mut s = true; @@ -168,18 +149,66 @@ benchmarks_instance_pallet! { assert_last_event::(Event::ForceCreated { asset_id: Default::default(), owner: caller }.into()); } - destroy { - let c in 0 .. 5_000; - let s in 0 .. 5_000; - let a in 0 .. 5_00; + start_destroy { + let (caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); + Assets::::freeze_asset( + SystemOrigin::Signed(caller.clone()).into(), + Default::default(), + )?; + }:_(SystemOrigin::Signed(caller), Default::default()) + verify { + assert_last_event::(Event::DestructionStarted { asset_id: Default::default() }.into()); + } + + destroy_accounts { + let c in 0 .. T::RemoveItemsLimit::get(); let (caller, _) = create_default_asset::(true); - add_consumers::(caller.clone(), c); - add_sufficients::(caller.clone(), s); + add_sufficients::(caller.clone(), c); + Assets::::freeze_asset( + SystemOrigin::Signed(caller.clone()).into(), + Default::default(), + )?; + Assets::::start_destroy(SystemOrigin::Signed(caller.clone()).into(), Default::default())?; + }:_(SystemOrigin::Signed(caller), Default::default()) + verify { + assert_last_event::(Event::AccountsDestroyed { + asset_id: Default::default() , + accounts_destroyed: c, + accounts_remaining: 0, + }.into()); + } + + destroy_approvals { + let a in 0 .. T::RemoveItemsLimit::get(); + let (caller, _) = create_default_minted_asset::(true, 100u32.into()); add_approvals::(caller.clone(), a); - let witness = Asset::::get(T::AssetId::default()).unwrap().destroy_witness(); - }: _(SystemOrigin::Signed(caller), Default::default(), witness) + Assets::::freeze_asset( + SystemOrigin::Signed(caller.clone()).into(), + Default::default(), + )?; + Assets::::start_destroy(SystemOrigin::Signed(caller.clone()).into(), Default::default())?; + }:_(SystemOrigin::Signed(caller), Default::default()) verify { - assert_last_event::(Event::Destroyed { asset_id: Default::default() }.into()); + assert_last_event::(Event::ApprovalsDestroyed { + asset_id: Default::default() , + approvals_destroyed: a, + approvals_remaining: 0, + }.into()); + } + + finish_destroy { + let (caller, caller_lookup) = create_default_asset::(true); + Assets::::freeze_asset( + SystemOrigin::Signed(caller.clone()).into(), + Default::default(), + )?; + Assets::::start_destroy(SystemOrigin::Signed(caller.clone()).into(), Default::default())?; + }:_(SystemOrigin::Signed(caller), Default::default()) + verify { + assert_last_event::(Event::Destroyed { + asset_id: Default::default() , + }.into() + ); } mint { diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index 0f8e7096e80c1..f7f11cafecbe2 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -157,7 +157,7 @@ impl, I: 'static> Pallet { if details.supply.checked_sub(&amount).is_none() { return Underflow } - if details.is_frozen { + if details.status == AssetStatus::Frozen { return Frozen } if amount.is_zero() { @@ -205,7 +205,7 @@ impl, I: 'static> Pallet { keep_alive: bool, ) -> Result { let details = Asset::::get(id).ok_or(Error::::Unknown)?; - ensure!(!details.is_frozen, Error::::Frozen); + ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); let account = Account::::get(id, who).ok_or(Error::::NoAccount)?; ensure!(!account.is_frozen, Error::::Frozen); @@ -300,6 +300,7 @@ impl, I: 'static> Pallet { ensure!(!Account::::contains_key(id, &who), Error::::AlreadyExists); let deposit = T::AssetAccountDeposit::get(); let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; + ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); let reason = Self::new_account(&who, &mut details, Some(deposit))?; T::Currency::reserve(&who, deposit)?; Asset::::insert(&id, details); @@ -321,9 +322,8 @@ impl, I: 'static> Pallet { let mut account = Account::::get(id, &who).ok_or(Error::::NoDeposit)?; let deposit = account.reason.take_deposit().ok_or(Error::::NoDeposit)?; let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; - + ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); ensure!(account.balance.is_zero() || allow_burn, Error::::WouldBurn); - ensure!(!details.is_frozen, Error::::Frozen); ensure!(!account.is_frozen, Error::::Frozen); T::Currency::unreserve(&who, deposit); @@ -390,7 +390,7 @@ impl, I: 'static> Pallet { Self::can_increase(id, beneficiary, amount, true).into_result()?; Asset::::try_mutate(id, |maybe_details| -> DispatchResult { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; - + ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); check(details)?; Account::::try_mutate(id, beneficiary, |maybe_account| -> DispatchResult { @@ -430,6 +430,12 @@ impl, I: 'static> Pallet { maybe_check_admin: Option, f: DebitFlags, ) -> Result { + let d = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!( + d.status == AssetStatus::Live || d.status == AssetStatus::Frozen, + Error::::AssetNotLive + ); + let actual = Self::decrease_balance(id, target, amount, f, |actual, details| { // Check admin rights. if let Some(check_admin) = maybe_check_admin { @@ -467,12 +473,14 @@ impl, I: 'static> Pallet { return Ok(amount) } + let details = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); + let actual = Self::prep_debit(id, target, amount, f)?; let mut target_died: Option = None; Asset::::try_mutate(id, |maybe_details| -> DispatchResult { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; - check(actual, details)?; Account::::try_mutate(id, target, |maybe_account| -> DispatchResult { @@ -540,6 +548,8 @@ impl, I: 'static> Pallet { if amount.is_zero() { return Ok((amount, None)) } + let details = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); // Figure out the debit and credit, together with side-effects. let debit = Self::prep_debit(id, source, amount, f.into())?; @@ -651,72 +661,123 @@ impl, I: 'static> Pallet { accounts: 0, sufficients: 0, approvals: 0, - is_frozen: false, + status: AssetStatus::Live, }, ); Self::deposit_event(Event::ForceCreated { asset_id: id, owner }); Ok(()) } - /// Destroy an existing asset. - /// - /// * `id`: The asset you want to destroy. - /// * `witness`: Witness data needed about the current state of the asset, used to confirm - /// complexity of the operation. - /// * `maybe_check_owner`: An optional check before destroying the asset, if the provided - /// account is the owner of that asset. Can be used for authorization checks. - pub(super) fn do_destroy( + /// Start the process of destroying an asset, by setting the asset status to `Destroying`, and + /// emitting the `DestructionStarted` event. + pub(super) fn do_start_destroy( id: T::AssetId, - witness: DestroyWitness, maybe_check_owner: Option, - ) -> Result { - let mut dead_accounts: Vec = vec![]; + ) -> DispatchResult { + Asset::::try_mutate_exists(id, |maybe_details| -> Result<(), DispatchError> { + let mut details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + if let Some(check_owner) = maybe_check_owner { + ensure!(details.owner == check_owner, Error::::NoPermission); + } + details.status = AssetStatus::Destroying; - let result_witness: DestroyWitness = Asset::::try_mutate_exists( - id, - |maybe_details| -> Result { - let mut details = maybe_details.take().ok_or(Error::::Unknown)?; - if let Some(check_owner) = maybe_check_owner { - ensure!(details.owner == check_owner, Error::::NoPermission); - } - ensure!(details.accounts <= witness.accounts, Error::::BadWitness); - ensure!(details.sufficients <= witness.sufficients, Error::::BadWitness); - ensure!(details.approvals <= witness.approvals, Error::::BadWitness); + Self::deposit_event(Event::DestructionStarted { asset_id: id }); + Ok(()) + }) + } + + /// Destroy accounts associated with a given asset up to the max (T::RemoveItemsLimit). + /// + /// Each call emits the `Event::DestroyedAccounts` event. + /// Returns the number of destroyed accounts. + pub(super) fn do_destroy_accounts( + id: T::AssetId, + max_items: u32, + ) -> Result { + let mut dead_accounts: Vec = vec![]; + let mut remaining_accounts = 0; + let _ = + Asset::::try_mutate_exists(id, |maybe_details| -> Result<(), DispatchError> { + let mut details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + // Should only destroy accounts while the asset is in a destroying state + ensure!(details.status == AssetStatus::Destroying, Error::::IncorrectStatus); for (who, v) in Account::::drain_prefix(id) { - // We have to force this as it's destroying the entire asset class. - // This could mean that some accounts now have irreversibly reserved - // funds. let _ = Self::dead_account(&who, &mut details, &v.reason, true); dead_accounts.push(who); + if dead_accounts.len() >= (max_items as usize) { + break + } } - debug_assert_eq!(details.accounts, 0); - debug_assert_eq!(details.sufficients, 0); + remaining_accounts = details.accounts; + Ok(()) + })?; + + for who in &dead_accounts { + T::Freezer::died(id, &who); + } - let metadata = Metadata::::take(&id); - T::Currency::unreserve( - &details.owner, - details.deposit.saturating_add(metadata.deposit), - ); + Self::deposit_event(Event::AccountsDestroyed { + asset_id: id, + accounts_destroyed: dead_accounts.len() as u32, + accounts_remaining: remaining_accounts as u32, + }); + Ok(dead_accounts.len() as u32) + } - for ((owner, _), approval) in Approvals::::drain_prefix((&id,)) { + /// Destroy approvals associated with a given asset up to the max (T::RemoveItemsLimit). + /// + /// Each call emits the `Event::DestroyedApprovals` event + /// Returns the number of destroyed approvals. + pub(super) fn do_destroy_approvals( + id: T::AssetId, + max_items: u32, + ) -> Result { + let mut removed_approvals = 0; + let _ = + Asset::::try_mutate_exists(id, |maybe_details| -> Result<(), DispatchError> { + let mut details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + + // Should only destroy accounts while the asset is in a destroying state. + ensure!(details.status == AssetStatus::Destroying, Error::::IncorrectStatus); + + for ((owner, _), approval) in Approvals::::drain_prefix((id,)) { T::Currency::unreserve(&owner, approval.deposit); + removed_approvals = removed_approvals.saturating_add(1); + details.approvals = details.approvals.saturating_sub(1); + if removed_approvals >= max_items { + break + } } - Self::deposit_event(Event::Destroyed { asset_id: id }); + Self::deposit_event(Event::ApprovalsDestroyed { + asset_id: id, + approvals_destroyed: removed_approvals as u32, + approvals_remaining: details.approvals as u32, + }); + Ok(()) + })?; + Ok(removed_approvals) + } - Ok(DestroyWitness { - accounts: details.accounts, - sufficients: details.sufficients, - approvals: details.approvals, - }) - }, - )?; + /// Complete destroying an asset and unreserve the deposit. + /// + /// On success, the `Event::Destroyed` event is emitted. + pub(super) fn do_finish_destroy(id: T::AssetId) -> DispatchResult { + Asset::::try_mutate_exists(id, |maybe_details| -> Result<(), DispatchError> { + let details = maybe_details.take().ok_or(Error::::Unknown)?; + ensure!(details.status == AssetStatus::Destroying, Error::::IncorrectStatus); + ensure!(details.accounts == 0, Error::::InUse); + ensure!(details.approvals == 0, Error::::InUse); + + let metadata = Metadata::::take(&id); + T::Currency::unreserve( + &details.owner, + details.deposit.saturating_add(metadata.deposit), + ); + Self::deposit_event(Event::Destroyed { asset_id: id }); - // Execute hooks outside of `mutate`. - for who in dead_accounts { - T::Freezer::died(id, &who); - } - Ok(result_witness) + Ok(()) + }) } /// Creates an approval from `owner` to spend `amount` of asset `id` tokens by 'delegate' @@ -730,7 +791,7 @@ impl, I: 'static> Pallet { amount: T::Balance, ) -> DispatchResult { let mut d = Asset::::get(id).ok_or(Error::::Unknown)?; - ensure!(!d.is_frozen, Error::::Frozen); + ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); Approvals::::try_mutate( (id, &owner, &delegate), |maybe_approved| -> DispatchResult { @@ -780,6 +841,9 @@ impl, I: 'static> Pallet { ) -> DispatchResult { let mut owner_died: Option = None; + let d = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); + Approvals::::try_mutate_exists( (id, &owner, delegate), |maybe_approved| -> DispatchResult { @@ -826,6 +890,7 @@ impl, I: 'static> Pallet { symbol.clone().try_into().map_err(|_| Error::::BadMetadata)?; let d = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); ensure!(from == &d.owner, Error::::NoPermission); Metadata::::try_mutate_exists(id, |metadata| { diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 5cddf23680ac2..b005131176f49 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -179,22 +179,6 @@ impl, I: 'static> fungibles::Create for Pallet } } -impl, I: 'static> fungibles::Destroy for Pallet { - type DestroyWitness = DestroyWitness; - - fn get_destroy_witness(asset: &T::AssetId) -> Option { - Asset::::get(asset).map(|asset_details| asset_details.destroy_witness()) - } - - fn destroy( - id: T::AssetId, - witness: Self::DestroyWitness, - maybe_check_owner: Option, - ) -> Result { - Self::do_destroy(id, witness, maybe_check_owner) - } -} - impl, I: 'static> fungibles::metadata::Inspect<::AccountId> for Pallet { diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 017db07194d09..cdd0553218225 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -121,11 +121,15 @@ //! * [`System`](../frame_system/index.html) //! * [`Support`](../frame_support/index.html) +// This recursion limit is needed because we have too many benchmarks and benchmarking will fail if +// we add more without this limit. +#![recursion_limit = "1024"] // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; #[cfg(test)] pub mod mock; #[cfg(test)] @@ -174,8 +178,12 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -195,6 +203,12 @@ pub mod pallet { + MaxEncodedLen + TypeInfo; + /// Max number of items to destroy per `destroy_accounts` and `destroy_approvals` call. + /// + /// Must be configured to result in a weight that makes each call fit in a block. + #[pallet::constant] + type RemoveItemsLimit: Get; + /// Identifier for the class of asset. type AssetId: Member + Parameter @@ -342,7 +356,7 @@ pub mod pallet { accounts: 0, sufficients: 0, approvals: 0, - is_frozen: false, + status: AssetStatus::Live, }, ); } @@ -417,6 +431,16 @@ pub mod pallet { AssetFrozen { asset_id: T::AssetId }, /// Some asset `asset_id` was thawed. AssetThawed { asset_id: T::AssetId }, + /// Accounts were destroyed for given asset. + AccountsDestroyed { asset_id: T::AssetId, accounts_destroyed: u32, accounts_remaining: u32 }, + /// Approvals were destroyed for given asset. + ApprovalsDestroyed { + asset_id: T::AssetId, + approvals_destroyed: u32, + approvals_remaining: u32, + }, + /// An asset class is in the process of being destroyed. + DestructionStarted { asset_id: T::AssetId }, /// An asset class was destroyed. Destroyed { asset_id: T::AssetId }, /// Some asset class was force-created. @@ -487,6 +511,15 @@ pub mod pallet { NoDeposit, /// The operation would result in funds being burned. WouldBurn, + /// The asset is a live asset and is actively being used. Usually emit for operations such + /// as `start_destroy` which require the asset to be in a destroying state. + LiveAsset, + /// The asset is not live, and likely being destroyed. + AssetNotLive, + /// The asset status is not the expected status. + IncorrectStatus, + /// The asset should be frozen before the given operation. + NotFrozen, } #[pallet::call] @@ -540,7 +573,7 @@ pub mod pallet { accounts: 0, sufficients: 0, approvals: 0, - is_frozen: false, + status: AssetStatus::Live, }, ); Self::deposit_event(Event::Created { asset_id: id, creator: owner, owner: admin }); @@ -579,45 +612,89 @@ pub mod pallet { Self::do_force_create(id, owner, is_sufficient, min_balance) } - /// Destroy a class of fungible assets. + /// Start the process of destroying a class of fungible asset + /// start_destroy is the first in a series of extrinsics that should be called, to allow + /// destroying an asset. /// /// The origin must conform to `ForceOrigin` or must be Signed and the sender must be the /// owner of the asset `id`. /// /// - `id`: The identifier of the asset to be destroyed. This must identify an existing - /// asset. - /// - /// Emits `Destroyed` event when successful. - /// - /// NOTE: It can be helpful to first freeze an asset before destroying it so that you - /// can provide accurate witness information and prevent users from manipulating state - /// in a way that can make it harder to destroy. - /// - /// Weight: `O(c + p + a)` where: - /// - `c = (witness.accounts - witness.sufficients)` - /// - `s = witness.sufficients` - /// - `a = witness.approvals` - #[pallet::weight(T::WeightInfo::destroy( - witness.accounts.saturating_sub(witness.sufficients), - witness.sufficients, - witness.approvals, - ))] - pub fn destroy( + /// asset. + /// + /// Assets must be freezed before calling start_destroy. + #[pallet::weight(T::WeightInfo::start_destroy())] + pub fn start_destroy( origin: OriginFor, #[pallet::compact] id: T::AssetId, - witness: DestroyWitness, - ) -> DispatchResultWithPostInfo { + ) -> DispatchResult { let maybe_check_owner = match T::ForceOrigin::try_origin(origin) { Ok(_) => None, Err(origin) => Some(ensure_signed(origin)?), }; - let details = Self::do_destroy(id, witness, maybe_check_owner)?; - Ok(Some(T::WeightInfo::destroy( - details.accounts.saturating_sub(details.sufficients), - details.sufficients, - details.approvals, - )) - .into()) + Self::do_start_destroy(id, maybe_check_owner) + } + + /// Destroy all accounts associated with a given asset. + /// `destroy_accounts` should only be called after `start_destroy` has been called, and the + /// asset is in a `Destroying` state + /// + /// Due to weight restrictions, this function may need to be called multiple + /// times to fully destroy all accounts. It will destroy `RemoveItemsLimit` accounts at a + /// time. + /// + /// - `id`: The identifier of the asset to be destroyed. This must identify an existing + /// asset. + /// + /// Each call Emits the `Event::DestroyedAccounts` event. + #[pallet::weight(T::WeightInfo::destroy_accounts(T::RemoveItemsLimit::get()))] + pub fn destroy_accounts( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + let removed_accounts = Self::do_destroy_accounts(id, T::RemoveItemsLimit::get())?; + Ok(Some(T::WeightInfo::destroy_accounts(removed_accounts)).into()) + } + + /// Destroy all approvals associated with a given asset up to the max (T::RemoveItemsLimit), + /// `destroy_approvals` should only be called after `start_destroy` has been called, and the + /// asset is in a `Destroying` state + /// + /// Due to weight restrictions, this function may need to be called multiple + /// times to fully destroy all approvals. It will destroy `RemoveItemsLimit` approvals at a + /// time. + /// + /// - `id`: The identifier of the asset to be destroyed. This must identify an existing + /// asset. + /// + /// Each call Emits the `Event::DestroyedApprovals` event. + #[pallet::weight(T::WeightInfo::destroy_approvals(T::RemoveItemsLimit::get()))] + pub fn destroy_approvals( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + let removed_approvals = Self::do_destroy_approvals(id, T::RemoveItemsLimit::get())?; + Ok(Some(T::WeightInfo::destroy_approvals(removed_approvals)).into()) + } + + /// Complete destroying asset and unreserve currency. + /// `finish_destroy` should only be called after `start_destroy` has been called, and the + /// asset is in a `Destroying` state. All accounts or approvals should be destroyed before + /// hand. + /// + /// - `id`: The identifier of the asset to be destroyed. This must identify an existing + /// asset. + /// + /// Each successful call Emits the `Event::Destroyed` event. + #[pallet::weight(T::WeightInfo::finish_destroy())] + pub fn finish_destroy( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, + ) -> DispatchResult { + let _ = ensure_signed(origin)?; + Self::do_finish_destroy(id) } /// Mint assets of a particular class. @@ -793,6 +870,10 @@ pub mod pallet { let origin = ensure_signed(origin)?; let d = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!( + d.status == AssetStatus::Live || d.status == AssetStatus::Frozen, + Error::::AssetNotLive + ); ensure!(origin == d.freezer, Error::::NoPermission); let who = T::Lookup::lookup(who)?; @@ -824,6 +905,10 @@ pub mod pallet { let origin = ensure_signed(origin)?; let details = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!( + details.status == AssetStatus::Live || details.status == AssetStatus::Frozen, + Error::::AssetNotLive + ); ensure!(origin == details.admin, Error::::NoPermission); let who = T::Lookup::lookup(who)?; @@ -854,9 +939,10 @@ pub mod pallet { Asset::::try_mutate(id, |maybe_details| { let d = maybe_details.as_mut().ok_or(Error::::Unknown)?; + ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); ensure!(origin == d.freezer, Error::::NoPermission); - d.is_frozen = true; + d.status = AssetStatus::Frozen; Self::deposit_event(Event::::AssetFrozen { asset_id: id }); Ok(()) @@ -882,8 +968,9 @@ pub mod pallet { Asset::::try_mutate(id, |maybe_details| { let d = maybe_details.as_mut().ok_or(Error::::Unknown)?; ensure!(origin == d.admin, Error::::NoPermission); + ensure!(d.status == AssetStatus::Frozen, Error::::NotFrozen); - d.is_frozen = false; + d.status = AssetStatus::Live; Self::deposit_event(Event::::AssetThawed { asset_id: id }); Ok(()) @@ -911,6 +998,7 @@ pub mod pallet { Asset::::try_mutate(id, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + ensure!(details.status == AssetStatus::Live, Error::::LiveAsset); ensure!(origin == details.owner, Error::::NoPermission); if details.owner == owner { return Ok(()) @@ -956,6 +1044,7 @@ pub mod pallet { Asset::::try_mutate(id, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); ensure!(origin == details.owner, Error::::NoPermission); details.issuer = issuer.clone(); @@ -1014,6 +1103,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; let d = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); ensure!(origin == d.owner, Error::::NoPermission); Metadata::::try_mutate_exists(id, |metadata| { @@ -1142,13 +1232,18 @@ pub mod pallet { Asset::::try_mutate(id, |maybe_asset| { let mut asset = maybe_asset.take().ok_or(Error::::Unknown)?; + ensure!(asset.status != AssetStatus::Destroying, Error::::AssetNotLive); asset.owner = T::Lookup::lookup(owner)?; asset.issuer = T::Lookup::lookup(issuer)?; asset.admin = T::Lookup::lookup(admin)?; asset.freezer = T::Lookup::lookup(freezer)?; asset.min_balance = min_balance; asset.is_sufficient = is_sufficient; - asset.is_frozen = is_frozen; + if is_frozen { + asset.status = AssetStatus::Frozen; + } else { + asset.status = AssetStatus::Live; + } *maybe_asset = Some(asset); Self::deposit_event(Event::AssetStatusChanged { asset_id: id }); @@ -1210,6 +1305,7 @@ pub mod pallet { let owner = ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; let mut d = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); let approval = Approvals::::take((id, &owner, &delegate)).ok_or(Error::::Unknown)?; T::Currency::unreserve(&owner, approval.deposit); @@ -1242,6 +1338,7 @@ pub mod pallet { delegate: AccountIdLookupOf, ) -> DispatchResult { let mut d = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); T::ForceOrigin::try_origin(origin) .map(|_| ()) .or_else(|origin| -> DispatchResult { diff --git a/frame/assets/src/migration.rs b/frame/assets/src/migration.rs new file mode 100644 index 0000000000000..89f8d39a9049c --- /dev/null +++ b/frame/assets/src/migration.rs @@ -0,0 +1,122 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use frame_support::{log, traits::OnRuntimeUpgrade}; + +pub mod v1 { + use frame_support::{pallet_prelude::*, weights::Weight}; + + use super::*; + + #[derive(Decode)] + pub struct OldAssetDetails { + pub owner: AccountId, + pub issuer: AccountId, + pub admin: AccountId, + pub freezer: AccountId, + pub supply: Balance, + pub deposit: DepositBalance, + pub min_balance: Balance, + pub is_sufficient: bool, + pub accounts: u32, + pub sufficients: u32, + pub approvals: u32, + pub is_frozen: bool, + } + + impl OldAssetDetails { + fn migrate_to_v1(self) -> AssetDetails { + let status = if self.is_frozen { AssetStatus::Frozen } else { AssetStatus::Live }; + + AssetDetails { + owner: self.owner, + issuer: self.issuer, + admin: self.admin, + freezer: self.freezer, + supply: self.supply, + deposit: self.deposit, + min_balance: self.min_balance, + is_sufficient: self.is_sufficient, + accounts: self.accounts, + sufficients: self.sufficients, + approvals: self.approvals, + status, + } + } + } + + pub struct MigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> Weight { + let current_version = Pallet::::current_storage_version(); + let onchain_version = Pallet::::on_chain_storage_version(); + if onchain_version == 0 && current_version == 1 { + let mut translated = 0u64; + Asset::::translate::< + OldAssetDetails>, + _, + >(|_key, old_value| { + translated.saturating_inc(); + Some(old_value.migrate_to_v1()) + }); + current_version.put::>(); + log::info!(target: "runtime::assets", "Upgraded {} pools, storage to version {:?}", translated, current_version); + T::DbWeight::get().reads_writes(translated + 1, translated + 1) + } else { + log::info!(target: "runtime::assets", "Migration did not execute. This probably should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + frame_support::ensure!( + Pallet::::on_chain_storage_version() == 0, + "must upgrade linearly" + ); + let prev_count = Asset::::iter().count(); + Ok((prev_count as u32).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(prev_count: Vec) -> Result<(), &'static str> { + let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect( + "the state parameter should be something that was generated by pre_upgrade", + ); + let post_count = Asset::::iter().count() as u32; + assert_eq!( + prev_count, post_count, + "the asset count before and after the migration should be the same" + ); + + let current_version = Pallet::::current_storage_version(); + let onchain_version = Pallet::::on_chain_storage_version(); + + frame_support::ensure!(current_version == 1, "must_upgrade"); + assert_eq!( + current_version, onchain_version, + "after migration, the current_version and onchain_version should be the same" + ); + + Asset::::iter().for_each(|(_id, asset)| { + assert!(asset.status == AssetStatus::Live || asset.status == AssetStatus::Frozen, "assets should only be live or frozen. None should be in destroying status, or undefined state") + }); + Ok(()) + } + } +} diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 21fb52c9cd931..567d63356a4ad 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -100,6 +100,7 @@ impl Config for Test { type Freezer = TestFreezer; type WeightInfo = (); type Extra = (); + type RemoveItemsLimit = ConstU32<5>; } use std::collections::HashMap; diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 65e8b66705290..d5fcece0e91d8 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -328,8 +328,12 @@ fn lifecycle_should_work() { assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 20, 100)); assert_eq!(Account::::iter_prefix(0).count(), 2); - let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::destroy_accounts(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::destroy_approvals(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::finish_destroy(RuntimeOrigin::signed(1), 0)); + assert_eq!(Balances::reserved_balance(&1), 0); assert!(!Asset::::contains_key(0)); @@ -348,8 +352,12 @@ fn lifecycle_should_work() { assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 20, 100)); assert_eq!(Account::::iter_prefix(0).count(), 2); - let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(RuntimeOrigin::root(), 0, w)); + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::destroy_accounts(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::destroy_approvals(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::finish_destroy(RuntimeOrigin::signed(1), 0)); + assert_eq!(Balances::reserved_balance(&1), 0); assert!(!Asset::::contains_key(0)); @@ -358,24 +366,6 @@ fn lifecycle_should_work() { }); } -#[test] -fn destroy_with_bad_witness_should_not_work() { - new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); - let mut w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); - assert_eq!(asset_ids(), vec![0, 999]); - // witness too low - assert_noop!(Assets::destroy(RuntimeOrigin::signed(1), 0, w), Error::::BadWitness); - // witness too high is okay though - w.accounts += 2; - w.sufficients += 2; - assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); - assert_eq!(asset_ids(), vec![999]); - }); -} - #[test] fn destroy_should_refund_approvals() { new_test_ext().execute_with(|| { @@ -388,8 +378,13 @@ fn destroy_should_refund_approvals() { assert_eq!(Balances::reserved_balance(&1), 3); assert_eq!(asset_ids(), vec![0, 999]); - let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + + assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::destroy_accounts(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::destroy_approvals(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::finish_destroy(RuntimeOrigin::signed(1), 0)); + assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(asset_ids(), vec![999]); @@ -398,6 +393,58 @@ fn destroy_should_refund_approvals() { }); } +#[test] +fn partial_destroy_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 3, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 4, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 5, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 6, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 7, 10)); + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + + assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::destroy_accounts(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::destroy_approvals(RuntimeOrigin::signed(1), 0)); + // Asset is in use, as all the accounts have not yet been destroyed. + // We need to call destroy_accounts or destroy_approvals again until asset is completely + // cleaned up. + assert_noop!(Assets::finish_destroy(RuntimeOrigin::signed(1), 0), Error::::InUse); + + System::assert_has_event(RuntimeEvent::Assets(crate::Event::AccountsDestroyed { + asset_id: 0, + accounts_destroyed: 5, + accounts_remaining: 2, + })); + System::assert_has_event(RuntimeEvent::Assets(crate::Event::ApprovalsDestroyed { + asset_id: 0, + approvals_destroyed: 0, + approvals_remaining: 0, + })); + // Partially destroyed Asset should continue to exist + assert!(Asset::::contains_key(0)); + + // Second call to destroy on PartiallyDestroyed asset + assert_ok!(Assets::destroy_accounts(RuntimeOrigin::signed(1), 0)); + System::assert_has_event(RuntimeEvent::Assets(crate::Event::AccountsDestroyed { + asset_id: 0, + accounts_destroyed: 2, + accounts_remaining: 0, + })); + assert_ok!(Assets::destroy_approvals(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::destroy_approvals(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::finish_destroy(RuntimeOrigin::signed(1), 0)); + + System::assert_has_event(RuntimeEvent::Assets(crate::Event::Destroyed { asset_id: 0 })); + + // Destroyed Asset should not exist + assert!(!Asset::::contains_key(0)); + }) +} + #[test] fn non_providing_should_work() { new_test_ext().execute_with(|| { @@ -540,7 +587,10 @@ fn transferring_frozen_asset_should_not_work() { assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); - assert_noop!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50), Error::::Frozen); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50), + Error::::AssetNotLive + ); assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(1), 0)); assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); }); @@ -556,7 +606,7 @@ fn approve_transfer_frozen_asset_should_not_work() { assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); assert_noop!( Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), - Error::::Frozen + Error::::AssetNotLive ); assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(1), 0)); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); @@ -590,8 +640,10 @@ fn origin_guards_should_work() { Assets::force_transfer(RuntimeOrigin::signed(2), 0, 1, 2, 100), Error::::NoPermission ); - let w = Asset::::get(0).unwrap().destroy_witness(); - assert_noop!(Assets::destroy(RuntimeOrigin::signed(2), 0, w), Error::::NoPermission); + assert_noop!( + Assets::start_destroy(RuntimeOrigin::signed(2), 0), + Error::::NoPermission + ); }); } @@ -803,22 +855,37 @@ fn set_metadata_should_work() { /// Destroying an asset calls the `FrozenBalance::died` hooks of all accounts. #[test] -fn destroy_calls_died_hooks() { +fn destroy_accounts_calls_died_hooks() { new_test_ext().execute_with(|| { assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 50)); // Create account 1 and 2. assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); - // Destroy the asset. - let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); + // Destroy the accounts. + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::destroy_accounts(RuntimeOrigin::signed(1), 0)); - // Asset is gone and accounts 1 and 2 died. - assert!(Asset::::get(0).is_none()); + // Accounts 1 and 2 died. assert_eq!(hooks(), vec![Hook::Died(0, 1), Hook::Died(0, 2)]); }) } +/// Destroying an asset calls the `FrozenBalance::died` hooks of all accounts. +#[test] +fn finish_destroy_asset_destroys_asset() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 50)); + // Destroy the accounts. + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::finish_destroy(RuntimeOrigin::signed(1), 0)); + + // Asset is gone + assert!(Asset::::get(0).is_none()); + }) +} + #[test] fn freezer_should_work() { new_test_ext().execute_with(|| { diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index 677fc5847c614..557af6bd3f488 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -29,6 +29,19 @@ pub(super) type DepositBalanceOf = pub(super) type AssetAccountOf = AssetAccount<>::Balance, DepositBalanceOf, >::Extra>; +/// AssetStatus holds the current state of the asset. It could either be Live and available for use, +/// or in a Destroying state. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub(super) enum AssetStatus { + /// The asset is active and able to be used. + Live, + /// Whether the asset is frozen for non-admin transfers. + Frozen, + /// The asset is currently being destroyed, and all actions are no longer permitted on the + /// asset. Once set to `Destroying`, the asset can never transition back to a `Live` state. + Destroying, +} + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] pub struct AssetDetails { /// Can change `owner`, `issuer`, `freezer` and `admin` accounts. @@ -54,18 +67,8 @@ pub struct AssetDetails { pub(super) sufficients: u32, /// The total number of approvals. pub(super) approvals: u32, - /// Whether the asset is frozen for non-admin transfers. - pub(super) is_frozen: bool, -} - -impl AssetDetails { - pub fn destroy_witness(&self) -> DestroyWitness { - DestroyWitness { - accounts: self.accounts, - sufficients: self.sufficients, - approvals: self.approvals, - } - } + /// The status of the asset + pub(super) status: AssetStatus, } /// Data concerning an approval. @@ -139,20 +142,6 @@ pub struct AssetMetadata { pub(super) is_frozen: bool, } -/// Witness data for the destroy transactions. -#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub struct DestroyWitness { - /// The number of accounts holding the asset. - #[codec(compact)] - pub(super) accounts: u32, - /// The number of accounts holding the asset with a self-sufficient reference. - #[codec(compact)] - pub(super) sufficients: u32, - /// The number of transfer-approvals of the asset. - #[codec(compact)] - pub(super) approvals: u32, -} - /// Trait for allowing a minimum balance on the account to be specified, beyond the /// `minimum_balance` of the asset. This is additive - the `minimum_balance` of the asset must be /// met *and then* anything here in addition. diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 3b29e55b306fe..747198ae3e5ad 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -49,7 +49,10 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; - fn destroy(c: u32, s: u32, a: u32, ) -> Weight; + fn start_destroy() -> Weight; + fn destroy_accounts(c: u32) -> Weight; + fn destroy_approvals(m: u32) -> Weight; + fn finish_destroy() -> Weight; fn mint() -> Weight; fn burn() -> Weight; fn transfer() -> Weight; @@ -89,30 +92,49 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } + // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:5002 w:5001) - // Storage: System Account (r:5000 w:5000) - // Storage: Assets Metadata (r:1 w:0) - // Storage: Assets Approvals (r:501 w:500) - /// The range of component `c` is `[0, 5000]`. - /// The range of component `s` is `[0, 5000]`. - /// The range of component `a` is `[0, 500]`. - fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - // Minimum execution time: 76_222_544 nanoseconds. - Weight::from_ref_time(76_864_587_000 as u64) - // Standard Error: 127_086 - .saturating_add(Weight::from_ref_time(8_645_143 as u64).saturating_mul(c as u64)) - // Standard Error: 127_086 - .saturating_add(Weight::from_ref_time(11_281_301 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) + fn start_destroy() -> Weight { + Weight::from_ref_time(31_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:0) + // Storage: System Account (r:20 w:20) + /// The range of component `c` is `[0, 1000]`. + fn destroy_accounts(c: u32, ) -> Weight { + Weight::from_ref_time(37_000_000 as u64) + // Standard Error: 19_301 + .saturating_add(Weight::from_ref_time(25_467_908 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(c as u64))) - .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(a as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(c as u64))) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) + } + + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:0) + /// The range of component `a` is `[0, 1000]`. + fn destroy_approvals(a: u32, ) -> Weight { + Weight::from_ref_time(39_000_000 as u64) + // Standard Error: 14_298 + .saturating_add(Weight::from_ref_time(27_632_144 as u64).saturating_mul(a as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(a as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(a as u64))) } + + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Metadata (r:1 w:0) + fn finish_destroy() -> Weight { + Weight::from_ref_time(33_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { @@ -302,30 +324,49 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } + // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:5002 w:5001) - // Storage: System Account (r:5000 w:5000) - // Storage: Assets Metadata (r:1 w:0) - // Storage: Assets Approvals (r:501 w:500) - /// The range of component `c` is `[0, 5000]`. - /// The range of component `s` is `[0, 5000]`. - /// The range of component `a` is `[0, 500]`. - fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - // Minimum execution time: 76_222_544 nanoseconds. - Weight::from_ref_time(76_864_587_000 as u64) - // Standard Error: 127_086 - .saturating_add(Weight::from_ref_time(8_645_143 as u64).saturating_mul(c as u64)) - // Standard Error: 127_086 - .saturating_add(Weight::from_ref_time(11_281_301 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) + fn start_destroy() -> Weight { + Weight::from_ref_time(31_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:0) + // Storage: System Account (r:20 w:20) + /// The range of component `c` is `[0, 1000]`. + fn destroy_accounts(c: u32, ) -> Weight { + Weight::from_ref_time(37_000_000 as u64) + // Standard Error: 19_301 + .saturating_add(Weight::from_ref_time(25_467_908 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(c as u64))) - .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(a as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(c as u64))) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) + } + + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:0) + /// The range of component `a` is `[0, 1000]`. + fn destroy_approvals(a: u32, ) -> Weight { + Weight::from_ref_time(39_000_000 as u64) + // Standard Error: 14_298 + .saturating_add(Weight::from_ref_time(27_632_144 as u64).saturating_mul(a as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(a as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(a as u64))) } + + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Metadata (r:1 w:0) + fn finish_destroy() -> Weight { + Weight::from_ref_time(33_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index cfed1c33c9b24..7b605be5f830c 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -168,6 +168,7 @@ impl pallet_assets::Config for Runtime { type Freezer = (); type Extra = (); type WeightInfo = (); + type RemoveItemsLimit = ConstU32<1000>; } pub struct HardcodedAuthor; From cd30493bc93279bf4b18d6505cc5bdc8d592cbe2 Mon Sep 17 00:00:00 2001 From: Artemka374 <88630083+Artemka374@users.noreply.github.com> Date: Tue, 15 Nov 2022 15:12:08 +0200 Subject: [PATCH 1383/1472] `seal_reentrant_count` returns contract reentrant count (#12695) * Add logic, test, broken benchmark * account_entrance_count * Addressing comments * Address @agryaznov's comments * Add test for account_entrance_count, fix ci * Cargo fmt * Fix tests * Fix tests * Remove delegated call from test, address comments * Minor fixes and indentation in wat files * Update test for account_entrance_count * Update reentrant_count_call test * Delegate call test * Cargo +nightly fmt * Address comments * Update reentrant_count_works test * Apply weights diff * Add fixture descriptions * Update comments as suggested * Update reentrant_count_call test to use seal_address * add missing code * cargo fmt * account_entrance_count -> account_reentrance_count * fix tests * fmt * normalize signatures Co-authored-by: yarikbratashchuk --- .../account_reentrance_count_call.wat | 37 +++++ .../fixtures/reentrant_count_call.wat | 76 ++++++++++ .../reentrant_count_delegated_call.wat | 71 +++++++++ frame/contracts/src/benchmarking/mod.rs | 53 +++++++ frame/contracts/src/exec.rs | 20 +++ frame/contracts/src/schedule.rs | 8 + frame/contracts/src/tests.rs | 139 ++++++++++++++++++ frame/contracts/src/wasm/mod.rs | 72 +++++++++ frame/contracts/src/wasm/runtime.rs | 42 ++++++ frame/contracts/src/weights.rs | 52 ++++++- 10 files changed, 569 insertions(+), 1 deletion(-) create mode 100644 frame/contracts/fixtures/account_reentrance_count_call.wat create mode 100644 frame/contracts/fixtures/reentrant_count_call.wat create mode 100644 frame/contracts/fixtures/reentrant_count_delegated_call.wat diff --git a/frame/contracts/fixtures/account_reentrance_count_call.wat b/frame/contracts/fixtures/account_reentrance_count_call.wat new file mode 100644 index 0000000000000..abb18e4d3d1f7 --- /dev/null +++ b/frame/contracts/fixtures/account_reentrance_count_call.wat @@ -0,0 +1,37 @@ +;; This fixture tests if account_reentrance_count works as expected +;; testing it with 2 different addresses +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_caller" (func $seal_caller (param i32 i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "__unstable__" "account_reentrance_count" (func $account_reentrance_count (param i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 32) buffer where input is copied + ;; [32, 36) size of the input buffer + (data (i32.const 32) "\20") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + ;; Reading "callee" input address + (call $seal_input (i32.const 0) (i32.const 32)) + + (i32.store + (i32.const 36) + (call $account_reentrance_count (i32.const 0)) + ) + + (call $seal_return (i32.const 0) (i32.const 36) (i32.const 4)) + ) + + (func (export "deploy")) + +) \ No newline at end of file diff --git a/frame/contracts/fixtures/reentrant_count_call.wat b/frame/contracts/fixtures/reentrant_count_call.wat new file mode 100644 index 0000000000000..5b4b7220cf478 --- /dev/null +++ b/frame/contracts/fixtures/reentrant_count_call.wat @@ -0,0 +1,76 @@ +;; This fixture recursively tests if reentrant_count returns correct reentrant count value when +;; using seal_call to make caller contract call to itself +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_address" (func $seal_address (param i32 i32))) + (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) + (import "__unstable__" "reentrant_count" (func $reentrant_count (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 32) reserved for $seal_address output + + ;; [32, 36) buffer for the call stack height + + ;; [36, 40) size of the input buffer + (data (i32.const 36) "\04") + + ;; [40, 44) length of the buffer for $seal_address + (data (i32.const 40) "\20") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + (func (export "call") + (local $expected_reentrant_count i32) + (local $seal_call_exit_code i32) + + ;; reading current contract address + (call $seal_address (i32.const 0) (i32.const 40)) + + ;; reading passed input + (call $seal_input (i32.const 32) (i32.const 36)) + + ;; reading manually passed reentrant count + (set_local $expected_reentrant_count (i32.load (i32.const 32))) + + ;; reentrance count is calculated correctly + (call $assert + (i32.eq (call $reentrant_count) (get_local $expected_reentrant_count)) + ) + + ;; re-enter 5 times in a row and assert that the reentrant counter works as expected + (i32.eq (call $reentrant_count) (i32.const 5)) + (if + (then) ;; recursion exit case + (else + ;; incrementing $expected_reentrant_count passed to the contract + (i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1))) + + ;; Call to itself + (set_local $seal_call_exit_code + (call $seal_call + (i32.const 8) ;; Allow reentrancy flag set + (i32.const 0) ;; Pointer to "callee" address + (i64.const 0) ;; How much gas to devote for the execution. 0 = all. + (i32.const 0) ;; Pointer to the buffer with value to transfer + (i32.const 32) ;; Pointer to input data buffer address + (i32.const 4) ;; Length of input data buffer + (i32.const 0xffffffff) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; Ptr to output buffer len + ) + ) + + (call $assert + (i32.eq (get_local $seal_call_exit_code) (i32.const 0)) + ) + ) + ) + ) + + (func (export "deploy")) +) \ No newline at end of file diff --git a/frame/contracts/fixtures/reentrant_count_delegated_call.wat b/frame/contracts/fixtures/reentrant_count_delegated_call.wat new file mode 100644 index 0000000000000..de8f7c1a7a954 --- /dev/null +++ b/frame/contracts/fixtures/reentrant_count_delegated_call.wat @@ -0,0 +1,71 @@ +;; This fixture recursively tests if reentrant_count returns correct reentrant count value when +;; using seal_delegate_call to make caller contract delegate call to itself +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) + (import "seal0" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) + (import "__unstable__" "reentrant_count" (func $reentrant_count (result i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 32) buffer where code hash is copied + + ;; [32, 36) buffer for the call stack height + + ;; [36, 40) size of the input buffer + (data (i32.const 36) "\24") + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + (func (export "call") + (local $callstack_height i32) + (local $delegate_call_exit_code i32) + + ;; Reading input + (call $seal_input (i32.const 0) (i32.const 36)) + + ;; reading passed callstack height + (set_local $callstack_height (i32.load (i32.const 32))) + + ;; incrementing callstack height + (i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1))) + + ;; reentrance count stays 0 + (call $assert + (i32.eq (call $reentrant_count) (i32.const 0)) + ) + + (i32.eq (get_local $callstack_height) (i32.const 5)) + (if + (then) ;; exit recursion case + (else + ;; Call to itself + (set_local $delegate_call_exit_code + (call $seal_delegate_call + (i32.const 0) ;; Set no call flags + (i32.const 0) ;; Pointer to "callee" code_hash. + (i32.const 0) ;; Pointer to the input data + (i32.const 36) ;; Length of the input + (i32.const 4294967295) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + ) + ) + + (call $assert + (i32.eq (get_local $delegate_call_exit_code) (i32.const 0)) + ) + ) + ) + + (call $assert + (i32.le_s (get_local $callstack_height) (i32.const 5)) + ) + ) + + (func (export "deploy")) +) \ No newline at end of file diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 5465e720dc197..539f4b2cf737b 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -2086,6 +2086,59 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + reentrant_count { + let r in 0 .. API_BENCHMARK_BATCHES; + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "reentrant_count", + params: vec![], + return_type: Some(ValueType::I32), + }], + call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + Instruction::Call(0), + Instruction::Drop, + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + + account_reentrance_count { + let r in 0 .. API_BENCHMARK_BATCHES; + let dummy_code = WasmModule::::dummy_with_bytes(0); + let accounts = (0..r * API_BENCHMARK_BATCH_SIZE) + .map(|i| Contract::with_index(i + 1, dummy_code.clone(), vec![])) + .collect::, _>>()?; + let account_id_len = accounts.get(0).map(|i| i.account_id.encode().len()).unwrap_or(0); + let account_id_bytes = accounts.iter().flat_map(|x| x.account_id.encode()).collect(); + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "__unstable__", + name: "account_reentrance_count", + params: vec![ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: account_id_bytes, + }, + ], + call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + Counter(0, account_id_len as u32), // account_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + // We make the assumption that pushing a constant and dropping a value takes roughly // the same amount of time. We follow that `t.load` and `drop` both have the weight // of this benchmark / 2. We need to make this assumption because there is no way diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 7955f076b84c4..76b200001af78 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -296,6 +296,15 @@ pub trait Ext: sealing::Sealed { /// Sets new code hash for existing contract. fn set_code_hash(&mut self, hash: CodeHash) -> Result<(), DispatchError>; + + /// Returns the number of times the currently executing contract exists on the call stack in + /// addition to the calling instance. A value of 0 means no reentrancy. + fn reentrant_count(&self) -> u32; + + /// Returns the number of times the specified contract exists on the call stack. Delegated calls + /// are not calculated as separate entrance. + /// A value of 0 means it does not exist on the call stack. + fn account_reentrance_count(&self, account_id: &AccountIdOf) -> u32; } /// Describes the different functions that can be exported by an [`Executable`]. @@ -1374,6 +1383,17 @@ where ); Ok(()) } + + fn reentrant_count(&self) -> u32 { + let id: &AccountIdOf = &self.top_frame().account_id; + self.account_reentrance_count(id).saturating_sub(1) + } + + fn account_reentrance_count(&self, account_id: &AccountIdOf) -> u32 { + self.frames() + .filter(|f| f.delegate_caller.is_none() && &f.account_id == account_id) + .count() as u32 + } } mod sealing { diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 535517e756c61..52cb7698d6952 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -423,6 +423,12 @@ pub struct HostFnWeights { /// Weight of calling `seal_ecdsa_to_eth_address`. pub ecdsa_to_eth_address: u64, + /// Weight of calling `seal_reentrant_count`. + pub reentrant_count: u64, + + /// Weight of calling `seal_account_reentrance_count`. + pub account_reentrance_count: u64, + /// The type parameter is used in the default implementation. #[codec(skip)] pub _phantom: PhantomData, @@ -659,6 +665,8 @@ impl Default for HostFnWeights { hash_blake2_128_per_byte: cost_byte_batched!(seal_hash_blake2_128_per_kb), ecdsa_recover: cost_batched!(seal_ecdsa_recover), ecdsa_to_eth_address: cost_batched!(seal_ecdsa_to_eth_address), + reentrant_count: cost_batched!(seal_reentrant_count), + account_reentrance_count: cost_batched!(seal_account_reentrance_count), _phantom: PhantomData, } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index bc2ee31681d7f..7054ceb07a6fc 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -4383,3 +4383,142 @@ fn delegate_call_indeterministic_code() { ); }); } + +#[test] +#[cfg(feature = "unstable-interface")] +fn reentrant_count_works_with_call() { + let (wasm, code_hash) = compile_module::("reentrant_count_call").unwrap(); + let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 300_000, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + + // passing reentrant count to the input + let input = 0.encode(); + + Contracts::bare_call( + ALICE, + contract_addr, + 0, + GAS_LIMIT, + None, + input, + true, + Determinism::Deterministic, + ) + .result + .unwrap(); + }); +} + +#[test] +#[cfg(feature = "unstable-interface")] +fn reentrant_count_works_with_delegated_call() { + let (wasm, code_hash) = compile_module::("reentrant_count_delegated_call").unwrap(); + let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 300_000, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + + // adding a callstack height to the input + let input = (code_hash, 1).encode(); + + Contracts::bare_call( + ALICE, + contract_addr.clone(), + 0, + GAS_LIMIT, + None, + input, + true, + Determinism::Deterministic, + ) + .result + .unwrap(); + }); +} + +#[test] +#[cfg(feature = "unstable-interface")] +fn account_reentrance_count_works() { + let (wasm, code_hash) = compile_module::("account_reentrance_count_call").unwrap(); + let (wasm_reentrant_count, code_hash_reentrant_count) = + compile_module::("reentrant_count_call").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 300_000, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 300_000, + GAS_LIMIT, + None, + wasm_reentrant_count, + vec![], + vec![] + )); + + let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + let another_contract_addr = + Contracts::contract_address(&ALICE, &code_hash_reentrant_count, &[]); + + let result1 = Contracts::bare_call( + ALICE, + contract_addr.clone(), + 0, + GAS_LIMIT, + None, + contract_addr.encode(), + true, + Determinism::Deterministic, + ) + .result + .unwrap(); + + let result2 = Contracts::bare_call( + ALICE, + contract_addr.clone(), + 0, + GAS_LIMIT, + None, + another_contract_addr.encode(), + true, + Determinism::Deterministic, + ) + .result + .unwrap(); + + assert_eq!(result1.data, 1.encode()); + assert_eq!(result2.data, 0.encode()); + }); +} diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 9a094ad4f7da0..ba0a0abf11302 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -578,6 +578,12 @@ mod tests { fn ecdsa_to_eth_address(&self, _pk: &[u8; 33]) -> Result<[u8; 20], ()> { Ok([2u8; 20]) } + fn reentrant_count(&self) -> u32 { + 12 + } + fn account_reentrance_count(&self, _account_id: &AccountIdOf) -> u32 { + 12 + } } fn execute>(wat: &str, input_data: Vec, mut ext: E) -> ExecResult { @@ -2850,4 +2856,70 @@ mod tests { assert_eq!(mock_ext.code_hashes.pop().unwrap(), H256::from_slice(&[17u8; 32])); } + + #[test] + #[cfg(feature = "unstable-interface")] + fn reentrant_count_works() { + const CODE: &str = r#" +(module + (import "__unstable__" "reentrant_count" (func $reentrant_count (result i32))) + (import "env" "memory" (memory 1 1)) + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + (func (export "call") + (local $return_val i32) + (set_local $return_val + (call $reentrant_count) + ) + (call $assert + (i32.eq (get_local $return_val) (i32.const 12)) + ) + ) + + (func (export "deploy")) +) +"#; + + let mut mock_ext = MockExt::default(); + execute(CODE, vec![], &mut mock_ext).unwrap(); + } + + #[test] + #[cfg(feature = "unstable-interface")] + fn account_reentrance_count_works() { + const CODE: &str = r#" +(module + (import "__unstable__" "account_reentrance_count" (func $account_reentrance_count (param i32) (result i32))) + (import "env" "memory" (memory 1 1)) + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + (func (export "call") + (local $return_val i32) + (set_local $return_val + (call $account_reentrance_count (i32.const 0)) + ) + (call $assert + (i32.eq (get_local $return_val) (i32.const 12)) + ) + ) + + (func (export "deploy")) +) +"#; + + let mut mock_ext = MockExt::default(); + execute(CODE, vec![], &mut mock_ext).unwrap(); + } } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 50947962c0631..3dac03cac625b 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -251,6 +251,12 @@ pub enum RuntimeCosts { SetCodeHash, /// Weight of calling `ecdsa_to_eth_address` EcdsaToEthAddress, + /// Weight of calling `seal_reentrant_count` + #[cfg(feature = "unstable-interface")] + ReentrantCount, + /// Weight of calling `seal_account_reentrance_count` + #[cfg(feature = "unstable-interface")] + AccountEntranceCount, } impl RuntimeCosts { @@ -330,6 +336,10 @@ impl RuntimeCosts { CallRuntime(weight) => weight.ref_time(), SetCodeHash => s.set_code_hash, EcdsaToEthAddress => s.ecdsa_to_eth_address, + #[cfg(feature = "unstable-interface")] + ReentrantCount => s.reentrant_count, + #[cfg(feature = "unstable-interface")] + AccountEntranceCount => s.account_reentrance_count, }; RuntimeToken { #[cfg(test)] @@ -1188,6 +1198,7 @@ pub mod env { Ok(ReturnCode::KeyNotFound) } } + /// Transfer some value to another account. /// /// # Parameters @@ -1354,6 +1365,7 @@ pub mod env { output_len_ptr, ) } + /// Instantiate a contract with the specified code hash. /// /// # Deprecation @@ -2444,4 +2456,34 @@ pub mod env { Err(_) => Ok(ReturnCode::EcdsaRecoverFailed), } } + + /// Returns the number of times the currently executing contract exists on the call stack in + /// addition to the calling instance. + /// + /// # Return Value + /// + /// Returns 0 when there is no reentrancy. + #[unstable] + fn reentrant_count(ctx: Runtime) -> Result { + ctx.charge_gas(RuntimeCosts::ReentrantCount)?; + Ok(ctx.ext.reentrant_count()) + } + + /// Returns the number of times specified contract exists on the call stack. Delegated calls are + /// not counted as separate calls. + /// + /// # Parameters + /// + /// - `account_ptr`: a pointer to the contract address. + /// + /// # Return Value + /// + /// Returns 0 when the contract does not exist on the call stack. + #[unstable] + fn account_reentrance_count(ctx: Runtime, account_ptr: u32) -> Result { + ctx.charge_gas(RuntimeCosts::AccountEntranceCount)?; + let account_id: <::T as frame_system::Config>::AccountId = + ctx.read_sandbox_memory_as(account_ptr)?; + Ok(ctx.ext.account_reentrance_count(&account_id)) + } } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 8632124c0200d..4652413df1158 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -109,6 +109,8 @@ pub trait WeightInfo { fn seal_ecdsa_recover(r: u32, ) -> Weight; fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight; fn seal_set_code_hash(r: u32, ) -> Weight; + fn seal_reentrant_count(r: u32, ) -> Weight; + fn seal_account_reentrance_count(r: u32, ) -> Weight; fn instr_i64const(r: u32, ) -> Weight; fn instr_i64load(r: u32, ) -> Weight; fn instr_i64store(r: u32, ) -> Weight; @@ -1020,6 +1022,30 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((150 as u64).saturating_mul(r as u64))) } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + /// The range of component `r` is `[0, 20]`. + fn seal_reentrant_count(r: u32, ) -> Weight { + Weight::from_ref_time(304_709_000 as u64) + // Standard Error: 67_000 + .saturating_add(Weight::from_ref_time(15_411_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + /// The range of component `r` is `[0, 20]`. + fn seal_account_reentrance_count(r: u32, ) -> Weight { + Weight::from_ref_time(328_378_000 as u64) + // Standard Error: 137_000 + .saturating_add(Weight::from_ref_time(37_448_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { // Minimum execution time: 69_022 nanoseconds. @@ -2236,6 +2262,30 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((150 as u64).saturating_mul(r as u64))) } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + /// The range of component `r` is `[0, 20]`. + fn seal_reentrant_count(r: u32, ) -> Weight { + Weight::from_ref_time(304_709_000 as u64) + // Standard Error: 67_000 + .saturating_add(Weight::from_ref_time(15_411_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + /// The range of component `r` is `[0, 20]`. + fn seal_account_reentrance_count(r: u32, ) -> Weight { + Weight::from_ref_time(328_378_000 as u64) + // Standard Error: 137_000 + .saturating_add(Weight::from_ref_time(37_448_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { // Minimum execution time: 69_022 nanoseconds. @@ -2593,4 +2643,4 @@ impl WeightInfo for () { // Standard Error: 986 .saturating_add(Weight::from_ref_time(1_867_001 as u64).saturating_mul(r as u64)) } -} +} \ No newline at end of file From eb1a2a8e8d1a84724cdcb80f706c9b17bed6d4a7 Mon Sep 17 00:00:00 2001 From: Anthony Alaribe Date: Tue, 15 Nov 2022 15:12:48 +0200 Subject: [PATCH 1384/1472] Assets Pallet: reintroduce fungibles::Destroy trait (#12708) * update docs formatting * reintroduce the destroy trait * copy changes from original PR * remove witness * Trigger CI * Trigger CI --- Cargo.lock | 2 +- frame/assets/src/impl_fungibles.rs | 18 ++++++ frame/support/src/traits/tokens/fungibles.rs | 62 ++++++++++++++------ 3 files changed, 63 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index beb234518041e..239395c95ccab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6329,8 +6329,8 @@ dependencies = [ "frame-support", "frame-system", "pallet-balances", - "pallet-root-testing", "pallet-collective", + "pallet-root-testing", "pallet-timestamp", "parity-scale-codec", "scale-info", diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index b005131176f49..6e0a9ac08ebb1 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -179,6 +179,24 @@ impl, I: 'static> fungibles::Create for Pallet } } +impl, I: 'static> fungibles::Destroy for Pallet { + fn start_destroy(id: T::AssetId, maybe_check_owner: Option) -> DispatchResult { + Self::do_start_destroy(id, maybe_check_owner) + } + + fn destroy_accounts(id: T::AssetId, max_items: u32) -> Result { + Self::do_destroy_accounts(id, max_items) + } + + fn destroy_approvals(id: T::AssetId, max_items: u32) -> Result { + Self::do_destroy_approvals(id, max_items) + } + + fn finish_destroy(id: T::AssetId) -> DispatchResult { + Self::do_finish_destroy(id) + } +} + impl, I: 'static> fungibles::metadata::Inspect<::AccountId> for Pallet { diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 9bdd5a10d7944..8c370e9a0d8b5 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -267,25 +267,51 @@ pub trait Create: Inspect { /// Trait for providing the ability to destroy existing fungible assets. pub trait Destroy: Inspect { - /// The witness data needed to destroy an asset. - type DestroyWitness; - - /// Provide the appropriate witness data needed to destroy an asset. - fn get_destroy_witness(id: &Self::AssetId) -> Option; - - /// Destroy an existing fungible asset. - /// * `id`: The `AssetId` to be destroyed. - /// * `witness`: Any witness data that needs to be provided to complete the operation - /// successfully. + /// Start the destruction an existing fungible asset. + /// * `id`: The `AssetId` to be destroyed. successfully. /// * `maybe_check_owner`: An optional account id that can be used to authorize the destroy - /// command. If not provided, we will not do any authorization checks before destroying the + /// command. If not provided, no authorization checks will be performed before destroying /// asset. + fn start_destroy(id: Self::AssetId, maybe_check_owner: Option) -> DispatchResult; + + /// Destroy all accounts associated with a given asset. + /// `destroy_accounts` should only be called after `start_destroy` has been called, and the + /// asset is in a `Destroying` state /// - /// If successful, this function will return the actual witness data from the destroyed asset. - /// This may be different than the witness data provided, and can be used to refund weight. - fn destroy( - id: Self::AssetId, - witness: Self::DestroyWitness, - maybe_check_owner: Option, - ) -> Result; + /// * `id`: The identifier of the asset to be destroyed. This must identify an existing asset. + /// * `max_items`: The maximum number of accounts to be destroyed for a given call of the + /// function. This value should be small enough to allow the operation fit into a logical + /// block. + /// + /// Response: + /// * u32: Total number of approvals which were actually destroyed + /// + /// Due to weight restrictions, this function may need to be called multiple + /// times to fully destroy all approvals. It will destroy `max_items` approvals at a + /// time. + fn destroy_accounts(id: Self::AssetId, max_items: u32) -> Result; + /// Destroy all approvals associated with a given asset up to the `max_items` + /// `destroy_approvals` should only be called after `start_destroy` has been called, and the + /// asset is in a `Destroying` state + /// + /// * `id`: The identifier of the asset to be destroyed. This must identify an existing asset. + /// * `max_items`: The maximum number of accounts to be destroyed for a given call of the + /// function. This value should be small enough to allow the operation fit into a logical + /// block. + /// + /// Response: + /// * u32: Total number of approvals which were actually destroyed + /// + /// Due to weight restrictions, this function may need to be called multiple + /// times to fully destroy all approvals. It will destroy `max_items` approvals at a + /// time. + fn destroy_approvals(id: Self::AssetId, max_items: u32) -> Result; + + /// Complete destroying asset and unreserve currency. + /// `finish_destroy` should only be called after `start_destroy` has been called, and the + /// asset is in a `Destroying` state. All accounts or approvals should be destroyed before + /// hand. + /// + /// * `id`: The identifier of the asset to be destroyed. This must identify an existing asset. + fn finish_destroy(id: Self::AssetId) -> DispatchResult; } From 108d8eed88e71b5bb676a23fe983174fabf43c35 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 15 Nov 2022 15:54:14 +0100 Subject: [PATCH 1385/1472] release `sp-core 7.0.0` and `sp-runtime 7.0.0` (#12599) * chore(release): sp-core v7.0.0 * chore(release): sp-runtime v7.0.0 * fix bad merge --- Cargo.lock | 73 +++++++++++-------- bin/node-template/node/Cargo.toml | 4 +- bin/node-template/pallets/template/Cargo.toml | 6 +- bin/node-template/runtime/Cargo.toml | 6 +- bin/node/bench/Cargo.toml | 10 +-- bin/node/cli/Cargo.toml | 10 +-- bin/node/executor/Cargo.toml | 16 ++-- bin/node/inspect/Cargo.toml | 4 +- bin/node/primitives/Cargo.toml | 6 +- bin/node/rpc/Cargo.toml | 4 +- bin/node/runtime/Cargo.toml | 8 +- bin/node/testing/Cargo.toml | 6 +- bin/utils/chain-spec-builder/Cargo.toml | 4 +- client/allocator/Cargo.toml | 4 +- client/api/Cargo.toml | 14 ++-- client/authority-discovery/Cargo.toml | 8 +- client/basic-authorship/Cargo.toml | 4 +- client/beefy/Cargo.toml | 12 +-- client/beefy/rpc/Cargo.toml | 4 +- client/block-builder/Cargo.toml | 6 +- client/chain-spec/Cargo.toml | 4 +- client/cli/Cargo.toml | 8 +- client/consensus/aura/Cargo.toml | 10 +-- client/consensus/babe/Cargo.toml | 12 +-- client/consensus/babe/rpc/Cargo.toml | 8 +- client/consensus/common/Cargo.toml | 6 +- client/consensus/epochs/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 6 +- client/consensus/pow/Cargo.toml | 4 +- client/consensus/slots/Cargo.toml | 8 +- client/consensus/uncles/Cargo.toml | 2 +- client/db/Cargo.toml | 12 +-- client/executor/Cargo.toml | 18 ++--- client/executor/common/Cargo.toml | 2 +- client/executor/runtime-test/Cargo.toml | 8 +- client/executor/wasmi/Cargo.toml | 4 +- client/executor/wasmtime/Cargo.toml | 6 +- client/finality-grandpa/Cargo.toml | 12 +-- client/finality-grandpa/rpc/Cargo.toml | 6 +- client/informant/Cargo.toml | 2 +- client/keystore/Cargo.toml | 6 +- client/network-gossip/Cargo.toml | 2 +- client/network/Cargo.toml | 8 +- client/network/bitswap/Cargo.toml | 4 +- client/network/common/Cargo.toml | 2 +- client/network/light/Cargo.toml | 4 +- client/network/sync/Cargo.toml | 8 +- client/network/test/Cargo.toml | 6 +- client/network/transactions/Cargo.toml | 2 +- client/offchain/Cargo.toml | 6 +- client/rpc-api/Cargo.toml | 6 +- client/rpc-spec-v2/Cargo.toml | 4 +- client/rpc/Cargo.toml | 8 +- client/service/Cargo.toml | 18 ++--- client/service/test/Cargo.toml | 16 ++-- client/state-db/Cargo.toml | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/sysinfo/Cargo.toml | 8 +- client/tracing/Cargo.toml | 6 +- client/transaction-pool/Cargo.toml | 6 +- client/transaction-pool/api/Cargo.toml | 2 +- frame/alliance/Cargo.toml | 8 +- frame/assets/Cargo.toml | 10 +-- frame/atomic-swap/Cargo.toml | 8 +- frame/aura/Cargo.toml | 10 +-- frame/authority-discovery/Cargo.toml | 10 +-- frame/authorship/Cargo.toml | 8 +- frame/babe/Cargo.toml | 10 +-- frame/bags-list/Cargo.toml | 16 ++-- frame/bags-list/remote-tests/Cargo.toml | 10 +-- frame/balances/Cargo.toml | 8 +- frame/beefy-mmr/Cargo.toml | 8 +- frame/beefy-mmr/primitives/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 8 +- frame/benchmarking/Cargo.toml | 16 ++-- frame/bounties/Cargo.toml | 8 +- frame/child-bounties/Cargo.toml | 8 +- frame/collective/Cargo.toml | 8 +- frame/contracts/Cargo.toml | 10 +-- frame/contracts/primitives/Cargo.toml | 4 +- frame/conviction-voting/Cargo.toml | 8 +- frame/democracy/Cargo.toml | 8 +- .../election-provider-multi-phase/Cargo.toml | 16 ++-- frame/election-provider-support/Cargo.toml | 10 +-- .../benchmarking/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 4 +- frame/elections-phragmen/Cargo.toml | 10 +-- frame/examples/basic/Cargo.toml | 8 +- frame/examples/offchain-worker/Cargo.toml | 10 +-- frame/executive/Cargo.toml | 14 ++-- frame/fast-unstake/Cargo.toml | 10 +-- frame/gilt/Cargo.toml | 10 +-- frame/grandpa/Cargo.toml | 10 +-- frame/identity/Cargo.toml | 8 +- frame/im-online/Cargo.toml | 10 +-- frame/indices/Cargo.toml | 8 +- frame/lottery/Cargo.toml | 8 +- frame/membership/Cargo.toml | 8 +- frame/merkle-mountain-range/Cargo.toml | 8 +- frame/merkle-mountain-range/rpc/Cargo.toml | 4 +- frame/multisig/Cargo.toml | 8 +- frame/nicks/Cargo.toml | 8 +- frame/node-authorization/Cargo.toml | 8 +- frame/nomination-pools/Cargo.toml | 12 +-- .../nomination-pools/benchmarking/Cargo.toml | 10 +-- frame/nomination-pools/runtime-api/Cargo.toml | 2 +- .../nomination-pools/test-staking/Cargo.toml | 10 +-- frame/offences/Cargo.toml | 8 +- frame/offences/benchmarking/Cargo.toml | 8 +- frame/preimage/Cargo.toml | 10 +-- frame/proxy/Cargo.toml | 8 +- frame/randomness-collective-flip/Cargo.toml | 8 +- frame/ranked-collective/Cargo.toml | 10 +-- frame/recovery/Cargo.toml | 8 +- frame/referenda/Cargo.toml | 10 +-- frame/remark/Cargo.toml | 10 +-- frame/root-offences/Cargo.toml | 8 +- frame/root-testing/Cargo.toml | 8 +- frame/scheduler/Cargo.toml | 8 +- frame/scored-pool/Cargo.toml | 8 +- frame/session/Cargo.toml | 10 +-- frame/session/benchmarking/Cargo.toml | 8 +- frame/society/Cargo.toml | 8 +- frame/staking/Cargo.toml | 12 +-- frame/staking/reward-curve/Cargo.toml | 2 +- frame/staking/reward-fn/Cargo.toml | 2 +- frame/sudo/Cargo.toml | 8 +- frame/support/Cargo.toml | 14 ++-- frame/support/test/Cargo.toml | 12 +-- frame/support/test/compile_pass/Cargo.toml | 4 +- frame/system/Cargo.toml | 10 +-- frame/system/benchmarking/Cargo.toml | 8 +- frame/timestamp/Cargo.toml | 10 +-- frame/tips/Cargo.toml | 10 +-- frame/transaction-payment/Cargo.toml | 8 +- .../asset-tx-payment/Cargo.toml | 10 +-- frame/transaction-payment/rpc/Cargo.toml | 4 +- .../rpc/runtime-api/Cargo.toml | 2 +- frame/transaction-storage/Cargo.toml | 8 +- frame/treasury/Cargo.toml | 8 +- frame/try-runtime/Cargo.toml | 4 +- frame/uniques/Cargo.toml | 10 +-- frame/utility/Cargo.toml | 10 +-- frame/vesting/Cargo.toml | 8 +- frame/whitelist/Cargo.toml | 8 +- primitives/api/Cargo.toml | 10 +-- primitives/api/test/Cargo.toml | 8 +- primitives/application-crypto/Cargo.toml | 8 +- primitives/application-crypto/test/Cargo.toml | 8 +- primitives/arithmetic/Cargo.toml | 8 +- primitives/arithmetic/fuzzer/Cargo.toml | 2 +- primitives/authority-discovery/Cargo.toml | 6 +- primitives/authorship/Cargo.toml | 4 +- primitives/beefy/Cargo.toml | 12 +-- primitives/block-builder/Cargo.toml | 4 +- primitives/blockchain/Cargo.toml | 4 +- primitives/consensus/aura/Cargo.toml | 6 +- primitives/consensus/babe/Cargo.toml | 10 +-- primitives/consensus/common/Cargo.toml | 8 +- primitives/consensus/pow/Cargo.toml | 6 +- primitives/consensus/slots/Cargo.toml | 6 +- primitives/consensus/vrf/Cargo.toml | 6 +- primitives/core/Cargo.toml | 14 ++-- primitives/core/hashing/Cargo.toml | 4 +- primitives/core/hashing/proc-macro/Cargo.toml | 2 +- primitives/debug-derive/Cargo.toml | 2 +- primitives/externalities/Cargo.toml | 6 +- primitives/finality-grandpa/Cargo.toml | 10 +-- primitives/inherents/Cargo.toml | 6 +- primitives/io/Cargo.toml | 20 ++--- primitives/keyring/Cargo.toml | 4 +- primitives/keystore/Cargo.toml | 6 +- primitives/merkle-mountain-range/Cargo.toml | 8 +- primitives/npos-elections/Cargo.toml | 8 +- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- primitives/offchain/Cargo.toml | 4 +- primitives/panic-handler/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 20 ++--- .../runtime-interface/proc-macro/Cargo.toml | 2 +- .../test-wasm-deprecated/Cargo.toml | 8 +- .../runtime-interface/test-wasm/Cargo.toml | 8 +- primitives/runtime-interface/test/Cargo.toml | 8 +- primitives/runtime/Cargo.toml | 16 ++-- primitives/sandbox/Cargo.toml | 8 +- primitives/session/Cargo.toml | 6 +- primitives/staking/Cargo.toml | 4 +- primitives/state-machine/Cargo.toml | 14 ++-- primitives/std/Cargo.toml | 2 +- primitives/storage/Cargo.toml | 6 +- primitives/test-primitives/Cargo.toml | 6 +- primitives/timestamp/Cargo.toml | 4 +- primitives/tracing/Cargo.toml | 4 +- primitives/transaction-pool/Cargo.toml | 2 +- .../transaction-storage-proof/Cargo.toml | 8 +- primitives/trie/Cargo.toml | 8 +- primitives/version/Cargo.toml | 4 +- primitives/wasm-interface/Cargo.toml | 4 +- primitives/weights/Cargo.toml | 8 +- test-utils/client/Cargo.toml | 8 +- test-utils/runtime/Cargo.toml | 18 ++--- test-utils/runtime/client/Cargo.toml | 4 +- .../runtime/transaction-pool/Cargo.toml | 2 +- utils/frame/benchmarking-cli/Cargo.toml | 16 ++-- utils/frame/frame-utilities-cli/Cargo.toml | 4 +- utils/frame/generate-bags/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 6 +- utils/frame/rpc/client/Cargo.toml | 4 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 6 +- utils/frame/rpc/system/Cargo.toml | 6 +- utils/frame/try-runtime/cli/Cargo.toml | 12 +-- 213 files changed, 830 insertions(+), 815 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 239395c95ccab..962d5f3adbe32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,11 +144,11 @@ checksum = "9d6e24d2cce90c53b948c46271bfb053e4bdc2db9b5d3f65e20f8cf28a1b7fc3" [[package]] name = "assert_cmd" -version = "2.0.2" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e996dc7940838b7ef1096b882e29ec30a3149a3a443cdc8dba19ed382eca1fe2" +checksum = "ba45b8163c49ab5f972e59a8a5a03b6d2972619d486e19ec9fe744f7c2753d3c" dependencies = [ - "bstr", + "bstr 1.0.1", "doc-comment", "predicates", "predicates-core", @@ -698,6 +698,18 @@ dependencies = [ "serde", ] +[[package]] +name = "bstr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd" +dependencies = [ + "memchr", + "once_cell", + "regex-automata", + "serde", +] + [[package]] name = "build-helper" version = "0.1.1" @@ -976,9 +988,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.0.2" +version = "4.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11cba7abac9b56dfe2f035098cdb3a43946f276e6db83b72c4e692343f9aab9a" +checksum = "96b0fba905b035a30d25c1b585bf1171690712fbb0ad3ac47214963aa4acc36c" dependencies = [ "clap 4.0.11", ] @@ -1400,7 +1412,7 @@ version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ - "bstr", + "bstr 0.2.15", "csv-core", "itoa 0.4.8", "ryu", @@ -2737,7 +2749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" dependencies = [ "aho-corasick", - "bstr", + "bstr 0.2.15", "fnv", "log", "regex", @@ -4921,9 +4933,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "oorandom" @@ -5986,7 +5998,10 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", + "sp-core", + "sp-io", "sp-runtime", + "sp-std", ] [[package]] @@ -6737,9 +6752,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "predicates" -version = "2.0.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c143348f141cc87aab5b950021bac6145d0e5ae754b0591de23244cee42c9308" +checksum = "ed6bd09a7f7e68f3f0bf710fb7ab9c4615a488b58b5f653382a687701e458c92" dependencies = [ "difflib", "float-cmp", @@ -9309,7 +9324,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" -version = "6.0.0" +version = "7.0.0" dependencies = [ "parity-scale-codec", "scale-info", @@ -9333,7 +9348,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" -version = "5.0.0" +version = "6.0.0" dependencies = [ "criterion", "integer-sqrt", @@ -9506,7 +9521,7 @@ dependencies = [ [[package]] name = "sp-core" -version = "6.0.0" +version = "7.0.0" dependencies = [ "array-bytes", "base58", @@ -9554,7 +9569,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" -version = "4.0.0" +version = "5.0.0" dependencies = [ "blake2", "byteorder", @@ -9585,7 +9600,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" -version = "4.0.0" +version = "5.0.0" dependencies = [ "proc-macro2", "quote", @@ -9594,7 +9609,7 @@ dependencies = [ [[package]] name = "sp-externalities" -version = "0.12.0" +version = "0.13.0" dependencies = [ "environmental", "parity-scale-codec", @@ -9635,7 +9650,7 @@ dependencies = [ [[package]] name = "sp-io" -version = "6.0.0" +version = "7.0.0" dependencies = [ "bytes", "futures", @@ -9670,7 +9685,7 @@ dependencies = [ [[package]] name = "sp-keystore" -version = "0.12.0" +version = "0.13.0" dependencies = [ "async-trait", "futures", @@ -9750,7 +9765,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" -version = "4.0.0" +version = "5.0.0" dependencies = [ "backtrace", "lazy_static", @@ -9769,7 +9784,7 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "6.0.0" +version = "7.0.0" dependencies = [ "either", "hash256-std-hasher", @@ -9797,7 +9812,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "6.0.0" +version = "7.0.0" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -9820,7 +9835,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" -version = "5.0.0" +version = "6.0.0" dependencies = [ "Inflector", "proc-macro-crate", @@ -9916,7 +9931,7 @@ dependencies = [ [[package]] name = "sp-state-machine" -version = "0.12.0" +version = "0.13.0" dependencies = [ "array-bytes", "assert_matches", @@ -9942,11 +9957,11 @@ dependencies = [ [[package]] name = "sp-std" -version = "4.0.0" +version = "5.0.0" [[package]] name = "sp-storage" -version = "6.0.0" +version = "7.0.0" dependencies = [ "impl-serde", "parity-scale-codec", @@ -9985,7 +10000,7 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "5.0.0" +version = "6.0.0" dependencies = [ "parity-scale-codec", "sp-std", @@ -10019,7 +10034,7 @@ dependencies = [ [[package]] name = "sp-trie" -version = "6.0.0" +version = "7.0.0" dependencies = [ "ahash", "array-bytes", @@ -10073,7 +10088,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "6.0.0" +version = "7.0.0" dependencies = [ "impl-trait-for-tuples", "log", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index d94955f722605..69bf228f9ef75 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -20,7 +20,7 @@ name = "node-template" clap = { version = "4.0.9", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = ["wasmtime"] } sc-service = { version = "0.10.0-dev", path = "../../../client/service", features = ["wasmtime"] } sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" } @@ -34,7 +34,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo sc-finality-grandpa = { version = "0.10.0-dev", path = "../../../client/finality-grandpa" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 3cfcef9d902ce..7c04838cae319 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -22,9 +22,9 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../.. frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../../frame/system" } [dev-dependencies] -sp-core = { version = "6.0.0", default-features = false, path = "../../../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 139264657f89d..1a3c5bd84223b 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -30,12 +30,12 @@ frame-executive = { version = "4.0.0-dev", default-features = false, path = "../ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/block-builder"} sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/consensus/aura" } -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents"} sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 5fb4c418e8ae8..33c9e7c89268f 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -18,20 +18,20 @@ node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } kitchensink-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api/" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../../primitives/state-machine" } serde = "1.0.136" serde_json = "1.0.85" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } kvdb = "0.12.0" kvdb-rocksdb = "0.16.0" -sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-trie = { version = "7.0.0", path = "../../../primitives/trie" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-basic-authorship = { version = "0.10.0-dev", path = "../../../client/basic-authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/timestamp" } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } hash-db = "0.15.2" tempfile = "3.1.0" fs_extra = "1" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index ffd40aac1caa0..9bec0e89195c9 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -48,13 +48,13 @@ sp-authority-discovery = { version = "4.0.0-dev", path = "../../../primitives/au sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } grandpa-primitives = { version = "4.0.0-dev", package = "sp-finality-grandpa", path = "../../../primitives/finality-grandpa" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } +sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../../primitives/transaction-pool" } sp-transaction-storage-proof = { version = "4.0.0-dev", path = "../../../primitives/transaction-storage-proof" } @@ -106,7 +106,7 @@ sc-cli = { version = "0.10.0-dev", optional = true, path = "../../../client/cli" sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service", features = [ "wasmtime", ] } -sp-trie = { version = "6.0.0", default-features = false, path = "../../../primitives/trie", features = [ +sp-trie = { version = "7.0.0", default-features = false, path = "../../../primitives/trie", features = [ "memory-tracker", ] } @@ -118,7 +118,7 @@ sc-consensus-babe = { version = "0.10.0-dev", path = "../../../client/consensus/ sc-consensus-epochs = { version = "0.10.0-dev", path = "../../../client/consensus/epochs" } sc-service-test = { version = "2.0.0", path = "../../../client/service/test" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } futures = "0.3.21" tempfile = "3.1.0" diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 681eb79f0d224..9961f23367dfa 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -18,11 +18,11 @@ frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarkin node-primitives = { version = "2.0.0", path = "../primitives" } kitchensink-runtime = { version = "3.0.0-dev", path = "../runtime" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } -sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } -sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } +sp-state-machine = { version = "0.13.0", path = "../../../primitives/state-machine" } +sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } +sp-trie = { version = "7.0.0", path = "../../../primitives/trie" } [dev-dependencies] criterion = "0.3.0" @@ -38,12 +38,12 @@ pallet-sudo = { version = "4.0.0-dev", path = "../../../frame/sudo" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } pallet-treasury = { version = "4.0.0-dev", path = "../../../frame/treasury" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } +sp-application-crypto = { version = "7.0.0", path = "../../../primitives/application-crypto" } pallet-root-testing = { version = "1.0.0-dev", path = "../../../frame/root-testing" } -sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } +sp-externalities = { version = "0.13.0", path = "../../../primitives/externalities" } sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [features] wasmtime = ["sc-executor/wasmtime"] diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index b7eccf9c36bd2..2b53805a6506b 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -20,5 +20,5 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 65a4223a7fb9f..9be1efd625f50 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../../primitives/application-crypto" } -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../../primitives/application-crypto" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 1f93feabf2f1e..418691ca97f0f 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -33,7 +33,7 @@ sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-bu sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } substrate-frame-rpc-system = { version = "4.0.0-dev", path = "../../../utils/frame/rpc/system" } substrate-state-trie-migration-rpc = { version = "4.0.0-dev", path = "../../../utils/frame/rpc/state-trie-migration-rpc/" } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index c45d468c59616..70660b9cee499 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -30,15 +30,15 @@ sp-block-builder = { path = "../../../primitives/block-builder", default-feature sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents" } node-primitives = { version = "2.0.0", default-features = false, path = "../primitives" } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } -sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } +sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } # frame dependencies diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index ed81301e45189..cf4d3b11d8df8 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -39,10 +39,10 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/timestamp" } substrate-test-client = { version = "2.0.0", path = "../../../test-utils/client" } diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index dc53dc08ec6af..e1d720f673aea 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -20,5 +20,5 @@ rand = "0.8" node-cli = { version = "3.0.0-dev", path = "../../node/cli" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } diff --git a/client/allocator/Cargo.toml b/client/allocator/Cargo.toml index aded67ad80cde..729decb5ebb3f 100644 --- a/client/allocator/Cargo.toml +++ b/client/allocator/Cargo.toml @@ -16,5 +16,5 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.17" thiserror = "1.0.30" -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-wasm-interface = { version = "7.0.0", path = "../../primitives/wasm-interface" } diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index 8cb3ad565afb0..c57a1e7221ad7 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -29,14 +29,14 @@ sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } -sp-keystore = { version = "0.12.0", default-features = false, path = "../../primitives/keystore" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } -sp-storage = { version = "6.0.0", path = "../../primitives/storage" } -sp-trie = { version = "6.0.0", path = "../../primitives/trie" } +sp-externalities = { version = "0.13.0", path = "../../primitives/externalities" } +sp-keystore = { version = "0.13.0", default-features = false, path = "../../primitives/keystore" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../primitives/state-machine" } +sp-storage = { version = "7.0.0", path = "../../primitives/storage" } +sp-trie = { version = "7.0.0", path = "../../primitives/trie" } [dev-dependencies] thiserror = "1.0.30" diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 91c977d90a660..0da79bd70ff44 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -32,12 +32,12 @@ sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-authority-discovery = { version = "4.0.0-dev", path = "../../primitives/authority-discovery" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } async-trait = "0.1.56" [dev-dependencies] quickcheck = { version = "1.0.3", default-features = false } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 43493ada051f8..09b5c47394491 100644 --- a/client/basic-authorship/Cargo.toml +++ b/client/basic-authorship/Cargo.toml @@ -26,9 +26,9 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../client/transact sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] parking_lot = "0.12.1" diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index a125d4c8d4f07..8b6a1336195ba 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -31,14 +31,14 @@ sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } -sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } +sp-application-crypto = { version = "7.0.0", path = "../../primitives/application-crypto" } +sp-arithmetic = { version = "6.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } sp-mmr-primitives = { version = "4.0.0-dev", path = "../../primitives/merkle-mountain-range" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] serde = "1.0.136" @@ -49,5 +49,5 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-network-test = { version = "0.8.0", path = "../network/test" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 3ccf83c1f5106..71220388505b8 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -20,8 +20,8 @@ beefy-gadget = { version = "4.0.0-dev", path = "../." } beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [dev-dependencies] serde_json = "1.0.85" diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 69b84132fe90b..2516374864bc1 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -20,10 +20,10 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../primitives/state-machine" } [dev-dependencies] substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index b38dba03d6b7f..3756a7783763b 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -21,5 +21,5 @@ serde_json = "1.0.85" sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index f749b9b5b0c4a..f1d0a04205dbb 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -40,11 +40,11 @@ sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } -sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } +sp-panic-handler = { version = "5.0.0", path = "../../primitives/panic-handler" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } sp-version = { version = "5.0.0", path = "../../primitives/version" } [dev-dependencies] diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 3fe9891e9a7ba..eb144a19fca9c 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -25,16 +25,16 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } +sp-application-crypto = { version = "7.0.0", path = "../../../primitives/application-crypto" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consensus/aura" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [dev-dependencies] parking_lot = "0.12.1" @@ -44,5 +44,5 @@ sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 6eefc60552388..bbe2e43eb6982 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -35,18 +35,18 @@ sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" } sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-application-crypto = { version = "6.0.0", path = "../../../primitives/application-crypto" } +sp-application-crypto = { version = "7.0.0", path = "../../../primitives/application-crypto" } sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } sp-consensus-vrf = { version = "0.10.0-dev", path = "../../../primitives/consensus/vrf" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } +sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-version = { version = "5.0.0", path = "../../../primitives/version" } [dev-dependencies] @@ -56,5 +56,5 @@ sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 8433e3ac92e57..0f937693488d1 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -21,13 +21,13 @@ sc-consensus-babe = { version = "0.10.0-dev", path = "../" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../../epochs" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../rpc-api" } sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } -sp-application-crypto = { version = "6.0.0", path = "../../../../primitives/application-crypto" } +sp-application-crypto = { version = "7.0.0", path = "../../../../primitives/application-crypto" } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../../primitives/consensus/babe" } -sp-core = { version = "6.0.0", path = "../../../../primitives/core" } -sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } -sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../../primitives/core" } +sp-keystore = { version = "0.13.0", path = "../../../../primitives/keystore" } +sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] serde_json = "1.0.85" diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index d5745665a79fd..971ee71ab8040 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -27,9 +27,9 @@ sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../../primitives/state-machine" } [dev-dependencies] sp-test-primitives = { version = "2.0.0", path = "../../../primitives/test-primitives" } diff --git a/client/consensus/epochs/Cargo.toml b/client/consensus/epochs/Cargo.toml index 5c52b76185200..c88b5c52ba18e 100644 --- a/client/consensus/epochs/Cargo.toml +++ b/client/consensus/epochs/Cargo.toml @@ -18,4 +18,4 @@ fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-consensus = { version = "0.10.0-dev", path = "../common" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 9c3bc5413317d..a066de75f7def 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -35,10 +35,10 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consensus/aura" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } [dev-dependencies] diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 4833786d2b990..480d9b23b06a3 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -28,6 +28,6 @@ sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-bu sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-pow = { version = "0.10.0-dev", path = "../../../primitives/consensus/pow" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index fae499ad7c7c6..4bb9387cf5596 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -23,14 +23,14 @@ thiserror = "1.0.30" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } -sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } +sp-arithmetic = { version = "6.0.0", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../../primitives/state-machine" } [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml index cf0aaf5cd30d7..0be48659f9c77 100644 --- a/client/consensus/uncles/Cargo.toml +++ b/client/consensus/uncles/Cargo.toml @@ -16,4 +16,4 @@ targets = ["x86_64-unknown-linux-gnu"] thiserror = "1.0.30" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index c12bf933f6bb1..dda1a640d886f 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -26,13 +26,13 @@ parity-db = "0.4.2" parking_lot = "0.12.1" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } -sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "6.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-database = { version = "4.0.0-dev", path = "../../primitives/database" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } -sp-trie = { version = "6.0.0", path = "../../primitives/trie" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../primitives/state-machine" } +sp-trie = { version = "7.0.0", path = "../../primitives/trie" } [dev-dependencies] criterion = "0.3.3" @@ -41,7 +41,7 @@ rand = "0.8.4" tempfile = "3.1.0" quickcheck = { version = "1.0.3", default-features = false } kitchensink-runtime = { path = "../../bin/node/runtime" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index e48c27dfc998e..b84529d2a80d8 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -25,23 +25,23 @@ sc-executor-common = { version = "0.10.0-dev", path = "common" } sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } -sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } -sp-panic-handler = { version = "4.0.0", path = "../../primitives/panic-handler" } -sp-runtime-interface = { version = "6.0.0", path = "../../primitives/runtime-interface" } -sp-trie = { version = "6.0.0", path = "../../primitives/trie" } +sp-externalities = { version = "0.13.0", path = "../../primitives/externalities" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } +sp-panic-handler = { version = "5.0.0", path = "../../primitives/panic-handler" } +sp-runtime-interface = { version = "7.0.0", path = "../../primitives/runtime-interface" } +sp-trie = { version = "7.0.0", path = "../../primitives/trie" } sp-version = { version = "5.0.0", path = "../../primitives/version" } -sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } +sp-wasm-interface = { version = "7.0.0", path = "../../primitives/wasm-interface" } [dev-dependencies] array-bytes = "4.1" wat = "1.0" sc-runtime-test = { version = "2.0.0", path = "runtime-test" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../primitives/state-machine" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } tracing-subscriber = "0.2.19" diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 71a6f2c324591..4b83e9fcc9b92 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -23,7 +23,7 @@ wasmi = "0.13" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } -sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface" } +sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interface" } [features] default = [] diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index f90b2e1439a77..c8b173de16e9f 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -14,11 +14,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] paste = "1.0.6" -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, features = ["improved_panic_error_reporting"], path = "../../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, features = ["improved_panic_error_reporting"], path = "../../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 879af677ca042..ef01f3784154d 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -19,6 +19,6 @@ log = "0.4.17" wasmi = "0.13" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } -sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } +sp-runtime-interface = { version = "7.0.0", path = "../../../primitives/runtime-interface" } sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } -sp-wasm-interface = { version = "6.0.0", path = "../../../primitives/wasm-interface" } +sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interface" } diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index fc6d5db14aa1d..a80ef77e0357c 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -31,9 +31,9 @@ wasmtime = { version = "1.0.0", default-features = false, features = [ ] } sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } -sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } +sp-runtime-interface = { version = "7.0.0", path = "../../../primitives/runtime-interface" } sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } -sp-wasm-interface = { version = "6.0.0", features = ["wasmtime"], path = "../../../primitives/wasm-interface" } +sp-wasm-interface = { version = "7.0.0", features = ["wasmtime"], path = "../../../primitives/wasm-interface" } # Here we include the rustix crate in the exactly same semver-compatible version as used by # wasmtime and enable its 'use-libc' flag. @@ -47,6 +47,6 @@ once_cell = "1.12.0" [dev-dependencies] wat = "1.0" sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } tempfile = "3.3.0" paste = "1.0" diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 288e579d8da29..a95e3e8da467c 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -40,14 +40,14 @@ sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } -sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } +sp-application-crypto = { version = "7.0.0", path = "../../primitives/application-crypto" } +sp-arithmetic = { version = "6.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3.0" @@ -57,5 +57,5 @@ tokio = "1.17.0" sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-test = { version = "0.8.0", path = "../network/test" } sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 075179d3ceaf7..06d3e8a304153 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -22,15 +22,15 @@ sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [dev-dependencies] sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-rpc = { version = "4.0.0-dev", features = [ "test-helpers", ], path = "../../rpc" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index 073199d005fd1..682a754ba16a6 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -22,4 +22,4 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index ff963f9d446f6..8766ee80157e9 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -19,9 +19,9 @@ async-trait = "0.1.57" parking_lot = "0.12.1" serde_json = "1.0.85" thiserror = "1.0" -sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-application-crypto = { version = "7.0.0", path = "../../primitives/application-crypto" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } [dev-dependencies] tempfile = "3.1.0" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 95c281456396d..31930515ff118 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -24,7 +24,7 @@ tracing = "0.1.29" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] async-std = "1.11.0" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 4637a2a5105e5..afd9880148081 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -49,11 +49,11 @@ sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sc-network-common = { version = "0.10.0-dev", path = "./common" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } sc-utils = { version = "4.0.0-dev", path = "../utils" } -sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "6.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3" @@ -63,7 +63,7 @@ tempfile = "3.1.0" sc-network-light = { version = "0.10.0-dev", path = "./light" } sc-network-sync = { version = "0.10.0-dev", path = "./sync" } sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/network/bitswap/Cargo.toml b/client/network/bitswap/Cargo.toml index f60e21b4429fb..9793eeae51b26 100644 --- a/client/network/bitswap/Cargo.toml +++ b/client/network/bitswap/Cargo.toml @@ -28,13 +28,13 @@ void = "1.0.2" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-network-common = { version = "0.10.0-dev", path = "../common" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [dev-dependencies] tokio = { version = "1", features = ["full"] } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 48d83a59c742b..bf4a89c70b88c 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -34,6 +34,6 @@ sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } serde = { version = "1.0.136", features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } thiserror = "1.0" diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index cd3be390d48c8..c7ec6eda7a70b 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -29,6 +29,6 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-network-common = { version = "0.10.0-dev", path = "../common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } thiserror = "1.0" diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index bcd6cf10275fe..ce1dd8f895d61 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -33,17 +33,17 @@ sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-network-common = { version = "0.10.0-dev", path = "../common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } -sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } +sp-arithmetic = { version = "6.0.0", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [dev-dependencies] async-std = { version = "1.11.0", features = ["attributes"] } quickcheck = { version = "1.0.3", default-features = false } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-test-primitives = { version = "2.0.0", path = "../../../primitives/test-primitives" } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 30a57bc1b5171..eb4d54b9dc82d 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -32,8 +32,8 @@ sc-service = { version = "0.10.0-dev", default-features = false, features = ["te sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } +sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml index d92c07cd461a8..147a86d8de2ae 100644 --- a/client/network/transactions/Cargo.toml +++ b/client/network/transactions/Cargo.toml @@ -24,5 +24,5 @@ pin-project = "1.0.12" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } sc-network-common = { version = "0.10.0-dev", path = "../common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 1e8c802496453..f23335ef97e33 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -33,9 +33,9 @@ sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-peerset = { version = "4.0.0-dev", path = "../peerset" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] lazy_static = "1.4.0" @@ -45,7 +45,7 @@ sc-client-db = { version = "0.10.0-dev", default-features = true, path = "../db" sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 7c4057154bdb0..cb82a3b26706b 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -23,9 +23,9 @@ serde_json = "1.0.85" thiserror = "1.0" sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } sp-version = { version = "5.0.0", path = "../../primitives/version" } jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } diff --git a/client/rpc-spec-v2/Cargo.toml b/client/rpc-spec-v2/Cargo.toml index 885d415eb50d2..51f5516ecf9c8 100644 --- a/client/rpc-spec-v2/Cargo.toml +++ b/client/rpc-spec-v2/Cargo.toml @@ -18,8 +18,8 @@ jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } # Pool for submitting extrinsics required by "transaction" sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 4131fecaf510e..0a420301826e1 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -30,11 +30,11 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/a sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" } sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-version = { version = "5.0.0", path = "../../primitives/version" } @@ -50,7 +50,7 @@ sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } tokio = "1.17.0" -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index a0c8f21effec1..4057e6072c261 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -36,21 +36,21 @@ hash-db = "0.15.2" serde = "1.0.136" serde_json = "1.0.85" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sp-trie = { version = "6.0.0", path = "../../primitives/trie" } -sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } +sp-trie = { version = "7.0.0", path = "../../primitives/trie" } +sp-externalities = { version = "0.13.0", path = "../../primitives/externalities" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-version = { version = "5.0.0", path = "../../primitives/version" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } -sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } -sp-application-crypto = { version = "6.0.0", path = "../../primitives/application-crypto" } +sp-state-machine = { version = "0.13.0", path = "../../primitives/state-machine" } +sp-application-crypto = { version = "7.0.0", path = "../../primitives/application-crypto" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } -sp-storage = { version = "6.0.0", path = "../../primitives/storage" } +sp-storage = { version = "7.0.0", path = "../../primitives/storage" } sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-bitswap = { version = "0.10.0-dev", path = "../network/bitswap" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } @@ -77,7 +77,7 @@ sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-offchain = { version = "4.0.0-dev", path = "../offchain" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } sc-sysinfo = { version = "6.0.0-dev", path = "../sysinfo" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 1f934a6e5355f..b2011c05e8235 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -32,13 +32,13 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/trans sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } -sp-panic-handler = { version = "4.0.0", path = "../../../primitives/panic-handler" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } -sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } -sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-externalities = { version = "0.13.0", path = "../../../primitives/externalities" } +sp-panic-handler = { version = "5.0.0", path = "../../../primitives/panic-handler" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../../primitives/state-machine" } +sp-storage = { version = "7.0.0", path = "../../../primitives/storage" } +sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } +sp-trie = { version = "7.0.0", path = "../../../primitives/trie" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 7f9a502aef8e9..07c08363287d6 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -19,4 +19,4 @@ parity-util-mem = { version = "0.12.0", default-features = false, features = ["p parity-util-mem-derive = "0.1.0" parking_lot = "0.12.1" sc-client-api = { version = "4.0.0-dev", path = "../api" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 12ffc0c2e8d7a..d4e8222911219 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -24,4 +24,4 @@ sc-consensus-babe = { version = "0.10.0-dev", path = "../consensus/babe" } sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } diff --git a/client/sysinfo/Cargo.toml b/client/sysinfo/Cargo.toml index 882cbd96c1c5f..c59611ed1b432 100644 --- a/client/sysinfo/Cargo.toml +++ b/client/sysinfo/Cargo.toml @@ -23,9 +23,9 @@ regex = "1" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } -sp-std = { version = "4.0.0", path = "../../primitives/std" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } +sp-std = { version = "5.0.0", path = "../../primitives/std" } [dev-dependencies] -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index 43fa2d4e52e8a..be6237a344f52 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -33,10 +33,10 @@ sc-rpc-server = { version = "4.0.0-dev", path = "../rpc-servers" } sc-tracing-proc-macro = { version = "4.0.0-dev", path = "./proc-macro" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } [dev-dependencies] criterion = "0.3" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 0bdfb623e6c14..f7f644a6b059b 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -29,9 +29,9 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "./api" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } [dev-dependencies] diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index 366d0eb99b945..e14a3ff4f3839 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -15,7 +15,7 @@ log = "0.4.17" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } [dev-dependencies] serde_json = "1.0" diff --git a/frame/alliance/Cargo.toml b/frame/alliance/Cargo.toml index 399822a2215f5..da0a7d665747d 100644 --- a/frame/alliance/Cargo.toml +++ b/frame/alliance/Cargo.toml @@ -20,10 +20,10 @@ log = { version = "0.4.14", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 7e750f7618437..715149b20c042 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -15,9 +15,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } # Needed for type-safe access to storage DB. frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } # `system` module provides us with all sorts of useful stuff and macros depend on it being around. @@ -25,9 +25,9 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-std = { version = "4.0.0", path = "../../primitives/std" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-std = { version = "5.0.0", path = "../../primitives/std" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index e70041f21ca96..5220edb9d17c7 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -17,10 +17,10 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index 7dad0b6b1b098..552f13301d311 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -18,14 +18,14 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index 514fd7e244ef9..47bd1a126f4da 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -22,14 +22,14 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys pallet-session = { version = "4.0.0-dev", default-features = false, features = [ "historical", ], path = "../session" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authority-discovery" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 3078b9dfa295a..7c0289909f806 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -21,12 +21,12 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 9f79a404724e0..a3232f6f981d0 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -22,14 +22,14 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-consensus-vrf = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/vrf" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } @@ -37,7 +37,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 19eb66ae624af..10086635ef08f 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -18,8 +18,8 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # primitives -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } # FRAME frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -32,14 +32,14 @@ log = { version = "0.4.17", default-features = false } # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking", optional = true, default-features = false } pallet-balances = { version = "4.0.0-dev", path = "../balances", optional = true, default-features = false } -sp-core = { version = "6.0.0", path = "../../primitives/core", optional = true, default-features = false } -sp-io = { version = "6.0.0", path = "../../primitives/io", optional = true, default-features = false } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing", optional = true, default-features = false } +sp-core = { version = "7.0.0", path = "../../primitives/core", optional = true, default-features = false } +sp-io = { version = "7.0.0", path = "../../primitives/io", optional = true, default-features = false } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing", optional = true, default-features = false } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core"} -sp-io = { version = "6.0.0", path = "../../primitives/io"} -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-core = { version = "7.0.0", path = "../../primitives/core"} +sp-io = { version = "7.0.0", path = "../../primitives/io"} +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 3e2de430f6424..de97ebd0e6a13 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -21,11 +21,11 @@ frame-system = { path = "../../system", version = "4.0.0-dev" } frame-support = { path = "../../support", version = "4.0.0-dev" } # core -sp-storage = { path = "../../../primitives/storage", version = "6.0.0"} -sp-core = { path = "../../../primitives/core", version = "6.0.0"} -sp-tracing = { path = "../../../primitives/tracing", version = "5.0.0"} -sp-runtime = { path = "../../../primitives/runtime", version = "6.0.0"} -sp-std = { path = "../../../primitives/std", version = "4.0.0" } +sp-storage = { path = "../../../primitives/storage", version = "7.0.0" } +sp-core = { path = "../../../primitives/core", version = "7.0.0" } +sp-tracing = { path = "../../../primitives/tracing", version = "6.0.0" } +sp-runtime = { path = "../../../primitives/runtime", version = "7.0.0" } +sp-std = { path = "../../../primitives/std", version = "5.0.0" } # utils remote-externalities = { path = "../../../utils/frame/remote-externalities", version = "0.10.0-dev" } diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index fd2312993b7e7..934138a900214 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -19,13 +19,13 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 62fabd387a167..33b93343106a2 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -21,10 +21,10 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys pallet-beefy = { version = "4.0.0-dev", default-features = false, path = "../beefy" } pallet-mmr = { version = "4.0.0-dev", default-features = false, path = "../merkle-mountain-range" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] array-bytes = "4.1" diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/frame/beefy-mmr/primitives/Cargo.toml index a097da0fc30fd..edd0daa5aa21d 100644 --- a/frame/beefy-mmr/primitives/Cargo.toml +++ b/frame/beefy-mmr/primitives/Cargo.toml @@ -14,7 +14,7 @@ log = { version = "0.4", default-features = false, optional = true } beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/beefy" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } [dev-dependencies] array-bytes = "4.1" diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 84aa8c7757c45..5cb180750a7e7 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -16,12 +16,12 @@ beefy-primitives = { version = "4.0.0-dev", default-features = false, path = ".. frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } [features] diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 61aa2b9b900c6..7c18b69401884 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -22,18 +22,18 @@ serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../../primitives/runtime-interface" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-storage = { version = "6.0.0", default-features = false, path = "../../primitives/storage" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime-interface = { version = "7.0.0", default-features = false, path = "../../primitives/runtime-interface" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-storage = { version = "7.0.0", default-features = false, path = "../../primitives/storage" } [dev-dependencies] array-bytes = "4.1" rusty-fork = { version = "0.3.0", default-features = false } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } [features] default = ["std"] diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 4aaf088abb5b6..a5411952a385a 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -22,10 +22,10 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index ee9a838744d25..6b0a672d04225 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -23,10 +23,10 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../bounties" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index aca2434127f03..0e8c5421f5ff1 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -19,10 +19,10 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [features] default = ["std"] diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 7483ec8935890..a4dfe308be249 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -39,11 +39,11 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "primitives" } pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../primitives/sandbox" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] array-bytes = "4.1" @@ -57,7 +57,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } pallet-randomness-collective-flip = { version = "4.0.0-dev", path = "../randomness-collective-flip" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } [features] default = ["std"] diff --git a/frame/contracts/primitives/Cargo.toml b/frame/contracts/primitives/Cargo.toml index c8b7c4a2f7c37..835970a5e5294 100644 --- a/frame/contracts/primitives/Cargo.toml +++ b/frame/contracts/primitives/Cargo.toml @@ -17,8 +17,8 @@ bitflags = "1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } # Substrate Dependencies (This crate should not rely on frame) -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-weights = { version = "4.0.0", default-features = false, path = "../../../primitives/weights" } [features] diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index 3c40017ece8e7..9bfc93f2d9ff5 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -23,14 +23,14 @@ serde = { version = "1.0.136", features = ["derive"], optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index e50d39ff76902..49dbe133d6919 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -21,10 +21,10 @@ serde = { version = "1.0.136", features = ["derive"], optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } log = { version = "0.4.17", default-features = false } [dev-dependencies] diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index ca94fef6a4356..ba460055e2358 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -25,12 +25,12 @@ log = { version = "0.4.17", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } # Optional imports for benchmarking @@ -42,10 +42,10 @@ strum = { version = "0.24.1", default-features = false, features = ["derive"], [dev-dependencies] parking_lot = "0.12.1" rand = { version = "0.7.3" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 5d064c770f8d9..754aa8d37aee3 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -18,15 +18,15 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-election-provider-solution-type = { version = "4.0.0-dev", path = "solution-type" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] rand = "0.7.3" -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } [features] diff --git a/frame/election-provider-support/benchmarking/Cargo.toml b/frame/election-provider-support/benchmarking/Cargo.toml index 0f296d9a70ee0..60538997773d4 100644 --- a/frame/election-provider-support/benchmarking/Cargo.toml +++ b/frame/election-provider-support/benchmarking/Cargo.toml @@ -19,7 +19,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = ".." } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index a7ce4fa662131..5a0c46cb83a0d 100644 --- a/frame/election-provider-support/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -23,7 +23,7 @@ proc-macro-crate = "1.1.3" [dev-dependencies] parity-scale-codec = "3.0.0" scale-info = "2.1.1" -sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } +sp-arithmetic = { version = "6.0.0", path = "../../../primitives/arithmetic" } # used by generate_solution_type: frame-election-provider-support = { version = "4.0.0-dev", path = ".." } frame-support = { version = "4.0.0-dev", path = "../../support" } diff --git a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 2cc620452586d..34aeaf9300352 100644 --- a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -21,8 +21,8 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { version = "4.0.0-dev", path = ".." } frame-election-provider-support = { version = "4.0.0-dev", path = "../.." } -sp-arithmetic = { version = "5.0.0", path = "../../../../primitives/arithmetic" } -sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +sp-arithmetic = { version = "6.0.0", path = "../../../../primitives/arithmetic" } +sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } # used by generate_solution_type: sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/npos-elections" } frame-support = { version = "4.0.0-dev", path = "../../../support" } diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index 2d71a6bed39df..fb1d924dbd1bd 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -21,15 +21,15 @@ scale-info = { version = "2.0.0", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-tracing = { path = "../../primitives/tracing" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index e06bfa374cd9b..8c69dc6c3e9ce 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -20,12 +20,12 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } -sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } [features] default = ["std"] diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index bc5c0ac036021..446af8dda9198 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -19,11 +19,11 @@ log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } -sp-keystore = { version = "0.12.0", optional = true, path = "../../../primitives/keystore" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } +sp-keystore = { version = "0.13.0", optional = true, path = "../../../primitives/keystore" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } [features] default = ["std"] diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index f6f5175d63bb9..b3e4247445710 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -20,19 +20,19 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-try-runtime = { version = "0.10.0-dev", default-features = false, path = "../try-runtime", optional = true } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-tracing = { version = "5.0.0", default-features = false, path = "../../primitives/tracing" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-tracing = { version = "6.0.0", default-features = false, path = "../../primitives/tracing" } [dev-dependencies] array-bytes = "4.1" pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } sp-version = { version = "5.0.0", path = "../../primitives/version" } [features] diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml index f14a5e7b9c20b..c48ff862b7dfe 100644 --- a/frame/fast-unstake/Cargo.toml +++ b/frame/fast-unstake/Cargo.toml @@ -20,9 +20,9 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } sp-staking = { default-features = false, path = "../../primitives/staking" } frame-election-provider-support = { default-features = false, path = "../election-provider-support" } @@ -30,9 +30,9 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional [dev-dependencies] pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } pallet-staking = { path = "../staking" } pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index 8c60c847027a3..f7bd98999f79d 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -18,14 +18,14 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 4bd17b914cefa..8da4fe61fcb75 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -21,14 +21,14 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] grandpa = { package = "finality-grandpa", version = "0.16.0", features = ["derive-codec"] } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 92e55c5c2b934..8c7655af6ab34 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -19,13 +19,13 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index 8c08ad1a8a89a..c0058e9f2371d 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -20,12 +20,12 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-session = { version = "4.0.0-dev", path = "../session" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index adc3f2a6ea90f..2431487cdb824 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -18,11 +18,11 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 486bb356059f6..14ec21a563cba 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -20,14 +20,14 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 8ec1087e5ac0e..b457c4c2911bd 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -19,10 +19,10 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [features] default = ["std"] diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 9a3ee517e7d42..8d1f897a65cd4 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -18,11 +18,11 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/merkle-mountain-range" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] array-bytes = "4.1" diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index eb2e1e8b53d9e..feacd7d3b3413 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -18,9 +18,9 @@ jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-mmr-primitives = { version = "4.0.0-dev", path = "../../../primitives/merkle-mountain-range" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } anyhow = "1" [dev-dependencies] diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index bfd0870d30c22..4e9f4f5d832e6 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -18,16 +18,16 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } # third party log = { version = "0.4.17", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 1d378b257f5a2..2390060c71698 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -17,13 +17,13 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 0b27028228c10..fbf486644e15c 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -17,10 +17,10 @@ log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [features] default = ["std"] diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index 2db0b234b726d..4894e3d97f19a 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -19,20 +19,20 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" # FRAME frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } log = { version = "0.4.0", default-features = false } # Optional: usef for testing and/or fuzzing pallet-balances = { version = "4.0.0-dev", path = "../balances", optional = true } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing", optional = true } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing", optional = true } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } [features] default = ["std"] diff --git a/frame/nomination-pools/benchmarking/Cargo.toml b/frame/nomination-pools/benchmarking/Cargo.toml index 69ba6585481d5..ac470f04a6195 100644 --- a/frame/nomination-pools/benchmarking/Cargo.toml +++ b/frame/nomination-pools/benchmarking/Cargo.toml @@ -27,17 +27,17 @@ pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../. pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../" } # Substrate Primitives -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime-interface" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime-interface = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime-interface" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } [features] default = ["std"] diff --git a/frame/nomination-pools/runtime-api/Cargo.toml b/frame/nomination-pools/runtime-api/Cargo.toml index dde925c62fe0d..cf72d795c9faa 100644 --- a/frame/nomination-pools/runtime-api/Cargo.toml +++ b/frame/nomination-pools/runtime-api/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } [features] default = ["std"] diff --git a/frame/nomination-pools/test-staking/Cargo.toml b/frame/nomination-pools/test-staking/Cargo.toml index ad36e89e0d68a..8350fdd05c8cd 100644 --- a/frame/nomination-pools/test-staking/Cargo.toml +++ b/frame/nomination-pools/test-staking/Cargo.toml @@ -15,11 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } scale-info = { version = "2.0.1", features = ["derive"] } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } -sp-std = { version = "4.0.0", path = "../../../primitives/std" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } +sp-std = { version = "5.0.0", path = "../../../primitives/std" } sp-staking = { version = "4.0.0-dev", path = "../../../primitives/staking" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } frame-system = { version = "4.0.0-dev", path = "../../system" } frame-support = { version = "4.0.0-dev", path = "../../support" } @@ -32,5 +32,5 @@ pallet-bags-list = { version = "4.0.0-dev", path = "../../bags-list" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } pallet-nomination-pools = { version = "1.0.0-dev", path = ".." } -sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } log = { version = "0.4.0" } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index ddbed3d3297fa..107a0489cd594 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -20,13 +20,13 @@ serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index 3c7a43068af82..e20aefd69ad4d 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -26,15 +26,15 @@ pallet-im-online = { version = "4.0.0-dev", default-features = false, path = ".. pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../offences" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../../session" } pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../staking" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } [features] default = ["std"] diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 77046f4fb58b6..3315405809491 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -15,15 +15,15 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, optional = true, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, optional = true, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } log = { version = "0.4.17", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index afec89ad40fb8..1674e408668d2 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -18,14 +18,14 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index 03f0022a42e29..5a20949e9f243 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -18,12 +18,12 @@ safe-mix = { version = "1.0", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/ranked-collective/Cargo.toml b/frame/ranked-collective/Cargo.toml index c8cf671a97467..c5e79eb68f24d 100644 --- a/frame/ranked-collective/Cargo.toml +++ b/frame/ranked-collective/Cargo.toml @@ -19,11 +19,11 @@ scale-info = { version = "2.0.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [features] default = ["std"] diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index fb33b88d2dfab..cdcebbec161bc 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -18,13 +18,13 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index 4e68d7528ad8a..a9428a408df80 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -19,20 +19,20 @@ codec = { package = "parity-scale-codec", version = "3.0.3", default-features = ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../primitives/arithmetic" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] assert_matches = { version = "1.5" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/remark/Cargo.toml b/frame/remark/Cargo.toml index f644ea723b59f..a827d165f8389 100644 --- a/frame/remark/Cargo.toml +++ b/frame/remark/Cargo.toml @@ -19,13 +19,13 @@ serde = { version = "1.0.136", optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/root-offences/Cargo.toml b/frame/root-offences/Cargo.toml index a205fc4aa6ca7..76eb832c88e1b 100644 --- a/frame/root-offences/Cargo.toml +++ b/frame/root-offences/Cargo.toml @@ -21,7 +21,7 @@ pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../. frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } [dev-dependencies] @@ -29,9 +29,9 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } diff --git a/frame/root-testing/Cargo.toml b/frame/root-testing/Cargo.toml index c625d640bc289..bc474f4f09c5f 100644 --- a/frame/root-testing/Cargo.toml +++ b/frame/root-testing/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } - frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } - -[dev-dependencies] +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [features] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index e78d8cd5061c1..86ca63c753bea 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -16,13 +16,13 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index 2ec765498be9e..a1e8dc453df6c 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -17,13 +17,13 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 14996782eae87..57b519e81e59b 100644 --- a/frame/session/Cargo.toml +++ b/frame/session/Cargo.toml @@ -20,13 +20,13 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-trie = { version = "6.0.0", default-features = false, optional = true, path = "../../primitives/trie" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-trie = { version = "7.0.0", default-features = false, optional = true, path = "../../primitives/trie" } [features] default = ["historical", "std"] diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 5b2fc0c9e1ebf..90d6d95c07f4f 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -19,9 +19,9 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../.. frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../../session" } pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../staking" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } @@ -30,8 +30,8 @@ frame-election-provider-support = { version = "4.0.0-dev", path = "../../electio pallet-balances = { version = "4.0.0-dev", path = "../../balances" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } [features] default = ["std"] diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index 5e13c95d74eb3..40b78c8922299 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -18,14 +18,14 @@ rand_chacha = { version = "0.2", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] frame-support-test = { version = "3.0.0", path = "../support/test" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index cf9e12dcd82b4..466883f868bc0 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -18,9 +18,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -28,7 +28,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, features = [ "historical", ], path = "../session" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } log = { version = "0.4.17", default-features = false } @@ -37,8 +37,8 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " rand_chacha = { version = "0.2", default-features = false, optional = true } [dev-dependencies] -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index 9e561fea4575b..c761517ea6829 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -21,4 +21,4 @@ quote = "1.0.10" syn = { version = "1.0.98", features = ["full", "visit"] } [dev-dependencies] -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } diff --git a/frame/staking/reward-fn/Cargo.toml b/frame/staking/reward-fn/Cargo.toml index f16131f481494..0fb034a17202b 100644 --- a/frame/staking/reward-fn/Cargo.toml +++ b/frame/staking/reward-fn/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.17", default-features = false } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../../primitives/arithmetic" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../../primitives/arithmetic" } [features] default = ["std"] diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index efa75813af543..b0e38b0139c11 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -17,12 +17,12 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 5af1dc26c1b49..b199c014d35ed 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -18,12 +18,12 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-metadata = { version = "15.0.0", default-features = false, features = ["v14"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-tracing = { version = "5.0.0", default-features = false, path = "../../primitives/tracing" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-tracing = { version = "6.0.0", default-features = false, path = "../../primitives/tracing" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } @@ -31,7 +31,7 @@ tt-call = "1.0.8" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } -sp-state-machine = { version = "0.12.0", default-features = false, optional = true, path = "../../primitives/state-machine" } +sp-state-machine = { version = "0.13.0", default-features = false, optional = true, path = "../../primitives/state-machine" } bitflags = "1.3" impl-trait-for-tuples = "0.2.2" smallvec = "1.8.0" diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 471dba8df44e2..0ac3d90f59e07 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -15,13 +15,13 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.136", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../../primitives/arithmetic" } -sp-io = { version = "6.0.0", path = "../../../primitives/io", default-features = false } -sp-state-machine = { version = "0.12.0", optional = true, path = "../../../primitives/state-machine" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../../primitives/arithmetic" } +sp-io = { version = "7.0.0", path = "../../../primitives/io", default-features = false } +sp-state-machine = { version = "0.13.0", optional = true, path = "../../../primitives/state-machine" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } trybuild = { version = "1.0.60", features = [ "diff" ] } pretty_assertions = "1.2.1" diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index 34bd980e0187b..ea22a735b3698 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -16,8 +16,8 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../../../primitives/core" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../../primitives/core" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "5.0.0", default-features = false, path = "../../../../primitives/version" } [features] diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index dd3a5d606bad5..55c9b5bda54fa 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -18,16 +18,16 @@ log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } sp-version = { version = "5.0.0", default-features = false, path = "../../primitives/version" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } [dev-dependencies] criterion = "0.3.3" -sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } +sp-externalities = { version = "0.13.0", path = "../../primitives/externalities" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 9ec9ed2ae6d21..30b299ea6a56e 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -18,12 +18,12 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] -sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } [features] default = ["std"] diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index ac495d84b2c1e..df63ed0d72b8e 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -21,14 +21,14 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } -sp-io = { version = "6.0.0", default-features = false, optional = true, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, optional = true, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../primitives/timestamp" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index b00a684c1c83b..7d0576ec28cce 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -21,14 +21,14 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-treasury = { version = "4.0.0-dev", default-features = false, path = "../treasury" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-storage = { version = "6.0.0", path = "../../primitives/storage" } +sp-storage = { version = "7.0.0", path = "../../primitives/storage" } [features] default = ["std"] diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index 9150f87c7175a..a2f77b6cf2279 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -20,10 +20,10 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] serde_json = "1.0.85" diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 2c1247cfc557a..51ce2f69a4d8e 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate dependencies -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } @@ -31,7 +31,7 @@ serde = { version = "1.0.136", optional = true } [dev-dependencies] serde_json = "1.0.85" -sp-storage = { version = "6.0.0", default-features = false, path = "../../../primitives/storage" } +sp-storage = { version = "7.0.0", default-features = false, path = "../../../primitives/storage" } pallet-assets = { version = "4.0.0-dev", path = "../../assets" } pallet-authorship = { version = "4.0.0-dev", path = "../../authorship" } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 9dd42c12c8bbf..06dcaca937381 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -18,7 +18,7 @@ jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-weights = { version = "4.0.0", path = "../../../primitives/weights" } diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index c0b816684a2f3..86753526fef47 100644 --- a/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../../primitives/runtime" } sp-weights = { version = "4.0.0", default-features = false, path = "../../../../primitives/weights" } [features] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index a6e177af1853d..73867c3643a69 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -22,14 +22,14 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-storage-proof" } log = { version = "0.4.17", default-features = false } [dev-dependencies] -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = true, path = "../../primitives/transaction-storage-proof" } [features] diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 08b0acdba5deb..993f89ff0faa5 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -24,12 +24,12 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index 51b6f91784594..247505e6130ab 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"]} frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [features] default = [ "std" ] diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 31aa608ff84b6..6e36240748c4b 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -19,14 +19,14 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } -sp-std = { version = "4.0.0", path = "../../primitives/std" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } +sp-std = { version = "5.0.0", path = "../../primitives/std" } [features] default = ["std"] diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index f49348338394e..de293ed5df8af 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -18,17 +18,17 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-root-testing = { version = "1.0.0-dev", path = "../root-testing" } pallet-collective = { version = "4.0.0-dev", path = "../collective" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } [features] default = ["std"] diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 6a64b474d1485..23fa06454b23c 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -21,13 +21,13 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } [features] default = ["std"] diff --git a/frame/whitelist/Cargo.toml b/frame/whitelist/Cargo.toml index 895a6e753816d..94fd0db0077b1 100644 --- a/frame/whitelist/Cargo.toml +++ b/frame/whitelist/Cargo.toml @@ -19,14 +19,14 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] default = ["std"] diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index a322799048a31..3139c66cef921 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } sp-version = { version = "5.0.0", default-features = false, path = "../version" } -sp-state-machine = { version = "0.12.0", default-features = false, optional = true, path = "../state-machine" } -sp-trie = { version = "6.0.0", default-features = false, optional = true, path = "../trie" } +sp-state-machine = { version = "0.13.0", default-features = false, optional = true, path = "../state-machine" } +sp-trie = { version = "7.0.0", default-features = false, optional = true, path = "../trie" } hash-db = { version = "0.15.2", optional = true } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 25000072c88a9..edc0d43e91437 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] sp-api = { version = "4.0.0-dev", path = "../" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } sp-version = { version = "5.0.0", path = "../../version" } -sp-tracing = { version = "5.0.0", path = "../../tracing" } -sp-runtime = { version = "6.0.0", path = "../../runtime" } +sp-tracing = { version = "6.0.0", path = "../../tracing" } +sp-runtime = { version = "7.0.0", path = "../../runtime" } sp-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } codec = { package = "parity-scale-codec", version = "3.0.0" } -sp-state-machine = { version = "0.12.0", path = "../../state-machine" } +sp-state-machine = { version = "0.13.0", path = "../../state-machine" } trybuild = "1.0.60" rustversion = "1.0.6" @@ -28,7 +28,7 @@ rustversion = "1.0.6" criterion = "0.3.0" futures = "0.3.21" log = "0.4.17" -sp-core = { version = "6.0.0", path = "../../core" } +sp-core = { version = "7.0.0", path = "../../core" } [[bench]] name = "bench" diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index 117e84e959392..39a3413bcf981 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-application-crypto" -version = "6.0.0" +version = "7.0.0" authors = ["Parity Technologies "] edition = "2021" description = "Provides facilities for generating application specific crypto wrapper types." @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-io = { version = "6.0.0", default-features = false, path = "../io" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } +sp-io = { version = "7.0.0", default-features = false, path = "../io" } [features] default = [ "std" ] diff --git a/primitives/application-crypto/test/Cargo.toml b/primitives/application-crypto/test/Cargo.toml index 2962fb7477735..b10b7a3218ba6 100644 --- a/primitives/application-crypto/test/Cargo.toml +++ b/primitives/application-crypto/test/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", path = "../../api" } -sp-application-crypto = { version = "6.0.0", path = "../" } -sp-core = { version = "6.0.0", default-features = false, path = "../../core" } -sp-keystore = { version = "0.12.0", default-features = false, path = "../../keystore" } -sp-runtime = { version = "6.0.0", path = "../../runtime" } +sp-application-crypto = { version = "7.0.0", path = "../" } +sp-core = { version = "7.0.0", default-features = false, path = "../../core" } +sp-keystore = { version = "0.13.0", default-features = false, path = "../../keystore" } +sp-runtime = { version = "7.0.0", path = "../../runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 60eac2247e830..36c86230e96ce 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-arithmetic" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -23,13 +23,13 @@ num-traits = { version = "0.2.8", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } static_assertions = "1.1.0" -sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-debug-derive = { version = "5.0.0", default-features = false, path = "../debug-derive" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [dev-dependencies] criterion = "0.3" primitive-types = "0.12.0" -sp-core = { version = "6.0.0", features = ["full_crypto"], path = "../core" } +sp-core = { version = "7.0.0", features = ["full_crypto"], path = "../core" } rand = "0.7.2" [features] diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index f39e59034dcd0..7be800a2e966c 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] honggfuzz = "0.5.49" num-bigint = "0.4.3" primitive-types = "0.12.0" -sp-arithmetic = { version = "5.0.0", path = ".." } +sp-arithmetic = { version = "6.0.0", path = ".." } [[bin]] name = "biguint" diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index b5491931d19ba..4b450a4da4a88 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -16,9 +16,9 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../application-crypto" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = ["std"] diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index 3a8cb3f37cbd3..49107ebed1db0 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 22e41b5130abb..586f2e4b30084 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -17,16 +17,16 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = serde = { version = "1.0.136", optional = true, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-io = { version = "6.0.0", default-features = false, path = "../io" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../application-crypto" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-io = { version = "7.0.0", default-features = false, path = "../io" } sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../merkle-mountain-range" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [dev-dependencies] array-bytes = "4.1" -sp-keystore = { version = "0.12.0", path = "../keystore" } +sp-keystore = { version = "0.13.0", path = "../keystore" } [features] default = ["std"] diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index a081b56b9d98a..7770a0e210c63 100644 --- a/primitives/block-builder/Cargo.toml +++ b/primitives/block-builder/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 454bc4d7c1103..7f5f22fe09b73 100644 --- a/primitives/blockchain/Cargo.toml +++ b/primitives/blockchain/Cargo.toml @@ -23,5 +23,5 @@ thiserror = "1.0.30" sp-api = { version = "4.0.0-dev", path = "../api" } sp-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sp-database = { version = "4.0.0-dev", path = "../database" } -sp-runtime = { version = "6.0.0", path = "../runtime" } -sp-state-machine = { version = "0.12.0", path = "../state-machine" } +sp-runtime = { version = "7.0.0", path = "../runtime" } +sp-state-machine = { version = "0.13.0", path = "../state-machine" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index 30f5c89650a78..51b20e4fb7e01 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -17,12 +17,12 @@ async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../application-crypto" } sp-consensus = { version = "0.10.0-dev", optional = true, path = "../common" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../std" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../timestamp" } [features] diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 049e511175867..25cb8a2bf64da 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -19,15 +19,15 @@ merlin = { version = "2.0", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../application-crypto" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../application-crypto" } sp-consensus = { version = "0.10.0-dev", optional = true, path = "../common" } sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } sp-consensus-vrf = { version = "0.10.0-dev", default-features = false, path = "../vrf" } -sp-core = { version = "6.0.0", default-features = false, path = "../../core" } +sp-core = { version = "7.0.0", default-features = false, path = "../../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } -sp-keystore = { version = "0.12.0", default-features = false, optional = true, path = "../../keystore" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +sp-keystore = { version = "0.13.0", default-features = false, optional = true, path = "../../keystore" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../std" } sp-timestamp = { version = "4.0.0-dev", optional = true, path = "../../timestamp" } [features] diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index d160cd118998c..6df4e5c7232a8 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -22,11 +22,11 @@ futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" log = "0.4.17" thiserror = "1.0.30" -sp-core = { version = "6.0.0", path = "../../core" } +sp-core = { version = "7.0.0", path = "../../core" } sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } -sp-runtime = { version = "6.0.0", path = "../../runtime" } -sp-state-machine = { version = "0.12.0", path = "../../state-machine" } -sp-std = { version = "4.0.0", path = "../../std" } +sp-runtime = { version = "7.0.0", path = "../../runtime" } +sp-state-machine = { version = "0.13.0", path = "../../state-machine" } +sp-std = { version = "5.0.0", path = "../../std" } sp-version = { version = "5.0.0", path = "../../version" } [dev-dependencies] diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index f909b0b466a71..495372089e195 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -15,9 +15,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-core = { version = "6.0.0", default-features = false, path = "../../core" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../core" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../std" } [features] default = ["std"] diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index a334b10d6586b..a7b941b3f498d 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -16,9 +16,9 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0", features = ["derive"], optional = true } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../arithmetic" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../arithmetic" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../std" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../timestamp" } [features] diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 3209fb230b5aa..7159da2aa1883 100644 --- a/primitives/consensus/vrf/Cargo.toml +++ b/primitives/consensus/vrf/Cargo.toml @@ -16,9 +16,9 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.1.1", default-features = false } schnorrkel = { version = "0.9.1", default-features = false, features = ["preaudit_deprecated", "u64_backend"] } -sp-core = { version = "6.0.0", default-features = false, path = "../../core" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../core" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../std" } [features] default = ["std"] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 3e8bac51289b8..bfec09a13c135 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-core" -version = "6.0.0" +version = "7.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -36,10 +36,10 @@ zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } lazy_static = { version = "1.4.0", default-features = false, optional = true } parking_lot = { version = "0.12.1", optional = true } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } -sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } -sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } +sp-debug-derive = { version = "5.0.0", default-features = false, path = "../debug-derive" } +sp-storage = { version = "7.0.0", default-features = false, path = "../storage" } +sp-externalities = { version = "0.13.0", optional = true, path = "../externalities" } futures = { version = "0.3.21", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.30", optional = true } @@ -57,8 +57,8 @@ libsecp256k1 = { version = "0.7", default-features = false, features = ["static- merlin = { version = "2.0", default-features = false, optional = true } secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"], optional = true } ss58-registry = { version = "1.34.0", default-features = false } -sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } -sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } +sp-core-hashing = { version = "5.0.0", path = "./hashing", default-features = false, optional = true } +sp-runtime-interface = { version = "7.0.0", default-features = false, path = "../runtime-interface" } [dev-dependencies] sp-serializer = { version = "4.0.0-dev", path = "../serializer" } diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index efe38af1602dd..1bb67ffff5142 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-core-hashing" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -19,7 +19,7 @@ digest = { version = "0.10.3", default-features = false } sha2 = { version = "0.10.2", default-features = false } sha3 = { version = "0.10.0", default-features = false } twox-hash = { version = "1.6.3", default-features = false, features = ["digest_0_10"] } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +sp-std = { version = "5.0.0", default-features = false, path = "../../std" } [features] default = ["std"] diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index 8f4f4e0c873ef..6d9747de871c7 100644 --- a/primitives/core/hashing/proc-macro/Cargo.toml +++ b/primitives/core/hashing/proc-macro/Cargo.toml @@ -19,4 +19,4 @@ proc-macro = true proc-macro2 = "1.0.37" quote = "1.0.6" syn = { version = "1.0.98", features = ["full", "parsing"] } -sp-core-hashing = { version = "4.0.0", default-features = false, path = "../" } +sp-core-hashing = { version = "5.0.0", default-features = false, path = "../" } diff --git a/primitives/debug-derive/Cargo.toml b/primitives/debug-derive/Cargo.toml index 50bb0ec65c0ac..a903b704410c2 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-debug-derive" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/externalities/Cargo.toml b/primitives/externalities/Cargo.toml index e84047d5da5ed..c3d32370dc32f 100644 --- a/primitives/externalities/Cargo.toml +++ b/primitives/externalities/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-externalities" -version = "0.12.0" +version = "0.13.0" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2021" @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } environmental = { version = "1.1.3", default-features = false } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } +sp-storage = { version = "7.0.0", default-features = false, path = "../storage" } [features] default = ["std"] diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index 32945eacf0b93..1c8011ff764e3 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -20,11 +20,11 @@ log = { version = "0.4.17", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-keystore = { version = "0.12.0", default-features = false, optional = true, path = "../keystore" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../application-crypto" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-keystore = { version = "0.13.0", default-features = false, optional = true, path = "../keystore" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = ["std"] diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index b176147c053a6..8f6d8aef155ac 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -18,9 +18,9 @@ async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { version = "1.0.30", optional = true } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "6.0.0", optional = true, default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "7.0.0", optional = true, default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [dev-dependencies] futures = "0.3.21" diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 26dec17e032dd..35f0fd9692eaa 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-io" -version = "6.0.0" +version = "7.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -18,16 +18,16 @@ targets = ["x86_64-unknown-linux-gnu"] bytes = { version = "1.1.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.1.3", default-features = false, features = ["bytes"] } hash-db = { version = "0.15.2", default-features = false } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-keystore = { version = "0.12.0", default-features = false, optional = true, path = "../keystore" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-keystore = { version = "0.13.0", default-features = false, optional = true, path = "../keystore" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } libsecp256k1 = { version = "0.7", optional = true } -sp-state-machine = { version = "0.12.0", default-features = false, optional = true, path = "../state-machine" } -sp-wasm-interface = { version = "6.0.0", path = "../wasm-interface", default-features = false } -sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } -sp-trie = { version = "6.0.0", default-features = false, optional = true, path = "../trie" } -sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } -sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } +sp-state-machine = { version = "0.13.0", default-features = false, optional = true, path = "../state-machine" } +sp-wasm-interface = { version = "7.0.0", path = "../wasm-interface", default-features = false } +sp-runtime-interface = { version = "7.0.0", default-features = false, path = "../runtime-interface" } +sp-trie = { version = "7.0.0", default-features = false, optional = true, path = "../trie" } +sp-externalities = { version = "0.13.0", default-features = false, path = "../externalities" } +sp-tracing = { version = "6.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.17", optional = true } futures = { version = "0.3.21", features = ["thread-pool"], optional = true } parking_lot = { version = "0.12.1", optional = true } diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 982abfd09a553..f6c8a8e81e452 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -16,5 +16,5 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] lazy_static = "1.4.0" strum = { version = "0.24.1", features = ["derive"] } -sp-core = { version = "6.0.0", path = "../core" } -sp-runtime = { version = "6.0.0", path = "../runtime" } +sp-core = { version = "7.0.0", path = "../core" } +sp-runtime = { version = "7.0.0", path = "../runtime" } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index cbb8a22ba4dd6..0d5d7ca5637eb 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-keystore" -version = "0.12.0" +version = "0.13.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -21,8 +21,8 @@ parking_lot = { version = "0.12.1", default-features = false } schnorrkel = { version = "0.9.1", default-features = false, features = ["preaudit_deprecated", "u64_backend"] } serde = { version = "1.0", optional = true } thiserror = "1.0" -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-externalities = { version = "0.13.0", default-features = false, path = "../externalities" } [dev-dependencies] rand = "0.7.2" diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index e857974ba898c..7f8b3b6afe5f3 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -17,10 +17,10 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-debug-derive = { version = "5.0.0", default-features = false, path = "../debug-derive" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } thiserror = "1.0" [dev-dependencies] diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index db42199a52984..b99b05e0e3a09 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../arithmetic" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [dev-dependencies] rand = "0.7.3" diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 293a17624820b..860ed6b18810d 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -20,7 +20,7 @@ honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } -sp-runtime = { version = "6.0.0", path = "../../runtime" } +sp-runtime = { version = "7.0.0", path = "../../runtime" } [[bin]] name = "reduce" diff --git a/primitives/offchain/Cargo.toml b/primitives/offchain/Cargo.toml index f21c2fe837110..cb567893776e0 100644 --- a/primitives/offchain/Cargo.toml +++ b/primitives/offchain/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } [features] default = ["std"] diff --git a/primitives/panic-handler/Cargo.toml b/primitives/panic-handler/Cargo.toml index 19f76dddbab22..9da052b4a05e1 100644 --- a/primitives/panic-handler/Cargo.toml +++ b/primitives/panic-handler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-panic-handler" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index f4a4fe12f6c47..ef9fdc544301d 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] rustc-hash = "1.1.0" serde = { version = "1.0.136", features = ["derive"] } -sp-core = { version = "6.0.0", path = "../core" } +sp-core = { version = "7.0.0", path = "../core" } [dev-dependencies] serde_json = "1.0.85" diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index e7f0cee3f140f..09f4b83d68b34 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime-interface" -version = "6.0.0" +version = "7.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -15,22 +15,22 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = { version = "1.1.0", default-features = false } -sp-wasm-interface = { version = "6.0.0", path = "../wasm-interface", default-features = false } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } -sp-runtime-interface-proc-macro = { version = "5.0.0", path = "proc-macro" } -sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } +sp-wasm-interface = { version = "7.0.0", path = "../wasm-interface", default-features = false } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } +sp-tracing = { version = "6.0.0", default-features = false, path = "../tracing" } +sp-runtime-interface-proc-macro = { version = "6.0.0", path = "proc-macro" } +sp-externalities = { version = "0.13.0", default-features = false, path = "../externalities" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["bytes"] } static_assertions = "1.0.0" primitive-types = { version = "0.12.0", default-features = false } -sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } +sp-storage = { version = "7.0.0", default-features = false, path = "../storage" } impl-trait-for-tuples = "0.2.2" [dev-dependencies] sp-runtime-interface-test-wasm = { version = "2.0.0", path = "test-wasm" } -sp-state-machine = { version = "0.12.0", path = "../state-machine" } -sp-core = { version = "6.0.0", path = "../core" } -sp-io = { version = "6.0.0", path = "../io" } +sp-state-machine = { version = "0.13.0", path = "../state-machine" } +sp-core = { version = "7.0.0", path = "../core" } +sp-io = { version = "7.0.0", path = "../io" } rustversion = "1.0.6" trybuild = "1.0.60" diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 6f6b71dc24658..9bc7161012cb1 100644 --- a/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/primitives/runtime-interface/proc-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime-interface-proc-macro" -version = "5.0.0" +version = "6.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 2905cf2c9879e..32d78ec2cee41 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -13,10 +13,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { version = "6.0.0", default-features = false, path = "../../core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../io" } -sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../" } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../io" } +sp-runtime-interface = { version = "7.0.0", default-features = false, path = "../" } +sp-std = { version = "5.0.0", default-features = false, path = "../../std" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index e9b2937227db6..5fb4850af8d9b 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -14,10 +14,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = { version = "1.1.0", default-features = false } -sp-core = { version = "6.0.0", default-features = false, path = "../../core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../io" } -sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../" } -sp-std = { version = "4.0.0", default-features = false, path = "../../std" } +sp-core = { version = "7.0.0", default-features = false, path = "../../core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../io" } +sp-runtime-interface = { version = "7.0.0", default-features = false, path = "../" } +sp-std = { version = "5.0.0", default-features = false, path = "../../std" } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" } diff --git a/primitives/runtime-interface/test/Cargo.toml b/primitives/runtime-interface/test/Cargo.toml index 880d03902b421..4e4522fd93dd2 100644 --- a/primitives/runtime-interface/test/Cargo.toml +++ b/primitives/runtime-interface/test/Cargo.toml @@ -16,9 +16,9 @@ tracing = "0.1.29" tracing-core = "0.1.28" sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-executor-common = { version = "0.10.0-dev", path = "../../../client/executor/common" } -sp-io = { version = "6.0.0", path = "../../io" } -sp-runtime = { version = "6.0.0", path = "../../runtime" } -sp-runtime-interface = { version = "6.0.0", path = "../" } +sp-io = { version = "7.0.0", path = "../../io" } +sp-runtime = { version = "7.0.0", path = "../../runtime" } +sp-runtime-interface = { version = "7.0.0", path = "../" } sp-runtime-interface-test-wasm = { version = "2.0.0", path = "../test-wasm" } sp-runtime-interface-test-wasm-deprecated = { version = "2.0.0", path = "../test-wasm-deprecated" } -sp-state-machine = { version = "0.12.0", path = "../../state-machine" } +sp-state-machine = { version = "0.13.0", path = "../../state-machine" } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 8d7b5b2b93354..578c01583f87c 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-runtime" -version = "6.0.0" +version = "7.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -24,11 +24,11 @@ paste = "1.0" rand = { version = "0.7.2", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-io = { version = "6.0.0", default-features = false, path = "../io" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../application-crypto" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../arithmetic" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-io = { version = "7.0.0", default-features = false, path = "../io" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } sp-weights = { version = "4.0.0", default-features = false, path = "../weights" } [dev-dependencies] @@ -36,8 +36,8 @@ rand = "0.7.2" serde_json = "1.0.85" zstd = { version = "0.11.2", default-features = false } sp-api = { version = "4.0.0-dev", path = "../api" } -sp-state-machine = { version = "0.12.0", path = "../state-machine" } -sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +sp-state-machine = { version = "0.13.0", path = "../state-machine" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index 90b7df105ecde..024fe7209393c 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4", default-features = false } wasmi = { version = "0.13", default-features = false } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-io = { version = "6.0.0", default-features = false, path = "../io" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-wasm-interface = { version = "6.0.0", default-features = false, path = "../wasm-interface" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-io = { version = "7.0.0", default-features = false, path = "../io" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } +sp-wasm-interface = { version = "7.0.0", default-features = false, path = "../wasm-interface" } [dev-dependencies] assert_matches = "1.3.0" diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index fb04b06e75327..94f9e8a23505a 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "6.0.0", optional = true, path = "../runtime" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "7.0.0", optional = true, path = "../runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 7afc13d7c5723..550c1485e992c 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = ["std"] diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 860bca2a9de18..98794db60d30b 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-state-machine" -version = "0.12.0" +version = "0.13.0" authors = ["Parity Technologies "] description = "Substrate State Machine" edition = "2021" @@ -24,17 +24,17 @@ smallvec = "1.8.0" thiserror = { version = "1.0.30", optional = true } tracing = { version = "0.1.29", optional = true } trie-root = { version = "0.17.0", default-features = false } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } -sp-panic-handler = { version = "4.0.0", optional = true, path = "../panic-handler" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-trie = { version = "6.0.0", default-features = false, path = "../trie" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-externalities = { version = "0.13.0", default-features = false, path = "../externalities" } +sp-panic-handler = { version = "5.0.0", optional = true, path = "../panic-handler" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } +sp-trie = { version = "7.0.0", default-features = false, path = "../trie" } [dev-dependencies] array-bytes = "4.1" pretty_assertions = "1.2.1" rand = "0.7.2" -sp-runtime = { version = "6.0.0", path = "../runtime" } +sp-runtime = { version = "7.0.0", path = "../runtime" } trie-db = "0.24.0" assert_matches = "1.5" diff --git a/primitives/std/Cargo.toml b/primitives/std/Cargo.toml index e4a6a9f6a614f..87ab1a46d8777 100644 --- a/primitives/std/Cargo.toml +++ b/primitives/std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-std" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index d04a88d129d34..eb166ee3730ff 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-storage" -version = "6.0.0" +version = "7.0.0" authors = ["Parity Technologies "] edition = "2021" description = "Storage related primitives" @@ -18,8 +18,8 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = impl-serde = { version = "0.4.0", optional = true } ref-cast = "1.0.0" serde = { version = "1.0.136", features = ["derive"], optional = true } -sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-debug-derive = { version = "5.0.0", default-features = false, path = "../debug-derive" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 28fa6e6213daf..6cfd17afcc5fd 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -15,9 +15,9 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../application-crypto" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } [features] default = [ diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 2e8f281cd7c7b..72266a48b0d6c 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -20,8 +20,8 @@ log = { version = "0.4.17", optional = true } thiserror = { version = "1.0.30", optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index c2ca57d2b5a43..794785085c8b4 100644 --- a/primitives/tracing/Cargo.toml +++ b/primitives/tracing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-tracing" -version = "5.0.0" +version = "6.0.0" license = "Apache-2.0" authors = ["Parity Technologies "] edition = "2021" @@ -18,7 +18,7 @@ features = ["with-tracing"] targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] [dependencies] -sp-std = { version = "4.0.0", path = "../std", default-features = false } +sp-std = { version = "5.0.0", path = "../std", default-features = false } codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = [ "derive", ] } diff --git a/primitives/transaction-pool/Cargo.toml b/primitives/transaction-pool/Cargo.toml index 544b149ce3a48..63b34a10cd09f 100644 --- a/primitives/transaction-pool/Cargo.toml +++ b/primitives/transaction-pool/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } [features] default = [ "std" ] diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index e916462675435..ea6419dfaa1ba 100644 --- a/primitives/transaction-storage-proof/Cargo.toml +++ b/primitives/transaction-storage-proof/Cargo.toml @@ -17,11 +17,11 @@ async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -sp-core = { version = "6.0.0", optional = true, path = "../core" } +sp-core = { version = "7.0.0", optional = true, path = "../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } -sp-trie = { version = "6.0.0", optional = true, path = "../trie" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } +sp-trie = { version = "7.0.0", optional = true, path = "../trie" } [features] default = [ "std" ] diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 211e071c073af..67839a157a02b 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-trie" -version = "6.0.0" +version = "7.0.0" authors = ["Parity Technologies "] description = "Patricia trie stuff using a parity-scale-codec node format" repository = "https://github.com/paritytech/substrate/" @@ -32,15 +32,15 @@ thiserror = { version = "1.0.30", optional = true } tracing = { version = "0.1.29", optional = true } trie-db = { version = "0.24.0", default-features = false } trie-root = { version = "0.17.0", default-features = false } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [dev-dependencies] array-bytes = "4.1" criterion = "0.3.3" trie-bench = "0.32.0" trie-standardmap = "0.15.2" -sp-runtime = { version = "6.0.0", path = "../runtime" } +sp-runtime = { version = "7.0.0", path = "../runtime" } [features] default = ["std"] diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 0dcbbd81fd93f..56fabcd566475 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -21,8 +21,8 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" serde = { version = "1.0.136", features = ["derive"], optional = true } thiserror = { version = "1.0.30", optional = true } sp-core-hashing-proc-macro = { version = "5.0.0", path = "../core/hashing/proc-macro" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } sp-version-proc-macro = { version = "4.0.0-dev", default-features = false, path = "proc-macro" } [features] diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index d61c74f20222c..2e997ef4a2add 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-wasm-interface" -version = "6.0.0" +version = "7.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -19,7 +19,7 @@ impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } wasmi = { version = "0.13", optional = true } wasmtime = { version = "1.0.0", default-features = false, optional = true } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] diff --git a/primitives/weights/Cargo.toml b/primitives/weights/Cargo.toml index 8c0302ff5d1b2..501a2c3b0a19d 100644 --- a/primitives/weights/Cargo.toml +++ b/primitives/weights/Cargo.toml @@ -19,10 +19,10 @@ impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } smallvec = "1.8.0" -sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } -sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } -sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../arithmetic" } +sp-core = { version = "7.0.0", default-features = false, path = "../core" } +sp-debug-derive = { version = "5.0.0", default-features = false, path = "../debug-derive" } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index fcac37441ba98..9a6428798c70f 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -30,8 +30,8 @@ sc-service = { version = "0.10.0-dev", default-features = false, features = [ ], path = "../../client/service" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } -sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } -sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../primitives/state-machine" } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 698351cd69f64..0e40f23473a8e 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy" } beefy-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "../../frame/beefy-mmr/primitives" } -sp-application-crypto = { version = "6.0.0", default-features = false, path = "../../primitives/application-crypto" } +sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } @@ -25,27 +25,27 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } memory-db = { version = "0.30.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } -sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../../primitives/runtime-interface" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime-interface = { version = "7.0.0", default-features = false, path = "../../primitives/runtime-interface" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../frame/support" } sp-version = { version = "5.0.0", default-features = false, path = "../../primitives/version" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../frame/babe" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../frame/system" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../frame/system/rpc/runtime-api" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../frame/timestamp" } sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/finality-grandpa" } -sp-trie = { version = "6.0.0", default-features = false, path = "../../primitives/trie" } +sp-trie = { version = "7.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } trie-db = { version = "0.24.0", default-features = false } parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } -sp-state-machine = { version = "0.12.0", default-features = false, path = "../../primitives/state-machine" } -sp-externalities = { version = "0.12.0", default-features = false, path = "../../primitives/externalities" } +sp-state-machine = { version = "0.13.0", default-features = false, path = "../../primitives/state-machine" } +sp-externalities = { version = "0.13.0", default-features = false, path = "../../primitives/externalities" } # 3rd party cfg-if = "1.0" diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index 3a3cfcbe33add..2ac944edc637f 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -20,7 +20,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } substrate-test-client = { version = "2.0.0", path = "../../client" } substrate-test-runtime = { version = "2.0.0", path = "../../runtime" } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index fa6dde5b5b57e..f5cba2b99be56 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -19,5 +19,5 @@ thiserror = "1.0" sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../client" } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index a2d548f1fa5cd..1b38f0295f8bb 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -47,16 +47,16 @@ sc-service = { version = "0.10.0-dev", default-features = false, path = "../../. sc-sysinfo = { version = "6.0.0-dev", path = "../../../client/sysinfo" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-database = { version = "4.0.0-dev", path = "../../../primitives/database" } -sp-externalities = { version = "0.12.0", path = "../../../primitives/externalities" } +sp-externalities = { version = "0.13.0", path = "../../../primitives/externalities" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-keystore = { version = "0.12.0", path = "../../../primitives/keystore" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machine" } -sp-std = { version = "4.0.0", path = "../../../primitives/std" } -sp-storage = { version = "6.0.0", path = "../../../primitives/storage" } -sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } +sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../../primitives/state-machine" } +sp-std = { version = "5.0.0", path = "../../../primitives/std" } +sp-storage = { version = "7.0.0", path = "../../../primitives/storage" } +sp-trie = { version = "7.0.0", path = "../../../primitives/trie" } gethostname = "0.2.3" [features] diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index 89e9ee79db214..26e07c79d8f81 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -15,8 +15,8 @@ clap = { version = "4.0.9", features = ["derive"] } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [features] default = [] diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index b8ad97cc6b6fa..0f3ff31756bba 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -17,7 +17,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-staking = { version = "4.0.0-dev", path = "../../../frame/staking" } # primitives -sp-io = { version = "6.0.0", path = "../../../primitives/io" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } # third party chrono = { version = "0.4.19" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 3d7471bf4d680..e329b7f3f2c58 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -19,9 +19,9 @@ log = "0.4.17" serde = "1.0.136" serde_json = "1.0" frame-support = { version = "4.0.0-dev", optional = true, path = "../../../frame/support" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-io = { version = "6.0.0", path = "../../../primitives/io" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } +sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-version = { version = "5.0.0", path = "../../../primitives/version" } substrate-rpc-client = { path = "../rpc/client" } diff --git a/utils/frame/rpc/client/Cargo.toml b/utils/frame/rpc/client/Cargo.toml index 80aa60f199f1f..78134a79bd0de 100644 --- a/utils/frame/rpc/client/Cargo.toml +++ b/utils/frame/rpc/client/Cargo.toml @@ -17,9 +17,9 @@ jsonrpsee = { version = "0.15.1", features = ["ws-client"] } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } async-trait = "0.1.57" serde = "1" -sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } log = "0.4" [dev-dependencies] tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread", "sync"] } -sp-core = { path = "../../../../primitives/core" } \ No newline at end of file +sp-core = { path = "../../../../primitives/core" } diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index d45e502df276c..4886563a99440 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -30,7 +30,7 @@ jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } # Substrate Dependencies sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } -sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] serde_json = "1" diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 38e40a33d9c7f..5b781c72056a2 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -21,12 +21,12 @@ jsonrpsee = { version = "0.15.1", features = ["jsonrpsee-types"] } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } -sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } +sp-storage = { version = "7.0.0", path = "../../../../primitives/storage" } [dev-dependencies] scale-info = "2.1.1" jsonrpsee = { version = "0.15.1", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.17.0" -sp-core = { version = "6.0.0", path = "../../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 5d8984e8d399b..ddc52ffe56a53 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -25,12 +25,12 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../../client/tr sp-api = { version = "4.0.0-dev", path = "../../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", path = "../../../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../../../primitives/core" } -sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] sc-transaction-pool = { version = "4.0.0-dev", path = "../../../../client/transaction-pool" } tokio = "1.17.0" assert_matches = "1.3.0" -sp-tracing = { version = "5.0.0", path = "../../../../primitives/tracing" } +sp-tracing = { version = "6.0.0", path = "../../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index c7191b7eb7f5f..725e3d565efbb 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -23,12 +23,12 @@ sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../../client/service" } -sp-core = { version = "6.0.0", path = "../../../../primitives/core" } -sp-externalities = { version = "0.12.0", path = "../../../../primitives/externalities" } -sp-io = { version = "6.0.0", path = "../../../../primitives/io" } -sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } -sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } -sp-state-machine = { version = "0.12.0", path = "../../../../primitives/state-machine" } +sp-core = { version = "7.0.0", path = "../../../../primitives/core" } +sp-externalities = { version = "0.13.0", path = "../../../../primitives/externalities" } +sp-io = { version = "7.0.0", path = "../../../../primitives/io" } +sp-keystore = { version = "0.13.0", path = "../../../../primitives/keystore" } +sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } +sp-state-machine = { version = "0.13.0", path = "../../../../primitives/state-machine" } sp-version = { version = "5.0.0", path = "../../../../primitives/version" } sp-weights = { version = "4.0.0", path = "../../../../primitives/weights" } frame-try-runtime = { optional = true, path = "../../../../frame/try-runtime" } From 38f473b84742d87d078b08a9614b40969bb7c7ec Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 16 Nov 2022 10:07:56 +0000 Subject: [PATCH 1386/1472] Release `sp-keyring` and `pallet-contracts-primitives` `7.0.0` (#12716) * Bump sp-keyring * Bump pallet-contracts-primitives * Cargo.lock --- Cargo.lock | 4 ++-- bin/node-template/node/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 2 +- bin/node/testing/Cargo.toml | 2 +- client/beefy/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/Cargo.toml | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/primitives/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- primitives/keyring/Cargo.toml | 2 +- test-utils/client/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- 20 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 962d5f3adbe32..a22cfa8ba8dd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5326,7 +5326,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" -version = "6.0.0" +version = "7.0.0" dependencies = [ "bitflags", "parity-scale-codec", @@ -9675,7 +9675,7 @@ dependencies = [ [[package]] name = "sp-keyring" -version = "6.0.0" +version = "7.0.0" dependencies = [ "lazy_static", "sp-core", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 69bf228f9ef75..16f87470dbc17 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -37,7 +37,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 9bec0e89195c9..b8cc63b991535 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -53,7 +53,7 @@ sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } -sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../../primitives/transaction-pool" } diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 9961f23367dfa..2830683ae8321 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -42,7 +42,7 @@ sp-application-crypto = { version = "7.0.0", path = "../../../primitives/applica pallet-root-testing = { version = "1.0.0-dev", path = "../../../frame/root-testing" } sp-consensus-babe = { version = "0.10.0-dev", path = "../../../primitives/consensus/babe" } sp-externalities = { version = "0.13.0", path = "../../../primitives/externalities" } -sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [features] diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 70660b9cee499..dcc59ce750934 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -61,7 +61,7 @@ pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../ pallet-child-bounties = { version = "4.0.0-dev", default-features = false, path = "../../../frame/child-bounties" } pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../../../frame/collective" } pallet-contracts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts" } -pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../../frame/contracts/primitives/" } +pallet-contracts-primitives = { version = "7.0.0", default-features = false, path = "../../../frame/contracts/primitives/" } pallet-conviction-voting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/conviction-voting" } pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" } pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index cf4d3b11d8df8..0fd236847c9e2 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -42,7 +42,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/c sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-io = { version = "7.0.0", path = "../../../primitives/io" } -sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/timestamp" } substrate-test-client = { version = "2.0.0", path = "../../../test-utils/client" } diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 8b6a1336195ba..999c5a298fe57 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -48,6 +48,6 @@ tokio = "1.17.0" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-network-test = { version = "0.8.0", path = "../network/test" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } -sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../primitives/keyring" } sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index f1d0a04205dbb..50025d591e19c 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -41,7 +41,7 @@ sc-tracing = { version = "4.0.0-dev", path = "../tracing" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "7.0.0", path = "../../primitives/core" } -sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../primitives/keyring" } sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } sp-panic-handler = { version = "5.0.0", path = "../../primitives/panic-handler" } sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index eb144a19fca9c..27faa40909713 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -42,7 +42,7 @@ tempfile = "3.1.0" sc-keystore = { version = "4.0.0-dev", path = "../../keystore" } sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } -sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index bbe2e43eb6982..01d7d897b4ba4 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -52,7 +52,7 @@ sp-version = { version = "5.0.0", path = "../../../primitives/version" } [dev-dependencies] rand_chacha = "0.2.2" sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } -sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } sc-network = { version = "0.10.0-dev", path = "../../network" } sc-network-test = { version = "0.8.0", path = "../../network/test" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 0f937693488d1..8e76b14005063 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -35,5 +35,5 @@ tempfile = "3.1.0" tokio = "1.17.0" sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } -sp-keyring = { version = "6.0.0", path = "../../../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index a95e3e8da467c..b14d40659783b 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -56,6 +56,6 @@ serde = "1.0.136" tokio = "1.17.0" sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-test = { version = "0.8.0", path = "../network/test" } -sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../primitives/keyring" } sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 06d3e8a304153..2d8a527ccef85 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -32,6 +32,6 @@ sc-rpc = { version = "4.0.0-dev", features = [ ], path = "../../rpc" } sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } -sp-keyring = { version = "6.0.0", path = "../../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } tokio = { version = "1.17.0", features = ["macros"] } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index a4dfe308be249..6c892a00f5323 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -36,7 +36,7 @@ rand_pcg = { version = "0.3", optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "primitives" } +pallet-contracts-primitives = { version = "7.0.0", default-features = false, path = "primitives" } pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/contracts/primitives/Cargo.toml b/frame/contracts/primitives/Cargo.toml index 835970a5e5294..d0c3a34ddfccb 100644 --- a/frame/contracts/primitives/Cargo.toml +++ b/frame/contracts/primitives/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-contracts-primitives" -version = "6.0.0" +version = "7.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 8da4fe61fcb75..5a85a3682db82 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -39,7 +39,7 @@ pallet-offences = { version = "4.0.0-dev", path = "../offences" } pallet-staking = { version = "4.0.0-dev", path = "../staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } -sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../primitives/keyring" } [features] default = ["std"] diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index 2431487cdb824..b3afa397c45f5 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -20,7 +20,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } -sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } +sp-keyring = { version = "7.0.0", optional = true, path = "../../primitives/keyring" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index f6c8a8e81e452..0646dde4f077a 100644 --- a/primitives/keyring/Cargo.toml +++ b/primitives/keyring/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-keyring" -version = "6.0.0" +version = "7.0.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 9a6428798c70f..2c61f4d3ce2ed 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -31,7 +31,7 @@ sc-service = { version = "0.10.0-dev", default-features = false, features = [ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-core = { version = "7.0.0", path = "../../primitives/core" } -sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +sp-keyring = { version = "7.0.0", path = "../../primitives/keyring" } sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } sp-state-machine = { version = "0.13.0", path = "../../primitives/state-machine" } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 0e40f23473a8e..b64a847b15943 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -22,7 +22,7 @@ sp-block-builder = { version = "4.0.0-dev", default-features = false, path = ".. codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } -sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } +sp-keyring = { version = "7.0.0", optional = true, path = "../../primitives/keyring" } memory-db = { version = "0.30.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } From b8ba481ad9331050634e471ddc428911182d63e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Wed, 16 Nov 2022 08:26:11 -0300 Subject: [PATCH 1387/1472] Fix `cargo check` for `pallet-contracts-proc-macro` (#12706) * fix `cargo check` for pallet-contracts-proc-macro * add test for cargo-check of pallet-contracts-proc-macro * remove cargo-check-contracts-proc-macro https://github.com/paritytech/substrate/pull/12706/files#r1022783937 --- frame/contracts/proc-macro/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/contracts/proc-macro/Cargo.toml b/frame/contracts/proc-macro/Cargo.toml index aca1d86ac24a1..08dafcc6a8fca 100644 --- a/frame/contracts/proc-macro/Cargo.toml +++ b/frame/contracts/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] proc-macro2 = "1" quote = "1" -syn = "1.0.98" +syn = { version = "1.0.98", features = ["full"] } [dev-dependencies] From 06998809eb270c4972e26f4934130758da94db3a Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 16 Nov 2022 14:48:58 +0100 Subject: [PATCH 1388/1472] [ci] Improve pipeline stopper (#12717) * [ci] Improve pipeline stopper * break test-linux-stable 1/3 * break test-linux-stable 2/3 * break test-linux-stable 3/3 * break cargo-check-benches 1/2 * break cargo-check-benches 2/2 * fix benches --- .gitlab-ci.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 75a1d54776eb6..d4b98db13b77b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -280,6 +280,22 @@ rusty-cachier-notify: PR_NUM: "${PR_NUM}" trigger: project: "parity/infrastructure/ci_cd/pipeline-stopper" + branch: "as-improve" + +remove-cancel-pipeline-message: + stage: .post + rules: + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + variables: + PROJECT_ID: "${CI_PROJECT_ID}" + PROJECT_NAME: "${CI_PROJECT_NAME}" + PIPELINE_ID: "${CI_PIPELINE_ID}" + FAILED_JOB_URL: "https://gitlab.com" + FAILED_JOB_NAME: "nope" + PR_NUM: "${CI_COMMIT_REF_NAME}" + trigger: + project: "parity/infrastructure/ci_cd/pipeline-stopper" + branch: "as-improve" # need to copy jobs this way because otherwise gitlab will wait # for all 3 jobs to finish instead of cancelling if one fails From a7ba55d3c54b9957c242f659e02f5b5a0f47b3ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 16 Nov 2022 16:55:08 +0100 Subject: [PATCH 1389/1472] sc-chainspec: Switch to `assimilate_storage` (#12720) Before it was using `build_storage` and `assimilate_storage` was returning an error. However, there was no real reason for `assimilate_storage` to return an error. This pr implements `assimilate_storage` and uses the default `build_storage` of the trait. --- client/chain-spec/src/chain_spec.rs | 37 ++++++++++++----------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 2cc9f356e4df7..0b951200b069a 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -109,35 +109,28 @@ impl GenesisSource { } impl BuildStorage for ChainSpec { - fn build_storage(&self) -> Result { + fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { match self.genesis.resolve()? { - Genesis::Runtime(gc) => gc.build_storage(), - Genesis::Raw(RawGenesis { top: map, children_default: children_map }) => Ok(Storage { - top: map.into_iter().map(|(k, v)| (k.0, v.0)).collect(), - children_default: children_map - .into_iter() - .map(|(storage_key, child_content)| { - let child_info = ChildInfo::new_default(storage_key.0.as_slice()); - ( - storage_key.0, - StorageChild { - data: child_content.into_iter().map(|(k, v)| (k.0, v.0)).collect(), - child_info, - }, - ) - }) - .collect(), - }), + Genesis::Runtime(gc) => gc.assimilate_storage(storage), + Genesis::Raw(RawGenesis { top: map, children_default: children_map }) => { + storage.top.extend(map.into_iter().map(|(k, v)| (k.0, v.0))); + children_map.into_iter().for_each(|(k, v)| { + let child_info = ChildInfo::new_default(k.0.as_slice()); + storage + .children_default + .entry(k.0) + .or_insert_with(|| StorageChild { data: Default::default(), child_info }) + .data + .extend(v.into_iter().map(|(k, v)| (k.0, v.0))); + }); + Ok(()) + }, // The `StateRootHash` variant exists as a way to keep note that other clients support // it, but Substrate itself isn't capable of loading chain specs with just a hash at the // moment. Genesis::StateRootHash(_) => Err("Genesis storage in hash format not supported".into()), } } - - fn assimilate_storage(&self, _: &mut Storage) -> Result<(), String> { - Err("`assimilate_storage` not implemented for `ChainSpec`.".into()) - } } pub type GenesisStorage = BTreeMap; From 35170c550e8088136bbe56717396c3dbbcbf8183 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Thu, 17 Nov 2022 13:19:34 +0100 Subject: [PATCH 1390/1472] [Cleanup] Remove obsolete event from fast-unstake (#12725) Trivial, just removing unused code. --- frame/fast-unstake/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index c83054189feb7..f94ff8f6c9514 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -166,9 +166,6 @@ pub mod pallet { Unstaked { stash: T::AccountId, result: DispatchResult }, /// A staker was slashed for requesting fast-unstake whilst being exposed. Slashed { stash: T::AccountId, amount: BalanceOf }, - /// Some internal error happened while migrating stash. They are removed as head as a - /// consequence. - Errored { stash: T::AccountId }, /// An internal error happened. Operations will be paused now. InternalError, /// A batch was partially checked for the given eras, but the process did not finish. From 4baabe418a585277d30e698fe49f284ac5295d84 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Thu, 17 Nov 2022 16:33:39 +0100 Subject: [PATCH 1391/1472] [Fix] Deposit for fast-unstake has to be define as pallet::constant (#12729) Fixes https://github.com/paritytech/substrate/issues/12618 --- frame/fast-unstake/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index f94ff8f6c9514..618afa63c2c4c 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -122,6 +122,7 @@ pub mod pallet { /// Deposit to take for unstaking, to make sure we're able to slash the it in order to cover /// the costs of resources on unsuccessful unstake. + #[pallet::constant] type Deposit: Get>; /// The origin that can control this pallet. From 0dc5358e43187a1f54afb2455d42eddb0965c16a Mon Sep 17 00:00:00 2001 From: Nate Armstrong <109548806+elv-nate@users.noreply.github.com> Date: Thu, 17 Nov 2022 07:55:56 -0800 Subject: [PATCH 1392/1472] Add event testing example to pallet template (#12722) Add an example of how to test for events into the example pallet. Right now, the information is pretty hard to find without looking into pallet tests or finding some particular posts on the stackoverflow. --- bin/node-template/pallets/template/src/tests.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/node-template/pallets/template/src/tests.rs b/bin/node-template/pallets/template/src/tests.rs index 527aec8ed00c0..7c2b853ee4dc5 100644 --- a/bin/node-template/pallets/template/src/tests.rs +++ b/bin/node-template/pallets/template/src/tests.rs @@ -1,13 +1,17 @@ -use crate::{mock::*, Error}; +use crate::{mock::*, Error, Event}; use frame_support::{assert_noop, assert_ok}; #[test] fn it_works_for_default_value() { new_test_ext().execute_with(|| { + // Go past genesis block so events get deposited + System::set_block_number(1); // Dispatch a signed extrinsic. assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); // Read pallet storage and assert an expected result. assert_eq!(TemplateModule::something(), Some(42)); + // Assert that the correct event was deposited + System::assert_last_event(Event::SomethingStored { something: 42, who: 1 }.into()); }); } From a73a35eaf917f26612f56395325017576ac7ce0f Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 18 Nov 2022 22:21:44 +0900 Subject: [PATCH 1393/1472] Remove the `wasmtime` feature flag (#12684) * Remove the `wasmtime` feature flag * rustfmt --- bin/node-template/node/Cargo.toml | 6 +- bin/node/cli/Cargo.toml | 5 -- bin/node/executor/Cargo.toml | 1 - bin/node/executor/benches/bench.rs | 8 +-- bin/node/testing/Cargo.toml | 4 +- client/cli/Cargo.toml | 3 +- client/cli/src/arg_enums.rs | 61 ++----------------- client/executor/Cargo.toml | 3 +- client/executor/benches/bench.rs | 15 +---- .../executor/src/integration_tests/linux.rs | 5 -- client/executor/src/integration_tests/mod.rs | 22 +------ client/executor/src/lib.rs | 2 - client/executor/src/wasm_runtime.rs | 2 - client/executor/wasmtime/Cargo.toml | 2 +- client/service/Cargo.toml | 1 - client/service/src/config.rs | 4 +- primitives/wasm-interface/Cargo.toml | 2 +- 17 files changed, 20 insertions(+), 126 deletions(-) diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 16f87470dbc17..469c939da4e83 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -19,10 +19,10 @@ name = "node-template" [dependencies] clap = { version = "4.0.9", features = ["derive"] } -sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } +sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sp-core = { version = "7.0.0", path = "../../../primitives/core" } -sc-executor = { version = "0.10.0-dev", path = "../../../client/executor", features = ["wasmtime"] } -sc-service = { version = "0.10.0-dev", path = "../../../client/service", features = ["wasmtime"] } +sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } +sc-service = { version = "0.10.0-dev", path = "../../../client/service" } sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index b8cc63b991535..d56764f9e2040 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -101,11 +101,6 @@ try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../ut serde_json = "1.0.85" [target.'cfg(any(target_arch="x86_64", target_arch="aarch64"))'.dependencies] -node-executor = { version = "3.0.0-dev", path = "../executor", features = ["wasmtime"] } -sc-cli = { version = "0.10.0-dev", optional = true, path = "../../../client/cli", features = ["wasmtime"] } -sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service", features = [ - "wasmtime", -] } sp-trie = { version = "7.0.0", default-features = false, path = "../../../primitives/trie", features = [ "memory-tracker", ] } diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 2830683ae8321..c814813d0ac1b 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -46,7 +46,6 @@ sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [features] -wasmtime = ["sc-executor/wasmtime"] stress-test = [] [[bench]] diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index 850be3e3c6281..4cbd95471b86b 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -25,9 +25,10 @@ use kitchensink_runtime::{ use node_executor::ExecutorDispatch; use node_primitives::{BlockNumber, Hash}; use node_testing::keyring::*; -#[cfg(feature = "wasmtime")] -use sc_executor::WasmtimeInstantiationStrategy; -use sc_executor::{Externalities, NativeElseWasmExecutor, RuntimeVersionOf, WasmExecutionMethod}; +use sc_executor::{ + Externalities, NativeElseWasmExecutor, RuntimeVersionOf, WasmExecutionMethod, + WasmtimeInstantiationStrategy, +}; use sp_core::{ storage::well_known_keys, traits::{CodeExecutor, RuntimeCode}, @@ -161,7 +162,6 @@ fn bench_execute_block(c: &mut Criterion) { let execution_methods = vec![ ExecutionMethod::Native, ExecutionMethod::Wasm(WasmExecutionMethod::Interpreted), - #[cfg(feature = "wasmtime")] ExecutionMethod::Wasm(WasmExecutionMethod::Compiled { instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, }), diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 0fd236847c9e2..a2b34cf59b120 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -28,9 +28,7 @@ sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-build sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-client-db = { version = "0.10.0-dev", features = ["rocksdb"], path = "../../../client/db" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -sc-executor = { version = "0.10.0-dev", features = [ - "wasmtime", -], path = "../../../client/executor" } +sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" } sc-service = { version = "0.10.0-dev", features = [ "test-helpers", "rocksdb", diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 50025d591e19c..dfb6d5c34c37c 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -51,6 +51,5 @@ sp-version = { version = "5.0.0", path = "../../primitives/version" } tempfile = "3.1.0" [features] -default = ["rocksdb", "wasmtime"] +default = ["rocksdb"] rocksdb = ["sc-client-db/rocksdb"] -wasmtime = ["sc-service/wasmtime"] diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index d761c854a6f0d..20f68bc7fb55e 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -18,7 +18,7 @@ //! Definitions of [`ValueEnum`] types. -use clap::{builder::PossibleValue, ValueEnum}; +use clap::ValueEnum; /// The instantiation strategy to use in compiled mode. #[derive(Debug, Clone, Copy, ValueEnum)] @@ -51,59 +51,16 @@ pub const DEFAULT_WASMTIME_INSTANTIATION_STRATEGY: WasmtimeInstantiationStrategy WasmtimeInstantiationStrategy::PoolingCopyOnWrite; /// How to execute Wasm runtime code. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum WasmExecutionMethod { /// Uses an interpreter. + #[clap(name = "interpreted-i-know-what-i-do")] Interpreted, /// Uses a compiled runtime. Compiled, } -const INTERPRETED_NAME: &str = "interpreted-i-know-what-i-do"; - -impl clap::ValueEnum for WasmExecutionMethod { - /// All possible argument values, in display order. - fn value_variants<'a>() -> &'a [Self] { - let variants = &[Self::Interpreted, Self::Compiled]; - if cfg!(feature = "wasmtime") { - variants - } else { - &variants[..1] - } - } - - /// Parse an argument into `Self`. - fn from_str(s: &str, _: bool) -> Result { - if s.eq_ignore_ascii_case(INTERPRETED_NAME) { - Ok(Self::Interpreted) - } else if s.eq_ignore_ascii_case("compiled") { - #[cfg(feature = "wasmtime")] - { - Ok(Self::Compiled) - } - #[cfg(not(feature = "wasmtime"))] - { - Err("`Compiled` variant requires the `wasmtime` feature to be enabled".into()) - } - } else { - Err(format!("Unknown variant `{}`", s)) - } - } - - /// The canonical argument value. - /// - /// The value is `None` for skipped variants. - fn to_possible_value(&self) -> Option { - match self { - #[cfg(feature = "wasmtime")] - WasmExecutionMethod::Compiled => Some(PossibleValue::new("compiled")), - #[cfg(not(feature = "wasmtime"))] - WasmExecutionMethod::Compiled => None, - WasmExecutionMethod::Interpreted => Some(PossibleValue::new(INTERPRETED_NAME)), - } - } -} - impl std::fmt::Display for WasmExecutionMethod { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -121,7 +78,6 @@ pub fn execution_method_from_cli( ) -> sc_service::config::WasmExecutionMethod { match execution_method { WasmExecutionMethod::Interpreted => sc_service::config::WasmExecutionMethod::Interpreted, - #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled => sc_service::config::WasmExecutionMethod::Compiled { instantiation_strategy: match _instantiation_strategy { WasmtimeInstantiationStrategy::PoolingCopyOnWrite => @@ -136,21 +92,12 @@ pub fn execution_method_from_cli( sc_service::config::WasmtimeInstantiationStrategy::LegacyInstanceReuse, }, }, - #[cfg(not(feature = "wasmtime"))] - WasmExecutionMethod::Compiled => panic!( - "Substrate must be compiled with \"wasmtime\" feature for compiled Wasm execution" - ), } } /// The default [`WasmExecutionMethod`]. -#[cfg(feature = "wasmtime")] pub const DEFAULT_WASM_EXECUTION_METHOD: WasmExecutionMethod = WasmExecutionMethod::Compiled; -/// The default [`WasmExecutionMethod`]. -#[cfg(not(feature = "wasmtime"))] -pub const DEFAULT_WASM_EXECUTION_METHOD: WasmExecutionMethod = WasmExecutionMethod::Interpreted; - #[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] #[value(rename_all = "kebab-case")] diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index b84529d2a80d8..7cba725a9ea45 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -23,7 +23,7 @@ wasmi = "0.13" codec = { package = "parity-scale-codec", version = "3.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "common" } sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } -sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true } +sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } @@ -61,5 +61,4 @@ default = ["std"] # This crate does not have `no_std` support, we just require this for tests std = [] wasm-extern-trace = [] -wasmtime = ["sc-executor-wasmtime"] wasmer-sandbox = ["sc-executor-common/wasmer-sandbox"] diff --git a/client/executor/benches/bench.rs b/client/executor/benches/bench.rs index fcefe408603d7..a282cdfbdd334 100644 --- a/client/executor/benches/bench.rs +++ b/client/executor/benches/bench.rs @@ -23,7 +23,6 @@ use sc_executor_common::{ runtime_blob::RuntimeBlob, wasm_runtime::{WasmInstance, WasmModule}, }; -#[cfg(feature = "wasmtime")] use sc_executor_wasmtime::InstantiationStrategy; use sc_runtime_test::wasm_binary_unwrap as test_runtime; use sp_wasm_interface::HostFunctions as _; @@ -35,11 +34,7 @@ use std::sync::{ #[derive(Clone)] enum Method { Interpreted, - #[cfg(feature = "wasmtime")] - Compiled { - instantiation_strategy: InstantiationStrategy, - precompile: bool, - }, + Compiled { instantiation_strategy: InstantiationStrategy, precompile: bool }, } // This is just a bog-standard Kusama runtime with an extra @@ -67,7 +62,6 @@ fn initialize( allow_missing_func_imports, ) .map(|runtime| -> Arc { Arc::new(runtime) }), - #[cfg(feature = "wasmtime")] Method::Compiled { instantiation_strategy, precompile } => { let config = sc_executor_wasmtime::Config { allow_missing_func_imports, @@ -163,7 +157,6 @@ fn bench_call_instance(c: &mut Criterion) { let _ = env_logger::try_init(); let strategies = [ - #[cfg(feature = "wasmtime")] ( "legacy_instance_reuse", Method::Compiled { @@ -171,7 +164,6 @@ fn bench_call_instance(c: &mut Criterion) { precompile: false, }, ), - #[cfg(feature = "wasmtime")] ( "recreate_instance_vanilla", Method::Compiled { @@ -179,7 +171,6 @@ fn bench_call_instance(c: &mut Criterion) { precompile: false, }, ), - #[cfg(feature = "wasmtime")] ( "recreate_instance_cow_fresh", Method::Compiled { @@ -187,7 +178,6 @@ fn bench_call_instance(c: &mut Criterion) { precompile: false, }, ), - #[cfg(feature = "wasmtime")] ( "recreate_instance_cow_precompiled", Method::Compiled { @@ -195,7 +185,6 @@ fn bench_call_instance(c: &mut Criterion) { precompile: true, }, ), - #[cfg(feature = "wasmtime")] ( "pooling_vanilla", Method::Compiled { @@ -203,7 +192,6 @@ fn bench_call_instance(c: &mut Criterion) { precompile: false, }, ), - #[cfg(feature = "wasmtime")] ( "pooling_cow_fresh", Method::Compiled { @@ -211,7 +199,6 @@ fn bench_call_instance(c: &mut Criterion) { precompile: false, }, ), - #[cfg(feature = "wasmtime")] ( "pooling_cow_precompiled", Method::Compiled { diff --git a/client/executor/src/integration_tests/linux.rs b/client/executor/src/integration_tests/linux.rs index 60e537299186e..efac4e74bb8e2 100644 --- a/client/executor/src/integration_tests/linux.rs +++ b/client/executor/src/integration_tests/linux.rs @@ -18,11 +18,6 @@ //! Tests that are only relevant for Linux. -// Constrain this only to wasmtime for the time being. Without this rustc will complain on unused -// imports and items. The alternative is to plop `cfg(feature = wasmtime)` everywhere which seems -// borthersome. -#![cfg(feature = "wasmtime")] - use super::mk_test_runtime; use crate::WasmExecutionMethod; use codec::Encode as _; diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 3217f9f96ca79..9b5c4b12fca99 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -52,7 +52,6 @@ macro_rules! test_wasm_execution { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_recreate_instance_cow>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstanceCopyOnWrite @@ -60,7 +59,6 @@ macro_rules! test_wasm_execution { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_recreate_instance_vanilla>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstance @@ -68,7 +66,6 @@ macro_rules! test_wasm_execution { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_pooling_cow>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite @@ -76,7 +73,6 @@ macro_rules! test_wasm_execution { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_pooling_vanilla>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::Pooling @@ -84,7 +80,6 @@ macro_rules! test_wasm_execution { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_legacy_instance_reuse>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse @@ -120,7 +115,6 @@ macro_rules! test_wasm_execution_sandbox { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_pooling_cow_host_executor>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite @@ -128,7 +122,6 @@ macro_rules! test_wasm_execution_sandbox { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_pooling_cow_embedded_executor>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite @@ -136,7 +129,6 @@ macro_rules! test_wasm_execution_sandbox { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_pooling_vanilla_host_executor>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::Pooling @@ -144,7 +136,6 @@ macro_rules! test_wasm_execution_sandbox { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_pooling_vanilla_embedded_executor>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::Pooling @@ -152,7 +143,6 @@ macro_rules! test_wasm_execution_sandbox { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_recreate_instance_cow_host_executor>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstanceCopyOnWrite @@ -160,7 +150,6 @@ macro_rules! test_wasm_execution_sandbox { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_recreate_instance_cow_embedded_executor>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstanceCopyOnWrite @@ -168,7 +157,6 @@ macro_rules! test_wasm_execution_sandbox { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_recreate_instance_vanilla_host_executor>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstance @@ -176,7 +164,6 @@ macro_rules! test_wasm_execution_sandbox { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_recreate_instance_vanilla_embedded_executor>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstance @@ -184,7 +171,6 @@ macro_rules! test_wasm_execution_sandbox { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_legacy_instance_reuse_host_executor>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse @@ -192,7 +178,6 @@ macro_rules! test_wasm_execution_sandbox { } #[test] - #[cfg(feature = "wasmtime")] fn [<$method_name _compiled_legacy_instance_reuse_embedded_executor>]() { $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse @@ -253,7 +238,6 @@ fn call_not_existing_function(wasm_method: WasmExecutionMethod) { Error::AbortedDueToTrap(error) => { let expected = match wasm_method { WasmExecutionMethod::Interpreted => "Other: Function `missing_external` is only a stub. Calling a stub is not allowed.", - #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled { .. } => "call to a missing function env:missing_external" }; assert_eq!(error.message, expected); @@ -273,7 +257,6 @@ fn call_yet_another_not_existing_function(wasm_method: WasmExecutionMethod) { Error::AbortedDueToTrap(error) => { let expected = match wasm_method { WasmExecutionMethod::Interpreted => "Other: Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.", - #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled { .. } => "call to a missing function env:yet_another_missing_external" }; assert_eq!(error.message, expected); @@ -577,7 +560,6 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { .unwrap_err(); match err { - #[cfg(feature = "wasmtime")] Error::AbortedDueToTrap(error) if matches!(wasm_method, WasmExecutionMethod::Compiled { .. }) => { @@ -886,8 +868,8 @@ fn unreachable_intrinsic(wasm_method: WasmExecutionMethod) { Error::AbortedDueToTrap(error) => { let expected = match wasm_method { WasmExecutionMethod::Interpreted => "unreachable", - #[cfg(feature = "wasmtime")] - WasmExecutionMethod::Compiled { .. } => "wasm trap: wasm `unreachable` instruction executed", + WasmExecutionMethod::Compiled { .. } => + "wasm trap: wasm `unreachable` instruction executed", }; assert_eq!(error.message, expected); }, diff --git a/client/executor/src/lib.rs b/client/executor/src/lib.rs index fefb84ede9105..1fb041c358fb1 100644 --- a/client/executor/src/lib.rs +++ b/client/executor/src/lib.rs @@ -50,8 +50,6 @@ pub use wasm_runtime::{read_embedded_version, WasmExecutionMethod}; pub use wasmi; pub use sc_executor_common::{error, sandbox}; - -#[cfg(feature = "wasmtime")] pub use sc_executor_wasmtime::InstantiationStrategy as WasmtimeInstantiationStrategy; /// Extracts the runtime version of a given runtime code. diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 991802340db61..5576fff186bb2 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -46,7 +46,6 @@ pub enum WasmExecutionMethod { /// Uses the Wasmi interpreter. Interpreted, /// Uses the Wasmtime compiled runtime. - #[cfg(feature = "wasmtime")] Compiled { /// The instantiation strategy to use. instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy, @@ -314,7 +313,6 @@ where ) .map(|runtime| -> Arc { Arc::new(runtime) }) }, - #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled { instantiation_strategy } => sc_executor_wasmtime::create_runtime::( blob, diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index a80ef77e0357c..b12ca0779e7a2 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -33,7 +33,7 @@ sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sp-runtime-interface = { version = "7.0.0", path = "../../../primitives/runtime-interface" } sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } -sp-wasm-interface = { version = "7.0.0", features = ["wasmtime"], path = "../../../primitives/wasm-interface" } +sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interface" } # Here we include the rustix crate in the exactly same semver-compatible version as used by # wasmtime and enable its 'use-libc' flag. diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 4057e6072c261..c165d2d1288cd 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -17,7 +17,6 @@ default = ["rocksdb"] # The RocksDB feature activates the RocksDB database backend. If it is not activated, and you pass # a path to a database, an error will be produced at runtime. rocksdb = ["sc-client-db/rocksdb"] -wasmtime = ["sc-executor/wasmtime"] # exposes the client type test-helpers = [] runtime-benchmarks = ["sc-client-db/runtime-benchmarks"] diff --git a/client/service/src/config.rs b/client/service/src/config.rs index bca0697bcbd08..e79ff48d6f0ff 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -20,9 +20,7 @@ pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStrategy}; pub use sc_client_db::{BlocksPruning, Database, DatabaseSource, PruningMode}; -pub use sc_executor::WasmExecutionMethod; -#[cfg(feature = "wasmtime")] -pub use sc_executor::WasmtimeInstantiationStrategy; +pub use sc_executor::{WasmExecutionMethod, WasmtimeInstantiationStrategy}; pub use sc_network::{ config::{NetworkConfiguration, NodeKeyConfig, Role}, Multiaddr, diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 2e997ef4a2add..1822ae43edb68 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -23,4 +23,4 @@ sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] -std = [ "codec/std", "log", "sp-std/std", "wasmi" ] +std = [ "codec/std", "log", "sp-std/std", "wasmi", "wasmtime" ] From 7cfaa03344f1ce792affef6d0052f3571981dc0f Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 18 Nov 2022 15:01:13 +0100 Subject: [PATCH 1394/1472] Fix the light client protocol protobuf schema (#12732) * Fix the light client protocol protobuf schema * Add another test * Remove unused protobuf struct * Ok you have to use the nightly rustfmt apparently --- .../src/light_client_requests/handler.rs | 33 +++++++------- client/network/light/src/schema.rs | 44 +++++++++++++++++++ .../network/light/src/schema/light.v1.proto | 32 ++++++-------- 3 files changed, 72 insertions(+), 37 deletions(-) diff --git a/client/network/light/src/light_client_requests/handler.rs b/client/network/light/src/light_client_requests/handler.rs index 77904c7256295..abf012b82f9db 100644 --- a/client/network/light/src/light_client_requests/handler.rs +++ b/client/network/light/src/light_client_requests/handler.rs @@ -173,10 +173,7 @@ where let block = Decode::decode(&mut request.block.as_ref())?; let response = match self.client.execution_proof(block, &request.method, &request.data) { - Ok((_, proof)) => { - let r = schema::v1::light::RemoteCallResponse { proof: proof.encode() }; - Some(schema::v1::light::response::Response::RemoteCallResponse(r)) - }, + Ok((_, proof)) => schema::v1::light::RemoteCallResponse { proof: Some(proof.encode()) }, Err(e) => { trace!( "remote call request from {} ({} at {:?}) failed with: {}", @@ -185,11 +182,13 @@ where request.block, e, ); - None + schema::v1::light::RemoteCallResponse { proof: None } }, }; - Ok(schema::v1::light::Response { response }) + Ok(schema::v1::light::Response { + response: Some(schema::v1::light::response::Response::RemoteCallResponse(response)), + }) } fn on_remote_read_request( @@ -213,10 +212,7 @@ where let response = match self.client.read_proof(block, &mut request.keys.iter().map(AsRef::as_ref)) { - Ok(proof) => { - let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; - Some(schema::v1::light::response::Response::RemoteReadResponse(r)) - }, + Ok(proof) => schema::v1::light::RemoteReadResponse { proof: Some(proof.encode()) }, Err(error) => { trace!( "remote read request from {} ({} at {:?}) failed with: {}", @@ -225,11 +221,13 @@ where request.block, error, ); - None + schema::v1::light::RemoteReadResponse { proof: None } }, }; - Ok(schema::v1::light::Response { response }) + Ok(schema::v1::light::Response { + response: Some(schema::v1::light::response::Response::RemoteReadResponse(response)), + }) } fn on_remote_read_child_request( @@ -264,10 +262,7 @@ where &mut request.keys.iter().map(AsRef::as_ref), ) }) { - Ok(proof) => { - let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; - Some(schema::v1::light::response::Response::RemoteReadResponse(r)) - }, + Ok(proof) => schema::v1::light::RemoteReadResponse { proof: Some(proof.encode()) }, Err(error) => { trace!( "remote read child request from {} ({} {} at {:?}) failed with: {}", @@ -277,11 +272,13 @@ where request.block, error, ); - None + schema::v1::light::RemoteReadResponse { proof: None } }, }; - Ok(schema::v1::light::Response { response }) + Ok(schema::v1::light::Response { + response: Some(schema::v1::light::response::Response::RemoteReadResponse(response)), + }) } } diff --git a/client/network/light/src/schema.rs b/client/network/light/src/schema.rs index 09cc82cc2811a..1fc91659a5bbb 100644 --- a/client/network/light/src/schema.rs +++ b/client/network/light/src/schema.rs @@ -23,3 +23,47 @@ pub(crate) mod v1 { include!(concat!(env!("OUT_DIR"), "/api.v1.light.rs")); } } + +#[cfg(test)] +mod tests { + use prost::Message as _; + + #[test] + fn empty_proof_encodes_correctly() { + let encoded = super::v1::light::Response { + response: Some(super::v1::light::response::Response::RemoteReadResponse( + super::v1::light::RemoteReadResponse { proof: Some(Vec::new()) }, + )), + } + .encode_to_vec(); + + // Make sure that the response contains one field of number 2 and wire type 2 (message), + // then another field of number 2 and wire type 2 (bytes), then a length of 0. + assert_eq!(encoded, vec![(2 << 3) | 2, 2, (2 << 3) | 2, 0]); + } + + #[test] + fn no_proof_encodes_correctly() { + let encoded = super::v1::light::Response { + response: Some(super::v1::light::response::Response::RemoteReadResponse( + super::v1::light::RemoteReadResponse { proof: None }, + )), + } + .encode_to_vec(); + + // Make sure that the response contains one field of number 2 and wire type 2 (message). + assert_eq!(encoded, vec![(2 << 3) | 2, 0]); + } + + #[test] + fn proof_encodes_correctly() { + let encoded = super::v1::light::Response { + response: Some(super::v1::light::response::Response::RemoteReadResponse( + super::v1::light::RemoteReadResponse { proof: Some(vec![1, 2, 3, 4]) }, + )), + } + .encode_to_vec(); + + assert_eq!(encoded, vec![(2 << 3) | 2, 6, (2 << 3) | 2, 4, 1, 2, 3, 4]); + } +} diff --git a/client/network/light/src/schema/light.v1.proto b/client/network/light/src/schema/light.v1.proto index 1df5466e21988..a269ea73c2074 100644 --- a/client/network/light/src/schema/light.v1.proto +++ b/client/network/light/src/schema/light.v1.proto @@ -1,17 +1,9 @@ // Schema definition for light client messages. -syntax = "proto3"; +syntax = "proto2"; package api.v1.light; -// A pair of arbitrary bytes. -message Pair { - // The first element of the pair. - bytes fst = 1; - // The second element of the pair. - bytes snd = 2; -} - // Enumerate all possible light client request messages. message Request { oneof request { @@ -34,40 +26,42 @@ message Response { // Remote call request. message RemoteCallRequest { // Block at which to perform call. - bytes block = 2; + required bytes block = 2; // Method name. - string method = 3; + required string method = 3; // Call data. - bytes data = 4; + required bytes data = 4; } // Remote call response. message RemoteCallResponse { - // Execution proof. - bytes proof = 2; + // Execution proof. If missing, indicates that the remote couldn't answer, for example because + // the block is pruned. + optional bytes proof = 2; } // Remote storage read request. message RemoteReadRequest { // Block at which to perform call. - bytes block = 2; + required bytes block = 2; // Storage keys. repeated bytes keys = 3; } // Remote read response. message RemoteReadResponse { - // Read proof. - bytes proof = 2; + // Read proof. If missing, indicates that the remote couldn't answer, for example because + // the block is pruned. + optional bytes proof = 2; } // Remote storage read child request. message RemoteReadChildRequest { // Block at which to perform call. - bytes block = 2; + required bytes block = 2; // Child Storage key, this is relative // to the child type storage location. - bytes storage_key = 3; + required bytes storage_key = 3; // Storage keys. repeated bytes keys = 6; } From c29095026871c2b7d42734226dd45db8051d258e Mon Sep 17 00:00:00 2001 From: Fredrik Simonsson Date: Sat, 19 Nov 2022 00:43:41 +0900 Subject: [PATCH 1395/1472] Update template to remove clippy warnings (#12670) * Update template to remove clippy warnings * ".git/.scripts/bench-bot.sh" pallet dev pallet_lottery * Update templates from child project This should remove clippy warnings on generated files * Update after review * Update frame-weight-template.hbs Commit suggestion * ".git/.scripts/bench-bot.sh" pallet dev pallet_lottery * Rerun linter on linked project Updates from child project * ".git/.scripts/bench-bot.sh" pallet dev pallet_lottery Co-authored-by: command-bot <> --- .maintain/frame-weight-template.hbs | 24 ++-- frame/lottery/src/weights.rs | 113 +++++++++--------- .../benchmarking-cli/src/pallet/template.hbs | 12 +- 3 files changed, 75 insertions(+), 74 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 360279129980f..9c9e297800869 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -49,22 +49,22 @@ impl WeightInfo for SubstrateWeight { {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. - Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) + Weight::from_ref_time({{underscore benchmark.base_weight}}) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as u64).saturating_mul({{cw.name}} as u64)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) {{/each}} {{#if (ne benchmark.base_reads "0")}} - .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as u64)) + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}})) {{/if}} {{#each benchmark.component_reads as |cr|}} - .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as u64).saturating_mul({{cr.name}} as u64))) + .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}} as u64)) + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}})) {{/if}} {{#each benchmark.component_writes as |cw|}} - .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as u64).saturating_mul({{cw.name}} as u64))) + .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) {{/each}} } {{/each}} @@ -85,22 +85,22 @@ impl WeightInfo for () { {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. - Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) + Weight::from_ref_time({{underscore benchmark.base_weight}}) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as u64).saturating_mul({{cw.name}} as u64)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) {{/each}} {{#if (ne benchmark.base_reads "0")}} - .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}} as u64)) + .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}})) {{/if}} {{#each benchmark.component_reads as |cr|}} - .saturating_add(RocksDbWeight::get().reads(({{cr.slope}} as u64).saturating_mul({{cr.name}} as u64))) + .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}} as u64)) + .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}})) {{/if}} {{#each benchmark.component_writes as |cw|}} - .saturating_add(RocksDbWeight::get().writes(({{cw.slope}} as u64).saturating_mul({{cw.name}} as u64))) + .saturating_add(RocksDbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) {{/each}} } {{/each}} diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index 4ced6a642781a..c0936ae6c8073 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -18,24 +18,25 @@ //! Autogenerated weights for pallet_lottery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_lottery // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/lottery/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_lottery +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/lottery/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -66,35 +67,35 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - // Minimum execution time: 52_451 nanoseconds. - Weight::from_ref_time(52_843_000 as u64) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 53_735 nanoseconds. + Weight::from_ref_time(54_235_000) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Lottery CallIndices (r:0 w:1) /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { - // Minimum execution time: 14_389 nanoseconds. - Weight::from_ref_time(15_700_569 as u64) - // Standard Error: 4_677 - .saturating_add(Weight::from_ref_time(296_850 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 15_065 nanoseconds. + Weight::from_ref_time(16_467_398) + // Standard Error: 5_392 + .saturating_add(Weight::from_ref_time(294_914).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - // Minimum execution time: 44_814 nanoseconds. - Weight::from_ref_time(45_611_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 45_990 nanoseconds. + Weight::from_ref_time(46_789_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - // Minimum execution time: 10_384 nanoseconds. - Weight::from_ref_time(10_727_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 10_783 nanoseconds. + Weight::from_ref_time(11_180_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -102,10 +103,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - // Minimum execution time: 62_720 nanoseconds. - Weight::from_ref_time(63_545_000 as u64) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 62_088 nanoseconds. + Weight::from_ref_time(63_670_000) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -114,10 +115,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - // Minimum execution time: 63_452 nanoseconds. - Weight::from_ref_time(65_010_000 as u64) - .saturating_add(T::DbWeight::get().reads(7 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + // Minimum execution time: 64_953 nanoseconds. + Weight::from_ref_time(65_465_000) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(5)) } } @@ -131,35 +132,35 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - // Minimum execution time: 52_451 nanoseconds. - Weight::from_ref_time(52_843_000 as u64) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 53_735 nanoseconds. + Weight::from_ref_time(54_235_000) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Lottery CallIndices (r:0 w:1) /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { - // Minimum execution time: 14_389 nanoseconds. - Weight::from_ref_time(15_700_569 as u64) - // Standard Error: 4_677 - .saturating_add(Weight::from_ref_time(296_850 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 15_065 nanoseconds. + Weight::from_ref_time(16_467_398) + // Standard Error: 5_392 + .saturating_add(Weight::from_ref_time(294_914).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - // Minimum execution time: 44_814 nanoseconds. - Weight::from_ref_time(45_611_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 45_990 nanoseconds. + Weight::from_ref_time(46_789_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - // Minimum execution time: 10_384 nanoseconds. - Weight::from_ref_time(10_727_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 10_783 nanoseconds. + Weight::from_ref_time(11_180_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -167,10 +168,10 @@ impl WeightInfo for () { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - // Minimum execution time: 62_720 nanoseconds. - Weight::from_ref_time(63_545_000 as u64) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 62_088 nanoseconds. + Weight::from_ref_time(63_670_000) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) // Storage: Lottery Lottery (r:1 w:1) @@ -179,9 +180,9 @@ impl WeightInfo for () { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - // Minimum execution time: 63_452 nanoseconds. - Weight::from_ref_time(65_010_000 as u64) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) + // Minimum execution time: 64_953 nanoseconds. + Weight::from_ref_time(65_465_000) + .saturating_add(RocksDbWeight::get().reads(7)) + .saturating_add(RocksDbWeight::get().writes(5)) } } diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index 7e2e0688d654f..1a69a3ae20c5f 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -34,22 +34,22 @@ impl {{pallet}}::WeightInfo for WeightInfo { {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. - Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) + Weight::from_ref_time({{underscore benchmark.base_weight}}) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}} as u64).saturating_mul({{cw.name}} as u64)) + .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) {{/each}} {{#if (ne benchmark.base_reads "0")}} - .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as u64)) + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}})) {{/if}} {{#each benchmark.component_reads as |cr|}} - .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as u64).saturating_mul({{cr.name}} as u64))) + .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}} as u64)) + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}})) {{/if}} {{#each benchmark.component_writes as |cw|}} - .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as u64).saturating_mul({{cw.name}} as u64))) + .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) {{/each}} } {{/each}} From f80c370cdce7c996e8bf8710b6522dac639fbab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Mon, 21 Nov 2022 08:49:53 -0300 Subject: [PATCH 1396/1472] Check all crates (#12709) * check all crates individually It's relevant to check workspace crates individually because otherwise their compilation problems due to feature misconfigurations won't be caught, as exemplified by https://github.com/paritytech/substrate/issues/12705 * adapt to lack of multiple macos runners https://github.com/paritytech/substrate/pull/12709#discussion_r1022868752 * fix cancel-pipeline-cargo-check-each-crate-macos * fix cargo-check-each-crate-macos again * time command execution * fix YAML anchors * add explanation for rounding division * ensure the minimum of one crate per group * collect artifacts for pipeline stopper * revert hardcoded crates_per_group * re-add crates_per_group=1 --- .gitlab-ci.yml | 16 +++++-- scripts/ci/gitlab/check-each-crate.sh | 46 ++++++++++++++++++ scripts/ci/gitlab/pipeline/build.yml | 3 -- scripts/ci/gitlab/pipeline/test.yml | 67 ++++++++++++++++----------- 4 files changed, 98 insertions(+), 34 deletions(-) create mode 100755 scripts/ci/gitlab/check-each-crate.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d4b98db13b77b..8519d0f88fc7c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -136,7 +136,7 @@ default: # exclude cargo-check-benches from such runs .test-refs-check-benches: rules: - - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "parent_pipeline" && $CI_IMAGE =~ /staging$/ + - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "parent_pipeline" && $CI_IMAGE =~ /staging$/ when: never - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" @@ -329,10 +329,20 @@ cancel-pipeline-test-linux-stable-int: needs: - job: test-linux-stable-int -cancel-pipeline-cargo-check-subkey: +cancel-pipeline-cargo-check-each-crate-1: extends: .cancel-pipeline-template needs: - - job: cargo-check-subkey + - job: "cargo-check-each-crate 1/2" + +cancel-pipeline-cargo-check-each-crate-2: + extends: .cancel-pipeline-template + needs: + - job: "cargo-check-each-crate 2/2" + +cancel-pipeline-cargo-check-each-crate-macos: + extends: .cancel-pipeline-template + needs: + - job: cargo-check-each-crate-macos cancel-pipeline-check-tracing: extends: .cancel-pipeline-template diff --git a/scripts/ci/gitlab/check-each-crate.sh b/scripts/ci/gitlab/check-each-crate.sh new file mode 100755 index 0000000000000..27e2cf947787a --- /dev/null +++ b/scripts/ci/gitlab/check-each-crate.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +## A script that checks each workspace crate individually. +## It's relevant to check workspace crates individually because otherwise their compilation problems +## due to feature misconfigurations won't be caught, as exemplified by +## https://github.com/paritytech/substrate/issues/12705 + +set -Eeu -o pipefail +shopt -s inherit_errexit + +set -x + +target_group="$1" +groups_total="$2" + +readarray -t workspace_crates < <(\ + cargo tree --workspace --depth 0 | \ + awk '{ if (length($1) == 0 || substr($1, 1, 1) == "[") { skip } else { print $1 } }' +) + +crates_total=${#workspace_crates[*]} + +if [ "$crates_total" -lt "$groups_total" ]; then + # `crates_total / groups_total` would result in 0, so round it up to 1 + crates_per_group=1 +else + # We add `crates_total % groups_total > 0` (which evaluates to 1 in case there's a remainder for + # `crates_total % groups_total`) to round UP `crates_total / groups_total` 's + # potentially-fractional result to the nearest integer. Doing that ensures that we'll not miss any + # crate in case `crates_total / groups_total` would normally result in a fractional number, since + # in those cases Bash would round DOWN the result to the nearest integer. For example, if + # `crates_total = 5` and `groups_total = 2`, then `crates_total / groups_total` would round down + # to 2; since the loop below would then step by 2, we'd miss the 5th crate. + crates_per_group=$(( (crates_total / groups_total) + (crates_total % groups_total > 0) )) +fi + +group=1 +for ((i=0; i < crates_total; i += crates_per_group)); do + if [ $group -eq "$target_group" ]; then + for crate in "${workspace_crates[@]:$i:$crates_per_group}"; do + cargo check --locked --release -p "$crate" + done + break + fi + group=$(( group + 1 )) +done diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 2e403c10d4520..906c1bcbe242e 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -90,9 +90,6 @@ build-linux-substrate: variables: # this variable gets overriden by "rusty-cachier environment inject", use the value as default CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" - needs: - - job: cargo-check-subkey - artifacts: false before_script: - mkdir -p ./artifacts/subkey - !reference [.rusty-cachier, before_script] diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 710fbe6227f46..c38eac45d7ba4 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -133,24 +133,8 @@ node-bench-regression-guard: --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA' after_script: [""] -cargo-check-subkey: - stage: test - extends: - - .docker-env - - .test-refs - - .pipeline-stopper-artifacts - script: - - rusty-cachier snapshot create - - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo check --locked --release - - rusty-cachier cache upload - cargo-check-try-runtime: stage: test - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: cargo-check-subkey - artifacts: false extends: - .docker-env - .test-refs @@ -393,6 +377,9 @@ test-full-crypto-feature: test-wasmer-sandbox: stage: test + needs: + - job: cargo-check-wasmer-sandbox + artifacts: false extends: - .docker-env - .test-refs-wasmer-sandbox @@ -409,18 +396,6 @@ test-wasmer-sandbox: - time cargo nextest run --locked --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} - if [ ${CI_NODE_INDEX} == 1 ]; then rusty-cachier cache upload; fi -cargo-check-macos: - stage: test - extends: .test-refs-no-trigger - before_script: - - !reference [.rust-info-script, script] - variables: - SKIP_WASM_BUILD: 1 - script: - - time cargo check --locked --release - tags: - - osx - check-rustdoc: stage: test variables: @@ -435,3 +410,39 @@ check-rustdoc: - rusty-cachier snapshot create - time cargo +nightly doc --locked --workspace --all-features --verbose --no-deps - rusty-cachier cache upload + +cargo-check-each-crate: + stage: test + extends: + - .docker-env + - .test-refs + - .collect-artifacts + - .pipeline-stopper-artifacts + variables: + # $CI_JOB_NAME is set manually so that rusty-cachier can share the cache for all + # "cargo-check-each-crate I/N" jobs + CI_JOB_NAME: cargo-check-each-crate + script: + - rusty-cachier snapshot create + - time ./scripts/ci/gitlab/check-each-crate.sh "$CI_NODE_INDEX" "$CI_NODE_TOTAL" + # need to update cache only from one job + - if [ "$CI_NODE_INDEX" == 1 ]; then rusty-cachier cache upload; fi + parallel: 2 + +cargo-check-each-crate-macos: + stage: test + extends: + - .test-refs + - .collect-artifacts + - .pipeline-stopper-artifacts + before_script: + - !reference [.rust-info-script, script] + - !reference [.pipeline-stopper-vars, script] + variables: + SKIP_WASM_BUILD: 1 + script: + # TODO: enable rusty-cachier once it supports Mac + # TODO: use parallel jobs, as per cargo-check-each-crate, once more Mac runners are available + - time ./scripts/ci/gitlab/check-each-crate.sh 1 1 + tags: + - osx From ee9ddf1238ce2c4a82f95841b8ac477a3dc1f2db Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 21 Nov 2022 16:56:29 +0200 Subject: [PATCH 1397/1472] client/beefy: persist voter state (#12712) * client/beefy: prepare worker for persisting state * client/beefy: persist voter state * client/beefy: initialize persistent state * client/beefy: try to vote from the very beginning Now that voter is initialized from persistent state, it makes sense that it can attempt voting right away. This also helps the genesis case when we consider block `One` as mandatory. * client/beefy: add tests for voter state db * client/beefy: persist voter state as soon as initialized * client/beefy: make sure min-block-delta is at least 1 * client/beefy: persist state after voting Persist state after handling self vote to avoid double voting in case of voter restarts. * client/beefy: persist state after handling mandatory block vote For mandatory blocks we want to make sure we're not losing votes in case of crashes or restarts, since voter will not make further progress without finalizing them. * frame/beefy: use GENESIS_AUTHORITY_SET_ID on pallet genesis * client/beefy: initialize voter at either genesis or last finalized To guarantee unbroken chain of mandatory blocks justifications, voter will always resume from either last BEEFY-justified block or `pallet-beefy` genesis, whichever is more recent. Initialization walks back the chain from latest GRANDPA finalized block looking for one of the above. Along the way, it also records and enqueues for processing any BEEFY mandatory blocks that have been already GRANDPA finalized but not BEEFY finalized. * client/beefy: decouple voter init from aux db state load * client/beefy: fix voter init tests * remove debug prints * gadget future must be type () * fix init from last justification Signed-off-by: Adrian Catangiu --- client/beefy/src/aux_schema.rs | 105 +++++ client/beefy/src/lib.rs | 278 ++++++++++-- client/beefy/src/round.rs | 16 +- client/beefy/src/tests.rs | 245 +++++++++-- client/beefy/src/worker.rs | 770 +++++++++++++++------------------ frame/beefy/src/lib.rs | 3 +- primitives/beefy/src/lib.rs | 2 +- 7 files changed, 918 insertions(+), 501 deletions(-) create mode 100644 client/beefy/src/aux_schema.rs diff --git a/client/beefy/src/aux_schema.rs b/client/beefy/src/aux_schema.rs new file mode 100644 index 0000000000000..e9a2e9b9e6126 --- /dev/null +++ b/client/beefy/src/aux_schema.rs @@ -0,0 +1,105 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Schema for BEEFY state persisted in the aux-db. + +use crate::worker::PersistedState; +use codec::{Decode, Encode}; +use log::{info, trace}; +use sc_client_api::{backend::AuxStore, Backend}; +use sp_blockchain::{Error as ClientError, Result as ClientResult}; +use sp_runtime::traits::Block as BlockT; + +const VERSION_KEY: &[u8] = b"beefy_auxschema_version"; +const WORKER_STATE: &[u8] = b"beefy_voter_state"; + +const CURRENT_VERSION: u32 = 1; + +pub(crate) fn write_current_version(backend: &B) -> ClientResult<()> { + info!(target: "beefy", "🥩 write aux schema version {:?}", CURRENT_VERSION); + AuxStore::insert_aux(backend, &[(VERSION_KEY, CURRENT_VERSION.encode().as_slice())], &[]) +} + +/// Write voter state. +pub(crate) fn write_voter_state( + backend: &B, + state: &PersistedState, +) -> ClientResult<()> { + trace!(target: "beefy", "🥩 persisting {:?}", state); + backend.insert_aux(&[(WORKER_STATE, state.encode().as_slice())], &[]) +} + +fn load_decode(backend: &B, key: &[u8]) -> ClientResult> { + match backend.get_aux(key)? { + None => Ok(None), + Some(t) => T::decode(&mut &t[..]) + .map_err(|e| ClientError::Backend(format!("BEEFY DB is corrupted: {}", e))) + .map(Some), + } +} + +/// Load or initialize persistent data from backend. +pub(crate) fn load_persistent(backend: &BE) -> ClientResult>> +where + B: BlockT, + BE: Backend, +{ + let version: Option = load_decode(backend, VERSION_KEY)?; + + match version { + None => (), + Some(1) => return load_decode::<_, PersistedState>(backend, WORKER_STATE), + other => + return Err(ClientError::Backend(format!("Unsupported BEEFY DB version: {:?}", other))), + } + + // No persistent state found in DB. + Ok(None) +} + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + use crate::tests::BeefyTestNet; + use sc_network_test::TestNetFactory; + + // also used in tests.rs + pub fn verify_persisted_version>(backend: &BE) -> bool { + let version: u32 = load_decode(backend, VERSION_KEY).unwrap().unwrap(); + version == CURRENT_VERSION + } + + #[test] + fn should_load_persistent_sanity_checks() { + let mut net = BeefyTestNet::new(1); + let backend = net.peer(0).client().as_backend(); + + // version not available in db -> None + assert_eq!(load_persistent(&*backend).unwrap(), None); + + // populate version in db + write_current_version(&*backend).unwrap(); + // verify correct version is retrieved + assert_eq!(load_decode(&*backend, VERSION_KEY).unwrap(), Some(CURRENT_VERSION)); + + // version is available in db but state isn't -> None + assert_eq!(load_persistent(&*backend).unwrap(), None); + + // full `PersistedState` load is tested in `tests.rs`. + } +} diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 441f6e4248117..3bdd13982aea2 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -16,22 +16,48 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use beefy_primitives::{BeefyApi, MmrRootHash, PayloadProvider}; +use crate::{ + communication::{ + notification::{ + BeefyBestBlockSender, BeefyBestBlockStream, BeefyVersionedFinalityProofSender, + BeefyVersionedFinalityProofStream, + }, + peers::KnownPeers, + request_response::{ + outgoing_requests_engine::OnDemandJustificationsEngine, BeefyJustifsRequestHandler, + }, + }, + import::BeefyBlockImport, + round::Rounds, + worker::PersistedState, +}; +use beefy_primitives::{ + crypto::AuthorityId, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID, + GENESIS_AUTHORITY_SET_ID, +}; +use futures::{stream::Fuse, StreamExt}; +use log::{debug, error, info}; use parking_lot::Mutex; use prometheus::Registry; -use sc_client_api::{Backend, BlockBackend, BlockchainEvents, Finalizer}; +use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotifications, Finalizer}; use sc_consensus::BlockImport; use sc_network::ProtocolName; use sc_network_common::service::NetworkRequest; -use sc_network_gossip::Network as GossipNetwork; -use sp_api::{NumberFor, ProvideRuntimeApi}; -use sp_blockchain::HeaderBackend; +use sc_network_gossip::{GossipEngine, Network as GossipNetwork}; +use sp_api::{HeaderT, NumberFor, ProvideRuntimeApi}; +use sp_blockchain::{ + Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult, +}; use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_keystore::SyncCryptoStorePtr; use sp_mmr_primitives::MmrApi; -use sp_runtime::traits::Block; -use std::{marker::PhantomData, sync::Arc}; +use sp_runtime::{ + generic::BlockId, + traits::{Block, One, Zero}, +}; +use std::{collections::VecDeque, marker::PhantomData, sync::Arc}; +mod aux_schema; mod error; mod keystore; mod metrics; @@ -42,27 +68,13 @@ pub mod communication; pub mod import; pub mod justification; -#[cfg(test)] -mod tests; - -use crate::{ - communication::{ - notification::{ - BeefyBestBlockSender, BeefyBestBlockStream, BeefyVersionedFinalityProofSender, - BeefyVersionedFinalityProofStream, - }, - peers::KnownPeers, - request_response::{ - outgoing_requests_engine::OnDemandJustificationsEngine, BeefyJustifsRequestHandler, - }, - }, - import::BeefyBlockImport, -}; - pub use communication::beefy_protocol_name::{ gossip_protocol_name, justifications_protocol_name as justifs_protocol_name, }; +#[cfg(test)] +mod tests; + /// A convenience BEEFY client trait that defines all the type bounds a BEEFY client /// has to satisfy. Ideally that should actually be a trait alias. Unfortunately as /// of today, Rust does not allow a type alias to be used as a trait bound. Tracking @@ -222,7 +234,7 @@ where let known_peers = Arc::new(Mutex::new(KnownPeers::new())); let gossip_validator = Arc::new(communication::gossip::GossipValidator::new(known_peers.clone())); - let gossip_engine = sc_network_gossip::GossipEngine::new( + let mut gossip_engine = sc_network_gossip::GossipEngine::new( network.clone(), gossip_protocol_name, gossip_validator.clone(), @@ -240,21 +252,38 @@ where prometheus_registry.as_ref().map(metrics::Metrics::register).and_then( |result| match result { Ok(metrics) => { - log::debug!(target: "beefy", "🥩 Registered metrics"); + debug!(target: "beefy", "🥩 Registered metrics"); Some(metrics) }, Err(err) => { - log::debug!(target: "beefy", "🥩 Failed to register metrics: {:?}", err); + debug!(target: "beefy", "🥩 Failed to register metrics: {:?}", err); None }, }, ); + // Subscribe to finality notifications and justifications before waiting for runtime pallet and + // reuse the streams, so we don't miss notifications while waiting for pallet to be available. + let mut finality_notifications = client.finality_notification_stream().fuse(); + let block_import_justif = links.from_block_import_justif_stream.subscribe().fuse(); + + // Wait for BEEFY pallet to be active before starting voter. + let persisted_state = + match wait_for_runtime_pallet(&*runtime, &mut gossip_engine, &mut finality_notifications) + .await + .and_then(|best_grandpa| { + load_or_init_voter_state(&*backend, &*runtime, best_grandpa, min_block_delta) + }) { + Ok(state) => state, + Err(e) => { + error!(target: "beefy", "Error: {:?}. Terminating.", e); + return + }, + }; + let worker_params = worker::WorkerParams { - client, backend, payload_provider, - runtime, network, key_store: key_store.into(), known_peers, @@ -263,10 +292,195 @@ where on_demand_justifications, links, metrics, - min_block_delta, + persisted_state, + }; + + let worker = worker::BeefyWorker::<_, _, _, _, _>::new(worker_params); + + futures::future::join( + worker.run(block_import_justif, finality_notifications), + on_demand_justifications_handler.run(), + ) + .await; +} + +fn load_or_init_voter_state( + backend: &BE, + runtime: &R, + best_grandpa: ::Header, + min_block_delta: u32, +) -> ClientResult> +where + B: Block, + BE: Backend, + R: ProvideRuntimeApi, + R::Api: BeefyApi, +{ + // Initialize voter state from AUX DB or from pallet genesis. + if let Some(mut state) = crate::aux_schema::load_persistent(backend)? { + // Overwrite persisted state with current best GRANDPA block. + state.set_best_grandpa(best_grandpa); + // Overwrite persisted data with newly provided `min_block_delta`. + state.set_min_block_delta(min_block_delta); + info!(target: "beefy", "🥩 Loading BEEFY voter state from db: {:?}.", state); + Ok(state) + } else { + initialize_voter_state(backend, runtime, best_grandpa, min_block_delta) + } +} + +// If no persisted state present, walk back the chain from first GRANDPA notification to either: +// - latest BEEFY finalized block, or if none found on the way, +// - BEEFY pallet genesis; +// Enqueue any BEEFY mandatory blocks (session boundaries) found on the way, for voter to finalize. +fn initialize_voter_state( + backend: &BE, + runtime: &R, + best_grandpa: ::Header, + min_block_delta: u32, +) -> ClientResult> +where + B: Block, + BE: Backend, + R: ProvideRuntimeApi, + R::Api: BeefyApi, +{ + // Walk back the imported blocks and initialize voter either, at the last block with + // a BEEFY justification, or at pallet genesis block; voter will resume from there. + let blockchain = backend.blockchain(); + let mut sessions = VecDeque::new(); + let mut header = best_grandpa.clone(); + let state = loop { + if let Some(true) = blockchain + .justifications(header.hash()) + .ok() + .flatten() + .map(|justifs| justifs.get(BEEFY_ENGINE_ID).is_some()) + { + info!( + target: "beefy", + "🥩 Initialize BEEFY voter at last BEEFY finalized block: {:?}.", + *header.number() + ); + let best_beefy = *header.number(); + // If no session boundaries detected so far, just initialize new rounds here. + if sessions.is_empty() { + let active_set = expect_validator_set(runtime, BlockId::hash(header.hash()))?; + let mut rounds = Rounds::new(best_beefy, active_set); + // Mark the round as already finalized. + rounds.conclude(best_beefy); + sessions.push_front(rounds); + } + let state = + PersistedState::checked_new(best_grandpa, best_beefy, sessions, min_block_delta) + .ok_or_else(|| ClientError::Backend("Invalid BEEFY chain".into()))?; + break state + } + + // Check if we should move up the chain. + let parent_hash = *header.parent_hash(); + if *header.number() == One::one() || + runtime + .runtime_api() + .validator_set(&BlockId::hash(parent_hash)) + .ok() + .flatten() + .is_none() + { + // We've reached pallet genesis, initialize voter here. + let genesis_num = *header.number(); + let genesis_set = expect_validator_set(runtime, BlockId::hash(header.hash())) + .and_then(genesis_set_sanity_check)?; + info!( + target: "beefy", + "🥩 Loading BEEFY voter state from genesis on what appears to be first startup. \ + Starting voting rounds at block {:?}, genesis validator set {:?}.", + genesis_num, genesis_set, + ); + + sessions.push_front(Rounds::new(genesis_num, genesis_set)); + break PersistedState::checked_new(best_grandpa, Zero::zero(), sessions, min_block_delta) + .ok_or_else(|| ClientError::Backend("Invalid BEEFY chain".into()))? + } + + if let Some(active) = worker::find_authorities_change::(&header) { + info!(target: "beefy", "🥩 Marking block {:?} as BEEFY Mandatory.", *header.number()); + sessions.push_front(Rounds::new(*header.number(), active)); + } + + // Move up the chain. + header = blockchain.expect_header(BlockId::Hash(parent_hash))?; }; - let worker = worker::BeefyWorker::<_, _, _, _, _, _>::new(worker_params); + aux_schema::write_current_version(backend)?; + aux_schema::write_voter_state(backend, &state)?; + Ok(state) +} - futures::future::join(worker.run(), on_demand_justifications_handler.run()).await; +/// Wait for BEEFY runtime pallet to be available, return active validator set. +/// Should be called only once during worker initialization. +async fn wait_for_runtime_pallet( + runtime: &R, + mut gossip_engine: &mut GossipEngine, + finality: &mut Fuse>, +) -> ClientResult<::Header> +where + B: Block, + R: ProvideRuntimeApi, + R::Api: BeefyApi, +{ + info!(target: "beefy", "🥩 BEEFY gadget waiting for BEEFY pallet to become available..."); + loop { + futures::select! { + notif = finality.next() => { + let notif = match notif { + Some(notif) => notif, + None => break + }; + let at = BlockId::hash(notif.header.hash()); + if let Some(active) = runtime.runtime_api().validator_set(&at).ok().flatten() { + // Beefy pallet available, return best grandpa at the time. + info!( + target: "beefy", "🥩 BEEFY pallet available: block {:?} validator set {:?}", + notif.header.number(), active + ); + return Ok(notif.header) + } + }, + _ = gossip_engine => { + break + } + } + } + let err_msg = "🥩 Gossip engine has unexpectedly terminated.".into(); + error!(target: "beefy", "{}", err_msg); + Err(ClientError::Backend(err_msg)) +} + +fn genesis_set_sanity_check( + active: ValidatorSet, +) -> ClientResult> { + if active.id() == GENESIS_AUTHORITY_SET_ID { + Ok(active) + } else { + error!(target: "beefy", "🥩 Unexpected ID for genesis validator set {:?}.", active); + Err(ClientError::Backend("BEEFY Genesis sanity check failed.".into())) + } +} + +fn expect_validator_set( + runtime: &R, + at: BlockId, +) -> ClientResult> +where + B: Block, + R: ProvideRuntimeApi, + R::Api: BeefyApi, +{ + runtime + .runtime_api() + .validator_set(&at) + .ok() + .flatten() + .ok_or_else(|| ClientError::Backend("BEEFY pallet expected to be active.".into())) } diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index 45d346ccd85eb..7a8cc4171a155 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -16,27 +16,23 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{ - collections::{BTreeMap, HashMap}, - hash::Hash, -}; - -use log::{debug, trace}; - use beefy_primitives::{ crypto::{Public, Signature}, ValidatorSet, ValidatorSetId, }; +use codec::{Decode, Encode}; +use log::{debug, trace}; use sp_runtime::traits::{Block, NumberFor}; +use std::{collections::BTreeMap, hash::Hash}; /// Tracks for each round which validators have voted/signed and /// whether the local `self` validator has voted/signed. /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). -#[derive(Debug, Default)] +#[derive(Debug, Decode, Default, Encode, PartialEq)] struct RoundTracker { self_vote: bool, - votes: HashMap, + votes: BTreeMap, } impl RoundTracker { @@ -69,7 +65,7 @@ pub fn threshold(authorities: usize) -> usize { /// Only round numbers > `best_done` are of interest, all others are considered stale. /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). -#[derive(Debug)] +#[derive(Debug, Decode, Encode, PartialEq)] pub(crate) struct Rounds { rounds: BTreeMap<(Payload, NumberFor), RoundTracker>, session_start: NumberFor, diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 1d5da4aaefba3..9a31d4a583d0e 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -18,56 +18,53 @@ //! Tests and test helpers for BEEFY. +use crate::{ + aux_schema::{load_persistent, tests::verify_persisted_version}, + beefy_block_import_and_links, + communication::request_response::{ + on_demand_justifications_protocol_config, BeefyJustifsRequestHandler, + }, + gossip_protocol_name, + justification::*, + keystore::tests::Keyring as BeefyKeyring, + load_or_init_voter_state, wait_for_runtime_pallet, BeefyRPCLinks, BeefyVoterLinks, KnownPeers, + PersistedState, +}; +use beefy_primitives::{ + crypto::{AuthorityId, Signature}, + known_payloads, + mmr::MmrRootProvider, + BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, SignedCommitment, ValidatorSet, + VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, +}; use futures::{future, stream::FuturesUnordered, Future, StreamExt}; use parking_lot::Mutex; -use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, marker::PhantomData, sync::Arc, task::Poll}; -use tokio::{runtime::Runtime, time::Duration}; - -use sc_client_api::HeaderBackend; +use sc_client_api::{Backend as BackendT, BlockchainEvents, FinalityNotifications, HeaderBackend}; use sc_consensus::{ BlockImport, BlockImportParams, BoxJustificationImport, ForkChoiceStrategy, ImportResult, ImportedAux, }; +use sc_network::{config::RequestResponseConfig, ProtocolName}; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, PeersFullClient, TestNetFactory, }; use sc_utils::notification::NotificationReceiver; -use sp_keystore::testing::KeyStore as TestKeystore; - -use beefy_primitives::{ - crypto::{AuthorityId, Signature}, - mmr::MmrRootProvider, - BeefyApi, ConsensusLog, MmrRootHash, ValidatorSet, VersionedFinalityProof, BEEFY_ENGINE_ID, - KEY_TYPE as BeefyKeyType, -}; -use sc_network::{config::RequestResponseConfig, ProtocolName}; -use sp_mmr_primitives::{EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof}; - +use serde::{Deserialize, Serialize}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; use sp_core::H256; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{testing::KeyStore as TestKeystore, SyncCryptoStore, SyncCryptoStorePtr}; +use sp_mmr_primitives::{EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof}; use sp_runtime::{ codec::Encode, generic::BlockId, traits::{Header as HeaderT, NumberFor}, BuildStorage, DigestItem, Justifications, Storage, }; - +use std::{collections::HashMap, marker::PhantomData, sync::Arc, task::Poll}; use substrate_test_runtime_client::{runtime::Header, ClientExt}; - -use crate::{ - beefy_block_import_and_links, - communication::request_response::{ - on_demand_justifications_protocol_config, BeefyJustifsRequestHandler, - }, - gossip_protocol_name, - justification::*, - keystore::tests::Keyring as BeefyKeyring, - BeefyRPCLinks, BeefyVoterLinks, -}; +use tokio::{runtime::Runtime, time::Duration}; const GENESIS_HASH: H256 = H256::zero(); fn beefy_gossip_proto_name() -> ProtocolName { @@ -531,7 +528,7 @@ fn beefy_finalizing_blocks() { let peers = peers.into_iter().enumerate(); // finalize block #5 -> BEEFY should finalize #1 (mandatory) and #5 from diff-power-of-two rule. - finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[5], &[1, 5]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[1, 5], &[1, 5]); // GRANDPA finalize #10 -> BEEFY finalize #10 (mandatory) finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[10], &[10]); @@ -573,7 +570,7 @@ fn lagging_validators() { &net, peers.clone(), &mut runtime, - &[15], + &[1, 15], &[1, 9, 13, 14, 15], ); @@ -661,7 +658,7 @@ fn correct_beefy_payload() { let net = Arc::new(Mutex::new(net)); let peers = peers.into_iter().enumerate(); // with 3 good voters and 1 bad one, consensus should happen and best blocks produced. - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[1, 9]); + finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[1, 10], &[1, 9]); let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); @@ -945,3 +942,187 @@ fn on_demand_beefy_justification_sync() { // Now that Dave has caught up, sanity check voting works for all of them. finalize_block_and_wait_for_beefy(&net, all_peers, &mut runtime, &[30], &[30]); } + +fn test_voter_init_setup( + net: &mut BeefyTestNet, + finality: &mut futures::stream::Fuse>, +) -> sp_blockchain::Result> { + let backend = net.peer(0).client().as_backend(); + let api = Arc::new(crate::tests::two_validators::TestApi {}); + let known_peers = Arc::new(Mutex::new(KnownPeers::new())); + let gossip_validator = + Arc::new(crate::communication::gossip::GossipValidator::new(known_peers)); + let mut gossip_engine = sc_network_gossip::GossipEngine::new( + net.peer(0).network_service().clone(), + "/beefy/whatever", + gossip_validator, + None, + ); + let best_grandpa = + futures::executor::block_on(wait_for_runtime_pallet(&*api, &mut gossip_engine, finality)) + .unwrap(); + load_or_init_voter_state(&*backend, &*api, best_grandpa, 1) +} + +#[test] +fn should_initialize_voter_at_genesis() { + let keys = &[BeefyKeyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1); + let backend = net.peer(0).client().as_backend(); + + // push 15 blocks with `AuthorityChange` digests every 10 blocks + net.generate_blocks_and_sync(15, 10, &validator_set, false); + + let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + + // finalize 13 without justifications + let hashof13 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(13)).unwrap(); + net.peer(0).client().as_client().finalize_block(hashof13, None).unwrap(); + + // load persistent state - nothing in DB, should init at session boundary + let persisted_state = test_voter_init_setup(&mut net, &mut finality).unwrap(); + + // Test initialization at session boundary. + // verify voter initialized with two sessions starting at blocks 1 and 10 + let sessions = persisted_state.voting_oracle().sessions(); + assert_eq!(sessions.len(), 2); + assert_eq!(sessions[0].session_start(), 1); + assert_eq!(sessions[1].session_start(), 10); + let rounds = persisted_state.active_round().unwrap(); + assert_eq!(rounds.session_start(), 1); + assert_eq!(rounds.validator_set_id(), validator_set.id()); + + // verify next vote target is mandatory block 1 + assert_eq!(persisted_state.best_beefy_block(), 0); + assert_eq!(persisted_state.best_grandpa_block(), 13); + assert_eq!( + persisted_state + .voting_oracle() + .voting_target(persisted_state.best_beefy_block(), 13), + Some(1) + ); + + // verify state also saved to db + assert!(verify_persisted_version(&*backend)); + let state = load_persistent(&*backend).unwrap().unwrap(); + assert_eq!(state, persisted_state); +} + +#[test] +fn should_initialize_voter_when_last_final_is_session_boundary() { + let keys = &[BeefyKeyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1); + let backend = net.peer(0).client().as_backend(); + + // push 15 blocks with `AuthorityChange` digests every 10 blocks + net.generate_blocks_and_sync(15, 10, &validator_set, false); + + let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + + // finalize 13 without justifications + let hashof13 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(13)).unwrap(); + net.peer(0).client().as_client().finalize_block(hashof13, None).unwrap(); + + // import/append BEEFY justification for session boundary block 10 + let commitment = Commitment { + payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), + block_number: 10, + validator_set_id: validator_set.id(), + }; + let justif = VersionedFinalityProof::<_, Signature>::V1(SignedCommitment { + commitment, + signatures: vec![None], + }); + let hashof10 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(10)).unwrap(); + backend + .append_justification(hashof10, (BEEFY_ENGINE_ID, justif.encode())) + .unwrap(); + + // Test corner-case where session boundary == last beefy finalized, + // expect rounds initialized at last beefy finalized 10. + + // load persistent state - nothing in DB, should init at session boundary + let persisted_state = test_voter_init_setup(&mut net, &mut finality).unwrap(); + + // verify voter initialized with single session starting at block 10 + assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); + let rounds = persisted_state.active_round().unwrap(); + assert_eq!(rounds.session_start(), 10); + assert_eq!(rounds.validator_set_id(), validator_set.id()); + + // verify block 10 is correctly marked as finalized + assert_eq!(persisted_state.best_beefy_block(), 10); + assert_eq!(persisted_state.best_grandpa_block(), 13); + // verify next vote target is diff-power-of-two block 12 + assert_eq!( + persisted_state + .voting_oracle() + .voting_target(persisted_state.best_beefy_block(), 13), + Some(12) + ); + + // verify state also saved to db + assert!(verify_persisted_version(&*backend)); + let state = load_persistent(&*backend).unwrap().unwrap(); + assert_eq!(state, persisted_state); +} + +#[test] +fn should_initialize_voter_at_latest_finalized() { + let keys = &[BeefyKeyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1); + let backend = net.peer(0).client().as_backend(); + + // push 15 blocks with `AuthorityChange` digests every 10 blocks + net.generate_blocks_and_sync(15, 10, &validator_set, false); + + let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + + // finalize 13 without justifications + let hashof13 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(13)).unwrap(); + net.peer(0).client().as_client().finalize_block(hashof13, None).unwrap(); + + // import/append BEEFY justification for block 12 + let commitment = Commitment { + payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), + block_number: 12, + validator_set_id: validator_set.id(), + }; + let justif = VersionedFinalityProof::<_, Signature>::V1(SignedCommitment { + commitment, + signatures: vec![None], + }); + let hashof12 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(12)).unwrap(); + backend + .append_justification(hashof12, (BEEFY_ENGINE_ID, justif.encode())) + .unwrap(); + + // Test initialization at last BEEFY finalized. + + // load persistent state - nothing in DB, should init at last BEEFY finalized + let persisted_state = test_voter_init_setup(&mut net, &mut finality).unwrap(); + + // verify voter initialized with single session starting at block 12 + assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); + let rounds = persisted_state.active_round().unwrap(); + assert_eq!(rounds.session_start(), 12); + assert_eq!(rounds.validator_set_id(), validator_set.id()); + + // verify next vote target is 13 + assert_eq!(persisted_state.best_beefy_block(), 12); + assert_eq!(persisted_state.best_grandpa_block(), 13); + assert_eq!( + persisted_state + .voting_oracle() + .voting_target(persisted_state.best_beefy_block(), 13), + Some(13) + ); + + // verify state also saved to db + assert!(verify_persisted_version(&*backend)); + let state = load_persistent(&*backend).unwrap().unwrap(); + assert_eq!(state, persisted_state); +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 9c14128624518..e387fed79c6a0 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -37,20 +37,20 @@ use sc_network_gossip::GossipEngine; use sp_api::{BlockId, ProvideRuntimeApi}; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; -use sp_blockchain::Backend as BlockchainBackend; use sp_consensus::SyncOracle; use sp_mmr_primitives::MmrApi; use sp_runtime::{ generic::OpaqueDigestItemId, - traits::{Block, Header, NumberFor}, + traits::{Block, Header, NumberFor, Zero}, SaturatedConversion, }; use beefy_primitives::{ crypto::{AuthorityId, Signature}, BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, PayloadProvider, SignedCommitment, - ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, + ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; +use sc_utils::notification::NotificationReceiver; use crate::{ communication::{ @@ -63,10 +63,10 @@ use crate::{ metric_inc, metric_set, metrics::Metrics, round::Rounds, - BeefyVoterLinks, Client, KnownPeers, + BeefyVoterLinks, KnownPeers, }; -enum RoundAction { +pub(crate) enum RoundAction { Drop, Process, Enqueue, @@ -74,7 +74,9 @@ enum RoundAction { /// Responsible for the voting strategy. /// It chooses which incoming votes to accept and which votes to generate. -struct VoterOracle { +/// Keeps track of voting seen for current and future rounds. +#[derive(Debug, Decode, Encode, PartialEq)] +pub(crate) struct VoterOracle { /// Queue of known sessions. Keeps track of voting rounds (block numbers) within each session. /// /// There are three voter states coresponding to three queue states: @@ -90,35 +92,87 @@ struct VoterOracle { } impl VoterOracle { - pub fn new(min_block_delta: u32) -> Self { - Self { - sessions: VecDeque::new(), - // Always target at least one block better than current best beefy. - min_block_delta: min_block_delta.max(1), + /// Verify provided `sessions` satisfies requirements, then build `VoterOracle`. + pub fn checked_new( + sessions: VecDeque>, + min_block_delta: u32, + ) -> Option { + let mut prev_start = Zero::zero(); + let mut prev_validator_id = None; + // verifies the + let mut validate = || -> bool { + if sessions.is_empty() { + return false + } + for (idx, session) in sessions.iter().enumerate() { + if session.validators().is_empty() { + return false + } + if session.session_start() <= prev_start { + return false + } + #[cfg(not(test))] + if let Some(prev_id) = prev_validator_id { + if session.validator_set_id() <= prev_id { + return false + } + } + if idx != 0 && session.mandatory_done() { + return false + } + prev_start = session.session_start(); + prev_validator_id = Some(session.validator_set_id()); + } + true + }; + if validate() { + Some(VoterOracle { + sessions, + // Always target at least one block better than current best beefy. + min_block_delta: min_block_delta.max(1), + }) + } else { + error!(target: "beefy", "🥩 Invalid sessions queue: {:?}.", sessions); + None } } - /// Return mutable reference to rounds pertaining to first session in the queue. - /// Voting will always happen at the head of the queue. - pub fn rounds_mut(&mut self) -> Option<&mut Rounds> { + // Return reference to rounds pertaining to first session in the queue. + // Voting will always happen at the head of the queue. + fn active_rounds(&self) -> Option<&Rounds> { + self.sessions.front() + } + + // Return mutable reference to rounds pertaining to first session in the queue. + // Voting will always happen at the head of the queue. + fn active_rounds_mut(&mut self) -> Option<&mut Rounds> { self.sessions.front_mut() } + // Prune the sessions queue to keep the Oracle in one of the expected three states. + // + // To be called on each BEEFY finality and on each new rounds/session addition. + fn try_prune(&mut self) { + if self.sessions.len() > 1 { + // when there's multiple sessions, only keep the `!mandatory_done()` ones. + self.sessions.retain(|s| !s.mandatory_done()) + } + } + /// Add new observed session to the Oracle. pub fn add_session(&mut self, rounds: Rounds) { self.sessions.push_back(rounds); + // Once we add a new session we can drop/prune previous session if it's been finalized. self.try_prune(); } - /// Prune the queue to keep the Oracle in one of the expected three states. - /// - /// Call this function on each BEEFY finality, - /// or at the very least on each BEEFY mandatory block finality. - pub fn try_prune(&mut self) { - if self.sessions.len() > 1 { - // when there's multiple sessions, only keep the `!mandatory_done()` ones. - self.sessions.retain(|s| !s.mandatory_done()) - } + /// Finalize a particular block. + pub fn finalize(&mut self, block: NumberFor) -> Result<(), Error> { + // Conclude voting round for this block. + self.active_rounds_mut().ok_or(Error::UninitSession)?.conclude(block); + // Prune any now "finalized" sessions from queue. + self.try_prune(); + Ok(()) } /// Return current pending mandatory block, if any. @@ -170,7 +224,7 @@ impl VoterOracle { /// return `None` if there is no block we should vote on. pub fn voting_target( &self, - best_beefy: Option>, + best_beefy: NumberFor, best_grandpa: NumberFor, ) -> Option> { let rounds = if let Some(r) = self.sessions.front() { @@ -194,11 +248,9 @@ impl VoterOracle { } } -pub(crate) struct WorkerParams { - pub client: Arc, +pub(crate) struct WorkerParams { pub backend: Arc, pub payload_provider: P, - pub runtime: Arc, pub network: N, pub key_store: BeefyKeystore, pub known_peers: Arc>>, @@ -207,16 +259,48 @@ pub(crate) struct WorkerParams { pub on_demand_justifications: OnDemandJustificationsEngine, pub links: BeefyVoterLinks, pub metrics: Option, - pub min_block_delta: u32, + pub persisted_state: PersistedState, +} + +#[derive(Debug, Decode, Encode, PartialEq)] +pub(crate) struct PersistedState { + /// Best block we received a GRANDPA finality for. + best_grandpa_block_header: ::Header, + /// Best block a BEEFY voting round has been concluded for. + best_beefy_block: NumberFor, + /// Chooses which incoming votes to accept and which votes to generate. + /// Keeps track of voting seen for current and future rounds. + voting_oracle: VoterOracle, +} + +impl PersistedState { + pub fn checked_new( + grandpa_header: ::Header, + best_beefy: NumberFor, + sessions: VecDeque>, + min_block_delta: u32, + ) -> Option { + VoterOracle::checked_new(sessions, min_block_delta).map(|voting_oracle| PersistedState { + best_grandpa_block_header: grandpa_header, + best_beefy_block: best_beefy, + voting_oracle, + }) + } + + pub(crate) fn set_min_block_delta(&mut self, min_block_delta: u32) { + self.voting_oracle.min_block_delta = min_block_delta.max(1); + } + + pub(crate) fn set_best_grandpa(&mut self, best_grandpa: ::Header) { + self.best_grandpa_block_header = best_grandpa; + } } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker { +pub(crate) struct BeefyWorker { // utilities - client: Arc, backend: Arc, payload_provider: P, - runtime: Arc, network: N, key_store: BeefyKeystore, @@ -233,23 +317,18 @@ pub(crate) struct BeefyWorker { // voter state /// BEEFY client metrics. metrics: Option, - /// Best block we received a GRANDPA finality for. - best_grandpa_block_header: ::Header, - /// Best block a BEEFY voting round has been concluded for. - best_beefy_block: Option>, /// Buffer holding votes for future processing. pending_votes: BTreeMap, Vec, AuthorityId, Signature>>>, /// Buffer holding justifications for future processing. pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, - /// Chooses which incoming votes to accept and which votes to generate. - voting_oracle: VoterOracle, + /// Persisted voter state. + persisted_state: PersistedState, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, - C: Client, P: PayloadProvider, R: ProvideRuntimeApi, R::Api: BeefyApi + MmrApi>, @@ -261,12 +340,10 @@ where /// BEEFY pallet has been deployed on-chain. /// /// The BEEFY pallet is needed in order to keep track of the BEEFY authority set. - pub(crate) fn new(worker_params: WorkerParams) -> Self { + pub(crate) fn new(worker_params: WorkerParams) -> Self { let WorkerParams { - client, backend, payload_provider, - runtime, key_store, network, gossip_engine, @@ -275,19 +352,12 @@ where known_peers, links, metrics, - min_block_delta, + persisted_state, } = worker_params; - let last_finalized_header = backend - .blockchain() - .expect_header(BlockId::number(backend.blockchain().info().finalized_number)) - .expect("latest block always has header available; qed."); - BeefyWorker { - client: client.clone(), backend, payload_provider, - runtime, network, known_peers, key_store, @@ -296,14 +366,28 @@ where on_demand_justifications, links, metrics, - best_grandpa_block_header: last_finalized_header, - best_beefy_block: None, pending_votes: BTreeMap::new(), pending_justifications: BTreeMap::new(), - voting_oracle: VoterOracle::new(min_block_delta), + persisted_state, } } + fn best_grandpa_block(&self) -> NumberFor { + *self.persisted_state.best_grandpa_block_header.number() + } + + fn best_beefy_block(&self) -> NumberFor { + self.persisted_state.best_beefy_block + } + + fn voting_oracle(&self) -> &VoterOracle { + &self.persisted_state.voting_oracle + } + + fn active_rounds(&mut self) -> Option<&Rounds> { + self.persisted_state.voting_oracle.active_rounds() + } + /// Verify `active` validator set for `block` against the key store /// /// We want to make sure that we have _at least one_ key in our keystore that @@ -340,7 +424,7 @@ where debug!(target: "beefy", "🥩 New active validator set: {:?}", validator_set); // BEEFY should finalize a mandatory block during each session. - if let Some(active_session) = self.voting_oracle.rounds_mut() { + if let Some(active_session) = self.active_rounds() { if !active_session.mandatory_done() { debug!( target: "beefy", "🥩 New session {} while active session {} is still lagging.", @@ -357,7 +441,9 @@ where } let id = validator_set.id(); - self.voting_oracle.add_session(Rounds::new(new_session_start, validator_set)); + self.persisted_state + .voting_oracle + .add_session(Rounds::new(new_session_start, validator_set)); metric_set!(self, beefy_validator_set_id, id); info!( target: "beefy", @@ -370,9 +456,9 @@ where debug!(target: "beefy", "🥩 Finality notification: {:?}", notification); let header = ¬ification.header; - if *header.number() > *self.best_grandpa_block_header.number() { + if *header.number() > self.best_grandpa_block() { // update best GRANDPA finalized block we have seen - self.best_grandpa_block_header = header.clone(); + self.persisted_state.best_grandpa_block_header = header.clone(); // Check all (newly) finalized blocks for new session(s). let backend = self.backend.clone(); @@ -400,8 +486,8 @@ where vote: VoteMessage, AuthorityId, Signature>, ) -> Result<(), Error> { let block_num = vote.commitment.block_number; - let best_grandpa = *self.best_grandpa_block_header.number(); - match self.voting_oracle.triage_round(block_num, best_grandpa)? { + let best_grandpa = self.best_grandpa_block(); + match self.voting_oracle().triage_round(block_num, best_grandpa)? { RoundAction::Process => self.handle_vote( (vote.commitment.payload, vote.commitment.block_number), (vote.id, vote.signature), @@ -427,8 +513,8 @@ where VersionedFinalityProof::V1(ref sc) => sc, }; let block_num = signed_commitment.commitment.block_number; - let best_grandpa = *self.best_grandpa_block_header.number(); - match self.voting_oracle.triage_round(block_num, best_grandpa)? { + let best_grandpa = self.best_grandpa_block(); + match self.voting_oracle().triage_round(block_num, best_grandpa)? { RoundAction::Process => { debug!(target: "beefy", "🥩 Process justification for round: {:?}.", block_num); self.finalize(justification)? @@ -450,7 +536,11 @@ where ) -> Result<(), Error> { self.gossip_validator.note_round(round.1); - let rounds = self.voting_oracle.rounds_mut().ok_or(Error::UninitSession)?; + let rounds = self + .persisted_state + .voting_oracle + .active_rounds_mut() + .ok_or(Error::UninitSession)?; if rounds.add_vote(&round, vote, self_vote) { if let Some(signatures) = rounds.should_conclude(&round) { @@ -471,16 +561,26 @@ where info!(target: "beefy", "🥩 Round #{} concluded, finality_proof: {:?}.", round.1, finality_proof); // We created the `finality_proof` and know to be valid. + // New state is persisted after finalization. self.finalize(finality_proof)?; + } else { + if self_vote || self.voting_oracle().mandatory_pending() == Some(round.1) { + // Persist state after handling self vote to avoid double voting in case + // of voter restarts. + // Also persist state after handling mandatory block vote. + crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) + .map_err(|e| Error::Backend(e.to_string()))?; + } } } Ok(()) } /// Provide BEEFY finality for block based on `finality_proof`: - /// 1. Prune irrelevant past sessions from the oracle, + /// 1. Prune now-irrelevant past sessions from the oracle, /// 2. Set BEEFY best block, - /// 3. Send best block hash and `finality_proof` to RPC worker. + /// 3. Persist voter state, + /// 4. Send best block hash and `finality_proof` to RPC worker. /// /// Expects `finality proof` to be valid. fn finalize(&mut self, finality_proof: BeefyVersionedFinalityProof) -> Result<(), Error> { @@ -488,14 +588,15 @@ where VersionedFinalityProof::V1(ref sc) => sc.commitment.block_number, }; - // Conclude voting round for this block. - self.voting_oracle.rounds_mut().ok_or(Error::UninitSession)?.conclude(block_num); - // Prune any now "finalized" sessions from queue. - self.voting_oracle.try_prune(); + // Finalize inner round and update voting_oracle state. + self.persisted_state.voting_oracle.finalize(block_num)?; - if Some(block_num) > self.best_beefy_block { + if block_num > self.best_beefy_block() { // Set new best BEEFY block number. - self.best_beefy_block = Some(block_num); + self.persisted_state.best_beefy_block = block_num; + crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) + .map_err(|e| Error::Backend(e.to_string()))?; + metric_set!(self, beefy_best_block, block_num); self.on_demand_justifications.cancel_requests_older_than(block_num); @@ -528,7 +629,7 @@ where /// Handle previously buffered justifications and votes that now land in the voting interval. fn try_pending_justif_and_votes(&mut self) -> Result<(), Error> { - let best_grandpa = *self.best_grandpa_block_header.number(); + let best_grandpa = self.best_grandpa_block(); let _ph = PhantomData::::default(); fn to_process_for( @@ -546,7 +647,7 @@ where to_handle } // Interval of blocks for which we can process justifications and votes right now. - let mut interval = self.voting_oracle.accepted_interval(best_grandpa)?; + let mut interval = self.voting_oracle().accepted_interval(best_grandpa)?; // Process pending justifications. if !self.pending_justifications.is_empty() { @@ -558,7 +659,7 @@ where } } // Possibly new interval after processing justifications. - interval = self.voting_oracle.accepted_interval(best_grandpa)?; + interval = self.voting_oracle().accepted_interval(best_grandpa)?; } // Process pending votes. @@ -584,8 +685,8 @@ where fn try_to_vote(&mut self) -> Result<(), Error> { // Vote if there's now a new vote target. if let Some(target) = self - .voting_oracle - .voting_target(self.best_beefy_block, *self.best_grandpa_block_header.number()) + .voting_oracle() + .voting_target(self.best_beefy_block(), self.best_grandpa_block()) { metric_set!(self, beefy_should_vote_on, target); self.do_vote(target)?; @@ -601,8 +702,8 @@ where // Most of the time we get here, `target` is actually `best_grandpa`, // avoid getting header from backend in that case. - let target_header = if target_number == *self.best_grandpa_block_header.number() { - self.best_grandpa_block_header.clone() + let target_header = if target_number == self.best_grandpa_block() { + self.persisted_state.best_grandpa_block_header.clone() } else { self.backend .blockchain() @@ -624,7 +725,11 @@ where return Ok(()) }; - let rounds = self.voting_oracle.rounds_mut().ok_or(Error::UninitSession)?; + let rounds = self + .persisted_state + .voting_oracle + .active_rounds_mut() + .ok_or(Error::UninitSession)?; if !rounds.should_self_vote(&(payload.clone(), target_number)) { debug!(target: "beefy", "🥩 Don't double vote for block number: {:?}", target_number); return Ok(()) @@ -678,122 +783,16 @@ where Ok(()) } - /// Initialize BEEFY voter state. - /// - /// Should be called only once during worker initialization with latest GRANDPA finalized - /// `header` and the validator set `active` at that point. - fn initialize_voter(&mut self, header: &B::Header, active: ValidatorSet) { - // just a sanity check. - if let Some(rounds) = self.voting_oracle.rounds_mut() { - error!( - target: "beefy", - "🥩 Voting session already initialized at: {:?}, validator set id {}.", - rounds.session_start(), - rounds.validator_set_id(), - ); - return - } - - self.best_grandpa_block_header = header.clone(); - if active.id() == GENESIS_AUTHORITY_SET_ID { - // When starting from genesis, there is no session boundary digest. - // Just initialize `rounds` to Block #1 as BEEFY mandatory block. - info!(target: "beefy", "🥩 Initialize voting session at genesis, block 1."); - self.init_session_at(active, 1u32.into()); - } else { - // TODO (issue #11837): persist local progress to avoid following look-up during init. - let blockchain = self.backend.blockchain(); - let mut header = header.clone(); - - // Walk back the imported blocks and initialize voter either, at the last block with - // a BEEFY justification, or at this session's boundary; voter will resume from there. - loop { - if let Some(true) = blockchain - .justifications(header.hash()) - .ok() - .flatten() - .map(|justifs| justifs.get(BEEFY_ENGINE_ID).is_some()) - { - info!( - target: "beefy", - "🥩 Initialize voting session at last BEEFY finalized block: {:?}.", - *header.number() - ); - self.init_session_at(active, *header.number()); - // Mark the round as already finalized. - if let Some(round) = self.voting_oracle.rounds_mut() { - round.conclude(*header.number()); - } - self.best_beefy_block = Some(*header.number()); - break - } - - if let Some(validator_set) = find_authorities_change::(&header) { - info!( - target: "beefy", - "🥩 Initialize voting session at current session boundary: {:?}.", - *header.number() - ); - self.init_session_at(validator_set, *header.number()); - break - } - - // Move up the chain. - header = self - .client - .expect_header(BlockId::Hash(*header.parent_hash())) - // in case of db failure here we want to kill the worker - .expect("db failure, voter going down."); - } - } - } - - /// Wait for BEEFY runtime pallet to be available. - /// Should be called only once during worker initialization. - async fn wait_for_runtime_pallet(&mut self, finality: &mut Fuse>) { - let mut gossip_engine = &mut self.gossip_engine; - loop { - futures::select! { - notif = finality.next() => { - let notif = match notif { - Some(notif) => notif, - None => break - }; - let at = BlockId::hash(notif.header.hash()); - if let Some(active) = self.runtime.runtime_api().validator_set(&at).ok().flatten() { - self.initialize_voter(¬if.header, active); - if !self.network.is_major_syncing() { - if let Err(err) = self.try_to_vote() { - debug!(target: "beefy", "🥩 {}", err); - } - } - // Beefy pallet available and voter initialized. - break - } else { - trace!(target: "beefy", "🥩 Finality notification: {:?}", notif); - debug!(target: "beefy", "🥩 Waiting for BEEFY pallet to become available..."); - } - }, - _ = gossip_engine => { - break - } - } - } - } - /// Main loop for BEEFY worker. /// /// Wait for BEEFY runtime pallet to be available, then start the main async loop /// which is driven by finality notifications and gossiped votes. - pub(crate) async fn run(mut self) { - info!(target: "beefy", "🥩 run BEEFY worker, best grandpa: #{:?}.", self.best_grandpa_block_header.number()); - let mut block_import_justif = self.links.from_block_import_justif_stream.subscribe().fuse(); - // Subscribe to finality notifications before waiting for runtime pallet and reuse stream, - // so we process notifications for all finalized blocks after pallet is available. - let mut finality_notifications = self.client.finality_notification_stream().fuse(); - - self.wait_for_runtime_pallet(&mut finality_notifications).await; - trace!(target: "beefy", "🥩 BEEFY pallet available, starting voter."); + pub(crate) async fn run( + mut self, + mut block_import_justif: Fuse>>, + mut finality_notifications: Fuse>, + ) { + info!(target: "beefy", "🥩 run BEEFY worker, best grandpa: #{:?}.", self.best_grandpa_block()); let mut network_events = self.network.event_stream("network-gossip").fuse(); let mut votes = Box::pin( @@ -811,6 +810,22 @@ where ); loop { + // Don't bother voting or requesting justifications during major sync. + if !self.network.is_major_syncing() { + // If the current target is a mandatory block, + // make sure there's also an on-demand justification request out for it. + if let Some(block) = self.voting_oracle().mandatory_pending() { + // This only starts new request if there isn't already an active one. + self.on_demand_justifications.request(block); + } + // There were external events, 'state' is changed, author a vote if needed/possible. + if let Err(err) = self.try_to_vote() { + debug!(target: "beefy", "🥩 {}", err); + } + } else { + debug!(target: "beefy", "🥩 Skipping voting while major syncing."); + } + let mut gossip_engine = &mut self.gossip_engine; // Wait for, and handle external events. // The branches below only change 'state', actual voting happen afterwards, @@ -878,22 +893,6 @@ where if let Err(err) = self.try_pending_justif_and_votes() { debug!(target: "beefy", "🥩 {}", err); } - - // Don't bother voting or requesting justifications during major sync. - if !self.network.is_major_syncing() { - // If the current target is a mandatory block, - // make sure there's also an on-demand justification request out for it. - if let Some(block) = self.voting_oracle.mandatory_pending() { - // This only starts new request if there isn't already an active one. - self.on_demand_justifications.request(block); - } - // There were external events, 'state' is changed, author a vote if needed/possible. - if let Err(err) = self.try_to_vote() { - debug!(target: "beefy", "🥩 {}", err); - } - } else { - debug!(target: "beefy", "🥩 Skipping voting while major syncing."); - } } } @@ -914,7 +913,7 @@ where /// Scan the `header` digest log for a BEEFY validator set change. Return either the new /// validator set or `None` in case no validator set change has been signaled. -fn find_authorities_change(header: &B::Header) -> Option> +pub(crate) fn find_authorities_change(header: &B::Header) -> Option> where B: Block, { @@ -930,49 +929,32 @@ where /// Calculate next block number to vote on. /// /// Return `None` if there is no voteable target yet. -fn vote_target( - best_grandpa: N, - best_beefy: Option, - session_start: N, - min_delta: u32, -) -> Option +fn vote_target(best_grandpa: N, best_beefy: N, session_start: N, min_delta: u32) -> Option where N: AtLeast32Bit + Copy + Debug, { // if the mandatory block (session_start) does not have a beefy justification yet, // we vote on it - let target = match best_beefy { - None => { - debug!( - target: "beefy", - "🥩 vote target - mandatory block: #{:?}", - session_start, - ); - session_start - }, - Some(bbb) if bbb < session_start => { - debug!( - target: "beefy", - "🥩 vote target - mandatory block: #{:?}", - session_start, - ); - session_start - }, - Some(bbb) => { - let diff = best_grandpa.saturating_sub(bbb) + 1u32.into(); - let diff = diff.saturated_into::() / 2; - let target = bbb + min_delta.max(diff.next_power_of_two()).into(); - - debug!( - target: "beefy", - "🥩 vote target - diff: {:?}, next_power_of_two: {:?}, target block: #{:?}", - diff, - diff.next_power_of_two(), - target, - ); + let target = if best_beefy < session_start { + debug!( + target: "beefy", + "🥩 vote target - mandatory block: #{:?}", + session_start, + ); + session_start + } else { + let diff = best_grandpa.saturating_sub(best_beefy) + 1u32.into(); + let diff = diff.saturated_into::() / 2; + let target = best_beefy + min_delta.max(diff.next_power_of_two()).into(); + trace!( + target: "beefy", + "🥩 vote target - diff: {:?}, next_power_of_two: {:?}, target block: #{:?}", + diff, + diff.next_power_of_two(), + target, + ); - target - }, + target }; // Don't vote for targets until they've been finalized @@ -1001,22 +983,47 @@ pub(crate) mod tests { use futures::{executor::block_on, future::poll_fn, task::Poll}; use sc_client_api::{Backend as BackendT, HeaderBackend}; use sc_network::NetworkService; - use sc_network_test::{PeersFullClient, TestNetFactory}; + use sc_network_test::TestNetFactory; use sp_api::HeaderT; use sp_blockchain::Backend as BlockchainBackendT; + use sp_runtime::traits::{One, Zero}; use substrate_test_runtime_client::{ runtime::{Block, Digest, DigestItem, Header, H256}, - Backend, ClientExt, + Backend, }; + impl PersistedState { + pub fn voting_oracle(&self) -> &VoterOracle { + &self.voting_oracle + } + + pub fn active_round(&self) -> Option<&Rounds> { + self.voting_oracle.active_rounds() + } + + pub fn best_beefy_block(&self) -> NumberFor { + self.best_beefy_block + } + + pub fn best_grandpa_block(&self) -> NumberFor { + *self.best_grandpa_block_header.number() + } + } + + impl VoterOracle { + pub fn sessions(&self) -> &VecDeque> { + &self.sessions + } + } + fn create_beefy_worker( peer: &BeefyPeer, key: &Keyring, min_block_delta: u32, + genesis_validator_set: ValidatorSet, ) -> BeefyWorker< Block, Backend, - PeersFullClient, MmrRootProvider, TestApi, Arc>, @@ -1040,6 +1047,7 @@ pub(crate) mod tests { to_rpc_best_block_sender, }; + let backend = peer.client().as_backend(); let api = Arc::new(TestApi {}); let network = peer.network_service().clone(); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); @@ -1052,123 +1060,130 @@ pub(crate) mod tests { "/beefy/justifs/1".into(), known_peers.clone(), ); - let payload_provider = MmrRootProvider::new(api.clone()); + let at = BlockId::number(Zero::zero()); + let genesis_header = backend.blockchain().expect_header(at).unwrap(); + let persisted_state = PersistedState::checked_new( + genesis_header, + Zero::zero(), + vec![Rounds::new(One::one(), genesis_validator_set)].into(), + min_block_delta, + ) + .unwrap(); + let payload_provider = MmrRootProvider::new(api); let worker_params = crate::worker::WorkerParams { - client: peer.client().as_client(), - backend: peer.client().as_backend(), + backend, payload_provider, - runtime: api, key_store: Some(keystore).into(), known_peers, links, gossip_engine, gossip_validator, - min_block_delta, metrics: None, network, on_demand_justifications, + persisted_state, }; - BeefyWorker::<_, _, _, _, _, _>::new(worker_params) + BeefyWorker::<_, _, _, _, _>::new(worker_params) } #[test] fn vote_on_min_block_delta() { - let t = vote_target(1u32, Some(1), 1, 4); + let t = vote_target(1u32, 1, 1, 4); assert_eq!(None, t); - let t = vote_target(2u32, Some(1), 1, 4); + let t = vote_target(2u32, 1, 1, 4); assert_eq!(None, t); - let t = vote_target(4u32, Some(2), 1, 4); + let t = vote_target(4u32, 2, 1, 4); assert_eq!(None, t); - let t = vote_target(6u32, Some(2), 1, 4); + let t = vote_target(6u32, 2, 1, 4); assert_eq!(Some(6), t); - let t = vote_target(9u32, Some(4), 1, 4); + let t = vote_target(9u32, 4, 1, 4); assert_eq!(Some(8), t); - let t = vote_target(10u32, Some(10), 1, 8); + let t = vote_target(10u32, 10, 1, 8); assert_eq!(None, t); - let t = vote_target(12u32, Some(10), 1, 8); + let t = vote_target(12u32, 10, 1, 8); assert_eq!(None, t); - let t = vote_target(18u32, Some(10), 1, 8); + let t = vote_target(18u32, 10, 1, 8); assert_eq!(Some(18), t); } #[test] fn vote_on_power_of_two() { - let t = vote_target(1008u32, Some(1000), 1, 4); + let t = vote_target(1008u32, 1000, 1, 4); assert_eq!(Some(1004), t); - let t = vote_target(1016u32, Some(1000), 1, 4); + let t = vote_target(1016u32, 1000, 1, 4); assert_eq!(Some(1008), t); - let t = vote_target(1032u32, Some(1000), 1, 4); + let t = vote_target(1032u32, 1000, 1, 4); assert_eq!(Some(1016), t); - let t = vote_target(1064u32, Some(1000), 1, 4); + let t = vote_target(1064u32, 1000, 1, 4); assert_eq!(Some(1032), t); - let t = vote_target(1128u32, Some(1000), 1, 4); + let t = vote_target(1128u32, 1000, 1, 4); assert_eq!(Some(1064), t); - let t = vote_target(1256u32, Some(1000), 1, 4); + let t = vote_target(1256u32, 1000, 1, 4); assert_eq!(Some(1128), t); - let t = vote_target(1512u32, Some(1000), 1, 4); + let t = vote_target(1512u32, 1000, 1, 4); assert_eq!(Some(1256), t); - let t = vote_target(1024u32, Some(1), 1, 4); + let t = vote_target(1024u32, 1, 1, 4); assert_eq!(Some(513), t); } #[test] fn vote_on_target_block() { - let t = vote_target(1008u32, Some(1002), 1, 4); + let t = vote_target(1008u32, 1002, 1, 4); assert_eq!(Some(1006), t); - let t = vote_target(1010u32, Some(1002), 1, 4); + let t = vote_target(1010u32, 1002, 1, 4); assert_eq!(Some(1006), t); - let t = vote_target(1016u32, Some(1006), 1, 4); + let t = vote_target(1016u32, 1006, 1, 4); assert_eq!(Some(1014), t); - let t = vote_target(1022u32, Some(1006), 1, 4); + let t = vote_target(1022u32, 1006, 1, 4); assert_eq!(Some(1014), t); - let t = vote_target(1032u32, Some(1012), 1, 4); + let t = vote_target(1032u32, 1012, 1, 4); assert_eq!(Some(1028), t); - let t = vote_target(1044u32, Some(1012), 1, 4); + let t = vote_target(1044u32, 1012, 1, 4); assert_eq!(Some(1028), t); - let t = vote_target(1064u32, Some(1014), 1, 4); + let t = vote_target(1064u32, 1014, 1, 4); assert_eq!(Some(1046), t); - let t = vote_target(1078u32, Some(1014), 1, 4); + let t = vote_target(1078u32, 1014, 1, 4); assert_eq!(Some(1046), t); - let t = vote_target(1128u32, Some(1008), 1, 4); + let t = vote_target(1128u32, 1008, 1, 4); assert_eq!(Some(1072), t); - let t = vote_target(1136u32, Some(1008), 1, 4); + let t = vote_target(1136u32, 1008, 1, 4); assert_eq!(Some(1072), t); } #[test] fn vote_on_mandatory_block() { - let t = vote_target(1008u32, Some(1002), 1004, 4); + let t = vote_target(1008u32, 1002, 1004, 4); assert_eq!(Some(1004), t); - let t = vote_target(1016u32, Some(1006), 1007, 4); + let t = vote_target(1016u32, 1006, 1007, 4); assert_eq!(Some(1007), t); - let t = vote_target(1064u32, Some(1014), 1063, 4); + let t = vote_target(1064u32, 1014, 1063, 4); assert_eq!(Some(1063), t); - let t = vote_target(1320u32, Some(1012), 1234, 4); + let t = vote_target(1320u32, 1012, 1234, 4); assert_eq!(Some(1234), t); - let t = vote_target(1128u32, Some(1008), 1008, 4); + let t = vote_target(1128u32, 1008, 1008, 4); assert_eq!(Some(1072), t); } #[test] fn should_vote_target() { - let mut oracle = VoterOracle::::new(1); + let mut oracle = VoterOracle:: { min_block_delta: 1, sessions: VecDeque::new() }; // rounds not initialized -> should vote: `None` - assert_eq!(oracle.voting_target(None, 1), None); + assert_eq!(oracle.voting_target(0, 1), None); let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); @@ -1177,29 +1192,29 @@ pub(crate) mod tests { // under min delta oracle.min_block_delta = 4; - assert_eq!(oracle.voting_target(Some(1), 1), None); - assert_eq!(oracle.voting_target(Some(2), 5), None); + assert_eq!(oracle.voting_target(1, 1), None); + assert_eq!(oracle.voting_target(2, 5), None); // vote on min delta - assert_eq!(oracle.voting_target(Some(4), 9), Some(8)); + assert_eq!(oracle.voting_target(4, 9), Some(8)); oracle.min_block_delta = 8; - assert_eq!(oracle.voting_target(Some(10), 18), Some(18)); + assert_eq!(oracle.voting_target(10, 18), Some(18)); // vote on power of two oracle.min_block_delta = 1; - assert_eq!(oracle.voting_target(Some(1000), 1008), Some(1004)); - assert_eq!(oracle.voting_target(Some(1000), 1016), Some(1008)); + assert_eq!(oracle.voting_target(1000, 1008), Some(1004)); + assert_eq!(oracle.voting_target(1000, 1016), Some(1008)); // nothing new to vote on - assert_eq!(oracle.voting_target(Some(1000), 1000), None); + assert_eq!(oracle.voting_target(1000, 1000), None); // vote on mandatory oracle.sessions.clear(); oracle.add_session(Rounds::new(1000, validator_set.clone())); - assert_eq!(oracle.voting_target(None, 1008), Some(1000)); + assert_eq!(oracle.voting_target(0, 1008), Some(1000)); oracle.sessions.clear(); oracle.add_session(Rounds::new(1001, validator_set.clone())); - assert_eq!(oracle.voting_target(Some(1000), 1008), Some(1001)); + assert_eq!(oracle.voting_target(1000, 1008), Some(1001)); } #[test] @@ -1207,7 +1222,7 @@ pub(crate) mod tests { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut oracle = VoterOracle::::new(1); + let mut oracle = VoterOracle:: { min_block_delta: 1, sessions: VecDeque::new() }; // rounds not initialized -> should accept votes: `None` assert!(oracle.accepted_interval(1).is_err()); @@ -1295,7 +1310,7 @@ pub(crate) mod tests { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); // keystore doesn't contain other keys than validators' assert_eq!(worker.verify_validator_set(&1, &validator_set), Ok(())); @@ -1319,7 +1334,9 @@ pub(crate) mod tests { let validator_set = ValidatorSet::new(make_beefy_ids(&keys), 0).unwrap(); let mut net = BeefyTestNet::new(1); let backend = net.peer(0).client().as_backend(); - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); + // remove default session, will manually add custom one. + worker.persisted_state.voting_oracle.sessions.clear(); let keys = keys.iter().cloned().enumerate(); let (mut best_block_streams, mut finality_proofs) = @@ -1337,7 +1354,7 @@ pub(crate) mod tests { }; // no 'best beefy block' or finality proofs - assert_eq!(worker.best_beefy_block, None); + assert_eq!(worker.best_beefy_block(), 0); block_on(poll_fn(move |cx| { assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); assert_eq!(finality_proof.poll_next_unpin(cx), Poll::Pending); @@ -1351,11 +1368,14 @@ pub(crate) mod tests { let mut finality_proof = finality_proofs.drain(..).next().unwrap(); let justif = create_finality_proof(1); // create new session at block #1 - worker.voting_oracle.add_session(Rounds::new(1, validator_set.clone())); + worker + .persisted_state + .voting_oracle + .add_session(Rounds::new(1, validator_set.clone())); // try to finalize block #1 worker.finalize(justif.clone()).unwrap(); // verify block finalized - assert_eq!(worker.best_beefy_block, Some(1)); + assert_eq!(worker.best_beefy_block(), 1); block_on(poll_fn(move |cx| { // unknown hash -> nothing streamed assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); @@ -1380,14 +1400,14 @@ pub(crate) mod tests { let justif = create_finality_proof(2); // create new session at block #2 - worker.voting_oracle.add_session(Rounds::new(2, validator_set)); + worker.persisted_state.voting_oracle.add_session(Rounds::new(2, validator_set)); worker.finalize(justif).unwrap(); // verify old session pruned - assert_eq!(worker.voting_oracle.sessions.len(), 1); + assert_eq!(worker.voting_oracle().sessions.len(), 1); // new session starting at #2 is in front - assert_eq!(worker.voting_oracle.rounds_mut().unwrap().session_start(), 2); + assert_eq!(worker.active_rounds().unwrap().session_start(), 2); // verify block finalized - assert_eq!(worker.best_beefy_block, Some(2)); + assert_eq!(worker.best_beefy_block(), 2); block_on(poll_fn(move |cx| { match best_block_stream.poll_next_unpin(cx) { // expect Some(hash-of-block-2) @@ -1407,15 +1427,12 @@ pub(crate) mod tests { #[test] fn should_init_session() { - let keys = &[Keyring::Alice]; + let keys = &[Keyring::Alice, Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); - - assert!(worker.voting_oracle.sessions.is_empty()); + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); - worker.init_session_at(validator_set.clone(), 1); - let worker_rounds = worker.voting_oracle.rounds_mut().unwrap(); + let worker_rounds = worker.active_rounds().unwrap(); assert_eq!(worker_rounds.session_start(), 1); assert_eq!(worker_rounds.validators(), validator_set.validators()); assert_eq!(worker_rounds.validator_set_id(), validator_set.id()); @@ -1426,13 +1443,13 @@ pub(crate) mod tests { worker.init_session_at(new_validator_set.clone(), 11); // Since mandatory is not done for old rounds, we still get those. - let rounds = worker.voting_oracle.rounds_mut().unwrap(); + let rounds = worker.persisted_state.voting_oracle.active_rounds_mut().unwrap(); assert_eq!(rounds.validator_set_id(), validator_set.id()); // Let's finalize mandatory. rounds.test_set_mandatory_done(true); - worker.voting_oracle.try_prune(); + worker.persisted_state.voting_oracle.try_prune(); // Now we should get the next round. - let rounds = worker.voting_oracle.rounds_mut().unwrap(); + let rounds = worker.active_rounds().unwrap(); // Expect new values. assert_eq!(rounds.session_start(), 11); assert_eq!(rounds.validators(), new_validator_set.validators()); @@ -1444,7 +1461,9 @@ pub(crate) mod tests { let keys = &[Keyring::Alice, Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); + // remove default session, will manually add custom one. + worker.persisted_state.voting_oracle.sessions.clear(); fn new_vote( block_number: NumberFor, @@ -1470,8 +1489,11 @@ pub(crate) mod tests { Digest::default(), ); - worker.voting_oracle.add_session(Rounds::new(10, validator_set.clone())); - worker.best_grandpa_block_header = best_grandpa_header; + worker + .persisted_state + .voting_oracle + .add_session(Rounds::new(10, validator_set.clone())); + worker.persisted_state.best_grandpa_block_header = best_grandpa_header; // triage votes for blocks 10..13 worker.triage_incoming_vote(new_vote(10)).unwrap(); @@ -1492,118 +1514,16 @@ pub(crate) mod tests { assert!(votes.next().is_none()); // simulate mandatory done, and retry buffered votes - worker.voting_oracle.rounds_mut().unwrap().test_set_mandatory_done(true); + worker + .persisted_state + .voting_oracle + .active_rounds_mut() + .unwrap() + .test_set_mandatory_done(true); worker.try_pending_justif_and_votes().unwrap(); // all blocks <= grandpa finalized should have been handled, rest still buffered let mut votes = worker.pending_votes.values(); assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 21); assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 22); } - - #[test] - fn should_initialize_correct_voter() { - let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); - let mut net = BeefyTestNet::new(1); - let backend = net.peer(0).client().as_backend(); - - // push 15 blocks with `AuthorityChange` digests every 10 blocks - net.generate_blocks_and_sync(15, 10, &validator_set, false); - // finalize 13 without justifications - let hashof13 = - backend.blockchain().expect_block_hash_from_id(&BlockId::Number(13)).unwrap(); - net.peer(0).client().as_client().finalize_block(hashof13, None).unwrap(); - - // Test initialization at session boundary. - { - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); - - // initialize voter at block 13, expect rounds initialized at session_start = 10 - let header = backend.blockchain().header(BlockId::number(13)).unwrap().unwrap(); - worker.initialize_voter(&header, validator_set.clone()); - - // verify voter initialized with single session starting at block 10 - assert_eq!(worker.voting_oracle.sessions.len(), 1); - let rounds = worker.voting_oracle.rounds_mut().unwrap(); - assert_eq!(rounds.session_start(), 10); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - - // verify next vote target is mandatory block 10 - assert_eq!(worker.best_beefy_block, None); - assert_eq!(*worker.best_grandpa_block_header.number(), 13); - assert_eq!(worker.voting_oracle.voting_target(worker.best_beefy_block, 13), Some(10)); - } - - // Test corner-case where session boundary == last beefy finalized. - { - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); - - // import/append BEEFY justification for session boundary block 10 - let commitment = Commitment { - payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), - block_number: 10, - validator_set_id: validator_set.id(), - }; - let justif = VersionedFinalityProof::<_, Signature>::V1(SignedCommitment { - commitment, - signatures: vec![None], - }); - let hashof10 = - backend.blockchain().expect_block_hash_from_id(&BlockId::Number(10)).unwrap(); - backend - .append_justification(hashof10, (BEEFY_ENGINE_ID, justif.encode())) - .unwrap(); - - // initialize voter at block 13, expect rounds initialized at last beefy finalized 10 - let header = backend.blockchain().header(BlockId::number(13)).unwrap().unwrap(); - worker.initialize_voter(&header, validator_set.clone()); - - // verify voter initialized with single session starting at block 10 - assert_eq!(worker.voting_oracle.sessions.len(), 1); - let rounds = worker.voting_oracle.rounds_mut().unwrap(); - assert_eq!(rounds.session_start(), 10); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - - // verify next vote target is mandatory block 10 - assert_eq!(worker.best_beefy_block, Some(10)); - assert_eq!(*worker.best_grandpa_block_header.number(), 13); - assert_eq!(worker.voting_oracle.voting_target(worker.best_beefy_block, 13), Some(12)); - } - - // Test initialization at last BEEFY finalized. - { - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); - - // import/append BEEFY justification for block 12 - let commitment = Commitment { - payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), - block_number: 12, - validator_set_id: validator_set.id(), - }; - let justif = VersionedFinalityProof::<_, Signature>::V1(SignedCommitment { - commitment, - signatures: vec![None], - }); - let hashof12 = - backend.blockchain().expect_block_hash_from_id(&BlockId::Number(12)).unwrap(); - backend - .append_justification(hashof12, (BEEFY_ENGINE_ID, justif.encode())) - .unwrap(); - - // initialize voter at block 13, expect rounds initialized at last beefy finalized 12 - let header = backend.blockchain().header(BlockId::number(13)).unwrap().unwrap(); - worker.initialize_voter(&header, validator_set.clone()); - - // verify voter initialized with single session starting at block 12 - assert_eq!(worker.voting_oracle.sessions.len(), 1); - let rounds = worker.voting_oracle.rounds_mut().unwrap(); - assert_eq!(rounds.session_start(), 12); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - - // verify next vote target is 13 - assert_eq!(worker.best_beefy_block, Some(12)); - assert_eq!(*worker.best_grandpa_block_header.number(), 13); - assert_eq!(worker.voting_oracle.voting_target(worker.best_beefy_block, 13), Some(13)); - } - } } diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 305b158124b67..4cb23107e7843 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -34,6 +34,7 @@ use sp_std::prelude::*; use beefy_primitives::{ AuthorityIndex, ConsensusLog, OnNewValidatorSet, ValidatorSet, BEEFY_ENGINE_ID, + GENESIS_AUTHORITY_SET_ID, }; #[cfg(test)] @@ -162,7 +163,7 @@ impl Pallet { BoundedSlice::::try_from(authorities.as_slice()) .map_err(|_| ())?; - let id = 0; + let id = GENESIS_AUTHORITY_SET_ID; >::put(bounded_authorities); >::put(id); // Like `pallet_session`, initialize the next validator set as well. diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index 453eb67315d4e..d7ac091491bff 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -113,7 +113,7 @@ pub mod crypto { /// The `ConsensusEngineId` of BEEFY. pub const BEEFY_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"BEEF"; -/// Authority set id starts with zero at genesis +/// Authority set id starts with zero at BEEFY pallet genesis. pub const GENESIS_AUTHORITY_SET_ID: u64 = 0; /// A typedef for validator set id. From 69662c4b912f1afc8f231c92981620234fa4bc65 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 21 Nov 2022 23:08:23 +0100 Subject: [PATCH 1398/1472] [Fix] Get target count from TargetList instead of storage (#12748) Co-authored-by: parity-processbot <> --- frame/staking/src/pallet/impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 9be01dd823104..c22a2bd2d1f77 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -948,7 +948,7 @@ impl ElectionDataProvider for Pallet { } fn electable_targets(maybe_max_len: Option) -> data_provider::Result> { - let target_count = Validators::::count(); + let target_count = T::TargetList::count(); // We can't handle this case yet -- return an error. if maybe_max_len.map_or(false, |max_len| target_count > max_len as u32) { From 6cb4b6799de6f784f4c42eb01a76a8fa67039a67 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Tue, 22 Nov 2022 10:19:17 +0200 Subject: [PATCH 1399/1472] Move block/state/warpc sync requests/responses to `ChainSync` (#12739) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move block/state/warpc sync requests/responses to `ChainSync` * Apply suggestions from code review Co-authored-by: Bastian Köcher * Apply review suggestions * cargo-fmt + doc fix * Fix tests Co-authored-by: Bastian Köcher --- Cargo.lock | 5 +- client/network/common/src/sync.rs | 81 +- client/network/src/behaviour.rs | 51 +- client/network/src/config.rs | 33 - client/network/src/protocol.rs | 396 +---- client/network/src/service.rs | 100 -- .../network/src/service/tests/chain_sync.rs | 17 +- client/network/src/service/tests/mod.rs | 67 +- client/network/sync/Cargo.toml | 1 + client/network/sync/src/lib.rs | 1523 +++++++++++------ client/network/sync/src/mock.rs | 31 +- client/network/sync/src/service/mock.rs | 32 +- client/network/sync/src/service/network.rs | 37 +- client/network/sync/src/tests.rs | 18 +- client/network/test/src/lib.rs | 35 +- client/service/src/builder.rs | 31 +- 16 files changed, 1213 insertions(+), 1245 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a22cfa8ba8dd6..ca0ebee0ac475 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -340,9 +340,9 @@ checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] name = "async-trait" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" dependencies = [ "proc-macro2", "quote", @@ -8321,6 +8321,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "async-std", + "async-trait", "fork-tree", "futures", "libp2p", diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index dd216b2a5295a..bed9935698769 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -24,14 +24,16 @@ pub mod warp; use libp2p::PeerId; use message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}; -use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; +use sc_consensus::{ + import_queue::RuntimeOrigin, BlockImportError, BlockImportStatus, IncomingBlock, +}; use sp_consensus::BlockOrigin; use sp_runtime::{ traits::{Block as BlockT, NumberFor}, Justifications, }; use std::{any::Any, fmt, fmt::Formatter, task::Poll}; -use warp::{EncodedProof, WarpProofRequest, WarpSyncProgress}; +use warp::WarpSyncProgress; /// The sync status of a peer we are trying to sync with #[derive(Debug)] @@ -123,7 +125,7 @@ pub enum OnBlockJustification { }, } -/// Result of [`ChainSync::on_state_data`]. +/// Result of `ChainSync::on_state_data`. #[derive(Debug)] pub enum OnStateData { /// The block and state that should be imported. @@ -132,6 +134,20 @@ pub enum OnStateData { Continue, } +/// Block or justification request polled from `ChainSync` +#[derive(Debug)] +pub enum ImportResult { + BlockImport(BlockOrigin, Vec>), + JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), +} + +/// Value polled from `ChainSync` +#[derive(Debug)] +pub enum PollResult { + Import(ImportResult), + Announce(PollBlockAnnounceValidation), +} + /// Result of [`ChainSync::poll_block_announce_validation`]. #[derive(Debug, Clone, PartialEq, Eq)] pub enum PollBlockAnnounceValidation { @@ -186,6 +202,13 @@ pub struct Metrics { pub justifications: metrics::Metrics, } +#[derive(Debug)] +pub enum PeerRequest { + Block(BlockRequest), + State, + WarpProof, +} + /// Wrapper for implementation-specific state request. /// /// NOTE: Implementation must be able to encode and decode it for network purposes. @@ -250,6 +273,9 @@ pub trait ChainSync: Send { /// Returns the current number of peers stored within this state machine. fn num_peers(&self) -> usize; + /// Returns the number of peers we're connected to and that are being queried. + fn num_active_peers(&self) -> usize; + /// Handle a new connected peer. /// /// Call this method whenever we connect to a new peer. @@ -277,22 +303,6 @@ pub trait ChainSync: Send { number: NumberFor, ); - /// Get an iterator over all scheduled justification requests. - fn justification_requests<'a>( - &'a mut self, - ) -> Box)> + 'a>; - - /// Get an iterator over all block requests of all peers. - fn block_requests<'a>( - &'a mut self, - ) -> Box)> + 'a>; - - /// Get a state request, if any. - fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)>; - - /// Get a warp sync request, if any. - fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)>; - /// Handle a response from the remote to a block request that we made. /// /// `request` must be the original request that triggered `response`. @@ -307,16 +317,6 @@ pub trait ChainSync: Send { response: BlockResponse, ) -> Result, BadPeer>; - /// Handle a response from the remote to a state request that we made. - fn on_state_data( - &mut self, - who: &PeerId, - response: OpaqueStateResponse, - ) -> Result, BadPeer>; - - /// Handle a response from the remote to a warp proof request that we made. - fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer>; - /// Handle a response from the remote to a justification request that we made. /// /// `request` must be the original request that triggered `response`. @@ -383,15 +383,6 @@ pub trait ChainSync: Send { /// Return some key metrics. fn metrics(&self) -> Metrics; - /// Create implementation-specific block request. - fn create_opaque_block_request(&self, request: &BlockRequest) -> OpaqueBlockRequest; - - /// Encode implementation-specific block request. - fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String>; - - /// Decode implementation-specific block response. - fn decode_block_response(&self, response: &[u8]) -> Result; - /// Access blocks from implementation-specific block response. fn block_response_into_blocks( &self, @@ -399,19 +390,13 @@ pub trait ChainSync: Send { response: OpaqueBlockResponse, ) -> Result>, String>; - /// Encode implementation-specific state request. - fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String>; - - /// Decode implementation-specific state response. - fn decode_state_response(&self, response: &[u8]) -> Result; - /// Advance the state of `ChainSync` /// /// Internally calls [`ChainSync::poll_block_announce_validation()`] and /// this function should be polled until it returns [`Poll::Pending`] to /// consume all pending events. - fn poll( - &mut self, - cx: &mut std::task::Context, - ) -> Poll>; + fn poll(&mut self, cx: &mut std::task::Context) -> Poll>; + + /// Send block request to peer + fn send_block_request(&mut self, who: PeerId, request: BlockRequest); } diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 2e646956e9d8c..48d6127f642c3 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -40,7 +40,6 @@ use sc_network_common::{ ProtocolName, }, request_responses::{IfDisconnected, ProtocolConfig, RequestFailure}, - sync::{warp::WarpProofRequest, OpaqueBlockRequest, OpaqueStateRequest}, }; use sc_peerset::{PeersetHandle, ReputationChange}; use sp_blockchain::HeaderBackend; @@ -163,36 +162,6 @@ pub enum BehaviourOut { messages: Vec<(ProtocolName, Bytes)>, }, - /// A new block request must be emitted. - BlockRequest { - /// Node we send the request to. - target: PeerId, - /// Opaque implementation-specific block request. - request: OpaqueBlockRequest, - /// One-shot channel to receive the response. - pending_response: oneshot::Sender, RequestFailure>>, - }, - - /// A new state request must be emitted. - StateRequest { - /// Node we send the request to. - target: PeerId, - /// Opaque implementation-specific state request. - request: OpaqueStateRequest, - /// One-shot channel to receive the response. - pending_response: oneshot::Sender, RequestFailure>>, - }, - - /// A new warp sync request must be emitted. - WarpSyncRequest { - /// Node we send the request to. - target: PeerId, - /// Warp sync request. - request: WarpProofRequest, - /// One-shot channel to receive the response. - pending_response: oneshot::Sender, RequestFailure>>, - }, - /// Now connected to a new peer for syncing purposes. SyncConnected(PeerId), @@ -230,21 +199,9 @@ where user_agent: String, local_public_key: PublicKey, disco_config: DiscoveryConfig, - block_request_protocol_config: ProtocolConfig, - state_request_protocol_config: ProtocolConfig, - warp_sync_protocol_config: Option, - light_client_request_protocol_config: ProtocolConfig, - // All remaining request protocol configs. - mut request_response_protocols: Vec, + request_response_protocols: Vec, peerset: PeersetHandle, ) -> Result { - if let Some(config) = warp_sync_protocol_config { - request_response_protocols.push(config); - } - request_response_protocols.push(block_request_protocol_config); - request_response_protocols.push(state_request_protocol_config); - request_response_protocols.push(light_client_request_protocol_config); - Ok(Self { substrate, peer_info: peer_info::PeerInfoBehaviour::new(user_agent, local_public_key), @@ -356,12 +313,6 @@ impl From> for BehaviourOut { BehaviourOut::BlockImport(origin, blocks), CustomMessageOutcome::JustificationImport(origin, hash, nb, justification) => BehaviourOut::JustificationImport(origin, hash, nb, justification), - CustomMessageOutcome::BlockRequest { target, request, pending_response } => - BehaviourOut::BlockRequest { target, request, pending_response }, - CustomMessageOutcome::StateRequest { target, request, pending_response } => - BehaviourOut::StateRequest { target, request, pending_response }, - CustomMessageOutcome::WarpSyncRequest { target, request, pending_response } => - BehaviourOut::WarpSyncRequest { target, request, pending_response }, CustomMessageOutcome::NotificationStreamOpened { remote, protocol, diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 14f7e8ffbf76a..50d8e2baba60f 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -101,39 +101,6 @@ where /// Block announce protocol configuration pub block_announce_config: NonDefaultSetConfig, - /// Request response configuration for the block request protocol. - /// - /// [`RequestResponseConfig::name`] is used to tag outgoing block requests with the correct - /// protocol name. In addition all of [`RequestResponseConfig`] is used to handle incoming - /// block requests, if enabled. - /// - /// Can be constructed either via - /// `sc_network_sync::block_request_handler::generate_protocol_config` allowing outgoing but - /// not incoming requests, or constructed via `sc_network_sync::block_request_handler:: - /// BlockRequestHandler::new` allowing both outgoing and incoming requests. - pub block_request_protocol_config: RequestResponseConfig, - - /// Request response configuration for the light client request protocol. - /// - /// Can be constructed either via - /// `sc_network_light::light_client_requests::generate_protocol_config` allowing outgoing but - /// not incoming requests, or constructed via - /// `sc_network_light::light_client_requests::handler::LightClientRequestHandler::new` - /// allowing both outgoing and incoming requests. - pub light_client_request_protocol_config: RequestResponseConfig, - - /// Request response configuration for the state request protocol. - /// - /// Can be constructed either via - /// `sc_network_sync::state_request_handler::generate_protocol_config` allowing outgoing but - /// not incoming requests, or constructed via - /// `sc_network_sync::state_request_handler::StateRequestHandler::new` allowing - /// both outgoing and incoming requests. - pub state_request_protocol_config: RequestResponseConfig, - - /// Optional warp sync protocol config. - pub warp_sync_protocol_config: Option, - /// Request response protocol configurations pub request_response_protocol_configs: Vec, } diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 63d060f423773..8c1dd39b49be3 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -20,10 +20,9 @@ use crate::config; use bytes::Bytes; use codec::{Decode, DecodeAll, Encode}; -use futures::{channel::oneshot, prelude::*}; +use futures::prelude::*; use libp2p::{ core::{connection::ConnectionId, transport::ListenerId, ConnectedPoint}, - request_response::OutboundFailure, swarm::{ ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters, @@ -43,15 +42,9 @@ use sc_network_common::{ config::NonReservedPeerMode, error, protocol::{role::Roles, ProtocolName}, - request_responses::RequestFailure, sync::{ - message::{ - BlockAnnounce, BlockAnnouncesHandshake, BlockAttributes, BlockData, BlockRequest, - BlockResponse, BlockState, - }, - warp::{EncodedProof, WarpProofRequest}, - BadPeer, ChainSync, OnBlockData, OnBlockJustification, OnStateData, OpaqueBlockRequest, - OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PollBlockAnnounceValidation, + message::{BlockAnnounce, BlockAnnouncesHandshake, BlockData, BlockResponse, BlockState}, + BadPeer, ChainSync, ImportResult, OnBlockData, PollBlockAnnounceValidation, PollResult, SyncStatus, }, utils::{interval, LruHashSet}, @@ -102,18 +95,12 @@ const LIGHT_MAXIMAL_BLOCKS_DIFFERENCE: u64 = 8192; mod rep { use sc_peerset::ReputationChange as Rep; - /// Reputation change when a peer doesn't respond in time to our messages. - pub const TIMEOUT: Rep = Rep::new(-(1 << 10), "Request timeout"); - /// Reputation change when a peer refuses a request. - pub const REFUSED: Rep = Rep::new(-(1 << 10), "Request refused"); /// Reputation change when we are a light client and a peer is behind us. pub const PEER_BEHIND_US_LIGHT: Rep = Rep::new(-(1 << 8), "Useless for a light peer"); /// We received a message that failed to decode. pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); /// Peer has different genesis. pub const GENESIS_MISMATCH: Rep = Rep::new_fatal("Genesis mismatch"); - /// Peer is on unsupported protocol version. - pub const BAD_PROTOCOL: Rep = Rep::new_fatal("Unsupported protocol"); /// Peer role does not match (e.g. light peer connecting to another light peer). pub const BAD_ROLE: Rep = Rep::new_fatal("Unsupported role"); /// Peer send us a block announcement that failed at validation. @@ -204,19 +191,10 @@ pub struct Protocol { block_announce_data_cache: LruCache>, } -#[derive(Debug)] -enum PeerRequest { - Block(BlockRequest), - State, - WarpProof, -} - /// Peer information #[derive(Debug)] struct Peer { info: PeerInfo, - /// Current request, if any. Started by emitting [`CustomMessageOutcome::BlockRequest`]. - request: Option<(PeerRequest, oneshot::Receiver, RequestFailure>>)>, /// Holds a set of blocks known to this peer. known_blocks: LruHashSet, } @@ -432,7 +410,7 @@ where /// Returns the number of peers we're connected to and that are being queried. pub fn num_active_peers(&self) -> usize { - self.peers.values().filter(|p| p.request.is_some()).count() + self.chain_sync.num_active_peers() } /// Current global sync state. @@ -521,106 +499,6 @@ where self.peerset_handle.report_peer(who, reputation) } - /// Must be called in response to a [`CustomMessageOutcome::BlockRequest`] being emitted. - /// Must contain the same `PeerId` and request that have been emitted. - pub fn on_block_response( - &mut self, - peer_id: PeerId, - request: BlockRequest, - response: OpaqueBlockResponse, - ) -> CustomMessageOutcome { - let blocks = match self.chain_sync.block_response_into_blocks(&request, response) { - Ok(blocks) => blocks, - Err(err) => { - debug!(target: "sync", "Failed to decode block response from {}: {}", peer_id, err); - self.peerset_handle.report_peer(peer_id, rep::BAD_MESSAGE); - return CustomMessageOutcome::None - }, - }; - - let block_response = BlockResponse:: { id: request.id, blocks }; - - let blocks_range = || match ( - block_response - .blocks - .first() - .and_then(|b| b.header.as_ref().map(|h| h.number())), - block_response.blocks.last().and_then(|b| b.header.as_ref().map(|h| h.number())), - ) { - (Some(first), Some(last)) if first != last => format!(" ({}..{})", first, last), - (Some(first), Some(_)) => format!(" ({})", first), - _ => Default::default(), - }; - trace!(target: "sync", "BlockResponse {} from {} with {} blocks {}", - block_response.id, - peer_id, - block_response.blocks.len(), - blocks_range(), - ); - - if request.fields == BlockAttributes::JUSTIFICATION { - match self.chain_sync.on_block_justification(peer_id, block_response) { - Ok(OnBlockJustification::Nothing) => CustomMessageOutcome::None, - Ok(OnBlockJustification::Import { peer, hash, number, justifications }) => - CustomMessageOutcome::JustificationImport(peer, hash, number, justifications), - Err(BadPeer(id, repu)) => { - self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); - self.peerset_handle.report_peer(id, repu); - CustomMessageOutcome::None - }, - } - } else { - match self.chain_sync.on_block_data(&peer_id, Some(request), block_response) { - Ok(OnBlockData::Import(origin, blocks)) => - CustomMessageOutcome::BlockImport(origin, blocks), - Ok(OnBlockData::Request(peer, req)) => - prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, peer, req), - Ok(OnBlockData::Continue) => CustomMessageOutcome::None, - Err(BadPeer(id, repu)) => { - self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); - self.peerset_handle.report_peer(id, repu); - CustomMessageOutcome::None - }, - } - } - } - - /// Must be called in response to a [`CustomMessageOutcome::StateRequest`] being emitted. - /// Must contain the same `PeerId` and request that have been emitted. - pub fn on_state_response( - &mut self, - peer_id: PeerId, - response: OpaqueStateResponse, - ) -> CustomMessageOutcome { - match self.chain_sync.on_state_data(&peer_id, response) { - Ok(OnStateData::Import(origin, block)) => - CustomMessageOutcome::BlockImport(origin, vec![block]), - Ok(OnStateData::Continue) => CustomMessageOutcome::None, - Err(BadPeer(id, repu)) => { - self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); - self.peerset_handle.report_peer(id, repu); - CustomMessageOutcome::None - }, - } - } - - /// Must be called in response to a [`CustomMessageOutcome::WarpSyncRequest`] being emitted. - /// Must contain the same `PeerId` and request that have been emitted. - pub fn on_warp_sync_response( - &mut self, - peer_id: PeerId, - response: EncodedProof, - ) -> CustomMessageOutcome { - match self.chain_sync.on_warp_sync_data(&peer_id, response) { - Ok(()) => CustomMessageOutcome::None, - Err(BadPeer(id, repu)) => { - self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); - self.peerset_handle.report_peer(id, repu); - CustomMessageOutcome::None - }, - } - } - /// Perform time based maintenance. /// /// > **Note**: This method normally doesn't have to be called except for testing purposes. @@ -721,7 +599,6 @@ where best_hash: status.best_hash, best_number: status.best_number, }, - request: None, known_blocks: LruHashSet::new( NonZeroUsize::new(MAX_KNOWN_BLOCKS).expect("Constant is nonzero"), ), @@ -750,12 +627,7 @@ where .push_back(CustomMessageOutcome::PeerNewBest(who, status.best_number)); if let Some(req) = req { - self.pending_messages.push_back(prepare_block_request( - self.chain_sync.as_ref(), - &mut self.peers, - who, - req, - )); + self.chain_sync.send_block_request(who, req); } Ok(()) @@ -921,8 +793,10 @@ where match blocks_to_import { Ok(OnBlockData::Import(origin, blocks)) => CustomMessageOutcome::BlockImport(origin, blocks), - Ok(OnBlockData::Request(peer, req)) => - prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, peer, req), + Ok(OnBlockData::Request(peer, req)) => { + self.chain_sync.send_block_request(peer, req); + CustomMessageOutcome::None + }, Ok(OnBlockData::Continue) => CustomMessageOutcome::None, Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); @@ -963,14 +837,7 @@ where let results = self.chain_sync.on_blocks_processed(imported, count, results); for result in results { match result { - Ok((id, req)) => { - self.pending_messages.push_back(prepare_block_request( - self.chain_sync.as_ref(), - &mut self.peers, - id, - req, - )); - }, + Ok((id, req)) => self.chain_sync.send_block_request(id, req), Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu) @@ -1096,16 +963,6 @@ where } } - /// Encode implementation-specific block request. - pub fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String> { - self.chain_sync.encode_block_request(request) - } - - /// Encode implementation-specific state request. - pub fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String> { - self.chain_sync.encode_state_request(request) - } - fn report_metrics(&self) { if let Some(metrics) = &self.metrics { let n = u64::try_from(self.peers.len()).unwrap_or(std::u64::MAX); @@ -1136,49 +993,6 @@ where } } -fn prepare_block_request( - chain_sync: &dyn ChainSync, - peers: &mut HashMap>, - who: PeerId, - request: BlockRequest, -) -> CustomMessageOutcome { - let (tx, rx) = oneshot::channel(); - - if let Some(ref mut peer) = peers.get_mut(&who) { - peer.request = Some((PeerRequest::Block(request.clone()), rx)); - } - - let request = chain_sync.create_opaque_block_request(&request); - - CustomMessageOutcome::BlockRequest { target: who, request, pending_response: tx } -} - -fn prepare_state_request( - peers: &mut HashMap>, - who: PeerId, - request: OpaqueStateRequest, -) -> CustomMessageOutcome { - let (tx, rx) = oneshot::channel(); - - if let Some(ref mut peer) = peers.get_mut(&who) { - peer.request = Some((PeerRequest::State, rx)); - } - CustomMessageOutcome::StateRequest { target: who, request, pending_response: tx } -} - -fn prepare_warp_sync_request( - peers: &mut HashMap>, - who: PeerId, - request: WarpProofRequest, -) -> CustomMessageOutcome { - let (tx, rx) = oneshot::channel(); - - if let Some(ref mut peer) = peers.get_mut(&who) { - peer.request = Some((PeerRequest::WarpProof, rx)); - } - CustomMessageOutcome::WarpSyncRequest { target: who, request, pending_response: tx } -} - /// Outcome of an incoming custom message. #[derive(Debug)] #[must_use] @@ -1210,24 +1024,6 @@ pub enum CustomMessageOutcome { remote: PeerId, messages: Vec<(ProtocolName, Bytes)>, }, - /// A new block request must be emitted. - BlockRequest { - target: PeerId, - request: OpaqueBlockRequest, - pending_response: oneshot::Sender, RequestFailure>>, - }, - /// A new storage request must be emitted. - StateRequest { - target: PeerId, - request: OpaqueStateRequest, - pending_response: oneshot::Sender, RequestFailure>>, - }, - /// A new warp sync request must be emitted. - WarpSyncRequest { - target: PeerId, - request: WarpProofRequest, - pending_response: oneshot::Sender, RequestFailure>>, - }, /// Peer has a reported a new head of chain. PeerNewBest(PeerId, NumberFor), /// Now connected to a new peer for syncing purposes. @@ -1305,165 +1101,35 @@ where return Poll::Ready(NetworkBehaviourAction::GenerateEvent(message)) } - // Check for finished outgoing requests. - let mut finished_block_requests = Vec::new(); - let mut finished_state_requests = Vec::new(); - let mut finished_warp_sync_requests = Vec::new(); - for (id, peer) in self.peers.iter_mut() { - if let Peer { request: Some((_, pending_response)), .. } = peer { - match pending_response.poll_unpin(cx) { - Poll::Ready(Ok(Ok(resp))) => { - let (req, _) = peer.request.take().unwrap(); - match req { - PeerRequest::Block(req) => { - let response = - match self.chain_sync.decode_block_response(&resp[..]) { - Ok(proto) => proto, - Err(e) => { - debug!( - target: "sync", - "Failed to decode block response from peer {:?}: {:?}.", - id, - e - ); - self.peerset_handle.report_peer(*id, rep::BAD_MESSAGE); - self.behaviour - .disconnect_peer(id, HARDCODED_PEERSETS_SYNC); - continue - }, - }; - - finished_block_requests.push((*id, req, response)); - }, - PeerRequest::State => { - let response = - match self.chain_sync.decode_state_response(&resp[..]) { - Ok(proto) => proto, - Err(e) => { - debug!( - target: "sync", - "Failed to decode state response from peer {:?}: {:?}.", - id, - e - ); - self.peerset_handle.report_peer(*id, rep::BAD_MESSAGE); - self.behaviour - .disconnect_peer(id, HARDCODED_PEERSETS_SYNC); - continue - }, - }; - - finished_state_requests.push((*id, response)); - }, - PeerRequest::WarpProof => { - finished_warp_sync_requests.push((*id, resp)); - }, - } - }, - Poll::Ready(Ok(Err(e))) => { - peer.request.take(); - debug!(target: "sync", "Request to peer {:?} failed: {:?}.", id, e); - - match e { - RequestFailure::Network(OutboundFailure::Timeout) => { - self.peerset_handle.report_peer(*id, rep::TIMEOUT); - self.behaviour.disconnect_peer(id, HARDCODED_PEERSETS_SYNC); - }, - RequestFailure::Network(OutboundFailure::UnsupportedProtocols) => { - self.peerset_handle.report_peer(*id, rep::BAD_PROTOCOL); - self.behaviour.disconnect_peer(id, HARDCODED_PEERSETS_SYNC); - }, - RequestFailure::Network(OutboundFailure::DialFailure) => { - self.behaviour.disconnect_peer(id, HARDCODED_PEERSETS_SYNC); - }, - RequestFailure::Refused => { - self.peerset_handle.report_peer(*id, rep::REFUSED); - self.behaviour.disconnect_peer(id, HARDCODED_PEERSETS_SYNC); - }, - RequestFailure::Network(OutboundFailure::ConnectionClosed) | - RequestFailure::NotConnected => { - self.behaviour.disconnect_peer(id, HARDCODED_PEERSETS_SYNC); - }, - RequestFailure::UnknownProtocol => { - debug_assert!( - false, - "Block request protocol should always be known." - ); - }, - RequestFailure::Obsolete => { - debug_assert!( - false, - "Can not receive `RequestFailure::Obsolete` after dropping the \ - response receiver.", - ); - }, - } - }, - Poll::Ready(Err(oneshot::Canceled)) => { - peer.request.take(); - trace!( - target: "sync", - "Request to peer {:?} failed due to oneshot being canceled.", - id, - ); - self.behaviour.disconnect_peer(id, HARDCODED_PEERSETS_SYNC); - }, - Poll::Pending => {}, - } - } - } - for (id, req, response) in finished_block_requests { - let ev = self.on_block_response(id, req, response); - self.pending_messages.push_back(ev); - } - for (id, response) in finished_state_requests { - let ev = self.on_state_response(id, response); - self.pending_messages.push_back(ev); - } - for (id, response) in finished_warp_sync_requests { - let ev = self.on_warp_sync_response(id, EncodedProof(response)); - self.pending_messages.push_back(ev); - } - - while let Poll::Ready(Some(())) = self.tick_timeout.poll_next_unpin(cx) { - self.tick(); - } - - for (id, request) in self - .chain_sync - .block_requests() - .map(|(peer_id, request)| (peer_id, request)) - .collect::>() - { - let event = - prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, id, request); - self.pending_messages.push_back(event); - } - if let Some((id, request)) = self.chain_sync.state_request() { - let event = prepare_state_request(&mut self.peers, id, request); - self.pending_messages.push_back(event); - } - for (id, request) in self.chain_sync.justification_requests().collect::>() { - let event = - prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, id, request); - self.pending_messages.push_back(event); - } - if let Some((id, request)) = self.chain_sync.warp_sync_request() { - let event = prepare_warp_sync_request(&mut self.peers, id, request); - self.pending_messages.push_back(event); - } - // Advance the state of `ChainSync` // // Process any received requests received from `NetworkService` and // check if there is any block announcement validation finished. while let Poll::Ready(result) = self.chain_sync.poll(cx) { - match self.process_block_announce_validation_result(result) { - CustomMessageOutcome::None => {}, - outcome => self.pending_messages.push_back(outcome), + match result { + PollResult::Import(import) => self.pending_messages.push_back(match import { + ImportResult::BlockImport(origin, blocks) => + CustomMessageOutcome::BlockImport(origin, blocks), + ImportResult::JustificationImport(origin, hash, number, justifications) => + CustomMessageOutcome::JustificationImport( + origin, + hash, + number, + justifications, + ), + }), + PollResult::Announce(announce) => + match self.process_block_announce_validation_result(announce) { + CustomMessageOutcome::None => {}, + outcome => self.pending_messages.push_back(outcome), + }, } } + while let Poll::Ready(Some(())) = self.tick_timeout.poll_next_unpin(cx) { + self.tick(); + } + if let Some(message) = self.pending_messages.pop_front() { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(message)) } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 5ffd36007f530..7d756ed2d1e88 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -38,7 +38,6 @@ use crate::{ transport, ChainSyncInterface, ReputationChange, }; -use codec::Encode; use futures::{channel::oneshot, prelude::*}; use libp2p::{ core::{either::EitherError, upgrade, ConnectedPoint, Executor}, @@ -264,11 +263,6 @@ where let num_connected = Arc::new(AtomicUsize::new(0)); let is_major_syncing = Arc::new(AtomicBool::new(false)); - let block_request_protocol_name = params.block_request_protocol_config.name.clone(); - let state_request_protocol_name = params.state_request_protocol_config.name.clone(); - let warp_sync_protocol_name = - params.warp_sync_protocol_config.as_ref().map(|c| c.name.clone()); - // Build the swarm. let (mut swarm, bandwidth): (Swarm>, _) = { let user_agent = format!( @@ -366,10 +360,6 @@ where user_agent, local_public, discovery_config, - params.block_request_protocol_config, - params.state_request_protocol_config, - params.warp_sync_protocol_config, - params.light_client_request_protocol_config, params.network_config.request_response_protocols, peerset_handle.clone(), ); @@ -466,9 +456,6 @@ where peers_notifications_sinks, metrics, boot_node_ids, - block_request_protocol_name, - state_request_protocol_name, - warp_sync_protocol_name, _marker: Default::default(), }) } @@ -1287,15 +1274,6 @@ where /// For each peer and protocol combination, an object that allows sending notifications to /// that peer. Shared with the [`NetworkService`]. peers_notifications_sinks: Arc>>, - /// Protocol name used to send out block requests via - /// [`crate::request_responses::RequestResponsesBehaviour`]. - block_request_protocol_name: ProtocolName, - /// Protocol name used to send out state requests via - /// [`crate::request_responses::RequestResponsesBehaviour`]. - state_request_protocol_name: ProtocolName, - /// Protocol name used to send out warp sync requests via - /// [`crate::request_responses::RequestResponsesBehaviour`]. - warp_sync_protocol_name: Option, /// Marker to pin the `H` generic. Serves no purpose except to not break backwards /// compatibility. _marker: PhantomData, @@ -1474,84 +1452,6 @@ where } this.import_queue.import_justifications(origin, hash, nb, justifications); }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::BlockRequest { - target, - request, - pending_response, - })) => { - match this - .network_service - .behaviour() - .user_protocol() - .encode_block_request(&request) - { - Ok(data) => { - this.network_service.behaviour_mut().send_request( - &target, - &this.block_request_protocol_name, - data, - pending_response, - IfDisconnected::ImmediateError, - ); - }, - Err(err) => { - log::warn!( - target: "sync", - "Failed to encode block request {:?}: {:?}", - request, err - ); - }, - } - }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::StateRequest { - target, - request, - pending_response, - })) => { - match this - .network_service - .behaviour() - .user_protocol() - .encode_state_request(&request) - { - Ok(data) => { - this.network_service.behaviour_mut().send_request( - &target, - &this.state_request_protocol_name, - data, - pending_response, - IfDisconnected::ImmediateError, - ); - }, - Err(err) => { - log::warn!( - target: "sync", - "Failed to encode state request {:?}: {:?}", - request, err - ); - }, - } - }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::WarpSyncRequest { - target, - request, - pending_response, - })) => match &this.warp_sync_protocol_name { - Some(name) => this.network_service.behaviour_mut().send_request( - &target, - &name, - request.encode(), - pending_response, - IfDisconnected::ImmediateError, - ), - None => { - log::warn!( - target: "sync", - "Trying to send warp sync request when no protocol is configured {:?}", - request, - ); - }, - }, Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::InboundRequest { protocol, result, diff --git a/client/network/src/service/tests/chain_sync.rs b/client/network/src/service/tests/chain_sync.rs index 21149459413f4..b62fb36461860 100644 --- a/client/network/src/service/tests/chain_sync.rs +++ b/client/network/src/service/tests/chain_sync.rs @@ -27,8 +27,8 @@ use sc_block_builder::BlockBuilderProvider; use sc_client_api::HeaderBackend; use sc_consensus::JustificationSyncLink; use sc_network_common::{ - config::{MultiaddrWithPeerId, SetConfig}, - protocol::event::Event, + config::{MultiaddrWithPeerId, ProtocolId, SetConfig}, + protocol::{event::Event, role::Roles, ProtocolName}, service::NetworkSyncForkRequest, sync::{SyncState, SyncStatus}, }; @@ -39,7 +39,6 @@ use sp_runtime::{ traits::{Block as BlockT, Header as _}, }; use std::{ - iter, sync::{Arc, RwLock}, task::Poll, time::Duration, @@ -49,10 +48,6 @@ use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _ fn set_default_expecations_no_peers( chain_sync: &mut MockChainSync, ) { - chain_sync.expect_block_requests().returning(|| Box::new(iter::empty())); - chain_sync.expect_state_request().returning(|| None); - chain_sync.expect_justification_requests().returning(|| Box::new(iter::empty())); - chain_sync.expect_warp_sync_request().returning(|| None); chain_sync.expect_poll().returning(|_| Poll::Pending); chain_sync.expect_status().returning(|| SyncStatus { state: SyncState::Idle, @@ -342,13 +337,19 @@ async fn disconnect_peer_using_chain_sync_handle() { sc_network_sync::service::network::NetworkServiceProvider::new(); let handle_clone = chain_sync_network_handle.clone(); - let (chain_sync, chain_sync_service) = ChainSync::new( + let (chain_sync, chain_sync_service, _) = ChainSync::new( sc_network_common::sync::SyncMode::Full, client.clone(), + ProtocolId::from("test-protocol-name"), + &Some(String::from("test-fork-id")), + Roles::from(&config::Role::Full), Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), 1u32, None, chain_sync_network_handle.clone(), + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, ) .unwrap(); diff --git a/client/network/src/service/tests/mod.rs b/client/network/src/service/tests/mod.rs index ef25616a07b0d..1d91fc142672f 100644 --- a/client/network/src/service/tests/mod.rs +++ b/client/network/src/service/tests/mod.rs @@ -216,31 +216,6 @@ impl TestNetworkBuilder { None, ))); - let (chain_sync_network_provider, chain_sync_network_handle) = - self.chain_sync_network.unwrap_or(NetworkServiceProvider::new()); - - let (chain_sync, chain_sync_service) = self.chain_sync.unwrap_or({ - let (chain_sync, chain_sync_service) = ChainSync::new( - match network_config.sync_mode { - config::SyncMode::Full => sc_network_common::sync::SyncMode::Full, - config::SyncMode::Fast { skip_proofs, storage_chain_mode } => - sc_network_common::sync::SyncMode::LightState { - skip_proofs, - storage_chain_mode, - }, - config::SyncMode::Warp => sc_network_common::sync::SyncMode::Warp, - }, - client.clone(), - Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), - network_config.max_parallel_downloads, - None, - chain_sync_network_handle, - ) - .unwrap(); - - (Box::new(chain_sync), chain_sync_service) - }); - let protocol_id = ProtocolId::from("test-protocol-name"); let fork_id = Some(String::from("test-fork-id")); @@ -289,6 +264,37 @@ impl TestNetworkBuilder { }, }; + let (chain_sync_network_provider, chain_sync_network_handle) = + self.chain_sync_network.unwrap_or(NetworkServiceProvider::new()); + + let (chain_sync, chain_sync_service) = self.chain_sync.unwrap_or({ + let (chain_sync, chain_sync_service, _) = ChainSync::new( + match network_config.sync_mode { + config::SyncMode::Full => sc_network_common::sync::SyncMode::Full, + config::SyncMode::Fast { skip_proofs, storage_chain_mode } => + sc_network_common::sync::SyncMode::LightState { + skip_proofs, + storage_chain_mode, + }, + config::SyncMode::Warp => sc_network_common::sync::SyncMode::Warp, + }, + client.clone(), + protocol_id.clone(), + &fork_id, + Roles::from(&config::Role::Full), + Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), + network_config.max_parallel_downloads, + None, + chain_sync_network_handle, + block_request_protocol_config.name.clone(), + state_request_protocol_config.name.clone(), + None, + ) + .unwrap(); + + (Box::new(chain_sync), chain_sync_service) + }); + let worker = NetworkWorker::< substrate_test_runtime_client::runtime::Block, substrate_test_runtime_client::runtime::Hash, @@ -305,11 +311,12 @@ impl TestNetworkBuilder { chain_sync, chain_sync_service, metrics_registry: None, - block_request_protocol_config, - state_request_protocol_config, - light_client_request_protocol_config, - warp_sync_protocol_config: None, - request_response_protocol_configs: Vec::new(), + request_response_protocol_configs: [ + block_request_protocol_config, + state_request_protocol_config, + light_client_request_protocol_config, + ] + .to_vec(), }) .unwrap(); diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index ce1dd8f895d61..841388c7a68ee 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -18,6 +18,7 @@ prost-build = "0.11" [dependencies] array-bytes = "4.1" +async-trait = "0.1.58" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" libp2p = "0.49.0" diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 75ecb9322ca78..697445334a073 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -49,8 +49,10 @@ use crate::{ }; use codec::{Decode, DecodeAll, Encode}; use extra_requests::ExtraRequests; -use futures::{stream::FuturesUnordered, task::Poll, Future, FutureExt, StreamExt}; -use libp2p::PeerId; +use futures::{ + channel::oneshot, stream::FuturesUnordered, task::Poll, Future, FutureExt, StreamExt, +}; +use libp2p::{request_response::OutboundFailure, PeerId}; use log::{debug, error, info, trace, warn}; use prost::Message; use sc_client_api::{BlockBackend, ProofProvider}; @@ -59,16 +61,18 @@ use sc_network_common::{ config::{ NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, }, - protocol::role::Roles, + protocol::{role::Roles, ProtocolName}, + request_responses::{IfDisconnected, RequestFailure}, sync::{ message::{ BlockAnnounce, BlockAnnouncesHandshake, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, FromBlock, }, warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, WarpSyncProvider}, - BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, OnStateData, - OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, - PollBlockAnnounceValidation, SyncMode, SyncState, SyncStatus, + BadPeer, ChainSync as ChainSyncT, ImportResult, Metrics, OnBlockData, OnBlockJustification, + OnStateData, OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, + OpaqueStateResponse, PeerInfo, PeerRequest, PollBlockAnnounceValidation, PollResult, + SyncMode, SyncState, SyncStatus, }, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; @@ -170,6 +174,18 @@ mod rep { /// Peer response data does not have requested bits. pub const BAD_RESPONSE: Rep = Rep::new(-(1 << 12), "Incomplete response"); + + /// Reputation change when a peer doesn't respond in time to our messages. + pub const TIMEOUT: Rep = Rep::new(-(1 << 10), "Request timeout"); + + /// Peer is on unsupported protocol version. + pub const BAD_PROTOCOL: Rep = Rep::new_fatal("Unsupported protocol"); + + /// Reputation change when a peer refuses a request. + pub const REFUSED: Rep = Rep::new(-(1 << 10), "Request refused"); + + /// We received a message that failed to decode. + pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); } enum AllowedRequests { @@ -223,6 +239,18 @@ struct GapSync { target: NumberFor, } +type PendingResponse = Pin< + Box< + dyn Future< + Output = ( + PeerId, + PeerRequest, + Result, RequestFailure>, oneshot::Canceled>, + ), + > + Send, + >, +>; + /// The main data structure which contains all the state for a chains /// active syncing strategy. pub struct ChainSync { @@ -272,7 +300,17 @@ pub struct ChainSync { /// Channel for receiving service commands service_rx: TracingUnboundedReceiver>, /// Handle for communicating with `NetworkService` - _network_service: service::network::NetworkServiceHandle, + network_service: service::network::NetworkServiceHandle, + /// Protocol name used for block announcements + block_announce_protocol_name: ProtocolName, + /// Protocol name used to send out block requests + block_request_protocol_name: ProtocolName, + /// Protocol name used to send out state requests + state_request_protocol_name: ProtocolName, + /// Protocol name used to send out warp sync requests + warp_sync_protocol_name: Option, + /// Pending responses + pending_responses: FuturesUnordered>, } /// All the data we have about a Peer that we are trying to sync with @@ -470,6 +508,10 @@ where self.peers.len() } + fn num_active_peers(&self) -> usize { + self.pending_responses.len() + } + fn new_peer( &mut self, who: PeerId, @@ -661,222 +703,6 @@ where .extend(peers); } - fn justification_requests<'a>( - &'a mut self, - ) -> Box)> + 'a> { - let peers = &mut self.peers; - let mut matcher = self.extra_justifications.matcher(); - Box::new(std::iter::from_fn(move || { - if let Some((peer, request)) = matcher.next(peers) { - peers - .get_mut(&peer) - .expect( - "`Matcher::next` guarantees the `PeerId` comes from the given peers; qed", - ) - .state = PeerSyncState::DownloadingJustification(request.0); - let req = BlockRequest:: { - id: 0, - fields: BlockAttributes::JUSTIFICATION, - from: FromBlock::Hash(request.0), - direction: Direction::Ascending, - max: Some(1), - }; - Some((peer, req)) - } else { - None - } - })) - } - - fn block_requests<'a>( - &'a mut self, - ) -> Box)> + 'a> { - if self.mode == SyncMode::Warp { - return Box::new(std::iter::once(self.warp_target_block_request()).flatten()) - } - - if self.allowed_requests.is_empty() || self.state_sync.is_some() { - return Box::new(std::iter::empty()) - } - - if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS { - trace!(target: "sync", "Too many blocks in the queue."); - return Box::new(std::iter::empty()) - } - let is_major_syncing = self.status().state.is_major_syncing(); - let attrs = self.required_block_attributes(); - let blocks = &mut self.blocks; - let fork_targets = &mut self.fork_targets; - let last_finalized = - std::cmp::min(self.best_queued_number, self.client.info().finalized_number); - let best_queued = self.best_queued_number; - let client = &self.client; - let queue = &self.queue_blocks; - let allowed_requests = self.allowed_requests.take(); - let max_parallel = if is_major_syncing { 1 } else { self.max_parallel_downloads }; - let gap_sync = &mut self.gap_sync; - let iter = self.peers.iter_mut().filter_map(move |(&id, peer)| { - if !peer.state.is_available() || !allowed_requests.contains(&id) { - return None - } - - // If our best queued is more than `MAX_BLOCKS_TO_LOOK_BACKWARDS` blocks away from the - // common number, the peer best number is higher than our best queued and the common - // number is smaller than the last finalized block number, we should do an ancestor - // search to find a better common block. If the queue is full we wait till all blocks - // are imported though. - if best_queued.saturating_sub(peer.common_number) > MAX_BLOCKS_TO_LOOK_BACKWARDS.into() && - best_queued < peer.best_number && - peer.common_number < last_finalized && - queue.len() <= MAJOR_SYNC_BLOCKS.into() - { - trace!( - target: "sync", - "Peer {:?} common block {} too far behind of our best {}. Starting ancestry search.", - id, - peer.common_number, - best_queued, - ); - let current = std::cmp::min(peer.best_number, best_queued); - peer.state = PeerSyncState::AncestorSearch { - current, - start: best_queued, - state: AncestorSearchState::ExponentialBackoff(One::one()), - }; - Some((id, ancestry_request::(current))) - } else if let Some((range, req)) = peer_block_request( - &id, - peer, - blocks, - attrs, - max_parallel, - last_finalized, - best_queued, - ) { - peer.state = PeerSyncState::DownloadingNew(range.start); - trace!( - target: "sync", - "New block request for {}, (best:{}, common:{}) {:?}", - id, - peer.best_number, - peer.common_number, - req, - ); - Some((id, req)) - } else if let Some((hash, req)) = - fork_sync_request(&id, fork_targets, best_queued, last_finalized, attrs, |hash| { - if queue.contains(hash) { - BlockStatus::Queued - } else { - client.block_status(&BlockId::Hash(*hash)).unwrap_or(BlockStatus::Unknown) - } - }) { - trace!(target: "sync", "Downloading fork {:?} from {}", hash, id); - peer.state = PeerSyncState::DownloadingStale(hash); - Some((id, req)) - } else if let Some((range, req)) = gap_sync.as_mut().and_then(|sync| { - peer_gap_block_request( - &id, - peer, - &mut sync.blocks, - attrs, - sync.target, - sync.best_queued_number, - ) - }) { - peer.state = PeerSyncState::DownloadingGap(range.start); - trace!( - target: "sync", - "New gap block request for {}, (best:{}, common:{}) {:?}", - id, - peer.best_number, - peer.common_number, - req, - ); - Some((id, req)) - } else { - None - } - }); - Box::new(iter) - } - - fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { - if self.allowed_requests.is_empty() { - return None - } - if (self.state_sync.is_some() || self.warp_sync.is_some()) && - self.peers.iter().any(|(_, peer)| peer.state == PeerSyncState::DownloadingState) - { - // Only one pending state request is allowed. - return None - } - if let Some(sync) = &self.state_sync { - if sync.is_complete() { - return None - } - - for (id, peer) in self.peers.iter_mut() { - if peer.state.is_available() && peer.common_number >= sync.target_block_num() { - peer.state = PeerSyncState::DownloadingState; - let request = sync.next_request(); - trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); - self.allowed_requests.clear(); - return Some((*id, OpaqueStateRequest(Box::new(request)))) - } - } - } - if let Some(sync) = &self.warp_sync { - if sync.is_complete() { - return None - } - if let (Some(request), Some(target)) = - (sync.next_state_request(), sync.target_block_number()) - { - for (id, peer) in self.peers.iter_mut() { - if peer.state.is_available() && peer.best_number >= target { - trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); - peer.state = PeerSyncState::DownloadingState; - self.allowed_requests.clear(); - return Some((*id, OpaqueStateRequest(Box::new(request)))) - } - } - } - } - None - } - - fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)> { - if let Some(sync) = &self.warp_sync { - if self.allowed_requests.is_empty() || - sync.is_complete() || - self.peers - .iter() - .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpProof) - { - // Only one pending state request is allowed. - return None - } - if let Some(request) = sync.next_warp_proof_request() { - let mut targets: Vec<_> = self.peers.values().map(|p| p.best_number).collect(); - if !targets.is_empty() { - targets.sort(); - let median = targets[targets.len() / 2]; - // Find a random peer that is synced as much as peer majority. - for (id, peer) in self.peers.iter_mut() { - if peer.state.is_available() && peer.best_number >= median { - trace!(target: "sync", "New WarpProofRequest for {}", id); - peer.state = PeerSyncState::DownloadingWarpProof; - self.allowed_requests.clear(); - return Some((*id, request)) - } - } - } - } - } - None - } - fn on_block_data( &mut self, who: &PeerId, @@ -1135,153 +961,55 @@ where Ok(self.validate_and_queue_blocks(new_blocks, gap)) } - fn on_state_data( + fn on_block_justification( &mut self, - who: &PeerId, - response: OpaqueStateResponse, - ) -> Result, BadPeer> { - let response: Box = response.0.downcast().map_err(|_error| { - error!( - target: "sync", - "Failed to downcast opaque state response, this is an implementation bug." - ); + who: PeerId, + response: BlockResponse, + ) -> Result, BadPeer> { + let peer = if let Some(peer) = self.peers.get_mut(&who) { + peer + } else { + error!(target: "sync", "💔 Called on_block_justification with a bad peer ID"); + return Ok(OnBlockJustification::Nothing) + }; - BadPeer(*who, rep::BAD_RESPONSE) - })?; + self.allowed_requests.add(&who); + if let PeerSyncState::DownloadingJustification(hash) = peer.state { + peer.state = PeerSyncState::Available; - if let Some(peer) = self.peers.get_mut(who) { - if let PeerSyncState::DownloadingState = peer.state { - peer.state = PeerSyncState::Available; - self.allowed_requests.set_all(); - } - } - let import_result = if let Some(sync) = &mut self.state_sync { - debug!( - target: "sync", - "Importing state data from {} with {} keys, {} proof nodes.", - who, - response.entries.len(), - response.proof.len(), - ); - sync.import(*response) - } else if let Some(sync) = &mut self.warp_sync { - debug!( - target: "sync", - "Importing state data from {} with {} keys, {} proof nodes.", - who, - response.entries.len(), - response.proof.len(), - ); - sync.import_state(*response) - } else { - debug!(target: "sync", "Ignored obsolete state response from {}", who); - return Err(BadPeer(*who, rep::NOT_REQUESTED)) - }; - - match import_result { - state::ImportResult::Import(hash, header, state, body, justifications) => { - let origin = BlockOrigin::NetworkInitialSync; - let block = IncomingBlock { - hash, - header: Some(header), - body, - indexed_body: None, - justifications, - origin: None, - allow_missing_state: true, - import_existing: true, - skip_execution: self.skip_execution(), - state: Some(state), - }; - debug!(target: "sync", "State download is complete. Import is queued"); - Ok(OnStateData::Import(origin, block)) - }, - state::ImportResult::Continue => Ok(OnStateData::Continue), - state::ImportResult::BadResponse => { - debug!(target: "sync", "Bad state data received from {}", who); - Err(BadPeer(*who, rep::BAD_BLOCK)) - }, - } - } - - fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer> { - if let Some(peer) = self.peers.get_mut(who) { - if let PeerSyncState::DownloadingWarpProof = peer.state { - peer.state = PeerSyncState::Available; - self.allowed_requests.set_all(); - } - } - let import_result = if let Some(sync) = &mut self.warp_sync { - debug!( - target: "sync", - "Importing warp proof data from {}, {} bytes.", - who, - response.0.len(), - ); - sync.import_warp_proof(response) - } else { - debug!(target: "sync", "Ignored obsolete warp sync response from {}", who); - return Err(BadPeer(*who, rep::NOT_REQUESTED)) - }; - - match import_result { - WarpProofImportResult::Success => Ok(()), - WarpProofImportResult::BadResponse => { - debug!(target: "sync", "Bad proof data received from {}", who); - Err(BadPeer(*who, rep::BAD_BLOCK)) - }, - } - } - - fn on_block_justification( - &mut self, - who: PeerId, - response: BlockResponse, - ) -> Result, BadPeer> { - let peer = if let Some(peer) = self.peers.get_mut(&who) { - peer - } else { - error!(target: "sync", "💔 Called on_block_justification with a bad peer ID"); - return Ok(OnBlockJustification::Nothing) - }; - - self.allowed_requests.add(&who); - if let PeerSyncState::DownloadingJustification(hash) = peer.state { - peer.state = PeerSyncState::Available; - - // We only request one justification at a time - let justification = if let Some(block) = response.blocks.into_iter().next() { - if hash != block.hash { - warn!( - target: "sync", - "💔 Invalid block justification provided by {}: requested: {:?} got: {:?}", - who, - hash, - block.hash, - ); - return Err(BadPeer(who, rep::BAD_JUSTIFICATION)) - } - - block - .justifications - .or_else(|| legacy_justification_mapping(block.justification)) - } else { - // we might have asked the peer for a justification on a block that we assumed it - // had but didn't (regardless of whether it had a justification for it or not). - trace!( - target: "sync", - "Peer {:?} provided empty response for justification request {:?}", - who, - hash, - ); - - None - }; - - if let Some((peer, hash, number, j)) = - self.extra_justifications.on_response(who, justification) - { - return Ok(OnBlockJustification::Import { peer, hash, number, justifications: j }) + // We only request one justification at a time + let justification = if let Some(block) = response.blocks.into_iter().next() { + if hash != block.hash { + warn!( + target: "sync", + "💔 Invalid block justification provided by {}: requested: {:?} got: {:?}", + who, + hash, + block.hash, + ); + return Err(BadPeer(who, rep::BAD_JUSTIFICATION)) + } + + block + .justifications + .or_else(|| legacy_justification_mapping(block.justification)) + } else { + // we might have asked the peer for a justification on a block that we assumed it + // had but didn't (regardless of whether it had a justification for it or not). + trace!( + target: "sync", + "Peer {:?} provided empty response for justification request {:?}", + who, + hash, + ); + + None + }; + + if let Some((peer, hash, number, j)) = + self.extra_justifications.on_response(who, justification) + { + return Ok(OnBlockJustification::Import { peer, hash, number, justifications: j }) } } @@ -1627,38 +1355,6 @@ where } } - /// Create implementation-specific block request. - fn create_opaque_block_request(&self, request: &BlockRequest) -> OpaqueBlockRequest { - OpaqueBlockRequest(Box::new(schema::v1::BlockRequest { - fields: request.fields.to_be_u32(), - from_block: match request.from { - FromBlock::Hash(h) => Some(schema::v1::block_request::FromBlock::Hash(h.encode())), - FromBlock::Number(n) => - Some(schema::v1::block_request::FromBlock::Number(n.encode())), - }, - direction: request.direction as i32, - max_blocks: request.max.unwrap_or(0), - support_multiple_justifications: true, - })) - } - - fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String> { - let request: &schema::v1::BlockRequest = request.0.downcast_ref().ok_or_else(|| { - "Failed to downcast opaque block response during encoding, this is an \ - implementation bug." - .to_string() - })?; - - Ok(request.encode_to_vec()) - } - - fn decode_block_response(&self, response: &[u8]) -> Result { - let response = schema::v1::BlockResponse::decode(response) - .map_err(|error| format!("Failed to decode block response: {error}"))?; - - Ok(OpaqueBlockResponse(Box::new(response))) - } - fn block_response_into_blocks( &self, request: &BlockRequest, @@ -1725,27 +1421,7 @@ where .map_err(|error: codec::Error| error.to_string()) } - fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String> { - let request: &StateRequest = request.0.downcast_ref().ok_or_else(|| { - "Failed to downcast opaque state response during encoding, this is an \ - implementation bug." - .to_string() - })?; - - Ok(request.encode_to_vec()) - } - - fn decode_state_response(&self, response: &[u8]) -> Result { - let response = StateResponse::decode(response) - .map_err(|error| format!("Failed to decode state response: {error}"))?; - - Ok(OpaqueStateResponse(Box::new(response))) - } - - fn poll( - &mut self, - cx: &mut std::task::Context, - ) -> Poll> { + fn poll(&mut self, cx: &mut std::task::Context) -> Poll> { while let Poll::Ready(Some(event)) = self.service_rx.poll_next_unpin(cx) { match event { ToServiceCommand::SetSyncForkRequest(peers, hash, number) => { @@ -1753,8 +1429,46 @@ where }, } } + self.process_outbound_requests(); + + if let Poll::Ready(result) = self.poll_pending_responses(cx) { + return Poll::Ready(PollResult::Import(result)) + } + + if let Poll::Ready(announce) = self.poll_block_announce_validation(cx) { + return Poll::Ready(PollResult::Announce(announce)) + } - self.poll_block_announce_validation(cx) + Poll::Pending + } + + fn send_block_request(&mut self, who: PeerId, request: BlockRequest) { + let (tx, rx) = oneshot::channel(); + let opaque_req = self.create_opaque_block_request(&request); + + if self.peers.contains_key(&who) { + self.pending_responses + .push(Box::pin(async move { (who, PeerRequest::Block(request), rx.await) })); + } + + match self.encode_block_request(&opaque_req) { + Ok(data) => { + self.network_service.start_request( + who, + self.block_request_protocol_name.clone(), + data, + tx, + IfDisconnected::ImmediateError, + ); + }, + Err(err) => { + log::warn!( + target: "sync", + "Failed to encode block request {:?}: {:?}", + opaque_req, err + ); + }, + } } } @@ -1774,12 +1488,30 @@ where pub fn new( mode: SyncMode, client: Arc, + protocol_id: ProtocolId, + fork_id: &Option, + roles: Roles, block_announce_validator: Box + Send>, max_parallel_downloads: u32, warp_sync_provider: Option>>, - _network_service: service::network::NetworkServiceHandle, - ) -> Result<(Self, Box>), ClientError> { + network_service: service::network::NetworkServiceHandle, + block_request_protocol_name: ProtocolName, + state_request_protocol_name: ProtocolName, + warp_sync_protocol_name: Option, + ) -> Result<(Self, Box>, NonDefaultSetConfig), ClientError> { let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync"); + let block_announce_config = Self::get_block_announce_proto_config( + protocol_id, + fork_id, + roles, + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ); let mut sync = Self { client, @@ -1803,10 +1535,19 @@ where import_existing: false, gap_sync: None, service_rx, - _network_service, + network_service, + block_request_protocol_name, + state_request_protocol_name, + warp_sync_protocol_name, + block_announce_protocol_name: block_announce_config + .notifications_protocol + .clone() + .into(), + pending_responses: Default::default(), }; + sync.reset_sync_start_point()?; - Ok((sync, Box::new(ChainSyncInterfaceHandle::new(tx)))) + Ok((sync, Box::new(ChainSyncInterfaceHandle::new(tx)), block_announce_config)) } /// Returns the median seen block number. @@ -2203,72 +1944,670 @@ where Ok(()) } - /// What is the status of the block corresponding to the given hash? - fn block_status(&self, hash: &B::Hash) -> Result { - if self.queue_blocks.contains(hash) { - return Ok(BlockStatus::Queued) + /// What is the status of the block corresponding to the given hash? + fn block_status(&self, hash: &B::Hash) -> Result { + if self.queue_blocks.contains(hash) { + return Ok(BlockStatus::Queued) + } + self.client.block_status(&BlockId::Hash(*hash)) + } + + /// Is the block corresponding to the given hash known? + fn is_known(&self, hash: &B::Hash) -> bool { + self.block_status(hash).ok().map_or(false, |s| s != BlockStatus::Unknown) + } + + /// Is any peer downloading the given hash? + fn is_already_downloading(&self, hash: &B::Hash) -> bool { + self.peers + .iter() + .any(|(_, p)| p.state == PeerSyncState::DownloadingStale(*hash)) + } + + /// Get the set of downloaded blocks that are ready to be queued for import. + fn ready_blocks(&mut self) -> Vec> { + self.blocks + .ready_blocks(self.best_queued_number + One::one()) + .into_iter() + .map(|block_data| { + let justifications = block_data + .block + .justifications + .or_else(|| legacy_justification_mapping(block_data.block.justification)); + IncomingBlock { + hash: block_data.block.hash, + header: block_data.block.header, + body: block_data.block.body, + indexed_body: block_data.block.indexed_body, + justifications, + origin: block_data.origin, + allow_missing_state: true, + import_existing: self.import_existing, + skip_execution: self.skip_execution(), + state: None, + } + }) + .collect() + } + + /// Generate block request for downloading of the target block body during warp sync. + fn warp_target_block_request(&mut self) -> Option<(PeerId, BlockRequest)> { + let sync = &self.warp_sync.as_ref()?; + + if self.allowed_requests.is_empty() || + sync.is_complete() || + self.peers + .iter() + .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpTargetBlock) + { + // Only one pending warp target block request is allowed. + return None + } + + if let Some((target_number, request)) = sync.next_target_block_request() { + // Find a random peer that has a block with the target number. + for (id, peer) in self.peers.iter_mut() { + if peer.state.is_available() && peer.best_number >= target_number { + trace!(target: "sync", "New warp target block request for {}", id); + peer.state = PeerSyncState::DownloadingWarpTargetBlock; + self.allowed_requests.clear(); + return Some((*id, request)) + } + } + } + + None + } + + /// Get config for the block announcement protocol + pub fn get_block_announce_proto_config( + protocol_id: ProtocolId, + fork_id: &Option, + roles: Roles, + best_number: NumberFor, + best_hash: B::Hash, + genesis_hash: B::Hash, + ) -> NonDefaultSetConfig { + let block_announces_protocol = { + let genesis_hash = genesis_hash.as_ref(); + if let Some(ref fork_id) = fork_id { + format!( + "/{}/{}/block-announces/1", + array_bytes::bytes2hex("", genesis_hash), + fork_id + ) + } else { + format!("/{}/block-announces/1", array_bytes::bytes2hex("", genesis_hash)) + } + }; + + NonDefaultSetConfig { + notifications_protocol: block_announces_protocol.into(), + fallback_names: iter::once( + format!("/{}/block-announces/1", protocol_id.as_ref()).into(), + ) + .collect(), + max_notification_size: MAX_BLOCK_ANNOUNCE_SIZE, + handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( + roles, + best_number, + best_hash, + genesis_hash, + ))), + // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement + // protocol is still hardcoded into the peerset. + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + } + } + + fn decode_block_response(response: &[u8]) -> Result { + let response = schema::v1::BlockResponse::decode(response) + .map_err(|error| format!("Failed to decode block response: {error}"))?; + + Ok(OpaqueBlockResponse(Box::new(response))) + } + + fn decode_state_response(response: &[u8]) -> Result { + let response = StateResponse::decode(response) + .map_err(|error| format!("Failed to decode state response: {error}"))?; + + Ok(OpaqueStateResponse(Box::new(response))) + } + + fn send_state_request(&mut self, who: PeerId, request: OpaqueStateRequest) { + let (tx, rx) = oneshot::channel(); + + if self.peers.contains_key(&who) { + self.pending_responses + .push(Box::pin(async move { (who, PeerRequest::State, rx.await) })); + } + + match self.encode_state_request(&request) { + Ok(data) => { + self.network_service.start_request( + who, + self.state_request_protocol_name.clone(), + data, + tx, + IfDisconnected::ImmediateError, + ); + }, + Err(err) => { + log::warn!( + target: "sync", + "Failed to encode state request {:?}: {:?}", + request, err + ); + }, + } + } + + fn send_warp_sync_request(&mut self, who: PeerId, request: WarpProofRequest) { + let (tx, rx) = oneshot::channel(); + + if self.peers.contains_key(&who) { + self.pending_responses + .push(Box::pin(async move { (who, PeerRequest::WarpProof, rx.await) })); + } + + match &self.warp_sync_protocol_name { + Some(name) => self.network_service.start_request( + who, + name.clone(), + request.encode(), + tx, + IfDisconnected::ImmediateError, + ), + None => { + log::warn!( + target: "sync", + "Trying to send warp sync request when no protocol is configured {:?}", + request, + ); + }, + } + } + + fn on_block_response( + &mut self, + peer_id: PeerId, + request: BlockRequest, + response: OpaqueBlockResponse, + ) -> Option> { + let blocks = match self.block_response_into_blocks(&request, response) { + Ok(blocks) => blocks, + Err(err) => { + debug!(target: "sync", "Failed to decode block response from {}: {}", peer_id, err); + self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); + return None + }, + }; + + let block_response = BlockResponse:: { id: request.id, blocks }; + + let blocks_range = || match ( + block_response + .blocks + .first() + .and_then(|b| b.header.as_ref().map(|h| h.number())), + block_response.blocks.last().and_then(|b| b.header.as_ref().map(|h| h.number())), + ) { + (Some(first), Some(last)) if first != last => format!(" ({}..{})", first, last), + (Some(first), Some(_)) => format!(" ({})", first), + _ => Default::default(), + }; + trace!( + target: "sync", + "BlockResponse {} from {} with {} blocks {}", + block_response.id, + peer_id, + block_response.blocks.len(), + blocks_range(), + ); + + if request.fields == BlockAttributes::JUSTIFICATION { + match self.on_block_justification(peer_id, block_response) { + Ok(OnBlockJustification::Nothing) => None, + Ok(OnBlockJustification::Import { peer, hash, number, justifications }) => + Some(ImportResult::JustificationImport(peer, hash, number, justifications)), + Err(BadPeer(id, repu)) => { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(id, repu); + None + }, + } + } else { + match self.on_block_data(&peer_id, Some(request), block_response) { + Ok(OnBlockData::Import(origin, blocks)) => + Some(ImportResult::BlockImport(origin, blocks)), + Ok(OnBlockData::Request(peer, req)) => { + self.send_block_request(peer, req); + None + }, + Ok(OnBlockData::Continue) => None, + Err(BadPeer(id, repu)) => { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(id, repu); + None + }, + } + } + } + + pub fn on_state_response( + &mut self, + peer_id: PeerId, + response: OpaqueStateResponse, + ) -> Option> { + match self.on_state_data(&peer_id, response) { + Ok(OnStateData::Import(origin, block)) => + Some(ImportResult::BlockImport(origin, vec![block])), + Ok(OnStateData::Continue) => None, + Err(BadPeer(id, repu)) => { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(id, repu); + None + }, + } + } + + pub fn on_warp_sync_response(&mut self, peer_id: PeerId, response: EncodedProof) { + if let Err(BadPeer(id, repu)) = self.on_warp_sync_data(&peer_id, response) { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(id, repu); + } + } + + fn process_outbound_requests(&mut self) { + for (id, request) in self.block_requests() { + self.send_block_request(id, request); + } + + if let Some((id, request)) = self.state_request() { + self.send_state_request(id, request); + } + + for (id, request) in self.justification_requests().collect::>() { + self.send_block_request(id, request); + } + + if let Some((id, request)) = self.warp_sync_request() { + self.send_warp_sync_request(id, request); + } + } + + fn poll_pending_responses(&mut self, cx: &mut std::task::Context) -> Poll> { + while let Poll::Ready(Some((id, request, response))) = + self.pending_responses.poll_next_unpin(cx) + { + match response { + Ok(Ok(resp)) => match request { + PeerRequest::Block(req) => { + let response = match Self::decode_block_response(&resp[..]) { + Ok(proto) => proto, + Err(e) => { + debug!( + target: "sync", + "Failed to decode block response from peer {:?}: {:?}.", + id, + e + ); + self.network_service.report_peer(id, rep::BAD_MESSAGE); + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + continue + }, + }; + + if let Some(import) = self.on_block_response(id, req, response) { + return Poll::Ready(import) + } + }, + PeerRequest::State => { + let response = match Self::decode_state_response(&resp[..]) { + Ok(proto) => proto, + Err(e) => { + debug!( + target: "sync", + "Failed to decode state response from peer {:?}: {:?}.", + id, + e + ); + self.network_service.report_peer(id, rep::BAD_MESSAGE); + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + continue + }, + }; + + if let Some(import) = self.on_state_response(id, response) { + return Poll::Ready(import) + } + }, + PeerRequest::WarpProof => { + self.on_warp_sync_response(id, EncodedProof(resp)); + }, + }, + Ok(Err(e)) => { + debug!(target: "sync", "Request to peer {:?} failed: {:?}.", id, e); + + match e { + RequestFailure::Network(OutboundFailure::Timeout) => { + self.network_service.report_peer(id, rep::TIMEOUT); + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + }, + RequestFailure::Network(OutboundFailure::UnsupportedProtocols) => { + self.network_service.report_peer(id, rep::BAD_PROTOCOL); + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + }, + RequestFailure::Network(OutboundFailure::DialFailure) => { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + }, + RequestFailure::Refused => { + self.network_service.report_peer(id, rep::REFUSED); + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + }, + RequestFailure::Network(OutboundFailure::ConnectionClosed) | + RequestFailure::NotConnected => { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + }, + RequestFailure::UnknownProtocol => { + debug_assert!(false, "Block request protocol should always be known."); + }, + RequestFailure::Obsolete => { + debug_assert!( + false, + "Can not receive `RequestFailure::Obsolete` after dropping the \ + response receiver.", + ); + }, + } + }, + Err(oneshot::Canceled) => { + trace!( + target: "sync", + "Request to peer {:?} failed due to oneshot being canceled.", + id, + ); + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + }, + } + } + + Poll::Pending + } + + /// Create implementation-specific block request. + fn create_opaque_block_request(&self, request: &BlockRequest) -> OpaqueBlockRequest { + OpaqueBlockRequest(Box::new(schema::v1::BlockRequest { + fields: request.fields.to_be_u32(), + from_block: match request.from { + FromBlock::Hash(h) => Some(schema::v1::block_request::FromBlock::Hash(h.encode())), + FromBlock::Number(n) => + Some(schema::v1::block_request::FromBlock::Number(n.encode())), + }, + direction: request.direction as i32, + max_blocks: request.max.unwrap_or(0), + support_multiple_justifications: true, + })) + } + + fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String> { + let request: &schema::v1::BlockRequest = request.0.downcast_ref().ok_or_else(|| { + "Failed to downcast opaque block response during encoding, this is an \ + implementation bug." + .to_string() + })?; + + Ok(request.encode_to_vec()) + } + + fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String> { + let request: &StateRequest = request.0.downcast_ref().ok_or_else(|| { + "Failed to downcast opaque state response during encoding, this is an \ + implementation bug." + .to_string() + })?; + + Ok(request.encode_to_vec()) + } + + fn justification_requests<'a>( + &'a mut self, + ) -> Box)> + 'a> { + let peers = &mut self.peers; + let mut matcher = self.extra_justifications.matcher(); + Box::new(std::iter::from_fn(move || { + if let Some((peer, request)) = matcher.next(peers) { + peers + .get_mut(&peer) + .expect( + "`Matcher::next` guarantees the `PeerId` comes from the given peers; qed", + ) + .state = PeerSyncState::DownloadingJustification(request.0); + let req = BlockRequest:: { + id: 0, + fields: BlockAttributes::JUSTIFICATION, + from: FromBlock::Hash(request.0), + direction: Direction::Ascending, + max: Some(1), + }; + Some((peer, req)) + } else { + None + } + })) + } + + fn block_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { + if self.mode == SyncMode::Warp { + return self + .warp_target_block_request() + .map_or_else(|| Vec::new(), |req| Vec::from([req])) + } + + if self.allowed_requests.is_empty() || self.state_sync.is_some() { + return Vec::new() + } + + if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS { + trace!(target: "sync", "Too many blocks in the queue."); + return Vec::new() + } + let is_major_syncing = self.status().state.is_major_syncing(); + let attrs = self.required_block_attributes(); + let blocks = &mut self.blocks; + let fork_targets = &mut self.fork_targets; + let last_finalized = + std::cmp::min(self.best_queued_number, self.client.info().finalized_number); + let best_queued = self.best_queued_number; + let client = &self.client; + let queue = &self.queue_blocks; + let allowed_requests = self.allowed_requests.take(); + let max_parallel = if is_major_syncing { 1 } else { self.max_parallel_downloads }; + let gap_sync = &mut self.gap_sync; + self.peers + .iter_mut() + .filter_map(move |(&id, peer)| { + if !peer.state.is_available() || !allowed_requests.contains(&id) { + return None + } + + // If our best queued is more than `MAX_BLOCKS_TO_LOOK_BACKWARDS` blocks away from + // the common number, the peer best number is higher than our best queued and the + // common number is smaller than the last finalized block number, we should do an + // ancestor search to find a better common block. If the queue is full we wait till + // all blocks are imported though. + if best_queued.saturating_sub(peer.common_number) > + MAX_BLOCKS_TO_LOOK_BACKWARDS.into() && + best_queued < peer.best_number && + peer.common_number < last_finalized && + queue.len() <= MAJOR_SYNC_BLOCKS.into() + { + trace!( + target: "sync", + "Peer {:?} common block {} too far behind of our best {}. Starting ancestry search.", + id, + peer.common_number, + best_queued, + ); + let current = std::cmp::min(peer.best_number, best_queued); + peer.state = PeerSyncState::AncestorSearch { + current, + start: best_queued, + state: AncestorSearchState::ExponentialBackoff(One::one()), + }; + Some((id, ancestry_request::(current))) + } else if let Some((range, req)) = peer_block_request( + &id, + peer, + blocks, + attrs, + max_parallel, + last_finalized, + best_queued, + ) { + peer.state = PeerSyncState::DownloadingNew(range.start); + trace!( + target: "sync", + "New block request for {}, (best:{}, common:{}) {:?}", + id, + peer.best_number, + peer.common_number, + req, + ); + Some((id, req)) + } else if let Some((hash, req)) = fork_sync_request( + &id, + fork_targets, + best_queued, + last_finalized, + attrs, + |hash| { + if queue.contains(hash) { + BlockStatus::Queued + } else { + client + .block_status(&BlockId::Hash(*hash)) + .unwrap_or(BlockStatus::Unknown) + } + }, + ) { + trace!(target: "sync", "Downloading fork {:?} from {}", hash, id); + peer.state = PeerSyncState::DownloadingStale(hash); + Some((id, req)) + } else if let Some((range, req)) = gap_sync.as_mut().and_then(|sync| { + peer_gap_block_request( + &id, + peer, + &mut sync.blocks, + attrs, + sync.target, + sync.best_queued_number, + ) + }) { + peer.state = PeerSyncState::DownloadingGap(range.start); + trace!( + target: "sync", + "New gap block request for {}, (best:{}, common:{}) {:?}", + id, + peer.best_number, + peer.common_number, + req, + ); + Some((id, req)) + } else { + None + } + }) + .collect() + // Box::new(iter) + } + + fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { + if self.allowed_requests.is_empty() { + return None } - self.client.block_status(&BlockId::Hash(*hash)) - } - - /// Is the block corresponding to the given hash known? - fn is_known(&self, hash: &B::Hash) -> bool { - self.block_status(hash).ok().map_or(false, |s| s != BlockStatus::Unknown) - } - - /// Is any peer downloading the given hash? - fn is_already_downloading(&self, hash: &B::Hash) -> bool { - self.peers - .iter() - .any(|(_, p)| p.state == PeerSyncState::DownloadingStale(*hash)) - } + if (self.state_sync.is_some() || self.warp_sync.is_some()) && + self.peers.iter().any(|(_, peer)| peer.state == PeerSyncState::DownloadingState) + { + // Only one pending state request is allowed. + return None + } + if let Some(sync) = &self.state_sync { + if sync.is_complete() { + return None + } - /// Get the set of downloaded blocks that are ready to be queued for import. - fn ready_blocks(&mut self) -> Vec> { - self.blocks - .ready_blocks(self.best_queued_number + One::one()) - .into_iter() - .map(|block_data| { - let justifications = block_data - .block - .justifications - .or_else(|| legacy_justification_mapping(block_data.block.justification)); - IncomingBlock { - hash: block_data.block.hash, - header: block_data.block.header, - body: block_data.block.body, - indexed_body: block_data.block.indexed_body, - justifications, - origin: block_data.origin, - allow_missing_state: true, - import_existing: self.import_existing, - skip_execution: self.skip_execution(), - state: None, + for (id, peer) in self.peers.iter_mut() { + if peer.state.is_available() && peer.common_number >= sync.target_block_num() { + peer.state = PeerSyncState::DownloadingState; + let request = sync.next_request(); + trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); + self.allowed_requests.clear(); + return Some((*id, OpaqueStateRequest(Box::new(request)))) } - }) - .collect() + } + } + if let Some(sync) = &self.warp_sync { + if sync.is_complete() { + return None + } + if let (Some(request), Some(target)) = + (sync.next_state_request(), sync.target_block_number()) + { + for (id, peer) in self.peers.iter_mut() { + if peer.state.is_available() && peer.best_number >= target { + trace!(target: "sync", "New StateRequest for {}: {:?}", id, request); + peer.state = PeerSyncState::DownloadingState; + self.allowed_requests.clear(); + return Some((*id, OpaqueStateRequest(Box::new(request)))) + } + } + } + } + None } - /// Generate block request for downloading of the target block body during warp sync. - fn warp_target_block_request(&mut self) -> Option<(PeerId, BlockRequest)> { + fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)> { if let Some(sync) = &self.warp_sync { if self.allowed_requests.is_empty() || sync.is_complete() || self.peers .iter() - .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpTargetBlock) + .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpProof) { - // Only one pending warp target block request is allowed. + // Only one pending state request is allowed. return None } - if let Some((target_number, request)) = sync.next_target_block_request() { - // Find a random peer that has a block with the target number. - for (id, peer) in self.peers.iter_mut() { - if peer.state.is_available() && peer.best_number >= target_number { - trace!(target: "sync", "New warp target block request for {}", id); - peer.state = PeerSyncState::DownloadingWarpTargetBlock; - self.allowed_requests.clear(); - return Some((*id, request)) + if let Some(request) = sync.next_warp_proof_request() { + let mut targets: Vec<_> = self.peers.values().map(|p| p.best_number).collect(); + if !targets.is_empty() { + targets.sort(); + let median = targets[targets.len() / 2]; + // Find a random peer that is synced as much as peer majority. + for (id, peer) in self.peers.iter_mut() { + if peer.state.is_available() && peer.best_number >= median { + trace!(target: "sync", "New WarpProofRequest for {}", id); + peer.state = PeerSyncState::DownloadingWarpProof; + self.allowed_requests.clear(); + return Some((*id, request)) + } } } } @@ -2276,49 +2615,100 @@ where None } - /// Get config for the block announcement protocol - pub fn get_block_announce_proto_config( - &self, - protocol_id: ProtocolId, - fork_id: &Option, - roles: Roles, - best_number: NumberFor, - best_hash: B::Hash, - genesis_hash: B::Hash, - ) -> NonDefaultSetConfig { - let block_announces_protocol = { - let genesis_hash = genesis_hash.as_ref(); - if let Some(ref fork_id) = fork_id { - format!( - "/{}/{}/block-announces/1", - array_bytes::bytes2hex("", genesis_hash), - fork_id - ) - } else { - format!("/{}/block-announces/1", array_bytes::bytes2hex("", genesis_hash)) + fn on_state_data( + &mut self, + who: &PeerId, + response: OpaqueStateResponse, + ) -> Result, BadPeer> { + let response: Box = response.0.downcast().map_err(|_error| { + error!( + target: "sync", + "Failed to downcast opaque state response, this is an implementation bug." + ); + + BadPeer(*who, rep::BAD_RESPONSE) + })?; + + if let Some(peer) = self.peers.get_mut(who) { + if let PeerSyncState::DownloadingState = peer.state { + peer.state = PeerSyncState::Available; + self.allowed_requests.set_all(); } + } + let import_result = if let Some(sync) = &mut self.state_sync { + debug!( + target: "sync", + "Importing state data from {} with {} keys, {} proof nodes.", + who, + response.entries.len(), + response.proof.len(), + ); + sync.import(*response) + } else if let Some(sync) = &mut self.warp_sync { + debug!( + target: "sync", + "Importing state data from {} with {} keys, {} proof nodes.", + who, + response.entries.len(), + response.proof.len(), + ); + sync.import_state(*response) + } else { + debug!(target: "sync", "Ignored obsolete state response from {}", who); + return Err(BadPeer(*who, rep::NOT_REQUESTED)) }; - NonDefaultSetConfig { - notifications_protocol: block_announces_protocol.into(), - fallback_names: iter::once( - format!("/{}/block-announces/1", protocol_id.as_ref()).into(), - ) - .collect(), - max_notification_size: MAX_BLOCK_ANNOUNCE_SIZE, - handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( - roles, - best_number, - best_hash, - genesis_hash, - ))), - // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement - // protocol is still hardcoded into the peerset. - set_config: SetConfig { - in_peers: 0, - out_peers: 0, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Deny, + match import_result { + state::ImportResult::Import(hash, header, state, body, justifications) => { + let origin = BlockOrigin::NetworkInitialSync; + let block = IncomingBlock { + hash, + header: Some(header), + body, + indexed_body: None, + justifications, + origin: None, + allow_missing_state: true, + import_existing: true, + skip_execution: self.skip_execution(), + state: Some(state), + }; + debug!(target: "sync", "State download is complete. Import is queued"); + Ok(OnStateData::Import(origin, block)) + }, + state::ImportResult::Continue => Ok(OnStateData::Continue), + state::ImportResult::BadResponse => { + debug!(target: "sync", "Bad state data received from {}", who); + Err(BadPeer(*who, rep::BAD_BLOCK)) + }, + } + } + + fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer> { + if let Some(peer) = self.peers.get_mut(who) { + if let PeerSyncState::DownloadingWarpProof = peer.state { + peer.state = PeerSyncState::Available; + self.allowed_requests.set_all(); + } + } + let import_result = if let Some(sync) = &mut self.warp_sync { + debug!( + target: "sync", + "Importing warp proof data from {}, {} bytes.", + who, + response.0.len(), + ); + sync.import_warp_proof(response) + } else { + debug!(target: "sync", "Ignored obsolete warp sync response from {}", who); + return Err(BadPeer(*who, rep::NOT_REQUESTED)) + }; + + match import_result { + WarpProofImportResult::Success => Ok(()), + WarpProofImportResult::BadResponse => { + debug!(target: "sync", "Bad proof data received from {}", who); + Err(BadPeer(*who, rep::BAD_BLOCK)) }, } } @@ -2677,7 +3067,10 @@ mod test { use crate::service::network::NetworkServiceProvider; use futures::{executor::block_on, future::poll_fn}; use sc_block_builder::BlockBuilderProvider; - use sc_network_common::sync::message::{BlockData, BlockState, FromBlock}; + use sc_network_common::{ + protocol::role::Role, + sync::message::{BlockData, BlockState, FromBlock}, + }; use sp_blockchain::HeaderBackend; use sp_consensus::block_validation::DefaultBlockAnnounceValidator; use substrate_test_runtime_client::{ @@ -2698,13 +3091,19 @@ mod test { let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), + ProtocolId::from("test-protocol-name"), + &Some(String::from("test-fork-id")), + Roles::from(&Role::Full), block_announce_validator, 1, None, chain_sync_network_handle, + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, ) .unwrap(); @@ -2755,13 +3154,19 @@ mod test { let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), + ProtocolId::from("test-protocol-name"), + &Some(String::from("test-fork-id")), + Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 1, None, chain_sync_network_handle, + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, ) .unwrap(); @@ -2787,7 +3192,10 @@ mod test { // we wil send block requests to these peers // for these blocks we don't know about - assert!(sync.block_requests().all(|(p, _)| { p == peer_id1 || p == peer_id2 })); + assert!(sync + .block_requests() + .into_iter() + .all(|(p, _)| { p == peer_id1 || p == peer_id2 })); // add a new peer at a known block sync.new_peer(peer_id3, b1_hash, b1_number).unwrap(); @@ -2877,7 +3285,7 @@ mod test { max: u32, peer: &PeerId, ) -> BlockRequest { - let requests = sync.block_requests().collect::>(); + let requests = sync.block_requests(); log::trace!(target: "sync", "Requests: {:?}", requests); @@ -2925,13 +3333,19 @@ mod test { let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), + ProtocolId::from("test-protocol-name"), + &Some(String::from("test-fork-id")), + Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 5, None, chain_sync_network_handle, + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, ) .unwrap(); @@ -2967,7 +3381,7 @@ mod test { sync.update_chain_info(&block3.hash(), 3); // There should be no requests. - assert!(sync.block_requests().collect::>().is_empty()); + assert!(sync.block_requests().is_empty()); // Let peer2 announce a fork of block 3 send_block_announce(block3_fork.header().clone(), &peer_id2, &mut sync); @@ -3043,13 +3457,19 @@ mod test { NetworkServiceProvider::new(); let info = client.info(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), + ProtocolId::from("test-protocol-name"), + &Some(String::from("test-fork-id")), + Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 5, None, chain_sync_network_handle, + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, ) .unwrap(); @@ -3117,15 +3537,16 @@ mod test { // Let peer2 announce that it finished syncing send_block_announce(best_block.header().clone(), &peer_id2, &mut sync); - let (peer1_req, peer2_req) = sync.block_requests().fold((None, None), |res, req| { - if req.0 == peer_id1 { - (Some(req.1), res.1) - } else if req.0 == peer_id2 { - (res.0, Some(req.1)) - } else { - panic!("Unexpected req: {:?}", req) - } - }); + let (peer1_req, peer2_req) = + sync.block_requests().into_iter().fold((None, None), |res, req| { + if req.0 == peer_id1 { + (Some(req.1), res.1) + } else if req.0 == peer_id2 { + (res.0, Some(req.1)) + } else { + panic!("Unexpected req: {:?}", req) + } + }); // We should now do an ancestor search to find the correct common block. let peer2_req = peer2_req.unwrap(); @@ -3189,13 +3610,19 @@ mod test { let info = client.info(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), + ProtocolId::from("test-protocol-name"), + &Some(String::from("test-fork-id")), + Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 5, None, chain_sync_network_handle, + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, ) .unwrap(); @@ -3321,13 +3748,19 @@ mod test { let info = client.info(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), + ProtocolId::from("test-protocol-name"), + &Some(String::from("test-fork-id")), + Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 5, None, chain_sync_network_handle, + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, ) .unwrap(); @@ -3453,13 +3886,19 @@ mod test { let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..3).map(|_| build_block(&mut client, None, false)).collect::>(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), + ProtocolId::from("test-protocol-name"), + &Some(String::from("test-fork-id")), + Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 1, None, chain_sync_network_handle, + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, ) .unwrap(); @@ -3489,13 +3928,19 @@ mod test { let empty_client = Arc::new(TestClientBuilder::new().build()); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, empty_client.clone(), + ProtocolId::from("test-protocol-name"), + &Some(String::from("test-fork-id")), + Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 1, None, chain_sync_network_handle, + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, ) .unwrap(); diff --git a/client/network/sync/src/mock.rs b/client/network/sync/src/mock.rs index fbb54bd5e998d..48d72c425bd03 100644 --- a/client/network/sync/src/mock.rs +++ b/client/network/sync/src/mock.rs @@ -24,10 +24,8 @@ use libp2p::PeerId; use sc_consensus::{BlockImportError, BlockImportStatus}; use sc_network_common::sync::{ message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}, - warp::{EncodedProof, WarpProofRequest}, - BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, OnStateData, - OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, - PollBlockAnnounceValidation, SyncStatus, + BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, + OpaqueBlockResponse, PeerInfo, PollBlockAnnounceValidation, PollResult, SyncStatus, }; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -40,6 +38,7 @@ mockall::mock! { fn num_sync_requests(&self) -> usize; fn num_downloaded_blocks(&self) -> usize; fn num_peers(&self) -> usize; + fn num_active_peers(&self) -> usize; fn new_peer( &mut self, who: PeerId, @@ -55,24 +54,12 @@ mockall::mock! { hash: &Block::Hash, number: NumberFor, ); - fn justification_requests<'a>( - &'a mut self, - ) -> Box)> + 'a>; - fn block_requests<'a>(&'a mut self) -> Box)> + 'a>; - fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)>; - fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)>; fn on_block_data( &mut self, who: &PeerId, request: Option>, response: BlockResponse, ) -> Result, BadPeer>; - fn on_state_data( - &mut self, - who: &PeerId, - response: OpaqueStateResponse, - ) -> Result, BadPeer>; - fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer>; fn on_block_justification( &mut self, who: PeerId, @@ -104,19 +91,19 @@ mockall::mock! { ) -> Poll>; fn peer_disconnected(&mut self, who: &PeerId) -> Option>; fn metrics(&self) -> Metrics; - fn create_opaque_block_request(&self, request: &BlockRequest) -> OpaqueBlockRequest; - fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String>; - fn decode_block_response(&self, response: &[u8]) -> Result; fn block_response_into_blocks( &self, request: &BlockRequest, response: OpaqueBlockResponse, ) -> Result>, String>; - fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String>; - fn decode_state_response(&self, response: &[u8]) -> Result; fn poll<'a>( &mut self, cx: &mut std::task::Context<'a>, - ) -> Poll>; + ) -> Poll>; + fn send_block_request( + &mut self, + who: PeerId, + request: BlockRequest, + ); } } diff --git a/client/network/sync/src/service/mock.rs b/client/network/sync/src/service/mock.rs index c146e1ec07b48..c8a29e1fba8ea 100644 --- a/client/network/sync/src/service/mock.rs +++ b/client/network/sync/src/service/mock.rs @@ -16,13 +16,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use sc_network_common::service::{NetworkPeers, NetworkSyncForkRequest}; -use sp_runtime::traits::{Block as BlockT, NumberFor}; - -pub use libp2p::{identity::error::SigningError, kad::record::Key as KademliaKey}; +use futures::channel::oneshot; use libp2p::{Multiaddr, PeerId}; -use sc_network_common::{config::MultiaddrWithPeerId, protocol::ProtocolName}; +use sc_network_common::{ + config::MultiaddrWithPeerId, + protocol::ProtocolName, + request_responses::{IfDisconnected, RequestFailure}, + service::{NetworkPeers, NetworkRequest, NetworkSyncForkRequest}, +}; use sc_peerset::ReputationChange; +use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::collections::HashSet; mockall::mock! { @@ -72,4 +75,23 @@ mockall::mock! { fn remove_from_peers_set(&self, protocol: ProtocolName, peers: Vec); fn sync_num_connected(&self) -> usize; } + + #[async_trait::async_trait] + impl NetworkRequest for Network { + async fn request( + &self, + target: PeerId, + protocol: ProtocolName, + request: Vec, + connect: IfDisconnected, + ) -> Result, RequestFailure>; + fn start_request( + &self, + target: PeerId, + protocol: ProtocolName, + request: Vec, + tx: oneshot::Sender, RequestFailure>>, + connect: IfDisconnected, + ); + } } diff --git a/client/network/sync/src/service/network.rs b/client/network/sync/src/service/network.rs index 44ed177661264..43501baeec7be 100644 --- a/client/network/sync/src/service/network.rs +++ b/client/network/sync/src/service/network.rs @@ -16,17 +16,21 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use futures::StreamExt; +use futures::{channel::oneshot, StreamExt}; use libp2p::PeerId; -use sc_network_common::{protocol::ProtocolName, service::NetworkPeers}; +use sc_network_common::{ + protocol::ProtocolName, + request_responses::{IfDisconnected, RequestFailure}, + service::{NetworkPeers, NetworkRequest}, +}; use sc_peerset::ReputationChange; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use std::sync::Arc; /// Network-related services required by `sc-network-sync` -pub trait Network: NetworkPeers {} +pub trait Network: NetworkPeers + NetworkRequest {} -impl Network for T where T: NetworkPeers {} +impl Network for T where T: NetworkPeers + NetworkRequest {} /// Network service provider for `ChainSync` /// @@ -43,6 +47,15 @@ pub enum ToServiceCommand { /// Call `NetworkPeers::report_peer()` ReportPeer(PeerId, ReputationChange), + + /// Call `NetworkRequest::start_request()` + StartRequest( + PeerId, + ProtocolName, + Vec, + oneshot::Sender, RequestFailure>>, + IfDisconnected, + ), } /// Handle that is (temporarily) passed to `ChainSync` so it can @@ -67,6 +80,20 @@ impl NetworkServiceHandle { pub fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { let _ = self.tx.unbounded_send(ToServiceCommand::DisconnectPeer(who, protocol)); } + + /// Send request to peer + pub fn start_request( + &self, + who: PeerId, + protocol: ProtocolName, + request: Vec, + tx: oneshot::Sender, RequestFailure>>, + connect: IfDisconnected, + ) { + let _ = self + .tx + .unbounded_send(ToServiceCommand::StartRequest(who, protocol, request, tx, connect)); + } } impl NetworkServiceProvider { @@ -85,6 +112,8 @@ impl NetworkServiceProvider { service.disconnect_peer(peer, protocol_name), ToServiceCommand::ReportPeer(peer, reputation_change) => service.report_peer(peer, reputation_change), + ToServiceCommand::StartRequest(peer, protocol, request, tx, connect) => + service.start_request(peer, protocol, request, tx, connect), } } } diff --git a/client/network/sync/src/tests.rs b/client/network/sync/src/tests.rs index 479c78bfdea97..bd78c3b45226d 100644 --- a/client/network/sync/src/tests.rs +++ b/client/network/sync/src/tests.rs @@ -19,7 +19,15 @@ use crate::{service::network::NetworkServiceProvider, ChainSync, ForkTarget}; use libp2p::PeerId; -use sc_network_common::{service::NetworkSyncForkRequest, sync::ChainSync as ChainSyncT}; +use sc_network_common::{ + config::ProtocolId, + protocol::{ + role::{Role, Roles}, + ProtocolName, + }, + service::NetworkSyncForkRequest, + sync::ChainSync as ChainSyncT, +}; use sp_consensus::block_validation::DefaultBlockAnnounceValidator; use sp_core::H256; use std::{sync::Arc, task::Poll}; @@ -30,13 +38,19 @@ use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _ #[async_std::test] async fn delegate_to_chainsync() { let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut chain_sync, chain_sync_service) = ChainSync::new( + let (mut chain_sync, chain_sync_service, _) = ChainSync::new( sc_network_common::sync::SyncMode::Full, Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0), + ProtocolId::from("test-protocol-name"), + &Some(String::from("test-fork-id")), + Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 1u32, None, chain_sync_network_handle, + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, ) .unwrap(); diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 035fc0a972a59..975d902157310 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -77,7 +77,7 @@ use sp_core::H256; use sp_runtime::{ codec::{Decode, Encode}, generic::{BlockId, OpaqueDigestItemId}, - traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, + traits::{Block as BlockT, Header as HeaderT, NumberFor}, Justification, Justifications, }; use substrate_test_runtime_client::AccountKeyring; @@ -869,7 +869,7 @@ where .unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)); let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (chain_sync, chain_sync_service) = ChainSync::new( + let (chain_sync, chain_sync_service, block_announce_config) = ChainSync::new( match network_config.sync_mode { SyncMode::Full => sc_network_common::sync::SyncMode::Full, SyncMode::Fast { skip_proofs, storage_chain_mode } => @@ -880,24 +880,18 @@ where SyncMode::Warp => sc_network_common::sync::SyncMode::Warp, }, client.clone(), + protocol_id.clone(), + &fork_id, + Roles::from(if config.is_authority { &Role::Authority } else { &Role::Full }), block_announce_validator, network_config.max_parallel_downloads, Some(warp_sync), chain_sync_network_handle, + block_request_protocol_config.name.clone(), + state_request_protocol_config.name.clone(), + Some(warp_protocol_config.name.clone()), ) .unwrap(); - let block_announce_config = chain_sync.get_block_announce_proto_config( - protocol_id.clone(), - &fork_id, - Roles::from(if config.is_authority { &Role::Authority } else { &Role::Full }), - client.info().best_number, - client.info().best_hash, - client - .block_hash(Zero::zero()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), - ); let network = NetworkWorker::new(sc_network::config::Params { role: if config.is_authority { Role::Authority } else { Role::Full }, @@ -911,11 +905,13 @@ where chain_sync_service, metrics_registry: None, block_announce_config, - block_request_protocol_config, - state_request_protocol_config, - light_client_request_protocol_config, - warp_sync_protocol_config: Some(warp_protocol_config), - request_response_protocol_configs: Vec::new(), + request_response_protocol_configs: [ + block_request_protocol_config, + state_request_protocol_config, + light_client_request_protocol_config, + warp_protocol_config, + ] + .to_vec(), }) .unwrap(); @@ -994,6 +990,7 @@ where return Poll::Pending } } + Poll::Ready(()) } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 3cb064ec814c5..63d60fb06f471 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -846,7 +846,7 @@ where }; let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (chain_sync, chain_sync_service) = ChainSync::new( + let (chain_sync, chain_sync_service, block_announce_config) = ChainSync::new( match config.network.sync_mode { SyncMode::Full => sc_network_common::sync::SyncMode::Full, SyncMode::Fast { skip_proofs, storage_chain_mode } => @@ -854,25 +854,18 @@ where SyncMode::Warp => sc_network_common::sync::SyncMode::Warp, }, client.clone(), + protocol_id.clone(), + &config.chain_spec.fork_id().map(ToOwned::to_owned), + Roles::from(&config.role), block_announce_validator, config.network.max_parallel_downloads, warp_sync_provider, chain_sync_network_handle, + block_request_protocol_config.name.clone(), + state_request_protocol_config.name.clone(), + warp_sync_protocol_config.as_ref().map(|config| config.name.clone()), )?; - let block_announce_config = chain_sync.get_block_announce_proto_config( - protocol_id.clone(), - &config.chain_spec.fork_id().map(ToOwned::to_owned), - Roles::from(&config.role.clone()), - client.info().best_number, - client.info().best_hash, - client - .block_hash(Zero::zero()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), - ); - request_response_protocol_configs.push(config.network.ipfs_server.then(|| { let (handler, protocol_config) = BitswapRequestHandler::new(client.clone()); spawn_handle.spawn("bitswap-request-handler", Some("networking"), handler.run()); @@ -896,12 +889,14 @@ where chain_sync_service, metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_announce_config, - block_request_protocol_config, - state_request_protocol_config, - warp_sync_protocol_config, - light_client_request_protocol_config, request_response_protocol_configs: request_response_protocol_configs .into_iter() + .chain([ + Some(block_request_protocol_config), + Some(state_request_protocol_config), + Some(light_client_request_protocol_config), + warp_sync_protocol_config, + ]) .flatten() .collect::>(), }; From 06d7a23231b0232f49117e1d73fdad5f1dbc0e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lo=C3=AFs?= Date: Tue, 22 Nov 2022 18:34:07 +0100 Subject: [PATCH 1400/1472] perf: generate_initial_session_keys: load runtime only if its relevant (#12651) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: generate_initial_session_keys: load runtime only if its relevant * apply review suggestion * Update primitives/session/src/lib.rs Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- primitives/session/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/primitives/session/src/lib.rs b/primitives/session/src/lib.rs index 1b25d285e3bca..dde262738ad71 100644 --- a/primitives/session/src/lib.rs +++ b/primitives/session/src/lib.rs @@ -118,6 +118,10 @@ where T: ProvideRuntimeApi, T::Api: SessionKeys, { + if seeds.is_empty() { + return Ok(()) + } + let runtime_api = client.runtime_api(); for seed in seeds { From 431429fffbce9f0e9e7ddaddf63dcf6ad639ea39 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 23 Nov 2022 08:10:37 +0100 Subject: [PATCH 1401/1472] Prevent epochs pruning while finalizing blocks on epoch 0 (#12758) * Prevent epochs pruning while on epoch 0 --- client/consensus/epochs/src/lib.rs | 88 +++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index f8b6253ef2353..c213a49b8e4e4 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -518,13 +518,13 @@ where let is_descendent_of = descendent_of_builder.build_is_descendent_of(None); let predicate = |epoch: &PersistedEpochHeader| match *epoch { - PersistedEpochHeader::Genesis(ref epoch_0, _) => epoch_0.start_slot <= slot, + PersistedEpochHeader::Genesis(_, ref epoch_1) => epoch_1.start_slot <= slot, PersistedEpochHeader::Regular(ref epoch_n) => epoch_n.start_slot <= slot, }; - // prune any epochs which could not be _live_ as of the children of the + // Prune any epochs which could not be _live_ as of the children of the // finalized block, i.e. re-root the fork tree to the oldest ancestor of - // (hash, number) where epoch.end_slot() >= finalized_slot + // (hash, number) where `epoch.start_slot() <= finalized_slot`. let removed = self.inner.prune(hash, &number, &is_descendent_of, &predicate)?; for (hash, number, _) in removed { @@ -1197,6 +1197,88 @@ mod tests { assert_eq!(nodes, vec![b"B", b"C", b"F", b"G"]); } + #[test] + fn near_genesis_prune_works() { + // [X]: announces next epoch change (i.e. adds a node in the epoch changes tree) + // + // 0--[A]--B--C--D--E--[G]--H--I--J--K--[L] + // + + // \--[F] + + let is_descendent_of = |base: &Hash, block: &Hash| -> Result { + match (block, base) { + | (b"A", b"0") | + (b"B", b"0" | b"A") | + (b"C", b"0" | b"A" | b"B") | + (b"D", b"0" | b"A" | b"B" | b"C") | + (b"E", b"0" | b"A" | b"B" | b"C" | b"D") | + (b"F", b"0" | b"A" | b"B" | b"C" | b"D" | b"E") | + (b"G", b"0" | b"A" | b"B" | b"C" | b"D" | b"E") | + (b"H", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G") | + (b"I", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H") | + (b"J", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I") | + (b"K", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I" | b"J") | + ( + b"L", + b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I" | b"J" | b"K", + ) => Ok(true), + _ => Ok(false), + } + }; + + let mut epoch_changes = EpochChanges::new(); + + let epoch = Epoch { start_slot: 278183811, duration: 5 }; + let epoch = PersistedEpoch::Genesis(epoch.clone(), epoch.increment(())); + + epoch_changes + .import(&is_descendent_of, *b"A", 1, Default::default(), IncrementedEpoch(epoch)) + .unwrap(); + + let import_at = |epoch_changes: &mut EpochChanges<_, _, Epoch>, + slot, + hash: &Hash, + number, + parent_hash, + parent_number| { + let make_genesis = |slot| Epoch { start_slot: slot, duration: 5 }; + // Get epoch descriptor valid for 'slot' + let epoch_descriptor = epoch_changes + .epoch_descriptor_for_child_of(&is_descendent_of, parent_hash, parent_number, slot) + .unwrap() + .unwrap(); + // Increment it + let next_epoch_desc = epoch_changes + .viable_epoch(&epoch_descriptor, &make_genesis) + .unwrap() + .increment(()); + // Assign it to hash/number + epoch_changes + .import(&is_descendent_of, *hash, number, *parent_hash, next_epoch_desc) + .unwrap(); + }; + + // Should not prune anything + epoch_changes.prune_finalized(&is_descendent_of, b"C", 3, 278183813).unwrap(); + + import_at(&mut epoch_changes, 278183816, b"G", 6, b"E", 5); + import_at(&mut epoch_changes, 278183816, b"F", 6, b"E", 5); + + // Should not prune anything since we are on epoch0 + epoch_changes.prune_finalized(&is_descendent_of, b"C", 3, 278183813).unwrap(); + let mut list: Vec<_> = epoch_changes.inner.iter().map(|e| e.0).collect(); + list.sort(); + assert_eq!(list, vec![b"A", b"F", b"G"]); + + import_at(&mut epoch_changes, 278183821, b"L", 11, b"K", 10); + + // Should prune any fork of our ancestor not in the canonical chain (i.e. "F") + epoch_changes.prune_finalized(&is_descendent_of, b"J", 9, 278183819).unwrap(); + let mut list: Vec<_> = epoch_changes.inner.iter().map(|e| e.0).collect(); + list.sort(); + assert_eq!(list, vec![b"A", b"G", b"L"]); + } + /// Test that ensures that the gap is not enabled when we import multiple genesis blocks. #[test] fn gap_is_not_enabled_when_multiple_genesis_epochs_are_imported() { From 269c79975898cad9e8f5d9c8be1e1dcafc436981 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 23 Nov 2022 08:38:34 +0000 Subject: [PATCH 1402/1472] return error instead of expect in `feasibility_check` (#12745) * Update lib.rs * make defensive * fmt * fix batching migration * fix * fix Co-authored-by: parity-processbot <> --- frame/election-provider-multi-phase/src/lib.rs | 15 +++++++++------ frame/fast-unstake/src/migrations.rs | 4 +++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index bc19e5143424c..2d49cd79dbcad 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -237,7 +237,7 @@ use frame_election_provider_support::{ use frame_support::{ dispatch::DispatchClass, ensure, - traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, + traits::{Currency, DefensiveResult, Get, OnUnbalanced, ReservableCurrency}, weights::Weight, DefaultNoBound, EqNoBound, PartialEqNoBound, }; @@ -547,6 +547,10 @@ pub enum FeasibilityError { UntrustedScoreTooLow, /// Data Provider returned too many desired targets TooManyDesiredTargets, + /// Conversion into bounded types failed. + /// + /// Should never happen under correct configurations. + BoundedConversionFailed, } impl From for FeasibilityError { @@ -560,10 +564,7 @@ pub use pallet::*; pub mod pallet { use super::*; use frame_election_provider_support::{InstantElectionProvider, NposSolver}; - use frame_support::{ - pallet_prelude::*, - traits::{DefensiveResult, EstimateCallFee}, - }; + use frame_support::{pallet_prelude::*, traits::EstimateCallFee}; use frame_system::pallet_prelude::*; #[pallet::config] @@ -1549,7 +1550,9 @@ impl Pallet { ensure!(known_score == score, FeasibilityError::InvalidScore); // Size of winners in miner solution is equal to `desired_targets` <= `MaxWinners`. - let supports = supports.try_into().expect("checked desired_targets <= MaxWinners; qed"); + let supports = supports + .try_into() + .defensive_map_err(|_| FeasibilityError::BoundedConversionFailed)?; Ok(ReadySolution { supports, compute, score }) } diff --git a/frame/fast-unstake/src/migrations.rs b/frame/fast-unstake/src/migrations.rs index 10d8e54134785..d2778d48b1b6e 100644 --- a/frame/fast-unstake/src/migrations.rs +++ b/frame/fast-unstake/src/migrations.rs @@ -39,6 +39,9 @@ pub mod v1 { ); if current == 1 && onchain == 0 { + // update the version nonetheless. + current.put::>(); + // if a head exists, then we put them back into the queue. if Head::::exists() { if let Some((stash, _, deposit)) = @@ -48,7 +51,6 @@ pub mod v1 { .defensive() { Queue::::insert(stash, deposit); - current.put::>(); } else { // not much we can do here -- head is already deleted. } From 08d1b2c7846f0280aa57dc1145a2c631b12c0789 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 23 Nov 2022 12:33:38 +0200 Subject: [PATCH 1403/1472] BEEFY: optimize voter event loop for fewer 'active' wakeups (#12760) * client/beefy: remove high-freq network events from main loop Network events are many and very frequent, remove the net-event-stream from the main voter loop and drastically reduce BEEFY voter task 'wakeups'. Instead have the `GossipValidator` track known peers as it already has callbacks for that coming from `GossipEngine`. Signed-off-by: acatangiu --- client/beefy/src/communication/gossip.rs | 4 + client/beefy/src/communication/peers.rs | 12 +- client/beefy/src/lib.rs | 4 +- client/beefy/src/tests.rs | 48 ++++---- client/beefy/src/worker.rs | 139 +++++++++-------------- 5 files changed, 85 insertions(+), 122 deletions(-) diff --git a/client/beefy/src/communication/gossip.rs b/client/beefy/src/communication/gossip.rs index 520548b943f96..bbc35ac8e526e 100644 --- a/client/beefy/src/communication/gossip.rs +++ b/client/beefy/src/communication/gossip.rs @@ -139,6 +139,10 @@ impl Validator for GossipValidator where B: Block, { + fn peer_disconnected(&self, _context: &mut dyn ValidatorContext, who: &PeerId) { + self.known_peers.lock().remove(who); + } + fn validate( &self, _context: &mut dyn ValidatorContext, diff --git a/client/beefy/src/communication/peers.rs b/client/beefy/src/communication/peers.rs index 0e20a0f4e0ff6..d7927ea72e661 100644 --- a/client/beefy/src/communication/peers.rs +++ b/client/beefy/src/communication/peers.rs @@ -46,11 +46,6 @@ impl KnownPeers { Self { live: HashMap::new() } } - /// Add new connected `peer`. - pub fn add_new(&mut self, peer: PeerId) { - self.live.entry(peer).or_default(); - } - /// Note vote round number for `peer`. pub fn note_vote_for(&mut self, peer: PeerId, round: NumberFor) { let data = self.live.entry(peer).or_default(); @@ -87,16 +82,13 @@ mod tests { let mut peers = KnownPeers::::new(); assert!(peers.live.is_empty()); - // Alice and Bob new connected peers. - peers.add_new(alice); - peers.add_new(bob); // 'Tracked' Bob seen voting for 5. peers.note_vote_for(bob, 5); // Previously unseen Charlie now seen voting for 10. peers.note_vote_for(charlie, 10); - assert_eq!(peers.live.len(), 3); - assert!(peers.contains(&alice)); + assert_eq!(peers.live.len(), 2); + assert!(!peers.contains(&alice)); assert!(peers.contains(&bob)); assert!(peers.contains(&charlie)); diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 3bdd13982aea2..9dccd4236bef3 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -241,11 +241,12 @@ where None, ); + // The `GossipValidator` adds and removes known peers based on valid votes and network events. let on_demand_justifications = OnDemandJustificationsEngine::new( network.clone(), runtime.clone(), justifications_protocol_name, - known_peers.clone(), + known_peers, ); let metrics = @@ -286,7 +287,6 @@ where payload_provider, network, key_store: key_store.into(), - known_peers, gossip_engine, gossip_validator, on_demand_justifications, diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 9a31d4a583d0e..6b9cf824d906d 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -314,6 +314,27 @@ pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> SyncCryptoStoreP keystore } +fn voter_init_setup( + net: &mut BeefyTestNet, + finality: &mut futures::stream::Fuse>, +) -> sp_blockchain::Result> { + let backend = net.peer(0).client().as_backend(); + let api = Arc::new(crate::tests::two_validators::TestApi {}); + let known_peers = Arc::new(Mutex::new(KnownPeers::new())); + let gossip_validator = + Arc::new(crate::communication::gossip::GossipValidator::new(known_peers)); + let mut gossip_engine = sc_network_gossip::GossipEngine::new( + net.peer(0).network_service().clone(), + "/beefy/whatever", + gossip_validator, + None, + ); + let best_grandpa = + futures::executor::block_on(wait_for_runtime_pallet(&*api, &mut gossip_engine, finality)) + .unwrap(); + load_or_init_voter_state(&*backend, &*api, best_grandpa, 1) +} + // Spawns beefy voters. Returns a future to spawn on the runtime. fn initialize_beefy( net: &mut BeefyTestNet, @@ -943,27 +964,6 @@ fn on_demand_beefy_justification_sync() { finalize_block_and_wait_for_beefy(&net, all_peers, &mut runtime, &[30], &[30]); } -fn test_voter_init_setup( - net: &mut BeefyTestNet, - finality: &mut futures::stream::Fuse>, -) -> sp_blockchain::Result> { - let backend = net.peer(0).client().as_backend(); - let api = Arc::new(crate::tests::two_validators::TestApi {}); - let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let gossip_validator = - Arc::new(crate::communication::gossip::GossipValidator::new(known_peers)); - let mut gossip_engine = sc_network_gossip::GossipEngine::new( - net.peer(0).network_service().clone(), - "/beefy/whatever", - gossip_validator, - None, - ); - let best_grandpa = - futures::executor::block_on(wait_for_runtime_pallet(&*api, &mut gossip_engine, finality)) - .unwrap(); - load_or_init_voter_state(&*backend, &*api, best_grandpa, 1) -} - #[test] fn should_initialize_voter_at_genesis() { let keys = &[BeefyKeyring::Alice]; @@ -981,7 +981,7 @@ fn should_initialize_voter_at_genesis() { net.peer(0).client().as_client().finalize_block(hashof13, None).unwrap(); // load persistent state - nothing in DB, should init at session boundary - let persisted_state = test_voter_init_setup(&mut net, &mut finality).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality).unwrap(); // Test initialization at session boundary. // verify voter initialized with two sessions starting at blocks 1 and 10 @@ -1044,7 +1044,7 @@ fn should_initialize_voter_when_last_final_is_session_boundary() { // expect rounds initialized at last beefy finalized 10. // load persistent state - nothing in DB, should init at session boundary - let persisted_state = test_voter_init_setup(&mut net, &mut finality).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality).unwrap(); // verify voter initialized with single session starting at block 10 assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); @@ -1103,7 +1103,7 @@ fn should_initialize_voter_at_latest_finalized() { // Test initialization at last BEEFY finalized. // load persistent state - nothing in DB, should init at last BEEFY finalized - let persisted_state = test_voter_init_setup(&mut net, &mut finality).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality).unwrap(); // verify voter initialized with single session starting at block 12 assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index e387fed79c6a0..6726fa4375387 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -16,25 +16,31 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{ - collections::{BTreeMap, BTreeSet, VecDeque}, - fmt::Debug, - marker::PhantomData, - sync::Arc, +use crate::{ + communication::{ + gossip::{topic, GossipValidator}, + request_response::outgoing_requests_engine::OnDemandJustificationsEngine, + }, + error::Error, + justification::BeefyVersionedFinalityProof, + keystore::BeefyKeystore, + metric_inc, metric_set, + metrics::Metrics, + round::Rounds, + BeefyVoterLinks, +}; +use beefy_primitives::{ + crypto::{AuthorityId, Signature}, + BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, PayloadProvider, SignedCommitment, + ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; - use codec::{Codec, Decode, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn}; -use parking_lot::Mutex; - use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; -use sc_network_common::{ - protocol::event::Event as NetEvent, - service::{NetworkEventStream, NetworkRequest}, -}; +use sc_network_common::service::{NetworkEventStream, NetworkRequest}; use sc_network_gossip::GossipEngine; - +use sc_utils::notification::NotificationReceiver; use sp_api::{BlockId, ProvideRuntimeApi}; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; @@ -44,26 +50,11 @@ use sp_runtime::{ traits::{Block, Header, NumberFor, Zero}, SaturatedConversion, }; - -use beefy_primitives::{ - crypto::{AuthorityId, Signature}, - BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, PayloadProvider, SignedCommitment, - ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, -}; -use sc_utils::notification::NotificationReceiver; - -use crate::{ - communication::{ - gossip::{topic, GossipValidator}, - request_response::outgoing_requests_engine::OnDemandJustificationsEngine, - }, - error::Error, - justification::BeefyVersionedFinalityProof, - keystore::BeefyKeystore, - metric_inc, metric_set, - metrics::Metrics, - round::Rounds, - BeefyVoterLinks, KnownPeers, +use std::{ + collections::{BTreeMap, BTreeSet, VecDeque}, + fmt::Debug, + marker::PhantomData, + sync::Arc, }; pub(crate) enum RoundAction { @@ -253,7 +244,6 @@ pub(crate) struct WorkerParams { pub payload_provider: P, pub network: N, pub key_store: BeefyKeystore, - pub known_peers: Arc>>, pub gossip_engine: GossipEngine, pub gossip_validator: Arc>, pub on_demand_justifications: OnDemandJustificationsEngine, @@ -305,7 +295,6 @@ pub(crate) struct BeefyWorker { key_store: BeefyKeystore, // communication - known_peers: Arc>>, gossip_engine: GossipEngine, gossip_validator: Arc>, on_demand_justifications: OnDemandJustificationsEngine, @@ -349,7 +338,6 @@ where gossip_engine, gossip_validator, on_demand_justifications, - known_peers, links, metrics, persisted_state, @@ -359,7 +347,6 @@ where backend, payload_provider, network, - known_peers, key_store, gossip_engine, gossip_validator, @@ -783,6 +770,29 @@ where Ok(()) } + fn process_new_state(&mut self) { + // Handle pending justifications and/or votes for now GRANDPA finalized blocks. + if let Err(err) = self.try_pending_justif_and_votes() { + debug!(target: "beefy", "🥩 {}", err); + } + + // Don't bother voting or requesting justifications during major sync. + if !self.network.is_major_syncing() { + // There were external events, 'state' is changed, author a vote if needed/possible. + if let Err(err) = self.try_to_vote() { + debug!(target: "beefy", "🥩 {}", err); + } + // If the current target is a mandatory block, + // make sure there's also an on-demand justification request out for it. + if let Some(block) = self.voting_oracle().mandatory_pending() { + // This only starts new request if there isn't already an active one. + self.on_demand_justifications.request(block); + } + } else { + debug!(target: "beefy", "🥩 Skipping voting while major syncing."); + } + } + /// Main loop for BEEFY worker. /// /// Wait for BEEFY runtime pallet to be available, then start the main async loop @@ -794,7 +804,6 @@ where ) { info!(target: "beefy", "🥩 run BEEFY worker, best grandpa: #{:?}.", self.best_grandpa_block()); - let mut network_events = self.network.event_stream("network-gossip").fuse(); let mut votes = Box::pin( self.gossip_engine .messages_for(topic::()) @@ -810,25 +819,12 @@ where ); loop { - // Don't bother voting or requesting justifications during major sync. - if !self.network.is_major_syncing() { - // If the current target is a mandatory block, - // make sure there's also an on-demand justification request out for it. - if let Some(block) = self.voting_oracle().mandatory_pending() { - // This only starts new request if there isn't already an active one. - self.on_demand_justifications.request(block); - } - // There were external events, 'state' is changed, author a vote if needed/possible. - if let Err(err) = self.try_to_vote() { - debug!(target: "beefy", "🥩 {}", err); - } - } else { - debug!(target: "beefy", "🥩 Skipping voting while major syncing."); - } + // Act on changed 'state'. + self.process_new_state(); let mut gossip_engine = &mut self.gossip_engine; // Wait for, and handle external events. - // The branches below only change 'state', actual voting happen afterwards, + // The branches below only change 'state', actual voting happens afterwards, // based on the new resulting 'state'. futures::select_biased! { // Use `select_biased!` to prioritize order below. @@ -837,15 +833,6 @@ where error!(target: "beefy", "🥩 Gossip engine has terminated, closing worker."); return; }, - // Keep track of connected peers. - net_event = network_events.next() => { - if let Some(net_event) = net_event { - self.handle_network_event(net_event); - } else { - error!(target: "beefy", "🥩 Network events stream terminated, closing worker."); - return; - } - }, // Process finality notifications first since these drive the voter. notification = finality_notifications.next() => { if let Some(notification) = notification { @@ -888,25 +875,6 @@ where } }, } - - // Handle pending justifications and/or votes for now GRANDPA finalized blocks. - if let Err(err) = self.try_pending_justif_and_votes() { - debug!(target: "beefy", "🥩 {}", err); - } - } - } - - /// Update known peers based on network events. - fn handle_network_event(&mut self, event: NetEvent) { - match event { - NetEvent::SyncConnected { remote } => { - self.known_peers.lock().add_new(remote); - }, - NetEvent::SyncDisconnected { remote } => { - self.known_peers.lock().remove(&remote); - }, - // We don't care about other events. - _ => (), } } } @@ -976,11 +944,11 @@ pub(crate) mod tests { create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi, BeefyPeer, BeefyTestNet, }, - BeefyRPCLinks, + BeefyRPCLinks, KnownPeers, }; - use beefy_primitives::{known_payloads, mmr::MmrRootProvider}; use futures::{executor::block_on, future::poll_fn, task::Poll}; + use parking_lot::Mutex; use sc_client_api::{Backend as BackendT, HeaderBackend}; use sc_network::NetworkService; use sc_network_test::TestNetFactory; @@ -1058,7 +1026,7 @@ pub(crate) mod tests { network.clone(), api.clone(), "/beefy/justifs/1".into(), - known_peers.clone(), + known_peers, ); let at = BlockId::number(Zero::zero()); let genesis_header = backend.blockchain().expect_header(at).unwrap(); @@ -1074,7 +1042,6 @@ pub(crate) mod tests { backend, payload_provider, key_store: Some(keystore).into(), - known_peers, links, gossip_engine, gossip_validator, From 4e3a12bb3f2eea8ec87c304ce62b859357677933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Thu, 24 Nov 2022 09:09:14 -0300 Subject: [PATCH 1404/1472] Sort crates before splitting them into groups (+ some improvements) (#12755) * sort crates before splitting them into groups this is useful so that crates always get routed to a specific group for a given version of the source code, which means that jobs for each batch can be reliably retried individually * more verbose output * misc improvements * put uniq after sort uniq filters by adjacent lines * shellcheck * rm useless backlashes * handle edge case of no crates detected --- scripts/ci/gitlab/check-each-crate.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/scripts/ci/gitlab/check-each-crate.sh b/scripts/ci/gitlab/check-each-crate.sh index 27e2cf947787a..24cad67007e73 100755 --- a/scripts/ci/gitlab/check-each-crate.sh +++ b/scripts/ci/gitlab/check-each-crate.sh @@ -8,17 +8,23 @@ set -Eeu -o pipefail shopt -s inherit_errexit -set -x +set -vx target_group="$1" groups_total="$2" readarray -t workspace_crates < <(\ - cargo tree --workspace --depth 0 | \ - awk '{ if (length($1) == 0 || substr($1, 1, 1) == "[") { skip } else { print $1 } }' + cargo tree --workspace --depth 0 --prefix none | + awk '{ if (length($1) == 0 || substr($1, 1, 1) == "[") { skip } else { print $1 } }' | + sort | + uniq ) crates_total=${#workspace_crates[*]} +if [ "$crates_total" -lt 1 ]; then + >&2 echo "No crates detected for $PWD" + exit 1 +fi if [ "$crates_total" -lt "$groups_total" ]; then # `crates_total / groups_total` would result in 0, so round it up to 1 @@ -37,7 +43,9 @@ fi group=1 for ((i=0; i < crates_total; i += crates_per_group)); do if [ $group -eq "$target_group" ]; then - for crate in "${workspace_crates[@]:$i:$crates_per_group}"; do + crates_in_group=("${workspace_crates[@]:$i:$crates_per_group}") + echo "crates in the group: ${crates_in_group[*]}" >/dev/null # >/dev/null due to "set -x" + for crate in "${crates_in_group[@]}"; do cargo check --locked --release -p "$crate" done break From f465fee723c87b7348839b5140135b17d0a48743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 24 Nov 2022 23:51:36 +0100 Subject: [PATCH 1405/1472] contracts: Replace `sp-sandbox` and `wasmi-validation` by newest wasmi (#12501) * Replace sp-sandbox and wasmi-validation by just wasmi * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Re-check original code on re-instrumentation * Fix clippy * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Apply suggestions from code review Co-authored-by: Robin Freyler * Replace wasmi by ::wasmi * Bump wasmi to 0.20 * Add explanation for `unreachable` * Change proof * Fixup master merge * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Fixup naming inconsistencies introduced by reentrancy PR * Fix `scan_imports` docs * Apply suggestions from code review Co-authored-by: Sasha Gryaznov * Fixup suggestions * Remove unnecessary &mut * Fix test * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Fix benchmark merge fail * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Fix docs as suggested by code review * Improve docs for `CodeRejected` * Apply suggestions from code review Co-authored-by: Sasha Gryaznov * Fix logic bug when setting `deterministic_only` * Don't panic when module fails to compile * Apply suggestions from code review Co-authored-by: Robin Freyler Co-authored-by: command-bot <> Co-authored-by: Robin Freyler Co-authored-by: Sasha Gryaznov --- Cargo.lock | 70 +- frame/contracts/Cargo.toml | 8 +- ..._fn.wat => event_and_return_on_deploy.wat} | 4 +- frame/contracts/fixtures/invalid_contract.wat | 4 + frame/contracts/fixtures/invalid_import.wat | 6 - frame/contracts/fixtures/invalid_module.wat | 8 + ...unt_call.wat => reentrance_count_call.wat} | 14 +- ...at => reentrance_count_delegated_call.wat} | 6 +- frame/contracts/proc-macro/src/lib.rs | 326 ++- frame/contracts/src/benchmarking/code.rs | 16 +- frame/contracts/src/benchmarking/mod.rs | 17 +- frame/contracts/src/benchmarking/sandbox.rs | 41 +- frame/contracts/src/chain_extension.rs | 30 +- frame/contracts/src/exec.rs | 4 +- frame/contracts/src/lib.rs | 20 +- frame/contracts/src/schedule.rs | 8 +- frame/contracts/src/tests.rs | 48 +- frame/contracts/src/wasm/code_cache.rs | 14 +- frame/contracts/src/wasm/env_def/mod.rs | 83 - frame/contracts/src/wasm/mod.rs | 138 +- frame/contracts/src/wasm/prepare.rs | 255 ++- frame/contracts/src/wasm/runtime.rs | 554 +++-- frame/contracts/src/weights.rs | 1869 +++++++++-------- 23 files changed, 1909 insertions(+), 1634 deletions(-) rename frame/contracts/fixtures/{return_from_start_fn.wat => event_and_return_on_deploy.wat} (91%) create mode 100644 frame/contracts/fixtures/invalid_contract.wat delete mode 100644 frame/contracts/fixtures/invalid_import.wat create mode 100644 frame/contracts/fixtures/invalid_module.wat rename frame/contracts/fixtures/{reentrant_count_call.wat => reentrance_count_call.wat} (80%) rename frame/contracts/fixtures/{reentrant_count_delegated_call.wat => reentrance_count_delegated_call.wat} (88%) delete mode 100644 frame/contracts/src/wasm/env_def/mod.rs diff --git a/Cargo.lock b/Cargo.lock index ca0ebee0ac475..a8c21b9830eea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3099,6 +3099,12 @@ dependencies = [ "serde", ] +[[package]] +name = "indexmap-nostd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" + [[package]] name = "instant" version = "0.1.12" @@ -5317,10 +5323,10 @@ dependencies = [ "sp-io", "sp-keystore", "sp-runtime", - "sp-sandbox", "sp-std", "wasm-instrument", - "wasmi-validation", + "wasmi 0.20.0", + "wasmparser-nostd", "wat", ] @@ -7320,7 +7326,7 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", + "spin 0.5.2", "untrusted", "web-sys", "winapi", @@ -8008,7 +8014,7 @@ dependencies = [ "tempfile", "tracing", "tracing-subscriber", - "wasmi", + "wasmi 0.13.0", "wat", ] @@ -8025,7 +8031,7 @@ dependencies = [ "thiserror", "wasm-instrument", "wasmer", - "wasmi", + "wasmi 0.13.0", ] [[package]] @@ -8039,7 +8045,7 @@ dependencies = [ "sp-runtime-interface", "sp-sandbox", "sp-wasm-interface", - "wasmi", + "wasmi 0.13.0", ] [[package]] @@ -9564,7 +9570,7 @@ dependencies = [ "substrate-bip39", "thiserror", "tiny-bip39", - "wasmi", + "wasmi 0.13.0", "zeroize", ] @@ -9895,7 +9901,7 @@ dependencies = [ "sp-io", "sp-std", "sp-wasm-interface", - "wasmi", + "wasmi 0.13.0", "wat", ] @@ -10095,7 +10101,7 @@ dependencies = [ "log", "parity-scale-codec", "sp-std", - "wasmi", + "wasmi 0.13.0", "wasmtime", ] @@ -10120,6 +10126,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" + [[package]] name = "spki" version = "0.6.0" @@ -11624,7 +11636,19 @@ checksum = "fc13b3c219ca9aafeec59150d80d89851df02e0061bc357b4d66fc55a8d38787" dependencies = [ "parity-wasm", "wasmi-validation", - "wasmi_core", + "wasmi_core 0.2.0", +] + +[[package]] +name = "wasmi" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01bf50edb2ea9d922aa75a7bf3c15e26a6c9e2d18c56e862b49737a582901729" +dependencies = [ + "spin 0.9.4", + "wasmi_arena", + "wasmi_core 0.5.0", + "wasmparser-nostd", ] [[package]] @@ -11636,6 +11660,12 @@ dependencies = [ "parity-wasm", ] +[[package]] +name = "wasmi_arena" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ea379cbb0b41f3a9f0bf7b47036d036aae7f43383d8cc487d4deccf40dee0a" + [[package]] name = "wasmi_core" version = "0.2.0" @@ -11649,6 +11679,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "wasmi_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5bf998ab792be85e20e771fe14182b4295571ad1d4f89d3da521c1bef5f597a" +dependencies = [ + "downcast-rs", + "libm", + "num-traits", +] + [[package]] name = "wasmparser" version = "0.78.2" @@ -11664,6 +11705,15 @@ dependencies = [ "indexmap", ] +[[package]] +name = "wasmparser-nostd" +version = "0.91.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c37f310b5a62bfd5ae7c0f1d8e6f98af16a5d6d84ba764e9c36439ec14e318b" +dependencies = [ + "indexmap-nostd", +] + [[package]] name = "wasmtime" version = "1.0.0" diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 6c892a00f5323..cf9889ac0be77 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -25,7 +25,8 @@ serde = { version = "1", optional = true, features = ["derive"] } smallvec = { version = "1", default-features = false, features = [ "const_generics", ] } -wasmi-validation = { version = "0.5", default-features = false } +wasmi = { version = "0.20", default-features = false } +wasmparser = { package = "wasmparser-nostd", version = "0.91", default-features = false } impl-trait-for-tuples = "0.2" # Only used in benchmarking to generate random contract code @@ -42,7 +43,6 @@ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primit sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } -sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../primitives/sandbox" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] @@ -69,16 +69,16 @@ std = [ "sp-runtime/std", "sp-io/std", "sp-std/std", - "sp-sandbox/std", "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "wasm-instrument/std", - "wasmi-validation/std", + "wasmi/std", "pallet-contracts-primitives/std", "pallet-contracts-proc-macro/full", "log/std", "rand/std", + "wasmparser/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/contracts/fixtures/return_from_start_fn.wat b/frame/contracts/fixtures/event_and_return_on_deploy.wat similarity index 91% rename from frame/contracts/fixtures/return_from_start_fn.wat rename to frame/contracts/fixtures/event_and_return_on_deploy.wat index 854b552a828c2..809cfe13545a6 100644 --- a/frame/contracts/fixtures/return_from_start_fn.wat +++ b/frame/contracts/fixtures/event_and_return_on_deploy.wat @@ -3,8 +3,7 @@ (import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32))) (import "env" "memory" (memory 1 1)) - (start $start) - (func $start + (func (export "deploy") (call $seal_deposit_event (i32.const 0) ;; The topics buffer (i32.const 0) ;; The topics buffer's length @@ -22,7 +21,6 @@ (func (export "call") (unreachable) ) - (func (export "deploy")) (data (i32.const 8) "\01\02\03\04") ) diff --git a/frame/contracts/fixtures/invalid_contract.wat b/frame/contracts/fixtures/invalid_contract.wat new file mode 100644 index 0000000000000..085569000c559 --- /dev/null +++ b/frame/contracts/fixtures/invalid_contract.wat @@ -0,0 +1,4 @@ +;; Valid module but missing the call function +(module + (func (export "deploy")) +) diff --git a/frame/contracts/fixtures/invalid_import.wat b/frame/contracts/fixtures/invalid_import.wat deleted file mode 100644 index 011f1a40e76d7..0000000000000 --- a/frame/contracts/fixtures/invalid_import.wat +++ /dev/null @@ -1,6 +0,0 @@ -;; A valid contract which does nothing at all but imports an invalid function -(module - (import "invalid" "invalid_88_99" (func (param i32 i32 i32))) - (func (export "deploy")) - (func (export "call")) -) diff --git a/frame/contracts/fixtures/invalid_module.wat b/frame/contracts/fixtures/invalid_module.wat new file mode 100644 index 0000000000000..e4a72f74273f9 --- /dev/null +++ b/frame/contracts/fixtures/invalid_module.wat @@ -0,0 +1,8 @@ +;; An invalid module +(module + (func (export "deploy")) + (func (export "call") + ;; imbalanced stack + (i32.const 7) + ) +) diff --git a/frame/contracts/fixtures/reentrant_count_call.wat b/frame/contracts/fixtures/reentrance_count_call.wat similarity index 80% rename from frame/contracts/fixtures/reentrant_count_call.wat rename to frame/contracts/fixtures/reentrance_count_call.wat index 5b4b7220cf478..0577314066f74 100644 --- a/frame/contracts/fixtures/reentrant_count_call.wat +++ b/frame/contracts/fixtures/reentrance_count_call.wat @@ -1,10 +1,10 @@ -;; This fixture recursively tests if reentrant_count returns correct reentrant count value when +;; This fixture recursively tests if reentrance_count returns correct reentrant count value when ;; using seal_call to make caller contract call to itself (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_address" (func $seal_address (param i32 i32))) (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) - (import "__unstable__" "reentrant_count" (func $reentrant_count (result i32))) + (import "__unstable__" "reentrance_count" (func $reentrance_count (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 32) reserved for $seal_address output @@ -26,7 +26,7 @@ ) ) (func (export "call") - (local $expected_reentrant_count i32) + (local $expected_reentrance_count i32) (local $seal_call_exit_code i32) ;; reading current contract address @@ -36,19 +36,19 @@ (call $seal_input (i32.const 32) (i32.const 36)) ;; reading manually passed reentrant count - (set_local $expected_reentrant_count (i32.load (i32.const 32))) + (set_local $expected_reentrance_count (i32.load (i32.const 32))) ;; reentrance count is calculated correctly (call $assert - (i32.eq (call $reentrant_count) (get_local $expected_reentrant_count)) + (i32.eq (call $reentrance_count) (get_local $expected_reentrance_count)) ) ;; re-enter 5 times in a row and assert that the reentrant counter works as expected - (i32.eq (call $reentrant_count) (i32.const 5)) + (i32.eq (call $reentrance_count) (i32.const 5)) (if (then) ;; recursion exit case (else - ;; incrementing $expected_reentrant_count passed to the contract + ;; incrementing $expected_reentrance_count passed to the contract (i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1))) ;; Call to itself diff --git a/frame/contracts/fixtures/reentrant_count_delegated_call.wat b/frame/contracts/fixtures/reentrance_count_delegated_call.wat similarity index 88% rename from frame/contracts/fixtures/reentrant_count_delegated_call.wat rename to frame/contracts/fixtures/reentrance_count_delegated_call.wat index de8f7c1a7a954..144df25d76835 100644 --- a/frame/contracts/fixtures/reentrant_count_delegated_call.wat +++ b/frame/contracts/fixtures/reentrance_count_delegated_call.wat @@ -1,10 +1,10 @@ -;; This fixture recursively tests if reentrant_count returns correct reentrant count value when +;; This fixture recursively tests if reentrance_count returns correct reentrant count value when ;; using seal_delegate_call to make caller contract delegate call to itself (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) (import "seal0" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) - (import "__unstable__" "reentrant_count" (func $reentrant_count (result i32))) + (import "__unstable__" "reentrance_count" (func $reentrance_count (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 32) buffer where code hash is copied @@ -37,7 +37,7 @@ ;; reentrance count stays 0 (call $assert - (i32.eq (call $reentrant_count) (i32.const 0)) + (i32.eq (call $reentrance_count) (i32.const 0)) ) (i32.eq (get_local $callstack_height) (i32.const 5)) diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index 648bf0fd1f812..399a1b413f121 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -29,29 +29,27 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; -use proc_macro2::TokenStream; +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; use quote::{quote, quote_spanned, ToTokens}; -use syn::{parse_macro_input, spanned::Spanned, Data, DeriveInput, Ident}; +use syn::{parse_macro_input, spanned::Spanned, Data, DeriveInput, FnArg, Ident}; /// This derives `Debug` for a struct where each field must be of some numeric type. /// It interprets each field as its represents some weight and formats it as times so that /// it is readable by humans. #[proc_macro_derive(WeightDebug)] -pub fn derive_weight_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +pub fn derive_weight_debug(input: TokenStream) -> TokenStream { derive_debug(input, format_weight) } /// This is basically identical to the std libs Debug derive but without adding any /// bounds to existing generics. #[proc_macro_derive(ScheduleDebug)] -pub fn derive_schedule_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +pub fn derive_schedule_debug(input: TokenStream) -> TokenStream { derive_debug(input, format_default) } -fn derive_debug( - input: proc_macro::TokenStream, - fmt: impl Fn(&Ident) -> TokenStream, -) -> proc_macro::TokenStream { +fn derive_debug(input: TokenStream, fmt: impl Fn(&Ident) -> TokenStream2) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); @@ -72,7 +70,7 @@ fn derive_debug( let fields = { drop(fmt); drop(data); - TokenStream::new() + TokenStream2::new() }; let tokens = quote! { @@ -91,7 +89,7 @@ fn derive_debug( /// This is only used then the `full` feature is activated. #[cfg(feature = "full")] -fn iterate_fields(data: &syn::DataStruct, fmt: impl Fn(&Ident) -> TokenStream) -> TokenStream { +fn iterate_fields(data: &syn::DataStruct, fmt: impl Fn(&Ident) -> TokenStream2) -> TokenStream2 { use syn::Fields; match &data.fields { @@ -119,7 +117,7 @@ fn iterate_fields(data: &syn::DataStruct, fmt: impl Fn(&Ident) -> TokenStream) - } } -fn format_weight(field: &Ident) -> TokenStream { +fn format_weight(field: &Ident) -> TokenStream2 { quote_spanned! { field.span() => &if self.#field > 1_000_000_000 { format!( @@ -142,7 +140,7 @@ fn format_weight(field: &Ident) -> TokenStream { } } -fn format_default(field: &Ident) -> TokenStream { +fn format_default(field: &Ident) -> TokenStream2 { quote_spanned! { field.span() => &self.#field } @@ -167,8 +165,20 @@ enum HostFnReturn { ReturnCode, } +impl HostFnReturn { + fn to_wasm_sig(&self) -> TokenStream2 { + let ok = match self { + Self::Unit => quote! { () }, + Self::U32 | Self::ReturnCode => quote! { ::core::primitive::u32 }, + }; + quote! { + ::core::result::Result<#ok, ::wasmi::core::Trap> + } + } +} + impl ToTokens for HostFn { - fn to_tokens(&self, tokens: &mut TokenStream) { + fn to_tokens(&self, tokens: &mut TokenStream2) { self.item.to_tokens(tokens); } } @@ -179,6 +189,8 @@ impl HostFn { let msg = format!("Invalid host function definition. {}", msg); syn::Error::new(span, msg) }; + + // process attributes let msg = "only #[version()] or #[unstable] attribute is allowed."; let span = item.span(); let mut attrs = item.attrs.clone(); @@ -201,16 +213,31 @@ impl HostFn { _ => Err(err(span, msg)), }?; + // process arguments: The first and second arg are treated differently (ctx, memory) + // they must exist and be `ctx: _` and `memory: _`. + let msg = "Every function must start with two inferred parameters: ctx: _ and memory: _"; + let special_args = item + .sig + .inputs + .iter() + .take(2) + .enumerate() + .map(|(i, arg)| is_valid_special_arg(i, arg)) + .fold(0u32, |acc, valid| if valid { acc + 1 } else { acc }); + + if special_args != 2 { + return Err(err(span, msg)) + } + + // process return type let msg = r#"Should return one of the following: - Result<(), TrapReason>, - Result, - Result"#; - let ret_ty = match item.clone().sig.output { syn::ReturnType::Type(_, ty) => Ok(ty.clone()), _ => Err(err(span, &msg)), }?; - match *ret_ty { syn::Type::Path(tp) => { let result = &tp.path.segments.last().ok_or(err(span, &msg))?; @@ -265,13 +292,13 @@ impl HostFn { }, _ => Err(err(ok_ty.span(), &msg)), }?; - let returns = match ok_ty_str.as_str() { "()" => Ok(HostFnReturn::Unit), "u32" => Ok(HostFnReturn::U32), "ReturnCode" => Ok(HostFnReturn::ReturnCode), _ => Err(err(arg1.span(), &msg)), }?; + Ok(Self { item, module, name, returns }) }, _ => Err(err(span, &msg)), @@ -280,25 +307,6 @@ impl HostFn { _ => Err(err(span, &msg)), } } - - fn to_wasm_sig(&self) -> TokenStream { - let args = self.item.sig.inputs.iter().skip(1).filter_map(|a| match a { - syn::FnArg::Typed(pt) => Some(&pt.ty), - _ => None, - }); - let returns = match &self.returns { - HostFnReturn::U32 => quote! { vec![ ::VALUE_TYPE ] }, - HostFnReturn::ReturnCode => quote! { vec![ ::VALUE_TYPE ] }, - HostFnReturn::Unit => quote! { vec![] }, - }; - - quote! { - wasm_instrument::parity_wasm::elements::FunctionType::new( - vec! [ #(<#args>::VALUE_TYPE),* ], - #returns, - ) - } - } } impl EnvDef { @@ -343,149 +351,135 @@ impl EnvDef { } } +fn is_valid_special_arg(idx: usize, arg: &FnArg) -> bool { + let pat = if let FnArg::Typed(pat) = arg { pat } else { return false }; + let ident = if let syn::Pat::Ident(ref ident) = *pat.pat { &ident.ident } else { return false }; + let name_ok = match idx { + 0 => ident == "ctx" || ident == "_ctx", + 1 => ident == "memory" || ident == "_memory", + _ => false, + }; + if !name_ok { + return false + } + matches!(*pat.ty, syn::Type::Infer(_)) +} + /// Expands environment definiton. /// Should generate source code for: -/// - wasm import satisfy checks (see `expand_can_satisfy()`); /// - implementations of the host functions to be added to the wasm runtime environment (see /// `expand_impls()`). -fn expand_env(def: &mut EnvDef) -> proc_macro2::TokenStream { - let can_satisfy = expand_can_satisfy(def); +fn expand_env(def: &mut EnvDef) -> TokenStream2 { let impls = expand_impls(def); quote! { pub struct Env; - #can_satisfy #impls } } -/// Generates `can_satisfy()` method for every host function, to be used to check -/// these functions versus expected module, name and signatures when imporing them from a wasm -/// module. -fn expand_can_satisfy(def: &mut EnvDef) -> proc_macro2::TokenStream { - let checks = def.host_funcs.iter().map(|f| { - let (module, name, signature) = (&f.module, &f.name, &f.to_wasm_sig()); - quote! { - if module == #module.as_bytes() - && name == #name.as_bytes() - && signature == &#signature - { - return true; +/// Generates for every host function: +/// - real implementation, to register it in the contract execution environment; +/// - dummy implementation, to be used as mocks for contract validation step. +fn expand_impls(def: &mut EnvDef) -> TokenStream2 { + let impls = expand_functions(def, true, quote! { crate::wasm::Runtime }); + let dummy_impls = expand_functions(def, false, quote! { () }); + + quote! { + impl<'a, E> crate::wasm::Environment> for Env + where + E: Ext, + ::AccountId: + ::sp_core::crypto::UncheckedFrom<::Hash> + ::core::convert::AsRef<[::core::primitive::u8]>, + { + fn define(store: &mut ::wasmi::Store>, linker: &mut ::wasmi::Linker>) -> Result<(), ::wasmi::errors::LinkerError> { + #impls + Ok(()) } } - }); - let satisfy_checks = quote! { - #( #checks )* - }; - quote! { - impl crate::wasm::env_def::ImportSatisfyCheck for Env { - fn can_satisfy( - module: &[u8], - name: &[u8], - signature: &wasm_instrument::parity_wasm::elements::FunctionType, - ) -> bool { - use crate::wasm::env_def::ConvertibleToWasm; - #[cfg(not(feature = "unstable-interface"))] - if module == b"__unstable__" { - return false; - } - #satisfy_checks - return false; - } + impl crate::wasm::Environment<()> for Env + { + fn define(store: &mut ::wasmi::Store<()>, linker: &mut ::wasmi::Linker<()>) -> Result<(), ::wasmi::errors::LinkerError> { + #dummy_impls + Ok(()) + } } } } -/// Generates implementation for every host function, to register it in the contract execution -/// environment. -fn expand_impls(def: &mut EnvDef) -> proc_macro2::TokenStream { - let impls = def.host_funcs.iter().map(|f| { - let params = &f.item.sig.inputs.iter().skip(1).map(|arg| { - match arg { - syn::FnArg::Typed(pt) => { - if let syn::Pat::Ident(ident) = &*pt.pat { - let p_type = &pt.ty; - let p_name = ident.ident.clone(); - quote! { - let #p_name : <#p_type as crate::wasm::env_def::ConvertibleToWasm>::NativeType = - args.next() - .and_then(|v| <#p_type as crate::wasm::env_def::ConvertibleToWasm>::from_typed_value(v.clone())) - .expect( - "precondition: all imports should be checked against the signatures of corresponding - functions defined by `#[define_env]` proc macro by the user of the macro; - thus this can never be `None`; - qed;" - ); - } - } else { quote! { } } - }, - _ => quote! { }, +fn expand_functions( + def: &mut EnvDef, + expand_blocks: bool, + host_state: TokenStream2, +) -> TokenStream2 { + let impls = def.host_funcs.iter().map(|f| { + // skip the context and memory argument + let params = f.item.sig.inputs.iter().skip(2); + let (module, name, body, wasm_output, output) = ( + &f.module, + &f.name, + &f.item.block, + f.returns.to_wasm_sig(), + &f.item.sig.output + ); + let unstable_feat = match module.as_str() { + "__unstable__" => quote! { #[cfg(feature = "unstable-interface")] }, + _ => quote! {}, + }; + + // If we don't expand blocks (implementing for `()`) we change a few things: + // - We replace any code by unreachable! + // - Allow unused variables as the code that uses is not expanded + // - We don't need to map the error as we simply panic if they code would ever be executed + let inner = if expand_blocks { + quote! { || #output { + let (memory, ctx) = __caller__ + .host_data() + .memory() + .expect("Memory must be set when setting up host data; qed") + .data_and_store_mut(&mut __caller__); + #body + } } + } else { + quote! { || -> #wasm_output { + // This is part of the implementation for `Environment<()>` which is not + // meant to be actually executed. It is only for validation which will + // never call host functions. + ::core::unreachable!() + } } + }; + let map_err = if expand_blocks { + quote! { + |reason| { + ::wasmi::core::Trap::host(reason) + } } - }); - - let outline = match &f.returns { - HostFnReturn::Unit => quote! { - body().map_err(|reason| { - ctx.set_trap_reason(reason); - sp_sandbox::HostError - })?; - return Ok(sp_sandbox::ReturnValue::Unit); - }, - _ => quote! { - let r = body().map_err(|reason| { - ctx.set_trap_reason(reason); - sp_sandbox::HostError - })?; - return Ok(sp_sandbox::ReturnValue::Value({ - r.to_typed_value() - })); - }, - }; - let params = params.clone(); - let (module, name, ident, body) = (&f.module, &f.name, &f.item.sig.ident, &f.item.block); - let unstable_feat = match module.as_str() { - "__unstable__" => quote! { #[cfg(feature = "unstable-interface")] }, - _ => quote! { }, - }; - quote! { - #unstable_feat - f(#module.as_bytes(), #name.as_bytes(), { - fn #ident( - ctx: &mut crate::wasm::Runtime, - args: &[sp_sandbox::Value], - ) -> Result - where - ::AccountId: sp_core::crypto::UncheckedFrom<::Hash> - + AsRef<[u8]>, - { - #[allow(unused)] - let mut args = args.iter(); - let mut body = || { - #( #params )* - #body - }; - #outline + } else { + quote! { + |reason| { reason } } - #ident:: - }); - } - }); + }; + let allow_unused = if expand_blocks { + quote! { } + } else { + quote! { #[allow(unused_variables)] } + }; - let packed_impls = quote! { - #( #impls )* - }; - quote! { - impl crate::wasm::env_def::FunctionImplProvider for Env - where - ::AccountId: - sp_core::crypto::UncheckedFrom<::Hash> + AsRef<[u8]>, - { - fn impls)>(f: &mut F) { - #packed_impls - } + quote! { + #unstable_feat + #allow_unused + linker.define(#module, #name, ::wasmi::Func::wrap(&mut*store, |mut __caller__: ::wasmi::Caller<#host_state>, #( #params, )*| -> #wasm_output { + let mut func = #inner; + func() + .map_err(#map_err) + .map(::core::convert::Into::into) + }))?; } + }); + quote! { + #( #impls )* } } @@ -502,7 +496,7 @@ fn expand_impls(def: &mut EnvDef) -> proc_macro2::TokenStream { /// ```nocompile /// #[define_env] /// pub mod some_env { -/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<(), TrapReason> { +/// fn some_host_fn(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<(), TrapReason> { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// } @@ -517,12 +511,12 @@ fn expand_impls(def: &mut EnvDef) -> proc_macro2::TokenStream { /// #[define_env] /// pub mod some_env { /// #[version(1)] -/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// fn some_host_fn(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// /// #[unstable] -/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// fn some_host_fn(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// } @@ -540,12 +534,12 @@ fn expand_impls(def: &mut EnvDef) -> proc_macro2::TokenStream { /// pub mod some_env { /// #[version(1)] /// #[prefixed_alias] -/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// fn some_host_fn(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// /// #[unstable] -/// fn some_host_fn(ctx: Runtime, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// fn some_host_fn(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// } @@ -562,16 +556,16 @@ fn expand_impls(def: &mut EnvDef) -> proc_macro2::TokenStream { /// - `Result`. /// /// The macro expands to `pub struct Env` declaration, with the following traits implementations: -/// - `pallet_contracts::wasm::env_def::ImportSatisfyCheck` -/// - `pallet_contracts::wasm::env_def::FunctionImplProvider` +/// - `pallet_contracts::wasm::Environment> where E: Ext` +/// - `pallet_contracts::wasm::Environment<()>` +/// +/// The implementation on `()` can be used in places where no `Ext` exists, yet. This is useful +/// when only checking whether a code can be instantiated without actually executing any code. #[proc_macro_attribute] -pub fn define_env( - attr: proc_macro::TokenStream, - item: proc_macro::TokenStream, -) -> proc_macro::TokenStream { +pub fn define_env(attr: TokenStream, item: TokenStream) -> TokenStream { if !attr.is_empty() { let msg = "Invalid `define_env` attribute macro: expected no attributes: `#[define_env]`."; - let span = proc_macro2::TokenStream::from(attr).span(); + let span = TokenStream2::from(attr).span(); return syn::Error::new(span, msg).to_compile_error().into() } diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index b14b107f34c90..c1e9f3208b286 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -28,10 +28,6 @@ use crate::{Config, Determinism}; use frame_support::traits::Get; use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::Hash; -use sp_sandbox::{ - default_executor::{EnvironmentDefinitionBuilder, Memory}, - SandboxEnvironmentBuilder, SandboxMemory, -}; use sp_std::{borrow::ToOwned, prelude::*}; use wasm_instrument::parity_wasm::{ builder, @@ -128,7 +124,7 @@ pub struct ImportedFunction { pub struct WasmModule { pub code: Vec, pub hash: ::Output, - memory: Option, + pub memory: Option, } impl From for WasmModule @@ -395,16 +391,6 @@ where .into() } - /// Creates a memory instance for use in a sandbox with dimensions declared in this module - /// and adds it to `env`. A reference to that memory is returned so that it can be used to - /// access the memory contents from the supervisor. - pub fn add_memory(&self, env: &mut EnvironmentDefinitionBuilder) -> Option { - let memory = if let Some(memory) = &self.memory { memory } else { return None }; - let memory = Memory::new(memory.min_pages, Some(memory.max_pages)).unwrap(); - env.add_memory("env", "memory", memory.clone()); - Some(memory) - } - pub fn unary_instr(instr: Instruction, repeat: u32) -> Self { use body::DynInstr::{RandomI64Repeated, Regular}; ModuleDefinition { diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 539f4b2cf737b..2494a4cbebd55 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -425,7 +425,7 @@ benchmarks! { .map(|n| account::("account", n, 0)) .collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); - let accounts_bytes = accounts.iter().map(|a| a.encode()).flatten().collect::>(); + let accounts_bytes = accounts.iter().flat_map(|a| a.encode()).collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -462,7 +462,7 @@ benchmarks! { .map(|n| account::("account", n, 0)) .collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); - let accounts_bytes = accounts.iter().map(|a| a.encode()).flatten().collect::>(); + let accounts_bytes = accounts.iter().flat_map(|a| a.encode()).collect::>(); let accounts_len = accounts_bytes.len(); let pages = code::max_pages::(); let code = WasmModule::::from(ModuleDefinition { @@ -2014,10 +2014,9 @@ benchmarks! { let r in 0 .. 1; let key_type = sp_core::crypto::KeyTypeId(*b"code"); let pub_keys_bytes = (0..r * API_BENCHMARK_BATCH_SIZE) - .map(|_| { + .flat_map(|_| { sp_io::crypto::ecdsa_generate(key_type, None).0 }) - .flatten() .collect::>(); let pub_keys_bytes_len = pub_keys_bytes.len() as i32; let code = WasmModule::::from(ModuleDefinition { @@ -2086,13 +2085,13 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - reentrant_count { + seal_reentrance_count { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "__unstable__", - name: "reentrant_count", + name: "reentrance_count", params: vec![], return_type: Some(ValueType::I32), }], @@ -2106,7 +2105,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - account_reentrance_count { + seal_account_reentrance_count { let r in 0 .. API_BENCHMARK_BATCHES; let dummy_code = WasmModule::::dummy_with_bytes(0); let accounts = (0..r * API_BENCHMARK_BATCH_SIZE) @@ -2921,7 +2920,7 @@ benchmarks! { #[extra] ink_erc20_transfer { let g in 0 .. 1; - let gas_metering = if g == 0 { false } else { true }; + let gas_metering = g != 0; let code = load_benchmark!("ink_erc20"); let data = { let new: ([u8; 4], BalanceOf) = ([0x9b, 0xae, 0x9d, 0x5e], 1000u32.into()); @@ -2959,7 +2958,7 @@ benchmarks! { #[extra] solang_erc20_transfer { let g in 0 .. 1; - let gas_metering = if g == 0 { false } else { true }; + let gas_metering = g != 0; let code = include_bytes!("../../benchmarks/solang_erc20.wasm"); let caller = account::("instantiator", 0, 0); let mut balance = [0u8; 32]; diff --git a/frame/contracts/src/benchmarking/sandbox.rs b/frame/contracts/src/benchmarking/sandbox.rs index 451d2fe433913..b0cb9297d5656 100644 --- a/frame/contracts/src/benchmarking/sandbox.rs +++ b/frame/contracts/src/benchmarking/sandbox.rs @@ -19,22 +19,20 @@ /// ! sandbox to execute the wasm code. This is because we do not need the full /// ! environment that provides the seal interface as imported functions. use super::{code::WasmModule, Config}; +use crate::wasm::{Environment, PrefabWasmModule}; use sp_core::crypto::UncheckedFrom; -use sp_sandbox::{ - default_executor::{EnvironmentDefinitionBuilder, Instance, Memory}, - SandboxEnvironmentBuilder, SandboxInstance, -}; +use wasmi::{errors::LinkerError, Func, Linker, StackLimits, Store}; -/// Minimal execution environment without any exported functions. +/// Minimal execution environment without any imported functions. pub struct Sandbox { - instance: Instance<()>, - _memory: Option, + entry_point: Func, + store: Store<()>, } impl Sandbox { /// Invoke the `call` function of a contract code and panic on any execution error. pub fn invoke(&mut self) { - self.instance.invoke("call", &[], &mut ()).unwrap(); + self.entry_point.call(&mut self.store, &[], &mut []).unwrap(); } } @@ -46,10 +44,27 @@ where /// Creates an instance from the supplied module and supplies as much memory /// to the instance as the module declares as imported. fn from(module: &WasmModule) -> Self { - let mut env_builder = EnvironmentDefinitionBuilder::new(); - let memory = module.add_memory(&mut env_builder); - let instance = Instance::new(&module.code, &env_builder, &mut ()) - .expect("Failed to create benchmarking Sandbox instance"); - Self { instance, _memory: memory } + let memory = module + .memory + .as_ref() + .map(|mem| (mem.min_pages, mem.max_pages)) + .unwrap_or((0, 0)); + let (store, _memory, instance) = PrefabWasmModule::::instantiate::( + &module.code, + (), + memory, + StackLimits::default(), + ) + .expect("Failed to create benchmarking Sandbox instance"); + let entry_point = instance.get_export(&store, "call").unwrap().into_func().unwrap(); + Self { entry_point, store } + } +} + +struct EmptyEnv; + +impl Environment<()> for EmptyEnv { + fn define(_store: &mut Store<()>, _linker: &mut Linker<()>) -> Result<(), LinkerError> { + Ok(()) } } diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index d0e0cf5cf95cb..3c3e9b1ef0f59 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -270,6 +270,7 @@ impl<'a, 'b, E: Ext> Environment<'a, 'b, E, InitState> { /// ever create this type. Chain extensions merely consume it. pub(crate) fn new( runtime: &'a mut Runtime<'b, E>, + memory: &'a mut [u8], id: u32, input_ptr: u32, input_len: u32, @@ -277,7 +278,7 @@ impl<'a, 'b, E: Ext> Environment<'a, 'b, E, InitState> { output_len_ptr: u32, ) -> Self { Environment { - inner: Inner { runtime, id, input_ptr, input_len, output_ptr, output_len_ptr }, + inner: Inner { runtime, memory, id, input_ptr, input_len, output_ptr, output_len_ptr }, phantom: PhantomData, } } @@ -338,9 +339,11 @@ where /// charge the overall costs either using `max_len` (worst case approximation) or using /// [`in_len()`](Self::in_len). pub fn read(&self, max_len: u32) -> Result> { - self.inner - .runtime - .read_sandbox_memory(self.inner.input_ptr, self.inner.input_len.min(max_len)) + self.inner.runtime.read_sandbox_memory( + self.inner.memory, + self.inner.input_ptr, + self.inner.input_len.min(max_len), + ) } /// Reads `min(buffer.len(), in_len) from contract memory. @@ -354,7 +357,11 @@ where let buffer = core::mem::take(buffer); &mut buffer[..len.min(self.inner.input_len as usize)] }; - self.inner.runtime.read_sandbox_memory_into_buf(self.inner.input_ptr, sliced)?; + self.inner.runtime.read_sandbox_memory_into_buf( + self.inner.memory, + self.inner.input_ptr, + sliced, + )?; *buffer = sliced; Ok(()) } @@ -366,14 +373,20 @@ where /// weight of the chain extension. This should usually be the case when fixed input types /// are used. pub fn read_as(&mut self) -> Result { - self.inner.runtime.read_sandbox_memory_as(self.inner.input_ptr) + self.inner + .runtime + .read_sandbox_memory_as(self.inner.memory, self.inner.input_ptr) } /// Reads and decodes a type with a dynamic size from contract memory. /// /// Make sure to include `len` in your weight calculations. pub fn read_as_unbounded(&mut self, len: u32) -> Result { - self.inner.runtime.read_sandbox_memory_as_unbounded(self.inner.input_ptr, len) + self.inner.runtime.read_sandbox_memory_as_unbounded( + self.inner.memory, + self.inner.input_ptr, + len, + ) } /// The length of the input as passed in as `input_len`. @@ -406,6 +419,7 @@ where weight_per_byte: Option, ) -> Result<()> { self.inner.runtime.write_sandbox_output( + self.inner.memory, self.inner.output_ptr, self.inner.output_len_ptr, buffer, @@ -426,6 +440,8 @@ where struct Inner<'a, 'b, E: Ext> { /// The runtime contains all necessary functions to interact with the running contract. runtime: &'a mut Runtime<'b, E>, + /// Reference to the contracts memory. + memory: &'a mut [u8], /// Verbatim argument passed to `seal_call_chain_extension`. id: u32, /// Verbatim argument passed to `seal_call_chain_extension`. diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 76b200001af78..2884779d8fda7 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -299,7 +299,7 @@ pub trait Ext: sealing::Sealed { /// Returns the number of times the currently executing contract exists on the call stack in /// addition to the calling instance. A value of 0 means no reentrancy. - fn reentrant_count(&self) -> u32; + fn reentrance_count(&self) -> u32; /// Returns the number of times the specified contract exists on the call stack. Delegated calls /// are not calculated as separate entrance. @@ -1384,7 +1384,7 @@ where Ok(()) } - fn reentrant_count(&self) -> u32 { + fn reentrance_count(&self) -> u32 { let id: &AccountIdOf = &self.top_frame().account_id; self.account_reentrance_count(id).saturating_sub(1) } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 52fb0190ba3a9..00b0655ea4af6 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -102,7 +102,7 @@ use crate::{ exec::{AccountIdOf, ExecError, Executable, Stack as ExecStack}, gas::GasMeter, storage::{meter::Meter as StorageMeter, ContractInfo, DeletedContract, Storage}, - wasm::{OwnerInfo, PrefabWasmModule}, + wasm::{OwnerInfo, PrefabWasmModule, TryInstantiate}, weights::WeightInfo, }; use codec::{Codec, Encode, HasCompact}; @@ -830,8 +830,13 @@ pub mod pallet { /// to determine whether a reversion has taken place. ContractReverted, /// The contract's code was found to be invalid during validation or instrumentation. + /// + /// The most likely cause of this is that an API was used which is not supported by the + /// node. This hapens if an older node is used with a new version of ink!. Try updating + /// your node to the newest available version. + /// /// A more detailed error can be found on the node console if debug messages are enabled - /// or in the debug buffer which is returned to RPC clients. + /// by supplying `-lruntime::contracts=debug`. CodeRejected, /// An indetermistic code was used in a context where this is not permitted. Indeterministic, @@ -1009,8 +1014,14 @@ where determinism: Determinism, ) -> CodeUploadResult, BalanceOf> { let schedule = T::Schedule::get(); - let module = PrefabWasmModule::from_code(code, &schedule, origin, determinism) - .map_err(|(err, _)| err)?; + let module = PrefabWasmModule::from_code( + code, + &schedule, + origin, + determinism, + TryInstantiate::Instantiate, + ) + .map_err(|(err, _)| err)?; let deposit = module.open_deposit(); if let Some(storage_deposit_limit) = storage_deposit_limit { ensure!(storage_deposit_limit >= deposit, >::StorageDepositLimitExhausted); @@ -1135,6 +1146,7 @@ where &schedule, origin.clone(), Determinism::Deterministic, + TryInstantiate::Skip, ) .map_err(|(err, msg)| { debug_message.as_mut().map(|buffer| buffer.extend(msg.as_bytes())); diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 52cb7698d6952..79f9f49e58190 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -423,8 +423,8 @@ pub struct HostFnWeights { /// Weight of calling `seal_ecdsa_to_eth_address`. pub ecdsa_to_eth_address: u64, - /// Weight of calling `seal_reentrant_count`. - pub reentrant_count: u64, + /// Weight of calling `seal_reentrance_count`. + pub reentrance_count: u64, /// Weight of calling `seal_account_reentrance_count`. pub account_reentrance_count: u64, @@ -538,7 +538,7 @@ impl Default for InstructionWeights { fn default() -> Self { let max_pages = Limits::default().memory_pages; Self { - version: 3, + version: 4, fallback: 0, i64const: cost_instr!(instr_i64const, 1), i64load: cost_instr!(instr_i64load, 2), @@ -665,7 +665,7 @@ impl Default for HostFnWeights { hash_blake2_128_per_byte: cost_byte_batched!(seal_hash_blake2_128_per_kb), ecdsa_recover: cost_batched!(seal_ecdsa_recover), ecdsa_to_eth_address: cost_batched!(seal_ecdsa_to_eth_address), - reentrant_count: cost_batched!(seal_reentrant_count), + reentrance_count: cost_batched!(seal_reentrance_count), account_reentrance_count: cost_batched!(seal_account_reentrance_count), _phantom: PhantomData, } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 7054ceb07a6fc..e7b27ed38e271 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -514,7 +514,7 @@ fn calling_plain_account_fails() { #[test] fn instantiate_and_call_and_deposit_event() { - let (wasm, code_hash) = compile_module::("return_from_start_fn").unwrap(); + let (wasm, code_hash) = compile_module::("event_and_return_on_deploy").unwrap(); ExtBuilder::default().existential_deposit(500).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); @@ -3720,10 +3720,36 @@ fn contract_reverted() { #[test] fn code_rejected_error_works() { - let (wasm, _) = compile_module::("invalid_import").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let (wasm, _) = compile_module::("invalid_module").unwrap(); + assert_noop!( + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm.clone(), + None, + Determinism::Deterministic + ), + >::CodeRejected, + ); + let result = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(wasm), + vec![], + vec![], + true, + ); + assert_err!(result.result, >::CodeRejected); + assert_eq!( + std::str::from_utf8(&result.debug_message).unwrap(), + "validation of new code failed" + ); + + let (wasm, _) = compile_module::("invalid_contract").unwrap(); assert_noop!( Contracts::upload_code( RuntimeOrigin::signed(ALICE), @@ -3747,7 +3773,7 @@ fn code_rejected_error_works() { assert_err!(result.result, >::CodeRejected); assert_eq!( std::str::from_utf8(&result.debug_message).unwrap(), - "module imports a non-existent function" + "call function isn't exported" ); }); } @@ -4386,8 +4412,8 @@ fn delegate_call_indeterministic_code() { #[test] #[cfg(feature = "unstable-interface")] -fn reentrant_count_works_with_call() { - let (wasm, code_hash) = compile_module::("reentrant_count_call").unwrap(); +fn reentrance_count_works_with_call() { + let (wasm, code_hash) = compile_module::("reentrance_count_call").unwrap(); let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]); ExtBuilder::default().existential_deposit(100).build().execute_with(|| { @@ -4423,8 +4449,8 @@ fn reentrant_count_works_with_call() { #[test] #[cfg(feature = "unstable-interface")] -fn reentrant_count_works_with_delegated_call() { - let (wasm, code_hash) = compile_module::("reentrant_count_delegated_call").unwrap(); +fn reentrance_count_works_with_delegated_call() { + let (wasm, code_hash) = compile_module::("reentrance_count_delegated_call").unwrap(); let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]); ExtBuilder::default().existential_deposit(100).build().execute_with(|| { @@ -4462,8 +4488,8 @@ fn reentrant_count_works_with_delegated_call() { #[cfg(feature = "unstable-interface")] fn account_reentrance_count_works() { let (wasm, code_hash) = compile_module::("account_reentrance_count_call").unwrap(); - let (wasm_reentrant_count, code_hash_reentrant_count) = - compile_module::("reentrant_count_call").unwrap(); + let (wasm_reentrance_count, code_hash_reentrance_count) = + compile_module::("reentrance_count_call").unwrap(); ExtBuilder::default().existential_deposit(100).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); @@ -4483,14 +4509,14 @@ fn account_reentrance_count_works() { 300_000, GAS_LIMIT, None, - wasm_reentrant_count, + wasm_reentrance_count, vec![], vec![] )); let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]); let another_contract_addr = - Contracts::contract_address(&ALICE, &code_hash_reentrant_count, &[]); + Contracts::contract_address(&ALICE, &code_hash_reentrance_count, &[]); let result1 = Contracts::bare_call( ALICE, diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 3ede6db6db5a1..eb337ac682860 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -192,7 +192,10 @@ where pub fn reinstrument( prefab_module: &mut PrefabWasmModule, schedule: &Schedule, -) -> Result { +) -> Result +where + T::AccountId: UncheckedFrom + AsRef<[u8]>, +{ let original_code = >::get(&prefab_module.code_hash).ok_or(Error::::CodeNotFound)?; let original_code_len = original_code.len(); @@ -201,9 +204,12 @@ pub fn reinstrument( // as the contract is already deployed and every change in size would be the result // of changes in the instrumentation algorithm controlled by the chain authors. prefab_module.code = WeakBoundedVec::force_from( - prepare::reinstrument_contract::(&original_code, schedule, prefab_module.determinism) - .map_err(|_| >::CodeRejected)?, - Some("Contract exceeds limit after re-instrumentation."), + prepare::reinstrument::( + &original_code, + schedule, + prefab_module.determinism, + )?, + Some("Contract exceeds size limit after re-instrumentation."), ); prefab_module.instruction_weights_version = schedule.instruction_weights.version; >::insert(&prefab_module.code_hash, &*prefab_module); diff --git a/frame/contracts/src/wasm/env_def/mod.rs b/frame/contracts/src/wasm/env_def/mod.rs deleted file mode 100644 index be6e688c97868..0000000000000 --- a/frame/contracts/src/wasm/env_def/mod.rs +++ /dev/null @@ -1,83 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::Runtime; -use crate::exec::Ext; - -use sp_sandbox::Value; -use wasm_instrument::parity_wasm::elements::{FunctionType, ValueType}; - -pub trait ConvertibleToWasm: Sized { - const VALUE_TYPE: ValueType; - type NativeType; - fn to_typed_value(self) -> Value; - fn from_typed_value(_: Value) -> Option; -} -impl ConvertibleToWasm for i32 { - const VALUE_TYPE: ValueType = ValueType::I32; - type NativeType = i32; - fn to_typed_value(self) -> Value { - Value::I32(self) - } - fn from_typed_value(v: Value) -> Option { - v.as_i32() - } -} -impl ConvertibleToWasm for u32 { - const VALUE_TYPE: ValueType = ValueType::I32; - type NativeType = u32; - fn to_typed_value(self) -> Value { - Value::I32(self as i32) - } - fn from_typed_value(v: Value) -> Option { - match v { - Value::I32(v) => Some(v as u32), - _ => None, - } - } -} -impl ConvertibleToWasm for u64 { - const VALUE_TYPE: ValueType = ValueType::I64; - type NativeType = u64; - fn to_typed_value(self) -> Value { - Value::I64(self as i64) - } - fn from_typed_value(v: Value) -> Option { - match v { - Value::I64(v) => Some(v as u64), - _ => None, - } - } -} - -pub type HostFunc = fn( - &mut Runtime, - &[sp_sandbox::Value], -) -> Result; - -pub trait FunctionImplProvider { - fn impls)>(f: &mut F); -} - -/// This trait can be used to check whether the host environment can satisfy -/// a requested function import. -pub trait ImportSatisfyCheck { - /// Returns `true` if the host environment contains a function with - /// the specified name and its type matches to the given type, or `false` - /// otherwise. - fn can_satisfy(module: &[u8], name: &[u8], func_type: &FunctionType) -> bool; -} diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index ba0a0abf11302..86bc377b81307 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -18,19 +18,19 @@ //! This module provides a means for executing contracts //! represented in wasm. -#[macro_use] -mod env_def; mod code_cache; mod prepare; mod runtime; #[cfg(feature = "runtime-benchmarks")] pub use crate::wasm::code_cache::reinstrument; -pub use crate::wasm::runtime::{CallFlags, ReturnCode, Runtime, RuntimeCosts}; +pub use crate::wasm::{ + prepare::TryInstantiate, + runtime::{CallFlags, Environment, ReturnCode, Runtime, RuntimeCosts}, +}; use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, gas::GasMeter, - wasm::env_def::FunctionImplProvider, AccountIdOf, BalanceOf, CodeHash, CodeStorage, CodeVec, Config, Error, RelaxedCodeVec, Schedule, }; @@ -38,10 +38,12 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::dispatch::{DispatchError, DispatchResult}; use sp_core::crypto::UncheckedFrom; use sp_runtime::RuntimeDebug; -use sp_sandbox::{SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory}; use sp_std::prelude::*; #[cfg(test)] pub use tests::MockExt; +use wasmi::{ + Config as WasmiConfig, Engine, Instance, Linker, Memory, MemoryType, Module, StackLimits, Store, +}; /// A prepared wasm module ready for execution. /// @@ -151,12 +153,14 @@ where schedule: &Schedule, owner: AccountIdOf, determinism: Determinism, + try_instantiate: TryInstantiate, ) -> Result { - let module = prepare::prepare_contract( + let module = prepare::prepare::( original_code.try_into().map_err(|_| (>::CodeTooLarge.into(), ""))?, schedule, owner, determinism, + try_instantiate, )?; Ok(module) } @@ -189,6 +193,44 @@ where } } + /// Creates and returns an instance of the supplied code. + /// + /// This is either used for later executing a contract or for validation of a contract. + /// When validating we pass `()` as `host_state`. Please note that such a dummy instance must + /// **never** be called/executed since it will panic the executor. + pub fn instantiate( + code: &[u8], + host_state: H, + memory: (u32, u32), + stack_limits: StackLimits, + ) -> Result<(Store, Memory, Instance), wasmi::Error> + where + E: Environment, + { + let mut config = WasmiConfig::default(); + config + .set_stack_limits(stack_limits) + .wasm_multi_value(false) + .wasm_mutable_global(false) + .wasm_sign_extension(false) + .wasm_saturating_float_to_int(false); + let engine = Engine::new(&config); + let module = Module::new(&engine, code)?; + let mut store = Store::new(&engine, host_state); + let mut linker = Linker::new(); + E::define(&mut store, &mut linker)?; + let memory = Memory::new(&mut store, MemoryType::new(memory.0, Some(memory.1))?).expect( + "The limits defined in our `Schedule` limit the amount of memory well below u32::MAX; qed", + ); + linker + .define("env", "memory", memory) + .expect("We just created the linker. It has no define with this name attached; qed"); + + let instance = linker.instantiate(&mut store, &module)?.ensure_no_start(&mut store)?; + + Ok((store, memory, instance)) + } + /// Create and store the module without checking nor instrumenting the passed code. /// /// # Note @@ -201,7 +243,7 @@ where schedule: &Schedule, owner: T::AccountId, ) -> DispatchResult { - let executable = prepare::benchmarking::prepare_contract(original_code, schedule, owner) + let executable = prepare::benchmarking::prepare(original_code, schedule, owner) .map_err::(Into::into)?; code_cache::store(executable, false) } @@ -247,36 +289,35 @@ where function: &ExportedFunction, input_data: Vec, ) -> ExecResult { - let memory = sp_sandbox::default_executor::Memory::new(self.initial, Some(self.maximum)) - .unwrap_or_else(|_| { - // unlike `.expect`, explicit panic preserves the source location. - // Needed as we can't use `RUST_BACKTRACE` in here. - panic!( - "exec.prefab_module.initial can't be greater than exec.prefab_module.maximum; - thus Memory::new must not fail; - qed" - ) - }); - - let mut imports = sp_sandbox::default_executor::EnvironmentDefinitionBuilder::new(); - imports.add_memory(self::prepare::IMPORT_MODULE_MEMORY, "memory", memory.clone()); - runtime::Env::impls(&mut |module, name, func_ptr| { - imports.add_host_func(module, name, func_ptr); - }); + let runtime = Runtime::new(ext, input_data); + let (mut store, memory, instance) = Self::instantiate::( + self.code.as_slice(), + runtime, + (self.initial, self.maximum), + StackLimits::default(), + ) + .map_err(|msg| { + log::debug!(target: "runtime::contracts", "failed to instantiate code: {}", msg); + Error::::CodeRejected + })?; + store.state_mut().set_memory(memory); + + let exported_func = instance + .get_export(&store, function.identifier()) + .and_then(|export| export.into_func()) + .ok_or_else(|| { + log::error!(target: "runtime::contracts", "failed to find entry point"); + Error::::CodeRejected + })?; // We store before executing so that the code hash is available in the constructor. - let code = self.code.clone(); if let &ExportedFunction::Constructor = function { code_cache::store(self, true)?; } - // Instantiate the instance from the instrumented module code and invoke the contract - // entrypoint. - let mut runtime = Runtime::new(ext, input_data, memory); - let result = sp_sandbox::default_executor::Instance::new(&code, &imports, &mut runtime) - .and_then(|mut instance| instance.invoke(function.identifier(), &[], &mut runtime)); + let result = exported_func.call(&mut store, &[], &mut []); - runtime.to_execution_result(result) + store.into_state().to_execution_result(result) } fn code_hash(&self) -> &CodeHash { @@ -307,7 +348,7 @@ mod tests { }; use assert_matches::assert_matches; use frame_support::{ - assert_ok, + assert_err, assert_ok, dispatch::DispatchResultWithPostInfo, weights::{OldWeight, Weight}, }; @@ -578,7 +619,7 @@ mod tests { fn ecdsa_to_eth_address(&self, _pk: &[u8; 33]) -> Result<[u8; 20], ()> { Ok([2u8; 20]) } - fn reentrant_count(&self) -> u32 { + fn reentrance_count(&self) -> u32 { 12 } fn account_reentrance_count(&self, _account_id: &AccountIdOf) -> u32 { @@ -594,8 +635,9 @@ mod tests { &schedule, ALICE, Determinism::Deterministic, + TryInstantiate::Skip, ) - .unwrap(); + .map_err(|err| err.0)?; executable.execute(ext.borrow_mut(), &ExportedFunction::Call, input_data) } @@ -788,10 +830,7 @@ mod tests { "#; let mut mock_ext = MockExt::default(); let input = vec![0xff, 0x2a, 0x99, 0x88]; - frame_support::assert_err!( - execute(CODE, input.clone(), &mut mock_ext), - >::InputForwarded, - ); + assert_err!(execute(CODE, input.clone(), &mut mock_ext), >::InputForwarded,); assert_eq!( &mock_ext.calls, @@ -1584,35 +1623,32 @@ mod tests { assert_ok!(execute(CODE_VALUE_TRANSFERRED, vec![], MockExt::default())); } - const CODE_RETURN_FROM_START_FN: &str = r#" + const START_FN_ILLEGAL: &str = r#" (module (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) (start $start) (func $start - (call $seal_return - (i32.const 0) - (i32.const 8) - (i32.const 4) - ) (unreachable) ) (func (export "call") (unreachable) ) - (func (export "deploy")) + + (func (export "deploy") + (unreachable) + ) (data (i32.const 8) "\01\02\03\04") ) "#; #[test] - fn return_from_start_fn() { - let output = execute(CODE_RETURN_FROM_START_FN, vec![], MockExt::default()).unwrap(); - - assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: vec![1, 2, 3, 4] }); + fn start_fn_illegal() { + let output = execute(START_FN_ILLEGAL, vec![], MockExt::default()); + assert_err!(output, >::CodeRejected,); } const CODE_TIMESTAMP_NOW: &str = r#" @@ -2859,10 +2895,10 @@ mod tests { #[test] #[cfg(feature = "unstable-interface")] - fn reentrant_count_works() { + fn reentrance_count_works() { const CODE: &str = r#" (module - (import "__unstable__" "reentrant_count" (func $reentrant_count (result i32))) + (import "__unstable__" "reentrance_count" (func $reentrance_count (result i32))) (import "env" "memory" (memory 1 1)) (func $assert (param i32) (block $ok @@ -2875,7 +2911,7 @@ mod tests { (func (export "call") (local $return_val i32) (set_local $return_val - (call $reentrant_count) + (call $reentrance_count) ) (call $assert (i32.eq (get_local $return_val) (i32.const 12)) diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 3e6b9eee96680..fb5ae1229078f 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -22,20 +22,38 @@ use crate::{ chain_extension::ChainExtension, storage::meter::Diff, - wasm::{env_def::ImportSatisfyCheck, Determinism, OwnerInfo, PrefabWasmModule}, + wasm::{Determinism, Environment, OwnerInfo, PrefabWasmModule}, AccountIdOf, CodeVec, Config, Error, Schedule, }; use codec::{Encode, MaxEncodedLen}; +use sp_core::crypto::UncheckedFrom; use sp_runtime::{traits::Hash, DispatchError}; use sp_std::prelude::*; use wasm_instrument::parity_wasm::elements::{ self, External, Internal, MemoryType, Type, ValueType, }; +use wasmi::StackLimits; +use wasmparser::{Validator, WasmFeatures}; /// Imported memory must be located inside this module. The reason for hardcoding is that current /// compiler toolchains might not support specifying other modules than "env" for memory imports. pub const IMPORT_MODULE_MEMORY: &str = "env"; +/// Determines whether a module should be instantiated during preparation. +pub enum TryInstantiate { + /// Do the instantiation to make sure that the module is valid. + /// + /// This should be used if a module is only uploaded but not executed. We need + /// to make sure that it can be actually instantiated. + Instantiate, + /// Skip the instantiation during preparation. + /// + /// This makes sense when the preparation takes place as part of an instantation. Then + /// this instantiation would fail the whole transaction and an extra check is not + /// necessary. + Skip, +} + struct ContractModule<'a, T: Config> { /// A deserialized module. The module is valid (this is Guaranteed by `new` method). module: elements::Module, @@ -48,14 +66,9 @@ impl<'a, T: Config> ContractModule<'a, T> { /// Returns `Err` if the `original_code` couldn't be decoded or /// if it contains an invalid module. fn new(original_code: &[u8], schedule: &'a Schedule) -> Result { - use wasmi_validation::{validate_module, PlainValidator}; - let module = elements::deserialize_buffer(original_code).map_err(|_| "Can't decode wasm code")?; - // Make sure that the module is valid. - validate_module::(&module, ()).map_err(|_| "Module is not valid")?; - // Return a `ContractModule` instance with // __valid__ module. Ok(ContractModule { module, schedule }) @@ -279,27 +292,33 @@ impl<'a, T: Config> ContractModule<'a, T> { /// Scan an import section if any. /// - /// This accomplishes two tasks: + /// This makes sure that the import section looks as we expect it from a contract + /// and enforces and returns the memory type declared by the contract if any. /// - /// - checks any imported function against defined host functions set, incl. their signatures. - /// - if there is a memory import, returns it's descriptor /// `import_fn_banlist`: list of function names that are disallowed to be imported - fn scan_imports( + fn scan_imports( &self, import_fn_banlist: &[&[u8]], ) -> Result, &'static str> { let module = &self.module; - - let types = module.type_section().map(|ts| ts.types()).unwrap_or(&[]); let import_entries = module.import_section().map(|is| is.entries()).unwrap_or(&[]); - let mut imported_mem_type = None; for import in import_entries { - let type_idx = match *import.external() { + match *import.external() { External::Table(_) => return Err("Cannot import tables"), External::Global(_) => return Err("Cannot import globals"), - External::Function(ref type_idx) => type_idx, + External::Function(_) => { + if !T::ChainExtension::enabled() && + import.field().as_bytes() == b"seal_call_chain_extension" + { + return Err("module uses chain extensions but chain extensions are disabled") + } + + if import_fn_banlist.iter().any(|f| import.field().as_bytes() == *f) { + return Err("module imports a banned function") + } + }, External::Memory(ref memory_type) => { if import.module() != IMPORT_MODULE_MEMORY { return Err("Invalid module for imported memory") @@ -313,22 +332,6 @@ impl<'a, T: Config> ContractModule<'a, T> { imported_mem_type = Some(memory_type); continue }, - }; - - let Type::Function(ref func_ty) = types - .get(*type_idx as usize) - .ok_or("validation: import entry points to a non-existent type")?; - - if !T::ChainExtension::enabled() && - import.field().as_bytes() == b"seal_call_chain_extension" - { - return Err("module uses chain extensions but chain extensions are disabled") - } - - if import_fn_banlist.iter().any(|f| import.field().as_bytes() == *f) || - !C::can_satisfy(import.module().as_bytes(), import.field().as_bytes(), func_ty) - { - return Err("module imports a non-existent function") } } Ok(imported_mem_type) @@ -366,12 +369,54 @@ fn get_memory_limits( } } -fn check_and_instrument( +/// Check and instrument the given `original_code`. +/// +/// On success it returns the instrumented versions together with its `(initial, maximum)` +/// error requirement. The memory requirement was also validated against the `schedule`. +fn instrument( original_code: &[u8], schedule: &Schedule, determinism: Determinism, -) -> Result<(Vec, (u32, u32)), &'static str> { - let result = (|| { + try_instantiate: TryInstantiate, +) -> Result<(Vec, (u32, u32)), (DispatchError, &'static str)> +where + E: Environment<()>, + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]>, +{ + // Do not enable any features here. Any additional feature needs to be carefully + // checked for potential security issues. For example, enabling multi value could lead + // to a DoS vector: It breaks our assumption that branch instructions are of constant time. + // Depending on the implementation they can linearly depend on the amount of values returned + // from a block. + Validator::new_with_features(WasmFeatures { + relaxed_simd: false, + threads: false, + tail_call: false, + multi_memory: false, + exceptions: false, + memory64: false, + extended_const: false, + component_model: false, + // This is not our only defense: We check for float types later in the preparation + // process. Additionally, all instructions explictily need to have weights assigned + // or the deployment will fail. We have none assigned for float instructions. + deterministic_only: matches!(determinism, Determinism::Deterministic), + mutable_global: false, + saturating_float_to_int: false, + sign_extension: false, + bulk_memory: false, + multi_value: false, + reference_types: false, + simd: false, + }) + .validate_all(original_code) + .map_err(|err| { + log::debug!(target: "runtime::contracts", "{}", err); + (Error::::CodeRejected.into(), "validation of new code failed") + })?; + + let (code, (initial, maximum)) = (|| { let contract_module = ContractModule::new(original_code, schedule)?; contract_module.scan_exports()?; contract_module.ensure_no_internal_memory()?; @@ -387,7 +432,7 @@ fn check_and_instrument( // We disallow importing `gas` function here since it is treated as implementation detail. let disallowed_imports = [b"gas".as_ref()]; let memory_limits = - get_memory_limits(contract_module.scan_imports::(&disallowed_imports)?, schedule)?; + get_memory_limits(contract_module.scan_imports(&disallowed_imports)?, schedule)?; let code = contract_module .inject_gas_metering(determinism)? @@ -395,24 +440,56 @@ fn check_and_instrument( .into_wasm_code()?; Ok((code, memory_limits)) - })(); - - if let Err(msg) = &result { - log::debug!(target: "runtime::contracts", "CodeRejected: {}", msg); + })() + .map_err(|msg: &str| { + log::debug!(target: "runtime::contracts", "new code rejected: {}", msg); + (Error::::CodeRejected.into(), msg) + })?; + + // This will make sure that the module can be actually run within wasmi: + // + // - Doesn't use any unknown imports. + // - Doesn't explode the wasmi bytecode generation. + if matches!(try_instantiate, TryInstantiate::Instantiate) { + // We don't actually ever run any code so we can get away with a minimal stack which + // reduces the amount of memory that needs to be zeroed. + let stack_limits = StackLimits::new(1, 1, 0).expect("initial <= max; qed"); + PrefabWasmModule::::instantiate::(&code, (), (initial, maximum), stack_limits) + .map_err(|err| { + log::debug!(target: "runtime::contracts", "{}", err); + (Error::::CodeRejected.into(), "new code rejected after instrumentation") + })?; } - result + Ok((code, (initial, maximum))) } -fn do_preparation( +/// Loads the given module given in `original_code`, performs some checks on it and +/// does some preprocessing. +/// +/// The checks are: +/// +/// - the provided code is a valid wasm module +/// - the module doesn't define an internal memory instance +/// - imported memory (if any) doesn't reserve more memory than permitted by the `schedule` +/// - all imported functions from the external environment matches defined by `env` module +/// +/// The preprocessing includes injecting code for gas metering and metering the height of stack. +pub fn prepare( original_code: CodeVec, schedule: &Schedule, owner: AccountIdOf, determinism: Determinism, -) -> Result, (DispatchError, &'static str)> { + try_instantiate: TryInstantiate, +) -> Result, (DispatchError, &'static str)> +where + E: Environment<()>, + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]>, +{ let (code, (initial, maximum)) = - check_and_instrument::(original_code.as_ref(), schedule, determinism) - .map_err(|msg| (>::CodeRejected.into(), msg))?; + instrument::(original_code.as_ref(), schedule, determinism, try_instantiate)?; + let original_code_len = original_code.len(); let mut module = PrefabWasmModule { @@ -420,10 +497,10 @@ fn do_preparation( initial, maximum, code: code.try_into().map_err(|_| (>::CodeTooLarge.into(), ""))?, - determinism, code_hash: T::Hashing::hash(&original_code), original_code: Some(original_code), owner_info: None, + determinism, }; // We need to add the sizes of the `#[codec(skip)]` fields which are stored in different @@ -441,37 +518,28 @@ fn do_preparation( Ok(module) } -/// Loads the given module given in `original_code`, performs some checks on it and -/// does some preprocessing. -/// -/// The checks are: -/// -/// - provided code is a valid wasm module. -/// - the module doesn't define an internal memory instance, -/// - imported memory (if any) doesn't reserve more memory than permitted by the `schedule`, -/// - all imported functions from the external environment matches defined by `env` module, -/// -/// The preprocessing includes injecting code for gas metering and metering the height of stack. -pub fn prepare_contract( - original_code: CodeVec, - schedule: &Schedule, - owner: AccountIdOf, - determinism: Determinism, -) -> Result, (DispatchError, &'static str)> { - do_preparation::(original_code, schedule, owner, determinism) -} - -/// The same as [`prepare_contract`] but without constructing a new [`PrefabWasmModule`] -/// -/// # Note +/// Same as [`prepare`] but without constructing a new module. /// -/// Use this when an existing contract should be re-instrumented with a newer schedule version. -pub fn reinstrument_contract( +/// Used to update the code of an existing module to the newest [`Schedule`] version. +/// Stictly speaking is not necessary to check the existing code before reinstrumenting because +/// it can't change in the meantime. However, since we recently switched the validation library +/// we want to re-validate to weed out any bugs that were lurking in the old version. +pub fn reinstrument( original_code: &[u8], schedule: &Schedule, determinism: Determinism, -) -> Result, &'static str> { - Ok(check_and_instrument::(original_code, schedule, determinism)?.0) +) -> Result, DispatchError> +where + E: Environment<()>, + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]>, +{ + instrument::(original_code, schedule, determinism, TryInstantiate::Skip) + .map_err(|(err, msg)| { + log::error!(target: "runtime::contracts", "CodeRejected during reinstrument: {}", msg); + err + }) + .map(|(code, _)| code) } /// Alternate (possibly unsafe) preparation functions used only for benchmarking. @@ -482,29 +550,22 @@ pub fn reinstrument_contract( /// in production code. #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking { - use super::{elements::FunctionType, *}; - - impl ImportSatisfyCheck for () { - fn can_satisfy(_module: &[u8], _name: &[u8], _func_type: &FunctionType) -> bool { - true - } - } + use super::*; /// Prepare function that neither checks nor instruments the passed in code. - pub fn prepare_contract( + pub fn prepare( original_code: Vec, schedule: &Schedule, owner: AccountIdOf, ) -> Result, &'static str> { let contract_module = ContractModule::new(&original_code, schedule)?; - let memory_limits = get_memory_limits(contract_module.scan_imports::<()>(&[])?, schedule)?; + let memory_limits = get_memory_limits(contract_module.scan_imports(&[])?, schedule)?; Ok(PrefabWasmModule { instruction_weights_version: schedule.instruction_weights.version, initial: memory_limits.0, maximum: memory_limits.1, code_hash: T::Hashing::hash(&original_code), original_code: Some(original_code.try_into().map_err(|_| "Original code too large")?), - determinism: Determinism::Deterministic, code: contract_module .into_wasm_code()? .try_into() @@ -515,6 +576,7 @@ pub mod benchmarking { deposit: Default::default(), refcount: 0, }), + determinism: Determinism::Deterministic, }) } } @@ -540,27 +602,28 @@ mod tests { #[allow(unreachable_code)] mod env { use super::*; + use crate::wasm::runtime::TrapReason; // Define test environment for tests. We need ImportSatisfyCheck // implementation from it. So actual implementations doesn't matter. #[define_env] pub mod test_env { - fn panic(_ctx: crate::wasm::Runtime) -> Result<(), TrapReason> { + fn panic(_ctx: _, _memory: _) -> Result<(), TrapReason> { Ok(()) } // gas is an implementation defined function and a contract can't import it. - fn gas(_ctx: crate::wasm::Runtime, _amount: u32) -> Result<(), TrapReason> { + fn gas(_ctx: _, _memory: _, _amount: u64) -> Result<(), TrapReason> { Ok(()) } - fn nop(_ctx: crate::wasm::Runtime, _unused: u64) -> Result<(), TrapReason> { + fn nop(_ctx: _, _memory: _, _unused: u64) -> Result<(), TrapReason> { Ok(()) } - // new version of nop with other data type for argumebt + // new version of nop with other data type for argument #[version(1)] - fn nop(_ctx: crate::wasm::Runtime, _unused: i32) -> Result<(), TrapReason> { + fn nop(_ctx: _, _memory: _, _unused: i32) -> Result<(), TrapReason> { Ok(()) } } @@ -582,7 +645,13 @@ mod tests { }, .. Default::default() }; - let r = do_preparation::(wasm, &schedule, ALICE, Determinism::Deterministic); + let r = prepare::( + wasm, + &schedule, + ALICE, + Determinism::Deterministic, + TryInstantiate::Instantiate, + ); assert_matches::assert_matches!(r.map_err(|(_, msg)| msg), $($expected)*); } }; @@ -718,7 +787,7 @@ mod tests { (func (export "deploy")) ) "#, - Err("Module is not valid") + Err("validation of new code failed") ); prepare_test!( @@ -784,7 +853,7 @@ mod tests { (func (export "deploy")) ) "#, - Err("Module is not valid") + Err("validation of new code failed") ); prepare_test!( @@ -910,7 +979,7 @@ mod tests { (func (export "deploy")) ) "#, - Err("module imports a non-existent function") + Err("module imports a banned function") ); // memory is in "env" and not in "seal0" @@ -965,7 +1034,7 @@ mod tests { (func (export "deploy")) ) "#, - Err("module imports a non-existent function") + Err("module imports a banned function") ); prepare_test!( @@ -978,7 +1047,7 @@ mod tests { (func (export "deploy")) ) "#, - Err("module imports a non-existent function") + Err("new code rejected after instrumentation") ); } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 3dac03cac625b..4c6006d2612fe 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -21,25 +21,34 @@ use crate::{ exec::{ExecError, ExecResult, Ext, FixSizedKey, TopicOf, VarSizedKey}, gas::{ChargedAmount, Token}, schedule::HostFnWeights, - wasm::env_def::ConvertibleToWasm, BalanceOf, CodeHash, Config, Error, SENTINEL, }; use bitflags::bitflags; use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; -use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight}; +use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight, RuntimeDebug}; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pallet_contracts_proc_macro::define_env; use sp_core::crypto::UncheckedFrom; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; use sp_runtime::traits::{Bounded, Zero}; -use sp_sandbox::SandboxMemory; -use sp_std::prelude::*; -use wasm_instrument::parity_wasm::elements::ValueType; +use sp_std::{fmt, prelude::*}; +use wasmi::{core::HostError, errors::LinkerError, Linker, Memory, Store}; /// The maximum nesting depth a contract can use when encoding types. const MAX_DECODE_NESTING: u32 = 256; +/// Trait implemented by the [`define_env`](pallet_contracts_proc_macro::define_env) macro for the +/// emitted `Env` struct. +pub trait Environment { + /// Adds all declared functions to the supplied [`Linker`](wasmi::Linker) and + /// [`Store`](wasmi::Store). + fn define( + store: &mut Store, + linker: &mut Linker, + ) -> Result<(), LinkerError>; +} + /// Type of a storage key. #[allow(dead_code)] enum KeyType { @@ -104,19 +113,6 @@ pub enum ReturnCode { EcdsaRecoverFailed = 11, } -impl ConvertibleToWasm for ReturnCode { - const VALUE_TYPE: ValueType = ValueType::I32; - type NativeType = Self; - - fn to_typed_value(self) -> sp_sandbox::Value { - sp_sandbox::Value::I32(self as i32) - } - fn from_typed_value(_: sp_sandbox::Value) -> Option { - debug_assert!(false, "We will never receive a ReturnCode but only send it to wasm."); - None - } -} - impl From for ReturnCode { fn from(from: ExecReturnValue) -> Self { if from.flags.contains(ReturnFlags::REVERT) { @@ -127,7 +123,14 @@ impl From for ReturnCode { } } +impl From for u32 { + fn from(code: ReturnCode) -> u32 { + code as u32 + } +} + /// The data passed through when a contract uses `seal_return`. +#[derive(RuntimeDebug)] pub struct ReturnData { /// The flags as passed through by the contract. They are still unchecked and /// will later be parsed into a `ReturnFlags` bitflags struct. @@ -142,6 +145,7 @@ pub struct ReturnData { /// occurred (the SupervisorError variant). /// The other case is where the trap does not constitute an error but rather was invoked /// as a quick way to terminate the application (all other variants). +#[derive(RuntimeDebug)] pub enum TrapReason { /// The supervisor trapped the contract because of an error condition occurred during /// execution in privileged code. @@ -159,6 +163,14 @@ impl> From for TrapReason { } } +impl fmt::Display for TrapReason { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + Ok(()) + } +} + +impl HostError for TrapReason {} + #[cfg_attr(test, derive(Debug, PartialEq, Eq))] #[derive(Copy, Clone)] pub enum RuntimeCosts { @@ -251,10 +263,10 @@ pub enum RuntimeCosts { SetCodeHash, /// Weight of calling `ecdsa_to_eth_address` EcdsaToEthAddress, - /// Weight of calling `seal_reentrant_count` + /// Weight of calling `reentrance_count` #[cfg(feature = "unstable-interface")] ReentrantCount, - /// Weight of calling `seal_account_reentrance_count` + /// Weight of calling `account_reentrance_count` #[cfg(feature = "unstable-interface")] AccountEntranceCount, } @@ -337,7 +349,7 @@ impl RuntimeCosts { SetCodeHash => s.set_code_hash, EcdsaToEthAddress => s.ecdsa_to_eth_address, #[cfg(feature = "unstable-interface")] - ReentrantCount => s.reentrant_count, + ReentrantCount => s.reentrance_count, #[cfg(feature = "unstable-interface")] AccountEntranceCount => s.account_reentrance_count, }; @@ -452,8 +464,7 @@ fn already_charged(_: u32) -> Option { pub struct Runtime<'a, E: Ext + 'a> { ext: &'a mut E, input_data: Option>, - memory: sp_sandbox::default_executor::Memory, - trap_reason: Option, + memory: Option, chain_extension: Option::ChainExtension>>, } @@ -463,58 +474,56 @@ where ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { - pub fn new( - ext: &'a mut E, - input_data: Vec, - memory: sp_sandbox::default_executor::Memory, - ) -> Self { + pub fn new(ext: &'a mut E, input_data: Vec) -> Self { Runtime { ext, input_data: Some(input_data), - memory, - trap_reason: None, + memory: None, chain_extension: Some(Box::new(Default::default())), } } - /// Converts the sandbox result and the runtime state into the execution outcome. - /// - /// It evaluates information stored in the `trap_reason` variable of the runtime and - /// bases the outcome on the value if this variable. Only if `trap_reason` is `None` - /// the result of the sandbox is evaluated. - pub fn to_execution_result( - self, - sandbox_result: Result, - ) -> ExecResult { - // If a trap reason is set we base our decision solely on that. - if let Some(trap_reason) = self.trap_reason { - return match trap_reason { - // The trap was the result of the execution `return` host function. - TrapReason::Return(ReturnData { flags, data }) => { - let flags = - ReturnFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?; - Ok(ExecReturnValue { flags, data }) - }, - TrapReason::Termination => - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }), - TrapReason::SupervisorError(error) => return Err(error.into()), - } - } + pub fn memory(&self) -> Option { + self.memory + } + + pub fn set_memory(&mut self, memory: Memory) { + self.memory = Some(memory); + } - // Check the exact type of the error. + /// Converts the sandbox result and the runtime state into the execution outcome. + pub fn to_execution_result(self, sandbox_result: Result<(), wasmi::Error>) -> ExecResult { + use TrapReason::*; match sandbox_result { - // No traps were generated. Proceed normally. + // Contract returned from main function -> no data was returned. Ok(_) => Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }), - // `Error::Module` is returned only if instantiation or linking failed (i.e. + // Contract either trapped or some host function aborted the execution. + Err(wasmi::Error::Trap(trap)) => { + // If we encoded a reason then it is some abort generated by a host function. + // Otherwise the trap came from the contract. + let reason: TrapReason = *trap + .into_host() + .ok_or(Error::::ContractTrapped)? + .downcast() + .expect("`TrapReason` is the only type we use to encode host errors; qed"); + match reason { + Return(ReturnData { flags, data }) => { + let flags = + ReturnFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?; + Ok(ExecReturnValue { flags, data }) + }, + Termination => + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }), + SupervisorError(error) => return Err(error.into()), + } + }, + // Any other error is returned only if instantiation or linking failed (i.e. // wasm binary tried to import a function that is not provided by the host). // This shouldn't happen because validation process ought to reject such binaries. // // Because panics are really undesirable in the runtime code, we treat this as // a trap for now. Eventually, we might want to revisit this. - Err(sp_sandbox::Error::Module) => return Err("validation error".into()), - // Any other kind of a trap should result in a failure. - Err(sp_sandbox::Error::Execution) | Err(sp_sandbox::Error::OutOfBounds) => - return Err(Error::::ContractTrapped.into()), + Err(_) => Err(Error::::CodeRejected.into()), } } @@ -526,15 +535,6 @@ where self.ext } - /// Store the reason for a host function triggered trap. - /// - /// This is called by the `define_env` macro in order to store any error returned by - /// the host functions defined through the said macro. It should **not** be called - /// manually. - pub fn set_trap_reason(&mut self, reason: TrapReason) { - self.trap_reason = Some(reason); - } - /// Charge the gas meter with the specified token. /// /// Returns `Err(HostError)` if there is not enough gas. @@ -556,12 +556,15 @@ where /// Returns `Err` if one of the following conditions occurs: /// /// - requested buffer is not within the bounds of the sandbox memory. - pub fn read_sandbox_memory(&self, ptr: u32, len: u32) -> Result, DispatchError> { + pub fn read_sandbox_memory( + &self, + memory: &[u8], + ptr: u32, + len: u32, + ) -> Result, DispatchError> { ensure!(len <= self.ext.schedule().limits.max_memory_size(), Error::::OutOfBounds); let mut buf = vec![0u8; len as usize]; - self.memory - .get(ptr, buf.as_mut_slice()) - .map_err(|_| Error::::OutOfBounds)?; + self.read_sandbox_memory_into_buf(memory, ptr, buf.as_mut_slice())?; Ok(buf) } @@ -572,10 +575,15 @@ where /// - requested buffer is not within the bounds of the sandbox memory. pub fn read_sandbox_memory_into_buf( &self, + memory: &[u8], ptr: u32, buf: &mut [u8], ) -> Result<(), DispatchError> { - self.memory.get(ptr, buf).map_err(|_| Error::::OutOfBounds.into()) + let ptr = ptr as usize; + let bound_checked = + memory.get(ptr..ptr + buf.len()).ok_or_else(|| Error::::OutOfBounds)?; + buf.copy_from_slice(bound_checked); + Ok(()) } /// Reads and decodes a type with a size fixed at compile time from contract memory. @@ -586,10 +594,14 @@ where /// contract callable function. pub fn read_sandbox_memory_as( &self, + memory: &[u8], ptr: u32, ) -> Result { - let buf = self.read_sandbox_memory(ptr, D::max_encoded_len() as u32)?; - let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut &buf[..]) + let ptr = ptr as usize; + let mut bound_checked = memory + .get(ptr..ptr + D::max_encoded_len() as usize) + .ok_or_else(|| Error::::OutOfBounds)?; + let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut bound_checked) .map_err(|_| DispatchError::from(Error::::DecodingFailed))?; Ok(decoded) } @@ -607,11 +619,14 @@ where /// regard to the overall weight. pub fn read_sandbox_memory_as_unbounded( &self, + memory: &[u8], ptr: u32, len: u32, ) -> Result { - let buf = self.read_sandbox_memory(ptr, len)?; - let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut &buf[..]) + let ptr = ptr as usize; + let mut bound_checked = + memory.get(ptr..ptr + len as usize).ok_or_else(|| Error::::OutOfBounds)?; + let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut bound_checked) .map_err(|_| DispatchError::from(Error::::DecodingFailed))?; Ok(decoded) } @@ -637,6 +652,7 @@ where /// `Err` if the size of the buffer located at `out_ptr` is too small to fit `buf`. pub fn write_sandbox_output( &mut self, + memory: &mut [u8], out_ptr: u32, out_len_ptr: u32, buf: &[u8], @@ -648,7 +664,7 @@ where } let buf_len = buf.len() as u32; - let len: u32 = self.read_sandbox_memory_as(out_len_ptr)?; + let len: u32 = self.read_sandbox_memory_as(memory, out_len_ptr)?; if len < buf_len { return Err(Error::::OutputBufferTooSmall.into()) @@ -658,12 +674,8 @@ where self.charge_gas(costs)?; } - self.memory - .set(out_ptr, buf) - .and_then(|_| self.memory.set(out_len_ptr, &buf_len.encode())) - .map_err(|_| Error::::OutOfBounds)?; - - Ok(()) + self.write_sandbox_memory(memory, out_ptr, buf)?; + self.write_sandbox_memory(memory, out_len_ptr, &buf_len.encode()) } /// Write the given buffer to the designated location in the sandbox memory. @@ -671,8 +683,17 @@ where /// Returns `Err` if one of the following conditions occurs: /// /// - designated area is not within the bounds of the sandbox memory. - fn write_sandbox_memory(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError> { - self.memory.set(ptr, buf).map_err(|_| Error::::OutOfBounds.into()) + fn write_sandbox_memory( + &self, + memory: &mut [u8], + ptr: u32, + buf: &[u8], + ) -> Result<(), DispatchError> { + let ptr = ptr as usize; + let bound_checked = + memory.get_mut(ptr..ptr + buf.len()).ok_or_else(|| Error::::OutOfBounds)?; + bound_checked.copy_from_slice(buf); + Ok(()) } /// Computes the given hash function on the supplied input. @@ -688,7 +709,8 @@ where /// /// The `input` and `output` buffers may overlap. fn compute_hash_on_intermediate_buffer( - &mut self, + &self, + memory: &mut [u8], hash_fn: F, input_ptr: u32, input_len: u32, @@ -699,11 +721,11 @@ where R: AsRef<[u8]>, { // Copy input into supervisor memory. - let input = self.read_sandbox_memory(input_ptr, input_len)?; + let input = self.read_sandbox_memory(memory, input_ptr, input_len)?; // Compute the hash on the input buffer using the given hash function. let hash = hash_fn(&input); // Write the resulting hash back into the sandboxed output buffer. - self.write_sandbox_memory(output_ptr, hash.as_ref())?; + self.write_sandbox_memory(memory, output_ptr, hash.as_ref())?; Ok(()) } @@ -740,6 +762,7 @@ where fn set_storage( &mut self, + memory: &[u8], key_type: KeyType, key_ptr: u32, value_ptr: u32, @@ -751,8 +774,8 @@ where if value_len > max_size { return Err(Error::::ValueTooLarge.into()) } - let key = self.read_sandbox_memory(key_ptr, key_type.len::()?)?; - let value = Some(self.read_sandbox_memory(value_ptr, value_len)?); + let key = self.read_sandbox_memory(memory, key_ptr, key_type.len::()?)?; + let value = Some(self.read_sandbox_memory(memory, value_ptr, value_len)?); let write_outcome = match key_type { KeyType::Fix => self.ext.set_storage( &FixSizedKey::try_from(key).map_err(|_| Error::::DecodingFailed)?, @@ -773,9 +796,14 @@ where Ok(write_outcome.old_len_with_sentinel()) } - fn clear_storage(&mut self, key_type: KeyType, key_ptr: u32) -> Result { + fn clear_storage( + &mut self, + memory: &[u8], + key_type: KeyType, + key_ptr: u32, + ) -> Result { let charged = self.charge_gas(RuntimeCosts::ClearStorage(self.ext.max_value_size()))?; - let key = self.read_sandbox_memory(key_ptr, key_type.len::()?)?; + let key = self.read_sandbox_memory(memory, key_ptr, key_type.len::()?)?; let outcome = match key_type { KeyType::Fix => self.ext.set_storage( &FixSizedKey::try_from(key).map_err(|_| Error::::DecodingFailed)?, @@ -795,13 +823,14 @@ where fn get_storage( &mut self, + memory: &mut [u8], key_type: KeyType, key_ptr: u32, out_ptr: u32, out_len_ptr: u32, ) -> Result { let charged = self.charge_gas(RuntimeCosts::GetStorage(self.ext.max_value_size()))?; - let key = self.read_sandbox_memory(key_ptr, key_type.len::()?)?; + let key = self.read_sandbox_memory(memory, key_ptr, key_type.len::()?)?; let outcome = match key_type { KeyType::Fix => self.ext.get_storage( &FixSizedKey::try_from(key).map_err(|_| Error::::DecodingFailed)?, @@ -813,7 +842,14 @@ where if let Some(value) = outcome { self.adjust_gas(charged, RuntimeCosts::GetStorage(value.len() as u32)); - self.write_sandbox_output(out_ptr, out_len_ptr, &value, false, already_charged)?; + self.write_sandbox_output( + memory, + out_ptr, + out_len_ptr, + &value, + false, + already_charged, + )?; Ok(ReturnCode::Success) } else { self.adjust_gas(charged, RuntimeCosts::GetStorage(0)); @@ -821,9 +857,14 @@ where } } - fn contains_storage(&mut self, key_type: KeyType, key_ptr: u32) -> Result { + fn contains_storage( + &mut self, + memory: &[u8], + key_type: KeyType, + key_ptr: u32, + ) -> Result { let charged = self.charge_gas(RuntimeCosts::ContainsStorage(self.ext.max_value_size()))?; - let key = self.read_sandbox_memory(key_ptr, key_type.len::()?)?; + let key = self.read_sandbox_memory(memory, key_ptr, key_type.len::()?)?; let outcome = match key_type { KeyType::Fix => self.ext.get_storage_size( &FixSizedKey::try_from(key).map_err(|_| Error::::DecodingFailed)?, @@ -839,6 +880,7 @@ where fn call( &mut self, + memory: &mut [u8], flags: CallFlags, call_type: CallType, input_data_ptr: u32, @@ -855,14 +897,15 @@ where self.input_data.take().ok_or(Error::::InputForwarded)? } else { self.charge_gas(RuntimeCosts::CopyFromContract(input_data_len))?; - self.read_sandbox_memory(input_data_ptr, input_data_len)? + self.read_sandbox_memory(memory, input_data_ptr, input_data_len)? }; let call_outcome = match call_type { CallType::Call { callee_ptr, value_ptr, gas } => { let callee: <::T as frame_system::Config>::AccountId = - self.read_sandbox_memory_as(callee_ptr)?; - let value: BalanceOf<::T> = self.read_sandbox_memory_as(value_ptr)?; + self.read_sandbox_memory_as(memory, callee_ptr)?; + let value: BalanceOf<::T> = + self.read_sandbox_memory_as(memory, value_ptr)?; if value > 0u32.into() { self.charge_gas(RuntimeCosts::CallSurchargeTransfer)?; } @@ -878,7 +921,7 @@ where if flags.contains(CallFlags::ALLOW_REENTRY) { return Err(Error::::InvalidCallFlags.into()) } - let code_hash = self.read_sandbox_memory_as(code_hash_ptr)?; + let code_hash = self.read_sandbox_memory_as(memory, code_hash_ptr)?; self.ext.delegate_call(code_hash, input_data) }, }; @@ -895,15 +938,21 @@ where } if let Ok(output) = &call_outcome { - self.write_sandbox_output(output_ptr, output_len_ptr, &output.data, true, |len| { - Some(RuntimeCosts::CopyToContract(len)) - })?; + self.write_sandbox_output( + memory, + output_ptr, + output_len_ptr, + &output.data, + true, + |len| Some(RuntimeCosts::CopyToContract(len)), + )?; } Ok(Runtime::::exec_into_return_code(call_outcome)?) } fn instantiate( &mut self, + memory: &mut [u8], code_hash_ptr: u32, gas: u64, value_ptr: u32, @@ -918,17 +967,19 @@ where ) -> Result { let gas = Weight::from_ref_time(gas); self.charge_gas(RuntimeCosts::InstantiateBase { input_data_len, salt_len })?; - let value: BalanceOf<::T> = self.read_sandbox_memory_as(value_ptr)?; + let value: BalanceOf<::T> = self.read_sandbox_memory_as(memory, value_ptr)?; if value > 0u32.into() { self.charge_gas(RuntimeCosts::InstantiateSurchargeTransfer)?; } - let code_hash: CodeHash<::T> = self.read_sandbox_memory_as(code_hash_ptr)?; - let input_data = self.read_sandbox_memory(input_data_ptr, input_data_len)?; - let salt = self.read_sandbox_memory(salt_ptr, salt_len)?; + let code_hash: CodeHash<::T> = + self.read_sandbox_memory_as(memory, code_hash_ptr)?; + let input_data = self.read_sandbox_memory(memory, input_data_ptr, input_data_len)?; + let salt = self.read_sandbox_memory(memory, salt_ptr, salt_len)?; let instantiate_outcome = self.ext.instantiate(gas, code_hash, value, input_data, &salt); if let Ok((address, output)) = &instantiate_outcome { if !output.flags.contains(ReturnFlags::REVERT) { self.write_sandbox_output( + memory, address_ptr, address_len_ptr, &address.encode(), @@ -936,17 +987,22 @@ where already_charged, )?; } - self.write_sandbox_output(output_ptr, output_len_ptr, &output.data, true, |len| { - Some(RuntimeCosts::CopyToContract(len)) - })?; + self.write_sandbox_output( + memory, + output_ptr, + output_len_ptr, + &output.data, + true, + |len| Some(RuntimeCosts::CopyToContract(len)), + )?; } Ok(Runtime::::exec_into_return_code(instantiate_outcome.map(|(_, retval)| retval))?) } - fn terminate(&mut self, beneficiary_ptr: u32) -> Result<(), TrapReason> { + fn terminate(&mut self, memory: &[u8], beneficiary_ptr: u32) -> Result<(), TrapReason> { self.charge_gas(RuntimeCosts::Terminate)?; let beneficiary: <::T as frame_system::Config>::AccountId = - self.read_sandbox_memory_as(beneficiary_ptr)?; + self.read_sandbox_memory_as(memory, beneficiary_ptr)?; self.ext.terminate(&beneficiary)?; Err(TrapReason::Termination) } @@ -967,7 +1023,7 @@ pub mod env { /// This call is supposed to be called only by instrumentation injected code. /// /// - amount: How much gas is used. - fn gas(ctx: Runtime, amount: u64) -> Result<(), TrapReason> { + fn gas(ctx: _, _memory: _, amount: u64) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::MeteringBlock(amount))?; Ok(()) } @@ -978,12 +1034,13 @@ pub mod env { /// type. Still a valid thing to call when not interested in the return value. #[prefixed_alias] fn set_storage( - ctx: Runtime, + ctx: _, + memory: _, key_ptr: u32, value_ptr: u32, value_len: u32, ) -> Result<(), TrapReason> { - ctx.set_storage(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) + ctx.set_storage(memory, KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) } /// Set the value at the given key in the contract storage. @@ -1007,12 +1064,13 @@ pub mod env { #[version(1)] #[prefixed_alias] fn set_storage( - ctx: Runtime, + ctx: _, + memory: _, key_ptr: u32, value_ptr: u32, value_len: u32, ) -> Result { - ctx.set_storage(KeyType::Fix, key_ptr, value_ptr, value_len) + ctx.set_storage(memory, KeyType::Fix, key_ptr, value_ptr, value_len) } /// Set the value at the given key in the contract storage. @@ -1034,13 +1092,14 @@ pub mod env { #[version(2)] #[prefixed_alias] fn set_storage( - ctx: Runtime, + ctx: _, + memory: _, key_ptr: u32, key_len: u32, value_ptr: u32, value_len: u32, ) -> Result { - ctx.set_storage(KeyType::Variable(key_len), key_ptr, value_ptr, value_len) + ctx.set_storage(memory, KeyType::Variable(key_len), key_ptr, value_ptr, value_len) } /// Clear the value at the given key in the contract storage. @@ -1048,8 +1107,8 @@ pub mod env { /// Equivalent to the newer version of `seal_clear_storage` with the exception of the return /// type. Still a valid thing to call when not interested in the return value. #[prefixed_alias] - fn clear_storage(ctx: Runtime, key_ptr: u32) -> Result<(), TrapReason> { - ctx.clear_storage(KeyType::Fix, key_ptr).map(|_| ()) + fn clear_storage(ctx: _, memory: _, key_ptr: u32) -> Result<(), TrapReason> { + ctx.clear_storage(memory, KeyType::Fix, key_ptr).map(|_| ()) } /// Clear the value at the given key in the contract storage. @@ -1065,8 +1124,8 @@ pub mod env { /// `SENTINEL` is returned as a sentinel value. #[version(1)] #[prefixed_alias] - fn clear_storage(ctx: Runtime, key_ptr: u32, key_len: u32) -> Result { - ctx.clear_storage(KeyType::Variable(key_len), key_ptr) + fn clear_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result { + ctx.clear_storage(memory, KeyType::Variable(key_len), key_ptr) } /// Retrieve the value under the given key from storage. @@ -1086,12 +1145,13 @@ pub mod env { /// `ReturnCode::KeyNotFound` #[prefixed_alias] fn get_storage( - ctx: Runtime, + ctx: _, + memory: _, key_ptr: u32, out_ptr: u32, out_len_ptr: u32, ) -> Result { - ctx.get_storage(KeyType::Fix, key_ptr, out_ptr, out_len_ptr) + ctx.get_storage(memory, KeyType::Fix, key_ptr, out_ptr, out_len_ptr) } /// Retrieve the value under the given key from storage. @@ -1115,13 +1175,14 @@ pub mod env { #[version(1)] #[prefixed_alias] fn get_storage( - ctx: Runtime, + ctx: _, + memory: _, key_ptr: u32, key_len: u32, out_ptr: u32, out_len_ptr: u32, ) -> Result { - ctx.get_storage(KeyType::Variable(key_len), key_ptr, out_ptr, out_len_ptr) + ctx.get_storage(memory, KeyType::Variable(key_len), key_ptr, out_ptr, out_len_ptr) } /// Checks whether there is a value stored under the given key. @@ -1138,8 +1199,8 @@ pub mod env { /// Returns the size of the pre-existing value at the specified key if any. Otherwise /// `SENTINEL` is returned as a sentinel value. #[prefixed_alias] - fn contains_storage(ctx: Runtime, key_ptr: u32) -> Result { - ctx.contains_storage(KeyType::Fix, key_ptr) + fn contains_storage(ctx: _, memory: _, key_ptr: u32) -> Result { + ctx.contains_storage(memory, KeyType::Fix, key_ptr) } /// Checks whether there is a value stored under the given key. @@ -1157,8 +1218,8 @@ pub mod env { /// `SENTINEL` is returned as a sentinel value. #[version(1)] #[prefixed_alias] - fn contains_storage(ctx: Runtime, key_ptr: u32, key_len: u32) -> Result { - ctx.contains_storage(KeyType::Variable(key_len), key_ptr) + fn contains_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result { + ctx.contains_storage(memory, KeyType::Variable(key_len), key_ptr) } /// Retrieve and remove the value under the given key from storage. @@ -1177,21 +1238,22 @@ pub mod env { #[unstable] #[prefixed_alias] fn take_storage( - ctx: Runtime, + ctx: _, + memory: _, key_ptr: u32, key_len: u32, out_ptr: u32, out_len_ptr: u32, ) -> Result { let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?; - let key = ctx.read_sandbox_memory(key_ptr, key_len)?; + let key = ctx.read_sandbox_memory(memory, key_ptr, key_len)?; if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage_transparent( &VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, None, true, )? { ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(value.len() as u32)); - ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, already_charged)?; + ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &value, false, already_charged)?; Ok(ReturnCode::Success) } else { ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(0)); @@ -1215,7 +1277,8 @@ pub mod env { /// `ReturnCode::TransferFailed` #[prefixed_alias] fn transfer( - ctx: Runtime, + ctx: _, + memory: _, account_ptr: u32, _account_len: u32, value_ptr: u32, @@ -1223,8 +1286,8 @@ pub mod env { ) -> Result { ctx.charge_gas(RuntimeCosts::Transfer)?; let callee: <::T as frame_system::Config>::AccountId = - ctx.read_sandbox_memory_as(account_ptr)?; - let value: BalanceOf<::T> = ctx.read_sandbox_memory_as(value_ptr)?; + ctx.read_sandbox_memory_as(memory, account_ptr)?; + let value: BalanceOf<::T> = ctx.read_sandbox_memory_as(memory, value_ptr)?; let result = ctx.ext.transfer(&callee, value); match result { Ok(()) => Ok(ReturnCode::Success), @@ -1249,7 +1312,8 @@ pub mod env { /// compatibility. Consider switching to the newest version of this function. #[prefixed_alias] fn call( - ctx: Runtime, + ctx: _, + memory: _, callee_ptr: u32, _callee_len: u32, gas: u64, @@ -1261,6 +1325,7 @@ pub mod env { output_len_ptr: u32, ) -> Result { ctx.call( + memory, CallFlags::ALLOW_REENTRY, CallType::Call { callee_ptr, value_ptr, gas }, input_data_ptr, @@ -1302,7 +1367,8 @@ pub mod env { #[version(1)] #[prefixed_alias] fn call( - ctx: Runtime, + ctx: _, + memory: _, flags: u32, callee_ptr: u32, gas: u64, @@ -1313,6 +1379,7 @@ pub mod env { output_len_ptr: u32, ) -> Result { ctx.call( + memory, CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, CallType::Call { callee_ptr, value_ptr, gas }, input_data_ptr, @@ -1348,7 +1415,8 @@ pub mod env { /// `ReturnCode::CodeNotFound` #[prefixed_alias] fn delegate_call( - ctx: Runtime, + ctx: _, + memory: _, flags: u32, code_hash_ptr: u32, input_data_ptr: u32, @@ -1357,6 +1425,7 @@ pub mod env { output_len_ptr: u32, ) -> Result { ctx.call( + memory, CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, CallType::DelegateCall { code_hash_ptr }, input_data_ptr, @@ -1380,7 +1449,8 @@ pub mod env { /// compatibility. Consider switching to the newest version of this function. #[prefixed_alias] fn instantiate( - ctx: Runtime, + ctx: _, + memory: _, code_hash_ptr: u32, _code_hash_len: u32, gas: u64, @@ -1396,6 +1466,7 @@ pub mod env { salt_len: u32, ) -> Result { ctx.instantiate( + memory, code_hash_ptr, gas, value_ptr, @@ -1453,7 +1524,8 @@ pub mod env { #[version(1)] #[prefixed_alias] fn instantiate( - ctx: Runtime, + ctx: _, + memory: _, code_hash_ptr: u32, gas: u64, value_ptr: u32, @@ -1467,6 +1539,7 @@ pub mod env { salt_len: u32, ) -> Result { ctx.instantiate( + memory, code_hash_ptr, gas, value_ptr, @@ -1495,11 +1568,12 @@ pub mod env { /// compatibility. Consider switching to the newest version of this function. #[prefixed_alias] fn terminate( - ctx: Runtime, + ctx: _, + memory: _, beneficiary_ptr: u32, _beneficiary_len: u32, ) -> Result<(), TrapReason> { - ctx.terminate(beneficiary_ptr) + ctx.terminate(memory, beneficiary_ptr) } /// Remove the calling account and transfer remaining **free** balance. @@ -1519,8 +1593,8 @@ pub mod env { /// - The deletion queue is full. #[version(1)] #[prefixed_alias] - fn terminate(ctx: Runtime, beneficiary_ptr: u32) -> Result<(), TrapReason> { - ctx.terminate(beneficiary_ptr) + fn terminate(ctx: _, memory: _, beneficiary_ptr: u32) -> Result<(), TrapReason> { + ctx.terminate(memory, beneficiary_ptr) } /// Stores the input passed by the caller into the supplied buffer. @@ -1534,10 +1608,10 @@ pub mod env { /// /// This function traps if the input was previously forwarded by a `seal_call`. #[prefixed_alias] - fn input(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + fn input(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::InputBase)?; if let Some(input) = ctx.input_data.take() { - ctx.write_sandbox_output(out_ptr, out_len_ptr, &input, false, |len| { + ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &input, false, |len| { Some(RuntimeCosts::CopyToContract(len)) })?; ctx.input_data = Some(input); @@ -1565,7 +1639,8 @@ pub mod env { /// /// Using a reserved bit triggers a trap. fn seal_return( - ctx: Runtime, + ctx: _, + memory: _, flags: u32, data_ptr: u32, data_len: u32, @@ -1573,7 +1648,7 @@ pub mod env { ctx.charge_gas(RuntimeCosts::Return(data_len))?; Err(TrapReason::Return(ReturnData { flags, - data: ctx.read_sandbox_memory(data_ptr, data_len)?, + data: ctx.read_sandbox_memory(memory, data_ptr, data_len)?, })) } @@ -1588,9 +1663,10 @@ pub mod env { /// extrinsic will be returned. Otherwise, if this call is initiated by another contract then /// the address of the contract will be returned. The value is encoded as T::AccountId. #[prefixed_alias] - fn caller(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + fn caller(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Caller)?; Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &ctx.ext.caller().encode(), @@ -1608,10 +1684,10 @@ pub mod env { /// /// Returned value is a u32-encoded boolean: (0 = false, 1 = true). #[prefixed_alias] - fn is_contract(ctx: Runtime, account_ptr: u32) -> Result { + fn is_contract(ctx: _, memory: _, account_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::IsContract)?; let address: <::T as frame_system::Config>::AccountId = - ctx.read_sandbox_memory_as(account_ptr)?; + ctx.read_sandbox_memory_as(memory, account_ptr)?; Ok(ctx.ext.is_contract(&address) as u32) } @@ -1631,16 +1707,18 @@ pub mod env { /// `ReturnCode::KeyNotFound` #[prefixed_alias] fn code_hash( - ctx: Runtime, + ctx: _, + memory: _, account_ptr: u32, out_ptr: u32, out_len_ptr: u32, ) -> Result { ctx.charge_gas(RuntimeCosts::CodeHash)?; let address: <::T as frame_system::Config>::AccountId = - ctx.read_sandbox_memory_as(account_ptr)?; + ctx.read_sandbox_memory_as(memory, account_ptr)?; if let Some(value) = ctx.ext.code_hash(&address) { ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &value.encode(), @@ -1661,10 +1739,11 @@ pub mod env { /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and /// the value length is written to. #[prefixed_alias] - fn own_code_hash(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + fn own_code_hash(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::OwnCodeHash)?; let code_hash_encoded = &ctx.ext.own_code_hash().encode(); Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, code_hash_encoded, @@ -1684,7 +1763,7 @@ pub mod env { /// /// Returned value is a u32-encoded boolean: (0 = false, 1 = true). #[prefixed_alias] - fn caller_is_origin(ctx: Runtime) -> Result { + fn caller_is_origin(ctx: _, _memory: _) -> Result { ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?; Ok(ctx.ext.caller_is_origin() as u32) } @@ -1696,9 +1775,10 @@ pub mod env { /// `out_ptr`. This call overwrites it with the size of the value. If the available /// space at `out_ptr` is less than the size of the value a trap is triggered. #[prefixed_alias] - fn address(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + fn address(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Address)?; Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &ctx.ext.address().encode(), @@ -1722,7 +1802,8 @@ pub mod env { /// gas can be smaller than one. #[prefixed_alias] fn weight_to_fee( - ctx: Runtime, + ctx: _, + memory: _, gas: u64, out_ptr: u32, out_len_ptr: u32, @@ -1730,6 +1811,7 @@ pub mod env { let gas = Weight::from_ref_time(gas); ctx.charge_gas(RuntimeCosts::WeightToFee)?; Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &ctx.ext.get_weight_price(gas).encode(), @@ -1747,10 +1829,17 @@ pub mod env { /// /// The data is encoded as Gas. #[prefixed_alias] - fn gas_left(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + fn gas_left(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::GasLeft)?; let gas_left = &ctx.ext.gas_meter().gas_left().ref_time().encode(); - Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, gas_left, false, already_charged)?) + Ok(ctx.write_sandbox_output( + memory, + out_ptr, + out_len_ptr, + gas_left, + false, + already_charged, + )?) } /// Stores the **free* balance of the current account into the supplied buffer. @@ -1762,9 +1851,10 @@ pub mod env { /// /// The data is encoded as T::Balance. #[prefixed_alias] - fn balance(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + fn balance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Balance)?; Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &ctx.ext.balance().encode(), @@ -1783,12 +1873,14 @@ pub mod env { /// The data is encoded as T::Balance. #[prefixed_alias] fn value_transferred( - ctx: Runtime, + ctx: _, + memory: _, out_ptr: u32, out_len_ptr: u32, ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::ValueTransferred)?; Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &ctx.ext.value_transferred().encode(), @@ -1811,7 +1903,8 @@ pub mod env { /// This function is deprecated. Users should migrate to the version in the "seal1" module. #[prefixed_alias] fn random( - ctx: Runtime, + ctx: _, + memory: _, subject_ptr: u32, subject_len: u32, out_ptr: u32, @@ -1821,8 +1914,9 @@ pub mod env { if subject_len > ctx.ext.schedule().limits.subject_len { return Err(Error::::RandomSubjectTooLong.into()) } - let subject_buf = ctx.read_sandbox_memory(subject_ptr, subject_len)?; + let subject_buf = ctx.read_sandbox_memory(memory, subject_ptr, subject_len)?; Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &ctx.ext.random(&subject_buf).0.encode(), @@ -1855,7 +1949,8 @@ pub mod env { #[version(1)] #[prefixed_alias] fn random( - ctx: Runtime, + ctx: _, + memory: _, subject_ptr: u32, subject_len: u32, out_ptr: u32, @@ -1865,8 +1960,9 @@ pub mod env { if subject_len > ctx.ext.schedule().limits.subject_len { return Err(Error::::RandomSubjectTooLong.into()) } - let subject_buf = ctx.read_sandbox_memory(subject_ptr, subject_len)?; + let subject_buf = ctx.read_sandbox_memory(memory, subject_ptr, subject_len)?; Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &ctx.ext.random(&subject_buf).encode(), @@ -1882,9 +1978,10 @@ pub mod env { /// `out_ptr`. This call overwrites it with the size of the value. If the available /// space at `out_ptr` is less than the size of the value a trap is triggered. #[prefixed_alias] - fn now(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + fn now(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Now)?; Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &ctx.ext.now().encode(), @@ -1897,9 +1994,15 @@ pub mod env { /// /// The data is encoded as T::Balance. #[prefixed_alias] - fn minimum_balance(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + fn minimum_balance( + ctx: _, + memory: _, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::MinimumBalance)?; Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &ctx.ext.minimum_balance().encode(), @@ -1920,13 +2023,21 @@ pub mod env { /// There is no longer a tombstone deposit. This function always returns 0. #[prefixed_alias] fn tombstone_deposit( - ctx: Runtime, + ctx: _, + memory: _, out_ptr: u32, out_len_ptr: u32, ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Balance)?; let deposit = >::zero().encode(); - Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, &deposit, false, already_charged)?) + Ok(ctx.write_sandbox_output( + memory, + out_ptr, + out_len_ptr, + &deposit, + false, + already_charged, + )?) } /// Was used to restore the given destination contract sacrificing the caller. @@ -1937,7 +2048,8 @@ pub mod env { /// backwards compatiblity #[prefixed_alias] fn restore_to( - ctx: Runtime, + ctx: _, + memory: _, _dest_ptr: u32, _dest_len: u32, _code_hash_ptr: u32, @@ -1960,7 +2072,8 @@ pub mod env { #[version(1)] #[prefixed_alias] fn restore_to( - ctx: Runtime, + ctx: _, + memory: _, _dest_ptr: u32, _code_hash_ptr: u32, _rent_allowance_ptr: u32, @@ -1981,7 +2094,8 @@ pub mod env { /// - data_len - the length of the data buffer. #[prefixed_alias] fn deposit_event( - ctx: Runtime, + ctx: _, + memory: _, topics_ptr: u32, topics_len: u32, data_ptr: u32, @@ -2006,7 +2120,7 @@ pub mod env { let mut topics: Vec::T>> = match topics_len { 0 => Vec::new(), - _ => ctx.read_sandbox_memory_as_unbounded(topics_ptr, topics_len)?, + _ => ctx.read_sandbox_memory_as_unbounded(memory, topics_ptr, topics_len)?, }; // If there are more than `event_topics`, then trap. @@ -2021,7 +2135,7 @@ pub mod env { return Err(Error::::DuplicateTopics.into()) } - let event_data = ctx.read_sandbox_memory(data_ptr, data_len)?; + let event_data = ctx.read_sandbox_memory(memory, data_ptr, data_len)?; ctx.ext.deposit_event(topics, event_data); @@ -2036,7 +2150,8 @@ pub mod env { /// backwards compatiblity. #[prefixed_alias] fn set_rent_allowance( - ctx: Runtime, + ctx: _, + memory: _, _value_ptr: u32, _value_len: u32, ) -> Result<(), TrapReason> { @@ -2052,7 +2167,7 @@ pub mod env { /// backwards compatiblity. #[version(1)] #[prefixed_alias] - fn set_rent_allowance(ctx: Runtime, _value_ptr: u32) -> Result<(), TrapReason> { + fn set_rent_allowance(ctx: _, _memory: _, _value_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::DebugMessage)?; Ok(()) } @@ -2064,10 +2179,11 @@ pub mod env { /// The state rent functionality was removed. This is stub only exists for /// backwards compatiblity. #[prefixed_alias] - fn rent_allowance(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + fn rent_allowance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Balance)?; let rent_allowance = >::max_value().encode(); Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &rent_allowance, @@ -2083,9 +2199,10 @@ pub mod env { /// `out_ptr`. This call overwrites it with the size of the value. If the available /// space at `out_ptr` is less than the size of the value a trap is triggered. #[prefixed_alias] - fn block_number(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { + fn block_number(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::BlockNumber)?; Ok(ctx.write_sandbox_output( + memory, out_ptr, out_len_ptr, &ctx.ext.block_number().encode(), @@ -2113,13 +2230,16 @@ pub mod env { /// function will write the result directly into this buffer. #[prefixed_alias] fn hash_sha2_256( - ctx: Runtime, + ctx: _, + memory: _, input_ptr: u32, input_len: u32, output_ptr: u32, ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::HashSha256(input_len))?; - Ok(ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr)?) + Ok(ctx.compute_hash_on_intermediate_buffer( + memory, sha2_256, input_ptr, input_len, output_ptr, + )?) } /// Computes the KECCAK 256-bit hash on the given input buffer. @@ -2141,13 +2261,16 @@ pub mod env { /// function will write the result directly into this buffer. #[prefixed_alias] fn hash_keccak_256( - ctx: Runtime, + ctx: _, + memory: _, input_ptr: u32, input_len: u32, output_ptr: u32, ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::HashKeccak256(input_len))?; - Ok(ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr)?) + Ok(ctx.compute_hash_on_intermediate_buffer( + memory, keccak_256, input_ptr, input_len, output_ptr, + )?) } /// Computes the BLAKE2 256-bit hash on the given input buffer. @@ -2169,13 +2292,16 @@ pub mod env { /// function will write the result directly into this buffer. #[prefixed_alias] fn hash_blake2_256( - ctx: Runtime, + ctx: _, + memory: _, input_ptr: u32, input_len: u32, output_ptr: u32, ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::HashBlake256(input_len))?; - Ok(ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr)?) + Ok(ctx.compute_hash_on_intermediate_buffer( + memory, blake2_256, input_ptr, input_len, output_ptr, + )?) } /// Computes the BLAKE2 128-bit hash on the given input buffer. @@ -2197,13 +2323,16 @@ pub mod env { /// function will write the result directly into this buffer. #[prefixed_alias] fn hash_blake2_128( - ctx: Runtime, + ctx: _, + memory: _, input_ptr: u32, input_len: u32, output_ptr: u32, ) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::HashBlake128(input_len))?; - Ok(ctx.compute_hash_on_intermediate_buffer(blake2_128, input_ptr, input_len, output_ptr)?) + Ok(ctx.compute_hash_on_intermediate_buffer( + memory, blake2_128, input_ptr, input_len, output_ptr, + )?) } /// Call into the chain extension provided by the chain if any. @@ -2219,7 +2348,8 @@ pub mod env { /// module error. #[prefixed_alias] fn call_chain_extension( - ctx: Runtime, + ctx: _, + memory: _, id: u32, input_ptr: u32, input_len: u32, @@ -2234,7 +2364,8 @@ pub mod env { "Constructor initializes with `Some`. This is the only place where it is set to `None`.\ It is always reset to `Some` afterwards. qed" ); - let env = Environment::new(ctx, id, input_ptr, input_len, output_ptr, output_len_ptr); + let env = + Environment::new(ctx, memory, id, input_ptr, input_len, output_ptr, output_len_ptr); let ret = match chain_extension.call(env)? { RetVal::Converging(val) => Ok(val), RetVal::Diverging { flags, data } => @@ -2263,13 +2394,14 @@ pub mod env { /// return value of this function can be cached in order to prevent further calls at runtime. #[prefixed_alias] fn debug_message( - ctx: Runtime, + ctx: _, + memory: _, str_ptr: u32, str_len: u32, ) -> Result { ctx.charge_gas(RuntimeCosts::DebugMessage)?; if ctx.ext.append_debug_buffer("") { - let data = ctx.read_sandbox_memory(str_ptr, str_len)?; + let data = ctx.read_sandbox_memory(memory, str_ptr, str_len)?; let msg = core::str::from_utf8(&data).map_err(|_| >::DebugMessageInvalidUTF8)?; ctx.ext.append_debug_buffer(msg); @@ -2318,14 +2450,15 @@ pub mod env { #[unstable] #[prefixed_alias] fn call_runtime( - ctx: Runtime, + ctx: _, + memory: _, call_ptr: u32, call_len: u32, ) -> Result { use frame_support::dispatch::{extract_actual_weight, GetDispatchInfo}; ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?; let call: ::RuntimeCall = - ctx.read_sandbox_memory_as_unbounded(call_ptr, call_len)?; + ctx.read_sandbox_memory_as_unbounded(memory, call_ptr, call_len)?; let dispatch_info = call.get_dispatch_info(); let charged = ctx.charge_gas(RuntimeCosts::CallRuntime(dispatch_info.weight))?; let result = ctx.ext.call_runtime(call); @@ -2356,7 +2489,8 @@ pub mod env { /// `ReturnCode::EcdsaRecoverFailed` #[prefixed_alias] fn ecdsa_recover( - ctx: Runtime, + ctx: _, + memory: _, signature_ptr: u32, message_hash_ptr: u32, output_ptr: u32, @@ -2364,9 +2498,9 @@ pub mod env { ctx.charge_gas(RuntimeCosts::EcdsaRecovery)?; let mut signature: [u8; 65] = [0; 65]; - ctx.read_sandbox_memory_into_buf(signature_ptr, &mut signature)?; + ctx.read_sandbox_memory_into_buf(memory, signature_ptr, &mut signature)?; let mut message_hash: [u8; 32] = [0; 32]; - ctx.read_sandbox_memory_into_buf(message_hash_ptr, &mut message_hash)?; + ctx.read_sandbox_memory_into_buf(memory, message_hash_ptr, &mut message_hash)?; let result = ctx.ext.ecdsa_recover(&signature, &message_hash); @@ -2374,7 +2508,7 @@ pub mod env { Ok(pub_key) => { // Write the recovered compressed ecdsa public key back into the sandboxed output // buffer. - ctx.write_sandbox_memory(output_ptr, pub_key.as_ref())?; + ctx.write_sandbox_memory(memory, output_ptr, pub_key.as_ref())?; Ok(ReturnCode::Success) }, @@ -2410,9 +2544,10 @@ pub mod env { /// /// `ReturnCode::CodeNotFound` #[prefixed_alias] - fn set_code_hash(ctx: Runtime, code_hash_ptr: u32) -> Result { + fn set_code_hash(ctx: _, memory: _, code_hash_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::SetCodeHash)?; - let code_hash: CodeHash<::T> = ctx.read_sandbox_memory_as(code_hash_ptr)?; + let code_hash: CodeHash<::T> = + ctx.read_sandbox_memory_as(memory, code_hash_ptr)?; match ctx.ext.set_code_hash(code_hash) { Err(err) => { let code = Runtime::::err_into_return_code(err)?; @@ -2440,17 +2575,18 @@ pub mod env { /// `ReturnCode::EcdsaRecoverFailed` #[prefixed_alias] fn ecdsa_to_eth_address( - ctx: Runtime, + ctx: _, + memory: _, key_ptr: u32, out_ptr: u32, ) -> Result { ctx.charge_gas(RuntimeCosts::EcdsaToEthAddress)?; let mut compressed_key: [u8; 33] = [0; 33]; - ctx.read_sandbox_memory_into_buf(key_ptr, &mut compressed_key)?; + ctx.read_sandbox_memory_into_buf(memory, key_ptr, &mut compressed_key)?; let result = ctx.ext.ecdsa_to_eth_address(&compressed_key); match result { Ok(eth_address) => { - ctx.write_sandbox_memory(out_ptr, eth_address.as_ref())?; + ctx.write_sandbox_memory(memory, out_ptr, eth_address.as_ref())?; Ok(ReturnCode::Success) }, Err(_) => Ok(ReturnCode::EcdsaRecoverFailed), @@ -2464,9 +2600,9 @@ pub mod env { /// /// Returns 0 when there is no reentrancy. #[unstable] - fn reentrant_count(ctx: Runtime) -> Result { + fn reentrance_count(ctx: _, memory: _) -> Result { ctx.charge_gas(RuntimeCosts::ReentrantCount)?; - Ok(ctx.ext.reentrant_count()) + Ok(ctx.ext.reentrance_count()) } /// Returns the number of times specified contract exists on the call stack. Delegated calls are @@ -2480,10 +2616,10 @@ pub mod env { /// /// Returns 0 when the contract does not exist on the call stack. #[unstable] - fn account_reentrance_count(ctx: Runtime, account_ptr: u32) -> Result { + fn account_reentrance_count(ctx: _, memory: _, account_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::AccountEntranceCount)?; let account_id: <::T as frame_system::Config>::AccountId = - ctx.read_sandbox_memory_as(account_ptr)?; + ctx.read_sandbox_memory_as(memory, account_ptr)?; Ok(ctx.ext.account_reentrance_count(&account_id)) } } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 4652413df1158..f5c12e92ca94e 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,24 +18,25 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_contracts // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/contracts/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_contracts +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/contracts/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -109,7 +110,7 @@ pub trait WeightInfo { fn seal_ecdsa_recover(r: u32, ) -> Weight; fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight; fn seal_set_code_hash(r: u32, ) -> Weight; - fn seal_reentrant_count(r: u32, ) -> Weight; + fn seal_reentrance_count(r: u32, ) -> Weight; fn seal_account_reentrance_count(r: u32, ) -> Weight; fn instr_i64const(r: u32, ) -> Weight; fn instr_i64load(r: u32, ) -> Weight; @@ -169,17 +170,17 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - // Minimum execution time: 3_064 nanoseconds. - Weight::from_ref_time(3_236_000 as u64) + // Minimum execution time: 3_174 nanoseconds. + Weight::from_ref_time(3_298_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - // Minimum execution time: 15_492 nanoseconds. - Weight::from_ref_time(14_309_233 as u64) - // Standard Error: 649 - .saturating_add(Weight::from_ref_time(930_078 as u64).saturating_mul(k as u64)) + // Minimum execution time: 15_218 nanoseconds. + Weight::from_ref_time(15_548_154 as u64) + // Standard Error: 732 + .saturating_add(Weight::from_ref_time(940_242 as u64).saturating_mul(k as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -187,10 +188,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - // Minimum execution time: 3_240 nanoseconds. - Weight::from_ref_time(15_076_559 as u64) - // Standard Error: 3_337 - .saturating_add(Weight::from_ref_time(1_244_348 as u64).saturating_mul(q as u64)) + // Minimum execution time: 3_096 nanoseconds. + Weight::from_ref_time(14_949_039 as u64) + // Standard Error: 3_466 + .saturating_add(Weight::from_ref_time(1_236_160 as u64).saturating_mul(q as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -198,10 +199,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - // Minimum execution time: 22_524 nanoseconds. - Weight::from_ref_time(19_939_078 as u64) - // Standard Error: 43 - .saturating_add(Weight::from_ref_time(43_802 as u64).saturating_mul(c as u64)) + // Minimum execution time: 28_333 nanoseconds. + Weight::from_ref_time(19_421_544 as u64) + // Standard Error: 92 + .saturating_add(Weight::from_ref_time(47_629 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -212,10 +213,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - // Minimum execution time: 261_039 nanoseconds. - Weight::from_ref_time(228_709_853 as u64) - // Standard Error: 105 - .saturating_add(Weight::from_ref_time(47_449 as u64).saturating_mul(c as u64)) + // Minimum execution time: 304_381 nanoseconds. + Weight::from_ref_time(315_177_233 as u64) + // Standard Error: 22 + .saturating_add(Weight::from_ref_time(30_372 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -230,12 +231,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - // Minimum execution time: 2_054_867 nanoseconds. - Weight::from_ref_time(259_090_306 as u64) - // Standard Error: 72 - .saturating_add(Weight::from_ref_time(107_519 as u64).saturating_mul(c as u64)) - // Standard Error: 4 - .saturating_add(Weight::from_ref_time(1_736 as u64).saturating_mul(s as u64)) + // Minimum execution time: 2_119_963 nanoseconds. + Weight::from_ref_time(337_976_516 as u64) + // Standard Error: 84 + .saturating_add(Weight::from_ref_time(88_566 as u64).saturating_mul(c as u64)) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(1_747 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(9 as u64)) } @@ -248,10 +249,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - // Minimum execution time: 213_409 nanoseconds. - Weight::from_ref_time(205_300_495 as u64) - // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_479 as u64).saturating_mul(s as u64)) + // Minimum execution time: 184_739 nanoseconds. + Weight::from_ref_time(179_778_057 as u64) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(1_487 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(7 as u64)) } @@ -261,8 +262,8 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - // Minimum execution time: 183_317 nanoseconds. - Weight::from_ref_time(184_465_000 as u64) + // Minimum execution time: 154_711 nanoseconds. + Weight::from_ref_time(155_527_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -272,10 +273,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - // Minimum execution time: 56_187 nanoseconds. - Weight::from_ref_time(60_636_621 as u64) - // Standard Error: 46 - .saturating_add(Weight::from_ref_time(45_734 as u64).saturating_mul(c as u64)) + // Minimum execution time: 294_982 nanoseconds. + Weight::from_ref_time(302_482_450 as u64) + // Standard Error: 62 + .saturating_add(Weight::from_ref_time(88_358 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -284,8 +285,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - // Minimum execution time: 38_433 nanoseconds. - Weight::from_ref_time(38_917_000 as u64) + // Minimum execution time: 39_655 nanoseconds. + Weight::from_ref_time(40_147_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -293,8 +294,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - // Minimum execution time: 41_507 nanoseconds. - Weight::from_ref_time(41_938_000 as u64) + // Minimum execution time: 41_028 nanoseconds. + Weight::from_ref_time(41_565_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -305,10 +306,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - // Minimum execution time: 249_628 nanoseconds. - Weight::from_ref_time(251_997_923 as u64) - // Standard Error: 26_157 - .saturating_add(Weight::from_ref_time(35_002_004 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_231 nanoseconds. + Weight::from_ref_time(298_245_008 as u64) + // Standard Error: 41_817 + .saturating_add(Weight::from_ref_time(16_183_097 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -319,10 +320,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - // Minimum execution time: 249_390 nanoseconds. - Weight::from_ref_time(193_793_052 as u64) - // Standard Error: 430_292 - .saturating_add(Weight::from_ref_time(211_029_686 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_152 nanoseconds. + Weight::from_ref_time(231_239_439 as u64) + // Standard Error: 475_771 + .saturating_add(Weight::from_ref_time(193_804_587 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -334,10 +335,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 252_469 nanoseconds. - Weight::from_ref_time(201_438_856 as u64) - // Standard Error: 420_040 - .saturating_add(Weight::from_ref_time(267_340_744 as u64).saturating_mul(r as u64)) + // Minimum execution time: 296_171 nanoseconds. + Weight::from_ref_time(244_339_298 as u64) + // Standard Error: 440_060 + .saturating_add(Weight::from_ref_time(236_224_857 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -349,10 +350,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 251_154 nanoseconds. - Weight::from_ref_time(254_831_062 as u64) - // Standard Error: 37_843 - .saturating_add(Weight::from_ref_time(38_579_567 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_891 nanoseconds. + Weight::from_ref_time(298_061_159 as u64) + // Standard Error: 30_013 + .saturating_add(Weight::from_ref_time(19_682_309 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -363,10 +364,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - // Minimum execution time: 247_875 nanoseconds. - Weight::from_ref_time(250_312_587 as u64) - // Standard Error: 17_901 - .saturating_add(Weight::from_ref_time(15_153_431 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_259 nanoseconds. + Weight::from_ref_time(296_675_355 as u64) + // Standard Error: 24_508 + .saturating_add(Weight::from_ref_time(10_949_451 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -377,10 +378,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - // Minimum execution time: 250_097 nanoseconds. - Weight::from_ref_time(252_157_442 as u64) - // Standard Error: 38_426 - .saturating_add(Weight::from_ref_time(35_084_205 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_507 nanoseconds. + Weight::from_ref_time(295_682_709 as u64) + // Standard Error: 43_685 + .saturating_add(Weight::from_ref_time(16_461_873 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -391,10 +392,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - // Minimum execution time: 250_034 nanoseconds. - Weight::from_ref_time(252_189_233 as u64) - // Standard Error: 33_081 - .saturating_add(Weight::from_ref_time(34_764_160 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_473 nanoseconds. + Weight::from_ref_time(296_523_274 as u64) + // Standard Error: 34_356 + .saturating_add(Weight::from_ref_time(15_932_835 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -405,10 +406,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - // Minimum execution time: 249_587 nanoseconds. - Weight::from_ref_time(258_565_111 as u64) - // Standard Error: 75_715 - .saturating_add(Weight::from_ref_time(109_687_486 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_889 nanoseconds. + Weight::from_ref_time(295_471_068 as u64) + // Standard Error: 88_937 + .saturating_add(Weight::from_ref_time(89_606_655 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -419,10 +420,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - // Minimum execution time: 249_735 nanoseconds. - Weight::from_ref_time(252_875_784 as u64) - // Standard Error: 42_024 - .saturating_add(Weight::from_ref_time(34_555_983 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_747 nanoseconds. + Weight::from_ref_time(297_023_967 as u64) + // Standard Error: 18_756 + .saturating_add(Weight::from_ref_time(15_748_008 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -433,10 +434,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - // Minimum execution time: 250_025 nanoseconds. - Weight::from_ref_time(255_212_046 as u64) - // Standard Error: 41_865 - .saturating_add(Weight::from_ref_time(34_332_291 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_590 nanoseconds. + Weight::from_ref_time(296_257_202 as u64) + // Standard Error: 24_863 + .saturating_add(Weight::from_ref_time(15_851_537 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -447,10 +448,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - // Minimum execution time: 247_641 nanoseconds. - Weight::from_ref_time(252_978_686 as u64) - // Standard Error: 25_820 - .saturating_add(Weight::from_ref_time(34_175_386 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_746 nanoseconds. + Weight::from_ref_time(297_308_097 as u64) + // Standard Error: 29_585 + .saturating_add(Weight::from_ref_time(15_608_985 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -461,10 +462,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - // Minimum execution time: 249_871 nanoseconds. - Weight::from_ref_time(253_237_931 as u64) - // Standard Error: 30_986 - .saturating_add(Weight::from_ref_time(34_305_155 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_662 nanoseconds. + Weight::from_ref_time(296_393_072 as u64) + // Standard Error: 23_750 + .saturating_add(Weight::from_ref_time(15_891_911 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -476,10 +477,10 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - // Minimum execution time: 249_787 nanoseconds. - Weight::from_ref_time(258_457_094 as u64) - // Standard Error: 75_835 - .saturating_add(Weight::from_ref_time(107_115_666 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_036 nanoseconds. + Weight::from_ref_time(301_071_620 as u64) + // Standard Error: 85_146 + .saturating_add(Weight::from_ref_time(84_455_768 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -490,10 +491,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - // Minimum execution time: 171_667 nanoseconds. - Weight::from_ref_time(174_687_863 as u64) - // Standard Error: 34_576 - .saturating_add(Weight::from_ref_time(15_895_674 as u64).saturating_mul(r as u64)) + // Minimum execution time: 142_655 nanoseconds. + Weight::from_ref_time(145_691_226 as u64) + // Standard Error: 11_085 + .saturating_add(Weight::from_ref_time(7_953_680 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -504,10 +505,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - // Minimum execution time: 249_610 nanoseconds. - Weight::from_ref_time(251_476_758 as u64) - // Standard Error: 39_422 - .saturating_add(Weight::from_ref_time(32_870_429 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_613 nanoseconds. + Weight::from_ref_time(296_889_714 as u64) + // Standard Error: 21_550 + .saturating_add(Weight::from_ref_time(13_672_097 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -518,10 +519,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 285_154 nanoseconds. - Weight::from_ref_time(307_768_636 as u64) - // Standard Error: 2_701 - .saturating_add(Weight::from_ref_time(9_544_122 as u64).saturating_mul(n as u64)) + // Minimum execution time: 309_866 nanoseconds. + Weight::from_ref_time(328_331_386 as u64) + // Standard Error: 6_205 + .saturating_add(Weight::from_ref_time(9_619_067 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -532,10 +533,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - // Minimum execution time: 244_810 nanoseconds. - Weight::from_ref_time(247_576_385 as u64) - // Standard Error: 80_494 - .saturating_add(Weight::from_ref_time(2_052_714 as u64).saturating_mul(r as u64)) + // Minimum execution time: 288_265 nanoseconds. + Weight::from_ref_time(292_739_779 as u64) + // Standard Error: 108_313 + .saturating_add(Weight::from_ref_time(1_475_820 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -546,10 +547,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 248_049 nanoseconds. - Weight::from_ref_time(250_148_025 as u64) - // Standard Error: 339 - .saturating_add(Weight::from_ref_time(185_344 as u64).saturating_mul(n as u64)) + // Minimum execution time: 293_044 nanoseconds. + Weight::from_ref_time(293_846_263 as u64) + // Standard Error: 641 + .saturating_add(Weight::from_ref_time(188_770 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -562,10 +563,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - // Minimum execution time: 246_620 nanoseconds. - Weight::from_ref_time(250_752_277 as u64) - // Standard Error: 84_300 - .saturating_add(Weight::from_ref_time(54_264_722 as u64).saturating_mul(r as u64)) + // Minimum execution time: 289_248 nanoseconds. + Weight::from_ref_time(294_406_912 as u64) + // Standard Error: 112_528 + .saturating_add(Weight::from_ref_time(52_650_987 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -579,10 +580,10 @@ impl WeightInfo for SubstrateWeight { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - // Minimum execution time: 249_065 nanoseconds. - Weight::from_ref_time(252_419_902 as u64) - // Standard Error: 84_223 - .saturating_add(Weight::from_ref_time(134_454_079 as u64).saturating_mul(r as u64)) + // Minimum execution time: 292_980 nanoseconds. + Weight::from_ref_time(298_232_040 as u64) + // Standard Error: 85_517 + .saturating_add(Weight::from_ref_time(108_891_823 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -593,10 +594,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - // Minimum execution time: 246_588 nanoseconds. - Weight::from_ref_time(261_525_328 as u64) - // Standard Error: 97_732 - .saturating_add(Weight::from_ref_time(235_555_878 as u64).saturating_mul(r as u64)) + // Minimum execution time: 291_668 nanoseconds. + Weight::from_ref_time(302_010_570 as u64) + // Standard Error: 109_901 + .saturating_add(Weight::from_ref_time(214_667_762 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -608,12 +609,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - // Minimum execution time: 1_171_144 nanoseconds. - Weight::from_ref_time(490_333_337 as u64) - // Standard Error: 404_664 - .saturating_add(Weight::from_ref_time(173_683_265 as u64).saturating_mul(t as u64)) - // Standard Error: 111_140 - .saturating_add(Weight::from_ref_time(66_081_822 as u64).saturating_mul(n as u64)) + // Minimum execution time: 1_163_533 nanoseconds. + Weight::from_ref_time(501_280_410 as u64) + // Standard Error: 601_576 + .saturating_add(Weight::from_ref_time(172_210_846 as u64).saturating_mul(t as u64)) + // Standard Error: 165_221 + .saturating_add(Weight::from_ref_time(67_584_003 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -626,20 +627,20 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - // Minimum execution time: 178_822 nanoseconds. - Weight::from_ref_time(181_571_518 as u64) - // Standard Error: 19_207 - .saturating_add(Weight::from_ref_time(26_784_712 as u64).saturating_mul(r as u64)) + // Minimum execution time: 154_390 nanoseconds. + Weight::from_ref_time(158_246_775 as u64) + // Standard Error: 23_812 + .saturating_add(Weight::from_ref_time(12_810_293 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - // Minimum execution time: 249_737 nanoseconds. - Weight::from_ref_time(208_095_467 as u64) - // Standard Error: 417_236 - .saturating_add(Weight::from_ref_time(430_088_574 as u64).saturating_mul(r as u64)) + // Minimum execution time: 292_926 nanoseconds. + Weight::from_ref_time(250_238_246 as u64) + // Standard Error: 485_292 + .saturating_add(Weight::from_ref_time(402_779_709 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -648,10 +649,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - // Minimum execution time: 400_055 nanoseconds. - Weight::from_ref_time(551_666_883 as u64) - // Standard Error: 1_379_652 - .saturating_add(Weight::from_ref_time(94_069_118 as u64).saturating_mul(n as u64)) + // Minimum execution time: 421_504 nanoseconds. + Weight::from_ref_time(574_267_945 as u64) + // Standard Error: 1_407_019 + .saturating_add(Weight::from_ref_time(89_516_682 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(52 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(50 as u64)) @@ -660,10 +661,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - // Minimum execution time: 400_370 nanoseconds. - Weight::from_ref_time(521_380_000 as u64) - // Standard Error: 1_112_618 - .saturating_add(Weight::from_ref_time(68_664_898 as u64).saturating_mul(n as u64)) + // Minimum execution time: 421_422 nanoseconds. + Weight::from_ref_time(545_948_271 as u64) + // Standard Error: 1_148_143 + .saturating_add(Weight::from_ref_time(63_958_096 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(49 as u64)) @@ -672,10 +673,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - // Minimum execution time: 249_711 nanoseconds. - Weight::from_ref_time(212_629_798 as u64) - // Standard Error: 378_159 - .saturating_add(Weight::from_ref_time(415_326_230 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_545 nanoseconds. + Weight::from_ref_time(255_622_312 as u64) + // Standard Error: 407_862 + .saturating_add(Weight::from_ref_time(396_764_962 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -684,10 +685,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 365_702 nanoseconds. - Weight::from_ref_time(499_337_686 as u64) - // Standard Error: 1_232_330 - .saturating_add(Weight::from_ref_time(70_648_878 as u64).saturating_mul(n as u64)) + // Minimum execution time: 390_339 nanoseconds. + Weight::from_ref_time(528_774_888 as u64) + // Standard Error: 1_278_188 + .saturating_add(Weight::from_ref_time(66_683_698 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(48 as u64)) @@ -696,10 +697,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - // Minimum execution time: 251_357 nanoseconds. - Weight::from_ref_time(220_533_580 as u64) - // Standard Error: 345_297 - .saturating_add(Weight::from_ref_time(349_413_968 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_904 nanoseconds. + Weight::from_ref_time(265_679_354 as u64) + // Standard Error: 386_673 + .saturating_add(Weight::from_ref_time(318_869_116 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -707,10 +708,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 354_162 nanoseconds. - Weight::from_ref_time(472_811_575 as u64) - // Standard Error: 1_109_282 - .saturating_add(Weight::from_ref_time(154_074_386 as u64).saturating_mul(n as u64)) + // Minimum execution time: 372_784 nanoseconds. + Weight::from_ref_time(487_784_160 as u64) + // Standard Error: 1_092_850 + .saturating_add(Weight::from_ref_time(152_413_290 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -718,10 +719,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - // Minimum execution time: 247_551 nanoseconds. - Weight::from_ref_time(219_176_526 as u64) - // Standard Error: 358_914 - .saturating_add(Weight::from_ref_time(326_009_513 as u64).saturating_mul(r as u64)) + // Minimum execution time: 301_191 nanoseconds. + Weight::from_ref_time(270_493_545 as u64) + // Standard Error: 373_565 + .saturating_add(Weight::from_ref_time(302_870_977 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -729,10 +730,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 339_149 nanoseconds. - Weight::from_ref_time(440_615_016 as u64) - // Standard Error: 954_837 - .saturating_add(Weight::from_ref_time(66_153_533 as u64).saturating_mul(n as u64)) + // Minimum execution time: 368_641 nanoseconds. + Weight::from_ref_time(469_340_170 as u64) + // Standard Error: 966_589 + .saturating_add(Weight::from_ref_time(62_000_083 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -740,10 +741,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - // Minimum execution time: 251_812 nanoseconds. - Weight::from_ref_time(209_954_069 as u64) - // Standard Error: 398_380 - .saturating_add(Weight::from_ref_time(438_573_954 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_717 nanoseconds. + Weight::from_ref_time(254_308_806 as u64) + // Standard Error: 443_802 + .saturating_add(Weight::from_ref_time(408_899_238 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -752,10 +753,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 374_594 nanoseconds. - Weight::from_ref_time(525_213_792 as u64) - // Standard Error: 1_378_489 - .saturating_add(Weight::from_ref_time(161_599_623 as u64).saturating_mul(n as u64)) + // Minimum execution time: 396_211 nanoseconds. + Weight::from_ref_time(545_169_999 as u64) + // Standard Error: 1_390_049 + .saturating_add(Weight::from_ref_time(156_931_202 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(51 as u64)) .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(48 as u64)) @@ -768,10 +769,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - // Minimum execution time: 251_379 nanoseconds. - Weight::from_ref_time(204_214_298 as u64) - // Standard Error: 662_575 - .saturating_add(Weight::from_ref_time(1_366_716_853 as u64).saturating_mul(r as u64)) + // Minimum execution time: 295_145 nanoseconds. + Weight::from_ref_time(241_332_033 as u64) + // Standard Error: 658_837 + .saturating_add(Weight::from_ref_time(1_315_958_335 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -784,10 +785,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - // Minimum execution time: 252_896 nanoseconds. - Weight::from_ref_time(253_811_000 as u64) - // Standard Error: 6_576_179 - .saturating_add(Weight::from_ref_time(17_254_952_849 as u64).saturating_mul(r as u64)) + // Minimum execution time: 295_624 nanoseconds. + Weight::from_ref_time(296_567_000 as u64) + // Standard Error: 6_725_484 + .saturating_add(Weight::from_ref_time(20_773_662_959 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -800,10 +801,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - // Minimum execution time: 249_312 nanoseconds. - Weight::from_ref_time(253_806_000 as u64) - // Standard Error: 6_118_873 - .saturating_add(Weight::from_ref_time(17_081_370_212 as u64).saturating_mul(r as u64)) + // Minimum execution time: 296_698 nanoseconds. + Weight::from_ref_time(297_541_000 as u64) + // Standard Error: 18_681_855 + .saturating_add(Weight::from_ref_time(20_702_951_248 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((150 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -817,12 +818,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - // Minimum execution time: 12_001_522 nanoseconds. - Weight::from_ref_time(10_903_312_955 as u64) - // Standard Error: 4_301_096 - .saturating_add(Weight::from_ref_time(1_243_413_241 as u64).saturating_mul(t as u64)) - // Standard Error: 6_449 - .saturating_add(Weight::from_ref_time(9_713_655 as u64).saturating_mul(c as u64)) + // Minimum execution time: 9_491_225 nanoseconds. + Weight::from_ref_time(8_726_446_640 as u64) + // Standard Error: 11_723_053 + .saturating_add(Weight::from_ref_time(1_107_970_775 as u64).saturating_mul(t as u64)) + // Standard Error: 17_578 + .saturating_add(Weight::from_ref_time(9_748_009 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(167 as u64)) .saturating_add(T::DbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(163 as u64)) @@ -837,10 +838,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - // Minimum execution time: 254_969 nanoseconds. - Weight::from_ref_time(255_984_000 as u64) - // Standard Error: 18_545_048 - .saturating_add(Weight::from_ref_time(22_343_189_765 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_351 nanoseconds. + Weight::from_ref_time(297_837_000 as u64) + // Standard Error: 17_115_732 + .saturating_add(Weight::from_ref_time(25_936_348_025 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().reads((400 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(5 as u64)) @@ -856,10 +857,10 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - // Minimum execution time: 14_077_497 nanoseconds. - Weight::from_ref_time(13_949_740_588 as u64) - // Standard Error: 66_631 - .saturating_add(Weight::from_ref_time(120_519_572 as u64).saturating_mul(s as u64)) + // Minimum execution time: 11_367_191 nanoseconds. + Weight::from_ref_time(11_186_726_411 as u64) + // Standard Error: 75_273 + .saturating_add(Weight::from_ref_time(122_421_705 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(249 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(T::DbWeight::get().writes(247 as u64)) @@ -872,10 +873,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - // Minimum execution time: 247_445 nanoseconds. - Weight::from_ref_time(251_229_791 as u64) - // Standard Error: 88_045 - .saturating_add(Weight::from_ref_time(57_577_008 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_753 nanoseconds. + Weight::from_ref_time(295_491_471 as u64) + // Standard Error: 112_217 + .saturating_add(Weight::from_ref_time(41_976_228 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -886,10 +887,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 308_069 nanoseconds. - Weight::from_ref_time(308_971_000 as u64) - // Standard Error: 46_181 - .saturating_add(Weight::from_ref_time(321_835_684 as u64).saturating_mul(n as u64)) + // Minimum execution time: 335_784 nanoseconds. + Weight::from_ref_time(336_406_000 as u64) + // Standard Error: 58_205 + .saturating_add(Weight::from_ref_time(323_644_833 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -900,10 +901,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - // Minimum execution time: 247_107 nanoseconds. - Weight::from_ref_time(250_125_030 as u64) - // Standard Error: 88_769 - .saturating_add(Weight::from_ref_time(70_727_669 as u64).saturating_mul(r as u64)) + // Minimum execution time: 292_772 nanoseconds. + Weight::from_ref_time(294_845_565 as u64) + // Standard Error: 118_932 + .saturating_add(Weight::from_ref_time(53_186_034 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -914,10 +915,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 319_515 nanoseconds. - Weight::from_ref_time(319_784_000 as u64) - // Standard Error: 58_896 - .saturating_add(Weight::from_ref_time(246_433_962 as u64).saturating_mul(n as u64)) + // Minimum execution time: 348_057 nanoseconds. + Weight::from_ref_time(354_903_000 as u64) + // Standard Error: 63_036 + .saturating_add(Weight::from_ref_time(247_852_636 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -928,10 +929,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - // Minimum execution time: 247_887 nanoseconds. - Weight::from_ref_time(250_452_702 as u64) - // Standard Error: 140_887 - .saturating_add(Weight::from_ref_time(49_538_397 as u64).saturating_mul(r as u64)) + // Minimum execution time: 290_417 nanoseconds. + Weight::from_ref_time(295_285_706 as u64) + // Standard Error: 124_630 + .saturating_add(Weight::from_ref_time(31_293_293 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -942,10 +943,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 297_534 nanoseconds. - Weight::from_ref_time(298_249_000 as u64) - // Standard Error: 49_680 - .saturating_add(Weight::from_ref_time(99_001_103 as u64).saturating_mul(n as u64)) + // Minimum execution time: 325_903 nanoseconds. + Weight::from_ref_time(326_482_000 as u64) + // Standard Error: 47_465 + .saturating_add(Weight::from_ref_time(99_615_769 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -956,10 +957,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - // Minimum execution time: 245_926 nanoseconds. - Weight::from_ref_time(248_471_834 as u64) - // Standard Error: 101_639 - .saturating_add(Weight::from_ref_time(47_889_865 as u64).saturating_mul(r as u64)) + // Minimum execution time: 291_624 nanoseconds. + Weight::from_ref_time(295_781_938 as u64) + // Standard Error: 849_772 + .saturating_add(Weight::from_ref_time(30_869_061 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -970,10 +971,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 294_835 nanoseconds. - Weight::from_ref_time(296_328_000 as u64) - // Standard Error: 46_612 - .saturating_add(Weight::from_ref_time(98_859_152 as u64).saturating_mul(n as u64)) + // Minimum execution time: 323_456 nanoseconds. + Weight::from_ref_time(324_815_000 as u64) + // Standard Error: 49_126 + .saturating_add(Weight::from_ref_time(99_651_878 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -984,10 +985,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - // Minimum execution time: 251_104 nanoseconds. - Weight::from_ref_time(253_114_893 as u64) - // Standard Error: 316_740 - .saturating_add(Weight::from_ref_time(2_964_072_706 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_244 nanoseconds. + Weight::from_ref_time(296_117_277 as u64) + // Standard Error: 513_100 + .saturating_add(Weight::from_ref_time(3_005_168_422 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -998,10 +999,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - // Minimum execution time: 250_048 nanoseconds. - Weight::from_ref_time(251_774_991 as u64) - // Standard Error: 115_294 - .saturating_add(Weight::from_ref_time(2_094_245_208 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_099 nanoseconds. + Weight::from_ref_time(295_349_591 as u64) + // Standard Error: 437_688 + .saturating_add(Weight::from_ref_time(2_079_472_608 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -1013,10 +1014,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 250_830 nanoseconds. - Weight::from_ref_time(251_477_000 as u64) - // Standard Error: 2_727_998 - .saturating_add(Weight::from_ref_time(1_390_149_283 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_692 nanoseconds. + Weight::from_ref_time(294_871_000 as u64) + // Standard Error: 2_737_018 + .saturating_add(Weight::from_ref_time(1_360_098_499 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((225 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(3 as u64)) @@ -1026,382 +1027,386 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. - fn seal_reentrant_count(r: u32, ) -> Weight { - Weight::from_ref_time(304_709_000 as u64) - // Standard Error: 67_000 - .saturating_add(Weight::from_ref_time(15_411_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + fn seal_reentrance_count(r: u32, ) -> Weight { + // Minimum execution time: 295_570 nanoseconds. + Weight::from_ref_time(299_077_520 as u64) + // Standard Error: 23_516 + .saturating_add(Weight::from_ref_time(10_971_589 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { - Weight::from_ref_time(328_378_000 as u64) - // Standard Error: 137_000 - .saturating_add(Weight::from_ref_time(37_448_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 296_873 nanoseconds. + Weight::from_ref_time(336_309_706 as u64) + // Standard Error: 125_484 + .saturating_add(Weight::from_ref_time(25_321_948 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - // Minimum execution time: 69_022 nanoseconds. - Weight::from_ref_time(69_707_657 as u64) - // Standard Error: 8_674 - .saturating_add(Weight::from_ref_time(887_555 as u64).saturating_mul(r as u64)) + // Minimum execution time: 686 nanoseconds. + Weight::from_ref_time(895_726 as u64) + // Standard Error: 144 + .saturating_add(Weight::from_ref_time(344_525 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // Minimum execution time: 69_491 nanoseconds. - Weight::from_ref_time(70_354_670 as u64) - // Standard Error: 1_518 - .saturating_add(Weight::from_ref_time(2_758_912 as u64).saturating_mul(r as u64)) + // Minimum execution time: 780 nanoseconds. + Weight::from_ref_time(590_334 as u64) + // Standard Error: 10_839 + .saturating_add(Weight::from_ref_time(1_038_503 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // Minimum execution time: 69_156 nanoseconds. - Weight::from_ref_time(69_917_601 as u64) - // Standard Error: 1_970 - .saturating_add(Weight::from_ref_time(2_753_174 as u64).saturating_mul(r as u64)) + // Minimum execution time: 755 nanoseconds. + Weight::from_ref_time(1_139_912 as u64) + // Standard Error: 466 + .saturating_add(Weight::from_ref_time(881_780 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // Minimum execution time: 68_944 nanoseconds. - Weight::from_ref_time(69_727_961 as u64) - // Standard Error: 376 - .saturating_add(Weight::from_ref_time(2_356_996 as u64).saturating_mul(r as u64)) + // Minimum execution time: 670 nanoseconds. + Weight::from_ref_time(941_845 as u64) + // Standard Error: 227 + .saturating_add(Weight::from_ref_time(956_897 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // Minimum execution time: 68_971 nanoseconds. - Weight::from_ref_time(69_755_949 as u64) - // Standard Error: 543 - .saturating_add(Weight::from_ref_time(2_489_510 as u64).saturating_mul(r as u64)) + // Minimum execution time: 676 nanoseconds. + Weight::from_ref_time(600_675 as u64) + // Standard Error: 555 + .saturating_add(Weight::from_ref_time(1_294_447 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // Minimum execution time: 69_061 nanoseconds. - Weight::from_ref_time(69_625_000 as u64) - // Standard Error: 486 - .saturating_add(Weight::from_ref_time(1_431_684 as u64).saturating_mul(r as u64)) + // Minimum execution time: 680 nanoseconds. + Weight::from_ref_time(1_192_340 as u64) + // Standard Error: 897 + .saturating_add(Weight::from_ref_time(524_835 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // Minimum execution time: 69_058 nanoseconds. - Weight::from_ref_time(69_521_790 as u64) - // Standard Error: 892 - .saturating_add(Weight::from_ref_time(1_964_054 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(1_136_213 as u64) + // Standard Error: 1_137 + .saturating_add(Weight::from_ref_time(791_920 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // Minimum execution time: 69_020 nanoseconds. - Weight::from_ref_time(69_344_255 as u64) - // Standard Error: 1_408 - .saturating_add(Weight::from_ref_time(2_169_179 as u64).saturating_mul(r as u64)) + // Minimum execution time: 669 nanoseconds. + Weight::from_ref_time(491_588 as u64) + // Standard Error: 2_098 + .saturating_add(Weight::from_ref_time(1_078_017 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - // Minimum execution time: 72_366 nanoseconds. - Weight::from_ref_time(72_869_594 as u64) - // Standard Error: 73 - .saturating_add(Weight::from_ref_time(3_867 as u64).saturating_mul(e as u64)) + // Minimum execution time: 2_128 nanoseconds. + Weight::from_ref_time(2_565_932 as u64) + // Standard Error: 76 + .saturating_add(Weight::from_ref_time(4_830 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // Minimum execution time: 69_164 nanoseconds. - Weight::from_ref_time(70_269_099 as u64) - // Standard Error: 8_824 - .saturating_add(Weight::from_ref_time(6_594_634 as u64).saturating_mul(r as u64)) + // Minimum execution time: 665 nanoseconds. + Weight::from_ref_time(1_593_317 as u64) + // Standard Error: 2_288 + .saturating_add(Weight::from_ref_time(2_195_453 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // Minimum execution time: 83_348 nanoseconds. - Weight::from_ref_time(84_968_895 as u64) - // Standard Error: 6_305 - .saturating_add(Weight::from_ref_time(8_395_193 as u64).saturating_mul(r as u64)) + // Minimum execution time: 796 nanoseconds. + Weight::from_ref_time(1_816_603 as u64) + // Standard Error: 2_183 + .saturating_add(Weight::from_ref_time(2_808_821 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - // Minimum execution time: 92_358 nanoseconds. - Weight::from_ref_time(93_605_536 as u64) - // Standard Error: 2_019 - .saturating_add(Weight::from_ref_time(536_495 as u64).saturating_mul(p as u64)) + // Minimum execution time: 4_212 nanoseconds. + Weight::from_ref_time(5_097_891 as u64) + // Standard Error: 576 + .saturating_add(Weight::from_ref_time(180_948 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // Minimum execution time: 69_191 nanoseconds. - Weight::from_ref_time(70_407_702 as u64) - // Standard Error: 2_812 - .saturating_add(Weight::from_ref_time(901_706 as u64).saturating_mul(r as u64)) + // Minimum execution time: 1_412 nanoseconds. + Weight::from_ref_time(1_733_015 as u64) + // Standard Error: 215 + .saturating_add(Weight::from_ref_time(366_629 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // Minimum execution time: 69_230 nanoseconds. - Weight::from_ref_time(70_255_278 as u64) - // Standard Error: 1_284 - .saturating_add(Weight::from_ref_time(951_754 as u64).saturating_mul(r as u64)) + // Minimum execution time: 1_436 nanoseconds. + Weight::from_ref_time(1_772_333 as u64) + // Standard Error: 288 + .saturating_add(Weight::from_ref_time(380_886 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // Minimum execution time: 69_278 nanoseconds. - Weight::from_ref_time(70_089_139 as u64) - // Standard Error: 757 - .saturating_add(Weight::from_ref_time(1_369_185 as u64).saturating_mul(r as u64)) + // Minimum execution time: 1_408 nanoseconds. + Weight::from_ref_time(1_731_571 as u64) + // Standard Error: 334 + .saturating_add(Weight::from_ref_time(526_489 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // Minimum execution time: 72_047 nanoseconds. - Weight::from_ref_time(72_783_972 as u64) - // Standard Error: 837 - .saturating_add(Weight::from_ref_time(1_471_680 as u64).saturating_mul(r as u64)) + // Minimum execution time: 752 nanoseconds. + Weight::from_ref_time(1_118_170 as u64) + // Standard Error: 302 + .saturating_add(Weight::from_ref_time(809_371 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // Minimum execution time: 71_960 nanoseconds. - Weight::from_ref_time(72_745_981 as u64) - // Standard Error: 1_086 - .saturating_add(Weight::from_ref_time(1_537_741 as u64).saturating_mul(r as u64)) + // Minimum execution time: 770 nanoseconds. + Weight::from_ref_time(990_414 as u64) + // Standard Error: 331 + .saturating_add(Weight::from_ref_time(831_541 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // Minimum execution time: 69_221 nanoseconds. - Weight::from_ref_time(70_010_862 as u64) - // Standard Error: 1_845 - .saturating_add(Weight::from_ref_time(933_738 as u64).saturating_mul(r as u64)) + // Minimum execution time: 783 nanoseconds. + Weight::from_ref_time(992_847 as u64) + // Standard Error: 437 + .saturating_add(Weight::from_ref_time(695_374 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // Minimum execution time: 69_081 nanoseconds. - Weight::from_ref_time(71_015_495 as u64) - // Standard Error: 27_078 - .saturating_add(Weight::from_ref_time(183_899_704 as u64).saturating_mul(r as u64)) + // Minimum execution time: 664 nanoseconds. + Weight::from_ref_time(758_730 as u64) + // Standard Error: 5_030 + .saturating_add(Weight::from_ref_time(184_801_569 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // Minimum execution time: 70_589 nanoseconds. - Weight::from_ref_time(70_175_537 as u64) - // Standard Error: 1_355 - .saturating_add(Weight::from_ref_time(1_323_745 as u64).saturating_mul(r as u64)) + // Minimum execution time: 657 nanoseconds. + Weight::from_ref_time(941_928 as u64) + // Standard Error: 216 + .saturating_add(Weight::from_ref_time(506_159 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - // Minimum execution time: 69_083 nanoseconds. - Weight::from_ref_time(69_832_339 as u64) - // Standard Error: 818 - .saturating_add(Weight::from_ref_time(1_334_198 as u64).saturating_mul(r as u64)) + // Minimum execution time: 617 nanoseconds. + Weight::from_ref_time(1_009_437 as u64) + // Standard Error: 435 + .saturating_add(Weight::from_ref_time(512_427 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // Minimum execution time: 69_084 nanoseconds. - Weight::from_ref_time(69_802_701 as u64) - // Standard Error: 744 - .saturating_add(Weight::from_ref_time(1_334_601 as u64).saturating_mul(r as u64)) + // Minimum execution time: 663 nanoseconds. + Weight::from_ref_time(875_558 as u64) + // Standard Error: 394 + .saturating_add(Weight::from_ref_time(513_247 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // Minimum execution time: 69_052 nanoseconds. - Weight::from_ref_time(69_717_748 as u64) - // Standard Error: 571 - .saturating_add(Weight::from_ref_time(1_346_564 as u64).saturating_mul(r as u64)) + // Minimum execution time: 664 nanoseconds. + Weight::from_ref_time(891_913 as u64) + // Standard Error: 171 + .saturating_add(Weight::from_ref_time(523_595 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // Minimum execution time: 69_016 nanoseconds. - Weight::from_ref_time(69_793_413 as u64) - // Standard Error: 769 - .saturating_add(Weight::from_ref_time(1_317_502 as u64).saturating_mul(r as u64)) + // Minimum execution time: 638 nanoseconds. + Weight::from_ref_time(1_003_558 as u64) + // Standard Error: 471 + .saturating_add(Weight::from_ref_time(502_671 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // Minimum execution time: 69_043 nanoseconds. - Weight::from_ref_time(69_963_419 as u64) - // Standard Error: 1_117 - .saturating_add(Weight::from_ref_time(1_313_727 as u64).saturating_mul(r as u64)) + // Minimum execution time: 665 nanoseconds. + Weight::from_ref_time(892_435 as u64) + // Standard Error: 162 + .saturating_add(Weight::from_ref_time(504_300 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // Minimum execution time: 69_032 nanoseconds. - Weight::from_ref_time(69_727_577 as u64) - // Standard Error: 662 - .saturating_add(Weight::from_ref_time(1_331_088 as u64).saturating_mul(r as u64)) + // Minimum execution time: 626 nanoseconds. + Weight::from_ref_time(880_015 as u64) + // Standard Error: 229 + .saturating_add(Weight::from_ref_time(503_941 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // Minimum execution time: 69_097 nanoseconds. - Weight::from_ref_time(69_767_650 as u64) - // Standard Error: 2_056 - .saturating_add(Weight::from_ref_time(1_875_021 as u64).saturating_mul(r as u64)) + // Minimum execution time: 623 nanoseconds. + Weight::from_ref_time(893_955 as u64) + // Standard Error: 238 + .saturating_add(Weight::from_ref_time(731_619 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // Minimum execution time: 69_153 nanoseconds. - Weight::from_ref_time(69_906_946 as u64) - // Standard Error: 1_060 - .saturating_add(Weight::from_ref_time(1_867_154 as u64).saturating_mul(r as u64)) + // Minimum execution time: 661 nanoseconds. + Weight::from_ref_time(904_145 as u64) + // Standard Error: 210 + .saturating_add(Weight::from_ref_time(730_497 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // Minimum execution time: 70_380 nanoseconds. - Weight::from_ref_time(69_867_328 as u64) - // Standard Error: 778 - .saturating_add(Weight::from_ref_time(1_869_718 as u64).saturating_mul(r as u64)) + // Minimum execution time: 670 nanoseconds. + Weight::from_ref_time(910_832 as u64) + // Standard Error: 248 + .saturating_add(Weight::from_ref_time(738_960 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // Minimum execution time: 69_259 nanoseconds. - Weight::from_ref_time(69_695_407 as u64) - // Standard Error: 746 - .saturating_add(Weight::from_ref_time(1_874_772 as u64).saturating_mul(r as u64)) + // Minimum execution time: 600 nanoseconds. + Weight::from_ref_time(910_816 as u64) + // Standard Error: 257 + .saturating_add(Weight::from_ref_time(742_585 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // Minimum execution time: 68_986 nanoseconds. - Weight::from_ref_time(70_027_081 as u64) - // Standard Error: 1_401 - .saturating_add(Weight::from_ref_time(1_862_971 as u64).saturating_mul(r as u64)) + // Minimum execution time: 697 nanoseconds. + Weight::from_ref_time(937_672 as u64) + // Standard Error: 291 + .saturating_add(Weight::from_ref_time(746_511 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // Minimum execution time: 68_953 nanoseconds. - Weight::from_ref_time(69_798_073 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_871_888 as u64).saturating_mul(r as u64)) + // Minimum execution time: 651 nanoseconds. + Weight::from_ref_time(920_151 as u64) + // Standard Error: 185 + .saturating_add(Weight::from_ref_time(743_483 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // Minimum execution time: 68_909 nanoseconds. - Weight::from_ref_time(69_845_981 as u64) - // Standard Error: 775 - .saturating_add(Weight::from_ref_time(1_868_722 as u64).saturating_mul(r as u64)) + // Minimum execution time: 622 nanoseconds. + Weight::from_ref_time(914_571 as u64) + // Standard Error: 264 + .saturating_add(Weight::from_ref_time(733_935 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // Minimum execution time: 68_986 nanoseconds. - Weight::from_ref_time(69_683_189 as u64) - // Standard Error: 503 - .saturating_add(Weight::from_ref_time(1_884_715 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(914_243 as u64) + // Standard Error: 199 + .saturating_add(Weight::from_ref_time(738_786 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - // Minimum execution time: 69_230 nanoseconds. - Weight::from_ref_time(69_765_336 as u64) - // Standard Error: 2_060 - .saturating_add(Weight::from_ref_time(1_871_848 as u64).saturating_mul(r as u64)) + // Minimum execution time: 625 nanoseconds. + Weight::from_ref_time(1_144_724 as u64) + // Standard Error: 1_367 + .saturating_add(Weight::from_ref_time(729_921 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // Minimum execution time: 68_953 nanoseconds. - Weight::from_ref_time(69_828_265 as u64) - // Standard Error: 951 - .saturating_add(Weight::from_ref_time(1_868_596 as u64).saturating_mul(r as u64)) + // Minimum execution time: 643 nanoseconds. + Weight::from_ref_time(897_337 as u64) + // Standard Error: 162 + .saturating_add(Weight::from_ref_time(738_471 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // Minimum execution time: 69_078 nanoseconds. - Weight::from_ref_time(69_832_768 as u64) - // Standard Error: 894 - .saturating_add(Weight::from_ref_time(1_845_786 as u64).saturating_mul(r as u64)) + // Minimum execution time: 672 nanoseconds. + Weight::from_ref_time(921_395 as u64) + // Standard Error: 465 + .saturating_add(Weight::from_ref_time(719_508 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // Minimum execution time: 68_939 nanoseconds. - Weight::from_ref_time(69_676_256 as u64) - // Standard Error: 374 - .saturating_add(Weight::from_ref_time(1_851_026 as u64).saturating_mul(r as u64)) + // Minimum execution time: 672 nanoseconds. + Weight::from_ref_time(889_319 as u64) + // Standard Error: 392 + .saturating_add(Weight::from_ref_time(714_186 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // Minimum execution time: 69_096 nanoseconds. - Weight::from_ref_time(69_914_159 as u64) - // Standard Error: 1_265 - .saturating_add(Weight::from_ref_time(1_844_489 as u64).saturating_mul(r as u64)) + // Minimum execution time: 660 nanoseconds. + Weight::from_ref_time(898_856 as u64) + // Standard Error: 189 + .saturating_add(Weight::from_ref_time(714_302 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // Minimum execution time: 68_939 nanoseconds. - Weight::from_ref_time(69_641_768 as u64) - // Standard Error: 347 - .saturating_add(Weight::from_ref_time(2_488_628 as u64).saturating_mul(r as u64)) + // Minimum execution time: 629 nanoseconds. + Weight::from_ref_time(902_499 as u64) + // Standard Error: 428 + .saturating_add(Weight::from_ref_time(1_346_772 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // Minimum execution time: 69_114 nanoseconds. - Weight::from_ref_time(69_844_395 as u64) - // Standard Error: 1_489 - .saturating_add(Weight::from_ref_time(2_456_310 as u64).saturating_mul(r as u64)) + // Minimum execution time: 624 nanoseconds. + Weight::from_ref_time(944_381 as u64) + // Standard Error: 389 + .saturating_add(Weight::from_ref_time(1_281_605 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // Minimum execution time: 69_082 nanoseconds. - Weight::from_ref_time(69_993_662 as u64) - // Standard Error: 1_218 - .saturating_add(Weight::from_ref_time(2_524_010 as u64).saturating_mul(r as u64)) + // Minimum execution time: 667 nanoseconds. + Weight::from_ref_time(876_301 as u64) + // Standard Error: 589 + .saturating_add(Weight::from_ref_time(1_397_964 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // Minimum execution time: 69_036 nanoseconds. - Weight::from_ref_time(70_095_304 as u64) - // Standard Error: 1_473 - .saturating_add(Weight::from_ref_time(2_429_659 as u64).saturating_mul(r as u64)) + // Minimum execution time: 611 nanoseconds. + Weight::from_ref_time(865_466 as u64) + // Standard Error: 253 + .saturating_add(Weight::from_ref_time(1_283_803 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // Minimum execution time: 69_229 nanoseconds. - Weight::from_ref_time(69_759_818 as u64) - // Standard Error: 573 - .saturating_add(Weight::from_ref_time(1_879_670 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(882_010 as u64) + // Standard Error: 205 + .saturating_add(Weight::from_ref_time(731_251 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // Minimum execution time: 69_151 nanoseconds. - Weight::from_ref_time(69_865_948 as u64) - // Standard Error: 721 - .saturating_add(Weight::from_ref_time(1_846_734 as u64).saturating_mul(r as u64)) + // Minimum execution time: 638 nanoseconds. + Weight::from_ref_time(917_858 as u64) + // Standard Error: 249 + .saturating_add(Weight::from_ref_time(795_023 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // Minimum execution time: 69_120 nanoseconds. - Weight::from_ref_time(70_135_849 as u64) - // Standard Error: 3_443 - .saturating_add(Weight::from_ref_time(1_841_784 as u64).saturating_mul(r as u64)) + // Minimum execution time: 636 nanoseconds. + Weight::from_ref_time(892_650 as u64) + // Standard Error: 252 + .saturating_add(Weight::from_ref_time(729_337 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // Minimum execution time: 69_077 nanoseconds. - Weight::from_ref_time(69_929_746 as u64) - // Standard Error: 821 - .saturating_add(Weight::from_ref_time(1_866_348 as u64).saturating_mul(r as u64)) + // Minimum execution time: 648 nanoseconds. + Weight::from_ref_time(918_889 as u64) + // Standard Error: 1_079 + .saturating_add(Weight::from_ref_time(746_835 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // Minimum execution time: 69_226 nanoseconds. - Weight::from_ref_time(69_725_630 as u64) - // Standard Error: 891 - .saturating_add(Weight::from_ref_time(1_873_637 as u64).saturating_mul(r as u64)) + // Minimum execution time: 677 nanoseconds. + Weight::from_ref_time(931_684 as u64) + // Standard Error: 259 + .saturating_add(Weight::from_ref_time(734_540 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // Minimum execution time: 70_591 nanoseconds. - Weight::from_ref_time(69_939_773 as u64) - // Standard Error: 960 - .saturating_add(Weight::from_ref_time(1_867_208 as u64).saturating_mul(r as u64)) + // Minimum execution time: 635 nanoseconds. + Weight::from_ref_time(914_996 as u64) + // Standard Error: 611 + .saturating_add(Weight::from_ref_time(735_020 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // Minimum execution time: 69_187 nanoseconds. - Weight::from_ref_time(69_845_516 as u64) - // Standard Error: 781 - .saturating_add(Weight::from_ref_time(1_869_613 as u64).saturating_mul(r as u64)) + // Minimum execution time: 663 nanoseconds. + Weight::from_ref_time(914_333 as u64) + // Standard Error: 169 + .saturating_add(Weight::from_ref_time(734_033 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // Minimum execution time: 69_065 nanoseconds. - Weight::from_ref_time(69_950_430 as u64) - // Standard Error: 986 - .saturating_add(Weight::from_ref_time(1_867_001 as u64).saturating_mul(r as u64)) + // Minimum execution time: 631 nanoseconds. + Weight::from_ref_time(916_503 as u64) + // Standard Error: 224 + .saturating_add(Weight::from_ref_time(736_168 as u64).saturating_mul(r as u64)) } } @@ -1409,17 +1414,17 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - // Minimum execution time: 3_064 nanoseconds. - Weight::from_ref_time(3_236_000 as u64) + // Minimum execution time: 3_174 nanoseconds. + Weight::from_ref_time(3_298_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - // Minimum execution time: 15_492 nanoseconds. - Weight::from_ref_time(14_309_233 as u64) - // Standard Error: 649 - .saturating_add(Weight::from_ref_time(930_078 as u64).saturating_mul(k as u64)) + // Minimum execution time: 15_218 nanoseconds. + Weight::from_ref_time(15_548_154 as u64) + // Standard Error: 732 + .saturating_add(Weight::from_ref_time(940_242 as u64).saturating_mul(k as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) @@ -1427,10 +1432,10 @@ impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - // Minimum execution time: 3_240 nanoseconds. - Weight::from_ref_time(15_076_559 as u64) - // Standard Error: 3_337 - .saturating_add(Weight::from_ref_time(1_244_348 as u64).saturating_mul(q as u64)) + // Minimum execution time: 3_096 nanoseconds. + Weight::from_ref_time(14_949_039 as u64) + // Standard Error: 3_466 + .saturating_add(Weight::from_ref_time(1_236_160 as u64).saturating_mul(q as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1438,10 +1443,10 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - // Minimum execution time: 22_524 nanoseconds. - Weight::from_ref_time(19_939_078 as u64) - // Standard Error: 43 - .saturating_add(Weight::from_ref_time(43_802 as u64).saturating_mul(c as u64)) + // Minimum execution time: 28_333 nanoseconds. + Weight::from_ref_time(19_421_544 as u64) + // Standard Error: 92 + .saturating_add(Weight::from_ref_time(47_629 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1452,10 +1457,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - // Minimum execution time: 261_039 nanoseconds. - Weight::from_ref_time(228_709_853 as u64) - // Standard Error: 105 - .saturating_add(Weight::from_ref_time(47_449 as u64).saturating_mul(c as u64)) + // Minimum execution time: 304_381 nanoseconds. + Weight::from_ref_time(315_177_233 as u64) + // Standard Error: 22 + .saturating_add(Weight::from_ref_time(30_372 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1470,12 +1475,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - // Minimum execution time: 2_054_867 nanoseconds. - Weight::from_ref_time(259_090_306 as u64) - // Standard Error: 72 - .saturating_add(Weight::from_ref_time(107_519 as u64).saturating_mul(c as u64)) - // Standard Error: 4 - .saturating_add(Weight::from_ref_time(1_736 as u64).saturating_mul(s as u64)) + // Minimum execution time: 2_119_963 nanoseconds. + Weight::from_ref_time(337_976_516 as u64) + // Standard Error: 84 + .saturating_add(Weight::from_ref_time(88_566 as u64).saturating_mul(c as u64)) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(1_747 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(9 as u64)) } @@ -1488,10 +1493,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - // Minimum execution time: 213_409 nanoseconds. - Weight::from_ref_time(205_300_495 as u64) - // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_479 as u64).saturating_mul(s as u64)) + // Minimum execution time: 184_739 nanoseconds. + Weight::from_ref_time(179_778_057 as u64) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(1_487 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(7 as u64)) } @@ -1501,8 +1506,8 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - // Minimum execution time: 183_317 nanoseconds. - Weight::from_ref_time(184_465_000 as u64) + // Minimum execution time: 154_711 nanoseconds. + Weight::from_ref_time(155_527_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1512,10 +1517,10 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - // Minimum execution time: 56_187 nanoseconds. - Weight::from_ref_time(60_636_621 as u64) - // Standard Error: 46 - .saturating_add(Weight::from_ref_time(45_734 as u64).saturating_mul(c as u64)) + // Minimum execution time: 294_982 nanoseconds. + Weight::from_ref_time(302_482_450 as u64) + // Standard Error: 62 + .saturating_add(Weight::from_ref_time(88_358 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1524,8 +1529,8 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - // Minimum execution time: 38_433 nanoseconds. - Weight::from_ref_time(38_917_000 as u64) + // Minimum execution time: 39_655 nanoseconds. + Weight::from_ref_time(40_147_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -1533,8 +1538,8 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - // Minimum execution time: 41_507 nanoseconds. - Weight::from_ref_time(41_938_000 as u64) + // Minimum execution time: 41_028 nanoseconds. + Weight::from_ref_time(41_565_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -1545,10 +1550,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - // Minimum execution time: 249_628 nanoseconds. - Weight::from_ref_time(251_997_923 as u64) - // Standard Error: 26_157 - .saturating_add(Weight::from_ref_time(35_002_004 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_231 nanoseconds. + Weight::from_ref_time(298_245_008 as u64) + // Standard Error: 41_817 + .saturating_add(Weight::from_ref_time(16_183_097 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1559,10 +1564,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - // Minimum execution time: 249_390 nanoseconds. - Weight::from_ref_time(193_793_052 as u64) - // Standard Error: 430_292 - .saturating_add(Weight::from_ref_time(211_029_686 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_152 nanoseconds. + Weight::from_ref_time(231_239_439 as u64) + // Standard Error: 475_771 + .saturating_add(Weight::from_ref_time(193_804_587 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1574,10 +1579,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 252_469 nanoseconds. - Weight::from_ref_time(201_438_856 as u64) - // Standard Error: 420_040 - .saturating_add(Weight::from_ref_time(267_340_744 as u64).saturating_mul(r as u64)) + // Minimum execution time: 296_171 nanoseconds. + Weight::from_ref_time(244_339_298 as u64) + // Standard Error: 440_060 + .saturating_add(Weight::from_ref_time(236_224_857 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1589,10 +1594,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 251_154 nanoseconds. - Weight::from_ref_time(254_831_062 as u64) - // Standard Error: 37_843 - .saturating_add(Weight::from_ref_time(38_579_567 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_891 nanoseconds. + Weight::from_ref_time(298_061_159 as u64) + // Standard Error: 30_013 + .saturating_add(Weight::from_ref_time(19_682_309 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1603,10 +1608,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - // Minimum execution time: 247_875 nanoseconds. - Weight::from_ref_time(250_312_587 as u64) - // Standard Error: 17_901 - .saturating_add(Weight::from_ref_time(15_153_431 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_259 nanoseconds. + Weight::from_ref_time(296_675_355 as u64) + // Standard Error: 24_508 + .saturating_add(Weight::from_ref_time(10_949_451 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1617,10 +1622,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - // Minimum execution time: 250_097 nanoseconds. - Weight::from_ref_time(252_157_442 as u64) - // Standard Error: 38_426 - .saturating_add(Weight::from_ref_time(35_084_205 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_507 nanoseconds. + Weight::from_ref_time(295_682_709 as u64) + // Standard Error: 43_685 + .saturating_add(Weight::from_ref_time(16_461_873 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1631,10 +1636,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - // Minimum execution time: 250_034 nanoseconds. - Weight::from_ref_time(252_189_233 as u64) - // Standard Error: 33_081 - .saturating_add(Weight::from_ref_time(34_764_160 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_473 nanoseconds. + Weight::from_ref_time(296_523_274 as u64) + // Standard Error: 34_356 + .saturating_add(Weight::from_ref_time(15_932_835 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1645,10 +1650,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - // Minimum execution time: 249_587 nanoseconds. - Weight::from_ref_time(258_565_111 as u64) - // Standard Error: 75_715 - .saturating_add(Weight::from_ref_time(109_687_486 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_889 nanoseconds. + Weight::from_ref_time(295_471_068 as u64) + // Standard Error: 88_937 + .saturating_add(Weight::from_ref_time(89_606_655 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1659,10 +1664,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - // Minimum execution time: 249_735 nanoseconds. - Weight::from_ref_time(252_875_784 as u64) - // Standard Error: 42_024 - .saturating_add(Weight::from_ref_time(34_555_983 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_747 nanoseconds. + Weight::from_ref_time(297_023_967 as u64) + // Standard Error: 18_756 + .saturating_add(Weight::from_ref_time(15_748_008 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1673,10 +1678,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - // Minimum execution time: 250_025 nanoseconds. - Weight::from_ref_time(255_212_046 as u64) - // Standard Error: 41_865 - .saturating_add(Weight::from_ref_time(34_332_291 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_590 nanoseconds. + Weight::from_ref_time(296_257_202 as u64) + // Standard Error: 24_863 + .saturating_add(Weight::from_ref_time(15_851_537 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1687,10 +1692,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - // Minimum execution time: 247_641 nanoseconds. - Weight::from_ref_time(252_978_686 as u64) - // Standard Error: 25_820 - .saturating_add(Weight::from_ref_time(34_175_386 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_746 nanoseconds. + Weight::from_ref_time(297_308_097 as u64) + // Standard Error: 29_585 + .saturating_add(Weight::from_ref_time(15_608_985 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1701,10 +1706,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - // Minimum execution time: 249_871 nanoseconds. - Weight::from_ref_time(253_237_931 as u64) - // Standard Error: 30_986 - .saturating_add(Weight::from_ref_time(34_305_155 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_662 nanoseconds. + Weight::from_ref_time(296_393_072 as u64) + // Standard Error: 23_750 + .saturating_add(Weight::from_ref_time(15_891_911 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1716,10 +1721,10 @@ impl WeightInfo for () { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - // Minimum execution time: 249_787 nanoseconds. - Weight::from_ref_time(258_457_094 as u64) - // Standard Error: 75_835 - .saturating_add(Weight::from_ref_time(107_115_666 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_036 nanoseconds. + Weight::from_ref_time(301_071_620 as u64) + // Standard Error: 85_146 + .saturating_add(Weight::from_ref_time(84_455_768 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1730,10 +1735,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - // Minimum execution time: 171_667 nanoseconds. - Weight::from_ref_time(174_687_863 as u64) - // Standard Error: 34_576 - .saturating_add(Weight::from_ref_time(15_895_674 as u64).saturating_mul(r as u64)) + // Minimum execution time: 142_655 nanoseconds. + Weight::from_ref_time(145_691_226 as u64) + // Standard Error: 11_085 + .saturating_add(Weight::from_ref_time(7_953_680 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1744,10 +1749,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - // Minimum execution time: 249_610 nanoseconds. - Weight::from_ref_time(251_476_758 as u64) - // Standard Error: 39_422 - .saturating_add(Weight::from_ref_time(32_870_429 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_613 nanoseconds. + Weight::from_ref_time(296_889_714 as u64) + // Standard Error: 21_550 + .saturating_add(Weight::from_ref_time(13_672_097 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1758,10 +1763,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 285_154 nanoseconds. - Weight::from_ref_time(307_768_636 as u64) - // Standard Error: 2_701 - .saturating_add(Weight::from_ref_time(9_544_122 as u64).saturating_mul(n as u64)) + // Minimum execution time: 309_866 nanoseconds. + Weight::from_ref_time(328_331_386 as u64) + // Standard Error: 6_205 + .saturating_add(Weight::from_ref_time(9_619_067 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1772,10 +1777,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - // Minimum execution time: 244_810 nanoseconds. - Weight::from_ref_time(247_576_385 as u64) - // Standard Error: 80_494 - .saturating_add(Weight::from_ref_time(2_052_714 as u64).saturating_mul(r as u64)) + // Minimum execution time: 288_265 nanoseconds. + Weight::from_ref_time(292_739_779 as u64) + // Standard Error: 108_313 + .saturating_add(Weight::from_ref_time(1_475_820 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1786,10 +1791,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 248_049 nanoseconds. - Weight::from_ref_time(250_148_025 as u64) - // Standard Error: 339 - .saturating_add(Weight::from_ref_time(185_344 as u64).saturating_mul(n as u64)) + // Minimum execution time: 293_044 nanoseconds. + Weight::from_ref_time(293_846_263 as u64) + // Standard Error: 641 + .saturating_add(Weight::from_ref_time(188_770 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1802,10 +1807,10 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - // Minimum execution time: 246_620 nanoseconds. - Weight::from_ref_time(250_752_277 as u64) - // Standard Error: 84_300 - .saturating_add(Weight::from_ref_time(54_264_722 as u64).saturating_mul(r as u64)) + // Minimum execution time: 289_248 nanoseconds. + Weight::from_ref_time(294_406_912 as u64) + // Standard Error: 112_528 + .saturating_add(Weight::from_ref_time(52_650_987 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1819,10 +1824,10 @@ impl WeightInfo for () { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - // Minimum execution time: 249_065 nanoseconds. - Weight::from_ref_time(252_419_902 as u64) - // Standard Error: 84_223 - .saturating_add(Weight::from_ref_time(134_454_079 as u64).saturating_mul(r as u64)) + // Minimum execution time: 292_980 nanoseconds. + Weight::from_ref_time(298_232_040 as u64) + // Standard Error: 85_517 + .saturating_add(Weight::from_ref_time(108_891_823 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1833,10 +1838,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - // Minimum execution time: 246_588 nanoseconds. - Weight::from_ref_time(261_525_328 as u64) - // Standard Error: 97_732 - .saturating_add(Weight::from_ref_time(235_555_878 as u64).saturating_mul(r as u64)) + // Minimum execution time: 291_668 nanoseconds. + Weight::from_ref_time(302_010_570 as u64) + // Standard Error: 109_901 + .saturating_add(Weight::from_ref_time(214_667_762 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -1848,12 +1853,12 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - // Minimum execution time: 1_171_144 nanoseconds. - Weight::from_ref_time(490_333_337 as u64) - // Standard Error: 404_664 - .saturating_add(Weight::from_ref_time(173_683_265 as u64).saturating_mul(t as u64)) - // Standard Error: 111_140 - .saturating_add(Weight::from_ref_time(66_081_822 as u64).saturating_mul(n as u64)) + // Minimum execution time: 1_163_533 nanoseconds. + Weight::from_ref_time(501_280_410 as u64) + // Standard Error: 601_576 + .saturating_add(Weight::from_ref_time(172_210_846 as u64).saturating_mul(t as u64)) + // Standard Error: 165_221 + .saturating_add(Weight::from_ref_time(67_584_003 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1866,20 +1871,20 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - // Minimum execution time: 178_822 nanoseconds. - Weight::from_ref_time(181_571_518 as u64) - // Standard Error: 19_207 - .saturating_add(Weight::from_ref_time(26_784_712 as u64).saturating_mul(r as u64)) + // Minimum execution time: 154_390 nanoseconds. + Weight::from_ref_time(158_246_775 as u64) + // Standard Error: 23_812 + .saturating_add(Weight::from_ref_time(12_810_293 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - // Minimum execution time: 249_737 nanoseconds. - Weight::from_ref_time(208_095_467 as u64) - // Standard Error: 417_236 - .saturating_add(Weight::from_ref_time(430_088_574 as u64).saturating_mul(r as u64)) + // Minimum execution time: 292_926 nanoseconds. + Weight::from_ref_time(250_238_246 as u64) + // Standard Error: 485_292 + .saturating_add(Weight::from_ref_time(402_779_709 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1888,10 +1893,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - // Minimum execution time: 400_055 nanoseconds. - Weight::from_ref_time(551_666_883 as u64) - // Standard Error: 1_379_652 - .saturating_add(Weight::from_ref_time(94_069_118 as u64).saturating_mul(n as u64)) + // Minimum execution time: 421_504 nanoseconds. + Weight::from_ref_time(574_267_945 as u64) + // Standard Error: 1_407_019 + .saturating_add(Weight::from_ref_time(89_516_682 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(52 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(50 as u64)) @@ -1900,10 +1905,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - // Minimum execution time: 400_370 nanoseconds. - Weight::from_ref_time(521_380_000 as u64) - // Standard Error: 1_112_618 - .saturating_add(Weight::from_ref_time(68_664_898 as u64).saturating_mul(n as u64)) + // Minimum execution time: 421_422 nanoseconds. + Weight::from_ref_time(545_948_271 as u64) + // Standard Error: 1_148_143 + .saturating_add(Weight::from_ref_time(63_958_096 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(49 as u64)) @@ -1912,10 +1917,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - // Minimum execution time: 249_711 nanoseconds. - Weight::from_ref_time(212_629_798 as u64) - // Standard Error: 378_159 - .saturating_add(Weight::from_ref_time(415_326_230 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_545 nanoseconds. + Weight::from_ref_time(255_622_312 as u64) + // Standard Error: 407_862 + .saturating_add(Weight::from_ref_time(396_764_962 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1924,10 +1929,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 365_702 nanoseconds. - Weight::from_ref_time(499_337_686 as u64) - // Standard Error: 1_232_330 - .saturating_add(Weight::from_ref_time(70_648_878 as u64).saturating_mul(n as u64)) + // Minimum execution time: 390_339 nanoseconds. + Weight::from_ref_time(528_774_888 as u64) + // Standard Error: 1_278_188 + .saturating_add(Weight::from_ref_time(66_683_698 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(48 as u64)) @@ -1936,10 +1941,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - // Minimum execution time: 251_357 nanoseconds. - Weight::from_ref_time(220_533_580 as u64) - // Standard Error: 345_297 - .saturating_add(Weight::from_ref_time(349_413_968 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_904 nanoseconds. + Weight::from_ref_time(265_679_354 as u64) + // Standard Error: 386_673 + .saturating_add(Weight::from_ref_time(318_869_116 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1947,10 +1952,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 354_162 nanoseconds. - Weight::from_ref_time(472_811_575 as u64) - // Standard Error: 1_109_282 - .saturating_add(Weight::from_ref_time(154_074_386 as u64).saturating_mul(n as u64)) + // Minimum execution time: 372_784 nanoseconds. + Weight::from_ref_time(487_784_160 as u64) + // Standard Error: 1_092_850 + .saturating_add(Weight::from_ref_time(152_413_290 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1958,10 +1963,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - // Minimum execution time: 247_551 nanoseconds. - Weight::from_ref_time(219_176_526 as u64) - // Standard Error: 358_914 - .saturating_add(Weight::from_ref_time(326_009_513 as u64).saturating_mul(r as u64)) + // Minimum execution time: 301_191 nanoseconds. + Weight::from_ref_time(270_493_545 as u64) + // Standard Error: 373_565 + .saturating_add(Weight::from_ref_time(302_870_977 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1969,10 +1974,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 339_149 nanoseconds. - Weight::from_ref_time(440_615_016 as u64) - // Standard Error: 954_837 - .saturating_add(Weight::from_ref_time(66_153_533 as u64).saturating_mul(n as u64)) + // Minimum execution time: 368_641 nanoseconds. + Weight::from_ref_time(469_340_170 as u64) + // Standard Error: 966_589 + .saturating_add(Weight::from_ref_time(62_000_083 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1980,10 +1985,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - // Minimum execution time: 251_812 nanoseconds. - Weight::from_ref_time(209_954_069 as u64) - // Standard Error: 398_380 - .saturating_add(Weight::from_ref_time(438_573_954 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_717 nanoseconds. + Weight::from_ref_time(254_308_806 as u64) + // Standard Error: 443_802 + .saturating_add(Weight::from_ref_time(408_899_238 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -1992,10 +1997,10 @@ impl WeightInfo for () { // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 374_594 nanoseconds. - Weight::from_ref_time(525_213_792 as u64) - // Standard Error: 1_378_489 - .saturating_add(Weight::from_ref_time(161_599_623 as u64).saturating_mul(n as u64)) + // Minimum execution time: 396_211 nanoseconds. + Weight::from_ref_time(545_169_999 as u64) + // Standard Error: 1_390_049 + .saturating_add(Weight::from_ref_time(156_931_202 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(51 as u64)) .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(48 as u64)) @@ -2008,10 +2013,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - // Minimum execution time: 251_379 nanoseconds. - Weight::from_ref_time(204_214_298 as u64) - // Standard Error: 662_575 - .saturating_add(Weight::from_ref_time(1_366_716_853 as u64).saturating_mul(r as u64)) + // Minimum execution time: 295_145 nanoseconds. + Weight::from_ref_time(241_332_033 as u64) + // Standard Error: 658_837 + .saturating_add(Weight::from_ref_time(1_315_958_335 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -2024,10 +2029,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - // Minimum execution time: 252_896 nanoseconds. - Weight::from_ref_time(253_811_000 as u64) - // Standard Error: 6_576_179 - .saturating_add(Weight::from_ref_time(17_254_952_849 as u64).saturating_mul(r as u64)) + // Minimum execution time: 295_624 nanoseconds. + Weight::from_ref_time(296_567_000 as u64) + // Standard Error: 6_725_484 + .saturating_add(Weight::from_ref_time(20_773_662_959 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((160 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -2040,10 +2045,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - // Minimum execution time: 249_312 nanoseconds. - Weight::from_ref_time(253_806_000 as u64) - // Standard Error: 6_118_873 - .saturating_add(Weight::from_ref_time(17_081_370_212 as u64).saturating_mul(r as u64)) + // Minimum execution time: 296_698 nanoseconds. + Weight::from_ref_time(297_541_000 as u64) + // Standard Error: 18_681_855 + .saturating_add(Weight::from_ref_time(20_702_951_248 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((150 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -2057,12 +2062,12 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - // Minimum execution time: 12_001_522 nanoseconds. - Weight::from_ref_time(10_903_312_955 as u64) - // Standard Error: 4_301_096 - .saturating_add(Weight::from_ref_time(1_243_413_241 as u64).saturating_mul(t as u64)) - // Standard Error: 6_449 - .saturating_add(Weight::from_ref_time(9_713_655 as u64).saturating_mul(c as u64)) + // Minimum execution time: 9_491_225 nanoseconds. + Weight::from_ref_time(8_726_446_640 as u64) + // Standard Error: 11_723_053 + .saturating_add(Weight::from_ref_time(1_107_970_775 as u64).saturating_mul(t as u64)) + // Standard Error: 17_578 + .saturating_add(Weight::from_ref_time(9_748_009 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(167 as u64)) .saturating_add(RocksDbWeight::get().reads((81 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(163 as u64)) @@ -2077,10 +2082,10 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - // Minimum execution time: 254_969 nanoseconds. - Weight::from_ref_time(255_984_000 as u64) - // Standard Error: 18_545_048 - .saturating_add(Weight::from_ref_time(22_343_189_765 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_351 nanoseconds. + Weight::from_ref_time(297_837_000 as u64) + // Standard Error: 17_115_732 + .saturating_add(Weight::from_ref_time(25_936_348_025 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().reads((400 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(5 as u64)) @@ -2096,10 +2101,10 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - // Minimum execution time: 14_077_497 nanoseconds. - Weight::from_ref_time(13_949_740_588 as u64) - // Standard Error: 66_631 - .saturating_add(Weight::from_ref_time(120_519_572 as u64).saturating_mul(s as u64)) + // Minimum execution time: 11_367_191 nanoseconds. + Weight::from_ref_time(11_186_726_411 as u64) + // Standard Error: 75_273 + .saturating_add(Weight::from_ref_time(122_421_705 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(249 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(t as u64))) .saturating_add(RocksDbWeight::get().writes(247 as u64)) @@ -2112,10 +2117,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - // Minimum execution time: 247_445 nanoseconds. - Weight::from_ref_time(251_229_791 as u64) - // Standard Error: 88_045 - .saturating_add(Weight::from_ref_time(57_577_008 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_753 nanoseconds. + Weight::from_ref_time(295_491_471 as u64) + // Standard Error: 112_217 + .saturating_add(Weight::from_ref_time(41_976_228 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2126,10 +2131,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 308_069 nanoseconds. - Weight::from_ref_time(308_971_000 as u64) - // Standard Error: 46_181 - .saturating_add(Weight::from_ref_time(321_835_684 as u64).saturating_mul(n as u64)) + // Minimum execution time: 335_784 nanoseconds. + Weight::from_ref_time(336_406_000 as u64) + // Standard Error: 58_205 + .saturating_add(Weight::from_ref_time(323_644_833 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2140,10 +2145,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - // Minimum execution time: 247_107 nanoseconds. - Weight::from_ref_time(250_125_030 as u64) - // Standard Error: 88_769 - .saturating_add(Weight::from_ref_time(70_727_669 as u64).saturating_mul(r as u64)) + // Minimum execution time: 292_772 nanoseconds. + Weight::from_ref_time(294_845_565 as u64) + // Standard Error: 118_932 + .saturating_add(Weight::from_ref_time(53_186_034 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2154,10 +2159,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 319_515 nanoseconds. - Weight::from_ref_time(319_784_000 as u64) - // Standard Error: 58_896 - .saturating_add(Weight::from_ref_time(246_433_962 as u64).saturating_mul(n as u64)) + // Minimum execution time: 348_057 nanoseconds. + Weight::from_ref_time(354_903_000 as u64) + // Standard Error: 63_036 + .saturating_add(Weight::from_ref_time(247_852_636 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2168,10 +2173,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - // Minimum execution time: 247_887 nanoseconds. - Weight::from_ref_time(250_452_702 as u64) - // Standard Error: 140_887 - .saturating_add(Weight::from_ref_time(49_538_397 as u64).saturating_mul(r as u64)) + // Minimum execution time: 290_417 nanoseconds. + Weight::from_ref_time(295_285_706 as u64) + // Standard Error: 124_630 + .saturating_add(Weight::from_ref_time(31_293_293 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2182,10 +2187,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 297_534 nanoseconds. - Weight::from_ref_time(298_249_000 as u64) - // Standard Error: 49_680 - .saturating_add(Weight::from_ref_time(99_001_103 as u64).saturating_mul(n as u64)) + // Minimum execution time: 325_903 nanoseconds. + Weight::from_ref_time(326_482_000 as u64) + // Standard Error: 47_465 + .saturating_add(Weight::from_ref_time(99_615_769 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2196,10 +2201,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - // Minimum execution time: 245_926 nanoseconds. - Weight::from_ref_time(248_471_834 as u64) - // Standard Error: 101_639 - .saturating_add(Weight::from_ref_time(47_889_865 as u64).saturating_mul(r as u64)) + // Minimum execution time: 291_624 nanoseconds. + Weight::from_ref_time(295_781_938 as u64) + // Standard Error: 849_772 + .saturating_add(Weight::from_ref_time(30_869_061 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2210,10 +2215,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 294_835 nanoseconds. - Weight::from_ref_time(296_328_000 as u64) - // Standard Error: 46_612 - .saturating_add(Weight::from_ref_time(98_859_152 as u64).saturating_mul(n as u64)) + // Minimum execution time: 323_456 nanoseconds. + Weight::from_ref_time(324_815_000 as u64) + // Standard Error: 49_126 + .saturating_add(Weight::from_ref_time(99_651_878 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2224,10 +2229,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - // Minimum execution time: 251_104 nanoseconds. - Weight::from_ref_time(253_114_893 as u64) - // Standard Error: 316_740 - .saturating_add(Weight::from_ref_time(2_964_072_706 as u64).saturating_mul(r as u64)) + // Minimum execution time: 294_244 nanoseconds. + Weight::from_ref_time(296_117_277 as u64) + // Standard Error: 513_100 + .saturating_add(Weight::from_ref_time(3_005_168_422 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2238,10 +2243,10 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - // Minimum execution time: 250_048 nanoseconds. - Weight::from_ref_time(251_774_991 as u64) - // Standard Error: 115_294 - .saturating_add(Weight::from_ref_time(2_094_245_208 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_099 nanoseconds. + Weight::from_ref_time(295_349_591 as u64) + // Standard Error: 437_688 + .saturating_add(Weight::from_ref_time(2_079_472_608 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -2253,10 +2258,10 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 250_830 nanoseconds. - Weight::from_ref_time(251_477_000 as u64) - // Standard Error: 2_727_998 - .saturating_add(Weight::from_ref_time(1_390_149_283 as u64).saturating_mul(r as u64)) + // Minimum execution time: 293_692 nanoseconds. + Weight::from_ref_time(294_871_000 as u64) + // Standard Error: 2_737_018 + .saturating_add(Weight::from_ref_time(1_360_098_499 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((225 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(3 as u64)) @@ -2266,381 +2271,385 @@ impl WeightInfo for () { // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. - fn seal_reentrant_count(r: u32, ) -> Weight { - Weight::from_ref_time(304_709_000 as u64) - // Standard Error: 67_000 - .saturating_add(Weight::from_ref_time(15_411_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + fn seal_reentrance_count(r: u32, ) -> Weight { + // Minimum execution time: 295_570 nanoseconds. + Weight::from_ref_time(299_077_520 as u64) + // Standard Error: 23_516 + .saturating_add(Weight::from_ref_time(10_971_589 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { - Weight::from_ref_time(328_378_000 as u64) - // Standard Error: 137_000 - .saturating_add(Weight::from_ref_time(37_448_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 296_873 nanoseconds. + Weight::from_ref_time(336_309_706 as u64) + // Standard Error: 125_484 + .saturating_add(Weight::from_ref_time(25_321_948 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - // Minimum execution time: 69_022 nanoseconds. - Weight::from_ref_time(69_707_657 as u64) - // Standard Error: 8_674 - .saturating_add(Weight::from_ref_time(887_555 as u64).saturating_mul(r as u64)) + // Minimum execution time: 686 nanoseconds. + Weight::from_ref_time(895_726 as u64) + // Standard Error: 144 + .saturating_add(Weight::from_ref_time(344_525 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // Minimum execution time: 69_491 nanoseconds. - Weight::from_ref_time(70_354_670 as u64) - // Standard Error: 1_518 - .saturating_add(Weight::from_ref_time(2_758_912 as u64).saturating_mul(r as u64)) + // Minimum execution time: 780 nanoseconds. + Weight::from_ref_time(590_334 as u64) + // Standard Error: 10_839 + .saturating_add(Weight::from_ref_time(1_038_503 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // Minimum execution time: 69_156 nanoseconds. - Weight::from_ref_time(69_917_601 as u64) - // Standard Error: 1_970 - .saturating_add(Weight::from_ref_time(2_753_174 as u64).saturating_mul(r as u64)) + // Minimum execution time: 755 nanoseconds. + Weight::from_ref_time(1_139_912 as u64) + // Standard Error: 466 + .saturating_add(Weight::from_ref_time(881_780 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // Minimum execution time: 68_944 nanoseconds. - Weight::from_ref_time(69_727_961 as u64) - // Standard Error: 376 - .saturating_add(Weight::from_ref_time(2_356_996 as u64).saturating_mul(r as u64)) + // Minimum execution time: 670 nanoseconds. + Weight::from_ref_time(941_845 as u64) + // Standard Error: 227 + .saturating_add(Weight::from_ref_time(956_897 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // Minimum execution time: 68_971 nanoseconds. - Weight::from_ref_time(69_755_949 as u64) - // Standard Error: 543 - .saturating_add(Weight::from_ref_time(2_489_510 as u64).saturating_mul(r as u64)) + // Minimum execution time: 676 nanoseconds. + Weight::from_ref_time(600_675 as u64) + // Standard Error: 555 + .saturating_add(Weight::from_ref_time(1_294_447 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // Minimum execution time: 69_061 nanoseconds. - Weight::from_ref_time(69_625_000 as u64) - // Standard Error: 486 - .saturating_add(Weight::from_ref_time(1_431_684 as u64).saturating_mul(r as u64)) + // Minimum execution time: 680 nanoseconds. + Weight::from_ref_time(1_192_340 as u64) + // Standard Error: 897 + .saturating_add(Weight::from_ref_time(524_835 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // Minimum execution time: 69_058 nanoseconds. - Weight::from_ref_time(69_521_790 as u64) - // Standard Error: 892 - .saturating_add(Weight::from_ref_time(1_964_054 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(1_136_213 as u64) + // Standard Error: 1_137 + .saturating_add(Weight::from_ref_time(791_920 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // Minimum execution time: 69_020 nanoseconds. - Weight::from_ref_time(69_344_255 as u64) - // Standard Error: 1_408 - .saturating_add(Weight::from_ref_time(2_169_179 as u64).saturating_mul(r as u64)) + // Minimum execution time: 669 nanoseconds. + Weight::from_ref_time(491_588 as u64) + // Standard Error: 2_098 + .saturating_add(Weight::from_ref_time(1_078_017 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - // Minimum execution time: 72_366 nanoseconds. - Weight::from_ref_time(72_869_594 as u64) - // Standard Error: 73 - .saturating_add(Weight::from_ref_time(3_867 as u64).saturating_mul(e as u64)) + // Minimum execution time: 2_128 nanoseconds. + Weight::from_ref_time(2_565_932 as u64) + // Standard Error: 76 + .saturating_add(Weight::from_ref_time(4_830 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // Minimum execution time: 69_164 nanoseconds. - Weight::from_ref_time(70_269_099 as u64) - // Standard Error: 8_824 - .saturating_add(Weight::from_ref_time(6_594_634 as u64).saturating_mul(r as u64)) + // Minimum execution time: 665 nanoseconds. + Weight::from_ref_time(1_593_317 as u64) + // Standard Error: 2_288 + .saturating_add(Weight::from_ref_time(2_195_453 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // Minimum execution time: 83_348 nanoseconds. - Weight::from_ref_time(84_968_895 as u64) - // Standard Error: 6_305 - .saturating_add(Weight::from_ref_time(8_395_193 as u64).saturating_mul(r as u64)) + // Minimum execution time: 796 nanoseconds. + Weight::from_ref_time(1_816_603 as u64) + // Standard Error: 2_183 + .saturating_add(Weight::from_ref_time(2_808_821 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - // Minimum execution time: 92_358 nanoseconds. - Weight::from_ref_time(93_605_536 as u64) - // Standard Error: 2_019 - .saturating_add(Weight::from_ref_time(536_495 as u64).saturating_mul(p as u64)) + // Minimum execution time: 4_212 nanoseconds. + Weight::from_ref_time(5_097_891 as u64) + // Standard Error: 576 + .saturating_add(Weight::from_ref_time(180_948 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // Minimum execution time: 69_191 nanoseconds. - Weight::from_ref_time(70_407_702 as u64) - // Standard Error: 2_812 - .saturating_add(Weight::from_ref_time(901_706 as u64).saturating_mul(r as u64)) + // Minimum execution time: 1_412 nanoseconds. + Weight::from_ref_time(1_733_015 as u64) + // Standard Error: 215 + .saturating_add(Weight::from_ref_time(366_629 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // Minimum execution time: 69_230 nanoseconds. - Weight::from_ref_time(70_255_278 as u64) - // Standard Error: 1_284 - .saturating_add(Weight::from_ref_time(951_754 as u64).saturating_mul(r as u64)) + // Minimum execution time: 1_436 nanoseconds. + Weight::from_ref_time(1_772_333 as u64) + // Standard Error: 288 + .saturating_add(Weight::from_ref_time(380_886 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // Minimum execution time: 69_278 nanoseconds. - Weight::from_ref_time(70_089_139 as u64) - // Standard Error: 757 - .saturating_add(Weight::from_ref_time(1_369_185 as u64).saturating_mul(r as u64)) + // Minimum execution time: 1_408 nanoseconds. + Weight::from_ref_time(1_731_571 as u64) + // Standard Error: 334 + .saturating_add(Weight::from_ref_time(526_489 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // Minimum execution time: 72_047 nanoseconds. - Weight::from_ref_time(72_783_972 as u64) - // Standard Error: 837 - .saturating_add(Weight::from_ref_time(1_471_680 as u64).saturating_mul(r as u64)) + // Minimum execution time: 752 nanoseconds. + Weight::from_ref_time(1_118_170 as u64) + // Standard Error: 302 + .saturating_add(Weight::from_ref_time(809_371 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // Minimum execution time: 71_960 nanoseconds. - Weight::from_ref_time(72_745_981 as u64) - // Standard Error: 1_086 - .saturating_add(Weight::from_ref_time(1_537_741 as u64).saturating_mul(r as u64)) + // Minimum execution time: 770 nanoseconds. + Weight::from_ref_time(990_414 as u64) + // Standard Error: 331 + .saturating_add(Weight::from_ref_time(831_541 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // Minimum execution time: 69_221 nanoseconds. - Weight::from_ref_time(70_010_862 as u64) - // Standard Error: 1_845 - .saturating_add(Weight::from_ref_time(933_738 as u64).saturating_mul(r as u64)) + // Minimum execution time: 783 nanoseconds. + Weight::from_ref_time(992_847 as u64) + // Standard Error: 437 + .saturating_add(Weight::from_ref_time(695_374 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // Minimum execution time: 69_081 nanoseconds. - Weight::from_ref_time(71_015_495 as u64) - // Standard Error: 27_078 - .saturating_add(Weight::from_ref_time(183_899_704 as u64).saturating_mul(r as u64)) + // Minimum execution time: 664 nanoseconds. + Weight::from_ref_time(758_730 as u64) + // Standard Error: 5_030 + .saturating_add(Weight::from_ref_time(184_801_569 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // Minimum execution time: 70_589 nanoseconds. - Weight::from_ref_time(70_175_537 as u64) - // Standard Error: 1_355 - .saturating_add(Weight::from_ref_time(1_323_745 as u64).saturating_mul(r as u64)) + // Minimum execution time: 657 nanoseconds. + Weight::from_ref_time(941_928 as u64) + // Standard Error: 216 + .saturating_add(Weight::from_ref_time(506_159 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - // Minimum execution time: 69_083 nanoseconds. - Weight::from_ref_time(69_832_339 as u64) - // Standard Error: 818 - .saturating_add(Weight::from_ref_time(1_334_198 as u64).saturating_mul(r as u64)) + // Minimum execution time: 617 nanoseconds. + Weight::from_ref_time(1_009_437 as u64) + // Standard Error: 435 + .saturating_add(Weight::from_ref_time(512_427 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // Minimum execution time: 69_084 nanoseconds. - Weight::from_ref_time(69_802_701 as u64) - // Standard Error: 744 - .saturating_add(Weight::from_ref_time(1_334_601 as u64).saturating_mul(r as u64)) + // Minimum execution time: 663 nanoseconds. + Weight::from_ref_time(875_558 as u64) + // Standard Error: 394 + .saturating_add(Weight::from_ref_time(513_247 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // Minimum execution time: 69_052 nanoseconds. - Weight::from_ref_time(69_717_748 as u64) - // Standard Error: 571 - .saturating_add(Weight::from_ref_time(1_346_564 as u64).saturating_mul(r as u64)) + // Minimum execution time: 664 nanoseconds. + Weight::from_ref_time(891_913 as u64) + // Standard Error: 171 + .saturating_add(Weight::from_ref_time(523_595 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // Minimum execution time: 69_016 nanoseconds. - Weight::from_ref_time(69_793_413 as u64) - // Standard Error: 769 - .saturating_add(Weight::from_ref_time(1_317_502 as u64).saturating_mul(r as u64)) + // Minimum execution time: 638 nanoseconds. + Weight::from_ref_time(1_003_558 as u64) + // Standard Error: 471 + .saturating_add(Weight::from_ref_time(502_671 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // Minimum execution time: 69_043 nanoseconds. - Weight::from_ref_time(69_963_419 as u64) - // Standard Error: 1_117 - .saturating_add(Weight::from_ref_time(1_313_727 as u64).saturating_mul(r as u64)) + // Minimum execution time: 665 nanoseconds. + Weight::from_ref_time(892_435 as u64) + // Standard Error: 162 + .saturating_add(Weight::from_ref_time(504_300 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // Minimum execution time: 69_032 nanoseconds. - Weight::from_ref_time(69_727_577 as u64) - // Standard Error: 662 - .saturating_add(Weight::from_ref_time(1_331_088 as u64).saturating_mul(r as u64)) + // Minimum execution time: 626 nanoseconds. + Weight::from_ref_time(880_015 as u64) + // Standard Error: 229 + .saturating_add(Weight::from_ref_time(503_941 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // Minimum execution time: 69_097 nanoseconds. - Weight::from_ref_time(69_767_650 as u64) - // Standard Error: 2_056 - .saturating_add(Weight::from_ref_time(1_875_021 as u64).saturating_mul(r as u64)) + // Minimum execution time: 623 nanoseconds. + Weight::from_ref_time(893_955 as u64) + // Standard Error: 238 + .saturating_add(Weight::from_ref_time(731_619 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // Minimum execution time: 69_153 nanoseconds. - Weight::from_ref_time(69_906_946 as u64) - // Standard Error: 1_060 - .saturating_add(Weight::from_ref_time(1_867_154 as u64).saturating_mul(r as u64)) + // Minimum execution time: 661 nanoseconds. + Weight::from_ref_time(904_145 as u64) + // Standard Error: 210 + .saturating_add(Weight::from_ref_time(730_497 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // Minimum execution time: 70_380 nanoseconds. - Weight::from_ref_time(69_867_328 as u64) - // Standard Error: 778 - .saturating_add(Weight::from_ref_time(1_869_718 as u64).saturating_mul(r as u64)) + // Minimum execution time: 670 nanoseconds. + Weight::from_ref_time(910_832 as u64) + // Standard Error: 248 + .saturating_add(Weight::from_ref_time(738_960 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // Minimum execution time: 69_259 nanoseconds. - Weight::from_ref_time(69_695_407 as u64) - // Standard Error: 746 - .saturating_add(Weight::from_ref_time(1_874_772 as u64).saturating_mul(r as u64)) + // Minimum execution time: 600 nanoseconds. + Weight::from_ref_time(910_816 as u64) + // Standard Error: 257 + .saturating_add(Weight::from_ref_time(742_585 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // Minimum execution time: 68_986 nanoseconds. - Weight::from_ref_time(70_027_081 as u64) - // Standard Error: 1_401 - .saturating_add(Weight::from_ref_time(1_862_971 as u64).saturating_mul(r as u64)) + // Minimum execution time: 697 nanoseconds. + Weight::from_ref_time(937_672 as u64) + // Standard Error: 291 + .saturating_add(Weight::from_ref_time(746_511 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // Minimum execution time: 68_953 nanoseconds. - Weight::from_ref_time(69_798_073 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_871_888 as u64).saturating_mul(r as u64)) + // Minimum execution time: 651 nanoseconds. + Weight::from_ref_time(920_151 as u64) + // Standard Error: 185 + .saturating_add(Weight::from_ref_time(743_483 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // Minimum execution time: 68_909 nanoseconds. - Weight::from_ref_time(69_845_981 as u64) - // Standard Error: 775 - .saturating_add(Weight::from_ref_time(1_868_722 as u64).saturating_mul(r as u64)) + // Minimum execution time: 622 nanoseconds. + Weight::from_ref_time(914_571 as u64) + // Standard Error: 264 + .saturating_add(Weight::from_ref_time(733_935 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // Minimum execution time: 68_986 nanoseconds. - Weight::from_ref_time(69_683_189 as u64) - // Standard Error: 503 - .saturating_add(Weight::from_ref_time(1_884_715 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(914_243 as u64) + // Standard Error: 199 + .saturating_add(Weight::from_ref_time(738_786 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - // Minimum execution time: 69_230 nanoseconds. - Weight::from_ref_time(69_765_336 as u64) - // Standard Error: 2_060 - .saturating_add(Weight::from_ref_time(1_871_848 as u64).saturating_mul(r as u64)) + // Minimum execution time: 625 nanoseconds. + Weight::from_ref_time(1_144_724 as u64) + // Standard Error: 1_367 + .saturating_add(Weight::from_ref_time(729_921 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // Minimum execution time: 68_953 nanoseconds. - Weight::from_ref_time(69_828_265 as u64) - // Standard Error: 951 - .saturating_add(Weight::from_ref_time(1_868_596 as u64).saturating_mul(r as u64)) + // Minimum execution time: 643 nanoseconds. + Weight::from_ref_time(897_337 as u64) + // Standard Error: 162 + .saturating_add(Weight::from_ref_time(738_471 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // Minimum execution time: 69_078 nanoseconds. - Weight::from_ref_time(69_832_768 as u64) - // Standard Error: 894 - .saturating_add(Weight::from_ref_time(1_845_786 as u64).saturating_mul(r as u64)) + // Minimum execution time: 672 nanoseconds. + Weight::from_ref_time(921_395 as u64) + // Standard Error: 465 + .saturating_add(Weight::from_ref_time(719_508 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // Minimum execution time: 68_939 nanoseconds. - Weight::from_ref_time(69_676_256 as u64) - // Standard Error: 374 - .saturating_add(Weight::from_ref_time(1_851_026 as u64).saturating_mul(r as u64)) + // Minimum execution time: 672 nanoseconds. + Weight::from_ref_time(889_319 as u64) + // Standard Error: 392 + .saturating_add(Weight::from_ref_time(714_186 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // Minimum execution time: 69_096 nanoseconds. - Weight::from_ref_time(69_914_159 as u64) - // Standard Error: 1_265 - .saturating_add(Weight::from_ref_time(1_844_489 as u64).saturating_mul(r as u64)) + // Minimum execution time: 660 nanoseconds. + Weight::from_ref_time(898_856 as u64) + // Standard Error: 189 + .saturating_add(Weight::from_ref_time(714_302 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // Minimum execution time: 68_939 nanoseconds. - Weight::from_ref_time(69_641_768 as u64) - // Standard Error: 347 - .saturating_add(Weight::from_ref_time(2_488_628 as u64).saturating_mul(r as u64)) + // Minimum execution time: 629 nanoseconds. + Weight::from_ref_time(902_499 as u64) + // Standard Error: 428 + .saturating_add(Weight::from_ref_time(1_346_772 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // Minimum execution time: 69_114 nanoseconds. - Weight::from_ref_time(69_844_395 as u64) - // Standard Error: 1_489 - .saturating_add(Weight::from_ref_time(2_456_310 as u64).saturating_mul(r as u64)) + // Minimum execution time: 624 nanoseconds. + Weight::from_ref_time(944_381 as u64) + // Standard Error: 389 + .saturating_add(Weight::from_ref_time(1_281_605 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // Minimum execution time: 69_082 nanoseconds. - Weight::from_ref_time(69_993_662 as u64) - // Standard Error: 1_218 - .saturating_add(Weight::from_ref_time(2_524_010 as u64).saturating_mul(r as u64)) + // Minimum execution time: 667 nanoseconds. + Weight::from_ref_time(876_301 as u64) + // Standard Error: 589 + .saturating_add(Weight::from_ref_time(1_397_964 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // Minimum execution time: 69_036 nanoseconds. - Weight::from_ref_time(70_095_304 as u64) - // Standard Error: 1_473 - .saturating_add(Weight::from_ref_time(2_429_659 as u64).saturating_mul(r as u64)) + // Minimum execution time: 611 nanoseconds. + Weight::from_ref_time(865_466 as u64) + // Standard Error: 253 + .saturating_add(Weight::from_ref_time(1_283_803 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // Minimum execution time: 69_229 nanoseconds. - Weight::from_ref_time(69_759_818 as u64) - // Standard Error: 573 - .saturating_add(Weight::from_ref_time(1_879_670 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(882_010 as u64) + // Standard Error: 205 + .saturating_add(Weight::from_ref_time(731_251 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // Minimum execution time: 69_151 nanoseconds. - Weight::from_ref_time(69_865_948 as u64) - // Standard Error: 721 - .saturating_add(Weight::from_ref_time(1_846_734 as u64).saturating_mul(r as u64)) + // Minimum execution time: 638 nanoseconds. + Weight::from_ref_time(917_858 as u64) + // Standard Error: 249 + .saturating_add(Weight::from_ref_time(795_023 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // Minimum execution time: 69_120 nanoseconds. - Weight::from_ref_time(70_135_849 as u64) - // Standard Error: 3_443 - .saturating_add(Weight::from_ref_time(1_841_784 as u64).saturating_mul(r as u64)) + // Minimum execution time: 636 nanoseconds. + Weight::from_ref_time(892_650 as u64) + // Standard Error: 252 + .saturating_add(Weight::from_ref_time(729_337 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // Minimum execution time: 69_077 nanoseconds. - Weight::from_ref_time(69_929_746 as u64) - // Standard Error: 821 - .saturating_add(Weight::from_ref_time(1_866_348 as u64).saturating_mul(r as u64)) + // Minimum execution time: 648 nanoseconds. + Weight::from_ref_time(918_889 as u64) + // Standard Error: 1_079 + .saturating_add(Weight::from_ref_time(746_835 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // Minimum execution time: 69_226 nanoseconds. - Weight::from_ref_time(69_725_630 as u64) - // Standard Error: 891 - .saturating_add(Weight::from_ref_time(1_873_637 as u64).saturating_mul(r as u64)) + // Minimum execution time: 677 nanoseconds. + Weight::from_ref_time(931_684 as u64) + // Standard Error: 259 + .saturating_add(Weight::from_ref_time(734_540 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // Minimum execution time: 70_591 nanoseconds. - Weight::from_ref_time(69_939_773 as u64) - // Standard Error: 960 - .saturating_add(Weight::from_ref_time(1_867_208 as u64).saturating_mul(r as u64)) + // Minimum execution time: 635 nanoseconds. + Weight::from_ref_time(914_996 as u64) + // Standard Error: 611 + .saturating_add(Weight::from_ref_time(735_020 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // Minimum execution time: 69_187 nanoseconds. - Weight::from_ref_time(69_845_516 as u64) - // Standard Error: 781 - .saturating_add(Weight::from_ref_time(1_869_613 as u64).saturating_mul(r as u64)) + // Minimum execution time: 663 nanoseconds. + Weight::from_ref_time(914_333 as u64) + // Standard Error: 169 + .saturating_add(Weight::from_ref_time(734_033 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // Minimum execution time: 69_065 nanoseconds. - Weight::from_ref_time(69_950_430 as u64) - // Standard Error: 986 - .saturating_add(Weight::from_ref_time(1_867_001 as u64).saturating_mul(r as u64)) + // Minimum execution time: 631 nanoseconds. + Weight::from_ref_time(916_503 as u64) + // Standard Error: 224 + .saturating_add(Weight::from_ref_time(736_168 as u64).saturating_mul(r as u64)) } -} \ No newline at end of file +} From d1221692968b8bc62d6eab9d10cb6b5bf38c5dc2 Mon Sep 17 00:00:00 2001 From: benluelo <57334811+benluelo@users.noreply.github.com> Date: Fri, 25 Nov 2022 05:11:19 -0500 Subject: [PATCH 1406/1472] update DefaultNoBound derive macro (#12723) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix derive for empty enums Update derive & ui tests clean up Apply suggestions from code review Co-authored-by: Bastian Köcher rename variable formatting & clippy formatting Co-authored-by: parity-processbot <> --- .../procedural/src/default_no_bound.rs | 174 ++++++++++++------ frame/support/procedural/src/lib.rs | 2 +- frame/support/src/lib.rs | 13 +- frame/support/test/tests/derive_no_bound.rs | 39 +++- .../derive_no_bound_ui/default_empty_enum.rs | 4 + .../default_empty_enum.stderr | 5 + .../default_no_attribute.rs | 11 ++ .../default_no_attribute.stderr | 5 + .../default_too_many_attributes.rs | 13 ++ .../default_too_many_attributes.stderr | 21 +++ .../tests/derive_no_bound_ui/default_union.rs | 7 + .../derive_no_bound_ui/default_union.stderr | 5 + .../asset-tx-payment/src/lib.rs | 1 + 13 files changed, 237 insertions(+), 63 deletions(-) create mode 100644 frame/support/test/tests/derive_no_bound_ui/default_empty_enum.rs create mode 100644 frame/support/test/tests/derive_no_bound_ui/default_empty_enum.stderr create mode 100644 frame/support/test/tests/derive_no_bound_ui/default_no_attribute.rs create mode 100644 frame/support/test/tests/derive_no_bound_ui/default_no_attribute.stderr create mode 100644 frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.rs create mode 100644 frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.stderr create mode 100644 frame/support/test/tests/derive_no_bound_ui/default_union.rs create mode 100644 frame/support/test/tests/derive_no_bound_ui/default_union.stderr diff --git a/frame/support/procedural/src/default_no_bound.rs b/frame/support/procedural/src/default_no_bound.rs index 192be0786d96b..b174a49e91741 100644 --- a/frame/support/procedural/src/default_no_bound.rs +++ b/frame/support/procedural/src/default_no_bound.rs @@ -15,82 +15,142 @@ // See the License for the specific language governing permissions and // limitations under the License. -use syn::spanned::Spanned; +use proc_macro2::Span; +use quote::{quote, quote_spanned}; +use syn::{spanned::Spanned, Data, DeriveInput, Fields}; -/// Derive Clone but do not bound any generic. +/// Derive Default but do not bound any generic. pub fn derive_default_no_bound(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input: syn::DeriveInput = match syn::parse(input) { - Ok(input) => input, - Err(e) => return e.to_compile_error().into(), - }; + let input = syn::parse_macro_input!(input as DeriveInput); let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let impl_ = match input.data { - syn::Data::Struct(struct_) => match struct_.fields { - syn::Fields::Named(named) => { - let fields = named.named.iter().map(|i| &i.ident).map(|i| { - quote::quote_spanned!(i.span() => - #i: core::default::Default::default() - ) + Data::Struct(struct_) => match struct_.fields { + Fields::Named(named) => { + let fields = named.named.iter().map(|field| &field.ident).map(|ident| { + quote_spanned! {ident.span() => + #ident: core::default::Default::default() + } }); - quote::quote!( Self { #( #fields, )* } ) + quote!(Self { #( #fields, )* }) }, - syn::Fields::Unnamed(unnamed) => { - let fields = - unnamed.unnamed.iter().enumerate().map(|(i, _)| syn::Index::from(i)).map(|i| { - quote::quote_spanned!(i.span() => - core::default::Default::default() - ) - }); - - quote::quote!( Self ( #( #fields, )* ) ) + Fields::Unnamed(unnamed) => { + let fields = unnamed.unnamed.iter().map(|field| { + quote_spanned! {field.span()=> + core::default::Default::default() + } + }); + + quote!(Self( #( #fields, )* )) }, - syn::Fields::Unit => { - quote::quote!(Self) + Fields::Unit => { + quote!(Self) }, }, - syn::Data::Enum(enum_) => - if let Some(first_variant) = enum_.variants.first() { - let variant_ident = &first_variant.ident; - match &first_variant.fields { - syn::Fields::Named(named) => { - let fields = named.named.iter().map(|i| &i.ident).map(|i| { - quote::quote_spanned!(i.span() => - #i: core::default::Default::default() - ) - }); - - quote::quote!( #name :: #ty_generics :: #variant_ident { #( #fields, )* } ) - }, - syn::Fields::Unnamed(unnamed) => { - let fields = unnamed - .unnamed - .iter() - .enumerate() - .map(|(i, _)| syn::Index::from(i)) - .map(|i| { - quote::quote_spanned!(i.span() => + Data::Enum(enum_) => { + if enum_.variants.is_empty() { + return syn::Error::new_spanned(name, "cannot derive Default for an empty enum") + .to_compile_error() + .into() + } + + // all #[default] attrs with the variant they're on; i.e. a var + let default_variants = enum_ + .variants + .into_iter() + .filter(|variant| variant.attrs.iter().any(|attr| attr.path.is_ident("default"))) + .collect::>(); + + match &*default_variants { + [] => { + return syn::Error::new( + name.clone().span(), + // writing this as a regular string breaks rustfmt for some reason + r#"no default declared, make a variant default by placing `#[default]` above it"#, + ) + .into_compile_error() + .into() + }, + // only one variant with the #[default] attribute set + [default_variant] => { + let variant_attrs = default_variant + .attrs + .iter() + .filter(|a| a.path.is_ident("default")) + .collect::>(); + + // check that there is only one #[default] attribute on the variant + if let [first_attr, second_attr, additional_attrs @ ..] = &*variant_attrs { + let mut err = + syn::Error::new(Span::call_site(), "multiple `#[default]` attributes"); + + err.combine(syn::Error::new_spanned(first_attr, "`#[default]` used here")); + + err.extend([second_attr].into_iter().chain(additional_attrs).map( + |variant| { + syn::Error::new_spanned(variant, "`#[default]` used again here") + }, + )); + + return err.into_compile_error().into() + } + + let variant_ident = &default_variant.ident; + + let fully_qualified_variant_path = quote!(Self::#variant_ident); + + match &default_variant.fields { + Fields::Named(named) => { + let fields = + named.named.iter().map(|field| &field.ident).map(|ident| { + quote_spanned! {ident.span()=> + #ident: core::default::Default::default() + } + }); + + quote!(#fully_qualified_variant_path { #( #fields, )* }) + }, + Fields::Unnamed(unnamed) => { + let fields = unnamed.unnamed.iter().map(|field| { + quote_spanned! {field.span()=> core::default::Default::default() - ) + } }); - quote::quote!( #name :: #ty_generics :: #variant_ident ( #( #fields, )* ) ) - }, - syn::Fields::Unit => quote::quote!( #name :: #ty_generics :: #variant_ident ), - } - } else { - quote::quote!(Self) - }, - syn::Data::Union(_) => { - let msg = "Union type not supported by `derive(CloneNoBound)`"; - return syn::Error::new(input.span(), msg).to_compile_error().into() + quote!(#fully_qualified_variant_path( #( #fields, )* )) + }, + Fields::Unit => fully_qualified_variant_path, + } + }, + [first, additional @ ..] => { + let mut err = syn::Error::new(Span::call_site(), "multiple declared defaults"); + + err.combine(syn::Error::new_spanned(first, "first default")); + + err.extend( + additional + .into_iter() + .map(|variant| syn::Error::new_spanned(variant, "additional default")), + ); + + return err.into_compile_error().into() + }, + } }, + Data::Union(union_) => + return syn::Error::new_spanned( + union_.union_token, + "Union type not supported by `derive(DefaultNoBound)`", + ) + .to_compile_error() + .into(), }; - quote::quote!( + quote!( const _: () = { impl #impl_generics core::default::Default for #name #ty_generics #where_clause { fn default() -> Self { diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index cd30946ae7855..41dbc4ee9592c 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -582,7 +582,7 @@ pub fn derive_eq_no_bound(input: TokenStream) -> TokenStream { } /// derive `Default` but do no bound any generic. Docs are at `frame_support::DefaultNoBound`. -#[proc_macro_derive(DefaultNoBound)] +#[proc_macro_derive(DefaultNoBound, attributes(default))] pub fn derive_default_no_bound(input: TokenStream) -> TokenStream { default_no_bound::derive_default_no_bound(input) } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 84e416e50544d..efecbb75f9c62 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -621,14 +621,23 @@ pub use frame_support_procedural::DebugNoBound; /// # use frame_support::DefaultNoBound; /// # use core::default::Default; /// trait Config { -/// type C: Default; +/// type C: Default; /// } /// /// // Foo implements [`Default`] because `C` bounds [`Default`]. /// // Otherwise compilation will fail with an output telling `c` doesn't implement [`Default`]. /// #[derive(DefaultNoBound)] /// struct Foo { -/// c: T::C, +/// c: T::C, +/// } +/// +/// // Also works with enums, by specifying the default with #[default]: +/// #[derive(DefaultNoBound)] +/// enum Bar { +/// // Bar will implement Default as long as all of the types within Baz also implement default. +/// #[default] +/// Baz(T::C), +/// Quxx, /// } /// ``` pub use frame_support_procedural::DefaultNoBound; diff --git a/frame/support/test/tests/derive_no_bound.rs b/frame/support/test/tests/derive_no_bound.rs index e1cf539f2ac58..f891b3a2d2db8 100644 --- a/frame/support/test/tests/derive_no_bound.rs +++ b/frame/support/test/tests/derive_no_bound.rs @@ -110,10 +110,33 @@ fn test_struct_unnamed() { assert!(b != a_1); } +#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] +struct StructNoGenerics { + field1: u32, + field2: u64, +} + +#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] +enum EnumNoGenerics { + #[default] + VariantUnnamed(u32, u64), + VariantNamed { + a: u32, + b: u64, + }, + VariantUnit, +} + #[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] enum Enum { + #[default] VariantUnnamed(u32, u64, T::C, core::marker::PhantomData<(U, V)>), - VariantNamed { a: u32, b: u64, c: T::C, phantom: core::marker::PhantomData<(U, V)> }, + VariantNamed { + a: u32, + b: u64, + c: T::C, + phantom: core::marker::PhantomData<(U, V)>, + }, VariantUnit, VariantUnit2, } @@ -121,7 +144,12 @@ enum Enum { // enum that will have a named default. #[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] enum Enum2 { - VariantNamed { a: u32, b: u64, c: T::C }, + #[default] + VariantNamed { + a: u32, + b: u64, + c: T::C, + }, VariantUnnamed(u32, u64, T::C), VariantUnit, VariantUnit2, @@ -130,8 +158,13 @@ enum Enum2 { // enum that will have a unit default. #[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] enum Enum3 { + #[default] VariantUnit, - VariantNamed { a: u32, b: u64, c: T::C }, + VariantNamed { + a: u32, + b: u64, + c: T::C, + }, VariantUnnamed(u32, u64, T::C), VariantUnit2, } diff --git a/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.rs b/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.rs new file mode 100644 index 0000000000000..51b6137c00755 --- /dev/null +++ b/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.rs @@ -0,0 +1,4 @@ +#[derive(frame_support::DefaultNoBound)] +enum Empty {} + +fn main() {} diff --git a/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.stderr b/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.stderr new file mode 100644 index 0000000000000..9c93b515adce5 --- /dev/null +++ b/frame/support/test/tests/derive_no_bound_ui/default_empty_enum.stderr @@ -0,0 +1,5 @@ +error: cannot derive Default for an empty enum + --> tests/derive_no_bound_ui/default_empty_enum.rs:2:6 + | +2 | enum Empty {} + | ^^^^^ diff --git a/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.rs b/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.rs new file mode 100644 index 0000000000000..185df01fe2b84 --- /dev/null +++ b/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.rs @@ -0,0 +1,11 @@ +trait Config { + type C; +} + +#[derive(frame_support::DefaultNoBound)] +enum Foo { + Bar(T::C), + Baz, +} + +fn main() {} diff --git a/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.stderr b/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.stderr new file mode 100644 index 0000000000000..12e0023671587 --- /dev/null +++ b/frame/support/test/tests/derive_no_bound_ui/default_no_attribute.stderr @@ -0,0 +1,5 @@ +error: no default declared, make a variant default by placing `#[default]` above it + --> tests/derive_no_bound_ui/default_no_attribute.rs:6:6 + | +6 | enum Foo { + | ^^^ diff --git a/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.rs b/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.rs new file mode 100644 index 0000000000000..c3d175da6c056 --- /dev/null +++ b/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.rs @@ -0,0 +1,13 @@ +trait Config { + type C; +} + +#[derive(frame_support::DefaultNoBound)] +enum Foo { + #[default] + Bar(T::C), + #[default] + Baz, +} + +fn main() {} diff --git a/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.stderr b/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.stderr new file mode 100644 index 0000000000000..5430ef142c5c8 --- /dev/null +++ b/frame/support/test/tests/derive_no_bound_ui/default_too_many_attributes.stderr @@ -0,0 +1,21 @@ +error: multiple declared defaults + --> tests/derive_no_bound_ui/default_too_many_attributes.rs:5:10 + | +5 | #[derive(frame_support::DefaultNoBound)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `frame_support::DefaultNoBound` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: first default + --> tests/derive_no_bound_ui/default_too_many_attributes.rs:7:2 + | +7 | / #[default] +8 | | Bar(T::C), + | |_____________^ + +error: additional default + --> tests/derive_no_bound_ui/default_too_many_attributes.rs:9:2 + | +9 | / #[default] +10 | | Baz, + | |_______^ diff --git a/frame/support/test/tests/derive_no_bound_ui/default_union.rs b/frame/support/test/tests/derive_no_bound_ui/default_union.rs new file mode 100644 index 0000000000000..5822cda1aa64d --- /dev/null +++ b/frame/support/test/tests/derive_no_bound_ui/default_union.rs @@ -0,0 +1,7 @@ +#[derive(frame_support::DefaultNoBound)] +union Foo { + field1: u32, + field2: (), +} + +fn main() {} diff --git a/frame/support/test/tests/derive_no_bound_ui/default_union.stderr b/frame/support/test/tests/derive_no_bound_ui/default_union.stderr new file mode 100644 index 0000000000000..1e01e1baaf8ac --- /dev/null +++ b/frame/support/test/tests/derive_no_bound_ui/default_union.stderr @@ -0,0 +1,5 @@ +error: Union type not supported by `derive(DefaultNoBound)` + --> tests/derive_no_bound_ui/default_union.rs:2:1 + | +2 | union Foo { + | ^^^^^ diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index e136da8b0bb75..43cc1efa0858e 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -97,6 +97,7 @@ pub(crate) type ChargeAssetLiquidityOf = #[derive(Encode, Decode, DefaultNoBound, TypeInfo)] pub enum InitialPayment { /// No initial fee was payed. + #[default] Nothing, /// The initial fee was payed in the native currency. Native(LiquidityInfoOf), From ab6142f7670e41084e51651874f14406b5f88732 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 25 Nov 2022 15:13:38 +0100 Subject: [PATCH 1407/1472] Fix rustdoc (#12777) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix table formatting Signed-off-by: Oliver Tale-Yazdi * Fix sp-runtime-interface table Using HTML now since multi-line tables are not a thing and fmt destroys them. Signed-off-by: Oliver Tale-Yazdi * More rustdoc fixes Signed-off-by: Oliver Tale-Yazdi * Fix tags Signed-off-by: Oliver Tale-Yazdi * More fixes... Signed-off-by: Oliver Tale-Yazdi * Use Bastis patch Co-authored-by: Bastian Köcher Signed-off-by: Oliver Tale-Yazdi * Add more backticks Signed-off-by: Oliver Tale-Yazdi * change ci image Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher Co-authored-by: alvicsam --- .gitlab-ci.yml | 3 ++- client/cli/src/params/shared_params.rs | 6 +++--- frame/node-authorization/src/lib.rs | 2 +- primitives/runtime-interface/src/lib.rs | 18 ++++++++++-------- .../runtime-interface/test-wasm/src/lib.rs | 2 +- utils/frame/rpc/support/src/lib.rs | 2 +- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8519d0f88fc7c..d5b8cc89037a7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,7 +47,8 @@ variables: CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux:production" + # staging image with rust 1.65 and nightly-2022-11-16 + CI_IMAGE: "paritytech/ci-linux@sha256:786869e731963b3cc0a4aa9deb83367ed9e87a6ae48b6eb029d62b0cab4d87c1" BUILDAH_IMAGE: "quay.io/buildah/stable:v1.27" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 6c03ac2c4ec23..5cbb6dbad54a3 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -42,10 +42,10 @@ pub struct SharedParams { #[arg(long, short = 'd', value_name = "PATH")] pub base_path: Option, - /// Sets a custom logging filter. Syntax is =, e.g. -lsync=debug. + /// Sets a custom logging filter. Syntax is `=`, e.g. -lsync=debug. /// /// Log levels (least to most verbose) are error, warn, info, debug, and trace. - /// By default, all targets log `info`. The global log level can be set with -l. + /// By default, all targets log `info`. The global log level can be set with `-l`. #[arg(short = 'l', long, value_name = "LOG_PATTERN", num_args = 1..)] pub log: Vec, @@ -71,7 +71,7 @@ pub struct SharedParams { #[arg(long)] pub enable_log_reloading: bool, - /// Sets a custom profiling filter. Syntax is the same as for logging: = + /// Sets a custom profiling filter. Syntax is the same as for logging: `=`. #[arg(long, value_name = "TARGETS")] pub tracing_targets: Option, diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 638a96eb3321a..bd1b14d10b013 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -18,7 +18,7 @@ //! # Node authorization pallet //! //! This pallet manages a configurable set of nodes for a permissioned network. -//! Each node is dentified by a PeerId (i.e. Vec). It provides two ways to +//! Each node is dentified by a PeerId (i.e. `Vec`). It provides two ways to //! authorize a node, //! //! - a set of well known nodes across different organizations in which the diff --git a/primitives/runtime-interface/src/lib.rs b/primitives/runtime-interface/src/lib.rs index 6ebcb7482a779..975d7158b8dcd 100644 --- a/primitives/runtime-interface/src/lib.rs +++ b/primitives/runtime-interface/src/lib.rs @@ -15,6 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Custom inner attributes are unstable, so we need to faky disable the attribute. +// rustfmt still honors the attribute to not format the rustdocs below. +#![cfg_attr(feature = "never", rustfmt::skip)] //! Substrate runtime interface //! //! This crate provides types, traits and macros around runtime interfaces. A runtime interface is @@ -94,14 +97,13 @@ //! | `&str` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | //! | `&[u8]` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | //! | `Vec` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | -//! | `Vec where T: Encode` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 -//! | e.as_ptr() 32bit | | `&[T] where T: Encode` | `u64` | `let e = -//! v.encode();`

e.len() 32bit << 32 | e.as_ptr() 32bit | | `[u8; N]` | -//! `u32` | `v.as_ptr()` | | `*const T` | `u32` | `Identity` | -//! | `Option` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 | e.as_ptr() -//! 32bit | | [`T where T: PassBy`](./pass_by#Inner) | Depends on inner | -//! Depends on inner | | [`T where T: PassBy`](./pass_by#Codec)|`u64`|v.len() -//! 32bit << 32 |v.as_ptr() 32bit| +//! | `Vec where T: Encode` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 | e.as_ptr() 32bit | +//! | `&[T] where T: Encode` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 | e.as_ptr() 32bit | +//! | `[u8; N]` | `u32` | `v.as_ptr()` | +//! | `*const T` | `u32` | `Identity` | +//! | `Option` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 | e.as_ptr() 32bit | +//! | [`T where T: PassBy`](./pass_by#Inner) | Depends on inner | Depends on inner | +//! | [`T where T: PassBy`](./pass_by#Codec)|`u64`|v.len() 32bit << 32 |v.as_ptr() 32bit| //! //! `Identity` means that the value is converted directly into the corresponding FFI type. diff --git a/primitives/runtime-interface/test-wasm/src/lib.rs b/primitives/runtime-interface/test-wasm/src/lib.rs index 1305aef66cacc..3720735ac773b 100644 --- a/primitives/runtime-interface/test-wasm/src/lib.rs +++ b/primitives/runtime-interface/test-wasm/src/lib.rs @@ -54,7 +54,7 @@ pub trait TestApi { /// # Note /// /// We return a `Vec` because this will use the code path that uses SCALE - /// to pass the data between native/wasm. (Vec is passed without encoding the + /// to pass the data between native/wasm. (`Vec` is passed without encoding the /// data) fn return_16kb() -> Vec { vec![0; 4 * 1024] diff --git a/utils/frame/rpc/support/src/lib.rs b/utils/frame/rpc/support/src/lib.rs index fdf6fe0be8172..a13d4f707797d 100644 --- a/utils/frame/rpc/support/src/lib.rs +++ b/utils/frame/rpc/support/src/lib.rs @@ -164,7 +164,7 @@ impl StorageQuery { /// Send this query over RPC, await the typed result. /// - /// Hash should be ::Hash. + /// Hash should be `::Hash`. /// /// # Arguments /// From 3e9182366f31ee93473a43d2afedf1357e2df7a8 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Fri, 25 Nov 2022 15:52:26 +0100 Subject: [PATCH 1408/1472] Allow Alliance Fellows to Give Up Voting Rights (#12730) * allow fellows to abdicate voting rights * rename founders to founding fellows, give equal power * Drop FoundingFellow role and veto call (#12762) * drop FoundingFellow role * drop veto call * Storage migration to remove founder role (#12766) * storage migration to remove founder role * skip migration if no members * truncate the final fellows set if overflows * change log - action order * MemberAbdicated -> FellowAbdicated Co-authored-by: Muharem Ismailov --- bin/node/runtime/src/impls.rs | 4 - bin/node/runtime/src/lib.rs | 4 +- frame/alliance/README.md | 34 +- frame/alliance/src/benchmarking.rs | 192 +++------- frame/alliance/src/lib.rs | 269 +++++--------- frame/alliance/src/migration.rs | 102 +++++- frame/alliance/src/mock.rs | 50 ++- frame/alliance/src/tests.rs | 174 ++++----- frame/alliance/src/types.rs | 8 +- frame/alliance/src/weights.rs | 552 ++++++++++++++--------------- 10 files changed, 614 insertions(+), 775 deletions(-) diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 0a5c797ba729f..b3f58ea5d24ab 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -97,10 +97,6 @@ impl ProposalProvider for AllianceProposalProvider AllianceMotion::do_vote(who, proposal, index, approve) } - fn veto_proposal(proposal_hash: Hash) -> u32 { - AllianceMotion::do_disapprove_proposal(proposal_hash) - } - fn close_proposal( proposal_hash: Hash, proposal_index: ProposalIndex, diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index cff33e0918981..88b0687c76b02 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1574,8 +1574,7 @@ impl pallet_collective::Config for Runtime { } parameter_types! { - pub const MaxFounders: u32 = 10; - pub const MaxFellows: u32 = AllianceMaxMembers::get() - MaxFounders::get(); + pub const MaxFellows: u32 = AllianceMaxMembers::get(); pub const MaxAllies: u32 = 100; pub const AllyDeposit: Balance = 10 * DOLLARS; pub const RetirementPeriod: BlockNumber = ALLIANCE_MOTION_DURATION_IN_BLOCKS + (1 * DAYS); @@ -1606,7 +1605,6 @@ impl pallet_alliance::Config for Runtime { type IdentityVerifier = (); type ProposalProvider = AllianceProposalProvider; type MaxProposals = AllianceMaxProposals; - type MaxFounders = MaxFounders; type MaxFellows = MaxFellows; type MaxAllies = MaxAllies; type MaxUnscrupulousItems = ConstU32<100>; diff --git a/frame/alliance/README.md b/frame/alliance/README.md index dff9e0a47aa2c..9930008e2d635 100644 --- a/frame/alliance/README.md +++ b/frame/alliance/README.md @@ -1,7 +1,7 @@ # Alliance Pallet The Alliance Pallet provides a collective that curates a list of accounts and URLs, deemed by -the voting members to be unscrupulous actors. The alliance +the voting members to be unscrupulous actors. The Alliance - provides a set of ethics against bad behavior, and - provides recognition and influence for those teams that contribute something back to the @@ -19,19 +19,17 @@ to update the Alliance's rule and make announcements. ### Terminology - Rule: The IPFS CID (hash) of the Alliance rules for the community to read and the Alliance - members to enforce. Similar to a Code of Conduct. + members to enforce. Similar to a Charter or Code of Conduct. - Announcement: An IPFS CID of some content that the Alliance want to announce. - Member: An account that is already in the group of the Alliance, including three types: - Founder, Fellow, or Ally. A member can also be kicked by the `MembershipManager` origin or - retire by itself. -- Founder: An account who is initiated by Root with normal voting rights for basic motions and - special veto rights for rule change and Ally elevation motions. -- Fellow: An account who is elevated from Ally by Founders and other Fellows. -- Ally: An account who would like to join the alliance. To become a voting member, Fellow or - Founder, it will need approval from the `MembershipManager` origin. Any account can join as an - Ally either by placing a deposit or by nomination from a voting member. -- Unscrupulous List: A list of bad websites and addresses, items can be added or removed by - Founders and Fellows. + Fellow, or Ally. A member can also be kicked by the `MembershipManager` origin + or retire by itself. +- Fellow: An account who is elevated from Ally by other Fellows. +- Ally: An account who would like to join the Alliance. To become a voting member (Fellow), it + will need approval from the `MembershipManager` origin. Any account can join as an Ally either + by placing a deposit or by nomination from a voting member. +- Unscrupulous List: A list of bad websites and addresses; items can be added or removed by + voting members. ## Interface @@ -43,10 +41,11 @@ to update the Alliance's rule and make announcements. #### For Members (All) -- `give_retirement_notice` - Give a retirement notice and start a retirement period required to pass in order to retire. +- `give_retirement_notice` - Give a retirement notice and start a retirement period required to + pass in order to retire. - `retire` - Retire from the Alliance and release the caller's deposit. -#### For Members (Founders/Fellows) +#### For Voting Members - `propose` - Propose a motion. - `vote` - Vote on a motion. @@ -59,12 +58,9 @@ to update the Alliance's rule and make announcements. - `add_unscrupulous_items` - Add some items, either accounts or websites, to the list of unscrupulous items. - `remove_unscrupulous_items` - Remove some items from the list of unscrupulous items. - -#### For Members (Only Founders) - -- `veto` - Veto on a motion about `set_rule` and `elevate_ally`. +- `abdicate_fellow_status` - Abdicate one's voting rights, demoting themself to Ally. #### Root Calls -- `init_members` - Initialize the Alliance, onboard founders, fellows, and allies. +- `init_members` - Initialize the Alliance, onboard fellows and allies. - `disband` - Disband the Alliance, remove all active members and unreserve deposits. diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index e2e1579fcc9b4..a34b76bd96ece 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -61,10 +61,6 @@ fn funded_account, I: 'static>(name: &'static str, index: u32) -> T account } -fn founder, I: 'static>(index: u32) -> T::AccountId { - funded_account::("founder", index) -} - fn fellow, I: 'static>(index: u32) -> T::AccountId { funded_account::("fellow", index) } @@ -82,10 +78,6 @@ fn generate_unscrupulous_account, I: 'static>(index: u32) -> T::Acc } fn set_members, I: 'static>() { - let founders: BoundedVec<_, T::MaxMembersCount> = - BoundedVec::try_from(vec![founder::(1), founder::(2)]).unwrap(); - Members::::insert(MemberRole::Founder, founders.clone()); - let fellows: BoundedVec<_, T::MaxMembersCount> = BoundedVec::try_from(vec![fellow::(1), fellow::(2)]).unwrap(); fellows.iter().for_each(|who| { @@ -102,29 +94,24 @@ fn set_members, I: 'static>() { }); Members::::insert(MemberRole::Ally, allies); - T::InitializeMembers::initialize_members(&[founders.as_slice(), fellows.as_slice()].concat()); + T::InitializeMembers::initialize_members(&[fellows.as_slice()].concat()); } benchmarks_instance_pallet! { // This tests when proposal is created and queued as "proposed" propose_proposed { let b in 1 .. MAX_BYTES; - let x in 2 .. T::MaxFounders::get(); - let y in 0 .. T::MaxFellows::get(); + let m in 2 .. T::MaxFellows::get(); let p in 1 .. T::MaxProposals::get(); - let m = x + y; - let bytes_in_storage = b + size_of::() as u32 + 32; // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let proposer = founders[0].clone(); - let fellows = (0 .. y).map(fellow::).collect::>(); + let fellows = (0 .. m).map(fellow::).collect::>(); + let proposer = fellows[0].clone(); Alliance::::init_members( SystemOrigin::Root.into(), - founders, fellows, vec![], )?; @@ -154,28 +141,21 @@ benchmarks_instance_pallet! { } vote { - // We choose 5 (3 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let x in 3 .. T::MaxFounders::get(); - let y in 2 .. T::MaxFellows::get(); - - let m = x + y; + // We choose 5 as a minimum so we always trigger a vote in the voting loop (`for j in ...`) + let m in 5 .. T::MaxFellows::get(); let p = T::MaxProposals::get(); let b = MAX_BYTES; let bytes_in_storage = b + size_of::() as u32 + 32; // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let proposer = founders[0].clone(); - let fellows = (0 .. y).map(fellow::).collect::>(); + let fellows = (0 .. m).map(fellow::).collect::>(); + let proposer = fellows[0].clone(); - let mut members = Vec::with_capacity(founders.len() + fellows.len()); - members.extend(founders.clone()); - members.extend(fellows.clone()); + let members = fellows.clone(); Alliance::::init_members( SystemOrigin::Root.into(), - founders, fellows, vec![], )?; @@ -230,71 +210,21 @@ benchmarks_instance_pallet! { verify { } - veto { - let p in 1 .. T::MaxProposals::get(); - - let m = 3; - let b = MAX_BYTES; - let bytes_in_storage = b + size_of::() as u32 + 32; - - // Construct `members`. - let founders = (0 .. m).map(founder::).collect::>(); - let vetor = founders[0].clone(); - - Alliance::::init_members( - SystemOrigin::Root.into(), - founders, - vec![], - vec![], - )?; - - // Threshold is one less than total members so that two nays will disapprove the vote - let threshold = m - 1; - - // Add proposals - let mut last_hash = T::Hash::default(); - for i in 0 .. p { - // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; b as usize]) - }.into(); - Alliance::::propose( - SystemOrigin::Signed(vetor.clone()).into(), - threshold, - Box::new(proposal.clone()), - bytes_in_storage, - )?; - last_hash = T::Hashing::hash_of(&proposal); - } - - }: _(SystemOrigin::Signed(vetor), last_hash.clone()) - verify { - // The proposal is removed - assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); - } - close_early_disapproved { - // We choose 4 (2 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let x in 2 .. T::MaxFounders::get(); - let y in 2 .. T::MaxFellows::get(); + // We choose 4 as a minimum so we always trigger a vote in the voting loop (`for j in ...`) + let m in 4 .. T::MaxFellows::get(); let p in 1 .. T::MaxProposals::get(); - let m = x + y; - let bytes = 100; let bytes_in_storage = bytes + size_of::() as u32 + 32; // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let fellows = (0 .. y).map(fellow::).collect::>(); + let fellows = (0 .. m).map(fellow::).collect::>(); - let mut members = Vec::with_capacity(founders.len() + fellows.len()); - members.extend(founders.clone()); - members.extend(fellows.clone()); + let members = fellows.clone(); Alliance::::init_members( SystemOrigin::Root.into(), - founders, fellows, vec![], )?; @@ -361,25 +291,19 @@ benchmarks_instance_pallet! { close_early_approved { let b in 1 .. MAX_BYTES; - // We choose 4 (2 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let x in 2 .. T::MaxFounders::get(); - let y in 2 .. T::MaxFellows::get(); + // We choose 4 as a minimum so we always trigger a vote in the voting loop (`for j in ...`) + let m in 4 .. T::MaxFellows::get(); let p in 1 .. T::MaxProposals::get(); - let m = x + y; let bytes_in_storage = b + size_of::() as u32 + 32; // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let fellows = (0 .. y).map(fellow::).collect::>(); + let fellows = (0 .. m).map(fellow::).collect::>(); - let mut members = Vec::with_capacity(founders.len() + fellows.len()); - members.extend(founders.clone()); - members.extend(fellows.clone()); + let members = fellows.clone(); Alliance::::init_members( SystemOrigin::Root.into(), - founders, fellows, vec![], )?; @@ -450,27 +374,20 @@ benchmarks_instance_pallet! { } close_disapproved { - // We choose 2 (2 founders / 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let x in 2 .. T::MaxFounders::get(); - let y in 2 .. T::MaxFellows::get(); + // We choose 4 as a minimum so we always trigger a vote in the voting loop (`for j in ...`) + let m in 2 .. T::MaxFellows::get(); let p in 1 .. T::MaxProposals::get(); - let m = x + y; - let bytes = 100; let bytes_in_storage = bytes + size_of::() as u32 + 32; // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let fellows = (0 .. y).map(fellow::).collect::>(); + let fellows = (0 .. m).map(fellow::).collect::>(); - let mut members = Vec::with_capacity(founders.len() + fellows.len()); - members.extend(founders.clone()); - members.extend(fellows.clone()); + let members = fellows.clone(); Alliance::::init_members( SystemOrigin::Root.into(), - founders, fellows, vec![], )?; @@ -528,25 +445,19 @@ benchmarks_instance_pallet! { close_approved { let b in 1 .. MAX_BYTES; - // We choose 4 (2 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let x in 2 .. T::MaxFounders::get(); - let y in 2 .. T::MaxFellows::get(); + // We choose 4 fellows as a minimum so we always trigger a vote in the voting loop (`for j in ...`) + let m in 5 .. T::MaxFellows::get(); let p in 1 .. T::MaxProposals::get(); - let m = x + y; let bytes_in_storage = b + size_of::() as u32 + 32; // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let fellows = (0 .. y).map(fellow::).collect::>(); + let fellows = (0 .. m).map(fellow::).collect::>(); - let mut members = Vec::with_capacity(founders.len() + fellows.len()); - members.extend(founders.clone()); - members.extend(fellows.clone()); + let members = fellows.clone(); Alliance::::init_members( SystemOrigin::Root.into(), - founders, fellows, vec![], )?; @@ -605,54 +516,48 @@ benchmarks_instance_pallet! { } init_members { - // at least 1 founders - let x in 1 .. T::MaxFounders::get(); - let y in 0 .. T::MaxFellows::get(); + // at least 1 fellow + let m in 1 .. T::MaxFellows::get(); let z in 0 .. T::MaxAllies::get(); - let mut founders = (0 .. x).map(founder::).collect::>(); - let mut fellows = (0 .. y).map(fellow::).collect::>(); + let mut fellows = (0 .. m).map(fellow::).collect::>(); let mut allies = (0 .. z).map(ally::).collect::>(); - }: _(SystemOrigin::Root, founders.clone(), fellows.clone(), allies.clone()) + }: _(SystemOrigin::Root, fellows.clone(), allies.clone()) verify { - founders.sort(); fellows.sort(); allies.sort(); assert_last_event::(Event::MembersInitialized { - founders: founders.clone(), fellows: fellows.clone(), allies: allies.clone(), }.into()); - assert_eq!(Alliance::::members(MemberRole::Founder), founders); assert_eq!(Alliance::::members(MemberRole::Fellow), fellows); assert_eq!(Alliance::::members(MemberRole::Ally), allies); } disband { // at least 1 founders - let x in 1 .. T::MaxFounders::get() + T::MaxFellows::get(); + let x in 1 .. T::MaxFellows::get(); let y in 0 .. T::MaxAllies::get(); let z in 0 .. T::MaxMembersCount::get() / 2; - let voting_members = (0 .. x).map(founder::).collect::>(); + let fellows = (0 .. x).map(fellow::).collect::>(); let allies = (0 .. y).map(ally::).collect::>(); let witness = DisbandWitness{ - voting_members: x, + fellow_members: x, ally_members: y, }; // setting the Alliance to disband on the benchmark call Alliance::::init_members( SystemOrigin::Root.into(), - voting_members.clone(), - vec![], + fellows.clone(), allies.clone(), )?; // reserve deposits let deposit = T::AllyDeposit::get(); - for member in voting_members.iter().chain(allies.iter()).take(z as usize) { + for member in fellows.iter().chain(allies.iter()).take(z as usize) { T::Currency::reserve(&member, deposit)?; >::insert(&member, deposit); } @@ -662,7 +567,7 @@ benchmarks_instance_pallet! { }: _(SystemOrigin::Root, witness) verify { assert_last_event::(Event::AllianceDisbanded { - voting_members: x, + fellow_members: x, ally_members: y, unreserved: cmp::min(z, x + y), }.into()); @@ -732,22 +637,22 @@ benchmarks_instance_pallet! { nominate_ally { set_members::(); - let founder1 = founder::(1); - assert!(Alliance::::is_member_of(&founder1, MemberRole::Founder)); + let fellow1 = fellow::(1); + assert!(Alliance::::is_member_of(&fellow1, MemberRole::Fellow)); let outsider = outsider::(1); assert!(!Alliance::::is_member(&outsider)); assert_eq!(DepositOf::::get(&outsider), None); let outsider_lookup = T::Lookup::unlookup(outsider.clone()); - }: _(SystemOrigin::Signed(founder1.clone()), outsider_lookup) + }: _(SystemOrigin::Signed(fellow1.clone()), outsider_lookup) verify { assert!(Alliance::::is_member_of(&outsider, MemberRole::Ally)); // outsider is now an ally assert_eq!(DepositOf::::get(&outsider), None); // without a deposit assert!(!Alliance::::has_voting_rights(&outsider)); // allies don't have voting rights assert_last_event::(Event::NewAllyJoined { ally: outsider, - nominator: Some(founder1), + nominator: Some(fellow1), reserved: None }.into()); } @@ -764,7 +669,7 @@ benchmarks_instance_pallet! { }: { call.dispatch_bypass_filter(origin)? } verify { assert!(!Alliance::::is_ally(&ally1)); - assert!(Alliance::::is_fellow(&ally1)); + assert!(Alliance::::has_voting_rights(&ally1)); assert_last_event::(Event::AllyElevated { ally: ally1 }.into()); } @@ -772,7 +677,7 @@ benchmarks_instance_pallet! { set_members::(); let fellow2 = fellow::(2); - assert!(Alliance::::is_fellow(&fellow2)); + assert!(Alliance::::has_voting_rights(&fellow2)); }: _(SystemOrigin::Signed(fellow2.clone())) verify { assert!(Alliance::::is_member_of(&fellow2, MemberRole::Retiring)); @@ -790,7 +695,7 @@ benchmarks_instance_pallet! { set_members::(); let fellow2 = fellow::(2); - assert!(Alliance::::is_fellow(&fellow2)); + assert!(Alliance::::has_voting_rights(&fellow2)); assert_eq!( Alliance::::give_retirement_notice( @@ -885,5 +790,18 @@ benchmarks_instance_pallet! { assert_last_event::(Event::UnscrupulousItemRemoved { items: unscrupulous_list }.into()); } + abdicate_fellow_status { + set_members::(); + let fellow2 = fellow::(2); + assert!(Alliance::::has_voting_rights(&fellow2)); + }: _(SystemOrigin::Signed(fellow2.clone())) + verify { + assert!(Alliance::::is_member_of(&fellow2, MemberRole::Ally)); + + assert_last_event::( + Event::FellowAbdicated {fellow: fellow2}.into() + ); + } + impl_benchmark_test_suite!(Alliance, crate::mock::new_bench_ext(), crate::mock::Test); } diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index fca17e69c7652..7e03da9ac1c7b 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -18,7 +18,7 @@ //! # Alliance Pallet //! //! The Alliance Pallet provides a collective that curates a list of accounts and URLs, deemed by -//! the voting members to be unscrupulous actors. The alliance +//! the voting members to be unscrupulous actors. The Alliance //! //! - provides a set of ethics against bad behavior, and //! - provides recognition and influence for those teams that contribute something back to the @@ -36,19 +36,16 @@ //! ### Terminology //! //! - Rule: The IPFS CID (hash) of the Alliance rules for the community to read and the Alliance -//! members to enforce. Similar to a Code of Conduct. +//! members to enforce. Similar to a Charter or Code of Conduct. //! - Announcement: An IPFS CID of some content that the Alliance want to announce. -//! - Member: An account that is already in the group of the Alliance, including three types: -//! Founder, Fellow, or Ally. A member can also be kicked by the `MembershipManager` origin or -//! retire by itself. -//! - Founder: An account who is initiated by Root with normal voting rights for basic motions and -//! special veto rights for rule change and Ally elevation motions. -//! - Fellow: An account who is elevated from Ally by Founders and other Fellows. -//! - Ally: An account who would like to join the alliance. To become a voting member, Fellow or -//! Founder, it will need approval from the `MembershipManager` origin. Any account can join as an -//! Ally either by placing a deposit or by nomination from a voting member. -//! - Unscrupulous List: A list of bad websites and addresses, items can be added or removed by -//! Founders and Fellows. +//! - Member: An account that is already in the group of the Alliance, including two types: Fellow, +//! or Ally. A member can also be kicked by the `MembershipManager` origin or retire by itself. +//! - Fellow: An account who is elevated from Ally by other Fellows. +//! - Ally: An account who would like to join the Alliance. To become a voting member (Fellow), it +//! will need approval from the `MembershipManager` origin. Any account can join as an Ally either +//! by placing a deposit or by nomination from a voting member. +//! - Unscrupulous List: A list of bad websites and addresses; items can be added or removed by +//! voting members. //! //! ## Interface //! @@ -64,7 +61,7 @@ //! pass in order to retire. //! - `retire` - Retire from the Alliance and release the caller's deposit. //! -//! #### For Members (Founders/Fellows) +//! #### For Voting Members //! //! - `propose` - Propose a motion. //! - `vote` - Vote on a motion. @@ -77,14 +74,11 @@ //! - `add_unscrupulous_items` - Add some items, either accounts or websites, to the list of //! unscrupulous items. //! - `remove_unscrupulous_items` - Remove some items from the list of unscrupulous items. -//! -//! #### For Members (Only Founders) -//! -//! - `veto` - Veto on a motion about `set_rule` and `elevate_ally`. +//! - `abdicate_fellow_status` - Abdicate one's voting rights, demoting themself to Ally. //! //! #### Root Calls //! -//! - `init_members` - Initialize the Alliance, onboard founders, fellows, and allies. +//! - `init_members` - Initialize the Alliance, onboard fellows and allies. //! - `disband` - Disband the Alliance, remove all active members and unreserve deposits. #![cfg_attr(not(feature = "std"), no_std)] @@ -191,10 +185,6 @@ pub trait ProposalProvider { approve: bool, ) -> Result; - /// Veto a proposal, closing and removing it from the system, regardless of its current state. - /// Returns an active proposals count, which includes removed proposal. - fn veto_proposal(proposal_hash: Hash) -> u32; - /// Close a proposal that is either approved, disapproved, or whose voting period has ended. fn close_proposal( proposal_hash: Hash, @@ -210,7 +200,6 @@ pub trait ProposalProvider { /// The various roles that a member can hold. #[derive(Copy, Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum MemberRole { - Founder, Fellow, Ally, Retiring, @@ -282,21 +271,14 @@ pub mod pallet { /// Maximum number of proposals allowed to be active in parallel. type MaxProposals: Get; - /// The maximum number of founders supported by the pallet. Used for weight estimation. - /// - /// NOTE: - /// + Benchmarks will need to be re-run and weights adjusted if this changes. - /// + This pallet assumes that dependencies keep to the limit without enforcing it. - type MaxFounders: Get; - - /// The maximum number of fellows supported by the pallet. Used for weight estimation. + /// The maximum number of Fellows supported by the pallet. Used for weight estimation. /// /// NOTE: /// + Benchmarks will need to be re-run and weights adjusted if this changes. /// + This pallet assumes that dependencies keep to the limit without enforcing it. type MaxFellows: Get; - /// The maximum number of allies supported by the pallet. Used for weight estimation. + /// The maximum number of Allies supported by the pallet. Used for weight estimation. /// /// NOTE: /// + Benchmarks will need to be re-run and weights adjusted if this changes. @@ -319,8 +301,7 @@ pub mod pallet { #[pallet::constant] type MaxAnnouncementsCount: Get; - /// The maximum number of members per member role. Should not exceed the sum of - /// `MaxFounders` and `MaxFellows`. + /// The maximum number of members per member role. #[pallet::constant] type MaxMembersCount: Get; @@ -344,8 +325,6 @@ pub mod pallet { NotMember, /// Account is not an ally. NotAlly, - /// Account is not a founder. - NotFounder, /// Account does not have voting rights. NoVotingRights, /// Account is already an elevated (fellow) member. @@ -369,8 +348,6 @@ pub mod pallet { WithoutGoodIdentityJudgement, /// The proposal hash is not found. MissingProposalHash, - /// The proposal is not vetoable. - NotVetoableProposal, /// The announcement is not found. MissingAnnouncement, /// Number of members exceeds `MaxMembersCount`. @@ -385,8 +362,8 @@ pub mod pallet { RetirementNoticeNotGiven, /// Retirement period has not passed. RetirementPeriodNotPassed, - /// Founders must be provided to initialize the Alliance. - FoundersMissing, + /// Fellows must be provided to initialize the Alliance. + FellowsMissing, } #[pallet::event] @@ -398,12 +375,8 @@ pub mod pallet { Announced { announcement: Cid }, /// An on-chain announcement has been removed. AnnouncementRemoved { announcement: Cid }, - /// Some accounts have been initialized as members (founders/fellows/allies). - MembersInitialized { - founders: Vec, - fellows: Vec, - allies: Vec, - }, + /// Some accounts have been initialized as members (fellows/allies). + MembersInitialized { fellows: Vec, allies: Vec }, /// An account has been added as an Ally and reserved its deposit. NewAllyJoined { ally: T::AccountId, @@ -423,12 +396,13 @@ pub mod pallet { /// Accounts or websites have been removed from the list of unscrupulous items. UnscrupulousItemRemoved { items: Vec> }, /// Alliance disbanded. Includes number deleted members and unreserved deposits. - AllianceDisbanded { voting_members: u32, ally_members: u32, unreserved: u32 }, + AllianceDisbanded { fellow_members: u32, ally_members: u32, unreserved: u32 }, + /// A Fellow abdicated their voting rights. They are now an Ally. + FellowAbdicated { fellow: T::AccountId }, } #[pallet::genesis_config] pub struct GenesisConfig, I: 'static = ()> { - pub founders: Vec, pub fellows: Vec, pub allies: Vec, pub phantom: PhantomData<(T, I)>, @@ -437,40 +411,22 @@ pub mod pallet { #[cfg(feature = "std")] impl, I: 'static> Default for GenesisConfig { fn default() -> Self { - Self { - founders: Vec::new(), - fellows: Vec::new(), - allies: Vec::new(), - phantom: Default::default(), - } + Self { fellows: Vec::new(), allies: Vec::new(), phantom: Default::default() } } } #[pallet::genesis_build] impl, I: 'static> GenesisBuild for GenesisConfig { fn build(&self) { - for m in self.founders.iter().chain(self.fellows.iter()).chain(self.allies.iter()) { + for m in self.fellows.iter().chain(self.allies.iter()) { assert!(Pallet::::has_identity(m).is_ok(), "Member does not set identity!"); } - if !self.founders.is_empty() { - assert!( - !Pallet::::has_member(MemberRole::Founder), - "Founders are already initialized!" - ); - let members: BoundedVec = - self.founders.clone().try_into().expect("Too many genesis founders"); - Members::::insert(MemberRole::Founder, members); - } if !self.fellows.is_empty() { assert!( !Pallet::::has_member(MemberRole::Fellow), "Fellows are already initialized!" ); - assert!( - !self.founders.is_empty(), - "Founders must be provided to initialize the Alliance" - ); let members: BoundedVec = self.fellows.clone().try_into().expect("Too many genesis fellows"); Members::::insert(MemberRole::Fellow, members); @@ -481,24 +437,20 @@ pub mod pallet { "Allies are already initialized!" ); assert!( - !self.founders.is_empty(), - "Founders must be provided to initialize the Alliance" + !self.fellows.is_empty(), + "Fellows must be provided to initialize the Alliance" ); let members: BoundedVec = self.allies.clone().try_into().expect("Too many genesis allies"); Members::::insert(MemberRole::Ally, members); } - T::InitializeMembers::initialize_members( - &[self.founders.as_slice(), self.fellows.as_slice()].concat(), - ) + T::InitializeMembers::initialize_members(self.fellows.as_slice()) } } /// The IPFS CID of the alliance rule. - /// Founders and fellows can propose a new rule with a super-majority. - /// - /// Any founder has a special one-vote veto right to the rule setting. + /// Fellows can propose a new rule with a super-majority. #[pallet::storage] #[pallet::getter(fn rule)] pub type Rule, I: 'static = ()> = StorageValue<_, Cid, OptionQuery>; @@ -550,11 +502,10 @@ pub mod pallet { impl, I: 'static> Pallet { /// Add a new proposal to be voted on. /// - /// Requires the sender to be a founder or fellow. + /// Must be called by a Fellow. #[pallet::weight(T::WeightInfo::propose_proposed( *length_bound, // B - T::MaxFounders::get(), // X - T::MaxFellows::get(), // Y + T::MaxFellows::get(), // M T::MaxProposals::get(), // P2 ))] pub fn propose( @@ -572,8 +523,8 @@ pub mod pallet { /// Add an aye or nay vote for the sender to the given proposal. /// - /// Requires the sender to be a founder or fellow. - #[pallet::weight(T::WeightInfo::vote(T::MaxFounders::get(), T::MaxFellows::get()))] + /// Must be called by a Fellow. + #[pallet::weight(T::WeightInfo::vote(T::MaxFellows::get()))] pub fn vote( origin: OriginFor, proposal: T::Hash, @@ -587,39 +538,18 @@ pub mod pallet { Ok(()) } - /// Veto a proposal about `set_rule` and `elevate_ally`, close, and remove it from the - /// system, regardless of its current state. - /// - /// Must be called by a founder. - #[pallet::weight(T::WeightInfo::veto(T::MaxProposals::get()))] - pub fn veto(origin: OriginFor, proposal_hash: T::Hash) -> DispatchResult { - let proposor = ensure_signed(origin)?; - ensure!(Self::is_founder(&proposor), Error::::NotFounder); - - let proposal = T::ProposalProvider::proposal_of(proposal_hash) - .ok_or(Error::::MissingProposalHash)?; - match proposal.is_sub_type() { - Some(Call::set_rule { .. }) | Some(Call::elevate_ally { .. }) => { - T::ProposalProvider::veto_proposal(proposal_hash); - Ok(()) - }, - _ => Err(Error::::NotVetoableProposal.into()), - } - } - /// Close a vote that is either approved, disapproved, or whose voting period has ended. /// - /// Requires the sender to be a founder or fellow. + /// Must be called by a Fellow. #[pallet::weight({ let b = *length_bound; - let x = T::MaxFounders::get(); - let y = T::MaxFellows::get(); + let m = T::MaxFellows::get(); let p1 = *proposal_weight_bound; let p2 = T::MaxProposals::get(); - T::WeightInfo::close_early_approved(b, x, y, p2) - .max(T::WeightInfo::close_early_disapproved(x, y, p2)) - .max(T::WeightInfo::close_approved(b, x, y, p2)) - .max(T::WeightInfo::close_disapproved(x, y, p2)) + T::WeightInfo::close_early_approved(b, m, p2) + .max(T::WeightInfo::close_early_disapproved(m, p2)) + .max(T::WeightInfo::close_approved(b, m, p2)) + .max(T::WeightInfo::close_disapproved(m, p2)) .saturating_add(p1.into()) })] #[allow(deprecated)] @@ -638,62 +568,52 @@ pub mod pallet { Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) } - /// Initialize the Alliance, onboard founders, fellows, and allies. + /// Initialize the Alliance, onboard fellows and allies. + /// + /// The Alliance must be empty, and the call must provide some founding members. /// - /// Founders must be not empty. - /// The Alliance must be empty. /// Must be called by the Root origin. #[pallet::weight(T::WeightInfo::init_members( - founders.len() as u32, fellows.len() as u32, allies.len() as u32, ))] pub fn init_members( origin: OriginFor, - founders: Vec, fellows: Vec, allies: Vec, ) -> DispatchResult { ensure_root(origin)?; - ensure!(!founders.is_empty(), Error::::FoundersMissing); + ensure!(!fellows.is_empty(), Error::::FellowsMissing); ensure!(!Self::is_initialized(), Error::::AllianceAlreadyInitialized); - let mut founders: BoundedVec = - founders.try_into().map_err(|_| Error::::TooManyMembers)?; let mut fellows: BoundedVec = fellows.try_into().map_err(|_| Error::::TooManyMembers)?; let mut allies: BoundedVec = allies.try_into().map_err(|_| Error::::TooManyMembers)?; - for member in founders.iter().chain(fellows.iter()).chain(allies.iter()) { + for member in fellows.iter().chain(allies.iter()) { Self::has_identity(member)?; } - founders.sort(); - Members::::insert(&MemberRole::Founder, founders.clone()); fellows.sort(); Members::::insert(&MemberRole::Fellow, fellows.clone()); allies.sort(); Members::::insert(&MemberRole::Ally, allies.clone()); - let mut voteable_members = Vec::with_capacity(founders.len() + fellows.len()); - voteable_members.extend(founders.clone()); - voteable_members.extend(fellows.clone()); + let mut voteable_members = fellows.clone(); voteable_members.sort(); T::InitializeMembers::initialize_members(&voteable_members); log::debug!( target: LOG_TARGET, - "Initialize alliance founders: {:?}, fellows: {:?}, allies: {:?}", - founders, + "Initialize alliance fellows: {:?}, allies: {:?}", fellows, allies ); Self::deposit_event(Event::MembersInitialized { - founders: founders.into(), fellows: fellows.into(), allies: allies.into(), }); @@ -704,9 +624,9 @@ pub mod pallet { /// /// Witness data must be set. #[pallet::weight(T::WeightInfo::disband( - witness.voting_members, + witness.fellow_members, witness.ally_members, - witness.voting_members.saturating_add(witness.ally_members), + witness.fellow_members.saturating_add(witness.ally_members), ))] pub fn disband( origin: OriginFor, @@ -716,7 +636,7 @@ pub mod pallet { ensure!(!witness.is_zero(), Error::::BadWitness); ensure!( - Self::voting_members_count() <= witness.voting_members, + Self::voting_members_count() <= witness.fellow_members, Error::::BadWitness ); ensure!(Self::ally_members_count() <= witness.ally_members, Error::::BadWitness); @@ -735,12 +655,11 @@ pub mod pallet { } } - Members::::remove(&MemberRole::Founder); Members::::remove(&MemberRole::Fellow); Members::::remove(&MemberRole::Ally); Self::deposit_event(Event::AllianceDisbanded { - voting_members: voting_members.len() as u32, + fellow_members: voting_members.len() as u32, ally_members: ally_members.len() as u32, unreserved: unreserve_count, }); @@ -831,8 +750,8 @@ pub mod pallet { Ok(()) } - /// A founder or fellow can nominate someone to join the alliance as an Ally. - /// There is no deposit required to the nominator or nominee. + /// A Fellow can nominate someone to join the alliance as an Ally. There is no deposit + /// required from the nominator or nominee. #[pallet::weight(T::WeightInfo::nominate_ally())] pub fn nominate_ally(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { let nominator = ensure_signed(origin)?; @@ -856,7 +775,7 @@ pub mod pallet { Ok(()) } - /// Elevate an ally to fellow. + /// Elevate an Ally to Fellow. #[pallet::weight(T::WeightInfo::elevate_ally())] pub fn elevate_ally(origin: OriginFor, ally: AccountIdLookupOf) -> DispatchResult { T::MembershipManager::ensure_origin(origin)?; @@ -891,8 +810,10 @@ pub mod pallet { Ok(()) } - /// As a member, retire from the alliance and unreserve the deposit. - /// This can only be done once you have `give_retirement_notice` and it has expired. + /// As a member, retire from the Alliance and unreserve the deposit. + /// + /// This can only be done once you have called `give_retirement_notice` and the + /// `RetirementPeriod` has passed. #[pallet::weight(T::WeightInfo::retire())] pub fn retire(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -914,7 +835,7 @@ pub mod pallet { Ok(()) } - /// Kick a member from the alliance and slash its deposit. + /// Kick a member from the Alliance and slash its deposit. #[pallet::weight(T::WeightInfo::kick_member())] pub fn kick_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::MembershipManager::ensure_origin(origin)?; @@ -960,7 +881,7 @@ pub mod pallet { Ok(()) } - /// Deem an item no longer unscrupulous. + /// Deem some items no longer unscrupulous. #[pallet::weight(>::WeightInfo::remove_unscrupulous_items( items.len() as u32, T::MaxWebsiteUrlLength::get() ))] @@ -985,17 +906,16 @@ pub mod pallet { /// Close a vote that is either approved, disapproved, or whose voting period has ended. /// - /// Requires the sender to be a founder or fellow. + /// Must be called by a Fellow. #[pallet::weight({ let b = *length_bound; - let x = T::MaxFounders::get(); - let y = T::MaxFellows::get(); + let m = T::MaxFellows::get(); let p1 = *proposal_weight_bound; let p2 = T::MaxProposals::get(); - T::WeightInfo::close_early_approved(b, x, y, p2) - .max(T::WeightInfo::close_early_disapproved(x, y, p2)) - .max(T::WeightInfo::close_approved(b, x, y, p2)) - .max(T::WeightInfo::close_disapproved(x, y, p2)) + T::WeightInfo::close_early_approved(b, m, p2) + .max(T::WeightInfo::close_early_disapproved(m, p2)) + .max(T::WeightInfo::close_approved(b, m, p2)) + .max(T::WeightInfo::close_disapproved(m, p2)) .saturating_add(p1) })] pub fn close( @@ -1010,15 +930,30 @@ pub mod pallet { Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) } + + /// Abdicate one's position as a voting member and just be an Ally. May be used by Fellows + /// who do not want to leave the Alliance but do not have the capacity to participate + /// operationally for some time. + #[pallet::weight(T::WeightInfo::abdicate_fellow_status())] + pub fn abdicate_fellow_status(origin: OriginFor) -> DispatchResult { + let who = ensure_signed(origin)?; + let role = Self::member_role_of(&who).ok_or(Error::::NotMember)?; + // Not applicable to members who are retiring or who are already Allies. + ensure!(Self::has_voting_rights(&who), Error::::NoVotingRights); + + Self::remove_member(&who, role)?; + Self::add_member(&who, MemberRole::Ally)?; + + Self::deposit_event(Event::FellowAbdicated { fellow: who }); + Ok(()) + } } } impl, I: 'static> Pallet { /// Check if the Alliance has been initialized. fn is_initialized() -> bool { - Self::has_member(MemberRole::Founder) || - Self::has_member(MemberRole::Fellow) || - Self::has_member(MemberRole::Ally) + Self::has_member(MemberRole::Fellow) || Self::has_member(MemberRole::Ally) } /// Check if a given role has any members. @@ -1042,24 +977,14 @@ impl, I: 'static> Pallet { Members::::get(role).contains(&who) } - /// Check if an account is a founder. - fn is_founder(who: &T::AccountId) -> bool { - Self::is_member_of(who, MemberRole::Founder) - } - - /// Check if an account is a fellow. - fn is_fellow(who: &T::AccountId) -> bool { - Self::is_member_of(who, MemberRole::Fellow) - } - - /// Check if an account is an ally. + /// Check if an account is an Ally. fn is_ally(who: &T::AccountId) -> bool { Self::is_member_of(who, MemberRole::Ally) } /// Check if a member has voting rights. fn has_voting_rights(who: &T::AccountId) -> bool { - Self::is_founder(who) || Self::is_fellow(who) + Self::is_member_of(who, MemberRole::Fellow) } /// Count of ally members. @@ -1069,9 +994,7 @@ impl, I: 'static> Pallet { /// Count of all members who have voting rights. fn voting_members_count() -> u32 { - Members::::decode_len(MemberRole::Founder) - .unwrap_or(0) - .saturating_add(Members::::decode_len(MemberRole::Fellow).unwrap_or(0)) as u32 + Members::::decode_len(MemberRole::Fellow).unwrap_or(0) as u32 } /// Get all members of a given role. @@ -1081,17 +1004,7 @@ impl, I: 'static> Pallet { /// Collect all members who have voting rights into one list. fn voting_members() -> Vec { - let mut founders = Self::members_of(MemberRole::Founder); - let mut fellows = Self::members_of(MemberRole::Fellow); - founders.append(&mut fellows); - founders - } - - /// Collect all members who have voting rights into one sorted list. - fn voting_members_sorted() -> Vec { - let mut members = Self::voting_members(); - members.sort(); - members + Self::members_of(MemberRole::Fellow) } /// Add a user to the sorted alliance member set. @@ -1104,8 +1017,8 @@ impl, I: 'static> Pallet { Ok(()) })?; - if role == MemberRole::Founder || role == MemberRole::Fellow { - let members = Self::voting_members_sorted(); + if role == MemberRole::Fellow { + let members = Self::voting_members(); T::MembershipChanged::change_members_sorted(&[who.clone()], &[], &members[..]); } Ok(()) @@ -1119,8 +1032,8 @@ impl, I: 'static> Pallet { Ok(()) })?; - if matches!(role, MemberRole::Founder | MemberRole::Fellow) { - let members = Self::voting_members_sorted(); + if role == MemberRole::Fellow { + let members = Self::voting_members(); T::MembershipChanged::change_members_sorted(&[], &[who.clone()], &members[..]); } Ok(()) diff --git a/frame/alliance/src/migration.rs b/frame/alliance/src/migration.rs index 8f98484240061..ea07f8c1279b1 100644 --- a/frame/alliance/src/migration.rs +++ b/frame/alliance/src/migration.rs @@ -20,7 +20,7 @@ use frame_support::{pallet_prelude::*, storage::migration, traits::OnRuntimeUpgr use log; /// The current storage version. -pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); /// Wrapper for all migrations of this pallet. pub fn migrate, I: 'static>() -> Weight { @@ -31,6 +31,10 @@ pub fn migrate, I: 'static>() -> Weight { weight = weight.saturating_add(v0_to_v1::migrate::()); } + if onchain_version < 2 { + weight = weight.saturating_add(v1_to_v2::migrate::()); + } + STORAGE_VERSION.put::>(); weight = weight.saturating_add(T::DbWeight::get().writes(1)); @@ -77,3 +81,99 @@ mod v0_to_v1 { T::DbWeight::get().writes(res.unique.into()) } } + +/// v1_to_v2: `Members` storage map collapses `Founder` and `Fellow` keys into one `Fellow`. +/// Total number of `Founder`s and `Fellow`s must not be higher than `T::MaxMembersCount`. +pub(crate) mod v1_to_v2 { + use super::*; + use crate::{MemberRole, Members}; + + /// V1 Role set. + #[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen)] + pub enum MemberRoleV1 { + Founder, + Fellow, + Ally, + Retiring, + } + + pub fn migrate, I: 'static>() -> Weight { + log::info!(target: LOG_TARGET, "Running migration v1_to_v2: `Members` storage map collapses `Founder` and `Fellow` keys into one `Fellow`."); + // fetch into the scope all members. + let founders_vec = take_members::(MemberRoleV1::Founder).into_inner(); + let mut fellows_vec = take_members::(MemberRoleV1::Fellow).into_inner(); + let allies = take_members::(MemberRoleV1::Ally); + let retiring = take_members::(MemberRoleV1::Retiring); + if founders_vec + .len() + .saturating_add(fellows_vec.len()) + .saturating_add(allies.len()) + .saturating_add(retiring.len()) == + 0 + { + return T::DbWeight::get().reads(4) + } + log::info!( + target: LOG_TARGET, + "Members storage v1 contains, '{}' founders, '{}' fellows, '{}' allies, '{}' retiring members.", + founders_vec.len(), + fellows_vec.len(), + allies.len(), + retiring.len(), + ); + // merge founders with fellows and sort. + fellows_vec.extend(founders_vec); + fellows_vec.sort(); + if fellows_vec.len() as u32 > T::MaxMembersCount::get() { + log::error!( + target: LOG_TARGET, + "Merged list of founders and fellows do not fit into `T::MaxMembersCount` bound. Truncating the merged set into max members count." + ); + fellows_vec.truncate(T::MaxMembersCount::get() as usize); + } + let fellows: BoundedVec = + fellows_vec.try_into().unwrap_or_default(); + // insert members with new storage map key. + Members::::insert(&MemberRole::Fellow, fellows.clone()); + Members::::insert(&MemberRole::Ally, allies.clone()); + Members::::insert(&MemberRole::Retiring, retiring.clone()); + log::info!( + target: LOG_TARGET, + "Members storage updated with, '{}' fellows, '{}' allies, '{}' retiring members.", + fellows.len(), + allies.len(), + retiring.len(), + ); + T::DbWeight::get().reads_writes(4, 4) + } + + fn take_members, I: 'static>( + role: MemberRoleV1, + ) -> BoundedVec { + migration::take_storage_item::< + MemberRoleV1, + BoundedVec, + Twox64Concat, + >(>::name().as_bytes(), b"Members", role) + .unwrap_or_default() + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::{mock::*, MemberRole}; + + #[test] + fn migration_v1_to_v2_works() { + new_test_ext().execute_with(|| { + assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); + assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + v1_to_v2::migrate::(); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3, 4]); + assert_eq!(Alliance::members(MemberRole::Ally), vec![]); + assert_eq!(Alliance::members(MemberRole::Retiring), vec![]); + }); + } +} diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index 196e0003b537f..e708d29d529fe 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -39,6 +39,7 @@ pub use crate as pallet_alliance; use super::*; type BlockNumber = u64; +type AccountId = u64; parameter_types! { pub const BlockHashCount: BlockNumber = 250; @@ -53,7 +54,7 @@ impl frame_system::Config for Test { type BlockNumber = BlockNumber; type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = u64; + type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; type RuntimeEvent = RuntimeEvent; @@ -61,7 +62,7 @@ impl frame_system::Config for Test { type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; + type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); @@ -120,8 +121,8 @@ ord_parameter_types! { pub const Four: u64 = 4; pub const Five: u64 = 5; } -type EnsureOneOrRoot = EitherOfDiverse, EnsureSignedBy>; -type EnsureTwoOrRoot = EitherOfDiverse, EnsureSignedBy>; +type EnsureOneOrRoot = EitherOfDiverse, EnsureSignedBy>; +type EnsureTwoOrRoot = EitherOfDiverse, EnsureSignedBy>; impl pallet_identity::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -139,12 +140,12 @@ impl pallet_identity::Config for Test { } pub struct AllianceIdentityVerifier; -impl IdentityVerifier for AllianceIdentityVerifier { - fn has_identity(who: &u64, fields: u64) -> bool { +impl IdentityVerifier for AllianceIdentityVerifier { + fn has_identity(who: &AccountId, fields: u64) -> bool { Identity::has_identity(who, fields) } - fn has_good_judgement(who: &u64) -> bool { + fn has_good_judgement(who: &AccountId) -> bool { if let Some(judgements) = Identity::identity(who).map(|registration| registration.judgements) { @@ -156,15 +157,15 @@ impl IdentityVerifier for AllianceIdentityVerifier { } } - fn super_account_id(who: &u64) -> Option { + fn super_account_id(who: &AccountId) -> Option { Identity::super_of(who).map(|parent| parent.0) } } pub struct AllianceProposalProvider; -impl ProposalProvider for AllianceProposalProvider { +impl ProposalProvider for AllianceProposalProvider { fn propose_proposal( - who: u64, + who: AccountId, threshold: u32, proposal: Box, length_bound: u32, @@ -173,7 +174,7 @@ impl ProposalProvider for AllianceProposalProvider { } fn vote_proposal( - who: u64, + who: AccountId, proposal: H256, index: ProposalIndex, approve: bool, @@ -181,10 +182,6 @@ impl ProposalProvider for AllianceProposalProvider { AllianceMotion::do_vote(who, proposal, index, approve) } - fn veto_proposal(proposal_hash: H256) -> u32 { - AllianceMotion::do_disapprove_proposal(proposal_hash) - } - fn close_proposal( proposal_hash: H256, proposal_index: ProposalIndex, @@ -200,8 +197,7 @@ impl ProposalProvider for AllianceProposalProvider { } parameter_types! { - pub const MaxFounders: u32 = 10; - pub const MaxFellows: u32 = MaxMembers::get() - MaxFounders::get(); + pub const MaxFellows: u32 = MaxMembers::get(); pub const MaxAllies: u32 = 100; pub const AllyDeposit: u64 = 25; pub const RetirementPeriod: BlockNumber = MOTION_DURATION_IN_BLOCKS + 1; @@ -209,9 +205,9 @@ parameter_types! { impl Config for Test { type RuntimeEvent = RuntimeEvent; type Proposal = RuntimeCall; - type AdminOrigin = EnsureSignedBy; - type MembershipManager = EnsureSignedBy; - type AnnouncementOrigin = EnsureSignedBy; + type AdminOrigin = EnsureSignedBy; + type MembershipManager = EnsureSignedBy; + type AnnouncementOrigin = EnsureSignedBy; type Currency = Balances; type Slashed = (); type InitializeMembers = AllianceMotion; @@ -222,7 +218,6 @@ impl Config for Test { type IdentityVerifier = (); type ProposalProvider = AllianceProposalProvider; type MaxProposals = MaxProposals; - type MaxFounders = MaxFounders; type MaxFellows = MaxFellows; type MaxAllies = MaxAllies; type MaxUnscrupulousItems = ConstU32<100>; @@ -272,7 +267,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { GenesisBuild::::assimilate_storage( &pallet_alliance::GenesisConfig { - founders: vec![], fellows: vec![], allies: vec![], phantom: Default::default(), @@ -360,7 +354,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { Error::::AllianceNotYetInitialized ); - assert_ok!(Alliance::init_members(RuntimeOrigin::root(), vec![1, 2], vec![3], vec![])); + assert_ok!(Alliance::init_members(RuntimeOrigin::root(), vec![1, 2, 3], vec![])); System::set_block_number(1); }); @@ -384,11 +378,7 @@ pub fn make_remark_proposal(value: u64) -> (RuntimeCall, u32, H256) { make_proposal(RuntimeCall::System(frame_system::Call::remark { remark: value.encode() })) } -pub fn make_set_rule_proposal(rule: Cid) -> (RuntimeCall, u32, H256) { - make_proposal(RuntimeCall::Alliance(pallet_alliance::Call::set_rule { rule })) -} - -pub fn make_kick_member_proposal(who: u64) -> (RuntimeCall, u32, H256) { +pub fn make_kick_member_proposal(who: AccountId) -> (RuntimeCall, u32, H256) { make_proposal(RuntimeCall::Alliance(pallet_alliance::Call::kick_member { who })) } @@ -397,3 +387,7 @@ pub fn make_proposal(proposal: RuntimeCall) -> (RuntimeCall, u32, H256) { let hash = BlakeTwo256::hash_of(&proposal); (proposal, len, hash) } + +pub fn is_fellow(who: &AccountId) -> bool { + Alliance::is_member_of(who, MemberRole::Fellow) +} diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index c55826768c695..363b19429b80f 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -25,12 +25,45 @@ use crate::mock::*; type AllianceMotionEvent = pallet_collective::Event; +fn assert_powerless(user: RuntimeOrigin, user_is_member: bool) { + //vote / veto with a valid propsal + let cid = test_cid(); + let (proposal, _, _) = make_kick_member_proposal(42); + + assert_noop!(Alliance::init_members(user.clone(), vec![], vec![],), BadOrigin); + + assert_noop!( + Alliance::disband(user.clone(), DisbandWitness { fellow_members: 3, ..Default::default() }), + BadOrigin + ); + + assert_noop!(Alliance::set_rule(user.clone(), cid.clone()), BadOrigin); + + assert_noop!(Alliance::retire(user.clone()), Error::::RetirementNoticeNotGiven); + + // Allies should be able to give retirement notice. + if !user_is_member { + assert_noop!(Alliance::give_retirement_notice(user.clone()), Error::::NotMember); + } + + assert_noop!(Alliance::elevate_ally(user.clone(), 4), BadOrigin); + + assert_noop!(Alliance::kick_member(user.clone(), 1), BadOrigin); + + assert_noop!(Alliance::nominate_ally(user.clone(), 4), Error::::NoVotingRights); + + assert_noop!( + Alliance::propose(user.clone(), 5, Box::new(proposal), 1000), + Error::::NoVotingRights + ); +} + #[test] fn init_members_works() { new_test_ext().execute_with(|| { // alliance must be reset first, no witness data assert_noop!( - Alliance::init_members(RuntimeOrigin::root(), vec![8], vec![], vec![],), + Alliance::init_members(RuntimeOrigin::root(), vec![8], vec![],), Error::::AllianceAlreadyInitialized, ); @@ -42,33 +75,28 @@ fn init_members_works() { assert_ok!(Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(2, 0))); // fails without root - assert_noop!( - Alliance::init_members(RuntimeOrigin::signed(1), vec![], vec![], vec![]), - BadOrigin - ); + assert_noop!(Alliance::init_members(RuntimeOrigin::signed(1), vec![], vec![]), BadOrigin); - // founders missing, other members given + // fellows missing, other members given assert_noop!( - Alliance::init_members(RuntimeOrigin::root(), vec![], vec![4], vec![2],), - Error::::FoundersMissing, + Alliance::init_members(RuntimeOrigin::root(), vec![], vec![2],), + Error::::FellowsMissing, ); // success call - assert_ok!(Alliance::init_members(RuntimeOrigin::root(), vec![8, 5], vec![4], vec![2],)); + assert_ok!(Alliance::init_members(RuntimeOrigin::root(), vec![8, 5], vec![2],)); // assert new set of voting members - assert_eq!(Alliance::voting_members_sorted(), vec![4, 5, 8]); + assert_eq!(Alliance::voting_members(), vec![5, 8]); // assert new members member - assert!(Alliance::is_founder(&8)); - assert!(Alliance::is_founder(&5)); - assert!(Alliance::is_fellow(&4)); + assert!(is_fellow(&8)); + assert!(is_fellow(&5)); assert!(Alliance::is_ally(&2)); // assert a retiring member from previous Alliance not removed assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MembersInitialized { - founders: vec![5, 8], - fellows: vec![4], + fellows: vec![5, 8], allies: vec![2], })); }) @@ -78,7 +106,7 @@ fn init_members_works() { fn disband_works() { new_test_ext().execute_with(|| { // ensure alliance is set - assert_eq!(Alliance::voting_members_sorted(), vec![1, 2, 3]); + assert_eq!(Alliance::voting_members(), vec![1, 2, 3]); // give a retirement notice to check later a retiring member not removed assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(2))); @@ -121,7 +149,7 @@ fn disband_works() { assert_eq!(Balances::free_balance(9), 40); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::AllianceDisbanded { - voting_members: 2, + fellow_members: 2, ally_members: 1, unreserved: 1, })); @@ -208,62 +236,6 @@ fn vote_works() { }); } -#[test] -fn veto_works() { - new_test_ext().execute_with(|| { - let (proposal, proposal_len, hash) = make_remark_proposal(42); - assert_ok!(Alliance::propose( - RuntimeOrigin::signed(1), - 3, - Box::new(proposal.clone()), - proposal_len - )); - // only set_rule/elevate_ally can be veto - assert_noop!( - Alliance::veto(RuntimeOrigin::signed(1), hash), - Error::::NotVetoableProposal - ); - - let cid = test_cid(); - let (vetoable_proposal, vetoable_proposal_len, vetoable_hash) = make_set_rule_proposal(cid); - assert_ok!(Alliance::propose( - RuntimeOrigin::signed(1), - 3, - Box::new(vetoable_proposal.clone()), - vetoable_proposal_len - )); - - // only founder have veto rights, 3 is fellow - assert_noop!( - Alliance::veto(RuntimeOrigin::signed(3), vetoable_hash), - Error::::NotFounder - ); - - assert_ok!(Alliance::veto(RuntimeOrigin::signed(2), vetoable_hash)); - let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; - assert_eq!( - System::events(), - vec![ - record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { - account: 1, - proposal_index: 0, - proposal_hash: hash, - threshold: 3 - })), - record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { - account: 1, - proposal_index: 1, - proposal_hash: vetoable_hash, - threshold: 3 - })), - record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Disapproved { - proposal_hash: vetoable_hash - })), - ] - ); - }) -} - #[test] fn close_works() { new_test_ext().execute_with(|| { @@ -447,7 +419,7 @@ fn nominate_ally_works() { Error::::AlreadyMember ); - // only voting member(founder/fellow) have nominate right + // only voting members (Fellows) have nominate right assert_noop!( Alliance::nominate_ally(RuntimeOrigin::signed(5), 4), Error::::NoVotingRights @@ -503,11 +475,11 @@ fn elevate_ally_works() { assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::elevate_ally(RuntimeOrigin::signed(2), 4)); assert_eq!(Alliance::members(MemberRole::Ally), Vec::::new()); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![3, 4]); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3, 4]); }); } @@ -519,9 +491,9 @@ fn give_retirement_notice_work() { Error::::NotMember ); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(3))); - assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2]); assert_eq!(Alliance::members(MemberRole::Retiring), vec![3]); System::assert_last_event(mock::RuntimeEvent::Alliance( crate::Event::MemberRetirementPeriodStarted { member: (3) }, @@ -547,7 +519,7 @@ fn retire_works() { Error::::RetirementNoticeNotGiven ); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(3))); assert_noop!( Alliance::retire(RuntimeOrigin::signed(3)), @@ -555,7 +527,7 @@ fn retire_works() { ); System::set_block_number(System::block_number() + RetirementPeriod::get()); assert_ok!(Alliance::retire(RuntimeOrigin::signed(3))); - assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2]); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberRetired { member: (3), unreserved: None, @@ -564,38 +536,22 @@ fn retire_works() { // Move time on: System::set_block_number(System::block_number() + RetirementPeriod::get()); - assert_powerless(RuntimeOrigin::signed(3)); + assert_powerless(RuntimeOrigin::signed(3), false); }); } -fn assert_powerless(user: RuntimeOrigin) { - //vote / veto with a valid propsal - let cid = test_cid(); - let (proposal, _, _) = make_kick_member_proposal(42); - - assert_noop!(Alliance::init_members(user.clone(), vec![], vec![], vec![],), BadOrigin); - - assert_noop!( - Alliance::disband(user.clone(), DisbandWitness { voting_members: 3, ..Default::default() }), - BadOrigin - ); - - assert_noop!(Alliance::set_rule(user.clone(), cid.clone()), BadOrigin); - - assert_noop!(Alliance::retire(user.clone()), Error::::RetirementNoticeNotGiven); - - assert_noop!(Alliance::give_retirement_notice(user.clone()), Error::::NotMember); - - assert_noop!(Alliance::elevate_ally(user.clone(), 4), BadOrigin); - - assert_noop!(Alliance::kick_member(user.clone(), 1), BadOrigin); +#[test] +fn abdicate_works() { + new_test_ext().execute_with(|| { + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_ok!(Alliance::abdicate_fellow_status(RuntimeOrigin::signed(3))); - assert_noop!(Alliance::nominate_ally(user.clone(), 4), Error::::NoVotingRights); + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::FellowAbdicated { + fellow: (3), + })); - assert_noop!( - Alliance::propose(user.clone(), 5, Box::new(proposal), 1000), - Error::::NoVotingRights - ); + assert_powerless(RuntimeOrigin::signed(3), true); + }); } #[test] @@ -609,9 +565,9 @@ fn kick_member_works() { ); >::insert(2, 25); - assert_eq!(Alliance::members(MemberRole::Founder), vec![1, 2]); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::kick_member(RuntimeOrigin::signed(2), 2)); - assert_eq!(Alliance::members(MemberRole::Founder), vec![1]); + assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 3]); assert_eq!(>::get(2), None); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberKicked { member: (2), diff --git a/frame/alliance/src/types.rs b/frame/alliance/src/types.rs index 90f7ce41b9613..c155b9fa90f95 100644 --- a/frame/alliance/src/types.rs +++ b/frame/alliance/src/types.rs @@ -99,9 +99,9 @@ impl Cid { Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo, Default, )] pub struct DisbandWitness { - /// Total number of voting members in the current Alliance. + /// Total number of fellow members in the current Alliance. #[codec(compact)] - pub(super) voting_members: u32, + pub(super) fellow_members: u32, /// Total number of ally members in the current Alliance. #[codec(compact)] pub(super) ally_members: u32, @@ -110,8 +110,8 @@ pub struct DisbandWitness { #[cfg(test)] impl DisbandWitness { // Creates new DisbandWitness. - pub(super) fn new(voting_members: u32, ally_members: u32) -> Self { - Self { voting_members, ally_members } + pub(super) fn new(fellow_members: u32, ally_members: u32) -> Self { + Self { fellow_members, ally_members } } } diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 29038efd2c25c..58d28b28f2cf3 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -1,41 +1,22 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - //! Autogenerated weights for pallet_alliance //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! DATE: 2022-11-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `cob`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// ./target/release/substrate // benchmark // pallet // --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_alliance +// --pallet=pallet-alliance // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/alliance/src/weights.rs -// --header=./HEADER-APACHE2 +// --output=./frame/alliance/src/._weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -47,14 +28,14 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_alliance. pub trait WeightInfo { - fn propose_proposed(b: u32, x: u32, y: u32, p: u32, ) -> Weight; - fn vote(x: u32, y: u32, ) -> Weight; + fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight; + fn vote(m: u32, ) -> Weight; fn veto(p: u32, ) -> Weight; - fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight; - fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight; - fn close_disapproved(x: u32, y: u32, p: u32, ) -> Weight; - fn close_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight; - fn init_members(x: u32, y: u32, z: u32, ) -> Weight; + fn close_early_disapproved(m: u32, p: u32, ) -> Weight; + fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight; + fn close_disapproved(m: u32, p: u32, ) -> Weight; + fn close_approved(b: u32, m: u32, p: u32, ) -> Weight; + fn init_members(m: u32, z: u32, ) -> Weight; fn disband(x: u32, y: u32, z: u32, ) -> Weight; fn set_rule() -> Weight; fn announce() -> Weight; @@ -67,6 +48,7 @@ pub trait WeightInfo { fn kick_member() -> Weight; fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight; fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight; + fn abdicate_fellow_status() -> Weight; } /// Weights for pallet_alliance using the Substrate node and recommended hardware. @@ -78,31 +60,29 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion ProposalCount (r:1 w:1) // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `b` is `[1, 1024]`. - /// The range of component `x` is `[2, 10]`. - /// The range of component `y` is `[0, 90]`. + /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. - fn propose_proposed(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - // Minimum execution time: 43_720 nanoseconds. - Weight::from_ref_time(44_766_307 as u64) - // Standard Error: 2_522 - .saturating_add(Weight::from_ref_time(54_721 as u64).saturating_mul(y as u64)) - // Standard Error: 2_301 - .saturating_add(Weight::from_ref_time(173_300 as u64).saturating_mul(p as u64)) + fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { + // Minimum execution time: 23_000 nanoseconds. + Weight::from_ref_time(24_357_172 as u64) + // Standard Error: 428 + .saturating_add(Weight::from_ref_time(233 as u64).saturating_mul(b as u64)) + // Standard Error: 4_474 + .saturating_add(Weight::from_ref_time(48_024 as u64).saturating_mul(m as u64)) + // Standard Error: 4_418 + .saturating_add(Weight::from_ref_time(97_604 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } - // Storage: Alliance Members (r:2 w:0) + // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) - /// The range of component `x` is `[3, 10]`. - /// The range of component `y` is `[2, 90]`. - fn vote(x: u32, y: u32, ) -> Weight { - // Minimum execution time: 46_984 nanoseconds. - Weight::from_ref_time(46_837_255 as u64) - // Standard Error: 32_860 - .saturating_add(Weight::from_ref_time(273_691 as u64).saturating_mul(x as u64)) - // Standard Error: 2_781 - .saturating_add(Weight::from_ref_time(126_964 as u64).saturating_mul(y as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) + /// The range of component `m` is `[5, 100]`. + fn vote(m: u32, ) -> Weight { + // Minimum execution time: 24_000 nanoseconds. + Weight::from_ref_time(26_617_201 as u64) + // Standard Error: 4_280 + .saturating_add(Weight::from_ref_time(43_152 as u64).saturating_mul(m as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Members (r:1 w:0) @@ -111,10 +91,10 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - // Minimum execution time: 34_734 nanoseconds. - Weight::from_ref_time(37_652_708 as u64) - // Standard Error: 1_270 - .saturating_add(Weight::from_ref_time(183_078 as u64).saturating_mul(p as u64)) + // Minimum execution time: 23_000 nanoseconds. + Weight::from_ref_time(26_045_752 as u64) + // Standard Error: 2_154 + .saturating_add(Weight::from_ref_time(61_220 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -123,18 +103,15 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:1 w:0) // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: AllianceMotion ProposalOf (r:0 w:1) - /// The range of component `x` is `[2, 10]`. - /// The range of component `y` is `[2, 90]`. + /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - // Minimum execution time: 50_147 nanoseconds. - Weight::from_ref_time(42_719_616 as u64) - // Standard Error: 19_981 - .saturating_add(Weight::from_ref_time(188_796 as u64).saturating_mul(x as u64)) - // Standard Error: 1_947 - .saturating_add(Weight::from_ref_time(95_998 as u64).saturating_mul(y as u64)) - // Standard Error: 1_739 - .saturating_add(Weight::from_ref_time(177_837 as u64).saturating_mul(p as u64)) + fn close_early_disapproved(m: u32, p: u32, ) -> Weight { + // Minimum execution time: 30_000 nanoseconds. + Weight::from_ref_time(25_697_866 as u64) + // Standard Error: 3_827 + .saturating_add(Weight::from_ref_time(48_360 as u64).saturating_mul(m as u64)) + // Standard Error: 3_731 + .saturating_add(Weight::from_ref_time(116_922 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -144,20 +121,17 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Proposals (r:1 w:1) /// The range of component `b` is `[1, 1024]`. - /// The range of component `x` is `[2, 10]`. - /// The range of component `y` is `[2, 90]`. + /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - // Minimum execution time: 59_495 nanoseconds. - Weight::from_ref_time(53_137_721 as u64) - // Standard Error: 138 - .saturating_add(Weight::from_ref_time(1_979 as u64).saturating_mul(b as u64)) - // Standard Error: 16_388 - .saturating_add(Weight::from_ref_time(8_198 as u64).saturating_mul(x as u64)) - // Standard Error: 1_599 - .saturating_add(Weight::from_ref_time(86_577 as u64).saturating_mul(y as u64)) - // Standard Error: 1_428 - .saturating_add(Weight::from_ref_time(215_905 as u64).saturating_mul(p as u64)) + fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Minimum execution time: 34_000 nanoseconds. + Weight::from_ref_time(30_725_464 as u64) + // Standard Error: 370 + .saturating_add(Weight::from_ref_time(2_367 as u64).saturating_mul(b as u64)) + // Standard Error: 3_920 + .saturating_add(Weight::from_ref_time(40_710 as u64).saturating_mul(m as u64)) + // Standard Error: 3_822 + .saturating_add(Weight::from_ref_time(111_866 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -167,16 +141,15 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Prime (r:1 w:0) // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: AllianceMotion ProposalOf (r:0 w:1) - /// The range of component `x` is `[2, 10]`. - /// The range of component `y` is `[2, 90]`. + /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. - fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - // Minimum execution time: 52_405 nanoseconds. - Weight::from_ref_time(44_494_732 as u64) - // Standard Error: 1_759 - .saturating_add(Weight::from_ref_time(118_517 as u64).saturating_mul(y as u64)) - // Standard Error: 1_572 - .saturating_add(Weight::from_ref_time(198_256 as u64).saturating_mul(p as u64)) + fn close_disapproved(m: u32, p: u32, ) -> Weight { + // Minimum execution time: 31_000 nanoseconds. + Weight::from_ref_time(29_444_599 as u64) + // Standard Error: 4_043 + .saturating_add(Weight::from_ref_time(48_928 as u64).saturating_mul(m as u64)) + // Standard Error: 3_994 + .saturating_add(Weight::from_ref_time(76_527 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -187,39 +160,33 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: AllianceMotion ProposalOf (r:0 w:1) /// The range of component `b` is `[1, 1024]`. - /// The range of component `x` is `[2, 10]`. - /// The range of component `y` is `[2, 90]`. + /// The range of component `m` is `[5, 100]`. /// The range of component `p` is `[1, 100]`. - fn close_approved(b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - // Minimum execution time: 52_737 nanoseconds. - Weight::from_ref_time(45_874_458 as u64) - // Standard Error: 140 - .saturating_add(Weight::from_ref_time(601 as u64).saturating_mul(b as u64)) - // Standard Error: 1_623 - .saturating_add(Weight::from_ref_time(88_372 as u64).saturating_mul(y as u64)) - // Standard Error: 1_449 - .saturating_add(Weight::from_ref_time(197_595 as u64).saturating_mul(p as u64)) + fn close_approved(_b: u32, m: u32, p: u32, ) -> Weight { + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(32_315_075 as u64) + // Standard Error: 4_502 + .saturating_add(Weight::from_ref_time(43_205 as u64).saturating_mul(m as u64)) + // Standard Error: 4_340 + .saturating_add(Weight::from_ref_time(101_872 as u64).saturating_mul(p as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } - // Storage: Alliance Members (r:3 w:3) + // Storage: Alliance Members (r:2 w:2) // Storage: AllianceMotion Members (r:1 w:1) - /// The range of component `x` is `[1, 10]`. - /// The range of component `y` is `[0, 90]`. + /// The range of component `m` is `[1, 100]`. /// The range of component `z` is `[0, 100]`. - fn init_members(x: u32, y: u32, z: u32, ) -> Weight { - // Minimum execution time: 48_821 nanoseconds. - Weight::from_ref_time(32_972_152 as u64) - // Standard Error: 17_618 - .saturating_add(Weight::from_ref_time(230_451 as u64).saturating_mul(x as u64)) - // Standard Error: 1_865 - .saturating_add(Weight::from_ref_time(172_532 as u64).saturating_mul(y as u64)) - // Standard Error: 1_682 - .saturating_add(Weight::from_ref_time(145_258 as u64).saturating_mul(z as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + fn init_members(m: u32, z: u32, ) -> Weight { + // Minimum execution time: 22_000 nanoseconds. + Weight::from_ref_time(13_523_882 as u64) + // Standard Error: 1_823 + .saturating_add(Weight::from_ref_time(91_625 as u64).saturating_mul(m as u64)) + // Standard Error: 1_802 + .saturating_add(Weight::from_ref_time(98_184 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } - // Storage: Alliance Members (r:3 w:3) + // Storage: Alliance Members (r:2 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) // Storage: Alliance DepositOf (r:101 w:50) // Storage: System Account (r:50 w:50) @@ -229,67 +196,67 @@ impl WeightInfo for SubstrateWeight { /// The range of component `y` is `[0, 100]`. /// The range of component `z` is `[0, 50]`. fn disband(x: u32, y: u32, z: u32, ) -> Weight { - // Minimum execution time: 256_235 nanoseconds. - Weight::from_ref_time(258_695_000 as u64) - // Standard Error: 19_643 - .saturating_add(Weight::from_ref_time(436_821 as u64).saturating_mul(x as u64)) - // Standard Error: 19_549 - .saturating_add(Weight::from_ref_time(496_858 as u64).saturating_mul(y as u64)) - // Standard Error: 39_062 - .saturating_add(Weight::from_ref_time(9_169_692 as u64).saturating_mul(z as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + // Minimum execution time: 145_000 nanoseconds. + Weight::from_ref_time(147_000_000 as u64) + // Standard Error: 13_290 + .saturating_add(Weight::from_ref_time(304_371 as u64).saturating_mul(x as u64)) + // Standard Error: 13_226 + .saturating_add(Weight::from_ref_time(330_798 as u64).saturating_mul(y as u64)) + // Standard Error: 26_428 + .saturating_add(Weight::from_ref_time(7_207_748 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(x as u64))) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(y as u64))) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(z as u64))) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(z as u64))) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - // Minimum execution time: 19_205 nanoseconds. - Weight::from_ref_time(19_502_000 as u64) + // Minimum execution time: 11_000 nanoseconds. + Weight::from_ref_time(12_000_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - // Minimum execution time: 22_562 nanoseconds. - Weight::from_ref_time(22_842_000 as u64) + // Minimum execution time: 13_000 nanoseconds. + Weight::from_ref_time(14_000_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - // Minimum execution time: 23_773 nanoseconds. - Weight::from_ref_time(24_212_000 as u64) + // Minimum execution time: 14_000 nanoseconds. + Weight::from_ref_time(14_000_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } - // Storage: Alliance Members (r:4 w:1) + // Storage: Alliance Members (r:3 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - // Minimum execution time: 57_709 nanoseconds. - Weight::from_ref_time(59_155_000 as u64) - .saturating_add(T::DbWeight::get().reads(6 as u64)) + // Minimum execution time: 39_000 nanoseconds. + Weight::from_ref_time(41_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } - // Storage: Alliance Members (r:4 w:1) + // Storage: Alliance Members (r:3 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - // Minimum execution time: 44_576 nanoseconds. - Weight::from_ref_time(45_162_000 as u64) - .saturating_add(T::DbWeight::get().reads(5 as u64)) + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(30_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } - // Storage: Alliance Members (r:3 w:2) + // Storage: Alliance Members (r:2 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - // Minimum execution time: 38_913 nanoseconds. - Weight::from_ref_time(39_637_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + // Minimum execution time: 23_000 nanoseconds. + Weight::from_ref_time(24_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Alliance Members (r:4 w:2) @@ -298,8 +265,8 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - // Minimum execution time: 42_947 nanoseconds. - Weight::from_ref_time(43_414_000 as u64) + // Minimum execution time: 31_000 nanoseconds. + Weight::from_ref_time(32_000_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -308,8 +275,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - // Minimum execution time: 46_281 nanoseconds. - Weight::from_ref_time(46_703_000 as u64) + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(30_000_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -320,8 +287,8 @@ impl WeightInfo for SubstrateWeight { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - // Minimum execution time: 65_274 nanoseconds. - Weight::from_ref_time(65_762_000 as u64) + // Minimum execution time: 45_000 nanoseconds. + Weight::from_ref_time(47_000_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -330,12 +297,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - // Minimum execution time: 17_396 nanoseconds. - Weight::from_ref_time(17_638_000 as u64) - // Standard Error: 2_602 - .saturating_add(Weight::from_ref_time(1_286_177 as u64).saturating_mul(n as u64)) - // Standard Error: 1_019 - .saturating_add(Weight::from_ref_time(70_947 as u64).saturating_mul(l as u64)) + // Minimum execution time: 9_000 nanoseconds. + Weight::from_ref_time(9_512_816 as u64) + // Standard Error: 2_976 + .saturating_add(Weight::from_ref_time(560_175 as u64).saturating_mul(n as u64)) + // Standard Error: 1_169 + .saturating_add(Weight::from_ref_time(24_530 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -343,16 +310,24 @@ impl WeightInfo for SubstrateWeight { // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. - fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - // Minimum execution time: 17_446 nanoseconds. - Weight::from_ref_time(17_725_000 as u64) - // Standard Error: 163_579 - .saturating_add(Weight::from_ref_time(12_823_232 as u64).saturating_mul(n as u64)) - // Standard Error: 64_064 - .saturating_add(Weight::from_ref_time(496_642 as u64).saturating_mul(l as u64)) + fn remove_unscrupulous_items(n: u32, _l: u32, ) -> Weight { + // Minimum execution time: 10_000 nanoseconds. + Weight::from_ref_time(10_000_000 as u64) + // Standard Error: 94_049 + .saturating_add(Weight::from_ref_time(10_887_604 as u64).saturating_mul(n as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } + // Storage: Alliance Members (r:3 w:2) + // Storage: AllianceMotion Proposals (r:1 w:0) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + fn abdicate_fellow_status() -> Weight { + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(30_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) + } } // For backwards compatibility and tests @@ -363,31 +338,29 @@ impl WeightInfo for () { // Storage: AllianceMotion ProposalCount (r:1 w:1) // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `b` is `[1, 1024]`. - /// The range of component `x` is `[2, 10]`. - /// The range of component `y` is `[0, 90]`. + /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. - fn propose_proposed(_b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - // Minimum execution time: 43_720 nanoseconds. - Weight::from_ref_time(44_766_307 as u64) - // Standard Error: 2_522 - .saturating_add(Weight::from_ref_time(54_721 as u64).saturating_mul(y as u64)) - // Standard Error: 2_301 - .saturating_add(Weight::from_ref_time(173_300 as u64).saturating_mul(p as u64)) + fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { + // Minimum execution time: 23_000 nanoseconds. + Weight::from_ref_time(24_357_172 as u64) + // Standard Error: 428 + .saturating_add(Weight::from_ref_time(233 as u64).saturating_mul(b as u64)) + // Standard Error: 4_474 + .saturating_add(Weight::from_ref_time(48_024 as u64).saturating_mul(m as u64)) + // Standard Error: 4_418 + .saturating_add(Weight::from_ref_time(97_604 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } - // Storage: Alliance Members (r:2 w:0) + // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) - /// The range of component `x` is `[3, 10]`. - /// The range of component `y` is `[2, 90]`. - fn vote(x: u32, y: u32, ) -> Weight { - // Minimum execution time: 46_984 nanoseconds. - Weight::from_ref_time(46_837_255 as u64) - // Standard Error: 32_860 - .saturating_add(Weight::from_ref_time(273_691 as u64).saturating_mul(x as u64)) - // Standard Error: 2_781 - .saturating_add(Weight::from_ref_time(126_964 as u64).saturating_mul(y as u64)) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) + /// The range of component `m` is `[5, 100]`. + fn vote(m: u32, ) -> Weight { + // Minimum execution time: 24_000 nanoseconds. + Weight::from_ref_time(26_617_201 as u64) + // Standard Error: 4_280 + .saturating_add(Weight::from_ref_time(43_152 as u64).saturating_mul(m as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Members (r:1 w:0) @@ -396,10 +369,10 @@ impl WeightInfo for () { // Storage: AllianceMotion Voting (r:0 w:1) /// The range of component `p` is `[1, 100]`. fn veto(p: u32, ) -> Weight { - // Minimum execution time: 34_734 nanoseconds. - Weight::from_ref_time(37_652_708 as u64) - // Standard Error: 1_270 - .saturating_add(Weight::from_ref_time(183_078 as u64).saturating_mul(p as u64)) + // Minimum execution time: 23_000 nanoseconds. + Weight::from_ref_time(26_045_752 as u64) + // Standard Error: 2_154 + .saturating_add(Weight::from_ref_time(61_220 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -408,18 +381,15 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:1 w:0) // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: AllianceMotion ProposalOf (r:0 w:1) - /// The range of component `x` is `[2, 10]`. - /// The range of component `y` is `[2, 90]`. + /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(x: u32, y: u32, p: u32, ) -> Weight { - // Minimum execution time: 50_147 nanoseconds. - Weight::from_ref_time(42_719_616 as u64) - // Standard Error: 19_981 - .saturating_add(Weight::from_ref_time(188_796 as u64).saturating_mul(x as u64)) - // Standard Error: 1_947 - .saturating_add(Weight::from_ref_time(95_998 as u64).saturating_mul(y as u64)) - // Standard Error: 1_739 - .saturating_add(Weight::from_ref_time(177_837 as u64).saturating_mul(p as u64)) + fn close_early_disapproved(m: u32, p: u32, ) -> Weight { + // Minimum execution time: 30_000 nanoseconds. + Weight::from_ref_time(25_697_866 as u64) + // Standard Error: 3_827 + .saturating_add(Weight::from_ref_time(48_360 as u64).saturating_mul(m as u64)) + // Standard Error: 3_731 + .saturating_add(Weight::from_ref_time(116_922 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -429,20 +399,17 @@ impl WeightInfo for () { // Storage: AllianceMotion ProposalOf (r:1 w:1) // Storage: AllianceMotion Proposals (r:1 w:1) /// The range of component `b` is `[1, 1024]`. - /// The range of component `x` is `[2, 10]`. - /// The range of component `y` is `[2, 90]`. + /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, x: u32, y: u32, p: u32, ) -> Weight { - // Minimum execution time: 59_495 nanoseconds. - Weight::from_ref_time(53_137_721 as u64) - // Standard Error: 138 - .saturating_add(Weight::from_ref_time(1_979 as u64).saturating_mul(b as u64)) - // Standard Error: 16_388 - .saturating_add(Weight::from_ref_time(8_198 as u64).saturating_mul(x as u64)) - // Standard Error: 1_599 - .saturating_add(Weight::from_ref_time(86_577 as u64).saturating_mul(y as u64)) - // Standard Error: 1_428 - .saturating_add(Weight::from_ref_time(215_905 as u64).saturating_mul(p as u64)) + fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Minimum execution time: 34_000 nanoseconds. + Weight::from_ref_time(30_725_464 as u64) + // Standard Error: 370 + .saturating_add(Weight::from_ref_time(2_367 as u64).saturating_mul(b as u64)) + // Standard Error: 3_920 + .saturating_add(Weight::from_ref_time(40_710 as u64).saturating_mul(m as u64)) + // Standard Error: 3_822 + .saturating_add(Weight::from_ref_time(111_866 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -452,16 +419,15 @@ impl WeightInfo for () { // Storage: AllianceMotion Prime (r:1 w:0) // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: AllianceMotion ProposalOf (r:0 w:1) - /// The range of component `x` is `[2, 10]`. - /// The range of component `y` is `[2, 90]`. + /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. - fn close_disapproved(_x: u32, y: u32, p: u32, ) -> Weight { - // Minimum execution time: 52_405 nanoseconds. - Weight::from_ref_time(44_494_732 as u64) - // Standard Error: 1_759 - .saturating_add(Weight::from_ref_time(118_517 as u64).saturating_mul(y as u64)) - // Standard Error: 1_572 - .saturating_add(Weight::from_ref_time(198_256 as u64).saturating_mul(p as u64)) + fn close_disapproved(m: u32, p: u32, ) -> Weight { + // Minimum execution time: 31_000 nanoseconds. + Weight::from_ref_time(29_444_599 as u64) + // Standard Error: 4_043 + .saturating_add(Weight::from_ref_time(48_928 as u64).saturating_mul(m as u64)) + // Standard Error: 3_994 + .saturating_add(Weight::from_ref_time(76_527 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -472,39 +438,33 @@ impl WeightInfo for () { // Storage: AllianceMotion Proposals (r:1 w:1) // Storage: AllianceMotion ProposalOf (r:0 w:1) /// The range of component `b` is `[1, 1024]`. - /// The range of component `x` is `[2, 10]`. - /// The range of component `y` is `[2, 90]`. + /// The range of component `m` is `[5, 100]`. /// The range of component `p` is `[1, 100]`. - fn close_approved(b: u32, _x: u32, y: u32, p: u32, ) -> Weight { - // Minimum execution time: 52_737 nanoseconds. - Weight::from_ref_time(45_874_458 as u64) - // Standard Error: 140 - .saturating_add(Weight::from_ref_time(601 as u64).saturating_mul(b as u64)) - // Standard Error: 1_623 - .saturating_add(Weight::from_ref_time(88_372 as u64).saturating_mul(y as u64)) - // Standard Error: 1_449 - .saturating_add(Weight::from_ref_time(197_595 as u64).saturating_mul(p as u64)) + fn close_approved(_b: u32, m: u32, p: u32, ) -> Weight { + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(32_315_075 as u64) + // Standard Error: 4_502 + .saturating_add(Weight::from_ref_time(43_205 as u64).saturating_mul(m as u64)) + // Standard Error: 4_340 + .saturating_add(Weight::from_ref_time(101_872 as u64).saturating_mul(p as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } - // Storage: Alliance Members (r:3 w:3) + // Storage: Alliance Members (r:2 w:2) // Storage: AllianceMotion Members (r:1 w:1) - /// The range of component `x` is `[1, 10]`. - /// The range of component `y` is `[0, 90]`. + /// The range of component `m` is `[1, 100]`. /// The range of component `z` is `[0, 100]`. - fn init_members(x: u32, y: u32, z: u32, ) -> Weight { - // Minimum execution time: 48_821 nanoseconds. - Weight::from_ref_time(32_972_152 as u64) - // Standard Error: 17_618 - .saturating_add(Weight::from_ref_time(230_451 as u64).saturating_mul(x as u64)) - // Standard Error: 1_865 - .saturating_add(Weight::from_ref_time(172_532 as u64).saturating_mul(y as u64)) - // Standard Error: 1_682 - .saturating_add(Weight::from_ref_time(145_258 as u64).saturating_mul(z as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + fn init_members(m: u32, z: u32, ) -> Weight { + // Minimum execution time: 22_000 nanoseconds. + Weight::from_ref_time(13_523_882 as u64) + // Standard Error: 1_823 + .saturating_add(Weight::from_ref_time(91_625 as u64).saturating_mul(m as u64)) + // Standard Error: 1_802 + .saturating_add(Weight::from_ref_time(98_184 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } - // Storage: Alliance Members (r:3 w:3) + // Storage: Alliance Members (r:2 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) // Storage: Alliance DepositOf (r:101 w:50) // Storage: System Account (r:50 w:50) @@ -514,67 +474,67 @@ impl WeightInfo for () { /// The range of component `y` is `[0, 100]`. /// The range of component `z` is `[0, 50]`. fn disband(x: u32, y: u32, z: u32, ) -> Weight { - // Minimum execution time: 256_235 nanoseconds. - Weight::from_ref_time(258_695_000 as u64) - // Standard Error: 19_643 - .saturating_add(Weight::from_ref_time(436_821 as u64).saturating_mul(x as u64)) - // Standard Error: 19_549 - .saturating_add(Weight::from_ref_time(496_858 as u64).saturating_mul(y as u64)) - // Standard Error: 39_062 - .saturating_add(Weight::from_ref_time(9_169_692 as u64).saturating_mul(z as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + // Minimum execution time: 145_000 nanoseconds. + Weight::from_ref_time(147_000_000 as u64) + // Standard Error: 13_290 + .saturating_add(Weight::from_ref_time(304_371 as u64).saturating_mul(x as u64)) + // Standard Error: 13_226 + .saturating_add(Weight::from_ref_time(330_798 as u64).saturating_mul(y as u64)) + // Standard Error: 26_428 + .saturating_add(Weight::from_ref_time(7_207_748 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(x as u64))) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(y as u64))) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(z as u64))) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(z as u64))) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - // Minimum execution time: 19_205 nanoseconds. - Weight::from_ref_time(19_502_000 as u64) + // Minimum execution time: 11_000 nanoseconds. + Weight::from_ref_time(12_000_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - // Minimum execution time: 22_562 nanoseconds. - Weight::from_ref_time(22_842_000 as u64) + // Minimum execution time: 13_000 nanoseconds. + Weight::from_ref_time(14_000_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - // Minimum execution time: 23_773 nanoseconds. - Weight::from_ref_time(24_212_000 as u64) + // Minimum execution time: 14_000 nanoseconds. + Weight::from_ref_time(14_000_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } - // Storage: Alliance Members (r:4 w:1) + // Storage: Alliance Members (r:3 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Alliance DepositOf (r:0 w:1) fn join_alliance() -> Weight { - // Minimum execution time: 57_709 nanoseconds. - Weight::from_ref_time(59_155_000 as u64) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) + // Minimum execution time: 39_000 nanoseconds. + Weight::from_ref_time(41_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } - // Storage: Alliance Members (r:4 w:1) + // Storage: Alliance Members (r:3 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> Weight { - // Minimum execution time: 44_576 nanoseconds. - Weight::from_ref_time(45_162_000 as u64) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(30_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } - // Storage: Alliance Members (r:3 w:2) + // Storage: Alliance Members (r:2 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn elevate_ally() -> Weight { - // Minimum execution time: 38_913 nanoseconds. - Weight::from_ref_time(39_637_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + // Minimum execution time: 23_000 nanoseconds. + Weight::from_ref_time(24_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Alliance Members (r:4 w:2) @@ -583,8 +543,8 @@ impl WeightInfo for () { // Storage: AllianceMotion Prime (r:0 w:1) // Storage: Alliance RetiringMembers (r:0 w:1) fn give_retirement_notice() -> Weight { - // Minimum execution time: 42_947 nanoseconds. - Weight::from_ref_time(43_414_000 as u64) + // Minimum execution time: 31_000 nanoseconds. + Weight::from_ref_time(32_000_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } @@ -593,8 +553,8 @@ impl WeightInfo for () { // Storage: Alliance DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) fn retire() -> Weight { - // Minimum execution time: 46_281 nanoseconds. - Weight::from_ref_time(46_703_000 as u64) + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(30_000_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -605,8 +565,8 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - // Minimum execution time: 65_274 nanoseconds. - Weight::from_ref_time(65_762_000 as u64) + // Minimum execution time: 45_000 nanoseconds. + Weight::from_ref_time(47_000_000 as u64) .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } @@ -615,12 +575,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - // Minimum execution time: 17_396 nanoseconds. - Weight::from_ref_time(17_638_000 as u64) - // Standard Error: 2_602 - .saturating_add(Weight::from_ref_time(1_286_177 as u64).saturating_mul(n as u64)) - // Standard Error: 1_019 - .saturating_add(Weight::from_ref_time(70_947 as u64).saturating_mul(l as u64)) + // Minimum execution time: 9_000 nanoseconds. + Weight::from_ref_time(9_512_816 as u64) + // Standard Error: 2_976 + .saturating_add(Weight::from_ref_time(560_175 as u64).saturating_mul(n as u64)) + // Standard Error: 1_169 + .saturating_add(Weight::from_ref_time(24_530 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -628,14 +588,22 @@ impl WeightInfo for () { // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. - fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - // Minimum execution time: 17_446 nanoseconds. - Weight::from_ref_time(17_725_000 as u64) - // Standard Error: 163_579 - .saturating_add(Weight::from_ref_time(12_823_232 as u64).saturating_mul(n as u64)) - // Standard Error: 64_064 - .saturating_add(Weight::from_ref_time(496_642 as u64).saturating_mul(l as u64)) + fn remove_unscrupulous_items(n: u32, _l: u32, ) -> Weight { + // Minimum execution time: 10_000 nanoseconds. + Weight::from_ref_time(10_000_000 as u64) + // Standard Error: 94_049 + .saturating_add(Weight::from_ref_time(10_887_604 as u64).saturating_mul(n as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } + // Storage: Alliance Members (r:3 w:2) + // Storage: AllianceMotion Proposals (r:1 w:0) + // Storage: AllianceMotion Members (r:0 w:1) + // Storage: AllianceMotion Prime (r:0 w:1) + fn abdicate_fellow_status() -> Weight { + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(30_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + } } From a1dc9d8ff3a62580491d4c38c06251d5a3ca99f6 Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 25 Nov 2022 16:06:04 +0100 Subject: [PATCH 1409/1472] Add total nb to trie migration rpc (#12770) * Add total nb to trie migration rpc * fix and format * Use struct instead of tuple * fixes Co-authored-by: parity-processbot <> --- frame/state-trie-migration/src/lib.rs | 23 ++++----- .../rpc/state-trie-migration-rpc/src/lib.rs | 47 ++++++++++++------- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 5255d4f6f3800..aab92e678e88c 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -1606,7 +1606,6 @@ mod test { pub(crate) mod remote_tests { use crate::{AutoLimits, MigrationLimits, Pallet as StateTrieMigration, LOG_TARGET}; use codec::Encode; - use frame_benchmarking::Zero; use frame_support::{ traits::{Get, Hooks}, weights::Weight, @@ -1614,7 +1613,7 @@ pub(crate) mod remote_tests { use frame_system::Pallet as System; use remote_externalities::Mode; use sp_core::H256; - use sp_runtime::traits::{Block as BlockT, HashFor, Header as _, One}; + use sp_runtime::traits::{Block as BlockT, HashFor, Header as _, One, Zero}; use thousands::Separable; #[allow(dead_code)] @@ -1663,18 +1662,20 @@ pub(crate) mod remote_tests { // set the version to 1, as if the upgrade happened. ext.state_version = sp_core::storage::StateVersion::V1; - let (top_left, child_left) = + let status = substrate_state_trie_migration_rpc::migration_status(&ext.as_backend()).unwrap(); assert!( - top_left > 0, + status.top_remaining_to_migrate > 0, "no node needs migrating, this probably means that state was initialized with `StateVersion::V1`", ); log::info!( target: LOG_TARGET, - "initial check: top_left: {}, child_left: {}", - top_left.separate_with_commas(), - child_left.separate_with_commas(), + "initial check: top_left: {}, child_left: {}, total_top {}, total_child {}", + status.top_remaining_to_migrate.separate_with_commas(), + status.child_remaining_to_migrate.separate_with_commas(), + status.total_top.separate_with_commas(), + status.total_child.separate_with_commas(), ); loop { @@ -1722,17 +1723,17 @@ pub(crate) mod remote_tests { ) }); - let (top_left, child_left) = + let status = substrate_state_trie_migration_rpc::migration_status(&ext.as_backend()).unwrap(); - assert_eq!(top_left, 0); - assert_eq!(child_left, 0); + assert_eq!(status.top_remaining_to_migrate, 0); + assert_eq!(status.child_remaining_to_migrate, 0); } } #[cfg(all(test, feature = "remote-test"))] mod remote_tests_local { use super::{ - mock::{Call as MockCall, *}, + mock::{RuntimeCall as MockCall, *}, remote_tests::run_with_limits, *, }; diff --git a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index ab180c7d45d5b..2140ee8845625 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -44,30 +44,33 @@ use trie_db::{ fn count_migrate<'a, H: Hasher>( storage: &'a dyn trie_db::HashDBRef>, root: &'a H::Out, -) -> std::result::Result<(u64, TrieDB<'a, 'a, H>), String> { +) -> std::result::Result<(u64, u64, TrieDB<'a, 'a, H>), String> { let mut nb = 0u64; + let mut total_nb = 0u64; let trie = TrieDBBuilder::new(storage, root).build(); let iter_node = TrieDBNodeIterator::new(&trie).map_err(|e| format!("TrieDB node iterator error: {}", e))?; for node in iter_node { let node = node.map_err(|e| format!("TrieDB node iterator error: {}", e))?; match node.2.node_plan() { - NodePlan::Leaf { value, .. } | NodePlan::NibbledBranch { value: Some(value), .. } => + NodePlan::Leaf { value, .. } | NodePlan::NibbledBranch { value: Some(value), .. } => { + total_nb += 1; if let ValuePlan::Inline(range) = value { if (range.end - range.start) as u32 >= sp_core::storage::TRIE_VALUE_NODE_THRESHOLD { nb += 1; } - }, + } + }, _ => (), } } - Ok((nb, trie)) + Ok((nb, total_nb, trie)) } /// Check trie migration status. -pub fn migration_status(backend: &B) -> std::result::Result<(u64, u64), String> +pub fn migration_status(backend: &B) -> std::result::Result where H: Hasher, H::Out: codec::Codec, @@ -75,9 +78,10 @@ where { let trie_backend = backend.as_trie_backend(); let essence = trie_backend.essence(); - let (nb_to_migrate, trie) = count_migrate(essence, essence.root())?; + let (top_remaining_to_migrate, total_top, trie) = count_migrate(essence, essence.root())?; - let mut nb_to_migrate_child = 0; + let mut child_remaining_to_migrate = 0; + let mut total_child = 0; let mut child_roots: Vec<(ChildInfo, Vec)> = Vec::new(); // get all child trie roots for key_value in trie.iter().map_err(|e| format!("TrieDB node iterator error: {}", e))? { @@ -94,18 +98,32 @@ where let storage = KeySpacedDB::new(essence, child_info.keyspace()); child_root.as_mut()[..].copy_from_slice(&root[..]); - nb_to_migrate_child += count_migrate(&storage, &child_root)?.0; + let (nb, total_top, _) = count_migrate(&storage, &child_root)?; + child_remaining_to_migrate += nb; + total_child += total_top; } - Ok((nb_to_migrate, nb_to_migrate_child)) + Ok(MigrationStatusResult { + top_remaining_to_migrate, + child_remaining_to_migrate, + total_top, + total_child, + }) } +/// Current state migration status. #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct MigrationStatusResult { - top_remaining_to_migrate: u64, - child_remaining_to_migrate: u64, + /// Number of top items that should migrate. + pub top_remaining_to_migrate: u64, + /// Number of child items that should migrate. + pub child_remaining_to_migrate: u64, + /// Number of top items that we will iterate on. + pub total_top: u64, + /// Number of child items that we will iterate on. + pub total_child: u64, } /// Migration RPC methods. @@ -146,12 +164,7 @@ where let hash = at.unwrap_or_else(|| self.client.info().best_hash); let state = self.backend.state_at(hash).map_err(error_into_rpc_err)?; - let (top, child) = migration_status(&state).map_err(error_into_rpc_err)?; - - Ok(MigrationStatusResult { - top_remaining_to_migrate: top, - child_remaining_to_migrate: child, - }) + migration_status(&state).map_err(error_into_rpc_err) } } From d11846b515d33e5ebb7667e8b6bde2ac6f28f33c Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Sat, 26 Nov 2022 04:29:56 +1300 Subject: [PATCH 1410/1472] add EnsureWithSuccess (#12775) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add EnsureWithSuccess * Apply suggestions from code review Co-authored-by: Bastian Köcher * add docs Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> --- bin/node/runtime/src/lib.rs | 5 +++-- frame/system/src/lib.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 88b0687c76b02..1df668cd5f972 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -44,7 +44,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureRoot, EnsureRootWithSuccess, EnsureSigned, + EnsureRoot, EnsureRootWithSuccess, EnsureSigned, EnsureWithSuccess, }; pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; @@ -1076,6 +1076,7 @@ parameter_types! { pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); pub const MaximumReasonLength: u32 = 300; pub const MaxApprovals: u32 = 100; + pub const MaxBalance: Balance = Balance::max_value(); } impl pallet_treasury::Config for Runtime { @@ -1100,7 +1101,7 @@ impl pallet_treasury::Config for Runtime { type SpendFunds = Bounties; type WeightInfo = pallet_treasury::weights::SubstrateWeight; type MaxApprovals = MaxApprovals; - type SpendOrigin = frame_support::traits::NeverEnsureOrigin; + type SpendOrigin = EnsureWithSuccess, AccountId, MaxBalance>; } parameter_types! { diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 477ebb97fbd95..7c4c4683958e3 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -775,6 +775,7 @@ impl From for LastRuntimeUpgradeInfo { } } +/// Ensure the origin is Root. pub struct EnsureRoot(sp_std::marker::PhantomData); impl, O>> + From>, AccountId> EnsureOrigin for EnsureRoot @@ -793,6 +794,7 @@ impl, O>> + From>, Acco } } +/// Ensure the origin is Root and return the provided `Success` value. pub struct EnsureRootWithSuccess( sp_std::marker::PhantomData<(AccountId, Success)>, ); @@ -816,6 +818,31 @@ impl< } } +/// Ensure the origin is provided `Ensure` origin and return the provided `Success` value. +pub struct EnsureWithSuccess( + sp_std::marker::PhantomData<(Ensure, AccountId, Success)>, +); + +impl< + O: Into, O>> + From>, + Ensure: EnsureOrigin, + AccountId, + Success: TypedGet, + > EnsureOrigin for EnsureWithSuccess +{ + type Success = Success::Type; + + fn try_origin(o: O) -> Result { + Ensure::try_origin(o).map(|_| Success::get()) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ensure::try_successful_origin() + } +} + +/// Ensure the origin is any `Signed` origin. pub struct EnsureSigned(sp_std::marker::PhantomData); impl, O>> + From>, AccountId: Decode> EnsureOrigin for EnsureSigned @@ -836,6 +863,7 @@ impl, O>> + From>, Acco } } +/// Ensure the origin is `Signed` origin from the given `AccountId`. pub struct EnsureSignedBy(sp_std::marker::PhantomData<(Who, AccountId)>); impl< O: Into, O>> + From>, @@ -864,6 +892,7 @@ impl< } } +/// Ensure the origin is `None`. i.e. unsigned transaction. pub struct EnsureNone(sp_std::marker::PhantomData); impl, O>> + From>, AccountId> EnsureOrigin for EnsureNone @@ -882,6 +911,7 @@ impl, O>> + From>, Acco } } +/// Always fail. pub struct EnsureNever(sp_std::marker::PhantomData); impl EnsureOrigin for EnsureNever { type Success = T; From 39ef178c439e606e608b4b27d435b45e6692fa0a Mon Sep 17 00:00:00 2001 From: Vlad Date: Fri, 25 Nov 2022 21:39:21 +0000 Subject: [PATCH 1411/1472] Explicitly unset RUSTC_WRAPPER=sccache environment variable (#12771) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CI: Explicitly unset RUSTC_WRAPPER=sccache environment variable * Try with `rusty-cachier` disabled * Re-enable `rusty-cachier` and try with the staging image * Bring back `production` image * Sort crates before splitting them into groups (+ some improvements) (#12755) * sort crates before splitting them into groups this is useful so that crates always get routed to a specific group for a given version of the source code, which means that jobs for each batch can be reliably retried individually * more verbose output * misc improvements * put uniq after sort uniq filters by adjacent lines * shellcheck * rm useless backlashes * handle edge case of no crates detected * Revert "Sort crates before splitting them into groups (+ some improvements) (#12755)" This reverts commit fde839183a12a2bd51efc7143ebcddeed81ea6fa. Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d5b8cc89037a7..992a2d491ae02 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -106,6 +106,8 @@ default: .docker-env: image: "${CI_IMAGE}" before_script: + # TODO: remove unset invocation when we'll be free from 'ENV RUSTC_WRAPPER=sccache' & sccache itself in all images + - unset RUSTC_WRAPPER - !reference [.rust-info-script, script] - !reference [.rusty-cachier, before_script] - !reference [.pipeline-stopper-vars, script] From 2eb512874c0c246adbfe4df564bbb1b809a5851d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Sun, 27 Nov 2022 12:27:03 +0100 Subject: [PATCH 1412/1472] contracts: Don't put unstable functions in special module (#12781) * Don't put unstable functions in special module * Apply suggestions from code review Co-authored-by: Sasha Gryaznov * cargo fmt Co-authored-by: Sasha Gryaznov --- frame/contracts/Cargo.toml | 2 +- frame/contracts/README.md | 2 +- .../account_reentrance_count_call.wat | 2 +- frame/contracts/fixtures/call_runtime.wat | 2 +- .../fixtures/reentrance_count_call.wat | 2 +- .../reentrance_count_delegated_call.wat | 2 +- frame/contracts/proc-macro/src/lib.rs | 85 ++++++++++++------- frame/contracts/src/benchmarking/mod.rs | 8 +- frame/contracts/src/wasm/mod.rs | 8 +- 9 files changed, 66 insertions(+), 47 deletions(-) diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index cf9889ac0be77..fead0a414442f 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -87,6 +87,6 @@ runtime-benchmarks = [ "unstable-interface", ] try-runtime = ["frame-support/try-runtime"] -# Make contract callable functions marked as __unstable__ available. Do not enable +# Make contract callable functions marked as unstable available. Do not enable # on live chains as those are subject to change. unstable-interface = [] diff --git a/frame/contracts/README.md b/frame/contracts/README.md index 18d16889a3fe8..6b8e62e840b07 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -142,7 +142,7 @@ this pallet contains the concept of an unstable interface. Akin to the rust nigh it allows us to add new interfaces but mark them as unstable so that contract languages can experiment with them and give feedback before we stabilize those. -In order to access interfaces marked as `__unstable__` in `runtime.rs` one need to compile +In order to access interfaces marked as `#[unstable]` in `runtime.rs` one need to compile this crate with the `unstable-interface` feature enabled. It should be obvious that any live runtime should never be compiled with this feature: In addition to be subject to change or removal those interfaces do not have proper weights associated with them and diff --git a/frame/contracts/fixtures/account_reentrance_count_call.wat b/frame/contracts/fixtures/account_reentrance_count_call.wat index abb18e4d3d1f7..ab67890664870 100644 --- a/frame/contracts/fixtures/account_reentrance_count_call.wat +++ b/frame/contracts/fixtures/account_reentrance_count_call.wat @@ -4,7 +4,7 @@ (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_caller" (func $seal_caller (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) - (import "__unstable__" "account_reentrance_count" (func $account_reentrance_count (param i32) (result i32))) + (import "seal0" "account_reentrance_count" (func $account_reentrance_count (param i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 32) buffer where input is copied diff --git a/frame/contracts/fixtures/call_runtime.wat b/frame/contracts/fixtures/call_runtime.wat index 62fa08680a097..d3d08ee24541a 100644 --- a/frame/contracts/fixtures/call_runtime.wat +++ b/frame/contracts/fixtures/call_runtime.wat @@ -1,6 +1,6 @@ ;; This passes its input to `seal_call_runtime` and returns the return value to its caller. (module - (import "__unstable__" "call_runtime" (func $call_runtime (param i32 i32) (result i32))) + (import "seal0" "call_runtime" (func $call_runtime (param i32 i32) (result i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) diff --git a/frame/contracts/fixtures/reentrance_count_call.wat b/frame/contracts/fixtures/reentrance_count_call.wat index 0577314066f74..c6b529e2aff8b 100644 --- a/frame/contracts/fixtures/reentrance_count_call.wat +++ b/frame/contracts/fixtures/reentrance_count_call.wat @@ -4,7 +4,7 @@ (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_address" (func $seal_address (param i32 i32))) (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) - (import "__unstable__" "reentrance_count" (func $reentrance_count (result i32))) + (import "seal0" "reentrance_count" (func $reentrance_count (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 32) reserved for $seal_address output diff --git a/frame/contracts/fixtures/reentrance_count_delegated_call.wat b/frame/contracts/fixtures/reentrance_count_delegated_call.wat index 144df25d76835..b8219a8462ee2 100644 --- a/frame/contracts/fixtures/reentrance_count_delegated_call.wat +++ b/frame/contracts/fixtures/reentrance_count_delegated_call.wat @@ -4,7 +4,7 @@ (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) (import "seal0" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) - (import "__unstable__" "reentrance_count" (func $reentrance_count (result i32))) + (import "seal0" "reentrance_count" (func $reentrance_count (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 32) buffer where code hash is copied diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index 399a1b413f121..5f08b2a9d3081 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -157,6 +157,7 @@ struct HostFn { module: String, name: String, returns: HostFnReturn, + is_unstable: bool, } enum HostFnReturn { @@ -191,27 +192,34 @@ impl HostFn { }; // process attributes - let msg = "only #[version()] or #[unstable] attribute is allowed."; + let msg = + "only #[version()], #[unstable] and #[prefixed_alias] attributes are allowed."; let span = item.span(); let mut attrs = item.attrs.clone(); attrs.retain(|a| !(a.path.is_ident("doc") || a.path.is_ident("prefixed_alias"))); let name = item.sig.ident.to_string(); - let module = match attrs.len() { - 0 => Ok("seal0".to_string()), - 1 => { - let attr = &attrs[0]; - let ident = attr.path.get_ident().ok_or(err(span, msg))?.to_string(); - match ident.as_str() { - "version" => { - let ver: syn::LitInt = attr.parse_args()?; - Ok(format!("seal{}", ver.base10_parse::().map_err(|_| err(span, msg))?)) - }, - "unstable" => Ok("__unstable__".to_string()), - _ => Err(err(span, msg)), - } - }, - _ => Err(err(span, msg)), - }?; + let mut maybe_module = None; + let mut is_unstable = false; + while let Some(attr) = attrs.pop() { + let ident = attr.path.get_ident().ok_or(err(span, msg))?.to_string(); + match ident.as_str() { + "version" => { + if maybe_module.is_some() { + return Err(err(span, "#[version] can only be specified once")) + } + let ver: u8 = + attr.parse_args::().and_then(|lit| lit.base10_parse())?; + maybe_module = Some(format!("seal{}", ver)); + }, + "unstable" => { + if is_unstable { + return Err(err(span, "#[unstable] can only be specified once")) + } + is_unstable = true; + }, + _ => return Err(err(span, msg)), + } + } // process arguments: The first and second arg are treated differently (ctx, memory) // they must exist and be `ctx: _` and `memory: _`. @@ -299,7 +307,13 @@ impl HostFn { _ => Err(err(arg1.span(), &msg)), }?; - Ok(Self { item, module, name, returns }) + Ok(Self { + item, + module: maybe_module.unwrap_or_else(|| "seal0".to_string()), + name, + returns, + is_unstable, + }) }, _ => Err(err(span, &msg)), } @@ -423,9 +437,9 @@ fn expand_functions( f.returns.to_wasm_sig(), &f.item.sig.output ); - let unstable_feat = match module.as_str() { - "__unstable__" => quote! { #[cfg(feature = "unstable-interface")] }, - _ => quote! {}, + let unstable_feat = match f.is_unstable { + true => quote! { #[cfg(feature = "unstable-interface")] }, + false => quote! {}, }; // If we don't expand blocks (implementing for `()`) we change a few things: @@ -496,13 +510,15 @@ fn expand_functions( /// ```nocompile /// #[define_env] /// pub mod some_env { -/// fn some_host_fn(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<(), TrapReason> { +/// fn foo(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<(), TrapReason> { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// } /// ``` -/// This example will expand to the `some_host_fn()` defined in the wasm module named `seal0`. -/// To define a host function in `seal1` and `__unstable__` modules, it should be annotated with the +/// This example will expand to the `foo()` defined in the wasm module named `seal0`. This is +/// because the module `seal0` is the default when no module is specified. +/// +/// To define a host function in `seal2` and `seal3` modules, it should be annotated with the /// appropriate attribute as follows: /// /// ## Example @@ -510,17 +526,20 @@ fn expand_functions( /// ```nocompile /// #[define_env] /// pub mod some_env { -/// #[version(1)] -/// fn some_host_fn(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// #[version(2)] +/// fn foo(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// +/// #[version(3)] /// #[unstable] -/// fn some_host_fn(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// fn bar(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// } /// ``` +/// The function `bar` is additionally annotated with `unstable` which removes it from the stable +/// interface. Check out the README to learn about unstable functions. /// /// In legacy versions of pallet_contracts, it was a naming convention that all host functions had /// to be named with the `seal_` prefix. For the sake of backwards compatibility, each host function @@ -534,21 +553,21 @@ fn expand_functions( /// pub mod some_env { /// #[version(1)] /// #[prefixed_alias] -/// fn some_host_fn(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// fn foo(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// -/// #[unstable] -/// fn some_host_fn(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { +/// #[version(42)] +/// fn bar(ctx: _, memory: _, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result { /// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ()) /// } /// } /// ``` /// /// In this example, the following host functions will be generated by the macro: -/// - `some_host_fn()` in module `seal1`, -/// - `seal_some_host_fn()` in module `seal1`, -/// - `some_host_fn()` in module `__unstable__`. +/// - `foo()` in module `seal1`, +/// - `seal_foo()` in module `seal1`, +/// - `bar()` in module `seal42`. /// /// Only following return types are allowed for the host functions defined with the macro: /// - `Result<(), TrapReason>`, diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 2494a4cbebd55..ebb94b97416c4 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1366,7 +1366,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "take_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -1420,7 +1420,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "take_storage", params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), @@ -2090,7 +2090,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "reentrance_count", params: vec![], return_type: Some(ValueType::I32), @@ -2116,7 +2116,7 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "__unstable__", + module: "seal0", name: "account_reentrance_count", params: vec![ValueType::I32], return_type: Some(ValueType::I32), diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 86bc377b81307..6eaf0d37bef07 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -2277,7 +2277,7 @@ mod tests { #[cfg(feature = "unstable-interface")] const CODE_CALL_RUNTIME: &str = r#" (module - (import "__unstable__" "call_runtime" (func $call_runtime (param i32 i32) (result i32))) + (import "seal0" "call_runtime" (func $call_runtime (param i32 i32) (result i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) @@ -2592,7 +2592,7 @@ mod tests { (module (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "__unstable__" "take_storage" (func $take_storage (param i32 i32 i32 i32) (result i32))) + (import "seal0" "take_storage" (func $take_storage (param i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) ;; [0, 4) size of input buffer (160 bytes as we copy the key+len here) @@ -2898,7 +2898,7 @@ mod tests { fn reentrance_count_works() { const CODE: &str = r#" (module - (import "__unstable__" "reentrance_count" (func $reentrance_count (result i32))) + (import "seal0" "reentrance_count" (func $reentrance_count (result i32))) (import "env" "memory" (memory 1 1)) (func $assert (param i32) (block $ok @@ -2931,7 +2931,7 @@ mod tests { fn account_reentrance_count_works() { const CODE: &str = r#" (module - (import "__unstable__" "account_reentrance_count" (func $account_reentrance_count (param i32) (result i32))) + (import "seal0" "account_reentrance_count" (func $account_reentrance_count (param i32) (result i32))) (import "env" "memory" (memory 1 1)) (func $assert (param i32) (block $ok From a92005a5092ebe6a636c96dcae814f9a378f5940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 27 Nov 2022 16:34:07 +0100 Subject: [PATCH 1413/1472] ed25519_verify: Support using dalek for historical blocks (#12661) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ed25519_verify: Support using dalek for historical blocks The switch from `ed25519-dalek` to `ed25519-zebra` was actually a breaking change. `ed25519-zebra` is more permissive. To support historical blocks when syncing a chain this pull request introduces an externalities extension `UseDalekExt`. This extension is just used as a signaling mechanism to `ed25519_verify` to use `ed25519-dalek` when it is present. Together with `ExtensionBeforeBlock` it can be used to setup a node in way to sync historical blocks that require `ed25519-dalek`, because they included a transaction that verified differently as when using `ed25519-zebra`. This feature can be enabled in the following way. In the chain service file, directly after the client is created, the following code should be added: ``` use sc_client_api::ExecutorProvider; client.execution_extensions().set_extensions_factory( sc_client_api::execution_extensions::ExtensionBeforeBlock::::new(BLOCK_NUMBER_UNTIL_DALEK_SHOULD_BE_USED) ); ``` * Fix doc * More fixes * Update client/api/src/execution_extensions.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Fix merge and warning * Fix docs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- Cargo.lock | 2 + client/api/src/call_executor.rs | 23 ++-- client/api/src/execution_extensions.rs | 128 ++++++++++++++++---- client/finality-grandpa/src/lib.rs | 1 - client/rpc/src/state/state_full.rs | 1 - client/service/src/builder.rs | 2 +- client/service/src/client/call_executor.rs | 63 ++++++---- client/service/src/client/client.rs | 35 +++--- client/service/test/Cargo.toml | 1 + client/service/test/src/client/mod.rs | 40 +++++- client/tracing/src/lib.rs | 6 +- primitives/application-crypto/src/traits.rs | 4 +- primitives/externalities/src/extensions.rs | 22 +++- primitives/io/Cargo.toml | 2 + primitives/io/src/lib.rs | 69 ++++++++++- primitives/state-machine/src/lib.rs | 4 +- test-utils/client/src/lib.rs | 10 +- test-utils/runtime/src/lib.rs | 12 ++ 18 files changed, 325 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8c21b9830eea..3c627ee2f9823 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8667,6 +8667,7 @@ dependencies = [ "sp-consensus", "sp-core", "sp-externalities", + "sp-io", "sp-panic-handler", "sp-runtime", "sp-state-machine", @@ -9660,6 +9661,7 @@ name = "sp-io" version = "7.0.0" dependencies = [ "bytes", + "ed25519-dalek", "futures", "hash-db", "libsecp256k1", diff --git a/client/api/src/call_executor.rs b/client/api/src/call_executor.rs index 949fd16a30704..7a42385010c68 100644 --- a/client/api/src/call_executor.rs +++ b/client/api/src/call_executor.rs @@ -19,13 +19,12 @@ //! A method call executor interface. use sc_executor::{RuntimeVersion, RuntimeVersionOf}; -use sp_externalities::Extensions; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; -use sp_state_machine::{ExecutionManager, ExecutionStrategy, OverlayedChanges, StorageProof}; +use sp_state_machine::{ExecutionStrategy, OverlayedChanges, StorageProof}; use std::cell::RefCell; use crate::execution_extensions::ExecutionExtensions; -use sp_api::{ProofRecorder, StorageTransactionCache}; +use sp_api::{ExecutionContext, ProofRecorder, StorageTransactionCache}; /// Executor Provider pub trait ExecutorProvider { @@ -47,6 +46,9 @@ pub trait CallExecutor: RuntimeVersionOf { /// The backend used by the node. type Backend: crate::backend::Backend; + /// Returns the [`ExecutionExtensions`]. + fn execution_extensions(&self) -> &ExecutionExtensions; + /// Execute a call to a contract on top of state in a block of given hash. /// /// No changes are made. @@ -56,7 +58,6 @@ pub trait CallExecutor: RuntimeVersionOf { method: &str, call_data: &[u8], strategy: ExecutionStrategy, - extensions: Option, ) -> Result, sp_blockchain::Error>; /// Execute a contextual call on top of state in a block of a given hash. @@ -64,12 +65,7 @@ pub trait CallExecutor: RuntimeVersionOf { /// No changes are made. /// Before executing the method, passed header is installed as the current header /// of the execution context. - fn contextual_call< - EM: Fn( - Result, Self::Error>, - Result, Self::Error>, - ) -> Result, Self::Error>, - >( + fn contextual_call( &self, at: &BlockId, method: &str, @@ -80,12 +76,9 @@ pub trait CallExecutor: RuntimeVersionOf { StorageTransactionCache>::State>, >, >, - execution_manager: ExecutionManager, proof_recorder: &Option>, - extensions: Option, - ) -> sp_blockchain::Result> - where - ExecutionManager: Clone; + context: ExecutionContext, + ) -> sp_blockchain::Result>; /// Extract RuntimeVersion of given block /// diff --git a/client/api/src/execution_extensions.rs b/client/api/src/execution_extensions.rs index 07a483bc3eaf2..58c085a29a945 100644 --- a/client/api/src/execution_extensions.rs +++ b/client/api/src/execution_extensions.rs @@ -29,12 +29,18 @@ use sp_core::{ offchain::{self, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt}, ExecutionContext, }; -use sp_externalities::Extensions; +use sp_externalities::{Extension, Extensions}; use sp_keystore::{KeystoreExt, SyncCryptoStorePtr}; -use sp_runtime::{generic::BlockId, traits}; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, NumberFor}, +}; pub use sp_state_machine::ExecutionStrategy; use sp_state_machine::{DefaultHandler, ExecutionManager}; -use std::sync::{Arc, Weak}; +use std::{ + marker::PhantomData, + sync::{Arc, Weak}, +}; /// Execution strategies settings. #[derive(Debug, Clone)] @@ -63,18 +69,81 @@ impl Default for ExecutionStrategies { } } -/// Generate the starting set of ExternalitiesExtensions based upon the given capabilities -pub trait ExtensionsFactory: Send + Sync { - /// Make `Extensions` for given `Capabilities`. - fn extensions_for(&self, capabilities: offchain::Capabilities) -> Extensions; +/// Generate the starting set of [`Extensions`]. +/// +/// These [`Extensions`] are passed to the environment a runtime is executed in. +pub trait ExtensionsFactory: Send + Sync { + /// Create [`Extensions`] for the given input. + /// + /// - `block_hash`: The hash of the block in the context that extensions will be used. + /// - `block_number`: The number of the block in the context that extensions will be used. + /// - `capabilities`: The capabilities + fn extensions_for( + &self, + block_hash: Block::Hash, + block_number: NumberFor, + capabilities: offchain::Capabilities, + ) -> Extensions; } -impl ExtensionsFactory for () { - fn extensions_for(&self, _capabilities: offchain::Capabilities) -> Extensions { +impl ExtensionsFactory for () { + fn extensions_for( + &self, + _: Block::Hash, + _: NumberFor, + _capabilities: offchain::Capabilities, + ) -> Extensions { Extensions::new() } } +impl> ExtensionsFactory for Vec { + fn extensions_for( + &self, + block_hash: Block::Hash, + block_number: NumberFor, + capabilities: offchain::Capabilities, + ) -> Extensions { + let mut exts = Extensions::new(); + exts.extend(self.iter().map(|e| e.extensions_for(block_hash, block_number, capabilities))); + exts + } +} + +/// An [`ExtensionsFactory`] that registers an [`Extension`] before a certain block. +pub struct ExtensionBeforeBlock { + before: NumberFor, + _marker: PhantomData Ext>, +} + +impl ExtensionBeforeBlock { + /// Create the extension factory. + /// + /// - `before`: The block number until the extension should be registered. + pub fn new(before: NumberFor) -> Self { + Self { before, _marker: PhantomData } + } +} + +impl ExtensionsFactory + for ExtensionBeforeBlock +{ + fn extensions_for( + &self, + _: Block::Hash, + block_number: NumberFor, + _: offchain::Capabilities, + ) -> Extensions { + let mut exts = Extensions::new(); + + if block_number < self.before { + exts.register(Ext::default()); + } + + exts + } +} + /// Create a Offchain DB accessor object. pub trait DbExternalitiesFactory: Send + Sync { /// Create [`offchain::DbExternalities`] instance. @@ -92,7 +161,7 @@ impl DbExternaliti /// This crate aggregates extensions available for the offchain calls /// and is responsible for producing a correct `Extensions` object. /// for each call, based on required `Capabilities`. -pub struct ExecutionExtensions { +pub struct ExecutionExtensions { strategies: ExecutionStrategies, keystore: Option, offchain_db: Option>, @@ -103,10 +172,10 @@ pub struct ExecutionExtensions { // That's also the reason why it's being registered lazily instead of // during initialization. transaction_pool: RwLock>>>, - extensions_factory: RwLock>, + extensions_factory: RwLock>>, } -impl Default for ExecutionExtensions { +impl Default for ExecutionExtensions { fn default() -> Self { Self { strategies: Default::default(), @@ -118,7 +187,7 @@ impl Default for ExecutionExtensions { } } -impl ExecutionExtensions { +impl ExecutionExtensions { /// Create new `ExecutionExtensions` given a `keystore` and `ExecutionStrategies`. pub fn new( strategies: ExecutionStrategies, @@ -142,8 +211,8 @@ impl ExecutionExtensions { } /// Set the new extensions_factory - pub fn set_extensions_factory(&self, maker: Box) { - *self.extensions_factory.write() = maker; + pub fn set_extensions_factory(&self, maker: impl ExtensionsFactory + 'static) { + *self.extensions_factory.write() = Box::new(maker); } /// Register transaction pool extension. @@ -156,10 +225,18 @@ impl ExecutionExtensions { /// Based on the execution context and capabilities it produces /// the extensions object to support desired set of APIs. - pub fn extensions(&self, at: &BlockId, context: ExecutionContext) -> Extensions { + pub fn extensions( + &self, + block_hash: Block::Hash, + block_number: NumberFor, + context: ExecutionContext, + ) -> Extensions { let capabilities = context.capabilities(); - let mut extensions = self.extensions_factory.read().extensions_for(capabilities); + let mut extensions = + self.extensions_factory + .read() + .extensions_for(block_hash, block_number, capabilities); if capabilities.contains(offchain::Capabilities::KEYSTORE) { if let Some(ref keystore) = self.keystore { @@ -169,10 +246,10 @@ impl ExecutionExtensions { if capabilities.contains(offchain::Capabilities::TRANSACTION_POOL) { if let Some(pool) = self.transaction_pool.read().as_ref().and_then(|x| x.upgrade()) { - extensions - .register(TransactionPoolExt( - Box::new(TransactionPoolAdapter { at: *at, pool }) as _, - )); + extensions.register(TransactionPoolExt(Box::new(TransactionPoolAdapter { + at: BlockId::Hash(block_hash), + pool, + }) as _)); } } @@ -203,7 +280,8 @@ impl ExecutionExtensions { /// the right manager and extensions object to support desired set of APIs. pub fn manager_and_extensions( &self, - at: &BlockId, + block_hash: Block::Hash, + block_number: NumberFor, context: ExecutionContext, ) -> (ExecutionManager>, Extensions) { let manager = match context { @@ -215,17 +293,17 @@ impl ExecutionExtensions { ExecutionContext::OffchainCall(_) => self.strategies.other.get_manager(), }; - (manager, self.extensions(at, context)) + (manager, self.extensions(block_hash, block_number, context)) } } /// A wrapper type to pass `BlockId` to the actual transaction pool. -struct TransactionPoolAdapter { +struct TransactionPoolAdapter { at: BlockId, pool: Arc>, } -impl offchain::TransactionPool for TransactionPoolAdapter { +impl offchain::TransactionPool for TransactionPoolAdapter { fn submit_transaction(&mut self, data: Vec) -> Result<(), ()> { let xt = match Block::Extrinsic::decode(&mut &*data) { Ok(xt) => xt, diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index a7326d57c2bf0..c1b4962d04a12 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -477,7 +477,6 @@ where "GrandpaApi_grandpa_authorities", &[], ExecutionStrategy::NativeElseWasm, - None, ) .and_then(|call_result| { Decode::decode(&mut &call_result[..]).map_err(|err| { diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 64b6cacaad700..58aeac66e5c79 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -200,7 +200,6 @@ where &method, &call_data, self.client.execution_extensions().strategies().other, - None, ) .map(Into::into) }) diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 63d60fb06f471..50b6825f0c707 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -311,6 +311,7 @@ where executor, spawn_handle, config.clone(), + execution_extensions, )?; crate::client::Client::new( backend, @@ -318,7 +319,6 @@ where genesis_storage, fork_blocks, bad_blocks, - execution_extensions, prometheus_registry, telemetry, config, diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index a1a012dcedd9f..fcece49b5f228 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -17,15 +17,15 @@ // along with this program. If not, see . use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes}; -use sc_client_api::{backend, call_executor::CallExecutor, HeaderBackend}; +use sc_client_api::{ + backend, call_executor::CallExecutor, execution_extensions::ExecutionExtensions, HeaderBackend, +}; use sc_executor::{RuntimeVersion, RuntimeVersionOf}; -use sp_api::{ProofRecorder, StorageTransactionCache}; +use sp_api::{ExecutionContext, ProofRecorder, StorageTransactionCache}; use sp_core::traits::{CodeExecutor, RuntimeCode, SpawnNamed}; -use sp_externalities::Extensions; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_state_machine::{ - backend::AsTrieBackend, ExecutionManager, ExecutionStrategy, Ext, OverlayedChanges, - StateMachine, StorageProof, + backend::AsTrieBackend, ExecutionStrategy, Ext, OverlayedChanges, StateMachine, StorageProof, }; use std::{cell::RefCell, sync::Arc}; @@ -38,6 +38,7 @@ pub struct LocalCallExecutor { wasm_substitutes: WasmSubstitutes, spawn_handle: Box, client_config: ClientConfig, + execution_extensions: Arc>, } impl LocalCallExecutor @@ -51,6 +52,7 @@ where executor: E, spawn_handle: Box, client_config: ClientConfig, + execution_extensions: ExecutionExtensions, ) -> sp_blockchain::Result { let wasm_override = client_config .wasm_runtime_overrides @@ -71,6 +73,7 @@ where spawn_handle, client_config, wasm_substitutes, + execution_extensions: Arc::new(execution_extensions), }) } @@ -124,6 +127,7 @@ where spawn_handle: self.spawn_handle.clone(), client_config: self.client_config.clone(), wasm_substitutes: self.wasm_substitutes.clone(), + execution_extensions: self.execution_extensions.clone(), } } } @@ -138,30 +142,41 @@ where type Backend = B; + fn execution_extensions(&self) -> &ExecutionExtensions { + &self.execution_extensions + } + fn call( &self, at: &BlockId, method: &str, call_data: &[u8], strategy: ExecutionStrategy, - extensions: Option, ) -> sp_blockchain::Result> { let mut changes = OverlayedChanges::default(); let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + let at_number = self.backend.blockchain().expect_block_number_from_id(at)?; let state = self.backend.state_at(at_hash)?; + let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; let runtime_code = self.check_override(runtime_code, at)?; + let extensions = self.execution_extensions.extensions( + at_hash, + at_number, + ExecutionContext::OffchainCall(None), + ); + let mut sm = StateMachine::new( &state, &mut changes, &self.executor, method, call_data, - extensions.unwrap_or_default(), + extensions, &runtime_code, self.spawn_handle.clone(), ) @@ -171,30 +186,25 @@ where .map_err(Into::into) } - fn contextual_call< - EM: Fn( - Result, Self::Error>, - Result, Self::Error>, - ) -> Result, Self::Error>, - >( + fn contextual_call( &self, at: &BlockId, method: &str, call_data: &[u8], changes: &RefCell, storage_transaction_cache: Option<&RefCell>>, - execution_manager: ExecutionManager, recorder: &Option>, - extensions: Option, - ) -> Result, sp_blockchain::Error> - where - ExecutionManager: Clone, - { + context: ExecutionContext, + ) -> Result, sp_blockchain::Error> { let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut()); let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + let at_number = self.backend.blockchain().expect_block_number_from_id(at)?; let state = self.backend.state_at(at_hash)?; + let (execution_manager, extensions) = + self.execution_extensions.manager_and_extensions(at_hash, at_number, context); + let changes = &mut *changes.borrow_mut(); // It is important to extract the runtime code here before we create the proof @@ -220,7 +230,7 @@ where &self.executor, method, call_data, - extensions.unwrap_or_default(), + extensions, &runtime_code, self.spawn_handle.clone(), ) @@ -235,7 +245,7 @@ where &self.executor, method, call_data, - extensions.unwrap_or_default(), + extensions, &runtime_code, self.spawn_handle.clone(), ) @@ -269,6 +279,7 @@ where call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)> { let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + let at_number = self.backend.blockchain().expect_block_number_from_id(at)?; let state = self.backend.state_at(at_hash)?; let trie_backend = state.as_trie_backend(); @@ -286,6 +297,11 @@ where method, call_data, &runtime_code, + self.execution_extensions.extensions( + at_hash, + at_number, + ExecutionContext::OffchainCall(None), + ), ) .map_err(Into::into) } @@ -392,6 +408,11 @@ mod tests { backend.clone(), ) .unwrap(), + execution_extensions: Arc::new(ExecutionExtensions::new( + Default::default(), + None, + None, + )), }; let check = call_executor diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 1d896d8acd8bf..8ded5ec95c166 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -67,7 +67,8 @@ use sp_keystore::SyncCryptoStorePtr; use sp_runtime::{ generic::{BlockId, SignedBlock}, traits::{ - Block as BlockT, HashFor, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero, + Block as BlockT, BlockIdTo, HashFor, Header as HeaderT, NumberFor, One, + SaturatedConversion, Zero, }, BuildStorage, Digest, Justification, Justifications, StateVersion, }; @@ -113,7 +114,6 @@ where // Holds the block hash currently being imported. TODO: replace this with block queue. importing_block: RwLock>, block_rules: BlockRules, - execution_extensions: ExecutionExtensions, config: ClientConfig, telemetry: Option, _phantom: PhantomData, @@ -230,20 +230,26 @@ where Block: BlockT, B: backend::LocalBackend + 'static, { - let call_executor = - LocalCallExecutor::new(backend.clone(), executor, spawn_handle, config.clone())?; let extensions = ExecutionExtensions::new( Default::default(), keystore, sc_offchain::OffchainDb::factory_from_backend(&*backend), ); + + let call_executor = LocalCallExecutor::new( + backend.clone(), + executor, + spawn_handle, + config.clone(), + extensions, + )?; + Client::new( backend, call_executor, build_genesis_storage, Default::default(), Default::default(), - extensions, prometheus_registry, telemetry, config, @@ -347,7 +353,6 @@ where build_genesis_storage: &dyn BuildStorage, fork_blocks: ForkBlocks, bad_blocks: BadBlocks, - execution_extensions: ExecutionExtensions, prometheus_registry: Option, telemetry: Option, config: ClientConfig, @@ -394,7 +399,6 @@ where finality_actions: Default::default(), importing_block: Default::default(), block_rules: BlockRules::new(fork_blocks, bad_blocks), - execution_extensions, config, telemetry, _phantom: Default::default(), @@ -1386,7 +1390,7 @@ where } fn execution_extensions(&self) -> &ExecutionExtensions { - &self.execution_extensions + self.executor.execution_extensions() } } @@ -1580,7 +1584,7 @@ where } } -impl sp_runtime::traits::BlockIdTo for Client +impl BlockIdTo for Client where B: backend::Backend, E: CallExecutor + Send + Sync, @@ -1637,7 +1641,7 @@ where B: backend::Backend, E: CallExecutor + Send + Sync, Block: BlockT, - RA: ConstructRuntimeApi, + RA: ConstructRuntimeApi + Send + Sync, { type Api = >::RuntimeApi; @@ -1651,6 +1655,7 @@ where B: backend::Backend, E: CallExecutor + Send + Sync, Block: BlockT, + RA: Send + Sync, { type StateBackend = B::State; @@ -1658,21 +1663,15 @@ where &self, params: CallApiAtParams, ) -> Result, sp_api::ApiError> { - let at = params.at; - - let (manager, extensions) = - self.execution_extensions.manager_and_extensions(at, params.context); - self.executor .contextual_call( - at, + params.at, params.function, ¶ms.arguments, params.overlayed_changes, Some(params.storage_transaction_cache), - manager, params.recorder, - Some(extensions), + params.context, ) .map_err(Into::into) } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index b2011c05e8235..8e6131cbb75de 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -40,5 +40,6 @@ sp-state-machine = { version = "0.13.0", path = "../../../primitives/state-machi sp-storage = { version = "7.0.0", path = "../../../primitives/storage" } sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } sp-trie = { version = "7.0.0", path = "../../../primitives/trie" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 788f119130ac0..be9253d8c78e8 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -20,7 +20,8 @@ use futures::executor::block_on; use parity_scale_codec::{Decode, Encode, Joiner}; use sc_block_builder::BlockBuilderProvider; use sc_client_api::{ - in_mem, BlockBackend, BlockchainEvents, FinalityNotifications, HeaderBackend, StorageProvider, + in_mem, BlockBackend, BlockchainEvents, ExecutorProvider, FinalityNotifications, HeaderBackend, + StorageProvider, }; use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, DatabaseSource, PruningMode}; use sc_consensus::{ @@ -1875,3 +1876,40 @@ fn reorg_triggers_a_notification_even_for_sources_that_should_not_trigger_notifi let tree_route = notification.tree_route.unwrap(); assert_eq!(tree_route.enacted()[0].hash, b1.hash()); } + +#[test] +fn use_dalek_ext_works() { + fn zero_ed_pub() -> sp_core::ed25519::Public { + sp_core::ed25519::Public([0u8; 32]) + } + + fn zero_ed_sig() -> sp_core::ed25519::Signature { + sp_core::ed25519::Signature::from_raw([0u8; 64]) + } + + let mut client = TestClientBuilder::new().build(); + + client.execution_extensions().set_extensions_factory( + sc_client_api::execution_extensions::ExtensionBeforeBlock::::new( + 1, + ), + ); + + let a1 = client + .new_block_at(&BlockId::Number(0), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + block_on(client.import(BlockOrigin::NetworkInitialSync, a1.clone())).unwrap(); + + // On block zero it will use dalek and then on block 1 it will use zebra + assert!(!client + .runtime_api() + .verify_ed25519(&BlockId::Number(0), zero_ed_sig(), zero_ed_pub(), vec![]) + .unwrap()); + assert!(client + .runtime_api() + .verify_ed25519(&BlockId::Number(1), zero_ed_sig(), zero_ed_pub(), vec![]) + .unwrap()); +} diff --git a/client/tracing/src/lib.rs b/client/tracing/src/lib.rs index 1ae695a725f3f..acbde8b75da25 100644 --- a/client/tracing/src/lib.rs +++ b/client/tracing/src/lib.rs @@ -625,11 +625,7 @@ mod tests { let _guard2 = span2.enter(); // emit event tracing::event!(target: "test_target", tracing::Level::INFO, "test_event1"); - for msg in rx.recv() { - if !msg { - break - } - } + let _ = rx.recv(); // guard2 and span2 dropped / exited }); diff --git a/primitives/application-crypto/src/traits.rs b/primitives/application-crypto/src/traits.rs index 7a99c144b69f9..853208bc20cbf 100644 --- a/primitives/application-crypto/src/traits.rs +++ b/primitives/application-crypto/src/traits.rs @@ -157,8 +157,8 @@ pub trait RuntimeAppPublic: Sized { fn to_raw_vec(&self) -> Vec; } -/// Something that bound to a fixed `RuntimeAppPublic`. +/// Something that bound to a fixed [`RuntimeAppPublic`]. pub trait BoundToRuntimeAppPublic { - /// The `RuntimeAppPublic` this type is bound to. + /// The [`RuntimeAppPublic`] this type is bound to. type Public: RuntimeAppPublic; } diff --git a/primitives/externalities/src/extensions.rs b/primitives/externalities/src/extensions.rs index 5db40f12c21aa..ecb489e5ec829 100644 --- a/primitives/externalities/src/extensions.rs +++ b/primitives/externalities/src/extensions.rs @@ -89,6 +89,19 @@ macro_rules! decl_extension { Self(inner) } } + }; + ( + $( #[ $attr:meta ] )* + $vis:vis struct $ext_name:ident; + ) => { + $( #[ $attr ] )* + $vis struct $ext_name; + + impl $crate::Extension for $ext_name { + fn as_mut_any(&mut self) -> &mut dyn std::any::Any { + self + } + } } } @@ -112,7 +125,7 @@ pub trait ExtensionStore { extension: Box, ) -> Result<(), Error>; - /// Deregister extension with speicifed 'type_id' and drop it. + /// Deregister extension with specified 'type_id' and drop it. /// /// It should return error if extension is not registered. fn deregister_extension_by_type_id(&mut self, type_id: TypeId) -> Result<(), Error>; @@ -179,6 +192,13 @@ impl Extensions { } } +impl Extend for Extensions { + fn extend>(&mut self, iter: T) { + iter.into_iter() + .for_each(|ext| self.extensions.extend(ext.extensions.into_iter())); + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 35f0fd9692eaa..cd900b8f158ef 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -34,6 +34,7 @@ parking_lot = { version = "0.12.1", optional = true } secp256k1 = { version = "0.24.0", features = ["recovery", "global-context"], optional = true } tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.28", default-features = false} +ed25519-dalek = { version = "1.0.1", default-features = false, optional = true } [features] default = ["std"] @@ -57,6 +58,7 @@ std = [ "log", "futures", "parking_lot", + "ed25519-dalek", ] with-tracing = [ diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 33516bb0397f3..ead3ada1d1438 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -698,6 +698,34 @@ pub trait Misc { } } +#[cfg(feature = "std")] +sp_externalities::decl_extension! { + /// Extension to signal to [`crypt::ed25519_verify`] to use the dalek crate. + /// + /// The switch from `ed25519-dalek` to `ed25519-zebra` was a breaking change. + /// `ed25519-zebra` is more permissive when it comes to the verification of signatures. + /// This means that some chains may fail to sync from genesis when using `ed25519-zebra`. + /// So, this extension can be registered to the runtime execution environment to signal + /// that `ed25519-dalek` should be used for verification. The extension can be registered + /// in the following way: + /// + /// ```nocompile + /// client.execution_extensions().set_extensions_factory( + /// // Let the `UseDalekExt` extension being registered for each runtime invocation + /// // until the execution happens in the context of block `1000`. + /// sc_client_api::execution_extensions::ExtensionBeforeBlock::::new(1000) + /// ); + /// ``` + pub struct UseDalekExt; +} + +#[cfg(feature = "std")] +impl Default for UseDalekExt { + fn default() -> Self { + Self + } +} + /// Interfaces for working with crypto related types from within the runtime. #[runtime_interface] pub trait Crypto { @@ -747,13 +775,32 @@ pub trait Crypto { /// /// Returns `true` when the verification was successful. fn ed25519_verify(sig: &ed25519::Signature, msg: &[u8], pub_key: &ed25519::Public) -> bool { - ed25519::Pair::verify(sig, msg, pub_key) + // We don't want to force everyone needing to call the function in an externalities context. + // So, we assume that we should not use dalek when we are not in externalities context. + // Otherwise, we check if the extension is present. + if sp_externalities::with_externalities(|mut e| e.extension::().is_some()) + .unwrap_or_default() + { + use ed25519_dalek::Verifier; + + let public_key = if let Ok(vk) = ed25519_dalek::PublicKey::from_bytes(&pub_key.0) { + vk + } else { + return false + }; + + let sig = ed25519_dalek::Signature::from(sig.0); + + public_key.verify(msg, &sig).is_ok() + } else { + ed25519::Pair::verify(sig, msg, pub_key) + } } /// Register a `ed25519` signature for batch verification. /// /// Batch verification must be enabled by calling [`start_batch_verify`]. - /// If batch verification is not enabled, the signature will be verified immediatley. + /// If batch verification is not enabled, the signature will be verified immediately. /// To get the result of the batch verification, [`finish_batch_verify`] /// needs to be called. /// @@ -780,7 +827,7 @@ pub trait Crypto { /// Register a `sr25519` signature for batch verification. /// /// Batch verification must be enabled by calling [`start_batch_verify`]. - /// If batch verification is not enabled, the signature will be verified immediatley. + /// If batch verification is not enabled, the signature will be verified immediately. /// To get the result of the batch verification, [`finish_batch_verify`] /// needs to be called. /// @@ -1977,4 +2024,20 @@ mod tests { assert!(!crypto::finish_batch_verify()); }); } + + #[test] + fn use_dalek_ext_works() { + let mut ext = BasicExternalities::default(); + ext.register_extension(UseDalekExt::default()); + + // With dalek the zero signature should fail to verify. + ext.execute_with(|| { + assert!(!crypto::ed25519_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub())); + }); + + // But with zebra it should work. + BasicExternalities::default().execute_with(|| { + assert!(crypto::ed25519_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub())); + }) + } } diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 1f106593ede34..225fe1582e752 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -532,6 +532,7 @@ mod execution { method, call_data, runtime_code, + Default::default(), ) } @@ -552,6 +553,7 @@ mod execution { method: &str, call_data: &[u8], runtime_code: &RuntimeCode, + extensions: Extensions, ) -> Result<(Vec, StorageProof), Box> where S: trie_backend_essence::TrieBackendStorage, @@ -569,7 +571,7 @@ mod execution { exec, method, call_data, - Extensions::default(), + extensions, runtime_code, spawn_handle, ) diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index d3e71f0ad28d6..8ee652abe2c70 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -229,11 +229,6 @@ impl &storage, self.fork_blocks, self.bad_blocks, - ExecutionExtensions::new( - self.execution_strategies, - self.keystore, - sc_offchain::OffchainDb::factory_from_backend(&*self.backend), - ), None, None, ClientConfig { @@ -285,6 +280,11 @@ impl executor, Box::new(sp_core::testing::TaskExecutor::new()), Default::default(), + ExecutionExtensions::new( + self.execution_strategies.clone(), + self.keystore.clone(), + sc_offchain::OffchainDb::factory_from_backend(&*self.backend), + ), ) .expect("Creates LocalCallExecutor"); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 8bda4ea602428..054b195fc6efb 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -378,6 +378,8 @@ cfg_if! { fn test_multiple_arguments(data: Vec, other: Vec, num: u32); /// Traces log "Hey I'm runtime." fn do_trace_log(); + /// Verify the given signature, public & message bundle. + fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool; } } } else { @@ -428,6 +430,8 @@ cfg_if! { fn test_multiple_arguments(data: Vec, other: Vec, num: u32); /// Traces log "Hey I'm runtime." fn do_trace_log(); + /// Verify the given signature, public & message bundle. + fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool; } } } @@ -863,6 +867,10 @@ cfg_if! { fn do_trace_log() { log::trace!("Hey I'm runtime"); } + + fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool { + sp_io::crypto::ed25519_verify(&sig, &message, &public) + } } impl sp_consensus_aura::AuraApi for Runtime { @@ -1137,6 +1145,10 @@ cfg_if! { fn do_trace_log() { log::trace!("Hey I'm runtime: {}", log::STATIC_MAX_LEVEL); } + + fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool { + sp_io::crypto::ed25519_verify(&sig, &message, &public) + } } impl sp_consensus_aura::AuraApi for Runtime { From d833e152475372a433ba63102a7c6c5a91dbafde Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 28 Nov 2022 13:38:24 +0200 Subject: [PATCH 1414/1472] client/beefy: fix on-demand justifications sync for old blocks (#12767) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * client/beefy: fix on-demand justif sync for old blocks When receiving BEEFY justifications for old blocks the state might be pruned for them, in which case justification verification fails because BEEFY validator set cannot be retrieved from runtime state. Fix this by having the voter give the validator set to the `OnDemandJustificationsEngine` as request information. On receiving a BEEFY justification for requested block, the provided validator set will be used to validate the justification. Signed-off-by: acatangiu * Apply suggestions from code review Co-authored-by: Bastian Köcher * impl review suggestions * client/beefy: fail initialization if state unavailable * beefy: remove spammy log Signed-off-by: acatangiu Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher --- .../outgoing_requests_engine.rs | 112 ++++++++---------- client/beefy/src/lib.rs | 29 +++-- client/beefy/src/round.rs | 4 + client/beefy/src/worker.rs | 50 ++++---- 4 files changed, 94 insertions(+), 101 deletions(-) diff --git a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs index c4d3c926190e6..00ee7610dd4f0 100644 --- a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -18,21 +18,17 @@ //! Generating request logic for request/response protocol for syncing BEEFY justifications. -use beefy_primitives::{crypto::AuthorityId, BeefyApi, ValidatorSet}; +use beefy_primitives::{crypto::AuthorityId, ValidatorSet}; use codec::Encode; use futures::channel::{oneshot, oneshot::Canceled}; -use log::{debug, error, warn}; +use log::{debug, warn}; use parking_lot::Mutex; use sc_network::{PeerId, ProtocolName}; use sc_network_common::{ request_responses::{IfDisconnected, RequestFailure}, service::NetworkRequest, }; -use sp_api::ProvideRuntimeApi; -use sp_runtime::{ - generic::BlockId, - traits::{Block, NumberFor}, -}; +use sp_runtime::traits::{Block, NumberFor}; use std::{collections::VecDeque, result::Result, sync::Arc}; use crate::{ @@ -46,14 +42,19 @@ type Response = Result, RequestFailure>; /// Used to receive a response from the network. type ResponseReceiver = oneshot::Receiver; +#[derive(Clone, Debug)] +struct RequestInfo { + block: NumberFor, + active_set: ValidatorSet, +} + enum State { Idle, - AwaitingResponse(PeerId, NumberFor, ResponseReceiver), + AwaitingResponse(PeerId, RequestInfo, ResponseReceiver), } -pub struct OnDemandJustificationsEngine { +pub struct OnDemandJustificationsEngine { network: Arc, - runtime: Arc, protocol_name: ProtocolName, live_peers: Arc>>, @@ -62,21 +63,14 @@ pub struct OnDemandJustificationsEngine { state: State, } -impl OnDemandJustificationsEngine -where - B: Block, - R: ProvideRuntimeApi, - R::Api: BeefyApi, -{ +impl OnDemandJustificationsEngine { pub fn new( network: Arc, - runtime: Arc, protocol_name: ProtocolName, live_peers: Arc>>, ) -> Self { Self { network, - runtime, protocol_name, live_peers, peers_cache: VecDeque::new(), @@ -100,10 +94,15 @@ where None } - fn request_from_peer(&mut self, peer: PeerId, block: NumberFor) { - debug!(target: "beefy::sync", "🥩 requesting justif #{:?} from peer {:?}", block, peer); + fn request_from_peer(&mut self, peer: PeerId, req_info: RequestInfo) { + debug!( + target: "beefy::sync", + "🥩 requesting justif #{:?} from peer {:?}", + req_info.block, + peer, + ); - let payload = JustificationRequest:: { begin: block }.encode(); + let payload = JustificationRequest:: { begin: req_info.block }.encode(); let (tx, rx) = oneshot::channel(); @@ -115,11 +114,13 @@ where IfDisconnected::ImmediateError, ); - self.state = State::AwaitingResponse(peer, block, rx); + self.state = State::AwaitingResponse(peer, req_info, rx); } - /// If no other request is in progress, start new justification request for `block`. - pub fn request(&mut self, block: NumberFor) { + /// Start new justification request for `block`, if no other request is in progress. + /// + /// `active_set` will be used to verify validity of potential responses. + pub fn request(&mut self, block: NumberFor, active_set: ValidatorSet) { // ignore new requests while there's already one pending if matches!(self.state, State::AwaitingResponse(_, _, _)) { return @@ -129,7 +130,7 @@ where // Start the requests engine - each unsuccessful received response will automatically // trigger a new request to the next peer in the `peers_cache` until there are none left. if let Some(peer) = self.try_next_peer() { - self.request_from_peer(peer, block); + self.request_from_peer(peer, RequestInfo { block, active_set }); } else { debug!(target: "beefy::sync", "🥩 no good peers to request justif #{:?} from", block); } @@ -138,11 +139,10 @@ where /// Cancel any pending request for block numbers smaller or equal to `block`. pub fn cancel_requests_older_than(&mut self, block: NumberFor) { match &self.state { - State::AwaitingResponse(_, number, _) if *number <= block => { + State::AwaitingResponse(_, req_info, _) if req_info.block <= block => { debug!( - target: "beefy::sync", - "🥩 cancel pending request for justification #{:?}", - number + target: "beefy::sync", "🥩 cancel pending request for justification #{:?}", + req_info.block ); self.state = State::Idle; }, @@ -153,8 +153,7 @@ where fn process_response( &mut self, peer: PeerId, - block: NumberFor, - validator_set: &ValidatorSet, + req_info: &RequestInfo, response: Result, ) -> Result, Error> { response @@ -162,7 +161,7 @@ where debug!( target: "beefy::sync", "🥩 for on demand justification #{:?}, peer {:?} hung up: {:?}", - block, peer, e + req_info.block, peer, e ); Error::InvalidResponse })? @@ -170,60 +169,49 @@ where debug!( target: "beefy::sync", "🥩 for on demand justification #{:?}, peer {:?} error: {:?}", - block, peer, e + req_info.block, peer, e ); Error::InvalidResponse }) .and_then(|encoded| { - decode_and_verify_finality_proof::(&encoded[..], block, &validator_set).map_err( - |e| { - debug!( - target: "beefy::sync", - "🥩 for on demand justification #{:?}, peer {:?} responded with invalid proof: {:?}", - block, peer, e - ); - Error::InvalidResponse - }, + decode_and_verify_finality_proof::( + &encoded[..], + req_info.block, + &req_info.active_set, ) + .map_err(|e| { + debug!( + target: "beefy::sync", + "🥩 for on demand justification #{:?}, peer {:?} responded with invalid proof: {:?}", + req_info.block, peer, e + ); + Error::InvalidResponse + }) }) } pub async fn next(&mut self) -> Option> { - let (peer, block, resp) = match &mut self.state { + let (peer, req_info, resp) = match &mut self.state { State::Idle => { futures::pending!(); // Doesn't happen as 'futures::pending!()' is an 'await' barrier that never passes. return None }, - State::AwaitingResponse(peer, block, receiver) => { + State::AwaitingResponse(peer, req_info, receiver) => { let resp = receiver.await; - (*peer, *block, resp) + (*peer, req_info.clone(), resp) }, }; // We received the awaited response. Our 'receiver' will never generate any other response, // meaning we're done with current state. Move the engine to `State::Idle`. self.state = State::Idle; - let block_id = BlockId::number(block); - let validator_set = self - .runtime - .runtime_api() - .validator_set(&block_id) - .map_err(|e| { - error!(target: "beefy::sync", "🥩 Runtime API error {:?} in on-demand justif engine.", e); - e - }) - .ok()? - .or_else(|| { - error!(target: "beefy::sync", "🥩 BEEFY pallet not available for block {:?}.", block); - None - })?; - - self.process_response(peer, block, &validator_set, resp) + let block = req_info.block; + self.process_response(peer, &req_info, resp) .map_err(|_| { // No valid justification received, try next peer in our set. if let Some(peer) = self.try_next_peer() { - self.request_from_peer(peer, block); + self.request_from_peer(peer, req_info); } else { warn!(target: "beefy::sync", "🥩 ran out of peers to request justif #{:?} from", block); } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 9dccd4236bef3..a057a9fdc597d 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -244,7 +244,6 @@ where // The `GossipValidator` adds and removes known peers based on valid votes and network events. let on_demand_justifications = OnDemandJustificationsEngine::new( network.clone(), - runtime.clone(), justifications_protocol_name, known_peers, ); @@ -295,7 +294,7 @@ where persisted_state, }; - let worker = worker::BeefyWorker::<_, _, _, _, _>::new(worker_params); + let worker = worker::BeefyWorker::<_, _, _, _>::new(worker_params); futures::future::join( worker.run(block_import_justif, finality_notifications), @@ -377,17 +376,8 @@ where break state } - // Check if we should move up the chain. - let parent_hash = *header.parent_hash(); - if *header.number() == One::one() || - runtime - .runtime_api() - .validator_set(&BlockId::hash(parent_hash)) - .ok() - .flatten() - .is_none() - { - // We've reached pallet genesis, initialize voter here. + if *header.number() == One::one() { + // We've reached chain genesis, initialize voter here. let genesis_num = *header.number(); let genesis_set = expect_validator_set(runtime, BlockId::hash(header.hash())) .and_then(genesis_set_sanity_check)?; @@ -408,6 +398,19 @@ where sessions.push_front(Rounds::new(*header.number(), active)); } + // Check if state is still available if we move up the chain. + let parent_hash = *header.parent_hash(); + runtime + .runtime_api() + .validator_set(&BlockId::hash(parent_hash)) + .ok() + .flatten() + .ok_or_else(|| { + let msg = format!("{}. Could not initialize BEEFY voter.", parent_hash); + error!(target: "beefy", "🥩 {}", msg); + ClientError::Consensus(sp_consensus::Error::StateUnavailable(msg)) + })?; + // Move up the chain. header = blockchain.expect_header(BlockId::Hash(parent_hash))?; }; diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index 7a8cc4171a155..48d3d087299d0 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -89,6 +89,10 @@ where } } + pub(crate) fn validator_set(&self) -> &ValidatorSet { + &self.validator_set + } + pub(crate) fn validator_set_id(&self) -> ValidatorSetId { self.validator_set.id() } diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 6726fa4375387..9669939e594c1 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -31,8 +31,8 @@ use crate::{ }; use beefy_primitives::{ crypto::{AuthorityId, Signature}, - BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, PayloadProvider, SignedCommitment, - ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, + Commitment, ConsensusLog, Payload, PayloadProvider, SignedCommitment, ValidatorSet, + VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use codec::{Codec, Decode, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; @@ -41,10 +41,9 @@ use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, Header use sc_network_common::service::{NetworkEventStream, NetworkRequest}; use sc_network_gossip::GossipEngine; use sc_utils::notification::NotificationReceiver; -use sp_api::{BlockId, ProvideRuntimeApi}; +use sp_api::BlockId; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; -use sp_mmr_primitives::MmrApi; use sp_runtime::{ generic::OpaqueDigestItemId, traits::{Block, Header, NumberFor, Zero}, @@ -166,13 +165,13 @@ impl VoterOracle { Ok(()) } - /// Return current pending mandatory block, if any. - pub fn mandatory_pending(&self) -> Option> { + /// Return current pending mandatory block, if any, plus its active validator set. + pub fn mandatory_pending(&self) -> Option<(NumberFor, ValidatorSet)> { self.sessions.front().and_then(|round| { if round.mandatory_done() { None } else { - Some(round.session_start()) + Some((round.session_start(), round.validator_set().clone())) } }) } @@ -239,14 +238,14 @@ impl VoterOracle { } } -pub(crate) struct WorkerParams { +pub(crate) struct WorkerParams { pub backend: Arc, pub payload_provider: P, pub network: N, pub key_store: BeefyKeystore, pub gossip_engine: GossipEngine, pub gossip_validator: Arc>, - pub on_demand_justifications: OnDemandJustificationsEngine, + pub on_demand_justifications: OnDemandJustificationsEngine, pub links: BeefyVoterLinks, pub metrics: Option, pub persisted_state: PersistedState, @@ -287,7 +286,7 @@ impl PersistedState { } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker { +pub(crate) struct BeefyWorker { // utilities backend: Arc, payload_provider: P, @@ -297,7 +296,7 @@ pub(crate) struct BeefyWorker { // communication gossip_engine: GossipEngine, gossip_validator: Arc>, - on_demand_justifications: OnDemandJustificationsEngine, + on_demand_justifications: OnDemandJustificationsEngine, // channels /// Links between the block importer, the background voter and the RPC layer. @@ -314,13 +313,11 @@ pub(crate) struct BeefyWorker { persisted_state: PersistedState, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, P: PayloadProvider, - R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi>, N: NetworkEventStream + NetworkRequest + SyncOracle + Send + Sync + Clone + 'static, { /// Return a new BEEFY worker instance. @@ -329,7 +326,7 @@ where /// BEEFY pallet has been deployed on-chain. /// /// The BEEFY pallet is needed in order to keep track of the BEEFY authority set. - pub(crate) fn new(worker_params: WorkerParams) -> Self { + pub(crate) fn new(worker_params: WorkerParams) -> Self { let WorkerParams { backend, payload_provider, @@ -551,10 +548,15 @@ where // New state is persisted after finalization. self.finalize(finality_proof)?; } else { - if self_vote || self.voting_oracle().mandatory_pending() == Some(round.1) { - // Persist state after handling self vote to avoid double voting in case - // of voter restarts. - // Also persist state after handling mandatory block vote. + let mandatory_round = self + .voting_oracle() + .mandatory_pending() + .map(|p| p.0 == round.1) + .unwrap_or(false); + // Persist state after handling self vote to avoid double voting in case + // of voter restarts. + // Also persist state after handling mandatory block vote. + if self_vote || mandatory_round { crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) .map_err(|e| Error::Backend(e.to_string()))?; } @@ -784,12 +786,10 @@ where } // If the current target is a mandatory block, // make sure there's also an on-demand justification request out for it. - if let Some(block) = self.voting_oracle().mandatory_pending() { + if let Some((block, active)) = self.voting_oracle().mandatory_pending() { // This only starts new request if there isn't already an active one. - self.on_demand_justifications.request(block); + self.on_demand_justifications.request(block, active); } - } else { - debug!(target: "beefy", "🥩 Skipping voting while major syncing."); } } @@ -993,7 +993,6 @@ pub(crate) mod tests { Block, Backend, MmrRootProvider, - TestApi, Arc>, > { let keystore = create_beefy_keystore(*key); @@ -1024,7 +1023,6 @@ pub(crate) mod tests { GossipEngine::new(network.clone(), "/beefy/1", gossip_validator.clone(), None); let on_demand_justifications = OnDemandJustificationsEngine::new( network.clone(), - api.clone(), "/beefy/justifs/1".into(), known_peers, ); @@ -1050,7 +1048,7 @@ pub(crate) mod tests { on_demand_justifications, persisted_state, }; - BeefyWorker::<_, _, _, _, _>::new(worker_params) + BeefyWorker::<_, _, _, _>::new(worker_params) } #[test] From a0e00dc87cc1c2e52281bff3db61a4d4cc1aa983 Mon Sep 17 00:00:00 2001 From: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Date: Mon, 28 Nov 2022 19:51:59 +0100 Subject: [PATCH 1415/1472] Remove Default, HasCompact, and TypeInfo trait bounds on AssetId (#12740) * Remove Default, HasCompact, and TypeInfo trait bounds on AssetId * don't use default in benchmarking * add helper trait * add helper to assets tx payment test * docs fixes * i'm confused * aha, cargo * move affected dispatchable calls into new indices * Helper -> BenchmarkHelper * benchmark use of helper * actually, don't break every call interface * use into on AssetIdParameter * Remove From from AssetIdParameter and use it in BenchmarkHelper * include from Co-authored-by: parity-processbot <> --- Cargo.lock | 1 + bin/node/runtime/src/lib.rs | 3 + frame/assets/src/benchmarking.rs | 228 +++++++++--------- frame/assets/src/lib.rs | 173 +++++++------ frame/assets/src/mock.rs | 3 + .../asset-tx-payment/Cargo.toml | 8 + .../asset-tx-payment/src/tests.rs | 38 +-- 7 files changed, 254 insertions(+), 200 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c627ee2f9823..8f4653940f3cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5007,6 +5007,7 @@ dependencies = [ name = "pallet-asset-tx-payment" version = "4.0.0-dev" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "pallet-assets", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1df668cd5f972..ef1e3bb8f3c4b 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1440,6 +1440,7 @@ impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = u128; type AssetId = u32; + type AssetIdParameter = codec::Compact; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = EnsureRoot; @@ -1453,6 +1454,8 @@ impl pallet_assets::Config for Runtime { type Extra = (); type WeightInfo = pallet_assets::weights::SubstrateWeight; type RemoveItemsLimit = ConstU32<1000>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } parameter_types! { diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index cf141360228e9..ede5b4e77fac6 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -35,43 +35,49 @@ use crate::Pallet as Assets; const SEED: u32 = 0; +fn default_asset_id, I: 'static>() -> T::AssetIdParameter { + T::BenchmarkHelper::create_asset_id_parameter(0) +} + fn create_default_asset, I: 'static>( is_sufficient: bool, -) -> (T::AccountId, AccountIdLookupOf) { +) -> (T::AssetIdParameter, T::AccountId, AccountIdLookupOf) { + let asset_id = default_asset_id::(); let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); let root = SystemOrigin::Root.into(); assert!(Assets::::force_create( root, - Default::default(), + asset_id, caller_lookup.clone(), is_sufficient, 1u32.into(), ) .is_ok()); - (caller, caller_lookup) + (asset_id, caller, caller_lookup) } fn create_default_minted_asset, I: 'static>( is_sufficient: bool, amount: T::Balance, -) -> (T::AccountId, AccountIdLookupOf) { - let (caller, caller_lookup) = create_default_asset::(is_sufficient); +) -> (T::AssetIdParameter, T::AccountId, AccountIdLookupOf) { + let (asset_id, caller, caller_lookup) = create_default_asset::(is_sufficient); if !is_sufficient { T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); } assert!(Assets::::mint( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + asset_id, caller_lookup.clone(), amount, ) .is_ok()); - (caller, caller_lookup) + (asset_id, caller, caller_lookup) } fn swap_is_sufficient, I: 'static>(s: &mut bool) { - Asset::::mutate(&T::AssetId::default(), |maybe_a| { + let asset_id = default_asset_id::(); + Asset::::mutate(&asset_id.into(), |maybe_a| { if let Some(ref mut a) = maybe_a { sp_std::mem::swap(s, &mut a.is_sufficient) } @@ -79,6 +85,7 @@ fn swap_is_sufficient, I: 'static>(s: &mut bool) { } fn add_sufficients, I: 'static>(minter: T::AccountId, n: u32) { + let asset_id = default_asset_id::(); let origin = SystemOrigin::Signed(minter); let mut s = true; swap_is_sufficient::(&mut s); @@ -87,7 +94,7 @@ fn add_sufficients, I: 'static>(minter: T::AccountId, n: u32) { let target_lookup = T::Lookup::unlookup(target); assert!(Assets::::mint( origin.clone().into(), - Default::default(), + asset_id, target_lookup, 100u32.into() ) @@ -97,23 +104,19 @@ fn add_sufficients, I: 'static>(minter: T::AccountId, n: u32) { } fn add_approvals, I: 'static>(minter: T::AccountId, n: u32) { + let asset_id = default_asset_id::(); T::Currency::deposit_creating(&minter, T::ApprovalDeposit::get() * n.into()); let minter_lookup = T::Lookup::unlookup(minter.clone()); let origin = SystemOrigin::Signed(minter); - Assets::::mint( - origin.clone().into(), - Default::default(), - minter_lookup, - (100 * (n + 1)).into(), - ) - .unwrap(); + Assets::::mint(origin.clone().into(), asset_id, minter_lookup, (100 * (n + 1)).into()) + .unwrap(); for i in 0..n { let target = account("approval", i, SEED); T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); let target_lookup = T::Lookup::unlookup(target); Assets::::approve_transfer( origin.clone().into(), - Default::default(), + asset_id, target_lookup, 100u32.into(), ) @@ -131,48 +134,49 @@ fn assert_event, I: 'static>(generic_event: >::Runti benchmarks_instance_pallet! { create { - let asset_id = Default::default(); - let origin = T::CreateOrigin::successful_origin(&asset_id); - let caller = T::CreateOrigin::ensure_origin(origin, &asset_id).unwrap(); + let asset_id = default_asset_id::(); + let origin = T::CreateOrigin::successful_origin(&asset_id.into()); + let caller = T::CreateOrigin::ensure_origin(origin, &asset_id.into()).unwrap(); let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup, 1u32.into()) verify { - assert_last_event::(Event::Created { asset_id, creator: caller.clone(), owner: caller }.into()); + assert_last_event::(Event::Created { asset_id: asset_id.into(), creator: caller.clone(), owner: caller }.into()); } force_create { + let asset_id = default_asset_id::(); let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - }: _(SystemOrigin::Root, Default::default(), caller_lookup, true, 1u32.into()) + }: _(SystemOrigin::Root, asset_id, caller_lookup, true, 1u32.into()) verify { - assert_last_event::(Event::ForceCreated { asset_id: Default::default(), owner: caller }.into()); + assert_last_event::(Event::ForceCreated { asset_id: asset_id.into(), owner: caller }.into()); } start_destroy { - let (caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); Assets::::freeze_asset( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + asset_id, )?; - }:_(SystemOrigin::Signed(caller), Default::default()) + }:_(SystemOrigin::Signed(caller), asset_id) verify { - assert_last_event::(Event::DestructionStarted { asset_id: Default::default() }.into()); + assert_last_event::(Event::DestructionStarted { asset_id: asset_id.into() }.into()); } destroy_accounts { let c in 0 .. T::RemoveItemsLimit::get(); - let (caller, _) = create_default_asset::(true); + let (asset_id, caller, _) = create_default_asset::(true); add_sufficients::(caller.clone(), c); Assets::::freeze_asset( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + asset_id, )?; - Assets::::start_destroy(SystemOrigin::Signed(caller.clone()).into(), Default::default())?; - }:_(SystemOrigin::Signed(caller), Default::default()) + Assets::::start_destroy(SystemOrigin::Signed(caller.clone()).into(), asset_id)?; + }:_(SystemOrigin::Signed(caller), asset_id) verify { assert_last_event::(Event::AccountsDestroyed { - asset_id: Default::default() , + asset_id: asset_id.into(), accounts_destroyed: c, accounts_remaining: 0, }.into()); @@ -180,142 +184,142 @@ benchmarks_instance_pallet! { destroy_approvals { let a in 0 .. T::RemoveItemsLimit::get(); - let (caller, _) = create_default_minted_asset::(true, 100u32.into()); + let (asset_id, caller, _) = create_default_minted_asset::(true, 100u32.into()); add_approvals::(caller.clone(), a); Assets::::freeze_asset( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + asset_id, )?; - Assets::::start_destroy(SystemOrigin::Signed(caller.clone()).into(), Default::default())?; - }:_(SystemOrigin::Signed(caller), Default::default()) + Assets::::start_destroy(SystemOrigin::Signed(caller.clone()).into(), asset_id)?; + }:_(SystemOrigin::Signed(caller), asset_id) verify { assert_last_event::(Event::ApprovalsDestroyed { - asset_id: Default::default() , + asset_id: asset_id.into(), approvals_destroyed: a, approvals_remaining: 0, }.into()); } finish_destroy { - let (caller, caller_lookup) = create_default_asset::(true); + let (asset_id, caller, caller_lookup) = create_default_asset::(true); Assets::::freeze_asset( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + asset_id, )?; - Assets::::start_destroy(SystemOrigin::Signed(caller.clone()).into(), Default::default())?; - }:_(SystemOrigin::Signed(caller), Default::default()) + Assets::::start_destroy(SystemOrigin::Signed(caller.clone()).into(), asset_id)?; + }:_(SystemOrigin::Signed(caller), asset_id) verify { assert_last_event::(Event::Destroyed { - asset_id: Default::default() , + asset_id: asset_id.into(), }.into() ); } mint { - let (caller, caller_lookup) = create_default_asset::(true); + let (asset_id, caller, caller_lookup) = create_default_asset::(true); let amount = T::Balance::from(100u32); - }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, amount) + }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup, amount) verify { - assert_last_event::(Event::Issued { asset_id: Default::default(), owner: caller, total_supply: amount }.into()); + assert_last_event::(Event::Issued { asset_id: asset_id.into(), owner: caller, total_supply: amount }.into()); } burn { let amount = T::Balance::from(100u32); - let (caller, caller_lookup) = create_default_minted_asset::(true, amount); - }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, amount) + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, amount); + }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup, amount) verify { - assert_last_event::(Event::Burned { asset_id: Default::default(), owner: caller, balance: amount }.into()); + assert_last_event::(Event::Burned { asset_id: asset_id.into(), owner: caller, balance: amount }.into()); } transfer { let amount = T::Balance::from(100u32); - let (caller, caller_lookup) = create_default_minted_asset::(true, amount); + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, amount); let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - }: _(SystemOrigin::Signed(caller.clone()), Default::default(), target_lookup, amount) + }: _(SystemOrigin::Signed(caller.clone()), asset_id, target_lookup, amount) verify { - assert_last_event::(Event::Transferred { asset_id: Default::default(), from: caller, to: target, amount }.into()); + assert_last_event::(Event::Transferred { asset_id: asset_id.into(), from: caller, to: target, amount }.into()); } transfer_keep_alive { let mint_amount = T::Balance::from(200u32); let amount = T::Balance::from(100u32); - let (caller, caller_lookup) = create_default_minted_asset::(true, mint_amount); + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, mint_amount); let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - }: _(SystemOrigin::Signed(caller.clone()), Default::default(), target_lookup, amount) + }: _(SystemOrigin::Signed(caller.clone()), asset_id, target_lookup, amount) verify { assert!(frame_system::Pallet::::account_exists(&caller)); - assert_last_event::(Event::Transferred { asset_id: Default::default(), from: caller, to: target, amount }.into()); + assert_last_event::(Event::Transferred { asset_id: asset_id.into(), from: caller, to: target, amount }.into()); } force_transfer { let amount = T::Balance::from(100u32); - let (caller, caller_lookup) = create_default_minted_asset::(true, amount); + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, amount); let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, target_lookup, amount) + }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup, target_lookup, amount) verify { assert_last_event::( - Event::Transferred { asset_id: Default::default(), from: caller, to: target, amount }.into() + Event::Transferred { asset_id: asset_id.into(), from: caller, to: target, amount }.into() ); } freeze { - let (caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); - }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup) + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); + }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup) verify { - assert_last_event::(Event::Frozen { asset_id: Default::default(), who: caller }.into()); + assert_last_event::(Event::Frozen { asset_id: asset_id.into(), who: caller }.into()); } thaw { - let (caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); Assets::::freeze( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + asset_id, caller_lookup.clone(), )?; - }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup) + }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup) verify { - assert_last_event::(Event::Thawed { asset_id: Default::default(), who: caller }.into()); + assert_last_event::(Event::Thawed { asset_id: asset_id.into(), who: caller }.into()); } freeze_asset { - let (caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); - }: _(SystemOrigin::Signed(caller.clone()), Default::default()) + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); + }: _(SystemOrigin::Signed(caller.clone()), asset_id) verify { - assert_last_event::(Event::AssetFrozen { asset_id: Default::default() }.into()); + assert_last_event::(Event::AssetFrozen { asset_id: asset_id.into() }.into()); } thaw_asset { - let (caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); Assets::::freeze_asset( SystemOrigin::Signed(caller.clone()).into(), - Default::default(), + asset_id, )?; - }: _(SystemOrigin::Signed(caller.clone()), Default::default()) + }: _(SystemOrigin::Signed(caller.clone()), asset_id) verify { - assert_last_event::(Event::AssetThawed { asset_id: Default::default() }.into()); + assert_last_event::(Event::AssetThawed { asset_id: asset_id.into() }.into()); } transfer_ownership { - let (caller, _) = create_default_asset::(true); + let (asset_id, caller, _) = create_default_asset::(true); let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - }: _(SystemOrigin::Signed(caller), Default::default(), target_lookup) + }: _(SystemOrigin::Signed(caller), asset_id, target_lookup) verify { - assert_last_event::(Event::OwnerChanged { asset_id: Default::default(), owner: target }.into()); + assert_last_event::(Event::OwnerChanged { asset_id: asset_id.into(), owner: target }.into()); } set_team { - let (caller, _) = create_default_asset::(true); + let (asset_id, caller, _) = create_default_asset::(true); let target0 = T::Lookup::unlookup(account("target", 0, SEED)); let target1 = T::Lookup::unlookup(account("target", 1, SEED)); let target2 = T::Lookup::unlookup(account("target", 2, SEED)); - }: _(SystemOrigin::Signed(caller), Default::default(), target0, target1, target2) + }: _(SystemOrigin::Signed(caller), asset_id, target0, target1, target2) verify { assert_last_event::(Event::TeamChanged { - asset_id: Default::default(), + asset_id: asset_id.into(), issuer: account("target", 0, SEED), admin: account("target", 1, SEED), freezer: account("target", 2, SEED), @@ -330,23 +334,22 @@ benchmarks_instance_pallet! { let symbol = vec![0u8; s as usize]; let decimals = 12; - let (caller, _) = create_default_asset::(true); + let (asset_id, caller, _) = create_default_asset::(true); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - }: _(SystemOrigin::Signed(caller), Default::default(), name.clone(), symbol.clone(), decimals) + }: _(SystemOrigin::Signed(caller), asset_id, name.clone(), symbol.clone(), decimals) verify { - let id = Default::default(); - assert_last_event::(Event::MetadataSet { asset_id: id, name, symbol, decimals, is_frozen: false }.into()); + assert_last_event::(Event::MetadataSet { asset_id: asset_id.into(), name, symbol, decimals, is_frozen: false }.into()); } clear_metadata { - let (caller, _) = create_default_asset::(true); + let (asset_id, caller, _) = create_default_asset::(true); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); let dummy = vec![0u8; T::StringLimit::get() as usize]; let origin = SystemOrigin::Signed(caller.clone()).into(); - Assets::::set_metadata(origin, Default::default(), dummy.clone(), dummy, 12)?; - }: _(SystemOrigin::Signed(caller), Default::default()) + Assets::::set_metadata(origin, asset_id, dummy.clone(), dummy, 12)?; + }: _(SystemOrigin::Signed(caller), asset_id) verify { - assert_last_event::(Event::MetadataCleared { asset_id: Default::default() }.into()); + assert_last_event::(Event::MetadataCleared { asset_id: asset_id.into() }.into()); } force_set_metadata { @@ -357,11 +360,11 @@ benchmarks_instance_pallet! { let symbol = vec![0u8; s as usize]; let decimals = 12; - create_default_asset::(true); + let (asset_id, _, _) = create_default_asset::(true); let origin = T::ForceOrigin::successful_origin(); let call = Call::::force_set_metadata { - id: Default::default(), + id: asset_id, name: name.clone(), symbol: symbol.clone(), decimals, @@ -369,30 +372,29 @@ benchmarks_instance_pallet! { }; }: { call.dispatch_bypass_filter(origin)? } verify { - let id = Default::default(); - assert_last_event::(Event::MetadataSet { asset_id: id, name, symbol, decimals, is_frozen: false }.into()); + assert_last_event::(Event::MetadataSet { asset_id: asset_id.into(), name, symbol, decimals, is_frozen: false }.into()); } force_clear_metadata { - let (caller, _) = create_default_asset::(true); + let (asset_id, caller, _) = create_default_asset::(true); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); let dummy = vec![0u8; T::StringLimit::get() as usize]; let origin = SystemOrigin::Signed(caller).into(); - Assets::::set_metadata(origin, Default::default(), dummy.clone(), dummy, 12)?; + Assets::::set_metadata(origin, asset_id, dummy.clone(), dummy, 12)?; let origin = T::ForceOrigin::successful_origin(); - let call = Call::::force_clear_metadata { id: Default::default() }; + let call = Call::::force_clear_metadata { id: asset_id }; }: { call.dispatch_bypass_filter(origin)? } verify { - assert_last_event::(Event::MetadataCleared { asset_id: Default::default() }.into()); + assert_last_event::(Event::MetadataCleared { asset_id: asset_id.into() }.into()); } force_asset_status { - let (caller, caller_lookup) = create_default_asset::(true); + let (asset_id, caller, caller_lookup) = create_default_asset::(true); let origin = T::ForceOrigin::successful_origin(); let call = Call::::force_asset_status { - id: Default::default(), + id: asset_id, owner: caller_lookup.clone(), issuer: caller_lookup.clone(), admin: caller_lookup.clone(), @@ -403,70 +405,66 @@ benchmarks_instance_pallet! { }; }: { call.dispatch_bypass_filter(origin)? } verify { - assert_last_event::(Event::AssetStatusChanged { asset_id: Default::default() }.into()); + assert_last_event::(Event::AssetStatusChanged { asset_id: asset_id.into() }.into()); } approve_transfer { - let (caller, _) = create_default_minted_asset::(true, 100u32.into()); + let (asset_id, caller, _) = create_default_minted_asset::(true, 100u32.into()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - let id = Default::default(); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let amount = 100u32.into(); - }: _(SystemOrigin::Signed(caller.clone()), id, delegate_lookup, amount) + }: _(SystemOrigin::Signed(caller.clone()), asset_id, delegate_lookup, amount) verify { - assert_last_event::(Event::ApprovedTransfer { asset_id: id, source: caller, delegate, amount }.into()); + assert_last_event::(Event::ApprovedTransfer { asset_id: asset_id.into(), source: caller, delegate, amount }.into()); } transfer_approved { - let (owner, owner_lookup) = create_default_minted_asset::(true, 100u32.into()); + let (asset_id, owner, owner_lookup) = create_default_minted_asset::(true, 100u32.into()); T::Currency::make_free_balance_be(&owner, DepositBalanceOf::::max_value()); - let id = Default::default(); let delegate: T::AccountId = account("delegate", 0, SEED); whitelist_account!(delegate); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let amount = 100u32.into(); let origin = SystemOrigin::Signed(owner.clone()).into(); - Assets::::approve_transfer(origin, id, delegate_lookup, amount)?; + Assets::::approve_transfer(origin, asset_id, delegate_lookup, amount)?; let dest: T::AccountId = account("dest", 0, SEED); let dest_lookup = T::Lookup::unlookup(dest.clone()); - }: _(SystemOrigin::Signed(delegate.clone()), id, owner_lookup, dest_lookup, amount) + }: _(SystemOrigin::Signed(delegate.clone()), asset_id, owner_lookup, dest_lookup, amount) verify { assert!(T::Currency::reserved_balance(&owner).is_zero()); - assert_event::(Event::Transferred { asset_id: id, from: owner, to: dest, amount }.into()); + assert_event::(Event::Transferred { asset_id: asset_id.into(), from: owner, to: dest, amount }.into()); } cancel_approval { - let (caller, _) = create_default_minted_asset::(true, 100u32.into()); + let (asset_id, caller, _) = create_default_minted_asset::(true, 100u32.into()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - let id = Default::default(); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let amount = 100u32.into(); let origin = SystemOrigin::Signed(caller.clone()).into(); - Assets::::approve_transfer(origin, id, delegate_lookup.clone(), amount)?; - }: _(SystemOrigin::Signed(caller.clone()), id, delegate_lookup) + Assets::::approve_transfer(origin, asset_id, delegate_lookup.clone(), amount)?; + }: _(SystemOrigin::Signed(caller.clone()), asset_id, delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled { asset_id: id, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { asset_id: asset_id.into(), owner: caller, delegate }.into()); } force_cancel_approval { - let (caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - let id = Default::default(); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let amount = 100u32.into(); let origin = SystemOrigin::Signed(caller.clone()).into(); - Assets::::approve_transfer(origin, id, delegate_lookup.clone(), amount)?; - }: _(SystemOrigin::Signed(caller.clone()), id, caller_lookup, delegate_lookup) + Assets::::approve_transfer(origin, asset_id, delegate_lookup.clone(), amount)?; + }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup, delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled { asset_id: id, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { asset_id: asset_id.into(), owner: caller, delegate }.into()); } impl_benchmark_test_suite!(Assets, crate::mock::new_test_ext(), crate::mock::Test) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index cdd0553218225..2902477d0f2b5 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -144,7 +144,6 @@ mod impl_stored_map; mod types; pub use types::*; -use codec::HasCompact; use scale_info::TypeInfo; use sp_runtime::{ traits::{ @@ -186,6 +185,17 @@ pub mod pallet { #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); + #[cfg(feature = "runtime-benchmarks")] + pub trait BenchmarkHelper { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter; + } + #[cfg(feature = "runtime-benchmarks")] + impl> BenchmarkHelper for () { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + id.into() + } + } + #[pallet::config] /// The module configuration trait. pub trait Config: frame_system::Config { @@ -210,14 +220,20 @@ pub mod pallet { type RemoveItemsLimit: Get; /// Identifier for the class of asset. - type AssetId: Member - + Parameter - + Default + type AssetId: Member + Parameter + Copy + MaybeSerializeDeserialize + MaxEncodedLen; + + /// Wrapper around `Self::AssetId` to use in dispatchable call signatures. Allows the use + /// of compact encoding in instances of the pallet, which will prevent breaking changes + /// resulting from the removal of `HasCompact` from `Self::AssetId`. + /// + /// This type includes the `From` bound, since tightly coupled pallets may + /// want to convert an `AssetId` into a parameter for calling dispatchable functions + /// directly. + type AssetIdParameter: Parameter + Copy - + HasCompact - + MaybeSerializeDeserialize - + MaxEncodedLen - + TypeInfo; + + From + + Into + + MaxEncodedLen; /// The currency mechanism. type Currency: ReservableCurrency; @@ -269,6 +285,10 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// Helper trait for benchmarks. + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper: BenchmarkHelper; } #[pallet::storage] @@ -546,10 +566,11 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::create())] pub fn create( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, admin: AccountIdLookupOf, min_balance: T::Balance, ) -> DispatchResult { + let id: T::AssetId = id.into(); let owner = T::CreateOrigin::ensure_origin(origin, &id)?; let admin = T::Lookup::lookup(admin)?; @@ -602,84 +623,86 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_create())] pub fn force_create( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, owner: AccountIdLookupOf, is_sufficient: bool, #[pallet::compact] min_balance: T::Balance, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; + let id: T::AssetId = id.into(); Self::do_force_create(id, owner, is_sufficient, min_balance) } - /// Start the process of destroying a class of fungible asset - /// start_destroy is the first in a series of extrinsics that should be called, to allow - /// destroying an asset. + /// Start the process of destroying a fungible asset class. + /// + /// `start_destroy` is the first in a series of extrinsics that should be called, to allow + /// destruction of an asset class. /// - /// The origin must conform to `ForceOrigin` or must be Signed and the sender must be the - /// owner of the asset `id`. + /// The origin must conform to `ForceOrigin` or must be `Signed` by the asset's `owner`. /// /// - `id`: The identifier of the asset to be destroyed. This must identify an existing /// asset. /// - /// Assets must be freezed before calling start_destroy. + /// The asset class must be frozen before calling `start_destroy`. #[pallet::weight(T::WeightInfo::start_destroy())] - pub fn start_destroy( - origin: OriginFor, - #[pallet::compact] id: T::AssetId, - ) -> DispatchResult { + pub fn start_destroy(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let maybe_check_owner = match T::ForceOrigin::try_origin(origin) { Ok(_) => None, Err(origin) => Some(ensure_signed(origin)?), }; + let id: T::AssetId = id.into(); Self::do_start_destroy(id, maybe_check_owner) } /// Destroy all accounts associated with a given asset. + /// /// `destroy_accounts` should only be called after `start_destroy` has been called, and the - /// asset is in a `Destroying` state + /// asset is in a `Destroying` state. /// - /// Due to weight restrictions, this function may need to be called multiple - /// times to fully destroy all accounts. It will destroy `RemoveItemsLimit` accounts at a - /// time. + /// Due to weight restrictions, this function may need to be called multiple times to fully + /// destroy all accounts. It will destroy `RemoveItemsLimit` accounts at a time. /// /// - `id`: The identifier of the asset to be destroyed. This must identify an existing /// asset. /// - /// Each call Emits the `Event::DestroyedAccounts` event. + /// Each call emits the `Event::DestroyedAccounts` event. #[pallet::weight(T::WeightInfo::destroy_accounts(T::RemoveItemsLimit::get()))] pub fn destroy_accounts( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; + let id: T::AssetId = id.into(); let removed_accounts = Self::do_destroy_accounts(id, T::RemoveItemsLimit::get())?; Ok(Some(T::WeightInfo::destroy_accounts(removed_accounts)).into()) } - /// Destroy all approvals associated with a given asset up to the max (T::RemoveItemsLimit), + /// Destroy all approvals associated with a given asset up to the max (T::RemoveItemsLimit). + /// /// `destroy_approvals` should only be called after `start_destroy` has been called, and the - /// asset is in a `Destroying` state + /// asset is in a `Destroying` state. /// - /// Due to weight restrictions, this function may need to be called multiple - /// times to fully destroy all approvals. It will destroy `RemoveItemsLimit` approvals at a - /// time. + /// Due to weight restrictions, this function may need to be called multiple times to fully + /// destroy all approvals. It will destroy `RemoveItemsLimit` approvals at a time. /// /// - `id`: The identifier of the asset to be destroyed. This must identify an existing /// asset. /// - /// Each call Emits the `Event::DestroyedApprovals` event. + /// Each call emits the `Event::DestroyedApprovals` event. #[pallet::weight(T::WeightInfo::destroy_approvals(T::RemoveItemsLimit::get()))] pub fn destroy_approvals( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; + let id: T::AssetId = id.into(); let removed_approvals = Self::do_destroy_approvals(id, T::RemoveItemsLimit::get())?; Ok(Some(T::WeightInfo::destroy_approvals(removed_approvals)).into()) } /// Complete destroying asset and unreserve currency. + /// /// `finish_destroy` should only be called after `start_destroy` has been called, and the /// asset is in a `Destroying` state. All accounts or approvals should be destroyed before /// hand. @@ -687,13 +710,11 @@ pub mod pallet { /// - `id`: The identifier of the asset to be destroyed. This must identify an existing /// asset. /// - /// Each successful call Emits the `Event::Destroyed` event. + /// Each successful call emits the `Event::Destroyed` event. #[pallet::weight(T::WeightInfo::finish_destroy())] - pub fn finish_destroy( - origin: OriginFor, - #[pallet::compact] id: T::AssetId, - ) -> DispatchResult { + pub fn finish_destroy(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let _ = ensure_signed(origin)?; + let id: T::AssetId = id.into(); Self::do_finish_destroy(id) } @@ -712,12 +733,13 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::mint())] pub fn mint( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, beneficiary: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let origin = ensure_signed(origin)?; let beneficiary = T::Lookup::lookup(beneficiary)?; + let id: T::AssetId = id.into(); Self::do_mint(id, &beneficiary, amount, Some(origin))?; Ok(()) } @@ -740,12 +762,13 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::burn())] pub fn burn( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, who: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let origin = ensure_signed(origin)?; let who = T::Lookup::lookup(who)?; + let id: T::AssetId = id.into(); let f = DebitFlags { keep_alive: false, best_effort: true }; let _ = Self::do_burn(id, &who, amount, Some(origin), f)?; @@ -773,12 +796,13 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, target: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(target)?; + let id: T::AssetId = id.into(); let f = TransferFlags { keep_alive: false, best_effort: false, burn_dust: false }; Self::do_transfer(id, &origin, &dest, amount, None, f).map(|_| ()) @@ -805,12 +829,13 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer_keep_alive())] pub fn transfer_keep_alive( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, target: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let source = ensure_signed(origin)?; let dest = T::Lookup::lookup(target)?; + let id: T::AssetId = id.into(); let f = TransferFlags { keep_alive: true, best_effort: false, burn_dust: false }; Self::do_transfer(id, &source, &dest, amount, None, f).map(|_| ()) @@ -838,7 +863,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_transfer())] pub fn force_transfer( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, source: AccountIdLookupOf, dest: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, @@ -846,6 +871,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; let source = T::Lookup::lookup(source)?; let dest = T::Lookup::lookup(dest)?; + let id: T::AssetId = id.into(); let f = TransferFlags { keep_alive: false, best_effort: false, burn_dust: false }; Self::do_transfer(id, &source, &dest, amount, Some(origin), f).map(|_| ()) @@ -864,10 +890,11 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::freeze())] pub fn freeze( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, who: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; + let id: T::AssetId = id.into(); let d = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!( @@ -899,10 +926,11 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::thaw())] pub fn thaw( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, who: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; + let id: T::AssetId = id.into(); let details = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!( @@ -931,11 +959,9 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::freeze_asset())] - pub fn freeze_asset( - origin: OriginFor, - #[pallet::compact] id: T::AssetId, - ) -> DispatchResult { + pub fn freeze_asset(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let origin = ensure_signed(origin)?; + let id: T::AssetId = id.into(); Asset::::try_mutate(id, |maybe_details| { let d = maybe_details.as_mut().ok_or(Error::::Unknown)?; @@ -959,11 +985,9 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::thaw_asset())] - pub fn thaw_asset( - origin: OriginFor, - #[pallet::compact] id: T::AssetId, - ) -> DispatchResult { + pub fn thaw_asset(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let origin = ensure_signed(origin)?; + let id: T::AssetId = id.into(); Asset::::try_mutate(id, |maybe_details| { let d = maybe_details.as_mut().ok_or(Error::::Unknown)?; @@ -990,11 +1014,12 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer_ownership())] pub fn transfer_ownership( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, owner: AccountIdLookupOf, ) -> DispatchResult { let origin = ensure_signed(origin)?; let owner = T::Lookup::lookup(owner)?; + let id: T::AssetId = id.into(); Asset::::try_mutate(id, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; @@ -1032,7 +1057,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_team())] pub fn set_team( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, issuer: AccountIdLookupOf, admin: AccountIdLookupOf, freezer: AccountIdLookupOf, @@ -1041,6 +1066,7 @@ pub mod pallet { let issuer = T::Lookup::lookup(issuer)?; let admin = T::Lookup::lookup(admin)?; let freezer = T::Lookup::lookup(freezer)?; + let id: T::AssetId = id.into(); Asset::::try_mutate(id, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; @@ -1075,12 +1101,13 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_metadata(name.len() as u32, symbol.len() as u32))] pub fn set_metadata( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, name: Vec, symbol: Vec, decimals: u8, ) -> DispatchResult { let origin = ensure_signed(origin)?; + let id: T::AssetId = id.into(); Self::do_set_metadata(id, &origin, name, symbol, decimals) } @@ -1096,11 +1123,9 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::weight(T::WeightInfo::clear_metadata())] - pub fn clear_metadata( - origin: OriginFor, - #[pallet::compact] id: T::AssetId, - ) -> DispatchResult { + pub fn clear_metadata(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let origin = ensure_signed(origin)?; + let id: T::AssetId = id.into(); let d = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); @@ -1131,13 +1156,14 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_set_metadata(name.len() as u32, symbol.len() as u32))] pub fn force_set_metadata( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, name: Vec, symbol: Vec, decimals: u8, is_frozen: bool, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; + let id: T::AssetId = id.into(); let bounded_name: BoundedVec = name.clone().try_into().map_err(|_| Error::::BadMetadata)?; @@ -1181,9 +1207,10 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_clear_metadata())] pub fn force_clear_metadata( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; + let id: T::AssetId = id.into(); let d = Asset::::get(id).ok_or(Error::::Unknown)?; Metadata::::try_mutate_exists(id, |metadata| { @@ -1219,7 +1246,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_asset_status())] pub fn force_asset_status( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, owner: AccountIdLookupOf, issuer: AccountIdLookupOf, admin: AccountIdLookupOf, @@ -1229,6 +1256,7 @@ pub mod pallet { is_frozen: bool, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; + let id: T::AssetId = id.into(); Asset::::try_mutate(id, |maybe_asset| { let mut asset = maybe_asset.take().ok_or(Error::::Unknown)?; @@ -1274,12 +1302,13 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::approve_transfer())] pub fn approve_transfer( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, delegate: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { let owner = ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; + let id: T::AssetId = id.into(); Self::do_approve_transfer(id, &owner, &delegate, amount) } @@ -1299,13 +1328,15 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::cancel_approval())] pub fn cancel_approval( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, delegate: AccountIdLookupOf, ) -> DispatchResult { let owner = ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; + let id: T::AssetId = id.into(); let mut d = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); + let approval = Approvals::::take((id, &owner, &delegate)).ok_or(Error::::Unknown)?; T::Currency::unreserve(&owner, approval.deposit); @@ -1333,10 +1364,11 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_cancel_approval())] pub fn force_cancel_approval( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, owner: AccountIdLookupOf, delegate: AccountIdLookupOf, ) -> DispatchResult { + let id: T::AssetId = id.into(); let mut d = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); T::ForceOrigin::try_origin(origin) @@ -1381,7 +1413,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::transfer_approved())] pub fn transfer_approved( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, owner: AccountIdLookupOf, destination: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, @@ -1389,6 +1421,7 @@ pub mod pallet { let delegate = ensure_signed(origin)?; let owner = T::Lookup::lookup(owner)?; let destination = T::Lookup::lookup(destination)?; + let id: T::AssetId = id.into(); Self::do_transfer_approved(id, &owner, &delegate, &destination, amount) } @@ -1402,7 +1435,8 @@ pub mod pallet { /// /// Emits `Touched` event when successful. #[pallet::weight(T::WeightInfo::mint())] - pub fn touch(origin: OriginFor, #[pallet::compact] id: T::AssetId) -> DispatchResult { + pub fn touch(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { + let id: T::AssetId = id.into(); Self::do_touch(id, ensure_signed(origin)?) } @@ -1417,9 +1451,10 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::mint())] pub fn refund( origin: OriginFor, - #[pallet::compact] id: T::AssetId, + id: T::AssetIdParameter, allow_burn: bool, ) -> DispatchResult { + let id: T::AssetId = id.into(); Self::do_refund(id, ensure_signed(origin)?, allow_burn) } } diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 567d63356a4ad..06b6ccf06c57e 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -88,6 +88,7 @@ impl Config for Test { type RuntimeEvent = RuntimeEvent; type Balance = u64; type AssetId = u32; + type AssetIdParameter = u32; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; @@ -101,6 +102,8 @@ impl Config for Test { type WeightInfo = (); type Extra = (); type RemoveItemsLimit = ConstU32<5>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } use std::collections::HashMap; diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 51ce2f69a4d8e..cfc56c91effd1 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -22,6 +22,7 @@ sp-std = { version = "5.0.0", default-features = false, path = "../../../primiti frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = ".." } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true } # Other dependencies codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } @@ -51,5 +52,12 @@ std = [ "sp-io/std", "sp-core/std", "pallet-transaction-payment/std", + "frame-benchmarking?/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index 7b605be5f830c..02e15654f3eed 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -16,6 +16,7 @@ use super::*; use crate as pallet_asset_tx_payment; +use codec; use frame_support::{ assert_ok, dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, @@ -152,10 +153,13 @@ impl pallet_transaction_payment::Config for Runtime { type OperationalFeeMultiplier = ConstU8<5>; } +type AssetId = u32; + impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; - type AssetId = u32; + type AssetId = AssetId; + type AssetIdParameter = codec::Compact; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = EnsureRoot; @@ -169,6 +173,8 @@ impl pallet_assets::Config for Runtime { type Extra = (); type WeightInfo = (); type RemoveItemsLimit = ConstU32<1000>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } pub struct HardcodedAuthor; @@ -341,7 +347,7 @@ fn transaction_payment_in_asset_possible() { let min_balance = 2; assert_ok!(Assets::force_create( RuntimeOrigin::root(), - asset_id, + asset_id.into(), 42, /* owner */ true, /* is_sufficient */ min_balance @@ -351,7 +357,7 @@ fn transaction_payment_in_asset_possible() { let caller = 1; let beneficiary = ::Lookup::unlookup(caller); let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); assert_eq!(Assets::balance(asset_id, caller), balance); let weight = 5; let len = 10; @@ -394,7 +400,7 @@ fn transaction_payment_without_fee() { let min_balance = 2; assert_ok!(Assets::force_create( RuntimeOrigin::root(), - asset_id, + asset_id.into(), 42, /* owner */ true, /* is_sufficient */ min_balance @@ -404,7 +410,7 @@ fn transaction_payment_without_fee() { let caller = 1; let beneficiary = ::Lookup::unlookup(caller); let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); assert_eq!(Assets::balance(asset_id, caller), balance); let weight = 5; let len = 10; @@ -447,7 +453,7 @@ fn asset_transaction_payment_with_tip_and_refund() { let min_balance = 2; assert_ok!(Assets::force_create( RuntimeOrigin::root(), - asset_id, + asset_id.into(), 42, /* owner */ true, /* is_sufficient */ min_balance @@ -457,7 +463,7 @@ fn asset_transaction_payment_with_tip_and_refund() { let caller = 2; let beneficiary = ::Lookup::unlookup(caller); let balance = 1000; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); assert_eq!(Assets::balance(asset_id, caller), balance); let weight = 100; let tip = 5; @@ -499,7 +505,7 @@ fn payment_from_account_with_only_assets() { let min_balance = 2; assert_ok!(Assets::force_create( RuntimeOrigin::root(), - asset_id, + asset_id.into(), 42, /* owner */ true, /* is_sufficient */ min_balance @@ -509,7 +515,7 @@ fn payment_from_account_with_only_assets() { let caller = 333; let beneficiary = ::Lookup::unlookup(caller); let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); assert_eq!(Assets::balance(asset_id, caller), balance); // assert that native balance is not necessary assert_eq!(Balances::free_balance(caller), 0); @@ -558,7 +564,7 @@ fn payment_only_with_existing_sufficient_asset() { let min_balance = 2; assert_ok!(Assets::force_create( RuntimeOrigin::root(), - asset_id, + asset_id.into(), 42, /* owner */ false, /* is_sufficient */ min_balance @@ -583,7 +589,7 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { let min_balance = 1; assert_ok!(Assets::force_create( RuntimeOrigin::root(), - asset_id, + asset_id.into(), 42, /* owner */ true, /* is_sufficient */ min_balance @@ -593,7 +599,7 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { let caller = 333; let beneficiary = ::Lookup::unlookup(caller); let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); assert_eq!(Assets::balance(asset_id, caller), balance); let weight = 1; let len = 1; @@ -648,7 +654,7 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { let min_balance = 100; assert_ok!(Assets::force_create( RuntimeOrigin::root(), - asset_id, + asset_id.into(), 42, /* owner */ true, /* is_sufficient */ min_balance @@ -658,7 +664,7 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { let caller = 333; let beneficiary = ::Lookup::unlookup(caller); let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); assert_eq!(Assets::balance(asset_id, caller), balance); let weight = 1; let len = 1; @@ -705,7 +711,7 @@ fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { let min_balance = 100; assert_ok!(Assets::force_create( RuntimeOrigin::root(), - asset_id, + asset_id.into(), 42, /* owner */ true, /* is_sufficient */ min_balance @@ -715,7 +721,7 @@ fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { let caller = 333; let beneficiary = ::Lookup::unlookup(caller); let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); assert_eq!(Assets::balance(asset_id, caller), balance); let weight = 1; let len = 1; From 9ce75afde9ada98a69e4ab3abbbfb7fa8202d72b Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Tue, 29 Nov 2022 16:39:52 +0200 Subject: [PATCH 1416/1472] pallet-mmr: move offchain logic to client-side gadget (#12753) * Move MMR utils methods from pallet to primitives Signed-off-by: Serban Iorga * Add method to MmrApi * Move forks expanding logic from babe to primitives * Implement MMR gadget * Remove prunning logic from the MMR pallet * Code review changes: 1st iteration * Replace MaybeCanonEngine with CanonEngineBuilder * fix mmr_leaves_count() for kitchen sink demo * Update client/merkle-mountain-range/src/canon_engine.rs Co-authored-by: Adrian Catangiu * Code review changes: 2nd iteration * fix INDEXING_PREFIX * impl review comments * add documentation and minor rename Signed-off-by: Serban Iorga Co-authored-by: Adrian Catangiu --- Cargo.lock | 25 +- Cargo.toml | 1 + bin/node/runtime/src/lib.rs | 4 + client/consensus/babe/src/lib.rs | 63 +--- client/merkle-mountain-range/Cargo.toml | 32 ++ client/merkle-mountain-range/src/lib.rs | 245 +++++++++++++ .../merkle-mountain-range/src/offchain_mmr.rs | 246 +++++++++++++ .../merkle-mountain-range/src/test_utils.rs | 344 ++++++++++++++++++ frame/merkle-mountain-range/Cargo.toml | 2 - frame/merkle-mountain-range/rpc/src/lib.rs | 2 +- frame/merkle-mountain-range/src/lib.rs | 102 ++---- frame/merkle-mountain-range/src/mmr/mmr.rs | 2 +- frame/merkle-mountain-range/src/mmr/mod.rs | 3 +- .../merkle-mountain-range/src/mmr/storage.rs | 209 ++--------- frame/merkle-mountain-range/src/tests.rs | 262 ++----------- primitives/blockchain/src/backend.rs | 74 +++- primitives/blockchain/src/error.rs | 3 + primitives/merkle-mountain-range/Cargo.toml | 2 + primitives/merkle-mountain-range/src/lib.rs | 14 +- .../merkle-mountain-range/src}/utils.rs | 83 +++-- test-utils/runtime/src/lib.rs | 6 +- 21 files changed, 1162 insertions(+), 562 deletions(-) create mode 100644 client/merkle-mountain-range/Cargo.toml create mode 100644 client/merkle-mountain-range/src/lib.rs create mode 100644 client/merkle-mountain-range/src/offchain_mmr.rs create mode 100644 client/merkle-mountain-range/src/test_utils.rs rename {frame/merkle-mountain-range/src/mmr => primitives/merkle-mountain-range/src}/utils.rs (69%) diff --git a/Cargo.lock b/Cargo.lock index 8f4653940f3cb..a99f3674de15f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4230,6 +4230,29 @@ dependencies = [ "windows-sys 0.36.1", ] +[[package]] +name = "mmr-gadget" +version = "4.0.0-dev" +dependencies = [ + "async-std", + "beefy-primitives", + "futures", + "log", + "parity-scale-codec", + "sc-block-builder", + "sc-client-api", + "sc-offchain", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-io", + "sp-mmr-primitives", + "sp-runtime", + "substrate-test-runtime-client", + "tokio", +] + [[package]] name = "mockall" version = "0.11.2" @@ -5645,7 +5668,6 @@ name = "pallet-mmr" version = "4.0.0-dev" dependencies = [ "array-bytes", - "ckb-merkle-mountain-range", "env_logger", "frame-benchmarking", "frame-support", @@ -9724,6 +9746,7 @@ name = "sp-mmr-primitives" version = "4.0.0-dev" dependencies = [ "array-bytes", + "ckb-merkle-mountain-range", "log", "parity-scale-codec", "scale-info", diff --git a/Cargo.toml b/Cargo.toml index 956c106e0dc2d..ebdf73db0dba3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ members = [ "client/finality-grandpa", "client/informant", "client/keystore", + "client/merkle-mountain-range", "client/network", "client/network-gossip", "client/network/bitswap", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index ef1e3bb8f3c4b..f284aaa3a69a8 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2066,6 +2066,10 @@ impl_runtime_apis! { Ok(Mmr::mmr_root()) } + fn mmr_leaf_count() -> Result { + Ok(Mmr::mmr_leaves()) + } + fn generate_proof( block_numbers: Vec, best_known_block_number: Option, diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 109e5aade02a7..4cb300b9bcd04 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -111,7 +111,8 @@ use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_application_crypto::AppKey; use sp_block_builder::BlockBuilder as BlockBuilderApi; use sp_blockchain::{ - Backend as _, Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult, + Backend as _, Error as ClientError, ForkBackend, HeaderBackend, HeaderMetadata, + Result as ClientResult, }; use sp_consensus::{ BlockOrigin, CacheKeyId, Environment, Error as ConsensusError, Proposer, SelectChain, @@ -123,7 +124,7 @@ use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvid use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::{BlockId, OpaqueDigestItemId}, - traits::{Block as BlockT, Header, NumberFor, SaturatedConversion, Saturating, Zero}, + traits::{Block as BlockT, Header, NumberFor, SaturatedConversion, Zero}, DigestItem, }; @@ -515,12 +516,12 @@ fn aux_storage_cleanup + HeaderBackend, Block: B client: &C, notification: &FinalityNotification, ) -> AuxDataOperations { - let mut aux_keys = HashSet::new(); + let mut hashes = HashSet::new(); let first = notification.tree_route.first().unwrap_or(¬ification.hash); match client.header_metadata(*first) { Ok(meta) => { - aux_keys.insert(aux_schema::block_weight_key(meta.parent)); + hashes.insert(meta.parent); }, Err(err) => warn!( target: "babe", @@ -531,53 +532,29 @@ fn aux_storage_cleanup + HeaderBackend, Block: B } // Cleans data for finalized block's ancestors - aux_keys.extend( + hashes.extend( notification .tree_route .iter() // Ensure we don't prune latest finalized block. // This should not happen, but better be safe than sorry! - .filter(|h| **h != notification.hash) - .map(aux_schema::block_weight_key), + .filter(|h| **h != notification.hash), ); - // Cleans data for stale branches. - - for head in notification.stale_heads.iter() { - let mut hash = *head; - // Insert stale blocks hashes until canonical chain is reached. - // If we reach a block that is already part of the `aux_keys` we can stop the processing the - // head. - while aux_keys.insert(aux_schema::block_weight_key(hash)) { - match client.header_metadata(hash) { - Ok(meta) => { - hash = meta.parent; - - // If the parent is part of the canonical chain or there doesn't exist a block - // hash for the parent number (bug?!), we can abort adding blocks. - if client - .hash(meta.number.saturating_sub(1u32.into())) - .ok() - .flatten() - .map_or(true, |h| h == hash) - { - break - } - }, - Err(err) => { - warn!( - target: "babe", - "Header lookup fail while cleaning data for block {:?}: {}", - hash, - err, - ); - break - }, - } - } - } + // Cleans data for stale forks. + let stale_forks = match client.expand_forks(¬ification.stale_heads) { + Ok(stale_forks) => stale_forks, + Err((stale_forks, e)) => { + warn!(target: "babe", "{:?}", e,); + stale_forks + }, + }; + hashes.extend(stale_forks.iter()); - aux_keys.into_iter().map(|val| (val, None)).collect() + hashes + .into_iter() + .map(|val| (aux_schema::block_weight_key(val), None)) + .collect() } async fn answer_requests( diff --git a/client/merkle-mountain-range/Cargo.toml b/client/merkle-mountain-range/Cargo.toml new file mode 100644 index 0000000000000..3630c42414964 --- /dev/null +++ b/client/merkle-mountain-range/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "mmr-gadget" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository = "https://github.com/paritytech/substrate" +description = "MMR Client gadget for substrate" +homepage = "https://substrate.io" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0" } +futures = "0.3" +log = "0.4" +beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } +sc-client-api = { version = "4.0.0-dev", path = "../api" } +sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../primitives/io" } +sp-mmr-primitives = { version = "4.0.0-dev", path = "../../primitives/merkle-mountain-range" } +sc-offchain = { version = "4.0.0-dev", path = "../offchain" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } + +[dev-dependencies] +tokio = "1.17.0" +sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } +async-std = { version = "1.11.0", default-features = false } diff --git a/client/merkle-mountain-range/src/lib.rs b/client/merkle-mountain-range/src/lib.rs new file mode 100644 index 0000000000000..4f911a78a51d7 --- /dev/null +++ b/client/merkle-mountain-range/src/lib.rs @@ -0,0 +1,245 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! # MMR offchain gadget +//! +//! The MMR offchain gadget is run alongside `pallet-mmr` to assist it with offchain +//! canonicalization of finalized MMR leaves and nodes. +//! The gadget should only be run on nodes that have Indexing API enabled (otherwise +//! `pallet-mmr` cannot write to offchain and this gadget has nothing to do). +//! +//! The runtime `pallet-mmr` creates one new MMR leaf per block and all inner MMR parent nodes +//! generated by the MMR when adding said leaf. MMR nodes are stored both in: +//! - on-chain storage - hashes only; not full leaf content; +//! - off-chain storage - via Indexing API, full leaf content (and all internal nodes as well) is +//! saved to the Off-chain DB using a key derived from `parent_hash` and node index in MMR. The +//! `parent_hash` is also used within the key to avoid conflicts and overwrites on forks (leaf +//! data is only allowed to reference data coming from parent block). +//! +//! This gadget is driven by block finality and in responsible for pruning stale forks from +//! offchain db, and moving finalized forks under a "canonical" key based solely on node `pos` +//! in the MMR. + +#![warn(missing_docs)] + +mod offchain_mmr; +#[cfg(test)] +pub mod test_utils; + +use std::{marker::PhantomData, sync::Arc}; + +use futures::StreamExt; +use log::{debug, error, trace, warn}; + +use sc_client_api::{Backend, BlockchainEvents, FinalityNotifications}; +use sc_offchain::OffchainDb; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::{HeaderBackend, HeaderMetadata}; +use sp_mmr_primitives::{utils, LeafIndex, MmrApi}; +use sp_runtime::{ + generic::BlockId, + traits::{Block, Header, NumberFor}, +}; + +use crate::offchain_mmr::OffchainMMR; +use beefy_primitives::MmrRootHash; +use sp_core::offchain::OffchainStorage; + +/// Logging target for the mmr gadget. +pub const LOG_TARGET: &str = "mmr"; + +struct OffchainMmrBuilder { + client: Arc, + offchain_db: OffchainDb, + indexing_prefix: Vec, + + _phantom: PhantomData, +} + +impl OffchainMmrBuilder +where + B: Block, + C: ProvideRuntimeApi + HeaderBackend + HeaderMetadata, + C::Api: MmrApi>, + S: OffchainStorage, +{ + async fn try_build( + self, + finality_notifications: &mut FinalityNotifications, + ) -> Option> { + while let Some(notification) = finality_notifications.next().await { + let best_block = *notification.header.number(); + match self.client.runtime_api().mmr_leaf_count(&BlockId::number(best_block)) { + Ok(Ok(mmr_leaf_count)) => { + match utils::first_mmr_block_num::(best_block, mmr_leaf_count) { + Ok(first_mmr_block) => { + let mut offchain_mmr = OffchainMMR { + client: self.client, + offchain_db: self.offchain_db, + indexing_prefix: self.indexing_prefix, + first_mmr_block, + + _phantom: Default::default(), + }; + // We have to canonicalize and prune the blocks in the finality + // notification that lead to building the offchain-mmr as well. + offchain_mmr.canonicalize_and_prune(¬ification); + return Some(offchain_mmr) + }, + Err(e) => { + error!( + target: LOG_TARGET, + "Error calculating the first mmr block: {:?}", e + ); + }, + } + }, + _ => { + trace!(target: LOG_TARGET, "Finality notification: {:?}", notification); + debug!(target: LOG_TARGET, "Waiting for MMR pallet to become available ..."); + }, + } + } + + warn!( + target: LOG_TARGET, + "Finality notifications stream closed unexpectedly. \ + Couldn't build the canonicalization engine", + ); + None + } +} + +/// A MMR Gadget. +pub struct MmrGadget, C> { + finality_notifications: FinalityNotifications, + + _phantom: PhantomData<(B, BE, C)>, +} + +impl MmrGadget +where + B: Block, + ::Number: Into, + BE: Backend, + C: BlockchainEvents + HeaderBackend + HeaderMetadata + ProvideRuntimeApi, + C::Api: MmrApi>, +{ + async fn run(mut self, builder: OffchainMmrBuilder) { + let mut offchain_mmr = match builder.try_build(&mut self.finality_notifications).await { + Some(offchain_mmr) => offchain_mmr, + None => return, + }; + + while let Some(notification) = self.finality_notifications.next().await { + offchain_mmr.canonicalize_and_prune(¬ification); + } + } + + /// Create and run the MMR gadget. + pub async fn start(client: Arc, backend: Arc, indexing_prefix: Vec) { + let offchain_db = match backend.offchain_storage() { + Some(offchain_storage) => OffchainDb::new(offchain_storage), + None => { + warn!( + target: LOG_TARGET, + "Can't spawn a MmrGadget for a node without offchain storage." + ); + return + }, + }; + + let mmr_gadget = MmrGadget:: { + finality_notifications: client.finality_notification_stream(), + + _phantom: Default::default(), + }; + mmr_gadget + .run(OffchainMmrBuilder { + client, + offchain_db, + indexing_prefix, + _phantom: Default::default(), + }) + .await + } +} + +#[cfg(test)] +mod tests { + use crate::test_utils::run_test_with_mmr_gadget; + use sp_runtime::generic::BlockId; + use std::time::Duration; + + #[test] + fn mmr_first_block_is_computed_correctly() { + // Check the case where the first block is also the first block with MMR. + run_test_with_mmr_gadget(|client| async move { + // G -> A1 -> A2 + // | + // | -> first mmr block + + let a1 = client.import_block(&BlockId::Number(0), b"a1", Some(0)).await; + let a2 = client.import_block(&BlockId::Hash(a1.hash()), b"a2", Some(1)).await; + + client.finalize_block(a1.hash(), Some(1)); + async_std::task::sleep(Duration::from_millis(200)).await; + // expected finalized heads: a1 + client.assert_canonicalized(&[&a1]); + client.assert_not_pruned(&[&a2]); + }); + + // Check the case where the first block with MMR comes later. + run_test_with_mmr_gadget(|client| async move { + // G -> A1 -> A2 -> A3 -> A4 -> A5 -> A6 + // | + // | -> first mmr block + + let a1 = client.import_block(&BlockId::Number(0), b"a1", None).await; + let a2 = client.import_block(&BlockId::Hash(a1.hash()), b"a2", None).await; + let a3 = client.import_block(&BlockId::Hash(a2.hash()), b"a3", None).await; + let a4 = client.import_block(&BlockId::Hash(a3.hash()), b"a4", Some(0)).await; + let a5 = client.import_block(&BlockId::Hash(a4.hash()), b"a5", Some(1)).await; + let a6 = client.import_block(&BlockId::Hash(a5.hash()), b"a6", Some(2)).await; + + client.finalize_block(a5.hash(), Some(2)); + async_std::task::sleep(Duration::from_millis(200)).await; + // expected finalized heads: a4, a5 + client.assert_canonicalized(&[&a4, &a5]); + client.assert_not_pruned(&[&a6]); + }); + } + + #[test] + fn does_not_panic_on_invalid_num_mmr_blocks() { + run_test_with_mmr_gadget(|client| async move { + // G -> A1 + // | + // | -> first mmr block + + let a1 = client.import_block(&BlockId::Number(0), b"a1", Some(0)).await; + + // Simulate the case where the runtime says that there are 2 mmr_blocks when in fact + // there is only 1. + client.finalize_block(a1.hash(), Some(2)); + async_std::task::sleep(Duration::from_millis(200)).await; + // expected finalized heads: - + client.assert_not_canonicalized(&[&a1]); + }); + } +} diff --git a/client/merkle-mountain-range/src/offchain_mmr.rs b/client/merkle-mountain-range/src/offchain_mmr.rs new file mode 100644 index 0000000000000..7400226b73c44 --- /dev/null +++ b/client/merkle-mountain-range/src/offchain_mmr.rs @@ -0,0 +1,246 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Logic for canonicalizing MMR offchain entries for finalized forks, +//! and for pruning MMR offchain entries for stale forks. + +#![warn(missing_docs)] + +use std::{marker::PhantomData, sync::Arc}; + +use log::{debug, error, warn}; + +use sc_client_api::FinalityNotification; +use sc_offchain::OffchainDb; +use sp_blockchain::{CachedHeaderMetadata, ForkBackend, HeaderBackend, HeaderMetadata}; +use sp_core::offchain::{DbExternalities, OffchainStorage, StorageKind}; +use sp_mmr_primitives::{utils, utils::NodesUtils, NodeIndex}; +use sp_runtime::traits::{Block, Header}; + +use crate::LOG_TARGET; + +/// `OffchainMMR` exposes MMR offchain canonicalization and pruning logic. +pub struct OffchainMMR { + pub client: Arc, + pub offchain_db: OffchainDb, + pub indexing_prefix: Vec, + pub first_mmr_block: ::Number, + + pub _phantom: PhantomData, +} + +impl OffchainMMR +where + C: HeaderBackend + HeaderMetadata, + S: OffchainStorage, + B: Block, +{ + fn node_temp_offchain_key(&self, pos: NodeIndex, parent_hash: B::Hash) -> Vec { + NodesUtils::node_temp_offchain_key::(&self.indexing_prefix, pos, parent_hash) + } + + fn node_canon_offchain_key(&self, pos: NodeIndex) -> Vec { + NodesUtils::node_canon_offchain_key(&self.indexing_prefix, pos) + } + + fn header_metadata_or_log( + &self, + hash: B::Hash, + action: &str, + ) -> Option> { + match self.client.header_metadata(hash) { + Ok(header) => Some(header), + _ => { + error!( + target: LOG_TARGET, + "Block {} not found. Couldn't {} associated branch.", hash, action + ); + None + }, + } + } + + fn right_branch_ending_in_block_or_log( + &self, + block_num: ::Number, + action: &str, + ) -> Option> { + match utils::block_num_to_leaf_index::(block_num, self.first_mmr_block) { + Ok(leaf_idx) => { + let branch = NodesUtils::right_branch_ending_in_leaf(leaf_idx); + debug!( + target: LOG_TARGET, + "Nodes to {} for block {}: {:?}", action, block_num, branch + ); + Some(branch) + }, + Err(e) => { + error!( + target: LOG_TARGET, + "Error converting block number {} to leaf index: {:?}. \ + Couldn't {} associated branch.", + block_num, + e, + action + ); + None + }, + } + } + + fn prune_branch(&mut self, block_hash: &B::Hash) { + let action = "prune"; + let header = match self.header_metadata_or_log(*block_hash, action) { + Some(header) => header, + _ => return, + }; + + // We prune the leaf associated with the provided block and all the nodes added by that + // leaf. + let stale_nodes = match self.right_branch_ending_in_block_or_log(header.number, action) { + Some(nodes) => nodes, + None => { + // If we can't convert the block number to a leaf index, the chain state is probably + // corrupted. We only log the error, hoping that the chain state will be fixed. + return + }, + }; + + for pos in stale_nodes { + let temp_key = self.node_temp_offchain_key(pos, header.parent); + self.offchain_db.local_storage_clear(StorageKind::PERSISTENT, &temp_key); + debug!(target: LOG_TARGET, "Pruned elem at pos {} with temp key {:?}", pos, temp_key); + } + } + + fn canonicalize_branch(&mut self, block_hash: &B::Hash) { + let action = "canonicalize"; + let header = match self.header_metadata_or_log(*block_hash, action) { + Some(header) => header, + _ => return, + }; + + // Don't canonicalize branches corresponding to blocks for which the MMR pallet + // wasn't yet initialized. + if header.number < self.first_mmr_block { + return + } + + // We "canonicalize" the leaf associated with the provided block + // and all the nodes added by that leaf. + let to_canon_nodes = match self.right_branch_ending_in_block_or_log(header.number, action) { + Some(nodes) => nodes, + None => { + // If we can't convert the block number to a leaf index, the chain state is probably + // corrupted. We only log the error, hoping that the chain state will be fixed. + return + }, + }; + + for pos in to_canon_nodes { + let temp_key = self.node_temp_offchain_key(pos, header.parent); + if let Some(elem) = + self.offchain_db.local_storage_get(StorageKind::PERSISTENT, &temp_key) + { + let canon_key = self.node_canon_offchain_key(pos); + self.offchain_db.local_storage_set(StorageKind::PERSISTENT, &canon_key, &elem); + self.offchain_db.local_storage_clear(StorageKind::PERSISTENT, &temp_key); + debug!( + target: LOG_TARGET, + "Moved elem at pos {} from temp key {:?} to canon key {:?}", + pos, + temp_key, + canon_key + ); + } else { + error!( + target: LOG_TARGET, + "Couldn't canonicalize elem at pos {} using temp key {:?}", pos, temp_key + ); + } + } + } + + /// Move leafs and nodes added by finalized blocks in offchain db from _fork-aware key_ to + /// _canonical key_. + /// Prune leafs and nodes added by stale blocks in offchain db from _fork-aware key_. + pub fn canonicalize_and_prune(&mut self, notification: &FinalityNotification) { + // Move offchain MMR nodes for finalized blocks to canonical keys. + for block_hash in notification.tree_route.iter().chain(std::iter::once(¬ification.hash)) + { + self.canonicalize_branch(block_hash); + } + + // Remove offchain MMR nodes for stale forks. + let stale_forks = self.client.expand_forks(¬ification.stale_heads).unwrap_or_else( + |(stale_forks, e)| { + warn!(target: LOG_TARGET, "{:?}", e); + stale_forks + }, + ); + for hash in stale_forks.iter() { + self.prune_branch(hash); + } + } +} + +#[cfg(test)] +mod tests { + use crate::test_utils::run_test_with_mmr_gadget; + use sp_runtime::generic::BlockId; + use std::time::Duration; + + #[test] + fn canonicalize_and_prune_works_correctly() { + run_test_with_mmr_gadget(|client| async move { + // -> D4 -> D5 + // G -> A1 -> A2 -> A3 -> A4 + // -> B1 -> B2 -> B3 + // -> C1 + + let a1 = client.import_block(&BlockId::Number(0), b"a1", Some(0)).await; + let a2 = client.import_block(&BlockId::Hash(a1.hash()), b"a2", Some(1)).await; + let a3 = client.import_block(&BlockId::Hash(a2.hash()), b"a3", Some(2)).await; + let a4 = client.import_block(&BlockId::Hash(a3.hash()), b"a4", Some(3)).await; + + let b1 = client.import_block(&BlockId::Number(0), b"b1", Some(0)).await; + let b2 = client.import_block(&BlockId::Hash(b1.hash()), b"b2", Some(1)).await; + let b3 = client.import_block(&BlockId::Hash(b2.hash()), b"b3", Some(2)).await; + + let c1 = client.import_block(&BlockId::Number(0), b"c1", Some(0)).await; + + let d4 = client.import_block(&BlockId::Hash(a3.hash()), b"d4", Some(3)).await; + let d5 = client.import_block(&BlockId::Hash(d4.hash()), b"d5", Some(4)).await; + + client.finalize_block(a3.hash(), Some(3)); + async_std::task::sleep(Duration::from_millis(200)).await; + // expected finalized heads: a1, a2, a3 + client.assert_canonicalized(&[&a1, &a2, &a3]); + // expected stale heads: c1 + // expected pruned heads because of temp key collision: b1 + client.assert_pruned(&[&c1, &b1]); + + client.finalize_block(d5.hash(), None); + async_std::task::sleep(Duration::from_millis(200)).await; + // expected finalized heads: d4, d5, + client.assert_canonicalized(&[&d4, &d5]); + // expected stale heads: b1, b2, b3, a4 + client.assert_pruned(&[&b1, &b2, &b3, &a4]); + }) + } +} diff --git a/client/merkle-mountain-range/src/test_utils.rs b/client/merkle-mountain-range/src/test_utils.rs new file mode 100644 index 0000000000000..0ba297c2808d2 --- /dev/null +++ b/client/merkle-mountain-range/src/test_utils.rs @@ -0,0 +1,344 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use futures::{executor::LocalPool, task::LocalSpawn, FutureExt}; +use std::{ + future::Future, + sync::{Arc, Mutex}, + time::Duration, +}; + +use sc_block_builder::BlockBuilderProvider; +use sc_client_api::{ + Backend as BackendT, BlockchainEvents, FinalityNotifications, ImportNotifications, + StorageEventStream, StorageKey, +}; +use sc_offchain::OffchainDb; +use sp_api::{ApiRef, ProvideRuntimeApi}; +use sp_blockchain::{BlockStatus, CachedHeaderMetadata, HeaderBackend, HeaderMetadata, Info}; +use sp_consensus::BlockOrigin; +use sp_core::{ + offchain::{DbExternalities, StorageKind}, + H256, +}; +use sp_mmr_primitives as mmr; +use sp_mmr_primitives::{utils::NodesUtils, LeafIndex, NodeIndex}; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Header as HeaderT}, +}; +use substrate_test_runtime_client::{ + runtime::{Block, BlockNumber, Hash, Header}, + Backend, BlockBuilderExt, Client, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, + TestClientBuilder, TestClientBuilderExt, +}; + +use crate::MmrGadget; + +type MmrHash = H256; + +struct MockRuntimeApiData { + num_blocks: BlockNumber, +} + +#[derive(Clone)] +pub struct MockRuntimeApi { + data: Arc>, +} + +impl MockRuntimeApi { + pub const INDEXING_PREFIX: &'static [u8] = b"mmr_test"; +} + +pub struct MmrBlock { + block: Block, + leaf_idx: Option, + leaf_data: Vec, +} + +#[derive(Clone, Copy)] +pub enum OffchainKeyType { + Temp, + Canon, +} + +impl MmrBlock { + pub fn hash(&self) -> Hash { + self.block.hash() + } + + pub fn parent_hash(&self) -> Hash { + *self.block.header.parent_hash() + } + + pub fn get_offchain_key(&self, node: NodeIndex, key_type: OffchainKeyType) -> Vec { + match key_type { + OffchainKeyType::Temp => NodesUtils::node_temp_offchain_key::
( + MockRuntimeApi::INDEXING_PREFIX, + node, + *self.block.header.parent_hash(), + ), + OffchainKeyType::Canon => + NodesUtils::node_canon_offchain_key(MockRuntimeApi::INDEXING_PREFIX, node), + } + } +} + +pub struct MockClient { + client: Mutex>, + backend: Arc, + runtime_api_params: Arc>, +} + +impl MockClient { + fn new() -> Self { + let client_builder = TestClientBuilder::new().enable_offchain_indexing_api(); + let (client, backend) = client_builder.build_with_backend(); + MockClient { + client: Mutex::new(client), + backend, + runtime_api_params: Arc::new(Mutex::new(MockRuntimeApiData { num_blocks: 0 })), + } + } + + fn offchain_db(&self) -> OffchainDb<>::OffchainStorage> { + OffchainDb::new(self.backend.offchain_storage().unwrap()) + } + + pub async fn import_block( + &self, + at: &BlockId, + name: &[u8], + maybe_leaf_idx: Option, + ) -> MmrBlock { + let mut client = self.client.lock().unwrap(); + + let mut block_builder = client.new_block_at(at, Default::default(), false).unwrap(); + // Make sure the block has a different hash than its siblings + block_builder + .push_storage_change(b"name".to_vec(), Some(name.to_vec())) + .unwrap(); + let block = block_builder.build().unwrap().block; + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + let parent_hash = *block.header.parent_hash(); + // Simulate writing MMR nodes in offchain storage + if let Some(leaf_idx) = maybe_leaf_idx { + let mut offchain_db = self.offchain_db(); + for node in NodesUtils::right_branch_ending_in_leaf(leaf_idx) { + let temp_key = NodesUtils::node_temp_offchain_key::
( + MockRuntimeApi::INDEXING_PREFIX, + node, + parent_hash, + ); + offchain_db.local_storage_set( + StorageKind::PERSISTENT, + &temp_key, + parent_hash.as_ref(), + ) + } + } + + MmrBlock { block, leaf_idx: maybe_leaf_idx, leaf_data: parent_hash.as_ref().to_vec() } + } + + pub fn finalize_block(&self, hash: Hash, maybe_num_mmr_blocks: Option) { + let client = self.client.lock().unwrap(); + if let Some(num_mmr_blocks) = maybe_num_mmr_blocks { + self.runtime_api_params.lock().unwrap().num_blocks = num_mmr_blocks; + } + + client.finalize_block(hash, None).unwrap(); + } + + pub fn check_offchain_storage( + &self, + key_type: OffchainKeyType, + blocks: &[&MmrBlock], + mut f: F, + ) where + F: FnMut(Option>, &MmrBlock), + { + let mut offchain_db = self.offchain_db(); + for mmr_block in blocks { + for node in NodesUtils::right_branch_ending_in_leaf(mmr_block.leaf_idx.unwrap()) { + let temp_key = mmr_block.get_offchain_key(node, key_type); + let val = offchain_db.local_storage_get(StorageKind::PERSISTENT, &temp_key); + f(val, mmr_block); + } + } + } + + pub fn assert_pruned(&self, blocks: &[&MmrBlock]) { + self.check_offchain_storage(OffchainKeyType::Temp, blocks, |val, _block| { + assert!(val.is_none()); + }) + } + + pub fn assert_not_pruned(&self, blocks: &[&MmrBlock]) { + self.check_offchain_storage(OffchainKeyType::Temp, blocks, |val, block| { + assert_eq!(val.as_ref(), Some(&block.leaf_data)); + }) + } + + pub fn assert_canonicalized(&self, blocks: &[&MmrBlock]) { + self.check_offchain_storage(OffchainKeyType::Canon, blocks, |val, block| { + assert_eq!(val.as_ref(), Some(&block.leaf_data)); + }); + + self.assert_pruned(blocks); + } + + pub fn assert_not_canonicalized(&self, blocks: &[&MmrBlock]) { + self.check_offchain_storage(OffchainKeyType::Canon, blocks, |val, _block| { + assert!(val.is_none()); + }); + + self.assert_not_pruned(blocks); + } +} + +impl HeaderMetadata for MockClient { + type Error = as HeaderMetadata>::Error; + + fn header_metadata(&self, hash: Hash) -> Result, Self::Error> { + self.client.lock().unwrap().header_metadata(hash) + } + + fn insert_header_metadata(&self, _hash: Hash, _header_metadata: CachedHeaderMetadata) { + todo!() + } + + fn remove_header_metadata(&self, _hash: Hash) { + todo!() + } +} + +impl HeaderBackend for MockClient { + fn header(&self, id: BlockId) -> sc_client_api::blockchain::Result> { + self.client.lock().unwrap().header(&id) + } + + fn info(&self) -> Info { + self.client.lock().unwrap().info() + } + + fn status(&self, id: BlockId) -> sc_client_api::blockchain::Result { + self.client.lock().unwrap().status(id) + } + + fn number(&self, hash: Hash) -> sc_client_api::blockchain::Result> { + self.client.lock().unwrap().number(hash) + } + + fn hash(&self, number: BlockNumber) -> sc_client_api::blockchain::Result> { + self.client.lock().unwrap().hash(number) + } +} + +impl BlockchainEvents for MockClient { + fn import_notification_stream(&self) -> ImportNotifications { + unimplemented!() + } + + fn finality_notification_stream(&self) -> FinalityNotifications { + self.client.lock().unwrap().finality_notification_stream() + } + + fn storage_changes_notification_stream( + &self, + _filter_keys: Option<&[StorageKey]>, + _child_filter_keys: Option<&[(StorageKey, Option>)]>, + ) -> sc_client_api::blockchain::Result> { + unimplemented!() + } +} + +impl ProvideRuntimeApi for MockClient { + type Api = MockRuntimeApi; + + fn runtime_api(&self) -> ApiRef<'_, Self::Api> { + MockRuntimeApi { data: self.runtime_api_params.clone() }.into() + } +} + +sp_api::mock_impl_runtime_apis! { + impl mmr::MmrApi for MockRuntimeApi { + fn mmr_root() -> Result { + Err(mmr::Error::PalletNotIncluded) + } + + fn mmr_leaf_count(&self) -> Result { + Ok(self.data.lock().unwrap().num_blocks) + } + + fn generate_proof( + &self, + _block_numbers: Vec, + _best_known_block_number: Option, + ) -> Result<(Vec, mmr::Proof), mmr::Error> { + Err(mmr::Error::PalletNotIncluded) + } + + fn verify_proof(_leaves: Vec, _proof: mmr::Proof) + -> Result<(), mmr::Error> + { + Err(mmr::Error::PalletNotIncluded) + } + + fn verify_proof_stateless( + _root: MmrHash, + _leaves: Vec, + _proof: mmr::Proof + ) -> Result<(), mmr::Error> { + Err(mmr::Error::PalletNotIncluded) + } + } +} + +pub fn run_test_with_mmr_gadget(f: F) +where + F: FnOnce(Arc) -> Fut + 'static, + Fut: Future, +{ + let mut pool = LocalPool::new(); + let client = Arc::new(MockClient::new()); + + let client_clone = client.clone(); + pool.spawner() + .spawn_local_obj( + async move { + let backend = client_clone.backend.clone(); + MmrGadget::start( + client_clone.clone(), + backend, + MockRuntimeApi::INDEXING_PREFIX.to_vec(), + ) + .await + } + .boxed_local() + .into(), + ) + .unwrap(); + + pool.run_until(async move { + async_std::task::sleep(Duration::from_millis(200)).await; + + f(client).await + }); +} diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 8d1f897a65cd4..cf26cfb231c85 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -13,7 +13,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -36,7 +35,6 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", - "mmr-lib/std", "scale-info/std", "sp-core/std", "sp-io/std", diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 8476d82f3e70d..6e520b3bf130e 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -238,7 +238,7 @@ fn mmr_error_into_rpc_error(err: MmrError) -> CallError { MmrError::LeafNotFound => 1, MmrError::GenerateProof => 2, MmrError::Verify => 3, - MmrError::BlockNumToLeafIndex => 4, + MmrError::InvalidNumericOp => 4, MmrError::InvalidBestKnownBlock => 5, _ => 0, }; diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index a2d42417ae5dc..cb567c0137e78 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -24,7 +24,7 @@ //! //! The MMR pallet constructs an MMR from leaf data obtained on every block from //! `LeafDataProvider`. MMR nodes are stored both in: -//! - on-chain storage - hashes only; not full leaf content) +//! - on-chain storage - hashes only; not full leaf content; //! - off-chain storage - via Indexing API we push full leaf content (and all internal nodes as //! well) to the Off-chain DB, so that the data is available for Off-chain workers. //! Hashing used for MMR is configurable independently from the rest of the runtime (i.e. not using @@ -56,10 +56,9 @@ //! NOTE This pallet is experimental and not proven to work in production. #![cfg_attr(not(feature = "std"), no_std)] -use codec::Encode; -use frame_support::{log, traits::Get, weights::Weight}; +use frame_support::{log, weights::Weight}; use sp_runtime::{ - traits::{self, CheckedSub, One, Saturating, UniqueSaturatedInto}, + traits::{self, One, Saturating}, SaturatedConversion, }; @@ -73,7 +72,10 @@ mod mock; mod tests; pub use pallet::*; -pub use sp_mmr_primitives::{self as primitives, Error, LeafDataProvider, LeafIndex, NodeIndex}; +use sp_mmr_primitives::utils; +pub use sp_mmr_primitives::{ + self as primitives, utils::NodesUtils, Error, LeafDataProvider, LeafIndex, NodeIndex, +}; use sp_std::prelude::*; /// The most common use case for MMRs is to store historical block hashes, @@ -219,7 +221,7 @@ pub mod pallet { fn on_initialize(_n: T::BlockNumber) -> Weight { use primitives::LeafDataProvider; let leaves = Self::mmr_leaves(); - let peaks_before = mmr::utils::NodesUtils::new(leaves).number_of_peaks(); + let peaks_before = sp_mmr_primitives::utils::NodesUtils::new(leaves).number_of_peaks(); let data = T::LeafData::leaf_data(); // append new leaf to MMR @@ -242,46 +244,10 @@ pub mod pallet { >::put(leaves); >::put(root); - let peaks_after = mmr::utils::NodesUtils::new(leaves).number_of_peaks(); + let peaks_after = sp_mmr_primitives::utils::NodesUtils::new(leaves).number_of_peaks(); T::WeightInfo::on_initialize(peaks_before.max(peaks_after)) } - - fn offchain_worker(n: T::BlockNumber) { - use mmr::storage::{OffchainStorage, Storage}; - // The MMR nodes can be found in offchain db under either: - // - fork-unique keys `(prefix, pos, parent_hash)`, or, - // - "canonical" keys `(prefix, pos)`, - // depending on how many blocks in the past the node at position `pos` was - // added to the MMR. - // - // For the fork-unique keys, the MMR pallet depends on - // `frame_system::block_hash(parent_num)` mappings to find the relevant parent block - // hashes, so it is limited by `frame_system::BlockHashCount` in terms of how many - // historical forks it can track. Nodes added to MMR by block `N` can be found in - // offchain db at: - // - fork-unique keys `(prefix, pos, parent_hash)` when (`N` >= `latest_block` - - // `frame_system::BlockHashCount`); - // - "canonical" keys `(prefix, pos)` when (`N` < `latest_block` - - // `frame_system::BlockHashCount`); - // - // The offchain worker is responsible for maintaining the nodes' positions in - // offchain db as the chain progresses by moving a rolling window of the same size as - // `frame_system::block_hash` map, where nodes/leaves added by blocks that are just - // about to exit the window are "canonicalized" so that their offchain key no longer - // depends on `parent_hash`. - // - // This approach works to eliminate fork-induced leaf collisions in offchain db, - // under the assumption that no fork will be deeper than `frame_system::BlockHashCount` - // blocks: - // entries pertaining to block `N` where `N < current-BlockHashCount` are moved to a - // key based solely on block number. The only way to have collisions is if two - // competing forks are deeper than `frame_system::BlockHashCount` blocks and they - // both "canonicalize" their view of block `N` - // Once a block is canonicalized, all MMR entries pertaining to sibling blocks from - // other forks are pruned from offchain db. - Storage::>::canonicalize_and_prune(n); - } } } @@ -313,11 +279,15 @@ impl, I: 'static> Pallet { /// Build offchain key from `parent_hash` of block that originally added node `pos` to MMR. /// /// This combination makes the offchain (key,value) entry resilient to chain forks. - fn node_offchain_key( + fn node_temp_offchain_key( pos: NodeIndex, parent_hash: ::Hash, ) -> sp_std::prelude::Vec { - (T::INDEXING_PREFIX, pos, parent_hash).encode() + NodesUtils::node_temp_offchain_key::<::Header>( + &T::INDEXING_PREFIX, + pos, + parent_hash, + ) } /// Build canonical offchain key for node `pos` in MMR. @@ -326,18 +296,7 @@ impl, I: 'static> Pallet { /// Never read keys using `node_canon_offchain_key` unless you sure that /// there's no `node_offchain_key` key in the storage. fn node_canon_offchain_key(pos: NodeIndex) -> sp_std::prelude::Vec { - (T::INDEXING_PREFIX, pos).encode() - } - - /// Return size of rolling window of leaves saved in offchain under fork-unique keys. - /// - /// Leaves outside this window are canonicalized. - /// Window size is `frame_system::BlockHashCount - 1` to make sure fork-unique keys - /// can be built using `frame_system::block_hash` map. - fn offchain_canonicalization_window() -> LeafIndex { - let window_size: LeafIndex = - ::BlockHashCount::get().unique_saturated_into(); - window_size.saturating_sub(1) + NodesUtils::node_canon_offchain_key(&T::INDEXING_PREFIX, pos) } /// Provide the parent number for the block that added `leaf_index` to the MMR. @@ -355,30 +314,17 @@ impl, I: 'static> Pallet { .saturating_add(leaf_index.saturated_into()) } - /// Convert a `block_num` into a leaf index. - fn block_num_to_leaf_index(block_num: T::BlockNumber) -> Result + /// Convert a block number into a leaf index. + fn block_num_to_leaf_index(block_num: T::BlockNumber) -> Result where T: frame_system::Config, { - // leaf_idx = (leaves_count - 1) - (current_block_num - block_num); - let best_block_num = >::block_number(); - let blocks_diff = best_block_num.checked_sub(&block_num).ok_or_else(|| { - primitives::Error::BlockNumToLeafIndex - .log_debug("The provided block_number is greater than the best block number.") - })?; - let blocks_diff_as_leaf_idx = blocks_diff.try_into().map_err(|_| { - primitives::Error::BlockNumToLeafIndex - .log_debug("The `blocks_diff` couldn't be converted to `LeafIndex`.") - })?; - - let leaf_idx = Self::mmr_leaves() - .checked_sub(1) - .and_then(|last_leaf_idx| last_leaf_idx.checked_sub(blocks_diff_as_leaf_idx)) - .ok_or_else(|| { - primitives::Error::BlockNumToLeafIndex - .log_debug("There aren't enough leaves in the chain.") - })?; - Ok(leaf_idx) + let first_mmr_block = utils::first_mmr_block_num::( + >::block_number(), + Self::mmr_leaves(), + )?; + + utils::block_num_to_leaf_index::(block_num, first_mmr_block) } /// Generate an MMR proof for the given `block_numbers`. diff --git a/frame/merkle-mountain-range/src/mmr/mmr.rs b/frame/merkle-mountain-range/src/mmr/mmr.rs index 1f5a5bdae380b..cdb189a14b66d 100644 --- a/frame/merkle-mountain-range/src/mmr/mmr.rs +++ b/frame/merkle-mountain-range/src/mmr/mmr.rs @@ -18,12 +18,12 @@ use crate::{ mmr::{ storage::{OffchainStorage, RuntimeStorage, Storage}, - utils::NodesUtils, Hasher, Node, NodeOf, }, primitives::{self, Error, NodeIndex}, Config, HashingOf, }; +use sp_mmr_primitives::{mmr_lib, utils::NodesUtils}; use sp_std::prelude::*; /// Stateless verification of the proof for a batch of leaves. diff --git a/frame/merkle-mountain-range/src/mmr/mod.rs b/frame/merkle-mountain-range/src/mmr/mod.rs index 19fb7b34382bd..51de294753151 100644 --- a/frame/merkle-mountain-range/src/mmr/mod.rs +++ b/frame/merkle-mountain-range/src/mmr/mod.rs @@ -17,9 +17,8 @@ mod mmr; pub mod storage; -pub mod utils; -use sp_mmr_primitives::{DataOrHash, FullLeaf}; +use sp_mmr_primitives::{mmr_lib, DataOrHash, FullLeaf}; use sp_runtime::traits; pub use self::mmr::{verify_leaves_proof, Mmr}; diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index d16ca8cf1e5c8..1f5d01f87e273 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -18,16 +18,16 @@ //! An MMR storage implementation. use codec::Encode; -use frame_support::log::{debug, error, trace}; -use mmr_lib::helper; +use frame_support::log::{debug, trace}; use sp_core::offchain::StorageKind; -use sp_io::{offchain, offchain_index}; +use sp_io::offchain_index; +use sp_mmr_primitives::{mmr_lib, mmr_lib::helper, utils::NodesUtils}; use sp_std::iter::Peekable; #[cfg(not(feature = "std"))] use sp_std::prelude::*; use crate::{ - mmr::{utils::NodesUtils, Node, NodeOf}, + mmr::{Node, NodeOf}, primitives::{self, NodeIndex}, Config, Nodes, NumberOfLeaves, Pallet, }; @@ -48,51 +48,6 @@ pub struct RuntimeStorage; /// DOES NOT support adding new items to the MMR. pub struct OffchainStorage; -/// Suffix of key for the 'pruning_map'. -/// -/// Nodes and leaves are initially saved under fork-specific keys in offchain db, -/// eventually they are "canonicalized" and this map is used to prune non-canon entries. -const OFFCHAIN_PRUNING_MAP_KEY_SUFFIX: &str = "pruning_map"; - -/// Used to store offchain mappings of `BlockNumber -> Vec[Hash]` to track all forks. -/// Size of this offchain map is at most `frame_system::BlockHashCount`, its entries are pruned -/// as part of the mechanism that prunes the forks this map tracks. -pub(crate) struct PruningMap(sp_std::marker::PhantomData<(T, I)>); -impl PruningMap -where - T: Config, - I: 'static, -{ - pub(crate) fn pruning_map_offchain_key(block: T::BlockNumber) -> sp_std::prelude::Vec { - (T::INDEXING_PREFIX, block, OFFCHAIN_PRUNING_MAP_KEY_SUFFIX).encode() - } - - /// Append `hash` to the list of parent hashes for `block` in offchain db. - pub fn append(block: T::BlockNumber, hash: ::Hash) { - let map_key = Self::pruning_map_offchain_key(block); - offchain::local_storage_get(StorageKind::PERSISTENT, &map_key) - .and_then(|v| codec::Decode::decode(&mut &*v).ok()) - .or_else(|| Some(Vec::<::Hash>::new())) - .map(|mut parents| { - parents.push(hash); - offchain::local_storage_set( - StorageKind::PERSISTENT, - &map_key, - &Encode::encode(&parents), - ); - }); - } - - /// Remove list of parent hashes for `block` from offchain db and return it. - pub fn remove(block: T::BlockNumber) -> Option::Hash>> { - let map_key = Self::pruning_map_offchain_key(block); - offchain::local_storage_get(StorageKind::PERSISTENT, &map_key).and_then(|v| { - offchain::local_storage_clear(StorageKind::PERSISTENT, &map_key); - codec::Decode::decode(&mut &*v).ok() - }) - } -} - /// A storage layer for MMR. /// /// There are two different implementations depending on the use case. @@ -111,100 +66,6 @@ where I: 'static, L: primitives::FullLeaf, { - /// Move nodes and leaves added by block `N` in offchain db from _fork-aware key_ to - /// _canonical key_, - /// where `N` is `frame_system::BlockHashCount` blocks behind current block number. - /// - /// This "canonicalization" process is required because the _fork-aware key_ value depends - /// on `frame_system::block_hash(block_num)` map which only holds the last - /// `frame_system::BlockHashCount` blocks. - /// - /// For the canonicalized block, prune all nodes pertaining to other forks from offchain db. - /// - /// Should only be called from offchain context, because it requires both read and write - /// access to offchain db. - pub(crate) fn canonicalize_and_prune(block: T::BlockNumber) { - // Add "block_num -> hash" mapping to offchain db, - // with all forks pushing hashes to same entry (same block number). - let parent_hash = >::parent_hash(); - PruningMap::::append(block, parent_hash); - - // Effectively move a rolling window of fork-unique leaves. Once out of the window, leaves - // are "canonicalized" in offchain by moving them under `Pallet::node_canon_offchain_key`. - let leaves = NumberOfLeaves::::get(); - let window_size = Pallet::::offchain_canonicalization_window(); - if leaves >= window_size { - // Move the rolling window towards the end of `block_num->hash` mappings available - // in the runtime: we "canonicalize" the leaf at the end, - let to_canon_leaf = leaves.saturating_sub(window_size); - // and all the nodes added by that leaf. - let to_canon_nodes = NodesUtils::right_branch_ending_in_leaf(to_canon_leaf); - debug!( - target: "runtime::mmr::offchain", "Nodes to canon for leaf {}: {:?}", - to_canon_leaf, to_canon_nodes - ); - // For this block number there may be node entries saved from multiple forks. - let to_canon_block_num = - Pallet::::leaf_index_to_parent_block_num(to_canon_leaf, leaves); - // Only entries under this hash (retrieved from state on current canon fork) are to be - // persisted. All entries added by same block number on other forks will be cleared. - let to_canon_hash = >::block_hash(to_canon_block_num); - - Self::canonicalize_nodes_for_hash(&to_canon_nodes, to_canon_hash); - // Get all the forks to prune, also remove them from the offchain pruning_map. - PruningMap::::remove(to_canon_block_num) - .map(|forks| { - Self::prune_nodes_for_forks(&to_canon_nodes, forks); - }) - .unwrap_or_else(|| { - error!( - target: "runtime::mmr::offchain", - "Offchain: could not prune: no entry in pruning map for block {:?}", - to_canon_block_num - ); - }) - } - } - - fn prune_nodes_for_forks(nodes: &[NodeIndex], forks: Vec<::Hash>) { - for hash in forks { - for pos in nodes { - let key = Pallet::::node_offchain_key(*pos, hash); - debug!( - target: "runtime::mmr::offchain", - "Clear elem at pos {} with key {:?}", - pos, key - ); - offchain::local_storage_clear(StorageKind::PERSISTENT, &key); - } - } - } - - fn canonicalize_nodes_for_hash( - to_canon_nodes: &[NodeIndex], - to_canon_hash: ::Hash, - ) { - for pos in to_canon_nodes { - let key = Pallet::::node_offchain_key(*pos, to_canon_hash); - // Retrieve the element from Off-chain DB under fork-aware key. - if let Some(elem) = offchain::local_storage_get(StorageKind::PERSISTENT, &key) { - let canon_key = Pallet::::node_canon_offchain_key(*pos); - // Add under new canon key. - offchain::local_storage_set(StorageKind::PERSISTENT, &canon_key, &elem); - debug!( - target: "runtime::mmr::offchain", - "Moved elem at pos {} from key {:?} to canon key {:?}", - pos, key, canon_key - ); - } else { - error!( - target: "runtime::mmr::offchain", - "Could not canonicalize elem at pos {} using key {:?}", - pos, key - ); - } - } - } } impl mmr_lib::MMRStore> for Storage @@ -218,42 +79,31 @@ where // Find out which leaf added node `pos` in the MMR. let ancestor_leaf_idx = NodesUtils::leaf_index_that_added_node(pos); - let window_size = Pallet::::offchain_canonicalization_window(); - // Leaves older than this window should have been canonicalized. - if leaves.saturating_sub(ancestor_leaf_idx) > window_size { - let key = Pallet::::node_canon_offchain_key(pos); - debug!( - target: "runtime::mmr::offchain", "offchain db get {}: leaf idx {:?}, key {:?}", - pos, ancestor_leaf_idx, key - ); - // Just for safety, to easily handle runtime upgrades where any of the window params - // change and maybe we mess up storage migration, - // return _if and only if_ node is found (in normal conditions it's always found), - if let Some(elem) = sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) { - return Ok(codec::Decode::decode(&mut &*elem).ok()) - } - // BUT if we DID MESS UP, fall through to searching node using fork-specific key. + // We should only get here when trying to generate proofs. The client requests + // for proofs for finalized blocks, which should usually be already canonicalized, + // unless the MMR client gadget has a delay. + let key = Pallet::::node_canon_offchain_key(pos); + debug!( + target: "runtime::mmr::offchain", "offchain db get {}: leaf idx {:?}, canon key {:?}", + pos, ancestor_leaf_idx, key + ); + // Try to retrieve the element from Off-chain DB. + if let Some(elem) = sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) { + return Ok(codec::Decode::decode(&mut &*elem).ok()) } - // Leaves still within the window will be found in offchain db under fork-aware keys. + // Fall through to searching node using fork-specific key. let ancestor_parent_block_num = Pallet::::leaf_index_to_parent_block_num(ancestor_leaf_idx, leaves); let ancestor_parent_hash = >::block_hash(ancestor_parent_block_num); - let key = Pallet::::node_offchain_key(pos, ancestor_parent_hash); + let temp_key = Pallet::::node_temp_offchain_key(pos, ancestor_parent_hash); debug!( - target: "runtime::mmr::offchain", "offchain db get {}: leaf idx {:?}, hash {:?}, key {:?}", - pos, ancestor_leaf_idx, ancestor_parent_hash, key + target: "runtime::mmr::offchain", + "offchain db get {}: leaf idx {:?}, hash {:?}, temp key {:?}", + pos, ancestor_leaf_idx, ancestor_parent_hash, temp_key ); // Retrieve the element from Off-chain DB. - Ok(sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) - .or_else(|| { - // Again, this is just us being extra paranoid. - // We get here only if we mess up a storage migration for a runtime upgrades where - // say the window is increased, and for a little while following the upgrade there's - // leaves inside new 'window' that had been already canonicalized before upgrade. - let key = Pallet::::node_canon_offchain_key(pos); - sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) - }) + Ok(sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &temp_key) .and_then(|v| codec::Decode::decode(&mut &*v).ok())) } @@ -342,22 +192,15 @@ where ) { let encoded_node = node.encode(); // We store this leaf offchain keyed by `(parent_hash, node_index)` to make it - // fork-resistant. Offchain worker task will "canonicalize" it - // `frame_system::BlockHashCount` blocks later, when we are not worried about forks anymore - // (multi-era-deep forks should not happen). - let key = Pallet::::node_offchain_key(pos, parent_hash); + // fork-resistant. The MMR client gadget task will "canonicalize" it on the first + // finality notification that follows, when we are not worried about forks anymore. + let temp_key = Pallet::::node_temp_offchain_key(pos, parent_hash); debug!( target: "runtime::mmr::offchain", "offchain db set: pos {} parent_hash {:?} key {:?}", - pos, parent_hash, key + pos, parent_hash, temp_key ); // Indexing API is used to store the full node content. - offchain_index::set(&key, &encoded_node); - // We also directly save the full node under the "canonical" key. - // This is superfluous for the normal case - this entry will possibly be overwritten - // by forks, and will also be overwritten by "offchain_worker canonicalization". - // But it is required for blocks imported during initial sync where none of the above apply - // (`offchain_worker` doesn't run for initial sync blocks). - offchain_index::set(&Pallet::::node_canon_offchain_key(pos), &encoded_node); + offchain_index::set(&temp_key, &encoded_node); } } diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index e47f1b3b2e63a..b5f9a78ede010 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -15,19 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ - mmr::{storage::PruningMap, utils}, - mock::*, - *, -}; +use crate::{mock::*, *}; use frame_support::traits::{Get, OnInitialize}; -use mmr_lib::helper; use sp_core::{ offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt}, H256, }; -use sp_mmr_primitives::{Compact, Proof}; +use sp_mmr_primitives::{mmr_lib::helper, utils, Compact, Proof}; pub(crate) fn new_test_ext() -> sp_io::TestExternalities { frame_system::GenesisConfig::default().build_storage::().unwrap().into() @@ -171,21 +166,26 @@ fn should_append_to_mmr_when_on_initialize_is_called() { let offchain_db = ext.offchain_db(); let expected = Some(mmr::Node::Data(((0, H256::repeat_byte(1)), LeafData::new(1)))); - assert_eq!(offchain_db.get(&MMR::node_offchain_key(0, parent_b1)).map(decode_node), expected); - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(0)).map(decode_node), expected); + assert_eq!( + offchain_db.get(&MMR::node_temp_offchain_key(0, parent_b1)).map(decode_node), + expected + ); let expected = Some(mmr::Node::Data(((1, H256::repeat_byte(2)), LeafData::new(2)))); - assert_eq!(offchain_db.get(&MMR::node_offchain_key(1, parent_b2)).map(decode_node), expected); - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(1)).map(decode_node), expected); + assert_eq!( + offchain_db.get(&MMR::node_temp_offchain_key(1, parent_b2)).map(decode_node), + expected + ); let expected = Some(mmr::Node::Hash(hex( "672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854", ))); - assert_eq!(offchain_db.get(&MMR::node_offchain_key(2, parent_b2)).map(decode_node), expected); - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(2)).map(decode_node), expected); + assert_eq!( + offchain_db.get(&MMR::node_temp_offchain_key(2, parent_b2)).map(decode_node), + expected + ); - assert_eq!(offchain_db.get(&MMR::node_offchain_key(3, parent_b2)), None); - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(3)), None); + assert_eq!(offchain_db.get(&MMR::node_temp_offchain_key(3, parent_b2)), None); } #[test] @@ -219,6 +219,27 @@ fn should_construct_larger_mmr_correctly() { }); } +#[test] +fn should_calculate_the_size_correctly() { + let _ = env_logger::try_init(); + + let leaves = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 21]; + let sizes = vec![0, 1, 3, 4, 7, 8, 10, 11, 15, 16, 18, 19, 22, 23, 25, 26, 39]; + + // size cross-check + let mut actual_sizes = vec![]; + for s in &leaves[1..] { + new_test_ext().execute_with(|| { + let mut mmr = mmr::Mmr::::new(0); + for i in 0..*s { + mmr.push(i); + } + actual_sizes.push(mmr.size()); + }) + } + assert_eq!(sizes[1..], actual_sizes[..]); +} + #[test] fn should_generate_proofs_correctly() { let _ = env_logger::try_init(); @@ -698,208 +719,6 @@ fn should_verify_on_the_next_block_since_there_is_no_pruning_yet() { }); } -#[test] -fn should_verify_pruning_map() { - use sp_core::offchain::StorageKind; - use sp_io::offchain; - - let _ = env_logger::try_init(); - let mut ext = new_test_ext(); - register_offchain_ext(&mut ext); - - ext.execute_with(|| { - type TestPruningMap = PruningMap; - fn offchain_decoded(key: Vec) -> Option> { - offchain::local_storage_get(StorageKind::PERSISTENT, &key) - .and_then(|v| codec::Decode::decode(&mut &*v).ok()) - } - - // test append - { - TestPruningMap::append(1, H256::repeat_byte(1)); - - TestPruningMap::append(2, H256::repeat_byte(21)); - TestPruningMap::append(2, H256::repeat_byte(22)); - - TestPruningMap::append(3, H256::repeat_byte(31)); - TestPruningMap::append(3, H256::repeat_byte(32)); - TestPruningMap::append(3, H256::repeat_byte(33)); - - // `0` not present - let map_key = TestPruningMap::pruning_map_offchain_key(0); - assert_eq!(offchain::local_storage_get(StorageKind::PERSISTENT, &map_key), None); - - // verify `1` entries - let map_key = TestPruningMap::pruning_map_offchain_key(1); - let expected = vec![H256::repeat_byte(1)]; - assert_eq!(offchain_decoded(map_key), Some(expected)); - - // verify `2` entries - let map_key = TestPruningMap::pruning_map_offchain_key(2); - let expected = vec![H256::repeat_byte(21), H256::repeat_byte(22)]; - assert_eq!(offchain_decoded(map_key), Some(expected)); - - // verify `3` entries - let map_key = TestPruningMap::pruning_map_offchain_key(3); - let expected = - vec![H256::repeat_byte(31), H256::repeat_byte(32), H256::repeat_byte(33)]; - assert_eq!(offchain_decoded(map_key), Some(expected)); - - // `4` not present - let map_key = TestPruningMap::pruning_map_offchain_key(4); - assert_eq!(offchain::local_storage_get(StorageKind::PERSISTENT, &map_key), None); - } - - // test remove - { - // `0` doesn't return anything - assert_eq!(TestPruningMap::remove(0), None); - - // remove and verify `1` entries - let expected = vec![H256::repeat_byte(1)]; - assert_eq!(TestPruningMap::remove(1), Some(expected)); - - // remove and verify `2` entries - let expected = vec![H256::repeat_byte(21), H256::repeat_byte(22)]; - assert_eq!(TestPruningMap::remove(2), Some(expected)); - - // remove and verify `3` entries - let expected = - vec![H256::repeat_byte(31), H256::repeat_byte(32), H256::repeat_byte(33)]; - assert_eq!(TestPruningMap::remove(3), Some(expected)); - - // `4` doesn't return anything - assert_eq!(TestPruningMap::remove(4), None); - - // no entries left in offchain map - for block in 0..5 { - let map_key = TestPruningMap::pruning_map_offchain_key(block); - assert_eq!(offchain::local_storage_get(StorageKind::PERSISTENT, &map_key), None); - } - } - }) -} - -#[test] -fn should_canonicalize_offchain() { - use frame_support::traits::Hooks; - - let _ = env_logger::try_init(); - let mut ext = new_test_ext(); - register_offchain_ext(&mut ext); - - // adding 13 blocks that we'll later check have been canonicalized, - // (test assumes `13 < frame_system::BlockHashCount`). - let to_canon_count = 13u32; - - // add 13 blocks and verify leaves and nodes for them have been added to - // offchain MMR using fork-proof keys. - for blocknum in 0..to_canon_count { - ext.execute_with(|| { - new_block(); - as Hooks>::offchain_worker(blocknum.into()); - }); - ext.persist_offchain_overlay(); - } - let offchain_db = ext.offchain_db(); - ext.execute_with(|| { - // verify leaves added by blocks 1..=13 - for block_num in 1..=to_canon_count { - let parent_num: BlockNumber = (block_num - 1).into(); - let leaf_index = u64::from(block_num - 1); - let pos = helper::leaf_index_to_pos(leaf_index.into()); - let parent_hash = >::block_hash(parent_num); - // Available in offchain db under both fork-proof key and canon key. - // We'll later check it is pruned from fork-proof key. - let expected = Some(mmr::Node::Data(( - (leaf_index, H256::repeat_byte(u8::try_from(block_num).unwrap())), - LeafData::new(block_num.into()), - ))); - assert_eq!( - offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), - expected - ); - assert_eq!( - offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)).map(decode_node), - expected - ); - } - - // verify a couple of nodes and peaks: - // `pos` is node to verify, - // `leaf_index` is leaf that added node `pos`, - // `expected` is expected value of node at `pos`. - let verify = |pos: NodeIndex, leaf_index: LeafIndex, expected: H256| { - let parent_num: BlockNumber = leaf_index.try_into().unwrap(); - let parent_hash = >::block_hash(parent_num); - // Available in offchain db under both fork-proof key and canon key. - // We'll later check it is pruned from fork-proof key. - let expected = Some(mmr::Node::Hash(expected)); - assert_eq!( - offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), - expected - ); - assert_eq!( - offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)).map(decode_node), - expected - ); - }; - verify(2, 1, hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854")); - verify(13, 7, hex("441bf63abc7cf9b9e82eb57b8111c883d50ae468d9fd7f301e12269fc0fa1e75")); - verify(21, 11, hex("f323ac1a7f56de5f40ed8df3e97af74eec0ee9d72883679e49122ffad2ffd03b")); - }); - - // add another `frame_system::BlockHashCount` blocks and verify all nodes and leaves - // added by our original `to_canon_count` blocks have now been canonicalized in offchain db. - let block_hash_size: u64 = ::BlockHashCount::get(); - let base = to_canon_count; - for blocknum in base..(base + u32::try_from(block_hash_size).unwrap()) { - ext.execute_with(|| { - new_block(); - as Hooks>::offchain_worker(blocknum.into()); - }); - ext.persist_offchain_overlay(); - } - ext.execute_with(|| { - // verify leaves added by blocks 1..=13, should be in offchain under canon key. - for block_num in 1..=to_canon_count { - let leaf_index = u64::from(block_num - 1); - let pos = helper::leaf_index_to_pos(leaf_index.into()); - let parent_num: BlockNumber = (block_num - 1).into(); - let parent_hash = >::block_hash(parent_num); - // no longer available in fork-proof storage (was pruned), - assert_eq!(offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)), None); - // but available using canon key. - assert_eq!( - offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), - Some(mmr::Node::Data(( - (leaf_index, H256::repeat_byte(u8::try_from(block_num).unwrap())), - LeafData::new(block_num.into()), - ))) - ); - } - - // also check some nodes and peaks: - // `pos` is node to verify, - // `leaf_index` is leaf that added node `pos`, - // `expected` is expected value of node at `pos`. - let verify = |pos: NodeIndex, leaf_index: LeafIndex, expected: H256| { - let parent_num: BlockNumber = leaf_index.try_into().unwrap(); - let parent_hash = >::block_hash(parent_num); - // no longer available in fork-proof storage (was pruned), - assert_eq!(offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)), None); - // but available using canon key. - assert_eq!( - offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), - Some(mmr::Node::Hash(expected)) - ); - }; - verify(2, 1, hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854")); - verify(13, 7, hex("441bf63abc7cf9b9e82eb57b8111c883d50ae468d9fd7f301e12269fc0fa1e75")); - verify(21, 11, hex("f323ac1a7f56de5f40ed8df3e97af74eec0ee9d72883679e49122ffad2ffd03b")); - }); -} - #[test] fn should_verify_canonicalized() { use frame_support::traits::Hooks; @@ -955,21 +774,18 @@ fn does_not_panic_when_generating_historical_proofs() { register_offchain_ext(&mut ext); ext.execute_with(|| { // when leaf index is invalid - assert_eq!( - crate::Pallet::::generate_proof(vec![10], None), - Err(Error::BlockNumToLeafIndex), - ); + assert_eq!(crate::Pallet::::generate_proof(vec![10], None), Err(Error::LeafNotFound),); // when leaves count is invalid assert_eq!( crate::Pallet::::generate_proof(vec![3], Some(100)), - Err(Error::BlockNumToLeafIndex), + Err(Error::GenerateProof), ); // when both leaf index and leaves count are invalid assert_eq!( crate::Pallet::::generate_proof(vec![10], Some(100)), - Err(Error::BlockNumToLeafIndex), + Err(Error::LeafNotFound), ); }); } diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index dea3a7f285117..33edc56d4b6ba 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -21,9 +21,10 @@ use log::warn; use parking_lot::RwLock; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, Header as HeaderT, NumberFor}, + traits::{Block as BlockT, Header as HeaderT, NumberFor, Saturating}, Justifications, }; +use std::collections::btree_set::BTreeSet; use crate::header_metadata::HeaderMetadata; @@ -84,6 +85,77 @@ pub trait HeaderBackend: Send + Sync { } } +/// Handles stale forks. +pub trait ForkBackend: + HeaderMetadata + HeaderBackend + Send + Sync +{ + /// Best effort to get all the header hashes that are part of the provided forks + /// starting only from the fork heads. + /// + /// The function tries to reconstruct the route from the fork head to the canonical chain. + /// If any of the hashes on the route can't be found in the db, the function won't be able + /// to reconstruct the route anymore. In this case it will give up expanding the current fork, + /// move on to the next ones and at the end it will return an error that also contains + /// the partially expanded forks. + fn expand_forks( + &self, + fork_heads: &[Block::Hash], + ) -> std::result::Result, (BTreeSet, Error)> { + let mut missing_blocks = vec![]; + let mut expanded_forks = BTreeSet::new(); + for fork_head in fork_heads { + let mut route_head = *fork_head; + // Insert stale blocks hashes until canonical chain is reached. + // If we reach a block that is already part of the `expanded_forks` we can stop + // processing the fork. + while expanded_forks.insert(route_head) { + match self.header_metadata(route_head) { + Ok(meta) => { + // If the parent is part of the canonical chain or there doesn't exist a + // block hash for the parent number (bug?!), we can abort adding blocks. + let parent_number = meta.number.saturating_sub(1u32.into()); + match self.hash(parent_number) { + Ok(Some(parent_hash)) => + if parent_hash == meta.parent { + break + }, + Ok(None) | Err(_) => { + missing_blocks.push(BlockId::::Number(parent_number)); + break + }, + } + + route_head = meta.parent; + }, + Err(_e) => { + missing_blocks.push(BlockId::::Hash(route_head)); + break + }, + } + } + } + + if !missing_blocks.is_empty() { + return Err(( + expanded_forks, + Error::UnknownBlocks(format!( + "Missing stale headers {:?} while expanding forks {:?}.", + fork_heads, missing_blocks + )), + )) + } + + Ok(expanded_forks) + } +} + +impl ForkBackend for T +where + Block: BlockT, + T: HeaderMetadata + HeaderBackend + Send + Sync, +{ +} + /// Blockchain database backend. Does not perform any validation. pub trait Backend: HeaderBackend + HeaderMetadata diff --git a/primitives/blockchain/src/error.rs b/primitives/blockchain/src/error.rs index c82fb9bebf4ee..783c40c4061ad 100644 --- a/primitives/blockchain/src/error.rs +++ b/primitives/blockchain/src/error.rs @@ -59,6 +59,9 @@ pub enum Error { #[error("UnknownBlock: {0}")] UnknownBlock(String), + #[error("UnknownBlocks: {0}")] + UnknownBlocks(String), + #[error(transparent)] ApplyExtrinsicFailed(#[from] ApplyExtrinsicFailed), diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index 7f8b3b6afe5f3..2e532990a5caf 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } +mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-core = { version = "7.0.0", default-features = false, path = "../core" } @@ -31,6 +32,7 @@ default = ["std"] std = [ "codec/std", "log/std", + "mmr-lib/std", "serde", "sp-api/std", "sp-core/std", diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index d46cb73c3c5e8..606906185077c 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -20,6 +20,8 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] +pub use mmr_lib; + use scale_info::TypeInfo; use sp_debug_derive::RuntimeDebug; use sp_runtime::traits; @@ -27,6 +29,11 @@ use sp_std::fmt; #[cfg(not(feature = "std"))] use sp_std::prelude::Vec; +pub mod utils; + +/// Prefix for elements stored in the Off-chain DB via Indexing API. +pub const INDEXING_PREFIX: &'static [u8] = b"mmr"; + /// A type to describe node position in the MMR (node index). pub type NodeIndex = u64; @@ -357,8 +364,8 @@ pub struct Proof { #[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] pub enum Error { /// Error during translation of a block number into a leaf index. - #[cfg_attr(feature = "std", error("Error translation block number into leaf index"))] - BlockNumToLeafIndex, + #[cfg_attr(feature = "std", error("Error performing numeric op"))] + InvalidNumericOp, /// Error while pushing new node. #[cfg_attr(feature = "std", error("Error pushing new node"))] Push, @@ -419,6 +426,9 @@ sp_api::decl_runtime_apis! { /// Return the on-chain MMR root hash. fn mmr_root() -> Result; + /// Return the number of MMR blocks in the chain. + fn mmr_leaf_count() -> Result; + /// Generate MMR proof for a series of block numbers. If `best_known_block_number = Some(n)`, /// use historical MMR state at given block height `n`. Else, use current MMR state. fn generate_proof( diff --git a/frame/merkle-mountain-range/src/mmr/utils.rs b/primitives/merkle-mountain-range/src/utils.rs similarity index 69% rename from frame/merkle-mountain-range/src/mmr/utils.rs rename to primitives/merkle-mountain-range/src/utils.rs index 0b8e88a9283da..619ca7e98160f 100644 --- a/frame/merkle-mountain-range/src/mmr/utils.rs +++ b/primitives/merkle-mountain-range/src/utils.rs @@ -17,9 +17,48 @@ //! Merkle Mountain Range utilities. -use crate::primitives::{LeafIndex, NodeIndex}; +use codec::Encode; use mmr_lib::helper; +use sp_runtime::traits::{CheckedAdd, CheckedSub, Header, One}; +#[cfg(not(feature = "std"))] +use sp_std::prelude::Vec; + +use crate::{Error, LeafIndex, NodeIndex}; + +/// Get the first block with MMR. +pub fn first_mmr_block_num( + best_block_num: H::Number, + mmr_leaf_count: LeafIndex, +) -> Result { + let mmr_blocks_count = mmr_leaf_count.try_into().map_err(|_| { + Error::InvalidNumericOp + .log_debug("The number of leaves couldn't be converted to a block number.") + })?; + best_block_num + .checked_sub(&mmr_blocks_count) + .and_then(|last_non_mmr_block| last_non_mmr_block.checked_add(&One::one())) + .ok_or_else(|| { + Error::InvalidNumericOp + .log_debug("The best block should be greater than the number of mmr blocks.") + }) +} + +/// Convert a block number into a leaf index. +pub fn block_num_to_leaf_index( + block_num: H::Number, + first_mmr_block_num: H::Number, +) -> Result { + let leaf_idx = block_num.checked_sub(&first_mmr_block_num).ok_or_else(|| { + Error::InvalidNumericOp + .log_debug("The provided block should be greater than the first mmr block.") + })?; + + leaf_idx.try_into().map_err(|_| { + Error::InvalidNumericOp.log_debug("Couldn't convert the leaf index to `LeafIndex`.") + }) +} + /// MMR nodes & size -related utilities. pub struct NodesUtils { no_of_leaves: LeafIndex, @@ -70,11 +109,31 @@ impl NodesUtils { /// Starting from any leaf index, get the sequence of positions of the nodes added /// to the mmr when this leaf was added (inclusive of the leaf's position itself). /// That is, all of these nodes are right children of their respective parents. - pub fn right_branch_ending_in_leaf(leaf_index: LeafIndex) -> crate::Vec { + pub fn right_branch_ending_in_leaf(leaf_index: LeafIndex) -> Vec { let pos = helper::leaf_index_to_pos(leaf_index); let num_parents = leaf_index.trailing_ones() as u64; return (pos..=pos + num_parents).collect() } + + /// Build offchain key from `parent_hash` of block that originally added node `pos` to MMR. + /// + /// This combination makes the offchain (key,value) entry resilient to chain forks. + pub fn node_temp_offchain_key( + prefix: &[u8], + pos: NodeIndex, + parent_hash: H::Hash, + ) -> Vec { + (prefix, pos, parent_hash).encode() + } + + /// Build canonical offchain key for node `pos` in MMR. + /// + /// Used for nodes added by now finalized blocks. + /// Never read keys using `node_canon_offchain_key` unless you sure that + /// there's no `node_offchain_key` key in the storage. + pub fn node_canon_offchain_key(prefix: &[u8], pos: NodeIndex) -> sp_std::prelude::Vec { + (prefix, pos).encode() + } } #[cfg(test)] @@ -142,8 +201,6 @@ mod tests { #[test] fn should_calculate_the_size_correctly() { - let _ = env_logger::try_init(); - let leaves = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 21]; let sizes = vec![0, 1, 3, 4, 7, 8, 10, 11, 15, 16, 18, 19, 22, 23, 25, 26, 39]; assert_eq!( @@ -154,23 +211,5 @@ mod tests { .collect::>(), sizes.clone() ); - - // size cross-check - let mut actual_sizes = vec![]; - for s in &leaves[1..] { - crate::tests::new_test_ext().execute_with(|| { - let mut mmr = crate::mmr::Mmr::< - crate::mmr::storage::RuntimeStorage, - crate::mock::Test, - _, - _, - >::new(0); - for i in 0..*s { - mmr.push(i); - } - actual_sizes.push(mmr.size()); - }) - } - assert_eq!(sizes[1..], actual_sizes[..]); } } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 054b195fc6efb..51f057e3ded55 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -612,7 +612,7 @@ impl From> for Extrinsic { } } -impl frame_system::Config for Runtime { +impl frame_system::pallet::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; @@ -974,13 +974,13 @@ cfg_if! { } } - impl beefy_primitives::BeefyApi for RuntimeApi { + impl beefy_primitives::BeefyApi for Runtime { fn validator_set() -> Option> { None } } - impl beefy_merkle_tree::BeefyMmrApi for RuntimeApi { + impl beefy_merkle_tree::BeefyMmrApi for Runtime { fn authority_set_proof() -> beefy_primitives::mmr::BeefyAuthoritySet { Default::default() } From 59ca8df2cbc7b954a1fb3a7767a6ae904853b434 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 29 Nov 2022 16:19:36 +0000 Subject: [PATCH 1417/1472] Require rust-features check (#12796) * Typo Signed-off-by: Oliver Tale-Yazdi * Move rust feature check to docker and require not to fail Signed-off-by: Oliver Tale-Yazdi * Add .docker-env Signed-off-by: Oliver Tale-Yazdi * Move test-rust-features check back to kubernetes Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- client/offchain/src/api.rs | 2 +- scripts/ci/gitlab/pipeline/check.yml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 7d3dd8302f343..1301ce9fd9627 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -300,7 +300,7 @@ pub(crate) struct AsyncApi { } impl AsyncApi { - /// Creates new Offchain extensions API implementation an the asynchronous processing part. + /// Creates new Offchain extensions API implementation and the asynchronous processing part. pub fn new( network_provider: Arc, is_validator: bool, diff --git a/scripts/ci/gitlab/pipeline/check.yml b/scripts/ci/gitlab/pipeline/check.yml index 878c46f32e850..55f0061501076 100644 --- a/scripts/ci/gitlab/pipeline/check.yml +++ b/scripts/ci/gitlab/pipeline/check.yml @@ -40,7 +40,6 @@ test-rust-features: extends: - .kubernetes-env - .test-refs-no-trigger-prs-only - allow_failure: true script: - git clone --depth=1 From 5c8aa7eebaceaf37c8aaa58c980c1f445fbb1ebf Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 30 Nov 2022 10:37:29 +0200 Subject: [PATCH 1418/1472] MMR: move RPC code from frame/ to client/ (#12805) * mmr: move MMR RPC from frame/ to client/ Signed-off-by: Adrian Catangiu * client/mmr: adjust logging levels to avoid spam * cargo fmt * remove unused imports Signed-off-by: Adrian Catangiu --- Cargo.lock | 34 +++++++++---------- Cargo.toml | 2 +- bin/node/rpc/Cargo.toml | 2 +- bin/node/rpc/src/lib.rs | 8 ++--- .../merkle-mountain-range/rpc/Cargo.toml | 4 +-- .../merkle-mountain-range/rpc/src/lib.rs | 0 client/merkle-mountain-range/src/lib.rs | 11 +++--- .../merkle-mountain-range/src/offchain_mmr.rs | 4 +-- frame/merkle-mountain-range/src/lib.rs | 14 ++++---- frame/merkle-mountain-range/src/mock.rs | 1 - 10 files changed, 39 insertions(+), 41 deletions(-) rename {frame => client}/merkle-mountain-range/rpc/Cargo.toml (96%) rename {frame => client}/merkle-mountain-range/rpc/src/lib.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index a99f3674de15f..883ad88c01fcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4253,6 +4253,22 @@ dependencies = [ "tokio", ] +[[package]] +name = "mmr-rpc" +version = "4.0.0-dev" +dependencies = [ + "anyhow", + "jsonrpsee", + "parity-scale-codec", + "serde", + "serde_json", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-mmr-primitives", + "sp-runtime", +] + [[package]] name = "mockall" version = "0.11.2" @@ -4685,8 +4701,8 @@ name = "node-rpc" version = "3.0.0-dev" dependencies = [ "jsonrpsee", + "mmr-rpc", "node-primitives", - "pallet-mmr-rpc", "pallet-transaction-payment-rpc", "sc-chain-spec", "sc-client-api", @@ -5682,22 +5698,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-mmr-rpc" -version = "3.0.0" -dependencies = [ - "anyhow", - "jsonrpsee", - "parity-scale-codec", - "serde", - "serde_json", - "sp-api", - "sp-blockchain", - "sp-core", - "sp-mmr-primitives", - "sp-runtime", -] - [[package]] name = "pallet-multisig" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index ebdf73db0dba3..fbe57e03caaa7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ members = [ "client/informant", "client/keystore", "client/merkle-mountain-range", + "client/merkle-mountain-range/rpc", "client/network", "client/network-gossip", "client/network/bitswap", @@ -108,7 +109,6 @@ members = [ "frame/lottery", "frame/membership", "frame/merkle-mountain-range", - "frame/merkle-mountain-range/rpc", "frame/multisig", "frame/nicks", "frame/node-authorization", diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 418691ca97f0f..a1f37e137ca1f 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -14,8 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.15.1", features = ["server"] } node-primitives = { version = "2.0.0", path = "../primitives" } -pallet-mmr-rpc = { version = "3.0.0", path = "../../../frame/merkle-mountain-range/rpc/" } pallet-transaction-payment-rpc = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/rpc/" } +mmr-rpc = { version = "4.0.0-dev", path = "../../../client/merkle-mountain-range/rpc/" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sc-consensus-babe = { version = "0.10.0-dev", path = "../../../client/consensus/babe" } diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 8596fe23321ba..0dc5ba4039b00 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -108,11 +108,7 @@ where + Send + 'static, C::Api: substrate_frame_rpc_system::AccountNonceApi, - C::Api: pallet_mmr_rpc::MmrRuntimeApi< - Block, - ::Hash, - BlockNumber, - >, + C::Api: mmr_rpc::MmrRuntimeApi::Hash, BlockNumber>, C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, C::Api: BabeApi, C::Api: BlockBuilder, @@ -121,7 +117,7 @@ where B: sc_client_api::Backend + Send + Sync + 'static, B::State: sc_client_api::backend::StateBackend>, { - use pallet_mmr_rpc::{Mmr, MmrApiServer}; + use mmr_rpc::{Mmr, MmrApiServer}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; use sc_consensus_babe_rpc::{Babe, BabeApiServer}; use sc_finality_grandpa_rpc::{Grandpa, GrandpaApiServer}; diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/client/merkle-mountain-range/rpc/Cargo.toml similarity index 96% rename from frame/merkle-mountain-range/rpc/Cargo.toml rename to client/merkle-mountain-range/rpc/Cargo.toml index feacd7d3b3413..abbf10c1b7f52 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/client/merkle-mountain-range/rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "pallet-mmr-rpc" -version = "3.0.0" +name = "mmr-rpc" +version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/client/merkle-mountain-range/rpc/src/lib.rs similarity index 100% rename from frame/merkle-mountain-range/rpc/src/lib.rs rename to client/merkle-mountain-range/rpc/src/lib.rs diff --git a/client/merkle-mountain-range/src/lib.rs b/client/merkle-mountain-range/src/lib.rs index 4f911a78a51d7..cb13977ffa5bd 100644 --- a/client/merkle-mountain-range/src/lib.rs +++ b/client/merkle-mountain-range/src/lib.rs @@ -44,7 +44,7 @@ pub mod test_utils; use std::{marker::PhantomData, sync::Arc}; use futures::StreamExt; -use log::{debug, error, trace, warn}; +use log::{error, trace, warn}; use sc_client_api::{Backend, BlockchainEvents, FinalityNotifications}; use sc_offchain::OffchainDb; @@ -110,13 +110,16 @@ where } }, _ => { - trace!(target: LOG_TARGET, "Finality notification: {:?}", notification); - debug!(target: LOG_TARGET, "Waiting for MMR pallet to become available ..."); + trace!( + target: LOG_TARGET, + "Waiting for MMR pallet to become available... (best finalized {:?})", + notification.header.number() + ); }, } } - warn!( + error!( target: LOG_TARGET, "Finality notifications stream closed unexpectedly. \ Couldn't build the canonicalization engine", diff --git a/client/merkle-mountain-range/src/offchain_mmr.rs b/client/merkle-mountain-range/src/offchain_mmr.rs index 7400226b73c44..f42dfc0cae3db 100644 --- a/client/merkle-mountain-range/src/offchain_mmr.rs +++ b/client/merkle-mountain-range/src/offchain_mmr.rs @@ -66,7 +66,7 @@ where match self.client.header_metadata(hash) { Ok(header) => Some(header), _ => { - error!( + debug!( target: LOG_TARGET, "Block {} not found. Couldn't {} associated branch.", hash, action ); @@ -168,7 +168,7 @@ where canon_key ); } else { - error!( + debug!( target: LOG_TARGET, "Couldn't canonicalize elem at pos {} using temp key {:?}", pos, temp_key ); diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index cb567c0137e78..46af84d218247 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -57,10 +57,17 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::{log, weights::Weight}; +use sp_mmr_primitives::utils; use sp_runtime::{ traits::{self, One, Saturating}, SaturatedConversion, }; +use sp_std::prelude::*; + +pub use pallet::*; +pub use sp_mmr_primitives::{ + self as primitives, utils::NodesUtils, Error, LeafDataProvider, LeafIndex, NodeIndex, +}; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -71,13 +78,6 @@ mod mock; #[cfg(test)] mod tests; -pub use pallet::*; -use sp_mmr_primitives::utils; -pub use sp_mmr_primitives::{ - self as primitives, utils::NodesUtils, Error, LeafDataProvider, LeafIndex, NodeIndex, -}; -use sp_std::prelude::*; - /// The most common use case for MMRs is to store historical block hashes, /// so that any point in time in the future we can receive a proof about some past /// blocks without using excessive on-chain storage. diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index 16f0922633088..3fd44275857c1 100644 --- a/frame/merkle-mountain-range/src/mock.rs +++ b/frame/merkle-mountain-range/src/mock.rs @@ -29,7 +29,6 @@ use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup, Keccak256}, }; -use sp_std::prelude::*; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; From 357c363f2fbd1ea53687e90d0ca15677c4468b10 Mon Sep 17 00:00:00 2001 From: yjh Date: Wed, 30 Nov 2022 19:21:45 +0800 Subject: [PATCH 1419/1472] chore: remove unused traits for wasm interface (#12792) --- primitives/wasm-interface/src/lib.rs | 42 ---------------------------- 1 file changed, 42 deletions(-) diff --git a/primitives/wasm-interface/src/lib.rs b/primitives/wasm-interface/src/lib.rs index 246c1abaeae3b..173e3241170fc 100644 --- a/primitives/wasm-interface/src/lib.rs +++ b/primitives/wasm-interface/src/lib.rs @@ -627,48 +627,6 @@ impl_into_and_from_value! { i64, I64, } -/// Something that can write a primitive to wasm memory location. -pub trait WritePrimitive { - /// Write the given value `t` to the given memory location `ptr`. - fn write_primitive(&mut self, ptr: Pointer, t: T) -> Result<()>; -} - -impl WritePrimitive for &mut dyn FunctionContext { - fn write_primitive(&mut self, ptr: Pointer, t: u32) -> Result<()> { - let r = t.to_le_bytes(); - self.write_memory(ptr.cast(), &r) - } -} - -impl WritePrimitive for &mut dyn FunctionContext { - fn write_primitive(&mut self, ptr: Pointer, t: u64) -> Result<()> { - let r = t.to_le_bytes(); - self.write_memory(ptr.cast(), &r) - } -} - -/// Something that can read a primitive from a wasm memory location. -pub trait ReadPrimitive { - /// Read a primitive from the given memory location `ptr`. - fn read_primitive(&self, ptr: Pointer) -> Result; -} - -impl ReadPrimitive for &mut dyn FunctionContext { - fn read_primitive(&self, ptr: Pointer) -> Result { - let mut r = [0u8; 4]; - self.read_memory_into(ptr.cast(), &mut r)?; - Ok(u32::from_le_bytes(r)) - } -} - -impl ReadPrimitive for &mut dyn FunctionContext { - fn read_primitive(&self, ptr: Pointer) -> Result { - let mut r = [0u8; 8]; - self.read_memory_into(ptr.cast(), &mut r)?; - Ok(u64::from_le_bytes(r)) - } -} - /// Typed value that can be returned from a function. /// /// Basically a `TypedValue` plus `Unit`, for functions which return nothing. From cc369313ae0ffac089dacd3a7334b785d59dd9ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 30 Nov 2022 13:27:12 +0000 Subject: [PATCH 1420/1472] sc-transaction-handler: Fix potential crashes on exit (#12807) This fixes some potential crashes in the stream handling in `sc-transaction-handler`. --- client/network/transactions/src/lib.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/client/network/transactions/src/lib.rs b/client/network/transactions/src/lib.rs index 5239a94ef23f3..4cc76507c6f16 100644 --- a/client/network/transactions/src/lib.rs +++ b/client/network/transactions/src/lib.rs @@ -172,11 +172,13 @@ impl TransactionsHandlerPrototype { let handler = TransactionsHandler { protocol_name: self.protocol_name, - propagate_timeout: Box::pin(interval(PROPAGATE_TIMEOUT)), + propagate_timeout: (Box::pin(interval(PROPAGATE_TIMEOUT)) + as Pin + Send>>) + .fuse(), pending_transactions: FuturesUnordered::new(), pending_transactions_peers: HashMap::new(), service, - event_stream, + event_stream: event_stream.fuse(), peers: HashMap::new(), transaction_pool, from_controller, @@ -229,7 +231,7 @@ pub struct TransactionsHandler< > { protocol_name: ProtocolName, /// Interval at which we call `propagate_transactions`. - propagate_timeout: Pin + Send>>, + propagate_timeout: stream::Fuse + Send>>>, /// Pending transactions verification tasks. pending_transactions: FuturesUnordered>, /// As multiple peers can send us the same transaction, we group @@ -240,7 +242,7 @@ pub struct TransactionsHandler< /// Network service to use to send messages and manage peers. service: S, /// Stream of networking events. - event_stream: Pin + Send>>, + event_stream: stream::Fuse + Send>>>, // All connected peers peers: HashMap>, transaction_pool: Arc>, @@ -268,7 +270,7 @@ where pub async fn run(mut self) { loop { futures::select! { - _ = self.propagate_timeout.next().fuse() => { + _ = self.propagate_timeout.next() => { self.propagate_transactions(); }, (tx_hash, result) = self.pending_transactions.select_next_some() => { @@ -278,7 +280,7 @@ where warn!(target: "sub-libp2p", "Inconsistent state, no peers for pending transaction!"); } }, - network_event = self.event_stream.next().fuse() => { + network_event = self.event_stream.next() => { if let Some(network_event) = network_event { self.handle_network_event(network_event).await; } else { @@ -286,7 +288,7 @@ where return; } }, - message = self.from_controller.select_next_some().fuse() => { + message = self.from_controller.select_next_some() => { match message { ToHandler::PropagateTransaction(hash) => self.propagate_transaction(&hash), ToHandler::PropagateTransactions => self.propagate_transactions(), From 2ed405854a84a071becb96f31a16309dbff3e2c1 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Wed, 30 Nov 2022 15:37:28 +0200 Subject: [PATCH 1421/1472] Don't announce blocks in `sync_to_tip_when_we_sync_together_with_multiple_peers` (#12783) * Fix syncing test * cargo fmt * Fix test --- client/network/test/src/lib.rs | 3 ++- client/network/test/src/sync.rs | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 975d902157310..4eb93499d7435 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -428,8 +428,9 @@ where at: BlockId, count: usize, with_tx: bool, + announce_block: bool, ) -> H256 { - self.generate_tx_blocks_at(at, count, with_tx, false, false, true) + self.generate_tx_blocks_at(at, count, with_tx, false, false, announce_block) } /// Push blocks to the peer (simplified: with or without a TX) starting from diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index 4515677d0b1e0..ea3895cb4dfde 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -775,7 +775,9 @@ fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { let mut net = TestNet::new(1); // Produce some blocks - let block_hash = net.peer(0).push_blocks_at_without_informing_sync(BlockId::Number(0), 3, true); + let block_hash = + net.peer(0) + .push_blocks_at_without_informing_sync(BlockId::Number(0), 3, true, true); // Add a node and wait until they are connected net.add_full_peer_with_config(Default::default()); @@ -818,10 +820,10 @@ fn sync_to_tip_when_we_sync_together_with_multiple_peers() { let block_hash = net.peer(0) - .push_blocks_at_without_informing_sync(BlockId::Number(0), 10_000, false); + .push_blocks_at_without_informing_sync(BlockId::Number(0), 10_000, false, false); net.peer(1) - .push_blocks_at_without_informing_sync(BlockId::Number(0), 5_000, false); + .push_blocks_at_without_informing_sync(BlockId::Number(0), 5_000, false, false); net.block_until_connected(); net.block_until_idle(); @@ -829,6 +831,8 @@ fn sync_to_tip_when_we_sync_together_with_multiple_peers() { assert!(!net.peer(2).has_block(block_hash)); net.peer(0).network_service().new_best_block_imported(block_hash, 10_000); + net.peer(0).network_service().announce_block(block_hash, None); + while !net.peer(2).has_block(block_hash) && !net.peer(1).has_block(block_hash) { net.block_until_idle(); } From 982f5998c59bd2bd455808345ae1bd2b1767f353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 30 Nov 2022 14:19:14 +0000 Subject: [PATCH 1422/1472] contracts: Replace cargo feature `unstable-interface` with config (#12787) * Replace cargo feature with config * Update frame/contracts/proc-macro/src/lib.rs Co-authored-by: Sasha Gryaznov Co-authored-by: Sasha Gryaznov --- bin/node/runtime/Cargo.toml | 3 -- bin/node/runtime/src/lib.rs | 3 +- frame/contracts/Cargo.toml | 4 -- frame/contracts/README.md | 17 ++----- frame/contracts/proc-macro/src/lib.rs | 39 +++++++------- frame/contracts/src/benchmarking/sandbox.rs | 2 +- frame/contracts/src/lib.rs | 14 ++++++ frame/contracts/src/tests.rs | 12 +++-- frame/contracts/src/wasm/mod.rs | 56 ++++++++++++++++----- frame/contracts/src/wasm/runtime.rs | 10 +--- 10 files changed, 94 insertions(+), 66 deletions(-) diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index dcc59ce750934..f812cbe030c86 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -312,9 +312,6 @@ try-runtime = [ "pallet-vesting/try-runtime", "pallet-whitelist/try-runtime", ] -# Make contract callable functions marked as __unstable__ available. Do not enable -# on live chains as those are subject to change. -contracts-unstable-interface = ["pallet-contracts/unstable-interface"] # Force `sp-sandbox` to call into the host resident executor. One still need to make sure # that `sc-executor` gets the `wasmer-sandbox` feature which happens automatically when # specified on the command line. diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f284aaa3a69a8..215b02bcca994 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -32,7 +32,7 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, + AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, WithdrawReasons, }, @@ -1191,6 +1191,7 @@ impl pallet_contracts::Config for Runtime { type AddressGenerator = pallet_contracts::DefaultAddressGenerator; type MaxCodeLen = ConstU32<{ 128 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; + type UnsafeUnstableInterface = ConstBool; } impl pallet_sudo::Config for Runtime { diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index fead0a414442f..3906e8589c116 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -84,9 +84,5 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "rand", "rand_pcg", - "unstable-interface", ] try-runtime = ["frame-support/try-runtime"] -# Make contract callable functions marked as unstable available. Do not enable -# on live chains as those are subject to change. -unstable-interface = [] diff --git a/frame/contracts/README.md b/frame/contracts/README.md index 6b8e62e840b07..4df7d9449682d 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -142,18 +142,11 @@ this pallet contains the concept of an unstable interface. Akin to the rust nigh it allows us to add new interfaces but mark them as unstable so that contract languages can experiment with them and give feedback before we stabilize those. -In order to access interfaces marked as `#[unstable]` in `runtime.rs` one need to compile -this crate with the `unstable-interface` feature enabled. It should be obvious that any -live runtime should never be compiled with this feature: In addition to be subject to -change or removal those interfaces do not have proper weights associated with them and -are therefore considered unsafe. - -The substrate runtime exposes this feature as `contracts-unstable-interface`. Example -commandline for running the substrate node with unstable contracts interfaces: - -```bash -cargo run --release --features contracts-unstable-interface -- --dev -``` +In order to access interfaces marked as `#[unstable]` in `runtime.rs` one need to set +`pallet_contracts::Config::UnsafeUnstableInterface` to `ConstU32`. It should be obvious +that any production runtime should never be compiled with this feature: In addition to be +subject to change or removal those interfaces might not have proper weights associated with +them and are therefore considered unsafe. New interfaces are generally added as unstable and might go through several iterations before they are promoted to a stable interface. diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index 5f08b2a9d3081..82b5b728a73ee 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -157,7 +157,7 @@ struct HostFn { module: String, name: String, returns: HostFnReturn, - is_unstable: bool, + is_stable: bool, } enum HostFnReturn { @@ -199,7 +199,7 @@ impl HostFn { attrs.retain(|a| !(a.path.is_ident("doc") || a.path.is_ident("prefixed_alias"))); let name = item.sig.ident.to_string(); let mut maybe_module = None; - let mut is_unstable = false; + let mut is_stable = true; while let Some(attr) = attrs.pop() { let ident = attr.path.get_ident().ok_or(err(span, msg))?.to_string(); match ident.as_str() { @@ -212,10 +212,10 @@ impl HostFn { maybe_module = Some(format!("seal{}", ver)); }, "unstable" => { - if is_unstable { + if !is_stable { return Err(err(span, "#[unstable] can only be specified once")) } - is_unstable = true; + is_stable = false; }, _ => return Err(err(span, msg)), } @@ -312,7 +312,7 @@ impl HostFn { module: maybe_module.unwrap_or_else(|| "seal0".to_string()), name, returns, - is_unstable, + is_stable, }) }, _ => Err(err(span, &msg)), @@ -406,7 +406,7 @@ fn expand_impls(def: &mut EnvDef) -> TokenStream2 { ::AccountId: ::sp_core::crypto::UncheckedFrom<::Hash> + ::core::convert::AsRef<[::core::primitive::u8]>, { - fn define(store: &mut ::wasmi::Store>, linker: &mut ::wasmi::Linker>) -> Result<(), ::wasmi::errors::LinkerError> { + fn define(store: &mut ::wasmi::Store>, linker: &mut ::wasmi::Linker>, allow_unstable: bool) -> Result<(), ::wasmi::errors::LinkerError> { #impls Ok(()) } @@ -414,7 +414,7 @@ fn expand_impls(def: &mut EnvDef) -> TokenStream2 { impl crate::wasm::Environment<()> for Env { - fn define(store: &mut ::wasmi::Store<()>, linker: &mut ::wasmi::Linker<()>) -> Result<(), ::wasmi::errors::LinkerError> { + fn define(store: &mut ::wasmi::Store<()>, linker: &mut ::wasmi::Linker<()>, allow_unstable: bool) -> Result<(), ::wasmi::errors::LinkerError> { #dummy_impls Ok(()) } @@ -437,10 +437,7 @@ fn expand_functions( f.returns.to_wasm_sig(), &f.item.sig.output ); - let unstable_feat = match f.is_unstable { - true => quote! { #[cfg(feature = "unstable-interface")] }, - false => quote! {}, - }; + let is_stable = f.is_stable; // If we don't expand blocks (implementing for `()`) we change a few things: // - We replace any code by unreachable! @@ -480,16 +477,18 @@ fn expand_functions( quote! { #[allow(unused_variables)] } }; - quote! { - #unstable_feat - #allow_unused - linker.define(#module, #name, ::wasmi::Func::wrap(&mut*store, |mut __caller__: ::wasmi::Caller<#host_state>, #( #params, )*| -> #wasm_output { - let mut func = #inner; - func() - .map_err(#map_err) - .map(::core::convert::Into::into) - }))?; + // We need to allow unstable functions when runtime benchmarks are performed because + // we generate the weights even when those interfaces are not enabled. + if ::core::cfg!(feature = "runtime-benchmarks") || #is_stable || allow_unstable { + #allow_unused + linker.define(#module, #name, ::wasmi::Func::wrap(&mut*store, |mut __caller__: ::wasmi::Caller<#host_state>, #( #params, )*| -> #wasm_output { + let mut func = #inner; + func() + .map_err(#map_err) + .map(::core::convert::Into::into) + }))?; + } } }); quote! { diff --git a/frame/contracts/src/benchmarking/sandbox.rs b/frame/contracts/src/benchmarking/sandbox.rs index b0cb9297d5656..a35aad3500109 100644 --- a/frame/contracts/src/benchmarking/sandbox.rs +++ b/frame/contracts/src/benchmarking/sandbox.rs @@ -64,7 +64,7 @@ where struct EmptyEnv; impl Environment<()> for EmptyEnv { - fn define(_store: &mut Store<()>, _linker: &mut Linker<()>) -> Result<(), LinkerError> { + fn define(_: &mut Store<()>, _: &mut Linker<()>, _: bool) -> Result<(), LinkerError> { Ok(()) } } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 00b0655ea4af6..4bbb311313d61 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -326,10 +326,24 @@ pub mod pallet { /// The maximum length of a contract code in bytes. This limit applies to the instrumented /// version of the code. Therefore `instantiate_with_code` can fail even when supplying /// a wasm binary below this maximum size. + #[pallet::constant] type MaxCodeLen: Get; /// The maximum allowable length in bytes for storage keys. + #[pallet::constant] type MaxStorageKeyLen: Get; + + /// Make contract callable functions marked as `#[unstable]` available. + /// + /// Contracts that use `#[unstable]` functions won't be able to be uploaded unless + /// this is set to `true`. This is only meant for testnets and dev nodes in order to + /// experiment with new features. + /// + /// # Warning + /// + /// Do **not** set to `true` on productions chains. + #[pallet::constant] + type UnsafeUnstableInterface: Get; } #[pallet::hooks] diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index e7b27ed38e271..e5395c73d2868 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -122,6 +122,12 @@ pub mod test_utils { } } +impl Test { + pub fn set_unstable_interface(unstable_interface: bool) { + UNSTABLE_INTERFACE.with(|v| *v.borrow_mut() = unstable_interface); + } +} + parameter_types! { static TestExtensionTestValue: TestExtension = Default::default(); } @@ -385,6 +391,7 @@ impl Contains for TestFilter { parameter_types! { pub const DeletionWeightLimit: Weight = Weight::from_ref_time(500_000_000_000); + pub static UnstableInterface: bool = true; } impl Config for Test { @@ -407,6 +414,7 @@ impl Config for Test { type AddressGenerator = DefaultAddressGenerator; type MaxCodeLen = ConstU32<{ 128 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; + type UnsafeUnstableInterface = UnstableInterface; } pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); @@ -2687,7 +2695,6 @@ fn gas_estimation_nested_call_fixed_limit() { } #[test] -#[cfg(feature = "unstable-interface")] fn gas_estimation_call_runtime() { use codec::Decode; let (caller_code, caller_hash) = compile_module::("call_runtime").unwrap(); @@ -4411,7 +4418,6 @@ fn delegate_call_indeterministic_code() { } #[test] -#[cfg(feature = "unstable-interface")] fn reentrance_count_works_with_call() { let (wasm, code_hash) = compile_module::("reentrance_count_call").unwrap(); let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]); @@ -4448,7 +4454,6 @@ fn reentrance_count_works_with_call() { } #[test] -#[cfg(feature = "unstable-interface")] fn reentrance_count_works_with_delegated_call() { let (wasm, code_hash) = compile_module::("reentrance_count_delegated_call").unwrap(); let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]); @@ -4485,7 +4490,6 @@ fn reentrance_count_works_with_delegated_call() { } #[test] -#[cfg(feature = "unstable-interface")] fn account_reentrance_count_works() { let (wasm, code_hash) = compile_module::("account_reentrance_count_call").unwrap(); let (wasm_reentrance_count, code_hash_reentrance_count) = diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 6eaf0d37bef07..ac338007e5dc9 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -36,7 +36,7 @@ use crate::{ }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::dispatch::{DispatchError, DispatchResult}; -use sp_core::crypto::UncheckedFrom; +use sp_core::{crypto::UncheckedFrom, Get}; use sp_runtime::RuntimeDebug; use sp_std::prelude::*; #[cfg(test)] @@ -218,7 +218,7 @@ where let module = Module::new(&engine, code)?; let mut store = Store::new(&engine, host_state); let mut linker = Linker::new(); - E::define(&mut store, &mut linker)?; + E::define(&mut store, &mut linker, T::UnsafeUnstableInterface::get())?; let memory = Memory::new(&mut store, MemoryType::new(memory.0, Some(memory.1))?).expect( "The limits defined in our `Schedule` limit the amount of memory well below u32::MAX; qed", ); @@ -627,10 +627,17 @@ mod tests { } } - fn execute>(wat: &str, input_data: Vec, mut ext: E) -> ExecResult { + fn execute_internal>( + wat: &str, + input_data: Vec, + mut ext: E, + unstable_interface: bool, + ) -> ExecResult { + type RuntimeConfig = ::T; + RuntimeConfig::set_unstable_interface(unstable_interface); let wasm = wat::parse_str(wat).unwrap(); let schedule = crate::Schedule::default(); - let executable = PrefabWasmModule::<::T>::from_code( + let executable = PrefabWasmModule::::from_code( wasm, &schedule, ALICE, @@ -641,6 +648,19 @@ mod tests { executable.execute(ext.borrow_mut(), &ExportedFunction::Call, input_data) } + fn execute>(wat: &str, input_data: Vec, ext: E) -> ExecResult { + execute_internal(wat, input_data, ext, false) + } + + #[cfg(not(feature = "runtime-benchmarks"))] + fn execute_with_unstable>( + wat: &str, + input_data: Vec, + ext: E, + ) -> ExecResult { + execute_internal(wat, input_data, ext, true) + } + const CODE_TRANSFER: &str = r#" (module ;; seal_transfer( @@ -741,7 +761,6 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn contract_delegate_call() { const CODE: &str = r#" (module @@ -2274,7 +2293,6 @@ mod tests { ); } - #[cfg(feature = "unstable-interface")] const CODE_CALL_RUNTIME: &str = r#" (module (import "seal0" "call_runtime" (func $call_runtime (param i32 i32) (result i32))) @@ -2311,7 +2329,6 @@ mod tests { "#; #[test] - #[cfg(feature = "unstable-interface")] fn call_runtime_works() { let call = RuntimeCall::System(frame_system::Call::remark { remark: b"Hello World".to_vec() }); @@ -2323,7 +2340,6 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn call_runtime_panics_on_invalid_call() { let mut ext = MockExt::default(); let result = execute(CODE_CALL_RUNTIME, vec![0x42], &mut ext); @@ -2586,7 +2602,6 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn take_storage_works() { const CODE: &str = r#" (module @@ -2822,7 +2837,6 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn caller_is_origin_works() { const CODE_CALLER_IS_ORIGIN: &str = r#" ;; This runs `caller_is_origin` check on zero account address @@ -2894,7 +2908,6 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn reentrance_count_works() { const CODE: &str = r#" (module @@ -2927,7 +2940,6 @@ mod tests { } #[test] - #[cfg(feature = "unstable-interface")] fn account_reentrance_count_works() { const CODE: &str = r#" (module @@ -2958,4 +2970,24 @@ mod tests { let mut mock_ext = MockExt::default(); execute(CODE, vec![], &mut mock_ext).unwrap(); } + + /// This test check that an unstable interface cannot be deployed. In case of runtime + /// benchmarks we always allow unstable interfaces. This is why this test does not + /// work when this feature is enabled. + #[cfg(not(feature = "runtime-benchmarks"))] + #[test] + fn cannot_deploy_unstable() { + const CANNT_DEPLOY_UNSTABLE: &str = r#" +(module + (import "seal0" "reentrance_count" (func $reentrance_count (result i32))) + (func (export "call")) + (func (export "deploy")) +) +"#; + assert_err!( + execute(CANNT_DEPLOY_UNSTABLE, vec![], MockExt::default()), + >::CodeRejected, + ); + assert_ok!(execute_with_unstable(CANNT_DEPLOY_UNSTABLE, vec![], MockExt::default())); + } } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 4c6006d2612fe..988bb224f2a6c 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -46,6 +46,7 @@ pub trait Environment { fn define( store: &mut Store, linker: &mut Linker, + allow_unstable: bool, ) -> Result<(), LinkerError>; } @@ -105,7 +106,6 @@ pub enum ReturnCode { /// recording was disabled. LoggingDisabled = 9, /// The call dispatched by `seal_call_runtime` was executed but returned an error. - #[cfg(feature = "unstable-interface")] CallRuntimeReturnedError = 10, /// ECDSA pubkey recovery failed (most probably wrong recovery id or signature), or /// ECDSA compressed pubkey conversion into Ethereum address failed (most probably @@ -228,7 +228,6 @@ pub enum RuntimeCosts { /// Weight of calling `seal_get_storage` with the specified size in storage. GetStorage(u32), /// Weight of calling `seal_take_storage` for the given size. - #[cfg(feature = "unstable-interface")] TakeStorage(u32), /// Weight of calling `seal_transfer`. Transfer, @@ -257,17 +256,14 @@ pub enum RuntimeCosts { /// Weight charged by a chain extension through `seal_call_chain_extension`. ChainExtension(u64), /// Weight charged for calling into the runtime. - #[cfg(feature = "unstable-interface")] CallRuntime(Weight), /// Weight of calling `seal_set_code_hash` SetCodeHash, /// Weight of calling `ecdsa_to_eth_address` EcdsaToEthAddress, /// Weight of calling `reentrance_count` - #[cfg(feature = "unstable-interface")] ReentrantCount, /// Weight of calling `account_reentrance_count` - #[cfg(feature = "unstable-interface")] AccountEntranceCount, } @@ -316,7 +312,6 @@ impl RuntimeCosts { .saturating_add(s.contains_storage_per_byte.saturating_mul(len.into())), GetStorage(len) => s.get_storage.saturating_add(s.get_storage_per_byte.saturating_mul(len.into())), - #[cfg(feature = "unstable-interface")] TakeStorage(len) => s .take_storage .saturating_add(s.take_storage_per_byte.saturating_mul(len.into())), @@ -344,13 +339,10 @@ impl RuntimeCosts { .saturating_add(s.hash_blake2_128_per_byte.saturating_mul(len.into())), EcdsaRecovery => s.ecdsa_recover, ChainExtension(amount) => amount, - #[cfg(feature = "unstable-interface")] CallRuntime(weight) => weight.ref_time(), SetCodeHash => s.set_code_hash, EcdsaToEthAddress => s.ecdsa_to_eth_address, - #[cfg(feature = "unstable-interface")] ReentrantCount => s.reentrance_count, - #[cfg(feature = "unstable-interface")] AccountEntranceCount => s.account_reentrance_count, }; RuntimeToken { From 009c872a970beb755e2ac98aef47b2a27e60951d Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 1 Dec 2022 15:52:36 +0100 Subject: [PATCH 1423/1472] Bounties use SpendOrigin (#12808) * Bounties use SpendOrigin * Fix tests Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * tests: increase spend limits Signed-off-by: Oliver Tale-Yazdi * fix benchmarks Signed-off-by: Oliver Tale-Yazdi * Fix child-bounties tests Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/bench-bot.sh" pallet dev pallet_bounties Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- frame/bounties/src/benchmarking.rs | 8 +- frame/bounties/src/lib.rs | 13 +- frame/bounties/src/tests.rs | 99 +++++++++++++- frame/bounties/src/weights.rs | 213 +++++++++++++++-------------- frame/child-bounties/src/tests.rs | 3 +- 5 files changed, 217 insertions(+), 119 deletions(-) diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 07dd781c29af3..84f5665d402a1 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -97,7 +97,7 @@ benchmarks_instance_pallet! { let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = T::SpendOrigin::successful_origin(); }: _(approve_origin, bounty_id) propose_curator { @@ -106,10 +106,10 @@ benchmarks_instance_pallet! { let curator_lookup = T::Lookup::unlookup(curator); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = T::SpendOrigin::successful_origin(); Bounties::::approve_bounty(approve_origin, bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = T::SpendOrigin::successful_origin(); }: _(approve_origin, bounty_id, curator_lookup, fee) // Worst case when curator is inactive and any sender unassigns the curator. @@ -128,7 +128,7 @@ benchmarks_instance_pallet! { let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = T::SpendOrigin::successful_origin(); Bounties::::approve_bounty(approve_origin.clone(), bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); Bounties::::propose_curator(approve_origin, bounty_id, curator_lookup, fee)?; diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index d947226f87fa0..2e350dd1e2484 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -357,10 +357,13 @@ pub mod pallet { origin: OriginFor, #[pallet::compact] bounty_id: BountyIndex, ) -> DispatchResult { - T::ApproveOrigin::ensure_origin(origin)?; - + let max_amount = T::SpendOrigin::ensure_origin(origin)?; Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; + ensure!( + bounty.value <= max_amount, + pallet_treasury::Error::::InsufficientPermission + ); ensure!(bounty.status == BountyStatus::Proposed, Error::::UnexpectedStatus); bounty.status = BountyStatus::Approved; @@ -387,11 +390,15 @@ pub mod pallet { curator: AccountIdLookupOf, #[pallet::compact] fee: BalanceOf, ) -> DispatchResult { - T::ApproveOrigin::ensure_origin(origin)?; + let max_amount = T::SpendOrigin::ensure_origin(origin)?; let curator = T::Lookup::lookup(curator)?; Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { let mut bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; + ensure!( + bounty.value <= max_amount, + pallet_treasury::Error::::InsufficientPermission + ); match bounty.status { BountyStatus::Funded => {}, _ => return Err(Error::::UnexpectedStatus.into()), diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index 68aa56ccdde7f..bc59e3a70fd82 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -106,6 +106,8 @@ parameter_types! { pub static Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); pub const TreasuryPalletId2: PalletId = PalletId(*b"py/trsr2"); + pub static SpendLimit: Balance = u64::MAX; + pub static SpendLimit1: Balance = u64::MAX; } impl pallet_treasury::Config for Test { @@ -124,7 +126,7 @@ impl pallet_treasury::Config for Test { type WeightInfo = (); type SpendFunds = Bounties; type MaxApprovals = ConstU32<100>; - type SpendOrigin = frame_support::traits::NeverEnsureOrigin; + type SpendOrigin = frame_system::EnsureRootWithSuccess; } impl pallet_treasury::Config for Test { @@ -143,7 +145,7 @@ impl pallet_treasury::Config for Test { type WeightInfo = (); type SpendFunds = Bounties1; type MaxApprovals = ConstU32<100>; - type SpendOrigin = frame_support::traits::NeverEnsureOrigin; + type SpendOrigin = frame_system::EnsureRootWithSuccess; } parameter_types! { @@ -185,6 +187,7 @@ impl Config for Test { } type TreasuryError = pallet_treasury::Error; +type TreasuryError1 = pallet_treasury::Error; pub fn new_test_ext() -> sp_io::TestExternalities { let mut ext: sp_io::TestExternalities = GenesisConfig { @@ -1136,6 +1139,8 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&user, 100); + // Allow for a larger spend limit: + SpendLimit::set(value); assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); @@ -1182,6 +1187,8 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&user, starting_balance); Balances::make_free_balance_be(&0, starting_balance); + // Allow for a larger spend limit: + SpendLimit::set(value); assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); @@ -1209,16 +1216,98 @@ fn approve_bounty_works_second_instance() { assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); assert_eq!(Balances::free_balance(&Treasury1::account_id()), 201); - assert_ok!(Bounties1::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties1::propose_bounty(RuntimeOrigin::signed(0), 10, b"12345".to_vec())); assert_ok!(Bounties1::approve_bounty(RuntimeOrigin::root(), 0)); >::on_initialize(2); >::on_initialize(2); // Bounties 1 is funded... but from where? - assert_eq!(Balances::free_balance(Bounties1::bounty_account_id(0)), 50); + assert_eq!(Balances::free_balance(Bounties1::bounty_account_id(0)), 10); // Treasury 1 unchanged assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); // Treasury 2 has funds removed - assert_eq!(Balances::free_balance(&Treasury1::account_id()), 201 - 50); + assert_eq!(Balances::free_balance(&Treasury1::account_id()), 201 - 10); + }); +} + +#[test] +fn approve_bounty_insufficient_spend_limit_errors() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_eq!(Treasury::pot(), 100); + + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 51, b"123".to_vec())); + // 51 will not work since the limit is 50. + SpendLimit::set(50); + assert_noop!( + Bounties::approve_bounty(RuntimeOrigin::root(), 0), + TreasuryError::InsufficientPermission + ); + }); +} + +#[test] +fn approve_bounty_instance1_insufficient_spend_limit_errors() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + + Balances::make_free_balance_be(&Treasury1::account_id(), 101); + assert_eq!(Treasury1::pot(), 100); + + assert_ok!(Bounties1::propose_bounty(RuntimeOrigin::signed(0), 51, b"123".to_vec())); + // 51 will not work since the limit is 50. + SpendLimit1::set(50); + assert_noop!( + Bounties1::approve_bounty(RuntimeOrigin::root(), 0), + TreasuryError1::InsufficientPermission + ); + }); +} + +#[test] +fn propose_curator_insufficient_spend_limit_errors() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + + // Temporarily set a larger spend limit; + SpendLimit::set(51); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 51, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + SpendLimit::set(50); + // 51 will not work since the limit is 50. + assert_noop!( + Bounties::propose_curator(RuntimeOrigin::root(), 0, 0, 0), + TreasuryError::InsufficientPermission + ); + }); +} + +#[test] +fn propose_curator_instance1_insufficient_spend_limit_errors() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + + // Temporarily set a larger spend limit; + SpendLimit1::set(11); + assert_ok!(Bounties1::propose_bounty(RuntimeOrigin::signed(0), 11, b"12345".to_vec())); + assert_ok!(Bounties1::approve_bounty(RuntimeOrigin::root(), 0)); + + System::set_block_number(2); + >::on_initialize(2); + + SpendLimit1::set(10); + // 11 will not work since the limit is 10. + assert_noop!( + Bounties1::propose_curator(RuntimeOrigin::root(), 0, 0, 0), + TreasuryError1::InsufficientPermission + ); }); } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 71f4bf01899fb..34e78bfa556e7 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -18,24 +18,25 @@ //! Autogenerated weights for pallet_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-11-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_bounties // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/bounties/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_bounties +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/bounties/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -69,102 +70,102 @@ impl WeightInfo for SubstrateWeight { // Storage: Bounties Bounties (r:0 w:1) /// The range of component `d` is `[0, 300]`. fn propose_bounty(d: u32, ) -> Weight { - // Minimum execution time: 33_514 nanoseconds. - Weight::from_ref_time(34_906_466 as u64) - // Standard Error: 226 - .saturating_add(Weight::from_ref_time(2_241 as u64).saturating_mul(d as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 33_366 nanoseconds. + Weight::from_ref_time(34_444_773) + // Standard Error: 1_161 + .saturating_add(Weight::from_ref_time(4_723).saturating_mul(d.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - // Minimum execution time: 14_129 nanoseconds. - Weight::from_ref_time(14_424_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 14_478 nanoseconds. + Weight::from_ref_time(14_763_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - // Minimum execution time: 13_675 nanoseconds. - Weight::from_ref_time(13_964_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 13_376 nanoseconds. + Weight::from_ref_time(13_705_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - // Minimum execution time: 38_926 nanoseconds. - Weight::from_ref_time(40_183_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 38_072 nanoseconds. + Weight::from_ref_time(38_676_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - // Minimum execution time: 33_774 nanoseconds. - Weight::from_ref_time(34_295_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 33_207 nanoseconds. + Weight::from_ref_time(34_415_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - // Minimum execution time: 28_558 nanoseconds. - Weight::from_ref_time(29_293_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 28_033 nanoseconds. + Weight::from_ref_time(28_343_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:3 w:3) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - // Minimum execution time: 77_042 nanoseconds. - Weight::from_ref_time(77_730_000 as u64) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + // Minimum execution time: 75_855 nanoseconds. + Weight::from_ref_time(76_318_000) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - // Minimum execution time: 43_632 nanoseconds. - Weight::from_ref_time(44_196_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 41_955 nanoseconds. + Weight::from_ref_time(42_733_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - // Minimum execution time: 59_519 nanoseconds. - Weight::from_ref_time(59_967_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 58_267 nanoseconds. + Weight::from_ref_time(59_604_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - // Minimum execution time: 25_263 nanoseconds. - Weight::from_ref_time(25_788_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 24_893 nanoseconds. + Weight::from_ref_time(25_299_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Bounties Bounties (r:2 w:2) // Storage: System Account (r:4 w:4) /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { - // Minimum execution time: 8_953 nanoseconds. - Weight::from_ref_time(23_242_227 as u64) - // Standard Error: 13_187 - .saturating_add(Weight::from_ref_time(26_727_999 as u64).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(b as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(b as u64))) + // Minimum execution time: 8_846 nanoseconds. + Weight::from_ref_time(20_166_004) + // Standard Error: 28_485 + .saturating_add(Weight::from_ref_time(26_712_253).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(b.into()))) } } @@ -176,101 +177,101 @@ impl WeightInfo for () { // Storage: Bounties Bounties (r:0 w:1) /// The range of component `d` is `[0, 300]`. fn propose_bounty(d: u32, ) -> Weight { - // Minimum execution time: 33_514 nanoseconds. - Weight::from_ref_time(34_906_466 as u64) - // Standard Error: 226 - .saturating_add(Weight::from_ref_time(2_241 as u64).saturating_mul(d as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 33_366 nanoseconds. + Weight::from_ref_time(34_444_773) + // Standard Error: 1_161 + .saturating_add(Weight::from_ref_time(4_723).saturating_mul(d.into())) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: Bounties BountyApprovals (r:1 w:1) fn approve_bounty() -> Weight { - // Minimum execution time: 14_129 nanoseconds. - Weight::from_ref_time(14_424_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 14_478 nanoseconds. + Weight::from_ref_time(14_763_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Bounties Bounties (r:1 w:1) fn propose_curator() -> Weight { - // Minimum execution time: 13_675 nanoseconds. - Weight::from_ref_time(13_964_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 13_376 nanoseconds. + Weight::from_ref_time(13_705_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn unassign_curator() -> Weight { - // Minimum execution time: 38_926 nanoseconds. - Weight::from_ref_time(40_183_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 38_072 nanoseconds. + Weight::from_ref_time(38_676_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:1 w:1) fn accept_curator() -> Weight { - // Minimum execution time: 33_774 nanoseconds. - Weight::from_ref_time(34_295_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 33_207 nanoseconds. + Weight::from_ref_time(34_415_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) fn award_bounty() -> Weight { - // Minimum execution time: 28_558 nanoseconds. - Weight::from_ref_time(29_293_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 28_033 nanoseconds. + Weight::from_ref_time(28_343_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: System Account (r:3 w:3) // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn claim_bounty() -> Weight { - // Minimum execution time: 77_042 nanoseconds. - Weight::from_ref_time(77_730_000 as u64) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + // Minimum execution time: 75_855 nanoseconds. + Weight::from_ref_time(76_318_000) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_proposed() -> Weight { - // Minimum execution time: 43_632 nanoseconds. - Weight::from_ref_time(44_196_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 41_955 nanoseconds. + Weight::from_ref_time(42_733_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Bounties Bounties (r:1 w:1) // Storage: ChildBounties ParentChildBounties (r:1 w:0) // Storage: System Account (r:2 w:2) // Storage: Bounties BountyDescriptions (r:0 w:1) fn close_bounty_active() -> Weight { - // Minimum execution time: 59_519 nanoseconds. - Weight::from_ref_time(59_967_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 58_267 nanoseconds. + Weight::from_ref_time(59_604_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Bounties Bounties (r:1 w:1) fn extend_bounty_expiry() -> Weight { - // Minimum execution time: 25_263 nanoseconds. - Weight::from_ref_time(25_788_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 24_893 nanoseconds. + Weight::from_ref_time(25_299_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Bounties BountyApprovals (r:1 w:1) // Storage: Bounties Bounties (r:2 w:2) // Storage: System Account (r:4 w:4) /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { - // Minimum execution time: 8_953 nanoseconds. - Weight::from_ref_time(23_242_227 as u64) - // Standard Error: 13_187 - .saturating_add(Weight::from_ref_time(26_727_999 as u64).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(b as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(b as u64))) + // Minimum execution time: 8_846 nanoseconds. + Weight::from_ref_time(20_166_004) + // Standard Error: 28_485 + .saturating_add(Weight::from_ref_time(26_712_253).saturating_mul(b.into())) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(b.into()))) + .saturating_add(RocksDbWeight::get().writes(1)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(b.into()))) } } diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index 67983b15f4579..f3415c69df611 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -108,6 +108,7 @@ parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub const SpendLimit: Balance = u64::MAX; } impl pallet_treasury::Config for Test { @@ -126,7 +127,7 @@ impl pallet_treasury::Config for Test { type WeightInfo = (); type SpendFunds = Bounties; type MaxApprovals = ConstU32<100>; - type SpendOrigin = frame_support::traits::NeverEnsureOrigin; + type SpendOrigin = frame_system::EnsureRootWithSuccess; } parameter_types! { // This will be 50% of the bounty fee. From 5ae8a3b64d3adf50f958fe3c8a6cb221d4d6d22c Mon Sep 17 00:00:00 2001 From: alexgparity <115470171+alexgparity@users.noreply.github.com> Date: Thu, 1 Dec 2022 16:51:36 +0100 Subject: [PATCH 1424/1472] Reduce provisioner work (#12749) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move create_inherent_data call to use side * Make provide_inherent_data async * Fix tests * Apply suggestions from code review Co-authored-by: Bastian Köcher * Log errors * Fix test * Fix test * fix * Deduplicate test code * fix * flag * Update client/consensus/slots/src/lib.rs Co-authored-by: Bastian Köcher * Revert "Deduplicate test code" This reverts commit ba46adbe089329c78cd69ccdb08e27ed67bd77cf. * Fix test * remove commented out code * minor to start CI run * start CI * Update client/consensus/slots/src/lib.rs Co-authored-by: Marcin S. * Apply PR suggestions * Apply PR suggestions * Update client/consensus/slots/src/lib.rs Co-authored-by: Bastian Köcher * minor * kickoff CI * PR suggestions * Compute remaining duration instead of using slot_info.duration * Don't rely on sub implementation for Instant * Apply PR suggestions * Use saturating_duration_since Co-authored-by: Bastian Köcher Co-authored-by: Marcin S. Co-authored-by: parity-processbot <> --- Cargo.lock | 1 + bin/node-template/node/Cargo.toml | 1 + bin/node-template/node/src/benchmarking.rs | 3 +- bin/node/bench/src/construct.rs | 4 +- bin/node/cli/src/benchmarking.rs | 3 +- bin/node/cli/src/service.rs | 16 +++--- client/consensus/aura/src/import_queue.rs | 1 + client/consensus/aura/src/lib.rs | 4 +- client/consensus/babe/src/lib.rs | 1 + .../manual-seal/src/consensus/timestamp.rs | 2 +- .../consensus/manual-seal/src/seal_block.rs | 2 +- client/consensus/pow/src/lib.rs | 3 +- client/consensus/slots/src/lib.rs | 50 +++++++++++++++++-- client/consensus/slots/src/slots.rs | 31 +++++------- primitives/authorship/src/lib.rs | 2 +- primitives/consensus/aura/src/inherents.rs | 2 +- primitives/consensus/babe/src/inherents.rs | 2 +- primitives/inherents/src/client_side.rs | 10 ++-- primitives/inherents/src/lib.rs | 8 +-- primitives/timestamp/src/lib.rs | 2 +- .../transaction-storage-proof/src/lib.rs | 2 +- 21 files changed, 97 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 883ad88c01fcb..6896d65f44c0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4744,6 +4744,7 @@ dependencies = [ "frame-benchmarking", "frame-benchmarking-cli", "frame-system", + "futures", "jsonrpsee", "node-template-runtime", "pallet-transaction-payment", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 469c939da4e83..d609edc88401d 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -18,6 +18,7 @@ name = "node-template" [dependencies] clap = { version = "4.0.9", features = ["derive"] } +futures = { version = "0.3.21", features = ["thread-pool"]} sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } sp-core = { version = "7.0.0", path = "../../../primitives/core" } diff --git a/bin/node-template/node/src/benchmarking.rs b/bin/node-template/node/src/benchmarking.rs index 90fe06edf04b8..480e547c9c73c 100644 --- a/bin/node-template/node/src/benchmarking.rs +++ b/bin/node-template/node/src/benchmarking.rs @@ -176,8 +176,7 @@ pub fn inherent_benchmark_data() -> Result { let d = Duration::from_millis(0); let timestamp = sp_timestamp::InherentDataProvider::new(d.into()); - timestamp - .provide_inherent_data(&mut inherent_data) + futures::executor::block_on(timestamp.provide_inherent_data(&mut inherent_data)) .map_err(|e| format!("creating inherent data: {:?}", e))?; Ok(inherent_data) } diff --git a/bin/node/bench/src/construct.rs b/bin/node/bench/src/construct.rs index 50b9db9f019d1..2e20a7acb1e38 100644 --- a/bin/node/bench/src/construct.rs +++ b/bin/node/bench/src/construct.rs @@ -150,8 +150,10 @@ impl core::Benchmark for ConstructionBenchmark { ) .expect("Proposer initialization failed"); + let inherent_data = futures::executor::block_on(timestamp_provider.create_inherent_data()) + .expect("Create inherent data failed"); let _block = futures::executor::block_on(proposer.propose( - timestamp_provider.create_inherent_data().expect("Create inherent data failed"), + inherent_data, Default::default(), std::time::Duration::from_secs(20), None, diff --git a/bin/node/cli/src/benchmarking.rs b/bin/node/cli/src/benchmarking.rs index 19bd1660a4dd9..16ea9109d0c1f 100644 --- a/bin/node/cli/src/benchmarking.rs +++ b/bin/node/cli/src/benchmarking.rs @@ -116,8 +116,7 @@ pub fn inherent_benchmark_data() -> Result { let d = Duration::from_millis(0); let timestamp = sp_timestamp::InherentDataProvider::new(d.into()); - timestamp - .provide_inherent_data(&mut inherent_data) + futures::executor::block_on(timestamp.provide_inherent_data(&mut inherent_data)) .map_err(|e| format!("creating inherent data: {:?}", e))?; Ok(inherent_data) } diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 6c29f0c08ee13..e7b825a8e5ef1 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -692,14 +692,16 @@ mod tests { slot += 1; }; - let inherent_data = ( - sp_timestamp::InherentDataProvider::new( - std::time::Duration::from_millis(SLOT_DURATION * slot).into(), - ), - sp_consensus_babe::inherents::InherentDataProvider::new(slot.into()), + let inherent_data = futures::executor::block_on( + ( + sp_timestamp::InherentDataProvider::new( + std::time::Duration::from_millis(SLOT_DURATION * slot).into(), + ), + sp_consensus_babe::inherents::InherentDataProvider::new(slot.into()), + ) + .create_inherent_data(), ) - .create_inherent_data() - .expect("Creates inherent data"); + .expect("Creates inherent data"); digest.push(::babe_pre_digest(babe_pre_digest)); diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index b17feae45897e..07f982542c95b 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -203,6 +203,7 @@ where let mut inherent_data = create_inherent_data_providers .create_inherent_data() + .await .map_err(Error::::Inherent)?; let slot_now = create_inherent_data_providers.slot(); diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 50a02726cf56a..839965a556e04 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -216,7 +216,7 @@ where PF::Proposer: Proposer>, SO: SyncOracle + Send + Sync + Clone, L: sc_consensus::JustificationSyncLink, - CIDP: CreateInherentDataProviders + Send, + CIDP: CreateInherentDataProviders + Send + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send, BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, Error: std::error::Error + Send + From + 'static, @@ -960,7 +960,7 @@ mod tests { let res = executor::block_on(worker.on_slot(SlotInfo { slot: 0.into(), ends_at: Instant::now() + Duration::from_secs(100), - inherent_data: InherentData::new(), + create_inherent_data: Box::new(()), duration: Duration::from_millis(1000), chain_head: head, block_size_limit: None, diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 4cb300b9bcd04..84b6893648f49 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1215,6 +1215,7 @@ where // timestamp in the inherents actually matches the slot set in the seal. let mut inherent_data = create_inherent_data_providers .create_inherent_data() + .await .map_err(Error::::CreateInherents)?; inherent_data.babe_replace_inherent_data(slot); diff --git a/client/consensus/manual-seal/src/consensus/timestamp.rs b/client/consensus/manual-seal/src/consensus/timestamp.rs index f899b80d6c9af..2cb9887a81f40 100644 --- a/client/consensus/manual-seal/src/consensus/timestamp.rs +++ b/client/consensus/manual-seal/src/consensus/timestamp.rs @@ -141,7 +141,7 @@ impl SlotTimestampProvider { #[async_trait::async_trait] impl InherentDataProvider for SlotTimestampProvider { - fn provide_inherent_data( + async fn provide_inherent_data( &self, inherent_data: &mut InherentData, ) -> Result<(), sp_inherents::Error> { diff --git a/client/consensus/manual-seal/src/seal_block.rs b/client/consensus/manual-seal/src/seal_block.rs index 32e3acf68506e..25c091bf460ec 100644 --- a/client/consensus/manual-seal/src/seal_block.rs +++ b/client/consensus/manual-seal/src/seal_block.rs @@ -113,7 +113,7 @@ pub async fn seal_block( .await .map_err(|e| Error::Other(e))?; - let inherent_data = inherent_data_providers.create_inherent_data()?; + let inherent_data = inherent_data_providers.create_inherent_data().await?; let proposer = env.init(&parent).map_err(|err| Error::StringError(err.to_string())).await?; let inherents_len = inherent_data.len(); diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index dcf069d617bab..ac7ce3b411333 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -275,6 +275,7 @@ where let inherent_data = inherent_data_providers .create_inherent_data() + .await .map_err(|e| Error::CreateInherents(e))?; let inherent_res = self @@ -585,7 +586,7 @@ where }, }; - let inherent_data = match inherent_data_providers.create_inherent_data() { + let inherent_data = match inherent_data_providers.create_inherent_data().await { Ok(r) => r, Err(e) => { warn!( diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 90bfef6c1609c..bc68797dc734e 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -42,7 +42,11 @@ use sp_consensus::{Proposal, Proposer, SelectChain, SyncOracle}; use sp_consensus_slots::{Slot, SlotDuration}; use sp_inherents::CreateInherentDataProviders; use sp_runtime::traits::{Block as BlockT, HashFor, Header as HeaderT}; -use std::{fmt::Debug, ops::Deref, time::Duration}; +use std::{ + fmt::Debug, + ops::Deref, + time::{Duration, Instant}, +}; /// The changes that need to applied to the storage to create the state for a block. /// @@ -195,6 +199,9 @@ pub trait SimpleSlotWorker { let slot = slot_info.slot; let telemetry = self.telemetry(); let logging_target = self.logging_target(); + + let inherent_data = Self::create_inherent_data(&slot_info, &logging_target).await?; + let proposing_remaining_duration = self.proposing_remaining_duration(&slot_info); let logs = self.pre_digest_data(slot, claim); @@ -203,7 +210,7 @@ pub trait SimpleSlotWorker { // the result to be returned. let proposing = proposer .propose( - slot_info.inherent_data, + inherent_data, sp_runtime::generic::Digest { logs }, proposing_remaining_duration.mul_f32(0.98), None, @@ -242,6 +249,41 @@ pub trait SimpleSlotWorker { Some(proposal) } + /// Calls `create_inherent_data` and handles errors. + async fn create_inherent_data( + slot_info: &SlotInfo, + logging_target: &str, + ) -> Option { + let remaining_duration = slot_info.ends_at.saturating_duration_since(Instant::now()); + let delay = Delay::new(remaining_duration); + let cid = slot_info.create_inherent_data.create_inherent_data(); + let inherent_data = match futures::future::select(delay, cid).await { + Either::Right((Ok(data), _)) => data, + Either::Right((Err(err), _)) => { + warn!( + target: logging_target, + "Unable to create inherent data for block {:?}: {}", + slot_info.chain_head.hash(), + err, + ); + + return None + }, + Either::Left(_) => { + warn!( + target: logging_target, + "Creating inherent data took more time than we had left for slot {} for block {:?}.", + slot_info.slot, + slot_info.chain_head.hash(), + ); + + return None + }, + }; + + Some(inherent_data) + } + /// Implements [`SlotWorker::on_slot`]. async fn on_slot( &mut self, @@ -474,7 +516,7 @@ pub async fn start_slot_worker( C: SelectChain, W: SlotWorker, SO: SyncOracle + Send, - CIDP: CreateInherentDataProviders + Send, + CIDP: CreateInherentDataProviders + Send + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send, { let mut slots = Slots::new(slot_duration.as_duration(), create_inherent_data_providers, client); @@ -786,7 +828,7 @@ mod test { super::slots::SlotInfo { slot: slot.into(), duration: SLOT_DURATION, - inherent_data: Default::default(), + create_inherent_data: Box::new(()), ends_at: Instant::now() + SLOT_DURATION, chain_head: Header::new( 1, diff --git a/client/consensus/slots/src/slots.rs b/client/consensus/slots/src/slots.rs index f3dc485a8e819..f8f366d89c82c 100644 --- a/client/consensus/slots/src/slots.rs +++ b/client/consensus/slots/src/slots.rs @@ -22,7 +22,7 @@ use super::{InherentDataProviderExt, Slot}; use sp_consensus::{Error, SelectChain}; -use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider}; +use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use futures_timer::Delay; @@ -52,8 +52,8 @@ pub struct SlotInfo { pub slot: Slot, /// The instant at which the slot ends. pub ends_at: Instant, - /// The inherent data. - pub inherent_data: InherentData, + /// The inherent data provider. + pub create_inherent_data: Box, /// Slot duration. pub duration: Duration, /// The chain header this slot is based on. @@ -70,14 +70,14 @@ impl SlotInfo { /// `ends_at` is calculated using `timestamp` and `duration`. pub fn new( slot: Slot, - inherent_data: InherentData, + create_inherent_data: Box, duration: Duration, chain_head: B::Header, block_size_limit: Option, ) -> Self { Self { slot, - inherent_data, + create_inherent_data, duration, chain_head, block_size_limit, @@ -118,7 +118,7 @@ impl Slots where Block: BlockT, SC: SelectChain, - IDP: CreateInherentDataProviders, + IDP: CreateInherentDataProviders + 'static, IDP::InherentDataProviders: crate::InherentDataProviderExt, { /// Returns a future that fires when the next slot starts. @@ -142,9 +142,6 @@ where // reschedule delay for next slot. self.inner_delay = Some(Delay::new(ends_in)); - - let ends_at = Instant::now() + ends_in; - let chain_head = match self.select_chain.best_chain().await { Ok(x) => x, Err(e) => { @@ -164,21 +161,19 @@ where .create_inherent_data_providers(chain_head.hash(), ()) .await?; - if Instant::now() > ends_at { - log::warn!( - target: "slots", - "Creating inherent data providers took more time than we had left for the slot.", - ); - } - let slot = inherent_data_providers.slot(); - let inherent_data = inherent_data_providers.create_inherent_data()?; // never yield the same slot twice. if slot > self.last_slot { self.last_slot = slot; - break Ok(SlotInfo::new(slot, inherent_data, self.slot_duration, chain_head, None)) + break Ok(SlotInfo::new( + slot, + Box::new(inherent_data_providers), + self.slot_duration, + chain_head, + None, + )) } } } diff --git a/primitives/authorship/src/lib.rs b/primitives/authorship/src/lib.rs index 7ea19d9ea5ff5..6ff6607a896cc 100644 --- a/primitives/authorship/src/lib.rs +++ b/primitives/authorship/src/lib.rs @@ -81,7 +81,7 @@ impl InherentDataProvider { #[cfg(feature = "std")] #[async_trait::async_trait] impl sp_inherents::InherentDataProvider for InherentDataProvider { - fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { + async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { inherent_data.put_data(INHERENT_IDENTIFIER, &self.uncles) } diff --git a/primitives/consensus/aura/src/inherents.rs b/primitives/consensus/aura/src/inherents.rs index ce3d832c78ee9..135ae2660b32f 100644 --- a/primitives/consensus/aura/src/inherents.rs +++ b/primitives/consensus/aura/src/inherents.rs @@ -80,7 +80,7 @@ impl sp_std::ops::Deref for InherentDataProvider { #[cfg(feature = "std")] #[async_trait::async_trait] impl sp_inherents::InherentDataProvider for InherentDataProvider { - fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { + async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { inherent_data.put_data(INHERENT_IDENTIFIER, &self.slot) } diff --git a/primitives/consensus/babe/src/inherents.rs b/primitives/consensus/babe/src/inherents.rs index c26dc514ae158..2634507968f8e 100644 --- a/primitives/consensus/babe/src/inherents.rs +++ b/primitives/consensus/babe/src/inherents.rs @@ -86,7 +86,7 @@ impl sp_std::ops::Deref for InherentDataProvider { #[cfg(feature = "std")] #[async_trait::async_trait] impl sp_inherents::InherentDataProvider for InherentDataProvider { - fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { + async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { inherent_data.put_data(INHERENT_IDENTIFIER, &self.slot) } diff --git a/primitives/inherents/src/client_side.rs b/primitives/inherents/src/client_side.rs index 42068e24e029c..1ece7e1e4dea3 100644 --- a/primitives/inherents/src/client_side.rs +++ b/primitives/inherents/src/client_side.rs @@ -83,16 +83,16 @@ pub trait InherentDataProvider: Send + Sync { /// Convenience function for creating [`InherentData`]. /// /// Basically maps around [`Self::provide_inherent_data`]. - fn create_inherent_data(&self) -> Result { + async fn create_inherent_data(&self) -> Result { let mut inherent_data = InherentData::new(); - self.provide_inherent_data(&mut inherent_data)?; + self.provide_inherent_data(&mut inherent_data).await?; Ok(inherent_data) } /// Provide inherent data that should be included in a block. /// /// The data should be stored in the given `InherentData` structure. - fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error>; + async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error>; /// Convert the given encoded error to a string. /// @@ -108,8 +108,8 @@ pub trait InherentDataProvider: Send + Sync { #[async_trait::async_trait] impl InherentDataProvider for Tuple { for_tuples!( where #( Tuple: Send + Sync )* ); - fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { - for_tuples!( #( Tuple.provide_inherent_data(inherent_data)?; )* ); + async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { + for_tuples!( #( Tuple.provide_inherent_data(inherent_data).await?; )* ); Ok(()) } diff --git a/primitives/inherents/src/lib.rs b/primitives/inherents/src/lib.rs index a3ef963c47b39..59db5ef3e8802 100644 --- a/primitives/inherents/src/lib.rs +++ b/primitives/inherents/src/lib.rs @@ -56,7 +56,7 @@ //! //! #[async_trait::async_trait] //! impl sp_inherents::InherentDataProvider for InherentDataProvider { -//! fn provide_inherent_data( +//! async fn provide_inherent_data( //! &self, //! inherent_data: &mut InherentData, //! ) -> Result<(), sp_inherents::Error> { @@ -106,7 +106,7 @@ //! # struct InherentDataProvider; //! # #[async_trait::async_trait] //! # impl sp_inherents::InherentDataProvider for InherentDataProvider { -//! # fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), sp_inherents::Error> { +//! # async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), sp_inherents::Error> { //! # inherent_data.put_data(INHERENT_IDENTIFIER, &"hello") //! # } //! # async fn try_handle_error( @@ -443,7 +443,7 @@ mod tests { #[async_trait::async_trait] impl InherentDataProvider for TestInherentDataProvider { - fn provide_inherent_data(&self, data: &mut InherentData) -> Result<(), Error> { + async fn provide_inherent_data(&self, data: &mut InherentData) -> Result<(), Error> { data.put_data(TEST_INHERENT_0, &42) } @@ -460,7 +460,7 @@ mod tests { fn create_inherent_data() { let provider = TestInherentDataProvider; - let inherent_data = provider.create_inherent_data().unwrap(); + let inherent_data = futures::executor::block_on(provider.create_inherent_data()).unwrap(); assert_eq!(inherent_data.get_data::(&TEST_INHERENT_0).unwrap().unwrap(), 42u32); } diff --git a/primitives/timestamp/src/lib.rs b/primitives/timestamp/src/lib.rs index d88b1839babe6..14b06779340f2 100644 --- a/primitives/timestamp/src/lib.rs +++ b/primitives/timestamp/src/lib.rs @@ -228,7 +228,7 @@ impl sp_std::ops::Deref for InherentDataProvider { #[cfg(feature = "std")] #[async_trait::async_trait] impl sp_inherents::InherentDataProvider for InherentDataProvider { - fn provide_inherent_data( + async fn provide_inherent_data( &self, inherent_data: &mut InherentData, ) -> Result<(), sp_inherents::Error> { diff --git a/primitives/transaction-storage-proof/src/lib.rs b/primitives/transaction-storage-proof/src/lib.rs index fde84c1c58b1a..43928c83f21ed 100644 --- a/primitives/transaction-storage-proof/src/lib.rs +++ b/primitives/transaction-storage-proof/src/lib.rs @@ -87,7 +87,7 @@ impl InherentDataProvider { #[cfg(feature = "std")] #[async_trait::async_trait] impl sp_inherents::InherentDataProvider for InherentDataProvider { - fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { + async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { if let Some(proof) = &self.proof { inherent_data.put_data(INHERENT_IDENTIFIER, proof) } else { From c17c7d81b44c6ad44ea0b618cfceb5bc22fa6f80 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 2 Dec 2022 14:17:08 +0100 Subject: [PATCH 1425/1472] Fix quantization in referenda alarm (#12815) * Fix quantization in referenda alarm * Formatting * alarm interval, test (#12818) Co-authored-by: Muharem Ismailov --- frame/referenda/src/lib.rs | 24 ++++++------------------ frame/referenda/src/tests.rs | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index ba5f4aec956b1..742ad48963183 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -755,8 +755,11 @@ impl, I: 'static> Pallet { when: T::BlockNumber, ) -> Option<(T::BlockNumber, ScheduleAddressOf)> { let alarm_interval = T::AlarmInterval::get().max(One::one()); - let when = when.saturating_add(alarm_interval).saturating_sub(One::one()) / - (alarm_interval.saturating_mul(alarm_interval)).max(One::one()); + // Alarm must go off no earlier than `when`. + // This rounds `when` upwards to the next multiple of `alarm_interval`. + let when = (when.saturating_add(alarm_interval.saturating_sub(One::one())) / + alarm_interval) + .saturating_mul(alarm_interval); let maybe_result = T::Scheduler::schedule( DispatchTime::At(when), None, @@ -863,9 +866,6 @@ impl, I: 'static> Pallet { // Set an alarm call for the next block to nudge the track along. let now = frame_system::Pallet::::block_number(); let next_block = now + One::one(); - let alarm_interval = T::AlarmInterval::get().max(One::one()); - let when = (next_block + alarm_interval - One::one()) / alarm_interval * alarm_interval; - let call = match T::Preimages::bound(CallOf::::from(Call::one_fewer_deciding { track, })) { @@ -875,19 +875,7 @@ impl, I: 'static> Pallet { return }, }; - let maybe_result = T::Scheduler::schedule( - DispatchTime::At(when), - None, - 128u8, - frame_system::RawOrigin::Root.into(), - call, - ); - debug_assert!( - maybe_result.is_ok(), - "Unable to schedule a new alarm at #{:?} (now: #{:?})?!", - when, - now - ); + Self::set_alarm(call, next_block); } /// Ensure that a `service_referendum` alarm happens for the referendum `index` at `alarm`. diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index 355ce3021b87f..db67825210360 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -265,6 +265,27 @@ fn queueing_works() { }); } +#[test] +fn alarm_interval_works() { + new_test_ext().execute_with(|| { + let call = + ::Preimages::bound(CallOf::::from(Call::nudge_referendum { + index: 0, + })) + .unwrap(); + for n in 0..10 { + let interval = n * n; + let now = 100 * (interval + 1); + System::set_block_number(now); + AlarmInterval::set(interval); + let when = now + 1; + let (actual, _) = Referenda::set_alarm(call.clone(), when).unwrap(); + assert!(actual >= when); + assert!(actual - interval <= when); + } + }); +} + #[test] fn auto_timeout_should_happen_with_nothing_but_submit() { new_test_ext().execute_with(|| { From 34900ca6f85ed74be7c49958860bc43cb4d03753 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 2 Dec 2022 20:14:21 +0000 Subject: [PATCH 1426/1472] Add `Weightless` benchmark bailing (#12829) * Calls can be 'Weightless' Signed-off-by: Oliver Tale-Yazdi * Fix (child)-bounties benches Signed-off-by: Oliver Tale-Yazdi * Just use one dummy value Signed-off-by: Oliver Tale-Yazdi * :facepalm: Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/benchmarking/src/lib.rs | 26 ++++++++++++++++++++++++ frame/benchmarking/src/utils.rs | 6 ++++++ frame/bounties/src/benchmarking.rs | 21 ++++++++++--------- frame/child-bounties/src/benchmarking.rs | 10 +++++---- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index a221eccb82c85..29fa0b6a6af70 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -881,6 +881,13 @@ macro_rules! impl_bench_name_tests { "WARNING: benchmark error skipped - {}", stringify!($name), ); + }, + $crate::BenchmarkError::Weightless => { + // This is considered a success condition. + $crate::log::error!( + "WARNING: benchmark weightless skipped - {}", + stringify!($name), + ); } } }, @@ -1640,6 +1647,14 @@ macro_rules! impl_test_function { .expect("benchmark name is always a valid string!"), ); } + $crate::BenchmarkError::Weightless => { + // This is considered a success condition. + $crate::log::error!( + "WARNING: benchmark weightless skipped - {}", + $crate::str::from_utf8(benchmark_name) + .expect("benchmark name is always a valid string!"), + ); + } } }, Ok(Ok(())) => (), @@ -1792,6 +1807,17 @@ macro_rules! add_benchmark { .expect("benchmark name is always a valid string!") ); None + }, + Err($crate::BenchmarkError::Weightless) => { + $crate::log::error!( + "WARNING: benchmark weightless skipped - {}", + $crate::str::from_utf8(benchmark) + .expect("benchmark name is always a valid string!") + ); + Some(vec![$crate::BenchmarkResult { + components: selected_components.clone(), + .. Default::default() + }]) } }; diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index 753e8c1c684ee..654b1c34c0658 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -162,6 +162,11 @@ pub enum BenchmarkError { /// The benchmarking pipeline is allowed to fail here, and we should simply /// skip processing these results. Skip, + /// No weight can be determined; set the weight of this call to zero. + /// + /// You can also use `Override` instead, but this is easier to use since `Override` expects the + /// correct components to be present. + Weightless, } impl From for &'static str { @@ -170,6 +175,7 @@ impl From for &'static str { BenchmarkError::Stop(s) => s, BenchmarkError::Override(_) => "benchmark override", BenchmarkError::Skip => "benchmark skip", + BenchmarkError::Weightless => "benchmark weightless", } } } diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 84f5665d402a1..adadb3411ac65 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -31,13 +31,14 @@ use pallet_treasury::Pallet as Treasury; const SEED: u32 = 0; // Create bounties that are approved for use in `on_initialize`. -fn create_approved_bounties, I: 'static>(n: u32) -> Result<(), &'static str> { +fn create_approved_bounties, I: 'static>(n: u32) -> Result<(), BenchmarkError> { for i in 0..n { let (caller, _curator, _fee, value, reason) = setup_bounty::(i, T::MaximumReasonLength::get()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = + T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; Bounties::::approve_bounty(approve_origin, bounty_id)?; } ensure!(BountyApprovals::::get().len() == n as usize, "Not all bounty approved"); @@ -62,13 +63,14 @@ fn setup_bounty, I: 'static>( } fn create_bounty, I: 'static>( -) -> Result<(AccountIdLookupOf, BountyIndex), &'static str> { +) -> Result<(AccountIdLookupOf, BountyIndex), BenchmarkError> { let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = + T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; Bounties::::approve_bounty(approve_origin.clone(), bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); Bounties::::propose_curator(approve_origin, bounty_id, curator_lookup.clone(), fee)?; @@ -97,7 +99,7 @@ benchmarks_instance_pallet! { let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::SpendOrigin::successful_origin(); + let approve_origin = T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(approve_origin, bounty_id) propose_curator { @@ -106,10 +108,9 @@ benchmarks_instance_pallet! { let curator_lookup = T::Lookup::unlookup(curator); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::SpendOrigin::successful_origin(); - Bounties::::approve_bounty(approve_origin, bounty_id)?; + let approve_origin = T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + Bounties::::approve_bounty(approve_origin.clone(), bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); - let approve_origin = T::SpendOrigin::successful_origin(); }: _(approve_origin, bounty_id, curator_lookup, fee) // Worst case when curator is inactive and any sender unassigns the curator. @@ -128,7 +129,7 @@ benchmarks_instance_pallet! { let curator_lookup = T::Lookup::unlookup(curator.clone()); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::SpendOrigin::successful_origin(); + let approve_origin = T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; Bounties::::approve_bounty(approve_origin.clone(), bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); Bounties::::propose_curator(approve_origin, bounty_id, curator_lookup, fee)?; diff --git a/frame/child-bounties/src/benchmarking.rs b/frame/child-bounties/src/benchmarking.rs index 697ed40e0071f..04a8583f286f1 100644 --- a/frame/child-bounties/src/benchmarking.rs +++ b/frame/child-bounties/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::{account, benchmarks, whitelisted_caller, BenchmarkError}; use frame_system::RawOrigin; use crate::Pallet as ChildBounties; @@ -94,7 +94,7 @@ fn setup_child_bounty(user: u32, description: u32) -> BenchmarkChildB fn activate_bounty( user: u32, description: u32, -) -> Result, &'static str> { +) -> Result, BenchmarkError> { let mut child_bounty_setup = setup_child_bounty::(user, description); let curator_lookup = T::Lookup::unlookup(child_bounty_setup.curator.clone()); Bounties::::propose_bounty( @@ -105,7 +105,9 @@ fn activate_bounty( child_bounty_setup.bounty_id = Bounties::::bounty_count() - 1; - Bounties::::approve_bounty(RawOrigin::Root.into(), child_bounty_setup.bounty_id)?; + let approve_origin = + T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + Bounties::::approve_bounty(approve_origin, child_bounty_setup.bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); Bounties::::propose_curator( RawOrigin::Root.into(), @@ -124,7 +126,7 @@ fn activate_bounty( fn activate_child_bounty( user: u32, description: u32, -) -> Result, &'static str> { +) -> Result, BenchmarkError> { let mut bounty_setup = activate_bounty::(user, description)?; let child_curator_lookup = T::Lookup::unlookup(bounty_setup.child_curator.clone()); From 9812205cb216f9c3598d733f63c0f882136b8004 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sat, 3 Dec 2022 09:14:47 +0100 Subject: [PATCH 1427/1472] API for registering inactive funds (#12813) * API for registering inactive funds * Build fixes. * Update frame/treasury/src/lib.rs * Fix * Fixes * Fixes --- frame/balances/src/lib.rs | 33 ++++++++++++- frame/balances/src/migration.rs | 51 ++++++++++++++++++++ frame/support/src/traits/tokens/currency.rs | 21 ++++++++ frame/support/src/traits/tokens/fungible.rs | 21 ++++++++ frame/support/src/traits/tokens/fungibles.rs | 12 +++++ frame/treasury/src/lib.rs | 14 ++++++ 6 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 frame/balances/src/migration.rs diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index d3085152eba6c..c4a8456c22c67 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -156,6 +156,7 @@ #[macro_use] mod tests; mod benchmarking; +pub mod migration; mod tests_composite; mod tests_local; #[cfg(test)] @@ -497,6 +498,13 @@ pub mod pallet { #[pallet::whitelist_storage] pub type TotalIssuance, I: 'static = ()> = StorageValue<_, T::Balance, ValueQuery>; + /// The total units of outstanding deactivated balance in the system. + #[pallet::storage] + #[pallet::getter(fn inactive_issuance)] + #[pallet::whitelist_storage] + pub type InactiveIssuance, I: 'static = ()> = + StorageValue<_, T::Balance, ValueQuery>; + /// The Balances pallet example of storing the balance of an account. /// /// # Example @@ -1067,6 +1075,9 @@ impl, I: 'static> fungible::Inspect for Pallet fn total_issuance() -> Self::Balance { TotalIssuance::::get() } + fn active_issuance() -> Self::Balance { + TotalIssuance::::get().saturating_sub(InactiveIssuance::::get()) + } fn minimum_balance() -> Self::Balance { T::ExistentialDeposit::get() } @@ -1145,6 +1156,14 @@ impl, I: 'static> fungible::Transfer for Pallet let er = if keep_alive { KeepAlive } else { AllowDeath }; >::transfer(source, dest, amount, er).map(|_| amount) } + + fn deactivate(amount: Self::Balance) { + InactiveIssuance::::mutate(|b| b.saturating_accrue(amount)); + } + + fn reactivate(amount: Self::Balance) { + InactiveIssuance::::mutate(|b| b.saturating_reduce(amount)); + } } impl, I: 'static> fungible::Unbalanced for Pallet { @@ -1418,7 +1437,19 @@ where } fn total_issuance() -> Self::Balance { - >::get() + TotalIssuance::::get() + } + + fn active_issuance() -> Self::Balance { + >::active_issuance() + } + + fn deactivate(amount: Self::Balance) { + >::deactivate(amount); + } + + fn reactivate(amount: Self::Balance) { + >::reactivate(amount); } fn minimum_balance() -> Self::Balance { diff --git a/frame/balances/src/migration.rs b/frame/balances/src/migration.rs new file mode 100644 index 0000000000000..e27efc217407a --- /dev/null +++ b/frame/balances/src/migration.rs @@ -0,0 +1,51 @@ +// Copyright 2017-2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use super::*; +use frame_support::{pallet_prelude::*, traits::OnRuntimeUpgrade, weights::Weight}; + +// NOTE: This must be used alongside the account whose balance is expected to be inactive. +// Generally this will be used for the XCM teleport checking account. +pub struct MigrateToTrackInactive>( + sp_std::marker::PhantomData<(T, A)>, +); +impl> OnRuntimeUpgrade for MigrateToTrackInactive { + fn on_runtime_upgrade() -> Weight { + let current_version = Pallet::::current_storage_version(); + let onchain_version = Pallet::::on_chain_storage_version(); + + if onchain_version == 0 && current_version == 1 { + let b = Pallet::::total_balance(&A::get()); + Pallet::::deactivate(b); + current_version.put::>(); + log::info!(target: "runtime::balances", "Storage to version {:?}", current_version); + T::DbWeight::get().reads_writes(3, 3) + } else { + log::info!(target: "runtime::balances", "Migration did not execute. This probably should be removed"); + T::DbWeight::get().reads(2) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + Ok(vec![]) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(total: Vec) -> Result<(), &'static str> { + Ok(()) + } +} diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index d0beb66d34923..48247b6021798 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -59,6 +59,18 @@ pub trait Currency { /// The total amount of issuance in the system. fn total_issuance() -> Self::Balance; + /// The total amount of issuance in the system excluding those which are controlled by the + /// system. + fn active_issuance() -> Self::Balance { + Self::total_issuance() + } + + /// Reduce the active issuance by some amount. + fn deactivate(_: Self::Balance) {} + + /// Increase the active issuance by some amount, up to the outstanding amount reduced. + fn reactivate(_: Self::Balance) {} + /// The minimum balance any single account may have. This is equivalent to the `Balances` /// module's `ExistentialDeposit`. fn minimum_balance() -> Self::Balance; @@ -212,6 +224,15 @@ impl, A> Get for TotalIssuanceOf { } } +/// A non-const `Get` implementation parameterised by a `Currency` impl which provides the result +/// of `active_issuance`. +pub struct ActiveIssuanceOf, A>(sp_std::marker::PhantomData<(C, A)>); +impl, A> Get for ActiveIssuanceOf { + fn get() -> C::Balance { + C::active_issuance() + } +} + #[cfg(feature = "std")] impl Currency for () { type Balance = u32; diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs index 90aadb6d8daa6..7b1ec0f434382 100644 --- a/frame/support/src/traits/tokens/fungible.rs +++ b/frame/support/src/traits/tokens/fungible.rs @@ -40,6 +40,12 @@ pub trait Inspect { /// The total amount of issuance in the system. fn total_issuance() -> Self::Balance; + /// The total amount of issuance in the system excluding those which are controlled by the + /// system. + fn active_issuance() -> Self::Balance { + Self::total_issuance() + } + /// The minimum balance any single account may have. fn minimum_balance() -> Self::Balance; @@ -120,6 +126,12 @@ pub trait Transfer: Inspect { amount: Self::Balance, keep_alive: bool, ) -> Result; + + /// Reduce the active issuance by some amount. + fn deactivate(_: Self::Balance) {} + + /// Increase the active issuance by some amount, up to the outstanding amount reduced. + fn reactivate(_: Self::Balance) {} } /// Trait for inspecting a fungible asset which can be reserved. @@ -213,6 +225,9 @@ impl< fn total_issuance() -> Self::Balance { >::total_issuance(A::get()) } + fn active_issuance() -> Self::Balance { + >::active_issuance(A::get()) + } fn minimum_balance() -> Self::Balance { >::minimum_balance(A::get()) } @@ -258,6 +273,12 @@ impl< ) -> Result { >::transfer(A::get(), source, dest, amount, keep_alive) } + fn deactivate(amount: Self::Balance) { + >::deactivate(A::get(), amount) + } + fn reactivate(amount: Self::Balance) { + >::reactivate(A::get(), amount) + } } impl< diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 8c370e9a0d8b5..0743e3031c467 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -46,6 +46,12 @@ pub trait Inspect { /// The total amount of issuance in the system. fn total_issuance(asset: Self::AssetId) -> Self::Balance; + /// The total amount of issuance in the system excluding those which are controlled by the + /// system. + fn active_issuance(asset: Self::AssetId) -> Self::Balance { + Self::total_issuance(asset) + } + /// The minimum balance any single account may have. fn minimum_balance(asset: Self::AssetId) -> Self::Balance; @@ -177,6 +183,12 @@ pub trait Transfer: Inspect { amount: Self::Balance, keep_alive: bool, ) -> Result; + + /// Reduce the active issuance by some amount. + fn deactivate(_: Self::AssetId, _: Self::Balance) {} + + /// Increase the active issuance by some amount, up to the outstanding amount reduced. + fn reactivate(_: Self::AssetId, _: Self::Balance) {} } /// Trait for inspecting a set of named fungible assets which can be placed on hold. diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 21b4d2b769c8b..4aa00c348585c 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -223,6 +223,10 @@ pub mod pallet { OptionQuery, >; + /// The amount which has been reported as inactive to Currency. + #[pallet::storage] + pub type Inactive, I: 'static = ()> = StorageValue<_, BalanceOf, ValueQuery>; + /// Proposal indices that have been approved but not yet awarded. #[pallet::storage] #[pallet::getter(fn approvals)] @@ -316,6 +320,16 @@ pub mod pallet { /// - The weight is overestimated if some approvals got missed. /// # fn on_initialize(n: T::BlockNumber) -> Weight { + let pot = Self::pot(); + let deactivated = Inactive::::get(); + if pot != deactivated { + match (pot > deactivated, pot.max(deactivated) - pot.min(deactivated)) { + (true, delta) => T::Currency::deactivate(delta), + (false, delta) => T::Currency::reactivate(delta), + } + Inactive::::put(&pot); + } + // Check to see if we should spend some funds! if (n % T::SpendPeriod::get()).is_zero() { Self::spend_funds() From 1a0af36d211eda7eb118f7c83070eb3364396bf4 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sat, 3 Dec 2022 16:36:25 +0000 Subject: [PATCH 1428/1472] Tweak to active total migrations (#12832) * Tweak to active total migrations * Formatting * Expose trait * Remove empty pre_ and post_upgrade hooks. Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/balances/src/migration.rs | 35 ++++++++++++++++++++++----------- frame/support/src/traits.rs | 4 ++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/frame/balances/src/migration.rs b/frame/balances/src/migration.rs index e27efc217407a..1dd3e6f51f1be 100644 --- a/frame/balances/src/migration.rs +++ b/frame/balances/src/migration.rs @@ -19,9 +19,7 @@ use frame_support::{pallet_prelude::*, traits::OnRuntimeUpgrade, weights::Weight // NOTE: This must be used alongside the account whose balance is expected to be inactive. // Generally this will be used for the XCM teleport checking account. -pub struct MigrateToTrackInactive>( - sp_std::marker::PhantomData<(T, A)>, -); +pub struct MigrateToTrackInactive(PhantomData<(T, A)>); impl> OnRuntimeUpgrade for MigrateToTrackInactive { fn on_runtime_upgrade() -> Weight { let current_version = Pallet::::current_storage_version(); @@ -32,20 +30,35 @@ impl> OnRuntimeUpgrade for MigrateToTrackInactiv Pallet::::deactivate(b); current_version.put::>(); log::info!(target: "runtime::balances", "Storage to version {:?}", current_version); - T::DbWeight::get().reads_writes(3, 3) + T::DbWeight::get().reads_writes(4, 3) } else { log::info!(target: "runtime::balances", "Migration did not execute. This probably should be removed"); T::DbWeight::get().reads(2) } } +} - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - Ok(vec![]) - } +// NOTE: This must be used alongside the account whose balance is expected to be inactive. +// Generally this will be used for the XCM teleport checking account. +pub struct MigrateManyToTrackInactive(PhantomData<(T, A)>); +impl>> OnRuntimeUpgrade for MigrateManyToTrackInactive { + fn on_runtime_upgrade() -> Weight { + let current_version = Pallet::::current_storage_version(); + let onchain_version = Pallet::::on_chain_storage_version(); - #[cfg(feature = "try-runtime")] - fn post_upgrade(total: Vec) -> Result<(), &'static str> { - Ok(()) + if onchain_version == 0 && current_version == 1 { + let accounts = A::get(); + let total = accounts + .iter() + .map(|a| Pallet::::total_balance(a)) + .fold(T::Balance::zero(), |a, e| a.saturating_add(e)); + Pallet::::deactivate(total); + current_version.put::>(); + log::info!(target: "runtime::balances", "Storage to version {:?}", current_version); + T::DbWeight::get().reads_writes(3 + accounts.len() as u64, 3) + } else { + log::info!(target: "runtime::balances", "Migration did not execute. This probably should be removed"); + T::DbWeight::get().reads(2) + } } } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index f09b715a970ad..9b5300dfc5739 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -22,8 +22,8 @@ pub mod tokens; pub use tokens::{ currency::{ - Currency, LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency, - TotalIssuanceOf, VestingSchedule, + ActiveIssuanceOf, Currency, LockIdentifier, LockableCurrency, NamedReservableCurrency, + ReservableCurrency, TotalIssuanceOf, VestingSchedule, }, fungible, fungibles, imbalance::{Imbalance, OnUnbalanced, SignedImbalance}, From cb3eaf26d4858398621948fb77086c33a80cf5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 4 Dec 2022 20:40:38 +0100 Subject: [PATCH 1429/1472] frame-executive: Reject invalid inherents in the executive (#12365) * frame-executive: Reject invalid inherents in the executive We already had support for making a block fail if an inherent returned, but it was part of the signed extension `CheckWeight`. Rejecting blocks with invalid inherents should happen on the `frame-executive` level without requiring any special signed extension. This is crucial to prevent any kind of spamming of the network that could may happen with blocks that include failing inherents. * FMT * Update frame/executive/src/lib.rs Co-authored-by: Keith Yeung * Update primitives/runtime/src/transaction_validity.rs Co-authored-by: Keith Yeung Co-authored-by: parity-processbot <> Co-authored-by: Keith Yeung --- frame/executive/src/lib.rs | 51 ++++++++++++++++++- frame/support/src/dispatch.rs | 6 ++- frame/system/src/extensions/check_weight.rs | 20 ++------ .../runtime/src/transaction_validity.rs | 10 ++-- 4 files changed, 61 insertions(+), 26 deletions(-) diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index b7884efccf685..71f138b596b8d 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -119,6 +119,7 @@ use codec::{Codec, Encode}; use frame_support::{ dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, + pallet_prelude::InvalidTransaction, traits::{ EnsureInherentsAreFirst, ExecuteBlock, OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, @@ -497,6 +498,14 @@ where let dispatch_info = xt.get_dispatch_info(); let r = Applyable::apply::(xt, &dispatch_info, encoded_len)?; + // Mandatory(inherents) are not allowed to fail. + // + // The entire block should be discarded if an inherent fails to apply. Otherwise + // it may open an attack vector. + if r.is_err() && dispatch_info.class == DispatchClass::Mandatory { + return Err(InvalidTransaction::BadMandatory.into()) + } + >::note_applied_extrinsic(&r, dispatch_info); Ok(r.map(|_| ()).map_err(|e| e.error)) @@ -563,6 +572,10 @@ where xt.get_dispatch_info() }; + if dispatch_info.class == DispatchClass::Mandatory { + return Err(InvalidTransaction::MandatoryValidation.into()) + } + within_span! { sp_tracing::Level::TRACE, "validate"; xt.validate::(source, &dispatch_info, encoded_len) @@ -692,9 +705,9 @@ mod tests { Ok(()) } - #[pallet::weight(0)] + #[pallet::weight((0, DispatchClass::Mandatory))] pub fn inherent_call(origin: OriginFor) -> DispatchResult { - let _ = frame_system::ensure_none(origin)?; + frame_system::ensure_none(origin)?; Ok(()) } @@ -1533,4 +1546,38 @@ mod tests { Executive::execute_block(Block::new(header, vec![xt1, xt2])); }); } + + #[test] + #[should_panic(expected = "A call was labelled as mandatory, but resulted in an Error.")] + fn invalid_inherents_fail_block_execution() { + let xt1 = + TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), sign_extra(1, 0, 0)); + + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block::new( + Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + ), + vec![xt1], + )); + }); + } + + // Inherents are created by the runtime and don't need to be validated. + #[test] + fn inherents_fail_validate_block() { + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); + + new_test_ext(1).execute_with(|| { + assert_eq!( + Executive::validate_transaction(TransactionSource::External, xt1, H256::random()) + .unwrap_err(), + InvalidTransaction::MandatoryValidation.into() + ); + }) + } } diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index d497a672e2970..1696e9a63915e 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -359,13 +359,15 @@ where /// Implementation for test extrinsic. #[cfg(feature = "std")] -impl GetDispatchInfo for sp_runtime::testing::TestXt { +impl GetDispatchInfo + for sp_runtime::testing::TestXt +{ fn get_dispatch_info(&self) -> DispatchInfo { // for testing: weight == size. DispatchInfo { weight: Weight::from_ref_time(self.encode().len() as _), pays_fee: Pays::Yes, - ..Default::default() + class: self.call.get_dispatch_info().class, } } } diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index 5c3b80f59bfa8..757b2197bc238 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -18,7 +18,7 @@ use crate::{limits::BlockWeights, Config, Pallet}; use codec::{Decode, Encode}; use frame_support::{ - dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, + dispatch::{DispatchInfo, PostDispatchInfo}, traits::Get, }; use scale_info::TypeInfo; @@ -190,9 +190,6 @@ where info: &DispatchInfoOf, len: usize, ) -> Result<(), TransactionValidityError> { - if info.class == DispatchClass::Mandatory { - return Err(InvalidTransaction::MandatoryDispatch.into()) - } Self::do_pre_dispatch(info, len) } @@ -203,9 +200,6 @@ where info: &DispatchInfoOf, len: usize, ) -> TransactionValidity { - if info.class == DispatchClass::Mandatory { - return Err(InvalidTransaction::MandatoryDispatch.into()) - } Self::do_validate(info, len) } @@ -230,16 +224,8 @@ where info: &DispatchInfoOf, post_info: &PostDispatchInfoOf, _len: usize, - result: &DispatchResult, + _result: &DispatchResult, ) -> Result<(), TransactionValidityError> { - // Since mandatory dispatched do not get validated for being overweight, we are sensitive - // to them actually being useful. Block producers are thus not allowed to include mandatory - // extrinsics that result in error. - if let (DispatchClass::Mandatory, Err(e)) = (info.class, result) { - log::error!(target: "runtime::system", "Bad mandatory: {:?}", e); - return Err(InvalidTransaction::BadMandatory.into()) - } - let unspent = post_info.calc_unspent(info); if unspent.any_gt(Weight::zero()) { crate::BlockWeight::::mutate(|current_weight| { @@ -268,7 +254,7 @@ mod tests { use super::*; use crate::{ mock::{new_test_ext, System, Test, CALL}, - AllExtrinsicsLen, BlockWeight, + AllExtrinsicsLen, BlockWeight, DispatchClass, }; use frame_support::{assert_err, assert_ok, dispatch::Pays, weights::Weight}; use sp_std::marker::PhantomData; diff --git a/primitives/runtime/src/transaction_validity.rs b/primitives/runtime/src/transaction_validity.rs index 4646808b8c8e3..d8e71cc2761ec 100644 --- a/primitives/runtime/src/transaction_validity.rs +++ b/primitives/runtime/src/transaction_validity.rs @@ -77,9 +77,9 @@ pub enum InvalidTransaction { /// malicious validator or a buggy `provide_inherent`. In any case, it can result in /// dangerously overweight blocks and therefore if found, invalidates the block. BadMandatory, - /// A transaction with a mandatory dispatch. This is invalid; only inherent extrinsics are - /// allowed to have mandatory dispatches. - MandatoryDispatch, + /// An extrinsic with a mandatory dispatch tried to be validated. + /// This is invalid; only inherent extrinsics are allowed to have mandatory dispatches. + MandatoryValidation, /// The sending address is disabled or known to be invalid. BadSigner, } @@ -109,8 +109,8 @@ impl From for &'static str { "Inability to pay some fees (e.g. account balance too low)", InvalidTransaction::BadMandatory => "A call was labelled as mandatory, but resulted in an Error.", - InvalidTransaction::MandatoryDispatch => - "Transaction dispatch is mandatory; transactions may not have mandatory dispatches.", + InvalidTransaction::MandatoryValidation => + "Transaction dispatch is mandatory; transactions must not be validated.", InvalidTransaction::Custom(_) => "InvalidTransaction custom error", InvalidTransaction::BadSigner => "Invalid signing address", } From 2bde8c1a44d8e376e3e6e5d2dd7266124ff5efa2 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Mon, 5 Dec 2022 11:18:46 +0300 Subject: [PATCH 1430/1472] Upgrade tokio to 1.22.0 and replace async-std with tokio (#12646) * Replace deprecated libp2p feature specs with correct ones * Bump tokio to 1.21.2 * Replace async-std libp2p primitives with tokio ones * minor: rustfmt * Fix TestNet to run initialization in the tokio context * Convert telemetry test from async-std to tokio * Convert notifications tests from async-std to tokio * Convert chain sync tests from async-std to tokio * Ditch async-std completely * Make executor mandatory * Bump tokio to 1.22.0 * minor: rustfmt * Explicitly use tokio runtime in tests * Move more tests to explicit tokio runtime * Explicitly set multithreaded runtime in tokio test * minor: rustfmt * minor: fix comment * Replace async-std with tokio in MMR tests --- Cargo.lock | 150 ++-------- bin/node/cli/Cargo.toml | 4 +- bin/node/cli/tests/telemetry.rs | 6 +- bin/node/cli/tests/websocket_server.rs | 13 +- client/beefy/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/beefy/src/aux_schema.rs | 4 +- client/beefy/src/tests.rs | 88 ++++-- client/beefy/src/worker.rs | 21 +- client/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 1 + client/consensus/aura/src/lib.rs | 59 ++-- client/consensus/babe/Cargo.toml | 1 + client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/babe/src/tests.rs | 97 +++++-- client/consensus/manual-seal/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/finality-grandpa/src/tests.rs | 113 +++++--- client/merkle-mountain-range/Cargo.toml | 1 - client/merkle-mountain-range/src/lib.rs | 6 +- .../merkle-mountain-range/src/offchain_mmr.rs | 4 +- .../merkle-mountain-range/src/test_utils.rs | 26 +- client/network-gossip/Cargo.toml | 2 +- client/network-gossip/src/bridge.rs | 9 +- client/network/Cargo.toml | 5 +- client/network/bitswap/Cargo.toml | 2 +- client/network/src/config.rs | 5 +- client/network/src/discovery.rs | 6 +- .../notifications/upgrade/notifications.rs | 67 +++-- client/network/src/service.rs | 14 +- .../network/src/service/tests/chain_sync.rs | 43 ++- client/network/src/service/tests/mod.rs | 29 +- client/network/src/service/tests/service.rs | 102 ++++--- client/network/src/transport.rs | 10 +- client/network/sync/Cargo.toml | 2 +- client/network/sync/src/service/network.rs | 4 +- client/network/sync/src/tests.rs | 2 +- client/network/test/Cargo.toml | 2 +- client/network/test/src/lib.rs | 75 +++-- client/network/test/src/sync.rs | 265 ++++++++++-------- client/offchain/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 2 +- client/rpc-spec-v2/Cargo.toml | 2 +- client/rpc/Cargo.toml | 4 +- client/service/Cargo.toml | 3 +- client/service/src/builder.rs | 4 +- client/service/test/Cargo.toml | 2 +- client/service/test/src/lib.rs | 89 +++--- client/telemetry/Cargo.toml | 2 +- client/telemetry/src/transport.rs | 5 +- frame/state-trie-migration/Cargo.toml | 2 +- test-utils/Cargo.toml | 2 +- test-utils/test-crate/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/rpc/client/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- utils/prometheus/Cargo.toml | 4 +- 60 files changed, 750 insertions(+), 637 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6896d65f44c0a..64e8cfa82d251 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,16 +162,6 @@ 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", - "syn", -] - [[package]] name = "async-channel" version = "1.6.1" @@ -250,67 +240,6 @@ dependencies = [ "event-listener", ] -[[package]] -name = "async-process" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2c06e30a24e8c78a3987d07f0930edf76ef35e027e7bdb063fccafdad1f60c" -dependencies = [ - "async-io", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "libc", - "once_cell", - "signal-hook", - "winapi", -] - -[[package]] -name = "async-std" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52580991739c5cdb36cde8b2a516371c0a3b70dda36d916cc08b82372916808c" -dependencies = [ - "async-attributes", - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "num_cpus", - "once_cell", - "pin-project-lite 0.2.6", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-std-resolver" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba50e24d9ee0a8950d3d03fc6d0dd10aa14b5de3b101949b4e160f7fee7c723" -dependencies = [ - "async-std", - "async-trait", - "futures-io", - "futures-util", - "pin-utils", - "socket2", - "trust-dns-resolver", -] - [[package]] name = "async-stream" version = "0.3.2" @@ -381,9 +310,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" @@ -2755,19 +2684,6 @@ dependencies = [ "regex", ] -[[package]] -name = "gloo-timers" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "group" version = "0.12.0" @@ -3459,15 +3375,6 @@ dependencies = [ "substrate-wasm-builder", ] -[[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.12.0" @@ -3630,7 +3537,6 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2322c9fb40d99101def6a01612ee30500c89abbbecb6297b3cd252903a4c1720" dependencies = [ - "async-std-resolver", "futures", "libp2p-core", "log", @@ -3694,7 +3600,6 @@ version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "761704e727f7d68d58d7bc2231eafae5fc1b9814de24290f126df09d4bd37a15" dependencies = [ - "async-io", "data-encoding", "dns-parser", "futures", @@ -3705,6 +3610,7 @@ dependencies = [ "rand 0.8.5", "smallvec", "socket2", + "tokio", "void", ] @@ -3833,7 +3739,6 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9839d96761491c6d3e238e70554b856956fca0ab60feb9de2cd08eed4473fa92" dependencies = [ - "async-io", "futures", "futures-timer", "if-watch", @@ -3841,6 +3746,7 @@ dependencies = [ "libp2p-core", "log", "socket2", + "tokio", ] [[package]] @@ -4039,7 +3945,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", - "value-bag", ] [[package]] @@ -4234,7 +4139,6 @@ dependencies = [ name = "mmr-gadget" version = "4.0.0-dev" dependencies = [ - "async-std", "beefy-primitives", "futures", "log", @@ -4553,7 +4457,6 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "async-std", "clap 4.0.11", "clap_complete", "criterion", @@ -4628,6 +4531,7 @@ dependencies = [ "substrate-rpc-client", "tempfile", "tokio", + "tokio-util", "try-runtime-cli", "wait-timeout", ] @@ -7817,6 +7721,7 @@ dependencies = [ "substrate-test-runtime-client", "tempfile", "thiserror", + "tokio", ] [[package]] @@ -7865,6 +7770,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "thiserror", + "tokio", ] [[package]] @@ -8205,7 +8111,6 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "assert_matches", - "async-std", "async-trait", "asynchronous-codec", "bitflags", @@ -8250,6 +8155,8 @@ dependencies = [ "substrate-test-runtime-client", "tempfile", "thiserror", + "tokio", + "tokio-util", "unsigned-varint", "zeroize", ] @@ -8310,7 +8217,6 @@ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ "ahash", - "async-std", "futures", "futures-timer", "libp2p", @@ -8322,6 +8228,7 @@ dependencies = [ "sp-runtime", "substrate-prometheus-endpoint", "substrate-test-runtime-client", + "tokio", "tracing", ] @@ -8350,7 +8257,6 @@ name = "sc-network-sync" version = "0.10.0-dev" dependencies = [ "array-bytes", - "async-std", "async-trait", "fork-tree", "futures", @@ -8379,13 +8285,13 @@ dependencies = [ "sp-tracing", "substrate-test-runtime-client", "thiserror", + "tokio", ] [[package]] name = "sc-network-test" version = "0.8.0" dependencies = [ - "async-std", "async-trait", "futures", "futures-timer", @@ -8409,6 +8315,7 @@ dependencies = [ "sp-tracing", "substrate-test-runtime", "substrate-test-runtime-client", + "tokio", ] [[package]] @@ -8598,7 +8505,6 @@ dependencies = [ name = "sc-service" version = "0.10.0-dev" dependencies = [ - "async-std", "async-trait", "directories", "exit-future", @@ -9196,16 +9102,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" -[[package]] -name = "signal-hook" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" version = "1.3.0" @@ -10762,16 +10658,16 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" dependencies = [ + "autocfg", "bytes", "libc", "memchr", "mio", "num_cpus", - "once_cell", "parking_lot 0.12.1", "pin-project-lite 0.2.6", "signal-hook-registry", @@ -10828,9 +10724,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", @@ -11018,6 +10914,7 @@ dependencies = [ "smallvec", "thiserror", "tinyvec", + "tokio", "tracing", "url", ] @@ -11037,6 +10934,7 @@ dependencies = [ "resolv-conf", "smallvec", "thiserror", + "tokio", "tracing", "trust-dns-proto", ] @@ -11223,16 +11121,6 @@ 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.11" diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index d56764f9e2040..114d324aa1591 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -122,10 +122,10 @@ nix = "0.23" serde_json = "1.0" regex = "1.6.0" platforms = "2.0" -async-std = { version = "1.11.0", features = ["attributes"] } soketto = "0.7.1" criterion = { version = "0.3.5", features = ["async_tokio"] } -tokio = { version = "1.17.0", features = ["macros", "time", "parking_lot"] } +tokio = { version = "1.22.0", features = ["macros", "time", "parking_lot"] } +tokio-util = { version = "0.7.4", features = ["compat"] } wait-timeout = "0.2" substrate-rpc-client = { path = "../../../utils/frame/rpc/client" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } diff --git a/bin/node/cli/tests/telemetry.rs b/bin/node/cli/tests/telemetry.rs index bef4e4ea03048..98cf0b3af32b2 100644 --- a/bin/node/cli/tests/telemetry.rs +++ b/bin/node/cli/tests/telemetry.rs @@ -26,7 +26,7 @@ use std::process; pub mod common; pub mod websocket_server; -#[async_std::test] +#[tokio::test] async fn telemetry_works() { let config = websocket_server::Config { capacity: 1, @@ -38,7 +38,7 @@ async fn telemetry_works() { let addr = server.local_addr().unwrap(); - let server_task = async_std::task::spawn(async move { + let server_task = tokio::spawn(async move { loop { use websocket_server::Event; match server.next_event().await { @@ -78,7 +78,7 @@ async fn telemetry_works() { .spawn() .unwrap(); - server_task.await; + server_task.await.expect("server task panicked"); assert!(substrate.try_wait().unwrap().is_none(), "the process should still be running"); diff --git a/bin/node/cli/tests/websocket_server.rs b/bin/node/cli/tests/websocket_server.rs index 513497c6cddb5..1e7450995230c 100644 --- a/bin/node/cli/tests/websocket_server.rs +++ b/bin/node/cli/tests/websocket_server.rs @@ -16,11 +16,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use async_std::net::{TcpListener, TcpStream}; use core::pin::Pin; use futures::prelude::*; use soketto::handshake::{server::Response, Server}; use std::{io, net::SocketAddr}; +use tokio::net::{TcpListener, TcpStream}; +use tokio_util::compat::{Compat, TokioAsyncReadCompatExt}; /// Configuration for a [`WsServer`]. pub struct Config { @@ -71,8 +72,12 @@ pub struct WsServer { negotiating: stream::FuturesUnordered< Pin< Box< - dyn Future, Box>> - + Send, + dyn Future< + Output = Result< + Server<'static, Compat>, + Box, + >, + > + Send, >, >, >, @@ -120,7 +125,7 @@ impl WsServer { let pending_incoming = self.pending_incoming.take().expect("no pending socket"); self.negotiating.push(Box::pin(async move { - let mut server = Server::new(pending_incoming); + let mut server = Server::new(pending_incoming.compat()); let websocket_key = match server.receive_request().await { Ok(req) => req.key(), diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 999c5a298fe57..b6a77f00e7199 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -44,7 +44,7 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } serde = "1.0.136" strum = { version = "0.24.1", features = ["derive"] } tempfile = "3.1.0" -tokio = "1.17.0" +tokio = "1.22.0" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-network-test = { version = "0.8.0", path = "../network/test" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 71220388505b8..11ad15af1983d 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -29,4 +29,4 @@ sc-rpc = { version = "4.0.0-dev", features = [ "test-helpers", ], path = "../../rpc" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -tokio = { version = "1.17.0", features = ["macros"] } +tokio = { version = "1.22.0", features = ["macros"] } diff --git a/client/beefy/src/aux_schema.rs b/client/beefy/src/aux_schema.rs index e9a2e9b9e6126..9d6a4292f32d4 100644 --- a/client/beefy/src/aux_schema.rs +++ b/client/beefy/src/aux_schema.rs @@ -77,6 +77,7 @@ pub(crate) mod tests { use super::*; use crate::tests::BeefyTestNet; use sc_network_test::TestNetFactory; + use tokio::runtime::Runtime; // also used in tests.rs pub fn verify_persisted_version>(backend: &BE) -> bool { @@ -86,7 +87,8 @@ pub(crate) mod tests { #[test] fn should_load_persistent_sanity_checks() { - let mut net = BeefyTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); let backend = net.peer(0).client().as_backend(); // version not available in db -> None diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 6b9cf824d906d..f6ab0dd1020f1 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -47,7 +47,7 @@ use sc_consensus::{ use sc_network::{config::RequestResponseConfig, ProtocolName}; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, - PeersFullClient, TestNetFactory, + PeersFullClient, TestNetFactory, WithRuntime, }; use sc_utils::notification::NotificationReceiver; use serde::{Deserialize, Serialize}; @@ -64,7 +64,10 @@ use sp_runtime::{ }; use std::{collections::HashMap, marker::PhantomData, sync::Arc, task::Poll}; use substrate_test_runtime_client::{runtime::Header, ClientExt}; -use tokio::{runtime::Runtime, time::Duration}; +use tokio::{ + runtime::{Handle, Runtime}, + time::Duration, +}; const GENESIS_HASH: H256 = H256::zero(); fn beefy_gossip_proto_name() -> ProtocolName { @@ -103,14 +106,23 @@ pub(crate) struct PeerData { Mutex>>, } -#[derive(Default)] pub(crate) struct BeefyTestNet { + rt_handle: Handle, peers: Vec, } +impl WithRuntime for BeefyTestNet { + fn with_runtime(rt_handle: Handle) -> Self { + BeefyTestNet { rt_handle, peers: Vec::new() } + } + fn rt_handle(&self) -> &Handle { + &self.rt_handle + } +} + impl BeefyTestNet { - pub(crate) fn new(n_authority: usize) -> Self { - let mut net = BeefyTestNet { peers: Vec::with_capacity(n_authority) }; + pub(crate) fn new(rt_handle: Handle, n_authority: usize) -> Self { + let mut net = BeefyTestNet::with_runtime(rt_handle); for i in 0..n_authority { let (rx, cfg) = on_demand_justifications_protocol_config(GENESIS_HASH, None); @@ -145,6 +157,7 @@ impl BeefyTestNet { session_length: u64, validator_set: &BeefyValidatorSet, include_mmr_digest: bool, + runtime: &mut Runtime, ) { self.peer(0).generate_blocks(count, BlockOrigin::File, |builder| { let mut block = builder.build().unwrap().block; @@ -162,7 +175,7 @@ impl BeefyTestNet { block }); - self.block_until_sync(); + runtime.block_on(self.wait_until_sync()); } } @@ -534,14 +547,14 @@ fn beefy_finalizing_blocks() { let session_len = 10; let min_block_delta = 4; - let mut net = BeefyTestNet::new(2); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); // push 42 blocks including `AuthorityChange` digests every 10 blocks. - net.generate_blocks_and_sync(42, session_len, &validator_set, true); + net.generate_blocks_and_sync(42, session_len, &validator_set, true, &mut runtime); let net = Arc::new(Mutex::new(net)); @@ -574,13 +587,13 @@ fn lagging_validators() { let session_len = 30; let min_block_delta = 1; - let mut net = BeefyTestNet::new(2); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); // push 62 blocks including `AuthorityChange` digests every 30 blocks. - net.generate_blocks_and_sync(62, session_len, &validator_set, true); + net.generate_blocks_and_sync(62, session_len, &validator_set, true, &mut runtime); let net = Arc::new(Mutex::new(net)); @@ -657,7 +670,7 @@ fn correct_beefy_payload() { let session_len = 20; let min_block_delta = 2; - let mut net = BeefyTestNet::new(4); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 4); // Alice, Bob, Charlie will vote on good payloads let good_api = Arc::new(four_validators::TestApi {}); @@ -674,7 +687,7 @@ fn correct_beefy_payload() { runtime.spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); // push 12 blocks - net.generate_blocks_and_sync(12, session_len, &validator_set, false); + net.generate_blocks_and_sync(12, session_len, &validator_set, false, &mut runtime); let net = Arc::new(Mutex::new(net)); let peers = peers.into_iter().enumerate(); @@ -713,13 +726,15 @@ fn correct_beefy_payload() { #[test] fn beefy_importing_blocks() { - use futures::{executor::block_on, future::poll_fn, task::Poll}; + use futures::{future::poll_fn, task::Poll}; use sc_block_builder::BlockBuilderProvider; use sc_client_api::BlockBackend; sp_tracing::try_init_simple(); - let mut net = BeefyTestNet::new(2); + let runtime = Runtime::new().unwrap(); + + let mut net = BeefyTestNet::new(runtime.handle().clone(), 2); let client = net.peer(0).client().clone(); let (mut block_import, _, peer_data) = net.make_block_import(client.clone()); @@ -744,11 +759,15 @@ fn beefy_importing_blocks() { // Import without justifications. let mut justif_recv = justif_stream.subscribe(); assert_eq!( - block_on(block_import.import_block(params(block.clone(), None), HashMap::new())).unwrap(), + runtime + .block_on(block_import.import_block(params(block.clone(), None), HashMap::new())) + .unwrap(), ImportResult::Imported(ImportedAux { is_new_best: true, ..Default::default() }), ); assert_eq!( - block_on(block_import.import_block(params(block, None), HashMap::new())).unwrap(), + runtime + .block_on(block_import.import_block(params(block, None), HashMap::new())) + .unwrap(), ImportResult::AlreadyInChain ); // Verify no BEEFY justifications present: @@ -762,7 +781,7 @@ fn beefy_importing_blocks() { None ); // and none sent to BEEFY worker. - block_on(poll_fn(move |cx| { + runtime.block_on(poll_fn(move |cx| { assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); Poll::Ready(()) })); @@ -783,7 +802,9 @@ fn beefy_importing_blocks() { let hashof2 = block.header.hash(); let mut justif_recv = justif_stream.subscribe(); assert_eq!( - block_on(block_import.import_block(params(block, justif), HashMap::new())).unwrap(), + runtime + .block_on(block_import.import_block(params(block, justif), HashMap::new())) + .unwrap(), ImportResult::Imported(ImportedAux { bad_justification: false, is_new_best: true, @@ -802,7 +823,7 @@ fn beefy_importing_blocks() { ); // but sent to BEEFY worker // (worker will append it to backend when all previous mandatory justifs are there as well). - block_on(poll_fn(move |cx| { + runtime.block_on(poll_fn(move |cx| { match justif_recv.poll_next_unpin(cx) { Poll::Ready(Some(_justification)) => (), v => panic!("unexpected value: {:?}", v), @@ -826,7 +847,9 @@ fn beefy_importing_blocks() { let hashof3 = block.header.hash(); let mut justif_recv = justif_stream.subscribe(); assert_eq!( - block_on(block_import.import_block(params(block, justif), HashMap::new())).unwrap(), + runtime + .block_on(block_import.import_block(params(block, justif), HashMap::new())) + .unwrap(), ImportResult::Imported(ImportedAux { // Still `false` because we don't want to fail import on bad BEEFY justifications. bad_justification: false, @@ -845,7 +868,7 @@ fn beefy_importing_blocks() { None ); // and none sent to BEEFY worker. - block_on(poll_fn(move |cx| { + runtime.block_on(poll_fn(move |cx| { assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); Poll::Ready(()) })); @@ -865,13 +888,13 @@ fn voter_initialization() { // Should vote on all mandatory blocks no matter the `min_block_delta`. let min_block_delta = 10; - let mut net = BeefyTestNet::new(2); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); // push 26 blocks - net.generate_blocks_and_sync(26, session_len, &validator_set, false); + net.generate_blocks_and_sync(26, session_len, &validator_set, false, &mut runtime); let net = Arc::new(Mutex::new(net)); // Finalize multiple blocks at once to get a burst of finality notifications right from start. @@ -897,7 +920,7 @@ fn on_demand_beefy_justification_sync() { let session_len = 5; let min_block_delta = 5; - let mut net = BeefyTestNet::new(4); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 4); // Alice, Bob, Charlie start first and make progress through voting. let api = Arc::new(four_validators::TestApi {}); @@ -914,7 +937,7 @@ fn on_demand_beefy_justification_sync() { let dave_index = 3; // push 30 blocks - net.generate_blocks_and_sync(30, session_len, &validator_set, false); + net.generate_blocks_and_sync(30, session_len, &validator_set, false, &mut runtime); let fast_peers = fast_peers.into_iter().enumerate(); let net = Arc::new(Mutex::new(net)); @@ -968,11 +991,12 @@ fn on_demand_beefy_justification_sync() { fn should_initialize_voter_at_genesis() { let keys = &[BeefyKeyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); + let mut runtime = Runtime::new().unwrap(); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); let backend = net.peer(0).client().as_backend(); // push 15 blocks with `AuthorityChange` digests every 10 blocks - net.generate_blocks_and_sync(15, 10, &validator_set, false); + net.generate_blocks_and_sync(15, 10, &validator_set, false, &mut runtime); let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); @@ -1013,11 +1037,12 @@ fn should_initialize_voter_at_genesis() { fn should_initialize_voter_when_last_final_is_session_boundary() { let keys = &[BeefyKeyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); + let mut runtime = Runtime::new().unwrap(); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); let backend = net.peer(0).client().as_backend(); // push 15 blocks with `AuthorityChange` digests every 10 blocks - net.generate_blocks_and_sync(15, 10, &validator_set, false); + net.generate_blocks_and_sync(15, 10, &validator_set, false, &mut runtime); let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); @@ -1073,11 +1098,12 @@ fn should_initialize_voter_when_last_final_is_session_boundary() { fn should_initialize_voter_at_latest_finalized() { let keys = &[BeefyKeyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); + let mut runtime = Runtime::new().unwrap(); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); let backend = net.peer(0).client().as_backend(); // push 15 blocks with `AuthorityChange` digests every 10 blocks - net.generate_blocks_and_sync(15, 10, &validator_set, false); + net.generate_blocks_and_sync(15, 10, &validator_set, false, &mut runtime); let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 9669939e594c1..c82ac65d18296 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -947,7 +947,7 @@ pub(crate) mod tests { BeefyRPCLinks, KnownPeers, }; use beefy_primitives::{known_payloads, mmr::MmrRootProvider}; - use futures::{executor::block_on, future::poll_fn, task::Poll}; + use futures::{future::poll_fn, task::Poll}; use parking_lot::Mutex; use sc_client_api::{Backend as BackendT, HeaderBackend}; use sc_network::NetworkService; @@ -959,6 +959,7 @@ pub(crate) mod tests { runtime::{Block, Digest, DigestItem, Header, H256}, Backend, }; + use tokio::runtime::Runtime; impl PersistedState { pub fn voting_oracle(&self) -> &VoterOracle { @@ -1274,7 +1275,8 @@ pub(crate) mod tests { fn keystore_vs_validator_set() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); // keystore doesn't contain other keys than validators' @@ -1297,7 +1299,8 @@ pub(crate) mod tests { fn should_finalize_correctly() { let keys = [Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(&keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); let backend = net.peer(0).client().as_backend(); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); // remove default session, will manually add custom one. @@ -1320,7 +1323,7 @@ pub(crate) mod tests { // no 'best beefy block' or finality proofs assert_eq!(worker.best_beefy_block(), 0); - block_on(poll_fn(move |cx| { + runtime.block_on(poll_fn(move |cx| { assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); assert_eq!(finality_proof.poll_next_unpin(cx), Poll::Pending); Poll::Ready(()) @@ -1341,7 +1344,7 @@ pub(crate) mod tests { worker.finalize(justif.clone()).unwrap(); // verify block finalized assert_eq!(worker.best_beefy_block(), 1); - block_on(poll_fn(move |cx| { + runtime.block_on(poll_fn(move |cx| { // unknown hash -> nothing streamed assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); // commitment streamed @@ -1373,7 +1376,7 @@ pub(crate) mod tests { assert_eq!(worker.active_rounds().unwrap().session_start(), 2); // verify block finalized assert_eq!(worker.best_beefy_block(), 2); - block_on(poll_fn(move |cx| { + runtime.block_on(poll_fn(move |cx| { match best_block_stream.poll_next_unpin(cx) { // expect Some(hash-of-block-2) Poll::Ready(Some(hash)) => { @@ -1394,7 +1397,8 @@ pub(crate) mod tests { fn should_init_session() { let keys = &[Keyring::Alice, Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); let worker_rounds = worker.active_rounds().unwrap(); @@ -1425,7 +1429,8 @@ pub(crate) mod tests { fn should_triage_votes_and_process_later() { let keys = &[Keyring::Alice, Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); // remove default session, will manually add custom one. worker.persisted_state.voting_oracle.sessions.clear(); diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index dfb6d5c34c37c..2f079a0c7c56f 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -29,7 +29,7 @@ serde = "1.0.136" serde_json = "1.0.85" thiserror = "1.0.30" tiny-bip39 = "0.8.2" -tokio = { version = "1.17.0", features = ["signal", "rt-multi-thread", "parking_lot"] } +tokio = { version = "1.22.0", features = ["signal", "rt-multi-thread", "parking_lot"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../db" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 27faa40909713..47aee0ec084eb 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -46,3 +46,4 @@ sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } +tokio = { version = "1.22.0" } diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 839965a556e04..46b9124f9077f 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -633,7 +633,6 @@ where #[cfg(test)] mod tests { use super::*; - use futures::executor; use parking_lot::Mutex; use sc_block_builder::BlockBuilderProvider; use sc_client_api::BlockchainEvents; @@ -659,6 +658,7 @@ mod tests { runtime::{Header, H256}, TestClient, }; + use tokio::runtime::{Handle, Runtime}; const SLOT_DURATION_MS: u64 = 1000; @@ -716,11 +716,20 @@ mod tests { >; type AuraPeer = Peer<(), PeersClient>; - #[derive(Default)] pub struct AuraTestNet { + rt_handle: Handle, peers: Vec, } + impl WithRuntime for AuraTestNet { + fn with_runtime(rt_handle: Handle) -> Self { + AuraTestNet { rt_handle, peers: Vec::new() } + } + fn rt_handle(&self) -> &Handle { + &self.rt_handle + } + } + impl TestNetFactory for AuraTestNet { type Verifier = AuraVerifier; type PeerData = (); @@ -772,7 +781,8 @@ mod tests { #[test] fn authoring_blocks() { sp_tracing::try_init_simple(); - let net = AuraTestNet::new(3); + let runtime = Runtime::new().unwrap(); + let net = AuraTestNet::new(runtime.handle().clone(), 3); let peers = &[(0, Keyring::Alice), (1, Keyring::Bob), (2, Keyring::Charlie)]; @@ -838,7 +848,7 @@ mod tests { ); } - executor::block_on(future::select( + runtime.block_on(future::select( future::poll_fn(move |cx| { net.lock().poll(cx); Poll::<()>::Pending @@ -865,7 +875,8 @@ mod tests { #[test] fn current_node_authority_should_claim_slot() { - let net = AuraTestNet::new(4); + let runtime = Runtime::new().unwrap(); + let net = AuraTestNet::new(runtime.handle().clone(), 4); let mut authorities = vec![ Keyring::Alice.public().into(), @@ -909,19 +920,20 @@ mod tests { Default::default(), Default::default(), ); - assert!(executor::block_on(worker.claim_slot(&head, 0.into(), &authorities)).is_none()); - assert!(executor::block_on(worker.claim_slot(&head, 1.into(), &authorities)).is_none()); - assert!(executor::block_on(worker.claim_slot(&head, 2.into(), &authorities)).is_none()); - assert!(executor::block_on(worker.claim_slot(&head, 3.into(), &authorities)).is_some()); - assert!(executor::block_on(worker.claim_slot(&head, 4.into(), &authorities)).is_none()); - assert!(executor::block_on(worker.claim_slot(&head, 5.into(), &authorities)).is_none()); - assert!(executor::block_on(worker.claim_slot(&head, 6.into(), &authorities)).is_none()); - assert!(executor::block_on(worker.claim_slot(&head, 7.into(), &authorities)).is_some()); + assert!(runtime.block_on(worker.claim_slot(&head, 0.into(), &authorities)).is_none()); + assert!(runtime.block_on(worker.claim_slot(&head, 1.into(), &authorities)).is_none()); + assert!(runtime.block_on(worker.claim_slot(&head, 2.into(), &authorities)).is_none()); + assert!(runtime.block_on(worker.claim_slot(&head, 3.into(), &authorities)).is_some()); + assert!(runtime.block_on(worker.claim_slot(&head, 4.into(), &authorities)).is_none()); + assert!(runtime.block_on(worker.claim_slot(&head, 5.into(), &authorities)).is_none()); + assert!(runtime.block_on(worker.claim_slot(&head, 6.into(), &authorities)).is_none()); + assert!(runtime.block_on(worker.claim_slot(&head, 7.into(), &authorities)).is_some()); } #[test] fn on_slot_returns_correct_block() { - let net = AuraTestNet::new(4); + let runtime = Runtime::new().unwrap(); + let net = AuraTestNet::new(runtime.handle().clone(), 4); let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore."); @@ -957,15 +969,16 @@ mod tests { let head = client.header(&BlockId::Number(0)).unwrap().unwrap(); - let res = executor::block_on(worker.on_slot(SlotInfo { - slot: 0.into(), - ends_at: Instant::now() + Duration::from_secs(100), - create_inherent_data: Box::new(()), - duration: Duration::from_millis(1000), - chain_head: head, - block_size_limit: None, - })) - .unwrap(); + let res = runtime + .block_on(worker.on_slot(SlotInfo { + slot: 0.into(), + ends_at: Instant::now() + Duration::from_secs(100), + create_inherent_data: Box::new(()), + duration: Duration::from_millis(1000), + chain_head: head, + block_size_limit: None, + })) + .unwrap(); // The returned block should be imported and we should be able to get its header by now. assert!(client.header(&BlockId::Hash(res.block.hash())).unwrap().is_some()); diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 01d7d897b4ba4..c39802ba237ae 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -58,3 +58,4 @@ sc-network-test = { version = "0.8.0", path = "../../network/test" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } +tokio = "1.22.0" diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 8e76b14005063..d0a65a3fc3193 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -32,7 +32,7 @@ sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] serde_json = "1.0.85" tempfile = "3.1.0" -tokio = "1.17.0" +tokio = "1.22.0" sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } sp-keyring = { version = "7.0.0", path = "../../../../primitives/keyring" } diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 8bef1b38b929d..7f51eb2c51977 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -20,7 +20,6 @@ use super::*; use authorship::claim_slot; -use futures::executor::block_on; use log::debug; use rand_chacha::{ rand_core::{RngCore, SeedableRng}, @@ -50,6 +49,7 @@ use sp_runtime::{ }; use sp_timestamp::Timestamp; use std::{cell::RefCell, task::Poll, time::Duration}; +use tokio::runtime::{Handle, Runtime}; type Item = DigestItem; @@ -227,11 +227,20 @@ where type BabePeer = Peer, BabeBlockImport>; -#[derive(Default)] pub struct BabeTestNet { + rt_handle: Handle, peers: Vec, } +impl WithRuntime for BabeTestNet { + fn with_runtime(rt_handle: Handle) -> Self { + BabeTestNet { rt_handle, peers: Vec::new() } + } + fn rt_handle(&self) -> &Handle { + &self.rt_handle + } +} + type TestHeader = ::Header; type TestSelectChain = @@ -361,7 +370,8 @@ impl TestNetFactory for BabeTestNet { #[should_panic] fn rejects_empty_block() { sp_tracing::try_init_simple(); - let mut net = BabeTestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = BabeTestNet::new(runtime.handle().clone(), 3); let block_builder = |builder: BlockBuilder<_, _, _>| builder.build().unwrap().block; net.mut_peers(|peer| { peer[0].generate_blocks(1, BlockOrigin::NetworkInitialSync, block_builder); @@ -380,7 +390,9 @@ fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static let mutator = Arc::new(mutator) as Mutator; MUTATOR.with(|m| *m.borrow_mut() = mutator.clone()); - let net = BabeTestNet::new(3); + + let runtime = Runtime::new().unwrap(); + let net = BabeTestNet::new(runtime.handle().clone(), 3); let peers = [Sr25519Keyring::Alice, Sr25519Keyring::Bob, Sr25519Keyring::Charlie]; @@ -457,7 +469,7 @@ fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static .expect("Starts babe"), ); } - block_on(future::select( + runtime.block_on(future::select( futures::future::poll_fn(move |cx| { let mut net = net.lock(); net.poll(cx); @@ -594,8 +606,9 @@ fn propose_and_import_block( slot: Option, proposer_factory: &mut DummyFactory, block_import: &mut BoxBlockImport, + runtime: &Runtime, ) -> Hash { - let mut proposer = block_on(proposer_factory.init(parent)).unwrap(); + let mut proposer = runtime.block_on(proposer_factory.init(parent)).unwrap(); let slot = slot.unwrap_or_else(|| { let parent_pre_digest = find_pre_digest::(parent).unwrap(); @@ -611,7 +624,7 @@ fn propose_and_import_block( let parent_hash = parent.hash(); - let mut block = block_on(proposer.propose_with(pre_digest)).unwrap().block; + let mut block = runtime.block_on(proposer.propose_with(pre_digest)).unwrap().block; let epoch_descriptor = proposer_factory .epoch_changes @@ -647,7 +660,8 @@ fn propose_and_import_block( import .insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); import.fork_choice = Some(ForkChoiceStrategy::LongestChain); - let import_result = block_on(block_import.import_block(import, Default::default())).unwrap(); + let import_result = + runtime.block_on(block_import.import_block(import, Default::default())).unwrap(); match import_result { ImportResult::Imported(_) => {}, @@ -666,13 +680,14 @@ fn propose_and_import_blocks( block_import: &mut BoxBlockImport, parent_id: BlockId, n: usize, + runtime: &Runtime, ) -> Vec { let mut hashes = Vec::with_capacity(n); let mut parent_header = client.header(&parent_id).unwrap().unwrap(); for _ in 0..n { let block_hash = - propose_and_import_block(&parent_header, None, proposer_factory, block_import); + propose_and_import_block(&parent_header, None, proposer_factory, block_import, runtime); hashes.push(block_hash); parent_header = client.header(&BlockId::Hash(block_hash)).unwrap().unwrap(); } @@ -682,7 +697,8 @@ fn propose_and_import_blocks( #[test] fn importing_block_one_sets_genesis_epoch() { - let mut net = BabeTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BabeTestNet::new(runtime.handle().clone(), 1); let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); @@ -704,6 +720,7 @@ fn importing_block_one_sets_genesis_epoch() { Some(999.into()), &mut proposer_factory, &mut block_import, + &runtime, ); let genesis_epoch = Epoch::genesis(&data.link.config, 999.into()); @@ -721,7 +738,8 @@ fn importing_block_one_sets_genesis_epoch() { #[test] fn revert_prunes_epoch_changes_and_removes_weights() { - let mut net = BabeTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BabeTestNet::new(runtime.handle().clone(), 1); let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); @@ -739,7 +757,14 @@ fn revert_prunes_epoch_changes_and_removes_weights() { }; let mut propose_and_import_blocks_wrap = |parent_id, n| { - propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, parent_id, n) + propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + parent_id, + n, + &runtime, + ) }; // Test scenario. @@ -801,7 +826,8 @@ fn revert_prunes_epoch_changes_and_removes_weights() { #[test] fn revert_not_allowed_for_finalized() { - let mut net = BabeTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BabeTestNet::new(runtime.handle().clone(), 1); let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); @@ -818,7 +844,14 @@ fn revert_not_allowed_for_finalized() { }; let mut propose_and_import_blocks_wrap = |parent_id, n| { - propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, parent_id, n) + propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + parent_id, + n, + &runtime, + ) }; let canon = propose_and_import_blocks_wrap(BlockId::Number(0), 3); @@ -839,7 +872,8 @@ fn revert_not_allowed_for_finalized() { #[test] fn importing_epoch_change_block_prunes_tree() { - let mut net = BabeTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BabeTestNet::new(runtime.handle().clone(), 1); let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); @@ -856,7 +890,14 @@ fn importing_epoch_change_block_prunes_tree() { }; let mut propose_and_import_blocks_wrap = |parent_id, n| { - propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, parent_id, n) + propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + parent_id, + n, + &runtime, + ) }; // This is the block tree that we're going to use in this test. Each node @@ -916,7 +957,8 @@ fn importing_epoch_change_block_prunes_tree() { #[test] #[should_panic] fn verify_slots_are_strictly_increasing() { - let mut net = BabeTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BabeTestNet::new(runtime.handle().clone(), 1); let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); @@ -939,13 +981,20 @@ fn verify_slots_are_strictly_increasing() { Some(999.into()), &mut proposer_factory, &mut block_import, + &runtime, ); let b1 = client.header(&BlockId::Hash(b1)).unwrap().unwrap(); // we should fail to import this block since the slot number didn't increase. // we will panic due to the `PanickingBlockImport` defined above. - propose_and_import_block(&b1, Some(999.into()), &mut proposer_factory, &mut block_import); + propose_and_import_block( + &b1, + Some(999.into()), + &mut proposer_factory, + &mut block_import, + &runtime, + ); } #[test] @@ -980,7 +1029,8 @@ fn babe_transcript_generation_match() { #[test] fn obsolete_blocks_aux_data_cleanup() { - let mut net = BabeTestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = BabeTestNet::new(runtime.handle().clone(), 1); let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); @@ -1003,7 +1053,14 @@ fn obsolete_blocks_aux_data_cleanup() { let mut block_import = data.block_import.lock().take().expect("import set up during init"); let mut propose_and_import_blocks_wrap = |parent_id, n| { - propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, parent_id, n) + propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + parent_id, + n, + &runtime, + ) }; let aux_data_check = |hashes: &[Hash], expected: bool| { diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index a066de75f7def..cf151424c2ee5 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -42,7 +42,7 @@ sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } [dev-dependencies] -tokio = { version = "1.17.0", features = ["rt-multi-thread", "macros"] } +tokio = { version = "1.22.0", features = ["rt-multi-thread", "macros"] } sc-basic-authorship = { version = "0.10.0-dev", path = "../../basic-authorship" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } substrate-test-runtime-transaction-pool = { version = "2.0.0", path = "../../../test-utils/runtime/transaction-pool" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index b14d40659783b..0d5b8eaca5bec 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -53,7 +53,7 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } assert_matches = "1.3.0" finality-grandpa = { version = "0.16.0", features = ["derive-codec", "test-helpers"] } serde = "1.0.136" -tokio = "1.17.0" +tokio = "1.22.0" sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-test = { version = "0.8.0", path = "../network/test" } sp-keyring = { version = "7.0.0", path = "../../primitives/keyring" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 2d8a527ccef85..7be77c122bab2 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -34,4 +34,4 @@ sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -tokio = { version = "1.17.0", features = ["macros"] } +tokio = { version = "1.22.0", features = ["macros"] } diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 93d20110ff5af..6b577fd712930 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -21,7 +21,6 @@ use super::*; use assert_matches::assert_matches; use environment::HasVoted; -use futures::executor::block_on; use futures_timer::Delay; use parking_lot::{Mutex, RwLock}; use sc_consensus::{ @@ -31,7 +30,7 @@ use sc_consensus::{ use sc_network::config::Role; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, Hash, PassThroughVerifier, Peer, PeersClient, - PeersFullClient, TestClient, TestNetFactory, + PeersFullClient, TestClient, TestNetFactory, WithRuntime, }; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_blockchain::Result; @@ -72,16 +71,26 @@ type GrandpaBlockImport = crate::GrandpaBlockImport< LongestChain, >; -#[derive(Default)] struct GrandpaTestNet { peers: Vec, test_config: TestApi, + rt_handle: Handle, +} + +impl WithRuntime for GrandpaTestNet { + fn with_runtime(rt_handle: Handle) -> Self { + GrandpaTestNet { peers: Vec::new(), test_config: TestApi::default(), rt_handle } + } + fn rt_handle(&self) -> &Handle { + &self.rt_handle + } } impl GrandpaTestNet { - fn new(test_config: TestApi, n_authority: usize, n_full: usize) -> Self { - let mut net = - GrandpaTestNet { peers: Vec::with_capacity(n_authority + n_full), test_config }; + fn new(test_config: TestApi, n_authority: usize, n_full: usize, rt_handle: Handle) -> Self { + let mut net = GrandpaTestNet::with_runtime(rt_handle); + net.peers = Vec::with_capacity(n_authority + n_full); + net.test_config = test_config; for _ in 0..n_authority { net.add_authority_peer(); @@ -359,10 +368,10 @@ fn finalize_3_voters_no_observers() { let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; let voters = make_ids(peers); - let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 0); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 0, runtime.handle().clone()); runtime.spawn(initialize_grandpa(&mut net, peers)); net.peer(0).push_blocks(20, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let hashof20 = net.peer(0).client().info().best_hash; for i in 0..3 { @@ -387,7 +396,7 @@ fn finalize_3_voters_1_full_observer() { let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; let voters = make_ids(peers); - let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 1); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 1, runtime.handle().clone()); runtime.spawn(initialize_grandpa(&mut net, peers)); runtime.spawn({ @@ -469,9 +478,8 @@ fn transition_3_voters_twice_1_full_observer() { let genesis_voters = make_ids(peers_a); let api = TestApi::new(genesis_voters); - let net = Arc::new(Mutex::new(GrandpaTestNet::new(api, 8, 1))); - let mut runtime = Runtime::new().unwrap(); + let net = Arc::new(Mutex::new(GrandpaTestNet::new(api, 8, 1, runtime.handle().clone()))); let mut voters = Vec::new(); for (peer_id, local_key) in all_peers.clone().into_iter().enumerate() { @@ -508,7 +516,7 @@ fn transition_3_voters_twice_1_full_observer() { } net.lock().peer(0).push_blocks(1, false); - net.lock().block_until_sync(); + runtime.block_on(net.lock().wait_until_sync()); for (i, peer) in net.lock().peers().iter().enumerate() { let full_client = peer.client().as_client(); @@ -608,10 +616,10 @@ fn justification_is_generated_periodically() { let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; let voters = make_ids(peers); - let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 0); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 0, runtime.handle().clone()); runtime.spawn(initialize_grandpa(&mut net, peers)); net.peer(0).push_blocks(32, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let hashof32 = net.peer(0).client().info().best_hash; @@ -634,7 +642,7 @@ fn sync_justifications_on_change_blocks() { // 4 peers, 3 of them are authorities and participate in grandpa let api = TestApi::new(voters); - let mut net = GrandpaTestNet::new(api, 3, 1); + let mut net = GrandpaTestNet::new(api, 3, 1, runtime.handle().clone()); let voters = initialize_grandpa(&mut net, peers_a); // add 20 blocks @@ -652,7 +660,7 @@ fn sync_justifications_on_change_blocks() { // add more blocks on top of it (until we have 25) net.peer(0).push_blocks(4, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); for i in 0..4 { assert_eq!(net.peer(i).client().info().best_number, 25, "Peer #{} failed to sync", i); @@ -702,7 +710,7 @@ fn finalizes_multiple_pending_changes_in_order() { // but all of them will be part of the voter set eventually so they should be // all added to the network as authorities let api = TestApi::new(genesis_voters); - let mut net = GrandpaTestNet::new(api, 6, 0); + let mut net = GrandpaTestNet::new(api, 6, 0, runtime.handle().clone()); runtime.spawn(initialize_grandpa(&mut net, all_peers)); // add 20 blocks @@ -734,7 +742,7 @@ fn finalizes_multiple_pending_changes_in_order() { // add more blocks on top of it (until we have 30) net.peer(0).push_blocks(4, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); // all peers imported both change blocks for i in 0..6 { @@ -761,7 +769,7 @@ fn force_change_to_new_set() { let api = TestApi::new(make_ids(genesis_authorities)); let voters = make_ids(peers_a); - let mut net = GrandpaTestNet::new(api, 3, 0); + let mut net = GrandpaTestNet::new(api, 3, 0, runtime.handle().clone()); let voters_future = initialize_grandpa(&mut net, peers_a); let net = Arc::new(Mutex::new(net)); @@ -785,7 +793,7 @@ fn force_change_to_new_set() { }); net.lock().peer(0).push_blocks(25, false); - net.lock().block_until_sync(); + runtime.block_on(net.lock().wait_until_sync()); for (i, peer) in net.lock().peers().iter().enumerate() { assert_eq!(peer.client().info().best_number, 26, "Peer #{} failed to sync", i); @@ -811,7 +819,8 @@ fn allows_reimporting_change_blocks() { let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob]; let voters = make_ids(peers_a); let api = TestApi::new(voters); - let mut net = GrandpaTestNet::new(api.clone(), 3, 0); + let runtime = Runtime::new().unwrap(); + let mut net = GrandpaTestNet::new(api.clone(), 3, 0, runtime.handle().clone()); let client = net.peer(0).client().clone(); let (mut block_import, ..) = net.make_block_import(client.clone()); @@ -836,7 +845,7 @@ fn allows_reimporting_change_blocks() { }; assert_eq!( - block_on(block_import.import_block(block(), HashMap::new())).unwrap(), + runtime.block_on(block_import.import_block(block(), HashMap::new())).unwrap(), ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, @@ -847,7 +856,7 @@ fn allows_reimporting_change_blocks() { ); assert_eq!( - block_on(block_import.import_block(block(), HashMap::new())).unwrap(), + runtime.block_on(block_import.import_block(block(), HashMap::new())).unwrap(), ImportResult::AlreadyInChain ); } @@ -858,7 +867,8 @@ fn test_bad_justification() { let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob]; let voters = make_ids(peers_a); let api = TestApi::new(voters); - let mut net = GrandpaTestNet::new(api.clone(), 3, 0); + let runtime = Runtime::new().unwrap(); + let mut net = GrandpaTestNet::new(api.clone(), 3, 0, runtime.handle().clone()); let client = net.peer(0).client().clone(); let (mut block_import, ..) = net.make_block_import(client.clone()); @@ -885,7 +895,7 @@ fn test_bad_justification() { }; assert_eq!( - block_on(block_import.import_block(block(), HashMap::new())).unwrap(), + runtime.block_on(block_import.import_block(block(), HashMap::new())).unwrap(), ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, @@ -896,7 +906,7 @@ fn test_bad_justification() { ); assert_eq!( - block_on(block_import.import_block(block(), HashMap::new())).unwrap(), + runtime.block_on(block_import.import_block(block(), HashMap::new())).unwrap(), ImportResult::AlreadyInChain ); } @@ -915,7 +925,7 @@ fn voter_persists_its_votes() { let voters = make_ids(peers); // alice has a chain with 20 blocks - let mut net = GrandpaTestNet::new(TestApi::new(voters.clone()), 2, 0); + let mut net = GrandpaTestNet::new(TestApi::new(voters.clone()), 2, 0, runtime.handle().clone()); // create the communication layer for bob, but don't start any // voter. instead we'll listen for the prevote that alice casts @@ -1035,7 +1045,7 @@ fn voter_persists_its_votes() { runtime.spawn(alice_voter1); net.peer(0).push_blocks(20, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert_eq!(net.peer(0).client().info().best_number, 20, "Peer #{} failed to sync", 0); @@ -1164,7 +1174,7 @@ fn finalize_3_voters_1_light_observer() { let authorities = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; let voters = make_ids(authorities); - let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 1); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 1, runtime.handle().clone()); let voters = initialize_grandpa(&mut net, authorities); let observer = observer::run_grandpa_observer( Config { @@ -1182,7 +1192,7 @@ fn finalize_3_voters_1_light_observer() { ) .unwrap(); net.peer(0).push_blocks(20, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); for i in 0..4 { assert_eq!(net.peer(i).client().info().best_number, 20, "Peer #{} failed to sync", i); @@ -1203,7 +1213,7 @@ fn voter_catches_up_to_latest_round_when_behind() { let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob]; let voters = make_ids(peers); - let net = GrandpaTestNet::new(TestApi::new(voters), 2, 0); + let net = GrandpaTestNet::new(TestApi::new(voters), 2, 0, runtime.handle().clone()); let net = Arc::new(Mutex::new(net)); let mut finality_notifications = Vec::new(); @@ -1259,7 +1269,7 @@ fn voter_catches_up_to_latest_round_when_behind() { } net.lock().peer(0).push_blocks(50, false); - net.lock().block_until_sync(); + runtime.block_on(net.lock().wait_until_sync()); // wait for them to finalize block 50. since they'll vote on 3/4 of the // unfinalized chain it will take at least 4 rounds to do it. @@ -1367,7 +1377,8 @@ fn grandpa_environment_respects_voting_rules() { let peers = &[Ed25519Keyring::Alice]; let voters = make_ids(peers); - let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); + let runtime = Runtime::new().unwrap(); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0, runtime.handle().clone()); let peer = net.peer(0); let network_service = peer.network_service().clone(); let link = peer.data.lock().take().unwrap(); @@ -1397,7 +1408,8 @@ fn grandpa_environment_respects_voting_rules() { // the unrestricted environment should just return the best block assert_eq!( - block_on(unrestricted_env.best_chain_containing(peer.client().info().finalized_hash)) + runtime + .block_on(unrestricted_env.best_chain_containing(peer.client().info().finalized_hash)) .unwrap() .unwrap() .1, @@ -1407,7 +1419,8 @@ fn grandpa_environment_respects_voting_rules() { // both the other environments should return block 16, which is 3/4 of the // way in the unfinalized chain assert_eq!( - block_on(three_quarters_env.best_chain_containing(peer.client().info().finalized_hash)) + runtime + .block_on(three_quarters_env.best_chain_containing(peer.client().info().finalized_hash)) .unwrap() .unwrap() .1, @@ -1415,7 +1428,8 @@ fn grandpa_environment_respects_voting_rules() { ); assert_eq!( - block_on(default_env.best_chain_containing(peer.client().info().finalized_hash)) + runtime + .block_on(default_env.best_chain_containing(peer.client().info().finalized_hash)) .unwrap() .unwrap() .1, @@ -1432,7 +1446,8 @@ fn grandpa_environment_respects_voting_rules() { // the 3/4 environment should propose block 21 for voting assert_eq!( - block_on(three_quarters_env.best_chain_containing(peer.client().info().finalized_hash)) + runtime + .block_on(three_quarters_env.best_chain_containing(peer.client().info().finalized_hash)) .unwrap() .unwrap() .1, @@ -1442,7 +1457,8 @@ fn grandpa_environment_respects_voting_rules() { // while the default environment will always still make sure we don't vote // on the best block (2 behind) assert_eq!( - block_on(default_env.best_chain_containing(peer.client().info().finalized_hash)) + runtime + .block_on(default_env.best_chain_containing(peer.client().info().finalized_hash)) .unwrap() .unwrap() .1, @@ -1461,7 +1477,8 @@ fn grandpa_environment_respects_voting_rules() { // best block, there's a hard rule that we can't cast any votes lower than // the given base (#21). assert_eq!( - block_on(default_env.best_chain_containing(peer.client().info().finalized_hash)) + runtime + .block_on(default_env.best_chain_containing(peer.client().info().finalized_hash)) .unwrap() .unwrap() .1, @@ -1476,7 +1493,8 @@ fn grandpa_environment_never_overwrites_round_voter_state() { let peers = &[Ed25519Keyring::Alice]; let voters = make_ids(peers); - let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); + let runtime = Runtime::new().unwrap(); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0, runtime.handle().clone()); let peer = net.peer(0); let network_service = peer.network_service().clone(); let link = peer.data.lock().take().unwrap(); @@ -1539,7 +1557,8 @@ fn justification_with_equivocation() { let pairs = (0..100).map(|n| AuthorityPair::from_seed(&[n; 32])).collect::>(); let voters = pairs.iter().map(AuthorityPair::public).map(|id| (id, 1)).collect::>(); let api = TestApi::new(voters.clone()); - let mut net = GrandpaTestNet::new(api.clone(), 1, 0); + let runtime = Runtime::new().unwrap(); + let mut net = GrandpaTestNet::new(api.clone(), 1, 0, runtime.handle().clone()); // we create a basic chain with 3 blocks (no forks) net.peer(0).push_blocks(3, false); @@ -1606,7 +1625,8 @@ fn imports_justification_for_regular_blocks_on_import() { let peers = &[Ed25519Keyring::Alice]; let voters = make_ids(peers); let api = TestApi::new(voters); - let mut net = GrandpaTestNet::new(api.clone(), 1, 0); + let runtime = Runtime::new().unwrap(); + let mut net = GrandpaTestNet::new(api.clone(), 1, 0, runtime.handle().clone()); let client = net.peer(0).client().clone(); let (mut block_import, ..) = net.make_block_import(client.clone()); @@ -1655,7 +1675,7 @@ fn imports_justification_for_regular_blocks_on_import() { import.fork_choice = Some(ForkChoiceStrategy::LongestChain); assert_eq!( - block_on(block_import.import_block(import, HashMap::new())).unwrap(), + runtime.block_on(block_import.import_block(import, HashMap::new())).unwrap(), ImportResult::Imported(ImportedAux { needs_justification: false, clear_justification_requests: false, @@ -1676,8 +1696,10 @@ fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { let alice = Ed25519Keyring::Alice; let voters = make_ids(&[alice]); + let runtime = Runtime::new().unwrap(); + let environment = { - let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0, runtime.handle().clone()); let peer = net.peer(0); let network_service = peer.network_service().clone(); let link = peer.data.lock().take().unwrap(); @@ -1734,7 +1756,8 @@ fn revert_prunes_authority_changes() { }; let api = TestApi::new(make_ids(peers)); - let mut net = GrandpaTestNet::new(api, 3, 0); + + let mut net = GrandpaTestNet::new(api, 3, 0, runtime.handle().clone()); runtime.spawn(initialize_grandpa(&mut net, peers)); let peer = net.peer(0); diff --git a/client/merkle-mountain-range/Cargo.toml b/client/merkle-mountain-range/Cargo.toml index 3630c42414964..6e8cb8194e48c 100644 --- a/client/merkle-mountain-range/Cargo.toml +++ b/client/merkle-mountain-range/Cargo.toml @@ -29,4 +29,3 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } tokio = "1.17.0" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } -async-std = { version = "1.11.0", default-features = false } diff --git a/client/merkle-mountain-range/src/lib.rs b/client/merkle-mountain-range/src/lib.rs index cb13977ffa5bd..59f26b4265708 100644 --- a/client/merkle-mountain-range/src/lib.rs +++ b/client/merkle-mountain-range/src/lib.rs @@ -201,7 +201,7 @@ mod tests { let a2 = client.import_block(&BlockId::Hash(a1.hash()), b"a2", Some(1)).await; client.finalize_block(a1.hash(), Some(1)); - async_std::task::sleep(Duration::from_millis(200)).await; + tokio::time::sleep(Duration::from_millis(200)).await; // expected finalized heads: a1 client.assert_canonicalized(&[&a1]); client.assert_not_pruned(&[&a2]); @@ -221,7 +221,7 @@ mod tests { let a6 = client.import_block(&BlockId::Hash(a5.hash()), b"a6", Some(2)).await; client.finalize_block(a5.hash(), Some(2)); - async_std::task::sleep(Duration::from_millis(200)).await; + tokio::time::sleep(Duration::from_millis(200)).await; // expected finalized heads: a4, a5 client.assert_canonicalized(&[&a4, &a5]); client.assert_not_pruned(&[&a6]); @@ -240,7 +240,7 @@ mod tests { // Simulate the case where the runtime says that there are 2 mmr_blocks when in fact // there is only 1. client.finalize_block(a1.hash(), Some(2)); - async_std::task::sleep(Duration::from_millis(200)).await; + tokio::time::sleep(Duration::from_millis(200)).await; // expected finalized heads: - client.assert_not_canonicalized(&[&a1]); }); diff --git a/client/merkle-mountain-range/src/offchain_mmr.rs b/client/merkle-mountain-range/src/offchain_mmr.rs index f42dfc0cae3db..1cdd3810b4c52 100644 --- a/client/merkle-mountain-range/src/offchain_mmr.rs +++ b/client/merkle-mountain-range/src/offchain_mmr.rs @@ -228,7 +228,7 @@ mod tests { let d5 = client.import_block(&BlockId::Hash(d4.hash()), b"d5", Some(4)).await; client.finalize_block(a3.hash(), Some(3)); - async_std::task::sleep(Duration::from_millis(200)).await; + tokio::time::sleep(Duration::from_millis(200)).await; // expected finalized heads: a1, a2, a3 client.assert_canonicalized(&[&a1, &a2, &a3]); // expected stale heads: c1 @@ -236,7 +236,7 @@ mod tests { client.assert_pruned(&[&c1, &b1]); client.finalize_block(d5.hash(), None); - async_std::task::sleep(Duration::from_millis(200)).await; + tokio::time::sleep(Duration::from_millis(200)).await; // expected finalized heads: d4, d5, client.assert_canonicalized(&[&d4, &d5]); // expected stale heads: b1, b2, b3, a4 diff --git a/client/merkle-mountain-range/src/test_utils.rs b/client/merkle-mountain-range/src/test_utils.rs index 0ba297c2808d2..b854686b2dc86 100644 --- a/client/merkle-mountain-range/src/test_utils.rs +++ b/client/merkle-mountain-range/src/test_utils.rs @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use futures::{executor::LocalPool, task::LocalSpawn, FutureExt}; use std::{ future::Future, sync::{Arc, Mutex}, @@ -316,28 +315,17 @@ where F: FnOnce(Arc) -> Fut + 'static, Fut: Future, { - let mut pool = LocalPool::new(); + let runtime = tokio::runtime::Runtime::new().unwrap(); let client = Arc::new(MockClient::new()); let client_clone = client.clone(); - pool.spawner() - .spawn_local_obj( - async move { - let backend = client_clone.backend.clone(); - MmrGadget::start( - client_clone.clone(), - backend, - MockRuntimeApi::INDEXING_PREFIX.to_vec(), - ) - .await - } - .boxed_local() - .into(), - ) - .unwrap(); + runtime.spawn(async move { + let backend = client_clone.backend.clone(); + MmrGadget::start(client_clone, backend, MockRuntimeApi::INDEXING_PREFIX.to_vec()).await + }); - pool.run_until(async move { - async_std::task::sleep(Duration::from_millis(200)).await; + runtime.block_on(async move { + tokio::time::sleep(Duration::from_millis(200)).await; f(client).await }); diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 31930515ff118..c40a830f9219b 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -27,6 +27,6 @@ sc-peerset = { version = "4.0.0-dev", path = "../peerset" } sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] -async-std = "1.11.0" +tokio = "1.22.0" quickcheck = { version = "1.0.3", default-features = false } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 5563b3be35e8d..462677f53c5fd 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -308,7 +308,6 @@ impl futures::future::FusedFuture for GossipEngine { mod tests { use super::*; use crate::{multiaddr::Multiaddr, ValidationResult, ValidatorContext}; - use async_std::task::spawn; use futures::{ channel::mpsc::{unbounded, UnboundedSender}, executor::{block_on, block_on_stream}, @@ -490,8 +489,8 @@ mod tests { })) } - #[test] - fn keeps_multiple_subscribers_per_topic_updated_with_both_old_and_new_messages() { + #[tokio::test(flavor = "multi_thread")] + async fn keeps_multiple_subscribers_per_topic_updated_with_both_old_and_new_messages() { let topic = H256::default(); let protocol = ProtocolName::from("/my_protocol"); let remote_peer = PeerId::random(); @@ -541,8 +540,10 @@ mod tests { .start_send(events[1].clone()) .expect("Event stream is unbounded; qed."); - spawn(gossip_engine); + tokio::spawn(gossip_engine); + // Note: `block_on_stream()`-derived iterator will block the current thread, + // so we need a `multi_thread` `tokio::test` runtime flavor. let mut subscribers = subscribers.into_iter().map(|s| block_on_stream(s)).collect::>(); diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index afd9880148081..1959e24bd680f 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -26,7 +26,7 @@ fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" ip_network = "0.4.1" -libp2p = { version = "0.49.0", features = ["async-std", "dns", "identify", "kad", "mdns-async-io", "mplex", "noise", "ping", "tcp", "yamux", "websocket"] } +libp2p = { version = "0.49.0", features = ["dns", "identify", "kad", "mdns", "mplex", "noise", "ping", "tcp", "tokio", "yamux", "websocket"] } linked_hash_set = "0.1.3" linked-hash-map = "0.5.4" log = "0.4.17" @@ -57,9 +57,10 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3" -async-std = { version = "1.11.0", features = ["attributes"] } rand = "0.7.2" tempfile = "3.1.0" +tokio = { version = "1.22.0", features = ["macros"] } +tokio-util = { version = "0.7.4", features = ["compat"] } sc-network-light = { version = "0.10.0-dev", path = "./light" } sc-network-sync = { version = "0.10.0-dev", path = "./sync" } sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } diff --git a/client/network/bitswap/Cargo.toml b/client/network/bitswap/Cargo.toml index 9793eeae51b26..02e12e8f91653 100644 --- a/client/network/bitswap/Cargo.toml +++ b/client/network/bitswap/Cargo.toml @@ -31,7 +31,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [dev-dependencies] -tokio = { version = "1", features = ["full"] } +tokio = { version = "1.22.0", features = ["full"] } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sp-core = { version = "7.0.0", path = "../../../primitives/core" } diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 50d8e2baba60f..b10612dd17094 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -66,9 +66,8 @@ where /// Assigned role for our node (full, light, ...). pub role: Role, - /// How to spawn background tasks. If you pass `None`, then a threads pool will be used by - /// default. - pub executor: Option + Send>>) + Send>>, + /// How to spawn background tasks. + pub executor: Box + Send>>) + Send>, /// Network layer configuration. pub network_config: NetworkConfiguration, diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 00fc78061293d..13b153be11d59 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -64,7 +64,7 @@ use libp2p::{ GetClosestPeersError, Kademlia, KademliaBucketInserts, KademliaConfig, KademliaEvent, QueryId, QueryResult, Quorum, Record, }, - mdns::{Mdns, MdnsConfig, MdnsEvent}, + mdns::{MdnsConfig, MdnsEvent, TokioMdns}, multiaddr::Protocol, swarm::{ behaviour::toggle::{Toggle, ToggleIntoConnectionHandler}, @@ -235,7 +235,7 @@ impl DiscoveryConfig { allow_private_ipv4, discovery_only_if_under_num, mdns: if enable_mdns { - match Mdns::new(MdnsConfig::default()) { + match TokioMdns::new(MdnsConfig::default()) { Ok(mdns) => Some(mdns), Err(err) => { warn!(target: "sub-libp2p", "Failed to initialize mDNS: {:?}", err); @@ -266,7 +266,7 @@ pub struct DiscoveryBehaviour { /// it's always enabled in `NetworkWorker::new()`. kademlia: Toggle>, /// Discovers nodes on the local network. - mdns: Option, + mdns: Option, /// Stream that fires when we need to perform the next random Kademlia query. `None` if /// random walking is disabled. next_kad_random_query: Option, diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 56cfefd75d53d..5d61e10727b66 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -481,20 +481,25 @@ pub enum NotificationsOutError { #[cfg(test)] mod tests { use super::{NotificationsIn, NotificationsInOpen, NotificationsOut, NotificationsOutOpen}; - - use async_std::net::{TcpListener, TcpStream}; use futures::{channel::oneshot, prelude::*}; use libp2p::core::upgrade; + use tokio::{ + net::{TcpListener, TcpStream}, + runtime::Runtime, + }; + use tokio_util::compat::TokioAsyncReadCompatExt; #[test] fn basic_works() { const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - let client = async_std::task::spawn(async move { + let runtime = Runtime::new().unwrap(); + + let client = runtime.spawn(async move { let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); let NotificationsOutOpen { handshake, mut substream, .. } = upgrade::apply_outbound( - socket, + socket.compat(), NotificationsOut::new(PROTO_NAME, Vec::new(), &b"initial message"[..], 1024 * 1024), upgrade::Version::V1, ) @@ -505,13 +510,13 @@ mod tests { substream.send(b"test message".to_vec()).await.unwrap(); }); - async_std::task::block_on(async move { + runtime.block_on(async move { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); listener_addr_tx.send(listener.local_addr().unwrap()).unwrap(); let (socket, _) = listener.accept().await.unwrap(); let NotificationsInOpen { handshake, mut substream, .. } = upgrade::apply_inbound( - socket, + socket.compat(), NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), ) .await @@ -524,7 +529,7 @@ mod tests { assert_eq!(msg.as_ref(), b"test message"); }); - async_std::task::block_on(client); + runtime.block_on(client).unwrap(); } #[test] @@ -534,10 +539,12 @@ mod tests { const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - let client = async_std::task::spawn(async move { + let runtime = Runtime::new().unwrap(); + + let client = runtime.spawn(async move { let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); let NotificationsOutOpen { handshake, mut substream, .. } = upgrade::apply_outbound( - socket, + socket.compat(), NotificationsOut::new(PROTO_NAME, Vec::new(), vec![], 1024 * 1024), upgrade::Version::V1, ) @@ -548,13 +555,13 @@ mod tests { substream.send(Default::default()).await.unwrap(); }); - async_std::task::block_on(async move { + runtime.block_on(async move { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); listener_addr_tx.send(listener.local_addr().unwrap()).unwrap(); let (socket, _) = listener.accept().await.unwrap(); let NotificationsInOpen { handshake, mut substream, .. } = upgrade::apply_inbound( - socket, + socket.compat(), NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), ) .await @@ -567,7 +574,7 @@ mod tests { assert!(msg.as_ref().is_empty()); }); - async_std::task::block_on(client); + runtime.block_on(client).unwrap(); } #[test] @@ -575,10 +582,12 @@ mod tests { const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - let client = async_std::task::spawn(async move { + let runtime = Runtime::new().unwrap(); + + let client = runtime.spawn(async move { let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); let outcome = upgrade::apply_outbound( - socket, + socket.compat(), NotificationsOut::new(PROTO_NAME, Vec::new(), &b"hello"[..], 1024 * 1024), upgrade::Version::V1, ) @@ -590,13 +599,13 @@ mod tests { assert!(outcome.is_err()); }); - async_std::task::block_on(async move { + runtime.block_on(async move { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); listener_addr_tx.send(listener.local_addr().unwrap()).unwrap(); let (socket, _) = listener.accept().await.unwrap(); let NotificationsInOpen { handshake, substream, .. } = upgrade::apply_inbound( - socket, + socket.compat(), NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), ) .await @@ -608,7 +617,7 @@ mod tests { drop(substream); }); - async_std::task::block_on(client); + runtime.block_on(client).unwrap(); } #[test] @@ -616,10 +625,12 @@ mod tests { const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - let client = async_std::task::spawn(async move { + let runtime = Runtime::new().unwrap(); + + let client = runtime.spawn(async move { let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); let ret = upgrade::apply_outbound( - socket, + socket.compat(), // We check that an initial message that is too large gets refused. NotificationsOut::new( PROTO_NAME, @@ -633,20 +644,20 @@ mod tests { assert!(ret.is_err()); }); - async_std::task::block_on(async move { + runtime.block_on(async move { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); listener_addr_tx.send(listener.local_addr().unwrap()).unwrap(); let (socket, _) = listener.accept().await.unwrap(); let ret = upgrade::apply_inbound( - socket, + socket.compat(), NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), ) .await; assert!(ret.is_err()); }); - async_std::task::block_on(client); + runtime.block_on(client).unwrap(); } #[test] @@ -654,10 +665,12 @@ mod tests { const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - let client = async_std::task::spawn(async move { + let runtime = Runtime::new().unwrap(); + + let client = runtime.spawn(async move { let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); let ret = upgrade::apply_outbound( - socket, + socket.compat(), NotificationsOut::new(PROTO_NAME, Vec::new(), &b"initial message"[..], 1024 * 1024), upgrade::Version::V1, ) @@ -665,13 +678,13 @@ mod tests { assert!(ret.is_err()); }); - async_std::task::block_on(async move { + runtime.block_on(async move { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); listener_addr_tx.send(listener.local_addr().unwrap()).unwrap(); let (socket, _) = listener.accept().await.unwrap(); let NotificationsInOpen { handshake, mut substream, .. } = upgrade::apply_inbound( - socket, + socket.compat(), NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), ) .await @@ -683,6 +696,6 @@ mod tests { let _ = substream.next().await; }); - async_std::task::block_on(client); + runtime.block_on(client).unwrap(); } } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 7d756ed2d1e88..d35594a07e38a 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -383,15 +383,15 @@ where .notify_handler_buffer_size(NonZeroUsize::new(32).expect("32 != 0; qed")) .connection_event_buffer_size(1024) .max_negotiating_inbound_streams(2048); - if let Some(spawner) = params.executor { - struct SpawnImpl(F); - impl + Send>>)> Executor for SpawnImpl { - fn exec(&self, f: Pin + Send>>) { - (self.0)(f) - } + + struct SpawnImpl(F); + impl + Send>>)> Executor for SpawnImpl { + fn exec(&self, f: Pin + Send>>) { + (self.0)(f) } - builder = builder.executor(Box::new(SpawnImpl(spawner))); } + builder = builder.executor(Box::new(SpawnImpl(params.executor))); + (builder.build(), bandwidth) }; diff --git a/client/network/src/service/tests/chain_sync.rs b/client/network/src/service/tests/chain_sync.rs index b62fb36461860..bd4967f25973a 100644 --- a/client/network/src/service/tests/chain_sync.rs +++ b/client/network/src/service/tests/chain_sync.rs @@ -44,6 +44,7 @@ use std::{ time::Duration, }; use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; +use tokio::runtime::Handle; fn set_default_expecations_no_peers( chain_sync: &mut MockChainSync, @@ -59,7 +60,7 @@ fn set_default_expecations_no_peers( }); } -#[async_std::test] +#[tokio::test] async fn normal_network_poll_no_peers() { // build `ChainSync` and set default expectations for it let mut chain_sync = @@ -71,7 +72,7 @@ async fn normal_network_poll_no_peers() { let chain_sync_service = Box::new(MockChainSyncInterface::::new()); - let mut network = TestNetworkBuilder::new() + let mut network = TestNetworkBuilder::new(Handle::current()) .with_chain_sync((chain_sync, chain_sync_service)) .build(); @@ -83,7 +84,7 @@ async fn normal_network_poll_no_peers() { .await; } -#[async_std::test] +#[tokio::test] async fn request_justification() { // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be // called) @@ -104,7 +105,7 @@ async fn request_justification() { .returning(|_, _| ()); set_default_expecations_no_peers(&mut chain_sync); - let mut network = TestNetworkBuilder::new() + let mut network = TestNetworkBuilder::new(Handle::current()) .with_chain_sync((chain_sync, chain_sync_service)) .build(); @@ -118,7 +119,7 @@ async fn request_justification() { .await; } -#[async_std::test] +#[tokio::test] async fn clear_justification_requests() { // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be // called) @@ -132,7 +133,7 @@ async fn clear_justification_requests() { chain_sync.expect_clear_justification_requests().once().returning(|| ()); set_default_expecations_no_peers(&mut chain_sync); - let mut network = TestNetworkBuilder::new() + let mut network = TestNetworkBuilder::new(Handle::current()) .with_chain_sync((chain_sync, chain_sync_service)) .build(); @@ -146,7 +147,7 @@ async fn clear_justification_requests() { .await; } -#[async_std::test] +#[tokio::test] async fn set_sync_fork_request() { // build `ChainSync` and set default expectations for it let mut chain_sync = @@ -171,7 +172,7 @@ async fn set_sync_fork_request() { .once() .returning(|_, _, _| ()); - let mut network = TestNetworkBuilder::new() + let mut network = TestNetworkBuilder::new(Handle::current()) .with_chain_sync((chain_sync, Box::new(chain_sync_service))) .build(); @@ -185,7 +186,7 @@ async fn set_sync_fork_request() { .await; } -#[async_std::test] +#[tokio::test] async fn on_block_finalized() { let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be @@ -215,7 +216,7 @@ async fn on_block_finalized() { .returning(|_, _| ()); set_default_expecations_no_peers(&mut chain_sync); - let mut network = TestNetworkBuilder::new() + let mut network = TestNetworkBuilder::new(Handle::current()) .with_client(client) .with_chain_sync((chain_sync, chain_sync_service)) .build(); @@ -232,7 +233,7 @@ async fn on_block_finalized() { // report from mock import queue that importing a justification was not successful // and verify that connection to the peer is closed -#[async_std::test] +#[tokio::test] async fn invalid_justification_imported() { struct DummyImportQueue( Arc< @@ -279,13 +280,13 @@ async fn invalid_justification_imported() { let justification_info = Arc::new(RwLock::new(None)); let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (service1, mut event_stream1) = TestNetworkBuilder::new() + let (service1, mut event_stream1) = TestNetworkBuilder::new(Handle::current()) .with_import_queue(Box::new(DummyImportQueue(justification_info.clone()))) .with_listen_addresses(vec![listen_addr.clone()]) .build() .start_network(); - let (service2, mut event_stream2) = TestNetworkBuilder::new() + let (service2, mut event_stream2) = TestNetworkBuilder::new(Handle::current()) .with_set_config(SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -320,15 +321,12 @@ async fn invalid_justification_imported() { while !std::matches!(event_stream1.next().await, Some(Event::SyncDisconnected { .. })) {} }; - if async_std::future::timeout(Duration::from_secs(5), wait_disconnection) - .await - .is_err() - { + if tokio::time::timeout(Duration::from_secs(5), wait_disconnection).await.is_err() { panic!("did not receive disconnection event in time"); } } -#[async_std::test] +#[tokio::test] async fn disconnect_peer_using_chain_sync_handle() { let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); let listen_addr = config::build_multiaddr![Memory(rand::random::())]; @@ -353,7 +351,7 @@ async fn disconnect_peer_using_chain_sync_handle() { ) .unwrap(); - let (node1, mut event_stream1) = TestNetworkBuilder::new() + let (node1, mut event_stream1) = TestNetworkBuilder::new(Handle::current()) .with_listen_addresses(vec![listen_addr.clone()]) .with_chain_sync((Box::new(chain_sync), chain_sync_service)) .with_chain_sync_network((chain_sync_network_provider, chain_sync_network_handle)) @@ -361,7 +359,7 @@ async fn disconnect_peer_using_chain_sync_handle() { .build() .start_network(); - let (node2, mut event_stream2) = TestNetworkBuilder::new() + let (node2, mut event_stream2) = TestNetworkBuilder::new(Handle::current()) .with_set_config(SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -394,10 +392,7 @@ async fn disconnect_peer_using_chain_sync_handle() { while !std::matches!(event_stream1.next().await, Some(Event::SyncDisconnected { .. })) {} }; - if async_std::future::timeout(Duration::from_secs(5), wait_disconnection) - .await - .is_err() - { + if tokio::time::timeout(Duration::from_secs(5), wait_disconnection).await.is_err() { panic!("did not receive disconnection event in time"); } } diff --git a/client/network/src/service/tests/mod.rs b/client/network/src/service/tests/mod.rs index 1d91fc142672f..f8635e39e9da9 100644 --- a/client/network/src/service/tests/mod.rs +++ b/client/network/src/service/tests/mod.rs @@ -44,6 +44,7 @@ use substrate_test_runtime_client::{ runtime::{Block as TestBlock, Hash as TestHash}, TestClient, TestClientBuilder, TestClientBuilderExt as _, }; +use tokio::runtime::Handle; #[cfg(test)] mod chain_sync; @@ -58,11 +59,12 @@ const PROTOCOL_NAME: &str = "/foo"; struct TestNetwork { network: TestNetworkWorker, + rt_handle: Handle, } impl TestNetwork { - pub fn new(network: TestNetworkWorker) -> Self { - Self { network } + pub fn new(network: TestNetworkWorker, rt_handle: Handle) -> Self { + Self { network, rt_handle } } pub fn service(&self) -> &Arc { @@ -80,7 +82,7 @@ impl TestNetwork { let service = worker.service().clone(); let event_stream = service.event_stream("test"); - async_std::task::spawn(async move { + self.rt_handle.spawn(async move { futures::pin_mut!(worker); let _ = worker.await; }); @@ -97,10 +99,11 @@ struct TestNetworkBuilder { chain_sync: Option<(Box>, Box>)>, chain_sync_network: Option<(NetworkServiceProvider, NetworkServiceHandle)>, config: Option, + rt_handle: Handle, } impl TestNetworkBuilder { - pub fn new() -> Self { + pub fn new(rt_handle: Handle) -> Self { Self { import_queue: None, client: None, @@ -109,6 +112,7 @@ impl TestNetworkBuilder { chain_sync: None, chain_sync_network: None, config: None, + rt_handle, } } @@ -222,21 +226,21 @@ impl TestNetworkBuilder { let block_request_protocol_config = { let (handler, protocol_config) = BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); - async_std::task::spawn(handler.run().boxed()); + self.rt_handle.spawn(handler.run().boxed()); protocol_config }; let state_request_protocol_config = { let (handler, protocol_config) = StateRequestHandler::new(&protocol_id, None, client.clone(), 50); - async_std::task::spawn(handler.run().boxed()); + self.rt_handle.spawn(handler.run().boxed()); protocol_config }; let light_client_request_protocol_config = { let (handler, protocol_config) = LightClientRequestHandler::new(&protocol_id, None, client.clone()); - async_std::task::spawn(handler.run().boxed()); + self.rt_handle.spawn(handler.run().boxed()); protocol_config }; @@ -295,6 +299,11 @@ impl TestNetworkBuilder { (Box::new(chain_sync), chain_sync_service) }); + let handle = self.rt_handle.clone(); + let executor = move |f| { + handle.spawn(f); + }; + let worker = NetworkWorker::< substrate_test_runtime_client::runtime::Block, substrate_test_runtime_client::runtime::Hash, @@ -302,7 +311,7 @@ impl TestNetworkBuilder { >::new(config::Params { block_announce_config, role: config::Role::Full, - executor: None, + executor: Box::new(executor), network_config, chain: client.clone(), protocol_id, @@ -321,10 +330,10 @@ impl TestNetworkBuilder { .unwrap(); let service = worker.service().clone(); - async_std::task::spawn(async move { + self.rt_handle.spawn(async move { let _ = chain_sync_network_provider.run(service).await; }); - TestNetwork::new(worker) + TestNetwork::new(worker, self.rt_handle) } } diff --git a/client/network/src/service/tests/service.rs b/client/network/src/service/tests/service.rs index 90945fdcef2cf..aa74e595fff7e 100644 --- a/client/network/src/service/tests/service.rs +++ b/client/network/src/service/tests/service.rs @@ -26,6 +26,7 @@ use sc_network_common::{ service::{NetworkNotification, NetworkPeers, NetworkStateInfo}, }; use std::{sync::Arc, time::Duration}; +use tokio::runtime::Handle; type TestNetworkService = NetworkService< substrate_test_runtime_client::runtime::Block, @@ -37,7 +38,9 @@ const PROTOCOL_NAME: &str = "/foo"; /// Builds two nodes and their associated events stream. /// The nodes are connected together and have the `PROTOCOL_NAME` protocol registered. -fn build_nodes_one_proto() -> ( +fn build_nodes_one_proto( + rt_handle: &Handle, +) -> ( Arc, impl Stream, Arc, @@ -45,12 +48,12 @@ fn build_nodes_one_proto() -> ( ) { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (node1, events_stream1) = TestNetworkBuilder::new() + let (node1, events_stream1) = TestNetworkBuilder::new(rt_handle.clone()) .with_listen_addresses(vec![listen_addr.clone()]) .build() .start_network(); - let (node2, events_stream2) = TestNetworkBuilder::new() + let (node2, events_stream2) = TestNetworkBuilder::new(rt_handle.clone()) .with_set_config(SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -69,7 +72,10 @@ fn notifications_state_consistent() { // Runs two nodes and ensures that events are propagated out of the API in a consistent // correct order, which means no notification received on a closed substream. - let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); + let runtime = tokio::runtime::Runtime::new().unwrap(); + + let (node1, mut events_stream1, node2, mut events_stream2) = + build_nodes_one_proto(runtime.handle()); // Write some initial notifications that shouldn't get through. for _ in 0..(rand::random::() % 5) { @@ -87,7 +93,7 @@ fn notifications_state_consistent() { ); } - async_std::task::block_on(async move { + runtime.block_on(async move { // True if we have an active substream from node1 to node2. let mut node1_to_node2_open = false; // True if we have an active substream from node2 to node1. @@ -216,11 +222,11 @@ fn notifications_state_consistent() { }); } -#[async_std::test] +#[tokio::test] async fn lots_of_incoming_peers_works() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (main_node, _) = TestNetworkBuilder::new() + let (main_node, _) = TestNetworkBuilder::new(Handle::current()) .with_listen_addresses(vec![listen_addr.clone()]) .with_set_config(SetConfig { in_peers: u32::MAX, ..Default::default() }) .build() @@ -233,7 +239,7 @@ async fn lots_of_incoming_peers_works() { let mut background_tasks_to_wait = Vec::new(); for _ in 0..32 { - let (_dialing_node, event_stream) = TestNetworkBuilder::new() + let (_dialing_node, event_stream) = TestNetworkBuilder::new(Handle::current()) .with_set_config(SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr.clone(), @@ -244,7 +250,7 @@ async fn lots_of_incoming_peers_works() { .build() .start_network(); - background_tasks_to_wait.push(async_std::task::spawn(async move { + background_tasks_to_wait.push(tokio::spawn(async move { // Create a dummy timer that will "never" fire, and that will be overwritten when we // actually need the timer. Using an Option would be technically cleaner, but it would // make the code below way more complicated. @@ -287,10 +293,13 @@ fn notifications_back_pressure() { const TOTAL_NOTIFS: usize = 10_000; - let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); + let runtime = tokio::runtime::Runtime::new().unwrap(); + + let (node1, mut events_stream1, node2, mut events_stream2) = + build_nodes_one_proto(runtime.handle()); let node2_id = node2.local_peer_id(); - let receiver = async_std::task::spawn(async move { + let receiver = runtime.spawn(async move { let mut received_notifications = 0; while received_notifications < TOTAL_NOTIFS { @@ -306,12 +315,12 @@ fn notifications_back_pressure() { }; if rand::random::() < 2 { - async_std::task::sleep(Duration::from_millis(rand::random::() % 750)).await; + tokio::time::sleep(Duration::from_millis(rand::random::() % 750)).await; } } }); - async_std::task::block_on(async move { + runtime.block_on(async move { // Wait for the `NotificationStreamOpened`. loop { match events_stream1.next().await.unwrap() { @@ -331,7 +340,7 @@ fn notifications_back_pressure() { .unwrap(); } - receiver.await; + receiver.await.unwrap(); }); } @@ -341,8 +350,10 @@ fn fallback_name_working() { // they can connect. const NEW_PROTOCOL_NAME: &str = "/new-shiny-protocol-that-isnt-PROTOCOL_NAME"; + let runtime = tokio::runtime::Runtime::new().unwrap(); + let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (node1, mut events_stream1) = TestNetworkBuilder::new() + let (node1, mut events_stream1) = TestNetworkBuilder::new(runtime.handle().clone()) .with_config(config::NetworkConfiguration { extra_sets: vec![NonDefaultSetConfig { notifications_protocol: NEW_PROTOCOL_NAME.into(), @@ -358,7 +369,7 @@ fn fallback_name_working() { .build() .start_network(); - let (_, mut events_stream2) = TestNetworkBuilder::new() + let (_, mut events_stream2) = TestNetworkBuilder::new(runtime.handle().clone()) .with_set_config(SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -369,7 +380,7 @@ fn fallback_name_working() { .build() .start_network(); - let receiver = async_std::task::spawn(async move { + let receiver = runtime.spawn(async move { // Wait for the `NotificationStreamOpened`. loop { match events_stream2.next().await.unwrap() { @@ -383,7 +394,7 @@ fn fallback_name_working() { } }); - async_std::task::block_on(async move { + runtime.block_on(async move { // Wait for the `NotificationStreamOpened`. loop { match events_stream1.next().await.unwrap() { @@ -397,15 +408,16 @@ fn fallback_name_working() { }; } - receiver.await; + receiver.await.unwrap(); }); } // Disconnect peer by calling `Protocol::disconnect_peer()` with the supplied block announcement // protocol name and verify that `SyncDisconnected` event is emitted -#[async_std::test] +#[tokio::test] async fn disconnect_sync_peer_using_block_announcement_protocol_name() { - let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); + let (node1, mut events_stream1, node2, mut events_stream2) = + build_nodes_one_proto(&Handle::current()); async fn wait_for_events(stream: &mut (impl Stream + std::marker::Unpin)) { let mut notif_received = false; @@ -437,12 +449,12 @@ async fn disconnect_sync_peer_using_block_announcement_protocol_name() { assert!(std::matches!(events_stream2.next().await, Some(Event::SyncDisconnected { .. }))); } -#[test] +#[tokio::test] #[should_panic(expected = "don't match the transport")] -fn ensure_listen_addresses_consistent_with_transport_memory() { +async fn ensure_listen_addresses_consistent_with_transport_memory() { let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)]; - let _ = TestNetworkBuilder::new() + let _ = TestNetworkBuilder::new(Handle::current()) .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, @@ -457,12 +469,12 @@ fn ensure_listen_addresses_consistent_with_transport_memory() { .start_network(); } -#[test] +#[tokio::test] #[should_panic(expected = "don't match the transport")] -fn ensure_listen_addresses_consistent_with_transport_not_memory() { +async fn ensure_listen_addresses_consistent_with_transport_not_memory() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let _ = TestNetworkBuilder::new() + let _ = TestNetworkBuilder::new(Handle::current()) .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], ..config::NetworkConfiguration::new( @@ -476,16 +488,16 @@ fn ensure_listen_addresses_consistent_with_transport_not_memory() { .start_network(); } -#[test] +#[tokio::test] #[should_panic(expected = "don't match the transport")] -fn ensure_boot_node_addresses_consistent_with_transport_memory() { +async fn ensure_boot_node_addresses_consistent_with_transport_memory() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let boot_node = MultiaddrWithPeerId { multiaddr: config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)], peer_id: PeerId::random(), }; - let _ = TestNetworkBuilder::new() + let _ = TestNetworkBuilder::new(Handle::current()) .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, @@ -501,16 +513,16 @@ fn ensure_boot_node_addresses_consistent_with_transport_memory() { .start_network(); } -#[test] +#[tokio::test] #[should_panic(expected = "don't match the transport")] -fn ensure_boot_node_addresses_consistent_with_transport_not_memory() { +async fn ensure_boot_node_addresses_consistent_with_transport_not_memory() { let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)]; let boot_node = MultiaddrWithPeerId { multiaddr: config::build_multiaddr![Memory(rand::random::())], peer_id: PeerId::random(), }; - let _ = TestNetworkBuilder::new() + let _ = TestNetworkBuilder::new(Handle::current()) .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], boot_nodes: vec![boot_node], @@ -525,16 +537,16 @@ fn ensure_boot_node_addresses_consistent_with_transport_not_memory() { .start_network(); } -#[test] +#[tokio::test] #[should_panic(expected = "don't match the transport")] -fn ensure_reserved_node_addresses_consistent_with_transport_memory() { +async fn ensure_reserved_node_addresses_consistent_with_transport_memory() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let reserved_node = MultiaddrWithPeerId { multiaddr: config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)], peer_id: PeerId::random(), }; - let _ = TestNetworkBuilder::new() + let _ = TestNetworkBuilder::new(Handle::current()) .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, @@ -553,16 +565,16 @@ fn ensure_reserved_node_addresses_consistent_with_transport_memory() { .start_network(); } -#[test] +#[tokio::test] #[should_panic(expected = "don't match the transport")] -fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { +async fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)]; let reserved_node = MultiaddrWithPeerId { multiaddr: config::build_multiaddr![Memory(rand::random::())], peer_id: PeerId::random(), }; - let _ = TestNetworkBuilder::new() + let _ = TestNetworkBuilder::new(Handle::current()) .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], default_peers_set: SetConfig { @@ -580,13 +592,13 @@ fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { .start_network(); } -#[test] +#[tokio::test] #[should_panic(expected = "don't match the transport")] -fn ensure_public_addresses_consistent_with_transport_memory() { +async fn ensure_public_addresses_consistent_with_transport_memory() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let public_address = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)]; - let _ = TestNetworkBuilder::new() + let _ = TestNetworkBuilder::new(Handle::current()) .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, @@ -602,13 +614,13 @@ fn ensure_public_addresses_consistent_with_transport_memory() { .start_network(); } -#[test] +#[tokio::test] #[should_panic(expected = "don't match the transport")] -fn ensure_public_addresses_consistent_with_transport_not_memory() { +async fn ensure_public_addresses_consistent_with_transport_not_memory() { let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)]; let public_address = config::build_multiaddr![Memory(rand::random::())]; - let _ = TestNetworkBuilder::new() + let _ = TestNetworkBuilder::new(Handle::current()) .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], public_addresses: vec![public_address], diff --git a/client/network/src/transport.rs b/client/network/src/transport.rs index 23645b11795c3..b0d5f0235b6e4 100644 --- a/client/network/src/transport.rs +++ b/client/network/src/transport.rs @@ -55,16 +55,16 @@ pub fn build_transport( // Build the base layer of the transport. let transport = if !memory_only { let tcp_config = tcp::GenTcpConfig::new().nodelay(true); - let desktop_trans = tcp::TcpTransport::new(tcp_config.clone()); + let desktop_trans = tcp::TokioTcpTransport::new(tcp_config.clone()); let desktop_trans = websocket::WsConfig::new(desktop_trans) - .or_transport(tcp::TcpTransport::new(tcp_config.clone())); - let dns_init = futures::executor::block_on(dns::DnsConfig::system(desktop_trans)); + .or_transport(tcp::TokioTcpTransport::new(tcp_config.clone())); + let dns_init = dns::TokioDnsConfig::system(desktop_trans); EitherTransport::Left(if let Ok(dns) = dns_init { EitherTransport::Left(dns) } else { - let desktop_trans = tcp::TcpTransport::new(tcp_config.clone()); + let desktop_trans = tcp::TokioTcpTransport::new(tcp_config.clone()); let desktop_trans = websocket::WsConfig::new(desktop_trans) - .or_transport(tcp::TcpTransport::new(tcp_config)); + .or_transport(tcp::TokioTcpTransport::new(tcp_config)); EitherTransport::Right(desktop_trans.map_err(dns::DnsErr::Transport)) }) } else { diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 841388c7a68ee..263c2d40c2273 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -42,7 +42,7 @@ sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/final sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [dev-dependencies] -async-std = { version = "1.11.0", features = ["attributes"] } +tokio = { version = "1.22.0", features = ["macros"] } quickcheck = { version = "1.0.3", default-features = false } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-test-primitives = { version = "2.0.0", path = "../../../primitives/test-primitives" } diff --git a/client/network/sync/src/service/network.rs b/client/network/sync/src/service/network.rs index 43501baeec7be..c44398b0f1a9e 100644 --- a/client/network/sync/src/service/network.rs +++ b/client/network/sync/src/service/network.rs @@ -126,7 +126,7 @@ mod tests { // typical pattern in `Protocol` code where peer is disconnected // and then reported - #[async_std::test] + #[tokio::test] async fn disconnect_and_report_peer() { let (provider, handle) = NetworkServiceProvider::new(); @@ -147,7 +147,7 @@ mod tests { .once() .returning(|_, _| ()); - async_std::task::spawn(async move { + tokio::spawn(async move { provider.run(Arc::new(mock_network)).await; }); diff --git a/client/network/sync/src/tests.rs b/client/network/sync/src/tests.rs index bd78c3b45226d..a03e657f03ab2 100644 --- a/client/network/sync/src/tests.rs +++ b/client/network/sync/src/tests.rs @@ -35,7 +35,7 @@ use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _ // verify that the fork target map is empty, then submit a new sync fork request, // poll `ChainSync` and verify that a new sync fork request has been registered -#[async_std::test] +#[tokio::test] async fn delegate_to_chainsync() { let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let (mut chain_sync, chain_sync_service, _) = ChainSync::new( diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index eb4d54b9dc82d..86b5be37d256a 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-std = "1.11.0" +tokio = "1.22.0" async-trait = "0.1.57" futures = "0.3.21" futures-timer = "3.0.1" diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 4eb93499d7435..d3642e69cb632 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -31,7 +31,6 @@ use std::{ time::Duration, }; -use async_std::future::timeout; use futures::{future::BoxFuture, prelude::*}; use libp2p::{build_multiaddr, PeerId}; use log::trace; @@ -85,6 +84,7 @@ pub use substrate_test_runtime_client::{ runtime::{Block, Extrinsic, Hash, Transfer}, TestClient, TestClientBuilder, TestClientBuilderExt, }; +use tokio::time::timeout; type AuthorityId = sp_consensus_babe::AuthorityId; @@ -708,7 +708,16 @@ pub struct FullPeerConfig { pub storage_chain: bool, } -pub trait TestNetFactory: Default + Sized +/// Trait for text fixtures with tokio runtime. +pub trait WithRuntime { + /// Construct with runtime handle. + fn with_runtime(rt_handle: tokio::runtime::Handle) -> Self; + /// Get runtime handle. + fn rt_handle(&self) -> &tokio::runtime::Handle; +} + +#[async_trait::async_trait] +pub trait TestNetFactory: WithRuntime + Sized where >::Transaction: Send, { @@ -738,9 +747,9 @@ where ); /// Create new test network with this many peers. - fn new(n: usize) -> Self { + fn new(rt_handle: tokio::runtime::Handle, n: usize) -> Self { trace!(target: "test_network", "Creating test network"); - let mut net = Self::default(); + let mut net = Self::with_runtime(rt_handle); for i in 0..n { trace!(target: "test_network", "Adding peer {}", i); @@ -894,9 +903,14 @@ where ) .unwrap(); + let handle = self.rt_handle().clone(); + let executor = move |f| { + handle.spawn(f); + }; + let network = NetworkWorker::new(sc_network::config::Params { role: if config.is_authority { Role::Authority } else { Role::Full }, - executor: None, + executor: Box::new(executor), network_config, chain: client.clone(), protocol_id, @@ -919,7 +933,7 @@ where trace!(target: "test_network", "Peer identifier: {}", network.service().local_peer_id()); let service = network.service().clone(); - async_std::task::spawn(async move { + self.rt_handle().spawn(async move { chain_sync_network_provider.run(service).await; }); @@ -950,7 +964,7 @@ where /// Used to spawn background tasks, e.g. the block request protocol handler. fn spawn_task(&self, f: BoxFuture<'static, ()>) { - async_std::task::spawn(f); + self.rt_handle().spawn(f); } /// Polls the testnet until all nodes are in sync. @@ -1009,34 +1023,31 @@ where Poll::Pending } - /// Blocks the current thread until we are sync'ed. + /// Wait until we are sync'ed. /// /// Calls `poll_until_sync` repeatedly. /// (If we've not synced within 10 mins then panic rather than hang.) - fn block_until_sync(&mut self) { - futures::executor::block_on(timeout( + async fn wait_until_sync(&mut self) { + timeout( Duration::from_secs(10 * 60), futures::future::poll_fn::<(), _>(|cx| self.poll_until_sync(cx)), - )) + ) + .await .expect("sync didn't happen within 10 mins"); } - /// Blocks the current thread until there are no pending packets. + /// Wait until there are no pending packets. /// /// Calls `poll_until_idle` repeatedly with the runtime passed as parameter. - fn block_until_idle(&mut self) { - futures::executor::block_on(futures::future::poll_fn::<(), _>(|cx| { - self.poll_until_idle(cx) - })); + async fn wait_until_idle(&mut self) { + futures::future::poll_fn::<(), _>(|cx| self.poll_until_idle(cx)).await; } - /// Blocks the current thread until all peers are connected to each other. + /// Wait until all peers are connected to each other. /// /// Calls `poll_until_connected` repeatedly with the runtime passed as parameter. - fn block_until_connected(&mut self) { - futures::executor::block_on(futures::future::poll_fn::<(), _>(|cx| { - self.poll_until_connected(cx) - })); + async fn wait_until_connected(&mut self) { + futures::future::poll_fn::<(), _>(|cx| self.poll_until_connected(cx)).await; } /// Polls the testnet. Processes all the pending actions. @@ -1067,11 +1078,20 @@ where } } -#[derive(Default)] pub struct TestNet { + rt_handle: tokio::runtime::Handle, peers: Vec>, } +impl WithRuntime for TestNet { + fn with_runtime(rt_handle: tokio::runtime::Handle) -> Self { + TestNet { rt_handle, peers: Vec::new() } + } + fn rt_handle(&self) -> &tokio::runtime::Handle { + &self.rt_handle + } +} + impl TestNetFactory for TestNet { type Verifier = PassThroughVerifier; type PeerData = (); @@ -1126,10 +1146,17 @@ impl JustificationImport for ForceFinalized { .map_err(|_| ConsensusError::InvalidJustification) } } - -#[derive(Default)] pub struct JustificationTestNet(TestNet); +impl WithRuntime for JustificationTestNet { + fn with_runtime(rt_handle: tokio::runtime::Handle) -> Self { + JustificationTestNet(TestNet::with_runtime(rt_handle)) + } + fn rt_handle(&self) -> &tokio::runtime::Handle { + &self.0.rt_handle() + } +} + impl TestNetFactory for JustificationTestNet { type Verifier = PassThroughVerifier; type PeerData = (); diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index ea3895cb4dfde..efe0e0577c11e 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -17,14 +17,16 @@ // along with this program. If not, see . use super::*; -use futures::{executor::block_on, Future}; +use futures::Future; use sp_consensus::{block_validation::Validation, BlockOrigin}; use sp_runtime::Justifications; use substrate_test_runtime::Header; +use tokio::runtime::Runtime; fn test_ancestor_search_when_common_is(n: usize) { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); net.peer(0).push_blocks(n, false); net.peer(1).push_blocks(n, false); @@ -34,7 +36,7 @@ fn test_ancestor_search_when_common_is(n: usize) { net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); } @@ -42,9 +44,10 @@ fn test_ancestor_search_when_common_is(n: usize) { #[test] fn sync_peers_works() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); for peer in 0..3 { if net.peer(peer).num_peers() != 2 { @@ -58,7 +61,8 @@ fn sync_peers_works() { #[test] fn sync_cycle_from_offline_to_syncing_to_offline() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); for peer in 0..3 { // Offline, and not major syncing. assert!(net.peer(peer).is_offline()); @@ -69,7 +73,7 @@ fn sync_cycle_from_offline_to_syncing_to_offline() { net.peer(2).push_blocks(100, false); // Block until all nodes are online and nodes 0 and 1 and major syncing. - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); for peer in 0..3 { // Online @@ -87,7 +91,7 @@ fn sync_cycle_from_offline_to_syncing_to_offline() { })); // Block until all nodes are done syncing. - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); for peer in 0..3 { if net.peer(peer).is_major_syncing() { @@ -100,7 +104,7 @@ fn sync_cycle_from_offline_to_syncing_to_offline() { // Now drop nodes 1 and 2, and check that node 0 is offline. net.peers.remove(2); net.peers.remove(1); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if !net.peer(0).is_offline() { Poll::Pending @@ -113,7 +117,8 @@ fn sync_cycle_from_offline_to_syncing_to_offline() { #[test] fn syncing_node_not_major_syncing_when_disconnected() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); // Generate blocks. net.peer(2).push_blocks(100, false); @@ -122,7 +127,7 @@ fn syncing_node_not_major_syncing_when_disconnected() { assert!(!net.peer(1).is_major_syncing()); // Check that we switch to major syncing. - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if !net.peer(1).is_major_syncing() { Poll::Pending @@ -134,7 +139,7 @@ fn syncing_node_not_major_syncing_when_disconnected() { // Destroy two nodes, and check that we switch to non-major syncing. net.peers.remove(2); net.peers.remove(0); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).is_major_syncing() { Poll::Pending @@ -147,10 +152,11 @@ fn syncing_node_not_major_syncing_when_disconnected() { #[test] fn sync_from_two_peers_works() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); assert!(!net.peer(0).is_major_syncing()); @@ -159,11 +165,12 @@ fn sync_from_two_peers_works() { #[test] fn sync_from_two_peers_with_ancestry_search_works() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); net.peer(0).push_blocks(10, true); net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); } @@ -171,13 +178,14 @@ fn sync_from_two_peers_with_ancestry_search_works() { #[test] fn ancestry_search_works_when_backoff_is_one() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); net.peer(0).push_blocks(1, false); net.peer(1).push_blocks(2, false); net.peer(2).push_blocks(2, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); } @@ -185,13 +193,14 @@ fn ancestry_search_works_when_backoff_is_one() { #[test] fn ancestry_search_works_when_ancestor_is_genesis() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); net.peer(0).push_blocks(13, true); net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); } @@ -214,9 +223,10 @@ fn ancestry_search_works_when_common_is_hundred() { #[test] fn sync_long_chain_works() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(2); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 2); net.peer(1).push_blocks(500, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); } @@ -224,10 +234,11 @@ fn sync_long_chain_works() { #[test] fn sync_no_common_longer_chain_fails() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); net.peer(0).push_blocks(20, true); net.peer(1).push_blocks(20, false); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).is_major_syncing() { Poll::Pending @@ -242,9 +253,10 @@ fn sync_no_common_longer_chain_fails() { #[test] fn sync_justifications() { sp_tracing::try_init_simple(); - let mut net = JustificationTestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = JustificationTestNet::new(runtime.handle().clone(), 3); net.peer(0).push_blocks(20, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let backend = net.peer(0).client().as_backend(); let hashof10 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(10)).unwrap(); @@ -270,7 +282,7 @@ fn sync_justifications() { net.peer(1).request_justification(&hashof15, 15); net.peer(1).request_justification(&hashof20, 20); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); for hash in [hashof10, hashof15, hashof20] { @@ -293,7 +305,8 @@ fn sync_justifications() { #[test] fn sync_justifications_across_forks() { sp_tracing::try_init_simple(); - let mut net = JustificationTestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = JustificationTestNet::new(runtime.handle().clone(), 3); // we push 5 blocks net.peer(0).push_blocks(5, false); // and then two forks 5 and 6 blocks long @@ -302,7 +315,7 @@ fn sync_justifications_across_forks() { // peer 1 will only see the longer fork. but we'll request justifications // for both and finalize the small fork instead. - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let just = (*b"FRNK", Vec::new()); net.peer(0).client().finalize_block(f1_best, Some(just), true).unwrap(); @@ -310,7 +323,7 @@ fn sync_justifications_across_forks() { net.peer(1).request_justification(&f1_best, 10); net.peer(1).request_justification(&f2_best, 11); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).client().justifications(f1_best).unwrap() == @@ -328,7 +341,8 @@ fn sync_justifications_across_forks() { #[test] fn sync_after_fork_works() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); net.peer(0).push_blocks(30, false); net.peer(1).push_blocks(30, false); net.peer(2).push_blocks(30, false); @@ -341,7 +355,7 @@ fn sync_after_fork_works() { net.peer(2).push_blocks(1, false); // peer 1 has the best chain - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); (net.peers()[1].blockchain_canon_equals(peer1)); @@ -351,14 +365,15 @@ fn sync_after_fork_works() { #[test] fn syncs_all_forks() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(4); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 4); net.peer(0).push_blocks(2, false); net.peer(1).push_blocks(2, false); let b1 = net.peer(0).push_blocks(2, true); let b2 = net.peer(1).push_blocks(4, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); // Check that all peers have all of the branches. assert!(net.peer(0).has_block(b1)); assert!(net.peer(0).has_block(b2)); @@ -369,12 +384,13 @@ fn syncs_all_forks() { #[test] fn own_blocks_are_announced() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); - net.block_until_sync(); // connect'em + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); + runtime.block_on(net.wait_until_sync()); // connect'em net.peer(0) .generate_blocks(1, BlockOrigin::Own, |builder| builder.build().unwrap().block); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert_eq!(net.peer(0).client.info().best_number, 1); assert_eq!(net.peer(1).client.info().best_number, 1); @@ -386,7 +402,8 @@ fn own_blocks_are_announced() { #[test] fn can_sync_small_non_best_forks() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(2); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 2); net.peer(0).push_blocks(30, false); net.peer(1).push_blocks(30, false); @@ -404,7 +421,7 @@ fn can_sync_small_non_best_forks() { assert!(net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_none()); // poll until the two nodes connect, otherwise announcing the block will not work - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).num_peers() == 0 { Poll::Pending @@ -424,7 +441,7 @@ fn can_sync_small_non_best_forks() { // after announcing, peer 1 downloads the block. - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); @@ -433,11 +450,11 @@ fn can_sync_small_non_best_forks() { } Poll::Ready(()) })); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let another_fork = net.peer(0).push_blocks_at(BlockId::Number(35), 2, true); net.peer(0).announce_block(another_fork, None); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).client().header(&BlockId::Hash(another_fork)).unwrap().is_none() { return Poll::Pending @@ -449,11 +466,12 @@ fn can_sync_small_non_best_forks() { #[test] fn can_sync_forks_ahead_of_the_best_chain() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(2); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 2); net.peer(0).push_blocks(1, false); net.peer(1).push_blocks(1, false); - net.block_until_connected(); + runtime.block_on(net.wait_until_connected()); // Peer 0 is on 2-block fork which is announced with is_best=false let fork_hash = net.peer(0).generate_blocks_with_fork_choice( 2, @@ -468,7 +486,7 @@ fn can_sync_forks_ahead_of_the_best_chain() { assert_eq!(net.peer(1).client().info().best_number, 2); // after announcing, peer 1 downloads the block. - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).client().header(&BlockId::Hash(fork_hash)).unwrap().is_none() { @@ -481,7 +499,8 @@ fn can_sync_forks_ahead_of_the_best_chain() { #[test] fn can_sync_explicit_forks() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(2); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 2); net.peer(0).push_blocks(30, false); net.peer(1).push_blocks(30, false); @@ -500,7 +519,7 @@ fn can_sync_explicit_forks() { assert!(net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_none()); // poll until the two nodes connect, otherwise announcing the block will not work - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { Poll::Pending @@ -521,7 +540,7 @@ fn can_sync_explicit_forks() { net.peer(1).set_sync_fork_request(vec![first_peer_id], small_hash, small_number); // peer 1 downloads the block. - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); @@ -535,7 +554,8 @@ fn can_sync_explicit_forks() { #[test] fn syncs_header_only_forks() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(0); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 0); net.add_full_peer_with_config(Default::default()); net.add_full_peer_with_config(FullPeerConfig { blocks_pruning: Some(3), ..Default::default() }); net.peer(0).push_blocks(2, false); @@ -547,10 +567,10 @@ fn syncs_header_only_forks() { // Peer 1 will sync the small fork even though common block state is missing while !net.peer(1).has_block(small_hash) { - net.block_until_idle(); + runtime.block_on(net.wait_until_idle()); } - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert_eq!(net.peer(0).client().info().best_hash, net.peer(1).client().info().best_hash); assert_ne!(small_hash, net.peer(0).client().info().best_hash); } @@ -558,7 +578,8 @@ fn syncs_header_only_forks() { #[test] fn does_not_sync_announced_old_best_block() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(3); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 3); let old_hash = net.peer(0).push_blocks(1, false); let old_hash_with_parent = net.peer(0).push_blocks(1, false); @@ -566,7 +587,7 @@ fn does_not_sync_announced_old_best_block() { net.peer(1).push_blocks(20, true); net.peer(0).announce_block(old_hash, None); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { // poll once to import announcement net.poll(cx); Poll::Ready(()) @@ -574,7 +595,7 @@ fn does_not_sync_announced_old_best_block() { assert!(!net.peer(1).is_major_syncing()); net.peer(0).announce_block(old_hash_with_parent, None); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { // poll once to import announcement net.poll(cx); Poll::Ready(()) @@ -586,11 +607,12 @@ fn does_not_sync_announced_old_best_block() { fn full_sync_requires_block_body() { // Check that we don't sync headers-only in full mode. sp_tracing::try_init_simple(); - let mut net = TestNet::new(2); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 2); net.peer(0).push_headers(1); // Wait for nodes to connect - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { Poll::Pending @@ -598,20 +620,21 @@ fn full_sync_requires_block_body() { Poll::Ready(()) } })); - net.block_until_idle(); + runtime.block_on(net.wait_until_idle()); assert_eq!(net.peer(1).client.info().best_number, 0); } #[test] fn imports_stale_once() { sp_tracing::try_init_simple(); + let runtime = Runtime::new().unwrap(); - fn import_with_announce(net: &mut TestNet, hash: H256) { + fn import_with_announce(runtime: &Runtime, net: &mut TestNet, hash: H256) { // Announce twice net.peer(0).announce_block(hash, None); net.peer(0).announce_block(hash, None); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).client().header(&BlockId::Hash(hash)).unwrap().is_some() { Poll::Ready(()) @@ -622,33 +645,34 @@ fn imports_stale_once() { } // given the network with 2 full nodes - let mut net = TestNet::new(2); + let mut net = TestNet::new(runtime.handle().clone(), 2); // let them connect to each other - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); // check that NEW block is imported from announce message let new_hash = net.peer(0).push_blocks(1, false); - import_with_announce(&mut net, new_hash); + import_with_announce(&runtime, &mut net, new_hash); assert_eq!(net.peer(1).num_downloaded_blocks(), 1); // check that KNOWN STALE block is imported from announce message let known_stale_hash = net.peer(0).push_blocks_at(BlockId::Number(0), 1, true); - import_with_announce(&mut net, known_stale_hash); + import_with_announce(&runtime, &mut net, known_stale_hash); assert_eq!(net.peer(1).num_downloaded_blocks(), 2); } #[test] fn can_sync_to_peers_with_wrong_common_block() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(2); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 2); net.peer(0).push_blocks(2, true); net.peer(1).push_blocks(2, true); let fork_hash = net.peer(0).push_blocks_at(BlockId::Number(0), 2, false); net.peer(1).push_blocks_at(BlockId::Number(0), 2, false); // wait for connection - net.block_until_connected(); + runtime.block_on(net.wait_until_connected()); // both peers re-org to the same fork without notifying each other let just = Some((*b"FRNK", Vec::new())); @@ -656,7 +680,7 @@ fn can_sync_to_peers_with_wrong_common_block() { net.peer(1).client().finalize_block(fork_hash, just, true).unwrap(); let final_hash = net.peer(0).push_blocks(1, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert!(net.peer(1).has_block(final_hash)); } @@ -701,7 +725,8 @@ impl BlockAnnounceValidator for FailingBlockAnnounceValidator { #[test] fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(0); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 0); net.add_full_peer_with_config(Default::default()); net.add_full_peer_with_config(Default::default()); net.add_full_peer_with_config(FullPeerConfig { @@ -709,7 +734,7 @@ fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { ..Default::default() }); - net.block_until_connected(); + runtime.block_on(net.wait_until_connected()); // Add blocks but don't set them as best let block_hash = net.peer(0).generate_blocks_with_fork_choice( @@ -720,7 +745,7 @@ fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { ); while !net.peer(2).has_block(block_hash) { - net.block_until_idle(); + runtime.block_on(net.wait_until_idle()); } } @@ -745,14 +770,15 @@ impl BlockAnnounceValidator for DeferredBlockAnnounceValidator { #[test] fn wait_until_deferred_block_announce_validation_is_ready() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(0); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 0); net.add_full_peer_with_config(Default::default()); net.add_full_peer_with_config(FullPeerConfig { block_announce_validator: Some(Box::new(NewBestBlockAnnounceValidator)), ..Default::default() }); - net.block_until_connected(); + runtime.block_on(net.wait_until_connected()); // Add blocks but don't set them as best let block_hash = net.peer(0).generate_blocks_with_fork_choice( @@ -763,7 +789,7 @@ fn wait_until_deferred_block_announce_validation_is_ready() { ); while !net.peer(1).has_block(block_hash) { - net.block_until_idle(); + runtime.block_on(net.wait_until_idle()); } } @@ -772,7 +798,8 @@ fn wait_until_deferred_block_announce_validation_is_ready() { #[test] fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 1); // Produce some blocks let block_hash = @@ -780,16 +807,18 @@ fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { .push_blocks_at_without_informing_sync(BlockId::Number(0), 3, true, true); // Add a node and wait until they are connected - net.add_full_peer_with_config(Default::default()); - net.block_until_connected(); - net.block_until_idle(); + runtime.block_on(async { + net.add_full_peer_with_config(Default::default()); + net.wait_until_connected().await; + net.wait_until_idle().await; + }); // The peer should not have synced the block. assert!(!net.peer(1).has_block(block_hash)); // Make sync protocol aware of the best block net.peer(0).network_service().new_best_block_imported(block_hash, 3); - net.block_until_idle(); + runtime.block_on(net.wait_until_idle()); // Connect another node that should now sync to the tip net.add_full_peer_with_config(FullPeerConfig { @@ -797,7 +826,7 @@ fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { ..Default::default() }); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(2).has_block(block_hash) { Poll::Ready(()) @@ -815,8 +844,9 @@ fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { #[test] fn sync_to_tip_when_we_sync_together_with_multiple_peers() { sp_tracing::try_init_simple(); + let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(3); + let mut net = TestNet::new(runtime.handle().clone(), 3); let block_hash = net.peer(0) @@ -825,8 +855,10 @@ fn sync_to_tip_when_we_sync_together_with_multiple_peers() { net.peer(1) .push_blocks_at_without_informing_sync(BlockId::Number(0), 5_000, false, false); - net.block_until_connected(); - net.block_until_idle(); + runtime.block_on(async { + net.wait_until_connected().await; + net.wait_until_idle().await; + }); assert!(!net.peer(2).has_block(block_hash)); @@ -834,7 +866,7 @@ fn sync_to_tip_when_we_sync_together_with_multiple_peers() { net.peer(0).network_service().announce_block(block_hash, None); while !net.peer(2).has_block(block_hash) && !net.peer(1).has_block(block_hash) { - net.block_until_idle(); + runtime.block_on(net.wait_until_idle()); } } @@ -865,7 +897,8 @@ fn block_announce_data_is_propagated() { } sp_tracing::try_init_simple(); - let mut net = TestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 1); net.add_full_peer_with_config(FullPeerConfig { block_announce_validator: Some(Box::new(TestBlockAnnounceValidator)), @@ -879,7 +912,7 @@ fn block_announce_data_is_propagated() { }); // Wait until peer 1 is connected to both nodes. - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).num_peers() == 2 && net.peer(0).num_peers() == 1 && @@ -895,7 +928,7 @@ fn block_announce_data_is_propagated() { net.peer(0).announce_block(block_hash, Some(vec![137])); while !net.peer(1).has_block(block_hash) || !net.peer(2).has_block(block_hash) { - net.block_until_idle(); + runtime.block_on(net.wait_until_idle()); } } @@ -925,19 +958,22 @@ fn continue_to_sync_after_some_block_announcement_verifications_failed() { } sp_tracing::try_init_simple(); - let mut net = TestNet::new(1); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 1); net.add_full_peer_with_config(FullPeerConfig { block_announce_validator: Some(Box::new(TestBlockAnnounceValidator)), ..Default::default() }); - net.block_until_connected(); - net.block_until_idle(); + runtime.block_on(async { + net.wait_until_connected().await; + net.wait_until_idle().await; + }); let block_hash = net.peer(0).push_blocks(500, true); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert!(net.peer(1).has_block(block_hash)); } @@ -948,9 +984,10 @@ fn continue_to_sync_after_some_block_announcement_verifications_failed() { #[test] fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { sp_tracing::try_init_simple(); - let mut net = JustificationTestNet::new(2); + let runtime = Runtime::new().unwrap(); + let mut net = JustificationTestNet::new(runtime.handle().clone(), 2); net.peer(0).push_blocks(10, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); let hashof10 = net.peer(1).client().header(&BlockId::Number(10)).unwrap().unwrap().hash(); @@ -967,7 +1004,7 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { // justification request. std::thread::sleep(std::time::Duration::from_secs(10)); net.peer(0).push_blocks(1, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert_eq!(1, net.peer(0).num_peers()); } @@ -984,7 +1021,7 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { .finalize_block(hashof10, Some((*b"FRNK", Vec::new())), true) .unwrap(); - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).client().justifications(hashof10).unwrap() != @@ -1000,18 +1037,19 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { #[test] fn syncs_all_forks_from_single_peer() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(2); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 2); net.peer(0).push_blocks(10, false); net.peer(1).push_blocks(10, false); // poll until the two nodes connect, otherwise announcing the block will not work - net.block_until_connected(); + runtime.block_on(net.wait_until_connected()); // Peer 0 produces new blocks and announces. let branch1 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, true); // Wait till peer 1 starts downloading - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).network().best_seen_block() != Some(12) { return Poll::Pending @@ -1022,7 +1060,7 @@ fn syncs_all_forks_from_single_peer() { // Peer 0 produces and announces another fork let branch2 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, false); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); // Peer 1 should have both branches, assert!(net.peer(1).client().header(&BlockId::Hash(branch1)).unwrap().is_some()); @@ -1032,7 +1070,8 @@ fn syncs_all_forks_from_single_peer() { #[test] fn syncs_after_missing_announcement() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(0); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 0); net.add_full_peer_with_config(Default::default()); // Set peer 1 to ignore announcement net.add_full_peer_with_config(FullPeerConfig { @@ -1042,22 +1081,23 @@ fn syncs_after_missing_announcement() { net.peer(0).push_blocks(10, false); net.peer(1).push_blocks(10, false); - net.block_until_connected(); + runtime.block_on(net.wait_until_connected()); // Peer 0 produces a new block and announces. Peer 1 ignores announcement. net.peer(0).push_blocks_at(BlockId::Number(10), 1, false); // Peer 0 produces another block and announces. let final_block = net.peer(0).push_blocks_at(BlockId::Number(11), 1, false); net.peer(1).push_blocks_at(BlockId::Number(10), 1, true); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert!(net.peer(1).client().header(&BlockId::Hash(final_block)).unwrap().is_some()); } #[test] fn syncs_state() { sp_tracing::try_init_simple(); + let runtime = Runtime::new().unwrap(); for skip_proofs in &[false, true] { - let mut net = TestNet::new(0); + let mut net = TestNet::new(runtime.handle().clone(), 0); let mut genesis_storage: sp_core::storage::Storage = Default::default(); genesis_storage.top.insert(b"additional_key".to_vec(), vec![1]); let mut child_data: std::collections::BTreeMap, Vec> = Default::default(); @@ -1098,7 +1138,7 @@ fn syncs_state() { net.add_full_peer_with_config(config_two); net.peer(0).push_blocks(64, false); // Wait for peer 1 to sync header chain. - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert!(!net.peer(1).client().has_state_at(&BlockId::Number(64))); let just = (*b"FRNK", Vec::new()); @@ -1111,7 +1151,7 @@ fn syncs_state() { .unwrap(); net.peer(1).client().finalize_block(hashof60, Some(just), true).unwrap(); // Wait for state sync. - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).client.info().finalized_state.is_some() { Poll::Ready(()) @@ -1121,7 +1161,7 @@ fn syncs_state() { })); assert!(!net.peer(1).client().has_state_at(&BlockId::Number(64))); // Wait for the rest of the states to be imported. - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).client().has_state_at(&BlockId::Number(64)) { Poll::Ready(()) @@ -1136,7 +1176,8 @@ fn syncs_state() { fn syncs_indexed_blocks() { use sp_runtime::traits::Hash; sp_tracing::try_init_simple(); - let mut net = TestNet::new(0); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 0); let mut n: u64 = 0; net.add_full_peer_with_config(FullPeerConfig { storage_chain: true, ..Default::default() }); net.add_full_peer_with_config(FullPeerConfig { @@ -1175,7 +1216,7 @@ fn syncs_indexed_blocks() { .unwrap() .is_none()); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert!(net .peer(1) .client() @@ -1188,7 +1229,8 @@ fn syncs_indexed_blocks() { #[test] fn warp_sync() { sp_tracing::try_init_simple(); - let mut net = TestNet::new(0); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 0); // Create 3 synced peers and 1 peer trying to warp sync. net.add_full_peer_with_config(Default::default()); net.add_full_peer_with_config(Default::default()); @@ -1202,12 +1244,12 @@ fn warp_sync() { net.peer(1).push_blocks(64, false); net.peer(2).push_blocks(64, false); // Wait for peer 1 to sync state. - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert!(!net.peer(3).client().has_state_at(&BlockId::Number(1))); assert!(net.peer(3).client().has_state_at(&BlockId::Number(64))); // Wait for peer 1 download block history - block_on(futures::future::poll_fn::<(), _>(|cx| { + runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(3).has_body(gap_end) && net.peer(3).has_body(target) { Poll::Ready(()) @@ -1224,7 +1266,8 @@ fn syncs_huge_blocks() { use substrate_test_runtime_client::BlockBuilderExt; sp_tracing::try_init_simple(); - let mut net = TestNet::new(2); + let runtime = Runtime::new().unwrap(); + let mut net = TestNet::new(runtime.handle().clone(), 2); // Increase heap space for bigger blocks. net.peer(0).generate_blocks(1, BlockOrigin::Own, |mut builder| { @@ -1241,7 +1284,7 @@ fn syncs_huge_blocks() { builder.build().unwrap().block }); - net.block_until_sync(); + runtime.block_on(net.wait_until_sync()); assert_eq!(net.peer(0).client.info().best_number, 33); assert_eq!(net.peer(1).client.info().best_number, 33); } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index f23335ef97e33..6406d7dc475a8 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -39,7 +39,7 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] lazy_static = "1.4.0" -tokio = "1.17.0" +tokio = "1.22.0" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-client-db = { version = "0.10.0-dev", default-features = true, path = "../db" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index ef2e6bec4cdb0..a3e64c367afb6 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -17,5 +17,5 @@ futures = "0.3.21" jsonrpsee = { version = "0.15.1", features = ["server"] } log = "0.4.17" serde_json = "1.0.85" -tokio = { version = "1.17.0", features = ["parking_lot"] } +tokio = { version = "1.22.0", features = ["parking_lot"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/rpc-spec-v2/Cargo.toml b/client/rpc-spec-v2/Cargo.toml index 51f5516ecf9c8..a0ae3038378ff 100644 --- a/client/rpc-spec-v2/Cargo.toml +++ b/client/rpc-spec-v2/Cargo.toml @@ -30,4 +30,4 @@ futures = "0.3.21" [dev-dependencies] serde_json = "1.0" -tokio = { version = "1.17.0", features = ["macros"] } +tokio = { version = "1.22.0", features = ["macros"] } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 0a420301826e1..d690e2c7b4cf1 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -38,7 +38,7 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } sp-session = { version = "4.0.0-dev", path = "../../primitives/session" } sp-version = { version = "5.0.0", path = "../../primitives/version" } -tokio = { version = "1.17.0", optional = true } +tokio = { version = "1.22.0", optional = true } [dev-dependencies] env_logger = "0.9" @@ -49,7 +49,7 @@ sc-network = { version = "0.10.0-dev", path = "../network" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-transaction-pool = { version = "4.0.0-dev", path = "../transaction-pool" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } -tokio = "1.17.0" +tokio = "1.22.0" sp-io = { version = "7.0.0", path = "../../primitives/io" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index c165d2d1288cd..8b17a8287c274 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -84,7 +84,7 @@ parity-util-mem = { version = "0.12.0", default-features = false, features = [ "primitive-types", ] } async-trait = "0.1.57" -tokio = { version = "1.17.0", features = ["time", "rt-multi-thread", "parking_lot"] } +tokio = { version = "1.22.0", features = ["time", "rt-multi-thread", "parking_lot"] } tempfile = "3.1.0" directories = "4.0.1" static_init = "1.0.3" @@ -92,4 +92,3 @@ static_init = "1.0.3" [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime/" } -async-std = { version = "1.11.0", default-features = false } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 50b6825f0c707..df20f2009ee09 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -876,9 +876,9 @@ where role: config.role.clone(), executor: { let spawn_handle = Clone::clone(&spawn_handle); - Some(Box::new(move |fut| { + Box::new(move |fut| { spawn_handle.spawn("libp2p-node", Some("networking"), fut); - })) + }) }, network_config: config.network.clone(), chain: client.clone(), diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 8e6131cbb75de..46ba1b33931ac 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -19,7 +19,7 @@ log = "0.4.17" parity-scale-codec = "3.0.0" parking_lot = "0.12.1" tempfile = "3.1.0" -tokio = { version = "1.17.0", features = ["time"] } +tokio = { version = "1.22.0", features = ["time"] } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../../db" } diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 5d29d34a3cbf2..5f75e3521e235 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -302,48 +302,55 @@ where full: impl Iterator Result<(F, U), Error>>, authorities: impl Iterator Result<(F, U), Error>)>, ) { - let handle = self.runtime.handle().clone(); - - for (key, authority) in authorities { - let node_config = node_config( - self.nodes, - &self.chain_spec, - Role::Authority, - handle.clone(), - Some(key), - self.base_port, - temp, - ); - let addr = node_config.network.listen_addresses.first().unwrap().clone(); - let (service, user_data) = - authority(node_config).expect("Error creating test node service"); - - handle.spawn(service.clone().map_err(|_| ())); - let addr = - MultiaddrWithPeerId { multiaddr: addr, peer_id: service.network().local_peer_id() }; - self.authority_nodes.push((self.nodes, service, user_data, addr)); - self.nodes += 1; - } + self.runtime.block_on(async { + let handle = self.runtime.handle().clone(); + + for (key, authority) in authorities { + let node_config = node_config( + self.nodes, + &self.chain_spec, + Role::Authority, + handle.clone(), + Some(key), + self.base_port, + temp, + ); + let addr = node_config.network.listen_addresses.first().unwrap().clone(); + let (service, user_data) = + authority(node_config).expect("Error creating test node service"); + + handle.spawn(service.clone().map_err(|_| ())); + let addr = MultiaddrWithPeerId { + multiaddr: addr, + peer_id: service.network().local_peer_id(), + }; + self.authority_nodes.push((self.nodes, service, user_data, addr)); + self.nodes += 1; + } - for full in full { - let node_config = node_config( - self.nodes, - &self.chain_spec, - Role::Full, - handle.clone(), - None, - self.base_port, - temp, - ); - let addr = node_config.network.listen_addresses.first().unwrap().clone(); - let (service, user_data) = full(node_config).expect("Error creating test node service"); - - handle.spawn(service.clone().map_err(|_| ())); - let addr = - MultiaddrWithPeerId { multiaddr: addr, peer_id: service.network().local_peer_id() }; - self.full_nodes.push((self.nodes, service, user_data, addr)); - self.nodes += 1; - } + for full in full { + let node_config = node_config( + self.nodes, + &self.chain_spec, + Role::Full, + handle.clone(), + None, + self.base_port, + temp, + ); + let addr = node_config.network.listen_addresses.first().unwrap().clone(); + let (service, user_data) = + full(node_config).expect("Error creating test node service"); + + handle.spawn(service.clone().map_err(|_| ())); + let addr = MultiaddrWithPeerId { + multiaddr: addr, + peer_id: service.network().local_peer_id(), + }; + self.full_nodes.push((self.nodes, service, user_data, addr)); + self.nodes += 1; + } + }); } } diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index f8c6f281546db..0a0b9284efa24 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = "0.4.19" futures = "0.3.21" -libp2p = { version = "0.49.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } +libp2p = { version = "0.49.0", default-features = false, features = ["dns", "tcp", "tokio", "wasm-ext", "websocket"] } log = "0.4.17" parking_lot = "0.12.1" pin-project = "1.0.12" diff --git a/client/telemetry/src/transport.rs b/client/telemetry/src/transport.rs index d64da44a83b6b..d8bd138c5af25 100644 --- a/client/telemetry/src/transport.rs +++ b/client/telemetry/src/transport.rs @@ -17,7 +17,6 @@ // along with this program. If not, see . use futures::{ - executor::block_on, prelude::*, ready, task::{Context, Poll}, @@ -31,8 +30,8 @@ const CONNECT_TIMEOUT: Duration = Duration::from_secs(20); pub(crate) fn initialize_transport() -> Result { let transport = { - let tcp_transport = libp2p::tcp::TcpTransport::new(libp2p::tcp::GenTcpConfig::new()); - let inner = block_on(libp2p::dns::DnsConfig::system(tcp_transport))?; + let tcp_transport = libp2p::tcp::TokioTcpTransport::new(libp2p::tcp::GenTcpConfig::new()); + let inner = libp2p::dns::TokioDnsConfig::system(tcp_transport)?; libp2p::websocket::framed::WsConfig::new(inner).and_then(|connec, _| { let connec = connec .with(|item| { diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index b803aad69263f..30d90e8b862a7 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -31,7 +31,7 @@ substrate-state-trie-migration-rpc = { optional = true, path = "../../utils/fram [dev-dependencies] parking_lot = "0.12.1" -tokio = { version = "1.17.0", features = ["macros"] } +tokio = { version = "1.22.0", features = ["macros"] } pallet-balances = { path = "../balances" } sp-tracing = { path = "../../primitives/tracing" } diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index b60183c180b4a..c7201da23ab17 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.16" -tokio = { version = "1.17.0", features = ["macros", "time"] } +tokio = { version = "1.22.0", features = ["macros", "time"] } substrate-test-utils-derive = { version = "0.10.0-dev", path = "./derive" } [dev-dependencies] diff --git a/test-utils/test-crate/Cargo.toml b/test-utils/test-crate/Cargo.toml index 2b66df6ae6513..67966dd2b6015 100644 --- a/test-utils/test-crate/Cargo.toml +++ b/test-utils/test-crate/Cargo.toml @@ -12,6 +12,6 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] -tokio = { version = "1.17.0", features = ["macros"] } +tokio = { version = "1.22.0", features = ["macros"] } sc-service = { version = "0.10.0-dev", path = "../../client/service" } test-utils = { package = "substrate-test-utils", version = "4.0.0-dev", path = ".." } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index e329b7f3f2c58..f24ab346c4084 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -26,7 +26,7 @@ sp-version = { version = "5.0.0", path = "../../../primitives/version" } substrate-rpc-client = { path = "../rpc/client" } [dev-dependencies] -tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } pallet-elections-phragmen = { version = "5.0.0-dev", path = "../../../frame/elections-phragmen" } diff --git a/utils/frame/rpc/client/Cargo.toml b/utils/frame/rpc/client/Cargo.toml index 78134a79bd0de..371996a4edfd3 100644 --- a/utils/frame/rpc/client/Cargo.toml +++ b/utils/frame/rpc/client/Cargo.toml @@ -21,5 +21,5 @@ sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } log = "0.4" [dev-dependencies] -tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread", "sync"] } +tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread", "sync"] } sp-core = { path = "../../../../primitives/core" } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 5b781c72056a2..119acbd937c8a 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -26,7 +26,7 @@ sp-storage = { version = "7.0.0", path = "../../../../primitives/storage" } [dev-dependencies] scale-info = "2.1.1" jsonrpsee = { version = "0.15.1", features = ["ws-client", "jsonrpsee-types"] } -tokio = "1.17.0" +tokio = "1.22.0" sp-core = { version = "7.0.0", path = "../../../../primitives/core" } sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index ddc52ffe56a53..56b8a79f8c080 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -30,7 +30,7 @@ sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] sc-transaction-pool = { version = "4.0.0-dev", path = "../../../../client/transaction-pool" } -tokio = "1.17.0" +tokio = "1.22.0" assert_matches = "1.3.0" sp-tracing = { version = "6.0.0", path = "../../../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 725e3d565efbb..e7bbba131155f 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -35,7 +35,7 @@ frame-try-runtime = { optional = true, path = "../../../../frame/try-runtime" } substrate-rpc-client = { path = "../../rpc/client" } [dev-dependencies] -tokio = "1.17.0" +tokio = "1.22.0" [features] try-runtime = [ diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 3c2f8321befbe..1371fe6f408c0 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -18,8 +18,8 @@ hyper = { version = "0.14.16", default-features = false, features = ["http1", "s log = "0.4.17" prometheus = { version = "0.13.0", default-features = false } thiserror = "1.0" -tokio = { version = "1.17.0", features = ["parking_lot"] } +tokio = { version = "1.22.0", features = ["parking_lot"] } [dev-dependencies] hyper = { version = "0.14.16", features = ["client"] } -tokio = { version = "1.17.0", features = ["rt-multi-thread"] } +tokio = { version = "1.22.0", features = ["rt-multi-thread"] } From 62a85fb07335b957ebb98434fdbd45232b732d85 Mon Sep 17 00:00:00 2001 From: Amar Singh Date: Mon, 5 Dec 2022 07:14:43 -0500 Subject: [PATCH 1431/1472] make threshold pub instead of pub crate (#12814) --- frame/referenda/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index a97faca3bbfc2..3d5fa753f53ff 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -409,7 +409,7 @@ impl Curve { } /// Determine the `y` value for the given `x` value. - pub(crate) fn threshold(&self, x: Perbill) -> Perbill { + pub fn threshold(&self, x: Perbill) -> Perbill { match self { Self::LinearDecreasing { length, floor, ceil } => *ceil - (x.min(*length).saturating_div(*length, Down) * (*ceil - *floor)), From 0ab43bcc54b63724046f24417b931665fc480373 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Mon, 5 Dec 2022 13:37:52 +0000 Subject: [PATCH 1432/1472] Non-Interactive Staking (#12610) * Improve naming. * More improvements to naming * Fungible counterpart * Shared pot instead of reserve * Transferable receipts * Better naming * Use u128 for counterpart * Partial thawing * Docs * Remove AdminOrigin * Integrate into Kitchen Sink * Thaw throttling * Remove todo * Docs * Fix benchmarks * Building * Tests work * New benchmarks * Benchmarking tests * Test new defensive_saturating_* functions Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Formatting * Update frame/nis/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Apply suggestions from code review Co-authored-by: Oliver Tale-Yazdi * Events added * Fix kitchensink * Update frame/nis/src/lib.rs Co-authored-by: Xiliang Chen * Review niggles * Remove genesis build requirements * Grumbles * Fixes * Fixes * Fixes * Update frame/nis/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update primitives/runtime/src/traits.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Formatting * Fixes * Fix node genesis config Signed-off-by: Oliver Tale-Yazdi * Fix node chain specs Signed-off-by: Oliver Tale-Yazdi * Use free asset ID as counterpart Signed-off-by: Oliver Tale-Yazdi * Account for rounding errors in fund_deficit bench Relaxes the check for the NIS account balance in the fund_deficit bench from equality from to checking for 99.999% equality. The exact deviation for the kitchensink runtime config is 1.24e-10 percent but could vary if the config is changed. Signed-off-by: Oliver Tale-Yazdi * clippy Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Fix * Rename * Fixes * Fixes * Formatting Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Xiliang Chen Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 38 +- Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 1 + bin/node/cli/src/chain_spec.rs | 7 +- bin/node/runtime/Cargo.toml | 8 +- bin/node/runtime/src/lib.rs | 41 +- bin/node/testing/Cargo.toml | 1 + bin/node/testing/src/genesis.rs | 9 +- frame/gilt/src/benchmarking.rs | 131 --- frame/gilt/src/lib.rs | 662 ------------- frame/gilt/src/tests.rs | 573 ----------- frame/{gilt => nis}/Cargo.toml | 5 +- frame/{gilt => nis}/README.md | 0 frame/nis/src/benchmarking.rs | 182 ++++ frame/nis/src/lib.rs | 936 ++++++++++++++++++ frame/{gilt => nis}/src/mock.rs | 71 +- frame/nis/src/tests.rs | 654 ++++++++++++ frame/{gilt => nis}/src/weights.rs | 176 ++-- frame/support/src/traits.rs | 2 +- frame/support/src/traits/misc.rs | 118 ++- .../src/traits/tokens/currency/reservable.rs | 151 ++- frame/support/src/traits/tokens/fungible.rs | 2 +- primitives/arithmetic/src/lib.rs | 4 +- primitives/arithmetic/src/per_things.rs | 194 ++-- primitives/runtime/src/traits.rs | 11 + 25 files changed, 2313 insertions(+), 1666 deletions(-) delete mode 100644 frame/gilt/src/benchmarking.rs delete mode 100644 frame/gilt/src/lib.rs delete mode 100644 frame/gilt/src/tests.rs rename frame/{gilt => nis}/Cargo.toml (93%) rename frame/{gilt => nis}/README.md (100%) create mode 100644 frame/nis/src/benchmarking.rs create mode 100644 frame/nis/src/lib.rs rename frame/{gilt => nis}/src/mock.rs (63%) create mode 100644 frame/nis/src/tests.rs rename frame/{gilt => nis}/src/weights.rs (51%) diff --git a/Cargo.lock b/Cargo.lock index 64e8cfa82d251..1caffc1d82472 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3314,7 +3314,6 @@ dependencies = [ "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", - "pallet-gilt", "pallet-grandpa", "pallet-identity", "pallet-im-online", @@ -3323,6 +3322,7 @@ dependencies = [ "pallet-membership", "pallet-mmr", "pallet-multisig", + "pallet-nis", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", @@ -4473,6 +4473,7 @@ dependencies = [ "node-primitives", "node-rpc", "pallet-asset-tx-payment", + "pallet-assets", "pallet-balances", "pallet-im-online", "pallet-timestamp", @@ -4731,6 +4732,7 @@ dependencies = [ "node-executor", "node-primitives", "pallet-asset-tx-payment", + "pallet-assets", "pallet-transaction-payment", "parity-scale-codec", "sc-block-builder", @@ -5450,23 +5452,6 @@ dependencies = [ "substrate-test-utils", ] -[[package]] -name = "pallet-gilt" -version = "4.0.0-dev" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", - "parity-scale-codec", - "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-grandpa" version = "4.0.0-dev" @@ -5635,6 +5620,23 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-nis" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-node-authorization" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index fbe57e03caaa7..e885f0916ca8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,7 +101,7 @@ members = [ "frame/examples/basic", "frame/examples/offchain-worker", "frame/executive", - "frame/gilt", + "frame/nis", "frame/grandpa", "frame/identity", "frame/im-online", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 114d324aa1591..108923265fb1f 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -84,6 +84,7 @@ sc-sysinfo = { version = "6.0.0-dev", path = "../../../client/sysinfo" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../frame/system/rpc/runtime-api" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } +pallet-assets = { version = "4.0.0-dev", path = "../../../frame/assets/" } pallet-asset-tx-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/asset-tx-payment/" } pallet-im-online = { version = "4.0.0-dev", default-features = false, path = "../../../frame/im-online" } diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 8d74f2bde0f44..1e4e806fd2736 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -358,8 +358,11 @@ pub fn testnet_genesis( max_members: 999, }, vesting: Default::default(), - assets: Default::default(), - gilt: Default::default(), + assets: pallet_assets::GenesisConfig { + // This asset is used by the NIS pallet as counterpart currency. + assets: vec![(9, get_account_id_from_seed::("Alice"), true, 1)], + ..Default::default() + }, transaction_storage: Default::default(), transaction_payment: Default::default(), alliance: Default::default(), diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index f812cbe030c86..dfddf6a89499b 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -68,7 +68,7 @@ pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features pallet-election-provider-support-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-support/benchmarking", optional = true } pallet-elections-phragmen = { version = "5.0.0-dev", default-features = false, path = "../../../frame/elections-phragmen" } pallet-fast-unstake = { version = "4.0.0-dev", default-features = false, path = "../../../frame/fast-unstake" } -pallet-gilt = { version = "4.0.0-dev", default-features = false, path = "../../../frame/gilt" } +pallet-nis = { version = "4.0.0-dev", default-features = false, path = "../../../frame/nis" } pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../../frame/grandpa" } pallet-im-online = { version = "4.0.0-dev", default-features = false, path = "../../../frame/im-online" } pallet-indices = { version = "4.0.0-dev", default-features = false, path = "../../../frame/indices" } @@ -144,7 +144,7 @@ std = [ "pallet-elections-phragmen/std", "pallet-fast-unstake/std", "frame-executive/std", - "pallet-gilt/std", + "pallet-nis/std", "pallet-grandpa/std", "pallet-im-online/std", "pallet-indices/std", @@ -223,7 +223,7 @@ runtime-benchmarks = [ "pallet-election-provider-support-benchmarking/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", "pallet-fast-unstake/runtime-benchmarks", - "pallet-gilt/runtime-benchmarks", + "pallet-nis/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", @@ -276,7 +276,7 @@ try-runtime = [ "pallet-election-provider-multi-phase/try-runtime", "pallet-elections-phragmen/try-runtime", "pallet-fast-unstake/try-runtime", - "pallet-gilt/try-runtime", + "pallet-nis/try-runtime", "pallet-grandpa/try-runtime", "pallet-im-online/try-runtime", "pallet-indices/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 215b02bcca994..633106e10b6f8 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -32,9 +32,10 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, - EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, - LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, WithdrawReasons, + fungible::ItemOf, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, + Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, + KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, + WithdrawReasons, }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, @@ -53,6 +54,7 @@ use pallet_grandpa::{ fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, }; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; +use pallet_nis::WithMaximumOf; use pallet_session::historical::{self as pallet_session_historical}; pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; @@ -1464,28 +1466,37 @@ parameter_types! { pub const QueueCount: u32 = 300; pub const MaxQueueLen: u32 = 1000; pub const FifoQueueLen: u32 = 500; - pub const Period: BlockNumber = 30 * DAYS; - pub const MinFreeze: Balance = 100 * DOLLARS; + pub const NisBasePeriod: BlockNumber = 30 * DAYS; + pub const MinBid: Balance = 100 * DOLLARS; + pub const MinReceipt: Perquintill = Perquintill::from_percent(1); pub const IntakePeriod: BlockNumber = 10; - pub const MaxIntakeBids: u32 = 10; + pub MaxIntakeWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10; + pub const ThawThrottle: (Perquintill, BlockNumber) = (Perquintill::from_percent(25), 5); + pub Target: Perquintill = Perquintill::zero(); + pub const NisPalletId: PalletId = PalletId(*b"py/nis "); } -impl pallet_gilt::Config for Runtime { +impl pallet_nis::Config for Runtime { + type WeightInfo = pallet_nis::weights::SubstrateWeight; type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = Balance; - type AdminOrigin = frame_system::EnsureRoot; + type FundOrigin = frame_system::EnsureSigned; + type Counterpart = ItemOf, AccountId>; + type CounterpartAmount = WithMaximumOf>; type Deficit = (); - type Surplus = (); type IgnoredIssuance = IgnoredIssuance; + type Target = Target; + type PalletId = NisPalletId; type QueueCount = QueueCount; type MaxQueueLen = MaxQueueLen; type FifoQueueLen = FifoQueueLen; - type Period = Period; - type MinFreeze = MinFreeze; + type BasePeriod = NisBasePeriod; + type MinBid = MinBid; + type MinReceipt = MinReceipt; type IntakePeriod = IntakePeriod; - type MaxIntakeBids = MaxIntakeBids; - type WeightInfo = pallet_gilt::weights::SubstrateWeight; + type MaxIntakeWeight = MaxIntakeWeight; + type ThawThrottle = ThawThrottle; } parameter_types! { @@ -1668,7 +1679,7 @@ construct_runtime!( Assets: pallet_assets, Mmr: pallet_mmr, Lottery: pallet_lottery, - Gilt: pallet_gilt, + Nis: pallet_nis, Uniques: pallet_uniques, TransactionStorage: pallet_transaction_storage, VoterList: pallet_bags_list::, @@ -1772,7 +1783,7 @@ mod benches { [pallet_election_provider_support_benchmarking, EPSBench::] [pallet_elections_phragmen, Elections] [pallet_fast_unstake, FastUnstake] - [pallet_gilt, Gilt] + [pallet_nis, Nis] [pallet_grandpa, Grandpa] [pallet_identity, Identity] [pallet_im_online, ImOnline] diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index a2b34cf59b120..694472123647a 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -22,6 +22,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } node-executor = { version = "3.0.0-dev", path = "../executor" } node-primitives = { version = "2.0.0", path = "../primitives" } kitchensink-runtime = { version = "3.0.0-dev", path = "../runtime" } +pallet-assets = { version = "4.0.0-dev", path = "../../../frame/assets" } pallet-asset-tx-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/asset-tx-payment" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../../../frame/transaction-payment" } sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index 1eb7318db52da..b207fc7f98ab4 100644 --- a/bin/node/testing/src/genesis.rs +++ b/bin/node/testing/src/genesis.rs @@ -20,9 +20,9 @@ use crate::keyring::*; use kitchensink_runtime::{ - constants::currency::*, wasm_binary_unwrap, AccountId, BabeConfig, BalancesConfig, - GenesisConfig, GrandpaConfig, IndicesConfig, SessionConfig, SocietyConfig, StakerStatus, - StakingConfig, SystemConfig, BABE_GENESIS_EPOCH_CONFIG, + constants::currency::*, wasm_binary_unwrap, AccountId, AssetsConfig, BabeConfig, + BalancesConfig, GenesisConfig, GrandpaConfig, IndicesConfig, SessionConfig, SocietyConfig, + StakerStatus, StakingConfig, SystemConfig, BABE_GENESIS_EPOCH_CONFIG, }; use sp_keyring::{Ed25519Keyring, Sr25519Keyring}; use sp_runtime::Perbill; @@ -88,8 +88,7 @@ pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec) -> Gen treasury: Default::default(), society: SocietyConfig { members: vec![alice(), bob()], pot: 0, max_members: 999 }, vesting: Default::default(), - assets: Default::default(), - gilt: Default::default(), + assets: AssetsConfig { assets: vec![(9, alice(), true, 1)], ..Default::default() }, transaction_storage: Default::default(), transaction_payment: Default::default(), alliance: Default::default(), diff --git a/frame/gilt/src/benchmarking.rs b/frame/gilt/src/benchmarking.rs deleted file mode 100644 index 92ebf81854f23..0000000000000 --- a/frame/gilt/src/benchmarking.rs +++ /dev/null @@ -1,131 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Benchmarks for Gilt Pallet - -#![cfg(feature = "runtime-benchmarks")] - -use super::*; -use frame_benchmarking::{benchmarks, whitelisted_caller}; -use frame_support::{ - dispatch::UnfilteredDispatchable, - traits::{Currency, EnsureOrigin, Get}, -}; -use frame_system::RawOrigin; -use sp_arithmetic::Perquintill; -use sp_runtime::traits::{Bounded, Zero}; -use sp_std::prelude::*; - -use crate::Pallet as Gilt; - -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - -benchmarks! { - place_bid { - let l in 0..(T::MaxQueueLen::get() - 1); - let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - for i in 0..l { - Gilt::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinFreeze::get(), 1)?; - } - }: _(RawOrigin::Signed(caller.clone()), T::MinFreeze::get() * BalanceOf::::from(2u32), 1) - verify { - assert_eq!(QueueTotals::::get()[0], (l + 1, T::MinFreeze::get() * BalanceOf::::from(l + 2))); - } - - place_bid_max { - let caller: T::AccountId = whitelisted_caller(); - let origin = RawOrigin::Signed(caller.clone()); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - for i in 0..T::MaxQueueLen::get() { - Gilt::::place_bid(origin.clone().into(), T::MinFreeze::get(), 1)?; - } - }: place_bid(origin, T::MinFreeze::get() * BalanceOf::::from(2u32), 1) - verify { - assert_eq!(QueueTotals::::get()[0], ( - T::MaxQueueLen::get(), - T::MinFreeze::get() * BalanceOf::::from(T::MaxQueueLen::get() + 1), - )); - } - - retract_bid { - let l in 1..T::MaxQueueLen::get(); - let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - for i in 0..l { - Gilt::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinFreeze::get(), 1)?; - } - }: _(RawOrigin::Signed(caller.clone()), T::MinFreeze::get(), 1) - verify { - assert_eq!(QueueTotals::::get()[0], (l - 1, T::MinFreeze::get() * BalanceOf::::from(l - 1))); - } - - set_target { - let origin = T::AdminOrigin::successful_origin(); - }: _(origin, Default::default()) - verify {} - - thaw { - let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, T::MinFreeze::get() * BalanceOf::::from(3u32)); - Gilt::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinFreeze::get(), 1)?; - Gilt::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinFreeze::get(), 1)?; - Gilt::::enlarge(T::MinFreeze::get() * BalanceOf::::from(2u32), 2); - Active::::mutate(0, |m_g| if let Some(ref mut g) = m_g { g.expiry = Zero::zero() }); - }: _(RawOrigin::Signed(caller.clone()), 0) - verify { - assert!(Active::::get(0).is_none()); - } - - pursue_target_noop { - }: { Gilt::::pursue_target(0) } - - pursue_target_per_item { - // bids taken - let b in 0..T::MaxQueueLen::get(); - - let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, T::MinFreeze::get() * BalanceOf::::from(b + 1)); - - for _ in 0..b { - Gilt::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinFreeze::get(), 1)?; - } - - Call::::set_target { target: Perquintill::from_percent(100) } - .dispatch_bypass_filter(T::AdminOrigin::successful_origin())?; - - }: { Gilt::::pursue_target(b) } - - pursue_target_per_queue { - // total queues hit - let q in 0..T::QueueCount::get(); - - let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, T::MinFreeze::get() * BalanceOf::::from(q + 1)); - - for i in 0..q { - Gilt::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinFreeze::get(), i + 1)?; - } - - Call::::set_target { target: Perquintill::from_percent(100) } - .dispatch_bypass_filter(T::AdminOrigin::successful_origin())?; - - }: { Gilt::::pursue_target(q) } - - impl_benchmark_test_suite!(Gilt, crate::mock::new_test_ext(), crate::mock::Test); -} diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs deleted file mode 100644 index 28a0f5fd56e67..0000000000000 --- a/frame/gilt/src/lib.rs +++ /dev/null @@ -1,662 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # Gilt Pallet -//! A pallet allowing accounts to auction for being frozen and receive open-ended -//! inflation-protection in return. -//! -//! ## Overview -//! -//! Lock up tokens, for at least as long as you offer, and be free from both inflation and -//! intermediate reward or exchange until the tokens become unlocked. -//! -//! ## Design -//! -//! Queues for each of 1-`QueueCount` periods, given in blocks (`Period`). Queues are limited in -//! size to something sensible, `MaxQueueLen`. A secondary storage item with `QueueCount` x `u32` -//! elements with the number of items in each queue. -//! -//! Queues are split into two parts. The first part is a priority queue based on bid size. The -//! second part is just a FIFO (the size of the second part is set with `FifoQueueLen`). Items are -//! always prepended so that removal is always O(1) since removal often happens many times under a -//! single weighed function (`on_initialize`) yet placing bids only ever happens once per weighed -//! function (`place_bid`). If the queue has a priority portion, then it remains sorted in order of -//! bid size so that smaller bids fall off as it gets too large. -//! -//! Account may enqueue a balance with some number of `Period`s lock up, up to a maximum of -//! `QueueCount`. The balance gets reserved. There's a minimum of `MinFreeze` to avoid dust. -//! -//! Until your bid is turned into an issued gilt you can retract it instantly and the funds are -//! unreserved. -//! -//! There's a target proportion of effective total issuance (i.e. accounting for existing gilts) -//! which the we attempt to have frozen at any one time. It will likely be gradually increased over -//! time by governance. -//! -//! As the total funds frozen under gilts drops below `FrozenFraction` of the total effective -//! issuance, then bids are taken from queues, with the queue of the greatest period taking -//! priority. If the item in the queue's locked amount is greater than the amount left to be -//! frozen, then it is split up into multiple bids and becomes partially frozen under gilt. -//! -//! Once an account's balance is frozen, it remains frozen until the owner thaws the balance of the -//! account. This may happen no earlier than queue's period after the point at which the gilt is -//! issued. -//! -//! ## Suggested Values -//! -//! - `QueueCount`: 300 -//! - `Period`: 432,000 -//! - `MaxQueueLen`: 1000 -//! - `MinFreeze`: Around CHF 100 in value. - -#![cfg_attr(not(feature = "std"), no_std)] - -pub use pallet::*; - -mod benchmarking; -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; -pub mod weights; - -#[frame_support::pallet] -pub mod pallet { - pub use crate::weights::WeightInfo; - use frame_support::{ - pallet_prelude::*, - traits::{Currency, DefensiveSaturating, OnUnbalanced, ReservableCurrency}, - }; - use frame_system::pallet_prelude::*; - use sp_arithmetic::{PerThing, Perquintill}; - use sp_runtime::traits::{Saturating, Zero}; - use sp_std::prelude::*; - - type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::PositiveImbalance; - type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::NegativeImbalance; - - #[pallet::config] - pub trait Config: frame_system::Config { - /// Overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// Currency type that this works on. - type Currency: ReservableCurrency; - - /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to - /// `From`. - type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned - + codec::FullCodec - + Copy - + MaybeSerializeDeserialize - + sp_std::fmt::Debug - + Default - + From - + TypeInfo - + MaxEncodedLen; - - /// Origin required for setting the target proportion to be under gilt. - type AdminOrigin: EnsureOrigin; - - /// Unbalanced handler to account for funds created (in case of a higher total issuance over - /// freezing period). - type Deficit: OnUnbalanced>; - - /// Unbalanced handler to account for funds destroyed (in case of a lower total issuance - /// over freezing period). - type Surplus: OnUnbalanced>; - - /// The issuance to ignore. This is subtracted from the `Currency`'s `total_issuance` to get - /// the issuance by which we inflate or deflate the gilt. - type IgnoredIssuance: Get>; - - /// Number of duration queues in total. This sets the maximum duration supported, which is - /// this value multiplied by `Period`. - #[pallet::constant] - type QueueCount: Get; - - /// Maximum number of items that may be in each duration queue. - #[pallet::constant] - type MaxQueueLen: Get; - - /// Portion of the queue which is free from ordering and just a FIFO. - /// - /// Must be no greater than `MaxQueueLen`. - #[pallet::constant] - type FifoQueueLen: Get; - - /// The base period for the duration queues. This is the common multiple across all - /// supported freezing durations that can be bid upon. - #[pallet::constant] - type Period: Get; - - /// The minimum amount of funds that may be offered to freeze for a gilt. Note that this - /// does not actually limit the amount which may be frozen in a gilt since gilts may be - /// split up in order to satisfy the desired amount of funds under gilts. - /// - /// It should be at least big enough to ensure that there is no possible storage spam attack - /// or queue-filling attack. - #[pallet::constant] - type MinFreeze: Get>; - - /// The number of blocks between consecutive attempts to issue more gilts in an effort to - /// get to the target amount to be frozen. - /// - /// A larger value results in fewer storage hits each block, but a slower period to get to - /// the target. - #[pallet::constant] - type IntakePeriod: Get; - - /// The maximum amount of bids that can be turned into issued gilts each block. A larger - /// value here means less of the block available for transactions should there be a glut of - /// bids to make into gilts to reach the target. - #[pallet::constant] - type MaxIntakeBids: Get; - - /// Information on runtime weights. - type WeightInfo: WeightInfo; - } - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - - /// A single bid on a gilt, an item of a *queue* in `Queues`. - #[derive( - Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, - )] - pub struct GiltBid { - /// The amount bid. - pub amount: Balance, - /// The owner of the bid. - pub who: AccountId, - } - - /// Information representing an active gilt. - #[derive( - Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, - )] - pub struct ActiveGilt { - /// The proportion of the effective total issuance (i.e. accounting for any eventual gilt - /// expansion or contraction that may eventually be claimed). - pub proportion: Perquintill, - /// The amount reserved under this gilt. - pub amount: Balance, - /// The account to whom this gilt belongs. - pub who: AccountId, - /// The time after which this gilt can be redeemed for the proportional amount of balance. - pub expiry: BlockNumber, - } - - /// An index for a gilt. - pub type ActiveIndex = u32; - - /// Overall information package on the active gilts. - /// - /// The way of determining the net issuance (i.e. after factoring in all maturing frozen funds) - /// is: - /// - /// `issuance - frozen + proportion * issuance` - /// - /// where `issuance = total_issuance - IgnoredIssuance` - #[derive( - Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, - )] - pub struct ActiveGiltsTotal { - /// The total amount of funds held in reserve for all active gilts. - pub frozen: Balance, - /// The proportion of funds that the `frozen` balance represents to total issuance. - pub proportion: Perquintill, - /// The total number of gilts issued so far. - pub index: ActiveIndex, - /// The target proportion of gilts within total issuance. - pub target: Perquintill, - } - - /// The totals of items and balances within each queue. Saves a lot of storage reads in the - /// case of sparsely packed queues. - /// - /// The vector is indexed by duration in `Period`s, offset by one, so information on the queue - /// whose duration is one `Period` would be storage `0`. - #[pallet::storage] - pub type QueueTotals = - StorageValue<_, BoundedVec<(u32, BalanceOf), T::QueueCount>, ValueQuery>; - - /// The queues of bids ready to become gilts. Indexed by duration (in `Period`s). - #[pallet::storage] - pub type Queues = StorageMap< - _, - Blake2_128Concat, - u32, - BoundedVec, T::AccountId>, T::MaxQueueLen>, - ValueQuery, - >; - - /// Information relating to the gilts currently active. - #[pallet::storage] - pub type ActiveTotal = StorageValue<_, ActiveGiltsTotal>, ValueQuery>; - - /// The currently active gilts, indexed according to the order of creation. - #[pallet::storage] - pub type Active = StorageMap< - _, - Blake2_128Concat, - ActiveIndex, - ActiveGilt< - BalanceOf, - ::AccountId, - ::BlockNumber, - >, - OptionQuery, - >; - - #[pallet::genesis_config] - #[derive(Default)] - pub struct GenesisConfig; - - #[pallet::genesis_build] - impl GenesisBuild for GenesisConfig { - fn build(&self) { - let unbounded = vec![(0, BalanceOf::::zero()); T::QueueCount::get() as usize]; - let bounded: BoundedVec<_, _> = unbounded - .try_into() - .expect("QueueTotals should support up to QueueCount items. qed"); - QueueTotals::::put(bounded); - } - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// A bid was successfully placed. - BidPlaced { who: T::AccountId, amount: BalanceOf, duration: u32 }, - /// A bid was successfully removed (before being accepted as a gilt). - BidRetracted { who: T::AccountId, amount: BalanceOf, duration: u32 }, - /// A bid was accepted as a gilt. The balance may not be released until expiry. - GiltIssued { - index: ActiveIndex, - expiry: T::BlockNumber, - who: T::AccountId, - amount: BalanceOf, - }, - /// An expired gilt has been thawed. - GiltThawed { - index: ActiveIndex, - who: T::AccountId, - original_amount: BalanceOf, - additional_amount: BalanceOf, - }, - } - - #[pallet::error] - pub enum Error { - /// The duration of the bid is less than one. - DurationTooSmall, - /// The duration is the bid is greater than the number of queues. - DurationTooBig, - /// The amount of the bid is less than the minimum allowed. - AmountTooSmall, - /// The queue for the bid's duration is full and the amount bid is too low to get in - /// through replacing an existing bid. - BidTooLow, - /// Gilt index is unknown. - Unknown, - /// Not the owner of the gilt. - NotOwner, - /// Gilt not yet at expiry date. - NotExpired, - /// The given bid for retraction is not found. - NotFound, - } - - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_initialize(n: T::BlockNumber) -> Weight { - if (n % T::IntakePeriod::get()).is_zero() { - Self::pursue_target(T::MaxIntakeBids::get()) - } else { - Weight::zero() - } - } - } - - #[pallet::call] - impl Pallet { - /// Place a bid for a gilt to be issued. - /// - /// Origin must be Signed, and account must have at least `amount` in free balance. - /// - /// - `amount`: The amount of the bid; these funds will be reserved. If the bid is - /// successfully elevated into an issued gilt, then these funds will continue to be - /// reserved until the gilt expires. Must be at least `MinFreeze`. - /// - `duration`: The number of periods for which the funds will be locked if the gilt is - /// issued. It will expire only after this period has elapsed after the point of issuance. - /// Must be greater than 1 and no more than `QueueCount`. - /// - /// Complexities: - /// - `Queues[duration].len()` (just take max). - #[pallet::weight(T::WeightInfo::place_bid_max())] - pub fn place_bid( - origin: OriginFor, - #[pallet::compact] amount: BalanceOf, - duration: u32, - ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - - ensure!(amount >= T::MinFreeze::get(), Error::::AmountTooSmall); - let queue_count = T::QueueCount::get() as usize; - let queue_index = duration.checked_sub(1).ok_or(Error::::DurationTooSmall)? as usize; - ensure!(queue_index < queue_count, Error::::DurationTooBig); - - let net = Queues::::try_mutate( - duration, - |q| -> Result<(u32, BalanceOf), DispatchError> { - let queue_full = q.len() == T::MaxQueueLen::get() as usize; - ensure!(!queue_full || q[0].amount < amount, Error::::BidTooLow); - T::Currency::reserve(&who, amount)?; - - // queue is - let mut bid = GiltBid { amount, who: who.clone() }; - let net = if queue_full { - sp_std::mem::swap(&mut q[0], &mut bid); - T::Currency::unreserve(&bid.who, bid.amount); - (0, amount - bid.amount) - } else { - q.try_insert(0, bid).expect("verified queue was not full above. qed."); - (1, amount) - }; - - let sorted_item_count = q.len().saturating_sub(T::FifoQueueLen::get() as usize); - if sorted_item_count > 1 { - q[0..sorted_item_count].sort_by_key(|x| x.amount); - } - - Ok(net) - }, - )?; - QueueTotals::::mutate(|qs| { - qs.bounded_resize(queue_count, (0, Zero::zero())); - qs[queue_index].0 += net.0; - qs[queue_index].1 = qs[queue_index].1.saturating_add(net.1); - }); - Self::deposit_event(Event::BidPlaced { who, amount, duration }); - - Ok(().into()) - } - - /// Retract a previously placed bid. - /// - /// Origin must be Signed, and the account should have previously issued a still-active bid - /// of `amount` for `duration`. - /// - /// - `amount`: The amount of the previous bid. - /// - `duration`: The duration of the previous bid. - #[pallet::weight(T::WeightInfo::place_bid(T::MaxQueueLen::get()))] - pub fn retract_bid( - origin: OriginFor, - #[pallet::compact] amount: BalanceOf, - duration: u32, - ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - - let queue_count = T::QueueCount::get() as usize; - let queue_index = duration.checked_sub(1).ok_or(Error::::DurationTooSmall)? as usize; - ensure!(queue_index < queue_count, Error::::DurationTooBig); - - let bid = GiltBid { amount, who }; - let new_len = Queues::::try_mutate(duration, |q| -> Result { - let pos = q.iter().position(|i| i == &bid).ok_or(Error::::NotFound)?; - q.remove(pos); - Ok(q.len() as u32) - })?; - - QueueTotals::::mutate(|qs| { - qs.bounded_resize(queue_count, (0, Zero::zero())); - qs[queue_index].0 = new_len; - qs[queue_index].1 = qs[queue_index].1.saturating_sub(bid.amount); - }); - - T::Currency::unreserve(&bid.who, bid.amount); - Self::deposit_event(Event::BidRetracted { who: bid.who, amount: bid.amount, duration }); - - Ok(().into()) - } - - /// Set target proportion of gilt-funds. - /// - /// Origin must be `AdminOrigin`. - /// - /// - `target`: The target proportion of effective issued funds that should be under gilts - /// at any one time. - #[pallet::weight(T::WeightInfo::set_target())] - pub fn set_target( - origin: OriginFor, - #[pallet::compact] target: Perquintill, - ) -> DispatchResultWithPostInfo { - T::AdminOrigin::ensure_origin(origin)?; - ActiveTotal::::mutate(|totals| totals.target = target); - Ok(().into()) - } - - /// Remove an active but expired gilt. Reserved funds under gilt are freed and balance is - /// adjusted to ensure that the funds grow or shrink to maintain the equivalent proportion - /// of effective total issued funds. - /// - /// Origin must be Signed and the account must be the owner of the gilt of the given index. - /// - /// - `index`: The index of the gilt to be thawed. - #[pallet::weight(T::WeightInfo::thaw())] - pub fn thaw( - origin: OriginFor, - #[pallet::compact] index: ActiveIndex, - ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - - // Look for `index` - let gilt = Active::::get(index).ok_or(Error::::Unknown)?; - // If found, check the owner is `who`. - ensure!(gilt.who == who, Error::::NotOwner); - let now = frame_system::Pallet::::block_number(); - ensure!(now >= gilt.expiry, Error::::NotExpired); - // Remove it - Active::::remove(index); - - // Multiply the proportion it is by the total issued. - let total_issuance = - T::Currency::total_issuance().saturating_sub(T::IgnoredIssuance::get()); - ActiveTotal::::mutate(|totals| { - let nongilt_issuance = total_issuance.saturating_sub(totals.frozen); - let effective_issuance = - totals.proportion.left_from_one().saturating_reciprocal_mul(nongilt_issuance); - let gilt_value = gilt.proportion * effective_issuance; - - totals.frozen = totals.frozen.saturating_sub(gilt.amount); - totals.proportion = totals.proportion.saturating_sub(gilt.proportion); - - // Remove or mint the additional to the amount using `Deficit`/`Surplus`. - if gilt_value > gilt.amount { - // Unreserve full amount. - T::Currency::unreserve(&gilt.who, gilt.amount); - let amount = gilt_value - gilt.amount; - let deficit = T::Currency::deposit_creating(&gilt.who, amount); - T::Deficit::on_unbalanced(deficit); - } else { - if gilt_value < gilt.amount { - // We take anything reserved beyond the gilt's final value. - let rest = gilt.amount - gilt_value; - // `slash` might seem a little aggressive, but it's the only way to do it - // in case it's locked into the staking system. - let surplus = T::Currency::slash_reserved(&gilt.who, rest).0; - T::Surplus::on_unbalanced(surplus); - } - // Unreserve only its new value (less than the amount reserved). Everything - // should add up, but (defensive) in case it doesn't, unreserve takes lower - // priority over the funds. - let err_amt = T::Currency::unreserve(&gilt.who, gilt_value); - debug_assert!(err_amt.is_zero()); - } - - let e = Event::GiltThawed { - index, - who: gilt.who, - original_amount: gilt.amount, - additional_amount: gilt_value, - }; - Self::deposit_event(e); - }); - - Ok(().into()) - } - } - - /// Issuance information returned by `issuance()`. - pub struct IssuanceInfo { - /// The balance held in reserve over all active gilts. - pub reserved: Balance, - /// The issuance not held in reserve for active gilts. Together with `reserved` this sums - /// to `Currency::total_issuance`. - pub non_gilt: Balance, - /// The balance that `reserved` is effectively worth, at present. This is not issued funds - /// and could be less than `reserved` (though in most cases should be greater). - pub effective: Balance, - } - - impl Pallet { - /// Get the target amount of Gilts that we're aiming for. - pub fn target() -> Perquintill { - ActiveTotal::::get().target - } - - /// Returns information on the issuance of gilts. - pub fn issuance() -> IssuanceInfo> { - let totals = ActiveTotal::::get(); - - let total_issuance = T::Currency::total_issuance(); - let non_gilt = total_issuance.saturating_sub(totals.frozen); - let effective = totals.proportion.left_from_one().saturating_reciprocal_mul(non_gilt); - - IssuanceInfo { reserved: totals.frozen, non_gilt, effective } - } - - /// Attempt to enlarge our gilt-set from bids in order to satisfy our desired target amount - /// of funds frozen into gilts. - pub fn pursue_target(max_bids: u32) -> Weight { - let totals = ActiveTotal::::get(); - if totals.proportion < totals.target { - let missing = totals.target.saturating_sub(totals.proportion); - - let total_issuance = - T::Currency::total_issuance().saturating_sub(T::IgnoredIssuance::get()); - let nongilt_issuance = total_issuance.saturating_sub(totals.frozen); - let effective_issuance = - totals.proportion.left_from_one().saturating_reciprocal_mul(nongilt_issuance); - let intake = missing * effective_issuance; - - let (bids_taken, queues_hit) = Self::enlarge(intake, max_bids); - let first_from_each_queue = T::WeightInfo::pursue_target_per_queue(queues_hit); - let rest_from_each_queue = T::WeightInfo::pursue_target_per_item(bids_taken) - .saturating_sub(T::WeightInfo::pursue_target_per_item(queues_hit)); - first_from_each_queue + rest_from_each_queue - } else { - T::WeightInfo::pursue_target_noop() - } - } - - /// Freeze additional funds from queue of bids up to `amount`. Use at most `max_bids` - /// from the queue. - /// - /// Return the number of bids taken and the number of distinct queues taken from. - pub fn enlarge(amount: BalanceOf, max_bids: u32) -> (u32, u32) { - let total_issuance = - T::Currency::total_issuance().saturating_sub(T::IgnoredIssuance::get()); - let mut remaining = amount; - let mut bids_taken = 0; - let mut queues_hit = 0; - let now = frame_system::Pallet::::block_number(); - - ActiveTotal::::mutate(|totals| { - QueueTotals::::mutate(|qs| { - for duration in (1..=T::QueueCount::get()).rev() { - if qs[duration as usize - 1].0 == 0 { - continue - } - let queue_index = duration as usize - 1; - let expiry = - now.saturating_add(T::Period::get().saturating_mul(duration.into())); - Queues::::mutate(duration, |q| { - while let Some(mut bid) = q.pop() { - if remaining < bid.amount { - let overflow = bid.amount - remaining; - bid.amount = remaining; - q.try_push(GiltBid { amount: overflow, who: bid.who.clone() }) - .expect("just popped, so there must be space. qed"); - } - let amount = bid.amount; - // Can never overflow due to block above. - remaining -= amount; - // Should never underflow since it should track the total of the - // bids exactly, but we'll be defensive. - qs[queue_index].1 = - qs[queue_index].1.defensive_saturating_sub(bid.amount); - - // Now to activate the bid... - let nongilt_issuance = - total_issuance.defensive_saturating_sub(totals.frozen); - let effective_issuance = totals - .proportion - .left_from_one() - .saturating_reciprocal_mul(nongilt_issuance); - let n = amount; - let d = effective_issuance; - let proportion = Perquintill::from_rational(n, d); - let who = bid.who; - let index = totals.index; - totals.frozen += bid.amount; - totals.proportion = - totals.proportion.defensive_saturating_add(proportion); - totals.index += 1; - let e = - Event::GiltIssued { index, expiry, who: who.clone(), amount }; - Self::deposit_event(e); - let gilt = ActiveGilt { amount, proportion, who, expiry }; - Active::::insert(index, gilt); - - bids_taken += 1; - - if remaining.is_zero() || bids_taken == max_bids { - break - } - } - queues_hit += 1; - qs[queue_index].0 = q.len() as u32; - }); - if remaining.is_zero() || bids_taken == max_bids { - break - } - } - }); - }); - (bids_taken, queues_hit) - } - } -} diff --git a/frame/gilt/src/tests.rs b/frame/gilt/src/tests.rs deleted file mode 100644 index 2ac369dd3b8b3..0000000000000 --- a/frame/gilt/src/tests.rs +++ /dev/null @@ -1,573 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests for Gilt pallet. - -use super::*; -use crate::{mock::*, Error}; -use frame_support::{assert_noop, assert_ok, dispatch::DispatchError, traits::Currency}; -use pallet_balances::Error as BalancesError; -use sp_arithmetic::Perquintill; - -#[test] -fn basic_setup_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - - for q in 0..3 { - assert!(Queues::::get(q).is_empty()); - } - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 0, - proportion: Perquintill::zero(), - index: 0, - target: Perquintill::zero(), - } - ); - assert_eq!(QueueTotals::::get(), vec![(0, 0); 3]); - }); -} - -#[test] -fn set_target_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - let e = DispatchError::BadOrigin; - assert_noop!(Gilt::set_target(RuntimeOrigin::signed(2), Perquintill::from_percent(50)), e); - assert_ok!(Gilt::set_target(RuntimeOrigin::signed(1), Perquintill::from_percent(50))); - - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 0, - proportion: Perquintill::zero(), - index: 0, - target: Perquintill::from_percent(50), - } - ); - }); -} - -#[test] -fn place_bid_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_noop!( - Gilt::place_bid(RuntimeOrigin::signed(1), 1, 2), - Error::::AmountTooSmall - ); - assert_noop!( - Gilt::place_bid(RuntimeOrigin::signed(1), 101, 2), - BalancesError::::InsufficientBalance - ); - assert_noop!( - Gilt::place_bid(RuntimeOrigin::signed(1), 10, 4), - Error::::DurationTooBig - ); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); - assert_eq!(Balances::reserved_balance(1), 10); - assert_eq!(Queues::::get(2), vec![GiltBid { amount: 10, who: 1 }]); - assert_eq!(QueueTotals::::get(), vec![(0, 0), (1, 10), (0, 0)]); - }); -} - -#[test] -fn place_bid_queuing_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 20, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 5, 2)); - assert_noop!(Gilt::place_bid(RuntimeOrigin::signed(1), 5, 2), Error::::BidTooLow); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 15, 2)); - assert_eq!(Balances::reserved_balance(1), 45); - - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 25, 2)); - assert_eq!(Balances::reserved_balance(1), 60); - assert_noop!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2), Error::::BidTooLow); - assert_eq!( - Queues::::get(2), - vec![ - GiltBid { amount: 15, who: 1 }, - GiltBid { amount: 25, who: 1 }, - GiltBid { amount: 20, who: 1 }, - ] - ); - assert_eq!(QueueTotals::::get(), vec![(0, 0), (3, 60), (0, 0)]); - }); -} - -#[test] -fn place_bid_fails_when_queue_full() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 10, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(3), 10, 2)); - assert_noop!(Gilt::place_bid(RuntimeOrigin::signed(4), 10, 2), Error::::BidTooLow); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(4), 10, 3)); - }); -} - -#[test] -fn multiple_place_bids_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 3)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 10, 2)); - - assert_eq!(Balances::reserved_balance(1), 40); - assert_eq!(Balances::reserved_balance(2), 10); - assert_eq!(Queues::::get(1), vec![GiltBid { amount: 10, who: 1 },]); - assert_eq!( - Queues::::get(2), - vec![ - GiltBid { amount: 10, who: 2 }, - GiltBid { amount: 10, who: 1 }, - GiltBid { amount: 10, who: 1 }, - ] - ); - assert_eq!(Queues::::get(3), vec![GiltBid { amount: 10, who: 1 },]); - assert_eq!(QueueTotals::::get(), vec![(1, 10), (3, 30), (1, 10)]); - }); -} - -#[test] -fn retract_single_item_queue_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); - assert_ok!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 1)); - - assert_eq!(Balances::reserved_balance(1), 10); - assert_eq!(Queues::::get(1), vec![]); - assert_eq!(Queues::::get(2), vec![GiltBid { amount: 10, who: 1 }]); - assert_eq!(QueueTotals::::get(), vec![(0, 0), (1, 10), (0, 0)]); - }); -} - -#[test] -fn retract_with_other_and_duplicate_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 10, 2)); - - assert_ok!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 2)); - assert_eq!(Balances::reserved_balance(1), 20); - assert_eq!(Balances::reserved_balance(2), 10); - assert_eq!(Queues::::get(1), vec![GiltBid { amount: 10, who: 1 },]); - assert_eq!( - Queues::::get(2), - vec![GiltBid { amount: 10, who: 2 }, GiltBid { amount: 10, who: 1 },] - ); - assert_eq!(QueueTotals::::get(), vec![(1, 10), (2, 20), (0, 0)]); - }); -} - -#[test] -fn retract_non_existent_item_fails() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 1), Error::::NotFound); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); - assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(1), 20, 1), Error::::NotFound); - assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 2), Error::::NotFound); - assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(2), 10, 1), Error::::NotFound); - }); -} - -#[test] -fn basic_enlarge_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 2)); - Gilt::enlarge(40, 2); - - // Takes 2/2, then stopped because it reaches its max amount - assert_eq!(Balances::reserved_balance(1), 40); - assert_eq!(Balances::reserved_balance(2), 40); - assert_eq!(Queues::::get(1), vec![GiltBid { amount: 40, who: 1 }]); - assert_eq!(Queues::::get(2), vec![]); - assert_eq!(QueueTotals::::get(), vec![(1, 40), (0, 0), (0, 0)]); - - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 40, - proportion: Perquintill::from_percent(10), - index: 1, - target: Perquintill::zero(), - } - ); - assert_eq!( - Active::::get(0).unwrap(), - ActiveGilt { proportion: Perquintill::from_percent(10), amount: 40, who: 2, expiry: 7 } - ); - }); -} - -#[test] -fn enlarge_respects_bids_limit() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(3), 40, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(4), 40, 3)); - Gilt::enlarge(100, 2); - - // Should have taken 4/3 and 2/2, then stopped because it's only allowed 2. - assert_eq!(Queues::::get(1), vec![GiltBid { amount: 40, who: 1 }]); - assert_eq!(Queues::::get(2), vec![GiltBid { amount: 40, who: 3 }]); - assert_eq!(Queues::::get(3), vec![]); - assert_eq!(QueueTotals::::get(), vec![(1, 40), (1, 40), (0, 0)]); - - assert_eq!( - Active::::get(0).unwrap(), - ActiveGilt { - proportion: Perquintill::from_percent(10), - amount: 40, - who: 4, - expiry: 10, - } - ); - assert_eq!( - Active::::get(1).unwrap(), - ActiveGilt { proportion: Perquintill::from_percent(10), amount: 40, who: 2, expiry: 7 } - ); - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 80, - proportion: Perquintill::from_percent(20), - index: 2, - target: Perquintill::zero(), - } - ); - }); -} - -#[test] -fn enlarge_respects_amount_limit_and_will_split() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 80, 1)); - Gilt::enlarge(40, 2); - - // Takes 2/2, then stopped because it reaches its max amount - assert_eq!(Queues::::get(1), vec![GiltBid { amount: 40, who: 1 }]); - assert_eq!(QueueTotals::::get(), vec![(1, 40), (0, 0), (0, 0)]); - - assert_eq!( - Active::::get(0).unwrap(), - ActiveGilt { proportion: Perquintill::from_percent(10), amount: 40, who: 1, expiry: 4 } - ); - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 40, - proportion: Perquintill::from_percent(10), - index: 1, - target: Perquintill::zero(), - } - ); - }); -} - -#[test] -fn basic_thaw_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); - Gilt::enlarge(40, 1); - run_to_block(3); - assert_noop!(Gilt::thaw(RuntimeOrigin::signed(1), 0), Error::::NotExpired); - run_to_block(4); - assert_noop!(Gilt::thaw(RuntimeOrigin::signed(1), 1), Error::::Unknown); - assert_noop!(Gilt::thaw(RuntimeOrigin::signed(2), 0), Error::::NotOwner); - assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); - - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 0, - proportion: Perquintill::zero(), - index: 1, - target: Perquintill::zero(), - } - ); - assert_eq!(Active::::get(0), None); - assert_eq!(Balances::free_balance(1), 100); - assert_eq!(Balances::reserved_balance(1), 0); - }); -} - -#[test] -fn thaw_when_issuance_higher_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 100, 1)); - Gilt::enlarge(100, 1); - - // Everybody else's balances goes up by 50% - Balances::make_free_balance_be(&2, 150); - Balances::make_free_balance_be(&3, 150); - Balances::make_free_balance_be(&4, 150); - - run_to_block(4); - assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); - - assert_eq!(Balances::free_balance(1), 150); - assert_eq!(Balances::reserved_balance(1), 0); - }); -} - -#[test] -fn thaw_with_ignored_issuance_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - // Give account zero some balance. - Balances::make_free_balance_be(&0, 200); - - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 100, 1)); - Gilt::enlarge(100, 1); - - // Account zero transfers 50 into everyone else's accounts. - assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 2, 50)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 3, 50)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 4, 50)); - - run_to_block(4); - assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); - - // Account zero changes have been ignored. - assert_eq!(Balances::free_balance(1), 150); - assert_eq!(Balances::reserved_balance(1), 0); - }); -} - -#[test] -fn thaw_when_issuance_lower_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 100, 1)); - Gilt::enlarge(100, 1); - - // Everybody else's balances goes down by 25% - Balances::make_free_balance_be(&2, 75); - Balances::make_free_balance_be(&3, 75); - Balances::make_free_balance_be(&4, 75); - - run_to_block(4); - assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); - - assert_eq!(Balances::free_balance(1), 75); - assert_eq!(Balances::reserved_balance(1), 0); - }); -} - -#[test] -fn multiple_thaws_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 60, 1)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 50, 1)); - Gilt::enlarge(200, 3); - - // Double everyone's free balances. - Balances::make_free_balance_be(&2, 100); - Balances::make_free_balance_be(&3, 200); - Balances::make_free_balance_be(&4, 200); - - run_to_block(4); - assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); - assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 1)); - assert_ok!(Gilt::thaw(RuntimeOrigin::signed(2), 2)); - - assert_eq!(Balances::free_balance(1), 200); - assert_eq!(Balances::free_balance(2), 200); - }); -} - -#[test] -fn multiple_thaws_works_in_alternative_thaw_order() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 60, 1)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 50, 1)); - Gilt::enlarge(200, 3); - - // Double everyone's free balances. - Balances::make_free_balance_be(&2, 100); - Balances::make_free_balance_be(&3, 200); - Balances::make_free_balance_be(&4, 200); - - run_to_block(4); - assert_ok!(Gilt::thaw(RuntimeOrigin::signed(2), 2)); - assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 1)); - assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); - - assert_eq!(Balances::free_balance(1), 200); - assert_eq!(Balances::free_balance(2), 200); - }); -} - -#[test] -fn enlargement_to_target_works() { - new_test_ext().execute_with(|| { - run_to_block(2); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 2)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 3)); - assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(3), 40, 3)); - assert_ok!(Gilt::set_target(RuntimeOrigin::signed(1), Perquintill::from_percent(40))); - - run_to_block(3); - assert_eq!(Queues::::get(1), vec![GiltBid { amount: 40, who: 1 },]); - assert_eq!( - Queues::::get(2), - vec![GiltBid { amount: 40, who: 2 }, GiltBid { amount: 40, who: 1 },] - ); - assert_eq!( - Queues::::get(3), - vec![GiltBid { amount: 40, who: 3 }, GiltBid { amount: 40, who: 2 },] - ); - assert_eq!(QueueTotals::::get(), vec![(1, 40), (2, 80), (2, 80)]); - - run_to_block(4); - // Two new gilts should have been issued to 2 & 3 for 40 each & duration of 3. - assert_eq!( - Active::::get(0).unwrap(), - ActiveGilt { - proportion: Perquintill::from_percent(10), - amount: 40, - who: 2, - expiry: 13, - } - ); - assert_eq!( - Active::::get(1).unwrap(), - ActiveGilt { - proportion: Perquintill::from_percent(10), - amount: 40, - who: 3, - expiry: 13, - } - ); - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 80, - proportion: Perquintill::from_percent(20), - index: 2, - target: Perquintill::from_percent(40), - } - ); - - run_to_block(5); - // No change - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 80, - proportion: Perquintill::from_percent(20), - index: 2, - target: Perquintill::from_percent(40), - } - ); - - run_to_block(6); - // Two new gilts should have been issued to 1 & 2 for 40 each & duration of 2. - assert_eq!( - Active::::get(2).unwrap(), - ActiveGilt { - proportion: Perquintill::from_percent(10), - amount: 40, - who: 1, - expiry: 12, - } - ); - assert_eq!( - Active::::get(3).unwrap(), - ActiveGilt { - proportion: Perquintill::from_percent(10), - amount: 40, - who: 2, - expiry: 12, - } - ); - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 160, - proportion: Perquintill::from_percent(40), - index: 4, - target: Perquintill::from_percent(40), - } - ); - - run_to_block(8); - // No change now. - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 160, - proportion: Perquintill::from_percent(40), - index: 4, - target: Perquintill::from_percent(40), - } - ); - - // Set target a bit higher to use up the remaining bid. - assert_ok!(Gilt::set_target(RuntimeOrigin::signed(1), Perquintill::from_percent(60))); - run_to_block(10); - - // Two new gilts should have been issued to 1 & 2 for 40 each & duration of 2. - assert_eq!( - Active::::get(4).unwrap(), - ActiveGilt { - proportion: Perquintill::from_percent(10), - amount: 40, - who: 1, - expiry: 13, - } - ); - - assert_eq!( - ActiveTotal::::get(), - ActiveGiltsTotal { - frozen: 200, - proportion: Perquintill::from_percent(50), - index: 5, - target: Perquintill::from_percent(60), - } - ); - }); -} diff --git a/frame/gilt/Cargo.toml b/frame/nis/Cargo.toml similarity index 93% rename from frame/gilt/Cargo.toml rename to frame/nis/Cargo.toml index f7bd98999f79d..be12d97dd871d 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/nis/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pallet-gilt" +name = "pallet-nis" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" @@ -19,12 +19,12 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } -sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-io = { version = "7.0.0", path = "../../primitives/io" } [features] @@ -36,6 +36,7 @@ std = [ "frame-system/std", "scale-info/std", "sp-arithmetic/std", + "sp-core/std", "sp-runtime/std", "sp-std/std", ] diff --git a/frame/gilt/README.md b/frame/nis/README.md similarity index 100% rename from frame/gilt/README.md rename to frame/nis/README.md diff --git a/frame/nis/src/benchmarking.rs b/frame/nis/src/benchmarking.rs new file mode 100644 index 0000000000000..606b1c484b1e8 --- /dev/null +++ b/frame/nis/src/benchmarking.rs @@ -0,0 +1,182 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmarks for NIS Pallet + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_support::traits::{Currency, EnsureOrigin, Get}; +use frame_system::RawOrigin; +use sp_arithmetic::Perquintill; +use sp_runtime::{ + traits::{Bounded, One, Zero}, + DispatchError, PerThing, +}; +use sp_std::prelude::*; + +use crate::Pallet as Nis; + +const SEED: u32 = 0; + +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +fn fill_queues() -> Result<(), DispatchError> { + // filling queues involves filling the first queue entirely and placing a single item in all + // other queues. + + let queues = T::QueueCount::get(); + let bids = T::MaxQueueLen::get(); + + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be( + &caller, + T::MinBid::get() * BalanceOf::::from(queues + bids), + ); + + for _ in 0..bids { + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinBid::get(), 1)?; + } + for d in 1..queues { + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinBid::get(), 1 + d)?; + } + Ok(()) +} + +benchmarks! { + place_bid { + let l in 0..(T::MaxQueueLen::get() - 1); + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + for i in 0..l { + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinBid::get(), 1)?; + } + }: _(RawOrigin::Signed(caller.clone()), T::MinBid::get() * BalanceOf::::from(2u32), 1) + verify { + assert_eq!(QueueTotals::::get()[0], (l + 1, T::MinBid::get() * BalanceOf::::from(l + 2))); + } + + place_bid_max { + let caller: T::AccountId = whitelisted_caller(); + let origin = RawOrigin::Signed(caller.clone()); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + for i in 0..T::MaxQueueLen::get() { + Nis::::place_bid(origin.clone().into(), T::MinBid::get(), 1)?; + } + }: place_bid(origin, T::MinBid::get() * BalanceOf::::from(2u32), 1) + verify { + assert_eq!(QueueTotals::::get()[0], ( + T::MaxQueueLen::get(), + T::MinBid::get() * BalanceOf::::from(T::MaxQueueLen::get() + 1), + )); + } + + retract_bid { + let l in 1..T::MaxQueueLen::get(); + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + for i in 0..l { + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinBid::get(), 1)?; + } + }: _(RawOrigin::Signed(caller.clone()), T::MinBid::get(), 1) + verify { + assert_eq!(QueueTotals::::get()[0], (l - 1, T::MinBid::get() * BalanceOf::::from(l - 1))); + } + + fund_deficit { + let origin = T::FundOrigin::successful_origin(); + let caller: T::AccountId = whitelisted_caller(); + let bid = T::MinBid::get().max(One::one()); + T::Currency::make_free_balance_be(&caller, bid); + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 1)?; + Nis::::process_queues(Perquintill::one(), 1, 1, &mut WeightCounter::unlimited()); + let original = T::Currency::free_balance(&Nis::::account_id()); + T::Currency::make_free_balance_be(&Nis::::account_id(), BalanceOf::::min_value()); + }: _(origin) + verify { + // Must fund at least 99.999% of the required amount. + let missing = Perquintill::from_rational( + T::Currency::free_balance(&Nis::::account_id()), original).left_from_one(); + assert!(missing <= Perquintill::one() / 100_000); + } + + thaw { + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, T::MinBid::get() * BalanceOf::::from(3u32)); + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinBid::get(), 1)?; + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinBid::get(), 1)?; + Nis::::process_queues(Perquintill::one(), 1, 2, &mut WeightCounter::unlimited()); + Receipts::::mutate(0, |m_g| if let Some(ref mut g) = m_g { g.expiry = Zero::zero() }); + }: _(RawOrigin::Signed(caller.clone()), 0, None) + verify { + assert!(Receipts::::get(0).is_none()); + } + + process_queues { + fill_queues::()?; + }: { + Nis::::process_queues( + Perquintill::one(), + Zero::zero(), + u32::max_value(), + &mut WeightCounter::unlimited(), + ) + } + + process_queue { + let our_account = Nis::::account_id(); + let issuance = Nis::::issuance(); + let mut summary = Summary::::get(); + }: { + Nis::::process_queue( + 1u32, + 1u32.into(), + &our_account, + &issuance, + 0, + &mut Bounded::max_value(), + &mut (T::MaxQueueLen::get(), Bounded::max_value()), + &mut summary, + &mut WeightCounter::unlimited(), + ) + } + + process_bid { + let who = account::("bidder", 0, SEED); + let bid = Bid { + amount: T::MinBid::get(), + who, + }; + let our_account = Nis::::account_id(); + let issuance = Nis::::issuance(); + let mut summary = Summary::::get(); + }: { + Nis::::process_bid( + bid, + 2u32.into(), + &our_account, + &issuance, + &mut Bounded::max_value(), + &mut Bounded::max_value(), + &mut summary, + ) + } + + impl_benchmark_test_suite!(Nis, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/nis/src/lib.rs b/frame/nis/src/lib.rs new file mode 100644 index 0000000000000..97f727c241479 --- /dev/null +++ b/frame/nis/src/lib.rs @@ -0,0 +1,936 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Non-Interactive Staking (NIS) Pallet +//! A pallet allowing accounts to auction for being frozen and receive open-ended +//! inflation-protection in return. +//! +//! ## Overview +//! +//! Lock up tokens, for at least as long as you offer, and be free from both inflation and +//! intermediate reward or exchange until the tokens become unlocked. +//! +//! ## Design +//! +//! Queues for each of `1..QueueCount` periods, given in blocks (`Period`). Queues are limited in +//! size to something sensible, `MaxQueueLen`. A secondary storage item with `QueueCount` x `u32` +//! elements with the number of items in each queue. +//! +//! Queues are split into two parts. The first part is a priority queue based on bid size. The +//! second part is just a FIFO (the size of the second part is set with `FifoQueueLen`). Items are +//! always prepended so that removal is always O(1) since removal often happens many times under a +//! single weighed function (`on_initialize`) yet placing bids only ever happens once per weighed +//! function (`place_bid`). If the queue has a priority portion, then it remains sorted in order of +//! bid size so that smaller bids fall off as it gets too large. +//! +//! Account may enqueue a balance with some number of `Period`s lock up, up to a maximum of +//! `QueueCount`. The balance gets reserved. There's a minimum of `MinBid` to avoid dust. +//! +//! Until your bid is consolidated and you receive a receipt, you can retract it instantly and the +//! funds are unreserved. +//! +//! There's a target proportion of effective total issuance (i.e. accounting for existing receipts) +//! which the pallet attempts to have frozen at any one time. It will likely be gradually increased +//! over time by governance. +//! +//! As the proportion of effective total issuance represented by outstanding receipts drops below +//! `FrozenFraction`, then bids are taken from queues and consolidated into receipts, with the queue +//! of the greatest period taking priority. If the item in the queue's locked amount is greater than +//! the amount remaining to achieve `FrozenFraction`, then it is split up into multiple bids and +//! becomes partially consolidated. +//! +//! With the consolidation of a bid, the bid amount is taken from the owner and a receipt is issued. +//! The receipt records the proportion of the bid compared to effective total issuance at the time +//! of consolidation. The receipt has two independent elements: a "main" non-fungible receipt and +//! a second set of fungible "counterpart" tokens. The accounting functionality of the latter must +//! be provided through the `Counterpart` trait item. The main non-fungible receipt may have its +//! owner transferred through the pallet's implementation of `nonfungible::Transfer`. +//! +//! A later `thaw` function may be called in order to reduce the recorded proportion or entirely +//! remove the receipt in return for the appropriate proportion of the effective total issuance. +//! This may happen no earlier than queue's period after the point at which the receipt was issued. +//! The call must be made by the owner of both the "main" non-fungible receipt and the appropriate +//! amount of counterpart tokens. +//! +//! `NoCounterpart` may be provided as an implementation for the counterpart token system in which +//! case they are completely disregarded from the thawing logic. +//! +//! ## Terms +//! +//! - *Effective total issuance*: The total issuance of balances in the system, including all claims +//! of all outstanding receipts but excluding `IgnoredIssuance`. + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::{ + dispatch::{DispatchError, DispatchResult}, + traits::fungible::{Inspect as FungibleInspect, Mutate as FungibleMutate}, +}; +pub use pallet::*; +use sp_arithmetic::{traits::Unsigned, RationalArg}; +use sp_core::TypedGet; +use sp_runtime::{ + traits::{Convert, ConvertBack}, + Perquintill, +}; + +mod benchmarking; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; +pub mod weights; + +pub struct WithMaximumOf(sp_std::marker::PhantomData); +impl Convert for WithMaximumOf +where + A::Type: Clone + Unsigned + From, + u64: TryFrom, +{ + fn convert(a: Perquintill) -> A::Type { + a * A::get() + } +} +impl ConvertBack for WithMaximumOf +where + A::Type: RationalArg + From, + u64: TryFrom, + u128: TryFrom, +{ + fn convert_back(a: A::Type) -> Perquintill { + Perquintill::from_rational(a, A::get()) + } +} + +pub struct NoCounterpart(sp_std::marker::PhantomData); +impl FungibleInspect for NoCounterpart { + type Balance = u32; + fn total_issuance() -> u32 { + 0 + } + fn minimum_balance() -> u32 { + 0 + } + fn balance(_who: &T) -> u32 { + 0 + } + fn reducible_balance(_who: &T, _keep_alive: bool) -> u32 { + 0 + } + fn can_deposit( + _who: &T, + _amount: u32, + _mint: bool, + ) -> frame_support::traits::tokens::DepositConsequence { + frame_support::traits::tokens::DepositConsequence::Success + } + fn can_withdraw( + _who: &T, + _amount: u32, + ) -> frame_support::traits::tokens::WithdrawConsequence { + frame_support::traits::tokens::WithdrawConsequence::Success + } +} +impl FungibleMutate for NoCounterpart { + fn mint_into(_who: &T, _amount: u32) -> DispatchResult { + Ok(()) + } + fn burn_from(_who: &T, _amount: u32) -> Result { + Ok(0) + } +} +impl Convert for NoCounterpart { + fn convert(_: Perquintill) -> u32 { + 0 + } +} + +#[frame_support::pallet] +pub mod pallet { + use super::{FungibleInspect, FungibleMutate}; + pub use crate::weights::WeightInfo; + use frame_support::{ + pallet_prelude::*, + traits::{ + nonfungible::{Inspect as NonfungibleInspect, Transfer as NonfungibleTransfer}, + Currency, Defensive, DefensiveSaturating, + ExistenceRequirement::AllowDeath, + OnUnbalanced, ReservableCurrency, + }, + PalletId, + }; + use frame_system::pallet_prelude::*; + use sp_arithmetic::{PerThing, Perquintill}; + use sp_runtime::{ + traits::{AccountIdConversion, Bounded, Convert, ConvertBack, Saturating, Zero}, + TokenError, + }; + use sp_std::prelude::*; + + type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + type PositiveImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::PositiveImbalance; + type ReceiptRecordOf = ReceiptRecord< + ::AccountId, + ::BlockNumber, + >; + type IssuanceInfoOf = IssuanceInfo>; + type SummaryRecordOf = SummaryRecord<::BlockNumber>; + type BidOf = Bid, ::AccountId>; + type QueueTotalsTypeOf = BoundedVec<(u32, BalanceOf), ::QueueCount>; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// Information on runtime weights. + type WeightInfo: WeightInfo; + + /// Overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The treasury's pallet id, used for deriving its sovereign account ID. + #[pallet::constant] + type PalletId: Get; + + /// Currency type that this works on. + type Currency: ReservableCurrency; + + /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to + /// `From`. + type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned + + codec::FullCodec + + Copy + + MaybeSerializeDeserialize + + sp_std::fmt::Debug + + Default + + From + + TypeInfo + + MaxEncodedLen; + + /// Origin required for auto-funding the deficit. + type FundOrigin: EnsureOrigin; + + /// The issuance to ignore. This is subtracted from the `Currency`'s `total_issuance` to get + /// the issuance with which we determine the thawed value of a given proportion. + type IgnoredIssuance: Get>; + + /// The accounting system for the fungible counterpart tokens. + type Counterpart: FungibleMutate; + + /// The system to convert an overall proportion of issuance into a number of fungible + /// counterpart tokens. + /// + /// In general it's best to use `WithMaximumOf`. + type CounterpartAmount: ConvertBack< + Perquintill, + >::Balance, + >; + + /// Unbalanced handler to account for funds created (in case of a higher total issuance over + /// freezing period). + type Deficit: OnUnbalanced>; + + /// The target sum of all receipts' proportions. + type Target: Get; + + /// Number of duration queues in total. This sets the maximum duration supported, which is + /// this value multiplied by `Period`. + #[pallet::constant] + type QueueCount: Get; + + /// Maximum number of items that may be in each duration queue. + /// + /// Must be larger than zero. + #[pallet::constant] + type MaxQueueLen: Get; + + /// Portion of the queue which is free from ordering and just a FIFO. + /// + /// Must be no greater than `MaxQueueLen`. + #[pallet::constant] + type FifoQueueLen: Get; + + /// The base period for the duration queues. This is the common multiple across all + /// supported freezing durations that can be bid upon. + #[pallet::constant] + type BasePeriod: Get; + + /// The minimum amount of funds that may be placed in a bid. Note that this + /// does not actually limit the amount which may be represented in a receipt since bids may + /// be split up by the system. + /// + /// It should be at least big enough to ensure that there is no possible storage spam attack + /// or queue-filling attack. + #[pallet::constant] + type MinBid: Get>; + + /// The minimum amount of funds which may intentionally be left remaining under a single + /// receipt. + #[pallet::constant] + type MinReceipt: Get; + + /// The number of blocks between consecutive attempts to dequeue bids and create receipts. + /// + /// A larger value results in fewer storage hits each block, but a slower period to get to + /// the target. + #[pallet::constant] + type IntakePeriod: Get; + + /// The maximum amount of bids that can consolidated into receipts in a single intake. A + /// larger value here means less of the block available for transactions should there be a + /// glut of bids. + #[pallet::constant] + type MaxIntakeWeight: Get; + + /// The maximum proportion which may be thawed and the period over which it is reset. + #[pallet::constant] + type ThawThrottle: Get<(Perquintill, Self::BlockNumber)>; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + /// A single bid, an item of a *queue* in `Queues`. + #[derive( + Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, + )] + pub struct Bid { + /// The amount bid. + pub amount: Balance, + /// The owner of the bid. + pub who: AccountId, + } + + /// Information representing a receipt. + #[derive( + Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, + )] + pub struct ReceiptRecord { + /// The proportion of the effective total issuance. + pub proportion: Perquintill, + /// The account to whom this receipt belongs. + pub who: AccountId, + /// The time after which this receipt can be thawed. + pub expiry: BlockNumber, + } + + /// An index for a receipt. + pub type ReceiptIndex = u32; + + /// Overall information package on the outstanding receipts. + /// + /// The way of determining the net issuance (i.e. after factoring in all maturing frozen funds) + /// is: + /// + /// `issuance - frozen + proportion * issuance` + /// + /// where `issuance = total_issuance - IgnoredIssuance` + #[derive( + Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, + )] + pub struct SummaryRecord { + /// The total proportion over all outstanding receipts. + pub proportion_owed: Perquintill, + /// The total number of receipts created so far. + pub index: ReceiptIndex, + /// The amount (as a proportion of ETI) which has been thawed in this period so far. + pub thawed: Perquintill, + /// The current thaw period's beginning. + pub last_period: BlockNumber, + } + + pub struct OnEmptyQueueTotals(sp_std::marker::PhantomData); + impl Get> for OnEmptyQueueTotals { + fn get() -> QueueTotalsTypeOf { + BoundedVec::truncate_from(vec![ + (0, Zero::zero()); + ::QueueCount::get() as usize + ]) + } + } + + /// The totals of items and balances within each queue. Saves a lot of storage reads in the + /// case of sparsely packed queues. + /// + /// The vector is indexed by duration in `Period`s, offset by one, so information on the queue + /// whose duration is one `Period` would be storage `0`. + #[pallet::storage] + pub type QueueTotals = + StorageValue<_, QueueTotalsTypeOf, ValueQuery, OnEmptyQueueTotals>; + + /// The queues of bids. Indexed by duration (in `Period`s). + #[pallet::storage] + pub type Queues = + StorageMap<_, Blake2_128Concat, u32, BoundedVec, T::MaxQueueLen>, ValueQuery>; + + /// Summary information over the general state. + #[pallet::storage] + pub type Summary = StorageValue<_, SummaryRecordOf, ValueQuery>; + + /// The currently outstanding receipts, indexed according to the order of creation. + #[pallet::storage] + pub type Receipts = + StorageMap<_, Blake2_128Concat, ReceiptIndex, ReceiptRecordOf, OptionQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A bid was successfully placed. + BidPlaced { who: T::AccountId, amount: BalanceOf, duration: u32 }, + /// A bid was successfully removed (before being accepted). + BidRetracted { who: T::AccountId, amount: BalanceOf, duration: u32 }, + /// A bid was dropped from a queue because of another, more substantial, bid was present. + BidDropped { who: T::AccountId, amount: BalanceOf, duration: u32 }, + /// A bid was accepted. The balance may not be released until expiry. + Issued { + /// The identity of the receipt. + index: ReceiptIndex, + /// The block number at which the receipt may be thawed. + expiry: T::BlockNumber, + /// The owner of the receipt. + who: T::AccountId, + /// The proportion of the effective total issuance which the receipt represents. + proportion: Perquintill, + /// The amount of funds which were debited from the owner. + amount: BalanceOf, + }, + /// An receipt has been (at least partially) thawed. + Thawed { + /// The identity of the receipt. + index: ReceiptIndex, + /// The owner. + who: T::AccountId, + /// The proportion of the effective total issuance by which the owner was debited. + proportion: Perquintill, + /// The amount by which the owner was credited. + amount: BalanceOf, + /// If `true` then the receipt is done. + dropped: bool, + }, + /// An automatic funding of the deficit was made. + Funded { deficit: BalanceOf }, + /// A receipt was transfered. + Transferred { from: T::AccountId, to: T::AccountId, index: ReceiptIndex }, + } + + #[pallet::error] + pub enum Error { + /// The duration of the bid is less than one. + DurationTooSmall, + /// The duration is the bid is greater than the number of queues. + DurationTooBig, + /// The amount of the bid is less than the minimum allowed. + AmountTooSmall, + /// The queue for the bid's duration is full and the amount bid is too low to get in + /// through replacing an existing bid. + BidTooLow, + /// Bond index is unknown. + Unknown, + /// Not the owner of the receipt. + NotOwner, + /// Bond not yet at expiry date. + NotExpired, + /// The given bid for retraction is not found. + NotFound, + /// The portion supplied is beyond the value of the receipt. + TooMuch, + /// Not enough funds are held to pay out. + Unfunded, + /// There are enough funds for what is required. + Funded, + /// The thaw throttle has been reached for this period. + Throttled, + /// The operation would result in a receipt worth an insignficant value. + MakesDust, + } + + pub(crate) struct WeightCounter { + pub(crate) used: Weight, + pub(crate) limit: Weight, + } + impl WeightCounter { + #[allow(dead_code)] + pub(crate) fn unlimited() -> Self { + WeightCounter { used: Weight::zero(), limit: Weight::max_value() } + } + fn check_accrue(&mut self, w: Weight) -> bool { + let test = self.used.saturating_add(w); + if test.any_gt(self.limit) { + false + } else { + self.used = test; + true + } + } + fn can_accrue(&mut self, w: Weight) -> bool { + self.used.saturating_add(w).all_lte(self.limit) + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(n: T::BlockNumber) -> Weight { + let mut weight_counter = + WeightCounter { used: Weight::zero(), limit: T::MaxIntakeWeight::get() }; + if T::IntakePeriod::get().is_zero() || (n % T::IntakePeriod::get()).is_zero() { + if weight_counter.check_accrue(T::WeightInfo::process_queues()) { + Self::process_queues( + T::Target::get(), + T::QueueCount::get(), + u32::max_value(), + &mut weight_counter, + ) + } + } + weight_counter.used + } + + fn integrity_test() { + assert!(!T::IntakePeriod::get().is_zero()); + assert!(!T::MaxQueueLen::get().is_zero()); + } + } + + #[pallet::call] + impl Pallet { + /// Place a bid. + /// + /// Origin must be Signed, and account must have at least `amount` in free balance. + /// + /// - `amount`: The amount of the bid; these funds will be reserved, and if/when + /// consolidated, removed. Must be at least `MinBid`. + /// - `duration`: The number of periods before which the newly consolidated bid may be + /// thawed. Must be greater than 1 and no more than `QueueCount`. + /// + /// Complexities: + /// - `Queues[duration].len()` (just take max). + #[pallet::weight(T::WeightInfo::place_bid_max())] + pub fn place_bid( + origin: OriginFor, + #[pallet::compact] amount: BalanceOf, + duration: u32, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + ensure!(amount >= T::MinBid::get(), Error::::AmountTooSmall); + let queue_count = T::QueueCount::get() as usize; + let queue_index = duration.checked_sub(1).ok_or(Error::::DurationTooSmall)? as usize; + ensure!(queue_index < queue_count, Error::::DurationTooBig); + + let net = Queues::::try_mutate( + duration, + |q| -> Result<(u32, BalanceOf), DispatchError> { + let queue_full = q.len() == T::MaxQueueLen::get() as usize; + ensure!(!queue_full || q[0].amount < amount, Error::::BidTooLow); + T::Currency::reserve(&who, amount)?; + + // queue is + let mut bid = Bid { amount, who: who.clone() }; + let net = if queue_full { + sp_std::mem::swap(&mut q[0], &mut bid); + let _ = T::Currency::unreserve(&bid.who, bid.amount); + Self::deposit_event(Event::::BidDropped { + who: bid.who, + amount: bid.amount, + duration, + }); + (0, amount - bid.amount) + } else { + q.try_insert(0, bid).expect("verified queue was not full above. qed."); + (1, amount) + }; + + let sorted_item_count = q.len().saturating_sub(T::FifoQueueLen::get() as usize); + if sorted_item_count > 1 { + q[0..sorted_item_count].sort_by_key(|x| x.amount); + } + + Ok(net) + }, + )?; + QueueTotals::::mutate(|qs| { + qs.bounded_resize(queue_count, (0, Zero::zero())); + qs[queue_index].0 += net.0; + qs[queue_index].1.saturating_accrue(net.1); + }); + Self::deposit_event(Event::BidPlaced { who, amount, duration }); + + Ok(()) + } + + /// Retract a previously placed bid. + /// + /// Origin must be Signed, and the account should have previously issued a still-active bid + /// of `amount` for `duration`. + /// + /// - `amount`: The amount of the previous bid. + /// - `duration`: The duration of the previous bid. + #[pallet::weight(T::WeightInfo::retract_bid(T::MaxQueueLen::get()))] + pub fn retract_bid( + origin: OriginFor, + #[pallet::compact] amount: BalanceOf, + duration: u32, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + let queue_count = T::QueueCount::get() as usize; + let queue_index = duration.checked_sub(1).ok_or(Error::::DurationTooSmall)? as usize; + ensure!(queue_index < queue_count, Error::::DurationTooBig); + + let bid = Bid { amount, who }; + let new_len = Queues::::try_mutate(duration, |q| -> Result { + let pos = q.iter().position(|i| i == &bid).ok_or(Error::::NotFound)?; + q.remove(pos); + Ok(q.len() as u32) + })?; + + QueueTotals::::mutate(|qs| { + qs.bounded_resize(queue_count, (0, Zero::zero())); + qs[queue_index].0 = new_len; + qs[queue_index].1.saturating_reduce(bid.amount); + }); + + T::Currency::unreserve(&bid.who, bid.amount); + Self::deposit_event(Event::BidRetracted { who: bid.who, amount: bid.amount, duration }); + + Ok(()) + } + + /// Ensure we have sufficient funding for all potential payouts. + /// + /// - `origin`: Must be accepted by `FundOrigin`. + #[pallet::weight(T::WeightInfo::fund_deficit())] + pub fn fund_deficit(origin: OriginFor) -> DispatchResult { + T::FundOrigin::ensure_origin(origin)?; + let summary: SummaryRecordOf = Summary::::get(); + let our_account = Self::account_id(); + let issuance = Self::issuance_with(&our_account, &summary); + let deficit = issuance.required.saturating_sub(issuance.holdings); + ensure!(!deficit.is_zero(), Error::::Funded); + T::Deficit::on_unbalanced(T::Currency::deposit_creating(&our_account, deficit)); + Self::deposit_event(Event::::Funded { deficit }); + Ok(()) + } + + /// Reduce or remove an outstanding receipt, placing the according proportion of funds into + /// the account of the owner. + /// + /// - `origin`: Must be Signed and the account must be the owner of the receipt `index` as + /// well as any fungible counterpart. + /// - `index`: The index of the receipt. + /// - `portion`: If `Some`, then only the given portion of the receipt should be thawed. If + /// `None`, then all of it should be. + #[pallet::weight(T::WeightInfo::thaw())] + pub fn thaw( + origin: OriginFor, + #[pallet::compact] index: ReceiptIndex, + portion: Option<>::Balance>, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Look for `index` + let mut receipt: ReceiptRecordOf = + Receipts::::get(index).ok_or(Error::::Unknown)?; + // If found, check the owner is `who`. + ensure!(receipt.who == who, Error::::NotOwner); + let now = frame_system::Pallet::::block_number(); + ensure!(now >= receipt.expiry, Error::::NotExpired); + + let mut summary: SummaryRecordOf = Summary::::get(); + + let proportion = if let Some(counterpart) = portion { + let proportion = T::CounterpartAmount::convert_back(counterpart); + ensure!(proportion <= receipt.proportion, Error::::TooMuch); + let remaining = receipt.proportion.saturating_sub(proportion); + ensure!( + remaining.is_zero() || remaining >= T::MinReceipt::get(), + Error::::MakesDust + ); + proportion + } else { + receipt.proportion + }; + + let (throttle, throttle_period) = T::ThawThrottle::get(); + if now.saturating_sub(summary.last_period) >= throttle_period { + summary.thawed = Zero::zero(); + summary.last_period = now; + } + summary.thawed.saturating_accrue(proportion); + ensure!(summary.thawed <= throttle, Error::::Throttled); + + T::Counterpart::burn_from(&who, T::CounterpartAmount::convert(proportion))?; + + // Multiply the proportion it is by the total issued. + let our_account = Self::account_id(); + let effective_issuance = Self::issuance_with(&our_account, &summary).effective; + let amount = proportion * effective_issuance; + + receipt.proportion.saturating_reduce(proportion); + summary.proportion_owed.saturating_reduce(proportion); + + T::Currency::transfer(&our_account, &who, amount, AllowDeath) + .map_err(|_| Error::::Unfunded)?; + + let dropped = receipt.proportion.is_zero(); + if dropped { + Receipts::::remove(index); + } else { + Receipts::::insert(index, &receipt); + } + Summary::::put(&summary); + + Self::deposit_event(Event::Thawed { index, who, amount, proportion, dropped }); + + Ok(()) + } + } + + /// Issuance information returned by `issuance()`. + #[derive(RuntimeDebug)] + pub struct IssuanceInfo { + /// The balance held in reserve by this pallet instance. + pub holdings: Balance, + /// The (non-ignored) issuance in the system, not including this pallet's account. + pub other: Balance, + /// The effective total issuance, hypothetically if all outstanding receipts were thawed at + /// present. + pub effective: Balance, + /// The amount needed to be the pallet instance's account in case all outstanding receipts + /// were thawed at present. + pub required: Balance, + } + + impl NonfungibleInspect for Pallet { + type ItemId = ReceiptIndex; + + fn owner(item: &ReceiptIndex) -> Option { + Receipts::::get(item).map(|r| r.who) + } + + fn attribute(item: &Self::ItemId, key: &[u8]) -> Option> { + let item = Receipts::::get(item)?; + match key { + b"proportion" => Some(item.proportion.encode()), + b"expiry" => Some(item.expiry.encode()), + _ => None, + } + } + } + + impl NonfungibleTransfer for Pallet { + fn transfer(index: &ReceiptIndex, destination: &T::AccountId) -> DispatchResult { + let mut item = Receipts::::get(index).ok_or(TokenError::UnknownAsset)?; + let from = item.who; + item.who = destination.clone(); + Receipts::::insert(&index, &item); + Pallet::::deposit_event(Event::::Transferred { + from, + to: item.who, + index: *index, + }); + Ok(()) + } + } + + impl Pallet { + /// The account ID of the reserves. + /// + /// This actually does computation. If you need to keep using it, then make sure you cache + /// the value and only call this once. + pub fn account_id() -> T::AccountId { + T::PalletId::get().into_account_truncating() + } + + /// Returns information on the issuance within the system. + pub fn issuance() -> IssuanceInfo> { + Self::issuance_with(&Self::account_id(), &Summary::::get()) + } + + /// Returns information on the issuance within the system + /// + /// This function is equivalent to `issuance`, except that it accepts arguments rather than + /// queries state. If the arguments are already known, then this may be slightly more + /// performant. + /// + /// - `our_account`: The value returned by `Self::account_id()`. + /// - `summary`: The value returned by `Summary::::get()`. + pub fn issuance_with( + our_account: &T::AccountId, + summary: &SummaryRecordOf, + ) -> IssuanceInfo> { + let total_issuance = + T::Currency::total_issuance().saturating_sub(T::IgnoredIssuance::get()); + let holdings = T::Currency::free_balance(our_account); + let other = total_issuance.saturating_sub(holdings); + let effective = + summary.proportion_owed.left_from_one().saturating_reciprocal_mul(other); + let required = summary.proportion_owed * effective; + IssuanceInfo { holdings, other, effective, required } + } + + /// Process some bids into receipts up to a `target` total of all receipts. + /// + /// Touch at most `max_queues`. + /// + /// Return the weight used. + pub(crate) fn process_queues( + target: Perquintill, + max_queues: u32, + max_bids: u32, + weight: &mut WeightCounter, + ) { + let mut summary: SummaryRecordOf = Summary::::get(); + if summary.proportion_owed >= target { + return + } + + let now = frame_system::Pallet::::block_number(); + let our_account = Self::account_id(); + let issuance: IssuanceInfoOf = Self::issuance_with(&our_account, &summary); + let mut remaining = target.saturating_sub(summary.proportion_owed) * issuance.effective; + + let mut queues_hit = 0; + let mut bids_hit = 0; + let mut totals = QueueTotals::::get(); + let queue_count = T::QueueCount::get(); + totals.bounded_resize(queue_count as usize, (0, Zero::zero())); + for duration in (1..=queue_count).rev() { + if totals[duration as usize - 1].0.is_zero() { + continue + } + if remaining.is_zero() || queues_hit >= max_queues + || !weight.check_accrue(T::WeightInfo::process_queue()) + // No point trying to process a queue if we can't process a single bid. + || !weight.can_accrue(T::WeightInfo::process_bid()) + { + break + } + + let b = Self::process_queue( + duration, + now, + &our_account, + &issuance, + max_bids.saturating_sub(bids_hit), + &mut remaining, + &mut totals[duration as usize - 1], + &mut summary, + weight, + ); + + bids_hit.saturating_accrue(b); + queues_hit.saturating_inc(); + } + QueueTotals::::put(&totals); + Summary::::put(&summary); + } + + pub(crate) fn process_queue( + duration: u32, + now: T::BlockNumber, + our_account: &T::AccountId, + issuance: &IssuanceInfo>, + max_bids: u32, + remaining: &mut BalanceOf, + queue_total: &mut (u32, BalanceOf), + summary: &mut SummaryRecordOf, + weight: &mut WeightCounter, + ) -> u32 { + let mut queue: BoundedVec, _> = Queues::::get(&duration); + let expiry = now.saturating_add(T::BasePeriod::get().saturating_mul(duration.into())); + let mut count = 0; + + while count < max_bids && + !queue.is_empty() && + !remaining.is_zero() && + weight.check_accrue(T::WeightInfo::process_bid()) + { + let bid = match queue.pop() { + Some(b) => b, + None => break, + }; + if let Some(bid) = Self::process_bid( + bid, + expiry, + our_account, + issuance, + remaining, + &mut queue_total.1, + summary, + ) { + queue.try_push(bid).expect("just popped, so there must be space. qed"); + // This should exit at the next iteration (though nothing will break if it + // doesn't). + } + count.saturating_inc(); + } + queue_total.0 = queue.len() as u32; + Queues::::insert(&duration, &queue); + count + } + + pub(crate) fn process_bid( + mut bid: BidOf, + expiry: T::BlockNumber, + our_account: &T::AccountId, + issuance: &IssuanceInfo>, + remaining: &mut BalanceOf, + queue_amount: &mut BalanceOf, + summary: &mut SummaryRecordOf, + ) -> Option> { + let result = if *remaining < bid.amount { + let overflow = bid.amount - *remaining; + bid.amount = *remaining; + Some(Bid { amount: overflow, who: bid.who.clone() }) + } else { + None + }; + let amount = bid.amount.saturating_sub(T::Currency::unreserve(&bid.who, bid.amount)); + if T::Currency::transfer(&bid.who, &our_account, amount, AllowDeath).is_err() { + return result + } + + // Can never overflow due to block above. + remaining.saturating_reduce(amount); + // Should never underflow since it should track the total of the + // bids exactly, but we'll be defensive. + queue_amount.defensive_saturating_reduce(amount); + + // Now to activate the bid... + let n = amount; + let d = issuance.effective; + let proportion = Perquintill::from_rational(n, d); + let who = bid.who; + let index = summary.index; + summary.proportion_owed.defensive_saturating_accrue(proportion); + summary.index += 1; + + let e = Event::Issued { index, expiry, who: who.clone(), amount, proportion }; + Self::deposit_event(e); + let receipt = ReceiptRecord { proportion, who: who.clone(), expiry }; + Receipts::::insert(index, receipt); + + // issue the fungible counterpart + let fung_eq = T::CounterpartAmount::convert(proportion); + let _ = T::Counterpart::mint_into(&who, fung_eq).defensive(); + result + } + } +} diff --git a/frame/gilt/src/mock.rs b/frame/nis/src/mock.rs similarity index 63% rename from frame/gilt/src/mock.rs rename to frame/nis/src/mock.rs index e1cdf6507ef58..ebe073d683309 100644 --- a/frame/gilt/src/mock.rs +++ b/frame/nis/src/mock.rs @@ -15,15 +15,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Test environment for Gilt pallet. +//! Test environment for NIS pallet. -use crate as pallet_gilt; +use crate::{self as pallet_nis, Perquintill, WithMaximumOf}; use frame_support::{ ord_parameter_types, parameter_types, - traits::{ConstU16, ConstU32, ConstU64, Currency, GenesisBuild, OnFinalize, OnInitialize}, + traits::{ConstU16, ConstU32, ConstU64, Currency, OnFinalize, OnInitialize, StorageMapShim}, + weights::Weight, + PalletId, }; -use sp_core::H256; +use pallet_balances::{Instance1, Instance2}; +use sp_core::{ConstU128, H256}; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, @@ -39,9 +42,10 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Config, Storage, Event}, - Gilt: pallet_gilt::{Pallet, Call, Config, Storage, Event}, + System: frame_system, + Balances: pallet_balances::, + NisBalances: pallet_balances::, + Nis: pallet_nis, } ); @@ -72,7 +76,7 @@ impl frame_system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl pallet_balances::Config for Test { +impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); type RuntimeEvent = RuntimeEvent; @@ -84,52 +88,79 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; } +impl pallet_balances::Config for Test { + type Balance = u128; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = frame_support::traits::ConstU128<1>; + type AccountStore = StorageMapShim< + pallet_balances::Account, + frame_system::Provider, + u64, + pallet_balances::AccountData, + >; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; +} + parameter_types! { pub IgnoredIssuance: u64 = Balances::total_balance(&0); // Account zero is ignored. + pub const NisPalletId: PalletId = PalletId(*b"py/nis "); + pub static Target: Perquintill = Perquintill::zero(); + pub const MinReceipt: Perquintill = Perquintill::from_percent(1); + pub const ThawThrottle: (Perquintill, u64) = (Perquintill::from_percent(25), 5); + pub static MaxIntakeWeight: Weight = Weight::from_ref_time(2_000_000_000_000); } + ord_parameter_types! { pub const One: u64 = 1; } -impl pallet_gilt::Config for Test { +impl pallet_nis::Config for Test { + type WeightInfo = (); type RuntimeEvent = RuntimeEvent; + type PalletId = NisPalletId; type Currency = Balances; - type CurrencyBalance = ::Balance; - type AdminOrigin = frame_system::EnsureSignedBy; + type CurrencyBalance = >::Balance; + type FundOrigin = frame_system::EnsureSigned; type Deficit = (); - type Surplus = (); type IgnoredIssuance = IgnoredIssuance; + type Counterpart = NisBalances; + type CounterpartAmount = WithMaximumOf>; + type Target = Target; type QueueCount = ConstU32<3>; type MaxQueueLen = ConstU32<3>; type FifoQueueLen = ConstU32<1>; - type Period = ConstU64<3>; - type MinFreeze = ConstU64<2>; + type BasePeriod = ConstU64<3>; + type MinBid = ConstU64<2>; type IntakePeriod = ConstU64<2>; - type MaxIntakeBids = ConstU32<2>; - type WeightInfo = (); + type MaxIntakeWeight = MaxIntakeWeight; + type MinReceipt = MinReceipt; + type ThawThrottle = ThawThrottle; } // This function basically just builds a genesis storage key/value store according to // our desired mockup. pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { + pallet_balances::GenesisConfig:: { balances: vec![(1, 100), (2, 100), (3, 100), (4, 100)], } .assimilate_storage(&mut t) .unwrap(); - GenesisBuild::::assimilate_storage(&crate::GenesisConfig, &mut t).unwrap(); t.into() } pub fn run_to_block(n: u64) { while System::block_number() < n { - Gilt::on_finalize(System::block_number()); + Nis::on_finalize(System::block_number()); Balances::on_finalize(System::block_number()); System::on_finalize(System::block_number()); System::set_block_number(System::block_number() + 1); System::on_initialize(System::block_number()); Balances::on_initialize(System::block_number()); - Gilt::on_initialize(System::block_number()); + Nis::on_initialize(System::block_number()); } } diff --git a/frame/nis/src/tests.rs b/frame/nis/src/tests.rs new file mode 100644 index 0000000000000..f0c45cc80b0e5 --- /dev/null +++ b/frame/nis/src/tests.rs @@ -0,0 +1,654 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for NIS pallet. + +use super::*; +use crate::{mock::*, Error}; +use frame_support::{ + assert_noop, assert_ok, + traits::{ + nonfungible::{Inspect, Transfer}, + Currency, + }, +}; +use pallet_balances::{Error as BalancesError, Instance1}; +use sp_arithmetic::Perquintill; +use sp_runtime::{Saturating, TokenError}; + +fn pot() -> u64 { + Balances::free_balance(&Nis::account_id()) +} + +fn enlarge(amount: u64, max_bids: u32) { + let summary: SummaryRecord = Summary::::get(); + let increase_in_proportion_owed = Perquintill::from_rational(amount, Nis::issuance().effective); + let target = summary.proportion_owed.saturating_add(increase_in_proportion_owed); + Nis::process_queues(target, u32::max_value(), max_bids, &mut WeightCounter::unlimited()); +} + +#[test] +fn basic_setup_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + + for q in 0..3 { + assert!(Queues::::get(q).is_empty()); + } + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::zero(), + index: 0, + last_period: 0, + thawed: Perquintill::zero() + } + ); + }); +} + +#[test] +fn place_bid_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_noop!(Nis::place_bid(RuntimeOrigin::signed(1), 1, 2), Error::::AmountTooSmall); + assert_noop!( + Nis::place_bid(RuntimeOrigin::signed(1), 101, 2), + BalancesError::::InsufficientBalance + ); + assert_noop!( + Nis::place_bid(RuntimeOrigin::signed(1), 10, 4), + Error::::DurationTooBig + ); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_eq!(Balances::reserved_balance(1), 10); + assert_eq!(Queues::::get(2), vec![Bid { amount: 10, who: 1 }]); + assert_eq!(QueueTotals::::get(), vec![(0, 0), (1, 10), (0, 0)]); + }); +} + +#[test] +fn place_bid_queuing_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 20, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 5, 2)); + assert_noop!(Nis::place_bid(RuntimeOrigin::signed(1), 5, 2), Error::::BidTooLow); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 15, 2)); + assert_eq!(Balances::reserved_balance(1), 45); + + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 25, 2)); + assert_eq!(Balances::reserved_balance(1), 60); + assert_noop!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 2), Error::::BidTooLow); + assert_eq!( + Queues::::get(2), + vec![ + Bid { amount: 15, who: 1 }, + Bid { amount: 25, who: 1 }, + Bid { amount: 20, who: 1 }, + ] + ); + assert_eq!(QueueTotals::::get(), vec![(0, 0), (3, 60), (0, 0)]); + }); +} + +#[test] +fn place_bid_fails_when_queue_full() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(2), 10, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(3), 10, 2)); + assert_noop!(Nis::place_bid(RuntimeOrigin::signed(4), 10, 2), Error::::BidTooLow); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(4), 10, 3)); + }); +} + +#[test] +fn multiple_place_bids_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 3)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(2), 10, 2)); + + assert_eq!(Balances::reserved_balance(1), 40); + assert_eq!(Balances::reserved_balance(2), 10); + assert_eq!(Queues::::get(1), vec![Bid { amount: 10, who: 1 },]); + assert_eq!( + Queues::::get(2), + vec![ + Bid { amount: 10, who: 2 }, + Bid { amount: 10, who: 1 }, + Bid { amount: 10, who: 1 }, + ] + ); + assert_eq!(Queues::::get(3), vec![Bid { amount: 10, who: 1 },]); + assert_eq!(QueueTotals::::get(), vec![(1, 10), (3, 30), (1, 10)]); + }); +} + +#[test] +fn retract_single_item_queue_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Nis::retract_bid(RuntimeOrigin::signed(1), 10, 1)); + + assert_eq!(Balances::reserved_balance(1), 10); + assert_eq!(Queues::::get(1), vec![]); + assert_eq!(Queues::::get(2), vec![Bid { amount: 10, who: 1 }]); + assert_eq!(QueueTotals::::get(), vec![(0, 0), (1, 10), (0, 0)]); + }); +} + +#[test] +fn retract_with_other_and_duplicate_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(2), 10, 2)); + + assert_ok!(Nis::retract_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_eq!(Balances::reserved_balance(1), 20); + assert_eq!(Balances::reserved_balance(2), 10); + assert_eq!(Queues::::get(1), vec![Bid { amount: 10, who: 1 },]); + assert_eq!( + Queues::::get(2), + vec![Bid { amount: 10, who: 2 }, Bid { amount: 10, who: 1 },] + ); + assert_eq!(QueueTotals::::get(), vec![(1, 10), (2, 20), (0, 0)]); + }); +} + +#[test] +fn retract_non_existent_item_fails() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_noop!(Nis::retract_bid(RuntimeOrigin::signed(1), 10, 1), Error::::NotFound); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_noop!(Nis::retract_bid(RuntimeOrigin::signed(1), 20, 1), Error::::NotFound); + assert_noop!(Nis::retract_bid(RuntimeOrigin::signed(1), 10, 2), Error::::NotFound); + assert_noop!(Nis::retract_bid(RuntimeOrigin::signed(2), 10, 1), Error::::NotFound); + }); +} + +#[test] +fn basic_enlarge_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(2), 40, 2)); + enlarge(40, 2); + + // Takes 2/2, then stopped because it reaches its max amount + assert_eq!(Balances::reserved_balance(1), 40); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(pot(), 40); + + assert_eq!(Queues::::get(1), vec![Bid { amount: 40, who: 1 }]); + assert_eq!(Queues::::get(2), vec![]); + assert_eq!(QueueTotals::::get(), vec![(1, 40), (0, 0), (0, 0)]); + + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::from_percent(10), + index: 1, + last_period: 0, + thawed: Perquintill::zero() + } + ); + assert_eq!( + Receipts::::get(0).unwrap(), + ReceiptRecord { proportion: Perquintill::from_percent(10), who: 2, expiry: 7 } + ); + }); +} + +#[test] +fn enlarge_respects_bids_limit() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(2), 40, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(3), 40, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(4), 40, 3)); + enlarge(100, 2); + + // Should have taken 4/3 and 2/2, then stopped because it's only allowed 2. + assert_eq!(Queues::::get(1), vec![Bid { amount: 40, who: 1 }]); + assert_eq!(Queues::::get(2), vec![Bid { amount: 40, who: 3 }]); + assert_eq!(Queues::::get(3), vec![]); + assert_eq!(QueueTotals::::get(), vec![(1, 40), (1, 40), (0, 0)]); + + assert_eq!( + Receipts::::get(0).unwrap(), + ReceiptRecord { proportion: Perquintill::from_percent(10), who: 4, expiry: 10 } + ); + assert_eq!( + Receipts::::get(1).unwrap(), + ReceiptRecord { proportion: Perquintill::from_percent(10), who: 2, expiry: 7 } + ); + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::from_percent(20), + index: 2, + last_period: 0, + thawed: Perquintill::zero() + } + ); + }); +} + +#[test] +fn enlarge_respects_amount_limit_and_will_split() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 80, 1)); + enlarge(40, 2); + + // Takes 2/2, then stopped because it reaches its max amount + assert_eq!(Queues::::get(1), vec![Bid { amount: 40, who: 1 }]); + assert_eq!(QueueTotals::::get(), vec![(1, 40), (0, 0), (0, 0)]); + + assert_eq!( + Receipts::::get(0).unwrap(), + ReceiptRecord { proportion: Perquintill::from_percent(10), who: 1, expiry: 4 } + ); + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::from_percent(10), + index: 1, + last_period: 0, + thawed: Perquintill::zero() + } + ); + }); +} + +#[test] +fn basic_thaw_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_eq!(Nis::issuance().effective, 400); + assert_eq!(Balances::free_balance(1), 60); + assert_eq!(Balances::reserved_balance(1), 40); + assert_eq!(pot(), 0); + + enlarge(40, 1); + assert_eq!(Nis::issuance().effective, 400); + assert_eq!(Balances::free_balance(1), 60); + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(pot(), 40); + + run_to_block(3); + assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 0, None), Error::::NotExpired); + run_to_block(4); + assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 1, None), Error::::Unknown); + assert_noop!(Nis::thaw(RuntimeOrigin::signed(2), 0, None), Error::::NotOwner); + + assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + assert_eq!(NisBalances::free_balance(1), 0); + assert_eq!(Nis::typed_attribute::<_, Perquintill>(&0, b"proportion"), None); + assert_eq!(Nis::issuance().effective, 400); + assert_eq!(Balances::free_balance(1), 100); + assert_eq!(pot(), 0); + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::zero(), + index: 1, + last_period: 0, + thawed: Perquintill::from_percent(10) + } + ); + assert_eq!(Receipts::::get(0), None); + }); +} + +#[test] +fn partial_thaw_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 80, 1)); + enlarge(80, 1); + assert_eq!(pot(), 80); + + run_to_block(4); + assert_noop!( + Nis::thaw(RuntimeOrigin::signed(1), 0, Some(4_100_000)), + Error::::MakesDust + ); + assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, Some(1_050_000))); + + assert_eq!(NisBalances::free_balance(1), 3_150_000); + assert_eq!( + Nis::typed_attribute::<_, Perquintill>(&0, b"proportion"), + Some(Perquintill::from_rational(3_150_000u64, 21_000_000u64)), + ); + + assert_eq!(Nis::issuance().effective, 400); + assert_eq!(Balances::free_balance(1), 40); + assert_eq!(pot(), 60); + + assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + + assert_eq!(Nis::issuance().effective, 400); + assert_eq!(Balances::free_balance(1), 100); + assert_eq!(pot(), 0); + + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::zero(), + index: 1, + last_period: 0, + thawed: Perquintill::from_percent(20) + } + ); + assert_eq!(Receipts::::get(0), None); + }); +} + +#[test] +fn thaw_respects_transfers() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 40, 1)); + enlarge(40, 1); + run_to_block(4); + + assert_eq!(Nis::owner(&0), Some(1)); + assert_ok!(Nis::transfer(&0, &2)); + + // Transfering the receipt... + assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 0, None), Error::::NotOwner); + // ...can't be thawed due to missing counterpart + assert_noop!(Nis::thaw(RuntimeOrigin::signed(2), 0, None), TokenError::NoFunds); + + // Transfer the counterpart also... + assert_ok!(NisBalances::transfer(RuntimeOrigin::signed(1), 2, 2100000)); + // ...and thawing is possible. + assert_ok!(Nis::thaw(RuntimeOrigin::signed(2), 0, None)); + + assert_eq!(Balances::free_balance(2), 140); + assert_eq!(Balances::free_balance(1), 60); + }); +} + +#[test] +fn thaw_when_issuance_higher_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 100, 1)); + enlarge(100, 1); + + assert_eq!(NisBalances::free_balance(1), 5_250_000); // (25% of 21m) + + // Everybody else's balances goes up by 50% + Balances::make_free_balance_be(&2, 150); + Balances::make_free_balance_be(&3, 150); + Balances::make_free_balance_be(&4, 150); + + run_to_block(4); + + // Unfunded initially... + assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 0, None), Error::::Unfunded); + // ...so we fund. + assert_ok!(Nis::fund_deficit(RuntimeOrigin::signed(1))); + + // Transfer counterpart away... + assert_ok!(NisBalances::transfer(RuntimeOrigin::signed(1), 2, 250_000)); + // ...and it's not thawable. + assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 0, None), TokenError::NoFunds); + + // Transfer counterpart back... + assert_ok!(NisBalances::transfer(RuntimeOrigin::signed(2), 1, 250_000)); + // ...and it is. + assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + + assert_eq!(Balances::free_balance(1), 150); + assert_eq!(Balances::reserved_balance(1), 0); + }); +} + +#[test] +fn thaw_with_ignored_issuance_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + // Give account zero some balance. + Balances::make_free_balance_be(&0, 200); + + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 100, 1)); + enlarge(100, 1); + + // Account zero transfers 50 into everyone else's accounts. + assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 2, 50)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 3, 50)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 4, 50)); + + run_to_block(4); + // Unfunded initially... + assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 0, None), Error::::Unfunded); + // ...so we fund... + assert_ok!(Nis::fund_deficit(RuntimeOrigin::signed(1))); + // ...and then it's ok. + assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + + // Account zero changes have been ignored. + assert_eq!(Balances::free_balance(1), 150); + assert_eq!(Balances::reserved_balance(1), 0); + }); +} + +#[test] +fn thaw_when_issuance_lower_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 100, 1)); + enlarge(100, 1); + + // Everybody else's balances goes down by 25% + Balances::make_free_balance_be(&2, 75); + Balances::make_free_balance_be(&3, 75); + Balances::make_free_balance_be(&4, 75); + + run_to_block(4); + assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + + assert_eq!(Balances::free_balance(1), 75); + assert_eq!(Balances::reserved_balance(1), 0); + }); +} + +#[test] +fn multiple_thaws_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 60, 1)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(2), 50, 1)); + enlarge(200, 3); + + // Double everyone's free balances. + Balances::make_free_balance_be(&2, 100); + Balances::make_free_balance_be(&3, 200); + Balances::make_free_balance_be(&4, 200); + assert_ok!(Nis::fund_deficit(RuntimeOrigin::signed(1))); + + run_to_block(4); + assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 1, None)); + assert_noop!(Nis::thaw(RuntimeOrigin::signed(2), 2, None), Error::::Throttled); + run_to_block(5); + assert_ok!(Nis::thaw(RuntimeOrigin::signed(2), 2, None)); + + assert_eq!(Balances::free_balance(1), 200); + assert_eq!(Balances::free_balance(2), 200); + }); +} + +#[test] +fn multiple_thaws_works_in_alternative_thaw_order() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 60, 1)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(2), 50, 1)); + enlarge(200, 3); + + // Double everyone's free balances. + Balances::make_free_balance_be(&2, 100); + Balances::make_free_balance_be(&3, 200); + Balances::make_free_balance_be(&4, 200); + assert_ok!(Nis::fund_deficit(RuntimeOrigin::signed(1))); + + run_to_block(4); + assert_ok!(Nis::thaw(RuntimeOrigin::signed(2), 2, None)); + assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 1, None), Error::::Throttled); + assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + + run_to_block(5); + assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 1, None)); + + assert_eq!(Balances::free_balance(1), 200); + assert_eq!(Balances::free_balance(2), 200); + }); +} + +#[test] +fn enlargement_to_target_works() { + new_test_ext().execute_with(|| { + run_to_block(2); + let w = <() as WeightInfo>::process_queues() + + <() as WeightInfo>::process_queue() + + (<() as WeightInfo>::process_bid() * 2); + super::mock::MaxIntakeWeight::set(w); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 40, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(2), 40, 2)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(2), 40, 3)); + assert_ok!(Nis::place_bid(RuntimeOrigin::signed(3), 40, 3)); + Target::set(Perquintill::from_percent(40)); + + run_to_block(3); + assert_eq!(Queues::::get(1), vec![Bid { amount: 40, who: 1 },]); + assert_eq!( + Queues::::get(2), + vec![Bid { amount: 40, who: 2 }, Bid { amount: 40, who: 1 },] + ); + assert_eq!( + Queues::::get(3), + vec![Bid { amount: 40, who: 3 }, Bid { amount: 40, who: 2 },] + ); + assert_eq!(QueueTotals::::get(), vec![(1, 40), (2, 80), (2, 80)]); + + run_to_block(4); + // Two new items should have been issued to 2 & 3 for 40 each & duration of 3. + assert_eq!( + Receipts::::get(0).unwrap(), + ReceiptRecord { proportion: Perquintill::from_percent(10), who: 2, expiry: 13 } + ); + assert_eq!( + Receipts::::get(1).unwrap(), + ReceiptRecord { proportion: Perquintill::from_percent(10), who: 3, expiry: 13 } + ); + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::from_percent(20), + index: 2, + last_period: 0, + thawed: Perquintill::zero(), + } + ); + + run_to_block(5); + // No change + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::from_percent(20), + index: 2, + last_period: 0, + thawed: Perquintill::zero() + } + ); + + run_to_block(6); + // Two new items should have been issued to 1 & 2 for 40 each & duration of 2. + assert_eq!( + Receipts::::get(2).unwrap(), + ReceiptRecord { proportion: Perquintill::from_percent(10), who: 1, expiry: 12 } + ); + assert_eq!( + Receipts::::get(3).unwrap(), + ReceiptRecord { proportion: Perquintill::from_percent(10), who: 2, expiry: 12 } + ); + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::from_percent(40), + index: 4, + last_period: 0, + thawed: Perquintill::zero() + } + ); + + run_to_block(8); + // No change now. + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::from_percent(40), + index: 4, + last_period: 0, + thawed: Perquintill::zero() + } + ); + + // Set target a bit higher to use up the remaining bid. + Target::set(Perquintill::from_percent(60)); + run_to_block(10); + + // Two new items should have been issued to 1 & 2 for 40 each & duration of 2. + assert_eq!( + Receipts::::get(4).unwrap(), + ReceiptRecord { proportion: Perquintill::from_percent(10), who: 1, expiry: 13 } + ); + + assert_eq!( + Summary::::get(), + SummaryRecord { + proportion_owed: Perquintill::from_percent(50), + index: 5, + last_period: 0, + thawed: Perquintill::zero() + } + ); + }); +} diff --git a/frame/gilt/src/weights.rs b/frame/nis/src/weights.rs similarity index 51% rename from frame/gilt/src/weights.rs rename to frame/nis/src/weights.rs index 82b199b1a6663..71577075ada91 100644 --- a/frame/gilt/src/weights.rs +++ b/frame/nis/src/weights.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_gilt +//! Autogenerated weights for pallet_nis //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev //! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` @@ -29,14 +29,12 @@ // --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_gilt +// --pallet=pallet_nis // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/gilt/src/weights.rs -// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs +// --output=./frame/nis/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -45,24 +43,23 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; -/// Weight functions needed for pallet_gilt. +/// Weight functions needed for pallet_nis. pub trait WeightInfo { fn place_bid(l: u32, ) -> Weight; fn place_bid_max() -> Weight; fn retract_bid(l: u32, ) -> Weight; - fn set_target() -> Weight; fn thaw() -> Weight; - fn pursue_target_noop() -> Weight; - fn pursue_target_per_item(b: u32, ) -> Weight; - fn pursue_target_per_queue(q: u32, ) -> Weight; + fn fund_deficit() -> Weight; + fn process_queues() -> Weight; + fn process_queue() -> Weight; + fn process_bid() -> Weight; } -/// Weights for pallet_gilt using the Substrate node and recommended hardware. +/// Weights for pallet_nis using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt QueueTotals (r:1 w:1) - /// The range of component `l` is `[0, 999]`. + // Storage: Nis Queues (r:1 w:1) + // Storage: Nis QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { // Minimum execution time: 42_332 nanoseconds. Weight::from_ref_time(45_584_514 as u64) @@ -71,17 +68,16 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } - // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt QueueTotals (r:1 w:1) + // Storage: Nis Queues (r:1 w:1) + // Storage: Nis QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { // Minimum execution time: 85_866 nanoseconds. Weight::from_ref_time(87_171_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } - // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt QueueTotals (r:1 w:1) - /// The range of component `l` is `[1, 1000]`. + // Storage: Nis Queues (r:1 w:1) + // Storage: Nis QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { // Minimum execution time: 44_605 nanoseconds. Weight::from_ref_time(46_850_108 as u64) @@ -90,63 +86,52 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } - // Storage: Gilt ActiveTotal (r:1 w:1) - fn set_target() -> Weight { - // Minimum execution time: 7_331 nanoseconds. - Weight::from_ref_time(7_619_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: Gilt Active (r:1 w:1) - // Storage: Gilt ActiveTotal (r:1 w:1) + // Storage: Nis Active (r:1 w:1) + // Storage: Nis ActiveTotal (r:1 w:1) fn thaw() -> Weight { // Minimum execution time: 55_143 nanoseconds. Weight::from_ref_time(55_845_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } - // Storage: Gilt ActiveTotal (r:1 w:0) - fn pursue_target_noop() -> Weight { - // Minimum execution time: 3_386 nanoseconds. - Weight::from_ref_time(3_461_000 as u64) + // Storage: Nis Active (r:1 w:1) + // Storage: Nis ActiveTotal (r:1 w:1) + fn fund_deficit() -> Weight { + Weight::from_ref_time(47_753_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + } + // Storage: Nis ActiveTotal (r:1 w:0) + fn process_queues() -> Weight { + Weight::from_ref_time(1_663_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } - // Storage: Gilt ActiveTotal (r:1 w:1) - // Storage: Gilt QueueTotals (r:1 w:1) - // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt Active (r:0 w:20) - /// The range of component `b` is `[0, 1000]`. - fn pursue_target_per_item(b: u32, ) -> Weight { - // Minimum execution time: 34_156 nanoseconds. - Weight::from_ref_time(45_262_859 as u64) - // Standard Error: 1_529 - .saturating_add(Weight::from_ref_time(4_181_654 as u64).saturating_mul(b as u64)) + // Storage: Nis ActiveTotal (r:1 w:1) + // Storage: Nis QueueTotals (r:1 w:1) + // Storage: Nis Queues (r:1 w:1) + // Storage: Nis Active (r:0 w:1) + fn process_queue() -> Weight { + Weight::from_ref_time(40_797_000 as u64) + // Standard Error: 1_000 .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(b as u64))) - } - // Storage: Gilt ActiveTotal (r:1 w:1) - // Storage: Gilt QueueTotals (r:1 w:1) - // Storage: Gilt Queues (r:6 w:6) - // Storage: Gilt Active (r:0 w:6) - /// The range of component `q` is `[0, 300]`. - fn pursue_target_per_queue(q: u32, ) -> Weight { - // Minimum execution time: 33_526 nanoseconds. - Weight::from_ref_time(37_255_562 as u64) - // Standard Error: 3_611 - .saturating_add(Weight::from_ref_time(7_193_128 as u64).saturating_mul(q as u64)) + } + // Storage: Nis ActiveTotal (r:1 w:1) + // Storage: Nis QueueTotals (r:1 w:1) + // Storage: Nis Queues (r:1 w:1) + // Storage: Nis Active (r:0 w:1) + fn process_bid() -> Weight { + Weight::from_ref_time(14_944_000 as u64) + // Standard Error: 6_000 .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(q as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(q as u64))) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt QueueTotals (r:1 w:1) - /// The range of component `l` is `[0, 999]`. + // Storage: Nis Queues (r:1 w:1) + // Storage: Nis QueueTotals (r:1 w:1) fn place_bid(l: u32, ) -> Weight { // Minimum execution time: 42_332 nanoseconds. Weight::from_ref_time(45_584_514 as u64) @@ -155,17 +140,16 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } - // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt QueueTotals (r:1 w:1) + // Storage: Nis Queues (r:1 w:1) + // Storage: Nis QueueTotals (r:1 w:1) fn place_bid_max() -> Weight { // Minimum execution time: 85_866 nanoseconds. Weight::from_ref_time(87_171_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } - // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt QueueTotals (r:1 w:1) - /// The range of component `l` is `[1, 1000]`. + // Storage: Nis Queues (r:1 w:1) + // Storage: Nis QueueTotals (r:1 w:1) fn retract_bid(l: u32, ) -> Weight { // Minimum execution time: 44_605 nanoseconds. Weight::from_ref_time(46_850_108 as u64) @@ -174,54 +158,44 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } - // Storage: Gilt ActiveTotal (r:1 w:1) - fn set_target() -> Weight { - // Minimum execution time: 7_331 nanoseconds. - Weight::from_ref_time(7_619_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: Gilt Active (r:1 w:1) - // Storage: Gilt ActiveTotal (r:1 w:1) + // Storage: Nis Active (r:1 w:1) + // Storage: Nis ActiveTotal (r:1 w:1) fn thaw() -> Weight { // Minimum execution time: 55_143 nanoseconds. Weight::from_ref_time(55_845_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } - // Storage: Gilt ActiveTotal (r:1 w:0) - fn pursue_target_noop() -> Weight { - // Minimum execution time: 3_386 nanoseconds. - Weight::from_ref_time(3_461_000 as u64) + // Storage: Nis Active (r:1 w:1) + // Storage: Nis ActiveTotal (r:1 w:1) + fn fund_deficit() -> Weight { + Weight::from_ref_time(47_753_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + } + // Storage: Nis ActiveTotal (r:1 w:0) + fn process_queues() -> Weight { + Weight::from_ref_time(1_663_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } - // Storage: Gilt ActiveTotal (r:1 w:1) - // Storage: Gilt QueueTotals (r:1 w:1) - // Storage: Gilt Queues (r:1 w:1) - // Storage: Gilt Active (r:0 w:20) - /// The range of component `b` is `[0, 1000]`. - fn pursue_target_per_item(b: u32, ) -> Weight { - // Minimum execution time: 34_156 nanoseconds. - Weight::from_ref_time(45_262_859 as u64) - // Standard Error: 1_529 - .saturating_add(Weight::from_ref_time(4_181_654 as u64).saturating_mul(b as u64)) + // Storage: Nis ActiveTotal (r:1 w:1) + // Storage: Nis QueueTotals (r:1 w:1) + // Storage: Nis Queues (r:1 w:1) + // Storage: Nis Active (r:0 w:1) + fn process_queue() -> Weight { + Weight::from_ref_time(40_797_000 as u64) + // Standard Error: 1_000 .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(b as u64))) - } - // Storage: Gilt ActiveTotal (r:1 w:1) - // Storage: Gilt QueueTotals (r:1 w:1) - // Storage: Gilt Queues (r:6 w:6) - // Storage: Gilt Active (r:0 w:6) - /// The range of component `q` is `[0, 300]`. - fn pursue_target_per_queue(q: u32, ) -> Weight { - // Minimum execution time: 33_526 nanoseconds. - Weight::from_ref_time(37_255_562 as u64) - // Standard Error: 3_611 - .saturating_add(Weight::from_ref_time(7_193_128 as u64).saturating_mul(q as u64)) + } + // Storage: Nis ActiveTotal (r:1 w:1) + // Storage: Nis QueueTotals (r:1 w:1) + // Storage: Nis Queues (r:1 w:1) + // Storage: Nis Active (r:0 w:1) + fn process_bid() -> Weight { + Weight::from_ref_time(14_944_000 as u64) + // Standard Error: 6_000 .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(q as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(q as u64))) } } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 9b5300dfc5739..1b1d5d68cb52c 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -27,7 +27,7 @@ pub use tokens::{ }, fungible, fungibles, imbalance::{Imbalance, OnUnbalanced, SignedImbalance}, - BalanceStatus, ExistenceRequirement, Locker, WithdrawReasons, + nonfungible, nonfungibles, BalanceStatus, ExistenceRequirement, Locker, WithdrawReasons, }; mod members; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index ce8faaaf37c3d..33e48faa7ef29 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -21,7 +21,7 @@ use crate::dispatch::Parameter; use codec::{CompactLen, Decode, DecodeLimit, Encode, EncodeLike, Input, MaxEncodedLen}; use impl_trait_for_tuples::impl_for_tuples; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; -use sp_arithmetic::traits::{CheckedAdd, CheckedMul, CheckedSub, Saturating}; +use sp_arithmetic::traits::{CheckedAdd, CheckedMul, CheckedSub, One, Saturating}; use sp_core::bounded::bounded_vec::TruncateFrom; #[doc(hidden)] pub use sp_runtime::traits::{ @@ -348,17 +348,25 @@ impl DefensiveOption for Option { /// A variant of [`Defensive`] with the same rationale, for the arithmetic operations where in /// case an infallible operation fails, it saturates. pub trait DefensiveSaturating { - /// Add `self` and `other` defensively. + /// Return `self` plus `other` defensively. fn defensive_saturating_add(self, other: Self) -> Self; - /// Subtract `other` from `self` defensively. + /// Return `self` minus `other` defensively. fn defensive_saturating_sub(self, other: Self) -> Self; - /// Multiply `self` and `other` defensively. + /// Return the product of `self` and `other` defensively. fn defensive_saturating_mul(self, other: Self) -> Self; + /// Increase `self` by `other` defensively. + fn defensive_saturating_accrue(&mut self, other: Self); + /// Reduce `self` by `other` defensively. + fn defensive_saturating_reduce(&mut self, other: Self); + /// Increment `self` by one defensively. + fn defensive_saturating_inc(&mut self); + /// Decrement `self` by one defensively. + fn defensive_saturating_dec(&mut self); } // NOTE: A bit unfortunate, since T has to be bound by all the traits needed. Could make it // `DefensiveSaturating` to mitigate. -impl DefensiveSaturating for T { +impl DefensiveSaturating for T { fn defensive_saturating_add(self, other: Self) -> Self { self.checked_add(&other).defensive_unwrap_or_else(|| self.saturating_add(other)) } @@ -368,6 +376,20 @@ impl DefensiveSaturating f fn defensive_saturating_mul(self, other: Self) -> Self { self.checked_mul(&other).defensive_unwrap_or_else(|| self.saturating_mul(other)) } + fn defensive_saturating_accrue(&mut self, other: Self) { + // Use `replace` here since `take` would require `T: Default`. + *self = sp_std::mem::replace(self, One::one()).defensive_saturating_add(other); + } + fn defensive_saturating_reduce(&mut self, other: Self) { + // Use `replace` here since `take` would require `T: Default`. + *self = sp_std::mem::replace(self, One::one()).defensive_saturating_sub(other); + } + fn defensive_saturating_inc(&mut self) { + self.defensive_saturating_accrue(One::one()); + } + fn defensive_saturating_dec(&mut self) { + self.defensive_saturating_reduce(One::one()); + } } /// Construct an object by defensively truncating an input if the `TryFrom` conversion fails. @@ -1119,6 +1141,92 @@ mod test { use sp_core::bounded::{BoundedSlice, BoundedVec}; use sp_std::marker::PhantomData; + #[test] + #[cfg(not(debug_assertions))] + fn defensive_saturating_accrue_works() { + let mut v = 1_u32; + v.defensive_saturating_accrue(2); + assert_eq!(v, 3); + v.defensive_saturating_accrue(u32::MAX); + assert_eq!(v, u32::MAX); + v.defensive_saturating_accrue(1); + assert_eq!(v, u32::MAX); + } + + #[test] + #[cfg(debug_assertions)] + #[should_panic(expected = "Defensive")] + fn defensive_saturating_accrue_panics() { + let mut v = u32::MAX; + v.defensive_saturating_accrue(1); // defensive failure + } + + #[test] + #[cfg(not(debug_assertions))] + fn defensive_saturating_reduce_works() { + let mut v = u32::MAX; + v.defensive_saturating_reduce(3); + assert_eq!(v, u32::MAX - 3); + v.defensive_saturating_reduce(u32::MAX); + assert_eq!(v, 0); + v.defensive_saturating_reduce(1); + assert_eq!(v, 0); + } + + #[test] + #[cfg(debug_assertions)] + #[should_panic(expected = "Defensive")] + fn defensive_saturating_reduce_panics() { + let mut v = 0_u32; + v.defensive_saturating_reduce(1); // defensive failure + } + + #[test] + #[cfg(not(debug_assertions))] + fn defensive_saturating_inc_works() { + let mut v = 0_u32; + for i in 1..10 { + v.defensive_saturating_inc(); + assert_eq!(v, i); + } + v += u32::MAX - 10; + v.defensive_saturating_inc(); + assert_eq!(v, u32::MAX); + v.defensive_saturating_inc(); + assert_eq!(v, u32::MAX); + } + + #[test] + #[cfg(debug_assertions)] + #[should_panic(expected = "Defensive")] + fn defensive_saturating_inc_panics() { + let mut v = u32::MAX; + v.defensive_saturating_inc(); // defensive failure + } + + #[test] + #[cfg(not(debug_assertions))] + fn defensive_saturating_dec_works() { + let mut v = u32::MAX; + for i in 1..10 { + v.defensive_saturating_dec(); + assert_eq!(v, u32::MAX - i); + } + v -= u32::MAX - 10; + v.defensive_saturating_dec(); + assert_eq!(v, 0); + v.defensive_saturating_dec(); + assert_eq!(v, 0); + } + + #[test] + #[cfg(debug_assertions)] + #[should_panic(expected = "Defensive")] + fn defensive_saturating_dec_panics() { + let mut v = 0_u32; + v.defensive_saturating_dec(); // defensive failure + } + #[test] #[cfg(not(debug_assertions))] fn defensive_truncating_from_vec_defensive_works() { diff --git a/frame/support/src/traits/tokens/currency/reservable.rs b/frame/support/src/traits/tokens/currency/reservable.rs index 35455aaecdb49..53f6764c3a1ac 100644 --- a/frame/support/src/traits/tokens/currency/reservable.rs +++ b/frame/support/src/traits/tokens/currency/reservable.rs @@ -17,8 +17,14 @@ //! The reservable currency trait. +use scale_info::TypeInfo; +use sp_core::Get; + use super::{super::misc::BalanceStatus, Currency}; -use crate::dispatch::{DispatchError, DispatchResult}; +use crate::{ + dispatch::{DispatchError, DispatchResult}, + traits::{ExistenceRequirement, SignedImbalance, WithdrawReasons}, +}; /// A currency where funds can be reserved from the user. pub trait ReservableCurrency: Currency { @@ -111,7 +117,7 @@ impl ReservableCurrency for () { pub trait NamedReservableCurrency: ReservableCurrency { /// An identifier for a reserve. Used for disambiguating different reserves so that /// they can be individually replaced or removed. - type ReserveIdentifier; + type ReserveIdentifier: codec::Encode + TypeInfo + 'static; /// Deducts up to `value` from reserved balance of `who`. This function cannot fail. /// @@ -236,3 +242,144 @@ pub trait NamedReservableCurrency: ReservableCurrency { Self::repatriate_reserved_named(id, slashed, beneficiary, value, status).map(|_| ()) } } + +/// Adapter to allow a `NamedReservableCurrency` to be passed as regular `ReservableCurrency` +/// together with an `Id`. +/// +/// All "anonymous" operations are then implemented as their named counterparts with the given `Id`. +pub struct WithName( + sp_std::marker::PhantomData<(NamedReservable, Id, AccountId)>, +); +impl< + NamedReservable: NamedReservableCurrency, + Id: Get, + AccountId, + > Currency for WithName +{ + type Balance = >::Balance; + type PositiveImbalance = >::PositiveImbalance; + type NegativeImbalance = >::NegativeImbalance; + + fn total_balance(who: &AccountId) -> Self::Balance { + NamedReservable::total_balance(who) + } + fn can_slash(who: &AccountId, value: Self::Balance) -> bool { + NamedReservable::can_slash(who, value) + } + fn total_issuance() -> Self::Balance { + NamedReservable::total_issuance() + } + fn minimum_balance() -> Self::Balance { + NamedReservable::minimum_balance() + } + fn burn(amount: Self::Balance) -> Self::PositiveImbalance { + NamedReservable::burn(amount) + } + fn issue(amount: Self::Balance) -> Self::NegativeImbalance { + NamedReservable::issue(amount) + } + fn pair(amount: Self::Balance) -> (Self::PositiveImbalance, Self::NegativeImbalance) { + NamedReservable::pair(amount) + } + fn free_balance(who: &AccountId) -> Self::Balance { + NamedReservable::free_balance(who) + } + fn ensure_can_withdraw( + who: &AccountId, + amount: Self::Balance, + reasons: WithdrawReasons, + new_balance: Self::Balance, + ) -> DispatchResult { + NamedReservable::ensure_can_withdraw(who, amount, reasons, new_balance) + } + + fn transfer( + source: &AccountId, + dest: &AccountId, + value: Self::Balance, + existence_requirement: ExistenceRequirement, + ) -> DispatchResult { + NamedReservable::transfer(source, dest, value, existence_requirement) + } + fn slash(who: &AccountId, value: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { + NamedReservable::slash(who, value) + } + fn deposit_into_existing( + who: &AccountId, + value: Self::Balance, + ) -> Result { + NamedReservable::deposit_into_existing(who, value) + } + fn resolve_into_existing( + who: &AccountId, + value: Self::NegativeImbalance, + ) -> Result<(), Self::NegativeImbalance> { + NamedReservable::resolve_into_existing(who, value) + } + fn deposit_creating(who: &AccountId, value: Self::Balance) -> Self::PositiveImbalance { + NamedReservable::deposit_creating(who, value) + } + fn resolve_creating(who: &AccountId, value: Self::NegativeImbalance) { + NamedReservable::resolve_creating(who, value) + } + fn withdraw( + who: &AccountId, + value: Self::Balance, + reasons: WithdrawReasons, + liveness: ExistenceRequirement, + ) -> Result { + NamedReservable::withdraw(who, value, reasons, liveness) + } + fn settle( + who: &AccountId, + value: Self::PositiveImbalance, + reasons: WithdrawReasons, + liveness: ExistenceRequirement, + ) -> Result<(), Self::PositiveImbalance> { + NamedReservable::settle(who, value, reasons, liveness) + } + fn make_free_balance_be( + who: &AccountId, + balance: Self::Balance, + ) -> SignedImbalance { + NamedReservable::make_free_balance_be(who, balance) + } +} +impl< + NamedReservable: NamedReservableCurrency, + Id: Get, + AccountId, + > ReservableCurrency for WithName +{ + fn can_reserve(who: &AccountId, value: Self::Balance) -> bool { + NamedReservable::can_reserve(who, value) + } + + fn slash_reserved( + who: &AccountId, + value: Self::Balance, + ) -> (Self::NegativeImbalance, Self::Balance) { + NamedReservable::slash_reserved_named(&Id::get(), who, value) + } + + fn reserved_balance(who: &AccountId) -> Self::Balance { + NamedReservable::reserved_balance_named(&Id::get(), who) + } + + fn reserve(who: &AccountId, value: Self::Balance) -> DispatchResult { + NamedReservable::reserve_named(&Id::get(), who, value) + } + + fn unreserve(who: &AccountId, value: Self::Balance) -> Self::Balance { + NamedReservable::unreserve_named(&Id::get(), who, value) + } + + fn repatriate_reserved( + slashed: &AccountId, + beneficiary: &AccountId, + value: Self::Balance, + status: BalanceStatus, + ) -> Result { + NamedReservable::repatriate_reserved_named(&Id::get(), slashed, beneficiary, value, status) + } +} diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs index 7b1ec0f434382..05e109b870ec0 100644 --- a/frame/support/src/traits/tokens/fungible.rs +++ b/frame/support/src/traits/tokens/fungible.rs @@ -83,7 +83,7 @@ pub trait Mutate: Inspect { /// is returned and nothing is changed. If successful, the amount of tokens reduced is returned. /// /// The default implementation just uses `withdraw` along with `reducible_balance` to ensure - /// that is doesn't fail. + /// that it doesn't fail. fn slash(who: &AccountId, amount: Self::Balance) -> Result { Self::burn_from(who, Self::reducible_balance(who, false).min(amount)) } diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index 244242c0f7580..d7b326164b7d3 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -42,8 +42,8 @@ pub mod traits; pub use fixed_point::{FixedI128, FixedI64, FixedPointNumber, FixedPointOperand, FixedU128}; pub use per_things::{ - InnerOf, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, Rounding, SignedRounding, - UpperOf, + InnerOf, MultiplyArg, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, RationalArg, + ReciprocalArg, Rounding, SignedRounding, UpperOf, }; pub use rational::{Rational128, RationalInfinite}; diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index 2932a742063db..fc3767761175c 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -36,6 +36,57 @@ pub type InnerOf

=

::Inner; /// Get the upper type of a `PerThing`. pub type UpperOf

=

::Upper; +pub trait RationalArg: + Clone + + Ord + + ops::Div + + ops::Rem + + ops::Add + + ops::AddAssign + + Unsigned + + Zero + + One +{ +} + +impl< + T: Clone + + Ord + + ops::Div + + ops::Rem + + ops::Add + + ops::AddAssign + + Unsigned + + Zero + + One, + > RationalArg for T +{ +} + +pub trait MultiplyArg: + Clone + + ops::Rem + + ops::Div + + ops::Mul + + ops::Add + + Unsigned +{ +} + +impl< + T: Clone + + ops::Rem + + ops::Div + + ops::Mul + + ops::Add + + Unsigned, + > MultiplyArg for T +{ +} + +pub trait ReciprocalArg: MultiplyArg + Saturating {} +impl ReciprocalArg for T {} + /// Something that implements a fixed point ration with an arbitrary granularity `X`, as _parts per /// `X`_. pub trait PerThing: @@ -160,13 +211,7 @@ pub trait PerThing: /// ``` fn mul_floor(self, b: N) -> N where - N: Clone - + UniqueSaturatedInto - + ops::Rem - + ops::Div - + ops::Mul - + ops::Add - + Unsigned, + N: MultiplyArg + UniqueSaturatedInto, Self::Inner: Into, { overflow_prune_mul::(b, self.deconstruct(), Rounding::Down) @@ -189,13 +234,7 @@ pub trait PerThing: /// ``` fn mul_ceil(self, b: N) -> N where - N: Clone - + UniqueSaturatedInto - + ops::Rem - + ops::Div - + ops::Mul - + ops::Add - + Unsigned, + N: MultiplyArg + UniqueSaturatedInto, Self::Inner: Into, { overflow_prune_mul::(b, self.deconstruct(), Rounding::Up) @@ -212,14 +251,7 @@ pub trait PerThing: /// ``` fn saturating_reciprocal_mul(self, b: N) -> N where - N: Clone - + UniqueSaturatedInto - + ops::Rem - + ops::Div - + ops::Mul - + ops::Add - + Saturating - + Unsigned, + N: ReciprocalArg + UniqueSaturatedInto, Self::Inner: Into, { saturating_reciprocal_mul::(b, self.deconstruct(), Rounding::NearestPrefUp) @@ -239,14 +271,7 @@ pub trait PerThing: /// ``` fn saturating_reciprocal_mul_floor(self, b: N) -> N where - N: Clone - + UniqueSaturatedInto - + ops::Rem - + ops::Div - + ops::Mul - + ops::Add - + Saturating - + Unsigned, + N: ReciprocalArg + UniqueSaturatedInto, Self::Inner: Into, { saturating_reciprocal_mul::(b, self.deconstruct(), Rounding::Down) @@ -266,14 +291,7 @@ pub trait PerThing: /// ``` fn saturating_reciprocal_mul_ceil(self, b: N) -> N where - N: Clone - + UniqueSaturatedInto - + ops::Rem - + ops::Div - + ops::Mul - + ops::Add - + Saturating - + Unsigned, + N: ReciprocalArg + UniqueSaturatedInto, Self::Inner: Into, { saturating_reciprocal_mul::(b, self.deconstruct(), Rounding::Up) @@ -316,17 +334,7 @@ pub trait PerThing: /// ``` fn from_rational(p: N, q: N) -> Self where - N: Clone - + Ord - + TryInto - + TryInto - + ops::Div - + ops::Rem - + ops::Add - + ops::AddAssign - + Unsigned - + Zero - + One, + N: RationalArg + TryInto + TryInto, Self::Inner: Into, { Self::from_rational_with_rounding(p, q, Rounding::Down).unwrap_or_else(|_| Self::one()) @@ -388,34 +396,14 @@ pub trait PerThing: /// ``` fn from_rational_with_rounding(p: N, q: N, rounding: Rounding) -> Result where - N: Clone - + Ord - + TryInto - + TryInto - + ops::Div - + ops::Rem - + ops::Add - + ops::AddAssign - + Unsigned - + Zero - + One, + N: RationalArg + TryInto + TryInto, Self::Inner: Into; /// Same as `Self::from_rational`. #[deprecated = "Use from_rational instead"] fn from_rational_approximation(p: N, q: N) -> Self where - N: Clone - + Ord - + TryInto - + TryInto - + ops::Div - + ops::Rem - + ops::Add - + ops::AddAssign - + Unsigned - + Zero - + One, + N: RationalArg + TryInto + TryInto, Self::Inner: Into, { Self::from_rational(p, q) @@ -495,13 +483,7 @@ where /// Overflow-prune multiplication. Accurately multiply a value by `self` without overflowing. fn overflow_prune_mul(x: N, part: P::Inner, rounding: Rounding) -> N where - N: Clone - + UniqueSaturatedInto - + ops::Div - + ops::Mul - + ops::Add - + ops::Rem - + Unsigned, + N: MultiplyArg + UniqueSaturatedInto, P: PerThing, P::Inner: Into, { @@ -517,12 +499,7 @@ where /// to `x / denom * numer` for an accurate result. fn rational_mul_correction(x: N, numer: P::Inner, denom: P::Inner, rounding: Rounding) -> N where - N: UniqueSaturatedInto - + ops::Div - + ops::Mul - + ops::Add - + ops::Rem - + Unsigned, + N: MultiplyArg + UniqueSaturatedInto, P: PerThing, P::Inner: Into, { @@ -803,17 +780,7 @@ macro_rules! implement_per_thing { #[deprecated = "Use `PerThing::from_rational` instead"] pub fn from_rational_approximation(p: N, q: N) -> Self where - N: Clone - + Ord - + TryInto<$type> - + TryInto<$upper_type> - + ops::Div - + ops::Rem - + ops::Add - + ops::AddAssign - + Unsigned - + Zero - + One, + N: RationalArg+ TryInto<$type> + TryInto<$upper_type>, $type: Into { ::from_rational(p, q) @@ -822,17 +789,7 @@ macro_rules! implement_per_thing { /// See [`PerThing::from_rational`]. pub fn from_rational(p: N, q: N) -> Self where - N: Clone - + Ord - + TryInto<$type> - + TryInto<$upper_type> - + ops::Div - + ops::Rem - + ops::Add - + ops::AddAssign - + Unsigned - + Zero - + One, + N: RationalArg+ TryInto<$type> + TryInto<$upper_type>, $type: Into { ::from_rational(p, q) @@ -851,9 +808,7 @@ macro_rules! implement_per_thing { /// See [`PerThing::mul_floor`]. pub fn mul_floor(self, b: N) -> N where - N: Clone + UniqueSaturatedInto<$type> + - ops::Rem + ops::Div + ops::Mul + - ops::Add + Unsigned, + N: MultiplyArg + UniqueSaturatedInto<$type>, $type: Into, { @@ -863,9 +818,7 @@ macro_rules! implement_per_thing { /// See [`PerThing::mul_ceil`]. pub fn mul_ceil(self, b: N) -> N where - N: Clone + UniqueSaturatedInto<$type> + - ops::Rem + ops::Div + ops::Mul + - ops::Add + Unsigned, + N: MultiplyArg + UniqueSaturatedInto<$type>, $type: Into, { PerThing::mul_ceil(self, b) @@ -874,9 +827,7 @@ macro_rules! implement_per_thing { /// See [`PerThing::saturating_reciprocal_mul`]. pub fn saturating_reciprocal_mul(self, b: N) -> N where - N: Clone + UniqueSaturatedInto<$type> + ops::Rem + - ops::Div + ops::Mul + ops::Add + - Saturating + Unsigned, + N: ReciprocalArg + UniqueSaturatedInto<$type>, $type: Into, { PerThing::saturating_reciprocal_mul(self, b) @@ -885,9 +836,7 @@ macro_rules! implement_per_thing { /// See [`PerThing::saturating_reciprocal_mul_floor`]. pub fn saturating_reciprocal_mul_floor(self, b: N) -> N where - N: Clone + UniqueSaturatedInto<$type> + ops::Rem + - ops::Div + ops::Mul + ops::Add + - Saturating + Unsigned, + N: ReciprocalArg + UniqueSaturatedInto<$type>, $type: Into, { PerThing::saturating_reciprocal_mul_floor(self, b) @@ -896,9 +845,7 @@ macro_rules! implement_per_thing { /// See [`PerThing::saturating_reciprocal_mul_ceil`]. pub fn saturating_reciprocal_mul_ceil(self, b: N) -> N where - N: Clone + UniqueSaturatedInto<$type> + ops::Rem + - ops::Div + ops::Mul + ops::Add + - Saturating + Unsigned, + N: ReciprocalArg + UniqueSaturatedInto<$type>, $type: Into, { PerThing::saturating_reciprocal_mul_ceil(self, b) @@ -1133,6 +1080,11 @@ macro_rules! implement_per_thing { } } + impl $crate::traits::One for $name { + fn one() -> Self { + Self::one() + } + } #[cfg(test)] mod $test_mod { diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 1c48b1933431d..276a62349a175 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -515,6 +515,11 @@ impl Convert for Identity { a } } +impl ConvertBack for Identity { + fn convert_back(a: T) -> T { + a + } +} /// A structure that performs standard conversion using the standard Rust conversion traits. pub struct ConvertInto; @@ -524,6 +529,12 @@ impl> Convert for ConvertInto { } } +/// Extensible conversion trait. Generic over both source and destination types. +pub trait ConvertBack: Convert { + /// Make conversion back. + fn convert_back(b: B) -> A; +} + /// Convenience type to work around the highly unergonomic syntax needed /// to invoke the functions of overloaded generic traits, in this case /// `TryFrom` and `TryInto`. From 2704ab3d348f18f9db03e87a725e4807b91660d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 5 Dec 2022 14:57:03 +0100 Subject: [PATCH 1433/1472] pallet-balances: Fix inactive funds migration (#12840) * pallet-balances: Fix inactive funds migration Fixes the inactive funds migration. It was missing to set the `storage_version` attribute for the `Pallet` struct. Besides that it also removes the old `StorageVersion` representation and adds support for instances of pallet-balances. * Fix test --- frame/balances/src/lib.rs | 29 +++--------- frame/balances/src/migration.rs | 79 ++++++++++++++++++--------------- frame/executive/src/lib.rs | 4 +- 3 files changed, 50 insertions(+), 62 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index c4a8456c22c67..381a0ffceeb85 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -246,8 +246,13 @@ pub mod pallet { type ReserveIdentifier: Parameter + Member + MaxEncodedLen + Ord + Copy; } + /// The current storage version. + const STORAGE_VERSION: frame_support::traits::StorageVersion = + frame_support::traits::StorageVersion::new(1); + #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData<(T, I)>); #[pallet::call] @@ -556,13 +561,6 @@ pub mod pallet { ValueQuery, >; - /// Storage version of the pallet. - /// - /// This is set to v2.0.0 for new networks. - #[pallet::storage] - pub(super) type StorageVersion, I: 'static = ()> = - StorageValue<_, Releases, ValueQuery>; - #[pallet::genesis_config] pub struct GenesisConfig, I: 'static = ()> { pub balances: Vec<(T::AccountId, T::Balance)>, @@ -581,8 +579,6 @@ pub mod pallet { let total = self.balances.iter().fold(Zero::zero(), |acc: T::Balance, &(_, n)| acc + n); >::put(total); - >::put(Releases::V2_0_0); - for (_, balance) in &self.balances { assert!( *balance >= >::ExistentialDeposit::get(), @@ -727,21 +723,6 @@ impl AccountData { } } -// A value placed in storage that represents the current version of the Balances storage. -// This value is used by the `on_runtime_upgrade` logic to determine whether we run -// storage migration logic. This should match directly with the semantic versions of the Rust crate. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] -enum Releases { - V1_0_0, - V2_0_0, -} - -impl Default for Releases { - fn default() -> Self { - Releases::V1_0_0 - } -} - pub struct DustCleaner, I: 'static = ()>( Option<(T::AccountId, NegativeImbalance)>, ); diff --git a/frame/balances/src/migration.rs b/frame/balances/src/migration.rs index 1dd3e6f51f1be..08e1d8c7a2c74 100644 --- a/frame/balances/src/migration.rs +++ b/frame/balances/src/migration.rs @@ -15,50 +15,57 @@ // along with Polkadot. If not, see . use super::*; -use frame_support::{pallet_prelude::*, traits::OnRuntimeUpgrade, weights::Weight}; +use frame_support::{ + pallet_prelude::*, + traits::{OnRuntimeUpgrade, PalletInfoAccess}, + weights::Weight, +}; -// NOTE: This must be used alongside the account whose balance is expected to be inactive. -// Generally this will be used for the XCM teleport checking account. -pub struct MigrateToTrackInactive(PhantomData<(T, A)>); -impl> OnRuntimeUpgrade for MigrateToTrackInactive { - fn on_runtime_upgrade() -> Weight { - let current_version = Pallet::::current_storage_version(); - let onchain_version = Pallet::::on_chain_storage_version(); +fn migrate_v0_to_v1, I: 'static>(accounts: &[T::AccountId]) -> Weight { + let onchain_version = Pallet::::on_chain_storage_version(); + + if onchain_version == 0 { + let total = accounts + .iter() + .map(|a| Pallet::::total_balance(a)) + .fold(T::Balance::zero(), |a, e| a.saturating_add(e)); + Pallet::::deactivate(total); + + // Remove the old `StorageVersion` type. + frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix( + Pallet::::name().as_bytes(), + "StorageVersion".as_bytes(), + )); - if onchain_version == 0 && current_version == 1 { - let b = Pallet::::total_balance(&A::get()); - Pallet::::deactivate(b); - current_version.put::>(); - log::info!(target: "runtime::balances", "Storage to version {:?}", current_version); - T::DbWeight::get().reads_writes(4, 3) - } else { - log::info!(target: "runtime::balances", "Migration did not execute. This probably should be removed"); - T::DbWeight::get().reads(2) - } + // Set storage version to `1`. + StorageVersion::new(1).put::>(); + + log::info!(target: "runtime::balances", "Storage to version 1"); + T::DbWeight::get().reads_writes(2 + accounts.len() as u64, 3) + } else { + log::info!(target: "runtime::balances", "Migration did not execute. This probably should be removed"); + T::DbWeight::get().reads(1) } } // NOTE: This must be used alongside the account whose balance is expected to be inactive. // Generally this will be used for the XCM teleport checking account. -pub struct MigrateManyToTrackInactive(PhantomData<(T, A)>); -impl>> OnRuntimeUpgrade for MigrateManyToTrackInactive { +pub struct MigrateToTrackInactive(PhantomData<(T, A, I)>); +impl, A: Get, I: 'static> OnRuntimeUpgrade + for MigrateToTrackInactive +{ fn on_runtime_upgrade() -> Weight { - let current_version = Pallet::::current_storage_version(); - let onchain_version = Pallet::::on_chain_storage_version(); + migrate_v0_to_v1::(&[A::get()]) + } +} - if onchain_version == 0 && current_version == 1 { - let accounts = A::get(); - let total = accounts - .iter() - .map(|a| Pallet::::total_balance(a)) - .fold(T::Balance::zero(), |a, e| a.saturating_add(e)); - Pallet::::deactivate(total); - current_version.put::>(); - log::info!(target: "runtime::balances", "Storage to version {:?}", current_version); - T::DbWeight::get().reads_writes(3 + accounts.len() as u64, 3) - } else { - log::info!(target: "runtime::balances", "Migration did not execute. This probably should be removed"); - T::DbWeight::get().reads(2) - } +// NOTE: This must be used alongside the accounts whose balance is expected to be inactive. +// Generally this will be used for the XCM teleport checking accounts. +pub struct MigrateManyToTrackInactive(PhantomData<(T, A, I)>); +impl, A: Get>, I: 'static> OnRuntimeUpgrade + for MigrateManyToTrackInactive +{ + fn on_runtime_upgrade() -> Weight { + migrate_v0_to_v1::(&A::get()) } } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 71f138b596b8d..5a4ef92b1c874 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -951,13 +951,13 @@ mod tests { block_import_works_inner( new_test_ext_v0(1), array_bytes::hex_n_into_unchecked( - "0d786e24c1f9e6ce237806a22c005bbbc7dee4edd6692b6c5442843d164392de", + "216e61b2689d1243eb56d89c9084db48e50ebebc4871d758db131432c675d7c0", ), ); block_import_works_inner( new_test_ext(1), array_bytes::hex_n_into_unchecked( - "348485a4ab856467b440167e45f99b491385e8528e09b0e51f85f814a3021c93", + "4738b4c0aab02d6ddfa62a2a6831ccc975a9f978f7db8d7ea8e68eba8639530a", ), ); } From 05ebde1044157bd90e90a1b493515341225f4d3f Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Mon, 5 Dec 2022 18:27:56 +0100 Subject: [PATCH 1434/1472] client/beefy: add some bounds on enqueued votes (#12562) Introduce bounds on the justifications and votes queues, so they do not grow forever if voter cannot make progress and consume from them. When bounds are hit, new votes or justifications get dropped. * use a BTreeMap and check for bounds * cargo fmt * use usize Co-authored-by: Adrian Catangiu --- client/beefy/src/worker.rs | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index c82ac65d18296..bba3563a8f70e 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -46,8 +46,8 @@ use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_runtime::{ generic::OpaqueDigestItemId, - traits::{Block, Header, NumberFor, Zero}, - SaturatedConversion, + traits::{Block, ConstU32, Header, NumberFor, Zero}, + BoundedVec, SaturatedConversion, }; use std::{ collections::{BTreeMap, BTreeSet, VecDeque}, @@ -55,6 +55,13 @@ use std::{ marker::PhantomData, sync::Arc, }; +/// Bound for the number of buffered future voting rounds. +const MAX_BUFFERED_VOTE_ROUNDS: usize = 600; +/// Bound for the number of buffered votes per round number. +const MAX_BUFFERED_VOTES_PER_ROUND: u32 = 1000; +/// Bound for the number of pending justifications - use 2400 - the max number +/// of justifications possible in a single session. +const MAX_BUFFERED_JUSTIFICATIONS: usize = 2400; pub(crate) enum RoundAction { Drop, @@ -306,7 +313,13 @@ pub(crate) struct BeefyWorker { /// BEEFY client metrics. metrics: Option, /// Buffer holding votes for future processing. - pending_votes: BTreeMap, Vec, AuthorityId, Signature>>>, + pending_votes: BTreeMap< + NumberFor, + BoundedVec< + VoteMessage, AuthorityId, Signature>, + ConstU32, + >, + >, /// Buffer holding justifications for future processing. pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, /// Persisted voter state. @@ -479,7 +492,14 @@ where )?, RoundAction::Enqueue => { debug!(target: "beefy", "🥩 Buffer vote for round: {:?}.", block_num); - self.pending_votes.entry(block_num).or_default().push(vote) + if self.pending_votes.len() < MAX_BUFFERED_VOTE_ROUNDS { + let votes_vec = self.pending_votes.entry(block_num).or_default(); + if votes_vec.try_push(vote).is_err() { + warn!(target: "beefy", "🥩 Buffer vote dropped for round: {:?}", block_num) + } + } else { + error!(target: "beefy", "🥩 Buffer justification dropped for round: {:?}.", block_num); + } }, RoundAction::Drop => (), }; @@ -505,7 +525,11 @@ where }, RoundAction::Enqueue => { debug!(target: "beefy", "🥩 Buffer justification for round: {:?}.", block_num); - self.pending_justifications.entry(block_num).or_insert(justification); + if self.pending_justifications.len() < MAX_BUFFERED_JUSTIFICATIONS { + self.pending_justifications.entry(block_num).or_insert(justification); + } else { + error!(target: "beefy", "🥩 Buffer justification dropped for round: {:?}.", block_num); + } }, RoundAction::Drop => (), }; From 404b8c947cebdec396117c45e11766ee33542f2c Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Mon, 5 Dec 2022 18:15:59 +0000 Subject: [PATCH 1435/1472] OpenGov: Abstentions (#12842) * OpenGov: Abstentions * Tests --- frame/conviction-voting/src/tests.rs | 51 ++++++++++++++++++++++++++++ frame/conviction-voting/src/types.rs | 18 ++++++++++ frame/conviction-voting/src/vote.rs | 6 ++++ 3 files changed, 75 insertions(+) diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index 7a3f80442014a..d20dcb66d6198 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -237,6 +237,14 @@ fn nay(amount: u64, conviction: u8) -> AccountVote { AccountVote::Standard { vote, balance: amount } } +fn split(aye: u64, nay: u64) -> AccountVote { + AccountVote::Split { aye, nay } +} + +fn split_abstain(aye: u64, nay: u64, abstain: u64) -> AccountVote { + AccountVote::SplitAbstain { aye, nay, abstain } +} + fn tally(index: u8) -> TallyOf { >>::as_ongoing(index).expect("No poll").0 } @@ -295,6 +303,49 @@ fn basic_voting_works() { }); } +#[test] +fn split_voting_works() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, split(10, 0))); + assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, split(5, 5))); + assert_eq!(tally(3), Tally::from_parts(0, 0, 5)); + assert_eq!(Balances::usable_balance(1), 0); + + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); + assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); + + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn abstain_voting_works() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, split_abstain(0, 0, 10))); + assert_eq!(tally(3), Tally::from_parts(0, 0, 10)); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 3, split_abstain(0, 0, 20))); + assert_eq!(tally(3), Tally::from_parts(0, 0, 30)); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 3, split_abstain(10, 0, 10))); + assert_eq!(tally(3), Tally::from_parts(1, 0, 30)); + assert_eq!(Balances::usable_balance(1), 0); + assert_eq!(Balances::usable_balance(2), 0); + + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); + assert_eq!(tally(3), Tally::from_parts(1, 0, 20)); + + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(2), None, 3)); + assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); + + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); + assert_eq!(Balances::usable_balance(1), 10); + + assert_ok!(Voting::unlock(RuntimeOrigin::signed(2), class(3), 2)); + assert_eq!(Balances::usable_balance(2), 20); + }); +} + #[test] fn voting_balance_gets_locked() { new_test_ext().execute_with(|| { diff --git a/frame/conviction-voting/src/types.rs b/frame/conviction-voting/src/types.rs index d6051dff62569..aa2406eef7110 100644 --- a/frame/conviction-voting/src/types.rs +++ b/frame/conviction-voting/src/types.rs @@ -147,6 +147,15 @@ impl< self.ayes = self.ayes.checked_add(&aye.votes)?; self.nays = self.nays.checked_add(&nay.votes)?; }, + AccountVote::SplitAbstain { aye, nay, abstain } => { + let aye = Conviction::None.votes(aye); + let nay = Conviction::None.votes(nay); + let abstain = Conviction::None.votes(abstain); + self.support = + self.support.checked_add(&aye.capital)?.checked_add(&abstain.capital)?; + self.ayes = self.ayes.checked_add(&aye.votes)?; + self.nays = self.nays.checked_add(&nay.votes)?; + }, } Some(()) } @@ -171,6 +180,15 @@ impl< self.ayes = self.ayes.checked_sub(&aye.votes)?; self.nays = self.nays.checked_sub(&nay.votes)?; }, + AccountVote::SplitAbstain { aye, nay, abstain } => { + let aye = Conviction::None.votes(aye); + let nay = Conviction::None.votes(nay); + let abstain = Conviction::None.votes(abstain); + self.support = + self.support.checked_sub(&aye.capital)?.checked_sub(&abstain.capital)?; + self.ayes = self.ayes.checked_sub(&aye.votes)?; + self.nays = self.nays.checked_sub(&nay.votes)?; + }, } Some(()) } diff --git a/frame/conviction-voting/src/vote.rs b/frame/conviction-voting/src/vote.rs index a8e012b6c97a1..1fed70536d246 100644 --- a/frame/conviction-voting/src/vote.rs +++ b/frame/conviction-voting/src/vote.rs @@ -74,6 +74,10 @@ pub enum AccountVote { /// A split vote with balances given for both ways, and with no conviction, useful for /// parachains when voting. Split { aye: Balance, nay: Balance }, + /// A split vote with balances given for both ways as well as abstentions, and with no + /// conviction, useful for parachains when voting, other off-chain aggregate accounts and + /// individuals who wish to abstain. + SplitAbstain { aye: Balance, nay: Balance, abstain: Balance }, } impl AccountVote { @@ -94,6 +98,8 @@ impl AccountVote { match self { AccountVote::Standard { balance, .. } => balance, AccountVote::Split { aye, nay } => aye.saturating_add(nay), + AccountVote::SplitAbstain { aye, nay, abstain } => + aye.saturating_add(nay).saturating_add(abstain), } } From b1396f708b2001593d5589dd1bd3f832821fb208 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Mon, 5 Dec 2022 17:29:29 -0400 Subject: [PATCH 1436/1472] Add `with_weight` extrinsic (#12848) * add with weight extrinsic * improve test --- frame/utility/src/lib.rs | 17 +++++++++++++++++ frame/utility/src/tests.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 41710be930b90..00cb18e1b23aa 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -474,6 +474,23 @@ pub mod pallet { let base_weight = T::WeightInfo::batch(calls_len as u32); Ok(Some(base_weight.saturating_add(weight)).into()) } + + /// Dispatch a function call with a specified weight. + /// + /// This function does not check the weight of the call, and instead allows the + /// Root origin to specify the weight of the call. + /// + /// The dispatch origin for this call must be _Root_. + #[pallet::weight((*_weight, call.get_dispatch_info().class))] + pub fn with_weight( + origin: OriginFor, + call: Box<::RuntimeCall>, + _weight: Weight, + ) -> DispatchResult { + ensure_root(origin)?; + let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); + res.map(|_| ()).map_err(|e| e.error) + } } } diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 848fc374619b7..d48ce139d839c 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -901,3 +901,30 @@ fn batch_all_works_with_council_origin() { )); }) } + +#[test] +fn with_weight_works() { + new_test_ext().execute_with(|| { + let upgrade_code_call = + Box::new(RuntimeCall::System(frame_system::Call::set_code_without_checks { + code: vec![], + })); + // Weight before is max. + assert_eq!(upgrade_code_call.get_dispatch_info().weight, Weight::MAX); + assert_eq!( + upgrade_code_call.get_dispatch_info().class, + frame_support::dispatch::DispatchClass::Operational + ); + + let with_weight_call = Call::::with_weight { + call: upgrade_code_call, + weight: Weight::from_parts(123, 456), + }; + // Weight after is set by Root. + assert_eq!(with_weight_call.get_dispatch_info().weight, Weight::from_parts(123, 456)); + assert_eq!( + with_weight_call.get_dispatch_info().class, + frame_support::dispatch::DispatchClass::Operational + ); + }) +} From fa426312187fd39366072bb6883d438a3e61cb4c Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Tue, 6 Dec 2022 11:52:12 +0200 Subject: [PATCH 1437/1472] [contracts] Add per local weight for function call (#12806) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add per local weight for function call * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Update frame/contracts/src/benchmarking/mod.rs Co-authored-by: Alexander Theißen * apply suggestions from code review * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Update frame/contracts/src/benchmarking/mod.rs Co-authored-by: Alexander Theißen * tune the benchmark * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * fix benches * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts Co-authored-by: command-bot <> Co-authored-by: Alexander Theißen --- Cargo.lock | 13 +- frame/contracts/Cargo.toml | 2 +- frame/contracts/src/benchmarking/code.rs | 16 +- frame/contracts/src/benchmarking/mod.rs | 24 +- frame/contracts/src/schedule.rs | 13 + frame/contracts/src/wasm/prepare.rs | 65 +- frame/contracts/src/weights.rs | 2517 +++++++++++----------- 7 files changed, 1383 insertions(+), 1267 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1caffc1d82472..5118edb9e3706 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5271,7 +5271,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-std", - "wasm-instrument", + "wasm-instrument 0.4.0", "wasmi 0.20.0", "wasmparser-nostd", "wat", @@ -7961,7 +7961,7 @@ dependencies = [ "sp-sandbox", "sp-wasm-interface", "thiserror", - "wasm-instrument", + "wasm-instrument 0.3.0", "wasmer", "wasmi 0.13.0", ] @@ -11276,6 +11276,15 @@ dependencies = [ "parity-wasm", ] +[[package]] +name = "wasm-instrument" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a47ecb37b9734d1085eaa5ae1a81e60801fd8c28d4cabdd8aedb982021918bc" +dependencies = [ + "parity-wasm", +] + [[package]] name = "wasm-opt" version = "0.110.2" diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 3906e8589c116..8e6368490f6d7 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } log = { version = "0.4", default-features = false } -wasm-instrument = { version = "0.3", default-features = false } +wasm-instrument = { version = "0.4", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } smallvec = { version = "1", default-features = false, features = [ "const_generics", diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index c1e9f3208b286..2074e1867d506 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -29,11 +29,14 @@ use frame_support::traits::Get; use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::Hash; use sp_std::{borrow::ToOwned, prelude::*}; -use wasm_instrument::parity_wasm::{ - builder, - elements::{ - self, BlockType, CustomSection, External, FuncBody, Instruction, Instructions, Module, - Section, ValueType, +use wasm_instrument::{ + gas_metering, + parity_wasm::{ + builder, + elements::{ + self, BlockType, CustomSection, External, FuncBody, Instruction, Instructions, Module, + Section, ValueType, + }, }, }; @@ -541,7 +544,8 @@ where fn inject_gas_metering(module: Module) -> Module { let schedule = T::Schedule::get(); let gas_rules = schedule.rules(&module, Determinism::Deterministic); - wasm_instrument::gas_metering::inject(module, &gas_rules, "seal0").unwrap() + let backend = gas_metering::host_function::Injector::new("seal0", "gas"); + gas_metering::inject(module, backend, &gas_rules).unwrap() } fn inject_stack_metering(module: Module) -> Module { diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index ebb94b97416c4..87e2ca4388784 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -2429,10 +2429,28 @@ benchmarks! { sbox.invoke(); } + // w_per_local = w_bench + instr_call_per_local { + let l in 0 .. T::Schedule::get().limits.locals; + let mut aux_body = body::plain(vec![ + Instruction::End, + ]); + body::inject_locals(&mut aux_body, l); + let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { + aux_body: Some(aux_body), + call_body: Some(body::repeated(INSTR_BENCHMARK_BATCH_SIZE, &[ + Instruction::Call(2), // call aux + ])), + .. Default::default() + })); + }: { + sbox.invoke(); + } + // w_local_get = w_bench - 1 * w_param instr_local_get { let r in 0 .. INSTR_BENCHMARK_BATCHES; - let max_locals = T::Schedule::get().limits.stack_height.unwrap_or(512); + let max_locals = T::Schedule::get().limits.locals; let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ RandomGetLocal(0, max_locals), Regular(Instruction::Drop), @@ -2449,7 +2467,7 @@ benchmarks! { // w_local_set = w_bench - 1 * w_param instr_local_set { let r in 0 .. INSTR_BENCHMARK_BATCHES; - let max_locals = T::Schedule::get().limits.stack_height.unwrap_or(512); + let max_locals = T::Schedule::get().limits.locals; let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ RandomI64Repeated(1), RandomSetLocal(0, max_locals), @@ -2466,7 +2484,7 @@ benchmarks! { // w_local_tee = w_bench - 2 * w_param instr_local_tee { let r in 0 .. INSTR_BENCHMARK_BATCHES; - let max_locals = T::Schedule::get().limits.stack_height.unwrap_or(512); + let max_locals = T::Schedule::get().limits.locals; let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ RandomI64Repeated(1), RandomTeeLocal(0, max_locals), diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 79f9f49e58190..9d02989642737 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -118,6 +118,12 @@ pub struct Limits { /// the linear memory limit `memory_pages` applies to them. pub globals: u32, + /// Maximum number of locals a function can have. + /// + /// As wasm engine initializes each of the local, we need to limit their number to confine + /// execution costs. + pub locals: u32, + /// Maximum numbers of parameters a function can have. /// /// Those need to be limited to prevent a potentially exploitable interaction with @@ -212,6 +218,7 @@ pub struct InstructionWeights { pub call: u32, pub call_indirect: u32, pub call_indirect_per_param: u32, + pub call_per_local: u32, pub local_get: u32, pub local_set: u32, pub local_tee: u32, @@ -522,6 +529,7 @@ impl Default for Limits { // No stack limit required because we use a runtime resident execution engine. stack_height: None, globals: 256, + locals: 1024, parameters: 128, memory_pages: 16, // 4k function pointers (This is in count not bytes). @@ -552,6 +560,7 @@ impl Default for InstructionWeights { call: cost_instr!(instr_call, 2), call_indirect: cost_instr!(instr_call_indirect, 3), call_indirect_per_param: cost_instr!(instr_call_indirect_per_param, 1), + call_per_local: cost_instr!(instr_call_per_local, 1), local_get: cost_instr!(instr_local_get, 1), local_set: cost_instr!(instr_local_set, 1), local_tee: cost_instr!(instr_local_tee, 2), @@ -792,6 +801,10 @@ impl<'a, T: Config> gas_metering::Rules for ScheduleRules<'a, T> { // The cost for growing is therefore already included in the instruction cost. gas_metering::MemoryGrowCost::Free } + + fn call_per_local_cost(&self) -> u32 { + self.schedule.instruction_weights.call_per_local + } } #[cfg(test)] diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index fb5ae1229078f..c63a5b1e135d9 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -29,8 +29,9 @@ use codec::{Encode, MaxEncodedLen}; use sp_core::crypto::UncheckedFrom; use sp_runtime::{traits::Hash, DispatchError}; use sp_std::prelude::*; -use wasm_instrument::parity_wasm::elements::{ - self, External, Internal, MemoryType, Type, ValueType, +use wasm_instrument::{ + gas_metering, + parity_wasm::elements::{self, External, Internal, MemoryType, Type, ValueType}, }; use wasmi::StackLimits; use wasmparser::{Validator, WasmFeatures}; @@ -132,6 +133,19 @@ impl<'a, T: Config> ContractModule<'a, T> { Ok(()) } + fn ensure_local_variable_limit(&self, limit: u32) -> Result<(), &'static str> { + if let Some(code_section) = self.module.code_section() { + for func_body in code_section.bodies() { + let locals_count: u32 = + func_body.locals().iter().map(|val_type| val_type.count()).sum(); + if locals_count > limit { + return Err("single function declares too many locals") + } + } + } + Ok(()) + } + /// Ensures that no floating point types are in use. fn ensure_no_floating_types(&self) -> Result<(), &'static str> { if let Some(global_section) = self.module.global_section() { @@ -197,9 +211,9 @@ impl<'a, T: Config> ContractModule<'a, T> { fn inject_gas_metering(self, determinism: Determinism) -> Result { let gas_rules = self.schedule.rules(&self.module, determinism); - let contract_module = - wasm_instrument::gas_metering::inject(self.module, &gas_rules, "seal0") - .map_err(|_| "gas instrumentation failed")?; + let backend = gas_metering::host_function::Injector::new("seal0", "gas"); + let contract_module = gas_metering::inject(self.module, backend, &gas_rules) + .map_err(|_| "gas instrumentation failed")?; Ok(ContractModule { module: contract_module, schedule: self.schedule }) } @@ -422,6 +436,7 @@ where contract_module.ensure_no_internal_memory()?; contract_module.ensure_table_size_limit(schedule.limits.table_size)?; contract_module.ensure_global_variable_limit(schedule.limits.globals)?; + contract_module.ensure_local_variable_limit(schedule.limits.locals)?; contract_module.ensure_parameter_limit(schedule.limits.parameters)?; contract_module.ensure_br_table_size_limit(schedule.limits.br_table_size)?; @@ -636,7 +651,8 @@ mod tests { let wasm = wat::parse_str($wat).unwrap().try_into().unwrap(); let schedule = Schedule { limits: Limits { - globals: 3, + globals: 3, + locals: 3, parameters: 3, memory_pages: 16, table_size: 3, @@ -736,6 +752,43 @@ mod tests { ); } + mod locals { + use super::*; + + prepare_test!( + local_number_valid, + r#" + (module + (func + (local i32) + (local i32) + (local i32) + ) + (func (export "call")) + (func (export "deploy")) + ) + "#, + Ok(_) + ); + + prepare_test!( + local_number_too_high, + r#" + (module + (func + (local i32) + (local i32) + (local i32) + (local i32) + ) + (func (export "call")) + (func (export "deploy")) + ) + "#, + Err("single function declares too many locals") + ); + } + mod memories { use super::*; diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index f5c12e92ca94e..680f4c94ebd9f 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-12-01, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -124,6 +124,7 @@ pub trait WeightInfo { fn instr_call(r: u32, ) -> Weight; fn instr_call_indirect(r: u32, ) -> Weight; fn instr_call_indirect_per_param(p: u32, ) -> Weight; + fn instr_call_per_local(l: u32, ) -> Weight; fn instr_local_get(r: u32, ) -> Weight; fn instr_local_set(r: u32, ) -> Weight; fn instr_local_tee(r: u32, ) -> Weight; @@ -170,41 +171,41 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - // Minimum execution time: 3_174 nanoseconds. - Weight::from_ref_time(3_298_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) + // Minimum execution time: 3_148 nanoseconds. + Weight::from_ref_time(3_326_000) + .saturating_add(T::DbWeight::get().reads(1)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - // Minimum execution time: 15_218 nanoseconds. - Weight::from_ref_time(15_548_154 as u64) - // Standard Error: 732 - .saturating_add(Weight::from_ref_time(940_242 as u64).saturating_mul(k as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) + // Minimum execution time: 15_318 nanoseconds. + Weight::from_ref_time(14_905_070) + // Standard Error: 1_055 + .saturating_add(Weight::from_ref_time(941_176).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) } // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - // Minimum execution time: 3_096 nanoseconds. - Weight::from_ref_time(14_949_039 as u64) - // Standard Error: 3_466 - .saturating_add(Weight::from_ref_time(1_236_160 as u64).saturating_mul(q as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 3_182 nanoseconds. + Weight::from_ref_time(14_837_078) + // Standard Error: 3_423 + .saturating_add(Weight::from_ref_time(1_203_909).saturating_mul(q.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - // Minimum execution time: 28_333 nanoseconds. - Weight::from_ref_time(19_421_544 as u64) - // Standard Error: 92 - .saturating_add(Weight::from_ref_time(47_629 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 34_272 nanoseconds. + Weight::from_ref_time(33_159_915) + // Standard Error: 60 + .saturating_add(Weight::from_ref_time(46_967).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) @@ -213,12 +214,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - // Minimum execution time: 304_381 nanoseconds. - Weight::from_ref_time(315_177_233 as u64) - // Standard Error: 22 - .saturating_add(Weight::from_ref_time(30_372 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 395_141 nanoseconds. + Weight::from_ref_time(413_672_628) + // Standard Error: 25 + .saturating_add(Weight::from_ref_time(30_570).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -231,14 +232,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - // Minimum execution time: 2_119_963 nanoseconds. - Weight::from_ref_time(337_976_516 as u64) - // Standard Error: 84 - .saturating_add(Weight::from_ref_time(88_566 as u64).saturating_mul(c as u64)) - // Standard Error: 5 - .saturating_add(Weight::from_ref_time(1_747 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().writes(9 as u64)) + // Minimum execution time: 2_259_439 nanoseconds. + Weight::from_ref_time(407_506_250) + // Standard Error: 79 + .saturating_add(Weight::from_ref_time(89_557).saturating_mul(c.into())) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(1_804).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(9)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -249,12 +250,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - // Minimum execution time: 184_739 nanoseconds. - Weight::from_ref_time(179_778_057 as u64) - // Standard Error: 2 - .saturating_add(Weight::from_ref_time(1_487 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().writes(7 as u64)) + // Minimum execution time: 185_950 nanoseconds. + Weight::from_ref_time(173_152_122) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(1_559).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) @@ -262,10 +263,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - // Minimum execution time: 154_711 nanoseconds. - Weight::from_ref_time(155_527_000 as u64) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 154_738 nanoseconds. + Weight::from_ref_time(159_212_000) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: System EventTopics (r:1 w:1) @@ -273,31 +274,31 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - // Minimum execution time: 294_982 nanoseconds. - Weight::from_ref_time(302_482_450 as u64) - // Standard Error: 62 - .saturating_add(Weight::from_ref_time(88_358 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 392_302 nanoseconds. + Weight::from_ref_time(402_889_681) + // Standard Error: 84 + .saturating_add(Weight::from_ref_time(89_393).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Contracts OwnerInfoOf (r:1 w:1) // Storage: System EventTopics (r:1 w:1) // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - // Minimum execution time: 39_655 nanoseconds. - Weight::from_ref_time(40_147_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 39_892 nanoseconds. + Weight::from_ref_time(40_258_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - // Minimum execution time: 41_028 nanoseconds. - Weight::from_ref_time(41_565_000 as u64) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + // Minimum execution time: 41_441 nanoseconds. + Weight::from_ref_time(42_011_000) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -306,12 +307,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - // Minimum execution time: 294_231 nanoseconds. - Weight::from_ref_time(298_245_008 as u64) - // Standard Error: 41_817 - .saturating_add(Weight::from_ref_time(16_183_097 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_919 nanoseconds. + Weight::from_ref_time(387_844_956) + // Standard Error: 38_460 + .saturating_add(Weight::from_ref_time(16_014_536).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -320,13 +321,13 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - // Minimum execution time: 293_152 nanoseconds. - Weight::from_ref_time(231_239_439 as u64) - // Standard Error: 475_771 - .saturating_add(Weight::from_ref_time(193_804_587 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 384_047 nanoseconds. + Weight::from_ref_time(316_828_665) + // Standard Error: 571_260 + .saturating_add(Weight::from_ref_time(197_635_022).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -335,13 +336,13 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 296_171 nanoseconds. - Weight::from_ref_time(244_339_298 as u64) - // Standard Error: 440_060 - .saturating_add(Weight::from_ref_time(236_224_857 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 385_259 nanoseconds. + Weight::from_ref_time(338_849_650) + // Standard Error: 447_004 + .saturating_add(Weight::from_ref_time(235_734_380).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -350,12 +351,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 294_891 nanoseconds. - Weight::from_ref_time(298_061_159 as u64) - // Standard Error: 30_013 - .saturating_add(Weight::from_ref_time(19_682_309 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 385_528 nanoseconds. + Weight::from_ref_time(388_332_749) + // Standard Error: 43_017 + .saturating_add(Weight::from_ref_time(20_406_602).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -364,12 +365,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - // Minimum execution time: 293_259 nanoseconds. - Weight::from_ref_time(296_675_355 as u64) - // Standard Error: 24_508 - .saturating_add(Weight::from_ref_time(10_949_451 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 382_243 nanoseconds. + Weight::from_ref_time(387_692_764) + // Standard Error: 32_726 + .saturating_add(Weight::from_ref_time(10_753_573).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -378,12 +379,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - // Minimum execution time: 293_507 nanoseconds. - Weight::from_ref_time(295_682_709 as u64) - // Standard Error: 43_685 - .saturating_add(Weight::from_ref_time(16_461_873 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_993 nanoseconds. + Weight::from_ref_time(389_189_394) + // Standard Error: 55_885 + .saturating_add(Weight::from_ref_time(15_943_739).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -392,12 +393,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - // Minimum execution time: 293_473 nanoseconds. - Weight::from_ref_time(296_523_274 as u64) - // Standard Error: 34_356 - .saturating_add(Weight::from_ref_time(15_932_835 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_057 nanoseconds. + Weight::from_ref_time(387_466_678) + // Standard Error: 38_570 + .saturating_add(Weight::from_ref_time(15_739_675).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -406,12 +407,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - // Minimum execution time: 293_889 nanoseconds. - Weight::from_ref_time(295_471_068 as u64) - // Standard Error: 88_937 - .saturating_add(Weight::from_ref_time(89_606_655 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_688 nanoseconds. + Weight::from_ref_time(394_708_428) + // Standard Error: 101_035 + .saturating_add(Weight::from_ref_time(89_822_613).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -420,12 +421,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - // Minimum execution time: 293_747 nanoseconds. - Weight::from_ref_time(297_023_967 as u64) - // Standard Error: 18_756 - .saturating_add(Weight::from_ref_time(15_748_008 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_511 nanoseconds. + Weight::from_ref_time(387_270_075) + // Standard Error: 33_383 + .saturating_add(Weight::from_ref_time(15_672_963).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -434,12 +435,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - // Minimum execution time: 293_590 nanoseconds. - Weight::from_ref_time(296_257_202 as u64) - // Standard Error: 24_863 - .saturating_add(Weight::from_ref_time(15_851_537 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_483 nanoseconds. + Weight::from_ref_time(386_995_457) + // Standard Error: 28_781 + .saturating_add(Weight::from_ref_time(15_632_597).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -448,12 +449,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - // Minimum execution time: 293_746 nanoseconds. - Weight::from_ref_time(297_308_097 as u64) - // Standard Error: 29_585 - .saturating_add(Weight::from_ref_time(15_608_985 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_630 nanoseconds. + Weight::from_ref_time(387_801_190) + // Standard Error: 41_234 + .saturating_add(Weight::from_ref_time(15_531_236).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -462,12 +463,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - // Minimum execution time: 293_662 nanoseconds. - Weight::from_ref_time(296_393_072 as u64) - // Standard Error: 23_750 - .saturating_add(Weight::from_ref_time(15_891_911 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_668 nanoseconds. + Weight::from_ref_time(387_490_160) + // Standard Error: 28_070 + .saturating_add(Weight::from_ref_time(15_639_764).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -477,12 +478,12 @@ impl WeightInfo for SubstrateWeight { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - // Minimum execution time: 294_036 nanoseconds. - Weight::from_ref_time(301_071_620 as u64) - // Standard Error: 85_146 - .saturating_add(Weight::from_ref_time(84_455_768 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_401 nanoseconds. + Weight::from_ref_time(393_140_360) + // Standard Error: 95_092 + .saturating_add(Weight::from_ref_time(83_864_160).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -491,12 +492,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - // Minimum execution time: 142_655 nanoseconds. - Weight::from_ref_time(145_691_226 as u64) - // Standard Error: 11_085 - .saturating_add(Weight::from_ref_time(7_953_680 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 142_684 nanoseconds. + Weight::from_ref_time(145_540_019) + // Standard Error: 18_177 + .saturating_add(Weight::from_ref_time(8_061_360).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -505,12 +506,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - // Minimum execution time: 293_613 nanoseconds. - Weight::from_ref_time(296_889_714 as u64) - // Standard Error: 21_550 - .saturating_add(Weight::from_ref_time(13_672_097 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_472 nanoseconds. + Weight::from_ref_time(386_518_915) + // Standard Error: 46_174 + .saturating_add(Weight::from_ref_time(14_052_552).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -519,12 +520,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 309_866 nanoseconds. - Weight::from_ref_time(328_331_386 as u64) - // Standard Error: 6_205 - .saturating_add(Weight::from_ref_time(9_619_067 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 398_912 nanoseconds. + Weight::from_ref_time(426_793_015) + // Standard Error: 5_524 + .saturating_add(Weight::from_ref_time(9_645_931).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -533,12 +534,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - // Minimum execution time: 288_265 nanoseconds. - Weight::from_ref_time(292_739_779 as u64) - // Standard Error: 108_313 - .saturating_add(Weight::from_ref_time(1_475_820 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 380_288 nanoseconds. + Weight::from_ref_time(382_064_302) + // Standard Error: 274_854 + .saturating_add(Weight::from_ref_time(5_341_497).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -547,12 +548,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 293_044 nanoseconds. - Weight::from_ref_time(293_846_263 as u64) - // Standard Error: 641 - .saturating_add(Weight::from_ref_time(188_770 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 382_104 nanoseconds. + Weight::from_ref_time(383_966_376) + // Standard Error: 668 + .saturating_add(Weight::from_ref_time(230_898).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -563,14 +564,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - // Minimum execution time: 289_248 nanoseconds. - Weight::from_ref_time(294_406_912 as u64) - // Standard Error: 112_528 - .saturating_add(Weight::from_ref_time(52_650_987 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((6 as u64).saturating_mul(r as u64))) + // Minimum execution time: 382_423 nanoseconds. + Weight::from_ref_time(384_162_748) + // Standard Error: 403_637 + .saturating_add(Weight::from_ref_time(57_465_451).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(r.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -580,12 +581,12 @@ impl WeightInfo for SubstrateWeight { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - // Minimum execution time: 292_980 nanoseconds. - Weight::from_ref_time(298_232_040 as u64) - // Standard Error: 85_517 - .saturating_add(Weight::from_ref_time(108_891_823 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 382_853 nanoseconds. + Weight::from_ref_time(391_962_017) + // Standard Error: 102_169 + .saturating_add(Weight::from_ref_time(108_325_188).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -594,12 +595,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - // Minimum execution time: 291_668 nanoseconds. - Weight::from_ref_time(302_010_570 as u64) - // Standard Error: 109_901 - .saturating_add(Weight::from_ref_time(214_667_762 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 380_999 nanoseconds. + Weight::from_ref_time(392_336_632) + // Standard Error: 168_846 + .saturating_add(Weight::from_ref_time(218_950_403).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -609,16 +610,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - // Minimum execution time: 1_163_533 nanoseconds. - Weight::from_ref_time(501_280_410 as u64) - // Standard Error: 601_576 - .saturating_add(Weight::from_ref_time(172_210_846 as u64).saturating_mul(t as u64)) - // Standard Error: 165_221 - .saturating_add(Weight::from_ref_time(67_584_003 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(t as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(t as u64))) + // Minimum execution time: 1_276_841 nanoseconds. + Weight::from_ref_time(587_558_952) + // Standard Error: 504_583 + .saturating_add(Weight::from_ref_time(178_141_140).saturating_mul(t.into())) + // Standard Error: 138_583 + .saturating_add(Weight::from_ref_time(71_194_319).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(t.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(t.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -627,140 +628,140 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - // Minimum execution time: 154_390 nanoseconds. - Weight::from_ref_time(158_246_775 as u64) - // Standard Error: 23_812 - .saturating_add(Weight::from_ref_time(12_810_293 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 161_230 nanoseconds. + Weight::from_ref_time(168_508_241) + // Standard Error: 31_112 + .saturating_add(Weight::from_ref_time(12_496_531).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - // Minimum execution time: 292_926 nanoseconds. - Weight::from_ref_time(250_238_246 as u64) - // Standard Error: 485_292 - .saturating_add(Weight::from_ref_time(402_779_709 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Minimum execution time: 383_055 nanoseconds. + Weight::from_ref_time(339_358_786) + // Standard Error: 486_941 + .saturating_add(Weight::from_ref_time(412_066_056).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - // Minimum execution time: 421_504 nanoseconds. - Weight::from_ref_time(574_267_945 as u64) - // Standard Error: 1_407_019 - .saturating_add(Weight::from_ref_time(89_516_682 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(52 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(50 as u64)) - .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + // Minimum execution time: 512_301 nanoseconds. + Weight::from_ref_time(670_220_816) + // Standard Error: 1_460_983 + .saturating_add(Weight::from_ref_time(97_308_816).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(52)) + .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(50)) + .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - // Minimum execution time: 421_422 nanoseconds. - Weight::from_ref_time(545_948_271 as u64) - // Standard Error: 1_148_143 - .saturating_add(Weight::from_ref_time(63_958_096 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(51 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(49 as u64)) - .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + // Minimum execution time: 510_820 nanoseconds. + Weight::from_ref_time(638_537_372) + // Standard Error: 1_195_632 + .saturating_add(Weight::from_ref_time(65_979_491).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(51)) + .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(49)) + .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - // Minimum execution time: 293_545 nanoseconds. - Weight::from_ref_time(255_622_312 as u64) - // Standard Error: 407_862 - .saturating_add(Weight::from_ref_time(396_764_962 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Minimum execution time: 383_596 nanoseconds. + Weight::from_ref_time(341_575_167) + // Standard Error: 478_894 + .saturating_add(Weight::from_ref_time(407_044_103).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 390_339 nanoseconds. - Weight::from_ref_time(528_774_888 as u64) - // Standard Error: 1_278_188 - .saturating_add(Weight::from_ref_time(66_683_698 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(51 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(48 as u64)) - .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + // Minimum execution time: 481_757 nanoseconds. + Weight::from_ref_time(628_126_550) + // Standard Error: 1_363_017 + .saturating_add(Weight::from_ref_time(67_242_851).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(51)) + .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(48)) + .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - // Minimum execution time: 294_904 nanoseconds. - Weight::from_ref_time(265_679_354 as u64) - // Standard Error: 386_673 - .saturating_add(Weight::from_ref_time(318_869_116 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_868 nanoseconds. + Weight::from_ref_time(359_800_153) + // Standard Error: 338_998 + .saturating_add(Weight::from_ref_time(323_351_220).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 372_784 nanoseconds. - Weight::from_ref_time(487_784_160 as u64) - // Standard Error: 1_092_850 - .saturating_add(Weight::from_ref_time(152_413_290 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(51 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 462_237 nanoseconds. + Weight::from_ref_time(585_809_405) + // Standard Error: 1_181_517 + .saturating_add(Weight::from_ref_time(160_905_409).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(51)) + .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - // Minimum execution time: 301_191 nanoseconds. - Weight::from_ref_time(270_493_545 as u64) - // Standard Error: 373_565 - .saturating_add(Weight::from_ref_time(302_870_977 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_794 nanoseconds. + Weight::from_ref_time(355_233_888) + // Standard Error: 416_492 + .saturating_add(Weight::from_ref_time(317_857_887).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 368_641 nanoseconds. - Weight::from_ref_time(469_340_170 as u64) - // Standard Error: 966_589 - .saturating_add(Weight::from_ref_time(62_000_083 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(51 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 462_530 nanoseconds. + Weight::from_ref_time(571_276_165) + // Standard Error: 1_035_339 + .saturating_add(Weight::from_ref_time(63_481_618).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(51)) + .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - // Minimum execution time: 294_717 nanoseconds. - Weight::from_ref_time(254_308_806 as u64) - // Standard Error: 443_802 - .saturating_add(Weight::from_ref_time(408_899_238 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Minimum execution time: 385_343 nanoseconds. + Weight::from_ref_time(341_897_876) + // Standard Error: 451_948 + .saturating_add(Weight::from_ref_time(417_987_655).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 396_211 nanoseconds. - Weight::from_ref_time(545_169_999 as u64) - // Standard Error: 1_390_049 - .saturating_add(Weight::from_ref_time(156_931_202 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(51 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(48 as u64)) - .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + // Minimum execution time: 485_507 nanoseconds. + Weight::from_ref_time(646_265_325) + // Standard Error: 1_495_172 + .saturating_add(Weight::from_ref_time(166_973_554).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(51)) + .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(48)) + .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -769,14 +770,14 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - // Minimum execution time: 295_145 nanoseconds. - Weight::from_ref_time(241_332_033 as u64) - // Standard Error: 658_837 - .saturating_add(Weight::from_ref_time(1_315_958_335 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Minimum execution time: 384_834 nanoseconds. + Weight::from_ref_time(348_341_375) + // Standard Error: 792_708 + .saturating_add(Weight::from_ref_time(1_336_691_822).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -785,14 +786,14 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - // Minimum execution time: 295_624 nanoseconds. - Weight::from_ref_time(296_567_000 as u64) - // Standard Error: 6_725_484 - .saturating_add(Weight::from_ref_time(20_773_662_959 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(7 as u64)) - .saturating_add(T::DbWeight::get().reads((160 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((160 as u64).saturating_mul(r as u64))) + // Minimum execution time: 386_112 nanoseconds. + Weight::from_ref_time(386_971_000) + // Standard Error: 5_920_386 + .saturating_add(Weight::from_ref_time(28_051_657_660).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads((160_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((160_u64).saturating_mul(r.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -801,14 +802,14 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - // Minimum execution time: 296_698 nanoseconds. - Weight::from_ref_time(297_541_000 as u64) - // Standard Error: 18_681_855 - .saturating_add(Weight::from_ref_time(20_702_951_248 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((150 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((75 as u64).saturating_mul(r as u64))) + // Minimum execution time: 385_776 nanoseconds. + Weight::from_ref_time(387_017_000) + // Standard Error: 6_680_801 + .saturating_add(Weight::from_ref_time(27_761_537_154).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((150_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((75_u64).saturating_mul(r.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -818,16 +819,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - // Minimum execution time: 9_491_225 nanoseconds. - Weight::from_ref_time(8_726_446_640 as u64) - // Standard Error: 11_723_053 - .saturating_add(Weight::from_ref_time(1_107_970_775 as u64).saturating_mul(t as u64)) - // Standard Error: 17_578 - .saturating_add(Weight::from_ref_time(9_748_009 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(167 as u64)) - .saturating_add(T::DbWeight::get().reads((81 as u64).saturating_mul(t as u64))) - .saturating_add(T::DbWeight::get().writes(163 as u64)) - .saturating_add(T::DbWeight::get().writes((81 as u64).saturating_mul(t as u64))) + // Minimum execution time: 9_623_952 nanoseconds. + Weight::from_ref_time(8_552_923_566) + // Standard Error: 6_582_866 + .saturating_add(Weight::from_ref_time(1_283_786_003).saturating_mul(t.into())) + // Standard Error: 9_870 + .saturating_add(Weight::from_ref_time(9_833_844).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(167)) + .saturating_add(T::DbWeight::get().reads((81_u64).saturating_mul(t.into()))) + .saturating_add(T::DbWeight::get().writes(163)) + .saturating_add(T::DbWeight::get().writes((81_u64).saturating_mul(t.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -838,14 +839,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - // Minimum execution time: 294_351 nanoseconds. - Weight::from_ref_time(297_837_000 as u64) - // Standard Error: 17_115_732 - .saturating_add(Weight::from_ref_time(25_936_348_025 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().reads((400 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(5 as u64)) - .saturating_add(T::DbWeight::get().writes((400 as u64).saturating_mul(r as u64))) + // Minimum execution time: 386_667 nanoseconds. + Weight::from_ref_time(387_559_000) + // Standard Error: 18_953_118 + .saturating_add(Weight::from_ref_time(33_188_342_429).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads((400_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes((400_u64).saturating_mul(r.into()))) } // Storage: System Account (r:81 w:81) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -857,14 +858,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - // Minimum execution time: 11_367_191 nanoseconds. - Weight::from_ref_time(11_186_726_411 as u64) - // Standard Error: 75_273 - .saturating_add(Weight::from_ref_time(122_421_705 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(249 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(t as u64))) - .saturating_add(T::DbWeight::get().writes(247 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(t as u64))) + // Minimum execution time: 11_664_478 nanoseconds. + Weight::from_ref_time(11_359_540_086) + // Standard Error: 45_626_277 + .saturating_add(Weight::from_ref_time(19_120_579).saturating_mul(t.into())) + // Standard Error: 72_976 + .saturating_add(Weight::from_ref_time(125_731_953).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(249)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) + .saturating_add(T::DbWeight::get().writes(247)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -873,12 +876,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - // Minimum execution time: 293_753 nanoseconds. - Weight::from_ref_time(295_491_471 as u64) - // Standard Error: 112_217 - .saturating_add(Weight::from_ref_time(41_976_228 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 384_826 nanoseconds. + Weight::from_ref_time(387_293_630) + // Standard Error: 437_875 + .saturating_add(Weight::from_ref_time(48_464_369).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -887,12 +890,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 335_784 nanoseconds. - Weight::from_ref_time(336_406_000 as u64) - // Standard Error: 58_205 - .saturating_add(Weight::from_ref_time(323_644_833 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 426_531 nanoseconds. + Weight::from_ref_time(427_315_000) + // Standard Error: 48_058 + .saturating_add(Weight::from_ref_time(327_318_884).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -901,12 +904,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - // Minimum execution time: 292_772 nanoseconds. - Weight::from_ref_time(294_845_565 as u64) - // Standard Error: 118_932 - .saturating_add(Weight::from_ref_time(53_186_034 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 384_084 nanoseconds. + Weight::from_ref_time(386_354_628) + // Standard Error: 195_951 + .saturating_add(Weight::from_ref_time(52_991_271).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -915,12 +918,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 348_057 nanoseconds. - Weight::from_ref_time(354_903_000 as u64) - // Standard Error: 63_036 - .saturating_add(Weight::from_ref_time(247_852_636 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 438_319 nanoseconds. + Weight::from_ref_time(439_001_000) + // Standard Error: 53_445 + .saturating_add(Weight::from_ref_time(251_353_803).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -929,12 +932,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - // Minimum execution time: 290_417 nanoseconds. - Weight::from_ref_time(295_285_706 as u64) - // Standard Error: 124_630 - .saturating_add(Weight::from_ref_time(31_293_293 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 384_397 nanoseconds. + Weight::from_ref_time(386_532_859) + // Standard Error: 141_195 + .saturating_add(Weight::from_ref_time(31_116_440).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -943,12 +946,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 325_903 nanoseconds. - Weight::from_ref_time(326_482_000 as u64) - // Standard Error: 47_465 - .saturating_add(Weight::from_ref_time(99_615_769 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 416_504 nanoseconds. + Weight::from_ref_time(417_686_000) + // Standard Error: 47_003 + .saturating_add(Weight::from_ref_time(103_095_636).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -957,12 +960,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - // Minimum execution time: 291_624 nanoseconds. - Weight::from_ref_time(295_781_938 as u64) - // Standard Error: 849_772 - .saturating_add(Weight::from_ref_time(30_869_061 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 382_479 nanoseconds. + Weight::from_ref_time(384_623_057) + // Standard Error: 243_054 + .saturating_add(Weight::from_ref_time(37_025_542).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -971,12 +974,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 323_456 nanoseconds. - Weight::from_ref_time(324_815_000 as u64) - // Standard Error: 49_126 - .saturating_add(Weight::from_ref_time(99_651_878 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 414_863 nanoseconds. + Weight::from_ref_time(415_728_000) + // Standard Error: 48_764 + .saturating_add(Weight::from_ref_time(103_050_672).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -985,12 +988,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - // Minimum execution time: 294_244 nanoseconds. - Weight::from_ref_time(296_117_277 as u64) - // Standard Error: 513_100 - .saturating_add(Weight::from_ref_time(3_005_168_422 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 384_418 nanoseconds. + Weight::from_ref_time(387_283_069) + // Standard Error: 526_301 + .saturating_add(Weight::from_ref_time(2_993_987_030).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -999,12 +1002,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - // Minimum execution time: 293_099 nanoseconds. - Weight::from_ref_time(295_349_591 as u64) - // Standard Error: 437_688 - .saturating_add(Weight::from_ref_time(2_079_472_608 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_686 nanoseconds. + Weight::from_ref_time(385_812_638) + // Standard Error: 539_029 + .saturating_add(Weight::from_ref_time(2_098_063_561).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1014,14 +1017,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 293_692 nanoseconds. - Weight::from_ref_time(294_871_000 as u64) - // Standard Error: 2_737_018 - .saturating_add(Weight::from_ref_time(1_360_098_499 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((225 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((150 as u64).saturating_mul(r as u64))) + // Minimum execution time: 384_399 nanoseconds. + Weight::from_ref_time(385_337_000) + // Standard Error: 2_827_655 + .saturating_add(Weight::from_ref_time(1_383_659_432).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((225_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((150_u64).saturating_mul(r.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1030,12 +1033,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_reentrance_count(r: u32, ) -> Weight { - // Minimum execution time: 295_570 nanoseconds. - Weight::from_ref_time(299_077_520 as u64) - // Standard Error: 23_516 - .saturating_add(Weight::from_ref_time(10_971_589 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 385_165 nanoseconds. + Weight::from_ref_time(389_255_026) + // Standard Error: 25_918 + .saturating_add(Weight::from_ref_time(10_716_905).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1044,369 +1047,376 @@ impl WeightInfo for SubstrateWeight { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { - // Minimum execution time: 296_873 nanoseconds. - Weight::from_ref_time(336_309_706 as u64) - // Standard Error: 125_484 - .saturating_add(Weight::from_ref_time(25_321_948 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 386_959 nanoseconds. + Weight::from_ref_time(423_364_524) + // Standard Error: 127_096 + .saturating_add(Weight::from_ref_time(25_552_186).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - // Minimum execution time: 686 nanoseconds. - Weight::from_ref_time(895_726 as u64) - // Standard Error: 144 - .saturating_add(Weight::from_ref_time(344_525 as u64).saturating_mul(r as u64)) + // Minimum execution time: 688 nanoseconds. + Weight::from_ref_time(914_830) + // Standard Error: 222 + .saturating_add(Weight::from_ref_time(343_835).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // Minimum execution time: 780 nanoseconds. - Weight::from_ref_time(590_334 as u64) - // Standard Error: 10_839 - .saturating_add(Weight::from_ref_time(1_038_503 as u64).saturating_mul(r as u64)) + // Minimum execution time: 775 nanoseconds. + Weight::from_ref_time(1_286_008) + // Standard Error: 391 + .saturating_add(Weight::from_ref_time(984_759).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // Minimum execution time: 755 nanoseconds. - Weight::from_ref_time(1_139_912 as u64) - // Standard Error: 466 - .saturating_add(Weight::from_ref_time(881_780 as u64).saturating_mul(r as u64)) + // Minimum execution time: 779 nanoseconds. + Weight::from_ref_time(1_162_588) + // Standard Error: 694 + .saturating_add(Weight::from_ref_time(883_828).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // Minimum execution time: 670 nanoseconds. - Weight::from_ref_time(941_845 as u64) - // Standard Error: 227 - .saturating_add(Weight::from_ref_time(956_897 as u64).saturating_mul(r as u64)) + // Minimum execution time: 687 nanoseconds. + Weight::from_ref_time(965_966) + // Standard Error: 290 + .saturating_add(Weight::from_ref_time(955_392).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // Minimum execution time: 676 nanoseconds. - Weight::from_ref_time(600_675 as u64) - // Standard Error: 555 - .saturating_add(Weight::from_ref_time(1_294_447 as u64).saturating_mul(r as u64)) + // Minimum execution time: 681 nanoseconds. + Weight::from_ref_time(778_970) + // Standard Error: 670 + .saturating_add(Weight::from_ref_time(1_265_116).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // Minimum execution time: 680 nanoseconds. - Weight::from_ref_time(1_192_340 as u64) - // Standard Error: 897 - .saturating_add(Weight::from_ref_time(524_835 as u64).saturating_mul(r as u64)) + // Minimum execution time: 673 nanoseconds. + Weight::from_ref_time(1_125_562) + // Standard Error: 818 + .saturating_add(Weight::from_ref_time(528_126).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // Minimum execution time: 653 nanoseconds. - Weight::from_ref_time(1_136_213 as u64) - // Standard Error: 1_137 - .saturating_add(Weight::from_ref_time(791_920 as u64).saturating_mul(r as u64)) + // Minimum execution time: 649 nanoseconds. + Weight::from_ref_time(780_802) + // Standard Error: 943 + .saturating_add(Weight::from_ref_time(800_988).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // Minimum execution time: 669 nanoseconds. - Weight::from_ref_time(491_588 as u64) - // Standard Error: 2_098 - .saturating_add(Weight::from_ref_time(1_078_017 as u64).saturating_mul(r as u64)) + // Minimum execution time: 662 nanoseconds. + Weight::from_ref_time(555_078) + // Standard Error: 1_540 + .saturating_add(Weight::from_ref_time(1_078_705).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - // Minimum execution time: 2_128 nanoseconds. - Weight::from_ref_time(2_565_932 as u64) - // Standard Error: 76 - .saturating_add(Weight::from_ref_time(4_830 as u64).saturating_mul(e as u64)) + // Minimum execution time: 2_177 nanoseconds. + Weight::from_ref_time(2_581_121) + // Standard Error: 67 + .saturating_add(Weight::from_ref_time(5_001).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // Minimum execution time: 665 nanoseconds. - Weight::from_ref_time(1_593_317 as u64) - // Standard Error: 2_288 - .saturating_add(Weight::from_ref_time(2_195_453 as u64).saturating_mul(r as u64)) + // Minimum execution time: 702 nanoseconds. + Weight::from_ref_time(1_570_695) + // Standard Error: 1_524 + .saturating_add(Weight::from_ref_time(2_192_040).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // Minimum execution time: 796 nanoseconds. - Weight::from_ref_time(1_816_603 as u64) - // Standard Error: 2_183 - .saturating_add(Weight::from_ref_time(2_808_821 as u64).saturating_mul(r as u64)) + // Minimum execution time: 745 nanoseconds. + Weight::from_ref_time(1_694_451) + // Standard Error: 4_170 + .saturating_add(Weight::from_ref_time(2_813_621).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - // Minimum execution time: 4_212 nanoseconds. - Weight::from_ref_time(5_097_891 as u64) - // Standard Error: 576 - .saturating_add(Weight::from_ref_time(180_948 as u64).saturating_mul(p as u64)) + // Minimum execution time: 4_255 nanoseconds. + Weight::from_ref_time(5_064_243) + // Standard Error: 289 + .saturating_add(Weight::from_ref_time(178_868).saturating_mul(p.into())) + } + /// The range of component `l` is `[0, 1024]`. + fn instr_call_per_local(l: u32, ) -> Weight { + // Minimum execution time: 2_802 nanoseconds. + Weight::from_ref_time(3_474_642) + // Standard Error: 28 + .saturating_add(Weight::from_ref_time(92_517).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // Minimum execution time: 1_412 nanoseconds. - Weight::from_ref_time(1_733_015 as u64) - // Standard Error: 215 - .saturating_add(Weight::from_ref_time(366_629 as u64).saturating_mul(r as u64)) + // Minimum execution time: 2_973 nanoseconds. + Weight::from_ref_time(3_218_977) + // Standard Error: 183 + .saturating_add(Weight::from_ref_time(364_688).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // Minimum execution time: 1_436 nanoseconds. - Weight::from_ref_time(1_772_333 as u64) - // Standard Error: 288 - .saturating_add(Weight::from_ref_time(380_886 as u64).saturating_mul(r as u64)) + // Minimum execution time: 2_912 nanoseconds. + Weight::from_ref_time(3_173_203) + // Standard Error: 260 + .saturating_add(Weight::from_ref_time(381_853).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // Minimum execution time: 1_408 nanoseconds. - Weight::from_ref_time(1_731_571 as u64) - // Standard Error: 334 - .saturating_add(Weight::from_ref_time(526_489 as u64).saturating_mul(r as u64)) + // Minimum execution time: 2_916 nanoseconds. + Weight::from_ref_time(3_228_548) + // Standard Error: 311 + .saturating_add(Weight::from_ref_time(526_008).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // Minimum execution time: 752 nanoseconds. - Weight::from_ref_time(1_118_170 as u64) - // Standard Error: 302 - .saturating_add(Weight::from_ref_time(809_371 as u64).saturating_mul(r as u64)) + // Minimum execution time: 739 nanoseconds. + Weight::from_ref_time(1_128_919) + // Standard Error: 479 + .saturating_add(Weight::from_ref_time(810_765).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // Minimum execution time: 770 nanoseconds. - Weight::from_ref_time(990_414 as u64) - // Standard Error: 331 - .saturating_add(Weight::from_ref_time(831_541 as u64).saturating_mul(r as u64)) + // Minimum execution time: 724 nanoseconds. + Weight::from_ref_time(1_044_382) + // Standard Error: 371 + .saturating_add(Weight::from_ref_time(828_530).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // Minimum execution time: 783 nanoseconds. - Weight::from_ref_time(992_847 as u64) - // Standard Error: 437 - .saturating_add(Weight::from_ref_time(695_374 as u64).saturating_mul(r as u64)) + // Minimum execution time: 770 nanoseconds. + Weight::from_ref_time(988_307) + // Standard Error: 587 + .saturating_add(Weight::from_ref_time(699_091).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // Minimum execution time: 664 nanoseconds. - Weight::from_ref_time(758_730 as u64) - // Standard Error: 5_030 - .saturating_add(Weight::from_ref_time(184_801_569 as u64).saturating_mul(r as u64)) + // Minimum execution time: 688 nanoseconds. + Weight::from_ref_time(747_995) + // Standard Error: 3_894 + .saturating_add(Weight::from_ref_time(234_512_504).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // Minimum execution time: 657 nanoseconds. - Weight::from_ref_time(941_928 as u64) - // Standard Error: 216 - .saturating_add(Weight::from_ref_time(506_159 as u64).saturating_mul(r as u64)) + // Minimum execution time: 643 nanoseconds. + Weight::from_ref_time(946_893) + // Standard Error: 188 + .saturating_add(Weight::from_ref_time(505_004).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - // Minimum execution time: 617 nanoseconds. - Weight::from_ref_time(1_009_437 as u64) - // Standard Error: 435 - .saturating_add(Weight::from_ref_time(512_427 as u64).saturating_mul(r as u64)) + // Minimum execution time: 663 nanoseconds. + Weight::from_ref_time(965_194) + // Standard Error: 343 + .saturating_add(Weight::from_ref_time(505_213).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // Minimum execution time: 663 nanoseconds. - Weight::from_ref_time(875_558 as u64) - // Standard Error: 394 - .saturating_add(Weight::from_ref_time(513_247 as u64).saturating_mul(r as u64)) + // Minimum execution time: 675 nanoseconds. + Weight::from_ref_time(903_705) + // Standard Error: 425 + .saturating_add(Weight::from_ref_time(507_749).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // Minimum execution time: 664 nanoseconds. - Weight::from_ref_time(891_913 as u64) - // Standard Error: 171 - .saturating_add(Weight::from_ref_time(523_595 as u64).saturating_mul(r as u64)) + // Minimum execution time: 637 nanoseconds. + Weight::from_ref_time(946_419) + // Standard Error: 301 + .saturating_add(Weight::from_ref_time(522_387).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // Minimum execution time: 638 nanoseconds. - Weight::from_ref_time(1_003_558 as u64) - // Standard Error: 471 - .saturating_add(Weight::from_ref_time(502_671 as u64).saturating_mul(r as u64)) + // Minimum execution time: 674 nanoseconds. + Weight::from_ref_time(963_566) + // Standard Error: 952 + .saturating_add(Weight::from_ref_time(504_528).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // Minimum execution time: 665 nanoseconds. - Weight::from_ref_time(892_435 as u64) - // Standard Error: 162 - .saturating_add(Weight::from_ref_time(504_300 as u64).saturating_mul(r as u64)) + // Minimum execution time: 663 nanoseconds. + Weight::from_ref_time(927_099) + // Standard Error: 336 + .saturating_add(Weight::from_ref_time(505_200).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // Minimum execution time: 626 nanoseconds. - Weight::from_ref_time(880_015 as u64) - // Standard Error: 229 - .saturating_add(Weight::from_ref_time(503_941 as u64).saturating_mul(r as u64)) + // Minimum execution time: 660 nanoseconds. + Weight::from_ref_time(901_114) + // Standard Error: 255 + .saturating_add(Weight::from_ref_time(503_803).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // Minimum execution time: 623 nanoseconds. - Weight::from_ref_time(893_955 as u64) - // Standard Error: 238 - .saturating_add(Weight::from_ref_time(731_619 as u64).saturating_mul(r as u64)) + // Minimum execution time: 636 nanoseconds. + Weight::from_ref_time(906_526) + // Standard Error: 246 + .saturating_add(Weight::from_ref_time(730_299).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // Minimum execution time: 661 nanoseconds. - Weight::from_ref_time(904_145 as u64) - // Standard Error: 210 - .saturating_add(Weight::from_ref_time(730_497 as u64).saturating_mul(r as u64)) + // Minimum execution time: 659 nanoseconds. + Weight::from_ref_time(947_772) + // Standard Error: 312 + .saturating_add(Weight::from_ref_time(729_463).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // Minimum execution time: 670 nanoseconds. - Weight::from_ref_time(910_832 as u64) - // Standard Error: 248 - .saturating_add(Weight::from_ref_time(738_960 as u64).saturating_mul(r as u64)) + // Minimum execution time: 646 nanoseconds. + Weight::from_ref_time(923_694) + // Standard Error: 243 + .saturating_add(Weight::from_ref_time(738_995).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // Minimum execution time: 600 nanoseconds. - Weight::from_ref_time(910_816 as u64) - // Standard Error: 257 - .saturating_add(Weight::from_ref_time(742_585 as u64).saturating_mul(r as u64)) + // Minimum execution time: 652 nanoseconds. + Weight::from_ref_time(955_453) + // Standard Error: 1_430 + .saturating_add(Weight::from_ref_time(741_624).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // Minimum execution time: 697 nanoseconds. - Weight::from_ref_time(937_672 as u64) - // Standard Error: 291 - .saturating_add(Weight::from_ref_time(746_511 as u64).saturating_mul(r as u64)) + // Minimum execution time: 642 nanoseconds. + Weight::from_ref_time(900_107) + // Standard Error: 376 + .saturating_add(Weight::from_ref_time(740_016).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // Minimum execution time: 651 nanoseconds. - Weight::from_ref_time(920_151 as u64) - // Standard Error: 185 - .saturating_add(Weight::from_ref_time(743_483 as u64).saturating_mul(r as u64)) + // Minimum execution time: 625 nanoseconds. + Weight::from_ref_time(946_744) + // Standard Error: 252 + .saturating_add(Weight::from_ref_time(743_532).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // Minimum execution time: 622 nanoseconds. - Weight::from_ref_time(914_571 as u64) - // Standard Error: 264 - .saturating_add(Weight::from_ref_time(733_935 as u64).saturating_mul(r as u64)) + // Minimum execution time: 652 nanoseconds. + Weight::from_ref_time(918_551) + // Standard Error: 313 + .saturating_add(Weight::from_ref_time(731_451).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // Minimum execution time: 653 nanoseconds. - Weight::from_ref_time(914_243 as u64) - // Standard Error: 199 - .saturating_add(Weight::from_ref_time(738_786 as u64).saturating_mul(r as u64)) + // Minimum execution time: 651 nanoseconds. + Weight::from_ref_time(923_475) + // Standard Error: 341 + .saturating_add(Weight::from_ref_time(738_353).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - // Minimum execution time: 625 nanoseconds. - Weight::from_ref_time(1_144_724 as u64) - // Standard Error: 1_367 - .saturating_add(Weight::from_ref_time(729_921 as u64).saturating_mul(r as u64)) + // Minimum execution time: 666 nanoseconds. + Weight::from_ref_time(1_136_987) + // Standard Error: 1_482 + .saturating_add(Weight::from_ref_time(727_254).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // Minimum execution time: 643 nanoseconds. - Weight::from_ref_time(897_337 as u64) - // Standard Error: 162 - .saturating_add(Weight::from_ref_time(738_471 as u64).saturating_mul(r as u64)) + // Minimum execution time: 633 nanoseconds. + Weight::from_ref_time(934_201) + // Standard Error: 332 + .saturating_add(Weight::from_ref_time(731_804).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // Minimum execution time: 672 nanoseconds. - Weight::from_ref_time(921_395 as u64) - // Standard Error: 465 - .saturating_add(Weight::from_ref_time(719_508 as u64).saturating_mul(r as u64)) + // Minimum execution time: 673 nanoseconds. + Weight::from_ref_time(983_317) + // Standard Error: 492 + .saturating_add(Weight::from_ref_time(718_126).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // Minimum execution time: 672 nanoseconds. - Weight::from_ref_time(889_319 as u64) - // Standard Error: 392 - .saturating_add(Weight::from_ref_time(714_186 as u64).saturating_mul(r as u64)) + // Minimum execution time: 647 nanoseconds. + Weight::from_ref_time(925_490) + // Standard Error: 1_799 + .saturating_add(Weight::from_ref_time(711_178).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // Minimum execution time: 660 nanoseconds. - Weight::from_ref_time(898_856 as u64) - // Standard Error: 189 - .saturating_add(Weight::from_ref_time(714_302 as u64).saturating_mul(r as u64)) + // Minimum execution time: 652 nanoseconds. + Weight::from_ref_time(955_546) + // Standard Error: 283 + .saturating_add(Weight::from_ref_time(710_844).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // Minimum execution time: 629 nanoseconds. - Weight::from_ref_time(902_499 as u64) - // Standard Error: 428 - .saturating_add(Weight::from_ref_time(1_346_772 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(982_314) + // Standard Error: 267 + .saturating_add(Weight::from_ref_time(1_344_080).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // Minimum execution time: 624 nanoseconds. - Weight::from_ref_time(944_381 as u64) - // Standard Error: 389 - .saturating_add(Weight::from_ref_time(1_281_605 as u64).saturating_mul(r as u64)) + // Minimum execution time: 637 nanoseconds. + Weight::from_ref_time(913_421) + // Standard Error: 737 + .saturating_add(Weight::from_ref_time(1_285_749).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // Minimum execution time: 667 nanoseconds. - Weight::from_ref_time(876_301 as u64) - // Standard Error: 589 - .saturating_add(Weight::from_ref_time(1_397_964 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(939_041) + // Standard Error: 354 + .saturating_add(Weight::from_ref_time(1_391_470).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // Minimum execution time: 611 nanoseconds. - Weight::from_ref_time(865_466 as u64) - // Standard Error: 253 - .saturating_add(Weight::from_ref_time(1_283_803 as u64).saturating_mul(r as u64)) + // Minimum execution time: 656 nanoseconds. + Weight::from_ref_time(951_030) + // Standard Error: 342 + .saturating_add(Weight::from_ref_time(1_287_904).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // Minimum execution time: 653 nanoseconds. - Weight::from_ref_time(882_010 as u64) - // Standard Error: 205 - .saturating_add(Weight::from_ref_time(731_251 as u64).saturating_mul(r as u64)) + // Minimum execution time: 682 nanoseconds. + Weight::from_ref_time(940_975) + // Standard Error: 195 + .saturating_add(Weight::from_ref_time(717_132).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // Minimum execution time: 638 nanoseconds. - Weight::from_ref_time(917_858 as u64) - // Standard Error: 249 - .saturating_add(Weight::from_ref_time(795_023 as u64).saturating_mul(r as u64)) + // Minimum execution time: 704 nanoseconds. + Weight::from_ref_time(941_860) + // Standard Error: 200 + .saturating_add(Weight::from_ref_time(717_696).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // Minimum execution time: 636 nanoseconds. - Weight::from_ref_time(892_650 as u64) - // Standard Error: 252 - .saturating_add(Weight::from_ref_time(729_337 as u64).saturating_mul(r as u64)) + // Minimum execution time: 648 nanoseconds. + Weight::from_ref_time(917_135) + // Standard Error: 237 + .saturating_add(Weight::from_ref_time(717_979).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // Minimum execution time: 648 nanoseconds. - Weight::from_ref_time(918_889 as u64) - // Standard Error: 1_079 - .saturating_add(Weight::from_ref_time(746_835 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(1_031_822) + // Standard Error: 937 + .saturating_add(Weight::from_ref_time(730_965).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // Minimum execution time: 677 nanoseconds. - Weight::from_ref_time(931_684 as u64) - // Standard Error: 259 - .saturating_add(Weight::from_ref_time(734_540 as u64).saturating_mul(r as u64)) + // Minimum execution time: 671 nanoseconds. + Weight::from_ref_time(935_833) + // Standard Error: 184 + .saturating_add(Weight::from_ref_time(732_227).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // Minimum execution time: 635 nanoseconds. - Weight::from_ref_time(914_996 as u64) - // Standard Error: 611 - .saturating_add(Weight::from_ref_time(735_020 as u64).saturating_mul(r as u64)) + // Minimum execution time: 637 nanoseconds. + Weight::from_ref_time(962_491) + // Standard Error: 488 + .saturating_add(Weight::from_ref_time(733_218).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // Minimum execution time: 663 nanoseconds. - Weight::from_ref_time(914_333 as u64) - // Standard Error: 169 - .saturating_add(Weight::from_ref_time(734_033 as u64).saturating_mul(r as u64)) + // Minimum execution time: 643 nanoseconds. + Weight::from_ref_time(951_949) + // Standard Error: 321 + .saturating_add(Weight::from_ref_time(732_212).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // Minimum execution time: 631 nanoseconds. - Weight::from_ref_time(916_503 as u64) - // Standard Error: 224 - .saturating_add(Weight::from_ref_time(736_168 as u64).saturating_mul(r as u64)) + // Minimum execution time: 665 nanoseconds. + Weight::from_ref_time(951_447) + // Standard Error: 346 + .saturating_add(Weight::from_ref_time(732_549).saturating_mul(r.into())) } } @@ -1414,41 +1424,41 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - // Minimum execution time: 3_174 nanoseconds. - Weight::from_ref_time(3_298_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) + // Minimum execution time: 3_148 nanoseconds. + Weight::from_ref_time(3_326_000) + .saturating_add(RocksDbWeight::get().reads(1)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - // Minimum execution time: 15_218 nanoseconds. - Weight::from_ref_time(15_548_154 as u64) - // Standard Error: 732 - .saturating_add(Weight::from_ref_time(940_242 as u64).saturating_mul(k as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) + // Minimum execution time: 15_318 nanoseconds. + Weight::from_ref_time(14_905_070) + // Standard Error: 1_055 + .saturating_add(Weight::from_ref_time(941_176).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) } // Storage: Contracts DeletionQueue (r:1 w:0) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - // Minimum execution time: 3_096 nanoseconds. - Weight::from_ref_time(14_949_039 as u64) - // Standard Error: 3_466 - .saturating_add(Weight::from_ref_time(1_236_160 as u64).saturating_mul(q as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 3_182 nanoseconds. + Weight::from_ref_time(14_837_078) + // Standard Error: 3_423 + .saturating_add(Weight::from_ref_time(1_203_909).saturating_mul(q.into())) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Contracts PristineCode (r:1 w:0) // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - // Minimum execution time: 28_333 nanoseconds. - Weight::from_ref_time(19_421_544 as u64) - // Standard Error: 92 - .saturating_add(Weight::from_ref_time(47_629 as u64).saturating_mul(c as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 34_272 nanoseconds. + Weight::from_ref_time(33_159_915) + // Standard Error: 60 + .saturating_add(Weight::from_ref_time(46_967).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) @@ -1457,12 +1467,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - // Minimum execution time: 304_381 nanoseconds. - Weight::from_ref_time(315_177_233 as u64) - // Standard Error: 22 - .saturating_add(Weight::from_ref_time(30_372 as u64).saturating_mul(c as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 395_141 nanoseconds. + Weight::from_ref_time(413_672_628) + // Standard Error: 25 + .saturating_add(Weight::from_ref_time(30_570).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -1475,14 +1485,14 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - // Minimum execution time: 2_119_963 nanoseconds. - Weight::from_ref_time(337_976_516 as u64) - // Standard Error: 84 - .saturating_add(Weight::from_ref_time(88_566 as u64).saturating_mul(c as u64)) - // Standard Error: 5 - .saturating_add(Weight::from_ref_time(1_747 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) - .saturating_add(RocksDbWeight::get().writes(9 as u64)) + // Minimum execution time: 2_259_439 nanoseconds. + Weight::from_ref_time(407_506_250) + // Standard Error: 79 + .saturating_add(Weight::from_ref_time(89_557).saturating_mul(c.into())) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(1_804).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().writes(9)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -1493,12 +1503,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - // Minimum execution time: 184_739 nanoseconds. - Weight::from_ref_time(179_778_057 as u64) - // Standard Error: 2 - .saturating_add(Weight::from_ref_time(1_487 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) - .saturating_add(RocksDbWeight::get().writes(7 as u64)) + // Minimum execution time: 185_950 nanoseconds. + Weight::from_ref_time(173_152_122) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(1_559).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().writes(7)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) @@ -1506,10 +1516,10 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - // Minimum execution time: 154_711 nanoseconds. - Weight::from_ref_time(155_527_000 as u64) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 154_738 nanoseconds. + Weight::from_ref_time(159_212_000) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: System EventTopics (r:1 w:1) @@ -1517,31 +1527,31 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - // Minimum execution time: 294_982 nanoseconds. - Weight::from_ref_time(302_482_450 as u64) - // Standard Error: 62 - .saturating_add(Weight::from_ref_time(88_358 as u64).saturating_mul(c as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 392_302 nanoseconds. + Weight::from_ref_time(402_889_681) + // Standard Error: 84 + .saturating_add(Weight::from_ref_time(89_393).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Contracts OwnerInfoOf (r:1 w:1) // Storage: System EventTopics (r:1 w:1) // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - // Minimum execution time: 39_655 nanoseconds. - Weight::from_ref_time(40_147_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 39_892 nanoseconds. + Weight::from_ref_time(40_258_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - // Minimum execution time: 41_028 nanoseconds. - Weight::from_ref_time(41_565_000 as u64) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + // Minimum execution time: 41_441 nanoseconds. + Weight::from_ref_time(42_011_000) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1550,12 +1560,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - // Minimum execution time: 294_231 nanoseconds. - Weight::from_ref_time(298_245_008 as u64) - // Standard Error: 41_817 - .saturating_add(Weight::from_ref_time(16_183_097 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_919 nanoseconds. + Weight::from_ref_time(387_844_956) + // Standard Error: 38_460 + .saturating_add(Weight::from_ref_time(16_014_536).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1564,13 +1574,13 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - // Minimum execution time: 293_152 nanoseconds. - Weight::from_ref_time(231_239_439 as u64) - // Standard Error: 475_771 - .saturating_add(Weight::from_ref_time(193_804_587 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 384_047 nanoseconds. + Weight::from_ref_time(316_828_665) + // Standard Error: 571_260 + .saturating_add(Weight::from_ref_time(197_635_022).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1579,13 +1589,13 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 296_171 nanoseconds. - Weight::from_ref_time(244_339_298 as u64) - // Standard Error: 440_060 - .saturating_add(Weight::from_ref_time(236_224_857 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 385_259 nanoseconds. + Weight::from_ref_time(338_849_650) + // Standard Error: 447_004 + .saturating_add(Weight::from_ref_time(235_734_380).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1594,12 +1604,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 294_891 nanoseconds. - Weight::from_ref_time(298_061_159 as u64) - // Standard Error: 30_013 - .saturating_add(Weight::from_ref_time(19_682_309 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 385_528 nanoseconds. + Weight::from_ref_time(388_332_749) + // Standard Error: 43_017 + .saturating_add(Weight::from_ref_time(20_406_602).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1608,12 +1618,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - // Minimum execution time: 293_259 nanoseconds. - Weight::from_ref_time(296_675_355 as u64) - // Standard Error: 24_508 - .saturating_add(Weight::from_ref_time(10_949_451 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 382_243 nanoseconds. + Weight::from_ref_time(387_692_764) + // Standard Error: 32_726 + .saturating_add(Weight::from_ref_time(10_753_573).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1622,12 +1632,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - // Minimum execution time: 293_507 nanoseconds. - Weight::from_ref_time(295_682_709 as u64) - // Standard Error: 43_685 - .saturating_add(Weight::from_ref_time(16_461_873 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_993 nanoseconds. + Weight::from_ref_time(389_189_394) + // Standard Error: 55_885 + .saturating_add(Weight::from_ref_time(15_943_739).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1636,12 +1646,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - // Minimum execution time: 293_473 nanoseconds. - Weight::from_ref_time(296_523_274 as u64) - // Standard Error: 34_356 - .saturating_add(Weight::from_ref_time(15_932_835 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_057 nanoseconds. + Weight::from_ref_time(387_466_678) + // Standard Error: 38_570 + .saturating_add(Weight::from_ref_time(15_739_675).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1650,12 +1660,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - // Minimum execution time: 293_889 nanoseconds. - Weight::from_ref_time(295_471_068 as u64) - // Standard Error: 88_937 - .saturating_add(Weight::from_ref_time(89_606_655 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_688 nanoseconds. + Weight::from_ref_time(394_708_428) + // Standard Error: 101_035 + .saturating_add(Weight::from_ref_time(89_822_613).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1664,12 +1674,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - // Minimum execution time: 293_747 nanoseconds. - Weight::from_ref_time(297_023_967 as u64) - // Standard Error: 18_756 - .saturating_add(Weight::from_ref_time(15_748_008 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_511 nanoseconds. + Weight::from_ref_time(387_270_075) + // Standard Error: 33_383 + .saturating_add(Weight::from_ref_time(15_672_963).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1678,12 +1688,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - // Minimum execution time: 293_590 nanoseconds. - Weight::from_ref_time(296_257_202 as u64) - // Standard Error: 24_863 - .saturating_add(Weight::from_ref_time(15_851_537 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_483 nanoseconds. + Weight::from_ref_time(386_995_457) + // Standard Error: 28_781 + .saturating_add(Weight::from_ref_time(15_632_597).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1692,12 +1702,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - // Minimum execution time: 293_746 nanoseconds. - Weight::from_ref_time(297_308_097 as u64) - // Standard Error: 29_585 - .saturating_add(Weight::from_ref_time(15_608_985 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_630 nanoseconds. + Weight::from_ref_time(387_801_190) + // Standard Error: 41_234 + .saturating_add(Weight::from_ref_time(15_531_236).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1706,12 +1716,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - // Minimum execution time: 293_662 nanoseconds. - Weight::from_ref_time(296_393_072 as u64) - // Standard Error: 23_750 - .saturating_add(Weight::from_ref_time(15_891_911 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_668 nanoseconds. + Weight::from_ref_time(387_490_160) + // Standard Error: 28_070 + .saturating_add(Weight::from_ref_time(15_639_764).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1721,12 +1731,12 @@ impl WeightInfo for () { // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - // Minimum execution time: 294_036 nanoseconds. - Weight::from_ref_time(301_071_620 as u64) - // Standard Error: 85_146 - .saturating_add(Weight::from_ref_time(84_455_768 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_401 nanoseconds. + Weight::from_ref_time(393_140_360) + // Standard Error: 95_092 + .saturating_add(Weight::from_ref_time(83_864_160).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1735,12 +1745,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - // Minimum execution time: 142_655 nanoseconds. - Weight::from_ref_time(145_691_226 as u64) - // Standard Error: 11_085 - .saturating_add(Weight::from_ref_time(7_953_680 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 142_684 nanoseconds. + Weight::from_ref_time(145_540_019) + // Standard Error: 18_177 + .saturating_add(Weight::from_ref_time(8_061_360).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1749,12 +1759,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - // Minimum execution time: 293_613 nanoseconds. - Weight::from_ref_time(296_889_714 as u64) - // Standard Error: 21_550 - .saturating_add(Weight::from_ref_time(13_672_097 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_472 nanoseconds. + Weight::from_ref_time(386_518_915) + // Standard Error: 46_174 + .saturating_add(Weight::from_ref_time(14_052_552).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1763,12 +1773,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 309_866 nanoseconds. - Weight::from_ref_time(328_331_386 as u64) - // Standard Error: 6_205 - .saturating_add(Weight::from_ref_time(9_619_067 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 398_912 nanoseconds. + Weight::from_ref_time(426_793_015) + // Standard Error: 5_524 + .saturating_add(Weight::from_ref_time(9_645_931).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1777,12 +1787,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - // Minimum execution time: 288_265 nanoseconds. - Weight::from_ref_time(292_739_779 as u64) - // Standard Error: 108_313 - .saturating_add(Weight::from_ref_time(1_475_820 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 380_288 nanoseconds. + Weight::from_ref_time(382_064_302) + // Standard Error: 274_854 + .saturating_add(Weight::from_ref_time(5_341_497).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1791,12 +1801,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 293_044 nanoseconds. - Weight::from_ref_time(293_846_263 as u64) - // Standard Error: 641 - .saturating_add(Weight::from_ref_time(188_770 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 382_104 nanoseconds. + Weight::from_ref_time(383_966_376) + // Standard Error: 668 + .saturating_add(Weight::from_ref_time(230_898).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1807,14 +1817,14 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - // Minimum execution time: 289_248 nanoseconds. - Weight::from_ref_time(294_406_912 as u64) - // Standard Error: 112_528 - .saturating_add(Weight::from_ref_time(52_650_987 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((6 as u64).saturating_mul(r as u64))) + // Minimum execution time: 382_423 nanoseconds. + Weight::from_ref_time(384_162_748) + // Standard Error: 403_637 + .saturating_add(Weight::from_ref_time(57_465_451).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(r.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1824,12 +1834,12 @@ impl WeightInfo for () { // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - // Minimum execution time: 292_980 nanoseconds. - Weight::from_ref_time(298_232_040 as u64) - // Standard Error: 85_517 - .saturating_add(Weight::from_ref_time(108_891_823 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 382_853 nanoseconds. + Weight::from_ref_time(391_962_017) + // Standard Error: 102_169 + .saturating_add(Weight::from_ref_time(108_325_188).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1838,12 +1848,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - // Minimum execution time: 291_668 nanoseconds. - Weight::from_ref_time(302_010_570 as u64) - // Standard Error: 109_901 - .saturating_add(Weight::from_ref_time(214_667_762 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 380_999 nanoseconds. + Weight::from_ref_time(392_336_632) + // Standard Error: 168_846 + .saturating_add(Weight::from_ref_time(218_950_403).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1853,16 +1863,16 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - // Minimum execution time: 1_163_533 nanoseconds. - Weight::from_ref_time(501_280_410 as u64) - // Standard Error: 601_576 - .saturating_add(Weight::from_ref_time(172_210_846 as u64).saturating_mul(t as u64)) - // Standard Error: 165_221 - .saturating_add(Weight::from_ref_time(67_584_003 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(t as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(t as u64))) + // Minimum execution time: 1_276_841 nanoseconds. + Weight::from_ref_time(587_558_952) + // Standard Error: 504_583 + .saturating_add(Weight::from_ref_time(178_141_140).saturating_mul(t.into())) + // Standard Error: 138_583 + .saturating_add(Weight::from_ref_time(71_194_319).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(t.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(t.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -1871,140 +1881,140 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - // Minimum execution time: 154_390 nanoseconds. - Weight::from_ref_time(158_246_775 as u64) - // Standard Error: 23_812 - .saturating_add(Weight::from_ref_time(12_810_293 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 161_230 nanoseconds. + Weight::from_ref_time(168_508_241) + // Standard Error: 31_112 + .saturating_add(Weight::from_ref_time(12_496_531).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - // Minimum execution time: 292_926 nanoseconds. - Weight::from_ref_time(250_238_246 as u64) - // Standard Error: 485_292 - .saturating_add(Weight::from_ref_time(402_779_709 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Minimum execution time: 383_055 nanoseconds. + Weight::from_ref_time(339_358_786) + // Standard Error: 486_941 + .saturating_add(Weight::from_ref_time(412_066_056).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - // Minimum execution time: 421_504 nanoseconds. - Weight::from_ref_time(574_267_945 as u64) - // Standard Error: 1_407_019 - .saturating_add(Weight::from_ref_time(89_516_682 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(52 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(50 as u64)) - .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + // Minimum execution time: 512_301 nanoseconds. + Weight::from_ref_time(670_220_816) + // Standard Error: 1_460_983 + .saturating_add(Weight::from_ref_time(97_308_816).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(52)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(50)) + .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - // Minimum execution time: 421_422 nanoseconds. - Weight::from_ref_time(545_948_271 as u64) - // Standard Error: 1_148_143 - .saturating_add(Weight::from_ref_time(63_958_096 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(51 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(49 as u64)) - .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + // Minimum execution time: 510_820 nanoseconds. + Weight::from_ref_time(638_537_372) + // Standard Error: 1_195_632 + .saturating_add(Weight::from_ref_time(65_979_491).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(51)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(49)) + .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - // Minimum execution time: 293_545 nanoseconds. - Weight::from_ref_time(255_622_312 as u64) - // Standard Error: 407_862 - .saturating_add(Weight::from_ref_time(396_764_962 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Minimum execution time: 383_596 nanoseconds. + Weight::from_ref_time(341_575_167) + // Standard Error: 478_894 + .saturating_add(Weight::from_ref_time(407_044_103).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 390_339 nanoseconds. - Weight::from_ref_time(528_774_888 as u64) - // Standard Error: 1_278_188 - .saturating_add(Weight::from_ref_time(66_683_698 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(51 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(48 as u64)) - .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + // Minimum execution time: 481_757 nanoseconds. + Weight::from_ref_time(628_126_550) + // Standard Error: 1_363_017 + .saturating_add(Weight::from_ref_time(67_242_851).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(51)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(48)) + .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - // Minimum execution time: 294_904 nanoseconds. - Weight::from_ref_time(265_679_354 as u64) - // Standard Error: 386_673 - .saturating_add(Weight::from_ref_time(318_869_116 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_868 nanoseconds. + Weight::from_ref_time(359_800_153) + // Standard Error: 338_998 + .saturating_add(Weight::from_ref_time(323_351_220).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 372_784 nanoseconds. - Weight::from_ref_time(487_784_160 as u64) - // Standard Error: 1_092_850 - .saturating_add(Weight::from_ref_time(152_413_290 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(51 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 462_237 nanoseconds. + Weight::from_ref_time(585_809_405) + // Standard Error: 1_181_517 + .saturating_add(Weight::from_ref_time(160_905_409).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(51)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - // Minimum execution time: 301_191 nanoseconds. - Weight::from_ref_time(270_493_545 as u64) - // Standard Error: 373_565 - .saturating_add(Weight::from_ref_time(302_870_977 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_794 nanoseconds. + Weight::from_ref_time(355_233_888) + // Standard Error: 416_492 + .saturating_add(Weight::from_ref_time(317_857_887).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 368_641 nanoseconds. - Weight::from_ref_time(469_340_170 as u64) - // Standard Error: 966_589 - .saturating_add(Weight::from_ref_time(62_000_083 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(51 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 462_530 nanoseconds. + Weight::from_ref_time(571_276_165) + // Standard Error: 1_035_339 + .saturating_add(Weight::from_ref_time(63_481_618).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(51)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - // Minimum execution time: 294_717 nanoseconds. - Weight::from_ref_time(254_308_806 as u64) - // Standard Error: 443_802 - .saturating_add(Weight::from_ref_time(408_899_238 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Minimum execution time: 385_343 nanoseconds. + Weight::from_ref_time(341_897_876) + // Standard Error: 451_948 + .saturating_add(Weight::from_ref_time(417_987_655).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 396_211 nanoseconds. - Weight::from_ref_time(545_169_999 as u64) - // Standard Error: 1_390_049 - .saturating_add(Weight::from_ref_time(156_931_202 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(51 as u64)) - .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(48 as u64)) - .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) + // Minimum execution time: 485_507 nanoseconds. + Weight::from_ref_time(646_265_325) + // Standard Error: 1_495_172 + .saturating_add(Weight::from_ref_time(166_973_554).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(51)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(48)) + .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2013,14 +2023,14 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - // Minimum execution time: 295_145 nanoseconds. - Weight::from_ref_time(241_332_033 as u64) - // Standard Error: 658_837 - .saturating_add(Weight::from_ref_time(1_315_958_335 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Minimum execution time: 384_834 nanoseconds. + Weight::from_ref_time(348_341_375) + // Standard Error: 792_708 + .saturating_add(Weight::from_ref_time(1_336_691_822).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7)) + .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(4)) + .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2029,14 +2039,14 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - // Minimum execution time: 295_624 nanoseconds. - Weight::from_ref_time(296_567_000 as u64) - // Standard Error: 6_725_484 - .saturating_add(Weight::from_ref_time(20_773_662_959 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(7 as u64)) - .saturating_add(RocksDbWeight::get().reads((160 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((160 as u64).saturating_mul(r as u64))) + // Minimum execution time: 386_112 nanoseconds. + Weight::from_ref_time(386_971_000) + // Standard Error: 5_920_386 + .saturating_add(Weight::from_ref_time(28_051_657_660).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7)) + .saturating_add(RocksDbWeight::get().reads((160_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((160_u64).saturating_mul(r.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2045,14 +2055,14 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - // Minimum execution time: 296_698 nanoseconds. - Weight::from_ref_time(297_541_000 as u64) - // Standard Error: 18_681_855 - .saturating_add(Weight::from_ref_time(20_702_951_248 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((150 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((75 as u64).saturating_mul(r as u64))) + // Minimum execution time: 385_776 nanoseconds. + Weight::from_ref_time(387_017_000) + // Standard Error: 6_680_801 + .saturating_add(Weight::from_ref_time(27_761_537_154).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((150_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((75_u64).saturating_mul(r.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -2062,16 +2072,16 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - // Minimum execution time: 9_491_225 nanoseconds. - Weight::from_ref_time(8_726_446_640 as u64) - // Standard Error: 11_723_053 - .saturating_add(Weight::from_ref_time(1_107_970_775 as u64).saturating_mul(t as u64)) - // Standard Error: 17_578 - .saturating_add(Weight::from_ref_time(9_748_009 as u64).saturating_mul(c as u64)) - .saturating_add(RocksDbWeight::get().reads(167 as u64)) - .saturating_add(RocksDbWeight::get().reads((81 as u64).saturating_mul(t as u64))) - .saturating_add(RocksDbWeight::get().writes(163 as u64)) - .saturating_add(RocksDbWeight::get().writes((81 as u64).saturating_mul(t as u64))) + // Minimum execution time: 9_623_952 nanoseconds. + Weight::from_ref_time(8_552_923_566) + // Standard Error: 6_582_866 + .saturating_add(Weight::from_ref_time(1_283_786_003).saturating_mul(t.into())) + // Standard Error: 9_870 + .saturating_add(Weight::from_ref_time(9_833_844).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(167)) + .saturating_add(RocksDbWeight::get().reads((81_u64).saturating_mul(t.into()))) + .saturating_add(RocksDbWeight::get().writes(163)) + .saturating_add(RocksDbWeight::get().writes((81_u64).saturating_mul(t.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2082,14 +2092,14 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - // Minimum execution time: 294_351 nanoseconds. - Weight::from_ref_time(297_837_000 as u64) - // Standard Error: 17_115_732 - .saturating_add(Weight::from_ref_time(25_936_348_025 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) - .saturating_add(RocksDbWeight::get().reads((400 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) - .saturating_add(RocksDbWeight::get().writes((400 as u64).saturating_mul(r as u64))) + // Minimum execution time: 386_667 nanoseconds. + Weight::from_ref_time(387_559_000) + // Standard Error: 18_953_118 + .saturating_add(Weight::from_ref_time(33_188_342_429).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().reads((400_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(5)) + .saturating_add(RocksDbWeight::get().writes((400_u64).saturating_mul(r.into()))) } // Storage: System Account (r:81 w:81) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -2101,14 +2111,16 @@ impl WeightInfo for () { /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - // Minimum execution time: 11_367_191 nanoseconds. - Weight::from_ref_time(11_186_726_411 as u64) - // Standard Error: 75_273 - .saturating_add(Weight::from_ref_time(122_421_705 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(249 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(t as u64))) - .saturating_add(RocksDbWeight::get().writes(247 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(t as u64))) + // Minimum execution time: 11_664_478 nanoseconds. + Weight::from_ref_time(11_359_540_086) + // Standard Error: 45_626_277 + .saturating_add(Weight::from_ref_time(19_120_579).saturating_mul(t.into())) + // Standard Error: 72_976 + .saturating_add(Weight::from_ref_time(125_731_953).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(249)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) + .saturating_add(RocksDbWeight::get().writes(247)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2117,12 +2129,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - // Minimum execution time: 293_753 nanoseconds. - Weight::from_ref_time(295_491_471 as u64) - // Standard Error: 112_217 - .saturating_add(Weight::from_ref_time(41_976_228 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 384_826 nanoseconds. + Weight::from_ref_time(387_293_630) + // Standard Error: 437_875 + .saturating_add(Weight::from_ref_time(48_464_369).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2131,12 +2143,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 335_784 nanoseconds. - Weight::from_ref_time(336_406_000 as u64) - // Standard Error: 58_205 - .saturating_add(Weight::from_ref_time(323_644_833 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 426_531 nanoseconds. + Weight::from_ref_time(427_315_000) + // Standard Error: 48_058 + .saturating_add(Weight::from_ref_time(327_318_884).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2145,12 +2157,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - // Minimum execution time: 292_772 nanoseconds. - Weight::from_ref_time(294_845_565 as u64) - // Standard Error: 118_932 - .saturating_add(Weight::from_ref_time(53_186_034 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 384_084 nanoseconds. + Weight::from_ref_time(386_354_628) + // Standard Error: 195_951 + .saturating_add(Weight::from_ref_time(52_991_271).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2159,12 +2171,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 348_057 nanoseconds. - Weight::from_ref_time(354_903_000 as u64) - // Standard Error: 63_036 - .saturating_add(Weight::from_ref_time(247_852_636 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 438_319 nanoseconds. + Weight::from_ref_time(439_001_000) + // Standard Error: 53_445 + .saturating_add(Weight::from_ref_time(251_353_803).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2173,12 +2185,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - // Minimum execution time: 290_417 nanoseconds. - Weight::from_ref_time(295_285_706 as u64) - // Standard Error: 124_630 - .saturating_add(Weight::from_ref_time(31_293_293 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 384_397 nanoseconds. + Weight::from_ref_time(386_532_859) + // Standard Error: 141_195 + .saturating_add(Weight::from_ref_time(31_116_440).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2187,12 +2199,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 325_903 nanoseconds. - Weight::from_ref_time(326_482_000 as u64) - // Standard Error: 47_465 - .saturating_add(Weight::from_ref_time(99_615_769 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 416_504 nanoseconds. + Weight::from_ref_time(417_686_000) + // Standard Error: 47_003 + .saturating_add(Weight::from_ref_time(103_095_636).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2201,12 +2213,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - // Minimum execution time: 291_624 nanoseconds. - Weight::from_ref_time(295_781_938 as u64) - // Standard Error: 849_772 - .saturating_add(Weight::from_ref_time(30_869_061 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 382_479 nanoseconds. + Weight::from_ref_time(384_623_057) + // Standard Error: 243_054 + .saturating_add(Weight::from_ref_time(37_025_542).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2215,12 +2227,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 323_456 nanoseconds. - Weight::from_ref_time(324_815_000 as u64) - // Standard Error: 49_126 - .saturating_add(Weight::from_ref_time(99_651_878 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 414_863 nanoseconds. + Weight::from_ref_time(415_728_000) + // Standard Error: 48_764 + .saturating_add(Weight::from_ref_time(103_050_672).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2229,12 +2241,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - // Minimum execution time: 294_244 nanoseconds. - Weight::from_ref_time(296_117_277 as u64) - // Standard Error: 513_100 - .saturating_add(Weight::from_ref_time(3_005_168_422 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 384_418 nanoseconds. + Weight::from_ref_time(387_283_069) + // Standard Error: 526_301 + .saturating_add(Weight::from_ref_time(2_993_987_030).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2243,12 +2255,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - // Minimum execution time: 293_099 nanoseconds. - Weight::from_ref_time(295_349_591 as u64) - // Standard Error: 437_688 - .saturating_add(Weight::from_ref_time(2_079_472_608 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 383_686 nanoseconds. + Weight::from_ref_time(385_812_638) + // Standard Error: 539_029 + .saturating_add(Weight::from_ref_time(2_098_063_561).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2258,14 +2270,14 @@ impl WeightInfo for () { // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 293_692 nanoseconds. - Weight::from_ref_time(294_871_000 as u64) - // Standard Error: 2_737_018 - .saturating_add(Weight::from_ref_time(1_360_098_499 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((225 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((150 as u64).saturating_mul(r as u64))) + // Minimum execution time: 384_399 nanoseconds. + Weight::from_ref_time(385_337_000) + // Standard Error: 2_827_655 + .saturating_add(Weight::from_ref_time(1_383_659_432).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((225_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((150_u64).saturating_mul(r.into()))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2274,12 +2286,12 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_reentrance_count(r: u32, ) -> Weight { - // Minimum execution time: 295_570 nanoseconds. - Weight::from_ref_time(299_077_520 as u64) - // Standard Error: 23_516 - .saturating_add(Weight::from_ref_time(10_971_589 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 385_165 nanoseconds. + Weight::from_ref_time(389_255_026) + // Standard Error: 25_918 + .saturating_add(Weight::from_ref_time(10_716_905).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) @@ -2288,368 +2300,375 @@ impl WeightInfo for () { // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { - // Minimum execution time: 296_873 nanoseconds. - Weight::from_ref_time(336_309_706 as u64) - // Standard Error: 125_484 - .saturating_add(Weight::from_ref_time(25_321_948 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 386_959 nanoseconds. + Weight::from_ref_time(423_364_524) + // Standard Error: 127_096 + .saturating_add(Weight::from_ref_time(25_552_186).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(3)) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - // Minimum execution time: 686 nanoseconds. - Weight::from_ref_time(895_726 as u64) - // Standard Error: 144 - .saturating_add(Weight::from_ref_time(344_525 as u64).saturating_mul(r as u64)) + // Minimum execution time: 688 nanoseconds. + Weight::from_ref_time(914_830) + // Standard Error: 222 + .saturating_add(Weight::from_ref_time(343_835).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // Minimum execution time: 780 nanoseconds. - Weight::from_ref_time(590_334 as u64) - // Standard Error: 10_839 - .saturating_add(Weight::from_ref_time(1_038_503 as u64).saturating_mul(r as u64)) + // Minimum execution time: 775 nanoseconds. + Weight::from_ref_time(1_286_008) + // Standard Error: 391 + .saturating_add(Weight::from_ref_time(984_759).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // Minimum execution time: 755 nanoseconds. - Weight::from_ref_time(1_139_912 as u64) - // Standard Error: 466 - .saturating_add(Weight::from_ref_time(881_780 as u64).saturating_mul(r as u64)) + // Minimum execution time: 779 nanoseconds. + Weight::from_ref_time(1_162_588) + // Standard Error: 694 + .saturating_add(Weight::from_ref_time(883_828).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // Minimum execution time: 670 nanoseconds. - Weight::from_ref_time(941_845 as u64) - // Standard Error: 227 - .saturating_add(Weight::from_ref_time(956_897 as u64).saturating_mul(r as u64)) + // Minimum execution time: 687 nanoseconds. + Weight::from_ref_time(965_966) + // Standard Error: 290 + .saturating_add(Weight::from_ref_time(955_392).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // Minimum execution time: 676 nanoseconds. - Weight::from_ref_time(600_675 as u64) - // Standard Error: 555 - .saturating_add(Weight::from_ref_time(1_294_447 as u64).saturating_mul(r as u64)) + // Minimum execution time: 681 nanoseconds. + Weight::from_ref_time(778_970) + // Standard Error: 670 + .saturating_add(Weight::from_ref_time(1_265_116).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // Minimum execution time: 680 nanoseconds. - Weight::from_ref_time(1_192_340 as u64) - // Standard Error: 897 - .saturating_add(Weight::from_ref_time(524_835 as u64).saturating_mul(r as u64)) + // Minimum execution time: 673 nanoseconds. + Weight::from_ref_time(1_125_562) + // Standard Error: 818 + .saturating_add(Weight::from_ref_time(528_126).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // Minimum execution time: 653 nanoseconds. - Weight::from_ref_time(1_136_213 as u64) - // Standard Error: 1_137 - .saturating_add(Weight::from_ref_time(791_920 as u64).saturating_mul(r as u64)) + // Minimum execution time: 649 nanoseconds. + Weight::from_ref_time(780_802) + // Standard Error: 943 + .saturating_add(Weight::from_ref_time(800_988).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // Minimum execution time: 669 nanoseconds. - Weight::from_ref_time(491_588 as u64) - // Standard Error: 2_098 - .saturating_add(Weight::from_ref_time(1_078_017 as u64).saturating_mul(r as u64)) + // Minimum execution time: 662 nanoseconds. + Weight::from_ref_time(555_078) + // Standard Error: 1_540 + .saturating_add(Weight::from_ref_time(1_078_705).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - // Minimum execution time: 2_128 nanoseconds. - Weight::from_ref_time(2_565_932 as u64) - // Standard Error: 76 - .saturating_add(Weight::from_ref_time(4_830 as u64).saturating_mul(e as u64)) + // Minimum execution time: 2_177 nanoseconds. + Weight::from_ref_time(2_581_121) + // Standard Error: 67 + .saturating_add(Weight::from_ref_time(5_001).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // Minimum execution time: 665 nanoseconds. - Weight::from_ref_time(1_593_317 as u64) - // Standard Error: 2_288 - .saturating_add(Weight::from_ref_time(2_195_453 as u64).saturating_mul(r as u64)) + // Minimum execution time: 702 nanoseconds. + Weight::from_ref_time(1_570_695) + // Standard Error: 1_524 + .saturating_add(Weight::from_ref_time(2_192_040).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // Minimum execution time: 796 nanoseconds. - Weight::from_ref_time(1_816_603 as u64) - // Standard Error: 2_183 - .saturating_add(Weight::from_ref_time(2_808_821 as u64).saturating_mul(r as u64)) + // Minimum execution time: 745 nanoseconds. + Weight::from_ref_time(1_694_451) + // Standard Error: 4_170 + .saturating_add(Weight::from_ref_time(2_813_621).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - // Minimum execution time: 4_212 nanoseconds. - Weight::from_ref_time(5_097_891 as u64) - // Standard Error: 576 - .saturating_add(Weight::from_ref_time(180_948 as u64).saturating_mul(p as u64)) + // Minimum execution time: 4_255 nanoseconds. + Weight::from_ref_time(5_064_243) + // Standard Error: 289 + .saturating_add(Weight::from_ref_time(178_868).saturating_mul(p.into())) + } + /// The range of component `l` is `[0, 1024]`. + fn instr_call_per_local(l: u32, ) -> Weight { + // Minimum execution time: 2_802 nanoseconds. + Weight::from_ref_time(3_474_642) + // Standard Error: 28 + .saturating_add(Weight::from_ref_time(92_517).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // Minimum execution time: 1_412 nanoseconds. - Weight::from_ref_time(1_733_015 as u64) - // Standard Error: 215 - .saturating_add(Weight::from_ref_time(366_629 as u64).saturating_mul(r as u64)) + // Minimum execution time: 2_973 nanoseconds. + Weight::from_ref_time(3_218_977) + // Standard Error: 183 + .saturating_add(Weight::from_ref_time(364_688).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // Minimum execution time: 1_436 nanoseconds. - Weight::from_ref_time(1_772_333 as u64) - // Standard Error: 288 - .saturating_add(Weight::from_ref_time(380_886 as u64).saturating_mul(r as u64)) + // Minimum execution time: 2_912 nanoseconds. + Weight::from_ref_time(3_173_203) + // Standard Error: 260 + .saturating_add(Weight::from_ref_time(381_853).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // Minimum execution time: 1_408 nanoseconds. - Weight::from_ref_time(1_731_571 as u64) - // Standard Error: 334 - .saturating_add(Weight::from_ref_time(526_489 as u64).saturating_mul(r as u64)) + // Minimum execution time: 2_916 nanoseconds. + Weight::from_ref_time(3_228_548) + // Standard Error: 311 + .saturating_add(Weight::from_ref_time(526_008).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // Minimum execution time: 752 nanoseconds. - Weight::from_ref_time(1_118_170 as u64) - // Standard Error: 302 - .saturating_add(Weight::from_ref_time(809_371 as u64).saturating_mul(r as u64)) + // Minimum execution time: 739 nanoseconds. + Weight::from_ref_time(1_128_919) + // Standard Error: 479 + .saturating_add(Weight::from_ref_time(810_765).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // Minimum execution time: 770 nanoseconds. - Weight::from_ref_time(990_414 as u64) - // Standard Error: 331 - .saturating_add(Weight::from_ref_time(831_541 as u64).saturating_mul(r as u64)) + // Minimum execution time: 724 nanoseconds. + Weight::from_ref_time(1_044_382) + // Standard Error: 371 + .saturating_add(Weight::from_ref_time(828_530).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // Minimum execution time: 783 nanoseconds. - Weight::from_ref_time(992_847 as u64) - // Standard Error: 437 - .saturating_add(Weight::from_ref_time(695_374 as u64).saturating_mul(r as u64)) + // Minimum execution time: 770 nanoseconds. + Weight::from_ref_time(988_307) + // Standard Error: 587 + .saturating_add(Weight::from_ref_time(699_091).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // Minimum execution time: 664 nanoseconds. - Weight::from_ref_time(758_730 as u64) - // Standard Error: 5_030 - .saturating_add(Weight::from_ref_time(184_801_569 as u64).saturating_mul(r as u64)) + // Minimum execution time: 688 nanoseconds. + Weight::from_ref_time(747_995) + // Standard Error: 3_894 + .saturating_add(Weight::from_ref_time(234_512_504).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // Minimum execution time: 657 nanoseconds. - Weight::from_ref_time(941_928 as u64) - // Standard Error: 216 - .saturating_add(Weight::from_ref_time(506_159 as u64).saturating_mul(r as u64)) + // Minimum execution time: 643 nanoseconds. + Weight::from_ref_time(946_893) + // Standard Error: 188 + .saturating_add(Weight::from_ref_time(505_004).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - // Minimum execution time: 617 nanoseconds. - Weight::from_ref_time(1_009_437 as u64) - // Standard Error: 435 - .saturating_add(Weight::from_ref_time(512_427 as u64).saturating_mul(r as u64)) + // Minimum execution time: 663 nanoseconds. + Weight::from_ref_time(965_194) + // Standard Error: 343 + .saturating_add(Weight::from_ref_time(505_213).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // Minimum execution time: 663 nanoseconds. - Weight::from_ref_time(875_558 as u64) - // Standard Error: 394 - .saturating_add(Weight::from_ref_time(513_247 as u64).saturating_mul(r as u64)) + // Minimum execution time: 675 nanoseconds. + Weight::from_ref_time(903_705) + // Standard Error: 425 + .saturating_add(Weight::from_ref_time(507_749).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // Minimum execution time: 664 nanoseconds. - Weight::from_ref_time(891_913 as u64) - // Standard Error: 171 - .saturating_add(Weight::from_ref_time(523_595 as u64).saturating_mul(r as u64)) + // Minimum execution time: 637 nanoseconds. + Weight::from_ref_time(946_419) + // Standard Error: 301 + .saturating_add(Weight::from_ref_time(522_387).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // Minimum execution time: 638 nanoseconds. - Weight::from_ref_time(1_003_558 as u64) - // Standard Error: 471 - .saturating_add(Weight::from_ref_time(502_671 as u64).saturating_mul(r as u64)) + // Minimum execution time: 674 nanoseconds. + Weight::from_ref_time(963_566) + // Standard Error: 952 + .saturating_add(Weight::from_ref_time(504_528).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // Minimum execution time: 665 nanoseconds. - Weight::from_ref_time(892_435 as u64) - // Standard Error: 162 - .saturating_add(Weight::from_ref_time(504_300 as u64).saturating_mul(r as u64)) + // Minimum execution time: 663 nanoseconds. + Weight::from_ref_time(927_099) + // Standard Error: 336 + .saturating_add(Weight::from_ref_time(505_200).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // Minimum execution time: 626 nanoseconds. - Weight::from_ref_time(880_015 as u64) - // Standard Error: 229 - .saturating_add(Weight::from_ref_time(503_941 as u64).saturating_mul(r as u64)) + // Minimum execution time: 660 nanoseconds. + Weight::from_ref_time(901_114) + // Standard Error: 255 + .saturating_add(Weight::from_ref_time(503_803).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // Minimum execution time: 623 nanoseconds. - Weight::from_ref_time(893_955 as u64) - // Standard Error: 238 - .saturating_add(Weight::from_ref_time(731_619 as u64).saturating_mul(r as u64)) + // Minimum execution time: 636 nanoseconds. + Weight::from_ref_time(906_526) + // Standard Error: 246 + .saturating_add(Weight::from_ref_time(730_299).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // Minimum execution time: 661 nanoseconds. - Weight::from_ref_time(904_145 as u64) - // Standard Error: 210 - .saturating_add(Weight::from_ref_time(730_497 as u64).saturating_mul(r as u64)) + // Minimum execution time: 659 nanoseconds. + Weight::from_ref_time(947_772) + // Standard Error: 312 + .saturating_add(Weight::from_ref_time(729_463).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // Minimum execution time: 670 nanoseconds. - Weight::from_ref_time(910_832 as u64) - // Standard Error: 248 - .saturating_add(Weight::from_ref_time(738_960 as u64).saturating_mul(r as u64)) + // Minimum execution time: 646 nanoseconds. + Weight::from_ref_time(923_694) + // Standard Error: 243 + .saturating_add(Weight::from_ref_time(738_995).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // Minimum execution time: 600 nanoseconds. - Weight::from_ref_time(910_816 as u64) - // Standard Error: 257 - .saturating_add(Weight::from_ref_time(742_585 as u64).saturating_mul(r as u64)) + // Minimum execution time: 652 nanoseconds. + Weight::from_ref_time(955_453) + // Standard Error: 1_430 + .saturating_add(Weight::from_ref_time(741_624).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // Minimum execution time: 697 nanoseconds. - Weight::from_ref_time(937_672 as u64) - // Standard Error: 291 - .saturating_add(Weight::from_ref_time(746_511 as u64).saturating_mul(r as u64)) + // Minimum execution time: 642 nanoseconds. + Weight::from_ref_time(900_107) + // Standard Error: 376 + .saturating_add(Weight::from_ref_time(740_016).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // Minimum execution time: 651 nanoseconds. - Weight::from_ref_time(920_151 as u64) - // Standard Error: 185 - .saturating_add(Weight::from_ref_time(743_483 as u64).saturating_mul(r as u64)) + // Minimum execution time: 625 nanoseconds. + Weight::from_ref_time(946_744) + // Standard Error: 252 + .saturating_add(Weight::from_ref_time(743_532).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // Minimum execution time: 622 nanoseconds. - Weight::from_ref_time(914_571 as u64) - // Standard Error: 264 - .saturating_add(Weight::from_ref_time(733_935 as u64).saturating_mul(r as u64)) + // Minimum execution time: 652 nanoseconds. + Weight::from_ref_time(918_551) + // Standard Error: 313 + .saturating_add(Weight::from_ref_time(731_451).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // Minimum execution time: 653 nanoseconds. - Weight::from_ref_time(914_243 as u64) - // Standard Error: 199 - .saturating_add(Weight::from_ref_time(738_786 as u64).saturating_mul(r as u64)) + // Minimum execution time: 651 nanoseconds. + Weight::from_ref_time(923_475) + // Standard Error: 341 + .saturating_add(Weight::from_ref_time(738_353).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - // Minimum execution time: 625 nanoseconds. - Weight::from_ref_time(1_144_724 as u64) - // Standard Error: 1_367 - .saturating_add(Weight::from_ref_time(729_921 as u64).saturating_mul(r as u64)) + // Minimum execution time: 666 nanoseconds. + Weight::from_ref_time(1_136_987) + // Standard Error: 1_482 + .saturating_add(Weight::from_ref_time(727_254).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // Minimum execution time: 643 nanoseconds. - Weight::from_ref_time(897_337 as u64) - // Standard Error: 162 - .saturating_add(Weight::from_ref_time(738_471 as u64).saturating_mul(r as u64)) + // Minimum execution time: 633 nanoseconds. + Weight::from_ref_time(934_201) + // Standard Error: 332 + .saturating_add(Weight::from_ref_time(731_804).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // Minimum execution time: 672 nanoseconds. - Weight::from_ref_time(921_395 as u64) - // Standard Error: 465 - .saturating_add(Weight::from_ref_time(719_508 as u64).saturating_mul(r as u64)) + // Minimum execution time: 673 nanoseconds. + Weight::from_ref_time(983_317) + // Standard Error: 492 + .saturating_add(Weight::from_ref_time(718_126).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // Minimum execution time: 672 nanoseconds. - Weight::from_ref_time(889_319 as u64) - // Standard Error: 392 - .saturating_add(Weight::from_ref_time(714_186 as u64).saturating_mul(r as u64)) + // Minimum execution time: 647 nanoseconds. + Weight::from_ref_time(925_490) + // Standard Error: 1_799 + .saturating_add(Weight::from_ref_time(711_178).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // Minimum execution time: 660 nanoseconds. - Weight::from_ref_time(898_856 as u64) - // Standard Error: 189 - .saturating_add(Weight::from_ref_time(714_302 as u64).saturating_mul(r as u64)) + // Minimum execution time: 652 nanoseconds. + Weight::from_ref_time(955_546) + // Standard Error: 283 + .saturating_add(Weight::from_ref_time(710_844).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // Minimum execution time: 629 nanoseconds. - Weight::from_ref_time(902_499 as u64) - // Standard Error: 428 - .saturating_add(Weight::from_ref_time(1_346_772 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(982_314) + // Standard Error: 267 + .saturating_add(Weight::from_ref_time(1_344_080).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // Minimum execution time: 624 nanoseconds. - Weight::from_ref_time(944_381 as u64) - // Standard Error: 389 - .saturating_add(Weight::from_ref_time(1_281_605 as u64).saturating_mul(r as u64)) + // Minimum execution time: 637 nanoseconds. + Weight::from_ref_time(913_421) + // Standard Error: 737 + .saturating_add(Weight::from_ref_time(1_285_749).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // Minimum execution time: 667 nanoseconds. - Weight::from_ref_time(876_301 as u64) - // Standard Error: 589 - .saturating_add(Weight::from_ref_time(1_397_964 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(939_041) + // Standard Error: 354 + .saturating_add(Weight::from_ref_time(1_391_470).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // Minimum execution time: 611 nanoseconds. - Weight::from_ref_time(865_466 as u64) - // Standard Error: 253 - .saturating_add(Weight::from_ref_time(1_283_803 as u64).saturating_mul(r as u64)) + // Minimum execution time: 656 nanoseconds. + Weight::from_ref_time(951_030) + // Standard Error: 342 + .saturating_add(Weight::from_ref_time(1_287_904).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // Minimum execution time: 653 nanoseconds. - Weight::from_ref_time(882_010 as u64) - // Standard Error: 205 - .saturating_add(Weight::from_ref_time(731_251 as u64).saturating_mul(r as u64)) + // Minimum execution time: 682 nanoseconds. + Weight::from_ref_time(940_975) + // Standard Error: 195 + .saturating_add(Weight::from_ref_time(717_132).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // Minimum execution time: 638 nanoseconds. - Weight::from_ref_time(917_858 as u64) - // Standard Error: 249 - .saturating_add(Weight::from_ref_time(795_023 as u64).saturating_mul(r as u64)) + // Minimum execution time: 704 nanoseconds. + Weight::from_ref_time(941_860) + // Standard Error: 200 + .saturating_add(Weight::from_ref_time(717_696).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // Minimum execution time: 636 nanoseconds. - Weight::from_ref_time(892_650 as u64) - // Standard Error: 252 - .saturating_add(Weight::from_ref_time(729_337 as u64).saturating_mul(r as u64)) + // Minimum execution time: 648 nanoseconds. + Weight::from_ref_time(917_135) + // Standard Error: 237 + .saturating_add(Weight::from_ref_time(717_979).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // Minimum execution time: 648 nanoseconds. - Weight::from_ref_time(918_889 as u64) - // Standard Error: 1_079 - .saturating_add(Weight::from_ref_time(746_835 as u64).saturating_mul(r as u64)) + // Minimum execution time: 653 nanoseconds. + Weight::from_ref_time(1_031_822) + // Standard Error: 937 + .saturating_add(Weight::from_ref_time(730_965).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // Minimum execution time: 677 nanoseconds. - Weight::from_ref_time(931_684 as u64) - // Standard Error: 259 - .saturating_add(Weight::from_ref_time(734_540 as u64).saturating_mul(r as u64)) + // Minimum execution time: 671 nanoseconds. + Weight::from_ref_time(935_833) + // Standard Error: 184 + .saturating_add(Weight::from_ref_time(732_227).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // Minimum execution time: 635 nanoseconds. - Weight::from_ref_time(914_996 as u64) - // Standard Error: 611 - .saturating_add(Weight::from_ref_time(735_020 as u64).saturating_mul(r as u64)) + // Minimum execution time: 637 nanoseconds. + Weight::from_ref_time(962_491) + // Standard Error: 488 + .saturating_add(Weight::from_ref_time(733_218).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // Minimum execution time: 663 nanoseconds. - Weight::from_ref_time(914_333 as u64) - // Standard Error: 169 - .saturating_add(Weight::from_ref_time(734_033 as u64).saturating_mul(r as u64)) + // Minimum execution time: 643 nanoseconds. + Weight::from_ref_time(951_949) + // Standard Error: 321 + .saturating_add(Weight::from_ref_time(732_212).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // Minimum execution time: 631 nanoseconds. - Weight::from_ref_time(916_503 as u64) - // Standard Error: 224 - .saturating_add(Weight::from_ref_time(736_168 as u64).saturating_mul(r as u64)) + // Minimum execution time: 665 nanoseconds. + Weight::from_ref_time(951_447) + // Standard Error: 346 + .saturating_add(Weight::from_ref_time(732_549).saturating_mul(r.into())) } } From 234749e0854c86885b3a9358c0c4513dfe9607f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 6 Dec 2022 12:01:58 +0100 Subject: [PATCH 1438/1472] contracts: Add `instantiation_nonce` API (#12800) * Add `instantiation_nonce` API * Fixes for tests * Update frame/contracts/src/schedule.rs Co-authored-by: Sasha Gryaznov * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts Co-authored-by: Sasha Gryaznov Co-authored-by: command-bot <> --- frame/contracts/proc-macro/src/lib.rs | 4 ++ frame/contracts/src/benchmarking/mod.rs | 20 +++++++ frame/contracts/src/exec.rs | 71 +++++++++++++++++++++---- frame/contracts/src/schedule.rs | 8 ++- frame/contracts/src/wasm/mod.rs | 41 +++++++++++--- frame/contracts/src/wasm/runtime.rs | 13 +++++ frame/contracts/src/weights.rs | 31 +++++++++++ 7 files changed, 169 insertions(+), 19 deletions(-) diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index 82b5b728a73ee..a8f95bd10cff8 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -163,6 +163,7 @@ struct HostFn { enum HostFnReturn { Unit, U32, + U64, ReturnCode, } @@ -171,6 +172,7 @@ impl HostFnReturn { let ok = match self { Self::Unit => quote! { () }, Self::U32 | Self::ReturnCode => quote! { ::core::primitive::u32 }, + Self::U64 => quote! { ::core::primitive::u64 }, }; quote! { ::core::result::Result<#ok, ::wasmi::core::Trap> @@ -241,6 +243,7 @@ impl HostFn { let msg = r#"Should return one of the following: - Result<(), TrapReason>, - Result, + - Result, - Result"#; let ret_ty = match item.clone().sig.output { syn::ReturnType::Type(_, ty) => Ok(ty.clone()), @@ -303,6 +306,7 @@ impl HostFn { let returns = match ok_ty_str.as_str() { "()" => Ok(HostFnReturn::Unit), "u32" => Ok(HostFnReturn::U32), + "u64" => Ok(HostFnReturn::U64), "ReturnCode" => Ok(HostFnReturn::ReturnCode), _ => Err(err(arg1.span(), &msg)), }?; diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 87e2ca4388784..6b8701ac84d96 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -2138,6 +2138,26 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + seal_instantiation_nonce { + let r in 0 .. API_BENCHMARK_BATCHES; + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "seal0", + name: "instantiation_nonce", + params: vec![], + return_type: Some(ValueType::I64), + }], + call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + Instruction::Call(0), + Instruction::Drop, + ])), + .. Default::default() + }); + let instance = Contract::::new(code, vec![])?; + let origin = RawOrigin::Signed(instance.caller.clone()); + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + // We make the assumption that pushing a constant and dropping a value takes roughly // the same amount of time. We follow that `t.load` and `drop` both have the weight // of this benchmark / 2. We need to make this assumption because there is no way diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 2884779d8fda7..c0cf6a9f4c4c4 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -305,6 +305,9 @@ pub trait Ext: sealing::Sealed { /// are not calculated as separate entrance. /// A value of 0 means it does not exist on the call stack. fn account_reentrance_count(&self, account_id: &AccountIdOf) -> u32; + + /// Returns a nonce that is incremented for every instantiated contract. + fn nonce(&mut self) -> u64; } /// Describes the different functions that can be exported by an [`Executable`]. @@ -654,7 +657,7 @@ where let (mut stack, executable) = Self::new( FrameArgs::Instantiate { sender: origin.clone(), - nonce: Self::initial_nonce(), + nonce: >::get().wrapping_add(1), executable, salt, }, @@ -1068,19 +1071,10 @@ where /// Increments and returns the next nonce. Pulls it from storage if it isn't in cache. fn next_nonce(&mut self) -> u64 { - let next = if let Some(current) = self.nonce { - current.wrapping_add(1) - } else { - Self::initial_nonce() - }; + let next = self.nonce().wrapping_add(1); self.nonce = Some(next); next } - - /// Pull the current nonce from storage. - fn initial_nonce() -> u64 { - >::get().wrapping_add(1) - } } impl<'a, T, E> Ext for Stack<'a, T, E> @@ -1394,6 +1388,16 @@ where .filter(|f| f.delegate_caller.is_none() && &f.account_id == account_id) .count() as u32 } + + fn nonce(&mut self) -> u64 { + if let Some(current) = self.nonce { + current + } else { + let current = >::get(); + self.nonce = Some(current); + current + } + } } mod sealing { @@ -3325,4 +3329,49 @@ mod tests { assert_matches!(result, Ok(_)); }); } + + #[test] + fn nonce_api_works() { + let fail_code = MockLoader::insert(Constructor, |_, _| exec_trapped()); + let success_code = MockLoader::insert(Constructor, |_, _| exec_success()); + let code_hash = MockLoader::insert(Call, move |ctx, _| { + // It is set to one when this contract was instantiated by `place_contract` + assert_eq!(ctx.ext.nonce(), 1); + // Should not change without any instantation in-between + assert_eq!(ctx.ext.nonce(), 1); + // Should not change with a failed instantiation + assert_err!( + ctx.ext.instantiate(Weight::zero(), fail_code, 0, vec![], &[],), + ExecError { + error: >::ContractTrapped.into(), + origin: ErrorOrigin::Callee + } + ); + assert_eq!(ctx.ext.nonce(), 1); + // Successful instantation increments + ctx.ext.instantiate(Weight::zero(), success_code, 0, vec![], &[]).unwrap(); + assert_eq!(ctx.ext.nonce(), 2); + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let min_balance = ::Currency::minimum_balance(); + let schedule = ::Schedule::get(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + set_balance(&ALICE, min_balance * 1000); + place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 0).unwrap(); + assert_ok!(MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + None, + Determinism::Deterministic + )); + }); + } } diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 9d02989642737..4f2d3b61d0176 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -430,12 +430,15 @@ pub struct HostFnWeights { /// Weight of calling `seal_ecdsa_to_eth_address`. pub ecdsa_to_eth_address: u64, - /// Weight of calling `seal_reentrance_count`. + /// Weight of calling `reentrance_count`. pub reentrance_count: u64, - /// Weight of calling `seal_account_reentrance_count`. + /// Weight of calling `account_reentrance_count`. pub account_reentrance_count: u64, + /// Weight of calling `instantiation_nonce`. + pub instantiation_nonce: u64, + /// The type parameter is used in the default implementation. #[codec(skip)] pub _phantom: PhantomData, @@ -676,6 +679,7 @@ impl Default for HostFnWeights { ecdsa_to_eth_address: cost_batched!(seal_ecdsa_to_eth_address), reentrance_count: cost_batched!(seal_reentrance_count), account_reentrance_count: cost_batched!(seal_account_reentrance_count), + instantiation_nonce: cost_batched!(seal_instantiation_nonce), _phantom: PhantomData, } } diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index ac338007e5dc9..e9e6b42dc3f8a 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -625,6 +625,9 @@ mod tests { fn account_reentrance_count(&self, _account_id: &AccountIdOf) -> u32 { 12 } + fn nonce(&mut self) -> u64 { + 995 + } } fn execute_internal>( @@ -649,16 +652,16 @@ mod tests { } fn execute>(wat: &str, input_data: Vec, ext: E) -> ExecResult { - execute_internal(wat, input_data, ext, false) + execute_internal(wat, input_data, ext, true) } #[cfg(not(feature = "runtime-benchmarks"))] - fn execute_with_unstable>( + fn execute_no_unstable>( wat: &str, input_data: Vec, ext: E, ) -> ExecResult { - execute_internal(wat, input_data, ext, true) + execute_internal(wat, input_data, ext, false) } const CODE_TRANSFER: &str = r#" @@ -2971,13 +2974,39 @@ mod tests { execute(CODE, vec![], &mut mock_ext).unwrap(); } + #[test] + fn instantiation_nonce_works() { + const CODE: &str = r#" +(module + (import "seal0" "instantiation_nonce" (func $nonce (result i64))) + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + (func (export "call") + (call $assert + (i64.eq (call $nonce) (i64.const 995)) + ) + ) + (func (export "deploy")) +) +"#; + + let mut mock_ext = MockExt::default(); + execute(CODE, vec![], &mut mock_ext).unwrap(); + } + /// This test check that an unstable interface cannot be deployed. In case of runtime /// benchmarks we always allow unstable interfaces. This is why this test does not /// work when this feature is enabled. #[cfg(not(feature = "runtime-benchmarks"))] #[test] fn cannot_deploy_unstable() { - const CANNT_DEPLOY_UNSTABLE: &str = r#" + const CANNOT_DEPLOY_UNSTABLE: &str = r#" (module (import "seal0" "reentrance_count" (func $reentrance_count (result i32))) (func (export "call")) @@ -2985,9 +3014,9 @@ mod tests { ) "#; assert_err!( - execute(CANNT_DEPLOY_UNSTABLE, vec![], MockExt::default()), + execute_no_unstable(CANNOT_DEPLOY_UNSTABLE, vec![], MockExt::default()), >::CodeRejected, ); - assert_ok!(execute_with_unstable(CANNT_DEPLOY_UNSTABLE, vec![], MockExt::default())); + assert_ok!(execute(CANNOT_DEPLOY_UNSTABLE, vec![], MockExt::default())); } } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 988bb224f2a6c..b933688eb61ec 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -265,6 +265,8 @@ pub enum RuntimeCosts { ReentrantCount, /// Weight of calling `account_reentrance_count` AccountEntranceCount, + /// Weight of calling `instantiation_nonce` + InstantationNonce, } impl RuntimeCosts { @@ -344,6 +346,7 @@ impl RuntimeCosts { EcdsaToEthAddress => s.ecdsa_to_eth_address, ReentrantCount => s.reentrance_count, AccountEntranceCount => s.account_reentrance_count, + InstantationNonce => s.instantiation_nonce, }; RuntimeToken { #[cfg(test)] @@ -2614,4 +2617,14 @@ pub mod env { ctx.read_sandbox_memory_as(memory, account_ptr)?; Ok(ctx.ext.account_reentrance_count(&account_id)) } + + /// Returns a nonce that is unique per contract instantiation. + /// + /// The nonce is incremented for each succesful contract instantiation. This is a + /// sensible default salt for contract instantiations. + #[unstable] + fn instantiation_nonce(ctx: _, _memory: _) -> Result { + ctx.charge_gas(RuntimeCosts::InstantationNonce)?; + Ok(ctx.ext.nonce()) + } } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 680f4c94ebd9f..c3f3b50097278 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -112,6 +112,7 @@ pub trait WeightInfo { fn seal_set_code_hash(r: u32, ) -> Weight; fn seal_reentrance_count(r: u32, ) -> Weight; fn seal_account_reentrance_count(r: u32, ) -> Weight; + fn seal_instantiation_nonce(r: u32, ) -> Weight; fn instr_i64const(r: u32, ) -> Weight; fn instr_i64load(r: u32, ) -> Weight; fn instr_i64store(r: u32, ) -> Weight; @@ -1054,6 +1055,21 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) + // Storage: Contracts Nonce (r:1 w:1) + /// The range of component `r` is `[0, 20]`. + fn seal_instantiation_nonce(r: u32, ) -> Weight { + // Minimum execution time: 293_987 nanoseconds. + Weight::from_ref_time(307_154_849) + // Standard Error: 27_486 + .saturating_add(Weight::from_ref_time(8_759_333).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(4)) + } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { // Minimum execution time: 688 nanoseconds. @@ -2307,6 +2323,21 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } + // Storage: System Account (r:1 w:0) + // Storage: Contracts ContractInfoOf (r:1 w:1) + // Storage: Contracts CodeStorage (r:1 w:0) + // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) + // Storage: Contracts Nonce (r:1 w:1) + /// The range of component `r` is `[0, 20]`. + fn seal_instantiation_nonce(r: u32, ) -> Weight { + // Minimum execution time: 293_987 nanoseconds. + Weight::from_ref_time(307_154_849) + // Standard Error: 27_486 + .saturating_add(Weight::from_ref_time(8_759_333).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7)) + .saturating_add(RocksDbWeight::get().writes(4)) + } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { // Minimum execution time: 688 nanoseconds. From 416a331399452521f3e9cf7e1394d020373a95c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Tue, 6 Dec 2022 08:42:38 -0300 Subject: [PATCH 1439/1472] Rename some crates for publishing to crates.io (#12837) * rename some crates for publishing to crates.io * s/remote-ext/frame-remote-externalities --- Cargo.lock | 94 ++++++++++----------- client/beefy/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/merkle-mountain-range/Cargo.toml | 2 +- frame/bags-list/remote-tests/Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 2 +- frame/beefy-mmr/primitives/Cargo.toml | 2 +- frame/beefy/Cargo.toml | 2 +- frame/state-trie-migration/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 13 files changed, 59 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5118edb9e3706..736501ecefd79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -374,7 +374,6 @@ version = "4.0.0-dev" dependencies = [ "array-bytes", "async-trait", - "beefy-primitives", "fnv", "futures", "futures-timer", @@ -396,6 +395,7 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-arithmetic", + "sp-beefy", "sp-blockchain", "sp-consensus", "sp-core", @@ -419,7 +419,6 @@ name = "beefy-gadget-rpc" version = "4.0.0-dev" dependencies = [ "beefy-gadget", - "beefy-primitives", "futures", "jsonrpsee", "log", @@ -429,6 +428,7 @@ dependencies = [ "sc-utils", "serde", "serde_json", + "sp-beefy", "sp-core", "sp-runtime", "substrate-test-runtime-client", @@ -441,31 +441,13 @@ name = "beefy-merkle-tree" version = "4.0.0-dev" dependencies = [ "array-bytes", - "beefy-primitives", "env_logger", "log", "sp-api", + "sp-beefy", "sp-runtime", ] -[[package]] -name = "beefy-primitives" -version = "4.0.0-dev" -dependencies = [ - "array-bytes", - "parity-scale-codec", - "scale-info", - "serde", - "sp-api", - "sp-application-crypto", - "sp-core", - "sp-io", - "sp-keystore", - "sp-mmr-primitives", - "sp-runtime", - "sp-std", -] - [[package]] name = "bincode" version = "1.3.3" @@ -2226,6 +2208,25 @@ dependencies = [ "serde", ] +[[package]] +name = "frame-remote-externalities" +version = "0.10.0-dev" +dependencies = [ + "env_logger", + "frame-support", + "log", + "pallet-elections-phragmen", + "parity-scale-codec", + "serde", + "serde_json", + "sp-core", + "sp-io", + "sp-runtime", + "sp-version", + "substrate-rpc-client", + "tokio", +] + [[package]] name = "frame-support" version = "4.0.0-dev" @@ -4139,7 +4140,6 @@ dependencies = [ name = "mmr-gadget" version = "4.0.0-dev" dependencies = [ - "beefy-primitives", "futures", "log", "parity-scale-codec", @@ -4147,6 +4147,7 @@ dependencies = [ "sc-client-api", "sc-offchain", "sp-api", + "sp-beefy", "sp-blockchain", "sp-consensus", "sp-core", @@ -5115,12 +5116,12 @@ name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" dependencies = [ "frame-election-provider-support", + "frame-remote-externalities", "frame-support", "frame-system", "log", "pallet-bags-list", "pallet-staking", - "remote-externalities", "sp-core", "sp-runtime", "sp-std", @@ -5149,13 +5150,13 @@ dependencies = [ name = "pallet-beefy" version = "4.0.0-dev" dependencies = [ - "beefy-primitives", "frame-support", "frame-system", "pallet-session", "parity-scale-codec", "scale-info", "serde", + "sp-beefy", "sp-core", "sp-io", "sp-runtime", @@ -5169,7 +5170,6 @@ version = "4.0.0-dev" dependencies = [ "array-bytes", "beefy-merkle-tree", - "beefy-primitives", "frame-support", "frame-system", "log", @@ -5179,6 +5179,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", + "sp-beefy", "sp-core", "sp-io", "sp-runtime", @@ -6087,13 +6088,13 @@ name = "pallet-state-trie-migration" version = "4.0.0-dev" dependencies = [ "frame-benchmarking", + "frame-remote-externalities", "frame-support", "frame-system", "log", "pallet-balances", "parity-scale-codec", "parking_lot 0.12.1", - "remote-externalities", "scale-info", "serde", "sp-core", @@ -7189,25 +7190,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "remote-externalities" -version = "0.10.0-dev" -dependencies = [ - "env_logger", - "frame-support", - "log", - "pallet-elections-phragmen", - "parity-scale-codec", - "serde", - "serde_json", - "sp-core", - "sp-io", - "sp-runtime", - "sp-version", - "substrate-rpc-client", - "tokio", -] - [[package]] name = "remove_dir_all" version = "0.5.3" @@ -9327,6 +9309,24 @@ dependencies = [ "sp-std", ] +[[package]] +name = "sp-beefy" +version = "4.0.0-dev" +dependencies = [ + "array-bytes", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-keystore", + "sp-mmr-primitives", + "sp-runtime", + "sp-std", +] + [[package]] name = "sp-block-builder" version = "4.0.0-dev" @@ -10323,7 +10323,6 @@ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ "beefy-merkle-tree", - "beefy-primitives", "cfg-if", "frame-support", "frame-system", @@ -10342,6 +10341,7 @@ dependencies = [ "serde", "sp-api", "sp-application-crypto", + "sp-beefy", "sp-block-builder", "sp-consensus", "sp-consensus-aura", @@ -10952,10 +10952,10 @@ name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ "clap 4.0.11", + "frame-remote-externalities", "frame-try-runtime", "log", "parity-scale-codec", - "remote-externalities", "sc-chain-spec", "sc-cli", "sc-executor", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index b6a77f00e7199..d0b36a9255f76 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -19,7 +19,7 @@ log = "0.4" parking_lot = "0.12.1" thiserror = "1.0" wasm-timer = "0.2.5" -beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } +beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", package = "sp-beefy" } prometheus = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } sc-chain-spec = { version = "4.0.0-dev", path = "../../client/chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index 11ad15af1983d..d27225824539a 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -17,7 +17,7 @@ parking_lot = "0.12.1" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0" beefy-gadget = { version = "4.0.0-dev", path = "../." } -beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy" } +beefy-primitives = { version = "4.0.0-dev", path = "../../../primitives/beefy", package = "sp-beefy" } sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-core = { version = "7.0.0", path = "../../../primitives/core" } diff --git a/client/merkle-mountain-range/Cargo.toml b/client/merkle-mountain-range/Cargo.toml index 6e8cb8194e48c..e32764eff1d63 100644 --- a/client/merkle-mountain-range/Cargo.toml +++ b/client/merkle-mountain-range/Cargo.toml @@ -14,7 +14,7 @@ homepage = "https://substrate.io" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3" log = "0.4" -beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy" } +beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", package = "sp-beefy" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index de97ebd0e6a13..941076753b4cf 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -28,7 +28,7 @@ sp-runtime = { path = "../../../primitives/runtime", version = "7.0.0" } sp-std = { path = "../../../primitives/std", version = "5.0.0" } # utils -remote-externalities = { path = "../../../utils/frame/remote-externalities", version = "0.10.0-dev" } +remote-externalities = { path = "../../../utils/frame/remote-externalities", version = "0.10.0-dev", package = "frame-remote-externalities" } # others log = "0.4.17" diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 33b93343106a2..f65270acdc3f8 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -15,7 +15,7 @@ log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } beefy-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "./primitives" } -beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy" } +beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy", package = "sp-beefy" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-beefy = { version = "4.0.0-dev", default-features = false, path = "../beefy" } diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/frame/beefy-mmr/primitives/Cargo.toml index edd0daa5aa21d..c087bc2f37cd3 100644 --- a/frame/beefy-mmr/primitives/Cargo.toml +++ b/frame/beefy-mmr/primitives/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" array-bytes = { version = "4.1", optional = true } log = { version = "0.4", default-features = false, optional = true } -beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/beefy" } +beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/beefy", package = "sp-beefy" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 5cb180750a7e7..707e8e25712ab 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } -beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy" } +beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy", package = "sp-beefy" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index 30d90e8b862a7..8d10a34077230 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -22,7 +22,7 @@ zstd = { version = "0.11.2", default-features = false, optional = true } frame-benchmarking = { default-features = false, optional = true, path = "../benchmarking" } frame-support = { default-features = false, path = "../support" } frame-system = { default-features = false, path = "../system" } -remote-externalities = { optional = true, path = "../../utils/frame/remote-externalities" } +remote-externalities = { optional = true, path = "../../utils/frame/remote-externalities", package = "frame-remote-externalities" } sp-core = { default-features = false, path = "../../primitives/core" } sp-io = { default-features = false, path = "../../primitives/io" } sp-runtime = { default-features = false, path = "../../primitives/runtime" } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 586f2e4b30084..a7ff212a09e81 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "beefy-primitives" +name = "sp-beefy" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index b64a847b15943..a201906f1cc4d 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy" } +beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy", package = "sp-beefy" } beefy-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "../../frame/beefy-mmr/primitives" } sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index f24ab346c4084..a39dc9d3866cc 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "remote-externalities" +name = "frame-remote-externalities" version = "0.10.0-dev" authors = ["Parity Technologies "] edition = "2021" diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index e7bbba131155f..acac966aa1a58 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -18,7 +18,7 @@ log = "0.4.17" parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = { version = "0.11.2", default-features = false } -remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } +remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities", package = "frame-remote-externalities" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } From 44fbbd92c3a03ef541fe0880b15bba33b943272f Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Tue, 6 Dec 2022 15:51:03 +0100 Subject: [PATCH 1440/1472] Whitelist pallet preimage provider upgrade (#12834) * whitelist preimage provider upgrade * rustdocs unresolved link error fix * ".git/.scripts/bench-bot.sh" pallet dev pallet_whitelist * PreimageHash alias, remove type annotation Co-authored-by: command-bot <> --- bin/node/runtime/src/lib.rs | 2 +- frame/whitelist/src/benchmarking.rs | 29 ++++---- frame/whitelist/src/lib.rs | 54 +++++++++------ frame/whitelist/src/mock.rs | 2 +- frame/whitelist/src/tests.rs | 69 ++++++++++++++----- frame/whitelist/src/weights.rs | 101 +++++++++++++++------------- 6 files changed, 153 insertions(+), 104 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 633106e10b6f8..8c4e70c37d8c0 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1544,7 +1544,7 @@ impl pallet_whitelist::Config for Runtime { type RuntimeCall = RuntimeCall; type WhitelistOrigin = EnsureRoot; type DispatchWhitelistedOrigin = EnsureRoot; - type PreimageProvider = Preimage; + type Preimages = Preimage; type WeightInfo = pallet_whitelist::weights::SubstrateWeight; } diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index e0a758b2ddfdf..923adc6ccf8ca 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -21,10 +21,7 @@ use super::*; use frame_benchmarking::benchmarks; -use frame_support::{ - ensure, - traits::{EnsureOrigin, Get, PreimageRecipient}, -}; +use frame_support::{ensure, traits::EnsureOrigin}; #[cfg(test)] use crate::Pallet as Whitelist; @@ -40,7 +37,7 @@ benchmarks! { "call not whitelisted" ); ensure!( - T::PreimageProvider::preimage_requested(&call_hash), + T::Preimages::is_requested(&call_hash), "preimage not requested" ); } @@ -57,7 +54,7 @@ benchmarks! { "whitelist not removed" ); ensure!( - !T::PreimageProvider::preimage_requested(&call_hash), + !T::Preimages::is_requested(&call_hash), "preimage still requested" ); } @@ -66,30 +63,30 @@ benchmarks! { // If the resulting weight is too big, maybe it worth having a weight which depends // on the size of the call, with a new witness in parameter. dispatch_whitelisted_call { - let origin = T::DispatchWhitelistedOrigin::successful_origin(); // NOTE: we remove `10` because we need some bytes to encode the variants and vec length - let remark_len = >::MaxSize::get() - 10; - let remark = sp_std::vec![1u8; remark_len as usize]; + let n in 1 .. T::Preimages::MAX_LENGTH as u32 - 10; + let origin = T::DispatchWhitelistedOrigin::successful_origin(); + let remark = sp_std::vec![1u8; n as usize]; let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); let call_weight = call.get_dispatch_info().weight; let encoded_call = call.encode(); - let call_hash = T::Hashing::hash(&encoded_call[..]); + let call_encoded_len = encoded_call.len() as u32; + let call_hash = call.blake2_256().into(); Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); - let encoded_call = encoded_call.try_into().expect("encoded_call must be small enough"); - T::PreimageProvider::note_preimage(encoded_call); + T::Preimages::note(encoded_call.into()).unwrap(); - }: _(origin, call_hash, call_weight) + }: _(origin, call_hash, call_encoded_len, call_weight) verify { ensure!( !WhitelistedCall::::contains_key(call_hash), "whitelist not removed" ); ensure!( - !T::PreimageProvider::preimage_requested(&call_hash), + !T::Preimages::is_requested(&call_hash), "preimage still requested" ); } @@ -101,7 +98,7 @@ benchmarks! { let remark = sp_std::vec![1u8; n as usize]; let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); - let call_hash = T::Hashing::hash_of(&call); + let call_hash = call.blake2_256().into(); Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); @@ -112,7 +109,7 @@ benchmarks! { "whitelist not removed" ); ensure!( - !T::PreimageProvider::preimage_requested(&call_hash), + !T::Preimages::is_requested(&call_hash), "preimage still requested" ); } diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index be5fdf9e472b3..1b2dc9415607e 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -27,7 +27,7 @@ //! with the root origin. //! //! In the meantime the call corresponding to the hash must have been submitted to the pre-image -//! handler [`PreimageProvider`]. +//! handler [`pallet::Config::Preimages`]. #![cfg_attr(not(feature = "std"), no_std)] @@ -44,11 +44,12 @@ use codec::{DecodeLimit, Encode, FullCodec}; use frame_support::{ dispatch::{GetDispatchInfo, PostDispatchInfo}, ensure, - traits::{PreimageProvider, PreimageRecipient}, + traits::{Hash as PreimageHash, QueryPreimage, StorePreimage}, weights::Weight, + Hashable, }; use scale_info::TypeInfo; -use sp_runtime::traits::{Dispatchable, Hash}; +use sp_runtime::traits::Dispatchable; use sp_std::prelude::*; pub use pallet::*; @@ -80,8 +81,7 @@ pub mod pallet { type DispatchWhitelistedOrigin: EnsureOrigin; /// The handler of pre-images. - // NOTE: recipient is only needed for benchmarks. - type PreimageProvider: PreimageProvider + PreimageRecipient; + type Preimages: QueryPreimage + StorePreimage; /// The weight information for this pallet. type WeightInfo: WeightInfo; @@ -94,9 +94,9 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - CallWhitelisted { call_hash: T::Hash }, - WhitelistedCallRemoved { call_hash: T::Hash }, - WhitelistedCallDispatched { call_hash: T::Hash, result: DispatchResultWithPostInfo }, + CallWhitelisted { call_hash: PreimageHash }, + WhitelistedCallRemoved { call_hash: PreimageHash }, + WhitelistedCallDispatched { call_hash: PreimageHash, result: DispatchResultWithPostInfo }, } #[pallet::error] @@ -114,12 +114,13 @@ pub mod pallet { } #[pallet::storage] - pub type WhitelistedCall = StorageMap<_, Twox64Concat, T::Hash, (), OptionQuery>; + pub type WhitelistedCall = + StorageMap<_, Twox64Concat, PreimageHash, (), OptionQuery>; #[pallet::call] impl Pallet { #[pallet::weight(T::WeightInfo::whitelist_call())] - pub fn whitelist_call(origin: OriginFor, call_hash: T::Hash) -> DispatchResult { + pub fn whitelist_call(origin: OriginFor, call_hash: PreimageHash) -> DispatchResult { T::WhitelistOrigin::ensure_origin(origin)?; ensure!( @@ -128,7 +129,7 @@ pub mod pallet { ); WhitelistedCall::::insert(call_hash, ()); - T::PreimageProvider::request_preimage(&call_hash); + T::Preimages::request(&call_hash); Self::deposit_event(Event::::CallWhitelisted { call_hash }); @@ -136,12 +137,15 @@ pub mod pallet { } #[pallet::weight(T::WeightInfo::remove_whitelisted_call())] - pub fn remove_whitelisted_call(origin: OriginFor, call_hash: T::Hash) -> DispatchResult { + pub fn remove_whitelisted_call( + origin: OriginFor, + call_hash: PreimageHash, + ) -> DispatchResult { T::WhitelistOrigin::ensure_origin(origin)?; WhitelistedCall::::take(call_hash).ok_or(Error::::CallIsNotWhitelisted)?; - T::PreimageProvider::unrequest_preimage(&call_hash); + T::Preimages::unrequest(&call_hash); Self::deposit_event(Event::::WhitelistedCallRemoved { call_hash }); @@ -149,11 +153,13 @@ pub mod pallet { } #[pallet::weight( - T::WeightInfo::dispatch_whitelisted_call().saturating_add(*call_weight_witness) + T::WeightInfo::dispatch_whitelisted_call(*call_encoded_len) + .saturating_add(*call_weight_witness) )] pub fn dispatch_whitelisted_call( origin: OriginFor, - call_hash: T::Hash, + call_hash: PreimageHash, + call_encoded_len: u32, call_weight_witness: Weight, ) -> DispatchResultWithPostInfo { T::DispatchWhitelistedOrigin::ensure_origin(origin)?; @@ -163,8 +169,8 @@ pub mod pallet { Error::::CallIsNotWhitelisted, ); - let call = T::PreimageProvider::get_preimage(&call_hash) - .ok_or(Error::::UnavailablePreImage)?; + let call = T::Preimages::fetch(&call_hash, Some(call_encoded_len)) + .map_err(|_| Error::::UnavailablePreImage)?; let call = ::RuntimeCall::decode_all_with_depth_limit( sp_api::MAX_EXTRINSIC_DEPTH, @@ -177,8 +183,9 @@ pub mod pallet { Error::::InvalidCallWeightWitness ); - let actual_weight = Self::clean_and_dispatch(call_hash, call) - .map(|w| w.saturating_add(T::WeightInfo::dispatch_whitelisted_call())); + let actual_weight = Self::clean_and_dispatch(call_hash, call).map(|w| { + w.saturating_add(T::WeightInfo::dispatch_whitelisted_call(call_encoded_len)) + }); Ok(actual_weight.into()) } @@ -196,7 +203,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { T::DispatchWhitelistedOrigin::ensure_origin(origin)?; - let call_hash = ::Hashing::hash_of(&call); + let call_hash = call.blake2_256().into(); ensure!( WhitelistedCall::::contains_key(call_hash), @@ -217,10 +224,13 @@ impl Pallet { /// Clean whitelisting/preimage and dispatch call. /// /// Return the call actual weight of the dispatched call if there is some. - fn clean_and_dispatch(call_hash: T::Hash, call: ::RuntimeCall) -> Option { + fn clean_and_dispatch( + call_hash: PreimageHash, + call: ::RuntimeCall, + ) -> Option { WhitelistedCall::::remove(call_hash); - T::PreimageProvider::unrequest_preimage(&call_hash); + T::Preimages::unrequest(&call_hash); let result = call.dispatch(frame_system::Origin::::Root.into()); diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs index d4446cb8031ab..ef5d3d4fb4d34 100644 --- a/frame/whitelist/src/mock.rs +++ b/frame/whitelist/src/mock.rs @@ -106,7 +106,7 @@ impl pallet_whitelist::Config for Test { type RuntimeCall = RuntimeCall; type WhitelistOrigin = EnsureRoot; type DispatchWhitelistedOrigin = EnsureRoot; - type PreimageProvider = Preimage; + type Preimages = Preimage; type WeightInfo = (); } diff --git a/frame/whitelist/src/tests.rs b/frame/whitelist/src/tests.rs index fd6558e83f30e..d04bb48c1ec40 100644 --- a/frame/whitelist/src/tests.rs +++ b/frame/whitelist/src/tests.rs @@ -20,7 +20,10 @@ use crate::mock::*; use codec::Encode; use frame_support::{ - assert_noop, assert_ok, dispatch::GetDispatchInfo, traits::PreimageProvider, weights::Weight, + assert_noop, assert_ok, + dispatch::GetDispatchInfo, + traits::{QueryPreimage, StorePreimage}, + weights::Weight, }; use sp_runtime::{traits::Hash, DispatchError}; @@ -43,7 +46,7 @@ fn test_whitelist_call_and_remove() { assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); - assert!(Preimage::preimage_requested(&call_hash)); + assert!(Preimage::is_requested(&call_hash)); assert_noop!( Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash), @@ -57,7 +60,7 @@ fn test_whitelist_call_and_remove() { assert_ok!(Whitelist::remove_whitelisted_call(RuntimeOrigin::root(), call_hash)); - assert!(!Preimage::preimage_requested(&call_hash)); + assert!(!Preimage::is_requested(&call_hash)); assert_noop!( Whitelist::remove_whitelisted_call(RuntimeOrigin::root(), call_hash), @@ -72,33 +75,50 @@ fn test_whitelist_call_and_execute() { let call = RuntimeCall::System(frame_system::Call::remark_with_event { remark: vec![1] }); let call_weight = call.get_dispatch_info().weight; let encoded_call = call.encode(); + let call_encoded_len = encoded_call.len() as u32; let call_hash = ::Hashing::hash(&encoded_call[..]); assert_noop!( - Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call( + RuntimeOrigin::root(), + call_hash, + call_encoded_len, + call_weight + ), crate::Error::::CallIsNotWhitelisted, ); assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call(RuntimeOrigin::signed(1), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call( + RuntimeOrigin::signed(1), + call_hash, + call_encoded_len, + call_weight + ), DispatchError::BadOrigin, ); assert_noop!( - Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call( + RuntimeOrigin::root(), + call_hash, + call_encoded_len, + call_weight + ), crate::Error::::UnavailablePreImage, ); - assert_ok!(Preimage::note_preimage(RuntimeOrigin::root(), encoded_call)); + assert_ok!(Preimage::note(encoded_call.into())); - assert!(Preimage::preimage_requested(&call_hash)); + assert!(Preimage::is_requested(&call_hash)); assert_noop!( Whitelist::dispatch_whitelisted_call( RuntimeOrigin::root(), call_hash, + call_encoded_len, call_weight - Weight::from_ref_time(1) ), crate::Error::::InvalidCallWeightWitness, @@ -107,13 +127,19 @@ fn test_whitelist_call_and_execute() { assert_ok!(Whitelist::dispatch_whitelisted_call( RuntimeOrigin::root(), call_hash, + call_encoded_len, call_weight )); - assert!(!Preimage::preimage_requested(&call_hash)); + assert!(!Preimage::is_requested(&call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call( + RuntimeOrigin::root(), + call_hash, + call_encoded_len, + call_weight + ), crate::Error::::CallIsNotWhitelisted, ); }); @@ -124,21 +150,24 @@ fn test_whitelist_call_and_execute_failing_call() { new_test_ext().execute_with(|| { let call = RuntimeCall::Whitelist(crate::Call::dispatch_whitelisted_call { call_hash: Default::default(), + call_encoded_len: Default::default(), call_weight_witness: Weight::zero(), }); let call_weight = call.get_dispatch_info().weight; let encoded_call = call.encode(); + let call_encoded_len = encoded_call.len() as u32; let call_hash = ::Hashing::hash(&encoded_call[..]); assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); - assert_ok!(Preimage::note_preimage(RuntimeOrigin::root(), encoded_call)); - assert!(Preimage::preimage_requested(&call_hash)); + assert_ok!(Preimage::note(encoded_call.into())); + assert!(Preimage::is_requested(&call_hash)); assert_ok!(Whitelist::dispatch_whitelisted_call( RuntimeOrigin::root(), call_hash, + call_encoded_len, call_weight )); - assert!(!Preimage::preimage_requested(&call_hash)); + assert!(!Preimage::is_requested(&call_hash)); }); } @@ -151,14 +180,14 @@ fn test_whitelist_call_and_execute_without_note_preimage() { let call_hash = ::Hashing::hash_of(&call); assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); - assert!(Preimage::preimage_requested(&call_hash)); + assert!(Preimage::is_requested(&call_hash)); assert_ok!(Whitelist::dispatch_whitelisted_call_with_preimage( RuntimeOrigin::root(), call.clone() )); - assert!(!Preimage::preimage_requested(&call_hash)); + assert!(!Preimage::is_requested(&call_hash)); assert_noop!( Whitelist::dispatch_whitelisted_call_with_preimage(RuntimeOrigin::root(), call), @@ -176,14 +205,20 @@ fn test_whitelist_call_and_execute_decode_consumes_all() { // Appending something does not make the encoded call invalid. // This tests that the decode function consumes all data. call.extend(call.clone()); + let call_encoded_len = call.len() as u32; let call_hash = ::Hashing::hash(&call[..]); - assert_ok!(Preimage::note_preimage(RuntimeOrigin::root(), call)); + assert_ok!(Preimage::note(call.into())); assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call( + RuntimeOrigin::root(), + call_hash, + call_encoded_len, + call_weight + ), crate::Error::::UndecodableCall, ); }); diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index 22d238d0fdd0f..efd48d657826b 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -18,24 +18,25 @@ //! Autogenerated weights for pallet_whitelist //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-12-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_whitelist // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/whitelist/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_whitelist +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/whitelist/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -49,7 +50,7 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn whitelist_call() -> Weight; fn remove_whitelisted_call() -> Weight; - fn dispatch_whitelisted_call() -> Weight; + fn dispatch_whitelisted_call(n: u32, ) -> Weight; fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight; } @@ -59,38 +60,41 @@ impl WeightInfo for SubstrateWeight { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - // Minimum execution time: 26_352 nanoseconds. - Weight::from_ref_time(26_727_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 26_261 nanoseconds. + Weight::from_ref_time(26_842_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn remove_whitelisted_call() -> Weight { - // Minimum execution time: 25_536 nanoseconds. - Weight::from_ref_time(25_969_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 25_092 nanoseconds. + Weight::from_ref_time(25_903_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) - fn dispatch_whitelisted_call() -> Weight { - // Minimum execution time: 4_802_466 nanoseconds. - Weight::from_ref_time(4_820_197_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Storage: Preimage StatusFor (r:1 w:1) + /// The range of component `n` is `[1, 4194294]`. + fn dispatch_whitelisted_call(n: u32, ) -> Weight { + // Minimum execution time: 36_685 nanoseconds. + Weight::from_ref_time(37_167_000) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(1_144).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - // Minimum execution time: 29_184 nanoseconds. - Weight::from_ref_time(30_530_970 as u64) - // Standard Error: 7 - .saturating_add(Weight::from_ref_time(1_496 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 29_187 nanoseconds. + Weight::from_ref_time(29_896_714) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(1_505).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } } @@ -99,37 +103,40 @@ impl WeightInfo for () { // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn whitelist_call() -> Weight { - // Minimum execution time: 26_352 nanoseconds. - Weight::from_ref_time(26_727_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 26_261 nanoseconds. + Weight::from_ref_time(26_842_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn remove_whitelisted_call() -> Weight { - // Minimum execution time: 25_536 nanoseconds. - Weight::from_ref_time(25_969_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 25_092 nanoseconds. + Weight::from_ref_time(25_903_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) - fn dispatch_whitelisted_call() -> Weight { - // Minimum execution time: 4_802_466 nanoseconds. - Weight::from_ref_time(4_820_197_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Storage: Preimage StatusFor (r:1 w:1) + /// The range of component `n` is `[1, 4194294]`. + fn dispatch_whitelisted_call(n: u32, ) -> Weight { + // Minimum execution time: 36_685 nanoseconds. + Weight::from_ref_time(37_167_000) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(1_144).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Whitelist WhitelistedCall (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - // Minimum execution time: 29_184 nanoseconds. - Weight::from_ref_time(30_530_970 as u64) - // Standard Error: 7 - .saturating_add(Weight::from_ref_time(1_496 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 29_187 nanoseconds. + Weight::from_ref_time(29_896_714) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(1_505).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } } From fafc8e0ba8c98bd22b47913ded414e74a0fcb67f Mon Sep 17 00:00:00 2001 From: Marcin S Date: Tue, 6 Dec 2022 09:55:10 -0500 Subject: [PATCH 1441/1472] Remove `mem_info` and references to `parity-util-mem` (#12795) * Remove mem_info and some references to parity-util-mem * [Draft] Finish removing references to `parity-util-mem` * Upgrade dependencies * Update scripts/ci/deny.toml Co-authored-by: ordian * Fix Cargo.lock (remove unwanted dependency changes) * Removed unused argument * Run cargo fmt (didn't have pre-commit set up) * Fix some CI errors * Fix another CI error * Remove unused dependency Co-authored-by: ordian --- Cargo.lock | 63 +++---------------- bin/node/bench/Cargo.toml | 5 +- bin/node/bench/src/tempdb.rs | 1 - bin/node/cli/Cargo.toml | 5 -- client/api/src/client.rs | 17 ----- client/db/Cargo.toml | 8 +-- client/db/src/lib.rs | 3 +- client/db/src/storage_cache.rs | 10 +-- client/informant/Cargo.toml | 1 - client/informant/src/lib.rs | 16 +---- client/service/Cargo.toml | 3 - client/service/src/builder.rs | 11 +--- client/service/src/metrics.rs | 20 ------ client/state-db/Cargo.toml | 2 - client/state-db/src/lib.rs | 59 ++++------------- client/state-db/src/noncanonical.rs | 3 - client/state-db/src/pruning.rs | 9 +-- client/transaction-pool/Cargo.toml | 1 - .../transaction-pool/src/graph/base_pool.rs | 25 +------- client/transaction-pool/src/graph/future.rs | 33 +--------- client/transaction-pool/src/graph/pool.rs | 9 --- client/transaction-pool/src/graph/ready.rs | 25 +------- .../transaction-pool/src/graph/tracked_map.rs | 2 +- .../src/graph/validated_pool.rs | 10 --- client/transaction-pool/src/lib.rs | 11 ---- client/transaction-pool/tests/pool.rs | 11 ---- frame/support/Cargo.toml | 1 - frame/system/src/lib.rs | 4 +- primitives/database/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 - primitives/runtime/src/generic/block.rs | 9 +-- primitives/runtime/src/generic/digest.rs | 3 +- primitives/runtime/src/generic/header.rs | 24 +------ .../src/generic/unchecked_extrinsic.rs | 12 ---- primitives/runtime/src/lib.rs | 7 --- primitives/runtime/src/testing.rs | 12 +--- primitives/runtime/src/traits.rs | 22 ++----- .../runtime/src/transaction_validity.rs | 1 - primitives/test-primitives/Cargo.toml | 2 - primitives/test-primitives/src/lib.rs | 1 - primitives/trie/Cargo.toml | 5 +- primitives/trie/src/lib.rs | 15 ++--- scripts/ci/deny.toml | 1 - test-utils/runtime/Cargo.toml | 4 +- test-utils/runtime/src/lib.rs | 2 - utils/frame/benchmarking-cli/Cargo.toml | 4 +- 46 files changed, 70 insertions(+), 426 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 736501ecefd79..1ba2462a24caa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2241,7 +2241,6 @@ dependencies = [ "log", "once_cell", "parity-scale-codec", - "parity-util-mem", "paste", "pretty_assertions", "scale-info", @@ -3378,35 +3377,31 @@ dependencies = [ [[package]] name = "kvdb" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585089ceadba0197ffe9af6740ab350b325e3c1f5fccfbc3522e0250c750409b" +checksum = "e7d770dcb02bf6835887c3a979b5107a04ff4bbde97a5f0928d27404a155add9" dependencies = [ - "parity-util-mem", "smallvec", ] [[package]] name = "kvdb-memorydb" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40d109c87bfb7759edd2a49b2649c1afe25af785d930ad6a38479b4dc70dd873" +checksum = "bf7a85fe66f9ff9cd74e169fdd2c94c6e1e74c412c99a73b4df3200b5d3760b2" dependencies = [ "kvdb", - "parity-util-mem", "parking_lot 0.12.1", ] [[package]] name = "kvdb-rocksdb" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c076cc2cdbac89b9910c853a36c957d3862a779f31c2661174222cefb49ee597" +checksum = "2182b8219fee6bd83aacaab7344e840179ae079d5216aa4e249b4d704646a844" dependencies = [ "kvdb", - "log", "num_cpus", - "parity-util-mem", "parking_lot 0.12.1", "regex", "rocksdb", @@ -4081,13 +4076,12 @@ dependencies = [ [[package]] name = "memory-db" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac11bb793c28fa095b7554466f53b3a60a2cd002afdac01bcf135cbd73a269" +checksum = "5e0c7cba9ce19ac7ffd2053ac9f49843bbd3f4318feedfd74e85c19d5fb0ba66" dependencies = [ "hash-db", "hashbrown 0.12.3", - "parity-util-mem", ] [[package]] @@ -4433,7 +4427,6 @@ dependencies = [ "node-primitives", "node-testing", "parity-db", - "parity-util-mem", "rand 0.7.3", "sc-basic-authorship", "sc-client-api", @@ -4527,7 +4520,6 @@ dependencies = [ "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", - "sp-trie", "substrate-build-script-utils", "substrate-frame-cli", "substrate-rpc-client", @@ -6379,33 +6371,6 @@ 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", - "hashbrown 0.12.3", - "impl-trait-for-tuples", - "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", - "syn", - "synstructure", -] - [[package]] name = "parity-wasm" version = "0.45.0" @@ -8066,7 +8031,6 @@ dependencies = [ "futures", "futures-timer", "log", - "parity-util-mem", "sc-client-api", "sc-network-common", "sc-transaction-pool-api", @@ -8498,7 +8462,6 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parity-util-mem", "parking_lot 0.12.1", "pin-project", "rand 0.7.3", @@ -8600,8 +8563,6 @@ version = "0.10.0-dev" dependencies = [ "log", "parity-scale-codec", - "parity-util-mem", - "parity-util-mem-derive", "parking_lot 0.12.1", "sc-client-api", "sp-core", @@ -8715,7 +8676,6 @@ dependencies = [ "linked-hash-map", "log", "parity-scale-codec", - "parity-util-mem", "parking_lot 0.12.1", "sc-block-builder", "sc-client-api", @@ -9723,7 +9683,6 @@ dependencies = [ "impl-trait-for-tuples", "log", "parity-scale-codec", - "parity-util-mem", "paste", "rand 0.7.3", "scale-info", @@ -9908,7 +9867,6 @@ name = "sp-test-primitives" version = "2.0.0" dependencies = [ "parity-scale-codec", - "parity-util-mem", "serde", "sp-application-crypto", "sp-core", @@ -10333,7 +10291,6 @@ dependencies = [ "pallet-babe", "pallet-timestamp", "parity-scale-codec", - "parity-util-mem", "sc-block-builder", "sc-executor", "sc-service", @@ -10850,9 +10807,9 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" [[package]] name = "trie-bench" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dae77b1daad50cd3ed94c506d2dab27e2e47f7b5153a6d4b1992bb3f6028cb" +checksum = "c5b26bd2cdd7641c5beb476b314c0cb1f629832bf21a6235f545e2d47bc9d05a" dependencies = [ "criterion", "hash-db", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 33c9e7c89268f..63087215ae192 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -23,8 +23,8 @@ sp-state-machine = { version = "0.13.0", path = "../../../primitives/state-machi serde = "1.0.136" serde_json = "1.0.85" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } -kvdb = "0.12.0" -kvdb-rocksdb = "0.16.0" +kvdb = "0.13.0" +kvdb-rocksdb = "0.17.0" sp-trie = { version = "7.0.0", path = "../../../primitives/trie" } sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } @@ -37,7 +37,6 @@ tempfile = "3.1.0" fs_extra = "1" rand = { version = "0.7.2", features = ["small_rng"] } lazy_static = "1.4.0" -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } parity-db = "0.4.2" sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } diff --git a/bin/node/bench/src/tempdb.rs b/bin/node/bench/src/tempdb.rs index eb3bb1d3fccd7..82895ddfab69d 100644 --- a/bin/node/bench/src/tempdb.rs +++ b/bin/node/bench/src/tempdb.rs @@ -29,7 +29,6 @@ pub enum DatabaseType { pub struct TempDatabase(tempfile::TempDir); struct ParityDbWrapper(parity_db::Db); -parity_util_mem::malloc_size_of_is_0!(ParityDbWrapper); impl KeyValueDB for ParityDbWrapper { /// Get a value by key. diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 108923265fb1f..cb2baf9e0de30 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -101,11 +101,6 @@ node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../utils/frame/try-runtime/cli" } serde_json = "1.0.85" -[target.'cfg(any(target_arch="x86_64", target_arch="aarch64"))'.dependencies] -sp-trie = { version = "7.0.0", default-features = false, path = "../../../primitives/trie", features = [ - "memory-tracker", -] } - [dev-dependencies] sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } sc-client-db = { version = "0.10.0-dev", path = "../../../client/db" } diff --git a/client/api/src/client.rs b/client/api/src/client.rs index bb88853d23afb..05e3163dcc7bd 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -197,17 +197,6 @@ impl fmt::Display for MemorySize { } } -/// Memory statistics for state db. -#[derive(Default, Clone, Debug)] -pub struct StateDbMemoryInfo { - /// Memory usage of the non-canonical overlay - pub non_canonical: MemorySize, - /// Memory usage of the pruning window. - pub pruning: Option, - /// Memory usage of the pinned blocks. - pub pinned: MemorySize, -} - /// Memory statistics for client instance. #[derive(Default, Clone, Debug)] pub struct MemoryInfo { @@ -215,8 +204,6 @@ pub struct MemoryInfo { pub state_cache: MemorySize, /// Size of backend database cache. pub database_cache: MemorySize, - /// Size of the state db. - pub state_db: StateDbMemoryInfo, } /// I/O statistics for client instance. @@ -264,13 +251,9 @@ impl fmt::Display for UsageInfo { write!( f, "caches: ({} state, {} db overlay), \ - state db: ({} non-canonical, {} pruning, {} pinned), \ i/o: ({} tx, {} write, {} read, {} avg tx, {}/{} key cache reads/total, {} trie nodes writes)", self.memory.state_cache, self.memory.database_cache, - self.memory.state_db.non_canonical, - self.memory.state_db.pruning.unwrap_or_default(), - self.memory.state_db.pinned, self.io.transactions, self.io.bytes_written, self.io.bytes_read, diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index dda1a640d886f..ee879a161edfe 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } hash-db = "0.15.2" -kvdb = "0.12.0" -kvdb-memorydb = "0.12.0" -kvdb-rocksdb = { version = "0.16.0", optional = true } +kvdb = "0.13.0" +kvdb-memorydb = "0.13.0" +kvdb-rocksdb = { version = "0.17.0", optional = true } linked-hash-map = "0.5.4" log = "0.4.17" parity-db = "0.4.2" @@ -36,7 +36,7 @@ sp-trie = { version = "7.0.0", path = "../../primitives/trie" } [dev-dependencies] criterion = "0.3.3" -kvdb-rocksdb = "0.16.0" +kvdb-rocksdb = "0.17.0" rand = "0.8.4" tempfile = "3.1.0" quickcheck = { version = "1.0.3", default-features = false } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 305db2284b2ed..426876f5cba8c 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -2086,10 +2086,9 @@ impl sc_client_api::backend::Backend for Backend { let state_cache = MemorySize::from_bytes( self.shared_trie_cache.as_ref().map_or(0, |c| c.used_memory_size()), ); - let state_db = self.storage.state_db.memory_info(); Some(UsageInfo { - memory: MemoryInfo { state_cache, database_cache, state_db }, + memory: MemoryInfo { state_cache, database_cache }, io: IoInfo { transactions: io_stats.transactions, bytes_read: io_stats.bytes_read, diff --git a/client/db/src/storage_cache.rs b/client/db/src/storage_cache.rs index d9253fe09eb50..474599e5d74e8 100644 --- a/client/db/src/storage_cache.rs +++ b/client/db/src/storage_cache.rs @@ -59,15 +59,11 @@ pub struct Cache { struct LRUMap(LinkedHashMap, usize, usize); -/// Internal trait similar to `heapsize` but using -/// a simply estimation. +/// Internal trait similar to `heapsize` but using a simple estimation. /// -/// This should not be made public, it is implementation -/// detail trait. If it need to become public please -/// consider using `malloc_size_of`. +/// This should not be made public, it is an implementation detail trait. trait EstimateSize { - /// Return a size estimation of additional size needed - /// to cache this struct (in bytes). + /// Return a size estimation of the additional size needed to cache this struct (in bytes). fn estimate_size(&self) -> usize; } diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index 682a754ba16a6..a432c2ada5c61 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -17,7 +17,6 @@ ansi_term = "0.12.1" futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.17" -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/informant/src/lib.rs b/client/informant/src/lib.rs index 52f1c95fe0198..b03b92686e2aa 100644 --- a/client/informant/src/lib.rs +++ b/client/informant/src/lib.rs @@ -22,10 +22,8 @@ use ansi_term::Colour; use futures::prelude::*; use futures_timer::Delay; use log::{debug, info, trace}; -use parity_util_mem::MallocSizeOf; use sc_client_api::{BlockchainEvents, UsageProvider}; use sc_network_common::service::NetworkStatusProvider; -use sc_transaction_pool_api::TransactionPool; use sp_blockchain::HeaderMetadata; use sp_runtime::traits::{Block as BlockT, Header}; use std::{collections::VecDeque, fmt::Display, sync::Arc, time::Duration}; @@ -53,16 +51,11 @@ impl Default for OutputFormat { } /// Builds the informant and returns a `Future` that drives the informant. -pub async fn build( - client: Arc, - network: N, - pool: Arc

, - format: OutputFormat, -) where +pub async fn build(client: Arc, network: N, format: OutputFormat) +where N: NetworkStatusProvider, C: UsageProvider + HeaderMetadata + BlockchainEvents, >::Error: Display, - P: TransactionPool + MallocSizeOf, { let mut display = display::InformantDisplay::new(format.clone()); @@ -83,11 +76,6 @@ pub async fn build( "Usage statistics not displayed as backend does not provide it", ) } - trace!( - target: "usage", - "Subsystems memory [txpool: {} kB]", - parity_util_mem::malloc_size(&*pool) / 1024, - ); display.display(&info, net_status); future::ready(()) }); diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 8b17a8287c274..87949ef12d888 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -80,9 +80,6 @@ sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } sc-sysinfo = { version = "6.0.0-dev", path = "../sysinfo" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } -parity-util-mem = { version = "0.12.0", default-features = false, features = [ - "primitive-types", -] } async-trait = "0.1.57" tokio = { version = "1.22.0", features = ["time", "rt-multi-thread", "parking_lot"] } tempfile = "3.1.0" diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index df20f2009ee09..dd89ce6dff10a 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -436,9 +436,7 @@ where TBl::Hash: Unpin, TBl::Header: Unpin, TBackend: 'static + sc_client_api::backend::Backend + Send, - TExPool: MaintainedTransactionPool::Hash> - + parity_util_mem::MallocSizeOf - + 'static, + TExPool: MaintainedTransactionPool::Hash> + 'static, { let SpawnTasksParams { mut config, @@ -540,12 +538,7 @@ where spawn_handle.spawn( "informant", None, - sc_informant::build( - client.clone(), - network, - transaction_pool.clone(), - config.informant_output_format, - ), + sc_informant::build(client.clone(), network, config.informant_output_format), ); task_manager.keep_alive((config.base_path, rpc)); diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index 13b249a7b9563..c83b3988f9fa3 100644 --- a/client/service/src/metrics.rs +++ b/client/service/src/metrics.rs @@ -43,7 +43,6 @@ struct PrometheusMetrics { // I/O database_cache: Gauge, state_cache: Gauge, - state_db: GaugeVec, } impl PrometheusMetrics { @@ -117,13 +116,6 @@ impl PrometheusMetrics { Gauge::new("substrate_state_cache_bytes", "State cache size in bytes")?, registry, )?, - state_db: register( - GaugeVec::new( - Opts::new("substrate_state_db_cache_bytes", "State DB cache in bytes"), - &["subtype"], - )?, - registry, - )?, }) } } @@ -254,18 +246,6 @@ impl MetricsService { if let Some(info) = info.usage.as_ref() { metrics.database_cache.set(info.memory.database_cache.as_bytes() as u64); metrics.state_cache.set(info.memory.state_cache.as_bytes() as u64); - - metrics - .state_db - .with_label_values(&["non_canonical"]) - .set(info.memory.state_db.non_canonical.as_bytes() as u64); - if let Some(pruning) = info.memory.state_db.pruning { - metrics.state_db.with_label_values(&["pruning"]).set(pruning.as_bytes() as u64); - } - metrics - .state_db - .with_label_values(&["pinned"]) - .set(info.memory.state_db.pinned.as_bytes() as u64); } } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 07c08363287d6..b6d40a8106322 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -15,8 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } log = "0.4.17" -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } -parity-util-mem-derive = "0.1.0" parking_lot = "0.12.1" sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-core = { version = "7.0.0", path = "../../primitives/core" } diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 01a198a1b3c1e..94d41787701b3 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -49,10 +49,8 @@ mod test; use codec::Codec; use log::trace; use noncanonical::NonCanonicalOverlay; -use parity_util_mem::{malloc_size, MallocSizeOf}; use parking_lot::RwLock; use pruning::{HaveBlock, RefWindow}; -use sc_client_api::{MemorySize, StateDbMemoryInfo}; use std::{ collections::{hash_map::Entry, HashMap}, fmt, @@ -220,8 +218,6 @@ pub struct Constraints { /// Maximum blocks. Defaults to 0 when unspecified, effectively keeping only non-canonical /// states. pub max_blocks: Option, - /// Maximum memory in the pruning overlay. - pub max_mem: Option, } /// Pruning mode. @@ -238,7 +234,7 @@ pub enum PruningMode { impl PruningMode { /// Create a mode that keeps given number of blocks. pub fn blocks_pruning(n: u32) -> PruningMode { - PruningMode::Constrained(Constraints { max_blocks: Some(n), max_mem: None }) + PruningMode::Constrained(Constraints { max_blocks: Some(n) }) } /// Is this an archive (either ArchiveAll or ArchiveCanonical) pruning mode? @@ -276,7 +272,7 @@ impl Default for PruningMode { impl Default for Constraints { fn default() -> Self { - Self { max_blocks: Some(DEFAULT_MAX_BLOCK_CONSTRAINT), max_mem: None } + Self { max_blocks: Some(DEFAULT_MAX_BLOCK_CONSTRAINT) } } } @@ -294,9 +290,7 @@ pub struct StateDbSync { ref_counting: bool, } -impl - StateDbSync -{ +impl StateDbSync { fn new( mode: PruningMode, ref_counting: bool, @@ -306,8 +300,7 @@ impl let non_canonical: NonCanonicalOverlay = NonCanonicalOverlay::new(&db)?; let pruning: Option> = match mode { - PruningMode::Constrained(Constraints { max_mem: Some(_), .. }) => unimplemented!(), - PruningMode::Constrained(Constraints { max_blocks, .. }) => + PruningMode::Constrained(Constraints { max_blocks }) => Some(RefWindow::new(db, max_blocks.unwrap_or(0), ref_counting)?), PruningMode::ArchiveAll | PruningMode::ArchiveCanonical => None, }; @@ -392,10 +385,6 @@ impl break } - if constraints.max_mem.map_or(false, |m| pruning.mem_used() > m) { - break - } - let pinned = &self.pinned; match pruning.next_hash() { // the block record is temporary unavailable, break and try next time @@ -496,14 +485,6 @@ impl } db.get(key.as_ref()).map_err(Error::Db) } - - fn memory_info(&self) -> StateDbMemoryInfo { - StateDbMemoryInfo { - non_canonical: MemorySize::from_bytes(malloc_size(&self.non_canonical)), - pruning: self.pruning.as_ref().map(|p| MemorySize::from_bytes(malloc_size(&p))), - pinned: MemorySize::from_bytes(malloc_size(&self.pinned)), - } - } } /// State DB maintenance. See module description. @@ -512,9 +493,7 @@ pub struct StateDb { db: RwLock>, } -impl - StateDb -{ +impl StateDb { /// Create an instance of [`StateDb`]. pub fn open( db: D, @@ -637,11 +616,6 @@ impl *state_db = StateDbSync::new(state_db.mode.clone(), state_db.ref_counting, db)?; Ok(()) } - - /// Returns the current memory statistics of this instance. - pub fn memory_info(&self) -> StateDbMemoryInfo { - self.db.read().memory_info() - } } /// The result return by `StateDb::is_pruned` @@ -772,10 +746,8 @@ mod tests { #[test] fn block_record_unavailable() { - let (mut db, state_db) = make_test_db(PruningMode::Constrained(Constraints { - max_blocks: Some(1), - max_mem: None, - })); + let (mut db, state_db) = + make_test_db(PruningMode::Constrained(Constraints { max_blocks: Some(1) })); // import 2 blocks for i in &[5, 6] { db.commit( @@ -809,19 +781,13 @@ mod tests { #[test] fn prune_window_0() { - let (db, _) = make_test_db(PruningMode::Constrained(Constraints { - max_blocks: Some(0), - max_mem: None, - })); + let (db, _) = make_test_db(PruningMode::Constrained(Constraints { max_blocks: Some(0) })); assert!(db.data_eq(&make_db(&[21, 3, 922, 94]))); } #[test] fn prune_window_1() { - let (db, sdb) = make_test_db(PruningMode::Constrained(Constraints { - max_blocks: Some(1), - max_mem: None, - })); + let (db, sdb) = make_test_db(PruningMode::Constrained(Constraints { max_blocks: Some(1) })); assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(0), 0), IsPruned::Pruned); assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(1), 1), IsPruned::Pruned); assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(21), 2), IsPruned::Pruned); @@ -831,10 +797,7 @@ mod tests { #[test] fn prune_window_2() { - let (db, sdb) = make_test_db(PruningMode::Constrained(Constraints { - max_blocks: Some(2), - max_mem: None, - })); + let (db, sdb) = make_test_db(PruningMode::Constrained(Constraints { max_blocks: Some(2) })); assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(0), 0), IsPruned::Pruned); assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(1), 1), IsPruned::Pruned); assert_eq!(sdb.is_pruned(&H256::from_low_u64_be(21), 2), IsPruned::NotPruned); @@ -858,7 +821,7 @@ mod tests { ) .unwrap(), ); - let new_mode = PruningMode::Constrained(Constraints { max_blocks: Some(2), max_mem: None }); + let new_mode = PruningMode::Constrained(Constraints { max_blocks: Some(2) }); let state_db_open_result: Result<(_, StateDb), _> = StateDb::open(db.clone(), Some(new_mode), false, false); assert!(state_db_open_result.is_err()); diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index 3711cf7a42667..df09a9c017747 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -30,7 +30,6 @@ pub(crate) const LAST_CANONICAL: &[u8] = b"last_canonical"; const MAX_BLOCKS_PER_LEVEL: u64 = 32; /// See module documentation. -#[derive(parity_util_mem_derive::MallocSizeOf)] pub struct NonCanonicalOverlay { last_canonicalized: Option<(BlockHash, u64)>, levels: VecDeque>, @@ -41,7 +40,6 @@ pub struct NonCanonicalOverlay { pinned_insertions: HashMap, u32)>, } -#[derive(parity_util_mem_derive::MallocSizeOf)] #[cfg_attr(test, derive(PartialEq, Debug))] struct OverlayLevel { blocks: Vec>, @@ -81,7 +79,6 @@ fn to_journal_key(block: u64, index: u64) -> Vec { } #[cfg_attr(test, derive(PartialEq, Debug))] -#[derive(parity_util_mem_derive::MallocSizeOf)] struct BlockOverlay { hash: BlockHash, journal_index: u64, diff --git a/client/state-db/src/pruning.rs b/client/state-db/src/pruning.rs index 458522b8119fd..d942fb2428b6a 100644 --- a/client/state-db/src/pruning.rs +++ b/client/state-db/src/pruning.rs @@ -36,7 +36,6 @@ pub(crate) const LAST_PRUNED: &[u8] = b"last_pruned"; const PRUNING_JOURNAL: &[u8] = b"pruning_journal"; /// See module documentation. -#[derive(parity_util_mem_derive::MallocSizeOf)] pub struct RefWindow { /// A queue of blocks keep tracking keys that should be deleted for each block in the /// pruning window. @@ -50,7 +49,6 @@ pub struct RefWindow { /// blocks in memory, and keep track of re-inserted keys to not delete them when pruning /// - `DbBacked`, used when the backend database supports reference counting, only keep /// a few number of blocks in memory and load more blocks on demand -#[derive(parity_util_mem_derive::MallocSizeOf)] enum DeathRowQueue { Mem { /// A queue of keys that should be deleted for each block in the pruning window. @@ -60,7 +58,6 @@ enum DeathRowQueue { }, DbBacked { // The backend database - #[ignore_malloc_size_of = "Shared data"] db: D, /// A queue of keys that should be deleted for each block in the pruning window. /// Only caching the first few blocks of the pruning window, blocks inside are @@ -251,7 +248,7 @@ fn load_death_row_from_db( } } -#[derive(Clone, Debug, PartialEq, Eq, parity_util_mem_derive::MallocSizeOf)] +#[derive(Clone, Debug, PartialEq, Eq)] struct DeathRow { hash: BlockHash, deleted: HashSet, @@ -345,10 +342,6 @@ impl RefWindow { Ok(res) } - pub fn mem_used(&self) -> usize { - 0 - } - fn is_empty(&self) -> bool { self.window_size() == 0 } diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index f7f644a6b059b..7a3ab042d5a13 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -19,7 +19,6 @@ futures = "0.3.21" futures-timer = "3.0.2" linked-hash-map = "0.5.4" log = "0.4.17" -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } parking_lot = "0.12.1" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" diff --git a/client/transaction-pool/src/graph/base_pool.rs b/client/transaction-pool/src/graph/base_pool.rs index 8e0422739cc63..67580d698b8c1 100644 --- a/client/transaction-pool/src/graph/base_pool.rs +++ b/client/transaction-pool/src/graph/base_pool.rs @@ -84,7 +84,7 @@ pub struct PruneStatus { /// Immutable transaction #[cfg_attr(test, derive(Clone))] -#[derive(PartialEq, Eq, parity_util_mem::MallocSizeOf)] +#[derive(PartialEq, Eq)] pub struct Transaction { /// Raw extrinsic representing that transaction. pub data: Extrinsic, @@ -207,7 +207,7 @@ const RECENTLY_PRUNED_TAGS: usize = 2; /// as-is for the second time will fail or produce unwanted results. /// Most likely it is required to revalidate them and recompute set of /// required tags. -#[derive(Debug, parity_util_mem::MallocSizeOf)] +#[derive(Debug)] pub struct BasePool { reject_future_transactions: bool, future: FutureTransactions, @@ -796,27 +796,6 @@ mod tests { } } - #[test] - fn can_track_heap_size() { - let mut pool = pool(); - pool.import(Transaction { - data: vec![5u8; 1024], - hash: 5, - provides: vec![vec![0], vec![4]], - ..DEFAULT_TX.clone() - }) - .expect("import 1 should be ok"); - pool.import(Transaction { - data: vec![3u8; 1024], - hash: 7, - provides: vec![vec![2], vec![7]], - ..DEFAULT_TX.clone() - }) - .expect("import 2 should be ok"); - - assert!(parity_util_mem::malloc_size(&pool) > 5000); - } - #[test] fn should_remove_invalid_transactions() { // given diff --git a/client/transaction-pool/src/graph/future.rs b/client/transaction-pool/src/graph/future.rs index ae49e3f2d3aed..d23b5f2b6e1f1 100644 --- a/client/transaction-pool/src/graph/future.rs +++ b/client/transaction-pool/src/graph/future.rs @@ -28,7 +28,6 @@ use std::time::Instant; use super::base_pool::Transaction; -#[derive(parity_util_mem::MallocSizeOf)] /// Transaction with partially satisfied dependencies. pub struct WaitingTransaction { /// Transaction details. @@ -108,7 +107,7 @@ impl WaitingTransaction { /// /// Contains transactions that are still awaiting for some other transactions that /// could provide a tag that they require. -#[derive(Debug, parity_util_mem::MallocSizeOf)] +#[derive(Debug)] pub struct FutureTransactions { /// tags that are not yet provided by any transaction and we await for them wanted_tags: HashMap>, @@ -251,33 +250,3 @@ impl FutureTransactions { self.waiting.values().fold(0, |acc, tx| acc + tx.transaction.bytes) } } - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::transaction_validity::TransactionSource; - - #[test] - fn can_track_heap_size() { - let mut future = FutureTransactions::default(); - future.import(WaitingTransaction { - transaction: Transaction { - data: vec![0u8; 1024], - bytes: 1, - hash: 1, - priority: 1, - valid_till: 2, - requires: vec![vec![1], vec![2]], - provides: vec![vec![3], vec![4]], - propagate: true, - source: TransactionSource::External, - } - .into(), - missing_tags: vec![vec![1u8], vec![2u8]].into_iter().collect(), - imported_at: std::time::Instant::now(), - }); - - // data is at least 1024! - assert!(parity_util_mem::malloc_size(&future) > 1024); - } -} diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 7b3a8db15982a..9c747ade1229a 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -144,15 +144,6 @@ pub struct Pool { validated_pool: Arc>, } -impl parity_util_mem::MallocSizeOf for Pool -where - ExtrinsicFor: parity_util_mem::MallocSizeOf, -{ - fn size_of(&self, ops: &mut parity_util_mem::MallocSizeOfOps) -> usize { - self.validated_pool.size_of(ops) - } -} - impl Pool { /// Create a new transaction pool. pub fn new(options: Options, is_validator: IsValidator, api: Arc) -> Self { diff --git a/client/transaction-pool/src/graph/ready.rs b/client/transaction-pool/src/graph/ready.rs index 220e69b13e7eb..b52372a3c4d10 100644 --- a/client/transaction-pool/src/graph/ready.rs +++ b/client/transaction-pool/src/graph/ready.rs @@ -37,7 +37,7 @@ use super::{ /// An in-pool transaction reference. /// /// Should be cheap to clone. -#[derive(Debug, parity_util_mem::MallocSizeOf)] +#[derive(Debug)] pub struct TransactionRef { /// The actual transaction data. pub transaction: Arc>, @@ -74,7 +74,7 @@ impl PartialEq for TransactionRef { } impl Eq for TransactionRef {} -#[derive(Debug, parity_util_mem::MallocSizeOf)] +#[derive(Debug)] pub struct ReadyTx { /// A reference to a transaction pub transaction: TransactionRef, @@ -105,7 +105,7 @@ qed "#; /// Validated transactions that are block ready with all their dependencies met. -#[derive(Debug, parity_util_mem::MallocSizeOf)] +#[derive(Debug)] pub struct ReadyTransactions { /// Next free insertion id (used to indicate when a transaction was inserted into the pool). insertion_id: u64, @@ -742,25 +742,6 @@ mod tests { assert_eq!(it.next(), None); } - #[test] - fn can_report_heap_size() { - let mut ready = ReadyTransactions::default(); - let tx = Transaction { - data: vec![5], - bytes: 1, - hash: 5, - priority: 1, - valid_till: u64::MAX, // use the max here for testing. - requires: vec![], - provides: vec![], - propagate: true, - source: Source::External, - }; - import(&mut ready, tx).unwrap(); - - assert!(parity_util_mem::malloc_size(&ready) > 200); - } - #[test] fn should_order_refs() { let mut id = 1; diff --git a/client/transaction-pool/src/graph/tracked_map.rs b/client/transaction-pool/src/graph/tracked_map.rs index 32d04b0068877..7292293258f57 100644 --- a/client/transaction-pool/src/graph/tracked_map.rs +++ b/client/transaction-pool/src/graph/tracked_map.rs @@ -33,7 +33,7 @@ pub trait Size { /// Map with size tracking. /// /// Size reported might be slightly off and only approximately true. -#[derive(Debug, parity_util_mem::MallocSizeOf)] +#[derive(Debug)] pub struct TrackedMap { index: Arc>>, bytes: AtomicIsize, diff --git a/client/transaction-pool/src/graph/validated_pool.rs b/client/transaction-pool/src/graph/validated_pool.rs index dcb8195073733..ab99a090e5654 100644 --- a/client/transaction-pool/src/graph/validated_pool.rs +++ b/client/transaction-pool/src/graph/validated_pool.rs @@ -110,16 +110,6 @@ pub struct ValidatedPool { rotator: PoolRotator>, } -impl parity_util_mem::MallocSizeOf for ValidatedPool -where - ExtrinsicFor: parity_util_mem::MallocSizeOf, -{ - fn size_of(&self, ops: &mut parity_util_mem::MallocSizeOfOps) -> usize { - // other entries insignificant or non-primary references - self.pool.size_of(ops) - } -} - impl ValidatedPool { /// Create a new transaction pool. pub fn new(options: Options, is_validator: IsValidator, api: Arc) -> Self { diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index a441bf9b2a9a0..0124038b75949 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -135,17 +135,6 @@ impl ReadyPoll { } } -impl parity_util_mem::MallocSizeOf for BasicPool -where - PoolApi: graph::ChainApi, - Block: BlockT, -{ - fn size_of(&self, ops: &mut parity_util_mem::MallocSizeOfOps) -> usize { - // other entries insignificant or non-primary references - self.pool.size_of(ops) - } -} - /// Type of revalidation. pub enum RevalidationType { /// Light revalidation type. diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 27891432753a4..7ba61e58b4cb5 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -440,17 +440,6 @@ fn should_push_watchers_during_maintenance() { ); } -#[test] -fn can_track_heap_size() { - let (pool, _api, _guard) = maintained_pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).expect("1. Imported"); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).expect("1. Imported"); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 211))).expect("1. Imported"); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 212))).expect("1. Imported"); - - assert!(parity_util_mem::malloc_size(&pool) > 3000); -} - #[test] fn finalization() { let xt = uxt(Alice, 209); diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index b199c014d35ed..4945b5ab915f9 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -44,7 +44,6 @@ serde_json = "1.0.85" assert_matches = "1.3.0" pretty_assertions = "1.2.1" frame-system = { version = "4.0.0-dev", path = "../system" } -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } [features] default = ["std"] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 7c4c4683958e3..f7e3849beeb8d 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -72,7 +72,7 @@ use sp_runtime::{ generic, traits::{ self, AtLeast32Bit, AtLeast32BitUnsigned, BadOrigin, BlockNumberProvider, Bounded, - CheckEqual, Dispatchable, Hash, Lookup, LookupError, MaybeDisplay, MaybeMallocSizeOf, + CheckEqual, Dispatchable, Hash, Lookup, LookupError, MaybeDisplay, MaybeSerializeDeserialize, Member, One, Saturating, SimpleBitOps, StaticLookup, Zero, }, DispatchError, RuntimeDebug, @@ -250,7 +250,6 @@ pub mod pallet { + Copy + sp_std::hash::Hash + sp_std::str::FromStr - + MaybeMallocSizeOf + MaxEncodedLen + TypeInfo; @@ -268,7 +267,6 @@ pub mod pallet { + sp_std::hash::Hash + AsRef<[u8]> + AsMut<[u8]> - + MaybeMallocSizeOf + MaxEncodedLen; /// The hashing system (algorithm) being used in the runtime (e.g. Blake2). diff --git a/primitives/database/Cargo.toml b/primitives/database/Cargo.toml index f19a647fed032..b1105f88ba50f 100644 --- a/primitives/database/Cargo.toml +++ b/primitives/database/Cargo.toml @@ -11,5 +11,5 @@ documentation = "https://docs.rs/sp-database" readme = "README.md" [dependencies] -kvdb = "0.12.0" +kvdb = "0.13.0" parking_lot = "0.12.1" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 578c01583f87c..8ea6ed3eb3b19 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -19,7 +19,6 @@ either = { version = "1.5", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"], optional = true } paste = "1.0" rand = { version = "0.7.2", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } @@ -48,7 +47,6 @@ std = [ "either/use_std", "hash256-std-hasher/std", "log/std", - "parity-util-mem/std", "rand", "scale-info/std", "serde", diff --git a/primitives/runtime/src/generic/block.rs b/primitives/runtime/src/generic/block.rs index 2cd350b2c5ba1..3b01633635c24 100644 --- a/primitives/runtime/src/generic/block.rs +++ b/primitives/runtime/src/generic/block.rs @@ -25,10 +25,7 @@ use serde::{Deserialize, Serialize}; use crate::{ codec::{Codec, Decode, Encode}, - traits::{ - self, Block as BlockT, Header as HeaderT, MaybeMallocSizeOf, MaybeSerialize, Member, - NumberFor, - }, + traits::{self, Block as BlockT, Header as HeaderT, MaybeSerialize, Member, NumberFor}, Justifications, }; use sp_core::RuntimeDebug; @@ -82,7 +79,7 @@ impl fmt::Display for BlockId { /// Abstraction over a substrate block. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, parity_util_mem::MallocSizeOf))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))] pub struct Block { @@ -95,7 +92,7 @@ pub struct Block { impl traits::Block for Block where Header: HeaderT, - Extrinsic: Member + Codec + traits::Extrinsic + MaybeMallocSizeOf, + Extrinsic: Member + Codec + traits::Extrinsic, { type Extrinsic = Extrinsic; type Header = Header; diff --git a/primitives/runtime/src/generic/digest.rs b/primitives/runtime/src/generic/digest.rs index ec74ebb0d4e15..1d1173057ea8d 100644 --- a/primitives/runtime/src/generic/digest.rs +++ b/primitives/runtime/src/generic/digest.rs @@ -34,7 +34,7 @@ use sp_core::RuntimeDebug; /// Generic header digest. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, parity_util_mem::MallocSizeOf))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct Digest { /// A list of logs in the digest. pub logs: Vec, @@ -70,7 +70,6 @@ impl Digest { /// Digest item that is able to encode/decode 'system' digest items and /// provide opaque access to other items. #[derive(PartialEq, Eq, Clone, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(parity_util_mem::MallocSizeOf))] pub enum DigestItem { /// A pre-runtime digest. /// diff --git a/primitives/runtime/src/generic/header.rs b/primitives/runtime/src/generic/header.rs index a7b43608f2b78..04d09f6b15541 100644 --- a/primitives/runtime/src/generic/header.rs +++ b/primitives/runtime/src/generic/header.rs @@ -22,7 +22,7 @@ use crate::{ generic::Digest, scale_info::TypeInfo, traits::{ - self, AtLeast32BitUnsigned, Hash as HashT, MaybeDisplay, MaybeMallocSizeOf, MaybeSerialize, + self, AtLeast32BitUnsigned, Hash as HashT, MaybeDisplay, MaybeSerialize, MaybeSerializeDeserialize, Member, SimpleBitOps, }, }; @@ -54,22 +54,6 @@ pub struct Header + TryFrom, Hash: HashT> { pub digest: Digest, } -#[cfg(feature = "std")] -impl parity_util_mem::MallocSizeOf for Header -where - Number: Copy + Into + TryFrom + parity_util_mem::MallocSizeOf, - Hash: HashT, - Hash::Output: parity_util_mem::MallocSizeOf, -{ - fn size_of(&self, ops: &mut parity_util_mem::MallocSizeOfOps) -> usize { - self.parent_hash.size_of(ops) + - self.number.size_of(ops) + - self.state_root.size_of(ops) + - self.extrinsics_root.size_of(ops) + - self.digest.size_of(ops) - } -} - #[cfg(feature = "std")] pub fn serialize_number + TryFrom>( val: &T, @@ -103,8 +87,7 @@ where + Copy + Into + TryFrom - + sp_std::str::FromStr - + MaybeMallocSizeOf, + + sp_std::str::FromStr, Hash: HashT, Hash::Output: Default + sp_std::hash::Hash @@ -115,8 +98,7 @@ where + Debug + MaybeDisplay + SimpleBitOps - + Codec - + MaybeMallocSizeOf, + + Codec, { type Number = Number; type Hash = ::Output; diff --git a/primitives/runtime/src/generic/unchecked_extrinsic.rs b/primitives/runtime/src/generic/unchecked_extrinsic.rs index fb333abd6ac6e..5d378410e4756 100644 --- a/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -87,18 +87,6 @@ where } } -#[cfg(feature = "std")] -impl parity_util_mem::MallocSizeOf - for UncheckedExtrinsic -where - Extra: SignedExtension, -{ - fn size_of(&self, _ops: &mut parity_util_mem::MallocSizeOfOps) -> usize { - // Instantiated only in runtime. - 0 - } -} - impl UncheckedExtrinsic { diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 3752e31cbeeb0..e94efda86aa03 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -874,13 +874,6 @@ impl OpaqueExtrinsic { } } -#[cfg(feature = "std")] -impl parity_util_mem::MallocSizeOf for OpaqueExtrinsic { - fn size_of(&self, ops: &mut parity_util_mem::MallocSizeOfOps) -> usize { - self.0.size_of(ops) - } -} - impl sp_std::fmt::Debug for OpaqueExtrinsic { #[cfg(feature = "std")] fn fmt(&self, fmt: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index d16a37e6a2059..0cd78ba6267dd 100644 --- a/primitives/runtime/src/testing.rs +++ b/primitives/runtime/src/testing.rs @@ -204,13 +204,10 @@ impl Header { } /// An opaque extrinsic wrapper type. -#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode, parity_util_mem::MallocSizeOf)] +#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)] pub struct ExtrinsicWrapper(Xt); -impl traits::Extrinsic for ExtrinsicWrapper -where - Xt: parity_util_mem::MallocSizeOf, -{ +impl traits::Extrinsic for ExtrinsicWrapper { type Call = (); type SignaturePayload = (); @@ -243,7 +240,7 @@ impl Deref for ExtrinsicWrapper { } /// Testing block -#[derive(PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode, parity_util_mem::MallocSizeOf)] +#[derive(PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode)] pub struct Block { /// Block header pub header: Header, @@ -306,9 +303,6 @@ impl TestXt { } } -// Non-opaque extrinsics always 0. -parity_util_mem::malloc_size_of_is_0!(any: TestXt); - impl Serialize for TestXt where TestXt: Encode, diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 276a62349a175..6af711cba8e50 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -808,9 +808,6 @@ sp_core::impl_maybe_marker!( /// A type that implements Serialize, DeserializeOwned and Debug when in std environment. trait MaybeSerializeDeserialize: DeserializeOwned, Serialize; - - /// A type that implements MallocSizeOf. - trait MaybeMallocSizeOf: parity_util_mem::MallocSizeOf; ); /// A type that can be used in runtime structures. @@ -828,9 +825,7 @@ pub trait IsMember { /// `parent_hash`, as well as a `digest` and a block `number`. /// /// You can also create a `new` one from those fields. -pub trait Header: - Clone + Send + Sync + Codec + Eq + MaybeSerialize + Debug + MaybeMallocSizeOf + 'static -{ +pub trait Header: Clone + Send + Sync + Codec + Eq + MaybeSerialize + Debug + 'static { /// Header number. type Number: Member + MaybeSerializeDeserialize @@ -840,8 +835,7 @@ pub trait Header: + MaybeDisplay + AtLeast32BitUnsigned + Codec - + sp_std::str::FromStr - + MaybeMallocSizeOf; + + sp_std::str::FromStr; /// Header hash type type Hash: Member + MaybeSerializeDeserialize @@ -855,7 +849,6 @@ pub trait Header: + Codec + AsRef<[u8]> + AsMut<[u8]> - + MaybeMallocSizeOf + TypeInfo; /// Hashing algorithm type Hashing: Hash; @@ -904,13 +897,11 @@ pub trait Header: /// `Extrinsic` pieces of information as well as a `Header`. /// /// You can get an iterator over each of the `extrinsics` and retrieve the `header`. -pub trait Block: - Clone + Send + Sync + Codec + Eq + MaybeSerialize + Debug + MaybeMallocSizeOf + 'static -{ +pub trait Block: Clone + Send + Sync + Codec + Eq + MaybeSerialize + Debug + 'static { /// Type for extrinsics. - type Extrinsic: Member + Codec + Extrinsic + MaybeSerialize + MaybeMallocSizeOf; + type Extrinsic: Member + Codec + Extrinsic + MaybeSerialize; /// Header type. - type Header: Header + MaybeMallocSizeOf; + type Header: Header; /// Block hash type. type Hash: Member + MaybeSerializeDeserialize @@ -924,7 +915,6 @@ pub trait Block: + Codec + AsRef<[u8]> + AsMut<[u8]> - + MaybeMallocSizeOf + TypeInfo; /// Returns a reference to the header. @@ -945,7 +935,7 @@ pub trait Block: } /// Something that acts like an `Extrinsic`. -pub trait Extrinsic: Sized + MaybeMallocSizeOf { +pub trait Extrinsic: Sized { /// The function call. type Call; diff --git a/primitives/runtime/src/transaction_validity.rs b/primitives/runtime/src/transaction_validity.rs index d8e71cc2761ec..3b89644c28647 100644 --- a/primitives/runtime/src/transaction_validity.rs +++ b/primitives/runtime/src/transaction_validity.rs @@ -227,7 +227,6 @@ impl From for TransactionValidity { /// For instance we can disallow specific kinds of transactions if they were not produced /// by our local node (for instance off-chain workers). #[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(parity_util_mem::MallocSizeOf))] pub enum TransactionSource { /// Transaction is already included in block. /// diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 6cfd17afcc5fd..1d12ed74ee6ce 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -13,7 +13,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-application-crypto = { version = "7.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "7.0.0", default-features = false, path = "../core" } @@ -25,7 +24,6 @@ default = [ ] std = [ "codec/std", - "parity-util-mem/std", "serde", "sp-application-crypto/std", "sp-core/std", diff --git a/primitives/test-primitives/src/lib.rs b/primitives/test-primitives/src/lib.rs index 976bb9ddd9cd7..9779fe2393c35 100644 --- a/primitives/test-primitives/src/lib.rs +++ b/primitives/test-primitives/src/lib.rs @@ -29,7 +29,6 @@ use sp_runtime::traits::{BlakeTwo256, Extrinsic as ExtrinsicT, Verify}; /// Extrinsic for test-runtime. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(parity_util_mem::MallocSizeOf))] pub enum Extrinsic { IncludeData(Vec), StorageChange(Vec, Option>), diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 67839a157a02b..68a5fb17c3c34 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -24,7 +24,7 @@ hashbrown = { version = "0.12.3", optional = true } hash-db = { version = "0.15.2", default-features = false } lazy_static = { version = "1.4.0", optional = true } lru = { version = "0.8.1", optional = true } -memory-db = { version = "0.30.0", default-features = false } +memory-db = { version = "0.31.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } @@ -38,7 +38,7 @@ sp-std = { version = "5.0.0", default-features = false, path = "../std" } [dev-dependencies] array-bytes = "4.1" criterion = "0.3.3" -trie-bench = "0.32.0" +trie-bench = "0.33.0" trie-standardmap = "0.15.2" sp-runtime = { version = "7.0.0", path = "../runtime" } @@ -62,4 +62,3 @@ std = [ "trie-db/std", "trie-root/std", ] -memory-tracker = [] diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index d036db7b1fecd..01650e9a376be 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -146,11 +146,6 @@ where } } -#[cfg(not(feature = "memory-tracker"))] -type MemTracker = memory_db::NoopTracker; -#[cfg(feature = "memory-tracker")] -type MemTracker = memory_db::MemCounter; - /// TrieDB error over `TrieConfiguration` trait. pub type TrieError = trie_db::TrieError, CError>; /// Reexport from `hash_db`, with genericity set for `Hasher` trait. @@ -161,14 +156,13 @@ pub type HashDB<'a, H> = dyn hash_db::HashDB + 'a; /// Reexport from `hash_db`, with genericity set for `Hasher` trait. /// This uses a `KeyFunction` for prefixing keys internally (avoiding /// key conflict for non random keys). -pub type PrefixedMemoryDB = - memory_db::MemoryDB, trie_db::DBValue, MemTracker>; +pub type PrefixedMemoryDB = memory_db::MemoryDB, trie_db::DBValue>; /// Reexport from `hash_db`, with genericity set for `Hasher` trait. /// This uses a noops `KeyFunction` (key addressing must be hashed or using /// an encoding scheme that avoid key conflict). -pub type MemoryDB = memory_db::MemoryDB, trie_db::DBValue, MemTracker>; +pub type MemoryDB = memory_db::MemoryDB, trie_db::DBValue>; /// Reexport from `hash_db`, with genericity set for `Hasher` trait. -pub type GenericMemoryDB = memory_db::MemoryDB; +pub type GenericMemoryDB = memory_db::MemoryDB; /// Persistent trie database read-access interface for the a given hasher. pub type TrieDB<'a, 'cache, L> = trie_db::TrieDB<'a, 'cache, L>; @@ -548,8 +542,7 @@ mod tests { type LayoutV0 = super::LayoutV0; type LayoutV1 = super::LayoutV1; - type MemoryDBMeta = - memory_db::MemoryDB, trie_db::DBValue, MemTracker>; + type MemoryDBMeta = memory_db::MemoryDB, trie_db::DBValue>; fn hashed_null_node() -> TrieHash { ::hashed_null_node() diff --git a/scripts/ci/deny.toml b/scripts/ci/deny.toml index 8cc7635d5049b..bc41f746cbb1e 100644 --- a/scripts/ci/deny.toml +++ b/scripts/ci/deny.toml @@ -160,7 +160,6 @@ allow = [ ] # 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. ] diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index a201906f1cc4d..7576a63ac3eb1 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-keyring = { version = "7.0.0", optional = true, path = "../../primitives/keyring" } -memory-db = { version = "0.30.0", default-features = false } +memory-db = { version = "0.31.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } @@ -42,7 +42,6 @@ sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = sp-trie = { version = "7.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } trie-db = { version = "0.24.0", default-features = false } -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } sp-state-machine = { version = "0.13.0", default-features = false, path = "../../primitives/state-machine" } sp-externalities = { version = "0.13.0", default-features = false, path = "../../primitives/externalities" } @@ -67,7 +66,6 @@ default = [ "std", ] std = [ - "parity-util-mem/std", "beefy-primitives/std", "beefy-merkle-tree/std", "sp-application-crypto/std", diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 51f057e3ded55..8b64528e243bd 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -166,8 +166,6 @@ pub enum Extrinsic { Store(Vec), } -parity_util_mem::malloc_size_of_is_0!(Extrinsic); // non-opaque extrinsic does not need this - #[cfg(feature = "std")] impl serde::Serialize for Extrinsic { fn serialize(&self, seq: S) -> Result diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 1b38f0295f8bb..5173340f7d0d9 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -22,11 +22,11 @@ handlebars = "4.2.2" hash-db = "0.15.2" Inflector = "0.11.4" itertools = "0.10.3" -kvdb = "0.12.0" +kvdb = "0.13.0" lazy_static = "1.4.0" linked-hash-map = "0.5.4" log = "0.4.17" -memory-db = "0.30.0" +memory-db = "0.31.0" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.136" From 11c50578549969979121577cde987ad3f9d95bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 6 Dec 2022 15:58:52 +0100 Subject: [PATCH 1442/1472] frame-support: Introduce `EnsureOriginOrHigherPrivilege` (#12844) * frame-support: Introduce `EnsureOriginOrHigherPrivilege` This adds a new `EnsureOrigin` implementation that checks if a given origin matches or if the origin is has a higher or equal origin matches or if the origin is has a higher or equal privilege. * FMT --- frame/support/src/traits.rs | 4 +- frame/support/src/traits/dispatch.rs | 92 +++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 5 deletions(-) diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 1b1d5d68cb52c..e5ba98fe0c5bb 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -99,8 +99,8 @@ mod dispatch; pub use dispatch::EnsureOneOf; pub use dispatch::{ AsEnsureOriginWithArg, CallerTrait, EitherOf, EitherOfDiverse, EnsureOrigin, - EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess, - UnfilteredDispatchable, + EnsureOriginEqualOrHigherPrivilege, EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, + OriginTrait, TryMapSuccess, UnfilteredDispatchable, }; mod voting; diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index b96cfae4500e2..36ddf5b507c0c 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -20,10 +20,12 @@ use crate::dispatch::{DispatchResultWithPostInfo, Parameter, RawOrigin}; use codec::MaxEncodedLen; use sp_runtime::{ - traits::{BadOrigin, Member, Morph, TryMorph}, + traits::{BadOrigin, Get, Member, Morph, TryMorph}, Either, }; -use sp_std::marker::PhantomData; +use sp_std::{cmp::Ordering, marker::PhantomData}; + +use super::misc; /// Some sort of check on the origin is performed by this object. pub trait EnsureOrigin { @@ -59,7 +61,7 @@ pub trait EnsureOrigin { } } -/// `EnsureOrigin` implementation that always fails. +/// [`EnsureOrigin`] implementation that always fails. pub struct NeverEnsureOrigin(sp_std::marker::PhantomData); impl EnsureOrigin for NeverEnsureOrigin { type Success = Success; @@ -72,6 +74,90 @@ impl EnsureOrigin for NeverEnsureOrigin { } } +/// [`EnsureOrigin`] implementation that checks that an origin has equal or higher privilege +/// compared to the expected `Origin`. +/// +/// It will take the shortcut of comparing the incoming origin with the expected `Origin` and if +/// both are the same the origin is accepted. +/// +/// # Example +/// +/// ```rust +/// # use frame_support::traits::{EnsureOriginEqualOrHigherPrivilege, PrivilegeCmp, EnsureOrigin as _}; +/// # use sp_runtime::traits::{parameter_types, Get}; +/// # use sp_std::cmp::Ordering; +/// +/// #[derive(Eq, PartialEq, Debug)] +/// pub enum Origin { +/// Root, +/// SomethingBelowRoot, +/// NormalUser, +/// } +/// +/// struct OriginPrivilegeCmp; +/// +/// impl PrivilegeCmp for OriginPrivilegeCmp { +/// fn cmp_privilege(left: &Origin, right: &Origin) -> Option { +/// match (left, right) { +/// (Origin::Root, Origin::Root) => Some(Ordering::Equal), +/// (Origin::Root, _) => Some(Ordering::Greater), +/// (Origin::SomethingBelowRoot, Origin::SomethingBelowRoot) => Some(Ordering::Equal), +/// (Origin::SomethingBelowRoot, Origin::Root) => Some(Ordering::Less), +/// (Origin::SomethingBelowRoot, Origin::NormalUser) => Some(Ordering::Greater), +/// (Origin::NormalUser, Origin::NormalUser) => Some(Ordering::Equal), +/// (Origin::NormalUser, _) => Some(Ordering::Less), +/// } +/// } +/// } +/// +/// parameter_types! { +/// pub const ExpectedOrigin: Origin = Origin::SomethingBelowRoot; +/// } +/// +/// type EnsureOrigin = EnsureOriginEqualOrHigherPrivilege; +/// +/// // `Root` has an higher privilege as our expected origin. +/// assert!(EnsureOrigin::ensure_origin(Origin::Root).is_ok()); +/// // `SomethingBelowRoot` is exactly the expected origin. +/// assert!(EnsureOrigin::ensure_origin(Origin::SomethingBelowRoot).is_ok()); +/// // The `NormalUser` origin is not allowed. +/// assert!(EnsureOrigin::ensure_origin(Origin::NormalUser).is_err()); +/// ``` +pub struct EnsureOriginEqualOrHigherPrivilege( + sp_std::marker::PhantomData<(Origin, PrivilegeCmp)>, +); + +impl EnsureOrigin + for EnsureOriginEqualOrHigherPrivilege +where + Origin: Get, + OuterOrigin: Eq, + PrivilegeCmp: misc::PrivilegeCmp, +{ + type Success = (); + + fn try_origin(o: OuterOrigin) -> Result { + let expected_origin = Origin::get(); + + // If this is the expected origin, it has the same privilege. + if o == expected_origin { + return Ok(()) + } + + let cmp = PrivilegeCmp::cmp_privilege(&o, &expected_origin); + + match cmp { + Some(Ordering::Equal) | Some(Ordering::Greater) => Ok(()), + None | Some(Ordering::Less) => Err(o), + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(Origin::get()) + } +} + /// Some sort of check on the origin is performed by this object. pub trait EnsureOriginWithArg { /// A return type. From 0d153c9c4003261d97bde4adbdd4bc151472f9b9 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 7 Dec 2022 12:19:46 +0200 Subject: [PATCH 1443/1472] Mmr persist state (#12822) client/mmr: persisting gadget state across runs Fixes #12780 * client/mmr: on init do canonicalization catch-up * client/mmr: add more tests * client/mmr: persist gadget progress in aux db * client/mmr: add more tests * client/mmr: replace async_std with tokio * remove leftover comment * address review comments Signed-off-by: acatangiu --- Cargo.lock | 2 + client/merkle-mountain-range/Cargo.toml | 4 +- .../merkle-mountain-range/src/aux_schema.rs | 228 ++++++++++++++++++ client/merkle-mountain-range/src/lib.rs | 64 +++-- .../merkle-mountain-range/src/offchain_mmr.rs | 163 +++++++++++-- .../merkle-mountain-range/src/test_utils.rs | 98 +++++--- 6 files changed, 477 insertions(+), 82 deletions(-) create mode 100644 client/merkle-mountain-range/src/aux_schema.rs diff --git a/Cargo.lock b/Cargo.lock index 1ba2462a24caa..c4f06732a94b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4137,6 +4137,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", + "parking_lot 0.12.1", "sc-block-builder", "sc-client-api", "sc-offchain", @@ -4148,6 +4149,7 @@ dependencies = [ "sp-io", "sp-mmr-primitives", "sp-runtime", + "sp-tracing", "substrate-test-runtime-client", "tokio", ] diff --git a/client/merkle-mountain-range/Cargo.toml b/client/merkle-mountain-range/Cargo.toml index e32764eff1d63..4fb423cee83bc 100644 --- a/client/merkle-mountain-range/Cargo.toml +++ b/client/merkle-mountain-range/Cargo.toml @@ -26,6 +26,8 @@ sc-offchain = { version = "4.0.0-dev", path = "../offchain" } sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] -tokio = "1.17.0" +parking_lot = "0.12.1" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } +tokio = "1.17.0" diff --git a/client/merkle-mountain-range/src/aux_schema.rs b/client/merkle-mountain-range/src/aux_schema.rs new file mode 100644 index 0000000000000..907deb0bde239 --- /dev/null +++ b/client/merkle-mountain-range/src/aux_schema.rs @@ -0,0 +1,228 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Schema for MMR-gadget state persisted in the aux-db. + +use crate::LOG_TARGET; +use codec::{Decode, Encode}; +use log::{info, trace}; +use sc_client_api::backend::AuxStore; +use sp_blockchain::{Error as ClientError, Result as ClientResult}; +use sp_runtime::traits::{Block, NumberFor}; + +const VERSION_KEY: &[u8] = b"mmr_auxschema_version"; +const GADGET_STATE: &[u8] = b"mmr_gadget_state"; + +const CURRENT_VERSION: u32 = 1; +pub(crate) type PersistedState = NumberFor; + +pub(crate) fn write_current_version(backend: &B) -> ClientResult<()> { + info!(target: LOG_TARGET, "write aux schema version {:?}", CURRENT_VERSION); + AuxStore::insert_aux(backend, &[(VERSION_KEY, CURRENT_VERSION.encode().as_slice())], &[]) +} + +/// Write gadget state. +pub(crate) fn write_gadget_state( + backend: &BE, + state: &PersistedState, +) -> ClientResult<()> { + trace!(target: LOG_TARGET, "persisting {:?}", state); + backend.insert_aux(&[(GADGET_STATE, state.encode().as_slice())], &[]) +} + +fn load_decode(backend: &B, key: &[u8]) -> ClientResult> { + match backend.get_aux(key)? { + None => Ok(None), + Some(t) => T::decode(&mut &t[..]) + .map_err(|e| ClientError::Backend(format!("MMR aux DB is corrupted: {}", e))) + .map(Some), + } +} + +/// Load or initialize persistent data from backend. +pub(crate) fn load_persistent(backend: &BE) -> ClientResult>> +where + B: Block, + BE: AuxStore, +{ + let version: Option = load_decode(backend, VERSION_KEY)?; + + match version { + None => (), + Some(1) => return load_decode::<_, PersistedState>(backend, GADGET_STATE), + other => + return Err(ClientError::Backend(format!("Unsupported MMR aux DB version: {:?}", other))), + } + + // No persistent state found in DB. + Ok(None) +} + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + use crate::test_utils::{ + run_test_with_mmr_gadget_pre_post_using_client, MmrBlock, MockClient, OffchainKeyType, + }; + use parking_lot::Mutex; + use sp_core::offchain::{DbExternalities, StorageKind}; + use sp_mmr_primitives::utils::NodesUtils; + use sp_runtime::generic::BlockId; + use std::{sync::Arc, time::Duration}; + use substrate_test_runtime_client::{runtime::Block, Backend}; + + #[test] + fn should_load_persistent_sanity_checks() { + let client = MockClient::new(); + let backend = &*client.backend; + + // version not available in db -> None + assert_eq!(load_persistent::(backend).unwrap(), None); + + // populate version in db + write_current_version(backend).unwrap(); + // verify correct version is retrieved + assert_eq!(load_decode(backend, VERSION_KEY).unwrap(), Some(CURRENT_VERSION)); + + // version is available in db but state isn't -> None + assert_eq!(load_persistent::(backend).unwrap(), None); + } + + #[test] + fn should_persist_progress_across_runs() { + sp_tracing::try_init_simple(); + + let client = Arc::new(MockClient::new()); + let backend = client.backend.clone(); + + // version not available in db -> None + assert_eq!(load_decode::>(&*backend, VERSION_KEY).unwrap(), None); + // state not available in db -> None + assert_eq!(load_persistent::(&*backend).unwrap(), None); + // run the gadget while importing and finalizing 3 blocks + run_test_with_mmr_gadget_pre_post_using_client( + client.clone(), + |_| async {}, + |client| async move { + let a1 = client.import_block(&BlockId::Number(0), b"a1", Some(0)).await; + let a2 = client.import_block(&BlockId::Number(1), b"a2", Some(1)).await; + let a3 = client.import_block(&BlockId::Number(2), b"a3", Some(2)).await; + client.finalize_block(a3.hash(), Some(3)); + tokio::time::sleep(Duration::from_millis(200)).await; + // a1, a2, a3 were canonicalized + client.assert_canonicalized(&[&a1, &a2, &a3]); + }, + ); + + // verify previous progress was persisted and run the gadget again + run_test_with_mmr_gadget_pre_post_using_client( + client.clone(), + |client| async move { + let backend = &*client.backend; + // check there is both version and best canon available in db before running gadget + assert_eq!(load_decode(backend, VERSION_KEY).unwrap(), Some(CURRENT_VERSION)); + assert_eq!(load_persistent::(backend).unwrap(), Some(3)); + }, + |client| async move { + let a4 = client.import_block(&BlockId::Number(3), b"a4", Some(3)).await; + let a5 = client.import_block(&BlockId::Number(4), b"a5", Some(4)).await; + let a6 = client.import_block(&BlockId::Number(5), b"a6", Some(5)).await; + client.finalize_block(a6.hash(), Some(6)); + tokio::time::sleep(Duration::from_millis(200)).await; + + // a4, a5, a6 were canonicalized + client.assert_canonicalized(&[&a4, &a5, &a6]); + // check persisted best canon was updated + assert_eq!(load_persistent::(&*client.backend).unwrap(), Some(6)); + }, + ); + } + + #[test] + fn should_resume_from_persisted_state() { + sp_tracing::try_init_simple(); + + let client = Arc::new(MockClient::new()); + let blocks = Arc::new(Mutex::new(Vec::::new())); + let blocks_clone = blocks.clone(); + + // run the gadget while importing and finalizing 3 blocks + run_test_with_mmr_gadget_pre_post_using_client( + client.clone(), + |_| async {}, + |client| async move { + let mut blocks = blocks_clone.lock(); + blocks.push(client.import_block(&BlockId::Number(0), b"a1", Some(0)).await); + blocks.push(client.import_block(&BlockId::Number(1), b"a2", Some(1)).await); + blocks.push(client.import_block(&BlockId::Number(2), b"a3", Some(2)).await); + client.finalize_block(blocks.last().unwrap().hash(), Some(3)); + tokio::time::sleep(Duration::from_millis(200)).await; + // a1, a2, a3 were canonicalized + let slice: Vec<&MmrBlock> = blocks.iter().collect(); + client.assert_canonicalized(&slice); + + // now manually move them back to non-canon/temp location + let mut offchain_db = client.offchain_db(); + for mmr_block in slice { + for node in NodesUtils::right_branch_ending_in_leaf(mmr_block.leaf_idx.unwrap()) + { + let canon_key = mmr_block.get_offchain_key(node, OffchainKeyType::Canon); + let val = offchain_db + .local_storage_get(StorageKind::PERSISTENT, &canon_key) + .unwrap(); + offchain_db.local_storage_clear(StorageKind::PERSISTENT, &canon_key); + + let temp_key = mmr_block.get_offchain_key(node, OffchainKeyType::Temp); + offchain_db.local_storage_set(StorageKind::PERSISTENT, &temp_key, &val); + } + } + }, + ); + + let blocks_clone = blocks.clone(); + // verify new gadget continues from block 4 and ignores 1, 2, 3 based on persisted state + run_test_with_mmr_gadget_pre_post_using_client( + client.clone(), + |client| async move { + let blocks = blocks_clone.lock(); + let slice: Vec<&MmrBlock> = blocks.iter().collect(); + + // verify persisted state says a1, a2, a3 were canonicalized, + assert_eq!(load_persistent::(&*client.backend).unwrap(), Some(3)); + // but actually they are NOT canon (we manually reverted them earlier). + client.assert_not_canonicalized(&slice); + }, + |client| async move { + let a4 = client.import_block(&BlockId::Number(3), b"a4", Some(3)).await; + let a5 = client.import_block(&BlockId::Number(4), b"a5", Some(4)).await; + let a6 = client.import_block(&BlockId::Number(5), b"a6", Some(5)).await; + client.finalize_block(a6.hash(), Some(6)); + tokio::time::sleep(Duration::from_millis(200)).await; + + let block_1_to_3 = blocks.lock(); + let slice: Vec<&MmrBlock> = block_1_to_3.iter().collect(); + // verify a1, a2, a3 are still NOT canon (skipped by gadget based on data in aux db) + client.assert_not_canonicalized(&slice); + // but a4, a5, a6 were canonicalized + client.assert_canonicalized(&[&a4, &a5, &a6]); + // check persisted best canon was updated + assert_eq!(load_persistent::(&*client.backend).unwrap(), Some(6)); + }, + ); + } +} diff --git a/client/merkle-mountain-range/src/lib.rs b/client/merkle-mountain-range/src/lib.rs index 59f26b4265708..401a5d5d4d56b 100644 --- a/client/merkle-mountain-range/src/lib.rs +++ b/client/merkle-mountain-range/src/lib.rs @@ -37,15 +37,15 @@ #![warn(missing_docs)] +mod aux_schema; mod offchain_mmr; #[cfg(test)] pub mod test_utils; -use std::{marker::PhantomData, sync::Arc}; - +use crate::offchain_mmr::OffchainMmr; +use beefy_primitives::MmrRootHash; use futures::StreamExt; -use log::{error, trace, warn}; - +use log::{debug, error, trace, warn}; use sc_client_api::{Backend, BlockchainEvents, FinalityNotifications}; use sc_offchain::OffchainDb; use sp_api::ProvideRuntimeApi; @@ -55,50 +55,75 @@ use sp_runtime::{ generic::BlockId, traits::{Block, Header, NumberFor}, }; - -use crate::offchain_mmr::OffchainMMR; -use beefy_primitives::MmrRootHash; -use sp_core::offchain::OffchainStorage; +use std::{marker::PhantomData, sync::Arc}; /// Logging target for the mmr gadget. pub const LOG_TARGET: &str = "mmr"; -struct OffchainMmrBuilder { +struct OffchainMmrBuilder, C> { + backend: Arc, client: Arc, - offchain_db: OffchainDb, + offchain_db: OffchainDb, indexing_prefix: Vec, _phantom: PhantomData, } -impl OffchainMmrBuilder +impl OffchainMmrBuilder where B: Block, + BE: Backend, C: ProvideRuntimeApi + HeaderBackend + HeaderMetadata, C::Api: MmrApi>, - S: OffchainStorage, { async fn try_build( self, finality_notifications: &mut FinalityNotifications, - ) -> Option> { + ) -> Option> { while let Some(notification) = finality_notifications.next().await { let best_block = *notification.header.number(); match self.client.runtime_api().mmr_leaf_count(&BlockId::number(best_block)) { Ok(Ok(mmr_leaf_count)) => { + debug!( + target: LOG_TARGET, + "pallet-mmr detected at block {:?} with mmr size {:?}", + best_block, + mmr_leaf_count + ); match utils::first_mmr_block_num::(best_block, mmr_leaf_count) { Ok(first_mmr_block) => { - let mut offchain_mmr = OffchainMMR { + debug!( + target: LOG_TARGET, + "pallet-mmr genesis computed at block {:?}", first_mmr_block, + ); + let best_canonicalized = + match offchain_mmr::load_or_init_best_canonicalized::( + &*self.backend, + first_mmr_block, + ) { + Ok(best) => best, + Err(e) => { + error!( + target: LOG_TARGET, + "Error loading state from aux db: {:?}", e + ); + return None + }, + }; + let mut offchain_mmr = OffchainMmr { + backend: self.backend, client: self.client, offchain_db: self.offchain_db, indexing_prefix: self.indexing_prefix, first_mmr_block, - - _phantom: Default::default(), + best_canonicalized, }; + // We need to make sure all blocks leading up to current notification + // have also been canonicalized. + offchain_mmr.canonicalize_catch_up(¬ification); // We have to canonicalize and prune the blocks in the finality // notification that lead to building the offchain-mmr as well. - offchain_mmr.canonicalize_and_prune(¬ification); + offchain_mmr.canonicalize_and_prune(notification); return Some(offchain_mmr) }, Err(e) => { @@ -143,14 +168,14 @@ where C: BlockchainEvents + HeaderBackend + HeaderMetadata + ProvideRuntimeApi, C::Api: MmrApi>, { - async fn run(mut self, builder: OffchainMmrBuilder) { + async fn run(mut self, builder: OffchainMmrBuilder) { let mut offchain_mmr = match builder.try_build(&mut self.finality_notifications).await { Some(offchain_mmr) => offchain_mmr, None => return, }; while let Some(notification) = self.finality_notifications.next().await { - offchain_mmr.canonicalize_and_prune(¬ification); + offchain_mmr.canonicalize_and_prune(notification); } } @@ -174,6 +199,7 @@ where }; mmr_gadget .run(OffchainMmrBuilder { + backend, client, offchain_db, indexing_prefix, diff --git a/client/merkle-mountain-range/src/offchain_mmr.rs b/client/merkle-mountain-range/src/offchain_mmr.rs index 1cdd3810b4c52..988b3ffef882a 100644 --- a/client/merkle-mountain-range/src/offchain_mmr.rs +++ b/client/merkle-mountain-range/src/offchain_mmr.rs @@ -21,33 +21,57 @@ #![warn(missing_docs)] -use std::{marker::PhantomData, sync::Arc}; - -use log::{debug, error, warn}; - -use sc_client_api::FinalityNotification; +use crate::{aux_schema, LOG_TARGET}; +use log::{debug, error, info, warn}; +use sc_client_api::{AuxStore, Backend, FinalityNotification}; use sc_offchain::OffchainDb; use sp_blockchain::{CachedHeaderMetadata, ForkBackend, HeaderBackend, HeaderMetadata}; -use sp_core::offchain::{DbExternalities, OffchainStorage, StorageKind}; +use sp_core::offchain::{DbExternalities, StorageKind}; use sp_mmr_primitives::{utils, utils::NodesUtils, NodeIndex}; -use sp_runtime::traits::{Block, Header}; - -use crate::LOG_TARGET; +use sp_runtime::{ + traits::{Block, NumberFor, One}, + Saturating, +}; +use std::{collections::VecDeque, sync::Arc}; + +pub(crate) fn load_or_init_best_canonicalized( + backend: &BE, + first_mmr_block: NumberFor, +) -> sp_blockchain::Result> +where + BE: AuxStore, + B: Block, +{ + // Initialize gadget best_canon from AUX DB or from pallet genesis. + if let Some(best) = aux_schema::load_persistent::(backend)? { + info!(target: LOG_TARGET, "Loading MMR best canonicalized state from db: {:?}.", best); + Ok(best) + } else { + let best = first_mmr_block.saturating_sub(One::one()); + info!( + target: LOG_TARGET, + "Loading MMR from pallet genesis on what appears to be the first startup: {:?}.", best + ); + aux_schema::write_current_version(backend)?; + aux_schema::write_gadget_state::(backend, &best)?; + Ok(best) + } +} /// `OffchainMMR` exposes MMR offchain canonicalization and pruning logic. -pub struct OffchainMMR { +pub struct OffchainMmr, C> { + pub backend: Arc, pub client: Arc, - pub offchain_db: OffchainDb, + pub offchain_db: OffchainDb, pub indexing_prefix: Vec, - pub first_mmr_block: ::Number, - - pub _phantom: PhantomData, + pub first_mmr_block: NumberFor, + pub best_canonicalized: NumberFor, } -impl OffchainMMR +impl OffchainMmr where C: HeaderBackend + HeaderMetadata, - S: OffchainStorage, + BE: Backend, B: Block, { fn node_temp_offchain_key(&self, pos: NodeIndex, parent_hash: B::Hash) -> Vec { @@ -77,7 +101,7 @@ where fn right_branch_ending_in_block_or_log( &self, - block_num: ::Number, + block_num: NumberFor, action: &str, ) -> Option> { match utils::block_num_to_leaf_index::(block_num, self.first_mmr_block) { @@ -128,9 +152,9 @@ where } } - fn canonicalize_branch(&mut self, block_hash: &B::Hash) { + fn canonicalize_branch(&mut self, block_hash: B::Hash) { let action = "canonicalize"; - let header = match self.header_metadata_or_log(*block_hash, action) { + let header = match self.header_metadata_or_log(block_hash, action) { Some(header) => header, _ => return, }; @@ -148,6 +172,7 @@ where None => { // If we can't convert the block number to a leaf index, the chain state is probably // corrupted. We only log the error, hoping that the chain state will be fixed. + self.best_canonicalized = header.number; return }, }; @@ -174,16 +199,58 @@ where ); } } + if self.best_canonicalized != header.number.saturating_sub(One::one()) { + warn!( + target: LOG_TARGET, + "Detected canonicalization skip: best {:?} current {:?}.", + self.best_canonicalized, + header.number, + ); + } + self.best_canonicalized = header.number; + } + + /// In case of missed finality notifications (node restarts for example), + /// make sure to also canon everything leading up to `notification.tree_route`. + pub fn canonicalize_catch_up(&mut self, notification: &FinalityNotification) { + let first = notification.tree_route.first().unwrap_or(¬ification.hash); + if let Some(mut header) = self.header_metadata_or_log(*first, "canonicalize") { + let mut to_canon = VecDeque::<::Hash>::new(); + // Walk up the chain adding all blocks newer than `self.best_canonicalized`. + loop { + header = match self.header_metadata_or_log(header.parent, "canonicalize") { + Some(header) => header, + _ => break, + }; + if header.number <= self.best_canonicalized { + break + } + to_canon.push_front(header.hash); + } + // Canonicalize all blocks leading up to current finality notification. + for hash in to_canon.drain(..) { + self.canonicalize_branch(hash); + } + if let Err(e) = + aux_schema::write_gadget_state::(&*self.backend, &self.best_canonicalized) + { + debug!(target: LOG_TARGET, "error saving state: {:?}", e); + } + } } /// Move leafs and nodes added by finalized blocks in offchain db from _fork-aware key_ to /// _canonical key_. /// Prune leafs and nodes added by stale blocks in offchain db from _fork-aware key_. - pub fn canonicalize_and_prune(&mut self, notification: &FinalityNotification) { + pub fn canonicalize_and_prune(&mut self, notification: FinalityNotification) { // Move offchain MMR nodes for finalized blocks to canonical keys. - for block_hash in notification.tree_route.iter().chain(std::iter::once(¬ification.hash)) + for hash in notification.tree_route.iter().chain(std::iter::once(¬ification.hash)) { + self.canonicalize_branch(*hash); + } + if let Err(e) = + aux_schema::write_gadget_state::(&*self.backend, &self.best_canonicalized) { - self.canonicalize_branch(block_hash); + debug!(target: LOG_TARGET, "error saving state: {:?}", e); } // Remove offchain MMR nodes for stale forks. @@ -201,9 +268,10 @@ where #[cfg(test)] mod tests { - use crate::test_utils::run_test_with_mmr_gadget; + use crate::test_utils::{run_test_with_mmr_gadget, run_test_with_mmr_gadget_pre_post}; + use parking_lot::Mutex; use sp_runtime::generic::BlockId; - use std::time::Duration; + use std::{sync::Arc, time::Duration}; #[test] fn canonicalize_and_prune_works_correctly() { @@ -243,4 +311,51 @@ mod tests { client.assert_pruned(&[&b1, &b2, &b3, &a4]); }) } + + #[test] + fn canonicalize_catchup_works_correctly() { + let mmr_blocks = Arc::new(Mutex::new(vec![])); + let mmr_blocks_ref = mmr_blocks.clone(); + run_test_with_mmr_gadget_pre_post( + |client| async move { + // G -> A1 -> A2 + // | | + // | | -> finalized without gadget (missed notification) + // | + // | -> first mmr block + + let a1 = client.import_block(&BlockId::Number(0), b"a1", Some(0)).await; + let a2 = client.import_block(&BlockId::Hash(a1.hash()), b"a2", Some(1)).await; + + client.finalize_block(a2.hash(), Some(2)); + + { + let mut mmr_blocks = mmr_blocks_ref.lock(); + mmr_blocks.push(a1); + mmr_blocks.push(a2); + } + }, + |client| async move { + // G -> A1 -> A2 -> A3 -> A4 + // | | | | + // | | | | -> finalized after starting gadget + // | | | + // | | | -> gadget start + // | | + // | | -> finalized before starting gadget (missed notification) + // | + // | -> first mmr block + let blocks = mmr_blocks.lock(); + let a1 = blocks[0].clone(); + let a2 = blocks[1].clone(); + let a3 = client.import_block(&BlockId::Hash(a2.hash()), b"a3", Some(2)).await; + let a4 = client.import_block(&BlockId::Hash(a3.hash()), b"a4", Some(3)).await; + + client.finalize_block(a4.hash(), Some(4)); + tokio::time::sleep(Duration::from_millis(200)).await; + // expected finalized heads: a1, a2 _and_ a3, a4. + client.assert_canonicalized(&[&a1, &a2, &a3, &a4]); + }, + ) + } } diff --git a/client/merkle-mountain-range/src/test_utils.rs b/client/merkle-mountain-range/src/test_utils.rs index b854686b2dc86..f345fb52578ab 100644 --- a/client/merkle-mountain-range/src/test_utils.rs +++ b/client/merkle-mountain-range/src/test_utils.rs @@ -16,12 +16,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{ - future::Future, - sync::{Arc, Mutex}, - time::Duration, -}; - +use crate::MmrGadget; +use parking_lot::Mutex; use sc_block_builder::BlockBuilderProvider; use sc_client_api::{ Backend as BackendT, BlockchainEvents, FinalityNotifications, ImportNotifications, @@ -41,33 +37,34 @@ use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header as HeaderT}, }; +use std::{future::Future, sync::Arc, time::Duration}; use substrate_test_runtime_client::{ runtime::{Block, BlockNumber, Hash, Header}, Backend, BlockBuilderExt, Client, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, }; - -use crate::MmrGadget; +use tokio::runtime::Runtime; type MmrHash = H256; -struct MockRuntimeApiData { - num_blocks: BlockNumber, +pub(crate) struct MockRuntimeApiData { + pub(crate) num_blocks: BlockNumber, } #[derive(Clone)] -pub struct MockRuntimeApi { - data: Arc>, +pub(crate) struct MockRuntimeApi { + pub(crate) data: Arc>, } impl MockRuntimeApi { - pub const INDEXING_PREFIX: &'static [u8] = b"mmr_test"; + pub(crate) const INDEXING_PREFIX: &'static [u8] = b"mmr_test"; } -pub struct MmrBlock { - block: Block, - leaf_idx: Option, - leaf_data: Vec, +#[derive(Clone, Debug)] +pub(crate) struct MmrBlock { + pub(crate) block: Block, + pub(crate) leaf_idx: Option, + pub(crate) leaf_data: Vec, } #[derive(Clone, Copy)] @@ -90,7 +87,7 @@ impl MmrBlock { OffchainKeyType::Temp => NodesUtils::node_temp_offchain_key::

( MockRuntimeApi::INDEXING_PREFIX, node, - *self.block.header.parent_hash(), + self.parent_hash(), ), OffchainKeyType::Canon => NodesUtils::node_canon_offchain_key(MockRuntimeApi::INDEXING_PREFIX, node), @@ -98,14 +95,14 @@ impl MmrBlock { } } -pub struct MockClient { - client: Mutex>, - backend: Arc, - runtime_api_params: Arc>, +pub(crate) struct MockClient { + pub(crate) client: Mutex>, + pub(crate) backend: Arc, + pub(crate) runtime_api_params: Arc>, } impl MockClient { - fn new() -> Self { + pub(crate) fn new() -> Self { let client_builder = TestClientBuilder::new().enable_offchain_indexing_api(); let (client, backend) = client_builder.build_with_backend(); MockClient { @@ -115,7 +112,7 @@ impl MockClient { } } - fn offchain_db(&self) -> OffchainDb<>::OffchainStorage> { + pub(crate) fn offchain_db(&self) -> OffchainDb<>::OffchainStorage> { OffchainDb::new(self.backend.offchain_storage().unwrap()) } @@ -125,7 +122,7 @@ impl MockClient { name: &[u8], maybe_leaf_idx: Option, ) -> MmrBlock { - let mut client = self.client.lock().unwrap(); + let mut client = self.client.lock(); let mut block_builder = client.new_block_at(at, Default::default(), false).unwrap(); // Make sure the block has a different hash than its siblings @@ -157,9 +154,9 @@ impl MockClient { } pub fn finalize_block(&self, hash: Hash, maybe_num_mmr_blocks: Option) { - let client = self.client.lock().unwrap(); + let client = self.client.lock(); if let Some(num_mmr_blocks) = maybe_num_mmr_blocks { - self.runtime_api_params.lock().unwrap().num_blocks = num_mmr_blocks; + self.runtime_api_params.lock().num_blocks = num_mmr_blocks; } client.finalize_block(hash, None).unwrap(); @@ -216,7 +213,7 @@ impl HeaderMetadata for MockClient { type Error = as HeaderMetadata>::Error; fn header_metadata(&self, hash: Hash) -> Result, Self::Error> { - self.client.lock().unwrap().header_metadata(hash) + self.client.lock().header_metadata(hash) } fn insert_header_metadata(&self, _hash: Hash, _header_metadata: CachedHeaderMetadata) { @@ -230,23 +227,23 @@ impl HeaderMetadata for MockClient { impl HeaderBackend for MockClient { fn header(&self, id: BlockId) -> sc_client_api::blockchain::Result> { - self.client.lock().unwrap().header(&id) + self.client.lock().header(&id) } fn info(&self) -> Info { - self.client.lock().unwrap().info() + self.client.lock().info() } fn status(&self, id: BlockId) -> sc_client_api::blockchain::Result { - self.client.lock().unwrap().status(id) + self.client.lock().status(id) } fn number(&self, hash: Hash) -> sc_client_api::blockchain::Result> { - self.client.lock().unwrap().number(hash) + self.client.lock().number(hash) } fn hash(&self, number: BlockNumber) -> sc_client_api::blockchain::Result> { - self.client.lock().unwrap().hash(number) + self.client.lock().hash(number) } } @@ -256,7 +253,7 @@ impl BlockchainEvents for MockClient { } fn finality_notification_stream(&self) -> FinalityNotifications { - self.client.lock().unwrap().finality_notification_stream() + self.client.lock().finality_notification_stream() } fn storage_changes_notification_stream( @@ -283,7 +280,7 @@ sp_api::mock_impl_runtime_apis! { } fn mmr_leaf_count(&self) -> Result { - Ok(self.data.lock().unwrap().num_blocks) + Ok(self.data.lock().num_blocks) } fn generate_proof( @@ -310,13 +307,38 @@ sp_api::mock_impl_runtime_apis! { } } -pub fn run_test_with_mmr_gadget(f: F) +pub(crate) fn run_test_with_mmr_gadget(post_gadget: F) where F: FnOnce(Arc) -> Fut + 'static, Fut: Future, { - let runtime = tokio::runtime::Runtime::new().unwrap(); + run_test_with_mmr_gadget_pre_post(|_| async {}, post_gadget); +} + +pub(crate) fn run_test_with_mmr_gadget_pre_post(pre_gadget: F, post_gadget: G) +where + F: FnOnce(Arc) -> RetF + 'static, + G: FnOnce(Arc) -> RetG + 'static, + RetF: Future, + RetG: Future, +{ let client = Arc::new(MockClient::new()); + run_test_with_mmr_gadget_pre_post_using_client(client, pre_gadget, post_gadget) +} + +pub(crate) fn run_test_with_mmr_gadget_pre_post_using_client( + client: Arc, + pre_gadget: F, + post_gadget: G, +) where + F: FnOnce(Arc) -> RetF + 'static, + G: FnOnce(Arc) -> RetG + 'static, + RetF: Future, + RetG: Future, +{ + let client_clone = client.clone(); + let runtime = Runtime::new().unwrap(); + runtime.block_on(async move { pre_gadget(client_clone).await }); let client_clone = client.clone(); runtime.spawn(async move { @@ -327,6 +349,6 @@ where runtime.block_on(async move { tokio::time::sleep(Duration::from_millis(200)).await; - f(client).await + post_gadget(client).await }); } From 200088e980a72978ef8011819c7f236c32542f81 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Wed, 7 Dec 2022 13:20:48 +0100 Subject: [PATCH 1444/1472] Refund referendum submission deposit (#12788) * optinal submission deposit and migration * refund submission deposit call, test, bench * try runtime fixes * assert for bench * Only refund cancelled/approved referenda deposits * update storage version Co-authored-by: Gav --- Cargo.lock | 1 + frame/referenda/Cargo.toml | 1 + frame/referenda/src/benchmarking.rs | 13 + frame/referenda/src/lib.rs | 58 +++- frame/referenda/src/migration.rs | 232 ++++++++++++++ frame/referenda/src/tests.rs | 38 +++ frame/referenda/src/types.rs | 21 +- frame/referenda/src/weights.rs | 470 ++++++++++++++-------------- 8 files changed, 593 insertions(+), 241 deletions(-) create mode 100644 frame/referenda/src/migration.rs diff --git a/Cargo.lock b/Cargo.lock index c4f06732a94b2..17b66c920cd79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5871,6 +5871,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "pallet-balances", "pallet-preimage", "pallet-scheduler", diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index a9428a408df80..02894e1499d93 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -26,6 +26,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +log = { version = "0.4.17", default-features = false } [dev-dependencies] assert_matches = { version = "1.5" } diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index bc6fb31bf1127..b82ac5b3bdfe3 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -264,6 +264,19 @@ benchmarks_instance_pallet! { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, _, None))); } + refund_submission_deposit { + let (origin, index) = create_referendum::(); + let caller = frame_system::ensure_signed(origin.clone()).unwrap(); + let balance = T::Currency::free_balance(&caller); + assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); + assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, Some(_), _))); + }: _(origin, index) + verify { + assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, None, _))); + let new_balance = T::Currency::free_balance(&caller); + assert!(new_balance > balance); + } + cancel { let (_origin, index) = create_referendum::(); place_deposit::(index); diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 742ad48963183..2bb01baa0cd3a 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -85,6 +85,7 @@ use sp_runtime::{ use sp_std::{fmt::Debug, prelude::*}; mod branch; +pub mod migration; mod types; pub mod weights; @@ -140,8 +141,12 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -342,6 +347,15 @@ pub mod pallet { /// The final tally of votes in this referendum. tally: T::Tally, }, + /// The submission deposit has been refunded. + SubmissionDepositRefunded { + /// Index of the referendum. + index: ReferendumIndex, + /// The account who placed the deposit. + who: T::AccountId, + /// The amount placed by the account. + amount: BalanceOf, + }, } #[pallet::error] @@ -368,6 +382,8 @@ pub mod pallet { NoPermission, /// The deposit cannot be refunded since none was made. NoDeposit, + /// The referendum status is invalid for this operation. + BadStatus, } #[pallet::call] @@ -495,7 +511,7 @@ pub mod pallet { Self::deposit_event(Event::::Cancelled { index, tally: status.tally }); let info = ReferendumInfo::Cancelled( frame_system::Pallet::::block_number(), - status.submission_deposit, + Some(status.submission_deposit), status.decision_deposit, ); ReferendumInfoFor::::insert(index, info); @@ -579,6 +595,36 @@ pub mod pallet { }; Ok(Some(branch.weight::()).into()) } + + /// Refund the Submission Deposit for a closed referendum back to the depositor. + /// + /// - `origin`: must be `Signed` or `Root`. + /// - `index`: The index of a closed referendum whose Submission Deposit has not yet been + /// refunded. + /// + /// Emits `SubmissionDepositRefunded`. + #[pallet::weight(T::WeightInfo::refund_submission_deposit())] + pub fn refund_submission_deposit( + origin: OriginFor, + index: ReferendumIndex, + ) -> DispatchResult { + ensure_signed_or_root(origin)?; + let mut info = + ReferendumInfoFor::::get(index).ok_or(Error::::BadReferendum)?; + let deposit = info + .take_submission_deposit() + .map_err(|_| Error::::BadStatus)? + .ok_or(Error::::NoDeposit)?; + Self::refund_deposit(Some(deposit.clone())); + ReferendumInfoFor::::insert(index, info); + let e = Event::::SubmissionDepositRefunded { + index, + who: deposit.who, + amount: deposit.amount, + }; + Self::deposit_event(e); + Ok(()) + } } } @@ -671,9 +717,9 @@ impl, I: 'static> Polling for Pallet { Self::note_one_fewer_deciding(status.track); let now = frame_system::Pallet::::block_number(); let info = if approved { - ReferendumInfo::Approved(now, status.submission_deposit, status.decision_deposit) + ReferendumInfo::Approved(now, Some(status.submission_deposit), status.decision_deposit) } else { - ReferendumInfo::Rejected(now, status.submission_deposit, status.decision_deposit) + ReferendumInfo::Rejected(now, Some(status.submission_deposit), status.decision_deposit) }; ReferendumInfoFor::::insert(index, info); Ok(()) @@ -995,7 +1041,7 @@ impl, I: 'static> Pallet { return ( ReferendumInfo::TimedOut( now, - status.submission_deposit, + Some(status.submission_deposit), status.decision_deposit, ), true, @@ -1027,7 +1073,7 @@ impl, I: 'static> Pallet { return ( ReferendumInfo::Approved( now, - status.submission_deposit, + Some(status.submission_deposit), status.decision_deposit, ), true, @@ -1052,7 +1098,7 @@ impl, I: 'static> Pallet { return ( ReferendumInfo::Rejected( now, - status.submission_deposit, + Some(status.submission_deposit), status.decision_deposit, ), true, diff --git a/frame/referenda/src/migration.rs b/frame/referenda/src/migration.rs new file mode 100644 index 0000000000000..e495090c13754 --- /dev/null +++ b/frame/referenda/src/migration.rs @@ -0,0 +1,232 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Storage migrations for the referenda pallet. + +use super::*; +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade}; +use log; + +/// Initial version of storage types. +pub mod v0 { + use super::*; + // ReferendumStatus and its dependency types referenced from the latest version while staying + // unchanged. [`super::test::referendum_status_v0()`] checks its immutability between v0 and + // latest version. + #[cfg(test)] + pub(super) use super::{ReferendumStatus, ReferendumStatusOf}; + + pub type ReferendumInfoOf = ReferendumInfo< + TrackIdOf, + PalletsOriginOf, + ::BlockNumber, + BoundedCallOf, + BalanceOf, + TallyOf, + ::AccountId, + ScheduleAddressOf, + >; + + /// Info regarding a referendum, present or past. + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub enum ReferendumInfo< + TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Moment: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, + Call: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + > { + /// Referendum has been submitted and is being voted on. + Ongoing( + ReferendumStatus< + TrackId, + RuntimeOrigin, + Moment, + Call, + Balance, + Tally, + AccountId, + ScheduleAddress, + >, + ), + /// Referendum finished with approval. Submission deposit is held. + Approved(Moment, Deposit, Option>), + /// Referendum finished with rejection. Submission deposit is held. + Rejected(Moment, Deposit, Option>), + /// Referendum finished with cancellation. Submission deposit is held. + Cancelled(Moment, Deposit, Option>), + /// Referendum finished and was never decided. Submission deposit is held. + TimedOut(Moment, Deposit, Option>), + /// Referendum finished with a kill. + Killed(Moment), + } + + #[storage_alias] + pub type ReferendumInfoFor, I: 'static> = + StorageMap, Blake2_128Concat, ReferendumIndex, ReferendumInfoOf>; +} + +pub mod v1 { + use super::*; + + /// The log target. + const TARGET: &'static str = "runtime::democracy::migration::v1"; + + /// Transforms a submission deposit of ReferendumInfo(Approved|Rejected|Cancelled|TimedOut) to + /// optional value, making it refundable. + pub struct MigrateV0ToV1(PhantomData<(T, I)>); + impl, I: 'static> OnRuntimeUpgrade for MigrateV0ToV1 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + let onchain_version = Pallet::::on_chain_storage_version(); + assert_eq!(onchain_version, 0, "migration from version 0 to 1."); + let referendum_count = v0::ReferendumInfoFor::::iter().count(); + log::info!( + target: TARGET, + "pre-upgrade state contains '{}' referendums.", + referendum_count + ); + Ok((referendum_count as u32).encode()) + } + + fn on_runtime_upgrade() -> Weight { + let current_version = Pallet::::current_storage_version(); + let onchain_version = Pallet::::on_chain_storage_version(); + let mut weight = T::DbWeight::get().reads(1); + log::info!( + target: TARGET, + "running migration with current storage version {:?} / onchain {:?}.", + current_version, + onchain_version + ); + if onchain_version != 0 { + log::warn!(target: TARGET, "skipping migration from v0 to v1."); + return weight + } + v0::ReferendumInfoFor::::iter().for_each(|(key, value)| { + let maybe_new_value = match value { + v0::ReferendumInfo::Ongoing(_) | v0::ReferendumInfo::Killed(_) => None, + v0::ReferendumInfo::Approved(e, s, d) => + Some(ReferendumInfo::Approved(e, Some(s), d)), + v0::ReferendumInfo::Rejected(e, s, d) => + Some(ReferendumInfo::Rejected(e, Some(s), d)), + v0::ReferendumInfo::Cancelled(e, s, d) => + Some(ReferendumInfo::Cancelled(e, Some(s), d)), + v0::ReferendumInfo::TimedOut(e, s, d) => + Some(ReferendumInfo::TimedOut(e, Some(s), d)), + }; + if let Some(new_value) = maybe_new_value { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + log::info!(target: TARGET, "migrating referendum #{:?}", &key); + ReferendumInfoFor::::insert(key, new_value); + } else { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + } + }); + StorageVersion::new(1).put::>(); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + weight + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let onchain_version = Pallet::::on_chain_storage_version(); + assert_eq!(onchain_version, 1, "must upgrade from version 0 to 1."); + let pre_referendum_count: u32 = Decode::decode(&mut &state[..]) + .expect("failed to decode the state from pre-upgrade."); + let post_referendum_count = ReferendumInfoFor::::iter().count() as u32; + assert_eq!( + post_referendum_count, pre_referendum_count, + "must migrate all referendums." + ); + log::info!(target: TARGET, "migrated all referendums."); + Ok(()) + } + } +} + +#[cfg(test)] +pub mod test { + use super::*; + use crate::mock::{Test as T, *}; + use core::str::FromStr; + + // create referendum status v0. + fn create_status_v0() -> v0::ReferendumStatusOf { + let origin: OriginCaller = frame_system::RawOrigin::Root.into(); + let track = >::Tracks::track_for(&origin).unwrap(); + v0::ReferendumStatusOf:: { + track, + in_queue: true, + origin, + proposal: set_balance_proposal_bounded(1), + enactment: DispatchTime::At(1), + tally: TallyOf::::new(track), + submission_deposit: Deposit { who: 1, amount: 10 }, + submitted: 1, + decision_deposit: None, + alarm: None, + deciding: None, + } + } + + #[test] + pub fn referendum_status_v0() { + // make sure the bytes of the encoded referendum v0 is decodable. + let ongoing_encoded = sp_core::Bytes::from_str("0x00000000013001012a000000000000000400000100000000000000010000000000000001000000000000000a00000000000000000000000000000000000100").unwrap(); + let ongoing_dec = v0::ReferendumInfoOf::::decode(&mut &*ongoing_encoded).unwrap(); + let ongoing = v0::ReferendumInfoOf::::Ongoing(create_status_v0()); + assert_eq!(ongoing, ongoing_dec); + } + + #[test] + fn migration_v0_to_v1_works() { + new_test_ext().execute_with(|| { + // create and insert into the storage an ongoing referendum v0. + let status_v0 = create_status_v0(); + let ongoing_v0 = v0::ReferendumInfoOf::::Ongoing(status_v0.clone()); + v0::ReferendumInfoFor::::insert(2, ongoing_v0); + // create and insert into the storage an approved referendum v0. + let approved_v0 = v0::ReferendumInfoOf::::Approved( + 123, + Deposit { who: 1, amount: 10 }, + Some(Deposit { who: 2, amount: 20 }), + ); + v0::ReferendumInfoFor::::insert(5, approved_v0); + // run migration from v0 to v1. + v1::MigrateV0ToV1::::on_runtime_upgrade(); + // fetch and assert migrated into v1 the ongoing referendum. + let ongoing_v1 = ReferendumInfoFor::::get(2).unwrap(); + // referendum status schema is the same for v0 and v1. + assert_eq!(ReferendumInfoOf::::Ongoing(status_v0), ongoing_v1); + // fetch and assert migrated into v1 the approved referendum. + let approved_v1 = ReferendumInfoFor::::get(5).unwrap(); + assert_eq!( + approved_v1, + ReferendumInfoOf::::Approved( + 123, + Some(Deposit { who: 1, amount: 10 }), + Some(Deposit { who: 2, amount: 20 }) + ) + ); + }); + } +} diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index db67825210360..c109fafe332e2 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -443,6 +443,44 @@ fn refund_deposit_works() { }); } +#[test] +fn refund_submission_deposit_works() { + new_test_ext().execute_with(|| { + // refund of non existing referendum fails. + let e = Error::::BadReferendum; + assert_noop!(Referenda::refund_submission_deposit(RuntimeOrigin::signed(1), 0), e); + // create a referendum. + let h = set_balance_proposal_bounded(1); + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + h.clone(), + DispatchTime::At(10), + )); + // refund of an ongoing referendum fails. + let e = Error::::BadStatus; + assert_noop!(Referenda::refund_submission_deposit(RuntimeOrigin::signed(3), 0), e); + // cancel referendum. + assert_ok!(Referenda::cancel(RuntimeOrigin::signed(4), 0)); + // refund of canceled referendum works. + assert_ok!(Referenda::refund_submission_deposit(RuntimeOrigin::signed(3), 0)); + // fails if already refunded. + let e = Error::::NoDeposit; + assert_noop!(Referenda::refund_submission_deposit(RuntimeOrigin::signed(2), 0), e); + // create second referendum. + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + h, + DispatchTime::At(10), + )); + // refund of a killed referendum fails. + assert_ok!(Referenda::kill(RuntimeOrigin::root(), 1)); + let e = Error::::NoDeposit; + assert_noop!(Referenda::refund_submission_deposit(RuntimeOrigin::signed(2), 0), e); + }); +} + #[test] fn cancel_works() { new_test_ext().execute_with(|| { diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 3d5fa753f53ff..0763a71a95ba3 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -221,13 +221,13 @@ pub enum ReferendumInfo< >, ), /// Referendum finished with approval. Submission deposit is held. - Approved(Moment, Deposit, Option>), + Approved(Moment, Option>, Option>), /// Referendum finished with rejection. Submission deposit is held. - Rejected(Moment, Deposit, Option>), + Rejected(Moment, Option>, Option>), /// Referendum finished with cancellation. Submission deposit is held. - Cancelled(Moment, Deposit, Option>), + Cancelled(Moment, Option>, Option>), /// Referendum finished and was never decided. Submission deposit is held. - TimedOut(Moment, Deposit, Option>), + TimedOut(Moment, Option>, Option>), /// Referendum finished with a kill. Killed(Moment), } @@ -256,6 +256,19 @@ impl< Killed(_) => Ok(None), } } + + /// Take the Submission Deposit from `self`, if there is one and it's in a valid state to be + /// taken. Returns an `Err` if `self` is not in a valid state for the Submission Deposit to be + /// refunded. + pub fn take_submission_deposit(&mut self) -> Result>, ()> { + use ReferendumInfo::*; + match self { + // Can only refund deposit if it's appoved or cancelled. + Approved(_, s, _) | Cancelled(_, s, _) => Ok(s.take()), + // Cannot refund deposit if Ongoing as this breaks assumptions. + Ongoing(..) | Rejected(..) | TimedOut(..) | Killed(..) => Err(()), + } + } } /// Type for describing a curve over the 2-dimensional space of axes between 0-1, as represented diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index d8609abb9fe80..f0eae517af743 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -1,8 +1,3 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -18,24 +13,22 @@ //! Autogenerated weights for pallet_referenda //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! DATE: 2022-11-27, STEPS: `20`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `cob`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// ./target/release/substrate // benchmark // pallet // --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_referenda +// --steps=20 +// --repeat=1 +// --pallet=pallet-referenda // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/referenda/src/weights.rs -// --header=./HEADER-APACHE2 +// --output=./frame/referenda/src/._weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -54,6 +47,7 @@ pub trait WeightInfo { fn place_decision_deposit_passing() -> Weight; fn place_decision_deposit_failing() -> Weight; fn refund_decision_deposit() -> Weight; + fn refund_submission_deposit() -> Weight; fn cancel() -> Weight; fn kill() -> Weight; fn one_fewer_deciding_queue_empty() -> Weight; @@ -83,231 +77,238 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - // Minimum execution time: 41_475 nanoseconds. - Weight::from_ref_time(42_153_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(29_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - // Minimum execution time: 52_291 nanoseconds. - Weight::from_ref_time(53_147_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 35_000 nanoseconds. + Weight::from_ref_time(35_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - // Minimum execution time: 57_322 nanoseconds. - Weight::from_ref_time(58_145_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 40_000 nanoseconds. + Weight::from_ref_time(40_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - // Minimum execution time: 57_170 nanoseconds. - Weight::from_ref_time(58_012_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 39_000 nanoseconds. + Weight::from_ref_time(39_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - // Minimum execution time: 67_805 nanoseconds. - Weight::from_ref_time(68_844_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 43_000 nanoseconds. + Weight::from_ref_time(43_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - // Minimum execution time: 63_408 nanoseconds. - Weight::from_ref_time(64_049_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 84_000 nanoseconds. + Weight::from_ref_time(84_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - // Minimum execution time: 36_639 nanoseconds. - Weight::from_ref_time(37_329_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 25_000 nanoseconds. + Weight::from_ref_time(25_000_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + fn refund_submission_deposit() -> Weight { + // Minimum execution time: 25_000 nanoseconds. + Weight::from_ref_time(25_000_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - // Minimum execution time: 42_442 nanoseconds. - Weight::from_ref_time(43_006_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 26_000 nanoseconds. + Weight::from_ref_time(26_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - // Minimum execution time: 74_681 nanoseconds. - Weight::from_ref_time(75_567_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 47_000 nanoseconds. + Weight::from_ref_time(47_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - // Minimum execution time: 14_262 nanoseconds. - Weight::from_ref_time(14_504_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 8_000 nanoseconds. + Weight::from_ref_time(8_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - // Minimum execution time: 88_618 nanoseconds. - Weight::from_ref_time(89_443_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 88_000 nanoseconds. + Weight::from_ref_time(88_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - // Minimum execution time: 89_784 nanoseconds. - Weight::from_ref_time(90_619_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 75_000 nanoseconds. + Weight::from_ref_time(75_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - // Minimum execution time: 73_179 nanoseconds. - Weight::from_ref_time(74_025_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 72_000 nanoseconds. + Weight::from_ref_time(72_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - // Minimum execution time: 73_168 nanoseconds. - Weight::from_ref_time(73_769_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 56_000 nanoseconds. + Weight::from_ref_time(56_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - // Minimum execution time: 75_027 nanoseconds. - Weight::from_ref_time(76_220_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 55_000 nanoseconds. + Weight::from_ref_time(55_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - // Minimum execution time: 74_815 nanoseconds. - Weight::from_ref_time(75_803_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 60_000 nanoseconds. + Weight::from_ref_time(60_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - // Minimum execution time: 31_877 nanoseconds. - Weight::from_ref_time(32_236_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 22_000 nanoseconds. + Weight::from_ref_time(22_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - // Minimum execution time: 33_322 nanoseconds. - Weight::from_ref_time(33_762_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 21_000 nanoseconds. + Weight::from_ref_time(21_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - // Minimum execution time: 25_393 nanoseconds. - Weight::from_ref_time(25_913_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 17_000 nanoseconds. + Weight::from_ref_time(17_000_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - // Minimum execution time: 47_114 nanoseconds. - Weight::from_ref_time(47_586_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(29_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - // Minimum execution time: 48_443 nanoseconds. - Weight::from_ref_time(50_003_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 39_000 nanoseconds. + Weight::from_ref_time(39_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - // Minimum execution time: 44_556 nanoseconds. - Weight::from_ref_time(45_167_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 31_000 nanoseconds. + Weight::from_ref_time(31_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - // Minimum execution time: 45_474 nanoseconds. - Weight::from_ref_time(46_105_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 30_000 nanoseconds. + Weight::from_ref_time(30_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - // Minimum execution time: 42_795 nanoseconds. - Weight::from_ref_time(43_123_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 28_000 nanoseconds. + Weight::from_ref_time(28_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - // Minimum execution time: 41_928 nanoseconds. - Weight::from_ref_time(42_272_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 30_000 nanoseconds. + Weight::from_ref_time(30_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:1 w:1) fn nudge_referendum_approved() -> Weight { - // Minimum execution time: 55_186 nanoseconds. - Weight::from_ref_time(55_714_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 45_000 nanoseconds. + Weight::from_ref_time(45_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - // Minimum execution time: 44_892 nanoseconds. - Weight::from_ref_time(45_353_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 30_000 nanoseconds. + Weight::from_ref_time(30_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } } @@ -317,230 +318,237 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:0 w:1) fn submit() -> Weight { - // Minimum execution time: 41_475 nanoseconds. - Weight::from_ref_time(42_153_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(29_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_preparing() -> Weight { - // Minimum execution time: 52_291 nanoseconds. - Weight::from_ref_time(53_147_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 35_000 nanoseconds. + Weight::from_ref_time(35_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_queued() -> Weight { - // Minimum execution time: 57_322 nanoseconds. - Weight::from_ref_time(58_145_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 40_000 nanoseconds. + Weight::from_ref_time(40_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) fn place_decision_deposit_not_queued() -> Weight { - // Minimum execution time: 57_170 nanoseconds. - Weight::from_ref_time(58_012_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 39_000 nanoseconds. + Weight::from_ref_time(39_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_passing() -> Weight { - // Minimum execution time: 67_805 nanoseconds. - Weight::from_ref_time(68_844_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 43_000 nanoseconds. + Weight::from_ref_time(43_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn place_decision_deposit_failing() -> Weight { - // Minimum execution time: 63_408 nanoseconds. - Weight::from_ref_time(64_049_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 84_000 nanoseconds. + Weight::from_ref_time(84_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn refund_decision_deposit() -> Weight { - // Minimum execution time: 36_639 nanoseconds. - Weight::from_ref_time(37_329_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 25_000 nanoseconds. + Weight::from_ref_time(25_000_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Referenda ReferendumInfoFor (r:1 w:1) + fn refund_submission_deposit() -> Weight { + // Minimum execution time: 25_000 nanoseconds. + Weight::from_ref_time(25_000_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn cancel() -> Weight { - // Minimum execution time: 42_442 nanoseconds. - Weight::from_ref_time(43_006_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 26_000 nanoseconds. + Weight::from_ref_time(26_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn kill() -> Weight { - // Minimum execution time: 74_681 nanoseconds. - Weight::from_ref_time(75_567_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 47_000 nanoseconds. + Weight::from_ref_time(47_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Referenda TrackQueue (r:1 w:0) // Storage: Referenda DecidingCount (r:1 w:1) fn one_fewer_deciding_queue_empty() -> Weight { - // Minimum execution time: 14_262 nanoseconds. - Weight::from_ref_time(14_504_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 8_000 nanoseconds. + Weight::from_ref_time(8_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_failing() -> Weight { - // Minimum execution time: 88_618 nanoseconds. - Weight::from_ref_time(89_443_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 88_000 nanoseconds. + Weight::from_ref_time(88_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) fn one_fewer_deciding_passing() -> Weight { - // Minimum execution time: 89_784 nanoseconds. - Weight::from_ref_time(90_619_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 75_000 nanoseconds. + Weight::from_ref_time(75_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_insertion() -> Weight { - // Minimum execution time: 73_179 nanoseconds. - Weight::from_ref_time(74_025_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 72_000 nanoseconds. + Weight::from_ref_time(72_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_requeued_slide() -> Weight { - // Minimum execution time: 73_168 nanoseconds. - Weight::from_ref_time(73_769_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 56_000 nanoseconds. + Weight::from_ref_time(56_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_queued() -> Weight { - // Minimum execution time: 75_027 nanoseconds. - Weight::from_ref_time(76_220_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 55_000 nanoseconds. + Weight::from_ref_time(55_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:0) // Storage: Referenda TrackQueue (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_not_queued() -> Weight { - // Minimum execution time: 74_815 nanoseconds. - Weight::from_ref_time(75_803_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 60_000 nanoseconds. + Weight::from_ref_time(60_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_no_deposit() -> Weight { - // Minimum execution time: 31_877 nanoseconds. - Weight::from_ref_time(32_236_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 22_000 nanoseconds. + Weight::from_ref_time(22_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_preparing() -> Weight { - // Minimum execution time: 33_322 nanoseconds. - Weight::from_ref_time(33_762_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 21_000 nanoseconds. + Weight::from_ref_time(21_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) fn nudge_referendum_timed_out() -> Weight { - // Minimum execution time: 25_393 nanoseconds. - Weight::from_ref_time(25_913_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 17_000 nanoseconds. + Weight::from_ref_time(17_000_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_failing() -> Weight { - // Minimum execution time: 47_114 nanoseconds. - Weight::from_ref_time(47_586_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 29_000 nanoseconds. + Weight::from_ref_time(29_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Referenda DecidingCount (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_deciding_passing() -> Weight { - // Minimum execution time: 48_443 nanoseconds. - Weight::from_ref_time(50_003_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 39_000 nanoseconds. + Weight::from_ref_time(39_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_begin_confirming() -> Weight { - // Minimum execution time: 44_556 nanoseconds. - Weight::from_ref_time(45_167_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 31_000 nanoseconds. + Weight::from_ref_time(31_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_end_confirming() -> Weight { - // Minimum execution time: 45_474 nanoseconds. - Weight::from_ref_time(46_105_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 30_000 nanoseconds. + Weight::from_ref_time(30_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_not_confirming() -> Weight { - // Minimum execution time: 42_795 nanoseconds. - Weight::from_ref_time(43_123_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 28_000 nanoseconds. + Weight::from_ref_time(28_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_continue_confirming() -> Weight { - // Minimum execution time: 41_928 nanoseconds. - Weight::from_ref_time(42_272_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 30_000 nanoseconds. + Weight::from_ref_time(30_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:1 w:1) fn nudge_referendum_approved() -> Weight { - // Minimum execution time: 55_186 nanoseconds. - Weight::from_ref_time(55_714_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 45_000 nanoseconds. + Weight::from_ref_time(45_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Referenda ReferendumInfoFor (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn nudge_referendum_rejected() -> Weight { - // Minimum execution time: 44_892 nanoseconds. - Weight::from_ref_time(45_353_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 30_000 nanoseconds. + Weight::from_ref_time(30_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } } From 5722ece5efb61cc82307f3e919a60bd4e807f1df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 7 Dec 2022 13:48:30 +0100 Subject: [PATCH 1445/1472] Remove sandboxing host function interface (#12852) * Remove sandboxing interface * Remove unused struct --- .gitlab-ci.yml | 20 - Cargo.lock | 634 +----------------- Cargo.toml | 1 - bin/node/runtime/Cargo.toml | 7 - client/executor/Cargo.toml | 3 - client/executor/common/Cargo.toml | 7 - client/executor/common/src/error.rs | 3 - client/executor/common/src/lib.rs | 1 - client/executor/common/src/sandbox.rs | 585 ---------------- .../common/src/sandbox/wasmer_backend.rs | 449 ------------- .../common/src/sandbox/wasmi_backend.rs | 339 ---------- client/executor/runtime-test/Cargo.toml | 3 - client/executor/runtime-test/src/lib.rs | 159 ----- client/executor/src/integration_tests/mod.rs | 106 --- .../executor/src/integration_tests/sandbox.rs | 339 ---------- client/executor/src/lib.rs | 2 +- client/executor/wasmi/Cargo.toml | 2 - client/executor/wasmi/src/lib.rs | 232 +------ client/executor/wasmtime/Cargo.toml | 4 +- client/executor/wasmtime/src/host.rs | 277 +------- client/executor/wasmtime/src/runtime.rs | 10 - client/executor/wasmtime/src/util.rs | 18 - primitives/io/src/lib.rs | 94 --- primitives/sandbox/Cargo.toml | 40 -- primitives/sandbox/README.md | 21 - primitives/sandbox/src/embedded_executor.rs | 478 ------------- primitives/sandbox/src/env.rs | 120 ---- primitives/sandbox/src/host_executor.rs | 274 -------- primitives/sandbox/src/lib.rs | 190 ------ primitives/wasm-interface/src/lib.rs | 57 -- scripts/ci/gitlab/pipeline/test.yml | 37 +- 31 files changed, 34 insertions(+), 4478 deletions(-) delete mode 100644 client/executor/common/src/sandbox.rs delete mode 100644 client/executor/common/src/sandbox/wasmer_backend.rs delete mode 100644 client/executor/common/src/sandbox/wasmi_backend.rs delete mode 100644 client/executor/src/integration_tests/sandbox.rs delete mode 100644 primitives/sandbox/Cargo.toml delete mode 100644 primitives/sandbox/README.md delete mode 100644 primitives/sandbox/src/embedded_executor.rs delete mode 100644 primitives/sandbox/src/env.rs delete mode 100644 primitives/sandbox/src/host_executor.rs delete mode 100644 primitives/sandbox/src/lib.rs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 992a2d491ae02..5b6748155444d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -166,26 +166,6 @@ default: - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs -.test-refs-wasmer-sandbox: - rules: - - if: $CI_PIPELINE_SOURCE == "web" - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - changes: - - client/executor/**/* - - frame/contracts/**/* - - primitives/sandbox/**/* - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - changes: - - client/executor/**/* - - frame/contracts/**/* - - primitives/sandbox/**/* - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - changes: - - client/executor/**/* - - frame/contracts/**/* - - primitives/sandbox/**/* - .build-refs: rules: - if: $CI_PIPELINE_SOURCE == "pipeline" diff --git a/Cargo.lock b/Cargo.lock index 17b66c920cd79..f2b394e099381 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ - "gimli 0.26.1", + "gimli", ] [[package]] @@ -648,27 +648,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -[[package]] -name = "bytecheck" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314889ea31cda264cb7c3d6e6e5c9415a987ecb0e72c17c00d36fbb881d34abe" -dependencies = [ - "bytecheck_derive", - "ptr_meta", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a2b3b92c135dae665a6f760205b89187638e83bed17ef3e44e83c712cf30600" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "byteorder" version = "1.4.3" @@ -1020,39 +999,13 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" -[[package]] -name = "cranelift-bforest" -version = "0.76.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e6bea67967505247f54fa2c85cf4f6e0e31c4e5692c9b70e4ae58e339067333" -dependencies = [ - "cranelift-entity 0.76.0", -] - [[package]] name = "cranelift-bforest" version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b27bbd3e6c422cf6282b047bcdd51ecd9ca9f3497a3be0132ffa08e509b824b0" dependencies = [ - "cranelift-entity 0.88.0", -] - -[[package]] -name = "cranelift-codegen" -version = "0.76.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48194035d2752bdd5bdae429e3ab88676e95f52a2b1355a5d4e809f9e39b1d74" -dependencies = [ - "cranelift-bforest 0.76.0", - "cranelift-codegen-meta 0.76.0", - "cranelift-codegen-shared 0.76.0", - "cranelift-entity 0.76.0", - "gimli 0.25.0", - "log", - "regalloc", - "smallvec", - "target-lexicon", + "cranelift-entity", ] [[package]] @@ -1063,55 +1016,33 @@ checksum = "872f5d4557a411b087bd731df6347c142ae1004e6467a144a7e33662e5715a01" dependencies = [ "arrayvec 0.7.2", "bumpalo", - "cranelift-bforest 0.88.0", - "cranelift-codegen-meta 0.88.0", - "cranelift-codegen-shared 0.88.0", - "cranelift-entity 0.88.0", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", "cranelift-isle", - "gimli 0.26.1", + "gimli", "log", "regalloc2", "smallvec", "target-lexicon", ] -[[package]] -name = "cranelift-codegen-meta" -version = "0.76.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976efb22fcab4f2cd6bd4e9913764616a54d895c1a23530128d04e03633c555f" -dependencies = [ - "cranelift-codegen-shared 0.76.0", - "cranelift-entity 0.76.0", -] - [[package]] name = "cranelift-codegen-meta" version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21b49fdebb29c62c1fc4da1eeebd609e9d530ecde24a9876def546275f73a244" dependencies = [ - "cranelift-codegen-shared 0.88.0", + "cranelift-codegen-shared", ] -[[package]] -name = "cranelift-codegen-shared" -version = "0.76.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dabb5fe66e04d4652e434195b45ae65b5c8172d520247b8f66d8df42b2b45dc" - [[package]] name = "cranelift-codegen-shared" version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fc0c091e2db055d4d7f6b7cec2d2ead286bcfaea3357c6a52c2a2613a8cb5ac" -[[package]] -name = "cranelift-entity" -version = "0.76.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3329733e4d4b8e91c809efcaa4faee80bf66f20164e3dd16d707346bd3494799" - [[package]] name = "cranelift-entity" version = "0.88.0" @@ -1121,25 +1052,13 @@ dependencies = [ "serde", ] -[[package]] -name = "cranelift-frontend" -version = "0.76.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279afcc0d3e651b773f94837c3d581177b348c8d69e928104b2e9fccb226f921" -dependencies = [ - "cranelift-codegen 0.76.0", - "log", - "smallvec", - "target-lexicon", -] - [[package]] name = "cranelift-frontend" version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cd8dd3fb8b82c772f4172e87ae1677b971676fffa7c4e3398e3047e650a266b" dependencies = [ - "cranelift-codegen 0.88.0", + "cranelift-codegen", "log", "smallvec", "target-lexicon", @@ -1157,7 +1076,7 @@ version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c30ba8b910f1be023af0c39109cb28a8809734942a6b3eecbf2de8993052ea5e" dependencies = [ - "cranelift-codegen 0.88.0", + "cranelift-codegen", "libc", "target-lexicon", ] @@ -1168,13 +1087,13 @@ version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "776a8916d201894aca9637a20814f1e11abc62acd5cfbe0b4eb2e63922756971" dependencies = [ - "cranelift-codegen 0.88.0", - "cranelift-entity 0.88.0", - "cranelift-frontend 0.88.0", + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", "itertools", "log", "smallvec", - "wasmparser 0.89.1", + "wasmparser", "wasmtime-types", ] @@ -1441,41 +1360,6 @@ dependencies = [ "syn", ] -[[package]] -name = "darling" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc" -dependencies = [ - "darling_core", - "quote", - "syn", -] - [[package]] name = "data-encoding" version = "2.3.2" @@ -1672,32 +1556,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21e50f3adc76d6a43f5ed73b698a87d0760ca74617f60f7c3b879003536fdd28" -[[package]] -name = "dynasm" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add9a102807b524ec050363f09e06f1504214b0e1c7797f64261c891022dce8b" -dependencies = [ - "bitflags", - "byteorder", - "lazy_static", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "dynasmrt" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" -dependencies = [ - "byteorder", - "dynasm", - "memmap2", -] - [[package]] name = "ecdsa" version = "0.14.7" @@ -1784,26 +1642,6 @@ dependencies = [ "syn", ] -[[package]] -name = "enum-iterator" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" -dependencies = [ - "enum-iterator-derive", -] - -[[package]] -name = "enum-iterator-derive" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "enumflags2" version = "0.7.4" @@ -1824,27 +1662,6 @@ dependencies = [ "syn", ] -[[package]] -name = "enumset" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e76129da36102af021b8e5000dab2c1c30dbef85c1e482beeff8da5dde0e0b0" -dependencies = [ - "enumset_derive", -] - -[[package]] -name = "enumset_derive" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6451128aa6655d880755345d085494cf7561a6bee7c8dc821e5d77e6d267ecd4" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "env_logger" version = "0.9.0" @@ -2630,17 +2447,6 @@ dependencies = [ "polyval", ] -[[package]] -name = "gimli" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" -dependencies = [ - "fallible-iterator", - "indexmap", - "stable_deref_trait", -] - [[package]] name = "gimli" version = "0.26.1" @@ -2754,9 +2560,6 @@ name = "hashbrown" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] [[package]] name = "hashbrown" @@ -2930,12 +2733,6 @@ dependencies = [ "tokio-rustls", ] -[[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" @@ -3365,7 +3162,6 @@ dependencies = [ "sp-io", "sp-offchain", "sp-runtime", - "sp-sandbox", "sp-session", "sp-staking", "sp-std", @@ -3943,27 +3739,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "loupe" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d" -dependencies = [ - "indexmap", - "loupe-derive", - "rustversion", -] - -[[package]] -name = "loupe-derive" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "lru" version = "0.8.1" @@ -4197,12 +3972,6 @@ dependencies = [ "syn", ] -[[package]] -name = "more-asserts" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" - [[package]] name = "multiaddr" version = "0.14.0" @@ -4854,18 +4623,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "object" -version = "0.28.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456" -dependencies = [ - "crc32fast", - "hashbrown 0.11.2", - "indexmap", - "memchr", -] - [[package]] name = "object" version = "0.29.0" @@ -6865,26 +6622,6 @@ dependencies = [ "cc", ] -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -7096,17 +6833,6 @@ dependencies = [ "syn", ] -[[package]] -name = "regalloc" -version = "0.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" -dependencies = [ - "log", - "rustc-hash", - "smallvec", -] - [[package]] name = "regalloc2" version = "0.3.2" @@ -7146,18 +6872,6 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" -[[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 = "remove_dir_all" version = "0.5.3" @@ -7167,15 +6881,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "rend" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" -dependencies = [ - "bytecheck", -] - [[package]] name = "resolv-conf" version = "0.7.0" @@ -7212,31 +6917,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "rkyv" -version = "0.7.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f08c8062c1fe1253064043b8fc07bfea1b9702b71b4a86c11ea3588183b12e1" -dependencies = [ - "bytecheck", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e289706df51226e84814bf6ba1a9e1013112ae29bc7a9878f73fce360520c403" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "rocksdb" version = "0.19.0" @@ -7867,7 +7547,6 @@ dependencies = [ "array-bytes", "criterion", "env_logger", - "lazy_static", "lru", "num_cpus", "parity-scale-codec", @@ -7881,7 +7560,6 @@ dependencies = [ "sc-tracing", "sp-api", "sp-core", - "sp-core-hashing-proc-macro", "sp-externalities", "sp-io", "sp-maybe-compressed-blob", @@ -7904,15 +7582,11 @@ dependencies = [ name = "sc-executor-common" version = "0.10.0-dev" dependencies = [ - "environmental", - "parity-scale-codec", "sc-allocator", "sp-maybe-compressed-blob", - "sp-sandbox", "sp-wasm-interface", "thiserror", "wasm-instrument 0.3.0", - "wasmer", "wasmi 0.13.0", ] @@ -7921,11 +7595,9 @@ name = "sc-executor-wasmi" version = "0.10.0-dev" dependencies = [ "log", - "parity-scale-codec", "sc-allocator", "sc-executor-common", "sp-runtime-interface", - "sp-sandbox", "sp-wasm-interface", "wasmi 0.13.0", ] @@ -7939,7 +7611,6 @@ dependencies = [ "log", "once_cell", "parity-scale-codec", - "parity-wasm", "paste", "rustix", "sc-allocator", @@ -7947,7 +7618,6 @@ dependencies = [ "sc-runtime-test", "sp-io", "sp-runtime-interface", - "sp-sandbox", "sp-wasm-interface", "tempfile", "wasmtime", @@ -8443,11 +8113,9 @@ dependencies = [ name = "sc-runtime-test" version = "2.0.0" dependencies = [ - "paste", "sp-core", "sp-io", "sp-runtime", - "sp-sandbox", "sp-std", "substrate-wasm-builder", ] @@ -8802,12 +8470,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - [[package]] name = "sec1" version = "0.3.0" @@ -8914,15 +8576,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde_bytes" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" -dependencies = [ - "serde", -] - [[package]] name = "serde_cbor" version = "0.11.1" @@ -9777,21 +9430,6 @@ dependencies = [ "substrate-wasm-builder", ] -[[package]] -name = "sp-sandbox" -version = "0.10.0-dev" -dependencies = [ - "assert_matches", - "log", - "parity-scale-codec", - "sp-core", - "sp-io", - "sp-std", - "sp-wasm-interface", - "wasmi 0.13.0", - "wat", -] - [[package]] name = "sp-serializer" version = "4.0.0-dev" @@ -10721,7 +10359,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ "cfg-if", - "log", "pin-project-lite 0.2.6", "tracing-attributes", "tracing-core", @@ -11301,219 +10938,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasmer" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f727a39e7161f7438ddb8eafe571b67c576a8c2fb459f666d9053b5bba4afdea" -dependencies = [ - "cfg-if", - "indexmap", - "js-sys", - "loupe", - "more-asserts", - "target-lexicon", - "thiserror", - "wasm-bindgen", - "wasmer-compiler", - "wasmer-compiler-cranelift", - "wasmer-compiler-singlepass", - "wasmer-derive", - "wasmer-engine", - "wasmer-engine-dylib", - "wasmer-engine-universal", - "wasmer-types", - "wasmer-vm", - "wat", - "winapi", -] - -[[package]] -name = "wasmer-compiler" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9951599222eb12bd13d4d91bcded0a880e4c22c2dfdabdf5dc7e5e803b7bf3" -dependencies = [ - "enumset", - "loupe", - "rkyv", - "serde", - "serde_bytes", - "smallvec", - "target-lexicon", - "thiserror", - "wasmer-types", - "wasmer-vm", - "wasmparser 0.78.2", -] - -[[package]] -name = "wasmer-compiler-cranelift" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c83273bce44e668f3a2b9ccb7f1193db918b1d6806f64acc5ff71f6ece5f20" -dependencies = [ - "cranelift-codegen 0.76.0", - "cranelift-entity 0.76.0", - "cranelift-frontend 0.76.0", - "gimli 0.25.0", - "loupe", - "more-asserts", - "rayon", - "smallvec", - "target-lexicon", - "tracing", - "wasmer-compiler", - "wasmer-types", - "wasmer-vm", -] - -[[package]] -name = "wasmer-compiler-singlepass" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5432e993840cdb8e6875ddc8c9eea64e7a129579b4706bd91b8eb474d9c4a860" -dependencies = [ - "byteorder", - "dynasm", - "dynasmrt", - "lazy_static", - "loupe", - "more-asserts", - "rayon", - "smallvec", - "wasmer-compiler", - "wasmer-types", - "wasmer-vm", -] - -[[package]] -name = "wasmer-derive" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458dbd9718a837e6dbc52003aef84487d79eedef5fa28c7d28b6784be98ac08e" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "wasmer-engine" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed603a6d037ebbb14014d7f739ae996a78455a4b86c41cfa4e81c590a1253b9" -dependencies = [ - "backtrace", - "enumset", - "lazy_static", - "loupe", - "memmap2", - "more-asserts", - "rustc-demangle", - "serde", - "serde_bytes", - "target-lexicon", - "thiserror", - "wasmer-compiler", - "wasmer-types", - "wasmer-vm", -] - -[[package]] -name = "wasmer-engine-dylib" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd7fdc60e252a795c849b3f78a81a134783051407e7e279c10b7019139ef8dc" -dependencies = [ - "cfg-if", - "enum-iterator", - "enumset", - "leb128", - "libloading", - "loupe", - "object 0.28.3", - "rkyv", - "serde", - "tempfile", - "tracing", - "wasmer-compiler", - "wasmer-engine", - "wasmer-object", - "wasmer-types", - "wasmer-vm", - "which", -] - -[[package]] -name = "wasmer-engine-universal" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcff0cd2c01a8de6009fd863b14ea883132a468a24f2d2ee59dc34453d3a31b5" -dependencies = [ - "cfg-if", - "enum-iterator", - "enumset", - "leb128", - "loupe", - "region", - "rkyv", - "wasmer-compiler", - "wasmer-engine", - "wasmer-types", - "wasmer-vm", - "winapi", -] - -[[package]] -name = "wasmer-object" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ce18ac2877050e59580d27ee1a88f3192d7a31e77fbba0852abc7888d6e0b5" -dependencies = [ - "object 0.28.3", - "thiserror", - "wasmer-compiler", - "wasmer-types", -] - -[[package]] -name = "wasmer-types" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659fa3dd6c76f62630deff4ac8c7657b07f0b1e4d7e0f8243a552b9d9b448e24" -dependencies = [ - "indexmap", - "loupe", - "rkyv", - "serde", - "thiserror", -] - -[[package]] -name = "wasmer-vm" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afdc46158517c2769f9938bc222a7d41b3bb330824196279d8aa2d667cd40641" -dependencies = [ - "backtrace", - "cc", - "cfg-if", - "enum-iterator", - "indexmap", - "libc", - "loupe", - "memoffset", - "more-asserts", - "region", - "rkyv", - "serde", - "thiserror", - "wasmer-types", - "winapi", -] - [[package]] name = "wasmi" version = "0.13.0" @@ -11576,12 +11000,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "wasmparser" -version = "0.78.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" - [[package]] name = "wasmparser" version = "0.89.1" @@ -11619,7 +11037,7 @@ dependencies = [ "rayon", "serde", "target-lexicon", - "wasmparser 0.89.1", + "wasmparser", "wasmtime-cache", "wasmtime-cranelift", "wasmtime-environ", @@ -11664,17 +11082,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f03cf79d982fc68e94ba0bea6a300a3b94621c4eb9705eece0a4f06b235a3b5" dependencies = [ "anyhow", - "cranelift-codegen 0.88.0", - "cranelift-entity 0.88.0", - "cranelift-frontend 0.88.0", + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli 0.26.1", + "gimli", "log", "object 0.29.0", "target-lexicon", "thiserror", - "wasmparser 0.89.1", + "wasmparser", "wasmtime-environ", ] @@ -11685,15 +11103,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c587c62e91c5499df62012b87b88890d0eb470b2ffecc5964e9da967b70c77c" dependencies = [ "anyhow", - "cranelift-entity 0.88.0", - "gimli 0.26.1", + "cranelift-entity", + "gimli", "indexmap", "log", "object 0.29.0", "serde", "target-lexicon", "thiserror", - "wasmparser 0.89.1", + "wasmparser", "wasmtime-types", ] @@ -11708,7 +11126,7 @@ dependencies = [ "bincode", "cfg-if", "cpp_demangle", - "gimli 0.26.1", + "gimli", "log", "object 0.29.0", "rustc-demangle", @@ -11764,10 +11182,10 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790cf43ee8e2d5dad1780af30f00d7a972b74725fb1e4f90c28d62733819b185" dependencies = [ - "cranelift-entity 0.88.0", + "cranelift-entity", "serde", "thiserror", - "wasmparser 0.89.1", + "wasmparser", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e885f0916ca8e..64ceb104c649c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -199,7 +199,6 @@ members = [ "primitives/runtime-interface/test", "primitives/runtime-interface/test-wasm", "primitives/runtime-interface/test-wasm-deprecated", - "primitives/sandbox", "primitives/serializer", "primitives/session", "primitives/staking", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index dfddf6a89499b..706d2c7720e2f 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -39,7 +39,6 @@ sp-session = { version = "4.0.0-dev", default-features = false, path = "../../.. sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" } sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } -sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } # frame dependencies frame-executive = { version = "4.0.0-dev", default-features = false, path = "../../../frame/executive" } @@ -117,7 +116,6 @@ substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-bu default = ["std"] with-tracing = ["frame-executive/with-tracing"] std = [ - "sp-sandbox/std", "pallet-whitelist/std", "pallet-offences-benchmarking?/std", "pallet-election-provider-support-benchmarking?/std", @@ -312,8 +310,3 @@ try-runtime = [ "pallet-vesting/try-runtime", "pallet-whitelist/try-runtime", ] -# Force `sp-sandbox` to call into the host resident executor. One still need to make sure -# that `sc-executor` gets the `wasmer-sandbox` feature which happens automatically when -# specified on the command line. -# Don't use that on a production chain. -wasmer-sandbox = ["sp-sandbox/wasmer-sandbox"] diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 7cba725a9ea45..83d4801d1c92b 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -14,7 +14,6 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -lazy_static = "1.4.0" lru = "0.8.1" parking_lot = "0.12.1" tracing = "0.1.29" @@ -26,7 +25,6 @@ sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" } sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-core = { version = "7.0.0", path = "../../primitives/core" } -sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" } sp-externalities = { version = "0.13.0", path = "../../primitives/externalities" } sp-io = { version = "7.0.0", path = "../../primitives/io" } sp-panic-handler = { version = "5.0.0", path = "../../primitives/panic-handler" } @@ -61,4 +59,3 @@ default = ["std"] # This crate does not have `no_std` support, we just require this for tests std = [] wasm-extern-trace = [] -wasmer-sandbox = ["sc-executor-common/wasmer-sandbox"] diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 4b83e9fcc9b92..648e937d371ff 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -14,19 +14,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } -environmental = "1.1.3" thiserror = "1.0.30" wasm-instrument = "0.3" -wasmer = { version = "2.2", features = ["singlepass"], optional = true } wasmi = "0.13" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } -sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interface" } [features] default = [] -wasmer-sandbox = [ - "wasmer", -] diff --git a/client/executor/common/src/error.rs b/client/executor/common/src/error.rs index 376ac190bd7b7..c35a874b7796d 100644 --- a/client/executor/common/src/error.rs +++ b/client/executor/common/src/error.rs @@ -30,9 +30,6 @@ pub enum Error { #[error(transparent)] Wasmi(#[from] wasmi::Error), - #[error("Sandbox error: {0}")] - Sandbox(String), - #[error("Error calling api function: {0}")] ApiError(Box), diff --git a/client/executor/common/src/lib.rs b/client/executor/common/src/lib.rs index b69883afbaac2..79bb74b62a41e 100644 --- a/client/executor/common/src/lib.rs +++ b/client/executor/common/src/lib.rs @@ -23,6 +23,5 @@ pub mod error; pub mod runtime_blob; -pub mod sandbox; pub mod util; pub mod wasm_runtime; diff --git a/client/executor/common/src/sandbox.rs b/client/executor/common/src/sandbox.rs deleted file mode 100644 index 1e925bd5a7835..0000000000000 --- a/client/executor/common/src/sandbox.rs +++ /dev/null @@ -1,585 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! This module implements sandboxing support in the runtime. -//! -//! Sandboxing is backed by wasmi and wasmer, depending on the configuration. - -#[cfg(feature = "wasmer-sandbox")] -mod wasmer_backend; -mod wasmi_backend; - -use std::{collections::HashMap, rc::Rc}; - -use codec::Decode; -use sp_sandbox::env as sandbox_env; -use sp_wasm_interface::{FunctionContext, Pointer, WordSize}; - -use crate::{ - error::{self, Result}, - util, -}; - -#[cfg(feature = "wasmer-sandbox")] -use self::wasmer_backend::{ - get_global as wasmer_get_global, instantiate as wasmer_instantiate, invoke as wasmer_invoke, - new_memory as wasmer_new_memory, Backend as WasmerBackend, - MemoryWrapper as WasmerMemoryWrapper, -}; -use self::wasmi_backend::{ - get_global as wasmi_get_global, instantiate as wasmi_instantiate, invoke as wasmi_invoke, - new_memory as wasmi_new_memory, MemoryWrapper as WasmiMemoryWrapper, -}; - -/// Index of a function inside the supervisor. -/// -/// This is a typically an index in the default table of the supervisor, however -/// the exact meaning of this index is depends on the implementation of dispatch function. -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct SupervisorFuncIndex(usize); - -impl From for usize { - fn from(index: SupervisorFuncIndex) -> Self { - index.0 - } -} - -/// Index of a function within guest index space. -/// -/// This index is supposed to be used as index for `Externals`. -#[derive(Copy, Clone, Debug, PartialEq)] -struct GuestFuncIndex(usize); - -/// This struct holds a mapping from guest index space to supervisor. -struct GuestToSupervisorFunctionMapping { - /// Position of elements in this vector are interpreted - /// as indices of guest functions and are mapped to - /// corresponding supervisor function indices. - funcs: Vec, -} - -impl GuestToSupervisorFunctionMapping { - /// Create an empty function mapping - fn new() -> GuestToSupervisorFunctionMapping { - GuestToSupervisorFunctionMapping { funcs: Vec::new() } - } - - /// Add a new supervisor function to the mapping. - /// Returns a newly assigned guest function index. - fn define(&mut self, supervisor_func: SupervisorFuncIndex) -> GuestFuncIndex { - let idx = self.funcs.len(); - self.funcs.push(supervisor_func); - GuestFuncIndex(idx) - } - - /// Find supervisor function index by its corresponding guest function index - fn func_by_guest_index(&self, guest_func_idx: GuestFuncIndex) -> Option { - self.funcs.get(guest_func_idx.0).cloned() - } -} - -/// Holds sandbox function and memory imports and performs name resolution -struct Imports { - /// Maps qualified function name to its guest function index - func_map: HashMap<(Vec, Vec), GuestFuncIndex>, - - /// Maps qualified field name to its memory reference - memories_map: HashMap<(Vec, Vec), Memory>, -} - -impl Imports { - fn func_by_name(&self, module_name: &str, func_name: &str) -> Option { - self.func_map - .get(&(module_name.as_bytes().to_owned(), func_name.as_bytes().to_owned())) - .cloned() - } - - fn memory_by_name(&self, module_name: &str, memory_name: &str) -> Option { - self.memories_map - .get(&(module_name.as_bytes().to_owned(), memory_name.as_bytes().to_owned())) - .cloned() - } -} - -/// The sandbox context used to execute sandboxed functions. -pub trait SandboxContext { - /// Invoke a function in the supervisor environment. - /// - /// This first invokes the dispatch thunk function, passing in the function index of the - /// desired function to call and serialized arguments. The thunk calls the desired function - /// with the deserialized arguments, then serializes the result into memory and returns - /// reference. The pointer to and length of the result in linear memory is encoded into an - /// `i64`, with the upper 32 bits representing the pointer and the lower 32 bits representing - /// the length. - /// - /// # Errors - /// - /// Returns `Err` if the dispatch_thunk function has an incorrect signature or traps during - /// execution. - fn invoke( - &mut self, - invoke_args_ptr: Pointer, - invoke_args_len: WordSize, - state: u32, - func_idx: SupervisorFuncIndex, - ) -> Result; - - /// Returns the supervisor context. - fn supervisor_context(&mut self) -> &mut dyn FunctionContext; -} - -/// Implementation of [`Externals`] that allows execution of guest module with -/// [externals][`Externals`] that might refer functions defined by supervisor. -/// -/// [`Externals`]: ../wasmi/trait.Externals.html -pub struct GuestExternals<'a> { - /// Instance of sandboxed module to be dispatched - sandbox_instance: &'a SandboxInstance, - - /// External state passed to guest environment, see the `instantiate` function - state: u32, -} - -/// Module instance in terms of selected backend -enum BackendInstance { - /// Wasmi module instance - Wasmi(wasmi::ModuleRef), - - /// Wasmer module instance - #[cfg(feature = "wasmer-sandbox")] - Wasmer(wasmer::Instance), -} - -/// Sandboxed instance of a wasm module. -/// -/// It's primary purpose is to [`invoke`] exported functions on it. -/// -/// All imports of this instance are specified at the creation time and -/// imports are implemented by the supervisor. -/// -/// Hence, in order to invoke an exported function on a sandboxed module instance, -/// it's required to provide supervisor externals: it will be used to execute -/// code in the supervisor context. -/// -/// This is generic over a supervisor function reference type. -/// -/// [`invoke`]: #method.invoke -pub struct SandboxInstance { - backend_instance: BackendInstance, - guest_to_supervisor_mapping: GuestToSupervisorFunctionMapping, -} - -impl SandboxInstance { - /// Invoke an exported function by a name. - /// - /// `supervisor_externals` is required to execute the implementations - /// of the syscalls that published to a sandboxed module instance. - /// - /// The `state` parameter can be used to provide custom data for - /// these syscall implementations. - pub fn invoke( - &self, - export_name: &str, - args: &[sp_wasm_interface::Value], - state: u32, - sandbox_context: &mut dyn SandboxContext, - ) -> std::result::Result, error::Error> { - match &self.backend_instance { - BackendInstance::Wasmi(wasmi_instance) => - wasmi_invoke(self, wasmi_instance, export_name, args, state, sandbox_context), - - #[cfg(feature = "wasmer-sandbox")] - BackendInstance::Wasmer(wasmer_instance) => - wasmer_invoke(wasmer_instance, export_name, args, state, sandbox_context), - } - } - - /// Get the value from a global with the given `name`. - /// - /// Returns `Some(_)` if the global could be found. - pub fn get_global_val(&self, name: &str) -> Option { - match &self.backend_instance { - BackendInstance::Wasmi(wasmi_instance) => wasmi_get_global(wasmi_instance, name), - - #[cfg(feature = "wasmer-sandbox")] - BackendInstance::Wasmer(wasmer_instance) => wasmer_get_global(wasmer_instance, name), - } - } -} - -/// Error occurred during instantiation of a sandboxed module. -pub enum InstantiationError { - /// Something wrong with the environment definition. It either can't - /// be decoded, have a reference to a non-existent or torn down memory instance. - EnvironmentDefinitionCorrupted, - /// Provided module isn't recognized as a valid webassembly binary. - ModuleDecoding, - /// Module is a well-formed webassembly binary but could not be instantiated. This could - /// happen because, e.g. the module imports entries not provided by the environment. - Instantiation, - /// Module is well-formed, instantiated and linked, but while executing the start function - /// a trap was generated. - StartTrapped, - /// The code was compiled with a CPU feature not available on the host. - CpuFeature, -} - -fn decode_environment_definition( - mut raw_env_def: &[u8], - memories: &[Option], -) -> std::result::Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> { - let env_def = sandbox_env::EnvironmentDefinition::decode(&mut raw_env_def) - .map_err(|_| InstantiationError::EnvironmentDefinitionCorrupted)?; - - let mut func_map = HashMap::new(); - let mut memories_map = HashMap::new(); - let mut guest_to_supervisor_mapping = GuestToSupervisorFunctionMapping::new(); - - for entry in &env_def.entries { - let module = entry.module_name.clone(); - let field = entry.field_name.clone(); - - match entry.entity { - sandbox_env::ExternEntity::Function(func_idx) => { - let externals_idx = - guest_to_supervisor_mapping.define(SupervisorFuncIndex(func_idx as usize)); - func_map.insert((module, field), externals_idx); - }, - sandbox_env::ExternEntity::Memory(memory_idx) => { - let memory_ref = memories - .get(memory_idx as usize) - .cloned() - .ok_or(InstantiationError::EnvironmentDefinitionCorrupted)? - .ok_or(InstantiationError::EnvironmentDefinitionCorrupted)?; - memories_map.insert((module, field), memory_ref); - }, - } - } - - Ok((Imports { func_map, memories_map }, guest_to_supervisor_mapping)) -} - -/// An environment in which the guest module is instantiated. -pub struct GuestEnvironment { - /// Function and memory imports of the guest module - imports: Imports, - - /// Supervisor functinons mapped to guest index space - guest_to_supervisor_mapping: GuestToSupervisorFunctionMapping, -} - -impl GuestEnvironment { - /// Decodes an environment definition from the given raw bytes. - /// - /// Returns `Err` if the definition cannot be decoded. - pub fn decode
( - store: &Store
, - raw_env_def: &[u8], - ) -> std::result::Result { - let (imports, guest_to_supervisor_mapping) = - decode_environment_definition(raw_env_def, &store.memories)?; - Ok(Self { imports, guest_to_supervisor_mapping }) - } -} - -/// An unregistered sandboxed instance. -/// -/// To finish off the instantiation the user must call `register`. -#[must_use] -pub struct UnregisteredInstance { - sandbox_instance: Rc, -} - -impl UnregisteredInstance { - /// Finalizes instantiation of this module. - pub fn register
(self, store: &mut Store
, dispatch_thunk: DT) -> u32 { - // At last, register the instance. - store.register_sandbox_instance(self.sandbox_instance, dispatch_thunk) - } -} - -/// Sandbox backend to use -pub enum SandboxBackend { - /// Wasm interpreter - Wasmi, - - /// Wasmer environment - #[cfg(feature = "wasmer-sandbox")] - Wasmer, - - /// Use wasmer backend if available. Fall back to wasmi otherwise. - TryWasmer, -} - -/// Memory reference in terms of a selected backend -#[derive(Clone, Debug)] -pub enum Memory { - /// Wasmi memory reference - Wasmi(WasmiMemoryWrapper), - - /// Wasmer memory refernce - #[cfg(feature = "wasmer-sandbox")] - Wasmer(WasmerMemoryWrapper), -} - -impl Memory { - /// View as wasmi memory - pub fn as_wasmi(&self) -> Option { - match self { - Memory::Wasmi(memory) => Some(memory.clone()), - - #[cfg(feature = "wasmer-sandbox")] - Memory::Wasmer(_) => None, - } - } - - /// View as wasmer memory - #[cfg(feature = "wasmer-sandbox")] - pub fn as_wasmer(&self) -> Option { - match self { - Memory::Wasmer(memory) => Some(memory.clone()), - Memory::Wasmi(_) => None, - } - } -} - -impl util::MemoryTransfer for Memory { - fn read(&self, source_addr: Pointer, size: usize) -> Result> { - match self { - Memory::Wasmi(sandboxed_memory) => sandboxed_memory.read(source_addr, size), - - #[cfg(feature = "wasmer-sandbox")] - Memory::Wasmer(sandboxed_memory) => sandboxed_memory.read(source_addr, size), - } - } - - fn read_into(&self, source_addr: Pointer, destination: &mut [u8]) -> Result<()> { - match self { - Memory::Wasmi(sandboxed_memory) => sandboxed_memory.read_into(source_addr, destination), - - #[cfg(feature = "wasmer-sandbox")] - Memory::Wasmer(sandboxed_memory) => sandboxed_memory.read_into(source_addr, destination), - } - } - - fn write_from(&self, dest_addr: Pointer, source: &[u8]) -> Result<()> { - match self { - Memory::Wasmi(sandboxed_memory) => sandboxed_memory.write_from(dest_addr, source), - - #[cfg(feature = "wasmer-sandbox")] - Memory::Wasmer(sandboxed_memory) => sandboxed_memory.write_from(dest_addr, source), - } - } -} - -/// Information specific to a particular execution backend -enum BackendContext { - /// Wasmi specific context - Wasmi, - - /// Wasmer specific context - #[cfg(feature = "wasmer-sandbox")] - Wasmer(WasmerBackend), -} - -impl BackendContext { - pub fn new(backend: SandboxBackend) -> BackendContext { - match backend { - SandboxBackend::Wasmi => BackendContext::Wasmi, - - #[cfg(not(feature = "wasmer-sandbox"))] - SandboxBackend::TryWasmer => BackendContext::Wasmi, - - #[cfg(feature = "wasmer-sandbox")] - SandboxBackend::Wasmer | SandboxBackend::TryWasmer => - BackendContext::Wasmer(WasmerBackend::new()), - } - } -} - -/// This struct keeps track of all sandboxed components. -/// -/// This is generic over a supervisor function reference type. -pub struct Store
{ - /// Stores the instance and the dispatch thunk associated to per instance. - /// - /// Instances are `Some` until torn down. - instances: Vec, DT)>>, - /// Memories are `Some` until torn down. - memories: Vec>, - backend_context: BackendContext, -} - -impl Store
{ - /// Create a new empty sandbox store. - pub fn new(backend: SandboxBackend) -> Self { - Store { - instances: Vec::new(), - memories: Vec::new(), - backend_context: BackendContext::new(backend), - } - } - - /// Create a new memory instance and return it's index. - /// - /// # Errors - /// - /// Returns `Err` if the memory couldn't be created. - /// Typically happens if `initial` is more than `maximum`. - pub fn new_memory(&mut self, initial: u32, maximum: u32) -> Result { - let memories = &mut self.memories; - let backend_context = &self.backend_context; - - let maximum = match maximum { - sandbox_env::MEM_UNLIMITED => None, - specified_limit => Some(specified_limit), - }; - - let memory = match &backend_context { - BackendContext::Wasmi => wasmi_new_memory(initial, maximum)?, - - #[cfg(feature = "wasmer-sandbox")] - BackendContext::Wasmer(context) => wasmer_new_memory(context, initial, maximum)?, - }; - - let mem_idx = memories.len(); - memories.push(Some(memory)); - - Ok(mem_idx as u32) - } - - /// Returns `SandboxInstance` by `instance_idx`. - /// - /// # Errors - /// - /// Returns `Err` If `instance_idx` isn't a valid index of an instance or - /// instance is already torndown. - pub fn instance(&self, instance_idx: u32) -> Result> { - self.instances - .get(instance_idx as usize) - .ok_or("Trying to access a non-existent instance")? - .as_ref() - .map(|v| v.0.clone()) - .ok_or_else(|| "Trying to access a torndown instance".into()) - } - - /// Returns dispatch thunk by `instance_idx`. - /// - /// # Errors - /// - /// Returns `Err` If `instance_idx` isn't a valid index of an instance or - /// instance is already torndown. - pub fn dispatch_thunk(&self, instance_idx: u32) -> Result
{ - self.instances - .get(instance_idx as usize) - .as_ref() - .ok_or("Trying to access a non-existent instance")? - .as_ref() - .map(|v| v.1.clone()) - .ok_or_else(|| "Trying to access a torndown instance".into()) - } - - /// Returns reference to a memory instance by `memory_idx`. - /// - /// # Errors - /// - /// Returns `Err` If `memory_idx` isn't a valid index of an memory or - /// if memory has been torn down. - pub fn memory(&self, memory_idx: u32) -> Result { - self.memories - .get(memory_idx as usize) - .cloned() - .ok_or("Trying to access a non-existent sandboxed memory")? - .ok_or_else(|| "Trying to access a torndown sandboxed memory".into()) - } - - /// Tear down the memory at the specified index. - /// - /// # Errors - /// - /// Returns `Err` if `memory_idx` isn't a valid index of an memory or - /// if it has been torn down. - pub fn memory_teardown(&mut self, memory_idx: u32) -> Result<()> { - match self.memories.get_mut(memory_idx as usize) { - None => Err("Trying to teardown a non-existent sandboxed memory".into()), - Some(None) => Err("Double teardown of a sandboxed memory".into()), - Some(memory) => { - *memory = None; - Ok(()) - }, - } - } - - /// Tear down the instance at the specified index. - /// - /// # Errors - /// - /// Returns `Err` if `instance_idx` isn't a valid index of an instance or - /// if it has been torn down. - pub fn instance_teardown(&mut self, instance_idx: u32) -> Result<()> { - match self.instances.get_mut(instance_idx as usize) { - None => Err("Trying to teardown a non-existent instance".into()), - Some(None) => Err("Double teardown of an instance".into()), - Some(instance) => { - *instance = None; - Ok(()) - }, - } - } - - /// Instantiate a guest module and return it's index in the store. - /// - /// The guest module's code is specified in `wasm`. Environment that will be available to - /// guest module is specified in `guest_env`. A dispatch thunk is used as function that - /// handle calls from guests. `state` is an opaque pointer to caller's arbitrary context - /// normally created by `sp_sandbox::Instance` primitive. - /// - /// Note: Due to borrowing constraints dispatch thunk is now propagated using DTH - /// - /// Returns uninitialized sandboxed module instance or an instantiation error. - pub fn instantiate( - &mut self, - wasm: &[u8], - guest_env: GuestEnvironment, - state: u32, - sandbox_context: &mut dyn SandboxContext, - ) -> std::result::Result { - let sandbox_instance = match self.backend_context { - BackendContext::Wasmi => wasmi_instantiate(wasm, guest_env, state, sandbox_context)?, - - #[cfg(feature = "wasmer-sandbox")] - BackendContext::Wasmer(ref context) => - wasmer_instantiate(context, wasm, guest_env, state, sandbox_context)?, - }; - - Ok(UnregisteredInstance { sandbox_instance }) - } -} - -// Private routines -impl
Store
{ - fn register_sandbox_instance( - &mut self, - sandbox_instance: Rc, - dispatch_thunk: DT, - ) -> u32 { - let instance_idx = self.instances.len(); - self.instances.push(Some((sandbox_instance, dispatch_thunk))); - instance_idx as u32 - } -} diff --git a/client/executor/common/src/sandbox/wasmer_backend.rs b/client/executor/common/src/sandbox/wasmer_backend.rs deleted file mode 100644 index 29926141ed8b8..0000000000000 --- a/client/executor/common/src/sandbox/wasmer_backend.rs +++ /dev/null @@ -1,449 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Wasmer specific impls for sandbox - -use std::{cell::RefCell, collections::HashMap, rc::Rc}; - -use wasmer::RuntimeError; - -use codec::{Decode, Encode}; -use sp_sandbox::HostError; -use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; - -use crate::{ - error::{Error, Result}, - sandbox::{ - BackendInstance, GuestEnvironment, InstantiationError, Memory, SandboxContext, - SandboxInstance, SupervisorFuncIndex, - }, - util::{checked_range, MemoryTransfer}, -}; - -environmental::environmental!(SandboxContextStore: trait SandboxContext); - -/// Wasmer specific context -pub struct Backend { - store: wasmer::Store, -} - -impl Backend { - pub fn new() -> Self { - let compiler = wasmer::Singlepass::default(); - Backend { store: wasmer::Store::new(&wasmer::Universal::new(compiler).engine()) } - } -} - -/// Invoke a function within a sandboxed module -pub fn invoke( - instance: &wasmer::Instance, - export_name: &str, - args: &[Value], - _state: u32, - sandbox_context: &mut dyn SandboxContext, -) -> std::result::Result, Error> { - let function = instance - .exports - .get_function(export_name) - .map_err(|error| Error::Sandbox(error.to_string()))?; - - let args: Vec = args - .iter() - .map(|v| match *v { - Value::I32(val) => wasmer::Val::I32(val), - Value::I64(val) => wasmer::Val::I64(val), - Value::F32(val) => wasmer::Val::F32(f32::from_bits(val)), - Value::F64(val) => wasmer::Val::F64(f64::from_bits(val)), - }) - .collect(); - - let wasmer_result = SandboxContextStore::using(sandbox_context, || { - function.call(&args).map_err(|error| Error::Sandbox(error.to_string())) - })?; - - match wasmer_result.as_ref() { - [] => Ok(None), - - [wasm_value] => { - let wasmer_value = match *wasm_value { - wasmer::Val::I32(val) => Value::I32(val), - wasmer::Val::I64(val) => Value::I64(val), - wasmer::Val::F32(val) => Value::F32(f32::to_bits(val)), - wasmer::Val::F64(val) => Value::F64(f64::to_bits(val)), - _ => - return Err(Error::Sandbox(format!( - "Unsupported return value: {:?}", - wasm_value, - ))), - }; - - Ok(Some(wasmer_value)) - }, - - _ => Err(Error::Sandbox("multiple return types are not supported yet".into())), - } -} - -/// Instantiate a module within a sandbox context -pub fn instantiate( - context: &Backend, - wasm: &[u8], - guest_env: GuestEnvironment, - state: u32, - sandbox_context: &mut dyn SandboxContext, -) -> std::result::Result, InstantiationError> { - let module = wasmer::Module::new(&context.store, wasm) - .map_err(|_| InstantiationError::ModuleDecoding)?; - - type Exports = HashMap; - let mut exports_map = Exports::new(); - - for import in module.imports() { - match import.ty() { - // Nothing to do here - wasmer::ExternType::Global(_) | wasmer::ExternType::Table(_) => (), - - wasmer::ExternType::Memory(_) => { - let exports = exports_map - .entry(import.module().to_string()) - .or_insert_with(wasmer::Exports::new); - - let memory = guest_env - .imports - .memory_by_name(import.module(), import.name()) - .ok_or(InstantiationError::ModuleDecoding)?; - - let wasmer_memory_ref = memory.as_wasmer().expect( - "memory is created by wasmer; \ - exported by the same module and backend; \ - thus the operation can't fail; \ - qed", - ); - - // This is safe since we're only instantiating the module and populating - // the export table, so no memory access can happen at this time. - // All subsequent memory accesses should happen through the wrapper, - // that enforces the memory access protocol. - // - // We take exclusive lock to ensure that we're the only one here, - // since during instantiation phase the memory should only be created - // and not yet accessed. - let wasmer_memory = wasmer_memory_ref - .buffer - .try_borrow_mut() - .map_err(|_| InstantiationError::EnvironmentDefinitionCorrupted)? - .clone(); - - exports.insert(import.name(), wasmer::Extern::Memory(wasmer_memory)); - }, - - wasmer::ExternType::Function(func_ty) => { - let guest_func_index = - guest_env.imports.func_by_name(import.module(), import.name()); - - let guest_func_index = if let Some(index) = guest_func_index { - index - } else { - // Missing import (should we abort here?) - continue - }; - - let supervisor_func_index = guest_env - .guest_to_supervisor_mapping - .func_by_guest_index(guest_func_index) - .ok_or(InstantiationError::ModuleDecoding)?; - - let function = - dispatch_function(supervisor_func_index, &context.store, func_ty, state); - - let exports = exports_map - .entry(import.module().to_string()) - .or_insert_with(wasmer::Exports::new); - - exports.insert(import.name(), wasmer::Extern::Function(function)); - }, - } - } - - let mut import_object = wasmer::ImportObject::new(); - for (module_name, exports) in exports_map.into_iter() { - import_object.register(module_name, exports); - } - - let instance = SandboxContextStore::using(sandbox_context, || { - wasmer::Instance::new(&module, &import_object).map_err(|error| match error { - wasmer::InstantiationError::Link(_) => InstantiationError::Instantiation, - wasmer::InstantiationError::Start(_) => InstantiationError::StartTrapped, - wasmer::InstantiationError::HostEnvInitialization(_) => - InstantiationError::EnvironmentDefinitionCorrupted, - wasmer::InstantiationError::CpuFeature(_) => InstantiationError::CpuFeature, - }) - })?; - - Ok(Rc::new(SandboxInstance { - backend_instance: BackendInstance::Wasmer(instance), - guest_to_supervisor_mapping: guest_env.guest_to_supervisor_mapping, - })) -} - -fn dispatch_function( - supervisor_func_index: SupervisorFuncIndex, - store: &wasmer::Store, - func_ty: &wasmer::FunctionType, - state: u32, -) -> wasmer::Function { - wasmer::Function::new(store, func_ty, move |params| { - SandboxContextStore::with(|sandbox_context| { - // Serialize arguments into a byte vector. - let invoke_args_data = params - .iter() - .map(|val| match val { - wasmer::Val::I32(val) => Ok(Value::I32(*val)), - wasmer::Val::I64(val) => Ok(Value::I64(*val)), - wasmer::Val::F32(val) => Ok(Value::F32(f32::to_bits(*val))), - wasmer::Val::F64(val) => Ok(Value::F64(f64::to_bits(*val))), - _ => - Err(RuntimeError::new(format!("Unsupported function argument: {:?}", val))), - }) - .collect::, _>>()? - .encode(); - - // Move serialized arguments inside the memory, invoke dispatch thunk and - // then free allocated memory. - let invoke_args_len = invoke_args_data.len() as WordSize; - let invoke_args_ptr = - sandbox_context.supervisor_context().allocate_memory(invoke_args_len).map_err( - |_| RuntimeError::new("Can't allocate memory in supervisor for the arguments"), - )?; - - let deallocate = |fe: &mut dyn FunctionContext, ptr, fail_msg| { - fe.deallocate_memory(ptr).map_err(|_| RuntimeError::new(fail_msg)) - }; - - if sandbox_context - .supervisor_context() - .write_memory(invoke_args_ptr, &invoke_args_data) - .is_err() - { - deallocate( - sandbox_context.supervisor_context(), - invoke_args_ptr, - "Failed dealloction after failed write of invoke arguments", - )?; - - return Err(RuntimeError::new("Can't write invoke args into memory")) - } - - // Perform the actuall call - let serialized_result = sandbox_context - .invoke(invoke_args_ptr, invoke_args_len, state, supervisor_func_index) - .map_err(|e| RuntimeError::new(e.to_string())); - - deallocate( - sandbox_context.supervisor_context(), - invoke_args_ptr, - "Failed dealloction after invoke", - )?; - - let serialized_result = serialized_result?; - - // dispatch_thunk returns pointer to serialized arguments. - // Unpack pointer and len of the serialized result data. - let (serialized_result_val_ptr, serialized_result_val_len) = { - // Cast to u64 to use zero-extension. - let v = serialized_result as u64; - let ptr = (v as u64 >> 32) as u32; - let len = (v & 0xFFFFFFFF) as u32; - (Pointer::new(ptr), len) - }; - - let serialized_result_val = sandbox_context - .supervisor_context() - .read_memory(serialized_result_val_ptr, serialized_result_val_len) - .map_err(|_| { - RuntimeError::new("Can't read the serialized result from dispatch thunk") - }); - - deallocate( - sandbox_context.supervisor_context(), - serialized_result_val_ptr, - "Can't deallocate memory for dispatch thunk's result", - )?; - - let serialized_result_val = serialized_result_val?; - - let deserialized_result = std::result::Result::::decode( - &mut serialized_result_val.as_slice(), - ) - .map_err(|_| RuntimeError::new("Decoding Result failed!"))? - .map_err(|_| RuntimeError::new("Supervisor function returned sandbox::HostError"))?; - - let result = match deserialized_result { - ReturnValue::Value(Value::I32(val)) => vec![wasmer::Val::I32(val)], - ReturnValue::Value(Value::I64(val)) => vec![wasmer::Val::I64(val)], - ReturnValue::Value(Value::F32(val)) => vec![wasmer::Val::F32(f32::from_bits(val))], - ReturnValue::Value(Value::F64(val)) => vec![wasmer::Val::F64(f64::from_bits(val))], - - ReturnValue::Unit => vec![], - }; - - Ok(result) - }) - .expect("SandboxContextStore is set when invoking sandboxed functions; qed") - }) -} - -/// Allocate new memory region -pub fn new_memory( - context: &Backend, - initial: u32, - maximum: Option, -) -> crate::error::Result { - let ty = wasmer::MemoryType::new(initial, maximum, false); - let memory = Memory::Wasmer(MemoryWrapper::new( - wasmer::Memory::new(&context.store, ty).map_err(|_| Error::InvalidMemoryReference)?, - )); - - Ok(memory) -} - -/// In order to enforce memory access protocol to the backend memory -/// we wrap it with `RefCell` and encapsulate all memory operations. -#[derive(Debug, Clone)] -pub struct MemoryWrapper { - buffer: Rc>, -} - -impl MemoryWrapper { - /// Take ownership of the memory region and return a wrapper object - pub fn new(memory: wasmer::Memory) -> Self { - Self { buffer: Rc::new(RefCell::new(memory)) } - } - - /// Returns linear memory of the wasm instance as a slice. - /// - /// # Safety - /// - /// Wasmer doesn't provide comprehensive documentation about the exact behavior of the data - /// pointer. If a dynamic style heap is used the base pointer of the heap can change. Since - /// growing, we cannot guarantee the lifetime of the returned slice reference. - unsafe fn memory_as_slice(memory: &wasmer::Memory) -> &[u8] { - let ptr = memory.data_ptr() as *const _; - - let len: usize = memory.data_size().try_into().expect( - "maximum memory object size never exceeds pointer size on any architecture; \ - usize by design and definition is enough to store any memory object size \ - possible on current achitecture; thus the conversion can not fail; qed", - ); - - if len == 0 { - &[] - } else { - core::slice::from_raw_parts(ptr, len) - } - } - - /// Returns linear memory of the wasm instance as a slice. - /// - /// # Safety - /// - /// See `[memory_as_slice]`. In addition to those requirements, since a mutable reference is - /// returned it must be ensured that only one mutable and no shared references to memory - /// exists at the same time. - unsafe fn memory_as_slice_mut(memory: &mut wasmer::Memory) -> &mut [u8] { - let ptr = memory.data_ptr(); - - let len: usize = memory.data_size().try_into().expect( - "maximum memory object size never exceeds pointer size on any architecture; \ - usize by design and definition is enough to store any memory object size \ - possible on current achitecture; thus the conversion can not fail; qed", - ); - - if len == 0 { - &mut [] - } else { - core::slice::from_raw_parts_mut(ptr, len) - } - } -} - -impl MemoryTransfer for MemoryWrapper { - fn read(&self, source_addr: Pointer, size: usize) -> Result> { - let memory = self.buffer.borrow(); - - let data_size: usize = memory.data_size().try_into().expect( - "maximum memory object size never exceeds pointer size on any architecture; \ - usize by design and definition is enough to store any memory object size \ - possible on current achitecture; thus the conversion can not fail; qed", - ); - - let range = checked_range(source_addr.into(), size, data_size) - .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; - - let mut buffer = vec![0; range.len()]; - self.read_into(source_addr, &mut buffer)?; - - Ok(buffer) - } - - fn read_into(&self, source_addr: Pointer, destination: &mut [u8]) -> Result<()> { - unsafe { - let memory = self.buffer.borrow(); - - // This should be safe since we don't grow up memory while caching this reference - // and we give up the reference before returning from this function. - let source = Self::memory_as_slice(&memory); - - let range = checked_range(source_addr.into(), destination.len(), source.len()) - .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; - - destination.copy_from_slice(&source[range]); - Ok(()) - } - } - - fn write_from(&self, dest_addr: Pointer, source: &[u8]) -> Result<()> { - unsafe { - let memory = &mut self.buffer.borrow_mut(); - - // This should be safe since we don't grow up memory while caching this reference - // and we give up the reference before returning from this function. - let destination = Self::memory_as_slice_mut(memory); - - let range = checked_range(dest_addr.into(), source.len(), destination.len()) - .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; - - destination[range].copy_from_slice(source); - Ok(()) - } - } -} - -/// Get global value by name -pub fn get_global(instance: &wasmer::Instance, name: &str) -> Option { - let global = instance.exports.get_global(name).ok()?; - let wasmtime_value = match global.get() { - wasmer::Val::I32(val) => Value::I32(val), - wasmer::Val::I64(val) => Value::I64(val), - wasmer::Val::F32(val) => Value::F32(f32::to_bits(val)), - wasmer::Val::F64(val) => Value::F64(f64::to_bits(val)), - _ => None?, - }; - - Some(wasmtime_value) -} diff --git a/client/executor/common/src/sandbox/wasmi_backend.rs b/client/executor/common/src/sandbox/wasmi_backend.rs deleted file mode 100644 index 2ba133f5f15b1..0000000000000 --- a/client/executor/common/src/sandbox/wasmi_backend.rs +++ /dev/null @@ -1,339 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Wasmi specific impls for sandbox - -use std::{fmt, rc::Rc}; - -use codec::{Decode, Encode}; -use sp_sandbox::HostError; -use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; -use wasmi::{ - memory_units::Pages, ImportResolver, MemoryInstance, Module, ModuleInstance, RuntimeArgs, - RuntimeValue, Trap, -}; - -use crate::{ - error::{self, Error}, - sandbox::{ - BackendInstance, GuestEnvironment, GuestExternals, GuestFuncIndex, Imports, - InstantiationError, Memory, SandboxContext, SandboxInstance, - }, - util::{checked_range, MemoryTransfer}, -}; - -environmental::environmental!(SandboxContextStore: trait SandboxContext); - -#[derive(Debug)] -struct CustomHostError(String); - -impl fmt::Display for CustomHostError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "HostError: {}", self.0) - } -} - -impl wasmi::HostError for CustomHostError {} - -/// Construct trap error from specified message -fn trap(msg: &'static str) -> Trap { - Trap::host(CustomHostError(msg.into())) -} - -impl ImportResolver for Imports { - fn resolve_func( - &self, - module_name: &str, - field_name: &str, - signature: &wasmi::Signature, - ) -> std::result::Result { - let idx = self.func_by_name(module_name, field_name).ok_or_else(|| { - wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name)) - })?; - - Ok(wasmi::FuncInstance::alloc_host(signature.clone(), idx.0)) - } - - fn resolve_memory( - &self, - module_name: &str, - field_name: &str, - _memory_type: &wasmi::MemoryDescriptor, - ) -> std::result::Result { - let mem = self.memory_by_name(module_name, field_name).ok_or_else(|| { - wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name)) - })?; - - let wrapper = mem.as_wasmi().ok_or_else(|| { - wasmi::Error::Instantiation(format!( - "Unsupported non-wasmi export {}:{}", - module_name, field_name - )) - })?; - - // Here we use inner memory reference only to resolve the imports - // without accessing the memory contents. All subsequent memory accesses - // should happen through the wrapper, that enforces the memory access protocol. - let mem = wrapper.0; - - Ok(mem) - } - - fn resolve_global( - &self, - module_name: &str, - field_name: &str, - _global_type: &wasmi::GlobalDescriptor, - ) -> std::result::Result { - Err(wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name))) - } - - fn resolve_table( - &self, - module_name: &str, - field_name: &str, - _table_type: &wasmi::TableDescriptor, - ) -> std::result::Result { - Err(wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name))) - } -} - -/// Allocate new memory region -pub fn new_memory(initial: u32, maximum: Option) -> crate::error::Result { - let memory = Memory::Wasmi(MemoryWrapper::new( - MemoryInstance::alloc(Pages(initial as usize), maximum.map(|m| Pages(m as usize))) - .map_err(|error| Error::Sandbox(error.to_string()))?, - )); - - Ok(memory) -} - -/// Wasmi provides direct access to its memory using slices. -/// -/// This wrapper limits the scope where the slice can be taken to -#[derive(Debug, Clone)] -pub struct MemoryWrapper(wasmi::MemoryRef); - -impl MemoryWrapper { - /// Take ownership of the memory region and return a wrapper object - fn new(memory: wasmi::MemoryRef) -> Self { - Self(memory) - } -} - -impl MemoryTransfer for MemoryWrapper { - fn read(&self, source_addr: Pointer, size: usize) -> error::Result> { - self.0.with_direct_access(|source| { - let range = checked_range(source_addr.into(), size, source.len()) - .ok_or_else(|| error::Error::Other("memory read is out of bounds".into()))?; - - Ok(Vec::from(&source[range])) - }) - } - - fn read_into(&self, source_addr: Pointer, destination: &mut [u8]) -> error::Result<()> { - self.0.with_direct_access(|source| { - let range = checked_range(source_addr.into(), destination.len(), source.len()) - .ok_or_else(|| error::Error::Other("memory read is out of bounds".into()))?; - - destination.copy_from_slice(&source[range]); - Ok(()) - }) - } - - fn write_from(&self, dest_addr: Pointer, source: &[u8]) -> error::Result<()> { - self.0.with_direct_access_mut(|destination| { - let range = checked_range(dest_addr.into(), source.len(), destination.len()) - .ok_or_else(|| error::Error::Other("memory write is out of bounds".into()))?; - - destination[range].copy_from_slice(source); - Ok(()) - }) - } -} - -impl<'a> wasmi::Externals for GuestExternals<'a> { - fn invoke_index( - &mut self, - index: usize, - args: RuntimeArgs, - ) -> std::result::Result, Trap> { - SandboxContextStore::with(|sandbox_context| { - // Make `index` typesafe again. - let index = GuestFuncIndex(index); - - // Convert function index from guest to supervisor space - let func_idx = self.sandbox_instance - .guest_to_supervisor_mapping - .func_by_guest_index(index) - .expect( - "`invoke_index` is called with indexes registered via `FuncInstance::alloc_host`; - `FuncInstance::alloc_host` is called with indexes that were obtained from `guest_to_supervisor_mapping`; - `func_by_guest_index` called with `index` can't return `None`; - qed" - ); - - // Serialize arguments into a byte vector. - let invoke_args_data: Vec = args - .as_ref() - .iter() - .cloned() - .map(sp_wasm_interface::Value::from) - .collect::>() - .encode(); - - let state = self.state; - - // Move serialized arguments inside the memory, invoke dispatch thunk and - // then free allocated memory. - let invoke_args_len = invoke_args_data.len() as WordSize; - let invoke_args_ptr = sandbox_context - .supervisor_context() - .allocate_memory(invoke_args_len) - .map_err(|_| trap("Can't allocate memory in supervisor for the arguments"))?; - - let deallocate = |supervisor_context: &mut dyn FunctionContext, ptr, fail_msg| { - supervisor_context.deallocate_memory(ptr).map_err(|_| trap(fail_msg)) - }; - - if sandbox_context - .supervisor_context() - .write_memory(invoke_args_ptr, &invoke_args_data) - .is_err() - { - deallocate( - sandbox_context.supervisor_context(), - invoke_args_ptr, - "Failed dealloction after failed write of invoke arguments", - )?; - return Err(trap("Can't write invoke args into memory")) - } - - let result = sandbox_context.invoke( - invoke_args_ptr, - invoke_args_len, - state, - func_idx, - ); - - deallocate( - sandbox_context.supervisor_context(), - invoke_args_ptr, - "Can't deallocate memory for dispatch thunk's invoke arguments", - )?; - let result = result?; - - // dispatch_thunk returns pointer to serialized arguments. - // Unpack pointer and len of the serialized result data. - let (serialized_result_val_ptr, serialized_result_val_len) = { - // Cast to u64 to use zero-extension. - let v = result as u64; - let ptr = (v as u64 >> 32) as u32; - let len = (v & 0xFFFFFFFF) as u32; - (Pointer::new(ptr), len) - }; - - let serialized_result_val = sandbox_context - .supervisor_context() - .read_memory(serialized_result_val_ptr, serialized_result_val_len) - .map_err(|_| trap("Can't read the serialized result from dispatch thunk")); - - deallocate( - sandbox_context.supervisor_context(), - serialized_result_val_ptr, - "Can't deallocate memory for dispatch thunk's result", - ) - .and(serialized_result_val) - .and_then(|serialized_result_val| { - let result_val = std::result::Result::::decode(&mut serialized_result_val.as_slice()) - .map_err(|_| trap("Decoding Result failed!"))?; - - match result_val { - Ok(return_value) => Ok(match return_value { - ReturnValue::Unit => None, - ReturnValue::Value(typed_value) => Some(RuntimeValue::from(typed_value)), - }), - Err(HostError) => Err(trap("Supervisor function returned sandbox::HostError")), - } - }) - }).expect("SandboxContextStore is set when invoking sandboxed functions; qed") - } -} - -fn with_guest_externals(sandbox_instance: &SandboxInstance, state: u32, f: F) -> R -where - F: FnOnce(&mut GuestExternals) -> R, -{ - f(&mut GuestExternals { sandbox_instance, state }) -} - -/// Instantiate a module within a sandbox context -pub fn instantiate( - wasm: &[u8], - guest_env: GuestEnvironment, - state: u32, - sandbox_context: &mut dyn SandboxContext, -) -> std::result::Result, InstantiationError> { - let wasmi_module = Module::from_buffer(wasm).map_err(|_| InstantiationError::ModuleDecoding)?; - let wasmi_instance = ModuleInstance::new(&wasmi_module, &guest_env.imports) - .map_err(|_| InstantiationError::Instantiation)?; - - let sandbox_instance = Rc::new(SandboxInstance { - // In general, it's not a very good idea to use `.not_started_instance()` for - // anything but for extracting memory and tables. But in this particular case, we - // are extracting for the purpose of running `start` function which should be ok. - backend_instance: BackendInstance::Wasmi(wasmi_instance.not_started_instance().clone()), - guest_to_supervisor_mapping: guest_env.guest_to_supervisor_mapping, - }); - - with_guest_externals(&sandbox_instance, state, |guest_externals| { - SandboxContextStore::using(sandbox_context, || { - wasmi_instance - .run_start(guest_externals) - .map_err(|_| InstantiationError::StartTrapped) - }) - })?; - - Ok(sandbox_instance) -} - -/// Invoke a function within a sandboxed module -pub fn invoke( - instance: &SandboxInstance, - module: &wasmi::ModuleRef, - export_name: &str, - args: &[Value], - state: u32, - sandbox_context: &mut dyn SandboxContext, -) -> std::result::Result, error::Error> { - with_guest_externals(instance, state, |guest_externals| { - SandboxContextStore::using(sandbox_context, || { - let args = args.iter().cloned().map(Into::into).collect::>(); - - module - .invoke_export(export_name, &args, guest_externals) - .map(|result| result.map(Into::into)) - .map_err(|error| error::Error::Sandbox(error.to_string())) - }) - }) -} - -/// Get global value by name -pub fn get_global(instance: &wasmi::ModuleRef, name: &str) -> Option { - Some(instance.export_by_name(name)?.as_global()?.get().into()) -} diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index c8b173de16e9f..eadf547823bb2 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -13,11 +13,9 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -paste = "1.0.6" sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, features = ["improved_panic_error_reporting"], path = "../../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } [build-dependencies] @@ -29,6 +27,5 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-sandbox/std", "sp-std/std", ] diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 0424ad418617b..fc98d1909d00d 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -29,8 +29,6 @@ use sp_runtime::{ print, traits::{BlakeTwo256, Hash}, }; -#[cfg(not(feature = "std"))] -use sp_sandbox::{SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory, Value}; extern "C" { #[allow(dead_code)] @@ -339,160 +337,3 @@ sp_core::wasm_export_functions! { return 1234; } } - -/// A macro to define a test entrypoint for each available sandbox executor. -macro_rules! wasm_export_sandbox_test_functions { - ( - $( - fn $name:ident( - $( $arg_name:ident: $arg_ty:ty ),* $(,)? - ) $( -> $ret_ty:ty )? where T: SandboxInstance<$state:ty> $(,)? - { $( $fn_impl:tt )* } - )* - ) => { - $( - #[cfg(not(feature = "std"))] - fn $name( $($arg_name: $arg_ty),* ) $( -> $ret_ty )? where T: SandboxInstance<$state> { - $( $fn_impl )* - } - - paste::paste! { - sp_core::wasm_export_functions! { - fn [<$name _host>]( $($arg_name: $arg_ty),* ) $( -> $ret_ty )? { - $name::>( $( $arg_name ),* ) - } - - fn [<$name _embedded>]( $($arg_name: $arg_ty),* ) $( -> $ret_ty )? { - $name::>( $( $arg_name ),* ) - } - } - } - )* - }; -} - -wasm_export_sandbox_test_functions! { - fn test_sandbox(code: Vec) -> bool - where - T: SandboxInstance, - { - execute_sandboxed::(&code, &[]).is_ok() - } - - fn test_sandbox_args(code: Vec) -> bool - where - T: SandboxInstance, - { - execute_sandboxed::(&code, &[Value::I32(0x12345678), Value::I64(0x1234567887654321)]) - .is_ok() - } - - fn test_sandbox_return_val(code: Vec) -> bool - where - T: SandboxInstance, - { - let ok = match execute_sandboxed::(&code, &[Value::I32(0x1336)]) { - Ok(sp_sandbox::ReturnValue::Value(Value::I32(0x1337))) => true, - _ => false, - }; - - ok - } - - fn test_sandbox_instantiate(code: Vec) -> u8 - where - T: SandboxInstance<()>, - { - let env_builder = T::EnvironmentBuilder::new(); - let code = match T::new(&code, &env_builder, &mut ()) { - Ok(_) => 0, - Err(sp_sandbox::Error::Module) => 1, - Err(sp_sandbox::Error::Execution) => 2, - Err(sp_sandbox::Error::OutOfBounds) => 3, - }; - - code - } - - fn test_sandbox_get_global_val(code: Vec) -> i64 - where - T: SandboxInstance<()>, - { - let env_builder = T::EnvironmentBuilder::new(); - let instance = if let Ok(i) = T::new(&code, &env_builder, &mut ()) { - i - } else { - return 20 - }; - - match instance.get_global_val("test_global") { - Some(sp_sandbox::Value::I64(val)) => val, - None => 30, - _ => 40, - } - } -} - -#[cfg(not(feature = "std"))] -struct State { - counter: u32, -} - -#[cfg(not(feature = "std"))] -fn execute_sandboxed( - code: &[u8], - args: &[Value], -) -> Result -where - T: sp_sandbox::SandboxInstance, -{ - fn env_assert( - _e: &mut State, - args: &[Value], - ) -> Result { - if args.len() != 1 { - return Err(sp_sandbox::HostError) - } - let condition = args[0].as_i32().ok_or_else(|| sp_sandbox::HostError)?; - if condition != 0 { - Ok(sp_sandbox::ReturnValue::Unit) - } else { - Err(sp_sandbox::HostError) - } - } - fn env_inc_counter( - e: &mut State, - args: &[Value], - ) -> Result { - if args.len() != 1 { - return Err(sp_sandbox::HostError) - } - let inc_by = args[0].as_i32().ok_or_else(|| sp_sandbox::HostError)?; - e.counter += inc_by as u32; - Ok(sp_sandbox::ReturnValue::Value(Value::I32(e.counter as i32))) - } - - let mut state = State { counter: 0 }; - - let env_builder = { - let mut env_builder = T::EnvironmentBuilder::new(); - env_builder.add_host_func("env", "assert", env_assert); - env_builder.add_host_func("env", "inc_counter", env_inc_counter); - let memory = match T::Memory::new(1, Some(16)) { - Ok(m) => m, - Err(_) => unreachable!( - " - Memory::new() can return Err only if parameters are borked; \ - We passing params here explicitly and they're correct; \ - Memory::new() can't return a Error qed" - ), - }; - env_builder.add_memory("env", "memory", memory); - env_builder - }; - - let mut instance = T::new(code, &env_builder, &mut state)?; - let result = instance.invoke("call", args, &mut state); - - result.map_err(|_| sp_sandbox::HostError) -} diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 9b5c4b12fca99..25b999f115363 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -18,7 +18,6 @@ #[cfg(target_os = "linux")] mod linux; -mod sandbox; use codec::{Decode, Encode}; use sc_executor_common::{error::Error, runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; @@ -98,111 +97,6 @@ macro_rules! test_wasm_execution { }; } -/// A macro to run a given test for each available WASM execution method *and* for each -/// sandbox execution method. -#[macro_export] -macro_rules! test_wasm_execution_sandbox { - ($method_name:ident) => { - paste::item! { - #[test] - fn [<$method_name _interpreted_host_executor>]() { - $method_name(WasmExecutionMethod::Interpreted, "_host"); - } - - #[test] - fn [<$method_name _interpreted_embedded_executor>]() { - $method_name(WasmExecutionMethod::Interpreted, "_embedded"); - } - - #[test] - fn [<$method_name _compiled_pooling_cow_host_executor>]() { - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite - }, "_host"); - } - - #[test] - fn [<$method_name _compiled_pooling_cow_embedded_executor>]() { - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite - }, "_embedded"); - } - - #[test] - fn [<$method_name _compiled_pooling_vanilla_host_executor>]() { - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::Pooling - }, "_host"); - } - - #[test] - fn [<$method_name _compiled_pooling_vanilla_embedded_executor>]() { - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::Pooling - }, "_embedded"); - } - - #[test] - fn [<$method_name _compiled_recreate_instance_cow_host_executor>]() { - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstanceCopyOnWrite - }, "_host"); - } - - #[test] - fn [<$method_name _compiled_recreate_instance_cow_embedded_executor>]() { - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstanceCopyOnWrite - }, "_embedded"); - } - - #[test] - fn [<$method_name _compiled_recreate_instance_vanilla_host_executor>]() { - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstance - }, "_host"); - } - - #[test] - fn [<$method_name _compiled_recreate_instance_vanilla_embedded_executor>]() { - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstance - }, "_embedded"); - } - - #[test] - fn [<$method_name _compiled_legacy_instance_reuse_host_executor>]() { - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse - }, "_host"); - } - - #[test] - fn [<$method_name _compiled_legacy_instance_reuse_embedded_executor>]() { - $method_name(WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse - }, "_embedded"); - } - } - }; - - (interpreted_only $method_name:ident) => { - paste::item! { - #[test] - fn [<$method_name _interpreted_host_executor>]() { - $method_name(WasmExecutionMethod::Interpreted, "_host"); - } - } - - paste::item! { - #[test] - fn [<$method_name _interpreted_embedded_executor>]() { - $method_name(WasmExecutionMethod::Interpreted, "_embedded"); - } - } - }; -} - fn call_in_wasm( function: &str, call_data: &[u8], diff --git a/client/executor/src/integration_tests/sandbox.rs b/client/executor/src/integration_tests/sandbox.rs deleted file mode 100644 index 643db5097c6ad..0000000000000 --- a/client/executor/src/integration_tests/sandbox.rs +++ /dev/null @@ -1,339 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::{call_in_wasm, TestExternalities}; -use crate::{test_wasm_execution_sandbox, WasmExecutionMethod}; - -use codec::Encode; - -test_wasm_execution_sandbox!(sandbox_should_work); -fn sandbox_should_work(wasm_method: WasmExecutionMethod, fn_suffix: &str) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - let code = wat::parse_str( - r#" - (module - (import "env" "assert" (func $assert (param i32))) - (import "env" "inc_counter" (func $inc_counter (param i32) (result i32))) - (func (export "call") - (drop - (call $inc_counter (i32.const 5)) - ) - - (call $inc_counter (i32.const 3)) - ;; current counter value is on the stack - - ;; check whether current == 8 - i32.const 8 - i32.eq - - call $assert - ) - ) - "#, - ) - .unwrap() - .encode(); - - assert_eq!( - call_in_wasm(&format!("test_sandbox{}", fn_suffix), &code, wasm_method, &mut ext).unwrap(), - true.encode() - ); -} - -test_wasm_execution_sandbox!(sandbox_trap); -fn sandbox_trap(wasm_method: WasmExecutionMethod, fn_suffix: &str) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - let code = wat::parse_str( - r#" - (module - (import "env" "assert" (func $assert (param i32))) - (func (export "call") - i32.const 0 - call $assert - ) - ) - "#, - ) - .unwrap(); - - assert_eq!( - call_in_wasm(&format!("test_sandbox{}", fn_suffix), &code, wasm_method, &mut ext).unwrap(), - vec![0] - ); -} - -test_wasm_execution_sandbox!(start_called); -fn start_called(wasm_method: WasmExecutionMethod, fn_suffix: &str) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - let code = wat::parse_str( - r#" - (module - (import "env" "assert" (func $assert (param i32))) - (import "env" "inc_counter" (func $inc_counter (param i32) (result i32))) - - ;; Start function - (start $start) - (func $start - ;; Increment counter by 1 - (drop - (call $inc_counter (i32.const 1)) - ) - ) - - (func (export "call") - ;; Increment counter by 1. The current value is placed on the stack. - (call $inc_counter (i32.const 1)) - - ;; Counter is incremented twice by 1, once there and once in `start` func. - ;; So check the returned value is equal to 2. - i32.const 2 - i32.eq - call $assert - ) - ) - "#, - ) - .unwrap() - .encode(); - - assert_eq!( - call_in_wasm(&format!("test_sandbox{}", fn_suffix), &code, wasm_method, &mut ext).unwrap(), - true.encode() - ); -} - -test_wasm_execution_sandbox!(invoke_args); -fn invoke_args(wasm_method: WasmExecutionMethod, fn_suffix: &str) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - let code = wat::parse_str( - r#" - (module - (import "env" "assert" (func $assert (param i32))) - - (func (export "call") (param $x i32) (param $y i64) - ;; assert that $x = 0x12345678 - (call $assert - (i32.eq - (get_local $x) - (i32.const 0x12345678) - ) - ) - - (call $assert - (i64.eq - (get_local $y) - (i64.const 0x1234567887654321) - ) - ) - ) - ) - "#, - ) - .unwrap() - .encode(); - - assert_eq!( - call_in_wasm(&format!("test_sandbox_args{}", fn_suffix), &code, wasm_method, &mut ext,) - .unwrap(), - true.encode(), - ); -} - -test_wasm_execution_sandbox!(return_val); -fn return_val(wasm_method: WasmExecutionMethod, fn_suffix: &str) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - let code = wat::parse_str( - r#" - (module - (func (export "call") (param $x i32) (result i32) - (i32.add - (get_local $x) - (i32.const 1) - ) - ) - ) - "#, - ) - .unwrap() - .encode(); - - assert_eq!( - call_in_wasm( - &format!("test_sandbox_return_val{}", fn_suffix), - &code, - wasm_method, - &mut ext, - ) - .unwrap(), - true.encode(), - ); -} - -test_wasm_execution_sandbox!(unlinkable_module); -fn unlinkable_module(wasm_method: WasmExecutionMethod, fn_suffix: &str) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - let code = wat::parse_str( - r#" - (module - (import "env" "non-existent" (func)) - - (func (export "call") - ) - ) - "#, - ) - .unwrap() - .encode(); - - assert_eq!( - call_in_wasm( - &format!("test_sandbox_instantiate{}", fn_suffix), - &code, - wasm_method, - &mut ext, - ) - .unwrap(), - 1u8.encode(), - ); -} - -test_wasm_execution_sandbox!(corrupted_module); -fn corrupted_module(wasm_method: WasmExecutionMethod, fn_suffix: &str) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - // Corrupted wasm file - let code = vec![0u8, 0, 0, 0, 1, 0, 0, 0].encode(); - - assert_eq!( - call_in_wasm( - &format!("test_sandbox_instantiate{}", fn_suffix), - &code, - wasm_method, - &mut ext, - ) - .unwrap(), - 1u8.encode(), - ); -} - -test_wasm_execution_sandbox!(start_fn_ok); -fn start_fn_ok(wasm_method: WasmExecutionMethod, fn_suffix: &str) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - let code = wat::parse_str( - r#" - (module - (func (export "call") - ) - - (func $start - ) - - (start $start) - ) - "#, - ) - .unwrap() - .encode(); - - assert_eq!( - call_in_wasm( - &format!("test_sandbox_instantiate{}", fn_suffix), - &code, - wasm_method, - &mut ext, - ) - .unwrap(), - 0u8.encode(), - ); -} - -test_wasm_execution_sandbox!(start_fn_traps); -fn start_fn_traps(wasm_method: WasmExecutionMethod, fn_suffix: &str) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - let code = wat::parse_str( - r#" - (module - (func (export "call") - ) - - (func $start - unreachable - ) - - (start $start) - ) - "#, - ) - .unwrap() - .encode(); - - assert_eq!( - call_in_wasm( - &format!("test_sandbox_instantiate{}", fn_suffix), - &code, - wasm_method, - &mut ext, - ) - .unwrap(), - 2u8.encode(), - ); -} - -test_wasm_execution_sandbox!(get_global_val_works); -fn get_global_val_works(wasm_method: WasmExecutionMethod, fn_suffix: &str) { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - - let code = wat::parse_str( - r#" - (module - (global (export "test_global") i64 (i64.const 500)) - ) - "#, - ) - .unwrap() - .encode(); - - assert_eq!( - call_in_wasm( - &format!("test_sandbox_get_global_val{}", fn_suffix), - &code, - wasm_method, - &mut ext, - ) - .unwrap(), - 500i64.encode(), - ); -} diff --git a/client/executor/src/lib.rs b/client/executor/src/lib.rs index 1fb041c358fb1..0670b840949d7 100644 --- a/client/executor/src/lib.rs +++ b/client/executor/src/lib.rs @@ -49,7 +49,7 @@ pub use sp_wasm_interface; pub use wasm_runtime::{read_embedded_version, WasmExecutionMethod}; pub use wasmi; -pub use sc_executor_common::{error, sandbox}; +pub use sc_executor_common::error; pub use sc_executor_wasmtime::InstantiationStrategy as WasmtimeInstantiationStrategy; /// Extracts the runtime version of a given runtime code. diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index ef01f3784154d..4235440023c89 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -14,11 +14,9 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } log = "0.4.17" wasmi = "0.13" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sp-runtime-interface = { version = "7.0.0", path = "../../../primitives/runtime-interface" } -sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interface" } diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index 1284cc23e4c96..6eb38146946b8 100644 --- a/client/executor/wasmi/src/lib.rs +++ b/client/executor/wasmi/src/lib.rs @@ -18,7 +18,7 @@ //! This crate provides an implementation of `WasmModule` that is baked by wasmi. -use std::{cell::RefCell, rc::Rc, str, sync::Arc}; +use std::{cell::RefCell, str, sync::Arc}; use log::{debug, error, trace}; use wasmi::{ @@ -28,26 +28,18 @@ use wasmi::{ TableRef, }; -use codec::{Decode, Encode}; use sc_allocator::AllocationStats; use sc_executor_common::{ error::{Error, MessageWithBacktrace, WasmError}, runtime_blob::{DataSegmentsSnapshot, RuntimeBlob}, - sandbox, - util::MemoryTransfer, wasm_runtime::{InvokeMethod, WasmInstance, WasmModule}, }; use sp_runtime_interface::unpack_ptr_and_len; -use sp_sandbox::env as sandbox_env; -use sp_wasm_interface::{ - Function, FunctionContext, MemoryId, Pointer, Result as WResult, Sandbox, WordSize, -}; +use sp_wasm_interface::{Function, FunctionContext, Pointer, Result as WResult, WordSize}; struct FunctionExecutor { - sandbox_store: Rc>>, heap: RefCell, memory: MemoryRef, - table: Option, host_functions: Arc>, allow_missing_func_imports: bool, missing_functions: Arc>, @@ -58,18 +50,13 @@ impl FunctionExecutor { fn new( m: MemoryRef, heap_base: u32, - t: Option, host_functions: Arc>, allow_missing_func_imports: bool, missing_functions: Arc>, ) -> Result { Ok(FunctionExecutor { - sandbox_store: Rc::new(RefCell::new(sandbox::Store::new( - sandbox::SandboxBackend::Wasmi, - ))), heap: RefCell::new(sc_allocator::FreeingBumpHeapAllocator::new(heap_base)), memory: m, - table: t, host_functions, allow_missing_func_imports, missing_functions, @@ -78,42 +65,6 @@ impl FunctionExecutor { } } -struct SandboxContext<'a> { - executor: &'a mut FunctionExecutor, - dispatch_thunk: wasmi::FuncRef, -} - -impl<'a> sandbox::SandboxContext for SandboxContext<'a> { - fn invoke( - &mut self, - invoke_args_ptr: Pointer, - invoke_args_len: WordSize, - state: u32, - func_idx: sandbox::SupervisorFuncIndex, - ) -> Result { - let result = wasmi::FuncInstance::invoke( - &self.dispatch_thunk, - &[ - RuntimeValue::I32(u32::from(invoke_args_ptr) as i32), - RuntimeValue::I32(invoke_args_len as i32), - RuntimeValue::I32(state as i32), - RuntimeValue::I32(usize::from(func_idx) as i32), - ], - self.executor, - ); - - match result { - Ok(Some(RuntimeValue::I64(val))) => Ok(val), - Ok(_) => Err("Supervisor function returned unexpected result!".into()), - Err(err) => Err(Error::Sandbox(err.to_string())), - } - } - - fn supervisor_context(&mut self) -> &mut dyn FunctionContext { - self.executor - } -} - impl FunctionContext for FunctionExecutor { fn read_memory_into(&self, address: Pointer, dest: &mut [u8]) -> WResult<()> { self.memory.get_into(address.into(), dest).map_err(|e| e.to_string()) @@ -135,189 +86,11 @@ impl FunctionContext for FunctionExecutor { .with_direct_access_mut(|mem| heap.deallocate(mem, ptr).map_err(|e| e.to_string())) } - fn sandbox(&mut self) -> &mut dyn Sandbox { - self - } - fn register_panic_error_message(&mut self, message: &str) { self.panic_message = Some(message.to_owned()); } } -impl Sandbox for FunctionExecutor { - fn memory_get( - &mut self, - memory_id: MemoryId, - offset: WordSize, - buf_ptr: Pointer, - buf_len: WordSize, - ) -> WResult { - let sandboxed_memory = - self.sandbox_store.borrow().memory(memory_id).map_err(|e| e.to_string())?; - - let len = buf_len as usize; - - let buffer = match sandboxed_memory.read(Pointer::new(offset as u32), len) { - Err(_) => return Ok(sandbox_env::ERR_OUT_OF_BOUNDS), - Ok(buffer) => buffer, - }; - - if self.memory.set(buf_ptr.into(), &buffer).is_err() { - return Ok(sandbox_env::ERR_OUT_OF_BOUNDS) - } - - Ok(sandbox_env::ERR_OK) - } - - fn memory_set( - &mut self, - memory_id: MemoryId, - offset: WordSize, - val_ptr: Pointer, - val_len: WordSize, - ) -> WResult { - let sandboxed_memory = - self.sandbox_store.borrow().memory(memory_id).map_err(|e| e.to_string())?; - - let len = val_len as usize; - - #[allow(deprecated)] - let buffer = match self.memory.get(val_ptr.into(), len) { - Err(_) => return Ok(sandbox_env::ERR_OUT_OF_BOUNDS), - Ok(buffer) => buffer, - }; - - if sandboxed_memory.write_from(Pointer::new(offset as u32), &buffer).is_err() { - return Ok(sandbox_env::ERR_OUT_OF_BOUNDS) - } - - Ok(sandbox_env::ERR_OK) - } - - fn memory_teardown(&mut self, memory_id: MemoryId) -> WResult<()> { - self.sandbox_store - .borrow_mut() - .memory_teardown(memory_id) - .map_err(|e| e.to_string()) - } - - fn memory_new(&mut self, initial: u32, maximum: u32) -> WResult { - self.sandbox_store - .borrow_mut() - .new_memory(initial, maximum) - .map_err(|e| e.to_string()) - } - - fn invoke( - &mut self, - instance_id: u32, - export_name: &str, - mut args: &[u8], - return_val: Pointer, - return_val_len: WordSize, - state: u32, - ) -> WResult { - trace!(target: "sp-sandbox", "invoke, instance_idx={}", instance_id); - - // Deserialize arguments and convert them into wasmi types. - let args = Vec::::decode(&mut args) - .map_err(|_| "Can't decode serialized arguments for the invocation")? - .into_iter() - .collect::>(); - - let instance = - self.sandbox_store.borrow().instance(instance_id).map_err(|e| e.to_string())?; - - let dispatch_thunk = self - .sandbox_store - .borrow() - .dispatch_thunk(instance_id) - .map_err(|e| e.to_string())?; - - match instance.invoke( - export_name, - &args, - state, - &mut SandboxContext { dispatch_thunk, executor: self }, - ) { - Ok(None) => Ok(sandbox_env::ERR_OK), - Ok(Some(val)) => { - // Serialize return value and write it back into the memory. - sp_wasm_interface::ReturnValue::Value(val).using_encoded(|val| { - if val.len() > return_val_len as usize { - return Err("Return value buffer is too small".into()) - } - self.write_memory(return_val, val).map_err(|_| "Return value buffer is OOB")?; - Ok(sandbox_env::ERR_OK) - }) - }, - Err(_) => Ok(sandbox_env::ERR_EXECUTION), - } - } - - fn instance_teardown(&mut self, instance_id: u32) -> WResult<()> { - self.sandbox_store - .borrow_mut() - .instance_teardown(instance_id) - .map_err(|e| e.to_string()) - } - - fn instance_new( - &mut self, - dispatch_thunk_id: u32, - wasm: &[u8], - raw_env_def: &[u8], - state: u32, - ) -> WResult { - // Extract a dispatch thunk from instance's table by the specified index. - let dispatch_thunk = { - let table = self - .table - .as_ref() - .ok_or("Runtime doesn't have a table; sandbox is unavailable")?; - table - .get(dispatch_thunk_id) - .map_err(|_| "dispatch_thunk_idx is out of the table bounds")? - .ok_or("dispatch_thunk_idx points on an empty table entry")? - }; - - let guest_env = - match sandbox::GuestEnvironment::decode(&*self.sandbox_store.borrow(), raw_env_def) { - Ok(guest_env) => guest_env, - Err(_) => return Ok(sandbox_env::ERR_MODULE as u32), - }; - - let store = self.sandbox_store.clone(); - let result = store.borrow_mut().instantiate( - wasm, - guest_env, - state, - &mut SandboxContext { executor: self, dispatch_thunk: dispatch_thunk.clone() }, - ); - - let instance_idx_or_err_code = - match result.map(|i| i.register(&mut store.borrow_mut(), dispatch_thunk)) { - Ok(instance_idx) => instance_idx, - Err(sandbox::InstantiationError::StartTrapped) => sandbox_env::ERR_EXECUTION, - Err(_) => sandbox_env::ERR_MODULE, - }; - - Ok(instance_idx_or_err_code) - } - - fn get_global_val( - &self, - instance_idx: u32, - name: &str, - ) -> WResult> { - self.sandbox_store - .borrow() - .instance(instance_idx) - .map(|i| i.get_global_val(name)) - .map_err(|e| e.to_string()) - } -} - /// Will be used on initialization of a module to resolve function and memory imports. struct Resolver<'a> { /// All the hot functions that we export for the WASM blob. @@ -502,7 +275,6 @@ fn call_in_wasm_module( let mut function_executor = FunctionExecutor::new( memory.clone(), heap_base, - table.clone(), host_functions, allow_missing_func_imports, missing_functions, diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index b12ca0779e7a2..7e38929f05a13 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -14,10 +14,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] cfg-if = "1.0" -codec = { package = "parity-scale-codec", version = "3.0.0" } libc = "0.2.121" log = "0.4.17" -parity-wasm = "0.45" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! @@ -32,7 +30,6 @@ wasmtime = { version = "1.0.0", default-features = false, features = [ sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sp-runtime-interface = { version = "7.0.0", path = "../../../primitives/runtime-interface" } -sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interface" } # Here we include the rustix crate in the exactly same semver-compatible version as used by @@ -50,3 +47,4 @@ sc-runtime-test = { version = "2.0.0", path = "../runtime-test" } sp-io = { version = "7.0.0", path = "../../../primitives/io" } tempfile = "3.3.0" paste = "1.0" +codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index 768a6e36e2390..0d9eac875170b 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -19,33 +19,17 @@ //! This module defines `HostState` and `HostContext` structs which provide logic and state //! required for execution of host. -use log::trace; -use wasmtime::{Caller, Func, Val}; +use wasmtime::Caller; -use codec::{Decode, Encode}; use sc_allocator::{AllocationStats, FreeingBumpHeapAllocator}; -use sc_executor_common::{ - error::Result, - sandbox::{self, SupervisorFuncIndex}, - util::MemoryTransfer, -}; -use sp_sandbox::env as sandbox_env; -use sp_wasm_interface::{FunctionContext, MemoryId, Pointer, Sandbox, WordSize}; +use sp_wasm_interface::{Pointer, WordSize}; use crate::{runtime::StoreData, util}; -// The sandbox store is inside of a Option>> so that we can temporarily borrow it. -struct SandboxStore(Option>>); - -// There are a bunch of `Rc`s within the sandbox store, however we only manipulate -// those within one thread so this should be safe. -unsafe impl Send for SandboxStore {} - /// The state required to construct a HostContext context. The context only lasts for one host /// call, whereas the state is maintained for the duration of a Wasm runtime call, which may make /// many different host calls that must share state. pub struct HostState { - sandbox_store: SandboxStore, allocator: FreeingBumpHeapAllocator, panic_message: Option, } @@ -53,13 +37,7 @@ pub struct HostState { impl HostState { /// Constructs a new `HostState`. pub fn new(allocator: FreeingBumpHeapAllocator) -> Self { - HostState { - sandbox_store: SandboxStore(Some(Box::new(sandbox::Store::new( - sandbox::SandboxBackend::TryWasmer, - )))), - allocator, - panic_message: None, - } + HostState { allocator, panic_message: None } } /// Takes the error message out of the host state, leaving a `None` in its place. @@ -80,35 +58,12 @@ pub(crate) struct HostContext<'a> { } impl<'a> HostContext<'a> { - fn host_state(&self) -> &HostState { - self.caller - .data() - .host_state() - .expect("host state is not empty when calling a function in wasm; qed") - } - fn host_state_mut(&mut self) -> &mut HostState { self.caller .data_mut() .host_state_mut() .expect("host state is not empty when calling a function in wasm; qed") } - - fn sandbox_store(&self) -> &sandbox::Store { - self.host_state() - .sandbox_store - .0 - .as_ref() - .expect("sandbox store is only empty when temporarily borrowed") - } - - fn sandbox_store_mut(&mut self) -> &mut sandbox::Store { - self.host_state_mut() - .sandbox_store - .0 - .as_mut() - .expect("sandbox store is only empty when temporarily borrowed") - } } impl<'a> sp_wasm_interface::FunctionContext for HostContext<'a> { @@ -144,233 +99,7 @@ impl<'a> sp_wasm_interface::FunctionContext for HostContext<'a> { .map_err(|e| e.to_string()) } - fn sandbox(&mut self) -> &mut dyn Sandbox { - self - } - fn register_panic_error_message(&mut self, message: &str) { self.host_state_mut().panic_message = Some(message.to_owned()); } } - -impl<'a> Sandbox for HostContext<'a> { - fn memory_get( - &mut self, - memory_id: MemoryId, - offset: WordSize, - buf_ptr: Pointer, - buf_len: WordSize, - ) -> sp_wasm_interface::Result { - let sandboxed_memory = self.sandbox_store().memory(memory_id).map_err(|e| e.to_string())?; - - let len = buf_len as usize; - - let buffer = match sandboxed_memory.read(Pointer::new(offset as u32), len) { - Err(_) => return Ok(sandbox_env::ERR_OUT_OF_BOUNDS), - Ok(buffer) => buffer, - }; - - if util::write_memory_from(&mut self.caller, buf_ptr, &buffer).is_err() { - return Ok(sandbox_env::ERR_OUT_OF_BOUNDS) - } - - Ok(sandbox_env::ERR_OK) - } - - fn memory_set( - &mut self, - memory_id: MemoryId, - offset: WordSize, - val_ptr: Pointer, - val_len: WordSize, - ) -> sp_wasm_interface::Result { - let sandboxed_memory = self.sandbox_store().memory(memory_id).map_err(|e| e.to_string())?; - - let len = val_len as usize; - - let buffer = match util::read_memory(&self.caller, val_ptr, len) { - Err(_) => return Ok(sandbox_env::ERR_OUT_OF_BOUNDS), - Ok(buffer) => buffer, - }; - - if sandboxed_memory.write_from(Pointer::new(offset as u32), &buffer).is_err() { - return Ok(sandbox_env::ERR_OUT_OF_BOUNDS) - } - - Ok(sandbox_env::ERR_OK) - } - - fn memory_teardown(&mut self, memory_id: MemoryId) -> sp_wasm_interface::Result<()> { - self.sandbox_store_mut().memory_teardown(memory_id).map_err(|e| e.to_string()) - } - - fn memory_new(&mut self, initial: u32, maximum: u32) -> sp_wasm_interface::Result { - self.sandbox_store_mut().new_memory(initial, maximum).map_err(|e| e.to_string()) - } - - fn invoke( - &mut self, - instance_id: u32, - export_name: &str, - mut args: &[u8], - return_val: Pointer, - return_val_len: u32, - state: u32, - ) -> sp_wasm_interface::Result { - trace!(target: "sp-sandbox", "invoke, instance_idx={}", instance_id); - - // Deserialize arguments and convert them into wasmi types. - let args = Vec::::decode(&mut args) - .map_err(|_| "Can't decode serialized arguments for the invocation")? - .into_iter() - .collect::>(); - - let instance = self.sandbox_store().instance(instance_id).map_err(|e| e.to_string())?; - - let dispatch_thunk = - self.sandbox_store().dispatch_thunk(instance_id).map_err(|e| e.to_string())?; - - let result = instance.invoke( - export_name, - &args, - state, - &mut SandboxContext { host_context: self, dispatch_thunk }, - ); - - match result { - Ok(None) => Ok(sandbox_env::ERR_OK), - Ok(Some(val)) => { - // Serialize return value and write it back into the memory. - sp_wasm_interface::ReturnValue::Value(val.into()).using_encoded(|val| { - if val.len() > return_val_len as usize { - return Err("Return value buffer is too small".into()) - } - ::write_memory(self, return_val, val) - .map_err(|_| "can't write return value")?; - Ok(sandbox_env::ERR_OK) - }) - }, - Err(_) => Ok(sandbox_env::ERR_EXECUTION), - } - } - - fn instance_teardown(&mut self, instance_id: u32) -> sp_wasm_interface::Result<()> { - self.sandbox_store_mut() - .instance_teardown(instance_id) - .map_err(|e| e.to_string()) - } - - fn instance_new( - &mut self, - dispatch_thunk_id: u32, - wasm: &[u8], - raw_env_def: &[u8], - state: u32, - ) -> sp_wasm_interface::Result { - // Extract a dispatch thunk from the instance's table by the specified index. - let dispatch_thunk = { - let table = self - .caller - .data() - .table() - .ok_or("Runtime doesn't have a table; sandbox is unavailable")?; - let table_item = table.get(&mut self.caller, dispatch_thunk_id); - - *table_item - .ok_or("dispatch_thunk_id is out of bounds")? - .funcref() - .ok_or("dispatch_thunk_idx should be a funcref")? - .ok_or("dispatch_thunk_idx should point to actual func")? - }; - - let guest_env = match sandbox::GuestEnvironment::decode(self.sandbox_store(), raw_env_def) { - Ok(guest_env) => guest_env, - Err(_) => return Ok(sandbox_env::ERR_MODULE as u32), - }; - - let mut store = self - .host_state_mut() - .sandbox_store - .0 - .take() - .expect("sandbox store is only empty when borrowed"); - - // Catch any potential panics so that we can properly restore the sandbox store - // which we've destructively borrowed. - let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - store.instantiate( - wasm, - guest_env, - state, - &mut SandboxContext { host_context: self, dispatch_thunk }, - ) - })); - - self.host_state_mut().sandbox_store.0 = Some(store); - - let result = match result { - Ok(result) => result, - Err(error) => std::panic::resume_unwind(error), - }; - - let instance_idx_or_err_code = match result { - Ok(instance) => instance.register(self.sandbox_store_mut(), dispatch_thunk), - Err(sandbox::InstantiationError::StartTrapped) => sandbox_env::ERR_EXECUTION, - Err(_) => sandbox_env::ERR_MODULE, - }; - - Ok(instance_idx_or_err_code as u32) - } - - fn get_global_val( - &self, - instance_idx: u32, - name: &str, - ) -> sp_wasm_interface::Result> { - self.sandbox_store() - .instance(instance_idx) - .map(|i| i.get_global_val(name)) - .map_err(|e| e.to_string()) - } -} - -struct SandboxContext<'a, 'b> { - host_context: &'a mut HostContext<'b>, - dispatch_thunk: Func, -} - -impl<'a, 'b> sandbox::SandboxContext for SandboxContext<'a, 'b> { - fn invoke( - &mut self, - invoke_args_ptr: Pointer, - invoke_args_len: WordSize, - state: u32, - func_idx: SupervisorFuncIndex, - ) -> Result { - let mut ret_vals = [Val::null()]; - let result = self.dispatch_thunk.call( - &mut self.host_context.caller, - &[ - Val::I32(u32::from(invoke_args_ptr) as i32), - Val::I32(invoke_args_len as i32), - Val::I32(state as i32), - Val::I32(usize::from(func_idx) as i32), - ], - &mut ret_vals, - ); - - match result { - Ok(()) => - if let Some(ret_val) = ret_vals[0].i64() { - Ok(ret_val) - } else { - Err("Supervisor function returned unexpected result!".into()) - }, - Err(err) => Err(err.to_string().into()), - } - } - - fn supervisor_context(&mut self) -> &mut dyn FunctionContext { - self.host_context - } -} diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 5bca899648c34..b124fd627dc69 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -56,11 +56,6 @@ pub(crate) struct StoreData { } impl StoreData { - /// Returns a reference to the host state. - pub fn host_state(&self) -> Option<&HostState> { - self.host_state.as_ref() - } - /// Returns a mutable reference to the host state. pub fn host_state_mut(&mut self) -> Option<&mut HostState> { self.host_state.as_mut() @@ -70,11 +65,6 @@ impl StoreData { pub fn memory(&self) -> Memory { self.memory.expect("memory is always set; qed") } - - /// Returns the host table. - pub fn table(&self) -> Option { - self.table - } } pub(crate) type Store = wasmtime::Store; diff --git a/client/executor/wasmtime/src/util.rs b/client/executor/wasmtime/src/util.rs index 83745e21e86af..15f62e475033a 100644 --- a/client/executor/wasmtime/src/util.rs +++ b/client/executor/wasmtime/src/util.rs @@ -48,24 +48,6 @@ pub fn into_wasmtime_val(value: Value) -> wasmtime::Val { } } -/// Read data from a slice of memory into a newly allocated buffer. -/// -/// Returns an error if the read would go out of the memory bounds. -pub(crate) fn read_memory( - ctx: impl AsContext, - source_addr: Pointer, - size: usize, -) -> Result> { - let range = - checked_range(source_addr.into(), size, ctx.as_context().data().memory().data_size(&ctx)) - .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; - - let mut buffer = vec![0; range.len()]; - read_memory_into(ctx, source_addr, &mut buffer)?; - - Ok(buffer) -} - /// Read data from the instance memory into a slice. /// /// Returns an error if the read would go out of the memory bounds. diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index ead3ada1d1438..600d76b3b4300 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -1611,99 +1611,6 @@ mod tracing_setup { pub use tracing_setup::init_tracing; -/// Wasm-only interface that provides functions for interacting with the sandbox. -#[runtime_interface(wasm_only)] -pub trait Sandbox { - /// Instantiate a new sandbox instance with the given `wasm_code`. - fn instantiate( - &mut self, - dispatch_thunk: u32, - wasm_code: &[u8], - env_def: &[u8], - state_ptr: Pointer, - ) -> u32 { - self.sandbox() - .instance_new(dispatch_thunk, wasm_code, env_def, state_ptr.into()) - .expect("Failed to instantiate a new sandbox") - } - - /// Invoke `function` in the sandbox with `sandbox_idx`. - fn invoke( - &mut self, - instance_idx: u32, - function: &str, - args: &[u8], - return_val_ptr: Pointer, - return_val_len: u32, - state_ptr: Pointer, - ) -> u32 { - self.sandbox() - .invoke(instance_idx, function, args, return_val_ptr, return_val_len, state_ptr.into()) - .expect("Failed to invoke function with sandbox") - } - - /// Create a new memory instance with the given `initial` and `maximum` size. - fn memory_new(&mut self, initial: u32, maximum: u32) -> u32 { - self.sandbox() - .memory_new(initial, maximum) - .expect("Failed to create new memory with sandbox") - } - - /// Get the memory starting at `offset` from the instance with `memory_idx` into the buffer. - fn memory_get( - &mut self, - memory_idx: u32, - offset: u32, - buf_ptr: Pointer, - buf_len: u32, - ) -> u32 { - self.sandbox() - .memory_get(memory_idx, offset, buf_ptr, buf_len) - .expect("Failed to get memory with sandbox") - } - - /// Set the memory in the given `memory_idx` to the given value at `offset`. - fn memory_set( - &mut self, - memory_idx: u32, - offset: u32, - val_ptr: Pointer, - val_len: u32, - ) -> u32 { - self.sandbox() - .memory_set(memory_idx, offset, val_ptr, val_len) - .expect("Failed to set memory with sandbox") - } - - /// Teardown the memory instance with the given `memory_idx`. - fn memory_teardown(&mut self, memory_idx: u32) { - self.sandbox() - .memory_teardown(memory_idx) - .expect("Failed to teardown memory with sandbox") - } - - /// Teardown the sandbox instance with the given `instance_idx`. - fn instance_teardown(&mut self, instance_idx: u32) { - self.sandbox() - .instance_teardown(instance_idx) - .expect("Failed to teardown sandbox instance") - } - - /// Get the value from a global with the given `name`. The sandbox is determined by the given - /// `instance_idx`. - /// - /// Returns `Some(_)` when the requested global variable could be found. - fn get_global_val( - &mut self, - instance_idx: u32, - name: &str, - ) -> Option { - self.sandbox() - .get_global_val(instance_idx, name) - .expect("Failed to get global from sandbox") - } -} - /// Allocator used by Substrate when executing the Wasm runtime. #[cfg(all(target_arch = "wasm32", not(feature = "std")))] struct WasmAllocator; @@ -1779,7 +1686,6 @@ pub type SubstrateHostFunctions = ( allocator::HostFunctions, panic_handler::HostFunctions, logging::HostFunctions, - sandbox::HostFunctions, crate::trie::HostFunctions, offchain_index::HostFunctions, transaction_index::HostFunctions, diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml deleted file mode 100644 index 024fe7209393c..0000000000000 --- a/primitives/sandbox/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "sp-sandbox" -version = "0.10.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "This crate provides means to instantiate and execute wasm modules." -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4", default-features = false } -wasmi = { version = "0.13", default-features = false } -sp-core = { version = "7.0.0", default-features = false, path = "../core" } -sp-io = { version = "7.0.0", default-features = false, path = "../io" } -sp-std = { version = "5.0.0", default-features = false, path = "../std" } -sp-wasm-interface = { version = "7.0.0", default-features = false, path = "../wasm-interface" } - -[dev-dependencies] -assert_matches = "1.3.0" -wat = "1.0" - -[features] -default = ["std"] -std = [ - "codec/std", - "log/std", - "sp-core/std", - "sp-io/std", - "sp-std/std", - "sp-wasm-interface/std", - "wasmi/std", -] -strict = [] -wasmer-sandbox = [] diff --git a/primitives/sandbox/README.md b/primitives/sandbox/README.md deleted file mode 100644 index 9335b53ae1fb9..0000000000000 --- a/primitives/sandbox/README.md +++ /dev/null @@ -1,21 +0,0 @@ -This crate provides means to instantiate and execute wasm modules. - -It works even when the user of this library executes from -inside the wasm VM. In this case the same VM is used for execution -of both the sandbox owner and the sandboxed module, without compromising security -and without the performance penalty of full wasm emulation inside wasm. - -This is achieved by using bindings to the wasm VM, which are published by the host API. -This API is thin and consists of only a handful functions. It contains functions for instantiating -modules and executing them, but doesn't contain functions for inspecting the module -structure. The user of this library is supposed to read the wasm module. - -When this crate is used in the `std` environment all these functions are implemented by directly -calling the wasm VM. - -Examples of possible use-cases for this library are not limited to the following: - -- implementing smart-contract runtimes that use wasm for contract code -- executing a wasm substrate runtime inside of a wasm parachain - -License: Apache-2.0 \ No newline at end of file diff --git a/primitives/sandbox/src/embedded_executor.rs b/primitives/sandbox/src/embedded_executor.rs deleted file mode 100644 index 115c3192f3d89..0000000000000 --- a/primitives/sandbox/src/embedded_executor.rs +++ /dev/null @@ -1,478 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! An embedded WASM executor utilizing `wasmi`. - -use alloc::string::String; - -use wasmi::{ - memory_units::Pages, Externals, FuncInstance, FuncRef, GlobalDescriptor, GlobalRef, - ImportResolver, MemoryDescriptor, MemoryInstance, MemoryRef, Module, ModuleInstance, ModuleRef, - RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableRef, Trap, -}; - -use sp_std::{ - borrow::ToOwned, collections::btree_map::BTreeMap, fmt, marker::PhantomData, prelude::*, -}; - -use crate::{Error, HostError, HostFuncType, ReturnValue, Value, TARGET}; - -/// The linear memory used by the sandbox. -#[derive(Clone)] -pub struct Memory { - memref: MemoryRef, -} - -impl super::SandboxMemory for Memory { - fn new(initial: u32, maximum: Option) -> Result { - Ok(Memory { - memref: MemoryInstance::alloc( - Pages(initial as usize), - maximum.map(|m| Pages(m as usize)), - ) - .map_err(|_| Error::Module)?, - }) - } - - fn get(&self, ptr: u32, buf: &mut [u8]) -> Result<(), Error> { - self.memref.get_into(ptr, buf).map_err(|_| Error::OutOfBounds)?; - Ok(()) - } - - fn set(&self, ptr: u32, value: &[u8]) -> Result<(), Error> { - self.memref.set(ptr, value).map_err(|_| Error::OutOfBounds)?; - Ok(()) - } -} - -struct HostFuncIndex(usize); - -struct DefinedHostFunctions { - funcs: Vec>, -} - -impl Clone for DefinedHostFunctions { - fn clone(&self) -> DefinedHostFunctions { - DefinedHostFunctions { funcs: self.funcs.clone() } - } -} - -impl DefinedHostFunctions { - fn new() -> DefinedHostFunctions { - DefinedHostFunctions { funcs: Vec::new() } - } - - fn define(&mut self, f: HostFuncType) -> HostFuncIndex { - let idx = self.funcs.len(); - self.funcs.push(f); - HostFuncIndex(idx) - } -} - -#[derive(Debug)] -struct DummyHostError; - -impl fmt::Display for DummyHostError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DummyHostError") - } -} - -impl wasmi::HostError for DummyHostError {} - -struct GuestExternals<'a, T: 'a> { - state: &'a mut T, - defined_host_functions: &'a DefinedHostFunctions, -} - -impl<'a, T> Externals for GuestExternals<'a, T> { - fn invoke_index( - &mut self, - index: usize, - args: RuntimeArgs, - ) -> Result, Trap> { - let args = args.as_ref().iter().cloned().map(to_interface).collect::>(); - - let result = (self.defined_host_functions.funcs[index])(self.state, &args); - match result { - Ok(value) => Ok(match value { - ReturnValue::Value(v) => Some(to_wasmi(v)), - ReturnValue::Unit => None, - }), - Err(HostError) => Err(Trap::host(DummyHostError)), - } - } -} - -enum ExternVal { - HostFunc(HostFuncIndex), - Memory(Memory), -} - -/// A builder for the environment of the sandboxed WASM module. -pub struct EnvironmentDefinitionBuilder { - map: BTreeMap<(Vec, Vec), ExternVal>, - defined_host_functions: DefinedHostFunctions, -} - -impl super::SandboxEnvironmentBuilder for EnvironmentDefinitionBuilder { - fn new() -> EnvironmentDefinitionBuilder { - EnvironmentDefinitionBuilder { - map: BTreeMap::new(), - defined_host_functions: DefinedHostFunctions::new(), - } - } - - fn add_host_func(&mut self, module: N1, field: N2, f: HostFuncType) - where - N1: Into>, - N2: Into>, - { - let idx = self.defined_host_functions.define(f); - self.map.insert((module.into(), field.into()), ExternVal::HostFunc(idx)); - } - - fn add_memory(&mut self, module: N1, field: N2, mem: Memory) - where - N1: Into>, - N2: Into>, - { - self.map.insert((module.into(), field.into()), ExternVal::Memory(mem)); - } -} - -impl ImportResolver for EnvironmentDefinitionBuilder { - fn resolve_func( - &self, - module_name: &str, - field_name: &str, - signature: &Signature, - ) -> Result { - let key = (module_name.as_bytes().to_owned(), field_name.as_bytes().to_owned()); - let externval = self.map.get(&key).ok_or_else(|| { - log::debug!(target: TARGET, "Export {}:{} not found", module_name, field_name); - wasmi::Error::Instantiation(String::new()) - })?; - let host_func_idx = match *externval { - ExternVal::HostFunc(ref idx) => idx, - _ => { - log::debug!( - target: TARGET, - "Export {}:{} is not a host func", - module_name, - field_name, - ); - return Err(wasmi::Error::Instantiation(String::new())) - }, - }; - Ok(FuncInstance::alloc_host(signature.clone(), host_func_idx.0)) - } - - fn resolve_global( - &self, - _module_name: &str, - _field_name: &str, - _global_type: &GlobalDescriptor, - ) -> Result { - log::debug!(target: TARGET, "Importing globals is not supported yet"); - Err(wasmi::Error::Instantiation(String::new())) - } - - fn resolve_memory( - &self, - module_name: &str, - field_name: &str, - _memory_type: &MemoryDescriptor, - ) -> Result { - let key = (module_name.as_bytes().to_owned(), field_name.as_bytes().to_owned()); - let externval = self.map.get(&key).ok_or_else(|| { - log::debug!(target: TARGET, "Export {}:{} not found", module_name, field_name); - wasmi::Error::Instantiation(String::new()) - })?; - let memory = match *externval { - ExternVal::Memory(ref m) => m, - _ => { - log::debug!( - target: TARGET, - "Export {}:{} is not a memory", - module_name, - field_name, - ); - return Err(wasmi::Error::Instantiation(String::new())) - }, - }; - Ok(memory.memref.clone()) - } - - fn resolve_table( - &self, - _module_name: &str, - _field_name: &str, - _table_type: &TableDescriptor, - ) -> Result { - log::debug!("Importing tables is not supported yet"); - Err(wasmi::Error::Instantiation(String::new())) - } -} - -/// Sandboxed instance of a WASM module. -pub struct Instance { - instance: ModuleRef, - defined_host_functions: DefinedHostFunctions, - _marker: PhantomData, -} - -impl super::SandboxInstance for Instance { - type Memory = Memory; - type EnvironmentBuilder = EnvironmentDefinitionBuilder; - - fn new( - code: &[u8], - env_def_builder: &EnvironmentDefinitionBuilder, - state: &mut T, - ) -> Result, Error> { - let module = Module::from_buffer(code).map_err(|_| Error::Module)?; - let not_started_instance = - ModuleInstance::new(&module, env_def_builder).map_err(|_| Error::Module)?; - - let defined_host_functions = env_def_builder.defined_host_functions.clone(); - let instance = { - let mut externals = - GuestExternals { state, defined_host_functions: &defined_host_functions }; - let instance = - not_started_instance.run_start(&mut externals).map_err(|_| Error::Execution)?; - instance - }; - - Ok(Instance { instance, defined_host_functions, _marker: PhantomData:: }) - } - - fn invoke(&mut self, name: &str, args: &[Value], state: &mut T) -> Result { - let args = args.iter().cloned().map(to_wasmi).collect::>(); - - let mut externals = - GuestExternals { state, defined_host_functions: &self.defined_host_functions }; - let result = self.instance.invoke_export(name, &args, &mut externals); - - match result { - Ok(None) => Ok(ReturnValue::Unit), - Ok(Some(val)) => Ok(ReturnValue::Value(to_interface(val))), - Err(_err) => Err(Error::Execution), - } - } - - fn get_global_val(&self, name: &str) -> Option { - let global = self.instance.export_by_name(name)?.as_global()?.get(); - - Some(to_interface(global)) - } -} - -/// Convert the substrate value type to the wasmi value type. -fn to_wasmi(value: Value) -> RuntimeValue { - match value { - Value::I32(val) => RuntimeValue::I32(val), - Value::I64(val) => RuntimeValue::I64(val), - Value::F32(val) => RuntimeValue::F32(val.into()), - Value::F64(val) => RuntimeValue::F64(val.into()), - } -} - -/// Convert the wasmi value type to the substrate value type. -fn to_interface(value: RuntimeValue) -> Value { - match value { - RuntimeValue::I32(val) => Value::I32(val), - RuntimeValue::I64(val) => Value::I64(val), - RuntimeValue::F32(val) => Value::F32(val.into()), - RuntimeValue::F64(val) => Value::F64(val.into()), - } -} - -#[cfg(test)] -mod tests { - use super::{EnvironmentDefinitionBuilder, Instance}; - use crate::{Error, HostError, ReturnValue, SandboxEnvironmentBuilder, SandboxInstance, Value}; - use assert_matches::assert_matches; - - fn execute_sandboxed(code: &[u8], args: &[Value]) -> Result { - struct State { - counter: u32, - } - - fn env_assert(_e: &mut State, args: &[Value]) -> Result { - if args.len() != 1 { - return Err(HostError) - } - let condition = args[0].as_i32().ok_or_else(|| HostError)?; - if condition != 0 { - Ok(ReturnValue::Unit) - } else { - Err(HostError) - } - } - fn env_inc_counter(e: &mut State, args: &[Value]) -> Result { - if args.len() != 1 { - return Err(HostError) - } - let inc_by = args[0].as_i32().ok_or_else(|| HostError)?; - e.counter += inc_by as u32; - Ok(ReturnValue::Value(Value::I32(e.counter as i32))) - } - /// Function that takes one argument of any type and returns that value. - fn env_polymorphic_id(_e: &mut State, args: &[Value]) -> Result { - if args.len() != 1 { - return Err(HostError) - } - Ok(ReturnValue::Value(args[0])) - } - - let mut state = State { counter: 0 }; - - let mut env_builder = EnvironmentDefinitionBuilder::new(); - env_builder.add_host_func("env", "assert", env_assert); - env_builder.add_host_func("env", "inc_counter", env_inc_counter); - env_builder.add_host_func("env", "polymorphic_id", env_polymorphic_id); - - let mut instance = Instance::new(code, &env_builder, &mut state)?; - let result = instance.invoke("call", args, &mut state); - - result.map_err(|_| HostError) - } - - #[test] - fn invoke_args() { - let code = wat::parse_str( - r#" - (module - (import "env" "assert" (func $assert (param i32))) - - (func (export "call") (param $x i32) (param $y i64) - ;; assert that $x = 0x12345678 - (call $assert - (i32.eq - (get_local $x) - (i32.const 0x12345678) - ) - ) - - (call $assert - (i64.eq - (get_local $y) - (i64.const 0x1234567887654321) - ) - ) - ) - ) - "#, - ) - .unwrap(); - - let result = - execute_sandboxed(&code, &[Value::I32(0x12345678), Value::I64(0x1234567887654321)]); - assert!(result.is_ok()); - } - - #[test] - fn return_value() { - let code = wat::parse_str( - r#" - (module - (func (export "call") (param $x i32) (result i32) - (i32.add - (get_local $x) - (i32.const 1) - ) - ) - ) - "#, - ) - .unwrap(); - - let return_val = execute_sandboxed(&code, &[Value::I32(0x1336)]).unwrap(); - assert_eq!(return_val, ReturnValue::Value(Value::I32(0x1337))); - } - - #[test] - fn signatures_dont_matter() { - let code = wat::parse_str( - r#" - (module - (import "env" "polymorphic_id" (func $id_i32 (param i32) (result i32))) - (import "env" "polymorphic_id" (func $id_i64 (param i64) (result i64))) - (import "env" "assert" (func $assert (param i32))) - - (func (export "call") - ;; assert that we can actually call the "same" function with different - ;; signatures. - (call $assert - (i32.eq - (call $id_i32 - (i32.const 0x012345678) - ) - (i32.const 0x012345678) - ) - ) - (call $assert - (i64.eq - (call $id_i64 - (i64.const 0x0123456789abcdef) - ) - (i64.const 0x0123456789abcdef) - ) - ) - ) - ) - "#, - ) - .unwrap(); - - let return_val = execute_sandboxed(&code, &[]).unwrap(); - assert_eq!(return_val, ReturnValue::Unit); - } - - #[test] - fn cant_return_unmatching_type() { - fn env_returns_i32(_e: &mut (), _args: &[Value]) -> Result { - Ok(ReturnValue::Value(Value::I32(42))) - } - - let mut env_builder = EnvironmentDefinitionBuilder::new(); - env_builder.add_host_func("env", "returns_i32", env_returns_i32); - - let code = wat::parse_str( - r#" - (module - ;; It's actually returns i32, but imported as if it returned i64 - (import "env" "returns_i32" (func $returns_i32 (result i64))) - - (func (export "call") - (drop - (call $returns_i32) - ) - ) - ) - "#, - ) - .unwrap(); - - // It succeeds since we are able to import functions with types we want. - let mut instance = Instance::new(&code, &env_builder, &mut ()).unwrap(); - - // But this fails since we imported a function that returns i32 as if it returned i64. - assert_matches!(instance.invoke("call", &[], &mut ()), Err(Error::Execution)); - } -} diff --git a/primitives/sandbox/src/env.rs b/primitives/sandbox/src/env.rs deleted file mode 100644 index 94b1c5e467a9c..0000000000000 --- a/primitives/sandbox/src/env.rs +++ /dev/null @@ -1,120 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Definition of a sandbox environment. - -use codec::{Decode, Encode}; - -use sp_core::RuntimeDebug; -use sp_std::vec::Vec; - -/// Error error that can be returned from host function. -#[derive(Encode, Decode, RuntimeDebug)] -pub struct HostError; - -/// Describes an entity to define or import into the environment. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] -pub enum ExternEntity { - /// Function that is specified by an index in a default table of - /// a module that creates the sandbox. - #[codec(index = 1)] - Function(u32), - - /// Linear memory that is specified by some identifier returned by sandbox - /// module upon creation new sandboxed memory. - #[codec(index = 2)] - Memory(u32), -} - -/// An entry in a environment definition table. -/// -/// Each entry has a two-level name and description of an entity -/// being defined. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] -pub struct Entry { - /// Module name of which corresponding entity being defined. - pub module_name: Vec, - /// Field name in which corresponding entity being defined. - pub field_name: Vec, - /// External entity being defined. - pub entity: ExternEntity, -} - -/// Definition of runtime that could be used by sandboxed code. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] -pub struct EnvironmentDefinition { - /// Vector of all entries in the environment definition. - pub entries: Vec, -} - -/// Constant for specifying no limit when creating a sandboxed -/// memory instance. For FFI purposes. -pub const MEM_UNLIMITED: u32 = -1i32 as u32; - -/// No error happened. -/// -/// For FFI purposes. -pub const ERR_OK: u32 = 0; - -/// Validation or instantiation error occurred when creating new -/// sandboxed module instance. -/// -/// For FFI purposes. -pub const ERR_MODULE: u32 = -1i32 as u32; - -/// Out-of-bounds access attempted with memory or table. -/// -/// For FFI purposes. -pub const ERR_OUT_OF_BOUNDS: u32 = -2i32 as u32; - -/// Execution error occurred (typically trap). -/// -/// For FFI purposes. -pub const ERR_EXECUTION: u32 = -3i32 as u32; - -#[cfg(test)] -mod tests { - use super::*; - use codec::Codec; - use std::fmt; - - fn roundtrip(s: S) { - let encoded = s.encode(); - assert_eq!(S::decode(&mut &encoded[..]).unwrap(), s); - } - - #[test] - fn env_def_roundtrip() { - roundtrip(EnvironmentDefinition { entries: vec![] }); - - roundtrip(EnvironmentDefinition { - entries: vec![Entry { - module_name: b"kernel"[..].into(), - field_name: b"memory"[..].into(), - entity: ExternEntity::Memory(1337), - }], - }); - - roundtrip(EnvironmentDefinition { - entries: vec![Entry { - module_name: b"env"[..].into(), - field_name: b"abort"[..].into(), - entity: ExternEntity::Function(228), - }], - }); - } -} diff --git a/primitives/sandbox/src/host_executor.rs b/primitives/sandbox/src/host_executor.rs deleted file mode 100644 index e62c051262ca8..0000000000000 --- a/primitives/sandbox/src/host_executor.rs +++ /dev/null @@ -1,274 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! A WASM executor utilizing the sandbox runtime interface of the host. - -use codec::{Decode, Encode}; - -use sp_io::sandbox; -use sp_std::{marker, mem, prelude::*, rc::Rc, slice, vec}; - -use crate::{env, Error, HostFuncType, ReturnValue, Value}; - -mod ffi { - use super::HostFuncType; - use sp_std::mem; - - /// Index into the default table that points to a `HostFuncType`. - pub type HostFuncIndex = usize; - - /// Coerce `HostFuncIndex` to a callable host function pointer. - /// - /// # Safety - /// - /// This function should be only called with a `HostFuncIndex` that was previously registered - /// in the environment definition. Typically this should only - /// be called with an argument received in `dispatch_thunk`. - pub unsafe fn coerce_host_index_to_func(idx: HostFuncIndex) -> HostFuncType { - // We need to ensure that sizes of a callable function pointer and host function index is - // indeed equal. - // We can't use `static_assertions` create because it makes compiler panic, fallback to - // runtime assert. const_assert!(mem::size_of::() == - // mem::size_of::>()); - assert!(mem::size_of::() == mem::size_of::>()); - mem::transmute::>(idx) - } -} - -struct MemoryHandle { - memory_idx: u32, -} - -impl Drop for MemoryHandle { - fn drop(&mut self) { - sandbox::memory_teardown(self.memory_idx); - } -} - -/// The linear memory used by the sandbox. -#[derive(Clone)] -pub struct Memory { - // Handle to memory instance is wrapped to add reference-counting semantics - // to `Memory`. - handle: Rc, -} - -impl super::SandboxMemory for Memory { - fn new(initial: u32, maximum: Option) -> Result { - let maximum = if let Some(maximum) = maximum { maximum } else { env::MEM_UNLIMITED }; - - match sandbox::memory_new(initial, maximum) { - env::ERR_MODULE => Err(Error::Module), - memory_idx => Ok(Memory { handle: Rc::new(MemoryHandle { memory_idx }) }), - } - } - - fn get(&self, offset: u32, buf: &mut [u8]) -> Result<(), Error> { - let result = - sandbox::memory_get(self.handle.memory_idx, offset, buf.as_mut_ptr(), buf.len() as u32); - match result { - env::ERR_OK => Ok(()), - env::ERR_OUT_OF_BOUNDS => Err(Error::OutOfBounds), - _ => unreachable!(), - } - } - - fn set(&self, offset: u32, val: &[u8]) -> Result<(), Error> { - let result = sandbox::memory_set( - self.handle.memory_idx, - offset, - val.as_ptr() as _, - val.len() as u32, - ); - match result { - env::ERR_OK => Ok(()), - env::ERR_OUT_OF_BOUNDS => Err(Error::OutOfBounds), - _ => unreachable!(), - } - } -} - -/// A builder for the environment of the sandboxed WASM module. -pub struct EnvironmentDefinitionBuilder { - env_def: env::EnvironmentDefinition, - retained_memories: Vec, - _marker: marker::PhantomData, -} - -impl EnvironmentDefinitionBuilder { - fn add_entry(&mut self, module: N1, field: N2, extern_entity: env::ExternEntity) - where - N1: Into>, - N2: Into>, - { - let entry = env::Entry { - module_name: module.into(), - field_name: field.into(), - entity: extern_entity, - }; - self.env_def.entries.push(entry); - } -} - -impl super::SandboxEnvironmentBuilder for EnvironmentDefinitionBuilder { - fn new() -> EnvironmentDefinitionBuilder { - EnvironmentDefinitionBuilder { - env_def: env::EnvironmentDefinition { entries: Vec::new() }, - retained_memories: Vec::new(), - _marker: marker::PhantomData::, - } - } - - fn add_host_func(&mut self, module: N1, field: N2, f: HostFuncType) - where - N1: Into>, - N2: Into>, - { - let f = env::ExternEntity::Function(f as u32); - self.add_entry(module, field, f); - } - - fn add_memory(&mut self, module: N1, field: N2, mem: Memory) - where - N1: Into>, - N2: Into>, - { - // We need to retain memory to keep it alive while the EnvironmentDefinitionBuilder alive. - self.retained_memories.push(mem.clone()); - - let mem = env::ExternEntity::Memory(mem.handle.memory_idx as u32); - self.add_entry(module, field, mem); - } -} - -/// Sandboxed instance of a WASM module. -pub struct Instance { - instance_idx: u32, - _retained_memories: Vec, - _marker: marker::PhantomData, -} - -/// The primary responsibility of this thunk is to deserialize arguments and -/// call the original function, specified by the index. -extern "C" fn dispatch_thunk( - serialized_args_ptr: *const u8, - serialized_args_len: usize, - state: usize, - f: ffi::HostFuncIndex, -) -> u64 { - let serialized_args = unsafe { - if serialized_args_len == 0 { - &[] - } else { - slice::from_raw_parts(serialized_args_ptr, serialized_args_len) - } - }; - let args = Vec::::decode(&mut &serialized_args[..]).expect( - "serialized args should be provided by the runtime; - correctly serialized data should be deserializable; - qed", - ); - - unsafe { - // This should be safe since `coerce_host_index_to_func` is called with an argument - // received in an `dispatch_thunk` implementation, so `f` should point - // on a valid host function. - let f = ffi::coerce_host_index_to_func(f); - - // This should be safe since mutable reference to T is passed upon the invocation. - let state = &mut *(state as *mut T); - - // Pass control flow to the designated function. - let result = f(state, &args).encode(); - - // Leak the result vector and return the pointer to return data. - let result_ptr = result.as_ptr() as u64; - let result_len = result.len() as u64; - mem::forget(result); - - (result_ptr << 32) | result_len - } -} - -impl super::SandboxInstance for Instance { - type Memory = Memory; - type EnvironmentBuilder = EnvironmentDefinitionBuilder; - - fn new( - code: &[u8], - env_def_builder: &EnvironmentDefinitionBuilder, - state: &mut T, - ) -> Result, Error> { - let serialized_env_def: Vec = env_def_builder.env_def.encode(); - // It's very important to instantiate thunk with the right type. - let dispatch_thunk = dispatch_thunk::; - let result = sandbox::instantiate( - dispatch_thunk as u32, - code, - &serialized_env_def, - state as *const T as _, - ); - - let instance_idx = match result { - env::ERR_MODULE => return Err(Error::Module), - env::ERR_EXECUTION => return Err(Error::Execution), - instance_idx => instance_idx, - }; - - // We need to retain memories to keep them alive while the Instance is alive. - let retained_memories = env_def_builder.retained_memories.clone(); - Ok(Instance { - instance_idx, - _retained_memories: retained_memories, - _marker: marker::PhantomData::, - }) - } - - fn invoke(&mut self, name: &str, args: &[Value], state: &mut T) -> Result { - let serialized_args = args.to_vec().encode(); - let mut return_val = vec![0u8; ReturnValue::ENCODED_MAX_SIZE]; - - let result = sandbox::invoke( - self.instance_idx, - name, - &serialized_args, - return_val.as_mut_ptr() as _, - return_val.len() as u32, - state as *const T as _, - ); - - match result { - env::ERR_OK => { - let return_val = - ReturnValue::decode(&mut &return_val[..]).map_err(|_| Error::Execution)?; - Ok(return_val) - }, - env::ERR_EXECUTION => Err(Error::Execution), - _ => unreachable!(), - } - } - - fn get_global_val(&self, name: &str) -> Option { - sandbox::get_global_val(self.instance_idx, name) - } -} - -impl Drop for Instance { - fn drop(&mut self) { - sandbox::instance_teardown(self.instance_idx); - } -} diff --git a/primitives/sandbox/src/lib.rs b/primitives/sandbox/src/lib.rs deleted file mode 100644 index b6b4a5a97da8c..0000000000000 --- a/primitives/sandbox/src/lib.rs +++ /dev/null @@ -1,190 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! This crate provides means to instantiate and execute wasm modules. -//! -//! It works even when the user of this library executes from -//! inside the wasm VM. In this case the same VM is used for execution -//! of both the sandbox owner and the sandboxed module, without compromising security -//! and without the performance penalty of full wasm emulation inside wasm. -//! -//! This is achieved by using bindings to the wasm VM, which are published by the host API. -//! This API is thin and consists of only a handful functions. It contains functions for -//! instantiating modules and executing them, but doesn't contain functions for inspecting the -//! module structure. The user of this library is supposed to read the wasm module. -//! -//! When this crate is used in the `std` environment all these functions are implemented by directly -//! calling the wasm VM. -//! -//! Examples of possible use-cases for this library are not limited to the following: -//! -//! - implementing smart-contract runtimes that use wasm for contract code -//! - executing a wasm substrate runtime inside of a wasm parachain - -#![warn(missing_docs)] -#![cfg_attr(not(feature = "std"), no_std)] - -extern crate alloc; - -pub mod embedded_executor; -pub mod env; -#[cfg(not(feature = "std"))] -pub mod host_executor; - -use sp_core::RuntimeDebug; -use sp_std::prelude::*; - -pub use sp_wasm_interface::{ReturnValue, Value}; - -#[cfg(not(all(feature = "wasmer-sandbox", not(feature = "std"))))] -pub use self::embedded_executor as default_executor; -pub use self::env::HostError; -#[cfg(all(feature = "wasmer-sandbox", not(feature = "std")))] -pub use self::host_executor as default_executor; - -/// The target used for logging. -const TARGET: &str = "runtime::sandbox"; - -/// Error that can occur while using this crate. -#[derive(RuntimeDebug)] -pub enum Error { - /// Module is not valid, couldn't be instantiated. - Module, - - /// Access to a memory or table was made with an address or an index which is out of bounds. - /// - /// Note that if wasm module makes an out-of-bounds access then trap will occur. - OutOfBounds, - - /// Failed to invoke the start function or an exported function for some reason. - Execution, -} - -impl From for HostError { - fn from(_e: Error) -> HostError { - HostError - } -} - -/// Function pointer for specifying functions by the -/// supervisor in [`EnvironmentDefinitionBuilder`]. -/// -/// [`EnvironmentDefinitionBuilder`]: struct.EnvironmentDefinitionBuilder.html -pub type HostFuncType = fn(&mut T, &[Value]) -> Result; - -/// Reference to a sandboxed linear memory, that -/// will be used by the guest module. -/// -/// The memory can't be directly accessed by supervisor, but only -/// through designated functions [`get`](SandboxMemory::get) and [`set`](SandboxMemory::set). -pub trait SandboxMemory: Sized + Clone { - /// Construct a new linear memory instance. - /// - /// The memory allocated with initial number of pages specified by `initial`. - /// Minimal possible value for `initial` is 0 and maximum possible is `65536`. - /// (Since maximum addressable memory is 232 = 4GiB = 65536 * 64KiB). - /// - /// It is possible to limit maximum number of pages this memory instance can have by specifying - /// `maximum`. If not specified, this memory instance would be able to allocate up to 4GiB. - /// - /// Allocated memory is always zeroed. - fn new(initial: u32, maximum: Option) -> Result; - - /// Read a memory area at the address `ptr` with the size of the provided slice `buf`. - /// - /// Returns `Err` if the range is out-of-bounds. - fn get(&self, ptr: u32, buf: &mut [u8]) -> Result<(), Error>; - - /// Write a memory area at the address `ptr` with contents of the provided slice `buf`. - /// - /// Returns `Err` if the range is out-of-bounds. - fn set(&self, ptr: u32, value: &[u8]) -> Result<(), Error>; -} - -/// Struct that can be used for defining an environment for a sandboxed module. -/// -/// The sandboxed module can access only the entities which were defined and passed -/// to the module at the instantiation time. -pub trait SandboxEnvironmentBuilder: Sized { - /// Construct a new `EnvironmentDefinitionBuilder`. - fn new() -> Self; - - /// Register a host function in this environment definition. - /// - /// NOTE that there is no constraints on type of this function. An instance - /// can import function passed here with any signature it wants. It can even import - /// the same function (i.e. with same `module` and `field`) several times. It's up to - /// the user code to check or constrain the types of signatures. - fn add_host_func(&mut self, module: N1, field: N2, f: HostFuncType) - where - N1: Into>, - N2: Into>; - - /// Register a memory in this environment definition. - fn add_memory(&mut self, module: N1, field: N2, mem: Memory) - where - N1: Into>, - N2: Into>; -} - -/// Sandboxed instance of a wasm module. -/// -/// This instance can be used for invoking exported functions. -pub trait SandboxInstance: Sized { - /// The memory type used for this sandbox. - type Memory: SandboxMemory; - - /// The environment builder used to construct this sandbox. - type EnvironmentBuilder: SandboxEnvironmentBuilder; - - /// Instantiate a module with the given [`EnvironmentDefinitionBuilder`]. It will - /// run the `start` function (if it is present in the module) with the given `state`. - /// - /// Returns `Err(Error::Module)` if this module can't be instantiated with the given - /// environment. If execution of `start` function generated a trap, then `Err(Error::Execution)` - /// will be returned. - /// - /// [`EnvironmentDefinitionBuilder`]: struct.EnvironmentDefinitionBuilder.html - fn new( - code: &[u8], - env_def_builder: &Self::EnvironmentBuilder, - state: &mut State, - ) -> Result; - - /// Invoke an exported function with the given name. - /// - /// # Errors - /// - /// Returns `Err(Error::Execution)` if: - /// - /// - An export function name isn't a proper utf8 byte sequence, - /// - This module doesn't have an exported function with the given name, - /// - If types of the arguments passed to the function doesn't match function signature then - /// trap occurs (as if the exported function was called via call_indirect), - /// - Trap occurred at the execution time. - fn invoke( - &mut self, - name: &str, - args: &[Value], - state: &mut State, - ) -> Result; - - /// Get the value from a global with the given `name`. - /// - /// Returns `Some(_)` if the global could be found. - fn get_global_val(&self, name: &str) -> Option; -} diff --git a/primitives/wasm-interface/src/lib.rs b/primitives/wasm-interface/src/lib.rs index 173e3241170fc..1ecff5a0ce91e 100644 --- a/primitives/wasm-interface/src/lib.rs +++ b/primitives/wasm-interface/src/lib.rs @@ -303,9 +303,6 @@ pub trait FunctionContext { fn allocate_memory(&mut self, size: WordSize) -> Result>; /// Deallocate a given memory instance. fn deallocate_memory(&mut self, ptr: Pointer) -> Result<()>; - /// Provides access to the sandbox. - fn sandbox(&mut self) -> &mut dyn Sandbox; - /// Registers a panic error message within the executor. /// /// This is meant to be used in situations where the runtime @@ -330,60 +327,6 @@ pub trait FunctionContext { fn register_panic_error_message(&mut self, message: &str); } -/// Sandbox memory identifier. -pub type MemoryId = u32; - -/// Something that provides access to the sandbox. -pub trait Sandbox { - /// Get sandbox memory from the `memory_id` instance at `offset` into the given buffer. - fn memory_get( - &mut self, - memory_id: MemoryId, - offset: WordSize, - buf_ptr: Pointer, - buf_len: WordSize, - ) -> Result; - /// Set sandbox memory from the given value. - fn memory_set( - &mut self, - memory_id: MemoryId, - offset: WordSize, - val_ptr: Pointer, - val_len: WordSize, - ) -> Result; - /// Delete a memory instance. - fn memory_teardown(&mut self, memory_id: MemoryId) -> Result<()>; - /// Create a new memory instance with the given `initial` size and the `maximum` size. - /// The size is given in wasm pages. - fn memory_new(&mut self, initial: u32, maximum: u32) -> Result; - /// Invoke an exported function by a name. - fn invoke( - &mut self, - instance_id: u32, - export_name: &str, - args: &[u8], - return_val: Pointer, - return_val_len: WordSize, - state: u32, - ) -> Result; - /// Delete a sandbox instance. - fn instance_teardown(&mut self, instance_id: u32) -> Result<()>; - /// Create a new sandbox instance. - fn instance_new( - &mut self, - dispatch_thunk_id: u32, - wasm: &[u8], - raw_env_def: &[u8], - state: u32, - ) -> Result; - - /// Get the value from a global with the given `name`. The sandbox is determined by the - /// given `instance_idx` instance. - /// - /// Returns `Some(_)` when the requested global variable could be found. - fn get_global_val(&self, instance_idx: u32, name: &str) -> Result>; -} - if_wasmtime_is_enabled! { /// A trait used to statically register host callbacks with the WASM executor, /// so that they call be called from within the runtime with minimal overhead. diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index c38eac45d7ba4..90b43100bcdb8 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -143,25 +143,11 @@ cargo-check-try-runtime: - time cargo check --locked --features try-runtime - rusty-cachier cache upload -cargo-check-wasmer-sandbox: - stage: test - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: cargo-check-try-runtime - artifacts: false - extends: - - .docker-env - - .test-refs - script: - - rusty-cachier snapshot create - - time cargo check --locked --features wasmer-sandbox - - rusty-cachier cache upload - test-deterministic-wasm: stage: test # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs needs: - - job: cargo-check-wasmer-sandbox + - job: cargo-check-try-runtime artifacts: false extends: - .docker-env @@ -375,27 +361,6 @@ test-full-crypto-feature: - time cargo +nightly build --locked --verbose --no-default-features --features full_crypto - rusty-cachier cache upload -test-wasmer-sandbox: - stage: test - needs: - - job: cargo-check-wasmer-sandbox - artifacts: false - extends: - - .docker-env - - .test-refs-wasmer-sandbox - variables: - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - RUST_BACKTRACE: 1 - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - CI_JOB_NAME: "test-wasmer-sandbox" - parallel: 3 - script: - - rusty-cachier snapshot create - - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" - - time cargo nextest run --locked --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} - - if [ ${CI_NODE_INDEX} == 1 ]; then rusty-cachier cache upload; fi - check-rustdoc: stage: test variables: From 0a27e54514338b71204e7321192fbd32dae3b950 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Wed, 7 Dec 2022 14:57:41 +0100 Subject: [PATCH 1446/1472] bench assert update (#12866) --- frame/referenda/src/benchmarking.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index b82ac5b3bdfe3..e57b5f9859e5b 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -274,7 +274,8 @@ benchmarks_instance_pallet! { verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, None, _))); let new_balance = T::Currency::free_balance(&caller); - assert!(new_balance > balance); + // the deposit is zero or make sure it was unreserved. + assert!(T::SubmissionDeposit::get().is_zero() || new_balance > balance); } cancel { From b99f2bc9c912261c64133ac5a3cb698a678beaa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Wed, 7 Dec 2022 15:08:48 -0300 Subject: [PATCH 1447/1472] Implement crate publishing on CI (#12768) * implement crate publishing from CI * fix indentation * use resource_group for job exclusivity ensure that at most one instance of the publish-crates job is running at any given time to prevent race conditions * correct publish = false * Remove YAML anchors as GitLab's `extends:` doesn't need it * Temporarily force cache upload for the new jobs * Revert `RUSTY_CACHIER_FORCE_UPLOAD` * pin libp2p-tcp=0.37.0 for sc-telemetry * Revert "pin libp2p-tcp=0.37.0 for sc-telemetry" This reverts commit 29146bfad6c31e8cf0e2f17ad92a71bb81a373af. * always collect generated crates * increase timeout for publish-crates-template * Force upload the new job cache again * Revert "Force upload the new job cache again" This reverts commit 5a5feee1b2c51fdef768b25a76be4c3949ec1c99. * reformat * improve timeout explanation * s/usual/average Co-authored-by: Vladimir Istyufeev --- .gitlab-ci.yml | 19 +++++++++ Cargo.lock | 1 + Cargo.toml | 9 +++++ bin/node/bench/Cargo.toml | 1 + bin/node/cli/Cargo.toml | 1 + bin/node/executor/Cargo.toml | 1 + bin/node/inspect/Cargo.toml | 1 + bin/node/primitives/Cargo.toml | 1 + bin/node/rpc/Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 1 + bin/node/testing/Cargo.toml | 2 +- client/merkle-mountain-range/rpc/Cargo.toml | 1 - client/network/bitswap/Cargo.toml | 1 - client/network/common/Cargo.toml | 1 - client/network/light/Cargo.toml | 1 - client/network/sync/Cargo.toml | 1 - client/network/transactions/Cargo.toml | 1 - client/sync-state-rpc/Cargo.toml | 1 - frame/bags-list/Cargo.toml | 1 - frame/bags-list/fuzzer/Cargo.toml | 1 - frame/bags-list/remote-tests/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 1 - frame/election-provider-support/Cargo.toml | 1 - frame/fast-unstake/Cargo.toml | 5 ++- frame/lottery/Cargo.toml | 1 - .../nomination-pools/benchmarking/Cargo.toml | 3 +- .../nomination-pools/test-staking/Cargo.toml | 1 + frame/preimage/Cargo.toml | 1 - frame/root-testing/Cargo.toml | 1 + frame/staking/Cargo.toml | 3 +- frame/state-trie-migration/Cargo.toml | 1 - .../asset-tx-payment/Cargo.toml | 2 + frame/try-runtime/Cargo.toml | 1 - frame/whitelist/Cargo.toml | 1 - primitives/beefy/Cargo.toml | 1 - primitives/weights/Cargo.toml | 1 - scripts/ci/gitlab/pipeline/publish.yml | 38 ++++++++++++++++++ scripts/ci/gitlab/pipeline/test.yml | 13 +++++++ scripts/ci/node-template-release/Cargo.toml | 1 + test-utils/Cargo.toml | 1 + test-utils/client/Cargo.toml | 1 + test-utils/derive/Cargo.toml | 1 + utils/frame/generate-bags/Cargo.toml | 1 - .../generate-bags/node-runtime/Cargo.toml | 2 +- utils/frame/remote-externalities/Cargo.toml | 1 - utils/frame/rpc/client/Cargo.toml | 1 - utils/frame/try-runtime/cli/Cargo.toml | 1 - utils/wasm-builder/src/wasm_project.rs | 39 +++++++++++++++---- 48 files changed, 137 insertions(+), 36 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5b6748155444d..0a686b06e9c73 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -180,6 +180,25 @@ default: # this job runs only on nightly pipeline with the mentioned variable, against `master` branch - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "schedule" && $PIPELINE == "nightly" +.crates-publishing-template: + stage: test + extends: .docker-env + # collect artifacts even on failure so that we know how the crates were generated (they'll be + # generated to the artifacts folder according to SPUB_TMP further down) + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + when: always + expire_in: 7 days + paths: + - artifacts/ + variables: + CRATESIO_API: https://crates.io/api + CRATESIO_CRATES_OWNER: parity-crate-owner + GH_API: https://api.github.com + REPO: substrate + REPO_OWNER: paritytech + SPUB_TMP: artifacts + #### stage: .pre skip-if-draft: diff --git a/Cargo.lock b/Cargo.lock index f2b394e099381..73effefc48da1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5189,6 +5189,7 @@ dependencies = [ "frame-support", "frame-system", "log", + "pallet-assets", "pallet-balances", "pallet-staking", "pallet-staking-reward-curve", diff --git a/Cargo.toml b/Cargo.toml index 64ceb104c649c..12f2ced0d1d03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "bin/node/bench", "bin/node/cli", "bin/node/executor", + "bin/node/inspect", "bin/node/primitives", "bin/node/rpc", "bin/node/runtime", @@ -39,11 +40,13 @@ members = [ "client/executor/wasmi", "client/executor/wasmtime", "client/finality-grandpa", + "client/finality-grandpa/rpc", "client/informant", "client/keystore", "client/merkle-mountain-range", "client/merkle-mountain-range/rpc", "client/network", + "client/network/transactions", "client/network-gossip", "client/network/bitswap", "client/network/common", @@ -88,11 +91,13 @@ members = [ "frame/child-bounties", "frame/collective", "frame/contracts", + "frame/contracts/proc-macro", "frame/contracts/primitives", "frame/conviction-voting", "frame/democracy", "frame/fast-unstake", "frame/try-runtime", + "frame/elections-phragmen", "frame/election-provider-multi-phase", "frame/election-provider-support", "frame/election-provider-support/benchmarking", @@ -113,6 +118,7 @@ members = [ "frame/nicks", "frame/node-authorization", "frame/offences", + "frame/offences/benchmarking", "frame/preimage", "frame/proxy", "frame/nomination-pools", @@ -143,6 +149,7 @@ members = [ "frame/support/procedural/tools/derive", "frame/support/test", "frame/support/test/compile_pass", + "frame/support/test/pallet", "frame/system", "frame/system/benchmarking", "frame/system/rpc/runtime-api", @@ -174,6 +181,7 @@ members = [ "primitives/consensus/babe", "primitives/consensus/common", "primitives/consensus/pow", + "primitives/consensus/slots", "primitives/consensus/vrf", "primitives/core", "primitives/core/hashing", @@ -215,6 +223,7 @@ members = [ "primitives/version/proc-macro", "primitives/wasm-interface", "primitives/weights", + "test-utils", "test-utils/client", "test-utils/derive", "test-utils/runtime", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 63087215ae192..265de731de690 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index cb2baf9e0de30..2ca37e7febe16 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -9,6 +9,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" default-run = "substrate" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" +publish = false [package.metadata.wasm-pack.profile.release] # `wasm-opt` has some problems on linux, see diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index c814813d0ac1b..8b3add78a9a26 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index 2b53805a6506b..a7343b3ca827f 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 9be1efd625f50..1aa0a8f0e27a3 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index a1f37e137ca1f..9d2810413613f 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 706d2c7720e2f..02a2ae292d83e 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -8,6 +8,7 @@ build = "build.rs" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 694472123647a..0154a778457fc 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" -publish = true +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/client/merkle-mountain-range/rpc/Cargo.toml b/client/merkle-mountain-range/rpc/Cargo.toml index abbf10c1b7f52..ca14544000bdb 100644 --- a/client/merkle-mountain-range/rpc/Cargo.toml +++ b/client/merkle-mountain-range/rpc/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Node-specific RPC methods for interaction with Merkle Mountain Range pallet." -publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/client/network/bitswap/Cargo.toml b/client/network/bitswap/Cargo.toml index 02e12e8f91653..099b5cd5e88b2 100644 --- a/client/network/bitswap/Cargo.toml +++ b/client/network/bitswap/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-network-bitswap" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index bf4a89c70b88c..545ae8a8af514 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-network-sync" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index c7ec6eda7a70b..5b84a0adde20f 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-network-light" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 263c2d40c2273..086ab3c30cc25 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-network-sync" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml index 147a86d8de2ae..cb45abca02f6a 100644 --- a/client/network/transactions/Cargo.toml +++ b/client/network/transactions/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-network-transactions" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index d4e8222911219..9730eb56e9bd6 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 10086635ef08f..52dd14b7d01c8 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet bags list" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/frame/bags-list/fuzzer/Cargo.toml b/frame/bags-list/fuzzer/Cargo.toml index 0f10077dcbce8..fc2334bea5ca7 100644 --- a/frame/bags-list/fuzzer/Cargo.toml +++ b/frame/bags-list/fuzzer/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Fuzzer for FRAME pallet bags list" -readme = "README.md" publish = false [dependencies] diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 941076753b4cf..9fb6d0154b302 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -7,7 +7,7 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet bags list remote test" -readme = "README.md" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index ba460055e2358..42cd682a0ff02 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "PALLET two phase election providers" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 754aa8d37aee3..b9584c899e1b1 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "election provider supporting traits" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml index c48ff862b7dfe..61bc823cc11e5 100644 --- a/frame/fast-unstake/Cargo.toml +++ b/frame/fast-unstake/Cargo.toml @@ -7,7 +7,6 @@ license = "Unlicense" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME fast unstake pallet" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -26,7 +25,10 @@ sp-std = { version = "5.0.0", default-features = false, path = "../../primitives sp-staking = { default-features = false, path = "../../primitives/staking" } frame-election-provider-support = { default-features = false, path = "../election-provider-support" } +# optional dependencies for cargo features frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +pallet-staking = { default-features = false, optional = true, path = "../staking" } +pallet-assets = { default-features = false, optional = true, path = "../assets" } [dev-dependencies] pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } @@ -36,6 +38,7 @@ sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } pallet-staking = { path = "../staking" } pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } +pallet-assets = { path = "../assets" } [features] diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 14ec21a563cba..9ac69d63eb983 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME Participation Lottery Pallet" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/frame/nomination-pools/benchmarking/Cargo.toml b/frame/nomination-pools/benchmarking/Cargo.toml index ac470f04a6195..be52d9777ac86 100644 --- a/frame/nomination-pools/benchmarking/Cargo.toml +++ b/frame/nomination-pools/benchmarking/Cargo.toml @@ -31,6 +31,7 @@ sp-runtime = { version = "7.0.0", default-features = false, path = "../../../pri sp-runtime-interface = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime-interface" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } +sp-io = { optional = true, default-features = false, path = "../../../primitives/io" } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } @@ -54,7 +55,7 @@ std = [ "sp-runtime-interface/std", "sp-io/std", "sp-staking/std", - "sp-std/std", + "sp-std/std", ] runtime-benchmarks = [ diff --git a/frame/nomination-pools/test-staking/Cargo.toml b/frame/nomination-pools/test-staking/Cargo.toml index 8350fdd05c8cd..a45c7852d4151 100644 --- a/frame/nomination-pools/test-staking/Cargo.toml +++ b/frame/nomination-pools/test-staking/Cargo.toml @@ -7,6 +7,7 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME nomination pools pallet tests with the staking pallet" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 3315405809491..def39d61d5175 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for storing preimages of hashes" -readme = "README.md" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/frame/root-testing/Cargo.toml b/frame/root-testing/Cargo.toml index bc474f4f09c5f..4d3f70c5d0d9f 100644 --- a/frame/root-testing/Cargo.toml +++ b/frame/root-testing/Cargo.toml @@ -8,6 +8,7 @@ homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME root testing pallet" readme = "README.md" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 466883f868bc0..3ad63ad94a08a 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -32,9 +32,10 @@ sp-application-crypto = { version = "7.0.0", default-features = false, path = ". frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } log = { version = "0.4.17", default-features = false } -# Optional imports for benchmarking +# optional dependencies for cargo features frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } rand_chacha = { version = "0.2", default-features = false, optional = true } +pallet-bags-list = { default-features = false, optional = true, path = "../bags-list" } [dev-dependencies] sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index 8d10a34077230..90c8f426d0e10 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet migration of trie" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index cfc56c91effd1..b192c4e9cd96e 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -19,10 +19,12 @@ sp-io = { version = "7.0.0", default-features = false, path = "../../../primitiv sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } +# optional dependencies for cargo features frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = ".." } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true } +pallet-assets = { default-features = false, optional = true, path = "../../assets" } # Other dependencies codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index 247505e6130ab..87aca0d1ed9f0 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for democracy" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/frame/whitelist/Cargo.toml b/frame/whitelist/Cargo.toml index 94fd0db0077b1..f3f44d3187a8e 100644 --- a/frame/whitelist/Cargo.toml +++ b/frame/whitelist/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for whitelisting call, and dispatch from specific origin" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index a7ff212a09e81..b286d9878b44e 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate" description = "Primitives for BEEFY protocol." -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/primitives/weights/Cargo.toml b/primitives/weights/Cargo.toml index 501a2c3b0a19d..00996458362fe 100644 --- a/primitives/weights/Cargo.toml +++ b/primitives/weights/Cargo.toml @@ -8,7 +8,6 @@ homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Types and traits for interfacing between the host and the wasm runtime." documentation = "https://docs.rs/sp-wasm-interface" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 9d242d8fb5759..74d2adb3f4675 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -161,3 +161,41 @@ update-node-template: --template-path "bin/node-template" --github-api-token "$GITHUB_TOKEN" --polkadot-branch "$CI_COMMIT_REF_NAME" + +.publish-crates-template: + stage: publish + extends: .crates-publishing-template + # We don't want multiple jobs racing to publish crates as it's redundant and they might overwrite + # the releases of one another. Use resource_group to ensure that at most one instance of this job + # is running at any given time. + resource_group: crates-publishing + variables: + # crates.io rate limits crates publishing by 1 per minute, so a delay needs to be inserted + # slightly higher than that after publishing each crate. The value is specified in seconds. + SPUB_AFTER_PUBLISH_DELAY: 64 + # We might have to publish lots of crates at a time. Given the 1 minute delay introduced above and + # taking into account the 202 (as of Dec 07, 2022) publishable Substrate crates, that would equate + # to roughly 202 minutes of delay, or 3h and 22 minutes. As such, the job needs to have a much + # higher timeout than average. + timeout: 5h + script: + - rusty-cachier snapshot create + - git clone + --depth 1 + --branch "$RELENG_SCRIPTS_BRANCH" + https://github.com/paritytech/releng-scripts.git + - CRATESIO_TARGET_INSTANCE=default ./releng-scripts/publish-crates + - rusty-cachier cache upload + +publish-crates: + extends: .publish-crates-template + needs: + - job: publish-crates-locally + artifacts: false + rules: + - if: $CI_COMMIT_REF_NAME == "master" + +publish-crates-manual: + extends: .publish-crates-template + when: manual + allow_failure: true diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 90b43100bcdb8..ea1240af8bd57 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -394,6 +394,19 @@ cargo-check-each-crate: - if [ "$CI_NODE_INDEX" == 1 ]; then rusty-cachier cache upload; fi parallel: 2 +publish-crates-locally: + extends: + - .test-refs + - .crates-publishing-template + script: + - rusty-cachier snapshot create + - git clone + --depth 1 + --branch "$RELENG_SCRIPTS_BRANCH" + https://github.com/paritytech/releng-scripts.git + - CRATESIO_TARGET_INSTANCE=local ./releng-scripts/publish-crates + - rusty-cachier cache upload + cargo-check-each-crate-macos: stage: test extends: diff --git a/scripts/ci/node-template-release/Cargo.toml b/scripts/ci/node-template-release/Cargo.toml index 0800b17536453..668e0f3f62a7f 100644 --- a/scripts/ci/node-template-release/Cargo.toml +++ b/scripts/ci/node-template-release/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Parity Technologies "] edition = "2021" license = "GPL-3.0" homepage = "https://substrate.io" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index c7201da23ab17..cd4839fa1cbd7 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -7,6 +7,7 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate test utilities" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 2c61f4d3ce2ed..106ec21d79464 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "substrate-test-client" +description = "Client testing utilities" version = "2.0.1" authors = ["Parity Technologies "] edition = "2021" diff --git a/test-utils/derive/Cargo.toml b/test-utils/derive/Cargo.toml index 4494b55220ef2..b55ace822ceb3 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -7,6 +7,7 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Substrate test utilities macros" +publish = false [dependencies] proc-macro-crate = "1.1.3" diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 0f3ff31756bba..04d598c7843c4 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Bag threshold generation script for pallet-bag-list" -readme = "README.md" [dependencies] # FRAME diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml index 6cc14a0595501..46d999daba9cf 100644 --- a/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -7,7 +7,7 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Bag threshold generation script for pallet-bag-list and kitchensink-runtime." -readme = "README.md" +publish = false [dependencies] kitchensink-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runtime" } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index a39dc9d3866cc..4cb847867f374 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "An externalities provided environment that can load itself from remote nodes or cached files" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/utils/frame/rpc/client/Cargo.toml b/utils/frame/rpc/client/Cargo.toml index 371996a4edfd3..bbe8879818092 100644 --- a/utils/frame/rpc/client/Cargo.toml +++ b/utils/frame/rpc/client/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Shared JSON-RPC client" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index acac966aa1a58..2b095fc9419b9 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "Cli command runtime testing and dry-running" -readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 07219676413fc..7688069dd7cca 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -365,26 +365,47 @@ fn create_project_cargo_toml( ); } -/// Find a package by the given `manifest_path` in the metadata. +/// Find a package by the given `manifest_path` in the metadata. In case it can't be found by its +/// manifest_path, fallback to finding it by name; this is necessary during publish because the +/// package's manifest path will be *generated* within a specific packaging directory, thus it won't +/// be found by its original path anymore. /// /// Panics if the package could not be found. fn find_package_by_manifest_path<'a>( + pkg_name: &str, manifest_path: &Path, crate_metadata: &'a cargo_metadata::Metadata, ) -> &'a cargo_metadata::Package { - crate_metadata + if let Some(pkg) = crate_metadata.packages.iter().find(|p| p.manifest_path == manifest_path) { + return pkg + } + let pkgs_by_name = crate_metadata .packages .iter() - .find(|p| p.manifest_path == manifest_path) - .expect("Wasm project exists in its own metadata; qed") + .filter(|p| p.name == pkg_name) + .collect::>(); + let mut pkgs = pkgs_by_name.iter(); + if let Some(pkg) = pkgs.next() { + if pkgs.next().is_some() { + panic!( + "Found multiple packages matching the name {pkg_name} ({manifest_path:?}): {:?}", + pkgs_by_name + ); + } else { + return pkg + } + } else { + panic!("Failed to find entry for package {pkg_name} ({manifest_path:?})"); + } } /// Get a list of enabled features for the project. fn project_enabled_features( + pkg_name: &str, cargo_manifest: &Path, crate_metadata: &cargo_metadata::Metadata, ) -> Vec { - let package = find_package_by_manifest_path(cargo_manifest, crate_metadata); + let package = find_package_by_manifest_path(pkg_name, cargo_manifest, crate_metadata); let std_enabled = package.features.get("std"); @@ -427,10 +448,11 @@ fn project_enabled_features( /// Returns if the project has the `runtime-wasm` feature fn has_runtime_wasm_feature_declared( + pkg_name: &str, cargo_manifest: &Path, crate_metadata: &cargo_metadata::Metadata, ) -> bool { - let package = find_package_by_manifest_path(cargo_manifest, crate_metadata); + let package = find_package_by_manifest_path(pkg_name, cargo_manifest, crate_metadata); package.features.keys().any(|k| k == "runtime-wasm") } @@ -455,9 +477,10 @@ fn create_project( fs::create_dir_all(wasm_project_folder.join("src")) .expect("Wasm project dir create can not fail; qed"); - let mut enabled_features = project_enabled_features(project_cargo_toml, crate_metadata); + let mut enabled_features = + project_enabled_features(&crate_name, project_cargo_toml, crate_metadata); - if has_runtime_wasm_feature_declared(project_cargo_toml, crate_metadata) { + if has_runtime_wasm_feature_declared(&crate_name, project_cargo_toml, crate_metadata) { enabled_features.push("runtime-wasm".into()); } From 6e73c85b7ddbc2ec2a9f6629ddc06aca2f83bcf3 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 7 Dec 2022 23:44:40 +0100 Subject: [PATCH 1448/1472] zombienet: warp-sync integration test added (#12675) * zombienet: warp-sync integration test added * spelling * Readme corrected * dir name updated * Check second phase of warp sync * zombienet pipeline enable + naive test network * zombienet stage added * paritypr/substrate-debug image added for zombienet testing * debugs added * debugs added * buildah problem fixed * rollback * runner tag * test name corrected * dir renamed (regex problem) * common code clean up * common code clean up * fix * warp sync test improvements * full sha used as short is too short (https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/2051228#L38) * disable tracing for nodes * COMMON_USER -> DOCKERIO_USER * refs reworked * paritypr/substrate image used * DOCKERIO -> DOCKER * generate-ws-db toml cleanup * improvements * fix * raw chain spec used * zombienet v1.3.18 used * zombienet: warp sync test enabled * chain-spec path corrected * log parsing improved Checking if log does not container error or verification failed messages * warp sync test: removed validators * fix * review remarks applied * dir test name changed: 0000_block_building -> 0000-block-building * transaction finalized test added * transaction finalized test: error handling improved * trigger CI job * trigger CI job * trigger CI job * trigger CI job * Explicitly touch `version.rs` to invalidate the related cache * zombienet add logs as artifacts * Revert "Explicitly touch `version.rs` to invalidate the related cache" This reverts commit 9d00ccfe897a280581156c281961a32665dba6d5. * file naming changed Co-authored-by: parity-processbot <> Co-authored-by: Vladimir Istyufeev Co-authored-by: Javier Viola --- .gitlab-ci.yml | 18 ++ scripts/ci/docker/subkey.Dockerfile | 3 +- scripts/ci/docker/substrate.Dockerfile | 3 +- scripts/ci/gitlab/pipeline/build.yml | 2 +- scripts/ci/gitlab/pipeline/publish.yml | 51 ++++- scripts/ci/gitlab/pipeline/zombienet.yml | 53 +++++ .../0000-block-building/block-building.toml | 15 ++ .../0000-block-building/block-building.zndsl | 20 ++ .../transaction-gets-finalized.js | 59 ++++++ zombienet/0001-basic-warp-sync/README.md | 101 +++++++++ .../0001-basic-warp-sync/chain-spec.json | 192 ++++++++++++++++++ .../generate-warp-sync-database.toml | 17 ++ .../0001-basic-warp-sync/test-warp-sync.toml | 30 +++ .../0001-basic-warp-sync/test-warp-sync.zndsl | 35 ++++ 14 files changed, 587 insertions(+), 12 deletions(-) create mode 100644 scripts/ci/gitlab/pipeline/zombienet.yml create mode 100644 zombienet/0000-block-building/block-building.toml create mode 100644 zombienet/0000-block-building/block-building.zndsl create mode 100644 zombienet/0000-block-building/transaction-gets-finalized.js create mode 100644 zombienet/0001-basic-warp-sync/README.md create mode 100644 zombienet/0001-basic-warp-sync/chain-spec.json create mode 100644 zombienet/0001-basic-warp-sync/generate-warp-sync-database.toml create mode 100644 zombienet/0001-basic-warp-sync/test-warp-sync.toml create mode 100644 zombienet/0001-basic-warp-sync/test-warp-sync.zndsl diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0a686b06e9c73..25d61cf349615 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -33,6 +33,7 @@ stages: - test - build - publish + - zombienet - deploy - notify @@ -52,6 +53,7 @@ variables: BUILDAH_IMAGE: "quay.io/buildah/stable:v1.27" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.22" default: retry: @@ -166,7 +168,17 @@ default: - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs +.publish-refs: + rules: + - if: $CI_PIPELINE_SOURCE == "pipeline" + when: never + - if: $CI_PIPELINE_SOURCE == "web" + - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_COMMIT_REF_NAME == "master" + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + .build-refs: + # publish-refs + PRs rules: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never @@ -174,6 +186,10 @@ default: - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + +.zombienet-refs: + extends: .build-refs .nightly-pipeline: rules: @@ -224,6 +240,8 @@ include: - scripts/ci/gitlab/pipeline/build.yml # publish jobs - scripts/ci/gitlab/pipeline/publish.yml + # zombienet jobs + - scripts/ci/gitlab/pipeline/zombienet.yml #### stage: deploy diff --git a/scripts/ci/docker/subkey.Dockerfile b/scripts/ci/docker/subkey.Dockerfile index 3483502845cf5..a24595d915a1a 100644 --- a/scripts/ci/docker/subkey.Dockerfile +++ b/scripts/ci/docker/subkey.Dockerfile @@ -3,10 +3,11 @@ FROM docker.io/library/ubuntu:20.04 # metadata ARG VCS_REF ARG BUILD_DATE +ARG IMAGE_NAME LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ - io.parity.image.title="parity/subkey" \ + io.parity.image.title="${IMAGE_NAME}" \ io.parity.image.description="Subkey: key generating utility for Substrate." \ io.parity.image.source="https://github.com/paritytech/substrate/blob/${VCS_REF}/scripts/ci/docker/subkey.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ diff --git a/scripts/ci/docker/substrate.Dockerfile b/scripts/ci/docker/substrate.Dockerfile index b4c103ed5244b..5c7909afc0eec 100644 --- a/scripts/ci/docker/substrate.Dockerfile +++ b/scripts/ci/docker/substrate.Dockerfile @@ -3,10 +3,11 @@ FROM docker.io/library/ubuntu:20.04 # metadata ARG VCS_REF ARG BUILD_DATE +ARG IMAGE_NAME LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ - io.parity.image.title="parity/substrate" \ + io.parity.image.title="${IMAGE_NAME}" \ io.parity.image.description="Substrate: The platform for blockchain innovators." \ io.parity.image.source="https://github.com/paritytech/substrate/blob/${VCS_REF}/scripts/ci/docker/Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 906c1bcbe242e..5bbc3fb8f751c 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -86,7 +86,7 @@ build-linux-substrate: extends: - .collect-artifacts - .docker-env - - .build-refs + - .publish-refs variables: # this variable gets overriden by "rusty-cachier environment inject", use the value as default CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 74d2adb3f4675..9053035a61cdb 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -2,32 +2,33 @@ # This file is part of .gitlab-ci.yml # Here are all jobs that are executed during "publish" stage -.build-push-docker-image: +.build-push-docker-image-common: extends: - - .build-refs - .kubernetes-env + stage: publish variables: CI_IMAGE: $BUILDAH_IMAGE GIT_STRATEGY: none DOCKERFILE: $PRODUCT.Dockerfile - IMAGE_NAME: docker.io/parity/$PRODUCT + IMAGE_NAME: docker.io/$IMAGE_PATH before_script: - cd ./artifacts/$PRODUCT/ - VERSION="$(cat ./VERSION)" - echo "${PRODUCT} version = ${VERSION}" - test -z "${VERSION}" && exit 1 script: - - test "$Docker_Hub_User_Parity" -a "$Docker_Hub_Pass_Parity" || + - test "$DOCKER_USER" -a "$DOCKER_PASS" || ( echo "no docker credentials provided"; exit 1 ) - buildah bud --format=docker --build-arg VCS_REF="${CI_COMMIT_SHA}" --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" + --build-arg IMAGE_NAME="${IMAGE_PATH}" --tag "$IMAGE_NAME:$VERSION" --tag "$IMAGE_NAME:latest" --file "$DOCKERFILE" . - - echo "$Docker_Hub_Pass_Parity" | - buildah login --username "$Docker_Hub_User_Parity" --password-stdin docker.io + - echo "$DOCKER_PASS" | + buildah login --username "$DOCKER_USER" --password-stdin docker.io - buildah info - buildah push --format=v2s2 "$IMAGE_NAME:$VERSION" - buildah push --format=v2s2 "$IMAGE_NAME:latest" @@ -38,8 +39,27 @@ - echo "SUBSTRATE_IMAGE_TAG=${IMAGE_TAG}" | tee -a ./artifacts/$PRODUCT/build.env - cat ./artifacts/$PRODUCT/build.env +.build-push-docker-image: + extends: + - .publish-refs + - .build-push-docker-image-common + variables: + IMAGE_PATH: parity/$PRODUCT + DOCKER_USER: $Docker_Hub_User_Parity + DOCKER_PASS: $Docker_Hub_Pass_Parity + + +# publish image to docker.io/paritypr, (e.g. for later use in zombienet testing) +.build-push-image-temporary: + extends: + - .build-refs + - .build-push-docker-image-common + variables: + IMAGE_PATH: paritypr/$PRODUCT + DOCKER_USER: $PARITYPR_USER + DOCKER_PASS: $PARITYPR_PASS + publish-docker-substrate: - stage: publish extends: .build-push-docker-image needs: - job: build-linux-substrate @@ -47,8 +67,21 @@ publish-docker-substrate: variables: PRODUCT: substrate +publish-docker-substrate-temporary: + extends: .build-push-image-temporary + needs: + - job: build-linux-substrate + artifacts: true + variables: + PRODUCT: substrate + artifacts: + reports: + # this artifact is used in zombienet-tests job + # https://docs.gitlab.com/ee/ci/multi_project_pipelines.html#with-variable-inheritance + dotenv: ./artifacts/$PRODUCT/build.env + expire_in: 24h + publish-docker-subkey: - stage: publish extends: .build-push-docker-image needs: - job: build-subkey-linux @@ -59,7 +92,7 @@ publish-docker-subkey: publish-s3-release: stage: publish extends: - - .build-refs + - .publish-refs - .kubernetes-env needs: - job: build-linux-substrate diff --git a/scripts/ci/gitlab/pipeline/zombienet.yml b/scripts/ci/gitlab/pipeline/zombienet.yml new file mode 100644 index 0000000000000..8d772ff51f9a7 --- /dev/null +++ b/scripts/ci/gitlab/pipeline/zombienet.yml @@ -0,0 +1,53 @@ +# This file is part of .gitlab-ci.yml +# Here are all jobs that are executed during "zombienet" stage + +# common settings for all zombienet jobs +.zombienet-common: + before_script: + - echo "Zombie-net Tests Config" + - echo "${ZOMBIENET_IMAGE}" + - echo "${SUBSTRATE_IMAGE_NAME} ${SUBSTRATE_IMAGE_TAG}" + - echo "${GH_DIR}" + - export DEBUG=zombie,zombie::network-node + - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${SUBSTRATE_IMAGE_NAME}:${SUBSTRATE_IMAGE_TAG} + - echo "${ZOMBIENET_INTEGRATION_TEST_IMAGE}" + stage: zombienet + image: "${ZOMBIENET_IMAGE}" + needs: + - job: publish-docker-substrate-temporary + extends: + - .kubernetes-env + - .zombienet-refs + variables: + GH_DIR: "https://github.com/paritytech/substrate/tree/${CI_COMMIT_SHA}/zombienet" + FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: 1 + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + when: always + expire_in: 2 days + paths: + - ./zombienet-logs + after_script: + - mkdir -p ./zombienet-logs + - cp /tmp/zombie*/logs/* ./zombienet-logs/ + allow_failure: true + retry: 2 + tags: + - zombienet-polkadot-integration-test + +zombienet-0000-block-building: + extends: + - .zombienet-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh + --github-remote-dir="${GH_DIR}/0000-block-building" + --test="block-building.zndsl" + + +zombienet-0001-basic-warp-sync: + extends: + - .zombienet-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh + --github-remote-dir="${GH_DIR}/0001-basic-warp-sync" + --test="test-warp-sync.zndsl" diff --git a/zombienet/0000-block-building/block-building.toml b/zombienet/0000-block-building/block-building.toml new file mode 100644 index 0000000000000..42ebbb58ac1a6 --- /dev/null +++ b/zombienet/0000-block-building/block-building.toml @@ -0,0 +1,15 @@ +[settings] +enable_tracing = false + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +default_command = "substrate" +chain = "local" + + [[relaychain.nodes]] + name = "alice" + validator = true + + [[relaychain.nodes]] + name = "bob" + validator = true diff --git a/zombienet/0000-block-building/block-building.zndsl b/zombienet/0000-block-building/block-building.zndsl new file mode 100644 index 0000000000000..c53e50915c202 --- /dev/null +++ b/zombienet/0000-block-building/block-building.zndsl @@ -0,0 +1,20 @@ +Description: Block building +Network: ./block-building.toml +Creds: config + +alice: is up +bob: is up + +alice: reports node_roles is 4 +bob: reports node_roles is 4 + +alice: reports peers count is at least 1 +bob: reports peers count is at least 1 + +alice: reports block height is at least 5 within 20 seconds +bob: reports block height is at least 5 within 20 seconds + +alice: count of log lines containing "error" is 0 within 2 seconds +bob: count of log lines containing "error" is 0 within 2 seconds + +alice: js-script ./transaction-gets-finalized.js within 30 seconds diff --git a/zombienet/0000-block-building/transaction-gets-finalized.js b/zombienet/0000-block-building/transaction-gets-finalized.js new file mode 100644 index 0000000000000..a38cf603fc57e --- /dev/null +++ b/zombienet/0000-block-building/transaction-gets-finalized.js @@ -0,0 +1,59 @@ +//based on: https://polkadot.js.org/docs/api/examples/promise/transfer-events + +const assert = require("assert"); + +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + // Construct the keyring after the API (crypto has an async init) + const keyring = new zombie.Keyring({ type: "sr25519" }); + + // Add Alice to our keyring with a hard-derivation path (empty phrase, so uses dev) + const alice = keyring.addFromUri('//Alice'); + const bob = '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'; + + // Create a extrinsic, transferring 10^20 units to Bob + const transfer = api.tx.balances.transfer(bob, 10n**20n); + + let transaction_success_event = false; + try { + await new Promise( async (resolve, reject) => { + const unsubscribe = await transfer + .signAndSend(alice, { nonce: -1 }, ({ events = [], status }) => { + console.log('Transaction status:', status.type); + + if (status.isInBlock) { + console.log('Included at block hash', status.asInBlock.toHex()); + console.log('Events:'); + + events.forEach(({ event: { data, method, section }, phase }) => { + console.log('\t', phase.toString(), `: ${section}.${method}`, data.toString()); + + if (section=="system" && method =="ExtrinsicSuccess") { + transaction_success_event = true; + } + }); + } else if (status.isFinalized) { + console.log('Finalized block hash', status.asFinalized.toHex()); + unsubscribe(); + if (transaction_success_event) { + resolve(); + } else { + reject("ExtrinsicSuccess has not been seen"); + } + } else if (status.isError) { + unsubscribe(); + reject("Transaction status.isError"); + } + + }); + }); + } catch (error) { + assert.fail("Transfer promise failed, error: " + error); + } + + assert.ok("test passed"); +} + +module.exports = { run } diff --git a/zombienet/0001-basic-warp-sync/README.md b/zombienet/0001-basic-warp-sync/README.md new file mode 100644 index 0000000000000..7550ca89236fb --- /dev/null +++ b/zombienet/0001-basic-warp-sync/README.md @@ -0,0 +1,101 @@ +# Test design +The `warp-sync` test works on predefined database which is stored in the cloud and +fetched by the test. `alice` and `bob` nodes are spun up using this database snapshot in full node mode. + +As `warp-sync` requires at least 3 peers, the test spawns the `charlie` full node which uses the same database snapshot. + +The `dave` node executed with `--sync warp` syncs database with the rest of the network. + +# How to prepare database +Database was prepared using the following zombienet file (`generate-warp-sync-database.toml`): +``` +[relaychain] +default_image = "docker.io/parity/substrate:master" +default_command = "substrate" + +chain = "gen-db" + +chain_spec_path = "chain-spec.json" + + [[relaychain.nodes]] + name = "alice" + validator = true + + [[relaychain.nodes]] + name = "bob" + validator = true +``` + +The zombienet shall be executed with the following command, and run for some period of time to allow for few grandpa eras. +``` +./zombienet-linux spawn --dir ./db-test-gen --provider native generate-warp-sync-database.toml +``` + +Once the zombienet is stopped, the database snapshot +(`{alice,bob}/data/chains/local_testnet/db/` dirs) was created using the following +commands: +```bash +mkdir -p db-snapshot/{alice,bob}/data/chains/local_testnet/db/ +cp -r db-test-gen/alice/data/chains/local_testnet/db/full db-snapshot/alice/data/chains/local_testnet/db/ +cp -r db-test-gen/bob/data/chains/local_testnet/db/full db-snapshot/bob/data/chains/local_testnet/db/ +``` + +The file format should be `tar.gz`. File shall contain `local_testnet` folder and its subfolders, e.g.: +``` +$ tar tzf chains.tgz | head +local_testnet/ +local_testnet/db/ +local_testnet/db/full/ +... +local_testnet/db/full/000469.log +``` + +Sample command to prepare archive: +``` +tar -C db-snapshot/alice/data/chains/ -czf chains.tgz local_testnet +``` + +Also refer to: [zombienet#578](https://github.com/paritytech/zombienet/issues/578) + +The `raw` chain-spec shall also be saved: `db-test-gen/gen-db-raw.json`. + +# Where to upload database +The access to this [bucket](https://console.cloud.google.com/storage/browser/zombienet-db-snaps/) is required. + +Sample public path is: `https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz`. + +The database file path should be `substrate/XXXX-test-name/file-SHA1SUM.tgz`, where `SHA1SUM` is a `sha1sum` of the file. + +# Chain spec +Chain spec was simply built with: +``` +substrate build-spec --chain=local > chain-spec.json +``` + +Please note that `chain-spec.json` committed into repository is `raw` version produced by `zombienet` during database snapshot generation. Zombienet applies some modifications to plain versions of chain-spec. + +# Run the test +Test can be run with the following command: +``` +zombienet-linux test --dir db-snapshot --provider native test-warp-sync.zndsl +``` + +*NOTE*: currently blocked by: [zombienet#578](https://github.com/paritytech/zombienet/issues/578) + + +# Save some time hack +Substrate can be patched to reduce the grandpa session period. +``` +diff --git a/bin/node/runtime/src/constants.rs b/bin/node/runtime/src/constants.rs +index 23fb13cfb0..89f8646291 100644 +--- a/bin/node/runtime/src/constants.rs ++++ b/bin/node/runtime/src/constants.rs +@@ -63,7 +63,7 @@ pub mod time { + + // NOTE: Currently it is not possible to change the epoch duration after the chain has started. + // Attempting to do so will brick block production. +- pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; ++ pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 1 * MINUTES / 2; + pub const EPOCH_DURATION_IN_SLOTS: u64 = { + const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64 +``` diff --git a/zombienet/0001-basic-warp-sync/chain-spec.json b/zombienet/0001-basic-warp-sync/chain-spec.json new file mode 100644 index 0000000000000..8c09e7c7b0321 --- /dev/null +++ b/zombienet/0001-basic-warp-sync/chain-spec.json @@ -0,0 +1,192 @@ +{ + "name": "Local Testnet", + "id": "local_testnet", + "chainType": "Local", + "bootNodes": [ + "/ip4/127.0.0.1/tcp/30333/p2p/12D3KooWFvMbTsNZ8peGS8dbnRvNDBspstupzwYC9NVwbzGCLtDt" + ], + "telemetryEndpoints": null, + "protocolId": null, + "properties": null, + "forkBlocks": null, + "badBlocks": null, + "lightSyncState": null, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x074b65e262fcd5bd9c785caf7f42e00a4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x0e7b504e5df47062be129a8958a7a1271689c014e0a5b9a8ca8aafdff753c41c": "0xe8030000000000000000000000000000", + "0x0e7b504e5df47062be129a8958a7a1274e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x0e7b504e5df47062be129a8958a7a127ecf0c2087a354172a7b5a9a7735fe2ff": "0xc0890100", + "0x0e7b504e5df47062be129a8958a7a127fb88d072992a4a52ce055d9181748f1f": "0x0a000000000000000000000000000000", + "0x0f6738a0ee80c8e74cd2c7417c1e25564e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1809d78346727a0ef58c0fa03bafa3234e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1a736d37504c2e3fb73dad160c55b2914e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d": "0x08d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a480100000000000000", + "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", + "0x1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c": "0x08d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a480100000000000000", + "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0100000000000000040000000000000001", + "0x2099d7f109d6e535fb000bba623fd4404c014e6bf8b8c2c011e7290b85696bb3": "0x08d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", + "0x2099d7f109d6e535fb000bba623fd4404e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x2099d7f109d6e535fb000bba623fd4409f99a2ce711f3a31b2fc05604c93f179": "0x08d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", + "0x267ada16405529c2f7ef2727d71edbde4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x00000000071c0d84db3a00", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9007cbc1270b5b091758f9c42f5915b3e8ac59e11963af19174d0b94d5d78041c233f55d2e19324665bafdfb62925af2d": "0x000000000000000001000000000000000000a0dec5adc9353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da923a05cabf6d3bde7ca3ef0d11596b5611cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c": "0x000000000000000001000000000000000000a0dec5adc9353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da932a5935f6edc617ae178fef9eb1e211fbe5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f": "0x000000000300000001000000000000000000a0dec5adc935360000000000000000000000000000000000000000000000000064a7b3b6e00d0000000000000000000064a7b3b6e00d0000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x000000000000000001000000000000000000a0dec5adc9353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95ecffd7b6c0f78751baa9d281e0bfa3a6d6f646c70792f74727372790000000000000000000000000000000000000000": "0x0000000000000000010000000000000000407a10f35a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da96f2e33376834a63c86a195bcf685aebbfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e": "0x000000000300000001000000000000000000a0dec5adc935360000000000000000000000000000000000000000000000000064a7b3b6e00d0000000000000000000064a7b3b6e00d0000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da98578796c363c105114787203e4d93ca6101191192fc877c24d725b337120fa3edc63d227bbc92705db1e2cb65f56981a": "0x000000000000000001000000000000000000a0dec5adc9353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x000000000000000001000000000000000000a0dec5adc9353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b321d16960ce1d9190b61e2421cc60131e07379407fecc4b89eb7dbd287c2c781cfb1907a96947a3eb18e4f8e7198625": "0x000000000000000001000000000000000000a0dec5adc9353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d": "0x000000000000000001000000000000000000a0dec5adc9353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e5e802737cce3a54b0bc9e3d3e6be26e306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20": "0x000000000000000001000000000000000000a0dec5adc9353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9edeaa42c2163f68084a988529a0e2ec5e659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e": "0x000000000000000001000000000000000000a0dec5adc9353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9f3f619a1c2956443880db9cc9a13d058e860f1b1c7227f7c22602f53f15af80747814dffd839719731ee3bba6edc126c": "0x000000000000000001000000000000000000a0dec5adc9353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x3104106e6f6465", + "0x2aeddc77fe58c98d50bd37f1b90840f94e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x2b06af9719ac64d755623cda8ddd9b944e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x2b06af9719ac64d755623cda8ddd9b949f99a2ce711f3a31b2fc05604c93f179": "0x08d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", + "0x2c5de123c468aef7f3ac2ab3a76f87ce4e7b9012096b41c4eb3aaf947f6ea429": "0x0400", + "0x2f85f1e1378cb2d7b83adbaf0b5869c24e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x2f85f1e1378cb2d7b83adbaf0b5869c298ef7dc060436e4ed803af07632b89b65153cb1f00942ff401000000": "0x601de9615313b00e8cea3ef84e79e50b2fb70e2c8a47cff478b9fe8b3fa8f2db02000000", + "0x2f85f1e1378cb2d7b83adbaf0b5869c298ef7dc060436e4ed803af07632b89b6b4def25cfda6ef3a00000000": "0x601de9615313b00e8cea3ef84e79e50b2fb70e2c8a47cff478b9fe8b3fa8f2db02000000", + "0x2f85f1e1378cb2d7b83adbaf0b5869c2ff3ae12770bea2e48d9bde7385e7a25f": "0x0000000002000000", + "0x3a2d6c9353500637d8f8e3e0fa0bb1c54e7b9012096b41c4eb3aaf947f6ea429": "0x0400", + "0x3a2d6c9353500637d8f8e3e0fa0bb1c5ba7fb8745735dc3be2a2c61a72c39e78": "0x00", + "0x3a636f6465": "0x52bc537646db8e0528b52ffd0058dc2705bea5c66d15541040ac6c3ae971bcf5f1040221a8d1f8b7c17e61bf21cce87411480b10bd8daa5e3c2b65f8c4aa364e5a8ddf27c0313827d06a2d6334e074db9ca7d876ac8d052862b9984530f4d340bda4edddd6e4de5ba624536717e1139e14df2d875c7f7086dc3fa3d398b64f50fffc58fbf4fb73ffb0d39cc2b86761cfe6d3073b9c1fcee7fe611b7f4875f9a7d8cfe208fdf493f4d3b07d9a73ad05c8cf39e5c4dde679c3c8391b9ceec4fd78c824d218e4cfb79cb8be9cb301eace3b7f8a274c182edb72e2e83349855e7e4a2a795d7e27998b94f46d92b42eb543afcbcf5f5c9e5bf2d52dfd9b2f93dc33262710e3fc79b943e09fe2d00f8dd7edc4350b92a692a2facb7adddffddd3d89e9babb7b8e0b9d61050b2b4ddf3efdfdb3f629e9edfe9c18c4f8715bebf42d6f6e3ff74be1b9c0c8b9187cb89c83618e5bce6ebf90cb3918729745244063391ee9710cdb87bfbbbffc6047f275725e904518e7f53cec48efa788c4bd67d104a4eb81534cd2bd67cbeebb075b4c32deee59a43da30fd2d0c979410f3db2fb2972cfcad89d0f822c7ab644bade3b59d6eeddc9925eef8f34e8645980eb0fb2f8d9b2cafddec99273d7bf234bee5995292c3051e1fa97dcb31285eb5f76255cff23de917c3f72c8afaeaeac6ef74e96462e7d70864ed2ef48be2c9ef05d8f1cfa6e67cb79dd0ecdabababab5b225d7f4a72cfa6a53d9bcf739903246f521840fe916b813c65e41c0c50b7b60fe76078bafc61ff4c1bbfac7d3887b3bafc37979f73580490ef389f9f5920c8edc3f3cee7075fdc3e4cdba79f1f9c200db97df896f532c31e008355cff83a7dff7e1791b4e5097b400cb89ef19def24533b4524b567fe2c96c02292fe233d5900f2edfed96d8f34d29c2680f3270934e67054b7a4b7bfceaf95fd879b568e777e395e3aa7139fded3ff484f77779fef3ebbbfdeb6364afae9f74c32bf6dd9ef3de714c839e5df7e908f8c208b30f2fbb388847f8a2354c1e170305cb6dcb3b2de7eb0436e9ff9edc33deb3fd24ed29ef50f602cc7dbfda0ac7df8f683331cdba73fd63efefdb2f699b79f45244e492a38b708a9def9f54e6ba3643efdf9d41acdeb964524d396f3ce3fd247fa2f7380e4736a01f2e59c72bcfd606d9fb266c81ce3fc32bc0d3a198071be3f3f8b27cc0f725b7bc6cf3d2be99da45f916a7e3f38c349d21b7211a2597587be4b05e6ceef17b908d1c4dd21112e95f0ceef777111a289bb43225c2ade9ddfffe2224413778744b8f3fb594c4271b83bff48831d3217995ffa73cff86bfb94f3faf3834ed69ef11719fdf9592481f68cdf6ded19ff91063b9c64df908b10cddca5e2ddf9fd2217219ab83b24c29ddf3fc51346dc9d1fb60fdf7e16934cdc9d7fa48ff4913ed24c72cff839a76dd0789903a49e5d06c80dcee7f629f9a7e59ef1f323cd2903720ee774f91b22454f610414ad21610c79c190160c991a32c6102286c0604808865831440c2057860431c469881042da10f28221370c9961881742e6186245881c426630248b1035848421248e214d42de18b224644a081b42bc08a11212032164081943081842d6102203212e102286902e84782184cb902d845821a44ac8154248304520a449080d3d36e8a9ea99a3478e9e387ad4e8f1d233464f0c7a723d5b7aace849414f153d24e839a247aa678b1e287a9ee889ea71a207891e237a44d053821ea89e247a94e81941cf0a7a5ad0c3821d11f448d1d3448f163c3af070a046c68e1a3b69eca0b173c68e193b65ecc060478c9d17ec84b103c64e979d2f76bcd8e982878947069e251e259e241e2b3c31f0c0c083dbb9dab963c78e9d3776e0d891c1ce971d2e3b2ed8e162678b9da99d1becd86087063b74ecccb133831d3976e2d8a963c76aa7063c1be0b9b293c50e163b2cd859c18e0a76a476aed8b162a78a9da89d12ec3cb143821d26768cd82962c769e7879d1b767cd80162c7033b42ec7460070440ec0072c70e13901b00b9da69dab101481640ba00f102880b807001b20490278094000813407e000204902cb51acc20a61390a51a0d80c850fb52bba376558ba3660710a5da1c409280e06a5635388058a9cda026478d8e9a1bb5aada1b35366a30a86d51aba236454d899a096a4c0059a386a546430d57b3528361e76987089d2f74dcd0a9d25943270d1d2a1d18e88ca123860e1b3a73e880a123874e0c74e0d02943270c9d3674ccd0214387063a32d0a9814e171d2b9d3774d0d0a143470d9d17e8cc40270e1d2f3a67e808a143848e077478d0c9a263834e0d3a34e8e0a0d3019da61f6afc80e3c71a3fc2f8d1821f5dfcd8e207173fbc981ef8f1c40f277e90e047133f98f8b1c4ab04f34b8f0c604288573fbebca26a54d0c8f083aa2af9f0c2c71735197e88a1d3c33787ec8e9009f6434d1b36573a869a0bbc2f3a778473d49e422ec2168453e11630203c1bfce0522347784527869a17542d68984219603d7442c086a8f902e34167294cea425023469df26e50e3a5878c70a926d5259b1d6267c8bebc5eb0d303cc03a1d2384307467490a583a70e74a851eaa0033d8e10bfc070a8568c3db8be78687c74f408e2c545b481cb4a8f14e06c51657851856d8c3bc8bc78c5c047d40f2d6476c83421bb416581cb062f2f2f34646ed42d7c24e164f1ec78a9e15223e6c54b63d4e2c38a48c78c1d95a9068d5a11f54aad04b51d5c68b86010adc61a6ad4a0597aa541a39463031033726aa08901c9445e21ade05841c6602307a9f423f827300d1b19f4d4f1657000825718382da827e8b0886ef4808123021c23708ae809030704384ce02c81c3054709215d709cf8f1c1f900ce062a10383e8852b468d0b2c26962c686991a7048b09303ce08704a504bc306861a326ad8b0d9400d0c6ac0c8990187861a3a74385063464fe12ce1c4e003063ec6f831831e40f4f0c04b8c1f67782ce8d104a8460fa79d257afcd003043fcc905981103764a2e8a1030803d005433e007ab179b201818d10f406a01dd48ece868e0956431743dd42bff4e8402743074387ebac74576a0a2a15758aae06b1aadbc07f60c68c971daf2f558a1e5a3aa577aae9a24bea66a077b8946a9868c8a0a1010d1d3435a061636606345e66e2a091c18c1c346bd0a83143c7cc1c3469ec0411ce40860b4d0b605a68585093aa69a131a25ba2c982e605b52d343e8c1bb0c901f6011808604f3c88784551b9c8ae646dc072f820fe88991bbcc0e88ae888e88c70c9d03dc18aa8319851a3f683c8c60c1a325f646e206303992b19ab191a66b0c850f1a282460c9c20707ac00142e60a192b6049302b3255c8a4e03df03f00d181831d4419d4c6b0517a55895334493b30b41534565c4b2e1ccca99682300d980e5e0d6057604cf306e31a3655231b3e62f08241f5e245c66b0c0eb48c408c3f8c1eb08943868b07e2d5454d1aaf2b5e5b6cdc78a9604c0387089c271928402e5e55d86001af6aba8871d4d0a0070f3634d4d8d1c3071b2b21ce268b8d0d3367d4bc01bba1c68d1f2ea859e387979a18c09a6c7880d95073364b3565d0ab9a19d4b2b091e175831a2b180d3859d4d421b6f17ae2d5c4cb891f37a89101784718c3cb0697198e858f261717ae12b846e02ac2b585eb042e295c53b8927081c015e59a72b5c07584ab0617169716ae14b8b270f5e0f2800b0bd710ae255c4eb884706d7129e17ac2b5838b07d70f2e1b5c50b8a270657171c065848b05ae15b8987055e1bac275832b07d7932b042e205c1f7005e15241cf54cd183364b862a8b99a2943ac439cc3e606110e9106e21be21d40bec0711273220a8068b169c3956433c3aca3c6c4b303073cbccee891c30e0e385c841b7899a1e30510aa1a143555b5276a4e4c2d707ee080033b576021d88961a7069c295810af357464086100bfe0203141600387cc13322600bbc0f100e8458f25c02dc030769a00c1787d51b1709d51b3807140acc1cb8b9a06ce11343000c204a40c58075e65d868a9b1012ba9fe00dba1034137448ba047053369bc6cf0838d1e3df464515bd0566ab8ecf0a0d34563f1d9507bc0116205162a544da22e5195a81e783272a2462a9e8b189731052e3b64553eb8689911bee18901048d57171d2d3836e0d48033838e0e325f006143c68b8f06b5a57a458c8b2ae5aa636c72a5d1e303a21db58a1a11b5281f31e058a92800a2850f18ea0a5e50d4cc21dea0a606231a43b8801101f321b4e25b8833a82a10e5a849c2d10296c533e3470c6a5c5073064e08bc1fbc19bc2b5e0c3d33e8b1a367e81a7a072057b4161b1d76b4b8c2a01903e452bb41cf17206a0021a3cb0244059d53a743d7d4d1d075a0d3d2fdd005d1c305080f3d5d741ce87ce87ae878e880e0d1d2edd079a0cba1fb40874377031016e00c61f3464d0daf0d9d1c7ab010b700d7d0b9a1870d73861b367676e0e14167079e2606e060c101838621e3820ea39de8259a896ea29fe82e1dd55f34091a0a97aa5cfc106fc423417304cd123448e41891e38408845884e834163192603402e4400d23c6464c8e980c649e64909029a207971e60f4e822a7889c12e488409c41e4808885468a460b1a15c4ba88c120e60558450503b442d64566860c8c19ab993b66eae8b1460f1af460237644ac043124782cf168e22143ab8adaa56545cb8bda45eb8b2fe245f042f838818f2d3e50f02178103c11b12b625bc4a44627c629c6a81814b12d3113f810c207123e86a8d9e0b9e1d1e1bd018301ac0cd8182316a31763163eacf0d1021f57c8acd00981ec8a0f86efca1783a884480271095087ea0270872a06a8e585e5b5c38b86d612b5205a4c842c08c908b1a835d42cd586fa058d153eb4f808c2070fad21ea0b5a21086f107e69bd117620ecc1d3a2268697453746774617032058d870c026861aaa9a1bd8d450e3854d520d1c364d3638d4dc5113860dae260e1ba69a2f80cca16307101bec28d145f42cd136340d4056d0589aa973681e3acb9ca3710d03902ee6d5acc1b4c184a3c76a5acdaa49032052736ab66066b164a260b2604e31a5983f4ca989c584629e60e6a609261573cbfcc05cc1b46246318998219843cca46965c6309f260c1357c50215983e3c994d4ea8b820a505a1261098400424f08006a49000144e40c001941820090953082300100091282c38c07979c648c16a072a6a528125539a00b1b0640938fd4914a0254b5abf8127529c003dc1f92b5c548401202551a440292a025a00f94c1cbc0c34bf24d4c40914222946455058f0e0956c3e89895a68e1f556b8a80848a8c7c7c0310f03b7700099c7f1e05c090935712224d48400349c3bb848084a1323a0274b80802cf0018e1d2cc50251a02cc10011900b434ba04cb94651805ac04013141ee70b03ad7003067a22c5c992274da4084d71c1060c64d4048a519426464551a0c870ea6021a1264e8c9c3421328a228500301c2b067212454a94254d9c44918200a3282e4871e2e4f6c0a9019429170345500a80814be2d020041c3a7270e660189c19b01ccc82132953806c70e26022175680628128529c2c8132e50255a0894d06a78a8b9e1035b90010d19215a24079120568ca1228536e91901429284481d2821404581c38780a14168a8880a25c40ca120c00057d80f3063f018ab20294a2282e18357122850a14178680961811499902444404c70d7e026589115011910b4e6870dae0222028465088a4b060e44293252b2c8132e53699f2244a1322127ce0c8802f0065ca25020a2292e28013481c361808c80520171290c213a015566892c20f9c35b828c809100b4ebc7091511420222016a240791c35a240b1800d4e1aec044a5114284446558096604068ca94264b88809e084171c116e4448a90ed06070d6e614913a3264f9a18011d0086734606a00835816204250a14191c3338c88914a10a2c013272c109501520189c3298480a01429e404215686214c5050b2c3172024404e54914284b96d0e880367c2083918403c3ca97cb4820e770b83b919cc66355b1aae694f951efc6c6fb273d1bcff3bc27c99b1b8ffc1beadfc75f7f5d6b77adb39bf963effa7d5d2be576e68ffb03e9f4fad1a6def7791fd013fe987a7b5f777fb4995b74ff9add99b2338b226566ffd8fbbe9deea87760f7d755efcfbbfb1b476ef70aced44a99ba7762f56e96d8ac3a99bac74ce64a65cd72cf9d3f0fdbe9d7ec2f661bfe987ecceca4dde9e73895dbbb72f5cf690794fac7edb4d93f76fa71d3ef73f7bc8fb6536766ca9429534ad9fb28f5f6ef83317b53a64c993fca4e653e66a7cced9476bb575ae5cafef19021428430c8eed4e5a20e7a575abbdd0586cc937a5ead1f738fcc9f3b6598bb5377efd1dd2be0eeb0eab5d6dae3d8b4dbdde79c3e67d3f6f6a6d4bbbf6edaecd46beaf5fc2af5c09d3af5599dddbf70c645db43f7daa42ba5ee2ff6f656bb7fee1574265d57ef4a7b093b8d31b37fd3dd41b052a069482b0dc31aef1a760fc309788712a8719ed3bf5ab97b727fdc13e4eb09e21e0176770a1386ddd3b9bb99fba3f9421aeace94db2140a97baeaf7eeef4f3a8473d66af52eade5fb7fb473fef8ffbc6fb3effe6fc981bf600dab4ddbb2937b37fdd1f7bceee7d2008a34054a820303bbfda1dc0cc3e3bef98b9fb989bb9eb66c7ac6eba772c67ee58ecccdd64ef581d77ce9a5dd771d7755d73d779c71db3983b666618666f6731c73033b35831cc95997aadeedd9f7b8e7b7737a51ed0ee80f6cbddbfe6699e6e8fba7703ba76f7a49501ed7937ad1fe5e9cddd1f7f5fc7d49dba376d4f61d20528c0030e9d7f780218051ad6f41ac7a969202774cb7cddb06eeafd79b57e8e0098ce016a351d6f1a86ec734e9eacf6febeef874c7ba594c62adb7ccc95a73bedd0dd457710e6e476b06d427666a6dd4ca33edd41f77228655a29ad94b6f70ca5b45217a5d4044a5db429f5da5e2b58bfaf6777fb6cfe3e9c0efae3e993d99550e7ea6cc3ce6266af71f7cf6b6776f630c63e67c8ede2768ecd364077e8edce727767d51866f7ca732661febc69f3474343536b7dbd5e73ce5adbbd84f6f6aa57efd09d046feaeefe7277eef9f5d7947e1f87cedeee4dab778314ac2085e9eee6ea9f37280382ec3ed929ad15a4947e1ff7d7d49d7d4e0ec3574e873e42483d44e2341e76bb7bddcdeeeeecfc7ddc55669e9f659cf979e8ec79dd4eabd7dab47af5efebaed56937add4a35e53da3da7cf39270c4c7be73c3bca6af72e403b28d33dfba360d7fc79d8dd9336a594b67f4e00dbc7edec3d99bbdd3fff3e76e6767667766f6766a6a0e73ebdbda977f7f4cf999d5266fed89ddb9d32333365fe98bfef6b76ff989d7a5f6f7766767777fed8bddbbbbf23dff7cd6aedafcee97d3319113c99effbbcef930d4000edc950af7e9fabbdfdfbbeefebfebe98f77dfc7d9ff3f77decf4fb78ec9a366d9036edcfdbddbd73ea7ded1fcf39448a2153380f6e0c10496901a805cf8805a448219a0242009e0011013d2192b2c427841e20284446207c0043d323a5a60b72d2a402424252402852d3c3470f1a1e464550aa00dd742d48e981620120a22996031b98284053a634b9f10b00450122ea0e5a806214c50522cb81058c5ce8c14115201696184581423465899322282ddc0cf1e95145ca058c7c3461a1c8475013274e80827c42e8e1c14188f40459d20314d444a8024b5688028585a2262cbc102128413c00f8800807690244e4032868895115a0283a3e3e807922048505274b8c845c686201a027b4ce88a88951d1073d1cfcac00a5888c7190220c00052d710245a8022e4c99111575d0e29ea22220a2292d4871b28408888a142740444b9a143d7102b42448904f083d539c0015fdb0587062d4a4024b58288212058a05661f60c002508880a870608980a200adb00400414208a1e709d0122946533040e4a4039610101520a125559ab480035b418ad09215a240596105294234b3051f0c446401275284849adcc054017a12054acc94169a181501b500c5e87b449102c5c84993a2284d888c96184169a1022e14d1584f80808a96b420e5499426443606c8a88951d1922022291730028a92032bf2596116821150d19227519a2c01226a32a5052943c62640424e9600add084488a51d112a1264ea4088140250a90b338c8922852a014110151594224c5a8c91328424da82c2982b2240a94262c38b18005a42c31aa02c401952840fe03aba3f986d44cf805a466c28dc462c247472c9009b7c20e09e9e8e8ab48ee47484820528b09231d1dbd8e8e68bb33399a4847474794c9d13cbacddb64f2c27c611e1d1d1d1d3192787474243261a48f8f908e909c9190e6d1d16482348f909ac96dde6ecde485f9c20bcd848f90909cc9d13c3a6a2647f36832e1a3a3a323a48e1e1d21cda3598f26d264723499091f1d39133e426a267c74c448481f13a47974e4313942ea98204d24a46682349991281346426a268c8484e44c9026d264c248938905bc342633cf168a9a70ff6aba2dbecb9bc2179ba6703ceccdfb193b61ec6d8ad3fa61f6369d5af6e654377762d95b3bc9d8a6622aae72ea625e8cbd219102ec61fec6fa1bd3105beb6f48a4d0bd3775fb6f48a450bfeb5c0ec6de580fb373b4b709e5b4fe97bd4d97bd7993686fdd14da9ec24d2876c109ea68a220cbde9296425bcbde904881f5f46f93eaf6330db1517b63d949e5b47efa9ebdcd29a7f577f6d6d5766e7a36a8a2065a90800530cca9a9c58c21d4f882082b9f3dea2b9a5002872dbef460a37656517915a572a2534d533447713977a250de975e0555e5509eedb450755fba13d5955367bb266fa25ff6d477757507185faca087266a3ba6cecd37bc08c30c20a4c2b0b1cdbf6cdced8f8b1dbc7842862cdcb0b1cd6d87735a7f39ab6eff1cc138bfec70b7bba9cb1c1c59a4d933361c31c711671c31c611611cc165882e59dc0c8c9c1b4288db0f5ece0d41c5104fcc1a30bbb3b395796543826b58f0c86e3ffffc59fbcc3075fb6f74daa76fffecd86d16fe36cee5c961ce39d9c66a98c3873984d395f5cc2d371260cf8668c26947f0b30d091c10081bb60640bafc2fc840c4b644c4d6cf362bf3cad61609b64773ea809492486310fd0f6e89d41d5dfa25eb006cc6ed2c11b57b26eb7724253b57a2ca562d8eb568a25fb228f9c105278b10f8e01e4da4ae9b0b281f40e625e61c9ad77fde00f293f00738346f3f0f5e6ef8dd3759346f7f8b25f065d9a0f9ac269a5cebdea8de21bebae0b73842f8ad16d87db348ce817ed8e586cf7a10ecc26e3dab45253409ebc33fd2247c0ffe24c16791e1bba8a4fe9c96b936cbb6936bf3590f9265b3a8d43be477e08c269237db8dc9f47f5c3a9f7970bade7f28a8b003166eabf159fbd878dde7cc98b0204667f3d1a38ddbe9b44fe9fd8c3baeef25842a30699f8ea54c689f79bbe7d1c274bb1fd2519edb3117299f9a5bf219b7ab3fe57edffc46deed07694efb74443d45254beef7f5fbe6cf32ebb00559a2094852782dcffb727edf64b51fe99125d2f5823c31c967bfff6cf98267cb79bb497f70762bf16f25d3b34ae677f737e00e425c8fec260cb7accfb9197c18c158fb78df3d1549a85fbe709564c270eb83dcb8fbbd47d68f2cbde73fe21e0c777e7b55f502d6fe793dffd83ee2f3c7daa7f5cc7ff339ed539f7fd63ede23dd16297e25914010fc231d9236f559396cb9f4451dbc07b95cfa1e07ceb8f441fa208834c367b1c00727f8437ec1076b908d92ef3bfab93e259feb03bf3ec86a3d5f56cb8e509ff5ac1db25cfaaddf21e9d2a0eebf0fbf92f3b25c1ca1d56ab56c50f725fd22a4138a906ef841de9f40ffb3a5f7a165f165d52e6431b4e5ed86ef912fd27b89394839935ebfc41cc4fb693be2210976a147fabf48b6555209cb06894f5f7c16910c896314df3df03d5b8a0f5a1bf0bfef94d017ad0d6895d4f7be821ed9fa2fa8d64f49fd6a12fa2c5b7a0f3e089265f836ace70bbe47dab0ec08dd830f5abe1c98e3d2071fecd06b3d68cb794befc3073d6c91e197f386df8d002601c1f767d9a179c57a7ffaa02d5b1f92e0bc1e396f8be43b2ff3ed8618b9fcec359c0168182ebf8b87c8d1446a7568039884410f5924c16d39a75802fbcf13fafd595f562e52bf6479e86439aff760fbe5760ffb32c8a1279e40df6d59af7bef950e7e210d3bd10095eccb22e7edbc9fff89273458c5138edcd6b3c8790d8024c56d3dd80a5926208d10e50e1dd52421cefdaa880024a7db7ab04396480292d31d62725b0fd6b0251a00c986db7a100c5962121eae1259a20948b7f5a02b641da0cbd7fdb8997976aef2a8e97a0f86218b65cbda2e5779e474bd6f91cc3a65ebe787e209fd2d5b4e164356927ecfbacaa39b4588ebfdbc959c17ac618b49e8fb4f71c86f903802d2ed3eebd9f91e34df46498981dbcf17a94e2f892c583c0a0ee4c09405072f138710ecefb7e99e67f7ec9136ddcffbfd07a3ffc1f5ffbec9ee677bedb5c7df5ee59eecfd11f7c8ee821dd90fce59c3d83f3b0f3b1a765dbff7839d38028be17d3357f3dcc976ecd907d791bee95b803c3b3082b387b193b89cf3418ddb405cce7540eace2ee778b04a6264a5ea96485178b774e1062b2eff6bf6303a1597731f58e2ce2d977340bc71752ee780e0c01449686541758798dcaa1feed091eb9646658c2103e296464f408065dcd2688632ba5b168141821f504cddb2286aea561c8eaf2effe56f1dc0a179e98394ecbeebbeb8f300fe6dcb5c08dab8f4e9cfef49da28e9beb8f4bb2f6e598474e977cf7788afaeae1ae9f6776ddc79c4964b5ef2821d3689733bb2fbe24e9184a72233ad512b7927c1eeea5a9b24f3fd4998efd608e4dc105eae51dfce96fd54e6f547bae47592bc6d045e7ea46ef69739ee7cd9eb3ffbf9fd5d3401490adae4fca60d23e76e38e3d6ffde6b7d25cbd607b1be7ef7dffb834d860fba481bd7f32d91aeeb3fb2ecb643af4bc5a8afebc31769e3fa79c70769d80f36699384e270177c7afd82df645f16934c5c8b24b8fe458eff91ae6fd2c317492f48c38f643aee8bf40b76e147f20dee8bec0bd29edc7dd41b3ffc8f643bee8bbbd9d425be5f317c316e48f68fe4eb8ff88bec38e8fbfa6e029214f5b9d63fd260f308f3bf2926f9beda24f11bbedfd0964851e070b749f0c129ce1a46f05d24f8305cb04317093ee86f5c90cac1735cb00b5d64d177a9f45d81685ef0a98864d230820f52710416e3820f7247bb72e0027f0b2e86eb22792ed8627d83e233d75aa0f8618b2cfdb23e64852dd6832451288afd21eb5b248b26b00e8b9fe707ebecd8336aed752beb996b7e5ec029c3482fe76e78c19461ec2ee76e880173ad83eff3bceffb496ae0fbbe2f0d9049708add5cebbabbab5ceb7e921ae8ba67711124fddd73e5225420097c5f0f32333373cf6772dec9af906baf6f3203a3ebc50f1ffc0c8cad677dfdef33307afe7af5bf5edfaf31c05792efbf1659de777d677d7dcfbd7a2cf0abef2495796bfd6f72bbcbfdddfead36a8fef72c1ea0b26c8974599375abee5eff880fdd6ed76675edda3ff9491bfff9fe4ddaf83b59c291cbac537effbd937cbfff2a9151788744b873caadcf621226b77eb5cc3a247c64593fc8ff7bb092966888ab70b86b04735bef6e14ded6d767f1842997f547ba92444322dce69abf91776b5f7f164954dfc8bbad6751c992cb7a9c2111eee41aeb2bcb32ebb83842f7b592f3bf725efe8e2cfbe733b5b5674e8e757e5880ecc1bc7bb0f307a7c86d03bfb625d2ed79fb9899ffe33bc9a1dbfd6693437e5fd33259d25a2793ee43dfd5d5d5975b9b1cf25bed9077cfde7f64f93d95f10a511c0cb7ec1ffabec07075a9d4921544bf3edb72bcfc4d86fd54beb27f8888ca778b90eeb42c2261efdba86febbd6fd9a1f9e5521669d497beb5493273d7bf4524fe1ec9e57cef9da4d29ef7b61cba5dfa5d8974bff9555bde6efd26677777fd598434e423f0f77b437e29b5414aa892f96e83f89b59b3e2d03327768055c6166f787a2663152e32bf6fee52f1441f1f7cf1a5ede37df8fccc7359dc7a2e3243f2b9c673f9bd24f5c93abf4e92ef145b606b04d66b5e904524fcc1c69eb59ef5e04f11c9b425d29d2cb2458295a4326f392feb2749655e16eb2bc99782ae6987fcda8ce077feb4cf35fe792bc9b241f5c1a7e250bdde8321f862fd14e7d2e86f59967f82952cebb35ab644baad89a405daf276c19f248bf49eac33bf340092149759673eeb8ff8d0ed7a3fcb5be490b3fc59e4541afdc726f97e64ed7a6425c119ceff489b6987e6f52c6fc1e1ee8feb8900f426a431a8fb0f6ed9d989a5677c3937830fe0c4d23e7ce9037111229e4b043f12a7f1f399ad6793966a36ef99626c58da2776e9d70c29632c85eec4d233fa3c68a090e4fdfc23fdc2584e2c977ec9685cfa37fed16974f8e004104e4051e17036efa96d92382a821a4010431027b0252dd56cf399626cfc494b6dfb9e6900b6f91ec93400db0d8914e6df50701afd3975e97b7f432285ef3d7b3be234fa9fbd219182f7d3dede69f43dcbc3b9dcfc92a7980632a8800837c230820c2efed21f1283916d483a6071821f7e98a2cb1233b0b18dbfe4b9f4594ce17138dbc4d23e1f5cfa9c436dd06ceaa63f80cc454a1ea457d93e2dfa1da547d73b332eb55de97df43f1bc5b3a5f742ae44d5edacf7a5dbf276a92b612d6cb89e25a2765f1e5d21241fae17450049b9db7d496d59e57a14d6a2e9765f66e052cf46e1336e67a79e50b0f30515f4062df7e672aee9cb053bec48226efc47afabab2b1f6c2c227033632861650d1cfd39e4575797085c0f1a86c8e244d48153125238a3297cc62502b7f30515382a0248ca55c1b1164d36fe3203b77be60030ef949cb3a1896b342f1131f0193696c5f11936b637fea3283f7c000c18bee070b66a7149389c8dbfbcbddb720a48c34af253d2bfc506ec7c31c5958d9fc506c0c81823047758b9bab2f1c7aeb77702d02925bba7f3ab5df7fe951cbbce6b345cece2b8b29e754fc979410fe97b1d9d9776c3c0bf72112f65d77f7a7d67bd7befdefbb3bcaf9ebf7befdfbbfb77e4bca047f2ed90b41bf48f74bff7d37b1bfaf3f6b5a17078df7d5e47ce4b495ab9c6ed06c8dd532ee23d7fe791437ad6bd1997a767ddb3e865ad52df7f5adffdcc7fc0effea67d68cfea774f848b3cd7ea770f9263d3eab7c8dab4caa3fa8fac69f5bb97b50febbbe72db71c72bbe7c145ea3b55e891fcc1eafb43dd9b9ed5ef9f3fc5fa36dffbed6bf37dcfb91ad4b89cab018d2beb597d6f885e96e59ed58e6bfc2c528f9cf7a891ba7625406e9fcf9ffe47cedb91f45924a17be6da08fef4711082c503f8d3af4f6d592ffd7e8a4355926280017787ca0bdcc08eabeb7d11d2f56cd1674bfadd91423529061868951695545b56015924a1a34fc511bc67ae95dd47ceeb911d126a6d92f8d3f7a736a89fdaa1db2dfdf677b353007e0f4e1109f8e1775f49f1998bb8de7bd0458e8074cbf0c1677184ea0aaacf1f9265fdf9e014d9835dced520c6edb8e6b53842f78b64fd16392f08b278807e16eb4592f52d92e7b3888465cb79d996ac6716d90ffe9106990c1f24f9822c92c0367cb043909c9745125a97b956f283e00cc1f08f34872059490c8ce183dfba654d526f688358df2059b27e2ae967cd568be4cb22f956be5e475292f68cc3e95a409e32d22f65b77b9eaee3b9dd773fa47b5913b7fb9bfe695b67e4763ab7fbb17dfabbaeeb9e733a1bc4b923907932cf27207fb0b0673114daa77c1adab8b92573b9f4bbff6af7f7f3bee42ef77b229f4f594b689f7264a17dbe37d23e35f77b15da87733534ddef25d03fd4e6dc85b7dcefb97d6c6e19bb2591fb757fa46fc0263f21a608eef760874df6952171bf07b927bb6b685e5dfe3ed63ef4bfefbfe79ccf0671953fcdda074baee797b21bf6e176ec3e092ebba1fea37fec9200f20e19230d586eff386120bbc029c3487b369f67fc29e92414d0b9b87bcdedfff096e3cd097b46a3009e230826bad0800439dc20031bc760d4b288643e1db17ce9b17d64b73fac3c6d783987a58d4badac67937336009968ec1ab6cf1c3b00b91c1b745dcd30c70d888445871b9e7000a34b1177d85804e7734ec943ce7bc1497b36699f4049f06cf9d7fbca1f8cf6cc96467e5b2f6b1ff0fd6fdae7033f16cb96ac6f3deb0b7b36b6cfc77a7ff023e7055924873f451278dcd096e1b7fe23f986a4915fd683b379baeb23f98224df168be49e95b23bbffacf95b771d3986be5cd9db6f4409fd323f98a30bf9246dd9d21d86195eb3d93652d2b7fb0c9624ecffcbfff9e7d4c52b29cd7238dfcf24f72ec19dbced69ef578bffa0fc5e170389ccd7fc645fc7acee569cdce03eee493b1d6366e7f289bc187db7ff3649ccff34ee110c96bc42b6d5cce5d11e3967ffb0a16f7fd47a769fd8d047c79df5988b40fe7ae7cb9fd46a67882ff7c1681c672d63d11cecdc074fb75fa67dafa8ddcdcb44f3f933c3d6b9d9ef57b47922cce581c615e9d9e4d71d6b37e0a8c47b7b60fe774371d0790c9381ff48e9832e2703818669f30bb7da4670e23e736c0e57e709d72112e1a3977258acb972fd885948bf4e5d2bffbf9a00bb26b24bbfd4e96936888af6ebfd177e9839ea8e4d52473adf4af9cc4fbee5924c1ff3bd24ef2ad64d97d39afff47da28f1bebf6d50f7def3a5245f4f54f2c1f52c73cd9f8a48ba196576fb67dae6d31695700da2cc6e5b3bb9d6efe209b3eb96b9d6967b3691be498d00b9dd7f2673bb2d274e54f2baf49da4422fb5cccecc5ce3205dbc7a7693bd05387f82977332bc60a6d132ccc0bbcb3919eaa0fea0fbd0bc9acf62166f06f1724e863ba693f37e97734c42b02ee7984470653d6363d620037617b9d621d7fa99ccc0c839a62dd72fe7985070cbcadf2f32c9d4c495f1e775d535763b80dc0ee89e1af9ad1d69e437c9c4e170b83b9f92464eef7c4ae7146386ee0f3a39599c7fa4bbeefd5d44e23d73f2eb9fe2fc16bde7a40138b18cf3d9320d387f9224f0052739831657d6b2cbb9a52fae2c1eb688645eced55075653d6b71885ee61a7f8b4886e6d5a5e15a7f8b24cc4b9f4916f927392f9343f3eace771109b5b19ef54f52c6b57e273530724e862362345c846fff28e322ad20fac10e1685174e923d58d833ee597973e7bb2ee764c8e2ca7a361f64ea3db973790e20370876cf3dab5df7471a04596c40bf2d912efd239b3b8b2af8b7bd21d96ef4dbe64ede906cf48f746d9fcafed35f1af95561e4cb29cc777b3bb22d213124c2f57eda3a92da72deee3db2f4db7d93fe47bc6d2ca6e0b6f9479a927c9b641bf74fb521f9517733813c34726ea98ddb5dce2d65b90c63918479fd8fb423cda9c4a70246160d807429b521d29c0570b204e49e913091f8a74842503fdf20b64347977fb200b202e81d2ff8a29d9b8074fbdb863df3f7a79d4742bfff91e6f6b119a1dfdfbd9f4f6bfbb82dbb0ff2a7ef791fb64f5f6fbc2a00590123f8a2bf84e5f2fc72de69c39ed1a70fbe4c18fdfb878e2e1d9a97da0a80dc20b74f7bc824c8394a6d8497a77d4a23df3ee5cc48fbd0f7d7699feffa8fedc3392531ae7fac7fdae639d79fdb27259834ff120097ec88e099bf976002e096d4a1fca71301d3fc69ade328fbffe0961fb478025371fb6b869431f214976f49adae9b20e91af5a5cff405705954d25d6abb6e7e51204319f90b14e42eecf21727e052afecd2f940a0187279faf7a5ce65066282f173da87763f85726eb524bd030a19dcf9a3fffcf4ec87acc6ed9e26d9badbd95228e73e1b23dbe6b482883b3830f586153a9c61732ba048e3baec7e4ed3e603891abdcb3928a86ef9777aed5e80dc3eedd94a96f5d6ffb8c8e77111afe3229d73116f2ed2938b4cae79cfdeb441defb7b5e93b567f57bef67b565add7fbeff3bcaea3d4bdb9487def6792ef76d523eb7b5d3f3bf4dda07e4a96fe4548b7bf497b98028bcbb929a2e829a06e0bd13ede50fcd3494cebff61a6958d85e5c33c2b3bcbed2f6197610f8021978342ea1af5f5279a4d65be006e8b27787742b14e7f0f31f2852a29974b446fc95d54e8d9a463246f433581ce3c9b30da339d9e75397358ac6736582e7d1bcf8ed0d77bf642055f6ef7448c4471fb5930ea1fcff517a07d38f74413b779b84c223ee3ed248ac3a27f9240272438f7441bfd1ef9002b73900fc045910fc045d133be3ced53d621edc329788015b639447c76ec9b9e35ec0131e47ac677bcdec30fce56f25c2682f4c412414081613583191c61632a2ef3cf8ef40fb5f1330466940f4fe0da89266eb71351dc6e9e198ce53febfb6e0ab2489e32185bcfb7f5f3bfd6f741f4e9839d888465025292efa72d83be9f22fd8f0cf23e4a270f6bfa1b15ac19e286d3283c37c83fec197ffdf69e7e29c473ebb31eac64ed591be3f77c9b45d6cbfe536dfdb59e4065de69a98dc2733d1b44bfb32358aeb3677077f7f9eeb3c7985eb610caa17d93dc44c5718650cef422c4236344172210e2f9beeffbbeeffb84be28dce5234beec25d7478867011f0f96ffa67e6f530cf1f8e3d00a6b7c9c4629e5b16461221f331b171e61b1623ebd9477bf67d0c19ebd9f733e437edfb1639eb190cc917f6ef3f32b0960c599bf63d8c1c7bf6fd48f2f4ecfb1739a467dfbbc802f4ec7b912ca167df87a4093dfb1e2451e0daf7ec3f449af67d3f7f8a23f46d59eed95763ba0b0128da92874b17c6e2b22dc51785786e149e1b147eabe4b9b30c6dc973c3cf893dffb70fecf9cbd88d79181869a467fd317248d3622cf8230cf94e9bffca9189e28ffe03f3e3f7c3902c22196d19fe57fe15df4596e3156d19de72e48bc20dfabe1e39d2d8b487cf96b3fb31598e2e11c808c67f1739739aebbb63f7fbf0b97fc2a67dff3d7873bf77912212d1d69e7d7fc443922c6577da3246b2ec67bb882ee3f89e9d43e61879cb9d638cf5997462ccb83c1632def295467e8634adfbafd67194c9fe673c3debc68f2c6796ebd9982582c575e6be7624c039bbdd29ed989cff8948645f8c6cbd18d97a3306237fe7e22a76e8206d752c2fac3d63ffce3fa8b3b567ccb3d6cbcc9fabac72e9e5cbb34507a50e7ed37b1aae75f4e69486d487be77e1e4e2fb96eeee20839f0472b808e55cfade046bc8e4bbe82efd4f4442ffa667fc32aef14f19c930a21d2dbfeffba8571a399805e46286dc1b605b9670895cfa538c71be1091cbcc52e8bc80bad3d9656a4ba4282e7df79f618cf35d88b75c3acb18e74f2e287da702049fa76e39a48cf5112ea202d7c42fdff5e5ec87884effcc9ce6e1f74cbb7eb5338db11c5b3cac073b474906ba30a28ba62bc4c3c5849eb946a74d7186e4bc2209640463498488ffbcdeffc88b046718b2fc27d6347fff58f86a8c446e8b88ff2421517fe96daff72f40fb94d5a7be7f09edd3ad677d68cb1b6f81ef42442eeb5d547253010e42405d21ee7259f4b2c8b23d7b7d2491c953617b4ed417e7943377bbef723b59ff94e0b4ee8938ad7b7e06b2c548ffd6b30ec8d408648ab19c5aa696f6e96f6b342f121fdae7733aa27d3e4b0454fb44b58f4d4f2cb77bbedfe8b4eebbf17295a55c05640463f725a8c045d0184ba6badd3379d23ef5bb670137a56fed530acdeefcfeeeab98506dc95c5c44e259233a9be05af71d4219fb482023602d3dcf184baeba5df7538c4a2255e6531212f497de2644fb94d3a97de8779f0f8b48be5aad106f51a28121b8f042758598ea4e7a3d925e4a7208f363fdc3b66aebcaf176b652e7fa7733f7d9c0df97eeeeddc75dd7f1cc72bcefefc85276f9fbb2eb3aaed1779f1e59c62e7764195eae43b8c66347070d27173d3db2b6c6e8d9dab376a6773ecffe32bc73ea08d7d8081109e480219433847f96c3c577f937936a72573bebc541bbae637ecafcb2aeeb28384da0725ba270fd2759f2dc39e79ce5ec9ad0b37e27857898cbed233deb9fbc85889139bb5c29223d6b4a96425198ea064d8b44a73fa1d333de22813b9fff36c5a8bcb94239977bec596cda92c89ddffd4ce7bdf7294444c65bbce9348020c8df24ebdce6b94de476f9df7739b7ab48c25a8fb450cee5a79c33e43291cbb2d28bf5cc93fdf5a6673b7276bbfca6946b311691944244eefcb6b3fbc299bffbd2f3f83dfe208fe716fc938b7e3ab718e7cf1890e075dd7bd77d10a5f426d67d4929ed485b32b9dd53727631cea746dded3a4b72d9755de74f20b70fbd6077777b7bcb00f697eeee3d6bbfccf432fbf897dd3788a8af5f5d3107807ee9de414e49a2795b095f5d5d6effb2bb8d5a890817c9a76701e98325330d625ba70b2a7391c945f896f4b9b6c6382f7dfa5e7b367ffec806f885970dd0e6394b505582d9ed449313b8ef8201726fc0eaf60c07708740ee12702901167480f38f984c7c694288af7d027039c744976be4d7bfc8fdb84873cd595150b18aeec585f791f1b1bcd4d7e55c1371b0445ccb69006b53a8456c05e1a247bc6050239d02165601d3da2226468232623130323cf50a3855408239aedf2e0196db3fc4c80765c84528002e915bde9044fe4454c6cb3ff4978a5fce5d4af6b8200d295943ca2ee88594e471c12fa4e4cc056b48c9980bb2424ac25cb0155232c805c190923c170c434a861714434ab62ee80a29c9bae02ba4a477c131a46477415848497a419890927ec19890927dc1180c2c2626e3b24446e3ddc9ddd0b580f30aa8286e49a19a8082f280169d86c262ced9ed05ea0caa840f4a24415929d1841249283184a7441b6228a1c496fa8d97734ac8515d31b0bca6568b0360750ac1277189dc12276831e10ae7d42b146364282e505bc46496f012c25c2616de662249092c4b58dd3126b3c41bb5c28493891a6238c74416d8f8728921d8625518170c16e04cc1571954d3edc94dc059c41836146e323373126d24e18593f8726524c87c11d39fad4a9ebaced39673887333b72a798ada72e6b69c35151628d87f3f8e0ffbbcf88f0c4dd9552fc8946d35f323e3f15134b6b574ee3fd9287694d31aca69dd4f4e6ba75c12b95bce2a9eba652f4199ec74923dccccc7bccccfe75156198c2dff636c29b3e5e8d45aaa6664ac66aa50cdcce0bccc30cd3055cd34cd3459c954dd923249d9d1025bcdccd4cc8cac8b4cf6fd4de53f3c686c6c2ccf6a6a2c0d0d0d0f4b79f008656f4566ca66acf7f3a7d37492eae9659c54cf1ff3b3cbf3ebd9a614fb39f52fb2e78e71dad74f29191a1e5353aacb949215999fb132a599b7223369ec0b323b3363a79722a4db39ae75c76c59636c39c2d85206b3e56cb4e5f7bfc8ceb195950b9ef84007d0880304b6594b2db551830db87165fb5c8ba8343c80abc3043656d73147087032e08ab0816c2859e9d2050c4e6063a7b95e7ca79af1c2644714554d6ea585e25ea04e2fd0a714c0616b24a66e4999a46ee75cb3d9d8b2a54c566df9f7b3b9dced9fe5b4388d9d3c5bd6a7ce962394d3f8525bca8e2411e534be6ecbbf50311dd303c83925cddd999f89e241130545c38366522d4eebe741e79cb28ac9c46233333433333c66666a64646256c94aec9564373ff333df3236375f4dcddbd467ffe161797c0d8bc682cf36997d61c6be20f3ad076913283e65125f4f712fd8bbd5b7555b5575eef3a8ea50ac677fe2a9b5bdb853d15792b1de45e6adc4629e6d4a32d6a73e86a45ae69496a9db1ff3e59c1a81d32d1b57c563d556fed34f4eebafa3ac9f6e3f68ad1ad731b69f26ae9fc62a1be7d47c9a5652d3d64f9d1a14fff55552b7ab6e4ff194ffc8c4bac81e05a74d2a1e305e669e9d36be8cccb3d35c6fc563cf4e0bbf63969d063e28533ff6e28c65a7b15ee65f3c2c3badf5330fbbc92ccff7532dfec3c3a2e0b4f93330b6e42e773ecc965566b42553ddf92f5b8e31cb4e73d992bddcf9a22d65a12db9eace07a996dbcfe33f2d5b56962dc7caf3f178b6ac9dadf3eb6521c1348c1c20e780ec3face707adaaa68d454e1b4fd127a7e12ad3d8c44f71fee3ef24d3323631ddae2375f72e5053fec3b62e54d40b7d826a2aae7226ff513a8ab1d5af4fadf0c9296c396979a55ba8a5c97f94beb7e255eb4c4eebffac37b93375d465bafddec5f2fbf7f4bd9fdfb2b63fdb9e65a7cda6a6f2a2e5f6971d75fbbbc97fc62a1bddbbc828eef697dfdf915063e950936d2fa34fd73673d38b97cfab9a39a8692515859bca35531729a7b537a99a3edda64ffed3475831061a1da86105b67e0ae53fae830dbe1061441054d8fa6994ffcca519c0b8b2baf2c2d64f73fe13e40a1ecab85ada62eba752fe339da82307263a70c0d95a4bffd4e23fb76903bf5bdfacff89f21feffba784fd55fc07b42538adb79838ff695914fa2793ffb0ac0afdb3a95a262f789605a7f537f52e5cebf72eb7dfddbd9f8971d2aa0f89f6584515ff61b0b2be9c5a2e2f4d1beb5fb077f173abf52087e2873ffeebcbc974f92b09b333cacb6827d4d2b4bd443b9f467e1496a60df6adfa254b7dc939f04b2297c32f792effcc7f6e283c3f8c9c52e48b9c5d5ce4a422a717d6f3d72a4ef347c169e2f38f22682753cbcea6b6a5cc4e2d4e9bb6fc3bbf9c52f367b30abe3f4f0debfb13a995b258ef5f82ff80e0cf9c361fb4ffd992a5eefcf23d5b724ec6b263674b22d569d4963c7776cd8a01e49cb273255b3dfd92a7a82dd996b3cbb664abeb930463399d9e6ec9565655fed3a50b1595172fe594f29fdb1fc5d8fca793ffdcc4f7befbc207bf64a9af6b3deb4bce755ffdef4b22b79c4e2e7b7b41f4eccc697d7bc1fb723a85f641a95ccbca589c8baa76fc884079b6b2d34a9e6e2175d31480a327fb76da7ddebb9effc3faac16188ab19779feeaaed7088b81791ba6698bc9ccf0a8f9a4a56aa37999272df1d86c6c0d0d199391313c666448598ca4e120f363c8fab15a1c040c6b6c6e38480f1f381cc425be46184ccd746fba8db445df738deb9e7ef8370773b85ce35e56bcfef737f7a77f0bedadab9ce650537846960b1c5b7ff3b1a79ce6b73975e3d9e404c29acaebec6d56fd847a7d2e741c2bd7385c2ee46155415541b1fe6b2a707cb6815fb693d89a4ea3eb4b1e5ff65db64e89a1958176ec26961dab954d1dc5d83e5b9dd6cf36cfb28dfa0b69762b0b9073ca59553faf7bfef71ffafc1ed991569c9256fc236f325fc91b8f3f8ab1252d8936eafdd2b4794d947e47ff567f69daeadfba168bbb5f9ab6ce5b323154ad5f9ab6968cbd252d89b62426116c32bf346d37245288bdccdf78d8db8c5d9a3619ff987f8cbd4d2aa7f9c3d8a5696bf9c3ec14a7f9b3ec8d89d3fc47bb346d9dffcbfecd6597a6addadbe8347fd14ea71b3bcd3fb44bd3e6f9837636396daa7aef8d9dd3ccd129ef998ae7e3aad69793aa658f626cddb3ec518c8d3edbbeafcfb6fae584aae4477a6447ca9c369f92efb4396348b3bfafea8ef44b59f9b79cf5dc31127dcbf5ce62bd7d4104bf5b2dd0bec00a9f3efb4f685f68bd7e3efb8f52d873c73834ef2765530affc624c4f6b22f802efb42f879569e95ff88564914ad67e534ffd02a85e1f753eab3e583560904676eda52d6b24aadb7525fa96539ca69fed47a562cabc47a2bd5be409f6d4a2ccb4eeb9f504efb703d778c44def7cf2546ce2181eb27a927ce2181bb9e37359f9efce766c58f626cb5f5dfaa3259fdd638de723edd9884d858764cd9acf80bec3411aa6c4f3d778c7fdb9673887ecf1de308ccb5b256f6979fd44c629c498ce5e7e459959f5397f9d4b7fca43e29ff994f4ef3af751c65b25b7e52d79ffdffe23ea74fea73e2336ee94d7956de54cf2d3d9cf7e4e13aa82e1d54ec9694aa63a26add9236d128dad4ddd2735e5c8be7bacab5485955b513aea59eaed55339ad7826ee4beec253d6eb7389712a31cedb5fcea7afea32074715a9eb97179066c766c5a9288e15ff52d361ec26e78be9b159695cffd2fc6cfeb2390f9be3d8fc039bdb9bf74c426c9dc454b359712bdc92676ba6b675cbd630b6aeb1b5b53508b6b6b7ee9984786c24c9ca6763e2b1f52fb9cd3b9b8b3697b1790f9b7760737bf36712d24ebbb637fa4731b6ef6bcf7b2b2eeb3acf8e6e6f4c426cfe4c426cb718b7ecb4f94731362621366fd21cf8fec334b6d34f5a7a99edfba4a5d1e63df8fcd57f929886d89262bf44c4d6faa5d096b4f436d6d7e797f94f12d34d28be5c3ffe528e0d7cfe318969664b5a2262837dd2128f2de6976636985f92d9c64f5ae2b179335bc741e6272dbd8d7290f9cc21cce78f215d1c643e0c297290f930f2c541e68fe4c821cc7f91321c64be8b8c7190f92239c341e687240f0e321f24652c647e8bfc38c87c16197290f995ac1c020799ef91351c647e47de7090f994ecc141e63be98383cc6f128783cc3f8a99ad05e8d15f8a6123494c3c36ff256a6ba71d7dfeafb25addf3879dadaed70883f1e78fb111262ac34698c21936c214e3c146986e646c842987868d30e9d8daca9c6684a9deb011a6b1071b6192f960234c6febe7c761234c331b1ba1964536e276ac61236ddf69f3f98fe86c2a9073ca6e0a89b1ec9e3a29f1add05c14ebadb00b4e500714d3101bfd9b9527ffb137b732886013eded86f3eccd7b1944b0b1ec0de9082a64e8ec0d034a503029b18226ae6c371944b0517b3b52c38730b43c75c9c1e6f4bb4f5a0a6d5e8faf55b79f296663799de7e35bd489aae3f134f63c62ddcb4ce13ccc146da2f65dfc1b1229906fff063ef9379b07e9e76ecbbe86e2fe657fc3ddfe9c8b1c7ccecccddf904821e667fed6317ffbfec614b3f98714eab6573914cdbbfe0675fbab6ee7d89bf81cd8b7f63692f6760404dfc6de68aec6dea8ccdefcade778d81bc7622f636f74caa7702c6d82c9be656fd487a5b4875dd2b1d5677d39e658f5a6e66d605ee4f1dd7a98538beaf657279967395131958dbd895f639938ad7fc6de50705a7f8cbdf138adffb3b7251ddbf7a1bd5128af72a886a2b15df53cc5e3c9441e33cf637c2fe6f523d46d575d280e21c40b47257abe100422480d636ff0b0421925c6f9bee3f44b77770edddddd8180618e12351a86620e3a345dfc10c3d02592e0e038b95d25d205e1be42100b1a1d43590c66b090470c1fc0843de0f020268c3131cee79c58c8030b0732618b0576266cbd80e411be154f65a10f2a7068c287818f9a3096450f9b7044c10dbd0963399b1ea10f236a7c846710118387cb0c8be72d3223e390a9537322dca0508e713e75777797c1096169c4ea87231731950c7d60016343191630ca41f82d8d342714a35e1d842010aeea410802217e10be72086761cb0990d2c2708c560521fcae60fd087d00e1e9842d233a2021521312e37ce7aacb5f1391f07750e37c7777770a24a470305bba13864174e5093d2e6690b053639ceffccc3b406a3a3f40a0cd3ef0a0831c0e2cf9383e7adcd8d4d0c878ccc8c46260785c43f3eada24e1b93eaedbd202b608af5e3dfc3aea125fcf2292f18f34c82212d81f6998ef594412c3748c7d0ecf902305402105264fa618e1926653cf3a4bab95e32d5a9ae6985a9a6696f6d1021391cc2ae66c82b7cc288edc1614de64ea59e3dc0027132ea97d7c1ce793771daa00469c3052654a1b56538caabceaf0c1881025108922c2021339bc3079c2822b8e26225a4c1832c5101550f0d20585145410d7984943b0a0c043029e128ed0c152470a5042488615cfc4a5a053021d223c7610e11942045ca30d9d39549849319bbd0c669f336bd54135f322811c26847264630d1e7cb0caea773f4b4452ddb84e2f483a2994735b767eeb33c1c82dd2a8bbad56cbd69b198ce574fad6b784e8a72212f08477f0c90d15df4d8cf5e54d7973c1564bd602bf7ecb96e07f7fc46364949b5b3ef944245f3512c7752b747363be18cb822c0aef5ba4904c268bc53e161945764b16ae7ffdde1391781f8fecc278304484622808bf450ac5ca5819bb2d4a416e9fd67b6194d82d85aeff4796fede772292d0bd1cb742b10b0b613a53c613bce8077e39dedc502af47e0fb6c872bce00bfcd7d3fea14d03fff5e10c403877c07f3d8fafffc872ca108f4f45242f6b44ef28bbe3f82f925ea3f009d7b748a1f00365b2da7a6f916578c177b20caf0b7cd7d719803a77c0773d8b43e1f56c697443f09d74bd8b485ce183e477757555c70dad5078c50767e822e975d156f97018f9bdfb1669e4d73ba8919d9c2c67cb967f5bb29b1bd9188b8de16d7d19b640f0f35bff48b3482a2db2acb7f54e96357c7f3a03c073a7a4b7f5fe21c93d6bfd1107ed90b7ba67916595a1d92292eeb31e299e403b6a67cce4a00890bf2231f2cf0180ff334aa9fd2029891f1b500308aa314b07738cafcb393594408063ac76ccde185d7074808291950608368ca3173433466f8a668391750508698c2214514fb33ad200c20318a4418307b934965890460c52e377830fc8183d393ec861a46f7840c358d360638c0ed0183b30406862ac5b7800c4c892ea800553d0e2780206682cd102348ca08931d6343ad862a4657460c6c802c3832c63ddc28df15b0108478c314e80f0c4c81ac1075d8c303efcf8800e5acec0b2c6194a5db8d8f2410f638d0c3c9861ac29f062fca2e8e089b1b5841523ab08da0c660c7141b0327e977366fc70671c3043cb9d9fc3050f6a9871cbe761dd3c7f09fe439f7f8afff8b3cdf3cf9cffccd6f31f61c17f68cf38cff6f5fc44fcc7d5e3397cfe09e53f391ffb98e757c17f609e3d781e9f5ff6fc28f88f8fe7afe23f33cfa408822deb05e19bb499fd07dfc177e48d55aaf99bf748cbc1dbffff481cabe475f0b3af24cd2a75f7b407c91cab94f3cfc18b648ffeeeebc3480fac07effd072f439256c9929ff33c481f568926f3f56948259b57f2f15978b9207c4cc7d6c3c7dffc8b54f261affcb02989efe36bbe5563afb86c386f639568fef537f68a8c4de9fb9a97d97cec5b1f432ad9c4fee65d37effa98bde236251eff7a16a97463afd46c4ab0bf717deb29a9e4b25704605302df47cb5eb9b129b5bee66dec95984dc9e6e9c3904a32d55ea1b129d5aff9b657aa4dc9e6fb9d66af4c9b52ec6f5ec65ef16c4aaef7f19dbd02635392f9d7cf904a337bc5c6a6d4bdcd07f64a8e4d49f6aff7e04352c9037ba5655382f1ec95974d297c1fdf81bd42c4a6e47dcd8fa4921525245b8ebdf2814dc9e6fddf5ea1d99466fec5fa7ff227a9c481bdd236a5f16fde8a1292cdda2b03b029bdde87556259a5f19560af04f34ab18ff92bd3e6e3497be5c7a6c4fa1aab54f357a6edadd27ca57e257fa5eee9e3904a3656e9cab4d9bc0fabe4bdd2f74aac9fdf83548af91bab646395645e69e69578bc12cdcbfecab4d55825f095c257125fe9f5ae3fe2209047b94b43b2d3f865e4cc69fc3c48149cc63f4356711abf0c399d9cc61f23abd3f863481ea7f1c3902a380de734fe919c4f4e637e1749c469fc22c9c469fc2139999cc60f9213ca69fc2d52e6347e1679c469fc9564c1694d4ee3f7c819e534fe8e7ca7f153b204a7f13b39c569fc4d4e2d4ecb398d1f691ed1ba12017283fcdc73c738c284e25abf0a5cebf6c058765303317ee397b381184ba6fa619cb7ac138a8b14f10f054dfe8f6a4e8f6a2fcfa45d62087e3b8d51dd62d5afbbbb9b54e02245303f14f47abe4530b6a9b856ebe787d97236bebe9c512b98ba8d858bbcec7f2d8e9a358ddf6539b4207b5354546b4671b5519f8dba1dc5b5fe26b6d591868061b3aa4175db73652dc752e6e4d04bfc21309cf3f54114ea5f41f4881b97f841f44926065121626010751abd20ea43cffa893a5b06512d3deb328836f5accb8f36d1b3fe209aa567fded14fbf7be7bfafe9ef39f98a5514eeb87b1ecb40e46479bcbe572b95cee874659772fb7dd8b7b712d5ab468712d2d56fdaa5aacfa55454949494949b5935454545454543b39393939d1262ba7282b2b2b2bab693535353535f534f5f4f4f4f4549f260e377113377113a70277e12edc85bbf0f0f0f0f0f0f0781dad4d342a2a2a2aaafb69136da24d54ae2ef234e322e00fb59c862068cbefd97ca2962d6f7a36653d9bb19ecdb167734eff30ca25866054944b0cc1a828aa16ab7e54542d56fda8a85aacfa514545b9c4108c8a72d9b28ab61cc3a81b2515e54d2d56edffbca9d56255fb7969b1aa179d5c2e97cbb596afcb75aa5a4719ada202499d5b555555552555252525252535a5a6d3749a4efdd3a98a95959595150a3cc5533c35f33a3a6bafe7d3ea55fa51a6fe80538db2060093d314b79c5d3ab2ec926b531c8173458a3c5abba9fba0f97c51e0daa4f1cf6c62f1cfecd234c50880203272a4b9eeb41276fdc18ea47736f98f6cfc88fa0ecddb3f9b6617ff91c9c6b1cbfdbc26a70d5cf3aad9e7d1ef1ec67276995daeff6c721f6532dad44e1e0c40ce017bee1887986b1f0a5c842f5bb23d307a141929b841e1d77cbf47d13e6590f83639d7df6c797d0fa9f17d60017b9c29987f2e314f7ebf77699f92af626fbfdfc5689f3248e639285dcbd7e780742c3debb7a433f5ac9f243da967fd4f3aae67fd3864fb20dbaa67fd3dc8be21bbaa67fd3664d790eda56773d24cd9e43167a60ce9627817e7e2538e854bf916cf79141ee53476b716b0c5aadddddd44aa8f54d6a19792bdcc5cb3e03fb58ea34ce6e57e2587442691d9fd50277573924d5cebff6c39f3d23ebdb47be9597727f5ace7979ef59ca367fd234c25d336960e8ce5f40282b1e78e916f0a5c643ecf8b4596cb392c926ed95e5860753d4bfbf8f45cd3ed7ce1fc5318e2f926b2a9b8083b55d3d7677debc1ef20c6a27ef7a74ced1334ad479111059628ec68ca65d9a245ca072c9ca684e0f2d43e41dee58a1ed13e412ec6d5d597ebdf3e8c657b89baccb5efcb49e54d5eaebf37799337f984729affa4f3b3448ce564bafe93a9a96758faa7b364e99ff6c187fe692184e89f3ea29be8997f3b8d2591eb445eb6ace0d8126d2963fdadb63af27091cf76d4f765375151f97ca69d37a93a8a8b7cefad6e7a96fd6acbff9494df1677529df15f4ad99ca367d496e3d06ca367fe2328999dd481712289930505a5df7bffd510fcd68b1fbee892c17ebc8979988f199a5f24f3b197b132b11818d8f8728921d862d5cfeb6833d163bbab5dec76a7dd77d8c25f6a3d75dbf676e4bdf72fffa6dd1fdd34adfe47acef64fd47ded3efabff512b46bfffa8be077ef7fd51ebfd975a369817addf7fd4bd0763fdf74720cc78043ee85a6ad9446b0567fcdb52cbe6b256705a7fc40261fe1efda3eefb996a6cafbf3deb8fc0ff7ea9651bad151c97bdb1beeffa47fef4996a6c626841cb2dd6d3ee8fbeaf7f3beabe6b59fab72396ad7f3bf2af7ff43dad479f773beae891b7fd0e01363f2840ea03b8d93c538dcded8dfe6dc9b3f90fe11c7d5bd8dcde965c367fa6191b1d9ab4b3f2ba62aab1f9dface02cb53a6aade0dc8ec49f792baf1a5b4d0c667481b0f075139b81195d60cc0b269b81898d2e500616139b898d30957a3132638f99188ceb8fc21f6f40d6d7fd91f74e440f1b9a97752f93592b38b7a3dab2a1b156706e472d5ad9064db69b9a9918cc08fe51f8aebf2db56c36d60a0e8dccde986a6c3ceceda8f5333198d105b2beee8fc2f7bf1dd59f89c18c2e90e57f14fef7b723fa33b1bf1dc93cccdf8e627efcdb11ec5d7f3b7a3df8b723f1bf3f0a9f35637364ec18b31f636330f6066665a395bdec8dcbc6449bf347a17dd08e2dcb2c1b56fbd9da21f4df8e3c1b760821f41f515b3b84f96e6987d0cf7f6433595220fb73fdaf7cb074bdf83cfeeb19e661cfb18f29737a46c690dfb37e1812468ea4cc458a64488e2d16890433671b20b74f10578d4145b8bae38eeb4135280c1a836241b2a09ba0b7422204e5f8d5d51dd7e71060cf1d2351918f21fe21d60fd51ffa7ec8fba1ee87e80f157d53b7bf0809d16422b6e5b39e8865cb9bfa44d596b2ef893e5bc6bc27f26c39764fd4d932ec1913515b52a9b9fe44fddedc6da9ccdc69735873c600e4f629f2bca2aefba12216ab55148645afd758040313f345ee324533333c8a643f34bf48f643343688686868841186e60fc57ec87f08f643ae1fa20fbe92fa4afa8766dbf2f6a4b1a56cdaf279d872e62626634b8fd952068bb1250ccc9631d768cb97cb9623f8546a405b862d5bb2a8d45cfa546a6e2da9d4dccf96df16d7f3efec10ced5d5d5a5b6a45273dd96df16d7bf34f2ae5b2a33b7ad6cd227c09b1eb3c8b44c33f3f26a6c280f598d89c9843d9b45da8e21172132a2b7fba1d7a532c3e2224446dea53f24c2a512bb5d1122a3befe437ea9c844eff95d9e8db5b80895f07645a8d0db15a102738b506951e94bed4dcf66112ae3eda7e2ba5e848a77dde6f46c1669eb47804c9fc8e87b7eda7d5eebf96b6db15ccf1f82a14b7cfe1136fe2bf6fc31d78589bd917763de68e60ebd2e8fe7978557e689a8d0cbe38de89d79a3d81d12e1da1019c15cd91319b52ecd1351f1aecd1bf5ad792222a3f1fa7822a37a7bfccd1bc9ee905f1c2223d725a2d217c736d7e61b7977be0fd2b936bf0749b936ff86ecb836df8664716d7e0d59b9369f86fcb8365f467a5c9bcf830cb9367f8604b9365f866c716d7e8c7c716dd66a23d7605c83e1da0cd764b816e35a0cd768b826e31a0faedd70cd866b355cabd56af3917c4cb7ea26a9154859b1245585941452725f4460031ee478aafae28a10b0ae48828731368e35a717d4000c28a83881162fae08afc8218771e6724eaa885b8eef6b744edd690f358c327777291bae63b1b9ffbbbbf70da3eb724e0a861b5ece5d41c7ed2ee7aea8aa01581241dd1e21c18f449090107fdb2877fe5123cd1e01acedd34dd6f993e79c64cfb9022e5cb8542e5c64df5812b9a38f7fe3e0e978f6bb9c9e7161755688e77a9ee7d93f03acb4769de75531c6f5aa80010c150b1876f0210926a82742d0c515705cd1e50a29afbb2e2d83c7e58aa4eb793ef4522b1db9e08d29b810e38c2fbcb03117ae250fe74ca29e2d5e688163ea06343eb0851561b0ac30e3035dd7759d155bb07458baa2b5250b261e991552d430bb12b028a55356f4205af154831532b8acd0e1735070cbe7f18cc86d69aa62cb16301a872e72d862820f6879838c2b1b6dc1a53fc271691572e8d04ab1cbb92d465cf0726e0b102ab83296fd749bca7f3c2fb3ca9b534ef3ec0b1eae8b6745c5349ba6962a4f4c3cfef37d7f49a47b1b25df69de5447da34807ef79d7da13eb5b10d9ce1870485044c9bf77d47ffb347ded3ee864403e61b245801ce569ffeedc8fbefab3df2fe85a3cfe25c0c1964c1d9e8d3eefb65fe4343701cd94f651f71e73fd934a07befbb299b06d0f79ebe376d1d3992b643eafe3cc0e33f6de3075f4f77faeb5d4fa442eb59df302caa70ab475a01e20b302f3a6883bd5b2414a6c2bcdcf994eaceffaa5ce6e9cc53d807f3627d507c5004ad4d3fab71534e9b0fd3c5a6adee7c5733b55337b5963bbf2389ba17c1fa300f635f807d7db689301ff331f685ef619e6de0b745d2b18f817dec5954e1fb986f62baf3452d777e8cb4f11ec9167bb02389fa55783debfd895468bdebfd871a70033ffcd737e026fef8ad07a7a802eceb4f5185ef611e85a4fa30e1d787b136f4679eaa386d3e8cc4d9d0e974e7cb58a8182975e7c790365e54eeceef4652e634a2a27987868814a0801f2252c1a601ad7f7dab9f48059b06bc5e10fff56c83f9b648baa70ffbef41d8b3a882f81f0c09236dfa916cf5412a2a806d49ad7f3500fcd6b7a882f8af175508bff52caa30da97b5f1774d89644856929dd6226ddca2c01d42974ada34928d9d763422755d5d0072775227c5643763cc47d9181bc7366698819513d440b5851646884ed45063e3e51c1549b0018eded9efd97432a767b418dc510618531da0428a2c7ea82148a25688e7765dd7f97377871b556429430d2f6164810596ee061afe676b7ccefbcfe83f9ffdb276dd8fb8ebdd6ee9765d47ed1af53f27bc9ca30204b77c9e6e066f94c5a8e8c0951e65e5786354d8304367a9b8b2e44d41b798428c18a618c30a8fcbb929d0b8f4726e0a32b8413abf2fc3eb799e57dff33ccff3bc8fa43da39ef7a3ccfb59fb08f15c5a1b07907368bf0da57d3bb8f38914a07f2ad5cc9dc0eacea992e7ce1c0a7077feecce2a140c714b2377caeeb4bad4fb3ec08ad50c99c21e1083975bdbc7610f88c1a9677cc1c9ddaeb6338e31e672ee04572e4f39317af7a5ce0562022f2935c11b9732d9e8c7fa87da28a5b3ac945213b07129a5fea3db8e83cb39135c71c5cb39134071cbf1697b1726f0c10447c891e3e58cf096cb43faa7daf87352545dd8e59c144997c5fe233ddd18633fffa69c1d19eb99900c9c88c1972b1a8050818d5e71e98fb92a2efd9bfee11c0e8793c1463fa77fd8466de95688675c63e45b8eb7dae6fc26c79813a3783907051cb77eb9e5f828005fcc3e77a6902f403a521b92aee58ea45c73bf8d9c7ba2897291eefb3b2e22c7954d27e9144e97a7e8aaae3f38d4fd34724e055d9e6ec9530eb502dca5560ed573c7d8cf391574f1efa4fce7880aa09ac65153b92e5254d75530d534be65e7e5fa774efe43a7a895ffb49414e788102969f5c68e366e8a8bb42dfa7ea8e8b3fec435ff69c535fff9d4a58318dbce2f5c73ce498971cbee72fd5b88b1ac01e01f87fa1ff6e11f0fa54da8c4a9150cb4899a041d536a06680441400353156030482c168e08048a26d7f80114801098b2545a9fcaf42888814a19430821841802000020002030334c0002449b3da1f71f290cec0d6a2eda91cd9c18032ff0dca5a25b87109f947ed71b47ba08981d9bf2eb8274611b9bb453e3e7ac8da1b052cda092de2ca54eb20d304da0082804cda4a1f3c20b1db431f06a0187aaa837b4efb965f92729070114f4bcea59b995635e6ab964472cf4a36ab4b19709c2ca9de559662a421ffc529d1a7b238b3f2aedbd15738daf14666fd4f24795bdb76256f795d26a6f84fde51b60d7db9446a2d08e90226a9d8d122b1a6cb88ea4185e8ab8e828c0b547bbd13679d2e8eb62008f3df7c003341b2a56a1313c5bee8c133f55ef2b6be3a8f64de1d95bb8527d6f859fb221f71f6bcd8b6c8a9d7e5ae19cbd1d83b6ef5dca812c912fb71f29ccf63e3881fc2ddb5d2cbf8e2013a84318cfc5ea0ddb63bb22e7865cad61f213d625e0059b3965d0d0ba019f1b9c8f463543f237858748ee5ea3cc8ce2e9169db250f69c42c4957ef25f05bf927d337805e7a9c127a68ab304437b4fdf1cec75c4976720c5cf675cbc7c9600104ec31deab1daa6da90ea2e68b2d3fb183b47fada1739a348859ad424dfcd9b5a51a636050bdaa24005bb3e09d32a06af898c3ed46bd7ac2df71250bb69135da4b3230e9a600952a3cc8dcc1ef833daf8af458999fb360a2a0b55ccab6b747098d712665194cb54527b1c476b4e091333379dbd6d06867ef58142c14f115b2b940d25b4d25e5dc424683aff6af940c398b7e6d19b796ea7247d57f6f1b29f5a3042643962d66c46aea38ee900a581e4719715dac6a44d115c8616ed20a5c64ae32713d2162995829cb618dba14a67e654b9a7aa0ad972cd3565b969a3ac543a5ca6a717047923c352c8baaad3acab74ac18f070c0da4cd214b5d89b3bab2805208b9e7870c36ad252ece6816850c9a571009a29569705ebaac0e73f4d13750b574673759a8e009465223fd72f4de9a84d861936f12ed4982c4395d1424c35e51c48136a3bb71e1d79b70b521edddfdd699a24380f1faa9b9e956b7b3d41859a768f66a9d89e720e4ef1c4423e57ef896749b13efdcf6ce9e1356c06ce10e06fa93e1305e565f67da0669b831e088c05fa2f19bc2ebf67657f7d691c9ce87d1f5761c8bbe256fe5cb3f027af104fab7322ded5187c0c5e42ee42ce8a270b5b252e3f050235054a7b7bf28ab5bea6c6b4f4964b56e2cb65ff8d2cea2a8a4b3f71ed05c0442127b2aa9aa3d5949d533991365698308826d8568c9a443f916060611e49de48596136deddaaca8651c4e1c762906a01a1b40da9f7888ada2ba960e322b592daa3de0455ba1582813a54d77f8d896cf131506088a9bba9f2e218a5a46f5ec66a4faf1697b1753c30fa2d759189369d38b8d6059246990ab474780e435d3f1772b935304f056102dd56386b9372ef6b781125778254d44995bab3eda025a1b15072bad43cc1afd5682b16ce25195ebae8309c013ed5bbfaa9c7820349259df8681249971dfd2c01ddc3db884b424f3a0126be38a999dec88aa3d05b904b4bd83d2ee6043c1d394cfae52f77a340521e074963371f336152fe576a72774a16cc67fe0188393e5257b75f154c9409184dc7882e8e76c44c617f8bbe191a9eafe4d9243cae15e21df29d5863ca452ef3245a288ba66b90922243c5425aba5c8c845af81354dfb276445e7638df27521ac547dbc3cba9a395ba982649ee347c062f49167dbeb91b7d93f4daeadffcdf3b893749e28ea96747a2251dd12dcddf32d81258ac5e1626fd71cad511914d5d789326ef8c6c39e122d373d120c1974946253fc4bfb63eed5e467fba65f46440959dd836ea6d27bc4a21e599bf34788ad8bd92bc90f8902deffc3049c8b70c9de0629f23c561da895c73531c7471978f3e349ec1402aaeb5a6420bfec49334613ba38eb3267466eb8ce8d59adf4b3e7fa89e2274c0b2c1d5e34047f6fa091d695fe9d1064ba530cecb62fcef245c4b8f43d09f1cfb284d2456bb7aacc819ca1888b7dbe2ca0ff83c8994bef1da1806f9c27a7ebb01f4066e489df2076af97793f05fc779fded8cc8857e1fa2017d627eeefda020eaf90d931dea0bf2ef799e2b75c10b0f8c339059b86124a8db6a81dc435fb43b9890082202d636438c8a86aba073f75df8e3cb00f25ec6f0720a6cd342f71ee185cf3ecc02d4534e7487cf64be6feb6ec18d340400426452f811407ee619e2f0a440bf0d20f1252a42c6506345663530c1585405f964c212073a6ff8b86b0d61a2ae9c0511f5e57ec7bb433e6514688a56697d15b4c70ba4dff9ab8ba44f7a83dc758e4cf30c54e781d89513d83d6c9915014b882ac53f346c1c4b54bdb424b3db0688c95498cb9cd1f3912197cad54afadd7992b8f40e38baf374eb32a5e899740e46de3a43a8f39bfe7c9f77fb734e886a2212d4c175032075d54e4f44663a096901c81b5d71042a0f83841fc18dcfbda063064b2b09936097c6d75db9116b120847d2f7e01baca50e9ee5276548f69e0b460954143ed52ace21ac28e0c83f9e3d68202df581b25a558ab3dea6f7903571f32706ea6f46e7d1e53f6d15283d8ec329093f492b9eb51e5911020f4c6275593de84cc4fa54886d513dfec010bf4ac8111316299d70238b13cb64835f4849c7656d2e0a85cbaf474a1b9ef97cc84dbcad93e7bdf19c407ddfbbdfcb660f84cb303a705bea1c8ca65fb7955df5a2799b464b5499d4ffb010399475a9bf24a1a5aa03ef2c7dd2742b2336842a1b2c0ad87730a7c4ca3f80e15e3855f446d650449477629f313c4f6fb4a4217a4a3923e2f24408ec1d306fe55d3ce2f2f74536516422b51e0064cdd56b59be5baedd1e0d3f181055d0133f7cc1fe93eaa5410f74a11b148f70902a9f4e2676a6b4ac09fe8adc5f2a4f92aa5b8eda56735b937214772fda15e585d2c2a28777e3e755039e14322c5e88726dd471b446e35431e4a16d93141a72c3cc5fc1e0ce7731033d8ed114ad8b28fb8134a6a282c1fc20b6c5bd8caf1dc90d42bb6a4b01633d71b7b117faef2ff0a21c6a04c3e80736d1bbe6e843733cfd43091f91d2457f54f5355960682c21079aa9029fd89d215e307f6a4302057a57c42e62e034e52adf29c32f54f2d3d99d80053b9635ef497c564f733fd658c2b2819f189c57e9ab1ca23f1f2edf474eabbaa0371d966c29c6a30ec7cf09e866b7f88dddf0491ded82d9750976336d482c070633bb3b74b3fb1bd64564faff999dc059947cee8bc9d7815955e5e7a395c65a9988e184cfa2aba11d7a67263257d80c86466de8f6608bbe5ce27fe78cec69c143a2f2fa3064b76765d5c5d29e4f467b4d60793bfa8711d61bcd37bd612e548d115f7e3601fb39192e1fc068ec54b4eb8c9bfbc03f0d32c346d587193b8ea03f89d7c3b0388800ce66685019b0302d438b54cda15e038f79fc73f15bba5e4eefa3854b37d6ed5b9871a4c68d574525fd6e5007eac2a7ab425f0f09b43d6b8bb407bdd007d57dfec15cc52977cc66dbd6aad4cf6ebb25c7c66c7477729dbd1e4102b4911dfc436e9c29b3aad343aa41ef334246749f382e62d8d479cac350015db653088a4e93b24be39fa1beb8e1add7776c9826d28c4e8a96d554e4e62560277dd21e413f73e700c1b10e90a442a210b5c402d206d083c21b9b9a166ce94ac1f82a51040b1f3125afd009698a7b3faa49f4758298e68b352fbaf599bcece122f88bb819e604cc23088b88bd725c06333d184a2fe4285c4adb755ee942c78e0dffe0ca705cd465f6cf41406053e51ba9f5d14894bc014deaee964462db16cd2b60296041e8c4028d9db38eb6acb9a1451d6f72e963f8a96bb4ca7913b7e16a174162118e1d94dcb0593f660ee859b9736261b26643ce67ff9f7cb76152f0f222db9042a421a9d4b642938423414faca9aafca9ac52a4e42fefe1fcb3a9769c4daabe989c05ddc21873df5c3296475701c66f8e8e05e3e4626b0bb90c5c81913b61afcfa5bed9f78b5d667473e9752ece61a6b78bbdc0c0f572d765d9e2566c5112dffe7a7967743bb8568337ee2c091e2cd153c350a1ef642ca8e59a70b18be35a73b227334de8796aa5a5f908ce82566553f0758566843c57684a09a19e832946a089080e73ec42c0e15dffa5d3fc3a22ed6eee702894ef04c694441d3882bab5e3b19b77bb39b9134f94c88af0dacdf39e785c32ce9e98219758ee795b329c4a3283c89609c765679600e120e0da74e43590531452a8370f7acdc890af227ef833ed3f89dd90c8c4212c55c15753ebe2d2d9f8d70034966d14f77a869443d5e7dd4f25387ce285d9fe78cffb02122ba74e6ec3d7316672bde6f746497f635c08deb205c8fba9babffdf05937e10c0ce4b7c43971ab6ccd20005665d40581912a831504cc53d99e2078a2609b21aa271506b5435301ef04c6d6457862dfae833c81651b0f1ba9dcc52a791f2aff85393f5d68a7855ab398698775e08463158fb97bbf52eb4ee24fac01c1a5354f3d257ff4745dd952081fbdd08ea83dcd92f6ae1863a07dd78ba04d4290fed64b1c6014814cd81c90ec593fd8fc8c9e66b6c4284518ca65711cdf049454e5a59a16f34e93c1fd23c2445da0b891957c66f9b7466cbc1fc32b0a382351bc5b631b89834eddb2a8d35d2c4f2261733aaadb940cfacc87c0403e7d8ba238d3f1314c24f4941115f54a5041b2fc58816ae3864ec399039a91f8502577fc5e9918a5c0e752ab49da983b4b752de08a80bf1d76cba9f556393aa8ee96a2d9d76f3a8fec390782b9205334370d4f25d0f29510e2f471c6684044fa496ac299c91e9cf4dad132aba8437a109d4b188b6381dccd4af3d725174dbbca4ba552a85440ef9cd9a2a2ce1b0658827443de4eb17e69e3ebd75c3eacec4710b3ee4c188d391abb468db4fce44553bfd415f77672ba125a64755f54e99547dc8ca391131c80eb8b647d9f2b18d07b17d015be5927b2a40a66bbdc312e16731e49afc6efadd90b887593c8f0b8ab7c48a8837d2918e7b9b2ce4b12cc5211481b78b474713c641762d99a8aa0aa5fb258a62a393fb6320e78f168251db5e5b57aeb0d02ea9adcc80d00245fc80b9b1000f99ebffebcd30bdfd3fe403aa53a590a57f94ebb7d4511a1e9e0442465b695f028e6eba26cab08cce4bd653d01a2494db4487a3dcdc294f84dc59c341ce6f57c976863b57e1c376cd23fea5c09ae5ede3444c64404597f3f3700f12dc40fdbfcc89cb974adddc12545701f469326f207c133d0e620693202b01a031c8f102835953a465db484773104294f553ce22e39a560466b228950fe8594d689cadaff46a6b27f4e6e6b26313ac6365b1a27268a86e41bdb58d392abd83920819849a02631c279e96adda9889d39e3be786535a4ead7082aa2641d98820623ef3a77bcccebe6adc609d7d2eafda7efdb410b95844a8542b575d27ccda880f4c430f8c40f9ca179b09fff92163c85214f868e9a91fe9dcea6fdc336d507b73aaedbf3275509a8ddea008f3a04e5847b6ae6b006c7b4655231cc72021e81cb57cae946139c848cf14f3eac4f842b16b066d8e2354def71ae1498e3b6dac3375d7f1653a41de6187acfef508754220543135350ca52ba889eabb99aed267c66d7a7627acbe02a279711a81bbebaf5eae1c9133973f49e66f9c6835bea8ee90033c0dcb5a3dea5ba9d7c3a65c454448d6eda84c84ecd37120b0d8e18f3bf1491ae04dc9fb8a980d92486aaa7ff1795f166f6ce68079ac865491a2b63250b5eb7728acfc0968cf9f753ed242c871a6a4d98c43393c93d281ecf57fe38bfbe7df0bbf3f5cdd764dc7cffb471273a2c76a9810446a1c374f97bc526978649b85703a35e6a6e02429332ac0d99f08a41bbea26920312ce7a72d4ad4bcfb2682e1d1de0174d36aa0d34abd484d402463d7916b493b31c135971183a4214ae08f2ef4c8d5b16e2ff523225e1d5e2c263d71fa0b1e0e2b9739fbc53e46261cd3e6f7430c2baceab7dacfa6e80f3c78406efc56e47a642c4de674c8b5d7cd35161e98669cd281daea8be38ce44a3a790012e4e78f2da5c1c0ac58c0340db48d6e7a1e13255ead70dd2e4a27c4d3af4bb7a517290d679628884204515a079c8ae88ecb4681903a942059fb88880ddcb8d47415132e20251249bd05aa612adaabd5cc0832e680c9faef141a7ee4abcf6c5613159737bc49cd19fe629a5f1be80b35cf8c79d78d591a96cb121569ae5c61df116e892e4090bded4b1b15628c1f85e2831f5414c8d0aadd23e8950c7d3694885a57ace181a0bd4b93dd6742033b4b982c5cce4c66586c3f3b1f682a9ef939a64b197e260b6c5edfc670847719916f30c7127d7b410344119fa2c0af3f72066cae9a77af860fb5ebbce040579efc9174301ef5ced5da526b5f20689a7905da5c733fcb7f638ffe874cc977a9d16eabcfd6f82734be5bac2249c28ebcc59e54a2bad5c69e546c0080ed310755e92eaa5a74d9537f8921efbc44ac80fa2a7775c46ac323495bf245eec0a02e64b99e2e6f0acc6f7a2625bb6d81124e2f7c857d09d08c9f065f0d70d78e3aabf2c8fe93268e87915e7121768a0c5dae4a80b502002d86d462394dfb084145326330cf6ed07196d69bd5ce3dfbbfbc629e78ff792c4071317a6dd87cd79fab4f436a6ec909a98233ddb29e058b802a16b4c66d537bac5c8aad17412ae3d0c3f3a4f663dabb21d51b393a96c23e41cf7acb5d10044a7e8146bd97e9f43dba6bfb67fefc076d7826dbf2fc01672e0762c4708c5cb2088307d946e52d7cb124cf662a0cb003702adaf04c0345175b811ec78bcd83989788f4e1b4389789fe4dda5ee4d74da8d54fbde74852312ea0c790ec4ce2a98a419d4b735def0dc3f20e6c0177c1f676532c82487b1d5648541255404d0cab3c6bbb9483628e098e6e823a18406276b89152fddabe3ab79a3fb063e06277a710a31197a50d815da9ba850d8633da651e85bf2945d10f58d559a9eb2790fdfb65c841e04bd5afc866cfe55bce1dd1738d1d2526e04e7fd7e59e1a35302c3511cf560c8fbfd080e1da8b05137ebb0e1ee3afc97bf49fc18031abc78bb60536b59514be897565860f2b22db46d52daedf17e0476a962ca623042a2a79ef79b8f2815258014be8610c01b17c89c7a5111ec4bbde5e67255f7ff18b4ef6a23a5e2be22186c1256b5b985809773e3ed2de021e8354add2140e28e298e31c7b19feb0c3fe768aa8c33f9ff2c6895f2fc12c01713c7147e1ed5238b6f429e70f6dd475e5f2f26645005e23ca1bc15f2872c9f985331550a198863031a98da57103656a596bbec59350157ea33a60d0428a78d711bd6a807d49371cc728c1abfb8a6aae18c34d0b2b36fc0533f4c929d6d01572763904996ed490ff3f41c37a44fa6eb8993050330e71b5463223bd8b53788cf6f648d7d2db560290c1051e6450723fb978a0c213f0bd1af931561c271da4881e8397c02f79b1a75b67db28d6f6f20051bdda420fd7c4612b20a3cbf9778f96301c4a70981940a072d2f16feae28627b44a64981e84bd589c105d1406eacd04b583fc2d78b2162e5c2b6b32026ca2794d38464d52211b47f2101ec587dc58e470e0b8bcedc70e31f5e02e2ae12d31f99fbe766657e943ccabf125d627343edde9df62e9de6a5b5838121e3f9fcb21d66a893986b295dbb78e95dca72a153110bcbd2efca9f860203b717b06e1b2a2640dbd133a3c80d3b7f474f176898ceb2b2772e0dab1f460367f61d11795fa715b91d3f17e507b47031d7a432bc7861d1f45db58651491bd0fd197a30a51ffff9fa2ccf40e934aeb4dcfbef2fb76d4e74c7233840be7bb858202832b39cc70328959c10045cbb234e06a2c1281acac44e7a2f84c7f7fa30f4308bbd045612a72f1377d55dae2ba29ef36bc95c195437c1a2cc4313c5528f6790c9120f38157128e41cbf10406a72b85e0507b7e1228a3f2a80e6b85d29554fb1872046ed90deb2d0e170023928856dc52f3671e60d928cf63edf42886fd2d4bcb17359f59a07ce5048edf58f6fd55965d770220ce1fafa445a0c11ddc30c271540d3f8135d170bdba4ded555d8ad4b3534296f2b0a762da4bea83d60d89373d5c742bb07c4cfb76c0b823edb23ecf1871ed27300461a3d38e360ee80d2e338fca6ad682b06481e8e83888d758f9c4f37764f83d8ac023944ead7e0a5664559e8bab6451b120d42088dce7ada71cf4a1c3bed6fcb48193d39482b288abba24643bcec7442d5759e9b3094c52dd1a1390a166713d6a0a37b3c7350481b187e25d71cbfc1feafcda1eb22b5d8730dedcf9be91adb6ecb16144a25631a496c5c66ebcee41d00b4640003eb9b1d394f5f8ee79736e2929ce3791b1cc3df155e6dd80b2bc7f91ad13c1997874e15ac12488acc3f4b56d50582f0423087562b03c5e14cab16d17910cd795ed4c93e496aec1c8e42b259af81988b6fa1b51a5e488049e14d63290d30463343ae3cf120486af08f1c0f37fdceaa01ae14858b4a7b33a1b33c1a12588bd226edc4b4b9e1950f63c6c1b91ed74cdcf08498cac054231dfda990740021df3369b6b917e083f70bd4650c5f4debbf50c304c2c02920f1ff289abb20c24c23f22a7fd0d09b3913960cfa389173cb50b1f33181fd6abcfb34618c82a073353a14dae776fe127aa44a747296904b4dc0cbb7d2462e042552d0f9a7770e103a780df978a841f8cd6e4d18a91eba4e27d15e4e2bbb5fd1ce94b332fc4737a572399f759f2d2de70d92bbdbf391252b54d4f9d2a85d6aa832c5ac0f259bb6e013ba2f6d387fdefbe287834c341e91eaa162ea5470ea969e6aeacab5edc457b0bfcf526f0be7d998d3acb54876ee31fe93b885ca08e03fd1101a9f6283b664cd8b66f7ae81af8c330f168269a3a00a2c0835be103c2365db06607e1b80df50733be2f24002d1af85080efdf2891ce24b98475708d11c44a9ada84e8ec23e5b6540f76a277df5beb0078ff182e145082c0b48e70b745ad2651bbb70bc8e4a44da8bfd261341f8b1b9f0eff3f5bf8f4cecb0fe8637b6414d0fe7dede56801b0c153b3bc732fe6905419785c47e72f5c74dca782f222d82c987d84d46c3f83849577f2f1312d9f7c43231455d231806b26dfb51d8ba02fa1be8a6899e3eccb2f5296a1ce3657f20cd4173ab6d5c6642f29621cbff6f5f3ffef84151fb5da5bee1f5de807e861ef139f4b5d0c8eb07ada9136931878d4dbab9de4a8a783a8672f17e87d089e3d744b63154270cfa78a78fe1cfa704129f5fa478885f56fe8e6cd20e377c600fdf148f36798aa837e0bc17ac305960771d14666f739edab5822869e9f5131173b050a24d269c7bc12eef2af6cfe83165b10677ec60f740aa0e14e8edfa28e6412999eac68e15de1d1fff9b82492156030b289ba7836893213fde4d4ca4d6489c2133a8332edc8f8e483452c05ab127846b65fc5930b858c4f6fd0adc85e18fc675aeafc65d9b9ced088ef36a8602b422833128d4263be2cf94612d8b6809da3fc68f4611417b55ea332ec007171df88497c2d16f589402e30bb79ed859d31d9d83f6904bff7f2431e7120b7517bd94dc57fe1ccc3965094d4c8e8be8a2e5481b575cc5ec4f76122c0318b34f5ea50322def9c366a9a9956b9089d7326c330655b82edbad92b26b29f2fd87ab40b833cdcc711dfc62f9cd7bf9eb0738d4cbeeeec7ddd4b6015639ebc1f7d1c01f716642d54edbb40c3a5c5aa960a7dbe6a063966885fa62d49b28ea00681281ccdce548ebfcbf26e751f1b299a8dc3c21023195d54d3347bd3ce61a69da8605f89c6d161737efe6b5e527544cdf3827f3e62ebf33a7d7520031b79f3b8967ff40822c9467bda6d2bf3c06b0e5b42791c3b04db66ba7aa48f10424ed7cb763ab0cffab6af5e679af3183869c74b4e2f63d2ee48f26712972c2d4e1e4849dc4c75f7a3100f5a165f5e15697dc70a5a3ce1f9d3998e8ee3e110c87ef83a5fbc2a20f64abcebe87293ac719fe5b20ac2afcfa7dd558e9be395d0d972a074512b12391d7a856e1eab046b1542cf803f928923f0350a1d76efe4800c91d65eb9659b051104f7163bedae3d2157fade540eccb48e49522780ed91c88b4882f1e6d5a9e4e956859ef320223ea68a57c7bb565981bb56086007e70335f42c08ff6d1ce6a24850a91251ccf43e9b9617100fee0f149ba9b3bbc944eb403286996ff9774228e77b6f9fcec469e0a3704fee9f7077cbef9c3e93117f8cbd5d915b3c53ad34a76cc7decdc8fce33cb69fd1a3db3d11f9963ec58c302e7288290b5a3614a0be453e048ac50974dcbcf9dbae46a11a2d01ba9d9493d386007defb4108f7504d77601c4925a6daad1c5363942e014ef97b2e7dc4a6bde641f4abcd86c5c178ccae69e39aed0f09980653a7d598a67d87587c06110e005a754854af55ef79fdf2034e5efba7bcfff842e16cb8ad4f524331a30ed6ca4b7d121bc637b804f90307a5c9175644db5e0917add4308549dbd5e51a4b45a208df16be7b50dd54e58545da5ec79bb82174614fea40bba4e5433357ff87c143611e007b7ed55347838820b5364dfd7de952e6fd5bfb344420f8ecf3370f611f1b8ca86c9f1dfc5151f5c3b3de30d55ec60359d2292e926c6a7595f5dbc7300730539f47274c2ffe43306cf8ee6bb2b18693b1dc4095bda26f3360a7d247ec03d03693849c8e3f91a802bad6cc4a9a4620f93c0d3e1a4c744c6cccc1d7a9e955431c43649497d61f3d162d53379f79cee4cbe6bcdc2d61751f09612519cae44ba28c9d9c481806c777a2070465aa43dc7b50ad106e6dadf39cd189d95d647b22a8ca6d931d7cd4da0bf9fe28cc59e705ee3a7e3368e5df8e746a0540ea25c8e769f6dbe1d9b5ece225b7c796066500bf6ebc057520700e429d65a4bf05bd72cead9948242ae7131f21941a627a08c6ee5635749207777ec455eefce4c13a8e956b4509c4a88bb6d7190c73399899730719b5c97974cb960cb578e885a1e3d1e1099dd25a1565d2e3cbce28987d10a8a7d9125c41f0163c50d7bb3bc7eb4a9bec9cc4facbcc08e202dd50f820bd081f446fe007d35b7c60d01b1fa136a46e92cf79aefff226dc939b539589da8912f1a6b4481dfdccad4b23ee88ac7312ca70d9b3f2073aa1a579d8fe7573bc7fa2bef54c696c6fdf7e78d4519e4c70c0c24eb83497faf40dad191c6e70faa3e93ef1d4c0b9eb43ec8716fdaa9ffe9f2dd04c99625a72e36f9ac234b0b681f406702964653482d682f1f31fef22bf1fbfcc0abb32da30bc7887cd6e1080f2d610fdc3c070a05da2ff98797c02832842b37a31486af908247de748b1b685700e2429d718f46ca2b34d19be94d8182562464ef17dbbf66dc9a516a2ef0715879561d631f86bad67db5a330f5d3143db4864349b4e5e439e6a145353bfca7928f2feace6eb5e4f935d923728bcfb8b800028ef0487a83fbe1b680b9a91fbc49d1847f4b0bc6d1d810bd1501affba3eb024258d5b681c5257f7bcf598307101af3bb497916507da43ced9205c51360fdcfa0ec6f9c3d6907a49c3944942ed6b1403321c3f47189122d85e842c1bfea28ac0f786ea654cfca4badd50bc7521af9093e0bb0ce3af8d27af12451912a7e03f9ba0884a04a6f63c436d3e690703b53f8016f8b6c884824a342b9d4bd811eaa40f474e30e1c54b7ce52f91e860f07616aac89882820a69da2f20aa2f5a7e48b6ae869c82ad837cac55af7c9e5a685474730c7618be629379d8a54b4bf5d6354c2dde2d975fc749a699de5bcf32dfe13e06054df534d6608db699e91390cb95e39778d8f185a045c9a6ded78cbb8bebb23c9a1657a9b4865c78a40a224b6ca1b7e087d0ad7113b3ea9dcbf4e5c377949d01abf2c32bba86950ca4d43aa3e271cbfa86608830fed8589fd5f57021ecbd1e54da6438a2454ef04a642a9fd42f4fab6590527517b7dd68956e86bbe299359914199efaf4397ae386da63f6c14e4a36c81f054218576a384b5108b23cbe4cac271234053799dacbd91adcd74df345dce2345c3a9707059cba4dca3537d37ee0ea4cec7a8fe6a79446e06814c687a9c68818f439d39aaeaebcd3e2cfe75774397f32430b66bd3877911495c0b90ec1f01cb2451211e8fac316c1084aca550cac2d1cf43f788f935a21c0a17b13f88290c543e6931996c1e25e5f1cfd818d68f1d718a14012873a7568e4a9c3ace3871dc91a530c3f8b3c08a115bbc421eedf719a144536195e12bdd800777f408e6e9aaf1d3b1b0bb87ffc3c94e084a0819bd9d3abf590030552b44ce0fafb924615dfb78247e8c7fee88ab90e7e2fb0f2f3d0369979b5e7fa727d6eb82cbceccbe6c2cfd363a489149a724e02405120bf626e544ca0fc97abcdba3054a11e20cee642794a24f5032853cbea21072372b64424a011e0df224280a169000737dc72ca147dfb1449e13e8e677e24480e70a695a9813dcdc5b1e3b94335331815de9e233d6bb925f0d7d308a3643d99d31fb370823cab57677ea5ad136b1b45c389b3894ae5f5d2f3b31d2ebb1e1d08906819b867c13fbe7975824bee474b0ed6c4081ae26e36685abb04e98ba00838ccb34b2f802a02014695e898ded7a225c4104411f9f92120a301c48795bcf49412e8bdce70dbf5198df4dc5113a9d52dc7ba1289e4b06191ae36940f6b13dfc92f6f18f669e92e0c3d5136c18859daa4a2557298b148187e29d8705f06809d260a3e5f676e2316ab31df76b55d641610ff61c97b823ed61e45fb25b89ad18d96d9168c1be55674a901cd7174e0498f1a1959721c12bf32c59a6d1b0b7acc96e006f714aaf451669379fb9637e82057cb1e8ba710c43ed117efddc17d4b67ecbec195561f8d195d0b51a654142b29848324853cc777a8fc1a561382e3e232004670bb3cd56762ae8341344618d4d47208f9ae5cc52718b08f889da9a97e06a80f700af8dcf73618428cb7379e7c5b5052b59918b751a4f32224c61a66047a9d609ef5cf7252744b2127b7b0dcd7f4d8d13419201b06df235b024967dc87a922b4aac44fd1ef94ca98805203aced89ba43710323d67c2ffd03dc483c224fe43dbadfcce5aea24ad2bcede482b31e9ab7a13b324162d56635f5aebac9329954e1d1636841199d58b8b0842b667111739611d939f35196b8329c0015252758e78be56e19c3f1d6e7b73d4973a07edee1c8f31d9f1d20c23403b2a69d1afbc501a68c5d04a537f5b6f7f7d8170edf8dfa4ea72f16891514b5d8cbb41345bf16564761d5c89ee29274db5a9a08350f6a2952bd1a9f8631b85a59ce5d056e32625c6c658d19dbc973c83bf165489269f42f7c502bd3c52ebad09cd44b8ab5e1762a868c442724e615c2e6aabeaa3e46c1ab7e6104a9f8312b55e914184f51eface583add07f9da6228d3b514c31ddbaaca1e2c5399ea3000df3342ae2ce01dfebf17217421e038494c4b3f8a52cb91b36c77299fa336043a349a2a5f5d4896a244afe4726e94f2f1cd02e89a8cc400eca22979c08e8fbee7aa0ead455ad470eec33fc85211e56fca0e18f50dbb16823a543c0268c73bdc87d7a13ad4465e7599845368875b45e64e77f9ac29910108941c4df04224bee7e0af26808da05b6f30a0d558ff366302d5b9441918617386790e390d43dd8972b5025c6c003aea8906482493b7eb6987e1c89e66b4cf8d66a6432f225636563d47896aa06320b538703bd7233d2d1529cbe7c7ee2dd4423412b1455299adba9e05be87f440f5e14012d7e44c0a70f243ea516758995fb4641dad229c4b2df55f4ed2569830fb84e55ddc040e7687690240734c5bc05981b9d3ac122aa490e35b08dcf2cb5ca0f9c3affeeca04cbdbedc41302e1f76e456709531f609d1747f497efa36735819d20bb73efffac7e9eff52b0b59e4d3378f92827dfd5044f3097f927bcc27172a13e535873bc7ee971f36e2991b3e5285ca6d09c9b166b6b2383a7107018ab6b541699593207c7925a0c5050de446612391dac6b634082cad3711cadd66844153421af90ca6ec7a352020316d835c08861f77717622817ab926a6137490c2df60c003e46831b23ed3539f988fd966b029475e30ccfdedaa30e92e76fdaf4b1ae25e58bc6623d7b0929aaeac3d7481d9575a46aeda762796905a64186caeb0bd257d996e9fe03c602b168926d04f5b3968ef45f001c25311619ac1114e23fd8b1f382abdc0b49754ab15076aff23f4159bd0fe8d8546f24b812f542c1fab63a0b775563536c8fab6282a5450a59ba64521d033718dbbd107e388c2a55fd0e4711900eb7ffb18f10f7f17ec0bc10d484c1f998edbfa3218494f575857949868393238dd66bb50341c84409381a5c5858a3090a9a5e3b58533aaaedaec495607d3fc465dbb027d826ee187dc2d706a0e058902d099e6bc132daee3c5c5e197d20835cc6942e849f9fd7a20cb3c51f707a9caf9af5c11c19bb3a83385cc47d78e1191d231f8ab3d1d9e783c7a17147e14f2e8cafd98a4cf8f1f9ffe7b1de3e8fd2385fe6e16743bd53565ba155d8b4f40320b9581ece0b38edf24bdebc6ba75c1fcf395c07a846cdd367357e89fe81b277ba6c89bf63ea5ca94e4784b72e43615990f0c0d770aad51c735ee622927c9ac3672eb2a61cb3aceea79f601296b9ee528c6354265d92cf2e03311e97acfc850799408287c1e6ea83720320c2a0e42edff504fcd6828da11b30e5fcaa543794f068cbf16518f78073053f5056c69896d91d70b7f471f180938f2178d0d091153276065fb61fe168fec0a4768f2e52ec14dc5c6281026d6bca4897d4a04f074a38b2710160171b4d2dd41e0245ef7da941f11e1c2d79d6ca006d018b395bfc52b92cb4473910a29ce103749da71e5f1feb322497717a0000ecda2e68e412d0ee340f70aab402bc7fabf24c05ecfed15496fd39a6b658b6f098bce75a34662085a725f364e6fc72b38368ca87693e2ee25a06cab2f13c10633ad73b4610a0edb78bab3efc06f38b29d3540aa3f72bc90efa1e3bf52e0bcd928af40844e9cc78b7df1e7d01f822e608089c4007f1578090ec3b3c1e9b25b89c2b07d48d6c7c7fdb0dc4b3899a32c7456fd13a8082b44dd67413911bf6bc98e8502520b8b90edadeca68de6641375b4cb4535fa9283490fc18de9d4df6e03e9b66b13103cc9ba7d5f3536e4e8814b5d70c2f01c7fb69161128cd4aff928ec7a4ab49e6bab1c7fe7927dc7adda2a08f0d1c37391d73346781c2aefa346499ea2e5d2ede2108fc44a03a8c38166dd0c4a95162db39cd9b834c7d804c4d3ab9eb3635502deab599d5bfb95d72b59c90614a5b0d74eaf9cdfd00982b5aeaeba9ccee837140dac541f5d0f80381e1a6a9730c4f8f7e8b592c539f96e73b7516b998db9b6940b65d5a0f0221eda939af58f93e7d77a24b06c49ff53589f8342ac16f6fc94ff29dfb4a585afee9ea933122e8981223bf3efd4af410088ffca42ee334992d706f527a8d8f9989af067e5a9a2cb1dcf0bea18232260654431dd51726d2483c29add94c217d05bb8f8df072f3290689d49212f3cea2fbc337c2c0a9812ee72cfb1d7acb55f9c35d61e5443e6aff8c447252f4aa7a1c1a61c06ecdca76b8edf64881827726e0601e59b5fb844b99f7ada63a13627730e93ec90310a41ee5c744b0c1870a1844a91155f0f08c4e160f9e8ba0a0decef6d6ced168987d707bfbb50e03073924d44e4238f11b1b9002bcf11b746dce92af119f877e66bce32ede73a19bab999413994040d76bc561c893cec7801149659b8ef301d6256931b573ebcb4b5ce0df690b72f8c242a9586967dfecfd553b34ac214c3dae889f4ff465a916d8849cb108a4dc1bb46d2e4753dc85642762e9d4283287ba83db9657a2e62004f4b0d620a89cb1a8784b54e34aad099ebc1ad7da627aba9597158639a5bfc526e68674a278d7b0587598890192478083dc5015f28582c8c423d6b7df57e2c03e92f99a19231ca14db9243bf11a8bab0a0e52b3bd1d4669e67461f34c00dfd0c48617bd01416c725384c3ab741c7f9c3b6da7fd521d4298563ef8353d0496a901838de4541b4559cbd589b083a13a5fb626ea4c8c042f89535ce839ab143ec88a50e3db04b581c7278f551a8a0c88f2dcc588482abcca00ab84d498b8fe29b401bbbbfa42a4cc226c1723dd88090ae5b22ba8917b5a060f2238fb5182ee2d41fd51783b1ce5e08f16626f5150a104e8d63eb005c41916c3b78ff58b8c4eba0dbf7ccec9aa6d2ccc3187a3a3c3e57243b0440e80824362fcfce297ae40bf0dffc84b19e9a44a14ae41cb024b9744ab18ede9e9e2cac6836fdb89bfc895a99275fac83c1baa87f0efc48166f755a68405144199f467d9e57b559937a996ae5a5f18f8295ee7db7a98a459850aeed35e90a245a0c6575de32d8eb0a2a7de98741e77e219d80119beefd82086712390ec8a2a37e78aa88704aa86a250c2f91d85cfafa9debbb80f82eb54509b6bbbe00e6225374e4a47fb5554c833ca88ba7eec656e9a5a403f7c0843687d500d2e66659f5ac6e26a922e047d0d0c9e25d47b4e48879a0caef173b279536eeea391eaacc1c095d2bce4f5e1a700839dd29cff2c1a158d13d28883594972f14f4bc943dbf18c1486a472445615dbf93f665fd7422e5b5382f6b9d148d0608df5f9209313c53139c979a50c6ad89841cf08101b2c6a84b18fab12f08fbfc2ca794c2c51817d67f36a01b56cb36ad8911d2fe033cc1359926ab888be8b04e6456ecd63805422364c752783210f6ea0dbfbf1607c35e9d40945be8d54d4d7fc90e7571e20cc7f8bda3b6547dd170a3e917606cea48db513251ec0129194d1342637a7ba2387ed867bfe195e002436a2f8f93fd2e79ed9eec513d79d2a185daa39101982a301e09c7c1c225ac2a62d9a3fb42db993f9a3f774e321c6843008dd08f367d3ee56f0543be85e04438800b0a64513803b6ab4a312663f544386e738e6f443e3fc04d0a4f81269f1ce79121e9f9466cad5c5eb475f26834f72cf718638528c3e086107f32ae58b8e29b3c9b8583796e9c240c0faf9435b770d89b007d2397b2746a1d9851f1b9c9b59efeb06afb1620d64dd67687b5745721b673c94adad2a4404c602bddbb2d23658d969318f449527b0f128cac9931845bfc300420011f792e93535fd3ea2126caf2c6b864cbb6bab4d30214e246464078127706dea43bd1db23d6563ced164200c029ecdd9e3330ef7d76092a4c2806c348170dcfdc08625bcb20cdcc4ad32ad2d289bf6af7d119037f605b5afbf130a6092e072dce1beb864023a9f79c5a3a5f98dab3a65515609b404d5ced7bc1375aa94ca605f68846ac4ac88bb194d6f6da7aef92c63733af3c43c30810409578e3d8e22d31d0b06283d6924c9bb4901042a939610c44bd3feb72862b816866ad20a54de52c01758813ca8b6ac36be0c97708225c799a837cb3cccc967080bfaed5163cf3d8382d0a7c5f482bfbcdf0a4ea2513670bc39a5e00fdf19370dc6542f5c3226d04b4d2c0c8a65bae7c481bc49ac926aed78aac0af2cb110aece11b8f2b6fb6cad716f50441029f1ffddefdce253c4708d22604a82b2f5016a63271cd02e506c7ee1c80cb4ced4e47f6383fa6eee82aa0472af9552e176672d5592362440923fda58a8509a950cad878e023c075f585dc3552eaa4af92367ec4659bf5cfd8e6afd04c17df69629aaf19d1855479b5f1d7c722602babecbaa9186e8895c4115b8238bfab23413046e63be7970c971d902fb5ca2ff4dec4a236343bea3abf1845c1b469d73a1582d164635cfcf2a04ec1e215e89b940fca1cbafddc50fca43805600a8e086e85195800ed609459d79690f4a0514c53c0f32c1c1b08222a1950c04972abeed430e0f17eeff06544212756bf8d66c5dac489283fc60846329da5412f28a0a83d30ce860d16f201887c0af84de974d009e0018964aff08d4a9fb14785d023bc804899568df516bfa449263b931b92fb3cd3a4f2708fdd851783d1362ca45ff38a0cded50a959292da82accb2164b0ba6e0d6ae606d2109b53f666359995afa62923bb4c3254b0bef114505603218e9a56528fef28461b3483249d1e9be49f2445b7a3b878eb4cfb1036ffc01f57ad9908c34da333896b780d4f748046462c192b269501842175b0e67d9d29481ba563f82c6b56f3421c637bce9bb65f7017c4cbba2ee7d9616657655095c1319e295d1e00c640eb26f2f431e1ae4587a4343a79b870d4528c8e0f69595a624599e938458ba643a20681980ab6970b017ac0d7efb1b5e83f1b1d1b063926abd58deca36d3565288acc2d4088b8e13896da1e46350c39c5e761abfc4703271e668c1059894bdff08f0614aa4772d9f72e40ca6e04fc34193503ef1c082e75c79095e9839c18185ff4a1551f946cd70456766db1d0a4f39e59c52f62cdbce32ed8a8d3dcc41fbdf155471ab636e474c6eed245703acd50824f44e0d6295915c1412371d0dd2536287265c93a71b58b937d47b6a8671bc106c95d7aab570c244ccba305e40c4d55127dbd9c5a9ba9447fb46c313266191a701c076b04f76ec98206554d22c4669aa6c85c0c762d20bbe3f6a9f1ca611594438f7895240610c58f75aad70cd75470f9a007a30d8b5a66b6cd5bcf836809b187d1ae86248f569bc749900106cc2baf43949fc306c496b9a6a34ec5baddea773dcb7be6e2f04e0e8839f302abd884c807aa696edf973eeaf905e67d6d1ec80e4026696ed140ae4713a22c64b59ea37cbbfe1b35c3ca0e35f07a2990236b360f30ad7e84b23b55ba60505cfdf008b59d44305570b0a6c4b61ed2fb085c6be5482d0a77ff94280fec16f228d04adeeffec810cebc7be2a3943f40c67fd14b0b35c4a3764e1b639249720dd7827cdb22a04e235c9299802b7cfea5b7e9b07a554046400639ac884ba9f7ca5c0315daeae4ad29a4a780f5bd9929780f771215b229624002975ab68241f120a3611a03619244c0cf5d911a6e70449cb23930c93c99c03bb04c229418c1d2547720e3b3f5f11a0e84f0f51fba5af4768708271f0d432dcd8c1f808bb517fca85b7eb18b4ed187e5fe7dfb29277cdf1e9b9278c766e79590745e3c9648a4a94b9f5111b59ff4aad2266bd4dcbb7515195fab0ba485c4b62bd46873652e4fe998bc4fe4ac1a50d4b0eed44010b2540927b78d2ef5310655f3234c947811482fd9c0c6cf8d57d82494189b66697dc8798404ea234f787ffd54f04af4e555e138802ff0328b4c181612b4d80208dbfe6fd60659c42b0cf8af21dfba0e02b4ae205ceb8d55ba19c43d801e50abce08d4456940b0b515ad01552167dd7149183d6d7fcc918d5c22d5a993660a5d87f30da0149d4d0b147d6e525d843a242acd3368170c7568ac5c4dc2c83b5623bc4197daa2e0a13c07552705d4dc3717ea70adad8004b6c51d8766d22d61599fb693ace46d0d7edaf0a79f426834864b8fc06c7faf4e63cff3dfc316a740bde3001f18212b212881d40245ce78e0ec4fbc0ff945338c6d62800ae1449d7404da370037535090fb2dc3507c93e817a9f9b5dc5ba646915052059b0130c385531acd4a53d6ef234cad7165e4983c14920a6b1dd439844c3e49a52035ee80c3f81caf89952fc057db6bc1bff7c84b99672ba5292ae0930bb2ffacb8c8c6eaacceb0de43af7b79575dc5e36931cf83f68165942fb9de822b40f64fb78069f6d9c4665b39d6c5a356dea6c7f23c5f638119327621b2f5921f5a38475344a68af2ac4c0f4c06f1dac3127766da05c31da5ccbcf18b6cf3ecd417178c808cce370407c25219795f8fd540c9cc89977073c9fc4d8638d7f1b18a056b42ba00da1a4ec79674148924d98e4d9dfd73e5260f663507af88dbd72c9b713ed17a919c655c4fca9b71693899e4d54dd0d7fda5dee217f563d1dcec94593801d3a5284a4968d5cda17684dd1ef507c10caf1ca437aceb7d0af69e89afc4bab4a19d5a3cb79d2061cea20e49495ff6ff4f5b6da38298de4dbcf9188b581a927935ae7da7395a63d717c8ac5eb18f1f5915e6dcfb781c4092d23fa99817d889bedeb5190597d71c448f9b70346d64334d17cae44d9fd1cd6abd6a1d1d331ac63e837550d40ae851ee34b314dca48f9de4d3d458cd0c7b422494006ca41798f11c6fefca4879067a76c39bcf38af2791c92ea1e810d041f517ea35690b4c32cccfa2ab67cad629c718014d15d0e79764f1e06fbbee7388d92db5c918955692f2e4e6ce4802bbc02cbc6016b35dabd0b3d7c5e6c50973edb775a83f9f51cc05e6674d572f0bdab7dc19438ace4fcda2c8787ed7cc0094b21c5127c6ed177f6364cdd5e92076b7d9b7f9a4859ac965fd2e454bdb77ab009e205a2b8cf0ec12c3cc6800e2745c3cd5d021e34bfb6cced466231f4446b3b0843de787a01c1c04d7b7380246d95a9d82bd2cae6d967b9edd23a9f8e6a2a61f96d5e277650b2057ad66aa25138cc5e91266e3be80733d781805527e225d91b044f2b3a1cecfabb3ae8e095f8b1eafb2ad148b8c6d410701f6c4dffecb8f431a49e70f337d1dd584b9a6095069ea7d87e14402c5483ccb79c815860349a6fc9eeb639cfd52fe2fcd5808d066a66c6300322d74e199fa8c014c78b5424abc5949dcb81c7e5cae3d6dd813a45c4582bd5bfb8450b03ae76ee5ea2ff5a1a3db944a2d5c638414ed72eec1656b46e2167f77dc9761e4243021bc45f7990b953ad35eda2538395ed7870f350cef1ba503aba18f172dde2d46de2343e22de42d3ea1c2ce175a73bd67f36c108ad619e7fb06bd27262e320e95d21774dc1b8cb65355f3db34c36bbd2f596b1e4334be8265e6d27e6667a8e163336ffaacfec3473d3bbedfd5b8b964210594fd36304cd97cb09daf43e20eaeebe79f08829e0700e685a3f98078c98e302a0f5fdb7d8d3a1ab30521ad8f42dfd27c7f9974f55f2978efe8f1124b194eda34f5fc79a825b8868e3796bf411bfbea58b0afdb042941457f3f321dc53128a36b89dbb2dd85bb9f96faa21961a3448033f29b2ee181443999cc30fea01d5e24ccfd0c5463eb8f51e9a1a8983a30093ba61393e1e8aa5287c92009f1a7058b09acdddee731e7a6c4861afc55c7091f2aa5c8ef698fa39eb79e0af6ba2eabbc5df753a0b36cbdfe42d955a3143cd93271cb8f012652c43e54775a31cc3e3c9b60fe8e495c395937bdfb8422a340a3071b8245a12c4f2480edc87ea8fc93101fed600f825a4314fa0482adf0eacdb07a029c1f2f07de4c4fd3a5c0107a6631078867a3a812c272cd2b97addd7c3b4c0c7c19e13396721783c4f9272ea714669dee5c51d246dee723fecfff678deb7c37756c4538a2b1945250e67c6c117e75d0a619163be94891e7f13ea29b7fad1edb8988bb19ca2af144ac13acdabff82d07dd1a6d72f527d0c1c988f3ed1bf0fa1cdde0bdec42b838035e659a8b2c53e1231ceb843235bfb1d7eb52dac6a6af0dd4feda255bdfbe90a80d5b24ab259f358e4f1fdd42ce99778784529ce1088e9ddb178ac67345e4c80bcce2120715a1ab4e17c0790abaa4b395439b5153ec5ad3fa4018bca598f242c5200df5c3d4ca72f72f4236e70b797355843533b291a40c63ad423ed5c16838c586142cefeaf2f4073fd06fd1198db10d4e327a9454a04fdb0afbd25dbde2d15179920e06664e6986a9551e6d0e750231c91f81065aa5cc56f313373c110c7f022e05a39b2b021b6f59d28733088dc715c31a410483dc68f022e9286016b05ca4a306182b829f5fa3140aaadf5160359b14eae2daaf5d9e0e55d52a97313d46c0ab641de352f092cbacdd880d85e0ee3be096076fa84c23cf3280fe1d4406da0bf9f233e1ea908944b8bd1964c5f8f0f765ac4c0fe9a9e0dbbbe42a6f8fb8b4b9e423fbf56393256669012a4dc005c89325a5ee52f14f98402e22b5bb2ff04692007853f3f3a376c7cf9c23c987b5e443c2d488a05c8295d0f0f84c6ca7360d3f22f3632f0c30377167e8d75b10c515fc21ad07824e0ef2b53971f73edaf1653c5ccca861cc44cae8354b3e92b4d99bbf7e590ab7a982dbfe883b872b2bf4c72841209f0ca3895360cdc5e7e484738d7e4b6886e227c1e2e2f1526d583117d7c654a75688b0c0f1310b6cf6f2c7dd49dc3a84d0010f2b83839852265f1fff3c307404f18b5926493b6de12288b1e703cc5f7f5ea06ef1dd2011202c80ffcea302c6758de23336d03c5d25f3df577790a4de49efd09472ba626a60573fd3320afc9893dbb35cbeb08014003cc61bdff6bb1d5c46590164c2c7a0b82f1707b8f42789a6e9b96640fff53f71c62840ddc5eb34aa4d3f3ffd8b9cc782a993dc2fff8b636b75ee60087bfec016c72cba50c76d30f9da80d8638f029d4db221e00d40a908fb7ca99f32c671387cd3448972d84a69459dd1a17f1b40e5512b04e46cc28b5c8156ad54c13720b0faeb614a97e08bb4a78039ea027bfccff6db0637cdd6e0ec832423ca170ad3deb57ffe3343c34f069a5349fd8eb8de975a56587044472f49b370550fff00b16e9fe39ce7e0afb4b8c0e43e234a4db043c88d04284e5228cca274ff92236ffe0f68ee67be398a65dc407da34fd518f807840732e79b881a06fda39874e17964b0f4742c2714e3e70d92055827725bbc7942d9dc4828d3227c7735267230ed24fbad8e9883907a1e336963125a2366390709741dc89e9448fdd2145be4e6d34a4d1d91470dac20b4eb76b970ca456f8572fc4633fc2598247b792687b1c7b331a3b4461f0012e4e9c9ee9b04dc587dc8371141a655998648ff89e91ea9264bba62c8e825489d9c7b6913443b8b2141bea76f451f489d05cd8241023b948b112a703a173fd65c849ff96ad41837bd93a18a59dd35fee4e6f87a9e5aaf775041f5da2d8112a138c0cb8594454a45ca083886b4e310d0137d663668d80b30a9ecaadb345d561049d459bddf0ae98bcd165f3d1ec3fda3e856e095d7d0800feb329b39f95c9fe291876825792a3203f4cdc3addca09a724f687018a24e104c3dce0bf414d27c0bb2d14bfc1f5860f3bb1d1b84869e0c8949b867e390207d96b9506fdbd486deefac20a0b1fc459983bc0e0b98aee13da113a36ad2fdc654a2f9fd8128409c00ca213bd405f60f97c85f4332738288791db25ca328b4e7b3adb7c0fef638f5cb4b1b31e94e47b9ab1e2e9a13753e1ac41f849edc5777d3e79e911225d79a952d93ac11bc52b67451cd6b87cd75c58e5ec3d2c1790d1637276914bda8b547057b6f09f9056cff04dfd118043bae7b50b13af90a8cf86475d6391ca5b22b0a23d769a35ade080c36174db8df670d0b7555619623dba5f03abe959f440ef0fe46f5c3b243c71d9f7e8a50aea522d08a3a89548150983254d893e3c26c8258f62008eac8e3187c0db5942ae141e62412aec3771cd63e1fa224b42a59847c6e7484ed31b26a1fd8381cc0ac1b86e6873ad8ddff7a50b08836baee156592c2e418a7c6b3294d246683b645f046163430e170d4d989fae7861782e9e85a4a8d677f8bbe23ffc486cbe8efe00a4832bda64d452a3000311df6aaa591268dd750376ae9ae734810613de6931414f2c3d202c82bec35f761dbf0588b62177647db07a0e9f9643862cc51e6403f02914657a27f457d717f19afa00bf6084b6b34731f5b9964ea7cea07d5fc5a85c12a00210272f19b38803a94e9a412f7de54621888be887f213fc7d9c336a07c5cb0bdc4dd73508109047147332fdf6ac19d17d0afb263dea52bf6a651a5a55ca912ffb69c71e36c05dc2484dc2aac4d0f848e18ee5718edeb123600c02b8df0614883dd215e67070e83b980571522882f83a1e9ce8e828ab2bfe34f42558e6a9817745974927ae5333d244821f67d9df9c95495ea16745e861e5f70b72027b74e25f0d125871b44f3463eb9a068bcef7cc2e5516bb9f3328e897121b563e302d606248b579f57b2deaa605316584c1ee99e24c5a257a590124cbde59c00253c501317b40c2afce813c59075b831ad1e47fd01ce1b9ea012264450f8d083cb43541c6b772bb254f0ea63ece3168b9a27ae823339c97bf53bcc40755ef1ad035c9046fc2f43d0730498fc4f82c511b831d1f6f671ffbd0f60aed8d1eda8b0a6c318dd5006684b14fe4a9b0d4289fb208146c66bcfa93837cbdc17268465e11b3bc4ec000eba5b06edffda7bb5b530b8f076b6de88621c368be445efc6934f7da18263e4945fff49415072fdc2432368dc42cd6fde6a9dbc6999eb59bea5f2bc2c1a311322b57dbbc7d66815760a6245b0a8801501fc46d4c86204072ea71310dc2170ece85a1a4e93fdb5f3279ba9ef0d8b214e89733782b3073cd170ba670e47d832f8d44d8cc452cbaaeda04e4bc0c8a5243f98713b02cac0047c88d02d7be6a9e661c47367b2d984668ed2631e89d848a37ff8f8b7466fca64fc614be9c9da3cbc16fce7138d531ba6d1cbc5f82cc7fb4988c4693f6fad48d115a621fa5a1386c3a158c28c25a8ef9dc7afe78faa7a3563650455c591a0d943da8b1854a3284fb24f48f8520da6e6ce0a50ee7b2deced0701ec88adfcbced1801c4f10b605819f80522e20b15084141fbfca155e9687368b7bac253f77f83bbea5c3a0a03ac22aca32e7dfaa5bc33b3ddd928ab92af639675012a1f14c7ac8e4370cde2f184e1ede5465f7e7e567f3ba9313ea13e3b371c0ab55900b58463fa2b623f2c2080b8bd6f0f040552f2a3177953cf405d8d64f1cd6f260cd10bbb1601cf91239eef86da322d064eaba184c4ff115858062197f40b1b91bddc8db374aadd3248036e6107e12d416d5b45e4e0a87f5e7366446c84d16451d93f985e9dc5dbc64394b513bf93b560abd74eb79bac566cdfd7fb0fefe8da81f9fcb266991ede82bcc349e8bf7302175f6abc5a2416043252e160e04c232deba30f24f5b9cec79f61801c199db899468416c198e9adcb709034392d70076c5eaf585cfc1f102ca014081a18ae0a5e32bc6acca708a6c160c57acc3aa20169e2bf91ea91c10aa8a2a58b2d498c69fb5ee647cba92832fa4473bdb495e17f6bf2cdc42a82b2e2bc0f7aa8884b16f147021f23b06554a56a21f9b0d9f235bffb1a1a9edb2e3b012cc3777409541acf5b275561741ece824ac7d026f0c39ff21e284ecaadafa04c34bc72ec88c8082cc287295d9c217ef957de0e1bd90401db8dc3b7361777cd144deb06d680236367a2b055381d645d6330af6005ce078240fe72b7ca0c303286c50f68ac2a419106b6d863a9b97f5cd88fc70aad3b8cb8cad39af5f736e88bd98415ebd8574e562f1c614eacf50215e1c82a930f3e2e82df5a21da4bd7120bd320b8f2eb6cc6d542e995e34d900988f5a94954c33bbca43fb6ade09cc973c836d9230ee66a2c0b4831ad630f49691ee0a1cb1465ec1ae046407f225fa016553e46bfdc4ccf459105440ee49e7da5db84014e2ca337069a8998de3b3cc25aba6db94dac1530fd577f6846e09e4e1f5c9914d6b0c78bf7ff28e9881437cc0e00ac98277405a7e8066963a29156f6a41d2d6a9630c903da922c9d720ff8fba2adf52e117f595cc200ae9ef0e7b51966af7e78c5ca656c549b6d617b8ed4aa9127f7ae7d80630f5536ac75ad2b56300dc9e1bf14a71d6b7850c312c702bfae60d0a6d50f76e07a9e3f6347506f636b13d271468b01ac1605de2217f5f0beb2f2e85c26ab56e6a91a108275b0bf844c958b0af0222ae7ecac2b96ea4f56f9ae0aee3b7845a7dd181ee81575fc1f440eebe579d10078131b2379103566478b904b5f28680a5fc9f3684f84bd7eb99967a9f2278595f330bbc41d10f7088c540d0d19a93b65aabbee34b26f2d6002aa1dd673837adbca65866675b2a125a352fb68384298c38e825f986f052db5bfbd1216aa11855509527d20411442b376f6424aa518d081a9371b6cd032718b22a6f0cc6e9667db39525e5a671575a706e6e5e644bf8b3b158ce06bdd9593f11a0f1d641109c25c9c0ab03b9349633aa57318914c4702a53223eef1923db68cb1c5020d905c01d0dcd38433006ad5255116a3dc5aa7e084d8ab10d1f270d1c786724d6c8760784d109314249181fdeef836d59c79ae748aeb2fadf41ae298d92d0ddba53f1f1f1ff30ea125361a23578ad4b937caa11a384fafa1c4978c19b71ff2f3b609810971bc6be60c0fb31acc3ef21cde2b85fd21aff4958e738b981883b7f30dc7ce85aff73e4ba80d4759108954456b8601d3c93c4010b24ece63159ea22bb69f02b60db70af792a2fa220b1035cc745c6018a5e967edc1bcf2e9a2ead4ce3077810b6f5c2847b43b85511e3ef8dc4dcd31a6158fa8ab3ec035d8bd4f134eeab0bbe1fd52c5c141e06577af66599783ab038af045885f2aa6da28f48408f667f8ea5b59587b5c475a1b1e55262b217157993e50549d4927766119e674a733cbe8caba446bda7cef55a0364a41e1aaa69f965c139b829dc7427e62d36873d7e19081ee1ca699422c92bdf8288e340b8ca33a9a35c58a92263d3b5070c62ba0b6313ba837040f4639a22d34982149ed38fa1204117cc7af4c959e0650dbb161f97ec704463b16a1589a08c096da40464431affdb0d6c0ab84e554db7aea6cbc316ac951f79a8c9459daadaff17f543c9c4859d36334b7518c52e9e06dee6723a41f96840d2386d329eeb316709c1d95caddf882b8cfebf27ee199854b124e1adfcd81b3c1e5f4ccbfe23430cbf72b49bb05c7879ed1aeb2acb1bc7325b900938318c7104d8dd2057eb604426907a637ed7e19c6d7336d83d112b83f3aa5fc6ff0984ad06cc6b576f6ec62c38f37f7b5080ece2c62d3025205eec7ef77c2f5c618669f1e5bf20d792365e6c44d3983f83128179a89c7cce1f7f9add93c736c36eefabbd2f501d1d423199663227edc8b90efa5256ad8c8206dae862489644544aae2b5342f9a2f4b325477667b2fef471db6c1144b15fb04e1f41a87a43f14ba69515b4cab35d5ba326fe8ee6917f867b9bd4e50a8f2230b06c8bba75dfac5785815c846c533e0983e997aac1dc83ff73577f4740df9ca1fcc3bed13b611da3ed055b25b12780f32cbe708a56a79952bc6e3d23c99312246b90d38d3e3c6c2e3c55ff2f04ea1303ae45b3617988af9ecfa86c6808f1b6bdba20c4cfda71e6430c58fb6c0e9c82cc0d0a9a2e63bf8e93eece12a943eb702e748081e9b4d2e37fb920ccbfa6dde536d9f6dee7f7abf2c6c13b0effcd1dd4990a52cc3cc6687ca703675dd1cc074b308e7fa60d57076e56383d5e5f02e1bfe29592fa6ae0e8c90ffbd94e8757f89cbdb196d1502cc598368cba4989beb574a8ac3022354c30a9fcd6a560c9e53c4975fd7757d74334459df724a84d6706975a56094de3e9d39090389951b903fc16fe19e6f8c80716f7b9137f6911e40b5540f57c27a47c68f40475000231e8c613fbde599d0a08d9276c2f58fcb1df2f111428af03f2e9d7d1c942c4fa58c67eae69bd5e51400b097d544b6be51e8c28c66048315e3d5cdf79aebebdca54118d5f32f5e024144027a63c6f162cf51527d130c5a068c8a213318b7f40776de479df22dba62d764b5b57b88c7b864a62d088466307de16f7e2d36751ebc1e2c4d046d2d1b6fb46f14c592589eb6fc5ed105b73692674121b979988efaa673f93b32dfb4641ad085da16e1e3a2cd9a9abf9678d3c6db4ac74c51132a0bb1d858bd9f247c016bf870a2dcb824231408875fda4ef8fa2c52114c7ee586e213834540e622014d6acb682ffcc2cccbfd13571f1266051578669dbd9622319359d66d27f14042feec254952d3549d8b027bad35780315b0657360aa18ef18c10917a0a9937d276cee2e8a4495b1c2d7c6c3ac8a06a69f31324b026b0295fdb3474d5b3c1b606eb62d851a1e2d84fc3576f99a300016aa356b11baba1e0dfec87eb544743ba15c92ed5c3565706ca8b521e5ba8631070dc1d1d63b5307fd2e871acc1268f0da20719202ff0f99f7f0f53aff74b773676415e9b1455e749d291e126bd032798675fd4725a2cb877d0e83d9840c74cc6e93d4c0011ca01a4100e396ad83ad8ba3bf80d3e3a93b4048edd829678d3bf9060af91c49c06c5c92d5d4827b310cc21d75817f02cd8bf4515155f90812d30ee24f69743314677574515b5c0463fd3a49aadec3d61be3067e41755a76cfa96e44d4dce5990ec80cb998ace89e5c8c728af14cbbcad72ef6559e0d65100e879db9934b71c4856f53a49b490509c2984f8612793afe9f285d17338e80a47ce8392239a1c451025f70ff2390538b89a5c1fade36f54e28cb17391294919f780f945fd047b639787c588ff4e9913e77348fd09e8ffcdad96fc16f52f72967b50d2de81ef3037455bec94e6e6f36809804b7306776c639daea9a85fe120c60eb6019526d3493490f65d5c9f4d7260b6dff838b311e1240f849c44e40a8a082a86843461a033df32f2c5f10c13c642b22563f15e83696f71c875294cf5706c5fb10fc7feb9ac57a4bb033ae537d35b204c4a9b0e6569c85a1e4ddc8d48371519ad438a7623eaa621a57934518f2d867b65d6b2582daee8f78be9db3a1076d945cef90d7edc816074cd461f4a71171da3536e38517aa1a7c1bd18433e0d86f82da4eddd6defbdb79452ca5d0c400d950d3e6f5e740975cdbaf8fce0bafc74d1527e6a3d2009cdaad4805cec0431010a42e2484bebc5dc1bc82648c8c802f16f563d929511f2372dbabab4173f59e082b69c28d2dfb188b60555c1e566f563f5fb665d50fe7513f250516bee2322fa4d73376bb0ad185a31b482546188288bad5f42d1b7055b39ad9e18824b4b1f134254c2ef9ba5e2eb0df3d7c777909f766f3368eb9b762b2202cdca2ab38ab0ef25dc8bbffda6159d3d7c0ef45db384be2dc821118538dc02c2f466e122310516687ed3bcb7857a1f74a48505373f852a0e4cb418af5bb8f3ead14bcae8a814abffdc9b8a37472e4a513497545cc446bb40eaa97d282da791bedc219544bafa8f0a8b045ee1ca9aab9b46b33547ab2e54735724faebb5e63edf483aebdece68ebfb66fd75f24559ab8cfa0287c3e170385c08e6d09c035f0c94ecdae541b7d977c6212d0c43f4b34f038be70ebd04bdfcfc9d57443b507e46f78d0f511bdfb9bffd4380fb7dcf0cf913c1d26c212cf594481e99ad79953a532289efe7932c711903e641871ec2768ef7e03fb7ffa15faf52889a427a82c8311ebd3faf8e1f077f9fefc68f553cce589724974cebe1943c3ac4d9cf67b73b1e64d92b566a679633b618b63dc0284f3993415ba7953c3f7aca5717d1a77c89117f4acf522b83ac64a0d287082a673c08959a4a9e59115f10bd3ccd267b96a083e7be9f7d67ff9cc4e78be0f7dfb9af8a526646b495fa871565d00e43258d4b262ac310f2ad34a31495e411162579a445191b221a95f52af9ae9edd82f0b687ceeef80fbed6a3b21c23ba28431c2c5219b4c3952f26309e9030cca68a3fbbfd218005ff7bfc96f715c328b3123746592211934ad04ba6a0fcb47485f1028743ab63c4dde6aa458b8040de6bc3e826eef4bda86851c8b68635ac210882a07f3db0f2c4ad5fdcb4174317efed3b73e842cf81d0bfed1fa29846d31aac9ed1a334dabf3ec6f904b77b6f89b1115a6febad22997b6f0c245555adb5d65a6badb5561c36e24ad1d55e115b9ceb91bd169b35f2077ee1a7f1ecda9b74034caa3c2d74a9e88dfbefdaafe62f15fd7a908ab808a3903f10346b842888e2f88de398c7118fe3388e771ced388e63ddb99eb3d974d10f346b5cf3828bf3675e604bb3863541f333cd6c9a26bed634cdaac5518faf6bab6e6a7ad9d7eb553fd8ce318eaf175996668d7bab47d54d1396c1f0af63fd9a69dacb34807db234611606abb9b437566dbaea982607f60d017009dea233186d26c6625acbec27e1e0dc9a8c6adcb7d5235a53adc6fd593daaae5303415f746b2d3565b058f176496c9408ae180d92967034eecd4ffaa29a878746c3341a8d766d85c1768effd120968afefa6d7f8988e218414ae36a194e998473c63b7767c7eed411b64d2093e1e0e4e4cc664d3bb527043f112747cfececeaecd096684b3c97c77eb3593dd2d1d9d9e1e1b9d1683d3d311f1f5c9251ad4040f8da71c7a67b2abe9687a67b74896bad866bb55bb322cd6c227bcc1a3eb4ffb13f15f7f8d89f5bc340b9abc6fd1bf5a866f0d57b86e53d77c5caa01e55c7251989e8a8e26523cb7bae3022cb219308768b156916b2f29ebbac718d8c4a23f2351a1989a191ad3cb0d247cf4a5befcf4f2da82654ddab9baf4ef6ce1345672a542ccd48aad5665b3134444434a335dd6645452c74ac458b16b0162d5ab468f1657c5bd8da53339b6640b4594dac41b66c02f2201bbed1846c4dee33dab56fab3f43f1b5280ac27e0800fefdedc15f5488f4d3ac71ffdcfaaa5061eb07733f4fb309b5e605e58a3a7487ecd0a7c2244036c25d5bb1b862e887be2811d1ed5654c4a285db6824d228864848e08794f145b24848485506db3986cc26a2dbad286909572b8b92058b580bb3a9fc8c32bed6a88ab08de38988cc1a96bc990618c1772002dcad88450b23b3c6fd5a8f8ef0b5b51e552f329bc4ebf8a2b5bf7bf6778bb6d66a3d8b9f495cadb579cfc0d246ddba3316b4598dd455377f6b43f445599806b06f74a76817481e64fd30d1d769607bdab03a5ba4ea464797cce72e3fdf33a3d8baa88da02fba4b24dc8b180cb3a9c6b03144d8cef147f90343717c91a5098b69d9114ece4c678787d6e3f353030a12f21355615b3144742b62d1c2081f5d5b9182fea21b036f510838216bade5d72a02b25eb2d65a6beda006fe6c91acd7f879eb625d72496bd6c05fe33e07f64350ddf2e8d23d3615b0f315bd17a05ffebefce12f5f20d82ec1570ffa8a6e0c7c05edad6086596b6f40777e8ccb2aabf7265a74e7382f0dda7a07f9b768e27b4b6c7a366bd8372ff89c03fbe641149b4d1fca817d83f3f6e0e782dff96d8da4afb37b13af12ce68ae471fd8af393bd5bd4935b951301e3111b8d136b6641b94c1d1204bc4e0deec6bc6bd595ec525e5d86eb3269d7bab269947c7e78869dc11631c866088437c86a82649fbb9ce5967b9c4d556b0fcc8b004cdcf926399bd963d332c3d2f1d7fc57268268c06334d8f5d530d6e8b5b6f9af6edbe6f1bb797682ce1a01b67f418c750186aa2dfb967dc974ece399b5245659ef50a559e505010134035dfb8194035b4de22dd0d70aa8914ecace68c2ddc52122ee9b7d5cd48b28b8a9d1516b4d45bc344cd05f57a3d23c8a0a939a0ded501add15253a6f6e3fb9644d67ed07a8b2aaff2ec54af17c512d490277dd658121b9cd1cde877e525f9b03caa06c201d56a49fc18fdd45ba4857323029cb3ca8cb8fc86baed77e51971d9d8711a971c4bd1dc719db3feecac9ff3af276b8db465362f7839462f4fdb12aa9209355743894aa1d26bcd95636c24fdf3986fd14400e9a2d3b8d78afd604755c2f51642cdfda061b53acb542bd2ce327d20c7c37842af3527f3d07f646809f5196791b26b748bff64c2d09e2570389e1de7c3e39b66b348d849ecc383d65b647b18e7dcb5d7413e77199e3bf6dbeaac91cffe9df5a6b55366038c6edbe3711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cb168e3e91609635ca3618c6bbfadce26264b831f1feffdfcf47a3e3ebd5e8f8bdeb6b7ad4e4bcd56199e1a0d9ce3a9b7c842ddf8aeba6050b3d2b470f4ad67b519361f1eda8f4ea3b550f125e70a638c4b1f2743d78e4d04947ebb91a10ce63c8ebd5a267be537b7dd7078ceb07e20c7c3ec558865e8be619045caf64ac7501ae65ddd5bc6bab7fbc4bb4f50ecd57dba4f3d3eeba9b7483c79f6ca066d2909c7d333e3e1e9e909122228485ba49186e65b346ef1a9b43133bad974199ccbb7a8ac5d6e64afd1b0d49beba191e4575a74973f3aad6ca1a2462dcabec31f259863cfa9b91ec75e2f2ecbb284f59c5697b33c5c9443d27765122b52e915e631c7a6024ab7569bc7ea62386e9964ae694c342c920df4deb255118d2d967bcb8e516ba54f5c6fd86967588bb065aaf8cace0fe44000d66e9178384723866627419a571a6aafb2e72b9cb33d5c943d6334db5e6d076d755769e39cf22e9fae5216af52f8f5b3e346cf5e9ef8142dd2e83430e8e1299e1de4dfb8f2756e1be563073fd06cfa5ce7b43f3bede79cf6abc539edcb4efbfab41fb36fda27edfb540bf47df4733c2e3a46cff1ac16892c1d9f1bc7934e0b63be5b6c15347e94b4efd88f5e6b8ec777ce8fa66fd88f5e5626dbb348d9471f3d8fe8b661f4a1eb30bbcf4e8719a5dd9b0ee7689edd2d137ef3e685bec763354773acb3e3aa84e3d8c39af3713c3a769f33ac45a3e39cb8de46979db51ef59ca387423f3a6d44f78def47c72602467474b4bcb78cbe3e6bbd6df2b1f39cb516edd863a791ddf62c935891b067a2c71e137aecb0d76374db3035ec34cf7db397e716c1dfc01f3a79ee325b2411c561fe7c7739d7fa3882acb67d9f1ef41ad9e2ac35fad14551747b6ea3174791c6c5dd72a45be748ab93d7e2961e74129be6a9c12d02fd737b7ebef556f7d662b3e9739cf4721ad79ed8bf93036c36c57cebaf9bf675fbd77dfb5ac5ebb1f3e7f398cf5c9f3f5976fe64f4670132375d03999b9edd4471c090510db4eba0384cd78e63e632cf91c2ce9f05c47ce63f1faa41cc673f1ac0dc74989b8e73fe7caee339d29cf3e7437f1690e338ae418ee3f8e738280e183e54031cd74171fc7cae7111e839521cc7f1f3a11d68a0e33bce809af2107111e833df4171e0d8f11d5407cd91e6788ed4ace9ec9673d614e7aca9ecaca93e6b1a3b73a4b033475a9e9bf6a0db8bde001d708623e8514435b8b70c666d34f69b331de499e8006e1148e3de40bf4ff4e719e4815e6d20ca81fb145ef108f1c918a9b3f7fa6ffd585b5d35650fd83155af32b82e8a9ad694b484f6f377edda2da0166107a32bc229cdf9bb5e6133837a84773cdd5bfd8dabbab75aedc5b0ab9b45a1abf7aca0abdf1834f62aa6f8695c5e0884d669eb4d28f5d04081ed495276eaa744516b1acd337abbb70e7a3d124dd7dfc09fef0d076c8dd52ef500e7a3862a1e47a8c0c3619db0814956ea81a52188375569b53136f8d6ad1367c04ca5624ef0822e253f304c9a22bc948c9d3ab4d15b8cb5d16f64527052d8eaa51e845ae59945ef4c3eb1a384def982fb6280fce0a578aac8d653ad328e2c09612bbde77dd29638ea1345cce8520f88f45b5bc29523572919dbc9b23fa4802295064037e429256f894f2bc5c30b4e2989afad382b398344554ac684c6e82dead03e2488524826ce2abdb310114ec24e113d85de59d64368081cb687901ca4521c1ec89670aaf1a4d27a29d8b7b7be6342ac4b6f114848ad0b171d78b5fc02480fbc948c65367a67120a718a29466ff127434d255195de1d9c46d8a564d797035010bd45924de53255a54befe39cb64c38ee94142698e8520f5e5fa052187e0c50cbbcf55ae62dd2972bba948c8950f4ce2fc6a0ed25a9ce48e19091e155e68c68268af04c96b18c11b90b9b714144e3842ce36334234378e6074e991e6740087110c93019cb44e19cf9209b717a911973660d4c099c32278468869067ce9489612433251cc28c4e2c53430e9a15341925f98c0d26192e386782d065b68466bc8848f81c09c9408166ce8867ae40abd10c980f4d8f98192be11929ca7811cd2891cfac5006cc2884c606bc4a395bf9e94ed5dedd81533d98dd39ded226c8d381bd114fe55de5e5a97a759fb62c2feb70efbbcabc7b05ea763c7c957b1f0fdcd9a99e6eeadb029f2ecf5e7d4fe0957dc2b96f07c3d75a6b73c618631fc771b4d6da529cfdadfd35fab3c7da9f81bc00202f0dfa96f8626c36651367f382ecd96cca68fdf087718da4c7582b3f59afb5166374976fad78f517e77bd1259eac38e75c7ece18573dce5586f59cdda2376c6dd7f51cd7f9b9680633c7f12eebf312b7c02f5f9f9d77ea52603de7bc5597878bacec94f9f8723287312dd3315849be463104a770ce56657dbc9d9f6497b481ac7b09976b0f43de7a046e4e5bc0ba8d9bab3ceb343078eb349d75c739a61d64e0e95062862dbad4faed955aaf5d5f4d5bbb1e0ce993c4a555a0db03afc2ed49a25eaf52be81ff7a154dd0d77116579cf5ac16c9bd5ea50c8a3324fafaa967444367bdb9c8af67507c95344f415f17aa79d1adde2c0279bd4a2dfc7a06c55709d3b3bf6e33a2d2d7836e462d5814d59bc572f47a958efc7a06c55709d33833da5fc72dbda0afd792968e8c5ab0a8378ba5f6f17a9590fc7a06c55709d338b31d9a8dda5f9f310021fafa0f8d0120b938326a516f164b3d7be1d73328be4a98c699edd07c6a37bebf8e410647f4f59e0364f00287e4e2c8a8de2c967a46e3f17a9562f8f50c8aaf12a671663b349f5a905fd7200241f4759a03221003c60b1c928ba37ab358ea19ad76865eaf12057e3d83e2ab84699cd90ecda716e4a8edf6d737d080127d7dc7021aa02029068c17382417f566b1d4335acdef39cbb93832526a41018ba4a2183718442f86702b906c36ee0ddfb837ace3811b39250a9262c0788143aa378ba59ed16a6ebb275801928ba325a35c0b2516141425dd6210c1187ab10267f37b5d04ba26fa7a8e57b3060e5d054b39250a9262c07881ab378ba59ed16a6ebbc9bc5e2526bf9e41f155c234ce6c87e6530b72d436746361e40297c4c3470cfa3a8e930f2619152ce59428488a01e345bd592cf58c5673dbcde89e00f0eb19145f254ce3cc76683eb520476d433716462e703092969ea060d0d7f5102800cc609251c1524e8982a41830eacd62a967b49adb6e4638b3bc27cceb55b2c0af67507c95308d33dba1f9d4821cb50ddd5818b9c0c148525a9a119544067d3db64b6241000030834946054b39250a9262d49bc552cf6835b7dd8c7049f77cbf9e41f155c234ce6c87e6530b72d436746361e4020723496949c68c1ba0d4d40afabad964ea6958100000cc609251c1524e8982a418305ee0905c1c19b5605174231a5a6143cb7b0ac0af67cb94e4d741cb14c3af8b9609865f7f59a6d4af9796e9855f8759a6f7ebda32e1fc3a8e65a2e1d7679609c9afef58260bfc3acd32b9f0eb3e9629007ebd66998efc7a906502805f77cb64e4d751cb34c3afdb2c530bbf3e649998fcfacd32b1f0eb2c2c930cbf6e64998afcba0bcb54815fc759a69b5f87619996fc7a926522f2eb4a9629e7d7972cd3905f97619994fcfa0ccbb4c2af07c03251e0d76958269ba5baa74f94be356c156aa708e04cc1bffeafbf4e03f6d72dc0f9eb01d8f9eb00f0f9eb3382fe3a13fad7650cfdf50a58fcf525177f3d07e3af2b29fd750ace6a91b68cbf9e74568b743dc6792dd2751867b648d75f9ca245ba8e3b4b8b741de9d416e9ba8b736691ae1f9d348b74dde8ac59a4eb2d4eb748d7599c368b74bde8bc59a4ebb7d3c8225d273a7116e9fad0996491aeaf38972cd275db39c3225d2a1aebecc53832988af346feebe8e9a7d01974029db5f3e7dc3376c5b2abd563a761e7397715f3d8774e9d7357358f7d76eecaf5d873308fc72e3bb7f5f1d8f5193bb78d7aecb073db248fdd3ccb735baab753bef268380c361001cee5d44ae15c4ef56b44f752e589e8ae57352bc420baadcee943b785da6574db295bf5d8df1a599135337ad3bee646b8ab847f30fa559ea59a5279336e8052533396664425594a5a7a824ac2253df62f3b68847bec9fd1cd480dd7cd76eb69d9dc860d4b0c58fb40daacbc38dba83df64f033411dcf0c00c475bb23113c10d6db33133f280164149bb91fd46b9717cf938679ff349578b847d8be5cdd5d42784708a2d25903085ae8717352510117eb50732388ce912c4051282209115e69081d72386ac333a22241ce1252c011128d4c0c584294af092664bf8840b574ee083102e1f2768e120d38da03ba1491256824033259c80133444818035c58820cecc109aa0cd1340bcf940c90d55cc3819ba0a13840a6d94d47082324c3c18a306092134b4095302191680382289102098b9210d162354e0208a287e2051831211ae1491c2f77ddff77df58a13595db6a420458931bd20e80b1282d8f0f402991344208284f033cd0891a5a3049e8e26d23cc4e7127a7cceeeb7abf47ddf057a14896255e487ad11c6bcc981e9f7c1bef2802893132409149128165a5882462b3bd1c2536865245a4bb4866811d1ca45b4f0105a369c3f3014c717599a3272776f37c9bd5d276153f776a9eeedfacd57e92a5da57a95ae52bd4a96eae62c8f3745eae6ecd454b5bb5d92a79bb34f4f96c7cd599dcefaf8ea22b8390fd8b8b90d947a5c5f7d833bf35a97d06abe337af59b118f57c7252dd1bcfa8cab642ac1bcfa007abc3a0607c8c0c7ab6be080085ca5254e9efe78f59f2278158bb556349b6c93aca91b60b8cbb29b013211f3b4f419b9929461c0dac2e117ae7a46d76cca41ed550afa478bdef6ca8a59e2e469cd73fcbac5ba01a85da59cab94e3d76b39388d2ec5253f3f3229f4ec5ce2e3398d0f49c6a2746d498fe7343d262642dbfcdeee121acd34c99c451b2de1e11983e824dcbddd253bbe63863df48ca57bbb4b7496febace87b7f400ee9299e734da62dd227b756fd7730b1a837bbb9e465b191220b09e82af3c20a29e8cfd344086c3c608596276a9cc6b7aa5eece5c404d655ecd05dc5486ea0ba2a065cc4e8b18aa1f231ef49002892198f86063450c1018728200c2abf22901f1c2e585228c40e31466cdd83543ce194957948f1a6648a28627217ed8906f789203c8981c80a0d2040f3acc0026081f6fc2207e8040e583820f614029524723a465e9ab5dad6e8f5bda00575a57ddaa3b874e14d19d6347e3310284fe43b13f4675d809692bc63bfb5773ae18638c6eec1f8a2d768b51119bf12763d65a6badd5daeada005b895759342ec637dc92dbbb4bb1975729fba4a0eb571a37973f2760ce19dd9f874e7edf9773fef2f77d9f8bf9dc95778a637df988e67bab34b1ee172abae39cddd1b2aa156d49e3ae886efdb2ec2097204714f1206a7bb6cc55027368367d4c501122cd6fcbcb4df9bfd3fe0b225c31e2b7dde51d50570682d9e7339b3218fa7590891e65d0fcb6f7011f9cd83f27b3d9f4e126bbf572aa392ecb91c95ce6158699e7380e1c9fe5a01e5c29a63ce1a03a1cc741af0e17d92e5c64f5059900b184807db061041f9cf8d064874f903c7ee5f9f0f47921ab6d83bcb7d5b1e8bef2aef06aef2b0f87153e3f551956ab1e5906dcf442e1a211f4ce4f6015ce7d5074ed74dabfa92a9c9351648b148f87733952eb9fd5778573301d7cd8f2a44bad7f5938b7012ecaca3d9c6bf1c313434ce952eb590be7725479f3e6cd1b2bbef207e22cabd1fdf5defa063897b770917574572dd4b4254aa2dfeeedd3db4f2a4fe5aa9ef54feb09e7729a58c2422fb59ea1b670ce3a815579f76d655e9109469e9cde7e4f34fb41bdfd2eba7317a8ed2786ac968903fb1d84808310fc1af56b3db24cf5abd71564b56dbc55ad16abef8d096d7d6b7bf1ed8729460b153d543867c99f0e4e4e6f26f9c01cb41330ac584211872c16e49088664988e37805a7e3647c895680bebcc8320baef270608ad14205f8611ef766734296592cd83433486966090096f16f997bebf162c24e007cf51ff79910b0d80c724b4c972bfca631415928da105a2643eb9d37329c0a8094c0c9917a5a3d9a4de5cc723c23cc7494b6e8ec7ca1e025c40ecf0f49578e858796f318ee413c5aed19abff70095584e0e7617a024f5a7fdd678773396a7803b5440a13da30712487df3e5c9ae8fd20c148942474e9f6c1f2dba792397383086f8cd031e44dba7d70f8ed63a5c46f9f2b1f2c2d3e44b444fddd3eaf2b9fd795cfabd7f3eaf9bc7a3e3d3c9cb33991850c0f4c7c6872c495df3d25b061099b10ac38a10211e9eeb1f2bba7891d9a10f245ca153247d2ddc3fbdda375e677cf16d70b494f941792297f774fd54baaa7c94baa87ea55d5b3fbdb23f5d7693d9cab5746b6ac382199e2cd90b4ca6f9ad65f29765052f5419a3457e9a6ddf09be6e2062468b2a42cb1cb92ee1e2abf7b9c9e86fcf5dd03d513b5040dcc123431fe9b96d545ebd245c37a39d1aa5e4e34decbc9eaafd3743857a580e255094105104a3062ca6f9a5391d490ac1c74d0ea6242ba694f527ed3a0aad090c58b0b6894880122dd341b7ed3a4fefaa64dfdfd4d1bc1f08c607878d4f070fddd3c5dbdde5f1eadbfceb3c3b96a35441026a0f8e0893354d228bf79a4feeea4b2d2a4f0c31133e9e699aafacd531535044b08266868d811916e9e1a7ef3585d61fdf5cd93c5236664c243e49944fddd3c50533c3ea67886f0ba783c3a1ea7bfbec3c3b9edc48ea9a822524cb540c3ef9d094031460910281cdc2c49f7ce0cbf77ca1c4105c994a91a76a090ee1daadf3b5a7f7def6ced70b5d989d266cadfbd5335ea769a8cba1daaf169076a7cdad98d3b527f5da787732ba24822a48d14179b23a0fcd691009728322d0041c20e27a45b4786df3a5d1948212545083abce1724af7ce93df3b4e7f7def3ced0cd1a203468b98bf5b27eb4aa7cb950e564fa7aaa7c3d3b1faeb3a3a9c2362d3c49724d448c98a4aa77eeb0899a201092c4f5c31a12add3a4e7eeb4021400d1537663e6063048574ebc4f05b47eaaf6f9d291d2a91481b91889bbf7bd625eed4883baea959d6546f4aebafcf76385787f0f1440813c61899c22385e1f74c2acbc9c9852d4e4ca124ddb326bf670228a2862a40a208614c0ee99ebdf07b66f5d7f7ec6a86956646244dd4df3d0bb766e1d64cd4e588ba99a89be5d0c0820845ac10a5072e5f5cf89df332b264ca1a2e19485022dd394c7ee7f040a50405ae3146207993ee1ca9df395a7f7de76ce57069c989a225674a4e931caa9edf39555739505739bb1c29adae9c9d43fb9d133ec1099fe0e0e0d07ee3845538210e1627281ca9bfbe71a672af74e3508541da8441dca8e1e2f92deb0aa1645921542f84d29221ca191f3e64d8c1ab926ed992dfb22aabbfbe6557322c7009191170095994cc876cc8ce6f19545757974cd7e56495a5b7d65c5674142b53feea2ad04a37b1a2cad250597a9725f5d7633d9cab65821882ca961dba9a3ca5b685df312d28944cd165b1c1865dba634a7ec77688b082113b62d0b9a9926e9de4b776faeb5b3f6910490c44128bc5b0fec6b2c0581518e38131abbf1ed3e1dc986508104ce0a16b8824290bbf634e3574545cbe484121871ee98e9de077ac2e2143171790eca6d44049770cc9ef98d45fdfb1a918d5126d9670f317d6f575c1d47c5d5ca0130c7482814e30d80ee7162085cb0f2976f84164f71b56c14441452607246d8c18936ed80abf613ca826ac4ee044854c0ee9861df90ddb3018961518112b517f619f15ecb3827d59e69705fbb260260fe7727c70240c12416cd9c1c41babc26f33688a561b116490a2254cba4d1bf5dbbcfab1e48413aeb658e121dda635f2dbdca6c985c48c8264ca5fb3c95f73eaaf592565424999bb6d4afdf5b287739509146890f232246a2b4d5ae477a95501178e58f9a1042740504977b9f596c8efb28b053655a474ecca2c916e13eab7e9f4d7b7f9640ef97494603e1da598b24b89f5b7ccfa9ccaaacfa9e4edd2eaaf973a9c3b40126b9ca0e1618db92185dfa5539625b4788152c24b0c26a4bb44e17749d543af0c9621b8146193eef284dfa5d45fdfe554ceef92ca0bd9c68b9bbf6457ce22d5e42c2e2d324baba7a5f5d7c91dcee500f2e508167638e10986ad21bfc91ac4944eca0a503790c025dda409bfc9aa024001b36608992b4c82a49b14f29bb4faeb9bbc22b19e90449e9051a40f72c85f12aaaaab8ad46d9287733c49daa059e2e4c7961382fc7e591d200c1145b4803ca52993eed7d5d3ef57d60d26f8b801ca171d2944a5fbd5d3faebfbb5f5e2ca415e517290d794579317d5df57557e41e5d72ebf7a38577b505d4a1429e28d115da92de1f7a895801d2660713a8344d491748f5b16c8ef71851b98b4b015458519a8a4fbf5e3f7cbe9afefd7d36b081ec1e0514cf97bccc263173c62e1b10a8f3c3c5afdf551877320b841480c63c490b01322f5f17b749a8185146a006303971ee91e9f9e84df23d411dd0c312c41262b041de91e7723fc1ea5fefa1ea7462a6c456c83ad886e443522d75fb1cb4accb2ea59ed706e5cd2c4901e42662823432ac26f512a07942f49a69440e5871ebea45b9c72fa2d3ae143161eae7a38d1a149ba45de87f05bb4faeb5bbc12b1701091080e2246bd7e8b50184af4210ec1525d584ad461291ece6de089335474d0d1c2134a52107e873b4c6d21c14b218a3031a43bbcfa1ebfc3ac0d58e04161450b0f880ee90e7b3c7e875a7f7d875b215711619422c229e3efb04a2b6ca215527585505de12e94faeb600fe7ea159e0e2d4360d5d0c312e98edfa09690962c3fd610c9024256bac1ad0f7e835d7fa5da8809a31b42058974873a1dbf43a7bfbec3a7bfe1102d20182d62c474835db0fe825957e0942b100be85402160d52449460f2258874834f7f75bf412850eaaf6f702a074b37487589b4b944dcfcfdbaee4ecddd714d7d5953bd292da9bf417a28618286aa89287a48f737f56f7e7f559fd55fdfdf15ceef0f2bcd47244dd4df0f6aebf3f1776bc85fcf5d9fee86a9526303902e42ac4e904ef13b5bfded42a5851f94b8e92125ddf94a8adf994b0a2c418ad4b0860990746737bfb3d65fdf794bfc9db9bce4285ea6fcddb949aecacabb9da57232fc7802ca8e24ba256914bfb156d5902436403142e40459e9c650fcc65d5d57968082c85615978f74e736bfb3d3d390bfbe3354f83b473dc1609e88d9b88badc245559867b10ee7aa559b34407a3abef850a4eb3776c25039e81842ca933527004937de3df11b4bfdf5df98eaaf8e3656879bbf4eb8488d13d743e1a2acbbc3b95a86479612c82c59410a98d489df57aaea5a31b9bf2fd6022e91ea25eaefbe500ef0f1376bc83bfdf59c0670975205f5667ddb285fc194bf396618a2ebc70a3c64f8b2246de2b7b55a00102427f43802831b2ce9b63daeff6db9feda24346e91f56da3fefa03aad2586fd62ffe3d8af96b9b84e9b643ec1313bfad53056c8c10420424b844e892b27927217e408982cc942d4b6cd9f284e50b1a273a1de9016e4e57b4c7922f639e44118509e9c5b9ba0686105ad0a1c908315c49ef9aaf00981e11212c99024c557a95f8eb38f0affb127acb9ce82dd3e9abb76e6ba2b7eebd75f3047aebdd5b3791e8ada7deba6ea2776cebadeb17f4d6bab74e1ad13b76f5d663af58158faaf382de31a7b7aee382de315b0c7ac3786fdd0683deb0abb76e96a037ece9ad9b3ff48675d1dbecbdf59e2d7a9b5b597a9b5ff436796f9dcca2b7f9f4d66961f42e7b6f9d2684dee5d65bdf71a37739f5d677a0d0bbe4bd7520357a97bab70e8484dee5d35bcf50e84d3ad19b9c7aebb318f426796f9d4704bd49dd5be771d29b7c7aeb2f2bbd5f576ffd9545ef57efadbfb2f47e49bdf557958be8abeaad874588553fbcb8e2458f994da2f3f41ebbdeba57d1fbe5f4d6c75e888ebdb7be0208cee5d4ba4cea2ad5add00a0a940f6d1f3acc6c0a5d08bdc7a9b7ee60f41e796f7db645ef51f7d6675af41e9fdebab6416ff1eaadeb287a8bbdb73ea3a2b7389ba2b7b844efb005bd45dd5b171241eff0eaad8342e81d5ab10e6ee90d5abd75708dde60d65b9711a13728f5d6750f7a7f5d6f5df3a037e8f4d683b4e8fd59bdf5202bbdbfac87f2200882a283601623511ff27ce8a6d9149679d14bb34924cd269066a57768934aef9cf5d64d287a67adb74e12d13b57bd75b288de19eaadc79eacc780e88dbbdefa8bca7ac983de7807bd7110ebe293deb7ebadf7e460bd078bde77eaad0745e96db7de7a5011bdafee15c03583171d4800697325cd497cbe62e4c7679f65bfe1ec349d4ea77b4ab3111fb6f8d05f665398035daca3d9048a6653b6593827d3c9743624f496e9defa96eddeba6c274b72a5080f9539c9745f14fd5f0ef779fd7e979f7fcf3e7b95faecf92ac5f88c6585309fb1ec867c76d06ccab52a7d0f66b3e92ba5d0af2dfd5aa34b157419a5ad1859e13176db8d56b352a489ff3c5f2516ff55a50a840b9fadd98471ff15a1bf5ed1ee65bc1144e9a4e82d9e59e449e1b42a9538691e4b5f29320196b2b09489e505c58ac345d8afc61883a8888b70d5bde1f034deb6eab1ae1be7a2a979accbdcaab13cb5bcca9205b2e441014b59cac298a5e804acdc71428c953b49e81268069aac9465d1db5e5d5d5d5d5d5de1943b5b39a598c4ac14d55ce9944e75b553024599c18856caa674f5945a47f629655bc49f12a8aa572b3f1ab4804a5993a0527fd02554025df172674ded2c3f1d325a962da8284536b652e45a51c246182a452432515926b9955f1ad16e5c510964456f7b7525b228c5234a71a66b34bfb528714cd6f78b5c6599ac0d6f947345dc339e342a7b6a4eac4538173a765c95f1557f5199b2579ede9465caa82da22255e15c88da2b32323c268fca9b9a6faf663a92aed2b6568f1dbb6851ab12682eca0f8af592442a3f5114af704e0cfa7c75f86660448ab637e79c69554697067ffb571df40e1f7c38572cd2ea598de09716c1ec9f69dc100cbf0fbdf13d08826808becf68c6e126a4675c7e58c962d046ed267e9e453dea10c5a9a0ad6f1c4ec4b966d3222449ad5e95212b0d0dbaeb99d6355ba6cf33ba6fe01b2d63dabde1330404b83a5b8fb2676c367dd93400f9e6cd6f1c3add67b483d16f885f91b2571c21b83f82f8419403fc23fadf35b5b4f52dea19cdde1bf8b3df376f42803d3f652c6af03fd75ba4812e82a7067d8b354a54d3b2e72ca2f8f6998681116d7d572b119b4d1f885ad3003a2e00e1c20f016e463b80d3ad21abb5b5625a5355aa32aad7db757d6f5729a7deae5f1ae700ead1f59c8c36d5db1dc0bdbdbea216fca0d19bf6167ccd6d94d72da8325e7fbd8a4f1863a85b84c590062ec24966b5f681f6dcb6123bbe50160a63df007f7e4f31f41c8ae199dfa2153c71a8d634dadeb8c7f5fac65d259427de0f8d756b64abaa76aa4a5dd036a1592a5e2d4700639d2a5230377d8ba55b290fe01c0c45f57d6dcf8ecfd0471bb6a610b551e69fe5b4786934f75bb652958751297b355e9007d1f6642cbbce4fe801dc9cbeb8a58d2b1f04cffab9ad36fb8c73b6fd2dd7a2ecb5cf5b97b6c74ed06c7dfd1aab36cf15004e9ec67cebbc132e8df9e629ddab87d64df00b40ccab93d6afd9047a788a2f7a782e8179ec7412d3d1699c03b8b7ebaf13832ae6e9e7cde8c49d49df396346ebd23fe2579ef884f6df3acb0d51e0d31880d72bf2662ad2b595b69fff88fee342fe23a2190079cd831cfb2549bb23f393e8a4488aa4e8a26f27495288f42092249d244992244992244992c4c9f199a9cb4c9224e943923d64a9494d239dd42167a4e79038a4cb48922449922449922449922435192361a4499664261de8ac9782ecb553c445d97f4e1b2996f072cd45d77f81fe73ddc783fce7a219d4fcc7813c3bf6d1c5fcf432dd6a6151d4bae2a0f3ea70d1cb814edb858b5eaf97bf5e4ee3be5e2ff7e979bd5eafd7ebf57ac972665eea382cc6f3bd5eaf57cfeb4543b7c8836ebdf3d241b7d5fd6bf6ca7939ce4bf6728d6e0bf5afd7ebf57abd5eafd7ebf57abd5e31747f4e30747f4f26fa2a5f24ba3fddbf72d7bfbc76d64bc1e73fa7888b3ef739352efabcda5e2807409ebe2110a4f56ab356c7c32d6ab1b5d8626bb17f19049d043ff0033ff0fbec67cfcff3c901fe2e309f568faef730a9ba53ae9276faeaf9c4dddb122eba8e4bbab71b8446df2a7cabee5548020f540f3ae8a15fbbc4741a97667b9eaaf4005586ace71c6b9175515753ac47d663e7cf75d26d0a3b7fae979ed30bf07360dffc580527bebe66b1a184c7eddb8f6118e210dda367979db11376bedc9a178c2e827ecfcfc76b36ddd0ab79033f017aba9ca17af0a2366e0fba350dd0d3e50c9407d1254e9e9a68d22db2e29b674dabf9a138f14737554afe2ee14e1af5c8fad882f6df22f9354b95247fd1adafeeadbe58af5e170c81b426a8faec3f4cf4b6bb7dadfe7abd17ad36eee9817babb5d6ef73d2def2dbb9da8b737514f475a1223014185bae9ca1d8fc7dd94eb1903f300cc12fc3903f300ca33e10fcb21afb81e0976308c2e6efcb762a7f6018825f7efa2167305ac6e49c79743927f18484fc8161087e590b981cacad923f10fcb2182e536e905a22e74ce6ea03c12f73d1d223e74c43fec03004bf1c953f300cc12f47e50f0c43f0cb4168f8c1bafd40f0cb27a86073b64ba6c879899c57e821e76c06e37b31d8f5808688b77e1b418a2b34a001b3c3e38a4081bcf8e6308761ce91befda56bae1cbdba5895aa522ed14aa215fbdf1d7ef5af32cdb048d7ab93e1f9d5b1de3e7386e863eafce775dfdf33c07afb5e21787cebedcbe07f2478ec7914abcfc6797df55bb357276b48d3222a81c704705b2d8665d4deffdc667cc1effb2c0c58ad479fe31ce22d8390a4bd49f2ae3c2da8bf713f06f2050c9cc2ccfa47adf94a5951b5028be8cb9010222e2229a2158874ecb819290a43a464851344552c3e2822f2e4c663280a16405a90c04209d18e1622ecc06237a445f401113a2f5c3d845022081e0c584154f0a10513ed8344914ec3c614d9a071b89c408b3810e1a0c32945635644515a714249eca981826c9321493497c49001c68b3cdbc2e9c8806481b25c581b9423738891d8f3a5c52c0c0b7287a24c2be2b68308686b684665137980a8105f3ba0e26bcce9563c07e1201494673d00e92a353bbbf2d3c4070cc393412674b20ccd2c6bac9c1cc4038e48e341766b7c195f70ef05f7332fb8f55e6dda10dbc132b93373ec84b22a7dd96dce8ef3bd5d8b5ed4de7b2f112f116a24a9883d59c22024a0f87ae10381b0f98dd0d6efcd366808f26b42c3a277feac944ffa5665dc6a9dc80e38b06ffefa0df1b3571bf9bda0770622a37307e1df10ffe702ac538fac59c3fc8a8af588a719503fbf0ec8e987e2f020e7f0cd14babfe8ce135a3c33ce395f8b03db1efc7dbf5d5cc415875f79686cb8d7f2b2a665dc17ed5ec67b7b86042f5b9248abdb31da46f13194e0a1c3951f8e20a24c5a2b88820b550e3bd82401c142f1d66553aa8cfc96039f4f5da56fcf40073cf67beedb5f7c4fd4c6edb17f32a90f95ed6449eecd7acf11bd653b190f99d355cabd951129222223521455e4a368c8df5d0425dbdd64bb22d9aee8c6c3b91a4c52d0b1c044162042dafcbe59d00684221f38a10b018874dfba7edf96d270e95a808147096fd27d7be2f74debafefdbd64db7b9e936b7db8deaef6ddfa0feeefeea9bd45f27eae15c8e11ca08e11df18147922652277e1369fddd41260a0626929cc9926ea2267e137101e20305365c88981242ba6f5cbf6f4e7f7ddf9e6e43b41081d122e6ef26cad257445df4151196ee1155e91e114ff788acfe3a910ee7aa9a214852c0c1c81a18aa30f19bc8490a0612945c45e124dd444fcfe6371114971f393061e20b5710e926da1149fdf54d3445fe26a2d244da68226efeee21bd1bd2bb213d35a4a786f4d4d0d00ee7f609bcbc312187373a6459e2f7d00b3a2755218871626647ba87b67e0f518006303a6489a2030d27a47b68cdef21abbfbe87ae62bf87b0d20c1149331405e3f710d4d6908fd8d690bfbea24beb86747ac8e9afafe0e15c03c20061c6092423bc014289df2bac9ae84a82ca981c88689921dd2bae92f8bd220b4b6bab0d4f47e449ba57a8f9bd62af58c1a56545142d2ba6ac68b282eaef5e51155b115b115b21f5d76d3d9cc340cc112c167ab0c10d9a1489df362d105c684184351fc80025ddb6237edb7a1f6831028a1e5a745049f70add0aa7bfbe573cc17eaf18127b6203137b621363eb62c3fabb6d595536dedf6db3faeb361dcee588caa18525588c14699225cd6f1b9a188ee872e689d319a874dbb47edbb0b4c023ca09549e5449b70dcd6f9bd414d55fdfb62adb94980e156d623adcfcdd2aba624e2ad43871fd85c2453128adbfae628773357448783494800505efcc6f1552434dfc80626a0a4c1050d2ad62cacc6f1555171082e68a8b10639a48926e15bc32bf555805f15bc595fead020b96460511581a15512a7ca818f277ab80826da16e605b2a78fc75948773475a469280b0638a2921647ea35a47a889828d151d2a40916ef4ca88df6856932294e8a1890f51a8a41bed15f11bd5bafa8d6ea51be5824541a3c0a2a0538e7ea355301eda8447054361280c95faeb670fe76a9b1d08563d429042e607dbfb7d563160a80851040952b89192eed312f1fbb422021b2082d8d1852724dde810bf51a7bfbed12774084c84130c4c04317ff7097b3a614f276c77c276276c779e3b40f1c16e2a4a93273ec6fc3e3da0c5083233f08010c142ba4f31bfcf18d63cb952c1071a76a090ee73f7617e9f527f7d9f53e6ef930a4c1b306efe6eefeaa9e9716d79d6566f4bebaffb0ee754b8e131f1810213bb35a910bf7d04a7204ea08a820c9523e97630bfbd4a032b5ba8a0b0830c4d9049b767fd76abbfbefdcab198381126517fdda1cc29f7313584d7c5731dcfe9af0bf1702ec71122d0a4e08305166ab0f2e5b7908c1dce7039c1c525cc07e9160ae2b75056069c78a932844d1125b449b71010bf85b690902982902982909010d5df2d54650a4199423b5348eaaf07f5700e035d636e6842c9921f74c0fa1d54a138320213676ec04ac2857407fdf03b288745489a10aa70c16221dd423efc1672faeb5be849680898203060c4fcdd4159bda02ebd20acada0aaad20de0eb2faeb413a9c8bc0162740b0a10ae10b0ea997df414e2190828411509cb070440de90ebafa1d046505c5ca4aea863160d21dd4c3ef20a9bfbe83a682a84a266d4a266efe6ea0ae2935535c3ca02c5e8fa7f5d781763817aa41c24409251f9c8025e5e13790140792f0c035029b2e1ba64837d00ebf81a480a1ca13504988d8ca4a375097df401b0808ab0d109136517f37105409e4a3041a52d6ba4a205d09e4f4d76b3c9c7b00970f7690f24215ac255c7ed774a60c3145550a2a84a14a776dcbef5a16053c1c4cb08107066b8a74d7b4fcae69fdf55ddbaa7191b528646d4aad09d5df5dabead5a07ab55d4f4aeba7abe6f4d777ede96f6d08c9e4070cc944ccdf1f72ea879cfa21793f24ef87e4fdfce8702ec79414ab16744873830b4c58fdfe410ae2861b868042450712e9fec9f2fba7eaf0640bcb0a63acae9449f78f0ebf7fa4fefafe99027fff50b569d3c6cddfedd345ea7cd4903a1f2ef2c9278b7cf2e99101a022a814091a0f7349a714325323c00040002317003028180c8a06a328c9b144f90114000e63b65260521e0824f220857110648c210a004000008000008001a588ca00984ddc1a451fbaf9cfb961c8ff7b3289e65cadbdd42222f66c6dd6ab7c1bdf1cf354aef12ef285df769b694d6dc1a333d0b5a3f8c7961c74a0d18c4e3dd24813a7e9f27ff25e9a1dd91c9326343a600a343ef5146b088a2bb11db8e2bd1fc26e9e0acd637d1d476173dfddbcad8b587b7267872f7993e8e7dacf52614b1bdeaafcd3e9be3aa9665dfd2e71d8f38ead7514b0b51baa7d7eab015f23ca901cc98c0413bace4278363584745700bc2f7ca205439e90da644d1af0b2c967765d8da3d3df290edd2f9cf2f48b3bdca118d5d6219b6ae8b4c33159f190f0ad12d23661796dbf0d3d46d64c6096ca0565c41bc82e53925b09e0195e730346a1c0642ac0762c782667a657bd58983e3a8369db82fc14df4c805591c5fbe8a63c420b9f468bce76a6f6e011d37547d5725005fadc4e0fd345637e8e0cb18c4ae6dd1061371328c52b1243f80e949c444a63ba5761a8afe2977ec36594747496e8fef731c433c3eeb1d0d4fcc9fdf6b11859b24e1a25930c61d914d4faba54e98d5ed4fa360a3d63e77d8aa7829e273a89c921b8aed9487bb9631e24bb547289d42e9521f2525d787d157d6f87f49345f26d501e97472c6e0d1eab884ca5d0a58fd4dbf8f3918233d097deff66b59aafda223d13c89e77d3a2ef63da73678d9de076508298328aa1c0f6c8bbaeae0dcca05c424cec1a375b4140a5c3e1a600280a39219be2449bdc19889004b31d38a7abb8d11953520f59b045ae700a7da6a498aed89686f7e93aead269de6e7c31b9abd054b762f40cb42cda90661a5b4a99290828a69def47260d649b6b29dd69b987a21275aada3f4c3616e554ad56832442805a962a68854d48274f4a9379ea14136e4c3e8b34d6377e003f991b3b73e4954f2920b0a5cbaf78b2852ccc7d6f7bc11981e052475c585592380b8d49ed07aad0b6b4f3aee88367545be5f15a2636cf5a225089fc7fc859ff7d41bfda5379385a2293bc6a1e9bc464b9b2a059484323829b897417ddd929969b47ad0a1ddf0339df0f15388d7c1e88a801cce4e69b09988e7b99428bbb2bc51bb64ddf4f022d57f4feb932ef720745e33c403818245b4f786ec3445ff9b020a71299336c04ddadb0b968f1081b6981a7b05a70276f8a3e2475ec520972156ecb28d02b08c266e1ea436434c9b06eb243fd122bf46219028429b3c013b9b6746ab970370f957df6fd2f64f4edc25d7a53f220339b5337a1c145c448f46f9d2f638b9a1288abfe40a3ca171740f87c1da80fc6349a5cb97f64094a383086c0dcae24701e8b0e17ccc5c07accae4233dad06aa3f31c706e046b7e50e7e9012e270c941886884026fa8dd0cb94b8dfd96a9bb854b39853bb78b30b30d209e810e5f256e703a6a041dee10f28cc625cc31ed8dc3520c2f8593c4632196fd7a2a8d9a0739414c4692c11b771f94e059c92aab39bd05bd24ec8189dccbd68b43e246ae26b2169b03bf141a60d200e280b6e6826703a008e9eddaebb7c5c3e5aa63cd390c8884e9e5f203755dec2f9bcaf695e54d5990806af7b6795acc3450fbb5534e322068ed64018e2f83ed9ef25705b193f2eb28fc91190b3c4685e17053dbe12eaaad9e4b683e9e35b32dfa544f1e87e301a1c4a6a5519be059303174506af9813a142da9596c9f9be4025a77ffb80d9de20e5db07286065345dd331684fa9dc4c352704695315322e616356d685f5aa05b043aefcd8882a949190870984a2a0ac1711d1f32bbe380a5169c09fdb553805cb7839203d0e961b5c3b6712d736b0178dc0c8fdc3604458418ef59a1495ec17edbdb0fd93e482a505b98e645884c80cfccaa2ebcc151a4a59593d76476620572e0288eda5954c755846875d40ac7c68114296488107a4231b80358a59fa70b383f0d36f684a5119885bea4c36415da8f7e8e4b551d995b449472234e3e14f58c2e75bbb060e558b7014abdce08fc5bc86dd8d83d18df260375ab882fcb42866eaec9ad651cf204ef9790048beef049781281b24a0b6aa0af03f183259e16a4ae993d60d471ad0220cf65220df03161ea5d63150ac17e5828c4130603d662d2b7bca17cfeb7cb85913df739cc507e3edafa0525d79d0c432ee0611f908d7bbc0a4774701c159ccad6177486e090f8e1c26c2432b74dd77c9109bf448dc2b1a4d2594d3f90b5260b1f31bda13e67ff72b008d1c7b5813333008eabc0ab8e65b7943d79827b130f38fa6b3560131e08352224285d60ad88cf75986348845da5b733b53b4f6b2a722259df684eb8a197029e92f568a2328bff318b4f6bac434abf55c42b357f0955d4e879607e48cb80849dc3cee84f722fe6daedbfd4cc20cbaa08904212285acc9f76b2f9955511db465e06dd0a82d9052fdd53da7c962ca46052153222a0d7e8f7a82fd0cba40458bd8105b97c4fd3bd2728d0b0797559fcbe18279dab5b9a541ae2423f23e971d0fe1d60ef654a3b512932aa0ea8e369d8240358f3d177e410c37ec8b918b4a7e97a243b382ba64e96924e571117f7458b358242b6795f0afb0fa388445fe239e16cf02d1be3e6df042448478e1bc457769af7e9705c560038c239c0132892f0e270e30408e3f8ff30388a864794d9f1d8511e9940a802a88ad15716c87d127116145711ef66089106924c820dc365d58b73e8832248a65ade3ea71a224bf922885053a7b8371eee4c3988b55d516e545bc6e16468f800f27808423fd5291b48db1ea191a76afe23448a6af1277c06994c93b41354182680169c2843ab568f9ce0718fe09d05f3aa1f9b51aeb41cfa0c61be9935ed6841a1da7d44b15439934f91c5c412857b17b4fa0c89dd026c15ae385ea91c9a906505e3acc355dda2e9ea456de8a793d5f3299d80a9230f0ce2c4874d849c8041603445b9e26aed63592e7b51d4bdd4c88c9c39a7cdf40ac46fd4b48daba5523e440b8a4a44147ebe6666fb573dbf1b2359bcc94fbb656bdd1871efcf0d343a5a1cb3f4c545905919fb0e9da13a75a97a7cbe996b30fe5562190c095150871da3088bdfb3b235daf2378c3f1a6df731d7fc8875257a1b79fda8859abab929b323932b3e8059187c810170466ec1a012018f5c16fff5837e1e203cb1a110f85a23d09b23acc203f0818b7cb9b082fa1bd61446f68b5e03d58a54e2bd96a32437b3e817b459c661966891ada83fc2aac6da067c268ad1b58a88c1fa290553f059d3c30638956901de9d54485f5269b10befd432eec6d1a1ab0cc8a15b2453f2562c781526acde7801927b34893f06373533b7d45e6b48c4ba67d09900efee3e23162e238ac260bae8ef40a22b255264c0c3f21ede8b771d884692692e93f0ef41656946de9c9c48df1125a902fedfe302622fdfd23eed8633a1ab3c00a2b65b20fc67d2b913327b3a62b8912564d3781ccfc83713331dd27e782955322330f1ffb9859f8806e76ddde7021ad993051d9d6bd4eec18a7b4644e566a86d4d83864c2c426920dcd9c8895879b326902b2a14d5362e25053a64c2083ffb9b8d56f80b492721ce0ca09e3b13a3efedb415726ac3181ccff810dd5bb28d7e79890af32c6245a2eb3e2976034bd4e6f084d2f5aa0fd257493ff6cedd36c84b4087cd42bdbc44ba029a51dca82990a4767203b454a90ebefba85dbba68e356900edff736e47094354ea2855b898c9edc0ecc225bbb48fd7ee7896122cca36eb0bf3d850d82dae5665cfa9314c8b435b858f38556080139d75cf5da329d6345f4f12ae567c09dfa7213c130a08a4e90d4aa3b149384fed197e3e9477129567cc28f4a3847701d85cefb443f7718209ef39de54064c203cc2e07a9e31d01a934a57080af926fee6e5d37fe1ea521f6c674e5c8b44ed060246968eec115a0bb88e0098dd38be8e0d2a7832ba10eae4b325cf893e13232ffb06dae919aa1bae8d0d1f0b221c40a6ee862a2cb5e4d0714bcfb4a90fa3f3be27e64e92fdd64562c1caf3a87e0e96db1888000949f57014c69543bc7f05861d99cfe52db502d7b1af734c23b289c6182b2422d007b8195c932001c6c3fef3b1b3864f2067bf37cf8579a0c28466851c129e684437b6a7ef03cf06843c5d3cd0fe73ce5b215f54e373ffcb424e03654e12654f6e8fc1f49d92fa264323626bcfaae27342a64a33d4f09e32ed5a62cc85f0aa4c846381b297093222f4d1220fb4f64465e0ca7dcac093f3eaed7c36a7d09d4cc832dc5c15084cae1b96644ed951f18fb6d95930056e34cf3a2ca5b6ed0f6809c9da8b29517da5f008e020bb6ccd9799773b5999cd49eb715def6ec2eac642b4adc5eb185e9adf196977edbbd1331e867a8ce6dcc46cbd39d08edf85e80a3a967fb6a701457642b3b6f5be1855987f1396e9991d913a99868f6a55c23cb36fa9191101754a98a8e72a9f9e4a4cab429fd3a2771ec26d668590e339a39c94d7c687f245174db142e813901572587117075de0f83632315b37d0bf7dd455e649e9be53cf49c7cbecd459dc72821124a79601cc008aab5fec97a88375dfb7681a5aa4fb89d8bc40096e803c76a7ed9b7662c06a3f1327fd75d9dbf0a4f79729b0362ceca7466814a4fe0a9484d16b1b6acfa8cb5ace96f5aaa7f7cca31322ead83cfec42ce1205249bb845c14f9e1b7208f9c389a323aa820a8fe11c95a6a7d5bb5d4e35a7b190a4893578512ea3bed8484ba220a610d20c59aa5dd4c2b01dc5933a08e4bd6993e19922d8c509293b355736992042b58528d3280039fc0c3069eca6881234248338b9553a350df75c7f3956501c5cc0dca0c3f662ca6d9e0cce59f58b491c1aa71572702580c50698b7895da5a3e135e2d7a423024aaf7ca9fa1490b24cddc0e507b86167f263e5cf811e1b086eee70a1da8813507b5a0842b5e38a8fce326bd784108ed6a15f8eb5454850ee1d5a255d5cefb00b5e7a72234919859216dcbf7764b37cf55a32db7f6a6231a9b4c02b7d9478d263aa4ddbec17be80ae16f8bebf5f897e9658d4d7debff96542c658de7725754c5823eb134829f9c0da5cbb9d2c2f7d5f80e06ea244ccb5a3bb789963589fa5bc947dea01e293b509473be1dfe3cd60277f28ed50a59ba77c0c297a28d9e84629d64c80e9b7cd8dac03b02ac31f44477532884c09b00be7de1b71ac0d2c33c2461bcfa848d4983c833663d383393c590b80e9c8d9a95853ab5783c55c9c8c4afafba0347a7d192498e7b38829ddf3b8af967fee0023afbed51f7a5c73008cb8185dd3351a53b62bbd62fc74b02948005829938a905225c98302e795aefd0c2160bd7d113181824a3b8bb4ca79a17108c11faf4be4bcc4963b6b280f107787126fe5ce523a487019daceda0ac19d0a6a982247e0668f07955033fd80f668381a07443e6d854dc63156722aa9d71c9a90824dad985af379e78812b7e0451f161351403e74ad4bf00067c7cb433478e438e06779f3d7a1e4a8d69c1c63c0590bf4ca3e18b9841e8ae086ba00822f9478139895d6ed92e9e2a905b7d2daad989f46def36eeb5a37e2eec5899755eed980d75a2fbf5a1ec6e20b64fffe8681d999cda81e790dd0650bbaebe074bb9e78dd9ed1d4f7ed8e078e4ea2cf3f5cb501ee9b49cce98601063ceab24b4883d670fd72f301ba80ed73332f0edfd2390ff702226192f95a702cd767276ff17a11b87a79bfc81bfca5d02bfbb893eac560d4150bd82989659a32737d06256323d8e61020adc76a3a741101b506a1d501416d1a4abc7b9108bafc12b004f93da056573d9993f7a2822cefcd1034608d60f3be8d22a0a6311121eea938d6e8eda267294070b23e8f64994aafb95edd4708936005ebf2ba4282e2060176d1be11558a6664ac90e4eb923ebd25aee87d0cc9f3a83ff73d935c7e72bb8e794e6025fd5bb33fbcb32b8934164120c8fcb28307face6c2afbdf80ac6a06f640a816ca84a31380a3b138f96debb920689701f19327ae48be359c9b27963eb0f45687fa95f7d888beb4836607bf022c9a71b9d649079a271dd7226be9762643c9730b0cbd1b6d041baa65a447f231f84432ae121000326a32e488a01ce3d051f2d4e8b23e53eb0b4d5cb81712760de61828c35058b8c9ae89eaa85f8293eed0b70104e3e9f0997e4e879232bd392902816b792bf96264f442cf5825da4a24d6cce9a453c8e5188fbf0d508c5d468874c374f7050d8e58726810c81f1ed0062d303d0bc289b5ae7986409d6c586e9331021e874e0afb0e915ab0c8403b0c9e022dd6e974b7b61a60933e2b0c859df4bd48e0839288408cd1e1276550810871c30bd053b50153ff758d83967fd7c1779b9bf0b829c30c98d5c71df838891845b1f4256bc45c2268a33e40408df62df428d7800e4dd0bb0ebe1bdb84c7471986c0549cc2c0e7580fa422decd6a2ff549fb350766b16e063da049a96209dec7134ac46add0c501a430358fbcc7ba82496ad61553a5c3639bc3560d734fb13f0eba8a6f1159dad44f5ecbc6e0501422e8c18c223d80514bdf5e29b1734313cbff05a0820bf9bd124602d479094885b834e18772341028abb2d6616a820739c1305d59fc53323b73b7b3887b2da9def9060bde6570e7f40564ff7e598516f3cd75557c0736d25924e958430a0519a643a183d598fa7c50ae46fa34989ea6fc4fd0b0e5e022ea0b7a585b93f871fe91f0181aa7b8dfdf48a7e78dad35508581b5f75b7bf79898aef7b8724b53680afdbcfa692b72daeb800667fdf778c3232151a33c7dceba9e904e33642b15026e027593b26de1663fd3134c53efd07a705a2a277b6d65845bc8df1b1b0c754631ecc3dc1f622c1f19608e17727da8ed45c7ad38259694776dd713bef6ae7fb8296455859cbd49fe76b64e62ecb46dc35b2015882b80bf432c04c5e97ec9183d0e94053ec7ec53a24c887bbf63b4a30f3ac740cca4f0c4edccf83663764d3dde5118177fdccb8fa922b500b99e0dde9e98efb900cf727b1b715094475dd1506f070f3ccbd5330c7839d0bc2b1355c6351ed1a4b80b8b4fd662f1abe4677a0d39a82504afd79087554074b98613db55a5161c4825d19e5a173b9486a4fe9722201f8ac91b2deb558a83d1560740d10cb71fe45cbb125f1536f657daab26c995ac93ecd5623d0c49c6c29417475c8b7d7da8a49de1ef82e5c50aa85e92e9fa25bd3b59490ec1f182f90220e6c9d3dda03e676f26ef384c027078964f11b3acb9edf188734ab8cdc889bf71abc4041a7fc64e733951f06b49b551777b7f481df974784aced2540054d8bc14ddd38b8a593657a1390701e14b6178848346e0d2431e3b9f0b83b51e02d49bb82aa8d0907e71362838655a8d1c0b798a4fd0858ed8623f4cc7847f758be0bd1a894b489a54176f34af19786657be77fde0a0f66e970f0ab6c323ed33b9a2bd58d8768f535aa686c97b5bd12db1acc955066e47cdbb8b0ee0ffc4b78cf4e1104824ce3ededa5e168f6f0275c41120fe2aa41c4d56795225e82e18437c9f2464bafda3a7acf8825ee5eaf8346b494ff932c0dbfa1873afcaaf0be3f2d304ae5ac84ac7fda4baf5d3cdd94c9fcec4ea83d1ad99600b89ba928719117223081699196c1f058f0e2f458a9bdc172edcc8d6d833ebc5cf929a0ed3937dab80888a2e19ad5d2c6dfac4d842a8fb5515d4e7e278ea572729b1d75d2b8cbe65bd5d20ca72c5e70116d4a919b0c42458a8d1c5c0db95c7147343cd1ce75ae1cf0ddda17484995281ef575a06558fcbcd8f8955b78cedf8f3ad053482da3ca8a8c4268c6388b257d160cad4bb8634a3be743f3403e6b797014b9327ccc02d405f9a2472dc05830a1471a264ea008c968296e2da4bc80fc303462614614dcfcbcd71ac0a1af1cfc79bc233a4ae3c15691501abdc18440c409000d811e89caaf57c4734b1cda101535ae6a08390cc2aa778a44403e75b276fba8b20949531fa481ff8a7176f0e4a8b527acebd2ebc2af8a935aeab85e3b27cbb2643d4aa8d5cf052add460e5d0d50248abd0a309f0bdf883f843ef7e7219a968e64f9d6f7b8cf3334acd044c63a5316e1d0ea89e1ea13c6c0faaefe7c03c4853750c8bf591e6448a6a3dd0734e7ea2652b0b321d516cc98fe5a042bf754a5d6ed54e28ef1de1e6588cc280b1760dfa4b92d322d025f4c6c0f7a1800b8c9a31a8dbf9dc732d59a5caedf273963ca7f5b83ed9bbc38fff45702159e04ad5a41d9980b3d6cfa40f4e6e73096b17843d47887dfdfa867cc0899b16f57b5dc173d407072095ba490be9601d19560e025affd6c3fd7c72b888ae28a0ec089ea787cf622e4038bfc30c9e3b14430b77d3f9e2e9955c9fc53bec34e6b2a7fd9b6ec69a7437cbd112e3a8c52e5115aa5dfe206b53b0407521bc8c62b86fca04e4960f144d7f2f24972c019d6a001e8f5f0884b4f3ea124aab54cbdc12d6d0e7fbe953293a6c1359f3d2593f794c3a2898ed250cacea02ec41ecf08312b999794fafba93070a0883a7b1524cc59fba3bb85a02942bd2e0d4160f1686b98815f8b96ffccd2b406f581661b70e921a0a2ac80c15ff39c9f133aa0204cec49142024cb765397103bf1f92989af2d67116e133ea8a8e86bd323b5c256584661fe1f366d40e3aa20be536254ce39ae4e65f812459779a91ea84a1dc9f0d58533d205820462ad75f484d43151de8b765bb8fb060fd183739f834c8aa4387e483075a3c89f4d8fce0e7a163d0f7bcc9b276611b57122ade7f5a03916a861be49a04068093a094e11deeb2fa00b21795218eb897cf0e59b555f738c92299d7146995ea78b274a69353f632d5c31c39e4cdbdf79a91761bdf08305938617d5efc49f755aa0e6b5c6bf3223c9f9058b33fdf2a88479e96428419e484bfd46a8a741f31cfc7d4d521c11a9a1c680b1bff22b306173095c6d3224274dd22db0e4fd467f9990fff220b758e21b4f406f9acb6eac1c993250de2d35cda3156d71ebb25ef04476e3e0cbea9882590744c3be8cca0ba5146fbe7f3dcef9d7a74ecb14884158704ed2aeff71871939e9874a5c6606af1f80cf558c1857dc4855de7460d4511126c922215c3e742340b31d1b5c3b75c848a71d71e6f411274e3b1e0bbc306801ccafa0c24e30aeeff05bbf99de67a47cb6f9dd2a471819902dbbe4e13f2b700ec818e7d5cfdfb759c0909b0ffb1105e3475cc00d382ed67a2a9321e5eda935e9960ccbc2da161f65fcc009e8efd76dda3fb759ce9ca624b9a51bc1d25470eaec57cd68bdc9e40406221871d87eefc7e074c5b064de1f97a7f874603671b74156e2e9e2b8416234bfabb8b9b1498df26dda1995549ecaa2d6b47e406daf69f5c8824bd11d2bb6581f3f7012b74ee68ea0624c3ef044597e1bbc7bfd047c087376b1bb49a575e6b4ed52531f1ef9d8671e77c8c6f500a0365ddf2ec8f8e58d0177d8d8a52832298678e6f27781d35a3c4fd4c87eb124863e8f644a01a630ffcd5c45a137d57a14fe3a1e2f87d2f10cec055a5753c351b3355520821ae8e90144e65b3d4410b5046da3d54800aed416770de131bea0df5d0e6fa1abac86944d5bcef9a9061f5dc82757e998fdefb399ec5584834dfc4ba4f47db06991bd1c7ea8452443fbd12c9c65979f66093a5ccbe708e1a5498a1722619a93cca0004c355b70edb15d1f5b3a601aa6b8d647cdb147a034da108e24448ff708a5d34b979327258edeeadead7b2edc619199863ed14db7b5b4a7a54adb74f45a1988762a2e1098d81277134d7bae71e526b5473ed7a8729ddb5d0ea3d3a20a57b13c4825aa64ca96e0909c2384d7b0f30fb3de700afb1887675accb6e401711fba90632520fb680e5f28c518b2784dda01017dc01475a245e3560d324047758ea20dadcbe1fa590b641d3051697069985b00ac1cf8a5c1ff7ac920093ab8606e52264cbf63d7e8c034e32699455cf8d1a2ba5a7f80f77c3795940d8de31759c66af7c333103b7fce6182eabd3fe7f051c0a515c513bc87a5ab8b292a6d7b350eabaae8b4584e6d1dc67d85f9bc0c6e912f69209ecf93291272b659e2069d0354c36d4b744bf9d744e05aa98d94d40ef903cf4a33e4751b66cc238a9fba76e1bf2b136819a3be28e6fc16d8293d73b75ddc691a393f7793154d550d2ef70c8c99cf9de43c1fb58b1770835e819d8c590f9c34995e818d4734319dee4a18cbc9a4372002663e275d4283733c6ad80f69361f768fbd9cd1805e454074d487ebd9e398116f14f22810f94f826c01b903e9b463ae9d050e2a6cc801c4ef9e3d7afa8d174f172e44914d8208699d85f0fd77efdf3d7b849e922f52f24d5238bfa59e9be8e411b3cd0ed770f34fa8ee9d7e318632d1761fc03287710e6f86415989ed8e6857b82f81597b2917434d1a72f0423ce20afd758085b152d02e07aba0998e7c9a75993e3701319e70ba52ee49d07e65bb3491c9eb96cd1247779441ad1284a30be8b7a162188d97628898a318ad09485f419f44a2119d7aa6bb5c63b4885cfc65dc284474847c8954964f07f8db960545d6ed93fe8aa96dec8cdbb208c8963dce210dffa58f45a63923feef227c4f48659b27a2452ca04573f369efc7cfaa39e90f7bbc926617be5839d9aec0b85b0765f527ffa39deb652860e5a4a53ab64d6cee1dfd345a0cf0f7f7a54a120d6e3278d78ee1145c456ec76d58f454525baea32bcf14952008939d338160179510ef2ed0324525a2470f499733857cbb5132c3bede02842e5b5347186e8f5b13c3aee74af83818643eb4c23e7f10ee10696b90a07df12444af27d75765c52dfe9211869af2c1dbf0ad9bd768a31c9c3fcdbcc3c39d54a0b24408969c8ba15bc31398af27180bfdd0e47009e8a1a553623bf67d2f281a428e1ee9a70fbb98cbf234b4a0814be188d57bdf432380d3a6a6b1a800cda084184ef999d3843bd8fe96f4ccd7042670597696c382cdffff90137bd36d7bf6cef744ac335c5dd75ccc5250a954a1b600200a758f655bcfca7ca6a2448c340b242dddfbcc5b02ac6c7b62280067d49712319607c255c78b4466610e790eea16ebaf9765fa21c5a198e64260112c05ba9382fcb9573bf730504a0b59cc16f914fb8c640d9009bc94dd1128b260184970ad6d20af4476c883a557250abef836ea1a5820ff10456a84b29c24ca66aecb31dabc89b2d98c4dd50cc571101795fbe9677c2eadbe349b1fd22ad5ba6e6490e96934886376c79567291ccc13c10020c25811ea15691655a0417566a5c163dc6c60336e6cb08ca53e903ee50bf82edd7d5508169b2cc2fb2d9e9e79504455bce4ffa821b3bfa8c1f31faba1f9dfc81875f7b2f2f97fee01ef3f56f6e85c3cb428310494dea4454f03a1f182da2387a597878ae59f070b0b640f124be61e2d7b6459dac9288f438ab90b7f22cd750f74209e10d773bc2495909d36a13d4d4b6a3d5f96f83d9096a87b722d757b542efdf670a1aacfbc40b7f724b207ed9b0edaece34e7d1c4d651552af72881d9803e3f30b266654b461d6259f36125db2a50da697d4b561f8259f3652a5b6db06d3efbd6d24452f97b4ff27e13243ef683da48c43c1cc9b64b5a176d97da9fb86f02816b329924411489c501812d3a8ad606d0146113ecb42bc8b919cbaddae0c66948909a629a246d0683b65dda31d4605f79413619c505c757c809ac4c98c7780d25b9b032f0e313789efa0a4d4e017b329524018d15b9be4dedc4edbd35e8e6568bd34cb99bd4dcbcabd3f9699bd302e137b732c37f56a2c7ff6722c43eea558ceecede84e60ef233ae2c732a8f6c9f92658b9894c8f9099a9b60eeeb0c336dc80f19d7d5f01ff46d5f07393d53373b7ab2b717fa933e5865227e6ce566fcaad56ffc4cdaa0e999ba49e39775b5d99fb4b9d393794c7666ece708a19db4b663659197d7765ccb0571031c520420edda58622d7dec7e859ee4324e8dd874dd0741f3a41cb3edc04cdfb3009baefc32668dd8749d07a1f2641eb3ecc04adfb30095aedc32468dd8771da6509320ea2b50a79f4e6ce337e5499f81713949d4e2aa5969b2ed1e457350cb309e37bf76a8b26acd7e08d4250436914111a5a5020d44082e252c352148e1a84a2286888124553031214c41aaea258d4e08242b0861214911a5aa240d440f2e4510d5ae2ee01b89ff6b6d23e1967470a5b710389bd8a5da7bd22d105c84b6852c3703faab5d09075c08e60a65707108e6cf751226990044e47cae72df795af1f7e3ea1c14bb32978fb2d28a18b0c6a47d24407e86db92a3f3655e1bd88594e436c355481d09f19fba94f2da6039ececa6a2ba1db369304359350a72516ec7cecded51b1f4064ba791aa75bffc0da11fee13708c8b8fe9057483cee7b22cba86e228915ebb46bd2143a590672c82bf340cb89463f793628d9af50fcb3ccf3a6f0b8bada356f807fbe0afeba3c173428774d5b014a5a52d0ba091adaf7b38b308133229f6ab544fb40af14949c3dba11da660d92e10782c84df32ecab758743b1629114645abbf4998a1d0126ffcc3a1d0a04dc094fc10e31d7d7de0fc53c855d810ac644a513cfedad39bb61fa8218009f4549a1f1920122cb3b891ded681030a6e5060c54291c8a20af0068ff9f402097710e4155177efdb30b243496212cd5878d58650fef871238488f6cbdd69070db7f4f8a6dfe1baeea6ecd48060088d15101c0f9d5c2b175389f6f2d540243d884f0d4c47e0373273a72034ec36ae693fb5837a6a3bc959b85c6f026966187a10da300f610d99c0c3e17fb340959320be4a683ed3b530f8496ba55a0a18c527dbd8f347bb0e23647156a450f3431d6b8d4bde9ad9c55d0004012cc62418eb10e39509e6f77f6afa0c86d96fa2c3c27523d82fc5c040b2cf6a34bc06d9c26513a23dd1771a42dacab4a0c038d99f61c00b575eaa0ec8dbe42a773942d82a923816423a58af41b65d0d9528b05dd75c7540561e1611825c33ea0179594483e07d108218e109a7d31460277728bfb887a89155ea5ab6e5ba8f8a83c5a70a6d376ef4bb60dbe55bd971c4df31b61d48189dfdcb5870631e3257e67b5248517ace70b1e4b42253518224f0a8558b7719c4c91b9f837b10637c4cae21c6f8807fee5fb803fa7bfffed9aff4fb7dfddd5fe8f75efcbfdff41f066e8a505cb01b44e6242e3fd2aa67ce67fb8262fc0fd4ca1be1a153cc366ad50a9a5bf58296ab5ed0ecaaf7bfbdeaf5632ad5c303e73572c07558b9880016a73859ad0daa24dc943d1d3b0730078a86e85d311e69d769b1a321ed96873ac9775ba1240f040c27744670d94e8209d3049053f4c9a2850a4137916854b56a84aca506bca0d115e44185048d4dfb3b3d445ff8ba469a36cdbea834cb51a259105e39b72c1132aa7dcc519557243af3b5427e3df49070421cc0fb86d0a65a0059a4a4bfb360f8f49aea084dd5ca39254d8d255aa69a030bf3321dc609fb0966247802d67e10b5461567ff8980bfc97c831d6aad5181183f71c0ed3381b7e2d0b461b383b07dba7e8d2bc92670f843ef8d20f3bd74163e3aebd215d8c890036988238459bfc3263b6c3b889aac2a461f0b643f3cdbb402773be3f5a879120d2393a1c06c8b5a8ff8884d14206f8bb414c7f7bb5b3cf29f8472ec94409bb3e3083f64efc0f9e6d220114a6a02770391b31b86f320afa6d3d819bc6660a35281fc9d170d061a10796ad6000a8c8963684011c2a4395464856a656eef0193c3b662709eeed769bd3e60741b0ec67a837b4feb9f8017f097510e63f42b76fb0a96e306affe1b5299b0e38f9683ff51bd6f4144f551c2889b1838dc22db9a3b1a742e75ee1500231fd565b5adb1efc7afc6600cabdf84713377be876af28f2ccdf3cc6ef971b3ad034709c6ff8b30f1ff76bfc6b81541088d6f53d1f24d25a98f339704038d51be8c4e0ec2745057192a9c444530b38ba8d57ce150d15774a8c0654cf19debe0aaa829a6a8427bbea12b4f1a25b2c63a94b5fe5c9429ec51a617e22b3c2305c05f5104ad034746582c42dccdd1ac5d6ce523a2b383d4e98a83ec19aecd590f1c6097064cf7f0a8bf08d1f78e55b0fa5250c99ea43407d706431cb42248e4122686fc1f674860fd0765139f1526f451b415653c9dc1d2cd5f9fabb4bf2a0d44aea6bf4efd13f89726d653f60e3bfde2c92a1b871196f7f997e85a93fe8ec948d494be0597f2c6a873f780c8ef3c8238380acb747b462003e6463410a1fca9ca27503af986504a7365ea451c3588a5f7fa23c4199a0b1e6661587d821320eb323998176026156a3a0dd04495acf90425724b9c67f441b9413a1b02d145921929d5054711fe604cca4fa26084ead2912aecc4c16a261fabad8747859d19451036ae8d8be5fa1f479d40051d1144f6be80826c7846648a34df0af6f61674cb0d56adce67d8eff71f9ffa18e951bbdf9dfe66d671a0aec902c08e8fe2297c8edf6b823ef1010f7f71a44f2318612539b58ac033df658c0fc3b2747cac106a417305a37baff069cafe733c1a19067707713a6d543abadbed259b5f74247702e053801dca07add35e77ed4f4491c5624ad0abdc05c4d8641e84ef293327c875ab65653d8c81443a571f8e5f74e5a2f240996c441eb6567d64349392e7bfd5e513453d76eee12ea57dda92c2bb35c99f8f44a18ffe04e5aa8be4fa10d8558738bfb1ad28bc5c357cedb7e067861f186dbbb3a245960965927901f5c23f9004a2e27005ecb7c3b9352d4cb0c0b4d2d630d8e32371a64377dbd2af7900d45ecc30950e2643c76ccdb546daec8e6223e2bc9bf8b5425b0a2d24ad75e055472234cb101a81e7180dead1278b1e09abf3c7355aa4d5c0d16e97e81a711646c6975c6c3efbe6e8687a5a20304037f3e9cebda2d2978bd3028f7bcaa1d09e3889a49472e7655bd50428c67731fd43fc2443e0fe4063a48b880b9b75015dc58455fbeb2f81ba2923730cea811425dbd4dff6cb20e76c33e8e4f528506721fffde6ba9dad16a32d3949b4ef1930f8bedc94df49b7c002e4285cc5c8124656ef9021ebe6b9018aa1a7481daef874c19e7d710e52d1640a4809b3490562c75feba6ead42d17c6d2e1fef5aaff8b7d012ca1aa424838d4280e5052d2ff93cc1a20b2394cc889305e324ce2b5c643a06051cc679cbfd0811e503197350f38ded07eadd56cbcc0f9d222a21f14be5741b8ec479bd388ccc517c4d42908d3c398cf37b2ac243a6c78ade57ea7730c51b30273e2e5e637363ec74567635c6056609a3c6b59eecbede479deecd0b2a7a4655f73e3569f2ed324eba9e1ff1520a2b4905af6c0af514daab6ac69232e5637be5091385079cdc2248c063ca1b985149239f1433b06081381f11b81b3a968d90775d6f3e55442a4b8f3f3184fd181e4e6762f0afde111dd22080814703b1e8886fffda8de78dbd5eeba706bb1ed45803c233e05121f04a613dcac7ba7ee2b34ac59a2ca9f439ff06f7fd158f84f8d508a3d4aaca7505c7bd07b54ecaee5bc708619bfaa0ed09709df31c6c4f21310f11bdb3f2bb89df2ba91ee7f7d425116290b19ef5cc3cdf56404b46951c0c8874c678b38986c88b2fb6b2973c13a57269323f5ec79f876612d4b58fb91c44586ac06cedbf7ae14b67fb009cdb3c5318fb90adfbd6c6c48765b0b774cb05656b1ec65762fb6d728b2aad69ad00bc8a0f692348357eb87530467343bffeb1284262a3fb3dff9a8b075fada0b76e05065b0307f14a765f79af62ea7ddb916e23d76c7dee007dca04eb8d8187516c2ffe7f505d3f5abefb8b68c124288937dadb9930f77d395be797c2a4a7e60ab9aced9cc3d4976c77f1682e847b27571f284d8f3a514482b3f37b000b07950c45955f900f31d95c937b99bab8ca47d1e7c83b0bc459f11a19f74fe2c695e72bc8ea395cedac4b38abd2ff977eaf906c0c43eeae22a93032a7870d01e19bfafae85ffa9a0f3e069bc0374bbbe968176173b38e4c5383a35d80e4e863500e21905f53875dd4d78a0a5167e30fe1b87d34b058bcc55e4e22c83fe4f84cac685c81efa79ecae4a310b5946793fd85ad07c983daf78b0522b20105b88e251a85dc8a7348328f4ee44775e3e901eba5928c2e4a900c02be691f12fc17f014a3020f68370e63c242f120f822210281406693e1e897e47446785755bc4c3899b5f5220fb96a21742b45ff1c207c99369b21494b365a757307b070a11cbf3123ecb1bbb242996e907319e05e397b96caa6efbb7658ba41e4135c5f9962f7e0422be3ebe65e6d6cf69234bc15fa008f0780137fab22d3b01f08091f96e154e218c8c7c25fecf1851bcaa7a87a93572ee23fd5c07eb0bee3eb4243ec8d5d3fcfa0ac38931664682b7506be24d5f7927abb13d5220ada0198536889fa4369e97f1b60dea267dc127b17238b89b29de63cf74d19bdeab661fc9728796dd58b981f0f37a98124019be0afeea881ce2a58da5780f662531b30dd0e44035eff384e77c3c53d7204712b82224b5cd96cd69c6e05b61f8a8421f006741af436c36b573e0c32d62067db26a0edbd89616698bd4a2d7a8626f15dc670aaf110701e6f24d03d90aac01b7ee0ce42f957f7fc73b9c40d290d5dc885a1e1b911b9211398e8be81a3454f1994a26a89ea276f884bba7e8290b0bdf5ceff1eb39e70b749210340053aed762ececa2763938c8e3e1624aa79e9a388a5078631b4bf7b1d71b7ff492b03879d24f7d4efe48aced9423421656f270c5dc9b4587fce4a1197487ab5b92b7eb079cdbde043c6b60ce5c3480b4168ea0b335c2e32aebd5c4adfa95ccdb8796f854e097f0abeb4cd2a85d0be6ce5463bb14de77c2eb2d30cc17ea507d6a066e8727d2133c62a286376bbfeb5be8f6d4fe8adc44371685ebf9d843edde3cadb992ad9eae20272ec18fff90f44a602c13a64218756e0affc3ec8919d70f11b86eecadd3e481b5334de453a4ed9ba318a7df66a3366e18e16ffc6386452e0f1cfbe6f61e41b5b6423fb1cd40ae5a884dd68c2e396fc5041cc957f4827e8b796268b7c97c25f80ba7c6f8eb8906c240a52162402c6669a62f6953c77525d241e13a0cfc42e8e9107cddd492b08a452e9845a16eaaa942df3428150915e8e62a0dca2a6af6b7cb3cf2fee2a267cb831de31f1357f1ca9263a3cd0c05c87264e20f192dd59412abdff08bd5bfe8dad4ab0674a81cb631a1a202309ffcee12bd58ed3ab9c01585c3b20eb9aed7ebebae70c6326ed8eb19c1b05d48de221504784f30282bfb3a52e7d0c0ca25601abf79eabe090855f26880bc8b7f1d77c6514ac1f09ab2d29321de96c570d726f6467cde180f895ec3c2fbeae36680c66c08d053d7816d484578de03d64c22457b53b8cfbfa40fab9ad1cfd93a8343d7db99529b5cece2e0853bc7f0c20f348797e8f3bb208f2949e64bd788c9626880e8de2e21d092e906cf31e2bf756d33f27d8cbbf2a0a06916ccac5118b3cf9a15dc265f61f874637a17b3f026abb91651d02e2f74be731cc86d4d32e174bf2bbd84c31a6ae5d3f7e9a129d24422e2b61611f852a505706abe7f21893fd5bfb0c0f606260a06871796246bff54b9b1fb4bf57cfc8cd6d72ff3bf9b31471c84c1a51be4774e5c0a17911e8c35a3f4d281a061e94bb5a75df2b9e1f0f21b6bcb0b38a37a3ef32e549b74181e32230c950bb842061fcd8f6ece4b4178ff27b8b8c17da1eb987ac6c1ac84bb41afa445190652c6d8e21457b8677813399d59d40c9d5e4038edd0eb97992cfd3607ec75d1b5b2ff97ae76d93a041a598b9b42ae5e2a840a72058ab80e854af4e2ecdda6387520473db9c345ba22eaa93d33d6991ffbfc996ee939d17cde47d2d4b73b4d10ad6dc0762b0b626a8a411358f362e89a942c7a8b466cc21770b5061bcf26faa3811df30592b8194850377900d4da4dba5196c6eccab2cb091bf4551eca27df5afccb0a955b5f43ae71df731ec3b02c93ab27a000c7304cb3011bdf2db43bf375f1910d58b6c44e270423b5e480160b8301e05b28c0e2404d403636e0114aef7181ca5dbf17a0e274f34609e59fb6b023a50b969862209d4a0e0d1021305ecb60a13fbb58ce2f81306dd7ab2181409975458129d875694ae7a13c1a35495fc76647f80b310acbb78c4ede3c2812947472f011606919b6ba04dec376b3e734a07b506804377c7ea4f6120c7d851690fbd561c01ae76b8b79e1935c122910b263ec61be06c75bc2c7f611ec1508971615c22641ef0e0e3ae003ddd25a4ccfed87b82815fae19da3573c813479c6997212fe2b215be94be2921a73dec66bb97f25b92510bffa04c25a85bae883704c91cbc82ab3fccda12732d94a36b29823ca4746affa834bc7be26afc809abeb9269b5493fa9e9fd27794d1711a85adc3a93871591dac2ce4cc39a8332dab7290bd7423cbb63678dcf2dd2ecc72f243ec9489834080d2c2ee06f4ea5c20d69b9afee922fe2ef3e4c99e80fa54785d4d32990bee9051f460fe02dda20af7b70bfca7a1e3c1b5c42d2e509961a102745eacb08e8b3019e79dcc019444bd2042d4cef10f1bbc665ee2164051a4adf0d4a278b97dc50d69d387b4fe0a015a2d8d3b95492bbf54b10400af950c9cc5b7910ebaad51e09a0129f5183660db0f579242e6ab4d0e70e98d0590b427ba1969f05e949c2d28061351bf832e63c134bd2945dadf3e36823faa5f19bcce6b8ddb8af81b643b892594f0a4c35ed9b77383083ee8e06ad155ff61359a939f6dc39ad6af842b56b4304c562089a1e5f2b32d21a8a6cbe96cab661da67ce0baed4719fec895af4179814f0741b893bfdc21d275a4ed8a4d0af98d641ff746396e0d669c92fa6ec5094db8a3b10ac697fe3ab8aac1d4318cfa36a0f56e91f6de0579aee033f77e9a757d7284368ce5e8b374a08540c8bfa08d55ca6fa036d8c30ff3d6d8dda98c2b4e9742c68f1ef89c5935b0b930791aa39bc756cb2139b6114d856d9ac9cfa940abbd0abf6d959b56c169cd211c2b1cc72a89f43fb52b0e728ccb64d4b6b4f42e9d600dc0f8542ec300258f2275afd6c32860ea73f82f1d77504183906a9801372d70f56fc6700295b99a83e4cbfa524045a33896df7015237377d9748a0341e5a5faecbdd0d9f902f429913836eddcbeb276ebebbb1d2223beba63e69fe30298f387d87e1f04755200ac8cbc93529bef2bd80962a25ae865e4bafa033bf29b0924957812c228984c2738812d203f65af8ce20c281e940e9c9f0c6b99c4906ff397173ea1f815790e3a55088e78d3fd82f3f7638e30cde40384373c1e02477d9579bd6de1993560dae29e0b12e0624d3639217ed873c6926b3460688d428fad0aeb687db9fcc3b36af336f75806f920060b7c3c01ed9e76b43a67d31330f578187e684b9a7cb0773178070528f9e1be1f3c36a96f3812050cf491a1e414efda1f46dd1c4da13b7dc1614a627d27366d30dfc5e01a52f3212eb208398396a4818d774364bb814be91fd7e27f36f2ed61cbb6f81bae58dfe61a7b19a29978c79f9f1fa23c3da26a9124c81bd8a6e7ee09a5e1f4e6056c1ff6bb2a9131d0e2e5edf6034a59d4dc23beb14d673b55ce77618ad1e91b88a8ce0955291f773ee8be47fca68f44c64612a62db627296d50f74445b47222151142e0235701d166872d863298bad5d9a9bba068a030bedc470fb834cedff4dcca543f36e84515722dd1cdaec754a591e2b2ffe70c334d0c4e12e10f0fe9fbae674b9e743ed0f59d674a45b17c44de1149d4a0078062924580ef266394d70d4f5d436248bd5c5c9156342b9fdf0496988349aea451d356ecc639f8f2322aa0c354933e1aace38c4602b6419d424e27e873cd401f4d74bce890a33e6b831260c899a1be34f709f43f68d58796b80e3fc8d3970d8a29ea3d70353f550561faa2a76315adf09ee7f9414669e1ac9f87261dfdaa4b5ceaef76f9d34f9264711033aaec27ac1e5998e95ba38da9be1f83736f0b9057d0f6477ffff38ab0b9daee2b907688bf35681ab33372cd4431464f335ffd6039d1582957816b91348c0a66623b9422795d797eb7a087edce1b35e0debaa8ab2d53665c8e43880bf0fdeb1a0b38273e5bdfb6c16d52ebcf28db601d146b4bbee54857bec63d10fc2bcb486e7694eeacca8d91307cfbec3935d2d762316c5616d02c1f91553520266aa56949ce2487dd2617ac020d83e9b47f5d677cd0a455a24caaa1244126eee3d6c6ab6d94608dc5d0675658c3861348aac0f46deed4d0e19d1981ecea73f28e2854c62f5f7f5078869f3e18f7e77b2be0843935d50be495e9b5635978c77aade571ee4aac066895332300435e00e79418362cd2cb03f4164a8c1a348b80deec28c1553435e97aeea1a4cd3c0662108b32aeeec32ff109f58914e20c1b742c715e1b50b8b47aee944b64b11a691454887dd9a2316e7f7cdf38d195a2e91aaf97a46fbc29efb5dcbc63c89ffb5143ab8d4b243470a158b07850bf1084295148b422e024817830aa615c8874c208a8537a24385054725d462bfddedb83ccb227cf4b34287970257f545f3d34148e8e6c26fff538458b91ecbfd59229f178a2b395d68da5cf4a30ce4452698f0135306e7d7fcc0348ccaad10b25df686bdc8d131c46309012e115894744663756279538b17891640d460680f95cb89a5ad0434e13905bcf9da7a6fafe672301afef0c3b72d67aedb8ed8f147e68a164c60c4b65906765e564714f0b0d534ee1f1f91da6dfbe05f3109670b76be344f044cc2690898f25de1183e8340e5bd5c2a27a4b585e32b428d90a675a67cf610fe5761228b8e6c029961b36b64a840960ea1c3e9529cb1d6ade5cae23f6bbd671546d28304979c51f7aaac25528ddac359a11f8cd632758f401bfc44fcc19e76ba8832bb11ac80458cd8a6433b88821cbc80374b057dbcf4607d0072504c14434cf61de7feb2515dd597999f9270227dd9d7c9c242e9d5d8436a46d2195accd86d90c28ec236f44864c1363b734f6570ad865fd5edf34f4ffd3e6493b50b84509bff453382097ccf9ada958380befe2966463f86ce83dec5886e8fed484b62352fe2754bb457f411da78891766bcd7832f9eaeac14e4dd693b8c92b34ad0d821e81573b7bbff2205901092429cb9e2d8c841b730abe05b9d32a3f4081928fdab4395960d8a26e70b81d73030ef2a1399f708cc4663780716cc78ab8e56414b0f1139611735caaf157a9f7829f4595c4bcf35fcc61d67507d08f0aca0028e4f508b4b052737bdbf46a0f70a2d9e43d2b24b07dcc6f3052a2470da80d2c50d72204dca81f9246d4034838aeaa262608096de97dfdf00d491f0e8be274f02ca624a3fa3f5fb46af1ea3aa57e5f70ac1d478a4ab7e0f84460013ea1ba3d42517f185f1c7c854681c4218ca810ce011c30d5d205054c58812d1ac946d38671a00b3ff3ed8ad2be3f4f981f8c59712f14b8dcdef20d26d8082b7f139935e9cde131c350ef97b1f3c29f459ac456f6b543bb94b1407cb50d0ae19f0ee428f79935c73999730e15164627a23e8b7fbbc123ecc78bd505090e9a20c2f485f0cb8e074e16edebb753b9c41b74366539b9617f1a0753581eeb44402e93c5cb01ee8215da3f4eabcafc2c639ba18e55f192b29a24f8011a54716beb885ab10a79caa3bb75a690bedad7b9f832fdd5f112d579296fef347fb487e506d2d835fe05988130b3c7ab8058f735360287bee1775848e5400b473d8dee5e5e49e088065727d72673f788ad2d63905209c9c90d5d7970b96494a2733abe136454a48722ed19f392a6caefbe082c109a568ec110cf146020410e6ae3584444cb4d59754ae8b4d22d52c3bf7f2ec907dcda65e4ada081231df4562a7032f2c4d964d10b8a3287c615e89151649e08b97008e464a0867e15286277cb9492b71abf136ff0497ce8808a8c8cbf1e52f8a856dab61e56c1755937951ec7c70dea12eeb5ae848384457212c317d46c942f377f0463b30043b41f0a0f67bb12f4c0807f0c304ea2005dffad0057602fa7c633656d18bf681bda8ae2f7ae73b336c2d034719f0692398353aff7d16ca0671c61d7f5adbc448a1cca51f4de6d571c4751706094f1be1602be5664f6eaa6372071c8ccea8de6a2f06ab83c2273be27727082661878944d76228ea601c1531a01807d7c2f9298f0fa4eb8a4a2f0fa78b91ca7e0a9210dcce16249532a4630746383c072e303df59aa34a019e25af6f2dac4809a77d6f90a29ccfb9f94ca4e3d39473035e61594a49bc296d3ae5b1a804a7323a972a1552b56aa68f12684519f02be794d06c5e9849dd3f5150beac987d80d2572ba1103230c1030ce349618d8519ca772d9921d12a89f2c83103af0fc8b5d189dd90841df9c911ab72d28319cad9b544edabe35886309e107ccc09e96e3284e0c87948b598caa90b022fef9b03726c59b7f23e02bd34ebcc9a185d623f599527957a4846003dda1bbdaba360687323df9d5e9f0a10c911d45c4fb8bdf0e8557fdfb45323174f49bb33036a7046e8deb57e602cf8b890657da8ae5c1cf97c763bfcebb5e62307de5ec47f0a7c307c61702dff064907854ca69a55493da7273bb08222b17eaaee7fda7c0a18644d84505de606da2be649464765d77d111159e96a8c44d66b4d59bf162a1aaecaa8c464fea76cbb117b55a71c378cbdb38edd1e8ca58e00d3c8c97bdd8f12dbf147c13c01a4c9000e26788631d62d3b736036882f57a397a5ee2ebb0a9946b6aaaed0f56182d795941216a947afe632b3848765c00cb0cab8aa3f7797978d3bb54b088a4058bbfbb660377da40625952210c0e8083d1623402060ebdf8dc697ef93118f15190f36c911d9088a78ddb18ef7b6a353d16bfb28952f3df6a520abaf632a00a5115ac909586741495e172c1862cb9af65bd2472be1ad2c5a96093ad05be1d113c4ee6ab50e50d766d3a1021a790b9d20a1b40210d2c9875b8ba95b5b8e1ec3e2bc85d7c5e11ed456d4303b49408a6ed7d5844ddfc2185ed7bba8a265c63e47992ca6fb0e597721f44e1eecc1100b11e6f0b96ea0e4d7a8c35d79e865a32de001606555fe5c25aab513fe434779afb16190168038c20cc496e114c7987343d8adc9976bfb2e689e1e3da4af10f6b6c7f726a9b9abc9339e988169831dbdb1a52af73cf6cc7a83b2f18f6306bcafacb21fa1934c92eeb94f26e9b06b128ceee241f294056a7160f6273c071ad600cf1ad829f164590cd507011264bb0741676e4008d28fece5e0a8f59448e4b35a8b735c1ea2880333f07033d8815bf022e2285b0ca525ce3acac512b4dd1353e1cd97140886b1d48d03a6ca31c2d0b83bf98008c8ddbbd66a6bb192ec0689ed92c93b35f246f69e8e946e6af5e81ce52af6a9c2590a2790e46f6ccf38456a017aca453e93560f09b9981c2e422e2c834864f3545b026987fa5a01d729ba98fe84c0316946fcc4371653dd99f2e560ae0b4bc60162412b0bf3975987ba294b59e2877ece0b71b6c448dc2d99e1f856e1cb4b84699ec1311cea4d29a2e3824bb703480da5c08efee30408bfd6b9272481a39caed7c82402eb3988a6893a3f5f8576a84946a8e2f3600f31f7f2c9fc27aa4a70b6bba8f6609764bb2ae05e43411b34f4ae1e665084258e4c0904698c2d6b9da455f2b3a68c876c6ac722e7cfb22d658f26fe74a9b438d48f51f4529e02b8178f6457c832f4e8ecd3a7c762037552a5ee8b7fca1dee72be675431a99a289668201f6dcd4b37bbce033a3c59e5e115ca00f7702a86df9b5b27915122a7357b4a16bae0ccc855103271dc4dcce6112965d42de6ada72f51909a08351900146c317ee13b27d8bcadc42a860b1b0472ddb272afcdb71e89485044019a3ec47b3ca960463d651eac263959f01380f8f919e2437872c0759b8e5c09264e0dac8e027e662c2abf75c1b1940c21e84e87a754d703713872cf1699547109aec7dcfc3238ff05873f96c1554eaefd0bbe377a29e80de5b85d83700e540b3b9d3ce0b024e41104ba6537aa5820da19a703cdaa62056cecf1c67c309c701df078e6b31026ed56e5e75da84c77bcc89632450232d54fd155fb03b19508b05002a310906a7321517d409d21fef5df3695bbdf86bd0ea43c5562c30411d9ddb6dc52a694640a3f0a930a7a0a49baab77559830c7a7c6777777ff23dbc3af9478632d47f7ec6c867d0c2141fd7d521f305e89359e34a89f2251047586342258a1c41caa2e939821478d31ce58718253da345236ad60819af6464ec125205c6567da9a6823679ae60f3346ee1760de63188691e6d2442a1f46397f985e029991b46dc70b368d944dea038aa0a0f5b943c690109eb08365825dc7d102a232658b9cf1de8a5c2959ca28658c314a12c827121dc3c14475d62d7fb617836c624448d8633f4c4c462c462931a90452d65fdab4171489667452d77b3e856ac618e35c4f6e552aa191f387b9bdb0756d240ff5fbcee380f5e2a3e20ba5336872386b2576d1054432c618a39452f20aba075ac728a594524a19638c2d85849146d05926d823c5467bea07817888c5253e020285fd3c94f1100f4d3efab9d19e192c7105f6386b0510c208218430ce28230ce6466512ccd2a13a91214bb22c215a32549d159fb92f0956fd21843470f5603761a8773295793217c166009b4c5af4d87fb0496d9e73a7a8a87987818ea8e4ba39bc3337ea10c3a28c58ef6059e0cb5f722ea58cceeeebec316e841c9296d25f3e74a34590c51e93f882b9517e652a7882c5abbe22131cfabb7b978461779e654a39290a4b02859a1b151a827232544a29e5bb9498942e4991247f3d967a786c1913844390ec52c2b9514a29254c179bf5c984978c31c618a5941247062ed7faccd15bc818638c314a29a5143782a1b880a3ec22482388e2db8821cd1831677c4c76362f6463e3332c903354df81a33acee6f3bff9f25ff3d001eae8201e1c1d280cf62f5926dd3413a9bd1c1bd4cdac0659616b6bfa4b2468ed30b922b2ca8e48890414230a7a7102f44550955c34fc7e6805917b9c3366934d36516cdc666e34c610b988d18f986a8c928a18e3a909378521a5134fc5fffa6408598b17f8dc286b21e4594c76648c31c618a39452da3cf119a44c22e7d87d85aacb44af46e832665294bde8eeee32b6df444d34708da62db0eedb24accf199dd0969312ca871042093b1a21a53db06c73229b2fe3cbc766b7af611b0efed14b3db0c6a45319d316a94829638cac448c3e027667c87d53e3016a1c4069b7fdba1a3f2e25bfe66103d4d11f9da06c803ca00ed4d16f32c1bc984c5b47eae6954a7ac9f97af17968d55c9ad86f823a7352ba03777a073939f84a7ad13a6e6be277a4eebb40f587ebc507c2258645efe0cf0b9c4570f9a432533024647a073b14935366922435b94919a3141a236f949a4cff9e874205712224b4519b1d2fc28c9874f7f7624449ac0b82094921a1fe190fe551b0852b7f4eefedbf444a229f40a1a6a99238b842f59c2b01d86555ea0cb03451013568d30038f842264d28312c4a8ce314f772b06a7bf79f476c9acc49229988b4eccbcb71c4c663cf0676d99e4b3f622a94d6afb66e07a6e92b70bf34de90e9930336afc9d2073dd18b5adc622946295b40a564e7cd64faf73c14cac66688cfd090f7cc209baf7dc47ebd38434926ca038d5ee4a6324bffa2c52998905e5ed3344eaee2ca575a6f1ad72bcd378de39526378d83ab12b7c90702137fbec3ffe88e27d013101823f1e917bb13adf33f4a2af590118b353edd9afead293881788d2fe9de2ce504b411f85eb77e303e0ebb11f8f1bd3bfdf01adf6b746e7f7dcec738b6dca394524a19638ccd33371aa57494ff6cdfba787ea64419aa47f6cabc828357ef41e95af966d81dd5d97bd97254a7a4ffb68a55ffb83c8440df1bec4a75a70175f7652132a6fb4c4b4d2fa58deb53f6481829e388b0d715eb866c4d7f944d723dc0b9d12b252a425d5ca930702ab141d5dfcbf1cdb81f99a90c650fd8f57a977ac8ff7e6d548fc9b41923b2281bb03303180fadda3ac84af5286dc1da6ca4b4b1e12a090358e9c7d7ecb509975fb46eb78644ca7ac46e8b564bedef8c3126b8628c53ba122637794e789e6f3fa1ad9452c640e73b16b7927c79c1482e47e05b943039355226a794513a9531658c5101793029860e5ec293d2cedddd1fb58355a5f7df4e229fd88169fabf4d9decda1f720e2184117b77c5103b222cbab92f0ec9b51e3b4f2261ba74e9327d90b24a9cb3e3dc4a1fa594b2b4a132cc83d08a3d4a4391509913892e6397b14fe10546fb48caa67ccd378d944d140ff451933b0c7e8f1d9d7f2b976cc881b521e421a2d8cc629c9352938905514a8f95480aa29991668c2065267f9b1f9bf5e933444248299f638c12462965472b40992d605d8c31ff79f43f948cff6c62fcb7ae17d306a580ac173f3edc940ff67a8b2af693ba806e32b8189cc906c8a634b05e1361afb499b48e2483b4aa08114efda0814d01b15e0c5797263e0ce771585420fa8bb4cae6074eed7ad35597083930a8feb04a8e0e1a86e3686afc35000ed51f66dd733562a0fac327f273a35b946d8112030e688cfdc055a4ca773f62aaf29deb266c131554ca29698fd89d9c78ebd35d069a0d8aa46da5196440d9d94da67fcf43a16c6c823c212434434ccbca1333ec68d0abf092242d470fa594d216accf1c359e307a410e9fc2f424e39c93e161d773251e3960a2417c3860abfa0f3940395472a654ef207cc97d471cd6df1a7fe89877cba457c067009aeaa68f729bad1527439aa6df145fba52f7cd2d8618ea4765cdba1f4a23a0f0872cad7187dc7b805576356e7016e1ff91e3d7bec6183fcacb3c59857decbe24ae0435354dbf0c0c5ad008bd015dba74f1ea7567fa68638c1c638cec0426d9a3a0497fe8b0d46362f2bd63a23552168954f9f1715a8b5becbcd483df25d63986b1173b9451c739bfb93941e5c7ee9b1f8397eff0096d71288c8a1f464e760b7fc71328c40176499a9b35967c6c855d2c01d92e409274a90628857579e7d1dda33bc767c618638cf993891bb1ece1aaa8fb84a911a67e94865865e76d4d3f8ce7ad4f19042c71450a32ae1d48265a3254d9c71fa7997bae431f18507f9f506afc2fa6ca0e026d4d3ff30028723dc0fa41a0f5097da40ecf0ff461a21fccd803a13fbbbb7bc78fc31c343b0a9b7e26ff221d7c715075af82ba0fc117047a85754dca01dd57fd7888833a0542106272508fcf60ae63a5ffe8f69f09e6bf5fd5cb7fa41ae767a82428c744fb207860b158ac157d0d869bf1f2428d01a840898ba51a6718a9fe839638b934f1b7971a3fe37cc02a89c657fd7f60553ef683d6ecbd044456d921d92e95d4c5ad8932ebbe10d408975f66e75b13bf582310d57f13105d8947d4e48882d7dce28c524a29638c11670a97bbe646d751805109ab9450a894914b3da27b1258e543f9fcb2f301d6d83918fbc26646f2a098935293e91f6709972b4ae95e7d0521a270c8f88c1118b61ee61553e2476670007d0105e7c0cc10ca8b012966537a703e918f5ef56e08f67ceef28744312487d60acc103cd0c2d74a4f5d00e4386c22e4cffcfb1153f57fef09f5ee6f6f9aa691cf2528930aa69ff14c0330c2144698a65a8475cc3e3e6dd5f6f2f1513b30ac09c576ac176d24875a6f879217ee4b9ea3368e6a26129771cb039511930f8fd8d4f8b00424c6132c5430eb9622076cea129923d9a3f8c8aa7964734286bd76f7ef086f9539ce87a51f70044ba4f8630f5f3efcc861ddbe7663c713a8ffd6f8b3d423da90533d7ae7f3c86684298c30c556034e38c5ad1ddae75da2d8d08bbdf9e582cdcb00d42a197e6d3a195ec0829efa6d3e6775eaee44011e2fc30b51c0db744aa4f42be0bb13c2e36578193a253c3e679504b5f99bf72c45bdcf407b23f7a6eb3e5759157c35cdfec48212e1e324d4fdadb1053627a526d3bfe7a1b00d9680406c8bc79d84c8f0de7b9d12254bf68a26785652fe952ce11f7811b492c2bd005e86cf59cd1550f8de2f8edf6f56b73875fafdd661d5007ebf9b70eac6ef374fab08f0fbddc3291bbfdf4f5895e3f73b0aa74cbfdf3fadaaf9fd06e2548ddf6f2aac2ac0efb7154ed1f8fd0e6a958edf6f214ecdf8fdc6c22ad4afccaf017ebf8b3825e3f77b0bab0ef0fb6dd447ad42c0ef3bcb99b06ac7efbb4e02dc09ab52bfef4fdca755aadf6c67347d402406ea986e0600ddcc4c07b560b07f7a00852e48423dd0228469c70748e899010097030b88cb8145657b80edd4fde778e213f6f69fe366466362c8909941a386c9c60deebbefbaeff41cf75cf7e178fe9cbaa51edfc11e1edc76c3650ae06c38f8ea8fa1fb260cdd0bdd67dac7c191ae905ceced9f38d21047d2c2debe0d8ef4626fdfc491b8705a8bbd7d1a9cd684bdfd199cd623c36932380d88d3acb0b71fc36942eced534ecba215692a4e3b6a9afd14a76d619afd04701a51d3ecefe0342c4cb38f004e0b3a00a751619a7d03701a8ad39e30cdbe0e4ee3699afd02709a0ed3ecd7701aab69f673702423a6d92700472a6a9afd0170a42c4cb34fc391849a66dfe3485698663ff35998ee9b1fddbaefb5eef32aaaf29fb2f98c85531ff6535786bd53d6d1c035a3b2cf2e4edd1862222818d57d2ee22dac62b21169e9a98b62b1154e6d152864a9fb1cd4aa5eed6793b11f4e7d994fdddfcf7c3875823e300a36855318104685539c82ba8fb9302b9c6214d49db20f547f92a01f746547381d006e5718f7f1ab6eadba1f3920ae52f705c02951b2243be2b59272f25f82802a442b2927effc55dd88bde5a95f7624031700ee60506644bf7e99bfeac2eea34b85bdec0802b1b70fbdd89badfb31f0d00fbab69fba0058522327009ce3096d673e7ed57e1e9df992874b5402e52752e12f078027d49344f835c2a036bca5f6f3164ec9f77e6d967a402b4a38cdbac9200832cc1da5a139c51fa462a5967acc1fefce9c29d3027d1b7461a67bf6fa73b0e7ede09784c22a29f377df35274171dbbd79a1eeef600fc21d2c58425e0ef6a012edb727318944ca489dc7218128f6e092c642b4da5ee3966c53ecacb4b721087bf07db0870327f8c649e9d73829d873a9c7ecb6090a3f86236c0802b3391db0454ff5ca838f205bece860c362b9a1ab0366acf37bb6f468d85ee7b373fbb0a9a424519bdc5753e7673fb98fa6cecebe01d4993177c4a662d84f200da8185714a7b01d2cc51ffe7c2deab7afec6b08d1ec49af91b89f29ba52dbf38250448aa854f83bb08ab3879f638d2a3c41fd76d41802d51a0889c33ee3fa39853d01aad82a5330aa6c434424a808a7becdc203a7aa4c014b859f837dec00dbab70cb10e8967ef0e4fab774034fee6bc66d1529bc2a97cd39272966393e9b1a2712d8e5c70ac108203a706a76275a6588a644a938326e071e046da907a8cb8328b450616976a61a50d30ae8e755f8455ab52b081fe38a703bc0af82ae1076762842048876972e15b2480c5305160c62270a3b2b25374c3464b418982f75da155eaed546822e2082cf8af44b78044106aed5e97356383e6705c3e7acfe7356dde7ac6cd4982123062d2979f9527712927de94b9d92d2679fb37ae17356317cce8afb9c55ce6abfe376098e33695028fc18388ffb2f5ee07070a82ef4e3d7eb05d71084ad96d1d18b3d7eb1e746157b21817e04b437b0f2bb0df6463e7f16a2ca4fd8e3fe99e63ed4dc7a6ea6769f2938849c88b23daed791f6f34511f5eb27cd8a3db429ec71048a3fcf13a56391cb81e2eb753464145f928b5e6c0dbf47f7865cb61dac2b5c5b7e98f04e8b75459525ead74fbae30fa7bee8457dd5299c621d13d425aef038d9b6137792008e3f3d8e0e081c7ffa3867fc79acd4235e9103290e903838de86e823e827c6ae0738030714d61ebc7eb185838b91cbbc686f606cb57e34aefc71a855710a512ce510c491177bd35de3ab5571e85539c630047d810138e24fabbce8856e9b669be6f923117b1363b0354540559401a4e1ffbf71e3e78badeee2cfd630571b54e8e745ce434d4ae06abbcf5463cb8615f4e3d76b6f56d59449bffad5a4b2084e1d10a71702ae4ea7ee147f57a7e7f71e5a63c842e3891b628397ba5700fdd41d88e080dee06c70afa5062763050adff4847ef107a855fcc5d2f03387e1aa3c82ca1f9b88ca40ec12e257a603fa404c7810d47120f843839bc1411e2450f832fc32f8618802ece1600c0e965894870d0aabc2180eba60100f7de1e050d3f0938ce0a645e8064e7ca2f84cf9f9b9a1c42d6cd2a567e54da0f09d09744b3574750224799df0b2220bc756dc012ae271c25ed429a27eb149e579e23d3d0ed4aaf8b38329b6ecac3c0bede2a7f26b6fe4de7021d2c21e3fd1162f2aa2c21ebbab7320f6f86100837eb1058de20bbef6a62bbfd6d21b4211da424bebb057a942d4abf8d2db8be051855cd8732bb1ee1536d0c2a499e5452d9d56b39af0ce4ee52dd5f0428d3f4ba05ffca9b0f4a3eb27822abfc4ed4aeb0d08fc5ec8ced5bb6fc9ae366ea32085240cad346e57923302dfdf091d25a854e9c9520f50d7950517d47e6d0d7f3cc5893dbf38152b3f1b716a5d5c742a3f1f754f4761d5328188b9706aab58b1c3af2fbaa2d87eb814a17e3d31e9409cfa62cbc5a9af5f419cfa9c4788535ffca95438c52d22eae7565af5f32b7588fae1a89951fca92cb457e800063552910cd4048d2d4e9dd8c55666165cb17b5d81414cd08f836ef07eed4dec4e34c81a3f762cb435fc469c622c5916faf5e3d756f78a185851bf6671166e827e3cc429ef4e4060779b0d481c13715116e8a6020ae58d1c8c5346da6e24712721a49c95c69d84684a66d3f86b9fb3da2d66d98bdd89867571a1739240af4e12e0df7eeb44407afe5dc1f7d7be243c597e7c589add0f9b1a5535beaac6c7691cc66123d9c7245cb3eef4237ee7035723f2d7c5854e95aa2ab97515fd548ddb1589db55e4785055f83be39299075a16148abf8683e3005665f2d7abf3f73f9b39290d92714998a6794801dd69c2284545285e90b781df6462ef701887530b21dc66d80961af83b0d75c15d42bbf0338f590fd0b66be2144bd3237f110324326eaee76ef6e6feff676ffa1113a8311c3d6ece7d4ad5b82e1051ca71b364c3568cc9091112386c2bc94368d944d4c466f2ef5e330dd6e7709cc61662d1af42c28bfc6dceefe12bb6ef729e95e62a0eda6f87d57d5fcb0dbdd87bb8421057cd7fbb77b994de0b367edc7aa91e6947feeee1b77abdd95800855a0dfd736cd78393835e4dffe93bdc781df886fecf57774c83db3ee7cf8717a924ed215be0b216ef799e0cf55650f29cc370db71d5f76303eec9c3d538c5d0f5e8f982a7c29c828a57c9798c4a4d7d825e10adfa9e0eef0c6468feefe53da9003ab57ffe07fcc70c297330ba1186394d284ea41a1e6464d419a97c327cfdea29412c3b028636904d24b3df8796e14a3a2273e0c2207b1d6374a29a59432c618db05ebf38aefdec88f9a8a42a171dc7a4bda6c6757d9fdd6c4e84fe4dd87d8b418639c73d2dea22d6fee5bd45bd1dca84de5b701428c5146982e3c89b076be3531e70a4e93f4113e3d57e201f17be80453ba54434ef59fd8b70f5cb1d7e6d6a51fde0cfb65ce0e4957ac93bda51b62e745c02eda421e0da1e47c602863e46f1fb8eb41c687ab23fe46eeea48baca6e3958614bc84c76aa9c1897b1883c077bf23df6e4a3d893b5853a28e3fa0af659d7575a8853d8cbff30ef6d4e5658eaf14215146ba12afda769a4730b63b0873fadea16c6e5c022b928afe47bd1ded474517d8b2a3f3641950febe90822dfb4e662d5b00de36690251ab0da8f7158d5b00dfbaef2fb8a8c51e5f79133d991df58a4785265073db3a4b0523fcf1b6b71ea93d9e1d487c3d4c33a9ce256932ad949953cf5c381956ee00f6c6a7bf91ed814cccb1712c406f940ac0afe348d7cf9436a7c3c173c13a623a809aafc60104172bda85236e99d22ec658dfa75508d26823c7a0ad4217f4aee2754f9f0a755dc6a9ad27f35de53f9301bc72d2c3d05f2682c56877ce923a8e93ecfa8fe162d1f05c2d6c82aaaecda4efab1871c0631d8b0bbe6614f76cb3aecc91df65ea874d0d6cc981c82f069177bf25fba06624f9686a0f2fb49fbc497dfadeca589ca2b4c2325ed1a4ba95bf6b6eeeb2c59117bab7133b0275fcb36c8e1d0c05867f30215f49ba9f2bf47710a56f95e0e4ec927717d853d99752dc49efcd975107bf284f51556f50f8bc5626225bf8338b5a9ead3c57a5bbf1a5a6896a5d95a7db02ccdf6c04ed54bd9631c576d7138e36417f49bdf030a7d28ad5fd1ee84fdae5887694ed8c38a75dc624f7e2605fd2ab520bf0eaaf26515f49b55be7c29492cc384b633d88a9df268ad2eedbaf3273d73c23d8a5b76ca9a7f383585819808bef0c354b054c873a542d65261f6ed9287531fb37a38f5b98ff4e1d4d747d2c9d17ef2898c52e1cf1406ba822ea74eeb59b765ddc47100a74a0fd9461e65599665fd5fd72c6866d9c3ecb3eca83a15fea1428ae591b1a00e9f2fc78c8f8d3ce29e8c057970142d9bd977f771fdf88759d079380ae4e14fa08eae87ab951fcc873d1e7e88e91cc9a3c95d0f70739e5651da499ea6c93a2ddb6612f4c37c6a14f6a0ff34cd13c8c3a5581df0a14f2ab606fec7f5f327153e73e73eb16e95574ffde4d12ce2d409e661253dfc8cfbdc0763b52a16613e58cf9be6cb2dc097612c0fd904eae0c2a923188eca14b54af2b46c0279482b5007fc37519e58d4a4d2d9c9a31eb3339966117b5b785a25839a069aa8d4acfbb028f06510d67d33ebac3319f452e567cfcccc2c5bf667533b6bc9035f5a813ca411d4c163a5c2ee301ff68eb6868b34823c6418ab630b5b035f4aa30a7f4615d4ffcb58af0a3356c6246bcd17a78c38d5c3fc24b36a0f7f1e712afb197984b57290fe93473d24a195df3bcf9342f2cad6609143328b0cc2ea80cf9c1cc2d640199471415f062d2adb81611b58689a0679eb66e6c85c12f443d5c9d0e173fd6085023b254b564b20f30d7c23d710429844728c2ee690c400a94020f67aa83affb7aa16ba8999b3ebc8f5bc5a2d14b95b684b0f35d1164e9dd61b4b6751a27ead056ed0d52ad872d5102bb4b235fe730594e10b06cd49a9c9e4cd23e88732d5ee866c8d7f0bb52a87a5f1f77642757f8d3179c56f5467c2aa77412c9cda2a5e04d50f6af988a840e425561550503fc8059311eef070cabf5d9c3aed7812f5834eaa0f55c7e16f62820e6995d734fede3494aae7a2f07fa65f9b09b49dd1b64077c3381a8333f22396ce561172e2a8a8bd198891a8f061aaf93b46977ac4d0b46d7ef940302b2c6931629adbd8830e85edb319323eb26464c9c822bda67dd6efdda576271f5bfd6bd8eadd8e2ffce7e7541c7e79e75e301b0f6774321d5c1a9c263dd6652f349094d841939d1da8e0ca125cb0cdd9bd5b317607444f44396a96cb0a52b297eb78f38f886d1a473f868342e349dd897f57349e76277e58e56fede7a0a02f5d13753dd459d8831f040dae7598a69535a15b321b77f2df1a3f5691385ec8c274c594202afbe7f0bc2a8a2a77a82aa8869580f0b0002654bad30f9727e8a9fe393db43139b05eec6dd53458f267ce077892c00b2780a2490f6b45e3a1d4f8053071558e46b784c6d378cd937005b20026aedabf0026aeda1d9425343a29fd52fc736870529a8b559bdb0cecd9b007677085aaf5e00ea70afd96b469dc565802224fd082dacf251c505cb06a7748d0fdaf5b9bc5e4c072c11765cfa120027af9b0a1499090201042f86a5513f58b6a41e1179b65b0772835a1f8053db65a2d085403048240104b8b080241a01a5d340d7914424643746832b443dfd0465be58ba37ac4a953bf026a8cc161f8f810b9b6e8d76b6f4e2ff4809a2a4c85df437bc3117161556fb12a08e44d2a7426b5bfa85f85232a08b151e6ddea8ceec0f8f30e4c0627c43a974fec7cfae19bbe7e5261d7722d68276169e067f5eb2157510f6d0d7c1c9e4103fa75ab5bada2f1f0db8855d5781853bf6ef5f7cede34511b310d7c58a36b2d760c7ddd1afaba15d3aeee83810f879e40bf6e56d011a8c0840aeb0c20aac1284ee2c62eb81971a9d1680b976ef08d4b409c61bf7c4aaad635769f076af3cbd51f0cfc276cc43615a029157e4701721e226a17bfac20d42e3ea27edde48b55f1503fec9d21232afc9e25885c0bfaf5d0107c085953a0c154bbe3d7d6c077223aeb56b9024f6d22f6e07f5ce3b724015fd590a93dd4aa1a73526a32fd7b5eb76874ddea1935a05a7f01f4858f0637025441ab58a155bd76516bab8071d45b6a0c81c2d20ddc8d6d5d02d23380e82cf558538cbf476e87726009a5f6b3528fd6e1428d5c8c0a4b3ff6bfb81bf483a31ab95861e986fdd8ed7a5e7b873dd82df6206b68ab7c81a5c25ac261bf3b243570edffe1b597d4f68d39fa16fd50d1e18fde2ff8e2d409b6a08e0a9af00e4c41d8f3b335f0fbd43dc4a958e1779626f2963761157ce26a2d9cda2a5db02afc36fa9ce53a15cae8dddae1d4077f2a7c58e448ebc06e52e1cf2c40e8f0676fbabfbb1fb6063e57f8700aa79430810f59ec4116e4610ffe0b3ef48bac0a3fb25a059df4ace0c756dc8952a114ab2f36893d3398013f803e82ec8dac39a0cd5718c0a0ce0c83f6861f3ebcc2a97df804d81af87c621f9cea0adf06f8413875a3c2ff01326115f41112c2a9adc245940ab554b85c2ae48fde28f8397038f511000671ea94e2d60c15ae950ab9637803e7e0d4c9042b8ebd81b50a196d3f75dfb4022a43ab0200b323e8fcd951c685c422f990a6b0caa687c464a82ea949dd8fd4438a5217be738a531ff422b238f57193d3dcdcc888fa3997ba91c984dd476ad5a5375841492d4ef1d4ec8853cc5c482c66c9bc8cd88347ecedcbb05d3c3172ad92a0ff302441bdb731711fac375ef317cddffcab5537bf34de0de7b9ab69b8de781cb6e118688f6cd8f8ccc6bb8d8fcf47a7c7f1f088536e63834279debfc9c4dd112cd530bfbbcf6117b926f4c3a2d47dd3e9e38fbfbef9d1cff4fde7d9645bd85ba34affc37e6a76d4d5a031a3fb4c2fd37defc9e83e0f15a3cb7c62bacf86494033a0de65af0c003a14fe9715d57d2c0aa7e00d6e2b89fb3ca8eed313f7ad95e73e3efad68a0d1a6607b940f11e87e1ab55cc3c5e0c4ad02f3b621ee8a2d014bbece8e326fbabf116006e573e30c110786ab4a005364db30f03125ef72686ffe6c2f01fdd176c1efbf5d77a93813b09f1f6a80a32385a799fb3dad21d11b023051d1e2c75ffe38fb7442f728483ea26e9ee7878310fc31d51b8c2cc5354c4a9d3101d38d126caf8691f3633146193cdc6c0c23b2f226e93a90f6fcae8db05fd3628898fe5d2926a320618b36930193d749bbbbb79316e3eca6b150f41a8cfce07c6f14a060a283f377bd9cb975363f8e285080aff232a0ac2362818803ad355e66e69fc913932fb47766f006b414a2e5b08b9bb7f6fe1eededdc61d68ee1ee72faf296851281b5e158a72499886872a502f6d51108c319cc561140ac53242deeef80298232d998f6188a828089c1886cd396d5c41a8aeeca93999c79cdd3d7fd99bf3677f4fd39c1deca67ceadd67a23d9f605be4a62ab05ed32c033090753f96a6bf3faebe593706d45ffeb7434578f801b2b6ca16a6d4fe21adca59f5ac3a4ca8d72fc9f3421e2fac4a92ac853c26abee7329763fe277334da8425b06d21a5fcec7e128a1b47e356798a6df25778a0feb16e1d82113185a0f4966c57ee1ea805ca3f7472cc6f81873d862bb3bb1b918ff7cf66214babfdf8500eababa7083ba6dc951d7d545a7d22c51c618e30fa2b020fe0c630140a2928ac05cdc0750d7d58527d497baae30ac34c32e30c182164840794161042618c8034b851e72aad0b245123b34d882cb166ae081ed2183c15a931ee7cb462aedd30d81173e3a7861d1d30323aaf0000d586083214461052bf0a4000c29fead28d2c41456149e8085a585a7987eae94d27fd0050c301da7262a432915b02c91456271052be850da052ba84c951c0c5552dd2a2e29ea47a1cc00084940c2105d24618515fcacf81f85c222830758698214a0d0a0084f5c8941fd4c0c797a6044142bb4c0e4f50fc42a28383822092944a1042ef8c7f46f031858e0678b1457086309415491c50b725084235eb005125842f8008b140844c10509b478a9c0083ac8224a9421a8c064052c7801152014094e4c38a009275842093818421255a860c21646208494524a29603efe1447909ad0993e9b18429e40081a26a8e28a294498011458780a200d8b2634a1e352d4efb5d0821cb55d5a5842d69a257091832368e1043d2862d5388c9deabac2e84295755d611ccd1bf8a854b0042030907022075380d2802d88a2f841124f68190285ca228a1ca86c3982082bb610644416cf62b148f099989ffedb000a24559ad0320250115c6042164f88f84901128ae0420411522c9607fc60092ac842062e2eac7041e5a75f8427b60a472062a2488a249a5471e2e708294d3401b40510b0f4e4e04089297494782541c78a19c4ced4b680051e37f104284d749c3cf1411195d5ee20082c28a83882111257acf8b7c4a88ae5ab2b8c292ada335b80bb40a89f8c8e23258e6a503d0c1254f8cd50fd7795850549e86942ca162656fe9453eca4faa338e5bf83532fd5dfc60141f6065688048450b52be99cca51631735da38827ef4a12b0b46a834aa3f34716ab759c56f9dad12418c1bc4bf83b14e8a11f8fdb25392b392bfa520b23bed6a36cd0ef933d511e4c386203f4026426c56cb16ed6bb978a71835838d0e14ff0eeeee6462e61d6c89ddc19c3333c78da61a5136ecb54692dc45d86bced1348d0477b0581a89599cfab6cb163169e7540ff293cc9ab5e64ac6afb79261b392f15f8d19646c1a89967e3f07ccc7bc36a4fecec29d1dffbc36fd98d2cb520fda49622d7d978080a04b972e433576473ccac1ca9da53217a4f4d2750f51c372f6c6bd1669950d4cd3df3ed8b381038fc4b3714170d89afe1b56c79459263bc8ca02876a7f7f6bdf0f593e3f7b8d29cbc77ce85a9adfac5a0972562188f19a73d833a77d89db3824b08b977a68a46f9246fa56890008192f045cc950c9e84e41627c8c4e095c8940c6c7f89c553faa39c80daba37f72386c8db63725ac8b9c0d5bd36d037b1d3b0f870e6850ef7c49b8fa3369776ee0514046272546b7a52031bad3aefabbd44352c8da9ae6536cd2ae2bfdd0497774f611c48686acbdd9da5880426d1c4c38d8eb2cec7cb0c7ff896098860b34fa3bb393a47d64f833c31e435485306633750c8704da4882d6a8ebc2821335d62d4152851c3fbc02856010e5e01574296dda7b85091a407168b66da651ce14d331313486b6c9b4850d7605dcc10a0ae2d407afa87c8581f415f0676e948353ba586db8a810540254c9ec4d12f686fefef73764fc500c380489d81a7e22b008085ba43eaaddb75da01c0cda1a6ef8a7de2c5b8b534df8a196161f5566ee85bc44508761e987d7207ecac54a847f074e1580e115508769b8053b4839ae366e403f1311e80787b4186159960cfbd47cc6985583f636ad8af1a55f2bf205e6b71352408506a87088a6428f63e8da80705543fbfcdbb4fba829497ce1bef764fc6743e6bf18d58cffb25a7ab82a1a5f2a3d8d199c0c27835b4e3ee44affc221698097b8e592b07fc376137bd0bd189d088088f142c0558c183f572d444a975363e4ac62fc6c1ab601fdca8d031aa3c7c6178ed5102b7bf7ecb9e7413813c01ac3e210167b081288e8e0f13b76dddd9d65bf599665998c09676bfcb353961539e2cf03a7369e04fc246152dd1d8baec7c14cd46fdb1b2ed62bdca0faebc0a902547fcd27b0375185f21d5be35e6de480fa0f69d59c1b58ff22fb45f50dc3d4aa97edfd5d1301102faf9562d7dc02125053240075863f1b185c5591a629e2382de793beaf3375b351b798ba65757bb8aa18bf6d1f83dba5217d0c4782e14893f4cd6d5fe2e6f7c675fc2dcde79ecf73766d92b942bfc8114fd235fea08453f3b90577f885dba669f662077f484c89b4dfd83372423a65339048ef836866a872a551f9718208e941e5d78155db05178bc51ac1ba8c822a3f2acb814525f56d91f30a2a2f1121b74d235292341287636b60eb57da2fabb49fbf714a3edc39c334d98e2f28c923751e7b9c7133f3833a7eb9124e4132d2d3b9fbd8cc3aec5b7345923135daccd5fc96cd2afba1f6cb55863d4e3787c4541b07ac7a00a63a56bb33e2b4e58300f34e02dda50bf74bec1b5bb9ecdc5aa0824c38bc1c54a0eb7a15d5cff41aaadf34e1f0729c82ccdf2a84592bed69abb2e79f1a6ccdd57c12c744089bd5fcd65c69118ad691709a94713cd4f8b9bbbb8c08a85b02b253a8db4139f92b59d70a04f34190a5dc9bfffdbb20d97b17815d651d4b8e34d0b65535bad082b5da1b1ac4a11f6a6dd29a33e2b4d4cfdce9477c7eee3ed819e13f75e7fd3935a7f6e9c7e7d4e6706023fdd388bf372cf1b78c43ee02ef6abbcb3c789779975b08389f5f6bcd5586ed66dd94dcf743ed561a49c2d565d4947b330fde8575ee4299b3dba6e95d02ed82aecb8ba2fa4d2f788884306b158d78d1f28275f28f8fbde44eded1b08a5dcb8651edf9afe263bf2dd32a621f39b92dba8a0f4b3460753b1ffacbea72adb98abf252002a8db4101417c1cf6eed285b74b975594400356b1dba659f6b6b9abdc605b9bbc49595e02b72ea6c60ed4fe41a31663cf6de376353921ae7570131081f0ea2708947efb21a56efb21fb3bb650247b94fd16d59c55ce8a3d761fd43826da538ec9f6dc0e3028923daa497ad70092869cdabb8ace958020a062afc94deb6f58fda7c64969d9dddd5e7ac93a1fb8627362327af747d78eb6ad9282fd6e15e209705f2190c562b1e0d27856fd03952727c5dddd7d484b0a129b6a2449d7f95ecd59fde84702bb544e7ec631c95e0829486c6a9236407ce64a35e464dcaebc6309888c2a716858fbb18c93e20363dd3de3cbec7c607f8c1d092bda72ca35081debe07a1108efef770e562d629c0f2cb1f7d681d6bdb1c7ee8ddda8f2b1caed33f6e9c7c23af906d8a57a27a10efeb81a81ff4988c9ae86af2cf706f26824904beddaa51fdeddd6f0c76f23b1ab61ab07b1da7a80eed009ac5446d25db854f88ca4bb7479e903c3ae078c75c0eef3973fbccf5f7e977050e2f18708620948a56fa8442c98ca9a5432442410000000026315000020140a068482f1804cd223dd0714000c7eac486a4a170985610e04318a216388210400001000011019a26d003f377ab5bb613e6773c7b7ad172515035068d34b4714ff6b36f4da4ef25b18a866ebec8c5ed5ae3710351334a1fa1a35d8d8b174c1cb07a3cddcf370caa0a4f18ca71e5e99be454e27a5bbd3b4d9de8b10fe01d9231f0e709c8260969bde5826edd42652b55b6554c5c67c4d7150b093502931c43656081818b8e4e561203835855b6ba3580ab49429c045171e75af299afe39e2b17855625631fe2efcfd492ec320efbd472ac454ac0d48a413ca6d17ac683863bc003292ece4136a8965134b23c12d9811a31c2595432145f489df68ed5a99f95d0190fd1c40642dfdc45792c4d0df4a89242691056950718080448f40d6cd63c0ea76833a10ac5466b185d102a1a4e7355839cb5ebea1d23bd392a94185e4cefe1e6720f9f29400cd831ec228dea517aaa5eaa7fd2751af49dde8252993126f0f9581b70a8d136fe121d0b971d95314e17ec59010fac9bb7099e2554d4da0ea396844a78753a088b156a13c35b0eccd07f5e52c5748f32479dc65943ed57b9e024b7540fa8ab3b360f07ad38f0b4be0d40889f2839aa56db96b347e05a1a45117722763bb0b7ee74d12c4ae40f590b045b8f6bde26caaf3b7f07379cd3891ed63cd382985e53184e3302c1af07ae6302ccb3d0162060a79104d50032e374709d3b2352aa940126a124d79d880190b85fad77cbe4de686e74b00e1da5deb53274074d1fa9f4eff58fe56dfe05ed1b5a4a9dc50998fa3b8bc46dca3da9ac6d4d5e4878a5ce0b424aedccf5ed6175071495bab00615c6cdcc45b2bc936a77e46aec17f6a6741608de59c18565aaddf8f9a98592c3e6b9420226b4510ed8b4a4a44a2c55822d87c10f7293f21a2a941620984b42b51d2a423d1325f18d98a3fb7ecfd3cf49b48e4b259d678e7efbc6f2b21d87ba3151f0b7b8d3b16a8fb5bd8a3de6f575b6f462d367ddb2d0d6d04dfa37731b791b020fce10a45e8bb872140ff05f1fe61eda5fdf7a7cab18fe24cfcadb5fd4971c8d79274cd9c019e3c3c79af8af682a2ea5bc6855f9267ffff6699908005ebd5250ce40f72aa81d73cf979c417a32fa676b7e582309174706aa7ba44be174219de7c7521a5fa8e07609ddd62350b69e245fcb8f7506f9c9f803b330f2be207b12576284b970715b935c7925b216a1fc0e73f6124472a400b158805e52178a5c404a1d65c916f563415684f90bf0fa7309fe49d7c9eba8e64cb5b9784778059d16543dd218e5fd94730d675b81bfe103fef107f1bf9ae58375e39248ecf4625eca9d31ecbc31dff20b894cbdf73e49911aebcb04e34fa05dd270cf385476397d9e7c91acb81c6fc04bfac104d93f05f0f053c667b47348c0523852215fd47c6913073ddc5efb8378a65e143b861c687e438d9cccb30a89f7072af4b2aa5199301ff23dba48c45f6ba662b9a912fbd49533e14de2da404e36389f052a431bf84983ee5c586e2c73345554642e1ca39a4d0220162bd7e23a0b0e6cf0b1f051b8b9c8c9c11da9a91742d3b660994fc5a78fc09fdf2354dc9570ca1f3a798d40b861bc03d4916845d32063d460b76ec4e5674535bb53b1631522eb46873e13419d20412c24cd02ea3b0be9780bb0dd7ad4a4146a9cf9bea45012b4c3d643de2613dab88ed250903698938a8acc6c28cd685da380aef9d36c0f5a0c1815936a268d3e41957e15804be307f9ab066f5d8ef7701c57a22b946c337bfc63cabd55d7e2f1fab31951d9d8aefaa2cc918f74e3519dfba80947184987f5f22e05321df6a8ba96ba6edbaed4521888cb65a410f893c97482b2ed783d89a103583856d1e6108849072e3036ef39f6e76fe4d3a4b6111fa7badec21f45caf9efc9fb8331219df48783a862be17c2466eba2d3679f8e1fa728e84812dcdeb1c4e0d023e7f32e1f0768fbabe1fc896184363d9f314006a945ff67042a23813cc6b53ffaaafeb0f26480e5458c774b0a493fc8f8ead0774708975ca0d9a4069fb21354fc8037cb3c8849c2fa42c7157b89286b2da1f412556e66475199af4e450d6169a8cd68e07a65ffdd4c2857be10f02df592be35e5275857609e02980a7cf32b77ef9dfee5e6ebc6e5c675d3edc675d3f5e6f5e675c3fdc6cd6eb8ff19b99fbff927c4c5f109072ff7473bdd16df1df5eb8de6a5ac0df4edb08ca5579d79dda5ffe12a1d1018cf8bbe172168e0a7bbed5e2abc6d54fe26a8529266ba3c2477e67a6045d4e2ab5ef98173209562a4e71023df1a619548448218499e589ed90975f1c6d5aa394337c2e32f214e547d71aeeef764a028aae6798cce850b3f839ccee4ec37a4be16eb11e22033e67587b863675e130318f1d1602a414f824075f8357b151b85f110723038cb02bd8b462c65d0621e7993f4635267c8ebc5068d3df1cbb41e9b848967f232ed17db6dec092ff3151bc2658e3dfad7841f8a1e56c5e60c4d19dc88b4054a00ece8b87ac0793ebc1000eec281cf8b27615aa01f25e3afd0b8f7ce03c7ef8dd00898ad28e62dcdb11b408e27de71f3321341d9a8deb9f2f2db0471ca006148ec19054ee8302e35d9378e072dfcfd44e840dc61fa2550b52af66a96937c8a8cc5fe737f43c1a2f6591404c2729e645b9487e70efa7ebd05be6287de044badf7666c4ed4feb51193f42bb9613f79e293a96b204aa383eb9f941bed3347eef13eb25af4434358111b3096092ed31eeb06334504a4edf4dbe4ba59e782fc56495355beb7c5d6d9440b7a6e9489855ecce444c882fbbde221ce00c275921c6f93d8ef43ae1d47815c49201edf2aa880b29edd166c1748b11354ac7b365c6a14749454893af162fa8b78e3ab25bbca0ad69dcf3c3ab34d3a48ae6b4bf76e97a6a982c4b8449ac10c405c6cf077dd54940365253560b7ee4c4b4475403c65d28c2c759c53d7097235521fe5f5a8e9429965a43a6f548f83ca70427f05c3a35bed4bf1b4a95da7265b2513beee10942f2ca95c8daa5c073e6030fcbb60f5cff4cb003d2df06405e2d2655def0b0a1a7243423c409eeeb5d22a0f4cd2714d87459b6095b510db21feb7b7b4715c9b615d43bfa65f89bf941b27c80b1f41b48611daa2b11bda36c5bf3224ed2a4ceb1a377d3129b3af4a492815c298e734fd96cd5c056a1ccdb93527c65e4d47f11ac058d550140ca90eb39517638fddaace56822f30768faae5237e1f55c3d08f3a6321bcb90f8a599caf72c97404484e985f8f28e3c813507c10d42ba427ab83cdb76e86856260ed86b23e5a13cfe74041450f6013d516cb0aea6afa82aae6d1ecd1cfaad36d8a85acf24419c50e63da3ec8ee934cc4dd000e177a4df31d369901ab7670dfbd494b27a16dc6c8e8d77f585cfbf0c45bc9c8dc86a4584bbc24c1385289310d0e0cad3efd8a1a862d8b06074838b6a9b52dab0827a2cb60646f16cb4323da13615342c9cbfc866646e513f53a5b4101d92eb63cc811e198a2b76b99d21454e32f02d8a06c56446e4f90783f0d72ad3ca1f7eeb8e6ccfc8361495f79a53e1077d316e7dd8758c5d582199002e666a8a5e5c64aec2e37384615abe9c52a8eb4e915455144c7949fa9b7a7e69d81b275aef28d32a69e4cd4bc11e196cbeec649eb0838cad87536708627419d5799538c0924276af4e10eb867dd6448fcece16ec464d78856b2b40a8b2cb5745685d2544bad13666b4230d19cb5ab9ce9bfabd2a3e7f6df82b02e744bd312434e1c26c68a79f5a8d9c56eeac28360985291f9b020d4a4f30fe1c1da0668eee333f91d4208996271b57e39e7ac239b24d92f61561ee335007e08b3ffb5be396983ea0ed3dfc4f24cf8d3cf8a8f4a662870e057ce0924d031c1ba98bdbbca5dbdb0478352e6478089d96adfb243cd5adb2af412ffa8e85a7cc60d3bf0ed0fed6ebb638efa405bb183551b35f27da1abf6d5864845270eb8c284e1510f8cd8a8212aa13780eca6db6a02a406ccb9c8b7322c2779828efa72238792930b88594e3f7b14bde0bb007708869dc115327065423b7671e35380a8476a70b0c4ac28dc9ae62469a98a29aa88658c1f1fb472ea88de83eee85c72b295165d8922a560e249541274f441cea02cb6b885664052e1022fe209759114609260e06bbe326c2e73e725dc281136b5cf0417abfb3451ae9d83dd52657041ad6e7f70efc4b97ca602623581181f991d06e3e3fa25803a78d12acef6caaf1607127900b7225dc81e81cbf566ab1d005735278e026e041f3d10613981aef008fc75bc277bf243cb94f7af030530431d817a0bf7132e252fb3b6c64c6b5ad53b29290a38096823f22a23961fa0289add9851277f335edb08e90ce950575c2178dff053d927456ddb8c2ef58e68148685b7c4a07a1e429f28a71df96ab8b68d294411dd33ff1137600ab2399b1a2b9a9901fbccaa97fe886263dd8b4ddc7115220416d52dae0c3c04f9388ecca5e76ad5c84d09f60cade4ef45443733f0bcc55e1cf9609b4ac71636e7afcd59e03c36a9e2fe72e2de3108d2f1b75e8556ccf2218a9739721968add49eade57e3ebc15328cd1332c0f0c0e3de997b853c3a6b134da6865fdc8867a7186017dd812a1cb9026f321e49c27f409b26906afb980c5d95ad2042394bb1db3a7a094b4ff2eab417998f6eb7ebbe7bae9369b7521b6c87cd9a666c302ba0e4deea8a6904a0fb8a9b8f920420871230a3a4eb5e4a9282855b3b15f7543117832439fc1e7aaa3166c2bc45db3877a3b80569c606268bf6327093146a0e035134298f03c8edd736412c2ddfea52cb484618163e0b47848662586d1f4e19a6d17da0a561a68af1cf04c62c8760cce06f41f09ea0496fc186c4512cb54d265344864f81c47d58c043438485835d31b1526da80b46a3bda075df8616580db1c5eb11d701de4f37e86a8f11eb472ce4ccedb8884f038e617ccc486b6b4b34d7f39670a0ec2a013ec0b99aee1c2d473e2b1922d5b8deeb2cb9b359ab4ffd1293e64702c53a927288d6ccf579387a48622df94ad0e4540b3c0a4b5007de1ddb3d64caa4bc2bd52c75c9f901a973a0a41850961e52616f6aa27e4cf08c205b20704fa84588c891be84226479e1ac6411715d6dac3c00855e37e8633963f0fc291608a95132c856caa8b9b5a6ec7d62a15ac6fb4fea54299475597523ae48917c093ca6ed24d70138c4e89a67e8df9bcc7b7998fcf8f6c32a4f1d5baeeb2ac984c382b70d3d1c0a154c5dc28d60c2adbc70a01881e7d67c980f2e336c783399058070b2209bd4afd09e929226780fd5baa2ef7ff464031b05824a8ac42e889e85d9e6212732f4c3f30d3d8701ab37ad231a655a1ae023728a303557d5e6e98b68bd7da95b7b15e9ffb6b4de2daade39c9abcbc619885ece1414cb595c3bb9132b41e142c87403adfa706f0daef98af834507c9c0628962ab657a01d6e07e5aa1365d2e248eb7cf47b0a5cb42cc2b3c32f91000102ed721b51bf1602e7cd3d5a4f6606c96b6f3aa1745aa0b1a8ec0285e46f0a01d91c846d82b83100475fa9ed12250e13641b51128e5a69e7e123fea07aeeadb0d1627483797071053b81628c8bb42d0f5bc20cba0c0df9e844854704a116c3714381c7478f64e1daf2838d8fe7fcbb629cbeb2c21c3e060d1d39baf60068327c9284575ec96a8401c4791cc48ca3df2c1a1b421645ace5c1f66139222dce0adad47cea0174ecc3a374aa3d1f2b5e3e8b48748d85e3a940d7352a805bd7c9591e549b6a6330f31d851531a3f2780ea1729b0bb145e920610369e00446da2a428912e1b8509118fb39029bde68cf02093b047533bdf8d114c2ccb956ea7a1b90b6d63684be84d37273b9f06e65553e8ef6db3d2bcdb4e2bfc126edbb54aba3015dbc3e4227b96648af98671ed6d286f375d6dce40cccd60d6b2c34f910ba84dd22aae682a23a4676b7e34f3f9e0f347301ff35be4b1808765246aee8d0193030570510c2d16471e8620985b52f82282c0422a2d603a3d387599e1c247324cd74b6ddc7ca1b1ecb890a1c857454728a2b0474d72a7bb5163fa5bce701076dda943d32e8bea413af0e13253de6aa3fe9ec13016f30b828bf3be7fbcffdf3b36ef11b2a2bf4c8f95fa36aec40f96d5ee2085578b8008530dc2dfe6fa573f21702dcb2686a64fef40160e8738c1810b2ad7c298d37eb0a3953985f0af10e08d9ae67041d50d800c38028a0e38c7b9aad57b24752a67db9f771b5a959570e2efc39c8f900a6290d66f26cab4d3bb540d069ddb31bbb7e96d10cadf7dfd9337b95f65e006f0dbc8f732293c510cb8530fcd93e15e81564ea390a80ac2876b75f24e3ffbc217dd7d05d35bdaa11bc619e7734082034c7c485d2d4041b9610eb221aed05182242cde059461c3c0b818d4a0c03c83bbf864ddfd745f9a937ed2936394287350b4ccac57c6601b65ecfdf0a81c70e6e285dbfa38b2c47654621f002f12c1b33a5d4e23b45da467eeb6578f86f6840cda781b221c3f18b97ee9a2dcfef2a9c7fe16ede06004d067436990090c2585ececc6ee86964e02dec5de68eb3c64cbd016e25746bc18c491188c1d2c7fa4115bb05d1c8285ca51bf7090fe68ac50090f3a140ae70d88afd2d085b8649d146923f1facaa537badbed807b80d662ba08b0b728dd9f2e1193419b1a45bc6bcbd2418c07ae1b037c0b225487c7db855d19d05c4dcbd3537765cba5410df7b2fd08e030a4ac17b207bbd4cb9dfd6baf0e3d31db8918784055bbc3bf077316ea1dbabf74c831e5f7518556550d3e372ac08b28d3082ac26f5b145face5a8253143239e8c214cee939005d1eaf77063aa72b7e1bb6f656eefa5ab54d451f953ed61f788461d8cd50279074d341d1691668feb7ca4858e9d6c907e4e2401c4dc29077416014ac9f1345935b8b59beea17ea7d924471b9efd8c03971ae0d9bd40c663029954e9068f3974208b688caac6b1e90db97312e01d8d8cb97073cce05fcf85ac5fcbe831613a58299f07d9869d42bb3c84f0f448a1d9ea9850a457d590353d8244d423ea95e07fb494530d5ffd538fa03b85484d939dc0d59238cbc4726f7139d3ab699bd6a0aa99ba728aa1226a4235e6c09f038e7d3d3d28ca16ce021a2fbfd85c90e66281bcd2124808e92d5f1f9d46baa3577d93e58ebda38671baa9a212651f8bfc72b61bfc85b80da9f4d6aed850fbe6512c3b1740236bac56463a497df357cace294ae31493ccf5915e9d6313048da035c809e8285a23b711052196a82eca830585de3fc564e83cc0a965dc1b25cc0432e1db47f6d89c0969505151d5bfdfaf4cf02382dec9ea91e409b6411a26b5940a1bafc3da0c14b974a5ae1ba534a5afd108e6341f8f4f86bbabd07300007223fefeef8543fbc207342018e957b88802d6ea17b398ac4cb5a05133f6eab839537f6b0c89133f3a114aecab88bb776e409612419f09dea656c16b5f4125a3cca32a2c0938707e3663d6b8b2c0a982598d9b4c8b30ac2fcf5a71f858c0f121e871a09f8b2b259ddb6219cee464432e93b2143d405bbb5f30dabfb20260b2bad0be4cd45edd8979dc1905b57f50652ccb16ebf50ce68ccacd66f35816138e06406d5a45cfd67d1ff2251c29fb378f11410dcfa5d39886f3d6d2e13838bbbec5936ad912c562945812d4a02926e50fe89ccc29001572fdd5a0bc87c1213e829ac54a8bd5e39294e71e696941c1678698f5c9eb4bbd0c5b3dd834b54bd629eba7d45808c983b1f6556570f3d2ddde0860306105f3ef18b52632fce3f7d8511cd4d129180758890113d29c1f46e3910a1b7fffc8478a7e15a0c8a86510861614af5a86c66240533f6e2f5e79a997bbc05bb70fe5c69bc5c0dbb1242b2018f684a596e6928496b605db8962f91ad2748132247db5855f27989e869b4781c37df347cef335cd61ce99393e9c78dbde19e55099cd48251574931e615d6af68fb1830e742b6141c7347d0fe89f03866d4665cec8e188333df6a8168510f52a929de4180b4dbe97d2302d4dc733d3d057a0d44200eaa8562a464d429005cb804e00d4154df4a7e7572cd8c56c6f35b860416d80f4b164945f3551ee171b0e922ee3dd3746e77432c27457e49c9baf2c463c4eaa5fc1b2e55e84142773acf6cceb70becd25377050d1901fe5dc4f82777651ca2671a0994457372a88617f47e896365fb7d0d2630ef70d250fd8ad269a1d1b8d615d45b0e7947953867fbb8f82093ecc07501ae06f0699fd383e57d23427fda748868d46831683a375a0f2d522b6bb988dd8e5693d693882cad11b7fe74397496c79b7cfacce01232020fa2b13ff0b4017aebb24b37d2cae2ba2c8680ad70684ccc01923369eb6c08b2ccf3050a85baee3b5c7657c13bcbe4df0720766037f093ea6f3a745f7031b3367d24ac6f694e34c533c47838623335f49ad5a5f7b85e1980283841adb9be0a4b930354214391e796c051b3523d11987dbf4ddcc3aab83bc818191c76278c5e9468d01a3e9c3e3d08526d9c53b39e550b80abe04bc2193989f124ca73b3e4d373c7672e2df8d45a78c85608d61c02f81bfde5afab9fb845ddfb173d0e7c7719f65b89e3864524ed14e54887da35e192aa967a49e8712947449ccd465497a1e3f8e5aa4a56122385703260e781dc0e123be0688fcd2b4f655523941ab242aad40c461dc386c160a8ccf39ecc017c52d19ed38d1772b5c70d74e2a53232b020d75c6a0bdcec0d2a7e97114ff66f49aa358b8ab63a4eb451d5230351e20ebcfe4c6470b9825caff1e82b2d7fed3771902c1fbeb6dc2840f31e93b7bb44c18ad3244d152521210510b6e3d507eabfcc8f1169b1c503631c8d29d95fcff95221dc492a06a5d8f55decefef653e219e8d2d9c655507fe0de978befb3b694ecd660db1927c5460fcfea93eab27cbcbee0521ccf339dacac74f9323b149e9e50eba2bbd4e6d6f21c54e2fb489236e3266a0b0db1f27171b70148cf8404324384b17013f43c45f32690e92d3f36d24a32aadf180d936ce5e22a2f52ee46923b44be6ef6fa2e25bc257dc63d0b5ea5d6b7f54ca1e233f12d5a6c3dfac15e865f0aaa33e5d4b3cd44b62b3621c592e312da4c3884468c861b7e9ef5cf32d613a888320b8d506ebd336f404b7532da2bf93ecef13402278d1ab0c3cc38e2faf85a00508c675fc1dda1d407af9c9c9f0cbd45db155167fddc2a4fc702f7dc45e1205759e50691d2bb31c9c6ee900b63ae15f43c32c99c3d7843606f724374933b22405aa81700fabec8d034a6453f305f68eecb3883a579d90febc625194b9a84034fb72a95386aaa662e6b2b1e6353d5e3416ce3ca67e7463845179c43f633199ac4404ccef2ad050cfc2b1c575b368e14d928a0759f34664f3d078e56b17a027f3a62e19cfca5bdc81e5eb0cd7f73aca6a40adc8c45fd6d3ccbdf78362ca2f9e8e2f07e39b571dadfe9b08a959def576d7d7036b8421d45ddf888e6a0cc384bc57126488d1ec6779d9469f4494e60d4467c2e12223a7108ec564e2925b9e8f5c91119c4715a42035b4291474eed855cb294d69f232029db6b03b1a1751d34b038dbf934eb81d46c078fcb474516e9e04e72c4979478a2fb8697715fb18114e0e0320c3bc5e79835ebee5fb3468706b1d93d96fa2a3373ac7e5e28182740483bf5918405222e13641475310e63ac60295206a11fa141d1014101a4fbd0565e8845760fe424294b458a66670dc144aceae853a3009b12770926346606fa01cfd1422cd536bd7a34849d6d331d7370dd0adc365ad720063013bbf393dbc3abab4986280821944fd81837a65850e83eeae9c9e52c5fe403eafebc83775203a14a3d0d351cd0f0b40f6a9bc8340168dec8e6aa8b588885f687a1758a2a894ee7f7e5125d522cbb5f0389764815f3da7467e0e88f3c03ec8d2e15bb01ff53e5fbc22fb4211fc0dbc0472aaa8cee97bafc190b33b3cd1ed1bb281cf6c19c94617c5f496752448656e1abf3e37c3946a25845c2efdc8efe6df563c24334103132586c1aa7627fd95707308f33a693e7849698804bc99b6b0874b5e8ef94414c3320406021455faed68f05376b6290dd288fd50227966070afad681cfbe241ac50155ba00279adfe2a6d842f14c6fe54115efdcd503a264cccfc7dc9095ae909fdbbff6bfb881679b9e3080c4aecffbfcc043d7c2d731a652f60737a209361500c02e0099f2e9befd39d5eabba98626baa854beca1d51cdde819368b67195d12a0c3e7f0bb7df218d6ec85ef0757e764b87d00674148dda870d6e5cbc4d1476b30890f74687b7f64378da481c37183347c4143b0daa1aa4c6cbe35a98d9d61175204c73603e6814dc6cd00953b0f10ce6a5b3cbbba2e703c9fa0879297458793d95ca1575e03ff265f9a9b569383dc5e94df14ba7204f34aa86e51c00df341bc3a8eb57df6b135f16b01bac7da6ca265af0e8ef8e53d2f69dd9cc1b84d0a1337a8cf0901768be4d5a23a82deff1a7f68866d9280d7df16417bfca2f30ce5b117c81c7a2b2cf789ef2372465e31a9524fa965c0b0a2da0c325d0f69720d25bd49038ab1cee418a6e2d4b8a129f9dae8d07e64adaf9cea2485f477f03d72609bb99b0ec600af2a1e0a11946d18910f495872d1fbe0e3090271c03a9e74095da90234ba249616044c3d1038eaa3183a8aa9a8c84d3b673c7d840476830e244d1b19e6fdbd6c05bcf336eafa2128072b3d97dd345061b144c4bbcdafb0b16db59a2bfab1b847ea40d183c1bd7730787bc1f91db15e7b758a966992baa6837608eed4519ba45a1b611564788fce29e0f88d5c11a26746c6ee0a3e3327efd8a31774adafed080d4a49f3b0164903009f97ab9e532770ad0cef7beffcb607216eea8026fb497d6a48e4c0d8706282abeacd1a58bd876d39e5ad8b54e78a5f28881af27653c3539fd06f6d0d66463bd557441440469332b0272793e782eff237c73575fab3a030bfa284526d95d89c1b9c041ff0b68113ba713e191e2a40aaed97bfe44420a1b0954480d8fd5db81aa31e003afc0c292984250ed599b2df105124eb7afef43045f617c544424b07f241d151509992b6f19c09479a5c92185165bc595bc5a2e02b72bdec2eaa386667911b5a54d2c1f9e75886ecda5cc1a5af1ff3203c863f98a20f342da55da62b01ebdc48c93d3cc5b72171df8fcb62b4bcdd533d90d493b07ad2428261984a075387f702adea3ff1446183ca1bd706d870f82d6fdb22c8ef905a7cf0d34ff57570eb262cfa2e6255c331b4028c215f1eef3de545e069eca52d5a3725b57091296aae4b1ffc87987b28b2e591d4717015e6319c4182193e4269ec515993a83aba7c21b935190e56dcbe33aec6d6b501384c590fd7524464c370043c2becd636f574dc18d26ae1c27909b428be71190859d94ba77d6d64151825280178286b0fefe7f6a5cd8af505d0ba29c05bea2556acb0fde62878136fbd99d26e290816ca8afa03477d6be4b0eb4112c5bb7dfdcf962828bee15ebce9ad9bd001771241604289db16074947eaa6201a308eeacb2bbb75360e4ce80c32a2d0de4028c00d3a9ac8af175a42bf564b87579c1cb37f065751b9e53e067a70683c34e02bb34b95736acf6b31605654b86810ee64512a751d395159f52bf1905d156b3ab709f68b94b976cdc737eb6d96d47b816e91230cc51ac78f7de223c70364cc2214a043d4fb9349d26e94309540078b1f1472bbae0e84893f523c31440cda29c352a067983868b1cc4935c0981a7674a89c48fd3daf4524b300b9956e54e9359ca7016a9f6c29b1fedbc99ede995b41617240a0c9ab53a72b7996533f3584d3e2c6a0011346173ec65ec01b23578c0c358c0fc7af9173b081689c5930ee4b510967c602eaa2fbc28f56e66a41854363cad7b2ae0984cfec4fbeb4e96e5d559956ffa7fb02cc8991dc870b08bb8606ad9455950e9406c6b592f9d210950fe58fdb8ac101cff9f60f0b60fdcdebbb473122ef8730552e1479f462dad68a993a7dd1981b21634bbcbe9294d41493c87ffe26c1344572f38ff84900666250402bbe0fc1e86ef30d48521463e973a42085da45dd18ed0c3d59a56446cfe06fb8d63941d79a62f20715800baacf3fb40c769d0a7f0c290dff1764538a7e37f65a996939fba1d841ba9b90abfcc65e757b9488d38f884421da665881021f1c4365f1291e56ef5ec76eeab0d204c54835f82642a13fde36fbb80ebecfe4c8eebb56b13906ed4dd22829b48a0f530b6824a262be77b9171bd08d8c7154f5c0e90fa4691d8fa696a7835020c1841c5d549679d3473b4f07d3774390e8fca31f8c8f30c524a5eff708ec4e0f53b3ac9da378119046f14693918ff3499cbea0e0ffa0d6dcc21857c905c558d5039e1d0505fc174d2faeed90a3d1a24a80c6b50919e7f5af72841c03bd895ea3ec4c84fe85075c307e239f915c38262b98d49612ac3aa4ed0f464480ad3789251b2131012e1bea8efce99b60d8bae984ecd3f6696a61a0541d275d643390998aca62a9789c04de27e5644fe52182ca337614e3961df5ede92c65cbf8a5c6c0cf4045c229310dbfe9ef8a3a42fa34abc7a606e7e69466f8486615ef139d4e257caf13eaf634f6188bd04c037736ea6a7bf783463a23f40802f43bde08c80528aa6422f4b869541100a3ad677c41d28185c86cc4c3b509dc01dd1581a1f09635c547ff7b3bf792cefe3d3104040fea7302438492345dde3ec9cb916a01891323a9c34f5b38ceabe47c1919752dc444711de5670f702142570227e161541c4d1a900e32fc6b09b4e1cf4082e676647ecf0404c70c575bb90384078b340a4f4ae76c5c1ba1088bd518c4fc14d8c32e0cbc65c0a2cee3fc6edd5ccf2228f93a93cd622082c2cd4ee614776d45c67021e28ee6ec77e8c437f85d923ec6375a8d3d1500eaa5d465d08b9eee0ce59b9191dee77e77c37695a57a546d13b9ccf42bc8fc5bbcd2f70952921c20694411858e0225ea94d7d86d48e046833cd401b72ce94a4415233dba5b983e06a662b69f21624abc613d80398ac2177667f56489b48fb45e93c95636dc8c465aab680f040ab0c773e10e05cb129703c1000b5fc0dfc4f32ba4be3d9c738a9d6a4086c0706ffc4d1ec08bb5f9fa7df24a84a3924857410f2cd3e9186b42a0010fc0545b644de56e9ba2f209d9b6f95b8eacddebc8e2dafc10acec466e455d186e27443134b6e27f591f096de8bf365756a7eb12743c33ef03531a8e950b450dbd170524385d6d2ac9469357be0fce6a3401f647c3dbe8e8343f13000f3b624ed16f704855cf53804dc2af0fe7210abd5319f1f6558d5ff40a4323601c95ad2661046d2ec327f660e6b69aedff825b90b6ab01f5354e03d653ebea6270688e20095c6492fb5ebb6268851e95f27e167b77b19797ddaca6518d7283ad3e5eaab8ca880cedc37f667688085d4a29c1d791e002d983b3c31a87ef5229d3083ded95ead402b78f716989e315619b641f11203eb49b1a451b00701383e382e080c84d2c675be7eaf48452879f88d7516ca04baf1d5fa54d610f9798cc7928de56bfaf705389d6ce4438a16b7848ebb9f6ab418369c51f72f5bc16e926628666dc63148df66686deaa9d45aa2f36e54f14538ce105ab35ac04c44567be15387643ff0fdb6cae0ce9c3a85ec15cbe485e0b4e96cb12de946be7319c3527b8cecc58fc1a92e687ca66005e87e91fa5622e978abf8f508316a6ca220445901048167d8e7bedf98347600101d1c120506002028eb1750ab4c2be3473d6e4d0aae7c2cef6f8577a200bb1e6554b26de6e965c2594d76ed3167b341c0c49b48946902a4d808b82e1a36af0594909891cec57a4486581e37c04c89daa2181de7104f1c8308604ddd1e029b747f9b7af0f228b8690cfc0c9b68c5a34fa7c4d078dd5577bdd7bf443d9cca7823fc1635b5c0fae65b621276768c030c35d9d073613591d5a7916ecf5af7cdc0897fb68432d9e93f25ed5318b86a6a0da8e4126a42a011be885f0bf5df2071412bfecef2b8cbdfa90bb7e2ae8702e85bfff1e732bf541dd2cde0f5e39f498b65be3b83933cd624465b722a4e52e3038d4efe310be15d4735ed0570be421de546880fff9d502ea49ddb98dec4eafee9c93fb1bfc77461fdc35fb034092401cf74a125015b6f09e52eed0138c4ecd49ee64380515da49957512dad8ee044eef060b7b1debc48358e596e49f3f82fb38179e4d3fb25cd99af884caab2f6764613ef18030df31784ceab1bb40e9382f4aa696f334f908a370ddc14b70d316e9ae93f82b81b2e66a5742bca027acc94c7f1290aaea9130b9ee841123dcfcf6abbe94fc70621c8af7e09ad8b3cd3258f3621e1622fbd99c661a8431754dd49f7dd1bcc8a40c81628f2c0df6e23fb897841dbc7b82c2ab877739ad4e43f7466a987c20c4a4bf0e286fd1a34c02194c46280ef30eace9cbc62dbb1c21be78599d20979a5d8a4ecb31b5e8125031da50d8b3e645fa062639bd1ba340b2e22fcf06ba4bb2c58424ded7fd7c35068966bc859fe48fbf1c2e770cb89de049fc393e913a487a0c228c6c66f564f60d4c248247a51912a1b023ee9e92d43b3900ace1e1ae30201bdc4f59a8bbe512220a65cab16b6e952e0f98c7750bec33a11b96bb3eab5b03b4e03f338748eb3482e665a6648a6349291d068c522be61da3689a75749551c5c9e82aca10e62b8f05bc3e2882d4a30edb55d8f1b3ffa6f2d10d26f52b9a38e590aaa0115e0992e3406e09270f03a3093b26d5a9feada1e7aabeeccf8fb128be603fd7313c5e9754fd074a6e533d6033b62625ab2cbe7f47642cc719654b3b96f7aef73402b1241399e6f87b63dd6fdad57aa28caa1fc35dc11d0f6abf552a2a6a12b9739d226eb8029cf4a6b57114104a492ad170fa75e807f24c175ecd20a31a3205e51248fbbf7907e1887f013634fc21fb051d6036cf8f6dc220ed39e8d3056beed5f593fa00357b9c17327d14c480683390b57888e0aef319fa56805642d9c58965676340629f1729becedb473059650264b1bf2d6e595e7eda059f595a7edef8792c9e5210ab5322f509ecc5037e759e8242496f119a56d6d7a6b28985d7c10e23dbbbf127227460fc439cd8e9c30874c80c2a1951c1a15259f12644173088300c6b80d8b840cf6bee1f2e0f98414674ee7f323538b29a5f10736aa39743978479579f40c5ef5832fa211e315415578162ec1cfcfc0ae524fbe754e3c15c56adcd7e1d1dcd0cef8b9b7f1278f56762068242138372c5edd1f883f9ec903a12333966a5c71f6293623f7a63648e5e3d7924569765104b58374ad2c2654158b1e94c3ee075fe40b20c52c3da7450fa7a3bbd2830652121f56299af10a5739b87328886e26d810334f30481695bdfdd04650eb668628b8a487a6f045d423a90ad6fbd112059bc812c9791f9c4cdc9d68cbb791b19af03cdb7756b30e9a0d7041b58e091507df2eb039052d947011eab0a72046e9c55bc1a45f708633ce5b5cac508e2018c9a512fd48891f21888094e6ad3ab2bc8cb4ae8c804e0ce9ffcd5004872d3045cce3680e2f676912562a57f6260778ff8100ed544454f6b672e27f5aa0505ba5a648c61c13eb16579c76fa986fd82e6cd63cdfa1606b17d2004f643ae1b0fe0b13f3eac65dfe906376bb02b7e11c17438ca458b01733af6915ee5b8690fcaff7c0af759dd167b599dfc6cf9aabbca6cdcace2a94deebbdfca5c11e917e64cf961cc8c29168c410eca9f3f24fe23cacf51cf6c8317f69c2601b90ca761b92f3e2c063f5df41f9390af587acb014f8a19714c8de40dc0b234c71b2c5a5b8382c0cd9cdd1fc6e1690d48cfbbd17d60e0f325ae3feab4f9b7ac016bad58e96687a308263be84c924c03d663617ef8b2f88ce62381935dbf9a5b275a3ccebc298080083cff471d819e23713fe105c30c203e9ff99ae052fdac47aa6ec924e5a53831a5fdce3251ee85824284e0b1f45676e5cca603a45405eb98fc64f4bf8003d736e869ccd99c66fb4f4b4ef1387e0a145d81eeb6acd91d7ef274b60470a04a32d43fe53f98c2475149ebb0a425a3e87d8a16d664e5073abd6ba43d7748f54757d592b8c4f857b51f9d692a5a1b4620da0d95a48ee1b2626b75cacdb17a34264f91aecdaf6ea5e1a2a381a92af3546c204fac86a40a2f01f606264f4067a902c4261e1af98007c2c46e3148784b0bcd7ec6176197d64b76e104d7236eb577cb88ff4a3f6530b4bd8583a5d100cd02db88c64b6f5a2a456284cd022cfcd2981e8c889eb54464ef1650c1b0ea803974e05d727bc01723ec65d5dbd2c64195bc2f02acfb62165ef97ebcca9295ff6a31bfb96ed8b9c43e70b0e29d3925d43d6d07c1d058398c570da909dd23be25bb2c02c1b9a7f1885a5d0f7bb13317c76a772e698369948411a38a4a8161d0dd8be8eefdb6314702ff4ca8ef02da3500cf1b399dd291d086f008708614a1a5dde41ed364206e13f15fb00e54e5e4fdd7580e5bb09b507c542b09e2f46a82d558e6c640df3164e51d9aac1864cc9b982d6c8057ae2d6fcc31ff22533ccbb95a2df33566e071a306158dc01efd77ca1ff1a7b661af5d15330f2ed55efb73d8008efe6dbea3c03743cf21e8f5a6b0828900370badcd8df6e51610c725378646c5fc300e886b22104343ea1de191b41a05796c850e3b59c32983dd6feabbff874253292c6e464e00442ee1586b0b9452002650b7e147c55ea8aa6ca6129ef227f7b6d7c13442e7b01f48d98c47870328d9f961d9bf49911861d935cb18ce5246b04e0f3058d33e46a9f28d6e156dd62b5c633440c8221d71a5c12bf5b6104acea94e69955e2119ddf65b9fc2ad3d5a0524ec4fd765ec97cb9003135ce31d674d239b0a16a59b8021dd91aa215589618ed0b2e3fe62c57f42d1ed600707b5b764abf009daf8ed9d54d458a4b7d91f51a8961229a4ac01d6cecc9d9c1e0125eec0f2ccd9bc400e3a6640a1683e8596760ae73bcd9469bcef912c2109f0675eca2438a8313e7d4c06e087d1f8a07d8f50fdb963142c75e43d59801921701004f08b3ebee574a90c92066232a037b9fdd097e325f300b6f1d6793961180ca73dc58d9d5654cee84d62027f215736c2462d8e8694ac8039633419c563e7e0eddff8c591c5bec7f5e34d809d010301a55c65272a1d50418c7ed0edd1886e49b62e8e0363bbc8fecbc987fd5bbe31d1805251d88514cdfbf7d1a113504bf64133bbd776d5af1fc3e7785ba58d4334fa0033e20b4ac56974ea8b35bb11b8de12a3f2af067742f0774b2cc99645e6e3ff048887514dae88af3aac78f2257a5c627134c40a14aa10f42c8183d01075a6e60ab94012e58a7164ef0d714ad96b27d0395a7d9df22af6c02461e475fb1c03aca0e515831ce2164b70877ea4f359036289e1c257963aa827eeafd8f1a184f3dbec109f7728a9f03fba01846a9d7121c5bf6957a00a3c95e2e3effc5cc96c214450a383cc00eebde608a37f6e52c53802b6820b1208622bb870204332df8cb425c0230bd3faa6792f514462c0554c96b39301f7bc884c07d0b2b0ded407a6dc6829202e89904385e4a6c2d0bf3550ddf5007e5d4a18311882362ac5792cbf12b0ebc6aa7a358f5b18a72cf9821d7f804ca206bc804a0ae734bc86573c67e1df8b8e5f119274766ce6e6ef295af6706876065bf6b7535256444c58445f70e80901587d9b333a6f9dbf1440173af9e1632565ad9bea741eff3896e64f17d73427b24bcdecc50b80fe31ba345c84fbc7b3d82722a46070faec51879c1e5fd0b854eea3e09e2c0bdb009a06b7d5188c9aa1f904185bb3bf1fe192b7eef5ef7791c7c081d986b0304e3f9d3fd173af2d3bc06736aa03f50ba787f0d497509a0cd7a16629853dc84a8c852cb0c9b1cd72112120e5ac57f339af7448fdfd003dd04ecbefb19fddf55778b869d191581182c84da051f55169196193cd91a6dfa028b2e6411c7309141222c2d61947e5c5230cd69df1391f3312bac67045c1adfa0caa9022f5cab051d5302e36541083110d2abd78e7e1abb6222e1d488dd89a20e75a1112c001c4fc9f8747afa88516463aa48bfbe606a219dc30cef0af2f8d90fbed0344806558cba64997210f779e9e45f2b080c3499416fbb3eac1a978318ed9f4fd34c6fc764a689177105047697acf52d93e8472a3190c6798901b36dadae0864eed48165ce57765d61272031a229d6605be903e38b3ab044730ca7f0bf28c182cb4d892ecfeba20ee72dd13d7bcefcf92a053ca91ffaf301a486ad92fb396cbdebfb3920864116a41a1d9dd27f5ebb53e4dc6a6fb4d656a6f4678b7197132046141040add4b2a135c027da490c22ce2ef5fef5d569ab94275f00b9be8a1055fd0055a19870788f1f37e61e9bc24c8b4f1852ec1a2c3e622a73ac3aa7fe57c0d2ae1bf372047d1dde0b6e46069d71113e34824b9bfd6d7206d706b0df6b389a17441954b45665bad78ec6e24a5d222daa406158ee49db4f3d964f8d7d908a132a805b65b5439f62f2a679c764b7260c2eaecec3a35019a0ad9fa4b35be9dd113fbd9e3858ea8f243c038bf283856a14642f6cba12abd3b9c7df3843e148522d2a5906b93e035ffadf996bdf6c648c45c84aafbada85302d3053b4c9ad653a57490ae578358f6bbea9901146417586e9a11e57cf050a4d574fe8087db4b98035aa6e4c84c416f19832c0737f5578829dfc64c38ce32768adb9c81cc655ac1d12e19d0d696da098f8cc2d10c66a7fb8b7004e71f91376f2f35230988784b8e911eba83ee469078ba79d1cd8097e472ecc0d5f233bb558e6dcb17509010f71c225cab060d5991004bad2014e0ff4eacae4337dc325acb80e63e9c5963b7ad6e52012ef07748b21b7b5be9eb79dc97fd8820c848c8ded194317ba556b9b58e364ef82b6986629f56d4ff65aae25e90e94271f0825996302c5cf2833cb825895c97431e5f417a483b8e7f3a61c3fabec64f8b0688be30a1588d2a337a16eca94e4228e6c5e608586cf6dd13345b408b2650a62073ea6e3038a6e0aece2bf6800513041f4073de9d53888969ae66142d5dfb7e2f0ad8a99607f2deb46db4a1dce01b311608e7562587d1adb9a1e9fcb326025410c629e0aa2148a5863d6a9c76b353c67c43ecb158ff0efaf596570614edba03f98e9f55c31daf8a7f4d8200defa06055e14337a8db6af16049fdd257aba5f76c54556489ad91466f800751c79af635c37aefd3e665d57c830805428f0ecf2fdb2caaaf55e2d8ccb7f96219c2fd5306d931771d8e206a761300e50a937782372767f7edff86c5adea81bb92b8128cd17c23313bca0dc00db8bae083496e215a0de67582f6f20ceb75dac2bb4afd98f2a6cf9dd780eebcd6fcb66203bacfc293944cf93aa72441c23df722f07c07161bebe940464f8a8fbe6f9e3cea2cc834b7c30236d3bd6db17479b14bf63b8442aba68ac1e2573b79536e6155aedfb17b82417273558261b97f9bbaa2a80ea96273f1e8df597d91df824ace3452377c5b96a48bc8b434e838d2d95ec218a35799e81833c067de69ac2836a0f57cb37dc07396ae0bebd0abbb1072bd0fb0a2c30b2d9155b304754b175cd6d94cb4b44758ebaa38dc8aaa5957a9dd012aabf7620fc425d05a30979ef357253b1227b89569b685eac691d45aea740f30701b341b51869572430f1a1c70df06150df65eacc14a1df08d446bd51ba730056b143b086031a500a2a0129211b4f45fc11b311d37b0d9e273fb6b3dbd0f0cea5d13b3a67e5856a51af7835de2fa32904366fad847229dd4af2a72d3ec12cef9e301d8ea34b18c6531867e4127fcacfe419240b427c662b6fbbf0a7b969abd2fe6484fd6da591b8e03cbe21dfae0809d6de5b0418966ea510503b8f3f3599050b6dd7e11924f429dc69b2d1f82d9305a7401e716fbfd53f8d51b0b7fd5f3ec53eb0fe8b76062ed9260a740626f8ccd3cbeb38d646dee589075d039ef7208f83e3373bcec38b05820c05fff0b681ef98a384bfb1b933198f2df981e8445729247cfe186dfc7c756683914e5df31296b162623309c2f86db977e1acb8904f8ef9e3f3665826c1c2ddb5c3411f8424d040afc982042b8845f734d2a7c0bebf0f0da25684e54bcaf4062271a080c3a9b81f601378c9ab74a3a22d8b902256efa8c48c3ad3dfdb295c5fbecf286eab755cb8be7f5205ec61f17bebf8464f817713224da978b44f8dcb9a7cf720626b2a47aa3360b91d712477ed3c61220e6029802a904ef16cba696206f455781a71bb73f0127bbd002670c9ccf1f132ce0a32be28fec58d7418c1f3c5b4b0681c3b73fca26077a88939f4960ee07721f1859e33f9b8b2191022883e724494588741e2fb858c1c823b34c20c2b1b96c609cb396d4ef7891870ac572c5d5c60e60f6709bd613e3809764109305f01adae46105e533602452572f8690f09e8ae449ceaa82386c90d62c22c5236a31aa3589c6ac38f864238ab0bee3a86dfd674db6281557a9e034975d3da35976d6a3a42cd87494821d9dd5ca0cec2753d1a45f6f2dbae438fd077500bd3268389c57793af96d834854b5f02124dca720def1c66d285c63d316ac4bd482bc492147c60720ca0de0c1f5bc4608679e1226a1150a717a45c66468b04714ef17f88ad968169a43c80d6c7cfb8f50dde222eb957e7ddfe5ab517e8d17bc5aa3426097ab67ad2b6cb2d5a56e70494673a465868277ba7d2d3f5654d180fbb6cf727fdadb85260e3383e183ab0db365dd8b661a2189df0a9f93c0fba98640f5699859212933ede180d2056bf8fde789aa1317020d220b5236fb351112c838d25f3bbc054a197e76e4addd2b0edaaa3ba1eae32a39aab52c1a40d04f85e281a69e5f24502deabc3862b004d6ef22c6ef0e97bc0b7d3abccec9f40517bcc06cce9e5e83ca14229120ba21b1e4672f6a60b53543adb6013fd60c89de7bf59622350b5e054260ba5eaf461269d222dbcdbb3b3b1ed46269929396bae63a0ed98db64a35791f5a307c308b242182d1f881335e7470f24145446a9d71065a02759047d439e714783dba45693f8f9de0e490b834bf861c68d9fea284f4cb9c523efe3f9393591e25ec9cfec12f8f37bc8e42dc3664678941ad2768c73927711dea2f42af9256617bd527f339c68c3f95bef715b442c3eef239e07525cc8e68d2590e6d4386b111b42ac60507b9c4048633a390c89ddd42feb4995b8bcc71d27acd4d4452d071d5f1a7327f51b86b8b0a747f1b46faf80789b81f4c323f67256603040095a34d6477f47a17098d4661829be1be804e3d69e95fd3a0a3fdc4457c76de7908b73dfcbd24cb5cf69041be019449a573b5d6a972b1dfaf351e4c20224e70323cde8986d509413cec84b017c7f3de1349a6b78da62b5389060f37d5aa4165bd11c7f6238de1c0c08deb6c760e108897a9e5a53f281e8863d1c4758dc0a15f3e3e927cafb6f5bdcafa920bb86924c119c44e1a482208278e222140bac402068280953cef01e60838b1da8898112ff941a4969c496309ccb300fcdc7ed72457a131f67886587344b15e2c0b8753faf395b432ac1bc82af3a2e0967c250532f0858fb4f6bba4479952b1795a2164a78fa9e3aec4203aa5131281faec613b4489109bfb9d1a6ae516af4f11953d65f3b1bc15f2d66a46ed473caa07e321e697b06483957a0f1aad5dee791b005fc57580cb4b4c0872f597d7d7b5ebe53b9c34983eacd97a18f83cfc5697f8f9d01fc280f2af023efbb1a795135a1fac6d66ae10285bfe7efa17d4911fa650b088dc6e393340ec6cbf9879649c27f59733638e4c1d260fdf808ec9762254e6cb8b66e2694933db23a8052f11526c75083f212ce0b63831f5ffd93acb91f9716d042706c4d6ce06350b72b341cfe54fb30721a97e5a2e203edbeaddc482a634efade976873fe04b93679877fa4e17e1ea812930c4a755365466517cd649e53f9c7dc99406f9687c1620636971419c85cc37539c80823c9c4472e50a7c5e95ec1bd725c02bc768d31154bd70da3b2e7447ae8b438c6387d772904551fb9ec94b8b4ff52c3d9403a6421f946e10197a016be6e401c531497ad9ac3317465d6dc5f676bdecf28a67b05380d5205f05dfcf1ea6bd031f704d3819bb332e8a57cf1d74d66c82470db235f66f96483ee3b6f80b4e6ec1709f26c59aebb28d54b757a3b5e7d4b4ac6f53f596c6d9f0deb1f2ef343311bbeaed4320f22837114d58880d05b250203abbda419731584f001d30e633aa6f8395c04e1597162a0c3ea572e58c5b423eac970b180fa25b770b9380c120bb37e7968ad5da8fb6a58bbe1ec88f368a628a8cee426274f5a20134d933d785697cb3b58859573addaaf3e0adbfe6d182c2aa56d8e52d0270c2b44813560bf3739ee468ebe74e1e8d910885dcc48504a661506fd7744fc0091f8f26d08893dc85b0fc8917e273f129350bc268ac897f1792c2752112c64d3f2c18b4e3fb38782c3354aa0b81689dd087d742895d23c98aa26727e61125f764f4b78d78a6a82c543ed5423d88e395c2ae7e279794d67a6159c0faa5017b0c4bc03d231d53cdfc3abe089dee5c4209fdcb93acd3c802bcda62170d47156adce77cdaec5b6801e07adfe56153b80325d3a37df6fef3bc623423daa63640d08dd15a8b7a2a4f4650951702fcb5307980ef1fa87d53d874931b0d4e7198907b9c0cd1fdf87a79111376184e88554b08143c091235197971cdce96407d2749fc271d286c752fa1981c2871cc049990f6eec5c51a657fcf4ee7862f578562df757d674f80edfa86a826d080405b1ee0246e60e978241a6db45ed6f59a90b82843820294e269e2ea0e6066345992c4a607641c1fb48eabf528b2cd2ed3897fe3be18992734cdf1a1b6a0497443bb6a7688f70e0b3220c5d0c73569e889976c70e0cfdd9111ab1829919d9b8a840e6435dcd7274238cb8689abdba6a0b6abde895655020f6f4d28f7edded0ceedb8d77c64b098026a210ab6a5261ee66b6d73a4369f8001ffcc67b25c6760fbd5a8bb3c4ad8f3f50b00a85ff61a8ec6e96ed2ca5aa537f9b115af98f82f46c15780f44a57409c69884bf8ddc48625c4376874eecaf928426e751d125a4db14af2737e227c98ba713f69909b2b46ff00cdd9c58e647d9b9e1762da520607e8b39baf9b707584ee277c55e51b8ea0e9cb039f2badc3b1acb230d6da22f8525f3054418711c66c69fcae312bc3808f098c17ed489c9861702ecbc2f9b9f4e48bea2914c8c158d1804b30df29af34522307832faf004ec720a0abcb5199a18ecb816e6fc5a14f5090a541d264cf9dfa83c31ead138ca5615b8b72d94b321feedefa56e8c9b4baa64c358a974f9af29134fd304b798243ceb3477b032f2c638f73260c9685623c57ac0b33c450821c78b6be2f9917ef5779b137c3a4e06c28f287d7645cce97c8891825c1d442cfc38af9b9b6e452c90a71f27b55388ff34a4f56b5c5c1cd69fbf19e7947e1aace7b60378e375ee65ddd702f986d9c24c19d1ad712026fe021b3e98b7254c64634364626b2ec625082138c9517441677e0568326eba12b939c04e473641e49c49eb2ecd72bc0cbfbe8aa3a11d91e2c32db1ab2d90dd16b001f8b4d9711d3f684124c6d9bc2a9dd885536613d295d11bc51ac7b2005a4d299a6952a903c06235b2f97dd6c4cb364d41e43bc3b445b4a2afd81b86b222729418a62806ee42af7b877b67f9a1b17ce61f9bc907f2be311b7d74f70f300b4ad76f08480d3b6aca0b48ca68a57a3930f54f438fd046ea82fbda6c6cc76a87ae52a03f006b2b75b0b6f4a832e53d496455c3a42dfa667a8d380a72e8a451812f4964b21b1a67afc228554a8488757a01523d59048a5e4a8b1ee4ef13a45aa4c98dc39ed77642bf094d45c41e83919ef5b28eb06e99e8cf76066173d4b6cf7fe5662d18a8afe4c1c26dea11e79857135d25878abc0a02ec408a62eda2d7a6f861226c9a99b3daaefb4fa3cd07b9199609fb27c0d1af0810bb335c28dda91425542db993dffb7e127725c5002cd793f33197fb82800a076178913b54359a44cf5328e149cde8c1576b83544eaabf341deb45f394da6230e0862a1c7c6c10bdc66358771b5a144dd2db223b595f8cc32bc79225034fc05dbaec1302904c7291091ea791793e7adb41ee4b22564198445745750b274751cfa052e18f550c0b4a60645c6cc6eb748a4836e3e75153787496ff230f6b5fc9abcca6a19ca4288c1185fd1f27988a21f8d1784b0766304d2da89be3781df4b8807fd735387a4299674a0c2e6e005fb953b5ff8b1f6715fe9c71404a246f1cb0f06e96c8897f271a17556c7ba0896568590e2aa41638317bedd969febc50112bfdff8744e43475d6974bdc6118a322f69fdd07493254c9fcb47dc2cf87d89a7cbb65e2d2399dab7667174d7fb21e427b39614e2963155f18b22ebd8ae875c2dcbd8e864b903c13a8d7d9e1fbe7b46df27820759b844fd5bf47cc3a5fe53d3d48a2cb344217916ece7e6c00cb847ed9918a887c5373da3ca224341025ebc9437b903de8bd84d977493f3125774bb0fc9f6fc94e7a4af7397f97d60356babb2939032bef769694d79c291356d658ce5441a67ea118ccafba69a4c8e100d730389aacf46a6a49023bcdd9aef4aecf81a3a0b9144cbe9cf3cedf8d8b4040c3f6dae8e44a38c7acf6e0582b709f90fe38186b3d82ff56b800867b1fc4102bce2ad5ffb856725b82f08a7974f2ac14e52f75422834f1c589c6177166ac552fea5623afd8587d512973a993551454aee3e0ca01b7d9a2ddf44b0a6b563ae335946e1c485a2f149787a4c6e410586f57b1952f53c75be5d87123a0a733d3ae465651a508f172ed5a1768c1cdf1470cd7f1b61fc76c67daff94c3dd33a5de821f08b6d128fc6e72ce24821ea945366e05f0cef469c064ae33bf48912f1b03ff9ea20a5e7d0f2adfdd48d5de69812a8a921ac48f7ff90b832819e2c472c82aa584360633c32185fe92257eed0161b2f8ac8d836c7153f6a51957760b35a1d6d665b58e35a1006dcb37450e0a6bc425ddd4cdb281d5254f991c0a193ae1c1824191b8fc29133cf0f180cc62b2bfee3718f875f909792f7c51c2a228945b5413e15d5515e721576889f942c97657382c29e6bf201584929f4fbd60cb1dedebdc87952e8b516c069a701a15e0bbfed1af9517de5e85ddce3281d07dc20f2a0a65411ca6d54412d5763e3f8443e889a7aa49a831bbfc9c0e84fb1f04feec07c50031c2fe91e2fb02ce28261508e48fcd42027aa03d27da747b3de5f95f95ec1439262726c9fb27a676d70e0ecdb2472570b1e70a40f853569be95cc57bab0d7e57d7a6904c749dd7955cb55d35113aa481be3b98effc3d662f7a595dcbe57cc00cd7abb613a31829756462e2a971b99e8283556ad0469a981590da86f1e14e0c7fef61ea00ddaad8441bcd631e9f68c3ad1e420d59d24d184a3c5e0d1bc3f230a4d24fd4430a2907aebcf28322a0cd9cb368e53a3420f121362dfc4843b190fa026f56f9f006978e6913fe3afa1ee2641ecfd52cb0f1f5f1fa68517d9a4567e0958255c28787f6eb294cc01dde4a82c7c3ddd2934ebde822a2cb0c1d0343a7e4cdbc638a9345a78f9380a96af9ac1131c6d3544e4e734cd33d4e08fe77fbc32638b88b7a61359c79462b131b4a53dc3be738de25aef21dce548b2b462125d6e6e167c409bcfadb1dd3e8fd937017be40b0e2bd58312b13438d9aa92e10148bb1b496aa41d818446d48a688b4fb65947977f6fcb0d6a113a053bbb363a85da5dc6f5f91d54db2892d977f8c2c2e404ed0d403c8d607a6035e915164a5b5ef8bd462a04f24073f528649bab27510f61af5669bd98ac7a15b3d706e751f217e4f4582f9cac9e42a310c3688226076f761f5fbf102f2c9dbe30b573340401dc9edcdd2b3a9459a00021959d441cd1f59b53b2ee7bd62e8382351bbe8b5e3f95e9e282bebe9c48f34a24fe377ca46f559c754e46746ae5a2ec32367eaacf56ea9360b92b31a647542b99da86c3c8a6065c24e5f9d1cac23d41b8810bd2a2ec55f4a52ac3cbe8de1d94916d392497c31c0767828883f938c090f18db508274a4e80d206f0aba97f07f6aaa59b062bfb7c7f5f0f9d381ceb4b9e54103be29ffb4efcd43d6a076e91e7ae3bb79e2b1bc512ae0e54648327e0e3f47d347f5113aec681dfc71800d151773c3aed31c03e45d7f9a7917f144531fb726acec0fa583849fa8d7c36a39a7deb0c8c150884985f402e50b7b384555610150b7afbdda9d5a46c19e6e79ec9e14c835e9685bca997141c73f701cce9d94f4bccd5cfa7e1f25a0411ac7311b08a6e10ab633782e8fc2799debb0454b5adc5dd77ad97aabd3eff8cb373ccf8032ba461549508d74f7062aad45ac7e2012a07bc91ce41a253bfe2463de0e5ea2ef32186121aa3c65fea6c667c55304f776c621c0d99189ab5bd761deaaa021c011a6681084af1e61ffa6420b2a3ba73675505e7428138d47706aaa4b630e1fcde009daea0a84895a12bc1123826f9d69d0f3670778a0320039bc1ba93a43658d41139fd7f296b863e6a6ddf6f5ab75bfe707f1d97eea9fae733268e17e8f703400169994590c6f2da7d55b7a446c4a59e50c62dfac0670f261a87374b894b405cb3623370e0530aaae36982f31f57abf2c2f5de9f0fe8c5d2a226aba51ff0d13108b4f8c9d421ba9030d66aec6d88b0226974e219ccdf3617568483af6fb37485170b6e3977841048aa70bf493fd4a17eab2a20c7d41f4960e91a5af8d09ca7da9a34b62bf95fccb07353915d15cdbb238f53d6dc1b61b6c0ac853ce216c172183d971ebd9e90f19c7ed23efd3e642e95f8488bb55c8d4ec472bff9a8fa8accb8cc5a586990efb70f0b3445113479dd6fd517aa15e36de2204ff7c181ac898bd7129c17017d91cd8f8c57d01cb4ae8995f7043474a9e4fc1062d7f4e8d0d95cadc1a2f4f44999c02d962e8357981ced71fe64968fe72486563b6e1d070aa5f523abca9f9f99ac43fcafaa452c72684492e40ba4e8a2cb3abc21013b23508c34565318e4aada1cf6a645ae0906edf030b6b4936460942c603f5da29ca358473e7d08d0d53c1b5f059559cfae579bc3ada96ccf0fd56cb7a0b921e408d3afdecdd7cf36ea83ab805ede9c4cb1bd30ada118e2828899050829e0fa9afd306d53f0b6b42edb20014e80183d73f9f7d06c69950d436f8cb1be43a12a95a7b1abb94090d790875e92232cb213b516b36f3d9d4a7cbe67d55568fd095c70db0a52b2e0e18dff623b24735d002dad91ad0368e0f6f1b3d4fa3b2384056301a34e6406359f9d408e308c5b70a75db5f395b479ca2b001a2a5104a5f89c922cd4d4482539ddf20d589023bb0f07c70bd3405521b4a86b12036283a768defc7ec32b08a7e63c09cf4316cb6c9e242c56a207c422f4c97cbe0edbc2d3be4c7d3951567afad7bce6a7b8b1f85468f97d63e6fa833944dd5d8d31fd0c5ffe6af822ac9245432b75deeb6296058345f3a8ee36fe42aaef01edd48c541099e3182e76d1f19df1003f14eb997708dc25a42f46fa300ae10edbf73b45f748f002400f93de9fef9fe92c03b48e9e8bb41e92c868328c78eeb53e92908dd85596f04da1383a7b3e6194763d55187e3220780a7a20fd501b31e5cd32052925640135cde8219955aff51ea08c5973acba08816c681569be9120c785e0ed54b9659a071a036ea6b21ef874512193d0141863673402613c2b0ea3c6161312f0007c08161607bd97bc404ddc522b42abdc1a8af10abce2eaa93465d1ca1adaeaeb3535e269beec6977ae59c76d0dd5d5668c92444c02b1f48dc356ae6ac0c9891f597710e8940217ddda28f1d8c815af094c48194d96dec3f397a460e1358919defcbe6b6011f7e04670e96e5928a9e08d2aa04a8852c9ee8faf5dfa748b9b063d7013ed7c8c911b3d8f8da1f3a62a87b4dcb4da545ef17931d8beea0bfc86dcc99160aa56ecd047b54248b2f00ad85d38d7f693afee7fbfa2128d018f99937dce7094db93f6bf0eaafb4d736bb8cbf5b7fb84efb93150127f16a30b353a6a9c3d9273ed790d90ca5cbbea36d80555c025cfa488e25eba5ae7d5c566d8540dcad41c80be280a3def80daccb8be3958f4e144d8a52290017864e4d2fbbeadb30200f88fda044e0c7438d8fde36cc56dab54264ce91140c7cb7ca2835e28748aebdabff0f0c4ff606b69fec88aa00b5dfdc10be5c37db87e3ffe8c858207429d37d1650772c9e7acb15bdc46af3353219b0919c792334a74a3ad9fbfa646340a8961037ab4f5ad1879aedf735e6d092c6b778021529a342acf125a44047eb094a8066fc2803844994b947123c1d4548a7804a9a642a1b99636574b67531884f4068d3f3e84d795368fb21399462c01f79ed4c89f24c58755c8423fd8b821a96257874ce559d8bf92e8f00309587029872e9a0ab108f846a386c245dcd1892b5c3dfd9a86ff085478f350d12b4f9f11b0bcca23d26af3c53ffafc6120f653cc441d675ca61e6384a09a7b75b347b24409633e3bce09011330ca3e3e0a04728a926910a36e0ea91c9b7340c50e2347270ddc2a8da6b816507f0657d532678004a8fc4b13abb08d28a85596f293346d9d8a42a5a70f662fc9cb07a6703bdb242fa139c2d861a9575a8f6207a10f8eee1d6a0d832fcb39f65461e7e734be83f1795bad95d21646a99a9fc5f0bb32d672780c27fdd0bcdd9404d343a7526291ce4238dd835790efd1429da4bf874964572044e403430fa9161dba21f70f703e2f635fe0c77c846b517fd2203039cdcbbf8ad13c6f3af43af3a8c92fc144ad1b4f8bf6a71c1ce9a238d256277e93aac5a4c0521a150bbb01a873c8907479f28d820a51639650d9c6cec2d0885d7724955b670a346725a04e2fb3b33082e55c3191ed6f823abfe671ee28921d919c6a1eb5b11aa0ce8346d739ff81fdf452ae2d74dedecc6bd93c5d0b45f94d5cd1eb40b15ea3a2524197f3ebd198520ab466c97b0231fe8629a8c273399e17e7a23a7bf9b76c281555653a07f986c72bfde7636d4616592a953a79afd01f01286a30f83049e489b395903b0fec128f9f3a074d986f9a4764350f0bcd0e54c6a3cf8b29778b775fa95b50f0af0034e1ca4ed93c4d3206e7541a01c134c62291125625a940b12a8e308e2fab3962764a80735cfc823d0d08aab4728565565d1fc6a205fcdd42228492f1c3a6f17cb0f6b5f9ca0674a8c592f11fc6a98a249a52c1e8f548cc28fbb73bb6324c895f862b2565a60b31ca61cd461f52b523193e27c598477e46d043e87012314e7234649958b8d3ea9fae87ec089af840f1304e061b65736c7d8809075585dad0d3699a7904aa1a3a8cc510ef7d5331ab1aba16bbd2d94d080887f8ce7d5d42f4816d70ed637486f5d00e654ffe14d52c3081021a8cfedc416ba75d7d6b2bc7111729e2409f4a03602f510ad65b33ebea2e98a54988e063a851ae3f3c0ff43b8136206132793b4a3ae32ad5b60358ea4fd3fe03e4746a945183085c6127e3c0b7ae06fc6c0b4bda553f12c9538a0f9f0fb86925a00000393c60b2c3b410cd4532ec09b069c89a819f95ae60af26ec66cb619c502b69188ff2c7ac883445008b909a77b81f97c20e5027487020e1100223817a1ffc7ce380412c0151956c1884e72bf1dba0202a6b25e2f2ee1c876f2f0296bf6a8f790fda128c9ce581e5401caecb39b0605606d6680cb2c05b33e8069569f9150d0ec2f9defae1fd30af0dd01e4ca75f829c81d6a29080cc9667985b76bfbc799a2fb65ce1a43382a9a512bc0c4185d562977ded362468a8be1e9a3fcefaa1f6f33374fecf3ea3e4150b0dc108e5335ad6e317f426e4055dee4b0414ba9e6df0f73f270e3701fbe2031cdf2927723840115c8a08aa8f7072f303bd4bc6554edbb2cedbc12036ce2866200434117ae83a45e59526342d1ead13981147d1b91dea622ef50c8d1f378b005fc06d5ee210b61f92c6267e9cf46efc41b55d37b800f2a619c2c2bc255052399650e2a5a8b1f2818fef77d1ade04b052d45295a6b561d92455efc1981e3260cc568f25a496a164013bf83ab9ba1b17df021668be876f9b61a194cdb92a731269fff309ee834e8563d5ebcde36b8f801bc300c2c1140cbdc12fc28e978889f12dc25299acbd37b8fca11effa843e0b72cf0b0cd474e678844ac4a41aa39b4d6a0d4f43a0bc05c4034134e14ac7444bbd301677a2b10837d4e24cd467058d47aa21cfec762bdb72794a0a2bc0143b90596fb4a0ef9e67afccb35bec6c54f25aaf8d4edf6d2d1e73f3cc18eddc61cfc89ba29bcd1f5aaaaae0952e79f042a58ad68628d515d2a6ed0e9b10e5a42736b3172dad43e4659fcdffe275750c9be96506a066e6d1d839c255446991457248e3597dda864b4f00176959fc0f3a7c6f1bcc672f2b0ccd4a5ccd46ecdb3b9a63a05a85beff49e8f88e98d3890349f92207d338e1337b34472e09a0b098cb43c9c9a034882dd34d893a364f65131a07a2f5da74f592834db75a9b3066030ec30f5f28ce8bf08af571ff4c47e8af12c6196c85b0975f88a3f089143e835b7a1879ec3443460d62b2b60915b88ba0791c6475388f47c398d026d3ab1ee8dce226203e9fb13820fec0fcb9b34f82e16e60a8efc192e0c381a1417306bce978eb8d05e958931c9aa533e8d0116f32e0cbe982b0e6fff77e19ed904fd2ecede624924e8bff0545de88763d4decadb6b07dd6115e9d402b999da3ce19a66317c02215914d15bd016d5cc13e674c27a7d0e2221cbbbccb0092031b42d52749212c297ecf6c4ee983f48ec0756a318aa168b934838d3c3324a0d2498ba3206a7cf8fe2dd13a9a5c29cff5c905caa9469760c80739a75f67f28cd02299e57f46b8623484cb00cbf6859a4298e5117f1cc41a61d1943199dbdeeeef45040870d5d3aa48763433f2370b0cd2a52c4bcf9440c55f3492e2e65f3914b0b380a655cdcd48d49608c64d981a47de3933385535bff5952d9376b4287d3ead35b307663c79d71bb4c007e68fa298c080ae047064b2f636c189278a4bb97784de29675ad1d8042baa85a23f810b601dab69161cf493108bcf7f6a1f67c397db571cdd169caec777dcdda34abfabf6ea70beacb82593c7f680a58f8a09e988f845616d2a7ea2a15bb166d04c1d32ded1ddc3be2562f6c252a7e49de157a2482a4ae92715ea1461a3a0159a990fcb344c37ff81bb0998100252ed801d8b98b067d53d11801145e7a6300e104ebe01405445f37ffe7856b66ce4ca3ef3838e0d6439df1a4e86fe767fd16fdceaa0d20c74fe91f3bcbfe7078fb3cbc7a67e61b6ebc8044cbe1a72fe2f7015aa71bc464cc078b630038a555d985dd73c2ad80e4ca6bd372829564690c857f14f3671d7f4737d7ff5367ec68198a1569f563859f5c60b7443980cc1eca7e4a0419a6ac875bfc598fb890cedf31f430ceb416d344b7eb007ce3eb9c8483faa824c7313b84269850ce88471b05838889064ca57c31ac480678f38f3d94c14718995aed836bbb72986dad40dfe4a65a24f2da03fc25042a6157a95a30d815271df1a9248c74b1cddde5f6e2a8e6ba65edffe82edb4892c5790a2d1d4de854167a7c90fa12714c2f6e57e904a07904ec884081213bc56c66429fcb8f0660d4baf7a451d822a6ced5476bdbdbb61142c82664ef2df70e5c0acb0a680aa44ffa19defe76eeb3fb7cd3cc96d0e74806897e589f475bd55a0e5b49cdfda846f490ca54327d6693e964f2ccd8fc99407307fcdc79d6a51e587b2f0af583e092252c968c138aa9a43de5db8ef2713f7db7441a556b62cd1699b3c3c3e289f9c9c0cf8f063210f343b2dcb5d7dc6f246b4ddb4d1876bf1dc65dfb4c4bebbad6b49efd997ebfd2533ab47387d96e4f43ae3b636283b4414afaf6c990be5dfbec35d35fdc4d18a6530fb3e75ef1ebbe8461a4dfbfb4f697d52c69c3dcc8eb42a6c8403991647cf6299ff6d3c71de5db6efabc97beeea34f74d2177a0cc5560aa9a5b4565219625c99819f1f0dc4fc34bd01249555faa6efe354865da67b718a9e647fffb2bfa7bfda4918b65d3b8cbbb5daed8772ed3bddf4dd8f3e12d54894462f5c6bb3c3eeed33fcd27ec23052ab6297e95dabb3528652ae7b9209d7d488ec4b58dbba90e53c91e88b2dda212d405ba347b38436cbd60c3404a1826290cc913b4a3eee337cde515fe8299fe9324a285f8a9e4895862fb65264a0f0f8087991a0eb22080a1a81b5f7a2503f088a404890b5f7a2503f08364a173af71a138a0a78b225148e3bd1c87daca9924028b3e2ca7cc7a23964b1240e6d3343160d59b8b39ee4b8d039cf74ef332d1b02b283cc7d1b727517322513e9d3208c865d349443287353dcce618ca57470efbec3fbe931e442691f289b18f787931a55ca956a94777fa1bc8b13e58d5f29efde694ff94ccbce16946b32a77be7beee9c0e1947f94bc651304cc71ed65d068ed3e217ca5330eca461da9dfbabe3ba9317fa4ab8a686f49ad125cd0dce4e689433495f6c09098a693d1283a7eba2eb64b4b16449cc85424ae1b6a3bed3657cde51bed2492926ce76295f6c914cae26ae26381abfcc0cfcfc6820b6b5f7a2502c6bea80f47bbbf79a93c52e53d7e1549f8ba6eddd5fdbbbf73b0cd3e14aef7e3acc2bbdf3be9d708aceacab190f8943dba474a4fcf457ca4f18a6d387999ef23a1d05c34a3fe118327dde4b5fca9aeea55ea5772fa5ec7778377d47f7d2a7c384e3f44a385aef761f8de109f974fd1095b1d8be96acb985bc6ca150e157dc0cdfe9a8cfbb8c0fe5a42fe5a510377a7767f8620bf5c5968c2fb648251cb345e6ecc470cc98a99a583af9f991959be2ce4cc167e0e74703ac19ca40cccf9c2d76ce392de5b6a3fcf49a947bdc86537d199f69e9b8489f993bbdfbebd47da615aeae1637660ec498e832f37c8fe862f366a79d38b4f1a7a35e8ee8d29fa7400c65202dba0615dcd3bd7337dd3ee52a1db61da58461a5a7749d0cda60eb64f8e55d0686a5600fc350f009cbe86497b1291ddcb7bf381c67865fa6973009d7d4dcd7885ee39d7bcde8db4bd36efbbad0c813dd98fb0394f568c86b8484db970fa515794e94cf3fe5d38ef2653f7ddb475fe9a42f65ea2ef26228555b285f6c9dbed81a7db165127db1d5c5cc16a984c7496318895df49d8c19dcf0ae061257240e3102c547d9f203b78a2bb3f10f6cc59597178016ae7c877e48d5f3105ba45b207ddaa7407888ad9a1aeddb6bb297de3855b18bf498ede767ccb46444bf9f8f3ab4dbbf2c86e9347e6537615809cb88601b96d191317dbbf6995608e6a923633ae9abd922c2291da56f4ff545b7f6a2dbcf6f2f7dbbd9e7bbd297ea974ebae84be9289df454e35709c716e9a2df7b114e354eed4891020f4ee06447e9262ca3f312bd84613a2f7bd161dab7ef109d034a20e1890b68685a220ccb6e2c7d243cfa745ca2675f4ad3b62f25c23535a1d774afd9aebdc67b0df71afbecb1b5512153356f3fee9345640ecd4d6cd9d8ca7e4cd5fca4204933b33922ba947cb8a23126ad953597559248b0649784e879a29914095aafb821cbdec8228d43959c9a9996906575958078c3ccf017a03daedce0862c1edd129b7559837af2451799c562b1589946a94a5c913ff97451e5345d4e1f0e47e8014fab93dee9935538a20a39ad6e7a13264f70c3049ed6e91fac04318b214a5a76dac027a8a5332f714a0753e9a6cf64d267f2fd4c1e7d268b3e93439fc9de6772f799cc7d266f9fc9f63359fb4cce3e93eb676025c88410d43abd0434c2a0a48582f279b1c13b1285bc8edbec923caf61f19dbea6b1a2a06058095a51a54b5d81e8ec0c51d5f79ec3b3c4a851176eec398305573ec7c7160c4fcc22c9933c9fa387667122cf4320bac4aca5663847573c4fb36f2f8e9117aeec9f79d3459530fee40cdbd0d4e8a4224a33d1a45f77c9bd7bd7494f7bd7c54945b4a3d402cf3ad194807dbdf172afe86691cda2edf6bbdb760f257a2612fde2f08a3ec2212a775ff82cbf98c3d71cb877b7a11ba125fab65f9fbd5a955dc3ae2de85a8c03bf3498612737ac91b3d7a89fcc3294837db5e1fd667827d477950f9c1bee8752da2c6fb3c84c4a8baff59e33cfc69ca2077308e62035d71f2f097349ccfdb03f06c495c9720016b0c1d9ad7883767b613030080c0b813568823c4f6337bc12e8e6d44bbbbdc5b058869686532e6d66a69544fbe254e510cab2932909d3030d59b68087c7933c234b18b178354b2a521b53ce796f63db51074dc3b012b4aad0c5709e74b13b635629cd689665d9a946c4cd88c0a17999aa3ee5d9999167a785fc08d260cd3020ec3c519329f6a6c5d120fd15375ce5db60f78c46c5aee675b16b25907a5601c306701557faddb11a675927c4aca43102945393b29364c9901b213e3f82c0accacab31764d5b07142d59a932787489aec5dcfc62c91d56ca12d1db4b59a2a6a69dcd16c6896987b88c151e4c5460e14ea07c1d5aa8bce15f3c1751dd73dc41479b19143ce6957d765a74a4619623e9a25b4425e2e986649913435437a88e9e1e57ac1bc62ae18ce1671b55a1d86c68ae58ae1e1a3c60b1874151b66a3507395a3596068ac58ae181e3e6abc445a83c62a7a34583456ab154d0b2abda71936d21ce3ca6b344b7871a81c7c71bd7ab061754f36a8fcde19570554a974028971a3125dfaa5db565cd7719dc3c5b259d1a811dba28cb83d344b687bd878c111f323082c87cb7a396c34d8e2613b4fd6060e1b2f3796090f2bba34901cf25324c80f2137384790c07a2889e1e1831557807e04f9010403e2e142175552dd16635d276d78c4f49034f2864804830fa0dcffd16d9ccc71bd9aa55fc0d249906149eece85b4d08dfad260a31a943e70ef1e72f7ded13a49f5fdd436a359c2f853eb411aed57346a744bf40250184836aec6f0a033e28a6cd06bf0d9edd7e125bc73ef66e806d71cf57c34d87fbd77ed5ea4d5d60d5f1be98ec6c566511207896788376cd886384f6933959ecbf203bd3c4d9d81d7f2b8c71c230bf7d07eebece779d693527ad6fbe6799e77ee0b676c0dddf02c8b7cb8bdf33e9abbedd3b66bdb69839a77db2cdbfb1e0e376c716c508b59d34e3ba44376972be64d8cdb03c73498fd93c2ed87f127025523ba1fe2533bc46bef3c731ce5c4167ba459ea61eaadbd17853aaa491399a4c12a711aacb7b3451e69547d9548ecb5a87b14f81588caac1ca27245e57aed8b1905ae583c3eb9c678882d98a9aa625ca9a4c1fa0ccb9d06eb27852ba7ac4d38ddc88356e220f105e20df3d3621c110a793ee4f2f4a1691c71a50c37bcf9d6e89621ded2eebdf7765d4a323379a770c3e8130407bda49138b4bc41d2c8badddd6dfae28692c607874facf206f99b53cd4906f2071d0653b001142d450a72761a5996652846e415dc20d3537a148b434343938216b5414f2fcd810e4c34410c5d48c10bc400a345a3c8947699524a293d856e509397b36cc615395469400e6da091c525648f61b42267437c51051429a8428f0a8030040539fb8a358427677f3122673d446021672f856e64b11e1c81232160082264fa1bba416f2290f4a8c8e189460e67e44c256736e42c873472868224c09cdda2a0276747d9e4ec6f96cca6670814e4ec2356a6032a9a082253c0135114ba9145a146a60f152144cf8c9cdd339249968e4e11c418999e531142103b310959258a205240809cdd460186abc5584d105a90f5d414c139ab91b32ccbb2b39aa53ebac45c4f2917997edacc467616bdb3e50718b2e8c1177e983831452b83226755d080660753f8020c9d24b4b22539ab020956e4ec349a45cb599665d96807379663de71b133bc78b4f79e5033ac56356dc990aa0448f361013da19e68925920b23062064dd505828b18f445391114041a9bae77b64414bc40664dd3b4d3207c11842733d35059eb398112596341ab5efba34bcc5a56c49156c53c8125485a1573682f0a8922f754837278df1141bd44aa3dab59560f20834bca91878b2105f0220603d0c2f572e4e12227c9ed72e4e12249017eae8c1c79b8904245836b73e4e1a209aa2cae28471e2ea4001ee16639f270d185ca095c7ca1251f01345531d397f6420a99e6d873040ec5e962086eec0102498e3d401891b721c71e1300753c59a2c0f86329cd33356dfd992ad9627dfac90a77d0a499a40b00f1939f34283f693a30834c1f76900ea52a903a48faf8045dc004364b08a50f95ed65593f6995fcfc3a2805d75adad59fd962ab882af92b9c3801284b2a04fdcc96d8720214647de28a9ca1226d00c1556356835658a10609e5809a856679ee8ba0661965f90ea743d22df2c80f67827086d70a2f69b4a60f92d84e93243f4e0421cb276450b384bd24cb870d463d92e5659d42969776489697960a4b45db6021b5f0e9427ee15333443eb1ca611fe138eb0364e346e39721cd626f6c911b7b636fec8dbdb145ec8dcdb13b56490ee993e5b9d08dc638ea14341acda6fefc6ca11b5d8f344bcda93b35a7e6d49c9cd9125b3b4a787c6aac8769433726860123ba00e0e7a626cf7469b2836c6caa1a871588c70d9ed9626353257fdb07757d5041d9e736e1b13e1ccd7dae3f3eb21e4e9ef8110426a483105d3c10ad903d309338c2c429ba45a6817e92a6c11a9a2136f2ed4474f1403d9039c693ec236e91a9cf159ee4e863852d72687d7cb6f8c9d6a759a2cf15ac681612901b7d8c009467c8910a3168b20c51a04f9329f6000dede08189533be489c31c62f6c147dc22630fc42d1a89db3c3434b9af10db014dde22d74f1291370dde1829522409ce9128c0901b89f5c9c9d9d949d248942cf16162254f83f230e878bea027490c1189e14e2a633c2af5f80331e4e9cdeed460ac8127db49170d368bc4a913d56205c6624e6c036e0f4d1557b493a8ea8709c832f718bd85c9823c51d060c8bd0a23f7971869b01f672a82368c1134ca7d181905d0184e40d9438382ecc51772a53396819a259c4672374b7711841c71c88a0fc137d8a780912e3418b97b8cdcd12587987f40c5157a525c918fb345c3332da94d19144a1c197b8a6e1cc24dbdb6db6f384efba55ef6da2dd6709099e7e35313ebe85686230eedad8844c99e55d65a7b061157625a637615bb553a5bc64e947a79adec342f917934935996c52aaa2a204a7e5bc7d1d99ce4a2260a81c82f9c91e3b3500e5e68c38d2cdbb8f285b44a9c5c6bf5116333c680c46b73688e0be53033e56e846883f15d77e3dab822bfd0bb9103cd368a3a11271289449b4824125991481365a24a4553d42229baa1b6654207e4071d6e9e77d103c921e6781e628b5ef2f85e1f8c18b7c7c3f80324440b1720413daae2251039595681849decb595fdf0ad842c71b89a715483a89924c6a03b73fc0cdda89a0dba33b4430fc9d95f6237118c394630d59d7b97b7cf005914c5851bc626303dccb709721afc4f13458a18094216326d5ae9875570c3991cbb71634ce9aa473a6822884c7118794ec793a2c65092572231dce77005529ce77972b4aa51524ca49208273b59d2c7fd7a5493dddaa4cf5e633f7ae314c52e92f6793fd39ad9b5bf320dc3742e86d98f0edb9e5d510e8943db68cfaea3bde257f6118689bceedc76ab3d7b66394fdbba5006d469419f3c49e10923908c138acd913ba3fbd347bafd52dda62fd5da97ea6c33b99ab89ac8202020a01e69f1ea2d5a8cdb0f59150810d00fb3abcdbad61ad2b9571d2ac35dfb0764ee7b9cd231bafd0eeeda65745edab9cbd88f2ea3f3e2aee154cb8c6e71aa239008e20f21d16566ae08398434811c01a55ca6d2f6d7e8dbeb372ed53cc4d6a8d5de0f201a6e0cd6de8b42fd2048234392439b5d9f382f456688916232625e4cdadc948e3a9df4a13ce513ddfb42efbe7bee1b75cacb6c9145705c1966ad563a622cc678d0e18a2b73ce3963766b310f40329c6aaef4d36b4c4739c5a9c62e6edbba14ae54ea300ce5a6c34e2f95bafba5fa5d37a58d597d712a7b37c2a90c7bdfb68bbe947d77d1435f4a4777d15316efe82e4aedf01ebaf7d04cce707fb40c10a098a67c3af528dd63cb7b6c99be542d7da98a5d35f735a353981e427e4423576c47644457935db6b86e12ebdee91bef26f49d6cdf7491c6e99c50ece726d6a46f6c6868fa2674d15fba6f668ba88814e130fe28d13e9acf4b17d1377dd32de822fa265e30ff00a4def8a1e254db7881f911a45b9a8633591c25695347afe17eba992dd2364e1ee10d631a2c5bd97723d8ef5354f58c1b0dbbb6bee924ba88d73c681cb412d987fb4b7bf387c3b099968c4d9574d2431a049aaf466822cd32b3226da459ea90fbc596bc29822377244f8e92fbc956119c9c1d253cd927fbaa0d5da4735a49fb344eef74ac6fa66aaebc99ac4b4328994699151de5d34a1fe9a65166b78cc7498c931f4052020102fac1b4b5e8f735da4975db4aa34fd1b7bf441bd660573412e1687d709234362938397207f5d99f3eed29a3934a753b95eeddecb9d7681fdd6ddb4efabc3d75ff6a3761d8e81a9631c9a4bc64b5cba0dc3ebc2b199d17eaf73232ce7df4c9a07e9ff2c1745e28144ee9189d7baabffdde6ff81e86721998fb08cbe8bc4cdf2e83f2d139946f9fe9a3efd6c3d88f0ea37dbbbd8ed1ada69d3e9dfa6ef4d2b7d2a8f4eda4a75edb49df768c4678c7f6d14730edf7b1451a7da5ed2361ea1a5121d2a6484e698676e7822eaa507ab984d2f7982d324e23bd07572cd4c75dc6d73de543f9fd4cb75faa6ea72f551f4a652f7d4b94528a83524a51534529a594d24829a5946625d26b45a174ef122551fa55a9547abfd47587a19ca3b4eb3eee4b357e7ffb4c4bd3629a45667a1e37d248b7a4f8a08f4fa296b58bde94cefd553a87613a5dc2a97afcb2ef308c746b755cf7289f8c8ecc09a7babbe99321754f55d2b9a75ea47327e1780ea72ae621b62eaee941efd18be8b72e34a254f260a193fd05bd7c119a3c67509e4ea69db13c451867f4893e7724d752c293a74f9e9e2c325b66d054cdd9c4499e4524cedca1b8831a6806379c3bdbbc22a88a08d4134e27363c441e160fe6cedc993d789e3ca078eecc9daec1bd84b7c84ee835dc453b9ab5386c9a5463978753edfdb5ddc31b27c21268aa66ccf327679b2d5e1325b365eecc6edaed93adb933adbd77a7795a49fb28992df701dbc3f6699eed8bad0edd706defe6ce74622a993ff38a3c67153dd349c7162d21ea20a01db225c2b09956037dd3e666e27411ee9c4c9a25ec2e0228dfe91b9df4d7e824f0de843f55364e95bc992d323af332a48f2e53fabd7d0da574903efa8bf4d1c4afd22fbe53652f7bfec754d1897f78915e3a0fb1d50316838148b8f4b9a68a9ef48d7e1fc6d8c453c695b8321fa76af4f5177a5c0e1b4702149863e4d0b756a29d3ec66791a9768d6aef6f9f0f2dea6f13e1d40ea2cbe720c2b1c14dbe747fa16f5fe8338481b293af8b741291652ad14a9c14913c3eb14ce9c4892bf41d96390dd27358e2b492cdbbb36b1a4c20bbbbbbbbbbbbbbbbbb5b7677db8bea6f49109bab17128936d971b6a6e6f6a5e67cd7ddc3b0d0bbc33ce9356d7920b0d57bf7852ee2ecf62d13e14f76dc66cb4099306bad5ad4773f0d6e91ab3671e85e8e07d4a9cce0662fd246fa488ce6c5f5b1cae10766c255eede5de6ccda7de2d05ed4bb87e04d7409e52ac5edbcc3f4a13bfbf61cb2778dc3794e6a9f30dfbcac974344962e2282f5b58b7c98d9625bf5ffc47d1357ea43f76e441209e170fbdcae3d9cf7f09d1f6afbdceec3fca9c13aab7d2825f76aad943951552f71c87da806ebbb5a67d7dd13964570779106ebb57ac366a23613b9be999038f4ebb970c32ec2a2d22c757ece39a7176b6863c53ef44e280a1ac11f4184fc90427e48ef2fed7a892ef337c796ee947b188f9029f707704b8cce7d36b6157af7d508c16a856e635ba38732485ba0f7d116987d555f57347c61dc9adac18633d9e2983f32dcdac9195b52d1129ee8a1bf44384e5508a7ec438fadd7a74afb08a76ce83b460f61191d9911aeb161b5ba0b615bdc778444b8665e08dbea1e5b1e76bd7c39aae85b3542dc568c090863121610862203c25845a6bfb305e647e2e6a1b75fa4d69334190aee0bee15fd35bae8f222d14f18069b91f2a5d24f1806bb33a4df4b895ff7270c83cdd819aead10dd4dd3f8c1c34402cd1a1bdc340dd2110eae8ca3340b77da9d5e2a992d293ccdc2a45942a740d1a5e485c8f2d2a01514658a61d1448b08441095f2c596e94727c5ad398c403274e3be93e2663f82d450c4ed3cc369787dd83499c62f9a88c211b01006115f006ad1d3f0499b4f0060dc27cd92d96878862f5632dc50dad8d4e98cd3194e25ce8c2fa5fda92fa5e11f5ea9cf380fb13503c32e4e3db66678f8149ef1451a3ec3e50c34c8af741a3e199fe1433d86487fe9b8a21df5c9f8a44dabe869fb1c9146a8cffd2493d0279334d8207d0acae8933c9fb459c2f45367c212d0b27c04a81722486f634ec99ccc268925d08659ab06c15879f566d4dd4d273fa7cc892bf311cb9d06230f8e1fd927cbf679992371f0e28a892d8748225922f9b6772a49dcbef797e80244e6eef3f9cbd9261a8d46229168f4eddaa7e592c9f4fb1da5d26fe932285f4afef4d8227d2989533a4847f98efb139639fd1e05cbe8bc4ef85e86f4d8eab24fcbda2512890359d3aaf921448ca08efcf8ec072b7d2fae982fb644210dcb1c9b371ddc0a06d7b605940830b8f9b1a146534a299594de076aada596524a297e5981ac06a72b8c44c861244296407f3ed62c210ba6074ae99663cf12262cb511e7ce6740e858a64db46850cb6d93a495f4cee5473b3f3932269bcc16dba26f9be8a265fa1e22b2c03448b7e89698a9a27247f2cc16ee07faa2696a32c5400fc9b49443885e8a6bf397d2d1ede84ec23542bca5935d473bf7fbd40eeef7dc2fae21fdbef4e9a476e8db374ee9307bc2589283344e499be812caf47208a594def9d5a01bf64e2b992da553d3e99ba777327d67fa52db675aa52fb5e11f5ea59bce436c99300cc433ad9055c23a1d82a6aff4d100c38d2daed59deb1b7a243649a64b32bdc1992dd6de4b7f3fd27782d11830cdd243440cf490fb23b5904d1aa4177d92678786505bb48a9e760dcd939f2f32a5b28b4cfbd3b2b599f4c556e672b0b971dbc4151ddc8a5d158cdb8f65ddc5baa8427ff821c8cdf24066196872109bb3937e1fca941ea477c1348823bad8d3eb105950f4acc8928a200522c7a0adfb81c082e0e689551ae4bed1bd4f14fa40d64f4d5cee5c7d78999abfd3fb8bbbf7790fc374267e79bf1816a7273bcf4fcb327423a523f4d15f211ca76a845f9faaec33845753458f23aed07bdfa78abefb5834a54304b79eabe1a6f1a776bdc110c4f0931590e310ba004556a7bc46e965f6507ec391f6a53c8739eece7338dc3ecbc50064798e468a71acb8707978f4f07129b970c3f81379785cba1379e4b51c7ba0c8228777053702653f6861cd29d2826cf1405bf52f1d2324bac8cf8b20f6704d5304371408892b93155d4279561c2382084ed7d67329ae5fccb985161db1d08105686a9db3d67a591bcc76b3a19da15b35cb74e9af441c62bc2114b78883a4efc6e100b27c78036a0000c061cdf2214aeeb8d26f2d6e189b8820e24043ded0ef5f20b6b060a20b6509c30b510b395221776c61916608bfdc8f724e29e7074a1c06106f90af3400904359664ef89899899cac3bf372f6f8653bcc07913ae8e2bbb3ac3d309bc956cd128a38ac5bc5f2f7e44597ea925db6962d146e189b6020ba3421cbb3a6aa87980b441c5e30d1a5de47f2842c1044e6791f335319ca81c6184331c31ffdece7810dc6b366cbed97c4a1c61be2258f96e3c3d8042666d0c5568d7c8c57e9d67b6096090b2cbfb3de5213216ffb96e60909db431ac9939ab860e931a3138a438778c3fcc42c23b05e592fb86174d2835a7befa39356d95a71443de8bad8639ece5833ed2079c64fd3deefb2ac434a2badd92773d5c1cbd9bbfe428d6adaa95671d75f988591ce9a793674233e76ee7e16c3997bebf8b067e7b066cba4b392529a6913d3ec21a594ee44eb7516636a06a81c1f67a593d619638b26a594dad43cdb2c61bc8c93ce39e7ec8e0b5aa0546a418a49062d68215a21597e5a1a032dcc89238ef25352e9a493bdd560c5799b25c6497134d88f361a6c1afd15adda0fae0d2058b38cc2e0aa3cd3ea0ceaa4d32c3dddebd9d922a3aa3e461a7d5e5ec6b85e965846907a1bb789626b53cc0210714111d900446e28c71e17d428e17239f6204186fc9ba172d68344177296654560308a9ba98aa018ee28c71e247e4023dc9b630f1231247cae82044e0ebfaa2790544a2ae795d3e6d974d22a86541837a4d9569b9d5a39a2b2fa7431c618230ebf1c278d94ce397bce49bb637777ce6194360a3244dd21ae7cc7d67ec0dcb4717ee243b905503f8632a8e7082472d8345dd3437213c91da3a1a109a29b8432890872b408430c2ab0410f6243c8a1f4d9410e654c62d1319913ebe8a40540c8a28e4f72d7cc9c808830960862084bc08101931cca224608914389238fe48eabd9e24310648083253b4fb65085560b213721db196b42104f8c410b1e317e5a3d45ee5f9cece54682152a4600c1003f99126122532264c8f43674838239461c0c90b96ba11b5c4619b182fce5ed59e8c6c6534365468352e786a8972b9ab42afeb42a66ea04045a5d11c4a26955cc4ab069d56c41a1622d6092eded9b25a4ff28fd8cdb90e2db9843546e154185ac69a7a59f9c653c4520e9236ed8b19f1690868606081e1a1a3b5bfae7e7a68b4c234f27a42e58790576e1ca10e544e264c9495114f6ca1863dd682127e0450d4ce0042a827002103d4e94411453f8a6894c4f8375a2072567286591e98d0d5880844c8f0adda07726891b90a10c487821451450340f144540913296b08230327d4a8480154f38a2022504f2618cc1586b2d8ceb158b7fb960228d1a8df1f33dc4263e31c618e3a682ac09b3091fa8481423dcb630ae9cc748f923251631461a638cf81469157725c4adb13d7b26d1c959653fac92892b1fb1684a29a594524a69a59452dab19e2554fc4049cc162bd151634716d4fd4e344b89c32c561da02eaaa88c9260439e3f9805716b27133058b58cb3e7258e9f0ae8c5157a0a647f5149bce8327f85ae4f01f0b933f245e9e0cab7066ed7168951d4663c7d7170e5e365164839f6576badb931ea92727833496679f9cc8594e76d6c91a48c73e5a3ca6c25745165e200274f7ff28bbbcad6de3b43301603820f9cb83b477cea1463c874708489c9cf33450bace8eea69466b5577727c623d6c3478cbe6009cd6685c4b559ce9d314615f4102aa707c6cda1bd3f3589631aeca15dbb0f7d1e0dcec693ca39e59453ce4b1cf6889973db68f3e83135ec9a314d9afcc4f468c2c34793263051a820df0cd44595f06e3d37dec881916e8903144f1cb9993f11078e1c4bf29c3c730a2249b6b879d6501a2bf21444bac8da125411f2c431ada5d1e012f6abd962f1276d7b848a1f1b6a4829aba4524ada5236c1d3b35b543ac618e3a3c4df887059f3190d54661744e4f4e2662339311be4a9a494524a29b5d6524b29a594ca15488f70795e6ce0c841a9b53725c79e2558b841ac0875b670349e4e94c3a756d5c7305cfad076f40341672b23cfa3c41b503d327dd5e8274a5c49a963a044707e86700399be5a8066fb6dc3a7b8321fa2783ee4792e8227587e11661553d639e794724e29a7aca11b92ce1ccdd2b3e79c731291854b26aba856c898f4913e32267d60af4019963e71a51e003cb8dbedb577f64bedc09c2af53a890a52b841196a603ae11236b265bfa38629705a4038a086a755821aa6c069592c839aaa6aa7aad630058e9d42078253e5801a9e96c51f0d2f50997d5631a2a422d8cf6c1ad44595b0d264da302b1aa48ff93448e792e812338d5d6be9ec209a0eea201a1e164b071949b89904b61dce9b36d3264ecec4f521d833dbac26b38c7e4183324c812850a6ef9d69edbdf3872aa1c8d4c79b3eddf4e927dd12c21d9b35dd90da759ef499dc073355f4351c71a1d8bcf8dae17ed238b62a9c357348a6dd1de4136b42df1d343b1ac213e7389c4428928963278e3671b28933a5c8f491dad4bad32db932ff40e9251d22aae88bc834894b95c8f41587a84c73ba90e589a94d5ca19f5c1177d263267786120a9c4c3f71664b131155f447e4c4c0064ada2674a3876472c68c8a26964bdac6da7b51a89634422a8de905b4b9276eaf4212e85ca3cf3d71b5980b26ba94327d0f99e6ba7c0d5fdc17fbe1c81eb7e87dc3dd8e6e7b5703127706ad794c00bd10b6c686d5daf01755f442d8d60d2b35e4edadc4a79095b8c6d6c5c5f71e0d43bd6733e4a641b06d6e6ca88fe842730fd17ac81c92da214b452a71673645245132809be8c283835c95c835895cdb87c329b9e18dc3323aafd0b9cb78dfbe830b9df3bc875216bf369cb2dfb8879e7a710f9debcec9fa1a90b832f4e1a896082f727df7b54d6f32c8620964a3c4460229b119722381b61c1b4cd5b7cd270c44a14cf631f10a64693736077da4bb69cfee96565861450e591a62d20994859f5a4317eeaa4392c644972fd3f7882e2497d9b6e3fadb2605e9690d5f5c170ee2dae7a05fb1bacf292ffa4ccb1b8930ec7e34d36a199dd7fde832a48b2e733fa29d6374993f19882afa3801c0832b3ae9323342291da48bbee37ea44374d277884ec2309d1dd20a3be0e2062fa0a16991f09daa968e9c4662cb0be11da593b08c8e8ce8252c33ba5f6c75a21cd1a553de67b28747df2a4774e94c65e69eb85a5c999d3d9c23aed05beef3eea98b9b61f0ab22973ff50b72460e929d9c06737696d41c6a9454a0c9a1a4024dd67a882e33d3675996512a8f9044642a83c840f33386259206692c94e1304621d37758823c710f394d7bd29eb427fd86855bf151e04fd735721a046bf491adfa4e466a73844597104e7419407499b9be91ecc0a20bcd0258c2cd00b073654ed114c52eeedeeb87705fe37c9d33557513e3f60d8e146e289db48d932adae64b7243e9244ea18323b9737de7c4313861840b4b2801c517805a7d443a914e52605c0d770e1ec2adb48b066be3cc961cefa1eff01ec232ddb94e86bb875316df06e736c5d5b004c2d24983f5b80877c2d480c455d5fa6ef694dd54442986c595fa9211892ab5b6760521503124f4840655e8a20a08be0630dc50f2f0742f3ca28b448991690c43a6d18b4c1faf90e9398d4a9ed992b2b4ebcedd5afce2be61d8760ea7ec630bc6bdc3298b6d8b6e53dc8aa5120de322dc50eeb4f66672b51c2fb9d76aaa68c6e4d21c99dc28a5ec2ad2308fb8428f852b314824d2189dc2912194083231b129c1e0081f538e3d4b96a084114422a571efbdac958bd2d31a4b9ac8deb54a744055634224887e712bada75bf670db28addfb66b1bddb62daae86128add46a543bd55e1aa477f9c034cb8b521bcd224fa190020d6f96415759d1a55b624b8cac0b4417fa18558dbae25611df80d8e29aaa992cfbae596bad36f6d859638d353eca1669f871657ef20702ab42f0f9810abaa88223bacc56b7b8af1475b839f440a6b2d5511129ae4452a68d6f5cb93adc4c7f587b5936bae5029dbcaa32ca31267b8e115d648e4d5c54c84c0306c61583b9f75e18d72be67ac1b85e30ac55ccd535ba67ffd8c8227ee479d8c82e71ccd7a3c196f23c7ac4f9f81ecd127177ecd851bb7da77d3d627834d83c9a45daf77b584dc6f0e8d119c681590df6bf9706adb0c28a1cdd3de2974c91c3db3fb8a1cd194d271f35d20580501271ac001d820c60a045567d2ceadd034518446826788191eeeeeeeea63dbb9b3261c2c4a7079f263e384a39f62c319243544f7592592a8c484204303ca9f72ddd979d861abac171b53ed380c9cebd725cf6ec3e7030cdc2d5d75aeb39bc7d309febd560cd7e3badeb05f39cadb8706bbc6aed898248ceea911bdaf823457df7f282ef6db63be77d355a555970fbe14aae7498fdfe61766d2c2348bfaa24c8fd4af30441e719a748fb4bd355c7d16870fb3e55f516b5c44b532f6eb8ca3514325373ca6ccaf53d82748ba8de064eaebd53a35922cf929c5cebcf92277218bb90118b5c3fe9aa59263dcdec8c08223c8944c8f133a24bccf2973474a3b69438e8434dd3341ccda2e16e1c0dea109365966326571b3824061b6c9ea661a359ba098d1e2880624ddc7e54e95ad34515ce4991b8420fd420ed2f32d56692a964ee34487170399ce812caa3df67f473e77ead440060dc89a495a4e44b13091039464ae2cb934a1876b19d2aedb0119e69350e9be7c6fb911d7d8461a393704ccd9e58f2ccb42c0ebdfd3b676862dbc9eef9d9fbd15ff7a36b3a0a86dd9b1ae5a37b6bdff7afd1efe8250c5b8d7034dda27c2f5dfa8bf41289849a2aad278cf4128e5355fae88dbae0fb46dbb8e38a761957343b5517a859681660ec9b21779374644b2b99aaedfd2e64e38624301f7ae82fed63d5d1c073650ed10fc19138589c9e1e239de6cd39499ff6d117e7d612ef207d8465644aa35f1c5bb195ea1da4df7b1930dbefb8279d84654cf8e2b7ec6db9433bb774424316985802354849a49209e5f6d36442e9e429e5744af9c5d7963eba45f9bd2d7df457e9238cf28b47275de6a67c32a593a8a4ac1775414c95a2190120002000c314002020100c870362f18040226b931f14000d83aa4e6e4c1ac9d32888614e216308318400000001181111d2b40920ba942a8cbde81c14c3fdea0a82824b6abf724bd5fff5abba7e36cd081f42841a3e8d589954911c46deff43d4a417d352a5d0bf67278edc51fbabef31ae69679b2f1dd7c53718eb4ee3afb8976666a8e4a974971f14e7bfdf38fbde0ca8c6dc55ec5d42fa48ad8d2ecca73c5f6996e2f723d936103f66e275c9145969712f4612c0b4531b223d07758f54d2fe9d5b254d19c99c68c975561f8a97eb15c2e93bec2a5bbd2d9fac9874f4cbf027ae16f95b9dc32c4f565a0d2dde3ea347a88ea53a6e693af227ab8074de3b2db55046dc750c71d88229e79b6ba4ccb7bf918896d0459cd1e659e21344a9c2c948c1f580b88168fd34359736516b624f824f43d4cbceaa5157c429c9d4203232548654acd9f60cf4d5077d4f4e1249fd985da0b1dca5d7b1915f5fb94fc274ae5616a5b25e6d5170303271e1b05d68bf326a82f8d260bbf471cbaf7a35e9025707ca0043f5fb7ab67a840b8b3263ecc7a7ddcd4ca2c30387d8b46b73f237b8df39c7a7e7683cff2cbcbb2193eee4b46756a84d1c2b465119c01182ea14d3cd3412a64fa67c286e7f82c3ef05221cea799a616fb80a57c5270400df974dea340696b8046bfadbb678cce68e7c8d00faa8552057e02b5fb713560ae861610cf83d2e4e6bf81943810214c7fd0402c44a772326ea421f35d8bb1800341d473566097ecf7143f5b041522aba2f3f8bca1d41f35ad19a653f799877d78ea3a01b13047cb28f6a8a34ecaed45ef33d6bf160c45298e1c6ce52a533d086fe5afa71844882ac39f71a41367c99d302a77f10f59b4bd36df93aa7b2d1552dbc1232add751559116803536225b4b0a121dba218946e5136d0e835a344bf0ba5a7ce6e16d03068bdb3a852a69785b99a7949d32f24b00937601115dbf53e1e5f7a7287eae0f4532a0d76323d926d91bfc7010afc08de1a571209d26f999481337e3352418b104402042636689f359abcf1d93235f48d5872853dc3f7f3ad2bd331c7cdc15c9d26996c706b6d20785c8e81f1f91cf58df09529a6e46d78a0955eed735b51fd8ddbb65e6aae25de354b86647473697135a38ab943b7235353d654ecb64608e63cb11a83e88a9c62b920735e21b7831b5c2f39f289cfded3b3d641d8e781679335c8a9079e768c77461e814e3e0021cc9f25738c7225091cf68dcb2006da4adb010fc4f8c0546d0e76c93b1b3224ecc30c4ff942c4781139cc82ff2293312b3bf47f2aefc7eae52618ec3c09fc1d3df7203bc0c850d1039b68cbddcea7fb8c622d6b9d9c07aab8a1e94e21dbda163626c5317278f0f06ca4ba80220e22ca74839e36d422158da641399e40921df24305e7e82ed435c376bb999e24e1260d285b6a889a0d7228a209187a20001d53b9d38256b37eb7b20a24fc8d251f69ccb4dcf071ea9432bf5f31467bf588e446c442d0a3fcac9456c150de2f062ac465c443a4b26f569e763cc131502652ff50963634a3b7297ed7edca438a27f163d318a37d428c664bf4e2f501236ec7c18c1d4c97aae59be2c689146c1d4d0d90e5552f8216bc9e2b6de2c813ad9c1b7fc487a7c1bc86c4d279e2870207f616f06022e5fd97eca0a0f0c05f5271b51f3d21e15cfb147bb692a72ed7acd5988deeda8b571b821aa63329dc7676b69b753e1e288a4263bd9221bbd1271b345f8a62c23ca5c946d31b0ac65ee7c057af86d8e3ae749202f030baa6ca2cb060cebcdb88593f0733d995bed518ad7b36225a57ae709c23847026329eceed3d0a0b680e29db470a3ac7ce5b80c0d368bc1a3993d949e9a83e1a4319b740b02e58ad6a0820ab7a017adb3d06d00c8ba74dc4ea33e52ebd244af9152de63303c1e2b38e0b66d317bf611b9fb039518c189f8db5f6a5502e2c9210746fba55065f4631a725041fed2511b0da29ec8373c15a5efa4bb7eba86802f5d5a1dc854bae79daf08254c837fc2b36db3ebe78d09d7950dfbe9a5405010ea4de4aa0807a1340e88284e10cb8d90a2f13935479c3f43df595b3440f2889b7f35d87b3356e3b162afe6b4927ec0ebe42392ec9fb999b4fcc2588912d430e4558d174f54bb361c4ff8ef4b163ec0e790f9dff1ed7c29cf8bc9e64f572ff7dd22eca03f609bab34fe18a4762c25593cd178674ea7b502874384956254f085b83fb3e2d7f7e318f08a01cf8b8c49f495ee913b6101418c659b00c640104ede37e2a3a4024733529d721d4003b5e5b786c29a7388450b3a641ac258ad9091b9bb5cff234c89b72c886b043c21cbddb5c6102d24264426ba7fbe73faf96e1dd2e69c50fcb430792c64a0e3ff061b0439e4c8a88794aaf6d299ee70f8fb3a79c779936d6fafa153a11be724991b0069a8fa52ecf46709a6c4435665917ec884383125606c7775c21a035430de4293ac57cbbda062ccfc23f546c2be6049383bd3f83964a411475d24fbd8c9e43a6712183b120f5009fb080eba7d0b0aa3ac2149a8229f3091a94a820c14219ed5f5914b32bf934fb7ac5f128218b94c128b2b691350239d536e907b74ac039f3f2e69dc721927668118607c1b68fc0ab47f85e79026b2ce30f14c29834ec3f14ce5fbe05d0f1e4e60c1d9a1ee42a79c41d659f2f24b0e1f82edfd56bbe680cacf94694a1760c3144333d55bc7f4d9529d5f8489e2350ef480b787f865293c5152fd9ef71c432a358a0829676949b0fbacc62b9b36f623f03ddffb1e3e91531ec8c128d54407a1e2b82880c465afa49d2fbf0fdf099a8b6807bb2f881ee22caa658f6ac1f1616f133d5ca35d2193abb8d4baac97bd1c4cfc3128866f8eafb35ca1ee82f2b005b8575bea9f27ec427885d50214f1fe6277d71b09b07130556a2cabf00ed30c9c20d0dd9fac0dd6696baf139e6c07ca531e1c8c6e1a3084b0e6e0d50ae7275a2e14140c8696734ef8fc243ed3bb27ec253e2366b99804ce1f90b094e00a5826500b1ec278068d9c5bc017c71c307331f2b332ecbea224bdaa14fa6357ab8b300d2dc81d97144029a9c1f87efd592fe367c51b3836c8ebc51fe6b8b85c123e6f92a9fd7f0dd62bcefe2b0f00a51c75250851df3e74ba4e678e5c49d88dacea588556380fce909cff8039b82d811e0585eeffc727834bd8b8dc6601573e8fbbfba51489b97f8a12d8fe4849761f6578df5ffb8cc4a5ec3a3cde9060385227f28411e8b282fb124558a600deed95789138c922928e4de8c03a82eff7fd4d05dc0501e400388efbd2b91920156622d7f214b60721ff5e1fd3f75e121ad75f76fef59fe249d860b505865d44e486c6114580aa86ab911ce832c155ddd186b5ba2279c00a40c89261e14c926b4490364d17d1559fdb6f79d73482d6b400d73fb05aa973a3fa096317964ade506c46db2aa910f91ae70267c83d62a701817aac49d2d8db3bab47cc7b6198bc75a327cfff3695f557dabd673448d45115a151138d2d23dc5a31788916aaf88f3ca1bfcfb1240e0c32ad0eb13dc1f5b6342a3090695c1a87c735bab6f26a0af94b57b5480d4c9b4e91935899a82c662457cf91a7616ff42d541ba3ea0d46724a4729dbe6f5a063af1fcd6708ca048152fdab2efc64e85f9c2f93054524e7a21a743ea9824712d23921a4a1302109b4783609a22ef39407ad727ce30a02ef619ce69d4886502ea8703104510f52d1d961f642d0212b0bc87d6833b8e34fb6f4cdd55aae01a63fa305fe141d7a6b20541e3054642392c0dea3984fb6f7b3a8deb36c1111eba7dfcddbee491bf7dcf1fb590aeab2716cd9993af260eabdf21e3323295a34bf5f9583f6ad63030ccc6e32a2025c429ae047640390374f01822fa23c72ce5a9dfbe386498e706069f4895cc518b49f9069d39b2587875200bdbc830372e4003d57ac6448bab4402224bce39b1d2268de6cfa0e1bef3232dcc66810fa447280227ba8c81694e1b55a060295b66735bec3b69929d90e8d51db54bfaf4008ea06e5f7eec487dcadd53cb657495bff8dbe03d74bad404af68385497799faba6eb2207b6a943a63b3f03c68c80f3275bc1a0bd332ad79416df200bbce6ec7c8551de0ba6939d0f932a171ce482f1de0fb926b94ef5685febe1610cc3edb4aff83805153de8ea2e9f9e5e332a9967feddbc29c5a00e17b75b7d59b2a6d53c249730a749b6540c870f18388f102b085e44bdb44889c2d956a70360395465bd0e34b40ab5c009f2896278258f705fd28c2f2596a79c10de9d6657336b44f658b390e4e4149bb3682dddd2b2fb48dab1750726bbe1a059bc60c0831589ac33f750ad1beca08f5cfcf0a407dd8c09b28fdd3d9ec31fbd5ab1fc54978bcf9e6a857bd794c7bdbb3a4e9298d07ec1c855ad8030b0520d42df0ab770317a3235f78d1281622604401195becbee5143bada08130deea7f2301e3b6172d7a8715e223bcf31645b27e0e558e5e5ebe610ec4a8b73ee667fba15728dd0e2234009a7ff9e6b96579a3d04fc84dbb5a277181fb379315dd0dd7d820afeb4cc69668a8690d493f3a54604f06fcb73e0dafa07befe56198d76bc7e67d47da62698b0f3b1047386e110e2b5d84da07ce4930f25bcd6ec27fb98c2c7e52f5a4e3922fcd05587c3fcf4649449b8fea7cd947df28f9da4f6506fafd229008bdcb101ff1ad4e0493eff08cf720dceb6852e5d40827881130e003c2ad9e54f15794eabae60b5a7d29075d40c7e9c264d7c5c426b00719a1ac3369c1fa29f1c89d192e1304542709ebfd8a15e724912936aa3cbb48ade181c70ae8b4635c3d604a9686e8432bfe909f6365c1ba7ca85fd3c424f9ccd91556dac0a137022b57cbd5615a189f8c4ac403204bbd61ddc4fe568aa1b24eee6676d8e1a50c4e4d3aed42f21d0b0aa73a806cfd3561657979d4c335be15f0579ef847107b0562dc126b454e39443267a441722ac106583e7e06dfbf9704290b659e9e11ec901f31b00dfaf26e5edec1341ee2bb3260a1872ae7b471307bb97c112be0bafc848de2b7e7860d62e517b6f7516b2c5f26493d6f7cc9f2de67c93e44214cb72c04d46277184c4fa5a31bce681153484768618cd68e147553953517ba55c0ea5867a4088e2d480d31ae67c9b6a3c6d6bc9e21a32c85d89a9d4733ec97e5390942daec9e6d357b2609a6c58f20a76b7e0040ca48d0bc2fcea5132e9ece05fbe4669e275c5cdc02de7398513c79190f3ea0d16410e7bec85e7b055beeec354deb090617b64c72f4075e5ce16e590b599ad61cd043b603f9085be0d6af7d586e7359016dfcf26e5e18abfc99b32e4915346d9b76309d25ee98f7da743adce963b25b7eabf7f976cbd9d1af9f2f46a287c8cb79ec0ea37861a60838c00d2ec566bccd4e812f0842d4db134ed77359df06959eceac428239e854052fdd86d14941c71bb9adc208551f39e3329769104e0c8eb24742735b828c2e2247d8d6453ebb881ae45ca8887521833b545886039302b9ac39ebae366307a4d9d9d3f4f40276d073282e3c51e5f510da1cfdeb6ceb0f45bdb38a64320810a8efd61e0527d6290adceecbd775d47ea2b8f51cf6d06b68516b2dc305f11b656f6c3b6d8da64d4c7741a2a6c056cb64713abf8bdccb655be03cf8292f271ec0e8a468391b4dbf66d975a8005c418b8a56bca370a448b59aa1b37294616ca10c59fc130d7187520dc90a6b6864d2b7432d4ac0e3a7c87853c8dacb90c9630d7c2272fa499214ba803da96f7aba412410cca108698f74e0b2513748833427eca73a3e79ca3c54c6451611367efabcdd872406d8d3b28abbd91ab70c0ce1542f4464e957a59993dbeb2518961ee07201170b1049a010c407c01d9643bc42948e676f14b6271a416e05cb140832cd7601a2906a16876605ddbf5228a00b78efaab6662889966d902bfa16467ca55db9c9dcbbf43fcf4ed74d7bad523288f494f1c3dab4e2422c0ac4fbfc7e7d8cfaed6f97981546c5171023e460c447414c1bb1fe1807374da41f78d4240c54885655ce55fd4429484da394f1f7949b0239512fd02c2ba92398bc4d7eefdd94fdcd14532eec727be4e5c7bad11381c7c2544a7d9b67a5826f11b1e4776aae6eb636c2d0bf32ea995bdfb803ffd8a7a565e23587cd66c3986ae179f6b129399f286aad7e4ce26efce8532c01e85850ad58f609eb6370a7dce18b8018c85824f37e545b95df1b7e04638c11546c006ba5c904212833b48c0caac3a21e367370cc100df488d20e221d1c071e06c16c28682b7a877475b6e123dba7c4420809d3747b653928c2fbb55a8614be89a5aec4e20b36b0430939971975ba923d92c54a8fe760f14b5d9e78f6141234b6507fa84b06c87f47c7939de2dfcbe6f910c3d056fa4977b51eee5781c4c536ab4af17fd623b417e3be4c567f18c29353d42534ab4a460b55be0bb5eb85295b16697499d165de1d5f3e402d51563c83a3e25503ecc45343253ef75d71f358bdae4fc65dbd7397c8937530371b34c803d3ce74b464840b595b84ca08671a610281fe8c1b3db9ff89387926d21acaea6967ca3174cadae1dd6585dfb606ab396b2827e0a57195524ff9a1326d427964a27fa8d3dbfbff44e550fac481ee644e1d89552af309c9efe2cf841d2126fee500d5802f22b60411c899e14b0ff836ccb85429ca8a2050d4d623e691184941ee4afa9e29ef8b865110d6861c4e2f305d9a8351979f4ebbbe759ee0cc9bb1637a78285897fd321ecb937ef08cac77666e5caaab72e2355b11416ae100b304799f5d416e59066edc0b833c01a3410c1b9f04959a1b62e320316a9268d7f1774a215ff21b62ef2896b8353335a32903abd275760197aaba2c6d8918d24424eb0f492315abf235c01b1a29a8b713d121f9f32e0d48a952c2882191fd836e085cceac673cad2f847ff40292e3c12f2764d29c4b2931f2c2b489abacd2b32aff72b1b0c58d242fff95c88cc99bd122d147f6d6a270403c0d8569dfe492478fb051fdfd5564286104b78c1c9155c048000d26276925961efdd6b8feae919f1a5de380f474007b4f9149ebe8bb5e229e4fea7ca54e11efda06d5ae5b930406e0d8a94c16bed42ce73e6d217c6bb5fda479247be06b8fabec7b99954952feab89ca34eccc4a3039c527955fd78f12c85f3069a7758287c57c27a9651e4304e07e4acafc3f6b56152fb7f5d0484656d3c378f5ab38346e70735de0461db6ed4d491f9af1699a0cf3dcf6aafbc3b7a77a053433abc351a6af39d59fcba3aea431b19d7571ea22dfb11c71321ace3b8c37fe23c874766ff44a4320a75d54130d80ec7621df0219b8a8d3e116f5e1d0e85a38f0a84c15dd40af3ed4796a5291dcdf7b012b89c528a348a06b5f9db31b4e18d345f36ded3be82a879744cce0847b0e13fba15c013ae892f0ee8c7c6840c1a5ac7318de809d9c2ea43f2e3a5136e8858f82bafc7b14ad066120226191be7ea480658ed5103c85d3224b110359236e647d5163f2e2f9603a6851bd367e395c84b4898196faabf63eebf1e4314493bd14f09eee37c4f42b4b86de4afae186f5b5d75fa5941dcb0ed5afd66c7f4070ab0b4585632d3c0e8de767d1865ea03bf397cd50e4fe0d7e0203a00b656f2003d3f6f591ec2ea1c6ac7542a567e39c366ef52ae892915081e360014adf7a594227c8f4bb03c4371343f4e24ec34bc23ec80cf1e7db1534186dbada216d7b9cce945e87614222eca43e0e33304c05939e44f5754e7ede6ad2f6268fc142619351163e7b34778a5c7807ead0695d07113e7a11c176a94021c3ed9d0cef3e4b274ae293aed5d9d3e9cfc45e35f5dd2d4b4ae761229b05f8c81db99330c207131b319a13d527980cbc82cb0704fc465ea75f02c4cf9bcb9c320a9721e27a4e9c333133737412cf8af2b3692334d3c4a0fa6b0d6eec86f69c1f88582c6d7645c9cbec53a8a47658ec3e1de06c9cf5fa67e4031e6db6895b6ae9315f67339fa290511850ffdf64f1dd5ed66c08cfd53fecfda9b66c7b49d9fa242a835a9da124ac62891871c1fa5be35e0ad9eb2b27ce3cd42e767ed91e4486bba2ce72df8c112bdd0b79b3562ee5f531d0f01a97f64238ea8b28f054fe4f37b6ae859f56d17acea721d3b7eac6f3d7a85f2e8930bf1856b8ac75cde72eadbed59d53f717cb8cb54c56589f60c995801e94391fc4724e35f0551e3b301f17e40584ee415819b3b7fc12d92f3429c3b54079acc852647a023279c2d036a6e29d480618a9df651e150166a137efcc2e309c3f72b8bb590cad436477909f0b8b0d94b9e6c7e1d682d248d67403c55ce1ca82ce8207b626e4ba6d737a16c7612a61e93984dd6c28a46f281fb34122bcb7c248ae39207674ae287a1f79387df61395cb6679443e482493926bf10290ff5666ae014d6b82b6bf139ddd89a9e34460640b3caf0b70485f4d37ab6ab6362429ad0c8658b76b900602ae8ccad4bfa3582bc323ae946d1b75e44d88ca86d0e5f637a6150882ae0f6aae405ea12d6df77ac663e28ab6e63ac9d3b8082c951d2f83df4550f2e645d4892498c52a3dc023f4bbc5500a3dd810a382966ea97d0697cb4fbb338a4f0b078f367ba4938059f5ed83a54f39788bb8404c35309bb49943d730237444bcd1467f268d8c83c6356bd751820ee3c9c576d3e538d5a87d63e0fa4d35ec0ecc6c08976f9c768e593d7229d4f3e4670f7063698fd873ed5712c0bbc2fcb87a08c432d3523798cf0119d51270496dd5e2fe3e56132962dee12d2c2f3c8f41f8fb29fc13975fe24ac35d696fc52bde035f4134584a005936c80a4102fb56d517fbca6b689da0b0cbe0652848599c0737597fbae03741fb0bd756fd40ae849d8c15ebbdb1adcfce40091323cd7f0a2d06f0fcba69a35c0db345b3170d6d03b7cccaec060b39402f8ee244c649b2523db53c25b6b4ce6512e08d2dec88ec22b203a2901ce5f433f6748b6aff81085733a1174ec4a3c55219f0962c00d8dca47fb4953f768e0a7b45f2147cbb8fd0871a2f180d82af43d00b3cb0b88fd63ec21e89e1e2221d69c7bf8a01cac477750127a4d4e99ad4c9bb999ef51e493b8c8e39c305fa0b86284dcf6c1e714c40330316d555eddba7674a83d2bbc8762a22f69d4ae2ff64381a2fe68a6a2e07871d4f27a9df04aff1ee0ba714262ccd301c7c3e4f18ec3e05a0f9d49c0bf6bb287fc7611aaacda61533305e7b488d4e03701f8d26632847e523797198d2ee4c8c8865cf1876e9b2bcfc1cdfbe6271a231922616a2aaf372894f6f30d28b065e3274f89faf3e02a24b0a541f3d5995d509511d0eba57da48e857f40882b2a65683b1a48d59bcd823f34094b754365c2db67dee8857b277a206a21f42de6ed2c55fd11ffd8d665114c780d8b7de7e685dc7f6fb36b05db99afb5fb745d74984524677c6babd41bc08b1228a2288dbc19af134abd271d76de955e0c5f4aee350a12487ed1013310a72ae9bc44af61a650d1a8b3f006044ae90930423b0b45a9d669502b90bdb098f9b4ecc5c8622e7429a0dbcef72b0cf84c865a8e938138af67523985787f0ab9b97da16f9cc888beafe8823e0a02b8b200756d81ee15adeabfc0eab9e6a3180a6f7c7bb1dacc65de75bd082d13b1b5fd055c487c6f1bc423ece879ee7f87348cecb87b6a8513032635bd29017deb751c9e08582117b880f6c355db47ad76de14a141da2bb894063cadd5c70520ba0015b286f61eabed0d88ded949251b40a1a23b151a1877329e86cdbdb1310936f05cb4550e069192a93af62573c4b708ab221d94210b874e5825bd6b2c52e78e8644773420f3759c654ba1e5d258ade0963191b5a1dd2a1ddaca4669666deb77496021ed3a14f0ac93b0c7babdc59789ae8a7280149a8d38d1ff581fa38b94c16ee8654ca1b6507a9a2b8b0bbb06b58d49e109e2d9019766926667e3fb0c2c2a41e783f7e9eff953e86750555e0d24aec890e9951583924fe18987eb161cdb84b13161c8d41caadf7e0bd6f64ee815053ccc00bc967c84584fcdbe49890a747cb647d014d48deeaa024afde198581960957923c48d94b32e93af7f9eecf7c635c68c2742cec1c880f20207dde5f8ad586e55d6f0987ee5b2519fe8cef1379f8dce8b39a42e38889f7e1e4c6aa3066b780d7ef584c3fba1b54cb268ac10ea5db8aaf13f1ee2136dd87325541233fbee10f25b3d1515bfbf8ce2e3c66bb0867ff1ae219f8805caad54b0a3191ed46f7e61d18020c3c9d8f475d077e188218459fd796c46b7598899898b03a0464140a2154bb93cea55f60d6d6742781cb0494b0954483360abf280d7460b52d3fe84d95b60ac9ed9b977cd6b65cc9cfbe7b08dbfe3af58c2e8d8b847271e0bc4542c1989982a0a22f5453e0852eb76d6eb362ffe82e709133431e846acb9184fb4f44918fe97389528384c01f81eefc1a1fb7157b3b864a2007111d5fb554a6d0ff87097af4ccca2db136b7e23f79d6aaad245ff998800442ab84a424ba24ff38599655418db7c07da9376e5a474a9c7d81668f8acdbe6e17c3f49035e01954d57538a98ad3667d2b332916cedefb47e5202d76441e6acdef3c748ad0fcc267698327f32b8331bf3234590be98077ff14537119c4f2dcc7f64c25f2f76bb187dbcba8e5a227b4f41d43a56b6449279adeca752e449362c7d0818fd99a4baa620e7e057426b15b43daf1832c4219959dbc6534b6667d13312c8ab12d38f7f5ea7f8b69498eb8abaf8a716db958eb8706451414f956e505758890ccc4bcdb44e3ae04d1d2a21603c53367a9e6eb009d4171bba4779cba21816fe0ce2c371dbb09f018c59ca15813e0a04119475bab3c1f0d3ca79884a1ba3d8f264367db973ca699a26bba920aeffb8c98d4acd309a8eafc04f52a4f5d4ce1adda7e0dc7d89e759e2ff479463e34a5676f56f796f6ad4e5ee454660dd642cfb5a874d4886a402ce029744bcefe5f81bedb06b1dd5b1f63d6da35bf22636efe884ae42582bf46baf6e0592385a31c853d564e89ab538bc12ed56fceb7dfb3e037b93d70ae7c315edab48a9c561ccd9dc91955660d371eef1548c88cdb8acb9fbe5ddc4cf7e4f461c335e0f8a3e8f2bfa8e3ce1227b17cbb943fec9e811eb3be16b4bb442d3cacf352dc9feb05c0ee0b3f044dca5477f3994cd25088209bf36fdd82424d8d695d0c5a722aee9ecf28c352958b2882a901e93c4c10ca49e7973e17f96fd56b99efa37dc15a2f45ced1cd63b972b18c1f1d7a7fb6dbe4e483b91a6d842d8e141f3bba1277310b41acee62472f184d24aa2e6423a3943c05e408a20231099174373c763e690950b0ea6e31075d414818c4536aca58f98f5ebebe3488b4a1ffd1e023ea9df786666643d2a4b729f0060eb53886182a9f03435cd75f318c2549a79366761dddd71ddc21d5ff01aec0c9a33d4fb649f99759a393764df9c3db4119e8d73b53dac303a8ffa3f92936ca1f4abf8d0629837090a863d85775d3d4e26e99dcf03cca4c9cf32c9d98154e391b6c5ce72f28e912181ee7fda8046181f69caa360506644df207ee55e8a17223bcdb3719518dcbee8796a0a5ca43003a757a841e88563cd4b72eec2c62f2b081a60213e25b810ea0fcea7dad26861dd7ed56c98767fb7b5a5a6aee612b843a9930bfe15bbf25b6c2aecb170361c67faf22a5066ac01b1c4c9f416b13f4a1081604bd2054f9e46363b67866577d0c621046f7188ce6397ac60844e8d8a818ef1fa09e851958bb252381b84afc7f382fbfb9d7c857fcd79fc8acfaa2f78f88ce3899e0cf7146b5011880d1a1946103572b4eb3092ecc77c4d744d03229a4be0599007439da4ef36fc69c5f59b229a46e13c616064829997155caf03bb0fc07dcefba8477adce1d668edabd14a708fa5a496950148901429609dbafafe7d6ee9432376415a9d4ccdeb11446da6a17bfc3015c6c449a0c9a371fbcb7b24c9d75757ffdfca3f0c043d91124c776ec3b5083ff0cf93448ac917acd9ebb2bf44aa4f5d78b138c50cea407ea53887ba4c162dee9ad00aa1e7ae861a8219aedcade0f05b14374f8d12cc7562a4058c2620308902948dfe6099b0d6ab962ca116d6d97668413fe562fd1a6308ac0f25e8034d8366781757775c88417709273b14e5775f4aaae8d7592b848a2eea62cfbfba52884742dff83cb50b1ce52b31c2896077430c9b3e633e9784b6876e32d065276df0451a1d32c0cc6fbd87e75b93049d37e6caa0fc6ca82250742229863dc0c0dd58ea17249bd06bf7856b3e28d0f5959e9dfd0de7552a892821c1e9cebd1b54aae2bd5adcc79d6937997a086f2ac7e8d1491a27ecfa0e6bddf443b797689d04d576469934cd21fc9f80e65b1c8100fbf423a0a1ddf908dd24ff14bf8f05b9fc8506e4b8a90be677da9560c2afc83de491cc4b97f94403abac0f0a194fe64be626019bf8426dca240383b6b8b7f8ee2d330d5efad6939ccd898bd0d0d8e0142389737439d98512164a7c1a6882194e72292abb10cb6590c0ca258fc4eb274ea4e3c342bf379927aa4477b962f150394ea6832831c8fccf69a5d8a0b32128e18a4344f1551cb06d2950222ba23b1c8c89655dddab670f4846308349cb9c0232deec73a8f44e26fe46f03eb45e5818b704bc967528a9e3620ab508089ca2b9588d23a9b664742892c6927e758dc1223fd388b65fae4fb55b416935de3d050b654918b8e9f78d91b49b994a69c179e1a2d80789b4e1a70843111a8d3bb7350fcba57d154838bbc1dea4f9159001b5bdc71f35a629f69448d2650fa0032919423aa1ca27b606a6fb4256346dbd0a60e3384f5bc9e1f177a4205e8be892ca8f6919246029471131f4efa04f69f26a3d23a3ca07a57a993acda25b63457e1254400a61d9e4e5cdfc13199bc835bd22a848d6fe05801ae7b8fa8a10b30bb7d9c8e4cb583e8aa5ae4830c9f14b933354dee709f909c1df1c744e6124d06a7708e5b1dee475f0a2c06719bdddbc88e4e43b50733fb956e4033bddba17c3c2b66047f32f304e54f56db386d4a0d10e52f93b8440a164719928625ef4a683e9666a56b0320717c0f9f14fb5edf9fce986b23cff84a2aee5271ce5f9798bafa4fe6f6c7e7812711692e83363c017b946c0f91d6f8be40eacf2fb827bae3d54d6d4f9387b8e92f3f82a1392b25f22f64174a19e14149a533725048908b6292200567ed9fe2010c1a7ea3347727ee569d472d03e260065991e26af101c251ba23a7d7480643295fb203d5b7a3b3e6e25af36a9c47ad7b9c38498e771dcfcf31574b8390c9191075abab3f89d01bd559effae6fd0c75e488cfc6379b8bb0dd3be1f5374c87758c011ab5b0313a0b34a32375b190eaea9760f336c664952e07beabfc838b9b8a81a5c420bc1d2856a83b67e6ec93c1b6258aaeca26b04145cf218cefd7b613aa83e3b9cdeee9fb3f1f228bbd6ae65f874212705c407752a0b1d740caae552627de4ea66e87360a180e31827b7c9fb0835d9c7ab168706ff865dfc7e1deb6e85d1a544baf53944d11fa0f6cf35c6355e202dbcecc76c52f3d188a43db6cc9dd73a4f8469a824b196f62124d32370f5a85ea45c14abfd037b752383cb7c5ce4725f42251b4ddcef8b6ad07e5449de1e58cb0fe500f6251ca865ad36c08340110ece19144bab4cece6964cfe2cc3bd1d29d1f193260ce92e734034630f2a35dc34103de3a7dd0e8b8c03d6edd8dd277ab4a7785710528ba32afe6a9225ae4c188bc5ebd50634fba8cc59ea7aaf3c7d0d052325daa473d2871e2f3161fccc44876a1c79595f6a46366296ed1b0c1cc49bd5cab8e05f59855139b602dbb0e1825889b2315de3594e6883d720db5558ab61b58efb142ae4c35b26a14972fd034ce7a9c831207f2a17aafe4de3d0bd1dce621babaed2fc8e1f561660b9626a7902a80d0ea0867508c9c0236c2900dd38d595b3d1c5e5d787b3dd92a23edec5716aa1e56d28f1987b215ce02664fa6b212ac3c842ebb7c579b3881c61ebebced8a06acdacb30ccdaaeda6ea8dcf57cbeff0eaa54252f18709be6c46358d9656054aebb848c7cd1b53223f36e94a5262215b004176f6963f05102b736dde71a69ffc688758c0961515525228552c4f630ec468399d151891721bb00a3a1ab5a92fd29ba2f3f465784c904adae0b00190ca8b0ff5cf003e63c258a2dde978f139c25b7f591c064e854521d02336fa3ed5953f9e6b66795c1a3c58affa386f8e752d4d57b8b57a88a4bbd31a297bc82da93217c67f803278cc3b8c6618154445edadf6e512e79dddfd81383ccebeadbe3ecf42e7ad28a18880963254c9e661bff80a7c84f7d7c53aa7fe71afb3c5004ce2e37ce595e88c642599718affcbf64c904780f035931b5c98985693ff9c6403a2b10be6750e6eebc11867ea182f0134ab5bb5c79a5fb7f527750958cb0e08229b4377591d30f91d1a534ff23e87f5c2054c11a57ba12fa3c2b976c00c1346185f5ce14de8ae218266e45ddddf98344364f4f214178f6954bcee6855bd3296b610e0fb69c8bd219aad27987fa31879e4743006e5e0f92d6bd15cf2f4b95fa0d8b7218ab21647b0bb1c0b83fd16ef26d9148d389bb09c5963cf9c9d4f6f539d827fa269cbe81c815c4f0752eb32d86352ba3e3e0427b78244d1e360c5504f830394b40948ccc8686a6578759b6991a4df92984876467262e6636642cd55877420344bc6569715e12071e692a7cb22711d90feb500f83d3df3f1c32f2183ef4fae32de6e8afdcef1facf6bbd531703d0a2a8838a503aabeb506bbf9fb87e2836082e1c9c55b0e5c082c0005b62a7778580858ac9d4d82171888b2c605d24b137281cc4556faf70d786dcbd9ecb11836b15e5fd7ea078399ddbeea4c4394fce1c704fde18a3588ba080cec67ea2bc3312cacb2a500d60b8e54ef07e95b3ef689ededb284e8c9c30b587443c77a1628cb3340ca7796768fafdd32442bc2b182d8c30fa54967c312894179aeb37e6002bf92f76af8adf5c12a0a43a7b419a178ca582d4e7190fa735411f01b8246ddc10d866916bee3dc55b59e58facc2713350bdeec614c937012efd402a99c5ca83b1c801d879c456ec4ae621d58c01d65680e52329ad87700789000a5c802ec7734bd7048b6b03fa009bc98e4a7eb2c34d3bd5b811042424680f5bc6c257cc32726f24995f53cd1ff4c746631f090e60892fa7b9e7d1f0d683121e2fa89b09d8594974064b33d11a9ea517200b2d570355eeb9a39f8cae722f970053879cba5ffb90c551e72adaebbdd15fefdfa0f3cf4e04ef9b67f9fab96bfb5d72d6cbf196fa98f1ee1e878ffa145c9bc4aa3e411954494aff8b80bdd7049fb3c814ec70dbdb414c34db693d6f5787592a0f1ebf7c1b89bfcb3fff936d7d7cc07326a52a57206c33ab8571101a11ce9245a6196e1e5f922edd50a3ad03b8e36fcc21667453c4399b0f4ee39f15550985c911cce8d26cf7ab1b815e7216a8e96b8a812462207f8a51e9a54923138a0ac220bd00bb11ef91e1e79f53ac8a70783e7a6998680e36000d002d53ba97fd51a09774f18d9a4220ce50c39fe527ae1024f2f285848ae29af638a1f5eb056305609f5e15cabd7b90f15442765684a010cfe570db9ba66de5ada9bdcc9456a3957bfb48d7f8051ab2234dcce2b8b01ae557c182a8e9500d4867951925f01016cd52046d8325f45add9128200fcd952cbc13230d6ef0563b0bdaafc71ae3c4f3f6e68d5b873f164fa1b479ae98428bb1e3cc034dc658b8ea4980e0fdf7adf91d61992d50a36597734fece06d591028ac47ccc25d7d988101e6b5cb656c34e362af5094e92c20e0d1f3c36dbe2f8cfa0a84372210ba20357e76f18e47e3e4006f1cfa400d087a61fcd2f101b11befeaafdb2994576a78f75839b6a69174175af485abc0e0a6dd81e12377ef180101d3f6d21c36eb58ba64c26f12a1d97c086ca5846a36eb3462bf35697fffc9bc1b97d0266f85c8118dc6594cf4ca82fb8405433583610c50642728ab66df25b1bb94c5efba828b7df6eeaec9530cc9ea33106e18a71790e0e4e531247379efde8299d39980e50a9176e18ce6aa82ff11b5c7f1694ea16294f737bcff2a0d9b4b26bd39db9d4961a32210e5321c667a95be90acac699a906accaf29ef36762e878789970f13fe6160db446ad1d868fc6857e68ee66d6d085b863ed18846e55e501a8aed72dcf5f08bb7ff70b48e50a144e7a037d214043015c69b0f18f16fdb7f9166dfb55a68480567cadb4fb21fe84559bf57e35285b43e3aeb1e5ac4feee183e701a834a55b0cd4b2f61eb9f37ca8a9e1efdc97921304be01b18e1d8a2d50f2c7978d090590f5c8ad4ace6b78b551e65cea365c8e352c5b4d6ae57c5a32e6eb632426b6e6cfb290198222b29705b4219c632e95124ea3d35f2925e45358733ba4ad75a7490ee8e77f8c623bdd3ba5a7c054e922fb8269e684ae154ecc668738bafe1a0188dd3beda462d254bccbb8187a9cc0af38f7b86ba2750b4a83b7a69da5a8316aec1db8a4f1fae550f37deea4ae9d47ece3f63fcb8abd655a94e4a13c3dcea1c662ff564e18662602ee74df9841be146c1c537454c28c53f4ccdac8c632c4991e8eacc8671782fec92f9b7d2495692f01880d715eeb4be0389c94533b93703818e330155076f9aa9be168007635b1f526d1ae5c92df354b5595c8f6bed3cde41ad916a3ee440ba1b65a93bae9994c4f8e601e079493963ee67061874ed5da40cdc0dad7247f68596979ab7105188584309ab480e699430b5a433b3c3013fbd4a1103ee8b570ddae0e9bc2f4567a94da0d98b2f182c944f3b919caf8c009fb15b91057713ee370272adcd8199de644ded7c908803c28b47eea19f486e21cf39d0576605ad7018612958263f1e672d044026f20eb1998ce3a4eb5704353e56b9b34b852dc948dc9bdbf1e8ea0a92a11c0e69c1ddfe16f39449f730681897cab56c9ac9b7d010005b1a93201adcdeb8a75390c6ff54b5bde37028332de40ec70694ce8fecd780f66c031cbfd4aa7c7d4383e5db1d2451baec921a76bbfceeaaee1530d7bec19525713c63f37a1b18df145dcbed6e981d600a6e1ec26b540e92601e841eb7114379313738f413fbade80b2f501f9bea60d12a43a045780cb4b373aa6d610e206ca386b99ec7fa1ab6681a9320bb86402d6456a8866ef352efd816affa080c327aeb164b11c3a51c467a5c78ee303787b0ac4ff528feec12ca3914f778d57b31d8a7eb2b8763d95fc40662d230d0b38b0e5054c775ff232cca8182b3896e6c8d1a2deb67ef93701b60768ab267073c7c89a070257ab1c771f9859c63414cb4f7b00371efde5d423028016cd0110c06e83069ccc4b26762deb14628080bf62b3700526069166038d95e9b1b1124775efc20bab823a52505ba008f3be66d99009d7730983766a9101f6ec5da1c69405036fe5de161db26d6ea785083ac9114148221fb14858b5f911a561296961b2fb232b0adc013b6802a2df0a766aa0524007f932a585782a54be574ef37a4db1095cce6be681302874a9fb8b1f992e2e0fe8ddbb4e84898cc168153e21d70f2bb2c8b9492782e169a753d9cb525e8d49a2500d34eb0a2e938ed7307563d48b321749501595da7af439ccf5861677e3b90632669029110ba5d59e2bb4b6f832425830e954a04d994421dc8a739c9878282fcdc5a928e20cfb8498b4687f921469938265809e04fd7ad21a0773a96e034b02f066edc0fd0afbd445f88487a72973d333ca5037a2d9f90c5eb0619616dc4c575d80569d9827e26a277d841586f9eef6394a325b5a9da5816b0690c558aa29a1331c55c38ec713216efbfb9322ff24cdc82e4d4034b3d65ea8c84efefbd3e5b116471a9920b77088a9d898fcb49cf8c4db764fbebb39b39d7b7b25b121d7ef7958930de12ab652153b0e893673c23b12b60c96f8a7c28d0ba6b5fccfa50594cfa6890e32988cf4ac0cd60480a57a84e4e25f21ac2eed7c9ed841fad933e2777f7f09a13bcf80988dae86dbe877d4e2e6d57c49d22625db425d9c44611310c5f46514c1a2c0f6b61ff1620410c05dcba6e427b9650d3baa8ab87e031f5a8cab39c1fde0be43302f8404f5571e5af37901145875c1d3fce05d7f777e1ef2f012850594b004888133fac7d0e4dff2b04711364bc49509c2f7e629b3a4f991497d542efa31b4eab2e0625f9d3272247e1c4030f9a19416fb5935622bcace9f200fbd6b7704e655e223135a99f78ff664764b0174a824c4ee3b0192c2768094d7c30fc2ed5f70cc6ab68fa1b493902d21cad675f0934c31e77b79fd45011bd0e6c6fa386f39f942d62ba5adfe773eb958318a52ba4c81e075e1411f7538ae17ad9d89d7f6875940226f6d00f823a9c58ef23480e25949414a5f090ccea2542db643f22c2560e906ce76684a618e231164ebace175f8b31e3bfed98153775b3a2004dc9314832d5ae47daf51ee6a813b073832949408cf1ad7cfcfc7f51cd2bd4bdd969751863183fe118995b7a268f35ce53443b6e12cfa4bc34c084e6d3e9215b6b51e477cf5248998da802478bb3192781efc22bfd2b2f85fb536a2e55e0295c094f92ae205a15bbf77e709b5a6b8157832c2d3e67669fb054c1f37c535fccfa7e409f4cd81fe8fabcf52ea3991ccc37016b661ff5bdd1d362ecb0d547a4351d567e1a839ca9e3c5bf27a9769528d86762e0358b7cb1b5a51115ea31c2afa086c93865c2410096e29f320b21f1c0887f25bcc50b320934fc9daf1d6589cfd66bc267f77d1128003c18b5c9ac345e883ac5ee11c5c41f543df29718dcda23807b1736fcaf2613003844b709a76c35d89173668af77459416981f036830aeef0eaeb1ca09d711bea22350f2a49db81dfe1b5a97886d6a15cb98190dbcbb877a3fdf629c30f16a6dbc2d674285f746fb1c2e4dc81f42b52f064ffb8a32da578d4ce9b76abef5a91947760496d1281804ab6f5bc079e19f02fc1ac63f76402f7a01beda48a08230a9dee6de6b8c8998cece6a4b3d3a37e880dedabe170153c9abc9541140cd00b9be5a0678cfbb72f268f145f265eaa781c34e8572b96327a64fe48d57827d492fa52f48907c0726062fd737640661d835221668cbcfd44c18b8debdf7c4efc016d4def3660e89921e037c27c7cb8c350741ccf2ac9b16c7ec14acc7e4b10d25ebd205d7728224187ea93867da359a8a6ad25d56a6e55c9b56c7b5ee3abe763d6b672725238c8c6037e8435fbcad8120f61617690bb2c454aed5e3c3a96f7d9c09342a3170040ba6e8d29021c70326cb3b8187e14c9aa1465b010a933724962ee485d4a46e1aa9d2d34d485827f3cfe37039050029d6d9625888806cdd36c0e1735c0ef6da4e709518ac074949a3c299b54168abce3198140d1de4d1bd92e48d59daa82abf6efe19c71cbc62f58b4efe1290d3e53381f0fe6915aa39492fad9e830408fabd9f25f0aceff1d41e9f51670e3cde28d1f89dcca8c1205df05b2e6c49ce41a81a9bd1907fb8fd2827f41952e5cb779f1401f3893b6a09bd0aebaab5b136590235e02f74f98fd49390757d8e55df118b7accaebeff5e707b4c2dc06e0cdf03d6444b63ddf3f2b7642e585774130b8433a322f989b485f6947a1e9f961a9dfe9fc3ef02228fa1586503d389ccf054d5c5c75c3bd96e065180487783ece3d78f79fd925ddda2c371ffa5fcce34c1e1462d54090d56ad53fc0090617983fc9778893d016ffdd7d809d440149b3447c6567ab62e4b43a90c784f4d42c777dff2554775e325d1c3100bfaa1bb997aaeae09f5c8ec8418345aed6d18de9855388c3fc992e3dc70ddebbf76cceb7fe39883301da39e36de59900d16d9db725f864746823bb16eb2820f1f6e4f39a3026e90d14a0f773fe6ff0ee3cfc8ba0884e0fed0e24c5a4f97c6d0e5ed7e07606e06aa4d5171cb43105dde426b9f227e69800a77f0797874bc401cf356cbfc83f8ff46cf1a38163d58199403ff40ab0177d994b63771332b0a7adf6674aa05b720dfe350fe87907ce62cfbe711c34b75a3e6eef46582058425ceb36c6e28e091e262054059cac5b54050ce32e8c3174db761ab30fc66972d95cd0d64961633405807e0d007556f5102dc2a49007832771b84cc8253c71bd62b07fea9e4772a7ec7aab58b23316faa9baac9a6f32395c986bd4398077f13cf5d2c0ddf0e6ebc469f46eeaf22f1e21714ecb417406a1b90192da3f1d4495c24cf6ffd5d101283b4649796ce7d5a802891d59ece54cebee724ea25adbb4f35512ba0d03570b1990b77c0578cd3364b7e51def8863d4268d1d6f3ec90d2bab2f557233d0d94e1a364474485c72e07cc9f90dd393aa587200c7680cb7e0011238712be6eddae7d5658a5f87a60432fcf767210978716a2283cb0220e5f9724a85107dbe64019e2763722dc8c6319909ccd96161512e216b137d044536ff5eca2434182c31c0662e620cc56752162d5b3fc894812f3b6eb862b4d7b8da5921f73e5d03dc8599526509cdbda1d6e8d80198018a5a91665a9d9fa7b3e841b769834d97d49932971db5659070201c4116ff76a0ee14eac2ca39ebd5baf84eebbf3cf8c2e3af8bad70d973f1067d12744c4b652ce27c2c1b80112115cdca62fff9e27de482a5ea08c6a63b633c514c73b3b52aaa47b1d79a65ede2f58f5b8cf5caea9070050d4159c71c0b9a4d6b552531ecedfec19e61b69ce0591ff82c6197f73478eb6b8fa7e62743169c92b5dbddd52c185029dfe5b558c7af6c7a919dd947c7492798112fd9772a62303014c62702ef28846a4279d129118662791a8ad1c157b9095dc022165cae6f190824e5841cab8c67a9ccbb432a5f18b8d2d3c89c57251bd22d4b62e4865c1d230c32b4b81b825fb074665699c8507af4c97bf4582ee10a1829b3994710b27e19cc96a1d4a8b8385e9b3b95b13694750eea4820d7917b322e6817dd048ef06d7bb21069cb5e5faae526cc71d9823d58635d49cc3221eb57db3aa779b5d38d94c87261048282fabe0afb000f5c53a3ffdd98b3eee06d37c8536e50fbb6b54f197a94bf8ea7ee7036feb187fbe2dfe1cd57637a54acb74ba3bf009e1bbe308a2041c61584b1644fa562000ee0320f33f50d34ed1900cecb47f91eb82a2ccfce0c8707651e422e913aea2ccee913e8ec318dd4aadfd9f687c8d27e61d30695ca6599c07f7b0a8c03d2f0f4859cb69d082462aac6634c59928942cbed1a5a18e439f5e9a3e8dda433d092d38f4a1e2dac01f36cb7cf9e0ef41b21cd4e9898557d15c1318a884a3090364245b86af30149a19866506f0d5e80d8f946142bd4930761b994c6fee386a891704809442f8b43fa770185123c9dddb3918e6c9ebfae5adfe866f66c0627553982f7cff6112636462ab2aba37c4f6ce5cc77e3570354785c2436e49d1d774ca2b9b8299805896a4a88390ad8d821e0c96f8efe651e4f7da2bab403a1c7fb3c74529390ad51ada3c59fa0b02bd22198a3ea84e291957a0554f22948ae7262f74fc312b1dbfe4363a32c04f7d126561e88d0806e2658c38e83d88ce9ce88bffefba70cad88c090f9ad9c9f5c7f933e80b69862dbf43bfc3f0c726eac154eb71e6a8db358a60670b5a310b6541c22c2d81dd250fea72f899a641570219215d52145c703d39008b6e5d31775ca33c57db4818a6909f69ec5ab55a5a6c680775d281c593cb21efc3dffd4a1b78519a893d259d525ee0a9c8e980c9d339c348dd0315746f14b1d2276e5b34c83c60be9ee5bc173c5a7ef69a5fc66a93482a6cbb45690d0ee970e577ca1998c614abb5f35711e00bcb9f90fc50e84b8e47cabad62526873921bf58b5f8bce088c99cc48a377114c0699796897242ffb2d7e2ff4e334cbc1330d3ae17b92e004a56c937c58a6a44b386bda191846ba8d140d2a09bf46f374987d330d8789607a353f5b84bf979db1fcf591174074e6fa06141bc046725d481b39c60ecd7d1a5cd9246f3485719911c2e8a8cc71ee9b7897ab385dc5836d28aa8de7da5b44a6b16545267a718db680765bde65630bb513be1fd796097da98d13ff347daf38a8e535035682b3c530fca9438f7596c07b04ca338132899c851a09b0f0b9cd22807fd9ad4188c16b68bf28ef36a1b1942d474886d7d87518e2bb7b8fa8cabf6ff95038f39e724b979a600f73526f0bcbc59155c609ab86f5e13a009ef1c201616d9f3dfd08816988631464ea60baa276b8f114a8b25d11aa70871de5928f7c6924e22bfd23f8a9330e5144f429573b65d72c21697a070924a2ba0c96fb84b83bc369809b41dea790ec0ce2205e695cdf5e74f53a268ca6d222b21b134638ff7bc1752482f8c47c3bc972d15be545b56601eaf81b55f0d0d3c1eb7aa26dcaf3831ed471bf02cd247df61dd4a6919688ff15bf80b1f16f4d017a30d7121fccbd875372f28d585797202fbbd9cf499ab0082c1dc4cb12303689fbfa89f73765943e4e9c8615c9ecfbcdcc0554a06fb192ae3bd403e834b1adfb0fbf1e06e4f8e921afe7fe707fd0ec9aa0150249c80dbeadd8c3b00e409f83501c10450830edcb9c578e443ed9a81130731c15e41cc04bb00d0c19e06d28f873915cee7b67fd4bf4f1e56fa0f53a127d00337bef1b0daad2867259ead6dc3926d096c053bbec653f99cfd89e433ef5332b0eab9cf96ec78f7e4b9284330729fc23464064200f9e6a9d1da6b487db3c210763d0b6d3bb3070ea95b5d2604946214aecab35051e2f8bf9262be2bb49125ba70a599fbc0377f029a79f32460dfb0df9ee305211a2b4d190a82130b26a0fdad7270e88a5b455d73dc8bce88e1c9f4f6e02a2d9a558a1631406d2db441b32c513dd7b2c3739be0d2d5ea4b5b4a460d3d90af5f9ec20337c7c2c784cb9fd796b1b4e2ad9615a258bd11ac8e92652188896e7799e57f7f249ec23233294b88c8151b5995739219ef0fa17eea76493ee56ddd7c5cd47ff779c361a83f2d1407c584a4c9b64193f61d14bae8bfdd45d151484fcbd61566cae7b8f1eb51e8c958e398fab2bfa08c2c8f8611bdc7466b23230bc2469be14d2c9aa20de768e4368a6ed3848867296d88a165b009de62a00a4f512c93ff57a70dde11ab1078a74b5115be11e43c39517a5ca141346654353c9094d0d4bf35ceb90f383776c47d57420a0721040966b6c1d62e0e997f7c2d3bab51e0be7549c17982bf84e6950901acbb71a44458ef48191c6a7bc6965f61624b48fcfe41ea4c1d54327cb34f7ac221d063b2e0b25520fb4db3523d39be5f20c85ee5a5d88c7da538110dd9fda0d0a62e2391945220732a02885e7b98d0a58009d00a3a723ffb9e5470aaf7e0ef1eb2012ad42522930da389e2b7b8bf6dd8dd44687c5a40585df8dced13e219fc298c74662d9714039092aa6c3e1642880c6f8d4d5243dd87be90fdcf3fbdd9bf5813124fcd7bf3dbcab63201e88d252c876ac5194b4f6d086296d5935ffcfc5cb99cb54b966906a39cc28695a1851906484b392c27b7d195917dabc9f5b3958969dc0cecb925d8f55639722da479ff0d2c232c87d3981ef17a9ab12cc8a61b04ae12edca7f2a48f363c9d18d6d5819b19ee19003bd2e87455418272156ad11ebe17492f9dfb1d3e128689c15a16844f473e628f61fabd0b88fadbdf124eea6dad220042b32e11d87c6a1d5787dc6761127566bdab8357ed1b4768f90d6611483161d22b4a8389186d6996f643496734388306ce548ec410c36c00198ff25ac2f229b9ed53a29581cc744e2e7d8d92490dd28360c14c93598baac073f86fa123f80c531a66e8affc021df8e749432c82839a3bd28122108a8442bebac3434c8a16512ab55955018555f867b7642b9db597894a75ab0000c81f2d1ba821a1a87a1b3ec952e4d2cb8286934537700c6a8603d545bd127f6cfd3e51b35422d0b2e2f007e9a55c284005ddc70d85b2f8df037d3c75406614e0e6a1c077ed9d8d5632779eb870c6ffea54f21ce636b58c94e3a5c437c7d6976d98b3cfa85bde04e2de1553ab7a214abf4ef299652a954418e423bb0da3b49a2d341cbd563cf535779fd9630e88c4de16c02a17d7c36ffe88c10f29c1558e764ba7925ef6c544493b7cdaa8c64c604378ba3a02986fd92a4acdd341a8c0c7bb3f1f7d9d9b7ee58154979b526944e9f7751faa3274230904d4011379cf228be33625d4cec99b9baef68f972fa9f3211a9576535938589bed476b56a5729cb1d9707d4cf43fd6ed0b4905db78439c4318620aec3353342d9203c745d171e85652ada68c2171b556c98ef3f8b0b54a9d2cc0e83c6e5c83ff7c4a6ff5ba22e18d42cddedce718e217d9a21d08d61bebd244b612990112b9fe9cdec3872d4be6d386a73ebb4db0ba5d9f7e21476f6e9ff929a608f52fc711a40d68bb7fae3b06a76718dc9836f5b2cf5a0eb86b529d33183692b028de22db2127c7201a1522de8f22716d09b6cbf1c49b72fb7bd212cc57280db71fc19b9d210a6aa08410440ef76b5f40f73fdf1b7abb41b532e84a03d65dc1c8fe63badb0f5227ab847eb58772ce7dc80bac4287e1e1f5677e908d91a035e5808e9c907eef7876ccde5de7987da71a8f81ae3402dbce411f4515d24fd23bf26d7005d4794ccb965ba56dd83c7cbdfee0cbda9ff7005a1c6ad912a44754dae1a1da6ac49bf288bb8f89c8e7df2d49d98e0c92a304bed8974b46f3b0846296b6dcdc1910f82adfe392decbeb5711772e9f89cd384dcb39c44a1ee077eac184bcb95133c273b7654fbc32ca2a19d783555687aa08388391ab83687ba635e7c8117a620d2658e203fdd06f835623bdc0a9d1f67ea1899e5ec8ffe6224d1db6b3fab67e1252a5ec256ce229ffd39d41259bad1d69a46ce425a005628427d395c0971d0711cc7443e23f3e34b53066a47ce124d8a70c7fd9bf5d61716309d63bfd3aff346054cd1ea73bf0eefa90a1b8cc407069946ddc5b35f7affb6a2bdaddd9792c056c9aba563027e1dccb3119e25f723815bc87de3cbcc770ccbc8ace611f10e47dbe7bad85a2a77b17249c3cafcdd1ddac81f09bb8f70aaf17cb8ca28a5c3a4ea836ed7153f86773a160bf24457ba03809a6469a292ae03a58981a8b1fd87c42431a23ca944501a3c8be85c339c32aae8344a51882a537362f392112efd0a0f62e1b89ce5abe7b08e50a1a3788f8f5dc9e27d7acefde45394b27f77cd22ffbcb26002665e29161b6a908a2801615842cff2491dc1c32a4319dcf622f9a438eee9a029eb80f8bf9e3507a5b7ea938d7cd82169964b6e7d08118982b1328c5316951d699ce2b967607a94df334ec8db489cde8f03f85c1953dae353bc7580d248af29958f941655da334a4135a24539e0e9b88bd898e944d0005640dfd4fe42691ac8b002d08bb1f63c602bf4fed452c190a7b00d93e16cbbe4d24eef721a64d3c84063a32a86539dde55e826264557fce17c04e130918369ab05f5efa631156d2c60f7469b5ccd7ac47dad4714a4524af2a9586f3908d7b2b8a6803f3d6fb58d5a25a412963ac1417ae9edbe25ae17a05e2debc7b470bbaa96e75c3a5966d9daecef89f8b201277a91b8f1467691344bb74a9292822fb6a2fb56be348509e9fc25c1cdd7a0397fd918aa89d6cdc1d51ce9ea0f12ea90cf71682ee34c3362e86d4438df91269162ec7afe9c55b9446a957c4c54a3ff475145d9a6b6888117db4e5eaef1386c221a36cef00c16a2f045b9975e15386033a40ef364c3a1e6c33b74e531ed4592de4a34a84388d2c3aa5a23ded91e4095e5c759960fcfd6f92aaa77372c47715a99b2c48d256de89b11c09c7b5fe2fa78ff22af4e45b99d2c964e4b11c5a37764aed5b30d611ca8c24441e99f960107b4dd07932c5a866d51a0e0cc1ea511541673c44bb94063254860f2679491490640f8c9fb0eb357dbc7ff6c4c2c0778f245018f4da9eb1ebd01ded5c649568e9c6711d811727595ccd4fe4aa0d30647f6796dca042f24746ee7bbe4b5d8d97893cf04944666375771f159ece94482db13f4715a4cf55369689a23c53e170e0bb06bdfd2ee15f9a89d5fc132ade3713db680b7fc368d4bc6b39f6e1f68e7aabd8882deea7461df0211c5426e8cf441e863fdb02e051f5f2f3a15ba7555ebe67b8fea237905bff2e1c2722a412b7c860c3317b6b882db62da647dcaf31a8838088e0c3c0bf4dc411d807e81401e72bf114dea5c1c6436a1a298f332be146f2fec813f1bb54c5707f06be8707c016c9c5a31013e10581bba3c5858750e91514464413e7e88f71a89c92b29b5ad9859b920d7921c85643e18b4f28a75b7060a7218eca89946b62daab95ec39468e071c3861bd773c5cc8b3b639fea3fa278d65a75b9693f2dc0aae433aa4758816d5be7c52e8f64facaa5e78a359e4e39da8ba28991ecf200a3eef2564310bd5b2cd0bea1978c5a89b1a8f5898c637afb718dded1d2f173809134cf29ee3875e5bfae417608fc2bd3dff223a854b9702f9aedc06302d0681c199142edf24eddd33505133192ea41115d8d5242f14791067755ccd10ec98b1b8c4090d4dc5d1ed2bf804ae8eccba4a2d6b4a1b017080e105656f642bf99a80f71d98b7612a1c337048da3d10769c12373ab3c3866560abe4dddd8a01ebc0f00bf670b36e232e160ed07f6a4794d1f717cc2e2daec2e579baf1eaab862be879a8c33f7b9aeced65941ebf2bfa66d2662585caa87724d639dc1a87662439131371e71259f6307ba194d70fab5f59190a0f057b301220076dcbd02320d558602f7698781f5a609ffc291d339618cdd6f1a69e4fb7eccfae65c7507d1b361d880b2982075b676f64d5f3cc909cf50f833a2ce390eadfaa0d41d7996848ebcfff4333d9cd080eb120ecb0df74f92347bbdddcfae579dc14eb05ec23fe354b5d0f09fe94beb6d672706319ef985e5693703c818356242601effec71d2f204746608c53a1ae490d4a2dcfde8ee032c99d7057d6f635b260e811fd882eb490cbc510f7e6ace0c08a1f8e38406963829bd55db708381155a81a52c2b2b4f67796144d965b2c8d38908aa8f0372c3d91e0559aa37365a669c661380d49c107eb60a4c81440c33ab19a71234d167f8a89dfbed148ec217ed97447ace156b4537e0d460728b5c280385c65d313be39baa27ce3f44a532fcd56577947b2edb9bb24c95b5932778e2a6647b2e9bb4df2267eb0ae8329ef9ff284191aef781769b9575becff7d51c5d028974b4c3981c4f4c7b0fc47614d2a99791868f6331046603f3a2588194fdbbfdd998f8049a565bedaf51df07d6892174d19b4876a3f5b1c4f7c5e414373a2ad9874351fdd092dbf8f6fca5c3c645942809a341e7c16c2ad354c759dd39a81faafd4cefa27aa40a914d3c4a5c0419d12e10e039e1166564e1dfd0d1c11991b2f7075c212b69e1b2b1287a387a133a7945213e6d503ce976a5aaa58ea3cc4b0445b24a2c145bfea82778d1ccd086baae94c9518df7e185e404fdeda70e3b0f2dc53b1928b977cd4d9dfb526cf374b9e4b34e740e4bc975f1ead44b2632e1875773861a996388d9566c8037d19943067691b9d7a429418d5387314e69454c91ae403f99d717c92eb0f78fba6228e61ae2e7d01caed2c9fe645013b56b9926db39f0c4fd6d067c8b3b9c9d0bf72e040195ff6b7d6b8bcb5b78b302017869b8690e2ca1a728c1e17d9d154ae12031f01129fd4e955090f31098d3a1655ba9b87b307a9c2c78af427e7196470eb453410ff9870e70669b60651a221166ba6299bb95571825247aaf92e028c1bb5ebd9915c5215c462c8f4b1dab28a95dde7cf2bd1f5f76a7447dc3fb6521dddb6e7b1bedfd76c53d2eb43eab18b23a4bf06d4503e84054e87e666ae0339f87d1fca555bcfe01459818e053bc99aaafef4d5df2810e8db206e31068459c31538142c9311042036c65e98090f331ed60b0bd4b77f30000ed4636610e83a2a664f2e3592c7144fa89ef3e78fecf4fd4072168168a2c5620a5c60119e48cd8393fded6962b22d5f9091f83626ab1a0d1e47aaf37cc3c647590ca6450844d460c4bd8bcad09294af2f527bf63d9c9457826755ffe4d1494839a39b7aadf80198fd179f99d2260bd213770a450a58b7f4ffabeecb6c0cdf066210570ea29d05b2905aa47413d512980a404195bc1ebcdcb6620b62b120142ba720cdd4c36ebb705bf42098a0afa6b4287782b38f514d22b5829ef4ecd30240311c795e886988048f34acc6009a2dd95a82aafed03326905af4abbd258a09f834a312e5366b35b7eeb502ae405a21b5f8b2e68c3a9e71a28e7c2699908de08a9385ed73ef65351af80faf37f78d8a2473742f6df73d2f508cc790c8c0d23539d37f74bfa2a0254fda72ffa2b3acfe4d2fb99ae727738066ddd0b6eeab8907d00fe444a38ac1e8bf63c67f93a9de4944a54deebc49952878bcccab035b0e4871cbc220a5d7dbdd2aff185a6bd5a118a345a29c6c9111bfd96833283b6839664153dc43646c2deca06755095c82098e30213c985dbc15dd1bb967370078c65577a50302ddea93917f2060be444967424c96f6bf3b2dfcd1002138439e400fe3d66dd0d38969df0f61cfea2fa041ac8aa7cf89b02bb63053c040cd416af653ba2e8b7b9271f0f56f0438a491614917de7208e63e4c926cf514fc97a7884602c348dc20d02d14cd5aac8ec0ce7fba996e2ac4a2dca2a347876f88a3706f6274e21a91ff43596fb4f088360d314b7054c25c127840c00a7338f00ea50f952ca8b5cc6c3619aff0278317a7700498a3053c764c0c85331585d36466ac76e78b7dfa88e42ba633ddd3f1491f84a0c2cc1a6d56f78dbf4bcd48c53b9e6234e32d29acce12f06f793634c236afe1f360c294c78feb8d548dacd6cb5f861ff590b7d8041037cf918c25c5687e0c2b69f30bfeebabd6b76024f11fd04855e36b2f5666de151b8b681cdf2d97088a20388f0aba54c08123bf6982b2ee4a300ffc1bf292f25a5007df8b73a5dc5dea2a3226fb400f91deee720601ab4c63df6dc4ecc54661b9a18c93fcdb0199bc410ee40192b9608f1000b3a986ace01e7823ba0027cc1544ab4a003650d12af1227d66db74c78934d7216f378a3d20711f15723fa7b4bee9a880a1fe5060282738b75afb5661f95cb7cb635f42386dd299b28b9706f6c08b0a10cacf71fe250bd90b246b430972b6cfd8a5727b62119ca3afa9918aa36424121fa1ea0638cd4e4c0200585c1023d5127e93cf585a05dc7d485fbbdef7b68d6911d0ed0f4ab6be285a842ddd051c4958d8d9d89d403560b3e78a2d7cc37d08aac26783f31e607dd375f4c552ac477809712073838d30f4e57b24e729d580b781294d763b25c7d3f55e34fb5ec46922d948d2d364951129ba75bbcdc8592a67fe1355a5a4b42707d14b938467a9d43c5fea7a2ae564c0467281a6e3ce255ab60f0b7eff7f7f24dc7b057f2f02fb5479dd954f90f15063d1b4db248429d627e8f234dc2df15d639592e550b3915c7d8ad4e9e7fdcd4d43480930c450dc942630f3238c2e7b176e912e10d7ba2c590be9da0367e4ce7ca02c63a23dc3e2aec3f6e437fcb0753447260a556f8409e24486b2fa72ded0c624b14b0c53313c40244942de5f76e89cc44f1cd62124f48d18c1a0da12d775e9c40beafc8a36770863c9a58952e03ed141240ba04e0dd4cf88b11507b9bf58bf4746bee50cf3792d1af80db365290f25837da91f429a3d064a195876158a32c6ede883a0e245951777c163106de1822c82f093abda3ce1b5fcf61a77972af3de3f7e2892ef55dd25d25f6ae7df6b01927187925ec17feeca6a64f00c64f1646e4d3b52cf75706bda87454d01115b5f67202741c19b5ea04a3c9ae94a999346ad0e90c74d519c4aa4acc6a4a58affa368c5b66afbde5a6b0f7c4fd1bfb24dbce0df84693c0260f22366cb1b2d2aa24036ac494717f296bd1f4b6ce8e75a0451910c3c3fa2a5e48ebf0e25cebfe2738a50b44f313e9486e6ae1e50cac3f20229fe1934a7005665dabffbc725140d13788984a5c12b0c8095a648699946bc37ad362d2ab79a84cf8d4bc0346227a52b40b2ef6e7f1047bd98022b88e71767e8eb8f61f70c81436bbe0a17abad222d0010c26f5b0f26d4b28a3feb1eb2a34af3ec491d63ff6a7da0aae0fd8ead6977fc02b61961cdecf001a6984e41fe7bc0b9a8ad24dc6f3789b8d3eeddd443de6bd3a12abf34ebc2ee7152cc298369f2720e10371929b3b5c38e9a6d7ea91aa4e14c00115beb87b0aa0464eee762d5eb474e77a11bc9a8fe1462cd018dc18060dc3bc8f0703178b3177ea984321610afab35cdba70e7539a8120460383d11889645987b070c481a35e713a2db71acca2e9d06046a41dc2fff6d4d9c916443b5b83b7d99fda4a3b0998c292787b65e8219da5edc0a63488a1c04c37e1ad4469a2821bb38dc9467f05b70ca3f26e640c9b14675042f5125c54b060c70b3f1264c61d0fd0479034796340290a7230060b9be7969c07dd2fd7c01dd33f8542c67665266e51f59946be712209e1e8bed1847982c4788a20839aeab4cf35ffea55e9eeeae1eed2fe8566c81063f3fc8179dfd25004a41e41e347012c2dfe66809d1d659bc6ed1e4a0977a229ad8ecf356105dc845c1211758837d55fbd9ccbf6f7de4cf0fa6e9423e2ee376b303dd4dca73b490eec3ec7fc1253f4fc898802d593edf976c9b38c5d1f9d37d0f7e6d5cdbac952664913596750ef5805413101401176be1fffa292bce4dfaa2261300a0041254eb1ff38a75645bd4c1ffd0446a281ff6f5b1bfe820ed69d32dd47f8cb6f81843801e0f2ff3b52c103dd60abbff87388133e294c9411fb777bbc9818e26e5b80eedc054c40282b280fca915e313c911aa5a0d8f0348ed7072d0147c898f2317b2490e16c0cdf0f3065c035724a19245de8926f3647db59850f32e8e29fed16aa27df418ae91f5c93911aa0205a29e9c70aea54db6c261a569a8864f1002e89db5bd07ddf76ab8c00c767d1218f40f3db05d211f027cdf7debaa0e731a95df72381ef094df45cb9ca0ad7a81ae600c2df4977fb722de929c7f0922f41298f1cf79d0ae17a3e46a6e16cedff9490356a5d211cf8dde32f949b649f493065afa31f1f34c325c425132d0b9baaa196b8302354527579ef2b759eade6745eacbbc11dc4219cd6f1a01b9f05f82952f8233485c9f57079107a80aeb11def45b06c5b0c46a3c7040677bc09de93c9c3b21be4877e02f90f01e77492f25260e3ee9764df120b830c48376c86d206b5c0b2a4b4311b845fe757b7522f500e92aa636b539c14c01fc2c20fc956ceff9b74fd087c3314dcf81ff8e24c06adf0ffc669634bac29c1cbc0d142588bc3f52de2881b6290ea00750ecb9b2a9e204d45102405fa58af25c02166482632df5cc525c751ac1873aeaf9cbe6893f494c999b4bc2c68837bafa865949bbdc3c445290f6ddfce018de6d9bc19ec01931b1c1bb918f34755fbbd61f4bbb089c60cf9b14b169ff0a077754b47a9c4945a12ba50830f3fae3d6fa0e199f5a77211a942351979eb19cd1b9d97ad5bd340873fc5c19e7a83028fefc6f571883490dfbf1bcc41e89c0b7a404ae77b6b2318c17813d9f0ff29b1b147d49cc7553646feac11a47bd2a20c59eaab4b730085f06c0e6d19fb26922f1ee1f05328d76c7e11f0aa90aad0f7aff603d92d3d5eb7b99ba39ccfad6ee3abc1f400c2d770b0af645bc652dc6666bb4f24b8c93400179e52862beb6a1254c97ce6e9de196adab02b623ddde97d3cc766173290cded705e1a8e81519cc19836b77bda6478edb5ea9fa41ef2ed53561d6a4bef3e62ef84f0ed339b1eb4c9a5677644b12824557b609541f6690976ec64d7456dc1d712ec6fe573990a63537742e586d07b7a6d5d6b7a4f2ce3db2328905014762c809bf622ccbe50ccda3742ad30c9c4c19895b5681e6f338b92895fdc217f2bc408dd02502f9027723ca9b8640abd22b39a4332240a7634d9048838e0c3f5c18acbd36f6f87e8cb9ecc7abbb8089366a7d5eb6c3d01a7842c4af95fd11fb3c48a793e2956b3042e8fe14bba5aebd16b71cce0d5d892645ab16ab19da271bf8b755d4938cdacac96e64da98c20e29cc4acfdf1b4f56851e2d80e1dd277e1fd57c86d05340b602fd52c8059e3e3d7e90b6ca7bb78087c0d1fefd90b1a17a4db4cf817b33eb1d507a83929f9099c169f67c27eb6d83b85f48da368c4ab28db4a76de41bd9967f55e0fba0a4c55aca8222a3b79b53a7cd58a462f6234c2d210c60a7adb9d69370a20993a7fd0e60f22c9a0c84f3c4b8404f8c09a47f412e9456f8babe3c636f2500f28d49dbd3abe8678d4dc2535af179d4d2dce797e0f26881cf05b0ed804922dcabef989484114dad59acd856edb10b41400c10dd2dae21503072d95f2615451580a6f8e3222dfb890d5dbe27e41b46ae2720546ce8947d2e6c8866e7467366def50ac1f37fad5169d263cff7773dbb35f8b563290a2229df50a8df80b2841ed830a81e21ffa07f2435b0652bb8c51a279e60816aed7bbfe5ea35ccc2450eb2b3fb5728bcfdd1e5357ceb26b597bf2b71872231a136e67c36845990d8a959035456032a63d67a5a30145ea503994e4191ec1e2aaa874b6a029bdd3c29cfe5f63c1694a45895bb0f30e2c0a823ea2fd6918ebd058120d24bf33f000cbd49fc7ab310afae7e6b5ab39dd9481695cc0a48eca57e98a0f6edf52dd99b6cb9a59429a51475077307a907d099497bfe9e821dec58885b34dc62a1199ec80765f70df91ece8dd6a03c839ce9b1ecb949cd63268ee59e7a64b0d670344ff31a0d3fe4c73e9e6080cffc5c19cb9e460334199c3a78bc1b2e2e48ba5946506f7a9e8b870e560de892cbb5e41a8ad262c245c9e55a720d452162b96a66686a6866a6ccb2168b8b926bc9e5e2e2ea2f5a0708a00ac46a535b6538fee632c3bda79cbb56eadad59ecfb44be9071757abd56ab55aadafbdfc9801c9e572b95c2e170de887f250ae191a578d2b860ba929caf52ecfb514d3329454f8ec0411bcd4f9f3b3e7e745aa5a8cf7776d32f33edd62209583542c757bc80191595c4e539d5b696e37a05c6568af3f08e7466b50f24d1c0886542ce34080d948e0b404850a25966035a1f90915d0da63da63271858d37e25d39540e6655e93e156503c009fbf04503c003f7b7982811f76363054e881cf3a205eb5af407bdc8f36f39b0e9ff619ae37ae57edf9db88423346d51b29f413126fc00ea73d98b781049d9376a8da62d29e3b92f6dc6d7ca19ee448edf9c6c4855a67be7f659329eb3efe2dcbba8f5ffbd3fbb8c6cd6721b1cec73205fc6ab5f2b195bb130cdb84e924242714a93dc76213047579c1d23bbcf26f2425cf5c9eda9a755f67a9ce318ca53a9defa9786ae79380fe01d37d3ca7ee536d1d4472ee6c0cd18f4e28b95df21d99b70983c6aea886a391e11ac991609ac6096d6ad9fe9d5aa0f72eef4e2dddddbddd0db7683c4c544a9807de2e2a3f90de591f13892641c15ee63faf2148a1f2cecc333fceea6cafbd6927c6f3f3f44ecd0e7d7ede1dcc621cdcee803755724de8d3224f758aa974915cd3a6c970fbe3dc3e5127e7dc1ed128e2e48473ab0326f3098d829af227a1981cd023e8e6dc52716e7150316ebec62fb3859e34de3c2d736e6ad9e6cc6cce6d13319e38b746158339f598266c621b746e8b284e14fac1189b7308f0817e53c6e6dc01686824cdd89c3300adc9e21c8faaf1807ed0b91d4ce6131a0545c5b3a27ad60a9585733d558bfbf313655e724d64ba7ec935a1dd760bdf66b3395700cac5cdc6a43b0b0f1695158fca4f41457902c40a6a1555b138bef8520c2eae2d6973903c65e5886873aee01d9cc4e2e8ef25f848edaf41829eb039b7332305cee9987840bf89c2e65c0b262c9cd3f14d709b7304a89333bd0c87c3ff40f1d7b83dc7b429e0f838c939f61a0aa71ed88d630ebbcdb91cb4051ff4e05df483ceb1508344bf89b339a7faa2699173386a70a0c2e6dc00ba702ea79ab81b4d687c6cbed0af860ad114ed6d4ce8dc0d19977302d887ada453fdcde449eda7e198885b2e88f66085cdb9154e3882b7611ce4362fb5f151eb508ca3f105dd0eded89cf3b024657171692fdd45fb80e68bc780e8077336e70240e96989016ccea98063730e00345a10aacd391c9a1816b0b03997c26f3feb51284a592cae88cce3f03f321d94cdd2a9fe66a22f9a2af58959fbfef321fc98d75638f598a9ceb5f445b562226e716cce97428dc7ada76ab8754a04b3be3d3ba8e5d89ceb564504d89ce3e83c42bfa96373ee6990b02465e1d8c5b192a7963cc553d47e966271d07cf1543f0be80423d06fb6b0615c13da563ad59f718c85e324cec22e14b8078ba3df3914aae909fda04d127636e74e989ee27678886c90406980f563a2130f28d6cdf6b4026cced9548c6b32f3936322a6d21e4fe954bf9c827eb06773ae46c5b826f425c7454c45a66322203467a3ba609a01415a0cef88d5c60bfa4158dd7fba37f48636e0d3de81f06f1847671f7be4c36fde617af89a16398f5c57ad6bafff97d307a8fd156e8e7f370f7ac375e56aeab9f188df577fe7c19bb3a71ed039ef2ab150e89c066dbc58c85b64b2621dbaf70ea0f70e189b9b717c9a9c01e5f7b8bed19b3bc640d3ba09cabfeecec528bb5bba43e85cba4008210c1146e8485d60eb7c44e0af167d1b07be38ba75f7d2254e8de30df30e3861cba97295ef70159beaeee391e1a43d825150e835bdc39b5466a1ca2716aa3470fd3889fd0ae5c5e124e88fb168dee1244ef5735d15eb6c7b9c456d156c75f38e95d1575e4c4a6b5037988c527a49baf0d07d0df04244514a5a355a609dc510c2a8292cbc1861e2c50701e4404f758bbcbc4005197891818cba455cbc1c89777777bd07e70fb5226887eae88bde689df87d80d8d92cff77361d4df1674ee8abb808b63f5175d152151c8a8a54b9010de20e2fb943fc886508b14b0e3b4001862b2a7191c312e10ae6840653d7284912499e4cd102830371050cf08570922cf0935c1159052076eece76842f00156adf50a576078ed73c6ac307e23562988cd371f8bf19a7c296b638951fd6f0135446a11d028f69b9bbbb3b33bbbb4b8feece746803407c77976e7436c18068d105b010e5e66616742bd5b12240bdf26cdbb62c7b53f7e33de53f99fb28636f7a1bf9304fe427eb6cf8f4dadb48e0f4da9f3a1b6c03b5fff43612e663303d8ca9c3ba184e359cba205ac79265475459fea8fd9a8f8f7f5201aa9a71369889b3c13a096c6f83fde989fc642f01eddf068b61c3be86adc3ba186a78223fa66f55e5eefb51650744556568cf67f061ee6ce4f3dbc8ce05acce24b074581d56c27afefdeeee1856dff9cbe6388ab23226d67fb9fbb19c0cfb31b4e72bc38f0fceda407bfbab045b315a051fcc48a23c3e1ac6cfc3a30b4cc6d051162e35c6960ef55bd7567494850918b78a8b1a8150e3df88b2fb9b257e7eac5facd84709b335a2f163e499b2e3a992072e9892648b4d0c7376447ef6b7bb522ca6ae51932c6a7758f74dfac3a2dff415c4000911484a29a5921d322600e580a48909905026a07062d54f7c71021efebf091640a8b6402285d0a2c3115478d1610b0d3a0a2962600458e504592069a2a5dea8a1355ed7a889154e68cbcdcf809d9dfd3d39806de03e22bdf1a9477cc901cd1ff9918ba1573ff297fb4a50bf10c0daaab1f3ee2b410cf4477ef16d1460aab103414c855d13f9eb83aa7a9fe655c542f3d7c10d5f885054b78aba39f0c2a546098f66bc25a32641ac24f9e32f6164057dcc43edb701fa98090f7a4a6d278cb8a27af7b1d26c2c5c8dab803210cebbbbb8b104b19cc548ed25b5d7df37f04e06b86dd89e2dbb535d3c3d3d3972701c8dd861a0f3d99ce6d14259e9a7b99d6ccf3a8abfb8cff6b030b03dbbcdaecd699f9882148a39c675c03b1bf9fe1fdbc82e067ee8e37c54bd93b67648506f43825f4b010a9d2aa03f54a420b60895795136ecaad50a0a0a0ae2968cb0b165a32756b539cb4b9be29f29a8fcdf168157d4abdc3577a94c4434b9b5571ea0a500853a11acb3ed467887e7119aa4f22f2fa9fcaec3f6cce7ef2ebb3337c56f43e5c9df4a73528a4211050505316fcfd3c43fb66e3db55aadf679797fff019bb31f143429ea9b835ac789608f9f6750f959e096f3cfc9cc44ad266a2566a1ee100d910f4d6da373569f1dd42dedbf0ee22a9c72c94e36e5bf4d6c133d3d3972701c0d1adc921dec5848e3b8a5853ad1f6c0f7f7d76a402613b210b77a4a7bfe454de479d0c32dd53f460ff467d51e507b9d05ef2cb7d1f696a2edc1de86af504ba046d002550595c269c81e7b4d4a295fc3ae547e2bb2d002938f715c8922514f691da5a5a6e2de49d5db4b94b0e5cf4cdc280653aaf313db93bdbf133551018a7c9f4062b985663df889ad90fbb88adc42f9e57452a3d5b18daa176d4e134a5390424d2b45e58f2888c8777835dd79c5add841c0f49ac641272a47e4478b5c07606783d9605d0cfd3df810f0518d1c1f55c86dedf721ac6794a0f5c3ca5159541657d2c6e88162bb9caf529042b3ba3d337b7eb66103857228fb5dd230bb4e82e529e69ae81f5a89a0cd518259add36a9d1d6a1d9bfd45d23a41adc384db7699d59e867a42f7d4a36356ebb8bb43d6a232e44056b7d005f2d4f2f2b28fcde1ef1e720be5b81fe887aaad04a891b4cebac01cd81cf6b13dfbb13027a528d47a1116ead7409cc43f27a528d4ffe7f1764db439fc0ee4abf6d8573bfbc395c50de4acd9a720e452ed3a84973a80ba46432c51b5de94e6dc02d63e3a3a6a94114d62a72c22e65ba8a7a8f9654e2527aa44bd71059402142772c5852e872e560a4850fa7209efc415f32fb3b4616510db637afafd72b53dbcf207a982da520719c4e62ce15467dd278be20bb0ee934ac0ee93466cf749225ce82a579bd38f6384d20eb573ebd591efb0ab8196bfa0bec609fde2172d58c787faf4302fabf00ebd82b282816416b55f3e219dec4e5c49a3f8257e9142dbe39b66caa0cb7768bea78ccb559d88a6531a6a1da905c3749fdcc2c8897c2752147b353a510d117465d8546f922bf90e7520fa8fa2be4936d4fe5e6d8f33d2f6ecf397dacc456dee52794b6daea2f6c7952bb9922b05c09536a73fc6b81e520eb2c0d2f289dc1c00218b2bf90b2d9dd48e4ad854b752f003900ae04a87da3648a12446628e5fe2176050a9fd722585a2f40ec792455a678dbe78523b4a24416040513fd94232022308f5934f3e0954fb393252af1118536a7f2cb283fa451e221224107018aed43a6b34840a6abf7b699d156abf73f207949f4f326c4ad0fd4d09caef10908fc3fc99f99898a72fa3c37a0d7b882814a548744e4a55aaae407b5df3343f239fd854bf14b5bf0aa5ba45c21c6a7f0dcd8c944ea4112a0959446dd9fa47a1565f6aff4a0acd2003735e6391f65a0ac52f9bd32fc345256c0bfd948b602c01fa63b818c6b2d06f02a211287e59b9746a2e8af6d2aa58eb6ceda56269b55ad9f0b3c44a11205793fa39abb6890913f57325fda5f6c36521b0d47e9c661254fb864c5d1a59e5d40a75bb1c75bb9e8a6aa2ee6b6e05eb70506bef4af0ce6ca24af52bb5df93f01f76875b9bea4715f1b55210b5df83b647e968624747be33f30dd37d936edd87cae487a25dccd73e6aafffeba30fd68f839edf63a5d78e5ac7ad60cfb1b052db7fe8209f93d25652f220131065a1ae4382a600857eada4a4a198a07bea74a05f077590efa8828e1ec0eea9566d0f7caeada4a41463ec3eba425dba297e5e4e6dce7e9f3a4606da5229a59473e54af98e75b283b07b50d5d6d322c671c58afa8227155279c1120c6050210cb8a85015a5385185922258441942f203ad547845cb912184b8c1d5c5163f108a20c85042b7f20ed3096416355601000b02c1aaf04a0ca290e669fc385ef7d57736528ffec5213254fb97e3f83c1e0742fee6f7719fbee1a9452aea1cf8e112c40227f343082184703e67a6ccb565779ab529ffd9858bea4d5c2bd81d6eb50baad3d4af5932a8fefca4394a7d9e2cd45e2b5b84d94eebce6404ad47726c38438d147600be90b84e57cd1f0ed315e55ff72c4d68821236b129236cc2c464844d684213fc1d09249cedd1da4d0e3388b33dd3835128f4364e1cc6f1f90d1e38aca3539df26a04b039fdb1f3ce9398c4a2d79ee76d4e1838dbb34daca71235e8c8448db1c6e78931c6185315fed60005157ecf18638cd1852a460405810809546cf9899da5c62d6ac46a8c31c61b75594a961c434028e68c188649214241d7a0803c157d67a5e840870844d19212450f11e081d2cb2e2855ab8abad862071981a32f9dda5547e009a04e6d8da927ba50c20a5350d30d01d0820715b878f1c30bbc60b202165e144151188dba454b10a2c2d6124dca0ff55bf85ceccac085123ec16e0e413b104695dcd9f8d8caffc256eeba0f7e0888549f765a5b6653fd348ab8d40c28e8477d053ce79b9ea1474c4e547b0a80d5d4c1d9bc5009e324f562bd39243ec7249ac6eb0ce34f7f08b963b7504b11df414a29e50f5030821720615151855505952baee400042b60384141144140c8a658416b872794ae8851b4608a1e5e43614bc056498e3046080097141900200846528600c011c5ea1a4979c1f4a72ea5f420a548fdbef20c623a5ef50e54edeea851942f5555d7e88820542d46b9c3585aca855a90ca1f3dc98e91e00ffdd86584c414779ec244acb6a2c2671eaaa8f07dc0e7221d42d4f4df9cd23aa687dd42609d3f613f44a9eaee6024f6e13bbcfa767807d3c9ae7321d67e46e21dfdc3e2800f77d48f5d7cc5d57d2aef3b0c728783f763020ee3070af69f10af3aa0a08b650f5f83f1e32e60ba0ff57468534b5424431847da9e609cfba60386f43875db1eb7752bc4abf6262e6e409b5ad60cdad4d68a446b53bbfbbd9bb3b51765377f92be2852fb073e77c1406e6a3f3f7f6b7d6ac23dde0d55054880f3dd78ab03df91000bec7cedfaf2582bf575f8e985e8b54ebf00ab8f28b4b89ec9b471bc9e694d23a830fbc180f6fa3ddf89a153bc43015e60e8f6cec7e6f43fa13efc7df80560e22f41f14585eac1962da4173d4829a554819722546104282e20c2059d2404138694219a8a2a264802bc92859222f1e33671c5bc1206108e6843b8c088c88a14459cc00737cc2956469a8afabd0f2d1e27bc07f55b24a4badf2a1da1a56e171f688110aa68b9c1122d48e2c7b11c61a5ba472104510a8660a2080b58f0e3af4ae1080d848c8c8c5870c38fff0cfe85d6353a62ca1147645a767b365effad3d7f17bcef5437e7f48257f7d30b587517e00bd9e905b9dc524a97129a60fc7d7a6e4e3fbf8908b46b3f991e802350adaed11142d81b1d11449552055a943c95f24265ea1a1dc13a0248059de8eda671bcdef13ac5af52f114151d1d2121c9d87da1df561f7513655c0f821d4542f977773b082184104208216466ee7677a1bb37ef36ec61629cefee32fce973be4318338fd9c4a07c87d9c4645c8a02e5668f2d73df56b185fb37dac389c9fec9e35aa4221ecf3d1dde411f150f8ff612f0791b17949188d062988d8cc0a1327ba89bcd41fd6eaaff5052752f0249f522aaa83b447ebab97768da3069a8e7ac1046201f9610621d01a38a255354f80fb1183101054208e1a90796a37e5b0e8690d0208a2a290a5bd48c410aa0b8e0cb1660e030742503362842020a1f562084112994cc304b99c54e477bce037a315a70a37e5bc56680a562180d84a818851edc2a5b2c11e40589269696fc402427a298004e3a37fac333685529df291d5aad563b1ce105cca473a3d93eb1031dac503f1d15f2582a589c7051e14348045185464418c9c0880c7cf004880a9fc7e7891315be0f1fd6088aab2655da3a271acc099d60590192a7763a1182110864594ae221b1850d50758b8e0045b5d28c8c60c1beb0d59f856ce4b141961bb22fa43d66e6863437ff727333fbe021419613b2b44186c8204286ac8fca0b32a48656dadd20429a0767dbc9757f743e8a509cda36b406d55e3f1fd12bc4c7d6bf0fb70b226408f6dfee90d6599e9352f6b129fe211c7bc41844c8108fa73d5e0a524377b7c733a4756a689d8f37d03142d426e1ec7791cfb055d7263ed728e37d5a4b323284ba2e33011b5a49467e508178980c34b763f4fc966f0f4de5e5d5af9432cbb239b1971c08b03a1f62523a0c1c06ac7c9a0f8ba8d4dddd2625e0869658fd9c60e0971d10afdf7cc871434bac6a9f1c306374b2f380a972c7455a45d0cf592c2424f41d47696f635ed39eb34d487bcb4166e64c2205e140b043b86e0b5c5ea406b3ede90598ff1689b7188eab0d29d4a789ee2e96f6564224ed2d0cea20ab3d56dd77972bb5a40775bdbbefac2f4b4c7e7ddaa769e6b7ab756a7ebf5bbec3937ea8cfe3a11b43083f20f3634e3d32245de602e78145aa1d8043754f351d92b38b9fa6fbe6ce74dfa4b4fb509eb3f6b2fb78ea56f82d1598d36bbf9d7a9c3ade3856c241ededdb9801fd980933691d5eb5b73f817c27884dffd6227d80dd656dcf4cdd7724eec3ee746b53fbbb9f759f2ba9fb2dc4ee386bdfa609f473d6909f1833289d018d988052f92643710f399cbfe1792b6954fb655996bd7c9f6ea19d936ec6dad4b6507b926b26ed2dfca73931804895add6e12a65c74aecda82ee774ba875be5e62d24f5a67c906beb7eaf2903c3ecc25a04832c00717ea4a5ae7e101647436fcfb23e3f77765644e640c3fdadb476a269dda8f5cb7322c5a75f96568cf480333b4b7fbdc7dde02121894df1ec6098912c3a694d23d761edda5ecba854bdaff407dc6d8b967d3e1cbce3d7670c2d8cdb781e653e343b8df8120aafafd00a26a61b98f85baec39eac28f4788ac0e39fad9cc1a5ba8df6e0fef3e8f70dbcb511bbee6de428d1f2b6cd96d1c39288c4125a0220c5457f8f0a8fbd204384cd01d361b6a7cb871c2232a61c224e878f1e85015c173e2068e14aba3bd8552aada833096a0db9768eb1be37f83aaa11bb682083b1d081dee8e7686ee0edd89488e476032bb2123460dcd8c0c8d81396d5a669a37ac563c28254d89c51831d61833bd4f9b30e639e7d6850959c4706664680ccc69d33008fc40a2800c491998c105a4cb15083119a974dca360e3841b9b1a34503364c4a8a139c26225090a5ad26a11212464c4d0901244444d141555393aba828464455252162e97164a4a4e3049e70ca537287884224c663c37363568a066c888514333234363606e58ad8c00011d61b19204052d69b5881012326268688a92942c624f63604e9b86fdf8142dc0c711047e20558007ea42289b586366d6186a52ca8e060d4229a536a1d4349865d9369526f59245ccaba19991a13130a74dc34c33d6d025284609b1a247c1c60937363568a066c888514373c36a650408e8088b9524286849ab458490901143434a101135515454e5e8e80a12921549494a2e083119f9f52f145e365e27bc6e5e36af1a2f1a2fd46bc64bc62bc6abe645f39a79c9bce82be605f33abdb697f632bde62bbea494d2a7943e6334b9c7d8d160828ec5d88ef1438fb086eacf32c687f26394cf9551e093164c663730a74dcb4c533260ca528cd221364d28fcc7e3ff3b00f7df1675ff6d134b2576dca360e3841b9b1a34503364c4a8a19991a13130a7adcad1d11524242b9292b27069a1a464d2dca4b9c91402697a8dddf421e82ae794262d738f99d330db7bcbe0e61daf87612eb3cfa64f475fe218260a26b3f87abd5eafd7ebf57abd5eaf215f6e58ad8c00011d61b19204052d69b59e2879c164c623be6cbc4e78ddbc6c5e355e345ea8d78c978c578c57cd8be635f39279d157cc0be6757a6d2fed458490901143434a101135515464456935a4a3060dd40c19316a686664680ccc69bb61b53202047484c54a1214b4a4d57a22243444833324209df01f8f8dff7a78d838e1c6a6060dd40c19316a686664680ccc11162b4950d092568b0821212386869420226aa2a8c8cad1d109ac19f9de29927d111ca8093c8c307ea0c4c741f50365fe37e99ae69ca1f406857a08461631c905f3bc1c2a158f2e72c5ba2123460dcd8c0c8d81396d1a669a37ac563c0001c5e0998586c9ec690ccc69d332d3941590c115c3d80d3730a74dc34c3332c0c789a50e8a68fca7aaf15f0e9bff74dcfca7c373635383066a868c18353433323406e6b4699c24286849ab458490901143435388888a6cd85484c92cbe5eafd7ebf57abd5eafd7ebf5ca5eaf9764254a4b344c66386b9a7386d21a2854f7bf82e7e550a97a78787e7c8a16e0e308023f902820435206667001d90076b4c264e6c557cd8be635f39279d157cc0be6757a6d2fed95bd4caff992af1a86ac260ab89545ecf41f0ae6bf1a31ffddd0ff6cc8fcf733ff7534ffe1d4fca7428cff3c19ffad30e3bf1ba8ff06a0925c503364c4a8a199e17a78787e7c8a16e0e308023f90282043520666d8b86f034a34045912c1901b562b360204c44798c54a386806674f3099c535cd3943690d14aafbbfa11487344cce68ffd56cffc940c5d7f6d25e3550a8ee7f054f7239542f13cbe70c9a583e67d004a18931c69e1707d65d319618f6d8f27c3c11091aefc8fe9bf03f53fc6f9bffc198fea3d80e5ed39c3394d640a13ac6c138fa2197c734886910c3b48c7971ccdff9b0e7cc76fe3a176fc02e4a68b3757625774787f0e50eddddddddddddddddb0218410368410c2861042c6b1ce45dbd581d07b4743b82b3dba943a107a775dbbbbfb61175386685d232f5a35092b758dbc4842d535f2a2c8b99bf93eeddc56ee36fe1a6817f3dcd1ae06a89d1e06a6b379000dcdcccb3c09683a09c8689d4cb73f9048e537c51334c524787200063f21b0deb4d7031802a5375a68ec4e0dab68b375761f528f54833176b32b4177b300f573a5947008ab1c080dad8290c3135aae349150828014456b28b5f2c5529ce24a500a6a50b4260917248104126134667d2eb62fe1c77d47653bf3bda34e3d078d7f5de030ea6eceeee6f4360cd31b1cd00f35e1eac7dd77329e1f3304414914b7ae11e1f620b07824f49b3b284f39ca860a14109e6ef6807e1e8fd6b9d13ab1759689708344bb0685e3a9183e0a158361ae61355840b1179a4e87e93e140c46f331cc3c8d4cf779357b98ee9b35bca7b29fe9b8209a51ad63de61defdb5a3fa09e98a3dccc7701f911af37dea11f31a9f5c680e7b98a732446a0b8995761d04c6015333339853f7cdb9751fd53a1397753b6fd4ee38f6625454b2551886614934d635222af2bf0423300a2459832d7870a4a3f84f5d28e8f71ec70382b40653f4c0d81596cb1a1cedf02fc591cad403742e3249f7a6e7993ac36e4c4079e3c137aaea0bc0fe7e00c87e46f9180facced5d3a90767ee9ccd1b5e53e1110015e47cacc33887cec59845397fce2e4ad3ab4c3894670df40ab7530fd6d89db9adcced796d08bdb339a2692b6b6b304a6c9adaa3c466a6c9530fafcd4159db9db92f46754ed5ad71a76e9d4f067f3042df1cc6d8157e9dc39999b48dfb6454e7beaefa6b9a6fdb729f7fc3f63e186fdea142a8c44cda688296d10c0000044100f3150000300c0a870342a1509646cab03e14800b739e42745a329ac6b21c4761180419ea8001c010430040000666a4d100d0df795064311ead65739644e40f58d6d7d089910dde5a6450c003bd139a4667ee089c9e430be73a8ea1522c421564652a7fe88484262d4c7de3442e4ef095221ccd1477b1c01742d59e3aa3c6e52e799b1cff4561f37e28ac7fa8340ae0d1068d3c4e120163cf1eea548dfe0bf4beb6593d54af47777ca04379f0fec2dd2023f1904834a15428953881b2ac036fbb044643a4427c471ec9e520e7ad5707e81ea4bb5ba0c62270eea9deb49f2f50599a0e9c6d610d24017d80d3a1af5301defb70de48e57814baa059841ad02f0f1d09b6542fb7009c8d5a04bc01bc8bd6674c5c8a265273a75554ffbfb4fd99a50221497fb1c0cf988a351ed7adecce5f0d696c3c5a6d394f4f1b5f0caab64af889fab749fd56ad7bd06a8b72d83b1130f942ea13c1a34ecbf1812577ca9ce88a0df98353b6bf924231a30d45ba4a4154174554da53a0e06540ddd5bbd80bda6c712eacb2d393e50256644ca044672ac681d5721d57a3d2b36f5405d131f362d02d360f7086530543bdd056e6eddf7109841946237ad1030cc04927252ec439263842eedde300f25ce859e460148ee615029f20850064bd01235ede6813610c8e1b4cabc0b2d70d78539d0182fa1f40e5e7ef2d82ae070ca3b048407507d8f2e7f7f9068c31a46d093d8b956fc0840cd5ae720f788626094a750bd69c9ab65e7b8035c270dd85ce8e1f1576e0f025819324b9ac586f30663ee34bd12d18f376b7cdf40cb4ed162c0d75acb7411c4bb89fd10db699bd050b32b46edfb6b6070ce27a5c241fb61d386cf492097ccc059af8a3d4e4151d119235a768d469e6e1d565b567de6a635441691c91e989be5333902c92ec5e6cd308b17a601a8b6fbcec7c83d96cbb208671c05380771a8d0b0c3fb01ce3f1dc746f70d426ba00501d3f5dec5202669d090c68718fd50413988a3736373ec778e79210a88896951cd1e514514a581fab28c82f151e4da366e94782f3f1cc0644c571be3c65830a381fa0364adf7ce615553fbc65f8f26a72f4d6fb6c8802e65f61435ca39db3f85d08bb1f76ba6c8c3e0712a57d29c52e27e3dfb34edbc418de55a8696282919a75d60a099e5817c4d81b227c19f827ac932a455832c5bf4be1bba015ab1742b8b3290a2e9b9c2a7537624ee69173af4e34ab5c49b99b3acdf78586521b7d628addddc1a36859b8f79b8217b781c8f9a4b6b5827b9a1411aa811218fdc68b5c1c0678ca25b5081c0e3152db45eadd4e8cbd613bbdc991b758dd7a5e765a9b0cd76ba891f5c209e04be9196809ff53ff3f22632d9b47cabef33078b50740ed0f2a020bc8e1eeafe34422364d82264cc67994897afd3465dfe7944a7bc6e2a997e58ef464802fcdee263af90836a2f6456aba9cc6bfcb329d99f17daf7ff2a909b494ce5df9bf31ce92bbc7ccb9e732906ad4ee29a87541ee6d76349eccf5c9d7c0814262d4badc4123a4c6456da52462decc5c576d7df7858901dc2d0dc4e88c8712637cea1d1c82ade48f21dfc7ebb2e7e574b54cc80eba0634f80db44d8dbad324502308500c92e8eef143c24328020d45474dc3a0cc2bd01ea2880f1be68222e47278a9c6fc9382b08621dc09b4729b04c0f0e63d240dad460d77ff87d4595350c42eb728852205a312d2d76990c9f1c8589fe4f5b130e2194834cdcb54bb388c7f977d7a138e3d9ff8d5caeeb69268aa4b9fc0d43bef0c71c3dbcd5f1624ca8388d0b2805287b3f16fd9a66136baef238a7c3280add275d7ef67c499c4f69a30e7bc7f668c2bed1f33779ddbd78c0dc26615d33e7df328ae240e8c8fcf4ce12012810aef8ff1cde2e74124317de6ca06c6e5bbb7a182ad3c47c65067bf7135b1ce697ff70979407b833d413c20ef708f8007b0371c9e8db0f939ecfe9e184a5acd59e91c9d118338d091aa496bc48dd9d280ae2e67272dac33c635f0a1ba7dbaec6ca50c351344113856a3a59b731fa4667cc076c0158307c29479f835bb30b24c4523cb12808b0eedc8e31e260a18082814243048c902d9502516e584269c4fc8e50a923dec5ff2998a842f9ebc68a435962aad1b0ea76b7e793a917275110c2741018cb14be13ce6526387427d424f1e13ba53b4add431c9349f50b3c61f3d8145d6be94aa1b38a8e89213b584e434a1d253546f1617772f5e838c071b9127e40ace55ff197b06f35d83245b85ea3de48088a4bd2c4597f3b16fb3a7c36cec6d56d7b1ae3ad5bdee3ad791f54533837cf5a69a32628daf4f4729ef062f0a7dba733b7c8eb1d214936c081c953662ef163e7f0ef3ac14ee73bd0ef6c2049e1b0bacc8f69514a06b623842675d886316682a7fec877e8fdb7e0ed0eac30edfc049b69a97f05533d1fc3b387705fc2492301889e45595ae072f3c8c7eb33e420846a20a5c82b23668940c50cb45c23d467fb1ea415cba14f47f037a70ee9f8735bc0da0003facb729d6a0d0c8ec68413ee73e37905d0bc6de20c572880da62e3251ffb982d41c8f2e90906532fbc2d2a7d25c6747b0511a9653a66f7ac49be061bed33989e6f61b6c90dc4be5bdc3be29e1aeb4c1a9ef16a63e094e6390511fc83e453f3ea7c9c69d8e1b4b8eb7185e9db238b3ebe78810e2eeb7ad202bcff13112d149f469f42474bea1ab1b469fb67a6fa51577e5b8ba236d484af528b1c59fab24742877332ee36c2b08022aba9cc045685f7e274b3ab3c7df070bf839f6f3aa7f978549c77b6daa1de3baf7c5921f4386ef2ff34066265667e2c45376700089aebde43b96749b8e7fcb4a5ac0119fc22ad2d841b284f0f63f353c88fd675a0f69aedfa8c5f655b6caa866868907981936b27d7f19619686d503d90c97178534ae06ac93a59520ba355be79ccd1cedd67e15497a3c997c443ec9658b23f1b5f79164d52132b29a612c6723d1eb5ac9b8fa9f21e760f1d2c142b937cf45b41e068fac75015587e3e36fb249677e54df3fe83c318075450f819cf4f4b843a55914ca0da4ea296f3f1ff1a510220a5d8ec022b45f7c97acc9a07e477da97c98ae1abe554431dd3ce5725b9888549e545ba8ab119cc04468b444d5f11ddfca9cad6e7c4eb6f3b9105d5d57e996b4191d0e3407e46d068b36518a1d6ea0a3b52f7d87251df3a36fb24a03f7c5db8c5c6302b94aa5206179293f052dc9b3eb7aabc04b4cbb80848953ed738a210d7ccda514ba9cc1476f3ee61d96f4ddad8ad5514f76c840e205457dee2ed0a9479217e90e66bcd8c31079dfd0bd32111d8208e3091f20bf4f6f4332f128b596086ad7af5e09de29efb4e7c07e657f098fbcd34112aabe7b9fe07accc09279f643e3b8541f16f5ba4f32019bcd54c1eb531607796c2d789e33ec72c23216461ffa8ceaf9fa3d866307c0a8f6e8ad6c5a0b1de239f2ed0d923623fbbcb1dd3dc3ab19e1a610974a85f73b73ea315834fa5a42b2f7f88eaca71d4ba180ad2ad6c5c77d213cfc5d4a8cb2c3e633c4f38b0f9052ec8ec2fa0ec23087d612a77d41a8ae25706f71d8146c30a9276ff05138c6b008cc40ba9bf70f9cd2bc6ec67090291a34232045387e6d696d03b96703894d074ec635d0c15fc9cb736850c7ff4f6b98685ccc06e4eff2dd1026323aeaebfaae06e2b6633b998790b4bbadca9fd68700d9338de539cc53839f6a9a8b721d880bd8d9fa196dde968eef8e37297c57dbda24f3c4def97686c7350027db4760ee218dbad664b4c05b1735c77cbc73b876000e0dab04e5c7a3b34a60dddbb1a60214d874e29bba9155e5cd1475faec963ad9889d4abcac18a2bda43ad971332e3cd0f961263b155b63b19f6689acc082ec27d2b72a38bb609078dc85bd576045873172549ad4c600bc0e1706b5bf3426dc6ca74812025330451d81d8dc643a16817af9e13385942e3c6c0de4302501a43bb027fe3d18b6e156e19aebfe6b0bf6e3bcfd181cda0ed654b92a432ba0ffee05f613fc4bea680446ad040f6d0a2ca458b65c050769f94b1fd0ff492b6a0b6fb50ef3bd9063238646f96ae75a893ae15709aad73aacc2b8a7b8fe44d356fdf879ec319ef9985ad49e17cec4538b4e00bfb2c3d8495d1480fd1f1752767a18ee8459454fce06c8b02450d6dcf50dac32e951453b0c98e1fe7e2e3de61566cd3079f4bac8fe404acf07237d0406210e2f7f800dc2534ee689f48eab0fe0af6fc8e60a821759fa76383dad01a00b11f260b7cbad6079e05eabd455f88e608c3615ae191cd60727e7de3b08ee483d60689edf9bb43f765e7e0c47ffd1047d13dac247f1268d2c8e17a765d6ff48fc1fed4b3bb443605a5ee55b42d54464497785436a0f74fa4669dea8b3921012c73af3327dc75f82126a68fa36b0e8b059e0de4009fd6a20d715fda45227b9c1d82e37007702c52cf5cd929535a777269869596a7766301d9a734b98e9a8c8701e3e1711199a014feba06b91cba96b9234a97e3fca33b91d122db83a8d142202854ab2a3232761483f03f31df63de5cc63b58cd8b61252b9507ef8bddb540dc9d8b776b8b3174dfb65a9d626ab4219b01b1018d9146f59ce21a0e7e386986366c79d2552b165518b868187328943d20724055a8b1cded27b78c287b9494110f2e8abfc61794176ce0f999953ec14992ccd6cf66c85b5ffd798751f23458e4c177ae9fb3c30bad18d0ec743b40924b4a1f2b6e89250695e6d01935e3c0dc9ce3f2c61b062e739390cf475be0eccdab1655502b070949a5f499d59b9ac08c19cdf28c1850e5d2d072bd0eb64c442f1810fea0762972bdc05e69f2dca7de0a19b63f62c1f8bad0b49ea1be7c963d85f51195ce9f1bd0aa38a80b89c22216d3e88e7012934b65db8af45671f79eff83301efe623453172d0ba0cd103319619761f18fc4e34707d1358c32015e5b58d2e1774988b84db402d051572d3f9497e57ba965e3e3cad30a43a1f25ca25b43901580108d3e6170ce01806ae1a09ebd08a04b3e1169dbab9c1aff4cc3f15fc8e5e0eb16fc9ca8d0cf9fe54a5da107fa6daa580e007636c7146ebfdc2ae45a23059b58d90f203b48680743b458c6fa916e3a368d1720cdf07855e13bd1f53e9b0853754827d16f96e2d2809ab3cf1bef14fc37c0d36679f5a0ffbeae887b99a3959b64faeddd853285608e2fa0c9bd35febed6fec065e0d983cbd8c187924757664a8a1a52b2b8239682a5f8d825fc5d821967a86390d3f67f8587cc2a46a274bc406449f1052635c7680e4e9e36f918cf459759ebe40f5cdb278094c7a3fa635c163f922471f31902eed7d9e3cde038abad625f7da1ff2405cfb3bfe5813747a1607bc223ff872c27663e9c8113ac4b81c569b8adb78072b471bf497600deaece3631666a400f9d1d4993bd3ba4a98d7598443f529d7b2949584e26a8740af14e66aeb2974dfb2908a269e07a87a3b6d1910f956deffaada1417e463f4834feb0eba9bc4e7a58344bafa5de615bab8fbebd6c604a6c28f82923c423f7b18ddbb6c0d221a0839a40a9884d694588150112893a8a72f7c1b4984fcc1f0b666d4868b0b6f46490710d47defe952a20bbe4d46929a59086fd39989c6ff4e01f33775112dd31f0a1c6b9dcdd8b1e40c4aa7e3578ba4d29742bc796cc7fff3dbea996345ff02b705e253a16c7400479fa29d257c9024a38eeff5a36f386354167a59e86e7d04bd74238bc3fc1c020d8ef2eed09bf0c5ab03ebc5dac26c2670a53b3545997577faa1e952be4843c1d474001a87bb15bb92d4b919809bdcaaf77a2427b0113d4248e67253782de84f09487167295a3aa038e9091ea44ebc09b7b2e963b73bfb07312b55255e0777fb601fbf2ad561399947d7b55b36cadfe8c39eb7f07a606a4c348d4dfb7a7fa07c989f72739c42e096be1e0d3c35525f4799d89fd26273a32b7e1f2a7e01a83b7e4029e125218276b6e5568d97e7d5f78c449bfad2b66c991452890e2ec07bd555f5c99dd50e59212de51211af6cb6827cc6f9b17381056e433a18e4f3c132a4c6fa4708fcf3078143f80a1559a6d8b9d10a0689f4fc61425db27380b00e6cca6a2b6047de0ad42af6b6b7dd3adff083c0360a6214cd9e984c8f0a48f8bab19ea50a2b93d04bd972a3a04c05abcaa20e346732c91b58a5944c1505ca36ebcfae15ad9c5c0ec3f3cb6acc271be14d2927f4afa1282d5fc7673887d6c08a279152ec4292fa2a7e6a99bf32885ef541c4fb45c9d15b181c8511ed5c9d4e44d8b656374146cad1bd6c602b892a816efe15f4234266ea2f44d45a8abd90b06e54939d05055bec508c5b76017b815c893115f164dc0b9432d6417efbd137f214c8b4370813d997f26f2f0e8c44ab8ea402d6defb8d32c1879aad03afdc204fa3b03a8ad00baa06f5196b4e0cf582ba8e2c110856ff46edd4e524583796744266489d9423e3782aa9b25c515402456613775356028df4b348b77d9fab9612c22285022b40352346627a1388015821ea8a747d8ded86809e215402a9017250fd61b106f216d465a4c6e822f930ae7f723dd1c57a98dd91bd0bc3a94b7d01560477c0846323eba415220177449bde08ed83a2c3504e52958936ca2639b5d8e6a71ca5669686015f1c645e520dafad39addb64f3cdbc510127c4e495b55201d0afc324cdd87093bd90b6f83d0e0404a25d82dc0ec66a1bf7b601f80f65bb70edbd5edfeba657cb077f4969d7c5e323f5719a7bfb8662ac24996a8f4ff1a8762f057fc9211fd0cae983efc840ec734e605f5e6509629b18e64620206d58253bb22bb03f480e42ab31a796e0f5c1ef57625322cfd184843e6bcc2a34c1f58df7222a7c3790433b7b6cbfd47646155e420cdf42dfc1a27c366d1293ad92df4a7d01a81cfbfbcc98a3de66d935c8afe64335bf1480a8af8d443af41b0bfe830b940a718fa880fc74a83a85b7952e907385eef739858601124a21e0f9a4c898b21e04eeaab7c59315e9f40da080a04b94bd2403714ee0caf44d35319f9ca87e1a6bbb5f7810a100f957f95485e85713654d9fed3233fca2ae425c10475ce586bfbd55db18562ce13e57a293b11411363781cb950e8e70e38012d6c02e4f06251476c14a2a30e21f8d950860e20028f8bab834f1efae6c6e81c0ec8f4c834273398f06eac1a065717b58410a03c109633270851a1f7636684415fa4cc530efff811b7e2571760fb11ce09e797d0e599012013e376f2e04c6c68d47cf077ad701153f3ea2fa478348e50fcb2e05a1218e862bdf9616d603a8fdfd2adff361b9fef6f8b19edfcf2c1dfee1fc8e86ee47573d83ac16d7c871877bce5751bf1fb09948bf858d43d70f96347b052bf2054008810e84037daf658b41a34c7fc8678abb1b11eb37b2de8f8389e05bcf1fdc816cc736219bae92a531fdcd671b2ea485b6e56463d81ffceeaf34ba5062eb537249b136b9564b2a83373bc8e934bfed3d8c66ad83f0e5d851d6cb23c18832a22f4ef93e2641ddf13c8791f06cb2eb2017ae72138f89fe1c85f2e57f2438348e6999c0ddd0cdf5438622640b6ee30796a4b4d4fb517e425b1aa9de428eb56285414240aa00a418661b5724124e29d1f08af8f6dbc8e834f574e6c085950342ca7209794a794e14fd583f4c807860e87029112a7c58db8915d116499f0af0a1cde3867eba69ca6fec51a16c8bdc9e750c35181d4f7b54624dc6692a9e083ad55f69109ba79b2e5a7c8706b0eef5df4ed13f955833c4d9949e2e0d44894694540fff8cf50e253a26f4c094f4a176a162a8ba2be16d894b1c4dcc572d01e04e8d3fa6c19e007a0886600ed5e5228041dea74138ce05528cba891a70b935ba81b208001a75e29d2736b124a85a6ab50e440b147dcaec352575167876bb07fba9e06f3390bf2e46039aea0188f8653456b810805cd2dfea5fb7bc626194c123e97da879e63bb3be3b830c86661dbc29d29651e32fd9ef156c95128652ab3a47c6b5fad20fe61d18d1220bdbf6ee0dedbcfb5f549e765ee92eaa151908ef72b29baed959920547f96ecf38fded3dcb668c9c703d66f37efaabc092fdb4594b46b673589c67e4df6a2dde5c9525290f9272ccc963edc4cc47133888733c4bcfae643754f248e984f476e63653a7623808c32001a191fc4ede45b04afa77da9e2524d9b7e62f44bdcf8820c421022116874f40f2338146e3137be335016a8271ba53dcbae0485fa7a147dc45253e19c2995fb68b0385cfa8ee0e7b51b0075bd75d651fe7d3ddcd948edd303d9dd149c607b32d0a90174e7fc22f4828b0403040a1d602dc520ec239a1f6ddf523322c9fcbc2ea02585f92dab2683442d7fc519df92e6f0b0a4925c5224814128538ab53962f56acfb068e00628c54edf44a2c23014629036ac7211e07919f61ca1ec7bdd6d8cdc431e8a17b15f65268d5c5b46b84bc09706b708f62613b480bef02adc1b69a6d5bf041afedfb1015a439e3fd36516eae779024b7e607e1162b1ff69c5cfbcc25210fbe20257827019ebd97ca25b9d8c639c913c715a18636bffd41acac736f050da63012a53f6c1bc918b21b064008b7c952b505e20fdf3e6ee9b3487d92442d100326ea15da1162c12039e7aeb3698754ee526c182ac4b327596514a2dd126671513eb609fe787f0c98e03b048881f613a66cb636ef4b84e0d4066f1608439be18e23e60e42ddc1d423ef57f7094587c682ef243319eb1523482389fcaf2eda2e0e9a635ab67b0b161d8c4612ae2a8f7a465881762b3bdb04203e209d4c3a5a1d307d42af73016e1c4a47140d305e5d3d32df9b6780e7f32a5b7b7532ed50614b8316ca9187ff652744db4e18faf3658f9dac1000d88cf283a3fd0e5d6ca229599e6aaf4f8ead73048d5c0803e47a5516e8e80defba2929ced244a30f268398d2e6aca80367861d605b2b6f7881fbc4bb86d0b6c03bb4704782251d3935d398863df66aaf9531ab00649afa44bc478bde633e739abc7aaecee9387af290898538521e1e1160f9429f50769daf79506e85f3d8187c20d89555cbb5c398c502e376a80b5a5d8f853ae59648e99eeba0672e121da01c3f72783de68543eb9f24feb5d9dced675119f758ef2efe309099d5c33536eea5fa0c5960b9ac90694b498f4eea9ce02ea426d14a9b1bcb9bcfe8f743c69175a6d5f83aefd3b8a60d932c24bd6bb1945dc905949138db8b41f2da228efe3e7ddc80a689e77d80398d4b50f1a414ab513a3f9abc133a91623d6d20b8ebfd2d65d872291099a3fb4c807b087aa0c1902bee1e3501cf16b2ca68898a045e3c70974da81b4a0771e81bd8e54cba3ab409e92923b0a21a569701e95f800d2f061c752c3abb3d8debf906bcad8b952344817d84a486d4828201d84bacde7a8aa2948dd5488446ed65d34c3747b3631ad3e9f16735ffc227092f697a856f366b8014bc69557d6a7062139dfcbafc5c7b1c36662ce66ff97d3778d183693ecab98cfbe941602d6e3c60bf6a9388147a45896e29d4925fc7e12c72d32a25b5b256206640e8fbd7224202e584188f52ac593e13fdc7d4a5e81337af345796bbd65894e0b5e86c19d9c8bba0663dc6bf4a4663b167bc14592577c803916b0d4e2467c1a2d12ac1463744b18af81d28cbe8f822dd51c1201c4275d6b79e3acd08b00f475003057088abf5fdaa30571ff0e62e419c8d086994cb5163abb796e86943142a8e622a6efa5ecfab5041db15e26d1ffa69136f7ae3bb9eed26407385b72a02e81f3a2daaa6e094e5208c38a84624c64f80fc81d7d9caad4b0aca4953b0eee10529b4a4272f97ef05b49630273dde627f6121e39afce8e575917826fcc131cf113fbeba77f2a265f3eb38611c8a5418bfdbd916cfaa06f4b95fcc0ca5d1c6e5bc48cc1e5d221e3664f098c008ab98cbc929299bc6dfb89ad30580cb2d69830d9a885934218be71570c08f8aac52d4e32de961368063aa7f72a913d98ffa0e09c9d377ac42652ecfd29241ee6369a7b3f4b167f4d7799ac227378aac77aa1c431796c6cc27a422919556157f6f7e7aa17aef1d26239afbaa735b7f0d4941546e6e0bc27bbd4b848c2b55e3f7b7bd639fbc31ffce601225043bc09205b307f020fbf96e734a7f9fb4919dc3c30f82b8b63a35c88b6e007f6f82ba89c30d72238288599711e000fdfd84d8d05ccce8b02f63a5ef4af63764936f48a9b443fc621cb15e439b6043e98eb58d7d2ba85d0ca354025c35524c05393588c75d4ca621ed4f66197e893b5c4e5b04b9496ea94334d32c446d995da7c8d59335a42c5a0d4ae1cda57b3c3b5b6d2c68cc873e056726b059a22e7435eac8a5889bdd2d456c6bedfe386bf519ac9dcac4740f7724eadde37cf22de3a243b3ed97a4fb834107019bc8b97092036d60095ef0eea350d29cf0be4f1e6dde1691453de32a5469d2e675f91846284cd5ea828a85746cd7346f2f8426a1c19df7cb0815d9e9d35290772034f21c756f88d5006de821cae6851125a5da3dbb48b8725fd3a31a25c3195c2e8ba295521c62e856e66d7b68c3d232e2dfd4170939f514605c2a22f3766d52b5005b92c11cc0bf8acce29789eb33ac008f303651b3ff7c645650391f46d4cb1a87a743c524c5842490101eca0a0b56eb74421541bd9f0ac39683603c50c99efc3704c9bea057ecc451baa944b0822355e3f59108a67da51103337deff97dca62378c1d07f17393775e3800100e73e5ff1c24bfcada77d9fe10226546939a9d4b58d995fe679981f0533832bb11a9dd3eb602c7f65e3d35cb15bed3a6e1d8b11e1aa40177b45ed3199edd77e0a2efd584996c46a8913c6fc8589617fdef789253f9279e76c161cbe4d3a8f439c28cd963cb8163fab40b9a0cd8de13abf7c826040a5241fa1a8fd1324eb40906f1f40f9188944362e983d39ab89b87d622df8b32b19c1dbc4d97c4fb9b4cc287ff50de6ec9487bfc6767b2f1b781c853c9f139e1dcebe1c1d7927514b68eaf2b0abeae8c442c775a20598b91456910c819132d19b30fdce330aae2ef32a90db888ef5e09fd5d747c5e54dbf130af6c29677c120ea94e61812530b76b1e60c6dfa31a3a4230c36a90fbfc8846bf932620e3e28c4e863b7992012014668cca1e7346d593a8ac436de93830077cf915f948917d0c21ec2511d831b32ecb99c77fa3c8bbf8542b01ca252d179aed4c24109a2bba3fce9bce75b80f13a3ddf96af9094e3157edf29411e677afe1127188f442ae59a6a5d2ed26c9cd0ba8d9ae3560790e40cbc829b4950585e97bdad5b3908e9a4e108f6a3274fc7915677b74a16091904c21b546bb01beb7c3fee40c8b41ffd07bca9a1187d1eb35cd2cce60b1cef23d58618b255a12ac6a5f0badb9af5abf40bf5d0f201b91b4b9cafe4b0d66c60f7146a6ee25ef7f750a81d6f935027d00ef70e9f48b75d800b0d305db87b8d9e39a1d152fbd1abe6e6dfe0340c70fd2887af99a04a36f173d5ee7210aaca7db26727a5e5e261dceacd56ffcf3fc2038d07ef4a93c12699dae49de9079616e9b38dadbe6bd1c3bedc967f150ef4f02783de16eb8b74121287049024fef877ebd8de1682faacb7962a8fecacd5370bacee8c2302191b0fdef9a79d4a18cbe5ca5ef3bad66fe55fefd8d9dc35e08e8bb11ddbcb9bfbe9b122a6b76b8dc66d99a064f26faf3096a4de5465ae8dacfdbb4840f9334475b8357d42140802c104bbbfa2fffe827859ed650ccbcf5c7dee37b288b34158a355889067261faf5af94d6d2e2cec9caca7edc1662e68a74fb41d9d5ce39fc9fb38539b89e1ad71a7fe2d658385463eff43d63f106f2171c92c559885af31c0ab7ae85a8e031208e899844278eea1d3da9aa5e4a94e8d9b73549ead2085088f13bdd567e1e2e23923072ab76220881d015e3fb390687449bc8ad829ab6286823d18bb8440dbec107c72d15f281e316e4c0548aad0fd8e9d7e7706a427ae31db9c2732d4cfdd671cb99d5c7ad6555f9f583a60930ec2da44dc5423637f9a3b655c284b8269e9a0fd9e446096468056e7a6d598190398341421726f366ee0261c6d0ad1203198378f1881d9ffe0061319105af7f2f9fe91357cb5033999c0c0f32496a4cf22878368556c146eb1ba76433e3921bfb36dc09e1fa738ef170a634a64ad9c2c93d485a7dd7d38a0895d936e29284af993f425c224c3c22c4916790c311bd120eb970b43307cb9273c98501ead19ca024ddca20ed8a78b797d4b164b3223f8a33790f94f1daaedfcdf523808207e8383cdfc5fa2913507d176d1630a08b2f8a090081c41ad355ea28606ca789cc2aacbe421e13bfffc564ea6e245acb8f7514f6f94da50b60fa95a3d256697aec17c633e1ab278fb4c4ba3acda78ffdd628cc1277f9432d2c681419a8973500ab4ded261d4b42b3edb16f4198e89302822bf11727fe79a5143b43d40dfcb1ef38a6ad491a788c4bda413bde92ef99e44604db7fde66a0ef8a3c4c3a30498e5ec09b2a65abbd1c10e906853cf88a05119aa502b8f8fd03e9647c81e1887ef754ae16fbaf6e387db28643b8b66a4e9e7faf31d087f5e1350257bc5c802a07998bf666a33fc3f60b28d9835dcebf8c5809e622378670814c30b9dd457159fb26b53e1c95e168660809b882ddc1c3d4549288db429866d34c76220154ddd4ab9e5596c13f60e13cf96bf5f831737c841c40aafa8e905cd01d7ab146bfd12aad52c7a685d8515377ebc87b2a9b1c3e6a93e0ac6a54d68a86260ddf635adaf7b09598a7d21c060a04e0c9273540f449264330a1d8d3f2a33cd214b7d4b76489a8eb05246f31457281204fd66872eb4057ed6284e4ad0f8095c26b3f54a17ebbbc427c68b12586e5104ff44053f4ac1f17aa6a8a59a4567d7e30b5394b69ac5dda4b22ba27d1c0251d2e60f627cf05e2c984cf15f84e0a9842896dc232d1347dd9a1fb0cbf58c2c039258059c52731179d1fcb8913b1c1a158858a408172d333c2f894e7877824f0b1507daa2733aaba1cfcbeaf786dfac0cf36624f6146a8173df41f0daaceb7d50e5dc2472c079d5adc8361313e20d8f575c031ede05dddbb7865d982f272dce26837d7fb61c6990e77379061ae6ce5b9fc9f3355bd4ff9a7db73f940fdfe0eb48a1152e89c4928723e9edc14bce90b22779c1b72f36bf24856720cb33f6a809bc9d2ad421fed5227bce558898c88f3f23114a453e7af0b0a760f9483396b571a37a4f255037ea0b2986f9a1f398bc80869d5d7d1de832cc72a10645984cd021c490e97306ef075a842a3791b2ca4816f3d23733ca16e917342c1203d8c846b1ab1be32eafe49924c8e1b81489d892215e90c59026138d530d1577b2f8010057e218bf92446dd05de7d6b9678420e0ffe060cb9412de06edc13e639d5a655b08ac6e3523aadd118ee1b108b5902e9f0cd94f59f9b21b25abadd84112b91a60ef254c0f394da418e64431e6eded88c865a976ae8b6332b92e02c324ce0238aeeeb94f1776b98401f04da5fb7e167fe892753678f7bffbfc1829c2ad70529723034e1bd36b9ca33716114aa3b90bd8c13b4fcdb9fc8a0235715a1463a91d7ef8814842283b1258808f4ad671c0e7611d7ff28f98300b79b63e266b7d0443ff9c99f7ca59936cfb22543b319f4ae0f8612416d7ee803b04c63c275d721f6fad0b60dc7a053fb11c72e33a78424addca64160ec17c71c5f0094cd63d2df90d565873ce629ff1f0bec2412a5253932cb1f931b36f566f757061fee36a8b4c4548793ff9e71cf318743f4a1c9488be3994f7b7e86c6e1281db3e77804bf2c7622474d9d9c4ca648988fed0e6d84bca4aac8479dcd701568470bd61f0c0b2888a1f23a35b559c0b816acfd6c1e53b892f17b9ecdb8650498a2eb11c812c800ff12a02b563beb2ef9efdcaaab337fa9572e92eba5aea0bad4877fce4843427637b7fd88535a30829795afff493e9998b5aaae17cbb6cb83b561a84061beb8619da0ca7a2e5142f10096d9890c65502ac423a1b164c23afa34de779d0ff0ef6d883f44c9628dab15b6d5dd7ce05118633e841f563d65ebd0b2614094a2e1b0de1f9c3f230f167c8dd67e2a20fe7f90ddff7b06f55b7462db05987eac44bfe9432bff0133585b7494c9a4c93b76edaff2e6d22a0e93e1e9e1985c9f8dda50822ae7747a8ab46ba238f438985335129a133fba59fcb64e969414be2ed36efd293956e3c89c5ebf846283b6a2d78cd2a5e3858e18c51cfa4255a0121b4af12ec4a3295fe949668d6907f7b5f0b9f9640b239d6d6367073680ab93f2cb1851ed0aacb307fe3145bdf49df5fbd414e3c225d645aa86c26f5896f1d7aaf13cc0a00cc2dedd5d3453bbba6830d804ad401b8fab7f6510dba3a21d65d5468e1107a7ddd63c06645ce6c7f89e82fb95439384811ad02a1ef00f16bca32421490c87f6d3d140d1ba6234ff9a3b74e66e774aec2807fe18700587a5090a6aa5f0f00e868f459d93831af24186695eb3c33d68cf6df43d2d3d1bd6f6420f1d7ef572d8e5d1d60d9f5071ffaab15d02417b4d6c94ace7a8246fb6bb4c2d45f04ec2f44400dac6fdc84798834340191dc18b137a836fd394798eed4ebfc39be3850e33893de7f928deb834d8cfa9342e2eb1250506f0d555007098d0a21cc8e4e3a636eff171ce4160a842f925ff50c3b1d257d699723b3b0d47225b092139d06c9043b87c0bd370d17064c7fa9b35ecfa6c0acd3aa3ad8170850d3c9a5d2bcf14221d77378e28dce1070af311c3c5a72247d9a43eeae38c0fbede23f500cb8a372df5b2c6a1437725dbb82f94dacfe713b8854c1607ef473d8b437bcc5866cb10a8bf9f7d056e6501d2e89ee8b52546ac2c1153f00b7a765eb435eba65bac805fe592142aeafeb5019d6d0f15a6730ce85837e2a08478c2dbef608b0c7912667f3576817d187ac4a22836bca24addffac70c15cce5604b0d7749d856cf75f7875c50b747ede9a43d3878708283283bf908efb14d4544ac28e96a7ef042a54ed91599496c40bf9fbfeea1a49c7760449c5d4f7008d7224d4b3829aac6b55a3f2295966d31821e20de126a7bc34a17d65f1db753ad4868a847c95a79b6d1b037ca9403f12639c5d94eac2e8087b0d302f914fb068290f77be34a0ead151b5e673273b54c0a986c85101d3616387644d3d535905e9baa83618092c54841479a06043804e081821364af4a5bd7151e77606ae4756e415a6debc80fc31e0f40665cb4521ad0eb25f09c307687630652570d83defe779d94d8bda202dd68b64b7f64c39edea7b911f58b975bfbc2de1c1ccd55bbd5c5d98b3e3a6a44899d4733dd5e73f5091ae98d83cce87a252d710a63b68b6b4d738e78b24b4413463850def2ac43fa0a87b9fae3d84a53df24655d86dd6a367f92eec4f52a2dfe029bf0d39fdf1562f38419a95fa3f1a9cb44d35b944c02b499304de70db1430a535522898b77eb812a54d0a8bdc3eb5c07f12e5c215def461a268a01fc77e2f3d43ae5daaf1092ad043548adba9db475f903985cf2075e1dfe217d44105466f6f107349c0290aa4f7e2f5d3a1dc1c8fde1ca8c79332014b6cc839bc05faa9e5405948cb91955c07e00dadeda8f0dea0a8e6cc6a6d93d20b769821f5aa4db2c0998f274583e6e5a648eee828a996341e1497c63118aab06c06c7195b80aacb62d6be6e8a10fc50ca56b9b94ab03a3c338e3a16be7aaa6b3d385bbea89c81b5b907a0c8c2fed07770ad3b1c8390f4c1215313e6981235160fda3bf0f46421b834856c83c6c42a575cbcd255cf4e9419f56565647bc1406f4aeceaa601732585496c4d0fa05b221b55179c211b90934b756c7c00afe15894635538d2267924c6c244a01bb536e08dcd1b35887db3d746dd7bc14923b54a3497da8637dda356beccdc18696cf58e69ab762792d874aa1e44c5a8dd577974d1c667f1e8a0aa72814bca3f937786b74a13198b9355606f8b11fb174a8b8b2d9c81bbafe90bebec204a3a93050328eaa3285f2f056199597bcc353e14b308bb5c3e22d91edd401124e03727bad236899b8fc26d0b51dcacc2b0da9414aa7683c3af2393cb106ca6223d4bcb37b77706a31bff303252e2c015dd0cd91a28fe85a9c28391e988ce70827c1db78ced988d71963e3e6de4b0588101375f33b79cb8d57c09a1c3637663da52523aab19532c031b883922e4ef836f34b515b3dee861f7907fa04c0cd4e083d68225d86851cb9f671c81672804714a9020acd0ca0be4f9c33eafd9286b844fab9c2a8580b5f79c7ed7992bb34c19eb5ee1aa38ebd620c999b91ffec0902d5fa933c47667c0628272ff3e9d58e623049ae0c3caa0f7223a48bd647a58ce1e95a62ba21b7505121cbd13411982ddf338793177c821ef7e2454dd2180c7e968f24cf53efbf7e962f769ded72c00c7312ea2dbd47ca95ca1eff0aeec8a8f331bd7405b44840cb0ba3b0cfded40a208730fe62e537c99561714de7d4f3c81e0824d7a045db8da8f9c88e1114a9a0c97e1fccb7f0126a95d942350ac132157eed442117c22cd69487a004c08d03eff97569e18adf23d2b54dbc924433b6efe4e20f42311ccdd66943bd5e31db7d4b1052446626486800a178347c5475274751719c7ff66073d2120652cdc9f1affc2a350583ede431cc85ec00dc441a6b529592a8aeea99047d257a05744f281982f8178c9a1364e21c9dd63fdae573e2b47f87b138a4b3597377a507e898492dfa61bb255c40fafc8bd9349896abe0a08b191cf1adb21432660a663656c53bae3b8f7db657878b2bb2d93e62ea399aeb6f5757e775b8e7fb3696da882d24d6f9465f1566edc0d2d6c08d2cd1a5dc56f30f9c47f78fedbd58d09ddac40b279026d513b7f9c1ab721dd1f8a6835218b0c62d8e03c6af48d530d6ba7c74ed3f11b51ac0b9a8f319ced2cd2846b6ed308a1551551dd598fd2f406e8731af3a8da3dc6fbbed744e4b22b3d73d5331bbb7245082ac9df6d72fd59db877d9b8bd442d0f671ef0eb2b872439c1eeb6b92368c52b662536b1e85645705511119f00949d5f2890652d1a71d5457674eb761b9d02657498f9b9f7bd8a2cf1cd6b1d5b45d64c00c7f2be2e546ab6e74d491898addc3e762c4476cddd4e5711f5a4ab6153e333204faa185c56c2a81628ddbf4004ccf4ce649c120d20fa33219d0196dcc0c7bafe2e34eaf327171a72a52c93528559ccc5961e1d502b158a7a701114c47f35cfedff455c23a67f5de66887b46bcda187dcb46f00c16e2225e88fc9fcbe5667a0676bbd527d371bd08eb4abec65801c226e021da0e0526dd1882755901482e8070572a43366ac23da5a14bc96330afb604b5367f64ac9fea96321efb0ddad7c329b3feee015b6a668e4473aa520c94ec95d4e367b50fbcdfcfd81e173052526cb65a34aa748476112c0c25dd60eb7a532d90f541bb948dc26018f4443bc714c6e67c0a18dacd5c6141b2ba8cca6bc820658d6de9523a8a42066fb0b3b56eed8f9ddf2d3735f87fc49ed82542fc2f8c4b1b71b1ae93c62ea07f1cc052c9dfbfa52f2f180943ca05feb7d5dfb04f57d4de9136542f9facb60af908e6c4a047496bf382a1658ec47d3a27be7027ec8555222f9f16dff7029983ba3bf0e99a913ee6f98ae03bf295f86469f935e0c0e89658d116a697009a0ab5a99a7434d55c25a770d4b57a741a55dcd7ae33ee33e819bad15413789fa3f1a6f116bd45c9cfcd8f0de0fe6c71814939633b8cc3bbab36ba416e0fc45a5ede806620506a6e5e222f0eae213c7e3a3a359fa4354a6d9e04dab5ced04bd140a0ed447f9ca458a9899933495f0337ae057093e52ad9aab05c6e4e161a540cc70e4f24bc7140ba401b836897e8651eccabf4fc3a1c0c829668dbbfc3448dd5cb20575753e7b1fb97a098386a10c9fc551021eb23eb681dca3c440b98b9bdc80723afdf5f22bbe5989755e2129648133ac04c1975118af613dfe9883d2982cfae922a19b44a875ca75ed3f5b92f704a2a0c8ac787e9f090f1b0c6f66223985544b68a5696f2afffd15601443e29d2afc6d9ffdb4f32b67e4e8720fb29102cdf4383e58ccbbafb106264e5a2fe47ff0f0e573c2e98b849a9f1b3129686a071e9b57540cbad68dd72e553dca204ee40ed99e0367ca45e42ca058f9c14da69349c183d8fc49d8236a0e81c9daed7082366627e9c95f72f67acacb320ed35c915d1abb8e49340e41bd3c04cc591a115e1664a9b6d8397097d9a6622a7c60e7869194589be5c0c7d6f0854dcb9f535625af328875c6266c3c0ff3df818ade7283bc1aaedee4b29e90666ccfe4e2b0d451f0972105ad695abde4cb846bd99573060701d477496c20f5c8a611cda86e46e6194b8b2974cad6b5fed3af15df6447fedb1922d54f71e325e7f27a8303fa42f60c14c6caab36ec22053599b1091540235472e37e774eaf461a4a64c54b9a482629495326b53b08c825e0d19a725f14d12fa7e2efac47bb2cbdc598af68f24e7f338c5d55950b2d47e09b6037e30247083a29038785da56134b57863725531cd427c13af0298dce83e68f17d13a85c2e28fe7d34a05250583b1a4732ca0090be652819091c161205f7edba145eb9f65351a85ebbce227e9aced84dc34de4cab1af36f52a01f287f1b8d58f35a17306270a19c057809e24ff4b78082df40a77de032f987d7827299f616be6249f4e5a3e190cc6aeb85ef605e27b80001a4ec66357ef621ad06649953c201770cdf8ab794ba2d74500a65aad04b9c8d793237185e79aca34c5b8d3399be558c70e4e907e9e70d798d62cb1888b1b0d6aeea4ab6c90c9a2b045221ec0a1df232b6bec70ebd5accf45927311c96e3a463d03039a27c137caff88b36ad06388da213ec1fc0c75c6c646faa14da7fc748dc01be9e6b62236053d79a50181fffe0700fd7d78815c3b99445ae88140febede19210e7dbb3db72b4c55b63cfd78aaefd598595faa58f9e72d00bd9b102bedc15fd31f33fd3a840c19987a91b1142b1f26df9635230eacc243f27b4fce3b1ef62cbcee2b30f3ac216218376d40db08bc35ad5f4a6f5ac0008a9032ed17e78798de71ba21709c63fddc113f14f320799c29e7ba89871e9225ac953bc3457e45470ede7b9fcd70714abc8dc19a4802bd06ab1acd59d69816778d55e7c9f10ed257d28e9c6e9ae0e3d53485a20ef6c2a46d6355a64ccadb040450dfa5f12c3f535c296e08e1183a685b57ada0ff8960a6a0d895e09c511fc79aacbcd03026b47eeb3ab4eb57beac82492303e129c3e168028c112518bb7ebb9fa4269617cb2ab61484914993a79a3f117434dc928047f2f549bc7fd0a3c4e593c7a554d046a94e549cf505fadc3537301f3be458add522bdcf5fdbc9942dcb34c158cb713e2df0ef0db5c7ef5500bff6bb2822c71a88b2c094d1ffc7e130a53552b4b3fab54e8372be661614df20cb7396a788eb565e30979e3c2b318a51257323b0f99ae03d179247f888ab731227111791f95134c2efd1dd44ab7857440fab93bbe07e6ca3e9b0d5468aa1c478ebc60606f5716b6a1bb53c366fe23fcdd205369178acd5dd230abbb0734270ed92436b5e73d0bfab9e956be48f2c31ad986acd2dbc06dea2763ce85e55ca73fb13e3d12fb5e8267cb7450057e4f4a0d1a7e3436ab139ec637c0cfd8d5bf14cc6e43cc61665973524a86121c07ae6611e43a5adbebe35549b42a4488fa0914243d47d13368da811e38483b67ebe5a4ea2f09a23b70dad0dd3693ba771899dce8da192f9b9536b801d3e0391968da8416b762aac180e30add2c730c85e400c27b419a2af339e481522297e3283566d296aa7691c15a87bd8c3a831ef477e13e9ac3d44e62731757b1838ae3b88ea3a5db9eb9c7b38bf16aa75cbe2ae9faede2366a17f9a208b3da4af81b2af3a7ca7b6a8c874d5f0d59e20a26143e911d4ba99925a47c5cf23c72d788bcb756a75653bd55cb0c13cb93e930b2e4ab236318e85d441b52af6793996abeac4e692961f7d335baf155068a2e99625def90b8434b80357e484381a791ed7ebf981d7dd5c202a15bd2536845660dff3a9a1ca6e9b7a2f904d1920cd7954918812ba863411a026440fbae3dcb3459d8a2c44695d23eb3abb56e2dc1935632787b33989b9876c6c3b03e50021740d3ba464d536e85a486004812ad1544ed10c4751ae13344102c44e50695a569ffe6d4083d5b26c2f46d7c5840c27856f45938bb13bd91e193c4f61c1f5ec2ce8e3a322a3b535a992633c3c82b62e5a3b81eee21d620fab80af635b1f85da35d204b07e5b6455d3db7e352f9f2968edce3a0c34fb0ac425da027b98d509d0862ad351763d7c4c9a4432b2cf741e2385bb26e7acb333b093aed231bc695330b188f140dcb89d752b9f9cf11716a076bf19690e8196f0ac4483e775625500edbb88e78a3befb70cbac0634ae3b998aa0b34db39f0c088f2196550552015a405c20cb171bccd981445b21176c24ebbbc32b2931c15a0f84fdeb8a9650f6af563f60b374da42601a6f7c9e1ac6ecb854712ccd5a9e811cdbe2229d8d517ff7e809e758bf7c03a88884bd33f7f1cff3c4e317d612e57c42af0da0deca619ec7a16f49131aaa68d42c4119565da3af3aab8804cf3e81b9c4cd389bf1c95c229a049b696d2f20b348b68d1c41441158a1a866446164e9fb4367dd861f287bd543eb164f57b1e80985bfbb0a75be18ada1ab4079301502bc7fbc086d2691082f4fd94c90c9429c99a703d724ea4287b70d58759a75ea71106b0e9745fbac0ac1d4b8d6b6c06b885413e3165f0fbea378507ff3c470a9acf63d241777f486386cbc66755d170e8a5a80fdc88d26b018aa35739993e7e8992ccb2ccd4edcba28e6cfb6241efe1689dd2f1aae17a4c1f765e5136a2288db67da39672195e702596a0b70b47299741f4e83390e3f342c046f2545766807f7b5d7ec0d867ba5e086ca36067a3e9c48ae593e101c9b517df65a4d2aaa16d3c996a1fcbe7fceb97a1f5bba29715407900f03f4e072335c34be830a347f75b74431496e01bea0f6767c3e7094be5669b514526fe0e55e808ed29f649542d2b641308cbd9b5f899d3fa8557891cc925bce017ebb6ad0c2fea702cc88dbcee394038c6f0b340db763e5fe15587df7d396da30abb4e3261a3fd41a36b17646fedc3ab94e585e989dab3ab2ccf4601e272bd1340e99ea9ed62eeedc719733b3077aecc88a1a77635003e81c1192d817f52afe089fd96df5f61f2c0f4bcd6490acbb9ee362247b8553860b5192d32b9592343c52f51897b45e3184c2986c2281572bc18a50463a2047c234fe0e7182c4f80600dd2c282209d207027be10db7e706e71f17e9c2ea51fec610fe718a5bca17387fed873dd0ecd822921d280487ffce790df1cf8e538c3d2864ca7532db8208f4bddd4a0fa9fd8b38b87c921d762cbb10b490af8262ecc0eb162b9d4218721a71c19618ec7e0392b9cc9ee104ed99474ae02a21b9af976b7b126696d075bc0c253106ad98fb7112844a6f5c91d2dc74cbb81d0225b2ca6baccdb8a21d08b3c500449aff7cf3bc704827acf1ed25ab076a0756d4f435b96c7b3f78793c311739242dff63a0ea974782d6135d49222f2d66f3a801a9f87eddbbef3d4f8bb9d14697587ef19a190562f768ee29b79563f4a7c3b9f906cf54cd1badba02d2ed7fbd5748988759103732fb186d2d1f2107ee1e8a706dc5e82149d7ed370d425a67c3f61686c652616e5eb6d782798ffff47b0a697a02a767655534c1bc1ecb71534b1798dda5c59adcf3a606a08c470d630c48c04ac34f6fca0baee01628d8b52d35257db44e995f3902ed32a84115168399107f2e4ce29733e5e9885f890cf53bab977906c42053d92b91831f42ac0f9562495c29dabe1162d57b2afc61d53cc893522818ac13cb266406b6659c2b8256401656e6cf45e43faa3b08a05dfd0307e6abd2365db2c7b13cce1b62c296d1b839899fcb4ddd31d17929822870756b93efd48f65ce56c0456ed0d376d7ac275282beacdba789253affafc7c162cb205178b92814a447c0a58563eb212e2c57693c25a42d820dbd5bd9df82c38e2e0cfb37823dbb5eb9924a848c83f5e87d53b324855499615300e8bdfc06beeb90bb2357e729f1f5c9c1ed405708ef046d602192ed4c3314b2e882ca19a175bf3a2cf2fb579ca16a4a008147684d7d10cc978abc1a15df0999d00950b92c34fec9340a25bf95e3b82f74b046c20be1ee9cea051055961e997e5c2e314141177a745c328aba7fafd05149b4430135836eca3cf076cbed9c34c3f7a93b6a8e8231266b24368a8b85c694bf7a30a046b74e25955f3615d404585759d215c38ced97abc0eec14251fd0f3541a6124ebe4b0309aad20459f750910cf1fbaaa49b7ab023a7244815e1ae4f5a299123548226d512bf52995aaf7112bc5470142587bad7258cad0ffbd9e5cd720dddfb467a61cac7cdbf0ba8be4be4d5690cc6bf9c2cc7ba65e8ba0ac2bda65aeb969502aa4a1c78e079b1cab3dcac5fad3618953660b40eb0d3487153decebee55dd0fe8f3da986268e7f980ef85395d02b277eae1a079b0ffe9df8b7a3dc7fa208125193c597c5cffb5f6337d58374fc5fe08c0c11bc6d7d114acff3898afe8a8eb47c8855983dbf2c57e0742f3e909cca9221ca770001bea85283cae48429e1466ca9669a4823e5b2842c89a462f6bad5c9b257e8ba1d1adb45382c5ac695d92683f06fe1838ee8da71a35741d3e208e664abccac8f311e8eaae2702f75199eb32efa0ba3d986638fa160096ff52c6aa2eccb10994de7ca31d1b41e75e765d546f0d29ca1596c66e0a59117b2fffa8965517c79dcc1dca80245f37960f606b468de54d8c53a481070ec5a136a228e38daae7fade7a9901044410a0622afd92bd0f75e4186316e3848d975077b9cd2f9445cdd53f8b12d9e9b84a1253f28e335bb5e6b7ca142fc70ebfb9d1a0160d6b740c7f920cb6156ace9a7ddb1eda66d2526151335eb012482b2559b3dca10980349a6a79919a7f0a27b29ac634589715ec9960c9368a5d1e5ad6a54b502b99f81a72483e6db177ab9e6a388a6350b3c9d4dc1a9568f6ab37f0ca9fdff3cebcd75ed1a9d65ac211bb086247334fbbe72d1f2a1ec892446ff72e425f1bf535a9e352d6237dba279d24f2c4cfcc15f18a38073955ad568e208d5c2fbf44f6991d6bebc2314ef3114de5d33c5825c412fe9b8e1ecfdf5e6895522a11fd82c8520579b6699f756cacb3ad361d18f726f57607606f009de77c45a37eac0a5ef501ad875632f44b65696370613cee04283529bc539ff8ab8dc71609c730c682f997548c6b0f878fa5c3a915d4a414fa995b038582c18ac14cbc38eab69a0cd06cc3829fd1955736bea523608fa040ca5f25a1c3b078bd821a093775a22e45f03aa4e3f578d18e9653a78ee96968390f999a04d4d8dfa929f14585c3c59118acbac5731584424fb8b054105c18503ba616bd91acd517c11902cca023e9b339c2745b1441bf5902189d035786038ef7468d2102e1803ee2d0823380214cdb80aefe2d9542231a63182d1a4d1e8cb9aa95c7dfbec0e45fd99e01260ccc7f6a8797f842dc1b1c4fd00adf9c01213731d793ed1ef15cead98ef8ad8600a4b6c22c0b4a6ed630fc3fa6edab6ff1cdb93da7fdb01482529b0927e00dfd849da00a5f0a3af79ca756dc81bf38b55dd992a5c4b195fbad7879170eb6583ed6e6da9567f48b6c29165e094ac78c9314885ca81dce5e83d20ad5abe1748a85a8d77797f425d0c212ecb2d9c4340080c304ee4ec611bc1b4c746c2028b213cfda833a8ab031bbdc86f1573794918cdba8b9b12446de3ab41f432c06b0473964832934b056df907d4d0886174e93207012ba0510a2a720fbc123df3d7973994a2d37d17bbde65a9052c32ea4a9eeca6376f6892efaccb15f2d2f3147e6323012227e06df99c3290224fffdbefddfc0419b35c43f3ff605622c3f1f637d705c6f85735332539ddf944f08899e9f10db362360f1fd81887d9ff1b19883e160d33e8c43303543637dc2ef471838e675033d6422e75718011fad2d2aa95b88ede49e63515e01b4a67dfdfc10a7bdea9fc44c367b32b5bf1373c93f7408590214f8917fafdac853e0ac06caf29c02ddf46e3e9fe6dd42cbdba99f3443b32c03844d7317c46b3736ff1790c121d27f58d02e031464a79d14cb8fa87a0f36cac25e161ae0c86a579ba9dddc25c9f22a894988eb3f082a4db6364d4124b163c427433707bd65f8749a2fe9e48dbb95ec522ee1532647ef4c3d3914245934d1956b65e62c480e138ea381c008cc36ebe541931164619c0423ad3f1b006b7180a670f8ec42a1c5d23adb34f94e8923b6cbdab6e9bc461c1d4e760aa02c9a58ee57060bdd61e69e418db70caaf5d627c8c28b279b0616573d1156edd31aa896783d6b9d8476c399596f6212b2118d9c4252fe9582c1d7eabfa64b63eda4f02831d2c26877654ba5bff1f7221ac21e1978691d5f0ad133cbae796a41c4cfcee54742b8c32b3b3ebf665920ff9c5064256242f9b3123960dfcd6b8b565b05e6fa4c242869cd191ecea62ea130c4022cc75d73722e90214529268a1116da3c388f7a8444f2e38fdf232d6d937a6f927ff639e46822a590bc08334165ed541fe4df286b04e692b3dab68fccca13f343cf2b7194d964600e40c7e01bd482923517bb537f3dca989c551a8677e92a8dffe401a379e020e8cfc5a50f208cb28d2277a3f0b757346c8c5949910935816cff07c5907aa121737b5ec576ba6eb598ca38df1bf9f9ce58e7bba9a326f1f79c371601885cbf5f869ef7ab61de86aab68cb84ac34d8b00719f0b9d79202e34709ccd22c865f825a4592229932b87c68c24e499a99b9be071737a506e80644bda5c286e0eb35d7619a4a482c4f07da3b2775941a499b0b3f5fbd3a203fa0d071d210b358c4f40f33f26ab5ab24db6090e90ce194403aeaecd0c710dd65795a035a4ffd32be81f52b095c2eab2cc1c50ace483e6767ff07df49f26d32563d8694edff2c0dbe650cc0e0d8a78f71854d8b0dc1758155cfdce898d62e813727465086f016468572999e70c8f7599d3a1354c71f3e8daf43b02ade7568ebf03cb076ca99107f81f04cd8748062fa4fe710ad3539493982f23e810a3cd7cb9e0fafb22b939132219f65f8402a77a4dcdf086e2f299026bd5731088b97434779c3a91f063cc9067807b9929ba5c956722dc00482329780a6bc4934025743e02e0ac2b844c3acf44352203a5947804369db5ca4da286d75d68d6f2422be879c3877257725ca3a84f81a73e5a81878164c130a1b53ab3e07a3aa990fa30144de232cb800f910443088a9cf5087ec0425b0832b30765179ff971f412c48acc27764aa2970c71ea67c2ac841c0264e80213a495c07cd7b548cff5f87453f314772d0b64523a4ac346e9a7638a9778531cbd0ecb60ebf7c801ca4a42628954b6bbfb9fe749bf421efef45f71b970627fd0832f00159414c0fa210346f2d3845a5bc917325360827db8e375bae6c56f410c79ab3a7fd70f1a0fba61c1a621bd058c16c7118420a037f5ba8d7260f0c897b19b656565d633d350859f5648c8160c63f2ff1b56819d5bc90febcf4eda5c0e7a2ef10149d7a5baa45afa7f7d423f54220f4342625a48a5878718f04888ba5c4826dbdcd4555e8075537bc473dff94aefec723d89d81838f646611219e01df5ea5515f5530b358e16783424811bcca5e5316dfb61a8f67d84106c745b0b170bbb7d42d0197e39d1a6d12114ef37488a0715d063e84e98fad7e342e2d5b3b0843cc1f456b10a9a2644297791076801cad64081674c08925bb49b324eabfe08f75c12f46308e710d3219f6941204b87322f0d3164ed50d01c8238460597a83a713ddfa14a8bb5daa0e983775317d21c24c17cc8da373c96620ff27c31f57978213bc7edaf03112cfb1fb3997129eb31d5708c2a6b605a7d4b109540c96803eb938dba7cea21c5edb5ca7255aa480ff3ae4d1d188366b91b984cde973022509fd9d301368dadd383439e5dc7eea2bb0e9cbb660c7bfc0224403fff18a8daaba7fed38c06919eea938ed5adc281643325d1de87365f00aff9d50c68036a020b8313f0a67a971cbb6350e14f0a8c06aef9954c8efb6b4be2fb4a13d688109098852e02fc55bbcc01baf052648cae44a93cca4fca29168dfea1d06b9c9344b8a374f7c1058344a47001c9ffc08ed3d0156652d9f2882615ae76d8d1377224a84dfb298c83f2cfb6c3cef1f849519c9ecf5e7e52e62ce9c66f85a9400c63fbd02b3d37e13f2c89809e12741be003afc88f995ba60b5477650f63df60bd30ad03921bb65b4c84582d912426a153b537c7d824cec8e1dfbb33b2cf30ccb31ffd013232d3d53c691cc262cc171a3ae9da97cf5fe677433728acdc3294ea79dd250cea4d9aaf2bd51a0010b586dce393017e292cc0459a835fc652d7cd66abb0500d95e3f04eb309f3ca90dfec8c1119c691fff1a04a384ddcfceb74e3162940920b76e64c80cf4ce4a5b3cd449c839b19c2e0068dd8c46fc506e9a905a4a16c3d21665a0916014aca5468390f8ebcbb375601afe0544b194eb97283aaa499733fed3944241086a1d82001691b75fc051a011e1c98651318b48b8d109d821cef3663627986bc49ddb55b93d60fd720a8759f315ef947b541981c32c403ad430e5b9cc87be358fe514d4d9b6ed211c77e72c71c136412728fb037faddf07e84a03a91bb28feb3c44a96604d781e3b8d100b51b651e029d19fb6b5261307ebcf27bdadeeee7c8fc6658785cc1323aa2a7f5d12d639ad71e91332f80ceb3111d8e701a815ef294ce7e2d247052c99e9b64413e61c87e1b7e96198f8a6244b94b124e7b2228ef653dc35b48e15a148664a360d21278907392cec5b37ab60d703ccc71f2016f33eaab3fac531ff92d840230d2a038b5e15c3e482c42b2465ee1e0542fa0dda7d5f5241cf8536fe98c4de80910eaa0bffae1397a1967e7b00f2afcddcea6023357028ec884ed5e5dc38da4d704f6259f3058d4bc2614739cc6230c9f1467c35c8bb4b6421680020c365f619a407f45cc5bc0197069e6991aac28e3f1589bb59fc99ca1b5aca2284b08e441eb576f2b708b64d414b2223e46f6fb55225005395bb1c8ef94079a7df2d26437051e149f6544bd10a66585604ef294c9bf9a783b17117ffc3a05ddd7073b629bda6a582270f3ed12e3ca40a9a83cd1d8148aef840e8fde04a4f2942b5900b7c79dd941f72be5dddea884c8421293cf08e6527400099672e1288e1ab957df1ba3090fe9aebeda5b48ef6bac2a39fbca30b5baa3691d4ec7661bcd2bdf5ec4f2d7cc3018e9e7da8f9571aa2501f9d3d5678091ae413e81bc9368f1193fa95ee437cd27447d944094cbd034a04639f5a304cca9a0e7589ed157bf66477b1ff7608fca9fdfbff9b9b3b641b094267b4eaa879bbbe76e5fe3b015a3336b8f3383f78bf2ab4a968fc14f467b68e18009de8475ceb0a13775033867d5ac9e00a1c4d5a6f5ad2f69652ca9452b009ff09ad095eb8a6db7857f58d46d363fa463fc134fa3b11e9f6771a6f2818488a1dd0eba24361a01fecb7e7fa36c95879d371110431afe5b190ebf9bf96d76a7d656fd916b7ba6a3df72a22e7f8661fc8cb2f2f8bcc402dca7903099ea45a6bad319c9925d11b7ab228d140b9602559a94af294a5861dda3ca1823d7102aa82c902ca87294fbaf8e1066773434f1625fa54cd98ca2689c6d0a40b13830c459e89145190512203021688f0c2e48a270f6aa9dadac31319ea931b5ab0b8169a685f3248d3b2da7452da462ebdd1dff1a79452002061e5652d38a4db6f474f0bee86647a59b8e61d679836600c2ef3f08e993bd2f87570154d0a799e770156f23cb6e23a6b711d851f5b85978b599ed8595428782a5c7724fe3c65b26432b71b8070250ed368f7cc73698f10e4ada265209c0cc442f66c09f6e59d1439ce10eded5aed97ec58a3e1c4d2c8c1810e1a3b3d3e1198d4c795cf0a885151974f5e3c88b9590766f6251ffbb0eddd521c6ebf7d7d1222190c84c4ca6019d3ca72c752daa42802f57dfdaa61336d4e2a72370b4f3e661bdddf5a2b8714b8f2fb8bb96c96534a798f6af795efa4cd6d9fbf688773fab794d2369b062510490c2d24619e2419a1460b12aa27ac16992254f8d61a37355902b01801451528a84070c50a2c2c9cd43047c0b086504a29e5374f6e562062840e55508e65864ea1c2e3bc10224bee8e5fab51fc54a5544b96268cf820c92029cb113b6a94c8c2e58ef6a7c097f7dff368fdabf55feb83c8f79ee9eb61cfe3fb9818c4f5dfc3c4204e41c07f3ddb2ae879dffa59f74734f9336bb63694a306866c035fa2c758d36511efc8fb22f0bda7542c7a7deb0556af138b5a2f4523ffd61bc9f73e5777420326282dedc1d7acfb23db8e5927ee402261040d9ad896e779b226c2082f9cec2281af50be8b6afa2443fbce18305f7ed17c5934df138d48903ff4a7c8f2a74a833276bef4dc9334917a35d83673cfeb231b0f31484bb4df75eb7974deb7bee547363adf45084708e97be883e52a11e80a5fff0f03cd9e6be5fb17c97759c522f99e68f47246e5f3f0ef5c9cd978487146c51dadf73a845d96423590d65961e54f4a933ff3bdb09b73d22ecda17817ec8c490342ad9cc639a409dd751fb61ec4c2c73ef20776598706652cdb8c9c8a5c2edfe57bdf2c72bd271a59978b46523462514eeb123d7fb67963ed4efaae679b0ce57bcfc3df25067105b1cd04ccdf0104a9087786ad188bdf54d11c1c047105f9bec500efe543c0e554e412adfce9209ea844993eaf7eeb8beab7bebfd5bd271a79dfbd518bbd8732eb56e87d51cbf3de251abd510ed9f6a1d8514693b2497fd2bcccd77dcff53e88fff7dcef7a1ec2513fc793f0c3856c5071509f6bad5855378765cd1df9ea7aaba3b48a85ead67fa13bb251f9f38be4cff9522c7a19c97f8947362a8e3fe6a5dffd9ce6b4a6893e4eab5fff93e0d0044ad8d1e7d66ffde873d9fffb22ff4ff4c4a27e17787dfa369da2e0512ace18505f3e8fee5d0ce2dfbd14833815f9771f447efdbc56fdee6794b65cf5bb96ab25a97cb16e6fc640954f9fc7fc2a0611833815d59fe2cc16a47b29ce5adcf179dd34f9131e712ff4c1f6f31d6934ff0efdc9c73e9efc99fd4736125adc815482064e6cce69b2d6dc8124dfd6ddb5c4bec964322677cf75e00456260c8ac359ece6f67f356883fb61b1e0e5af6003d806eb6b89c81f0f2ad8facfbb76d878745be0c7be88be053bf96c03c3991465b656947d2c55ee68afec6ab70377c04422f5c1270212fd9275fd170bd9666d38d47d0d3656e7777e26ffa8fb991477207993fce9de99e48fd2d0ed5e03275609e7bb9cefbe8ff8d304dfb1ad7b9a31a03ef822d087e9fc4e0c49e902490a7db0f2f90279cd5eafef81746fd47ddf3ca8bbdd779307517121184fdd3752f7d475dd94dbf591dbfdeb7beadea978902b7dafee9d18a8fb9d1088fce95ea7fb5619eb504eebfe25fa93d3baeec5275676bf430ae588b3ef63247890fcee7548211c71f6893c40fab00f521f7c1eb08f7d4c0c421ff66ceb5e042964bfebbc8060c915c0652f3454dd0e08fbbdcf3748f4896f47be828560d81a796ebf7c2f949d2bcd1725564daa246c7e58ec8e9c5f65ea459b78cdc91d193765b2891d6560083e4ef31acfe52e3f20dd1935d9c48e3469e5abff4db6e1dd4343b50e5e5696071848135684115a6ca39fc19dfb00fea93fd20ec0dba2080c543f47093b7653d61bb621654c6c0b5944807471eb7718b6c1ced46a6e8de25632b70e89b9d5b3b2da4d4b4c52a889d6818586ba69484b3714c4d8ba4ddf3def251ab9bef546df473ba1c8f5df090d609b953ff54d6800dbbc6f00dbe67fa291914cfed43fb2c91f69b24619cbb6d6b36dfee8cdfc8f6cdd14ce5cdc81d438f953bfa15a8326d6f5f903a9ef79d666ddfa1a38b1557efd7e924250d599a450ebeb7b9314aa9f58df25d67770075238df15ca5752656a75538c27ab81be5e3ff4c176cf77eca66eaadfb5833b54af56ef755d68821df7a1b973d87ec3c73edf87c5c23e2c96079c31e08b604871662b3afa22850f30d8ba975fd4bd148bea7bfd23db2d72d96ab0b1ddd7df81d489550d0e25d95116fa60e9f31d87d8fc00a5852cacb842c35ebab9964fbe9295d16e4bffef0322979ce6f5482e8d4777be6d59f3ac1c7b35b28698a24b1a234b7a58c346bc61b2a68d99124c29520596272d1e2693c89552ca1987bbc1063254a4c8a0851a2c2c34998207a90c0e862c5ba496f0ab2b5c58f71cde04eba362ce39e79c73ce2b5cb430320409a41470b0cd3477ce39e79c5fceda862e1560acc8a003939929407089818a2b4c7460340095a58817485071e5031a299d264652b850a384eba1c817567ee5ca085a4c388922aa34fd80431a2f8e988200586438024a0b16397421c50f3e504a29a594524aa1585862045a72534c0461a3515c4a29a594524a7718c87fecb9fe3d6c835d72210127a2f0d084e588ac2dce5c5121a74991264fcc60254a114c707028de804e1c0cab01a3d3c4b160198105154cbcc062c604ac2d9e3c59a214849b27babc98f8110f63de2031c40b356099f29c95282a5ff28d99c27577e22c2bd084952d597c81c4cb5499194baec0f04407295c38391182167bd381e86047cb36baeb36b7c99e76dda54c227b5a7727ca3a83da878f4c27c1cc2cce21b3bae7dfb1879ed37cd049a778c2bc3e68d72d95c99852ea31f3147fd0eb2fbd88adcf5eadf2877af2a7abacb2ca8e79dacbf3798a9465e8e38e3b578eb992622945963ffd1e333f03b5ccaeb1fce3ebdaf80a37bc44ffb8c1652019069779f8877f8a2f83feb43b0ce442dc7d0acbfc1ecdc65a5ecbcbf2644e29a7b5ded7f758a8eb2c9e353c6be49c9d0b3feae59fdf2985dd009e73ce89355a2cdb3fca50b2fd9ed378ced7654aeb0b92a964fa94a7052b2995799776b13801dff33bdf231a39ed8845e1fb88463d1fbe518c17ffc866413863c0051fe3828f312bb2e07bde82ef7919e18cbecf1fd93efc97f145ff329ebe0c19ef231acde81fd964bcd18c8a2714f93c06df00b621c5780c4423230c1e03d1473cb27dcfb3ade747598fc8b618e205e1d10c7370feebd705e1914d0cd916866cfb906d3242b659101ed9186cbd53fda8b7257ad50a9647f430a33f4979d0d4070b9de67f3aaf0e5d5716b2edeb20e779fe6370e771be43fb3ce128de1d91e773489c30271c7d884e8b85f07d7ff0bd8f219e7fe1c8253b8ff339e17874731e0724caa1f43de0707c9e709c97e777c2b1efced3b0861536d49138bf131e5d1d71004d03e76738d6b8389f43e684e0e384ae8785e38c1b7b1b8eaf1b13619f43c2c2fa603895427f721a94d3e4c34022973897785fbdf9e5ca3975a5c089ebc18e8ee39c8e30899daf249bf9a79b6f87732e71c7c578f92ee5423df4e53b94074d318718e29c923f522a9c54f207e7342a6a74772d58bee3c44d9c377138a93495a6d2954e257f80b03f451c8e891b1af2260a12e5e0c08d4dc0e4dcac6f119594586105218c501652104e80bb630dcb1ee9788c283cb4765ecbf5bd4058cce2f4effc8e38e67c8bb30f76bebfc551e777de493af9f3849e6f30e7efe88438a1b58285af304aabdfebafcd3e13c76791efabeeeeeef4ba4f2969f2a7264a29a54bd9b49aacd297a27bd3d04567f70ef61da197ced9ad3a67ab9bd22a25129a90e70c0116e28030420abcbe0cdc7e497fb69c68269a2128173e5f57cb342af2ec98465ff67c815becff4cc1f6bc4c26853eb0e67ac19e6d36146301b874000bb832a7c509dcaf7330609b81a890d9c47b4911dc623f5a69cdf39a44cb3a5969ad34031fecce652d50b840ebc1e6bc01c01bdb61411bc27a6aac99322e18f9e23f1c8687913101a83273c41d2d2dcb0cee8e5ffbe1e3037c9cc3ce7f2a9b0a4ead31235bccdcb6dd563a2a4f539a62f676bbfda84f4d5198a0c0708e48dd8003e788940d51a02cb5129813c58b121f43bdd44a9dd4482f9daa23a0a8d1498dd437201f8f14313bd478a48891d2b7ac36fc3e5c14d8d086871914d8d026046daeac466859e5c614793e63a8f8757850ed3c2a291cd5c74b121c6ef776766f3b291c5dcd832a0d8018294bf89005408c143143b5193e9300307c9962070402c0f0458a199271b47bdbc94f4eca62a488d9e1766f67f7b6eb6a53ef19a45e776f6d37e7f5f0a86b9da68f7db22e8da56d9b27853c2b73a197e7341b7f87b2bbbbbbbb650f0ab6866c9320d10efa9ff77ab9d0ab461bdb59f7b9b13c293d2576ac5df953865eada291101b156fd5c9f45c36bda1e9796fbd9a1372a6dbed96c456eb53857aa2893b565c95fa1feb541d13e5e54d1e99e18e526949ce8f7249e74719e5098a0cd51d254e4aedfc28a7787e9461aebfcc492ba43b4a2cd966821f6516053f4e24a52527aedc7132cd28b21f67138c1f2795eb3f71e39c7222eb8e936a86a9e0c75935fb719eb9fe136b66e59ac0b92345ba1ee329136d9272474aa95cff9142dd1fa9d4f5a754b4eaca1d698e9eb9fea61e79a2883b56a5bae4ba6749284d5f64957c73640a8f73ccb4a24bd40aa557d76d236d731dcc94ebd31d0c133ef5a58601c3d379bcc40d2b9705d21554a67021e608054d535c3db504973b36d51d3bccf5aeea31d7cf4061024a0c848dbe347a13099cd8b9a353b9ee6ee5ba4b5d7f1e9dcaddcb1d3de767ae3f7390bdff3240a2ef8f80673968e4d1555421c2e72ff831079f0b442136a71e3ec4fff7219d942871bbe27ff8168044e1874cc59521e3638044322cf81e90c882d78db17363fc8cf19e991be36d0eeac628c3c28df133902886ec08a5dbf31580443db323eeec618044b30a5e06125500c3092617c6530012c190c97e029048e67329c85d0a9e0724a26082097e07249ac0f29009c1e5791d908867c7b6f33920d18ecef398aaabf33820918e276fce5b9028872685867098c04102078704575c1c0c2e0ece5b2717a704555c9c31572ecec740229c21da0fe530c25a31d61ac0e2b8638d6b9f77b8b600d7dab74c9cb9f66555415cfb9fe4daa73581c4b55f23810dd73e0c24b243ae1b7b10248ac196007361ff02896042e07f2011f8aabae3ce7d8577ecb92fa0fb7abdfd725f4b44b92f3134dcd7bb40a2d77fef72595d97eb3d90c8555b60baadef40a2d6f5c254b99e19cf76168009e256f96092eebcb9dba25b90c30fd5a65ad65e4d8937b6bead696ee5b9b5d65a2bce6b47833bf630a18416258a48820a1f3276f4e6eb460d246a88a105092c544b77fed3a8c0dcf9b5249ceefc184834876aad3a2e14e941892a374954f02d7aa0c0823164a6ee38e34b0e253022052398b418f1e68826ee7c1848346bad74bbdd54a0c2050c324dbc6a2c819bcabaf3655ec4dcf94f4408ee7c5a8d0821eefca122a898829a536d9ca25089c2218b93275c8b2c3cd82f83a924b7be8bca13b0560008d0c5aa4b955bdf135d40a2c9480d527ed022eb4a198f893beef4383144d4ad5f65530529983441040b524800e5a6cb08902845820b9b5b7f7a7fc4a44d15140d48a84052c536b3e8d283102f0baeb0a34cc6369ccb9958106768b398d99c71a700ee9c5235dc2995c59d5c906cc982021d3c18920b5f0a3930890bae214a2fa6262da4a7ef07275e0a2e235ee850a86a458d515289e0bca8354be810ac6ecb902693470a750b0c2f48f6a6c7a30813e52d4d30f01882dba225061e448e6c19f38407529519a8cfc1a2659dd75a31e8d245959f2bb82ea6a46c8ccbb82e8ec840073bbb8ceb220d00907851e40d086a489aea1839cfb16f31096e7b9e4be9628fcbbcad3c07d5583efd503220acec89359a459250e188cd68e785b89b9bcd29f66ddb098500e0c8cde624e5b374cfe8c8858923900b7b0fc7791ba55190204284e0ae7f8e7b61a10907f8e28bac5166dd9ccff910bc98788209fdc585b12d278cbd5b715ae3a0947a1022013cc536e86d98d75f6e5aa8609edc51d4223814b19c7f82ddd35cd88fbe060ad49b9cd0b1c00e625c173dc74057566718c8a75873fb5d7a3206732c35b718cc83c2cd46b080d3ac744bddfe5c4bf9f270d655fe04d368878281fa5b0ffb58ce83d03f9c56c28f9d43a32302c9f27ba38f348d2bb6e1a9e11bb06ffeeee839b631bbfd7e866dc8b7dfef51f08dd8f7fb146c23e763b19b63a517f6d591b173476e57e574ce2879100bf510b7bebaa2e2b97ed3d2c9f11c15da9de1343f83c51dfdeaf663d52072793be8cb9de3a07339e618dbb9b66a346c038b6db4d886ebfb3b8b6d7cdfdf6fd8c6ebfbfde6485af08d9ed234fa463f358dcef9b1dddcfec6826fe4bcce8fdd05dfd0f96ef2254953b8b86cd886f7bf5ad7437965d867ae988172574daca3601a7cf93be92a754e071ba3ba7df908a5db37a96f3495297da3ab9a46f78d1ed3b2a6536e3ff912032931902f5172fb1d89c770fb1d06a6d1af139e00fb1c49a56f3813a6d1ef4e6e3f0e95db6fc39ea2a3601afdb0b0d5308d7e306c2ca75d856dc540cd40fdadb0730cd41f463dd891b360583916a8aec8dd907076ec1bece948d2153bf6111eaa27dc0eadd44b5cb0632bc16e4f550cc19406ca12942476ec250a8ce45098d24c1de5891d9bc93e15914295a62939d8b19b5e4c8ec3228527a6272a4eecd84fb72e5c18e9e2e607282b33d8b1a126c09acaa2089b348d6ba99c1c1555509921d253fd85891d7baa02aa21724cc034558769c18e4da581522e4d19aa9c9baa3141d8b1ab5e4f5db6c0ea92c552e7fa8c153b76ce454595a686a099424a6275f5821ddbeaaabb4db539c3e436e50688a936423456b779b26363d1dc1553b92bca7456bf01811d3b6b3e2d2d21c40dc9c98e7ecb80ea48921f89620a8c4b1451a2b8442186cb992ca52558ece84a4f309eb8c0d0c40506325c9450e1b2e4c51214253bfa12ceed892c24a6284aece84c2da521d24861d5e44e831d5d09b7c50d6bb29ea8f8d304538986a7efc6a40a282b382911d8d1713bb928235f0c29e253fe658a1d7d6a4c054a5262c24889b9024b4a892b29313938958711c28e4e0584a3f2059557f918afaa54b919d8e0925879cecf006147cf71172afa06046ee5576e055261ad5003c814b502ceb1bc0d0f7674ac3617e4864073c5d4c2a73484153c0c8126cab3fc4d0d76f4ac2532aa2e5a246175e982885c973650ba643d7143a2624779a34f4833507961c591a4263bca233838a9b42489ebb66407a5255176944a4762514837798b2262064b0b17555143965882e2831de5d21230b70549d29314a62d48ae6c51ca3145b9c18e92a975cb59110595155c344d81623f6ff965eaf64b2a0f9ae0f6cb2c59180f629c1a9c3c63e5a3c4926fa6740975fb5b090aa766c9f5ef97563c68e6a27c725a3fcf95f2692a197971b5aa8c81fc9bb3f5c29b5b94239ae4a465a85879b57a6d6a509222a5345de1aca865802f4a3cd95ae2914d4a59ef63205bc50ebe1448d0643372bd908ea266cae624ffc8f6b54257c82091d7d55951eb67452d57382b3ab2e590267487d41582ecb68701d9ed6f2155b7fb1a8edd74ab27a56ced2ef4414122da6275797786de6dc9cec12e1fb3003e9642d236a5b777f05506f244727a908b3d7ec82bc48fdc35f0f5f821af8b33297ee0cf01797bf077df78a2f365f28786423a2b21b52648a86c4eb3fea3dbe2cc028d1442e34d53968d7d838f4e1ab29a2b2c4b36dad5f7c49b90fad5c8a9fbfa4642e8cfefaa2864be73d9a0ff6397019070b619b2ed897ddedddd3d0f62a64dc76eda83d28e763de83b9deeeed5ddeb8feeeeb5dbdddd6b37adb46b57698fdad5aed2b047f557ed78ba5e7ab35dca1e3de99c41d26ff4ed1eece8dde9cd3b6ba55cc1c06030180c06832989599c9c17ceeb735e39e0386f4c84812f58ef4cd17df7bb9444b97f9dda703d832074627f77fb9c507ff495df0ce57fde4f7faff6140c21f43c1cf57eca64d68e5eec5d9c9e373de8aff733304862bbefd75b80840bb08dee2995219359ae79907d9ca73fe441f43f1bbe9c063e4e689d063e831f607071c4e934f073b8f5faee2c4fe81b0b4fe80b0bc7d605c597d3acd36efdc4f979a2e7c9efeebb47cb1934a5777b3f767777777beeb3d66e6f47a1e594b8fbf1abc3d677e151ec82633803c17bdcd6bbf75edf0aa86cdf762f1cbd1edefb4f30047f31508ebed19752cfeb72f878c4583b4b782fb95852e537db70792f5d9fc33de48077fd7d4e087ff4edff5e14a42cf4f2a752faccccf45be2d8ba14e7524f1c615cda458a2fb782cb5da4e0e17eee7d47df7bf672ec6875debf14caf90a03ff25be2803ebf7f55ba0582ba0a28e1d2dd11347d98591b3d369948ab30edcbfe6bece6377fed49f320dc77eefe70c9a72fa8d13fab2e7795ef764af2b90c1f673b7cbe512e56d47a1a707fb150463f9c71d7da36f6dbd8be3bc1ce8eb89b30fe4175fb03b56cb6d12174873ce39e79c5ab6d8c2ca953f63c8c7837a9aaefcd7e8197dec3352a52b9fbfbf7850470025b6fb640d17727d5f1084f92ed1fb1ed6a0025ce2d823a3ff8130c348f90a7388bd2bf6333441c8ed76f6d2fa1efc75fd9c52a34b9cb99e8a2f97e89910bbde832fa9c658c936b7a4a5284f56a6c2e4ae661645f22047727ac9a90a8220deefbdbe1fb712ff97962ddadcd77f200852ca693ba29c0af9b6402b85fdc04ff080afeb3d68bf2d90081499698cdffbbf9e411082dcefa7260882df4f94524ee340dfeebdb0ef1667ae7f072a20769981bc10e4944c8281644b34a1e594d32437a5b0f9359461c620774e5152814ad851e2a86efb3355f29c2633b3bff4319fd2e94d3e376faeebe75f5da0cb5adc58b99fbf725caed073c8913c612e51feb844ef1369e174212427ef918abceb8bd06c4eafa7dff77db1b0ef9c733a61c71ebedf2be4eb66ca35c0652d592c5ddc652f97b56425dd9d1e0f8dedfe73c2ca6f70becbe572b93e27ece77a97cbe5daf120970873c55c2e97cbe582c580b03d4ef3d6cb157af7f57a851cf0ae0b043f19c85fac000c247362b1e9e5844e385370fea3af1fb621f6e070c99eb0d8b740d87f1ee8c1843d831dc4fe85a3033bf060de97f862a059072fa7bdc41eb18379633171c86931256ceb7b7a767660b158ec5fb1900023b0b1afd669fd31716708471c3d02046169072fd08a218c7d77c2eef6dc0edc715ae3709a1c62200240d94f1c77ae164f974b70594b9698fbb95e5ec89f1376945d097ecb55410d33f687bc2e79bf594c3c0184f9c1f7531c5dff89de77f70b47ef8b8923901b73b99e9dc6379675edc73e87bb4ce8ae15c7be31317489a06520091359bccc409d43ce5bb6f1bd74fd50d390eff964ff999f681968fe50dfc0611af3a5ce7d39cd479f11e7ce2b5f3db7e70fdba8f7831f06ea8fb90e13669ecccccc93999927f374f38db5878164723e9db3328737586571e48e3b35c6da8ed3e7015f134c9897190887813c7e859681b2eed853c1072c6bc1c2ea71d846d8d7f320b681e463af49e1103dae1d43b519bad25fe08338682fb3d5602199ac7910ecfbb99b89ed86751048170693fd912de719023c3fc11751f032d1c8a973c471e882df6211cf4f70646b71ac5d1004c57e863a73c10745761a4ccce1b19c3f22b23018ec3de070fc11c679753e271cfbe63c2c0473421c9d30f63938e2009a46ecc170ac71639f43dae9b41a56d8873d188e5c55e3824d60e875e883abaeace5b1abbe17569f41b33b12c7bd2b7dc4e290695d66c22acc6526aca42e1017bccc84150cb73bf0b1cf38b9fb56add5937df7934da92696bdebce0f5609c3ef41f6c5b2d0c3f88ffc0e3f9c170e48543f4cad46cee34c1c1c1c9c9fa109325e5447fe13159ec1a23f99d00e25f54bec3895c239c36e9eb7d3dab73c9fc33bb43f799e41229ecfe155f729c0c1365cc8a9e48f95424426f87f22305e06052f3e910a3e94fd054f64f616e4b8209cd1bfe0637c18ce76c470b623ce18207ecf1789013a5970d04982c5883539580069795d03a1b33618207ce5e5ba216e799db367bd4e66ab4e0224104d53c63ccd97d5837c24b7bc4ec7649a2c6786b1afee641b55555521034d1a65ecdc9de241f25fb46f592daf6ba6dab7acac2c20f2a78d1dffceffff7faf8a40fbaffaaaafd2d18940fbaaaffaaa87c23e791015176a1f206118ef2f9e959595e5b4fe2e060f1f5fe0052b6ca6d8e4961cf12d2ee042ae25edeb738d08a49c4fbb70a4728a3d66276957b1c7a44dbb6743f1e4e30bb880c4e6089b26595417545703de352176fb93bc7c7c811a97a358f8d242d3e5a8a42fb788cb5149b7fb3eb42f36ad6efda82bb26e157ff8dd80ec8e406eb7dbfd21bbfd6065a6cdaf5efd49c51ed7ebc6fa7356b1077d797bd4dfd9a9228e2345a46d486773d2c0bcfd7ec3dd6eee21d9d1ab4924a8e4ecd9fde524e9a0ed124bf0dff153af43fee8e4ecd84c5f241353333593753925ede7fcdc71e24d5a86d61c34b5eb81a5843cffe9762967cff939efe998f9d19ef7d211823733f1d43d5826f7a1c5c4403558a6afa1953f4dd5a3c4ec266e1eda9f81b837171b05a621bf134b903fb2c5212530501776ec269ab73463a96fcc97efd1a858fbda6b799d7b1e9691b1ba894f5337e91b93a984eeaef94f0fe508c5a6d15f4397459cb9ea2a69951ba16fd06a7fb214ea3c76b968dcf2baae25d6e48f7ccf7a9d4ca4c91f1d9c1dbba99b9a264e0998cee96a9da41c1e4c24aefc190e154046bb4193d17288d8916941e3ebe6c0b96c2c175a2707cf6b87d2491e340a09b18d66a0a6c91c363de5ec9e3b4ca64fcf0e5fdd4973da1c3a0077a131d0147f6402b8d2935db1e3506d2866c3c7e3bcfde1153bf298dbcccece8cc3c809cb357a54b02c8e3db7ad1447a32b9f8f26f3d16c1ad51ca5c29b2815982e6d1ba54c9f7ed75adbf5dc6ac960f00f7d119cd632cc62e97fb114ecd838cfb356267b991403d13fe3340f8d8dd1c48eb599fc7ae79dc9e725a2d8e2f212516471c7ce758e568a8bb1a455633e076c2376e988c325ca1888fe055d58cf72e541b866c25fd84cf887829d856d34e8f4c2e152974b1c5b864b41d90a3d90a8d5b53a113665297d0ba0b0f5ebe5a823315c7939eac8d2a5f5e7bf6a388d3e1dc01256c7e5c0698dd5420363ce29ddddc5277777779fb25f3bd7ffebe934af041edb609e724e1c9df8441bca5db5acd166481bee58c39d597ef9d8a756ab31820f1c595f86a8aafacd15bed16a9886cc72c75a96cb625fc1a8902de6d0c6835cf4b1e2683ef619fdd603a8358dda320b856dbd477f874cfe8823b05feb86be7f3d0fd7776290ee5dff1283381575ef1267fe3571e6570c54bffa19db594eab5f3f0463a5486b2c97c8a28cdb1d964315bd5a9349211db52a73d4fc26abbecadf1c634ba0973e093e74882085be2394f21f61f9c187bdeb3f4f6cbd80c81fea33f931ab99c46ab562e24bd4d1a2af1cf2879e2063a06efdeb257d5848935d38434ffecc8ac07f3d28b2fc697f7deb5f624b647feec0ed102b4b9039a4d0f7f475009142afa7fc632dacc91ffa3487d653f6a4508d7f78aa255af9c37e3b246ef669320b8ad8d90e24efbbc7b97d5da3cc2fff8de5cbcabef043990cf6fbd7fbcf9d1d2cdfef5fe26cc7f7b306b0ed13dbf6fa198fb6bdbe6d2ff1e58f8c81eac7b6589907dfb7dee8b50309c9f52fa4d67fe26cfec7b8d93462f9e3fad6cf6fb5fe138d5aa251ad32185aacf572d487affe67a590b4d51ffd368d2a59c643cfb2ca0069eb442b9fb0f4bfdb1bcd910d699e68b24203153a8c913514b1446e49c9932f5524c9a4a8335777e7725411365a2e3ffd915d0be36e0ffee9ce74ce661c53dc01986760fe5cccdc62af19a873af9479824c93eedea07706c6175632b851410635b43332e490666882f1c577b2d25aa3ae9248b232bb237380124c0188ba228204575277b4566677c4cb512c48b16f03922dc858d855065b2c5826032d1654a2089b7339aa0a2e071184a91285829cac65b437510c9171396a851ab620411249282811c3840b2637de9021b5d65a398082439aabdb11596b240d4542c026290d45e342eb7294162c53522debbcd25a690650589ccb5157b8d09454f941b2f672d4151c9eb8f2441645a4086965aa0c915a6bad33cc550d449e5a628604c1c290145ddc91712c1525451452e48cd4bce63f4e4fac60c4c2de6470439b0c6ef6438341d513187861e9e5a8dc981f2ad6bb1c950bf3349b0c5551556e789f28235f5c7a390a8ad51dbfd62447dfa33e6ad77a33dcf16b90e18e4338b424943b32d55208eec863ae3c73c44b142fa4a2aa9031442d3de9d45c5145d2940a498419e248ca1b23382c490551440b36f93aa4900796a678818d1a1e8c28d964eeda1ddae5282757dc9ccb514e7277b44f83068c90220d0f52acf04413f904eadbc242adb5562b48da90a0852e7e6823612002ea85c90313921e28a53074435c86247838628635e4b9bc4f9496a66b2f476959bae3d73a2f7ecc60f065c99f389a21c907334850b88105304b6868152d545beb981699289076d6b82e471589e2c2b81c55e48b10b59ad76ad349e9a44961e5e5a8225eee68a558bf1c55a4cb944e8660353de09c308249912f2cc8265145b87407966680c10b93149535b65a8d2a92e58e5fab8146abd59418695fab81a10245052a0c946432c40a0a2570814c0a6b9a904b34704314370481c20878b805e15794c8d8e18b2263b07893c3937f2899e48eb21741d21434ec60868724ff503cd29ccd1a2b68b24082839632b51a184fa3064a22e112e4b0830b6c567022428bff20388cfb5b28773327542a31c0a188353621ae289bd3f48cdc0808bcb06213a2010b36a749a9bf6ad83c30b9a264933571c6a37e97664c931b6c426057b6fa9d68d44e048182954d488e0bb62ad27c83fe23db375f7456548d3c230aacac10c2260414c25637e8d0680055aa18926513e2512bc860abf906fd95f61824b26461a37da553d4154bf787bc19cc78d059d39f4f43ebdede3e1b0528eedeee2e9f711fdb867090f083032a574a29a594b286d736f76e8b3ed3e50d1ffbcc781835154fb6fa4e10e89ebe37c666f48db159f913847d79b98b104977ac5d2995dc18f4c18eb22b7f2e40bb1c756b73a36e672e47ddc2005d8ebae1703f64a11ad45208bac45045893636f90d82d04d10c672d44d863bdfdd8bf8e4532674b87df2d541635df1847e138e6ef747dfe64aafb790759b1d69b1eb1f631b5dc17510013c639c2fbf7f8ade112ebfdab5d2ee64d470afd49bb8e8b47d8bcfbf63a07ec97dfb7b6ebf8e22179281a5c50b2b35866ef317e93c76fdafdee9d806ffcdc969934f5934b998b2d8c273045600545d5c58b20605ef65e50e76b4ddc213160d48724aacc87a7ab09e10b164c8fb2cb1e3d36684c08eb44ea6596a951953ab21c58eb5dbbca209d7550b433898ec3834a9a8b49082d3224b0e0e60b023e3a67094bc48c17991e28497262b2f529ae84840163bf2540c8b6a4892253b8a6cb0235329cd2b8e7c57ec204204b6d891ab3e2c2cb0a4a061040b70ce958b62418a112324f880b2235b794ab92ad250596151c28f2a7664ac1615152b50210390a114a884ccf695412c95b2810000001000a315002020100a87842291480ee4d1b87c14800b759852785295caa34912e428884106194000218400008c31c42034662400841b56c86f71fa51417e37e4a71efd4006fa43a135d3dd9925766406335d98e1f3e42b414e52679ac03f9b8fadb2dee55c91f30e1778182846c5412f0ffa798402a4f097292e3f54c25f9bf50c5a21bfbc262d9f838ccf13512bf4298100996c1df0280bc341994c870ab3476634a005339c3ac35044545f0142aaafcb7d202390cf0e4619ad6342aee4896ff35f326500502460c97e021613232e30b7204cbe25e8d5798ee4187c6478ed99443a591507d17ee3f4044db28af9c22619afd3a4239f17ec93c277f28adcd5b12617c01685ea8c298b4fa3d65432d88bc90533c25157b51de23d6e2949123f0c450d880224a9cbfed72488d92710e8b226ed4321e6827097a4e04bc62e2e0a1d64c3da301fbb474a3afd9bc9cdbfe5fe9b20f199d9f0a907e4e9c9b7781d3914c58569fa7036dea1014008d1ca956e1b0e3c39d5e9635d5bedb8c92cc67d04a3ffd72f4696a91e01014c7d70bb6622a11365cd44828e603513073a02a899d4b7a23e85e5a2bda008ca259ce31112c100d47009363ef61b191bc7c2f60784631d254fd276a92219cdcb8de3125580c78bf433350ff14ba7523a0f1c12370fb631cd1d121e115a9be519f7dd5c922f02fa60dc1de55cb7e4790180facc5afa2332de183dce8bee354b21b45c62d69236ef2117f24b4405fee26f65e12f22c25bca9ece60c8e7d7dee37f2c11ec111aec2cd05792923b459d8e705ea15603cdf780e8559bc0a233c572a11c44f6df3d4f933733e9aca49e091339e428d9152f693fdc3274887c1ed38afac03b8162d70c32bcd8c4cd123276b829764c4c55610929aa9823c6b90c8ce21238edeb5e85faea737c4667331cfe8021ce1b669c6a789678861770b2a3962896746e7d7c7e501f18f50377e6323d27fadba284e56d9c46440ddd99b80e0fb7f5790c79193e6991c8db54f059fb01842936962dba14f3a73b0b4f62b1ec615d9d9c4d6d16f8b58f5f86305e517f4a1e0f6f61257baaffdd9b5ce6c01a6f85ea0dc58fa0ea13706ffa74c43727a1352e52f47229761169b983a3e23a562d7721af8002cbb03f866f0426f1e1801f62f99bb2933ba87670e11faf1e3b5903e40da79c3c87b1f4f819f9e01842de0b853f88576255d8a9ed0af895fd66348f2a07b3a5088497b9551c71de3680ae0322c1aa22931084f63b6492df2705fa031976583f01e568ece8af6c4d79ce5f5c59859e18135340d925f33139bc3a3731fb57177ebc4469508db24e289f37635f6008889323ab619f542c1f4b14be1d67b08fba2b576748c32e764558742cc1c40d583fd07b256ce20f28c3484c020155d8c8e2adb1110e8c9e3a4df7c2b33e58a9a7e91b64ea71afa9de5c7a1477e44288d3969f0dc465e5303d132924e1a10225790e101df415554b9efb7343201ce30b3b7ce9b45930a0b5ea74e296274da48b24628f4c94f004e06a5c089d88ff510c7d32d020ce5749f9dd54b6144708df323539aca15de33859670536ada3ee520a7b26f779c21fd5ae9b08c9298dc99eaebf440c4ff7e789ae30a8d221a2818c72bc07627527953e2e6e5037b9e2df569de38a95a5297d9c4db126b4c17b7054d2185549476bc3a402612353abe2e2d53945376a5cbd34cea40eb305f028f655648a4db4fefda2b4b67bf9d85739d13963ec899175688d8a2d0c33cc15831e10040f02fd3d316878e79a528b78a0c6435da6c25ce340d11c9fbc71456e2794791c94c214d9052118ed20add31cade11088cf3a407de4bbe8102d7d28132a9bec53c4881bd99f47398332c0cd517ecf456fcc1179316f452c7e6c3249c4a0165eba2ba422eae611a5465b3e8a3faf6b35cc5c1a216b649e4bdb8afd3077940ac2635f7eb166dc10edb075d5e1735021fdffd40b51fd28ac28cd742b756b4db53133ec632cb56f5942347191cd7e6302f14fcaa6645482478598055d683c69c1a592c3f6ca1666aeba3d043e40afd031d11c79084d629c932679ad7f8e465826f199954919508baa410c204cca2a60446307875713040b242b6a223352e6452fc5b9374f90ddc0684fc98add717c36c9fa0111575e43c2514e535fab39d6392017714691276deab6621e547308212a62ac848a8d78dae616383eeb0f4326fc1ef4b460d6060eea79b96318c8ea79513259e56c95160e62cec5ac56e93331a81a1639eb4b8a6a687f4c1db40cd5850b11a45db9b946fbfd284085c10500c37e26354723ce43e00d335e227acacae44a6b3539f363cd35fcc772d8726ba3f44ba304f0c2f9722b894eecc9c2da2496672c8770a2ca56c63764ca5738923b8b37d5c42a0251e6b66d6c7d9abe487c1e7231dabedab3215adff85e1fc7f6513aed6eb14bcb70c19aaf24ad82d413e364b531ea42f54cc7858d969f07116be9bb2e0300c32915da84f61a6b1298c5472abd8e95228a1c660a62563268545b54ecd57ae16fc10aeb2c9eb4855e941ec079276aeb134b1c76d03d8f5245b8379f22e82b500939b4bc17639f547948145660c96af5ce8a391dc34fcd46d3fa2b3ea23c6745f799f3c4d42e8952de67a925d8f1189692d24d0f8049f239026bda8b68ce7d62a5c0ccf09ca400f349a7631529ee4e26e7332fc4ca9f623c486b32b20edd172fccb7354c6d032b3b9ecf5a5cb960c5cfc7c12ec65bbbed92983280356d989cbb4ebecd6569020aea7e20352b3bb2fb69aee8a6a51df0d067ce3790361571e73820820437ea77f28791374a8904907a70ad84b30595491009b21887301019d8cde5688095ca3b56317d39894ddf196e1128c5629707ee3949ccd528ef7c4e7a0754c231dbac62e0577390cbd9311f60ec3cb8e96c3d4f60a1b4019771bdde4bd4a7e4b780071829878b16304288c69aebc0d34444f6ad1a07dc9f2a3083f214f54b53511246c4134be6b180219d9fda0be16a1c4d1ca6671df8f1d72fc22fa607704f52c9c810cbce163c7e8bc8843a770b96c958ae5387cb6df7f36b210fbb3459225f06b83e6c7bc8756f9403ba56ccc47c59043d04d3b750a516e60f56928e3860504956004554f6b7a0affb84a0b536980414e880133edd9fbea08010fd5c0918a1ead00e6810c51030e0d6e17c14d3ef862857e0dd2c503b7db37c234497773a5483ec6d7d9fb7beb43b7cf25b7ac86ef370a2c42ce03b60848e6f18930b6f9fe19961a6450ac39d9a55de5cb6943fe226ca981a68d77a989aa17ab483c4dd957bd2ca80f6e5f9f61c0f5a5f5967b02d7f6161d0e58a7a2176bc64f8bbb0ff17797b7a1796d40b092b78d907b9970055e4537e2a6e3713772e07a58a7a326cd600c2add81aba8dc9f1466474ee7e126fe0e021300c97162ca537083d4c88bae6313e61c46bd7ea07e456504707cd1165880b636213703c068645cf205d855307ced1c81043a691c2351e6e571d93375ecebf127be3a3cb2c2094cb8a66d47dfdf26071603385f8661f65d099ddd7c22648f6c5e861de69184ae19ca63ee7a1d68607f56aceb9e369b12e7b1ed37261d9dc1361910e633806d77a8ea7a067d6cc101f39a2503ef46247f505726e242c3d2103140f401986032a030bfdb7ce5a6b1591dbf6381ea31e88dc47b03634fb1be460c0d9d7d91d7965e67c9e70a5c833de5d52cf12f64e94ce265efcac479f97809ff9ba13cdb4d7094635a1a63fa04eba1b1b1d3b71b3f2c2b2716cb92b0aa7922872de90d4be1bcf06ea21cda6653e7f2df5f3aa0b33ebead26ab7618e26cea3040d8b83406460f79390839cf83dcb63d26280333194036c26b5716aa10542667907dbfe5d3f1197b4aa0c4e85596d297f8527defa46280de22946203a49a2b48b363850ff260061072a49e42a7aec7b10d5b4e672716cfee4ad125bfc9741eaeffb3380c34cf02faf2be702901256a5ed80e4f684b87ffd87d962c46bcf7bc11b667d728da01e4f5f17adafc0e7e61baf43e3636b695266a2433559bcf5d7698fc913c59b518aeb4b6c66e8e8c37d30ef931212733329cdbfea178dd2804411f2b6591fffd5144a787f4b3cdb8cfd083257d81bdc4edac8fe5c2844f8228b6cc45da57d72b8fb0f62f30e42bda5dd50fa2e834090f509caf7e35bc5a4d43ba829916776256218d8d43d1094fc580796356c45ef880bdd476bbe9e933150892ef8a81b897fa46de126617d52c23c9d9d0aad823cee0e4f2bbbc0758b2ab0ce0d4d343a89d4779083544521a3b80480319c6f7d9587e08064381416a74e492478bcb0830a90598b90a2e3c115ded0db6fb04a438da79ca254c54bd77558ce2612800a7db2cfe7917076b8df4cfa1cf1faf20a668dde5d128fdca12374ec36fcbb1f77f7f1c9ee2bf12a744b6b53137edcaa9b776ea94f34c1e4cbcdf2bf02092e0a691e2883f16c852b119eb012640e7cb697426b133703df66e6615fc8753cecf57e28ac8ae88a6bf800b5da25343b89b6f868393bf0c79ce2719fb825b9568569be30bc3d5806aaab6a19f2d056857d275d563211d0c11d40d06f65d7a260cfcbafea4a6bcfd422c60ec284abb50a98465537bb4a7c83322aa591b6429b3a6698913153b799a0bf09cbefc7714b60b7ac6d3e20f984bec3620f53ae44153540daa67034fc85b09aff1f29cc015478da5559651122ba8501a67ea0ec02db71dd865bb49b381374fb84a23e44644badb7f17a6c4f606f6befe6b6f89a0510a10677bbb4d7e9e165010e3646b67beb85eb102a628ba121075705e536eaa2d6fe55bf0fbcc4250cf007ea711cfe59e5b6720850484d2890d591e5d12de986e75afceb10620b96f6ac0e27c8ca34fe4ca17b1a0852b392455912f45817f39cf02a968331031c823ed8e022c0d06789c61eda6832e9c192ce590b5ddc885d74fb570828880086f5ba29124dc73c9e1f18f8cb83a1eecc8d51ffbb0bbfbf4e671ea104004c4a97b1aaa346a87e02fe9373371ee006d5a4d4012c166c0e3f40a72c77a96bdde65caa49d3f084aed6f65c532abf408ae08cf3b513491a7e09140d7355c89410f16444cd855626314a3bdd0af929772252f17672207cc8239ddc75418d3aeb0e598d4263cd3eb0c4122b866b042d4fdd6cd32b200b0ab1e8fe08f5ca4dbc302807c2cdd494b91dea769564b1aa9d4d83529d1d786f471db47f9dbf812c3843e433611dcd4b07391db4d6e4db7ecff3cfc0c1ade2f451be34cf7d00d86a482614d1b015dc99437ab043756346f361466ffe977d8c6a4bedf4a37414cf7f8814a98a06a4d11ef139081432eb85e856f033ec62addfa2f91c683f52f6bc17108662b6cf4a899fcbc4e840b858fe3127d9912e4ba84352f88c8d34b4338473dc94c206deef759957c90157d712a0e534a485a8ea755d2acd8ff22b5ec754c21487e5d96551e275b10e20338bb0fc243cdf6511a04d66dbcd9a0c59b1657c9a924c78be832b1242a65c02f041293079ab2c598aeb600211b909fbe694ceb1a91faac3f8037dc370d8af630e4637d8644b517309f9074aba1c8edbbfb857cc617e972f10c672ecac8da1ccbc7c680d4d8e38dc6f83865446736e90b4b6540e1145a7e7d4f201833df2c22317721320a43f922a629b197460b21bac26470e3012cdbc5d384c5bef5209805648a41a4c5126e3c7129dbd1d48718bb316f71012f504fe1687cbffa8358f0667e528e578a0463ab8839ba62bfd36e8216d8d9fdf301723527c20f87cfa612652e6f657fc92d57f98359e733d481e8f1cb9ad14cdf7f725920572c678782d9271c8733aa1629a9c9dea4012e5b0e8117f1bfd81c74324a28d92661c9376196bb0ee04e3883889fd99a18a4131d189d9a0ca03e73d0d6c167d53c7f58db13aca35a323c572473bd03de31c1d69aa4337b8a794cf5ea962fd49c035137dc600bdeb23f5fbb080f30e7bdb3c5de8a24954aa534d0ea27fc20270eede74fc4d270781c39119a859af32ccd19c9ef0875032448bc93808db1c4304694485f53b4dc507b52879a027adf3476269a8434272bd12220505682fbe978702073925255462b3a5cb14d90742cc29592266dcbbf28dd6c3571358bc6428fa28993e333189c60b9821cc89f813ca58b0c6a3da74fcf0387f888f1943a1e3306ee4854577b25500dd28a84ac5fd1026f76933435ece7f38bccb0ef16c744284abf84f3a24b9f03d81a3c09449f6e2e7f684ae73749e08bf4992cfc9d7e4e95f3045ee15746c3aae5ff62b10cd9fb705b9eabaad56ebf5e1d2a4f975dc27965097c833016d59eda716530ad9e29e58e2f2ba171399cc3303e5ae3907584bf5346e6b119f0b0a9fb2f5a617bdefade95f4a36e2861a4ccc047b3a3f655b4ff9f65ed139f7c1308f32a22c6f5b56c0d38054d024fb26ad4b7c6220ffd7912ccfab37b59590f1a3490c53afa5870b8463d7e6251a9448d575e4327039a2416bb65d25cfd6ee136d595e6bf28e96b60a58590a805f166d4d0c8ea09eb431a81be04dcb6a5475dea07f0593afbc7dd138a9ff99aac9778bf440d3e8473fe34a663d0c018faeb09bdd5c1d283ac464cefbebc942b49ee6f4bccf3c2e59248cd7bd3c5c0d93c9b68e34c70403a73e2d839b36ad4b424adcd7eca3a4b34b2e4aa294c847bf977559c58eee92299ace0fabd21d7439c6659d7c74ddc78e9d0710354e45f45f6fe396a247be17fb7067eeb344b000787dca4e003d133fd045d75c97e176320d3264fa91324411d3d6080cb99eb2332a26f204cee4d7ce2d8d399618481dca8d8bb577a183f1ecf971c9b94ee228dce1384ee7c76a9715861055cb09a933ab602b2920d41091eb5c14ff15809430c901aaffcd70ecc051e87fa6d62f9a97e48e4a60347f96d0bce2e8dec8ec3ecafd291b9a2dfdcb1219650d1bcd0b4685a4b6302c3351a5f030a799172a6464d3032889fbe1777d41f42a5959442551cff5242c8247a03750457c416f0662b6041352d1435855348f81566769593b1c8eca46e86ae44ffa4eb90a2af3789d3ab3c893b54778742271342e390c1c686d59a22586fb3ac42439011697dfa5127a83f1412d36e3dcc7697087d07b6fa472b9abfa79535fde6adc820c5f0e65d1cdaec158fcb0fceee5641ba6ea5623b95410ae1367bd55a265c78805db58af2fc062916dff637a9ccd0afce96c349867ae41c7a1686d68f056219aacc81a8c291930f9f4602a9e861aa0af51710e05c594434d56445f23cdee64b8c5d43eafe2e6904e97a8fe59b36c8ad1e7e8574ba29ee1478a180d0bbffe8e5db0eac4b47f9f78d91285fa3414aa7293409848037188c0750cd2a349948b7c32795d0e48b4566f7255249f48d56fb2d1785ec3e4934a3365cb35af90b02ec768685ba199072041c4b3d6fc7f099495ae99da95255adabc5fc6b3ea26ee056a445950003afdc03891bd0964ae84e6f6361b98999515378da4037c2b2dba5d5f91da039afa378fc7a382be0079792ae9fcbb5e2920e4514c155eb025bd08bd142b5bc67fc3772fa6feb355d02c50f969b281e43804804b5b01703c9fc386888d4f3bc808c61412de13a3b70e66518e56ec8de304b2901d789effa31cdc8d12331663a1a9c61f62c0584c99f5ddd782158e3df32f5509d191e06bf97defdf704688d80fb48b68b42b0e009005d8361b758ad1fbcbf655c4b2a965449a359738c91ea7f13a528a83880022c893f51020941815c8f6996c36fdf537c9ae3e11272e9334a57a911f8a563c47089a4f33c6b05bc95c002db0e040089ba31503222b6b54525837bdc6966df58548e790a38941b7b28df87bc6c7c9c66860a15913999769cc125ef58f83203833625062ec5675aafb700b489366786c14d621ca9edb5297f590ca43f71a2c93211cd7e7338dc1dd8ebb1015c5d12424470c46a0dd7a8f2862171319cb482092da1a9866e56b5f20afc1cdfa0247d783368164409d05f95807e1f7fdc143ead9269e916c125dac91d2cc0b267fcb641e4c08a28067b4508b77d106fd4849642696f820982df7344ed9910a2004ccd8704c2cbf10917ad74c242e5808f9e39122299a3ff4dc66f3ef957666564a3225cbec265086bd05351c3ecbff9c41219ab8cf3ef1ac58501442b083c09a8d43b26b8d1aa886ccb046d04e152f471b77432816139a18ff6f20edbde91351ce7c4f4be25a6109812ca62dd66eb558ad28fd6decc03263fc7ce143f60af7575d2048213b5011b78ca3e2c78c64dd6e38291b46b34ae6abc1f188057d17296bbbecd5b08c0395120211f3e9e2d588d34975f8c6cdaa3929ef58fd1f393b085bfb0deb11b433c449961c48195ff4011a493492fba7d4e54e94a3c38d1521280116ba5ff19b627d858898c403b4dcb0d1c80e39fb9acdb1b836d6a7605e93281cb1f64746e6913a8910e27abc301b4ddf69a77038cacf1f36a4ca51706aadebe9e0313585adf901482c0de6b14154724ff40308a4076d024ade8b088441d7fe1d17b15bc8bed23921b6101b05f9436b382ebea409e6be863b340cfb103608a87da97775e8cd056c688353112942790ed56ab9da46322977ba0c426af2046bf4025cfa04ad8809dd04d9321f7087b135cadbaf5126dc5c1182421496f8b50d230f5d9a103f0fa1a2d42b4407f876a92b416be125ac60f0c9c10ead93145134cd1cd8b968768bd42af51da46073c0a19dbb405cc30976c1f3874324bbd425e846303b8c8c01542d6863233a122c1144910a8b2396ad987306a4a2dc8273a40d741b60625150922d0167738bac7e4f6b6ca52ab1cd0ada5e55d5d5752d9019f707206290d49b31c3018af200419258098cd159141c34d1fd803ad74a382a4fd32c57d11a932a0c6d9561fe176513e0cdbb61cee338fb54769c20084255b3ded5093fe0783796b18b85d5d93e650f5e39c53e317bc0e881a75c542a36653e517bc0525f5370c68487183b6e3c4f7e9e9ef258a0d67e09474c70c475e761cbd19bc62cb9714c79e9cc13e1d884e4c226f133e181068456373ae0cdae6b2d141dc72b477b0d864a57f5b5d3f32b6bec7e8d262d8a694a030ea07071418da035f40d4bed45df3c18aaefb09817a51e667e81e97d077849033beb4ecf4be80b504de9baba66bca16141bc89bdeab8bd66af424b266e6fb79d09ce85775615d43a99ddef8ad2f6813a7b0f8603ab8f6e6ff9b3064fef8b1843c8915d4616921e58c93593760469b8dad6017e6b289acf31b8b2ca59570ae8bbb622a1538cf7bcd7e41bf59101d56634d39064217d21d63ec8cce3a1b746ef54fcd124607fb34893792122e5cde06d875e2a7330c20383d2af3b07dc37a3389d1ec6197ad2e0586a46d700cd656a339bdc00792a796e3a07131a01a9f47d872938a326074abd889f81f8fad0f2634c1b8c6eac8af67ff9fc9ad0c1a862748e04fad1c8454e6cee6fe83804a0f16f68a6b4737aed674b5caf706e8ac8ef421e6e7f434e799bdfe8426c359764492900d6a7f1742e3a32a0277731c82430cb7bf2c4fde836c50632ee7cffdec82c03e336a1042d3307239ced5b886bc13a23e0a7bfef22c1721d97214e8c50fceb2b4189a583610eda9ad21a0a60866a165a799184b520baace846a7e79a6ac1dc74cbc53c67f30ebfb622a9586a3714e9592da159a5debe8ef376708fd5dec1b17e83d5ebbdb41814935a69ac4c5194d13927bf7fc501a5f5fbd929251f9ec33800c5632a1236f844a75b49106adad7254e06e48a1b13ae4cc0f09463d6ff283e68cd7a01c52720e0c22c9140447295798afb48c93c242df820ff06d70928fc6959be3a16cac9854b572de7f7006af27ec864b576f3b4222d91ed2aab11e66ae912c1040e0a1cf1cdefec6eaa263bbb85ae81c724145f093520014597200a9710d9127f0b3e6601928453910e17a85f1700038486bd8c132556b894455130a96cab26441c0bc9510a2977e87ff002991331f5aa8d4700632fb2f11ddaef0203ad8c14e2cc2cd7dc0163e03582a78a78074d103cc4790f0325056dc2f044b37a80ea8397ebb9581c5d22123415506f9a081e9424dd3413000460cb144a8f093f619971faf6d98a3bded5c8150e7413166232ed59b2a4f099696c62f47a84c39930d26ba981b41aa55d0469519d6a4acb8269aa5471e45c94652ef611a88460bb31c7bb2596fcf65929e2ca36297de3ff4e6027e4d503135649d8fdd91669d324ed39a1061a3439a53a5a60a326dfeb45eec36f832018b5b444f0bf1524b45cdbcf6133bd96a4dafa1c9efca189f8e1260cb2246d8f02c4842406161ad13ed4a55a87b294eb4789fd175437eed5b028727ffe7439b1c3b4962407c30ae26991404edc855c4a01c5b54010584e81680ce4808f1ba314b00ccfba5f19c02ca4a4e14357bfc41f98a3377238f98de8844d1c3ca022591707774f4352b2a1c5d3e856ac9f5660bcb587e8c3580d6c76fe9c396e06ac5e8040ccaa46037549f8d900d9c29c40f96a1863c86aeb7c375f5d3c484fb534902702304fef264025ab229fe65e509871800b224b20ccea288fe7a38787a3b7442f300101b79ce690583384cadcb2546d468d34318fb3280a853cb6d60bd4f33d2143dfd03c062772ca6c9ba4317a3b61dc658da3e35c91a2fc6e2b1552579c52359a109e27667e7294cffddd04a0937808253b7f84dd977f9a1e00b88a219ea7dc50d329fdf0d9d0ca0c23882d1aad09353bb1ff4a53f3250949c67d1da8d420556b4d399de51a0c1dc77b64dfd5c669e6d84efc158fec2313fe629cacd1733c4a5f8c71a77218f2a56950376c64d7302c4b56c31fd3d44959d6afad7bdd39dbdb4d514855c480f23d106dd50844209b0a546723a4c4c82b2f1d71dc3460338f8d59c139c842d5b22de4709c1317182084200a338990fd59f7ce54cd90991d2128454a0823be45aa93e14446f90d808f06ce74c76f3ed2ed03b0dbf5cb80fce8936eee86dd636dba53a6c66c51b567c1262da575c4e3f6bae55ed01830892898fa9578f4596ef081fc05ad20c6c58fdd0dcf9f316b42eff73de75ae1737f10f5f9aa6898b7c8838197a4cffce9ddb44465c92bb6e77a1f79a172ded3a893f17beec8431da52cf0ecc0f78ae3d6ecd3da29eedf8769669d3e9bc7e6e0e59a160110e4e82af2894800721638c65f60fbe3e80b6d89fc99b52cbfb50292f3c7f513bb221f42234d64197a56260bad1f06df318236cea18bb5700149cb01473e335d7cd6ec47d4ae8c902077106287d67db85809837bb821064c9ae0ff9552405a68929e054cb5af4d845b6d342184b55aa25e7efd55e379ceaa9f8672817762842a1958162306ff629d0bd6d6c7e991d61c00343e2b400244c5f483a163a9a76ef38b8e8750e0b07d4be5716ec971e0eb409db861747134338c8989bd4325f3d7b5c999cf7ff595f841959225f04d5d170522941e4242a972e12f5abc280ccb6738669007b59871ce7597f9596b003b41c233b50f35c950793c3a625898fdada168fd0d18c81db19f51313161545845d8db20b339eb7acc5cfe4119b746d671b1e80c3fcb29a0c86b22088fa77ac035a07eec5bbbd364c0d7c4258c3591cc102844fa863353590206604838b78558ecb075a4cb6738bd2e4c203ef9a6990b8077c627f472d0bee8c2140ef111468d8afa022d9d76117ca87b7f562bd0892f16b574a924ddbee141166977844943c09b3e65004a5bf0c34ccc6c60b70d774f6758b860de80cd08d5dae3d0951c5bda3eb9f3ead78e19b26e2b16cd280641c4a320c051ce540433997b337f5f2110be182a954eee183ef8a93ac4d9f250531e5a921c79e78bbde82d4995da489170a73f9e4db0df0c203655f0e52f41305e35365908131867fabcbe1a54d0198c1d001d11af417a6e0a7e75a7fceb8645563e33fe0ea2aaa4c4d84c7b03c7f05ec37e2bb1e011bca3f17df3076dc4ad2d2d242c42ca857cdaed821a0a95438cb5018b43e305a8d188b890adb3504180c7536a90daa81ec34130865db10c82f9501b67a8f50a0c02fa63b8a8ada4967fcd9d7096f7dce32d854e0e25339b217382d835c555f6d0d840f72d0b1a8f8078f55d7afa537ebccdc6a75981a74f60f7f11b600408a7e417ed66b889f940fdd779c7bd194af212853687378f56a0b70fc89b47aebc32dfaff70e392f74382fd14a06f4e43a74479bd371bbf86a09ecbb77bd6acd63e2673d392f61330dedc85c4531316016c08a1c3ebe72060b7a0df1615da352da4b849123a5f0390e3536b2b020899d99ad0c2ef0d9f963e0d203764cdd806f92e8485ad4537bac7756ed400946897d756a569b00687daf7f519e73b75161f0cddcf79cd4ab672e45a6d8e97637a3b2ed1e520a983782752ec266d22ab3b75479ef5a9ef74f5c2ffefa4523dea50a3ff507dadbdf1bcede271233116c70a9493fb8943b903b84b2b340b63109b327c12914cf9f200eb131b0e0df5f7982482c37bf784881c7d8c294221c8b989cf0dfbd0367f07202207ce08d0590e9507db901a2def4478df167fc7801bebeb7633ccbbe3aea84377b533d6d00c90cf9ffa7e20d8809bcdad167cf47ad4ea2790177825eeea966c020f83dccf087dcc27cd05c1bfe448419ca557c94d7513dd0228139b7ea58561c1ba303064f3b5b90580feab4ac661677cb373f9d52d8044c40e120b5b4459c9f795aac1ed50be1c1d18a72703a42ab317bf108bd2c701a955618b240e2fc14c22221085061c28cbcc83c491780115367c83057491b516cb15c1fefb132bdf617eb942fea8cc97526fc2ba21cd3266d82412876b9a0f83578e7faa3e631c16f8749329eaa03d7cd9718b44d2c8429539cfa8eed9ef2d634692c048645e5f2c641539c83563e8514f758bfd2850d7bfe15024421875917ae698cdc1108304ecd83539766e0b22e820edd45121b336072e67acebcb2e1a9beadb84f06248e4f72b0a00288ba59f67ccca91cd94b56cc6c1e8ea77b385bf2c7ce0aaf026c12fd2d7428a5e482a0fdb2362ec17be85fe971759ffd054919a45cdffa348ab0e5e812030159cc03b19d78b2d57be5c076a2d09f54a91f91a49ba38deefc794483c836ea63ed4252b1312f2617c9948a867d6d7c9f95ab61fd6af15f95d66c265bf9a98fbd75c3e73aa30e0af0f8b1e035b13a9d0bb613e8de0556ae00be92606bc95a90ab20462a7cd6b5b9b5fb252926704257f87f4e3887eccb60620efbe4d17cb84c9424c342f989162ecf423588cf36aad32cc19b0b0eb1b1ace3a87092bd070b0464216d203aab6ddef2b2758374d2f10094b4152c7ba5da4995e89bd4765a7adbaa87d5762846d79d52e6621c10e203ba175e7edf5ede13e761c2cfaa5cc17e5cb64618f69853c091ef9fbbabd8b57c9e2d72a14e23d3ebbb67010d8f472c9805423df1e68dcd526e21891d5b0f235e7a59aab86e75f882fcfd28fe8e2aebdd6d2b19d8b9b19a2807349686eb1606dea25cf97b2e587d203232137924fca1db45dd2be7de55b6a760dbb01e5b2661b3381994eb61a24ccbda60bd322646a7ac4114ab145a1c3473ea36a6628a5fed87a616fc3ea760ca41579e138b62731e66143167f791c88a67820b56292353c9f9f318db9a142be455127972a298055e93315f9e548c6518e1cae6fa1406b6ac8f136f4b0a217d2de576672ea170824b1dcea9dd37431707a0bf6a12d411f163bb30d90b5d972394d7b6c32e87b7b5b7b88f6c88e265c2324565f92fcb17008f6c5f9e99323271165a0aa6a81494490d7b935981dc43c5296da0ad648d16551654ee2b7a98bbe0f8d0a5841d2aaad430aa8cda85a2ddab1be7d2049f241c3e5baf1ec8d341b36f8eb49c1ee56083c6d28f71cd6f4653cbd98507081e795a066e226c0fb4d2c6e1fd7fb7e177bb0d390319b4e0948c720ba8b1ae58c6280247b777a7324eb1d57c9fe7330ae227f9e4a49350e44726936775937367fb46b624b6f69ce3a06bf0e7f9480d29061d72c495e0d7b4c9d66289d944857fc37925368e3c34d03429e1e5273bc27918535a15e7336c140ac8124e9c2e9b561880179812cd08e33ce09ea7ac52197b34c9da3aad9435be0d6aa53357fa1303870de46ddb4358694ca249e4632b25d56f4b458f9b0dcf5c91764bf8a94524c589c3756bc0b0af4f2badd46e6ee0ac4e6156723f6f6746312a50495dfe4d5a1f1fc85412b61363b5b1bf5f6d29e1e2c6946868852701d5bb057df911b71f550481dc191d8901a445c12b698ade5583ae67a0f226d1247d3fa6dce4a78a0cfe98d9b4b0581b47b88f36c34abb8e7737964df85e012e77640ca78265a13f4d3428329c1e53f6e152cf4715f8b129145142156d8dfff644233ff2d175d79f87bd37e1948fae2f574b1d274b0ec13bde05ef8db54f1982cc795a40119ee01099662614e7201635d490e7243caae301d912c0b703d8dbba7a78d299d1fa70293202bf7cd10a7f8bbb3bd231bc8a97b0b0060817e13e747687db9876febade1be570d631772395cb676fab1fce95322ec350d9672423da22ea02b930f3bfa90bda31dfd614047feed67c1e4cf11c4ca91fc2f6b74f5383521e5c1cec9e3d81a8e5d948b5400c87f9a0fac49508eff3e1f95911d5dd13f3f1df388466a3af4b1c397446e11f2630b55b061d9b76f2ff7b71885a8ad424ad8f4da9f5b901f5707b438c2246983018866826cf7eade1b921ec3251f5a6283d37699964998d56472bd1a08fe463da4a91ed118af90bf3a7ff0d49fc554f5aa79e38836f6b19ba777cf37f8241aa725dee6d7fc0f1dbd3e059c6b69b75dc280217426f1f3a251dda3fe726e24a0bd10bda449bd55df63cb9bc0ce77f0a32aef85c78d69978e9de58392a631dd21c0dea658065d1a5c2597763c846ac512e0cd160e9448d1d7cda8a5198cd8a825434d4a0170cc266aaef5a78c7d030ae80f136dc41692473b059d04b1e972943d86086ea019511d615e21272599c051e54e458b5873eb3450437a251dd7fcaa5f6b549f1cd2dd1c82dcb680be32a1af7f38f20067e7a249edaf75ff4699cf5d25b52ccf8c35945cedb620f0b9236b267e804141012da3b543abe6bcde1f1e363621ae94da82f61cda86eeb1b2c0e4523035499201ed5ec1933f73104ebaf827eb8bd1fbaa09f829a7206e8369619a47be9ef37f6563e31271c9cb44bd580747ec37cb50f32629a6233c07239cd8ca0b091cb24cce0bebaba8362701d7570b8d13a960d6ba7316ccb9d12737436617e8cac9921a7e15604cb692da81213980b4742882c2cf0d38cfe221b8deae1d01bb26e4ec56486e02cda2b172a7944cc79857a8744533ecb0e5d8d59a67be46712c48ba5d2fa34fac8fc8b3b12f3bcf5a06844ae2c44462761d752a8de2cb38b0018e868581ebacd22690392810704661b5b3536c8281fcb7e1ca7f216892a1b09abe4260a96cff14138920f514a3e86139bcd09875be55d9b45e8a674980170c2731f53f221f7937c9474a400d35900bc75a41ff4d50beef98cd403e4e7b30a89041d6a107bb376dccbb081368e5d5e64828a2e302ba0b5123c048249c60751ae5c747716ec4bbaecfc1c687ee3c34bae01e5ca8c22e1d791f12a72be28d16c4e6efb85c162741b27f2c9d5c7cf704734892da45aa0cf00062c390c5275fb52c7a2f900c1029afdcedd88cdde606925011a85c42d6f3c70af95c399ca9a7322b5cc23e58543fec4ee52a87532d33106f8a4d0167e9b7db2f16e016a0c86ba70fe6c03a712897083ead0d3b31175c331db5963c30408370c08b11e7f457ea44954a54a6f1c15ed771eb2a0fb1335a42967fd05809a1f6c3c3376a6fc80657a9842eda066c91f9fd9043b889f822f83c11fb28e83fcaf2864e5785d0ddbbf60da73b86539feaada1b551eccde7df9deb238a963666179416234587ffa89eb4e19b2a992ae6d68a07e18a672a958df1c69c1f872a9e2c9b2cea80b223aa626b3b23d81ce4a598d2d7c374cc978fff163eac42c84a6c0cf88ca6c279579ded7d6f621ab72e180f5b0279c7b72dbadf5e04ac30d0764834e83d5f15b1e50a9046a94c6fb653af7ef215a08428809b8a58032e78dad5ab058cafe3124c000144920d85333c62dac934dd83c7060d7dacd811dc81ad13275a020e202f8f9b8632577249dc1a8a2dc25ffb727fdcfdb7f9af9ac6ec8a6f096260f7af709b689a22dd2f187ebb73df5e439d2f9361a14b98c48f9eca0c5259abd3722dbb3bbf98b83ca4f440b6552b1837d7aef7c607aee0a78e18a0ff430591b78f62cd99fa314bf7396733b2e7d946b5ebc34d0d86158bc6175d5cdc99560970f34e1aeff5650cf47e4237cca0b53a981862d0e8931b0ef3d8500496e04dbebbbf15ccae0da299dc0fddc597027e4eaafef71bee2d6d74829fe1dbf3d2d7836115a80cc5aace84838ab19e5714dfb010b8c79b0008c6f8d350d3c8687dcb2e48ec269d8ccfaa9d773e7207e1dd28a3857144a4d52057cfaac8bfd41a34321509e9b52c16358b068917d5832c6654647c4e2d305072df04c35b2178bd08b8c29e91a417128ae5ebb95df1a24a06d1f1b1eab3b5b1ddf1818d613909ce3234242c2aa8cc5e163009bd4403e03732846ceadcc36fa935d62209bad635a69c4e13a71f4bed4f81a9d514aecc664cbfc638763add6f8b99ec84a280cf5e9683e07b20b11f1cb0fede3eb5ea69af42e40ec973ab65fe40f5bf283aeb72556df84c4808cb28231132532d2dca7f78a99c857e7c67ef2b1357b28b994988d90a8640d8ed9083d315e71d5162c7ce8d08d4660ba990109ab991ac399b951ce4c46b3fe7873a39021e7e12b04e653a305ba793a54003c46769dee3197f2ad465a298cbc42f3d7a1f480efe98d0253cd95342c4cd22049cbf0b0c267a104c8b33f961e2af95026fbda6d204736b18b49700f8e87a21d096acb73dc1a7ff29f49032c5c2e7a45594740fd4800a368f7e08758f2450a803a717f5ec012549c04bac9163b8a99ab94cd5941671781c0f8fcfafde5279e14be8e5360e18d26e85740bd89085e1df9bc3189fdd34c6e9538f47d061a2c1fdf2529f4b2494a5f0f6de1e40b3156dff9b59f4299844a507cbb36f7bfda9c35454f47b3690986958f46c80710edd2d116c5e0e4faf7c5a68682439bb925a164969048d9e86f2474aba183af13f6dbee1e839e9c36e0a6aa342c86722b6e171280e1ed4e58531ac8129cc0beaa041af085c63c777a5a66e21c2b58b18379948c3f5e5fb3051517b889348deadb315425536fe5dde70fecbfe37a5e3660efe3c87e8ece9576674bb93db3d0b47f3a771cbd8e7fff13887b7bac15735d7c6d9c6ac15dd22a400f3deccc24949ae9219c9ca1e8fc88fd798cfe5ecc8d259a84fd442be39514c7d0b7fd08ef112fb70df9f231362776ed9a766409b8b809b043c681159bcfb72331de75cdd6bebd4c453fd704bf7dd295499067191511415a4536897bb943a6f5f5397ed9a8ab85ed1cff8782a3e889769e5306737b81249517ee2a105479b54f45be9d580f83d85c8039d9b34ad6312d86c6bc48c30a3dc1c3297d855d49ced13e2f353f9e41f252b6a83e72b6afd2a5e7cf54068ee99f2191935166c7d7135db821b3fb4b5b598bb0413b1a30d8bb731e19f57b969083ee6bf340b5547dc0fc121de1d079ac11336e0cc865d22986d3b95826fa6de54a45e9d09f63f2154a6da26dc785d33b36e6004414424fd95dca6682601fc1d61417713aa6a2e0ad11c03e6cdebe24ef83ac1191f5c77f43135db0e3f7fe515b185873d6f6ceebaf125fef4500e4754569303240d40e6d5c7308cb1d27efe375c5a6d613abbd2b196cb04becd63fd8e1612bdb291848e6089a5258991254c0f4c6f4737f27c3e6fe218f59b7e3fdb5423066cd2eed6fa539b4d0018ae4ad65ef9034d7b1592556e7d5aa8051bbfb112236bc6869385e19ced1e2fc2c4db4625d439cca0a309146071687ec3f7cfc94e3aa282c84f080aaab2e4462f841537eaa96378bb74e2c2c7e24f38a3f720aa5f37b4b34bc5d1b2e38ae1fc869fc8b558a35cb6e509670a24a4fd9d024ff6b2d2ce730e0f0359495fcd98a2199ca42b35613db27865dafbcc75c719767c48708733e65b53d052ea0922b1546b33d76cd9b1b0b11bb1b79aed07a20e8c4a99f0a37132c6b86903f556db9130b354698e3303e50c73aabeaa670a6aa297c1ac7e9c66f708fc5bdbf397474a34274f448d7935d8b040285192b6600cd66042fd41400815fa9e2f838c315c1a02fb820c1dfb36d5fcbedca77aad73ce9420e7e52a757edef19e21909bcbac302c7b1075db767ff16e8c933ab79b7ba4b8938f1ee2e759cbd383aeb18bdc883d21b8d03d0a312cb2c307d754889022acca3169054122d191dec1546eeb6b12b8bc940307c36fdb9105d512b5d631ac344dafd65096e51dab35d1c33fb1c1bdc6f535f8467dc5b54b888c6e58e2894fea19fc684dcc35e22e1126a7520d75d736a8ce3e91655dc1e8f46a99cd05c5411d72b6e1ad6b34e5bcedb860ed62310e96a431fbfcebfa14a444bb134a73251c3c1a33f75c11f66d97c813fadfcf0af55f00efd498ab1bb1ca18dda349098c881046e7989b162888d63841172a5bcf65b42af81887b60e9aee9f27b6eb1a1957e6b1fcc8f807642e568621dbbabae3abaa7d03ec80b915f155d01e6aa08f2f6d3e24bbb4c881a49dbce2de1d45f7f999c8336304838de2d3a57db7f23d8fb29026021268cd3200bd7d8937fdd2052eddeb68d8510bf3562438ea0eb21f5eb5611f4f8e6e0871716e786e552e4b480c5026bcc85b7103d65c7059dd30239ea05a4cc337b658020b061174d5c00e5a19ac7c3bc42c2b9310dc491fd37d50451a67aad59a6f12ea4b65a5077e7ea387589955108d7d838457d82c90bbdf0d2ff79627ff9b604de9d2cb55e10329daae942a4c5eec8c53525c53367b1f3e971b63f4a05e36faa7065ac35eb21ae0dd8dac51b045d4fa68babfece59979cb36c54cef4e4363d86377d0d667bf30263d4d70c9f95d620d1a9b1c584bc3f08a940dbd6db17528dcd1ffe1e68d28b54be1347ce0c91e3abb56dda5ba9b32ed448cfde6368f41910160b19b908f3b5609cd833827c990579298fdbc527868f01aa563851f094847dca8644eeb300d19dd419da702f8bd79b2b77a2d210d5f849bf6f771533a9e9a5593baeae695252629a61fb341478dd8151571873031793548503f53791692d5318d39d93abd6cc5e77f5683bea336673382b647829101cc83b2c49405d10a8a50a5b4ac733cdfd8f55d4a2cc36d2144ac51c95a6878a041fe2c79302e7d69b11112d4214a3cc2d6d54ad40b9b08953842f1ae0352bd98938bb615ce3b9197a8b39e25fc62dfc7ef784695315aceb4724bcf8d3c7a4c0105fdcbd8d8508adeec78aca5d536d34840f2d0d4d33019e7fcb75df9becc703243141d5cf935f9d42f6b36e3f67655845ab79add0f050c0ce40e7e28179673bf54c52950469aafb65303d0e27bae68c18b741ba8f7c1fe8f9633066d49c47b523c6f09d7e441895fe50a71dcfac15e0fcb13f5082d2fc94a5df8965b5e11ddc4d11d36f69cae7e93694e214a0996a0705ea35139b3f6b9177343ab967c6d848a43367be183948083883f4765312b5094103b66e8c8d35cadfe3c776154649a9385a8442c86a391b23bba19ebbbf1d0201471337522399b781b5376b9c3ded4db9a00f271904655ac4ae42474a2cc0b1d0f3528f72c57e5e62f800a2c6c8d19413e51c42f6081bcca51ef3d87f16e16db9597beff6801a76c3adf2793a939d296f302a351902a3a9dffbd185ddc24f9eba8d57dc001be14c69b5749c6f6c6a7eb6163b1e1571c6f107abb3b9a1be3f3fc0f888e69d07bf07c24be2e01913f7df895511c74ed0197681ae1f86559ecb64a09f869c50412a9d8ea3759f356aad509da3617f739cb1b95da1e19b5140e8c0ceca139274d2ad7d41247b275ead5039d27667547520f7755f9e2c5c2c6836e5f4027b0160801bfd3240e73a65d1a97f3bb48e431c241028e49eb846939baec30c42c717f4cae9f89a62d2fc51ad6dae1cccd268f606eca0c96dcdaae574fd31152524bc787c244c69b31543bd1c488b29f7101f8e425eef3c6abd2bc0c55b308b305b30d1e7387462087522117596cf1dfd14a079430e312f137220959a27864c8f7b4a2a1fdecfdf7bce75508ee81679731f32d1f7f3198e3f535bfdfa09170ff6cc0a95719916083a0e8ad9d3e47120c9e98ffc7e9398dff0d74fcb3361b51b4f24d293c722cb7a5ad8954b114192833d3b1953ebc1e8d12fbab74116e56d0e07519ad354ab86056234cef3704aa91c1262b4d3db4fcc12c7a554a10051f52800a0dc718c519effe3fd329057226eee2121d848fe075fc439955a509a5c1ff8506c68d54e6bf338995b6750f9433dbebc89bbc3be0b8c650f2352925dd5b22dfb43834f15aed82f3f70c32a948cfb11b4867088fe0569c2f5ba14c012f23df7076eba3b55e2cc70527d42ab4e57191f8a25ceb41b9d4d01dc64a8efc67fada379ff5d48c33a0e1c3521387fb0952918d8427b695e8862f40c222f20d30a13c7c6cc8a679fc2cb8e469018c977c31168ad502dd28428530d1b630e95ca75d90543b64da9470b0a08ba9b1d45b956360cd7a61e4d9fd5f339de6c508b4831b55a222159f573d55de262c44e3efea22dccd0063826ae5882ffa001f78930142330c4d652c067431fb9a574fd40fc436b4b04d3e9cce778c02569f12dc180e092e8629fc7c38a70867360dc6da0d5e37c9c14733816595ec3e418887e9b9119fe8100374c6823bf5d06d5d1d1469354971be8640850805827dfa6f0475dc530737d8e552701cb47a35498dc2e01285f910aa51583e810d622bd16b450a78089c1dd5731e1cc5bb4fbfb2911b3c8aea094426c16985f27b085e89ed84baf28f85eb3cec2d31c65116978a44a575087b72150ddc6460babe6a332962faeb90c4002887d174dd01bd4194e04488afcfe402d54b05fd70f9d19daddfa35e9427eac7f4ea0c4cd24bbb1fa04e7543df268f32cf221b57b1fe9156c034c4aab5576d7e91820be44060874136b4bcbcc6b4f27681575d3ac2c0f396b3fc9e8913c225bf35b8cbbd3e4825412f53c6b4ce56305961ae0abf8ee5412eae33462bc489b6c28a3821e2f89afcdbc34fac7fd573699e46f2b381daedc84b34f91718ecb7de5268734f547f15d21089c88b5bb1bb1b5df6ff1ba655212acacb9a1d7afc9927abd09fb7493fe49bd010d73e0c6f5597c7babcc094c915c4a1414583e6239f0b75537d975540e73f3e8bc0d1b28c073072a1b0596bb36a69696c514dbe9bed38ca8b624962632461e4a784c64dc0f258d2c383d0fdbca7a08c39224e0dfa6e13d99d70cb5290cec2d725181c86ac2e4dc3fcb2a5e630ac60ac4085d76b162abf6c90a3969274ed348ff8c2493ab00b7251da422eacf82247cb2f0b0f4f31bcd82ce43c6a8160ceab52db4d5aaede3f71f878cd109e6795a01b7ecb23365511cf890ce9a45609fe555ee41680d902141d3cb45b46400cb08e53b688df527b14ec84264d0ca6ed9b3615f55e4f4384d0c6d4489cd75ead20a2db945632752c965d06a402f9ce0b0adae1caf70a77ca665e2b3642cbf93557356ba98b4a46dbea590f6fbcdfe359717f1c465a2b7aefa88894f329c22f04e1e3199189a71955e727edb4638f849d133ea0e747b1f3043400d4a2b8d881794cd24cd299bce6cce65ee63603c56d076a4a427b7b86fc48be1f436ac3cb21d969014c803f0ab5dcf72a72e8293db0c4f0d8b4751349e144df9aaaefdfd875a98cbbf9858aab07326e3e44d91c51813cdb84861117bde4e5dc7a84f9bca8e960801c35d29e3b592543f5bf197982646e510b6d53c697bd3518e462d7788b04d66626952dfc99e652064cf68eb6993eea16ea02c30361a1e69c413590f44cae96e8d6a9e1931a45379a742c246bdb78a11497d6622eb2e0aceb201781a1a22b6c1425319aaaa10a9dad236d99eb1019b884ff186d6759e18948b8fdd46d6cf83f5efbc390a14e97f8781fffb40811dfd57bc684fece0db13aa6a1c214493f19cb0707d9cf72d9602293ca31bbe5b8d3834094a8d0e92feb4aeafad66853ae8c3b6dd410abc5c1a5e94137b325200fcb0545d6121a790afc49a8c8cec757f68f5991b0c00fa1086d54040d1452a819a5c1aef4f3738a6db25505a7b703b11659fd0897b62c36f951a4e0abcf1aa3e10e0c9e0e44fea6c1a95cb7c5a36d9933f9445fd45752fe1f1f680af3e92172c55fc159d0f911f9ed2116a323ffdd64faa074e649017f7cedf28515ce3d46cc6d01611617fae87d82df6df30546c589e9817b9694e4db98c63b0b9ec204eed41186b62e4dc60e69dd9fb5e3db4264293b1111aa1be2bf9bd982f2635445f53c1688e52143233a10d374e01895d072ab317b6e878de15a65f991f93d367e634a8019b4166927c9a24b98ac0725278a7dc9afc616e381782d503be9e49422b45377d34ac9bfc0089b037bdfbb0fc7eddc00dcfcaa597d181e39b7ad17586fa8cdea62d8dd906f56333cc6a831b9d03cc5b90c37339b6227489ea9900dd5e1d5908c28020694d9a3cf024cbee07ac85add847c1aaf2b0b62b303e2d512b7c08fe72e17c603a9b7c581a7b3fda3c522c3e30f080921431e3a4596ffcc941612685df714c506e0b216eac8cc7d9691ade7cde74edc2fe418da8b3fde3224eb882444a4392807d44d161e5d6c51dd3b771dd6a4bb30b91a20eb64766b8540336473dd097dfc3490e8de885f345995c8142fcfc62747bea4983f02bb69e1d567a7c0784e456d326a41e697ca8a8f342c28203df70ea7534e6df76201d93acc2f9951ea250261215ac58348ef6f32e1e7fb5e7e69d9dc8107d9a253b4ce4efbd5c6a8075b23434b293fab8042e9ab62161373a9679132b775394c8c6013489ad462c86a24431ed68abbda932058ddd126a4b088e3b4575752404072d48cef7d4a83e6ba7034ef779bd527ff4906b6a62e15d4869f51bd30047a7b60c9e29522d6b02cbe992283552200559a76552a5cf4d684686376d2b69572d58ef12c2bb560c54a9e17295c8727e5ed5b601eebb2ed7bc9d4f52001b12d5ab85123dd70db77b346b12eba8aa653bdcc49ed987dcd9b6fa9e8073c71a311a06c31442e39f7d6954f05400284403af0c880a71f3a096289f9c97f8756a485baca2066f230e0abc16cc07ca8119caf43d44ed5ccdea9af525b3fa5e9c363121d15e6e898215d6a9dae0764599d66bc88bc037f291c879f31b05e9be4467522ee6d36fb1ce9603202d0f6cbb30532a962f3881e604af270b9d639d622457985216e1657d25bcdcc0df17bd023a5729c4f151162514e1874e3d970be14dd08704172488098370c27a90f74e15b0a5a1612d29feeef192c412454da4040ddcd0722963c254b874dfb158253845fbf7b6015b0833ca2cd024c9200096cc9df8a4a41ca0881011b1392401da68cec795093af2e2e7f83916089733fd4ec303dd9457e17a2e44eca9615f62ccfa3870ce672f2f34a0e92bf60072799442adf708c17c163c0d97b483fce83f12893abad2b3c66c1b1ed0e2484170799a561b5a6c9d6c3fcced52b61e14cab90698d4dc9093b6e09aeb491e278eee4c6f257fe4fbdf77f79a672cd5515c78e49e9dc3e81b0d51db9f4d970bceaa75e531383c16420759d972e8f7a7362410f0a2aeb0014fa0fa76b4546b42c8e15cd4f7c0b5228240e4f0c6ef6007debb09c1b4c8e63e21798d5554c21044bcc2a6e7a2136a6757bd456ea7217bd0e88aa3226d65611c205431747d132602d7f7409cd74c167471f8a7041f60b4d41ee292d551377078a5fb9361961513278cacef52356f1064a44ae356380b8bcb6739254beb5a3a6cc5feae7c4f99dbe81073fa38fd3905bc159d13b4e896bd023bba3f076e276444d87360b3811eeede71b96cee3682a27d35282fd6f44989e73f4138c4a29eaacb47cc28f2c5f2f2933218476c497737ed4501ce3e624598b6ef0efe7de6a37d25a051264094fb366622ad6f1be5ad5c3dd49655f0977c802a55e6e570622135047dd0ac1984ad7c6b0ef865ab2e64d15ba658edf0a89595c2a96470eb134283976accf90a919931e1247f39f15296f667b09700e990ca37ce8a85b9fa32cbecb6238a493a416201f6b24beb3e45371c973744430ae02d85237d510c2a5ba7106eb4106cabf774d04ad3a08c66e84675739dad7b11268a21bf2f7e51baf213f4dbfde2ce71fed0c043d37ab246a288d96ef4131124c9f6aa4eafba1d2355ed51a15711e2b827329ab1415cf7c61cc6d2ff614a2c9d05500b310efc37d8bc05f853d6da21d0eac7e9a91ca31841402d249db15a370a44f75ed3991ca3c7a51a9b84e5d765d316402c11ddb9df587908e08054961f9052c1aa5327002f1e2f8bbc3bb594fff81d8236558cf5548a40c4b1b03721e3275c561aa58b28f1fec346091afc844435828685e71cf35814d50886a0012f3fd0857e3303d15f11b2a0a2b6df2d71a9fac43b0084e11063cb411400f4fb08cf6e9021a498f018f66bab530b20e58f0fcea73f64c6d71906adf320cff8f1556eb4c9bd4570d362d1b7db57e8115a8bfde565a4a2430ff5bee598cd0e01ffea8b3fbeba0db07286a4fa5d61aea62608f6ca5376ca18bca8f3a60585fd47d8cb7ae18b2969adea0748bed7ec7442d0f88f5cae067d899c0b9023a76c6388e22cc050eb0b55801c1634a971b4ddbc2d3ad671a57928a13f321d9e335e56ad02fa724fcae024189cca7587d498df9fb9c978a2eeee7ce73c892459f0452ac026b20f1f08dd4d3daa48b8a508a5ca9aeaa8f67bda8fd57c837877d5924a4caff0f185688c4336beeb1034b700f52ea05eca02e38a3fe60e813522e082ef724cab829511e0fbaca9a8eade836e33d3356e41bf2e1f156984b189f56a464fd8cea525b448225407c1a41c845ff5e3fc49c0fe37ee766f0c0caa2efdeae03bba2c0d1a28b28a1d14abef0274162e109a54fd0279f86e9650d038bd6e5648611f1dbc141d110eea7ae35468598dff70a8a31da0516c45f40b5dd835c419fb1844fc593d343d78a2a68d05794fa08d5630fae41036431b8bb5393e139eba0eba01ea0876ed7f6a93ded9cc30733f55d9e67cedc7e741a20f5ebac0ad89fa43b8cc78aa42c886032cef1c11293cf21d23ea0873c0ef7e5be5179918b97d783cce1c1bb965c4dc30b6244e16bbc3d56deac22f5cd50625a95d3f6e4272609e3c0d85dcf23d66bbc3197e73a096ea919a88b1f0c62eb4eafc28162623cb1e96e523f6f08a1fee78a64f6949d1b4cde3361ea87455776582f7df350a30768c5550bd648d6f4234a66cfcf3696cd337357153e2a1fa3f57a6fad70b369b6766b46d9326ab4ddc3183f9e603c9ac3409017acb59636ad0b1e7a9c65743aceed41ddc86b0f08caf5e4e980dd5f326eabc28e1ce681f62307a2f4b7e2c031765f8931c449e8178688fccfbddebf6456f475de2791e12f8e62c434cdafb0a84cf00b5490a36b4548e59bd7a9a40c4417cad2567e8ab2725dd0bb6e1f31072dbe354b78e4695ab14c41824da053256cf8a8c08e118f0d335bef1d324ab554dc01e4b00962f272e9c092fe1134f4153f7f41f4362306088e5e936642260e35bb9a8a7de6f7833a0ccc26ee9ee69d5c5c48909f1bc01028fe64a0fa55bafe8b02302f0f8c2182c254a9fd584ced26ae066c3c56fa68281489fe8cf0dfcf08cf6a93fa9a83d7186145fb5034485b99724f8a3603b54fca0ba520d87a2151b20f75931dffb2dd128b8d79fa20a8da46ea6b97e8d4c4f2ec12bb07b6ba8d781d3712af3ca4d0b1a9f37c57ccb2bbc4c53fc3324feba1c7745f59ea2c010932994243bd40268841bc44eec3e40bbf5ab275a02b1abe007bd399e0b8ce14b12a28ba0c77864c89e05cb5a78ac626ba25e9bb487c5956c8eb16f42b8423536878352dac51a1c92b25b5f583f3bbd52c50a235958cf45b0497cada21a28ca88424c69bf6a8f5e270e27599802c69fdbc0af25e8f70b6e5d66360f95499904e5516c39e7e3b1486bd57a55ba24e002028c164d3614aecb67d141a5bca59172acfa2819f860aded79af98e2107d4da7fea951f16803630644afff40b27e8911a23916f958d579f7780775556001a64a80c10b3547119c29823c8e6f6221ea62f2cb7e7a16bae65baf063169db7b4451bb545da46b5f77f1ac5df1ff72ef38898164d53b23bebcdcdb71d7d45e3fa3266cca0027f87c8e8eb6bfcd5213c01407ee2810ca8a1ac73a63fc5e345be45174753380949448e786161e1de2863e4c76f32fecbf5443b07c1e31c7c579d4fc94632797586f8f363baa792849914a98484f91255aec102e65ff4a92d5602ffef95c437179a5d2c483b724c403d0a1b84ca08f7fd3ec0a78abdbb7b05e1bf110308fdff06e141927fcbc11f340c27e9bc82fb043e1db113239202307473cf339cb291014307da46022786cfbe62bce9f8877ebfb67134312a92345d24a88082d63e0cdd4b7870203e874255b458fe5f3804f3ed0ec25670af750b50f60fb8acff97d707741ccf770928634dbf63d6dfc3925ff9efe8f32ed70ff71f2dc5907aba4cf35a661875ae222693057ddeb481c668c00656b714d9e0391bc1c8c9983f2c308b2f4e69c1620a6dc6c3cae2e3e1873ea13e31d1fa29cc15806580e534e1a48c319f6f28f00e3c817ccd451c82cc28bb95623f4d8adacb54eb9ad0fe7e0b52385281a4930c28c2a33d1b2b2a141aa219dd6adee1c59b172159e466d0071b092368d658315f9e65c6f6ae63c376adf3309f05ca3411848e14af0347c2e446915951dcb91f2ce9918e09d1cc1201cd1da2e7ebf6c3bca0fd8c40985e2519c892915de2ffee9b50d76e54051d7d21353230092ff24e0dbfbadaacf9f85d56c9873974b4382f424ce4007b93d01a37490155e716103de87055724886d57c68468f440c5ab75317b0c101260d3d3f70b790b4e8a10a3fdd846b40ad1731a868d48bd5dc0ffcaa7c3fd6c0a4ce9e085386670175d056a53161b7b35caf514e93f4e51cd54e6906356c390b8c93dffb07c7b0ca69ffdd83bb7e0d309ed6c788bcd3e3d42584af4e49e103614dba2b78cc23b35b2e8228d81d849c7ff133bab5c8adf8264479f86126e1090b897df48f9b3778171049ff92b44010f1cf03f02e32e196a14fa09717cbc829c7cd619bf03ef832d995f2848d0a265abce8bbc8fa2a2d0e430071e8feb302bccc320a05d15aa8a99e88e414f2212bb81466179e51194d1c5a01d9e274d85782d49cddbc46cacf3a14ca1072be7e9bd1799621c41e050e4f423078e025acca7e2d6603f63ef4d61a3e79518036f0e1b0c4521b6dfb4fedc938308baaa7f8833282e24cc0037ce1b27ccb0a411c3bc735a0907045a6665f80e92ad1a844fd47eb4004ee922f5c7a586c46524242603aec740fe292eaf876d47699158faec3c784d0267142d2b9a4dab63acd4ae53ff7caf051615eaaa09d4293b0233e3498667e97a475e6472d8e9cf44fdb26729a570994d223d1e3a424ed686accf7f895d9459b1d5a95d79fbebf67057248922c6751163a1dcf8471b41c49470c29f1f922a2f4d77eb6d00da4135cb688e9960eb28eac5ac380a376e04b86b623b7b4a2cb1a051f5851ef0489afce94bb94b7a8c3682c00b4882051e8b9aa6aa6bd60eb0fc43410255b19749c08d4091fb20dd8e11bcf3f810ab03e7ccc98341747201268c649bee58110048d3d2aeadf623ef2a1fd0c77c30bd7224a93562dbf6377fad34b0dcc60445373e1ec6b2c591b0a450ea32f78623bba2cdf0ae3b1fb4661d4e68a865e6e4869d9727b371a78e87d7439b3bcf7125c169d47ec8d13da26820b215ca0cafac680bde1e66288d7cd7b5585dcd062272350ef5ab500a3644d368e5aac7379843a174ddfdf46150f926dc60d0fd5eb3b3bd399012c1ba36ad0d9d5d77e88c601cf410e56f83cb43896929e6745a0f8e4a43a30e5501205119577328783ffba93e6ece4b52cdaebea94e26dc7c228703ad2cbcfdedd949bb20ca040b786c441791a45a7c986ca4bca556d2b9a42c273008aa13bcd3309db652f608582348187809e4adfeb4a24d5abd7aa26da0791be3b799c1f3c83586ece4d63a83149309296f959fba783ac627cc009ad18f050c88a30be908eac13d503fbed0f6d981f16de606ff194cd97ee6c43407c894bb5c2ba7ff3102533fe649df333b924c2d5d28bc0149723578881229239fd802a8fdf6a56f1bb53c09a91a913c499649601248acda2845d015c14af42f0c9971346139de39630c20c5a60f651f02f6926b29632b641790516582f9f0a3e42e626228feb4ed6abcdad4a614e3cd57da7fddea64ce6303e4e2e6f26bbe629549943f6d6081ddd6997b9008f0dd4e78b761249f84f5632e4800c4fb05921191a6ca173fd1f17c4af8f2171c00509a48c4f8d960906cb86e3aab7b0e79fef798ef5938c8d822dfec981f2dd3bc31375fdd17635204acfac307a3487d0451171c12ee1a209f103cb2b7c45fe2d358e9c5d2b2dd9d300271d3735bb2514ad3adf67699c2b3ef3f802d0d1a08aebd49361c0f9c5b134d1f214768bc6e1cc588fb0fa3aec1221bbc1bb3757378d82807861fef9c634f13d9e9b9c3891039de80cfae1fb7c30d78212860da6046beb7317bc7e760c7777eaaa046cc4f02ba68314657309c19a50367919a9f3e8ff1b54898cbec5cee96c4aea4aa90266193660efbae272cac2e61f18c5c3202f108aba1620d8c2f020182801ec0f2100a6d1b363a90ae07c5bead6fe25784bcefacfb1bd97b4b29654a32a5145804040483043fc46088142a539e9052c462600b059835f57a71bd18d1a8dee2eba3d6d0f057b6592fdfb24adb238558bf2d8ff555b64232f7d547ad61f92adbac6c7b96678568f9172c991048ac96ab86c52ae960cdd130002a180e31f0dfe20d228a6079ec8b68f9173a2d4ac074b27ccbf7fbf2a88d96502c58e6434bf622d34637e410d866399b65fd0a673839d69095ddc8b1feff2dab94838363e87a1c1c39164ece6549232d9fe2d135faedfa95ccc655ba715d2ba3d168a5aa5aaa2a23addc609a6be5b7ea476f55a51b3682aaef01c7cacacaca252556246f304d2565766394d9b8c134bb7384a3aaaa1cd670dc108bc5fa4d8b2c8bf4625996949794524a79c9eaa5bca4252d69b9110dabaaa48d1ba7972775295ed8cfc52e33d8a5c205529230062e84fc4197f7eeb7efef377f98b53710deedededf0fd2d58227537d6edb0fb750bf166e2ab4143448c023aa19c1f73a113899452d3fea6d550a0c92367f93479ec98fc6e79dcf26c0f931d22c49789155a86425608733770ce71b303c2fda658cb9895df65cbec76cae9fb47d59178c75c6cab8028cbbddb238898a6a94a7a86e43712c800349a517ed49ad1cb6ce3afdee22ac6cc850443c68f5a0343662fe58bc7fe07cbb73c101931dbb8c25eb0582b2596910e2396571942acbcb3947e20a9c0e8c6e829a03256328de44cbfa24026eb480e816de68335ecdaf877db87d90e1cd678d7adfb2ded60cdc9dfc132a2b1d241964fb125df6df22f292fab64bd351ad1b0ac2b46964cd9147fd3118db8325ebfc5b7de8aa5527c7959d688c675c9aa5ac96854d9c51ae3304dccb6fd6aab321c9d384cb32f7fa755551fe3ea5428d4cd0cf86e9b19925e2084f0dab0c931cad2cf4a961a4208e146194ab028f22aa6e10c3de841163d903b4d3451d44415192eb420d4d811420861b8ac86f35ad6b2afe557cb57825143fe84ee1d3e7efb30779e915873dfcc211cbdaedc5d811e1743767e6420a4040c51e2c3f70f5e315648603fa900c217865c1a7b982afe00bc80d980ff227c09af8fa51e3ee1e8537c1919653060f6acbdf752098c0a28ba98efdd0fb01212cc7df5a92bdb80cceb65bc7e4735e05bee610f9faefaf70c2be8a073f3491852c6a7c409cf7c34ccf782fc5021ca3f29ea7192c4542ee693113e148a69f4c97c0f3303017dd2139db0d4d2eb033be3abacebbdeff8de7b3038ab015fbe7ced17b9c03097caba2eab8a80cef71edfc1a8117fbed23eaed8e224307f17d2c77e349c0e3a6174432402b044f38a111d57b3190c2430fc7d78cf26b0ffde87150249673ee8c31762ffbd10485ce603ccd409f1b21b9480adab29a989df14f9f92f2ad8f614d08782a53fb820899423528278ca114454a4f474a11342f8e0eb52ab6624c69d2396c2583e225c1fbb034405888a8bf921fe7a1b403afc36808080522faa1c71717952a031dc3b1f2b78e74365dc0b1f6c53206c8642d127eae40a05fa1915d113344b539518d1641a819f627fcf7746c7369719e1791930eb5ea559c2850648b8ac80861c4c71f1a1a10916eff251a2e779bc873023b06d77b41d229e69b4c741c13a6a138f1c6942e707a55924148a1645222c45c0b6f5f16142476de24f1678f972478029400108a00cb880c6708f4365acc0b41808d335f879453a3a7a042d113bb6e7b5f7105589cd8c065093d4d882699d796665db02d17126f73196743e46f72265541bee1f6804531b87a94d4735997879f898bc58131857035b31777ffee4cb2934c4e0d758c75cd7b80373bd45357e8d8198ebef618ac5ecbbe7c5fa1151889aba00379ddd9d1dc2989b1467bd8d85f7ebf7e083dd3b58b18bb0eeeef6e8839dbf113c9722780dbf9d045a8c7d02191a3b48c2ee4b62b06661caebf7fc79630f0667c5139a05afdff3e73d22c21a28ee04a902617b15c8e0a4bdfbf573944382f9bbfb7bbe648808ca69c60b9b9e417b601a7ffd1b3ee0e4d880d6a80c853c652663587337acdd50044c8b790ce1ab1e84aff2e7f253ec19ac640c6b314eb6d40a42c055c95635974073c7f7b2205e670fbe4cb3de7d8cd556104d8bc1c931a34c4e4142cffb47cac50a6cd3283b7ac44822318dba3410ac7de6c90aa32fafc4101114b70c3720bcea7ae5724f340b53dc498c6bf1c518939c463b38275d181244db97f272a2a3b3fbf3c7cccccc9c392f6d3de0e4871042f8aff478b004999cc1e601c6ccccddbd8ebbd7b97b9db9db77e3c608a360294c3fd74419afdf830f767cbe6193f302d6dd1a83bf479cac32fb1abf63d5de0826bfebeece56659663ec67448c4d42475595a5094c1fbedd1ed696486683b525d2dddd4b647b4a3b647bf4692cec59225de5e4d8d7d26e8411427f858e3fc5d2aa5e96aa4a36aaea5996f5a41cc9fe37aae17fbd0d55eb2d592ac9973f83b5eef15e4544395e5766433f6e31b391a584307d9dfafd02a834aaaa663e58eb1dac45e9d922f05b1deccc331d2d59609b0add70291bdabdddfcbd0203e75cf78e94eeee0f2ecb88c693b0d71f6cd75d42b573ce41e8205ce71e3a084fb09d73fd9e7b19cafd7b7ed1f1ce38e33d84ce41f7dcbdbb25bd406cbe2ef55477f7dff6e7de95600183b96285a5ab990ac1367ac04197c33937849c910ec59a0ed3c4f8d6c1cf6199a3c3555b7e4508e1cbec848270468c314a1d7e8d68b8846e79749f21a584988eb6fab78ebe33f60c2847343cba8dd6d1513df7482fefbd6ee8ba1b967e3ad70dddebe79c73eea4c8589285c9b41ad8defd1cce98d5d10e1c64deb0c97d8a515530ff4d0b01434063b46bf7209c4b30d9f735d7fe5e5dd3b217d6629c2efd8aec4c54877aef596f35c26a4403be3895b9e4dceebe760f3b704d20fad7c8f5298e9594efd9893594945e954634aaca23af389837aad16f392a7ef5562c954e712687bb4bc8f022f5a8068a6922cc50a7c928ae20c3767087df33379bdcbf0c87693ce30c4786d305ecc47f61158f9460694c40ddb8682edac60005d85545bf7e0f3ed81da7a0a0dd06bafbf337c39d80e955554546de17b5e13190610996830b62da0a4642069827fd6bdae904a439130e4370bd03054cf5af61ac397f2a92cc28606e27059c4ea7d3e974caa1323910718299519bbe809a0a1db41196bc7ecf9f7764d40d4980de7bfe9ca4fa5aa3833953ec42843a383848a4229c85333f6e899d9d203b5660c1ee6ed3d06c9a768108c484859a8914371c61db62f8b6f4a66abd9560baccb25bf55e611a46627cf32746830ee183cfc130835876e102b6ad0fff4cf113a39d4e33393a6e8e080d3d39d24414a7d3e9743a9d7252806dec73f26102867f9e3869a593ca9c26f39ed486e7d545c0bc446facbdfbf5731ef1c032e1c764b28ac482e8803b53d5f8da69820f112245889060dbf69c7a86c0a498462f1f2208050535219a1b6a6e1a4ad3b4d7b409401930c371261b54806d0c04c4049e5c0d94d12ce4031b4a2d2d9d6117c768afdff32122283c7e18e9e1f9fa3d7fdefe8a520522fd5cc96cb896ab840035f15725abf480d6d4c4eeb4794096d80373bd6532c63dd107c5348e089122fde4891327575cd1a40993b9699aa6695a0e36b9cfc1010b28a6713e37f8c1ebf79c6558ae3bc4aef184212228afda2f16403cf5b5289e7714495acadc5c5cf80626d8b63f3fcc404344507c5a7b01c9a016211b50bbeb2bcbf16a27227cae3b7b374cf32858ea520936cb5db0b43909a67ff3e0e6e387250622e59584c89c7a55e2ccca162e3b65f08135a1671a850de123826f3be57818ae19bd62a3920e9d3662a808c771fc3d0e0ee78793e1e028451cac392f6055c90de1c877590faca11c6ac6cce30724574604d30a2d85bff7f62d33ef430821fcb74bc4ddfbb9f773efb7ebfebabd776494214bb1845dae08330df7ab7dc7be355a262f06afee41f74f4387f00d114159c93670c7e8842a314b3848151ee22176e278dc107ea2b1141e622a6ec70999ee9f778cc638d818c9a4e289a955d66750356d8c646e3ce42cf0214e986e7bd1b8a8b95002dbbc4811a6790232136ac33e38e889d188f0a1280a17334cd35595654130c5a9d48c869026bed48c979af152d97b103e1acf66a466c05497092ea6d1d601cbdc1f690c6c87e395b9414c8e23d5f6d703936377cb6bf481c9afdad563f2bbaede7d4c75314d1341f99906a51a8cd6905093c78fb9af3a73df470560a647f6c8ea3e715a263f1bb442eba465587b9d2c1729988cf5611f159c6620e9b5d3ebeab6ac6c3b36838197ebe2466dfcc6010e40296a4335401900821e2a93c3110c6fd4c67b0a3e2722448a14e190cc806ddbd333e4f4989999b50984da04055058292ee22286c251e8e400036c632226e22729286e681540b8430522e810bea1202127344e34cd3d01db5648a8899290a48bbb7b555553f66b20e9d40080ad061b38e0520310bbab23c6a7043a84ef46131a7aa2314dccced41dfc41414242397c3a9d4e454551a250494d1e3973377b895d0574081f7c7e5d2e2e2f2f303537dc198a351bae88d1b58fcfe3e0189203a55272a8ecce0a41ddbc6abc82890bd3fd86000dc374bf2da0a43516180d816d27d4699f3323703398579baaa66da3a0408a2387ce0e95713cd4e478a2b041a6734d9ac09c50674e601bbb2017238675cf885b8e20c2c47d69bd04846387b183bebf0efaee3e04feaea43073615363320bd853e1832bccedc47cc4d21f9410d242480b283f509cdbe0101fbb0b86e3cb8be68af5dc624fe7fe456fe791ff65f3b930f02b1f5896aab2bad730ccddbcce9fdd7719863575cead7bfbbc9d332bb373ccbcda0e33332bb36bc15a67d700d8c63666deb25619552765dde3f3d8afbb338deedac58e0d9f7784cfabe817d67bafa5e9570783edebcd5a6520f4ded8cfb5eb6fa7704af9fb98cbac9bb461af99661f3412218470480adae7d160058e073310f99122b60842c2c303173f4158010f5b502942944491dcc1922e9a54d1c5130c3006aca74ed10591c9075d3cd186740125092225446a300322b438a245920dc8dce732401865f7b231b8549300d574360603d4c4598c262f99cca2433cd28177e7f2af940256aa02ebe74b4d2f231c56a24861e90f48489912450b213f54621005c67b0d3a8194a94127e862eacb6a6c357ddae8500485a5038c11f74cddfe0fcb296408172ec32a4c09218410c22020844f4addc27237fb9dafbbba2eb391f79c70c2df69d7775f73777f1d3358da74bc533f3fa90cbfe7ce637c8d84b5c8708d85e53a87cab876ce0531e9288e080b735e776b672eb2d6ceb96f6e02e327aa6ae0fbdf85fff103e27929e60a6cfbf8de1be2ac192f01ebdfddcdfcbb5b477392d7ef515fa639b42efc8659103d3d6329b8a7d52c805c6825444586869c14a181326099b0c412459ae05004b6ad90d0154588526af386869ca4b630379da2331dd217b06d8584ae48a9cd9b4452284263ad3252c2779aec1f137a0b163688bbc2ce921aba055878a719f705f7f71c421dc23f7952852a40010a4c60021290d080b9690dd0344dd3340568cd05d4a4b50d3b9a8f108478788444c1644811137b647f36898e0ecd622a16a652406b58244ba653844da11bd514217c9d18e1f2c408e52e0f0fcff22c4f559d2047336c11e5d3622c2dc6d262acaad262dc568eab7e107655599f62ab6a29a5bcaeb6b690a51baf2606520ca5d186aaaad0ec1b737fc75f2e8b18049ea1a5a8c1080a8542a152286772989017f02e84259e6ced0e0d64fab315a55ef2922069a84b357eec355447d5b875db31f78a7db590114c6af3def3e7fd1bea0028140a8532c0d2686035f7a80ca8cc4a91496db897f939e66d752b9b951cd0c95b6b8f394d406de09394308592b4484280d668cee4da5d8c1849d329801c61f2db080a0a7a95d912065e7a6ce0c6f0a236ec2f4a524db57d8ff1e5a53be3f1638bb83406662f31103f5615b73f8f511b864668fbb2022f6ada1ca4c9e3c7644c4dcbeb8ef0d81d82110f0d63bf0dc86c87fb63eef36a0c765e6776eb56de4329af070584fe5a922c55cdfa8dd1923700f568c4157b0a96b8e0744ab91a949af8af203e3ee48e838367480e873dc43804db3468eaa032ff026cd321140e1dd446a5081eeae66d2378dda81bd40deac6279883a8b48d9b0731ab118004100053160000180c060483e180703c502451f914800f638a3e745234140844418e03298ae228c618420030041963084146a1a14107e32dc3d1252b309dd7fa2bc0260079069572cfdd25f0912778bff438acfd9fc4976d00892659e065144eb16a5cc5703f884abc36ec39236ac9c68d22f6e8dfa9c3a2e0689183a8b9b2e418026f1413a23a74a79d2f4fc72542a96905712f3deb2e4531df19e7c0e10e287f6d526f88756e52b727ec51c9fede104e2c3f650d0d090a14c493773849f2a8d8e49a7722596df977ff473ddd6bf929325352d82d02c772d2f10a1ba7c21bc6f6669c807882078fcaa7754a09af00aca0de2b5c291d08c12261090a0f716772ee185e9a3f5fd7820abd449c3d71a03acfbabca4a9aa8ead156be86d6c98de91fbfda227167382dec6ba64cac7a1273009f2c48c16793ba387921bf88293cc582e19e2e058fbd918441e4d030758968975a6bc2a24ca886e9161b84f4f619fe4cba73e775f2985728c8d7cb80f84baef87cc221d1fdffdc0e8b36261c39ef596fb889522843127c9f02c5bf723e22d9c77103d53a8b3b467cbcd70d441bd9043c416a5b9894e80a28c580a7aad37a643bc85460e67af37ace7611ce4517666e2d1737b287fefbf53b37ddab7920e087a6ada1b2dc7a9222179c8fb465cd2c27124757e6476fb7317b7b070896f2b2a5725683da7ebd52634c1d0d732d25de98b488423cb0a07be5e440b8c3f7173c48ab255a8d4f08920620a0b0262ae3858d66f92bfc215a462f4ab9ec066a74c32c4411c77cbf2f2af5bd97ca2a0b8a4f34ace709d8862ad4f5c15a5f074acb7bc720397ea0e50f9b45f845b7fca5925fe750af5e3c4e039c9be96becf7affca4afd7315cb64d276a998bf5f7aefb6d64f70c4e0497604780aefba6bb9580ed4470635a02ce349bf79a2c87fbf87fb17def7793ec92667a06c322b5a46ccf986e89e52c221293b95c33d2dcf5cc8f9fea810e38a4c257d615f359989c57ed79212a9e20f04fd1e045dcb9619677c2353b809c48787f9c1f4c119a01b0aad3a8006a23623b173de268a308dd1f286643599a366c277fafcc6b304e80fd667c9474b61fd6c82a1d998cf082bb8c6dcf29da4957f3286bcb93f6e6d497669a4a4084e54222410d0d1c543030fd0e326c4c6903bbe3d7731db407a623a41a3d7f5b6943a2bb6fe63d2621e6eafc9cbd408e214fada0c4f7c6b7003b9e22c9ac29d851bda1be502af396da6567eef582742cbf80bdc1756e1974d332d2a90507934be2ddb9916c97c88fae15befd0b1acaa06cf0ae97b65ec5104b13e2b729a5e9c117c6503c78c55cdf8e2fb3bc1ae62becfed8a0aa76989c8e6e84e9bd4a66d308826a604d0a170d1dc5d37e88f9a1937630bed3ffd4ca3899990f005511c1d3999bf833e5ad7136548c3977e96c1f9fa6a22fb7f72e12fbbf9534f8bf7960de7e0b86081a2dc883200ef0046000d7b5424c4bdc443b374118dda2a3008007b99b625e52eda4b3d2180355a9591ca6dae395db38bd5e66ee8ed179ce12c97a46bbb4aff9a361f481487b12943c8e7bb34c577a180145288b34353dc659e999fe6142f6002ea0437a472dcc4d053ade531d56f2303a59c22a6ac0f213e5cc2bdfe40bda80bb0f41c4d73525fb8451d0c2506db1cc6a1c0948b986c243423d52ad65169166cafb029e770de7a25c6100aa75cbd122a5a29d5d2b23f92104ab1bc0d8569282a7dcbffeb66251c490c005c6f1c40ffcf6771f2230b80abf8468a92bcd8da023a0fc26269c3d574e66c9943d7c28614119e4e0a7b71b54a4a2b486bbfa9b8e6c996fb8cec6248db170f020a560765ae9df90214c5b1623cb33588f87c01effd151e26bf3b45650d0e2b18b0b1cd23b04842df3e687fa28de7aaca8436702c7a6e166569adf90da6e9aa1c0fd0c65f0b64812a2d1dc6a63924f3d3e2d13d648d97380ea56509c53526b002511e933543b46cb09463ad4bc5c3e4b121bf622f015742bf76835417224e5ebfc63bceb42200f80579eec1fe471a30905bdcad33ec7e36a33b3436a2617246af64f9543a422f53369a5a6e75eacf6b57307d8410b81e239cb9c130d45d143500ece27e0253baaf3f1095eb97acda7891c5755725c9452e5eaaec3e5fc740e707854b62185f74d26b756a599c8d82bb8126b28f0f4943d59a1c5d415d5597bc2cc0f643055500b84a455a768da16ee34a57696cfed198c89b6c509e0e2635c585229404e76f7147c5b6cc73d03a083a78e2c7ee96fff9aba14e925e458618540e171d3c929a094f3c396483ff9632e1c5ad8bfbb611097a85ea23fdfc13214ef0ee3dd06b67d805306a588029dd59873a9a84882ad100b799bbff483b44a54cf4af18961fe9422b20d9a2bfb20955115995842279365c97d77b145dc2d39b4431b753ab06bd573bad8a76b55d65a779238ae2c748150473a9bf3ce516a3283b03092d42f17d0af4109d54cbb324fe109a8998e40bc4341bb7fb2724ed875bfc04aa78cdf12fad6e0d73bb8370f3cd5dea055906a1472cf2df66e9f801ca39d174db1de9da875f416b7b1951d55a7d0a4681efbd7843f769ca8a55a7535f6dcb1df52df8ad8e82773acf407d7228d28b92851c60e2df939a7e5143b1a3eb0e8048ae7cc8a415bc276c6996d73f790f9f08ff254c4b7403481d0902e40acb349ec5f48407b05d5768d9fbfa0e5cbb88be68dbdc59740bf05ceb10d6785981635a8a871956b99dd85d25bbd2e8f5e5b3c44a83e1edc5b9efbfcb9cf902dac53f413e8a43b0942f521e2d6ab2ba237705f6bbd5d8d797e3f788b6d03d87360c5abaa967e74ab22d93fd226f5ca5b9a19875511abc0d883fdb7f060e520ede22391ba4e86ee181bcc5a1347a63ba29968ffcd16cd8c972382dcec61cc72083962a8ce45efad0611d940195a9b97e0b8a162d6e601507107a40efd12b09f455ff7953a34a57137a9cb7e7d95b8dac2068197c3786d8a8a11ba05213fe306bc99c070670be8a0926ef2a4dcebe3d09ac76ac206317c7c4acf6547dd51313e7f979092027c7951daaf7b24298a116736cfc1a2bcf90a91682571c325595548ae8fda47a62d8eea2670e7dd1a5d91c7abb4b299436ef807641cf19572ecc6fa4662979e1bd145efec0c26e39678c4d6984f45e143130c0071ae448a36758acbcf521560913c2600012135c879bb8dfd75afe6f568c571899c22744fdff38d2fcf8d72b90a691be4dcd0dc71d32953a37d0ae133ec1607304c42cc103e2092858d5301cdc7bdcc2c3d4090109071fa09e20142cd062af13d09f1da11e77a0711b97d0df886c21df7d4f0f23f5faf5021eeaf942bbb853d487048766646b481242ebc5e74d5ed648985208dc9c6a61943e7962a625c2d705fabbf840893302d6346f729c087c7f9d34ff97cb9ae3db3b49a215be9951a728558fcc2564dba3cece45a34799c181b5e2c6f7b03f98984262853fcc2269c93857a68ddd8a01c8a065737585202aa172cbaedd78228cd8f54d2fbcd24774d906e64fd8530170dbff84127f5ffec779c7e2a6a57dac009c357b00c9d63a8cc0c30ea20b6dd2b8916eae0f07db64199a8eecf0cdaa0113a8412866cb1336877f0c3d8a8800487888e03e0b0190ab936dae58cbbf610e0ab9e835963fc570b902d867781327c76d5d876268ff6642042c59415be738c04c48f1d46aeafcb171b9a898ea95bb7d2a142e4816ecfb96e5e67eae12f7965312111560fecd486b761bcb42054664986ac5a6781ce7f85070a611eea49fcda12684238fc73f90dc2d9c46ab11fddd48fd7e86d3d8f119ac2936bf1ceeb6b1424bbba8f0ebb8d1dcd02442fb92aaafd9eb9c028526a29d5fd1d34b5ed9c150cf915b81de6034343ff5e5ec45f1cb8cb82e2a0085772a728112c88b88f98caca38228e0479d8d2c4431a44dd7a4b43f513b037ed8a1167124230bb62434bf47786cad4b5ca2809ffd7af6a6c700b042d3c1d74e0590193f4197f65fb37885d86ff8a710cbc451f3cefb04bb7e13a538db8cf9cea37423d8ac44e016d8cf84c44b9f63f01b170b0a8abd869d824a399c46240043293b24c567b36b5a1df40a3119d4d17b5b2f21c70fbae7aa256159a113e1813f0cd272c8fa1edc833da0ab3910523c2577b1dfaff6cc93c5ac8f5ac33ef680c14786c6fd600f2dc180b9e96f63c896e35e43e13a60b05224f8cf11fed8d85b859e75d0341235f73e60b8d385efe0db1ca614babf3fdd073b7ac3eb03e5e8cf34db305188031b1899e9f30148f444074691256d7fdfcde7e7251e08697175d25b1a2cfc6a69e63eaa08a3bd3e925513b10c766c502eb616e5e2a34545682e7f4b12caf7d6a41c81197553d3185bf0fdaf187ca54fe7cc1af5c6463a41ca786c4d60e76a2cf71294fb0ecdb9da3e2765f679e3157bc48c7b684116d5e76a13a0474db2bae834e93e1408944a3377a0ee3e48e066e1a4b6d164a1f0dad493a8bcda73c8832d256375f7c8bbc3beecc3523ab3ff53c4b59bd5d7aa76a2d617df64d87743d5601cf306f1edcf67a742b2462e652fdecd1fadd5ff5a188847c090cedbe91b07f11be7a0c5ead55724fde695667b2748da1dd4b4ccc16f3ac9d1d12e238451e02a6e568299bbc482a695d7907131f1ff76e69876570e9fbc590547d0a578af61018046788c64f6a36c1c683f55c665e5c597f3f3c04149894547d691cd93a6fd3ead19c602d385a55ae653847f812c071ca623b58cb4aeef98861a58432e499e991c33d61004b102443283018bb8ff7420a1e0a0bfd955e79fdaf57c438b6687a7c382a93a16f78147fb2087a20066d0cc3645e4a6c0a7b6fc3428af50826441e7bccbb84c92567935caca940479dbd78b569d9dae0d693d0c83ae597223bfe23024292c36d1e3bd9d755fb4d7d59db78e75d9ab5c06af0de5582791b223606790bbaa6169cf38fa2caa82a1e46d549938987a9ec3de7df22b693c620f3b885c37d2a604e78dc26796016ef5b81a3274cddff09cdf898d84f9e1e990026ffce732c37cb35fcbf8f8272c3613b9a2b7312caa9b7556e16bd7e8ca811c85d8d59d3e358c1b6f44fa9449687a01a8da8878ccd2b73697f225667ecbbfcd166958d2185041ce9b03b0908070f44e9827440c7aa87653f354fbdd4589ff4ddcb27cffe4a0755aa4b1fd51602dfb3c842dc1c0ab78b748c7afd08d1d5418d874921bd0da8b447839aee22371fa4c2ca4a182ad249704d86db449ed91422fda4311018c7da08645f46d7ed8eb207349a1cedf2e4bed7449c5cf5615c16b887f186aa44e69e0b52cace5e8948b190b19ddab7a7fa22a7778589d3e7e1964ad2fbc142063e0adde6750c238a40d39bd93e3c8087822c869c4cd8e12c6d075ed958fc7e06a0172d99bc4328fcc952c60069e14c70427a91c43d8bd5c650cc874836224f6157563aa8af9ab1e1536d1e6967a2d8409959ff1e03b6ec44f46ae70b6d48d1ce93c1b3d38e1466300a3ec8980e9551ecfc90299124b957dd5062cdf648786c70d8c6596e8b57d287eaa87aaa1116e406df1708a2a03396be27ef79338e1498a8e82c747b099b2a791827cf97bb4b70ee24d612db8f6862a8bdc9553d831114be17ba9a1223d6f919e952174802a755753337a7a7ad63e7a2d9e3a5d723a2d530bb703838b20567f34101fd1c40ba07e60ed212f1bb6b0c89f963bb1133d59dfac88f2eab5c7fc146f51d321f830de09760ed9d8afa6c4e50bc02bc560f6d2f026065cc14107471d3b40b4ca80b76a9697266e6a58b239236ee06ecc25cb4bc5e353bee892da74527310810cc6eb7ac3f1f40c3ed7cba8ddf8e270ed0c53966b98797d06c6e75d7b55014c315617ae4560af12e639aebf60232b7f852ec9d479010b3f328affea318075f5731d1f68f4066060977428b1cc935a8a9681b4b144c394f8719e80db9d01f23a18952387d513181ad082e87264ed2f6ed18a4dc1533d0a35997712718bedb972b873eee40a2a2df8de6739aa9e322bdbc4fb71601e03a5a5c05da08f179dd5c2a1eb3076383d052ba2790b19d992f1001eaa70f61f17adf456b6bccdf0aae90dabb80cb0bf303e5fc1ee1fd129f74198490dd877e7eebf9a2df0e6032432bd0699f0229803debc0da4e58ada9f4979551a51f5a9cac181db016d4dcf17090910000abfb5d7c89f35f803f2af27259ea6f8c3e8c2849e2332697a89d5020f46ef07cd770bf1540fea48ab0fd336905e9c347d3379fe41f248a388bc004a050d072f381513f64f7843802f865ff3fd9805a10e93685d59403122f68d2bd8871d5157867e9b7635842690f6532d70b4cbb22b930548640b9cdccbd0ff1e6928f70d2305472d6a13cd4513f6b46745ff86f54318eef2eb8a023ae06211e0f6923df53f7c36574664c1987ed1df5c5adc085e3e110ce91cb791d1fcfd9903b38d3d6615d3e90e75ef81b27de481e9b454dbc9b4994da8b4ce704616499645e019c21d90d0a3daa60760832019816978fda118ba67f67ea0f930fda00e275eef1c1b17d7973726cecd9b75308f9631508f0ec34f606cb92a5d1ec3dc747e44b22fa88827059ae67f32d7beb422ed85948e4bcfa0b9ae1b7ed355a3792101e67619c9f2cba9c440d7f1c51adf1c21acbd7c46982c09467c4463fad0175f16ad4b1130b9ab20671d412274338313d0cba4caf1202674d2144a9501991d4585c8ac48d00cbc0828bfb15149c7311e1210949f74beb65e81a49403401d6a669621b52ce362a8911f04a60ec415980b78fcfebff641e093465091403aa4206bdfc7767b97cc0c8e6da82e97226ffd6fd40644aefec499a666268996d2ee7f27f50c066d97d2118d118b5f754c83632a791765e500002121ba23234c49e17310ad04be4592f31221ea5faf4ccb80af8c14befea77e4d3e1f1e056111a19ba29bbf688736fcfd4a1f04cecbb170dcf51c542ff6a3df4610e173c2d79d0708f976a75f7e1e6d8476294a62af717c92afe490d6221f5d1cdff520681516f47161480fe89c043257c60ac8635a3c57db15fba1d3cd8d71b5af4b121fa3c30e27fd2562d953e22343c816317e90fcb18784bebf259a8a3705fb249c4a74f0e178190bbe24cd352775911b53f09467fbdb3de80c9424a1f73b15e82895886920ee8147b3d1498a4a123d3191e680cc0aaf7a3295bbc64eda3f32fc3aa08764c2492ec5d59ebf4a002b2f2f1d42a6308a00fda7fef23b5c892317b24b00abd135a58ce5701c5d868642238cf32969f264e28803ac71f5483212c94b66bb0b58a719a181025d17f1cc381b9cd7c3c877d236ab68be2e5ca94cb8a3847b7da3a55af18b0dd460742730c790bc19130f33f6ea11019865b1ec1937ebb98378a26a4085c04b00b21d1a62b6b8e116242c5c303bd0e5971eece4e54230ba9ca99cee962b2e89319da81566eaf50dde148327073f93e9a275a665e938342bfa3843675048d0ef8183ab4bc015775e11722490a02c399a29ba427133a25b618f164b496807784f5d8a5f6ac49349d467320e740c9eb6ea08604874f07b906293e8a71a855298917b7060a845e40401ab40ed74082a31a97080605ae7626e256d4e8ea3bf68987c2f0a7b5c653e6431261a0b3266307673cc330c8fc84441abca6d1a95707d621a2aaaee762b0e01cfc89bbad795fc71b5bfef138ed619cffef71b9d05e2c8d394954c5c21a07be021318035bd3f2dd890eedcdff3d024740c9441a4c228651ee48144a1610886d52f07d52f80046620d17dbf58830fa30d1e086cbdde0e8798379629693a9b107643fd51430f5c20e85f5f16084b0a5f5971dcdabe0696c0fe41e1de64eab245d2a2ccb4811b2b2a5de54b57357a9a80a6bca9a79e1193dd1a9a6098ecf8162ea7b2c26a21484f08d32daa41b3b1a1d9826e575bafb7eb5d74b28dd46ab98f57d2d3712fb55a5bd55b955b518b0fc68ac7b9878e61a3c69c629916a6e6aa084e4fc17d47f48e3f843c7e8010eb6c8a88d184400f1bc4198322c1aaf55863fddb0021d3b3c0cf4fee7b2c685617f49e64884b3014e836c0e02a6c59516affa8446bb119c87ffff6b2aaa2fe3cde9a54204eacc1e38d49f3dfd656dda91b5cafe586f5655de7e4658625b600c1dac54176c7b10e81a2dd75f2a25c9743ec394c8347e10a225c2e0e5c0c26a6015e6aef8bb078fa888329d40b450766d639c041d3fddc1048f99e847b0031f09ff9acd3d97455760c55cee5709ad1a40339f879af2509cd68290c6809d3d0182c4cbbd8f611a40eb62ec1c72557edefdcecdda00e3134b5b8e41fec0a003dd2c3506b4bb2dbcf588398ee49040bab7460f1bf2af4cd0d061dc7126e54988505e64f596be25fc828a0c9f1b62cb4f1c5973f0cf9ed439a4dbe68414db052caeefe64008b2ea722b080ff3d0fad241241999f9468ac3bacc28c2776644250268b7c3a4b3906b4b3350a8d141023797459f6c02ede1b74b98db06bf44e30822aca84daebd80d82c32291cce91ac304a80b4869dfebb7151493169da0c419e2d0edab5813aa2febddd1dcdde643e97ebc2ae881074762fceb1dd4ccf9a57a03ac831397509fb913f02663d6ed03c2e03a41aa387fbbc62ef16d214744bf9d96df55f78392a4d25ccc34c0aaa7ca7c4cf3dd47f508391df3e839db57f7b93838c3dddeb73e8e75cdb8898178c868e325028a86eeb271394e8ca2e9b12fb2f172405d6322ab678a404b091aa52cd18978cd32230fa2e4e6f04ebc34faf5bab8f35e4d11d6ebb2640094da629fae19de32868d75ed825f8864108873194c39ebdf25417c4020d0f721ecc4ef525f3d36e4dd63d62a0b878a91a1662315b440f3b1c0d04140012744991c2f3585dd68bf73bfdc804e394ce17c9801074e8b270c616d0160dfb2e0e6435d3020f45de64f1fd55e1b93dd17ba2e6e4a2592351b44598d732114a764c45c895546af728cc919bc4013ec5dc48094aebc1b477d396c4356aa4cd233dc3dcd322e69295e6e246af8bdbf50b410d86136e0e38c5d2ca1b887f07a99d610e5f6b8c4ce27793c1358ab34ddcf63f2b64b65c6ed06207810576fb591543600107e80e49ca619c14936c4c029fa50a4cc2034bc398da83ab6968452f451c833f45b3558207004dc060e77e437e06a17f2c93d4405316ec26c3066b6c828abeeb80ca85c52c88b8ceeb1012513dd2e298c5625a4edabbd1e8b2b495337085df65eb7f05d12e1d03e1234721541f85546141d233326dafdb85a93ab615864e96c46042f700e6b4e43bc65d454b7798df39359e2681b8b6fcdb223d2723449626f106fb9187e043e9aaea82be91247708ef1111f31a46db2788234ffe29800553e2d3a7e73ec9fdf41e6e95ed35c97a4e28513baadb0ddd952cddfa0b91002c46a7a82d802dc73f66522ad3639f886d7aa52f32bac2f1564b819049fd87d7960cba44dcbaa5453c9144df9d684a708056a596309922cae60b8c123b88fd951b0859816791cc1f7232d01ae4fd5d3ab3bc7e15dab9224dc799c934e89e06d231f5bc475a685d4053a9f3991434416fc83b103490cf4e1d882e64fccb6d4aa3d4d19cee4f91a11002ef25288c2c0085cf053b4e7a81fbd1df14ae177f66382c271f78c0f605635d6b53569ffe09b339fa90e3ba63c08a25eafa97f5c554f65373ad254c359e79ae98404b5570793d20f9a92a323aed1aab908769de5c0dfeb13a808b4a58b832f4c6e2e9d0c890e8aad48e063c1b82e04c83e67e34f67bbe963404148bdd8cf6cc0797ae998c84068f3bb3dfbc592af6268bb39cda9b9bc55513933ef62ea18d2b69b4bb5f9ae515f718a77fed7363393fa1097a126847bbc556df26932a3797968dfd63bc928f7c73575c72fcfcf38e70a93e80f9823096bf7b920c2e2cf69be33486e7c90f78c01a75a0770ff0ea613452340755cd0c83696f19beefa7988f5a0772eca56b3db6b450d829854867462465d88a5b278bdc5b75a2dab07cf2a47b4bfff10bce98576ba64bc72cdc12fbd7cf0e675ff41d002582fdcc5ff80d4bc476130ac8fab9729e746a2c9a23782bb57ee515d01f4036042df31593935ede2305d54eb2bfa4cb64aa752a952f60aca5fc8d4fac98175cd697206c7e0961674fcb1031c28b2c9ae9b2ba8a8e861a009cac598eca6a72c26541f219f2a074cc6b88040008d5234f704bb44fa1a28f8b1a4e0aba961da23eb93ec452e8b1ce6d450c01de456eacbedf8845c0ef1ec507aa684d572a6c6d510fa3569066482f40cbccb6d0046227e45264a74139d3a31106d13764b6562f82fe0673351facb4ffffbdfcfc85a30b99b3f2ceb38a6858a7d5006283ce8d2f9526f7eb942a8c886736df899e7c8c6388c0600b4479ff9751013380d0c640ef9445c2e8a9c8d86e75f4ab0a045b12cdaf1fd0d81171dc4396f2b88149f1d6a714e58857f04b954be2d48cd198cf244150c8431abfa02a551d16db246199ac36327142dfb42e57dd990aead33bf41764b8161274801148d3fd506baed5aa18a3c39ca078d08f8b1823c1e0ebf83af0c5a5697407857d580e32573f717dc8a0325c46a8782e7f10af319c230c422a5c6d4f23bcc18e016b09fe90e1a0ee05072fa07e799abc40b7ee9ebc2ce6d5d835b05c7e17db5c1c813d05ef2d3b9aca1d3388293edc512f0624b95a8ca8a15012abf54b67348462b4efa5ddfb56491804236ead4d9d2ec0c1dfbe85ba3a47ed59b12c675e19308b515132b2601bd62b2a10fdba37550f9451e2bf5c01bcf6e45fb66439bd2239f2773c38739eb5c119d26c9a38d6c7475726dc8f6db7acb1bb48d5cd055a7bbf87b22d3bbaab0937d306a408b289155f748d63683d464341118270e86b631c2cc6448e34abf3904d6b27104f80e8762c398e39db084559ae88c3309a52a999bc40be1c09b8ed0c9bc027fd753935ed3cfe4875ec0a2354aee2fab065e1dc10b9f428621cec5c23e4b9058701c4efcb1d81fa68f5a6cf5b87415cd1fea63d5e8b74bcbbc94593373e9aa8552754554da69cce451d28770459d622b7eaa0e057f5a5b2174ce039c40fde8eedee81339981f5116e4b27de56d4d42d1235897cce28375aa95508b14cccaad574859e1084d0b9d581a637c14aa8b132a66c03d1eadac01a2fae834b083c7f606d911c5fd496059bcab9ff82c12da259eaa2d115f395c2a91f91ed154e22e4aa1a8e05e4527c4a19943cfd1c42accd41525586a01fff8e66fa06c876b2e80be2c22f1aa9c2a57860e18f78704999a83257e5686b197feb97f9ebe47494586c34ff91b587b68ce05700b9b72b94f28f1522f0f08cd2a1be22a83fc826daaa20552baf3c9a9abfa88d7313d5c99767482814d9146cc431edaf7849c12ac1a6f7828737acded992383d8622847980e30d116b00e70eec3043c839259601e7378fab8cd9ccda075ba245fb6a1f0b62cbfa3a69b8c1ae753c677f517c8e52aa5e8f861e54264a2c43e524a8e36d2fbbb8b949adcc2ced9dcfd09e3d82f3fd703acc4077cb8292f5ab61cd830c6d43be9855461ab7e2da48f233d53df31c37a058045c76ea4c7a2046f572f54873bcd2db17e78bd488e4af2002949bd5f3969f7de5f7053dc844a28702de30b8b104411c2f8d6bd527ab3321efe83947ef3318732bcfcc6a74e43800240fb0f028e53de04540b80b7ec1bf15605707140b0c57eafc8efaff8182bffefa5627551462394cd8ff91c3f3e1e87fcedd3cb504cc49a93cded15f9e2eb0f0c27732a2cf846c6cc77da5b3383d3c2a50d9d87b4ed94472ea7b55ba2f2ec0fac5b98fba936aab4bea63e791b40bb270775d8497c078d046d3069d28dbda02aa3e6ae0663e83bd102dceb4464e80d0b8d4bd19f33568075f3d508c1bf060ef9bb8a4caa0d15aa6ea98a120a1b6a6ebf599ab1b74d526edf7c9e00851465f26843bac5df8a0a3f604aa6cca8b088ff5859141a66dc6c506be24347086309fb9f161cc2b035475a3424c0ef3eb0f70bce43c280698aeb960f58fc608e662f4cc046af85219b88f460786c5b78f97aa0fc8f3e34537ebf86a2c0b4f5618d042b5c99c428068c3e79a9c7997d35fbd35c0f93439e48f022875a432755d5cec569a6904097a1a99fc1348413bba428fd672553a40c595da1e721838e0a547b6ab1a1f1a08e8d4265f2f9273258f60379ac15bd15077b8656239310758b422ac3667d1b14f4c91c88f6075e742a98b5ce08d1ce57e2643333ce97e42a76083f8f2cbdc484a152ddf43f9b26368cea0cc58987dbc690527a80ea8cce61cd8db7774a6563a3cc92983ad3564bb0e83be9b52bdbd32aef41193da50cf1e1a4d755997a5ede7288e4d48f43876080bedd047309cf83d2f651054a42719f599343978dd444bc6d0f3ec99f30ea4c0cd2de5e2f642784efe7aa4d595e3d6e3c528d2c3cb1f184132500605e51c9e2642a5db48e116f650905e49ed81373d1e2ed86726604938149e5f33a7293a013e9bd0d43d29f594ca0536166e33987dc61db4e0917329cc93c2833391f398e6a4c0383fe4a1fa1f709d9176bdb92536ab646d751e59dd02db2d7a9e0108409e7170277d5f858dac385bd40bce6e0886a7b4b33bf4924bc1f2423e3cc5698ef272edaa02bca8cb9000e4120fe35b43e7e9c801c0cc5da4a93013dcfb665d05f5a954266e20a9705b8799582f8f8cbf0291e681740caadb6cbcdae5eddd814e49c080bce664cab1d8ba040713f0d3849e898d7e36ac411919fb56018b80d403dfe62d603ad6745769b60d0b6046e9d1b4a9c896ece6ce644c2f6b922273abf60e825b639a8034238450f93f822f4d96630af25b68db1b8be58a8316f2313c5f09c6ac8ececbfff4081a9a938da4e1efe57ab3cfe69115911afa49897f0eff48f450c962168644b1ce7796058c260570ba229b8df9f7e85286cf1d38d5ce78b4a9f82d4b448a0124b1dec0f47e0473a5d8d07d9c13f42734ffcd29c450538c8f6c640d56919fc7f230fdbc387130c9fc8eaf02ed16cb74cf7a4eb3816371ab3192f6d82ce8472e42653d22a5fae0ab296d935e647c5a1c5d9909ec6528cf83cf7a4d00b0f74b0e4355900ed127e64baf6836cb8c18985a0bb48b28e2cddd0c83c05ecf088f45fdc814fd915e9207075dd8303281660411f70733f50a661d57d2dfd5a2a296313ba43c7571ee5c46e464826ccbe1a6d8726b67d0a4e56fc2ee76bf0b85c36dff559c1ecf33d4a32b97f81ac0fb3a1ef5fc8db98723f4cc5d2aff315ce2e0a4010112fb97e9b527f41bd67b2a66d43dd3586207f1d654948151cd44ca321e756c5cba9d44b9e8f724344c4e94814d82314394c28733b4877013d1e6cc237e4d74101c84f49ba9a7d00dcdb668b3c3b507e900887d9115aa991fc797609217b6a3de8f7bcb078659a668ec21166c538fe894eb143b3df42cafec0b8a583182ba2c8ae314afcdff3b215ccc60a21dc18b730d59d0d47ec0245c60a65e5440acc76c0dafc93ae373f8b6f56274e079d995ea79ab561fb4c15a5c307b19a617510b3c20c215e3da04ae61b9036685c3b105026d02ab1278da66627f11990970f347d22e47170894f02c2769f5aa0d5f6db46cf3ee996c68ede1dea816bf49158eb9a3a68ea6f613d4c4edd46a9b295637a4c6b2c8c3fe690d61090ad3aa6ea10321e6b559d6a453f716bf19860ca76fe01e8d8e794643beaf0bf322a0771494a2645a95016531daaf5c7a21b4db01c558749e3e159d952b02652d5f81a59fccaf8ae3f280e727c965e1d3fe67ee427e1fe64f1aab09032d7a09f5aaee06c2d4a34a897c1134d9a220e8e0c9b7fb935ca4401aeb6942732c99b8401ff2aca2398249c590f0cfa0d5639e22ecf1aacee33491a5a4e2d78882659dc06d3f0186b09ff8f4bbec1b6e161d164c9a8e3cafa1ed2278a2c8b283a85988884acd6484b618395181c9ba38abe4f7c57aef001fff311fb36504a8b11e9ae46272f810111dcbb5a62478691b84eb9ecdbb514a69646b4ed801f3e8b78e913b89de9cd902244d9cddf12244db728227795977a1814d065e8752d885edf1b4d65d427ac0550bba5417281eb56c05753720dc997c56a08c44a1332f4b46569e13c0568187d8cd7ac97a158c5720167da760119e015bdf1db7d893e0e4a5e40bf0254db2ec91155413d9cfd912a0242e6d27bb974a01444d99436296944c4dee492cbc1a086f250db52ccd47cf478b501332138f086fd367ba991573affd6bc0382975ff0bd10eeba529c6d9dfc12d987ebc49b7954053fecd8d1725f77d75704fcb258c836faf56b7d1a04702903b5a0a7c4c217feaa9b2dcdda821d7eada0da9766cb4996ebeff3fcb283897ae568417b4bda3e3c4dc729a39ec3e4274184316e842adf06e6a528231d82d3c2ddbf9fefbd06f749602089161601e4093f67c4cfd1e8aca4167104346836752cce382ba0868226f0d9428dfce013ed1da11469c158678cd9c8fbed77cde8287702e8bcb3a5f0b12caeb141701747caf5a6d9e694dbb6c24295241a1aed81a7d7e49e22fc0e4a22756e4548e1a222f3da9d318a387db1ab0d8e54a62bc9d2d48a50e98d7db21c18322e3032dfa2d5df302015bcb687910ac3a23708fb32b3128b03f653dae55d9b7370de05305bf6d5e54ee9488f2e426ce857a5fa9b33c3863b5810a1dd8664aac0b703439ca0d038c18b2c63fa24ce3575b5c4f42430088b140e7fbbf1420712f8bf92043c01bc522774d50a33da91a2f22e476bc05dc5d8a308a9829357e1b15477e171c960dec328cd521dcc3c8330ccdf52910b11223069e672ef024fe761a618befd11814951b2015da51ed54193c22d1d6836a6d706f4a42af4ab275ddb9f6ded2339722c9f3fd029b5304c30b07b0fbc0dd092a386b502f802aafd202f554242caa1059f85c7e41fc1d1b866b4349facaba4255b0f849b225b10a513d496c6ce70ba6cbdf166992fb329cf1f5ceed998770d56174de6f724881cdac946eb34d1c506f8ba86cc69b97d90c8b2a0e4400b54debe16e69c6654d2b9f1d36b34f80272169cbcfeed61c5a22f146da42a9b3b9411cd790b2a8b569c7554557e55e555d10b0d0474d75ce281cd59fa3701545170407dc76070bc03e81f6367175d54da3f9dc3d10534fd8869fea87afb0c7f4c527066fb025c2ebed3f5d8bbae1082a2cb5acb1b7bc659ec2ce0f95ff10d8ba2cb1a3ffe56fcd2e4eac18b5216cad870c9b81f4c29acdf211990dff82d7ad422d52e7f8d8b097358a596dd3f19dad9315fb5c51f1f9ed9a0095a396d7ee36c07d1320aaaa3df05d120362dd8490ce469a55b89b0b1bed5fe317edfa1c0e19106046396ab0934af72be7be909835f651a153c2bf208269ee4270067ee0c6dc0e66a52c7340c6d86da2e5dda9dd30d8f7a34e931b7625a30efb196ea2b8b1a1fac2d3250791c79f3ac92a92684107218119ef83d5374e4d78538b497f7ccc8425ea5cd1b7512f0ee1ba2bd1c5981b9f7741164743808341b91cafa456038417a15c049f2169a44e87cc50fb549a62cdaf0cbe85a4bba4af70adb5d479dca07fc654ad1105120b877c4d66f979e6149a7ceb655888f4b51d4d4f5e6b3a82e00bd423b23d334856ed1997562cca85921dfcc512cd01bffa23b5b88053c7d279720057a0933029fdbc049f8ceef897411a919a624198bea23c89b3211c6c84fd77712c9de5b38cf2cd73423ed15de063ead87a817cb85bbbd8e58ac46a202ce112babb60f648eab22a3e9a71e702d8a5e01192136bc1ef4a619d4d0310ac9c14e8d0e80ff9dcaf887dce2795a48416f4e64ae0188a67cb9d1abc3f1e85157bf3aeb6dbd3f6ae40257f95ec3005d530def59031e6360f6468c30a4cd34514240e08a8cc08961bdbaab75590a5692043c17b8cc3d6780d955c4f1792b781a93f45612b932e221210f17429b00b4b35008145482f218abab9870c30e191d0871727ae944c6ed1571978477328fd986509f1276fa6adad31fc978fc5e96db5b7404db0e7086d5b373be097a1390c8a92e617be7848e0856f5a5e53d4376f12c3967fddfe04ff868cd428131ef2444b573d0e7e7899b2a5a869a2ed19da1b2b70453b883e74394feb55f53ccb510e5e0965e2828492022a8a7f88c6f31c5bc6d72f41dca8744a54c562b22401a5dc368d5ae15980f0da0554a0ec133d8bcc023abb40646344e6d17f486dde77ebb0fe3e49ce0acb6afb6e11cf70d874de6c7c2b484e57efde757ac154c4d53ac149bc8b77f414808b2a8b71a3091a81c3710e2a9d36de5747066a9b54cca337b10ea947944079de1791066e959b3192d15ea7959bc1bb39663dd9cef5dbd1f36f20d6fe7b0949c37b7ae135ef57e70de21042b54266ebe7a743089a783920aa537d88f09208d8b392a4fe77d24793fd3484bf6de780b65b2b3fcdcecaffc48000d252076a2d44fde6c283ac595e0f99f8f389780271ec6852f3f63608b47183942aa757f07421b718522199772b50f07580b7e4e98b848e6d5f6d1d784e7b8b8994d0f2b66bd1ea465724f6ab50fc4157215ed830be3e792b0c908a61ae01875698cef994dcf63b8447532893ef274cc25b7a8230840d1d442bc30f3eccce9485472ab1b3ae7a20a7d40089e7d7287048de485c6ade633549feb12cfec21f13e9b93877f32302dc77ebf0bd6f20325c6590236c9c0eaf156777b282724361d3099eb116948601a6f41f5abf30834ed32338f169e4002b3d026231a48a70bef6d6b72cf3df05dfba0b03e4a357ca678b885f3f542c8fc195b52b4ae1e34df456fc42d28021c8ee01c3cc9ec2b6612d17044c5ad99431c9dd7c65155c85b8e0e8760b300f60e4e41e141743820c73b011acbfeb514662c53121e0e8d5e752eb1e8c639dae88638e4ef0334e50374d508e8b31a74acd35801724e8be6f70cd5f0b3c67854283912626aa3d8f2d861a2813752bb55059354e09025da3184235f983808bc11dd8371668c39d49360a4e81ce740d03cf7a4926726b908468029eb280c08f6ab1f32fde9b9beab2ad2fd2217c8c0946e928e49d8e6f901478ab904994568bd4bcca65a92ea0ac847efaf359dcce8517cca9e42c62506ccd0e8732256e1b0250603d41223da7346b75962b6129b46665962307d9563b9813049b0c4d099ee2b31e19544cd33a34392f9a1db0ccd83c7c7ed9598f484247a2d591f0851bd728d13607891ad099345082e1592e7de18e938315063c05cb5cfda080aa52b2ef8e12134c8015dd4287f456aec4b3a842b858e4e7fe6ac348cb0c17360cc32910022ce688921394672bfa1017c757c0cbb871bd85206f64d3c4530c1c6eee1435f61b0356813951920a5626a4a1ba512eb232940c80ba154db09a4782075e87c5cd399bdf80f8a09358b22c0dc5a65f3af50db313913b5bfc6b70d93104f4ea4707ec5c6413e96a849bb9ce589060b725689d5b4ebba4b5306c0d795eb505495ff90675b2dbbf023381e3271c5631ce9be67ef2d838684d3178625ed2d5be716e72fc965c690602f36295f64baaa5507984d45e3250971d9c0f97211b6e67e44a431bf3e7c09566de3f59fd7289ca0dbe7dcaccc49b6e68d8ea5fe81d2b9f793848c2b35196ee684d15d026e802013ca54a2798ada5b29e4d5fba9398ebcd5ab3db9baad6ac6b702375e8d3dffbf6ed5ec7794ec8b28b88b5a5edf578858ec65deb1b6c4c2ee4bde05c8325f9d3ff17a72db12083265590da06ab3f875b0735971ebe7a0048d4767e330647796454572423045047011cfc903a82dde9bbd4338319785fd38c34e19014a2bd6a920f6480c39aa17de8790334c562cfb61494a90dc14a50a95f01a2a82185e63d9190f0caa75a3daeb79f8025848e472da38c13036ce84eb48a79d0b0d1267a7c5ad0733d0bb050603142edeb4a06044d17427b781b27039abe21b17024b3f273903c4a7401957c90709df19a4451e404221ab48f05ac0914e0556086e15447f7e90309edd83a96a7f9ec3bdd37c87e8970f10043441363f3f769bdc48e299662b229b781c53f7d00a7d39bd8eb771662932fddc90d40a2becfec6c0206fff2a6a8ba62f933111591fefb4367cbab6bcc840d8bdd7e052925a878bc1d1369f88629f75c4729e2c7036f652dea484396fd48124f4187d144429aa57e9106d214e7dc212db4365ac8f4e0b3d24134113d1250b3afd606ad1bf7a141affefcd99530f6640e9dde85108b04474ebd1ab8bd673b51ce328dd4e3cdb314f0c8f962e3106b68589df552e11e7903f87527778c3fef9f4fcef42f7822c7ba86ec3e69ab27316a8f96ee6b9ccca6ac3ab346815144563d07b9be14af51fc21cce51dca2aec0910a5d29a8703331df63198139f9004459a0d90638ef7534c9028ed620e2faca92fcecd3aa57cbaadecbc7a0a9159fefd2ee89f793007820d3418991d907e61baa1fc668ee4f8ddff5c77cf488059b9a9b0f5a277b28842588e75270c1e77fe0d9263e940809a7bf95224078a6804448f2c4ea20521cc7b2171de2603585228bbc91a398df4dd927f690972a8ad928167649d34b116bdb020574c04370ed6da5e7f928bfdf263cf1591a4fb63ec147d880d0555e40c022092959e0e7e9f86014334f7afc874940e1f9d15d61db7c8d45ad7698db4b495d238494df84f7074352761afc8f4dc48da95174cd84f9fc02c0f3da4d53e685159ebab0c2a6e2a7af29fb8cd5b555f091e9d20ac014d8e7a32e34b3a030ff6937ca54596ffa865199e49c4e5257b6a5a843ae49bb2c8a58789c4639fd6e769b086f174d0b1f96a187a41b0f5656b8b80237aa8066169d12eb690944835ef2f9160212ec62378a09d43153c9ef9fef570953dabec02a51439575079e680d23b5a8bfe370020ff32a5909aa828f3b5bdb6fcc8af6d75b9f8ae112eefe561f51602a97225b3580264d105ec6fba8dc052d6f9e2000be6ee3c077f6020aee3d52ab39069c4015d8d9355386e7566dbf237d00b0f9326de98cae0fe1c44c4bcf047ccde6a4baf9a7f8b8d533bab5f2dcbea68193da8289a5d068c162002e93047de2d35e4f07cc52b6a65cbf66f8b536b1aba664e41fa7f67e7823b70894dd5937649a7c0a199526f9928bdf722e8aa444c01c8e31e8882a80d5d7ecedffde4637795161d06d9be4960d40ee103a3ca9aba9ae5e4d9beaa8c18b415d7e790c966213f8dd29d4b54ee55cd580d06b99427ead75fed4d1b1ce42a4ba29a9f41039f542d130eb2a331c41ca853941393e9bd1f7596d963e66506c4e06371334b65b79cfb677d61b6bfce635894c06f9ae1d6b5e9144d0c10622a57a934cbca5f6df39240ddba8073ce6fdc8454b74e43fb229e9f7b5450aa98ba4b85c0b14415cdd4433a0ac0ce309c52d7ad733d845952cc7246bdb406ac822d95096e90d814baa71821cb4e39ec432163f6f305c4fb76c6561cb2923dde27c17e5339145b47fb9bfe450c052d893b99e4f7302364433932e4a5e26b0184387bdb403c6e26e646dcf3ea58269f083ee1911b759e9af8d141c0a6cd24a1473194c228bf562426ae37667ea055cd4fd8b7f6c91b77040e239189a79607acbfa7f1038e3187ac3f9f4eec9bf1ce4f04b67a4aeafff2ed629e6ee031d7679774afa270bbb784175cb0a7644fffacbf40438177bb03ee10ee53346403c1a284430bfdd0de66af05430fe8413a26d6bd791c7bf4ebd1acf637098711efa7eae8a6e73aff547a421587cbf508c9b5271e8a5057d136dff739a1fc05f45ef44d553e2b95ff1eccce39b7c5a8447ae1b78a4a6bdb4a09505a7d8f25280ce2a7cde2f6268062a07c8c3985a0136001bbdb602d5713543e8389debcac84df0f156f61dcf2c3e3e462e49b39d3f16c009f8cecfeab0ee65b2a5ef168a9f21ae25e4061a1c2df63a409ab85a4506a2eee736139612ff79044f62bab0a4750e56dde97248eaf9d745346f5a4d6173849ccc8d5f02c2bd55886162c8a795332c2673c7c857f5d689fd37cba093c0ee588926a1f7f5a071ea3452340d41597682663f39de020bcc3b60b0f2c2a3890a4c893d41f26c7097e679a1bc798c3d4bae849079048866861b2305b8f7e9a4a111607c9ba33fa594b7922cbb620de516aa172e6b0d41c033f890110644963578e61e6eaca32cd2e57caf1825fb93bc6f09705f06dbb88160168ac5fa76296042e17b5cccd9c3720032882ff476ff7000ed4dad02d3186dc25bf0b41b02fc53f5a292fe25a4fac97afe7965a377a9fd09779d3e5eed756bc10b6b61bcdd2d354b43ae5cbdc75a2bdeb3a18b6736ffb671d5d1ba2fd8ed4430fca2edd450aad22c253f88805e2bfb44dc8d4a617f37f49bfeadc8b8a97b69f40ed43003ca5166785b30ce424a07026d0563d3624b9e585045b675d6f88af2f2650b0a863ac375b916ef185a765479f0392e82b1fc2c59c513b167383d6704629dbda1392dda331023d02c5379d0573c7b3edcb730b3f3cff125217befbde59652ca246584074d07580746320713d115f6efcb79c4d8398c0a696811fb8f161b4ac638dc9672bb94c7de85d409ebb17320a5443207fb66451e29d163b74618e76c8d1efb8ff65890635e038243192e13aa3d09276358e289e88a8b89ea10c456bfd76b074de4f9b5d62ded9980c3d13770f4e72e98bdf41c30fbbef454a8e1a763b7d66f10cb8473497966a6492e0b6369e462ff0eea3dadad991765cfdf2457f233f7d6124e32dbe06da5c2c9189688a5114ac3d4c5ac13cf3a33c59dd1692fbdd3da7c9a8a9b96b3fd1de89cc9134f3ba7a5d576fe80ca2b355666f369aa8ca394a336b7a320bdd5e6ebc9c9e916576e9bb3d3c0dc3d719cbc76823033a5a1c8aa524ad90e020eed6e5b314867edeead0739daa7e368bd4a5a6d7733ac6d574a99d17a86a33da59436b576d4a7b596a3b46a1d05b1ecada3603d2339ed4caeb5d64a67d6d7959d2caed5522f5c4a29a574aa524a596badb5562ff294b56a980911194ac9504a260d194ac9504aa64c1a329492212aa30d7112c76a3808f57e64d8478fa60c671680016b43397f3e85644efb0b9e0b2db6c7b4cdb6e0b3b47155051438ceebd19cf34e68c9c26915f734d055630d6431a95c6834b4032171b43f7d0b21731ac914125a80c7a389ebaac469d13d9f4353680aa986c8546b8d6a427c35e31acf4f8b9e4bc920e9124fcf52fca4ac1c4824f1a33c82f59c488c9933e69c530236c4d0303ddd508689d6a444492899dfc4738e538ad1112c871fe7d2e4b2f9386363a6ecf264c9044a82708202d49a94499432b36676b3835c2e170fd31b520288899a49b09fde4b930b2945e68cd9657ece897482a04963ce3969d83c0d973f3c0da741430a134fc367783d34da490d92124dbec6b3d75393b3a7bc9e9c8a42c6a71ce5f5a45028f7bc1e54f6a204f15ee79cd7d3d56c79ce2513cff9e6f5709b4fc9b3d56836afa95ef3aa6945535e4b0204afcde035c75e8ff601d2d0e31b24b47cf655e1ba520550bebcc5625c3aa0043de5e95cf434262a86a1dc7b7dd8c205cd099cd0e204d6bad488bf4d90f99bfa7befbd4fb0ecf82d96780bf298fd090e7ffde27ba99080bbf7de7b594eae08c20cab595e13a323db164e5d132c48b426ae89971c300b6584b6262c38920135925ec91f71ee02043008426a1206d0cbc94f08582043e4c48720169a849c9400a8014c8c9c2001c4c216474e9e48c2020c8c6aceb09ab55a926d5e221991428430b088b20598dcbd443232832422224cf9090a80999c7a89f433f4c50f124ffc40e12c2a9c8ca1095119436528a1b12e7d0447d4aade9609218b3c4e8b2717dbc4e4d3bf2ef26c59b98133d6a2f530296b3e8ba40b94c773eb228bf254b756ecaaff2856cefa9defbdd8859e0be93e50d5a2f5e0c81224436d2d097eccf116477ceb2d5abff19166aef8c287232e578b3a8fc67d5db65b89a399ba09123298ca70e5600229685c689ac660da62362c571966dba25a9dcee974ceef7a67860d25b78f5c0d25198bdc9e5d467ad0d57458ab614f81984d6dbd6066a90e101062b94b5d91658b1d7e39fefbc27de1beb8900497f558fa419f66901018114c245dcff51ed02dcd39bb55c9e35ca22658bf49a1ca505b94d8dbfba99f30cef99b42736922993ba6d2c4d14adf48be5b1cee7a08390dd1272257d1cb08cc8fd4c83775b5d84a734787d163cc2a6aa3986c435a5a4899e8ca4b6e400daf81ef837c4f81c8344fe5ac431910276338c2c818466328b9b8202aa2a34498248941248653bf60cc9827a630929e8ee88f112e308ac0782ae3e933901f080864a466a5d3cf34c9a7e9edb125a963a3c2f17a86a8b5d62aa7d3d945e8104dd3d4dedf5376eaa686758cba6a0f5121fab2e16d1acda514a3445a795b25a34396070934d44343f410ee21cad44df488aeda312c2f1db986a8100da2afef1b1a1a72ad00c263a74cfd31313149a61a86b0d323fa7d97c7d3a1efa3b6bab223629eb9d6229e007044ca5b8b268f19a988230178eb9bd763712de18857099400838594297489985a6bbd7992479694357ec479eb7289b75e7126810adefab7e4ad7bef48a4129c1173344009a4a126ae2d4b6468112788626b0e2290c04494f1d5b3a326967873f563f7b58aaf4844dc60f4d56db64ddd0f752888afd8fab0be1889b1394ba7c77810be7eb92ba3648a122c3708c5944c716448496c042a00b1a4a40b20158496104999ae8c5e896d1a2a6fede4412a8900f6d6dbf5226491062644b691921d0905c5c893525a6b6d254a7d299ca199acd43b0d6b476186f9f5254df333f46b91390d93396d43961842501ef1df681c74fb0cfde3acf9d622736a97e9332db616c9a342af7a8c18305eacf826244c4628500dbb89f369516cba847de0640c4a9c80f102230999ba1565fbd2b7a2dc33295545b65e613926501f75524f1b4ed89c3c351967f2d48425f41c75b6a24c7f86da0364be01648e0d9fa3ab38796daba595565aab05a9137db24ecf3c51273379a430aa449774cc64eb29bf6ec1ceb90c95023d3f9239d4fdb90b6af2a88aa437a1fa388fde8b9f312fd87c7a2798900a1b70bdf819e382f1c7a3fa68a4443cf50e1ca90d638b9982872dc4f450bb9ae480c482a7def1a74e943a5198cca14e614e79a44ed4a99337757aea488410947b86dbde0d7db2734939e8ca488b64e486f5518bd4c71c96671ed1d65affb99ea7516647cd534debd6b954388b64ce9469349350c2f3ba0c0c4d7120ab03459c1651a107bfb528c5a8c529472ddaec5b53ae97bb20933cc11b2d5acf204eaf2c0b9438accf10640e94b7d979b48e0cb717e4c92473cd79e1640c565e62573aa350f2f376ceafe79cf34eebd65a2c28161c754ed6306b9a38a4903a66986d51253b76c5624bb228e72862619c33a543928aa2fbf7e55cf47d2e242a8cf260b7b021dade03ba859faed3d3cde92967b41919519eed888a1f679435c13823a7ad4ace9ae60eae0989630ba9837b42e650a7463267883c72464f7d33a23c0d83e5cf45f1c7cd6886238bba165444e22029112bc5eb2079b420ba72cd1d163671507769413e04c128b5520cd156bdce84a44a4891ba85cd1dd9d3c4419dba164479e813623cb530091be229bd22f494a67ecc96640ef5322dd2cc296b6a91d2316b921486f3e74d14e98970ab2bf2a6183386081afaaa62a4e90a11a22b36c03a06548a10ba62435191e6f055ede029f68b4e9eda524b8d24f258b52c5b142f8f88cb4a749f9883be0d67f3957105ebbf3aaf87528ea31dfe6810875112e9a56be0248f386585ebb42ee348c963ad49c04bf77e988180a41ab13c561a366080687fb8bbbf5fbd33b106ddc7820d3a8c73630fcce4117fddcbe604b9060f073b747043c2d286854a67c991f2583de8a42aab168ff0d966e70be797f5e086d27ce5072c9d7f0902019e6c96f2511e2b88036673251cc019d939620949494a4a5c66d69522a961ad1f783dd5034a716a98002080a7dc45041b2fdd032f64e3d54baf60371ba857edaa7cbb1a68b028c256de13364410800e00bc748e881bf39512411e7108f57573268fb547cf11bf9e50109b624c4fe711ab7d7a3ddc00c258c794478c03e7fc7deea2c89a2fdc83bff4400679c40408ea845445373627050802238fd58397ce8dd065d747c0f325c4f79da1fea42474b5836e5eeee0965db493457d960e0fba9a35a6aa481e717e52a73c6ea3ca54990dcdbd837fcb22675511271c47bbc3584addde7b25186bedbcf25e6b6dadaa5aa59492524a697777eb349d61ed30febeee9e362fa90447a9e5e5ea65d5ba9f86e30cdf614d15f93e8d410c2c92dfe418c460bc6169cf51fc35fb5a29a55d6fd42c7bea17dbea9cd7d3dd466bf52c08e69c93ca7b9db22e9d5d6bad1a94c9e0386fe0b0c2a6b47691a758bbc8bc5dd5a2740dcae4e9b8c5fc72529ab95a25adf5de7b6ba594d6ec95b9f6da5a6bd55cdab95d8b6515d265aaefd3b67a2de6bc32da56b39a6badf55acc755e190f4b9e35f33a6bd5b86dd3327bc95cbfb6d6cc6b9d30d8b56450489cc471ae69ad813797a20b558a9a735a87bb70a4e135d5f7691d963ac2b983a250e36bea8e976da28f4f18176a21e6b84d7bade332ceb3365ece53e2a01fe86eab92af732994ddb814d8e3b3010cb28794a7739b95a2a65d97a207e6a62d4d58a5ce759dd763dd9b3b54ee58e917d549a9a3276c09d6e459dab33a795af0c70a7a2ef584101c1753923c28805053acf84c8eb179db658c278ce0a919a454f514c7a9e32a9e7aa6fe35d1c55377249e22393186d1d3536f297982de6e915f473c15a47ed8a1b3e20955840f1c97208f092642b07561eab0e8a0f9a880897be12d4bdbd22babb8cb8bae2413311f7c52006302063f3419b97af0b1c2c8a8071e7cae10322a010f3e312123293bf87081195d09f2d9f2649368c0c5899c7a896483183a10c94174caf825121120a62042048e75f9d571c660a8a4d7e1f74d27b80a562f05196cd76e3f417e8741ec6fa0abcfcbf4585a2f05d902cf1b94cf49aeadd7c33927bf10c1010636e09f1d7e248fcf3df2f8fe2087782d244a86915d24151f19327f21b9a03c124c2ff50e75ecf61ed12e7287b467465be6b1cb1ef398cb637bc563dfbae49a9caab42937e7061b80372d7c426e1ed0adeb1cf806fe8542a60e2598e2490e5a1414b49e68524b94d74f4bc890ee86d613940fc95460a5f544f331075d217b89969c280f8bae700aa6d43b35eea36db2461f1ead11c67e9fc84c3d63dbaae48cebaa64ef477f295bd5ebf1b9a17e9d83b0c6e80a7b06de50df20ac4c4d7485bd82c92f649fe82d7a7c891edfa1c7d7f5f8be1edfa0c76e63168be4c9fce6b1db29bd73d43b358edd26491ded1f76492d938d8faa1fad91063e5a2a1ebb7d519e2cb446f87fb42fb03ac99c6a46aeb06357961ac6e3ba4457d89f62c9a37db5973cd6a5c7d8ab1592875597a48e49231c3f3259cc58bd7c3351235532b74774855d7a12b86e8de80a3b8fa64979a444449cd68d9eda22d3f0b19f28914d980ac74c54c3f1c35b953c5aa3948fd5db3b98e11b0df0468bd81bbc115bc42e9f01a9b0fac6254fecfd243eb5881bcd63dfb6e4544d78420eab13c83d57ad95c730db84d43c1af2680f92c85928e4490b995f0f85c8319e285af282c9d5ca42ecae9634616e3fbd94134d049916b5883d1552a21631f64b947d70f619e00cf37f481d9b63f7a13ccd4457d8714e61e750a0fc0d94df4cd825b6fdf4f98de6b9d449af3095d22bdc44e66007e50e7a84c48167cf6d4bb6b676addfdced582cd11a69e196ecdf1b68034d9489e9e808069bb1212712a71165fa8d62fc7dce8302a13fcee7b6701cc2f43ee61005b14f30887dab5129bd6ac72115cafe45dbd712722c91bb27f2f4ab9467488d90c917d47ec8d2c49205f038ba99d685deb1dffe02d0b7cf97440193058c7c177d3b0cbd93999424795b6951ef8cd40895d23bd4c9b77737bd14ea1b6997af42fef68e873c9d47d3a3ad67fcc0c918b87079bd5e499cecbd768bead5722057f0c909f2250cf2acc19bad1952f08547af107f5459a194822d4a90b6cc0029055470607008b01553fcde9b44149a8e3a73ac00fa5a3b89134014e32c35e1a46f7e578a7c2c588a319d398382f602054f38bc709072c3d367003f9014b5010542568ee0f2d2ca112fa0f19b19194315463f473724f919ea19d8ae497ec65b6fa30204215d41f2d665116f2d75ba02e5c72e7aebba42c58f3de5ad9d6d9bacf0f58ebdd6553b640fca4f90c67333e90529c8a0797b7611dedfc673d36341f3ee6aafbcdced5a0be19194a6e0f670d8e099107c830078db610f9b947d04e9951dc149cebc1b49061a7d967111d2a29d209216a36fb083f71d72032579eb1f2c6951e2c7b9f401985cbd4738416925e8a5b74292d46225cb4b6f85ab85b20048567cca793427bd9e9437889de835b0bb3661fc04717ce6e998c9de09f4a3b802835f7e823bcf496e6eb2ceaa859f731bd24f5083e7384e7a0270411e7da83e9b1883a3086b7ae9e998495af2d33914cc043f4104fcf474ccc078a8f1bd42167a6d3d2d4b969fa0cd679e0928ef10b7e63ce8cd747933e705718338bc3d7f6bae037163253f41033cc7693ec1d9d1e95d97cf35d6b4c7a1750c66ae81a38f769486a588c14f90009f8155e6d010843eaa03471f5fd8655d9662ca4fb0009f819dccf911a47e56c1f80902e039e9ad90b578a73441f319de4cef97f3a078f47143eb13ec6e28b5b002cac151a565cb4f90f519a881a30534d087eafb06eaa8052f85ccfd2f289194927c8633e585207e82e14b6f85cc259682c84ff07b892d853d75bfa0449a22f617df5c9748515cffe0550f84f31b02998f0a479b4779d722762e93b351362080f01287a30fd5639fe1383c77935ef0d24b013b0daf711e3dbb098af017f452b8a10ccea3db6380e633ac1ecab9eb61efc0f92660e7c0f91c9e586250b68892dfddb44ba4242b2f91b018f113bce990019acb1645781b3fbdae459473d43be1b62009a416bc94621291b493a246218f8465e92798e3bb934851bc7e821fbcf452981b9a414db24703a2b1209ffed2d7c4f7216617cc300df0a6ebba5c3b1478a36929f046736d626d0678c339e79b731c5803e2c61c28df03b78e4e303ec1b994042848f593531e9b60687cf1aa1db2e73304c14249e6f56991bc0d225a1332c7e1a87aec5cf7dc8979b4e4d1b863b11853ac29e6147bdad1f2e29238a80d1b8f026de85c81478c375c446346b1a3182cb684029d9317dc41e6e040cd97ab45eb63b55e8af0e2c48b142f53bc24e96879519239f2b9bbfae9ad1e05ae1ed7a6a6a332f248e56533fcd16203c55c73fe0cd1bc0ba2a7855c665353513657d03c3b613e9a3e4a41f389a4458d869f6e83fc741cf167467dd84c14d8403a5e720fd11f5d6c8ca39e29682ea4458dca167dd864e7d10d94f35cd609c9951cc244b9e833922bed0a2800f05acef3681498f318942a787a097b89d465cb5ff1fa0f5e227591f29cd669e06c0a9bba145104d1b4ce659d06cea7a32b623bb449d64dd488af8e99acb92c0a421fb502ca37405f86d94def84ce35ce51e31606a13f9d73ebf54c07e14a96e102d3fd65389d66538b5665258f3e6cc2116716678fa45fb12c5bd4326e03c7efb7e975285be6e8e94cf753bb94d0b491dea12678eb5369168591517e7d7a5a389f269a89e425c99c4eca8c9b4b8f85e94e7a678e38484b5497d50ba2c29135def0e969e1db67e6bd834275a89a02c709e4538836f1b4931b37a68b3635925e59b7363d28cff7a1c2cc7edf2f160a3d2a6c003fca2d131bb7804af5d35b6cd15a950d68a4c84cd37a32db87b72ee50863f3f0d6fb8824c13a0ec71f8fa7d69a57c3006a3a923a2e3d821e71c32ecd91d4a185fdd2e9925d0852c1ce688777ce39a7ca6f03e970c9b8f2a0181cc37b7de2b468e7b401279a5e596fcda7b7de320686d2f374cb7a27e91eb3e9ad6b7367be756d86b66d87dd3d7dc020dd42d5622e7030c08035d1c2d0a2b52fc0d0a2d5c01c39509895434bbece594785e3073e47f3cf557ee3c60be78652bede8937faa5853e3e8e428b3a54e47b820a3e2dda51e543fccce96d816a5909bda3eda0dcde70b4c05f9f5c4d2da0455b82064e47813e7eb468bd877c9518294f01f58e9d28b7fea3772447bd9e6906956ac187ea512ffc0cc7394e478152f3f1f3c17a1cba4079a63c62593bc1348f8d4fb7311bf035f6ab815ab41bfc04259252166f2d90ccb17e25bf28400515578a145d314274a548100541ca6597edb89c2ca1c6a57fde0898e1d2bb1a0464976e933397dfdc9185aaf98df91167ee58491c7646e8a1386d0d88e92a4bbab2b2f581972cadcfa2deb961c01c737c367f1cef4b691e969559e6371bb54ddbfcef78b9ab6930f40ee79b11a9a3bab5ae0f2ffcca34c47963b264075b953c30d0150c94a731ced7fbfbfa0556c03b08a88786fdea320fe319b628c5021c8a88690103072db67001c5481364c8c08829a264b1c1c9ac4c492c0bc5124058e9258ba6af8edd71b22c82b8588a135e9d91c5ebeb972f6fad95ec3858108de0d3996441c4054b5d50b9610cfa848932342c8ce044d1b26035ab0373c60757181c7c180a134410511813bcc244e941284cd21108588185b102041038620af365070854390ab3050f548ec28c910304a8307d354b61352bca8f1850641a2f917ed26071430f4d727d897403098c18d1e58627696e90f2c31d01ca4285e3acfc7047b63280b250e1b828595c2e233680968881c2868d0fc9880d20d7123150d8b00145cc754ea65259a5d539314c9a74680919c215910255a69794e9ced6789d3dafabf1e6161d949ca0256488a6248a2459e4eebcc65acf7377eebc1a8bf20e47cf6f4620ed27b40ca3e75c8327c8cf35ed1c38c2f039e49c07f57cc2c42c91f97bcdfcbdb79f832a79ec180338bf01e3faf5eb9cedbae92fd3df8ec9ce42f2d0eb5507c943c306d3abebb5c7f8f0372cf3d7c72ac46da1d650c8e4c23485a92564c846054a4b0317326446085ad587cc2f925a4f524ebd86d6061b803588aeae6b0056a126e13a05ebab48f63ce5637dd5787b69bf28cf34fcfb824638662eb0163f4ed88b0bc7d48c70acae26e1067dcd8bf2b417b9ba391c5bcc5fe75ef5f51de34290abd39ee1f811c9f56738ba9099b40488574bc8900d8a0fad27d387cc145cd17a9272ffa8e4b1632160c1b9b763134657d72f1ef353afc92e6174c6955e082687b94e5dbde3f9756aa4773abfde31a963fbeb0d46eab87fc3f1eb2ffee6e6e2efd85ab080f29b145232749e72947b9ed2209c4abdea6eead407369816af7b6037b578bd03fbcced588bb7c77419b09d5abcd733a516efd2bd1e02963aa4c2827389b1c1b9c46c6564e1b632b2282063b744327669e7c4d22b9808902035408310960e175abcb5928ab7d60f80c3ddd039af013318c4aa5a5ce13a0e715ab4dfa7815fd6b44e2a2053df52b9e67a0d28e50afc361c9c3983d8e7401c15c7398fc6a07dae3b2e03f33b9f5e0fc63d1e8a0b551d289f66dbd488641a9e401dd72fa13bb9a32345b9430089a50e96ccb1ae52b1b20b6bae098ec894295b1954a8e08cd475b5495bd21fab4d8b99579f4b9e04a84fd8e80e4a1ded46fc0cfd33f45b2d896cadcd42ae660244965afc2f43418380b250e1a86099b2f9b724872046bea68750648ae937edf480861afc1cbda0a14dca921d9c704438224b2ce162441811652b632b830922b62a990a9d9146738a06e40fa9c3c65b0f2275c8ef495e328738e21979b528640119968c028f164340ca4b4b34bcd1ac07c92fa985eb47ac85ebabedb14e85c821189169add685fe9ac81ab6529cf81a560a2583415ab4aedc2f5d79cb001089c37a0d7fc81ceb1c9c208ffe35ab2e843e43e41fd631ce4ed65a4b438bd67f380d3fc21fd4696302280b150e0cb7440c1436c2d8b8a19ebd06fbdc504f79f69b94d7f80cf73e2a2160e11a8950074dc941720688025d59af01adb5b65abfd5390faad6bab5d67a2a64512c99456dcedfe7f54bf6f10305f6a02b6b9d26e5ead662c0ba0fa9a3bf71fe7c9664787f41ef258ebd55b060fbe284c8921e63230c14ce35440c60c6bc9a7208ba612c81a523de709c4f6593f9d8f5681fcdc3d2116f388e6c1a6dbae9e9e441f274109d403c6da78e01c993e94aeae09eba0fa9a37ef3279341bd83b2b0837c64ce03e48a3a8bae288bf53d2da8d32b8aa3e4116f3fe69f8eb73272ff985fdab6211199f66811ca8f1e48799447d80c182eef4aac0d883c666fcf9e045269d2a449d3aa2d64978b490d6d5a3b22fbc8829247dcdd587032862f498a94c6a83f5e8620f535ef3a07727da401871ba8f116a494524a432099b7822c3d0c643e760e879e0aa31602b93ee2e93ed7418c7f8621902c6442bf7012a79b2a2ddc5c7aee398f6ea9bc0b8b741de6b6ceafd7aef39f1a5a5df893726f0b81648e352628cfc0142acca173da85120cdbb9e7cdeadd9c5e89d0ac67f7a4938657c88bb195d01b88b73072b0bc9e59adb5f3a66a5eb34c63d54bfdc3517553de58a73818cf6ffab8f1d3592de668517a074359ceb00653a6dead754dd7a0647052aee44803f5ea3fd64720c058c38fd22509928451c88fb2a6907f86e38f9febd47f6ca5610e5feb877aed1bfe50ff09c71f6f4306d4fc0ca524806cd51426fee9429e4caf610ea96d812438e2f086d9e29c7399b3b9901a5a5bbb0c41ea03c97cd47c03f4997460f3bb85456a70b58a081992a64a165d80310619695a9bffd4d0dac29fceb9300492b9740b32d9864cd7d150d0cb08111b5a45649ad6ab466b0b73d8fc670b2f38fe781b6e60e4f0b57e36e79c8639e0d60fa62be943648c888c1f2e63ba94f1a4f5f3a47d0ba9cb1b1287d21e8e887ecc4743eea4fd907d74169625260fec4157ed1d8893701044a6432d8a7d5d903af0b7bf30a50ecebb8af1dc4490a7cdb6853917b528851aa1c92315a2453b45429489cc69bf61ca54c85f680474deee0215ea9d9132f9f6a644dfde4e2813a9c33bf0463b42f57dde8114a8574d5f1f6c91c7a654322dea1d3a4a399dfab0348221db4969b13da66971a38ad3b7d6a12cd6b7731ca5aea72727a7a69cf4a8348d1656410b99220800000100c314000028100c08c5429148200fe464df0314000b85903a72549bcb836910a3200a32c0184208008000000800801087aaa60800c804c07847778a62af42045c3eefb1395633e29e034b5cdf2546325fbc9c514f576782761573019d19b546730653acc2cc978365d94273680b7ab0d6ba402a841a45626b2a7826cc0148433ad8c14b87bdb74671d85c2fc8e1cd5df4eff07fc2f3af20fe69ede617637829b6f1ac2acea81d7b731e23d615868225d8d30e4a2fd73a9ee00fdb3bb0379f2c623787d6ff0e60bde4e2429651c41054f1b8e5eb177d93487f1a85c27fffeb02c5ee47001de08d4d4e3da1a43b78d0cd36823dfcfd63ab1559e12971e51e16ad1d9aac40d1b8a1d5c36535fd152cdc1dd743a6d1e713dd022c657f81aa1b1ddbb6ffcae518ad2be036bceaf2921aa2705002f800c7774a43b0ce527d08b6496bed3e58b2761805597beb0c54416617d55f1b56af38d66223fbd0a748bfc1abad4d37eb1cb6c53d2572046012dbc8ad1bb71d254c3a3cb7c2e3dafb5f5a980f5c0bcf895fafada1b01c51473e5f878fa12557bf4d03819c452e6f12e2930139c8d49e428e443fa2428e924dc486bc24fa881878a5eb7e4cac4db4c33e138c559a01664d15c9de976c24c17b5706157cccb889fe8b74a68fdc3dc5d1e105186a265886585229a734336ddc1636a4af7ccaaca6ddc215b168432cb21f5cc0beff97ed10668377117741ea4e0f3bd6094655b7986652629084ecb289add5684280d798e06fe7c76f2dd87b0b80c6d881dede7223cf0df9aabd8beb883623568337f4eabd45978e1e8874268ec27d758f2532d17ba33b412f940e2c3aa0f4ddacc85d4d89299fdb772c99897e86f4d6737bd32d3df748eec647ee3edc273419315e634e5a6c633eb08a285b4d240cd05aab26cd03c1faa733e8e2ddf046250cc643a48e2f4b14500262a0095c55191d8b7e95851ca50daefed250b591c12e1f27cea70f3844a68eaa475d344ce97aef58357f5a422136c8d1fe0da71686bef4fecd995dd063a9faef2bda19214a5b53976c43765fec464fd51921955d1cb6be50b676617246b8478ca199345ed4fe1a90006ac71abdd7e67b3b1780ddfa7087d73d18fc125f72379742ea53aa3087501ed05505f77d03e141d17fdca58a194ae6d0c3040397839e50c2346a68db07d05c2dfa9d7f84c1cf3973f67a0f7a382238e01e438756988ad898382dec85da89415f9d93bad46179f09ec8ef6e037a8ac7145f753d6528ebfe58bb482feed01572e5f6413e4f7eb147d9e7570bc205523acbbe61a3cb0387a5b206768dc06055259084c297f7d579bb1dc111afb5defbbf1d15ee906a5e81033acca506cb4a6e9468ed0563273e2d88d221c33e56bdb1c7160e48a876ce33926373eaf2aa82588be50b23e6366c5704446ae843ca862cdfec095680aab539b47e3f445bdf47b92032a3487f5b76d1e2202c3282bc794d2f216d7b16bf4593d654868899018f277eae3f8faba52e7c31aeaae28fdd02f09d4032d3c3b7b30e9411460b3cab5d78d182d63484b6cb23b69315305a9d9a496b9899c4defdcca32ab49c06efa833c6e110e30e0e8acc1ba2ea4561595cef8a4bb8bc6a5520ef01a4ff440c6bfd79a6d175045316452ce210924922315e8d66b83a70966a8f2962788b7730a48439c0c57b50a3163d96adcaf00e8c58928bf5e783eee9f7b9533683224120d8c6fbce093b5cf4e17bd49cd8ec0dc92480420e5ea6fa84c455798b19cccaf848dce911cba782654134648acd0024ba76416ea60957934c9b2586926a42e08bcc6a3915093a968ed2eaf9561160d5b5a798c41377d03a62ebd9ea92c56e65eaa1e918bb67ad93c4d8c0b7e91209736a37da56e81c540a097037024cb036586efa74a4262ca2d657bba891bea062f9026b07ffcb72aaee241b57c1d563027cdfcda26064625d9adcb55825ca7cd8ab0de4595c62f72e236d5595f588094b439dd8b73177fafc8b8518787ffe52df8a56d030a1819e651fcdea99b504db92a225d1202c6c09f9a13c11231a443ff9b99efa069efd92979f4f702dc291b11f316fdc25965832d7605c31193a2947ff72dc8dd500b70802f66daea38bda1eb816f1d2eb0a28fc2411f77a7d5445cd181120e65663e9ec3d12b9b088f9a365f215c0ced12e609c478f0f8bd0fa58d2f5dfecff35d7e121921b90809b93198aa87ba951c80be1f90036629d5b15c67cebf3d496f120e9df73c60bb3b831906e7825194d91319d9ba2b65720eec3e7e3292168157621f2796903e8cb0cd5ad2b5f85f5a1fdcaa42772ee681b7c3a0209ed17218475fa3928b0401e2bad58841677bc944569126e3f1d148abec182d675042ec67a6f1be04dc4716bf184b398c903621717c280132166226e5f549901c16d963e80b4d295543bcb52fbd3e57f548ddfa59c460ddc5a1efce7908f3af2647087f57258507ea2661a66c937bb28509516795888da0695c34e116d433e305ec12cf9d6912e881c2f8a76b1e2e4ecf4742f3118656312552ce3da13a8f37b4e846503f51520ce9d76b10f2419ee8d88b5e4715bad2ddaf1ad1ae58436353cf49b1a719577186b4bd0c48403564039398b9bd6054b8bf13732349794951afcc2adc2265cc215a8e7c17a2516c9a325940469611fc5ea0aed01c03d8d035ddf7fde924dd6b32b8866256f35fca8886f5a4153c445366f61c0bb452a2ff470b0c4f1ed6dd9bd229998be2910743241261156fbb9feda06160c6201a02782ca826232e4f799922bec0f2794a16588fa930952dc4b3cde1ac6a174df06ff9eaf4e46c7caa56040a429ce1a79f15828970cf01a5c806fd636ead0e9df1953890bde4c8fa4639c05db3e0fc9bc0078c67e52683aba9d5528ec84864fbf4e42879d1ac22c28f0977d2c5cc565455db7c7a7fb5160ce50a67a58ad1e6ef4eae88de23df15a9043b9b5297179c238abd060b40798bca8731db0557b35b51c8304a9d7fb63017622a05e2b0ef967f29d1dda46d5b740d2b9f72b4b4f3ec7829eef860d9217b54045dce60b23d4bc8921e5f33caf44bbbe4c05b55fd24d3c00a7f2fff1bfc02e6c2ccd077a2cd8fffbdf1d54245da179e3a1269fee5b49c77123fea85bba483f55a507b8d50f512c4566c2787a59514b02af6c508fcb0082fed5dd2a26b356ba7ef692c9dd18b6e59500b7524c2cb0722b25d082593da662e301b0d6c39769bfaea7f3ab1244e95c9fce51f95c75b11e383cc210e55194832dc2c4b5bc9a977ff0e205beccea0a7bb4ebd82d1bc3a9fd819da5cd48f959ce2c7298ca44bfa02023e4de912c2ba61389de414c837c8ce7bd587017ae64da958b875084bb77c306b8a0c8520dfddce7e072cc0eed5e62364336c02a841efe26f0bfbc79ca321c8eb8ac8935678c599cc85c898673ca03fa93d052917a94364561bd32d3cefd43de8c5656b538d2e151e9bf018f170ebf7f2a8b5a31a79bf049a3fbc9b00e45dce6d81b8d9b4f45e4053b6c741a8a3e1bb364ec15b7718d488fc3c59449992aaf97a1e24d108166cc200a653607ba74325e1b8f0ec9cb25a87c15b4188aa8fd4673e0d68c56067ed2ea874065176af3ed165484b2fc8b0d2f78c80d7aba42ef9d66e3619d3da9d10bb6562604d5adc509b5dad6be2c0205cc915c8f099118c4d0b0bdec8dfda7d266da81ae89f8a6eb30c3e515b8bd846d985c463fad024185eef147a81aaa23b4b761955b027711d49655df8854ec2ccb62206a45f8763634ff0374b5e02737791f02bb47edfb037296d897de719e91d50b92b27ec7d44debbb2776cef3d762408c1466ccdd991d906cb0586f0947fab9987aba1ed5b7beb899f20401f53a79c084d4abeacd3777a60c137220248aeec16e8db96666627e3c4f1b8a5edaaac1535925a8b17ab9595336c800c368f078dd7c497526858b2f330c953a18d1f199550d5b13b709f66255c42c90748c4d884dd8934a82d7c832674990e2c530523a1d9b70f7dad0da3190be9e8486735baab7af0c6a39cbf1f98f67fecfd9fcd81dc4d9d396b7d5862fb0effae3052bb49f27c3c06e46b2bb92977d4be43a32d513c89ef0644447d1697a3ead73d57eaba307b29d884289744de4937cb65864650997a207f7ac5d11c3553e3ca3005e683cb74e79be7b787c31d6bc2bc6fe1025d57cb72623819ae8eca69232971d645c381841b72de279ee4e7bb7f543841c264b85501bc492424bf1ab2184b7d2f4fe1d48450bac1e91512e1e6e117069f66298d3debb42b8999a261bc135446fa74d27219a5fbe8f45696577c87f6f7096c059546712b1fe7156b03d4428cb242d2b56290caccd8927aa18ab3f7db81bd0a6efc765266b76b4090cb6420f68aab7c5db9a54d8c326602dc6a0c27aa7689e159a148f494829b82bd2ae450757536e95c89b6b4da68e897fa20d4e737aa559493b19ad5675a451d27c785f034d5f3151cba0305840c72ea9cf0c6c3369a9abc998f035696f40605549c942c8c26df2591d8eeaf429fffe619f4f9afb78a10e57cf8e12b4298b459565b6f2ab3f7d5c13cb07ca53ebecf431881471fd49b0a6e0371c7266f4bd1529b546855c5406713d2373ae3a294c82ec1034012c956c95889f36afe71b77ff65bb7c0b05071e5f398d55c13537015f0b2f2f4d3c72bdb337addd708a41eaed5b626d09b49ce479e5be7676bd72ecbaf154a11d448ce1571091657c91cf73dd66c58160b61510851c17d90a9ccd9ffc435888c1f364dba51b11f65404ec8bbcdc945cf7b3d3ca1e758a130681879002bd0332d1149fd31bc9d1f2611754cc59d788b2b4bb40215abd0ca033e579292ea907f6b0f30dcc8540fd0ac55475698fe9fc28286208ab0d0fa1bbf09493889ee0ab19d4f7902815334182359be35cce0ba28918a8dba75202a470349f3cf4a8d00b9b765ec78bbca9679179bc57008ad28b77119b8ae8f0889d582318fa6ac6df0924af10399ca8f6c8047a88b651e3892d22d76e0166603796fd69522a3cb88c59ce36312830d16a88e35a43aae866d58d4c78b4c6f116de4fde286a8d9f2d8eef7d70cf9b28633e3760f046d331d15cb4aaaa766d4ee566fd6e0b1c15b29a870f6c335b3de247e267cd5020fb3c365dab1309af01107d8d4d69ef6824ef12d4b3bc5aac83bef9c636a27113e5bd09531089f5e514c09cbe9d80f8544dcf7bb2fa0f4f65548c2a827812dd36c1f49f2a85ba0337b1e278c26358b274335a3f9e632a2f75accb2bff78f45d8f3c142d34746abde7fb592668e568db0224aa35522c4fe6291670f0e0c7ec1b4e829bda17edc6cca97df589ff45b0aea3e9a6f70bd088d6c0959741423f87f3ec210c7fb93f79e393337d8e59f68ac40b652ef684322aeaea11affcc733676310be2860d8aa0183562eb00b198ec628ecca18edc841e533fa1a31b7a98dae68d094a3396b319997e289ef389d09c251f23296332eb3750fbe3c0bc9ca3b30c10aac1af8a89140feb4560004e758844d71fc26693e5020a5d35da4648213283be0862223c3bacca945e27a0dbb90939ce7d91d5e2ce1e6d2097a28c9a3237d32580e3183187961661ff6771d74aecd538be3c0891d26f0bbd9693dabdb1ce18135f2d7db42833d7a390166c48968397abf9c058ce251b279ee9ffc4c7709ccb077c0d21d4c915ad87c9143300c3c36b277eac6c2929d903beb9d1ca6251aeee830fed76d63844d7b73805b8846ddc7be2d377dd8883064528f0d05219905a70b370113a01227cc8fd4463360be2c62f5093bd1f7881d51fa7b71c69fb1bb1f6ebf00504dd41594d168ee702d81b9c6441d31f97d587ed7abc3b70c382eda4e9d3f64e86010196b8613090d3ea64e7036fb9ab876d5390daada4c74c0dc4fe89e2ec0735d3cedc3754d7b922a6d40410e51a47022c6477f036564555ba430978216ea1681fcc3ea06efa7d32ce98ab73f4823771e2c9f022cc84143aa1bc3913f9b1867c4fd3a27c6eb1d9290cfd457907655d44addcd3ad2726dd351e98a0c2bc831745e3ddff79b9d228ad638ce92273290bdaf47eb54b2d457c6df2226981c5b41cddb291e14d48058de736720fa7151ea79a6bbdb90f3779159bbd577b011680c7a1fe3db4fb5bbcb2ca2b7008ea0d1c22970fd6bae591564070006488eb5cd0bdd12f3a477125293a1fc7515329b1c1be54f53999e874f522b4633c6276e5d27e02bcad0b75c2f4bca4529a44b8ad2231b608b280bb7d9d1771d1baffedc9dcd906edaa43dbf43bac2652cc1c78586e520da1574b3161e043e755680380a511748d8d6c7078d2cc0bb699d6b2ed7e2e4d6a2508536462894188f06f570c60f182a92882b643350c22b85eae96ec9cf1300cf7acb00e1aa2e29a3872975be0ad3f104a126e5d37e640e53bfe7aaae15e74393cbd9984c99b293e9ea4636423e811dcbc585e6a6be97db4f9e187887568ebe04ba8e47375044fe5fac39b7446dbb1b0b196530896fc00c0b012fdbe40d13e5f2172b2dc3af6cfbdd62acd0b13174e13cc126ca5b44c341cc43d9ffda0d0cafd4b8a54ca125724f653e4864d51a797b63037f48c261745311bf8d27c410b60228c13afb6c184965469f25ce033550bbb03ce70d5cf28a2f219f7a30ad2cd72ac3ee52dc9b56a0fb3e5d2bcd8120c1260649621968891b1f1de6a626e14d7bb2f8389faa8a9e97838cc2a67c23bdeb028f6862f1fde349915ac1e69d419e5740f5971f559a4be3a2da91338831fa8dda71568e160f06021dd75dcc772b6802c70aaa5588087ff01d5795baedace066395bf32e13dc7477559200d799c4c717f28a21b82945a1a4c4a077e89a149b94d891d2a377a66d6eeb3aa92dc1ecb576ed1241a96814a46da8ccafbcb081b5736d4e90a666c3368ba6792bef17b6e02e5840dafbbaef7df9df9d84fd950d4f0ab930e0d735d93dbc923f4f19341e447b2ce22fb27ceaeccc67dd6faba4550c78b61925cd7d2fd789e7e41fe6bdc7e451032a442f547a4e64ff4dcea090dfbe5eb2ed04f5427df0d8808ae5bb2e9fa79626f4e2c2a6ec2485e54f251424747308560e11a24343e02eff07ec4961221f799614b8713908596d8a400bf91e5d741db91bf1890c3856a7bba7876e1f6d3501850eaf899c0eb76b50fa51b65876989b8634215a663cc54439d5d27a4999d4fe8270a00a2b30046aec809dddd8368885324c129f3a3ecb8cec18db0f046de988643a34a533b52b5dd140b9df3897c8c0aea401f30ff0892df608b26c5e7eb3b17913026dbfe757a3e7fd88bef645700ce3947c6868e369e8e60eeaf4e746c6e3f409cd6fbb0beb404188aaa6f4c5eae5e8ff89312f6a7d8063c3e008fc34cd74f97e52431d42857dc5f7bf86e214f78389e2464658786b5889d33c91ab278d2add0122ec450ce51ec529e307fb46aa7f96e98f925119ef3bc7d836346338d18bf4859e9d67f907748675be65321a46f3312877a34ffeb3ae7500429de8bc423ea758a55279402155d106a446566f0d684d50b77cc97b4034ecfd11a059e4e91e5cd40a7a78276330ead47a3a32c7886b4e3ab94d2978ca64adde5453ebd46df2f766582a6ae39377da521439479d4e70f03bb70b101a21f8eaa988843762525236d4212d1d31785f3b7f16911f897a0b0d6c4acb63fe03feffdfbe821c0d908bdb83813558b9db6253abec82205adcfe71e401e0897f30f3fd192e534f26736359ab24a959baaee44c446eca96a1729e4b900624533c710c1a95314fb106f15729dd62b74b7345dc242ac46ad0114bff663fc011cc2c16dd093413758ad1246c435c796d434123d5798baff894a6c60626b60750c505840776e32000f44d18748ec3b38dc2a4ef87e1ee4f130e2768b38d45eee75eee9d7faa68889bf22295914c9b43eb80ca335ef4a09e841cb00b2ac34573b342d4722eaf837091d6b4220e1263290f006c2500534ca478a29504aecda8bc7e1090fd63d81a9815af311f338f49bffae5f206385e2bd2ab9d6ccea77fb1b1263ecb428dda194dd756b5fb13ce1ae19532d41669cca28711eb44c86718bfae91a382a1e8ca4e1e502e8686533c04aa4734cc189df5c12594c96eee18d21706858c350a3129a873f7c936755e8ab373a35d90b2ef271673359fba688050318a9644a66737e2b66603097e4005e783656d71eab1b5c79c7dd21453cecaf9e417534333e3c4953dec02c44da472495a0086e29a017e0c5fbdfaee1948d5e4ead29c78c52eaf14fafdf09ec09c7a53a6a8773cae0be90d2b75c3be34dc3c36b6df59dc148c0163f3480746fa027a32c953d04996d1c8beaa2fed6c835c9a56675d1f2a24e731d8cdfc809f20744cc0c56fb7e0139769bd057ae106d0487954bbe51579cc42b303df1f07e42ca58a41714cac5d669e43457c7c387d3fc83975088198b395fd3b4965c42c7b0d20e2d5b231d03ac30961d6b9fa1d12e73b7078799f8412ca3021b4045e3a6b34c976b281e327155f67e5d76489d4243eba0150d3fc9af300926debb7d394b6b121adcbc2a2351465ad06b497059430d46f970d0475cf3c8d605c16094316cdb2c6f7f6a6141f4d5ae01ea3f476502bb9fa2bc04fef37625d89614c480a3732cb6643b984549bf623d33b5ba9fd50a77e8f86edbbc83316810b0ce86f4cd2170aeb9d611ec3d8c718a83c7a20b79dde15dadb7530ded64d4b5dcf38fce242582329f9d6b2d70e7f78add99abfe700b3c0741d6ccd0cb5a8a5e913724fc3a89ba16547d2b3ee0c48e36c1a5dda14e740b8955e03debb344bfccb25c1888524de63c6804b546c419fecb95ea41ae7324275ace92a99695afd356abf5c32d432ae104654a61ceae1cb409c5ec0c6e13a513ea6e67de8101046365b749c25d29e4fb1e193c224dc03ec48d9aad7d9687478395062766f1964e7f75243c98db05269174f145149f816113382d8bf337d028b2ed03b98449e48f1c28f3dd3669d9c17a8a27fcd18d28abdbd3a5057f054a8746ee9fa172a9467a1e7941aefa9f38790b2878f2b85c4ac240b06d9019761ce37d8782db30fc6a6ed3094223a3b96efd290ccd85702a4ecb8dfe069aeee384281f705c1a1710fe9060439b05df3c3f7673f38b24fbb9cccb87ad2e5dc84a75dc77f2bb03a4bb700ffa82a017d09b48e6e1373015469c09357e0894aa22d3a0eb5ecfb078acb222d004e8e1b3f46652b419bedf149815b8cd143402f70220a76046c1c3cdfc8b28ed911a6ce754c718c20fed989007d07389648f2e4f85aad282f0ec26cfd5afdd8478320cdea21884a44e618d514eded2d18e5f51b7c7cbbbeac558751ea844d937d7f1c7664dd10408aa2b23bf87dc57f8f4cb64f04bb2108e6899ef2f7b2e449f3e429669dbd69c5ff705ec8d616781a512a602469f1880c6ac596237d602ce35fdc4d9021269a97fb8074c890fd117dbc587d5ac360906cc07f799d3f17abdd6496cc8a9ebaf5b8c2231097ceef6409e63f2a25cbe306f79b00ea9bab38bfaa9bae97b2a14f6a50fb2156c9331c6dfd2950524d1c0108dcf44aba1002ea6a1ea530eab216c731131b482f52ea75415fe8eabf4f11ada7036dd8081523a17b6010b5ea8ef0795bddeac1e7f42d710371f00d881eecc0d7e8e0900f02927764ca33070ebd12a841d6d3495b380a2fbc346423cc4b11a2fa1021bf567c3a8e3e9ac87f02cc16098bea6ede1074c527dadc29a80ed57ce3eb684659039462ceef603a9ec1dfcbc26832f5e3a27c3b7b8e02b297e8881d9a528a02d01fed9b3c1f8792a5f0570c8e261a5a29713bda9bc0fa4c9b5af332d0bc0988a883f9f1dd4b1e0238b7aa34aaee15f23a90849e7be6af8919888128abd00afa80e839852b88bfa0298f878e0a62a39af6140ea1cda4d37c8baabaf07498239a04deeeb59b8b7f8e43fac96c7e3e11ac7d6fb613d26643189e8c068cba9ac075ffbfd3ffefa4c8f26eb34bc914384b07aba06eb957a21a02402ec0b4ca122d3d00de6c16bd64b04d98ada1ca2c71bf3fda34c0cb603558337619a531f4e786224777da08fe0e54e083ea0f6a48c019fcce2edc4732b16aa203c2dc77eb7ff6b7047b524dd9bdb88b01fab841b4c3cad0ce22e7c8870d31bce93967f09583e635de14fbb8a10fe95aa6101dbc5c4c3b1a7a2722cee3b0e94bdf39ee8dd9608e6e22e92c6e2262907f72f0a5a2b7af8908ea9aa924e41d13cbba7cf1ed1841aec16051a2faed66cf96713f9b05e502dcc5722485ac11dbc3889a08112c5f6b8e72dd57905ecf8891d98ff4fa615b4fca0fe93f56a21e7831d0a3eb363d5ea20b2120942b434bf4c3586b3924d375442c59411d8f91790a16ba8f2bf8322b8631628b3cb201b08dc02eb2f54fc6721cb2beb47ff5f62d01ad019177dcf94bde373d58991cad74b0b37db45e97f03765eb7f06e8641305519801e46dd422aff8c65dd78ce8dc2ae80552e658876613ae24e1e082943fc6ec1f53ebf60bf8acde3e5f9ccba39f2e443c190286bb4b526e5fc38c69be2abd470f15e3505e9f9446dab80712ef019abbfdc16a3d5b818225313471c0b45314fd9706126bc85c3bae0b9f7aecfc80c7ab898fb4456797e9a748e94dd08ceff58f18441e8bd41df47a7022239ffacad6a79325f9421d08f4c81c621fdee3bd9185c78f1768aae42f9d6e74c5d4b33fe454a754ccbd5feae7efb687004e569d79af6cc538eda04341dcdc4c140e22ac17b5270cd37b712b6195f3c0c6c299984e78aaf3be5d8dbd785e18b0b58de4ec46038d545227615983a5ba217ab7a0d400b1624d9fa254b7d8e092f06646c9ea557de72b8dcecda8267603759dc58a7ee097566048cfa4580f790b0e9c2a8de1fc05b48ffaa20600a10388a77d44b4829569202fbe10e6e54dc0d4c39642b6b0f3253ef7dc764c896d897a0ac5ce077d7f2aecb22416ec44e3fcae0cf99f77ecf9e3aa85eb7a50a1bc5a279c40a45cd0732a99fa967fc870cde5cd9865a89362bd5af786349e737b70fe5c54f52bfdf90f829a78072007880b2df682906e611ddbab939104299c0bb78c182642f8909a93e58d3d56002a9242259e0a06a674af7854203f2ff8c55b8f3c911a140630ba6832e7ced3799fa6e2e4f7cb6b2efc26327e028aeb52865b8328bf2745145bd868b7b5fe7bb1c03bda037be8b13faaa9c9da5db6fcf055e7f0fd59ddf66006a1e2b33a815bfc0d1ee7df62545f359ae0a07e001ac56b59a019674b2e0edaf2567a35abb0b40c612f65c21af620c1a8783a09cda88c01c908f688c893cc0e90f70bafdb3a80c7dbfcc574e0a0eefa05637be9d9cfc8856527a829b0207d17ad486c881e0c8074e8e807734523d403e0c4e7dc0a0bb3eb84aaf01df34d2c00069a8d3646224a7f4bce96804ca74d02069812c538bc4772b01b63d1895fb7e7a0771ca22e6efa73d2516251da333310f095608b9b9c9a0f8d8b808268e3d710218289a1293df318ba543521561fb57ccd98eef73e7565c362319d07b57a5c67df699719a4ab70e51235c18d59dcc014df08b1d75653369dc16b7102f4cb534fa828efaef19eec0df9f10389cbb233c06631ff5eb4e25547b21bc5d25e09aefc978e98a5af91dd5a748431d774b0a1d38423d271da3a9e1731f858cfbb6286c152241a667b723024f135d2a9436a035c5633b420f38175f6ecffe8ad869a56c14c78f89712fd35c5357f71bfbdac3104642b5a62f134e7fc8e9f047dd925b4d0e9a709172ca6cd3c344dccf0b5d17f7f882e2b5c81c570bf855cda92d1d97bfe2f103ee264332660fa57807a58f9ab6530c7b6b984bbc3a7daacce621642513e85f37dbcd421e6adf5ae764b9b64c2fdc47187192c68f16f615ca7edf987d117739dc7920de9d2b7f917034b37444f488161133bcb609a6b586cb32d41817cb502f42c96ef625ef6ba7045cb4c8d1c10f8cee86805e63056848534e04b01889d5e7614c1c1d87f9194044906db2bbbcc96d88cbcac930bb02a56de121a107b51eb67c86d66db7b59879ed79faf887449a34573f4bd38525acd4a355852e0e6328aeff41343a7bd285a9515cccf7d27636e3a0f0e755eee1bf5d4c8a716e9212a7d36bd7250d6255d7868f75ceb2510d8a36a14d2abf7abc0bcf2e33585cc2bff3784b890f78fea584dbd84d886ceb93d8a1cf6829147f22daa19d85d5a006e01753f484a99461619a567f1729f286b51e8d3d4205be768d22ca07375905853e5cb8c5a4b3532625f0bb4a1563df02ad233fe0f1e3e88a791ec4e0c07e1d621a9f052c963aa6dde02df6722649340088c26c83ebeb53c49473d0822443767526aa422afce8852fac6080dd90ed81b0290d3f1d8b8e141ac258c26dc469736855636f63e0f251fa4184678bb039ce0aaf5247a5aec47d93d17344b0d701a1168df0926e7551c847111ea00f37ec79d0ab674b5c01a2762198df803b0998561ff956a8114ddeac273b53c808c5774c632e26a1344608e71cd720d901db9334eb6e36e4c27773d9cd0a40de072cf3bd71afef9b1bff0d01737a8dab3ef9dc8cfc89956dd50e5eea663b7e266ff042b22ce2add235ea5628469ad7b50eb988cf020d80fddf977df93f1031f74994cdb4d88c3310197406d0fc1379e3b91421596465040bd500e275b5ef1f77b4bb105afc2c4684e0c6d6abf6227f48e8057c184bf7313933141581e95489902f6f0ea86c643d9ba018febc98694093300f851d8ff52817f69c805c1fe3535bd9ddbbfc400e3c217543950a5c3bc99838e114fd55ea9200b228bac4e9d20d87c15564f00d143d1e00a45954053da15242bfdef7ca2cd69ff60fea8896ff9a4616d6ae84d9408ab8733a87a5e3d642e6bc92e16ef57243a359e83c51d5adf6cf5f51636c9fa8ecac699b2ce78669db8ebe04f43f38bb53adfece5ef666251bd4795bd689716086815ef76c0d8d228343c097efdd4632555de08c69e98e2f91738776ef88d203adf3552b503fd4381385f9f7e7340bc8381da712fb952709199bf570b45069903c77dcb608526e8882724dd1a459affae4d999a1267be00a1f2042ddd899a028be5331860f9b39d001ff509e243d9e636346ad4189c4fd9351d06d4ba128c1c4e91df7f96fd71859cd07c8d378927d0d1040a31184a141722cf8e96d72cadbec660c178944a7106cc3a1b97c824c741f33d137503c1e55575d538db5032717969c7fdcf89d5faa692fe9016f1c7b7477185a06ec6ed03a660b36ec115825628b22f8621fe895c04e36d6f97fb523295d70a2eb1ec2a1c5f8ec2fe9dcad70094b63b890b05bcd173407f092dc8373f25c1420ccde3bc5084c70d5eaf2b2b1995745e4cfec75fa6b882fd09c31e5d36e2a57056efa4d475bc18f007891f83337fd5a9cf262daefb57e56d830562622265b29067fcc42e64867fc71501cfad996841e60f10244b41ee01622fbdbc5615050b9be2b08b4fd7e4f6c06227f720a8d02c410595ffe8cc4aed707f022ecf917284a8d3e871c50cef30328f69c5c526138b14298070215994634fef1cc2213713e90bcda24767b84172513f066652b9074f34a0499a6cd0365769c1a3ff5fa10b3380c970adead64306c51cbfc2d4c44c8c6f2776028b49f11718466c3861e40cfc49a1860067629f36d52fcf1cb222958c8c65269a947067662bf24082adf5d0f3fd9d34938be4e22e1ecb8453df2dfdd0f81c3c52ef28270c1b08feada6f9ec6ddc177b2f24b515021dd74df595bcc35a7aa154bf6e770161d2969a54bee6c3dca42d7cc444372da1542581e840c4c729259e51fb6e753fea441b6c4197cc6d4d57d3b491d68e8e4ad2a8f4d10f99b930a28695aa80c109982d1540289cca45f7267699ac0ccdf594598d370b185a117ac3afa9764d9525b550d12dc6f2143d41137b21f1ed0b31fc430d934ea2a938fdd60ee85c742645f24c6770e3448b59e7344b6a561afc7a76fc1a2efa8da16fd3601b9a6843fc83990156f6746e81836fda5fadef4c52eb54da10792a8e6048592d0b5f7cabe31963ef48b4f0c68b0c4b6a729de7030fc0596904f1b0e25419a225f407768e8253a989fd4306fd71001408f80beb6d3e7bc30755cf9ed10f0a515cb8dac5d4a0939ae50fd5e7fbf71e0fff878bc88e040a46f7c47439f9dc6e9e8430572da2d4efebdbcb59a7df4473e9c6015a84b742c519a8b5b9933a58135dab4d0feea5f0efa413d57737b3dba0de981dfdf23aa51e08db8aa24a7d68ad2caa1283134045f444ce97473271c76572c90aff2b4f10d006149818047cf2a900ef0ef34a6406e1bb9f5e438040a6c27e2ec197c2357c8cec32e231abb48b20407994403688940c4b8d6a0f8470ad695d24aa00c083992857a00d5889d73265894a0307bbc546ba01bf17feb60e2dcf4123a721da5d59f5a47e0d08d949d19d20c5ac7d694b6417916501c89fb0518b0c5ab0be8b3d8f60f15eaadb2a65511273255853cce06e7616db6dc48e79c06e63492d5243690d52ec79a66a0f1ac65d5ea2737b324c0a8a1c72a12768e406d54f8fb5419387a270c6627bab9f3f1cb00774e639333d696ebf6666699a574a283270d17d05d68c8e2eca900eb5e72a7d0e6dbb5a7b23d4c2e99ed7808131b5b04cfa281fc0d38cc5677e55fa3eac13ba2b325f887698d59029138dd3afcec9f950c6578e573973e04e6302a33c7a0a0d10544ea43d5f7eb5b5badbeaf63d4fc2d636e19aecc54ec6a12048226a878b66ff7e35c114c438c0423982df94ada9f80506e3aafa4f90eee5220030d15b746d0ab45b37ed63bda7c0e7241a84a46d79a6c5bbffac788e9119845b83364aabd5e2c1fbb8909f23ffa56001db509ffa3ca57da35c7ccb14d1ad21f89c1735a016407d60518c5b6bbce4e79dadd126ae0f883d80723f9e2e8ccd75990b80529c04ff568059b527b5c82cbb2c14851e7b252464cde9531eddd886ba096c8a904b516ea01f06f80e682234a1071722cffcff7dfafefaa73b2431b31e88271bb7cb93a596e48470ef32d4bfa7486d904fdd7babd89e1756b850ba6318c68f05ef45c6b92ceb47833f2f81950a19ff39c0f1042be5a442ba6fdb738580713b0058618b4685e081a32c8208eed57d50fd0bf271d721eb5a0bec1e753066be82714a0b93aecbb729d0df8ea368741ebec11781c067a6d48821822b370186b2e1e6c20e7b2c4b0e55e7d6e1211a3fd6fa81adfd3a7fd114cee79fd75c7aea2dd2e2aa87632840b2c75d13a4631a87d73c7fed14ebc9f4f604d22c1408ff7d27504fe68e4d0e8860daff1b9cfcecb29a425a63e004b454deceaf5f6e94b49fc775400f1ae021c6b582774c18d280c7cf6732e455798c1f719a3c42e6adf011716a38deb6ca293a57a1d4a51f9412851db92d054f22edb91dfd62e6b52be3a64f92521238d6393565a46cf0fac72f38a3cdc2b60a6ebb3eff89b1b5db544941b46cf64d68ff555c8653cb86ba6753b3e3e87bfcf62aa140be722bc452cec56fc8647d8b01edc7071ba5a04aeb598a2eb5067dc4c375cc81f553a11d586f9bed470db9916d6431708ef4f3f162549b0d8192f36159f20235cad552e822d6f27fb9ca14b1bab94dee7cf81be67aaf913eff0e512b7904afe179466adf109bd74bc0c105251b91557f050b13ed4185b69292a9131b03298da5dfeffdd8be5dda7f65f838d0b6fec298c8c445dfe6421afffc3ab88207974af4deac3c9805243cbe41a85cecba93f8ab6d2ee0a7cf30b091fc739fb7850d190a7289a0c297207f87b159a0561d55400fc6de42bc18db19b0673d45d1fde93d6ad557011883186c0c99f01439e51a213fea6958e784b5d7a89b74a64910c758a38425b9b9e6891c32665313b825909ce7c5cc3498b061edb562b8da00b0d94e3112051023c63848087e41cb9e9d5ef30e6dc1c772c730e92c36a00fb5a76f3184113b3aa680459b4e4ecb6575644e27144f46c93e9c2bb359428dd05fac819963db353defac9ba605f6506ebdadf953895a60f23cf55c2ada02c20c16f4887385383602b23aa16a6b75940d19b404bbd5a2058905cc34b70dadc14519a119bbcabd533f47de6f4756944966a96aac379460aa55231692cbbbba35606d037561a4769f19962d01dd2de5ff4b17dfbc4a04cb20ec7e3ebcb0d8326e0d77e9bfb3ec0b17dec52dc2de60b47c1ec360e0162ddfc82018b50962a7a7efb97cc038347646b2ef453c6af4a9d3b7c9e0df8a5d9018dafeafae65d8b6022d0400ea512bb80f3a3dff9dbddd909c792d289fffd196ffcc3fdc3ed4597e182b1cacc9eeb6de434545066cbdb5fcfdf0b28205170da8032a104199b5451e6a65ea15c6898e681531dd096741dc3546f6fcac4cce11c429574065544d085c2bbc02807993f386b6060ee0b56caafba312fed026f524ceadfc55490d8f41160fb4ed3d702359b320c0ca62944a833e344a8d24079ade725b853b3ac979023504cda981810cfcd6b230540da59783ee0cd4cdd773c16b1aa68f52bccf825fc6bf701c73b73522efe067ae4762dfbaf4b6823c6cd7d522a9b84b597283cfe5ba748c42c1cf9227d8a28d37be1843c54e91e2a7fc5cbce2f689a1b79a4d88898f8afd619ee6883752eee43233b12570db76eb9fb8791bee3ff20c7b5e77fde9c64bd8e8c3146850cf0bb81d74f72ac26303a866811da35388113158a891cc2ed6746a5581aa163ba9c736031e37b54bfb6ff00b424e50102554109567aa16b814cb4ee905800c820287c1512bb241da79cb4f5eb276579a83746181a071f6215b3bcdc90cd057e17fb06e43e19d92ed01df4101d43306b60b4aabaf073e4d10a7844c0d47ccaa06b30fd437488921521de8d354da6d2af9ff5873e4ab190cdc9445e4d629b5bd56d866a7d292256d51804be07f35c336a2a53910aeb12ee3ca68221e00d3909a87a0cf76a55d4140d9c5701eaeb7d05c2475610268207ad0d674f56db3eb62d8e89d800655150174b8a4cf6c747124dc15c9798e5ba0dd62a04e8e67b82f7c950dbf8af6aa9197382704a911aff2e458ab934fd7fda4a5620dc02185e972c93cb2b8a8a8317fdef0a9e7ee03f1babaca7760a941114f43c96ea71bc00f532a6dd63fb497aa8a4421c63eac8ca722f636a27cbbf94ac3a81f000ceb3b97864acd43c2f07fcd2b55c30507b2ef1481f6387c33b5902175de5b8baca2be6f900af631c26ae1c93ad9404691d337188555b4aaf9a70820e53ee9caf1b2f284f62908287bc1abdb7d55357006326a6177890a79642b0a270e94cd629d65e0a1eed0e8d340e901c3d720bdc3a28f01a1876e26db30e0d0323111c7f8b0bfdda65e88a6da16b9af2938582a1a16e9f8eb054a01a50ecf05b2dc5a7619aa6249d865974dfa1f2c69c5524029eb3a05ff382b2573c30077485397975a9e6bfa649a4a8072b7ec42349991b30328d330c6e111aac471c664210ca01ca57db6ceb3b01d9c3196140459b42f70df7bd24d1bac7a753c014e3a407df854e157e11b833c19e613ab7e7da017e16c1ac9bb1df67236ab56c013f48504c3b2dd19931384cc055fddbe83351d074af7da1119538b4332be2ba8406ac94c7cbb2c7e98cb68f08265d17f94244c0dd88c957bc58cecd1313bc1e0f1e3b2361381f1b58920d6618890860db7a321c8724c41d826facc5c56f9705b41d3efda5fbe0f7ca3bdb93099250e495136d2f8211b88202684749f86f3d26820c6c7b0c367a1ca3dbfb31f80986b1c3389b4872593d31a84e6a25b131091974764e01452fb5270637e41bfcc5aaba6632e164e68a2811ec5d17f6b94cd79128a9512b3f2f7dff1f18132dc540b36f1f2ce798daff58ef873e1209e6e2ff9821f26101241e8f47ba58c52875d6ca85dcbd1b72238b540bc0a9c4c41ff33868aa0822c70a8870b08cb5d80914ef160a3378da4c388d1a7335363806bbaf1b0e9cd689327dddfdb327b894b091457748d3dc30e605d63abb2ab27606473b94801791e3d9d0692782546ec582337c490fe09943d3e99e46371c1f788810f32b94acdda5936304a585b3d8ebe64092d1b8f6249989785cf13c6ea70bbd94eba8f281e38bd796c424dbda62fd2f9801690e16b6ccd9b3ff9ae9897b245294ccb71f25effbe4f0256d3f514e532794e792e0fcd5b017a4a02e68b86b0d22a169a1d42b7e20da054ba4f8c4d65fb330f729231de9a258a44895c2f926e4b9b4d16befbb2ff1ae9147cafebbe32523788f504bdc1f95b9f0a5e87423867d9e2e3ee6a44211021d46db7cececa656ddf6338ea0c77719217f192881d7cec3f3a26eef04cf2b1937900bb38f79f45bc95777bbc11636232d8e198a9330be3ec4b4677afd2342b98a22d6285279b49b2f6372f259f84fc38536f3900a4d63351744894b4ae9825da6ef650e1dbde149230482f64abc1250aa1c51c4c304db7323de36c3e6a78de0a5fa496246ecefb657edd048221be03d15baec12e72e34a1727947a66acd961c35368361717ecf9177ea0f15bf4eeb7c60aa1a5baf6e1b4a2445842cc3f8b2078b62df2424e59ac2773075a749661cf085119f8a0d997c8ba1efd3b84aa090b4aeddc42c730500d295c1462e993c7c63b338402843a307e16b2409a6b4bab98505dcd4e53ce1b339ae071f938aacf44853dd9b66c17d5a85e81baead308543ee1e8a1b64badc316b1a0b250d36b5a8c992c45379fda70f3dac5382b687f470b91640b2aebc55cd681f9f24df4b9da3303a61fdb1fbfb1efb93f38193c6d08b48d0946a2a7190202d08b7f65eb7fdd1567da5541540bec7314a250e10a1b2d4b476cccb05764acd82858c857392f532b8eb1de95a82c9df013709342ece1a1371c210791ac5b45b70e0c3f0cd0ba6048e413dc458b593450e32c63edce10ac9ef21ad1b4dc825c1510c4aa3278bea3e8bf7b9893dc9fcdeb4a510b65679f608db85940bad7071b7f83bfcb61d08b211e05b255e8b022ee90812189a69873934cf8e94f469cfc7a7488d51132ab8ae55d90bff0d5f9370ea6dd847c4f2d4d54c8fb6825004dbc32d869a056e9cf3cf3d1e0967579520e3eac734eb2621576dd5ab1ceb9fbaedcb225468fd3df2b473abc7578dcc33786773c1da1ebfe2d2108018ae2f93d957f72016bd2fa30eb64c9b3b9df3046edb284a9e86523040beca619afbfa1fe873c786c0f4d1afbc71928f58fbd1bd3ee2f1ee929a5181c64fc24a351d58b5567b4cfbf0228ec373f0a15834f66191bb7ec622ba406f58ae6ce5637e79d7bc83c632350845dcb8fa14241ea1988f0c41ac20ed17d3ab20e5b721737417532e98891c164717f0ffa66b1f8473f8bb8a6d5d2933cf26b46420f794acdd8e904e22fa4cdb530d8c43be850c85ec143b21c3a6faa21bd41078a8e509e9fa09fc48d5747f37652790bc6f29b60adc9f0faebe7ccc21a69670c58023355c4da98852a2f9ed027db7ca2012bc6021ca6b6fea003423405a3c3330803e7f0debfdd0e7a568ea4e9ae51e930dda296f42ff213df04fd1a5420e567125d4f27dbe5adfc67f4e8544f78a1fc3c78507e5292bb970d1be158484d394607000656bcb5f27a830ff7cc4fdce386ab7ad67147cbc66fd57d56a909c3e850a4adbe8192bd1567310673579364780f5d7da7a17dd2ad247b35580961ee44d288d14f72c84167204f455490aa47a39f955b56be55068365f87bf1307b3fab238801fb59ca41283ad2c16f85ced17dec48590f925ee84396ce2ad70ac400381ca959ff1f4129840a932daab92112788bff75cbcf97abe50844bc4166fbe97b7922617b5dd81a91b9c0a8f46823cb168a75b5eb9aaac37e6260fc40fa3afaefaa5bce19e43d1575e4a0f9d332a29f123aab1a590182d7dc1c5624de05d4508acee1bf9ee36d6a33f3385f347f4a885be7b31e0d4a6bc8249a1641eb43f1c1e6994a2ea3b16eebdec04acde26a27d6aa9d7d0339968e7c8721729d85537e38118519fae8a41c965b23c0b7f5c65a38ef79dbef49cd8f975dc7f87759560ecbcc4026540d90a142e953e571f25927fffde1891b22e3c07c1861cf1f37759230586b499a8f4fe2fa31f5645eedf1841ba6527a492c42d6484b25b7e0c2dc4bea2a70e13459c34274e33def0535ff417a851539ee782ac5db3621073d814cb7acaadf1834c73bb36801f802b4b96acbfa4c5004fe59d2bd32a24576cda0f33b41fdce3ab5eeac4c47c8419b501e22c94532c1899f50743a4adb682ceced311479af705b43f718e08946112c486232f6de6ec16569d1da3ed57174bf973035b52fd4d780b3262a732c1001c35faedf21a1d691354bc3662ee43d9453e5d393070d32b7c62b9f14e0ffb845a6d0e1eb2618d2e1b91d20c36d601620d4c64fff067b9c54891e30824e5f77c1944e8eee66d624d69e5465d667c326a9a8ba9a2a3919ca3bcf9afa0d70300337a9a109c3b77e52e07420b161cb735f8a55dc7c695ac5cb8a2bcea0365560c74f8160b10e879693db13a131f9cb6094a16b4076ba397c4bdcbc011189a6dd73dc7e9483a42ddea5ac11a7b3c0aa9655150eba55a3ba56aba086b51585b9037283c6b65955417cc8a6b514fbce1da452ed2aa0a83fc019c85ce05de6900191589ed772623ad73283a92fbb9b07299c89dca21d452b6537a695a55b286fdfa2e37eb4dda913c7cdc96d8042659533c9707a72ddf0bdd652722739402817887bb96cd8ea77fedf9da12e51aeb58e837b41002d4b7f563ae1f07f355dca70179e36cc41e55f0fde64a823708ae088a69694d4cb5db5f756a26f21b99cd56fa04ed050dde746f06162869244a8605d766074d590e3b5d350f06b68d731be29532bd24979080d78aac31c207fe53614a9e74cb36e5f8b2e5a41bbfbe0783004c77a0a649e1ccdab450f1544688da6ddb016d10a819c2793158997924ecef636c34c36427c29f0648423a59aa0ba9860594c1629f69a5039731c898fda902e17f5ce62e541b56a84c6917cacf72cc67a137ff34927c58ff84b6c8584c68141b6d3fd3a7ab403ecbdd08dc1ca63d9ddb8c2de8e7a9fb6f625140dd123707110a326227ccbc7842bfd5aa9ed027fc155a2ef8da030a6386b3312270f548eefc6c88eb20f5c46663795dd9631dbfe45575d5fa9035af6546b47d679b02036cc01881feaaf032c5b23241b675b41801d8b37be5a8961849b9f56c79e0bda89d700f529926fa3eab15f7351ab8d67a5fae2f6a71630667ced0ad0f9d5a754ef5ec8045c8dc438aefe8c0795557b2db4a93ae0b410281acd793a37b0d66697e15c1ad2f244d537a554bf36d53e160aa8ee9a77eb2053a3ea6ef5d435bcaa77ea8c29e9a373862d17038b3f41b7e342cee7b9e180ce21ee0dbd5838e7e989153353138d77d4903631410ffb91777db7f5b9bebd5d66aec6594aae2ef16fbadf63cd0ed9af01dc57b02ed7f489ab03d5e2eba8caf5d04d511840dce48355be0da1c8c5f65caeb8149a6acb1b59b50a4d8903868729d148e8d4274d7e91cb16b59e82ab10c8c3d714f4f54926c3ac55eb97b72d4ba78b72815187fcebef017dbeeed57b062df85b7df8f28348760806fea24f8c1600b6e5c9ad7e17e32cff29d42cfcaec2457f856ab7f30cd1ae01d321914ab0733a8921566407954b9fba629c0448a6ccf3187fa62750b70c07d89db7702be336f1001b33360acc7a05f2cc374a4f70ad15ff34c52ded921bb5599e5b86ebbb1e41b3117c465946caabcd25666fd1d7edf75c0706e2ab513775f8c8a238c49eb3b0e9c6ae3aba42f60094b7c7cc8ec07834d272dd997f7f44183bab7f6f5178e20479b7216729750a18ebf5677e9a1319e0b0a1c22d9fe55adc259ffaaba8f34f3b131e006b8ffbf47e82d244a6804293a9139147953c8171e7b0be689c35ff633e54ac95e6719ea7ea5cfeaad03f31c63a8dfbe06578c1abc8569ce1f9a00d1ef61d165e0d3e3b347a0ce03d44f4335074d86ad6e6a40f692d9415a01dc76a88ebc9030d41118f33be2ac3146de9345858c0d06ae288f2a7b7ac75eef79d35c84d1a3fd42b5cb7faf16a2a9eab9dcb33059ab867ac513bca348e091af38ee6ed54de90dcac28c86168038b5f599e713240bda2c40402984ace1410fd9c8d4e8fc31570865c574290a98f5768761ed68258807aae184709bfa986db86fa690129e9305a74e884df6c5cd5b45bfdbcca3aa3dea13b9b8e982e1805d21044a969a370889cced618bb32ca38ee18efeab32246355104e21a51ade50290b3206c8cb419c844ea497bff09863dc0adb8f5c3a025dec5e51ea3eec5f3ab824a5955cf590db9a875f9dbb52e735b634d8cfe5f28615474c354f346a0bbc22ab5dae87da94742ea3e7bd28a3aa8f7b0cb9cba91401092aa77b608d3518b2b04a7f1e93e065be6ae931a0e7a6eceb93ea78e57788bfb59d3b2b45ddb286a513fd0a48103ce416d08dd331f771526473435079441ca0a060e40f393b4b3fe77e16b8d6bc1c94b0800756e852bc0ddffa73e8c897dfd3c332ba21c507aed811da3d0be39ff6597a0fe50135a74eddcb7c4f68c863cb1837e4a208af34d561e0d84a7a45fe854b961d0fb1492db9862ac80f5ee5eccac19583283524049dc578b0b8284daec6181e1d4b308b1500584e5ec0504563a1de8fc00ef25a685101547a2aff6ab62886ab5811f4fb00e2005dffd74a21dfbb8debd16188c701514c472d12ca0a93d5e1f575d02cbb6520077f997465f797a2527d4c6dd28f1d1e98419c45d76b78f2af5df5ed4ba5de31127e4f1056f075a72f716d77e2a8d3201b1dacb59d22a61ece1ffd3e3d8e1b87e08fc7890b850fadf1334853acd03b1feb2f824fbc771c050494fee381c7542730b597b5eca41af19d4f9b43c22cee22cb27ed6ae5e0606f772ff849918b7de30b08a57bf21a1b89dcaf66c999507d032610e45d5094d913e842a98144744ccfaca195bcf61b96f9a5b751ca651d0a4af77e835c3e09e0efaf6665efda482573842bfe235b0ea00437d914d93277f0d76c0c97a5fed00b014560b27cbaf94e8e2b343d8869d771c9baaa7963a4f769ec11ae617228b5fedf936d75b7fb9cfda1fd0228a066cddcfde670fef4749f7f3b5ca0133893db5839bb2f69c9cc42d0d9854259c05e179f466ca8f15d9ac52a0401c5d4dbfd1606268457b7af377bdef8524079ed339e267ae1a65478999821828a6fa57108ca3a780a382a55b0558c3136e3bd3fe451731eed7e855d713aab78e9ebec43e6310ea79c7a10ccd187c86d35e9deb96c5adb4826783d21840e3c36048b3f2f96ccef819d125ab0ea24d9807d0535f1c855753cfa7def4a2863a8be3d3d40cac6055abf27b738bdfdba734f729ddb8f894429c05ee3efe25bd1d030a8d5a8e78e0edabb5d667b9d2c5331727cf167c6d5058747388a59844f0157ca85c4730251dfe464324010691bf767e287b21337a01133f1230cfbbac12d43bb40967f3775306b13e6e4fd7097b8694287d46f1a8671fa20cf33d51665f89de15cd6b8d4362574c690ba57187839447c95f69f5120e51e4d95efb0760bfd2c4c8991e1a4a8c0b79d1d614ca444c928a56675ecdaa31aa90931451a4ea464984691d322041bd05ebc8635900f4447809e503a112068034374f2dd364e16a95b85ce610786446efa473d9a0e350be60208cce974a09bb991a6406227c92711c01c1106ceec16c7ef1b218d0285bfb34af34d7b8253083eecc5360a820daa4237e441f071fc464fefd4b27edb0f480ef192ae587fa99a805045574ad5a0dc5149808549b6bb7d73852040dce7cbf0ed5f0721bbdc5824f56bf3875bd756c258d104e1f36f94b1364aa26a2e49ce0a11c1fb9d5e8dcb886abe4f0f9d1f27c0716ed71b1342b3348a599e422f56858ed5a87093683a82fe03022a95e4aad209fcd48eb1059091fa0744853cd044e69ba6c29f460e9f4d8af0a10b7fafb4f5c9c70aaae6f688925618bbc27d09cad29bbd93c37dcf6a3c9ceb309efdd0dd21e25a83645fbbfb2b87a7e93407e31264f89f6af4ed3e4022f4640961cf9d098b56fcb129cf4971dc3b9b8fc70eccca2ef332252979afac760e20af6cf26c6d09b54b42290f17ff4a9eec01dab5aa5d463b5c55573b9c7290ee33b953cc781fe99c81154fbe121e5e66f1750d326827c263ea3a9681e5dc0256d2a52975d400fece0314c8335a32e59980537ba80cf416b433dd6b9df0314bebb17446d0646c629235c5c6393d1b0d157094a1cee84bb1aa393074dbe4f16852fbae8a09db910af7a3bd2adccfeaf013d98587c51c78e96653539b62d4c636398491758c1746ff273716d7e0d78e63aea748bf9a48237a589d9baffe2fb64244480a4014e341c969d8fe6077cff35c998149cea5bd1706c6cfc2de6531ad1aa84ecddc68ae1c37360b95ce355293b8295b9c804f72c761f3b57ef2471fc2e183e90d14afdc70c9ef4e98e0b46643596e995263606c3867f45daee83114e74e50c3149d69fc933c0ed990789aa0b71f54b1c5a01a8afca063e29f4152054595a21e101d395a491ee8c6d9bf1d91eae4913a09d90910ac0513b10b0fc6513e17f96584c7d9cfa6bc86ab1ed366df18e1b4abc30d0efe08f1d3680096bf9b376ff81c43d04dd4cc802601329b3b26b435d2ec04c12fe278c66d20979941b91ab1ac55ace047b55014c0ede4ee29d0d99086c2821556f4a91179d56cd5ec1feaf0054a9fc0ce0af4ec6c917f156a639d91629985b13542d569483751a3cc134e22d614e84dd2049aab3ec31297a79acfdd5b2e77fc3b287baccee5157fcdaa1a2cdd6614f9db583b6abd06e90d50885a23489e7a9857472fefc7a5c475352a3aa08ad5d2d18845d8f0cb2f8859f2d758f0f67af6116888b3c5ade1e2ee78ced3e5f0bfe25940940b99e7bf1e45fb87f843462f3fbb7dfd8eda26c8af81b4b4ac7160a2e7f887edaef3a81912b5cd859c81e11946c72f6ffd0168437131f03a5340e714066e67f66b2ab2f55ed676e84fb27ba9428905ced0a5f7a119ace3a840a9c9af0d903e399ca912505c12cc4f3e6cdaba7e11bbb3135b4b7e36677fd6859830084d8c4b0e74ccd02d03157c021dfd255ff3537e405e3f1d0fe836c2f1cb4deebb392cc02e6d4c05c2dd910d0ffd18e42f674647bf1440f5166266f5d52be6fd9539fc52d487b82459e73b5e0ca251216d76c69e0fb4c4019e9b4a501ccb53158a967955c81eeece059a5b0207fc28eda87de2470627f8af7185a818b9893a24c81f3920a25e196d668589492cc434bde85ba8926c5fcb23c57f3d301937d59731a0a3d2008c28a5324098b2bbd263c0f9a1074fdabe4a85121b72a74d0b1314385c757be1a86b50537998f3efb14999ab9c69afd4fad3badc61eed9499025a69283ac0bb55bdea481d09ad2569bde73c6f6927e76035ee3a7f80c49cde86b0cff1bdd4cd575391b271755e2eb54e6191c58bfec1961029f178aa74497bfdb42aa6e59bc16d58c95073ac95842b62b46fdcbc309d9ee4b424dcaa48bb17c5dc6240e5b6a2ef2c3dba724a79f4ef1490a8797fad94073897f428eb08cc76b86a6bfd465a694e3d7c33fd9efd540e9c72d2ca80743774e246d1c8d47e55be6853f5ae0029283a522f46f93fdac991513ff38b7471c802023738a479ebd9d38e638da04d557dfa8cd4573f8a3b2a13c19e6baf482e8d9bd0885a58cfbe4dc53c107ac456ecd7a087b3bea4276d52a1479441a00505c66377d6fe693682738494b3af989a84b6252287b2d78fccb585b410c90d849cfe568103712239c1704148bbda4b342fe07a46d7b0cec8046a04fa23ff468c009ca41c4565a93b432fe50b46ac56cfc0f4e1840c4894bd3357726ca7c36ac2625d48104b707e126dbac7bd7b49f8958d6af26797c3037fa6c6cc0346872f0c4ee63a8c76faf67cc06f3dc6800e99bd53c3bd80ab522e700c78b0b1e052220427042ab99e8d5920d0ba4a0789afab4ff41b19c0d004ede52fd750e36730b063c54713c06f4eefc3c7a3c396b6910303b55651867664b102a26208e9c012ec964a317dce1fb2c3685af643016533fbd608ac93ef43cd92bd09917b4b99524a018508f708df0842b10b283f09d80a7026ca1f6dd7c69db8c65251523dd29d47d943e3f628b548130a0df5cead0d2e413be2a33efa78247feaf4d5d928234d182baf073e507e2ab859430d7270a60d30747f770d48adeed3292b7b2c958783e3717b685c822653efb304b304b46ecfc9ee45001ea15f7a3cf855de4a51a5b75bca745945c0e3f13649f070910081b74942ebdcd3517785c242d5b059ceb033d592b5e373a64d15b43f643dff7cff1d9fa3faf8fd9ccaebaaeac358551feb78a3c171c1eb5ab8c9056b7596719c4179d75f1d44acf1679051bebfa68b4625dbcfa06d9a8cf125ef96338ceabe6bc7866dba76f917bb5ddd7c0119be7f9bbe84a9fd1d83c12a5f408698c43bcaca2085294354c608856d9763d1b58ed569669943c1e3510f87358ba2acedb185862e1e8623619eb03d98ba6a079d9373b04b3d974a3df34c116997b7b0b33b3fb118f34ef348275baf7cd8fc77cd196936b2f97d2e6a215ca8aed9a51b165073dd125ae01170707890e3f77fb6c7bcf1011097c054780447e22fdf3175d571aa70659bc756783539292635cfd6b8eb8a2fbd6e5df1d928321fc95a167fd398411d2ca9e5c0f11894443c90e190ede01c600237bcdf17ff8d07848448112335ad5a0384f11013edece710a09d1b1e37b5028e54dfd1ce06a3da72ac05b46b57b833f0c6e37df1db78abfdca95c7a0f6d5782ceacfab292f060d77e640abd6f6c531891e69da9176a41db5f66d47234790340fcfded2d89c9ae5ff3411ef91cfdf4d3be397489123acfa987635d4eab837f9cb27106b37d55022c94f2bf2973b41c39648d59be7a979f871b035a1fdcdbd65993bc0cbeadf1851485299b9b977c025008c9ab8b32c97eff29392bf5ddccccc1f9ddbdca4ca42757021703b46f624c68b538cc98a12121528474c1475868c19d4986804b7bbbbbbbbbbbb628290e0b3b31d37f1c8e9b0c8fa1387002f16e06aea6e29a39400309c6c3163e8b5acf164c46dddc8ed07caa072c3531151173750bac1e886a4309cfaece8b19391b9eba279970b2e0422caef33b2affb141b63d4589aa67dfbde55dfe2b66d31fa5744f66ee8d2dd37c61853bdec3451882863163251926127d34f9ca5b9dcd98948501c1276b056aecb65f4d9f136668ccdae038e893613edba4f868cc2704c945f3291f74800d8907af94154bf3d173fa005536c50f9db0f69514aed555f90f6b5e2fbf8cb83e4d78adf0882c8d7be2097bf3c09b87d12d027f555e9d00534e587bf9ab08419d22e873242640bf59fc925987224c3ca4e8c3136e9581500329a54f9a908c61893d0004510485f286d6962058c47c42f0c1369ac18c71655fe54c30555fe46b184991a0863c450e5cbb83748428818638cd10331c610c3a5c6d805e7504950e26a982c66d5c8a096a48005944c8c998c0d1d8ec814dd1023f38215349119a2c80260c82cc124ca0c2616706a22c3e5862f51646650a444068c1b88c898b1c102543c8911030e16f87284130401c058c2e40585872c4ba0b858da07644e4d929a8c692f64311b906c20c306a2346cf0c42436864912d4f2482d6a1e5f933146c9bc05b7756577a4fa737b715d712291cc51b8fd40184e2b706202bba1090c3064326a46d54c8ddf0bdb997aa46b0b488e7aa3c62f4c81f6c9ad9bf632ba103f5617e2e344fab1564434aca9fd610df46de07098a1494abb3f5a23bd758de1f60363c42c812d61d2637ca006514a9c94c8606d300e1cd0fd30d6b8ad4292daea1a6afc3589732fa979ae72724137c62825ff7e2dff50a0a9fd6d6533a4fc5ce88f31da3e8a7493730e628c51070be87ed27d77e516a594a1ac45bad8b030ae0eebf8816effec662835d3b959fb26d77df9752791dc5a382b92b342a3b78203da68a38d36826ccce58713638c5e39d2a7f281c7f766f6707804fed87275687751ca9e1da3267bf8a0b6ab1177706298b56be3152e80baa9fe3c9a67f7a34ea8bbbb7bb84cd9ddd7290046d058c3ae76cbfc3a64386e1fb79f31ca9f3f5b93114afafaf3c7285beef4246ec2f776c13f8747e09f3bf6c5dfa4b5bb7ffb87ee66f160f6ff68bbda8b3c61a41b54ddbbe3ae9432eeee8e4be3393f8489839cda6fcf693cc250ff9652fe87c03b48000c60445c84616262064668a0c90e34389343163b98e2454049f913ef24452bd0e287a41df84003154f8a4fc2d6eeee6167ecd27425873262ae8851014622ea01c64c51c516269808a20897c1961a30c1c1f184aaa0faf7f6e8da3121ae80820c8c95b07240f96ba5c0fe49aa2bb50bb4c0a28595ca7f02901061988490c2534480a2fddaf342c5ff218292b0bf886b5f0b3d2415db2e4998a95df73739b93a21fef869178ba084b6526817be166bc7c7441ab573e4b7eb5d3cdac5eb84a5490dd74989863e4d34b9be38e38aeedeb5cb9d992977c739a7cfe9cfc349a1daefcae572bc82c0bfc06da852deceeaf84f6efa967aeee9b19e3f8efbfdb39eb5e38fb48b3ea1fee1ec7cf8330bdc49c5384e0a0dbbba404fb3a62fbcd4dd528699caaabba50c3195ab91ff020afcdafb884976482843631bd53bc6ed07bc80925153a25423538dae3dafa426b58f5a8c5fa87d2e685c94518b316ada27bf7dc12b7f8575b1e3eaede12cd5df54fe4d6a1abf4ca5bcd5e9dac57146d6b6692b5e1dde38068573c518638c316ad23deeaed4b64ddb18ddbdbbbbb5f8b1bbffa8abd32cd69ccc3fdab5b4bb37d6c6d327b46b3f046ef7a04b4d4ac571aa94a66d8cabc9d9dc944a95da1c57f456673fceb66d4bb172ea4a7777df388c7126d95dc6a86952326fdba64929b79a252dae5edd7ca6acb15dedda326874cf9152935195d32eafc6e75d1fdecdae9bbda5e3563c68341937d50a38c6892915192783855e09796215d7b9bb0fe936329b18db2aa678a4562c16a5fe43687cb058354dc494a879bc86de44d58daaae8a53a53457a9542ae7544e44cf709b23e78ef628b56d5b75504043625c6e95d3a57efce5e3a3c2ea476a05e4bda254bb9a48232202f235eeab7e56af38a75d3f9b8771dac5dbca472af08fa69641798fea5543ed045381add68243bed6146e41d94588004155debc6264a4d2a2a6b9e611082866fdf191ca63236e83c2b33585e91e0f92a4b49556ea587be94d6b2828a82abfc734cf92a9f2f90c17b54bee88d1fed83ba8e03687cb21a3b3ca3258122c06c5240595bafdf6feb1d991aa9b31b5f1a91bd05aa183a13585e6190c62908bf852bb9b53e551cee11f23cb1145c366637b18ccbe787ba8b13c1d667b3aca5f1c420c34aace9fac0fbb29ab27ef612ff6c54fa64ce577352aff93f70ccabfb065bebd87937aefaf7e1a4ff5b1886b7afe2e5bf273dcf5d3190ab5b35379d67ef29eee992b6366820fd00f7ff1bc12e3591028a076f17fd0792cf3177f121495839bbb6b9aa6757c0f716aaf2ae020c7fd148750a2822d757e3fb51857c845705445fac5ef1fab7f44188a05f70a4490534a54881a6e540b322068b850a9c631228b585d1dd4c5e26949cb512c06ab61d80a29507e2d5f30ae82b4a6b0c0f717abc0055b53b45f9065441935dc99bb76a4e7e3af2b43b5178885ba92c52e3b10b4cb818a29a104ae288b448a18d515eb68294a110c3c298a13356428bb9483931a466e77a10122f01ef91de0bf998081e1ac6bc4909e86b1a268f547c2b0a2a51f70a8fe4466ad2f701b2ea31449f9236fc87e78cff4214d3274c5d03fb8e9a57e67474b7d3796d0709b90782472d73aaa8ad66906a2eee9fad5bfaa256e8041c3598dcc663bdb59ca7be6f7e41eeeb7c7c63daad4eaf403790ff7a9f8d5dffcd2bef0c6497ee107b53fb6b7363882c4c89c4dadbdccd45c3a6132543ba85ffd48bc8784f66242ec9e552d41bbf697e3c47b4eb0affe18a692271c90ac0e0fe12f88a328d155f79777797957d3de59ba74e9d2fd71982e6cc27c0cd61ad6aee62149049dc5269a18d2344dd38e905490180263831a59a4903dc1a4c687a218c8a198e44a524a29a5c6b47d318368484a29935c79028b35a6502286882e9c698a303da8be94012545b524a7abcbb483ac0cd72df93442b04147101d0307b34359ff392e1e06604206008b1504c8328500aaa05add25a62e71dd054b4ef0a07ddd25a62975abbbc474e44d96fa0a099ce1e405982b76f8618cff2b5b0f9a51d1126954839438bb03254ee567668900a4d0ad2e130f3708a3868d8728d5290ed30e666aaa2e130f5cd490fe5cc2b7d490f500335fa0aefcb0035292ebf0af7445ffd36c41f77763661cd89318f3182d95dd573e689e7bd54b6edd66bdd77d230e272326ef3d52aa714a793bb1976d979d9aa7bf9bff7d766a9efd7ed058a27fd050da11f6b9a95decd42eae5c436eaa1c26a9dbd51ecafbd347351f3d1b7e72eeb86df536de115f7d8d27a45d71e58366cacdf7cac7ea93acec0d47357925e811627737efcb18a5bbdc26f6d23c2958d38b81daba1f3fb1d2c7499c5457c5ad8c454e9abcb84daae3525d978ace3aeac14ac7a58a624d4c36f1db091bf911151db02751b5417e2e95e4b1cacf58f8dba9297e69721813466a29ed62362ac2b1030d39eae663682855ee1b8fc911af4ffc73fbc2f9313f0d214284610cf5ad80aabe85e6514d6905b9f1fbb552d829ad203537bf5f6b63128eea9e7801f2976cc98ebbc48393ea41e51e1ba39913a3213889872d356c2a957bd7c9b35476a2863c2602aea3024ab43d36080530dcfc0d0d409ce7e728efc1f982664802a200e7614801ced3c020ce1704821fc09b1b5f1008a2802b213734006f40d615fafc9579da5c000605fb2a0e28d4c5507352eecf63a80f7ca0fba9d4f37a5b395ef5735c149ff11a66039d1f721217e73782197dcad971a620c314685a6afbfdf678ac34cf7e0c2526da5c00f6648408d582862b2352a47b3e0097a3b8547e3ed3b05dda010a6e871f87057787a356879f9f78f093cbd5319bce4983f382168c17322881422c45d1f442b4040a0c1a018b2d305088c13c394206c65640abb7d0c0cc0cecd14314483118c845efe834b16558230b224e76ee05ad0da03043060a390d4ead15be209e728319a240a1550d33d03f4619b460e6040aad5e8004fac72f8865e0a48918284473c611e8df6eabb112276494c0f616148adc38f4182bc0785a2e509834711919506902395f42c31846a0d026a31b460a18249093ee04ca4a1328d49d39e268dab08596797483153230888198c129060af90e47a076460a1033b06938228a285003a306982890eb68342d6b1c29f10ed6698b2632e712f58453ff10454313c8f96ed114451228d400323d84891a0c6a98411328b4d383981844275c684004725ad79e27110326723003b9ad6b2f686540d4c00914ea34aa84818019c0cc402e654506284ea0d00e94334dc09c56407b4108c0818c245068aba0828015283102b9ae6b0f0135d8900472abaebd03b4414311c8d174ed711618cc10052e93922e512047bbf6dc8719c8000672365d7b41ae0519658a40a1950e4f14dd74ed79d10f349881dc8daebd20f985071a66a0d03a1501469caebd78650b2d92400e47d79e63a146124720373dd0d13550e982040a31bb1358cc38710472dcb5d76a982992815b85194dc840cebbf63887299e20818cc31145c8c0a03ea3062398b604092b92402166bec107eb7bfa98dc75cf751dcd8faf7e3e7b21d8597561f5f397b43871dead9ea5303333f3b6d1d4d43c57b3d56c5b951f4b69573f8dec35e856b93528576e0d2a2b173bd51a5a975aa1a0aadbef340f8b45a993eb3ff0e19b67fbfa1989f2cf9cb88455ad41b515ffae363ea2195237b903a49582fc14f091ea4377e276f2399dbc67c1e94a1ee522384143f752bbdfbdc8afb5fd5657bf54f28e6d338d9e3ef8f0114be1595dfdacabd5b3e72b2f7e77146bd84523e0da0a838645e2d6004abfbf95be161fb5cb632967d0bf12553525ba8572636957c76a33c5ca1ed7560ae189324ddf708184adc7713268e0fa4bbed7efde1159b1a0618b69a7586d294c5868377d1dfbacd0fdb063304683e3a464667ed9d139c4bfb065a21605f8b55f41fe7e30eccbd73e18aa04d967180cf2f96b2cabe3bffef2e7dcb3820ec94f0890cd0d686a5ffeae239c5e66476a0e7ad05251430e780085b62cd0007fb4a630ac700128b45d010350bef605ad164d4e4a80429b1210a0fcb61510f2a8fc49407f7fad207f7ba92465c497d60a9f267ffbb4179a33dc40e70e166d0591d383f6092e567801063cec2fe5e73c1454fbd9cd5782d5c310ef7922eeda1e5e0b44b6ede5a1fd7aa14fd55ee09e9db5d0fc0d51a29188d742bbfaa714dba30544fbf8da47262a667599a880aa05a8cb4485953a9b87a97e5da62f522a173b5f49b949606b94c0566d86b2b216b5fed82cab06a46b7f093c1026a9fd496a7f3f0da4df05ed350f4800aafcb65d75733c32e198be38a9367599bec0bedd1853af799b53a5b7af79aa8f5e00ea265dc6df3eae50e89f807cd9d5cda95acec6af43a22e4c76256e66228d33c47df3040d5766831ab342458a07b6c7cff668ee9f2d1e83a7d82f8f45fc34ff682e445aca5ad6b226d24da4894c2dd409112832994cf603886a319b1cbac848e7b0cd3245462277195f70cf0356cbf67cfbe2af41ab600b1d587186146210000a0454f61e95dd0b5e4f29a985763191fe3eb023f87f42768c2d4d2e040d295454932225d174515c03494a9467686790ea0f6dc30119cda4ddcc8e934f4c16ee0c8b152ad508926d9a91718f4b4c14ef88f11943c61828471e738fcd8cf88b998d301bd16464239a9c363a90329ba5543355145c1a45508c60b1b2b9fcc53db7d6a28be23aee3eea280dc4aa8b7240c39d4d1ab9e7169ba3a0b151236ca53a9bcd664a9369622370699f1e4858b8a3847009fc710c438cb00c5a40b9913468d8b00ebba836a9bc89bc67f51edf699a703cde11ba8eedf3dee6711e9fe20d2e768cf8f8f8e4482aa28b895ec0eb4eaed1ced9a60eb149678a494a95834f556a23cee1a870dd8d0edd0a071a32d18a0627079a9a9b266ae80d26166a08b5c942e30e269b9b3528efcd0d336ee044a191c331e273860f0e19d0f8fc383aefe5222226f282fafbac8f07396e80918395c5647573a3abe33f844be0cf6647b8f1c54cc756417dce9821c30a13319940820924101111f9fcf08f65e5d0f16388dbe112f8a70008b0d9016b87fba6053d77543bce83c71b5de2dc51ed481c208af8949a130d37c6f270a763b2e3a345dec0a0e12209194af59f1d1f7f2d2e0e1d380e070dcabbbbdddd3631a0fc5a7c5985f24edffdb40f8165357edddd0d44eceeeed8dd317677f4c254f566efd8da1641f9e3abee8dbadb366b65709b13c68e9ddca6cdeac4df1882d4be6c44b0994046d9695b472937d9cd8a6f33048d326a51eedd44d149bbfa7520456ece2dceda1efc5df9bb591d790304d555fbea7d495509ba3d761dcbdf5d6af365949299e76b9d9c40ac470da58ddae51f1849d13185c6a32e4654b99aee612727560b8d1144598c9115437efae019c939c9830f5929c7c7c8454382e2508d2f24d620699ed6c718a353c4e98f1f7fb6d8a02def9b7e1869887ff0852c1d5f485939be90e5c117521c319c2f9c4621f59b161b34ec66ee365f386521ad29f21dde3a79cb521f51f50ffac610aec99afb2c5839ff0eff863e55b00d4766662766e06ea2061f93962dae2899a8419558a65489455665134330f183ecc9a104462e4dfeb38625a6b8e2a5ba6a36c1344e57643a7fce7905cb15236a76708ff8f30aac4625246afcd6ca47a4341011e58b0e9e58d0448728b248d1344dfb20f5a44445893035be8e958f488bf83259719f60cae149e205498c5102a96a4890a9dae758f9d05c55601113638cd183950f197657e454eda3f6338caa3d3d628caa3dcb4a1355fb474287236ea8dae358f9d05c581c01e6468c31e270d951441a463451841155fb1b2b1f1aa54bc49002eae8090dba28e150182104b793ce8ede6c971a76496324c5a0c6b759f9883963681874e5438b677471b50668da965043126a6842d59629842a59aab021832664f005112d20a28baafd5639aadad3346591a166a90a518df157ed84937c4dd3344d8bb17972545966aea6254a142f4a4a645c3465c9c2c251e4da1e4ee5892acc1237a8a416638c93a67eb99c06d490c7135a96ac3040d57ed218aaf62ced9f49d5de25c41455fb9d1554ed7d8670aadaffb0a06a4b31b8220b6e4372a2c6d7b4170c41668d1fd6b8f2e505dec5883238b9f221674e036a5c42ea414c8d1fe94e943151d4700415596600e35c9460c0006003d452e3c777aa695786543896a65099223c99da26b7edc809903094acec6003a8288c80c8949682f8c208880d8a5831a4a52c456c6abc92e84ddda52c2f4882eea8bb9445869913b3073821bb517709872527742883f67b6fef2e37af7cf65ee8caa05dc39f6550aee1772d5710e83a3dafda1534741de99e4e721e924907d89ebef9f83bdbc3e6e9872b5b2f56b387f86b6adae86071f7ae0ebf8dd749de53a45ff1e36b5ff1a39918d3a871e38259286a7cd5174bc5b88076aa317e38239176bd14347424588def48716e7c1f6a16941a9dd438654c20f0c154606b05185ab45d314aeaaa3102404643972b27d2744a8b18a4356541d6ae363eefbbfcb5fc85eb64820f945251513c8a694d4949fc1c0d1b51c16691e324ef6125fca4f247a548c44944f10b3916e78cb18bab18e5aa536ddf7393316a1a5be917d7481cda3d8d6ba7fb58feab5fb0fb9045e4323281e8a7f37ef82b16c41be22f21575443463256412d05015b828192f61a0c90ea9a517749ca957f0a43bd1899c0af02f7778c8cdcc87dce55d1eaf0774882f00f274569cc7bf84914218ae0278e19ad0e3bed60b1b4546a4e6e7ee4542b1fa9e7150af3b7d7e616a3f69af69aa63113738e07e1bef3f9e13e97efa83e745556815540a010fe9091d888a1b831565081db17d16c38aa53b62f88c1d60adbcf9f1f0cf3b7af06d97efe377bfe825b7703e12f2e0b9847c130e03d2278012606b6806cbb0aa27dad0952d54fef705610ede517d49ab2e3affe7eed7b97bf3af60fa02b50fef953d4a10b19454c45f3e733c1b468991d390c894a0f35eca893665d44651cac0b0065a2f88b37f2392a95f21ae6af281c2ccfaefc56b24df4042b4b37015086527e9ab2d509829fae18b183862573445136b6879f6417557ed8f116dbc3515c832adb68abf69325a1629d7cf7f7afe352352b1fbefdc79523f1fc6ececa3554cb5a42495977547f61cf729e15030d218a2e5964e02165e84aaee44a4a3e49d876bee7a4dd51fb926f6482f4915be891595bfd496a557dd8505256fe9c50ac1c28c74aded34ff6253f4a1155be92944e6db43a12ca09a71ad20a15c4a0ea7f3809003464074d367e8c9fe302628107e530ed35951f877754aef1fd9f66a73efc9bac3e2028eddf811ea9d1a4055328b78ceeee21cc7c0758aabbbbcbb8d345530c607bf47b7f5d506e57bb583a50ce3bd512b4e917a309f1f311e10a6522a8b7093f3eed62614157c77b806145b1c58747102933dcb66a620201fafddc0e2fa85d60031318b8c30b0a126223643cc4c02af377bc083aa040b8974254ee93d4766a9e30cda3e359bff9c66a0f7ad6b0380fa85d1bf7add607df4c1e4ebb5aad0f85ae2dae6edf5468533bb598ed7b4cf77094eddb8a53dd24b87deb03ee08168668336a9eb0a554212a109ff1c2c40994ad35bb99460d0ef7d1766d34eaf01a69fbe875d20e19286c7b96c74349dbb3d3f639be90a56a1c8ff385cfbaf185ac8d05866e543620a5e6a1f9ed1b4bf3a8d0db37d3f6d07e93cf79e1576ec8eaa777f3d10b8b2c540739d2757e3fde4fa14fbd01e16d3cd5afbcd67caef341f05a292198d8526b1a69076b7b6e87b75d10310403819a67fe4685053210a680f03b3ca0e6f9eeb7e7be1049e57e7a21923a9fdd0be777c441f85af31764a15fdb775f6b7eacf313c2c445cd99f3fb8f80fcd5d378ad14668802a85d714f65e5f168d79684d4aeed456883ce57a179e647a45ddbeff0b81ccc62e0ae2ab06df377dab5bd099e4fbbb64fe5405fc906757e612bd52d6ca4bafdb46b73b6cf0587511568dd1fb076a054287f1bbfbd233ea5fb58e8178f61a24e89d95e917d4261bfdfbd10ec537561bf91585f682b050f859eb457a576f77bce20ede2ef3d3e94ca3ba5fbcd2bb24fb55d8b71a7985591e45af4199130fd19699e0d970cba83052fa85ffcdb218942fb1b22a45d5f147de2518195449178096a62183f50f3c8a3caaf42f3b0a050fe1fdc2d7911537b3581fd0e6218128e88902726e2e13a21baacccccac04c6520c5566662ade4cad1d12b444f146f9f8ec33d7354a7032071774ab5c41802b03d16a2b85cf058d9bdb24abbf0a5400474b5ebc8ce1a63db369cbd462ed3021a6ba6e897a73fc58bb1878ea2e49115565f4a8e6e100fd10a10dca83846ddad9d99e6caf71e1769ca191080b438eb4a66d5d1847f45059fb8aac530a5d18473cf199554e56c2bf9d26e8d6d8cf0e25bc20edeaa75cc352146264f4d6d7d6b25e987d90419a877f9be1e989334a0051c39e2d085150ee57cfadbc86f217b39ed0d404bb75da50298772198c363bcc7bbaafe53df39eedb74a46cbbff9dd07c30743151852afe27ece397ffe0043270aaa1224154ed91eb67d42f361f8d4b79cea22f53d09c181ea43156c1f02559db27d3020f1d747c45faa2e54dffa2bf53191bf70c044f3abe2dfbdea4356179d8fbf1884293445f35bcdb7622b7e53bad80c8a6ac84620704137075dc6a00106c230bf05443ff54940fa0555f1dfbe06a95d9cdac2cbb1652876aa4d5e08183014ab468a30602856a7c020b4c9c0d46f9fda425b260216da5fd84f7593810ba63ed82603b7afc5338ef217d450c38e70f217ffa6c9dfbe4e1ad3444c5a16726da6767592bfa648bad2a4863d6b275dc4db5a9750ba87953419542a379da91cbdc3e6d6b61766a6957ffb884af3eccf28109cbf12b4d5bfe0a6b630abfab0f40416232c2d20db02c2ad9fa2fa84546095fe24759ff793d424b50544abfdb552bfadedabac1b695af27342bf260155e3ee744ee8cece67478436e886446d6666d5582bc149521db3fc6c36cf458c9663a9e90cb7d8ab7f10edd931455f869cd849141f691d817e0489c2e15504ba87edd1411b336307513c81421cc59725c02afda0062435811f4ea369fd3fedfdf0819ef00389f70075511cd43024ebf403c9eab88deae7871bd5b56b7bdea889a30534649db0f2a1fdaea226a36c7d0ed777252809ed72c7a9db05091e6ac84426f8d4241dabbae05a40fd49407e76fe1610f3b7fe62b0fb19ec8fbef6fe24e0802e9fa04203b58be3d57e394ee809f6e5ef2f85913e3e8a3a8a95c1450551fb439b96c02a02ea360d9d51696da212e539417168a1336e67bc8b1815e18ef0c38ebf711ff990d632b1d2f7d43d4def8186ac1424a9306385cb11182454c3c3141780f4855a32a411036b825a01fe351e9256803390d404e47327c5867f0b5989abef121458aa4735cc4bf56f22265090a9feeda47b968b24180c16c32e4d61a63ae8cf6d6c85612dd7e2af6a8e1d1224341c551aa2ddb3d2d675bef2d1d1acc47450fcb44350f304bdabc29dca4afcd3dda7f23ba11060a15382ae334cb56a354143b6c25492c4a86ea00cc54fedf2ff9ad0a54fabe36fa3023a47c0f5e90857b9339f676ca679564b104c75fe74549a4154fde9a0e6d96fa2213fc57797a2fab399edb1b5bb9f6284220a29b5bf9c6f9783536cb49fb6f16a94bcd4137eac50212cc4232ebfbbe3f7d7fa515598693c01390e5de718e2a3d0709f7866c84c5c8e01161242991583630c50804eeddf1edb7136b553b59fb74788105f7d47646aeaa8f36dea4cd5f9d3c6f358db0b0ee0df55737bf7053c046739fd82a05c4f5804833e3319e23d3f29eb818474169403dcc37dfc211bd81ea98ff353de065627fe72805ff1e38c7b465c356a8c435627c6c8c31237cca0e14ecafa77ad53051888029302abd31598abc57eb1646a8e9ae372fa6643b5046d9edd1e110c6003fbf20f67eaeb6f00db83045c9989b9690af1971764684531c6d2594c7fe9981ce3588f0bac0e06f8e5afa37e21463885e4b0802ec736a6e5c0a996a04cc6b22064a1a87c44d096dde430146e98392965b11c025b7dceee2c88b4d0aed412f42b83f277165886b828d13c6100b8abe9ed129959939b9c526eb29b638c31ae4777d75ec02a6f5d3235b70c547fee8eac52b1b721d3344d8bd107ae6776a8a3ae4df476775f01e1182a4ebf2825c3a293d9bb70817243ebcfb5e3f3365f3379720ddbf0cd17b2ea46433a3f74edf8a4bc3db9bddbb67c21847803a75ffbad1415f46342d070ce36a2e669178f76c9ee62f7a87e555e0bed496de7495bfe9fde96507e2d885b80431950606090d08241620656892f5423464b1358a5bf0532644370a2a88b47f7a89e559a27ff0b1d0214a479b69701a6a8a8a42ef64435756646000000008314000020100a860462b1482c1a1236691e14000c7b9a427c56990a84519203310a21630c01000000000008608066c4120025949beb342a08da99c14bd40aed6e5ae059c18bece3e31c32031202481e301737c55a5b07996a4ef450ab8c2c9344c846b0b4ed9c39f2e3e8455d22c6257bcaade8167c40387c9bf12f38617fdf5e8a2ea2c7bab614bd54564dd3a17670f89de9fe9a112a22d00169d178fb531749f72dd5877d220f48ff91ab95c5b8268c8f25c178a7404d68694635be7478476851009fafed2039e96ab767e9e83ac46814d3d4ca2b497301e6338da96dea5e2729b3d48a6dc9a6d87dbc21cfb8d6f41ed4a8735b32a40039082e76c6040c40bc1a446ba2c5f59ca560a3c5451c72bd6bfb325a370f2c9d559ff0d6f893ab4fd1f12021e520069a0b14516b6e0305a22945032da57ff829965ede15325b2ab9320edd598e99f7b3e45d98eb05bf6f44c1bec7a7860ed09932b335007cc3d6f09de42cb657c656d9edf2369de1cd2eb564b865d9fe0321ce12d8312c8509375c4f2a62f0cdeeadbcbcc761d82f2f5b80e6ca90018b2a9e704d2c94fcd6a170ad44d4ffa4faf775322fa1579b46436aa18636555991c2c3a06467aa2d27554715e24a3d38b2aa1d61f45d7398236e5d57b35a4d3011bd71c6ca5d175f0d215d1be0ea7eb60eabdea5ebdff72ed14081ac7342bb16eb2a84f3643b2707906d419451504e2ab2460bd8267ba6abe7e26782a7d0550e3d1b826450ce28e53d3d325785889bb5f17648aaa8e011338940c4c03c2be6fa9427e5ada20d6ada7118b4f507f07d0990ce6c835a1d9ae8d8ad303a4cc1a7975b6ce2a9b378a1cab18bef6e11bd7db76dbecc43830b5d3737dee3e5f06013567dcda06c34d1438de4423fe6f985ea5ba9bcea516c58a060cd26846d2b9abe4bc1c98b08d69255f68221b9a75c9018be647c0e5de9f24a5ba6844ed731fba7e47ac6fdb12cd543dedbe1c3b10ff92d4219b935d7485d0b8bfc446c94d299a4f87b9af0a838b0978f3481cab9933c6cc36f4cb86d52f3c61d63d307c9b28680d1f364b9b1c8dab150383a7222ac62492a5c686a9835a0d513a08dda2463c144a490ed1dcd06dc77f16e3c9d0b94dcde994b0f13d5069433403a4834ae2c03f76ac35318415d3f208e3748e1ee9ff10a859fab119769aa2a63ba9a7823d9c72f4b1ef903730a7a46d9d2cdbd77ff8367e2e871594a6e75dd028f7b9086bad736b6247c859011fa399f401c43b8a742cd9ae6cdcac91ac54a1c9e7cd241bea75782ae3bc9e53f9b7ca7c8f0ad8edc40a297681b2d32f574b0ddd1eae80e0eedbdd61d69e3390e359ea48a393985c96d8397d570f74d7e6e9ed7872bdd8f299815a6d5721d05c17845597d8bf9e64c8ebc5d33126c9c35b5d7011ee389bb5e19b8808cfe9055e606eed1795297ca82966dc8ba3532dba779e7f91f14c0f25e8460c9a4ee4f238247a07f5d624d25548d8f0d15d6dfaa3bf4afced947f0ddad0d1d9ac8b9254dc21f769e44db7bba0f96354d7b45a7e0d89523a666da797c33b17572127faf0ff3ac99d0088b7e966765ee61590731521e813f07311b2251a5959c858f9601aa44d11f53fa49a8e62fa06a5efff21a07a2647b5bd85e31a465ec3b2be336f94ed4db158173fe8719450e01f99cdb3486540eb93edb6036baa5853fc5f8d312491a6cad9896d0271892f12dfa7b8f0388017beb01c3faaadfd32a4b189b72ab2daed67499490dd426de2a40d1f7ec5d56271ae571b680d48d341c3269ee8a96442280579123815fd02e97bddeabd35bb7257ea4ec1af879df3f74ae0c01c6f56c7076fe3ef7e05bf0d552ccd2c733c7a0cbe9546053c312a870ee00db5f3ee538a969fca0ce58e672824025a679ce5216e6eeacf3f505820175ed3be7a5bcba5460dbf1ebd60ef02d610f3c3f90cba9e7648b4187455f724c5f9c9f7aec75da96555116ecf3f3fdc218649260d406174def4f2e2fd267e81cfc8d7881d1c92dbf9ea3f5f154e81832cc46cf1cb0344b7962e31fbd5471f728928e93e69d692670a3c84259f220c66045f1cf5b75baaa7cb0e7ecd804c5afcdb5bfc7c4f8c8ed88d8eed88eda0a6629be786b8048da6d3a2a29f2aa7d965a1550cac60aa52bbbd72c665f54ca6a5d5b2a96f02790f000dea89a31fdf32a9091c6cff0c4eb1f6fc6781d349876f8e1ac2b23bdd70d43348a09c35e3b22bba9ac6486b4de48388afd0203ed374b0346ef63650a0c0dc33fbcd6e3d1f550526c252c313beee7f8815c809c0a0aa431bf552228eabf8864a558b2c1139bec6d35a49e2b7d9d3289cb40cb3832960e6ae2a903bbface4bb5a99fd5b1a8bb24e897e62cdaa3518a0424df95d2146611e29742899449e0927ee966cd051005f36cf42e0bbaf5ffab32b0e7b5e892a665351b2023232ae6f5e8a59da1ce9b54d67b4c6ff3b1810cae5b9a154514266a98cf040645efb3dfb63aa5270217648623142fec434f1bc7e85c4dff0c03f4375fc9cec82941e533bd73a889b932f829ce7b343e6be751fa1fc5b7e5f5bb99af0842199218465909134e78404490113e247b12328fd15b10e40b4a9e70ba961ca33ab1a8098923d29288f1ad6ae190497d2538c52748d3ca7c63276961871ed89e44d2d781b8272a8b89eb47f24007038b2fdac94fb49cd859854ac757cd192a8c4346a01c6f3f0e55f0bfaa33cc79463166a2e2d1fe7b623b52ef03e2560e813f1ee2f13c9f125a1f49f259abf95b4add92ed9b2ad2ec303c41789bb1cfb3c9cff949653f6f967f462b7175d4919e65f021189b2c40db4cb6012c6db9462b70690208ef7dd6070191f7d000dbb022c630093cd3257f81b2d2c2e9d2bac7194ea88f4228766636ca966cd997ec13b20c7fa672291090e7a370e3b5dbe826dbb9f546e4fbca1d20597c57c7ba254d4a3b5c6f625ec79561012156c77d581878412c89f76401ecf2e684804aaab91525138b7d42255a4069cdb5d2c4e54234282ea76b05d96b6772ce236068cef19c5b0438ac8c37895c8352cc0fda0bc3add46852950dc1164546f8b853f1099b9fa9ddd38cd922481aa35c12ea5e1bdca18b577f1567d391fc64b7d5d04361bfdaa5c6536772f6e5db87efc213fdca1b38f20bf81d2a7918c74a5e0c6d3fdd4dee3c6db28791d667823316ac4e01b4e407aaac34edc907d790cc1353c67accaa7380c9a937fb58ef3630662d90e7b39b38c0101b606183eb5d5da9267fcd6801bc20d79528a571e3cce59b3b2e8da18fdf55806a3cb16fea53e3728b07eebc2979e108f8d2d9b532423d231e506c0546b2a7793284d9a07aaea5d03ecd9446d6a27f8b551dc233b1d869e85f654fe929477169c237d13542ad3810ef416c39e0e4dec26d093682873d6d909dd8cee81c07f72add41da08950eb414712285b63d1fa6a0a99b1d2a80bcf4dcbd8f407f3492cb86b4901141ade321c9b7147c20ec43306cf6d8d72b2fb3c962a2e1b547d18e239f4b9c43d65fb58a181e09a0e43ecef88bf95cc7858a6ddc8c0e8c8a8d3b3fb407e37d2a17cc05832d064a4779f1d3f346b74ff69f0a5e88cc5b7a56d6113aa55ac246f96bae29a6cbd62131b56973b7bae3bf81fa0ccafbde42e1996212a081d6d47b6807ed3a5d9186d4afe6d31535b3a71dd6fc41cb83f1906ef84eb21afbc487d95f16dcbf9301f03dc10cd19ab81ad9be7bd9a68b4a4e5d70d8d7d77789302ac51db2bf43f53ca3647b4bf3064c51ec0f5f5dcd40dfdd28bc2d94d132cc829d13349c9e6a0571e3848b2b0228222491c2ac0d7b31e56c942f5ed68bea2724deac0271b0c2dd8677f707d4b0636408e0eb619c5e89def5ccec3304378e622ca32ea91fbbdeb97849da203b157a8951e1ea4bda398ff50195f042fa29a464c76126be7191fe2365e7bef6f5adc696f30c5ab448edc05019b47533efd2d1a8e9a98fe2d2f4f71da215cb33d6b5527132174d202ce7f46eed2682782c472200bc296330a43d6164f4a4c0e8841e907f3bae7b61a9f00deeda2385a7ee777a3bf1f67c65f55c81ccbec3e582f22f2897432d2dbd6e071d5bd68678bb4562d645c79950edd76dc7ce9a26712c3b788875f6b7daf8dee73f79737f314c2623a24acbdbb193958ffe8c3f834c659dad64901b437b736e823824d066221f9f296c4b07c961e8431238518c86e4a20ad19a8e14bd1b772234e0568b6c690bd31935380b6cc9f50b5ef9eed3af09fb477359a3f226e6087793d5e49ba0343cc5e6b8e41534c1a6015eeda31e3871306aa5075471542bd9b324417e10f09789e663bae8f6464847544fb56fde9f8810ece2aa1af6df348888352d3d2dcfc0c19efe4445b65721baa97730f665fe1e3dfdd9cae5c7281e553868b48c43cc863540a8eec6422cb36620147aa6a07e8df4865b62bf0336f71d99058aa51aa302fb2e3f26aa795233cce1adc34ea64029ba611fb03070bf8f5c3a619cf28f282efe9deed6ef22142bd61d9e15c360e4df2b90b3e25e590b9ba564e2944a4966e7e334c64c71ec10163ed9c9e45ebe08a3940066b96bb75cab2c3020cade315faa88964168ae278fe6ffece6898f92a4e4820a84fc04da65026092b58d522dda43c703d746f61f198300635f47dd5640f3d07c15de9c05c05bf87e463e11867141e6949cc905cd84de3175e64b8918fb9a60297b654e8828a4e5dc978c3208b52a14f34a234086da23ae5427fb012be53d3d5a260e45755659458c9624ad84813ef999b24c3c05a4f1ac88e0580b437f4f001f7df7c344cc226f07dd43cb0e8832b6a330c0d5b89160d968c8795b246065516f958c9faad7f64532ef0c20c72d393ca7a0a63afd936835c53836e3c4949708cca9bd452f24d2df384ad2fba0636872482b2c72ca73a8272d5dca3081bb49022b312925c717be76cd4b20ba54d6fde0ba3a34ec9f520e42634a59f83ece07341c16e490bd7cb0ee488705fce61b00ba28282f14fe49dada049e96d3ea7c5ee08bb984c8896d16a83aee3aeb7255296f21b01bc43a2dd4eb06ba5e208fc5c2b343b691b96aba210c06ce91439f09ad60ecdbb596d885999b6758b9ecdbf8f96e966fc3af177a1efd6fd9197f55050c0a93ae7f5a4a1c38e855b462930a7282f7008aeb9d694f6e4134dc359085fda9ca36c205db9fd3aebe8bbbd5bec90cdb3b005c809d8af3aa4c1024a2afaf5bddab8f94a50ae23b4b5bd00fb9edb99bcf1fb0f3deeb6cf16ee2cb310f4b679d9470be66b7b4fa11a845eb2acde4687d1e0b19128fdc2d8815c222041cf6282cc4f7e2dfeb3a3aa13890fe4c19e223788914aa52082578214a027dcd12ac9558d59bce8bb718ba3592a6df05eabe9e83256bcfe2a00c114f513ffa81d1064684b0c9f8d488f913d518c08a9634f09e6a0c8776bd68e7868808832a1300ed1db4ab2719cdc4c6e4f8e2bc55702d411c351c29d2643738ee67ed12ce5da1d099d57590eabf96ecea7ed375516973bc9234af21d3c0c197d0b45a662133912d18caafcb44a09a5a3cfff99748e07dd590c5fce43d50631be3ab47936ee1c4e43f171f2b865fab372a60d956cc4025d6c93bb8afc259439ed9cf38f7a7c95fa2d7f7e3afb63e43b904d6f2cd12090ba11dd3ab90d08eee8d49b8fee235238d8d3275a8ff44962c4d00eb1cd41d2dc54ab0a41d7d86d60c93152cfbef5c0ca3f803831d0f1c14100c64a9a260ed6fe43e2dd41788795cab5e373e1ade5f354f858ec509d2b6e59736cb4d25f37749703ce7f6664f47ba82c21f2386b55aa9b427218d1195ca79f8072e7f0dee8d09f0cf7b868d14061a2cfaeea8d67791bb916f7e8d2a87b05c112730a4b0a9c064ab8134c6cafebabf20156ca9840a38e7e53975f061c76e8335c021ef521f7554e8eadb7bc726ff20a4c4297221642e3a7c4923b854f6888a9985fe6e3f1ca48296385683c5b9372c609068569459c9d9ece3d452826ef245008c09814804fc097aa40a7e0db1dca621041bd08207ca708c3c03537af66d52f4608fbf49c0a56e5d87c734e39a451c7c975a07d5a65aaf63005548b6b82b9645db2d6e4133b46cec7067eb8bac33f2dcee9e22479ed878b866b68fc75e51439457c42aec219b0401884a6f8db72bcd0a662f4e275c520f663565a10610135f5f4924e9d54a0a03d2ffde49039c684b95741e0f7b35c173c8f915aff228137912fba39a768cd4575b788bff724102b929155b91d74001393cbe84af7d46552fb7a9c52b92d86500fd41e4d4cf7465372c8bad7d15db2043fc9b7ca2df98cbaa90d1df75b504a7b82a3705423a17d22acc5c8de3444edef7c41e47995091bbf47fa343924752e6e3b51e210f1248a5960a79c3590933410efcd04a52001a73ea87c9a461d9fb476859a4d64a28c651056b2c93ce99e7f422751d21738ad857212e2baea08158efd8f47ce8b74460d6c928136aba46bc3674d853601026ad5fdfb2d485780be8da5b0d82c98714b6cde9d72a2a747fe6eb29389c40fa75c127812ad3afd5a15622fb55022f8dd0bf5fdfb79adbf08ae2de79131d476b7216818d133fecb35f3bb4c5eab12efed4e125daf8f0ac0a48e6cec99c4225ae4d913c5730186a081236616611d094d3b7fea045756a779eeade5c2c38cf99e5555de212e3506614343492f7f178072b698d77c124eb990fa12f80143ea745a46ed73e8b667d6a9e072e3d5c99a821918b3615c7932c85874236e8590a7814a3b9d8f6fb2c018c5ed045f9c37885b5beab2e5b8cbb05c4af5965bbd6e21ffd0ee71dde62559804070273904a0699d07634d6f373743836c68a5c0d27fb5c9e87ee55f6408aac5ea7aecf5dd543218acee9ca3183041a7993b42da88179c1a657f3a43bb3ff16241b519e8aeee937e80d4b00f892ea09bdeb76f908cb0d81e3984e42e8dcc0df59bde0448e5e5bba48437c1cca8aa4cd69bfc138a9ae8ff0b3c352ed1a489dd720555deb55f05ad0bc8a62a5cde8a82746aca9da02342d18aafaa63fde1c98e7ac68a3f832adaa9ebc594f70aeafaac5157d6d9584ce11b5b130cc2dd872dbfff93d0977f91bebfab4ed7f92c13c8ea7b2bb6425a6e7a501c819b76864eb305b27e004786d71a2e9b0b85a64b2a2326c55e60a586adefaeb15aa6d9357b542755b45cb27431f53206ce52c11f46ee6f22641001d83e28b801e4bad813e7e83c6bbe1a6ab456384f19723c140319846d7353b6e4ca01ffb7e5aa88ce57bfb4af38781b2d388b03864df8bef400bff1517482428067bd2f285bf43ac8593f54788b404370c757647705a15ba1e5d940cdae74c7623905d6b5d3cb356ac38badeff3e899a34deb7dce17f9cfc173613dcc9b62b1cdb0672d64a954dd90370d22c6d65e89c77c72b462014370f9bd57b49938dd17e6c4464aea2d0e63124ab89c6ffe10468ce7b23c828bc51a3ba7cc28d1457fd50bddec21b738340b0b5e6b9c8ab8416d01f89e36b76a667160d9a0039dfd885d35ad84264c9525aa531ae66dcef1822f703e3e909141e29f26325a0830c7b4972be562788ac5e50af9dfb99749cb544e0b21c3ae1cb1cfb44254cb8b162973bc17279c94215d5f4479d86f94f8910b633d6797d8a16adeeff1b126d6707c99d073ce089ddf3c475fc2a328917169d7c614d649c541a659155f523e44858fac6a804a31bd1252950804e844a430f64e0a203890bab444fd84425209496c5fa43d5f5452064482029c6c6c018f069d30577d018ba006fb44e4a0635422efbca3586892c0e01d0b35bed3abf1d02d9e32d02c907e9e4f9dbed8e5bf60a28c955dbd51dafad029bbfb829da53a655c8c3673ded35b7901c98c56a904b8bc557acbc264f38771909f90b2a20f79d8f24e37e41fa898068686235cae85ba9fc32e243e234fc3995bfa3d27ff8520bb491c0f356193557716b353a0f65e5b46acbf4e4a14b7f341b9dcd6122f9aba0e6aea55d3db4def82787882021ed08665181b35084f519f86b4e720e159d04c9c9915281e135c3f2ac4a1a790a67f591b01779214bf9b7e6f9f2c0b6ed88c1c907eda0e9cf552c6448692ed9829c2dafa593b32e2f7f20f94c41ca6c8098ab43537adcb9637d4d2e3afbd12931e875882aabe67a1c034211b575c5725fbbe98e4ae1aaec5aa44f1a9bcdbae868366c43968525459198fe89d368482d8d6154c0314849580abc34bfed219f171d08173991342b2b9dd3ce1e298e3dd5c87f634ea72ac6ac5253062cc4418b5c03af73adf7319068415775135d19ca4dfaafcc4a1c5c81382f689458b144d2d5c857a4fe9a012ce69b6398cbb8979b4c177f6f4478bb92e09f033f032c1b817d99e0968ef9f95b8a3b600ff4850c4830c8f226cdb4ac9b8192a138a12d32453786e4be7eb4abe343063e6a6a64454aea7632ec613dc872b3858fa4b2d29b1de3b111d8c1f1121540970999c73821623ba927afb9abd090c65daf437e1760de8977cda703e043f7016a128c2b17c2fb5ae246408ab280827dbf5525565507bc02ca56089384d007cb9dc4e649c9a4f4870137dea2611fe7dc54f09e2d0e2e83b67ec873c64dfd44f7bd25bceb52d08662389cedba8f174db93c24b7a6721170eb804d6953da084a6454c61780a8c4cc9a0ec816d26c19f0cfd5edf20086e037fb3905d490114c107aa59a08a3e09642f8f8197b7a5f121a6c61a3f3d1a3aa7e1fb7dc2974485f021eb0064da66515b41b77e0b4503d6c6351629f55f7be94859f4620c6aef4d34e2730255574883f33b4de348e09fd3089be315e1e775506b75455c5acd7517256aceb4a9650d1a6990f713b44512526d3cfdb064df0b0ce8788ddb2a433a265c67a6bf5a5fac5a5ee633008cc4271d044ca40e994420cb1412dff0b2c65b479dd20679a6ea5268e8a0d33b48530ad1b822111b4f312a4322ae2e4b7b00c2b8c4f1094fa7dc55798f01141d6eed89f88089cdb288315db50f1477f64b48c6fa1819c38e03e52e5eb563ad94a729dcdb8916a4794fb78dfa9c28d182a0ea12e5a560bfd34be1c3c413f13c52106e604b814f23f18ad3826a0109fb14c1adce0345831d39700d6f4f9ef22e8ceb46855c3609b0cc5c34a5fc546a97b74c5f3bd84ebede1e798de74ad54d963625cc00fb45e7652481dceacbd7280c30786067bd7b7228a0cd0c3427087aad96ab11684e8b59865373102a628605471a476023c9e79ca1096d1ef01f9fbc1519c55e19286e4909ec13dc20318f434c047a6ed0887a1a973835ff0ac7b757ccadbf24febc63a53cf5add643da960a5ad78b12623637959940ca7185a5b314e5ca1a9e7d777cd5002f682e05d3fc21e1624774086d5451b9420ad8b3d042e38b90079d78565be5185a68c4b113da0abdf7a758c35cc636ee7dddd53e078d77b8cc54701536b979491600bab02832332def1bcd73b34a441b525ae77aae318aa2786532684dc5ee13f7fc52a0cade15b086cb861edbf21f0907b2e73f50fdd3509799bb117522d3a5cc643cff9d5b07ae50f188441bee420d8a2efc3bb013f582b22439a5d0464919944fd8816edd694d827541a5c8eaa3aa7bbadc27391b82d8f442b5487f7100a186818d67031ea3103db375899b1eba23b3c0f6d41fee2eb18cc795a8c2723a26145beb918792112cdc5f5dcb93e11f748f18cc525a3459f474c7744bd5ea5b1a251ca33f199bbc87ccef9c0a3a43e2b82dedd3102ab17f0dec9d281fe0969c5f175eb90dbeaf92e061b667cf5c3819e1e3d5a91eef7b6a4d5466fdf2091eed321ceb78bea8e395573066d8df8b650215771b9d3f2e4fcc354a4fda1bf4d7fe5901903be8bc7696fe436a72e2e8cdc1205e754af016edf187a8f2cd2a2da3b335ddb47bd83949000d9743dc04ad0621d42471455f2322331e744ce7246dcca279a5f9f30bfc72d4e7de8a02d24930240280457b0cf212f465b7ae951c7d7ba1a54bbd28aa579375d3f3161a89c3df9f1740356e578b1b364aba992121962e36f2b96d4178dc1142d1d4cc5174e9b11030f6fef82541da218bdc49b6b115f967ed929fb019f2df5f51ea9c0a59fc6beb7ea99c30d08093d31f49ea9856bdb17eb1a73fb953ce362203eb7d3cde1b8d1a55f81233dff4a54ca3f60bb856793a855571004363099abf71a092bf3ea3fbf7f5b7241379a3b1347c603b0489995f60fd279c973f6b9f9d8cace18f2b7991591bef90fdf5283c21e65ad024fabac0de9a61af0fb69f268e8d69b5b5e0ae4001907a8715eb5c7f5c2d8d95830bc02ac5bbf059791c0fd28d1d2e2f6ceae94de1767058dc86d82e7bad218af6ba59fb1dd951974c274a43de9236d7f5c60a4394104c85b024e99140ec6a5baaede28bfaa256336b4274ab905c6e8bee5e92c55e8dc917c966015c6315f07c1d8c822d5dd036180a5dd2db3f6508ed8ee32a6a0efb0a4d1b8c59f26981f70b811ed26818c7004fe0ccf44e758c8c28ef019448be469422514de3fe4603f0cbb8dcd405029c7a63ae74a886e4ed392f374f742d4cdaab4d326160d47d559b8ec21f725d1cb9827bbec15599ab7191ffd09b514b246b7b50404b68ae576ccf2fb6198ff0ea591a7f15355e43a11af4c61625ea302a805b39d7fd8fcd97ca915b53c989655b2ca666bce5d2fc384096bc3a55d4e0d9d79607e829a708e888f7960bd6ee06c2e4e11948c2d35afc04b88cd50ce4c06ebbd07bf54999018bf9b2fa092d1e9436b4c1f0947123b27e5137858ab55b1a9f8913f3667d1c588d362065cdeb656cb0dfc1b1fea4b7e2eefa2e38ef09126c9a39926a40db466bedf2df53dd0201e00c914bb4cefe797353039141de0269ab7719d9d477b184ff63bb7634274af6fc5169f78fc65d1aba9b8216107bbb67bdaa3bcda654722add7f2b32582e798f8d074c838ae7b8c34017e30c87f5764d82bd020bd72d544a4fb2170061c19ce40d10fe8d11d5892a4db3331f055a757e6b3a42ea973efdf1e1ea6436755027ee967a0499b762cba390a1923da2978706703f28e3fb01456f3d5352c18644f16ec55e38a3907a13f2f63ca41b75383a855119e5d22fd60bdf1809d7e30f4b62beb9cad5d2717d97d700fa14480cbb8d6053ed86b2b618c5b3f680a00518dfc4ad6236c9a4128c8187c71bfab5c0c7568b51b2aac54d62b9fd604dba152c7c2b27606c3f8091367de8d04b703d3c3a2800cbb8b3b1b0cc50561fe09059ab97233a827577a435192fe00e8f1917008723551ac688068fe5c75081e33c62a23786cfed5a5c10b1e9b763cf4b7f384e8a9f382882aaef4263e8d4ca32106eddab2f7c87f7f15ef114577e0f1e0e3d5aea118158415f930e6b0f3135a77016c65f3dc810d64d161a9bef1611b7308fa516d96747743f8bf9a60decb6dd4e9f7ad9df420c25084dad62257f963e49288ee0dd309c854f73cc34d4a53edf54d654c49047b23a59c6f13f65cedb3902a226b61bff68b3b6e64a6f8c5330da8e636e0b819c0e76fd426132dbb12436a4cd280afedaed90e772f3c5c46c76cdb6fe6e7b770a521270dd6eb1510e59713fedbaf874434bd78f297bdcc42cb4c2f4da9fa018003cbcdddfab79b432e77cb8972a130a8b4c689d23017dd1753f7dad7c48de8d85e3933f5c9d718897119891c38d4a3a93e7454abb7808c8e4fc4fa230ef4925d0339e92d1ada7b5cc5a482df4a054fd1603548234a7443bc9a2d7b664967c3b5b84b6d9825e27f0fe8f3626ac41985f54807237a95cb2a9af87b01a7462cf43556b902a33b335cd17153b08780528d56871402c5a3107b1f40f1d62548b38b53346b7434ac301d5218b2a5b1a02078a1dfd4d75a27499398d1584dae3a7627d2e53de5c3b6bbb8222ad23a904863d68982a4646b027e21f6a8d5574398bd6f30a6c913027faee3b880a4f5c038a0eb7d3af133f96273c64c408a4001870a93384474678001a88789795ef91a3f214823ddfe8b833f64f61344e9ef3c8923fa1d2ea35927e1030b0a70921842374fe8cfbe1379c0d23c06024954fd4b4b77c98c8ef93beb96c6b165aa1669d32a0897eb705a9031f9636fc9ed8e98610a24ea878b8349198945285005435485833e707b3a91bf6907506f119aa4da0503c5dc7baee6e855ba98c7cc33abae0e23dae57cb8654e1e90fcbaa1ca35697a25061d225ba2b626699b4802515fdf271f324a3af9dac3fceeab0339bfbbf00934912ab1c05f80cfbfae102cd39c978437c61b17d391788a0b0613b86b51d8f5079a32f8498224025e835077f57ff1f055af2846245427d4cb4fd97e6c526a9d7c417c0f6e051b2e1d3520a45b6865bf53b05dfacaddc4a39ab1ac06657ae2fa80ffd19003e2448de43cef866a44d59b0e211264338bca0bc480308fee2ff9950660a2813029a85836ebc758abecd548fc96c020eefd2ae1ef93435cd692b26b72e3ec803eefaa7b8a908bcfa74e939ba82f50a49a1c4e45ef0b6b610f37911f8d28d01f455cf17588d9db97c47780cefd4d32be7c9a4309d31fa2710d4d0bb3c847e8b43cbae682a2974c01ad8fc5563954ec75094bf3f4e55e28728bc425160f4e9621a3a41486dc4c641c08ba3bf170b715d486e355d5059277007297c7a8dda904aab666a411a92a8a88e7314819cda8089653c38ac789fa7e1dfa0bcae9a9aa3eacf03368ca0f59a47e94af0b09a564602734b3e768e48e6b05eaf7be03586a5fa03c73121085295397903994b3c0238fad942ffa17bca3a774abdddc278de187079b60e00a4c775409e3b61dbf5a59b02df8b77ed1fb2ed8041dbf88f9028e36c78b20037a5d2bf60b1d8f58638e3c743289260a5bfcae7946951cd640be6cb80612796f746cdd76977522c4126101d3f0bb0b1f94bcbc9728cab904397719205ed21ee1ac9409052ed54e3e46cf391009956f1884a89c7f0c2b4dce98a5419cb78067dd7a1822b46777dd07945d68d4d7d34698a1a3f7ca2c4998835212e4ad403fdae85a02c45e226b8318abcff5b791182b64c1c90b118d9c29d91dc147d5818b3681154d32d3b33ff8e56ac2192d4052527cf7e8566b489135c78286ae6ac87a295df5d6561a9eeb3038836b58f8a563643afa1680440925d5398883f10508741be320ac6c58d230f8eeaf63140d6c60ac900d24f5c6b5b60f6d813edb94c991f5676157320f3db6fd33e2a8ab87e92f7f7c7718fb507399a85adafe3942f8267216486910f6787ad1b455993c05fb075a0fb6f048d01a502d8b9da96b3752356a944339ceded31007ea022e0d4796471fe2661040587232758e46d6714f81fa53883bcf0ea5590a9ec9e7c4b94a6ec399aad3b81f60e8a2a07f924efc52701ac53eb8e25718c301e16a373b10cd997f7a2ecce6f270ec04dd4c27a2c5636b6b20889e4e6911108764a8e48c2739d83a4e8e66f95a9121899625efaba6cd348aba1fe5b60ec1d6bd2803cb5eac75efab6472a9bddfb6453bc98dadc6c246a1152484c31352cd7785baa371a8785cf59f64fb0e840acc2dd9de1a64d17903e5cc707fc986271dbdba632caf479829eeaa6708945d4003ced1017b4769ff7038f83f32d21b67a3ee778fa1a5d2ebd33776dd796da8466ee68d07f35ee4107b61f00bed982f94d8069451b9b042e78e5ac365fc4816c2c9923ed63c483c7d639aa16e7ad4fbcb8354f748bc3bb67a5bafe70cb48ac175ddd9f9c6d86d58e0911e9bb5f7e9d598012f3135733a0c8a9106358d429ad64603bbf6c57c5d0a3a391c591dda9168bd1feae8de23640a41f1d7d9cee48798e21d0fb4a8d7cd8d7652d991a246b6d57d338d7f965d7e4683f0ae48eccecf0a475245f9f33bad5ec4c688943553a0f94b496de195b5eea86adad1adc0afc65dda9f70e43d853a184df9eed774a322a97d8d1b82304263067b17a5d50928baa384fae2bc007929c22c05bb74e3c7435330aec68df4a40e9622462881a9fa160a6e9493aaf00fc665c2baf1eca494086ee05b59cc74e4cfd91dd0818fcea0f53dbb50b75965b402dbd1e82664a592af2089980799ac343ec0b70c36754b9f7c82d237008b46994e8be4c6a00b545bd1186e370dad3e398e61abf20f980dd4eedf53003f9d3307b30ea7105590a29d2fe55e02388339be7d0cb8a243fd572bb4197e5fc5f5b912a69f09b6a5294848bdd19a652da4fd5c638d9d7879c04bdd441cca7a25a80da135373b5febeaec2f36b2fa4a33d143679e4eac89f15e2cf2ef34550c590c40426a854a627bd9c5ffa2c85cd2e43423ae40c1764a6b07acfe6be5040cc3477250b9fa725f4382e57e0ee2babe440e36434ab19b0ec2f001cbcf821788c2a02e8b2a23b525a7a7f01cfced901640d87c3a48bac72169d92d2c178fbc4881c1d8e2a9f1f411bbb578950b6c5b34af6013cc16af496938044b983981a97ef8031371ae8f028eef7d649f4a0560e70153ff6ccbb72c807b1f39e473de24b6d27d7b6808376b7553223fdc63ed22eaaa595c26e9f3ecb30fc6c9e1586a14773bdeaf2da5c6003e783ec65dfc25bcf354afb64368e9c538d3708e5dc635e2b62ba7a9f62344331510b7652f60e04fa399fe5723935d44d6cb78be7ebe96b57e7dd384d61e2b3cbfcd739dd13ee46959a537091d60b373acef04a3889286789287b060ed76d189fee6708c5f8f1af9119ca241f6b934f0b9a78d487f72912d943ee74fdf7267f2670e6ecc8bee4c2ace3dc3d6f61e3de2e92d993450d10cd5e29ac7e91c0f47c4e6b142258e075356271a64b122348e072762ada3f11899d5b71c8c0680a6b61aa142de67025b57640e35c577d937953d1791e1d34ec1529e7ec01535b875f87417cf4194e36843f664d5c7f72aa31765900be30d760fdad5245d4696d35a6cc05ea853173e50fac202a4e2d903b3d876b34f6ba09ce6eda810b6e5e0d47a664072d09967c18f71f37917aeb9e47cd1c5d02f5da2c0618aeba171719a03ceac7f94aeac2f10363f09a5cb8a3240703d1b6afe0d3ea0d00a72bee9acff19cbac28be12012a37d55b79fba3705763b75d16aac8209bd164771411b3ec96c0e7bfaaf604074e71336e1b60d8bb53801ae258c2d9659d9780514b9319fb8eef09bae972ceed2bfe91f7ce41c861b3c186be4119306f94d9b0a183ab0e0a0c20dd5e217cdecac65113f8a7c320e177544e6eee8b3ff4eb76ca1196eec3b722bd0a16ebefe705ef777ff4e86ed751c6a7f80562f1419b9e7dd01f7f9c0f7b919407316d824964ee2c14663b3c3b0602565dae13059336dd9afcfd9042c4af74abf25b5ad9e4bd49795ef3e01371a5e84084494823b8f93191d14a1c2b9d059be8169866222ab532b233f7a0aaf1613517cada50f71057d6880e118bdca0d8f6265ba1f8582faf97b1d04d8d85e26b1b22f3a501ab930aca7129a05aa7e8f4ab2d68110d0f9684cdac3af5332c753213deaa98a7f079eefce267cb69f7c67634c74eada140b30b3ed83a0d2f8ccf65e73d3259942d1c3dd5de409608612869a198e21c51598cb5b07d674daceb0df4a58640716e2e139fcfedf43da2de3a64a4ce6e7a8f672f3590a1a2cda3c2c4edcb1a885b09343439a15c62b11b26b44f4ad05935722fb4c98cdae873c9be541c207437ffbe2b7a80227b064572552f878e39f838734fde73ba21d8466f8d62c83321d354a10c3a6dbc81ae53c57bf03dee816b7de38c4144b98983e71d9d05fec4c08c53622a70f80c9b268928b659aa6cfd95fe6fa451d021789a9630a71f7c2b1d20e73624d3e7892591d9cae0654052e5caa40aa689c66b111f6e70ef4d98382a0e3123192eedaeb23de64a2f22e68081e533cb840c42db55de4a3e5646c9e0d7b3fb842f7a640dca6fee3abcbedb40f6ab311494961ee2e823189bf6d8aa91f46c333d9f384d3cd43ffbabfadefdf7a7e9a6f7baebf73a483ce68c775af34e846ae009318e83646edb920a31ecd4ff3bb0eaa9badfe6a1d26c66b86ee69e23c67abe4eef8638a6abac625605dda1229853cfc2c31fcc562179a6078db6a82a38e22c3cab143ecf1866d9fc41d5ce8cfbf1cef0eb67d989dc40836246e5e88331b479959983f4ec91d24061c0c88cb7f03c78a1b76e4f9303a2690f0308542bef979959e06f78a4152eca5f9899424b086320ad320025b893310c4c36aa0be34532d9f025a88b5e11e2b4b986b90c4e0511aa0e2c65d06de49d85bd1d7823cc819504f80b6327913e2b8b5aaa491829ec66d9b75ba5ddf5a6bb6ababc950d1046004fb04ffca53a79d8673d695468bb6cee9eed83d101e0cabce36add74ba5730ed7f04876e862fd07a2998c14a0bfe2c9d6d25bc8bb8873707e97197eaf78390a080744790bd61d5dece8360f156da94a3a61d225f68c92e2b0da4a59817bf7f81ddcd16f3a20d649f82cbd38e18637da7306f8968aca7de2c16072626fed7cfff047607001a7bdafcdb52cda29897aea74c59402564d11e9ea0edae44872ee60a8011867cc53fa38401594a3d38a32e060d84c0329b53e1d9a8190a9358f4863544efc945a1d737cd77f5c6e598605956b7c9211e4d8f880b2d8053511601d6289cef348e1f9727598a21a57f99e830d030a2db74ca7e0d1cfc621fc81a05087dedc0b7a3f4a302b63e5799e50d3d9de36534afd1d5e209d6756923916010f94fa44f079fd8f6e6f27645bb0abecf1eec911e1204f529db990528d435293524904cc5362a533d278ca267085ddd44ffcc2a0a023425dd41764b719cbe5b5c8989b40def1417caf775738ae660db10b4982064272a70aadeb92dc7720ca6dddf8625ab312058ced1922592bacd722d17566d4d8ef5212210a86c8c5910aaa06b43de1ea53aa011450c12e84bc58a1acf17b2a014a92eee2b8505288b880fcf8ddbfe7da413467a0a29635d3a6e4a9141bffafa63cdfb21d124df06b2aa82585ee1f178722d4de0931e88aeb9b0823ef4a4ad0bc04c97d02358404c8075ccb9bb71364352ac4a9223a55e009f548037d98f8c6f0d53715938b3fc607983a7990531605ff47322a511a7b7507eecf4889acbe8f2957dd5a2a53137b4ef3e920a2769834e23931f45f70321dc7a425b6b131a229a8c4d7c1087699c1814d751c7c806eb22fa120e07a3f7a59fdbf51c00494d1d9cc947b14ef3103aacfd51a0268469c76a628182e6b170dd8ce36f52b329f89543d85cf0d0c5b87ea24384f2242bcc35317d53e0a91c15d1c921657c05e1098611d2fda349760ac815b7c61d2da030e67aacd20358f54c255add543f22e5afee28bbeb969a661934590ecc1c3d8cd66633ed6207c7d8605a2c9d72bbf8fd6cb6652f37b51120e634c0a438938dfd68ddc941519e8545fea41fbcb2e65e77158f7bbce6c561a951b4ee6bbab3cdbb36ff2ff8e1048422aad5099f9617438ede1979361032887ff2ce2c2f28aa01f692116994dc05450f572ab435778731277000f48ae60288cb01609ca1ca60dbb48e35c1a85824934c9a7b8eede5408e3714b88fead02c511c162502bc4d0c8f33da4166c16acc1884336e123675460d171c33f20955c894bf05737a68e3081b5882f7441a2625daeef79ec96b244423a4f992628be30db48815a9dae2eecdab262f1f9c54df3603a419ed5fd8dd7e0353181c3035dfda84a06270e3db5c4e2a3ee695b2bf5391bb2008094dc4bf417547e0785c17ea56c1e7abbf5cafb40f9c428f8cb35370ab5092b38bd2b33cc88dbe85f7cfaff06771e4fe664cd89bda8f8a9e4695f4fbaa5b0bf148c6373dc77cebc0d8009c05031722303e7ff6e4f49660202ec20d6d6924d8b716364cc8ff60c837ad1086f484fcf64cf71f747bd0a72ab48b7c8ff61fc403adde3253fe6b6f8a726b20c9ab2b8efe03e6a22dcfe30f004b2cf5219f79fb881931be2dd5a5236b3bb3413e02548b28ad729b6e263c444c41d42d4162cf4e3c83e1c6985e84939a8c4c9f5995613fb353ea5f49acb808fb872f2f5d2382f451541b6b0eaa46057fae52c9d7ad15b2d2034ca8f82444098cd644d68c4d5003622b41cff80eaba989a54f1d9ee1be8515cd41caa27c85bd30875ef752e2e27d934f9f74d2d4eb94637968ef5a420a63676c83c942fe03f1dbd1b2aa608faa1a1093d9fde94e3e835ae1c40e29251a85e4ed40c2f5b7a2fcf62768650af7634c8153203024dd6d63c3d085c0a8ab720b66f022d1b9674dfc98e0ea5fdd854d48270b796c935102cc32ed0a389e79cb3fe3261537e741cfcb5209c5d4725161d2f4cb199737debea6b7497d5883567c00c967fa432b1fd511822a907ab5019e2d0289ce79d25561c95064a3e73bd54470bae829825cf1278dee01931314fb3ab93e573807ed7df3f655050ad51597e4d494aa55c08775be61c6c62ac7336454bad1bc8b9dcef3f6b8a88107f8c87dd0ac3c0d5372513f5887335905743d39cd66f20abde60bc0b96623dfec7c1d6c1962fa06495d9723946b1318609cbb7c87c1e952fe8f61beb352ab1f0b4b6cb14e970f48a730b69ff7be4afd9000572c6a83bf45168cb9948bebece7098e2b02e89b0e00141ca8e9e7517c3804c3f1d2233509100b5fb01138f8e50cde1414cb5d33fdaff786acd6f64854ff0d635bacff49aee8a62db2afdd05736e4ccd26ead9b99086bb046250c0de2a53b12a29e81b8f8241c33f737b506823c7259e9eb37ce7c50783ec24d858cf5503b8b044c962af1be529c79f2e1de78d64a728d02ec4e9360d7d69d5bbdd9a13e2a865e9cb6f9bf2c09a5bf98e7345747df37c335dea394143d2fec9091d3d3d237fdabbb4d21429ac60a0b83fa9db382dda7f0d444ecd5ac1009aec380b5a7b6264b9c4ad50b67575dac4a28e96686004f2371267be1cac849ac5b900cc51370d5d6aa11aab3d73dc102d91f329a5e94a60cca5740a9e02531d35e7231558b28fc6455d11b6b3e88dd9b8a59160dd646746125cdae8f19ccb41a47d33083e93073e67ab23d4a04f5c2f76d4b02340183720f52439083195a2964f8b661b7fd05146c1c6f783896e3b5cbf64a24aca407f3791dcf76103bf47343720029dbe239d897bb2d66d766a8ab1710ce4a1ca111d11e17ab3f29168f315d41338845bbe3ed30f5c75a0406c1d3755155a9860511bb05e8b5410dbd6836f0429687d10ae29b2171d0c2b8be71c06322ddee6cad1b6b6b3593a77a724184499a59a00198b83e1ea944ae574f00753d64191bb00d69db13db487946f03d97a9aee4b3ec6e105a0c771062349ee4d32acb30cadac76d5c68b00b26e956528f2d474a188a03489aa88744fd630f0c889b512bc993046919a97480e96ba2dd6525bfd567f95c5588e14d5c2c540393d7e11c9438e07e00141700610229138e94f92980321ba75df15de13b17d10e4d5947122e217d488590ba802142d1069ba847f060bfd6de1bcf10cce23a22515b86c6ca7f037aae88cecb0e252c5d76c113b07eb5a463ca95028861a0890bc3bd228cb77efd30b68fc8b134492b42b5a16b0b292a3ba2247d457844ba775fcefb05bdd7771fb79f40bb60f48de308a953c093a5b3986c06e0f0ca3785e0060295a59529e69007c7a688d815deb50230adfc90c3ed1df4a9f65e27c05a7272ba58f5a9165cfdf07119fcc228e0f5a32eda758fc690ef6a65b7b887b584bfbf54e7fb559202c7a6fc628c82cba006ea866cf288c7d4990c4ad44b8242bbf80f3d13658f4f1f8397349b61ae4dd616dc24d0fb3fd0df0e267c2409806439d14807a0ac4ebfb84803c3cd0d92b0ba2495fa4f8489ce8057625be66fd40cc99539c98f7849193aab82767fd2b4badcdf70d57dd86b0f670d89c24a97da7eaf510b6a73a95592b287824eb7cf21563f0f8630f767e80c3b04c202ee36580fee19fa80abc78dd28017a134093722db8b5aa122173ed4d1eb0765605bda2e82347487c78e065a20c52862cab7d059dff69c5f01ee140330163df3fbc36f989f9dfb39868fa608cd0dcf17b9e3bbe44b4bb31b790bfdee40d8f62d1c6a9e8674ab6d0bf11c151d4dc4808ced08fc03094f0edf5f73123f877967921b0529148db8f49180049836fed2ff509ab28b58de46010ecd1603680f0a687626ff97a5ffc01f63081d6063f69385b5c8b40c0c68c1efd500410a4292106afc743ae5b054936ccab21c7946f899678d57c8ea324d84228c2ca0b24b7fbf3354bc8d5697571ce0c47744492a2e906aaefa9bd2ac2084e205dd58e25d5427ae63f65c905c2b7c3c6abe82e8380334204dbdb66c32722f645b8d0e054d27abcd5773280234feeb8c7fd907c568dedd247c2bed67d547dd6fc58faa6486f50f4da612bbd9cd68c4d0b24ce2df10a2eecd4183753131eb191859768ecef0c32a5f9e26c8e85b068c9a922bfa9e216304d37c2c49984d16450e0d2584440f91edaa6ae7e6e7abb661f436758f067a9f0f43ca9b82c4edb5583aef9da02a6d0f520c3655db6916cfd8a3d8de73cb6618ae56ffdc2e16de5e4b3c86881d48934b73db6b47f144e2d42659034479b1b398fa2ad90ecf6bdf22c923de9e304070793b4d32ba7f4f05535aeb3a0af4fe3c90442323b331a5416dcbea2edc590ea359fbaa8982e73e28485e86401edc51b72560afee7c4d79f87d7e6e1703d360707fc01f17f8a23bc24e98d19d9f37fe1d19ddc2754123e878ba26547402e9367359d40ef916bc289f36a5b63bdf336a63f4e23f211a3cd0afa6763ce09237066874ccc77ddcdde214e406275aec9eecc7c85ecd666d54ff08a508af33c958cb1086f0b63ad85815eab4617d34a71f486d835602504ab82ba172b559755e6a200fe09e25d55b12d49ab4db4f4f5d134688b22e755a7f75d6316f4edcd88f87dcb8a6bcc9eaddd31d9508289271d64c956743aff3f6666f80b7774d44f5d6b35f10c31f47f6a420450c0ba0f235c80f6b5078dc5ea1abce0cb0144cf60f5634e6c24cdea5f4140b581448b6c70950995fbb5d96499dec3c12dd1260f26c81e98ce7a6dcc40398b9d1efc62c46908768c6ce60b04be82c2510f5411ac9898bcc04f469e842ab79b2abfc0aa369e9d993f37457a2adaedfcd84f52a127b854b038b174e6fabd668ec33cd8540aff6c73381732d54b5bcb6ceb2ef10336390e0747247032da9db6b275f196bf65f80d0d1eb6d06713bbab48bcef4cf78011abaca99c0df1f237ddf34a5e09a75fe1563e09425e2e4291d50bfcf6b85dd25fdd9d0174f9e654440e991296c8c395ac6bdf03d54827a437cdf8e61b7995adb6f1d5cacfe2faeaa368be7d37036b4d40fd91900ad7ea668fc0e614417bb16e62111cf5be8ccfd95a17d877a6c900fae797fa3b6162824adedf38dd59cfa949e797cf8b8bc5369bd3ab017d2cbb95fd6637117c08582a0cbc17ffefb5307a512ac322d9888ba36bf4d8928241cf69e0f866146accac95aa59a7e06115f5db1c732e7198d5ee86186709000915a5c78030966bd95c6e53e079ebff20f65f7bdadae2348880900c1229433ec0c5ce1f22c7302a32cbe860549dbb89890f917ac4141fdcb2900eb0f840f1bc1d8e083e5d9dbd3b38a12338345581e53068a07be6a1bc605617b87986124952ced9c7d199b4eaccb366dd4338b70248db90936bada8a417ae357cf54bd41e70fdce12f05eb40b47bb8bb066a3e7b3bafe7aa82e1c32f14ec3876d9f5e0b54e66fc603929bafeaa0799547265e800859f28a0671ab0c8588b015dfc2a4149d09dc8ed197e74a58fbd597ce28b43d56d8a126e508db508dc28b8da17a6880368dd884c0d1276cb9fdfaa549ba4096d30b58c41ad1338387b3479b791627ffcd9c542a65ba49232d7f94ef54d18c3fc60c29d0187e228387598f15337b64bef3f3133e8bc367a01df3e65efd14c8373c245195380ac2cb2b8760b8278470c4b1bfb75fcd9e523f5a69d9d962b4695b5f659afe6d24dbb26a0b67b857083f7f0f718a0110eb879fff0c79a80e5f72c13b64e8e206a4b36259d14fa31cf01a80617e5deb4ef092503ee1a01ad90e7115ef89ba7a92c55196d0509b6c6c15918d738fc1326da169974f6b0da7b77da8ca462181b27d75157b757490457220a7c7e93d31862e1230c578f8f11538a54148ac72338db3c11c6e494345f7bbd3ba0a486f151bb72402f641e321251c08b82a2bccfbd4d8d93204752583dddc8fb36dea1a80fda6693d38b3489ac43440f55b8337d5b3d8412ea35480cab494dd2cc3a8bfd913492750a35ea78a25bae3221590a8d5a8e054e53c9e926120c63daed779ca354b86dbdd5d09ed5fcabdfce30c9a53329e8517715ffb89d3a89a331d37ce70673158cc04e5b75f43be68d78ddf9e63b8b35435bc3812844648c36b4a836601cbad9bd754cc0f875158a627e48f6f316538fb309532b7fbc1a3051b2bc7c9bad1889397415ebdf556be1c587513ad8b04aa66e5dccfb36bc57e03853f52e73bf1b4aeedafadf7756fe07ce66fcc8a14cd8af03069a0e5e6135045f0f8830b3cd3e2e5f23b91378af1b2a22c5b4340fac8db4456a1b165d76975caf3d4c263abeff92b6ee9dd9cc379e8321258ce4322bee5b7bee0ec05357568db17dbf4df684a239ad0b678c40147e73faf5ddf2440e92142682ba82b54297ff48f1a8839dc62cd524a62e932e39d0eb2cc7db4254f210a70f80640df0aabcea7beedc496baa5f87d2a3be20124f456a1262990e93d1e850e0568ed0354f4128424504d600334278146ffc052846424e6ebb233bdb1c561709b182ec7a67e371eaefc4a09c650d7785c588455d3e5c6f2f0cf70799278a685419eda16fa0adc03883ecb9d71f53d3a353038b29fb48fd6c4c804b09e8be4de9f0749e18fc80065694ec1662cf44de97f2fe4fa9fd0cc32b04279c3b1a3bbb18924c98b524a55a7c5f4053bb65713d07dbcf74182e8fa8a7cb1291209a58deb47997b5fb5f281f6028515af21904215cab456e90c004aceac3e2a1757b8a8963d9a271a80e1856533c3844253679cc8f495dda6addbc98d8d8f0b1903b797e6f8d6736902e535e5d7084de8b98a98a265d60f091a0ff8f0415c654877ded29c9eeb95b9aa26abb6c7a21076ac8db903f358e94ce38b0adbe7f61714fa8c028340bcf92b80126181f30a082d88ac0a07c42fa4435ee0dee6fc6917dc0a0ad0db573c024d1ab868d72e876b0e428624964c952ef79fef55f85355821db4fe1e1136dacd26825abeef7971ec42509da3370ea5ff31971d5590e03de35096ccad299602a55047c8ab3485d41563196c5b4d3880ab605c73eb5eb8165ff5ee5473820e93e46d42cc71f700982a32ecf64ff1a565e58ae1a4649dfab17096718e6ff5df6dc059e9c65c4538072336a6ee1ab29d9138d017da1971335e8a71a433f6d13781bea4c80279d2656c0fae2b011198cfa13b0989e228fe2a8c29061d85155d69b51814235b03427276ee228c79a9ff8a3005e3260a942392a9b62ac89181456c40e9665a906e6ea42ea99d4a632c67f6c7958b10662b01541fa53b2e865f3641515d2a685d408db977496d8a610f8977abfbdd27d941c2add24edb67d0d86a7304cdb9637b75f1a054d228c600ff5466a4df03cf5a2b53c367050e8e7179be9e76e8946b9c3917d146c43a78af0756011af07245aa3d74c84752f9b0d08024c532b077221ee8e695d66e572a66042e65d47a505dca98578c8adb02f7d1c2a94c83f459d58f5ed936a9274805dc4ec5d29788edb8b6818d3108f0b73f733a623b08c15e176e8a40cc179e8371f04a55418fc081e5a9e9d2dec90b69cfb0ede5be668284e337c7a6cbc3209698fa366c5c413e3bc0b199c31409c729abef337ee7073b9b1e529d3ae0418054371e9da6979973be3c56b36e12c85374fe238865cfcb55e5f30ba80ef00d2bfc2c79022c8fcc31cb137c6a878f9969921d604ae98899e9d519c75d95171073f12adf00a2ae17d0940407ba4cc0cee2bc82ef564a87d5b0701df35e417cb9a113ced67f0af049aa5953c3aaa3bd40a5a8d56c8280c0b12d4f0a3ffaafae3503637c889eda78e7faebe83bb2b7c353ac04ad8f36c3d4e587c5ec1e0d63c2484b0aab8b297ccddaa1987d96be1209facf100166d11a7d17203d6950cf1cb3bef2ef2d4039120464f7f828f3f7bb99bf82d170ffc320f5f5bda400fc6a7f300e446033bc5f7ebbd4217d853f379fe1b197a3e1b3e02166f4d54394fd3a014b1ef6f3eeaed1cf8a538051b192df38f161a1afda14768b792c609e0b612c2826995414413f65cd5c6f827e922e8b8d5cdf5016dc62db320a212aac3d02a4c3cbd86b6a4381d27be74b4b718502e89886aa485784f20d6eb07a878886e2ced02a9f34d42016b8114d55eb0ce2efe413d6f0336ad4294fa6683acfcdb79520688fd7a2db9fcb9f3e430a24b3ef359467b858b3ac4aae79ec836c62184c2d666d2b1dc3ccc21db6dfcf566689f87e5872e7938524312c563545c8c7c187124f3dd1d4bbcccb0cb654d32efe785d4afa96f5a6ff9879ad1f93bea579049e46edab020ab9e30a9e8e9be68f76e2bc02c51b24328eb2a6d0a3bcce9e4625b0a9bab52b203b50fceeb063d898cf3184f400447443eda016f1874631edd5311134d726608a4523e091b7b8b7eedb22d9826274cf4700aef3f177196bfc1f92e1042be2439c77b4bbc1dee8e5ca28a69448a9014a1a9fd2d5d14b3103bd7cee397fa9d4e34f097f3491a49d50a5fe66e00e92942740839994ff9a88db1c00b8e28102f61d2e0a37e228424a33e8cb64024d34a8de220cfd2c51ba0091c2a227dc84714a60f0f9e4a0fc04cc852542216c5a756e33c914e18e3a297556ac19ad2d796e633de97daa53ed0d66ebb8153f8cd2fd01b197f9c8f3bf89805c694edf192fd134eb942f37820971df1bf096eddbe609563e7637891ef1ffd8c1f557afbaadc7de1cf4545647ce41e51444591b072431c4ec6cf094c2716c365ed2498a81a44f4f10314b15927dfea8c012dc089549f11800b76680a4dd946003ade35ac309a4c420a7517cb1399d5f8cfd91ce8e8d92dcd680b66e6dde5902a4f86df016007d489413689c72c2d4088f5535aadd953295be45b2edf2282593b14f9e77cdd4af04c2d7473b1d3b02ddf76169695ba6320271a1e0d33a00f50c024622c7f6010ece88e03e0e238af667af9d72582dd973e84bc5477593c5611cde8d79285b41c7096313bdb1431520acdae2c1368a2fa5fc7e2012f1d23d355c2bbd319471b77a22844af1566f668bd54b52b4500bd8887a037a843b747bd46dc97689bb32b00fdc518add482328b30461954db7edd1b158a3a2d97caa11059a1bf397ff81b971bd24e8ad96067edffbfa3093d7e9f34639eb5551f3d6e9bc1743d8d6f98a66c9311a14a86f761171f931200ce45d62c34341ff4f677a24b563309b3441b799c2d66b755ed84c571ac1a1747a8e2d460ae239814c142b6ef7d0f1328e11b620b956b5c5996372b9305d001ff4bbf6197fbe40f62d19396234191ad09cd27dcfa0a1410ece3a7355b4e59a6ec71da467360f0a80b9a47fb212dda2a3b2823822511289a69f3a48f6b913207d55a2735a07333f283287b4177c55d1a309be5287b23b94b4f30597ae7a843797dfc04d9d32f3826138f772116631bcdc1f0f252214c0be07a269d9f92e09071221d12e2f4df8e846d6265f78dcf95a07a6a66b2e054cb1f401ad7abdf81bc410532741465850b06d00a282c81561daac2a7945894d2e9ddb80ec7e84dab9c9444ec9a48aeb0bee07eecfb87b305762aefe45e613a62b2e1b5cd2125b945bf346aedb4f1dcb01ff20a70b9d55d445464330a0365ca78ef64c280c25e0f2dfd1f90e9b3dfb8255db412b2793cf91a914d66ee574d8c5481275f2ffc0bd20907ed232e40cf572f650f3b9b20df3c1da05cc511eb1cafc01f3460520d59540608d83bee506c9d49c5dae91f91cd4bf6af4e7ba7ca1913e0e3d22f3fed6f9fba77096a4bfcd09b47f26f1ff64785634666c682e0a2113af42955a70d68095e9567d8d65a7af37ef9d705ad91428222b88276c01a82e425c044cceb2e4d950d3109d1d1f0497bfa5308782de55e93648329c06aa7c4d0216142a4371d0ca5e10e08afc4eda47d343c37b63dd056e5202e3d397c0d212e66a5f1d50406d8c0eb047a8727d7aa0a6f5c24f27e3be894a262862960318f1e3b8ba8a44433f13932945e0108d3ff43439f5743501b415c76d031acc351ca63299f8987ed37e74d7b5365d9057d7fc72a5f8baaaf0b107b854887b09cf2a1c25a684211017a66506fdcacdf4067505129a0c93cdf33143f0cc6615644217bf6c9e21138174877b948dfba3fbef1ab9e99d5a1fdd4493b98040f186aedfef02e1be02e6ee091b958ce8cb0165eaf629331622a5c9705475faced7e17483e220dfa71cf2ae6b04bcf9ba76ad7f2fd8a07d23a8dac6a99ba8bfc929b403f86c64991af57d8c68d8c820645189038691069634454286100704555d647db9828d0007fe4409c9c35e1cb0fa283519dbd3bed45025b60a8e83c487025fca91d8e3e3d828d9a182ff331ebf1bf5a7244fe1edbbe172ea0af4ffa4445a91d168896e42b9f108de91866970c31b6d4d496e00d6f321c933781981aab303bddd364c6ee14978f6dfb448cb4882843516417bbcb6abb0d800d812d2bbdea9d3863af8d9e6af982d0f4e95a1d53ea25534bf23080f6077ca0a2579a5a810dd8615d6ed065d0981a13d10e0215410049c4f949dfc343736edaad8a42d443d0b0ef5b0a342564da2959dcae5d02014c8de1b16f15c0c4db6129e6bc1c1ae74efc756d3d74aa2eadf1236ba95ac256450dcbd78111bc9e38c0aa0c989f6c0d11169ce76ad9f1603eda75de1a7994705748b07e2fe33f707576c80983a3ab82d9235e63dcee29eace753bd8d2e766cb8966be84d9350bc082cb4f71db2e50c1912acf8766193de087a5cb51ae7897a423429b350e314fb57d0fdf3b7419d72c257df3587c919b6dec98ef14278a6c0eecdaebf830875e591f4aa98d9b15c99aff07071b1a98938496a230159b9bcb091b064d44276ac168268246ec19bd67d56453181b12e453ce92666d5ec0b18008d0f925f8188354108fa508834cfec3f84fb836fd40b3b6ca1d7915beb26c88ea44fc9c7de840d8d65cb149ac6bc1655923cb48c449a36e94c256ab6baad13070991588e4e61aba968630df9cf5783a7a0991a8593f0fc7f9fa01769feebb28e8dcdcc77b10a795b0650b956a94597120825018daaab3023cf6091bf7a9cb98ac96078f008731512a3caacf61e5f764d8a57acf0ee61661527361ead048be13be85ad95733129ab05e4d521a1da81f08107e2bfe8bd92533c9d8a756ecdf5b6b9619430b0fb5e4684d0260048bba35ef5daf623938731956b3eacf37ddcd8e268e3bc5351aa6b85367d7da0c0cf37fef0cac309182b6571fdb08775d887e75489865b6380c599551204a0a21e51e7cec8299a31180f4158b573c5cb6d3a8a3bd61f668c36f7337443d231cc60778b249ed011f3c5ac38142cb3e46fc604d40d33084180a7e4b128d0b5c89e25c439179318c088359b3777d2c4443159057c6c5043471bdde99710b04c10999538670a290935cbabc7a2129441b426c046d33421a35e9168b8d4b1b1c6ced3adaecf038539611e5a92bb4657cb937e775325d2e0b5953b448e7b9cbe586af04d7c1aa4442e8813ee399c5fa3a9f58ba7fdc6865bd27df63692294d041a158343aa41f4686de6c3e92630fd906b4c3b16cceb174e2ea7e58ebd7447d3a3d11dc5cff66820d6a0c7364092aa0be5bf0f8d6923bab94fe830956799e47c1c430c9bb6b6dfc9a649ec90baa78b2b359b288af9334259a3bd8c3437ed7c884fb94a0e5eb7ac86471d57f865326cb15618681198e001ac8822833ea83b2095fea41c8af99be51ad2c97308e88facd973845286a98a592e86f5b93f2a6bbcb72ccbe03c7c21009ed392c86cb1f97b056bad56aede49fe6489ad9dff61d489f59571c88fb64a6d7c2019ae3e980265cb43a44e8da2111a8258140c31e93c5d14503913a705a1c1e81edfa348e06d9c28b4dda02d98185868145cc43d72187082c388ace7e19ee9e2b30f4f18f25c9545830235b46ed5838ed0b2b8193b8058cc0bf5abe9b3733a735e2e61ad6a11e435ea32f77530455aa65c06be6d1c74b9e9d385d4be1e41856f62df0cff507ef5f99717c8c98ee151f72a828472a17e73b66c303054cab0965aca620beb0a43996cd91427081d585376c4f04f58e5f74387aca95daaeb2130dbc08acb4d9b81a4f98eeeed61c050bbc0e59d0a18f9927bc5170e403da59663b295e98a1797e5434df7d8cc39f785b7492fb31a65b4ef8b791f26acc252111837b448fef81b9bf0e6d24b9fd718abc11dc1bbb103a5643d45d504b467364907c7186df40c585352abf72519e8c73abc055a8e44e4d0681cd89dcad907254e84ce83b718a1b643a6b564004b9eb36b7340e834a08ad0caecb1f2576c400be6034647b248d2bd3f8a7c6b037034edf8fbeff6c3bd04f3e952fa3d0bd93673bc332b1abaa31b2ac2792fb742fbfc6d477c02204423ea1dd55eb3a0e9acedbed6f182dc80747f488a4d9cccd280f6355226e6e0473f3805489e77c3ac8b832401011f97b6283996d347e97f98d8d639e1142626365a3f186eca5da5a39712ac1ff366e63f74e8f5c4e13f40915f3e1fee2add369bb880ea668564c2d1748035a13c14f42f65c88732a26859a8fcae53f0d84c593fc8d9754df6639d539cb612b90e9ebcb9b0909caf258aa70fccddcefdfb7e12bbe4d9662936922e31bb927817be35362efaafff252f493f97580725810213b3af048ed0b1089729f1705dc2c1572a9060e1314454b57bad6f3505cbbea99fd98490fb88dbaa56ff2221f6faee10835f6e4584e8152668d1715677ec9c70bac658c2dbae6a9a8f01e6ba59b85df1cc63c0c893e04faf53af156a76bf77c707478cc177b71e5f90f9cb422f1428467b6a7c812ac44e81a38c9cdf192c85cb74c727bb016f9e40385c5114e99bc48d5cc0fa09cd763a9d80b5647ba643b0d85d1e288954c35328f1647bae4a7915db438f2f8e3f6d2aa88718ffcaa62af6cad51d435dff35f2d98c61ed1ee68399e8afdbb60aec14c7baa63ef8c38b03110d8fb44b1c5e9b293cd10f5bb0c7c3973f7ca907fdbd72ff83ff35011d0d1029a63110d1702f9d7e61827adddc5b1068d4a3879c252e494d88c7c0e1a77a7df12934e405e00f4e2145990404c44e284bed917c65a083982e55463d73ee058051ed2b5260c501812236ed8137268cfddf25e5ec40b74cacb8c2684c0df7a19fdd7df1346813994b61fb52800d5cdc878571b448da9320894a8269813e96b19fd3ae5a76a4990fa817caff7b9521724243f889eaac25cc377d6df64c9e501d8d44b30f71aba685f85b1ae9857a23d133cb47196b807d4ebb8766936c28bd58d5acad1ceb31cdb59a6826f25cf866d430c3b34af96d174df7a6dfc252cbb0dcf5fc15946a3b3253380be242e3e40079cd26d11c9e730ed48043047f81bca6523027f88a364ecd66b2c083a3dc3139907225dc66263da3513e49bef5ae844c9e4ba4abd3a2ef82f0c31bbbdff516f9d879bba8a8ce59133464d5043e1b1101a552c9f29661e6cc3031b478bd4e1bf7fac6b79e6c09125ce59988a7d1c1b7c278ac13b79f275fe53c8675a7509e6bd4ab87674206cedde3e9af682da4c76bc8b33292013c4ec41e5cf0e71b5becfb528190b58832fdcdee718987cb6ab679bff3d31809e48628a7269abf99e4ec376cdba18aadb642c990f12d3a017e0d26c617db836d2d0296a36cd4fc189050713c7bd7963750bf1059b73b1614aafae80bd0c6e2552abbfb352a34f2639499d226177b22adfa30429c14dd992354800c4b451a374f55490bd6d02d03663f3f0da91fb52c671634ceafb7b7f3e7499c3699c130f75afedc1ddee42e5940f73ce5463f96b857f0073f31476dcc42929adeeacf672f9325ba53c189fe2ebc162efc1a8478fdcd805796455cedf8ed31e87b932b751b006a33246cb2beb94ebe44a9257a5983fd1a9d9f317d3dd10bda11438323283335bc746ed4bb74f4e3bb98d559d000d490ec843cfbdd7587557d462f09ed0620f52c5c6fff7c54e4d593c3341f68405791c1e9b01ca233f029263ce65ea386b180f1e7a9cc5eee69154479bd017484f03269e4cd7f60226e2801227012f713d6abea192cfa6089383c856b4ccbc3c3e3845a507a5051dd9be7c885138d7a1dee1dd6afda4d84aec3b7fbc31c6232af11234b3a0c95c4e4a4e5cad9b56b8b325d69c257a037f38d293feb77a59c1102504f5040612f6a96cd6bc5ea000a626249aa85d0b0fd854c68217e9db8b6e0b1fe833d13f5fbbd6b0788e64961dca7c6a9a362aaa58d508313cc5fb368dbb57f48d9921633a92256bf49a13e4c00369f7dc4566a66f46732945a49baa75198abc50e170373ce3a381cb3bad4b040285654572e6c8213e2d2b8b4407160d4c17695a5d5d9d653b16a12e39ba490ef49ca9c075f2e01c701f725a5198095803ef4601ec5432026c8ed9d33dc38ba021458c24323bfc2345e006b5b029b0434f28e04280ed1443058f53228aaa314cfd1918c2abe80c4aae3f5582bef8576e4ca7a78912fdf9be2ac9d690852cd504e07e59c8faf35bca2a785417339674292cb5a19659a8a98ce9641c48c35dc831bf61d24b09c78c2b67abfade50ef405c288b036d6e4cac9c1271411af959235f602dc3e4e7e882406110f4e47555b44d04e788956e33439d81f33e5c318e1c156e148c10e003d6008641c26d0593cee1282e5acf7dcc4eccee4ed4b36b48ab3ed1b274046a83a5f102f808aa17062dec3324a1e1e6d415ee1e2257f3f93400cb5a6efc1bcfc517024fef04e0a95b3da94d40aab810f24943854a10dfb89b9cf9d0d10fb68a61085800ba14581100af53c3c326fb103c3c9ff012d91db2d44c31579f29f522175a470c89e8adc62bc1a57113839711395c94188003edf748e477550387d636b3f04debf1d65c1974b39c75202235b2ce9e5c5743148224632df292b88bae45c77ccde542c9ca16864ebfae169e04da5a365b1714c72460d4d4203e9385ac86be04c99b090bd2a071e28570b2f71a360324c0357adbd7fcebc8d65c1693c74956ea85bf6e7d823c0268c84ce6a57c7b48e23205e15bd2a68f43606ef4e8d3fc2a1fce594df950c95717af73c00c845b10e3e2fd1d168bedd362759654d113902de61c25859292b152529cfa200dfdaf6161dd96585be5a6dd9ec6e5decfcbbc5f78b99b18b9481fc8db9327b1a384991109d01a804f38756aba10baa0324c6487e339fe2b0db6acdc1096c1051cb303af0c8278869ad1439702bca63293634ddac1856f0147b082fe6332ecad08829f34a72cbcf969c5a24cb1dca073bde74e0cfd183631dbdb1870c0ffaa61d82f80de0c6c4d616a3117574a82809c06a4883ca63e0314342550efc395355540dd8bb8e49c844818784274bfd86465350a8987586625e41bcff984f6edbb440f1ceb42edf8c759aa184f3ee9fd0f06fa6769f98062978f7438d36e72e55d9ab190ef09b27037e477193157ae7b8cf9e808c3bfab668ec1acaf224cf21a41ae7068a34c2bc22a518129f7794f966369dbaf0984c3b4f88d070ca32d4b988c3a18d7bef087233d6ec03cf20d768d41c5e1eca012e434aa1412d08026a5de46c24cc370f8d387030657ef46d4e6744f342070c77771be046210bda3e075d27a4626f16e6a87afb45c95c524aa536f00ae2782aa0915cf5e3bb038159038a58ba5d1824cb04a237d7a94a842d3bd075a37770c7edf0dd11b20a17fb12c05a8223278d57788109a721b8052b0d3cbed9eac8c48e4ffc83e97bff6a9b184118e2c09169e79e16881127df462fbb4f581099a6031e7d8380b9f5499640dbb1f1a445d02d3e9450f96f9c8a5b43eb4e3205527da9fbc799eb5597bd8c761808add79c2e59d0a2161e02f60bcb96d2013f78d97a519f5be94a7827ddae8f6af915671ae50716b64098a2d9b0e309d7158b269248dafcf3666c47cb08d52854803e6e20ad4173e1d7a683d63b9b487204bce22a2f18a2ab87f0a44fc846a3e4c728c2691caa226263b1fcd6a821e279269d0e38ffd30d852947008a180bd1ab7e431a8fc83585c8d8968ee6fb2d6daa3f695837eb558064ce81d3e4f23362c7a30b8def0e1cad6b527ada0df038ed347461d956e7fcd60a7c98bd36b3021513a403c8148f181c03d8fc3f04cdd2b8f8e4124121c408f9f8cc945ef9169c0c8bf072c6826823242e077f2325d6dd0f5de852dd2af1fcfe123cefd014de7237839ef4ae393752bfc43bc6ef06a2339046561c81a5026660293186a703631fe24a76b13323b1509dcd7be0ae1cf6c6922f8013756e8d71108f02ac42473f21f80d70e710e3953f5f1690e22bbb3b8594837409e3eb7519699ede13d5ca6b0aa33765c198d4c0180b2cfbd743afc36777a346276e9fd27c0fc58e10dbdadf3cd45540204d718cd52f8d87313d44fe9b6e9993e519127981878a32203437695f21a5d421d01a8a5c68de7c23042494758ef5d344ca8c3d063d4cb9a570e736ec3e824f575e5d59093de70b271359c5491b5997d2825a5af0112b89a96897d93dccb15ecfeb0488b83d0f731cda2e920e388728daea48b29a32b1adf517079f3345fb296e47365df70aa9598a735e317e060f8a9eeb5c2bdaa2372c3bf5bb2fec4059703a62a0185f0cfa94cf734cd26ed49c06f7a2149d0e7eaa628f588e5d5afc74815b24c04d3e0d306e0ee0a4954f2290d94e7163d5722252b18561f1f5c1476d6b1d75d000c0cf8de0aef25ba24d976d7a7d128d4e2f9b1b41e6d54d5d5bf9397ceef6c311ae8b3a08fad0dcb013a1424a22a65bf7de311aa487bbdd42e7d12797fb46016fd41de6effc87ea790049b86cd186e31c56c448b8554c416482c96d423bf7e449250ff8f1f35d52e07b3188ea7379df6ec42bf30129fdbe06e08eee3481d8888e43ee481bca4363aa6800f53f4877e2ead080625b3e0bd0c71f16640996830d79e5340e91ca80a94e565d94bf4c8134504c581b878cf64f3e87f979ebf9c6a8858786e028568580422ba525584c8b24ea4711b217034fbbe97b3aa73824ddb74df7baaea1fb54b7cc6659acd7c2df81ee5b88c1e7e6b93c82fb04af84b5d583e3e4cb2ebb9a32191397f13b648140cb165fd0803256269bfe1d4020e0c01cdab84f30c5d2b11d43a57c7c3ef5747814508607ec20ca4645a1a0a3e2445d96ef6dc5f7ec5c7c73a9caf42252370b34617b92974017f9924b66764b4e4ecd2fb5814afb2dd413a8a9b12183ec19fed07b5d3839a2643229051139805de8821b962e301161321b1823398e7c3ad40cf155bbbe254af605d610aa6b9f2635b5c065c443d515fd49594053ac6d54ef8875631679637d65f12cbd9542812b57722090da030df62683e30095887a65d7f4e28219f3ed27bfefdab21a31b1665fe59101154698ba9327ee232453eabc5cf943d7e14e33ef703e4b00f891b0e62579567ea8df6063588001fc8edadb34c76cc8f49fbbdaf152e5f60e11285d13358869156283211fb0dd002962200707290494e6a6d07fd22cf3888e40b44d7f8222df9eef51ad11a94117a706c241cbf573f44f6fd502fc345b68cd12ed202b8b89d1072dcd76855a410c889923400d1f68ab640c0ce55e27d8f1e5dee76480523b45abf216863e158ace23579ac4fdbf069fab8476a3afc580859d170050d2d39086df7be33bda9d9881e7a788de0dcf7bea40905a6bca36bc2d04dc81d692a5e11a7cc3a6a7777731c40651a2b5da7acbcd00680c5d476a74321c9fff4ff3085b7eb36103cb0bff1e9b38d0e398e1f9d67c22288c1257ceb910d0f5942b26aa0e31b08bff4c1aad1cf151a952ad91ac6889b2a79e076ac00df04183578208305475e7453d6abf66c03ede7bd3a9bcbe386ec8b3e56e5b3643d97164a06a4e1e04ea7c6b945071fd73c4e12275384f4fbee39271612add7343edcd19048e3dbc72cf78b90bb2927d989274122064d39691326317055439506bf101c5c763070f87fc5cd8233b1c229fdd02a64bbf2792b86d864eccddd7c21a133846ad737deacbba40342702d3ffc1e8b83dd2c273e0cd7bd2cc7691dd290118a64c3965e1615df8bda12fb1218f3b5a0c9f0f79153f4e4590436f6311a08ee66044bd8b8a534c674385771d0d513fcef14b43098489126497774c0ff59ddd5de28df632ccb1a353b40ffa1709a40a073b303ddb557532422aa850e31949a768b4e7603cde96d075c87e492d291418bed49b96cf69e3c651f33247a5e9400c698bfb665b3d5a4addecee71c0057c84847a65a4b0af2f42660d02ce4a8a8c907484038ac40e43092aa4d050bddcb00afbbd70b253bac8233b753990da2223c17f2f03354f4778c8fd6d8d8b1f43c2b7c02e809c0ad65822e5b1688c1f70f0685d0c31742c2886793bb122ab3cc047594d387930b10adfb88ce10d84703ddb75f393dfaa24bc903643b889611c7b03d9b88faf7060b5c43ff8464a42514c8237f1d8fb11bc6c44ddc952f56954350945a02a4fd537c9caad27f120bc8e3278f91bf2b68b998991b1955f374dfadf87a978aacf0fa253743b735678f36bf52b1ff1783f92589e1394568e5c7ea924048eb632facbb07aff3456fa96ce301c4904173ec82c728007a2e7b9402e3ae81b1fe51e980cd41b5b83e079181389507cff283a610c1d4b0aa06641344933bcadf5f6248acdba454bb054066aa3aac8f40a4701a20ad8594a6fdd14a6db03b961347f407058cce7c18cdb50661b842a081ccd7fdc0de7a0f4428b37fb09ff1da08e912d083ab20f3e53fbaad162aed0f8bbff263bcfd34978d2a78e08efca093ac15d8011337bd7617c001d4b5c45253fd83edf9151f59b9b280dd531b3a560b21d2aa37c77c9d25b83a343b993740bc5e568e49f22546a8599d622874e276aae802166b2583a5b5503cef5ae8f1af4c6e5e1314be8ffdaa512705cf7008f849a45cb4c473585e6f892c06f620954f76a077b3c92cc62ca368f2de1847a8b96d7eee47ec584bd8514a43f8ffab21bc07b41104daeb82995c30ccba9a0e251d2a102168e36481dce2c0d163f09bf18284e080c6488505424ba5c256ad2ca04381c9334548b60574387598b96fd7f1d76954156f4dfc445d8b88ed585ffc2104c7858e5cabde0b8da691496b7bb735b9a594322519d9095c094609453b64fad3484b9e93274b261268594af776caad6e49f5bc77ded7bfec7c4dcb4442510f0da81f5e8061ca0b9313198511605831005330a165cc172699116392e4f900f0e1872ac44801922d26808225082856386fd4336008c0194c9c0126d7c7e027063450810214966e505a413a0d71c39c73ce1e6f68ae7274ace8c24486972a5670c40a9acab0a18c33c4389921e50c1472fd1ede50ad2408a28647ec124446d1d413793e8f8e183c5480058a29a35c7f07930a78c091eb5f20450aa6b0c01baa1b971c1480494111b97eec36f9114956cc39e704bda109801e39cc914222d725505084822272fd1d6fa8ea3821b50206b9be0e6fa85a219ca0c97133986fc7c832c60a79be8e37346f5217343806500031a41003863c1fbf5e4c4a00c316585280c20a098510355b2b7e07bb5b8c10d4e4f99f373473c894084396411846e4fa9f4385eea28ee45adf460d91ebdff0866a17f50421b07202a65cdf863754b7271d308ec895e96b784375b3628a1f2576f80835608a57a2162f9074783145982861b6f862875cbf07e88b2e72fd1f4082e4784375bb225a10ee00a36403cc152610c204b55c1fe60d551d1474395dd472858a92ebbfc010e5fa34b0121266b821072eb40c219f20620515ce1417f8708145174170a143aeffa242b48af7755dafa09ba6e2eb17242e50f8c224d7b7f186aa1135d4787122cf7719d9e450e143835ca3960aab61b8d428c68a14acb0a28b5cffbeac3023d7ff2b9ac8f5412c72c8f57bb01893eb03d5b8e4fa3fb21022d707b294450a725dd2e2895c1f842d74c8f52d90812d98727d225e6878bd6aad482899894133edcaf34a9729baa45053830e1722b0105197b8c872ad5aaae821572c5e86115dbcfbbaae976b56c18214797ef73a620bee36518124cf5f7d3184956b9b9e92c8138bce9309b9d65a6badb5d65a6badb566b92087ae297c9862cb0979fedd52459e4f5f3f905133a3531679ce295158b5d65aeb4e9e45042db1f7058ba2498597164734a2c832bbe1128563b7486293b76d73bdb098820595d78d422a494d97292b6437d784992b8b231b1750a0a9c2a866861566b67072452992a935d14c79e1621135c3840b2d2e453258acc0d262ea66f922ca66191343b785118b89122e8b266f04ab2b689d9621544f9c653a62b718ad66d32ef1586cf2c4633187f7554bb2802a9cc25861015a142d69197364015434a9b0002b8ea4a02149920287a2055cf1248514240be082f4399a4c6dfdb295564aab8e272e8d1c9762b872e472392ec5c0c50a3184912403d113198a7ab85549d365d174b020430e3218b1e446278ea0e59d2519a05892a1cb7dffc273bd9c80b224d39f5132998c05195680a48b4ed470845ad0c2ad39c18223eeab091597660af874594a607155392e359122ff52932b4ca83a4930189d48622ad31c645cbb45cce8da1c979a7851c495c971a9c91832382162e2ae725c7292828e14eecc71c9c9121b392ecd30460fa782eef60ebcd0c20d2fc8eeeeeeee186eb6736d312846cfb12f6b73fe25c494835105827e3ac3c9184252b6a726b8ddb382843d665cebb13e2342dd07ab5f2b16c27a0e17693deb8b70dfbd11211ae74cfeb45e7ebc2dfce2aecc7bcf61ef693ecad8ccdf6dd24209667e437ab2bf63a97463c60d6d035ac8fb8ef5716db749eb240eb7928c612bb7f3be48eb65dec345baafc1600d4c9c47642d066daf3c49c8128757929125966164f9f3732207392ca5c615d785a5918cc999bf1f8258cc602040637ce0032d5c448a90d6771f65ec65f007baaeebbec320f88005eeb7f0c5edf4dd87f1098b16b64464cc7bcff3dec320f80057996e7fe8442d2ca50616f7bd0fbb080bcfc718dc772c25077fc95509799f0ad75f853530a5d3978bc3885b6bb88e8d3c87e0affaf9e1dce0aade5ff5dc6c99a3acfdc8300ee563c70e9dad8ba1edec6b2a064510f42efa916c21f9124a3a5296b827cfa2e8d2684a1c76b307190b5142f16f0ba7466beed3126ace6613ffc148618ca498299b4573891f492319258732cad1e752554297e240f553314b563df7f50bc17f72d063f2064b407dfa1c547f0e749e2a2712e33e2a1c420d679e218ce0b92ec0e248bf10fc371a427d7ffbd14b802a048b00bc7909880e4aa9fac54c9b62507de95f8b3c3f93c8634bc41f9985962b57644d8350d67cec78bd646454d39f1479d8978831f95934451ee9a59f6a2a2b8e43764327f269244a9e1ff3c4b52831b2d6535ee38c58ff1870f800e4a5c28d1ebee1fe7020b2d25aa794524a29a594725229250754f5616cfaad1be2c2ac94db263729e595745220b449bc575c07e2df06af136ef430941b46a60dbaa393d2de6c383d95f3757c839e5a5cfb405cdaeda3106c73f78a9baacb7be50c0264851b9970dd95ef6d822c4109b61792bace1b6a2d0e7abb3bf548bd9dce0c8c9cb41c4d1a35256530dbb918db5dab238f1affc3c01e5f7212931d6a7af48064d2069bff74cddbe994d14a14145d249ddd1435e53eb2a1c254713159bef5861c07894eb20271b3d70f241079e4ab96b81209cba317686e28f9e3a2f93c8aca55ad7c48f58ae72742a41f1a41c24074caa111a41cc2fce6def5c1fc6dde8810cd07f3a22330999f79966c72c1904fb27cf9c47d4287923469e4a054d17db9c47dbc972f84e65d2ff33580e65db2fcf120dfb12bf9fd9c8a741a6e3515717dcdfb27858585b8de0617b179d7d77c456a9ee6af1897bebf74288fa202459372b0dae028635d83a3941bcd93311eb974d93d329c51a8bfd0a964f93964dc501ee121aa57492877a92807a5fb181c675cff469247625c9d12ae7f9d5df9b11eb9f263457271686404528aecb8a37040b961877941b9f2b54c18910c4b40e71fc8c854ca96c1acb8321ca1e6f72f00cdcb775acf644c65853e31e2b8012021414145351d4509239dc8a14b1d4d41426a922f9f38b9d374b8f2639634ea94ce9671b21286caac84f2c88a54b7d42487b28b4c924c5dee510cdab23c8a729fbcf84f902c2e618162924eb24ba52d619dd454a46b4992f2a89564902ea16a209157dca71fe93aa883918ecff151e76b212ec77795acbd5729c7176b2c71e5bbcf741a89ce21c7e74daee40298b4d3f94c68a1300ecea8e9f704b7a1ba269b24b9928d25f746de799d0f811e082e4ebcc0c504a83184e6cbaf6b2e80f939e6ebf86291ceefe0225284e4f81cb888fc4d8a101daff345e4e7f8fb51fee8e022fe3a709431d6b33ec71765ecfe90b1f96ef3fae834609f63ff7e278536bce12b13c1f11dfed5f7aaff1b4f3f4aafc6b79e88fc71190e1cda0f87afc7e1dfc021986de01a3804ca3fe48f7b7197cdcfc1a187c9f36138b434f00b872e26cfbfc1e1cb06879228cfafc1e1bb300d0ec1192c83c39efc6ae110c89540599d5f2beee1121163f3ab402d912796dc4991677e9ddee4e0fc39abf48e945575be28e4440e4eaf1263f39700b1e449c5865d8989eb8e83882b8dde5949465d6ef8b1ff2a03c04028f7a7179e73832f8932461bc1eebb1122d87d47c4ebb82279f52dc580b2524e282eea6c51c6de5e4e1d392bddbe5b750772b95b712b1528bd0d883ba3cbfd2d3d9244942a35262644a13f29729f965522134d2abb90ea48460a555fc6c9eede906398fc2f7706024b0e5545d51bf24ee6606fde90e3d8e28676ca4e5931d6be5ecf7943931e1539d81d11d20d3b5957f41a81aabeaf2bea64f4ad980fcaf673fb8ec83b99fb548fe2b1d9b9937545ee13ab4a36e52086bae12dba45ee538418395415d12197dbff70ba750d1c2e4d8e5bb68c206ba0fd48ca7268a537646be470433f72cae176d4e3847b73e5aafeb574433b7593c4a54734949472d8c972ffd1a447b9df33923f5b918cf51fe5de68b93ff490727b49b99f4611eb4b0e3d2bb228748b84b8e1565494fbb7221bb7a2dc5fa162cc63ac50381c52a1324c7e14f2280e937f24e6fe94e4e1bae34e8a314a96c450b6ed3b6a2a777f03a6d086ed94dc8eecd496d4b84706e972016b2f2d6ba5a824d418e6452fd418d64d2e112b640a3586f513b95063291c44107463c08893a21cc470e1c315412c49117534a3a2d4b049c0095210484b556c01430b162b284e0006892701133932753ed0b8187f36b757c6a8c521fd4ae9eb65ed638b438c514afa93cef8515c8cd14b8eef4a3551b76337998a5a26b65de692f27cf9752698fd5eb38836ec47fa21e0d0beea6df521752d8675509f6e1d1ac9f439efbc0ebed0089df282b813417ff9e188608f18f3ffc99e43c38716f24608f3733831ac83cff53fd74975b044e83179e27f9593ab56d56e5ceb762c4f86c635f3381fbd211a35df3eab5d754e62065ef4688841d5d5e3a36bdd97f9f845dc87f5f17be623cdc7ef27add44c34c2d6f28adf556206eda57bd87cd84b3ff149e0c2cf0cc949f48f42d481e8df474070086c890ae81efea01733d8d13dfc77d830176af310503b281a384d5e5e37b89b6c70e85e831baa9110e0b9c6042e9a9e4599cd198f95813e12f552e6b6820c6179386c31de6db647013d3dcd75d4d7611c7429f7b73874a2ecbfe1b0c5647f2f76646fa8c8e30ffb0eaa280639ecbbbb63b7fc09c31d06aa4a4375e1331c9791eaf999423019ea8e0f2304514970a92d2185822c4d542c2b54289c4890274427011347d4b6265078188e7208eee8f172648261492da1d229636cc5e860fc5983129b5015a24253889b1dad1bcb0acc4686f5aacd93a492c478fc8ebaf225c7ee22c76f2f3108a78d9cdae829c6be32a5ca94a51cbf9562108d8f4528e49824472639badebf9fc87cd84744eda489688841351f9f7af6145bd64443c808139f480ceafe87178f31c6da1621518aece4b129c420c7171283bcf701a44190dc9175a2df9cebcaaf0ee7a3dfece2099c4fe626314a5d3c71c3062c49eaca97dcef44b98bdc8f63e3833dec6dfc8d1b30182ceac6d719e7eb6c03ca0b8d8f7ef3937949889c1a9fd3942a35a4a7a51a9f8dcdc33ee7b9ce1bcab1b1b1b992f375a6f175863129d1f862c6e9dc45ce247751e4a9f968cd376b3e995b0437af2f03dd4e723f95dc35af4fe665dee66f6e6464648e6ebece355f679b36ea2691a7ff8bd945a7ccb532c098a1f9641f74d110329a06d5b35a19341f8bc5adbca119160bcfc88821e27d747a9fcc718ad6931721518adc2fd55bb2773f554b019dbd272191a7df931ff50264a7ded413000d72a62a4f0146b2ca474f4b47d6513f2ff7fb8edcefad93376fa8d6ce5de4e98f3987e8f63bd9e818153b2bad95ee94e0cae4c8d40253d1f572646a61881c2a6801e97e0b32b8a0baafeb7a41c9335a700188abca91a98523605a20daa1dd9a239392339894444d2f48321633a53b3f5c1a53e8d002450e9fcab53932295122ef38a14409dc40491253922472f83d3d4877f98fcb63fd4aaab9b13c57c751a970707ab23eefeb56d64655b3727134b6bb92eb64951b9098251ec113d063c68c19d31eebb65a57a6a37165a51c9d3ca95743bd9a1ad652afa6c6b40102410bf6006d30326e38694c98bcd1572f8f4e2b99ed7dfda42c20dc6c09c620dfe13e1debc8838100727f3880ec1d1b87e6ffc69cb37538295dca28a594aa18a5a4966e73d6bad139638c314629e5cab9961de99cb3fb557fce3a65f458364c5c8cf12565534a698cf1467635b8bc26add1c53bf2dc2e8a09e46084d9703d3796db6fc3ed0cb3e1469b29433a5d730c4ae30ced628c118740e594b1975295ce6c49c97594524aa99452ca158beb28a59452cab1ba19b59aad6e46a9ec94895bcf50cab9bae8451c4ae0ca6ec76f88ce53eaea62e49194524a29a594524a6d7c8cbe2ddc7ef9b4bb439d1c256aa5b5ba1cc442d4248fe058667904efa93c82e777106f5b0e558ed5089ee387f5e72aabb6ca7539e2d75a6bac35c6aeb6fa7632b5d63a536ba5b17155cea69b33da5a9fbb795557df7412a0945219a3d71fa2e30dcdc773ce9b5965f64c719a4637a51ae6e4258fe0596a86f4e5770f05e7e33c75725e37382e53029d9bc5e95577f7a455ca2e5772b9b252dc45b3abb8928a2b7174b0b3a1a1abf1c2d0b470984564ae6cda9a6290dd2d251829c1483926090d5232f13061e84c1266d231b015b88a3b779e71b13dc33a885fe414814ead9bc579e5f8bde2b8ef5b71ddcb7d54acf8ed31c8fecafb4ef515c144ba2d534d42e4f1b7dd4d718f74d11204c82c71cfa43062510f37ad9b5e03a4d00a379216aeb3e96a3c8fe5b2400d04164d6bc6a99b76901ef03a9879cadc1cbf08526e26d6cacdd0b4726a60d5d874d14b6edc9187bacd0d2701073f887315243ae174919b9a9a542a2f9c4b94d3ac553d7d57c96d82e5745064efa6d844ec2cd97d065a4e8dce02c10a883c37861a366cdc90403d3d3df267c571dfcabfb8f118470caa407afac7693247cca0a3ba87bf183b56756b50345f254d164af4a7adc53baa33e825620f7f2f5d8c7237214613f7e1d078dde0ccc701135bc1cba8f20512313098925049929464ca28989220fd1b4d773a414b122c2fe2a27325994cb66405160a52b49294548832836486d73243c76ab574726b47abd5f25a1f8fc8ad9f2d26246372eb6f95dc6afdaf00456e3d8824b7be87052772eb8156c8ad99536e254912a3cf67cff33c4f0531d93be2c4a4c2112ecb9373652e27733f392e8527994ba18bcc7939ca036042a10935b273fb28c656837664ea23533a001aaf6090c3a8a50bcd804ad126f2c9611fc9b49768403f66c994bebd24a420d37f2165fa1f0231327db0042032fd9e12aec8f481984a1893e903214acaf48310a520d3ff000428993299e045a69f01fa44729089c08ba21e32653ae14ba64c011f975799f33af9a9b2cd5cab93df96b9dbc9af669ab9998e867375359d8d8b66a6e686151ac9b00e6e3a37f68091d92ea6a38e7bccb9e1c69f2a748c1d63eceed8dd91c6ee27dca42f99f8f4affc22209bd33d467713b8f84831469d3927954e1d989c2955b6fb72e5538a6d94f5ba125b1d816a256537b74fd2f9d58f66d5eab33182f4adfcb939f5bd5a6abf036bdf1b52596c75b0364c4509d9c4001de3733b5f1402bf22345000e3884c68e7b92e020267e14b91d0055f040400e0e2284a28f616c8b80fd991675ec6bf70479699f91fee9fcccc476f68c6a6c647cf068d4fc7fff0170a3766fcd6b5dd0be686b2c88fcc8e5a375afff26f73ffa68efc6cae09c1fdf79ca9c30d5f5eebe2e0d3d40d250ddf7cbbbe717c7b43aee75c2e3a66cc182c3947a5aea5399af33b1ff70dfe0e88fb776cb8709f06ced30f07e77f382725c5e108343ffd6cd89367ce174aa770484f479de04a263188fecb071d72c5a1acc1667b4614f9c4084bda279b3868cdb8345ff3f6551f4a1a77b3a972a85e7a43aa8ae36b8e987138def960f279fccecf0f0653bdfc0dfc602adc001ebff330893de081779ee7c1876dd8039e079f0783df12fcac8c71bf5357cfad6256e178ca89f023cf77bdcb254254ca12873ff2c421b85ec7ff70ff5cafc3e70f77bc4d11b6ed13c100746772b223e24ad294f6297d42975c7243b90ffdde41c096a964b1581deb6547955a0afcb61b9c100115b42652fe944e93d2734fda6c311996fb6553948a8a4c4952b925131130e4502a5dc9dd3fa52b2146892b5f02259a6c9c4d173d0e74bcebfd73fd8effe1396f9f03df88d0dc79f085ec3c08f3e78932362516b20373ac0121e0f3e0223fb003a2101019eb0fb283ed86a5c03e0af1f0ce87bcf20f5fcd6ff5f60b3fabb0857d21d4bff987b45f97f375dfe3e3b103fbf09837d46117eb69bca1d5bbbca1ee5d1feb7574cf7a6ef5dd2865afcd9a94a2ae92d39383c0fe90f31ba1f3dc70e0f78f7b9a83c3435e19c7db1c3d1cffc3c31c78484fc6f1f83f2917e7693c87f3859db717a5b1610cf4641d1adfde100dd8f7309d8fded01724e7619653b9761e076f3938b4301cde1756816190fcfaf971a0f3f7fd0f7f7da10e6e3d8daff307e5869396fb713c1ed293bf9f1dfe6cfe3e188eef93dfde3f27bbefc3f1850d73dc0135caf4bf8f59ca9c9e6a505153535150b5272737f223a424a5a626a524243f8a9a729917f98ce6349f4d452935393dd5a0a06a4f4e4d4a3d6b5a1bf511525212521fb551d37a166b112a2a6c595117b56c2aaa07282af5e0f1f100b953e6fe87b7de88833c3c7a7c3c3e1e108bb0e5b033067a3287c320f987e3577d18d85e7a43f8fffb42780cebc0cbfe5ef6778c819e4c7108ad973df95b2663fd4684769e87061c108544e0de0151087c1eb8481110708fdf791e1fde1e9fe411b66ce7a3d08e0f63144f186b418840bc835fd25a7eadf7aff53c1f2cc88e8771d8015168078e3226b4f3300f5a68e75b6807f74cc65a166b29b5fec6e79f94eb5fc36dd4a851a3468d1a356a7c9d6dd8f8ba461b19b9769ea3f9c2ceafb7f9866e705e62b007e855bf3dad6559a353df5ce539387cc1f04603d315b698c3385f3842cd37ef72798d95351f63cd4b0cf6b83e04ba71bd7f353fbff0e6dd1baab979aebb1b8c3d8cc76a5c51f2d1915f71b05fe67ede34d4c29ee47ddde746df852b4b9afc89427d5434739fb02ff87c890ba0df82afa75c00fdb12fba00e4e7448d50f392dcdfb289b4b966881b4db511c881bff33e80b2a4d5ecef3407dbc886eb4d6a9fdcf9bc04c42758c88edd6886f2481a6530cb270787b8b20a491483a2fc96e1953e2e254dd27c892bb32ca72021d9194c49c6fa618e3bc98ac4342d4edd4a2d3b9a328a6a1a54cf6a71aae73df6c41028dc3ae8595681d093e50f395718033d5985c320d27654023c3066cc18a7bce1213de0ce178566974b8b415dee974631a8c34cf9f7909e3ca427cfef28077b4ae9facff61026ee2929cfe17243497bb2f3f40bb0b3f30dfefc064123f7a118e66fb37fcfef89a11c543d216950547ac8b2cbeca79def0989bdd41cd4a1a5fcc7c378acbfa71c3bd40ac9fd9e42eb3092d6500ef63794910e9f8018545219e5766f6dec6926e647fc3b3c947712dd34504a95a69cd035ed0195e74feb2428e28c07a294522a71f28422cf773a060633c6488113279c7084a48288a93a43539e566a92ea4b511493932f96cc4878400b3424478c9824c961f60025494c3308a1e40149a03a147a3607bfdc558e4b4a4e782d2d51a2134ea5ec7ee3c5f599776f68e667e48cfc5519575a4e46e6391919ee7ee190b7ffc3657dcb71975e7ae9a5dc8febe387b688f8e3c231c65898091a6c25bbccf159cfd18ef51ce775ed7160bf22c929e57c6eca29e5949999796e662674654a714711417a1c788e52463e6c2e711f9783bd4d23ff79e43e51fce72c923f52d692fcc9bbc830eee332647feb0d61e9bc8aab57e6b8c8bd27399555197766d673fe0aba00c8d2822c71228e3f4e8b5f0c8ab97b80a4bfc45362a6a46c6aca5a6855c6ad1a90b28fa48f309e6864f23a80cd23da7d2865f3894c5a7bedfde849a4c8e3f208c71137743146fe75e6412ae54a2499342391ac375d262af5d1d7aa54ef17be72eb0b6d9e42ba1269db5e25b1f538f0fc23f2f8d323f789b2b5979e3295dda5cb29739f302acd22f70925929c9262e4530e27d13c92fdeb064c4d9eb237921e20b047de97b419fcc0b2a7c9ad1543a14940ac9227f6e13d34df061e73202986a43aef9da424e33a50dc6071c3e8247ffec445a450db42f2e9c4b097833b40f901f184b8501123424032d61d6b4e515f28c150c5dd9d521a630c928daf74f9caf366712b0e87b8f0063fb3e31fab14eee7f0a504be72f74b8544189d6adb10d50417471814700722bb39a7063a87ffeee3ca9f41087bfe3669ca91a949d2528e4c3248e56792c14bae3f9da4bcf1722703e2529ef89b4febcfa7923b32790cd8de4a0fa828e01404073fd672e22b7b7f54124d94a69c90bd8833b2632b59e847dbf445fbff8cecafe39fe3378cdb0f5edfc8c8b4bf2ed78d6e5b75291b241f5e3c76d92af5188a5290fd75bc658c42e215c52aa1d65aeb96335a485070220c192238b2811ba0c6a0a054c2962db63cbde045f17483122c6242d081394185e7cc781d95540ebfc722795b69ad7495040d546011a3c313a229b6b43013c5161c9a98f7755df7c6315a48b1f0c2d30c4e2c4df1658b628a3050ee65e264c3840b2624a0b92e262652324e8e4c4c96e43075d2ba59d58aeb58565e4111003916c522abba325f6c2266895c7e8b1cff00d18bfebb86a5e3a4322a6b9b71cd0a04fe903f351f7ffb2800426dc8c416a0ab4d8c4c36400ad16022644c7d2ec47577bfeebc8e2e57adcb39e9e0ae643890b96d0ab7a7cc8c4a2929a986a456cb1b627dcbe3c0b3ea672c919679e71ff88f17452872fc05b8064282282006a9b647723b9b4569b55adf2d3cbd157655dd6a48b547b2b328dbaccea2047902c2cd7433ded0f6331e079eebd7d86c1988535ea441d105397eacd66a5ddbac962405f84f276d76f65ed4b575c6acb596da95da14990fa88773b95c3536b55be5b420cad9500f4c1b1b9b9bd7ecc95ed4b5eee17f5f2f3abda8e633236a2de946fecc7cf8caf672f78b4232ab4c693fab85284ebfcc95f9eca521f18412391a2d9623b1fc6bb1d6760a0009285cbe2c51b3a20769c50f38d81e2b434c996925994c76245ec9f406a554504a63971fa464fa3f4801b104105053aabc10c409327d20415ec8f43f10022aceef07223b65afed0be48354cd0d510aa4207e90c2f85025d79ff186aa0f5b7c209190e75f6f68ced083095a35381080872ab2f42025d767d9d04981c20309b9bee70dd59a274c5290d0a8c9218a19b9d6e7bca16a8520aa5959e014254b14151130b02c8f284620c5084ac8f3b74b850b5b6badb56576108369075a9e4fef9c53096fce39e7bcb88acfa18f5cc15cebd10db91e89c9f51f9c814987292865e40a14047777a0687941060c0bbe9ed490d84cc9987df2850a355a9c6c9e4c417125d560c181862317682470410897a32892ccb658418896a3308a8e987020e30425990bd6056e8b5703926ddbb62a68b40aa3cbc311551551dc2b872232a5db539ae569cb52dbb2406d59a2b62c531edbc026b668a7bd82a6ea525d2f2b64326673f86205da258a902e53b61cca6032a5a02205d385b26426048b1294274a8438d5a008a144c8144d509a8e087932fa9e90b4525a2d78e1d21c979a5ce1056dc9c9931811b7cb71c9490f3b29383102cc618b135c1a26a42d3a90f0e1dae4b8e4c48a0b922c39215a7232c61126883c168fd825b7c9eb89c72213513c167308c68e80628cb991e3120d496a947d4efeb42f3fa39634c924c6ecab24cdeca2ea644e30fb8b946c5f1eb98c1283aa945f3b7ded25f2d8a75fd71cac12833afbdbb73548a61dd94a22b2f5215b1db27d570e97ba8e6e2869921655ef82726592fb6c336f5f1a49c9e1502a65fb5151dcaa5379181e1585fa03e2ceef1cca999cd99ff6673e6924690edadfbedc9837498b3cf6372eaea3107d5648a28f6a87f6993cb40fd744f4a150449feeedbb0939b81231a8b3fd767ab7eff5972cf1a7919a3a83bed26664db28c8b6bfc816894bb6d6beffd05092c49f0cb808da3e12d97eec22b2d521cfc0c47ef55c4f6e3f573d06d477e170ade522875deba4b559becc7be00f0b222303f3e02dcd5f07ed47a1d7a5c130efa310cd47a10bf360e6657e06c33c0ca5e6a390eb6530ac6228331f856476d4a18a4130dbaff97a64ccbeeb039231fb349f53b5efbd878138686393ccf7818cd9bfd5daaf6f0107ed4365fb8d74a53390b3ee61df43ba32abb556ce3bdac9aea37226674d29fdd6b4b3283db3cf51caf2b2773e27d79a3d25f79cf4eaacd6fca6b56fbf8f74068dd43da2676d876d1711b4bffa7a8b085a29eb1ef66d7b1163f64390eddb318c5a397497451e6b27b6ff61b92b4b439a6f71c8765af943b61c9e13e987a7dd502737533fe9eeee4e8105df9698d88beb3fbb890d377a584a13f7799913dc59420e6bf2fceb8a41dbcfe96097a6fe58002e72ecc902a4e2b1bc96c8516210e33fd83f7d45c7fc6b5051397ed857f48f3ba970c8c3e250878d1cf65383919d8bee6de4d067339f55e069979b504ca7f9e43ee184623a4d2db3cb84c2a7c824242f90b4f09991cf7cd61598451e7f3148536492ac85f19f98524c420b2d4d579cb2cba7ecd24b76da4e336fba22bbf8ac27a7450e25174dd28718f39759f4500162f9255e55b23b11f24be4e95a3fe1d87a67350e7f83fe69619914f2c861010ac0fa2ede4b4b77e3150ed491436fca8e7978412412f672c3396b2d1e94a0d2c4b484d64158ac8779e081f71b863540f5dcdb8779c0c1a4c530676158c51e744f571836b1072a98c450ba0dc31c43517d14da3ebef7592b1de3eb25f8515122bb0612c8c106fa2181787ceaea73082eea7034a600f7f11d3948ac9229b5d4e577c45de51824a3d71e02bc2c710da4d537fd0f885bbf33dd24f716e3d55bfc41883807e3aa704ffe0fe346196b9a8392ca98162eead4af8fe867420bb551c4c07f03e346198b42dcd32e6da3c8e3bf857139b74fffe949e23e52616b44b123893cfed1480a8beb53fe3886dbd88bdb180a7dbd7c4274dd1f470b37eca7a7277f9232e9754a8c31c87c70c782e848efc84d73374d36b1ed3845e48686eb665cffb069e0911b85a2500824611207110a6b8ac8589b715be68ec3042476c05e2491d2332497888346dce80de1143a02f57b9c6d447051e795dc28e3d634e36f3fed4f4e2623e2e07cee05c38d1edee186718a88aa7fc619e777b9b218b42306adf2acfba99247befba28cad6cb2dcf856c61f1b0011f20108ee038bf88bdb0f10199b1f8292a88b7e7090fac89c54c62ed9670e88423f646cc65509d1845b69fd721c9c8d03c98d320b064ce2da1c999e3ce5f056c182e40913201597e6c8f424891a25d01daed3ea3ae5d65deb477fabdfbd75779d34470259b9d19c6a5f39decf6ce395e3edd0696d9ea55c51fadaaebd76a3af1c6f874e6b524bbb4b819b52caa77f03f7e8f89c73ce493ff6f4a89aa136ede89cb3937246c5182395b56ba594527a2da5946e1b1254c61869ddac8a524a6b8c91d6788c2f393b2be5fcea54553a372e0a183060c0cc31130c183060c08099748699632818304761cee0a24ed8b5235b172d99cd365b8ba88848a9e46aca71f2f1a4211670d07f840c38e81fb59a12e03e90dd1054d77943abef9e257b8040ff97f781fe4a5468f2a7993ce6b6afb41114775292060e42791deba35252126773582a57917163ed86317078c891c9e315a6274732b54adc1085c6ebd4c2930d275ca61b54d0a5eaac40083a850d4972e4fa53e74a0d5276e4fa968a5ceb2da2883bbf062436d01ca851134b84bcd06484059329a3291784b880549bd87ccc923282b833487408716768b8e0890f31302e54d9e1b6725c72018a1d2ff7e6b8e4c21535725c9aa184292a318733c69c79811873ea2f7d6e34b640e44972fb093339790f3d8b41396250cc114714b3f944b325f46d8c71c39ecd9ad6b2af8b965c99d0d3f7f1f229a5b321b87e1a36b636b926bb66b24cbe99db3af9b532cbcb5de6b84e06a5d8a8248df745392ad19400000001004315000028100c088402814828cd835db10f14800c7292427c5c369708b324c661144286180288018400038801305354e3007682e79eee7040c7e23542471cab3e8a5010746afc592d0001442be9be613fda755f3bff06fc67ae8bc9ca997de96f1d991bfee11f78851670b5b4b95668efef23aa28d84cff32f9e73389ff847f590a00db04c296af65c491abe3239626006d70d79e1b50b2a8e531e915c542949b08c52a423b61c2fda524c05831051a9755895e1a838004331485d7366eea40ea1053646b76a6b3398ffa7bdf548259fbb75d0a2641fe4b53720ccb00a8e2a12e7265874ac9fe1c9598a0014341e72b10ad74c411e5592742c7d0d6560d6e2bbf532d6e3b93e5cf47dc076b5e091e66f6ebc986754743fd6af4aef6ee3a306529b3e65cb17656e46bdba337a7172f212c7dc14a71782b98036879eeceedf35b87e932858369f19ae72d42f10e70a33e4b73084ebd9d2541774ed8808b5d2434c37bda30b660efdfadf39df20e4b9134759d5195464f7fb9e90642fa50bcfeadd576406b94d4941d98490e3b8a18b89e601e2ed493990b7f6bffedf0b768360bc28de26d84ef4c2c1b9172118272f62bf53f842898cdd30bf1538cacebbc17da9c752b2af19a22e18b48ae093c0f38d82df097090c7ee2c06ebb421126d1c4266c9b584e3c7f902d10fe7e96eaa9665ede7e0556184ef9038e40695d5a9bee647059f5c304ffb41a0a73d6cc0dab4cf8e8360a629cfb0b172ee198e0fd13b5ec739f7986cba0f06980554f3cc2a3e4ce8d29a624ccef6d7e09c0c5ebbbe055339800b6ce564edabd1fe63ccffb6a773d2d6812470681e7aa4a32e34cbc41a0e63582ace32718f8bf1771e47685e7db024b98c5a8beaf54ac4ac370b5782cf42ce8c0c190ae653f34ad15f5188a6168b383498461a09652f82a8a1aa1f530afbd18776ff8850cc83b11315bd5bb196e62e3475875ea6f3047d5822bc946de632dd8cd6fca0e287071e47bd136ad41b10b8496a6ae3876c5d8e381bd6dbb1a94ced56d323cf21353bf045b32e525b0e326964b11344d8aeaf6cd8ef23836171e31b7f7181a9ba0ec6525215513c42d561f3f0827d887c190d0652c7d110d751f2ed6c67f011590d1e39c94531a937ed345eba0b992ce21a48d4ebb9d0de364478d859e0dbda75473f819729f61af4905bd86cabb1f27206f3be97e06d9d1a73187a168b7bd811eadd8953b27b00c5eaee05d885db156a8ef6c4a801525026cbac229c472aef2aaafce5ff7a8e79abd1b6ac827e7e458f481e0b791cdb5c7f5f950f5398db7a4ac5ee6ecd3bf9a2e4992188fc8ba142ef93b5a0a7c7e357dea81219fc92fad06e6605d5d4d80d86ad2b506e218a887b4fa9197525f82253494a9a1008b27403dd97f83a2a960c9c57308bcec5825f0250c6b865ee6cc2648aa84018432a72efcd72da302166301ea4f56e9f2fc80f0006b6507f724242c13f630a8cb1277843665c572e9161bda2a4a65e24c5e3a7ad532b5a171a3e3d87cbe23531d81d99a4173d6b28ff6c42bf6eac3fb72bb9e3f0af4d2a42c1e84a9a0d1d271a7a0a2820c7211ea675bb18b356681e60a28be3fcb0dd198b81c2c7e2e1a9237deb891f2eedf971cade6de3593c824b140b528b206f9efcba4738f2be492128ee5401d147f2401103782899c198323182f9deffd9181ebed7962c5bd5e3f9f34fbf6646fcde6b006d3cb342c8618f122078e02c77d27119ff066b4918c31fd57e2130e7400fee29e9010d144ddb296c9d0665c9e3de67ccd0f513362b26ab5abbdcfc31ce12a2a91e98b3314671fc95f9df63b3690ea1759b18b9beb2b84fac899206d6a80ff66d73863c79ea7f39021fc9c8496fc360d121079a2fedbe07955b2751aa6e1516b55bd982b283d37eb7f959c43c9ce3d7b94f494eec30ab16d60d0efbc2cffa157921afe127cfe10a146fa8484968cfa0eefe665107151aad7b6bff957f9f0ec3779c898698d4fca929b73074ea4faf5c8a6a7171bd3263cf97a169e1908adeac7b3d95cfe1802fa74270a3034694de89423dc548ff858e8f22388b915badc1b04d8457c32b64b9051960a5d4ad684b31c2d8543afa5672e85b633537b399a97485d4468f74985ad28b5b624dbe2c011bc1599cb1b98061bd21eec7b63b66924c3254f187d00232fafeee16f3ca502a79ae6c4fbb6e25592463f7ee7eb145dbaa4d7d32ebe4b4548db2520e3682c79a7ee34470ecbdfb4b6755443935f664bb4907bf10c5275e485cd70559b01953e147c477f91bd24db739898e47a03d6e9afa1cd9355437f3a3d2b083c3a44addb3f8613544a052804c2e75674fdbcf836c4d3755fcedc7f2488e7a9e99fe1cc82de48ad6ac17a0a9a2ad38b03d2c57bceb38484b1678aa278d574415bd3e6d355d12f02dca12677f77775506d0f844e3b3a0f4c3cce3ad081b09c3e394db22955bbe392310cc33bc5e76903c2c46541748969f6655e1986febd04cf474b1ea758dec9030fcecc1dc1a3e4d967545d7a00ef220e1a127b326d585dba2f30da5da00b4181abc7c1e3f67a9a30b085434fcca8d848267ba21a7b1a5b7634663975ce777d0892c1cd96672a6b1a646c7ab01d863c832c9b47fc7478a0b3f07bd39e11d8da08cbb2787c4e2e6f903d2721e5ef59a2811fa7065e19d64e69e1f9a1440147a8ee0650083dc729a4b0d3609e47f7f829fa1a9b59b9b06fb672f996d43780981c3e3e300d247841f76494956d40f9529c791dfac074537bf78efd8e017a8e05b986019ea70b521a24024e68b525b16986d6d2f8379c909608178633e390fea3617618e8ce5b833088c111f6d03156e9f1f4d3059f58598669a8eb0aa278eb07425e9348a17472bbe5c27f5a8051a853dc0ccfd5c3f685f13ccd4c7efd7c0d1bd3f30cfcd2c234fc5f4a29d24b5f0de189f6d67d5a7f0a77c48e1b9ca785d1c02c3ac557cd2538f11ac84f54fdc5c9644c2dd0dcec2dd598292c602d2549c45282c581096f4b4a00d08cdf503b70b33e37b54fbdaf4b987b72da3501da27b5656979f7f0420c11b354d47d34f86cb3aebf5aa992819b0fae6e8298e599d5534b776bb1fb69b56639ddd2f2aefee859ef4c5b631a772e7e416d168dd080816f4fd409a194df7faed7765a51b58218501608f5029f9714501e090a281889343c139186a783736bc48c699aa58307a278acbb86e5b1f66a05c6510922d111a0f480a0693a2251a2d0b98b75edf55113c98962c939d21cd9dd11df61ad460643519705930224aa3114acfee91f2d9232e9c8889f12ac2aee97fe262a7299b7c18236e7650740e0ae8889418646be6239c3650c8de14c6d503763dfffb5a45c0222af22c67151eb9627e2686df42edb06e6ed1ccd30c81ab17f10b428b7dc6eb066b5548744dbc33f10c037b9857b166eee6ed0cd9098c744cbb8398241b38253d37584776b7a5f479db366551e4b586f720b7d00ead598bb921c4548f49d9368273500ad01c914a8456dd005a4346cdb2057ce80cec123fbe5bb3d48520c69b367b8e6d864ab81193fa1555ccc08780686a0370be40cf22acc428360e24f018b180e2a27e9598631272b0bff68a6b02531fb6da3a61530c5aa804575c7573c8709557022f7456c2b33629a26c076c98a98a8452242558c13416ad78b4adb2bd2b972a4d3358abf44f088dbf9111c7ec6fc9212c729bc88767724d99ccae0891bde99eae80c2589ee2b3a033d301d63b22c5e209172ea6b02edfd11af599309227ee974f38d9b77ce70a4bd642ef160ffd76e853d9c1fc7a27858ccacb653af36aa478d9a6f9cbf904d437de6771b70b761da17701c138f5f1a1d2dd0930c9e5c7a4e0356f1bd0e429b2144dcc345511955bb471514771f22a53bb5ca1a178b9229cec2760c5cfe549c60fc54b0ddb8f484553cf035eafe0c508b0837671ee314c11f1dbef267fe402024b97b32b40b954080a3e7323f2eb8e58cb71652bab0c1b246bb912190ee56422e3831b6f3a6698d4051b311192485e565aa53f2eb292848669909823d1852be4142869a19752359346daf96e7e49f85f2e152cadd4259339af1658d6e457bf0fd7cced16c8e686434a2fc5c0f89c62d589da28a96b452660a78d87aa8711faae79d2732592b2bd0b3a560cad54c9a9b086b9046972729f17d53d04f9d32a9fbe5d9d0d908c1782bba71f3f0f9749abda0edb1edce33b191de79aeeeb9ab4f6b7c7dbbf1932d9ccca879c11ede04d96dfcc4994ac73d4d8f5e5701ed1038133feef02f4c01a2c8d3d5b4e767a9b512c33c16dd7dd359f04802fa2e9903f2486ce933a53a9b84348997508e10fa63c50dc57d0accadc6004dd37791cffe308d2ec05ce42c60dc60b4484ece62c7a24c495346cc8ddd71984877f02bf4c338d4ef0a2d4ce2746bfc5a212aea38545c1937008cd03e20b4e81887a20b2d0a6a8a96870bdef54f5e943587d33c9eeca1511962ec300aabdd9167a2c59048797045a4b002a626c624e4da50a2635de6b619b2af32e3e0351635b254d4870607f183290cecd3271a8835433d7d10d129b194928d6a5c06bd2e94e589e4ca8ae13c03d9183a63394e3cb220787b8289aad9c6236d35b496023a27e85ed60a14c75328b3ddb69c7cd0ee4c4def6f1b7289089795a029bafe62f7ce585bd3cd1814cfd090cb0c560f7d370d91184594cd06fbea69afccbf1f1c20c31e15c1783c4b3c144da257695487eb793d0041d88b8f60186bfc9b607f2a2446999673216bd2cc7060ac49b079ca05bbe83f83a41dce6fce9afc7b24af4d55481f59de189fff0535159aad329a44a05626ebdbf1d94d18b2657037dec74412c9c000fa5ade20e3e01f49376b6fda09b8b5de67fdf22bc3e040e1efca4a25ebf80f3d8e03da89ea107709c74a49082e39f7944784c2a29479a83c742be426d4c95779174ed814c5b3a66b151ae1a52ddb3355aa2a22cdbff22ae7695c30090c2ffb9b46e33a0b1bd500d69169831b46cb5b9673d57c01c481fef575d16dd22ff5b558de252620cd732e68421f18fbd2c2e9a3624a981e56fb684f0e296392b0ef94ef77a13cc5b4a2eac92d805d51f3011019024b492496b40ea0a2a8b318473fb9a6221970200b4311c39cdffe6832770f85569c58da0be34673e2388156f074aa42edd75f3e468273306993682db5767d3711a0d14ba75655a4c64b9061bb831b6e5c2d0c58872fdab87baed90ef512c184250ebafeae305c60f020fb802c6a169db66651ab9d677a2c971c9b71531809c1c1d0bb6b59a74c33f30e2b32200b2328513dba98e30a73f4d20c3c18193dc02cb46e52684d3f209ae0d801de4b70167bc98f5ddf0885aa2e28ab142cfbc01c99be142caf3b3bd8e8b5c202df8b1ed4fe24aeaefd6b0420ce74816c33135f48233dc4a011ab8dc4cc13fdf762bbedf24257875e2e2d15818a38cb6617283417a8aa6c6a6c36642298cc7f1a17b65ce4902eb64bf247cf84abe02942ec4cbeed68e0b9cdecb995a32ec72683c4029fe4b2d82e946d458721ffa229c887196ddddcce7e20f42f24fb7f012c40c24526581348d93aa66c09d96d1e908df8643270af9e9fd8fd613e256b8b7ff340eef5bdc6597eeaf034621d3137ce4684aeb817bc76a051dcebf2691a296732082ccb6120336e69948ee703f4c50062ec8392a5adb464c004ec477fb56f457a5ae661068608d04ecbb556b577da687a7e67c73627c4c47aae74210fea689cbca5da2f031b5e06d625c1430ac87df6533504dc9f0c5370b383172d82d93511b9d759c7bf935d5230c213962a52a49bcf748044e59be91433e2ee556ff6685ab8fe3b938be2d57db7285684e1e0eae17fb4a2d6ad272da5b729a7c2517ab1e0f550c977ae955c16cb20bbbbbc5a26a2798f5e302ead4183265370dfbeb229a4ecf2398fcdac89e9634f4c60978681e5712a064bb8e2b07a43ccacf7ee08b4af294d8f986bcb304ff82a3204a0a487b72a8f45bd8aba3f8a2333137420ecc71c2d1692e24dee4c63ffef09b67e1dfbcb222422bebb4e1009cb8e2d1463a353529bcdd97bcebd6da2f11c86089e3f20c4a63341ce245ce4ab3de841b081865ded615e8354b45a77bbd8704905a06d50c1c17bf0bb072fa79fa07617bdb52f5d68ae777e033d8ae8be6829de3a20183ee72485f73b921cd56b5a6a3ba036a1e1c4c89355856c4d4b69133ada1997ee7915b0e6e73677a1b48bbefb015595566054de1ea727e2d6513f74c7d52107fd901691a4019422bf1809938bfcf6ec19ab951431acb030ab3dc52a071498643d027a1d41adfdb31dec49acefd200401d66f30435fd0a757f15e7340f89aeee55f573e065bbffc9b3d275ee4ed7862f610d47edc0997caa88ef533a590fc52f082a472957c27cdc09651811966a5ae676a1250a11f912080ede317449c7c84ddfe6659d5d5933c22814764fce43e42cae02fdf3340f4d0a601843d8cae7219a9acf4314d4a5cb93c2eddba4f9bbc9bbcc7effb373a88f34a5bf444435f11eb76f3934a4f404add9282378e3dc15b06c008f766fed68d1e15bcb27a976bd9fa54ea0201d986bb5317f40c31cade6f4b4c203aa967d2871214ee5765e88c8b4b6401faba2b4b2302c0e529385d90b4430c657b15531b57f4c8e3373b01c225065c016998af985014e5c5e8fe99893b300b96ed219b6b5468e4ef9a1f0b960456e299e138695be55514f1e6ae3bc8ef5f525b9884aed0674da427341e50163e1da6e72a2a2674d8678cd01634473defc80520b38ba14dca438d0617ae9642afba9ad3834305f7fd74cacc9ebafac2f4c74d3bd68ee6e827179f52d9725e6599d2f0d79b5668c53cc76a502e1223c729f20893b2cbc85ed5c02ace565c9c6e2d7161e9c96a6eb1ecdb01c9f549f260cd4884599906444059193ea5b27495be531a64c60a375d1caf782b9c6e87deee7a2be5754434dfe11dd10ad41374608285e23ed834a44e2442f4e804e885b556e7a41a3684600e6bd80bc9a21aba2f51024dd1f6491dde1fa6f198ccd8f5ce8fc56d8af9c6fc798adcb52e96572e90a051e1bf94dd36e4bf40d851920eb87be3ed26ac19d32effd0d51947f1956cbfeb13b0fea0e74630915d1f79bb786363b3637f9f3709f894cc5513391db01cce56e827f34738c26fbb06043b3cfc08152ba04e20bc4bafcb94bcc791e7560f054820f3226c58715957015472b5aeaa6bd0fe0a0be6b328e14e95a1ec28928d1d3dea3d85b07d9f2a685333acfd0f4e4f9800a911d2b83accca03ee80bade8909cafa71bc4a738b05d56839f7681b365070707c19a06900a71851ab10e5454f3ca17c793b41cb38e1a70bd96a2c38d9d84c3172032436bf3e81030d26d35c2b1de54350d7f18f24fc4c70898a8ffebb14d378a256defdfec1fbfba3e5bc54472d344fc1ef7b392fda337fb208aa4acba81da0b9e03f9d71871cc1142e40f09f57a2afe442b077d05dd98921afa5289630a4f699afb81ac776a99dcdbb919728241c8b28701b5eddb2aef8e245b88407bea83b0ea893442c61370021a03e5048ea818f2e90f81ed46c7cd0e25827071b00f4a01223fa40171e1642ac94c184e212486ce299b2988515b187ca3ad1c9f45d85bea3fd4705443952de219720fac7e540a77ca02d466980e21dd140d2927d38979029180f10de1c8fed5d368ccc6f401978475de5e12091c62d0149f64c615150fd58f30407cc2bb3923d8da06da6a8b5f52d1529eb9929b32843ea11c5c8baeec819c8afc5848763657f84f6dfa63fbf050b3fd82485e49c30e29d917c29f5946fff9e6b80897fce88e0688ca7e2b878ca1e44fb4b4905502d0458041ce4cd42f948099266302ece1ed26d686d49881806021ce9e148021c6b21d0293424136d047df2ab35930927f1f41c73f42e9bea61765b54af114dde4b3e26234ebf42bd1108696765729a8927443bb53311537c043102fa466c854a4a4955ae5800c7d479abab134b365e59e9c72e83c8c8ab35a728248464794c4858ad14339ce8d4cc57b142dda3497775dca2c1ba3412840d623bf28f6448b4c2ea5d1f283948cb54924b2d423df8761c4f5782c3b12487582925c3a10153ea7bd91708e9196f57115ee4bb4f19708bd23d391a472b981285e486766209210e2c518ca341884bc22cc84267e004cdfe15cac0d7a1062ced52d1d44e1117ca4230a6fb57bc33300f36e9906b476c724b6c13c72ffaa5528c0b5b45764c747b46715688ca847a7153213de367f2b0c7eba016e299455b69d31e82bade1a677fbc3b702fae29a5689e2c90351cd1ce808b12257a0a81e02d7aa7e65f88953bf44ab5bdb6dff66251830ca3f25bf540dbac8dc7b78cdd7e29378071b040de96448ca954ebfe545842dc40a712887f35eb0cd32fdb6489e6cfe715c0e903e8b212b7ef048abd9d66053fe02d60f5ae16d1233a2cd5519050a92992ce98aefb72c163e35ba664a259f6c17ff66fe19891cfcf0254ce9853a8f6884c068031b553d9eb990ec723dc06ceb9419689a14aef187d74ef71675614fb9d753af8feec9d97c89abab3ef8f450f55e13ac0e480edd2f0fc0e53e256809d011cf6b854a84eed9c432a33f348725593419df15eb381a2e730121a881abf7b29e600d6419a008340565bd7c866e6e10a1ccb6a9049ee9a94d1fa35c5c19720b6e25f54c61821879078a03ceeaedc6362bcd0898557b693f587a70971581fd0518dd6a83d2bf9cf1f05f2b30a5f0ba290f83849587a3b795c2d1e350b25e273b5953d8ae5c8858743b5a09d0a2e9d5f772ec8f1226703dd47ef160622d3fd2b5787f17963393184a243ee6fe0861e8d48cd1f97505d6701512ef41da07bb277bf79bb973027fefc9c8a34ce27aa50a99e207e54bb40970cf63c88c8104068a675d515910d24b777619dac0b09b022b7f8e6caf8ef2c2d7c91f476f89de58c90d4c611143a7f772ca2955eb543ff0d7ef5bec1d40cd2b6d4ef97926ae1b98d709ae9a819389e26445727323fc7664bdb1c8f5bad2ef90f1dc82ce6a4682b7a9effaf169adbcc3db015b357fbfa8f9e773061c9d42eb22cd795192f4da985833de501e775f14cd58af70cd2a2c1e71849602cf265dc8a5c654411f73d1dce6997c1c6a02633edfb26da42c6a7006728ab1068f80141fa8d5f9630084026b2524186b34ccf9e3fea705dde4606a797e1c3435a1fbfe8764e4e5ee211e55cd368926eca0437fe0040fe3bf12861dc21bc736891b23112631099456512cba94706e56f50e175c1153d36ed93c85ce8ba194161efb5f9269bdf86ffa35e626f65655e0e1bbd9becbf1853d6bed5685f3fe1b2a08c3be820f2853b5c9e83c66f28530d135641343e3b06498fde7e68de70837ca49b801d8a91e9c8164e23f964979e99766431b86ab2fb4785dac439876afc34491ae029c7548401ee818d7bdda9e00a795c303b679c9ff49ea7d00f5587c8faa59e6744926d643ad35d84e2f8a67ade9c476dcc8c19d56ad6ed1456ae4f0284815427c49f2277f59fb1faa29c6500f1baeefe9cd0df345e1a66bacd6adfec55cf2a2d2383816b48b6efa53ba673f121e915511ebf3ce246deea71578581a904a5ebe1692a8b71ea8fd9635ac82084625148c9fe6698191dd9556b745f8214b257c41a3962df35058ee57b6dac70ad887e76b6dbb35515cdb62c320d3b8f284cf94ba2e53c8f8a6cb4ce4a49b607125112ae54105d918f8b80670e8ac050a41562c3c73436c8a928bba6694c99dd5d1bad666879203eaadd31cb33292999a40d16d26befc6fdb6bc931622ea8fa0333843a397118a10892309441a83b82f84ae0fca6987d56972dd553229fe2ae1e48a80b6370d030bb131fbdfdc1f63437bca62fd35c4790ed5ddf0f1b3079231a9926c135072c58740cefedf2ad536922e3012d7482fc2ed5ae6a401c11aebcb0dd28a0149095ca1f27a8c13722c782698351ae6f7819686799733555a5b22029891d732a365be636474ae59cd31dad8c2972e42c6ab1a04b0a43a9bdcf1e6f1edc8420f10b7c2b189e148c60f05ca77d8ab184e0ae977fc8ebca2c4ccd8d7d03e8f46a4f7797ade07877c1459732a0898f62f1dc0476fbbe4421c6e7dafd02c2b577a4753979b583072ac9739b79ee952aaa965e31bc34a7ce2441f7605457739c0ecf54e8cb11c9604679b01faa0191869a98bd942d11ab993285655dbe54e2e920ed5038c202d18cb7a9baba3dbe66e2dd025ec5685e2738e3c10001ee0f0f548a71e4b47890280b675a028de6f66a8082cdf4a539cbdcf2959c1a2dc148efd55218fce24d410d401b64e5a43a2bb4bb8876c75828931a1b86da756dc2ecae9c4c4d22396129a76274c92f0df2e88753bef5b4ab8fa9a8ced53e2352c16b9b005ee3b5dc14855520f2f59fe210e0b82351c0517c1d8d16927c681b2c7bd1d42a6962093373ae9294fb7cf176cc3eefca7eb2ada239f4609bbae5bbab837ef2156d40c830203efcd2f0e289aab0a138ff68540dc0712551149b4586f631ba07d6f85004ea84b28c1cda635af7c3b231733798faee680fb909cf1c6f9322da48d17072fe433b64c60b256950312dd51b932087bea40ff0ae20ea468cad25d79fc0ed37b3b9305f7864b111ba58cc4ff7d23fbab72170baa458590fde830231d98caf2be60abacfa9150243bb86c0db1504281c9fb9679f33eb505ed5204a9fb7e5c8b56b3dd3788d328e2a9d15b445f9ff60a133f4c6c319fc1dbf886d6c98a2097041870447cdd7738b7c81424106fa275153a68206ee7f21d92da4153cd83c944f827cb786538db0334224640a096050075a01044200eb135ea712472cf3fbf96a67d9180f6ef247f0f89939e90b159fe1f3786adfdd6aeca0e092c224b8006b17751584ee068b5f5695e2966b684aef5b11aeb8a8fd2044275161210d9acfc8998ee926e7ca16cf38eee05303f39a2bca2f8e081954032bb78bcc3ab956a5b2060648fff8b5177eabbb704f1b5555b5de8b80ab10947cf52c1909c7784b8239e60d25455f35de3fd4ad6f6614d6fad5e596c59cf48c98787491785c7725a7fae719da7e6bcf43499db4b14a3120bb794bd99f31404a139f93b8e9ffe6e401b7e200b3e4c9f6d32310473021aeb814e8916c3ada7a5e82ce39246b052eb9219e1ff4d5a00e37140b96dd9d18fde32874334ae6ce2a22db0e31318acf98f351ab5b0e4637282483576f3906ac7c90a40d2a7fac82d52e208be812eb4e05fbc939496122560a7be667e82763b7d60d6150c7f09e10c14ac9c62cf551c45ce322e62fade950371aef2f37cebcb8e1ff09d302d90e9b85ea974e892d929f383ade43a8d7738129fb5388e388ce8a429783d6602f1c1c6cdb7128cb14afaac30283d87f5745aae4a74e5a72feb93da962033d6f4f49400fbe0ecd5bb40adce3f8fe41abec029d5eedae924d0da2df33912e07e09f40d9f998872bb06deca410f84f025f99f02af712e86d3e5e800f7a80da30889e99d62f5887d0410931c807f70ae12790ff941721df1fc85f92a6917c4653c41dc00c7af993400209ecc4d0e8e3c3d743aa198220e45935903411f05e4a033024f88724ea8178fba0eda71999c2c00f2bf73c888875bf17f96c824604cc1688c602e13361145d9ddf11cd5f1edb9e71f5ee2def31510c1578593b75c86c6585b6ae3f2e89d822507a1f7af736133c8d1ff6c9f89d3a09cd2e1ad8dd53a91b9970430699a8da912a6efc3c19d82fa8091e28d703c37d8d2293a3d6baea2445212e8cb1dde0ca857e13257ea888071729b78a170b6b6a805335edc1fe09946f59fd029ef046003dcdf9b02b2272d82721cbecd40d0a8ac8ae0b4e9f4c71c63076a3faa191aafbf096b33ea760bc74d5d78f0826b7b03657aab5b67d9f2636ccfcfcea5d9fe9b312e155a8d0971a78288f78b6a0bbd1384f40366383733f59657cd3151592a4d7a6132cd704c3f025224170cb3172fd66f49efce417cac2ea4f2882d651d3824f9a0320b493df7b410a38ad2722032a9921d06c655cc0c2b5bc8a6476b27e132c237d22d5880275f6a48444be5584281c0d76afacbd2820a766209cdadbb523838535cc5f7f69be0f34e59ebc9bb6ef9327a24e79b60b0105382b5b7ba673ffe1251c2995cbef1ee3d6efe8251ca5e5deafb2c9df5904a401033dbd0f3fb4d09a24b9d5f28b29ae396b4fd7100b6eb4d50e62d1af29f018930e0f5809082b0abd17f1eb8baaa0211f2bbf6cf1e2a51528b71bcac670d6df28e3618c8419dc63d4d5bda899e4bd4c004f13e7bc6f6b88e287de654a32417a8e273a90c588404653687716d675302d3f58513fb6b293e9a9d0c6c868a99a129e3627bcf25cb531d7a79d5aab4413871c8a9ea543d5bd16dd3b811b6886772a65c3bebc39d4e59378f1d63a2f67d48c6dea1f6cfa455dd8fbc38e939e2406d4e7130095f732b307d98aa190a4a32a92510592198e817211b43bf640b8b795b262a9a6274227d840f7605b33181316faf3b49fab71ea06b846f07f4a95baa2ea6e24a28c514dfa730b88da2c698641005672ee338672213a88f17441710a9858c9c64d6c7755689596291866eaf2d7c09c76433cadc46400fc522429928a004ad3f748042adfd9513c207c0208048295808ce7992216693e00b57b8c4bd24614389fb2c86feeb60dff532bfdedb74da93f268e4dbffbe3c0db41aa8ac39399b7d3b0b60d8879bebff4edf4cbc52e84ff592521a3dfc3b01e98d42e1cb57d1fd6de43e9f77534d6b2922a8ca937a0a6bcfa4c70be0000da13c8dabd6777bcdc073e0e08b95f3a3efec6cef025145dd1fa7493930c8561e121457a653ff46c225f1a56edc767b0e61e236c3529f19beba65e2362ccd2715117aab698829e1af7ca222bc91bc101aa9b0a5012ad6c9d4a35dbb130eeadaab51978c5cd5b04f0a4494fc432b1e485fe3c4b8c0d42060d5018f79b3642e4bb017fa604a00a25016e62f72ad335a8ca08516f516201b7d116571092a6413bfd03e3b1714d83eb6f2aceff06eea44745634c4d44826fbef2f7f372da0ee6bbc34cea1033ff82d7fa2a831f0067ed02f0f1a0d79cb26b4d0521da7259f234b25b8b5532c12659de38f719861703dc9b4cd3083324e0478259e42483a61d6a44e84fc3285bfbeb65c2c8e4960dd0feb02655f7418d81ccc99288abf0486318c8fa04c0d82cdb46adc20600e841e4168baa44f5bdfe615c66395e141f76d45e31599ccd9189afb234564a1a787c5e1395ec8cdf4a3a863cd134f55e49409e6f4446d3c18058fafd1295b2e19d0666b4fa2a7268932d307ef6a9cc86e1ad21da32942b1593c2c3462f9d1ffb36b2d88683ba6d7bc918b34cd5f1d412cddcc2f8228b34e1d96933c6c39bea970472655c53f977348e1412f7d0e124b478cecbd58f4a5063ce2059e9536ea47b0e43172c2a7c76a8e7bfb3d84327cd7ca671c957cb5c8b8d14530791061faa95277e8410eb3bcbc6f38daf0d97399e6467bddaa5c55dbd309a32e6fce3ad2e8940f2360dfc8f77b194d2381e55a9a4823a2ea3238041a4238e8bba966123f548a933c8501b10bc6d8639be1053a756c20e46310cbd5bb056ac50edf1ec389f8ec1c041074590c964a2122ade63a3c7857efae06971a23a26a0b18a4cd9c2e94cb146434a928b73a7aa6f71001ae4f61d0884ab43299117bb1626ba9b503f81a302380eb1c9275de3002749e05f112d29f5d476e25b9f97b905787cb7c70ea14f39909099a739c17f7b532216e5dda5a7156e2d907722b66c54ab23a69e0506039a33a18a3abaf859e19e1609d7b3115a4a4bcb6e690e459150b416a587202d30bb5395677059bfda741626babedf072474110c7b8a843a17a216ac57a9925142b179f89e537d0cd57f3739f9ffd50a6f4c02ac5d8443fddc2aaf53bd9f0fdb018c53db11a97405ea87b44b59c85014fdf0a398caf91c670cdb0805bcdf1e741ec4d36ab77e48531bd6afffbb96e6218f79d358a84e313c7bf4805660c38f76e0aeb106fee5197976f2f9cb0e6dc90e1c35fd09f9c68e5f8e3f45d8115ec6f8fff05f772c8dbb5c0d44f4d90ce03336d579bd68d22101ef72a9805e9c7b152bfaac0ea15c8f3ac21b1420c820d9dd580163fdd743b0ebe9a26bd0d6d2197296225e7b18f3e55d8d26538c5728edc98dd85567797aef9298e00f13c8e9bb80a2d956c944b42de90731553906f8f41be77af8ad36e7cc4a58f165b262e9b30466e1f817175d3a1d9dfc36ff68a0da3121ebb820ef72888c0331d0f06b1326d76979d477ad0438ee97710cc1c86a03a21ec778c4bb7b18fa9e7c854df32ed9658c0734da9507b8e628f4f3aed61101d928b65bdcc84cd9c70ed896190f58bfb1be0d489a4b52dc003987a0b4689642758041032aa394fa7b8e04b3011a01c11d020944b2cdab16776f0de19e3fe91e0df5af3b067f760e97245383f4d217e44a815cac4131dc5fedd83e89302d9d38c2997ed03f868d997f3a0083ba568c8ec8cd91082f34175f74c9c9b37df2627262079eed831048b345613f15c2ba1b20bbe40549874805d1635716205574248f2001195a9bd87dde611de01cccf96932a3f51475930903145ed5a5c481416fce8ae0eeda25e966034254c8624db7a5376772e735476cbb0ae36264e044f4ff53f3870f21a7199cd1764918a0c628b054e915e41fdf34d9aec399197827917b2bba39c0471ee85ad4c56d1aad9f2aabf35eecf0240817f197d0ca5844acee815619c6afc4df5c393e8c306f5f26aad7528f80321577e391950e62d8679be6e43120e186df31a8091719dd077c32d82a2f7a90a2ee14eeacd131aa6dec47637b1ea59f52ec76e63a9cc1200f666325d107dcb41239f72f0ced12982d2b6cea4f16bb6f4fbd6aed01f661c877a80610ee1007f5e1cbc83c9507725a9068bd3f8136bfaef15da0f27966aa17cf9afe610771f678c5f70f79d0bb5bfb4b693b9ffd0928c0297ed92f60f06563a4fe924757622554f32d673493135cf3a9ca668e7ec46e23ab4b01735857d18a6bf06981958d7ce7829fe0c12c34c646732fa1ce96141a65e5b99ec6ac4b8c131eb053b459b91ab9b09cd1a223bd789ae6ed3e1cf17e0b2c76b90d34f1cbcd5a002d8354ef18c01cc9dec8dce67e989119841dc514f427ec2d505453fe1d4a932f46bb1f8e7d9a65cb9fecc307362a5d7eafc3e4605e7b2364673ba95043a78cce173ac38c710b2620e06c5370120c15869299bc88b48eefe98278a83d35c46168fbdea497c34c613b31d4e9cdedd4628c4639bf2526fe1121a1277b03dff90605746b735eaeaef73fe08ef8e7e333bdc8e9c00c245840db48aa3beadf5538b3ae43f098870d05125cea03bd43f6cd4c055eb8547bc74ca32d6378bd0af58a846ac0965870a49fc74a7ca9f4369cfad9c21870220d76c42fd4eab9ac029dd336c0b6afec4f3a48c58551d04c6d15b9bf18fb9c2c2890ada1f046b88fec1391e17c60ff0bb9bedc271d6fac69610f17e8ea37fe74a176c82702f4cbb1c1ed44071421a6e296a1945363ceff1ebdb3943e72452c35ccf7765f378c4103cca698204c23884cb6048f4576c7cfd9de75667441d29740018de41d9e68004915b9a715dcb142480469f44b298bcad5d7f50a110472c98efa412de53ca818e04066d57415b8ca81013cdb59a006c157ea511efbdfcdc58d86cd3b2d4b96b209a53591cc17e3cb00762d5f62255618be056110092945a09310fe890d789b2c106b8b6c8abd6b54066246732f7e5575628795bf7d4e503358f93505bf1c30f136a43740e99322ce49bf9fd6ab4181a0f1fbb2755d8d993d3827107d6d6f8cdfd7691de9d8ee7f96212cc5df2af3bf437a2663719d788c39bb36a1d9a59a7b5d7ed4428581c248863bc71c33f3f8a9064a504f41af47904373c583e04b971b4996907e236289a21265b375a329fd217223815c2182639a4c54c03f038f01f2cf302b8c1df57710c4e41e58a8dbc444ee2cdc05aa4c168ff056099f7d1a9626c762e9992b459eb28c3f7db9ef9d4b63160422801b711f0413e0bb555a08336aaccb2aeedd111bb913ca118319b0061ca2bde5d6bb509adcceeaf11d2ed69fc6874cf7fd4021d8d7c8d7da0c3db868499997379cb22c41b8a7a408e7e5c1c5450835fa9e10d3cfd2fc9740245f260d4a0d2bd85cf0292cc27e7fe4858cddebd82137957308175dc04811a349e7f85f2c1ca58dfb9e04cc843b66042e0b40443f01f505360e79d0c0d0d7493ce4b4e7c2e00192cfd717b0b39e5ac2e940012072d8772106cfa90d9bc180a1c6dbb3ee876a19952000e51dc6450c02caa5ca0a11a12014e4239947749683af4f55352056abb144395d9df4d8bf67d4526925451039bdda0d1c744da5e4575145989108407320efdfe34a1165aa3c4608c0bd1a333bc68ea071363b64f8e228a9734727b43eb87df8410c0c1b05ea3eaddbcd7f53bd179817454c7ad158667143be6f7c025410386475aa646816fe4d30e6510abe49c585a5e9fc61e6262a17ce2b153c192ed05ac637a34db89f52a7180f9e0022be561ff29bd901111b5f22a98fd0ffb698270bdc19718833fa847c615f253be815c2570c5c9f87fb061cc63cc50741a52160eb2f6154dd41a74658a480420a1ddcd214acfa5f54f2dc0f108c4753a11d7a9b8641e7c9fe3744ed3d183a6b888fda6417d1f27c53cac96ec2cbf62c6268b240234e4283f07323b1a7617f726151f2e16c668a78cfc22507b1a164f81e2b0746cdce2d0db3c63f04f82456189b9469d6768dd409c370526c6d3fbcaf1af7d8dc7675b6bd63e05444eea6d5e41628db2035349dc171e3af02be77f81a6822d85c29bd5dea00b6d9e45f2afcd18f0622fd179c0f05209da3435174bb789ccebe4a627f11a95692eda3d858310b7a036d4a0eef435c74a5c9fa344a9cb37983b97343b4d2f50a5a42bb88854055d14828fd99e672694f309aa168d63b7a1e5b8441d5f799ae4fafb4c7945d8cca24d40999fd8981889073c7dc3bbca9b060a0ca2ed5c130920b3b0c03893bb8fbd3b5b9a79d92bd31cff9a8fe53deca91d0f3f5c3f7deb1221d58a894e0ff93eeabe670a146b2f18ac119a02b2c74edce75900eb87b2573e091034eb1c8daf9c7a131de8429320e6d3e9116e789e4a53fc619cea1e670b48305bcfb27d8dc05452e1f851c3978d076bcee70dfb8620318b1fe7c9fe3ac3305d737f7f51a738a500a392e7c8e0f2fd2dd7930e5392daaae1ff131cdc3800f1bbd40978907523751d460f1df51c0e8c8b51d9a0dab61b7f580489eeeac852ff6e8ffc6f468e8f9d780a6a650e9ebc3abe5d797e021a0f7597f2c6346252b7e8861070c1159adf9955993bd1eeb7d0ac155864f4094f9ac658dc85f2f32cd9eea110fb58512ceb393c8ae90aa9e31012d08ece5927312938ad0669c0a1230408bf6bafc395ff6d965c0aa9b0687a66639093cba3c5e8251e5f1fce2502da951447c43d5d1acf9985260f7a092b7a5b3e929375e635bd6a8829a1a1ceb4768a912f6249f6ec062a0ba9c0334b4b0017de97017fd2a7c2de60ae95f3be46460010ee4bce35e1f7ef15fbc0ba6970f8dc202fc1c3937fa6771c8185e65fa062b7e1b7f9a2ba3e7cb829abe5f5c3a527f60fecd62d271dddf1b7ea1c4ff19dc0dce809f26476b9f37b55b8f74012f2352683abb408053415a89e912a48b399f0b7df5a15cfb7436c94ccbe6d7ea3c94e2464e51a7e438a5ddba6f93ad9369884be0034d000a401ecd5b43a68ae644e7761f535b081cc420ec76b50165d94ae85a8e6da6892538117e41ed23cd75272cd98b6ac35925b03a17492c23875231abfc0f16f7b90c3b58f4f92d8b361d31696d704bf459abd1cbbc3aea66baab105f7b49b8bc79e7193aa07e696442f3a327c5d097f0bfb2f6cec225cd137807a8f87cba1b9fedcc816e1a0bdd6e2948f07e2b6fb0b71e3cb8886f37e0bea940119a8208ebb4d06106338d04081291cdd753b1eecdaa2270c16b2093c71d53aeff1494867d0c4bd4606785e24b7ac400301901f4209c54a911466b494b4fb183f347178c0747ff1dc6432d6b1093dbb36e292cae9e35fdae32ca9486c3c0b15441ccc27a90c062c03766fd07d77ae2ba283ea85f829e46c0231099d836da229458d5c700d3aa092d510b2b4ceba1ec11650b985ba1709604ca8804c3d3c18a4811fc433980e7d99df65515c5790f10410b8052080ef208b145ab7ea40214168461ea56d93d45a8426c30cc2699e812ec620d71cddbf31eb3974c35025e7acde5dc0ef5ac054a6e30841c805986cc1a42d1a501c0abb8e6934e1b56a40d70d0499de386a66287de65e84962c86645ecad5379ea2882449035d512649a6f6c88a91085de595f4c3b2ebab803d7323aa00c0a7358a47d83f2bb9094955494fe6853495c4e52133840988ab8a72b948578afcb2b209c126a344d56cfe56b2ae33b5b89f96c7d6aa35b788bd06ef573fb71a06075868e4744af71a4aa0b665a4fe79576219e41f2ddb8c77c498ad2167f11aca8c9376a0a199cffa877ba059bf4f461a1373a93c450293c3300103d08642af2b8c1c1ccfbe3fe4442194786d3ce3ca22015bc59259a5ff83908dcbaf623efd2c0a908191fff58aa355d48b44b1a82dce31b36a3abf6837882daf5047d4f5d546677f894b956242799e3a525b7ec3e825f4e003055567cbcee91b265e040d82581a7c19f7952547b41f157e5752f88bf60c5fe62ba56d0de6f45d130007c4de68ffc66af75ea5e89235a5f4b90a00647e79a3acbc9a0e33691e4cb1f18d0a7810442b49bfba1eb77450bc27fca89d6c3f2e631e3c2d040cca1f5579891fe1752f493555ccfb29e675fb7d5ada7e02c6d026d049a3534b342196b075e135ddc6078dcfdf4422e62400d5830233ab6b24105ab164512913578343620f3713d31a6f014b4850811dbeaf506122feb2041250a77720f52e746a6002ff074c9ee00829ad2ddcfcb8abe4b1d6d9832f9427673e9b8bc63de25ceab83be3aae9778918a1b82d6549683187c900bbe43571c4dc3673c480a3de7c9a8fff20bb320c84f2d20ae2bd98dc9cbd220330e27a78bcb1ba279b35e39ee18806cdfe7d7f6e3af5bb03401362a78d994227fd90ae65a5d63996280d857a8999b02e215da8d623fa12f3444ac98a94831d38b07e90f2cef0ec21ef7edb0e575a855ebb0a5aa777093bcf435601b82bca2b22949166a751e5ff79b046b76d730b000dcc8d75f56e7380e810bee5775d244a05f5b8c9568504f39dedff95b53ce24e68fa1e98af8cb77e5631e6dbff8f3deb62620b04ae1561aec71c8df9ce27bb7b7d64bc0b8de3c2d8525778fcfa4252e51ee6f1f366889365494a0853aac874dcde127c9941911b8606f46a9cd6a85dc027b7bc9cda337d5bfb04fa7bc193d2da402cb1e9c3f3d053b6301360a3806692be13812076fb9bb56f519ce815cca7aad43300992772fbabc34a7c2a30dcb375080de4403dc5a109d0ecc2f8de6f19c8b263398b839708952cd354ce68dcf2c6561110235908d65ef5eb404f77f97fb948b8c82108e41d4337ca53dfbe15f31db3ad487386435507d773e59f90a5e5a1a3651cd45b02773d8f71e4f8064efa3a902e815e1a0fd98446a1491f84d8df6c8e384115fa6d1ffa3265a184d3b98ccb21e885831ecddd4ec90663367c0620ab7810a0dcb19f101baeec58e171e4713603e69ef69c946a041c7cc1ecf088ea2956b55c8a9ff8b619d52cd08da70aed2f47a20fdafcb5d4f8912fdb914b328670ad64da9b0d335190d3399de7d611b9c6256b3bb128914c3ce18b34abefb09db252f2107fcd82efc9bc30190853c512156166a03f52a45922e9892f7c017e58bb3e8a7f1f538840317ab8bd931dd20cf69c64b4ab6af0cc35c56e786ead61cc8ccc8bb3c3c6bca3a0808ac03b8822f4747141704e0a783b94aaf7b16327a9787226d4f90786a832c5f2ef2e6b64111d9015073f4c8d67687a45db95651307ee1df2974ca5ace5481e1f1ea2bd6e4e41cd4036b4097fc8ca3467e030e785833f87654bb53570c28f61d52ec5aa93e37dc9f72ad8a2a30058319f8abeee5846d454267c231c982bd9a760a09dfb7824dd7ffec872384b01efb78653f9d84baa3e492c22a741d1b90fce50e79a877a28b80eb23061ef2c3b623cfcc0cb8a13c819cfe049b0b0d376bd0ddc1b8d2df6f249735a5754b6d16b42607981549d74e0538d751a716192777bd23357bf88fc3141d404bae76ddf7fbea845d6c0ab2472301c1a6d12274f3d662d91f3cb94222f8cc10e161063d204f11cc2152ae5a6116fc294cf47811e202a8296874577f8aa65c7d838c4cd9169052fe26a6382fa9f4ce52e92a659d41b6312bd1b50d2860b1c7dee8375c43ec40900223d9e35bdae127c9b459ed75dbe4f9caba443d2926514b6440a11362a04ee0cf73e407280e6d607f3e5c0646148228296f92815124cfd761bf584c90ee09ba17ae0d0cb94f414a65808a15360559c408fd0cc8bbfce46765eaaed9a4e726de66914211222d901d6fe45ce9b8162f1f60d9a90b31dd0d49972673afb202fed1ef043630776898c49ef67adab577e509a0a1a6f28f7e3d12288332ed022898c6716206176d8c9a61024a9e442adc7adb34ec8046447b1d0af89e0853c9491e871012940af7d30558190e150fba91bafea662a298bc726de678e109046cdf7ca2beaa64534234650af2c3b3f5e39580f8c8288adc95090e0a7bcfb26a7f1d3cc0c815e96e2a1c24bb699ab000e8a08753cbb53d45367116130238a4daea5d766deab0cf1b75376b3e3790f21a524a274bd517334da91689bf73e3cdda52854175b0e0d9058bc99101266105f0a24f29c8ac91420af246a264fb2ba2e0ca20e361414424f9a4529d1b34ddb9ce7af76f6c977df90edf25fe1517815c1e021de8c90025f64a97a0722d9afad4ab8766758d2f4461bfd50c9a91f8ceb27952a466a7f01bf4aebb3ee739ec2fd7e2d0f1eab3336d22b5a8dbdbe802362b14496f6a6c747ac0ae1dd13c1d084eb33d7fc1acfb77623477a5acb3db14f36572abe60141fbd4b56ac608bd45462f44d28fbf432647e2bb105443529eeacc5fec45b665f5009d400c76dd6d24a99a7a4ff2fff533bf9e931085aa92fc5c9ed7875032bb3d523bf8851b154cd57fcedfe464e908c1e984fafeff246af3f8082094a92b8d10302f001af04abaea3892e90d9085a04ce7c686dc64c9bae933ebadf1c556abf84f6d6b9fbeed692fa12c6e906264ffce27a9be730150c76ac24735756313f79fd5693f399bf50c823d5fdd8d7230d389afa31f829183f079f5e68822f1d0e891fc03b0bc384550475718205b5f5b1ca2d4b5c15acb571dd3d99de1e346147958693b1945054ede4800f78c357974c4168ce71a78703d63ec9996fdd4e911cc6cf43a941c14e66f2fbd3c0433497b45546e9e244fe17ba133022791eac05f9ae3d27fbbac14e401ef94321f6e0129fd0b936f4f125978873d5d6931e6fb576a4cba0c7834c7a451d8baaa5eb7149cf7d86c43fd55e3a9d311ea3b297f54193d741dfa7b5d024499735d23e4ed0a810018b7437735935ab0d0162850f01b1be88f6f6124892448377a29ce8e4149cace7186409e9cf99d90090b3d007d3a83ff4b652280772fb9f3f4eb0ac5888c06fe1d7745769d312fdb9ed0186a13b03b13d2e241a1e91ff2371de143e982ca0b4d99b74296e47b9671e3b7d90bf9858be611a5f1d433e0fbb5be5000c03405ca82d8034ad2afe97b6ab6421cb6877e2a8000308f393007a7bf13403087068176e16a16ad61a4b5cd0546a601961a263f922adfda6950131b301632e0ea696c1921c32e654b658285a2c267501907930620641a2a028dac050e0d103627a2a6a154304de401721c3443c231988cecf63b6b853ab5ad4c32b4a1086b4c8b1e013ba52f26c96c8254ac201f85eb73d53a56eda2e4b2caf05ca4c90a9ba417e111b6d17c84082370b7e0a0951594cdc1e211d33c11eefd09653f4028ce32b8697b8837bd56e216e73d71669328718c2499b453ee458745c462c386b8f3f129382e3a4c54217bb2156cdc131286d9b68bcc7af32731a8f03d4bf602a4fbf9e14869f0aac5dbd281de986bcd23c2e00a91599f302ff39f6947aab6a329011f584191a58637c7a44f105d6b39b41947686418dd33a36df60e621c91e2ea9e0558073f7a20385eb359ee016a9c697a17ecb78ca760da0b1330a7de30694c6518311058a8502e3862e507779d14149c4409ae8b10be32d70ba038201102ba80e295da21db101ad32a508796f5e0597a49c03c04f33f9c108268c861275bbb0e12a9d57425832dc42b682d64e3c9af3e157aa4408cc48d4f16a59a7f4860950172077d2b4693275be446499064f113846ef55aa755b06cac23d2179e3a951b528866f2872a4b5b599367e0c9625babf1919b3891836321e74c30a7701b2cc68608ba2ffbd986139883a47e937ab0972719d0813605bde34bd62e2106baafa345c03d6a07b8c8181ec883bdea7d6e5aac78414ae6402e608477a9f3d5d2f190f817d8be1a80f78d2a304e01ec631400b92f577d585967ac41f03511ffc78bb54a33cfc21317011a46c1b076f84cc4f06b42fae1fcfaa409ad5b93e5f6be0f0a60b02ea5024162856e3c263758b91287a95b1ff7d6ef443b6df104560a3fcd454f76fa30a5bbf6aec7afed8950e5e899ceb586b5f7e4f112f5abb49705059d4f2339a709d226c4e8ecf57e300d060b4e753e7571a0a71d7262c974dbd14d16f4995241fa9b9f8abc9305b81022f8747fd0ebfd7d49c6700535909afa36bcdee8cf1f8f5e757f4fe51c4d37b2d23a58abe1027bf70c445d4fe540143f0dac1bdd65477e96679efb045119353e2d8bbb87ebef4ccba05460030dec2f105e4ec8cbdb6237badf6c66c009d4d9c048aad6cf8274b5789c809dc8bf4c5b48141010977d55ed8a5c1c6b1cef254fe8837b1d0617638e48474d70cf38724d6d5e7442e4cb0185415aa02b463002d052bd4ee3f92b7641c1a33e609262611486e3caa3a7671e275e84e803b408c408f922470b1129c58a563941e8d4eb1784a614805c5a56e547b2637062a1cda4e737ccc41f1487874e0309c8c081dabffb52347eef0de26a73abb341f976f82ea82297612051a4f8240150ea5fa0b07c6521572b4cb827e4657c57e9e8e08362e68612514b75efc86b805af9cff34cf78d74f7f808d471506be09d0488297c168917044de93c68c2776e578ca6b1108d79429a8ff8c721a520192bfd560ceca52390b16d06c8b649aca0bd9e9f3cce24d2bf1fc6353aca13f95b1a555740685bf7fd9400615e76b6f64221419a31d5f762466068051630aa8fb144f2f15024c36d239a2efba2522a7d8ab84d563805cb19ddcd91c716b476c0f1538cbd034ad0fa73f29ea898652f712d060cbc2717a50dee8a4f2fbb86a350796e8676ae1da0737a83736090944627c91775baffeeed78a33f8478fa68e3cb496e129e41da07bd6fb2c41f17c7c24f803372c542a0ad7e46a7e0d0c753d95e60e8913ce694113eec95d280ad4b55488db6b71350fc6de4d477aee70885b8a22964602ac0351fd7aaae7c3a0f414239d150aecb50c07754bdb8c7e566470a58f38ae4f6b4eab52ea4ee2b6cdf970e2ee609179338d5ff506d46a52621fd44f5cb1550d507443dd1044e7f22bfade45b97690906d19f6788ce2a4383b64a791dbf395d0b1cf9076b1cda679908ee4a7ddc45a14b725101b386b17e493b0ccfdf647a01f5f115273c2eb9eb9aff8e20c7c2708091262211eddc41434516ff09dbc28c36fc11b19c6e44181070af03b30f8bf4fe41e69b27bc186871d360d27b5775f93b7fe8721b28ac5d814875eade81f8b656c69e00ed7eb1819534d1248ab61d52f84f1e004a72caf5c8df0846beaa4e8e599823d78eb383bdaf47f70ff92ba6b4fe16b352a57b370777ddc87ae43f2b9f7b3a8f5c39a96f3ef7bc82ba51620f89561aeeb936e806e0f3b426a4ef0626813dcc52aaafa76fc47a5c2b943ae8594d04366b1672b3486073d7e298e802078e9464a56fe77548afa6d78f996245e623568888b98e57b1a016f3f15d1cb17a2bef10cc2089fbe5a2203f6c505886104be9b8c6c5e7b3c3b18404d5ee37d254851d495a77ab348f0ff4755e0a38081f1fb738cb5864735903ab0523cfe065236f1e6a206dd86effeb3c58565744e24d26f813aad283c6dca20283303724143ef81dbd25b625c47fb7cb478cbdbf53d6391e4a6d6df4cea26900b91062025a850b70b0feb918ff7d43dcd06e9ac72b0e7bcb43f5db7e8be0200c2df9156ef91f7aae0f97fb8463080cadce9d4507be5cad2ab54adc68bc22e64fb3e3ae2ba58f99e8639fad36371b889e7f899d214da0418dbc3c4470b87552d8508a14b7f7201090f522b13a64b765e2c42ba472b5e0395681c8fa2b272207738c4439377e2832a87bb14b6fbe7d90342e9dc69a3d8051c6fdd602dd5d1f197f862a4023426643e8f0b3361c5ec2fb76cf0e47838fed41ff25114f917fe9d96bcbee1dcb3ec976a9e2e55e8ab01abb7afb39eba50a9506845e5ae168b13b2f55f0d9347482ed87540484d3856f17b81f7bf0f1edbc3eef5b7723b06311d84617dd769000aff6c2305767740a4a44260d4408d5ee0fe6d867ac9080b378cf41c80f1cd3aaf18fe8fcd5b15f203da2df112c103d3c4083f9f184b6ad1f22425b1f188cdccc215f8e0311a8fa202ecef048fa9f97471db630271fa81ced5d8f4788d350c0f1d85832c9e7611a63ba30e31db103e2140cc352ee720e4d6201c01a96173a37e3478a59d6a046d5afa24b3473f368af8bf0dac0ed40cc1f7ce3c1647ae998804bb353ac7f65881feb846f681650c856ae1a2c6cbe71190bbe14c0a948ae24765407b168ed6f25d85c22b7f10051d8aead42d4d915b70599c57662a8d5fba727034a91af6d705d432a5c688a0389ff69164787251c00f9217ef9fa4cf00c2536ceb1c039db86ca2ba39f1b63921b941e1d42c7e98f0e290db381b42d7ada32fb6f4b07127ddcc992e2f178a610d5acc487934e0578d07d1b0a5d9bffb75972851df09b982e8340f18705f0af40143c3db451d0821600952638b05900c965a2ad665938d625123f9ac3673cdedc791d7704c3f318a08aed37e99f7eb27bafc2bc49f93446b28ebf749c27dd644f8fe245a0d21ad06b16b3f185ccabd017d1bfee04c4ca16d92a3c2f8fefe16819161cbdbbbde145c0dfd72491f31d25c6b9fc661a5904589eb84a1c48aff52a360ddb3ce0dcc9cf64740d1ea822a08b2145aae2a0119063906e4ecc3706571d595ebb63ea13034012f21fddadc68769823642b863f9d33bc241523b221ad37dd29893b8c5161422e46ffdbf0e78800eadb9da845c5d5321bf1534213fd2430dee2aaa31910b88427e2c9a42eba7ebc52dab082a09142ae109f9f5bc392a22e4574a880323c0132228988b0dcd98faf8eb8698bb6160aaf3c5322c010bf6e1688bca65d5f791f5236bc930cf7abe3dd00096f3efbcbf8ffab1f34b365ec1dabd2b1f859c7c9f062b49ed5ec2009bf90f50ea4db1f983d5fec538dc358a2ce630a96d0040a8af12bbc73b971fafe33d98a6985f5def9b6c8c9cff80b847f6e144d0ccc5f0073f57bec3432e0bc4d7de3c05290edbdec0777bd31e7a83466405a3dec93b3ca3f9a7ced23c5961574568d370293ffe64c7bf559302ea6bd0fc16c7f59d372fca6ef20e24d26a65efbf96721e4889cb4e610520543158643f43b18598499627fa4acc8632bf9e5317994a99918f8c654d4bec62411b76f68680ade5500215d49acb8331cf63018d51fee0f665d01bc3cec895d05bb6cf8f0603014c2a1eca7afa0a2e282b7fdc63b094f293a1b6ca80026526290d98197b521e2b5175ad6723ec71cece2e6f650dbeac74610154c7c1fce1f0dcc713a6a426afe73692097042f0c1b9b7bc4c4e61bbefe2818a979ceb0404fe60a730e8b8df770815465b5d7ec234ef8aeec66d14ad2f25102170c8efacccff3a93946f7350143368afa0bc65de027db0db117978c073317d4838c9a5b140abfd68d9f1b136937a1edd86604f095f1cb094709e6b6ff66212ff29c0ac106d161bccb4aa66f383263bc66c924793909b3ec7e6fca29f9fcbbb7ebedd1cd0d5102f4146359f1cc362905d0faf32a863bcfc016927c1f6486b31193dd5ca7f3de37561ed4e18f14f39343c148c978b5be431c4349b511fd220e726eee022de4cdddff171d956914f188382e5c83b2317ca21266bc761aae7648b2d7a3243c29d96e3df7bcfcee559dea2f52f31654561fbfccab1390e4c2c6a436a66f9a453f8c2af2e647b577788ee386ae6984d68ebb3227edc559781751ea0320e1626b75aff587289ce04a6a1fe04acd230ac85f9ab58b9994a8732bc22c2e25434e69f88b34f68cd3e09a383c228647930c903f88fa2ca6b8fc7f5ae2cf46b99da9e6efd7c3855406ecd3ab83abdf8edcfda9283ccd95d17b4e500ede81967fcd7798c2dc9759894ed46ae3ac9c1dbf228ad8f15742c2b2efbfdb287e574822c51140eae7983d9958e40ca8f689de5361685c20eff44f0cf0923d8f5b6de6d28c2e0239e15dc55ecd392dc68f1063679df00b8178502d7943780674dcf5dcfcabbcbb2853615c4130b5706aec20b074d2a6058565c0b7a12cd0e6880fcc221f9d6c184ad336ae21d71f187bb0014d600f2f7ae93a764722d60ed8c96e12105a8acc09ca0daa53269ab0da10827c5d8ba322b2943953bad198cbd714bd93c06f0e017104a2c08a56cf5121755040e68aafc11ca5d2e8308d62a4d761ff257a5119a63a485624ca89162a01abf7f0227d8ca07dac6e54fc06b236e672345f07a03828daf27705a77964ba15db181912376b9765ddf9a2a0f62ec03df15083d9931fed94972de4bbaf6ca45018aaeb49502ae6ab41461c6b50e512be7bb36d590068a55045c1753e0c41d92d11e096329a5642b273ea91f7042794928ba2d92398d9365aca43b40c99ce0b2868983fdbb5e3e4091bc516848fb6fa85f6f2700a287d93874069b8600d101529681fa52890e537f331a79ac32b1930a41f18503666875a87be7b3ffb93266f78c182cebde965b2b114b67b21ee8bfdc3486d1cf380d17c52788ddb06dce4c298834dd14a032f791edf2b096f83022fc0d5420b69ebb9d739239f424090556cc8139082419ac90fc030f91dcfef2df8cefae62c01c9631f1a7706681e1139c7d25a2e6541cad2507ceb3c088487e8de6a0d60124f07f32d518c14e9f35c322793b89c74d60b6ac7988061044eff19ab982d0070f5134d2e1d5176be0e189470c26bb94e465eaa37f5564fdd6f2b75fa8449b964adbf95efda31a0786ddbb54e6337fe6a6a0a8cd8b5ad81cdc83b9e42899eda552da5c0fbe43b7bd40430ca4db196904acd59fc9dd6d2d9a1fcd896416c28677ba6b741f49e36cce89abb946c8b658402d3e71673f0deda41bc7fb6b6487bf446e944f04d7cdd1fe35d8c11f1136e2238274e338fdb982477072d596b83f0a4c56bc1a294ab6c403d4e2c93beb83bb2afa51d50f603704486579fca1a56c6823972cf7886c78bd09b99251d1dfe0684bbc1415c309ff09a348ea73477cd24f1fd2a87a78f2cb1003fde4e3b9786600eb4976e066c3f6418e25dc6ee42f9e587de0d233524e872570d07162edfa3770a0049c1c792098b8807e3f23b04569b2e5383648e10fb93b0c8d790e1a0b5bd85a7ac29d15fc5d77ed867f1310cc37fe6e37ca687a518c88dd5535345fb8b4719f20719615a0db182cb74f9576b3b8f1f8a439c04172a293f0c4eb34759cf7cb302e6ad0ad0527e05891b90c3b5122cf06957b37846e12038225f01bf6dfbe94e31b675c36c9b0c65c9db294c0154cad324a36b72413ee68af50c5e8f7076af3628b2230fd72bf44a721bf4cf9cddf65c027d642a18db7dddc0dbf1212ee4327657149c8b0189933b3a83a5da495d9fd6cb0a1c2f4520419ba8a26d79528d715f10335a0d4101d4f6da509a3c2e3cd32c0efef852114644575a7ed150c66813c0b7511e9463182517aa608fbdcab48d152bb9ddcb0494171f5253c86f8ff85cb1c905e4780910708422172cacc0962edd2f9d7b08e56756ef9d0965228d5d7c128c278b456c403c5756467cf3764a5987e0fd0693cf5cc8e75bca9ad130782410cab4d51691bf04f3b4130cb514f4de8b4e1acfb85ef18c3e689b2bbc07cbdd64ccb88fab44ba4cb9d7d7312ae0d4ebf8015fa4f9842c83268f2444bac6cb057717048eda2907d68174555cfc1c5bdd6069ec460da69962490f44e20041f43c23ac04964388e08d1c2db030734c10e6e84b17ad86bda100f678967dc6a9c8523469f1f362c7c1def807f5914d1397b254a21ca9d98dab989fadad6fb853412dfc3f63168e9e253ba61b39b2e3ce0165c5fe2de1730d6028030b144c3b3db810f773ce4f98dcb3ee5084a62ad2d076a12515d790197eee0cb0dadcd55cad4614d7d13468234b78b4d29625faab6768dc806c139011752dd36d096c57a4d9e4086915bb9d019673286ae37b02506283f13f2e272a31dad8dfb9eec4e2b48541ab683441fd5854d498757c5e0b0d2b3e31dd9b58a129671243444a72bb75e92fe7f32779320b042e8e1a908fea768a3c292e09320b415865054d17da8168015f0721de685faae1564ee66900744c59ed23d2a839c6cbf582341f8eb41120661b5363188a5ee9431a8bc29caac697344b6abe260a5d304be621a9a00cf171446d6d1de576bbb97864c7792b05161c7c34f455397eba9c509cac949bf71399bdb9ea97fb38277204bd22964ed90a0c0612060c56f7106af32da9f387ffe107d9d099771e509554c1fde9c36a4b4ecd4358bcebae2e29ed99f953e910b5891b7269cc9067f2c06a842afd18d157f86eac1be24a29c9c436ded017fa41a3a4adf75d5bb1cd61b35b2545070086dfb96b246bee7424b3323f379e3e398a527611ea627fa2423ee559034f58e01c67c1573971e42675fb637bbd0f9490d8d8b0a05275651c73d0f6ef35656b58fcfc8a09ba244e2a820769e1316ef82788093076d1e342e595f2b663217e4d2f3260cc6b1c74d844440bba0e4feb2798c03a0a0d045af4a16f65038739c54ee840df2fb9561d32cc8ff709213191d6631e313b95fff0de876c058e23f9d1eba5ffc141640f445c520680c96e8bf7431062921c5a5eb5f402efa7db7efb7998497e7c0caabbc6bfa51e7311ef277185fec4d8e91e0c8d8438e9c651be58019da1fdcbe97d1a046b9c0114488dd928618f71202672c33234fce51cb15f4a6b2733eedc8590044a72aa83fe8a3f79eb1e1bbbdbeb00bab7b2282e801957a693a4f4f0e5954cf88326ca59fb19c002656c12b5dd22e710cc14e72a947050735a09f168582d782d459c5424944948151263cf65b3ae5271bf377e11f235e82966524b1e9aeed22dc3ae3544ae660aae370792182f07d7767b4cc861193b79adf7c8716ae767b1760f958be5290b6fd1b48b0a12bc79be3a6e2330038bf7268d478f83cfefa3baef16f279a6717e616d586e693846fc49462ee5936632e0aa65b05834ea6fa78e6d4a9384bb905a1fe1b5d4fb6788a109113d9be875cdb7e33350e15d038d44b485c55f637f4cf50b8b6ac9769e400d78ff8f8a3ae6c7eba2a4be0763fc70e6350c6a1a2a64a18fb9c64cdfbd52428255502e0858de1a04ee3297136e9c5e588b50cda1cdac118452315f3282082e86b0c4be17073913718bb8346dd8756a47e59845d9901718d53a7b58ded58f442d2a6f1fb1d35b07fdb0cc2cddc5f0e64eebfa18b0b5e6ce5fe687cf1f030bf7c5146dd74c83b1ab7e104cf47ec0bf01947660ca532a778c02772a1cf4d23827d2b9dd3c79e0b9409d0d91cadfaca5056eca7204ef42ed44eb1b1e9443d81d17aee5f0fcc95723961d6d5f6389e86a1ca0b1ee7a30f463e39954207a5049280d2beffa264e30192325a59caeb9573eae34741cc635bdd2322b11cf113ad00461732dfa3458d5bf81200a66f9f79779c844e20845b8a8b7b67a0e64edafa20858c3567d3fe433a7954287fee03240d983a7cb93b46c5fc80ea253a622866a994c01d4bdfc3e235e551392b064b4a434e40d45950006c38b448ab40ae852f9b52c45604235dec6145f6a66bcd709c71396c903a196258591d6cd9bcb7b7bf70b0240106b47b5949f02490c1450002bbf9e312d0fcda6ce5b27e8a6a82192700054155ccf1a118a0d84c91603ba9075492bc4d380275e43651228582481a1a7ea22c35f20be435a52b664b1bbfaa8bbc86861e077f48c84fc8df7b8eee2f522c5b0e756df61474d3e13a95c6fc96e92aaf5da158307abecace3ca29e5b7066b2db049290491380a641f3bf5a87f12ac448a27990676571ffc4a4d4d1446a7bc8f25f5c5bd609ddd79ac0120dfd0520f4f3382e28dfeab834166f4bb27af544399c117df06450565394917c364a517a7a10c310d18f3bf7ebec3605b704ca42242be2532b00166d6a3534d74dbf16085d493c6852eff9a4b002f6098923ea8707857e1f08087b0e69cab39090569ab59df8e5f1035e4e4d21673831592b446a05eba947988535ba06b3ba45bccd54845d26d36a4a8acf5b6782e12a55d90e55fede0fe5f443b57e811114263c668e91806da972a6f6d3b8e2c66237699a1c5a1ca4396a91b1531d458adee2592247d21fa938709647b1b428d7ec9e783b807ae1f835a8327aefc9f4b359364f9d6fcbcb1c4870c0034c53b7dbd09452e449bd224f1854843f7d54000a7d288613225a6c66381050261fa72a2f9d7912240201ac735ebf77e5210e5befb703ca4a6300d7c0424639ed8d09e06c41ea3a21a87b3950392a2f783faac210726220b492b38f90b45b46e671223379a6e606cbe98bf66488c5223c665151290838b8850524ef971ab8d918c70948a62be09aadea955b105ae642224c6762c520cfc44a86db2908536e7ac4782fd7d2f4c4a151aee54982a1b4485cf6b84f88ccc5ad420dba073aa574da294dcc89232b951f5cbcd89abb9eee2a80c5a3ed2114c21e24537f47c7e52b0555d7db24b300e5acb4375ed269673149d42a5e1e64bd778792ebe96445ed33c946f00b0b1182dfe1aa888605d893c398d48892d0fe6016fa3de9665a7422503d10995676f1b4991112141d832422f23ce245c08198b451c7bf9d64b9989e4b5575dc3f70d5b95746a1b8fb26c7ca9490670908d724c3708996af3b9d664b044f7e4950210a2896d13e54a8c1f7d0e6e72c37b53195b11f30d1a620462c02c65470738455bddff7ffb1cd289338ee9cf3bffd169a7650f9ee481544605c7ce19063a87777f180eb77f908f230738a822bfc675d2a4ec8efe0d24fe7fb14a0ea168af7e41bdc822cd1cb72f73e212f3f3d8cffa62197a2795d2857d0aad8af5771079c68935f2727d1930466652cce0dd947aac90e430b2a3bfcce0326298cd480b9a03f2f721eeb4506f5df67403669ae6c7688576cb9dc4aaa0f7f05a11db6c48af522f74a69b506f740c4ff115f2cea0c5d2a93d8d591175445daab3c24e17e0da5b6dda585683494afb3c7423874a235a89de6ea4dacc0a3c48d6e06d83687faff2fcea016a2822cc25d578c75ac9f9b68ebb531307f8ba97f3645361c921369f25656f9b38e547bae0685105b34d0d0e8cd3879973c2ee6f1d99e63a669534d9fa7baadbc97ff89fa9f161ae23dab1cf8e388d355433c816fd73404dcc6901c10c6cef13b9b5bd7fbd03dfab0c3100e6e3dd88187d78b3922eaa803e0ecbe3e6c374cb85dac51f0233f075337912e82e1f884e4018ae22005352d4d3d159d81bd40a5ae914f07f26926a2af720f373be19c36239f2e9b50cbda9dfc7533208a04eae2cc68431bfa0418a0b976d3a204f71c2820c4ce2db4dfa5f66d2e966114c59d143841bc7e82ce9a2347ba002a6d5777fa5f8588185503bd70362e15a845d103230c240cddcb4d0edada2be960d095aff43f20d68f34271cc69cb4d40260c368066823d03b837e0f44c57a602ca1b70703dfdc05bf56f0ef9acd46bad10b58aaae821f91b114da682e1ad3556f4c28875c2e5a3bee0378c12624825c4cc305d20b162ccf76502e3450747f0795210099606813a90863cea75133814bae7767698a76c016faa3ab21b61c5498633d55466f2d990760c00fe48e7d64417e3a431358598fc88f0b78fa200165b40e5ebd40e35decaee6fc696ba546c929c72813384f43923a4138742a443c24c5dbaaf6184b6badb6dd32450eb05ae99032bc5b1fd2204ee4f1d149f836b084573b97cfbba9bdf45b42f81f25223bd427fa528e3718e6baca056bc083b6f89994c838f910eb9b2ef60e2c3f59f9f05b1c6442df0844cb906aa7aff0291659954c1dd510d9dc99bcb9576e21e297124d771adeab31478adee2e34f27e5352d8a43e8499e2f3b07c51babeb5ae7491b4183a66bd84a1b6b4d124e87456ea612a4da147ad49b5fde21ac34ce49c8ac1e364fccf0bb099a75af914e1f60166008fdef134e3999488461f9bb227825df4ad75ca08ec27ed200cd0419131ba6335bbeb9bd623b4d9ee96dcb4126f427e8a458567b7d36f13487dc140bb2587fca48162adc67cd0769bcc09d309aa6d09b23650adcfe97652e00d1e24f1d8d2105e0523ce3deba68e3eab113c5aa633637cf7b1ee413dc288de57f0588ed27cf8ba0732e5a90bcfef8419f1acf73f6318f7610ab07902dddbd5bf84a4068f5249e6d5f6fb9fce44c661759ea3ccc76c031e814453d05cb71461b84aeb028b6143ea3e0dd4231e614650d452a423b5a601db29685d05370e369f4939aaef07c8c1f73f17a51b5e82296cd0299904a098a7c97025eee55d14b29519e75f12f5dc09f4baf55bb8e58c4e061c80dcee40b8cbdcb662a596e9daea7bb60c8ac2a08053ea37f2584c6a1ef5e2e02133d8abe25848e94e61af5381192c627f54a121934a703ca941684582056b24a07f26597e77e2fbd1946fd6760593e9d316307dd13c1cc5cd5030680fd9fbbe537813459e0f28c39d16d1f823a43ee45b6a9ce15d5c0480fb04a5f9178aeb1adec2563e0008b56d2882464efbdb7945bca94640a5b08c60743081ce4f6734b7e06e248c2862e84f373dbd21591dbec59f971fca3e6421e61422e452bdd18390e23bba217535a0907ee2d6e8112ba4e646253fc3b3ed9a64c791225174c1d9138454e59698ea223ae742e713764a6302ea9b9f1a8874b32b211cb9187e32db9f52475d1e32ff6f1e12e1ab1cb3f1d2c6b05298505a41591c202ca5e7e2133b9118c9175771e7e88a6cb11e7684493021bc62746401af40634583445baccf58f5a6a8818298b28ee91cb754cce90c4cbb821af31847361c368148d5ac8cb183e2c09643e3afed286a28ff69b0d3c1ae25127c05ffb0858edab6133faed63a282cff63dfda33de649d93e123009f2d15e7a524640030e358c407b157c827cb4eff12d763ea48c407b29db47821afa4be0c3dd8ff6d1107dbc411c7f09619deab2b1cdd67991b91c5efbacd142b14bc7a13a2939be3d1c1e7bebf4598eff7bc45f375eba14563e51617fc3a38149f439c206907fe3dba321faf41f21295d59fdfca8e58b928ba568f4c5a42f1e6151f2d45ccd7c03b13457ab29af944fa43c41698d2bbfe5af66e6929116a52ba59371e5473594ba7858572f041bc6a335a6b02c1fc6a75fcaaf76257db61928bffa9939e77cb2f20060836d8761793a9ebb16747c7b355ef4d1e1235e2935afc36379dad778ec53738477a6cc873a2e657b2b106ff968ec816032cf1e83fdcc175aec6bea65bc50478c97144384f1629037642615f6a9172f05ca97f259be7c50e25c2925273f8787c36b216fa1bc76d2445de3f5136fc9674d91bf153971e5ef68b234f453895d20d05f03096e3c0ed1e7c627a58c5db279e5c735983a87bbf27b4a3bd12f0008f5122d574a19a5a419364390cef1252197622e3197984bac8bcc6426a5c8921ca9df94321da386e79814cbe15c5bf7896126a0946294821527d6ba5a514a674b4ab9c8cc94524add23bf5ff756c3a5cce73c654f2ffce60c1bf39f93e38db367bd724e2b95e0eeee320773777777c7648c4ba639991963c6d8c3306c323327ed650c0929e7a44fe56cda22e5e7be45d62cab5ce4dc82512e1bc7338b8f25e900c93927bb2acd2a9d53c75f2f74ab29c0376d01be2264bac7cde71727e63b1a0431df3cbbaa7508114782b5f94a31ba84ad52003fd8d465242cb818c3dacb485850017e81050d70c02209ab821dfac1b7018b28f216635800d104c3304c054b2ea840cb009ec06207af08e78a0757b2ca6abff21855bca06b34acd8c1698d1b97a051458aada2835395266b650bee06537448582cc9ace4dcb0e6aa9e7170552a555293ab4ada82b7204aa56a6eea6d6eea53a92b7eb8a92bb0dcd40d82e801a8e57e0123515f918070516fad407151cf483c705284aa904191aae474485600a1564a6b2e0dc0a5b40a1f5c6a45511534e01e84418333785812f2c1aa38d21281d0c419480c61791c39515153ac649538f2e5eae80834260c1555ee2cc09d54a471670db09ce69c734e71842b6bffc089271ac663871459dcf9727e8d72e7dbd51457eefc0771a494524a1b3421a59472dae008cf0656a42062fe9cd3872f9cd8d003305a70848b31e79c938389020c1c512461f5824d8b5a6b553d11860f9688a2972788d0030a0a96d4134d442726cb830f9d1051504634e1a29c9218628342d4219d407b22c479e1244b41940d0a317aa84318695014e107fa6429b341070c668582a21ac50e3c4c178448a25140c941c2ac86bcc5350a24807061082d5140e1c4851428457185095c2062298a1cb8f0c4c82ba2310304cfb03097ab141145006a14e1c40e4554013a29420758952280e0a40726b4748b992a135dacd0ca8526869e0041145104af6856b1b10d10b12b82cd0013e19db8a2497d31c41bc6a42c66d56312bb20c03e31bfc5206ef99be0faf340c4bf566bc31587ffba212f6d552c0c6dc41bbb1e3f319f51c1b9acdb4b09e2e8a834f6d3b3bfb8b69f2aa5a1bef03b893e33fd98e4d2db3310fcae54e6d3a25beeed1ef81e84f8e27acc47c45b3ee3840d75e8e09d7ea2973e19b1c5dfee1a18c6d3088ecb1db8ae354ad17ee35a6b0ff6b1ead724d8ad0df382284563217e7dea15c9324ae9ccbe30d2c7aa473f529b6ed9e37b5c62536c395060b19f397eb0fcac060cc0a0728512582831f9c497b10138f2ebc962fd5b7d5f911217507ef09dd8b7d773a77f8fdb2db8ee188350843aa5ff832ffdb02f94f383b0aaed60bfb9234e82d54b3df6d9e2a89b882f1a88a3f3d957d4a9e3e637bfe370b4f9126befda59c72cd6e834de19b99b2f1fabe37f968b3407da4d2ccc6524a3265a2db0db6524a3237880646485910e6a58ae09891a24a108260840440d8a3080218bb5d16a52032d60036ab0342f23f5604526c5d32a0c16e2ad9dc9c308e01300b0e38fc9bef10a41ba57b4303100f35e6830e29c80009efbb12b7edff82c9b8bbf79949977ce9106e30bcd205906c18285b1f4910e8e4dc3505046df12843484b0d20eb604218d20323a16383b7078ecc03140eb1aa051a8020b50d244af95ab594dd178de110eb361aad1b204be846c327a1a42b00ca94228c01d19315b380de756ab93d0a3b16d31cae8b1b52933efda36d4dddd1b7377d7399239b20747c75fd8ecee7677f7d8e5deb1bbb7d34c0d5863c0c72efe2ea6408169107b49b1ae07f65e986d15fb9ec6b288bd0cd2458be130c7d2c9132a08bbf87980dc18262d8679956a84cc74b78de3ce89329f64661bba7f5766cccc9699ebe4103ca1583ff5a6645469c1a114aa4255e8052e7e55a494b40dda066dc3c6c7e8d3261b9f37ea853acc1fdfa56b524a29a594d99c2fa59452babb3b7f3dd2203fe52ed863d8d4a2820df2cca47429a5942ea59492c1adde60e3b39452b2942e8fe0a72da69c5272ec32659729bbc8c984c904c90425cc39e53bc628bb4da13ad8f82e6990a997ecc8c86808a329514d4d72367199b2a949ce262e534e2967939499724a2e7236bd787c9fcc2e19e717b99c3c2544e614fb28eb9cdfe3d393b3004e6cbc731ac166e34dfbacca4c6699967dd56483dbf7f4f6d17e9edf13fc8d7a717e766adadcb6d7e6c7e9fde0bb3df5f8c6d82c03468d0d573d9be296ffc74e0c7bbb1f7fe727d303ebcf752bf2965d8fbdf97d27869d9f7db6413965fd2f321fa6d3b25ff96fb3004e3c09bddac70273d3cdb0d9036773c28a0f4337895fcb567e58c18dac0323a594527ea1119c989898ee7e791a2ffcf9617eb5aa55af52a9bed008cecf4f4c4c0ceb5931ac2fe6865dad98c8bc3c8dca0b8de0e0dca059794c66647e62626038bbe2602a0eb7aa41b5adf2d26112192691292dd5b5bf2249e4f5b76ebdf0486b1d0a853a9d78e774ea3adee93a7669cff18ee4b4df78476e9ba6f18ea66519bbb4fad2abecd29ef2cee9b59fbcc33ba9d75ef24ecef61ec63c18df68df9ff23076f59f3cca3c926ffab5774fb24b7be94d76699f3ac9937fca637679cbe7387bfacedf7e117f2939a97a4ec5a99ef30fc9e993d244f5aa6fe6552a99998ff9f92b7fc1fcacdf9e6b2108baf6b9af5e9124f2da47755f68bf7e6ec69389f12c8cb73a72398ee338958ae35e5eec498a8d6deab680edd95b42a53e0eef43c5e3e4ec943f9fb9c8a30c9b7d6cba217d4d03927d614552e443fa49d9a40cbdcff695808a7c2acdaa57de8af960ed7d8006dd47639b5f04491874432925a0529fcab645ee7ab40ffaee7fd2b447c27d32d05cfb1aa7d99e6e6603c8741880dbf27b1c8dc3636e75fbf3553d9fbea755a7af764e11ecb3eeadfdf6c278bbdf5e3e36ddd46f1b6fcdc9ab39e7f9957d65fd4217279f7947fbd3b7abbf507b1b54a47941454d57e39a93af79bd3d12fae10cb79381e6729f7aee1e502f12fa2128a27df745b4efad3f24f44329f39bfc90d0f65cd62bf3fdf621e13e294d645ee6e96f350e78ee7e707c4fcb78d55b13c717840da07a99afab42ca7ccdcfaffeaac121f3f337d5b7b7a341557fdfa00ae6653c1c3532ab97f998d43ccd3391f91baa9f7926aabff1d65f333fbfc6b3dc52fdca5f377ebe8ca7fa1e87f1c2005cd557a47bbea87ff14223ac74431074bbdf842eb32bf585ddd7bf3d5feb6dcfbae1d1784c561f0dda0a8c98811041508183283e3cf3d9adfe0d1e68d8fadb56fd45c3126ea3c947e66f883e43d48749908fcca67dbff4b46f85fafd80faf2bd5b81ded63efec9930dbe62bee3623cebad292718563e8b85af97952ee60019e2cd3ed60af5d23742af0c7eabd2152e98ecfcdeb6ea890436f617951824109b7cba3de6965797df0af5fac73e415d82d82d3ce5d842561ffbfa19e6dc7caed7bbc9427dac3275006d6a6aea72b125d46fc1a873642b5df9d987f5a994a1f7d1be12b4920f957eacf3d15fdb9b9f451d77730ef3fafb01fd45b0fa2d18e9b863a0e2df6c1d4485c7d073e707f57cf71c9fe3f6e750419eece9f69f7430337318743d36ddeed9f568f693b3fcf9b2b080db31b05658c0ed5f0037dd3032bbead1c468cda6c635d87111d6294fb27315e8b8f543a2e3d69f3eec4512996e8d4b1c79e29491a79550ac6ea1fc0ef2e137ec5898efdc39a0629f8fed6bc7c2fc2abd96e26e5e91ecf96a5e91ec63617ddd0b5d855b3f242adc1a65bb3c85a0af0cd87d8a7d2cd82eb6f86c5314b1b4165d6a72f02407368842ce03d2164b785ec7288f36c6529c174497df89cbafbafc85245801d9380496b1ec807451dc391e6ebf6d918b6ddcf95d3ba7b2e06d08ddb0044aee6cbadb77b92f8caf6ddf378c9fbd772c047953d3edf19edee16a1e17a1cfb77a45e8a3629016fb045b3fdbcc96ed2dd333bd6a55c3744cdb4ef54bc746f5a9bba6f9d67a6bae6bd3c63a76bcf1fd95c586a561fec81ff957917f26c67ce10ae60b2dbfea88e872eab35fb862b141842516a13e2e62ed86c74ad1ebc7589c915fc6d58ddc754f0bd51f6859776466e62fbef65d2337333773a41f63a4941e493243e7546c6a571ac4d260fc8c1081e185af71aea051609b99397baf34f8168b62ccb237d2491dbb3b7667f1e5b6fdb66ddb16330f89c77844e784418f02db4410613771fd91ba09de6116e294ed88066583ee99d751fa8829ae431147252d0baef30be79c7372546c3f7fa1ac517af4b420ba31f7eb12b26460e33b958d19bb825d91f259baf7732fb179bb7bccbbbbe3f01a77f71befac777799777787797777777777777777f71fe2eeeeee38eeeed57d453383a326d3b04a3794e54e5d4a05f3728325a3847583663523a324060c18d58b92ee74ea524a2cead4714a68ad7453a26595e6f84e89ccd1a111d939e4155b70f4cc112d34976a15ba3e31724c3774a62e10601fd7c23e397450d9857dcbef3a439d4bdd85bbfb7b8f9618f6ad79365b11b91ec52676e4e3dec2cf7077af2291d8f86347b99b73dd845fb6871bb95c356a3e8c6b5cd6cfcbc894f8f2acfad4c7eae476dc5ba6d6128bbe88568b78426dcfcf21022e53c746452ef126bef64cde8a356b27f1e6f9c75f9e14562391c7cd8845456e9dc8976826262277125b49a9a8b97051f21797c8d35ac49bf85a70616a2791a7978837d1ad75a2d84eb468a9f9c215eb0bbfc64931ed84da3acebea852b3fb81dd1b344966acbea4994fe67333623a1b7c4b1a75094530315b542fee728975a225525cc7c4c4e44e2ceaa4c4a553e294b86c182dd2a2a8480bed732dcec4a5c1a8466f914b6e8cbec68d436057fcb05d0bbba2141cdfd960f943d7d2ccccccfdee9fbb96226c8cfc6125aae9192628fe4a713aa7c38814bbfe1b31c8db3caefcdd3d41b1f4b18fcffda6715bf65aad5ddb3bebd495479388669986f5b66958779fcd8dfbc2eefbe91cbed147c3beb0d2d45b54ca9e1e75d2ba8ab179f577e93289bd4831c62aabd58a777a48b768582b76d9558d0d965ab1974fc32f03649ad6f508b2e21dd495cf383f1f9006654c0f36642c38b458f98eb1a0c4963ddbb24cc5230a214123a5947ed635f6fe713e730dd2efe94a64bdf31174315a44f7a675cbe03124b1ec924f3d1aafa65bf235cfa65bf2376fff56ec929b7b2cff90afd86028aba1c807fdc21a8a2ef5519ffea84f7fe3066b8cb49212b726c1aefab1eafb576badf463cb4ddb5b6bc79ae6f0dad12d6eb5f8c64fa0975ff4f945bf1dddf2c7be70bb61bdf38b4166a928bd1d382028b9e8fdfd2bedea9d8d4de6784dc5309a2465e87d28f6a5d0a04c815d724a4c0576c95700dfc8df648f14748c6cc8615c39a473c2958e01704de45100dfe4e01d156e5060f0a5c32ef9f3637c92d1afaf7d3603a25f310cab7269cae0d421a961c69578d4f9e062d1d6f9d8ae4f28ba3f82f5892311b5eb9e4f1fa134189f28b1db0c341c894e78a76ff7f18412b2dda35efb6c72bc63bbbc46c0adce7e339c86387d7dfab1566befe9749ac15f40521f0ca8cf4883324a2cf758f730af7ad99dbeb3dffd0cfe02bdd57d4d755b87717d7aa95e4e24e097eaebbe1b724e9f0eb77b1450b7bae77ff18274ab63c1ef0a7cd371dc6f282f88f5f8caedfef49da058ec27e8af15b8d53d19b7ebba0f756ef7ec5de7eabea79fd8fef89143eef6e985ffe40569b0fb976e736ee66562663e2b1353ebdfeebbfb5902d3bdeafbf156f7b103d260f72727acfcd87d4c2452fda97b98d3cbab4e1f0bc54259d4dbd3a34ef6843afdca5bdd9f76b0a7eec3d5ed7e86ced1713becbbeed9a6fb8ac4a2d9a726b82d08cb0daa61c615ad8b51b4eb9f7591c84776fd6b17857cd4eb12099273b7813962a3bf69596c162bef64cca33d6fd66b40b7e847af278506290fbb280a7c43a906d84561f016cd00dfd06ae90b7449763d2aa5f4638c315a22fea2f1894486b0f6535f14fa58402fac98b7cf3e2f1fe423559f7ad5c7024ad1c09280ea6154413ed9cbcbfc4b4d7d2f1f7b2b4e919bac1cc795b7e8c378ff42e7d00869907e7b400d6adf4f8354c6041de01d19ec0698c79f3e911778277bfa30748ea66d377adacb08d9909788f00eeae96780794e4f5f039cd33dfd0e700ef7f48b70cef6f441c02f1d6fd19fd1e1ccaefa272ff24dfdce7306eb731e65b0fee66d0cd6d7f1178a932e7df6fada47fbeb117dbff42fdfd0fae9b08bfe098adddc7ba1418abaf523c22e4a9ffd6fb59f7ad587e32dfa2f40f653f56365f5b38f95696fa495b4ac6a35ab0f7a8bfe69079b42e760b9d90734a5c1faf1eb740e4d143af97067add507ea9e7cb0b171b0f10ec7925f5cb71ca65b1e39de9827e31b7faec1d6b2d8adb9ca2ed724d75ff4954817684a833cc5c636dd200873a3f6608b5f37cb7ad8254176a11a1004e3c0cee96f4757ae87777a08107f116100ef58805d3c14e01bf9d2524ecb62b51b72d6f9f00360b1f236734efdf60360b1f5fde7e9bbed39a0d367bb49e9c7a2d91bd9329a51a6239dd3577e922c56de21424e4416fb285bf7eb9efbd67efbee7b0e48fbad3f963b7d23ade44ddb9b8f72ecc43a23421ab1c929de6ae951640fb51091d785c9859c49cb1253176ff563515af2566b51aa4a995151d2512735166ff5917614c588e3a4d745de92d2eb28a827442dd44344714888a94b149ae1486bf196901f18881c252d49e9e9e000e9a95bcc13194e7a9168860501f601bde5ffdef228e4adf68e784b7a44bc253d21de92de4f0d273d203838e9f5e4e0a4a7a383931e8eb72427bdff38e9adbc253d6bc349af7a4b7a2c80959dc14a8f0501f6a9de72d90918f216c8498f05243f18bcd51fe4b371ebb4590103e946302e237df1837cc55c19666e7c18dee98f30ec8a32d4db57cb627d75e58d4fead7803d7d09843dfd3e1616560d45379c6fa495e6d785d2f53fed6081a68438389d1373c4079106fd67f7d3e0ec6910c7877f83cd4bb6f0c6652d872318bff0bbf1f9dbbfb0ef3718afea200aa101668c31c6c8aef81e5bf16f7c8c4a4a428ef4e0064764ecd84c8012853ef56cda61981c815235246717135309619c77c5894f66b0f20810b656cac4c474e4c81115143664a623a4e61df9354b42a6c1e460436682b2bd98c15c8cf47041709d92ee74c56e27948a092818daaa6cb02133f15175e94920423a8bd44b1362528aeb1893224f04d231e945b506962337f222214474705216757a51ca89b261d5ae62d738fdc2f9be756c5ec13d874d32738c07f0c2c2740eb78a1dc6b0c63f295629b4610392152cb0e189248c80c40dabd665a4329eb8a7cb483cc8610d185bd1e83064b208c21658ace08c2cbef0342a30450926306083871900c194c4134af8b0050d2c43284388223ce1c5510f16a5140013765eb69203130428b2f5b2951c90a04866108159c961e86e97ad3461a3d7702d6104932266a0841437306a1fb41449741835a805549a8cb6a8428910d478c2a70a2a866842858c13302142900c94a0820aa32fcc6062061a407409c3084e4c21c4141d7079820344d0c0062e6010c590920fc188043734f1448726286109679cc14df082cb900cb890b16404dfe25a18074c8c8104222ba46c9101ced72c965042b542c4e4486594016385480757bb6c85080b256af31bb513467d74e5092b188a201714c1a8054760b1c610429e250442f0392aa3890a9a60804614a38612436432a4022f24242424b4c589932daf4587036891afc396e82de4d19b9c6c1c5fd873830d13bfc8c3374c126f94427fbb51250ebd0f76e304966f84e996cb1b3e08aff2eb7e649c445edf912de994dd4a3d61e3cf2fda25fcf894131b8db055ece5639827035d210addfeab55e6d56fbb014e56b5c7b4ac22f19034d03863256cf62b599379d4c3784828babbbdddbbbbe79c18f6cec4564694324eb0c619647421c50bc808828c1b968ca0ba8cb434c6cc65a4a5a4251a2c4959ea610c36c640c21867c85c461ae34ad218518cf182315430c6500e4968a265088b09c4c8811855c49881182e10e30731726023e632d20fb460f9c11596062eb8302c38228816fc608805b76b821117264b142c2bc0a2888b824205b7a302e5724610714f3f5c19228b10f7e53252184a9edc4e8d2b29c88282ab9d11c44d8101c44565f1c3f51b5cf1214b0f17ab82e8a68a78b8f40527b8d5881d6e0784934b2f23f960071dae652387db3135b95996a1bb8561828bf10087bbe180c99d575c5992e5869b4971c5862c4aee160329743b175c69cad2c69546b071ab1057d6c8d2846b2f23f5a0c915266459c2dddab8d2258b126e97c695247041421635ee16c6e730c3fa11ae5f4602030c30ae706a051ea51777f2004540480bbe04549f521a238db45aa01f20ef6d9a4cc005e6f1e71d5a7fae1a9c5f6570b0212bfdb4108109580003fcd2a94a3ab5cef97702fdb06b2ae18029ac341f5c71346b28c5408ad534987d2c1ae96fb4522c64d51f33d6844666c4e6a45fa433624f2316e7b4737e2c6c3ef6b1300c9b139bd954025cd5ac583435362be660cc38b2e2332a3a02408d0d8b66b5a259ad6c914dcdaf56384c4c61f31d0489c5528079f855bf21f4931f0e24f586b4101d6cb8ba14c0b1d915c22effd313db92597eac39b1297f4a39a5bf5c213e46619198babbab7588191860977c29dc775ab86f488331604f7f089117302f89bd1660579d31e98b47f128c3c17182e3afa885192bf94f6ad147b153e2508348d90c6c4c3aba72a59d81893c1790e11d0cb08b89020cde0879626bad4cb1c8a4e9c0daa0209ffea98951b3ac9ed0f276340fb0f22bc3aa579dc60acb3ef533d495f5ce2484628c1c86b591235e926e1561977c0ff08d740ebc61977c29db73de06ee68d088c300faeb87d6c73a1fddfd61970c13ab02bf56de927f02efcc977fc32f06230ff6f209b023f2642fbf00bc739379ae1df6d26f1579b0afc53749270800c3b00108615c6a0a51877fe8b44efc8142ff40c17da0905d9f73fa9c523be9d0d9d9c8ee0737d8fdf8f958f7c39b92310c8b18d6da09094a763f5cca1fddfdf0ee47164baf96c56675326d6cc3c1649bc7d91b564d567bad734194514a83505c4249c02ef923881995523fab948619581d1d22f3669d8feee228b294526efab1d7e3587772c262f3d3316fd8d42b6a566b96d55a9bb677cd6ad0715cd771b33d1edbaf6aa66d9f0e8ef6e9e0b827b3a4db9e28875d591b1362dbb8b94d8fe0abc5add9fecdbf524952cfa32e62b14b3e0ddf14619eac12bb5babf5c3191b1c21754bbe94ec352fab300d629c7bf18838c58b4b744b7e0b8cc06a8c825df2e3137ce351a278378c464652fb19fcc57df1894fbe51f7b410e9c355dcd0fa0d1e6558aee2b27bad350bc08d4bd5ca0b53f10bfb6cb8cda673e263fcc2dea625a57c7e9e99e117b317bf5bf2d3b055e9a773429d2b5f2fa49342e7c897cf2e798212df0ba5d58a5d2ef4db2b1f8877fcca1701bf70b8255fca9608e057c8d3b15f401d060dbf70bcc53b4da441f92f6ec97fe1c89ffad4bb55e7006159527ab9e1eaa66eb7425fec5babdd0a7db5f7a858edb3a206811a940f34a48508b04bbe8f1f2a4a1e15cb376a58b20d468679b19734d2ce86108d146157e5f100dfd49ae5f0e82e07a7c1fa59e61969100625360ee1a0842c8f06eb6799bcfd5e03d8557f93c9c1cae01749bdfda83fbd4f57bff690c2699dd6f568b2213788a37b97a74e2bc2afd3179d74ab7efd803882f635e1d6df28277383fd10e7662feeebc7a1531c7a20feb2df0a25843d7ddfea22a95d8f9f25a8afbb38d460fd9313566bc2adfa462c0961939e685eb5ded250d93357351dd8556313bea99cb7e4861208f970acec51570af771675f1c8252638dde12ee71781feea3a269bf753d32da0509ba5aac7555ad91f9b1b28f393ef9e2a2938e43cd796c0486ce89482292be8dfad3671f89bacf501fe8adfaa78cfb2efb581a4bd37ed3b22dd3b2f756cdbefa30b06ecdadb1e885093892b20f549f94b08dc958794cff64171bdb586b51d7b24beee8168f6ea598a7a5e29d137ce686f64acb3b280cfb0dbba134bf08f65549c106a5ddd1a0b49db303a6b31b3b20a306ab538e51c29678c7256c138505ddd3a3b03f7d2c20fb27d59f9e7dec07f954d4a7b0477d2c20d4a73ef5d150c30bea837ca27d98b7dfc37c8ca1de3eca4e89ac18a3576f4d4c27059dce99f1e8d3c6e8a96e276f47b7e6470f64d7041d4ba1c1d9e3adf9123b256193db61d32d8f6fe6a901dd9acf7f9a73887d0cf08e0cf602cce33f5fc810dea13fbb1e18a555767d213abcd3fd7c149887fbf93cac02338073b297101d1b73dee63983d86b1e6510fbccdb18c45e88bf5013fbfeaa576de67c9fdf29609f0ebba6ce9d18b6f2d6c4308c6215a3d869074b3f7c1bfa014d9961a60e8abc314ab13232d94894813b40558a6f60bac6dadbcf2cff7eb4f6406fe1780b356def4aaded1c2d126141bc96659a963d517dd243dc72a795ba67350832ab35cbaa740fc889069f68f5b34dab9fd1da5d295b966173238e1b639aa6a27ca06e7fab2817a7ad88b26939750bbaa7362ccca79efd25e3431f27a394f60edaa53c3ab90da6e63198ba55ced2e7b1e3045a6586629847867a67784786d5b5abae5d8f0dcbbebb8a79dbad35dda230dd52a5f8867efd2cbbe8cbd86035201de407e41dfbf45bcc7302e7dc20e0456774548b3a751c10c60246ad2bede8f73418843a901d0e82dd0ad86b0ff3aa1798afaa52ffb2bd9156da364e92b9f483d0d73c5ee2a688b2aac926d53e97a27dd65e0c49e4bffc9e35bc722fa2b6a8546d58743de910d100000020004315000020100c884302a1503420c8b2de1b14000e7398486654170aa491280762140541c6186000200018628c31c814155501adb64ad121e68267de05dc66414b0192b2c99904d78b62811c63441cefdd086fa45d23c4ea2dfddcce1af0e3e2b9ddea3d2e65bba93f07f1c59389cdc74e88304acf3892d9bd7ed743c5fea13601808dedfdb5ee3a724f371604e9c3c41cdd767795a0debb90827bb90a030e1cc1dfd6227666abe0f2476168b85d92c8105e546b2f625141bc561002aaaf419ad79bce52906ea36db067f465719d7696e225044a49a1944f2cdfe99b65d335ff143e31df13fd157505f6c8d55161dfe7a963941dcf6f1784367056b8ac3af7f5e79d56a67d2f31b99adab1b456bcbb4c903d55af6a1b08d975cc1839f970c4cb19b8540775c70c497c8614df17d3c1c6d92d3c4d6a393e768969844f72dd9378672fe1767d6bacf8ad3187b109d62936792a4714f90f447c46d1e2d714ab200cd582025ecea6c41c44b72991bca4827d5eec13d91c86d14333279be7f2495e5cfe611bd1395a911d89829d4138382b157cd759061644b49a4e62f79a67d563ed009d4439372611ab04b89027da8ae8fc1ff9e26894452a0dbbe52e816fa154a9015b680808e3231f1967445fa0b6cade0e21f5af7a2a63c6f04da34723774ec0661b00eae40fa42b09e00adc0c738033ff5aa9da41b66d1628c3473c368cb861967c284e6ed6536b5c83e56f0afa8ef4f7cddc1a78472bb7cafdc0cd1ea4be39889d426dfec678ad6e36fe4714fb0764e72713109a3682a42799ba8702b186ad25858f05f5a92721cae4265b49c34890713baeea52c19ed0afc09751e5e6ef9a776299d9a453d27c28b6d2355b92920b120a556c08a7573e95b04b50e1768a299818d10d1b0c6c9094a98d6413960a1f7d66434bbaebd38f3365d2a4e280a540453a1f4223920964ead75e64f80f9c31489363b51bec9705cc492215a5821e42ff28aa40794a95ec20868a655ee4de7e1ef6aa196f3308396955d43125fe9c24ee23ccea8dc5fb48a9b02aa67ae73fc284c2609569dd126f259e793a6f130c229054df76fe23a5da284618ad2a2dff2317080f55553d41afaeaa8f31e88530de31d809fa84afaa4060733b7d1bbf0812ed7d9a4f721a0b43615996bf1a0bcc6c2c9be85ea43187100ad1db7a5cd23cf6d3b7237ea15d8920f8b6e0e4e44545daeab9aaa6a6ed7c4376879ae63d2a103dd7c5635ee02e00a1ba53d33c3261721a8cbb66166c7dabed3e7250b2a2a6ef6d24b56610f6ce4092ec34e08ea0665aa101b9c74981c65fd001986baac1f9dbe5571fee8f6c82a53d14e384038a60c7307d62d8b99de4e9fd119b6f92533eb4f10b70844a04b294dccdb7e86271bc4248c5c9bdc46104c2ad0a53bc49089f8ed65274b951adbe23bca97a17d3c55b2a3bfe96cea8ff886e2bdee6f48d59ac02cb337148f8447e94a314117c400081ef43b57446fd8ef046e1073101741cf7fbaa0f1a426cf4d4f6d3ce32478e9123d9a85d65b97488fb2b10ff4fb208463a19fef524dc6d95a7f517e1247a350b3c63ca17cc9225685af1777215bb009538521557088e156155fde15749a2fb1fda51ca913828e380c705dd90b1e1dfc973a3131b1fb72a9273e09dd2385222a2e495d4d3a53572a27eaa1238cd2ff51cac5ffcc2c02dee07d88becb4ad30ba7c4c04939deefa2503d75407a767ec217e38393a0d2ecf49581f5c84d31163c62fd866c581093f60b2fae4815d615ccc74ee1cab7492e25400f5556ac244f267636c9c4c5a21172f42a8d6d8eec256c4133059d5c53e682798c6086212a1c7d55774db521a0de1cbf3f0492386efe7d1829b3be6d50b1989f68af2264c77d78fb6a38d6a9c27006900141c17f7879b60a74e64ee56fdce02cd8d5c25722d2792c9aa1029170c2cc372bced2357f48696905c5b53955c7a659029067ae3531fc7d7743cfc82d23c48c4f99892ea7d184ebd733a70c2ddc33752b2931059f67e41a0075b4a3d17bd2ff0d11279a121c0060dfc30b1a449f612e33d5811f7c63a03f81b633dad03f9c8c43144ba623cf0f60698c9ffc860781e4b6f04f7cdb33ef6831aa06f4f6824798609e339957358a4ed42f6d777928c205fa88959fe9dec7f8532db336203713f4f21d6f6122f9eb016717b46bb9d8860ae03f2d212f52006a300f31944876959f48a5ee16d91baab620d705407c31ceb3a6b42f00c255d2f3e828625d3895b49675f695e8b66fb98b5d05afd4ad7ffb9888231160f42447bf7eff30819e938f6a52fb9c04363bf97f4c5414a13b208bacdc17ead0456093b7fb2369a244f849654e9cfc340c471993d1e3ab3f4915eb311a22d0cece2fa919be8a2597a4427954bb9076a0ae69b0469c6f4ba1c2e318db7fe076d243429592c90a360e2dc889d999d7816b9a63b122e48508aa84dddbc4d8426aeeca2bee81e187d8e2ec0b9b82e9a2c9180968426a6bfdc06cee6d17abac1dde03a9d6af0e0874d72e753e993263b2599500d08d944ab5564051a10a0e536a7a935297c985d2d09317920b5ea574b1c6c8bec7e6d7fdb98a68581de0e38630036c1409bae8df108a9707885b5cf0841d69cd09abf9996b5e475633d494e1796c700dcbd74d64ce9220c66c32b3318a4b1d38094d572a390f65320c24d4888c4645a8f34dc7b6a50fee352779e8d90e9d5cdac20e0515835cb03a819cd61724debd0383ec328abe6512ca6ca1d684b5b019cce4d17ce46e18a5a67051498bf3c42745579427c8cbd19fca8535393bf3c0c30d98f04bb8a1c99dc07da1bd04d135b11285200767ed4373f87768a660c91e51fdb1a3351b43537b613c1fb9897b4daf87bf6fa10f414709dd2eb20176c1b52428f071c987b563edd726f7db9bee413acee6ab92da64de4e204dcc74dee9719701c95c6e4a7dcfd5af771184a209a9e80673226882b136a71e609ded70c7293ad46c8ff9c02da7c12cb3a4bc537060ac28867731a823c30cb62de804a186026e937c80e8d8880ba0be97ba24805564deccf2c3189b4708e543a4c873322aff11800904e9f33992cb4e7d1ab04dd12cd9fdbedcad5d25ba2a1880fd567ea77c9c6fb1f2bd2f8e183f6e3661f61095d5e898811624806b71b7404e5dc74b1721e353576697b85e24374b78019f0682b25c779f32b527ad3ab93c88f129b3e91629438eb288db08a33af8d489679378eec838c52b407733003a8d84b998d7aefb39b1c8ff18a370f083f6387460aa09c7450bc0f9ccffad59784491efb640622727de772c5c53b83bfeee59482dfd0fe0fbd8df278a45fe95bbd3494825c2edcab25571d2ff195b756811c65ebd0ee80dd600de274489d0478a5be74fd39a8710e7f8883209e926300270effe1fec05672780d41612633cb6420debb15c6145af01e1cf8c6086f233dff5925dc97cd2a89d2737e74b0da8c0486db67243089c587de1bee42ec1977d1d457f9b75e6d988f6918108c7903495e191c21938a52ca0c9a9206bc47c4eba798be72f9126bea561470f21dcf76cae091812455de57f9ae30636ed4780e78c80b3a0b51ac20e4ff375b4ccc4461e33a8f9757b5442becc0ae8e6b5b44f0baa99036063b7a01449fc12f37561d1b4abffaf89c7c334fdb47ec4c8583da031303907e0c0ebf2822dd5a76606d278a1290fb30e62c38198f6223336d8d446d4a84f0bbd96ea93fc0d692e291744ef4a5abe72ecf1c701ae35ea15f7ce98282df4617edc6792a00342b698b3cdc68cc68811bb8c9834dbe9e0e80d0cd163845b9deb2f766c63b035027ca22d3f1f1dcfadadb8f41baf53035988f851911e8388cdf2e14ecd1836bc77cb2d42ec19e2fb8b618f8c753a78ba803d726d770eaed0d2abec200ae69c04841c15acf60477b213035f72181ab0df77b1950886d7508753c4fdb715f84de16f81a75e871e4c8eef68aa3afcbca306f854f66fea2058670914c556f22e4a605436e3c7711a6f46d5689f0857025c46f40d7dcb1690d86eb0ed6ef3fbe5e0f2e675455277bfe33b09faea9cdbd144a8ecc79184ae29cf48108699f0b4546079e4ae536a8ba24518ebd7590fff3d5acab0ee3fd99e4785c854bbc5fe7da3f5e51385d2e4cc359dc6c2b5c6007cfbf530e4f6badedda96bac0a8dc5e65acc9060fcd1e884af99d102840b2889fc592780161a9fc48c9ec92d1135bebaeab1e128bb0e2f5a2754031f01f99813b925df2c51916e2e5916f54534ad849b34878346003e9e8ccf0862e789ad4622e0f787d25ddaa0d32b567dccc81cebf28d4d01ceb64e80ff753e06a17c926f695e315c8eeb067b0aac0b1c17e279a274126463c1405028fd83ae65490e83d07acb41b2bba5c77791d0e30cac1fce9593115b6c3ab017f630febcbdeb4ab1c8f6d07a11303b00a2588377ca35d5e3249d05b7df5b3a7f4e9480bca93a37c5f3fedb1c13033cc30977e65451a3fe467460782ea48f33c064d1c205bea5ffa8c8062a29a2e099410c688dfa9a8bc4f5a2351bf3bef231a131067799eb8701bc28dc269b4d1ed39974520347759ec502f5f64da015297d3d44a061e3980b1382529b252f07a8a5250cea15aa665fb39567afdb3d572caf7f4dcaf12c9544ae24cfd6e58c1665ac9e7e1c2ad8d443dbc5bb11c29cccaeee8ac42ead27cad770c705b238b0194f77d1224f4ff98a3f5be76679f43e25fa36fac564ba76f7031e90c2e784569c8108926ff075cb8cf2724ae60015922a80725d5ca5e1643a09baad146efb7067e9775a7280d3018a3669f97a2df154d33d91e2ff7915a4a843e9101efc20aaa1a6aea475f8218eb02e890ad1c1cb35d3128ec83d9fc7bd90fe5a986c6357f2f5c8ca05a42dbfa326ab7abd56140040ee4b61880aeb680b262f26d892d77bb8201cb17fd3ea5f8856001f3fbc730d37871d2ce69bb586c81023668967136e0855989f92d9fe7e00fc4115af2a153ff6fc50dda5ef69cb5ca4449242229cdd65bea42e6b98b1fe19b5fd97e2cca219806b17e256a29dd21abf2c5a85aceca816ff5a0c047b9a61ac37eafb0745fed28bddf11e121364a1cb3bbbc25dbde661380e0e1b560fe8ac69bab1dfe152fd34065008520c9b786783b260a71f5cc0c2e2ea9181258ac2ed1a304f87482e43e6bbe10be1f62f503d9bbd6555b413880ac444e5950c55824043303e24b9a14e88e01f039367aa38829dc22721d41e9087c55132be348e63d79760ed90aea7594db9092374ff8bdffc17dfe3f900f918b50be49a3baeca61c67aa5ee82a44e4a4b03eaa10d417c9352f79377dc556e52fdab60fb7b7f6633243665d9cbc2a5241b08105b2cb54003d221bae9b613dc03494c0766d500442ded0e59de875a6c587ee0a74f2aa900d62133981d7054a017527e1f0f2a06c24b0d09d98d9974d8d5509d26f0d3c5afae09ac6de5252536db18b420ccc31649a76401ba124e338af97d71bed34ac4c443d3a945ce163c4a5626061cdccea9b9bc5257d612abdf0c8eee23157458c013cb859286cad6913651d62ac3d81248287f84b32b7467f315b964d1334658a30c4f14179e5026ec2c30e555529436899953c9042b8a196a30443e8928434c31bb0efa6f29c2f8be7108532c9c2b2b46c512afe309045c5c359a7787ef4fdc5a47e10f4a8b7cb995cef769a4287ea4bcc0cbf885d16451964d9a120287346f660b332662cc7b009228c2e8ea9f60038f4fe8609930924b6b08bd84ec56ef9cfc564d605c0cc00e265e7cfe14cae009cb6834f16d93eccdeacdac6e7badadff84e6c80581f20f8e006e0920d64bed46d7fae47a365d89ad71888580282957c19cc55afc347edefecd2522ea26e9562f84e8a0efec7f898c7f05b82743f8330556be75c0a83a32f0a3606e18b3ff9f21b94ee15ae92f9909564b4a664fa72d8ae413223ee34f5d5b3235e659f265839a27af614ffa38a62d4b7908e526cd4e302122709f68f32f74c44a55ba2c2801b66cb199a2515823dcc7436d4ffd033d5e1fa0cf433b2288df9a147dc9467920a29652fcdb29c7d717dc576943ea90ae9b5a393d6b8586d1fc1477b670ff67fd09b5be4022b7abac859474bd8f8f3d572cabb9051ca547247b43489d339d63655bc6d135e4da61ebabc149f9e78da150e02c0babf5038f0984c13ac07120f20ee09c6ddd03f0793a6e622558c994e7350bb00e8c2b5289e6e87320ffcfb3a3651291984486dca9ec8c2026bfbcb4d17507c28e255828ff01373c36d96c97cedecc0f218558981e52cc73e11745d12c98d7911f1c725cce10339321080c68a01c3e2e169e025ac61e52c0dd4e40ed7c9ebe735ef9c229d8ea7602e75bb6746c2147b735a8f6dab5a5cce634f36a737250853531be9023fd4d6412b2ea58c16d055735928677d97ef181c51d170a405c87bdbd0303e102542a9d9cc2bcf71b7ad1510d99a6e46652c3b8814a911bd16ed4a7d54e68bf20e3139ada9727a4e9a9c38266f73f25e37616b53baa7d3700fa4b8be61852ea87ac2866267e524a5f6ee3bb7850cf10c827bafc0e323f1eb2172333df3fac7db189cf11534610db4d6878f9488975c1f807ca7f89490b55688ee625de50dd8f723baa37d137d2cb7308955aef02a312aab1c241566c843bf93971b4a0c204b0368881ca0f66b5b9315e03b1c21b1b9099cc267dbae4c880810c1b6b327dcf250596c7ee5b245b8f5413cc7ec90a515690fb5ed3d481a4ae6f921227349940c5eab5055d3ee976c2df0f28f139d11f79e009ac4356c279cf2cea91f97cb5259350bf1d01e415490060ea217f56038b5eb9720beac1f0a1580333275cc8321a48f3f56cf51a4cde698c6ee246ea9720e33741ce4896eea7e1064be8e5f1af395463b9f5f6c897e46a50beffc65d9de65f9a2089e92ab7563fe32447a76dfdc327447f73c7768904d29ea15a8fb875b887ea37cd48faedccec84b239330201baba091952963db90c6b647284ff145022c78827f368bcfa805afcbd21dad9bb5038dd18a525d890d66dadc241f6f5f9db575cb72d7aadf9226ab13f21ebb5db2531b4ecd5c5128f533a23b6a0f316bcb43b1c1c9cc7f9942b4ca940591cb9e30593dba7c433808c4f8be55c8ae40d9d65665e5e62aad402a16067347e61199a6ea79cc66469f814d222d5ff2bb7c9b8c57abe74cfc6b28ec2ff16e5f25f651950b8030be98a3471a2526937a7861824678cf2ce12598826f90418662e0bc08f16b98634d494152d84ac034164541dbe4fb9cadbe4fee6b7cc78068379dc47ea9c254c405103b6043ec3fead90926710f3308ff84f1136f67c325046fb54929860fef5f78814810def2b736ecf4905408dfa1edd3b5de549bf3f1a4386ed588914572373e39f97624c928c7d70ce2163b877e832e42e37d95662462f1a151f92456c6b1376575d94a073e27e88926e56164c9e080932201e22870aec4f0c82d17db623ebae21e5737c31a6b9d2e8f7100f88439071749e7fe15ae9019e9ae42a0f1fde6566a86c70c401fa9ff88bc6c56ce0d1291dd59ca6af157694989109ab1135f55a0bf4a48848a84f530fd807566601257b5c69e65a6a604c1629fd592047719a9ad3a62a03329ed2cc44008eded2255f5788fe8b5aaee082198d2b9a1adeabb68c2653b8f97e223ff0504209cfcc68b282f391956f3119447462097f8f0ba3f829baa8a2e753b3998e04b19eb69768d834492eb6ab304eebc55f81fbbcb106dc30f6c73a519118cc5c727402f623799cddace960f82405c571733987fd652151a3e2dc672a6c82c8cf00fb5b90d120ea5bc07bf90052ded24bc664dc2ab48b011b8342029f269b27c25ad618cacd1bedbb6b08d15389380628fcca383855077c9f05240b84a5fe97bb1953970691b0e8d2390119a1fb73ea4e2a7ee2fc69a47de3be80ed10cd7bfdbdb14595a4812c1b73cb5d5a5ba1c22541ff01ddcc21637b4c16039b5ded8fc5898f0fb2a61f8d2f8d4e7997da2c1a87d294411c4841c895063d1b18d2bc9b0dc7622c8eb38e4b6eaf2ef320c2212517cb0355b225730078d29efd51fa19501929e8404d46243906e2e2130820ee00bd1d849608dbca4c3a9e8af6c44e94aa48cf5654545e9ad7dec1694481feb72680fdbdbf95c7b5ada979c17bafb3627669d6b9fd619aabf60454228a10a99049276403b5ef266d8eb8c6d72d4ec508fa46480706267d42db00390a997cb11ce81dbfc0f933c6269fce244e40d07b56c8f0044ec12f8a0b04f841f5bd44e0d78ca9ee0f15fbfe1f46c4afc03960b83c37d2f39cb0d72e32b1f8f4bf484e0860a68f0d8b3c41ddf909ac4d5b3d7c4efc8b43203dcf66091b18d51d5571c1cc96ad2d143b0af68bfab3e5d4ee37684807983a730fc53308f6defe48bb53c323e088b6577647305e24fef966301e90a8069f6baaa0b8f8dfc62ca6e549205fa498f73f5a072a63fb44b9a65c2c9671d4e2449d69e6152e8a55413f93f1d45fbe3807240fa2aeb6f1dd3b012952a8cdea136be7f017723423763dd2e089475f1cc07836e2257cfe8d6d87ecb14bd347803ad37dc04bd4b2373e530869e3987d28e0b90da2b6e8d11e6cd13e2624a0435dc5918eed3963801269036d9865a6fcf642e7879d00c41e3acd8c1eb2aec691f6f09175953d90e4ea56c95e12cf98f2223f98da000b884322cb57388bde3d7d37f2fbdb1546cc2a629a8fb19cba1c6e8096f901986ef2c866c542a7d55a36a6bc989714cebf4e431d9d4e22ff30446d7fbc0309b5031b1c02f9d325d223f547373c4ca349e14e85d4a1b3088d1c495b2f512eb8cd15c2b4ea598736625782d600b2ae7656bd9342e3daa030e11f6b920538960f0433605e6d4c429c58e5b5ed7bfb49d1eeeb626c5adb2a3bd190add64b6f9dc3ae55e2967fb870b36e23b7c15a9ef35868843a7040a0d0fe2c8c274b532400074cd3e7589ca6efe4e1090bb5e41edef21799337a627531afbcdf552abeac42877bbb8dc9d4676f5168d0bfaad782f8cfd708ac2ead7ad138cb686279f1fdf58c2adee4230e4922ff48ab7bc062f5c6918f6a5c6de614613e9845d2f0077fa24f9d1216161a06adcaff4a07ec9fe0bf3a2c5fedf35b591b95d4d828f73c0e7f59cb747b99dd3433e5e7ae32e0ade2052abe4e2f48e1b05c76d2499cfcef01427b00d67698b8c733dc2d75cd9d3409a95111c306b748692c9fc74350d6799be551adaa09f1ad6dcda31f5e460f67e06d768e40982e7c212b64c78ce98542022fd9d591bd1baf2af3a3509b3535fe31ec1534b6aed8d163f98515298ab2701dc47f1f8e09304514bca92271f6bc8602f2344424b6b410bb69a5d25195bb6d069b038e72e7dffe79f1a0291759d5af51869fbba2e0cb6557f1cfae22d5c38aed8f33da45e3d6bcd4fcd23789dd5f9f932c35b64723ef8a8190638c965735fcb400bbad5954a73a8c234c889bb84260ab13d138fc0263bedbbc479fc2d424ead3a735ec5b0801198ddb80f317dfbe84185ef5f797d5d72b4f71128e641cab789ee105cfb0926a4e1a3f9baaf81ef7204ac1ab00b46fbc9842e6bdd997b8a37df849ed4f629028c36dab6c4a0e27780273135f619abf468d8ea3a25814a8018c095d7dfc0a0172efb7c644cbbb14db5f8333d0a7bbd70a52ad448f0384cd77a3f94c31ec258a0ce37115eeaa6b62fed5c8123453809a1c9fc806db38a1541d04aecbd593c6b1e741868764c5a2be5aa9cced303dc9beeb68e7fc96a24806f4d2f280266d6441fc0224b8013194bd13672fc08ace2cb7e9d8980e600b48298cd5a82536396eeb9763cedf26a5ed9196bd43d8256c3b3137ce8115dc16aac3b3da26bc2ab9bda444d3e8dca5723d26fe0cfff259dfce3ed4e52f89d622c00da53bec616d0ebab2a57679a4a8b308dbaa51107220787df9fc594871e687d0bb91b84a09f0f852e130c5298ceeab1d2296b741008acc500d2860ce0915269fd47af8f2426765090f88f0aa002935b708a26a24d69c34cd679875cf46442ae65fb0b6b7e0c85f7784c7bb4f5a60ab94e4a36b8ec67b913e3d663357bc76370accd64011443fa9075a9ca02e057292f0212b3ca46c4623f62b16dae1310cca836227de1f3f0ba40ebb4eb0a4ab6602343222920b151e9c4011810a15a07891df8552bf72e6f46af2dfd45d79c959d1c436dc6b9462fb146636125915027582c380ebf73ff2b8b15c4b21f5b99c20f88ddb81a26f132129d80aa81fc55bf1f29a6f0e4e5c65bf4a1d4a0fa451f7ef43b950a357809a10c1ed1501fb92e447ab44f63d4280ad6a45825d233d36c5c670900d0800ae3e0a84454517d6bc1f0b675e01689ffc156ec75ddfda8eb165d41ec411210803abe492e5762f10b9a44d2105d304dbab22281535e5ff570c6d6c398506803328abbc52fbf5767e510813d60c0bd1d8880f6a88b0fe38c8435d6314374378d2ea937b345e32dec1a0cfb0c64638ff8ec2e832bc99eadfc949ec1a97b43bb51da987e301e73ffda8b2ecfb60ff0470255263069a9afefd7c75e269c8d53f0dd46d6ccbb46069ba65888e6badaac8978a31f6724276962195df087fc6bc8469a4ae1790419e2309b486b830f7fe6c287e366db1c398976a79c60c23b7c94ed66e92f54bb61a1a0ebf6a041d011c6cab0994fd80df84d6118e080f072715ee03402bdc9398f078c494144629728edfbc61e26d6c7beea2568c0fccba7712839197799683e359db3710b91ed5f2cbc9e562fc4e1a2d9bf82e69c065b3b29ac139f03ad191fabdb544755e606c59807b6ce4ad4051decf223d840e4f63b7d0a1a32a79de8f01280c02a9217855d88b7bfdcb0f8416432b3539da890547adf85fc5cd367d9db1189e6c79a1bddb73b701b47c89d971c8749d7ddfc708959b6991af53cf421c9d88a5ff1a8c041cc7e94b926f561a859dd417c8d7ce169ccd495447322793499b97668088d899696344ad964cd94c471f80f97ea5642249afbae784d8003a07ee8f588253271f1eed3bd520722eb4fa2eea55059ea65e34572c60fa52489a4e31c029a0f034a1d449eb87d3284abd77858bf7910ea8d0cc0b7827a976b3908cda0a84d632c7ee4a5397c9856ee019f8f93fc0dbf3f374b2434789796b181d99859d3e78045f0898bbabeac292c9a545a931df70e40d3cc108ae2ea732bde581ec67f91cd860cf94218ed63941b1bbbdc4fd443a5b62dee7ebbf1f00a35d1737488a096ca649d118a1b4d3b9498adf1a3d0a72afaa62821639eb7643eccb5934e8354cde6328608204703abd6c8d5c2d26e460381bfacfdea6ca2abd188b4f1a98a5e8431f228e4e82658cb6f2909c49ae72832e8ebd09c1c2a0a588bf490349614ba270fdb94388ce49c8ccca1e2b500804140f54409267342c105bea3c6c787eead27322e8ca09703b7413cdcf6296ffb438c6ae1a6c4620cefe2dd0b16dd6d017ddce8457134e2f89d58c06608bbe299be9dd91f77c028813b6cd53f6debf885c5d45685a42d035744bf77cb128c4b0fb85749000dd0ca4671b26a9648fd3c8fbfafc1bfab8be9ebaee200227bc4810dd6aacd9fb6609ca331e54b5303b58838f39784477c80e04aeb1a1fd63e7fa6568a434d675854cfc190e922ff5583d0e4cf56d8a50700a5b1f67300b8f8fef2acf72005a950f12153f194cbaaea80d5385e9236b0fc53260aa582e69b4c3f9f5b0e6a47e28e780b556eb6774b1f75697f0c45228a60bd608a3285395b9f5c9770e8a5c11c8afbf79196a854a92a0f3e007ca8bf14964495ec65eebdfe97c592c509f57fab9624a345ee8168e76a430992fc7925a4275aac61493bf12f7ced7cd3a14aa7c8dc29266086ad7aa7ab69713dd9fa418fd0e5a43525fb1f68ee103df4f52a6d29277d51feeeea86fa830366bf0b8c6fa5571d881a7e82d4b7f487a654152f6d6029d504dcd60514232d84fc790a245899364d944207c8cfad8b9481c41508e11432bbb4052abc4912e8c4fa20d487d1964bec0be49224d60508e5afc2ac903e6389431276c6cf4656be7cd5b53049747e5bfa2b47d50cf5b4756c87dc9af30459dab09fa931fc9c6362339ad3c729ae13189ad538c8097f53267fa52eea1cd7e6b8dc4427c36849da699955b4abd18d3b10ec3623922d495487fd38e540871a69719a77935618f66795442194fede38075d3600e6df797f38ff491e753bd31af6c0f3cacea884c0b62d2e308534f9baa53cf4f3e5230a1dc6ab00acf66bdc6a44760ee75fee62a1767184c852534d5f02e11faca1429800d2da226c42b82e5fac89218067bee9365942ca8f9693285aaa98290a7ccd55451b4b16d0fc17a9f6376cacda42282939115732d20dfdb177005c20e7852a4b161d6e606ae2f88288556c41dd19c2656b546a0e1af15f5368f63290e3f7530684c80f0a0d5cca8c20d0c64a6723f8375283355aecd0230444f6f2a3a5b156c0707b2635d948ffe2859410fcb05738007aa0e41cd060ff20c26e70688999e52c7b1dba716ccce36dea3d70b3e32e43a5cf047de3b057cdc1870e24f15294408c659de16cbd937e9fd7e20de08df9f7b9efa7f44dd9472a8b6a1fb9a3ad6e63eb28fa6d7a82af61245a5d9cc21d594eb670bc70a733c7edf70a37de7d861b0943417285ad6b0f7c87899235a892bcf25a37fbc12012fe0d24d2c019271832ab12589d0d0de81914ef9d89d32619862bd7cbc405bd0881e34267976cb18c62d7f6fe6a72609ee8c08d197f801e1b472b1b870ca0515125e4bc0247be43bb959925b41055db1eaa204d6529dcb4368c5d004ccf7a58a350d93a81a91b4f866489865e0e490cef54ffbecafd5e6ed8d3bcacc32a2c7d08c9bc9f98ce0ebc6b93518c87e66046b0290723c5047bc773cd7751259e35ece5c880b04f85d4ce873736e648efe11bc1b823a07a0ff8c6cbf15387b4dfa0fd0cd4568450cf468d17d01dd01b417d705b3ceb5d86f4809e7e944382e532d99288ebe023480bdc17ba8673146075ff3031ec93ee9516c2a5800de32ec7604bd311ff959320b7dd88de83bc20d850d3425eda31286533a02cd628228c8e90348bf749ec40b5d1716c7e6d63e3a0be77621d86bc3b3a3d3ac1620065ef4e25130215a49ea8312c4681a2c548d8d9bd093366d3c923ceb86320b56ef84d29fb1691ea673a311a883e16bab6cbc5d5005e5311fff76d61b68bb4a32bddd3f9fba7c509e04fba8aee29d02ba40ffbd2c4266443877cba9dc18c1a6324baca6a6b54cc41b42d11647d8917a260fdb911d5872dab819f72ae6f3576c00e3169ba0b7a2dd06765bb67df0ada8a1eb412527444d27d3f13f384249ed547b85a70d8e6f00196d3e19b44dce1f5b152463de577952cb1238023a973ea392ed895683a8ff364ca5ac37c06fe436ec91c7e91363dc4b0fa194012ccf166557804f9c12774e1dcb6907d2f262a4b0dbacb21e3d984bb725b3e48298103c97ead4dc958e5925bef578d69df4cc37b97869977947d3f49ba071cacc65159dc11837e50daf12e5969b9a52ea613769a65137ab11bc0d15eccc7d7eb98c71173f5cd548f06eb0e8507ae04d7993b34407d389b0a046f24e192c012306b9ab5b4c9497985185430ba511aada683db869352a37e93948b2a7d75a2bc72588d54f13ec7b886a558258208e4005e7a0317a721a57fd6d2c4ac6bae4f1ecb93fd1dfd72debb8f7da4b986d26aa055d2d9e9a1b15c89c62097166f2cca5b3a133abcdd152d69d1f13ca0b4708c264c5d7a298aa5cce299e281ec9c95755b33a1c3d7a046d78c7eaa14df33458b642a6636cdfc0f925561f68c1cc7e868d2d31b1e5d318e419e28d73ec1a206cd694ce0cd4637956caeb778630bee52691252958def97a88f4c3aad9b29133b3502c73de0622b8cfd9e6539decdb3f356040796bd8c9de8ce0360969877b531636694a48b063b8f350a503e60104c598f2d42d2b6ffefed4f83e4086a7fa7690b095f867784e99130efc98a39f8cd322714603e072f41cc2b49570722375e631a8691cb32fac31c84d7a81b490326246e5f6ee53ff2cd0cc62ccee594191a781e3d5336d7e62414c70fdce8119c04507bc741436c56eed8131be3bf04142815e29f05287bf5d88dd0c1ff041428adf0500f7145225d5811a6a8be261118c32af7549e53f4b10727da65702dc41aef0918cbc8d75e20ce7e46c2fd7e7145e2efba17a3fd5e865964119a2785102c1a4fba30e0cb8ba128ef9c7a3c105fac94e51d1a8c47c90c093a298eec3b4afea3144832ea58b6392476b2121a8ffa50ca8d8bb0670db8b8bf39f59d71c67b6c1908f997201f05d1dd5320ef3fa889c07809a87005eacd497a6beb9e40754d45411cece865cba7ce6cab1d0f5c2bcc6dd14e7cc8d0fbcda8f446893948924e8e4ada01d87f81fe586edeab3fc61c06a3fe889ed179c01d18d5d18d2ca2ebf4de4266f1487235dcbec04c382e67b7b96ef263cbcd0f5b8f5eee165a5e307294f35ca0b6a470ecb238880379efcd3e57479b64b06c7436450b6dd38353709ed7addc9e61dca4a69349350ec90158c7056d52fdcf2165e2cd8ea06c8159dc20fb1aab5358f186f8496864aa2fb7f005b0e68e5ea7d58ad596be96ddb6ffa8d03e968b2c599ff49bff40ffe4a100dab2e0a9af88c8853470c0b0be4eb3e44d03decaf0c2b3e77f3586658099743074546596ddaa0f76fda9c4576f061cfcaba691d20d34551d89838c9f287169bdf7a4bf6bab4d845f295b1759ddf06cb72e0349af25df4e61f83407bf273295f84e712fdcfad67d4700ee6cfba8da7c724e0280c0e8b0bd5e9d94ea5ebe3e17a537ba9c0e50d67bb3fb4e4c16f50ea8b649a343cbe72b77dbd59ec588bf915790250202dd10f3b3f5a50972bfce46145a844fce93e7fc3a39bb8f5f264b404e0ce551ca7db9000ac3d471939e1d78d29affeb6fccac41e45d7d96559b1735cae8cf7c7e32787ac64f1ee0e073c0db24b015ab3b2a040c13fb4192420401a03bd87f85ab8ccbf80c0f825328c1db39c105b8d2c7ddbefa6b69cd34d5e75f828f543c76043dab30ea62387e6e257fb20e6dcc2e0c8590fd3bc6422653a582abae4dd1377c1cd6bf4a2fbf9833b99e91e1780bda61e32a47450ddf17b06d347aff92d1002e27f177b97751520827491b639036dbb483a0260741e109786e48b8c1938126b895de91ee94f073103aac2a3a58a092880cb739c1c63990bbb160442a3ea3c62822c92e1bbcf5ca26b114a958abc8eb6545beb3e93e13811d69f52c6a3098a336a024881eda852369d6f069c73edb6142c63e1d67607007b6d37ba494603064488c2daea01d2b542de8252cc39514caad8a98241538c42d959de569c1d2043992ca71ed59de90b91da4276a68a9517336254b041d202d4f04a74d3667d95d91e101d0cacdd3355fe86abbe8f112a05b31216225b114f63ebc9204d051d2d54657c80e661124a008d546542d2876804db8da86114099b19ad230811972a196bbc76e1bff4075832ac084ce91367c1114663bdd207c10dcd7173d7a546cb41df09517639272d6252f3816b5df0fca75b5c4f20c91f11d27b70b9d6685b97b46dea073b67f373cef11aee84a07dfcfa75c162efce3b33b576f50e490717440fc336493572651ed9e11b947e382ba64f94f246d31b51f82b02feaa8bc90c19b6e19edf9263c972dca1a4cce2958cc9eb47ac4e5b1d3955b8509952b50c7206e1c58b711a3b1b681f110d3e6d5afe66c8b57ec6d4bdb581cb1e2d6a07081b6d004bc7562e5ae4ebd8b034407c6818a6f6dccf49d99c77e7b2e19908c76bcf3ec12b3376af1385165842115ca7d4162644fc0db3354e80124b5c291206763fa8c50a3a19a0ff051e0d46afdc5e8ce608ab25032d760a1582320769b439a3f958fa294c79177a4f57c85992e6f3436e23cb9017e935732528fa7661829afa83372d51a7c63e1e946cf4c9e62260743436ea102941ae82cba04a9ea739b550998cc385506db268a9455c911e0a1099f755b167af95ca0b468a8913e7f6bd90809aa429c7d68c7104577883f1c22743ef09ec7395f5b533a8095be91b7c9ab6884769131081dfbf48ef8bbc4076e824f3ec51b460b1911a8cf3eb1dbf14b696738203d5ce2bba17f45fe1b4f14d02061486500a292c46becc7a688168df040c9ab1ee8fc6d4030c3e6f06e851cc54c881c14a82fea782b1315b22c7e3f0a1da2e5db0942dd642a7c7c9940b4f47485651d9a6fbc6cb86ed4f5f1d8d99ff922828c2ea50270ee3ea4c864cecdda00a894bdebdcce2c3901ed0dc601830aa276ea90198204146accfa749a74ac40d5b82a7b648d8c36d9abfa31146cdb284a60288bfcaababadf938f67b1bb223a1bfa81f0fbcbebd24daf4ba41751fdb6e4265c5a50b07ce69c4f2f3d96c35863d4445e188acf83e5cf76bc841596f86ae16f47e8f8cb1f57579c38b976e7a7386e8e6850cf778585e553a3945e61e54050923ad7eea7639ef52f26ce0d6766887c1f62202a1b850ca3c3b44a77cb04563b30ba57dbaf2e29ff450ebf5d60f83379c5af0e7e4ac01de828db26c4c2f5c11d7591706c756f2b6d1098b852de236e555494090d706fc11a3f4f9a2d115702c72bf211b3cbd8f052044e28f4f2f71c27711916715ad96cf035d1ed588efd2d17b20b02ced01a87272c05cfc99b9fdae190b3b92357cd5e4051d5b2bec459428e4cb0ede41e848a0a31aa809208bb531e032aa797e4824596da07f99972ff6d6c1b72c911655b01530221bb10c2b953e7a1c9bc808e751fafb34db23cb349ca12bb9f2833ab1ab5b1a51c2da99cf600917e6264060e10d2db35099904f932622ed48360ac334c7788c3528e668b152e9262d802cacf413df119443727ec3effea4468662fa6c6994d02159159f0220b73496906732ec3c4ca4c9bac873dc90c479ace8f52b71ccb7e549494666658251ccf8556c7adfcfdb9655ee704514a262c1076cd70929dce25c836573b069cc26986c3c855824339d761e4357d482f5640c956a733fe214b6c0357bc247fd8e9246eb9a256a20d5a10bf7b0deab4b241a92618c793f688a1f36b0c2160ea2b2d41f66678881af4dd91058ef52f662ad0a49d75da4073814c7c601c230ea59d524fb8f911e0a6546af7d6c7288c3da58aeac4e1abfb894811e212a2f9f541864d249c4332429e0c0667e463279474f277789105b5ba03273f0f319c7185205b18b4f073144a1ed081c9162ef18d71c652f74befe7313d130941952cf4312338f095163075c91785af6c8229f2c609c6909e6bbf117892f9794b67514f2c8254fdfa5786d5bf042b9922ce2ede45dfb6bcc6e440e2aeed12788c349eaadbd22cefc184c663b1b99ede3681cc52ae0d81cb51eaa92636f966ccca8c7177fb0a21faf331ec03e29eb4c3edcdd5bc2e7db0f29f2972668872cddeb0ddc7983c7f851cb6636bc52acf62d283689e1e66284e079ee6d3604f18f8125ff92b0dad007677a43ae102dc6c21b4cc31599e26d03c5b9ca1f1596a631cc2d92c13d014259da4ad2e027bdd2cf25b72dd0dab9e41995cef1085c2e8e1846f3154a4943ce33f92ba6d1a07ce238606c1c4d415fa78a046d7e0df504df6fd099d112f6c0c1f19b231d8c628f450668f1e31a7f2c61646b6c63c3fdc39cd49cd21853a22d40c66a6e5378e82de2ab0b477d1bf8d50f0081e4bf415caf82e04b895aa342b9e4c0cdec3ebefca5da545faa162628888333b7e32c0bdde0c1343f62ec2f9a2fc23a456eea48de8cb3a9a2a4085821f2c7f749c27d2144afc426878d64829245fc75edaefaa2dd0ffb94809272fcb776b2568c433069df6a5c64d440f06516539e2630cd50282cfbd9151695da13950349541d22b29fbf936778ca390a27727165319701ea0b8b8418f0b4184b4725cd3eedafeaea12984cca61a44b77dde4195dfc8a2b3a9ab1133bc251204e8e5a24da39f82f2c64ec3ba41a7e5ec7bf828440be64073bfd17448438419f0b6399282f2a2d4f335f9ed7d9f748b379c2faf344abcbd42e3a08c648a4205fdb037ea9dc48708675685c539e9c2b48b9dbd38ddb1d9033fc41311c35b9ade22a86dfb93415cada5646b6c67c3aa017ab5942c744be4a33edc089d7bc163c224b0452f3b7dd495a10eb1d480b7428d6dbdca88a504d368f6125ac15350d6440b60f3a0a10450858ca80f93b44da4c27a10973cd323ef86199932585250a6a3e3ab408c035814190e76cf93da062b5f087c8bfc22fb91edddf66ead5450e2ef9130068d78f485c86be9802553e8e34a70ad2545eca03885633881b85507c65bca2ab747b2992bd03624b6a5933bde7fab0482b16282171c76f6fd013b2c3daa3e7d5174bf8726d2c3f402cae5f240f5be729d8b024a95fb49ae6245f6f02dd49fa511b5de45ea6b4f0d8ff5d402193912b3f96999b4a7fcbed572147e0b02f1d3a78f1cfdd6300f93b9c4b18a64efc1b649cdc0cf873692ab249306c87e27d39c136c828b94163fbed501f392989ddd99c817503616ba9c453b3b8e4326516407572dece4e4c04dbcfe9bd76face522671f1318415ad5cd38fc7c1b1972199ab7e90fdd6bab8d63d3613af408f6acc76b054415c06050726e684ada91064409aa081d145761ec27d891df81e195b0e08e8640b68e126acc23247508b79e7e9cadc730a3f451abd483f01cb6e938758216c0f6b1d6e7b67d8a99acd8c1ef1dab92d2d14c977ecec03b872a74f7632a5e1e318749d923b9f8ddf0c0ecee5b9f0b1774b7b81e91b5fb1d59fcc13c0f16993cdb78a2457e657edd9541476670d447538be79fefe945f0fedfaf24b79b030ebb1a16536bd66b87b23a3f4d763b8291db1cdbe4ba366ccaeeb324d91b78a2f533bed512a63ce35b5b9320b643214a6f2c69c45535c7fd1a3bd0b3495a59e1ae8b2f85bf3a39f3efac8e3503fe01ace8c5fd565ff5cf207620c2a1899148d9ed0816bcdbb2ab8574fd54c84d97cd4442c0ee14e3dffa83e65df4b17607ef01dddcbcac52c88363913dcc2efa57b03a6637ec44a8c1e252214e728d915c0a7184b632a3e4f1a92b520c34488a45b57a27c2e98c991743e0fd8f916ca874364abaee5744c61f4024966ccc69482af7d817c4cdd00369285a7debf869fe646fd0903753b1440995a3bab952f91393f1401d6392fc643e213146ba6cc79940cdbdb35310d4d85382a2c1205e528bb24263e850170540fc1d071c4223b441f1eb8d783220681329d1c25b35480311bfad007d8e9b85425956c67b19e2bb4e62b0f6ec495595b37a96aa053d0b7dc54a2ae2223e1227e8fc3a16229e4f9a904103e2376898c56a6f7a032fb17cce48c298faaf103b433e7edb7f4222a671a47800d25d0fe2f39f7db4aa0119b7166a9cbcf1abe35869c52f801b803a759266018ae3c349ca05756310a64203f48905146a81f8a3d9cd0091a8fa7cf378525e350aef1ee3876289b166c10187b9126d8af1ce95b482fc95d47b29b11bf70efaebc56ae3378d2f9b3160907c76f80ed08d5ae32628efbe6f216cab582a0f693e8bbed4236c06aea5d886c3d4f7195033546dfc22d731aa95b038fdcedc79f827b4567e0de2d7f86c79e4fd0d491165bef6b031f83e2078847b52d21fa6fa6975f37cd0e50f3e25e893f704b6f06cba4e4846580f8e70590cc30660c596bd291935361fa23f00803277514e5f585709a71b88be0d5a2b051cc41a5135402416e307d5081959e85af76050b453227611f6d9ddd028dad8805a3c286405eb92f010a8654a7c03183c1bee9173a43bafc2b0cd34f7018360fbec1d0bd46f215fff365159de3047f461830b66b6527eea31baa317a4b27b24ab6013d434467cef156bd3416aea227b5386c11a18768f51f45ef9fb511cfb92dc127a24336c6045d3788951c6fb2c2ea14a73206b7c69d03a2991f563a9eec1fae7d42f793b61295862a7028bafee1b9d5546ff60d8350e56ba071b7bec964b30f4e0008ec1849bd088e1cb28b17366a110a6b39796408140386ffb8d4603830dd32cb4117f70da94ddce89ff8cc0fe4ae0b3355fb90b1c620fa6d85c3b8416e8cad051825ba064cf27979bed061b0132ada91b9f19259f83e5f419918b2f05695e690b64343c382988ebc69bffae31fa57d1b713111465030aacea73174d4f0873094cbc96817ef66cd4eb81c1eae442ebe8792b388a68062c039d16071cf244c4f191a07aeb5a30019c2c8d6d40facb5538438d0c749e5dbfe78487138767b40b47f499790075b8a5dff57c70bd67f03dc5f73a18871de36aecfd292bcb0a89b6c0e33ddbe35e6a541904c0b8eea67145f9cdb4fa0a79d7a0ce50d812bf579259679360cff1398fce1dc06c4599a00332959a472a319a46141cd07805c010c58555e054c56ea14b6087e11af74c0f6b99c82e26cf88199b95e03e0cfb2cbb193dd27233fff25e5bbfe64f9863c1118beb13239fdbe3500f77e4e02606e9c7d3191b6cfef270462df39dedf9430cd093d0f85ed3d0f22b457186870c036cdf239b5d177d05d79dd4a761af2ea46b3a50409e56da306422f4b0162347a7e79e9468c192c3ef773fe6412629dd9b6b0ebb48335deeaccf31a17bbc45df14f123bbb6deb3dbf854a3fb0037f6c88f7c3482bf8b4da1b802ff1b8322f64cf455f2d0b10f9ed120f1c93dac20d0838de107eb9bd1318a61f2dfd8936104efbac5f6ffb673562329227240b2ad50f65441ee15ec930dc74b087552f254753f9ecebe2d63bd77ce6ba9a6cababa926796bdfd5652976455dc1da7ad0ff873349ef3dd10a1a5e0b92b3a6014df06d80dfa692cc8407d163b5c0c9a8ace50d1bcf164636ba49b92b7d49931405be577114347cf1c4d85c2609126025ce2080783f01737879249de7aeaad6f33e091d54feb4c45d2830f88efa01fb32f0fcf67dc66ba98b2060acf504d0ea5df09eecc5a501ca7ec9901871d044145cceec8277a8728ea34483fc480f6cca223019c9c7261427a4b418e1d0ac40dfa170603193598cea1359b3291ce8085318a7cb67548aa1f1243db75719da8f17135064b984b9e5fa96ff056f638837e169bc103dc360a284c06d3e68e79a91ee5dc14ca97ba4242d3b7e09ce531fef4582ef2383131ff5803a36ba05e260984eab61be17d5607d49ce5f6db11c50e90df29def9b44e9e48227c5a6c8a1dd37b5cd59da7f40644fbfe795e5712064042e259063b3b834aa169f3cecdbc2c2fe16ed9d588942a664f6d17a9869f6532680f3b09fb420a875c225fff1fa2e26754b84fb4cc1ae54e4101457dce3d4b2c9177c78f5caba7b5498756bd6345b18f2d3b9a9a7e56289a368f4893b362ea98799b4a76a89cf3261cc1909ba5470d3e078872f1b7287a36c986d2113a29a50964d5c80bf87f3ca481cd6748a91c31e94e8ee8cfda615ab9249eff787bc615e014a11e75cae53f9f9573e8604bff5b880ef8499703463db5a71b093adf60981bfbfd00fbaa8c6690d0fc27b2aa75d58570bf3c1fd77912aba09dbff32274e73c575865d5bc73f9f1cdce8066f925ccd31049c777be01dad7452349408566f4c2810c13b95805792513d0236b4ba7e142e5c8c7dc26e0a628396c45861b614c5f8d627587adb6574d276e68b0f25bf0e7f10e439e80db2c8370813b4d2b4a03c6a5817767d5b328d1092ce45033748f570d0ca32b19d25fb6ac12c6f8b484a8e2ea509f4a11b7996c9e6d3abfe2f1d89ce3a2705f2a1adfeef2ec141f1f894bd5d5fb9b605bec011c4753b25c4f2d4c5d35cecd409ca6d290eaa52e416cb0d601918098a9a9dfea46cbe6e4ef61e67094b313f04448a5e0706d49ecccaf23d083dc8f4c8eaaffb8451746ce85851894960e7df687bd24babc959bb71084e93a0b575db7897628675b9139ab6a9c31bddd58c014a860a64103053ed333214a4e8f928459e521ba4bc1f1936e7e2c0ad3a4f35f5545288345ed1072a302aaa4bb422d041ae5518deaf10d869d939ae43d6bde03b25085483e13311288a27ab6e211079d9141ef89664ce6289cb2dc18097b444a5268fc230a81bbf4e01aedd925ce2d1e73a809f5c1bc6a33e91b28059632d1c7feac77df453a38b5357cdffa0d234d2a86ed0fc34d019e7ded9d87cd6dbd537b474d448af3cb74aa45ec1c6bd7c59a7078820f11e8bd9e8e8edeacb24372e4dde9451ae6649bf4abd605cd6730703437a2f36916deb13b8e8d183bb4d7c32da9720e9f1c23850663bda3d8c268471de84d892fbc28e8ee22e3369c196fbda6124cfab2c54e15440c4e27e4429bce9c4297287f8ebe939dea95324eeb981a14897bece61e35701393eb3ab659a3159ecb19e6d09dc0d2a630a58bdbbac1e0c536f2b6e604eea740054e425bf34f8895719a7be3a4117580571087f49088652af6450ec20fd209020693e31fe58b18eacda49b3b245dfb0ae0aeb0d1c0f036de53c8096582b813db096f3df7aa38da5803fe591c14166bee99118e227b2c81149322489a56a696ae3e550e23f88224c8db8ca0f048d246c9507ce33f901b859235a225e26bd0f35a74a6a7d85d95745ff6d45ea5aae51ba42f5fafea5d64f7201f905155e743d561cab3f0dc8d03398852b8e24a1e27558266a7a868de044c72d3d1d064775bc9de806a8eb7d2d735d70e37f34c33e4c1a08828f333130106f69c60f5648d4f4419bd6cccd57188417521dbd1ea4f0ae2257032749fe196667ffecbb3497ed10ad35873c44db037ff18123195fe916afebf28a5fb90d91c91c702b4c4f23e4e9fc6badbf1b678fe76ebc11333a6db4340e9da126dc84c2ca815ebeda2f7ecb7654df3d1958a7778ee2678bf64578ccb93cca228d770494f0d59ec89f1b2800756690429060430e77c0b88fd7c2214c559d44474b39fe269ae6fee2ef6a35d70b219cea7f04bcd11706e2cd1f56fa8ba8d399c0cce55b18a3e995882733ff0c63c5cf184f3a38a91a902b433dd3c2d3a0dc4c50e30d5f3f9bfd7f60519ffeea0ac96d4ab84c8b8f329161f4622656f01f7252006f24ca1f23d8ce243c4d070a30183f5e4f1779703a65a48da90553b6e410738c84db270eb129c82a62c26f812d9628a15f45a8427f6f0c14100e398c488633d2ac86151388697db61992fc4948da136040ecbc0eb76aa7aa07908b72cb2bcb719a54414c3755229bed338306bd4b5491fa29ee3a16525db5c1007033db451d5cf0da302052fbb766de86f3569af6e46ff0945858f9dd52f2a72b2966d7c54ca7131aeab8b67266b94d3871c513d52e3b532b00feac4bc93fc6399237d0ee6d69665b3af154bfa646a3a578b9f98f7d858893507adf1221b073f2e4c50b274ab280e1b26a169886e2bcd4893c15548f11c7cd830505306779061add04b1e5734bc67df84980acd74574cc205543f991f118d7284ccb4c4d9f54d1871a00c6268a48f9b59dd4ddd4bf8f861a3cbbcb5748660a8182c6cb3e1d6bdecb54f56c6933817ba12afd74b8e8ff631203fa294aa2091f40e4914355da6c1f0bac085388d17345766808ae5abfa59218950dd369c6e256870bfb5789f5e1d4a97340f9a962e4937aeeb0defd980e20598bdd68425518b018d37067d1c365bbc247730db31695240b2e2883c58a8edf1d9e37108b7c5f576fa2ac269b26883f541a7dffb25146bbae4fe3900301fcadcb8bc0a00b0fa316ff8a04a6c55209fb127da406f9674009c2e20db614114fc5743383c2122c52f27daa70ead2d5e00ed2a50de4b67d8542b08675fb39539adaee2338e8fe19846d9a18e6d9682122c8a0a622a5b835db000d3d8318a87a76d769d872a8ccf01072f5f71058770d1b1dd5cfc5a5af457e62cd01da88297319668c5a8645c102158c5e7dfad2932711789a44979ad7e7337a69b7dcc29c8b1279b4704172adcadf81ae682647fc684351ae5da0ecf6ee9d900cf8d7d29e7ceda7385b98b2c05f069991061bfb00b1c7dc668886954bffb0ec5a198982e4ec77869fc79da7d95b92cd901d8c36f6771a64ed81afc8fd0c0d8d5f79d4f919ecb4506badedaf8fda5e3a9de7f8dea577def88c1e0f1b0e14e08a47ff85c2a928f95663d6e2f5d1e9dcff9f001c1306db2243ab0c34ceb26432c877597602bb2e8bf463d1f9afa8e39de67b3b43f54e80bae59896dfc7569b043319cb53e379215b0c8c8b8a7c67f2e6698d72a343f303e715db24d77ad2acfe83d3fa1a65d1f94d719c8d4516b021ae0a488cbc52b862b54cc3b2a858be86a9437856a978eeecc851c8b0c0845cb597ce6b093dcebe0c05b375a5c823aa03e0449c9772e35bcc145c1bd7e095afdec8396017017895285b31782509314209e3c79ad3a9d80b0f7f54390d54ba0699d23e53fc0eb266fa7d777fa244a7dd9dfd7d9313f8cd3980076e5ab1e62c6aefd049aecb887ddf2323fe90df38b2bf76a36f305ee2b430ceb0b2879c63800ca9dca94a5b0dd6ff768d516224ee7d9fbe04d42ae16f8967182d55155f0125526c8cbb1f651ff2867c8f301621f65dc3334fe96b5ef49f9d913c71420533ac86d769173c2e9401ab74c243696de8db47068b7e0de56b63be10cab5a6f09f7740021fb9be99a60307a90676a65c5578f9963a4cc256829811fb2b45cd13085e33c2390f21f9cce78ace23cf2788527024e1041bdc1a430f6cdc57f36b617c1a45267990addfc14380ddb3fff321b0eb61bae24af2ad33de982b0901cf760ec0bdc59cf2a1859e9f0e4269c3e82c06c354ac7552230d26f955da5df27b1957e9570eb687b724da2ea8a377bd068ab26ca9cad6d50abd1d87be51c5d15186b4e0c898c7db513b0bdaf74df89b18fc88770e32e0263df00adfa8afab90f160e7f96c33e89d3533fbe0dfbf6e1d1e0799638472e75e01a2dadec7ff6d3dabd5fa79f3d5d3d74f1ae2ed72793031290757dbbc7136a782db59ff8c85370b2c08025dfb768a8d487797c1fb3b0568af71ac2cf2ce91822fcbebae6b7b154747d6cc2855262fc201294547a187f5db21858930fc157c57f9721204018aeef0bd79ec5d93271325891eb61f06fb70e6d4618abc0efceae62c20310a9063371e5cac44185c78c67254f531638d9c61ee5fa2a4f02dd8b8327c40b271ecc475f411375ed945f2bce50803d41f84bba76bb3e48fa814d610b83136a0589682a57d852f601a757fc627000fbc4d2e2e9035492d7aef38f07aa0b2ab0e8d444d6ca9f2c5b1f92253de07ffb0a17c7990a05665d1cd97f57c089001d3e627598132e8b9e963589234398950076b0876b316eec96c8148b8a2ff3fabccc76c488cdd72a928f6a53ed3a95296833ab8fec8b77be7f10bb1c14ee36c17ebf3108468039b7fdb468bf2f0c6982bfa45e09d88356659a47e95f2fb4952ad29dbc046ad40ea9aed96027fd6243fa4b0d4e2927b06ef2cb77bbf1ca0d66055146aadf8c967858499ee6c85ec3cddf1155c4970cdad5eaedf0afd1c9e7425871e5a1f0d03aed0f042a96b81bb19772dff69f012dbe5d5ef90d2c5052b493fd9c2d0f032d9ebfbc648d5c887cf90b1fd5c93647b4628a8da8d0bfabfc0cb568faf2926d741670a2bb384b7884da13df42a20b91ba8da822951014bda239c58d4e16a4e7d046c7082e741a1510b98c376c596d71227b03550f4cc767bf3c414bc2219c7e2a1cf049bd21cab406de78576d9be0c7aa08b2c24dbc34c752a6466671dd05bb9d0ee2a35b3d5b5828f3e0ce7b48de3f4021657c997e98db2004a823b5e7f98e5fa7d010d6422a023d7850f982512a0248837c6eff2322fb7b77b6862b712b3d094eb835559d72a14689b014ad943bcd3d978942bd1c5059ead3f763339184e10a9303b6b117e2de1eb3003d7064ebabfe52136cb6c999065ecee0380588c7743c848580967695f6c8e67a51a1286565e2a01fb69b104d74be196c30e4270505ef4491e8c8d0103116093c84414cd8697484bb6357465350c180a4eefc6a8399ef384bb39ab2e52f8ac410f13741d8c52f0d467a5462e4852c208ec49f65635abc2251f3a9d7975774e076aaf7971790b78aa394f1587b377075ef14d6ef3acd7c03a7b805f3151bb09847b4045c0a2921ce4e448fc1e0dc2c7833bc5cd4b76de9187654f65e78de35e0c3db36a464fff70f295b04c0fa2c4b03f660a5e875f1acafe4333cc07706290abc7fbae88ae1fa8cd454ee1150b6833e437fc7cf59c28dcf99d07123860aebf1e36f1d25f5c7f4dc3fc578f615dc25340ec59fc27b0c0a5d2b229a3bc7446e313534d9156ccf28a2dd7366ce439da125c124aa8cce12f62f49b57b190c0efedee7d9f49ec8f91013f863474e2df0cd8782d978db791f84b9027bc804916bea310002f7ec933a7f00d10af21d1176aef1a78249ff41ca4603b67ded5bb46ecb6c3e084b465e733cba989d90a92c839bedf72b51108d7bba586494b95c5d41906474ca12e87a9f88e102f0ec7d9ccb23027534bd71218b224a5fa1f21b21679bbaae9094339aa79ca68e9ce5e4cfe626d7cc98484f35db7ba5bc1409044b5e3f6888dce2e8709efd2283327ea95f037c4cfb2082e526e713fb8ebda8417eeab48e9d8c78fbfe74e0bc08129ddc3895533a2926798009eb2f19c884e2256983882467d876d1f6ac0bbf5027e24ef0dacc9967895c09a803e858799a4ad6e5a458b7cc3f73d68527f36ef3f2659d96c945ab4137241ae4280559092d502d739c30917b3263e7321b53bc2e15fe5fa9065ddc2b81d2bc11822fff8ff012c384fdbef667b7a3e8aa276126810f2237fa9a7b1c96c32b20937963729eb527ea326982b5017234ce330a12ebd1c93d05fc06decd5abc694d046e0a517950fe005ef86dc66238610be6716b67e54d9f427c845c9965a3146553794fc236b2b050d7aecc440a00c3d46c8a5149dbd902256a1b4b8073bf68521e6bc186c392b6864311d21bbbd72684415e21f0428891655e96eeae276a1958c8fa7ee031e2bba2d75ab525ae2d3100a20741823747d892c46835803c1dd38ef419474d9d0573d303239b10fd6c104891cb98554459d2ba41382241d86db4049638b1e9eef17edc3332e9038f51b15123f95134c575d2ac7e8921a48d38f7e5a9ad6d25c0793498c25347c80cc92f6de08be9c5092506dbc9a1c9a1e1646cbf7d21f9bba110741ecf26d9ede1aba247b7fb02fb8e80f773c6af5dd4807de848e57fa0fef3595cdf71010152e67c0b4988a28d431faf8a0ba01dd423e3e3d1030f29643fe17bb72f29a1dd80324a5f92ae414d907655e1d97f688b0140738afa5d1ea610b5a8d7348a508cfaeaf2bb8924e462b6516cf15a5f882b1df813803c4cbc0f1b821ff974364e3e312ee21c2a6d3fd0854d8e2e086979292a2dbf43d3ae08a016cfc384680f66cb64c97e8fef67917d2d3e34228ee539f47ce0595825361a264187504b2920c1182013784d06d418b89dafc1469d6f4fab5d8386e940ef11e46fe685cce87337929155f15006687de0d1b1bfd9f9487c4e77d623bbcb9c96da745ffe477dd362e7f6bbb7f37690c388529cab9ccbc577ef96cd0d32ec9981730cf47b2753fcc26407e27aa5b32a229ca3613c02806859097b75cc96c46655fbfa208aa902232821c2402e780cf933608b98f0f3c52f79b15ec196283f481d006bd43fce075e5618be101a717c810b2e073914c711549fe22c39bcf25f1d0b4c636ef92c2fc97651011b59f99c6a05157c7f7aab0fa1645cba9e7395dff61e13e6552bfbb2ef415f46d5ae71f0f7cfe65f3c5b39b5d34db04c5f166702b2fdce5f04c487ed3028accbf3da510c05cf104bcf5633ab4a44ea32df7814acbd72fefaa3f1da9fff62974d833c0b732ba563634168a75cbabd4b4785c762393ca75efeff7bf5150478509df5f8709fd330df110ca2198b5e4ce92fc5c613e4d41c21e79029de18c01ba130972557153d76b21c04b50d6e1a013158f5c47e8a1c77b0aa5ed18ecedc4a523a5d6b0aee7ea0a75572a0b54ad2cf96489577c86edf4e906b1913dea529cd7e9dda1310019c6dc51b4641a038ffd7924b80b9af6a12dc7f8ab09770612152004efca8a65395dd248c96aa4845452b884ae48ac74d7eca51b40e9bbca282e14a265938706d6b101dd7f5337d4b725c61e1a79e46a29303b78d512adfefeb0b1e7540df32f7e513b51def3dc7ce29176722ebd991ab5acf9d7617403c6985cef3601ee5496c7582ae4ec98593a5b746586fde02aac4a2065be599adbe20edb135e9d8ab13ac00add4fa50eb592d5630bfc4c2d325598bb97ee38956233d1eda5602601bdeeaaa8d2904764322021c3a64a144cdc2e8b76ca3b9825144e9ef8a5b9cb2ad281db08caad09dc51d19670b975128d5832d4a44ecab2dd4e392396eadfd322f9479c637e4fc10b55b2afc66e6de7ea30ddfb56bfed8d3e05e0a4d2751f49310c4419262269bc9a2ebf4f8bba0bb94d452fc60a2ed6bb0e578e4916ebbe0ff95ce265a115d4be44b6bf650b5a4eb94fa77341969b3c0ebcb07bb0c7821bc0709a93b4f2478454b741087a35cd07a13a685675ccc2eabc25d8ad3c7f5af234e7241f623b133afa9489f8453227b0a7a259d43721100714d2857f9615cb846ba363ef789bdee76bd438c40c7fea960a8bd55513033348699b7961cad63f6f42d66cc431e660e48bfc1adf43aa0dccd01e4b1ef20decfb4d5cd47021fdceea9e16328a0de9e33187ba04011bf12683b2ff85e8602730da0eeb96e5e1f2ce64112bcf9258ca1ec60093077f690daf1f0b4e95233a4d87c092d8bb758a856be895afdedce82e5148085f7e1aa71e279b8609cc1f89c8f2dfe7201868e754b57eca92a074b05ec878cd5db88ef975ce4906255b3199ffd16caf0fdd4c9cab70ae3872cd807b8bf4a364babb7acd6a989c89eeec35172fc47e398a85490a272b8feb983e69ba725f66a4d10556db21599d82805f6b186bec99ae06d8c068dcca64cd4d34b339b5e9076ab1a4fbd8d93d0a378cece535fb0b6fa581f66561d14b99b374f18c63063e1e7b7d1bb02ce395772621fda74625592a1509bfb7476f1089809039b7c2a26c2d64c320a5252f91e4414ba9061109f2860c2df52966398af4e4c210b6b269869702a909a19ba3482e066d50f8860673122de6304c1e9f974482078faffbbd3a24d040a2498cde2b5b943e20e430a95b7f307517543042edd7efaf93c99abbf5337fa85bcb7c53361c8bcf45bd1df499767c06e6b73ca5a7d4e06d6ccd0628eb48813e87d6a4cf519c1022b4dc4c5bb33bd6f5ca7d45509dffd2e6e76fcc88325810881ff9d11147fbc6a2a1b97fcfb9b5426003eae371b2992d95c0190ebc3bd6ef09e792f93e061a6ea994b32d401febadd90de2a5a6af4658c78c6298fb31bdcce8148b972d98b7cf0d3731e6d91f840062b4afac78bfb64b56e65b2de22231bbb313dfa49704fbf7cb077598514e25e43409fbc3b4e65db3b0c0ce5b835402e66bb09dd55a86ea57be1e582366d67ea58d365943c4cca29101ce70af911d6cc3cc204eb2fbcd07079a098c6fb99d632db6ed099b602002ae7000c4231c70832c87bf8b916facb0016104069e0297a228e4f24b1ffc9e37e8e604403ce491e4469cd0592bce9a5fcd2c1a960d2a96176952e6e6c7c53c950e2cc3efe17f4f8c0215f7f4c9d81c615e7c112cf37234325a9c6a041abee4f2e1483525ed7ec6f864c25985ac92e2b098f6ae42ee429a451305383627096bcf95018cb22cd9a1140ec78319de29c8b5211874042a1a2b6b2005f714d3c5688ad364ebf96c59216c32d325bd66b4149e8acf9817483c9f7264dee0ee6c17252fab5f1afb4e41f5d513ba4cd18c818c557174f6142668932111ae8886235d28355e8ffca886470becade505fa99472c03cdb64e9c76d20e2fcf77d002c69b653060cc13920b703afa67b36190193abfae2edea2b75ba65a8a94f147cb10c388915d2e620c813591476b40526bb0487d18e28d882d588be8c1b6c01b8c92b4423a80279b31e14408086d27f1795adaaee62273c4a2c09674948107482445230d40c2d51200613e4a7801e2d09158503d1c63e1913580a22056a8523239fd8b5eb7ad4d6688b65dd946c63c5e0343e9e207b744fe28390bebe69ab19bce1671db644f5c4d706294bfcf23b1045c0dae24a1b548f832d704c1171d668e046a29055765f64cd122c83349280207f713ec6d7e3362320df75136a5305a49103ba72b27f5820cc524a0783fcc92540a636b56512542300ffde127ca48755ca33eaeb4a3fcad21b18b0a6c2379d0b877c96e7020070fc623abe006cc2c593f76252b6698f12d8255385b3bfd9974e5664117d49c8de9b6cb9a59429c914a5072608a0075147ff084d17cc60fd434a95744317dfa1ba4da541305656914d0db60632d8fed8b42a74adb921786955adb4caab6ed3afb7386cf5c686d996964d76f5943d656b3626b253d844a20f1a8cb25bf64b6db5fa6d255772255752ca8f88a505d7552ec431eea87bee91b6ef65b41db17e7ba46e7941a26cc8532ecf3661d3d8909f7eeb51b2e1dfe84d0d4697c2cac299764c0505b9504389c5a729a62b2f08cce0cb7f8a89415f6a3042b9fd852745cd08fb5d7563172737642a9f6bacff1642080db28ff94db5213e710038c4184fa85f0485a4bb7aeaf54fda0c6020d611c6ebd3f3b95556bd12b3f14fe85437723e47b1bbbbbbbbd65a8f1c8b952ae254413535e54d0daa9973e7fa57ab34cd397343ae9a33e6c63f8a4b110a0b8ff598d8138cd8eb62c0b08e68e958869283e5862e0575e39c7136cd836f9443e7862e0525e78d508cc5f735cdc3d930778cd1ca78dd3b07c1e7cf8f0760c6cacfe353f3a8f5b6b1215715b1d61381244b57d8ec271b3b35c8c15b8a032d754d70f76fd67529068acfba633da64de9857c879f7a46664f0492d0a9725d2a2e71749a6efca3168a11ca56e5912d2dc50bf0e0cebe6106ee3c2a21def9448e14462b979fbb1d57b08f69d085441063fc1a638c532ed56044622b2c53c9e8a166fcb1f62012740130c813b99c6c1524a61b72951179b9cf6c56242bc29572d42ff71e0d36acd9d31d2bb0f46764ee699023a458f71d21c5584158314887f41212e359ffa21f9f6ebf75de11ffa3d677cff25e42fc488c7b7aa4f5befa55fcd949a0e76dacdcd3a220dd778414eb7ea394fb20acef28c6aac32207e97edba851358af1acefa8f531e867b46d528f04fc59efe560c31a3bef48f7f6e30a859e6fcdcf0bdfc5747ef835fb59c429cdb49f45fcd2af48ac5f18b38c9f64025a5e52cf97a5df7e475adfbd7722b4be9751f7bd84b0de9f553b8ff5ac2772cab1e91971cecac609e89eebd35823042e223e25d80b7024d4d0831bbff5b343aa1cbd19bdd67b566c5867b6630536fbf8f463adcd7dfb4e57146375a4cbfacc7b01b14fff957df721d2cd4ca81fae3e3ef55e402a53ddd667b1fbb1fafac9ee595ef79af44224ae5ab95c3dd0faa61835b0c165282aae5031755b9f3da07b1a56f6da15458f487f186fd6fd583deb930dfa0784fb2cf3340ef403fceb7b25b02dd66bdd1722c9d80de95fc9d0e76637a3f4b3c9f28a6419fd2c760ff0cb755e9178b9af886f5fe85e96d198d4d967c46fbf5c791ce8d73e1328fd5e3fb2ef05a4be7f28bb1fdc60483fd2be6d3912f4110cc443ce1e0dcaafe39c2cb93010f7fb833d5b4ae9359b93cae539e753c96c3ca8536c910a7318b558f0d6a128050a150af9cd11055888d983f8c523ba5ce9e5f613c1e011285879310822bedcfe1f18944188b90d24defa452706923f2c61bd58a575c569ea7664ea9aaa24314c5a2614eedc6e40ebfa73d26d8fdedefe8d0245d29a52b1796cee98bd6d904e4a4106ca420a6d308f301eea98655946a3dc3e6e7960b0ee7e10e0fa34ccdd12b1be8492a684ceb9a3259973ceb92599f354c164712749994e09d5a6821455ca93357162369973cec9056dd2e4882964d07ab0a658a1e7888642082396cc07ffe75da87ea54049ec3084154ed04045455e6102059dc354032b3141f650dcb007d4144e6ec84f5041526fc258a3a429a19452eaa50a2a6a157652a8e20e8d32e79c93ce4922abd0228a0a3ee78a2e0d0b090834349440872aaeb0e2c9ffbc79f39455b14605695dd6c75a3071bca0f64d1a1c59bd0cf5a6cc0dedcb293e9b72ce3748ace077ce39c12ede68916f787012f98d0d4b2cc8374a5254ddd0be1072e4c869aefad81aaed8a4e887941bebf0c840459fc6a0c76e16f16def039d75d7009f1d9dd545fc4a59f4fa31affc79e52743eeba0fa25e451ded2c078a28a5947215853806350f8dbff0bbfc610ed7c7618ccb40714d0458a8c793c043f139c64e36f3478e1cb24ce33ea7fb941d7cffaa6a610ed787c1ed8ed1234ecd28986fb33a76374f9613d162aea05b30a160cc2c2920e924e0d0691ea2d0c18e17477899410c1776a40e52bc10a5704297b0cc610799e509a5945236db9299a539e79c5bb42496ce6001536689cc218a3c38bab80e021531a490c50b7660708a414561270a298c608edededebc00792363e08a715737ba96ed0410f884c8df3c98b71a3dc6e81ee8910ad12a1f4941fbd51fadbe97907aa4fdeab35d100d29cb8b525b836050a305954be3b21a2d92ee2ae9fa1663e762a0d690b02110b96e8df8ae27567e3abc8ce66fd33b92c27cfa47d9d3ef25847efdfa1dc93efb65e1587741e6571d5614841dd6e06dfe6929a557ab11af3134e2d78b8df1ce90b261e50924ebd95aedd71e840e8df8cdbe703aa5596c31db7caef40b91aee6bd7bfdd4cbe873d461f4fba83639cce46fad785d57fb8d3fb0d9d3cf3edba4c746b0f68528d4a75e18847ff5fcbd7ec4d79efbedbbedbd82dbb7f7fc85aeeab18725dc50fe10d7d5e86fabee39efc8eb47f6abd5e7dacb8c662f1becbc7e5f7df4b28f9da669da735e1d12224529dfdcec7fd0cf68a5af7df54ca0affd466b5d7daf9708fedd1bf5733f02c7942cf15fd2cf7decf50be97f202265b4289b6a98628c5c966dcd5572488332f3a10648a2c776231e1b729c127c931cc75b59997dd7de40a615bc3be7ee3e65dcb05e4966862eab276a758f05451837c6b8c48a4be365f3e07169bcab2ba2e1fa0bba22d7054b66b817bc055dd10516fc8caec88219cf65ee8cf7e98a66f8bc8caec8a70032a264e0b83264bc1d7365442941726524a9f2fc262a05237ccca9f3863560d77d6d73bb28244144252d0d453279b258cde76a3f57d3c0b8e26a618401834c0e28305c30c01765044085c31ad7816ef8737de8ba7781e7ba175dae7fd142175baeef7822e9e9d28832521084d405cf972f7440a2a44649621142c4192584b83367694af6f0f1adab8b2b61b8cda52fe9db00ac10b9aa252e7d59b9b8e1d26f592323ae9ca9a109942e26903c68b182e32ba59492c55dea83c10d6ba4d962882a2855415cfaac05144f292d028719435c5ca5d1428d16488ae48f1a353c74c31a2b9872a91aa815dc61228b2f97feaa2ba23f7628163c0061a1e6d2d7ba22ea0202aa8b3ca410183c58e0e1e14a2d5f5ab42b9a63ae78e2ca9f49288f2b942e6582cea5575cb9d44529a55d0d3b6899e109a8289cc81d82684329a551892b5fca6a0410ad035cd9a4c7d2a89366050bc2dc71d59942698618a70bead059c167aaca823a5eac20038cd30c3b4e96629471f2b1d342cf1a19766e7062a798a69a62d82c515a524f3d45b0c022f364c57462a85a76d840e1ca24b1ecc459dac254e9ecdc5995e1ec78a18599daa044a960a856539c645254da0d4fe8d454f58185d9942121472853459960c14798da32a558a14700c324a1acc013471853e577902cb198a5762d599f79394a69e986f63fa62a9d3063c4065466c2c0943063260c336f02800233564099c90206eec1ff018518d3303ec3e6cd0842d0f17721fb50679e38d9accbfab8a82e33c1b441155b5f0077b03d337050c6763ec048605746dc60b2aea81e2c8dcb5067daa839a3050726b0f632141a261c0461e56528343074b0049a18b8a0a90216292555283478aebc1cc504889a467ec040524af9335e4687c085667cd149c6e7b4f919b9c5c9bfa393537b216850dadb5e062cd8beaf7e19fff28ff148b157ff8c7ff97794c5fd339a71e413a570623346082f8208f326d6de14368c4edcd5b2854bf3882f1166bc8c1732e37bcd8f21e435bf2016bccf736c8637c5f09a5ef367fc8bbecf7c19ffa2f463cc789fef288606868d5ba2d30caf4e4f460c3b592d5bc442710aa7f0001cc56418cd16da5aadebbb19a760a16efa81857aca9d78a8e7ed6f5fc86fb80d0b0d198e3ac00da35310cc73f226060aa3d395641836e5423e45471b100d19eb4d55ea80815efdc2a7e14dd2c730907ce9f235505ae2d132a9f565c78ac54ce632475d3e40fd3008e65da6c15a7da21030900bc52c0c237ac3fa421d6d40344f66fb42171f400b0a75c0408f7e215755d9f8452c0cd4ffa6898d71a83450a2ba336b20e221edca0fe10703a434c240f2a50c6a50d24062c3a0fb2fc45588104519a5121a141465f5a15f0d5783f25d4f49e23031c5263c24b770b95a8c04312221c85410128884800d150fc9205808749893161ee2d897332e3251472465494957f8d2cf3e99cd7eea713569529b94b4c4431dbf081ceefcfe0a033592fe72fb6392152b6e686fff2775a1a2a27092ee002e434901c3dd5afc2359eeeeeeee524af9bc926337aebb197d38fd6ea8a8a44b68b0692029212669a064e9ef7822e9f6c73b3db8ef8f639a47f7fd318a7d90109f044025e9c647bafd118a87b4efef383da85a055f6e57cf9eabb56ea1e5cbf52f32d1225abb4da5795471a1d677670083657deb8dcc4b89da87442974f3c85483a51f910f095bff82276c1899989a877c252c12b21ecd636e3884c7c8cee306394f3210fdc85402fd76b99828c779803ffd6a784149f0af3f6bade4b1f2c75c60bb3c86f5bdfc39e641c3fae5d743d362ff06d1e686b1ca8e226c18745b4f36fed956726cebb21cdf1144801e02906c226080201ed22efd1e3c945d4a298d94ee6890067957580b368fb075e9d3a78fa379bc44982fdf68befc5e6e24ffe534c8ebe16058f0fb06a9f7848dcf2d1ef2a74fdfe5424eb15d8bd78fecf267998f23ff1b82af20b1cb135c945f12ebb098041737ecf1ce64c3ef6e23b6b8758d06df07b38e0b6e5cc1b11cfbf0501d29b788237f4c6a9fd78fbeb7430f5caf21bb600561c35aabec8af43512af4767f9137511bffef93050af56b4bfc6cbe95397b3bbb3ec9d66efd9f7aaaf5a332dabd98a66b4468334fb5c0c445d48946905875da8d6af66f139ca961d65ec2867d3bebe84c423d947a4d8ecd7be5f46dad14b483752cc575fbfc8c45ffdfce339992753c97d822596b0239528a5948af912a6c91c33658b3995d426d9145a9d25b78261c527fa7cf4c1ee75d655cd42326c3ef5a6cf902bbbd3b4164d8a1224a14a73ce3971e0acc89aa024c86850a299d214154c4f64c8d8d089939da1d366632e5aa89374450c5f5889f23fadcb5074cad0792242894f09cbb97a5c574baa25852403fbf23753f431bf768add020ff9d7276020f95576fe0555ac43d9f935d34ba766f26abd9db8a71c2669d59572cb93ed0fa55383528bbbbbbb3bcd6a56b39a65533a15f13c72cb4c63a58cc997f225a5d3952fe593749a5912175bcfc8ec2ebf38c34b66f6cf04feea00bcd8500ea08b0debe54827ba942edb3f966ea4bb7b411a74b11c638f066316fbf10586e5675d6139cbc62a39dde8aa11b5029b1b81e460f969ac60f9392e2c3f8d26cbcf6961f95759587ece0acbbfb962b0fff1fb698d952fbf23f225443b32ebcbef6524e94bffa691cf77ed031d16654357c631d72ae9e9c95aaa6ecf9e3cd2aae8c3bf6ea25df050fc3a06a9c36dd9e4591303655318d6df2c75f0ac04d3091bcaa62a4a45a9eacd92a20fff4ec2427d03c3fc5b0505ddb8a18106afd70d69950c1937a455d90978c83f1b32a7e8237e5d259eccb2afc618a43583e5a0fb65d7bf12c2c84005eb3f4370ffa0c12f96a5571692672453ca9c65f2e7c7ccccccb17f91735e13e6471dfe8573ce497d4e77671f43bf3f32f3836c57aeeceb17cea79ff48d29fff44c4aeab37e6c3e98b579d0d9834ab13dc3fa4dfef931d07c39db063bb3e7ccb3f7ccdd9d4ee7a4b75fa553122e9862fde51070052a3fd9a046e99c93524a69651b73596599ad2bfbfa8594d2f7d64aa394e9277f8d95ae7243db1c1c1b3fb4769b2fa5d632217b7bf9f20db3eff5c35efa56725b99e1b2496da756b3596687317fdfd1b9fb0423d90581afc6401c65fdd8ddac3e0b8a3f4ebf6d153ffa8842d661433e30069b7d17f13c79eefc000085ed9e7b18a5dfd4697baf9e3b23f1fec8600525a8103e2019aca084822bb39a7943828e6ef6e4759ed39698c47dafd5b31e2976f45a716fd4fd5196d567c4fd113bac23f24ceb07540e04095a7536a66672c505b9da576ff34222770baa755bfde6199137669ccc3167556b500fb0d6ef2a653a72b7a05b3b22dfbc217eb72d7ba2ae73ca5b2f145d8146e1c6f899c07a9e3c4c3d3f645580e3b2428aa156d13452cb45a105153e3b1df87abe0adc215fec351b27a06a14a87d6b833de4a7860fb6bdea853528e0dae28324c5dee1c6d42b77a2a0246c2a777efce2d2276a10dc3afdab3744bbd37f2efd420adc213f57360f198ba2b4dca960cbe001f0fc2e1a6c28a5dc7e0078ff1978367078ee0ee53ad3f5a5eb9ffca8e5d29f1edc3bd32bc2527e7d27a7ef1efd1e4abf5b2cfa1db73dffdd322e7695b6d25418a8df29d392cfa5c914e91a4ad5604f6c2a3ce4b7eb58b9dc2da0bbf30e03f5bf1abae6f627e08654eaf6bf7ec40fe79ddb318e8cef5a2d8871e89ae843aa79b00b517bc5e9125df2f61933aef4e61b0094b131261719a582944be372940a4e57724f13cac6383ca4cddbf3126183e7e085800febe46f4a80beefe037f080707836dec3f130cffb0e827cde14d1ffcf87fce4c6c67fff46dfff3ced5efe7d363ea39feffb8838ac8170bcc77770bcf737bc0e1ec8037a22df9aa311c777248b3f8ef77e03ef7bd0bbf1409e8defc0fbe7c0037a98d7c17bde919f07df3da39fcf3e0eef083b6c83204a6c7c47b218d978d81fa9ff1db1f1c19ea877b8c1f13fdfbfc38d8dff0fedcbdfc8c6e378a3ff9fcfba977f22e0781b6f64e38d7ebeff1d58d8ef6f3c070ffbf083e6f7e1f81b9ff73bb0b040dfc16ff0e0051f4409d077f03fde911bfff33872bc87c3fb1c38be1b379e633f39fe7ba31bfff3396e7c471e8eef891c47920601781168e0e1d0e003f044fd9a36bca58ed9f8f794304140ccc62f75ec7f7a416cbcf446e0988d774f88c7fe6f784772fc8d07f28eb218e9f80ebe23254c121003faa518ebe0757c2fff7f8e1d2dc518d0bfdc3b92c528c7f7f2cff11cbbf1475efebd44d0f138de28c7df781ddf5116a3ff1cdf5107ff7f04f4369e63389ec8813c8ebd67c36387edc0638b7018d703485787d7081cc3f147fc1413c18d17018ee7588c85910948098eefc637af743061de5cf22607de065e00bc977c8efd7cf18af7925facf27dec30cfe398e6c5022eaf25468cbf315c3786651692317e2e7dffe4c243f6dbc7e743ebf3af2f74f97cf8e0f599532e7480eaae9fe2823a6e28a76e5be0c509b91bd2a513a40c2fdc71c3b914ce23b8c1cc7e1e3050f6d26b58f63b82b2677d2178b3ef6453b67d2bd9247d4269b02753f6cd2522ac9cefcde33d8e6d36bc23b6a28a229262287448a05012cb223f86b2c98697c1bf07802506eaa5a8a464632ff150d75ab2f1ff05a87e8a4f36bc230e63878ba6180a1d12306462598808804ad27d01f1f94929cdc3bf5794ba52f70ca5734d1c7fd31fa9629517e3c8407a75065a9c4e4ae716d65e8e6a52e786d6095ba700f3d849b54113343770b074095818bb41c1e21811c3096ec860b5cb514d7668e2060ea6d8ec7254132a514d5450a1d1ac71185882a8264b3026b65e8e6a920456452d2dddb0c5883d3fa0952c00781d830e9391d3b48ca39ccb67b2b495c7ae39f8f3355c96ebef18db0220ba6ece07ce4fad2e17e8deeede2e996bdb6e29a59452cae972d5eadeeedeedeeee1e4677daddddddddddddddddddddcc1e6b5633dbdd168c891cbf7ee2cb96d3a7f469a5f4e8eeee3eddbdcacccd63dbb81827c7e1abde9e3be7b43d5c10e7838dcfb1e9996105671f9d9eb4eecc2d2959b29bdc26b4d2404f4ae9eeeeb23a33334797524aca75c58172cb28375db2b816e703c7c6f7766666890597c5c697cccc2c8362581968dce5486d4a275a9b34b35c6b955a46679eace59e676a92524a3549bfd612cb0d4a2d8fbb9c4efb0b7c95ae71ee56f6d0430f31e41472dce568529335a3938ed46a46670f313030e2c96378d0608f1e2c7b7a68cca0b2517a936696de217aa259cbcdb362b78a110c8a42b109cf2acb326e3e07a475b32b5b4a6c7ca2bea2803b1bb7e23a6d55a90780411804ae7b0ccee7ba1ff2d20910b9b856d6b2140ef89e8bc613cfa6553775537f37b5f74c4bd497c8870ab7327cba46833e3e5dd17c9f0e8478b7ef91351109e103063491e8e3b2eb2a8081180f118765868c18b56948d597b2baaafd2a41f974b716c72f906881a10446125c1e2a3d75f2741191b461a590c38c242e2851a25e71dac2c275289f0f5d6acc8d5467dec42dc6a51b5f32c9a6282638dc5056915602bf3557b533ae1aff036a727eae5ae7ac9e03f31712b9fcee69316ace9e11d97dabf5acdf9cc7cf5baf46c36495a42b5c4cda925445ca690b978e49639a4774aae1b6969854030f456b5f0cd419e5be90b3cd43d3be6d83fe5af36885ace7063b20ddb79e763f58dffac2ee877faf1fff99c07d7d13581ff7b1731edfcd0bebbdb776f6e372fd5416c45663cb6f296b6b5ab665f57385f2fac88fb7b0fd527619374565839d7d3472552e06a795317e1f2748ea10db25730d1777f4b136f2701e91fb6958fbc795a53733478dc50c245faae988d4d1842de4fa823556b0ab973cf4bacc1139ac351937cdbb526a14b8f5d3a17b2217b2600e192f49b1fe10788abb27c81bdaebc3403e633608d1076d14f2164720982fe70bf22708f65a2f7b0c9ad81882526280c5ceefad2b821297ec09f2b6d2f471811c59f6072d4eb23069c70d665d7da275355ab027c8195d51f3990f78a559502de058210a777b9f79675cfeee4090cf711fe76d2bad66744abf1bc771ab8de32c6bd3a17ba1eeb3b55ad75f30eb16602f064d408860ac50b9fe12c808ee7c39878c97a41b9f8ee04a2963dd04bf61816a4900b458d762fde517065961c0c4fafbac33ae3ee7e0baea75f66f48d06dd939a0748d6ec6bba29ef7aec8468dfb0171ece8211bbcdb13750cbff5930de82be3eb0848323821c1020625b2a071136386ad7ef3647c2b2f94778be1c5cd0b8feecb7ecfc70ddacf6708775b9f0d3595c16deb3ce95b08384f3e6fab2f3cbad525b38e63441a6563fa723e9dd3887b992165432458fce49c1f90ee8847bb62e3e253c5f6f21b48bf34322f064454adc72552c788878a14173684b1248822b0a041bac10b2a52f0c49aa617a03883a51ef1a5890b4b5bd4489971e20e9427636a70a18a34f38212197c50228a175e52e044132c984c0933450a253985a5bb301126490e5cac5461d102945c420e1a178620c10ada784953c606364ddacc3047094c1d32588a50f183152956cc14d1650c92152469b2f06108252b5188711c783042c30209dc2041c39a3261d88b28787e386229890c45c43c0a9326f06899414e5211601070c50a2a2559e84c8142aa480f767218020571b248e14b12121f78c0f24445c78d12333411461b20f0a8417243145216195878d374c4164c501af00186285190c0f3660a05484c48be809344c40b4c5978d12189282827a0a0c9d243122e28beb800c60b4b9078e1e9d5449326a29ea2c890844422ce1b26a0f2cc80e4c9982e3d749b33499871a24c0a787e807204961f5334c8f004551518d0482e0ee7688a9492921b92ec70c5882fb248c1c1ce114f9c48228bb02c3081a50c1e20bcd040440d5257527053039425e4c82db379b0001c12acd0c59c1380791a824a082849ba8c31c2890c42fccc2084933a2e8019834706b1c110456c21e70b0c4b3c915a6201e29c3b1828488cfd183dba7497d2047fcbf9b894f2db06e0c532736c61e39fed7fdbd1e08423e55a96a282caf5e8cd0a8faef605c99ecfb4af861b1b1a91d7ff33af2bb259966599b31cab7d4fd8ec897ca57d6683953fe78330f61101d6317b0cdd98414d82c3e6134008cb178479ab77b780ecb320acfab357f6b5c197f6f433ff97f63103655fa5fac2cc5282534018b22ccb3249b92b9f5969a35936e79c349392f9d9a564965688bc0cfb6ab55a497777e9e2ea5dc732b3e5724193f53959f21429a59430068a43eee04f8d70ce39259d35f32624b394cccc524a29a5945232b313ac2ab6c15d00fed81579db62a27f5a16fb63fdceb2efe88f8ef891621c97fa6d2cfb5ef30ba284484c7298fc1c6e2cc7b4cf92e52542f6ab37ca7e95511965af7d47447e81a7ec439ee25864a21aeadb58babeb1bde56ba706e57b66ac7f3f295929656520fe4660398a853b37690496a35a48ba1a0f55285151b4cc1fb0a85158f82259e79c73ce6f86a72c2988422a4e9dd804e2ce29ef9c73ce282876aeac320aedb3d5afe25ca0bbbb2b9a9991797d6a9a94ac56967d8b2f708d4c6f0f071b5dabff5c1f1176f55eb4aa736a9aa6d1baad3c49572bc642c677df3801514c4e709e3ace5add7cf7b1ddd9fc699817ff6a6dfe8b962459b65e45f5301c193b4607a37750501838e4f72ef97e411359d34829074d3a77528e41ae17eefc1a3be6fc1a656c92940bc5e8c7675895b65d9f552297d218437214644727e8e4b084ba5952479ea15382254f986e08e2887af2e4facf1326782403eaeac78316cab6678ea8041ea25f2debf983feae42ba27ee7cae85826a341577c670fd2368d3f0100b2399f0e1fa00b4a13b9fd9cb9d5db24b3f01309003a8940278c0f5e79e3ba9f3263b20ad1f0a6c2baa553a23730deb276aae824be0a1eab12bd2ec4ac4bc91835d71e1c1f6e02786e2a9356ce2dc59410855f47294933437fca02dcc45d5103e709102869730f2045b7871030c29b0810c1236fc8025c825c50a2edc2c718309a27832473acd3373a20cf15b94133237e427285e739dd9506597a39c28f1840b0c6a2995a9e4b201e76e6c86c0c00e65bab860064e17282658f26632b1444e0d486aa05343d2172820020b1f9e9023656e804a933356a058b303179985c9d28a09262d38993f9f6813a529b436dbea7294132e576cccee85ae382465fff42bd2baac8fb54feca65d8e7202844cc1c7449b945ad5b41ab34863f4e862ea8dee4aaec7a406659426868ac2f247270957be7b174cb1fc52724bf68e6eb60c54b0fc910121307f80d4b1973cc39841068a3f35a4e5cf66d44bb03def60201b622cf3d768707a4b2943ee5a8e6777fc9658304ba794ba9c9e0e4456b2c75ab2f27988cf8df23959e98c69985d0ce4534379e7bd7bd8f8e7b3cc595096654fc199516a5d73d6ca94259d328b9369fc9a3d675ea0eda8044e974435e9d0d4000000404000e314000020100a07042281301c1ed2e55dee14000d7992466e5c9ccc635190c32808216388210410000801060898a9a1210e00686d76025bc4ea29c66fddb6a2625ef32650a17d51929d62e56f757534b5b9e7b69a46ae0504606dd7041902b0ed88c9166c7edae2f917205454e88abc5ac38df461653ceac3153de72f6d48708df4bdc8f5494b6e6f0e589b8d05e1a32f599c0eb4703af805f5e7ba19063c3213553b890b1e3413f8104878e29d927f86f3302866c12b308e9971a5f0e562c1f5372fe18aaf8e2e40d0dbf772add0bb868d736f6fa555237dfae0d3b0d09a62de1bf91eb8496d23c5ea087cc370f1123ee8c4dd3f680660bf4b8ff0ee53012625341a6c7d3a262ef00e23d8b42b83ae8125ec0359d869361d26e8998536ce15c471e4ef808d8917825f6f8af2787bd0dea78a4cc528c7fa1ccb668f297dba1a2587c1d45e900e0e1a3020ba5062eee10cb5761b9ebed3d6a6d0672b8cf10a10ad077cb63340cf968c0f51a2c04565806f62d25b8e8db508a6099e4a810b9d053c74d86a66cec8875fddde71ff2ec76a5123d2803790b430886eec3d83b57e1dd3db0386ad98029a74eef4ad1fd92abbf0e77a4fb6aa8ac22bc1126c21b4315717640458ab3492e4d0679644ed8d371a52efccc24715b1d5a908ab0ba4bd7c94ae6032833ea11ccf7efa2c004ba4fe30ee2a1138e6c6868bb86721ae3d088a38a0e8c49e63b24a275a614fa83877dba3a46d7bc2abe565ac528244b10bee5e192a90248b978777b897ca8af3bc37313b80edf8696418bf91832ddad7aa5055822c6eacdf814f3f9f9f701fc49ee5b94b70642832cb9b883f994f2a0050fd767cb1d6a7618dd35b7f49a74726bc5303fdda29631a435b091c33f32810c0cdf439f1d1c71e520e206f798ef2713ae4502fd133463345999c6d44b54c9753a4b943d2c1c56e8cd6e248e01d70bb887a2bb224da2517a133f668b32dddd59f4438ffe030bc036072a3eba9ab97fe5a621d31ff371be3ff8f3cda7b6446c797ae9ff1a3c0dd77c0202b91eb36f6048e8b42033d1e9ec14d211a7d430a44e1c9956731f50156ea6d7b70d1140bd850de7c9e4e5409e4519fcfad5aa90cf606e1bd68e2c8f49a2db2e94a3cd7ed0a1e52790bca95181efaab69a04bc593b91ce64548bd3343ebb108e882c57cf4be98d06fcdce6aba45422417e8d4c8a8cd9fd09dc95ac0e273bbf35c6a92830b3daf1e96bd7448a6a9691c5377bf6d35ab30331450c9926b19468c9792ef4b554f52349020eb109f6ea8c8540457cf80334706f511ab5419a891c01b27f28bac0e8878f851d49142885f64ffbe325bffc7080865f3c8d1ae5391de18526bce8b43d3422a994182d73656537c21ed39cf4a578c435568bd8dcd4d1d0d4b8aa0c8cab19efc2c352b5157125c28f771c5eb7b36f7ac89eb8ae6fd25f3b9b8feb4ce8c9861a7ca6a4a6121de7eb91ffc4aceb45df6e58e185c55316ff4898059a018caed30ba1dff6e5e5d2bc7489a09d323a2cee41a363990e621e5ae9236bf1e9d04c747c1cf713ba3a6c59d23ccee2e929b1fcefdb7445e8f12382c344a3bc2bb8fd904dc6bf3d66c6924d4c746884e0300298393c069081b51d59ed0efa673ae13ac788742757d91846fffe312d22b0b064a9269be70c4f592c0c6c0de52d8ced45ef73c43a5beb5b2ea119b026b36a1effb37f5a12692677ca2c5541421b230b03791102770890cdc7c70a662f1e82aaadd35591c2b36d7013a371e49e4de7d03423f2dae50a3b90e9179cef4ccac2c355af7b1e8bda115ff7f73a32137f52a4f59eb8c6910e1a1193ef2084d82c9d356319c934e1fdc96888d0be44f164cb03cc48e12cf2cb060b0a25a9e54b91e06353967ab779355891c3dc4d5630fd838d8540f72d9e2e0a637784e68821893b91e26c441476473e3c5608e067d75ecc04043e73b800a7dec75044d97c73f0e933ce1b83430b4a851104e11e1a6b2069e4a1c1a262103ca332bca7b0e252e9c66c4dfdf2ae04954229363bea1f88c183b70ecc34a2b2302d3ba0bb9a111c06ec5a2dca278802217fb0855a3ec8070b1176240771efdec29d0b4880d4371392a170cdf200faa9804599f96c90c7dc90260072255633517ff0fb5095a771c7c1dc51dc867956f830a24485d39f37050231e5fcb01e0449c1a2c49b1e4c41481a94a700c177649de02bde910e27fa12161399dfc84bcac462f9142f5b20ac5b29a50cfa442a04ba756843f75e50becbe095baebe4b075a1e2dedb473f07352a268f32e322013f4ac1caec9e9796843fbf014747798d3180c661dd459b583abc0c72ffa2403f583034288187c83ee4262581cfb45a1e6eff1c18333dc76a1b123518cfc9219879c90dc6413baf3b142cd965ecc06d11508dbb941cdb956c18dc67141a85ae572d5e9e7e78289497fb28733aa74b38115f72453178729f537c645adc677481290f448b568a5e7734bc7e30ed2fdb19473908e08ef89f0e4f7324e7f1c9dbb86166edac1bf0225e2ce3801a1ff61ed21c025793a38f267ec88b38328e908ff60cdcb51542c8d424ef440efdbd7eab13d3dd9c8ee930882250051dc5fdeeb70b2ac9eb2ef950bd21cbd697f544aa562c5bdc5e1dba3a89c20da006ab3577c6090257b5ab837564a2eb0faf6063c6d3c8dc238054fabd9e346ee26029deb5232d786cbcb997eb9f237288aab003a534f990912bad043603937329654630adb6c17aa52727e42b9e776e716128f077f3333990953b6d51d344adff581943dceb93a3455d0b577294bc41bec01d431489a681f505c165eef26738811023a4f2a564dd7112fdff8d491e168d15e8f3501af80b5d1e19542ba325cbacb755d2b8af9717eca17680e11b6e5bbbc04bd11a8ab82dda34442adbcf5f4268d1d0adccebda03c2d016e87eb329efce80ba8b5c80addcc018a646550acf33944ce4a8c0a3a99038ccccaa050f73980bb598976e5920d47792da8ba2a7cd5e94a0c0a583de184e8f67ebe25b5d8c4c9c1daa61cc4dd4a2529296f5dcf99226e21b98ab904fe9253dc4fe610150284f374145d57f6d9334f104b7a92c2783915f6d230b1f5a9a1bed31536ed668cea09d414b6979e37ad5864ea0e712b725889622f2d616fe61611e03ea358e44e46af0981ccf3b25a462220d52f354dedcecd5d3f03a2169f892820944e343bb2c9455ae24665a05401e39b6f7867f7a178a544c27a1c51888c447f7710021309b1bfd87fcac3a9ce0babc7d84fde08063f1a8fec58de1666fe375287476adf88e8d03a83309f524de2674618c0ed83842607ac8ddd1bdc5326ee942db97e00be6c4d95042884d9363ab6d3128274de8e879d587779b72e62bb96127844eaa1f1eabfd65292cdf32cd2ab58d76b040ed1b39d738a4f154fdd0ff34a2dc6a1cc05a078814b075386993addf53cb2284628838aead645c15605ada73443d9b002004d930980570187ca6d7f22dcdac215541e626cb6888e985c4e0487d8e2286a221a3dba8987177bbb57b52163203ce118a1ba0a546844fa000b36aace6391cc654bbc9427b45ab9a484d59b48a9a16ceb9f3a1f81479393486371a2e6703064575dce91a832a90fdd323954a60820eca2fa9b24497b94651915cdc36438809cec30630136b7514f7169a381f181c4f93c2dd854806273e69b96b74da636c1af04d7539f3d9206487aba6d63eb9d8ae9f70d8499cba1750f5d4e032e3b8593eb412a36e382715c64f066c874f6970150148bf9182abd3ad5ae846b1ed687ccda5cd9b96800ab09087052ed6927c1c444a5fbf287ace9521cf27cd561892629188c58425f26258a2ef57351e5cb1955a56500e640e0e2c6df48a5dcd24d071482bef17d1899fd9f5630b3c036568aec8d0f6169bab3b695ee320130083f9f82d6ef2201de83da92fff4a66424813cdb2031f3da18ae33a7dae28d83102a9a3f3ee06c46f1d44f83b7824e2201297183c742391ef22a5b2de7472c4a7d4c6f47b809f68723112eea94036ea46fa763d8dcde494fc82f2e0606f80e583749591a2012c1d5a04f4b26d545a89ef91098c5cc8c3ca2dc80be25d28405725a46c9d1aca405028b1073ef6d2f94ce8a7368451c9490afecad731e617e682989c002f0d1d848f63340ee072ceb5767fb370596f4c182cf6a836d63757370a8320ee74cddd8ad0cc46927e8f9e64fa6c1c4587df416f96d9798aae74089c3ec5f0d5075c18c3763dd516627cfbc9b2e8df870996cc7a99d3e5631b9c90b64589ed12f1cae303f8d52ca09da7c26865a5a6f66fff17bd45245a315f5df46e7aea209535e5e30643bbf9388dd477456aa2a00ad4951520f4d115801f0be5e62670a9ae6fbece34b9f6cf672ee60ee0ead44152a26a3fae43e9f4588daa9010d97c7e7b0bf3c0551b55029443d6c9c00135f0d7830a266522780fa1cb1b79ae7ea0e8b14f0b3592de045824b857558e5cff771bfc9ed31ffa6b159fdee0964a6b7a534b6b0b159793b1d0c9a9c9c24bce3e66eb8cfc4bce036ecec3fa88b40706299a6698f4bcda375b51ad53854a0fa537ef266b37e9f2a718818cb075aa6d7703b5cbd5458bb027c58d54ef05f187c1799177ba2f7ad38c5de65bb4ab96a161f6e46dba55fa8d2908fdecb5a622ec76821400a23fd771735cee9dbae0df327f24846f426b84857d027f7b4ce3b6d9994f29466127cf1f4eb852f1509791d416975cc5576f68b2eb0813cc6cf025f77fca11b365f6688aee19c7e856055fa5202cd01dd05447bd22088f42d0d06e808588bd35394526e023e74e1eaea32b282610c7bf4fa4fde324a374b4cde461b7709ce3560abd8592aee09afd0d3fb4efb25bd9ed5a9e2a1fbf9fdba4bef0af6d5f74db0c0dad119684f9471bb57e5bc0df284472af5bffdb98623d08c45fb29d7b905ec28e353409cd8fbfc3c5e4fede3a8f2af098c073ffe6156539dd7c65fcf1e12c3410a7b69a5a24bb20af60b6c707b49b1d4bbb89c50eaa91c077ebf3c5b5db1ddfeb78d4e993807f1a34f62e6d9a8f2e9a5307703304f2787700504a8f61b467cafe2e9c80e10e9e351242c40da681931aa1736100cb7196ee7802ed58efcdb7dd41c76a54f01c2d94b38880324dd9686a0e087aa8efc647adfb53b21cbe24ea0a625ee140d4762277ba9f4affdadb938622f6a288f3206ed7b1c76ca34e9a1bd000a2dd53a424b96558974dd1eb75991e051dcccbfa83e81a22bc40a3bbd472c7f623d0d60b2bac20c48e9aa52720def41c406505c0cd064784d4ad74339ecb926ae4736ac33d5bb5c0b0bf833f0eb4feed4409b5793b879ac4f9da3938101215fc84739c4a78e81adb26dcd612959e08f19fa68928b55d36a715156f08e084733ce8c686fef5281e8d9f97fd146aa81a5a45aee9a72c426c479f4820db4dfb9a3122447dd75a4c7f69679991247902e80793237fb42853bad956f94c7ae5f2edb4638fd7b510c6b962026e3567eb26543b35f9789aaa5002ae5f311cb1a5798d42ce1f1e9d7a4d77da7705bcced0fb37af384891a470d2a63b2886cafd7d0930148e77e1200c207264232e931cc4935afe50e61bc5f8d38c09d1d85ef1994803de4517fd0601e40dfbf91030bc49e8fb818036d03ea29bd0135d20b90ca8d39077286dc7f90851a79b598cd5d5dc711f95496864ba1418173c3f0eb74a8cc7e130896e7b99b03f705f4ff8b4fdeb26c31f59806cdcc4f09d3084044554d1b052c0691e9ba0c6c1b4bfef820ce8d3f4e81411cf9d89e47575a8247302fde9bd864c628585df5918f07b270d202a938c58d1c4f70591d6887ed0c4b07916c66c71019e86dfd08831d08593892a41db5499d17345dde2f39aacf439213882ae02dbef297dc7fbb94ccda52a80ad4d5ddccf2dc73997545b6c39b1f29a105e5e10cccc06d5ff79954632ac034cc395db74b5271e0f1184209474cb4155c88a8d409082df84124cb5ce45af10656ef70b8cd49a67c5ce923ad14983ac3ab530a710638c66434738e03299f25be424011d4e2dfa94a71b63270f9bc0db460325e402953f1517ab84eb0ab628451eb0a474d4bd8d755298d670e14699611b4ae1454a0485728536c6ee46aae4bdc678e7c2f59e23fed3a6c86f87874045d571135e438fc35bbe4a12504ac96ed4309d64ddc2d021b80eca9b2c676bf9de37164d61ed2ff9ba205fb23d285d59ad5d0632b8e0c45942c17430e20559ffa7d8d69a9a5a46ab4506d0ac0147fb1e53431788e8dbbb44e9df60394c6e47c624a28ed0c1da21f97549357b16d4c998457170f0e82628b4f1733696143322f196f7d3f978825f3a0b14478e1c94de9cd0d961e82478223a705421a3a5d47ed49a0e8a57025e6c765bbd8d2cb193acd09492e6042cde10aaa1b6024e226123908891b69ac0f24205934c1bcac72d011103744640462dac81c4ab7404de9170d629d1edd2a95801a962c4d7934f10c127abcd8c21c91217ecf666a99f4f8b9bc421d4a8832618a7a1b503557f67add8e4edb6f8155d174ae0848c8800d4e411d847ab6b084f4b49daffeb5f9c7af769a887245ea40b55bb2e3be2c643771686fc5f6ca27f4a5af6b7a091f7890d36c0ac8761e8bc047864dd09cc59abf21c638f29ee78088d75de7979b759d3800363d57fd7a01a939974a912d71d2834f8c9ca82b942d0fca5d849fa3e9cf23c12611a355fa22ff3397a44a9e86b1ca6d5281d6a67f4a7bd706a7939c17cfa753910e99b730ea713ae976c5701ecabcf3323d01c0a6fc1e85e60fc82fcd4d9b4779eb4464e9f33914289d3dc5521d1f331025d7f3d1ab5f88c2ee2ec72b274583d01fa3dadbf73d4fcbd3beb3e38fa7b962748761c07d104a4a62ac9fb2442fb691d83ada38153f65164de908146378ac870ed904ab8aa0f6f6608293dea14f68a10288766f70accaaa3d66ad4ec19ff266b4427a240bca7d17b27e74f9bbd272930f9ac40aa9ddf0ad088fe16fc3f41196c10d4563c53991a27453b4aea9d1eeb37d52fe06ac2328e6382daf5c60610638b0032159d5caec79adf47e861cb439d60c8231cf0ea05edc48382dc62a836c49c24b34a285cc5783613501101f630d5b545d679918955cec7aa40cafccf208044306029cbf03bbeb2c9b7dfe2aa3102a9dde11859c45a5daea4f2c6cfc506b9e63319cb90c4c90c58de303071196b7d363f9bc82e6c4c5882bc661b472fce6c836c3cb6952192a3fe74aa3f0e516aa24655c579e052b9b45dc74da903df117e411ce32b2c94cfcfb11249990ba9e4312fd84f8e114ba6c184ac91ea88b692d09c01401802ced0c6b2718d83c95ca4f38fd4f00c08f8b8e30f019c2799df2b953995fd32a314d6ae03395ddbc732c60c7d66f428297e5d802dec21a26d4e9881016d34ab9b28ed0012e3302c10a9902f2d70d0e6b4ff4ff8beaace306931d093f5cad0cd0a1657a5331484e71fda0bf5d5287b0424f25187a7b0514ecdf6699ec5f85147475e4993eadf79ffb8016c9e1ef16362041c063dd373590d14caf8fb191410e62c23bc4b6cb04f3105d4c70858b2a41cfa0128b3c5899822cb79d047b1687834dd053a242d1687d2854f8e9273f8ced39e82d10d9c0d10399ff4d7aaa75d8f08a38c108a80731d31b792108ac21e09396d5dcf1f9606bff035113687fcbc695ba3d19110d3e9fe9307600126e0e0000e166ce053633df90058e0337d882c84ce184cfc8b9b1c6385556258e1de4031c653609f20949136ec5d639b1da4d100bb5c48d4f42b17be11bd3559aa1146c16cd2e160d42354eb84c150c1839708c646b064e06e04d085e3261e23c9fd105ac363000bc60441416a299970701609e3b541b6e5045b107b3619c4f496a725b6112e0cd5c4d6ea1fd55f9585981df823acf7939d974c98097d9608abefff5d29fe1c88519b20c652780b632683313624f1f36ef5575cdf6dab54cf6afa1b1301d5c0f8c0bc2196142b04c115748494c20d2c702d84c80d51c4560d0aa5f7b1bb10deba8833a06540f547582209eb3643c356a914661d811667cf2aef048b29ddb45a09a8eb2e6e12968b9bcf40d8bae67d89df437d41a0d063d912dafd639fb7c393fbb0bbcaf1720c09821c9316f36a36d0f0a663bb546dd98e51dd4ed65cbf240064737662d252742b994fcef1bac11060e9b1c290b8570915c623ffd5506cbf02b1e8671323ee0d7b0764d906442a240c7e6bbc147dde0c391e2147dc9cc9a916006d545daa04109458fd3e39803a85ef6ecb8b98982f7d3cd52cb34b0aafea94c562ce26e04b53006a7ad2f0c1937eb7d065eef0fcad34ff6ae80dce7c0e72cf471d69565fe5eebe158a1e95d8d6160abc4782328e5e9ca8438aaf43843dd70690b44f02e5bc894cecdcf8c4dcaffd72dc6287285aba75e03adccd9ccfea2782c302f64be619a09af731410f72614b85407f9bc9f1ac5728f8a38c8fa30bc1f33bc05476c1d4355e235f9b198760f0174120c32e400ea5a9bae1044194e79f42bc9dc6282d2e8e503f4afff1d222d027d2e80386c9521a4737d9f19d5857926cd8f45f99b84e3d5ac10883664f674bfd5d3bed864f302e2e503f3b038ae0974c2707c42fef15a8ac56aaef21b2cbcfa5658b2aef3ba27c27df53e9742cefbc741f42f3c644318201bae7540184792af7e95e87f6b27a94631543330ffb8cc2a062a366a7ade77c166490ae2e0206073933d7ec2a9dbf4e15be9e5a5a9ccab5d2c6cccfdc984f89970ed49577a9669247fde50920b31aaea972d25a7849b893cf16a0ef41b7c8977a2aa18e7588bb5242327db9008d12f5a2a593e14616c0a634fe6731741c04ace10c3754acdc06faa11d3a61381fcfdca365e41eaa37f516550589e91fb1fa34a7f591fc42270d1f85d3e69f297d5a76795436ecf6e9a8968ec686b575e703e3ea8fe10164f7bf587dc96c6f50a4a71efc3c9e070b0e98ef6a8c512edc3071ebe8d16fd89781ae45e010cf24eee2958dc61fa5c30699af775235f552f849676978bfbee5c752242596185527380f1cd40e18c5bef5e599aa335ee04d6c77ddaec1fdc1217c5c127374b3b69c139fa19b83c7998edb182dda062e757e5be1a2b6cb6d36b44968cf1dca232a3658fd299216342724067762365cff57e14bc4d6470e5cc75ec7a09fbaa49be4dd76f3f9626dd92b3755a2d11eae9089a8733630ab481a9e3d461943bbf1bcb5dc750292c1b5ec0f6113bfc9baa8d258a6c03bd29536f62691fa4a200ca6e24767e9dd9b1ad5aca15a251c57f7d615d0ebc2a8943d256095a28835d16ad3d6e60f26411beadd4ce208558abdd529f4c7ef29ac36f8e0726e5050ab329d6b041ee84db56cd83b9b95191aeaeb2a3592edf681721d5c45f001295e8a89e9446e78ddbe23f5f15bfbfdf1df1bf63dbeeb431c906279563457126b2a7481c6b7ba0fb4f8d8e30ebeb88e82f2b350d47f1bd243cb4bbe416b786ef6d193922cd16c5548f5b3b2d5acb3245019201f383d3047974cbc8f3160fa7e107f0cd0177ea67a79ffffd0e25e42138a03e0924702976104cca260c79f78c17a53800b2ca0c6603f2841649a411ceb6adabd228ea97622a2c3ad195cf9e8c029d218e3f3731bd741c018807db42b59a44885b40772b0488cfb0f3712803bec5f1afee58f6237aa9904c4abfdd09d24c22889d924754512b6e435b4ec22753ac1fbcbc8692001bbf386268436ba12afc57710584f4420e4dbc04a2716c5adf49a14a1dbe201107b737c88a07b91b0ceabdcdd53676d5104c3203a71eb93ba402e26a8764bb4bf069d957c795c62751614a91dd2003fc8f5b0af86174049e2867867c0ac114f1e40ade705abcdfc8e4e1458719d1e199c2f184527313cb0da23ec01afa53a2006f37ccaa3d50acfd8e8416aa705d49e058b2b82da0d7bcb3e0420c824d8136306e6b0301e501f00987c21c1b9173ab946e931638c9d56a794cc0b3351da7a604ef8d4b9bc3e8c2a1b004cbd60f58f72b0163e43b16a9b00e6eef7b3c3fd2b886ace554ee41ed11e31fb3816d1ab1a07165855057baaf5aa13f38d629f88b5d0901eca002e4d80357814a437357e0468924dae70ac5293bc734790a18c7910041f99a8efd39f673198574bed10744bfbc0ea5471f8c1efffb4556db3fb618d91d041eeb057f1d436456205315eb75469365dcfe1fdc22009c15d8515306c4fa61db008c9ffd70aebe56504c6c38c8414f00ff9a0084ae8f928824609b259beda0bad48d33b408adc1a10a51175919fbcbbe057ce4041c7be2c0bcaf9d772ae05b48523a962cb06070210d94a0b2822f3fb030e21a08226702a2870a9cc637f8c2b26660cb699dec04f55ae4b8814a27825f01dd3e8134d082f07371799664842184afea0442f00927eb038ad4018e760c4f0b746e19d21ef70a8400d8fc89230e151207de4e0c7d5b32fee2f775c3063238dc205b52c208a860d296bbcc2d67d03eab7e588b25f271c87e37a6bea86e05026acee08d694655c62f6c043209a868c632602271383ea3e6952b08c0ce28ec010f2d62ea4de050004451e460cd4c4121cc09caf28ecffb41d74ff0bd3ee48ea25d71748504112df0bc35a1d6e9d9382c069e63c60d88289e837638596f57fa22da3e7ce906fb85202efef24356e0ad964f6b0be5b2452678af4e6fea45d28b4f8e138c77d1f4321ede96b3bd0f21223a1520d7b74b1ac60c4d1cdde05d054e47f8e01d2e44d0e8ce86ae1bcc030af4d554eafca9cb325fb2af676aa3d125db7b4c5571daf742bc7f80be3b8ca1474324332a4db35cbf6ccc7bfef3a1a7c51a38bd02f494230ff4baf7a6693f9aedb5bd1ea6f80d9ce8a17b35f51b079bff1e76291297ac81bd95aa39a708940fd4ec86f2afbb97b4dcb4baecb008dfeabf9ca52f1b4dda758fe388ac68f6589f2b6dad34554db2b74860ec5526bed67b95dbdf3e8ff87a953c324a24efa7870cf3d73025020270207bf7c4be9bc8a09e3130473def0563ea4353304c5d4c3383458a0100fddca114f74e378fa06145f5faec7c772e9fb9c1e78cef7cfff22e844b02ae7457b07691fa49cd106e03b1b42956ffb91929e3d0f00f2e2dd6ed5db63974e18ae3cd459d9268d4e20bc9edfa95124920783bb1d06c5d35c8191e6d455ff0a3a90d309c7c25c9af449d5ba745fa10609621a9817393973bf4b4ea75958faa39eb0715c35a2a3de6d6976a82a841ef45afdc1f24b06a6003e0b3a7da9e5c1b87f054aa09efbad578037dbdfdd7d2133abe925be59f9e7fd683be7362ca46e37923f00bc8768110ad85c387c76ecebd8875e97ec47421e6093631d09ba734fecceb8af3614fe20eb778d06cf6bf4ec1bc1f02dd391ce80fa96cd7877c0f501bdccfe8487ebc87788acc1445bd3204323f871f3fe0a28f130fdce254200b3f1a36d71a1b6147143f4a430517688f82f7f4e40fbe7bd29f864964b3017ffed1bf2f69766afc7aa372dea1c021aacb624dc06b12227e0cf1600802573ffa4e113e27fc16569bce7616da9da64681e4acf896d45eab051c55cb3de88c2cb8e9d6282e5dee3fd25c88caf75eaaed1ffe75a7682d4b3558aad1a1520d7dea7ec1c1b879e099c0e5a185628abdc28035ff34867a855011efba09fe7ec1e080aa2ffd5d9f194a16552e7c57a9605076d50b79975130283755b4f25df301368536e93dd48669b2aa2e80a990952cf42a7ac1366c946a5bdd02671a495eda21a8dd1bd54c67042028a4ffdd5ec2e3a2d943d0cc8cf2cda0d608090898c939a828457a5ca01774cb12a1963c265f8777caa62b39042c8176de6d63ca2903c0b6982f45375a44f85fd942077aaa7564584259b29ace640b53609d67e0306e757699d01b30ddc2cbb6323427db79cd07c9dd2fa0ec56820e00d1012a2953ebaa1e751ddd44e378c2ce97cc6281162e64a8be58d6c59ff8bb73e862a6be3165103c5c1a845825b93f1921ab432ab021d3e095307f8b836ae77ad62e8d090134a48f2b3edb08f891c2c8ac3ce18492006d6e84cb725f1164b5827fd6caace9b0150f1462d25939f0e075439df17b71f53bb5036e0ff77547a3ac59f3da65ebfb673b8662e88a2722511fbcca8e191896f5804562b1b7e383952858b71ade6407b42ff952f9d7cc09411e84b1f2ab9a3c634cfd258366146ef8a883208307b6091aa6de65c7f5607b780093bb429429694e34ee6fb8bf64b1ab45274a1bd1b5a11615b20a4b3c175cdec3a376f4c04bdd7213b9ebfd14192fa8cdcbd7a3ea0d67c706d650558684fbc0284ad0d5566a75b2b315ade236f36c82709b561e59ffa63f6808137d157fa0ae4754ad479947fd47510a4972bbc5523b73c47b8f505d24eb84e77856cade1702aef08b9d115b99f1246d271f1a2abcfc6c0af38b51a7779c500d74353352c98e825e3c710b8c5ec26940e8ed90de734da7abe28fd5b132874c107198c9decee9626a57083a30d822218f9b781c3395761b903be931b19132748c4372b1ccdc487d56629fd775baa481a7aed10005d5b1f63a023854295e80dbeee46a99df02216fb6a22142622d363292953843f5c5eaca138205bd5a4654c37bac8865ba2584b4b79ecbcf456b6132120425d71650c2324532b982a988e5361c95e114dbf0a8897a312296fbdbd10762e466e0c8f45623356ee903c45420ba12d390ab8780f76c14b08c64839bdf1f9caea41756170bc82022834ffff51cb1fda1e00942a8dce1ecabfb7bfb4785795e5c05f4f1d1a9a144e404683d85653b758200b984a151aa9339324d48b5c3dd1588bab30e335e9cc0bddc6f27f226ec17aa8e9b92cf9ce5999b46ed016f40124f8ae8aef2b85f93ba8cccefb7b1e7742967abc134e5774fff2477b997b570d74571037b490ccdd4d1110ff28401731b2ffb680d28f80a0606ad8aee68c7d3c60ae79a015d5a1aae5df92c74f45211a1fc8070411e78df07ed0e9c27f4e98f9833df9d906d7f2f150391639cef8a3994f0e968096395d9f00e1a2f4f358bbe7ed22d657ea8fd9da9c5edf21440480b606840ded9be0b0d5a4db98dd9d650381c2f1147fffda3d51e13c124e4dae72d5b59c9f4456148e026157f4516f95dc1261488878fabfe755a65c644f11b78018bbbc429fe1a79d861051fe5aa38fd7fec7e653e1728cf6ce847b8643c770853f19741fca90de277315a9a23ea1843d6c44aba2b46d67de4fa5ec1b037fe37d59586305b1835ec0414f4f1c867778154831f8311806b2b0d29923e96a77d19284fbf5518976084b19f54ffde40508fc8a4ea41f27d6817defe93125e9d3035ad687f8f460b5b9dd0616885a4eb540f02792f93b2cf547646315633c8427b9b80401b807da220a671fe0aa22da59bac88d90a7e8a513c9f809e80c84338faeb66b52ea111be9daea01168c49af7fd67691055f1ab15c384d0104715430f32ba7ce080f5bfa05509a95d0328738b1dfd9dc6771515c19a3f4db04f9a24911081e722198753a510133a3c05ce5e30ba983ea7585905940c8202938bc0c6835127306b394f6fcf1e5836b1d9d6eba112badd6f08db63c7a706932098e312f4f200695bad3751011e8b5dfe0053fae8ff2d5c354f62ddae0bfe2158813dfbd4029c2f5fceb959824e2c7ab18f513e7f293a023c162119761e2cc1520075b2f7be552faaa70c1bd6318f3bd6cb6fa64224671ed6acdcb2e996661373b44f065350d0a2e56fea12bc6cfe326ccc1b64513f117fa47e0ca8c583eb25bac76dd47801cafa753f195dd99408ea4dc582564b228fc505ad6cadb22bd22fb5ad412163039aaafebbf07b00c8798034aa81159635892c737653b082b9d2a723dcd4b5260f0d43c41df65bef89c507b2fc3764eaae98e0bf6000cb36f503c8a584d84b7d8c42eff3d05d8331a3126846b390f198d249139448f86f07e50dba15ca7ea3a86622f4408d191cf0dc4f854fd1b52c50c5128c41ee071e37f714eddd1450a64ff8fc6988dbc3b848c4a8684d02b12d87e0d0d3185344e053c89f974a4694c47d54d76cc352d74f86502ff871974f3bbfc27cfc3aa303161ee9a84880953b275a7a759cb7ec9155ede82be28c3f182dd9cdbdf315969d52b6eeefa3a27336c255951e4ebf8556a04b4322eb431a3afc0ccd49508551c24d43a7e1f3895aa0d8e9d72c15da0f8103dfa1f9fb1bedf88d1bc1d7d3f34bcda9f41e26d44b864cc0c2895525f362cd7257d11aae8680d33f56cc98adc548b47bba82430f7d01bd0a50ad9bc9d586eee2ef3620f95f3f37d7e8cac4ccdc17f7e91486dd5018ad3f2257dc475594eb5e8dce5c5408195d052b4d92fae966fafd851e458143ba19bc4e5d9cd3ccd3fc89894b62d96e0de96b8000b760de82d7733c8bfa25f4f5ae0373cf9f8eb2fea7903be204931727066744d0f933e2b24a5e48c262367379d49000b65c968560233a851a4208bf2f89a2d7e11a37478f588c26a1072a446c2d7f46e6700aed9cb9a358505b60d88963dced832ef99dd989eb43cb4a5a69b00b49e02e00a618c63349140041a62acdea08c18c214f9dce10243d69850e5eacefeeca4e4f87396b6aac652b748d72064faa23c275d668c018a685b44e12637cc7f90c2ad8f3236c70ade26fc4310d4435d7514bc708e1e54757325d7d8aca953c0b6a7b2eac1e91152480bd3d3943dd95f636483302483fa22c4e691279907af25fcc833e1688731da7a85a8bcf2c7090a236b755cbb7085f446214e6b36c02d1b9a228769ec69b85f69f8a525e90a7f9b94aeb73d7834b2cf0f84fcc801078361d228138ac043d59e54c240c269d16584950f60a08ff46ccbb1b128cce20305d8a334d2a4a65b3e6d6e646a90c0d4c4abd7f5516f0c0f5fbd7caf1435063799d972904554fff0f5c7aa9ea8127fae8be4b3c112bd8a34ffb2547310d00466f706e10f1cc4b050260d320d1bda3f8124149a0a96243261a6cf78196aab0f7b08b536c16eb65ae7c7f97ada7c938aedd41a0d52b06224b348f505606e53179a1dd9bc540fecff4032f7d7102ec0fe345bcd7229611654587ed28f09bbb5dc032aa1526347af6eae3d9aeac9835213132ea3e3e71b86100aab66b817c7cf7b921560b354514aab3ebed138d8180fc004557a97be9015ac00ed49c3437f9019daef2e95cdc99133519b845ddaec5a02cc0d6e994ad5b33d50d393f0fe505808140852e8a6af9ebfd1db2d8f074ad29180305f87083f9e3fb77ededa663ae9531ce44074bea3e3bdf23d635a0102a5df6415caf4e1d780e3f2f2c0c1ff3494a1102458aa9c58979b554c3a71471f4d0d80c408468633d02c7f645716aa5d1959f1aaa51fbd377584f0daa34f2c6415bae4c2ed42a748b78f5ebc08a905a8a6ea5d1d7d791f236dd456cf52c8d30bd136435afa94df4689094ba1663622d6f737c1ac5202b315143175a7b26ba1dcdbb276246d10659255848206d10a3d87664fb557821a1515b368efe5b2263500d8895464677d7864e4d51b0d3a26821d214f94fb027aad69b1b35159600de727f7846f7a2ff3993d9386b56fa38a8cda76d909d45686216d8535e544bb8d3e6e9597d12ea42db5481b8b925e322359f1717dd83a2d6cebe47a94ad52e3ad9d322c69487e8b444020eb8f3a96e1daddef17b5ae478711141b3120c994371518ac72f9dd302e1395c5ee75b641eb05ec81b84e74d0829c202616050fe320d6f31d53b0fc9969912cc9c205a17fbb0c502e1245f91bfa91d0b0a1b0b042a2049240c6f0356f88fdf56efd83f4b32155d66943f92a8f5d1383a159f3ee1482232f1da96e83c77deec7e7947fa771f9596029c118dde3f9f76b3fe12ff52c5adca917cd59a9b95577e3e132750644803baa609ed0cc25122a20c14531d5cae26ff8c9c0b2a0772401563d5218725924e8b27a081814dc80bbc88a414d2546cd768fc937e857224e3b7d00fb22d82c788bd8998b8f79877c225ee130bcd6fd231fe95bdb48c883332a4284ae83483b2f83299de1780da1abcf41c8884d21667371b046eb4e98109b23eaf2715fbc2d206ff444fa664609340c28131627d622484d4f2824d9eb0534f63706043f1f03f66969121c524c269ee5c3f1970a86f61cec1e69d561c6add3182a252d333924c06ed692e22988e9adc9253e19f8ccc2ac2416c1f0fc947435083d20bb44f3572388405a1335403245a03249bf73b5419100278f563b92674a81462ee0251e942f60671bcf733733064733606070cd9b69ce6f35b785c480c341841251c33e2379a75c6e4fda1d91964c53fb1a1b68bddccee1f266e2c5394385d9c4baf082a281d304863410c3ef16cdcd45f20a6479df3f1bac6024e42a10316e1e58f14fdf56c274fb99fc20f0c1129d9a8670534cb271cadfc0fef4a7ee4eb1fe46e50ff4730050d689249336a46572156d09922a23b5fc30d2f1469d9dd9d33080455665b330d9a9f71bc7a7eb21bb191aa3f3eefd0537754dcde2d0ec4a33fdc75cbefedac2190d502db251bdcdc9b73dcbf9e76a54fe4cbfb707691c92bb2681fd5ef0c22899335eff3d41b0c0463f25dbd0faadfc31258de222b7d70570bc73bf828aee036cb2ac783ad29076daeabfe694ae8812aaa522db506ce3da6debb5b78ddcf357cb72ac488b47b517edb7acc80f8cce616d4c4c25b125e6a21ee741d2ade25fe7837e475a32669b30400c560c3f0cc412a78052f5f82d1d1eb1bdf5eda234ab55f26c7ec586f93c95154039e4eb248f0d8e3b72e1cf5ba208d01a4305c929d8b6b420a9a64542a39442cbb2990856e9e8b61669bf196eb528f9cb8ceb1a7d17021dd34eb15b9541e290609c44e436b99faa512b6cf606f6225e6ffab94db941818f03106f200d426ded1512a1d6b8d814337e8c636ed341e813e5507de6fb8e7508c9e2f8290de405734b3af784298853d9b07cbf098f32f153c70db2a14464c4854aadc45641c744f322d0a4d02bf608d7469fc88e0585acd1b3691f2887cc02840f8217016e9cc87bc205c113a689cbc641b8ce797c32153de0ec7ad75a0e89f251fbd415fcebf7e88a39166ed834e141c34dc861e06c3447484f8f51fbe67cf46a80a6e73a4301504aa7872ab32139d9536a9c1f8e0c584121b2e200f30ea6739813f008904035976f26bbad8af4e090258cdc7aefdf712b207ad71de30c07d127bdc8dd9cf713ef009834628a1c57d510209122f0e2f41199e01a6543e58d6416e8c49f768ffe8223ec834de81bfab71db97c01922025bcb7e1cd3fea60e752d25b4879cbbbe5a6dfa00e32adbc043da5c62a6c1e810f7072d7b42877a81e354b6b4bf13e65ecc804e507b41eacfce632feab55774216b9bdd40445eaf151c457a924e5449daa02640dcff2699c13bf9a96901c0c84c82e1224976475619999179a253f823a06ca6b8fe11f9445d4c995a7e82bede49db3422cbe2bf9c7e81154f07767b193a41908f079432d409f8ccfc964a49d9fda188de07244aa9627807332a6b99bce9e95f700553fbabb053a09f11ab3c1d073c6ae4f4b2da197e6a1754d0381bd9a5d4d4fe45b3d555d4012089aeb442fcf05b978c65f8aeddc6d82a879cc2cd24a7d5aa45742f635be976874fcfb62aa4ede08b7a27b75a3b1768bca69e8fcb1683fb083e069a48e369840199025b737408d365c45645e40f6bf8a3f39d09c758743ba5dc4916431758d7b468d451686402d9a81a6a602c18911732069ab8b2f22d0988bf0ba9a33f728cf3112abff76aea06e2ec4b744bed12d1e50b099583c89aa5941c38c4203a54ff10903cec4f18aa84884402f82cdb473283f91bc5e60f7bd319db11ffc74c4bd3e31b6149be4d12309420e967814f4fb3f5daab019a58ecf89244bbdc20b131c2468e7dfa2a33f7436eff65a8ca751bd3dad736ff04ad0e9fd8ca6dcce3d46c9ac185d7cf8cfb397c4888f043f2cc48260a190bf1e5a6d75ecf5b3f5a31e5b67a34fde1297a8ea7a3a9644d79b98ba856e2d9a9f3e9f62a1f144b022f995242a243cea676e0c1e20553c7af32bc847d0a4376811d688a8effd19f15deef6473dad972884460fab3a1454f4bc82305e80261fb92752baf4971dd19b49de6082e32602183902ad2975d63885a2a40010114a8c999fcc934724e7ec68117872c18c60e60d9e3a15911537a47b5520ea6a1915d0f2b73583ec805bbff55a38422c85d2c1f70951cb793b76412a8390f1478c98e24ee1861bbe9a48907143972a0a85f48e6ce0bb729f4647429869ff33003f649638e700988613419a95e5f48f4e553e8b811e79001c0bbc73c2d291beef22c48a3ba271c604d55a5874fc1b98ebc42f029c04f3d6b6a7223bd2a50bcbb470c6c7541f50c69de850413ba77a7fcd6cf539371277d38b4ef6374aac44e46658e3aca566394ff7e2733e6b6656cb025b71bd694d236a0516e7b3dc12dcde00696df3eca092fbbe3123b9747c93eb179d925bf536ae37c009f6e021281fb2303a168d2115686ee366004201ed70e2405af6d00ee2b0c1065118684297e24119130ae6df79671a71e5e101264114c407e157f3a7e30bfe2a89b4ae619ca3e10de20c843316111df289d508400d1d550fcaf2501da33bb43adce25c7154c4a843c582c29b0dbb9a863c35a94651acb822edd59b1f8bd09ed5778880374cf56999150e204ad46f7f4ee903d6f548dbe00177afbaacb8255664bfcf4c9d12148bbe14fd65070bfde24b1f1434facc9fae1593faccf316e5d3f75693fe51620a249db1f6e191ef0eef924980e94fecbc6a32f9f66f3cf510d66d8b0e531876799eda5d40eca97e9858e2637d258805de1e43b69f0ada8d46a29eccf0da07e517624705d085cc35da3a92d6d489d04af97e2d748793a19fead36dc40124763b8469520b36e9c6d8fd9186d24e6acc52bb791c25e8be971989ba84408437b0a2f0577fd27ecfdb38af4e67f9144e27e6f9aff7f9e282f0b5188014976934a655a1e2307b2edc3d81e74a8fcfe617279e6bb0a3e8526856270efbf2a781b0dd96e3a1d471bc4519c60109e5d216250dbf9905e7537eaf9acf8f71afa86535e08e511179f3ba0024e2305921d855d9295dd3df55ea384f678a55da3779a00d31d262434f2f4b682a33d0c319472dbf56e9abebfedcffb06233e689f9d0f014f0e885bb767a2b8536fb5d85a92b924e01c2cfca852212bd0bddb1ae3528b3c4175a02c590e484bbc8467e500cf6051a0bcbb315f0902cca3f4942a33e2a026a522234fbe3ca064d539d617da5ff1f1a59f15ea18a386159ea1d4668c93d58f45a4185b57ac191adea4ccd4f4378516276c84ecc59395461e0b740e6fb4325384a04a50f48fcd15dd1f69e0244851dba66db4120e14a3b3089281b13433f57abe60137e0c9fc6c52043f9bd76b90086aeb4dbe7b850b750b6bb53ba8e1e71a052b7f08da5b816b91d9122a9abbf2da561d5f3e6209f26915f60c1190af367478b2fe33735775bace397878f302c3742ace2dcee927901cb09d1123cb7372f419ba7970809ea25c6979607d37d402e64485843c47cbf5c952185f33be943d0701a9d7a0a1b3a665bf9570d3d4c7d372f5bc9443714dec33ecc847a1da94dd54bfb9ca4be2c1f195122d0cc042de68739e9fcfe2d045770800829006da2e1041b09f8fb11f577f10297a6bf55584f48dc777ce34a415d1d01f0e264499a0880634f5b1aee639208017038c4765b6a0da523c217d4a6b3bc59fb99818dc5d73f576583fe6fd6300af76371115c07fe007808732198eab5e66190cfcebb22340e64d1bcb555bb2ad0305a2e6f97535d1b7bc2149895044d2332714a09289a698849876ef651b181bd3a42b7b20c7a4c72fb65a8b933458822c85b141234d1f591489a4a7ab9e3c0b4312257ac29eec498ced58894ed8b4e11fabfd5339dfd9e952de5e7de42234654438f3a2830ae8a3029db266f50420b654a228e1c4bbf38fe863bc6d98402760eda3f949441387086947b15b05aecd7a24c33bf2d24e57e5db58bf89c1820ba54cd73919c28fa28246ce977178f818903f31c585e8490f09c483fcb962dd9c4c7203472f7664b1e6892e3b12b7ee06cc9bb18e0b53ad2ece96bbb9eab356cb3dfcf8ac35aed3b0dad5ade14a34c80c53218ccffb769bae236dd8d1199c7ec7511a493615f3e6b4d68f9aea112b5f97e437714dc555f03b084070c744a9b8316e3f2c1d5615de61a7f219559cc7fe17d58206ed80ea9b57340be35960c2c50b25d6ac1c35f579fb2b506c91a8acf130b7db23626b4c2a3ef959e7d691d5c9eba7de5ba65bf4f0cac19165365ea57e921e6ac30fb1fa381667f2d526a38667cdc94155b1f994fdc6662b2a4f3e11b1a4a4e256e819e3afa069824df70a003e161ea426e868b7f49fff155ef02531b13d39907bc000dbc72806374a8ee4e6838baeb39f4aeab34645e838cbef0189c5f97c6f68305b59f2dc7f4e126141ee36b9eee6da581df7a7f840b92b9c171c6e11747f8f2ec31799debd884c75856865c5ef7f75cfd9eb31ec7af0df66a1857eaea47f80973c025c4e456a0845bb004e87370bd76dc530b8de7dd85c862bccd7e730aa94ee87f5c825e93faf2b1d9a4e1dda35079a6b6a763748735cfa19057d94b664c46438d3c5899520d9c6d3e17734840724376ec7809e4270fe686803ea53b143789f9f21fe6aada26aaa3e136c23167a7027a04a9daafc6e7b62a1b07d2bc08d12781e5f83f6cda491f5aa31c23dba13f6273a97b6f780955dcc43d8dc6d23279c337d3562bd250d61b168969b1ecd1f2f90add949a96345c541bcdf1ed967a3b381dcbdfbc336d8dd35f14aed206300f5eb50e65be2a77c1c38b791e6e0839452ba0805231b5df19166df0b99e2e5f8ed5857429e433864ddb549f1725e9110ab1e0737a62ab476d153bf3174d3d2505f1567d2b5b0ea20dfa332893dec5881655ebe236b199de5ab4f412f92d192b0e352a4c211b0f23c2a17a8300c947fb2404fd65db5fd68173b43c99077bfe45bed7c7736b3943017a314369fe560322ec9210c1ee710fb3f8bc597b6819a64858b49f503174eb37065ee96a684ab58dcb7ce4562c80d2c20c78ec256431fa245c30981911ffeb78d659312172e73d17f4397c0a83167f1ee526cd5d12d2d48ffde9d94803956597a386eac8d66c4389797f7f93c53f5d9f4c7c71dc2693aba15d5b95d0ad4816e4304f1c6439b59cadca720fa365ca897bd73a4e133653d93332a110ca1d68b58dc98d26561b362c11dbcec605de270e6889f95b4efa159b8b1edf8982c2661eb11c77a2d1a0380a85fe761d053c8a894028374fe60094cd18a869d87f9903b81824596ef0f920871bb9e1a60c7ee860beb741a1d36b189dadc644bd0a0f95cde7c45e51023580f81e4245cbfc28b23968da0937696ba007e8cf7e404173e6882d027af461ce72092301dc90e71123dc5c70d24299de0cf7b26d3b38a36c6adf0a165f0653bea90f8ceb27e02a43cd541ca43371cf6308bc1b9d8bcc0b2f7889aabeaf138a610a6833a8245fdffdd656418d0327f5c322a3425b6a5c2e1fe1a8189e90e3f02ebf9a77f348b03a6235eef5443e8942df8d3f63ea33afc37d2784167613abea4fb1465e8aaab51f71c51d35cd726a5d5117784c314695aebccf967bd185747154ce9557b457969f490deca1a805117365c47f75a3e4cab87bd1b00064ce7c2d975f9768a545bf77691152c4aa4bb6bfee0eddd98e790d7ba913738e99726cf2f09b8495e3531cded6d96d5119f5da971579f4dda5102c27e563d174d0f12a098139f7c469a135f4b790f350c4036fb67e6224cdcccfb2e9ff1a41f939cc68dc4c0b24070c92a7b8c42a2ab216107c94e621a2c74d3059e3409403ca2c737acbb0d29fefc69c9ff99e06a12ad9888928e4a2a353855d4e171f0b3816973812edbc6f7cceb6ec2a63628dcb2409d5fc385c40e9e01dd1ba6b10935222e416665957baa754260ded401f2c0e11b69cd174799a2c5090358413fdc14ddc0bac60219001fa97322f5b1bbad5a7e1caa8220fec2b222bcf1aefd143e52ed8b353152322891fd153c8d8b6bc8d7e45e49dc89f0df7de23110fcd8b99b28f4edd1497b5d679c769f0fa8bd3b8cb92a035d6788d1dc8ff7f72454812fa6219192a4818b7420e2361e0caf4493aa2bc1b751847d818a08e3f59b29940cbba99a4e6fce60252c70bed88724dee30da6ebd9c4795076d17fc94e8f61a62d300867ef4a76cfe433c1087e66a4a1bbb81d1ad209b579c442db285c11a1e89c66604012f0f6e7e142b5942a5b40909b38805d1b3c762327012a89444cfd78000201753625c86f108f5d180218827ccc1e6bdd402fa96e80a32bfb2b720b85ddb168384d38b36bdb31044fc9119dda0482bf2a575878d8989e3f4a1dc93b693c754cc5b27e065bdca5deb7c254f83b21fcbe680f0e817bd9a800c7c150603f59acbf7aa5c76a3c7f0053cc7889868dc4aa5d54fa216067671fefc11fa04511ab513d65f2db00605248b974250806022f163d1e3bf385a80ed5d2c60a8f2814662a1300adf85ca39dfbba1771ab2b3e534fee7e51129b90cf92fce697219cb7e20a06371a09d1f64e21f54c2537a3c5a0f3ed5398429db3d1591f8c7a66a4a2502bf4d0702a24db41e9df2deeda38fc0101d5eb3654f75c474afab54e8296b60087598967c1bb8a0db4056163b4403ce6dfb68e721f6db933e606d9effba251e7d056513117031906aa79307857c029ccd87c719b32a80afe7c8e2ecf5e2f60a729f28e230cd75a377a641bacbc2221f397c9fb62b9632806e7e33db7a5e5e3ef7d96ba2b3980dca335ff4a50cf36b51c8c90ab8208ae8359d18a71e7bb190ea7fb40594252ffc1c2b1d6b86840725eeaef5da16ec0cc337888ec628e9bf8f1f5c5b381bf2a267c11bf6c634f1be8115b8d6be52ca1618e5906942fbb6a682e4171d849af3c973d414a26ea3d87c23999bb80619bed6c4d5a2906b80fbe8a41af1127b2034ca403e109b7453c73ab467fc7e472f2f6aed293c96f3f1b32fd713b298e060781d8b564541be9c5c79d1475835006174b448490bd65fd0fb1ae60d0ae4633d5cd17a4d0d44d5492394478b9bc9c9650cf4698cf795f64fd40f035d1b72d30762f245c1c8be85f76981758001a1b160a56a812d5df257a297b7e12d084440a8f111bdfbd081a1e320a2e3f0a9f099d032304f77f58d13991b8c6b8ff822977b20c66910606412b7c5d5e8978b2d5b75f7295524db7679b4331c5827f0f81692cb710e20c7f3e20e754b34118defe53fbea9c3a0a65134387bf3cc9810a6ac7b3b3b15f1c8e88e1d068cbcba076324d732c9f6ecfdedf19214f41f85a78039f63da2447e1a9e35a0d8cbd2819cb6ac6b46ad11fe87aeb2641e9814386dde74ee5667180c26371843b569c1103c13b119397a269318f1502761a5ae0c3fc89299a914d3faae9fc95c38e1a5b7ce9083a4fa5bffb963b2770b900e90d587096a9d33981b179291c9af15036b1f9d385c6c85980cf9580c7b898534d88c16ecf5ea245ca0587959c2fc791376a38abb575a8b9b05cc155ce4572d474d35e323942ed289403210f45396309878a57b54065877f3aaa59758924373b47ee929b0830ab75c6fd1fd855e3a4321afbce4b84d15e2f71f01ec0c1610b53b7b3460988a6d9534da8c385188d57c88973db4d5eb8e2007b00f53ca35ecf0ad19cf7bdad3b2aa68cd03fe58737a6cfd2c8b370a70e9d4b433953ad1040def61a9caf1367f02698c694b840df28e078a0a4f581886121f860fbef28995036edc9e4b9cb8ea3f83811f9c8ec5a28252cb80d7e3cced9c82389e410c36002ecf25842cc523a58f7d046c2092c63006d8205537e3aeda22ecf2f4c479226cadd47aadd4985ebcc11e1129845d53fa3023800b358ce38257275ab3c8095ad61f6aefd20ce441560804247c8a7d73591cb1412b22952a29bd18485a0058b9742f6feccfb86de074f1d19f498a16b65ed6cba8210787ca0b3a9201cf8de5541bd599a62d519a33c32c0f7fbf329578322c6ecbde3b92d1be8241e2146d691d29e970832189746f968ac3bd79ce43a5c5558b3a42a743f3127a329c90389fcfc22d60777210f3ab6be73ef8cdfc5ee4b8a90f026b4d2b462446ab5dcf9aa05e37f1e24b47aecb77b63541228f78115283a615d40c8ac4a9d51dcfb567945cb12bd9ce47d1a0e05781d9d351ce863065d12f7096ba11d5133a0f119f930d5f15ed14fbc152a24f5e9b10ec10a1165e3b747c7ff5de5c21603d24676c3f9ffed4048ebd002e5f5427f5e40912f5799587348ca28512a2e4ab012dc66d7ab9221a55a8aa12c977ede77e96f7c0a01aa21c0c9c937e13d8e4466adccc35b4525ff01ac17669a98e31cecf9df6bc825b68b86a27c922104f28c0cbf1a6fd312577ba7f27aa1e1ed80621cfae46ec385706a295bde402cdcb8c0c6247b6f81b1d4cf222908218cf8fa275b4ce29dce03e956052bd1b3a4ae1061095015079d2fbb5c8cbc3be96041e4b60a5a019c8d71a2402301e86d0f5c67190bbd013ea90d94dc4e297211be06015864ba75001be8cfbe78bdc2f73a12279798fd56f9ee918e2f3e65b8cf84208160cd3c113446f2a6894c5136dc033353e9a87b38fd160392cf724a5b591ce8818824415d6bc50b40643d2f61541ecdff9e62e46085683614d9849c3aa6b02ead05f8b7c001b409d1da3ca7954f1acb8281bf3f53f62e7e2ea324247941a97063a2588578ede81f46ce3f59e7e44ce42ee6dad846c8216d000ba5c0a711828bad9fd60ed399fd703c8e9f2f1cf7380807fa462187080b71658cd17c653b152c22cc1bda870e98d68996194894d0867fc7f57a9abcd496cd36b19fe0dd1c54300a55d5451d5b67ea969735de4fd6fc3f06ad07a307ece0074b0d80bcbfafb30a8656a9965ab4c2d8f911430b11472ee5ef1b3a2c053e48db3e82f1d4139aff10d56d5a8d46de6f3e960a806d7202375a272ee99114935c15bbf286a875a28eff62b3f3bec83b765d03e5c8d01eaf1853a380226b842dd18c453ee0720c9a70b1b53a681200b232bea0d2d4db5a1ffe3c65ab15200c8d6bd963422bca72f4541397575b8d61c291b2e4ea95c3784e75c663ecbc073720efd1e8556112c3a9ab2871c408d1df32ed653cd58411034800b897666ab7dc16846defaa9026eae1811785025a33f9d3b33b6b0181335194a82b99a6bc4dfbe0fa3bc6788df9cf8e9c7d1f8098d14c5f365ce355561bb4e0820aa3cd2d786cc44688d226a715456ddbf4e483a555b1683af231b32662d7a1061ad6ef1bd4a8e9024522d9534eb88ae5863afc33461eb6f0696a74762e4b8fb742536ea0a1e01d1ebdf94165c2547d8342d67bd8ca87191f7f071ea412153557fbf0580a723b420121e101b24cedfe97b6d897b9be8de8779c482538a8f4cb047b5fcca13aff715880e1211e7119d2457d3484440eaf0830b6f845363f5e63fe4abd50b301bd0bf746eec90ea03a36ae540b6cc5c125732c9b7daa7878a72ffb84113aa157cae408c9e9928600db33d91108e465e146488c95636715048b86a9155a5dc4328a990c6cadd4d01bd30427de3b4deaf3ae5f659689b5240209b61523210d0576b4362804a554ba98c9f31b39bdc19e56e8cf1611006df99f7edc9ca8e94c54c40e235710a42bc200249d377c3b183f596c60fc03ddbdae6bb4af1480eae36c59c0d11b3d6e5a8e5ae7506ccbb7f884eb6b1e72d84f9695e96d5b481a5d9a4991ea5976db9a926527121e96ad9afd23210350286a5b32cecb68870ff1b9d56a2acf6d8a71c610234ffae297d84125b182a4809f7c6ca9b00821d46ec0a2d6a59a1a805b9aaf57b72544f40d54cfaf36ab7d55d295bef11044015d675abcb831a4046d00d29e109405c01527528f0f5bc821b0722875e8664976d7deaee2ba2b58d6b70f8320895593a5673944e3fbd7e4040b5811df184e069928ff23e309d149381e5b25440902429a8ce5ea394eec643549fc0512a8477ba48df6d564af9ada1fea8155507ce1e45d30be966853cc2b0806c5a76ec92d7e710ba1c0b9f855a59cc094699788e2a747a0971d2ed9a321fc63a22ff5dd6c29bbe21901344665628c55001f998806dab99d9efa692bdd340de9e19c814f4577ae7745bf441344d92320a4dcf8494061470d25e1e26612336677018e4e439c870022214ab11d9e71a9b1491ac1d0b376f0e30218c7e48d497af6c62cf4e7722e56030c11d26b1ca51434e4fe8003cba95407ce1c6438a6b2c99cd33bfde34b2682b3d4c2f8e60dd11e6881b8414182ec2bc9bbd06e579158f0ffcafef3610ecf0d59d4ada78161b2d5fc99548d3a236436b2e38d47f21fe34dd9d240ac85a9ec54d1c4890ced77124d27ae3555cf47cd5dfb1f0a4b83984cfe51d53a56f2a6210620ac6f9c9923950f70bc4c5738d2e4e9767a37a91714d969ad66b7bcf52c9012f15dc602ca95798c59159cba69cd29b6a4232cabeafc8c87be24dd1f02842204cc1332b8afa3f9e09e6cd160704e1ca7d1332b890a2151a94387b675564c52bf662bd6119952be8150c8c4a245ccb22e6db18a05fa121b2b577a94c71b08d7d021a5e64d54438cefc5d2ac4867c10868d68d6d0a4cb48a43084a06f19fdcde7472a84d23abe8bcdd37980eeba6b9ec6a356949159187d4b2b9d8a874312b3b9983514787b102add531e6a640e8b8fd240484b80f3d1ccc95b649b6c2750f4a6397d33c59367685e5cd2530310aa9bbec18ecab748f7545c5ed8c746b34b0102780954347e5650c6c1bfc23e66d7d9f438c32d4903e8326b927d26088b1317c2e3c1aa6db9f1673bab5fd7fbc9d45425b9e413f24b886105edbd1d23ae511b45384614a5ee7710e7b784205456d861425a6382390a0f73fe10770c4f3cf23f8206b410e9639784e632d79fe439db98e46193784ff8ba338d434ced3382bbd790a85ea122dbb1dfc9d474a566b455f2be3fd6d2f9bc6d3d6432eb437accbb4db6dd83271f07828e0857b9fdc64eb88cdf2faccb7dc00be0a17353eb1b0bb6c0d7695e6037abdfca41b88004fd3ad06f7f07ee9c8a1b602c7d306d4e9cb8f75fbbc24c9da340f406ef9b1647524a88c356a14e78072535bcabca2006086b852c903032639bc6a285982625f0b36d3440798101c8d4c531be35db8e9311c43509c378999a52c6415d666c69ca58f6ad912ccf5d91a80a9dbd3c92988222965ae047f8982a412fa9f5aab07407419dd5d0d4fe961da0b013b9fd9f08eea991e4fca2edcca85d4f43bbdf6c3fdbd478cdc2e7f9f9f177569d536f94b7f36dcae2b9a7e59164259bb533f59cc22f97604e83cc41da5c4ec16e15cc6940177352f08fb5345e4da6ac2e2f695bbe694587aed814e117d3737154e07f59bbae3080afc2ff6beac6988862d3700b57b5bce295d8d46816cda8808c4855c1da25c99a205d0a9cc344b69165b1fa50c2d32803cffb399f0b0e94806dedc32864bf1b10178c014815f553a6be84a2953e57de36fbdd9989fec704ec9c0895c4472f90b501d35e95092af866019481205e60e4cddfb82880e5448b9afe51e9d2dd4099be398fb7fda61ddae8610542c683fb0d3750e97e37c055e629b47e4d4e1f268a5700f133d81aec8acd014280bada48a6371d198b3a5920a1b5b2b88ebdb9d4e0f1b972045c21d34e1b542a1923c0a2102d3321ecafee4494e0960c4d798602ae3af5ed1c681fb8e85d4a26fb8119acf774214e61517eabc537fbec3ddf5613264e5ea3f8413ba8d24f8482b94c0109c662e50f42da86da41a2ac34e38bb7991bd6b0038180802e4f9b709feab5b9c444d09473d458e5ac30a6f9bb0cc4b00c24d32f79910ab8e9b36826b73102aa83a331f7d1c0ca8433602ebf935c217dfd29aca8f8e9ef1e3e9f5acf9bc7fa003cb1fe4548b54ace0a4b619b2c3f207c7428ab1803ca56613098d859c885a93dbb01d7a222607e27e71a15a34a7d1d1efe0655b818f044ddd4ec4c91ab49ab18d58a7970021f0c92e99c3a95705a797a99a8b536baa6f6d31d2a74c4c3db08217a00bf8026555a6f869285d79d8a7f8db9a67db608dc994a3d21e07bb7b333c2f423a5b31471a39506bc823b6310441d9f6448c9c7c8aae1bc391fff94419da3e5a6b4c5edd87df9c3fa25b8d4a7da86c44c2406099bbe6e80789c942450d325a5c147f1961ca74b7e688be7ff322616cf4706a9149c9fa114dc80d704df620c8a9b4ce483085fdf63d3154c533b645729c3783c6f4a95537a230c492068e61091298b3cc70e90431e26b516ac8ae634910e1c17f9ee734165f88f366a0552890a246f7abefbbe6438d93b8896be71db18e964ae0f49e9adfbc1e1b987f212148ee5e2ea746909d8f857a17580237b41957ddb2c0036b0db4741cebe30e42b5983f4ffb452ffa9797b00d55fd33f52b3100a274c909c30c60c0907a2ae864b145ca41031eed91fe779141baf7d871b6bf351d82c415f00c7c848f937b98eef20768782670cc962bc4f51bea2c23e3539c6377464acd12eeb6ebbc623713a3b4a22cdaf4c312dc9b3c90d4c1603d54f738e6f889b445d8001709ab1db64c24f057a4350e9de7772d559638ce3456a3852f8bd5f94d6cef422c1f2c40c6892cddff12edbd983d4475fa59bae4dc9b9b1ab9d6b6c3fed4046559700c194b81bd7ddfbb16e7ca2b620a2541c1a7e946a6b6c86036862804e4596db4e4fa6619def02764163512278680fbf40bd6f44485f771cac100d379773d58d2a4d2f21f2eafbd306f26ad52ef2a8abc0ba39fbb9b985f4d9415ce937181466a0a24070956e562bb9d00549fff52aeaa4f4c6cab434d017588775cd0737b551d7b7979ee32c12361a7512a60083907a5e6b97f061a2920a210a89b35750fcbe355fd58d7211e986633101849b9ebf53912cab3d50a61069fd3f58aa08d9f9c5ed69e3ba31563316d25d7ee6c62b7b629cd0fcac976e9bb0dcef4f69eda5992f81ecc1d90af0b5189bb99072377c2239560b8a9df3ac9f9b36f86fd2dc9e7c7b2f2ba82b671d29f11f15777b30544fadb41b1620f2787975a02f0e64d208d2bd3f9e54a00dcff19ba6fd77963227c654c7e358042a7ab72c24c1db6842ab300091f3cd7b37611b94d732b2bca6703fa096d23540b5b1a80f80cf3a2af3b8530e85e388093464a98c3e30fccd48a5fec468d683dea74504f645446f0ce029575e879d855acc68cba782af074fd4ea41169c71cc488d861d31ff20918374900346222eb083da3251ba1ae7cac6d26ca1fdb3d0ad3595f4acb0679855f6535f8d0d954e898eaed73f65b62367857daa729c5d315f223cc7502bc90fd1ef70f73df55cdc04875b5f8e387f2c1efa73f090e4320f31d8fb62833c5a052b2405ae5886314b98d6330309c621862634a6879816a73d67302b6a1a57f10c2f3e627b5f1790dc3f8b9f4025aeb03fdc30744dfdc8c979985b3a6096abd32cde191087125e03b9878f431e0be8e353a1804bbeebaa6723c9832fd53ae5ae10cecf0356a1c8d0ab70e720a280e69bbdfae01b3c7cea347ae04cafbac9e9b3cd707c8c099db3526c06803063b427eb46e4116df13d33c5e5b7df524dd1cc5bba20036f02bae5968a1d00223444030a4c06795c308c4a4e07ebde33e77b6cb6e745b30d681b967e9329debee0e531201ed67bba102646712e7e606ab87e4441a758046cea5487196e5741601cfe3abe995ee48e7f0323a400aabed1d0da27f5fa5fe013c84b437bef2de5de524a99648107790758079c16a78b2a85b0f3c8e5cf38ca2f7f06da5b083b77dbb87da305b88dcbc8a8ac0a5917f7e5df3e201db41657dbebffbe22a128d15db509dd44af71dfe2083df76a5b6de30664e7f56bedb5cd3dfe4dd4e2aa4389a8d7dfbdd6bf3312d14f645656b9fdff1117f7ab1cb0a4b24e54517295d359c1c5aa11f7b54bfdc27dad155685dcc57d0ed8c9ca70dffda4a437e6ef5125395ddf5330ff97c7215403221ceead444037f7f641b8f17762a9f735da9bce155815a2cfbd0c532028a80c51c392132f5078808b65220e15158cac0eb54aeb1b870c93710a0e51462459776b3dccca00be6bb50fde71eeaa268a289568ca2043e9044c7630aa72c3ab7a400a6a0b0bb3872311966a40410a3166ec127084c8709ac4c0e9616b72ffde264b708a6e1370cf599631683a24db15b20fa626094e042e2099b1d6daad5a6badb5731583765d7d5a6badfbd0a696035f83b6f427cec974f1fbad368b4319e816ad2fede27764cb0798810e43ab83e723c4ee2da7d4bed16f92506a69a594d25aeba6744b736da873debb8f6cee63d4086142d209a6086302154bdb96ac80e3c25695d4eee33d6729a4a0046f06b950a7547fc8fa4cb3b9c0dee5d68bb6e2eec6070469427f34a7fc6e361d757e90afd91e382be34a0a5338144ba8084848418924610ab25d6a319ef7939294d2df58bb8f783badd537a5d4d234de0c0ab95615f10cb5487e145a47657150b9f8a8ac2898fc69d3a10a0524f404184e609182e504242758151698105984329e0866a0c061db4184378345c90e3fc867cfd995dad67bceaed076f9addbe4cd2077771daba78d49c5785f46e57cb9daa8ffc97914ea518f42bda638b647a13e9c17d8478d2c3aa0bbf2c7fb9cf113cb0af6b8f77239f851a811bf833be8bfcec9f970dac8c911eb8362f7d543594a5a1232c7b536c77dfe8d02ad9cb9f74422211cc0078feda3e7a1bca172d2bcd74151169871460fbcf780fbcd1bcb567671bb973a3cfe39cf23aa763e14e83df765ab14c29c88f23c07776c5fb6bccf62d9da1985aae1799e8ee7fdac42a9f7428a73c0ef537af4b1cccfe5926c096d9abbce3fbbe7ef44cf9efd3f686d6fed2ebb73b873efbed6aecb9ca69e145df7572cf5f61e7ff77df5ca233beba0ddb443ecee9ede21768805a1fe160b945f1ed9de885fecaed3e9c65201a58f7d7f47cc93e59f12bd8ca78dd6f6cfdb7bd4c7b2b5bbf7442c96be87f6edf0f85d52dcf7eaec1bdebf5fe78bed63a980dd3d1ecb17bb0c3bdf41b737e269c3bfe5e9d04a74d93a7bceb064b1f9f1db2be2cf6287e9d74477ffc1d0eebec478d30f81288e0f8676ee511ed95dfe8ea81b4bdf2b6f042102dc1fd9734f8ae37ee7fd043b2f7fedf2571022b0d2c037f7aded818fdfc6dbe650acc59b41d7ea11989a78282929d19413b4ee50a95695c4de9d1aee96f2b2713470b809e71d1472973aa1f376da789f0a4a8de15ad55dea91ecd35a6bad8558d1a5cea1b5d69a47cd51a291e8d1aed11aad512154d786425dd34f18292d618b794c25944e3da1b98d1b794c24362567d2e1b123839214159817dcafafb5d6dcf64c2237ea0a88d8b4b6422f09b1bf94a209d5e05dc0021e67d3771e4f56a1eef36fba89498f2e94e8efc1e71e7feec6559d5f470ede1357f37356b31b577304d2fd4804cc1c8178d77bfcf9c16f9c235e79231ea70e71c5adca32a2f46ef14e4812d3d528436b0d7df1f07ff93fd1878e203527a774070999a6e1121065f99626d910c9a3d5c444294d559175a94ee5a42555268fd28406793c86643e688e011d7f4c0bea73a38e334c581d4ce872d264474d827ca1d168349a75ef8046a3d160f8da2062f48deb94db6a8e011d7fbc0478db797344db82bfd0b8cd5ad5082dcaf2a12f5e130a4aa275afa3e6ea893e74705059ee44e3acdd39a20c1502a29ee45bba7c411ae2369ad39ce65b10ee3dc80c528530a69c2b15d3e5c442640d12547a6cca7854a19a0f893e5e95cea882873a1fb0d3940db496506daacb4d95b99baacac6a9d1e5d090fa55001d0cd19a001c03cbd1cd2fde412229cbbfa85abaf9cd2938960e0d6dcc6d37af5cf0b056edd85a6bb5b539ebcf596da57a1363551fa86a65532b1b7777fbc6f278a0aa950ab55aadbb6d7776956c7a7baaa93d675962b14dc986440f499cc95e9c6c4f9b52957befbd4b565051955c41432ec10d97b3e72ccb122c66294e94ba74c512ccea50abb4ae5966594698a5304496a5166dbd211363062b495274dd73666506194cac1c69d174cf99953056b47c332b55665644d8df9eb32a5434616940228592cb4847820c461449153ac45c46e69922a6334ad018d1118aaa78b9280e3218417379db5745fa324a62e48a4384acc8e5e1af8a5e53f2a6e69a66a0bc70e49aa1612a7279de57c5a12e5d602eeffb2a1123b336c399970bcc2a83fbfef78f6c22463e22a4bc5c608c7c415489b9c05491087d45b1c2e4226284f322cb4d60ae490990f355b1e55290400a25971114938ba404407d55f41f8c2863e49a52e0f08393cbd349d1265f684c2e3752692da2d29f9545691554da747111f13756b481e332429b2081ebfaa82ce79264cb152e231e1043dbd048e4c2c0260531b88818018f704d4a00235b9926ae23faf572557105a4522a684f4cae3af2c0d92908168ea8d72cad793ffc0961387fb8ede2546a47ab5cf5f1f418d90955433c61cf900ff5f1ab52a97878787a7a7a7c7cc8300c7f7e7e58b0f0e6d461dcddddbda7c72728fcf9f1f171afeed5abbb7f2b5fcdfaf3e3eeeed5ddddab7b75afeeeeeeeeee5eddbdba7b75777777afeed5bdba577777afeed5bdba57f7ea5edd3f16fad361dc5bad5640aa162e5c00bd78f17a6f8aa238864463059ffbd00d5518a4220ad23060c4881123045285402a55a8dd9d060d1a34aead9486cf1f202090a885aa45a802c2d385d3161f510b17ef22c8d2f0c58b202272877beeeeeea5915dc7175f75afeed5ff5f14c571ac00dce1a001e80763c6a0313cc6ada0023003bb71108c1ad467850123460c13741d65c890419224eb63b166cca001127d90bf0d90c823d23a8cc78821838824594d44feac1b435313a9767cee2e43860c70877b24a88106f60542f0489205ee98f139050dc07aaf5e4a396c67ad7a33543342151d67801af82e8f78343e1d46d7a861e3d361b407000058f059e0b5565b1ed1416b7c356cd898b5d6fadd7bef68810ab444d7b1fc2cb0a0d50a400004f0b93b6500166f660e7fafa7503771b890677f8229b29543984f341fde5459f47ba2f0d74b6cc0e7a0748608c1ba298bfe8092f43bf0b40e4a27b5a3fa3014150f17180c96278b3a9329e44dee4293afd0e42838acc98f9a7a1e1084e6c3000e9aa8177ede6b308339f3260e03e283a99bacdc8180f766479f362e3562594c1e3e9f0f48843f04ba3836ae088802a9a031ac49112c870687866cfe0949f029d96afd7879ebfce416b4d431720702721890e7e2d36174e9b04d5f7c1fc5e10e03896aeac54e8a851a6db1c65edb1eea032a17a4d8710383f765091e304ca0dc69fbb73d136cefadf758079dc55830fbc2011833177c8863a685daaeb5ed3997466b6f81661b102bc10f3398d1326506850d67542d8011807d6dad6a5b6badfdbcf4b0b7b75b0b5af63685fdba98f12245972b33b60d2a427f1097372c8badb5d642e00a9b1fc8a0a04413319765b32d0d4cb605b7b5d65a1e2ab6657078c2d21d2c1026b3ade58264db143e0a13ac5b4f5b1888bb1ca7a5cc931f2d4c2b2d67aa84492cb4b489f93cfdac80e449cf9657b80294253c1a2835f9ac80258a2a4bad6705189cec24f18c8192d2f2a4224267470450b42a5401565973b6c2d3955814a31e578e909e662724151183cdb68c800ac7719c15d9374978928d9a8c683a0a941e28247179d223cbd1079cf4b0525466498f2ab42094f44821294d093db6182561420f2cb4190b5158e9b102d3cc032454e9a1a5287c41abc228ed527f8c1b748bb6ae93302a5d62c0f4cf9e332a60643ce99e3d6754ccb06054d4e87f2209a8c3708a538f2935fbafa9b899f23df941a414a51e5298286b4609fa1b018906f79cc59eecf2ff63574cc83ad4aab047512c07bde365c60934169344e33232aed0dc120d11f477264691d64acc2881b652b068d076cf59ec0d0d2ab11390446164333054d4b0e2031812642976d0b7948ef5edb5e38a7a083cfa57a4b4eead1ce9d7bab2550b92962d974b7ed15a90c8bea5f6eface307dfdefeaa7c071bceecb2b563fe1ded9ca356fd4e52b2cb9615cb1a45cf2abc2c6b183da8bf71c97fb9e0af2217d8afa8fbaa66289a7ab922dbbe46cbf1533ceaa840dba8af0dda69fb07e5f83a6b503a526ecf1e7c28da75fc1e47d125de5bbc567d774cb75b3b3e25e78341344d8ee20ff4898b34321ab52719ada98b15b4bb01dccb297b3bd60d1b59a35aa62a55d9b441ff0160740794a4a2149a8cae5f6270532af49e6002aecb7e1551dbc50aba3ed2a6235cd7e746d7b1ac62362d67354252b3983a2255a34b0be26a9a5fface1914a4edbbd47b622d82d1f769e6fe0eb97b08e5fe7e1db978701f73f17e13571b16b9747fc5cde954d11757746cdda0acfa198abea3f883067b80e01e95687f6a995021216be7914db4da7e22816117fefc9c08c32e0e7f16930cb9b8bbda461fdccf0d44bb70b9fd2a836e6fa305501b8b738a46b4bf6f969d214b0b33a8acb2cd3daed3fb184a5c6d5a4727f53535a6bec8ac20155d525965794f521cde7bdeac792c3fe86077bf4d173dd8368f8ea56ff781c49f925ee78d1d45a1b4fe3a16015344f54f3425b7c75f71fd0d2afd6a77c6983e904a47226030ad78abb58ea8ed270af5aa71857fe7552b20faf10864e755757b4fa5bf52fa459efa984c4ab45e478b7efd22740c2264d2666d7374e5fddc65def26800bab3d7a2c4609bfbec5b6d0aea8d1ae0711b29121f4850afc1efc421746fafc5557efdd3851257795cfda88ffa0df4d3478df48ba86812c87d8e48912829345ddcf66da8df60e77f679c95f58d1ba08ae8df54e26ad33c4f44f528a1e9caafebeac77dd42fc03ecfeba0358f3c63113dae7ed457fd4a35aeb6a7f4f5d3d7aa5f6d23eaf5afc447893b44c00051bd1e8910019380e94252040c109ed73e5f84877bfde1ab463faa2cee9fe7555ffa9112e1e845af373ea31efd6f8c3b5f448f2efbd28d94e019551c87f281a24828c93d4adc3eab258a46a2421388990a6b36f7f3a94c61082ecf8ccaecb27ed9dc6fff65af29c198ae3421e18c36f72ba751927beead134fec922e39b14b8a4604b235bba46b36d7c42e699bcd716d7e3a5192e3e85115a2322aa301ac292481356ad4a041b3b4942307498ae2cf8f8e4ecebb3651b2be57b10826b7a8b188116ac4930bcc7d9e31b210f5f55fe7f5a833fea847b2b2eadb2094bcf2c54214bc2ad3022bd22b94b4f6099daf104ab5a314d54a631b17c58a2e6952514c6f493c288eaac63e07f382fcf6194071786f3ffb0a98187c6fed27828077fe3eca1431d91215eab9625fe9cbb67eb4ad97d93607fc666390b66d6d4b8bbc310a25adee9cf407d3c6486563280ed302fb58a462a60dfb3489929ead688f8d3ea6d1db584e37442440c59a2362bf0405169c5ca8c713d079fb7a5ec0bd5d0179d44864b5414fd24b8f458cd027925ea8df19573bf8f572a5c6490980f5d7d4eb4f8d9f7ad4a7c62761db79c5b6938a6d8b448f4d1bd60a5dd2188d6d238dd531a6472221bc5e2e8d1a894840e9ebebe5d2634fd2ebf5727914ec803783c017a818b9ea1f71856f74fd20eb33463086852663a490418c511263f6449ec9e10972891c9a72600aeb9a5aaf67d4bd2426c98e729abb2426c9ae6e1a773767eec720d22fbe24263bbf2426c9eeba777edd2f8949aeb31f750ca85be0bac6fdf246d0b3f6c67dfe1af7c6102b070d1af7ea7b6fd4a8d1ba31c4dafe9406ae5af537b4bb6edbb75ddfdbdc1bf723508c8d7b8da449920b8a111463cb01b7a018338ef03c4a291d29c514079d94529fb5d66ae9acb5d64a29a553b4d6d25a6bad94529aad78d85acedacd5a6b6dadd6564c71688a81b51587b556bfd65a7b496b2dbec1db2e75ce568a73cf58abae14d56590a8d2c7b456d4fb9cf306aa06fd26a5d6526b29ad1445524aa9a6d4da9be7eb18dce1b8c3718763afbd1b9c6b3738ee70e824b79fdbfb06b67de72ab7d56b647b1b277beddde05cbbc1b1d7ed7577270be78b3783ca5a349d668a2f77b76ddb360e5f8e26f99005ee84dcc959f4e79eef50388efa255d12b2d0a95dbad3c59f76af7b3e750caee52cb89f1d03ee7a1b77fa28491fc438dbcf74733a42a716751aa24eee64371da12c74faeea7efbb7dcffc29fbbee918383939dd29a84a958b76d80ce99625f56b991b1a74dcd480044de726072414103ee47ce3061876fe9c6f78da59cc6c671c9eec8c030876fe560e5e86f4dc81e382366739ae862336670396cdd9a0c4e666376ca9810a8ebc51f30cf7c3be4928ec7b3f6c61df59d2153430792fc4c84c21d3b219b57e20cdae3448997de0f5b29d3d53c133d46070c0aa66681234c311a784b540481c60010509e90ad212dbb2b132c8b6d5019b5073c0a187292430d44ba749939cbfaf634cc0129a5031acf03169ca89e18b134f098cc106269d2a6452f4cd4ac830981743104b7009455d0c4d4eb825b21c83131dd8f2f8c304d92c8627273f9c182529e18712a6274b7e3429aa5204f362c20f136a33193eb0e4078c89862f84474d1586155186d8fa67519678c2e950ab42a638af598d8928706a90d2c40629566238d1a83d67525c8891468a0d240b5278505531d3ba33cfb7879a73ce7b875c107cd3af7f64eba074ee0952588ba3dbddb62be309adb3e70c863755681f353386d03c3ccc4881fe6ea061a4c13036c070820a309040bed1e0130d3ae584084767bc1cf900e648461e25bda0b4cb6f591454c7b9f33e300744695027b5a38259dae313feb05801b570e1e2c58b6305412f60c49041b266d0a86103002ffcf9eb59a4d37c727ad51cf6e44a5e3accab05ad00086000376edc20000ea19616d779a13e2f7f1d06bd5287404f7a2890e8e6b80e41206d732caaea8fe2708da4718a32a13f4a5677b7d65a6badb5d65a6bb3b515d7ca430577ef56ebc5b5561e2ab4bfb5d6da5ab3b5d65a8bc9b7d65e5aa9b5d65a7b456badb5d65a6b3d6bedb7b364684fafcb5e9775a8ebfa4368fffb41d0aef5a2eabdf782f7de7befe675f7d68c3bee5e226cadde7be79c2048543f08c869bdb7de5a6bad76c35d9e5d9e9823efbd97db26b74d8a290e71daa8b372b7dedfeebd3af587ca9c73cea04aaf7fd0aedb7b76ab7bb31f04590fdf6badddbe8fdb3008125dfbd9fba6cd41699dd40eea9b14476a47c5d393da51599e7b6f8f4f55f1f4f46c9e9d3d3fb5afcfadd5faf60189eefb7cb527fc6ab5f75a8b83c577efd517e8de163e55bc66399cbb0704614363f2e14ad5d6cefb7418c0c109b0b64934101f600eaa2a1929c551ca41699d8fc90829d0493d06a6902b391425264a2328cd5a5532528aa394da5165150f16cab55aad2664b2e867803a95f089762578c6d9743472a7692384c27b7cd8b051a9787eec1552850c096148085a488e1a9bb0874d0f143d60abd5f3c3a27ab9f3bacc429c17bc601ab88ac87fd808a9d56a405688650394f2daaa039ebbbb7b0577d8bb836ece49575d5544f6c694bd70baaefcd448b5f6de6de3a6e83ababbb5eeeeeeeebe7118679c73477d568cf3e79e73eebacef3be1a443be89c9808ccc9b19bee54965277cff33ecfc999f6fb9ca26a543b83b46a72dbe501411d46a374ddf56da523ce41a1505a6b9d21a21c3b7cdf0853a9d40e49546307dd2110dd2a1e90082889ae63a9bdd65a6badb5d65a6badb5d65a6bad7574f7fc5d1e8968c085abd6eed5bdbabb57f7eaaea3a3934aa5767676542a1511518f4f1895554e1e4a1d746010310407b90811471fde7f4e854dfa449f6a94299bc640a21ac3a2c1112f81c928c42177538de85315aa5b6a14c7a0569916d047a2f5cba68fc2941acb5386e90b3124697dfea49422a184e6508ae4068922d66ceab02f94525a4413344529a54eec1d4a2b0e4478e0043e74608511580e6cfaaaaeebba9f212165776fbbaeeb2a120f605ea0bd5cf9f1e440a2bce9edc3ed081cf6f6b38aed618448a20ad9cb8531fe376208a618bbac6184525396a61a0864455071c66e7f99d43cc984465f950f46cc0050c43d7387b8730aa625fbbebd976969df2150d8778811ec4b44d2bedf3af364df1fd27106cdbecf030d07f645d3b46f1a12f64dd3b46f115e5eba0a5da6cb2484d3ae2f5ebabc340dc6defd68632c44d3bb80440a2e4079c900b36d70e802b6865440a4400041800922ceb68fdbdcb80104961940f0b06d8e7d69afd76bcacd21892b650389364bc6daa06d6bb0586d34e55463ade5b66ff9d93f6ccb83990e98e101cbb64ff200c5b6df1a62b2edeb506261dbe721dbf67d70a01467db0fd203d3b6df8107b69df960c5b61fc20f4c2f2db0a23073b634c3b63320901cddb9b570a40993315a509064042c2cd828a4783c4ba66bdb33d8be3b3051e605ca832e75ebc60e4580a006aa103ec6586bad7fcc9a272d2c86e2e9c598374d80546113b226949a6072118e8953b452d3444d143557d46c69f1b22725b050856e62405816bbf23302a3950ce94aa8e689858ca9c86789a61f198d4acf12b05076022a3c163bb1e4041a27d4f8844e4e5025e1d44326cbbdf75e36489435c59459fac1060d0f48c491648e8a52aa906644eb423ba2acb9552119d9131dda0e19214cd03fa0e89222a326ca1346984ccd494e125d34193831d06210348180a6759862429b241d567852c44b87189ca461d241c624044cf88726b8a933a20967c491114959ebd044d1e606ebf006ca9dd8e2354a3fd630717a87244eac2a8c628a1f51584159739758ef1025ca089c76e80213c10e47454d453bc8a614a114bef036806025a9e0c3942f58b4dd7336850c8c351aef399b3233010833539a76a99f86294db08af4ef399b52c5192a55c2300446e0cffc16e4a19c4b3ff3d72f73e89f96b2c0df11756c624bac6298432bea5c50ce337bea7c39d3f89773884e447d8ef8bd8b3954ec6ce888e564431ff42270a744d47ba2fe1cd17b1d31e7679b0d72306d80ef2dd9d068a858ce1e76a9cb09c410bbd47ba6d99a875c3b3aa2426a9ee7c9947833a8cc479b7b8ffb12dc9c36f7a56a03c1dd9a6cee37cf0a4a72db6b73af83b2d8a5dd774baa4275ac5b52cd3f9f6e4dd306f7155ca14b2e4efe42716cb5fbdc7369e615b93493c5855c9c79c1b46eaa0836c7856073f768ab2579e8ddc7cf81fd5c57f46f5265713f5dd8c73d72e12d147719b11125b91f63dac77293825ff7a80ae1e7c27ba4b967818db82ed8c7d78fce09bd7db9955b93d1e67eab71b5cd4dee5dd034978f9ce2ce6883ef91b5770a4121d0f2a042add6745971ba3c178f0e9a73ce39e755b5bf01f9f4ed58040c10f2e9577b7f0392fc4b7e9109ae7ed8afbf01f9f48afef68fb8aab8ca9ff30884becd39e7d7599c5b67189651127c2ae2a2ca0261c4788d9594d0df971c6c73471c8c039f2ba238ba073f3f75af0d76b00d96dd1a8a83e7c1cf4e1487eac1cf6d288e9d073fd7288ed4839fc1cf4854686baa2c30a8829e9f3497d96036aa4239ccb1581592f1e0734719e87111e61e7c0c23638ce573628ee12d542897a12cf08fd0a08131967329682c679959a682b1cc91e3c68d5d724fe44ff0c7aae7ef1f71ad7a80d4bf2311303d4f64044289904fff882bc7385865818fc7b1c45a1c4b1dfe58862fc6f2398e5659e0932ec6926c31963fae46163fe1586a9fb1958f36f89e7f3c222e8395f01266c26828093ef9d365c5551e2fe043c6a7385815c2f8e9712dc44e1ad3b00c912345fcaa2cf0afc81d7134b0e48eb8a3a31cd59554361a734c2cf118d3250e017e55a1eda8b2c0bf9ffa9e3127bf6e4ca1679b0cb41da58e8e36f8d3458ad3c523e63594045f2566274a82bf23e636b94649f075c43c0525c1e76855686be26038d35e18a68b3608eb621b7cd8069f3baa421989b2c0cf6a9ad0fc52584667311b3cda60ce98c71fd4254397d1dc13f75431e69e9e36f89efd5a059817cc0d3e90fcd2d9bfecdeeb44164c3ae7c11e3963d206df836ec494fcde52f27b1dd43352ceb10450d71d73acb2c0ef9cd0b3ccb1a6a6a6a60d7eab0a3960b2c007a3d8e0e7b8a0e94ec494ec5e8b9692dda3c41c31487e308319043b2316748506fc493e08165901195b3f8b606e95df77fe551ea7cbe6d873a2714adbe8a82c1087f7f33d2cd6dfc0f74c4524603cbfe713ecc6361c5416f818fc2c967a83ba07fd3d8ce679b40dbe3375e07b97fc20cd20cd20cd60fef2c17798831a0cc1f73e1104c1ff3eaf29e1cda0922bbaad2ae4faf7a2269f2d5ed0dd779e534ed90f77d1a78f7a1df451e07ba223117d54163864dbdfe8304a823f4170aa9ad0df7bcfbd40eeb5c1df68756eb40dfe26ab186fb20dbe0b9a2e72a3ca025d1ca1ed57071feb2ab43df8215985eea3c632c49b2be262568d7eeb256cfa7acd765a43700cfc0625c329f404260620e00d42d8c107f3821bf49dd20c5c844d472edbdb0ea60dbf42039feca8c48c9a6962e9d08c00004010002316002020100a87c442911c87f24c14dd0314800d65823e665c401f88435192c34008628c21c4004280310418620c62caaa0ce82a27d81a1ac6c4d01061b5d9edcef91f453135597b57896b298b5c3fed1607cb8201197f8f5f0b436057a8d99f0bf9df4b0982c9d8a91fb0b66e869a4f43fa1ddd75ec69db3caf7c264881990dc6a65fcde8b6eb2fd58728b77d373a70d78b6ab8db30c1258e45eaa8e9bf1378e20dd0f39bce6dc57d9ee720f1fd0bf4ec72b18683abeb89f8ecbbde6857bfd033626cd43430c9911a89c73558d1ade1cc59ecade19f68984a28de704b00c86e1033c924462667a000997ad9e6656fff6e3aa9e4c3221c21951df47598f989bfb3a747f91fdfadc6fb8a6910d74f90fdc7cb2040a317413834047e19b9d105e45e54c75b7a7c8de76a4a3cb8b2b970206acbcca66c79930d6e481c8615bfce2dec4810865abf6c19f6a0c1c2a98c2f23c3bacbca2dcf7f44cf630c6ec94b5026011c8f8f599dfcac8e5c73b2d5dd7c505ab97fb19c9ee6409494fa22491750fde0fd9467f535c948f53a394e0a3fb5a51439a474a43ffe0da2f0fb6225beeae4d2bf425289b3d7d24d1411cd89049d38e1905cb5c1f58c5a7282a2aebb4b01a7f3cfcf1e91334257e1c78ba5ef2af4f6591ce6e3da3c315dd24bef1d6226f74ba6169fd7c5f7107c2e78bd0bcdf326af270dc269fa5692034440a399b139884ea4386b2e6f1818c921af102f9a4d4776d6e1dacb78121feb114e2da06156ece0b1294d364a6f9a945644790f06d10b189394897602912627164d109876a7d104b94a02d963b04c98adfe403829338635d40289c7bf7ec49b1885578e65310819420c4340b0223899f025f244a068b79d492266c9fcff60100068c9cf3b66322c9a0e59f6c641e7810e1f95b821c769ddc56ee1acf5984945cb94453feeafde9aceda418d5068c6ddd8431a9b2431330886538fb0b5f29e2cfb904739c92981f50ba5a8a09900e1cbf7ce45b53a3412d2199c79f3d73279ce7bf8c76555c28536b3115e28e1cf42d426884fdfa5657aa83f4506f8f2c20a335085c96c98e8c841e481cdc5f8e789bce4f5fed95e47bb40a8f0d98c2bb2805ee504f04ea7f02d6119965c5fda975c2f4f89a25a6b61b4201ea3aaa0a9a9f0ebb8dcf3e12b9c10b0b18ed82b3cbd7e99bd98d85ffcc22551f2a8ddb51e579d1c2839cee2b99994c7ff68af798c5550d55ebe53f2fd9c7cd7fafe95ef8b372883c2fd75f738a45ae9d2835979ec2e8472f86e2e9dc91b3027eb487aaf74b275c9bb45fd7fb93b914fc20c0163e2556e6820d3e87f737c6b4167f9950cd460687eaeefb159345275223f0d26ebc0348d4feccdb3c955e74251d4956a1198835f2549e842e1725db120c2984255cb18ae10a0ab8cacc0ecdedfc96e82e6954497942952d6861f9b4d9927fbbd06b62bae756af2d71b39b2891f5676abde8076e883d075b9e6df8bcb3856d6e558bfae510b77bbe76aba13ebbe1c8ea3c63af59f36c84d316917d238164dedec159226a108c8ba947c9c62a0c03014eb9c8d509ffa5bc05e41607c6c1dd535b1a1aefd55f6db9f96d7a3b4266d2eb39f69bc491c6705170635417c76f54703283816e6819c50faf07ce909da0355d728e3cee04d1a8a8918516c52d4e508ab22291c139e499378066fa2098da96ecea3b20d632bee696da3f856c7114bc00c7c795d6c50aea4a5f77c8e8668e51dd5269c2ef02b1c48dd6419f6cbbce964b8875173e27282c87f2e351353154d91a39bf7f803d6d3d51d912d98309669d2010b52e5839308a2069b02be7d3627223b48889c6cb50d6cfe56f7bba647e6faeee75aa747dae0c3b80d82a1b20897a22569a1aee7de6dec850fe285470d4650fd7ed5bff265cf56e3e0b7aa584af25fbca77bc576d8f8e320a50a595325a07b4a7cc9fe66bbf2e1dfc3683c6a8f769f2645cf49f1961276f04f5a9bc0cb9380747d1075107a28e7a5b6d071242cab1cb1e0ea9e3f70a6e4bbeba8fce40b75d97b52356f987ab24fa187d438aa92fc23803271ffe4d658dd7f9d4b4fdc4ccb8e39ef21b13ac9f116ea22bf08059a1029821fbea8ce91694f634fe3e20670d28b1805ac5bad5c52de942e18e92dd1950384b594cf9ee9db5fda8399a017dc3204bd8ca37c8f9393edebcd9fd887d35a00d06b25c7481116d85c65c45232f6495ad569fb53fd2efa112bea7534b0cb2d399b4caee03b8d601c6618d213f97632f991829a2d23a0e988a01184ada7b7d6a20ab748f24b75b7acc32c90d74eae950073858dab1ae2a47d95f83d02dd2e42ba19c89c073e8394857ff25a567ae5be5d255ebee0367125100a3d1895a5c4794c0679555eaf33c0f7fc85480836be9d8a913631f4c1fcd008e5d0d9df2ebc2d77959d0417b9eb31165b5bea1430194084028e88c6f2955dc9b9bf641c3a6a718d1c0ae442a5378d747440564a055d57a5e6b40dbd02471728212291f7bcaf2a6ccce8b9c4c47b03330427cdf29f9263bdc8cf8021c8cce00b28bdbf0af40bd2d25e6b0476e5eb662ee0ef846570cfd469589934a62d5cb8eb8ead95dd475c37147410608873b81452f58247c2bf07c80f241789faf967072df51961e9fc4b31927fa71ce272e5c8be516e761f8754f05d74b9bc8074ff31ac4eaf56e8985bdbd9640b994fef6feba9e81defd161185527321d3ea19f3cf19275ea7135a42da5955200b2a990c4d2e6625f8cb513ba220f1d67fd3fe90b28eda00bdba9fa161133374b3d69d9663794b9d60e423bb4f92222e3c011f1367d71055c4f9e49f007cd48ef0c6b59517c8d34f9cc2895bae29adca51953b4d75035c7e7b437a5619d2e369b310823f197b2411afae924ac4111d40eeab670594b05482e41417a181c89128e3595a6d09c0db69a6f9d5693a3fa789ae4c1265e64768fb4ba30d5f41b7e896c5857a57722bb24c2dc61bd42f36f78b5d972703c07644f72c2b0486cdbf9042177938bd4194fc2564851ce6342ad4d864df71fcc4d3c6755480c9a1ae1eff08b461d3404ab9a28d109975dd48eb47b23a73dc73228d20e0d6981777c23b0be501a1084d4f5cca8b54773e8c85fd612003940f499e88862c0e7e0b4bcf235a960fc5e925701b59e568474ba462a9ba301524dfe5bfea76bf83959878a77611885cb2265578cefea64cc9a2456ff9436bb136ffc38633df479f5325a5bd0587342436c0a3ac35da5f019d2f536810e36076dc04219cfb3ba8fd1fb3987d7c4782e7440bdb1b8eff106a67e52948bba04147c8cf4191cee1aec8d2df88cefc3ff8cbf5b353e4566453b35be6d199fbe7d073f90b35a7833bebb682133595a7c04631904f560f184f8b8240c30dd5a0e449e2db9cb5127c5a7ac0f1a70f57da79237af81cd81088e977d097e61138949481a1137b4de92edf28df8bb787c9102ce7befce19e382e5b761ad2d03d3b71b0887c05029fc4f7497ee6aef1cfb1ec7172feb4fa09eff82041ef92c32ec5de519defc68c2736e9c3edeee16bd2f794eebb42bf65dea99b110037f29017aafdcd7d91d036569bf32e00d8b7da8925ad6fe4eb49316fed23372c42983cae806b82a4f7cc58597a8f01fa84db9aefd1e48f975b892764ad8b1c3a7a9fcc9a27aece21e5883c40bbe52821d8c02b40981d6b65fefd7922ab78966632ebbfa852d3d724b27093a6b47824b0a6b0d88d2fadff1f5901abc0959139faf3fe39d1873be45e5fcb7ed134990172dedcad8e998158b2bbb5327e5a404d95953e1f51ecac2561767e18e45e2d0aae56a8c471d7aa7140f8086112591d9cce551e38f0ebd2fcee6ca0cf604986e4d1e98527302a132d103a27077a31d525c88986c67cf4a82ebf0bec430cc8f1ffe8f92a88c69672cc364ea2b5ae017ba9d74188f0c75acf22dea894fc5a1cdbcfd916491f296fa19c755201e98a3a190cc5ea987afaf44006da82152eac9ca23e503729f814944a78a604891d0a8d0729dcfafb6d58e98603c8bc8eed584fe24c37ad1b7c09658f982fb7cc585f4f8e7e637b3be7c20dc89702920252588efbbbb8bc3537f892a44958ce2719a15f1a5ee67e5b42068d8efbc16bebe6dc98000aeeb5cc297310fb464df60bbd49aa5265cc59c4134a009487c1c97aa94f53c318170df2f91110acbc96d6a289bf75376ea0ec600c3e52c5cab8c0743e878335034ec53ea79c790e617ed5ca5c6066885f1ec090f3255dee96b256f02e8f7d36fb9c1a476cdbfc23e3d68d2a31ab99fd207e6c60e5a74b6cadfcee3072e9a551c4118f3e28faf0be5bdebae8015ca5a829732ad95e599a9348ed881a992c356381a5b5f0df5aab843e029e0f24ef7e5b5861a0291b8d5a124feabd0d0c8591c19ccf10578d813cd4809e55b18f625f879221052f514ea5629ae02e7e80ff21f9e0f680cfd0aff1d1b821be69b73d9a34fc08cf43260813c0ff7a646541136e4394c5c584ee40feb07ec8f1def6592c9b624f73e47dd7542ead4b43b22b47c40ec1b8243ce508114229a823c2d9a8c8679a0c7133a05be73b83765153decb64c12d25895ede4ff315904d593edac9a0bfe41d5d958ca9c999c775e619e2af9d6acb34d2c7f521e11ebef4dcae296c28e304d14410664e6cc9ae8edd0bc5eb6d2c68114745428a0c29a69a5f0546b2d3d2caff559c304e074f7e5c6727ec59edd35216adbd139e32bb199d5837ed303550a2b5cb739ba2f977aeb92a304c20481c9b834e5a2bfc25bb7d9e547f640821ba1a82c5526abb8014898b0b5d051d9cb5f28a445e19b3a2dd950c01204f1c7669ae2131694420c44ed42cbfae04978fa5c57548acc773861715ab9c7f047d72420fa8adde633d1156d5497a5329dd6da7c2b340897cc030917c67c974e145fe28b04d0fa082f6270fcd7443a1dc948c9c297f66b40da218fa736c8e30d469189d5fc6675bfc5f9b5aeb027c3dfbe5df94c11f74226ba670c628ede39fc2e76321503e2a61a02915b098f6ed2584d053360e58a7a6a9c24cf8b7704ed642d943cbc97d07a992a1f5ecaebc20401e7a0203729716ba6b31ce7ebe75c618f998644fd9a890b581586d596240c7626a19eaf11c116e401875c37f5c7d880b10f92237f941e269710c77c07a5acc91de1e4728c5c4d89f07a235634e62f219f18efb3616102006a12c9f03cfadba5514d5a52ee8ef3e3bbde7c2c413a2146ce87e934659d4504f71b763f423ae176e6af2a606a6170f834f82346d632448cda60f28f874541cce70ef4136548a07498c113394e64a250902b398edb23d3a2aa588830149328f483ac398405be16f72fa02b0c214c2d2564c4f7338899174d7277ab2e2e81cb2aabb7624ba23bcdccb7adf73836718044eb753229d835c634dd9e04f1ed9c1623006d9359f2159fcffe3e4f5acbfe2e0f4a815a080ad0735a752a6b2d7b378c6ebbb439450d7d475eaba29ee3a90314475edc8248f814f88aa0701cfda12108a323942e5ffc5446ab97457776a384d1e7073b85d9e8717a91b9ddc1298f4221817d378a7f2f0ab05d3dfafdcacf15462448839c82a2020495d44204bc49a8fbff7f19000d8393c670b92f5e28f051a6fd336f00651d094e25b23325c330a803c32d013db104b79129954d725bc94b807d5cac913c61b84696ce5574615d9d5f6b5ee87ef037c3ae921a7477cfffb77e9e76986055f79479bf16e1c572bc58ae94842233149a8845a279ba6c67a8e6fd357c1cc47baa6257fbf55bea7c025873bdc1ab3374a3ec4df449837d3e841ce9a90055f78f5c05e9f5217e1437c09c05135d35e3da575ea1c2ff3f90c11cd0816a01ef9790c159b19dad415457589181ae8b42bc4c9235981e0d61ef29e3ddd9747826c5f97aecb0063e132857176e11030b302c1d3ffde49776f3082c3d30f3ebb62ffa322861e5a88b238c78d965621ce69d1dbfb1a5462893067f99452f2cebb646401be4550fca1e268fac4efdc31b1f9876d55bb6f6dbfdeefa8428cd0bf3a71e3ec12ca2d341395aff4e314650fe31dae67184ed130bf2417a7a1cd577cd71b3c796e75a0fd6ce479565d2f24cc1ce97aa276b2b9381644c5bbba4168c7f81147e60d5f0874ad8409424d7db856373147d036c6b2eba5c3a042d146cfacb30ec4663701fd2a437f2f8d155f3b8cac7947f0b226d3e25891cc7a5f2f7815e9ee68245c23ab9ad76683f27532dfef21efeb63b4288e29d8365011a4335e2385aebb80d558e598400ab5be7e43cd49d1be351aff492523477b50c6fcfedc8092456d50e2aa89245a932feef1c48415f849ec4259165bcb2e7e2b3ad2782b9998ad1a8f4eb0e1f2a959a2634d643e5ab4b0bf48136b810d205173c7799a3ce7b4319821926feb0c756d78f8486ffc99c46ee5756e4fdbbf15c894814c98a1d5346e95875166b22bfc010c74936f74dee4a177b3fe1402f60540d13c36700a8b44f7fab7e4106601b1f9e70a03c7b262ad83a9f9516a01e7c7f9b4ea9b7871970f8c35e35f08387770dc88e32bd6ec2ba924b91af8830fd36a33d0837be85db1113766167f79bbe241969656f848299f88218757d2509141648a25db98bab04bfe79e5543ffaa492f823fdf4adff6369b37bb93f6a607d73e534dea327536dbd957edbf298da5d7d9afedd156f54f96fe52eea7e407536053cf7129c1e982b8eab2538206b3e0ee40f81582cd970efd5644fad9cf72a46be60c6f537f10a6f688ff4a152227c333d81bda8244522ed828692b3362e1e1489da72b95e14c402478922307856c981ce5cca51772a8712f661d441d5126f9d7cc9b5d821395c7cccc1774633c06a7874c1227bbe284b8a0695582c685817749f7219364335e07068e9264512fb0ea7156be482e076aab1ff85b059a16a99732343d0c3f01b56b381724dbde96093f716025f098329b9dd7449f02d00a1cbaf7582f49e89a2c6347477834cc210947bc3bf93adf364c0e52b95a1c2fad7d8d46345a87b2d83e0b0c2ac7e6817bf6befb6f4552c4356f3ce9bab94e91c835c372da1abdb896fd86e1587567f86506b25ff1cc8137402724630d1a6e6795f0b0b5fd4c94b9a31a81a40913a5d5251b0a82f77c0dbf6f4375eed7e34d7499c9d65fc75fcdd5f839678c6918b015882cb57c4c74d030fd5e06c60661c23b3cb3e30aaee8bb3c66948f776a705da9db7dc6c89728a0716a7058c7ae127dee1c63d95b75324ab28f68ade867531222cbfbbbc7426fa6b245e29c0ce08c05cac466e8d6067f216604e72bc4d0319c93c69282a8325ee3973d5a56ff521dc0a62e33379ed36108e069c38247f2b42b3a1edae6fc9bb45f2648a3557e4280ff6b9209ab9c60821233e81312b5f372fe9de589d205a773c8043d33c16f8ef38462ed9c434624c213aacda13eaf674c20d75d712b4e992fbb2b3188ec9776a319147de8dae1b8140c1f7dad7d16869105dad409a0dd0ca53244bcccb90a397302fd208d6fc4decf8a9c147a7fa33800f5de467238164ea008916557b9a8f8a19c00bddf4aea3cb139f5f0743a83641b764917b8fa07d047d83609ebcbcc9ccdd4f3a4677b7e7acc37467afab81def59a09b8960694d199d0b62debb85613acab89ee5859b41e6f6eb891fce67b290289c0b33419841a70978da9e711a023a9da6941d5122660c84844ebb2b087c8eef95eb0e0ce5a8a1b9494f16e57d05c1e3a0fe13730f9c9fd6e026d1e4e5b68870ad0f832f5b8d42a691bc36db8f459f36c84bcbade7d19d89fecda504c6e64ca2ab9c710456130918899ea439ffdfd4728e2593fc80354cac56a517c6d0010ac764dd6818380ced161d6a89fee0ed9afe545dd749b6006ca89220c69f8f39daf7bde019eac750a129e1612de1c5b8b6da9e438898d667645789e12cfffb0dc5a1759c98fc5b02b387f833aa559310f062db5adc550a04de4ad05e7ebe46c7544d822dafdfb8782273c8a95c0a707babe9438f76fe5ab46335979328f0bf3cae9b4757b7f3ae364efcfd06a83122f0e81bd71a0cc22ed62e9614124125af12cefaef02cd343550b8860c38fb8ad0cd2d5f7029c1180c00007cec855a43d54abddb4ca207660846fcbf12cc9834c97b2318e2706fbb8e75c9efd4a124f2608bce7b5172e7dee2b8dd24d9cf1717a505051eb659b7ac3b0ec6990e77e3411ec89a86d7c106b21373d4f5ec6aa034e24f29f9b40a1575932636256fe1c2007a5a95db515d54f2351db807713e3ab3e81f29a723348b6e0a1cbd158d36a676f3c5da9f85ba3094f7bd70dbc2f824f4640bf6f4b210923f64c061ff99447daa9fab2d10cc8eac73d8cb2a398670bda1eee8234f747aa1650d2657da29ff8ddbb3ab44ca2bf9097bcfa1138391a68482f49b86cf19f345f81916a819ca3b504ecf853840ae4d56599edd4cfe61095c9bd03b69c75921c6f4009d04da38357c226212467928af5885c8aae60b3ee956e7f96046165fcc7196b2667d276980c4f8c51c143685fac6243829f00e7c90e63a59fd993261a1ded0b202e58c4c076be600272a364d229c1c9139b3426271fa5d889eb6522142d589a0420323c1e53559b27e161d9fe67d28ca80855b3debc04c6c906072584ff6c051f6c4e997c74838fb9d157e725d55ef61ab258aac8a18d1042a5cce74833b4e1151d3ecb39d9aa6db8a0dea13bda5854d8196b41c2b61cb0ab2c1d673d280615e84e2311557d97e542a09b359beabbfc494d45b810e82761c3c049487cfc648b7a9bc27c42e68fe89f2e23f3e28e4958e3083356b54fc04d1e5d70fbf034e0db313192aa688bf60defaa81a0889793e68daad33179b924af7ede6fb6f97d6a51b018e3af64dd9aff4879816b728e800f3acd2f2ef99feb4fa6f9860be97b95e9b9efed7ca5d0d3594ff73ae50f64bff6036a92be0c1097e08c24d1525bb1f1047e60946366840bc0c559c0c47716a2c79dfd095fbb35f54a57d0f2822777bc5a6e6783981ce89a55999814a31b83a05ef1f54f99910a78fdb2202088a369fecf5209531f46acb16648c03232b24b9e0245266e3d9d08268a59c394f58acc75b5a47fb5088b5f8b3d5a9602b4d6040a999a29864a860a4cdf84b6c3d26499c6ed6e2f71a74d1a7370a1057a65d25fa7bd34120cce69e954d4f7ed3b510d6c3f6e99fd4d24509bc9ab57929b742609acf035507574b0f619a431dba47ab9b9a61cb8b09f79c694c392ea1bc3271042e2c835aaf211dc2798c58ebbe15fc4b66be58859b631949c78cb0c22b42aba140d28a50dc5c55a8fa56705028dc1c044576a9546c45ecae16666dd4a4c8d28937d66d89d54a5fe386d07c18e924ddf712dd59f4563434b14bc406def999c7e9358ffdba647b9420f4e3191ca553327665ee7f68b0f6525774899f1fc840a49f5de96a5775990a1f9c7caca4e6c55e4af053c36b95a597f5c6a262c44ba364a551f21dc6d275ec05cf7a7b95d24ee44a02627283ed6e3e28202bb5c70d86bc83a7d8f32e2d15be65d53926eb1ac2031b0ff2c860f0ed23dce8ef2dbdcc3d588fade57de8514b067c257800fd300fd1e51f3ad58691b4d0bcbb549600970cdddda5acbbecdcc277e8f01bdf693869a4234b9a6cd216812172d705c8b69a73dc97c31ba0635f8d0811ba7b118b9aa855dc0584a02d2e5941ec1b749750255b3a9bd418ac5117c0c2f4e3b52f4092dc915ecf99af53d2aaddb94ba2d41b3bacf405d47bf7886fd3b5b0c5cc0582700453fb0a906e214cd35247840a12f344939f78e7ca5adc366d90088c01223f66be5110460cbe00f1e84a9128436c299f045500ecfee680d69fe14b27cd3418b273001b43cb65b4daac709bd4b4aea000e3ca8aaf95e8f60fae327734d716aa8d80930aec558bcc424bd2030cbfbd3707de433ba43c6122c014d63e052c08d0118f14980b576591afbc204ba19b80dc5d047fa7f7a3ff92e8df5da75460d85d2282bc0840f9b9f78f043fffcd317206558920c8f5295d520d88779f75436c0171eab692af86fa0ddc7744fe435522cca42fbfd081fea78fd7f6b984222219da97851bcec481d7845ce2f55f1c33bf6ed7517d949e698221c74a21d3728b3748a1f7ef0a3bb1cc917e656b37b2f55bf3061983a21d25889e4ec34a8784f6af12ae3d909eec0d58f730c2ce008d5d5f72eb9427eebd4423c0c8b61a725bc0f9a121b5b3a73c551f71bc72fa0cc90d2a21713052277e2eba3b5c253a8eda809aa671964a7426afdcad8e76005b37d918ab051f27dd13faf625cc0686923c385d7fc1408aec4fb0edd4a9db18c3d1b1023c818597fe145a0be2fc2d1e77be16de7bdd51e1ec88d2b0d859f3a9a1b85d51cbeb90c3961dfdba70952ba444ffaec9c233604976c382678fdadae4a0bae5b971fd85f5c6c6f38a1d56db282ebe3ef698c7e44b47212b48159a00c102e4165aca1e4ba0f781068753f56835cf8eeb97c578a92d0c020c2df5d9d29c532814b7e66c02d5d5ed9201c07843c4d8df519ccebcf0fa05b091b7b60a1884bebc103bae7a71251632517c153f982862cd855b904f70108efc6951b7cac2855c2bdf3a0658552a3f4336f473ca5bd12088fa3becbc8f05c1189d01012faafe0471c262f1af7382ed398134c41ea6a16958a786677efeddc8b77240862b30d07af6ade53dad1adb8d01fac102ae29db97e1d6357926311ee8a712f5b7f23d4353790a988357e13dcc119c5d9eae3d6696cf81ae24748401fa270dc3d6c5280c4403eec3d35125e8a8d3154f84a04d6751e00788a62af714ce12244a61ae16e8779fb231a014c71005fb58df9fb37cd0a916f49fae00ba77641461967b2b493babbf9a9d544d66dea97c3015f2cf04cc93c8dc239557d8503a3824878c788da8f7196781894b402fd8e2d89d30dee8a13eea62bc8bc843193e519dd70627b56a10a09372ca7a609d589c31e755900b0e11033a624200deacd23d58d5a261dcd289b5fec7714cc15907b986fffc9f48ffdc041b6707fe507a3b91d9cd15d74176e6963e2caaf777e0555c0f22c0747b275eadcc03560548278bb0d6ffdf9ed91624299f8f070246267dfc85eb161c05f6cbd9445c2fe0e17e2bf3425050ef35ba3cc0d74a55fe8d73b52feac3fe2106c18b0a8bbf02b207170cc541b61b829e8b958897ec7caab7dc79a17a886b5c2d0b27f69c29f458c6c64e24fc87ed1eeddee1b0ad699ae2fb6f79c664fbd7fa7bc9fe62077c1b5a20289650fb9fb9427790cb786720234980d00a435a097d1b7709e40f0e33b6180f2c56fd3eee3c7ab131772f57afc39e9d735edef9b9ee0d1ab9519fff1e7f6b24f685f8ed0ac01f199585590588babfcf077a6dd39c7b37ed85da08c9a4d42ec6112877cd25e793a398b763075bd44cd6aeb8a6d040612a5c7197da9221a1fad69d837c84b8d08fffecd18799f13383375fad267803dccdc461f53c2f255b9bfa28227f182224abdb06c128548006d3ccb0442d88ee898f13fa88fff7edbced3f26c8ccd568afdb6e481c9af5b21e4e11f79abe4da39c4ccb8961891f5492e5fbf0fb81f8df23f9fb3709714e4fe55b218cd035e6cd0371a5344e4ceba07f3404e20f6a0dfcfd232202345a7bc185cda2331b4e6f38f18db2b1ee94514234d9a4a412911a383a3149400793b7d64e4d511ceec5899d5b7d483185f47ffab1f1ccc61f70165c0f68e842e60eef4014fcb0bcaf6870bb9258804b4a2179b8f372818e90ea2cc5dd208031583ae89fe3e012c818ccc361b26e7a6a67643d47d7a06788f04383c665a7d71e424d22f206a7ddbe0e06169dd0e9c900ac2edb6fd67da36ace681ad3dedaa02b6f7306816e22891715ef946ca29b12a6a2f6a43b1684697740a0ca56261073dc15941cf8cefcd7760ed44d676eb9f6590d52a7a6ee80814fc43593a492d39cc9e6e80e9f85fba34751ab426703d33dc85ec262c751ca69326e6d4104192fd9280a1982f32af1bc0f43201a773374788be3f39d12ec031e11b7008733521a20f15f38e87b0be1ce2394f568bac2b3aef576a8b641267ac81f41506af7bdadb5a75ff18dd1c801b84128f733284e4ab2b7db5601eeb191b98ce5a23107cd0c7a01500f194df7c2627fc52a2b73fc2d955d66e14e6560e88447587054b8ba6dcea50fd3ecfd184388f7c6a960569cd2a4da0be53568e41a72a6e7645e1e6c435ff92804e925857e9f06622170510743db2afde1a329dd0953f27f5344afcde33181b6f010adc49c8710961b92dfa7cd2f55f2b0781808638e209c4c5cf5aaf94166fb1824bdb3c956444aa32379b79743b438972941aa811a527378863190c31bad24304fa9e4059e8afc284b980587683a8f14628b0711709aba9cc5af570870e22e45d3e84beddbcfc382d864324d9eb0409558bd437ca2219ade60228ba6b4b4ad13bc4de71568e492f8ee78f4b8ed1e2228bfb20e17920d8924446efa5e1a4f5c343ea31e9c0db8870fad37e4a1dc86f1618aac9a91a103d4f17bf8baf70a1ee61672b3faca04535b49093a155e38361cf78521dac54b70575ea75915667da5acf9e7ed2a453b015125aad9a8679137e696c4c947beaef0e6e84fab616ef04d8b0549e835aac8ebd9c76dd01dcf1024f2fe320a171f318be32efbda1c7582048bff3ec7196799b5b76d8f97df001e7cf9ab8bd33bd45bcfb73e6ec840bff3abb3979e4d2012ee291e3bca107030f2ad2043f0601ab1ff1be9c7654bca225b14730f6792d315542c73aead0c78bbe4433758363a00dbb3418007195bc1707b0bbb00861909a70cf1d5f3e51ae57bd428e793b071c1bb1240a7e3999ca9e9f57eec805de1c6d99dccf0a345e8c1e26780f32be0f849a3390619a89222be8219617044219a5e20f6c99c2024ace24db1f5b1c10a597fe6583de0d2657ad9024e0c14a2757f0ccda2329a077313a60aa4707da658e6abaed10fe94b078c625cac3c0e75b1be553179c424866f6e8a86e924f6c365abb22f4bd80d0b52d774ad757c231fe5e461f46312f310a37534873ba75162f6febf89aeb0ee1304bcd2f63284d9ed04417df1f9b5785b39b317c565096a7318abb0da0e264e77f2a28b41093569cea1a7b6001e557a9f540a3f26b094a110d0b94687924fd1dda3ab59a3c0138beb014a2ce2a39e3a88d69d98ac567cf394e31205bbfd3a7b406a928adcc6a604f19a30c1b06dc464d514f68029c2c7296a10ad178e9caa7e3202f2b58e3488a643e67b505017df4d11b81647b126653963c701e645cc112bf9015789b4ad71e6eb450e30a957ca0bc1cc935682503a6d51c79a933fc8c11ba37a1ee0941236093081394ad414e3bac384846cb7a72cf9b92e4e102b6fcaa288de03ca052c1aba40282f219f41b43b95d643d2cf0c2c5cfdb704b3208408f3fa3b50332e06d16ef4444bda02edb258ccf0cb8577824c6537389b8c4d0db14aec3299b84ba2165ff4bc4a6b98efe2ea6a38bc84b31f6b3194816b6bf93fa543a2711504cfc41b1c165641e77a718f310967289107bc231444d3c921540aee9b7ac8e3e9aca9b72ec18c266812a69834141bb9c70b4c99d911961e7ad05e7f28085839026f4f780f808fa168b9e236638584209aaecdb0eda555debbf4253825fb0bc3cc63502dc854cbf4341b9fcde7f2faf67070ea4b4b017ff10a8f45052e50d416b58a5303fc6c74556936682952093f31f119ae24bc07e7ddf3a6c2d591a85d96a0fee331cf5ab0ee6e9a30abbd45814d9790cca5fda88f586fa09568205a7ce078d04c46356dc96865a1a15c3cc279794593521988d615582e0c3940a9dc9f37927f0fcdd1aaae0960d36df722dfcfb02ee7ae0485231ae9af86801ce4a7e35f3d3c6b668218668eea9419d2581f1e52a3bab9aa42680e4b8ce2f06a98d7cd92b42ab46410e58d2443064c60e81200b38016aac53148acfc9ba6a9272c8fec5d3e852d0af0eacd018582a007be737edf271901d1ae642f903e319af0ac8eaab754e55de24a56b338ef2fea6a20af7e808ada3c78eff9ab3193f11a4a138078c66531b0053b691b7c939357bf3bd7373e9bb316934e6f00d13a0e488ff57a4a3f68da70e302ac956ab45028908d716a3b98bde9e9444f4a13241afdc42a457cfaf7e4f00be92e45b5864d6785102881d525fcef67c7d7348eb8a0da8e415f6f22cfa9e398cff8780d12af751a08ea5ffb8dfe8e747f2d6b883347f8fc3c7a29b2d9b66a59f3d3a8cb3649456bc206d5e301c822b7be430de4ae6a7ff214d937cef4718477e252fe6bab45aac5d1872ba20a0aa53f171158852e3e1959f2ad3bc7ba5b63cb3622a8f996dc66b5b71cac32dff3c363e1c8ec309d586e5e6e8144894325ea63836d56882ba1553a1c13e153ada13b49d0adc49accecaa10370d5bb43357c8bfb8045d6c4d105b339f76746d297d07ad8f177dad9f23596a6ec75b74f6fd692bc95a29fb3139bb200c550b553a8e371f7cd1b06b33f5e308729eee3f417dd08d3129c9bfab52d32af84e57d117aac2d839422a813d7f68471cd87d322d69c729aeab06aa3f56512d8e11d093bb84ac765670b94740e85e656168a3a6717d3aa9d2d818bcab86abc2f3869f0c563b12b048054d8369f16a08ead9d75ca920c769cc6a7315bbb4094ec817622497ff1865c86224f04f6646f899a13e8da9717133ee6c6bf830c3ab4fa90f328f55d8faf5f445620a9ec07261c74b05d34e11b4ba631f5cc14d5b1d5def056d978ac35a7500be44962c22d25fb878d333f6c13c3c9c5c811c220b83fe976fb2deaa8d980535cbdb565aadcc907ace4f6121fd6075cacbe7ced5bcac5c7cdf1b6f1230ad67771ff749bb994dd91c1f19eec37d33355ecf6ca51b49ca0baa9906de2c4f2dab6704f74d9e1965f9aac5ac4659a5792b1cf6ca60e818e8d23de1a43e95e88c41a995c90ecc0ec22a676548ca6ee6230a153217bda9dabc71c1ccdf6aa967b62d7a8753cb0dc78c835b3df663ce7d700be6d90b55f4037eee03ea2a1a910f2e511c1da3342727af92d5fd7ad83b86fb6d5119d2eb6c9358ac765528273b18d831c370f8c3e626966a13679469b41d4ae427b930049649565a17186a368ea679e37c0fd74c5f55eac3641ca1f2a0c125c37cdd22f12dd3639b7674cca3d0edcef440ee648690a69e96c9018d3c41f19ee6e6ef68dd1fa71c7fa7fd6a99cd04e8e66172e282bcf9245f4a6a8c0d5840b26c57bb6e243b95e9395c79be7bbb75c47571bb83f8fec0de3e0b37c33db2188838ab67a4d388893d58b061aba9f0721ec167f248cb02873e77d59752682733eb3436343aff1a76ae51487accb15b2c6220a157b3538bf8048c8b1834e9ed50a6415ef771dfeca20241815efb838331e59f63fbd2efc3dcf618755b0e8b6d4d0d6441c5dbfd969bc3adf3e1b8bfbf5fd4e212fefb093474ae278e7e9e46eee3231394815e0e962ddc696417a9503d8399310c459f1b1eda2485717544a50418b3174954d5b3c0c30284bd8ec86055be15949821fa22fdf7bf1db0f24ab324ff74b4c9e92b623f8f7ccf1759a534ed63a88a8595530909456e571d3bd3d7c6505b28203ed41b341a5ac67fc4fd82c184ad88bf903cc33adc8d0339008c1f2b8121d908195d2569e4a81f601a0d123f1b215905a717c9d23cb568716b0b7761acb2603fc95d4eb45543e14b4c295836cb48ec97b15f2411d5e1e285dd057e3636def3bc225ad757c23362aeceae3f7e819172297f8073457bf8c4996e52790c0ae5e361b6d563b74efb22c153de1cf75cc075856c86c40ce71bdc9a3211d19654fb457f06c64bd34d5e0cf30ce0b224a22328d74505ef2590199fa8e894d3b285f81384428932b30a644411ee61626db9ca111369c172c6fb3cfd09372b6c884a8e8cdf6c3c8b6c80800a9c42cfd4600bc0817079b61f72312d5cb32ab465a5dd8df1e6f13e8455eea31992ea86041188507e92cc6e7ac90383a25c88741d19fee86760804340439e724b4736e90879cc26e3117b1b96bc78a91e9ee562a0c48012c6f38f0950f8f2797ae61acd7cadbfbda4dd651b4fcf2ba87fab9b751353ad772027847e67d033c4aaaccc05daf4f8a736776bd890c8e123ef3905d055d072426127a717829ea04fd0b62204f25e12d48c57b13a8e7463309c83cc3c6d620413e95dae059ce24692a98291891b102fe314f1352e0fd91499aa48f2e8b444edcdaf736277db2d09f80c98adae794d534de325101097ba05d739bd7cd2899583b67977487a7a6f3e0f13e25682760dfba50295dd0fc82ad3095a76292056a66a8c6cfc802019a73819e0407164aa60b27603e3653a45c93407c691a982c9da0d40902a3d0f683523fa6cffe235e56b3f2f92d4c7f77860437d64e30a09f490a5d7c70f39db4b23c8c5a7f37ad5935b9913e2e755e8dc18477a03ffdb931bea03535e136922b1e514bb0bc97bcc948a79c063e274a61cdd7cf4dc9bc1431de207f08d7cf75c938148886c47e9e988c100232ada72d6928c3530ffd85eb6eb0aeadf4a9d7be23039a88d5eb8aa6707c88b0f5a9067ce15cc62905875cf42859b1ba74c2ddb36dad5c8622c229ddd1e4174f239031037e9a7a4e0a3947d359292c092387804039cad6321936c9a8cdc17d993634817d95c1a5e4bea3bb728e60da7da5ad46f1f1f5986542c84eb55328971250cbd649408bfe9896314693c84d021bc7da0666b257ca0b1cfa811478e5948dfd1703746c30cf117f848b40f01682bbf7f3fc7b5c5c16919a57aeea9e124a45418e148ed721ba7c582ca6d14d560a9c7c71ef32f8e4f9c9b7bc9fb99d9174c45bb238a879c75bbc79fc76704ceba7258af664177211ebfd66e11c8dfd2953b87e01181a17658ed3576d572ae5b42b7df366755637108d4b431dafba62aacddb46efa2bf82d4c48559c9347305823cd5b8324c56c923b13bca18b6e1ba1ad6347ae221035b9a83a5f27b9bc1ba2c65b8aca4d36d644d22381c4baaa8d0c462439652df63e96449b96923e70c15e43254aa89baa549e784beaab4e9061671b648d24efe7b3b5ea49d21ef40eb5e5059612b820e0b89730db20ac5825057eefb25b86cd2792eb3275ccce960f8b10b0bec0020dcc93610bcba5a0acb5e135c67f3978570fdd739a0fa6343b5a43a14d26e4ebbae0ad93553dc7a6695cade9f034fa3b15ebc838b587f78217897327d8124da372bad0143fc0f063d3a02f4548343df13c5240ad4f0e0a6ccf2875f2b7a18a4c90c333aade36b3596af339b287e90f6ec749941718019b0b6dc4ae7ac0b968741d6783ecafec30b8a87e042a6ea9f53630606a1a3c4d6a9bee5aaf1d4a979f41f68c40efb236b0fcb172ba10fde5289ddff7ed50b763c35e5075ecf6449414a15bd606d616024ddbab3454f940a64b958acd85684b40cda3b6c5245b38422d7a3a54a08083271120e65fcacf4b782415c2d21ff034011a120db5783589acc177dc67694864bed5713e4516db58264657a600d2bea9fecce391912439e7b2fc3c3161094e8639b46214edfac6aa178b49550007611456b0a17bee73c1b55cdb1ef155fb7b5d9ed605964c543d286719ca4438f2071480450bc0c1cd44bad920313ecd3f70f6f8d78f2a1c5b7bf2c4b23bffcc05828a5489ea0a4b66e8190eec9120e7381d824cefdf9792495bf7fe1a6ebeef23c6af070b56b5e54cde44b7e507115a8e4f8d1d4197fd2ab7b8795bf701831f1bf0df21b3beddd2f470765a529a23aa8c4a755cb3d898d39031065f6e2bdc9c60894f12d1b79e4f13d23e79502775abfd15d54a42c59c48306ef79fec4ba76b191f4f43733fca00514d6267367a057c42e5578bffff741ffcd0c79201cbc0ce3045baa9f4241fd14809d5f32bc178bc709b6c7949394efce4b93448408059bd4204ed5cd48608d7287e692e5e8488765302fa504ccd65269f541c01086142f4a715b6a1f2fb1bbac3366d91a6900b3750e681f015256201e1173a2e6dce48bb83c114cef2bfff8c564b3836dbb0b59148274c24a041edbbfc4ce336e9eb51391ab30afa1e62d47dc11db58aca8e872fa126d13eba3729681e5cbc4b10e5faf32a7e84b8362d155a7a16f27af5750e5d223e4a004870409f02d4255973875c533f4a78b0795e813334319a7a3a4f36880a86d46f99b76b1814803f3279343814d8f980e5513038ea0f0461d9ad718afa5dfe8554e34711a00621ea67414797fc1898a3979297a8bf04e502e119fcc73353deacb4c6e910ef8ae2826767fdac30b9f4fb26fe93cc1512a0c1c0f055335f1d1026ab425e80edbe137c42759755ccde3a703fa7f8fcffe0eb0f9219bb9d2d571f9219b23711231eb48d6421e3e6cd57e0b1fb99473c415df767618026d58a73cf1f90054c681c31988ba9d4a013e1a1cf8eb9015a32c62d117db16f3e3c7424b52d8f75bd54b99d9ffe024772c10125658e814bd67e8db2075b7f663cbeca7b8b96573eec67ecc241c2c5c7f3c1e837c2685b5e733cb21201712ed0d9be67702c5f56371444fb792f10d8df6cf3b28b55b950f98123055f97c039883102a48760b25efe6c70c94ec7a020b252fe3ef5e5ceed9877973f1d7d17ae1e301dcd44822c72128ebcf149f57163901081c0e5a47a23556d88ebf51fec757f38b87fe6f68cc34bd29bb36fdc77c19e01feb061c8437bba8ff1c1c9cb8fe77d6b0bf9dd933064f2804c4635e6c7f36afa1aad138523e0e8c15d5bdeabcd68ece9fe4c06a4c98df6918dfd657e030838eca2e080443832b0703d44e454e09d0acf0d0df27e43e3f9df0a003f05d7b49102d63849de00803d2527b285d1f4f9f87d2000647663846af838b513824ab2576ec9d8e7100f1745eb3ed4fb4796142245105818d008429ce040c2376fada931a490f225c7297c58f0076a00f88a2f8c422eab67fa75cbfc4ca40be363d91df1f92d49b7bef20114aab86d3fb4c91852e833d73e64c489e44fd2bbe810f1d534e20bd7cf9fb276d0a896f5f3ae506a84d5f2831ed0c9de277079d310440f9cc564430e97a541df9188fe49b9abd8a203561e77022b6dd1ff96ed6aa883aee6f3ee00e132fdbc8c4c4ed23b5e7a1f052a803b2f052106d87bcd8940e7e687cbef6e19a72005b30762d84e37c17fe121a8846dd9325ee8df5e60bd5f30c0d3225306ff6227f06d84218debe3ee16fee70f24a9d0097a4913ac309f619832ded87858522f90ae60a84e01f592455ca38ae13ffcedcf3f14b3868fed29e7c405264d143e6704477c6824aeb2cee72d7cb8a22f56c9922b4552777833fe331cd917635534929f51768dd055ba8ab053eaff83c8265dcae994cf52b99478b471e97ebafad6f13ee52f677925e28c1742cd36baf0e61d85658e080cf5c26b86363a5002a4d535da0407a29ac5b5f8b4d730632f76e0c8bdaaa4873602bf275606813f53a82552aa44eac4bfd1a17d4639dfd3b8189643f464803781640a224b54bb3f0cecc8acca6c7196be52cd47bba012201af5a42e40d19e6f014617aa3f6306d8673ffcf12ecfc3146676103c33d41775b420e199f9a5ccd9e69f56532ad56d2f09da9dea36f59206d65e1277618b9f978836342374875ff278439766893276c298271612655093bf8df19fa8f5bea42e94337b39792813be84f84f6d91a7c22f52a86eb9605871f3d1a975ea41f42895826568bc51c4233e059792c3e9daabd2439c0e343543bef3afec0dada24458e63e369c6e42d14784b4d3d0f1a801d9c1f4d8d9d0f1ef112d1e96f5a188f9be74c55f00b8cc31466bbc07405d72e5f0907bf6f05a29c7c60e0f497f7ab2342f9d14dd82bfd0a7ac63767b27d7cada2f29aa7c7afd3e4a0745bc14863c4e973e39679bb1d016d8fabe7fcc47665810663c078ba646cd126b2824b5f2448f194d765f22bf6116073980a984ee51966eca29ddebdeb045b9d09198af0f4b427180960e4429870cbff7054e9ac0118d663e7d352393243698f55b613d8e00965438fafb4e9f2756e80caf90243a48d2b064ad4d9c443c77e05024cf84a68bbbf69ef0241d7f04fa566cb719ec6c99005a9ee89032eaa23d93f105b0c1f4ef96d83d85998efe6918bec970e158f387015843fcbe7d9fea1e748ed5ca08c06868f6649363d86100074b6865f508af811c94247fd87462fca1b5c35763e21410c705c4b1e07cb081d632943e7c1e3d4f2edc22d698e85ac112592740e03c469a7fa8875be4d92dfdd008549ff60408f9866ec4c6e9128ba031c18285686c5ef6fe31f3ae5dba8b746b7d0ad7b2f7c629fa0312155759620ef37f4bc6c349c6b46087f91fa31a4fe51583f1138c7908a344b937d0c900f058aac9b2dcc12c4e90c093b5630f462fd1a8ba4cd5251a9d91f5982a24bb3f9e8b42a6f1d01401625535d7afd9938fd84ad2701a86c81ad463c49b869012f2c9655a7a22d8a786a2c1748dd295fc289ca0ab2fc0f80e16956048c51de8d5e1720a6b4c2ed0a824b55c7f1bdae0cf278d490f0abdb350c848b88992a9e456793c853bec5d0b3623d693f65e9d12d0af4fc2519e90b5e978d3c9ef0a28649c16f6609169ddcc044bc877e50e9102a04c0570080bc99533890e0c2fee72fc7bd9f1d2ab90d079dec7fb12b43a4a0579c7cd26be8cc968659dec653c3132d026391bd139d9f9efb71baeda2200c77539cacafd6dbc9d3ff142a6940b87212ed03900e936498010f77580b62b52e6e22a2b74dbdf09535fc7e1b2c33d454b61f7fbbe9254b46b58924427e0e36464f0985de1b153adb9ecaf06b007a8dc6c5ab86e7d76c266a428b10ca65faaa1127bfbbb8566f29a697fc3178a3a9938d202ae7480f78dc79fd8eea2d261a56c17d609baf4fd5195443db72a9902abd4f488354b660eb722ceee9cd58ad881485ede5314cf48955a82d44392d8b511dcd5d7a6726b4bcae7825808c704e8a880c892f607543711c43a360c747b486899a22a731940e582c34c6746e476873e5d6ff2463a1ad7a4d266b7bc4a63843701e25d4ba789ec91073fc655f2e08ecbb91f32aeb746a37e1eefa5347ec160912223fcedeee3175728a220d08b2c314cf54569da8cf3f39032f5eb6b275c849b066f0e0ca120c41da2907fdaef2ef627e0d12834cd2756422aff55bd4bb116f5f0dca276489db87550b1e38ed98bdafecd72869bfab0eaf7d114eef5e337bd7c10b9f2c69d6d764bc7906e421edb6ed9c9ff06f58e34bc004901784489a71e00ec1d90b72819d3b55f47922a8ccd7d4c9d4f7f36fa2a196cae1998c99a9d123743b57110d0e3fb0c744bf894287a627230b00a5cce0c0db8add0b690d1862101b07e219f1e4ea5eaf4ce0cc89f65f88f078c974926819cd36804291b8cf62b69056c365ddf717f0864b46f3c7ed7e614af9f295c9fc7fe0eb3e2101412cd38fd9ebf95a7750c7ad60683a26f876e69e33a03ee7887e4e2e6e54dd5d048244aba73607e410c7ec899cd2b7b50d51f75672e90c143c63f575e644b1d6913df6930e21529778b35ec01743d95c099c76f14ed0ee6ba80b127a25697f5fc885cf6f260d299884730fdbe5e7f4b51c270b9699b5dc5f4f8eedbc5fc85d33cd343d455c3daf0300a6dced162ca522b157b3d90c82354a9778ba9445d89ded62704278e52beef9f95e7ddd25aba3afc7e47f3ee878de91ee837acab605771f4f5b72c1afa40b76bb8635310d56a2bb07a99820bf686a34e5c8ccc230c8b4a9b91e46a096dd85e16ecc40e97e19f0959846e621a4b72e5dd38104012da037c10d8c2993a94960c2d60b3bc8d8a09de0ea1e7d2b40b26c2f1446e7bfe41aaaa1878e1da14fee86d9fe51b35c719e1de5215d78868229575f5fa3b849c6fea86a2a04f9acfe106ef670e0459d044fb510424b82d3fa3ed586a052cba5356949103e945cb4da21c0ccb16b6542c2c382ef5a2935a1e9fda1451ad5907f10486f4060afca2aa4aa0aff201a49b403454d7cb4d29802884986baa3ab96280878763b51e197ca4c659d704327dd8a966c10e969ce02af81411f5968e58490de59e730ef83dab89a3a123fec9cfc8af360e27a961345dbcba8f78e322cee41079ea15628b1c382e9f765e17aade169694353d0956d87b0387bf9494f6c3881d58ca9b9558f0bbb18082d4539b747675368823213d496807fcce060c3efaa8b5b5f6abd204ff9edff6c6a1c0584908cf483165a98865e785fd0a96556c27d708bda67b057929d6d4d6913e9d64e90838b92a86addd526a9fc0135d4c162f216c22c0779bf7b0e0086e014258185b8c2ca2ddbc29af6c7bb2f3f39fc5e77680c6e0604467256477245307b8367ea480bec0c23b86a35c937717f30d3dee87a46283e75f5f3f78c74071ea2764f53f66b893f123412be41b12f8efcbfab0f48dbbbdfbba5f899d0a27ba656ab3d4f16532372806f5197b9ee60dc89b69711f88997c8c745e08fc4d9eccef93a7cc31576ea9cd0670e2e017ac84a8b2aff23b3b240e54e27046cd469a25cd2128838e8bb54a218ab7a09e0aa409576d8de1d68c30228151b86ae33a215674cd059defcde2abd498c71fb1a9a2a1319776391cbe97163fa15232e47d7c6508756b25eb81563c12b17a3477eed186bba073571c1e766e54bc79ec58a23b7a7f8d611ff75b081659b59a4486ff4518f571a8123c6545d17b200b75618a7948a703b46f375837b33f3c810b53758ccb5a76b2859709bc23da25cac032c4153fe1f3e1643018b41e733f285adfd6c392ae62d444f98100b6d22b8c3240d21ace2d1f71870eaad62cc139208548d7739920055a703de7bb49818faac984b8874c9dad3e61bd2414f95ea476e43a4f2236a65511b430345e4eefca155816af2bc16229f41cef905677a5e786d64a790bd1b2ed61698b4f92a040fcd5a896a2de9349739d5b6ad2595e028ab0ea570b21ca1c754ce95a6dab084b4a70bf18f2c1953d698770708b1c42def9becdcca4c06f3357205460bfcd901a1a0979c4dab3bebed5bdf4bfb2b7dbc968adfa08879f3cbfc96a285521c4d8fc553eb31dd84afdf382b4f5a86dcb40db0adf644affa4387b996601d657647be5d384801ef5d841da65c3fc065cec94b333d5ad8a03b89db3ec1c4c21232bfa899cc079ff59df4fd78d7216386b88e462fa40c8ba7b4a30e61f0f0fc8cc4b73cca3fa4eda9a84de6444ec58e6e338ec1747fb15ec40afe8643d325e3fd6073017f0855ab0d994ff728fe242112aff087133da467a437f29c96d0f5a9c7d5f3e158a7c9384d10f4900f015dfb1096500586da61f10183b49188971c27e24aa620a564c2128c828653981fc5e9f034e52d9cfe6c6e222d50c0cde28d2206d19f723a42f88524e7b98b9832c45bc4194ee070df3d9081639f5b91a6811e9cd52025d2d259720de8c4529f311111d911e2c0a6bf4d5294e2841b819e5d11b043d4b0844f5d6d4708901197b5804f4756917588b02d97a18616f43e1f88658cfd8a863a01ec49bc3c8c833290876039da4b4f7d48d68bfa6140a6e4c22f6503d5b15a03bde980d07cf2cf6a4c6cff391abbd24d494e7201feac8c3c4668fcf9565a18622682be0884ad162589b06f95c288ed290569cc527e5425e31d2a5bec58b53cd7ef507840a4162e3be4184a3f496f75049f55a3491cf8b1a1ca017699fa910125cf93eeba2bddde17604152f9d368bd8cc334130f94bbc70f88b8ef9178332b48f8a4c38f60c21778c08efaafc4850e0b819e68b84106e6b1fb2c99cecf181dad6aadc3db7ee7a84efe5d0c9d42dfcd1696a2b7d0eab3ebb258768ed961395576d5e84c958ca2112623875b7d998185b5844901b6a1609297410753f91e9a94361cb1617ed19b9f8e272710a1ed0981102a04540872ce7765c9db290be76af87d0efb2b0aa928e85a54be50626b6181b9ba7526a7d45e4ae8aa828d91dd917ad32c319e5a0850abff1c4c8f2d690a0fa46d98c299e91131279ad55fefd96a6031b728589c8df4c3e097568eddf76c40a6cad256d3447942e4b0218958d2363b3c38ce5b6020df4ccfa1ce2fae3892b343aa84251d1ac480f4d218dc481b3d23c49036408269c428eb5c399b8696bc079662b0c143bc562840b41829860738d3ecaa3092aa46b772cbebcf497101da277be91c042174423a6a7538368083044c27453a7469c5b2ca7c35001de8b6ad60d2abc0b3015a1a2aea46b71af2f0509e61201830f9aad4919e75c0e9aebefbf58ebb7605e942c6b210cf9129b434b999f4074a66249975cab3c23e9dfb30db820d7e629bd8d14adfb0c32bb144d2d2fa066ba613c699c469b90ace8e6d38040815ea69e575b1bc4de766023fe3b2b842a1a7f77532539d992f880725cf03767168c21ce1f4698e0cf5888c255a297731c9756795c5cdea96f97e6f28a741e310dd0e841eeef5debeabc71081ae5cc119b4484b5ac841bf61cb3da27b553f1db4968ef64379c46149ae56159243910f9c30b14c9cd1e7196a4d5bf18950333e8c7622a82d9293bb4e615aed431b40d7cb30132fcc8b4fbc68b361599fdadd228fd701ca3f44a8538487150b9a543190867d0c3b91bceedfb0156f4b020500a02125aa8a7766662a41a32fcdd3bb21a58d94fb69470f37f7e43585b0bb5450c0c9da0b88e40df21e3a12e1b11f17e223ef98829854290c5eb9fe265f860c3ec79ebf78a6921dd743daebbaf151922babb4d43fb80164937be03651dad2692c996fb81bd8ef6cc7b697d9dc47b3282a07dccc95014ebd3749bc4fbdeef468de8a5e9653a27464b4fdade2cf8daa1acf0df840266549205902376a65f295018b5aab2637a5362076aff10cedfd0d788b503bd09413b83b476e06510b422d825c62c3870dfa33aa514e4e791f3b64e293f3451900e98c5807c9f844cd57607d89eebbe71a70b85197b206ee6c68f243809488281bd00ee03758334d8d1736c74e7de7c46c1227f22c4273ab16a1f4423211550f8e96b7265af7359478ac550937c86cd2ef4f3cc2cd6618451f9c5e8c01a879223118ff7e499711cdd1f0731b70fdd7b5739cd9897498f716738b038863a50b25f5c6150c27c5536615ebf828578a29d23adcf516f836e14772f93ee6bc694f69a845f91b3bd81333c97c907c8c885822518e06fd035ac09e05a7a3706d62aad3466c923578a5746c79041029f45f99f04d4fbd003bb6805de9a8576002867b3d4d4a6af0197734baadd2ea3e903aa492167acc9259f227f84116e45d529279031316f794cd529db374cb3e59917da750ead0f3b8e9b68de0436595ec1a214ff3d37dafcf1789c65998c049722c5a4d95db7065f97b69a7e5dd57ad1e6ab7f8af21d4d5f5dc042aee323187c7e4f1d82ce11472fbdb1e2f978027dbd16940dbdff59a1eca22147fc79cf57a163a8e877d8723423e27e6c6eb13fd7f68a5ecd9902e38d0b9e6866cb01c3bf9ab89bf3160ad2dff4e9bace58f929a8676e509a2bdaf6ff9fc27a8b78971447af602f70e669ac636e62d715b541017ae194964ae5c2dd7157a8572f2417c9b89af50bb9370e87986bdf96b52e2ad0469dd3db86bea32df576404da3f3c1f5a085f7be512b24e0045e11393be74f98d2660cd5c94589360f152af1cd8a46e4320d1e885204200994515879d601eaaac3fe8c518bbad5b893b481fa43261a3cf89e14b9e3b8a928055b8b53ceb6b5e86bbb20c76ae3d9cdd002078952ecd4b89acfc3465320d6c75a7cf815dde49c3cab279fe8624f8253f98cee7519998059f6d514bac27adba9fa7b99ea998a6ee41b3631b906c532d7be0fac9f2ed29c31c99e9f30edd132f8df2650e7aaa162d21e2c1e4e2e9ea81c6c085394f7b9d706adbf5d3f99a0147e9ac7e4070624bc6add5b9f21eea422ecc48ae550b27ff94322d174b4e4ece165ba3c02b75775a746ebd046b870be555d1b636acf23b9ba4a5d7fcc7c297fb6c17356de085ba43c28208d1aef0af1488cbf65337715646a7f23381f54024f8bb9bfe387c422362ce92af0e2e2de5ac1a84f75137cd7c66ea4052981ce51a173afa843b8e7dae610622f50c51756e567645d189fdf3a5fe0fafe1d2c56b11d531d62679f10c61df024814dfd95524789ccb24469ce1280760a9bd26fc0754a477b498fee0a81c53ff1cb26ecb5f33ddc867d0fd12a41c787a5c5919e0f25cbf221d67be6a12a4b05adf4dd869befa1ea453723a4dde1e3796f2aeb3418d33208b9e8923bbd6a925ae94504a98c48b7d6127a84cc4141a5161136bc54d0dc5069af5416d383a8d12783016990d706720707f85e8b4aa178a726328e9d5b003468caf3b8cce020dae4c7196cea937cd1170f3a4049db8906257e6808ea8e0cf16051474aa6d5db0df643121c991cbfa7c0291f5591b572f3e8fe36df0a72cb4b6d9e69db7f32a1b5fa21f30a99e7742c2ccb4a1c850e19cea7e11c394c178d5055d15c0b490cd15980b97082a1026438dfdf962f14b49edc5654f3ab2a972dbbd0125e324691b711cc37b9de1445ae644f02e4a618a70248b3232afbb332b58508b7068734f523b6cf7a49211e2be59f1cf3bb2ca8b77f891d76fd3fdd820ff9193a7a5bf067e39d55814119920b19a3a8fdf5434fcd901b8565257e60e404ee02617f3d3565bfcd90f0f16a3538d20c002a7ca78580f645b75514ea4bb5076de34a1a8e05657a89830f40db422bf921d38aa287489a3250d922ec8e620ab0414d48cafa09e28f54a24ba82ba30d37174ef53ab0249f3759cf608797cc14c1ff88be8ab0580b8639eb8fccbe8d4eb298cdd5c6bb4d6473024af389685110280d6b3a39d3395132b120482b223f1040bef91ba9a51f9fa287a49ba5a13fd591f6bd88d3743d68a7b9300a984e0790aba471a66ffec552c23ca2fa118d6a5b987910706cbdd69a486b7bef9da44c291e06fc063b06313186d8f7c3c418d42cc5c499c730f39eb731a9598a7df8b11e91490d8d09bc813071e63dec391613675ecff33c94f0610fbbd94c883d6ce6f5d82eb4338fc77e3e3fdf6d5e4e9d836a937312a15ce0d7796b42a75befe89cec797cd338f43c7e3d3c1ff2bc4b64eaacef1199d42cf57c90c8d43dbdc5d455624f55cf5550f3fc27edecdbce46a82f7fe622942acefc9bc6d7ff0c0afd7e2ace5c54caf23df84da38b09161969e8c811f5f36a967c9e3ea55f7f897ecd51a7599b4f4599a37f934e3427f4d3c9c70728eba7be8f8f9028b77ca65396a8a5c71f91871db25ece66f5f4fc4d6e053d8f413e7f9b4eb29757b336e98ea74e198c424bf5652293ecd52c057d159964a20cba62da216ae95148ac0a9fc7f06fb24d28cebc6f1a6515cff3c823ce3c51290b4379393983d223fd1ee9f37cd0579149cd6c845a79ceaf6d96ea07894c136ad6dae480ac07e5e5666dbe8fe5599b50558c21776380bd3883127bd8c744263533a5fa24f0584528de5698383ef85085c33139c9317c2cf561e26c89be12cfc77efe9134421ee7135c94d8628b34c418b05411479f8a33a5faf4617f9b57777a5ea278ac17b35ed4accdf7aceefc9b0775a78735e57856334bd2e64472f3363c6b722a7cc970b3a6356b73fe043cdea69607d4e452480bca44dff305439995eefa7759647fdf161b0c7b4e203ae1ad714ddabf67ffd30fdcb3b945ee98bbb9bbe7c82f94f6b21074a3adf0e94d2ef2e9799ed771e9ba07ddbdfb29eeaed5f99c1eceb1621bd778e6bc5c18267415f8caddf89c2012286bfce0d75b1d7716ecba06251465a2972ebf2392329162cfe3b96e0c24047ad51b912bff25b6d0f7babeeff55d650c14bfd7ab07cc049e87895866507a847d8f30d1a98e3cefe46316d86b01c76623dfc76c8f12b6e4238fa885069e11f672f45eeffa91d9c8f779ef1788e27e1df0142d6575326d3623231aedffc5535cd77b52dcaf0396a222287a9ec8ffe01b0aca2370ceb682f2211441d99c70b6d4bd7f27fe84e2d177bd7bcfe36ce9fbee3fb1136750bed777e26ca96302bffb9ec7506acddad6ace1a6d3cc9a35cb238fa0e5f1850b5fce3557de239226614888898a614191b34979141027e02c9146e825411b13fe98f902ce0e428408792e4fc1c9f2469d2ac8d00a3206196974e9fe66f7c7f31596a5e5237b240a595a0d4ac1acae7a66387966e5b1362734ab2bf975df045dcaf3bcc5988d62939a6058c3d8e7dff74d30ac611873a344886be8c8a51131024274a402b18542624262f2f2e87a8c6c7f934878a40271a344488c687e3c5fa50dbdfcbe3b12abc2fa0eecb67d31900868439a529425b3d6555859ddf7816f5b625465456330269ecb23ea9ec2604cbaeffbe6ac9d6d09cdf57d0814ab955e61dda615c6e4fbe073a254ad8dbec21ac6c21a86b1ef0b6b18c65c9fb4739c9ddd765fbbbb7bceecce53745dd775b3737767263289a6cfe95ee7eeecd2dd6b6766767707634176a89c6efb6e1d13cda75fdfc9cc36afbbdfbbe77ddff7cd2c14fa73b9ac9cd057adeefef96466ee84be3dcf33a27d9e47f43d337722d3917ddeed664fe8e3c3fc7d9e6ce3fbf9ece705d5cfab554be8d03c2be4791e1da5363e77f7aeebdc3bae1a92a9999e85c215d84c347b78320fbdea6ee544ea935851bcd9f9fc1f9d4fcff33c22666666cff33c8fdff3c0392de3d073cff33c9b91e7defff03acf3dac28d2ea63a2d9c373cf9bdecf6fafba572d71b7799eb7867d8ee7795ef53c4fc9ddf0bcce465d22129d7be7eedea921474ee75e97eb72eee5d49023a7f39c1a72e47877c7ebbcceddddbdf3ee4cfa72a7b6ad7aec2a3933cac509b5867b97f32ea7061b723af7ba5c97732fa7061b723acfa9c1861cefeef8634de66e29bdf33ed0f5a2151663201893ee8576b88e3aa52831295a563c55575655c5b2b4d0482c8915e4f323036b4ce94a46c124546df3925268e41ab906284868c7acc7078ba1c059ce63636267cd28a50965a5d34be2244e268331f15e36c4c34b7229f06f422e3f90ee8582e72098211e5d7dd14a5f3c916a1f4d79db73b7aa575de5790ece32b14e43d2e4c7608d85c5a4f301c164566214b22614d4cccd35726b4b6e493bb8de9a503cb69f62ed641b06eba86e2385a6d7f41a1e3c66104827336a424da85966464da8324ab3165454b7fcc5a5eda6bae53797f65475cb5e5cda54d52d63e0d2aea2bae52e2eedaaea96ad2e6d2baa5be6e2d2bea2bae52d2e6d2caa5bd6e2d2cea2bae52c2e6d2daa5bc6e2d2dea2bae52b2e6d2eacb8b4adaa5baebab4bba86eb98a4b1b03d52d535dda5e54b73c7569bfa96ed9cda5fd4575cb545cda6054b77c814b3b8cea96a7b8b4afaa5b96bab4c5a86e33b8b4c7a86e31b8b4c9a86e2fb8b4e154b74a2eed32aadb2497b619d56dd2a57d46756bc1a58d55ddda2eed0c54b74897361ad5edd1a5ad81ea16c9a59d46757be4d2de40755bc1a5cd81ea96824b5b8dead6c8a59d55ddc62eed35aa5bd8a5cd46c7e90ed4366ad835f937effa34d28fa113dbd857fe38f2a3714d5862608241022f5c89800b10b0f28016aa5071000b2ba830e5968294063060010a4800020e8082010a70020106608200a204000a00964a20610425114200e183271e74e08483264c36d060bc4b32c0e0022549922cb0211d2139520105468cbabbbbf316a28798b28d36ba8d968ab9bfd79d06f6647ef77d84950662281379defcbee979a02cc2b48e91684bb848ca2ff2dde9b74adfb93fb826ff06263523c9bc2542cf13c3252c9b4598d6305b9df0f6dd298e725ab594cdb2a54b9fddec9cbae1b9d7759f473f57d7d53bdfc117ece592b4a63d5c84f2e7cd8a48dd6354bee47c5a292c84d5a758aca7613c62b33b9f863c3ddf13fa589f9e1ff1c7072802a09f20a2202021219a50d08e1db51d42329904b21d43434386643c7810e131349b15cd78f4e831418f990f1f457cf480000223087cfcf861e40704ff14fc0f6b2bb02f8a47441b410448221089888e88220002040908519020b620408408b14048101a2d8926a4564b52a349208112096a43865c304402cfc31e17ea2194ef44ba6ebe5b90c890a20c8a883c4d2075e70445628a4c51640228a30b1815f912ca77235d47c59d6f04340a75a0c0df29303255010554472aa802c991aa232456201d5d6143c2c2025b164916689124690b2549b8b8408915061774910106185892811777c99bf17ea1c108c6061a84c16483ab264cc4e0a0c9184e3820a30327703ce8a08c271e98f1c1933340f8002b041032204208682889a0811194d22061840d94400207964a5003004b595000b04600a0b0112500710410458e0902e8c0004c6883000370e304026815e084370c5000385030c09c03a0400701078823010890430109f0c00214b0c58005ccd10006d491d2003a529062e796c207a6dcea50610adf5941051c0b2bc8e0001666a0e2001aaa50c9d242951a1ed082162b0fd802012b4e2e40c08608b870c395087079e14a1709bce0050609e0c004430e31306189e1cb9d4f9bb0e8806bda41061c981964e0818619c264a1414c0d59a0b4d4d0c3162d639cb690b1c1a9cc0d36f8c0e506335db8fce0a54b140e5e80c80187209e7210e2cbd3103a7c39b3830e4480d9010d0f6072617828424c1823a0c41cd103549a313da82133660265c820e1439935667c48e207331488faa1024044b1090208258408c2024308b1c49921da107186093444349143e34411b9278c28028a238c88224de50976e823604de6953db8b0af144770cb59344111232314547004c91192cd82a4244a2ec020832577d46003264d3870d281074f3e00210411944620a18425004009401401983000029c500003a07000042440010b604003a4a4709ba2c20a2c38804a95161e6005022e44e0ca0b12808129062c4d8d6b197a86a6a1b3740dada5b7b453dbd0373497eed25e1a87cea19ffa4bebd03b3498e6a1c3b49886ea1e7a4c93e932ed439be91f3aaa81e8205a881ea2cf34118da6735d441bd147749a58db400748e5f3db7e5df03ba5ff7bf01381aed755a8dc29ddbbc0fefe16865ba1fc39e9eb6fe1ed34d7fbee4b6cc1656f54ae07de1c67b3d96c369b4d4a29a59457fe7dd3a960a482d17c158c5430f2e20ca83be4f294196c5ccae35364bfdedfacb838658a3f089dc856faca96b31bec9fe24dca7ee3ae053333b333b3333333773a5871d74d766766eebae7ae73f7ced9d9b99b13092396396d8eff9c57d8b123478e159e2a030e381f04255127250fa919d58f35c5c645b174834428aba494a449299e73cea9a933da14c599a2443690352997b8a8c2284a92f644d82f9334d9a0d1cb967064514654196ba8c018e2f6b84cf585d4a53c332597f7f425fffb66dfd366cd639a3f452699d734be8d041ea9c87493f9df6cddc86307fe1229edecfb28b3e67dd3e8b2b34f6c81041e95442627de38e37f5d89b3251c55c3429b20fff54bf3ebf357f92f91a9aac55907dff77f4fc599d2eb674bae7fbdabc78631f95cbf444a291ceed266ee1903c5f073d92bb3e671d67cba220c2eb25c0f4a1e71185b9491483d4e0e430b2fcd9def69bdfc4a61dfd4afc6c5a57e98c8c4d474a52a8a94ad2b27597c05fb259e87f53ccf7be21253d087df34de786be61f7b1ea59db9381b413eeca1f407f7d6746e3fe801d9858aa83454fcd0c595623b95e924ae1cc2ef6f2bb6e02e1839a693cc4ef2b054124d029f3c37d9fd6e61d79bb027733a7d2394ba231df71ae7b3ace5f4cefbc029394059baba653d20112e92df31618532d1cda9cbf61dea896aa8eb346957234e727d4f100c4399ec1f8b6fe7248df62f9365792e97cb45eb64e2ca2a9db0b0b0b01a8b7e7d02c13094b9aa8bbe948934f4f2a97c1e6b2f264549ffc65b208c8a4d66ee36f5584fd3794a79c8befc59a59bef6f9c45c5f924aba4d4d02f99435686269c35d9535de22cf62c4536e2a409e34002512130e8a78707f6469c247b17dd41bbbf4929100c4399ec9f8a4de49589b3cdcb29ec2c4993bf43149508c127e992469c249b8986aae20a893723d7f5af9732834420d187b3c450bcc9c498787b176751795d4fad1117b9c4998b612eb1c9bc3723f7c65946f6d64d5cf9df7472dd1b67dd8c48ad6bc4d7ec90426d384141444e6611071c4f23953858a08ed448679d39b8913a9809e046da51255181a7917a5a4f1880a30b2a46262c3ed6185922c122d4441d4ae046ea22838e0dcc31d217951719a81a29f522aa0aa79156aa3590801a29ac8a306f9c461a0be3ccd59b3284c88d3484b2c269a43d555a5983971bda8cd4a74a2b6f0033d566a43f55daf6a2c50a6aa440555a2639068e54165b231316a6630c183a46352278995822c1c27696787a625433457653278bab910a0505350b0d6141868badb1a9b1b49c5274de2a7ffe94190265a2e99dc8d414b03343d588e5cb1a418944ca0b8437f082b3366b73fe1499769041c3184ea38bb44e62ea08ac91ce9601ea8ca7715a1e5b76179f349ff2146fde688db4e1ecf0343a9189026a6434b49863cdc85ea8c1658db4ab9de53034f084d548bdda5926b6620b17592396971458d3ca664b1dcf160b6c8d1dd8d9231ba6781afdfb0ec8a00b041f9c48af07c16f4e127611f9a078035d6e6f4d13c6840a757710743d88f4025dfcb2409dc4254e9d51c575f166b3048d3450c1e1264c8479b1dcef13dfd288e6cb3a21e850d0f1191599e01675443ca1cb433e095c354a8309e1711ba4c72d901fb7444111ec1087ecec7dfcf80181f511410f2033213c6a6e8786b89515b9dd51c4ad9091ea3688e5d1e74a96cc9a5ba0fb592512897c7aa4bafd71eb73ddf6b80def74cb93d434a9b36c01172555b754092f91ed16bc605a2592e6d6ddce25d52de0a20d24136fe2512d0e40f75707b5031813ff396b375b22bcd96c4be4b741a844d6a407b127e107defd810f08402108892053e2e1a30704ffc3462012050122a4469380c890a22213185160a40224478e6c481624495282c10519dc25e3061a30e1a089130f3a7802c207212889304209242c410140000410c504020ce0040314a08b1214aaad8b94038049c182ae262500cc6d0164a634a08c0af24b8187156a2b619ab48069720aacc9df166d6156a86efb884b59a86edb884b1d50dd76119752a96e3b776995eab6d15cda4275db445cfa80eab6cf5c6aa5baed212e854075db425cea4275db415c1a81eab681b8f44a75db5197be50ddf60f974aa0ba6d3397c250ddb60f973255b75de6d218aadb26732996eab6c75cda54dd760f9736aeba6da84b5b86eab6c55cda3354b71de6d2a6a1ba6d1e2eed2cd56d83b9b46ba86e7b874b5b4b75db3a5cda5baadbfe72693b55b7fd7469db50dd760e97f60dd56de3706973a96edbcba5dda5baed2e97b697eab6b95cda3854b77dc3a59d4375db365cda4fd56d3b5dda5faadbde7269eb50ddb6964b7b87eab66bb8b4c154b79de5d2e6a1ba6d1a2eed30d56dcf70698ba96e5b864b1baaba6ddca5dd4375cb772eed31d52dd7716993a96ef903977699ea96ed5cda3e54b74cc7a56da6bae53a97f60fd52dcf71694755b7bc75690351ddb2072eed20aa5b96e3d216a2bae5382eed21aa5ba673699fa96e79cea54d4475cb705cda68aa5b7ee3d2ce55b7ac75691751ddb21b97b611d52db771691f51dd72072eed34d52dcbb9b4d554b71ce7d29e4075cb6c5cda4854b7bcc6a5bda6bae5ac4b3b89ea96d5b8b42950dd32072eed0a54b7bc814b9b4d75cb695cda4a54b7ac814bdb02d52da371692f51dd72062eed36d52d635dda4c54b77cc6a5dd4475cb665cda4e54b75cc6a5fd4475cb702e6d28aa5b26e3d28ea2bae5312e6d29aa5b16e3d296aa6ef9ead29ea2bae5302eed0b54b70cc6a51d51964a18810a19618a4c0385301207ccc1085c94c025acac586a49c90acb8c0fe8a787ddfaf77137fbfddc7d7252c7493ccfef7152ecf93f4e82d5245a39097c7e588c87cebff99ddd9dde9ddf9dae3befbcd13b937c7ebe9c9c14fefc0ae3a4eee7f78909bfefc702f9d820a11db2211eb31e3e20f8c145f6878be48716c8060971917c98ddc145f2ab95d9211e5c24df6567b6870f2e82808b7e70513847e8a325046f70ef7c6e3e746df5d33365403f3d56640f40a1191158055cffd9e38621c82008be3b7844d63e6ce3e9b072b281067707ef6024215c936f346b42180909c968225da6f20682408420d8b91e04c5255cc27ea3b9c112ab1c6067c8807e7abeef6fb0ef6f3c975fc9f79c844e9077f0e922f2db0235e9a16fc810280c7f5ad18822b04cb907082491be9f3d74a875228f1c4ff4ef867bcfa7dff7cdceeb3a6f4eb71fd0f7c942300462d9114a248df6830c30743a5dd7d3764f2783a083a1ac7560083e4f36e19ca1ec3c91e6855606e8b5e7303dd91e967a267c61044366c92c999925b364e6efe9f1f1f9f9010262212166e6f7616666c92c9965b62b0b7213e4e60aefce095f96b649abc08856011f3d61da74226936224fe4d195bec2e16433f7a4311294ae4d6f9c6d2d1c15a564b9137410fcc0cfddfd7ae715d40ae378c3f7e5ba9e573d8f525707e5d2939dfce4d7e5acec48a4be0265cf798393389136f4ec2b27b0cec2ae14abb4b4aa566b85a083134b6ba2f181adf9665e4d2bf06fd3ca65acca772b086a69b95c1de875567ee12227a943c3d045dac0a38cc2418eb9f3a5d60eac500d23358e6bf3d34469219bbaa184e2ee88229c5ef0d1f7f367183c31506792c1488d9bb54e72a58b4c99a881099b6df9ba6ed7755d57ab7ce224d95ab62f5b29054b279836ff4a27e9ac2e327f5291c4c69dbce5e562d157f24a369cc6126d17e1f7b7bee24ec6401cce09c411e1fe65681cae03c12f8cf5f490c964412ebfd86f8f6060da1ce2a32b9236e9874a12063e4ac2b4f936499b4fc5bebaca5aea22f33bf1939fccc9237927903b5f5ec934241288c5664a4581bbb2ea4e09e7ce29dddcf99fd7754f9ba58c755d8fd2446aad247cd44eb491b469158b6959595ddd97e5d13949def93fd2ba6e8f9ab07b29a5c4698562ccb0e6b66d20b8288876828fca740f4c9bdf4e5dc79d6dc4937438a14c82651a4e5ac349f226739cd473e7576935919eb8487e895ae2f670e7d49a35d87d59394eaab0b55aab2b623271678e8be6b3010317c544ea37e600e74f2d31c29bcce5e60cf3ebb84eebce032ef4c8c3febeaf6777cb29a79c5e85334ff7e979288fe6f7ed5726692e0508ca99c691c031c8e5a90e7820ce9bb0839801e68d335371d87ce1431d5f48b065482e6808301b000347ca0d38fe812b26cd89ef14bc9812238e1c3b5e9cb1f3459d26a82b78b89ac30cac2b92703a6850307903079c115b561c78c2ebd47e38a18a34e83c3103163f40f91cb20f813a1abaaeebba2ba400e38501e99b31a8cc5c5dd7652a33767290800b194d703953070b0d0c31856f8121c7240386902cd8042142881c5f1c088c1a0f12c82185a03d5138b2b429734689ab37ee8120564c2068524b1a566feea06163ab8c91d11b2a36535084e0652a3650c83ca1cb546cd0b02923ed0ce94172d18137f241f9619b3754312e6f5c5bc891f2b6bc19837e3d2e538959e2d2cb5462d208d1c1853b45a46933831923d6c861f485c75185c5962f6e8ce12285865167bbec4ebb42cb04be2d5f842133a9c4784165460dd7130d5da6d222cc7d5da6d202897b7ba32e0ca3967d6c847e792a8e5518278b2f0edbcae16a035dd6b0628d71d28983c5957d5371a6be08c3e9727dd3f5bee9d20f7ceec1e3846f078931263227c021ecdb5dec56e13bb7fb5825e2c19e4c97074d2d806fe5bb9ee73df1264d37d9c47bffe941d3ad12abdd7f6114c19dc738893b30dbdd93bedb2332a4e63fad4c3e99dfc4e7ac83babcce05ba3b0cfcacf5afeb5ca0f884ef5cff2a3ca5bb4feb60cba9efbf8f69a44d63bf27ce963cef9bc6177fb5209bf0065e998f2542975113e1105c1c2da5a858d162bab245e3d0927ac24a85b3a54fc9c927ce48e0d1d634468d4c3d766ed6feb6992e428544514d59dd7e6e28cf93603a2bd75abdb50667e6de9a4e63cdb937994576612c293d89bcac89227a0a2594952c2325a3726fa454d59a36b989c4e3d8df663a89ac52a68bf4f3982ed233694796813374fb659544aa61f5d41c3797cdcdb1e6c471a9141d32edb3c7749996c2658143ceed3702967ca8040c1d28a95388460000002011400083160000200c0a070422911c04e248177d0714000f65783a64523215082391381848510c84530c432110c22086102619320ca2191b5000fe119b2f79ec20e98583a718e11691fa39be5f84663d1e7d5568c5c2e90c46c61fc91f537bfc407132d6e8571cb37ea078d81a85a8fe08d532b182b5998d69013d9c71789771c5122b9c17527f21b526f5b4e6b465ac4ddf395a537c3198b9296b86b57126b6c05b3df56f9fd74c84817f9900714e928259802658f5a4ff6f9541ad2b84f154e13037523a695e9f2754a5deec90a13f335a901a3be75bd0f54a724f810c69536d4d04212658b9171312f131e35024d4432e96ee8ad01704a843c4b94703ab55e0588fa1e8a38756627c2b9605bb7c5a310961b7cc6c6e78494891b7c06226f1df093469c07ccec0b16e634ce30f42f44c659e1ddcde70e4e3946f8b495d6ca37752f85236b222e838da1db0239b2390acde82ba8f431446d84acb558c7d2889d50fa64209075818a604537fd45d2ebd4fb748845fe54049309847ada679d79a6003ddfe933419ef93dae1aa41667381343252e3fb92ce76e1491e6b7bacc8b7393f999f6259c70412ffe03d4f3515225a586a51d6feedcf6c36189bee722c5839181998b5a1102b6e411e603f7f0e7af2cdada2827c62e90268448bf44887012665473272323d353ad65e207044bff3b76984da6a5584a625ec990dad613f477212189e01be8c37d06c80662b6d2ae4e82c990bd296c850da2f6ebd3ee6b3229660410843389ce78222091d201fcbce0ae0a4e77d2e330c15cbf9babef1e4c62485c2818e097c08ae0b90b40c5a02d552c262f557b55b37ad1f6289b77dcc81ec3d8c4dabfe0870de6b9757b0a7cf1ad492d8001ea9ce71494afe960758a8ec0a4d180334b21db9e049b1be4dac63e01bac7ad1c96e2154ca89d4d63d0775dad7ea88266ddd9921ff03235860c870cf35dc2553f666e9f5a1a359c544021f178fb55e4fb2af9a357fb5049bfd32d771df33cf334f0fed50f2e765404037058271620e6312754c01d375a736cb9e2d193ea3fb8e1776a82a5f2f9bc248828593022cb73661060810d2b1ed123fe001af3340a59303ba729ce3c9ca6ae97c74964e9d87fbcdeedaf805999ba5a38d6a3507d9a0d81f747e7a67b1cb4309e6bd7709f4b39176940d24ef7bb9c43cc8c240fcab1be31190c652caecbd84b3ef5f8c071c7f4338422e878481383f05dc987019d0232ac0856628df9a39c756dfa50b696367b4da19a9c14636c2d64af06ef86828383b3810c10601af19e6e9e9a52e632edd6502a897339fe73e4ff7f794598e517d9a8980d3bbf67959b26054563f2c0a90fd2e6caba6eeac97811db36c4df002c306c30c50868753b90adf445a62d87c71b5df90056e6506f3fa22b9642237c7920c04f2ad66a1dd70e87efc0e440b2b37748938e61686ebcf81f62ec716c6a449420785d09109fcab8211d1932523a47fb19207ff60e606f1f0ab329a71b13a23da45c5472f9a860dc1320e71daa154cae3e1ed0c26f0cb99c080e91e746fa3f99c4781d35c713a4b8270a16b712e3424e1e4ac969caf2951c96bac26d3189f5db3db9b95d41d4b0d9c465954e5a5a369035256e239b3153a57238a030dd19885b3501f60d45fa02b4cf21e2c4079808dbb9515fd47f4894987c633d1ad70c06862f42decc13071533f2c63a1c685854cfd38493f6bc9e5349b871eedb7e815f5e1520a3f31f6edce2280bc18f5922a8a170b152a5624664c55f1bd2a8c718590d154b03d03371f2f34837e1a926e954fb68cdeddc55ad52aea3d67062c13655f44d7978a1483347967030a30163b86a010ec9a4da939b3b4cf66d5ccd293de65caf3be3f1e2343a37fe7fdf05125815cac8b55ce2a431633010d481c5df059d2be3de0718ec276d215b6321612428f87c7c4617cf6b56222519974dfbee97734e52b1a3890401833e45f2f9fe06046cf8b81ddf2be892545fb65119d7887e95a257dc4ea2640d781c59ffa767c1e10be6fe4da8f33798c84612ffcfe3548d501d4bf576bbdefdbf43fe1f77dd4c718c8f755b895c6365ed1dbad8381a20db3ce8325f4787dae2bd8298b08eeeb50c4b25ad4e44e2d97f771f81680b6ff3c468f26eb627d0fba81bf34dff129a0facfccf1b71d8bf35acc5a75775c4a98692999208fb8f27e6ac4337016a171b90f9466e4f8e9ff72e6f9e3907eb2f29c5b817f8c01a5e11bfd238ffda9aaf282e86f70e87f6e79fb036d285b5403785e019e3e9f019ece2a6c0e59f8bb2016025be3ee1e29940560bead25b3b381d3919cdd91103a32f03a6a3546e8bcd9115f960cbfe89ac14a099df3f3e7f5f3a005f4808a3d26d2c1cdb5f0fe3a6122687a55a1293b2d72b80ba563dd0b9bbd481d32572cff070b09c5adb6e4aa242db23c49688e19cf0c895b090a37c160276410ed5723ad5afa835b9f3d1eb8a3df8691871fe4795b9968dbbb4decd698d8726e398ddb84634e415354c3b88d2d3459d23bf03de538685e1807535aaf341b2fb70919a90adfd36d82e1a88a089da0996d824e814511a080054bb6b2d4ac78215e90654433bbb1b1fe4ee9c2064ade943968e0d4cb630296560a2c4fca83eab3560828230277eac1d61224ac55eee676f298149e6772b53266bf0d6b47359bd004df6a2c534fccafec66bb18a65988d6ac84f566e2a40121162c11310c0cdfdd645f69d3c7701947a82116e12a8a94ffb363bf0e9b30fef63c3acdd4615e567fc8c6939fd8e3950f0fcb341080306317c8d97d6a716da352a5de4ff3794eaac4a0343a42fd5db26c349bcd80bd0124260d57952ddad545980fea828cc28f0265267960d8f89ae3bcde8151e1812e8c5510a2c4fd21aecd6e6dd6234482f83a5c1c0cd7ba0f6d7a506b8a4ce3a609b4628c9e8a2383943995df99fef146ce42a104db1061e4677dcda006328ee7bc2771d29ece5f8971c56300fdf1d3242868c845974b551ff2151a8cb280f0cc2075b8dc2d8a5806c370d115a20a9c546f3e9d998b7c90fe3306f558c6454d207ae51b0a514e579f05553c259a83217f068c3997434c6a307195a4ec17f5dcf04f137ce10297df7114f4bfbea3baf0b8f25042b84670a94d90bce6dafec1318c481d7d25e4b155181af2aab2b8ffb1f4551544d5fa5e16c8141d30cb5fb5a9dd00fab5f9bb37bc658009b62bdc7b0bfaf34b4a4e8fe239ead0968fab92a73050ab64d521b0e0a4656ec944bb35138a1a3e33f369f70980feb26c69a124c407824ebc035965d114ef6258d81175d3ba17756db5d69e5a0b427f039c7640f8541b8e12123d012837a8ad7e6955bc2bc56bc5826a4538bdbeb66114e104cdb134b3e0e15d7f58978b85f5c5d556515b54b7f52c67b338e3ae502e93c3257c0babe0b1ddd8e2bf86fe995403c4d8de3a876b92a8821afe47f812138cf3252ec9be34b3e0a6e07f48f6d1b881316c97b81dab215dacac75b80e40552c586dd1f2ef997adccf62932415d645de4ae27ee25beddad8a34e707de5948c2d559fd4b974a0644da4b64b54da45f6288aac52d9704c38cd364e5a46a25252cba012a1c8c4fae605165e241df31d11be60f7f0d71e3c981f2298dde1ae60495fb5b2165a7580d8f3b32f35a587e4034709081a38ce88be45f34b31dd85232b2b3059b10b22f9c2c50468882d0ae025615cc473d4a14a61076380000701b35e8285fa602dea80850502bef6ae6535645d258bae7d3e269941d8126a813bd24bac76d018d041a6b7258413a49f6b8a6c3611da3c7547a575a2825942539373cf188d96a5e0852e9db4acf01b52c2c29ced8f9f71bd360416c4fdfa9d4b3c152d0fb220e2b12f1bc376a197a4093fd558d2adc3e839fd6050f637276a83d7758df9a3b784cf2492ed6b2eea56d769ecf287db1c2e9a0f453c65c746985501fd6ce3498275c2bd57d2aa3ed12517af954593c6169b794c812c29515866aa7465b4569bdf04a80da439d6e9f6ba7a21edaf63a7130b0474ad4a822d850f8d1553549038f049aec7ad9245b456e8abf8c9eed2c716794a016348594e0fd48f3bbfcfe84bf82f65e1503cecb947d8cc1654278ffa7237b67d4aa97853d04bc9a736629e693d794f6e43711d02220c05c2dcd5fafa8640181540f2f49453ce9419b8dee6cfa512466834ee9e7bb937d3102a504ea62803561aa2084f4ce4ce52010c1a6ccca3b54f5015773f530ea1537f5060370584242c1d845e41a20c709e905e87bde3b6935e3b32c46a951ae533ec7a01a1e2873ab8550d5801471ed35795dced4aaa8c1c312a83251d4a84f276d6a94b9aae182e0b7ea72b184eddd286488663154d12e1697b806e8b8a90ea150c392164183e32afc05733ed8292420c87173ce394774ecd0b032405bdb7abe30529106f868e3a146836661cf7615241912fd2b9f5bfa5c1852cb3aaee8b87023f1555d2832d6db526a460982282923be9d598603f25cf6acb03a71b0d9387f1d655a223b3c47261a677d1808fff37cfb8ff39e7734d73ac7a073a90060cf4447920822c10f4e11f196de8277df9d4e20e761508747cf8d63e62461a431135d9fc4f2770f54674b64a7b003c8bab13812d367173c5d96d8395aab241f10efa96109f9d3cf674dc3474556c461dac57f00cdce6678bc99d842ceea7fb5dc89a35e9a0570ff5d9c91d7b64213f6dc672c1656100a7b3223516add60839287c3e6946b40535ae799aaf0df1a5d88dd611a8e4f5684458be52b6e15917d98e8cd1eccc47ba0cba9f1972d348dfb07c5fe0646e88685b68868bfbf3dc36b261c560ff497e5ddc71ba757a1d060dd0d3e9d8b3c9bbfbf354c460cb8c33d1571b47f97c1de8a959e53f3410a8836d7de7b6d3ddc6aee4d57c1df53fac4ba00de3bbd88ebdd9909f36636db9ec74b7f90abb9935e7296dc51834185b663a0cedf69ad03d0540a951c639bff9f224b25f876a4cb6a7964acab129a6853a2b54eb72897925b5844f589a897fafa40238d3708ab591f467fa2b952bc0e56f31b07efa71851e80e2b47ba2ad49a63265faf344b014756878b8f5fc3c91c0a09954687a2d7896c4eef4bd18951a43253d6cd1dc3ddc8a0c764afa8b65a00087fe415b70926a3a995b113ade89b8a59aaa42fbab28302538926a648caaafff58e306434092d04c233c7ebe0e789a0f1d6d9eae46dd8a6325f383d36e48ef4a6131a4fa204ccefaab8b87d7bb1c91ea08ae86229f364a39b68a58729e0ff2d352393412a547b192f4a14cb6668ae8f380e12d19325182a15add83bab2099e09f3e2dd5275f26c8bda0baa5a28b81721463728ef7cf2c90101d540b12c276948413f0474905d5e7206a8215c8d8e559865a082bbadf0d2bb8500fcba31f8d5139548bff03045de92c42236892de493e813caccb82980b031dfde3ae48ef6bc49c5c6332468f4b2105689c55132e645c9c88ea186d809a54b5742d11c32ae7fc6a0d3038ed887ab7be650817ca585c100af89aa50e25fdd3b7765e7cdde70ff32ed3c32330504e7cf6f983f369018d24fe3f7013cef17c845e5d8dacfa9ba812a72b5d9a0fbe3d9a5d47bcbf67b43d2065587e33508108bd4c53a00046b63ba709e6ecaa32afe5b6c87e03aec259f716a45406bfe56adc8f5e329f1a4b80701c4e9f6ac2a881d6dc126891634a0b77ddc18f214b347d6c692916b5dfbc8414e7c64399628e65162618b1e88169e013c8815d6ba21f9790854513cbe568f00ae14ec9bfa2442ceca8c6ad5c8824ace7f569bdcf5f2abe63745ab65149bc3fbe6c0b5785c116ef208ef017d02f5aff1636cecaa05e09e5bb522e0dbe0d1ed924dcbd121262bc9ad2a6a8748165ba15c542cbea0d5fe81d826c4d536879d1f5fe8584108012736c235bdf7927a704d5bb62d9d947a81058701ae58433890a51cf8e217fc312e5b169ded94efe6b6481aae83cd820cba68c406d27f90f8891cf5c13594748a56c67e26d5fde3d11f37910e98890daa9d4306f84d6c0e983429a0a2f5819c677b2e65b0c472a7778341b25f7f42443d38e0736f00be78c809c5e7c8ef3de915ad25268be88e178ae67bb5da915005260b9c24daaa28b84b517ca3a55d0cba7e0b3c546451c25141474f0aecfc3d10c0b37087c20f050ef77ea44268241aefcbbed82ed3d95871d01df3ac4ac58122415b720ca3115305c31c708ee8df707fa8422a20e721eb102814b232586ed9b606b307e9beb259e7f1aee62038e737fe2b99697c188aa42a7620bbe2fb6c04501a51b233698b5e5f515f191774ec0e9c028ccf5562ee5c4a4fa0f64fa85c186e9867beadd179e8124f63f7b85212459b236622de6454180ac475b59109057721a0826b8d51adaf8866fc028aff5616480418e4ed45694462b7eb5e963666ca921b3e5418354a3bd6ea488282b83b5826c9bdd8e2848176d789afd4f7e62b9fd17e2375203e3fd26366b70fca43bacac9b7d0560c57d5fb5fa7314162be7fb4ec70386974d8e037d22f7fa70e2a7df0b885d1e9a9233508e3012c0d230dae0d2baceaa3be857f4576969d40e57daf6240f54d9f37bdbab66bed2300e6574b711c8b703c6856961c039da44a855cddd5c8e8a7bffc5deddf1c7523400ecca6bfb749aa214f524530011cc91e4422f1e8584c75967d9ef5b8f416ef16af03942ada14299c3d4d70a59bcb40b460a92ad0b239513e7d48f4ebd974a4e5479d1eeb4178d41ee417c1d011242c4e17eacd8249955a4aa9f7540bc5b8e430fa8d8974bd850cd48171e1f5024996bebff4f338f0a024d13262ab3fe56807bfa9d4d5979a5f0b42ab3b04d4f19c474e80cf1fb2e8d9e612723babb57e66d6a326a0db6a6e18b48351d6fa394a71ca174aab190c94ae5d589f04c8f2d9a12b18f53150f2899e89ccb27ff91ddce3345afded292707144e392b581e4849ed43bfc051babf6463d175bc994434edaf9c6789fb9850028b8d74f431a033c8e6763268b4027f1c9108f6f218414ae1e1b1b762841fb748891b8adb421803f11c2bdb12c6a0d42e5d5de84396f6cf6d407092c3bf5c406b1bc1cecd31dd990da0f075eca171d3f0ada99d16145efc1e7da565301de1ed10a915d77e2ac5efe45430a240046b0145f58b75ccb4d98960109ad9263cfbdb598f08694c1011ac47e0fe1290b203faef9bab3fe1f9f82f6461ae1304f4bdaf6e6f949130f250fa0123b910dee0e62d0d3e0dc91a2cbae33d0efcf4c053d16d1233bc2091764ca7b85f29e8e14d2747d8564829f99310d28009c8836e39e3af0ce757ce1bf85c7238f822f29137dbcc37d3f0342207516ba79c607eb919e97a013257772e171eb84da9212a364dd1bf54d7d4e106c0c0be94eed395d5aa682a1f8b8b3421c6b59bfbf11b8bc8536d05bd80da44fd002548db3d605608e0bd664241cf19744d676dc5125effb00810ef332c47d0cb9484fd46715e40f9eb6817686a3084a3a40070ef204b109a11b326294815931e4c86c9ffaf6d0a314788d92c93b3bfca1a1e1733270a194cd274a336678e8833e0bc51b77e792cf4c0e9dc5cf643f2f5d03a93b9dc4025ef80f9443763b77f8ca09c5c5d2380f3f05d29c8c0df2d5a6e49ca33613865edc8527eaed125f0af8cd92d5c0556385ee6ee189796afb64d8190dc57d4f4b8b5f93dfe4d7c07231967daf15e21827c85cac6a977058356ecce0d1cd92f60b0700bac30df9b560702215826dd6d86f07270bdccfd475a912f6e0ec02a5935dfefb1138efd8a745008b223b1886fc8015d5718d48b860db05955b1074d92bafe5823d51344650853d86f4ff773c46aab645fae90714743de5361d050e21d11f9c4a5509ef60eabb162a204d1fb1243bfabd86b7ea3a1da566e56ae370b83acbed768aed29b3b18a45d1a87e23fcf0c550dbd663f581f34b0fd8c8c6e296c0ead83186c62840143cfb76bf7d3f2a70b7cf35b61311760ca9bd6311befacd0281ea17d8a0a6aedccf4d9255c4f529685987d37918fb2e5504d174c4ab5ed72a75d7e4a2d60677214b58f653f960525addcd7a4eb9603793e4305f5cbf7bf91e8b57e498a70834cfde331112142f6e9e51101fae817b11ae2584a8f8aa06213fb39b55027257e7c801c87fee64ba66701d1cef47e7840ece7d085265252be04958ecefe3dce6e3c29c0147d778536f985b43f85f163575d5e2b783386b5e0aea373ad7d5e83c5202e9562ef0a4de9107aa50f164eacba26e784292ea16198d270a14ed60506af0566f77b3cbb48a4f75689ec8861823376d0f7873af70016988a536dec84c6533fa55ef49e277c01b5982332113856c41fb8cba8b2817ea879a3d2f34aafcf73255dcac858771cd324fe60458d3e60f29dccdac5c9a0753a2f7a60238f6bd422853cb438690c929191a91a85529bf1992bf750c630517988ef7400ab85d6d35119be8259496369008aaa0a8af84db509b1c38abdc6d813bfba97c3f62237dc27d85030c719cce17a9fe97eea3e0a3824c159450c19dab45b7a648ebafc68328c6ac55149e703da4d0bad530f4ba28ce731296b5182553000642a9bac31709a7e39f3580e94fecafee734d05d04e2982173771a08f99ddd85506839e176ab380135759333bd4fdbb9ecccfcb4a15d5aca3ded4ee24cc6d3362e39ff3a6d688796644ebb9238a3e0b48dcbceb04d1bda2d2366d3964d99b4f4e4ed42e0554a73bb584008c9ec0a8610080903287e10718edbe0c30e7e045be3af47a372784dfba8f18ac8f5ab2491b254386530108451d5902513953d47bdc9bbed179cc8e0f0b93fef2a6ff01183a8691e15096efba1fd99295c12ef159145b4420cad3f90943d4b5aa76a425496a63f05041667c8d9a59e89d50b24ccd53d85d4c6fbc03fe4575584f00aef5b9ca2362312ef0a3858e5a32d9d23bc5971596cdf3864e1c5fcd43d2fdff24eb2b3b63fe861cc75f2240de001c5ca56e1321ca4e467f3c2197100ab2592dcdb213e71cb2a0d177842ff98c70ad309d398573abf47994866c8007b79d2fbc1dd24da88b7d24ce411dc6a516bf169c8103d6429ebe638fd4cd24905bae87a8c3d743dc87d753ec43e5d1e635f1d1f739faec7b04ff783b85fc763eca1e321f7aafb31f6e9f210fb75fb98fb743d847dba1fe2de3a1e631f1d8fb9a7ae8fb14797c7d8afeb63eea1e321ecd1f918f7eab21f232b13018c0ff4d0eb1bd5488fd614f64951d4babec83d3f222295dd63765f9518d14ec01105716d40ace3659687e27f6b6aea84a772aac0727bec47100faecf492ea65d926ed5d5d34ed6a6db3c7d1035a16591f08f09cedf0abad4fcaf5086b546781f4dbd3278d4fcde8f531596b3b992efc5a7113a7369a14bdb26a8f1080b1e13a7e803776389eb96edb7a8d40177bc3be0f28bf2a64bb690ae190fba85b10021f482bfbb1c7d1e955c6cd6ee17caeb2e8b397c6e45c76cf8528db8f74cbde4d551cb164c9c1eba3d480f7058fc597998bdcc36f5b5f1f04a179d2a70f1edae5dcf3dd3bea8c0868f66d3e7be57de0ac46f77715ef7cd07d4c5a3c988b398862534689d06408389a270b6369a66a5378745b9f2aa86fcb9c6db3b3eed580dc6552f875da3ed11740af332fffbe3fe7098a4f219cb45c93561d1fea806100b8dcc67ba65413e3b905b9899ffa7e3eb495d46ce782831787da586aa8c3b5cc5bf58b77ddff7d039818060df2198e9858cd961199b31124b978dcf4f11589bf4a3888301a14e342ca4bbd5e6b89611b5c353753fc7ae0c413d416477c31805bc64138fb9247c8502644c0224b99c80fdea37828e1253b892658b9591fe010fed1f42e8a28b7ac14301b45b7d7e246cf046cd92c6084827360b411402a22547a78ea63a80962b2fc60c69c3391d7c0b2429b534e48206b9f2581d805544da231ba2a4d9f702a23627c70210f08e0af8dc9214ae9063c5afa96249cd14f94fcbe6325049f256da42e24c9220fb7be600219ee5c06c7ee57f59463b657e9bd50cb1cfdab457ce9eb3cc12995a887d5980bc65c1ac51f99810909ce80ae88e04da59d6476b8a644bab221aa502734575203b12c05e791f6d33322dac0ac1140b981b5581ec8800fbe5f5e00dc869655544575a682e7405304702ed2deb83352045ab7513ad7201b9d04ba01d0b69b7bc8ed600292dd795e80a85e48056817e50a8bdf23a9a2624b6b86a82291422075a07da4321f6cacac19a23b3e5ba88a6a490dc2835d0e3802d6459650171444955fa3a7d1615d18eac89c0f4447185740ade65d4e17a8c4c2ff015ca101846e8a6819660be959e65af6038f59e7f1b01ac2ce956fdd8ea06471127a6a88b80edcdda7bbef0027f71ebb0925024c4dbaad36cba3b58df4f1dcb06cb06c2b15063d00a0e8403cb450380767aebe024c6ab4735241ed1e28059b191ef07077961cc4c64c9f79389b8103023b0e6fbcb212b08981735f3fd71909503990bac5c7e58c49623662246fe7f7964a50033b131f71f0e9942cca8a895eb0f87bc34664860c8f5cb455c123122b273fde5212b88988bdaf97e701095838c05a67cfe78648b11732256fe9f3cb2420823b135f71f839452c8acd8caf78781b830642432e4f5cf445e0a1811b373fde79095440c8b9af97e18888aa3cc45562ebf49b42937212762e4ff9747560a30131b73ffe19029c48c8a5ab9fe70c84b638604865cbf5cc4251123223bd75f1eb28288f9132767dd46b245882d72780e6efd77aad265eedb4b84e8dda55723b69d2280c62ef2fab0e90942f5fa2557039b7e24a8c62d71f158ec2d0274dcd2ab8f854e2040eb2ebc7258e83501b5de920b876d6f13a2e12cb89e58761221747ec9cbc34e4f11aae9975c2c58f42b813ab384abc566bf08d131165e5c2c7a81107a73e9d560a1af09a8774bae1c167b35b1349fe414cff74d81cc5ed8c9b94cd2f00a3a4efecc826e73f4b7dcd74007c30dc37521bb78fc429fa85e2f633221b82062d220578d080a74e9963b505627145cd330a94ac03ae50f81a5bb055c3cc7f0b5c399ad7d31c3518ea81363acd0ed1e6b43403afc3caae17c382a1f4ea7127f8c7c2a6de48e7f54e9e96341feebf8a60ea3573054867aa4f0838be382b17bbaa49258a856e19b386677426b161529f0c858dd04997d417a6d471caf11dc094e0e72d8f18dc4f5e67a3449ecfbf89cc04939b7397ae1565534992f018fa675bacaa3d3d2102954e6eeee8a6f6b21f9a4738aee0c796ce9bf98727e73ffc772758621db8d34bc8db42bbda0567ace869a44dc142b048c7ee9a8bb6834880fc80796165d6822176e2acc124224701275b491160458d4917ba6ff1137ef0cab2a2bc6d013b84e7e1e29c3163c961da8921edd5784d84a0f9efa0432db155379f1266fbadb50cb7e0e083f878aed2f9b14cc17c782585087ad4d33457711e1729f6084f1887d42fd4644d6a7ec756a363654d63c8ecd94676ce0e4bd1067169fa6fab643d27d224cdef44a908f2715c3ebbe35adc470a532f021433382ccf21f2968b384f46825ef81aaa80c2d3339b5efbf6b44ccb07a596eb14670e09adfe230569e9b5a8d16b1b8357d966c8ca6dfdf7baaab977e4397553c99d4c5650c0c6f1ba113e1723ec0853073d33113d9e97cae7e9b6e11d093bf854f3f6391702bb13ed261bd4bb968eb0a9b736cfc69b186dd11f2d60d349226e25112ec0d278f5bdcebfedc39492420eb69c221d67ae5c5bc2ec8de209df94549534b745f9531d56441e1926e3709cf2e87dd61356f6a6027539e119df563d19f63a28ba7af9e9ec79e3ecda97d00bb694adaa66a9f55ec31705632f84ca7c7d07dc6075e7754df867dafb4e8b095372e3c6db295cab859bda9df10201f79f6120107b8adc98be26969ffeb21611dfd7e7794a884ba5c9fc7fa3c75734a6104cfb910fe75c748e1fb1e59569a5267d9e96f054bb3cbab20b38882825bde1df1f4f62d6f61710444c18716487014c517a058f70fefe79e0be48034f5524de6989b7d50b7b65457bde92ff58026f60c18a9cd8c3a11390f64eaca5db8f721d5e137403cd7adb664bf5833941d4e73023ec694802400d29c5603c065d92ba5176ec2eceeca28c5c4265f84007eac27c14eb80a1d4acf4bca5e6cb240b16510cec5a468e64b4f7b7cbca46b7656195eb83658d7b25f7f179e6122c3fcf88ded36270086c9e67c47caf7c66c96e84799d51f25747716da79bb600eef7539d6c8fc9bcf4ea7c8d40c7a06b40d20390144f8f8f54b65f1306b07341e2b935b88592092318267b14509eebb573b5bb439a0cff63a25feae606a0096c4761b67a0cc28dc5d77043b944e5aa279045c217a39c17f93e0b6eb2481ca89c2e5c2b9794690fe9a8e821ed412200eb7684de10e8fc44de51706fdfd8a75b326ba1b32c53e083709700719baf45b5f30a653bfb002002cf8b21310db1773bc429442bee053a8a2dcf438768002021315fe01d43c7b50f26d4ada50a2e5d066ba12e27712f076df2f15685955586f194189b8c005c5a22e0eaf5a114677c1052c12b9c9d752666d3b99418d5ed2972214a32eb4991308974b6e11085db7873389a8598a6bb5d72bd447fee13dceeaa09a8a96a51326abb4d9e9c608217e9e9b8e2c6915c2445f4df18f6b43452faa6b3d77596e34caa3cf92ae04fbfc0227c91e9c087611612e5541b93943b1d3cac13819d66aa9b0130b8a7c55b2bced8f63134cb6076c2443a918f5dbd52f16b1958410250f56b4a0639b2e7ff484ebbf8f41d76058c20f76d70a1469d3165c51da10067bcf77c485ced737cb06d4f94d8eac408d2235c2ad2cdd3f4526fb7cf44d6a0090ed7bfca0319af4b2144ba13806a764a4e1fe907bb8193a4b4e1cfb13e0c5b85013683ddc08bac6748345c19d04a1d515e11d55e39d4b6f0b79e6077f73823bd2a506e076b73a60728409d622d6b775db016fbfb6fbe56ea58e550a825323d8b552dce3e70657add147d15b1fd00159a2967242fefa37d8022d17a0112e373a3201fc1dd32cca4edd3dd9dd8eb20037d12545596dc1818bbf09b676abcc273ca9b8a08d7761a8515add6582f9c7249f8a3145a461ec83d8ea4aec5adbb7035d8e66e8e619e20b379d7ae071d4838234b7362f981f389dc18afb8299f4ccd6b4c5f308149f2fcd89e888f64d6bd44adad62f3c7a5eac3ace4a7521248976edcb06a44083741105aff0f7c2a6fa71f3dea9287372a81f17e29991e3bfde777668a19ec16648c4fb21c21853aca3c045f3ede91acf102aaabcfff8c6a8ad62c1e612f9e741c102f8ebf1c02ad66fc5af60902877f279094e312954adc70c1ef7d12b855c2333d14c68732ab73a8c93e00c94565b1e755ccf4113c88e8d47c432f6006c326d8359a3093b6ebeb9512414233e72f400a1934174c2d82b1cbb4df7cc3315e84a12b50de71b60605ba6ff780859cd2fe063eb05afcb6e383537566752976787a58db6be0eb88d1884912e51950740c1bdc948cdc01bc7da5a585398132b9dbccc96ecad097c85656481f4042b28b8cbb2013d07064bc1199c3f74968034c15a14781f8086f0df43389122ab3ece51ae1b83874d59c99802d05b34d4fd06e9ad58cbf487a4e78d23d6ed0b4427e1ff0f47c2247cb90eca4688ccc5629b10dc830dc255a72dd65c0f40a508b24deb0e5008183dc1061ca6d06408b30208cc00e0bb5978aa5ef7adb862434e8f2d5fe71aa0a57063f4333408ec128244d7c05d253c78de38249c12bec676f1ed2aa71e350178565646338fbe1e155fe52679d282a68e05be44483e463701174012fcce3af8e56e49b4697ffa7df43feb06ee718a7d6e1615169634f3b109599fd70fe49dc9d55215585d637297b086ca92faebf359e77dea47703bbecb70a607f44332795f64e5c267f33db1e44420ec4703d661692d9b6e88d0e4f4ab55d9c0631885b1f44f36a2be002ffc01c89524ce544486aa82e15ac9884a7ef6ce2e5640d3bd334eac12905426b2b771418a99d924c55859504643e828a40d69de91d013a2d62c61fd5a958ee518aba792ffe79813305fab11fe67f9cd2250efaeddd98264b3064ab3db1873b13a0d124fb6a171b504f9b624cac3c6082ade878d6632a4f07950cd4ba95366c1bd42bf96ffd2d1b56b5483c140c0187a37edb84df314d538f61d0b4433a04b174b8390f5b641b25aa159e81835f8832ab19d3e679fc4914938ab897158bc2e2b309112ce6f69a542c36bf861df3c06ebdc296a5189fc2dc2eb5748110a7e749a4622e8018020d22aeac517a42912d56471d784d669a7c4386cf52d072fe5113700806d77b59cb2089786d9439212740acc868e6f7a02fe30c8f6ebe06bf52fa5328503819945d970a0f970e4355dbd9464a31f90a689e7cb3c7c3435ab31656d667077cc1060f53a6aae3a6d2a767cd050bd367b101b0041ad2fe2bb23f76944051e6df5a0c49a329167b4728f7ac7ab2f0386e825b3381c4ac68048d0410f03c65b004cd2b8395cc66472fd3513a05913f8e3ad944c8d45fc5ab1d12fc6b94c6ee8234cb56ea083fd6e7142793418a253a032874bc0a2efbd0753e6345a4b53d95403c4d40a9ac3c034d539e661ed2ff06688789e6ac1b8e76a4a3af3b940cde3c5fcc5f41526002e6975a8123c3647b0e1475a5390bbfa7c6899056bccb9ea0695e38366003dc56a62c658b1b4d990cd95554f7b33c472aed4437dc505eda3487b4e57dc61f3d7e9dfac66715275fbb41a68f965a002f3c221442f3864d53cf10a1bf5318344b1decb3999b39e1c06a8738a439429f5d83f966573582f050754ca212366ddb19e5784ab41ce278c187a92bb2a24b2bef50dfd582f2624fa81ec1206bc7fa2cebe5f5b1b66b1a3c424dc7228d77ed211341f90d6a7932a5c5f0b1330eec3d2f1ebdc1d78e9f3f69c31f0b268bc545794a4a76b19df37ef42d987c74a19752915a78aa64fc5c016a683ae0ca14d1a4e6582ba079f862e9df0d5635283e04e7c839350b4c1c60978050ae78f13b08fdf37e155b36fc2cf5c7e5d72eaecf2c7573e56ada22f4fa491fcf05ec4f820ceb571cb817193dbc07ca75871439caf688fc846a10be9cc03620a1525b233e2282f2598dc616370626d4b537b7e9d43de831acecff895768e953f037fe2432ac3b1bfdfd55d2d476ee491ec11d6b6c7b8e9e5276b0cc7df4758636ec743d2abeeb797a8b46682a7a4c9a1d8e9393c1185e84ed1686f9e385ce4c0ed0ff7cb518917906229432f61dd48563cf3e3b94cad4487eb08b1758e3660e914b6f351479e57199c33b1bfe4b56248e89240455c245eaae2554a54de941bb958890d4af51c8986951950fcd12254d4ba78b5ee41c400327ec2eb37701c591987d91333942a980f327a70055954f220f4b826cc79c099550309816de8e3c814557d16a1a73f0f8e8139a2135f69f187f25cd5bdc971a912ed28d0af229bd207792310f7bc3a9732f70c187d0cc55ce5545ca726d53fc00a9f3aec619bfba0ec4b4852776d589cd315b43e07c13311258379308c11b975a438e38cc50a814edb18ecec3f8f33119ec7c0bcce20074ea60cc3750b05683cea2f486ee98eb26d17515525c3ed37cbb10a12411dd1566cf6eb8f3681a0e351b388dd8303ac60f8931fb3ca71f561e695113b976156e7e9dc11311c9c118734e5b92341199d10957bf496ad371c10fa947cb48fe2d6436828a5581dca2c7668a4afe42c3c1bb23fcb258ae3ec47ebb44ef07a73a6f4f24cb9289648162ea6b51bd85329006461e921428c310cde6125d914906222753416601d453c686078cc6a5237b78736811659927c43a2b245e5374f0a0788eb5d63541644471a390e4e62b27812b3e2b84f2f05b049b358b0546aa1c30d68854227a2343ee3293d8deaa9019047d9f5d50b172545d6e8000cbc29a6d1cde162c1f4b91429e394314a4a3f54fd87744ee82304bcdd1d55e0310c830602c74fc92e094a8b27fdea2b286b8b09ddd78a89012d66c01c6a84545727629ebd5cd96c950c8548ed4fa73981c7039064185e4f28f72fb60e115b93835df6938d8040194dc447dd971a76f5d1a85ccbfb05b2d60a38a8fb47f22d95821d1b53d82c79402b872db5984a55352a181ab3a5e38e45e8091fb015db034184637304b5eac0b1e9c0386be3cad265ca6c67d25209915c6bb0dddc0893cdddad9027c4178527ba705b8abe9a95a4138a84a7487e95651db272e7b8dc344966e58530362580f8061088174a6ebafb67646227f9a89ad0f82ab479fd8afcf063536e726451460561b635465adc3835a05cf612ea1e97e9f91fbf8be34d6b264de119ea7d1dafa4b3a76062c1643e22ec7ea17bb374a24a893d0018b73c1a0d42aa9721b42912532ec8fca885b59014935543f0149716dc72f86014e2bb74badceaa228d5537bf72b538a27e52bed4351a8a06ea638797869c25b065924344010b811eec5cd9f60455e81943189e473542b34d9cb2ffb05c5097dc2cca887be639ed42a2f8634f496d784d2020eca218bf249298b9a82f3e69355ca54a44b0ad3f4cae5eab74e4900ff7c8261c38be5d2d3e7a44b79512daf3acd599e7779522c0087711be71959aaa4ef741648cf059c60800bdb9b96001bca50c8d385a9b02cd46485c3958f5bc850d3491d61927b524424114be8660ee055559ee32c4a6e488c37272409b062c52059cfec17f6356ecdc22eed08112cd85772c0e469c1683b673d84eff8c8a82db8c3faec2e5c6b62726044c6a8deb90dae917dde4d0b93311a13ee12bd904f179c601b49e826b0070dde35039fbfce2d4976b4018a876641e1f348c50ced53db4216c4895dbc05ffbbb54cc74222b11514a533676ed04b2b50315eb5fb75c139c84e5301a0aa9f21666ced5b425a0008fbfe21a3b60957fb1779e379e8d00ee2a85a8dbc45422ab71def9b92a992bc638932ee17a85f0f425f3ffdebeb9fd607501f3d35233f9e40f1c6fea8c56491babf5a2a0f8c08d2f54a98eaeff37dd8fc574a9a60212bb74ee8c4650a9e8b7e14d2040becdddf171b23c5ba7189aebb14ea0d7bdc5496e316b2c74a9dbc235d0706bd92a2e0ea0bdf48c5e33ea053a9e283e4c67f94722cc757b392ae2123124f03c88a52a8dab26b38cbac4347e1f70a5ff08e892f397159e57cbdd15d86cdb918dae75630d32c6724bf9c2af8563dae3b8325dd138534984194867173e7d9e8b906ac9e97667cefea387ae4a997dda43f1afb857c220128fdd3f12bbaaeb7fe0d1bad7ceb4b532f1456ccd5d7af3b8d66a74706cfebe986c183f3ee77fc7e3730f487a51cd8770d4ce115ef8ab2156baa07912d3ea1822d6ba0c5be7777bbff161ec792de29f2940e10ca0ca162708978450a12f97c1c5f5a631841d3e05991e4dedb4eec91a8aa641ced9f0d01ca8c4f991b117541c19fb4e8c141d9c30f37c0378f03f10a26adb849eeb21a16e2c6576954490c41ab7a6363461e7396a5439d208e1b099c1f9850383a402f010eb8a8fa566df863af97f8301e8359466eafb6df57c36a0e3ff90f9b214b6d4ff2879eda8058e7b6b3ed7c88c636c7e588b0a72948fe10a84f23923d37f1c172e21f138f3d23e34391fe85bf90bd22742bcb86a7d20767d161acc8db632593d707745b7e38be07e745ddcd3ebcc1563b587f208930f5bfa0e641ca8939052eb71e6fd74be343818e68a311b680a058c6bc4af003fe3a21d5082b94a5b6bf4edcd6eef6de7ca35cdbc4bd7f88da7bd1efcac9c223e6ebaf08d17d883cff270c85c95b6060c6e66cc99f99e2f92ae58f5a9e798a8e6f3eeafb0c6a06f9f86c7c009d53c6585e1e8e9de8edcd4efd4128a7f046077e353afe90489ff612808368f4e0200f6334b8f38309d2a4df7541515a9d65e727e8acbfb85b02942e15c2578bfbccf676820298cb6901b4b7e03b8322fc15ab49a73f19d7361d84ae9a9947637aea0dd511ad61c1040d2297b8b0a9ea71c7803adecd828267e2ea43451b878d47578444b3faf416521de3205af9788d1bf64bc580e0b9c16c165608bc544e9b16e6a13225b4d8ea58f2425772497ccb8f8a8871de6d405fd746fc0b15af0dd4bf8042b8b07bc8c5e1a656456bd1646676fe0c560a6e067c5413a9459a88919765fd2dd0f58b50a48e958381130d881243bb127fceabea4fa5a112aa0fc5ed6bbfd638da931efb6a48e439191f010489cd32b0b31e6b4553b5a41471a85a90ed1355afa5b41c2dbd525bf1ff945dbfc3b205467a2b602fb65ebf4c09d254b2eb2ea694e2f3b5b239550db193ea969d62659e1a015f258e648189217544a0af6422b02f0e5db2a1af4aaef5c0287f9cca3ae03ddb46d3f402c52f36a4ad3675affcfa6bfff69b7689f181aca4acbb683e19facc9fee7ceb50e32536e9db29495a41c93e668ad33101dbf7cca098506f49db7c2e4f928212cef2ac534c7bf489166ba002ba738997489e770c76dc963667b8e5524e33039abb17a6bb6980a6948faa82fd97bf5cb25cd1004f3525ccefd5cb046f2396e3557c24e83e7e1c664042d3762bbfc3fb39778568fc67363696be9c8a01b580b35cb6be6b46ab4ac055f09de5ceaad881403b310c8d3d7104356d3cb109e1e141c1f75de703225d15801fa85784251b785996ca76f9884c5d5602ecb3568499fa1ce9b54dc7ec49f8482d41755fc20d89175a1b06d362265af4b2c3d07ea82c5657c6da0b660b37a66ebe6536dcd66297cc53f8d3fa6bff62fdadcbb21be3c3e63654eaa9a0e2b8977b80bdbcfe23cdf57ab952d2cb61635e5e445ebe31c9efbd1b6ae534ce7ed0e5043b13d9b6d1a09e8e81080624ba036aa12e8657205816a703f9819b4295991c26757055b82fe96e34a8125773129a97aae8feecfc88f8292ae25cdefbe214013b2845fc8cebfcfdeea32ed63c334d3907afbb01306e789d8d7d99b24cbe15ff2bbfeddd6d6fb9a54c29c922086e0865082017ca6ae58c133178d272c44b5dedfbda311848f6b6b9e8125d97df43cf35227288f41bf8da1645475da04ffddbd8e28c81c7d54298955b468e2e548531dcee55c49121da6ac86cf9a967385538ddf13744fac97bfe86742f3f9def71ba0325b889def3a61722f15e14f6d7bd28947e9aad71b26eab3e1d3827f4f20bc2395f28fa49863cd024647660284412ea54daea36385220eaba3d65a06f9bb5a512eb8e0c2473d49caee99205c9648e92393eb329cf992e3f7533500ef3d93fc99d2e3a1dd4665ab7ac0134c61d1b48ca88707bf410c5ff52a97dac3505e99c6dcbc2ca58266d247f75570d1b48025d1cdf8080569427e59658e0b4180d9b3c67cf6666e7d9546b588b81c3375ad82fa6f1d7f193180c44a5c59101004c654db7f5b7b8591c1e1ef73baa9b099259fd97959033a328ac0fec77646f2628b9dc023e71109c059e71e743105272cf6d5828ec868db01899359b713f577ef2d04f959f9c59fc04abafc819ff8ebb7f60c7ee59875325671c0b3b36ecfaab9fbfe3286baab46f335a0c3ef9cb8eb25a8d9e4dae61ad86ac51000e173e15a6f1279bb66d75ab9ad69a0264cd08a4e8353e388a59de023ef97b9be13280f5ccdc09ee197425e48cff085c49cfef1cff10d8391d14f65ce7409390d073cf21098544fce47f822acb09f17777fbc08259cc624d5517c0bf87a0ea1a1ffd4f9a7d66c82c1f66b399aac539552db6142ca9e73d3df349a93837666656a3a767f5faeb703269d1574eae4f958e97f5c6d2413d9be9c857b779dce3038f0f9d5729c4853aaf65daa9e3083c422b5ba7aaaa565df3829c4e2693d99a52266b56e17d1e15b57893999987300a08d6b13f1208f6c9019fbc99d5203fe1f2fdf82e87cc52c352a7325953256d4ed77fae1ce5393e5bf7f975706135cdfd4315d871aaa6ca513d5389c4b0e3545def3b551368aaa66aaaa6aa67ce6da31bb349811030856f0b4b58774ee6fa6fe0f51bd747d77face17a3f7b8ab9953842278f23ece839d5bac123f449b0e9d0e8f4ecc63147b58f4f0c34f5079a5af4dda110d193422426ed4dfd2ea24762d24c1d9a82c43ce987c0c03c2914220a212ea19531df27c91975ab5b2d92625e5efbef9afadaf3e81aefb570f469d15bda57d1ad1730941ee2f8c94d3a2f6fd2417b17d29b86700ee9d954811717d2cbfc8d1f42fad18f42215ec2286a68caa17ef8fda4d01444e66fc8fc0dd390d29bbef4a6973931a149fb984f920313923ee685903e26441285f7484cdb9be8c39042d37c93f6a497425e3ee6634224a62d3c22c4e5edeb2073621ee687c43c4c28441442460ff342d810498fd7109851a803f3129a667844079963d2483fc4e54921920f63432c29dc2149ce2881483ff6c851bf7f7c1c2f735ec2284c397491ae2b187a1238fa17b0e56340978701edf367d291791d648ecc0fd1f1a5979f497b2dd4b9f144748451f49b1e3469323a748451d452e961625e8852e803cccbbc8ea7610c1da9949f489fe36352314ffa0ac07c8ed0a443223de7bcbc3ce7bc3c4ecb8032c7049ab4cff149726e80262d34e9c8bce97384486ebc298c22f4329f244706bc11de78ebf242dc08b9c7becc9b9e86314ca1f493cce871b8fce82b601f47f89cd3d2f29cd3f2387d03e49c12c8399a4f8b3e5068ab35764a04b64fa7564f7c7c644099d34f80a200d150ca74b956ab2d86543d9897ce051c81cfa305b4626f5d3d11d82993cbf694b15351ba46037275cd4be698f875790a50bf1cc6b039e9cb6f6e73e3d015767e3868e12849a861b87f90a7d9da7713460b6b9bfbed473b3f7485cd71a917b344429d16a77dd5f4cf470d400a3712a5e327be3182056d237cc32d1d1fdc299bc0ac27ecc3eaf7a4117e59f97cc8a7d35ba485f245ca481716d3cc9f22c847c822a4b803d37012f2347f9271e78f3d1ee0ce25eeec959c9993888ef7ccea03e4e0ceaa317d7af9f3a1b3d385d2756ee897433f9d6c61097bea17bdefee169658ed76ef3d0c98384211d6c8d9e9de7b9c762f7485e52b67a3be97ec83c7117647e97f5c61fb8e7f04071df7fb0d748267cbf9befff3c01e72fee6be7121ffe6fcdb3770bbf2f3b0449234fd149469112cc2f38aebea4427794c665b62666ecf9ba51668a9856935d6261565a0a1659a69bb49e9943c7b761bc8540bafe4824ffe2bbed144e7825132f0c99fae98891517ec6ae6e94dea69301918f5834f387ef2e7e71f16c73217923022d2a6df9f0212c55b704e7cbfc3944bc4515f58e78f8460bf173dbb80ac0bc552fae431d72808b67e5faddf8878bbd435dbc4a1022bafbf1372060792c69f03d9899c59b1941d587eb1ab45b0087694414138ea4706f19c6c92a1243a57ddfec0b130af3b719557349860a7044836ed47190433b9baf910c1ecc82eaf0bbb4edc6a8f90a6813a57ce0401ca1901c10601393b87a378b99968326bd7684f1f8a7f09641037461c91156ce415ec46a97ad4b585dd4b0bb6c4795de53927c79e0ca2f785447d4690489035da1741daf0bfdc201cf585bcf213dfd090a3ac3e1b561ca579c5e148a3c8c031af021c05ff6eca633013a4e8cf51f846879de0c5758e12057649200e9233fe0b0082c32e094479355d937aa6eb32744d498afe23e82251a23cf977d334a78b5f1cb4c353a4b08cb3308ccbb8feb39999081fcfeb28a5f46f13e19b10c81f8c92fce272fd475748189d1f84a36cc84d644b18fa7f3fd7bfaf8bdfe56217bbd8c5ae3943eda3075a3061c5cc54f479feb651f6fd4bd226f4fe37a4cdf6fe38a44d871a8938d8e1f99c96fa2210880d087be97b20101d18430f3f75600c9a46e4b26844e48d9bdaf61cd76d60e8a927fe10c029009e486f0b08d3b6c5dace748a42e16f5b0edb739b6df916b0879f5a207ecd012116fc8af9916bc2d5d1adbe725fad56950833f4959cf1245656fae48f659b59ec0e55729d2e99939d15faaa45f00b3b83e6939e554c2833ca9472a9346ba5ea993b9fa584e5ba159d1d3b76ece0e131c82f06bfcbb5a5a48445c2bebcab40def0c034cea335e5206f8b47e70bd8c20bec894b811debeb4ea9b0ae196b8a47977074165c7f1b8ead44e32ee4c95f148ec2d191f08523b331ba8baf3c9fc1556a25c562b158ab98d02530c0207a278fc11a8bd5181bb24530df43dc2b4080c2ef7243d85a46d78c9a6ac7f5ea4a0339e33f5facd335db0e5d511fcaa230a02ea067d02b940daaa24be40c738b4271d8dce9e9a427939e4b945cd8b65381da448df18d16ce17d3f8aa36c1286f62f60c8b15292f17eb89931d9e949c093a03c69b985de79bc9869c50b88217d765333bd2d89c6958b4202d0b4c8bf1c8ae6b53d0903447980212aebf26a5fb32b42854a05c9fd2555c2368506c21699e7869ab96e6735de3b9ae29b9fed40945ec481b2b8d6a257d2a83ca681579d343481a9736fc4e1c713d4b2fc1727dd450705f9e3f1fa2679791fd3c1a8b89c0c6f202f6cc0ae87ac26a273c2939e33d5de32a12f4895f66c1b2934509ffe84abc65ee0d83bdfa497743e928a95e754ff3901e86926667812618e562f009039589baf2267cc531ee420c867115f6829df00a8fa031a9318e8ba9982891418679475f854db0a34f1e7fcf022ba36bb66f959f8266cfa56ec50b7b498b211556b6d84b666490e1f341bf82a14bc123950b6d95ebc2b179683e1f737acc614e65fa18de041a8e9cc5570e7398c31cf672a2b19ea8a2ac9c256de83777c48b515e78043bb24f87a3c68489b4610e7d481cb7558d4ea64e288b52262d1ee0009f8fc91d61433ffa6ade2e015e48861df9d53b3cf3b7679f57cd91fa24e02c65748ac935808d4dad5cb7558e7d6e6cb0e1f3d1cf60e83678849f04dba55ac8307eb53845cef85356829ca1f1974a47da009133fea1efbbafe1aef13e0583c1d8a04f5a6451271e48574c542d32fbb89c30100d704f550d527ca3853a4c235f2e2951666c763161976f6695e9c574c2f5b7a3d077b2fbae3f1fdef77cbde62be8e52beaba14e8d21e47558daa6e89f278c979781a7e871c666147a157ddc27aa5c4dd2d5fc7fda4c6449e0ffbb0cf086c292dbaa2c819568b4e562219aba6344aa74ffc332c32cd8a56c67509a3726da0311a1b698c871dd887ad982f15d3b0158caa66f049759965be1f5f35c363aa9894ec302fac1599a73ca3adaf1665420f43c684529ea6640f71abb9ea15afa68cb957afd7063a00368103e0ed517d98c6a7aebc89ce039eccf181d1993741653e7c43af5032a81a3b88d1181176ac31719e214ffe57aecbe810b329a3311aa3311ae338cef27a7158633e6ef8814303aa1a5418d000a64ce88aaae6773978dc11b6bf7b80c7da75bec2af51aa0deb5fd018743fa9938f862b592e8d491b1ac81b5781f32b083fe0178d4925211b96569127ff3358577c281badeb7fe3a331baa24ca84aced02554e52df77196af441d27ac5ee97c10f87c841e02524640488e1ca51b5336653077984781bbc9f5ff42dcf6a4d23a6b5795c7311a9bb18eb1b792334e5a6445e91a1f2c77a4b11834a0eb515cca48633cd2980d3406d3112224021190c01026d2a9dee12cda0426c051e056c023810e9b389ccae7c3615b583956f61013581ad53c74e77a96399b5168e3fa0d6341d2f8944dd99465e954ef4cd994f5aa9d28d19e684e3426da121aa3313a2de09140a7d2a73e8d5ec6f5d74020b64b4326c8197f0f43d290402718748247cc810981d880b0b75f03df8f8fa76400039f8fee31f0ddb0018ffd4a8df5180e8b8df575bdc586e52b55aa8c5f2e98273dcfd7ab6b48307436d3d9dc5635caa0e4b6aad10d6c60871d38e03d619a1a30aa82c1277fd235382f83f5761ff018e4eb32391306182f47f912a220850f460002860e63c18e1bcff5a70cf3ce2fef48205865ac52ae7fcdb8ed5c4f8244d529d2865bd5e77edafbe58f866167bd4348328fd33e4c41609ef442609e04c3313f6d57c381a53b20cf40e9a798977921312f43fa98f015f348603e26e4d776dd95c819ff900d4b5fe6c0901e66474ad79048a153d0838298af098b79524cccf277463ce92812cc8f3a607e748143be9937240260ba2ff423bfbecfebfb422b612a1cc4b3dee1d8e78542a1d00dc58032679e2167a0c034565a9cf5c412d4a27720df18b0731a7422e649608967cb89d1d1d35f82b5e854a695299b58ee94855d8c5336d615533932cb9036f35b546034467ec2f577987b8cbbce578b77d553e627ff6db3b6549a29e01ac92214182599f674cd9436678c1a112b285122ac15661ad7a76cca2efdd219b6ca3629d3989cf1a755349e23ddad29e9896d9bb53446631cce57d7cc0f78fd810f7c3ebaff0008b63bd61583b5ae384bd7b077936a4cfab6d2a8988ff99898d077b2602983ca94981f3b8acc8f0de5c7aea2144a5f72653cc6619ef4386dfa422a2c87ac228135e6ef1cbf58d5ea9ab1c6ba46dac4aa8c8eded47aae2fb9ae299133313b8a77a43123357684e51fc7cf47f70cf62df2dd50c4ab31695345a2b88b578d711581c7af66d2356c480e43b6206da412d71b09cdab73951d6458fa9d5281b45102f341ec63054b96eb3b17e554a6a07ca5a451358a85c25ec51226d743273cb4f892332e73c6ba3a5dfe422a2c83da75f7771813541aa5b1ac8cdaeafa87bae60b8d05b70b79a3a940d2bca4cdca511e863cf97b95cdcfb0ee57aeaf1c267ac1fac52f7ef14b5ba2f5809a1239c32f7eb1e6d335a394dd2a5efe74898c56719d3eb94e9d30b91e8edb168ed6964ae1f8e27c98077bf849bcb1f58cbaaf28a3933ca476e58b573edf78299924470ea1bf0d39f1c8b2a7743e4ee3a07dd3d9abee884d5dfed20a6c897e0ed96db914a56346b340234643166854817aa92ca44003caf4b59ef4e7d26f4f874f87d0735fa2ff8e12620b815be8eb735ad564619c115bc28b007a72cf7a8d6ec198c67f0d46f50b5a72bb7e5ec0285e83595bc88d615a14e1ba37aed4a28858aa0a3da0d73369d3fd836eadd1335e836f7a0bd93ef056b7357dfe7068118ce7dc601c8644f54f0bd6b29dc8db31c5f2fd5ad2a1fcc896b562abd5f37d3bb2f48c3e9d1d20477d2f7afe0ffcbee58788de8abee5452fc4e8bf9739dd8e2c9665bfc586a6feef47a3377528e4fb914988e85d5ef42eef1f1250f67d53421381f502dbf2f6e76b2d282dba11972ca4729065f4489b225ad883f66ec4ebb612d2a6732cb7815aa444b032685821a2d05e88ef5de67743cb14e47b9717f2bd4b28fa51c8834c14dbe2359d2eda5e04f6cc82b3949cf1300d5b05599386b4b902ab5544af5a37c802a87bbaa7c56ab15a2c16abd25ab5aa51510bfd91f7e295a4b063b77ab688b69e9033cc05df74e7a0597d65d69f8f1fb88dbba3063c76ec96dc9e55351cdefc6ef88122081895180cc6400ea4c308931968c643b8fe332698cf476b74bb188fc1d1ed969cf1d98807505c219bceeb7ab7ba55c33d55cd62188bc1e2a1e26ddbea562577b3b85b0d04ee1e69b3d5c7e91fee14ec15109ab48089eb9d7cb990009231c38e3d6b713ff6ec093264d81b6652ecd82d192b36f41df5b6ba79ceef1f04fa869e65ac60719ac17ab7cab354dd52a92d354b5134ecd8d3f3b41edbefd0c28e3debe16184e597a965a5164b5857de915d2ef04fcb823bb0520b1400ddb17be413aa80a15185185c91c62c0cfd58ed8edde380f9a67e4a04cb2e25ac2bfc1ce0e0c777013812a8d25ab5aad11d3cbc17c460144bc127e7b055cd7a0106183e1f4e7c36f5fdbd9bda0146f5ef868f8bf09c3de72401bd4070923b9fc386d2270ffdd8be5ad8add08f1d9f79ce2a8a9e288aa11fcbac198fc18f492ff9e9663e853fa1fd58d3ed5b9aa2ea9e16bbc759b552cd6d9b556301847e66251dd81e703c27ed66f0669861003bccf218740bc851a29fc29ff0264e5d57a4fdd0431f6286c4aa67c794596805c85d9a6f6bd1bb87fc6c8b53c219084083c720b37eece4ae8659dda2fe85507ce11276ec1fc80e82acf1810c2e1612d53d7e6af10dab68705d1ae1fa11d28b9022b73c099574150d96b8feceac59f7a8ba877e17a56f6e5bd54416acc106cf0862b00bd6b317fc4967712cdee34e3c359b990bc04a7413492345b7a07b4a4cd8b17b1a4b8fae449485f60fcf6aba35a78d0d37ddd35724d713fab17ec7eeb99f0fde69d19f49cfd89028265d17bd121689eb3e32024b9b204775cb51cd6275688a95e1c28eacba11b116728a79b6b023a7e61dbbe7867eec773f1aae4c19836312d5e5b05946a4ecb64f11be100a1b2eb1b31f79f2174217b36ecdba35eb59cf7a26fa3c26020b3ac943898f3bc2f695339bc82bde829f90db4adab470b7d9b6711777fb99e26e1c645bdc9e4118d16b71631e39b33dc8861d79b56d630d77abd94a77fbcd13a174cdc8473090a3a436f211d2a6eff63ad28657726607470591286e224fdb6fa328fe7669a8847b98270b368a104a88f9de6f510899efbd10f4bfefb1bdd8b1778fd4d46db0de6e52272d6e4fc1f9dd90e476340c7b2ba8a5aefcb8c7e96a5ff44346159ca9db51cf3f5310d1b7bc10d1b788420f85881ec9e845db57b053d7c74fdb083485defbd07f4f2916ebdf813ca5c50dc84f9beb075310fadf5760bef740d8a62267b66ddbde51dfaac4f2d3c6ab16472e0bc4767ff8812ffdf938ed59c9630b8b74ac4ba2abf527581fecbb759ad77d921c1387eefe48bad1e6749bc71d6119a4b7d3bc0ddcee9cb7e3a8e6b579e336916cb1d6e77a61a0b0f46768da3c3485deb4bdbff726eefd33857ed382ccef7e0385ccef42d3f6dd8f9e0385f87ba12948f7a3376da1902eecbcff5ef4a370fb91fd9d963762cbe9de9a3621ecbf84435c46ef12f6f0537d99d37d3ff0252267ea87be203307c74ff5394e081cc562fb6b0f03dcfadf016e7d2f01b77e07ce204ff5bb8fd19033f537905e6945ced4dfea16f2acc7ad0f7e613bc525994db36cb381b828a52efaaa556693728a5344e80c01c2375ae801a619c2a81e7a60141bc127244b64194b649650a74d168d603c70fe188e3c2ecc8f31301004b8b29329996acd41b59eb5ced704a3ebac569133dd61bd22692a19ddcdfa457d7d95bd9a70f7578b3ea5c50a83e88458adfca38913153ed58c1a0b408d5533d86755cd60546da2731f39d344cef8aa09f729a4374ffdd1573d66a852a4c8eaac56a932bea957244d25430d2e083003d50463be6898af09868a7d26188c622b9a99d90ae62a92b9260a3ca078e01b2ddc767adbe19bfe5965dbb92f03f0d03656f8f020a170fdbb1b7e3118b4c6180c465533eacb06ea041a03e3c5d5a736a9aceb7c53a7a837a0c20b16cdae691e3ab52f477ea1c346702af472f118a42f35764375428dd526eaca058f5f3870119caa818a01f38bf9622bd8278619fa01105080d73140cbc1ab2b087835562adda82bd3fc15f00df73b3ca61ce8f37328ef568382aecc342cece8ab1b8fe3475f1d69aab3b3c353430e0ce9635ee6774a6fc4d672e5e72af015308defdcb1797aa7ee58122467585602f92567f097e12401466e8294338c3c46e9d3a173605ee60b327360428ee1c0696cbea84aa632d5ef4c5e0eda646575683ab0cf310e9236f20acb292642cef8f3b4c3fce46d04c16032495f3eda89e89dee22a88d2b4197675c85c388d9b1c48ef5a519616b65b1c871b26d8992a674a76738b1a88650ad27a7d888909f18c128ae019f425a830a86a4f1e7d3c8fb42cc4f5aa34104fde08cb0e394c9ac2cc112648481b094167de4d55abf90370a7d558a0bdef49955cc2753c9ec993c2e782eb80045cef877313b5b09247a882a9a54859a8a6735a4c08ebe72e2acda64861cca7c144a94ebaf49b9fe74caf59f54ae3f3fe153fc78f3256dba90289ec267be7cec8ab26c8b673eee4dc63aab41be92994f9f41981f6f9002cd8af9005680966fced9f2cd1781324703e54d329bdc80697ef46a0d3b726c7a9f17e220bb90354d24123128354dd3b417cfda29f31fc9b1561704cbdd915bab21f00d18d5293fadf8462c2dc17a5184920fec0e3855468b31366c6ae58a327250e81322fa165260b9cf851f3b3207f14de8fd17206d385104248ab330031802b286539eead405e2a798eb0bb30089b95cb1de36b07b408514bd7bb87fd08276c92460b1ead70e4f6a95e2d20784526d631ad157fac28c574cd3346db52af57da1a93c69979306ea29edd350ba74c36b1c8dc3d3869033fefefd4835c159f886959044a4ba2e08b6cec08e9d1a6bf87e882834f177434c1ceae488582b53bfe84dfcdef726ee5ec8f748a2e0f09174ff0185dcead5f51a1a8003878ef21c85833cf9ab80ac56da6ab5ea55af7ab581dceda4b6da9ac80a3aefade94f10887ae5bb12dfaa26411a825b928d598cae6bee2b5be48ceceeb691524ae914083ca4db946529a73085124be1eeeed259d0f168517a73523a5dca3927d542295896c297668b7336a1352de81514d4461b1bc7416183823627f51707390703776f7ab3062efca6014cf3af1467111dd53b6c481aef56725bbc020705695b6d1804050505f115244a6706a5256c12b7bb881a9d3a8ac2fae63d68b70abe9fa2605f73e3e88b9d080a92335e586e5f6d35c00112ae48238b531a965e99451a4069b45cceec20290976f4eef5cbec2c6ab123971718528c4ce9060e530e1d4e9d3a75da820b0f863b78bc000018c453000410c38c0c343d661800010840001a0a50538029e058a0aee1ff12cbd2a88ae5a17d3eaae631ee75faf4a6f7c3b4ed98eba5522db164395e776e9bd329f55992a5f652e9fea88a9d2df29c1e02b960f657540186cb3ba70004ab8424765cb67405c8c25cb1c11ded43a1c42500645141b1f5ca2cae2821801558d29559ccb2fcc006f998cd9e30843bafcc62b6e2e1413453b18d84f4765c39df0339e5a720fc14b33cc5101205c44fd2467bd92c2e1cbb899c2133909f805c40409bc370470682e18ed2757b8a3b843c39c75c3e72c683662d863c48693ea8da7cbe99a10d4c23830d4b48a147e6d3cd559b3229ccf09946c65260d40fed7b34ad292067e6ff8fc7a1b3bfc5b0a39c89dc125b2fdc125b2d51e41b8e314d174186c859bca6c05e8e6225e4c9bfc9f5af1a9dda8e97956bedda2c999bf358c6329ea99c30162bcdd34c38884e4da353abb5d6aac1180ce697f6fe42b6d0c21f39e392335d7bda5639308084f00d6f2199e594e6275866999fa858af07d6c42f734cdc3304ebfe1c964a1206b20556dc1948eee11bae82892ae48c5bd2466b438a5790a2f3c05d84ecc1c24d8265adbac00e445af487f5c81997c9aa4c26639946a7cffb5081b35ccc1823fdedfa04d1f0c0eda79e3592e3f617a1e198e3f673620c321cfb678edb438e5b84fb51738c392e573b346cff37c71c957eec815b84fe46bb508f8ee98eb6695be5667353db26a5734ef6baca6bfc748e5230bff3b6e91d0d694d84bc9fa0474790e4b24ff6c071bb73765c881d8aba6d200e9cba53dbd8351f5b05c769396e2b21ca7130fd83eb01e616e1e877dd2247e9e4be4e2e1c616e11e66ab8bd12db3f964a258fe3429a86c4a6bd168e20c96d0e9caef1164a19c3fc19a2da6fcf6d1bf5aa51285da8fbdf363727d7bdfde0c3f5bed2ed470edf9b55b0fdf6e78fde9bda08641bb7e547ee47a1f6ddc0859e0da9e8bb341cf9ebe7c3d6c295e511f9beef3322de5ac11ec4aebdee46b1866a35f1f620de16517d7912fdf72ddf712e2010f5ba70b3d62de4e2f238ce85b4d9e32a47f2c7df1ada14d87e17d3a86954f3b4f9385dc11be4cb4b696302222fcc0f09b8f56b38822417e6c7fa9b3743a12d7c6f9cb743a18f646248a4972191b649c281e36ffca8fd86e36571bcf613c717d1b690391ce1d6a27ded06285bb45f02678bf66540af45fb31a06dd13e098469d13e0c7843c660ff05c42167ecbb8039a468df04be3cd93b0a4b72c6fe078ee2b5e13712b945be1789be2e044405e5d4b45a1fc7ab374bfd31999365287466cdb7ca3c9d8990962307ad959b93a3b4bb2bad5b87638e4b7bc871399ee198e3ceafcf6d2d8eea9e8e39c2ea8190b675b4f98bd4ef2ced7e4ab939394a9fd66deba17427b7fde55c58027d4f9b97f26079b845ea87359cda15d80bb9c06e4f9dfbfe0a8a5db3859b87251c7fed37edfdb5d7e86b4184ec7f2ccb6d93deee4e6bad557bd7b4f75a04a2c2890bc356e3d1a8d0f7e9c51e4fe4008a99b1c68a7ed7021a36d40ae3fa8f1d3709a280ca7db9520b1410e176ecd51848d44b1bd2a54eff8926977ee743c8438bf4c31e5827240ac74fb46b76685e42d67440320c24cad61f590797527f7b433c7440d6701252a4cf3cb4fbcd93903552d2e71ea72cc5fab47eedf1a894751e929b03aaecd60f8542a15028140a8542a1901129bb45ea6f1f0ad5e7ed4bb11a7a9ee7799ef71d0e1ad0b045425fc48894dd51f4f53d6feb72e87efb31f4a328d4ea9cd5d6fa3538aabf3e10593726ecb6ddf0fd180a4729bba1914d41ec8f7e88fd91e887b4bc281c43ef3d8e87a311ed3d2058bedbcb9003badf3c50fb7e6cf543a1ef2ae87de759db6243ef51d0dfe285a31129bb5d38562e046ecff9d85aae7492c7e851b8270301511a82bdeaaeba542cb93917171c857211046b11fa11f56496140c73314dbfc0056b6182143016b77beaca0b1825d987909d0617c172cf546a5404172957a5b56a55a3dcd4298bc1cac10c542e18524f868911330315b74bd9e1e8c92ad30c54936a52a47a443c29508af5973255b03258ac8c1a56260d2bb386959fcb75f1662335048f8c10ecd8ad1d50b07c7e72c0aa3c907881b504005708828b284be041446bc62d2fe9a0c2cadbf24f856d9d524604c1375aad35a238a8540dd65639eb140d0800000008a3140000200c088703e2e18040a20782a83b14800b7c8c407462381608932887619451c6186310218400010118819991ea00be231d829503017ee523f858000fe934e6bd14408e7c2f48bddc293628b7668cfbd82a34b80ff58d0de48ee977fe6222a58955f1a59754c38eebc5b7c60c4662a7a14ad62fdf93d6308ca6c658645293f2e1525337a4beddceaa9adb35a60284b6dc3cd149aea25d23877de2a0634845399c9e97f975dc4b0745e765e4350209449ec12970fff12ca61edf472a8dec65c563683a5663114f67f615ea3374324360f9b59f8b8f8e925bc3c78bb47c48c70514cb1321624a297052b30ab69e8bf9920771daf3e3d61741ddc2d6721ec3530dd113343ddcdc17c4418420bbc44d145f2d1019cdca430c21da2ec409670f01d9bc8f5e1862ff62a1efcde85604ccf36a60e41eefb1c51bd54c743670b1d093a14bab127131ae1be6bfe2fbe49c2faeb40d62dc18686b29292347407b046573618310d36dbf6379cc9a889a3e08101d814272c68e62035168fbea7086647677a35f461cc0120f0aaa2516b38a08a94216a1af50e83a53f990341392ac1eeb63824c8f11cb85e3a110dd3b03e72638ff878994f9a18c49c83dbd9980321eb172f4b02603f81b42c38679fd8607d6870fe780c11b9d4f18fc5b767d9abc51d2150cb39f0e3c8242a02517254c14a400a37b0614c03a2fb04499aff770a17c9e0235fc2a6df0f0525d6e2803c56774c8da1946e0a8bfe47899b04b441d37e92841480725543b64421e69531b6530a15ff2762652e0cb33294d41af9495978a48187c25bdc248fb47135de44f3435d4c227b7496bfb3b49f8b91b530f7f94fa60080fa9f42be88c1634fda7345939f0c5e0d08937a205b297654355e34881e49438c8c72b0fed9ab6c76bbb98742a8f925367419bd2a3db73d43cf59b8e80988191b498d19aa73082fbe54b07f2f9e0e32917a77b9631facc2bb9a24b39108ec8df7f477e994587acb973b682fa487aecc635b9b891811f41140f41867221a81c41df8aa24bb1c86e2ba8055bfdcc9293845829ffba1d3fecc63b2256d91b01e1abb6f6483807e418ec476c25f1b2571906044e2e19d8f54dba583a52724682627cb320d59133c676da2aa6b3a56eb81983768bdcb47e34a4f07f9fc972a2cf1906dd924583587851246d84704f0e746604fb1ad19ea2f9db8a4bf2dd6689d9b0ad1320be5b037fe0e4bbc09d7a659b83cdf2c05c770c60ffe2f8509e77cdef3e6564aad574f657199f75f8f4d06bb80f0f7d322f778591aff05e6fa7cae2503f6b22a3a0e979cd644c86443a9e245a7946d7f13731c82a53c04771922436f8a7fb7e591329f7d456afe2dc3d73b92412e8c614fbde13a0a3ad0a82a6b2733b21132876a7effe14027633bb54b183c822787f1eff91a9628b3c1faf5ab44a14c909145a0ed886ea90d8e2d7e89577a32bd6c2b3dcd543749d839a898fc15cd9b29f1c933a0a48f5b354977e01ff0d5d021e76991e152b354721490af95754fba1039494ce715b34f82e2bf47ca3fafbf11f202f481d7dd457547616e1d373975cdc5a018ba09234bc86dc91d1da138f0752cdc0e5bf83d1397266496b774657556d41b2362e86ead366b7783911866bb7c7f441133891c063be15ca86d977bf421fdb963426a2d7bc8179ce6a77eaa924c3ccef1ca2dce60a6d93915a0ed72ef1efddd737d6e1ff3527a644940c341db1af6fa9ab93676ec97a9f2038332ab555336888815155d9dba9a1b8e03f3dc4e68fa81003aea8afb2fdb9608e48f8454736078d0debbc0be16a9e7101c7e6559e1e2f6b9793794426c564a0ac2612d2842ab453974678475b2391e0b8d9aaa26e1cd46f96de73e3a94bc92ae5d0f17d7e18528db4d444f2837f33d93a3f75e2e7796ed4b8031ee25d3c8f84bdc11a8298c821630fec94e76e46821cb1f975c3351414a4f9c48379ae87d2088ebe8b9116f9bc358cf770e9d8b61a4248a16d2909acad65c2b08a6c0dc60d53d09c59e838c4f0f1c716aab44e1dfd114f2294f033cb843edc6006664473d262991c1be3f261817066fab854d64570e23cdb817da47be1f9dac4394f8aa231d200dfacfd960e0f5cdcf96ae9efb0b07f703ca50b2d3b8b3d3cc0cdf194e84c676f3eca501150378d63684fcf4613bb32837a106310c9ef63e227e5c33872ca6ac421cb9e7c7d864352192a90a146e0314e5bd9f84ef527678a609848592d523c7d2c612ed23509920303599cd4a0ed794b0a5064d734c39e33bcebf80baa1be98636d1787e1b678d532253523036f182587722876f240745b41c385634f575ba32efc70fc162a1ef248ae23f403f5aa0a443145a76b9bdeaea3f92279f9c57af7c0d39d169f7a40b7159b1f0fb7108cee3fde500e851f6e57f394bcf7520c3da842c7755b8fa9b7d9b31eb787d7a2f5867d0b87433608c164c8ae5edf1c00de6db67c984ee2c6ff6c1a894f2230f96bc71ff709924c2d2ad0fd001e2c9ccdc735697168cb56063b188b193380ff0411ec4b4d77385895e7253b2371e3e4bb17667bdc9f226647bf9d0a59b1ea296860d9fe57fd70f696998460a8220749f2b08d28599825099efc44266468207b8df5eb5591dd4a00ec167e27ae536ae8e337931542554fac246b6f5120e0fc359051c998840edc109fdd81e56ce4ebbf9eacdfab1947f453bc034b3d2c27dc0928bd417a07cf5c79e225639a2f792a028de6885f75fccf8f71f70cc0b46c5f1d539a30d5e812f34afd09510aaff8fa4dddc0822549cab8e74126dea9a89aaeefb4f0307a083617586a0e2c508ddcd706162e22daf2ab62b13ce3d99d1fcd678e058821f5ac770d208c5078fefed67aabb894323331d3fbeb9b07ecba64aeea4e47918f6afd2256903897277bb1dc319c9cbc8e2ff6b700a2f99a7a9e10e4664525d6a821b690f3b41afca6d4b504aef3129a3e020a499760829b0086651e0fc8262e80ad8d7e8bd501481a2599666bc9a91f7e84f5184216793e54f10c1ac7e7214092632e603a6fa6c75c77fca21451731fcea82a5eacf26a0e2a06731e8f74cbdb7a77ba73a716ccdbd220cee1d266657f9aa96d9d1b9ab6b9a63ca7e56faacd8a19900d2edaec3fd32bab0fdc2280a4613f46d66ee7fe8523be24189fc9a1569d4d3db08e9d673e4eec35e862586773f2126ed00cfa240926df00a4e6471533fce91396e116474c3c0106f85291e72f4dc2f28163a115bac0c8f82dac4d72b96ef6141bc6c84a0271cc8ff009c38bb6affb12ae4df714c8d16bd880ff41bdb235e4f4f3679ed375198ca3c417d03bca9d68a9dcc8721a004479092519428c9942a80cf2d1fea4bf1359a0abcce9bc687105667e614333327cdc79f46d82a75f2b106c65700bc7c2fe13e1b3db829f677692fe3bb93ec59d188c96b38ab8cb27be0098ae03ba17e35966e73ff587cb7872717d8423254ed537054f98497aec21238c0916e15568d0a4bb2d348f4bebff37cd0254a121ba9dc099f059d1e26e829567f7ba94892b2e6bec56ed354a7c435f4dda696e12322fe789508ff8d59abae962ddfdc1f6d07a0a792b6c2498e492f0fc2a9c0e071981da593743964466e5aa8519997f355ff202c5b53f53c0df38af0b94cbf1f5f1c0a490c4e1e82d56c69188a612045c218c8ffbaa50dec70d26672b44ffe742e19a7f6fdd2663c58256965e953d367e1b1feec4362c335c1f6f5be3f2e2678df5accab67144e5f1d8c7316aa5637ef939915997b923018a2dafbf67e4c00f1ee5b0052d57454b90c204eea5b349de4f8658b1529760d362f51cbbac81f275aa24258a1f6119395a41b059d16923bb865a86be5d9b31bab77e9b0319eed1e88ee80cad6f9eccec4e0450aab8881e3b932d2cec9bab0c695fb0ddba3a238df61978543e1bd7e8555dbc85163f63d42f58e2762dcf7d05fc1e48984130eb09c6df7aa6f8547901942b079802dd79efc0763aa40d4a1290a9061effaa39b6b0db3d38ba62b4ed2e24677e4b5995d588bdaa417a52dba137a069e954c0bf9d893e5887a87478da10a3e5b2d238343c8975932ef3149c139ce0e52d704ed288279dd4108868e0c5fd4d408541643466f25bc4307535ed3bd21224e36b2f0a9c44563e81765c487668acf99733ca5eeafbd6ec2f03f4a4ab0da67e70c0404928832843367f7dd8dfa3e798cc300f067e646e4cb039be3f0b9ee84e2253a2689b4b233434dc537e5285d1385b58062363ae6ec809231eff1f258cf4839f6488b753c6b796ba50da9ee60ea084c936764dca09493d382871997036073667513e39f7cf84daa19e440b18cec99959a85441435bfd08fdf62e51b895b0c17d91247681ca79ede288f1590a41a93f991ad39882360c5ae27cdba6aaf167260429c5793cd5ccd9b1adef5016e64d981bbc6e58f84290e594de303dd5c45f7fe94c4ec6308e1ebc34decc3c5bc0fb7047d05e465b311ead1066bef6f532394d299dbb8d7171522e1b5cb450bfc9b4f0b8cf4afe402cf115c2c3d56f9f7dcb4428341ef1760e68a058af0e807bf42a18adef36a6c8dd3f63957416e08f4fba4f40351eaf5a009c1f3d50d7f9ed3e95fbae627b30ee21495855a4e512850cd9360bdd803bdf8449ddb9ec73db4f2c283f2ca602cb662438f6a1e227c3c135bcda7d698db6360d4bce879e81e189dcbdbd124c04d95ca03d5dc274f0f5011c68a5791f7a6c817d95d2bef506274f3b788c44a69464f2cb0000f3d7139b9ade9ef87659cf299f977d66c2ff1009b7178054ca3fa7db27ab62178c73cb38639ad5ac4b4f9c90c09897a5626750823fa3cc05a2537fd78f294db47a1f3a4a3f0df45231440ddcda4061a57807b421ec3c018ed87cd8fe48770cffb8825350f0ad8861e7a64cfcad27a32ea9370d26e0182db8f2db2c6582717a315adb60f48c00d2a966becb3e52383ca89c8012698d30286eae20cc8eea74f4011bb78e021da309366e49d047d1418eb580ae9b41bf260f1017d2f3f22b04061a0890d9da9683f7cf16a23336ad5010d61563857c890b1e267f11647ab93899b5f62151757564adcbc5202809efb6230cd1d19947b9fe6c38af442929805a357f3c9a3603cfbb996721101a13c5b2617512b416e7dec41999db32e8088502681933ed74ca29c75fe1f1352b4b94ff99731e1e4e79938ecda428228f29f160430a8aafdd90692c71b0bb976d944d1653f3c5dc8e567154bd8b756253e0e7580c0e6fed26b12003a7a8a13ac5ad76f45f67413fa26671ed93c0385c6df61b39bd6faaa109a0829e07143604f4801e5720458188e52959a5d7d6baca94f853d4c7065bb0bc0a789b60892ef01a8d6a6651be0a5803cbb28b5f3c3891b107ee99424b8d6069313d2ebbbc35e62c5805f0c60992c5e090ba1c32fd17e4d684ba47b851809d60113180c84adafaa24b7ec3bf08299051f3980117945db3ce2fd775d91574b1e4b3cb607a488eadcb387fc028e347cedd67e5163b6a34ab912383e3726ee01b85dd017e3ff17a06040f0357e474958ff9aa76a7c45c289b5ff245589b4f06287be8aaec2ca4b1c9c8f18a68c1954cb195a915f8b4cd8edde3fec5a9ec30fbb5496450144f8e2479b68e1e1ddc156405f45e28d0581eb1779d25c272096a1e856c190bc399c0e0c0d4d1bab1388b8fcc69e1997b1397ee0080afac909e7c045b2b181e6c6591e4ad92ca8fb6ca2e1602ba3d5881090048e7cf52791a5acf6ef22e49d18cca55ed2041ce1844555aeedc6334ab92b724d2f8962b5c264750a3c11f111af0fa4befeca44aa2c441726bdd51de875962ee9d673d212577e0494b893dc9f1f2076ea2b3af4555c2499f13d27d358884d030984c59edb302313af9b802246fc50a9664702315ed2c0bed99864461bae88b3e40d254a131a20a7e6ec4cb8081b6282a7be3a6e64c3ad1a0134be3d5dbed2c6932403b629b448fb656fc6562b68bd51bb069e162e09cd03dab434501b48d40481cdfcb9daabd62da73ce2a8a3bf20fc615f166713a7fc8be1ff082195134ae95c96247a4ba918f19fac2c26c4d5523ac3691aa5a5c132a133ad894579c03b3da7628cb296ffbc0f1c02b26d2fc7944e67915601c2d5184b79ab07f6119d595eea475d0968bb2046fa9fd0275a0c9cea1a1ca459abd0e309f723f2d4fcda9fcbf35c0287cd846c27b58bfb2df41090a7cdda70a508c473e33e733ede6fe8faaf627228bffe8085ed2f40a6936244ab85aef85c5bca5d02e0240350d4b564f65d6f27d3b9097fdd8260179d0eb1fbf33905a9dd9b693abe278436450cd299399907fe14032b97261eeffdbb20785798ad16774c7499abc7565588beeab1d9b62c6090d89c31a437633e82b1c861d126619c0d2537069f7f30edc2a2b3f89c9c0ef202035d7fda3d44ed9e65cb9b50b349766205ea63e24fc764c26ee49702dc836b427413b6eab33a95f77e0eba02375da3544ec7ec50997d46808267f42baa67ab44ed7d28aed67c781f8849c86f18abe4ef4c52612525d225ad2aa9335e7a7b6da33585bf1d6f4b592e853ea40d67ac1eb14af71ddc3b482026049b7146318c5b95051158bdcbe53a46329280273f235588625a9e726ff33c793ee859d082bd3151694f0f89028945fed400869570905306138e668650bff26a7f1b02a89654f0db86780258bce146720f3a14a80fc0cc503cfd3265ed272291cba4651cbdc0e4c3d54233b67a994ec94071e17b10fc9ad959c6863de13a3509103ece71197154f810b28aac71b810b982c5f69555cb0561bb3ea3b50ab5ddde324b7c4c19d2fb1972fa2a3b74e4a10354df1de5d49e35a79a8291ebf9b2fee7f6c67fa79058ee19ce729c060131d2af4fd861b510db865088016e153b3050a407f3d8754ac56616cd460a130f98c50babc8e9d575658cbed9d1d221d8b00651cc208058afa0b8310e85cc80a7ddb6eefaffc2e24f7a9bb7d886f1ab89ea8cd108b770f5b4ae139cacdff4a5753a2cb2a986ecd8d1a5672ae03184621fe4e08e210fdd2d3253ed57408c8d9f8a1727bf22ff4810deba87d44c8ebb40a3d7b1bb00640567909b401aeef254306c34412933e4a83fa0f614c494617c85cbd19061f9e8f1cc778453a8f749ef7c45c2ed2a362a8a9333c781fde05dcffc47a7280b957c8e75dec96b78878f9f2eafd40486538f0dc8a9e39944c785d1369c52172e5804b865177c45ed0e44dccb5bf2f1a5a6ab004e73e5fea79926bd0cea3a79e3a93618e933c9c954fa3a37395753930b1fafda91895b12c721f475c1efdab64105c874c130a5755b2daa8d82f4e39a095d9fa488902783718ef9ad1bb24e65ad1c63d9567cce61e87f6b5065a3e2929eb8d70e20aafa251934ecdde984a68e2f1955c91ea19b4e72a7d97c4eb0f85d5cf6bedbd8b12760395cc5b1f55fd90b9dc34f130ea2afad88ab917a9e66a61aaeffbb2946c79c6b23b161440637c1e1b19d7a79d489f52d347dad34711c3dcbc2a220054907b8b7999ef97cd1fc1b298a2a2864974c11208252cfa11882f9bb40d678d9d05956cf293512ee9c19b81fd6469576f48e8d1ef735fa2adda5059227711937d7cd7fd1b4f82fbc2b83b198759043ed751758359cd6da4fe4951974b66fa6156f5200164607de9b8bfb0fcbb561625f65e683200c49793afb5cd2f7ae0a9d5b3e1aea03873e66b1d68336534a935e6574c593d589b44017bd5c1442d51c1377a1cf7a020e84c220038eb037822945d2066bf8bf94383348cafd4ec43f15f965eba005dfa38c5f94d79dd0173418361c2652c4ca4014c6d0cda75a790a6c3b6c77e75d0c172c28e944d97def7b9bf023278373652ac0cd40851f94470874ec892d80e4205840504dd402b76863e2303983f840333d48bfc470146927868b43caa0f9fbe56af036f96627567684cf90fb8bc94437a27313e898aaf71de55d93720a664894be15e04e6b0692eaf21fa7ed279f8ecee91c9fd8f467f3010c54e58b8c3ee3cf83588622120379851b4cd506724796c55f7c137466dd480ac5c23d954a913415362dc572455ae454a2fa6092439b9c6a5632d84ad71aa96dc8574cd10d4143870757fda0eaa43bb958222f8d4f7e664e680ee7214a31420da84cb1fb486fae544dce469705c01619d9c14777395b892979c8276f4e656f3ff1923bf5f7da8e5dc75a76dd63ed1027b3b2512661992528744afbcb8384dc81d9c1addc6d13ca3b4ac70f33e04fb5c09c61d7fd5514c3109453fba7f7376747d22356e95a6c70e4c2d30e43d4f8e52825e83f163451592793fb1c708164ec42cd069b40ef372faab79aeb5d08e02aba14c8f89772c5c113ad6d4c635d718db58157d815a4a540b357f6686b29886a4aea35b1704d1423e1ea514af9eff46b03f7e40c146befa2e4a082743a62e493c56a59388c72c3b78637e7bbff6969afd01bf16b2fd8b8e0759dd5281b2d690b5445a2600ba3bb5515997af3c8d70a40faa3c1b6087b63274a8b953c88c22225637f931d6317e1d340abfe51dce3c8dd119ce2ef6c68a957288fa3e424ecdeaf16857b9189727cf047ea352b7e922e6735381b1a3e739024cfd994f4354e97e3df4227f08e61f1badbf04485f10658a42871c8f3df3f360f35c3990876a23d97f40af8fcad37b82ed38419ad85d44b05b3792b69bbf0a538118210d56c9d4333fa67820e086f4e56ad466e606c84f4cc9462702153efcefb9738e769f499ead904a0a266ec8e39eae699386d3d1a7e69c01345e61371e855938d850fdc6fedb294ae41bac012c82413f3f2f3488bda9195b8929b8c64d9e603e042d3824816f551d775c02bd3e042014622d81ea1455d3d8680b9020ef09b143345d436b4465d050acaa6bdd20dce09b342c0965c976d7e9c25811478f4935897280789c09e052abb292513246b7292ef97b1517837dbf7584d7826355e0c4c82ef4bd88cbedad2485170a98539c7c72774d0b2540bc64188c89bd4c05e44be5e66bfae8ca6d1844ac0aa6cfafcdb2c7ea527bb247fb12b663922516994b220407241a8c15df45c6b444b39f42ed0caa334e947ecea01e0e01b4999fc8495211cd2f03f5342e3dfdb1f314381cdca1b12f74ff7cb04bc79ed7b1a33347745c388eb07c760114d84ca408d1c2c6eeeb920ddd7f4b89be9c9c319e6a46769846ad9ba88646391849671d1224732c42b43c5fb2675a15156caf76d5d332685408b87f92245e70db3c999e57f8ee08e4cb6b836568e291631cb5a634c018363113cd8b3cfb6bdb6e542bc74b74e574cbcda6fea681b1b81da88f32a6412873c804b49388c3e136da31179c529214288ebf626180cbb29ada0c0e92697a3809ee35d5750a928a5a01ea0ac8e4f3cb615b002bca4909acedda0f333409b6a8ed4e3245f99bef2a4fc43a73bef2fb7e0e3d0e7347db10beec567b7f6d1a0d95bd9ca1bec8a6c67c091fb30685e80d6f9df290de3f41b8bbb3a4fec9566cea4745b2db16939930ce3bd515f85d5b054d88475c0bda4162217b89aeb02acd805495fae0b5827ca969cdcf76bd89480d51970bf68df2eea4a53d0febb1f76761c0d640586cc66e62c8f85144b571096a6c834dd44bbf2ecbc343ceee97e0570b77cbd8194313241a8d6f814684919f26ca4f9db682b84a6d591f1627ef86871d79e8a3d83d84f62c0c77325bb241a1b45e6580df458b80d45efcf3ea95b322aa279a250de6927100e51c66d354e259170e4afd76033d9977cdc7e34b2846d1e69aa3ba28c12c3b476e67b7b868fa73353a5cb2b228ed5ef9e33f85869e1186e487e5fe96b16a9b5a272eeee82fbc525cd913baa6052c51345e9e75a87570bb2189594c749b3f56d395d3c95392e2f4efd9452f95615b5ba1cb1786d18f655fb0ce96ea9525d003f817b37329f8c345bf4eddef37d1cf1bd719028622cfc2b325821db19f7ba70ca00ae07fb9e6ff0df889c884134f86796a680473bc76ad9a9b8b79ee7ce6b782d652615554de6fed04bc06d4c5f3bce8afa8171c83943ccd4938b296410aa9cd437b9fe052d0d9d2c078716da054ad7b430e9c20ed62cc48f3b0b12857949afb94e68e2d7779447ce82038a4fa8b21276704162160b5ae71a9a9836070e28496a2df502a8c404f5a13b6880185794ac46de8f1e1450c069cef43213e6d7d067b47545ed0a2bfaff20f11d798c13cb7c0ea1a29814602aca5d6a7d1116f97fb6bb8928afe32fc443b7e03448dcf4874939d2fb9dc54ec2be43f11509cc9bfc49e80cf4552cee392d321a1e4529a54b904ac7a88097663d64d949d90f9df9482f866cd027d9394816b029639427f392b781a70971c310ae20e3591e59c76dec0c768c1d3184d78891321861333118b865d15b14f08487316573211b30fe70bd8cf11715acd5278cf10a3bea32221d5269fefbda5878ebf5e45ddf2f580b1e0a1f19e3bceae34a3ca7159d3fbb125fee3b28405df5d8e0ae8d9c9cb25ea15711ee33faed09b2d18771b047053ee9db5f54c8451d475a20e5a17b14d88d1c8301264099a13358d0639bf96f600c542a812424348cb027f0497f9fe7b13e5732f99a389429bc1f11394787aa361f293dab8b93b52a80a819256b34183c7a99e35c1017c6de0eeb1da011d07809e703394b3ec37148ca8fea80e8692c19ee376cb7c6ed665c16753b526e43c32ef1f1bd40ace941cb2aaa1e66452427fea2ba8a75fab091612876a1e38d134474b6dc3ad6b9fd9b3f94809387112a9dd0ef897e794285fb66e4ac3eb393087579e873d8b645ca62407f0ab9d8095e7d9cbf75008d63c3906ddd2f69b194ad87279b308c445cc5a508f8a2c0227180d483053a945664be07935c3d10bb00bf16f8b34444fb3566a0bf04d0df57bae4bdaedb39497190f3556c51d19fd7353f41971cd0b7ecf145af628b364c841c6d99ded3d8eeaf3d12bedc1288585c112809dad72c3a1141ef622ca7cdcec4ad074305f961212c497d5e3da196ea4fa4b87e00ba79012d0914e225461a172ebf1c89cb49baccb27c31383893d463c2ebecbc5d4e4a2c3b54d0e38ac21b90c5e8a7dfd820d074d70f2dbc5bb1c3cf01c3d8153fcfe8e7768d801dc8904f5f2a77d0b8c91dea52209aec560413126372ae7adc81f0b6ae0d884be4298a59524ff80cadf0ed8b13804f9ee9a5376cc241d093b5d04bb43d01633c1c95082b975a7bd22f27878793d7bb7ab12a665cfc727bb4b30bceff3740683a3d17ab1a07db3e5aafece1ade5cbd1c6506e4cadcbf36a82c44c8714899b699bf1a88637b66f2c9a529b2c3875bf03b4d20e451bb4411dabaca8a03dc5cf031028da62da85bc971de37975f9f4d787cf24de9f236f7fa543f59c33b8da97a6c43227be219de69717263d78605fd8a262ef3bd56c1264c03834d1dff8cfd00fa49b9a18e46bb76633bb89227e609978cd67678572dcfab9405093fc8f92fa9fe8ea643ea110080bd1bb65c107c6d1516b5d8ec820abfb7948d8a91bccedd2219c6f6cb123ae369adf1cdaf44512d425acb64e3229acd232da5259af0681efec2a944ffefeb1cf80774e41f96e488f2f4e3d9e5252364cbefc358e8a3603e4eab29bb9362d37c3a0d0da615934e2d83c51fcd725a16454ca4389ea59efefb34277ab9ec678acd1c8bb2bd39db618a5816098fa94d3fd1207fd74b547ba1db55ae113048074599f588083968a4b4b85c0c84248c2454c3560c5910b455b2a3c58afd21f71767247e475082ab953b7e45f5524e9582465da05eebfbd6997e4f992b2f4f5a4db881c06c0a4d7d67bc1f89ea57781af84669ae280a0b005cb07592305274b13c07cd274cf89909791e90d7ba5677cbc703b3ac5b6a2bbc0458d9430b0f4e52040706b70b28e0a3d51edd8c334f4659e53ce3ea64c5818b52cf7a23b852634ae66282fed75974027c7a2fde03d72f33a0405017752da647fcc6586db16759d20ccd138705eb10887dc2b1bb9f8dde688f2e05b4cb06bf1f171dbcbd80c00711a3b064f5078878e0587d35072b00350cc416c71bffc577ba38cfe9e967af0126ee13f70d83e033a285c5d09334bca6c27ba71d4e8e328cd8a3824c3210daa9f7d9a57878468ee0bca12ef01190798b1a3ffc4228f214d449333111590d5e9085957caec71d2b76522de183abce98e283929bb0c3c32741a628e284cf4c42337dd292702d28e9a063b65193aa756b9b1eda37e107a249721fa66e0f566e236b042477cc24498bb8e115ecfca982a118f28991640a8502217a6d9af9a44964c5451f78eacb86ed401f0986db768170609ef253a239de19d036e78063c364888868eb4f10c2f1111fc102250502d7c51fe605aa6002b85e909bc48b02bcf7759d2e4d8c4208ae03b9c850bfd5234c496ca985aaeb6efd7a03c2916e8861f80379887ace64a8e5f198dbcc28c6d44d9c4ce7e529bc0ca89ee8dd376702f2b4a8b5c505884c3894d7888b7a620bd351be945398c0a85df348a5c5e1e617938bd8799b804ffcfcfb56b9466af445b4c140b745c255f69a6c79349a4c32a1cfd44aca486ff290fa160413f9fd7e16088e5304ff2428d209c36ddd3b0f651d636f423e24e3320371b8b03a12f390054ccade002aae2422e84fda2f007b3e7f929ceb911de67daabeded28e3995939401ab1ccfed6cb211e1fb8e9c187518c63524fef89127360f20a76c851bd7c98df9980922f9671015a120dd825ce4a4e670314d0d5923d733f64cbb2ae0954e47e2e5c9cdcb05f3f7a0d2b91111e5c1d641c654b3f12f543fbef36f58b32b80270d27e48eeb3d44c9987368972cd5938890eee583a4528daa243cb9d2ade01318176a1ec83400551d746c05257377d79dafe0e0d5e1dd9e0445983c947223a40ab65dcef9f373b469a651da47e74725e73d077ec8e6965439cee220736b156d504384abb47256734552ea69b7e3c8c6aefdfd39f684beedfd5addfe6a32c8563234d1c9b611a3e59682de7efc3f9cc9523a56e9d1beae5aacf5140103989c2fc295ad7a234caef29f09fb5e6c8108683702b27debefec2078b7bd8f30d63b3dbbe5a09ecc83aeafad2f8a7bca3eb97811049ac0b7062fe9bcfa42ee160a889461a9d8480ec0e816c7beda7fd032f960be7adeab3b9c8caec1322938b0c99fb87ac18e95726d3589a2bd914ee15614c8e2878ced75a91ccc2b267971f6206033d6c40842659c1870f6f464d0c4966ca4eafb8389cc5c979f83f208c3a8d5ea6a5ecf2902a3fdbdbe7d55b5e16bcd1e2d120c58a4eed2ff44c5a23af32a21eafe5274ae675bd202b1781b7b977bc458f31341cfd3a5fcdcfe4d16fcb1bbc71d36bb536bc0b41860ddba15cd57ac95a4ee5a80c2ac4628206b616561048263bf22c5ff297ba0589ea6596df46e90b8098d1606bbc0d8cb5c1374f38568380e479d9d93ec01835b218b3ed3b6017d4f146672bb16272407914d98677cbb03d85075738d915435a98ee133ada2bb344c77f03229762d1a06247fe9559683c493fbb80a63901fd4f30c9ced26ef9665f39a0cb7827a2303ac124d2cab1ad8efc8815588641a00990e4063113cc3ce6e48e056335808fff5bb61c61091b26e2409cc591941127f89df7548fd6e0a8fdbe87e72265b03bff47b848ce41d279cb386505bcb86e1512a82682e08f039accaaa3f1d821f8b8ea833e666c2bedb0bb1f41ce8b1f41b25704321c5dc7982e73cbee39979d9c8b07a7c1ad72f2455de5e6079621ff4397c95624d4c4e44f563a56fb85ce99d6693187bfcdbc7ef206e312f597f6ff9b4fd2ff8f234c3c873d66afc7ed2093f3fa336ca02f5d93830634cf50cec09e5dd3433f6de986aeab6a67dc425b6d72fd445846b305e31347b76ec7c9e7d26b0228e50bc1cadbb018cc32c211f40973cdf5a195e6c31f891c26d75cca0749b4b01b4d02309819702979098e58cca06f06ab16a7ed5b09ad5a57cb942e6bcc010428c38bce727881b00cfeeee52de91335e62b9b31c3c7e1ecf528d05502ba54c4e92d902da8bf41db79a83351565998c25dbedd2dd05c068fb2d08325c480095ba9da00320370fe0cdbbd9672169adeb1c5c013deb0c6f7824e796a75f927ba961c7da8c82de7a2a60552eb63cc2e7273ae33caa3e8c15def0aa967dab2c1235d47204ef60e8ac14ec39c36dc66272a09d368693d64e1a7d8548b501b9d64436f578cc0a91d7fa1ebcc0711a8a396a00f098dfc105b8fc4450ffc77fc1bcbfba6881b0130f04f78fa6199ca3e2ade1e464b2d54c3d9d36f3eb5f6c814e08db0ccc8a76b8fe0aeb85e22cc28c6b76c48ebc9e4c936c8cbfde80d50067932a70488eda1cc5418fdf0c1161aaa3389b47e3568e02efc6a8476a7a1c95edaf4cebc1693e46c57d739fe01def2e988f36c9a2d86089a8205a8f66a017ecd373c5fcf5c9a7677e5bb2564ef4187fd61ef230d5bedb92d1f3376296d6a1f738f8037c5425e256e2d54a054a277593a3698de56f2b439364c9a8ff736e74e993a741df893fd7fe589cb2097de9d4892cd0fcc27df14b77d7d6e2a4e32781d442a1e5c3ff5a487038e8bfe5c3aa06a8b44c53c4e3fea58e58c9d6d59e43f9c455e633b397bf3547d611b6e0fe3263b90fd73e503155d8135139d6ea9bceb09dfcbee6b68d518ef4833102308f05bdd9bf5e872d11da13a5cea7090c6215cac0eab1a07306d73731c952939fe242c1b2898b4ddc289d37ffe24a95ae4157389dc9d49c8b8f6244b2b55150a2b45e149a04005988b148c8820015d5117284e9fb3b9a927bfdbf90611f5345564eac866f1a22c833b2af3582bdbd6aaab9d683f4e45240ff7aa142329b53ecbe889501b987441c07c799f30585fe236fa0e10660b4c4bb9bc5daef4d047f0d4b9e69de3d5198d97343f303090520fd3832df14cf52cb583e3a6ae78a3e313981ecd011150c5f52546ab710b1d5064abd2d6e1a250b1e325e8dfd948e9b4635af7f821fb0f95e8ae8cdfdedee00b85f71430b41905ce800b2fd544a4f19afa98c9ba5019845343640308146e5ba8ddbe8db12775e516ccfaeef95d2ca8eb6b4b7c1fac90cb34a6f0fe87649fc06acc9d45139c4b2d0f4447a9589fca8468efd3465d36e01ae6c6a556df1417ce4da61366f3b4359e082c43f7832b46c64f52da8cd249d3c30163eb948199532daba5c35013f8ff5c0f246adba9cf79a03f0ef80038feb71211ee59bab93d725d11efff58b77a708bca225c6b40eb87bd468051d9028d183025c67c6b9b8e7c1907b8ed204326cc6ec953a385a8b13b532a145d74d78808b17360117c68bef7be55f3d8f9f1910d46be16b86c3f8d810235cee45e0945e111541407b8f3898c8ba21d73806765582bb4928b726323381f05acceeb205f0f65fe50fc70b016cdee488d459c4f6215b24f8e0f5e5dd2c0bab0a1b2adadddafbf6e10a9ff2ecb0478da5d73ee4691874bbf53af8dad139cfb2a97cc9f3b5be8edaf5602ae0f6b76fb911353420ad352d76693d5b827e4604f7d6ccc57556f35a9dd8a62b4676f062a3f9e7f764ca50b4bf98e15c5fed57208ec61e6aa52410365a32a65e31a3e93dede1b81ac0b921612618fcaf5137f0316924cb2ba91afbc3f088b3412f0ee0ea5c0f05c771a6c00f637c2ff4dae3abb303c073a4860960403e720c204e7f1fad39709caa27d337b3d8f572b435cdfee518661a1fab8e64c7aac1586b56135d92d04ee9f4d63bd516c0b8373841cfbc5d25c7e808eab1e4561e0a7a93ef7c731dabbdf6405a5f8b1bdd92a736942ca38c1eb349ee051910a27e10fa7b91ca5c36b8823aabef1560e81e719523f575bd954e8e7339e6bf5a9e8898e34a5044c255519bda83282a5114250c62d9ee4ddffa2f527888c3ac010c8901da01f4464842662a07192298eb8ceac5f06aacd9ec8c095d83b6fc4750ef763061710191f7f4c928bf0213922e17cfd6536e7b33fff955b81169749f1a24fb6bf3cfdf9b97156092585e526e78c3784ac03e78a6972122ec1f555c61ad2cff36ba604390421589e045a8d8b84c40507adf6880059aa38f437afa672929e0c3aab215180009ec6aac1beee8a69193f681eba3c8191780fbf1e20b8c2f1f62a7a115b98eb1e41499b8844d362555183c6e3eb8d203c692595ddf8712006d00f7be4fdc6b42c90b9d761a1a391f2804a517fbd31befa9c2c66238b965d8aaa705457bf331492926aa7fa412072f2a55d43b667c3572a716943480992cfbab67cba785ec4599643d24691e11e90ef8a5fe71226254ed1578e01342370d100a0b908d55a319bd39f03b5e4f8ef37e08f08132b861af9d7cfa2472173224eb4b1c38bccc3248538457c8053a530a8ae51adb598f00526cbfccc4c04a98af0306c82a11749d0aabbd1b6b792271985770eca1f4997a4ab0c6d8d5338515f50a40d8c8459d845a8b275a4ef9042e753d4f5db404563f4b071639572520742d9187634997d189dbfa0de42ef91b8763fbbb5b317d6ae28543b9d112125506f9e16be829ca297f0c1b3df5090a63763051609219350dfcf5fa94678abcd5be8ca8339671a17cd1c03ff374ae99f51bd1603a2fd9322b3e8e4cec10fa41f4cc756bc46f3a1ec5d0f301ed8ec67339f317579e66fb081581c28588ae07f415013c91c18fba3b17708d838dd92f789e061d1356d24ac02c0dd0d8d3ba44f89d5c8068e967ceb94889e3e9e87064450dbffd478324cf4270e13f38285755964f537853fc403042b298e68b8368f58259cd3b0ce9bb468b55bbcde7aa59f90b3b4629364c128dd11106a82541c474d47441defa9a7f9938c439b8a2997211d64c9642a607c27432e8c6ad1ddf089a30ec1f4509bc0c26b922cb9fd16c68cfa4cb6db18fe540352eaead0413a5469fbe9a65cda02c7ee85ee788a1fce28727b3a4e2eb0d320e1b568b040b8c4bb85aec536a096d12d0c2ad7adb391190e3a986aad53d1cc8640f6f42e1375e6a17673b6af547e90ec9d18f0c7e447f8109d111f3446b3c72ffbd4e54d4e95daf9d7b1e57a0a8dd50c5395789b2d50e58a0598d51e682997d6239a6235c1e3c1d0415cd0226df024a5d5a4c27010ab4488784b62d83eb2d66ff073183d34b028a101ff8c223eac5731199bdbb907c02cb845d3abd65008a26b44b5ac8195b12931140e5271483179949ecdbc3599abef333c0305bd4f7005d9bf6366428191c05f3399ce9027f82b5f5812e71a14ed8a77c4d0cd7a8b9084e4b95c997e3b4041a64a454ff9410ceba45f069ec5ac8f434dc2172e147c05c3c255a094cd68609be864c7187b95aa7c5ea772e295581975fdc8624c10bbb847b41986a1a18f6385930a229bda2ed9acf82e043662dbfb357c6bdc288f4f2f1dd9f77ca03ff6f0466b223fdd86e13ab702b56faa9a1d2124363f76b2e59dd73d62910cf27ca79b55bcd0c179e0a1eaaee09b3109ccfa525ba8aeb28c5c329b5aa16eb2b00aed95bf1f3d53ea74f7af1c0e152137d7690c7e59a8a7442e6505a20e556a8c6d0361215711ab69d2ecf02ca479a40cf4479b4d47c8e082d13e4a78a1fb250f3a00e2a7b03470a6e790f266847048d73c388ebbe0576a69a21867b50a56d3240b84eeb1050ce30f51df03facf240fc2737b75f20f8c1f0bfc00d985ab818a44c9c3b43c214af8684d774b88823520d9986bdc0030b48be3261e90744ad06447b62123fca6aea5c073ab635d7de7d15104668d5471c72af988a05676de3d14e2ff8b2dc947626ce4987912034bb469ec6d324f24d2e0ee99d784db08fe7cecf5b1a85aa0558531a752b115c0f2902828ced5ae075662a5715beb97eccaeccc5e2204c011cfcd0ff0a73b3f79512a78d65da5f2c448e41ef030c2b793a33b53233d8ca4caaed376b14f1439904c84c6a534eae9459c69948654fbe1094bcd09848c0bacbcc65289c9ad8b5acb7253c9e63d59047c13374ef98a28495f3dda9c917b0174726125df9f9242e258eb46ea183b467b38bd29773a06ae66edc46e5d3ebb7c30b5c5ba2d6980648505cb5769e37af64ecffc9c9fba4c3e1236ca722b7740ceb09f8f65017f45029694eb6ee9366a50715d36e507b1462eee151948956beb9ab25824611e58059e24bb288efb57bc0ae052fc7184c732962b75c3f599088e0b2145dee4b46cd260e50296eb3c4334b7da4757d30da6ee8a3dc04250ca2ec6158c4b39c02e002a30545b021a93569152362e60a4fce5e2b0adc835fb1fbc91e79c5d32e3bc4491944abefef218349fefe0615bb64ec6086ed398ab56074b98787878650a5d84ad8688c1a4815f5be54c546513d381a6e744de59086391621abc8062f4523f4a3ffe4e9355cbc8ba6455ca6044d64691c215b44bef2ef281d8a2074969fc411ce749b3f8de30346694764432f467d152053262610252f89f67f47204e3152dffa2b00d39b122377c1906cc63ad40f38e4bc1dc49a3606060517cb5453d0434545ea8e02870b859d2797991933fa02d40022fb9f4ec487b812a6b2c551656b6162d6ab1759e212cf2d42872a43e0e3ec372d24f37d0f7a0e6daf41a95c80bbff0e0bebe6488af7971bdee534414e3251f37d3ac799860e7f5fd4b5a093b152940a8b4bfd6a2994eeefb0eba935904531738fa657f40969208c7f7f2994a5ea02f7a8ec9d0dbc9c4cc21d7bdef28a753fb66440fd19f869495b0254b3fb5a76310280719d06aa424d6c656db36ca44013692b63648166333396415c843628f94abe19067717ddea9b9b8f4ec0f5173844da8ddb29f5b633229295c741d50b64d846a6919f798061e383158e3dcb2dc83e171a1a0db89c16000c92fb1e903789fbd75ee15ffdf1e465c35fff4364afbfaf0d82d4a5c1b64c31369c2a72b2f484b7b5c773234f066760f09a3b486519ec1804b14f5ff005528f40c6c140be2b27d7a87ad1cefee41d59701c540c5fe38cb3f408a28ae60fb1f489c352821e5f3eec3b983c7e84f070902cf36a5f0329dea20ce823e7d52cdd341faf293e4d3fca3b6b4f59a01d18d4fb3f0c8ecfbf3645782d48937c02f98d68dc1790220554f573186f890bc1748a4597574a351d09bbe7cbbb13eea38a36032b7520b900d31dfa05b628ef1c880c30eede5673e8ef87be4c7e1eb3e55b866e0a79dadd40aabd51e921593fb3eabad598bcd788bf04b2c9ab31c7e75d4e10c224a11e9cd4ba65f08e3cc21b01dc220f0f6f5ed04294f40b74bd946c45b5dcd841042204f87a0c9717aed7ab3d2a7e0cebbb3119690915dc9aca0012a7ef3130b7536e2e6ee58f192d5b0ac29fc0b596748b9540714395b971c789a720136ea2fa8be33155595b6d6d6772a90b580180f8ce6841253249b30222e85683a470d91e0ab8f4b70bc75d09e98134fd31aea8ec283a8f09de0a7ee68f366764003e7f76ae6ad0b9d7cd06599c9ef408b1dc97c52c82833c5317b09a78b3d65a375e56e4778f4b56e9b52f5b88efcba089e1a16d9a76bde1d1a2b4cbd5482a26a1aad7a7c7943776cf268f8881cfb7c09d80e120685fea9d962354b9b78278d0108992b8e7119a2e11882358e84b6a0ca60e7f372ea5a4288b6d51fb7484338e9e5e9c055cb4eb64f71eb6fa4a97ac46df0ef065bfd2fbc7191135d0314496d5d6f6d0d4ea9d15c51499160462b4659f6f67cb5066df22d47c1472e245c4bd146381a3aa6a735dc80d6eb96ee6631cd488ef3e049664085221c92cc74329a41edc4081a040d95204220ac4b61e7d42aa30e2a0e28860eaada6da05f6e0679e86e822c548782637334fabbe432b30e7dc3e7d8b0a66d3f8fb007fb6a188bf7533a02dd17b61429582066fa45ea122d13a8f2f60397ee7b184d750926b9fc28f8c4a6d27e452aa3b6a52f239f446ba9eb5507c1f3ab679afd9efd684f1845eed7a9da8cfdbba0bb96f3a2cac22efcad9e5dbf43cd628cc9c14b5ca529d572770bdd9507b3de01fc7ce78bd3b4d4fb9ca8ef177eb6d58ddd0812329467668e28bf966fb571cf5643c7faea3059afbc912ced37bbf97b964c2784b009f2928709a1825dcaf8ec062162887248ccd996342aec5b84102d5a6808ab3063cc6f35572a62e1d60575b5670401b140f2f797353a151969c240abcb8a20228c53ecca4065eb49f49c471e4955b3b000f70e0a4be99a45fd90938b70e66deacf1b407386deaf54dc40afcda5a6fc1ef220c125caa2b68bf22ebd66b1a2b164d048e9b91f043cd90b1eed4d2ef84b7a24dd553fc67acccf4008e53f6b294901957b12f5931b6ac2b113317a808dd0198c10ac51bce247a1bc793b8d6e96222823580bcf9d5e2f028cf6116b88784fa1477a281d1478ca9f35bcc636c3f7c5a281d85d147496f99f93eb35db15e8cc61b4d7efc7d2b79128fb569443dc1a64dc61fff640d6f6c766e0d12215657bfc6f62c4750b4505f78ac4e10a64a32fe686b7615b69c5c0ae92c0a22700f846c218276444d40cbb17ee03299ae07c477e25768117b896aad7714be3377a34a3d45c14dcb5d9f716d6a977369d902cbfce970841ffc4f5af51501f3884f3e731b1a35867322e79ccf47e886d3b51a4a280833144b7a5474a04d89b0964cd6901b48ca40eb973c2bf394752dc574425f982846bd873182f02d91024493f710e6c14c9b46c4a1c08594c76df400da0f2e01a8857bfb5a898582d00ae02214b6e6ef2c3454378e5c21489225b05db4ca9352e449d2f2eee4e5bdda8cc85296e8ac50286eae97a543630f61db0d222c49d757cc95473c494f063da26680a3b9513ee5830a644aad338cc6feaa84f8582bed672ae3304b0598e44f3afd3aeafce0814fcebc18e38b4355e87072329138114b99cbc3556467c8619dc2c96843a39cf5423fe3c5f823b705ca74b8e12b46a32ad5bb82ab18456b044bd7f221badef67c1bfa5b8b8486a96f32ee7604e8136b2d3b1463569c224fd5081938db3842338759a1e62d8975b51cb035efb896ecd57b988c9f98db4b8094598883b5774d6e1dee0ee66a529f4138a8b523d5f4f2ba775c60f15d6eae4df50db6d3903c251f32f6e456bfd982dc5d33e1a89a497b79b9dd5ab2b5bd0f546a63e5fd02c775124834fc825ca88a773ed052fb968884c1f2d86d71db0831c29fb86fc8f1f562babc4a55819fdc726bb5025497ff15f070fa2081c07cc1041d733fc712687c483b40499f62515e8b23b4cd6136430e1f8114dcf68937942d3cd88069bf34d093fd49edb71ae438b505b0db13f7fa85fc3c3f90a70a73c1eca04b893d396d5ce548a608b56aac3f461f3e1883c6b6145afade6c7d47486aff547ffa1e309464cd51cc8abe60b32dee670bf29f10c5d6c2f7b35403ccd563006149c698f491129f04805ab7acbd67fab2c9f2bbfe74ad21faa31db21bd92974f4ce58600d52c957c734a6dcfc42d1043c1063cac03d47808d022b21bcae03ecc905fab4299a5ea87db60ca89c75f3d0d2d6df536c884a9d4de24943b1010180183ff4cdecfdd7ff9241fd9a3f61ec02c3eec0649c7ef1927276019a35cc76d40bbae92d2ad134498f5c8291206df0f47f7da3b3add1c53e52f71b8b45a48358c0baf7b80207945d21a5a14b029f29c6c70cd2d0a7bdd7701ae00ec42ed4f9ca8876dbd0f5a4a714e3329225f7429d8bef3b3c99d5804b695a2a18d2241c265321802d0ca5994d49fd05fbc192997f3035d7f355d2f03040518916a39b8fff20832233f1f635301b10479b9428b107196bd671ad3c79b062bfbda63a66242763aea0c90d8f195331cf40e55788661425ecec129d767ab7dc62db50a9c6a84f3822163ddd55f8aaa6f9070b4fe71b9257f7fe4279840e06a57414ff1fd6f14506cb6ae73d3e82b04d2cf3a883b16f3c95d1a56046b6b242048c0990072ed398f2284a98ede53d156c3e4e8476ff4f68ec85cde5dca377c65af6f9b4c88d5821179841d8db743c4295d300d020c28541c4b5389179e5c20b3989843763fcc75f9d857f5e82e163c75dfe661eb532b4e5578532764f12ea9714994ca643d5d1029edc9baaf7000df0d511dac74852796846c1140f720ba2c0b81615470467bc1fbf81af2b421fa74f0a7b3097fa2f612a1c85999e5e965986774b936cebb08a1615d8f89af748212b572a633b99807a0de10d7eed93b476685f9203cf8e17dee0cb5b3badecc917645e8fe4fa6bfb31a59689760ed39378155441df9f182902d7939b78b6dc8a6cd193829dd2599a328ae56e931a69485f2420d909b73d9da4d84d927462421efa566b53b5228a0107d2fced97c73bee3e59fa9b712dd61f4a8197531e9224f95e5559bad5b270a3965b34fdf71ee4cb7b007dddc6e84e02a8610ddba6924b7a9ea6912e07d494c8523827b1894ba6bdb50e17f14c40cf92aa43dbd6a21fd9b01eb48157b87166b72d1c59ca7d6eb591d4bdb5a9bf96433a7e90c7bd05156dbb39fe5f73f3cea106fa4e084904765faae98450b1e28076b2fe166cc501fc13e348389cc00953170fb69d8d17ba463bd930a6b2fac7a720f214b0c0800f6303326f030a2d08d7d76b8d8702a916a057510362d2b2dd0484e9762b938f4b76836b77c4f7883706d9d1414ecff5c94e9cb8cf875985b3e26fa47e7ca633fcd83da2d6d97df527ce3ebc575aa9aef2890aa645f1ee506b4524da4930761a56a4536f3090473a97474df0f1ad17b5b879d385ba251ac5f9a5c64b7d929518719896832d579e0052db554ab831fff57550b9c2cbb03ab063933e05b1c0293f43044f9dbb623825ac23e12b1fc4e674f0098f1acfab472b1594b522515a416917106e990b8ce03c3c34091291c4e8a813ae3685f0ef1a98500f94308a1d756dae7cb2a5f6e658950c04e4c85a4be542a479914dc310bf9975cf4f322f5b52379eb11037ed306ebfa3655f630ce5fcc01e9f9c98166db4f5fe5e623db08419def7fa089d080841320d70aefef0bf2a4509736d4381f81925b79554291f956d85ec7962c30373e2240361958d5fedfd12f05eff5a5d06742e4678de72102b8c0549b00b2d21fe392bad65083ecc6012a327240bbb1ea6a11677274c30acb7e1e5af74a3b836b195388c735e1b1f97a0a6962a55d1d9f5c813896a7c0b1d1625af4bad9f9cd41c8c43d778dd373bf0f9e755d83c2a86a444a63c997ad0447c40f54632fd0670905deb60dba56a574d4649c51f7a314de94b19759f6c873753408ae49f71aa7b714329dc36bc202a6e976d140ff3529492b5c87246bd7fdf145c56e8408bde28f1f9d5e9feda39d0c5b952a073dff8627b7ea805f9d57b96121966ae616751879a27bc0cd9e7671d894aeb0148c3f6c6b94d53e09bc35b44753a9e4d775fb5eec89dd14b66cce6f65938355d55c0c5a3ed5d2d6ba02bf1defc8d29f330871c5200e9ff49c4ab5f0ff17159cc96ecfbca8520672cf8c917a4b5f3c632e862609f695b774ef219ff7bda407a08f15b0f75b81247dba1dc1dec5cb247d8dfebc17f17520556ada65aa06d490ad59fb8e6c49a7d9f7736fa4af0afe222686b141fa0158aea41ad1e8706f3fc1692bc32e2157c2a4e200350c06651d176e9f0fa304d0cc72a4931a550b6587f31c7c54ed61ce0e010efa047a58c50b2a57fe8b70e481b387e37da9976ac9850bf24c901ffce85072cf5865dac2a908f8b882047795b8bb78919c2607f8dc3c5a718887f70d08520dec343fb623efcb9f448c1550f07c1ba075b910c8f916b65450faaec150dc6c2d3cfa2b56776082c831e885cdcb5b69235d4497e65fab67bf4ff8839ed58004fdae901f09aa887e147bdfbf5d65c65b1999084ba0f27058139ea1e60c0d37cd68948194b7c0e8be9f585c64bc6c5100ce9b7a840c1b06714eb6f7f4e2cacf54326a33a49d6480b3742d5e3554f47ff171e187c51eb6aa0976ed496cdd87ed71aa3598c8c8691360e181bb2247e3dc863f5cad877b7a5eb97135b53dd7176d7dd3006d41744b58b861f889eb4468750ee73278ef2b21ca1d5950073c1e926da58250b7aa7d6478c4c784f0bed51d158f0ebe6fe26330b56c7d07eb6809de72265587175e8cb17e3ce22a05ba4500e543f3fce8e5685017928857d4793454fc5166c922f2cc327b8faa5825437b6d4addab460aee7116537f3cc418d47155f41b21132578edc403ea7f62d4e58567f007ff4c61ab1cb90d0cfaa09a8277a97e45a8b6e78b162a717221af6fb13d515431aaa4a5f1ae85296165a6ac3363d61740b3ab36e1edc34e8e73a022d724bdcd3a980ffab6e1de5e3e8e1ffa931f263d5af061e1e56a83d503791bfaf1c2711d1ee8280d94c371afa5baff85b174653d6c875dc2a9e609f4484b3cb16bf99bf630eea650ee31b31e9bac271579a3eca32efc7bf5eb044ea4589c080ec20ee8aadb75cb7bceb7cc6890a3647ab4a28236f08a7d7fd1d82f40b82a5c231143f6261e17307c6095423d57bbca23bcbc7c95d3a72d2c35b76f67af91ebff4e8dba568c277e13978078944ba48ed8b8e1758a17236f7c5dc809936a37e564f8c8d9d732019dc49802a5ac3cc039dc8c795acf1523141dce6eb6e9aa19fb4f72852806595ad795a88ecb557e5e7d3ec0b85d692981b1d577d4c1668b822efd5c3fadd2f4e82fa47e701e65100a11d776c292f27656edecd981e89245be302bfa8e5e81f18bdd1cba40a5ec19656b02e502fc18be709cc1699f1afc16ca9353829eadd98066242e4f88382bb879148e9da0dbe338fb7d083b6fbe66f3c816a3b20ff266889bec9a43932dc638867f85e655f1384c923de503f4c1af2afc68a0a1fbc2297da0d7ea3587929a9d2838c8e09a535aa4b76d6a054e267e3d9132bbcc60447606306dd0ced5c386721e0403edb3d8dc2b64d09f9a239d512b04e0d6b3814196502292a118021364eced07821573f4cf3da7d6ba94ac75a1087c6e7a78dcfe2f8b87741cf156de9d449a58e552df95b6cef5716428b37354f98f62023887376ab4824a55d27b8852181028d24bb517f0fcf60695aa465575b7d16adc11954f650496f52d24cdc67593ac11ca4291676f48fd23a342dd4b685da3332ab5f4991be8a6c6e89c9df6ca31467d49139b90cce8c4d4c06ea3b35ce854f143f1c03bb7596f7462b25f9c8262d49ad7dec663ab49a4ae0fb0991d0a35b6dccb1f2e7dd5be6ab4a33f302331fc2b2798cdde9b71596d2319478362bf842471b7ff025bed5e28ee6c509cf363e15bc4a846241b62a212c39e895aa38478592d1516ee7b5b95c1be73ec1f5a1285a9a09879cfb76eada1f960f23f59eafc89555a69a21babf1e5978eec61b5c6a626d0c22865e14d30c6b72ccfb049de909c0e5893bad84ba0b090495ebb2e3f0ab28a5ca4d2ca62b40030a16c9dffa9136916adea9c9d1ceae7038e2ad8d831a2734b87f0d7b2f6f4358785e9723027b308fb39385b8e4763e6e67fc9b5c8ab22928039684407cc98a5e7d37803e6f4c1acfed4bb1c37e5cc1963d3bf4c743c06633c68fc7dec89c9e05e61073b5a5d4e9398ddc8c7e0bddd5f35923c931b3d44372de55da5b9506a1ce657a24645f93b58010077e1688aa9cd85404b7c4c61971ca5ed1277364535c2de422f01e082a74240677c8e6289f66e51350561b86de8f2aa2441913567d00c7aefb18b124e53ebf057edda8d7f188b653e06ca313c8ad9d723b8fb32f1a27bedf5cbfb6e1186c367a54d0fd303d7bf0f4898164f49652ac71e0b38f0052b202d93218592a76a96372ce426b1b60e2959267c59fb08dacb26e24d24627e63b7bcf632f6d3d75a08efa32707fb9a2bced37b22e81c2d9d97434ce3a6a7b0ba434fcfd6017949e25e117db16365681a49d5cc4fd7363f520380e6a37518eed6759fa062b811c833dda6528674c0ab7c2be5159a62e8c2abede6270149c965c03a01456f581803ae4773547491a52c8b295504bf3492ffe5bb220a43e1cb6001fbc75948f49ce875b3e055c1fa2d496914d7f49e98e7a1678b2351aba528ff14a2252a6c753bffb0a044f76e813b84b0538fa1060144887e98976c9eebc5f89bd03a3b4e04b68088230889623d728f9096b1b29f97066974153456f15f5fe6aa040ad4df7ea73fe6d737acb29cd20e0b87b158d053836670a23b31c6fb27fc13df39f906dc7a7289fba17c1e3b5d0de847b97058c6799d409d78a93f441be76eb8d0719639cbe3bedabba07ed830c55704aa1054e6c08b7b26be44bf6345fd8bac2094d383bb1863e625c538050df18cdc375352f06e6665313d6789299d5692393fd1d468ffa8889a866fe5a6f9aab8288b89f68889896e146a7427c5037697a0eda944a3f4cdd0d98c308fa41d397ca52fbc7d653a02f5b2ea7f08e00831546719dd025a379c9fb87fa5f1eada8d64c1c3c8e43ff861a331588160a9cbf19027d095e9d4d98f8aa358f23ddd8b598aa89ae982d8431b853aaeb7ef0d859cc9d62c7e864e4f771efb18144d34e1df75abc740e2f84820a387f1042f21e3985d25cf354388f0b6632d949cb9caac901631b9318d1e92e7f5caa3842bb485ad398d724f584b910b4b985c743128953147c49ed9329acf4cecbc7ce2673590d9263be40a25f640c19d3df2d27d04cf07aa2b37eeb8a6cc08ca470b6385b85ba5be7a19702608ea502acddcd01486ffbfdfcd5de33045c3656954c9ba1be85f4f2060fc9faf57042bebbb7633e167f2eb34e47e293714a51a3341ad46252a6f6cd9ef476d3de991030cee72ddffcbc953b68367e287373fcdd7cbf2ac1b5a22d8847abe6ff29a7577d09f8bb8c0becb6fbb2220726fdf21c3deafb67ff65fe7ce1f4e3867c8a6a818eadc00965592df155e94bac654d4c3acc5cc779abc3dfac21c553dab8f72515a061bfde0dc546817b04189831efcb38affc2f17725eb6c234247ef9672a1e89c83791321e0852e196ae8094afa8fa1f5152949fa0f8bf1f9f465ca3a994d33f7b8c825872c8dd086d3b38f8d1f7874ed0166668a903049ff5ae76fd66343d5d093fbeea8e8036d7688ea6cac5bef200826943caed7f0811df30412c11fbca212782af7d19c8e913e45b6b7b46888e1997ba42e8592dc03d6e03f03078b42aedffd213bfcb1f592e4dc31725c33e68b7bf48057fea93548e7bc4f65debc9936efbbdd883e40e025bf7441c6e357b4669b008202f61ded44344c7d0c8b5e9c9068beb6537a4c2b2c3a7b49ecaed3414fc8d9a9609b38f623b0d14f1533e27264ffacff7aeea69e0339abde8a9b82e4564bcb9d90a9251a35217dce79afea1f3f4a311340915afa33a7d4a5bcf6d2feb0c2437cfe7d4a5f0d938dc078240d38a3d9b7fed5124ccac30d29f4b09ee7c0ce7ca317a3e1cc91623755f112d9fb510669083a3f20341fa0ea2ba4857485f7ebc7069755aa734ca69c14360906d9164d84c5fa62029db6416cf029f0e7862ad9d025cfb6d1f3f11bdda828310ce5ac863dadcb615b3b931a364b0d34d101d9134bababbbb8273b3e7f2b9d411f2702aa5b6208df89b9317e2d9541c42e2ee339f4988a49fd10310c3b3562775608f19145b66cb5c34046054878edecde7831cf2d8ba59f37467a525620f6c728434484dbbb32cca6cca8fafcda45078c2d3f2b3f27bba120fecf4dc575610d4229a0acc7f9498cca52a28105ceb7817f358f7db4582d9aaccddd98f5638ec5b1e45cbc7a86ba177178e9ac0d22d536df35e5d983e29fd24e654a1e196ccb60ea7c46efc720b94b39d0f86a0fe526a68b8cfb085d8c81f5f8dca0aa9efadc06858e3460e8e18cfd92f6dd29037017899a9b7cbe2a88f623383910d92d5c36579180ebdc884f95ca153a81e0e27eebfdb6315bf4bd2e9fe78202ef21cd02d1de1283fa8b8f07b76dd4012f09cf85d141978e4c8b0ca5c1ed57f5097f1e580b71a9ebd63bc907d847a4f233f60ec5aebfb7d059840d6d6ce2ecda2975ae2459ad4765098b69d0040c23db036a54ec11ff7cd04a06d50dfa6fe90dba93b3a37e47d1dc3feaa34047122dc329d769ecd06878ae8c1e912f0b9773e1fd2138ae19c70d3dcae23265eb67005e042d415aac143326cdb63c3e510632e5ad72a23fc46b8806810b02c1ae90c6054cd09b4521e61b7a606ce456d8ecea77d1064835b88ae6eeba25c81c943a21b365d98dcf830b070d590f74d5c20098ad43b984220bba0196bdfb4bc9beeaa1088ba4d307ce6675b8f1f3b96d9b940b82cab9f7f592673bcd4b6b4291ad1269c710d9b8b0abc45ec7ac7a85a2560a8f3494432a8bcec00a73fd92046ec9f35b22df7c065b2843bd1a0c3284c47b7c1d47437a70136e0f2040bfcb761f6f148eca114cc925b37fac8ec002a44d804f0c470fa8498ade2733158ab1b913c037c87cfb4b92292f790281b4609bdadee8b8c8fc23ebc390870bc157e6cf8e17303148b2a60591679d76f096378cba85a15f07bf357a085b825fae9737804adf64e537426242861c1eafc08e3eac8380ea3898d9d0a553f53374270a4be45a7fdc088d3f8923ff4f1779cdd4c2ee98926b855985b13d1fbcbfa42eacbfefcbdefcc464e88f56aefafd74314526e408b3b23a434c741706dbd60926e0db4f99b7d8b4b8b5e2e2e2757c9bef8567be60500096dd4ddd53b0be674f347f5d224f569a8cfeccaf9e80dc5125931b737873682cfc43a62704b91964ed8096c527255283c3fd0a6b8f6bcb963380a91e2b085e8dacb81e6577e54288f8be899b6b1f0c2a21672ff176dd1574d6bdc98ecc1848b122994e7a6edfc8d29d62d160c796fd3e5fe91772476be0d676724f5a27007862e0764ef792c8e8598a79ff4157d57e80756e57e29a5cd64ddc68ebd43255e6f8c3cdf60f548f9f98c719bd7d8cace6fb37df13903322e538eb19a8ce3e30a37e7341e7e8c511a27ef302814aff8ff40aa7f1e8d96f10cb4991815fa9ab3bcf7cfda0c03adb5e878ecd99f3f40d31812b34e8034a5bdb6dddee350734a9f6ca88648f63aea30722ba410a8cac1f7a58ba319b1c3b04887e23a85c2ac01397ccab62f1102c705ee10bb878d86b66198d5550233ff8f2ed7f3e22d48bd800cbb600a97fd1bc4adc162050330f7b1942b6f0b499d8e423d03e8faba442407dd8ee0872cdcbfc15e2733dbdbcfcf033160c6c9f6384915ddbc2284d5aa34f025ec1658b221e9efb94240b3ab170e633ad0eae39ee9ea6cc1898fc0ddc662319c322ef2d0cd714b8131420ea6c8cbb1c94a49cc877d88913a9a084567aec4fdc0138b601a8a7db0d8190964b867da451ad845da51ff99fa41493aa927000cd5132b0ab93bad88a3e68cb42430c0e3d5ec93bd91f43b260f983936f65cd1a9b4fb1a87ec8ba3b1ca85166cb9e1a4ed2a5d15690d94e798e1ed24f433dcae76d72e5537f6563046e38ce709ee8b2f600e89583feb492df6f42aa17bc3cebb99cf97832c72602813a5067296e434506ae063fd5fb0b731de2e367a8d130615c9ae86f884fc60e89ec8c8191740f861cbe56dcdf5c21256106951f651ecf6f1f34b57ff1171b763c1ad4ce936068752926c5a4845f048c35a9ed64adce76fb7a34ecb35d5a12c05987cb24718576a6f9b78268f6090c4e1a85c954b504bef34f75227f67b8b06801201887692945936b93851fae203fd54d1e11f7c24334c5c50e5f79cbc3d0dfe7a8be447031e4d00526ee6903409191faaf0e4cabe006547bb64060fb846a21a120d926fe4744941e8034d318e46087b91129173cd765d36917878797c0d15837fbda0fe2206d8ec71b265ddbe4bce9bbbe9387475ec2f2ef1302f060c48db264394fa80ef270c2c09da2d995d8a00a4a500051ecfd06d6ee59f16cf4c4308562021ba1091b63506e4d2496cb0f8274e49b96b4d120e815bd508efe975fc988638e3717a514a238e8b95ec5d6ccf0abeaaac310015763c49e49f7b1886b81f46e1534fbc28ca796b233e820b4fc0e6724bd8614055de6ec312dcd1760164ba2690ff3b61785755c603f7e8b15ccc2d7a5585124895786f69755437f6aa29c3eac0666c1699376c0b467a1e1ebf175c07b3ba2a2cd3f78910b9bb6a564d84c1e2782c73a5422c980b68d1e6dc016f0ef1156bcb41782453e4ca77b2ad3bc2bcc1596fd3ed4b0d6f16243c14186b4ca764df572edf2c3115afb12f730666ca0071549d07a2ca3ad2c20a1fbcccfdd1a6641edb2d294d819b292a5e40404a11af20b65ef638eefe150b9bf5bcc73317a6d60e410417724113a629a94f231d15aff1caf940f023b08456a3b4e3f780d08d93bdc58144dd3a3afc3df3f96adaa68d6a4a0005c1ccdf1163fceed06346eb3e622bf2d62388561442d825d597af6ae31726c156a8121ac9dd171d390e74603481852042909bf596f7187b76cf6666da36c899ba466965e802722751f6997754bc2f372a032a09985ad2428bbaaf6d81ee99c9bef3019c6582974926721629d4321dd289fa89383fca693a5d4bdc60555225f11566392ee259c6546bef9ac1e26b8241ad9846efcda391e160b99160b5157407f2e396e97bd163c9baf30a45c887cd6a4e1735a675374dcfd364c1ad5eb078d511a9bf493f7d54089d36915d74a6bbeda99c742e9f034b5e5340b4f5e791b6c987368b5ca6c019733258df6f9f3159d2a298a5c1f76e51f152558c1e5da90deaa4de403f20ee8f1ca479ad61394fc810817d97f9cf52eff06c2e037e3cf147f783ca5a20399350d48e50ed349958706f4bebe6b9db4175efa1016997b88b4b7f7628c6a42c62377d4ebe88c84f9401474afd9b490b760096ecd5d7fe9038a3eaebe08913395cad829669cfe05120df11339d3ffa978aed2e7ef211f05e2d26e420b6ca07f01322c7052a441b5aa24f1223c9a8def535b541e61b3f160ad3494afcd2f092de90a929eb9bab47a078009c9a53da0a2bd6527e73d000cc5431020f15bdd85ad5f5d2129ced3eb02d40804faa7fe885720d8dda80369d5edb5b5d45d553aaab4b34857914e13829bf64654c9261966fd63dbb691494363e6017c3f98d1b15e5edeece10d8040b4c6778c09a43c6e7e1fa7aaf3628aceed347072e5ff219fbbdb6eb9a59432a514520879087c087eea9ce0a6a445c1f6adb646981096deed8f665b8584a6f16f42d5c27611b2c216bab86d04f903a6f17fa24a61a908314125b1e812854419e1524b1eeca0422f5819fe42dc702e41d29420694f6cc892c6b54ad2685325699226699246a9a449daf4991e52b22e30d8d662adb6baaaab6d1549b5aeeacae3f16c9e0d06f33cdf30b7f1ab43678b1677f7f73c1b0cb66d2fe29a2f01a102583a37ae7a3e9dd753708dff9848645c86f4b819bddcb8eaf974de83de4396fd96224c11c66d2d13c6a50dd63a302947f877115edf3dabd94aa705defbafc0fb929c9070c9f361618844d28dccdec85a4bc39ab061c3fca3542ad7612b58d36030180834ea713344448406079124e9d30e188c460d56b163e4c8dd1d6bbfdad5adae358abcdbad180a75b1eb6a5723778cddeeeddddeddd55ae337e21a04704d02c09273e7849db9e1c80bda3a49b86646847b708c3f68731eaef3628c317a3778191ff24e172758c162dc7edfaaac51322b4c74efdf5418879947f7856cc5ed77cf732d2e75ad2e4d66e0df4bbe3086cbc46d3c149740385c86351249b09d4885091eb3f6cecfc8097b03267e2d73900ad3f803a15e71e71a7f990c060624ea71e3a00f0789d0502409d79c741c1cc956359e2063c7c8919bdb4837ec155dd1155d5b6f5bdc6273fb8e91232a2837d880ea27351d39778cd0aeebbaaeebba91c7e3f178b66ddb647c61258dab854bdbfb47572475ef1f5f481cece872c51797e8f58f57b024e152bf0cf3d35cb3b9a060d9c4262cae7b32f8ddbe245ce31f4534ae112e11e13ddce0bad7180cd40ea9ee1fe216a554a107a771b1ca42e5613c798d0ab1f5459683f20b232b028169fca7a822ba8ca476767676768cec189131992756d7bf8b1c63c766ee1be6888a27af79cd6bb4298d3436b7cf9b799363e40608f8602f1836e98d83a20c6d05d7f8b37f77715d8beb322e39b3d74d298d1ea5f1f361c2865e9bdfb2ce433d2c8049fe8ab02b768aeb2fb6c277380be622ca261e06cc654e664544b93e856bfc5532559b1ec60e5f1897d81f423737b55a4be9cd4d942b1959a462c7c8919b6541aaa591d28d6e3146598c41e246dbb62348dc464712f7bfa1530da54f5bfd12e0b569c252080a2023043861fb23c035fe096892049ac63f2626f46cdbb66dfd59c28a98b01bd3606ef464700ae4806b74b0b0bdd1205ce347e2916d6b7074c453b64ac739d8bde5e06f44b02d16f58a25c44a2592a12896bd8f8a0de5f57fc5183932f39c71048140111465deea6696f10517da8936ce628db19014f6891a0fae472aaec71d5c7fa70293dce5059760de7594f418a62937de755037a61b0f836ab2f12124ec0daedb8087507c018b715d72b1509c146b4770c913ad78ace2510947177089bebf6bd13b3c0b2ecd8f43c47c1881b81e6770ddb770ddade05db8ac068daf26f385f5da982fb432be6abfb0ba565416492d93c9643299cc23eaaed55c2a95ab93459290982c268bc9e88b40a2be5d8ba423227655aaa642f5e3944512334f8f3fd0c1ee641de8eab8fe11159b38a97a17772e1e995cef40d1e7274e0ff42010687aa0771b50bc71e32b358dff87f6c37ae383e223c2f5f7a468015ce3ae831376def0e6d33961411fde88e6ed3e9f8e54804471072deb9aace6aa2e14eabaeafdb82e8b3c445a27eae1b2b26871e102e3bafb8c2d01d11ea66c4597c4e80ed7fdc3d053d09c5630cdcca24e2eba2f9c604c19d7b84c76c5f0316ebb7a4b1458b82d8bb55a3b57aa4872ad56b550c85a97aa5659fc0212c51d8822155ce36f43f4825445528c4552e401d3f8fbcb5452ace213abf88395cb7cc7bd10f90b2e85eb1f12312b20f4285c7f1b9ec5f597ae488a3d341598c61f89d00d6c105f1012030b4078e0b0b0f2146b2e03c92c16f1e43b91343defef5dfc0ac699a0f7772bb8e4bdbf37a171b870a973a7fde876f7bc9bb255e34857f3983299ecce952c9298a5cb5ee9f23dd0099826922ec034fdcc85aac4f60c9a50b5e84700d3e8d802f37e25ca0f3d97305f38616044de4724eb47048e6630c10e07db656e13c618ae749ec700f7f1c3217ec4c1f3ce3870384cc1c1f3f1dbc46e33677ab673eff992f873df4cbf2989e7e337d3df8d0ea6d932a1feacc5c19f7b8f28b6e787c4f73cfdbcfe84e8bc203ee7118db866bec80b2b67cd01ba27830eb74e2bec0cf1bbc7803ff73fba796edbf462bf0621edcdccd03df743bae7be2453b64f12bffbb66f48f749fcbbfeda0bae9913fc4449b0f2c38f1f2b9d5e417e118b11c6cccc393723b0935fd8f62f5ac618ed17b20893524ae78c94ce58a3284e4ae383925239279d944e49279d91718a413f4797e3e278afdeff289fd2b05e19075d7a3f64cbfa23ca3869d41fffe3231cf4c3f81f3f5aa07f04618eebf30bdf47a5df0d78e76de639a2dfccfce49df7521d599df6ec4bb7377d79530e02731888d1859629877e620b2b35d394fe20b46ea279bcac38d8d14fc77d3892405ef711b5c79670a471fc8340f3f8b07c68cbba4262e66a24a46be63595758544fdbad63ce23b124dea4d6e5bddaa9452d64e344d94f2bb691e1df7e99eb0db13f673fd76338a10c491f02f1d9d73e33e54e4ad22b8a6ce561e0e085f5a1f99f191c6e9562f41eb86c25a1de9a6c56677773a2708052466abd5aa6e72dbea5665e5a4a7fb745252295b5cd33070358e5361239ae8ee09dbdd2f36ec58fdd04f9d0bf11c36b0f2b7207caba856d8a6545ee148ec0bf300c24a2965f7f1401f2ae26e75a249bd45d3cc20d038fd650b246efcb8ea2f34004dac5fd07b272f3fb8c2085b708107ea09d1017da148131f86289c564ed8b0b31076166ef4d30d0f3c73c2e9e674bae9d837ce830eeab43ac9205c43e794f5930506b0894dde924dfc1fef47e5368e9bdcdc56ab6debb62ae20b12b1e9745af9670389dce48992f4922378809972682780f083cbe4bd114d0a1203a05bb17d4d206f2b92dc89477151e1aaa8135127073f2cb6d5dddd5d02a6f130da861162300e8ee6e18fa3c7781fdedf112c4edb5fc138f1f4a526340ec7a5fa56d5ee9faead8a8d53a479f8cf4e32ff22dea73fedf1ccd37d8ee3681c1dccc37b1cf7f3f7e339734d7b4baea91f19e3c74353b85d889c71ce3a6b8c31566baddbb6515a2bf56a6dea0109bdc0355d802fd4c5ce90f7fe5c158d22c9fb66601a7fcf62b409a92159d56ab55a0d0912d0ac999bc66ddbe846bbd25ab7ba511a29cb91ec1163947d7a60437f5db7c1e23630b7992f63acb53d5c953b2cf921e435aeb919f5b8d9116385abc562514ae98e118ee3385624b1228d1cc755aed46bdc7024bf27d890778cd8e047dc66bee7312e51fdb07212259627386d8a5415ab2b602f07a5d36f918dcb5e047c87209114a35061d5eae08dcc11b13833839b629e394cc0e502b00da54c30e81fe2b83ce399bf654cb04d2bc1b4e536cd9af14516ad3355eb9c73ce39e79cb3d2a9044bb94b348dcf280cfafb84c2ce26521e45b3454534b138a8258c1dfdd01a2362138d11b949cbf5a781f58471e6a6985f718ca84d51c4b7e3e68d11b1a9ebbacf526b4c5f4f65c399e2b2d5ba6d33156933254f0e42e192d499a82e369c29192a6eb7613bd89952c2b2f763a6666a862849dc828242cd9443ecc1cb04c31022e86d94810fa8dbac3a6d0dd1ad6198a908fa60449115599755ad0dd56835b06e54b061b35256dcc609931a9592af48aaf1345054505166111316036b2ad11525b27c60c39992f9195fe39b9941e667fc4c7f43647ec6cc901a1ffa1a1f7adaece74b13c988362eac77e04c7f8dee97097d8d2f898d0f7d1200fc8cd7c144433403fa175e07538c6806d4d9108db62b581a2ff322206c979a9981c6c73c0664bec6338e1a49313ff318a8f1386afcccd7781c684c1c1f80c7c0cc0be0c3c1c6cf7c003e1ca60cb1f1338f03001e47674394d3e30a36e66bfcccf63a98a82bd208d1a1b0176d459a0304615de69dc6e733f38ee3dd0380884d315f030038be991a2aba7d3313a8bfbd0e37462aa22219dfa21bfccaf8220d9a074c970bf3531416b9309f13ad28aa60bef8648698bff14362fe068d2fe6852f89ccc739d113cd10b1292462538c884d34ba4fc83fb1a794dbd0bcc45a9c39e82e51110cae710114d7b7309b8856e825b8cf0d67ab8b619022184cd3c91b9b0a60cc142db2680e7adcf9c2ced4e748e31aff2e78c76bf1e435afc51d445664c52cd189e8839899a2551c74eaa22d185e60e387d479e0128dc6cac2c1808511f31d644b58a99adb8491b5a2d1bca4669309e54b644d9f59668a6be60ff38a0c08312ab028b10897933ba33839588b446898a9ae61a68a843cf3d08ce7be980f41b7f14d554ccb66b4ac4616685441e6eb2d66cc142d66be68b3fbccd46471892fbde16c4d29b11559363eb40c7470816052a4451a6f9cc8126388248e60d03fb23c92a612ce510c26aebfcf17d7b87baa65911669916524922218318c9d1d76967891365373ced93595a231900ed663f0325fccddd2255b9265ebd6db16b7d8deea768264b15eac178b158233078d98e233b789dff216d7fa28e30b1bca4e4996cb6da4152e6ddf754ad45056556ca122595226a7b82eafc89914b11536942c09939fef1e1472ff96b0de9a7ddff711c99688e5921549202859208b6e3af849bb9ab41acb8a8291d4bd7f1a003bb0d3e2d545f4642092011aa41467c9c0dac2b66ab74593ec275b9dcf7c06f35d0085b2e059afc2071cc00de34b1ee086f1d53188e8729b3006115bad2a31462b3706c125d6d7856507a713969382d6ba6ddbb67d88648049f1ca4bf67ac5dc30be5876854932ca8bf5928105856be2a64567b9fe339e39a145b9e2379e20595c23a3482b5255a0a638edc82bb8c6d5b1497f506cc8b4193edf3d0628066ca481c27e8e965198c65f52b92e81705d5eb9ee4956a758ed4a75aa53f3c5f9278339e7fc7c3e1f4ae9a4f3f3f97c4694d239e7ece1a4fe7c54bbd13c1ff77d2fc4396984b1c562b0d7bffe35e7dce6165f91f4953a6ccb84f29a5aaecf2ad79fce6df3bef9482a116167fdaad5da5048b6c00b03171b53602b08cbde6784f55fd5d5b6dabef0b7554c4d1516b799b05904977670295eff199bb348ea3e04044ba5ce28dcdc895ed8ed89839b152cf7d2003eb0fe7c398a2e5c6edb4c96db843175533eb5d84272d30da7943bc60d638b4b7de327aa41c77d463f380f88df6d9b1f3d2022bf51e55dc04d311505dbf160d914bf7faedc26fecbd5625d8f22d912c9c086b235a16cb096dbc46f7be2a02792810db727dbebfa6f5ad8fe30a656a9a852a55253958ae08d2c95c72a5315695cc776cb411f4f1c74c6e2e9e964aa3a6f015c5322029ddee7864bf1e30f31753363aa4a3855b2255b32bb4d617bf27d7860a76a968a3207a74a0a9646beb6205d30933298491acca4103369c42c0bd7bfb1c0a54d62c134fe52b8fef10bab85eb63cc18bcfcfb0726c9163321f55442515a45b43ad58598daa61853750256019b80d4af2879c0530906e36a3261c4759eaf364210aea726cc55515485a52fd9ba79d5dc6e5dffbe3245ac8a9815b1d754bda66aaaa6aad61d23071dec566db1cd0710a5b3810c0b103b302b56acc41839b2a7eb4fcf6284c42e0a892410308dff16d73fecb8e6b8c8c58e8989d93eb5562bf7484ecdea2aad9344d55250fe95db6a48786b8ee3aac771713aa83f346a95c2073a34a4c43123140242103233ac9db36eb14306084a2b5be48832bc1ff17bda281f3737a36ddb1a4581202f24923acfbbbf17b93d90cc2259d56a35e7768c7adcf8e01a121b4ab89b993bb2562a5b69531a69ec6ddbb656b54a35a9bb8d0eb791e2a43afb32bdcc39e7a451b66d71dba20cafb25d6bed6d1b218049120c491bdd91478475976b676727ba7622084a54241941a15ed2a6132e3d719b3058d2e4f6a11f782e993b4c9611ff18bf21dc9784fbeee3fe685c03055b7feb264dd6228df770e9c541ff3837340f5f010b1a87abbf936af73e2f22918424d2344e4ef390bdbc20c9f97c5efdf9ee4f0dc9e713424237d16914922f36d08a741922631ef5c8018670442dbad3f5e8d445b1d026940965512b5445a15c7f19455068c1429fd0551435a1729b761b896a169394db44978c0f36152342511445538d436920002736a42852acd5da900f360036a0a9bafa01846f7f32e5a05314d7f8e7bdbfd1c38b75d74db90dcb1bb24c004278661e4fcd43f3ec7864d7ff46b760352600950d23ab968a39d8b558cc16c164c5c513a594527631bbdd2dd7bbbb259df3935d8ff1c186a35b639ea73dd03be84b9283a9c240a02f097d2501fde73b8f6846f4cdf4c3b4e787783c0ff32561df9e7b1d4c3a7414f5c2151b6759708d47591436ac308a1a82dbc022699afc6bcc6d7a78b15dbb2145f96f35b7691a4579fd627ab0ed9a32a47bef4bd2d5ee874d53c21ed7e455589483ce84a6fa0b47280d8091c635f091c68d60c31fc51b273676fdab169817fb1702312708174ba5891bd22154081136e458ade2fa6701a3281445511445515477b2f1454a29fd7a924b112ee1b8fe466c9032923a402bc235fe9f13a4eccd49acc52d77cdbc702b553ce65dfcc51b07c1d2206ce855dc4626817a13ccfc2458c42e65e35227650ae34423e020ecd410d7047d4dd0b7e33c34f85e60e9875e60528ed320e0728ebf935a44a790d0a42291c697e8aecfbd39952291e44b348d37e1f3854e8450fd4287c29bb88d045fa2b71697a870a9fa1242446887a2bd096fb9b7ea87a2703b91edf5b75a9ed06f7b68ba66eb7113631e16e8c8c7a787a5dc9467e592dba8597fbe7ce504c4650f24b3fe39ce0c84d58a15e3220506e5b5a56585ae56d5bd7635eec9c27237fcee6bad5f3f97bc15144d226244af1a87da20d48496218108a126ec12fe7586374d7bd5ae48530433c7107694ebcf79b7f2e0fa3f5769d9f951fa021bb26c031cd000976ef00126f5e949f3f0f76853f801130c869a4707e1c67558f33084ebb18fad0ed6533fa127da4f6606b80083880cb65aad56abd5a8c7ca52e166a64c9bfb65737222a94a493b0f1555aef9175a96d69430c963c34858d029cf97e3a371b88f86e6e1fffcf2726898afd7e49253abf461060cfad3d0384780602b705919610818d7662c2b66f3dde3e68185a5b55a6ddbba3098f993827262f22122ab44b8f35c91b922658e48294084694d7a1b69dc00d37dc05988d0b972743dcb105ea24966334f3794b957ec8d1bb24cd6cfe7f3f9eae0e73381e8f92244081b322dbc61de22fd34f847e446caf20d43a0474185d828fecc32c4ebe9d787610a1b72145f50b9a22996fbeebbb9f9978076846bfc6d11d6238a5ef480f483b040c041e7bbcd7c60e10d13029e28fc206ed3d94c520cb20797e4fb1549001def36954b5bc771de8fcd0697526069304e7f29a856864b9e77cf15eb5d7bdd779fcfc7fbe1f916c944e172f6084bbb1f1a8d46a31df1bc1d0e8e1cece1e08d833e722010c4c16e193e88a1dc85a5091396955635143a1a7532274f9cf8cb10979c8e4236c0208dfafb236bbdf4a768042d9271ce398af3e5acdf10a7e98cb07ec31010d6e6c086f6ba7c8fef38fe7cc51084d840dfbdb0262463e380c1216c689c3e1de1022f5a57282143316d368aa25028140ab56d3b463d3a06338399ebe82736d4d0a76ec234fe12a3f333ccbbfba5773d3cb0a31b3f9e15e1d9ac8894348cb98a2d66d7218bb1d825bea2966d4606ef3ed7f87ff7c726f3b76ddbb61a5aafadc6c5a5261ac7f3fd963eccc370c586b1359f348ee7065c62e2243fbd22c953339aacc99d4892f1fe13758a246fd249999c359ba44bb6e42aca28cc87f2142a854aa15cb3fae578626722107ffe8caf03150eb5d08a40709a4e49711b260e63058b5a82e212f3c7631173f6d5da50282e81b9f10718d10cb771116f5785f58f556e186bddb6214245d87645527479a660ebfdcfe1a4c8c4458c1397300c5c8a33f8dcf0bdcb7db515bae185b0d8b88469fc7fa84e228a6bfc0a1bc6566c6d1f7a1f4ed38f058b6bf12d22601c04308f7e5983112e4d0528a0fbc25a3d5f6cc556addba8c7cd5cd950d2ac6256ad184abf9eb4165655a9ba9b9b1bbad55a6b7d52f7616dff4251b061e84a5291a8c4f5ef2118076c33df85e052ff4da4691ccf97a479f88d77439e7d5f6e92d4f79bfa85355f6e68641e709266c25f51dc2074872269014ce37fa35255954aa552a938ae0a19e260ff27369bcd763ce54fbc7054173f7913dae46a4339399184a4f6e068462c51a06c9f56713991e43f1a816008d6b39e71e9b3a104dbb7ebba6e3ebd61ab26f390e17ddfcfcb077d731e902888839e811d52a20474615b3509543525e9314cec31f48f4056a6e9ff421b2af7db047a04bd6d40e87b6c60d8ddb8efeeba0f924e61b1b5630efabb604abf0ecc2b895d389950e0f6e57432a14226985702533b9d4e261d1d2502a05513cc2b71c02c6482791d253cc6eb64820168827918dc98604c30cfbd6c900f0b9d05d3cc9eb0ef1a62d6a63b3d836189ddbe9909f408e6f7ac023341d0c2ed1cffe00e6f5a8f59382a41dfee5974d9f006c4041bf6cc51b3d96c369b51ea33cf65b67065d65167a08f500eeaddb6b1043b9271123b5713e7873bc21cd7a9cff67ecc2f6caddb3665a432da3ccd79d2d15698344b67d55552934fa78e0c82b147a3ffda5f47c4dddddd3d09e80bd8ca94c388c90f5ca629fd21c36230fcc0facf990830974b9fb95cea3a7dca9175ea0607a9128be408f5e00006232ceda0b0f23671d053ad1c2acb7c3a9d4ea73ef58952a7755268ec34b7711dfec5dfbdb8bbec642097fc9238ee03eb573b8f16d6efec9e5e3708d391449fa6c37d7d5a2455ee0b400dac90d98d1e5e2ccfaea36ed846c0208495c16934da9c3b68758c8e99274f99acc7b03559173f317a778a42987843d75b75606a24b5153bd7df690d6cd8ad4869b2586beb38a9487f09781e611fa0f72f82821b9c04fa680d0025712793ebfcc53b2b1e366458ea156b1efe138b834da4b0adfa9ed8119020ec1d9c808df81371555c9062080c3ad83c8a500029322292a06a8566383ed40aa5a4a452527630d26ad156abd5ad6e756bdb463d5a33a4b85caf1d2f586656645ec0b65497ab7dfb500f48e7e1b863c3762921c68a3cd142609c2456669f54deccfbf629926efa497ca2a2a208dd4a4214ed84b80385b5723da9f2ba5cd5e572b95c9c886fbb869cbc2e4e2754cb0a1396ceaa4aeac9e90482b20623c95a2e798de35dfffac562c1e5367d1b50b047e889f66f4fe9f6fdfddbf71ba91ff24e7df0648db06d65db28a5b6e3a55e05180a77fb3ed5ea606f2fbd1f5b1525c1bd0d6ea4af9123f2044b7d4ed70dc0a300bc8502c0c6a9410938416aa05d6c100c02c1a07f0d8d83a479f8105d584a382276da69d970c4c869e774629d4ea7d3e964b1405f1cc7c5da49b264151df9454a296badb5e6c076dfc1a049978508dafdcc5924e6863cabaf5a3b092781b5849429490e323b28d3e773e8b8b032791f6b50dc660726758d4b325c9a21272c7f58721d06256c18dbd5318fc13f0dfaa6312fd61cac5dc023c39b6133d948e30f33051b46d749a2b8a71c05b2dd30db33dff3f15c1679a28f8863acd185edbeb0b7442ef10a26512298c67fca941ef4e086edb272c376f911b1567bc2054ec80df4d6e73e569cc6fbebedaf5d4caccb89d30d252ad6ac58ff6e2bc27d72885061b91bf2dca813d7db65a579b812d207066740ad4820e42a0a39c42bd624ab5dd48adfd4502b4822a96b55d45c35b9721bae166bb1166b1e0fc735421c1c4284be6c00c1ccb4b1d056df4412dfb0870a0b739d524aa9bb870a6b61c842686665b15a739cac5c00b3b826a6c541eeebd4ed20ae7f6c988f9c9b90671fe010b007901841e33414be02140ac54385a5fc04834180328486122b024bc6daa4d06655615d094d11aa227473c38ab1582cd6b6c154890921726242c310a6e9f08cbd906ebd05724c08970470fd89c0000a283d19a6582a73847dfba9967e433ad50d79f6b2b6880d2152b013f0dcfe402e794c888cc562b198903977787c60e6a992826a321b89b551eff40cc1728c49705f9f37fa7f798aafe2adc899354a7b38cde69b1662778cb17687c57a37ac4dba35c6186387c5c65e71e9bbee8574b0729b9614a61ff6eae670e5d50e3329a3bf6f6d6795811d503db0d36bf0067430dbbd6ff5e7ffe5571539ab55575fb93c7592a97f90684929e58e9119dcc43dc3803e1eee330203f27ca4b0ec604ebfbe70f46166f678a011e89b3ba31d5be5975365fde837bf1d233b3827288b52564bd6a54aac61cda55d946bb53614fad128ca6ab5f61f0447a366f58b4b7c7d764faf1fc6a5fe1fa6b84634a10b76b3a351a86d121c3721063d58c294433c220c93e7bf54ca32d7d8c993274f8ff60cfdbef4abe7a39f1107dddfeebcad4bd8203b18b1b65a6b592c101073ceba4dea24c65837fff13f291d758a76c157b0204290e80ca100eff0175917589066120d1a39187683cfc042b854e3bae806e192288bdb42827cda415110075d6efd520bcc11fc4990ab7ad2c38b95715e95759356791031ec7c820dc1eba22dd81094f2fb85041171b121087acb240c0683c182ccb9c3888e8fd8100e7f99c383cc9e93ba8e3adbe9597be9d8a45cf274308d3febe8f1ea973c5dff26820d2e729a5ffdc9d51722ac97cb59a8e8b2e58637314358ce4205961bde64a982c9cd424595cb598ef0e2e2f6eb543f1e1ffad55bc4729dbda4384bac4a9f9acb7c65893de186bdf369653942ec86ed456e348c56a415aef7f0aa3199ae80df5aad0d85fe417074634508eb1e1020ec20783ae108c5d3cb4ece628425d8bc765eafd7ebf5dab6978582e338e68e7c24e9288119638c2e9c4c32af2383fb9890679f1f8c2304300ed83cdc13b14946c4261939ce711cc7fd370e17f27e8608f41f519bac884d9c2889cfc788941c9111c910292972fa3cd853dc225cffb000d73f2236f5dd3e326e9a216a1367454a723899bcef603ec7258ce805bb9e08072433433eefbdf7f97038d271a2d6e260f7f2e19182c5e16a975feed362a5b07cbd9f7201192118a3c56f00e8fd6788580121cef5070bc0a53700f3601b4a039530e8df34d063b8eeee340ee42ddce71f49344ce38f802b15641a0eee73d41d5686877624e420d708f1b8c5c2e3f1b0876745aac7e3f1783ea311087ebe1a699cd890675abc97306157b9eede00506fb9a410278512383f9847949b273a52ba05e5ca78fb31f67432b90c5ba4eb72201084020e1ab1e1c80d48224d7f441ee794d45ab972ed20b88542455253a9b5d6eac9c0846b9c874a7bd23a6e93059372228d8eeb6134185c0069d9c0862db3f12f12699630e908e7c3c3033bcaf3f5ab50a47893277de7dcaa7c00036193152690538324f4175360d05fcdc3fb0a4c03c5f5530db8d0b296a3aab85a2d6ba18e5454ff509d340a2593c96432d9a8879021a998d5687453c4061f3db8cb4b0b6d853a236c7f884bdea871280fd73fe4031b8eee0cb9949147233a1a8d46a3d1b66db5be55881c63c766668e0fc3e50771649a077fbfa00a1760a61c1820c41096609acf1f120117f1174435780cccd26336123bc03cfcdd3fac2132820d6faed74abf9b1b29c1ea25c618afb07d638c3146902cd65a6bad52f610620e7d90213970dcf80c001036e4fd33925e003f2f2b43d7fd8642a15088527a84945246dbfaadeb6eb08a31c65879d63ff817e19201a4c93ecc69f3d8a8a24b72e474bad1830ad606f0869f3f810e97fb7e90c83ad8fd9d534f06f91fbbddf2f35d07deeed37d1495a0c7f8bce78a9d119f8b9df48000e10bfaf682f0057d33de8f803ee8bdaf0718a0a75f1f06e663be1a693ceed99bc17ecc10fb319ff7cd44a0043dc609e483bee71aef0b6d002fa7c3fd70a28f8c7ad9ebb82f6c6c62fd7360439ef12039e06bf57ca1e8f6733f2bc27156c435d25899108ee71a219e837630a71466446415a6d66a63ce39a70e9348245598da9da304db452f3a78716fcf8b2ad61491b8754422e97dbc17aee99085ebefa8482272d2c18103a777a8748db805356534020000000033150000200c0a860322e17848260a728d0f14800c70884082583e1a48b32088611ca4903106210300060404400433ac14053a62ebe1d49c3cda53fe7eae98e3e643a94226bf60417b85a91e3e638bffe5089ea7e763537b32c3cd1b038c3ed906023efb9e63f336e064a8a5567cffe1dbc0c094a9331d30f3b69c1fa8766c68dcdec5dbf79c271ee0c74b7ffa91677432bea0e7760a7cc1827b9935fc8bf91b5072e98c86924426c89c405bcd9ec76dbe2abf8b798d697cbdc896c50bd10f35b60d3eeee2e3a9e6833d8c3fdc9099ab586de87e245e3dd53f5a77d96d350a46ee4a20ec638faca8d75b58722f4c9d5bf121a79728d4dbff51812d25abf793941e0c2a3e16ace0527081eb1399986398e835311a9d843c292e10d193638c719ef7cfd7f6db872fb15176b6af55a7c41259774b743e7789008dcd33fdb5aeee4c0821d8133f78bf84d086cce763fd2975d25249e98900256f18c87ec3ec65ba3796c66396f3d40cb3e4c9235fbd9c386e20e511a6494adf8484fec0ac303cc9fd5ce9de955f3b8c3d890d84fc9f49851918390692050b930aa0579e9ad95d4f67abac99a2156e8e93dccbeff8726d19dbe1f738d5e6ed7c81f89e00e560d99582d3511fd4eae2c29a878ccd80c50717ab9af4827868365075a7a67f4f981646cae036e7d550443e5b091d11a8dbb68935740a15ed5daab9b4b9c564bedf47b8c41e2b26eb9f4fab1ebcac8d42f858421a2789cb6abeafa8603cd6dc3ae1df90ee6c4ac2ee834dd2688f12d65da7c2fb57c0b5720d571f17e5b89b64333557a8403c519ee0153a81296d23cb115ec9cc8faeced45f44fabdbb023c37503c1bda0f244dd058a0871e98bbd4e82b4b63b49ad2739856ea36ca901473eb0b125b68361cadce9e8fb4c36654b25830f9d53498c9060d377291e29da82124d2f2f2b081a8f4863e004b0616448ec2caf20752c8ec48e23aab98bd5aa73d6e853ece07c8aa7c44562ff00118bb279768075bf267ac182846526963eace6824eb4f159bc13b95b78e24f09182615f1f6c8da9cedecf86c906d856644d1778143198c830b1d57beb955188d86a275864d4f5fa80a4c72e30164540087cc42ff9727c32262ea5fc500adfbdc04c1a29e92a9f226a78adad762c357c9c06f4635c001d00ce22e486d8041ce8b8063ddf6937531de8bfaac2e6631107123727a9dd72003ae25618b18b7d7895e442553a98a6bd0b626aaf43ebaf5713efdde821caccb1fc37d15039cdd5081133f990cdbd4572ba8199fae0fd85cb60836e247223e06cd98b1a2fa39f743322774f5ba60978abce004c9f467bb2bcd1b1d1f16bc0c0b1bfe4380594a60e8c292610bca3f87e4b333474b25b02f8c15541743895ff0d42318117dd915595f6cdc4236582b62383e04de142221d853474510a33e68c682aba033e40b58ebc76bbc6290c30773b02cf76fcd1178b3a2ee7f8e8f0fc7390ab6e209eaf8cda14e00a8d0df50fb9901c367b8d55d2671cb402de4f72c2e7e2287ffdb07044884a22902a1b17269804e76d75db1de3187ae9943411682352fa2fa673fb0b818702808f2048681c5785b1afda62f312e6b7b34085bd8e3327cd5a3516ea969af67a2efb5fa660a86b841d56073fecdc848b0ab4820cf1ba6a0518546fddc3aa69f5022edec05965ae0c3dc47e8a6e85fc73ac1b4e09da48ed3d53a56bc3688a032d9ee5c8a52c55e44998a3c187ff1d5957efcbe0dd644cfb9adfe76930432b7015d19ac16f64b416e9a0b4d35431c27fa157c4d6546b94469717208a9ef5e444089ea933e9cc3c016aa0d2d87cbb90bd340d5d291e694d283f019bfc4f428959d736f5b64ec3e26bd24ca3c5f47394d134b17a824e181534f7c4c7016c5975e862d77f7c17203f98155dc4bc3dde2706189ca8a0f30cdb6ff0b7ac52c187aacf776aca195613a013c29d387817a57895e7df921f24384c56e9bc980f61534848c2bf683912224128644ca8599eb24a5afe099b80a72846470d30e9667628615161a4e182ca3ecc012a5f463a792f424412cb371d5289c610963613d2c89bf147ab590b596ad168d09f959ef77dcd554a927e8557c038723f857f9a6fdf08cc80a557b738a86981da9b15998db868ef528d12ae19edf7e79192f43b0030a00dd35ae6422ac970c657fc6f05d16c62d285b56ae153ba5ebf61882126f6416070e6d6caafc044f1410cafcbec35560083280eb41ae14101b312a1f906d0803adeca8d56e3b55c8b7d59082f6f0967ca9c3013ee94d68236909f3592ba01c801f3066d9e8f53db3ee9917d641c7afabdcef143a35918ff1e0b3ee042966632845372cb10a3d3d7165f0781b38fc300e1a6855ff14a54d9e0b85da30c8e917554f58acb08ce62b3b4d0f0cc431fe514351b0dcfa6ee4a38048fa8e95ccc4ac6a6bf7187a708329cbbfb45a20400f766dc5fbe3f8bd6c01c11363d1d5403eb63a2e564ca500c7c5ab9e57b63b842a4ca541f88c27623994bd1223e82a53e4ffd467bf353255ec48c98d1304d65a0bc0bdafa55e8ddf9fa060cf497c2745543ad5855612761105814e8c8dfe28965282f1121502ac17f9e23fd242b5509870abb0cfc3cea02d28700aae84c53c47ee4bf9f48611b8c30af99f36881d16a91b2626e9fa5b2fe34126128a51b518ff14868931744b9cefdf7d89295be661474a494f2305e25a17568dc11611278160b9ea49ac7aa0c4f9d1ae59aebd032ee838a6fe11299727b97cb6f0f3891bbd69cb48535d2f68b8e28d7a7e27b8cf0b8d8e20ffa142478c06d8a0bc22ac0d7ba8b3afc491980c809b0eceec3fd899fc402108979470025ebe8a8a222f98194fb3e9316e16ef9effd147df3da0eba96289ae5ca9e362b9fedc74695958a965df4dad6b72fff8d05d4a4be04e5dcb923077c745526bae38d9d6774e4e7e63afd4922fb947b0572807c84f889a32f90fb771a682a9bdf5155a31e0986d469b0e69181d19624d0ae384985681c49ffcb2e141ea8440f30b0d206d9815d7ce97d04067f1001a7f9aa4cea198e2bc91f6310bbd35cb4658d06a1e560182dce36c20e3ce539d4aae733fbc4a2edb6a1cbf13e18d3c52332047fd2f87bb177025aaecd21a3d78b3f859ad953338f7d710c9944a348921805137c51cee1ebf3b7abd2bd2eff48bc6c2f9f3bdd0b32de2ab613313936e325cbe3749ffa7a6377a01532bf8303a282701f102eb21647f7cd7fe6703cf7f5a0f1fbb0a0ecce432b02d948eb1bb99f850eca8db8a04a2a42df4ae6d8640c26f51a6926fbbd67a5c6f408c0d2229665949e909f22b189f71e1b69207e6e162b7c085dc9b1f84c419878845a611d6c7e1500a61d132064056bb5329615241cd71aa62ee67df9700cf1ef5725fad2508f59f41c94cb7ab6362247b7d9b9914c94602e602c81e1e69b2746dfbcfa05eecd43af1277f83745bf2a2bcc8105fbea6e82656bc44a25427fafd91311c34049fbd38599b17536390b654c662572d6180f070a5e1a5eefbaee7b186f2a51d0f94eb86423f7049c09867a6ba0e8e831c963a0895b087d0a72382505fd857e22f100695c6b2db6d500b563e0d93810de15bc602be8ef3e3e953f6f5071a3cca42145469abf001a1d644e6470733ab6f9153268eb85fcedc950150ede8e01fb480db574c85a9a2f49e5df326c5bedc8ad6e28ef29d8fcf5f0188892809f680888a9dc93c51f3f66d98713b45e19ce33b05c4f11d7bb1fb015bdaf0629ffc8633b1a0fa3aa3800fa003a7f72e4a60588ec8743207b6f21cf9f96b0fe20cb33d3e5361989f0cfa05ee8ac497760cb21e4e253876ea6c690fc812946908b79e8a354dd2665f3415cfa23420fee8b62d1743447aab966c99df93050992cda4ba6125f713a111191a8220b177f575b71426f3c25aea18ea52b6e24be13f90de47ccec53fc53d328697ffa8601d6f804022c3cb68e97f047cc83abf819d3218d36ec4d9951ade708a04561c7eba07edc995ed404c7c1b7f174246a2509c5aaf325d3ab9e467377de354d7d1802a79804da159f2fbe2af88adc376df0046f15a7c6bd109475608da1dabd3043aaa2d9fd190f62e131fabe00eb1487c39431aff841da124546423ce668fe09ee5500fd5abaacf527d06e5dcc128e77c0f530ccaed2e9c9d4b0461c8cf5af3bbefff458dc6aa2eefefc4f69e522bff8463d0343815021966c9f5aee60e025d943f37baeca3e0421500081742a80c14d9ee95d07f88d88e62e88640803219da46a860f1d8aa905b12356aa842f2d8e4bd536e625d3488720018d8663186c8cad165e9f3e44f6b6ca5da5329850b9332056d0ecc5c1cc7eb691c14d2aa9344cae648988be775ed2a5a3767493f9ceebfb7e54268d5c133addbd8c83e93504f758d452df4d7387168061150bf8d1c2e562078c4ceb31eb453672d4e18c45a5c7d50b3d76f27351715f300aa0507b2293d88489abbce4edea2a30b1295927f983f4e9fce7b547a49b1f2dfa38a0bb207e1a3a12d89eac800d15deb523fcc44cedc16afbc04e160e26662b2da8f05d238d6b81fb8abbc5c40e5c7ab175242d54e20fa0f839d54b32ec3ba87ef63e407746998e6536fa169dfd074af8a30a42996c6bc6f155698dfcc3ae14b76c556f0c2e790ac3ed65101d3f746a62e45d12556afc0841c038a7f9226ac88bff4c9e13eaa2ced3719a7a6cdf72771d3d1420cf79af1945e6299988d9630305f06c1643bc4a42d090e97a460602988dd09d55a0f3338ddb4f6898290dc1bb69701dd35b1457e1a0170b56380b06e82a7e86aa2ad2dae523308089e49c7b499da12a5826b44556984b4ce04b44412848a638881b2275c58d00ccce7200eeb5771b9895f0ed4d841fda00b28ca8cfc8f9a3249ecdfc74398fcabc720b8d458b3557ed9fc641f213abf5a7856f49394d2cb8b1a3196f55fba01a9691fe8d5c96701cb0d89f20245c76fc4ca49b6467f2a233142aad5ea75b0b4599ee4a86bf48f546db9f59396f73a836c176ea6544b4a640d6c5cb5135c29dc7ca942ef01f1e9c93e1520c961a1333f1625e04057ffdd71386530417f1a5d7a7b6c91ca2c870f23eb8cce3d44f66492c44a8f353f836afba51fc3d64c372c2e8b473a721254bcf0bfceff3867966954f999a814c4a5d0b0b154b6a3aa5f83770e14de14c8e9c390d8410ff361d5f0838dfe306959254f62e48adc6112ae26527bb0062c12ba5efc99a6fa8fd341bca9730ca51a730e8086ddc4bfda344f91bda9685e9867f16964af46d2da38c4fa40aa814aa99d13749bf4ee6d155d113be71763d80333ccbe9ad85090b228552db7b5bc3851cca82e80705b740df45251a2b3321d7c5ddb0fc8e064c802ad6907067bfb6d3ea8bef3726c87bdbef9f5cca7f30d644a1f5919df5ca9f58d02dc53007b2c001b05008efd46bff4948e11197283f84526e333ea5949f592a79c9a487ee2deaf5aa02d976a25db0710717faf8b196f6df9939ea8f409defac02ec7e97fad3500286567a1fb4178d785b85619f23ef685ce551434af46516459e00fb1c5a1b88c1ed57300fec042a57f70f91aed1093ecc1f4af0d1e34f494adc503a0a40739769cc95808f2f1e88520ae5b3f5940995ba243a12576a917d1beee263657207e7ad94cd2b06b3068c011c60fb1ff9dfd2c07386d0aa3c7f461d382f9ebb705aa3db04f03b651ff004c518e63f7c65baeb517b0845d83523f57feb52cd31a0dc803ebcc521b34e3c58081033b77650efa62e9187d2291b314604b21df488e64f4990c8990a6f36a9367bc838d6719d2ac2d1a2d7d667b56511b37271a94e6ca3caac8e3a1d013a16037807ebcdfe18bfb9e0f6521cb87e4fe087283a3875e9e60b550a0ddaf9eb2b672bc3d3a708b915eb573e4eb36cd2b7774b21f8a3504794586673342f0e8b13d13e46855f2aae9493fb020bdb826bdef0cb42a5aba683fbe60c48146a1a77da9187a73b833550c8bb91060d970ac3d2ec5757b6353eac66c81f4a8e488fe6eb69e88086ca3633b5b3655a07c8dd2ce7cbbb26589b4b8f21d43d723f80f0c7cd8535217eae639934e30caa982bfab4a6c3b38fdf4e163110414168ae9a527a6605160885dc7199f8cc3d9afdf7a369f26742ea7df8486badc6bd765a2fccd717800d46c36962271b06b00dbcfe576984c58b5e7deebc5b0d24608a87799298632ef373118d225bed47cd647e298643587c0a430b01ca837c52e0788df4030c6b52b278bf8b5847f8498a9496aac1b54815cfb50c33e5f0581ddda77c7d95c38ef4d9ff0268aecdd02d7b164bdd7267b66e91f0cb5533ba3cd65840ae0303838d390668185f0f8b6235ce490134eaa7e76ee062c82999e666f30ad251cde26fa4aa5746ea2acbbc55ea1dd785d357099c6b0ee1686d9d4942aa96081d29bab3545acbbd2430500971ed86b1f0b2482530ed2ebf14f7bd4ad3ff94eca7831fb70062ce6731ed80454ba3bdf7475c4b919f13c491ccdf5669416d170e0c5793df76518e18c3772e91b5ef1c6095fd9d4bfe0d973b3666042df85b6e02f1973eceead3aa3502498508f7c082d764a1926122900a2c20f4366592563d1b55f972488987214d63853a6036339fc387248f9da2ef7214e7991c23a16b04431468d795e3c7b2da99257f678d231d8b89cc96a26a68c4b8d82a451fd8ad2c79546402bfa365c58f8bc31137fafdd03be7cef9c594a4b7f1ab17fbe233a665c1f071e5a3073c1cfea76b9b1252409bfb16ace86d006880d08f0a035f26e689f27a77e7430d41b77785b56d31c307d2c0b4b1a33d8ad0dcb042a2330947513140aae52d98ca629b717ece28ebc04fcd85c549ec66f63ed8dd952f1aeffc971f5469330250336e774f057afb15b224c07716bc2b2b33d1c490a67ac82f84147c54181cccd0fa76f5d3cac128c8dd781158ffb581ad87c8e0abda6771283d6995cc2e27a78bc28f9dcb6ab478a95f01047a55321a3ba8b0eda1db2d9e8eeef611a0e0501a83cd3b17567dd1888a1f0aa7b72c48fcdde05c13e5c909eed65b6fdaf0ffe305445d988476f4d518566aa03dde53ea7c45cd1d63cc700457b20e7999b1b04eec640c4e03c0250477b4c24b34513fbd7a58eae9ca9daa3edc905d52069886e01351a9d344404b52337532253dc27b3685bd71cc26f8626e9b1b1f8f0d51fcc83cabc8592099d3241cb7af063e03d71f688938becf2efc9160494a2ac78d5074e928382d6412719339a6e7b07234699d5147c1b8a985495bed6f49926844b2300a0c9f7aab8445de6796253f54205e446f2cd0113a8c3ebb7d3e57361f03cd71a21c2319efa7da6c0f3c417ae916fbacef331ca8196f8d104e594b55be7f9a9a11cea92feb65579f2faeb5d2d2895044ca2979969e3b65d790a0d0765aeeaf254e1370465677b6a2366602d1328664f23693de008ff39441030f1150733fadfeb6c38cff28519b02a145a4c6364d05a756b1e78670fbddedc947e13b6ae175fefd15a10564252275495f6b34c996bcfbb743644cbf89a69b252966f9f4047f5f21011a90f85bab824dd2974a5125f8bc6ad6b4a80090105e6f8342649fcd4da0d86ecd4984e72783f6d1e657e3da8b9cb43194c59fc429709e4e5023e8bb5c50e864d27a11a6d3742b5acadc4f23ae21456b9020ee694b7de5663a7a86670f34d5217f72564eae30bc40f510c2c60b081230adc5c2aacafd1e66f9568b5703f6446c504756ee69733fad92e9aa689823d0a23b97d46b99612182c95bafc9819ff1067cb41922db2dbd3ad5bfe33b48767a688aa33f393abf4933263989a7a564345d7c83d0548487b0e09649f112201c3ed470109dec0296820e1505b76575d44d4befff5dfd01c1fc49b010593470761108bde3a441c7c4fdaafb190b564170de9ab9df051e7bb0adcd9908e391dbad9f0ebf0477675ecdf311799e69b02ee8318bbd2a025c3c0edaac4a3592b79f62a4837314c11201a84f31e9e6d958e57866040a5f2bb06982cce859b06162e7a040a5b33f2be5623200756880a328c9a19ae924fb7c896f5496a60340abc3125eec47590fb92dd03ca44299e8716bea1d047d06acc421483b6e41fc46a4a745e158aca19797068758b833d51a5179d53d42138f6381735cbbb0c2b54426754a62afaa6fa98d0cb4625e0b03ca0a3d371cd2e6dd1ad6da6d2bdb297f5f13f597d5b7077ad97108d0e98ef8ad3321cb4370e8bf374dc67e3e00030171ee1601d2f95086414f8c70209dc1716a50219e35992df51d221d1fdc9a18a45e8b29ac81e5ca93d30d428216c45440b8cd926add5519b0054bb86a61b307c22323015401c2eb728da840ef047d4c2abf2996a60944aae607e0e052139c6d12df55f4e28505a16c0e7ac134af49afc298e4f7493270bfa502282bf2bd621c1aa9383e0a92d5858523b198cc46a14067c1e00d8de0b32ed1c531761786b9e130d373eb9fccc6eeb2eda5d8f75785b906bc1c05906e0097234487c6f9c1bce308eafa1615256edc6b6b87a2e70d81c86576634bba14ef1b2daf37a283a5f4cb18ae78e59b20362d53afe4710bcf560be1b0bd378dc7d95accdcd00d0c880634eeca564b4796895b914c7c506238ae3c395a68137a2195e000451995588909204a746379ac80f54b7755f9c430f7dac534b39ad28c28b99e8015638307e72450b8cb6d56c68b791582e86757a7cb90d014c783178b14b8bfe53fb1abf2a9111591961bd0131261c82275d1628a06024cd36e44e0e4fd5204894b6e17086a8c8ba36d0aeab3737556bc35642082d351adfa2270bc1faf0ba09d661ab6cf443caca1997093d787a97413cae68482221254ca6ad099580274db1646fc195b4b105cfed9fba2d3ccabff992b2e05a6aebb5d6ebc7ae40ddde56c86763007485ae72adbc1375be6925b889e3e02259bf24b1aa12b76f9ad65306490fd405938953c69b71f50d702e82e4c451a537200e3cc349f342daf3a4c3c7ccb0f15e616383124ba5de8ac5d60764c040ff56c415220aea6222300c018f7ca2ea3dc57d508c677b779fdfb326d77d64b7cc573d08f2d8d48e79cecd62f080f04b96580534a807432fe4e4f0433472e7030652a9a146b463f83bc36b46c41ffb48b1325c11a3538a845639d98c970e1445658a013a8d9a72ba36aedb034b621b89d757e460e32d771eb95782d6fc4a726c9accb93774b04d23430bc9e39b9c2181878fe1ceb632adbbf2df4fb39fc55a73fe78cf0a50a40791b2f94d84e756b7c29e6f7f8f0f4c44a87775423b21980066231bd3cb306d03a86ebfc70a38aeecec325b7f9e8c4ac1494ee261f2a283ad8a2970450d2cd5254dbefa371d98ba1b27bfa0284bfb1e4d069735b724225ad6d93912466c1a74f07cd9843d4c411fc05540c4777283635a8ba7322b10910fba436c84809e0c1cb773f53860351cace24da7f26f1aa05ae4c0a1a1cfca141c8d28c05a16ac2cb83404860d2702cccb54f37aa462a600e70546cd3e426f7ced4f257c8a47f406b1a0696ba3af516dd6e02e3d55df110ee1ad2539d3d21f7fdda85ead65d32d69791e0ab6b3be2b2a3f158a38b2d8a25ca8ceae350e29a573a3e1c28310a92bfd4cccaa5ca4602788c2936196e7b694c31001029e7e9131abc4e57be60c8d60d90dcb73f084ff7735d9b6b40e357f528f934cc700c8d873c4018b91b15293e280528bc1abbc95f361e5aa23a6df9f4c3ff3a5c6be857892e384b0889b5c844f5f0c63a698c04bff8571655ba39c0d6d98bb355d39b4eb75e43715665d93f7d840aac0539d367298834087915c53105f9282082bf20629b93072355d70ab1772d0069349560a1901db72e359a81848280cbeaaa41a6255212fc3c9d2c035f185fb6c3f0a95daac8bbc6b7baeb449199ca6e671f1116ff046fc4d2fe77d654cba12b157f2f217f4c9d24de8e021b95fc4bfea89bda26b27e2dff3956947cd72fe88c34e647c24f80a64f157eb3537a44f4560089e81ce39f4814c7c921a1fa0c5e85666555bdb78b272bde309a023bb70ec66ca3005144d6de55edea7ec7394d1b2eed9087eff331eb5bc5f92efde73c5b1449dfb5f8d822094a12624a6de71d2efba4699d16baf0571eeab785a885669f7a64c1b5cd34d43a2e27d12e5a726b993525c633796837224003c7b3602469c8e509304f21905f743b88340ed228bb1ec4ad54bbeb07e8216d08e31b295c69dc52ef205e8ebf038bed90be5f70c60bcda7782207f3db2650d2154d7d774ee622bc31ae36232a1563d1067b4eb0e46aac2fb174a39c0b066de4ad7ff88b6625f7d7db6823b3c919769223f5971942dd7d3c9ccfa912f38f6096ada99838387799883324dbd265f55e9f8b5d34c3cdc699464517ac47a02a9939a82aa997f3a37696f4fbd9555e4189f787f9f71d3d290864aac4a1cb046a33875f5b32e9096f6969c4948b49ef670d0c8add2dd394568bd98985bc772598d18c3eed9327befa440387134671d89c27a04348f8210988b37304870ae817268ea4b03bdab17d757423f12a239eab66631fbc9b8ab917fb0d2dc0b89ea17114f80e01006014f1608233a4fb1f11c9d1b76e4ec072518d98848fb2373b034060fe6b635dd7af23d1188d3873b11a5eefbc847ab0c8308b41eee2d3bcc5fb3cfffef4a800eeb7a48b65d6991fb630aa53788d49e3abe8faa94d78b2c4f9bbb2769d9501e8c5303be66cb20046b5d82acbe1496501670b2e05439b70e57ac25fb3f018d4d37cb45bf7c42f62aa5e1e221c6b9b28407e6e79f9cf6d1b358d8461b9ffa992b0d40fbb18c5de6aab2aa76e3808fac00e780342c661ad75270afe59adf06d299d15461ef5e081cd4e32aff98ba8f7e200124bb361f1b0116e66e6595819e6eafba9af907db765da91d61dda9a00156948626da81e037589f371aab04fdbe959b4f1fe0d267b311dc59689b8ced5e175a1906f194b21712770f3b31c4ef87a826ae9515df000e88dac119c99004266fc18303621595fb33b04b0b8f6306103924ff5d26540b087aa20df6d04adbb9c265cfb6d23e1de3c43204f48533b6d6a5e7df1827e8f8152c75f7bad60c0c4d3deb6b3de5392798ba377cf6824017190849b04e2e14d774ad42480797d80817db91e36a5f26841809fc418d6695c867d0464db2d4390f4260b4f1bbdde97802cae777bb192f8b093b3ebba2a865458d262b1a1ee4d826bed829bfb52369e4a13307990bffc22269b41963c938b646935bf28b90ab1cb32fb8f5ea03229c8ec4610733b4b09eb5997aecad42b68e119bff37536d9c6fc0e240892d488c8f4e26757f640d94d07fd7a4b49c7042f7aef009a8495af1b9aabaa32b69bfb611c4bb6f53958ee3812cf95c091b0f55220cd3c6d8539e3682de051b36c348243bb6f5636ccb51d3bb4ffdf525e36ca342d7c45c5e112ac40b02af57da520e2ff87c06fd575aa8bd9a2128b9902fe131d9c39a9c7fbf496b50aed58cea85b516ecd60996ff961d073b42bb01ea4b14b6b8608ed3901a7f29302bd825fb74f5054bd1660ecc654e76eaffa4cd88fa28caf6256ec32ceb2c60bc50c1544c0fad34d0a51effc2ed614630e777d126164013d729701fffa0cebd3f6ae55644dc6a0798e2a068fae33840a03f6468b5b22b60db75c6faf8c97e0f069fcbf8fdb60c9cc5879357f0188b68376da4d6a0cdeca36e729a63e0ce5f59de37e3017deb575791c57e9620fb2de96a7d8f21be0a7301939ec61819b8ae52abc17fac40ad022fb06304f71a40d20d7784408a4cfb10636de17817ff6fd862d7ac0bb7c2b640b5751078c4885f4fc28b803ce31b20267443e1251f6f248e0607299a9d912e73a18dda523911c36f840c7fd7064a245478505d30994d090c2291627f44552ce0bbc8a37008de2a018a38a4c55ec085301b5dd89d51ef0981523d72f9697d8158d3d030a48ca9aae08ac397545e443675925f75cf51cda139d3cf07e73397fb8dc520884214c292b43d343258314c471f4068682a463877f12c8581681ae56116198752e6735176004d5934c99e2f84f9072ee8d9d153a340fe80906c95d55a8c9cecc6d502255823e95d971ded6d2d6a1cea2f0496c37e609195b0d0e500bc15228be89f59c4d5599a4c5bc19e816d4f6067aff643c5edafa203832bb50cb18980704e560ad70f57546496b34f2d535c779a2a51596e8c7855c05c0e7cd9a8b916782abc2430131ffc773837f1e26bb650ebb846377daa39324f298956c08ff5cf0fbdf2a3307ce0213b375696e2be34ded5835a6a2d73825f79c92e74add5ab94393066d3821526a7c720e83f80a44abf231a3222f0dc7a4538d2f9141f7d5ca2be517827943108279dbb22385046c5ee71ddf7ea41e16b077016028f0a18f000f821cd83ed20afb1638be0296efb9865c816e6292d4416e165d8f4974c87aa9a1f9a49620494694ffb742a5ebe486c5777243355ccc4d942ee5aa512d80452427b384eb5f8dbfb2a53814d19ac1bb310b8e47e243e615d68d9bb18f33b6c59e6ea4cc0bc61a2a24672f23d9b1430d8953f7be0dba7805714cd2984c13f8a7f55932ecfb1ba008738515170f305854a408f2f25b2780a915575309959024221d8d7d3501a3538b604d2472a73282228eb7ab5f1f23ace15cd85aa28581173b847650731cad92b488f04a9cf1bddb329051e1c411aaca34467f5d1c6105c5cfc059d78f33ea865c8f3787b531c0603bb1c6374ef72adc8106690f86de4806481b7a199ffff55106eadf8e6a2349d3025e9c4d6bacad5b6c569f519f2e85771d601c0014c28c570c17659b9ea605010700789703e086fa669d91ca726bab52998ec221c9bc9bdb144304adff22d3738dd7328b4c19f76c16be3f76833fab29afaa5b0c0b15135d7c3a80421a150c48fa4f65792d9ecd9e14e7cbf07530f0122f58a1159e1bebabdc375861850d77449bbeb5ecdcad20f2b6b6619bb9e57520d187f8eee371a0f01c784d1491746686ce3415520922ff10b49cc4aeabb185a9f41c449129b99c51658acd5ee7418027c7feb40ba420ebbfa2e759895257576d9adae4119ca5949d7ca113a18a1e7aaa4a0f5574b0128fda51ac7f91453424e4550ec0b7f3643fc4f7ac1900803085384deb4e016f21bccc1007cebd66d52ecd217adfcc785d857f162877d41016f197b4e2f916689bc7d4b205625c4d348165d917dbb981816180bc59afeca4184c842973693b6568f36e477a801a8b4e6d6c81710167cffd5929afb761c2101acbf754f7a08583f33dde4978af1af3510046f0db6756684ebe3e1401d81c00e20f3185a863e216efba675453b202d28c62e3491d6eb63c7d37aa10035c85a7517795a330b154c7cb2f6083c136e9fbb25c36e6fb192d8fd5d55c7d99f40dcc6518a419cbe4e4bc143aa301705733a263402ace984fb039ceae69907c022f7219788edf9c91d30281ea6026149c39e2c208d6337e76289c62d7febb1dd5101338d03c489b6adc2a94708a556c6b3558e49ac548eb29cb428c0b584cdbb554f3473f478d86a071e67cb2857ac6331c1a99c89537623d4ade22a5b8bb3f58c066cdd5a78245b54d1b46c5508e9aa5ca480d6c0197c30ef4ec078d86c7c72b9b43f53201f6bcd62b5ab8d7b67b01078e005fb58ddf52c091c11fc63a04db4d4f5ba97598ba81cf668ca917e6bf1b021779ac9acc81b2ff42fb06b2cefd491adb7d616bac7d314212a8966e5c79f95bedf02304968fbb040c76d423533b96402fe7407535ae831ae5cc893342eaa58a7052658c43ccdf677c5b9a0a729ce66716d1e0e7138fd5713c02d3d3aaeaaf2430543c12610caceb5e667c3eefb43e9c4dde55220ecaf3df2d3e55fc660fdfd6d8f4a399394c1fad386e3a30945c406ddb95cce3faa541aa011b4fceddf4f4fa5eb8491ad0598cb7f35dab27f8f5d0179ee5c3ff96d970c92dbd67826be8b92a1012207fd80ccf0df4f7663abe11e21717fb20a130a4b7cc3f2a4ad0909836f3255c844d43e9eec2e91a5683962f89c0b8c5c7818e376b0dad205bdcce83f18f207c2e7fc4ea3f106ce02ae803ceefd8611c8b708b335f8c2fd637200cb678123037135e0f237e6f9f18b04e30947bc0f0ca60895407b3e65dbb7720ab08f8fa46332dfd0e26a4dece89b67229f4a44ce1228e404b179442133e9a6cf90af982dc87c8495ed2f55e69c3641533bb5c644f8dcb161f8373a87f8d90984853151252daf616c94e0576a0df0d7d8c8ac2c6df90eb70af87ba0ce497d35a1b0b9941beaa5f6f17d3866a3bf3eba92347c56e7195483a6b66dc4d504da7b010674f4197340b44bb4cdd871c20502fd1caea9b820fcd47c828afa01021027e538b49239b9a990ef86730c82a4a9372e956c04a92b2ad355c1b423d487c3cbc112a990e72f755b721057880a4690a8d1f92099757ba174d7d887f1d9db36756d051ededd04c9b5b5020f15eeda6e02d5bea38696fc277177cca7dafadfb0184ed207ad0f840e0d27bfa626e48ade790a78f6f0cd5a127e283a93ada77af832706bc1a66d87f73f7f70b26859093f05ca7baa3432cafd5a42981ace66c4bcec1404856bef94b15c0af397bada8e30fed61f41681050cf98c9bafc5f6b94d8e9adc8551a31608eb43ff9754dc6d389eb6c7eec194c6234735aaeb5ed3740c5712e0a2c4d550bbbd3820d8353c12a80089856d01d1f559bb8c3d85d141e571c7351aa84001f802004f06e06e0ee4f9418253194a80cae1f68f3ea80186a35893eac6c32be4dfe0731b4322014d8b666a58081ba67c209afea223cf0750746672e268094cb4b1464c4b47a6b3c00476b645250105717a8ed7b42809e35ba86b264e7fac5d704493bde4bcbea7f7852649929b2eb3f1633f1f9fbf8d7a208dbc9b3ab3dfb9b2449c00afcd03ba03660811f9b6bda0d92003dcef87b32e1856e5d1cabe9568beb8ca647d0d32f9e2b040f0c30ae8ba71c02914658d6b47e31d620e7e85d4c6e32acaa125dce72acaf3c3af1770bf1ec9a2c88cf20ab6be60c9a44b0a092432f54e4d31abd701d5515cad6f30f9a62f20a5b983f39fbc3aa7997b9e60fae514f7ca3a18312f396ea699b7362b25e2132c34c1657adbeed960afbb0aac991742f204aaccd7f80432ad058ac4062b68d5d16e8ff8953dc32adc059dc572baa1b7495a0cab58ea3eb14e0103ad282a56b91ed5d43d6e0f18f175c98e02eda980b864ce32368c60381a9912a4494a376d874de059734e878e1fe264c61451161c4d303c98339c530d2a5329245ee2f081964883cfe76601fecbd0e9cb22033e74cadb3dc5857a37c64b5e01c1d6f809f810563b38d000c7557613475297eafb8e2587192fb9cb048869ac64a48737d4971363c80a054806df784cc5ef30e083e9ac6eb8c1701b08495a832340270a4b604a9f2deedeadbf50a16f12aa03dfb2d8009028f3e9baf68732fc24a95b65feb3fd0c25e7b52b021a50c85c02830f7dd0729bfcb440fa7a471cd5ed864487bd068a0a766b5e15305934d2ab6caa449ebee6c51869a064dcdd418306763257289ca32e0a7be9a93e866f388cbd85fadb7d68f55e346b6f7fd5837b3a71ac6e245b39c1f1bf48b0937dcc0045d32a2c8f9ce0f4a29deccffb65d35af6994a24b743137efda26c028afc0482ca9034ef0005a8ba5ec7c450f486b84c65deab89d00acbcaffd3191026b01017b56bad2969c35f79fab7d7e6e555015ea9872557a551cf7636fa579cbaa67e1867991c93db45ec52ed559819a3701d6daf9c104dff2647451dcbdd51ce1f837a86dce8a7e6708abce62b85fd8d8130c8834c7446c571139b3df6a375b97a55556f7199c74787303703de9ceafc1880179a61a075f80761836b98ae5502c1dc9d860a244328d1a33229c3fd7b61fea92b8bac334cd36b971071f38aa87670dd178417e4ef29bab34e4a22685f57e1cb12c899605bef84494cb058b1458fd683b86517dfc6e142c603e48c6cdfe3813a65b8c8fec9fe86a0a80a20deeca116178e5ae71cbf4226aadb7098aa9a87265437d62583528de7ffb1d26c887e855de6befacfa6ad6ba55b26dd1dd27c238589144a2080d8a1dfb3979aa1c8e0e1691ad3911ba66b1ff705856e0d451f8720d2b05964fc6a11509ca76b3060107cadcb45fa3785c418348321caf7470dd5e52f756d89ef4642e241e06cc8626af2d0db5da0d76ba074c59a0f8496f45a1d55b61dc9abe52e250a34f6ec79cf353998e712c62e9e7782c24b68676813113269263bd5a36801f88c39dde6f7dfef6ea4c3972c4958fb0fe63b268dff39f7b3df2481ea4acf1bb5db76fba5c4981b7eab77db2c23de2b11e2ead7db601cd1b6f5e86b5e6c37418763555bc8458eff7e802b18335c72ce12fff68ee581e3e230af6a56bc0c9dc99921ebcbd1674bee1b902237f9ab70edb6b655e82cd7cba88b8e2849e2f15dd206721ad142984f65ef13f3f143e5d95c25e37c4672f3efd4393c0f26b5280dc330e74a704fd6421505f65a923a4b21c40668102f7b15dcd0f82938fad13c4747c591a3ee84725634186877219dbdebbbcb83b98118a4640fe93305b571e7e912112e63e1aab96867e438c612ff5b32b828b09dddc147db76cffe1dc8b6542d388948222c1956118a203456e37ba6178300fbf711de38c758531b004a227f1fdab53a826adf3e6329dbc6cc72f3ae57e566c502fce9aaaf7d8bd42dcbbcded253e6478429bf846db7c0185e590d391a1da5eadfcadfec21aabbbe9c8e97706c6eced6f8b1960f41e6086baa9c2f4385195b124df5825dab2e57afce2ce59628ef6df2f5c644de08071db5a1ffb3d061c3ba083c4c874bd9d040c87dce6d7039550afd7ba98da24f7fd96a07f44040639452d1e8407272a137c28233a650706cd554d37c5f44466dde0777c801ca7af1b3e29d38e2b32321cdf8f26d269a8c1dac3f5e95f0393d2fd0c1911bfcce84da0112d556df7b06748c14c66b1b2910840991a75184b669b0a83bbd65a4267d8cd65400e4adc7ec4c706a478ed4d5a7923e8bf68941a6f397b914aa2137daaf543c73f8415329a5277aa90f6a632d1bb41ba4a9da1bf741b9e640dea902c906f510af80843fb59f17dc8dee8f27c4b255c0338ae75918311eab7100518f536fc3f1927bb56e3b186a9526748c61f7cd768fa1ad1e4376c6dd8ae91391a8a7671ec8b446b47d8d92a27ae5aca8d20368870a731aa411a2ae493fd133ddfb2a2ddcee5a8b6ac3665a6fee0c64124f07339b24d4ae9ddcf0f46ec28c636ac7fa209fa4c8cfac5c4c0171df05e4d8c69b8516816b0df2b05862471f65a7612da344c479270a78cbbb54d6f496a2333024b818b0d21910658e6aad69ab2c816a8d9af76b2576b1447f613039a5757d131b2bfc37351642e3ae6a2b8b262d4160225f937190bc7bd8b774edd8eb2d12108597a1e5cb05213fdb0cf0e1458f16c74c71105ad80a14ed1680dad776e6213c2f7a65cfdca20cb7517802c7d30d25ced7df83a0dbce5212f427989db4edad7622bd731d9d74b62a318858e0586547395d772f5f7d0ab376bd6839b9c15be9c111181d0d5c3cd460a0d1273bbb818d07bb0ed2a9dba9cb59b0e839bc040bed2809aca1b069a83dfe6da1b1b800bce62747dd66a3d270991335d0a80f1fc555a6c52b458369db029071183296ed98990f888ae7240bf8ba8609111b01f64dd4c7f9df805b81a58abb8ef49be421820093b54efa715f42dafa6e71a205c7252caf80b72d2ae51c0c017d40218932150304b2bd548e4bb009aa5a968d182f9d4702f4141208695d230ae6f4c8f7cc28698d3b0672acf0df2c36e57500429b460cc89eec2846e14ccbb2c2d569121dbd8fac0f8f291c02e152e0f51889b02e88b8469ef16e37354f3f63fd038696aeb8ae5574334845ee23ab2ec48cd066aabfee7ba85ce307242abf794d2128608510bc60a4774da2c9074ca44623460ed6da1c958aa10a88deba50b1df4d783618d2a30186845edb4d44a24cf3aee719f0db34cba41ad30430db935c2f30d276f11e35b47b6315e82534d07f8b1696cfba72581e5fa3cba2e7befa8c8350d68315c7f758d87da0ca0bae484b910babc2f0153255da145dee6546d8431fe487998facc1e8a18b4b2017c0f8a993b08a4f853d645cfdd7f12294f6e65057717656971d2bdaf8846350e6a7b4db5565bb91a6f13eb8421f1bcdaba61f5da99fef77b9b8b6ab5dfdb0a1fcbd2624146e6c54efe99002a7d1ccef3a6a049aa79b3ac7a082c9a9f6702df0e8f1fd1c3e0907d13ca2d5c9943be4b5465b0a5922f69f1514bea4cee8368afdb09264d20a92b4b0d54a917b8554efaf87062f2e7c1441b8a6a44eea9fb61fa5d28b2dd1fd20e88281f1ff52d248786693efa499ebd7464b3738aced1f499222af7caebdc4e21c5893461621afffc7edb52f2f928747875a10593dc114836349b219122553d8acb0eccbb105349265538ff196a8cfe7293dfa81ba58ca7b7979ee3300d90c5393ac4a82c6276c57f930346deb7721b993b1bae09e47cd6272867e5b236920ac3efb9b9d6b41e29ec033a586071e5e53cb11e1a8293e1b49673624225597c49a63755c2f53f95e7c5d0857afb31ad163362c4f8535e2b2df837d64c0b6adaf017851baa167877f63733b6715993e3105d6b1a8f6202388fd5d6ce021ed6bd30f7c2145977e786dbbe968e032ee5929e65bb5f1f17ecbba8a587c29d69fe430780d30434db3f205e13022675a75dbb582c0ec8bbf00b37e157934cd16864af98080ce4789b24c40dde2d45692e51726f42e5f5c406deaf27b33c2e268dc7ae03f8d466f5a6043b814fe0a23cc85b7f6e69b6750e3b9352b34e78471f628ddee680be61a2cb8b371d324451181e54b00468eb1edd149feb6bd8b65621b6908b9d90dd1d76da5d212bb6afd6094a2398b2c54f41650082aa65511cbc89f8dd6b8ba81a187e288d75f120fc6581583d6502bb0b22bfa99cd1ee45bf31a3b9039587081cf28a91496152901d9fc965c954cc71dba5c4dafee67f7c0b2b62a1d7616999b27bcea58bcbbd55d7956ba41793854e4d2c59b51d6a9114142edcbe9a6e95cd0a1733b4c2ef80dfbe56c5e92d516edc68646f89ef271cd3667e0c3278c8f968e8020bbe7f51b65fe82cba0ba3104c48716d03d3975ff1046e6644b528c89f10624c1f99b4cc2936f268cb7defa05d49f15d5a82946c98a634d9004a315d50364ad980915a758b35ce3e91962e96199ede91d2cddd212f2f3b1efa465e0ed0626a5fea7652b4fd2aaec1183db649ee9504d5cc415a0f92aeac9a4afc1288341d8cf74a711984beb31a82fb605cbe77599fac0c08ab17929c6367ac54c9c547385518ce3a20ac03f700d97b38167f15e8011d92526a9d6391a57e297222d6a00a9be584d59ee91449bea91c52a80087942c66ef1ac5bbe7f38a3060b444552cc58a6b92fe4dc679542f84061ab27264ede6aafbfcbfc1d506da2b43970db032dafc7056419c003e7614b154482077ca1ddc54a0a446a8116a70f0c6c241ce2b43567bd8416fd29471544ae581740ce95a52983ec0963aa073755b73f0e5c12d796b05c6a7542d9e4e4d092fb8ee0dc89a8f5465a43e0a92c927bb32d16bd6055d2e2abe860eb4bbd652ef090dfbc52ec9fb3e86a069ea63fe3390ffba165177cb3768e7bc5e45d0b86b0aac27d6660426af993da77b80794d1532c1e20d8c52e89fdc370f8f1b087ab689df216285ad668f1a39985fdb8dae8e226e54ad723ac96f8fc4a731e0c4116c93fb97c2857ee985a8f60bfadbd82bf2b1d97387c0cfaba64beac91e72d525beff87935115581ab9afd1812f1e61b46d99ab2e9016caa2b6b11a6959d1212e80aadc5c1210bfca8c00d8ed767012d4cf8101a2b4654e10cac7342fee7fd869e8fc83ab7ae0caf55189511f266375b4aa66227e9f3b1f0fd37cf9ec2cd64d27e4c4eab78490d0cbd03ff96237872959b6b64e2893c80512470794b1855e63b1077d40bf835c93b11675d24ad6396a5327321c19543d11bec71cbb802aabfc55b9d09c7d83fca03ee3af414fda88a4eeaccbb3f4717e9aa7d07a0d19f38bfb3ef445c3f6a5d0c1d9d89a2caf7812fc36d1b1e10bc5a3a5435af6e2087c34e770c1d73fabc8f0fa908aa4e487a8d2f11887952008622ab8b8d9db8d981829c54e1a5de3eb3766d0f5955ab74aa2486067cc75f11b74d400329c23c07210bb1bbc39204f83c445de9875f9dcf94e0415271b5925eb32813035122555500f78f0c4a108d7e0a1b119c278920e1f3ba344c1fe250e56a577710377b4d08dbd7dc3491f4c3414bb9fc995fcbd34d7b408f36f3b10d8af513d3a85a62428f949586babd70c15b0630afe1db956d05ec8fd7ee4d4250df08ddf254e1c27ca192accafad9bf4c9301b62b7fab614d0667351334c92a6bf8d2db855b9d2031d371059e1569b4e3df408b4e5613642a6ed26e65c7aec3c2a86cb2533e29e80c08a3d03d0e653c927032393602a02797119d62c678870a7a13b6420bda1889804c73e930f65179fe8023f3fb1661e64d9e5479e247f7c123e9666c19e89b634c322d4d1b3fcc45c61c4b4574822967601096a83d870ac9ef98e82cec79c008de2e0b9c7afc95e86b226dfa81932ba175268f0d7e390951e40af0b057beeeb756f7983496ddf18228bef4b3a8549f943e88946ba49381da02aa1bd67d0d737194cf1dfbb93e36b5ed54887dbf908a353b65092afdda2d4021b575f5ea1d4f9cdd6e968a96ac3dd6a442343d90b1a28ba19d955bcfe338f40f59e53812f5be502e2a082e501c3a356200b47e7f0575bea4bdae77a9e385ea9c2b71817fb942971cd659b2c3b0f80b0342c7c3bba06adc8d75caa5d44209a8bfc55000053d43868041d71065ca61939017c00d16f9398704c052eba7e4869d72369334f29fc432587c5608ddb47bf5e6c08c3ce58bb1257b12973a89b3640110accf4f26a7fd0ae57ac5db02b7709a27f811117bb33669f1139e2043ac9d1286f288cae9696a75522e8f4177ff0b7456f6170892c7865a92ad49af6a85d11ad4bf6cee3d3e80c7388eb3666ebf4997812fe14e795f7515979f5f1ba3de1592c79288408862985bfe5c33a360dc963397a809ebdb21c20d9b681dec0590f8d98ed8d959ef9fc95de6adf19ba01d9049128f3f9f0e087f4c68d201c36b8aea07a3c7577aab068f79f64cd709551beb2165a277d2a2dbf89e653e512f0f4d905c6a5ec25242e220cf838f5382262481b6b298e32438221effd31cf0a49688e574e65e8c081fbf6a680fef754cd9135a16a4f932d23b9524dcb4831b9fc01e52c454a451759a82e776faea3a6f81cfb8373859bef442ed3dea358bafea3501b6b72a0b2886ab83a210b5378bd9563a7908d4d33622dc3e026d79e58f16a22bb7d46adc2a982cede2fcf5ce5ce7c5ab567c4b60d646a762345473296141bf0833e797eefe35713af32669b1cf9617f75c785300e2a092645bb62f23887c13089796a40954bae6426e1898b3c683bf623cc6ccc138445c5c52d1166cec802b0b6b51d52163e6d0c55989cda9f8d68270f9924a52e197cd38c0bba515d2a69a2002162dafbb5258a61581e9cda65163040cf55f7aff0117d6c2587ff5b3fa9660d53cd50b8880ee0ed3153ae91c591e6cc5d16243c1e06d45e827b377e988ad5d617af7f3f2686acf249ec0e5790615d0079dec7f9339106d3fc44463cac394108fc86c83fba3b85fa4c78aadf5b4d9ac8eb78d0c7291239e65a784091e77eaae8ba450a0a17daebee902daf1d1e460c992f8e5624583c8c651a130c14c188c585cdde36c00442dc29f50e5d3e0e88f6729336366920956986592ffc25e42d4fdd76fa9ef2b8475ec56471226869ee8be0e6bb0624db6c7808647cc9bd88740bfa19d9cd43c061ba4139afb3e22d814d546f9e82d338119bb9875a19294c034e881ab51a072e2888fe8f7a911a0f5dcd830bf4d6edec76b0ae66524519092b7ebda85eb38b432247f3874bfc0023f6c0876dd1476d29ea17c71804a813e80544fd0a3755dc2e37e8d951c8cf95d65192fc80bd21441814bfc249bc4d8802e361d36b86184da2697f3856c3dc4f0b86f1fcb8a33ba285d0a3acef6a23b7074aed1ed15a967d94339086ecdf896a7318f7fb32b864631b18d5761e2fdb6c79a1fb5c043d70de28d5f0e69dd533afac3b3d2d9cfbcdebb309b46388d649d0ed32d30d3dfc918eda088fa39f84c5694b88b6655ece8980b654ec3d47c0a0ec7b7797c0614011f7cf57f9c46cd8d2e90d9125404f92b9dbb36bd3d9f6a3abe9edd2a62e0e595a2fee7a2f67a344090120056b3023ae6a6991d7d20ffb0f38d673498f4cc5cf022c7565a716845f054fbf1573a6a733f54c324376112fc507c329feb837c31f671bd5ef970c28519b66b9fe09e83a5110bc14c031cdfbd4e39ff38a552342f369220e9cdd623f4143b3a4caa2b2a87c499f3fee9744d5d2cc85171825d988dc5bac0b26d8e7f43c25378d8827053bd88b5f06efa3854b530963439d108d92d87088a853e0a63b9743b495fa2d4ef797dd9f2cc3e6c1641d40f112b2d020c13da59676a122afbf6b6d50355ba901ed3384d743202178c557deca94dd20aa16223155b93e7a59eaa0416b6dc4ac8cacb3d39d1c28bb6b73638628266a42753149e3c30ab7f33b01daecd2bbf566f8aaf5a35892c3c9de83f20b90284115ad4f46b9913d9985f1e76757abd9e9c288cf1e45364a6d2623c0a04d031ed2017393f9f34923d5e79a5714ad7cb7404e3fa0a90ac881ee08f39967e6a5da7866d6b2075c293eebe7f4fcfc80c22599d12bc15f574955d7f49e75234d2dfc0536849a19d6f419eafd336789679cb96fb57ac9a6698539694b197593403daae72c162baad2a1988df8343b146402ae6e2a5f30e544cf5511fcf075ae834741acf68cd298ab3a07e7d8b53f040c677542af1221e261de84cd62d6c0956db0d92ef7830ccdc7928124ed20488644300a99f7f0cbf41513a84178b710afd5b47102ca794a3b267a01623308ae01d60f124d88c8af3695bbe8637250fe46f53ebf359ab6e501aaea643d3d597babc437b243ad1bed7c096d2b6e2f0308708c0dead206f7d6092974f0c23d10966b4dc501a03dfe0e842dd0d2418d35dfa0b7237ec43698110e8329a6b2777711535eb53dc2677383c901724df564a01939bdd9456b93aca7c0eb6117341533a9335a10e2d587c11d9916d7c4890c1537a439fbee851b0824b1f523bbff93b580126677f6ce02a9a5034fc9341b8fdc790f9ca2a24820ecffdd7f6036e4cb06bc0301a0f264d46e84621649ad65c7f24917f6dfead5d9385362a829d54c14829e16d559547f288d5a59081f4c9c6f511af5e94804f10d1fa4690ace573b82f10726297953db7c7d38523658c9d4546548acea36cc8d11238a88d8501462131b9d0010cbe488048b0f83d203107bad3d777c587608b6173c8c1d58dc88dcd2069ecd981f87cd9498196c40940ddb85601c467ddda3cd0ff014c7f779cdea0f039f28d37821ce4db6669195cf5f28741341cfdd84718b4d573dc633c42030ff1e7b8d11837ef70b52fa62d2b3c6a8df64e0cbddd91e5ca87173c32a531eb6a6215f9ac61d48bfda398750ff039ce903561f62ee75e1410b8c884f889bfd4ead3621b1dca902637cf3b4d54800eb58155c8869b7a5e1ac823c3ac40a191c894253979d0a7140ecde4f6c412ae707fdf858ca6c6de95db80205d1946460242d8887b9219c6eb1d67d94589dae015e2cf4f4709b5c0317b9513044a389110d22f70840aca7c8c6fbc81846e2a486b27304e1504033e9805bc41194f1b04a56cddaac691f9d612a6c95ab3d2b7dc4f25df31f5aa9349fae70ce2226f121556872a1c1c6333ce81a47de02dc5adf68e2973399991810d14dbdc2fbc6c022921383df5c03ad371fbd00b9bbb7e1ca6c63bb9205aef492813f654c2fe128c1e98c3c2843400218efcd34adce90f64614e752556d77eca1c9232ed2d7cadb928e330c1ed0f88ed9834ad62de3bd00eadc32e5b79aae44e1331b15ac08356eedf0e8e6132e820b28990b837246cb03f54e073feeda6a8ec4f9ecdbdae07921c6f0b06edb399f77895b33c843d434a86d538e0e8e37700c88110fd54dc2fc82c686866cd1c29ed427050751b2966acb056818da3e79b84c4e37b1779da3a101f812af231f792285c789f087941431225bfaa2512af3f4121791b987a83c5c46d2cea321ae16813056e4ffb6c9c6c346d79f5e9b9a7fa70368af5a7ce4f6b3feafa57d1e61684634e07221012e4a03787c7f8f3da6d3107bcf03eeaa47fa8d6b09b2e7549644bad5974b374dcc1da11221f81c22f9343cd58e43f229a3b188163606d4a0fe1826f6eb66d1b6d8a3ecb8e3c434d419af53681c842521ef7f29a3660489543b66d80a1370600e2ad5316f7d3278d376ed39d377a076e01b9e95d65da55c2cadd3a2b6a3ff7d40a3cb14545d08550b967e48da7a903fa632b90b5667ce5048ecf42957ab53b8b712f0dd68004351e2c5d89bbfc2261bbf76795d1388b034514ad4a335a4dfbc17b9f736232a470d5d6b9957d9f7abafc020523c74bdafa9b82f2d48554d56db16a04d0b26938d2d3d13e34cc3a1dcd9a0f138f7471973e050bbe26f6813ae1fed03ef91daea1cab3490a37d432f1af4dfa4304d1131ff4f30cacf53153142f348f7b51a2fc83e58279f0e8603393321d86b97ffa7cf21c8a1d198bb9a8ee3b51c65e4a4e0ab69b62f084410f38d9039920556751fe3391bf6560e2acb3151700311331b02fa54e44bfd4ba103afe621cf8fd1fa83d8c30184a15f6ad48fa9c29059867fbd5caf143a40282e1d819bf3c371bf31f62df1d80d9fbbc5cfb4a18db255c51b6d55a912bb0465a175c291ab13f838789ba549214caca259192ea38bffe43c84a87e4cd5d6498ae94ee3a0f99656d3a825b7172e9bb28150ccedecb77aca715c441b45772fe2ce4e7635ee4c8258274f3eaa94c482d097232a66b7611c8efbd80e5fa315218ab857ff5ae03ff33976c4ff92f1c4cebe43e993f7a5a9b8b2a132e1fda7dec957b3b9e98d36911829909a284ed6ef1240e02171b323e922212c78cf84ccd2453b092e928c9a04c22f7825300f5345c3dce8e5967856b084b851921a6257a68d933b101b9cd135fb12a159c190dd0a212960e72c8a0fe64bbe958025dd845d296a509a760702692575aad8f0bcdcd9eeb7c83c5557b134d999cf01ad47c7c1cd1ac7406af0a44d5fbdb9eda198aef9c41e77061506445e4813239e41dee6cadccaa221fc66f6ad87cb421821fbc9172d04793c0c2e044ec1be5d81e006e2016ce7339022b7d52b37b36e1e648a02f4400902e9d8ca229565d9d3ac04c1dd6a8d4368f302b789915aef24b76d1859947b9a551be34ef9b4386ecd5cba2712d3f4a9afb50bd2f2575a8d98e75b065c8e29328d89a1fc74f2aa6174ddb527eeed80e5fe83475d9a78fa525901e582a05e88f8ffb558438e32d68a341de6e95e6944d10ff97abf89cc5c4d4abb6a55898b09a9c46810b54548556ba7296aa31a80e5c4e2cec5dc58b0c8edfef3e41541b79bb844ca925901533c7c0ab303f9ca371879cb68ed6fb9b900476dfc175be1803f14848ebd88d6af69bfe28be8d0da3896e07d8b8d89f40f348b5ebf010698e92d44d4c2976962d9b576fe6f9bff1ba382a4a3da6a85c7f087df812800e3939c26b4c44de3a2bb4d0d5e5e6c5c09d76524318c2116037afd338985499b26049e7eab7853d6a773c3ebea01f73d010159351c9a303e11c1d5bb9970f18c4ff54d4b690a7107664d73770cf628b8606d13ebd6e4fe80549fd336e5c6808033a8e60d693f5dd3a339fb38a39654188a539d984cbee76662ed9d5d28a5f1a9a28120487f888d825f7c3541851a6220a2eb06c7380cb6733978ea5e41f0ce2abed93029a376c66fa7eeefa056d6f2fa00f025be678e5b4a25ecbbbef826495f01101205991592a7fb231f5e0726c00a4b618206d9a14843f4c30473b4e091d92f41f05ecc1269559fe17fa2bd7b881791513551312b058be92b229f7454c153776162f92579b10ca2b35ef37dc95e504b6d92a235462325f312a95953174a3c4bf8a9599ed4f44f49dafb0fbc49a3b2330b5db7588a792ec00d68677addcebf77680831cc74302c40f2b0268144b5f1970ab4839cf8d466ab3ab00547a45e1eb272519ce0a613866863b69f3e5d9f7b79eb9313dc04a09462c354c2845fad52e5406cc412b77a32c071caac2c8032840a4dac3fd01a6b4133c16e438ecf28812432b51ba02a939892bc84c087b54be99705e77a344021f2b70964c2dd445120323c85b4a2a16334c682fcb0869ac0503cced5b51fbc5abba6b528ab0bf139685f9b09f313c0e9db38cb3955d49eb5d72885d694d8ddd9e42531c6f11297e1f15ee92be370a967092a09eac04759681d0eae33e5043cdf7d2d4129f9c9fbb227270c4ad69db3b3e119002a3726783f273bc1abbcd469278ada4c7ff8acbc5a839aa52a33a8223b3a03bc80eda648a6584a220e504d435a9c014f2ec135faf78cbc7f488b532a868baa0f4536bd4323e7e27c1951e72c65d2b8563c311b676f7c2f7c6eeefa176085a6f08b62e03a23c131739e87bb9dac05c0448093a22dcb491b8389fe4c6c962ff8843ad0e76baa23a6ad6aaf29048e3174d3f71b5e1109852cce9b92a8c0b34a065d5b761f9baa13b335e95e8927483c95c7ae2baf97f59dd50d397c6714e0a5f1e3cfe4544057ede6ee94bd4e21b483ea50917d1aee469701008d0baade1b55e707eab23e929cce9f730ec14831c9be24dc7e071839714ea095568881caa5dadd42a370032a289fc0094731ba4946d479788ecfaaee55b4cd3466a5b4b2446b04a30d5a5503e8523d958afbd1ed1fc70f487a579d11d0816073daeaeddcf85cdb54b54f177e1bf3ddec7075ca8ef32f9735cf82658a145586bcda4a06ae26d61b84a59a0baec5ac897dc5663c81b3b54976e73c92d07f26fc98c78c733eabafb9559e843598ad76cbea68336c70786cdd7e7e0d680e7d9e73caaabc8b4f8d35dc60a19dff7373017d59b4106c569a2839c7b7b274308711c58e658dfc9ca9756cdff2c1716010df4eca49e2d1c2c7fa17ea110a979d7d046788ff86f57ee164fa2491787dd64a5e13a745eb60638c20017e013e04f3572fcd247b0d71abbea295dc36134b4c238b963a08b00e1a690a8374bb12be81ab11026a27aaeb533d117223a35d4ae0467a7dbbd0d5830d6917290a5870e6dc46f9d9398b5173b4dfecaef3bf7ec096ac4253961925d592ed75d9579b574a129bd1025492c08aa835ae96cbb461271215ad48cf5b208816e7cd0c847473feecf1d419cb6bba5d77fa4225a20288f5274846ae94f5987bdced38d756bd8c396fb245a9e2b4c1326cce16a120d8c30d3b086a2e8e6245a358ffdee715c32baff63fa01a32659414a0e24f2db0e2afaec89365f7c45e22b662f31240e7969723e008876479cada45ae650743cb4411d80eb74ade9202275304e624eb0fb12fa93f1586f671633907e4b713d4c05b5f2b1e70454916e45d71ac2cd380764527240489901ee3a00cea6088faa2c5c9a799ba93adc666e41ca3ab4839a53321a33195854748128a1596b4982f223b41f48d514b6a484eb9bfa92d5af769bed16671f625442b5b0f289d39e8449cbd8bf01226429c5f4407af4a07e75618135067374d6e9a2b37e064ed786e6c7dc20cd45bb73b95b794250689e8a557168277439e4bba35c842c1ede78a1f7944d74f4ff9ae151b6051612891b53a3d9f224672f8744d6d09f81d5308fb7ff59654588084f44158214eca054eedab94d6930b15f1452c727c5868f14e02c9d9945ac048439c393af89ab61a422ba67e4d8c07326c463a2c5712ed5caf34420296a3749ebc694fbff47f69753195e2489d98261da76dab7831f5e660aa1e21961104954140165593b5b0b6ec9525a337ac3d0722d0252cb0b1c9b958a0edff3471ef0d509ecb6ad68d5e602a17b00ea99fc3057236d18676cbb8bc5b6988a8d213d1d31634f94a952510fb1ee1b66ea3117cf65463fa42b44b96d303829acfb26b791b30780b87c1c7cbca3afcb97f18adf3176b79f003933d671d5cd48d57f049d8759b5475a5805373d53b003bd004790bb1a6403ac35a6fde7e9aa250ac2dcbb0f9872181ca2f6f1c11070a53a37cb88e2c4ceef08b0dcead10ed26f90dc3594b7d2b1089c4caad77fb6c505c9a141dabac72e3ca17234e5567c08f86138fd871a104dcc34b0bbae329470851487f16acba4b6da1f4f19e239a6d68dd7c7819706a2aa67e77a778db72d911a77801c443b404e6e7a1e91664bbfce3ea8562cc8ffce7700244308983df19e007043dd66d86cebf257cba8227f0993ae355c4c6a1e0dbd5552350495524e5bf594fa653073ca5a38b4ad6e20d5e1f4a4b44d54b95582d74da101c06625259ffc2020662b1738dde95a6c67301f8d887c32793101f74408a92a83c199492de55223dfca478067406586faf309c2ac2a15c450fb60265b27fb83df96ced792663d61f8eebfbf827e939bd0031499083c8e5274b13e6ace4991cf85dbd35621fe46219477bc996b6dd7163c85cd84c8f05ae9c7604e19a8b2cda641afe1a20db79a5b2d2c937c9f31686694670805cbd7f4251f99568fc1b9afbc6ca0fa401221a5e3bab4365240d75b84f64be0195a44da6d2e0ffb1cfa8416ddd994e15307f86225c777d8257ae54bde5e6c5ff8b89ef5e225f4b6c7f4c3bb50851cda62154d0081d34b91344ac33d72b0faeb2605e8bcb69a9135cafade1a1c540ac9e10193e95de6d58591a202918c7044bbf0bc59186736553289cb3397189df8a1b09dcab9378de24dd0434d46b2261e76f2173112026dde1483186ef7268294e8b91e649b36e83f3c92570b334e662233c272b9284a6c9a0da34bb670ab02f519863a3b50f874eb95648b740397870bcdce75b0d66e7d9ab763b04ef06cf5434c1b02c54c51e83a41d7cb7a9d1d3c516cff1fd371737211128e46a2a865fe1ed3aac76d689d9cf22711e879b8d76f1b889f61aa1df3b03dae0c35d49ce3027182ed32ff993444c8f63e4f4a8065c91ab8b0944e24e74cd1f1a244a05068b5a43b1497df6ebcc3a59956cd10b903fa5620b949dae2a184dd589154ac609f1aa9ef3fd0c3e687556e6c943a1975df244d8786240c59a2e490d50aa785bb0eb33545ad00aef11fc1db7b1a674874b5f89dda6e307a6eaac1cbe471c6dc279745dba6e8a982ad94f5e26ee00542ac96cded164bbc9b3539e4343606f84d19a41f76a3ad681a343eb32f7a67978a496b15f4914625ae662a173d536ee6f8a7ba9347d1131d7b96a3caa44533f5038ea67e9993a874bae31966bfbc794a1f35b9efc249a6076e639bee04c1ae6234f66cc53342b9c5983ec68e165797054adb636ae71c6ab6973b63997012747b504ee426a46230710528245f271b0b4b120e46e731cb9f978abf4be721391d0915c46a302ddf7b61c23fe34e0b7988840c8b06b22ae586443a2623be6a79cc08940bf004ef733a5b7a559fc8128986c71170c5e461334b812d87dc9ef3c46bc0bd667a144bc0dd7c26522db94ff204d942a10408f3107b8d3478f51018d0d7afad1116121361260f785beb5185b3a4a91fccd66e982ca89b438865f0d60913eeeb9df77b36e3e79738ea1517c888b6dd26d8fdecd1153dc527187c9a98d984552102752e695bc2c5ae18fe5ce73dc0f050e0d2db7c69fcc8c30b878821a3d9df2a4214869075ad75c1f6e5e0ba980e07f91e53ce10a5e8c18fba754a722f28a369765561456974c0dca108bb1f420f833acf526301b018564d33e1aede0335b000757192324e7df4f80e4c11e5b8d806e2040425b926c26f9be6b1e0ef5dfc70bd993339bd39033abca0237dbe6b2073d7327f314883b052f3831052c2626ed92561d50b1be74c5c423ea7df697540c6ed4e6f2737870ad91d6c80554a17ad37ab9727dbdb821662bfd23a2f8c3e8687e299c8a7125a75db559d9b4518a2b1003186fcd9838303260186ab2b0e44b35de5c8354a68ea69d174b7c33c10f3879709c5fee8c1dc22f6b0c07527011b0cbf6c4352b391f162e8c7424be55e855b27d3ff613db56e85525af830dd0233d1312a63e52be6f8946afc365f9e6903b23bee323535c3321f4124a404496318f6a1f94230d8452456d53ed43f322d04928d02ac565e5d5481699de8b7efa0ff5d9718a89e64d14f05716e3819b67ff4bc5548cd8d8ea9a94c313cd733c803f15c1bd8ae962af3a4d5c491f590f2b3b0ba26c925e48b1b9bcf8e7ca281091b0f5d9ad2f45b655a2e5ae9739edb51658c7a7cc788fda2c833646811f9fcb2792b89de42156a3c34c07a808879bf0abbd9b08343b8e08adee2a3795d5f24196e719dee7b220dca49eac557a741b2bf9512b46e665ae7061f0c9f4421f8ef5d9ffd215ccbd837fa15ac05195b6ee4699740a5d835912aa1d8ca58246b465e9462ba9de0f9fd555288f8e61863697560a366fb0d694f1a03c78ec79130a2bed12f4deb851f40d4eb27fd5c69b885484e8243138a5279c4547084ca1d9f1c6b56ca0d4e4e3c0b616485bd8fe6e5b8c237f8676ece24102ae885238456e04d8cf72437ec20acc47b707dd0d1c8338ddccce6a67f1e135eacb57e4515deac7cb2705b1352a16bbc9de10c2a059f1ac7a2156ae841cb41f6f0ed1af73cd166daba0c5d5fa8382a8fc877b746478b2564aae4ce2a998b097bc527b44b00ee4bbfa0a14c7b807adb4d31f070594c494fe1404537c644290abf3174fae852800e6502c6c04a0d00cdecb84e291c225fa40ddffd53f28bbf2bde3015acc0a03b4e6636ade4f4ed88909ec9f51b2c1028dc74fe40664a989f69b774ed56388b6cf2d7a3f5b657dc816b08766bc3c21724284400931a7a1d8fce0fb947cb0935985338ae90ba30e407b2bd5f5e85751f6be259a01b3fe64bfac0f2f96e92898496c51af5580638e45890a8b17957278a474adaf90835c9bbca65c39d6a5677425eebcbbf7d32c5eecc1c495440f1abaf550ab0347431c9b24ddf0f50ce24a2af3d964039cf782a7bb6ab822b85d6587576596251728953d92f6843d14c207528386942df47109f9d0a405a392e427f1f34b93d83490048db38bb81766e35cdccf2fb903cef71e4c9228559dd1aac0de7fd7658409169c468d382eeb512f87d7bd8e50015f74f207b1044e89644b87db3e0097a7ce2436cf90de5f043157bc942683d0f66c535623ff162b3ce598af3943f27d1114f9e67a466c5a08bea0d97c2cda582aee94e3f8a7f7c4802b7df4fa798b0da5b8378b03cb1927acd376467d1e78b860096683a713e7d3cd8416fda734ece30b6dd376644f1ce3f4dc0f77eba11b913ffcd52335d61891c368ce76e63454937007b63a96ac57e330687ddd2ae8a9fcaa6014849e70e9c0f981447e28d08eebac4c3b5838af4a321a535911f6c539b109705c06b051edcf5c4203a3c628891e741ec7285163099f07f471b47588adf898aba0b7189b80f525841d9f3e1093824b4372fbe738316a43342829b7b1e7374978610bba6d961b3ba4a74d5a504284693bc9d1ebb69854370d0b3a8771bc71dc02077982b8bb03338f600a3d2ebd98a57bf3d46ee7225c618f7ca9071c6a958740202610ea0282252df5d2c62a6651640c83fa8e37691165b359a786ec6858480678b62b8ab6f3431fe743cb023d9b1b8223acd86b169a164e2a62e3626b780cefe4a4088432df4a244be431ae422f1d586faa7bd221433e88866ce7aa7b42a71cb263301a120691d4b5ffcdfb6b8e3209762b3edff6286823aebc5451670792aaff5247b313378042c427aa37816efa2a06a0424f27254ac85ce13a04cc641403b8da44ae5ffabd82e7dcc195fc8ca23cb085482957119db777e14c787d28f82d83b243518e0dbe28ffa5eef745405e37b4973bb43c563124854b494ef58af000c2c182fd76f58a8743bd360478432d4b0ee97ce1c581aa660ff111e65f390cdee20420d8fa4d8d692076167e6b2ef772695fde4c3fd420b94ec04761bb129598ee707397da0518c054ce178a646ce0e9db289fc301f2b432acf1e1cc9ef5eb56448f598c72586fbf008c08e07fb047bb70de34e85f5dfa9706bdace478a0be5a82420becef94a4f1d94263de507bd21dac40648c4a681dbf628f8707d2d2c6dd401904ee01680ebe823304928cb0239193076fcb5efca1cdeb12fb1e109e8491e5207322adf4a044037f4a02818fe52abd813bb931c2509640afb1aa2cbbf218b08f98472092cf7fe0842444e10df19061e34523bfb51038ef29cf29ed18fac3f290d2f211e228a219e0ac384d3ee01cb628b6e210a684ec13b15ee16ff5c9e7c51e1d83657f30d74951381a2cf0f8e4bc458290ba4b340d7e659294937c05ab75c5ae3aa4a38f4a4a0fe0dd2497877a83702c83724a24de7152d459239ef472afe5ea9ef091b66012237412cca772d7b391d89aa8512c21ae54d3dd91f2bcb46691dd9d955ab171df60d861860137a5a5dfdd6fb4780b2ded6017d0b663bd29a4010cab8fd38eec114a37d01aff11406605486fb8ebd155f275015e2e3d893ad5220178f97addcfe06dad81826225888604530d0a16571cceb45635fb0c69f60ede6ff091074722a3d749cc99eaf08c522433b2a75c12532437de9053666968d66dbbfa4d54683e1635404e12b975997243d9012bf523ae51be174232da9065ed45c4886165434e87a136943bd4ccfb9c5e62aa2bb41ec270296fb4a2eb76f1091f79a2af8729b675caea7774babeef5a5b1dcbd7b88c31d83847edadc280a4e02942a1419c4f8511fff75e4ea13d3d40737ed88ba62cde622fab19725a98e018b5d51281eae636a7b547ea4941c26a8b7b5916fb648e274040c6ae13c35fdddd2f49874ddacda922a0ea56eaccaf1a2170c18847246c8feece050b4a1511da13d151f30e331880db300d0d58cef821c90d02df1e817e68b9bad148242f4e016169eedcf00ed03054e24275de95f013ff591ceafbc27a9beadda8c0f1adc4106a00e37b9f8c1d2334f097b9ef6602cfcb10f8c1347717a563c92f2ccc44654df86a0a25d84d364da7ec0d2008f677fdce7e454211244da0baedf597cd5a641a82bab1e959d71eee131a0b05682917d427db195b42fe63b504cd1fa98b8011218f17891852788d1763abc05c7980a2d88f1102a42db1d38804c9d72d7bf4f909c1ff1dd4cb3d2aa543927385e0c89624aaa6c6399ac10f597c568b01612dcc3a981d10989c4042141611b5fa3c7fa67b70b2e8e8016c41abe720ab3eef1ce57c2723de3a48133ab87f047f894f2cec8b5e4c5ad1d0dca54a8315f4e82f1f2d0d7c0c5f60f5c51ebd70bc013ff448b596848de3c2bbe96a42941b86466d643978dfc82667b19df25b491ac04907d66cb73498242f88c54871da6d1c592eb8b9d6d7b3f83276cc4df65ea541ce82d7b84cf2bd3e6a62a8631e3c9c48488183639399ff3e7a980ca4a0fa9f41b6ab69923725f33603a0d8bde144a4a5cd10b8ac21344be6d7045e58b680fa5fe684f3199361f5dec7ac2a331327f4fca6615ec591818d8a8af43a8c92436c72d8a884f11b9e414298e191192cfb6641ba2cf6f1a5f494e5207e14137e16e6d1f78a2c38e6d1cb44e36a214e0587323816448068b04e22538c1f68e712c42311904426712dc5c50e89908ca93707a60126b6e79cc09ece4992cab2288e226656ee3c83530971ea6196aab06bf41e4ba08ab1423559e22b009c4238335a44f64e6f68281d98762c296c8f5c0813904243140db2a3db11d191432cefd034dfd335ece71dde2303a9446d9339ac36e59e4a31af53722e19a8ea36dc0c34dee2912a276f1658ad823e42aab286e1273a11d804aaaa3c4be2dc36e8e5fc2378c64d1edd9f26d245bb1c0f7d9e3413eabdd20e0b171275eb208c94307a5320a9604b32af250a38ed1c1c7d103ab0051d1c0e781888440b77d1af5d99c32ae8ff3418677b3dc7ce24327f9a934f8c02843181090123229bf2c463f75bfba55dbad63689cba2df98a203017c8a03da1e8a6e5920da15a903d9abd27f458ea7769d7c31cc9d5666cf13012eb38c2e4c5d4817d6c9680af1660be02e4427ed4b600ce01cd600702076e890f040c95d081e7d3bf0c3b271a7f28ca15b4b4222a8027941dc6def2df79652a69402d206c606e40623d80c9ff1a2a4c1f519df2f6962824dedc334da87b3ff89c940c791b8153e3e05916bc120a89953cbb7a09e6680a26779fb32c0202da8a7960641508752097452ac766fa01f10380871b9efa47077e53d6fcd65480a19af7d3cf849c67becf96466762dd44df0c5869e665c0e5c79ef3ab9a28cf244ca64109d4376219bc005394a981692149200512e71fd59240d98013d246cf4b22ed64a47739f59f8f33ea3588b5d064856404f829dadc9f290460c262b7c6245d7d171978e8e8e8eebb8cee7222a78d286bbf58a80cd521bb2da9881804bfb47a24e6e57e089629ea8999aadc93387cc23e66a2a993ab3c8f567c9cc2559ab944f230a2b6a2f47d0abdbf990f1392f36a26f7911588410a719dff2334432b04922e1924abed8885a5ef4a3a9e049c97ae6e34d230adbaf434a6004bdba3db4a6bd4c617d786eeb5e0629e78712b0f839c958dd9ea823660be965c6b7bc10a7fa5dc04f31bc88f46223fad18fc09cd18b5e889337832451a4171b979ff12ea0444998ef67bccb8f482f3632fce8650047e0cbf72ee0cb07eee0a7183e0650aa402dbeaf3526634cac48592c2f56fba25d79d65c8245a14260ec86fe7850b7012d131b70bf1f31d109a0d440766a29419354e28f188f9458f16f0bed6f037de8d5953ab012a808c5668809569ca86e990c2543c9503294f6a22b64133551ddd665c4609c73b240f30769fae91af3266886283373ce39c70bf8a987840192127203c60f128689cd2143eee0c8144c4345e7a84cb3bd8c0178200b143b234d4088f18425cc9546bba7e3eaf63d5bf50dc8f340b16dd53d9de366b58a75cf0dc8f34031ae9331f2c701f246de0887e7755cdd34dab205700956b67a70fdb9d3a4681c5ce7182acc47f86ebbb7043e5066451ec23210827f304d739288fbd2f4da4cb60a010f9c59955158bf75369bcd4a386a6c6a7b3ee0669e3c7bc6672882952fbeb681de337366d4629dacaaaaca65bcc2ea936aa44875d59eca9acdcc524ad7bb58ba4206b7608204ec94f36385253b7dffa3a508d7a90ba7e0aa629a15d3f068095724565c7f1a46ac58955c7f8fe723c2ca97cbc31e3f1a94b0defb007def49972b7485ae303564479d02099575fd4d9508c35415c7f8fb083d28641a661a174161e57bccdc1dc182eefc5e76083de879f0fefbd16b94a88d22286c836255d2a2bf4d3925d80357afd65ac11e82a017879b99b99b6a929341d0db83f6cdddddac854421c0fecaea09b2bb3b6ba129d65b591eb6a42bc4a7461df1fe03736a4769d2885362eb0adc99a982179a68e11a4f7ceac0235e71a4492e61187f9974a9aaaabe5c66565555555555555555516aa393cd5062eceeeeeeeed6f89b58e107a8536c14628930c1211858d0dbcf612134b9623ce5fc5881bdd7e81c7c7f4e3188abf56f93f492c3143bf6583640840cecce2311f1ea71fa00baa28b2802907f38a658973bc198115eb8fee5e072ebd7e47ae86dec5b30476af1841e273be37802fdcafb57635f23d9db24d6a20848ee46e26b493d4a18d44702033b03c2bb01283361cc4c99b97182157bdcb6d0460947e720293839729c1c512c2547ac82a8e48e4c713299176b99ccca703c742c2cd3f8f4004e8f3aa43be372de6b37a42947ee69a0426a82650f6d3cacf2c2c94cb0672f9cf721ef43a00fd07f209f38506c1f4e0621c994370ab115e4389415e528479709e226ef1df40a446f973f0938b39d1ed6670f3be5212705ecc2b287b54acb98a60ad370d30939cae44892a3cf26784029bc4e89b1e29b92a6940c076d6a9694dfbd1ca24dede27ed324101c348c1ca261bc03454985acc17599c4f5e7da88ebae2a71a049204cb3bd8c42d6402661c428a1f0d6624c09639b9aa6699a8d871330409bb86bdc03304cb3b111b817390b1a5101e3c8710d23a76a46cf8a56b5f95a47032b8eae7f7f5add3628e69cf5980e12616549ca4d1bd5c0e66c369b513aa56bdba9b5568ed5e7176ddc7e1a2014d45bc11078c8347c2587ce128707d3c80bfad58e0ef49fa67d0fea3ad07fdd7b3c80fe034b2e60f0f1bdb7f2a1d7b4eaf2848f2336a15f791f1ece4bf7f7d2200f3cac84409046c312b603bd9f76d48034baf1e7750ffa1c30c7035d442f6cdb01345260020e6ffa060bbc600710217ba53886022c2b712dc9706432994c86c3712b51586245a68a8c47c8d76b072baca7dfe1322f9d16e395e08b7cbef385f8a10b560c7b8734596b297592cbf526055d602d8bc5816dd1c76d5bc48ae10da5290786f187b2e347cef9e3bd58dddddddddd1a7b5d8963dc9320b650ec77c55207c57a572c953a87a39690da154ba551693492a65269541a953a28d6eb4ab26989c545370fdac443c2748eaac48b0a2f287891058d2456641f70fc72a84f3f1de697c3b6b5ab3492168a5de176668b039bf5846b48eba458012feb3ad0c7f7476c3e90c197e9e3653e9f3a1a9858ffce8ea4cdc20633f3a862c16ed788d1bf09863bd6a5f88ffb78e83eac924fc9673e33b39dfea261fcfb5be7755ee7e7013257ecd8f6bd063e17ae30852f2440ab44f791b9a2ab1e7045dfe19058d9627948c308cb2c27e22a1f1f1f1f1f1ff7711f4a6d4891125aef689675234ddc7332c90bdd3a311cfaded8a0092638874ddff0da840a7ce246e65070a64acfbc9182cc27e8262716ab321addc4b46dfb949873f2e439e79c737a366a74873d86f4a9128bb2a3720c6c62e53fc7bc5eafd78e275c2e53b581654c8561fc64fa77b519b6b05f415ec781c03ae76c1b7c474cc704c3f7d0e50b567ee7c0ea70b95c2e970e4aeb1394520aaba1d2b44d6a018ef1f7c14d1501579ab6efda4198ca6d928d4d0678e81bfe1b49233961abc84710d989059886effb0e1ce3308e03d65ca06fd8d0bef1b0524d2bdda0d6ca951bd6b18e553b44126fc4f51ddf683d0449221c7e2ccb1c33478d7eece29a63099f1d2178bda28462b59b03e9a43ca5e372d2446b088b476584fbf9f9690ee4714c41946a744a3baf683d10685d292edab4c30b870215ae37ca9398be8567e1499c0aeb38a85e83ebaf5d61454fc16029580af6ad48b1e00fc8c30e8aedeed63fb27fec0f140bbaa2ad3d52a0fee43df7d607568914de37cc0391c026e714c7b1384f718caf9048adb8221e4ed95cf4aa6157a86c20e7ac54ba87e826ae607d0304a5e01c70e863150ce33f04ac75450f58a9fe7151e9d98fa760ab15acbbbb57a9558a4ba552a91df8467f123ce5291c351c637323831593b55ab162517660465e4f5a3c158562d91512984a07ba4e225defe2fa92eb9d27a58c59e9ee4ce34b347163b8ac8512ad4b3f20fa5623ddd717a7914bf295af6444f9bada532b5c7f2986bb46a3781595693a762cbc07bee21831d8e453ace46bc54dae285f2bf95ac9d7eab5922ff95ac917378bccd554ada68a065484693628388764b24295a039c6ef064a9ed56baa54413c0832e64260182f5e1edb9cc0e4ab5153c5327649596513922402c748270ee3bc85273df5b56af1fe0b710faa3e05c738e854348c7fa0e85c5c7f0f149b0572c370a0e85b340c2849c334283a0fdab7a002e63275c534dd73a01b218b24207f5fc95713962fa6e1a0742191c079b5d65a3f0f9c71988ee11bfd376a709027c31352c662b5645294c47660515cee84a65229562ae52c16d3905a002f4bbf45f9e4fab33c6c79d87ec475e2933e85c19a34119dd5800684218924830c2c2e1343abc2ca9f48b0288be52c96a649901315a534caf86476840f95580c0683c118c635d2d4fd5fea1fd9339773f68c695cab2995c23006a3c104eb75a100ae07be50d0f75ee841341861c546813c1fdc7befa37bd088abb31aefb9f701faee6342b0f48680e831ee4b9022bce7be08d0772fc4f51c071cc3c2728e7020112f35dd5f804f1df8e5d0af69df0d25d0c097991a5e72a0e2cbe6328515676ca0c252c043972aacc8aff9e9606f835270df2869b2a222b1a8158c4a4d0b6d947c73fb82f6b17b44b1941cb10aa2da49496696b254b2121c8114c0915c9f0234763e722b608f122c7dad6218e92cf447a91ab97188d82ad625aed1d5ae518ee338fae823a5212d1c368e23eb937294b526b19386173616a341c48aeca2410496b5d6da0edc073dfa4ec3a0513b49ac5fb1562c7058859dcee1afd1b7f01d18a094b8cb437f6f314d7771794a8c0a1c240a2bfe0522040926c6518bc562b1586cdb3e2ade88840ee69c7394b2f267a9d65a6b85511a6cdbc61bd76aed68c4b6246bb576349261e871746adbb66ddbf64d60bd84c3a07e7ad997b5f6e572d2398cd008b8b3c72f9670fd6b04b1628ffd55607b50cc61db8090638cb1c9a003db9f433f10728c31a64b5932bd2c2c10d26bb05d1c9345dff0b79e85f5cb333995ed970b4c59970b4c76066b2da53c76e0ece0d14ce03009ad262499210a2bfdc331eebed2beab2e97cbe572b96a0d39c6c56264345d78508494ac9e73cab64cf30dd1a6b053a206334918c169bf7de55eba7b0725a4d324edfad73f728cff04c230cc800d06d75f93c1047bfc306261457e694e58314442b550c21da3fc5ae7f49e98218e391acdf9df7279083db0e28ae17c71e4ee4d50a9ab80cbaf99948a85bd21f4c51c51ea9a0b344dd364386de29ee7f34fa93d3f0b81c9cbe7f423e485cf890bfb86bf0c0654775a9a0d8648c2ad9f6ea00d35e4b421e461406986366861e89a0c67db4036d05ad358638fc5ae7c2c76f43e3e432c7b48a5f4402bf60b5970a5863e10e775dad4b8bad53ac339f7858e8eead553c4e52d77e22bdf9931f7c9e33293089b5a8700d7df554ce357c63b274df64587d1a0c28aae13facb2eaacb50a699b22575244a0a6153cb078d04c380c050b6c9681e92249d837bef76fffcb5a3d572994f6b47abf59ab5c637411554bf1aad1608342b28b45102b9cb16bc6913d464f496d3371c023e30d23afdf07666a7ae93d137ea26b51a7434806fbce66888c6d1c98139559b54677c05418d3a3339335f135e33a3191d978e8e8e8e8e4e8dcc93f2ffebd7afd555841498b0a95500609af6de821558e50425d07859b15dcde3aa6258da4bbade76e530720414a0508da7feee9fbd916c38a6c64350b4a06c5718566cd503c18aed5251c0c3510f8ef177cd5c3eee72b98b028d637bed29f8737e3e33357da8cc586c4ad122d31fa4053327d1a3eaa9e5f9991f80aa27d18bdc1589fa7b5e791d4e830afb329faf769a3e3486478931c72933442d2d2f12b55811c9cef8185e943f35325e87c7a0b049fec8dbf2f2478c1faf63a377f99834b98c4a2ea492e85b5e9425ede98f07913f31d0ad21c00d3d2af46a446143ef695cb062c76231f9c3f2f67fa68c22653226757cfa0649362161a18fa7482c6154521cc6bf3562ad5432406fa9b10473c728188bc5c299b2ce82c5c62ed7eba78a131f1e1915d893e972b19cbd8df64cd65a0150afb02f3bf8a9e7edd7130b4a62e9e778ffe4e9974b1cf5cbc562695f353027477bef2b98537fe33ee783e11f0eccd940ff32419b8fbe8fe7fec5c67b1f9587dcbe971db4dfde4603e76bcf270ada54f0067c9960cd69eeb4abd52c579425ede258bb38d62e8eb58b631c6b17c75c1c3332d359348c7f17302e9a6ce18a6d00ca288cd194d18d6bb2d060cea94d6dd643f6e8a17953aea1693dfc9b2013baa78734795f396f7605fb89c350c07b7c13ecd8f53138c6ff658c9bf3a20f35c6e8e798264c2ae8f9cb53430d38703ccf66cfdc0d4f9a617e369bcdb6ad34da18a8b657cfd66a6d206f03792330ece5d3886f9de252ba09d7bf91f413b197741324987a4818d8900b6040032c532a75c9927a48538d8419d239980e81d5004b804bd3488ee6aa860a27c45aadd3adadd699d010b899678ca5bcb8675afbb57e53fa4cf3b9e8c0b287b7bf1b660d13895aad9da174d5755dd76a750e6460f7ce816a6534912c79691ed8ad195d8189bb89d40b266559135a2a9f222b554b65237beac669df01fe0007543d5a35fba902a98fc044e0d0f6105d9715d184b1a5ea3a15f75dabd59ab1999921f96db53c2fb451c251637313c4689b9b3948376b5ead6fc009c3d22bfe126c0f4bb84c831081dc9e2bcfea8bec73e3a107403058917d4413338f1e48600296916f5d70fdf3e1d90d0d7a3ac56efe36ee15146be07a6afd826cdbb681402216bb12fa40228fa5b3dc4a0d7d54d3346ddbb66d037d9625b4c20256cbad84be0ee46d9bd771356439c161ccb0d878c4939e9f202d6b2923d1ed92d87abb24768eba2476e4a387fe4305c463c58685ba4ad7c934130e5552878763b8ea412a18561c09c089ed7fd1a18ddcee1b49c10a366c94a6aebed8bc67bab9f4a582363f9a1246aca3c1081721d896151b562a51d8f852c31246f6c460ad82e5400a969955b0a947bb8ab83d706db3cd25af381a81110557e708a5a9abe09a15a18511d63ec2465bedd980c49088f580cd601b0c06b37198a60283e1a8117501d3509a864ab57886b08e5829d1d15028ed09b11a56a56106564a6dc60cd804d130c47ad81c48c52e20d4a4848dda3698f7844c715c5754adda0c2ce781225c6f2de8a80247e17ec181a4d62899ca63e9152b2af460b3fe8b1ce143e4ec2ae75447b35c34daf6038b6528160ac51282041344505c2c168bc5623729ce2d9526a289182580c39134351305d0a1936f7eaac05f7d05418d3a23e76c1a680bd8cb07f0e33e5ec563b399599624ab540a435913aad4101c1e33b8420aa8d38f298428a7232f3a740fae33abd5dad1c86b50bba669db65e7256150723d8c22bae8557cbabb3f3d42830e9bf564fb555f355eff9476b7bf49e7eb8ad7742758b00e7b85a26f996911bd7cc5341bd3d02b7a57182d87c2f22e5e1c9fba24f67b1dee45bcfe1436318df73c3b5e8d5c77306c42dff22ca496b724d13749868ccf01fd8c0fbd88b4f220d207e67c2ffa1cd0b71cb111bd8cf7d102ce781f22d0876d7087d0b7fc4de85bc09c2336325ef4392c3f03bc59791198635f460b89e54524fb73b290f83449dd8b3caea8bd0fa3db4998d10d1de83f1c159702865771186fc2add611fd0ae23e6da45ff7670ac3f8bbcecfebe7355ffef297bf5e2f4a619dbb38d15ad358e3e6315f5b2101d1b70438b4461a898063fc7de0186718ff2a5be0c1857dd19e6f09da6df01d2e235fbb3c62d7885d231d34287169db569dd8b68d37d6d1d9b0e083c372c79126eebad23182c5e101019a3044804d38339d23878930298e157c28ce26936dda56ab27f3dcc7758a389594942e9b996bb52ad5ab54b2566bb5eb54ba4a9afce42ad548baaa8e8690a1320abfbeccff022e13c40557ecd4a80512d515bb894de4281ca5e7f3930d1031ab0047b9f3c9ede7516b10ef4917061e848007490bd5e3aeb7bbcc640b516eb77f9352cd063318e18b91e3d8fac6711cc78dd2b46975d3ea07e27134053b63c269391648b6eeebcc04b94edb368eab756686eb487cbbd5753536375cf0388ee338862c47ecfc9186a156ad473dd28bd78139317401060f4e393fbe24a723f47ff40f923875dfbdf47b1ffa482ffd20b05bd50097ca94202b021359ebf3beeb041d232684cc9692d075d09282f3465b5f0c2bc060b7baeb5958b1a90ed977a3608f1d845220429060626cb55aad568be588bd92e79c94523ac1be9225537a75b80f0971ccd1684ed115ec775166bb5361a43f2158ff2aa511b3d9b8da09a2d2318262aac39fd020866d596c8918aa7e384cb1f28a55d37a36c36d7626ae5b212e45d899f67db9569487de1c116c8361d858adf2ab42c7cc35a3b3d96c369b699a3785d6fec31a0fd8a8e1ea2971bfe64282b1251afe5326d8fffbb55afbbf6d4e34959479aa092925ca9c5276777f1886f839e5fc98a1c4ec14fa1f9c173af6a52c0c36f528933e4c334720a314639453aeff94b210cf9c734e1114566c253bdf0e7d0abd46aa170c825ed10442dceebdf73ee47954649f293b1db8a78f4347677f3754903ddc260f13366945c85432954c25234919c704e118bf230f1ddcb1752453c9502e336532994ccaa48c521baa101566e6f97acd58c591a639271039ba48008462a76d28dc0588331ab94cd7754d0242ad10002c7c0d52781d417bdaae57932d3a47659acd077c75bb374fdfa82feff55ce7813ccff32a28b4d1d203d555c0652db450e57a2b9452daff9765e877f7d73c48e2ce27acbf46a2b4524d2b694a24a574d229c7719423cb15e5a85d51b21cb1e28f9e102bf68b254b96a2ab821b720c33b934338a5b02bfe24b77d0093b8ee3467f0325d0af51272f0d3e3703db301211ecf793d2eec8d6db4637ca1a1de0824eeeb4bb9bfea6c3f348d20abbc35d94d00ed4d11be86803450f78a0f73c1f40d77b1d1e690711ebbdc82e1bc01d38a858fade83409482a8b7c47a339ebd1e0741c3191b58fa6209071c331dd75f6d14b62389f5fa50e36a4fa5699e4a330c050c0683c16a361b25263caec1cd5c7b7e9cf8548945a9d5ebea0652a954dae488a86cf7ebadf5946cd2d4e329b1f28acf63b52bfef5ba4f88edeaa655971efbc2bd1097a3a105db2abe53f5e2513529b26a7d31b0948617581f47fa7d74efbd8f9707da8040ae46ecd82caa28d2b19b580f7f504f471949f97e19f1d281deca75001af66262d943ee786c93b4ef6feb1cfcc8a5dfa3722c2d4a6538ac97794a29a5da87615d00b022c452f0653e0b71bbd520cf65b48edb36baa2a0495ff30f87bebda2a4ed7a3f60130e2887f7aec97432dcff0c21081d8676fbab8f53a7a0a26f386b27d55af56a4541d106e0a35960c20bb60409cfc85a511e826046ca04a081384cacd8abd65e003f92c1b2700e467abb4e8ef19c458939e7a4829d1e7ee1c4b6cdd9715b2761484ab05c00f017b06d9536cbb65adb9b42a552ad60fec4c8ab88ab87a544a51a8d46230e65a92459a552188e46fc725273c3329834f95879d0b6f9b0ef3912b7c2bef73cac3c2805969910197299896aa70897993c3185eb29573292a61a2961ae699ad63f05abc4271a66e02a8e718d44a43ead907a95d349f002aa75fa315b4a749195ab52aaed4557a9422f690a7244abbff2dbb63dfd2ca001b9f31bec41fbf99ed7a058128d443fdfba4cd7812f3bd8173d0f2bcf028a56de87e86d079244dc8f6ef7deacd665e66b2ba4976949deaf3c0fa067017dd807fd0ae8c3c7ca7bcf27fe74a0afad9034ed7b04a3db81228fcb813e8c6ec3be9df4388ccb4d6e727b52c3c3fb95d0adedf3335bad34a67195f3381157f5ca55bd72550d35e0c06163a55ab9cb086aa55aa95e2a954ae594da50712e0315b8d979641e7329fef21ead824fac8fcbd09722f4a28c22633b5ab7c33457700ea984964e4bc75b5d41d933f668d1df0183892540d6006d8709f4df7b9236f5f03a4792040ad71fe481a27331db62e65968ee45928a846936ff828b2d3c0b6fe9788b894ec78a2988709cb7bcd571a18d128e9f6f8ac7de0aa594524a295da976f480d087422f0ac0d42d8771d7102e9f28a5945a92e85948f657487d0a919eb8fe4e5c06f837164d84437f569f4224543d8942274bb2608e039c70c13aadbc10276f85c4e30709b342e2615f447a11813f802ffd166c70073f853e04f62861502e43b94c119c63fa4801430ade5728740ea6f95e7419cf2079ac7c917d388ee338707379a8846392f40d241cd3e2987602dff07f3510f8868bdd9a7139c61b089b7634bfa783d7921a74d139ba7796b72f826edf986003692101a2eba8648eb87456b2110100000001131500001808060583e190583c2e9c27d51e14000c61804084643c1a09a4410cc350c820638c610600620000000c0c91a8005bc4b75540a5a7c72b1deac50145f8dc4928dd364c074088a269ee6dfe486a1253dfae4a91eb83683c7be2abe30ad51f973c7c268c732e8ff712c14d2b6159b51439e66fbb7210af987b982a00826bcbf7e28eb27efa429df022e047c4271939921063dd42feddf0f2719645a76fc4a962a073a7af70baa8efb54d55a27d93719c641f8c33029f90d5e58d35719c62d7755351f582d2e269d3d628a6a751ed31a34f8240329c070e9648c5802a045db863d9cf40445b0c278df7d0fdf26edd62eb90caf0a8a0a1d69d84882dfb62ffad8faa54d3307de15dd3a4cade71fc11a4c9fe03c21e02fac399b2997cc8a7581f30db8a441934184df0eba87bfd4c734b0a3500e2cabe6d7e2587073cea4c712c021a900e439abe8a36df876321bd5e1dd189f53fdb99d07b13dd5be66c12e3107a6e1fb13d2e9aaaa80a707b64848797408927c17d4278565c732853861a9b5652083c50acb269abb8d77f5325231858e3bc3604e0cc020993c41205628091b626e07eb718fa43c37cb4e2d484f935d82269a29d0c2698a6213032ec325c24380ceeee5160a8f8307a02a297966fc2f63df573a80452eec54da143bfcdeeaee51ec6f06c1c04c9b27c675ce3ce96b1300961209fab8aae6c6968d96a2ef24ed067633fb5349caf52c366b82f5361003c7d5dc4f209b46aec54ceae2bc361ea71d77f6779559c9b30548c205520b84d0c6c00b953d273ccface5a88ff49f5320dc4cf82f7e966b2d97d82ea59e90de3eb2284f69e12fd4aa8b8f3b63a290a242f139a2bb71e7fdaa2dde223820750fbce770f88ce7ffa4963bbdccd1923811cb1a3310872841489428b57cd37e8bca7095840ec583dc08bcfe2a9259390a06bf59c1972f6db1ef75c123888d24db519f82c9223ec9311750ca9039825b68a01cd4888bd54a844d70eb0c32e7366dc4dc32fa794fe4ffcb78259a2e16d2c1397a38ba90c9bf56a2f4060c24048bfb2304d1612f8b233594f77fc494f62a29c14623721828a1e4b5264090272e3efb2145450631bba11192cc5da390cab66c8041590d50a9bb19390378271977000321aa13ec11b9c6b5ef849f56990610c2891094cc57ed207da0b58ff2630cd3030a2343b72fbaf7863d5c02ef0fcce269c574fb398d5f37922212a71037e680942eaeabafaca5f8d22e00672ccf690b3efb177ede1c8e0241ea5f6cce84181921802f9e88ac7db43133771e6ffe87c5078b9880fab08ef7f586d6c305f763c9753bdc537bc200d22a1b3552a06463d1c1ecbc7b1418fef7470020eca9b44e47dd34f56179f4d3979cfc99ae87c3d50a586b4e45b9f38162737f84268c7f031aeef6deac37571ab87ffec269b6622c4b8ebe1bd9bcca9ecfc587f01d74ae4205fa715b832ff7a18ccd52caa79ffe0bf8ba31fa94da79c386099d32273c4b492d095d0dfad08c5dda8ec265996925e12f3dc56165fde30179e24c75ebb34ad4d869ea5e7d04d122e6278686dd34d01192f098e5f11178f25da24ebc534943b0c54da911116a0225c41a7bc2b1ddc80969369c512d042a0983f92fc084a8ba29eeb386d4fb08afa396330a5009b14ab80775aea993744276dcfe0824b6c90a3c105ed2385304f95525c3c7316f5e508b3e4d48265a737cc2b2427e2d809572cf6190871215ddb9b526e68599f27ca8c7e9acf43f30f9180aee798c64a33295cd17b24a643b62ea6ae59d78f71369b67de7a77c0fe88eeba008439a19e32ef7b88b2095c2187ed8a5bba01de81222a89bf6167a78184d1e358988615b41bf88485c56ab78871c2f25a76443eb9efef0bcbaf66041011f07b8b71797d5d82c0d326c4edb90a633f4dae21cfe522bce3b749ae2a19ea31fe08ea8cce9ca9d4c17157ee00b22931e61f68d277b4ef9a623f4cd7ec43c2958fa53a43b50fd4a3fc47bfe7a05a39e5be281b6f58110248ac2606f7c1e7848cb2b5a0e3ed9875d048c9e8e69af173ea71ff6910b7d4dcf9fadbf1661c5db3115cb9cb1aed85079706255abdc40c69d0d2810a2a1ab821f4dc5d2a141f3c4a74ffb7dc1fa3337a8e53db2777235f1bd902d7165f482f30ef08313bc4d8e827f8abf1df92fb57482ad4f85ccb67ff6254990853988f8e34c1ff7c7c2cc1a8553ceb6f714dced694df8c12b789fc51c671a3d56e358cc4ed05c3c08be80b4322d7fbb964c450acd41f24390420649b61876ca9e84b4dae0b44ec88662bcbd6627f1f9cb43fb4406e7a4231e6686635002426c5c5cbdc10157e2e0d03896c2b2a85d91c7ea3a2388270c6de417c82f0296b6ee7ad0a33c5175fe4bcf5c0488d85c42924c9f66caaa4b7cb5c3c486ce6c1e4f736f27c42c10810ea7e52b86ca09826317c1f4e791ffa7f970d753bde5b1d8890e2110aae3e960ae47bb62b05c7dce68304d4478e444d0b0021a16dc5c09e560d108b55f9a83fe4ca4263c25bfd1ba7a8cac88314099149e8b8a3302525ad21e6e171c4857023c0d22425e956613687fb84caf0e1085f04a5dcebd05aa14149bc9000f40ae7d0a979eac196b3ea77cc1e900472d196d9dc10322a43a4b63824b1a73cfcef9544ad41a9f541500cdd601ccdcb55239616fe2cf20805af10064c9a2c103eab785fb5afcaa0288287402fb8881a11ce68d4acd689fc170f0dd4df4605deb214bf82b78db0c5dab8a95077a0c43e074b61820de2d5b9a3d319331124705fb27d4dcb192e0403cc241667f512595d84bd36f1fffa60f0455f9ac022e3402552c38da214794ab8f1f925952569403a2769c7dcc4290de6d76a71702b2d5b8c26662793abadf79337f21efd7293cb1d57f27c43e1643278f7014493a6eadebec9eadca9c8c8337e69fa88b81601253b10fad222b24f717d93155181b51cca11ba3a945fb686b5e81fd95feb5aae1d18036c9d58c781f997df3afd81d4c32b8fd02498cbaaf172d0ee81b76bd4d4e8d6f2edfdabf747de81b5f0a0ee42841b7f50dd2e6ca5f682e69211372f3bd5ed3101ad0c3415cf89f4fa0b43f7049528721df18c30e6bee31e41b7dbd12ab574ed3128f7bf85a1e0603cc1611690fa946e93cd34c0464626e8f1875a506b2264317cb3a1d54fbadbd5b0b2117bb166dacf872c6f910da40765a58474ec680cd3a095990db68c06cce2be4490b31c7c2e5c63a1a61a95f9a026ffed3669fd2ff1cd5b14cd2c97b97c05d12208576bbb3aaab596342dd5653ba3892f73943305d99ed76676ab49765defd56c6444a20d36059d73a3467917a7462baaf8c7f5864bcc84a436553d58061691eb013920b0ff338f4af469f67cd8fc77dc77b15a3cc7abf038185113104ba82059b8b47076ee02b7c3a8a02af80e0917107c765d0a9a602cb280d28b8a1f1e37e678b1d6d1dffd1347b2433322eb500ac5c669a3f595cefd6e21c7fb2cec274ae8e60854636543912d940011857b03cb3c9e40071656d41a7ffa2b2c27ba5e45e73e406acb1722fd0611a45d56117ab5793c0b41d7b8e0cf58a768ba160db3ae9670ad342aac065a4e48b12a8648c3b2b0c52498e3aeff2091cb30f630f9f360f533113f92ddc8d77f4c7184a3950b9960661865dc046af7fd502e451a2c1ef5d02ee69f95a2810789004dd525e386936d41afd48aefc038aad78adb8fd03b3b28580a296c543deb10f79af3a1cb06670df1cd083434d9e1baaa7105aa1b1d3c737064b21ba962fbdea89fbb4af8d4d1ca8045700b6411cda7b616d1b7a5269eea20001de27a1d306c87eeef553e34df3cd071d078ea81ef12f9b34ada1905a9bef9e589e60554abb265bb1315d20c238760207929536f6e2ba2769cba4c786d75f9f3475e1b14ea60bb0ff131d7599c205b8dbfd92acb7325ccc4b069d0563f30ab50c54812c66f0a7b0eb7555c3105677d10c2d6fa795b06c9a2b6e73c23be86dbb3ba01fa702162eaeb905cba71a18041a138899b7efff68b82245aa071c00a3f2af2cf5a4f01fafb2a3b6ae0202394cf177e37d1c739a6998d2d3ec9e60706782ff3ff22d4de1f2133e0b22c6c04eb6085217a07002426f234f7207ca3bb5afcb0cfd66c61c8770aa7ccc0608c53c43e753cb300cbe0d3a1c2319b96fb9c510afea4040e9285c320bab877d9d0af1580c3498e6a16fb58566dbe542cd0fa7d945d8194518520194d2f26278ba18b76b31a4a74088c9c3c35060c85d9007a4707b6ee0bed053c580d2efcf5911213e2300b0b510058f2d040c9ddc2ce13f8e26063b40f862245ad3920a320fa5012ae625435b878fe65e367265e5e35bee89b3f612ba3fa1465a463c141c99e6da0250c96a9c2ff6ea8871bcdb4ae49448a0f033d9ed696bf24981cf9efe568edfda34912c0e3ffa3df8fffda3b699910c4d5c183d98d05bd8129e1f3d1e0fe7fc0d5c813375dcd1b51e0f4f8ef2ce5234a35051cc4c0c93ee922e7645c121ac28e2c7728129633860f383211aeb1c8311f3b9633dc0e506ec87ab243dc6acc4f05ed9f2da9423f54791deb92ee12e698f3857b4b0f7afb5e33307655cee87cf1c5757db9c25cce8c40aa0a45331790844606dc4d40a696465c4bf79c7d10dcab3f7b8425cf62826480cf5e108686b6f85d1f626e12a8107026d1d48d56b2407b22b34d4807efe83e83782bc1468dd24ca44f1aaa2856140929b19a24885d06161de4802df2f01c2f932fe726068cbf3dad0baf78b193bd59c0923acc2590b53ae4f915fc0a22d3657d085139dd3d52c45feb687c9a03392cf530bf92095889bc942763396398baf7a754b0e2539a16db4cc63adcf983900d2f5cf077192ea85ce7c3f94b202f32648055b102a69b500501ba4cf025ba411714cfe7fda756d812543b31f7920efd20968bc0911faa7c23a24ad8ee628eeee220337093e246d31362a87d746bdadba15ea2625f769d93753775056fa3cbdd5bc36b1d4198e8984b67a31d8727720d3f1351916ec303c58efe0a0e0bf235296b3c8fda15d69f8270263d26de3ce55556cb61a3c2829c4241695c6874c0e6700334c567df1a25fd379579364e3d563ce9375ea227f13f027e6332152580f80a6dcdce6bc34e17331ad311e9d76f43a1dd64e1bf8402b6066e5f9bc2ff61cc4e27e1469e01f9c3cba70112ee9a4fbaf73a47445e9913963d3c6846c16d3307af07dfb56d9d416324d3e933bc4644b67a61d4a1e4e9dc3d66a002207672bc3b66b8cdcb0e09af3d3b97ca754019f934b61541cbe73d7c109f3f9535cb97a5f75d5c086fc2b4ea0cbcea4bd2284b609d4a5718201e069000ddcec080ca97f8f7fee1dbd005cc8527250d8a4bc1179ac1d74aac425093c162aff0f22605059b7994783f3232f4dd96c5bb1fb3fd522d2da87bc2a28d94e5ae2ddb2a6c6004f2a51dd7c0c3e79640de48147ef7a0f70c3272916d86e3939c8d83e88328bd11127d56b487089a977093b4e2b676cad27f44dc3f4d28139a4d6d81f5a91342974a1ae1b8634396d64c634708e28e48d39df050ec23d228cdb2d45ba753eae3f81b3282838d9c1ebea26a5d07deaf56f2fdef6d014b4d7621d7c2797c1532378df8d1815ef922536e52b1305979a9a64bd3544a486f45c39afe07a8d4201407dc16d2407cc31b247babe960952c56986ee75c5c1ba142facd46615372e9e88a360f0165fbe01e8ea572300c86cbf3e8fd1499d999163cd8f620e21433a520b80fd80e1557214b7a644f09f897091a362adaba63c5071896bebd27e1c9268f425239540699e6807a2c23136c082aafc4c29502628f4bfdf396e852a62522538c0780d812d3fcff8991528c5ecc10800607df981879205463d8e9e2bcd776c3db3ea0bbfae2b431f324fa3d1636b51e554f219273ece699f8f8088bd9757390e4dcf481fd97414486aecc9ced42c6db6c2d68303366e8d51194e7c443f5a8d62783c4b7b21db259b9b52b777db591cca8e2bab424ef7abea063244517d78ac424b1466e8cabacdae2d665388a6f811e69abd342e1e9c55516ffb7cc5924670db1c26c9932a7316a88a4b515fd8e2ffbc378d2465811f892c80d743e5c6206b1c0c5b6cc23f0bc020d695d64582781fec69c308f352e89d3fc132cf19f0951766d7875d656172dfded480a15532c3c5c741836c39f99ab258fc55774a35042a3dc04b5c1d89fda1f0da289f1296ed453795248dd9542bb27281048bcd6aa8f192f41bb39c9ed3fcfcb65a3c28b4f09ea79940efb07de19203573248c986c7746c95a1574a9eec60078c0f6dbe5a4b7611390671d38d5f3181facbe02a09e7a3f2bf1c276aa60be6d1fba3124c272ca8c67701db7168dfe3f3f5f7faca407b43cfdca7d442b390eb595404e51726c8733da3fe70154f7a671bfa23d03c286b8aba37efb31977c4d3a4d6405463e2b504a896cfd76ba0f754f3e801bfe5a18633422fd50ba93c24302eda7f820584210c54ee037d37db88b24cc733511d1711e5530b02101f3fe70cc297d1f2977103e3cc33f7f50c7b830bfd2e485d5645ef17fa1e98d5dd430a7c3fcab0f546238c6c6003c2c48af161ceab17973e96f58e256782d8deee55172021c039455d71af78f6f4a9b93e73d8e665b94e993710bb710854c20aebdd021e6964d1909a875df30fc3755fa9b61e29443157998c09c1fa8546cf1202d8c01520d3e9a63a1c538de76203d87ad2f673fe4d0ad34d90d04fe7d4ccb14759e339d1e886cbe9c59c05f73c478dc5d6d05d822fd26e9b137b42a97756507811d77b89daebf9b18e7c6bcf0e0f08e1c4152bbe7860af7515db364fc86436f315ec87215318ad64aa9751d0ed9286bb5a9f1ba25b42cfdc8d62a58655d82f200e27269f6a43c8eed9a7483e24ab1c62b45ca509e9cb0b0f84819cd8c7556ed2b8ec83faaac3949d56c3a2a197c9f53970f2c6c37af0272c8839b2017316b4d38ace2151e9f3f47893dee1c6d61c31d24449c1bbe9a5d667f0f70ac9159b9171bf2e221524b470c24ea40bc16341e0fc172b6d3172488ff911e9b5875a0b2626029b8419d76aca1031f60e323054b5eb0e0c350642731f88030ad1faf64a6a4076f1f40e9ced772881da70437f16168fa5c3fe4c36cb3245a04e56b0d195c6b8760308052cf8931f62fe34ff28210bb876abad9210731bcb1e40f6e126a82ef504461f14788de7870662695b53b2b0f75b58e7c20f6ffdc1fe66e78fcbf6390f5c76d10b89b7fff00d43cc1e0ca9167c82522cb7a5e1c3b0b052235d5e96fc6c87f58310fd0873bd2e551b8a5e198cb2a27600f5057b94a474fda69a6dd8f10837b6ba578f561e94f135aa25d0b508a58bf7afd30cfdbdfa5544192f6c7adc0055db1bbc95499e227fd40b1ce63c443fa438ea2b72d7ba454c6f6120de5f48a79049f4a4426c5253981a4e0d382a4a965d3d0fb769ef5a5d6d3d6bdd28577a3499ae518c3f3dcfafb4ae3b2011dfda41d042bdc10b643f1b231d11659e6d8cc8ac395bcd948932e81da32772c416ad932f0db8c4ee1aec87cb988c880a31167c56777e7851648a451d7690089a01ae253995c2511792f4adf9ed67b40e60bc179c7b8f2bd51afc0c80f7631628cd6a126fa6c5d1c66d568db8d32f7f6e39da066f5c62b9c49389d1c9ce6a70c6a41293dafeb7d726cf24bf0d9240b0231d628690802d50238fb5d01a1958150c601a9821fcce1c9aa2593fc3f5ec53ec007c1cf1c7bf2fee13bf71a34e04a4ded34dee000cdcc9f7b51166e4a9a640c97ebd2d4b287525fc226a5e1959851825639227f7948b6e1cf3cdbea9398373f86c8cae16429426c462331cbbef3a338a57375479af28b6078e1aea62909b4dc30fc2bbc50843dec6f7f28942283bce03c0ea1e7992ee34982e713d0c6b11ffd5e5ca23296f27e97ad7714c8fa414dd3bae9c205fab2d077e6349da1e40f620ac725f145565b231df862fc9405c58b2d507a2b699935287b860ec7da0150b3bb93092925c232729ccc1251a0737b6a272b82a21a65cdee1f15974490e8eb826a6a9b57f0940895824659a0fd44fe73be6101b7ca86aa235dd3984a65b72cdb6d801499f1f4e14fbeb22827f4eaaa5327e2af6d472faf5ebd9c9d672d221c251d89fe619951cded6cec9788680e5ea9b617f5e667670adc80ebc230f4bb9b1aa1e26a73fa787c3699b244dffc88053cae09c51622d0954d96ca725a7f1f196d7e7c5af4da93afb134c6336dc4d471fe287701d580986d5e2f9e7ab6413380dba9aaa6b469e4f86bc82affec94353ef1344244873851ef8ff96aa537a6cda05c3f9dc0faadd387c0dfe1c07fc775a0f32dde5c4bdbec0c6e454a172de29f596ca138aa27f77549b24a193707289be392fb54524394f158abfccbf0920ae379963689ef1a3819932ece9c585de74d697bf0b5757cce238c27f5aa7c015500fc27b751339eac4655158f8029a87ee2dd524fb7cf48371d437d7507a664e835ea064c0183bf90ed0d504f11952aeb149d4405f6bb08594b491c4b891adc52251c800a6631b2f458bd3e2fffb06ad5b7ab5739deeaf65f9ca59d8fe8a1d5ce5c62a378036d148ccea23351231951cbb37e52f153997274782f33a1bff0120698706e508348484cd6ade31e378ee644040cf4b1e94a062cd992696a782938ac494395e597356e521cdee2aefe7b2915e2168411d38dd3ac38c72f4aec8651b5faa50c5d0ea5417b75fc5a042a38c5b3306c7ca817f50fadf12602d0cc1b904e747fe73ee15ca4f31d0ab20911ee0fbd66c972844050aadb1ed586fb23b6beeaeb80353f31dbe00c9f654189568ab15beb542b692d4c60d17a8c01b1a4df9440e41abcd118d3c27b627b78192eb976effc09f3f911fd4d55c4e0296fdd250d4dde80ded3991d61704414efc5de9a403852b6c4c42c6f015c8e75a6fdf09bc45070e70d189d42eda5b20aa431a3dd036e894e60523c20091c0696aa367fde0fe6e8011381c49b84a0a050c3c200f997b00248f1ee8dbb7c26d7c0a0928128f3aa103d40d548bb5bddd4b873a1a799e942d4e4d4fe9080804574149f75ec757915984aa798b75522da221fff0e37269123ced35d12b78ca6782db74e630458df7f4942fa7b910ebacb38ab4f45b572cb43322d9305d409c737b6929d0cd6fc84469134c3f432dc1f420e092a2b1e613a948f502a5165f781d7cb447d97c82a9ef0a94e57d827e051ead65655265a167b8eb4ba198fa2372913af11f12b88db454dee48893c4be33b40347ad01a57e2b2345dd483e1871a34e6c57d36af4b4dd15651891bfb71450902334c1fcf33e97c749e07cde87cd8adfe233f02b5ca7cf9746660fce1b5c0f09653979fec34b3bdbb86e56df7663cceb82c65b75bc31233df99d32ab520f4ac9154a587ea42f7fadc824479061fc095476e384c73722962c88c394968af26b1189abf3724bc4bfa296f4245741f68ecb71ec5325171fcaf44cb1fff56ba063234ad465741a2a11e6e5ea1818898bdb7d37517f6f16da61623641a4e26bd1d5588ab6a9c6129d5ca3a4259b943d295427dfa0b9baf551f6a42618c906118511675b49378daedf12abd77de1975a091e6a8ce98a170a3205b749710175d879859b457ec988bd89f2100eed0a9c02e95a0ce7bea68d5a18dc223b08d0fcbdc4eea3438e9cb310f72464992be3f5fd45ec6b3cbcc3a282cb0455f91d6e350169ea9045aae6e0b8c5dc190511845507f105caecd0092e6430c512dcdad69d622a6af8373511dc027a65af7e8f3d3f52f6ed97416f8717938837aad82dc000b797f739bdbfefc1e0c740a49b2e53df5339af86aba1bf116d34094ee24db37a0cb16eb06f6edbd451c7a5122d1688702a56c18352d5ea017838d9e8df9f33d8e51e9c80e7cd84253991de7f31b5990e44c210199b5066ec89b61d12af912333a253f76615b7eb899b29c8df7b591740f7c9162b20038a6342796fe99a66ec397519e602f352dad809548bb3a70403101c069c3cce76b40a202af446ef9145de16e0d33c646e9e36258f9a4ffdde85c3155603e59c6a07296a3b93e0003e552f96a6734f6e42742cf55cc1d425ca2de539ec2c4c9c7e123a77e40791534e0697e3d4482716dbb5963a051ee7e6e381d443ef62e132092387350e3cff79c22e028cd4dbd70b150cceaa2cf7449caa20c679576d15135eb22bed8a36f893c6c1848d96b89fada8850c29640b639fe6368975bfcf863c5d27b59422b181ab0ac18e04c57a1bdb2a98a9653d16f6e651853137c7a1b546088cf06530e1f0e17c0fa75bcb8f2f4ab6c29fc3dd81e5dea0a4492573e6c0a29f8c090ee7cb10eee41c28c7f79dfac954d95b8e7ba9302d7fa57f2698b0a6c496c77b483767e423778200c2fbb5615ea53b751e20daaf9964bd37bc787f61374cc20dd36482840401de24097d9610e2cebc2273eb99c866134a25ad804b24152d751a8596914c2c01c5dd76bd388121d2171205614445f8166625ff79ed11b425bb4f50de399f3fbc3011c78da96439c0a85db5ead0dbc568fad5763c127c3be6b2a8c2f0ca463acb8969fe8480f289acac064b8ce5c024abe6abe476391f258a051486d35ca14ed4988a94ad0285dfb60772d62a2611a811fd30002cc86a296752d1dbb7bb4c6a88cdd9a5c90e99d02d6cbfc97c64dbcba749028e38fa7fc33030f7f6e21ae7e680600cf4b2a765fcc4b740ab6229776e1561eaf196adb281bedc3f8d10efd1df336468af4f04438d94987b88993cbdf7f143143dc6636a7efdcc838e65213a1dd11adaaa4fe2810ea161a1d2cc154c3c5c28d8898a7b8b70344edcb82ba762bc9c8b35cde31d785c59a2122860b117b3078339018d3c176b6f07c8a5b2b41fbda86c63a48f74cafc3d0d99819debd46a724e17656abfb21d20355cd0572a5f85612ec6f2b58486c5ba80811a90b9c69ccc90cd754844a53e49a3f507ccd51bd2d8952de78ca474df3543913422312024012c670e880450cb97a18033a464d5356d57d2f51f2bfcda01e5368d8db7c89916c773d4341f75c51a447d420089b5e6d23bd5eff3f439e7471418c0d8b68deedaded2d4ba2dda0d0c995856196d7766ac0a1473f5cfd9ef411ae7ddffe3fb2e76633c5d17d9eef36a420a236e6ab7159dc573b5156b91d4ac6687978703fe02861ab9b808f7aac5c5bbdb137e334e4a046f370c4ff51088ace0bac5c232a250bdd29ac26e8d7db9fa65f93a12203996726986cd1c0a1458aa42b16e43ac1321a4a31a3964e5e0486aace2bdf936f2bda43402b080b083eb1200b0894a64820c37b312138815e59abd319d121456276f22973290f406c61c489fa920d75dc084cfd5c1aaf7660f238f0329f8132369431b5e48eb67c612a3e336cec069afd52994048045ac69c7065c410d6278171e99e096a04e2bd23213532b970656c5a06b75906b73b52f51c277d5d63e70c7a2e8ecaf58c89ddaeaad68e40855ddf76e04d3f1edbc88e4093d84b3cd0fe67e88b983fe444bbcd88ccef64c2930e1b7aaa5be2cc90122816d0cbf48f0fae630ff71d621fda69d62042e006ad96a3bbd0588a19e65d1c8712ac8b587909209bbf5f009fbcd2e0935628a4e999635aa1deac96b4abf7272905cca58102d8aa9a8f80943d735ac52faf6b816aa35e868306b9d1fa2b56249fd644a23f49c73f10cd6f089bffaa859ebd3a1694b8b21cb5b0ae9f9adc17c23db222d00e04afeb2b980db309fa90700bea810a590d23f809b03eff7d30962bda5fc942057595f79e2879df7eba0df55ca77453e84a7115b1dc9427e9c6dcf20c99dec66e6cc34962dfb81a60498a40b84aa7b3cc04b973cd63b323ed1a16121d826c572db5bf4e7cd8a8dc5748741eda69685280d8c3c416cc87a983181a29a292b201e32f40ac3aa6d035c82543e2955ba01d0f1cd355b3035a18b72bcaa9a3ef6544de4a3729542ab11aa9590ff1d2f1895159cd3d46c008c608b0c940abc6f6492ae342c7e8c19072e896e93516d749b646de09cc355385753472a71310e4e5627d4bcd9455855c3ce353cc0efeefc5f318af3f731d0d26f7dfa9f308f0fa942c003c2fa7217dde59b746926d44e33031d1ecff9574d0b9e7f2e13537b0d167e903fd5dbe050e1da40618e7382a709666bff057b39b5373a96c1d6aff5a10546234cf6eb08289cbe8606cf75eb41eeca09184bbbbe27c334ee08f0401505812346546cb03b08fb6affb5378624228be5211f1904987d4c6376b8191e58634fe8294ae97ac9091dbc67018bbe695492668c02dfc01819d98a25e3b26be8c11891250211e19d80764f69c64d241c49a7f5b5700efb0e0218dbeae2ab0d41c6959ec1f7eddafb5c19221e0e57944a892b6580b8de6eda32c49fae0e944e8d7adf8bd841afa058aa9c69b1a44988ca0aa1f2e2a4804334c581c96274917e99f3098ec0cc8ec29ab4709aac9ea68a7e9a5cace3f1725010ff310979cb3cbfd06e3de92119c9f3831fae082e3879909c50c02c71dfb2e83233e1b6f43c0cadb38f62cee202963846ceaf67fb202cb1e9674b19abb2ee12a57e757bd8707f150350b4a52988de0ff06ecbd83561cac68454511ee69cad9b752aaa851cd63787db35e6ea54122436a4c3564c2058640dafdb67a0202c522dc68d26233e1f0702e8150cf955c7fc1557cc1e90fe3bc52a5750d85ca24f9f83a0576994a75a300aec370eb29877b107c8e656df2e7b990534b0c1292b3c4f5037f08d9a7e265fabb8c0296534b59b1b364f8e6203173d67ac9805d1011661750192f3907cd633db59a5673125d4f7c323590187c9b0e0f043a307e83fb9b22722334912263c16177a9bb3dcdedfed2bcdf53c5d4c32c8522d75f76d74208fac5f80259d1300bb2730c86b93a029db926ea0f0ce83f45347923ba25ff2727ae66971c9c2941ad5dc4025428db6afc1e7b72d7befcc6db16976584a2c66ae1ad676f6245334bf4712074155800dc048cd340c0dfdce0585128d1d53e0fae1d68229c6d70542413b1f4e5a4b9815be942c537ebf901d98158dc970a00ef63e77de541172f7da53678bda02c0aecf2c121a40bb9a91bde2e84442177e397264971689c0240adbdeb4e83aa18eb0b9cf6b3986c8a39865e6949231710c6e720cd05a5d7dcba28e2ed5f934069ee0b70bbdde8c7fce7d2ea26825bd40b5b3a04d3b62c8708898637e613a22e4e351377c95e0851ea25d85b9276850852e80b2c69ace512cd2463493a0eb80b91f2532cbfd3f910c1b2357a468dba2e7dac6414ce295f36b5bce993ea757d450f78950c1040ae921e1838a881fa99ddb27b8de1647364cb323cc77febac0c4d9d400313027c21d205b02820e85a0942e9e4047d65b9597dc26e14b95e3ea1586740e113e218772e28c21cb8042bb68fad17caa1536f8c7f54d816a02ece6e7b0bd09d1c487f32e55d7c200e0d036b473f45ace576a1de4007b639f3fe2d7e8d09e63e6c04a0bb682cb80ca0918b71ff16ae4e94bd4b2aa600975ba444477c55798d321a177506d5861c9617458a73d153b67857c541f84aafe698cced7e09c6600205f03ee14646461c63527d70843c690844eb7178b591122f849cf1a5fec5bc0f07275d5d102a440e5912f2f75b8ac5c11e65328970e9fd410e55cbf4ee0850daa696581b943869be35e431a472951d7c145b5d6df832c61e5f1fb95428764f2f1f1b13582570f19f7f16b1c275a33a04b370ff5e202e7755483fa0db6bc41b142a431a7ce87cd09d41154022c7e36581e3cdcfb81cc9c20aa2f6a6e362c766f4aead5719f2c3fa95ef972bd1fe7a500acce6c360455cc1535692a8d34f030aabd67b52ce855d67e3457b2089e8d12f3468c05403f414f580b41a0e302c1b8894a695b939564858c5c7b7b7425e1f8eab981acd58be6d2094cc98668ceba21168e6b6bc94ff870de594f041490ac3cc09e5fc80c818c95563361e5fc42656ec689cf182e15e4ce3fd8dee70c89afde7c072f5dce544652145e04c2c9f1e31c02299390224b68c4b44c3a1bb5342cb491900d0983b70594c132176b9dcaa69271799715a01ccfd72b9e058d9c991578fa81aa50f541a55db386a327fa6af400548ce9c2fbf495b9ba520b5df6b4fcb5369862a0d4f43464379c3fad7a6802f75782c5bcc9863c5354536f0a4c090951511415cb22d7d20e8152576efd513260582c2a1d8754d61515fd25b0d4e9ed72380b9e2683e62a3a92c5efe570b8995fcc9d620c46f2c1578f3c7bb5ca4805b3fb7984e87ebd06062b5b5a68fa3ab60a0dae27c1b5851e337d0f9e01a1f2d2eee0d74e092ab282bd7ebfe2bdbf0d419a8e61c615fb8a819ec759d4c0d114f17306584c9ef46b16f7761a1f0ad8973714897e3ff8632595af32aa4839d6d7901e103a5f1ea6a5153602d2d416128e927fd978eec93a40d438e5bf6bfd535dd8a13673f5b880a9f5ca5734526a4118b2b53fe96f8779ee452b36d3b98b08cddc18e2ff0fa1366003ea20ad894b4bfc2d6d3c73f7d4ecf32850085c4b6a0d97e17ec7e2fbe12269bb3de3d8c8d0d135de8e9f97a5ba007f91399e1b30457beb9e1ed01d2c9dd9903ca645f022d28b1c29c4c80bf65b404c16531f3ef30cf5297c8cc81e1907bbf29c463fbd4b997fce4a5c21aea9c78e732ec67c3f551734bcd1388ddf7a5a7bb1c10878359805e605fb4fa3bb28aac12ebf267927fa7e776656d325f74ba29da5c2bf3e97413234efabcdb51d309c362bae4cb685612ba04ee50e7e9fac94df9445490117765325d9d9cc2536f9576f79e0b607495e3e5a75285a0adee504b1a78e65edca0862f2852d1fafa4888d098df513802120c26800c93d2d729a0722ac8b1d43bbdc9c61b8b0d61551c6b3ba6d9c76844f1da1399d459cad53f660a5b08f37bd7b5c60f60a85597d7f9bca4a7928ffe83e1faed5b40776eb974403f42477c91c664ab12a5b8625cd0605719f1cc82b9d18a2f100b279901ab9f66eca211f23d9c51155bb0d67bf434fb9a5e52bdb13c148a4b4f5068124bbb1fe18d3efb69612cc1b021d7e7859da69f8af25084406f289bee11e19bce8fcda2beaa94e02b552dc890cbd8068f04d6d759d916c1048bdef77a5fc3f3c1df687a8592b0246f0b476c820d7a01546fe5a2f0fe1d450eb551a492b65eba8840174351856bc4b4b1af8062263f8685cb81ecfcf3adc661ca2f34dc6089d3d173092c634266b9df1a8650e8912545984129363f4db3caebdc130a758209dc38777ad5e759d4039ac2e68a3149b1fedf082deb1b436284a6c557a6ea1b0a3ac7a10206e4d477efeccbfc3004ae888dc3eaff9ee62b8248c68e66b66701c0da40151b2c41fb02b3a19dd0c40b30199bb13db63e566fd6af3e3812f469ed23341e3c0972cc6e1ac0868ce0043cee79f89922b14d4b9d40a7b4c5ce184f5850d4a91de0e6b0497598062604245d60b27a37a27eb37faf6e801a04e89b12b080f74925705cc9107f29085bae3a8c5d368ac4e1a76bffd6169eb1f314100acfc4923303f72a1425e9643ffba82c3da63b90ed822eb405711f21ae1915f8816051ea837bd335bc10c6a3aee24e0fa4c1323cbfee3062e1b00516f60e50ea2758f725fef3a27ad16fbf95d7958cdc20b5e81a44aec8935f4d17116ab8f59a24c74a55746075848b991017651d3d1a6b9e6185e591c0bc206856988f2f522d132cf7428c2b45b678aaa38ca5d2e99a80303b95381b8d51450ee7d40c4f18cf6428a07aebaf22533ff86f8c43c192df3e659320c71826e4060e945c449d008113db777a856e9c89050adc8a96765a74fb13ff8853936d1d60d98d764d2d07c0dab6f795719c8283d048424295effe0711e12214489a970351b55644541beffaefc7da8c1a86fdde7deb735ca5fe3123ee03034be9bccd4ff3df460a9e8f31be0dfb49116a5c3dde10d9c955479994d3fbbdf7051aa94da6ab5c7391dcfd2903cdb350e40a2bde5710bf582eeef32128e3dbedd2b20204bccfdf0b57754169b31d72825dcfe0493f17206e6b06103c3091bcf693e0868183eb34f80f00763e06f04e2e60abf92f5f8103e288ab431266ec594e0d80c68dba450c6ecbdf7a0a84d4dcbb9bc5b21866364e0cbb6426993cfe5dc03a5e61a6d62805d8c2d8cc44f04b4e07fe2b97f0f608bf43d47b1678e0ba9f5095e5340d492a795a0d9de9c398a79a9caf105763ad6f0c56d492989fa088729fc1d62b2a31070f3a3e7c7926761884194ef95076370ec4ed8bb2abe0fffd4d1e8fdc7bbff8a912e552d42e44e91bc82fdf8878098f5eaf1bdd0d8e3f4684e13a778d0c5fc33ed7f048ca2f9a82e9460767949f6c0ee7fef146590ecc664b28e28c21e309a0b004974d44447fd1ff477ed9403e08f27864e4d354aafe3bd8152a89610276fb71342a507220493e94da9266d2e0ee186e0a492695111dd17793594b90709daecf592826fa480300293785fab87ad630c430163dd2871eeb1ca218d6d84d52d58e8ddd4a6d510444b90db32b562d4a5e76a84c281630cd80a3c41468757100ddde4d28bbcf1282038984171203c268c697741218ba0bcabdcd5f82fd377a1eac1e09f9524ff0d72a8d43e5265767cb79ee7b25946abde2ce090bd38f907ab823cbb3ae3255e9c1bd27c8f4173cfcd6ce1136e908828d1199cd6553dcbaa45cdbbddfae2ae13270a5e15b11dcfd28c9f040b76e1d189879138b807a116b00abbd1850f56db94a9b5cdfa1c294ac24811992e510c463a31d8dba010494d8b77700b186677e94fae402bb9f69ce396320c1412f65641314b73280580872468d9671b0c546ddb8b585ff76210e0e028a98132a098d1127b4bfd7b3488a129bf3111144fe1ad63e085f9e63c6b6022b35a557a34cbe8f8d82c58d6f015ad29d46d4eb607fcb4bc102e3cc726d153d3c0657d4171dfc39f3ad31962629769fb432aa010e43a5c30b4e71c0d8ba124355c5b2a111280037569a63eac424322c432758f7a007f0962720ecf5915ccfe1c01eaeaa75969ec2fe588e808da49ce8135f7d4c51d58ccf37a9b8538576afe6218bc020731ffbbbfd76160d546f570d58bb2a9131090dd2c31967d66a471c1ff64f939e38dc7b4df8150bf4be18b58721ad96a177f577c3b5eae7a398e30dc8297b476aca74ca8234b076a5afdf339381200b8279e92e98bdb4cf4c0aa48af634ed738210497e6d000eb99cbf1ae704071a6c431c9abc8997c23749070d53fe4fd53838acb06aaaa79aa46af9c564305718235a758add978bc65d315bc0d01e5a2511b4bb03c3715973a4666b9cea3cd9b783e86ac224443eb948c2baec8c99d18300410cc1713b92202ca86f88a2f877128a81abd3b08057c7c25ea57f2a1f8d9bb974ac05c7ab0aa100df66600ffbd3330ce099be1dcc11f846ba69ec08b0c96b6649ad5fd96e11634260ddfccbffc49665abc458943444d0b339c4c445e16e114a3b6ac5c498107ffca4cf541b30c684729c16adaa0dc2460b8aea248bf7e19843503b9fec3bf7f1c6284944f6fc63016e6890f07fe630427eb0cb471f191e238a43f194941738a0d19930e8da9a553d3c681673a832e013911cf85407f0c8dea55c91b47c01179f94cafa55f19480ca240c7b5b1f372b6e405bae9495d32e36b698dc2ecc60353d114f89ccf724414c2d28fe8cc36308a5e6d4116da7f59aed50d38ba103fad4bbdd6f183ebef044732439fe0963305ea5485022c199eb4241ebc6f89dfce44bcae8f927d67ee80467dd20e4ce5955bd51f62dddcb617d399c43ce46621f6e5dd0a94c8c1ad655b532a43bd8cfbfb783eeba32618e662ab00c0b80952688a45423558401a1bf07c8f67ccba199db609c3c1d31db6879fb919e477ed6e940020665062a84ccada77f96af76587e404ef4bf562ffeafc45a14dc8b18a4129dbdde07655c940c27cdbfac313d04e80b032574a434c66bf19f9017e715220ee28f478f748c72190e61638fd5e763b5fef74318115a0d85c9264f6708e002a50fb158144a4cfc23658848771d8fcebc522942405345dfe00f9b6e8c19f387b13470d6ee6907606300300008382d4686ef3de62517c93837f2f60fa9347d211f5b166fe4d7e531c05c57210b88b29e56c1405cd6c9b153e3f1bb5c5703329037b2b254be23223e68746dab50bc1f25ea87020f2d95c818f21b63f386f41c0fb0dd8254155b81dee18cad39426ca90e4a535cb9e76a27a089b2c3ae6cf104e69ab3a99e937f4ae18940efae603b8817676e4d600c46d4e427dccbfc714dd5589f65b645eb9ff71c70f9c0374304ab21d76e386d628081d98f0b3ba608ede102340af0e9b9ef8226a8a72730635b0921a25b3a0578a813cd9db37dfae130e929edbd48b44d6453c29f2bea4c53dc358e8ec9a1fab04808ac103f8cb8fd59aa9992f8c241449b5efd1852f7bf1c9eaa003074815f9bba43fbef249973c30fcd29e5d0de69a4f6b6ec6cc12950ebc85d7ace1d0ce29d7095a3ca01db64cf02123814f82fc5bcd5dec1eb06582886a34249bfca144872ce269aaf50ea4b7e71ece906d7ebafa2a2bf81646f4b66a203e1c8b44f7dc48f2b90f5e7f728b3ae5fb89b6b4bfe90c0d3fac21ce81545abfc3f0d7bbe37e209b71310c9f53bbf4236ca4acc586a8a70341397f12344cc97bcd25f6c3ceee685eb9a35c0fad93837ca52af8ea92d03221df9eed6ef563b23941f87a4fcdca2dbba87a8c2b9cbd05a106cbbca20e16f93d3c26415e84d970bc54ffe830c866ab4549a12c23ff84645817219f91fdc101048256ece05958c0ef86eb38eca2b55a28e397904a0f8e0b9f94d39d49c689367610fed215e50d17a051fc26f14b07743aba98a218a1434f2ef82cbc168d72bd658550cb8c2acd8f3fb02ef70a9367ab085d91a51e8e5c4f2424ab56f0f25382d4c11903956da35da763f89e4da7bf91a9cdfc7a54ba3cda529b7c04ad2bd23410288075ef88b13a9cc07e5c8ff4cdd79d476666c049753515aea4c54fbd2bbf28020b6935e6b3b93a106d310cf407818ef8aa6b31df4d6d190dc20094924513cf488e1610899310ae60cf9946737833a074822250cde9288cbacaba54b3e124c00da42ec163955197ddb58e9375c0907220c93d4113ee729e8d98f6a34ef8c6713609972666b4f84e10c7f575742e1f6f8d641d99524446eba86e9b3e9ccc180ff0ec3cb40c8f2d8ef8e520e180c289d3c4ef298d6f86e257cfecadd1e4638fd72f611339af20bcc7b98b2d71b55a6c2c468412487946907f476278c10500512a6bd8386e0ef261d9b9d3f4010487bc45823b1f36ea63f71a06bb1a772f14a09d9b8c40d250b6b8ebe87d0c7292b8890da226011b96addfd8a75a04621a851d368a0a1879e22436408d11e66e984338db2662e48130ed18ab9670d824c80b189bbb74fe25b90258a03ac816cd00a59566ed2e7149ddd341bed866deb076fa4d0ddc32c0952815a633eada34deda23925d3949eefd2c296d2b2b801d502933445214d79399fc2df95b7d6a311add180500d0eb98a965cdad919edcfb2b456c832560370607c0ea605330a6a25c63a700760279cc1f650df6bc8b7f85776dc6ecdce55b4bc62eeca940663ec638412300d0fea94ca33064cb8f4e022a5fc8ff9b1a71f15227ebfd770a511be21f2aed815b9d27814f88f35cd51a197ee29273714c2ac5ad8f75a898bb44cd8571aab8f69cb2af4db6676db7b2f530e362b1c3bd0fb67caa48cf5df5607e56f78083e7137aa97bd7da13e3824bd3c5e292c81d26f7d1078a29935e05f7503659aa56271c5262391d6c8e2a08fff86c22f6bab3f3c1efebbfe42cebd00433f555e517ed822fdbd34de4240b79b5c2dff9aac290c3857463180f21591ac197e218244125fde54dfe404420bae25f8d781e28c9ea74a8c2f746d428ceb70243577eb03f8321ff9abd41e8e6e7a8ba6b4a3bdee9168d2ccfa499303d53df271a15245f58e0ba28b94377ad046138e287479d9ff58721587043af7c89b03210cc1e8249f3dc5f45cec07861b08d7f8ae5bc094b0a52c2dff86cb1bcce9644477114ee9b257e4446ec63de1b488b155a8bd9955425f6be3699c5d2be7ee10a4ad426d2a693d7e0ffc0e38d2623cab55f28f05c5557c1da59896b38c07f89f141a4336c304cee5c289e9a05581b0ef813fa1cab7026978b74413d261b75f6114aa1d5124e8cea8cc4dacf091128675bad07d6f2b6b55ba182d57cb5eaecec5a39c6479873e0e37587fccb6d07bb0544437e2aa8f2e89a548e87d3329626438df0f8f8becba8e0c41f45a1e4fb5a5444eadab86d8156b6319654cd1feebb1289a09664828afeb4adf9a5839d01c85a238ee5be9a24569d7146f5c5a9678908c3c4941c72b6666e42a3e6f4db434198645b9686ecafe52a100316169ef4fed55e036ccdc099afcf298d73bea505df608abc60225504566aae2b83d2a221de7657579748efccb0a7c70ba4a6d0837cab4d58e46f9a48a07756b53a1a5ea0f7635516b907bb64881c5731e8fff60097fe4335b275e56df9d80d97a7739606a23efe4fa7fb2dcde63ea992acb3491851c1f94bcb67a42ef5f7844d293388b315223cf205409cb9680103af2b223dcded5b2fadbd0d339c75bf63b19042aa77869f1ce4d54932f4e9b7a864a1ad8fe889077cc0c885ab105d6b4ea87eadc70793f21aea5e5418915951d3e7f59783e9a48007b1dd3ef033c6140a6b41ec4c64f715c6343507d05b88110e024350867ce3f6ed080e90e6d7f9a480556a5a70c5d17ae4ffef9011f769c763cb0941087965d3ce4b4cecfa81dc37f6359e4dd370bbebdb1cc895dd53a3b36fec10320f4b16bb39f2204210ab0ed1d5fc01cd489023914de7aca27c8891dd700cf07bd28c9278511f3fc2b9da833aef11cfc46f4b3cfa147b2977b99930c98f359eab14c71b750b8efeef8265c868c0d15d5175e1f77dd22ec47efb08c44930ce860d12497ea7b9ee5b6354be91e6d0cd85ac4110cf0d84e60855c5cf5c3a60bf42c1034209c8508d516a49e360014f62be407adb5165fe7e6d215f9a21ca0f1957a92d3bf40bc6687b37e8b90347d3e854fc3d06146acc42bc6e512bbcc7b90fa3fb627d5e5a70a3048dad8ac721f5f3e11112cbdcee5c1afd6d1a31d0a81c91ac1d6a50eeefb966737e3ba4728275dd0a300573c37a22470f859ff5db3a31ba6fdf2e5522b143ed2283e5e8d29ae429c6b6b81b843118e67509bdb87739b1527c63491df3cd2916c69c5f7e09c7a7e6cca493eea08c77144706ab7e5f3e1aa8525d3cbcf2ee1111ceef895f16818b06901c588cb4f71680c411c0a6e7a811ee6e71b0f5096304e6b2469cb131c4ab174fbfdb82d0d9755612428bdb0f78f85fb7dc4565580a61ab107fd4cc0b9ac381a859a8dac21d182c00efc11d842834289f2c3f487b761447d55fc6732427612a66dcfc6af7321812de5277a3c681f7200016c0574a107f1c133dd68d1ce966ca0a5d99fe1ea1a77e61b0aecccfa1273a46036a1563639926abd89d323eac27de61ce714c9b840849937535767dbc79925dece58c574bf4244707e91aa2fb9f26c01bad21602bdc064682a30e3f5e5a48c978d2c0faccef90cb904fd1e7ff7b13b67adcd221e6fa6ba7aa63d05190598dcc8e0a1b60cf58ba335aeda1d983b6ebedf045d4e77d11c2270ebb158c2655ef7fce3cc45f39c0a83f3d0e4104d0c88b71cc45dc235aabfcc9cfa71c115a9161fa08a8f946c2d205c023740cf063e0041d98a91684f080c5fdb00cf4defd83cf92a813f93ea01e1e91e33d8fc60769c8274b254dca39fbc8c2f2aaea89d0225eecad34d1886bde1d9066959e853474a71ac6fbb44714026c3b5af802c9b977aeb83338d5479c9d7ec01c86bd357d04c80e4eeed0564ede4b2444a99d9121b8a823934c270906b48ba2d1b35e0057ec2608338c70db90b3c77e5548a002d88fca8b68d07136a647de9d2b94a0dd8f2323c60ff2185237ba07efd8d49b4bd809bcd0b22a864ab8a279cef7cbdb22e0ecacd8cddeb6fc8fe24d94f2788d91eae144874a53abca9e1c019351654663f5ecf40e1b256d13a3012fff19af4c119a5d0a3d256c87e05dff323f3d89af38b8b6975abc69d3a5cfd70a78bda5488d353a97bb20805262c3884eec00c098c9472a9c17661c273e05d409c1d7dd569a25d0f8e85859751609e6805a8079169517dbb8cf82671034c8ccdaf73f8107d191a524d23bf0853acc1ebc400305425371bddbc230e35675770b0c5c27e0d59e294db4032b0fac21c83bb971c4a57242b40c14d088f9b0b3f6fd422a951da18b66a38752273df0419a74579e1d18a82bb8d21628ae1dfc1744deef83163062281099fba4840177acb4f68e4bc97c249f4a98c1e778eb63309528785e6ab1bbf9f48f1f155b0fa44a76e764e2b678c4e3282e9d386ee6d5e844981fc0d068ce827e092c66d7016f28260cae6966b6f343a2721489a3113fc9cb5a7b18044a2b3c883c4a076c01cdc6853036d4eec04ad9737bd327a350df1fbda99a86da8c321057903c15f54c82eb040daf29d310666013fc8c473b3242f8643d1fea179e1a3539d4bbbeec7579da5f2d0b4a0057639d682b1cfb7fca089c02b9ff52a68242802b71292926a7c2206572a1903acb4f705704de9f6be532ceac4a4b30014691d0a94c12096d7d4659a86061fb91228c073ea4b0ac2364351573000dd3ae49964dbbd915341d3c548430916af268b05883b15a0cc851bb7e755a0325a0b12fbe7b2c725484e50ee3087ff80c2ab5730b91b5e5e2bea2d2823a40a68745e75d0810cc1a5e9bb5b35c1c13af83ed9a1dd43984659e4acb80bac93f55b2efd6721635a0b3713048288f2a61c5082af585a61c621046c37133df6877d84e79f9d1fac2490de14c798440701c6d41a00ea2996e1288467cf08a7825e88ae82358fe05293ae71f91ab4ec498c3a157c01910a31cc017e27af57f926f1b4a11273342924f7a0d08a48b707560adb1ce9ae81fe0cbca97900b771bb5619a88b133157fb585ebcf264f26e0246a29126c18cb7692456abdfb48c1a102aa54ebfd5ba3ad107faac1bbe07c8ac8c4fd217e29bf142ae7d386cb0ab4e560a9db9bbc25effbcbfb8f35df51ab5e76fb81790176a6b84331800015895b09e8d8caaf5a2fcdfc518a2bf8a31ab50ca30fd6a28ab11f96ffd8a1be471c34613e29ec673cbe802e17373373d5b069f4d8a8531066ce2687f0c32e0056c1c5fdebdf3d163b32da327c74d45f97d1cb31e73596d0f18a3a0622914df5d2716788b3831cdc3bc4459bb9943150ef090bfdd1742ac89b472388cf746ce7c6e6115e31964d4d22849c1e50edc4c42fe91cc4d7f2ef3f0f66898183514e2b07b72b73ef9a63313466878209f0b51901ed12442924d60512bd10562b500965b18e8487c73564df6a393e1ee64099c13b880d3004e31cd1d3bf0043a9d2bc52f6875d7bb22efb00e01bd10256817ee8c7d02935cdfb4925868c2e556ff0a0252c6f80b41e3ae221a845b2e0d07188a6b1f22f533a02f2f13bf2fb06b317577764c40f057808b3138e21f7b430cb79f800f16f899372296268643d6c8aa884beef196ac118b2355181c687341856628a9fbda1222b327c99420912bf62b838599195d1763c1f7be40aec21581be1a12b2d7e267811a8dc4e0cc3242973a15308c24732306a05da8320926255fec276050ae29782f8eb2aa510f1d55d30682edef929e6ccb5d0342f4411187407021b5b11b61a4922ef93e94ad1abda2fe548c4a81b79c3ff4dca1db0984345ee5a064d070d09c51b7a89a423e97e198c75d99d0363112df24cc35c051bd577e3e6f1c4dd0b8d66a5ced9ab0648c8dc6ee700d445c3c3e5f0368168ffcb0a13e21202bfd678a94891c7be25fbc7f8b9645fe645c8e2de4060a0e496f2e1627673064fcef19ce19e313c1fb3384740fe77dd6155804e46fac78b905d906ea28b7771ddfe2cfaba204eb48d65c1c33e2c93830940ae44e5abf50e0c50e67c7b6500dc981f7831cc7d421a9cad4119787c1bee501df5b3e419006a21ab5cfaec44c6b28bf082ac31865784d732ad407974a6b9cb3fc788702400bb233c8250dd636e4cfa559e73dfdff531f7d151aba75b13c93d007702759d4a0d5c7053d3c1f84a46dfeab5f1782e766fcf738eaeb2bce8edee1a08431aa0a2c5743ed412a0d68208398d503d0104080c86bc3cb4901448a1224f9d4a57e49cc5b06a2357ca97f13fc3067a72dbb559af7f347983854a28597e0640619c0faefe4e306aca40c6c836b92aa3935154a7d2387994c9eb371374eaa0f64c651ca76eed4d2683286ec2a6c648e9e4b1f69aa91fac2c083824a1381c583f369b8069c1df44e799f0ea0af8fafadcc2c0804db33a7fcb5e324d55f4271a63d70ba7ad9ddbc59e440316f1ea85ec74e62d1d5a9200d965145f1480d93791ab88bdc71cffb508d587e6636dbd7c447f5416f087196abf41e65823eb988cb9341a9c84549ce4856d4d35545fb1936c8003f2a637751f408daef9dca9bc63121197e57c1133520e770a5c19795d9019c9668a1546f7a318b4ce74a0c49e0f6363ea597e60c77db1c54e20c758c58ca1e30c27a22e4304be0207c5d18d246253521d122c008222248bdae69217f5bed647a6b6df7b43ed3740c8f2cb7d8239e0b0f2fd82253956b92ef29f123b034040c8c841b013f1cd23f3bb0b2e595d5862b560d52fc24342b656393e7fd5ec1220d0b97ace46011d61c31b2cbdc87626858552362dead4bb43feef46d346d8133c72f9f09786356bef5354ae1d1720be9e0e382cccb9215f514d52783d63749d5bcaf56d9287cd287230339627380ea20a0850b5cdc3c4cb413dbfb493f34c827670404e281f5d34b80e1cc129f2e0c99c6f3bcd475a38c10e261d22460f6c68e59c50c328ebc3e069d1bc1860c69d3bc3f7682eae08874ce7f8a7022e130158eb8488c5af85590e35a53dd5fdf54d716e3e7713a331151b25386de025b0eba5362f4b8297d66ad5e6f152e9808c7e921145ec445cc0712379bc324936161c6f5cc4cd0c353c12683aa6a424a502f3d78c42cad6a5f4b7db57d0c364e32b3e8d8cad4d01c6472a33f002257cfd7585af45a41084f932c2dfe8acb5b8822b79861729ee055ba89b96fb025d7a6de8bd9e6297dd89fd206e4fcc209c29ea187d8e496333d2789a8a6dc5e20ad045363805188fd2d43aaaf9aa99d066429916e81e1227977e065a6ae7f3b85ca5069a59dba92d96ab00fd17203a110f5b9892251fa731b8a8494c2818734315e364e8366f66f69170672ed93283a445207fc617244e11ce338ebd22d5d7bbc5b4138e2b9075055f91b5a28741a71c22d857e07865504197f63c5c58d9b4556aa6b742fd0109fef09250c4c4cbd037a2cf9a96dd8f731ac821c863a5130bf5e0f86f498f5d22554bf1552200f753ec72111150b412f80e2f55aacb764a9234525c2410545c445efff46ce2f2fba6d58c3fec874e694563b8350820d4af9fbbe6ba6d14c983b3b6716b8f26cf73457fc576ed54206e8eba3ba6b25b9cecf347d9a06edd2a3dae8ce97035fc246050206568ec815dede61d503cff6e9b7753604cc70bcf80404082eaed037f629d3fbbec371e7a5a077ca0d9b50c9d38ba11bb4ae6f28032af931d3e183e4421c39c91acf01a99d6236755b914b8655d29fb86c0e543569ffa995eefe52d2342bd951147cb1a4bcb4cd4d69d9d080aa7bd07b57e15a0e0ffd8f96dddb49381bd0ed88defc964af041207569e67777a449d6934dbbd359bbc45a4b8d218a8e9e6729fcb26169f74204145ab9e2e67f9ac7569aa9e70471d0c367925e9932c564828a2ea5c91f7aab2415285edd2d224671d34e54961a5b1200a25754824a3fb596b699cf108b538040bf2f00d43e8e158f36ce6a77079cf78978d94735332300a5c663e441ca07c7415f7582d52cc565fe08186c0939a0a53e596b62a424cc454683919280a218f8e21d8fca2e0a0b609bb035413167006be16a1cb9eae2f76893444efe8fa26e0bde54e54cf682a6f91a0d2faf7c4f31d9567972467452d2524982c6706b242d35989285902e7503c14fabe5aa442fef51a200eb495490e6a397dbfc4d594ab7fae388774a3a775a3da383e650521fb5936b40b0beb12c1b87bc088328785b80981f3510da3114697643df3d280fb6608b84ef69a7a5904d489334ef150a74ceae6ee6d704ee2e9baa7f4281fcb16f4bf315774f49ebca369678186912d871e9cd21f8dcf28eed11284eec6be42140e551dd3ec59e9344758468dde9e9ad00caef1f03e4827aec27e46586a51de2d26fc2e17c470ea67463130669f0c6d34224acc32458e2747edb44ed167f33fc2984ae8d0e75019673cce3130e6d4f549055ae941a0c6c464519221f73c728bf376bf0ee4e680da75e910f0f618b0a3c599f425f67acf2c31f6fdb95b38206ff8eab309ef755f3c2c31965131f290fa771851352125e7a795c08159c6dce4894d046aa1b6a2af7c19d8e8431c5ebf29997fcc22b7841d2039e5ea8c01195103574b2800ea16fd15388780eb1bfb2bb052062be6adf61884f043f871f9179681b40f2edfb9ae04d4f09fc1df56daf2a5c651f6c1655666822177b1f6c27b3a2bc5d5bb46476eac65e2be24e6095e162c138b6d46112c54c97c18cddd5069b836aadd18c1112eafc6ba8a044e07fec0b57f67cdcdd9cfa478890ddf61ac7b04c5abb47bb8525cdac4776185a100e74d6e95b92c1e8872adb07a329c9a7442f5ce4895dd1cfede15d6898a54b063d8d87274fe88b3149274b56f75f5f6bf5a6ca9999611bfb2e114742f96c52600b11a4a4491b09f046f5dd3a3e546f39d177f561aa35d884e49af9c0e2edf900849213edba22e252d5767ce0404f8bcc4f6c8d974214efd982463a94e769bc95ca00bdc88a5f62f5257e62f2f5f9f5d2faf8af85073b11a176cadae0c413e57cfdd23803405502679c8ce929c3fa88cdc3e0db896d470480b1cb1b4b47be284049fb79e04ed2d7396e927fd383716a55d6a9a1443fad25ae320a87ae51c06ff44a683636ef354d841ce451b79e8b5e896684c22ac6e54bbe6f73a01c8613cc80d52437bace8c0ff8b7576550ad2043223bf59fa7a000983d56c3a9eaa428b73e498832606a1cb8f3f7fc3825548527004fa224cd934c06a8d82ab3809418f8adaa2892395419acd0338386b6d1f99754625ce03630924dc74575cb37ea3b4151951fa9b6c1d3ae4bf689489fed48e86078b3827d37421ae1d146c4e9569bb0274419b72661c39b43376b9814ca79f2fa7b28ed9e04a3d498529413af3b51373c16d0ce9450d6b74137e12043045b530713d5106fabc45b8767b30c11ec4c51aa224aa6baaebd9950afe32c82ea597765fc020b567f681c7247275e748ef440dcc1c3463105d35b2ff94c83e1a73d2ce7d1fa0246bd20bbe58a97835d2830278bb9406767c80d8db5d849a0fa73d95e06636009b583e7a712e7627a64cfe5866efe2176890413af4637fa870f6340b501b0393a8c5e4a71c4e71f22a594f6eff9c74f26393e865cde5313fcb432bc99f000f1c1bc69b32aaa99c3fe0f1113f83ecd5a65915bc41db9799eb6b1b03d0fad3c6be77919ab232e9b6947d02ca6e3350f57b46f4d0068c0e319de44b7823b5cafc24385408f55a95057109fe411d2d77421af97c490198168677da6e59d8c469ec699bf93040b851a50d8f57923a2b36b25c5024b84f7225fd6a9c4c76f389dca07c64fc1987d8ced0694e106d58ebe39a001e471f1552b831b5f050da9dc19fb44171265e8f0e1696166579104b09bbd4ae41efde8ce8cf49f4f0a987f9120962c6123d25008387c6383b252b2d89435dc002017675f5efc51b486213c6608dc104da9ba66fb31cc044229fe9ac5b3db9efd0de219e511893b408d3798bb57215137641565d5ffd5095841b7a3ba6c4502fcea53910159284c2ff910612f2fdd2802d1441b242a0fab9d74a3fce6137ba649677933de48ab67d9ac2ccd62a31844db8db2016fe6753f2708e37237d8a9beb85c71e2d981327c33823a8d4207df0b0121a4c38badcc72f8f650ad8a3f1c964d61410a553c7fd5350e43063a438adfff5fc929b5e6e1d0215fb11cda94fd962a69645bfb0397f2dfd9c1a2267a56cf6c14234184b7365e5b880c9ee6fbd5f5e300502344afef7ff8add0203ca4c7e021f0901f5b79f2c99745496a16dffaf962d4bfe02aa3b4fbde7af311ada018384652168fea2579738ba3daec9a2a614fc1bc6bf633c5e4b5e9c4c29437885f927690cc55887aff87bfb58dfbe18f087a0d0789d4a454be9c37e733f6a39b1a14ddf0acc8c2d4c1db96b3a42511a01b3ab80dc2c50265493cbeab9534c8fd878902b7846b72cfb4434a63b67bc3ceba0ff42bb8c552572a560c04e9c8b76cbda952e23031faa0c39db5b158833d958451a9a6e320729f0b40c69dac259afac3ecfc852d05dc22c71425d543951a6f592337fa9c4d51b0306ecda6d23c7a6086fb5d96564dc0f717cac82b7679fda27bedb4d79c118f66cf64873e374023a55e29389186a0e1b8f64e5baa7f0894646129fe468ea9e0b39ca15be2343988e5a85344edd1fab58be7d8add79eb726a5d0544c836029d6374dbc85f93636cdd0fe783485e42d708c13344d208a9eb57a0a2bf368f9f1978efb3fd57501e5818debc2d3281d176a029379b0ef90b29adeeda8249654530ab16f489d43a6f8b04fca74d48d42d44752e2206c64e5185b3f8ef31667ab347b0f4908c8e963fe49d5cb246904ec6bdd574d016e0034701acc1c75c86c1c0435b9306473cf8a413794fb46840fa559adf12dcd7c3e09f86b7b17c912afeb705c395eddf457d125bc23d745674d3b7be5ba4ce3b9464b93095ca11bdc6a65e3e3470f2c834caf76ebb588c3fc654af43cfde26a0e0ff79626de3cd93f5f8f3ba5fc462c6a9928914ab0f2ba7ccd50d14d4e567e2e9b4e1e50f60c8151d11f962ec175609bab069b70f93b158618d416064138b4eae630bade7ca82bbbff0f54180b654ccde3528a950eb43bcd0cd30d5bc488fd5123ddb8b5dec0f395d73e67ea618a501f0a3d9a31d04332b92e9af355373c1913dd5a98013cf8f2637beff06462c9c5ccbec42e3237bdd7347374d9b3b16940be20ff8ca6119368087edb207bdcd6b00cd245d9447f9e92e19548e9fcf72ea2a8a6e1ecfce44af6864a9758b5eccae389e33e742f235ca10007ac79942f4cfd1e200320af1c6c6938516268d3823bb20f53b8a0282c6ef2d9a5dc3f0c9926685c3ec93d6a488a6de61b2b57271f7b05a997c20a87b080fdd8c8980c4e600c37845a4db55de43b023e646074816fb68e431660bdb72db70c661cee0888a9db65fe98b8a1d574b7950b5e9e51b24146007a2afb9a1a7c8352a10edd1fed170c93753848c0f70e708c21b552fbd9255ce646b2ea69e1fed9110a015633d987ca8fb6b99fec50402a5dc40d8a349a4800272867b9ae501fe9a94fcec2e7e86a209210d9bc2aab338720f9e28612ba1ecddd5cefb91c7dd5902f24937365028a879e11c17a227b2b38cbc6d2f79794ad52eab5d1a98ef13aaa3e22eab5db0c753e1ed856349e3a07ce6389722be9fb40077ecae38bc3b619617e61450d276646e5879c70c1d9ee90206960e470fe5da9fe925e8adb5672f3a7526665807f031d960c749d6cbc73a0ee040252e87ffaf36703e1bd29e1d540a824631f2418e7ffc8f7dd35c9327d0fe1373d08755ba1f290771fb65ea28bfa1d1ce24551743ea2f5f9e4f2aae934d870afae0dd1273bef0c2d6e85de10d9b59b601d7e3d0b1933de33ae204da73b335c366dc9b5188eeb059f7a5c6eb2228d41903c0859b0ead3d901868274fa4068e3c813d00033741ea73c915dc548822d584e368c0afb9c8fff7d4650ae2c2051dc60ee3eacb4e37afa2d870529cadb159d725835f05dcd2e56e16c2a14855a8ab285d8cc94af527e35605952cb29ed045ce53ce96d3012d2b87cb5dc9c5940688b2ca999417e43f13d350ccf33f13a8c24599a177032b13fb0a9828bef842959b645bb4be9843ce7bacfd24360f686807e329afd84902dcc15c93da620e0216276e80ad7e32891c526510d878fb53da51ef66f25e457e971c56158744e306d30ded17ba8cc9703f94bc2c663ca5456c99988df30cba8a9cee778d8051fa62589b34b0a5bfed80a7ac5e9f8b8067c0676581436a7046a87e95aa70532b8a9e64899a4a1d79d4598b914dad5df0276cbf5a0c0e6bf643dd2fb9ef53ea8e356417cbe71d05b1b81a51ae3ddb78995c1490f492ead7046b19c5fa0ce2c89175d9010c59bf2695a926bcf96ae79d347fbbb8319e9c2adb28752a6b9c1fcadad91d8d95b286b34326808aa6903dbd806fe6e7f1c1e899571b0bb4e22296cfd7412783b127b1c84d762e11ce0ff1d7a75752e198641454cba8d94192cda93586a6988c8ef74d97f6d083ff746376eaeb14ec5a1d6dda6ef4f261a08acc46032a2bf9b970e7aa8f6a6c4d7857d1fd2290477ee669400ed6f746a3e5572b849367d029632653ab6106db9fd2e639531b9e1098218a4f53473e2bb3d165b365b04f09cfcff0ca8b42ad7dbc66e93900b90020d984e76b5260a7658d0826120c8087850a135f7fe5fd8a30b2ae7b8c3d9fbcff4558b267097dc8eba576a2270ce990030638b75b7d462729830b5b57fa46638c6c00d6dcab8381c768a80131ec9b059b39beb66a77973a406c9339b06c4f376df92b49ef6904e741bbd04417a93b388909ab029f1c5db8a19525995b328138b99748ea71456e7a413241b33241d030ac8dd5d5c4014163707b1cd0e9bc5f1b25d7fbb7c3b7ccc80b57226f47da9cd3aa090ce9aed9b97c99f4b96b177130434f5f044b6c3c5a68bca0835bcf0b8df831fbb12c7e6b41f4dc96f61b6636cd2d67b4a5f804ff482464b9b244922654a29bf05cb05c2056384cf83cb4f3f94103246cb4b5d903f84b0582e44878a344992244992d5e52095e2a2bc4ea7d3898ad39f2845013eddcb896047740d85c169fcd3f79c565229a8405788ce7890f1adf0991b0aa3846bf6fa243ae6f35be130df666a2714bf82f37a2b5e892b89a6b1bfe4a7782856f0a753105bc4901fac7be61d03d608a5ba1d90130cc33014eade7befbda11008a6bcde542873280cc3300cebb1d1aaa27d62fed80fe5f90976a821b06359bcf7db7e58adddba17bb376443947da7c5d5c2d9b4f628ccab04d134bbd429ddb44dbb30f6bc1cba3f346ddab4bb5bebeead9b366ddaddadddebcffa4157b0caa7e3b615acf2e938ae082c8a6cbeb24c4921c6b53056f988e83be8de2c5f9cdb40a390f320366299ea609867bfee7eddb59b356a35ab59cd6a5ab679b125d42efd9ae6477d352d13d9bc5cd1ddb4e9fdffd13b2a84ebbaaed369752ff5bc9c413014baaeebba7c34cdd7ce78c576180dc57ea2e9780ff1835df5a0c0758566d14f7ea233a09675cd3753500582601af4e4613860f04070030e5f5ae6b305b5744c0aafe0eb743a9dacfd0f183a6763a6f9add6b71690795afe7c26d3667295b7bee5262c302569134d9224fdd60a0fa6be050c3de33770d3fb81ca0b5306372440cbf400402652355e04920973349fb80933796e3299a6699ae6bd366e4c9527582854ea89142567cf2a8a8a8b8a429521efba2e123c9dd05ff6b9f8d59b0f9a977edbe72821b0d85c847f9120830d5b506e830a19a03df4aa4fa1de7c93d237e99b660875a25028140a55832bad8ef58c45e061be011df33561cbd0ee017bae39d3ec206ce489f59145318e23a9ec1142ea9c929488d47154a94a6e855dacb550f073b57a900b374de747b221af72d2b1dddc60bfe1bad15123d040086b0e1e3a22d034ae23819e711e1ae673d7f9a85a6185518676e27ed241142fc2ebb9ab1fe4018badd27185d7573f198ce3388ee3385e570d1528a59229c584086aa754723a7215e148bc896badf59215c287b8f9f1136ec4061a7a16fb8b8ed263033e680002dbaf827e72afdb0e158197c475a7c6832ac0a107ff93826b16c130003d2a5da552a9542a595b23f4b182529369753b462514ef755d2c2ca15333b78897e4f2b067b25c696a0b1fa92762a75eb2104ff53cb8036aea181e5c3f2f91c254c634454d2693a99e40d44a92e5ebb85bb783cb5ade9ecea853601d554ca1d28131de386d0a3c23145b955facc0627ec9c2c6831d8e500a8ba1971a60f1caf0b2048b311c80d6af069a3d50433b096faeb986fb7da09d84f55bc15361d1eb3e22f067838733c24c099c4307f4491e29a295003f797af0d64b02f2b390b72b14c81b9ddc2852a6e83c89e61ee7799224499224795d35700f1126241126b2bbb3ceb22ccbb24c0a07ba6bc2e17b9b841d8e8cd20f94153e9ee79ea184a29b5ab2acd600411908d10297f375bde0fe8944958a2442d14d36b250c846e0ea50c500080eb836290cdb68e0b1ca5bfe1da41b6e735296d910bd6063ae80715374a4d48ea4b247888e3dd924b66489849fa91d59cdda56f762ec7939836028f494d2cb0bd15014fdf0421e0b13d833cbcb711f98a8cc510e904d896ad4ef420e908da734e2c9329090115594463c58f644e3687f9891bd241adb22ec108b72c933f2f7a8568764c707ed4841375c21e602cae1d9b1b292735cf2ca97b3925b720e4b9651bd3acda1147ace096b761790e6dcf6e9724e0ecf0e973ce3cb99915d3e1a38f728c725d3c026954fcce1f4c901d57da20dc78386f64da0472ea01ecd9872b30cd4061ad6cf0606b8645f0be8078519594dd33444f40c2dcb233a0b7a648950a435605d526849672e130df3f9f244d1636b60c78eb9453aa67e57eb6299acd0eebc35d99114beafd81213987e383f6c18586cf3e6871d473a8ee368473b86f5a654bec5c465cce639cebe8481c57e02e4ad00e28811977dd019f046017bc6403cb8669b5da39a96fd014a53f46819759a8d701f298fb68f86e71e61370f9af77bd22cc0f75e1f3548911162f5125493f07307de65027f7ed087b756268c18b65ae5ce977b2f4bafe15c86e3388ee39274ccbb736e39950e24e2bcc6008d002e947580451f3fa1180a49ce43d770dce751b4cce71b8ea4c1ef3e97a26368a87d5e96b4c440f9ef5d89810b748d972e43c3e5cf16f09a2d7fa6a169b416ab9de01a2e53eab8da0758995d1e1db76929cfeeffae95e3f8abf1d3e273d9e6bb5ce3931d3bfed4f87c3a6ed340b563ee83dc83e30a40d45a315b310b002af08cfdec9b409b66c8b699e301d05371aeab063686b5f6b2172e71e05e620232c4b2e7a74df3ee8e5d1d0e232b39fe23f41bc21a7a156ab889562d485ce9f02af40097452c671983720b9feeea64c0fc13b90e33500ee1e59f58f3f6ddf061be40349c7b98cf5912d8e66be19b45d1a783a11fccb24face177307c7819592982455178896c3c0c58233472411882e3382ee7cf4745c64ade01c8387ac99d5d724bd6998157be729917508f3619a097fc0179cba7e3e35df8cc92678058be1ef28887cbbef21a11b4cc679719f9472f2b36bfad805eb20c900a885f5436caadf4c8c572d957befa924701957000298c4acee7c301c85683114f96731875c7ccf8d1c67d7806b843140f057a84734b969157f2966f68596d2e777b6e9101bab7e5e215efa2c16081d24858ad3c2e832151ce9d8d037444e066078fea590574298c73ff29dd2772b350bc95c9dff01f7a8696a4a6e9c65155852af543dc756ef62cd2abddb19a200ca267e8fbd03768e5618817f40dc2a6f1ec45150d856ed131d46c9a6adaf19a9ac4445b49764c74a6a292784d6de2325d9324e19fa087a84dde888ac52f51533fd22fefada82615559b5cd7a97bc61d46afd174681ace344410f4d4343f6ed1338fe4838ca7919ec60424000441a01452f8f154d69e9aaaa8d1666c4ad3383d62ecf3c7d17fc450972601a24b744c915a83f0082a3c8d271dc6204174580149891105a110405c25741883a800054200319ec6244e2f40d2848d0ba66a661cb78e11bd70aaa083b516afb0788deb0842a967169ec01f09bc0061d82a40c2046038c2e03ab88ceb8c54e772d2785d1876eb652d86a9986853ead4bbbbbb3f4702ee8cfbc3cf0a8f7cd499d6ca82ec89946cb56a619c1287cef4c595d65aff71b390c2a2af2ed18d274ca9b121464bd42d9e26e76a85d918f4f0d0d3c3c3e8299c9e6ef5e0ac56ab9567c3f3562b4ddbc14385094f7cd05a6b075e7c20c1627e5a6b39841449962b2749cc23aa26282524e9799ee7d119aab3e309c93478244a0025144956b4472b27d414249df1d6553eab758d17293c57d4ac2a3ad3de2354499e4ca5195a928eab91349246d2485a95ab7255ae4ad34fd2248f409e48484574828c438a189d8c41c62145ac56abd5494de7399a3facc6d509c6d8349d3a72498ebc7704d8cb28f8ca66a8cea7d0353448cbd0d01d466ff452892c91259205631ae487d2905211a5911c499324c91a42a10c8436e083070d3d42a150284492a927caeb254ae45484f49ef968d7f38f86f9ac7d62163e97826635ab594dd334da1d734ba552e95dc1cab2fbddeef77341462095600123e89a175c4648d35c3d3c55ae3b991052a74898f530cc285f28c153e04678145fc251a46b4631cd9b8186f92c468f934422e517722691346d070f179c4a77777777f7aede1ca5949abc887690144c24f426ed0799fbf943b52ccbb22caf4b8b5ad6b2a2ce28b5274935ab939aaa4c52a9542a954aa572ee546aa351c4094a52a32fe2c4893412c1100b5f60b1969563a10a7cb5b004ae496a595b50026399c6f5ff6421dcd6a2ad90b5907a98cf57fb52a48ff42454288a42b196f553dfe2add042287eaafc944d7d2af5292f371312944ca3ebab9ed37c7d34bad68f8528b85d86e690f3c341f4aba74e0b267c7d622d3b500e38a168f30d34cc58ca06a7b0c32e7767013c8ee3986b78d5fa7d8afb5ec9c37cd674c01555cb0759080277e832b496652dcbb2ac652d65144192e5ca4912f388aa094a094692368796e18ed13e5c75d0198c1f80379017587452c454872ac791cb95640c2d43438004e1cffca030ef425ce603ed76bb9f9bf513310c046088816878ae76c7e7a6af78d4ef668a1b5409b502149193c934dda04c138599a6699aa679af8d1b53860e7ad5cda3c70668e8a6d775b917b829752170a61fcd1887563ce86ab55aad78d47aba529038d01ff61867173dd0a104477eb0d65a104c65daf54e5afeb30603b30985301b1d5c8a7a201f6d1c8805284001c228078866c5c84d9e032a48ce491afe7d3e2f290c0cf7f9690c8c41e1ccf12948be388d72806c4c588dfa5d28401023ee5df80ce47918c268bb3ee0365d7cb5b68f9447da47c39a2c86ad5adb9349a8ce94a73bdb7d9bdfb66ddbb6bcdda6792c14efed981c83f79d7b3d3f315a5a71ba7165813fbb3cc1a2ef34cd969f07fc7da287bfe5a7b67d94480fa639e557f48d2cfa86155e6891c2c165ada67d626bd9d5b0ec6adfaf5ce673876a012d4183bfa24318117eeba4a413cfb2e8e797bfdabe5c6ddfafb45c7e6bcbb9d5e556abdad0228b89f9b39853df2a0974bed9b42ca3f289f77e3e11e3eee33e31b75a1c07d6e898908d9b8ed9c1e3069cfaf9171f4c96144b88c565064b904abd7492f4141c71c4e98b68bef32e84e5092c9fd862884159348bfd84e513fb0cc72c7379cb2fb0e4cf083080ca27e3dcd2322d9fd8397896ccf26d94a394858585858525b3b8cc7099f1c98d9f252443c60aa8c683a18eb121dac183860771721e7427722ae2a907959832be33a2d66aabbd31cd9badffa7c09e6f9ae69fc98366c7d4d4fc0c5a86e6b57833090ad5738305169dc6cdd987606b6cd3b80adc0c30962fe87234b016b4125e1f17e13379f0632c0ec2cfbf45cba85208038b7ebeea513553b106d488f5390163d96607c9086db6f92b963021e2a6693eabd7da0e862bd3c00f7e06b984b7090f839d5074d62545665d4e9e60dfd9d1988096b33c03368388c27c773842e7953dcfbccec3bc83713ae974d2e9a4d349a7934e279d7daef499fdc8e4fb890f8f74b9bb63185823e482c4464130c46303363616134ada41d0dddd6ff0d07bf0114f8e0ffdeb4f131004c15a59250a957a2245c9d9b38aa2e2426b8cbff4b07bf66299a6699af61d0e2c7f56bbcc65b15bee99cacd8cf33a508f34500db31e7da77d8ecaa080b32f14ca26ca35bfd84d09bb37a29f348d4816ba41a15028146adb68183b1b60ac29d87996251d3a9aa63b555452809df4b913bf441be91bb507e572a6046dd206ba59f4f30ec1dd24539c43601d55879f5ace3e1a375aa641811e693466c83ce20c00b0e234d241013aa91110da8339caf2075a4223d9870348619ef6608eb6ac65d1f3c126fac66e6c422ba1c15f3dc10b25241fc10ea7ea4b4c4cd5a952a2a4c7799ed8799ee779de7b73aed06064b15aa723534c52be54e4c717c2627dba4fd77517cbaac0a2b35827d64a7edc7d3eb9eb3e9f87f38ae7173d29fd0cf9e17c92c56ab1582d91889e8e3a4f2ae564b59a8613f2319a46628d45cf9375b2ce2d735974161774c5e4c1a74d5c8687929e22ab7f1485d1314d2a53ca4404f53bf74fceea4c2c16cbc462b1582cd655a38edbaf149165fe2b58e5d371db0a56f9749c870516a909cb70b295560aadeeee6b93650765d9b5f9db319fafc96432994c9a76a2678f55e7b8accd19e833c34d7df4394ef843d163a1891e9f50f44e9c448e1a7ae17b87492c7a5ae81e9d494015de0cbc2d3cd149abf644777787e82a1402c19cdbfd5d6afb1158f4540a0473f6ae86e323cd5d9645279908d08d1e0b23984b8c48b14003dc581c0109967b7a1eb4f91b7d39b67d46ba8fcb9a566d1c908d38fbbcc44ce025f0767531d40bac7181dfc5d00fd21c4225a1b761437ed5cf895d951281205523b50245adb56bfb05fab073dc0812518c2320da1045463c9e37202ea8afcb36713a91669323aa22292eca9e7b3a7912272fc36ac7dd8ed3a8f0b8ae0b39bf3714047a825fd0a61c271dfcf9860ff866b7375eb361b96e9f13d1beee98eb52b400bb0ccb1758ee220446084ae8c6bca75396ed18adb5d65a8b596b2db6c1808a2a701676a1e88516eb70703178775805d8731294babf2021438c9aa6691a160aa5f22766cffb7080bb58a5a0ca543e1df7659fdb5d16168c3d2f6710bcda6adb6a846c885eb0710087459bedde2d9ceeacd2dddd38c0526ec011515102a8e85bd7759f8822c5eade7bfb2f765d1fe63baff3c511a81110059cb45062b4b9d0e2240fd2329f7750e94174538ecbbc7773c4eedbb13bf7ee6022d1cd329ed389349b1c5115497151f69c4e2b1b9b3055390cc36c9aa63ba92801b2d1d3eb7ef423d2ab4c0394427802cbf7c222a27f813c9d5ab4568e0a6b4dd3344dd334e94c2804821e78c19013312851a31c200ad0190269c4e3194808053838473c5a1645d67e8f553162cff1bd9c7212e6eeee5cb6a00fb492d0039eb9bc7508702f412215f61224ca5026ec25488ce193e4c665ff9c84611223b9ce45b6c8d8ba2772022c3ee9650042dba3cb2d1fa8613cbb69e24fc5cd2fecbedc315e2a7925f16710be8b5baed7855d6e5a1b1bebeeeeee9fb5d7755dd7957178c92e19072fcfc88fe401a4977170c92f198719d9cba4fd8e86e7195eb24b9ec1cb335e5cf2f5edf0f20cda61cfe4cd57758c0a26f6e5931be80554432b096dcf0f7cb8c16867809e04b9cc7814280c7bc44bf2c12dba00038a49924f3ec992f1019062b3eeee16ffaabb6d60791865fd70d68f1387fe1d8e6a2ba537887af402ce0f51005a851911dd116a02d0ea23882602167fa2a1070fd66a87b53f4c2c168bc5fa11b2f1e1a1564abfd5067cd46bafa555cb5b7655bb691976dd5aedadf6baf7da22863ce6ee8e5dcc8235b831fcffde7b5d49ca2ccbb2b274f7a157d7d5ba4a4f728328fa0676c3d6ec701922f80f2e0dbab0fb6291893c51c64cc6fa86a57d03cb9e9b66a84a7778749e0daf2357b0539e1efef59fcb4d5c64714583249779d702085307a1cfb235e2943c4cd96a95996e19966559869ab68347c912c4da16ceea455d6932f03ea30116166d1b823ddb8cd3575f7d5191c5b0ac0a1004310631884bd6087a4813d137b24c81f01f7c6479211c08acc9215d7f307a66253fdda125238b0f454616df0832726733686615460d819587fc900a9272313e2b327056c99fccb29245af594dcea8edf0b18a505dcb5a11f075752c2cdb2643fb8cc8f872808cbabc8525217564393b060c7c84f0b38a11c2cf1f28210dd2cfa23b40216475cc93a592e82caf94eabe3f39f102d327e7833db0582c168b755d66ad6fadbd027fbc2458ec966a478808870b85df753c5b48bbce092c86b4f0e66f5c81b3f01ec1622806ec490cfebd3871d3c239b55aad560b27f582eeae5d5b2ab5f4a2f4ba905094124a92a5cd46391b6b6da8c03603010720ec254a9284b69b408f74ae6cb3d8ad1728e0ed72047001fe2e5aa1a396ece0e43d95dba8a0ff1f23def702fc9f93f02181c56ed510a769bc898ea9a23405141d128ca309383bea055224a2244992f43728176bca759ef8576e93fa5c8434112962e3505e08bd2e6e09ced12a702a7c65d246d3b4ce33d6c960f34b16d8412fa105d56e0277dd6bad09ca186a6e7930ec0e077e50088c57f0bc9bb13cc3fdb04c02338e89c88ba05bad6e75abd53af2048f154eeb3ccfd3da8eb91e93acadd553700267d75ed9fd687099bf9db59496e06cb55aad160e86854129a553f0f6ff5448ad6507b81a241403096fadfd2ec77605c6e1f770db82f3dcaec09e4bdcc39bf252447e9ee779f6b8ae2c0aa6b5d65a6badb5ed3838f7629c7316e1d0999c5bb9955bb9955bb975b3ad954195123aa71c209c12e48887cb40424490608d78b454a9d4342dd664537466465e59242bdb4412d65e3bd6644ba59bada6597b5df6ba2856b14aaf6bdbecc57da41691eb889ea12814132a1e1b2459b52c8acedc286090c242c5c406255bea9824d7674976b4452c59b2da05f9fdecc97e3ee29456ddaa944e415114652d2a8bac9106515e439f582788405116c5836dc1684b2b9bea9826e7ca96e8ca96ac2dd9922dd9922dd91286995e13ce28986952cfaf188f42dd7b31db11d1fd4cf4f32c014785f0ff47f03c8ce1192108660e1411423734b4dc619685e84cf9284eb4ccbce9cb0b9ffda8042e3b5ce9900000000001c31500001808088442a17048342295b7b23b14000d537442825e3e1b4a849124c9d114a30c328621028801408000c150892c2ddcd8ab999bd4543d9452a28be475855e6441efdf869a9c7eed04c8b24feead4d784bb5e98b0eb34645472f2c0aa6a5cb1e45c9525fbb94b0cb7f78143c9c394150da8d0fb07dd83214b014cbdbc732b77ac29132d9d931009fcd1a086ecfd58179be1a213dc83a3c45775a5bed482df17138484987626691f016730dcdd1047c6aaf9a6b54421a328c5e79562cbae5dd98150d7d18fea05a2d2282bd9da99e3b53515262afbb684310daadc2e33b5bc08160d9c1027a6e280a71d70e120f70c43c48f97d58de2761878cdd226f85980c9a9e93cd6f7ac287d8fa75c023f002e713c5b76ffd48b5ffd85062a200daaaf1e0711042b3a8126bc2c5640cf13778af074eaa29f81fd4e241a49165a50e9f539d751e5c906d684d935cf592db0d35020ed627c712ad834431c04ac64a13f7a72aebb6809974d250527c7c41f7f427597b5cab489f7c2631f34e88cf3ae4f42baf87af76ece5576c5bf0b49233e4484a6fcbc4d814942b2a9c99f313cd00d97a5482901a68aba5dcd569425b9da6c8512bda8a04f531448d64143806f621a0b7ea653ebb21fd1296bf63551cb58412662de6bc64232558eab703222b9166339d28217a538498d8c55f451fd8d1af76ed151e5d86b2ff932ffe56c4c59b4e0610aa12840804debdf5af4577aec948eb8fa239b7f47fc6f92f4f9f5753b41d7a0a1d653f6c4625c01e609eb15af69727ed58b9a14b2cf2b0ef42e4cfc1312b79cc6a86359867f18b96bee4cca441a7ba31888c4c3ca6784cd22a999a54e6700f6238f43715d7c03c7c9345e2eda3e80047325f9ecb2c8e083dc48427a206966e39142e75cc1cc5a3263331e9ca51639ae5996b82cc04e58f19ea44f3245cccf0ed4bf25b31ba3103ad980316cb264fe8bcc08934ceac860f64eefba4d5969aa5c18c1d7948e8424d9199def6ab0d9a1152cc7d11fc038e70364293e7f79e80d20d7d2f823710d1549f325459250e8157debd11b931e82c9662e4fd850176a1b6be3b6c7d3bdd29ac108fd47ef07dbf639aa9fb076792061d28b6dd82aa88d417f2c7bfd63498e3a1a9818731ccbb2b967def42f8bdac8fdd6c19703c113ab6ce9e2e2236205166a3a77f4f01d4239b635650920adc89154b0d635a23c631fe10436de96ce08af2ca3065bfa1789a704e79d6c8cde9cd1a1923d65fa01e373bf629356c1448bb36329877ad885d023c5b4dcac57a10659764699d3e2f7c2c3b128553b6913ac4f039d903de3a342227c0212916db8893c904313ff3b5a92336f6b21242afb37af5c72bfe908db124646186a3fb597694b6930f12dff4a139fbeebd09a57638f42aa3d5c33258f8565a29fa0915866561aa8e2da28c3761ad2884407cef8e13bbf490ecd17d5fb1be6bb9366b8fcf79418540bb930dae190e431c90dc9d81a97ff9f5328331a95eef4b243f6efc1e13c8af4d453ac47c1cad32f35a98afbdb4f5303d54434b73a45991f9ea0be154d7fe48a9634fc5f5104fba3e8209aa723ade8f9ca96ca9c2bb4515f1128312160e910cb9249ee7b93b105d91834d27c25afd9ec80ca7d056b381a4309e6d30d258f92cf6059eefefa98d76324424840a08b839113193246ca59d296b6819e6765a3480dd053fa0bfa54a876a85bb1bbe512c7c105c9499d51b7c7bffb46680060d06dfc18a9dd4b735a6366b41a07c84124ea9415ba8dbfc6fd31553f857b0423e67d215f3b52a113bf8348f4c407199978f5ceb1a625dfbbd65e570d5485b6eaf5a58597b2103a2b9092ac094289327835c09a18acdb282964aad6e6e65be42ab39e767c9349b9fc89f96a4599b857c6ccb6f70d3b8f260017f8b9bc50ffaaaf705bec76082e2d52cf42ce46832193772ed946c0d51f87d935ec9517a2a1dd450760926bd0cf24167426b79cab2e456a44583a3a89de85bada3cb5f48f567504b26db24e66c26e00e01529e90cb19c29375688e776d1f7397e4739dbe1ca563ad4db46de9be29db682dc5068e5d8b1f1c944094d5fbfc52d08e9886a38b2983efb848a4ba6dd9e4ab1a3c6b5bbb713cc4bb07a21f13f378c9546447b40b9d5c3764295d85368a96637e3cab8bdab6fbe0f8bec7eda54bc205bc2d75953d535cf8a21d3b812a47eb8c76f51bfea362c45f6c87640d79d2bdbe392530fd0d22233d802a058b8040a129f1b7f229457e0ed2aee6a385afdf7cb0fe457e1d320bb0a90068c6b9f39cddd8cb0c7740ce68d61e094cd3358ed99fd5293a661d13250147381caf90ac58f5bb87ef6cbb67aab2e7156537593eab8f1db81a2d33f5d87d3d1046075ac7858f336c9e4f54b03065585d57298ea3d6a206b5db8de10eaf2ea6159684182c1bd447c407aa4024149f67dc69612c511fe0413d63cafbe347419a88e88922a901567780a0174a07ed577dd760886414ad95eab06d2f1b01adc55728ba22793c45c155e69bd6a40fdec8068107cb9e9e97518ffaec2545a5c3074c384f3bf7e14c80a691c69f272ff146ad861432a21a8cda43a420e1f26bd1357e29e1bd50630cda39d6c6d58ae035c4ad6120430a39c3d2d08b882463e094073fab43fb2905a94cf4a50e6eca31c4b0493857b59174a84afff3f07af2e9371857c2c53c523a93d180eb59cfc3e1b56f35a5ae0e377840be332dcf11f26041cd29ca979a20e84c27b2ed612a9d4bc3f00f5c4fdd6e8fd801bfa3c0ebf2f7e28c4f406a5f472558a880c2568dc266fe86f51c9b9e22e62df55e1b0ed003f5ab3533641e6f0d7842bd1b0776a6cdd7d63b21185e4f96ef84ccff8611ee89aca01daff09e941101c89de345514507acf9635494e88e928b08ee93bd14951b00416b84d0eb61b10c1d2f73087724c45d8cdb374b85bb35c2dc3fecd85a230860b1093419bfd64dbf293284571adfb27bf951c70ac945e9a5f6b54e7917e025f16b1204595ea3fedae44f196ee001af608028511be53e9f613e9c844dda4741ef94333cdbef91f0f16ba810baa132ae82c70597166c28dcfe3f0d9f3bc01f78f62ea20a0d6358d00e15e32783a88277903fd06f672cfbd3acecf5d7f29bab88ea85b3498e12827d984e489f360583fbdaaecfa6a6714aa7d21c8f23334f281ba678af6733400fe9d11e5e25d0d1ad1497716a3587a749076624f81178015bf47cf0106e6818b828ba65a2a287ab12398b605e17f4e97576db31c709d88e8a5585b6a1bb512e628e73731fa8d754677cf6ccd9e9950874337f880ad364826df075a46ee444ec74cea06b678132e273041644d8966a8f6368390a121b8528966239f2ec58e798a9fa2b0a8b5e04d9488fce37bce285e27b803237a5c45d382ffafbb3a0be967a2b126917e219cb090a06de48a5adfd84f623b681742e860197dabc1f004109972f51651c495bb32c0c4a9b93eb99a331cfe8cfdcd4df2eb753ba9c34715886ea2f07814b2a7e633e0bf1fd49e6585e0e07e68dfd1051ac0d928acc8a21dfc91331f8472792227d6d9102c800f8f1fa35dacf9cf3a57122b5ccfb86489c049f2c6d27908adbdc1d3aaa36f1d4157d311ff0003f7c2baa78e4f4864161eef5ca101c97eee9caebae37532cbc6b034f320ee1780e3c626cab2df674bc978ddeb801cf5232133ff18bd52044ccd9ff0912177a1cb610924c1ba15a2d31a35b428223c89d55a2227e2dbcc2afe5c4f835d8e658dd92403a8730d87b9f851d70f8a6668efb1aa091b3ae5b9cb75b99173432730ce5e2e6ed66c972bd3085200b8bcfc257aa77cc964f483df88c311b89b2d19606fa6dc3b7953ecfdca90afcb81924870dfba42edeabda6b7898530583e060c6f27164cb67b094a2e3f60838c84afd8e95a5af628822719b919b1f0eca7a68046ae16bc17940aba218da2401ef4ae03d0ccd018e2808d15a6b5a0718b24e6d4014e303f3826ced880eff2f206ebfbaabfaf8588c3c2e623f2f51bf1cea41e7e4c7a13974921a5f42b346b01759346773c6e704e313999fc3e198dabd2bfc8935e5307991f1253156dc2a2c9c516f3b0d8e8871bac88740b3f477356c2160cdfa29863121b5d6dcb917415dd70bf50691224a16809f09b104b0ffaa0e0652c28484274c198be2d0e36a948f873f36c03133caf074bab48916619934d17319b20367ace9ced6e2505ceee5aacaba9241ac2fa4d5a228ce9a7192fa2b7b2de3581f858b11ee84746dc640b9d31403ccbc34194c1d59d2360cd937da21bf0e4267503cdb2e8872c9554f209116b6c60c7d0b15f0e2c2f854088734cf646a874709f241d82ca9c0e6c1ec9d90be5d7cfba4761d64520719a94ead7fed8f17e085c0dd17115862d334067be0b9b8e4242daf953f16b8c9cf1108a940b2788d7138ce0e281b20a4353b231744df56a1cb8c97af32eece387a3340096528af1d160b6bc4d2a1354adc74e520ccf3cac1841c0662c122b12ae26ace04351ca9657dffd66dbc59bc0434e5e4ea63b1a0a49fc7bc3034b8c780fe46a50c7f8c90dd1794df8c3233b61750f470c31005a899268ac887146ad8c11e16df532592c70cab5459eb768ac26a80808ad4d0e3711c2acfdb21a80982b5ee83354b2846450aa51cf16c798327094c5ffa98a28266571992ee3929c06432fe51fa14ef291452e77c8c32e18de83a195d1cedcb151281454849890fb730ab7642ea139bcd3c9a329a11fc002aef36f923ecb0c664112d8a557dfda6eb513d98fb5b6e2254d1364a788197055c422ca8fc1fc917d038c170dd88d7a7bd2d9a1909e1dff0695f854635fc37cf9f03a066a6f8674b48ec80253b1b33eee4cdbc32e8cf5c7663b06942f0103495ef4181f79c00b83240b5d7fb635d31a19db5ad1533d78ad5eb7f5031e779ffbfd13b46aa49088b8004b6d7ae3a15b8644931ba55e535998fc83cc252b1d1ae62eb713e6f94c492a2d9fd6103a2b9d77e78fa7588ca6c6b4c91b26a3ec974954fcdbd4d362ec644b2bd68a7bd4ac95343f73d898f26ee3c1c358fa5bc574b24ba47094304be79cb4da72e345b8f33678a04129f6652e3971ff22047e77706ed21b38e44113a1f8a347582dbc64bc4dcdab25067118a38c438ed952a323a9f83a3c375d5c5d75544f0432c7d416fa6d0919403ca69756272566d0fe9052e013dbc2b5287add033ac768518eeeadcb7faf3ec4b9abeb7538e2b836f5530a2fe436a1314ba486c41bbebebc2fe6ac95e0f6d7e9ad1065c1793100f255eafbc923186230c96ba9f2afe0f8555935a54a542bc54c457755002bd6c969ae0006003a0f2b73782b98681d45941b3c5d1f512126f253e1a1a03f249e0a9b59d8c169ba8ce5caf66cb16c74fec5e74c46097c3baf86302acaf298b6434926e9d337b30e5247364e981e2250fc4d6f2a4e5af3a59ebc51bd6382e86f35831ad7ca7ba4b6a95c1cfe746325ab5569f2561fe53156622ebf91d08a3c377fb6425bd6b710613937c0436c4ec796cc1c23c032cb9fd4d8ceaf6122abc18169e34e098331872e81a7caddb273a6af965b56efa1bed756313a8f8ee8647f24909599c4a2196542a0f96685b840e6daf1848b4b1fd9393409d76229d402340a325f6b1ce00297cc4680b79fbdad7c8bbd341cae7c95b92c1024ec2eb6f4976f669099f0a4177828589554a1e6dc8d9f47b9164aff79661a1e11fdd1e310d2933b224bb08ff5a86250b04c7f6653a0ab6ac9b1e93b9fea3ed7b3ac9c76112fc240ca3b78319fc140efdf24770d3f4306d6a33b1a49bba76db61c478be52fa4cf948fc51a6a587b9a27288a5ce44d857c3f047db005c13235bb79019d1fc894db43914083c9c90a2cbe950491fc22a5fee2805ca40da169e83fc1e6b82f5e459abb1dd35e1d6600c3b4d00f973c77325b9405b270ff2f55ebf047aacd26df7c2139698ec5bebb31c9037c183f299d70e35e8340072f4256dfa56d93a14b9c851f40e9b94b89790533a4a808beae3c3b83d08d105656073183c34f863b8f48768bebe057e55cb5be67a04f0e2d7ea5a99725de18ccb1477a74fc87ccba2915a16a593d49cc52687254b5ada3b15f61f9cb721bf1cf4bad678c2cc2b343893f9f0cdfb6566b0a14623f601185b809f957855b7a6f7a6a6544aa9456d3e85da043b47521f0b60e7505b0c335a73b5fe20d9301c668a083dcc442d65dedcd77386ef481be2c844d4ae8cda706627c9598a6854c3c77a6e04647e320dd7e887a1b8466f188c363fc31f9fc94170fe55b210d6b80741c1fc746c954dd99d836399066470e0fd938428a7e1780e1f4be40426d1f529d7626584d6934be930bb74393fe6801716ea34919cd327c5849e2da71ee143b1b134cfbf12ba1cb60ad5a49a9d80e72c4de474537bb21d27e0612532e872e90de18a426b08ead20b64bb0086325754a02e74b95cb9a45dba963f10b630d5a15a6e4c09581100aa30b33093c4098fa8214362fb676e06ea4cff1310b4d694b05b760519e5570fb1e522ff088cd2aa1cb3731797f6df1503a4bc0a7857f9086747f6de797278dc203b5f463c6b8133217dde9d1fa50e6cb98ae2b6902e727512fa332c0735b6dcefb3e6144c3756e2c69835c79b29fc05a15140271d86d973cbbd5005eaee72d9724048ca0b05bf6839488fa1e5002d715a943d2820a65f1a58e2352b55fb99f9b5f4e492a12e4c3b0ba06648350b0f240e0ac455abecb750644ec9064f7ce55073192d2ece691d217c3507705d6c7c61524719e9ca3222f1b8475912e4ee159ceb3b798abe032330945a539458135c6ab713e67c7184f0260702683d2a8e4c0b13ec223d61b9bd01823603a25724e2d174eb60681b8bde11de521de241c8dff470f782bf55abf5128ee0d3902cb002c74c5cae10e76271d6d81fd0475ecf48e551628ac9485143393589e85878c1374c6f24e2247285330b599a56670381222b54e57d3c1f38eb00e8dbe5e7046f808477978bf0ada4a7bb7be62b1c9aae02bb7934731c3be8c964805f3287b46a2ee216e66d914b916b130d063616a6eb1fa44d004bdabbe70860859c9675f89fd5978a6a7d601a8a0c6c1fae93419903aa3839e24ed43ecd44a80df420364e7ebe333a295f95328ae6f9a3fcd908345ad595069bd72be9058b281f33e45bf519c5f1714fd39b82e473a66ae4098982c6b7cbbfb7b30d949e94624affc426e449b924d16cb8827a640bc76e18b170fa8cb6548eba488d5fcd4de90ebf8437427ecb2906e65b061d303a29e66dc3fb44902e69ab1836a86207e35841309926d3dcf3a3e6b5908c1f1521f4fb9c34bcdc203d796a8b0be8a385b92addd0a36b247beeb210c0eb8ebc2f48770fd299055864fcc5fed0f37d0b0c8992b6c29d2c3af021779503ed1aa89ed2c3095c43e2860e50491439c463b290a7138035f51df94be4576dfed226544362c6aba12f8b37837952208bb260300e83525abbcba683344af6f7c164c19a472ebe85f68c54264fa30114a9f12395e88ef9966dd6f0ab5d1d3bfea1e8f8e36196769a885f841a27980dd7f47c0ccadf58434f82ca748728cb91a525f466290c34993462d9a71e7a47f0e5bc3b2303be19588d96e1b89b8ce24a114da4334ece8466647034c093855ac8539f141cfd72e89a0de523cd72f2cc65bc1ce9997dcb7291c4424ac7c4e6c2e1a5982d36c6279fc3cf437dd149b5971db863aa414fcd673c84b159828a1e9fc66412c90a70036c181425d6697b84515b11df40700f9d857f1026f711c71ee06e94e86c476ce1cc6cd1b81cb8c69ff05a416933e06d6d3cd18761cee8060dac5cbdde9d9f067b4d622f39e8d3f4c221f343f8c1ecaf2c6d5b9287ce4dd85e43a99148aadbcba7ad20fcbca2908c27a0742b821aa2fa84ba5df63795b17ab7a7598b87fb9b728bac19576f6d9a940b44b964924d82e765fa33ad33924e0db10393f5c19985a36f3c0faa42717072f9e2d9a34e048004167c9dd0ed4f679cc12158d91466e08be8b694994c934acd82e7d452a9cc2b4408b084341a74443863cb6713d2d378627414eeac776fbb3cd793d76ab71abfefdfca86eda324276ce779afd6bb02eb8a6a8f232c0452273f73bad5729877460ebdf9a663ccc4f27e7f559375d252d37a0519b1fff036b77863480d83f0a2b529506d045422c94951b18b221a269be1d92846dc607d0da70589fcbe88f9785c6e60c62f37a940f889d7875266054b07a596cab30915957ea5f201e44ac5595279d2cc7e1565572481f395b24b2bb880e722e3d738a166a4f213a06ba7dd128e1580a5893eab2614b3fbf6d6db963071358cd20bb2547aadf04537d228fc6d1a72baaf4ec38c905c04a770f0b236433df01584455731321862ca75d60ee4b5fd7f5ac9ed4380ac7d113bfda8f65de0d5918109bcf810a3b401340879b4f4e9571b2f5c1c9fb1a71fec99ee75747f6b6efe9a9460c001ecdd2a5ea819ac85a6e5dd8886937de53d55d81ee982bb5d682b3c0e921d8ddc94d7122499950407d112d03d8c9310e6cb3f58e7d31a90e47a6d7a729fbc425871ab26da749446f36b70c8838088a34c3dbf02748996daf5b45adcf85e57a88049c85b9e71f2147ca5dc3a8d2e6a1f84b68bea956fa149ecbd97b822d50913f41f6902d4c58823d9e3ffd03a911d04ea493690bd0d4065028fddd9c3088edd487b5887f8588cbf8b70d88a160cb90aa62536b6334c5dc5001b3e4485dfd4b8de407b1537299bcf6c36492d7b03762e3122d59d2fa0a610e8d4067a0bcb816417b52b34ef41807b65fbe7545ad51f11a82b4a395f498bd87b90915b19d7e1ecba217de937d3f68f85b0e23ca03438a623811b25505499286c3d6bce49b3bb4fc701d5f45d9cbe229b17ec6b901214eea6c5bc2b28e8695a111e9c8e25360b9dd536b29193ee9683ec8101c3d02276b85d7bedc25022a0ee8a5feebe209e568e868b66ab75febe44352b82e8b6155517c89c4442f265a25c38466a0fcba093ca29c4779b4a8886083a39ce39c6d6c836476ca3d497a43c7fc9621e5eee377f5b295b9aa40c0592f460388ba129eb18683a861b447f8085f42df80a4e58f068ed7df32af9078671d953e839581a456cca4d034aa923db9bd42b0723c46198a237c0d18cd6a6481e08edab6fa438b4743cb2474486e4b8035ad6fcc4530c03068da1c04d62c472b823f2f11d7a5e6007c84b2a93c9699e6696c29ae5d0a4937b17d0f4344053f481183087c2bab8fdc5b87fa62873cd53811d911e598ef194408376707b8946030aaf60689f790ee014b8de67dee1ddccfd149e469a9644a4a996b2f8a7a8d8ac4437209bc8df37ecf054c9fdcf2eb5c7cf87d2e477a9a540286e6d821e898f2ff22d5bf63bdf879db340f9dab9ddcf984a0d53f1bdae520ce76cbd19d5efcdf1ed36dfc1259aa6c202494bc4e02f60db1e8cac542162ad04efc1b77b4db45a73604514e3519e65224ac4ca4fcc4156680bc0a7804ba455c8f673070a4c3fe00b02d5ebf47598a635a18099c18da48e3c5fea6421b6711e9d211b437ac2ad60ada11d3968a7e729f6850e60a06c13cf2db1d17cbb4ffe5905a41f877bf454a24909238447cb2ff6f60497aec953c884b35fa82c4496896c765fecfce8a2e94f8d4fa7160d356a1538a0d87e80538f9f0185c38342c8e0b5a7553432ef4185b06dbde434887f6b2f9dee6d0e8bc59a458d226ed979d86a342b2b331133b72d4e89dcc152da2a6952ca3f67ca0b678d34b77dfca91654d5b45e3177b9f2888c8760ad99e99bf2a21a05dec8a82e574b1cb8aec136f8d9c58e1d921cbed385fd5ca04cd98b20440415916e30f2d38c211a2d4bb96e82191f7085c495f65fc599f30628ed0426078bb8fc2a81eb485213d6b9b8e3ef5ebe8d3dd2d2575a11597e50e26f7d32a4c50a9fc762a95f55d07b189f4039af12e4f3afb5d1bf642568007b70d96e9e93433b306dbf826f8340fe257444366729197fca98c1422e64943d46fa4f36db1e819c3096b59e9b24ac4e0e4940943f6599fabeefebdc6d14eb9165edb05f330ac5b6c0e27d17fa953c96a2fe53908b8d88c4cf76a18a8fac1641b9172768f611a7d3c904c7d0dd0a0f7f732dcf78983d1f7debefca4b0695f1c3955a3ea6bd61561a01286eaa89249ce4329ddcdb6bc11835d5b09b4072d14d2b1f75addb4a908b39fc3ba179c6c23d89688d4a374e8fc4a44bd846400cd0e57fe0ac52c3da024e82b94c3cdb084685e028256418cd8d57430617c9c14884bf877dd871c74ae9498bcbfb9173d38722f84602a18575e2f4185f5bdf44c44ae305019471ea44061d52c08564f9259d3d73d328a636ebe6132ccb7e8d6b6841c1aa00c93f177c4a270b52e3579bacb8c37d4badaaabfaa7758afdc594a2d09cdc02f66d89f03c780e3a001b8847aaa2831d97c6cffdefaff8eecde42659dce336870af544a12a0b1d58af12e5886ea048a275e4a25cc01c98d8b66f2fa2b5c774aa18528259788466897d323c54ad109d97f05763c8e2e1c2ccb7bf7fc0ce200cf596c6b8e28ba55666e0eab2e3fdfb6d5ad00dbd1ea6773fc56cea76d806a02ee0d8cdb632039137e56347d69e18b46715a5f4809f6200ebeeb8dff6f6838acfeb260657f58ecc0e0c5e6a6884bba4126c68485ba31f37343ac04e89e863c893f129f3e92a14acb844976f6175c01472b24c56d270116c7a72306c070b99b18822656006d40253b1a7428fc5b990b717c568bd05cc7b11f1c13b9c2907ce224bd32ec89aa9c891999dd2526d9addf0734c78465186b42accea6778b5f06dbc507b27886c515172a13e991a915e7c7f95d181b30d20a864f7b7c3d8614c6dda8e1475be097025355c8a49d671d9b46723200eb0a9658b803676ffd2d575841afd2336ebfc1f53ef211d4043bcb34fe88c06aa0c446706b8b3b2283671eb71f9568e39e1215ff4372088d534564fd3322fd25554710dc387b47f44bc4fab8e1b6c707e9980d9ff268ea72f0e2afb2f0bb70090cd1b0c94b3d61031d64e7d23110b6a846b26cec0b5560eba1d02c03e54320f19aecf6aac4aac952585b8601800acb40271a67fe84c7c317b3214d8ab36dc2728a8135a780278e48de7475467bb39e9b7343ec8f8d08ae9532e8800400c6089778d57e0a12a7cacd0a7dc5b5f880e7854073ff2109118c9dc04445ac2f0e7ff78b4a559008c6ee1b841a88c8d906b00ee5acf97466ec723495241af1ecaa9fe5b87a7427bb9356bf05137f80345092d3fc339b623a826e6d2f28213c83dd1b95032fe22bc7f2687b2c88380ac3ec67ef491b7dc6013b1ed877371b72028ab0a506ee4d36250438335c1f7f3cef52435f7f7ec7495431a1644f5863e4d1a4250d60aa2b5536cfaf7de04c51abd4de05ab98d7869d64df4242174ccda7d22ac7322379e4d19305697244e5124495030241406573cd425cc4ee9bd4d57c033f277ffaae35fa1096f3d96e4eaf36dd302bbcb80f64ea5c4a7978dcb8de06b1824c9cef5a7c72d741f6609c0c572b2a65953f24f71cd42bfc7d29a019767b7b5885e1485bc31a8ae30148020032cf944c79cfd3b100d76ff7c99ad6641b161f3432ca1d70c5db91064f52f86f977e71b5b5f489167e5ec635081fe9584180a5dd21855e35b95e53ad4f8d6b372ab4a9a39a6abfa482a2d19256d5f63b837c4f3188bad3785f4514d00a699850f37fcf53708d2a0c06915286d87adf1f5bf8d355063c7d605860e73e537f15f4806dc6bc08d1093b77a6025beb459624ed64e539ed31e95e8ca5ca440c5c5193455a43012b7885cad713249cb47ce2846c0283a0c490e6880c57beaeecdd5103e99851790f4011afa5f325e235877a5a0bfa96d38f535810f688019782d41a36f358e4265466a0468721eecd40f8193352c4f6aa20432475984255634430b6663022534997844970e1ef01bc69f4f63f2814369d2f745cd6dbb6089657f6eec3d081850cd36827b73b8fc911951ad2b761d81dad57462aedb1102365ad864f5b7559b924e0c086b05d425cf2bf8d36d99cb56add289899f8a7153e27c6a266128fbb88abbb8ee24c4f8f455645177cb1c9fafb5a549f95cfe69970c3f9771e732adce75ec10b16acb8b716e0f22481889b92b846525942a72ba408a11c751b59aa81c7504123e09a4162c554dfc0911ba01c62e4434b542c78fbc35f576520ec9d2115e4e4d5a7369eb72326276a29a5856c96ce2a86635025b70f0ae0d84f92d5a8442bd4d8c797b71d9f2df80ec33f2f8f36823d38a39bf37b77ad434e09704aab409291dfda2a8c01775820ab32aa38020b453c68d7bf2b9dca0401d51182d56bae2b78bfb411ec771ef526ed0323de1777690c47c9a20566f74d9e86f03b33a4613e80c45f1e0c341fa127e0e68d36d3a2846c5b4e944a2da195f784658acea1e9134be42dbea2206f4555bf142020aa876930b272764283095da7fe21ff07c27489516d9dd280c12ab7184c3c55df743977c669580e6703b0f98bf269730b4036ffd27bb32df59e6c8f996f539c046f880a99f85b2602917da7059fe718875de643ffce75a9400f7363574b9cbd3223d7d718cb7d2ec3f3e9fd3582dc4180ea186ede1831c07fe295a4c5288239fbae18ed1d11deab78d40c1217e6bb663fb742dbfd620eb36950a025045a1296f1c8cc58d69f6e99aa882101be12048017edc87860a4a9e53dfab05ab783ae6ea58b237d364f0e1e9c5871484c94ec394d6cbf4da1d54ddf72c08ddfb9f4f0ff393c5ad830534777bb1d4f4cde55f3659a8837f459e5d729ae3184105352b3e69d8fe44131ce64e0cec3808685f7ac4fcd40684646025b97caefd5464f295e8f4e682a74202773e3b15dc9c2cd7eee918a94fc7c454ec9b789291769d0d32ead9070df8284ecf81f0cf91b56f2e79871bb100839c550e1cae97a346dd6c62afdf4edd7e810bd910e48f717c159f6765a5bd2f3d601cf63427009544f0fa6abed4c316d45f10e50afdd501d33afa9e105a6e4a01e5d6c9dcdf274e015b7f9f008a259974f18b9e4d54aab50c16ad33831590e00c96f9d6af6e3c016f14a652b44a327787dbe7d3ac986e84da957cb4aff994b940a922e81ba2eac0b8f4be962e3ba8d554dff58e8b897ec40d0c8f4a680cb11a228bf3105e32617b096bf67b319b64cac1d4c2f74445371329a21c6d403f65529de61419a800c9b0247fcd3cd8f96dbbdcafd730657e651519359cc2bb5b08d98f819158ca983629e2239cc82d13e46631162cfbe46262b1c7dada16f2c36d9b0c520ba9059e92a496226f9736c94c39d266c98530f51b2ae9cc0f3a633011e2d730a6a22563b272306dc398d5e52ac580310883bb690595d3957542b4ed3a711dd780585f5982df60fa42d3aece90db5fadd375f12e988d65ee80b90083614da7298a8bc39ff1d9d918a65f16ddfe890ee74db420f8964ac240c120e59d942b0eff6f9271b56b23cba943efd4d439fc41da041294b8f263f3ecfc14298cce3b6b22fc6365067143721287443c2b33ecc42ac551b30a3f5f00a75410a94698a6f9a87829e8de2d9c6b2564e118ada4c223d8f44b0cbf3f934942d02a4d4d0511a99c530618cf69b5c9359f826644addd9270d0675e06fc5d1ec8bc2e480762caf181a47ab0dc13a95462d5cfb93c3150bce59c9231b7ed5034e647ef9d4b21b960d0d6a898bc528551ce0fc3a027ffbc48bb6de3167f2a0a4e9b34498774b8f03c032f46591f1e5b8e8900d1bc41b404b1b756afce3c3136dfda82d4cc1a5cd7b319a2b314c33790d4b9ac47c22083743da1428b803910891909bc200536fc5ce2b45df325e0facb0864356634716975bbaa784408a06219900948d87d54e7208ae128e29792e4ea8fd560097330308a7e8ef08225629fd84ca6f0a92e96c2178e5184aba21dcf7669ea49a2722e93145ea34e90816ca4306fbc759641a882854e50d0a4173a06cb1d40bbb4af82e278933a5030d220bbb944100b3824a05507ad6dae71861c8d38cd42d68c62c7ec37be50611861950bf32661865fba32df5c787b951a86f8d775ca81cf594534503a4d36b76e495251a8855801b0d734579b0f8bf4725a16508503bd16f46afbbfd8a31fad25ee017ce43b32651569f5b26d3bd9e4db1354910b8cf51e40040709681115b9a05d8c582ada63aa48b8ad53f186f716852eddd94ca08a40aaceefb10a4515d9930277a5f10a19cadad1eb3e9f5930cbcb2879ce29c67a6e08fffc77968e454646ceac21dfa2704590027552259af8edfbf5c4bba74853c5abea7f7b512872d2c338a0bed9bd85de5a6b982f51d10903e204afdd090ac23e4391db273bfa630750ce748308c5428873b92858a481e771b90ace55c5de1c6ecd36def60e73e43491c9f4c787889a619d90a82298e3b0969a88a03ac0cedc5344acbfae1d3d1b2313084a2da8f87ba1d6f82dc2de50c66cb43c0291c5c8cc0e7ec135534e3e26ed040915622d22c39f7dcc0a26f137b6daf65acb96aa95ff2b50a6c7ffe7f2ab0954ed6e923f1809f872857f44e54c264ed7732d28376d9d4a1a055007fa10fb923b28d259eafc47a89e9756ed4357708067e0f6de7c969dd6200818def3bf5c421dab786992512a3939f467494737d48d0c0d9c79a78b7af3c2252418475ee41573d6fc47c9a1801ec50ca36862b1fe984b313fc083b0d0f9be92476e760416115bbd4bd87da197e1cd83874cda87c0797136c5e0a578e55d7e71d8aab97ffaf2286a834db791270e217c0d9fd5f706db36e8f24d481e821f17ef33dd99797e3674fa560b28a1f38af89d1312020f17f146a36c1d23dad75c23992c613a9124d3e5545cfbd3051b91e55db54b1b40bd43a3f8fd9493dd1e3d5f6e48ed5a29bf429a614671f9bdf410479363bf5e4a7ffeb86d3e013628fcf8baba271c94e1bf6e1f16da3d772b39d75304b746201a950052c08f9e7d04828e86847d186aa1335601ad0204e836bd51adb0345e22508484b6cd3cdc9c0950916e318c33b0e74e7f0de57678c8e712b1c49ba01e7238a15686ecc70963a38636c5631ec7df0b59b85d593f2817ecd8a432bf6cc6caf9a9729d7ec93af35ea781b68ae94b550133c35b7da0c8e0f8f4b0b2ea4eea7dba7d39568f2acbf999916ef77f3d9de4ed73c38969bd3675a10c04c9c8902210671f88711973785f216f81b6be9043ca3144faa6767232edb5f6bfa7963ca3d1c9f3d5d81b28ae4d5cef5e22275433f5b4ad917a7f211bd0cb08b0ca7663a2153329423139edd4443597871300b00019ab45225fcc210cff1104660cf48339124969758af975e8a5e7cda4d37e4603270c6985d5facb53334a215b520a61802926db529552da0df2c0a1d2463628b36857e1e1d94813e212d98c984013b66246fff8bb094a59fe4bab6ae159bdc900ad4268d2cc7465d74fa49cbe73cf8261180d1c5b71f0ed938ae74eeba71cdc19a4a5dc0028ec16553fba0bedba34897f73a25aac2a8b7c79fe2a7e287395812d434c3bdbab6b0a81441d6495ff76dfbb55319af7c93cb4b6e9257b095d2c008844dacb0825f6022fde172b29b9cafb5e2b7e622c789d22eb73eb78461043a173e2b933e28fa50ab224578da1dbd6fba8d219dcb0fc7d15a2c1acefdc32a07dae30f0177b15265ec84bf153da268cc814640642cf9224341849e9cdae095a95328ca43743242924f9c1c61e924c9b38e117ad34c2d78e90c5fef223119947ffae2460a98ffda68add68482ef2a462689a320894dc1ca21505b993ede407aa849cda1d073298c966dcbfd935170382c4d38eb7a72f533645919c6a71a48628a91a831da57ec9c9b76225a00a47dd99ff7b93046e2f6240cddbba497e997091b103c0e144aa447641422b238adde70758c94311ed098c55ea92b407569cb365a8563e40474d7fa959dab10cf06a34392bab28821b43e00614fed85356c3a1aaa55bcf61260f3bb43e93d97394845a885e55a0be27988c2c48ae0737fd175fb38598c3463c62018ea43c5272098b73249ef7c4befe1448e86384c893accd48514f76da6e391d2a91e7cf669eeed8971b22cf808d0e20213299cff0f6f5860071ef14a431ca3c91dcbd96acf168933efaceee2b411c3a05215e3f23725e70a63ca02945f908726579ca97a85d468d75945e883d9106a53dd93265564431b5747abe0e48d0cf96782189dd99e06ae73e4fd26982f595c6ecb4dbf3507304c1a5511a345be9049f10fe5390c22dd52d2aacef0235a87d1c5cd7a8da2825b12d2e9bc54b91b6dd1857f9c7963d8b58f6c18e05c073a3224ca1d117885691f9458d3f292e54dc6fbe542aa982b9746f1788e8e0a318e7b0e24c458a7d2389646df1fa468e8a4f0c275e5949e5535237c57a8ba7699316ceb1d407f199ac0893679398916ef827ee280f3b6e8c027bc8029ae130d35de8f4ea640802cbb44baf51c8c9ad262720902dd02424ff5abf0ae738b83fc0df9eb46d4e17ea60b3b887a273aab899a30a0827ca0f79e0b8bc65829edfe9119cc504a7c2a691d102e74efc41000a039c7ffd13d6267262f82b4c85cd8986f274dee642e56e0009e97e887ca37137e0213be7c5c6d16f771ecd40f15f69e95ecfa5234cfee5a426aae4cacba826f1fd7bff17633cd826251768fb6b06f0dd44f50c599497a60015dee1f1ba9c3c16d5e3b7cdbed23ad6d7bac65004cf4f9613977563f6aca206135003781de7617aa53590432a14a841c10fa17d3b7009dd31b0150058d569b0d735430ca428c4a00e98d7fcda98d9afad85c07966b9d0374b0c38453bbc5c36c331a3337a0bbf23730783a31f860fd166eeec27db2eb80834f5b84625e345207427fc3d84633141c661b4489054fe0969d61408c6162f6f513c8160516b1aea89ed26516407d5605e6ecf9d77044c1da1e63ba72d49aa19b49f1e4844c70e0e212ff9467ea48b4a5d0760521d03af1081b83fb61ff05c664034c70e4a230ef8236b00ae89c80e62a7051c911d088c2abd88ec8033522a68fb87db47dbb1d03ea16cf1c1c9273d99ee14c80ed27da91d1d341b0c78d00e1e36723b956a09d4ee7f2eaf586707aa9b7e44ba615d7763ddc85fb3dea804fda11ffe45b0703aae2efd40b27e5fd01f7096f3dd9575d2325397c3e0e09bfc5308ac41b21ed448b10a32823f2614ec147dd003f97857224a761bfd7c87fc01271dbefd6b8b63831746132883b6c432b878881d462f8c64b907fe23e234ae8611747aac8dbed0dad83849d648f99cd6b6ea21ce5483bfa8c6a4504021b72de308264694001579647cb42e6a66a07277a56b8ee3a4c50e6cd4a65961d14a67a7b84fe0c7313e5fa2c4c43d738380d8ae5e23938b361a3eeb4d770fe657e9a198e0c4a623c17e337d63e9961024365682ca5634ae910e8e0d2d495300ef162c670b78368f3027a87398e2d36f36948c8313008f4e062b85f7bdc560c9a66e1c91ca9de004f7b1cb38ac571f9a81c587204b47bda16e60b7d644c7fee79f66f2eab53edcd93b3bcfeae6db6dbbb63c21704fb048c8723129d2c40539d862e6f37db337df49d1412695eaf3ed515111b2a4aa0fec3dd429d127b449eb60a25a9100f1466ddf30d9c76611a89e3672b56fffc605839890635541cfa5362da2ea532a34eba9b10c9629fa14ef1bc0be4dada92d00906f811ae3028297e1fd156f84fe4f0303bc77217be53897629b1142cd96c9601f57e6725472c0b3716c2110e1b20824cdce5ec02640fe2bedafaad274dad4bf6aa8d662b45ac47cacd2d74ba53d8bfcf92957966010e825a1826df349107d95feec3cff04a335d96639134e7dba1606dde82c2ae0dd9b81d1651c37ff369601587a6c53fd5cc8c38adadfa2ba43c934c129e653658372f6ddb0df3e33544caf26268642839cec97119ea1bf82efad609ffc42b8dd46d474136a7986eae95973f7acc1acb8195a70d0b3596d931c24857839abe40c452e390bcf33e975a4e4255d487f5f173e56bc05db85fb98a7c8069d4bae97a950ad51fa6cdd788a20e4d2afa788191c2303977955ba1939e5c8594670690a369f956d10cd266b1409f0ef1b30592a01fa2a6b777e25149d24de86446102c11584e61e26f9d37b09f735eeaf68607831bbb16075211d896c5d27cdba5f99482edd822f44042ae570fa249e19f50563e056e41cb4f019935c04ce1f478ad260569b721afe497856c61af92923c2edf16028cf65477fce56724b13ffc3d30991e89b29f101831d715e00ef4a304bcfa1a5277a94de16cddf5eae3c5fd9ff562312777e04f4ed4ea5243179fe5f44fa3e64f26df2d1df59d4f73bf14b82f2cde5bb9c5109faf9eef0893137224a2066a6f9aea3358f664f383d1b8b8cf3856f80334d3958283f2d7bd74902b28f1c888b74948448ca1be95efef9a2ad0a18c57fc9759c6fb907c41c89d2672f12fc26b90b376562288e5549e95aa1ca447a245d842f19fcd5197fc771bef00cdb6c4a56854b006f6448cddc84be01382325e85930ceb74c852ffe206421747bc45ec856dee7e67c952a78c255b9e6a0f2bf3248e97935a65cabbeda869884bc533a94c7dfad72406aa24c37c80c23419fee28364b0837c7d2156c3a50b051e2d1d49cef66b9d7152509b126bbc7d7801b27c515311175deaa8384a0ec2e3e715aaaac39ed95d7de7ad128ff1273bee0d7cb3fcee70f3819dbdaa1339b41e995efaeeb5a6a65e7015e6ba1becf7bdff67973b606b5c936b6245d26d0af47fc746b53a9b4fb3b30ee36fe48970febe382db3d734ece3f7d43d0c59299686871cec6cf7e09401317d21087284f384c9d9ce30092db0c5fff2bed078e0343c35b3011fd138de43dd35567822f7a422476a558a381c231bed794f72028b43eafe664ae5394d4db411e5203c5da6a32658a444b4fc0ef4f3c6f661e73f1cb09048b1557c8fe6fd5885c8b7122b8ab494329495597b1e504df7e399e50ab21de2ff8e0f6b6c60d792816273432c029b431e8b17a111a7a3c1e759903671cb8e1ab0d924d294be502495e23b5efc941ca720e1e0bbf2f56352ef8262f0a62f6ed87d4629e4fe09893b676221de295afca56bc3247eef64e262c9377cceafec2ca688dd873c4be3db2abdc246a28c7cba2de78675d7361d76c840a651eecc0a2db9ab4e2244c53ed942c3e2a3ac6910a710b39cddca4ea2e5c52b2bc660c2568a3c7583060b5a38bf4c7f3ea190ba8dbfd33db917b13c1bb45217b54019f53085be7e1de821d500a90c64173c43782a49adf5f5181c80dbb7f41c1f9c9e13468140635d8cad9f0486bd0a10b1ff21bbdae377caa8d3e764b8b2439b38708578e672382de17b17a20b7a7fbae90e62080a143073a48098fe0e26727a84741ecfc5bb473b59c71fdb84f3caf7b6d1ccd13c68f599f8fe40efe26871f641fd3c2ebda29736131809387d833420d65c2360541096242876668f6344351d469ddd307640f6d2f58d48586c90cfc69340d7758d3ce9a0d9f2775e0835a6781b6806871a5ab7151f2190168919d21b95ef3ae8bdfb28251d50d6650cb079bc6e248c427e34a7366e71cf048584a90a9f7d185180076d3325f4f2c30c1be23a48385e12c2b3af8196e47a183e085eb1f02237317a52f875576d062d2f0e9b0603350312819bb6bf690ceb789319728b7c045ceac783437796f38b75bda27b9a3d581a34c3c5d6f41b982b017a991b3147c019656e02af822f1b05843ba721b4ab531ac04c383c3385c0a76160c84901a579db7bf4604a20da31ba8ef88886a123fdcf95048fc3a184234c59a17da25ede799bfaf9fa3b7e6687dcd87048d5e92ff39a229655c0d55aac3bcc07fa3684e2a357854d0e4bb529d7af08128fab5def92e858b01e2dfe27552b3cfd03c25cff80c77490782cb0d657141537ce0da170c5315a42671bad21b472d2c6ecebf0deca0596b2af5111695b398143c4c717b1bebb7ecdffdb65c62a81d5af918cf6f0d58cbd655da5c82effdb54960ff63364658aace409f922f2671e66358953347a58481570d3c0edd9a9e0a52174873424555dc29ddf8b9a5594e1751004d016ca8570be745feb7ec6b0a47cb2cc79e63af02d06865af1ffe14576f562e536f7437cb70010b23ffe718649584d0507b4f63714be9047529e808aafb75de0441980c5035a980530c3e38886fe823c110e0b10f54a8cccbae674f1126abe51666a91d97814a6970a32d39ad5f76d83a3319d1865bd14fa2fae908edff19564b2f6d5632d9de0e7c0cd10471a0196629a5d61e99b09c4664f07a8320faba24164460e1fb4e263a4d2c8cc356f51a08189f95e2589db59ce086e884e30f5dd3e3902ef04d632fc530cc4479f8f166a3b8d6634c17c6684b2b1ee3a6c5b7eea07082fa4c2199d5279de8567161f48145f7de3af54e94f47ebf4c066ad4a57abcac1730896e23cad79aa8b5f8b57e4aca258fe438d6495649024f0e308b376744b5c662a6d1ee95c2bfdfff2197d486988608a2aba9efd1733342e704ec0c42c80ca78f4b6a4572106ead8947bcc8c01735d465d4c4b77ed1974cff9f3e28a04137b0144b52a7efbcd81192855b8c5f3b9ad29f195de871c4926d4a1aea5c176ebb4abc54bcbaf0563bdcc26bba15a58f9adf699d4e5d53c500d6f55aaff687dc70b78e0e3f762e240385cdd1521f13bf5c2d2ebcce37baf8b5118e905d15180be43f3d831c7c91ba7674ead6eaef5a18be999e09bd51f94156683f40afe48e87b1d1a77b02247268374ceef84bd1cbb8313c75d3819655e66fc6f8d522b94a518cf068e4c9f76d72ecd5910c8354f7d71bb194007723d16be13bf81c37961c4f67cfe9b853ca7d350806a6f1c758c47573fac9da52d46d6675e361f698d66588260358a4d918f59edc01488f30e8ac6ed7b5af8951aaa062771fd4dea41deca000c2eade0a404df79f19a2427905b1cde9fc72b0ada361dd9147a168e2fa1aa46304affa74a4e6cb3a68d3b9db3d248189a350a6735677869ca4783bd1ac7663545ce792b1dca963bca87db8578b52405837412154a84929027719f8f84c62a2933f452f0ea85131a970369b24df26211f74cbcf37f263ac32a22e128d80981151c435e4a24bda86b105873e3d8e660a8cc23e1698e8a146a5005f2054e9db911faa763fcbbc0205c86ddd23e47e91a76895bdf3f63192ce712ecf12c6d714cba02ad6b7c3810066ceac7da83c1ca30b34386e61e18797161fc774163e909b6252152b557bf6bc036f319dd7537f88b4358a241754aade0d866bf689c6749151dd9ebef34216107da9ae61a0ddeca5d3eba7ae18e4c9653d14865a645973e5546bb530b430039486bf4b420373355953677a5f0500acc856c816a874d831f3ed858e9c1e7d3e2a00f06b475f363a053e6b846945b6b53e8f0de71eb37a10d49252acf174a529d4298db602619e057e041044331ad64caadc7b737898a93849bcd1ddd96e9f81bc6d207dca8e6f1f187a0437101c8d9175d6ad37057a3fe6a7346500126370d06b8c1ec92aa651ea3b7cd17ec37912f542132d448c3024f53e8d6d47ea321e98914b0a7c394be700125276e155e7256f3c532c0fd5d1a10ac14401137a776be45ab08127d4b805f9c83506636f4bd64732f9875ff0bf5a69e0fd42935c062cbbb816107e9ec3ec6bd5688e4a9b414ce28fb04b31f0be7b5fc48b80d194ed333673a6b9a938a8260dbda2567726e1664fdf581fa5c24a0ac561909f5f2f03d204133b2a38548f56e1d750368dbd4dc1cf3dbe246384de6122e22e2e022202fc7b060ab5494bdd6a67f48383b21941f18d376fb4099998f7139dd6aa271573919b47466c16d0cad8580d00cbfbe55fcbe13a0efef82ecf1bec2592070cd366d9f721db3d9b48315ec9205aa262e35f2868c4e33b21a0f1dd016ca436160d6690116086294f17ac4c9e3f402dc04c940d509be40d54e10893d8e96a77eccd6ffe7a6b268d4a1a22a34d1d939fd67f525cb21b8d4c60a09a22470112fedfcaf8deed7e963597e885c8b099843db0a8bcb386dda43c9f9961da5e68b1582d985830e6bb5fc285a07c92c27c4a4c537983cf5d6e10c1dec23d657b5d612ef17650efa05711ef6c6f124bf152e856edd78b2a0f1f0a43c88f71e1f15f40102d9bde3a49a798fc85eb214e8a0f72cbd3b256d3b5180a832cd500359f97edc354cdb90466611ac6418ecc6e40c4f40df5eb56f5052e000346f7505e3fce4d5d18ee27e30114a96b17d02b1dac569fb06f4cb33b85f8352438b93d9d4116ac376a3d92d93ea66c69c5440945f74a43ee38cbc3a5c2dc35f2632d6ec78ef6479916d47f768b0fdf3715e402be01bb07b85e62bb1d8b466868a89e6a83a8f1bfaa8a2775453530e4122c9f16df2ef24f77b7a986ec2975ddda3678406e06d0ba7c525d6610e773c83d623979fe9cd23b00d67f9ce87f1cf2dabe327792bd225d9b3ee225fe9de7427f6c3651910958ffd13cde55eb05d90af8af11211745872a595e0ad787b6837055ff53b5881ffba8833a332ae57b13721815a47540549e03a9d38b6b89aa6a0071439a390c3414399cc49d0a27e33259696df06ad09fecf329718eae36f58219823d8f816a0764efde7542999aed9ece46319b876ec8219c4bc8a79750b6e87d02623e293a63b038c50656abf90098de7d1667f0569a36a5cb19f7f2baa481ea8f53570bb0d744bf5ec6716f07c0a00ee32d835a428ef30e3071c9b278fc19c4089c1fd1abda374c939dab7ef38083315b8ad9676fc40765a22c727640fb24635b86da0e5b9ee8faeaa1811c5152154195d1808354ad9da2a5ef80348786b0c482c7aa44d81f39781ac2e9e87616504ab229033de9bbd63ae5ae105b9f282ac1e82a3251e03b2955191efed4060db9455710c618f92f4f57f512e5eb8aed02d74d71bcb11c0ec2e9c4e299a8ca72c600954829c32ea7f67f7bd1e1e1f9a9844d9614cd8f5b78da4bc455638707a299050ccdab95ad4d2a91bd9f81288f09225871a358af4ae09ddee54edb7801bd51ee01350924555abd312590b106755314e86b4c6e4daf14fef4d4cc60e7f21827bb45d5612456206a2bc5059010ab52ba3ab568fe9a8e1ff303c4ad6a6ab38de4887af7107b9cd2408d83e154295cf57da5500f0beea88d89854d180389837902504e11ecb1f53270de9d5811ac4224c074463702917194b2c822b8149a4293c1f02c82a688b49a1eb55594927b0d051c06893720d4749e07a417403918c18c2becad3010a9badc01605b18c1e5e37b22c4f508af01ab719701eabc0a7489c5bdd0ad4e9e55a01bdfd295ad85128f288092325df61963020247e7816491842902553f9e4b05668a367639fc7cef98cc6afd0164891bdea9c9c25d386c084dfd13651c7ea16022db893f873e5072e599b55d627f513aa95bd8b1bea372c32893199219199753993a484ef18e8af7930c893b91c5206f254dbd28514a14ff14064365eb1449bfd23165e47cc87593a6a84134292963c87a0bbc8f3e0c12a3ea649bf499b87ec60845c44adea44009bdb273fc21d236ab7e01e0ddc267def96c6474096a8afe1a49f55a2da00a0f30a3fee65047db0d4da64ab1153a01b7c9f7943c0b8e30df564b149b7685a617388d5e2fe1564ab3733c899ab642e91da185d424122d84bf410f2e9e79064e70497869ef50fb9b9d8f463114c403296c93cdcef97415ce4c0a0c5a635d388547f47043c623f3abff46f9c14ab9b5f1c3357198c456d2019a69f448e52f532d8ed2dc474a96522ca1656f0a770f6626abb5384c437ee3857b212b3b88aad59e6b565d8d47b6b79543ad7e0716d3cab2907f512b9069d5c7de3785e068ce7b312d1cdab4765348d658fa6f539a5d8a7306517c8d37113868461bdad4b1f32a7919ad25eec686b1f8f84cea836856a94a07456a51ab56fc96a91be026c15dc5d9c07521a50582f99244e8750f9b6d575e83373dfc4e2605ab5812c920b9a643133ebb282cea0334f71e5437d98da1eddc0f50f36ee7cc78966c6aed662be312c8b1ea311f8ecbd349051c66e0229b54b499a77402f6a3a3f4149e629eb977c58ef0c0ff87f14c8a904ba219f297141efddad5617102021c61a5053ebae4d9c9e40123ca730744ca68a357114b0661da17092f2491aae12c8b9c8aa72d3327723554fa5f75c7a5be608e7a5674ff534e9e82607355abfed7b234eda1a6d6ab9ad3c35814553acb070dc85d0ceb806dcb0f69f71ceb8ce3878d708cc6b848e8319275b90b83a1a72790c117f7ccca65503c5ca178121a89eb47cbf575a7b7388b6143e8d551cf57c085590ad40f9ef56f84945457140875b882166d4a9d22e92a5779fc880595cdb47265f5ed1241bed76eeda69e00eb5d61b272bf792ca393bf73cf5b3a51646851fd5af9f3937981de9abfc75a7aee959e9e2eaebabb5dcd0316e0a7b13ec0a24e67e94cac4375acfccc01cc7496e80738c5d8f5fdc40381d05b8bda1e770541f9630ba1907cce783756c9803efd43f977c8903f59cddec74cd972bea9de860aa5c18db6e4b47e591b265d91ec7d476950bb3fdfd64c8022746c7366a060b451c0b502c9a9e3df5d74035bccfc9d16058f2ef1ec2f5c15c3f966850826cd7aef05814aa51a7918285702938a996dd0c643647b384d4f9bbfb85f70209d4bc1cb9a7b4100c31d220203b88d597acc1d6060e7b986c1b111f9d22a211640b5b8c0e4bb40482e09242ad3c80d6435d2445decffc44d03d8053028147f33ceab88dcab9b78592cf697893df46af231629a8c8b6436090e95ef88b66167b75c7b6fe7ee52edfe56fe2c97e78aaf11c57d9dde7d9c52627399313d27427df2885488164dbbd231b56761df171e81648c14f158de379333e83f9b7e1501e67ae5bdc9330f4d46fe320cb49d2b055d2a18ebbc4dcb008b9e41f1a72d54027cba7687e4419b658e4049b5726eb240e060cf599b58bc06966d5941c8ba904ff337ae8fbfe85fa838065b99e0a049a0b38d3bc5086095ee0d5a298d364eeddb1cd93fc380ae6764d2e8503201393b6284ad90ab557367dae61bd08b604d2bcf81979fd4a643b68764d4c387022799fc7be21083eedc7134f643312578f9fb2d2e6fb1598eca608ff3cf9a49ffd41ed1e525077a9b4f889692d4310515a4cf2c3b2379fd533fb12cd74ed248703ebd74bd544da6b8bfb83f97f39236b916760f5df44423479df36bc6c53c5d4f03c054ac0a85d9076444e85026ef7c4888c483b2c46c010350563f5381bc58b5af76f2698b0f52702a805f1a3cb9a7c5e423186f93532c686d54d9f39c0122c357dc5b01cf2b88b2eb8bc7e18576a30d46308c46075267bf043ad3aa4606f8ecdb15f860c69d4133c03e42c1775ee5ce4c748640e859a20502e97df08009733f5f1e93a8a8a959bacf20cd4b46ce47768cfb268248e00873d8e7e0ec1380948c087419910717c2a385fbe93b5e206d8106729c2b7e6e74896a472c953f9a2f80c82f2f285d1725c272ea735aa949244fc9f7005d2a43d23faac8e788dbe840436f21df1a5c0e11e16159ffeeeb6ecd8850d21ea0187c41cf27aec5783b2c379a04cb65a6c209337ecfcc5433d6df6ee600156b2043b2536eaf00aceb28ccd3a6b86ac0f73e8c9f407950221f1f77768339590766c967c617fc651e0ba92e2dd006d0818e1cd3df05a29d5cb5a5e5da07c69a3617f4bd035874718f4e7b437e20ed2904258405d2d3b1addd8f0c3e92507970281cff5b1618db7ad3a6405a868fa739c2969ea9864d8f1081d203b6628d50f6ceb2c26422fd5920974cb92dc8153227eb4e482bf12802fc626fba616b9cb30cf3f087ebec37f8033ab4bce2cd1e0c5e5886cbdf6fbff038784f9179ac2800608f0175a8ff5745361ba60d3835273e0d1eee2d1437e2f7f8fff57be2baf823d78bf19be36b1a485b84031c8075097e19a71e8ae80882dd92b507b67152011f2d3c737bda76db5d1d316f01efaf9e0ed0fa11738f5e8808e08adeca6ef235aad17838e0bd7cbf4b15c53ec793286025f6fff9fe46ec95637e1e095e5dbb8f8a115ca14baa15e373c5816d386c00acc88dd1a3e472e4692b1960d082ad5e8a062a953ae6d220529e4ca67f17df9bc69cc2903db8e41ee9d7ae41d63d56bc0dfe076790456f18bb160b7fce44df852d73d6067791eae69d6e9b06c0d8739433d988f0fc769f31e2c298b9ad0db0dfc0aff0a22f6b3c008d09c906b081c7131a886c5941c2d9e79c7db5303ec6e504c7b7e3cf24d28bfec4aa12247af47f3d5171d5d9dac0fec0387de709201f235138832da48a3432ed961ea72a140420a48a820c8676a9449b62e2cad85f63f64e779ae341898cb722d6b5242a1cbc49b43c43022c895d864a772881ac87423db7a94fff7df2d763957156e1b0dc2431f6545b9603ae4ab2838e0a5d7e42780ed6121e4548ff02959e8ac6581eb102060fc1bf5738c7321d4e5477cc73ca51388e1603e00fd6580b4064561c004a4796ce7c0f0d561e416a1a48ba26a5542456b4f46a38490c4cc5dc4f826fef82c8eeab2aee892b78dc7de1363c86b019d5d4817f067eb7a8722575ded07e5397b727081a1c00e90388dc9ba09c21fd16b23ff72a1fdaddb012e174579ea4290d4709511fe0572de5df6f1beba6054d3e8dddd03342e817ca82384b9c487db5ca88a4e1b73fdf500dcde5d47a419419212a025ed51b6e64cb18310994d6c36a95b7b8e1cdcfa4a27d917ac8f10247e40a03f56497894bc86cb3345863c7ff0dacc3f602c0275e46e4c58d126a59e171544622cdf587776645ce89df8007a086d9f1b786b7c50040e4bceab847c2d9fac05bea40a6848f6ffebee3fd053e30aa6803d0e9136b22639d1bca08785ae8fda927a81959ea3b13c84b7081afe73e1215c97bfee0458580d59453c853ccdab3447149d260a9f93f960aca9e5949f7a2ca6f7aeec4c8769a2f4738d79c632bcc2ea737ef4482cffd457f0658d4ca8874a7140ff6e76d9dc05616ca4ce82bd05b7402c3e18103f7e21b1db179a121a823043777d7ac698a8fda28be778df475629d4e64572b4ca5061656040ba3ba79cc3299c14aabe35baa2b457232c12d150a4e9e0d3b7a4fefea3e3815fe300a090e6c6be04e8fa511f7d9a65112d3a48e35fb97a03077500ca39f10dc249dfaa7ce67edd05501135aaf30cd2935eb06de6f204149e60d41099dc619a236b7d20634209c318138f3216a69a1c9770e4c3bc0999b33f23c2be1ac6cc98e1f48b4da194ca9106f257c8449dcbbdc525b7023261ba145fc4e616b1f0094559b7942176c7824f3969be8c09eba3fe4310ff76dd5ef39b018990db75217b3ed7577815e1b96ec5c271f1bb8d6ff53d859ea0c980335217e24324d4ac1fd5581b6483f199990c6dff014f0a6c7b46ffd0fdc1d035ab33d595930dad53607e5c8dc585e72aa45b8863fd60f0e78af06e43efed81b58131b6b27d4b4fbc55899a3031d56ec65d89c91a1060a27c1604690d718705a8e83f9457e7f9e6c1d0803e0fe7bf2e049fe9f8fd2464b9b249152ca94646205860574053e45755a29469c4cbd47d662f9567a29a59ebd3806eb9ab8f7d251278aab64431b924e4c8200b14aac6889946559966559965f7ef9e5975f3ecd975f7ef9e5975fbe17923165d08636b440acf811c9164869436bc3907c7d98ef67aa4aaee4743a9d4e65792a4fe5a93c95211b96655896362c4b1af35f9665f9e597effd7f59e2adafa0c39e96b021b640ca29eee28fe1644bb2a17b5d156c68c37074981a86a10d6d68c397ab34030c2349154e766fce7064dba8497cfed7a84d4eca904206bb94fdc514a394d20bf3b277af4ab9d9a3fb18dbae05c7fcf0eb303fdcd590922dfe8b81b2cf2ac8bf0b5444d3ba4e52fb730139ae6c67cf9bab0a5384385d40eb77398b4c8395bc3ce62ddc2bf71572104eee63c67ac4324692363732aca6871e3ae9c4c483003129119d084729c7711cb771383f080cfcd1673961ba143e7fd6e74a702cda86ff681adc4731c5077a0ffc89b6d1393c98a61a8073f5351318cd976841b37eb40d9f4247ac29dfe3f09e3db9f3e03931beb66aa7b40d1ad2144c01838ebc851df3cefd4ee5b40d6fa552ad9c0b7b8bd56a1b1ca6651bf66d4a350d7fae33a59c06d399985eb7ba065ef87c4c42071eb23c4aa93dd8ac1437e23ab57d380ab930f470348249c3075238bda0280f3dec74b84dcbb0e63167f4f0416524b9234a29a594524a299d18e7fcf9fc87a80ae35528346766df20d8a30898a04b8f7895af4d05640a2a910f2158562511f742784c2d51e76f673b140d8ad22d681628ea0485eae137fcf862b22ccb2e1a97c025a2a64b494b391d3a0c8d6a5d0b0fdadfd741cb287d8c7eefc0ec077af8eb073ebdd8fe3862c6d829a0e60a35572857425128cce650da36f8b9cea6c53eadb97ef02b07ca3f1c4551144551144551144551d4bda19110c2d0462770220bd4a3380c3a800043eebf66cb081530c678bb19085317f1da22d9f5393add17395618c3b21a343964e4755dd73499ae1d95da1db9acd4e693bfbd817df695ce15ad533401840483115a26922a884832917600294b20330048e43967dc073d938934994c26934966fb81c1efee340a72fab6ab967620d6e1f9f953dad54c8d408de3691545892a0999836a728de3d829cf7d918c580a96923d675b1ea198353899550c804963219988ef68d2c4a2f965d883e1513c67005a64fa9d8f233e4670a6625471f538f2e0466c15c2e73bda862b691ade4614610a57620425aa2528811c57230e57e24a708cd738625ca372857d52366181a1cab1a9944629f574321319ec548c4aff1472a5c9b142ad344dd33c1d4f87b1bdae9661d85e375585154d581bb76d1cdeb86de3f0c66d1b87b7546adb36ef25b4790c1bd0cb5ace89dc14881e33f84fc76b0ba2584a3d218212726a624a8245b1568cf1171983583948a886babc94fcda637d755d0dc5ba0ed234b80e420a1264073a08d28320a828c49448ae3872ce5967d5461a83c5b410af61ced42fb848824344c6a1f8ca552a8ce17f956a6555f831ecf157ac93a12efecd64013e84593d0a93cf875059b6e322759d7380ab542a95b52fab8d8806843585aa6e0200838cdd8729ba6e7713864c43eee59c73d79b5a2f16dcebe14904217e3deddbddb79b826677d3a7d76317c83eb6f4de7befe6850c7eea67738cfd3f14b04891bd2f640a81ac83c5f5ae8b8b32e79cd66698bd40c8321b17727d50a60273e5f3b7995d4c61b6ecf0813cec1235c3de5a6b6d6685ec9915727337441081ee8af495d1227fdb9b9a1f993e58e307ac0f9c2b1afcf3214992bcf7254496aebeae797154a4722453cdf615b95ab739b8901ebc5f6b9cf93db6eceb532f5d7fbb52069adb83738b1c201ea20e39508b38ec8b21438e5c6ee370d4dc9426ea9b3d67164eaaf03172a2078d691199fbcbe15199938cfa9426fea02e8c658a1013dc6863e17ae374fc9024cbb4d30fee614964ee734b877bfe3fb8e7bf83a344d091e70fc2f3f9c10683e32ce0f9dcd22a2a313a1ff957de07d7e5ce07d739c863f437b017f58ac6ac742ddac7985ad72201ee57de022a1fa30bc2a3d279ae9ba20e688a3ca029ea96c3b4683fc4a7817f611886611a913a52977aea247d726fac25ed63b8df3aedb5ecbb3522d5544b602d655ced50cb6853ac9a6a69eb8a700fd6d2a804aa715243b4711c4712d7d295611a892d79d552b6d512564b9ab6615ab66d9bb665dbb665188661d80f2e9381190c06ff055367b2a9c5bc625ad1812ec568b46dde8bbbd490c18126071ca81986d4596bd79e329ece26e3b99bcdba2b32fdb985429a0efed3fbb7d66b1c845a6bad1d155e593aacdd42097b10dc6a6152eb6412932426afebbaae2773c64a53355902164d7247c3224f56aba80da60daec89ce93cd7f512260d876927d3f3f7c6a2499324258720ddbb45b65ae410414c1b4d360de736ad5bd98f16d96a915ce7d2c1c241692b8c1285c17a7466bcd036b6566bed5cabd4225b64a9d52a795a2d4f89eb783cad96c78343c7699082b5d68a22c639ff6b1fcd8de7a8a190e7e5bef7da720b916ba9c1307cc21fc6e00cb75dc015007cce8217e459679d2dfdf88710cdcf067bfc36d8e3164c9ba29aadc51275c1c0206a218af7be84481d23cc39efbc5bb4966d91e99555f22c45d0319e0c2928c20b9fff006cd04ff17ded9b86c5b6cec7111f5b37b51d884ba6a0b4b71c8ef97518688b4ceb4f6e87ecc33bf4e31bb82ba239e77d5eeeb82ead7c42a7d3e9e42cc34a0c337c5e064b0c510534452b20950c6a510cdd8f23d8b3fc87a5e333c8685106b98805f42023842812e3697c72376a10f9597e05d4b2a2f247f011ed8710cd009aa24f86719b8e180ed01a484706c845193445db16e33d5088ca5017acab9d9597e163f818cf926198eb1ccc029a2dd218191eb33c986374169dc7d1438dcd8d0f397ed001844aee782787ec743a9dd99d4ea7d3c99f19c3097905bf4a1325a81edab74c974c6d24c98925460c31805838cee3a1c901877b3dd4d8b877d33fe800c2bdc65ea094524a29a594d29e349c93e5edd7183f6bf8a60058e0a35a648a669195b7b1a295ce8710a2958f010ab1688a3416509f20758396c89770210c51a4f9114c9c208a348a8223986089b47a04a9092d91664f80d30529d2ee14486a8012691793205c4125d230145054220d2b021454a148cb84ec201469dac602ea2751842b91b66d2ca036c2881ba4441ab7b180ba0826544889b44eee84c0f3d5074d26478c1889b4012cc94f54bee24c1bfea4690871184c9c3397e7b36a25cb790b3b4f2912d3e355b5c49c73deaeb6e68c2fe68c279f4a075622a52ac4fd49dba8389346eec0ca8433e173fb2bee7d6c2892413b6ab9401a4259d1987ca3380c062fcb8e62bc2562ce99edc5061a3a7634b16ca29e8ec807da519de29eab3a1d8b4bf2d90e94d9280d69d8aa3046476d10af87e1741ad2b08661188634b4f6e596d955be18eff5ec23ce0ec018a6d9bdb53692318f5266cccffe721ce013350b8f34d4c54e549da84a1b06398274a152428ebb5add253587aa0b25b0c6d5683bc085942f56f77a09d5f03c29c158ad30cef93fc7531ca190e7652e2efe8f13f185141c0018e48f98c15ead1ca673accd716f6e3169f48a0aab1386e9c8844194e3c175e05f57dd884bbe21efb460ce894321defa8155b9bac77814dfb0cd5952664c06006cafac7316f690738693e9e2bff2e273af24968f72fe7c7c544953e54bc8988b9e9488d9b91467b9776d6dc14d0dc3bf303d475123a68bbf14244aa22a70161593b88f95847125a9703e82290916c5b6d65a6e7bae7beae2e07f18ee66c2b611ad1e6dc3a604d75eab65afaa3db40e773219c6183f6e1b3a7a4c7c84c76ed6a6a6ea7a11258aa2288aa11a353659d45ae76ceca2fa824c5f730fab9cd18b0cce32026ee4ebef20d41b5399c1df8ee3388ee3bda1910bafebbae6e4ba0f253f9e4fae992e2e8009865c43155ef3e347f6d8ffd87ad42175116f6ac81a92478fa68bff689251c85f230ab98507017cfdb4fb40ff7f5dcb0eff5d8fb300041924d1852d82a08552047687795c2928a145175f37a7838c530627596373e303d7d1e2aa21a37531e7acb356ecf3c7d35a7b85464411a191a99a53b5aa610d925347505a1508ebaa54dddd1da2636fdb5328582ba20926910f219a481729d191d9796780e763541ea4513e5a2ad1122d8d4a9a66b79e344e04db69d756b56dabda76752ad59c69fab967ebfcf643883815ee8710691d100da94b8b4dfecee78e862d990a25659fb3ced3d11235512a326847d9db133dd9d169644fa3d3a87b85655bd6cd3963b37fb9fb58afb88d82f4823aaaac7553d5c861ee4a4557aa95ea5af14156a9ee6d194f5cd7cde5836a03d7755d97733756e4f999f63df86fa0ff5cef85643006d1e4e01e8e1e40a522c66661f39bd5d92ecf59af8b5bde139ff4095bdec4a1987ecac950fc496a625fd2232715e0d3beb62dd01b8dba4755f491f8d51a02716f840251263455494dc345da8d843811235ae7237519cd1944883ef2d168f4987a4569d6a2c874a6711e001dd3316811fc64568b22bb1645ee0ffc7c9f6cfbcc19ef743a38e2e7b3849a2a52f173823cb96e063d3a4b02eb01d7389c0e2bc8af850cce164e0cdac59190728044132d22c960e8a3223645418aa2288a62ad9d1f4c1ba0c8f33b5a9669dfb1d66e3ee6143e602214f9b85e080f293a72fb7998f6825a76b83f5da5bad7407ee0c7ba2258868b4075f48218d4757e1d9b0ef795abe97c77b8ac6e71f30495fdd168341addfb121a6952e8a9892909a694528a67eba3df4adc05479c2871a2c497cf3452d20ca5826b65328daa9c24a4911494131393c9f484c94d3e254ac95af156cbd432511c984c485a2d8bb24b9a4c319551587346e5e20a5df8dc3e685354455d4ca696a9656ab54c36c8df72fdfcaed4d5c42f158d59b99e78a916148fe9b28a19e3a4542a954a792e219fd4674fd4c55b4e52d99469cea04adc85e2c0549a4a53d932b5544b98584c399b4ca4c96432994cd70a0c20b40199265babaad86d0cc3b02539866f080df15f7f6d13a9a1e44dc6f2f939038446413748327d709236ee79dfc74fe96dadc66168cc0f3537b4cb51ae7a24ee28cbb2eceeeed6b29a39a736b5d63410f7f5c7075bde344dd3b4a7716d730fc7d542d74a69571965c6d7b5d61e31abfdda3d8d5f208caf8b3a6a9cac3975ec1089f0002214d262e9506121d77b6f8dc145fe0ffcd0f4efc075bf7ecdbd5173df723740e045188d829e73ceee401503584b336248dc7b2fbeeebdf7d2eb567bafb5b8de8de534978c4c4a46ec88030799d2c8ac7d77c39165a426c284c9e19ef5c04c5d92df3bfa7e942cfe74b807f381e9f9f370ef0324989e5b92ed20006814a0a8708232423a31b15fe9052253831ee10371f83a1a2c0f6f71407f1ef26bd9c1437efd1ef2ebaebf1607f4d7b2c34f2490beeeecf7a41225914824128944ba3744ea187177afdd3d8634a626c9c964c4f675f12b810411a2dd6ab28cb465abbf6f4eeedf98e47104e2030022b93ef83a34c78300be3a031872f6f87176cf823a3e903e109faf3e8d8fa036b9974b2cd94734943503b5d4faf9d86cdf22feb40de4b5d85246c6fbe914db2abb2bc5ad467bb04b353fb00efbabcbba161bfc6204feebd1bd5a06711797d265d865d865d865d865f8a2a2827d9354f6aac3322ccbb22c4b6b5fca184ca04e27146b0a9395125594d493d309632ce5ca329f33442efc099281c4b4f8449c928373c8669c7d76b91b7d5a32636a6af83e594c27a793a8042b419d5a6082214af04dd2de93b34e18630cabb141dd40ca1778d049e183dab60ddbb0ee31fe1504e6fe911a615b66b047d5da17952f68d6da69a7c51d1b5bd3384204492484d664145d3f2f900f7e4377b70f5b6be0e694c1900acc21b7f75e5c20bd7365ec7018eb27db699526398d27c8f56ac2ca8a528a1208655fc103d58884095648018491342a41c2c1109c71f45e42b4c385765d2fb9862d642b10d7556bbd735a4f167d5517c624d684d32a8a1255123207d5e48ea3aa474a2bbd51a96846158db9c944594959b8062bf2a42e2fc83a8fba786800a50cf6489be8aa010e64e0a655f6e80a3d5aad3b8ee3385e17e785cbc0b6dee762528fc6e76f593e9a61b08690b135c3bec4f45cc084a906a37164afeb3611482881d3a3ab464db9412142134f89d290bbd3a0b134e744067b341aed20f7e0e19edf7882f60ba533d4d3c57638c820a6251d6cdbb6b57a6cdbb66d1dcffbcf4a6470b63e70b2b2fd56aba58282eadce4a03a76c86053065b01711c4d0e387aa8b1b9f121c70f9ece6a73ec8566ad9d765ed8cf8bf1cda670041654221f42d0a0c24a1465ef43081a56c84288487b2166167250240aa2ad6fb801c4e1f3cfe14f83835540a72b420efd10419d3316490f69daadea97698c942fb81ba150180a3b0c851348c04d08019309d38a9950088970088e1234eebd84b073a75a6f46a50b46f7de1fe4fc00ca144d9053349102711f3781918c93e8fa16283214597c6837eeeea57a363e3428a24b850fc0f8c0a9f201111d50aedbc950971c2e0d122a3e70b27a3055d5da9266e4de712ccb1d9f4ff9293f234ea271eebdf7ca9052d3552c91b14506272902df8164361473890c2394423bc4aa6d35ddddf1a9187bf083e149624badb5f45a0ce49f18a3753cdcc5ffab3b505fcdb99da3c0052600030d683b546050426b5c8d754790107c11da71af2b546305061a8b00df9c12c5dd2f56b7680c0de70c28c6d7a45a0330258bd9635bafebba2e989c6f5c1de8e3bb78f8879f86ee91420a84843b0a7d5c3a4ce91e48451cdbcf4e87fbad0b627b6e7bae1b421404f79d0c743e3f7d95ce67117e5af2803a201ca2f6da6f8f3d2b88edb5b7400bee2ca0fdd65151744ca7d0162d411a8496301948e4e11fedeffa9a6538e6873b1ede3474984ab32830bfe811cd4a352bc5eae80f2125d13d275e16de161e0ed6c562b1582c16c65e8e62db5a6a69cb58eb323273a63ffc7692572783657e166152978f0a191742768cfd6554f6de1a342a5582d184c5643585848275a94bd376bd2297ba346738b144c74fcba7a2fd8794431f7dca074d29b207f1cdaec8a539d3ff83bbb80fee6203039386ff8c06e60c77ee060ff7ae07bb74030cec9b9c0e334aa67d373bae86325513bb8175ad2a92c12ea14aa55229c707f740aa9b39c33327d5cea6811f43a1b2ac860c0e3452604c92d9c74c4336b96d5c6419b68d66ce601f27e348c6e29250f03fee36f206c69d4291ddc6fd9cdd3daebfd129cd094992645ed180a13a94a8c5c0d62776d0597d630c04cfd71d0e3232d78533a4858316929648e2e93c264a85802924896173860c0ea4e6311821b5bb975d204e51d92d2832385b94bed8da897da23f421f6d3320cd39ebac5a5649b4da11574b29a55893b06fd29ce990c6ef0fac94c126913e0f88b130580eb30a50c06c8a0893c6942839547cce240559cbb08d524924128944b2f6a563857befbc531445ea7934a48d628be258924183eca1b73c9bf8b1ff74596eac2124113853b7033ff5ebae676022b78c26641f0d046708a70cb7484b5ad2520cdd7075a077832dcb39430cb2add124947a61e2a16c5032039939ef17e2de776df45b88d77879b1c1061a3eb16c510740684d42b69f13294d454585eb171d667ef4c39cc8ff953cc0f96cb0fff8b3b7d1402dfdddca402dddd574495dfc4b20ccdba1bbea5e0b71af4527f93ff1092a7ca08fa6286f5996652903671cc7d32a8a1255123207d5641ce99c18ff77163295a9e99691e971cefcf56559d6cf910cf6785d374a669fcaa8840e7a64c968040008405000831500001800068442a16040302094cdc37a14000d577a3e805e401c48644916c46008a2903186190288018000019299425500c62fcfd202af25a3cede476926b63f2a54c0fc9206d818fc040159cf0a4f6aefc8f07baa91e60ed749d43d2b2075d1742bcd3bb80fa7945c6b03d62f00a582e2d7e383ff660afdfb19659cc6015385c8a50af437bcd7837524f7e494b6b04eac50e64b6d2bfa44c81c8133c6b6b6e73ced05c1a6c24ed55d67c4e793a6a61b9a093193f59769678b8a9688a82c81b1de893b294755e589a146de29e630e9526c64172833fec060d2124d7fa25cf39990a45895a744f0967917d7c338afacc4d92b9f99e2f1427963fb6d07bbcace34e5bdacc0d7fa2d28aa0865e6ecdeb93f5f49cd395c52ea42f19c6a8e88b23f8427b54f294d5953230599815eff254d31dc54b89aec8180f0f077c75465fd946cec4cf1462a94c23935156412b78c13bc3b0c5dceab9ada90ac8ab60db5aefa194ea07c7797fe8537843952fd2c2fcfa626275d37e31da9e4ccf61327d44dabe18340429de298001def786b431a7ce3484191777928e9314ced8158c3ea8e836b83a3ac51886c4e8d470523b04b12c0e8dc2eeecde12a9cc60f7b6ebff74d1b80f0527e7c2677df060728f3455f7a41ec225d68c8fd8579603fa9d283b0b1c37a7e5568a19c1b3586e2830b848d02e99c4dddaca53fc844f1a25075c611859fc4e19206d7511e6e3c024201e88d02ca61076ff5210056b04017c2c22a71ee401e494bd4f7f985fefd0eaa0e459f1b64a5c723c562ea632c58793adabfded5ef5542a57da5716045e64bec5801589356b54dd105eae52abd44ac0d454f65a70cfcdc7553f8844295d833232334965459bcb2bb59dc359b221cc1e6541b33ba8bdd2994ec0e1b34f1aef368c5baf83d472599f6467bc44adc24ae290a6d0b8a8ac76bf3d42a0fc9f668b18bc958f481124b044e07f00618073b1925e58c15c162a9b830bd28f0e61c41b2629abac63472c652f087b0676e3b2d85f830ffd62ac5e22d87846f368b9a357c2249ce95e10fb9080af3a98176a217ff4d3d00a6e4bbc6cb81877c78e0356ccfb560260c3eac23fa2d9664fd88a11e08fdedd7cb6ec92ccd8b522a1d41008cc3c232bb64545679de519890597285d53b2671ffdbcb0dea41897c74d49caf1341b38640217cdb816821984cd168191389176c94cfeb9e17e068949687149e541f57a3f69ca67466f159c142a3af050b1549b8978345f8029501125fd07cc395a18741557f54496a191439f69def98e4ebd420bd64219404b58f3c91af362336cffa5c9eb0e42640bec22829b772c9eede40fd4903d2869df7778f7ecedd5774f4b100e746776a2fdde95ca10a3feb74a75ed01bccbd4516c332926999679fa8951155178a92b9c692a0ff1e3bb012689f538ffd11e70539114f90a13b0da116f6e3c87c8860ea453c91c4518a98921d5c6162d4972b74900ae45fcd8753cc61c5370c9d9e11ded5ad755fe3d0732817759f78221afb637ec7c57e3993e30fd67becbf4ae2db726811d0ddede8ec02734a435f2b192e4c8217c0ec681c956644890b25453d4b6bb720b1302676c43213334d24ad2b627409b327d1bec1ee3f06fcf0cf2811089ca9eb4326473277dc27d2523161c5617e954bca0df6c2a9654d1c3c4ac6719087917a382dc680231256c87b822c5a9e22c8c20d0035e542af3649632d6a533983ce8842a5e13b6482689a6641792c004890c1f19842737664dcdc43b4dc79fe6452dad542b3c48a7ddbf4fd26ec1b3b4be258c89f982de888620b28d7aefb09c469da0dda58e9282b58092d48f7e06fb59753701b436c87777b513159b43ce6aa785751a5b7a13fda5703f485c159a418ef0c1cb98b569e23eb32ad5bd151c5a4f75409c3e966de62d24c66c405825a5caf780d4868827bbb2efe6ef83e3543fada09ee8acd91b92a9b0a426799ed9a2b40bab7a9abc3c5db38cf3fe312c2424237a6ed5cd106d07b71e64f297a4626c30f4afbe78e2325258c0087b639dc9683ef76edc4dde00a1a83b73fcea0e18651830b82d60940785535eb302f5506faa736f3df332b86579a9a462e8880934aefc18270b8aa317628cbd245e60eadf848b366b064eceb7d199d023bf3f16100a7b4247af47512ca48b29a84359047501d7014628363ab2d0c0942d7f851b8cfc5375d3a63dad817a3b8aea4733952284530a9b16fab7827aa40cb3a437d74f5925b64dc5c9ea6ebba9a5c47bc79474b1cbaac42e3d8e96c8eac84225f706d16e113eed66a1b265f84ee753c6521a063f4b09ca749bb03cf7caa3a76c7f69e8b1f1fcfb99dcedbb67f5d3ad68d2390b39759ea25be59ba325308a46b3023a49c08630957c34f3ae33cb446b0b5c9b5e9526978bf55862dcc9afef56b072f2ead393efa23f8971793aca9c6213419acf51fad0cb2b6c17993ac0a27d94827d9e38e3a8725b527595ca7014cc4496c734fe964eddba4eec1b5bc25595712997d68405793ecb08b2cbaaf88c396dc02201d1baad3daa4ceaf59775714fa3cbd06802c95878d0f3431633bf964fe213e9cf56e1cbea79aff2313b56781c3b8dbf7e13aaa0849bfba71b82643208a9f129918a03d868e86987b589aa90fcfec0b7c3c4e4bb58691cb1b64593e2d5d923d4ad3175c5cc0f5173beb928e59f8bb6840abb9f8eafc30ed483b8fdd9d245afff0c2ae7cefa90b6d35de87e1e1ee29d862cd3885499143fb27d970e85722c5c52cbb3ebf78ad6d0e58a9cc5f238cb86d06ddc69ee718b9286c15cb7108c70aba2b3e70a0a23568e62a0943c745060c106e314443933b9a5e18adcfb1ad909891b11eb136071dc8c5507267982866d613a0ad7388ab6c2bc329d5ed826cfc012a76f19c9a3988218e8294067e7c5dbed236ceeb30619a490a95906d44546fb7fd59222729df91a7a510eebbdd71ac0972b124012f970c39b4159582f8f0850e028d6fb234f1244a00d7d4bc171e21ce81ca925d2e2afbd23d4a56eb6a5023d7193fb1546da43da033abc5fb0f2f2bc3f54290fa6d20c8bf6047381407fad8c58c7a92af6d5b0514ae1e97e74670e750a1d0d976830681fcc6e292f87305515ba69d0a87b0f01dd8436d5a65b0d7dddd1c1a4353ac00f33e38446398d9f5744f1deaeeb4e2e164462740eb0d351137a8b3e5d63c9362a538e21928fed3076071d05c96d070ceac4705076eed0a1f266c64a22826c8cd4769cee50b3a53303fc4a5bbd4e210c0d2645487d0fcbd224d63d8a5eb6be5ea590c1893c18a1f5a3c2c68d287343f743bd6d904ea00c0804893ecf34395237e5372b59889ba0c9d1fa2e302d13c2e94a021aa63df3faa3e80bf1eba8f27120e25845ae8358c62998a84a232c5b43d11a4f275bf5aea2ec8c1bab9842ea2614ec2ee030530a52ba9101eab409698f939c7e1206d1aa3199288e860906bf12451fb6a486c9a6c6bbf9bd75fc25246bb6136bbcf4719ebd4212226e7b97ec531c84c31f66904e631171ed4d55c2d0380c682eb5f7b8a837f3b0ccc8dca8ee36381b7f5cc9267ddc4051203afcde2315f9d4f4612538025cee70a924a19ca6620035decde70fbf2ccede068b1ddb27b9edb09e66d03ed5aece4938ac49a8edee848260b224bfd6e7962d97ee60f805d230c8d1dd279911c49c01ba0f7a87b04075784ed76de05730e121c45a9043a483b9a235152f0964b3a2878527cb45ebce69eac7dbb2ad2021d8d3e9178189e9f73a0b671b28a2384421a7aaad69ed778b30e8e077e63a7173e756f25240fbe40ad1e69156ef56843d75efa0742a11efea63ae4d076295fbe6fa481a0417f63b7b1e5eed1b5628f40e3c78686b2a31587c1be4a591bfa28626150f583d0bde714e8ab8c753552a4f6ab55f77010a542cba9d000980deb78a603befa003f74ba29b677d53a72da7eff92310c0428693d5ee7fbe99b32f5d4b6fe01c78a5563afef4336d82e1e2214e2db9389226a958270abe5b7264cf60315f5925058e87bef5637502b2313265f7a7d268c1bb5ada9008fd6c01da67c69980ee4761022d52020a4e2eea3a905fc41783f12068291f85803b834847ab62adc49313ed6f52c87ae37eb8f5204fdb9699cbcd6887dba04511866690ac16199ab8cc8c7b0827dd10608367e664cd177b3758d2d1d3a2bb8e7ae8e62175da57d71b007a244438b459b49ebd2aa139882d373b52acb6852b1bf4fe480a6e351d3a6847ecc255e889ab30701322702ac1f31cbfaa16fdf60526665a88cd1ba9414600720906d97969b2ec9cc8dbea16bb005cdd17ffaa4b2eca181e279fabd82e3734013b7c862760ce382162675d95269bc90612924f1fab6e883ac02697a89a58d4e89f567a4373ebd3bd0bbd279d5d20bde63ff24dc10cb2fe235f7a5c3735f09c3529571ca80b6c9dd9b078fa726bf31555992765c38c5c6480a32da180196656575e9bc1044b9758bce811411fcf7d2f79b2632ba4bb46e4f9c1a949e19f07684770459bc3546a743fc4daed6874e254238b7ec78120514ad4e40858343c960ac18ba84ba168b793da5daa2748615689ed5e1f8d6b3a669b61bb2c0755e472892b60e97f16e0e08557544c43e12ebeff854cdf4a867343e8c32c570b8549879b5f3e323d5efce881b44d5298a23f8d1ad7e026c2df0c58fdbad2a1d1f57286163fd8faf0414fbd9f38be581b686316684b50c2a5fa6a54e2b41462f21a7d503f3aac04aac67c142060662c32aa1273d0dc0f8fb4499947ea15c2d629b125694007e3aabaaad95c1c475def01edc2243c1529e16f86c6bee1cbbcb233b38414f8f800c2ed772f81ea9a89a67405e8db86dce67ac1e266818a31a1dae67ae4f0053697d01f3190302d1de03d40a878cd722ffaaa693647f36581f2b4427c7070a17948e194be98e3eee1b62663f5c03944cd88462c01711e99d943610a93f2351147d0e02f2633a9074efd3295c7f0fb9b3c6c1994c911950e2c2e8170e98f0c85656dcbf80bcda19af36be7951e1d634b7c154a5861e3df779586ad4ac54c34c42e00323b66e1c3f6ce7ae6688a4b7aea13d433bbc017a036ec43ceb13e264e04141a93ddb719f9b3c41cce03eccdadfb9e8ba4ab95dfbd3712054ee8c846cab5f936aab94c202c0a2949f90c9bbb9937ddca230fbdfb10a35fd5b6082487f18eadaa173926a8324017ccf81574eaad92f8ddc70d4585b75e34e82c643d70dae5a300e26ab120bebb5a83c12917324849b9b8f1c5bdf154af4ac99435cb445eb02128417149b91c116081bda59aaf18140ef2bc55207ae028835fa038ca06210bbfb11ac43c50a7657c687a24508b74ed3a693f1a174261006d245692616a5fa3618ef21138a308bc0b946efdd1d8fda64d15e9256b637ad0ef58f0bd7e7a0982f7ef138555a04b57c695924fbc242f4c9acb15afa8416d5284f21424517312199d119dde35c73bd8625e7a54d7d266eeedbadf38b837c9fee88fda35690429069b43fea9282e84d47117a465160878ac87ac67df5bbfa8345a3f86fee172bfff0c0a2184e9914a09b02dc3d5e5f9aca70c70c4db170e68cfa030975008de8a28e2e9b124792d0606fcce338d5e11dc1121afcb516011f4167a9f56430654665c78ce470fa902e53ae49807a477eb9e6fb4e03beea5c03eaa5423744e0ac17d1abc548ce8989854726e764ac4b1c109c490064d77c6ab5d3f9302370a9143a13824f53e13288f9d5b1da91cef3031d3074afd2dbb3cf4a6d7e9c13bae16a0e108297d07e69e248354e6d527f76d9a617475cb14085ac564085c80276dc57d4b6a41031a3feab429dc45e61b3d19abc7582622174e7f81d6337aa97ca672a64d5562679c80d9dccfcb8abb6397cd7f8527c7fbeb5af40ae8e64b4a278b23dfcd0bbb6030ae95940ed9d30f21281fb21abed9ee79ef14c78dceda006d7b6100514d9da46ca952809d4d42f8ae722c9dcbec8f9365eaf22820ac3b907dd7ccff00b164bb74fc3fb8e26ce70e49d8fbd5289cbc4e3198515d2e80ec75eb1f728a6cee7a557ac117f0cd8f189c55134ffe12cd95da9976b9dc750c1b48cbb805f6e6a0e8e928d4cb407eb2da462aa9deb1c0ea86a0a5fbdf9528b5af05241d8519c745ebf80d00271df256a2969e7c6a0be9c8ee8b8bba52ae4f9b12b2c1f7e1f6c6cce1241beec981d945d15d3557a61078c11cf3f229e81f670ab09f7aad3bbc055fb5d2d3d16912d8ab7013d1db96cfcea00e5d10f5c5201aea9dd38d4823f563839eb0e60c862e46d7f228f75acde2270c01685e8994854fe83ee3fbfe42350f4bec63245bdddc83de2640a841670c1e67965d181850347ce1118bc8e69f630e7036f374b6f382e7a6f5d065098bc505d3bf725c4128a4ef7e2a06facb1878d8d2db970ba5d807040a4a4e7d5ebfaf993092dc170719ebfe63cea2f025a64dba471b110192343732696ddef6f38e5fa7e8eac7115758fb971745998cf4e0736073a719a537b3e16d89e999ee0f0f244052adff6fdf2cb6a84b37b71ced93c9915bcaa99f23b01f674cea1600da4f57ed62664d4f120e8da4a1843612b108688b5938086ef15b7e460a15bbc0978e60c7a087725c212cdbb0a062b5d93e5d12792641c4f3bbcc128c8e6ed5ccc0851778ba5861aa36a35bc8fbc4caf891a2fbba244a7d76994c7e7fd1f2cf449613c71b72f16ba0029fb0191e93b45261e64a74832ae3c1ffd1982e5ecb7157024bafd75c1e5812ddc30591b09fd2e72e95fcf45b060c5a2ce914234cb65d1acf974629f98f274ed0903602a73a6391f4f6bf702b8cbd9a18a4ac92b075260403941e4fd136500848f702375294b3b47ef6e78e0499b33e4deb9cb658714d2219cbb93f422d78fa87f17553eba3224871548bf275b646056b6514009fb8a6032fc0e9409750f177df7f303987bdd75cccbab3789b56c794ec7f85e6fb232c4de00a4cd6e03d8ea308b25dc3dee58fa5762708185c82bf88278b96d8e305c9453c5b830103dcee14fd87d1f76da413cb7a8cd30f2e878fa02eae90bac34967f7120a7379d0e0f528db0382a694bfeec64f772e546346ff0170137718ec7d2a33bb4acf155a03f18eac426612784d1ef466f4a258081482589ad54204e5997f3e92c2c1b08190ac78fd80aff472a37ba9731cf50f6c9f56afe1109ad1af84d10bf5ce63ff9c609860912d3b6c06ee193d855de9ef3b41049b757f5ab942cdc0df858e16139267780795e100e04503cf320a1fe06e3a451719a441e40cb9d0e78dad4095f62094a27b7b437232895bc338f5ba0b4938f4cdc406942722940c851e5cfdfc4b93691bd718fd4eaddb71d050fb1c37cce18dc3617782509c7175bd3625fd4b0d9e89606eb7fb2b00a0ed54839804260142eb72a4477fa1c331734e13798affb63729d209edbf4a50c4ca900a98bb4a0f358291ab785632966ba14b57b92ad73e04fcb49e963d07fa266dd8a050cb1d6a95eaa7c18a8c225502e5cf8d4bcccf453f5998aa177e5a5a53130ebfce7c7d7e76ee4c6668412a52a044d6fc987dcc133df96880185254081c738184688e7dfa69fade9376b03d5929143d3e480eb9d3d79c42865384e3f24eca2294d5a8dd6947442cd3ee8c2400cf18127261846273c3362956c65b11a2ad147e658006d611c68fd564d557e73e988ed819ad84c9b5454455adb63458d31bb7d121ecbde3e5e98476d89485bf05aea48ac27112c4c6e1dc68435c69467617ef027f76b7f65ea0cbb34b5c44ca0d8096aeae18832b541f515cb59bb64f6a08f7d8b69314824368fd2f081db48c7ef890c3b7799afa9d2c18201ab1b2202f2e42dc8f672e13f0c9a2be755776c3772181490b98ebe09baaca3d6f4b3a64e93c74803dd2084e34369709fb7f5949c739727af81c1707ff4cdb8dadfc8c00814ae121090c48a9af2bc882e73eb046c1e26b042c46dc3143ad20a78110a0704374546e3884b8640a5b06b57ae60e9600b574d4838281571522703b89a54526930c68a26c3c23f53946535c1d93cb7dc2e21bc772fdb4ab067aa14da4b2719be6416b92c707a27622c55e204b34085a743f77148d6a88972d6c7c3d7b4ba2600a1f59f2b959927ced9917331e3b8e5cf5fb76bf1b2cb3108bee4ff0d0a7d01a882d87e30140c61af2d3212c971f7ce678084e8eef547e0bc65ca54431a0534cff6a4826982847f2b6a8662669b9e48064c6a7e7ae0cc52ae6655518ba5765a7d2c57f4a7c3850dbdb2e5b8f657820f72dc215e34dd75d49c42454afa42b118ba87e195d562e56c346d57d4c2da3f5b094fd492da6b96b41737a2e632500f8d0f67f53414132b3bbf1f17b861de0dbad2b0f1299f402e538ac08b200b901d054222e08f4828b6e9062094cb11f3578de02b4a15db227bd9a111416762043725c2d7a533a518608a0a00ed3608a1cef5b5b0cada9dd7f4474236a6561362710bf3350565a1d7dcef49c17775e161c3a720fdadeb4f45696ab530aad3fd4e190227d0cab95f0ef8553b98f6875b514696f119c0a18c7083336aa63912d980b351313ecc3f66c27a4e61462ee23a0a7303be455d81a6b5140fafcc1a71acb192b30a80b3dbb29d737b67a2238e9c7d8fe553028ebc9726f6391c81a88f33a83dc9e372dae6cfd756ac34336d1cec50485f887843086f90d11b187d6fe9e68062a59a86e14f646e01156911e652cf54cce7ec15d98bcb68b0402c29ef3f8b2ae24669698192896d29aea2beaed1fff9c63aab186ebd93b4557db92ba813bdc8edddcbec07112583da2333f62e6bb075bc12c88f7c87366230b7ee84a3351ffe7952f8c03a0affd90a56745a28dd8f3cabd53a33b7d0e5029fc6af0a8f8168b1fd4364b1c5e2ab7fc0a94a2b4bcc7904e3bb3f58d139c2dc8c5e92a334222ec27a10a1cee06c18a2bdefbde33645c916d10ecef3e38994ec8a8494c2aabe934a70cda2b8f31e1649082252aebc457394d42cbfd0983ff21625ae9a7004aea66aa6c3b6b70817d1bffa9e810ea5599461276c1afc51694fb9357da37fd556fd96de313731a7e92ae2446715380694f9f8f3a652b8f5cda16db33442f575c54c7f42ef0da60bbc456c8a5323a8c410d10b8a134a49954a0c1a6d7cbebe91463756f0a526aa7b369438a8a6f9c8110a68433f6c35097176ffa01fb59786f85ef4b2694518afa5813668c5222faffad826b97ec92c8b0739989096e970b366a2b2fefde632f3e199cf492833be9a54411d9d78c536022ce502ac1deeabbd86a49682275b51ba0e797c18fe92708457230ce35cac66d4701dd7ffcdeb316fe4522f27a3e099653808749ad7d87c7518fa02fee83c10e1067057961f5a4725127e11a210ff99d0f9065629632f4fc0e82ca94107886a2f40a37731c45cf22c160962f3d59129142d642263f280a9571fd1127679786cfc51b9ff4b9f25f0d3da7b2294c84f3024376cc0932069de82f3141823447403e555fa6e04d6511272cf0d2228c98a2749be9ccd2c0292d060e4f2012278271f012e2c32b652360bf6e4701fe2b84adce4a3078dcafc8cb8474215346293afe42439bf02cc3d0da7d92979283d6c8f1370c68f286441858c61fb266776eac6f8dcf2c36755a16f7801bdbc9bac2d4492e6ebf76efe88df38f0d3b87e8c4a3999236902fe525b2db33e36e666635380697508fb3aea391b8978c6aa6585a3b3201beed8a582167e97a90ac9dbc75a6513902f9cc9c80216ab400eaf1e7433c306129641faec246b2826fb711a2b0f5a0d7da4bf0a249e5c8ebdec98ba026563e0b81ee30ba846e42d01be1374026089fa1e58a7f3900c1d04e11d15307900b4c784a3fda73cc3bd8ea1eb81bb8b232613c6fe6344627336b5431e11041e9b5dcfca3955c858101333642a04fb71b99172035d8070b5315a918c639043305f214c083388abd9900203e62c52c9c8c3382c276492b971746b4427865414beca5f1e2610ed5a27e9aa4b453083c5652ef161cc04f1d49c3b6ff5f40444af49ebc71e15de033589e68c5b982e1beab107b85793864a084eb38182c94d0ca268cb4d59c54d93be162f6fa4025baf51eca72dade4d00684ccb84fdee4d5d6ee3e7c85cdf13bc1ec699dfa0018a6e3bced9868757a34e860bb38475586ccb3177fda5b6fdc859b5600580b531706db503f2bf55a7416289fed1c5e877baa0f37871be7c09c0d0ef7b7ceb1301920bd49902f834f0ffabaa2611f08230fb4d2e7fe6e075c0a1765e753b899b6bb6a5c5a779754369f7e4ed93ba8bb5bd4cf7194b9580d8ddb60ce85da4e0bfb63faccb5d4778750f2eedb84bf80c3616f1f8542bea8fdbc22eb978e4a030819d8d705c0c4aaf12ba3f1abe4ea7316bb8a3f94d0e694fce11cf6c935530474e099db288d3fe924b72e99f64aefc04314e637a57454e930b43060d314e992b58148d3fea48cf94663b07f71ab7f1255924d261158c472bf0dcc1630a642afbd931ab7d19d340c9344aa8f4daa86be9bb031a1ba52f730573028c50dd95fe8e7447d39832e3cc2d5aa740196573a802b4b9b70313b173f0d503bad24f0fbd689e06a401fb7771ef79d80d88dc4bd36bd243a4dc198646261176094746ad89fa779a74dbfd518c23d95335cc6b5299e0d6467788452cd09106a3bf62e537faca88892f228851266b1c6343248853388634e9a733005a145c6d46ce45f1921a120864c79a9e5c4ff0a26603e681341c3bb25bbc16fcce7fd242a904b81271a8b07c4c75da1fc39925d9baaaa8575286035fe5d24571ae28c0af6abb6c96171e6bfd9c4ab18527bb2d018c6efac2764855d70044cc800b9ede4b6b7ec38ef28738a21933bcaa25d105dedc687e8b8189650eec4f5d1db1dd32ff0ecaaabcd16caf445bf47d88261c2f869394c525e10a758e30999ea6eae752dc4917c6d1deec71265482f4626aff6845f47be3527caceb76c1153b235776be5e6d2a4a4ae63c21000d750c548477260fe0891eb1b9e9f1bff3bd9de9ad952f1b4fc3cb47d12d2dd4da2e585fa095755e56e2c9b6aa40573bfbbc6f1a0a34871e358454c5c9faa2908d4b50bb10f403f1e381b35c9ebb39d00aaf58374b4917498563dd488e341b7c0aea43de8f160de4cb5c2a2883998f6668a48e9e21d96d04f8f07311f34efa84c37040e92591d9feb84c23f32a7d7ec04f35872b51a8438a9753ce82171e73e0000f2d7beb6f236f2ccac0f548b1b06b4a254df3508dbf3e37aad35604118eb601c0f4a2296ed132268a9b805be5a5851cb76970ee3385bcffde98f07bd7a968552abe772ed5dcbd45946dcc5f6cd302ed6b8570a31f7d356e323f12f77e24141f7fe9c76d60dbaac3683013e17af1318282172ea45f93eda84fb338432f4cc5d488ccfaac24c6eb676c8be18f9a2ddad0c7c02bd7f118d7d49c669fad6fae566fca49f9d9adb279d4b1e6333ff0610e1e253d632e83437d359ecec21d3de502f2fe217923327761663d93a7c80ca6c2ce5993b71088ad7652650605e8d982beb012c9159c317839d61d64a9be669f10e85d98d582c2c36af66b5bdcadf66ea4de334682d559be1555348dfe01e8ca584793797476d32eba446061bc900a050bbd3676c3974934f974a10d3dafe8630fec658cb812e00bf7b81586474b0e25f3309bb501781506e676da8086f2924888cbb7ffbbbb9df2333ae069acbc92f069e56e916ba901b6e9d82067a262d6700f085dc5a802dbe0e99697723cccc2e77526c26f15b34efd455aa20374acc9b6114c6a64e36809af56de7f30e72e3c1b27f92f1ffa46ab97bd003f0ea39ee3e75263c072aa9b567572814d68a0671fe698c82ec6003f6dee5943232214b76d49e39151f3069e13c8a378baf3b4d1d08e0fcd63e09b8c333703669bb65250270f60642dcc63b0eb78bec38955cac4db336834fdda5a419e9352c371372cec4f59928b60ee5fa87080c7458df60f82162acd52c531970f0e3a8394d1fd6ad860397afc96c67c400ca3f73f869f892af4b1a046ee5ab321e1f65b650a76e2ab4ef6ad459b23600150b76b800d6d88d3b36ef11dbb710024165580b33fbc125f073b4e6462a4d2b1a58f4ac0315a3b5709f7624e63a3dd1ba468739dc167c3887b3a9ddbc456e12853aaf91cfc9e2a2259cacf0c5794b6ed9f3962840f5418c6b772cf0724b6d6e3c3da2ac764d404d5e308313cd56ee1f455c5f79738b885cd5da77ad4a3e8e2b33995aef7c456d0a7f5792f19c840e0fd9b67810e2f52d7f503870003c3cf4d7508d50e2b6c55e5b93849ec62b24bc929aa822e139c9b57a6df12b4818a15622cf075f32e9eb4952e6bb9510c109e4608ff6931025cd02bd96d534175587fc4d3e281ec845f68dc2aa060e94465c30bac79c2f8bab7cd2b096e3b2ba66c8f9b18ea34813e2e172bd55d47ef937194cef571262da86eb9ab5b32d1a317e196499a093181a8ffea317296b928df806c3f6b39d64ad6fb8fc8a78b16b1da3275f280f95b13021ea4740c91bc8dad97ad2fbb7b6b2787745aa5a46106c7edae4f062cf1254e8435b535f477dc9f150e5488c20d88f0473199146c83405bc8b5507814d8811dd049c4430bdffba1dc7727fd5a25d5cc547b4b36d52a4b4cb2354dce4100ccad5b59eeb53617671a9c6bedb62c6ebd901743dd9061a73286ca38b830deffa0166562a5b61fccbba29db1056722ee328bc16b77912e85b3d807c41b0d4956d295c6698e070645823240216abce102d212b3ce13a24ba87c5ddd6ccbcf6238743943edcecfd462828d7c2ebd3be4af91e738c60686a334beae5266079160d4aaea3cf278132342a6909cec0090eac12b2eb41bace7b602b7f4e23a7eef8ced7ce0996b3b9891bb51ad6f799985d6850c0225452228c159eec8056261ef2ad00d85bd12ae2b9c5e2642bb2606f092c714ee3c9cf04ae1e4af59d0e0213975ff9c2de2281884701a08c2806e3e876851db50256794bbe278afce23a36d95b7474a3dc80a0f7b6f64ba8d3e82f15fe2ed04432f147e9180561ee837ffec21a1a13bf5e304d39bfbcc6b0c4aaa71b315a4a0f7cd437b090cc280ec7d860fc7e6ee35315ebb906138ec05457f98b36530933e1d391c424943dec3701995ac57221b8a2fcc90063d8a8d12402561abfe833083b300c6bef70d9d53d1b79eef8ad7a91b95e7f1d810071fc6dc24d44f18e345bd4882f30d4d186a09aa3cc945293c33cdd60448b93432aaf85651dade7d436ba4f0e77a8bd038eddbabe862f7818be49d9816b3316eb08e47aaa6ad756fcda54138663c37475ef6184ac38125863b4066babe67e3759b7523fd551df3073cdaa10e6aac83c075303947d746e0bbe7c0d73ff5844b7d15a45e834601395651ff71c1fc2da244af3131809795685e3d11297b38f7b5ccb9b5663cc2aeea5664959d8d65bf9daddb1b2ddcdd87b2895b241a80e22b326d3563c80e56a769087346bbb94a9fd96c989f158fbe28377ea9f6b55684b4fbabbd525399ee01a086e08ff5483f33ecd062dc32b54220315d99098901ca28b3403e0f89a07a893d67278a02bd865366f915f1dda5a7b2c71227c5314a1bc59e8dfb2aafcf87e07433d25c54e9b95a526067e95fc40b6a6fe4bdfeb78f4606c5ac4ce2d1becc716dc2c987fb919d7cdc25d395f2b73d54c4cb6fae1351b928086be2694bbb87e244bfbfe15362386db0016d7ab02864a3ca2aacce0e98015cbefeb3a773e7ffeacc296df5c579b3d0f07052a1b9f48aee5f12ebda73f79b95031bd48f223c4b638f8d4eee87fb1ff9cfb295f2977cf8f269f9f93109573ff27ce7e99b8bb31d79d9ed602181829515d135df8744601e8179f043a86fd6cc057b06fef9af34ba30168e46e553c5b3e0fcdf9921db8a1a419f6c7babd0edad46408b9b270e863a32cf896b3a1ac7f25992fdde4579bf7e95ee1cb161aeaff8af849c32ef86009005829537f0a521ca54ca16886c3fba55476b23068d7a24bff95c6660dacea458e1006fcc4197d6b8bbd20b77f6b14bdfa37c5c495a6c5b0374f8bab7622b56039fdab072030eda1ce03d6a1330e0d33e0046d4a70667c273a5c61af4f0b193b896c5fb99a68b26f0a7b442001ab48c9e5fc04464eeb386d3947db3e14a2c38c7a25186e75330c5a816c210b3c65b43a6001f358bc0c6d8406832c32ad5a3002fc53b65f49ba405240e31b314f5aa1fa4dc9ee366fa7e0c4b4c5680672a4b709da37d2c9448ac1b8a317428590dc47429ae841e25d718682497dadc2044cdc57540a0c67e6c0f96033ad7ed71b48bc524a129c0a4e0735a397cf0e51e5765f56279c2a72d0dd1d59247f8abc64ca5d0519a691b710c8d5516f27b1cc6930e99243c1971c65d27414a9c34579269eb13b7ebc4e999ee7cdc39dcd3ba037af9eda42ddbcd9d882d2e816f85b6e7bea388e452b75b7841dd859f25219d08f479dde74cec802e86c81624cc7229137d0979b3ee3342fb7f949b9ae9fe467489b7b756bed08764e7221da1abec729c513bd42693470f36f84c8205b9e793515d70b8618bd0398b6ec7599ecd8c4995e481770d848d81b6a1d1384646521155f28833fba10cef0e603ab91a2ee3e0e0116b3a7685f474d41122cc947b33199d6262ad28b06047715a68ef2c94b329b38ce8d9e428e894c0197cc66e05ef783eaece0221a2437bf60084749f82e3fccf9e779e129c49f8ec1624134fae6852f8bebb967691ab790385e6c3aa4a35b88b9fb1c6d167b26a43e6d10c3ead4a79a5eaf8fb68903bfc5165311637b894a16a9c34eb438170f69ca781d6885d6a09bbf8bf0dab88a38a34f75d0f427d33b3d2a796156bc3929b30efbc1c1e06e226cebf61795a52104f5f95d470534bd0bc28bd19457a79a6649c7625820554d2ab695f80ca0c708f0cfd0e7d59515b81bfd9b0758fbd2b9d7bc1b59e764466416c7ac1cfa87320eafb891d73ac579d984a3a6d41d82e671ffff9221b7c57edcf2187bb0b2db16e0e445722a1dca40c78154dbcf7536cb2527d87f4d3b56604b63640b6b3978bd10af4ce70d0608c4c66c8d6260c8c802e26c4df85291528d6a0c5097424aa31a680df5ec9a41070144f342d30c5d8a4148283cfe5fd74a4a5be354baba5e725078d7d563fb4939b36681cba48a2ff5ba201ae93347547f696b5820b66e436c0c2731d895458878eda0d6d6e440d60ae1dd3a5d34e824b9cfa96dcd69e8329237df73cc6d8be2becee34b5d7edc53c9503a44138031a9be24f935b8e3defe95a8abb6540499a91385d55545dee69321fc1272d08e8ff0b8fe0a17e653f0254aa1f7fa368c6d4d5de4f29dfa8ff4eb976df7b8f554a571b34aa371be258ac0bd21078f044ab5154c9aa10ed56668627ce492905a42feedbcf234443820730740fb1ca9993869643364dbf4b4c6ff4d92bee72e44fcbeccb7f731f85d23195fe8015f0b5816b8290fb37505751b8868c5365152005b97705289c65e7315b5b69f76193c4f6dbb69fec77be5f305bf426917c0249982589d14a620c0685b22191c4a6365d17b8f92b7d3ca72c35f42ce9af50f627b0029ade625b103523a367a696014f20ded1862fe0e33ccb19092868b48ebb4ad43969951db46390c6940d8c8e80d74367915a7780044ac04df259b3db4c7dbeba6e6f56dc61edc215b69b283639aa5981de21d14b8a62599a0e59538442442b2235b090a1c5989d4687fcc93b9eb0c22ce8207fb6a0389ba0870738319a125d6326332756fe54bfd33f9973c0c35e91490469c317536ad3d848c878711dc1e52952ee89b32f939596fadcbd27145407313520dbb32e13c5229e35f9b857cd3d4604a8bbe63cd4cfe9838774a5d3a72063812d1b66e9fbf1591ea449964d4fd451e92f5daa1a5fd6e6e48a21a4814247ee3ed4e763511169e06f9c197fe00ab271b234f27f993c0c8011d1401b3c3db4754ce7a3ec6be141f91efc5a2de8ddbba7804f99987ac9cc8da33607dc479de58405843f2ae6ebc8533efd97282c32de3de3e835afa38d634d1aa87d76a9ebb0801e421959959cc34efa54b3cca73927fcf653b56de764a20564f4feea9a7a7c2603fb351a5934b33c0a278a49cf94a7822a52b35c4d70899e6d1a0e7b384553f4416387808b62bf3766ce0eedf077fa364347b031024044b52034989abc811bf4126830bd443ef833e5d92f47b1ba082a6232e46cd3ed6dde994c71ab76827e18550cee24921d0f157683a711cd58ef8afd3b27bca1f97afdec1eeb2ee009d895ea9dcbbc99c3657c7328ddb9258c1a347edf58200739425ab30d9c1ae1ff84bf291e616f5b16198da5f74ef9c1aaf881ab447b549e7ab1486cbefe1ca097e79ef0b868d7a501c64c178a7756f7547286aa0dedad17b2bf1c4d8608588dea2b765f6074d57e54dc95030e1a8601650ac749c9395b254de1a79833ee153339322bf006b01e7a43a4b15441857e808593d775c7a85587b56937194434a089469f741a236258cb04a3d5dfea4079e9fcb2711a1dfe68c3bc22d150fb499aaf431056d65079029454728b086999864e2e7fd1f968f72d37ce77601a727dd182715de56e0b79fbc661e66c289b0ad74037a5e536958fc95eaf2c36ea6504917550966164b5ebe2e668ce265135ac4b5c949f9fccaddee62f3d9e5905a91abf536bcc029b51dbd38f8e01cdd3c414975086a2124e23ccbb19818680b2d896a750999a9b34b826e45b95977c74981cd0fa9a64bda3fcd5ca96042f914493b8c8172f4e6558594275025dbc90509b84c5580809d22cbc017b9f923bd1c71b845a928bd91ebe31a50af6e3a9f38d24086e0f3d00688c88cf8b4ad315b6202ee7cb25674e5823ee5f269c7c281bcb207ac90438a56ec79a5cdbce21861819b798c98d326da3c06644a4870ed890150fa72fc24067cc40d02d856ce689b315b63d1c92a1619fbd9022bee6a94e88c25209fe68446a40b229005f70a4e45b509bc78fcabf4b0995ccd9e46d9058ee6e0acf26349a9dc36324903bfc6001880736541f402c5d40350d0e331b822d84ecf43295e28bc7ccebd75d1542a6b137bee79bf053816251ce6ce89883b1918e6f879f1a51324801c53b3edfeb759a41730f928ce53d70eb3a01608931723075b9030503eb38297d38f3b20a444952e7c4054a0971ba4cf911ccc8f3abfa0dff23fd170e0cf0ddab25f5ce308178be9678a6f7aaee4b1ff45bbffd4e1fd85d9fe92cbebb576bf28851cff3924e5ebff27c1fd184c37d64fe767f71f492abaaf7fc96ac23cb479ad16c5bdb4019f4c84fdf17fd2ef546278f4c27f937a7c1bf053772a53be0e7886572a930ba9a9cc55be9190a61a23b51486c4e6c901dc17a6eb4e7626fa93a7051e22163f8d34ff8cb2f151fe5879fc8ec3f09fffd50510b52cdad8cad8f5d317614a36048f3391ce800c49bd09bb91e90f47091f96fd59c1a5a7dbf47ef884e14bcc756f59815555016fa8cc0dc3fdf9de32af5f64ee14ff57aee0a26cefd51abfea360c8984add837d82b450da5cb2cea355f7fe47b63fb196b8bfec78be2756ce9eec2cae5802662eca7f98303388efdb864fd1640f6273d59cf1f32e1d81fcdfeb30e66b9cd800f5a33eb1f75849a41fe574d2c5f0d4e0cfbbbd35186c238f2a7f064367c10594038be2e51cc942037a7c5f2b1a6866239920277ba1a65e7a60c4a23912883c430c41a09d8e62aa53795cea2cfb61624c836fb879a9574ac9ef68bb7fd00b5f3ca7f94766e9c9a7e225502fab91b99e0b8ed631c1ceb84ddb012b8e93836fbf77fbd56001b1f8b18b61a43872df64e6a94bb90c13e32541878b96ffcad4a8ea41924ef319c0a65e6e068b7317be246a2d1744682bed142da46dfcf04fc1656829a733f092bec40124f0027eea838a5409fb4e1fc1b8e1fc245973fa6c53fb9a9661b0c0f9e1ff7536a92488d09ffa3c1b5a1f0a4cc7fe88ab0960d04b17b4d8f79bde38f0b2b24f1ddf30a3fd75b853651b4e73da1c840a1f0fee536fbabb213292ae7b1ed40dad312024338167b60528609f15457ae7b6941e8ab01302c72f6db288ce77f7161eb35dcf89bc84d70d36ee6cdd0ebf1c6ed077bf5caba58ea497aff1d9b3bc4cc9802a7b4ccf2f125482d6e0d1c6c4cd9b43fcae01f82c0562a8fc3be3fc2e534e939fcf2aeaf4aff5b0cb7aaea70a5c1480de76e00c2b35b3a205851ff1265490d126f0df0614250de7dd3bee49b0b39e673f2e4a62cbd0dea0e1f0421cc345f63afc80dbc51d1901135342f71aa1d2d5862118c869d050726d2ee09fef3e1384078a916accdbdc7fac1bc9e4042fa26fb9fd80551a75c67bc8b28c6db6072d070f54dbbfcf7bc826fd172fb42ca356cb4c4a9761107e0214e95cc482d756a342d66b4b6618d976349b25b263d2ec79b53c7d439cb1bbf8a68d0bb0ad484246f111a908c2be6adf43360fc50e093c311deeaec42e0c5818aafccc6c815d3244d88999daa4257510c34b43eeebb2a608b674e2b3bc4c38ccf2659fd923c0ebda89cb2d767b7eb9dc727a4899a605b7f5722bb8882b280ae252dfe0a925dd002ea5db098bdc349b2d9a57d21210eb44c4f9961c7f89d136fb095f9e0cf685788fed0e2202cf27780eeac7aedecbd2568d63627683ace9f5b6c69d8391a6a2b61d18c967a9c050ebc93950dbff161e59cd6f843de895d14f302161659c0018c49e36cb7bd39bb81a8eeabbc06540c5933db06a557a904a3f9c56d9d0786e4118e1b4b53eca846ae0212f930d863b8738af580067a3ee5b6c6ef1a64c1c27215324817ae8ae9edd62d0af33f031de707c06431e6e2de6f00edd47958444e5e7e7de3da0349f4670a6aa1f38ed2300ac7aa606d111080b2695042cc0f434870bd3bf710cb5255fb557f71ac6957f04684ad49ac63ae19987e04fd0981f4930dfafa236c39610edfc18040e8fbd7afe72dfe70a04597c197fb41d998c8449dfef34e650562586b6d09a1cf9610559311b157de674834e0b051f0faa74b196d14074e5d78b5ac6fb2286efa45a9a1d1189ed4573fec3323dd514af5d0f5de4e4affc147d2af527a69fce7b5376a90a4d86678ca62e56f5cb250fe3796fe02ae90c4865677b9874c40ace6bc288daf987dea8c841964cc37dabac6b5885e52234433dd6b00525f3dfea2beebc068bff9f6fba915231bc603b87d7a227dece951b89e2c2057babef5c57559efa59b2f7677e183d53e718e978ca1df9137daf4359a884937b40596392364a48fa217255d2180817fea2d3eee3352533e66b8c561aac40a0fb33c0044280c7059dc11cd783222a481a0cc3cd85d985b13ac204b790a357a845fd1502e9ff07ad4c1b51885e1a2a374748c00af687576219f57b49e8521f7e46055b6d1ca53111570d217560686c50c58615b78c04c1e217d69cf5d5966d6a6fc20a0b5ad2d5c541750704a9a072628af962b36de467b563026438d740341e4d359759609402c1935ad60eaf6f99d06b02f8781af16b0cd381e06f58745309c882490170d5f546aa9221348173440a0a8f755f335ddfb2680a1b6975d95fee57ae0990c4714abcf53f2bf79bd03e8a8e8b09489dc474a958b10e62c9992caa0a5e96853d7f2c490eff718273224720119c453ae3cf13bb8b151dae622a1406ec6d2b00913c26423f6d3ad5f16ea1f1940363aaae7c989742b8530d7ebfc07c6cbee8dfb1d7911c91f1b18e570dec5182dde7846af6ffd200231b46629dc0b791cc674c0568c9e4ea6b8f86fe1ec81ef7ce5dfd505b78d36764fbd5d17cc2e357f95e38e885c71d3c954f17dd6209ca7d83975b9fbeed37dfc13966708922ff9e13ceed8baf7881c543790cb87f5d2f80643703c35c84351cec52905dffe9d645f08bede8eac7b3377119700dcbecfe8850b0d07b1a710a90190b66965916bace8ed1d34855886ae2e0b0ec88e0f50f61730a87d8a062fcd810156c26a3611373454756110286255659fe2515023ac282c454b70f80fe0629c2a5353b1802d35e33e619e4e4c06ff81420ba10bb08d31ba1ba20e252ee90ae239cbeed027d4af5f06cb7482ccf30bc254b19ebcacad8b580c44206ed0ececa6682e8f7ad65e77a43c663103b3dc23cfdcda54e48de000473fe9d6cecec9bf20dcd05e7b32b3ac8b71d522029809e537f61b796e185dc8d63e700f03c07e997dda89672a6e4f6eaf9058f0fb884ad6a6d3b8bef13f6fb76da64c2c90233b4455769bb06b6f3b7a91dfd753c986ff6157f6a7e653d96fd135e32b39aadab067499268eb8650fec8dc0261412928500763aaab80224dd009827262106a2c900a6273845a42bd3d07c5cf9f21138a82eb3b7b2be3b7c264ce752edaa35d423eb374da021dc2b617f189aaec1a368202bf297fbb6011ff5c0157e65cda8750b7e3adf2536720b8cb94419bca4a4ac02de87fc9cc95c1f64df8f02ea3a05e8fc19f85d63cfda3c9257231064f9979553bf202ed6582d1dcf75d8ab168ecaa3860cbc08f1f188a72fc24754cbd51fb5fac4f5bda78107b25d034480fa370074ce14c2f98e31a6340372b6a85b2dd7d1c10b65872871a8c89bb5b6d6291f1ee8c83118fcf4c6876d2cf246139e3c829f00c64132065c272dd26f5ac72cece4568586c93564d70375fc7d510ddb0e60f86a1f0adf11ff636dc17f622a87faa8226278d1085022421aaee77122a234588227dc00dbbe8c6066c38cee9bda5a9e93c8593b917ca05a114fc24e03e5775ec6095f9036aadd1e386bb00e4272617657d12658342e3426bed1b2278c556ded8d22ac052084371a8558bc01933caa1188ad95843ae00892f1479aca1f8e0c1f94654fe6a8e966fb04ad38c19ae7398c83f0b65d8d28d656215ab5ec576a3b6082e9125ca956472edcd6a12502db97b0bba51b225cbfc2e490961f3f3fed7880fa08b59aa3175cb616083a360c89279efbf5166a5c151d8d7993aa16adc259eaaef8c919bb1881ac1a2c0896bcaa74d5b72bb06706a6ecabaf198a65b58b72209d2378b9bea7a78b779289c2ec7254d75c3544a945e6d79cb32f42bb8a4f0b00434151163a3a4d593cbbc6426d369380a067151dc55c3c44113fe7b1e8da9612806087161ec3c75d206ea41feefa987d925e7de71b401fa6bbade669e311a6bbcef828393d468030486ad9d006611fa4aabdbb8abe9ba4aaeb9847216303cda8076fbd851cb33055574b202204a0c3c2c487b8dcd06b37c294674a88fc99b45c6469ab17d8585d2d106407b08eda019babdd79f360aab765d93f407d2f46c367854779e40c571bb6e430fe9930201960b2bfc186d20616637db5bc8be8be444fb7c952140884398ca66b1e00319a88c4f6b36451b2c899e79d3f4a8c5d5eafd4156c28b2ea970200342957ad083f86c10fb690b3b74464bbdfee0b301fbe685ddd420971c29401349a7a5e61a7472f3e2e6d676ef9ebbe86ee1cb50fde19a33ea892cc59b4222cad73022a4a917b128a7bd6b60622979bb85b2556ad77a382574afbcf15e4265c35577811ee9148a5989c3870370ef610b364f21914145a5122ddeb6f87950dd87e3c3ab69dc869e68481ae43b4fd0b36868e06a391770e823e6ba442b8b8453d80d2c7088bd6aa039971a91da348582c4e51fa7eaaa558a09d72d0cb232b291826038f626a44e4d0463751c787c021f6f0ad2dae04ca9cd1aa4d2466026c8622499ef7346d7fccbe7490f2d9df3442051dac959c7d784330b081fd3736317d2cb69ccfaa5f43e554e348a07c7a095eb4101278aae78b6991289f71e3a2357e21c2fc2e0e793a206011848c528fb79c64f53f219d9a6c5b81a1650908ffaa9dc7e9d7ac07c647aa10b15a8fd9c31be18ce4aca22f00499341521cf195c24a79cd18a2afb1a332650ab7802d8d1fe5baf5f42471019d50091b5ff0592954c789db462c19ac469a16ee40393b308b58e6f35104913ac56f5bf340e7a4d0dbae945c56cb7e0e1d9566febe127029447e204513d76f5fdc4a470be7917d9e972f0e2afd2430052b0a9f4a2dd4669f739f8edf1917bcea9c4ed0079fc420fc25f83879e54cfe90781411004cc33676ef018a598ccd600acbe051a3e1093ea39ee4d1fef0718bf9540164a5be16a1d48fb887b09f902676f91636cc4d9ee83a4ce38032c88dfa74628a7b1251732d4ccee2cd4ccb1ccdd36111bcee342406ea787c79ce397508e5fb2503af2b040a824356724e30a502179bb8c6a336c3371d4fc658935d4181f5c1a793c8f89eb10cf53ba5385894efc739781f1cc15a12f910dd0cb5fe0430a9ad4ad9e4569ac71aef71079484e34082b2df19e760f2a821145f0f7048d6f4146aa939984803a547d77255fac21e1c2ac6665f153400335f81a60630f396225f3e2c7465cfd14e6760b20e9d6edaf1bc6705f4cc8cf575e2c511dcfb48c8297d7e946c67bdbdffa73a0207c97c0ab0e262cb5a7c0b733a4bd8f326439cd44a81de72989a25a3d10853f3fbfdd1650b725039e2c57eac1650f9b10cc4473dc3a04ae8f4c4dfbb087ea1c1308b2e0fd02625aa1b514395d709b3aecae19c0c31c5d4c0283126e959efa474bac198aec8a1a6c53052b04857520e8bdbce80c7f34beab607e660bca8bb97ff423e8d1dc7537b1ffb2fe2a115d15c5bdd556cb94fe4475856c94c9e296ec990a240a0d331fd0536d0722cebe172aac5afaf47f25e366b9718e26bf79987f9202a9c829c20745c35d6c2e852c984ab202a6d556dcbc04de62c74ea6ab2212241bafdce3345136362a721c1c5c2019b6718b0a7e736e5acc00333d014d7ad6a56d040afde47d361f19c93947b37c97e24d47655da3327a9f594e46c9f43c58991718232130a546c03cc0c81ac3b12e2361222ec87ae6b40b951a126ee409e849cf57c5d66555399ebe38e0b95e8b2020b79363c5fbdf73e0ddf2d0f86165ed56acad1c83ffb6a1192ce5941e28d3270113c5100fa50a1ce683430c4301531c6e7b1de339a102f4b0e6b6db4f23b16b3fae68f4426b151783312d294e22f330dcedba593582e6af622e1fa298f97de5d2f9be1593b7786e33ecdc2a6ea96b036d7e882fd37e39681fef2b7c0ca90f464bff5e2a1933be6d8547859e972b94957afd0d0695ed206fe0b75fab9f04cc21ec242fb26c8c09024949feba9f5daf4012e25b6deeb4f25ef105f223b0c7d71fbfca6d43f5663f25c5ccf86c15670b0434c33bd77cf31563bbc19106981a6557d2e29088d67c468b07edd397aa99b1a6424687092c6ae79045722b4215280d7ac5f07cb1180fa0c91404b1ffd0c0dfcf0b41d1dfbdb1dc6e2575ad61f401f1f71827f541f9cac859a20b6e699450c1813eea20903b01bb8c29c003e2a4fee05091ca637f9e1fad0ed0227512a2a36bd7e63aa3f66b388bb52611d2e246c9cb591142f0373b06edf2c9fd78b7978f6783a1a7f090bf18bc5fad13bccfdc237bbf7cf2512431cc7c5430f313f0fd7d4884598b9cb2f8632099dfa4836a4a99296f0b8a347754e78c3e08ca9216a0423366b4e3067e76da5298f5aca1827f1d4bad6f03fa2db26c1c2349f32c0ba210bbcf835823c8c420880a0c8ab1b4824158d21b1cccb65b6167bd85c21dda6e3e50bdbccd0888b10144041e8674e3036d6a178b31d18ec327ee9a943954383479c93fc21a8fb543065b21654a118c13cc0f2c34c7889a633f4904931d5ae0d2405b973605be9cd9fadd91536d990f5974d7970239065addd0db7ac20f966b58c0cdc9f814d94e6ad31580f27424b7189e1d3b7976e03d52238ff767396e1c4f92966747657b04611fd9d63fe2e0811485ce948c095fa66ae95417786cb8a647c6074dde996e4f96d5200fa995f495de60bbd321bfd2ae379cda28fc82506666f15e7672fcf57298bd7c4b90f62d4ff8c2c8ba5ff6d285714264c6a6821324f29d794f9c40a74abb0bad2045c327a35cac25c12a6f60f64e035be2b0b92fa2ba60f9e53e183229f99d0b399168174bee85f673526349e43440e568724b72eb475515c35feecc644627f181723da4c27aea1a9d9eac2474b71bd45675dc744506bfab468cf8a0dca0b2b01c517c37ccef474b744b3baf5cc8658444a1c87c849f550b08a2612abaacbfee646a1bfb6a41759b1a0b44c0de52b38311ac897d613c277d5efcd100404515274294d4e93d9c1da388c9def1ba4b5fb66c18451f11eff5a5e4b25f62257a84f12aca9a08de493aadde18408532f7646c6bc75071a17773b2963e8863a8ad04f10f1cbb87670858c9773ef6195aadc4062e7f996f310e0f8a4d4aec1a157e4fba89a2646b5ecd292a75c1106a549dd58f3835089d5b00e074a822f49b00a10753b5bfff2b12d574d4e31daa9faf8a9c348e65b610a61d3f22769962ab6d4a853f17c532a59a29e36f93ad5c9db2ecae4ecb64e59a838b57e599d04719246a41ccf12cd3995bc7766229488946189c972b15ce6cc5924798dd989f05db20731dd2d2cd1f20a94c1063bb75b9e4832d7e84d6a1a4de7573e5673f217bab3320e470ad88db461ef4a5d85e6f00d782b8db003be0c420cccb532a782b8608a898f451c96fb7b92f3129d7a458547f8a928e373db2134f70a36f491a42164b162ccf162496645d1d8d9c4158ff59da588825aede81c172a59ac534ddf4a873793b168c1aecc059d8b5dabe17a2b865b1d32d0dd6ff646195ce9e5f07f684ff2394ce5f6e7f449b19574bf66df92abb02ace7520c1a4444789ee12abb63d8116024c62c7abb87e640e79ef8f18d96462fb8dd631a940e300c2ca9ade500ba0aae6152183d96bb6403537878613454272ed7867e19cf02678358373aecf4b66571b0f83f850b5a7c652e674ec8269e56348e02be54ccb12db18cd69b23767e7269993eeb8d8c5279645ca11ccccd3d2fd1da18d5afcb718d96750f6bc590184d1854c8ed27ae2798207ab7c2a3ae29907e1eff4235f7ebe8040cb990a7051891757bbc9593d08699c76d50ea016a7aaad68870448f34eefd45660204fa03d463e1c6409860edebcc3a27cb4b508ae45cf2d2acfec0d91f51c4fbee0c1bfa261c1c47d152ea3a7aff3a8f065a3e6b192892faf85a03efc5b5d6336941fdf590607ef8acec096c22f39fba11a00f6672fb08ddd888788025d740039f11758817a72c055ec1889daaadd3e73baf9df1625a0891e750604b302069619fc0036ed6c53ee25bacf4ca31e1fadd68c77ae542f70dab8826b00ed10106a541f99b5f54a5fbabebd0d991ffaa927fa78d560add28fe08fbd66145349c2e2591ee4aeb1dc256fd4ab7352f44310240b89fd3bfdb9d289fc9d437379c36058bf256ac3a63483b4e20bef9252c8484766c03d68ae5acc436ba65662a80b8ccb08de04fdb449cae5ce49c4319e60f5ce8fb4972ab858ad2e602af963f92054348b38249379e1ffabb2df5b9c220cb702f92a7062177efe5bcab725c5e53943dfba69f310f71d429d497d96ce300ff1bb5f551f305fb3492fca17de04273f2bac0194baeb838bb000d2556aebe7d40c31255ac6536af19b34a8a3a040718dc58f167d3d16551c87a017f87647a27562ef4830a5c0430b673508dd90c55260248731939ebc4bdd7abbfe6e5e081fe0009e79371a580ddf7e0717cb251225f42b267a87b675ddad92aaa3753463bfd230b8ca0421a22e61f57bc33b0d0fa1a2524643ea262cf51251f016a331f29ddb3d8749606f57fb6584b77cf6b90f742b7c7b4bd0c0161db3b173bc0ba93a8f554e5f09caef6ac7e5139112a92528ea04e0be8099047c3e640f55db57bd8969c0b7b5a99feefff4d60fb8fad07eb142c21c519129a669825994fcd0acec5602c9d0bd3b59470f8b43d8c0b730eb4b5dfdef619b2c01729bf2d596bc9125db0774e08a742d1a6cbc53f436bc485b1ba429198ba7cb428f9bb216e6efd17b20676218157afef3f81ed0734e471f72d90250c17a8dd75614ed910756f64d01f59be57060ab23c484d8f196327c48346d1929ad0cea5c8ef4e918a2584c625ad33ceff46f8952f4d7607562ffeeeee633de6d7a2fa421ef27a980da427cff4d45f5962c1a70d6b89b8ad58852aab47af230092d01cd60c98321b4aeddf0027da7273549306515d914fbc4ce5cd25c43ccb5ed24379381801557f19e1d7d2e14ee0e256d89ab0a422915727d16cde6dd128d9d03d11b51d5c69d7135534ca6aeed8e5b05881fadbeadafa458af811c91757f29e1cff2a0c5e12ee76c5f5ad9e80c4d7798fea8bee7b8a3dca2e66e4ae3980c203378dcd52172416d9855a0d0038099755298a1ae0f0b86acc3392c5eaf17c71bde76a3e32f3963e470ae263c00438661afe371977a22442d9b837b99251b354b08784bfbc3e21cfc5134a2c68a94bfc1b8027819581db89aa3763b775864d27c978fdc8746b1ea82581d063026a2ca293561a8b1c0decf1076a18aa4fcbe73837f959b7ca8216874b03103fe1a43ec22340878ea697d5d770bb87ecabf7d56bace48c11aff6a9b08309cb341b7539e3c707fde42f72c2166a044824360e24638c31065ad1b82692c0521a8871ed51ac032dcce313f6510e0a4160ce97a3deaa8e68eb900d87b7c2726ef86962376a7e36186fb9175607a6aacd97b7c406c367e85bf8f9a6355da3e167b538bec7bd541f191b1d2a0176dc2c4832138bd293b54c93dededf8410af2f72e0e37c4e033f3f8980617a9e2f4341798a5ab15a798d1660d4028dee75adee4d0af74649470a228571e9d94b594981a70a84916add37da6026c110e9bfda93072314f35a18f956a49698bb5fd8d12cb481e51ae5dbef7b5e53222c570be1f9955b4fc03d825b4061e195b5ffb07b9eeb3a750f40e848b817fdf24694282d0e17fd0fb860811cbc7565c19fb4592545b8fd971aaaa25aa548479b6a5babdaab57ac836201179f129a1333f085388eb3986fefd370dc56b88265e303ed6c0c0c53fdf443d9502d28835768ec33cb110f7d9dd9ad3f01c39d6585f8cf0b5d2aafd279c421edad415dc82ca599c8ac29caf5d6435e8cc7f9a52ed4cf5ec25372c543812469789f28fd8d8d96072da1262fc9b892ca149acd93dc58f18fdcfdf45728238554a64821c356a1ec56461efa9926f4a5e509b7715c341f4eb15237c60eb4c7e2b41340a0450b4d1c0173e7dec2bf4c0a7248206192cc37916e860be965b151587766cdd785fa005d0b20b2357bf7717ef8e240c619e8aa01c627b16de979b3d56cb8191983cdddac1893911d6b4dddee1591f6a01126d65a492b11b074415e2c07590dc3f015c1182b92323d2ef456a1abe24fdcbc12cc4f17b7734be358be389844cb19537b0527a42cc7a685c4bef8e4fa2991f0bebb45d38ba4f3f44cb51b3cead60c764fb02760c51dee1e32a3bb671f67585322e23e86173630c0413383e7335d77df0a96d0ad6a6161aa14a4d4815a3d7f6cb74c4337da781761fa92a77e06934966e735eee1f9340410151d5de5f0247908ac95e60d67ecd78b9e0794afda2c47ccf319ba1389eddd974eb73c23cc763b884de374cefb9060dfa5ffd031ecee0b1119600ce1d2d069986bb1f099c0b036b1962c54a5ab693fe44675bd83850079da9fab5f3a073af9cbc2154779793ab22e7225a272f7dc599386f61ea1a2c148142d37150ace6786b2ce67caf2fb90ff46b99a616fe544088d99d43549b818211980f5e374d0aadc7b38ba7162aea7e785548cbda4ae85fffdbf7afbbba4384c634bdf9f97d2f1f5bd540689501364980a0e47b9e9985154f91ff9407dc2437901b9ae648fa30021fc638ec2af60846bf3123027f2bd07e508da449c3a90701a4536e0781313defe21cb11482933251afbc50b9164c01b75f9327e7ba850d458f7c5c27632f825c9c4585885ba9f735b8ba78c2b56740d6abd9460069c5d02aa71814c5e4010424e079c48509fbd9d87254ec77dc26891177202d14e2a3955c91b46bf28b6354fcc4f99f5ea70983f81cd73b51d11e662407fa4dede007b5248697cfc3e000c01690dfe98597fe37b1b3714289b67ac7dc86f7b77db724b99929429b704f104a80477766dec707148a66463078f7b677776efbd3317a14c9d973017b219ac07180960383c2d2ae2869033e9d3592ae188e082f2c4154c18d8d431ddba278a3c9564aa2ae6d9e83bf2672af98ee9c7dab1c88b8a6e2fbae8e26c36b3b163cb8cc717fa640bed2189fab0042d82c160303aa444049986408623f758866c48b52dd2e7ad20b1e5615e248aa2488b6614082ba5052a5a24d222f145175d74d1451769a92864a2289b55516294a468ca501351f48fc5542a95ab602caed2297acc251689f090cc61be63c23277e46c478e335a98f9656eb1b9154571c8771e3063642fcb2de2d0c762624c8c4df1b38781cdd0bfc83136c4846886bea585c5863445c533994c9c899fcca0cc4cac391363be3391c4c498288aa29128c3c58484a702134a2975efee9eb5d65a6b952d1a5488ff7f57ffcc1f49a3aa2bc4fa081b0c8e87367c17a539b42d2f586bdbb61582a769e34c6c7928d03b27744ff70a3f9a2a5dc75f69cbdaa75572b6eb68784ab8ee5adf29ae11030c8c90439c40ee20ab136c249bcc1df9d32f2cb37665eb8f9b95c8de9de04116a315118ac9623c82c631a8729c4c867f51fc9ab5be93a5a4f87f7f1434e0ac22ee50074ef0f6f696e0cd04df91220a5246ad76fb82c2ad0341e4d7a13e35a48c897bba19a48f7529a791283d294ad143a186784513bc6bed6b04293d51fcc21c9b0a10701cc7b54c06050f1ebe834307997ee5e13bd68e76a45f47aa82ab64085f69c4b2d609a5b4d24a7311f1f0f0601ef9f1d42aab9492561a004a29a53cdd0326b96bd624ed56332cb72ddf0e494e8e0b735a9f0b3826332546b20ad1134e26eb3b6b36c8646fefd4913b3566f774cd09b87ae2ca2cfdaae47e7e5923fa407804d594a83c0de2314390134ab2224231598c870cea710cca525a60c4590b8ad6de60b797b5d676b693373b4d34786a08811ea0943efd1e57e62a3105d2fd218b92d2ffff27219aa064d908c857a8f29ee5d7e56971dc45e9b04baa586d569bcd66b3d96c369a1a96bc49cfa3fc87abc96469562b666a561af8f1bcf6214d9d37ddf6530d431d3434185ce9a8c1290f955aa1c306a3b00dcb632b3e8cc23658e8c3365f0aa750df89357540d64b524cc3bd3c13cde42c57ebdb8fde99424cb57dffcb9891dbade5184b7932cb32c7fc566b6db5542adab79a41a81431f43385101942fce1808f98ec47ce600508db8f47a94f4a653fa5f724b11050f020f4336f3a1f23ab905c1784c8f94ad22709e9c3e15aa4c6aa8ff69161a45cda409eb8d29ab5dd51a5846f79625aa4a2294dd38fb5f7ce94e40d759bb7a1a10a0299705da247f754fc61be4bcb98d84bc798a69fd7bcbd8cb1623725a48c892b8845ca903f73e63b3f676f4428d631a69096f144f20ce336d80de6dc57a5acfa7f251ffa2e3ea890ffdbed769bb79c6ab3b1c1c3906e45c62f5fab1175cd03305d92268d0680182e872b8f2d1fc4b1a4945f721314aad631a495ae8d58c669abd97258695d6925b55cb45aad56abd57a28c116a19f0c988e1065fe020c068b113d293214246b2294e46130a2144e5c180e3da59340c81e2409ba2f1216ac1949605316a1425c6bffe9ffd75abf4787bd300c433725d9bbeab24dee2a56fd731c676bc51c0854bbd51213ee31752c36b1660fdf913f9d65e1e8b85c978d2f9c0dcae1ce22011934f0be1328e528e59842a5505c9696c6a5a571694ca152282e4b634d0a75023f8f86e6d6d0d0ccb05e1ac8174b9c425dd673014f2770e9f34ee0d2d2d228e5f875266b39eec32fb3349868e84629471a6818979696c6a551ca51ca71695c1a53a8148acbd2d29842a5505c96c6142a85e2b234a650291497a531854aa1b82c8d5746fb2914ed5228da9530b3657574e9c7142a855a1a1dd3cc9f203dddfde481cd719eed4cde079e64ee0c4d0dea53a9e04085940d7e1256b9111752a9542a582c52ccdb54e23a2bab54e645dc572b10a8c32b160b9b3b02949cb9f3e2967164b1484d2c361b0b162c6e5aa06646d3e8c511a9765373a52865b1c614681fc78202064ee81e19cc005be31cede346264c1daf7b4c4832d913a427376496127b0002cdac58b0bebf333317df197c71cd6a0e8140175c32651f8805fc64bc930dfc6c349b5846486ee44648b22732d993f9a4a8a8850b9a24e24c9e96a32f5e80408fa977b893f867d8b13a09674448e845786791196bd10204aad8c50743465e94aa03b9924996ed6028896c68064dd88b172fc2ee9e53b646463264b676db368b5c33cc0dc607e01750e9839c6fcb38e6c4f87c25b1cc70da6208c08454abc9c4298aa128abd0aa003819df0c10acab6b309e369231dec4681f37cae91e0efb282b5a2289aa11677d947d93f1998cb229b359abd59a0102673b292e91424c868666cc980142081505a51e4ab2888c8100020821d0a0b63361894b450821844063004ff3311c36680cc05fc9279938138b339c414e3880afbb71efeaecec804016ef002db15baea44fdfd626423718ebe880401dd6010f309be7abe1c9dd417e98e3cc3b753adcb58f8fb64da69b4df6954c9c297d1ec98bff0f7b0ef8f89db4f371a0e2effc8162ffda7bed94d96030189030317c12872d2e32cc185923e50e294676982c5b0ac9a59a8d1c6292a584c1602afc4813c84c79132365bf66912ca51c132583f8a70e8f0e08b3ece15e62c29a3a17e46e8988dc81e92a625ef85a9029b661bc84f1c0b54982041b488211207b2d7bdb9eb20ccaae8a8d62d692373f4431029bfcf8bd10f48061c10d6eb8410c90c01811213f9e3539263ffea993b22c14a16acdd60c144262160a304240226c322aacf049999d5a8879451481320c31898e636d20d2d13c2676ca6ce2346de2f494dac4e9fcba2a13b0400465488d881f375800a302e48614252b416644b622455b84dc18628c727362c80d22642a03c06e298068cd56b843162a4a64b1f242873b933b4a96248cc8d2c48b24ae4cd08b1bdc0bc307395c9a1b865c9413183029306e23123e8c4938398c4e44318a995d530b3831dc0fc90c1fb8dd8a830b19ee69042c48fac105946b734749a221d55e80b99f3b4a12521049361843dc2f7794a42c2ec4242fb0580e6aeac8562a779425885a4bb557acc8d1e10f733f2b28ae3ff247822b747c0a8e2dfe562958560a8f6b4dc04b695ae155c5dc63ffa16354faf3f3d8621d8f2d4b87e31af3a79f748c8a6b4caeca99d18aca95b439dd87f45e36b7784c3127574aa10a787dc34287fb0aadb53fdc0659426e63990f4ecab55163864bdc76f7fb7d79369e9826a960f1be6e60b8af36aae1ee3e6407dbf4e1f50d0b22aec4ed3f6e83aca1dbb8c674406a8c104c62c07de34d164bc96d2ca7c441e99dd6ce1e8e54a526b9a2f55818cf6a59ed58c2ccb087013e4bdca3d216441b524a2965ad392d5aa7848b2eca66559424299a32d464766777766777164700c8159f26122560820387d8d0223ffeec0e47bcd793c58911a70991217f8b204fe495ad159f6007140c65b9c188177e2af5916badb5d65aeb10b533042830a29fbfa3180c29c84e72e068f2eb60554858d48f2d41669828aaf9e1e57a31a2f92166888c6d26489153134a170621b00922991b867cb4930e413c116c126412bf22221d0e2f364f052d58946ac871da8816645758883511c3d145e9080814457028156d40c85864051c369821c1d104ed28880788e0606244e11544a31caad150b8d9b25feb2c094c98e4aa88b1706d6cb872051e82d89e1283a231bb700205930683c18e44d1a202203da50363a6307eb860ee285aa49440cb0b5c50b95cee285a6090e40a102d4ad0aee78ea265091b19b4b828cd224c6389e90ac79de30548dcb152e852d0414787254ee1c76311e6be46c8d415e4ad706cf10a67e998d8aed0f1987ad8b9cab231438a9d5563b278b82f55b70a5f61a68e5f2d17a5dcd13da92c318feee964171e93b58345140fa878078bc96dec49a1e93d4154eb110cf4e8b0ffb77c3c010d645abf8ae90a02f36b4fffc71d6b8489232d0f0eadf4516b25eaf6705f570292a7016d93ba8bdce188dc12db2c16af6fa4cf8ce57eefb4923f3468cc90051357e220b7cbafcf7d5af54f25e276585610d79faf62ae9a2a06575cfd5692c94a12cdb062d34a369961ed1d8e533b9b7cb2c4e7cf4be6563672a1262e4dee23159a6489714c706b721fa9600308ee4cee2315845ad0eecd7da4028c862bd325044209181db81f0c421e6e97fbc8470b4224d73b7231c68710889323372a37dc0f071832a8618ae8c3f5721ff958c104b7e63ef211a44596cbe53ef201a3b9a37499511bb8a74295c245a3e570d16834174d872b878b46a3f9d72e1a2d878b46a3b9683abe3f4551dfd5c7db88aa48d009aeb9e3a2d1683453cb90728a0aca08e1c4613b2146feb8bd132de68477174d872b872b29c9f522486fe58438e10c1180c879e9fd2d9ba391ed235bc68cc9d45d8a31ae5f07a8073febb2b56b1b756e34da08a12bfc2b8e42152b57925cef2e9a0e570e575be92b9df4d2c33027c4e9300c3f10fc4cb7939886735c2fbdd58a31001f12bfa40b395c345a0e178d4673d174b872b868341a0d575351f46decc499aa2f9c2a3c2fec7a2fbd7be68781a9232fd05d5e49ac42a680219f913c94deddfdffff9d524a29a50fb8930419ffd34b7777772ce54bf9ff4effab1e67b2de75d6c479edeeeff56b777fa7a07cc09ffeffc6656c58ab52d15a2b5d514a4998f7b3dc8dbbbb4b4ce9af7000e4631266f84e030306954c316d3c95f3a8fceaee6e4b6baabf97af1cbeb057ba12bfbefca29452fa2ffbcaa189dc8ca59452eaf8e5b793c194524b29a59452ea81df077a4aaf97e9a8dbeeb7335fb9ee6a739a46536b28eabdc8eefbfa724f2f956259777ac78425ab9b6567284daba69452fa1ed8e0e1779f3add3dfd294f6d7116f5594ae9d3cad98e524aebed0429d64c1d8952eae269e5a03ecbd9f99da9ffd27f7de03bd269becc75758cc63cad0f3cc9dc194a29d8dd327786a60675bf199aff477dcdff7f8f4acd7c3b5d4decdda2391da331a594524a2b4d0d8a529a9ad286e2d777b516d72a3357ffdf4bf1fd972b255dbd5ab955df2b85faff5e2bebaee28a1072ba7b6581edb66ece4963ce3973e6f4e9d3e7df64efeeeeeec972ef6a55f2bc39a7e339fd954657ed7dce9f52cee67467bde69c73ce39a75fd895787e375783faffff9cf596ad7f73fa4c25c5e0e7513c29ab398eda315f393a865677ec4febe931f8d9dbe3563a660cc5e17dead0ee6581ec983eeddaf5ed9873bc9646e7bd3e98d8c3691f1242fbf4c6f3f0347926fbada6d723db9b2debbb9084d0860b870e04341696bda9b9412c83db08374f4b75c3803bab9532bae72439cb8194b21e012d63e21bd646a57d35dbf8367aeac84a95bca3bf338060a6cad10c3c7490bf07c9165b9e34501d2141fa37412808216a803283211b55e194ffffc3c712875454ca01c8145b8aa4859b2e2f9e40e7883f715552c5c95083235fc28f5a95e106a2039951f10521b38420e28b1c3822dbbe8d1995109bdd2391680890a932c00c63d783aa735a29ad1fc470054a7e61a32b5492ae8c30aa5c8162063e821a1331519d1626ae787de3b5c91b00305c4e04dcea9e1499c33cddd399c31cc7610018b935b738dc608bbb2cf0e3e66648cb6a750cae95396bf220777409c575b524667f28e7ab1a8ec3e15fcd9793c3129ce1309e3a26dce18a2f873d0f3768b2d85911086fa898a24409b2ad768616638badef38b6f8face636bb15d7140826bb1c53756646c599cfde1b0b5788696e369cd90c3ab2188ec0e5ead153f9ee1062270936db7188fb0a0851147a0c0d8e182b98f8ef03074bfdc4747720899dccf7d7464098e0bae29f7d1111a5ccce0080b2e5e7069c2e080e0aab0d4702dd20b1a2ee782704603c2881035301244d1f5dc47465210c28c14d9c8600829bd69fa899a4f2557396a6f3a4085bee3d66788ec58eeffff2d27f32f4ff3ffffffffddddbfcf1de3ffffffdf29a51eedee6e53edb8eeb6ffffefee9cbbc9762050e37777f76aa25e77ffd7dd0efa9ffeffdf72efee52e6ffbfbbbbfddd5be604de53072e78b2bbbbbbbbbbbbdb57afeeb2ad34cf39a7bbcf5ebd26276d87e7ffeac5a2cf9a33ecd56b26b7cb4e8b27bbddddfd3bb7dddddd4d83a3ddeeee4ebbdf7ac773ff5957a652777759a9bbbbf707fa40ebfca4ac5fdf7274e94afcd57274cc3fada6af6368fda1e72a1dc3d9aecafaf5e95793f7b4f6f7e0385a9fe3f073958e01673f06fe7e4f9ececffda9d71e88b912d3ff80f5ffb49a68db5775d8a1b5d60567bbdad3e451295d5c29c1126696ac3779ef792b5f1779deac6eb735752bef0329066fc870ac578ffc2c1a13ca4df8815352d938373ff89dba6350fa2c21acb5f7fe0dc2ca580b42ae500d342ee46082792f147102222345e6c8080c34b2966bf04f1d1f138d23188e589c2c13832c834f2090cc494b11f80211ca046c054e6ae311413c61e445952317828e8488744cf95b1c872d132d20c95c01321d8283231686402ff2a53c62416c2d31edac90447eccc18d122b1ce5aaca15ab00816a132b5635638523f9710a10e8392b5768e48a6d40a07a332b12829d5c71aad66a73ad15dffa43ae18d72752a6a88043814095e21a2247e4a7921fd38040bf82232235cc1459f98b45e6a60643029938a8d4ec5de88e1136400013170000180c0886c3218118071339cebb0f14000f4c783e5c5c2ea48bc3a1481003290a63200662180620c410630c610632a8ea08003bb571b1b5d28e6ab92538f456f188d0a93bc2db4e411b91dfb7b4856b84d6e480282c8c87b213b860ecba34d473f9b735bbfbba91cb070e27583551eb3da938d2af070a9dea78e31d45ae15bdbc4b472bb0e231cad3c4b1669cb35b5de25156c939cf179ee56638e10ccfecb6a85f71ca3d35163060397332c2b945e7be8b899d412132c255c1f44537de41fec2f8aa318cf66b4d8990abdc9bc6ec35b76dde7ac80fdc36a53e9d587abf2f40e01e3970815631636c60ab0a1156e1d4f90f3bb46b4f06b1e5cd616eefa50cb268764122a6fa3d35d117befc737f84ea8b99db2c2b047e2f1df8604004e03229edcb7c70a7f661750314339dbff564fcc0e9c9a593a0df6f6882278635bc7ad7f242e6bc7fc8b650b4fe4b03d8bbb5a6a20cca8cfb705ff2d320d58f8250d4e15356a630b331527f21d78f0b09784f078618b31f88b506c5d3532bf9d045cc023420f54490e05374bdc7cf38d30032a38b8a40b693497c3e92b0198836f00edbe47f10128bc16a040f0755a466aa3360164d6d76a313e9451b5ccb67e7a33897cb09c30f710a3d73ad16548444cb207e87903444ee736dbef78077cd2f9adc6e9d6d3ed530e1a06a5634c4d4df1e24d7ea482951f4d033d2e2eddd15e64dead564dc9fccfab1fb39bc2e9c18b095510f64e817100070a66a3277ae0f11241a121fcb9dae7e9388d17891a97f1a180b4c38bd1126224e5b5f1888cf60c1c7c3f6c8dc5c77bfd82b912b1b53194cbb4a049af1ed9f20d4ed3bb4663028c538739f5839151ced87d66d92105c67058f6ac9c9f2c29ff0bdaeac1800e4455c7948ca6556a6abf7ff36e1a195a095bbf4daa9614e0733785d569c6900a7456c9b1520e50b3485d0470d4c4ffc09715281b1227c1a850f98634100e43b1cb279f1ef91e2a0a7458833734d31443a01cf2af6409bd49ccda11d47271ae8d5ea0e2b1df7e0d5b9e358ec19838921dcbd474a9b967b9494b4fd6918deead420956a79bbc567fa0f0f1736d0a0c00ab61bdd61fb4dae7c1c1dd7fc32c05bbc67e5e4884425336fc30b1fd3be75c93ed4f1222ea65960f253ca2846d2c0f4646142dee13f2dd0a4587877bb31b64186d40d1983b70503c40c61f9fc363133d3bacfb6e5a6d6eb386ba0c6d09ed88f1daf1222abdd5a1fc352bcd6c50ff4dc9dd38c2c09b5f1fe02413f3673684382a1dd44ecf827e7fcc956669913b75a0ae217bc764f8efb0a243667170f49b01417109bedef089cab7c89c627a9f7a7cd11493dd61ad6b4764e46300cc5ac8eb08f3b448148dd44a212f5437073bf71efff21b519d91fcd1729f4fc7684d2824d965102782691e37a21667a4a99c44e0950d4c7229be3e1faf9d1031a03029070b454a7e32543bef3069c915bac9b164dfd320658d64a7573dd8875b1376feb28e972e1266fee6bc5c75bfb808279c340a64e7c16e01d88954b8a5e38e6411fe04adcb71e5b9b20d20001d2c3b3489378b067930d9d171d2166ce7b6059692dbc6b14fdcd90ab2ada6cbdb63c0177a94aa6ddeb62a3139d49bfbca036d955ca5d145d29616274e6074620e8250891af575cbf83f6842ecb19b97a1e8c4e684d010dde9685cccdc21916e103fb0570e37e309a892693f9af27a698227b21cf152c854629ca0b34cc9a11a5b82278cab805ef2a2fb4aef2a3de8f203ab31848683d4360d87393e574bdef9e349ee0a42f7c1e13f0e620d005ee4364af3269467a237b46bda1e525da1d3df2495a4cea457a4b00acf0597da411502a56c7e9d3cc79a3f1d3096b2ee52a95aee1640880977a17450e8546d5ea6f0808b0c8f95c8815b50ab034236e2203c299503373d5acb9164df38d7cf932b14842ef4986b174a9b2e4b87f125d2a8ffd96d5517aecdc05c5158177925257489e9d90bc2cd2d0a534717bd0b2e8f6d4444f5464642f883294c9468ce820cab0c1d66012be6bdc7e47b871e7ee9bd53748e9f69a75a1895a1ead7aaf550686e75ceb529576945f464141c587a4cb3204891a18e16122232c485208b71c93edd5ec52daa140c96dd4f0b30dc7845f615e34a5a515e7cdbca068b8b1767bd0a3711205ba86ee9d3466d51622022cf2c34f7df617bf6e2ff800f9fe85e708b8417cc4e8943b75ab91e2f0117867ceb8c38142b34a2ceb90167101b8de441a66b77fd6e96f6f826d3006654bd33989cc79ed8582d574a764fff390e2e84a2aaecc89409f8dd638dbc1c3b482b9ef0f0c0505acaa620c53473345c9b22df075a3130245c7c962263f3b1911645aacfab545a1874317034359eccc515a07d2021d340647c1d7cb00555ec111cf988773c93042087c75c7cc67b354c5d2b3325c5cc260cf05280f81744499cb1bbf2556b89e3866e94f2fdcd9a112cffc07d51feccca81b3640ba1224109303432c4625229f5e8d87c620118894ce78261509d979c5a7b1285229d5c3cef4e688978c40558fd2b6350d0c15359c7e58d328a8326c6eca1802fce969b51ac6fea73488359b3c192ff8a0ad9862a79f2cc9463e5957bc0008058878fb6f122f4dbf4b649f0e61cfa6520f9df547ed9cece0d4cdfc2ca233347ec2337e9d0bb503c31b3c221c7080c828dd2b5439409105a0ebf1bfce1bc31032d85921c6443319c7b75c39cbd2729c9d510ddd074fcf1c422cd6adf9c80a7c3f4b091a699d1e5bec8e3bfab5201c630048b68043c31f3b66df91beae21889687aed006a7d745e82c50943cdbdeac4f3ebbb56b81c14922723d8f1e163ab24604b350a78632168fc3e30a1ff41d0073f52684cb9f089405181267286c475c016b33f306eda46ac0481d4fb529ed3c348860a38e373818b30e32f97b8bb124a366264276c5c5dd345b9b1fbede1ee200dcac8e02e2fee8dc9537f0c9e715fd6f6554e15ff007cbcee52bc1cc1e088283179a5adc121dc5e240b593518c8defdc1a41a12ab8ca33f19833ad77a39d0d80c2326f993ad123838a40757650782cd4660d175a2ec5195c84a008d94d24a6c4280f6eaee278807d2de44401291366e1ffb067dce109852b637b10695bd1226258241652a93be4959341cb5131f29e57c7ff4410f8551044860963b1130428e467c38a12858bd45a9504565d01f6ba0c901a2b90acd357d4e0094e1bc5e08ee580141088ea9d41bfd321ee81d8b055e759ea417e1ef71aa9f3eaa2a9d730b028a003cb997062e0cce01c6842ca64c94693d1a10ef3d0ced97afc87991acf5cff9fc785f2a13632caa1976a054221de0d73272465f2ca3eaf7f2be160f23a6a61b8a24b5b6b2283ea1ea3bf40f20c75d8de09753543dc80730bb09e6df2515280c52e3a4d0861da1ccf871f04f18a15cd8b00ed03fa5da1a527bf617a5d1e071bcb33e5f66559a8dd31801770a34e0acd35cc1882befbfb885f41bac8ce8e1bb42b18c16b5d28ac308b12d90a1c20f01c405c8e8f5c38a8e3b09bb614d92bfa3cd07b5f55ee47073e6601423ae0d1cf349a2eb1a6c3bd4043e8b156d764571a3b1eba08519a686bc0ba4ec4af54ade220078b463b1cfa3f5051854869fce246e841b834ec0683c589fb5bec071f3642bb2188dae89042bb2cae7c6f76cd42d1054316ae824c36750f883dd77d3341c56f9837ffa0c86500de8a297ab5621bc4162ac042093f2349de0dbabe6e93cc8a00978113b173012111db42b857dd4c08cadcf8a9f89443f87e9a8e5f46a5a5ea26e805729e8b8fd2053a2b84de1f9794b99dbc9c076c166d61b321b68ac2ebae1343e839d7436e9b27873c26988b3b56eed102b978223ede406d382c081d5458164edaab6c6da1407a417eb380dee5721459c8e641d68a30319bd2ab71c5487b42b07d183e763c98001f6d913e2f1a2aa269bbf0a462c8c10ac7825ded2b39c74d3e2f344cb2922bc3f61506bff128bbbab4e6a70257b0a5b5cfe7ca82c838bcdd291a078233da2638400e2b1a1a1e592ca09c584dcda74a0fd30ed18dc5121838921208750de5ebb6442a13e42127b3881d997329bc0223bcdfa30a29430c59b430f5731578275dc7a8b4e50e2e77d0838cf293122a9a680197c2e03cb49b35d70cccfc043cb5876e4176adb22f4905d8bdc2cef495263851d456c36deeb236c50b70cf770b28380ec20c2f6b9f9e4108759127261bf535613e42e2a3767e140bbbfc703f919427277591623c6141a4f50583eefd812f158edd7841af0d01316d1bc3e8631a501883b7328caf40244e9f005bf83c6a7512a4f51ee94de344602d96f05140fd769a3c351ed80d9bd7030dce6b9c0e913988a4f0b2db1dcc8feed0dd28253b91e57d19330738ee82f9cc5890617a47ad0bd3d229c701749d200d2eb8063867707fb3466ae9a72e7bec7df4e2baf69bf5f6ea0de4072a8c3280e008afe7617cf388fded2bc9411892cf9532963c4d4f0a888f743a98f44ecb7fffba61941e9989f0002fc604a06a4c00562c8462ae47d433040f0d1c90891ce0491294c4c5c985bca61919ba3127adfa366db86b6ef2433397c862ede49572217db7d3b21596af8996ab62446dd79eee7239097707ae3610d7deb6435c9bff8e6d565eb652904d46badbc1f11e393ad78ecd64033bb1594921301dc629dc529fa815df6601c1eb1fcd4439dd9a409a59c8bfba4990940a014137357311a94a5e73ee3ff18abe813048a9e0d483926f9bd68e3d9e5490b35140b0bb5e31ceba77ff8396bca321f38b385b902f493c3a5b5bf7e9afcbce86fa1e7cc3e297270f6a68952e9fabd6377b0e946901ad59895ef6c34dc4aa56a899aedf3fdc0d14d616fb08a5ecc89d2b333764c38a07faa87460d064f557512717902b37029eba00d92a44844a117b8374d5153c65346b3e22ebdfd1c20bcdf030ae244c1770ddeea3a86995bebcc219107f897339b5269ec8e7cd46c53fc1b0521b36f3d7c94db3e2675aa9ff644b4d8ec76b75d84f9f4ac72cde4a7c4e034b2107a7081866484a7da76656423629593a7ca81c1e9481d0d41967e3cfe00b44451936e111ce5ac1c2c64bffe56c05688cbd1a1be7a025db666b0d717ceac7e7f6dd15347ba1ea26f8d3221e68764904a5d1ac3792eec48b8d652a0e3fa21a4eb727717638d83d3043b3e7f4f32560439dd21b809d36ec81af37ed0b55d1b89a757f790d1a397846d84d5b46696a3bd6a6d12bd68ff7851486b0db7e628759e7e297239afcd881d99ed3234e4a13de9a74441b28c7691985d35ef3d06ea8b388adcfb0ceec20831ada9eb4e3f7e7e6dd1af5c29b9897ae57dba4e4714a3a5d391bb49c7672602934d403e6b483f49099910ee98983ab6eb252ba4267ebe742cd6cbde53de7b04cce4cfbb227c4dfe72f2d82c7d65eae4a7e3ec8cbe9afd0f97d1a2f56a1130635012ae1222b38d216204882ca83aa80131625dff0abc2feef24b82846646a9ea9ab2af577da7a720dec7a8afc11a70798c9fcd702503e217f133a1557a6aeaad46f3f2ddab59050e300515f8e4c9bb06a4644579f066dff9407293003862807bcb2caa5d618349f7bd81299fdfde77c1043f7777e7fd5a0ced70cadf7cbce5588020a266fc1fd8f6c8ecd0f50d3d056eced0e95c5e6c00d8b4dd0448adacaf0e69b5c067607177c61748bb37c4ad6f02eb6560146352417555edb29d5d1616a799ee5c9fd5c092ef97f9bc92646a9ccae6bd7324de5812d5d5ab96a29b07aaf86a66ff0b7e4dee6fc8d26a1e92e2e317991507a1bd22201fd552177d1e7addfcac2d686330095d4be520e15e94cd0903b5b9b1bbfa03edd82dc1871c9d12e8ca1d6a4e6fd337b3a64db7fe896f2bd2a525899bbd62b6770816c21cf0389502280194cd9f91c39083da68306f8567e6f70adfe37e4097225d8a57b8edafce75be8cc88dfb0c4118ddc5df05c32d406edc8777dd0e459e4995d5d1a5020e38fcc2c3047f134023aed8328e7293dd1658bee72a3771b40f9036cf06c8c644b5e5334dea15f3e991bcf92ed441ed4081e5a1c1fb9396dc9da999c6caa5bf237ad0468633090dadcd9b6eb53a635d3d92e8f572c9cedf4076e34601040c3797fd1b619c115b48003698612dd274322a0ba5e6385c499cdcd04d7d96aa41bcc5d958f03677d18e9e0c858c7925b4147a189c9909f24b62f1855db48278587d726238e474971208fd2f23102564415f1621c31b5ae7020799b151f659769a7e71f01baaed61567404a65dd1c2ea7adc9550aeffff50292fc1161f0b104cb161ea6a704aad0f460b244c109e476304daa3c2b3898c466e574bb6b08a5308e64c2e194f3d050d85b81ab4219fb074758b2bfb847047d8dd29fa7ae882752bc52570e8990732144fc371222dc249cc9acbcd1613cdba85355700d5243166ae8c798de09341d44041bfc8e87e8087af7ba75aa7d51eafb78e09bd1740d58138b81f0242c2cb2db38fa7da17951fa94523bdada8a641129395ab908721a50721ef5482c106fae070630c3e84126f2e7026e2cac916608e2c9cde19bd584076d4e58ebaf2fa0e416a30058348322c48336798a719bb8ef477d4d5a8106d437baca5adcfb22ef9486b7ed95a21fd11f5de0d52d56ef777b0f86faff9bd024772878758fe0ecd4b4906ba855af06d2cf03f74d715a82999b355edca070660d5f4ffc81d5cab272f1f3f803edb52dc222d207bef40e0751e28314f23996faf2f444c7ae53d6193bb016f9082fe5f724f903710fef65f740aebd792c13a7a45a1fa03e6da6f334c5258f63d4cc66950ff56003518be09529c1f3f94197486ea0ff39e67c4cac99904fc4d0baab43c29e2546c9c013d50cae6f2c49f67a528cf309083eb0c44671c5fe34541f08090dfbbc6544a650d1c8db8d30eca03e0eae5f27e2cacd570311733551af20eb8701fb885d50e9838f154f1daae4482deaa00119cfd741fa0953135681e38c633b0c35c4b419830863958d5e895f8f14616d5c7565d4fb6404727bc2606092825728b4865a8bbc548f55954552e1aa0a4f03930a48f64f8bbf242355c8c5f7a288b81d4ca01020f1799afa9cbd4f76d8d52651e10956d0aa1720528924bcad9e97446a1dcc2ecccd12493477e6994fcd031647126bcba93b6d09f80ef115d1b8f5652778a10ac4639454dfabc77057ac09f3d69b3e2998a63d0b5baa4fd16cb1d8cfb8f9f8fc496ed431aa7a5748605d6f74eb7c71aa5eac94662cd0a61da51a3eb3240a173821c467965f81154a185713cc1d94427a9284467750a918345fd158c7e1b30910b84dc5b65d2f8053252b006cc75785abd70b4263d62a80233ab8922ae393216a9d8a5674c12ba44111b3ccddf2a7b02e22f6ca7e5ac943ad686f0a4cd76c5a826fe61fc45a676c129b8383021bc4396917a802602b4271f407ab4978046c92c1ff39692fc6bee0e29c46987074c60de4820260195e75091838e8dec05f427593b0dac948a1d76c265f0489d4f68ceea602d18ce71506212d51f864e60c1ce9f77eda39433b7bbf1a0b2f280cd9d524392b4ff0222fe8a62acdd6b36c2c2a64c07b946ad2567cc2ced2d0d9e1e3d6a56184c10712988631762b92f137d3fced2037807fe6d21ec72827813d073f828a6c3b5bc573dd7a60d265e64dfb7476ccc961827600a891e58027bb7b8f044dc299d4bb0435902ef03b31fe65845581c192be887c17cbaf7e9ca897c250127141ba4c5f76c0a3c422999b39b7b52a923d0870078d55058891277ca6b3504582dafc146418a77c22c0dd1cf99741164506a70169f1855135760b3494832766a53947b33bb40d7f656b8caa6138c4e628ed40169c036c4e3e2386ee31e0ae55852b5a769c78a6e2a9f7dbb6141765b01f0502955608a78a7098ae16e75b19590c20a47359c6a144545628fc390d1c8596b8eef54ebf11ec2ed84b0fcf34e784a65d72f7a592c16cc4b693e6e14f0868417130192a5cf2323aae6c51d7cfe710678f8c87cd61d4e2be5c98af5311809b45be29f67eb5e30d6c9c6a02c5b5b6f09395b5510454600f6b673a21b2a9c50f177cafc02a20c63e23d06e898f8fab8fe0a693c8d3eeb800d390efedeed045a871110b5cdd158c8f0a0b82adc973fbf98096d0ac01dd8183ac7572251fbdf2f2c71a8306ecccba9b430027e74ad1f5eb755152d5bfbfd4ca1aed3e11d7b10e117f51da6662015f828b08a8c16f1168356d79a7a3d2611fe5bc0f0876129fa873f06c5dd54c6776ce2060883d41e41ca63c08141eae13a884e2059ff6a73ad63e01c127a0da3a4587e5b54ba8ba97465b216b997b6dc1bba316196c69d9352b10bdd0f94684bb6e95670ccaf6d5002d915ec185c8a6def1dd1194dbb7cf828ab5f0ac445b23a6a9e87e407069a6a5a8b06eb13084c5ba02448556f6680497be2e7fcac45743a4c492b69bf053a5aea7e28ca77b1cbb7a63c40ff29d5230f1470f22c315df38e99a6556ae4e8b6e8c39c366a8a96fb8bb7a8a264ba12d7e3d0bd689b4d5c3e2267adf52fed6ac145b50640ea6ce06b3e63245a4fe4cdba64454b0e182a5e640d50f39cfbe1e064a5e0d24fb759b7741350c8eedf6a4f64bfa7007bcec918f2b203c8dd2c7f4285f9a37b3e49a604ae703eaff2c1c59de380583e815a07585faa489448890bca0092ca8ac6fd9f9b93a9ce647b864f8213447ae2d045cef5568e5fe7c0229e33a56bff2d42bb75d1fd3acd9cf60ea464fa8aeacbcac788d094219caa9bdaa04904b148401fe2f010c0b5698a438ce50c7861b0096fca4aa3f871702dfae180c8249f25abacb8655612d1449efb10dc98bc1665c2fe33ee7f92500c2ddc59418083a4343a996525c044ee8edc0be298bd13f28be8561fa401dd0ad150530afd1108238889e9f5fa64f25a71bdb08e8d108e82888683d8ff8baf82b4f1709109e927612d95719e402c2ba0b1b9fcd1fc5bd9fd9cdb18600a626bbce6dcd9653a84b08eec2191420524f6678dcba412d422656b898eeedea9d2f2748d57c88b655cc3c31ed054a4dace0a71d7b4fd51bae7752b81311d65d42b7ede5e3c477845f7a06bffbca4b41e4305ae1e4c428ab7341e03af9a0b6ce8ee438b39ce09edf48025528c338b8c807b737080003a0884764b972dbac5fd8a1d196b480f6d5f1d9356a206a25ef7dd5504b46973418090c0265c30072b3ee3344a6f18d3d19cab8df175db8b3890d88d12cf097ea8e2f1543c1a0c06946f556b3c23781df1af9ac3fe2dbf781e09c614a10697c1096444f7e0da43015471de4d2bad04eae4493ca8a56f6cb8a4cb78c10fa4b138451702ef10394d19d2319a05412bb045efbe89a76e72b7dd9a4c0de56367ed8b2fd1605c9e5a4b7b5291a8cc992d2e2810246c8f747b0de7f7992395cf66dc180ea9e23cc14f5a55945c28e822cf1b58e4c7240b78b22e4e0973cd5726ce60fe5d20eba9fb791a036c29aeb8dfb13e22ea42418b06fbd28566c9746891fa8b388e8791c48c000b868181b06d06376ab1824ab776fc08c60a26c537d49d1f65d2d4f6830af29ef5b1672d0ef57c33f3fe19588efa84b41b71ebcdc6c474af7db3907f989235fe93297d39a50c528769dca711ea614a4f773951a3d3f6e1040ee7df39d6e922ccde0e0a8ca9aa25e29e03e8601a4956f4eb518588b727f21bae53405946812e8c89a32e8abbf7452a6697e78132994a47d69f6901f05dca76e278121f5dc4ab2f9228fa2865b47e93564094e39546ba2dcfa9920b84e2c40ce523f8f5dcfd91b25729b4fdae63ea89c7b241e1c596999fcfc03575cbd39fb0695d55d8e5152a58a1597eb72981311e4b9dfa368b8ca33c78977b54d9d3fb7525162866409962bd7ea34e201131f8f6c21e9a518e98fa4668f1dbe156cca4771886439bb43d4567ddfb34cb9dc318f3731c24f82df80305d1be941461806a6670859c3fbd984d197d53f253b32045021f40091dda44c0175408d80b235f82b40d708bf5420b6e1612c43bbc614c394a8056e818b82a0fb0645e94fc71411c6067aba2cb208c3b420e1cad140f112112a978947b8202353855158fca35bb8a2c201fa1ad233f64e8891cf0cdcf6a73b12da81546f188eab38bc602850d241a538514f839d01ca624d5a7b05496136a5a4a80fbf105a3303ded484e83f2e380605eb4162826e800fba03e24ee8082a33e003748787b10d426d980a89f21af41144c7d85cdb6af8d15a60a5819d31658226128875c0aed86a401109c64a37565b310a4306ba89614ad0d895cc682a52dbc0663ee9845e66e46c5ee09542140406e70a9c80b40bc92905961153b742fd27cc0358f9d22044411da85bc8dc264052b8d13e3be0bb9fff5be8dac7006c4165f30f349692ce70d6723161e0a716c2bdd6c29cfeac2468d3c8e81bec420dbc1f82849155b98a6500cb1db90c2a13fb8237578424368653da4bcde9f95bbae556858a874b739ae2ad6631a0955ca9247614b59e083784a6d777e5f555f9b1a0490f623a95dc651ff8f81ad093c29d208a832dd5def508bc040bb41d2775fc1bb80365efcc7c14911094c1865c6b9ebb71b58c02552149d21db10dc93f09043d9186996c0af98f3ad3a06713c45bc3abab2590e318aee9e0db39a807566fab1a0e17d8a0062d935d08d59882462120599e6eb945e714a131af453fa70f40584ae71d703197676c62b09afc5bec59786a72db2657265298f89d7f3d5d029461480913ed70caf81d9f31cae1495513ba0b39451a8591dfa0ceadb989d6036971f24c2f75d36ace8b8f298413dc459b9a7c74ec1f372833b21cf0f88500d4d61d930d0de98472abf6859082f9beab109e7b9aa24f80f67e2d273ff3660ac2ac265a037409cf83bb723840be1dd83a47b5946a12a07a3128448876cd0d456554e4a2c6d211009aceb63e86c0137ce21cbccc84c23d59131265004aade2336d2fedc26a1c2a9cc5aa272fe0cf5f33d27a067eba590e0b719e646292547faab164bd0c24d5a85bbeeae1d4ad72155f40cd2c72248bb0a10bcc284379c751a96a5acb54b027bdadb032b2ca0a54aca352b6b0921913fa0e7a0618c5602ebd6ccae333feb8fdc343f2d42f3aba3f411d69d26c3c5004bf99b3bf535877cb58f101d43d93daa296a94bbc8820a61569671d65e61979eac9f2a86a2ddaeb501fab41dd543c742da0e4527f04000a1c48feb4d10bccc079c4b36344416ea0948dd4bd7f0fdbd682094910ff468616913c01b2b07850e81eb873128683e889d785589c3c0dafbe61b2661f1415db244c18cfac9e30e86774b2b19e0508f3d687b4ca86613442315c42f1244817a7eb07aebadb654b3433e886534dd3839a6da9a58dda0e68b37dce520c9ee66b8fcb8ce6361c8bdf81d950821ff46cc7b40f97ea5d537e578859378357420f722a3420676ad204a8d619948677d93085936cf314a8f5bf93fe690c4740af777268f6ec35f0427b45f3cfa6da2374ca57a03ccf6df6b1103388cddb623884acdc4de051515d958878757e1125044ef03c9ae121ed95b353b00efcad93c6dde70bf12a077e7e227f01e2b5ebc00d0e0bb59617434cd40503490e9ac80f32265cfd297efbe64712357d5027a021f05a6c62081a890012bdad8a8b123b1a38ff706c0caaa50290c5bab95294c4c5c1731831ce932ee11a59f9ef712a080343d08c527263286cbc0975a4965e23d37c4b519cc4a05873e0376443fbfdb0e5d645fab842e6dfd6950389cd7cafb99818b709ba10eab352f3946bdfbf381cfa0e644df698a535ebbb98124d42d12d2b86dc702eb21902186cc0ff88688cbe46f1be0263ca1762029b85414ded2ff7010dfad105920f77cab0d7f4cda2c2630fda6d469ec3b904dd1ac5de0e623cf6a8cb46c709016d0dac2e5bebf3c0e458bd6203578dd9ee112a57b4915149866d828525105ba01ceb9f21da4d9c828f28eb8e0f5f877eb362c0bda0c6d117727344c2367b10ee3951aac6dd98d2759328f0ca6a99e7ac7d20f361fca569d8982d4044a028dce1d28bcf18d548cbccd50900298914726dd6b47200331cb7cc8b519061206db8b39a0ff8b8e6a261f9134f23cdd44adfa5e30b2c7fff9da6e6c6bcf86996a6535df054f3b58029f557e624d0d08bb1a8ddc1f195a23f4ec51c69cd7ff81d4257ee3d52abd59dbf4e6233611d14d001dd26cd1b077ee3c5f24f278b34e8fe201b830da21be340fcfa2d17f39924e569830e31f6d2239f7a09e3b9ee2990148656787baab78b42418742346653ee38dae9da3e2d363052ff6d704c7f667852f25862069e583fadbb1690df6e4be619764b1ae7202e9b583683ddec99b2fa1395e3271676b68df627c67d35d2774a0cbd91f65a021fa06aa6aa0059e3d9407e79ec8fa2941acaa6cf0ff4af99226a0dec8ebf9f3cdd36b099eebc434b9b235a519367d2d220fc2b96e065d4a348fea9e6cd2523c3a56c2721aaf8f51bc270345bae13c2da86b3838b8e2c7d708473d1f2729958c95aa65143a597c9d2e4b74eb82a6ed184147de7dc465c2e2a8a84ff5a0003d1e1fdf17d1458932a442ad009a2719a2bb145b3baf82c39858b5ec5ce8674599fff3828a48a3ceab0df7e9d86ff04d6fa7cb6e6bc031c2aca0b7310d090d812372faad95c09b55f28162f13835933c3b46a998600e87588ede951b513b77a1f43af5ffb1eef6801f4b93aa00e362310a02ba26d2dced2754a19156d7d7c246cbc939a6aca78ace58983c035390836758af77463f8f9fc349cfcc27964549dac7778a658361d84137ffa7d46c4518caa2dfbe738f7629abf505936121feb49babd1ac44ce3275a63fcba3c4c6b0d3fa99a5baa69dea226ee5b6d4fc5a92af6a5e52e97b135e54dc89b7cbb690a93b5dfe92df775bcceec12e88bd322e63e7200d213a0a9f3c4e92d950d63051b65ed3f42132fba7ccb62d39d5800f28158c2eed121b3a17fa7d1326584537390aeaae48f5d97cf95d3f584fa274acfbbae2a5ecfaf0ba6748afcfbedefc419b62b55e2efb49dbaa3770d25ff99d2aa31c67ddc7d5ecd8f38f42369502c3874e2d7beddc255163b98374571302598979ad8b2ff1524934dcd8f226717a37680e0765d434671d730f546be0b3f91a17a78e6f5c7c707297950a768ab7014d39b0986a31bb9feb2d403567f2fe252cfb926c1d6a20eb6f6e74ff8c11c7a06dc871c0fbae4c48bf59aab81557ea515661f236a4e8dbb07b38f824ffd068b786666002b7fb9b477d457a063a059f9a0e0110363897dac74d98adc34b3fd1d8621b28f992117bf00979eb09749c50e2774db1efe390935726f1a32da030e7f717da7b12b3c375490a6741e9edb81045d994a0a677bb87afaa66c4446bf55d68a1a11fa55249e671dcf97cd664ae851cef4552332eb1c76c1af25d796f495ea10cd49ca740a95dcc4e6e3b49e899053d542bc8ffb8441d335228fa17ed3b5251a8fc3590ce1fbdbe02135e831b30becb6438614d5fda70e74e730777331f43efc9a63348eb8fd7662b0d97386d002d8e06cac2354ce136bb82b5619ccc9f85df17f630c783912085bd1e259c69657249d72835db4005ce694427d4f0d5be59491c8ec4cf0112acdbb5b8b60da1ebafdb377af7097684703747f45f63db5f62e0c5403b497349d457a7dfc1f1d72dca54b40d38fc69f86c24f35f13891fee5b466f6821b4a0472dee3333a8c5d5ca5d1f0c18ade7cdb6932d9c75eb56ba342911760349dbcaf84a98dff196a9ddafc2b8ad6d784da52b1461198fcb2e318f71580bd217b628e8a119fba34b2219504d3b0ae0d39a41da448a85f2474f35462498f85321aee754e204d2e05bbc1e0d4fb167c85dd27583ac18f7ef81268bd220bf2b682b4e41fab524c55a78048aafc06934f9c83d641afa8c4e42ce80445762e5b3db843cc681229fe5b7330b50797105598237cac3a4235c397d81e0b6d22f4cb7c9c9cb341c1e7b494b9cd48a263b27f1cf1945ef0b44f4fc8c95ebe4fa0e6dbcf663b1693d8cb636dc7d2c4ad5ebef3c35b861db3d257c945e2ae536ac32de15ecd5369b8f1a254ebc5f18df7026cd7913706734a377ccf79617bf81b85f0e36776db11cb956dba76101a033d42e33945ad70fb7f1c6be0b9af58444c7f1943c54b3d485ea095feec24b208885e10dc260a5050c889fb21b68280aa67910063523b8ef200ffb1397296039e22b5c9b46cf1f48a88ee9c9200de0e1b98b8733922c72f7dc615f62d6456927a7517836f64c98143990bba0905980acd21df42b0658eef1e6b7c8602fb0ae65f72397c0b0b47f8474aa43fb564808c64df422d25e81d93bea0e04b646d644ff8161af25227172ae54ae674649a25f30a5ff42a92536c7c678a1df5e1ecc35700fda37599f7ac4afe7c2b81062b6a375f4e224d3764e1cb93812caf44508c5b4a2eb3eff02245f3803acc018e2ea94da9d17afe89b067f96b5195943c3392b8816f3b08e9e1c0b7ae7669409062000491bd344303f805133b314417c91969a181a339cda45a721404d16ded7dec0ae7e9bd9cd9ea9810c70a2ca6267fd602c27e4119779102d1e3cf98c9188111f8f60b4a85c14be980a14f31873567713f6821f3c5d52c5c9779472fbc0cf6374a3a5bc44d91f8ca6c85e8d6d7afb5f9bf7d65302460a01790d50f644db96bb809cac62b42952e0d7917983166df5396d739d6e871045e369403c518413586d8b27c3d7f350b24a83100c70dc3859455671e3679a5c9c092e15cba6012882170131a7022fcc1b739cd1051c018e1975274a46664e82583d57798dcd4183ee2fa6080dcc7de6f987979db612c6ff4cf1d89b76100b7abafa91a42d19151886ce07ffc557a49f9dc49229a889725da0bd10d60dd5246977b581e74772a33774b06ab9dc8e941efe114ed7581c616b66f0ba3a4dc05ddf48aa372d0cbb53c1c44596bcb14637f5e1121a48b14b569e6b86bca70bd01fb4a3a7277eeec368450d309fbe98ca9ff87b2c237d25d5a4149de38a5be1bb17e7fe666a068ff156d7b5b0cad2fef355fc14fce04e2496317f82db4727209120c0f3a2fd8be93e0775cc3c6a6761b8b75e37f99d4be23496e5708b92267735723443da89f0f96ce450360b9d31d1dfddf48055efd76941f07f9413e86d71c5d1df2e1324cd89dfe84028ff0c4be4a36d4b16eeb364f7efc2af51be8d1d7eb080bbe41c20a01be827d098f00f0bd1c52add0b82dee12b137753a71baaf8c30fd14ab81f33402690723e747e894b0f4a3c1d3b3050ef9f669c3d1da11215de238dcdc12381d8c65b2eddca014bea6d73dedbf0c232ec5e8ef5e4e786cb44a6d4631a99322d9ffe0c3495c196a35df44d56506448f1f1739d5dca53b8fccb3819e7f17f7673368c8b8048ecd4e3a6daa1072d75ed32d8bebc5c49199163c3394d926e24feb7106fdcfcea91599fefdef18d524e90337a92d9ad1586545c1dae1c3df6e040dce7f55a9f488e0011a36fe9460f8528fbb3e177127de898afd0beb6927c13fbb4dfaa78617b8ea234574b7b905bdb0f974feacf00be10cc7e0cc0f803c0e1e94031d30b37793cf72027675505ce053c3d537ce5b74c9b55aa9a2fade9faefd027c2c60d293d13ef0d7728680a70fc8f419041c9470b558396ecd2ceb572221bb3a7598339d2abcf1001bb59edba032a8446954d5f42db8fb5485f68c626c60feeb555da8df251182fd708ea05b834582f7de84012ceb40dd15bddf0ad3f86fe4de17585fdc5d952832b995316fc396fbaea639da06c606029311fd9251797a4ae870d137d329d2ee8f33bc59fa6c755f87be7e3382409c479c7889bbbb6760040889297f1a065469ebd96313e988aea3372293bd89b626fdd375a25b1fceecae324cdcd6a708b53ec4574252eda425044b255c78d5e21a3a1c29daeb68605c8be2fa4dee0a026d1f80ee24e01bda2eded0d8e1c07c0a3ee8e80784dc22b846d7be67f81b618a4ce7e186beb9f5fa6c8daefe87c2fdf58691319f0850ba2df97e62411f732b3e714a85c46dda776c869ac65caf1a74d493f55c7b1d8ee15f0be33e784fe7174b34ed3beeafd92026445b84eb7979050c0b2d16733cab7a2e6202459d61f9053746283a111294e593fa454c66749a7254c150bf507565f0ebea91417d6d20187ec42f5fb7ccd77290f46294acbfc67564d0242569c3090c90deb09200ec87d86ae83b83830960f96b5248e930bf753a9d5c19f59a135b686b42df5bcbe7ee9a9ef299b086c72ac82829e8ebbf5620d777324a5f94cb1cd57afcdb4fa9e3c3c4a1432aa1a3d826d92a3671cec4262104b8d070bb7e7a515061383133f906604a072141fc965bf98de1ff341069658013977dff786461b3b13621f27d4b181adde0072d163b1572d8ea08d1529612230a3b9d39a8c5d83ffafc6e30576b7796377da74a31a985dae10b0c7b4dc9954b3f7ec3313325c60ac4920dc5d19d93e5798189f7575938d7a4f2635e635e7220fbedf9f0356e053f4bb4866636ddab29d13b2eb767d71fa6115cc85b492ef5d7452ec4399c670f00f9b453dfac690d1ec00080b69305949de57acc2a1326e66a0078191fa68ea255b76a1357456f5a125187b6831afda8209ca31716a06d782e4ad4f3988e0dd2202ac6e31c3916edb999be0a17fd97a38e4e61c7348bdae9dc7102de2b788bbcaa36ba7221d3bf5a2d1afef867a39a1f64d59218628dcf9f8048c942aea766a318d86c902d31226baf33cfeef09248a0a4998054edb0e98c3a98b87d8f3abeac04db5751e6d1cb6ec93d4d36d65553700c782fbe25bf44f9dbfea94ac227ce586521aba6ade6c4a9c9be4b4f467ecd151f997c7c6255b09abb95098f0fc4f56233168f9a833ecfe0c7faa7aabfbd7573ca46f6c23d2d11dc0c51c61b56557cfbc10501d05e19c860f34f810ed214e774dc3c2be45e1a44f2c7e9538a622f821861c4c92fdf5281a7d0377a7e139d3cb9584b921176745999a5aa9a9e465fddec800fbc3e54c417d6402f525e9e157cfcdb6e864f83c8e0e96dbe54efb2ee0434485c96aa3d5fa1420cf0ad78ecd2943af11bf5f72269e5a64c879bd9c4f005dd5465c47dc4d13c66428042f9dfcfff61865a926a5032501cc4853f90b9a23ac75a23a943e7d85c51330a2585b43077489602a60a3fa82bd0edf6f46811adb5ae829102279f4b526ea99bf0796b48bc5902521da50b95aa89dd91b9288d9e00dfd2b804f6cdc9b08394273464b033bb8b2013b6cb7e47f8807f129bde855d2b7242c147e66dba936f735c1123a79efc6c44c03a0470310fc0497e2e17f857cc340802095bb10fb857ff1057868c6239c054f1d058889b50cee6fdcca11aae53a6f454c2d15ab7a16039702a2e43539b60ca68e562c13d4ecb565d95fae5c29e3e669565dfaea37b7c5b4b84de44580c17af18278e7a6d9b564c406857746e4d42560c0a1102d2eb069cdc01d2ef5330a2bed9bff252b9e887d284d57c89b52b6633969511723e48d627ecdf26279c93d6cf263bbe7370aad25d10db31d38beecc824152bfe11d6a713da9df7eab0f1b4c452e8d0e8a320efaa6d49947fd82dc34b389601d0f8aca9db686f6c8ac376f4445b705330038ab7efe3b3a9714812b6b242b2d6a22eb23bfe6e3a613f33d4ce3f3be2ee00e02662aad313031e3f790969fa4276d7329de32355f77a9ca9b50061391b232cf0782c946aa684b99c7170e367e1a72a3284ac33751d8c95f28a4081fee4c86a0d97a094c73947a6e435ccc81e3ec3d0e3498ea5ae586069f8193e63aeed1282f523b0bd5f0c93c7fe16aeb05f70100d4789a3fb2b036ed7f7f602abb478e5d63bd3381b612b61ef7fc1bfb3589f88bdf40dcbcc6bc95aafba8ed05296e40080ba6b79d4664630a21b62934cebac5fc73a197b0eab7b3976cc8d5674d457b5109bd70c71089cdbed50f0490628bd5c47bb45effb36341cb17bb19b7ba3986e3966b0207411479311b02189672e33c4148e5bb06593f37659d196eaf9b2142ca8dd5bba539dc77131e50dc29426f873db21e1f0e15c8e35fa2eefea8f6dc979c0e09cd9d7272c8ae678b90411c97e9d6b004e12a37adf668e349f52189c83554c356ba386542ab7ab81651ca45e6afb8c3453819b252625e595c5e317f2aeca3133081de114e370c3322baa1fed60877745f37d21382fa7a0f95641d60570eaf0f9930cd14ae03840c1caa08d3a07b4cf0a9a0d34770daa393c75bd769a76580d35d2e68fddc7404d4b65c3dda54a7b7e3854c1fa3fb9aa0b7eb14f9979e8aa4d0f7c1a16b1d6cff434f2c52382ba795289d40f41c3c2f31b977e86fae8310e71fb58672871e92bad782850aa25dbed375eebc901dd0bd9e9273c087d2de24a51434bdcc92629f2ae19aa69d0bce0fbdae98c03ee5e261950b4afd1c7215b119783a68bad0fd1dee23391f8dcb35394899a352832d2754275e99746677801ee5c2cf3329fe89f3123193ce52efd31056cb003d2743615bf3e7515b3013cef3f388569f47bbd5a0b6862bd3530ec34707f4fa14360337feae21899e100355deb735777fad88089ba3b921627a53d82ab89795e033ed0ef0e879598a3163d4229eb86145e8dba7db6b9e4e05069928cebc7cc49d2b02f4b2793d0a6da10c5945366e2aede6a1639678e3ed7f2a4ec1da5b8c26a78124960b70b461f82419ab75ec0703ac0286f14549c844e937920c94347d20e4582e45057d2b3e5baa3a51c9a8fc05407ebc2c5d420ff8823ee160f294323bd0005052d25ac938e05f4ec0eed7d3b4c9e087c834c02433fbb084f2531c414bac8920b45ea75f52a61698ce6e747bd2e018a7d3c1cd1b42f96f3dece717295958d84b46d8d75a4952ea4a176ee9a87696e369ecc53d7465e4d3c759aed2957f5303b0db25675c0d4b889ccfc4f9150b5d96eb16b49f61794aa2a97dfb397fd3b6662766a209ac593ed08b00d88eb0131bc97179612d911ef00fa49e646b6152a13ef69f3fdb0d424df27496b44cbc3dedc3ccc7e25c96d8aa710bdf2bc45e85182e202c5b0d23dd65820dd6a65506376152d389a5e282c8b898527b317256bdaa3be98da98527c510afd369920d9b616058b2377b9e361af7dd85bca3d35331dc9d373fce60bff7e704678fa1e3737c79383e8c19f8760554dbf43148110a6068817e9c8ac81272e3fd2acf50bc1e0320018bdecf258d48852e9ecad58cc3faee4befc393bbfa76b18d66c07621dadcc78002ef3a9180594bc2267664547444fbbceaf8a019d7c22080086c4748b5a020d90209b3acc2686b1fe14c1b02518bf891fec37823f95658a15cd83ccc8a023c71c5e8fb9021d9a3cce4aa48622bf9793f56e2b3f7f9a6dd006e803ff2d534bddefcc3b24b60f90a508330be8390941d8cac27a1ff39bdddb2dca07253eb8ff74d3db78837cc02e3d3faa41e01012153f2b15df2423cb48332bd4c7625ed2436a61d91f1a0389906dd6a74a40193f4d051fa7a61472c5e709eef74f16f307e42fae827197d22412ad6fb9c9a40d09a9c7d49495b5ce2836ae9f82ff8dd452bd35b004e658a2818f1c32e2bbc345f80ebc54afd32aeb33708444fd8fc6c9b43f312991b83a8c4c7d1189bbc83fa131559bbcb69c8415099c3b2a14737596183e465433ee60189fc42c772a1175990792aaf00c7cad7ce604002ecadc5f73c650910570eaa49a7d602c6ab799a87a256888310fa8ae2ece0fbe026a68c2ac6fb40bdeec8a921ed3dcd3d9af03528a866778a11da18b06f8f85a2596f2170f572a6f939559cadd9e7ed33c225c55e4ba9aef80072a550f0d85931ac021f68703657f73e8925f81cd779fdf4184bb4cccdf667bf03cf4eeea24c54f08f4d158faa2574ddbb9edee98cea195ab7460685eec506f6df97d14d5e5989c054ef428c2b462661433cc2c7be41a546b09c3636792310c300da66e4776a4848b3a3ea6ffa0ac9896aa4d0f77bcfc15eff57bbe5ea37a0981d1d07131ef6c333740e199a41d0e12ff0c49f0f7117b31c49ac91ee9d33b161bba92904026b665d63083c07905ee95d9ffb49b1df8e4f7ee3b92280ed13a3084bd324e3dc161787a73ad8b36eea42d90f332cd30c8d10c34e65790d59095946f013a3f630b81ada24c075bc00b0837c9c54bb275ccf57a2ec947789d0b1c6595bb7f79399f1e9dc68d804a486c19be164a450b431381d82331abccbcd0cafa1934206e502f76478904c492be848b6559c3e8b2fe65f947c2edd8f245bd6115afd0974873134f6730b0cc74f359f06047671ffc500f65432ead4bea9f1fa6ebd86604267d1e5b5766e3d77d3c526e3cc2ec9c21425b53390a0398d49fb9a3775f4b65039932a8a6d3673ac46ebe94706b4c004eadf4bc158309a55493ab94997836fa9ad91e698ae1372c7228d282db805765cd2d761d81debd680de4b9ec23d23381fc5fe2f6017c49a453a361590a574c1ef05349642d9d65a687eb19753a73634726d6c6b9f10b21bd984ecbdb70c2d0cfd0bff0b3f6032f4832df2bc5c22ca9f792d6543552d8bb86a6d1131a33c3f7f1dc5196c49f4381bac5505fb655f2f419221d6ca13758d257b20ab394964a711b8081c64bf7894e7446113c6a978ec29d3b19ba2299ae26d748d797a244489f2a42d5a94679c731e80c7bd899e2623571368557cd441d7a0af8936284ed163294cbb32201e8e38a45cafdd20e92c8955927b49ee222d6f56eafdcc7643b416d073f373d3c40dd0cd913893dafe9ba01b2b1a47e92d858f5047a12877ad75b38158c2c0b65c2b55f5a9db49557d2604fb5a0f6bf58c72dfe3c9df25942b568fd1a071c05c8fd5a0716cafd86b3d35d2ab520684a650d028aa0b88c419fb7ada13674eafa74bc41994d7d37aca449c49793dfd8933a8d7d3261a87ca1571a519712d1b34f683c69ee819eef518111a23922b17afc75a72f5f22c0b8c091de2d124b25167d80e723da6b31d4da07924ceacbcebb118cf27933ca317752d4b94eba7075a264d9dc6c1f2fa0b49ae3256fd9514672ea1ebe7899fd3a07b814dc1374790eb6554d4ca95e8df0594ebb54efdef01f38b85dcc3fcf73017f2a7606eaafb7d0e2b75531d4e0d913acc6f52877977188c63a4c33730bf18e71ee6387fcac2dcd4bdb7e56f4bd5a5c373f9c815cceb67d2ced52357a9771db6a96ba54a3eae5aee928a4172d5826512963128855baaea4d295526a91c72404a8734e381e9ba2c48aaea3defaf35283b3aca3cefef3a6b934a317e7e7e689665493229294b4a4a2a259592ea4fa9a816957e4a3fa59f52515151517dc62357f54866414212a6eb8e783cefef2c4f2614399b954f9d23d95913922bad2555f55b140d9d904d91ab1572ddae1081c6a3b53423882bd792ab3aa426916bab12b1db85b91615e5fa7ad4bd5e13925bc0745dd7e10f3a212857a05c3b5bbf6942b9a6d8934c922b6d8bc6d1597ac1d28de56a465da36e3d5255b52cb4aa5ec80b3a50f793ebe6936b85c2e681a7a1d322570d0bcec684371e93a954043724106f411b904c6a1cdbd1651a7a26d1383a5756b5495a4faeda0c727df58255c97832dbc18c27d7dbbb3511bdfad3dd80a2578f72b723770b8a5e7dcadd9044af1e7537a1e8d5abdc2d49d7a8cf82e44a631255f543b2242c916e893311942b52bd8bab194955fdcbd58e90e4aafe48557d96594b91727de947ae341ea9aaef4ea59f5c9f25c915e72355f54036a8133a51fdcae596e091ab0d8b56d5d77a14fc65f5167fd603b98e20d713fe626496bb1d758daa823fee27d7734cc499ce75abe79a88ab529254d5734b74492c92a423b9bee3366ec95614bd7a0d73ade8d59f56ae2f25d52ecbb623d376546f326d474f6c59fc9492eaa611895ed57aa257bf618d277af52f4ab09fc693ebb72ce20ca713673eee4ce2ccc9ebb7a3380373fd8614678eb6d8a2d892e2ccb77121d7d7ed9f6694eb2bd251d5c9b51ee57a4d6e2cb7ef8d24b9aaaf3ff0465ed15b1d912d25e55aa170dfd29d6ccb1fd3552e54d235e051f0291726814217228141f0db91cc326bbbeef73c996d3bcaf5a5a25a2acaf5a62b03af1387dcb8c18a7d7048a6b883121fe80452de8e51146c7300948323792b8294b7225b446f834582608ebe59165b5f6c31814724c9f0ddf83b62a7a79094b767f77bfe6011a0e86dd656275a52b5bdef44125d230bf6834ef01849e2d99ce0c9db9dd0525a0e84f2f6147cdcc95f4e90a64dc1246f5f53a19337888b00e56d4950be4e04925c4123494418c915f6ed441cc915fd56d2a610ca17fe9a8a9dbc61970823a9da0e8d24c915114852b57d7b864eece40d7f3d4552de9cd0c91bc5441c49d57623db59833b20cadbbf9ec2c8897fd9edbf0e3601245792b51d36112457a9d3210b07b250be1d1a218a33a56f4694e4ed42793bcab552b5fd74b72b5bfcd9bc39d1ca1beea2b71d1a6999f0971519e5ed2da191a3bcbd6336ec033a81a49de8641a59a963293c91a604c237c2f0235ee396586e0a0bf3b557ed55833c1fe409ca54889ef6348e93d3d31750251a473d7d71faac7519c995fca4cf6ed02b2d336233204091b32430394b22ce9c4e9ff1c41994d36744e24ccae9b39e6c8938833a55397dc644e358393db5226657d82cba2df2b6c3247a43323d6dc995d6d276d094073d633a3dfd41af5a4e4f85e4cac5e929915cbd9c9ec2a0bba90d323d9624579c516986e5dd3791ec0ed5f18aded1cf34f4449a498da33b3d768421c5192c08f3912bec545382cf5fd0a5c08ea0b3cb039916b58830a1be0ef31ed8535848ead853c72e04e6d79b958a4f3d8775dd54bcb98e3d1ec39ec238a963c781f9f51cd6062455dbafa0bc3d75b7c36cd7eabace0ec643afa41b34be974c5199a6be09c10ef3ed02362c8f5a7336da6ba2f6c286e5baf066458457645b1692730086533cb06387390cbeb9708ac7f5eba9a7369b882fb072202758019295fa0f9d5b7295d5d20e4cd7791e1090d692ab52c9f3feaeab317c7c7c7cb22c3b3a7a719b554292484825a4125245aa48b59515c995d6aa3ed5a7b68a327d6947ae342359020a92463b3b3b9ef7779db519cb679291dc82e46a23922aca41d12afa188513b82932e5ac68b2ed6c44db5644e4026f45529564bbe58ce4aa32d18670465a129c1167945ddcd45fae4b0b22b532bd6674fa2d081555f4305d672dfea0138c720065fa43a3db82327da32e391bed84324464a5b62c1a47e76c2bda582ed7ddada86b703c5245b72a5a451fe401fda7f3c994ebc95453421aae458745a65b1632e5764a2520d8526dcd23997240dc4fa6af8913a971d04f2d7a55ea6b080624579155da7822fe361764faea851717b24a3b59666d0793e33f98fc957632fde9724c448f1ee5723fd1a34fb95c1397038a1e3dea7247a247af72b9a0e8d1af5c0e49d7a02f01c9d5b64554d16f4cb22136898ec8b9254a4672b51d19657a17772b922afa97bb191dc9959665d61e65faea2357db4ed6551f94ea93e94b48f42d5bd419dd5b2921657a969b237af4db8e5c955a454fe92dfe32fad3b6f375cf317277b3ae4157e80b10673ad31f20ae2a9254d1d3d3e4e8aea0d47b6735ee8aca1d61ce287af4970afb71464831227596957a95654f6c3ed4e5f45b12d1a33cd1a3af78db891efd8b12ecb693e9b738637a8933dc29bd8d33df29fe3828ba38f37156c8f4b4fedb8a32bd762457f49a915cb55c6a49996a4699debe3790e48a266a3e72055b156fe415bdd511d98a94a912ee5bba93f5c974e542251712a1842012940b83e0912cb3b6eba4cc3e9a5c5b729565d6766d65fad295b9f9891e7c0a17e1728d883a436edc913756a44adfb8ff88adaf93bec8f3f2bd04630b26f9a0501e42b22e5c845461f9cb4af7061f58a49964753a9e7afaab8958ffeef3ae234a72fd1556d46f22d57fad848672d77e51aa1d20a7eeb4aa9ea7a7d24a3fe34fd7a89f9c022a4ed56f18d65bba76bfeb80c9254e074cae18967047a1954f7450628e1f151376cb3d04b404871f9be51e025242f412af99bd64d90b98652fb21798bd642fb2972c7b41b199bd64d98b245a96d1f6608430d2a04993096343d4b3ac258c11c6a15894936453f41941932200810a2ec880154190239011723c2ace7017908e8ece0e58f15d5c75cb1700e42f86c68daf93c896596cd14cb27c7f7088849192892920921bf9834994c025566401990c49a20a199790b1892311494cf2452553c85f5ce26345969734e0c97288065ac8f2afc110b2bc375483a3dc4336384296af714196078207135ac8f20c18628249962f020a59de88a11b504107073ad8c10119788a14a1c7a788157e868a8021cba11f21211ea2560e9214191d21dd20cbc3241da441e7063b3b60034f1347e85122cb1e3282f4e30411509010114f963dc483a32c1f731667be4d28cbc34d28b7d014497913da8c907dc82dce40a20cb7242cb825c9cdd9c4d2155d37e4a36404435f68f101419e9fddec253ea8424a9e73ce39b119f97a2791628a198c60ce20075d0a2613544d6610021990010c43621c010c2be8cce0838ef95aa8eb1c1d637a65a52ac295f686456e4455bc8c19ac4cd7d10091e55b75bd74bb7c1591e5bdabaf0d64e95d38124b298cb6157d4cb4020c482527d80069044d8fb410c1bdc71ccfa41fcc16d0132da0f1424b0648f9eba22cdf56c877f2323159ee2119b4e8921944accd3da4441bb2b027b987944022a2b50f52061209d1d09841a38b4ee491349a9877727970b62f8aca646ed0d050e5c8724ead7236d8c466092bcd8e863703001e958d9a7925bb2eecba2edaa815b9494faa68eebc24362f99f3a4f39a5794534e39a5fc94726612ce89ea1848e3ec0bc503adbbe17c9c53e2ec0abfb0e7f40ff62cf19ac8c3cd715baa240f7c81b9b806b9d3ed9cd23f8c2c78c9d95ca39b86e250a877af22ea5a09439e9724f6933c197ef630e529a89f6e6f0afe687c3437b9beca7a6f78cbfd6ec03f68e496dfdbfbdde4fb12f7433ce18f473edddecf3ee5f56a29d7e68616f615e67a697fc8a0ee77bacb4b9c8dc51d3d18bcfde28e5e0bee6ba50d5fd421d75d43dd0f66ad391d50e59eeef77cd2ecfda1b37dca9b4b4067abf2cbdaffd0d9e21b5a5815fcd5bb1c723aea5b6eba2aaf9129d74f56b939b906c1320a63d086cb6b644dcca2075d60df6398eb05e622c22c05c71f8b4ff01dccaced3aea792cff6458fed1d44896bbf2973b391b95a7ee4bf4506f7977bf9cdcb1e49614fce5e494dbfb5d057f30ab1cd67acf9391913c9247aae0abca57aea9ace0c0aafcebb2ca6ba2e491f0baaed35df0e9d8e926fc7557777b597e6a39ca9b1302f5165c6fe7eea2ce72bf6794157bb8726d4565e5d637a75281e8ac828360d93e7241c03469d26447ccf51980b9e21fa8af5c9827b74326a75ce5167f5008eafc24f920f51c411e2323a12322a496fdd745349efd2793abfd47a3723fd34f6f6e07e4c9292af88b4056b9bd9f4cb6aff77b9675d7fa1aa972835c59e5cdd9a86020327f30a3700564720afe78d87b7abd28879c0dca4fb723109d2d0e7205d181264d9ab4b209ff90c9278f3b72b5b5aa1ec6e4faac56fc6df8078ddec997e7933c196f71d5aca933800891e8d1ba71487b6534cb7ace47c80361e7c060c4e090d135e2bf1b06e0411bf1dff38c4cf4228acbcd43015d63e60d442f7f32594787862a80479228a3a5101262e180d8409c8155682f62a199340a3212ba060c401b2cbc7681c007a00d5647d7f824ccf276864d58e8c3920f9093e1a14fcb962c0c90abb74adecba48c5d7d5d04d334e4e7f5a169c09ad2101861bc380c6491bbade8259d64cbba3b2667de0b68b210ca0c4050a28b88a8c602b2bc5ac5e50b0359decba65c49d69793eb9039148221b9331c02c18ea9e5fdc6e98ed3f22a6a8e38c8954ddaf12100ca2fb987424064fefa25244bce46bab80c41cadf3cda8288792ec10940c81f3542434b6e2e2e93682a89392ac87e14c800f2a674c43cbf247a51069616d1d60c269e3f716662d1aaf8a905518e474747aaa0e17137d6c5c54546a665c4564427c3eeeaa0582d5707c5822b6fce86e535918888517ec94d44e40845355607ca53de33af93cde97dc234283b02731345afe584cab18b7abd29775ead6be5a812cab5e6b0cb9b8118c4f591a2c750ee970198a27807cae5738d440902e445c6404ea6c03cccb31586951c3434f9c80704a6264d9a346175d7b0ad7427d09d4dcc9fe8c5cec7757aac00353f727af2751ff39d2f98fb28a78460e5698b0201d1a0d40e7a79fa2eebb2dc51a0959be5a02a0e3081d8586ee7959b659cda51b37ccd12a78290f312a778dcb4a8d103666b12b576928841d18b4838ed2d1807e3f0d8812c97df3c858720e103cb05a7e40e64a5a4cb7ba4eee272212d4fe11e2e7ff90b16d2dd05a724e6f17297964b2002f448f42e6db95c5a44e5b4fd2146b9a7907b68c808326d512671c6f4f82c1b621f4fab50c9f1b4886a91291639d22ce47829ff6c892691bce48f59447d81fd2890c4418c381267604bc21389bff664689e9d1e3b6dc9a352504e6f59a76d207996154c5530968251f00957fc7979074dde2890c9740a34b31c2dae004dc6f00784e9a6933b91442f4a1ce40a424893264d88323689b6162acbbfe4eddf34ca4e232f4faa745c789e6e9f1fc53f68b2f60dcfa049247a1113faf901029a447312116597372bf566c9899d3ebbe6d2b9d6d27579777a7bb43c75ec0ed1f2141662e4c6e5dd85a4de22790c4961173c892065f9d91afa409119904a1b9d5402b59800922bdaa29802490a84bd33a53ea4c4a91d9ffd494c7fa80f6542ca679c8da42d7903135b391e43527739057249e13b7bee1c123df9895dacc17e3979ee64996d55bce46c36708420fc60c8a5933ab21f6d115d7174b493450f529cf926912de2cc377f72fce6901c5b4b620f2ed48a38f3fdf801eaf191ab26b2f3f95da7adc6e1e3c215b82e9168651a85c6d157e44f6e91618b1a5d17863c9047082ef77161d85272e991a872b9cd921253a02a02daa2401f355a82f6f4c096cb5b6e4abe59ddb1a3388321c955cbe3b124aa4377e4cac5e3290fedd1828d3ab9b38b7be94855fccb9d4952159fba13e9ce23a98a7771646dee2110a4217ff3c8e5c2ee9690000422f3088910bacbeea624a62dba641ec5792404ce884b0c3a310afbc122b8127df041073b20db927be80936e427bcf044d14f4b99a3dcba054e2a3430d04498c92e92ba89acf8c88a184708aba50a3b02464c0a24403188e1f3a29c72ce396717a44ca459a994d1186126e79c534a1b39e9906c49447461d817ae2fcc78c10848ac0470de0c6d2e51d367ad22a3226dbbce5a795df68ca7dcd825239c48d7135910b66801d0132420b2001e9f2764d08382a427828082999d4048aa3a7b228a152c00053a3a80b0a311bb30ec8261041b2377145d10438c28788105387cc1b2e48ec20b4e14c10b51743d48b62e22cecc13cef4dba355d76d77215f4ac0130e6e1a84105a6b6d2dc1ec1f4d861d764cabb2cfd4d8ededd10768b3961ac34abf6e91d28fcd2eb863348d3078cdeb9a9e91adb9878e78e10a360bf9fbbc47433b524516062928967be8881443ae9f9c88a717b439693721bd539e2c90a3ac79e2c800cdd81ba50239c6d32cdf37058165898174938c6118e711391ecec72c6e51d7755d5729f7d01126e4cf7ee640eb188de330d5fe936b13b91ee59a45f42a508c9f628b5c638c3046182352aeef187f72358254df874690ea8d8f317e12212455f1f144141101e39d58bb76ec12512455da8910922b228e2e2b9e42286b4652a5d5973eb803a1acfdeb298ab276680429b3b68d2065edb0891fb98a2c4d3bdc01529ce922ed2db5778cc61323cd82968a5a9cf893ff41e24b9992513e428886ec59ae509f90c77e599e2f8a6ce7963458e9237bb06338a2feb514ada20ca5100a6aa01f9f9d3c44d1bd018a1ef4bab33cbe6b39cae52b7749a9682a97e5a8fb37be69c2450a1d54d20a5286c75f4be1c828432914ada0e46c22c65e2335ecf60d2df02704e8f04280ae8bb3b988446fb6cb8d30d83eca31c60bd2a3e84d9a459eb185099bfde0cc277a970a3b1f77ae9e222bdfff681010504f0aeb89de757474a4f21ea9428332dd30d91367a60cf2bcf4996ad0e9c1ce90680434d48321ac83f29c8941974b0cf58027cf5324712615e7e74ff23cecb1fd8ede8ec9d9348ef826287a2a1772f488521a74a9fc3aba7cf2853f382b6f79c461b9cba3cbcf4fea86e5a9b33ce5027de42a75d31df5eea86bdd6de95a30cf9d4279c68e3a73fe221267523e3f8be40a7578048d60512b7fb2a7855a9ff168ca783f0a75a1905431498a1e44f28e1e3475324fe2ef47ec9c1cdf728593c3ea4caa7eba46aa8fbd71aa69d668d30873f744c513eea993933ae79c73ce39e7fc49e5b84f8e3b0fb99a5a51a61742a4492f26d19bd717a06a7e9221cfa9863c4faedd0c64393e1edd0b8bae31df42996af205b2a767c87eb2470ae105b5679d73ca25c823a0b460e1b116b6445bc1c2a2b460338de62963906da52c3be1cf5a3c4dcfb2ad44b169858db95e42d1ab6e1983691b0796a79c22cfd951fc93373092a704c2fcaccf354543d14e9ae998e9167f59663793e9d7e46caa50d64a375561adb5e22f55aa37dd1f4c2653ad37d592092b99ea4b2b7d714a3b764dbb66d26ebda95ec3b2c725639e0c8f7a8f05746f298058de52106917666ddb36ce86fe6272ed3a6a1c58f40a8b42abe667e93acaf39ad46e56deb9a0def21edd5db09095776fc1428cd40b5139eacdeade2a1d16d2bdfbca85a0aef2d4102a47fd46e5a8577cb3f2ee3571720a6816cb4d5514eadd6f50ef5edf756fc1382bef8ea302391b1e2c3db98347b10465f815a10caf72a5206299577951854df140bdf3d7513092e208a7490194e18b6047c1285f4771267efecae2428a3312338a1e93c696604558ab8fe2104552055f449cf95a8a534ebba6dd5a51b8130c046257748d79b1d6c5965cac08b3e2c87e368af81167e8e7a4415235b9cfedf3725e6e1167b417f5b4788876bea983b5bac6445dc594325d339d6ebad8d7a9d33b0b01caa6db37a7c3def49a78ba3f98ac35996e4d266b712a6551ac111a8a351d25eaa06b74b6a65b5392d5546852ca8961589bd2de9673ce0bc34e4bd74412e38c104278b718e3c4d98cd7fdb2aef15d2288914a794929e3c4536230cee092f18a18931ec4b0c65f863b5ed7bc660e8573083b646a88fb983300ff86cf9be1af8d72f6989b828f390ebfe1a68688390e4f41dc23e638a47adc7018bfe1301e00690a6cf6d835b128893d429484a0241c654882dc43486802094b202189dc4354d8dc43541cc9dcfd66e64e4caf91abd4498c13ec611cef2a5c93c9958753a51838558a8153252144259309008f817164ee6537ca30e336fe9d9c7236275807b762e3a6e065bc5933ae77d57bc4b80c2c44c663c8c0292e47c815d0ac4b55ec72581e4ec19b19f70eefd5780c8ce3bdc671627c460a4b46885291540ade06be078dabaec238399a164fbc9be262dc1477ee9e7715c6b171ef3800788cd410337ad4788af3aeba9018329ec3eaa1bacc65b0100f5fe0467519188706d748553c1052156be29b65037f4d44031b816f1600b0e44ede31b2779b756760bf4e7a76f29314134e0d112386eade853c06eee10951e14b95097bb8a5ea6ba19cce1a0e17c6ad81fb74b38cba7d1d9e0809477213292122520224747294fbc18c029fe12c86848a868ec024cbe41e12fac94976b60d951ae21e873be01e079c72003e8c18f77e13e31ec63172729c141703a7e05537321ee331304e8ac3a92166dc7b8f19f7b0102337315ee342bccfc03d6a7cc6676021315e03374b069671151662e466c655172203f7505dc6656021dc55b8a5ea44939c0da732e3a64c4fa5a49868524c29de4a0af7d44a8a938153284f7137329e4aa1c898b1825354b65b141977064ea53cb57273192bf886c655dc4da5527a7087d67ec6950144e66a514ad69eb0acfc2b87f98ba7522e9ef297a79e4ab9dc9452397794afd0a4c0bcc09f8c8b14cff47217930aa7b8d368c12915942fc8cc283fa9bc26e664538a3bb9a9d4cab9a71cfee4326e6a050f41e3aaa738dc8306567dc6653c95827bccb88ccfc0324e375d2032a79c64dc96aad355b7a5ca05d2dda4499336649413cae995b34139eafe885ebc4518c1c28cf21f7e1cc2c37b82bf994d87af917106e5b18838739a97717892c15dd51c96891ec763c82f55dc077540c8e16f66eed7e1551d3e3b39bceac2132c13bdb73d577ac3ebba258883cc2026c7711cc75d1cfe70327778af77b7ccf418387572d5735826ece1d4094e0de13dc66fbcc7f8c963601c2327f826c65518e75275f21827b89fc3aa91f0367781d0264d9a30d921b3c680dbac184064def007b38681c8128e000eb759306eb35ea260bf1f5d84b3ec628fb9cdbae136ab46cedb196313b78ecd81892fa630e79cf2f04a29a5d426ca35ed1aca0f9a0c3921b0b6fde446cee6243e27cbfb3d4720c39fee372f67da6e6f4e8637c8b55ddeef46deb8fb6d599b3ae8350c51d77e733e85c59cf3f31e0d19334fe25544eb984d1e420861a4810d3112610bc96b0def4723c39b60609b551f5f83c87c437e850afb6d25d4077f75ce68640cbf9382fd3cf983468e9797c9e2cc87cab285a609e0ef11ec0735001c28cfc3b8d6dc8e79183fb9dfc9eb8366a4e4ec7508c04bb502086c9251ac853fd6da1b376e683a04e03afc6ace2687d7c4d5ccea5773363ba04ea893a6556b6db53f9c6c3c8a1eacb54a1e0cbb2857351b7c92c706361ee5ebd5daa4dcde949b6e54123d28f385630bc79947f8d3456022ef50842345189277f80e45207245cee11fcca72da0489273780e876289c66dd8c9c9c93cb9e289cc41871c0e374e07cc395cb3a75faf185669d0e9302c2c29296f8e8525e584c36e6861535236cbd9d4aae3f4eeb5c26a391da7eff0eb62ab9f6ee7541030ef70987738ccfd72f20edf2108017c00ef68accc8e9765f6b7efe674c01ff071bc26621be5ea75b8343434a75c3dca8534a7f9e9d809e6155fd7f59caf9ee535b2068919f52d25057f39574acad53511b25cabbf2e7b5d36d6b68c8a5a45464618923b77468216b2c88d043128b1b9912006241ba783dec5bbeb020a26906c81040a22499664fa08c5904c1fa13852842d327d11aec8f4ddcda27797d45de28c193366cc10d23366cc98819343e35c0aa72cea299f05a203e6ec33628d15eb5cb81cc31f8d8cc538eb23516b0591282a6971f6cab37036b57e72db9bd38e72533a520ee328efcc72181e5eca711e5e13b59ae73c95c2373cbc06e3f4701e8ee3c3733c87d5dc3d0f37957a7eb372dc54aaa62663213d9c87d7f4e003e4ee9b7b711eee759d2e9657cc741a4f0162937d06d681e3dd4df7b3f93fdd171708ccdd258763ec4edffd59fddf1d1e77f45e70b76121e8bbcb7b81c03c00fc65c771940b738c9d0a6773e10f275f3511757a146743af410e08cc28f745cab19b8284c728d357242208657a8c08addc435464d1e51ea2624946a293e9afe48911830346a9e6c3cdf11e2e0f7f716146b930972ecc382ef67b61fc8147cf72dc87332007f6e10c38bd876bcd5d3cecadf7874cb6f774c19a68aff77ae5250f0e31317e612ef0310c8ea84b4e08fa8a534160c791a88b44b65a8b5142501f6e0e0bbb9d5fdcce289defeddcc3cd61e1fbe5644a2477eeac71a86b184cb9306f712665666b32bd394a4da68bcba2579f72ba66ef1724460e01f51988d9877dc7fdd0ddbe539e723acca89bb2efe13039ce728be4c029fb1ce7e1ddfd307cc2457ac0298b83d8e1399c073cc4880e01780e3cc4c8ea489c656426b56387e7f01d9ec335952d09b98790f864c8518cba30290b36559f9383d8e102b800b00fd4777867980a2287d757ec03f51cde7905f3950e872ff8fb75b82e8e934f98b529b76731d9145b537016bddabde2d3399b0be6a77b17f7833987a37678773f9cbc3abd1f4ed621871b24e61c0e7383c4bc03e4ecb31baf34cfe24c3dcd2f997ce3f6ded0c2d2fcb3f906cd339a67375ee284a04d9a3469922bcea277e3cde9a0c137be9ad921e8c6953a5c49240057e670e51237b01ffcc99a83c9723dfd84bf99ed3526ecb79ddeb9721c67632d863f1ccc9b433dce543c3b16da75428d03e61bb096aea32c375a8efd861baedf7043938b93afb7d88b0178fa0933a5e4a4d4c81b302cbbc7c0313860f853adc51fcc57095bfffff3bedb5e3140aa2aabd61b99a80651db80af7129b4c4ca4f39fe753cfcb331efb8f2e1313e6058d403e601b754c9e0962ad5ed8cba9d61b4beae0ffbd34fa7afac5cc3b69595affe74235ff57e1727db5f29c71abb3f6e4ec10180364eaf91315f077361c6a48fcab1a75c4d6e30299ccd75dd0f02d95ee56ad7c500cc11c8f55f677a733627db25194bb92b1a2a25db265945454545e55f17d9fb5d08e4facb9aae1f379b7000a00decf67e3a646c0543a213ee681a07ecf0977df52cf8eb360065fc05fe3299bbc0aadfc62127848d9fbc466600dc0f66188745366ee3326c5c067fd606fe7ed0c83030004ee3aad74800dcce32ee97a9eed7e51af79347c8f0312ef793f8078d3c4fe3defd6e320da824d2b81dbdfe2582fd32ad844f5698c8f525ab72ad7f78390bcb3597bb84fde2d191f77cdd775c1d2673c1b227c76500c49e823fef84bfabe0afc38a60dc895e123d70080b49f9e61ec2c292ecb3454fa6711817dac9306e3fb3761921a9878c4044fa40266c66b6ec277af51867637116bd8a82ae016fed0a13ec2751903f591467ba43974395c34b14340ed36947bc9049103077f466ae4fb95ffde99033611df51626058939eaa864e070cfb396d6fbf066e5780fefc1c37dc0427c380fef010b3172e3c379b8901e9ee3cd8ab906b7a813756024459d24265107e64f0dd1c373bc470f38a6870f98077c1ef9e3917fc8641818dcd13b86f119340e23c62d0ccfbbaad398110307d59bb39171a1920b7188f1c3e06f66986b37f9f47a0de35a6eba761e9ec3aa16a786c8711e7e93e33c601c23f638f526c779380ff039700ecbe2efd69eee07f329e5d5d6cd743f1ab962d36ba4e9dea7dccf7b7342c0b88df9e9de70c983533b6246ddc56b24ccc5e1302e048231f7cbf2fd2f0e312e447299d4e8a35e666badf5516f2d13ad96256a1129c100ccf65048e8542f54ffc12024156340668b81402660abc2d60b201344ad97291c11b95ca2be1e5efa1ce5b0208c98b75cc1bce52ae532390ebb28d79f52ea4d3030f04793eb636230c69e973fc92393e30e19e1486e79e9da4ffe82c48cba8b766df3af18ee9cae35077d603e1df6f02ff3e19fcdf65f97ed3f2fdb5fae78b87dcd6da972711f6e0fb7e50f997cfaaf9d2ef409900bf330fd29817a0c63c8266c0893b040c35aa3721ffa68783519da099aca18ae0bbbae09afa0417a45a88529b33c23af2967f462cf75daae9479e9631e3bdc6e68c1a68248f1318fca9d3b7f13a776a0327654c660cf77ce1d67e4f624547ca09480b00d4dc02e7a51ecca4209dc381ad6de9c19c811a3f89a1cc8f130cec8432886ace5a5564d9c6530c3160d34b863769baeac35ccdd3967420dccc8b25d2a6345d60c4347168c11b200e7ea406bb96261d89583102c56ce3c0246b80520682c0d6e57abe6c90296456fb3b0db2c0d76bc6eb396d0b03967841ed0e68457072694110e41c37266a075a9bd920660074e3ae7829009373c10d4829d12a020091f104187e107f69a584e11248c0cdda00966e831ba90a022092d4ef043a63bc3fe6e83fc793468aa60227f2dd44986aaa8414f14296862086a1882c492b28972cf1b720f1535c9a6dc434548f688d6cf826d2e421e493e45d306441b0eb48ef920cfbcaeebca2ad69bede6dcf29cef0b4462b7c8764d6e14723371a66aa5f78138409c89327af2317a387048f476a8dd400b11fbc9e46db2c06e7126420ce9135ac764119569e24a9b8176552a22ee207f4d09c87798d422077104b4b09f0c16f693c9376b15bde806f2754920aa906692269d60e155b4b0f0f29b110b85748dbe0a182c3c8c314231681d53935b080c36fe9a71c618048b54d0b41c67e39c0c71ebe8d93d67f7ecd9b3bbc140318c6254ca8961584b2963f2bca83c867b46b694f328e8c7a6402b652f3dbbc41fbc32eca39f5d83bd59edf89af304cbf097fda2b77ebb27d72ef7c9c38c524c7f7439fba4d8857f1421ef8f2ec74b25d06fdae18d2da4e672230c9b768880f8fe341c44faa83888ec472d621ffdc1893fd87de1ce4060ee5f37b5e37afdf5fad227f6d19fcfae5d3aebb33b2b9e1b86951e5f7a8d2c5d98afc38abfaa5dfaed66af77be5ed330bd2d61fc75af8f2032777fe384886fec235ed334fc553c4bf7a15dc336cf4db5cd73977ec22032633e801c41af8f2012bb3ee23b5f1708fce4769c726ae21df1fdb8a3cb5fd32a4a7d9230768650681d330fa1fc25040b1f2f2bb0e53819e9a8699a8f2247c8b08cfcba20b88edd4706642ec281eb9d254e0eeb7ae471e1ebf04e213a595e0f8194980611ade116b90f9108a069dd0ddf57b0dd4162ec9eda15ec372584337a57b0d9a78410c2ac218470369411e9ef8285ffbaecf22f71e66edddd36ebeedeb2190498bd0f2184597e9ba8f932e7dc8106000fc06bb0514353386ae5aeb1d316bd993b0a3028c95df41aff784772fccb148260458e570840a0d1488185ef4d87488370caee6e8bd45300e5eeee9e32c6c4c4995496b7eeee9630b08d7d3492fc804681902a78db51d84290b2a09021514da7e4869c0228ab846b5860371067e2e171e20c4df4e05519e64f468706f302da8364d9342746310cf380c019bdc982655858f089d82b04bb5261ad15ab87174837418a335be0479ef9b94d21996cc43c4bf70d7f7f07b18d9d8795e422205b44f4e6514e60e790a833758032c59148e4c178628c31c6083725b496f029f2018fbd11208d0862fb4e6cc27e91076a10a7b2c76738882d0e49d1cad8e3cc1cce66346275a2146c7cfd23ce00cc1f95d8b586339e60df6e77967f453a1669640552d0c91057405a0106223a39620dbb189cf9ab3ee283cc8c1dc38c88de3c8d94c2d94a944c1d29298c3a3b3c30893c672a08cc47846fae07cb3b8c8343852776585d77712012419041100bc7e5382fc7717178533b4acfb961b99188bb474e47841c8f96d36b5a844f5d23f4dbdd3175c4eb031ede5410a5c797bea3744af107e3212704c70096a7ae414e01cd6a79730e60790ae31c216f4094c44abd7b0660ce5e23e32d3dbba597ba8b0341c03385100bc7053ea2a7904410cb883cce0b3ee286198258296ca474177c04968424969193b7b038c1ce97ae4c5db973c89d3bd12b510cd57d6641e6cc6cef446f422b8c66963ac212267e8aec767b7a9a379623715647ab112caba8e8cd883f1a18362961bf78abc3be747abf0c578046f6615fbabd56baf1f4f06218a5cfb0434b33faef26c30ad0c8df4df69e9f3a53c7b4448c31e66843b1c89361fbed1661f9d54165b97de441a1c1da4f163c87b07c0e89de1cd29de52831c218233c1dde53778dc0b35c24ce32f2d2b19c8bdc351695b7ca63562a7dbb5f4ede340cfb0f9db1e76478bfe7084c085f57de5c94a5d39b93e30d72e5151c0068e3462ebd466eb7a3b7650ee51c8eaf9147dd6fe6146c44f47ed0c8273c77a6ce144a7189fad947457cde99608b4e9e7df6dcc4990b70df80c8d8558185cfb2d935127e592ec272ecfea0c93106b119fb01224d9cc93e9fa3c6932b16dcd1cb6663a16b58a16dcc6b175ad135e6e98557942e3cca227a33ab6d141fe329463f9a4c6113585932eca92c8bf391888b900e3e4b92f2bc4f134079c6a03ce77c4667a6ac429e3a7205ad88aaf979052c8ade8482fda68ecffc9ccd3242cb9167b24e0dd041823e72c5806cde8839fff2010bff02027b09a5441b628071f61704cb7d7923ebb79d114e4a31ce112cfa2b23555146aa6472c7c3932a1739b0f0510a1ce4f8971cb0e2e5fce7498f860b27d44352d0c9b1832c2329f0e4af5b9c8e148a90bfb6425eb38b332f71669281c6cb08905808641e73ef319fa20530b862152e256cc8c109ae147477cbeeee8edd0db1abb1eb6aec9a92045a1c4084534a29a794524a6d421bb023b431e5001ada90d25a137607703d8bd08694529a8080958680ad602963ec18e337f3978ad0463fe6993b69638ccc119ff2d76519638e97dd0def17f3c92c718cf29ab223c45840712e8c5ed725e31111bb9a482831d8a4dbc69cb31fe1bcb00bfb81c5ae26f3921884524278c2a08497d863298310c3221614e3a6e85637567adfa3efcee240b32ba6db867ca984bf23f2d5860cc32efafe840328c5b671c1d8309e408c4e194f5e34db221c006cfa2a4b598c56c26a29533cc4c2d7c489d9b8a49098e7b5d2f6755b561bc7d4b87b6a95fc76a53c59205fb133407326af439a4ba73b2c964b1848d79047e44b7275bb22044e402206186c29f7901236d0ec25bbae086722f4e0fb82d73c84104208af39bd6c622f110ee03ac5b2972c6799e72c4d6cd2db7962d9cb8bab94c15206e11bb3557cce2cc9946491bf4e52a4a40a29e418e42b265f57138e902f254ae4ebc615745032f97bc9c1841e26846109567ceacc107476094755c8df96278aa80479526188880b4b90420c2588c00a4ab8c2da2fcbb009f644470be2764a5089f800cfb682522b49ab415675404b4f604e10ca86884c70cdcc4e91822ea080080f04996147676768880d44e814a5d44026cac490813de58e420c6c802164b5dc518ce104558ce1055f18c30c66f4d82c771463c88137033ba99079ee28c850c5fcc001e2cc67a3a60040a0ae6ba27e20c08413af28818040a402851f9ca025a60d489aa8ec0401c8058c249028a11205105c40052888a09288a0029311b2eeeef6011172f7690ac0a33f1b675266314fb0f0fd3883e7212b7a727fbe5c97854b50824496f88978868e872965747663d735a38c538832c2d2a905c20b4613b412b029ffcd39273c651f6d62fd9a98d1eb98bcaed933a31836e7ecee19e48ad3057d2161e1e375cd6be294c472c4a2db66d9b265777777675052011e368700982057a4b4616268c30b754ddc3171e144cd84104a3803f003fb6519a8a58456286163bc1a9b33b330c88e3dc3b28cca2ca318c33d6397638c1d73288c4dc4d87dec7336f6c67e659916331a23ce6a60d1314a6cbbc61170ce6641291cc9f663c71c081f20e535e735fb03ddfd5386724af99a78c1fce564f9a923c2a3c81d68b2bb5bcaeeeeee8e51cad9b108730c5d843093ff72329c17964062d89c58b7a9d492177627463367dfae715d18c5e6293ebc2e2f6bd8d735fb7a4d2c7537be2044b141264f39a544a26577c309610732ece779fd82311a6918bb21ceb07c733912c227c42cce5ca62ccec0381ba722ee5cca16e83296d1f79db3c212cce095e1a71c81d4eaadf5b262b54a292fe7155a8c51da07d5a880200806913065f6f929bb67e4bff92cc64b39e79c73ceb89aac289b905168cef63c19191a1aa12c7dc83e64d3eeabbb9f050dbeb24bce970cd3c83db3d2bf790c675225e72f0c772b20a96ca8a46d15753d8d3a4533224000008314002030140c8804a3d1682ccc13416e3e14000e839a4878569cc9b32c88614a19630c30400400404000406466da00c0c436764055e2e393cb7f7b1169696b44dc3d53a14306f060f1015863a2d2a8e5843b9ffb1ffa8beda4fb023d1822bb81e7dbad20d60725548b59eca7d708e201e3b7810fef2df099633a29698dbd2f1ced3defba012367169b549e4d97c89dfa747367248fa832b38c5672abb70631dd62fb7c83312f247bb3001a6313212385d857242d53ca162676cccbb2253d5c5e75268c23f738cc0ed896aff9c3a49f7b4211fea5dd17ebcc4092a25af46e284d62ad80824a16614b6585ce602bf3971b0c8d51f74d0ae44034f3aea9ecf41d62ad7d8108397e3277bb31d0a1a1c8771c6c2e2776520bd4328b64ca5ef0d7aa8ffc40782d4e095f26371739baa153e4cfb722c8e14744f4cdca76cbb26eb4068f060f03935dc6e692010fe6aeb8bd090278383d7c603c47eaefa506271e63afa1838ed54ae28f32a6b9064e12c10b0b4488bc7adead5c92720472bc2420b75c37d19f2ffee648bed2445cf523c8b70c463f768135a76089b243a87348f645980f14e377a9cea930fc076a81638f0d0d90086e1d54713a8721f80ec81b7ef4c39bda043b160e3243110d5424069a3480936c7a4d954cd512e0642e15543b42337a6cbdbd8b8d281116e2510fd134f9c9f57848ecf632a45b81b40d5be89fc85854397205ee5d25fad1ae49424ceda8258c431a9d380e047c84615b261da9fd3d61af153243bf0aaeacf3c6b18225e8c690dcbe4416ffce18c230257e1d8cb20e0c3e1fe18fcd421986c2399fa401b3eca1ef13d0293c667ddf4869e7858bd67ef8bded878b01c03731c2ff9be456fff7694ddff5f69e73e8a185cc91e73b8fe6a044ca8a7ca55efd7ea8f8961e72e36431c4611d3fada9655befdc3426b1c299cb0487195a16511d77fe3b83ac56a9502e95d8a00ccdb971c23c1dd65823ac470d3418a6fba0523b28c099062a9e98893b143d5a8e1e9b0f2478495e81b84ac1722cf92302aa9269b36de546705a4bd228249def296ff7fad39edfa4317049cde183030ff9e1a30389330ed683ca5bf18a1f1c5d1c51b32529375d164e4ff80208ecc4ac8f2b3bb7c4420fe3904d931f937293c371d5466e0aa0e34b00d6acfb4e0c58f7f476a28e13f9884e0cdee4b5eb55c5564bcfcb3edad5367a6a5797caf0956978b41005a2bba3275d275c5d210e7f919a800383ae15989db5bb8c2f32433a440bc8ecf88a61e53b75b7ed8a01c2e4df9c4062b1c2b6fc48f701d70a8a87e34aa2014adbc13e7245a93bb0c2a6f41108779272ec56c733252b48e88ecfc0c57e7b989db3a5ccef273b165d5394961537143bd85c1bef0447647df647a9ddb3eccdf51f021bd69a5c4814db14a2df1b3986e44abc4dd8c2e9efc10bad6e0edc875bbff776c47ef0070354dec4310362cd23194b7037e939e3c6dcfda97aec58aeadeccc3afdc97f380e9a284383367c04da44e6f14a2f6f6046bf80c9598f35331f1a0e5113ba8603c2f863028743239e6fb643fff67e8948545b549626777658a5a50cc544b4e1639e4888859c598a9279f210a81dcaa528ceb010399ad36a9dcb4dbe86e2dfb9b1ba3c9169a3ca4ff1c4d288165573338e200b8e6140be97975c0a4a01d11b881ba1b0688513c657481b947a58c256a855e657015c8437fe54329753b0f14ca5dc2466031d3003d348ac380c969c5bb6fb579cc23582874b87202068b76b906831396ed9352a33632cb81dccef939a2960823a5a8714fcf13ef3f4521445ad7fa4d496d3dc4efb1c7837a2f9ce1089147a7b683113975e80d235164f2c02992f69340182eee9aea434f4c5b3f53f804bc98b2c1e60c6d0c98471c064e711a9cfcb5111fe990de1f10265f67d28cd21a74a4a6384d49e53e43b191a7e781f1d301129f523d964b37957d8e146ac0e673fcd126e69718fd540016b8314dee79fbe432bc35daa3f3078388aad066ec691bd0709840ed1d930e67738a2b355b4cfda2a494a9cfd26c6463e17aafcb5815b5b48ac8445e24d5f1cfda0b9ef3777c0f24a2f58cab0e4e63fade0cb9d2cb593caa285d84c4125bd80a1c6aa230d2c06e34a2c78fd74dac4733a1287122223f3ce7351cdb88d925b0edf02711ad3fa38f264d2f039299df95d04dcc0b17dcd11f1149f079538689e70eee6257ba8ba85532a9afb879e765bf9c64522a7f5aec4cbd9d8bfb1689f41dea405ad318c868aa5391754a78f8d35b47db53e8ecf87fec02ea293550fef24dc6e0cfc11e93b502d626c3afb2e1600409277155fd28a69bfbf18f2a09f67cdf609f61f8a3c890673951edb4f23d78920cdb9e08b157b1c168f45ad2f8cd73931a232c2b62d5c4cc108516dce83a4bb3260006e8848136064b63b69c5e8fcb9e3afbd61d9fc4623bd2487b5ab41c337246d643af851320faeae845109fdc4600f216fe429290eddaf6aeb6a8648754188c8b3ecd379e96ded7132c80288aec874cd785721725ca353b4903ba297d656f76292b5fa5f4f9be561c4de639a6aa0054f89af41cb7b338048ac33e7d8ba371515f93c4badaaa7d9222ab3d6dd2906da792a2769d17164a3ee090c88c545a3694bceecf4ab1e484acc4d232c63fcee98c29cb492f40352662cc0147d07b2580a19392e91a0dbe45ca52a0252f0d1fe4c976749a875e91a9824a4ad32df1acb490a2958b2b571c5061bb57b32665108f383c4a7d463fe69469322de535b6436ec0d31348b52283e2ac868bebdecc72e517c662ea1420e2ea0be47f8df233a9dac41e771df965e986cd3557f8ccfc73defadacb0c835c53fdd2f0fd4b802e585a67f29d292d08f49912853080132ccac600496561df98a1fdb943f1a53bbf403c907e392a3125bcba002b1581853775d46ad8a84d89b9d0c527f885ff7a1bed4a09bbae225512e8eaf4bac07d6eaf3db807dfa8edbe84036738d189bbb8e0b83da99150ec914475556ce094223ddfa764366ea61d81ccf668c9a81564ad7c843654ef76b2ed5bd8407d61621d86023f2d32b1d5b38784d4179f1db676e9f6f96f97882a70cd33e84d51da044ce43897a29e8010191dd76e3020d94cd3bd912696a4b2cbf873a099050f5050e1ed2443331784cd4da9d0dd116b5681b20de4ce509416829d191ad8f178d8b6a168a1a68f7a0a9d509b59d6cd9d732b57451ba7d59caa22d1c723552f4246b63fd06a5267695481dfad90f4a1646f68917cb45692155f4558c59cb9e6f1612902f88593d046c10915ce832aa5a74a0cf22c141fd5a75c91e608260d02db438b5ae0c2d453b39ad74716da369e58239773c59fabd7cd27ba89d90a52ffa0c3b4624ae55a9d99aa145307dc6f5675e79e3558f1f8cb09086e9e61f976c3f7f9de8331061585d02b49e0961dc181c4d8e048c0529375f4f8395255be020b88ef7e248a757fbddd76ee806ed79c8533fb2f1f8b00f0b42b8e62e22726a128239fbe2fe73ffad1d0478714e044a519fdaf4e4706b801dc16332d2184bc824e9041b6a6734ce7585cf52fdeaaa9498aa3fa449102819f0005b45b9f6667f4fdc400bdeb3c8d4f96a8144484ac9b8192bc7c2446cc3f370c42559c58fd2304f901cbc2cccd89bd5c4db98ccf407e05db64ab4c2176dc67ff2738b667f9706aaf55578e3980512f3c94e1c83fdfc096ca7b00ada08c4b9a7f2981dd8c3f3f323baa278672bc14f3d8d8db265e2b4c21815a78f7d19a500fc55762e262930f4b3128e2a7327b23dfb944c190fd25da2a7a6c2f28809f1e7390bb4a77614e8d9dd4d11a9c4412a6b06f6829beb8d73898743c877264b60ec764d5fda11561eb330f0fa6fc9e29f3c61444838a18f3b7b598987bf87f83cf8a0c707d900fdb815b7b5302e2e0a0eeb5c011cfe26a6475f8608b5ece79af3ea01222d31b9b3853f20b4569878eb9b01778bb180136b8917c6130551a2ff655fc189b32c56875b63e8277465b8259b2dc8a724bfdcb9645eecdb04da3c7ff11aabfe6a5f52026c4cf1978ef96c9f31a56c230882b9a2feeca8b39a187e28e1294e2f79aae36e05dd3865255b32214d4ec03e3f435724c100194febe1452bdf276310313add860c512a98e9de30fcd174571a482cbf73c78e5c08b4f9c49db2bd84bae61967dc7b7e7e807d9ebcf9af37e5c1af22459ebc14c8b2108d54b7fc92f0e415b25d293d9c98c921088d0726366e4762d5c16b62a72d3e058764ec60809aa67c49937576038955367aac259476368557b563c9b418ccb7055523bb40ce828e8ce4ae77d8b8e9acaf4cca4f081361b3b084f4f935099791bfd4b1751eec0aa0d1a604816ccb54923ba5798186c0690090ad100ccab762315eb4d0ee2fa776a9d09933c891169770441c83ec869ed7745f9ddb91d665069cce12176d12dbcca8b1048224a5119d499cd0082e0b24f74a6d6cc4640ef820b6ab6836cd6d374099f74421d39336dd554ac6c59a6328d5c4ebfddf7e5a1aa4db59b44912b25d2b1637e8a185ac0fbbb455a2cc51c3d06059d4d3bc9b72b419c3527e85cfd0ea43c1963f023d279efb094fa4a962a75a8812a24bf50fd36234b848566b364e135b53b81e8ac88f11e3898cccc3ce692e2bad8a36dde9b7d61a6aee17a0ad9ee49284a283424f4d9130023ed4858813e0347fb41d54f96f7986dfbf09875b67ab3ed2a2c0b4e485391f37334b7280ca971cc8638e572d60e46b5fe4ba501c40d5b777741f316c6fd5c56704405ea6bc294616ff95d3ebfbed3fdcb256d56946b6c04e058d732bdcbbf14c4b2b5465581d70a26202dc5d50b49f321dbb18bdfa69a0c0de8227873ee9b67647f8a3a7bf381295f219414cf7021d7b633b7f95b04f43857ce6998beab7ed66e02ce435f378ca9afc2d9c97267c9289dc9ab53f92b4fe7b2b506ce9f49b073d8bde4c82496ea32c16c043674bd820f5acb061b56b0edb407cfc93423bd161eebcc7be83b4127e1fd4609651aef10343abe834f1f164a3c949275cbd854ab9e294e231946bf9d5bf170a3ee72466d9a6562d7656d0525d3209ec8d839fa8834a3af685010b97a062ff3ae0c1a80a111424f8828620829497fef4953551fe52ee21f884a3fd53dee6fa17644471f1c59f7f7e01f228baeba95416b67d24cc975394a85685ec21e576c7446fbe1a4a701dea87f7381a10a929fe6a751e80f5d7a679b56dcd61db6553bd133de15a585c1cfc32babc38e429df36b9cb1b3e93c10911a0ac7665edbb2de33cfa3b101312a0c8b11e14b129197ff0eb9f121a617c44a805c17b44943f5cbcf4c288a5aa32ee2a5080ff8b943be8d6e0a68ab835a78f68c279e43712e350c34c502ccadbb24419da5c3bf22bad29696e0f3854772d50f7968b9ca069a2728d3905fa00329552a684e4e9e5f82d55121c1604db0ee006f1e0de516ab1d70bc0ea68472480b58334b11f2ad7a5ccb5a4032ba260cb212eaef0be6ddf4c95e11c346772740989e9faadc8f8c11876f861e512b894d47a39921ab4c6460c6e8bebc09354fc804cf9b59bdad3cb94ce9085005eac5cf49533945096844f8a1113b7b4af69ee9e75f7d0099d6e75bbdd39c240ebbd0213f73a4df4cbee7052df8dc2cc845f49324955886d000e51c89c8bd9a78c043fd1e48941fa253a1d8fdf06e00d28860ba268e24d049d96a813972283575024338d4c151e95c2a4510653434596a7d1d305581dfb7be6c5115b9a93152c70f647244f735a9298faddff763b70bbfa4d5901bea34bef9f4219f634fa35a93533000336dd0d99116e4d3a23880084464052a2ec469d321ece80db6bab330ab185b32a876637306004978b49bb01081d3a58ec5c3b2f9b3b5db17a1a4d2e9c9236631b8624cd2862fa1c324217ef737e0e46cd79c08f67b5f39db24580b8716bfb096bc790fe1b02ac658c8a3c33cf064d2ccb50905963826c6850e3a4117db24ee9b2bcd77171dab1bb4aaf63ca9847a0e70cdfdf3baeebb801c617eb6e7dee919eeebb194b238fc8fb64705eaf05ca0e8fc4f56510939759682aa7d5277b968c89e172ec3aeb851a16f05bc67c4a6715cd10a8db04dc5deb3457c757a65c8a3c667c5e3ba3c81ceb5036cc17bae2a9324c055af9e7234664c3a306f5450f3162a074bc5048b6fd7663501951c48015fc300a7a97dd7ceb05a8045ad549414d086536d6ba4fb877585d07e99f7106a36e009c422fb77d27df07a1e93137268b1bc8a23be72272f76ffb3a32bac5248c7ff8fc7ad3d146e27950700e3c2c59aa1f5c4a0d083d68187521a83e36b473cd5005f19b35e6edc23ccf897a4c3fb93f859dfcd1f0f26cc45a40859488c8c4a11ed9aad3d6cac4c0c156f8332cd24c01b1bde76017e945da6bd1e13db405e8aa020319a69b4826017a36a4afa4a00d51b3705cd4f3022e88353c8a5d0dd1fff6dfe234ac3abf1e9156411e34def8a982a74b9911909931e5338cedc5342f31e5e251b9739911c2954798b5140edcdbc72c2db3d9802807395a921921326292c6bbef0c4572a97bb5d7cdd5049a2294788648820a1fc9bf143429fb3379fd88c2ca5be114100b2711ae057f598cf75df8ef1c38865325177b55648a1d15b7a5252d04c2edfb49079b9a3b4046b1e1f87ce526545a018a071aeee55747c87919e11237180b5ec6e02e41a2e5f77de1d43155514b9942ebbbcb2ed59a8105e89fafcd38858f8ae336a7afce90c14e8eaa874e40b64c03afca87c1cdedb4261c9ee486e88f09527e4c24feb0924caaa40831326cb457a85856eb55d282780f5b939baf9264cedbcc435326cbbc3b661ee33848592d6acd4d983c34e06a7b5bbdb4af61f1caf746cca12648d9da68786846bbd6e645615496d98242df15a44904dbc2e4721600338967605d57fa23233cd0d4af629f0ec9e6ab90fd4a7412817a33467402b8be0161a62288bb95c135cd23402a11918fd250f3d6d0904f1569af6a54cbe389600542e2fe0b3707eba68556a9c522e8fdfbb31b6c46212d765977a0286045fafb3918d38c38267b0e3a972d811264401cdf3586844982dd59af7e0058031992c77450b0250bd7e5764320797d48a0f3f36030e45c1a21e8be1cf44814d080a7b15e267236f4740a927d028e4ed0c97bfecee88272bd827341c703b1d4c857cca9fbd3d10a96b3e6f9fb1421e1eeec91d1cb30cca8506c120dc7a6c616e370138a02f2ded6940db5c1e92941c416c2f2af7d50ae5381fa970c8a0a44edc0fabaafba29f38c902a34f9f523050d944688ac0dc001df3ae96a435fa621cd81a601965f2985b798ad3243c70765eb68f7f67e1584400b5d9e2729315e714ac75b0a0b32c194a75a3e9c0f0ee1acbdaedd40214324409db721cbff86ca6887b90b800e7860b9ada5e3cc499096a954134f4e765f6a58b33abc4dfa1e0221b46fdcd08adfe3953393f16a8a2a117cc52bf1d0f428209ba78b10481c55803e95cd3ec79099771ed3507e7b5f6551fad4b49f0f7a32c71a052187ee35c347df512ebc40bb7ae94a2389137dc510b694233b731af2a00bd1507e07c441d9c2f219b02e923ed5e5b7a1bd0b544e226474274ec8f35a85130468320076bc9ce0c26dd033b154356d9bb33d46c556988a5ec27b97de18f4915751cd18aba8dee4a73eb172742819871c40f9495d1121f4becdffbdb6617d1abc3152254489d6236309efce375519506ab2fb31c2448b9b32d91efeaf93b80251915292cfbd573dd5ad75726989e843cf9e3934eab3bbd7adc7087be75d787647cd70a5b69ca3337b327dfc7ad5569e23663ca5ee844b7480054b31fe72b96387aca843c0b59334d599441dd664685b56bb9f4db46997cd731d2da3b0089ff13c11b09f98e135666da5306a248611337788444c59ac0aa5c614035ff50f8272cf339acba389309006f8c477867590bf080bddf6bfa523027ab143c68498b11728afac88f684ccd8e04806c91d9312fe8411b6a4937d8102715a0bc838a49f1d0e0b9e27c047a1cbda06fefe380392fa1fbfedc21a0651d93b20c81a1111a7ed0c44cbcb8247cb703e575646a5241a663350e5ee0191bb9167a60cb71321cd7211ea634b735db159bb5b420b343d4073a333091046c703e45a5e43fb48b98fbfba7761d74205c68f733cc25bd16db1a4d633a9cc89d0cbcf3058f4b58e231da5fe8de53672689e03de0ea79afc6538a62d36d729c33c58ae66712493a44c9799d4016ca6e249e2dded55ee119f8d43ad1be5920f725668c8f96465db3a1c9ae67468b8fa006363d6d2fee85ed9eef9a113896a08d35bcf3783d121589757eee278b94e71e4e94e41bac9c0e7bb844740e3abcb211ad2060947948086da401d702af6dbdbbb18bee1375ac4b2f088909309677193aa468fc3125f3d6170a1afd7fb1e551afbbfde8f61d0b71d00ac1fe932c08d62382c1f97af39417f7cea6981b125f2f3b5f7369060f67adf4dfabd5ef3da7d1eaffc64e3178c0df4958c132b673b7e24dcff797937f72567034de94f3318ba0f66c241df9003c2f09f9f71b71f7974fcfb6e2459dafe8f2135090fc1cc1468b449dfc2e5b67d926c0af2be9a478da0005d53f3fe8fa8356d2470d01185b0e45067293aa82fae2ce8445117af79631f84375d7b4f9f4e7855a9457d3181c3d0a6c13dab0a1a41c8aac32bf5c41864cb436c97e7c739d749b124941dd404c9af42f60f4da322fa05dc5aac283f9fa612567b80a664763787b9f1761fa06ba811147deac1207d0c6ef943c33d29e9a031bc144b10b32e30cef6b7d5c7ee4a1762825590e05f6b3afd1212f95458bbc1a545cd66ba2adc3b9a55a2aa3557770c610c6d051239da83d277001dbbf035b77c7ce6da840f04d43030a3f065eb5f74a0f70b78f2bdc7bc9785c5b1369c9115d790cbbd8cad3d8a23d1efc6db23b8faeeec31c15489bee096ec7381f8729e6886be1837658b80a135c4ee7ffa6d06c6fa304994bf8ba9c4e7edc8f50836ce1e1c3d386a1c6edfb9ee95e5b1bb52dafa58f7be9ce5b0e882195125a53c4e33e795eefb3352da1c20872bec804997f96659f111ad109435b95773eb88bea1c124c4516ee559e7c581d9b1143ec5ee10f32c519e3227882d82c4e74250d429c23b044616e0a70cdfb63b616562f6231c37bb53a4e4206c21ff4d9d1c431a65963fdd765f068daaa97d009778b37dbe92fb13bb0e3ebab4821769b56b7347a32d1f0631672ecdadb753719d6a17949fade60ec0f1d942bf35eb5fdef580bbda9218bdde66519d8fadae2c4f36ff389b5e8bc79e67846aa4faaad24854e95a55e654cc4c4da3720feec8dca98950ba6598e9ccacaa09a404d52945f55248e082d366abd210594afaf5101cbda6b4ea4abf6e3efbece722946f79c2de62772118514a3e5dbff9af6a22b5ddd7b152eec6709d74341278a99637a94e297d4cfb40c8e954064fc3810ab0ea6e5a2b8d77f6fafbadcbf05385f82396fd07a0441b857f752c696a469414dc1f63fc4589df6a018d5cb6a54bdb3c59219ffb3570172b02fdd65bddba677814fb1dd29ae243a7f060bcb25b7725286bb3745eb7dd95be95bd7c47c1aac839153f2e480b0b1ff021e8f4a4cf3b34e5978093a48691fc83150f2e875c0cecbb37f6381de797e0ef00dc8b883d25f9dc24a2a034e05e45682bdd7fb3c865a501f63e52af077a3ba2501270af23b49502945e25c95c44e2a72753a338155f4aa2825b35ff71efd112e499212e3b7a81d00693c768c07a13e736bff9b4e35dc5accc57a344bdbb776326d4fc8e870aba582bb7f1ce91ec7993d40247a9e4491a9ef95a5853dd4551a860f1c5b5611e2d6adbc2aa5c6d152e5a546a87f6a3e5a5e0221b658e30cfdcd11b9d873690b833c345182c771b0a14f357ec53a0d611649b93af066f6ee3a460943cdb21f3724219771f1977b5f3846750f6424112a885cb10b10f48ae93756d470ee3ed54ed81ce8cae6c3877db6641b0643689973367125ef406f696eb58c67dac6f1c1767d4eaa82d0f4d35236c998b3c0bbec8301ef4871eac90dd66739b2c73936dd6eec169479eff6d8632302955ef3e01e20193c49115aa31773c625a1eab0d69c01fdbddcf56b6f6a5a799d34d86438af30624bee30d6aa1498514d436a73927182302d2d4fa426634492cdff758548690817c85aedda916b44073f881d0e1ce6aab2e7aeda4cbf24cc324c61569186dad962ec6de7bd095ff7b0c8d52f1b64c9686f70c73a2e3c6e0e29c283811b93e76f4579878bf19a1a65cac5cbf1dfbd53ce1621dcac6b4bf1b5143a90661d14ea2287de3c97d1066a4d405e76c20e8d9ce6a622ac9ee42d232c60d2ea1f672a24414458366e6e12abcdd3918c01d7e70aaf05ae487994a5b84fb97becabc2e6a564d1c0638516c384cb27f148d497f208142b358366adeaaaf229e360b28779999395849d5fafcd6d89d96b05267ada1ed91f9bfac8985d396d38f464407d46017dcb4867d7c5d1ec491d235a0d1c65233840b9f8bdbd237097aae9ada2618c883db74dffb7b2f6d0adb19c76492332b6e8c80d8f3aa6c582595464cc0ec84dbab790bfb1de86cb54bbe24e0ad25b19ea57cac39504a65daa8791c17b2d3479dd373ea8e9f0b7ae0388da35b29953c9d46cf08c263d24e66a91195dc748a67ab3ddc1d1b565acd2a55109b199c553d040501ec9c3c101470bcf49e45f9b40088dd22a0a40c2895f8e28d58871779e145562689e9ba8893931faad1ef3b13fbe728d11f0dbdab3d898ca387ad000b817166914a4dc89800c81c1b526ffc2901db2bfc615a645ea6d5d49ef7728900978c9ea1a02ff31545255ee28100e4ec7053a2631e946ea050df4559fdda37ba1b8ede8ceb446ee7e24ef41a7d0c7caf81b65b67262f7842ac705fe36f803b11032c3f4eabd191de8bbddecc64624c49bb0c098b73095799d5c69b0394f3f884c4be4bad81d892de9e56b8562be2ef4d20ef440d028a9b13a11cd8fa6fb9661524895dd322739c762bc7c13ab66d7912566709ab1f522c406dc6e3b54549b86a7b29fea9bc4604bde5d1b4330817d0d7647be40bfd5030cc6601df002854190fd186ec7ceb90976503dc76238653577055a4ad1034198b32d30302fc9bb6560af0705596ca06b4b6107c5003c225bccd708edb6cfb9e84defdef90357990be679485cb9f112cbbad0c9513d166aa8184818749807b2665e0a08234a81b8d6ae0558c251e684d3c0897d532f09a40b1eedf699639a1558f6c75e3761350465114369edecdb9e04f2304527a68183230327280e61d2ca7b0619efa07e98b133fa0b860a735a04619e2002e9e9a71732bc51bde299beb151d4d5b692711a827bbddd1e43592bfe844ef243065056e7f40ab7760504c6adb9d899c2a601eb2e44dbd635c1b051a8ffbfb1dd8e9029c9d15a4fea5b74c905cd615ad9f8643a9af046d59dd90121092022c0aabacf2a7dbcc82250f451e008646d51f0c655a6c86796016fd266ff7b2ce86f13fe6154a4665c7333fb049d6f7f9198ebfc7936e74340d74c3e745e6149eb31988b046f38e522b2422a6bd154ae0fe6e8beb7aa4c816bd11436a59956eb134426ec501ea9e631aca105dc86c151c0aefac881e0009149a496091be97713360f935337768040b217d9c407828882dd48091779884a834ca2999c031ff13681a1884d3a90819ede08e4b07c8fc5747144c598106e02d7064fe5207613864ab49276eb27a370b197348bd556d9881174626102866a2f862d6d6c10004f2ca0887d7f17f17343074c401d78ac8fd3f47ab55cb19f757a18b1e33b324dc8894f0307fae4575108d37cd7a08aa9c157df624a116a225a1aebb0fa04b38009a9cecdb28d20df2629a4346f2b48fca22bb65573bd28652d02e4709b663d7923586ff586f131a1c22f29f5303db8e5828011dab99bfeab744e816123123b66bc96e9e64e758f805bb202dfda12395c902566c5f506626f0e2cb038a9c7676817dc72e1bf196942893112c3468e306cfe1c0ed432497c921c6b7db911b823b7ccf7becaf0d1dfa618accec50ac6fcbf48b2e01bd3d781a7a8d21bdbe54c612ed8c8e433ca4b7f8a5328d1dd9098ccc63801d171a0f131db61dc46878a0923693c19f599dbb418fc85c7c73b7e04e3ccf5786dce0e06e084541d9e1db27adddf10bade7a791511e0481bcbf048da90aa09bc7bd019eeb51748644e9e6a923a363e1bf5c6b537775d5e722058fe6402a725e61fcc89a6ff6e379864cafcac0c03a844438d9aab5a97792ef193d7d5023d706b9a5b96c865dd4873b350e3322886d3a512bab9f27c9fa91b3b870e26647d52626ba26b332c17a22be9d4add760e3375d028fd10e7a6df2c416119c56830b8e0fc91c6235d39a162a047cb692e56eddf63d7138b0e26aa3fc693d7562be780c432dd54fdd8e18a57146bda6c30623b846f82737d685b2f42141c03edea0f4924e55a45bbbb07031c9778047e62463849dc3a2d25f5666a2b502a1d3593ff07f04bed875ce1105562492876d59193e79ca4135c387d005cc5e758faf234c8128f740c35ddb4903e5cbd69150b9e5e145019b7448c24b12aa0b60c1c0461fd0db1ba51eb4a1b81aced55864b569fe754dc6418de827663bffe0b38aab8cb0b75ffba296d84bb6ee7a90d16ff3ec936fe547877db655672288790f5b9290ed4f9285947453ee85522da2e033a6f5ccd52c828803d458c84647e09ca9e66c564d46b10c85666900bc5149bc5c6468341b3f737987aa0b7dddd2804e9f5d1f0318d910a14dfc9202141cfd79a95aed2fbe82631584c8a44af2584d8ffb2a56c90fc9f1d97abd66fb02bbe384d339fb7baa271dd04cd23f7ffb3faaa7bc34843f0f4353f21d3748eb401ce0e795831e0db60024f47884def0f5cc6054fd99906ef4c46fb872ddf55d3043f4e6c23b3ad847f8232f7555efc0fe5232d7dc7c5b3dac37be54f9781e030b2d2cc1f41ca1674b116127a7ddc50febe8eb00f1d14298791c65381eba2fb49474523e2ec5307a31bc65171ce3f098087a030a79a70cb844e88d1213cfa58e54904d86d2e0222075148152a7d1a2efa27041789aa4f8eabfcb5a43f2f905a6b01200967a61d15f0ab11cc558d388fd40ed4206662ee52f41930ecf87a0680223f8ee0b1f197e21e1666d19f6f4d5b871c07a92ffb8b8e90e30c16213d6a8d2a4367b5d207fbcebec1842e5dd7ce59a9a3f330ace7e29428cb660a06b3436b169ec66b92bff32f7368608a25a3ed7f16ec4ae410111a226c0194e7aa3a98e7fcd3ac238f6f34f5fa5711c37b6081281de0ab688ee667448fdad44ee54da9cf6a0f6f94cd0ed114f019b5bf2f9e6ed21622f3699a4437136159275c437736875adc7654931be3bb41d2e753407be0984e923fca1b4b086a5912c24b104e922c7ab58fbc374a12d75be1bd2a48285b00365bc3692314369eb1d71b85c42f09d747ee0054c0d9eece12f11596e86443013058c81843033b96f2031e8c2c39611d1f6fb4d384109fed2869b4f5313da0b9800b41ec60907fc9894170486fcdeb5835960ee31fe63a0d21e3f8b1539e938f775b1fed43ca09b0d6f9056384ce40d992008ab0bc44696cdcb99d24ab7bc031b40ef7ad59c7bc93c47bbdfcee8f5643c0504dfa659d794fe8f8643a0bc2f3ac9bb99091af3b0ae2784e23489f71d22f42a09e46b4de865befa2a346de0bc882642231c1f76cbf6094c23002be31429d12222de7450de501cd8b2af9202750593bd38b6c35e2cd25fe67819bd523ca87e5c24b7e517b746a23016f645ec988393a89f1122b62fe4862bceb1dea888c825bd5960d4029831af2b9aa1075c647291690fba5f82dfaf332ed2540c9bf3471b8744ff79882d22b5ae7d318d70192b5a12c4460d46cf1af641a69975b7ff07d41ef2a65ff1e51f36512af357c16c414055e5b3eef7b5268ad64650e4fd8c19f4f2fa3a842d1f2cdf0a49005f5d0350141f9490a5e2061dd03eda013346af81468b1855f1b9718020d0d158973a41b38b270e3ced6b50c4ff42bb78b4a3361b121ccfef2472d4c32592a2a3f4155dc202a8e784b661a1a28d224714853636900f10c37a31deb824732a3d56aa2daf861ed337d7cc89e54b648a78666279d903d475f7d0520561a4a2e1c25ca1a11ee59543d90ee4b80aefbd9d776187edf7bc35b3df1efd2f0c8410d5bca2536c75bbf08f976efdbebdef84cbcdc40916b9d38f1a13f32ce1f679fddd7c24f5f926c1a2c0a5ff8f7a657eb0bd21f1a10a0adf82e62abd75d057b0960a08773cdd04168a40ea6b9c8cb1bce3f101b1fd1fffa4dfcb610905f8279b9d2ab87f2db75757ec60c93937bba28a78d31753e536f04f9e84d6c7411adf693c26ded1a4451d08afb978bbbb2bc12591f520a5d2bbf1aefba606285c479ebe5acecba1f008bc9b4afb3503739bf1e6bec461d55dfda827fb3195dab61702d48c505b88925e2cea0fd0bc86eb7bafd2f480562bfed37fbc92b2e2e3904b07100f8da40494087a968425c85bc743e011b137129fedd7752a66f1dcbbd975e6fb14a047ebad528168f98d9491fa140717bc20dbeeda0c0aa4ee2d0498b2e017e21fcc06c5a8dd63dd56c7d93ac939832189bb20e7816c0e0b3d93e7dd3cd51c79cc27397565fc31cdb4ee34ef9365c2812c341c70e4d312e0076d0154dcee2682a1ae2aa9db1881acd181954a2e1743661cb7a3f524a855c6f05e4629578c357612aad2b23bf8b8e9151b14a008d4cdf7d5574d330706ef158b04f941249c139d7b2aea6e5bfa16d649055a7706e8b883c0d64a3331d08a65e56dac6fd367ea257f84ae464b3fcef0555aacfddd6f6fe9dc5a2c28f2b0382069deaf7cae4c14dde2a4af2540967ab8fed78d2d377d70084c2266d135b61410e1463f212360c290d1c7c4792f721b046033d6ed7acf193405b973818af0ec7e026c80d0a28b9fdc09ea73bfb0d0fecdc347d193d107513115d520c0739fd34ae7525dd795d0a4d6a8bd189042303c3944dc2c3bb913d40a918722ad5f08777bfa45e90125afe3160a9cbc067918fff1847147324879610249f643f88086295a6d7ef1b1ba0c6999f4fe41f2ff9b88d54445b94f58b066d56d405b452b3b38c8f51fea981f4a21da56426c1cbd71cba4dcf362e432481e4bcd317b5bd0a67db67b0a559dcc252b459ea1847dced7c8c8b153e3abe034f70e2b29f708783ac9c8dc073240f49a7609662801c9f89c48d55772ba037be420b47a473329e21e033021ae4da13729695a7bb563f6c277ced9bc63e305ea3bc2b1f9c0e7227099230376bbad2091e51edec9e4dbf0d2854f8e75aaadf13a5adb51a95bc19cf53f1d13716084390d1e765f3d4b296079700bfd7647086e9e01d4e35223a303b9a10fc061962bb29667f31261e7d6d00ab8b044ca292b91ddedfbe6877d260096660e23c6b8c41e883763b636c71d787c019b3eee8665c401178af18a6403dcba1c8b6fdbeec3a0fee6b2878bc03f30a82ea62d2cd60c46524e445205c68cce4a49f145e2aea07be1e7e38e41ccf7e091cddc2ab0f708b9d210c8bfc2af7b4d9b7ab67205b53667c8e7f9274e2eaa3c5e4cff1b6d637b802f189ab81b1528f912e0f398a6e9b6dcfbf2cf968822d95a69b1bb98f6bec02f8b2d4dd4e5ea78dd4648d4e9835c2c5d6ea6e57a633033fef44eb478a056a485c7523348583bfc549673c39768c9e0c51649f6792be29a213655f54ee2df44610776c42223ebf6eccc4fa6eb7f122fab17d82b85941859e556ec947e5af5ed293382485a5dd2e8fe0e34edb3e6a0804e92f23a4bf9892102abd65310a2d65b1fb7147d5a29155deae468fb8e470296c6a9c55f04b2dc6d42ebf8d65e6ceafbb42cdb526f7b1af844b7185234b687b6fdb64a530c5d63b60b062db1a9b2445b6d424f563f784e0ec58c70ccfc6c6ce04c70d2d7e48767ce7ac6989679918446171e50791dcaa69a6125c580e5dcc4ca1bce6eda84dc3539c95f658c37075b16f6843b3f5d306cbeacd5ee5c14906f58afd327cde5c43d5cbf7530ac0d510b206ff85da670d5ccd1b4c40365287bd48fd8ea07d33241f7da4b68fb0b4a4c55f481f24118143c7a52c5ffb219cfdab489303321cd0dda1232eea3ad777538a4a7ceefe8b01e7e10681d51bbb283ced841ed0d0df633d40fb174de1397c9b193c0e638828e82e2c9a20f59329ca4287d61feddd39fc3e476e4d5800cf9fe1f2ec61ee4313409af24d344c38c57c74b3ca3c0d0dab0ae4e8b91c5266605797626ebad7ab3238d4a7411d554c2c233d6c96f0cd15fff9c548cb6d38a7633359294a4c2d203297e0fe8dbb2392385632e915ae5d230d9eaa57ae5ab014b4519fa4aaa953795f9385ff9459b05b7f88f98cce6821e3532f27edf388d9d98fceb5b92c3276c4cd6567375a29dabb52a75da242b7a314809d267959b263df1e6f373b9c77d8861c95569c9e9797aa02b7883e0027637e1051995b20aa1e33db0bfa6a0c679088da269cde95258d64874164f02fe2a716bc6805bb2b5ae2e85f77508f28d09e5a493fc7c4b4ff811d0b205399221532c678a4fa0b95df74ac3c736a31654306a9dcb4e9465a15adc26c57442449a8c83319efdecf6d74592421c0860b68aaf60728912ece1ab8daa507e32caa501484fed83c9a5689c2de2ec0af973caf23d907b403a64b6b1f3c21c2e12fb07afb69b89aa6b81718dd20eb03e086e3cd27a9b64ae9b033b693fc4e1592387b1aaf070269e2f716cc694246582a7a7056c2ff46985a397770620a0b33c81ca8c908f889cefde81ab7830d7162800443649c13961076ba66bf3ceb306c45cd5848f8b6bcb6495f7013fd3e84baad8350d369f53c105739851238a9f0c3bf7e03cde451595445093100e63c376aff60a216a5d51c43ec80bf1fce647237a7f22bf19c83199388be072c3982af0259066fe01afaff41a285f6d990bf365f5546d455ef7ee8aa0c71fc95033068d0fb35e36278a00701525151b92729f20716ebca2a2a91aa73b8b3d7cf1095874df4b74ecbbc19523818c603877fec492228aaabcb49cb0c5f8256267b76647002d288a0d23591f620067e987c241bcd08ce276a073e21b3acf61331edbec6bd129c2e7ea3df45be5808109dde59d1baa6456912390779193ef5177f0ff4e977552ad603758a1373dd6b5094a626b55de0f336a058e390abd183a49cca8a965afc770cd8279be614b1ab9d1e3cf458490030411c2e1f2f04edaf1ff1a33d3e08961988b2ce49c2b0636a076cec93e6b2c90520cdedac14c4a87443ac5cdb189a42223ee196d21483486df2a64820c35ebd7b680b1b7f6a3d5dbb5756a7ae7d79a82ff82ff440b4ca9afcc1ed44dab63bffc93a3ec0d87697d2290374b472749fc19a42ea1db1dabfc41cd085fe6d52a1a557e8ba08e9d01c7db50515c2a32e3c5891a7ddae9223edb98edaedaa01915330d2b84e2e27a2b90ab1098c149a81b60b522e094923e158d9fee0f9b099a281d6ab3e9445ef4f4fd062624736cc9e620d256743c62c0d387c348c2fb60453d74f1a8a6164cc68b81077cb0d29d4d2846ae974afff20a6eb3df9e464f66c47b4bea18301c2eac14adcd9bc56eb6a12c7b6bf45c0acffab7a7b1fe70d69f6ae5093143d7dd900ca021ae1c97700ffd1b16617b151e8fcb7ed40af480580c9cb4a4c92c69b383cb88edf652feebd84bcf52b30df8dc58f485d0e74a8b2fc908bb69f2271a9412c9077331f537765b857be7d6ff48e0601b03755eaf7e5d2434077215131d55aa3a361ced31dd9f7d055e6cd589a5a48a2d43b0121f94b6a8bcb8353526b8c16ad83f7501a2df9bb237f25fd05bd8449b295775fbb8b6abe34f0ea66038f385c2451ea912db50134c77dd904a41ab0c54c1173434742c690ed384ad073ddc05144870c08ce31fdfb5b86ac5fee2f9e49a276613da33d682a862fa272236ec96c36015446e356d7adf5fdc197d757b7d7258eac95d90481973785b6471ac802f726e17dc824a5860dfd60f98f253aa6bc8376c71bbf88e14fcff5f1b0f473a03229308410fec36fd004946a8b6808219e95c75fc36e9dea6cc242d4d2f076e3c17bb0e7602a8012afe9450778acec6ecbe39d865b8e73ae85f9f3c448e0d7d5ca2bba4fadaed67cba29b985e22a2442daad690380f751dadc931ac9285a6054fd05e01a8ed801b0db90749644673383fb808a8adbdda51000bb08c522fc5768e8566b4280b0408c36d9a6d12ef4bc0a31095babf53c64793a3b794eac375708c3769ca46786bcc2d90d8b9e2f8dfe18453cd24f1a495fab30be5130fa2e4a5b1d22256f43176c4a58028ff12eaeec070eb35abc8cbb5beea7a0d3e390864b13ccf18d74debecb0f12e4db6b1b2608da8bcf3c4a6c85eef8db244b691d5732cf20f0d8aab1f5b8aedbf4777b4f4801a491f40ac7f5735ad60c42689138cb2d648ca60fd67548933c869d5f640aa29fc533c928911e99d375fd8a7ebe28309376500c48970cd28c020c7f3a338fe889e1766b276c6d175e090263edb794ac371a1a22b9adda656a7d3e3712cf20dd1413999b0ac37f0ffd3227c40d136a78c74592ad3d91e89becd842ab08a3d0b16d0ea230c5994ac0bc829477fc6e8891778006c50533b83a68542d30c36aa914408f9190ee72b73379b1ee6cdb9d8db26cb50233137ab3cbaacd0736f5ac3995804fe4949bc0dad0e1108f96f39c07e1b63081908ebbf9576235bfddb489460bfb94217d09d176947e8d50dbf4dca0fff975254a3b275b297b6930b2d04d9115e6865208cf1097a0cd1c41df0f8ab22434398a976fe8872c37d4171202fdd969cd66959ff487001c41dc62dbabef24b40a14e733f824bd4bc401cf0961aee662ce2c08e7e71dde9da5e7fcb0464ecd7c7b652403d712bb9200dc6c4b9dc80308b91101febeeb9d0ee049af0670d0205307a09d386e1016ff3e0247e563addfe562bf8f1b589a605cc713459c887111c1a6bded18b0a33eb3db58dec051796312261028fd66af69e9dfb822439c9a0274162d61a1a4c72cf0b2208404114838055e53ff0fdb86856d3c6e4a28365056c9d28b19ae8fcdbad74e631bfe053aad406170f9692583f09452b3f298dc7cf2158b4429cedcf38619e620dd60723a056213103904f39505fe4b956ac0e7e4b4ce3735d2db55e2400d27d5201fd2bc24cf45d2bd8878a0838383450e6d2826565c180a2cfc76cce131ca61a05bbb11fbdcb8bbd67e40d668ad90fd0a11ac827a5d07cfa0555d2b59b8f2f2b4f90e833ff119da56c87108581c2d9b5a7a03c70c39e1005f18f72845be647e7cb63c6bdd8d58bced3ed7df99f355492a32ebe824ffe90b33e8bf8eea189c64038f7870ef9bd1aa9fee79a43dfb806d11e55e24610dd3e0a635a2d039fc55e449d1b62f22c1662f619891f0ab0ea2ff76653c17985fd1b25881be516a66449f1832ee84562b63bf104f8d327b1e56bab6d6e14ee347a64b5bdcb23cf1695d7c85ea181e875c570ab971cdf2c80a15fb49758caf03da703063f19abdb6ce6e4356fd1c131efc9b2cf1d3dedf968608391ced7b96ee6d071c6a8e38ae76cafc922c3dd99b7eb5c25da32c8892435d119e8533fc3bf65ebd02015b7013b82996ec98d18793a6c43625f0ff004762ab4df9c04e83b4768ba6df27a8b407f5149907819b5344f0e4a76c433ef88880293866ff353ff4f4b5f35789694ea52008808e815026fa225f0cd3636f65846fed129935f410b495045dedc4e2a706cdc292203e0e4188a27690bea5f86f22b7b5a857cee935cafb9dd50ab51b32c6ab96a104271a12afacbd795976718602098b257abaed5d77d1eef63650f2db3e2f815b83a359f31a74486571335467c4640d5257d731515bb0ded783e589fb8559e3d7f17f455115860d679930fd5984411c39c2df51e320acfb8c2b8249f0f80501558bc9d97e4edc268de6f98b60905f169ead6517061521999f68d1e38c251ebca319e222f8e48f084eacc6ce695f847925a83d2db6b75ac221d6e092e7338a703e66f5ec3a3a4930e1ec40a7805b167b1256af10622fcf44b11dd191f4f145ec0ac5fec7c99845beed924138ae664b56fe112ca3ff0a2212a043651ad8b579f32710de1f11856dfc12c6be0f817fc81a0e9e22ebc75806103faf3bc26ab1854291ba3ac0649a8aadb04452e18456af98617a3fd3538f315e060fd875bef2fd0f58f8c2bc0d134e14f71637cf880c955edad8e8b611258b9d0895cf2304e46380b28b1c598043e82dd57e44ad06bc617f78ad02b205c9a0d292e0ccb903a834989365267713e54690647ea678a0e30f8545f43420a700b965204ef96330855644eee547351a9153ddae1175c5c3a49615261002a89a3c7d28061d6870254bbfcf8c4d3f232c3b458bbdf452b4ee34f22b3848515cbb8621ae96977019660a2a566dd107b2e69d8f88b8b63a3a3db4c384833cb5dec81772ed77ad64ba5d2f574c2cd0f344976ed58deba32a0351fd15b151547da3ee939f239e01c7243e77da80e84b77ec27a9ade9e837aece030d51662288da86781348da2cf9e4d91fb1cf94d77fa9d82927fd506624718b8cb4168d64f1be9d785abca0fae1fe967e8bece4a59e416fe8fcb06e2a6bf560d9025878d4ec80b8a1a000f3460ca67d4d0f389276b674c70b4222c1c22c5bfbde3e51faf73e1d4e1457d17d911bd02e2e9d96571a739353a1a39d22247711eb86f688155a2726035b1db07adfebdec94af9755e8a48273d18c61d81e6f03afe27cf96adcada8b8e2422475af05eacefd52e17a3dda8c655a41d9b8300f1e6f94d59a743ec7ba5245af0517981f8d9e6f8baf8b86a0c82fbff35b84fc993861b390bdae49f3c4c73768f4106be0437f20d00e5b95a3cf611821aafbafa8c73e48c18a7012c4d20f6cbe87e71f5c6fab6e44556e79f75b643915068073f7a1d94604f7226ad60633ed37bd4ab16e4415a7b80d7903b448f9031760807a180d55a7f1854579b5272b11957aaf1612d02750c1b0ed4a59f6a0260da01bdc294e39416814845ccda753801cba9e02968325471d550cc2b2ef8c1fa0fc8700126355ab49b98e12c2b160ad383e59a00692599dc3a35e8b9b4467ad4f78591a0b8fae470077f55f1cc14fa24a682c61762b12d9f60de3c89110c2408f3a83c4a2a9c87d0f3f111a71d5a3c35fcd49da62b08414d6d34a28878cb2b1a625dae9d88dbb12b6385b1ce48e25584b561963cc230d98d1c2b6e31505279a1f0bf4dd9f44a5b50108abce5b4903110cb5afcd61c89c91f2ac4be423f7de443819a9b38cef2b501ad2a42123a943856ca3e66f327b4030242bd9639c4901443a99f54c2c08d768bd4bf755ebeca478b2aeae56c936ac081d81c97b3081a4a48d49978870f31f7f774a63f0102348cd06621a8465bc756d11f7edafaee277d33e7f2c35ac543f025e1db35138430a298f796cb30bf208294ef18e18ed8286233e477bd1e21438a8088e5b88fc664bdfefad96158f5f8db305babc207f361aa787711edcd0040de5d2b60d38652981e2f1346fcb1af0412113ce3b1340489010c7f373f1b4218e146858c017ebd9305f3524de2fcaeccdaa814c7dc88b7202fcdf6aa417745bc1ed88fe3e2bbbffdfeae08fc3196641dbc86d76238e96d608cc0444359d7de34765505d899cc0d538bf10ebcdeb8d945abe5a1ce710b676394190b80a76b7f6aa56ba74f2a7c86a6157ce8890a5dfbe0a62ae28ae7347f0bd44d3b67461b7d85a6739215ee65c9f304f1d64d34baed53a40b135f1080c599e30fd504f462631e69f743e766f7a8514ded78feabb6ca781789b2eb83ebe056286d212175c9e08c0a5f1991b14825c501f3e7b8b59e242a11768ce43902711722b383c7e61e150d4eb1dc3d7b99dd14b1565b2f98f16e59e3f6d3506d1ae3c1e4f6b310da49462744bf307a6b1d361ab45835316aa96ba83fe8e2e5d5e2d0b836b396ea62de9b5f83e1f76cc1fb7adc9c30983ee0fed148a50489cbd1435bb0d69d2d8ee98754690fdec4ad02506ebc30f255bb96c281e1dad74ed2a0ac3a477f597d961b2c7bd0627a42fc11d00d04e5b59c950ca94d00b64bc0945fb3dc5e58241b4c3c13b846b61424c6c86c751c55749fbc48a2545b6375a0b09f5ad8927359de381f0c4b1294a50d8cc73ba487915775640afe2c3cc45a7f060cb1ae44b2931ac78a2e5539b3ba79184d775a5fae5df3d433e32c312df49171bb3c7ff1206a515562446b7a5a0b399d22247ef327a5487927fccb78aee4d40fa26f7c0757bccb233d8e2af61d588da5a51f5a00f32ca59af193844e11787f86d1fc968412c1af469bc8cccbfd775580dd646523d2fb63ba43e608908e372216bac21f61bf3a359da80ccc9fb3689d5fb058f793d2bbde05e6f1339677b48a606868818db2ed04fea2c00fc730f03586e116eba4642c404df12f6a09879ecd5d620c7af27ddd8e5b72a3790c48239ab4155e147d0c26085b1068686cf17b89e8f62156670e25f1d1b0234a2c8c2dd532606c3f2b8940066deadf66f56a922b8c9cf60da212194af4316cd4536a0de98198bfc9388cc1b7c5cbdeda337e1ba003451175a7b390a11d9e4040894ad34eadf3117b6b3861d7ce0de1be0a2404a40f7de0cad44410e0f892868a392ec0090cfa482ffe87de1dba5402550fa24fb045ed2efbc9461e05b52ae48b35f65185464cf6b462e063f4f2c6063dffeb4848b50b52a0a14105f89f0aad3dac2c35466ca7af93e8723ffdf0271dfc73506cdfdd8320a28137221b7fcd608d32ac486c2909c1ac125b05ae3f11281019adde1c1329cb3df59849f502c88f1bf3b9dbe218cad2299ee2b5cdb14715068dd52809b001e98740673798fcbb4569e6b557a9f6daf4cd90b4b55f6e151cc2fd4b9646e97136b108fde318263696076ee49074466211ef7c49c13ae075e9d83845ead3cc005304d81fb57cdfe489f2594235f94478622c8bf8383ff6074a8daa64024811500fc192f8c1a925a5db63022e2821d52dc8c53e41c5134433693b7f67e0429f6d0a93422a684846bfe3e797c3dab31cbd0e6dbe76f6788711d335c3bdc070c8ad0cb4ab20c22102d82989e9baed187e4e21df4b23ad043d91383869311668ebba68721586a097fa504823f94abf8bee2c60787b4e58ed29486b2290f005ea5b32ab0df41b648a4b8a214457f8d006b68db587d26a474d55acfe7bc8bb9a795e2c101aa468001dccf1271148b7818fd7728108d3e94ab8d42ce7ea4e38e1e8429e985c08a5b5e2112f514f35ba2f6efcbc52b672a1a6a1d8bb31a3353bbd89267469059d30207dde74a498105c20be18992bc0304053b1c45aecb1e82d652fd88a57e6d875f16ef84f3e627ec84d1179fa9cf46e212ecb9728c4938b398fa82b1517b33f1940bb31e13ee69adc6d9b1ac1c4de8c40caeb788364dc5bdef3805cb6e2ceef695627b21b443c45613a8bb2f2ed5a0f2efbfc2aa0d428179a308318c8c7e5daabbcc30e7849bfcc11c8db56ea1583f0de3d322cba806c9249c5542b2c9877ede25c23475ab5727d3543e7cb7a2037b9356ac95ce4e7ba518385a5bb1a752e9abc41d73b3f36286c2f0599d3e9f23895ad4c5c4b442811bb430c470e634d0751a5c5eb0b4eba30f482f35b67acb748c7a7df179c043f661a2a1531e30fa6a7ce50f9c2162097b0b3d168abbec56b36d2889ab4a8af033097c9aa15182f3f3baf6508bb669e14dc0fc26055f4699522b318cb6fed27025105446dd3c9e62d3d796934d0fca083ef3e54123992cd5be88cb6aa4acb41ef6c20e394e220d368258ebcac7cde12b2a3231441db814d82110e9a078cd9c3afa8e7cb06bbecff84ddaba5e21d0a20f66938dbe31edf9d6f0b28b8bb04167eca3b2ffe703a230e8ddbd4bcbe576903cb061a907e2d01feb3220be336bf9640965e64a2d71ab29ed35b0bbd0db739a0c3a686f44b2d3c4538836f9bd32c4921b8867036bf9e0df731b46458c0b24100ab9daba55026c39d8ea78eab8951f7248d77b119191f91efa5d7b698de7e209089d1b452f538762a8b6936a7da646460e43d49d78424a3848790bb9c2b9bf641b1dfcdd9ab695301333bec634e610165af8860cff21e80f301cc0053cb26351fb4160aca6e99fc9c1717d635396a8052fa97029219c6570642c519ca55d40883f1a49b1b94e42d44da967bd7983474dae43a0d9c106ab6957f7bd7e98f919cd87e29f46b4394ae40724246f783dde38bf5b286fdaeca31981fc047567e7f6e353833e548ba1ee51ecb2cc6f575737568f203bbd412c8642d36a14c10347b3843afe9079b67adf8bfbd888633c531ce524aa8c423e4c106a287a733c2dc49892493e29a394ca38c289136c34fc730d6400d66e56f5befb615a3cf83910b1a35f704e7aa114a843f0bcd23fad81276504b8f31298046e11e91332dca33890239c82d924439f258e00e3f4e621b6ea4a645fa1c451a0383913cf7b9f070861a92b4b935b6a513803dd7e65ccb44ae88611f7af66ec68ce1afc575f9241afb39943550afd4e8cb67ca4e6c5cecb86de427b290579a207cc7d8252b27062dffab384ba338d4cd6fc2573f02d4a0421a51ed218b19f2f0fe3d81eb819f81b4c6b735a31edbc59ebe5eba4b081cd151ea943052f72e036b76b07a70455ea383f291b6904f1f9eab6c793b645c73635108abf378a9571fa6a505de763ec58f9195c4264ba895c09c3be0bee4644b65b029d48f3c48c16859f04251fd2bc24d5d83fede56fb05d8ea311abfb620e56b13fba59fef5f22c98189d3a94cbed22b0bf73396d9ed71a986d07bb75e56f6eb4955ac218b1243c205ddc5b6085da66fec5fbc41953b27b7b151e7317c3e6f9fa9006f0f2f89cb53092486577244abfa99065e705a39e4ae5e2f9182626c9c67fb0c3c17870e6a3a9514a789e90dfdf977865d22ce65218a910214de41a7894766e9d41b80aed92573c0c12e1da0fd1592a78bcf60f9f4fb0c5fa1cdfbc792f78f9714ce6cdd692c76e05684158b827c2fa26f03a9dcace322b61a76180d8e91063a8807731bf46b5a4f05db19373b88d85e5ca06893277c57bf2c1d781aadafe2256b599f2103d19a9ebc7c75c42aba47e25e31883f138f7e5b214a3bd32ac84c41ea1c60dd43cf2aa7402729e7f6cd68bbd47e26426a839c8aac6faef6552267d0d7894bf5e95618a6d7bdffe5c5ede31515e1b4ed325f5f1550f8886138ca405ef357bdc79bc0115462404d615762d78913c8f9292bc007c9f9abde4ff78a6cb6f0d2640ad4407602afd3825f50af05fa65db34e8c8ebe1460f776ec01e512e4b64f62b81b3367c1572b7489416368859071baafbce97d325940304d6f58029294e354f9e03f4d03a42e4cd0e30b88c61d9399fa25f076f9bf896f4733a986d1d9a63d17e26705f1a681a36bf5b9452383fa018bc48d01a3f9d8344204c989ad191c1b6ab65993d57ffca0e9e931f34883821825e8378a74e824e48ac94607602f5f2659d35d41682c275c861afa189b898101bec6e1470a82a16ace3c95a03e878d8b76c6dad9578668fea2d0952778403f082a683c5df519c0a2580eb9dde228e0284cf84c2936d3777395d49a13dc50d38bacacdf6cf2003d309196c92c17983a179777451abc874331d342e02c115ea9147a565968cd52749918105793517e9ca35af49a18626843b6f1a63fb087e3b4133f55cf2ff79ad6b113f40e04420aa1cdc447c6b3700b6041acbc2a17fa81712445a07f070db66f4edb4408a8e499fa7cd821908bab367cdbe5f235e3023c588d872f3f415ffe0c461d2faec735a339303c63e74f57088cb89775dee600eaf9a53e6c9608dc9a8467d8bb5b4eebd69c2ed440927c45337184dbc906963f627a13f13185898faf4443dd558ba30fdcdc4a6144333206c945d7db4d5d1460596c31b2c00e435d6326e95e239394fd8e9bf411cdadcf6f9899195b0898ae37cc25720ad74042788885fd66da309c6b13a0d73bc0678f0afc6b0a71fd7414e880da125f5158d23fb53567db4a42141a121e7b2326c50d3ab3ba34bcd2032ebd41237c056575d26c85c426a8ffb575054ea3173f1c6833fe8582a10a269bbaca3d082ca1a52e5553c871f0f82522deb356c416e88538dad8e1b4b912c176413573507db238d1a725533db557c2285d9304e2b7d19ff4c4d24fdb48cbd9b6f19d9194ce5c3424431c0fdd583ab25305ae6cf6b25811edf0f01f7224df67873b293930dade3e3672055224dd0f9ed455cfdaf041268c8f49a7beb51de0aff27365b215a241d71f41174257eeaafa0a68beab5a9ddab171a9db0721ac17aaa90242b6943c394feda96730f8f85312d12c27a7a88e8049486f162b3ce5b02111db0fe360ca416d27796f25d9d2e78ed1e5ebbc0a20b4083120865fe96daf9125256bcc530a291541fe87c72eab57e15c9643d2a61e4db5cebaca8f52f9a85a0c78a40ecafd1526a927f18039af82075cf1bc0bba98f7a00402c1b803f4c574f6d40db76cee91506d0da21402298b2bef6187aee3b85f7e153386580b82914a4b3c69cecdbf1a108c70174d933c9db0f54bdf8f546b514fafbf0512de6d20d780a002bda80a5726055bf8a28603219d862fd92910297e4ed0227a3437e42ae3f78e8e6e22345dcd87ea404d0e29f6818bc82dd1da4109e030465210fca758bf462a474af16fab51128c5cdd66808b9e038eed7cc7ef9956a00bb082b1c4685bd314aa0ba2492cbd7d10bea7099d18d1d6a377bbf1ea4db13656f600611c12a84cbbed41d571aeb9934036ed40536fcf813125b2ebd953e25bbd2a45cb7a24ee5f6622e8ab37465619bd178175df9b7c95ac64367378c3cd0140069f1a771f53c1aee04e1f055038c566b91b95c7ca22655c860f06904f68b7e18261c129e2dc1066f3675361e66e7d2ab46b72a4c2a377378da04199aff21e80ab70b35db6770582ba46656d2137222a01a683821b72e589c8aa7f49217a74c628dd2017a48bdf83b2f3462487b2606f2f47b1eadd7abaa23616f5adebf77a39d3d323d14938ee88ceaeae23e1b4c9b3e3ce1f472632f5b5f39d76c946a67980a135458b3ccb1c9509dad37b522981d514b41b4c131642b50067fcc118d524317d9e9bb442ce396a86e5b428b6a40b0e6e9e857065be7c103a77ddd2532889c1354383e1f9c160afe5590bf756109964587b7c9f3d92666eb9783551511848096b8d8fd30f17c9642c58cee5c0d6de55c522906e7c45d0939454bb44fbb47348db92fb76d51b2e1d7b32abbbea0d179d49ee3913f8165dd8456d2ba61a5000ca6596b3b9f3723523e0a7d82bfd26912cdcd8870dafa7bdf5b480290a8a735d157012a965415686d529745418d21602241402b778291d72f7fc183896d77ee248d3fb8b61648c9c9a8e19492e106ae93b0cfc4306970a53bdf9059f151b3001eea9ef41e1eb894adaaf54a13bc734fa0e6f6112685be9f080717db0122d99faa1fe97e05fc1c57e6cc110280d9ab0dbd8ca86243f9fbcd6dc56ad9e77625902dcbfd7b5a172cda669cae253cbb95c3c97c18ec3584f70c4491f6d34a2c55bca6d25d7c99801f94e7661c0a03320031466d9e9adba4e1981b7261dd844d109016712db57388c1d35d1b999928634f84d5ca611cac5e53d2e2039b2d2c38a0d3ca438a9502964a21ed1ea5ed8c044b3e022a4aa02858f29d365559f77471675ef0755b25c5bf04c2f9f3b1f39d920e1b498a3f92020833c2755565baf15e96b2b266a118d40b39653c63033d31ba1db30d33b5f2e9237b2156a46bbb2c74619f06619a53ea93bd56ff1fe58669fe7511c7a990ecc1a5ed2bc9e6d45f87e5196d40abc44772e37ff7f101988e8a9ebb9ad25949d694f124c02153cc6970290d864c9fc72aeff8e522298c4cd489ce25e2789c1921c1422806bb805c617c8981f9af5fe0e4e9b95e6e60fa69beb19c5fca08a0bea187eed957d3893e77b59a91fc97d7290f6c23b4e17520f9430e3a898c7259cf76caa23d06ccf16d36e0c7900dcf3f1c0c6916d425e20f7bba9b45a1d09dd87e58bb85a621ba8d74406a767ab59f97334fb7bcfe113e966f57ea87b90f6ee7bf4ab3660f2436c764f87e32bd6a4a5f978fc6e9ca350260a4c1d4d1dcbcc7c059ff8de670c2a5faf08f5cea1d9ad4f931ad45fceaab8ca38719bf8ae152e302a7e03c453bb3338d02c226c1776fbe8e696def33cc9a8c9000c6b680a5d20055aeb5f01948480f2206be62f668247ddf0c7424ca4916f324aeea057e551b0629edc70cbb75059d714fa3f5d707c4602e27bae0361062da7c6e503e62ff3c30b0d6ea39534d6c23d2f89dc49d6488392305f499865b2e861f20775641888c38bac092a1338f422c4e159c1e1473ff24bd214cd639a5fbf5823bbf3537745755101814a4cde63c0db6511d4390fce353cfa12700aeef529f39da47d3d78b77d7ffc08871e5061d166580596586a33022568e0a95cf7736f611b39b315357615d4a3f6f86211409cb0cc64ffb35760123cffa28be2fd724596afd020fd0606d159ef9d5720fefe5273afe00cc8b7ed5865a5d488980d67ef2092d5bf331f2fe24071b68d51254e57c1881dbef8b4bcddfb4553081196965fffc1b05b39562a191b41e6ad1551f9afb575c21efbe8616e516d9092005a6084a09459996d80416e9ceed1877dec58fb910045aa73407dda5e58104366d3712aa903d766c352b84e78676f30cbfd99547d47ca08c2c8728e5f2ae3df8a8312186375af03aa99dba2af73c21f87ad675dd8798a7c997a65a3ae958d01b217cc4b98bb08a3abbcb77237092036d9bc43092367d4d0aaa905cc39e28e11a72a5045123d211ca54d98e669240dff4883fa2de45daf38c752977fa811c1b55609c8309b3550a367079c1f6fc8ed12bbe2dc4c9553470a59d54d323420762f84022764669e2bc16e67d0bfbf723c270ade8cbae829256ae252aae31387d096eeb18989067ff40ecf6d9be0342960df95780ef81a84951b907fcdbd61bb4d88492c590411462e5e1639a5fa251c03212ab94e4778ebcd48ad5df206b2fb4fc4033833b9034bd6ead0673578d551691020256fac43fb95aa6ae497134ca08e7d3518057f3261387cbddbc1bbffe402c25564a7f2af46154124ac783318364a6f22f293e3a82528bf3c284babc3d064f142758ea9d291de32f62ce0008ade2de0a150a61c86b011430a144588b7ddee8ac29f9fc767a89615593c7cef9a3e02db71efb96210ffc816057bdfab5fd9edfed807ffb3cd84a99ed564ecd5acbf159a7662b9e83f401c9489b65f88d28c97b3be308c3119a80eb23877cf281eb11a6be5e765cefa15ac4bcc8dacf47d8e483877609393d19f95c9a51932adea06a1ae4cb3c0ca4867dcd8dc487acf0cc0296852ec641da9d7c90adc81ef02981c82e33da89718949f34877cbe0787bd80b8a88a08b0d6c8e100a911a79aabc524e257890db7cb927f4305ab2683ec9d378019880afa570ae15f6a52e8e170567c9a91092fbc294a7bf71f5278c5f99b46b78713fcf3b9810f421acdb2b014059e9cc5627e96660bb8ceb2dd172f412e4f6c614bbded915c71ce29d7d6eea3da7cd166caf4ce413a5f66002edf6b1d496bde3823c26117940b9bf5f4949d6ec4df19310a57bc43a6ca03b020a28f1bebdeb251d164edd02169a57247af1122ca37431883469aa901e50aee0b69745fa977c45a9477c1f45acba96be8bf42a68e4a48ac6ea275dc87d5647e2e4bb616ba6f4586aa3a8fb3deaa7b8f082cc90e104a1611654166541f14826d253082135ead870a659606b596b8adf85934b0b079d1e7a348209359f8d168b15d0ef918bb3dafe822f91a9131008bf9bc199f3a422af1388d5291f23219001a3f3d5c5e109fc8d4ad62a06c63db3ec3d1f1c59bd61ca52b8e4f8c4840570a2e9e26665b3d8541ce32b34a5b12d9c425857fa1bec75d78721537a4ef452ddc253b79c087a28c5bf338978dc89be8f76cd64a252ef0e7d46944b1d89efa1889ca5c81d67d660f50610fbe71ad304d29f313fdfd898071a4e0562cc3b3a65c72a4341a59bfd92fe192d481032e53482eff4d94565562c8f75638a1ba60594a8156699ae300377c18afbfb4f302ea6b3963704a0410b565f7c971d249255883432743e5001523f663eed6660591eaf966200fc61e1b87911d4c7522d50ec5ec51c15578cf50f497b113e1da18444d50dc7e723f0363c352ed6ca3406f959e0f064827e72f9c80f923804a3555826927e11609a0eb522669404843073b098ae0603a2041c38a2f4214289217cef2c63ae05beaa00c4b77f7620750c01f1003331775706336f448ad32d03974ea0ed155c22e2c0b50284ac48930d58be043c9628b8faf8661d782ea9437cf7dc50820019faa5d8c33e845ac65b064d007cdf0aef93ccf25126d3827b7c60497cbfaccd4530e981976044008879c184324b2281f396bea0b15df5aef0a80ab4a74398e3110515c98a8de0caba4a43eb33607c9a1bd0776134292c039741b8e986de6cb8a66aac1ae7bb9472fd97d61c6d8b84070b1ff7096d4fdc52e66d17ea857ec064a1b77821eaba5c7cf25dfe8dd9188c7a70f327a4386953898c50515c5e07b0c8d6e20e0c40e749b414ca0dc4d78f302122a0d60d41c0d7fca4c5f851b06e55b183f78e629b3fd93c1677a707fec77251ee896bc52d6e13432c95e54ac7eedab5a6d4f4bf009343e6a283a80128dc03b60d32c47e69ffbe15c3cf1539a46079ebd954b9b07ca34564f3051b25957b3fd9c146a43835ec85a59bdbece417978db00e2d86ecd767eb9db491a3f74740fa159f871790ca84094bfe32f747885cd831b693d2e63e75e963254a313fd01e86d5d29436397bf7d69a7825a8084a5d17d7fa6f130b642e0e61f86b346e15fcbdc868f4409d046959b16662eb78ad806784ba3bd0f467acc909bef00a7acd467eadebe651ced6543c8d98538731381fd0a23cf0ee97170830e471309294933439d001954d21c72ce443210703b0805e073ab3bba107a02a78b87e77fc3c2384222163c35a4c46582b2448b3c808c48c862f1a2b4ccec42968704a2a951d320da2c846537b0fa1b5d854da779109d7dff4dc555ae775322a750112438bc976a3628945153369e17c1264478f227c0020a773c6437c7999e6764911aa5d8527567ff4cbdf0143e23842f5ad3c06050cd6c4de29450a9f2e0c9d248992872fcc9ed18dff47fc32527d0b6fe889e000d54e71ce5cee2188dbf37fc98f2e3d34873d09982e4011564bac12adb29f0e5790b47d2812800808aeb89821365525dcbf8bab4ff7737a89f634a93bc80acda41e358e611a024f02399520cdcd11d4486c0908e134c2f3c7c18f93a5bda9d6c5e54118598f93131d9bf4631b0cc424b11f043741ed6204a8c51808115b9e4b4dee2d50a31608f1414c3fc4de83a5c7f1687cea2eba3b92782603bfa73a54bc78fdcc752537c60b0f5f1fbfb4e05140588636e9918dad3f48d75ce931a02f39d4fe0b39a7d0eaa3e224ef825cb7d94d25380e1fb87fc36c760f3f6e6b62e2d52d4d1682f8e6684f49df629902262fd646ba2a011e70d14f3ac26fd3767c10709ee101153500b44e422a69cf21b5381c6f4b15f724317092d9fd7af23e6e97258ee7220020fde3f01c465d26bd888663966848540372608437fcb966a8d309a7d75858d131e72f173b6b85f1a27c80a88328a1577b68d201f1a77bd0dc113b061d544978f06dfb4fe840c2d8981148d625c85dd069744b55b65908bc32a4211568bbb20af3525d106d0ac97a0ec3f7f27349087e89dc5ed7d33f3bbfb5711904b085b6cb3e3346e0c901a641874a6de568564285939a19e317c7b4aef66b744d7ab0163911b1e911d7bd2f5ccefd9fb12a298240ef6a837f32714e3709c6e08ca9216c981c9b1a582984dcf0059310c09c55cda92ef77a329a8e86fcf0f744767a6c4616726bab748c5a6fc32f1a05e45a1d84bcd20c2f0275849aa97ad4d3f0451d0ce73a04a45016f760d36643afb9eba6d021ecb6e53b912cbef11d1f590bac099b3e98e8fecf332bc009c7ce15185796d3d2f8acdcbff84a3b11cc89eec9296df8fed6a231a8f41651a673f14540c1190baf6382354de66ea56ab686d7361281573ff327442f7a085429844b800364a662ebf996a6a3b21769b9cfcbaf41806d7cadc138b57b44a2abdc60a731d9c54a6c8323fcf279c2fa13c5c8e8b97896cf3c54be90ed130ec753757511ae6917b772dafe94f521461d63cedba8242e1105f28a261632a30db863d7e29e7835f3b71168cc8405ae199b538d9e3a5d89d16fcb1a87dada4f29fbb52b717efa0930a636924b530aa4958d20941a66ef0564d55ac8f667807bee96e083e2d6bdeff0d73807fb2e08a6df6154fdc05ebf09dd2603a9a387f5d6f0d146676f5274409f10e064f8d88f54a6cfffe2e69b994d5d69757d57c921983d16a7d0806cbef21ebad0b1f139466ad8b0c0cb8a54e53c3080c616b026149cf39c3acc29e759d0fd6b54dd428ccd182614944a9b71adcdfbd3e8a95944f79b1337050feed6ce72dcd4fc6b36bac51a05083d62406d0d4e83041632a9e84d3d0ac4ff393059f7224bf0ad5a4cfcffba0ae9660ae3f350354522aa3394da4ce1383faa6723b8063c93262a593a590d76d00f38c149e69925b9ce9ab15c3b5e88f94a3980050ba82eea1d90ff8530787e72564125ad5d6c9a2347d4d1b1bf6fb712fb96bcf2c20116c762b69449118546829be48b8d980e1e04712d4c90136832f2fc03bb9ace910446bde292d37e0ba2e228b80ab527406c460004db2e108a23374d737147b1cbc22532b8cac84b1bfa9a55ad8cf29fb11e04b18f9834763279aacc000b88650c893678a5d1f4ffd844f7ae79e04a33a1db7b89e7a4cded60883703d4c430ba44c7990f59b5e0e1537afb6caadc2d649b18b19c4b236314192e3ab8c5c62f007341ce35a86d809756859fa14afa6184296f65a4c262b14b9bfef9795860986eee85d52d25ce6ad99cd48be425b91d3b6a18236b5a6b327532a26d2c2d8387a338169fb882cf145b7e8434bcb7d829f22f5e954caa9e86a1d7bf1240feced94f80e00eef078feb402f008ff05ccb20eb1a74bd61089d92b519064ff5c2176cf5be544a2bfa705ba62bafda1c7b1551cb4460bf0cc233e2570b2068cad2dbcf92b112521ee8eec2d9703da3b49fc33fab217ffbe97573271b867b7e6649fcfeab4d359ac0e8b3d37b2eb1bdf4fc38e5a8e7734bc6e282b34fd6d292528a9d92740468988f9a2be8e47a838d538a0cb08b914e8dacb50c9e996e91cd9e63aa1a8df0533a60289ac23c577340e6bb490676a1f1c23fc8ca6f918049f05425f7d0d240f1562f8e05ab891bff85ce6fe67b7f265e1903d2e44d3c9a030cf1b61d62ac6cb6ea29283319b65cd3d1ed99ee9b00fa0bcef7f83076494857a1aabb73d8c8dab2bc97452e2a10a1d158fec1bd1babf8a836dbc0924759b67a1168ddea7ad06b73e05390e8c92b79703e6def143f28365b62e3c1e0416281da2b8f3c9b3adcc2398b0a7a4a75d9617a8fa5a27a5e9123056b1adf2fee36342c98329970c01b0e9271b4012653d4355ee0552f0809c288fc352b8b71bb2b2adfb224fe3c3fee3f6c9c236781fa8f452c1a3da1aa50fd8072aec2af1fc479ead2505224c0e7cdb00cf9712e282d964a6202fb6732c77bc425620b1a36a5f60bdcab24b99a5a453c5882783a1fd8aeaab85865842dd03ee87b3b4b7713b105ea4618ac3563234e2c2d2a249f7bc63e75ab93663b324ebca3775ce4bd3c11e40754d45fa24be8fecf73240d0208a446324c7f5e86c2a00a735a9c8e21dacfa4acc9673f33bdab6cd97cae66492989a4cd1f0a2431e58098515a1068a1bb703539672337e9b7b25ec0747737630c6e2b259967efd4b77d44d2a92621a25865b3900657cab83bd399557bbe6711c0fb0acadeb930f7a42feefb9e21efded7a2329fb1a00fb0288e463824882efc21cbcf93f671aa687e990f23191ce25f9a4d0d5f7eee8292bcd4fc031a1b9cbb0774cd2b8a792bb8d81fb55485873b875183e5f91ebfe9f1de1d8da605fa615e3b372b6d5dda3e70451c252c39d4605fed1b0f3bcd993005a2c398c6d0efb2ffb421cc4424563dfb530c7aef1292627ee24226c6bdfd1ace879a94f379bce15e2bc50071bda35c0beed005b269478aa892aa8f605c5556668fa685f7212ba0523881d261005b245b6301cbb132a45b636bc5c8d50876738073908aef2e92dbe881853e0b9785630679571d900bce84b8fb6459efe8c6d6227a2f5be9b8a0e274e6a57b143f3e52a8a3a1b36916575a00c0a35e238e3ff4bedd51fc1a80c7fb01e11d04d4898ca07fa9d641695cbfc0b7bb94595b05fe9fec182ab259ed771f4027a3a892bef38142c92eff302e5b4a3ac9c1a95d339ccc253766ebb29b6595d32d1190e23cebc5338cf91b4f4dd9c92bcc677d392690519712713cac72f3df2161f4e22e4c153ec8dee26b4918bf30b507460a93cc3d6cad0c40eadf6808ba37e80d93e31904f568edde2130984a123d19d58b59f02915942a54364e8540560fa6d9aa95025d3adcad447d05a09b665f02d8c2e319ed1f66f8b2e2b11392574e8d83405cff9a54b74fd2da9ed6e0497a530078d8d7832c59e37c813f6f4da8da2cabe89ed55647de9f912af9cad9100f4f1321cb856191e57051196aa9b54c0061c834be101a4d700ec16528155c16388913860ded7c62500b6098be0589ae1ceae8de53123dae708cbd9c8a88e96472e009737a1ec6464fcc28fe1983d8abc58f5fdd9353065bdc79ff750beee71b2cd45fdd3251b223a95403726ce4635c5fd20764ebee9e2b7e725afa457513bddae2d8468a907ebe1cddf204c831422bcb07c36d046cc0512e1861adfe67af02477513763bc8bb4de4f2ae3e04a201c9af37c4b8bed3e8200297795510a0f166b4bf301b8020615120a8ea242ee1da6ab60bc6373cb32da51fb3ce051013a7e20c519cf821b7d1c36ca1a0f9854d52f799b0454b5da006bf3b83c0853995887f6443a7e545b4c29495ee0ba8bb50f403ca75b35f61bfc0948c9e033afba4edbeb576322d49035e4cb60d113b40370cc87a35328e1f26f8dc18cd70cfbbe0abf6a81f1b0ec1760e683c2bdfcfa11bd40c2eca814f4b4195819a985203b41fbc98377f1a11fe498e21485ef200af052d2d8b7c40c87c8784e0799bbbdeab5de79328f8803f8d942a24e83e190ea1a0912fc950220ec17daf0d5928d2e8e2de07f2e076f778b1ff6a955f2d1602aa5cc1dfd30c3b70d0a7f74d2826c6792a6e211535bf946a4f50c684ffa188600acf10f00886014d881610f3c6b3df2c8a5a265dd2c45a7ff7482790ad62542af58fb8b339b82fdc171b28269acb4108e886842f7121ae47cc9fc472f4536506478e182201dc3e246496513c05920a3cdf6a8c3b47d794420671e592b93cc258b73e9a5d6901607523af77118d2b7e2294e2d6ab989cc80754359177bff28ea4341483e3b57779c4b80f5a041ff07ce5fcd9bb9a2ae1b624f6aa544e11c5c55f7dd8aaf1321fd9aa92e7640038545b24f0240d7257de4f2f4b45a08cb26eac54fbe52e2a0267256c1be98f6e7a6eaa3eaa5794d21e19b3c6341bab8871dcbaa5ad1b32916f152f7d5baea0c0a9feb50745a268ddd70a3c1f73e4bd7ff1362d55147c2a3926f92a4815db9c9eb1610fd357702d3e74cfa28889a6f3f38caa7962f5670a3fecaf725d0048036cc1b83b6f84aaaf44d5e9cf6ca300d393b03c517c4c08aef9924e26e7d02e9386fcef14c4ae018c91982f1944a7e5127acb6681bf4401d975fc666314642efbb7793b047d45b3dace5cbae92cf46b1e97428653ec23c06f208f1a4ef13cf8aab69e3bbd257e4e27dba671f5e128a4b47c1e876d192209c353f721ce48a55374b98a697036105457ce1e8ff732d5d74b10d1e68235647a86ad785262ecbeac5342b20025229dc4e2735552f37da064f36a573e0913993afbb98938dd4c7473cf71b0384a630c3d4ec85d486b69525095815f4797375f97a045fdefb535c683e5ad08cfe3c47a0b75792b35b6ad427f71e0106e2229a3d83aa9f22ae155bd75f84151f5e24a0c2352dab48a3d577cf0bdeda6d7cb8712e48a1d3e25b677ea3742f15953e39ab5621f869ea1896f6536c472d79b2369e70f98ceff2065cec129d1b389417b2deb536bfb04dcd088d04189d9765182e11e4354930af9a80361d397c6cf92f6d7427f2bff27f8ba94accfaa5e84384e45954d02ddec3a6504ef07a1c45f4268660d2645b258d2734d885acde6e204a8412f7d7fe25a0c3ae57bcaa747e6c8aa9225a71fecde5da8cb98ae17192df28ae7a6db30ba2bb1fa92bc051a1995e8d1c3d98c474af51a6ef010fc9ec1956400d1b6908a5c5dcd5c408d9b3e20807497ca37247f17e1cfdcb7d8e44556b32a898eb0d2782bfbb90d68e41147ba2170536329f531930daaecd543012cc48752177aaec84110dad6809c969a0ab6968e323e658b64538ff43c5af121e4f66399092acf200a25d932ff59a43dcd2da420c5ee72d4f52ec56e1904afdd7a87efe2431635a7ebd7d81ec5cb836eff8d4b22634ebf11d1438f91bee07fb1c30031d8da24c10b1f6b66d48c638d48e67af9887f7e59985698c2c1bfe48ef0281115a153d84c6e21bcff24231662374f7202c00ac6bff57307432222bcde5d86c73597deb83cdfd73bf2f3961308d2f4eb625b46d16b88ab83264a2861f3291a4929636885286d79bf9f45395462169ff6bd53e898f54509b38cf24570c6dd89601a5028cbe528a85639bf8ff0a53995cdbf18bb8fb9d9c9abf96699cdb4e7b067f82b8e34fbb7f095c98ffca8afd10c29b1b217a6d91e8417c1f5fba6725bbe3895db33948763429a69526454262779520cf05ffd78a07fa8a8997174a8d7b2fc34d6b39c6cafed1a6032546b2f1de727b0385932851a133acbf694ec0fc4ec9565958f480b698c81431924924c8075e56a52d00327c80ec2e2193cabcc2810b7bbf0b46e5bf39b1ddf653195a5aefa3ee4081a218e582349bec13c5b46ad910a7d036f0d2c608d9ac8feab9b1ce781818404bfba61f81394d4367bc8bc61157d70ec7d878e63982905418ab0692e4c5f7b3ab76fd588231ed030e1003665fce7c9c2440c421d28381098730341048d10df3dabf079eaa304eace1e3fe012408a8f29a844371f2546350d8787b435ccd2d014aca1c78bc6cbad243829972abe2acdcea7b9a88b50a90f0c9204ca3a3f9b54305e15251d2f4e10ee00105140cae798342b731c20e6cc34bb3318e4204cdc37d1219c52bc53e32e6bf45c1d6ef7bbe8e72ef9c5aedf5f175380a7e0a7b76ee2daf2633ffb1fb5d61a2184904df6de7b932de50e8b09f50879093a76447829c34abad4df71a1b6bdfbee7c3ce553cb49a485c4d6ac23a5dd58e7d27295dfa695d2c26b52db287b55a0c24b4ba11dd5d3c70a1cc147820fcf43e0a5edcdf3f8a95d5611f2d05a92c2c753e9b1d4e381b492f4159e02b9b582f156cddd0ade4a83cd3945c05f9af5a7813e699f4b2d3ed3a8c33c092df3e47aa6b33aad33061fe11a186637994da6042b5ad57ec587a7dae4c7f311ae41a789aad475d94d66b2b48d89dcf86815c12f55871612d5e5f391119c3a0fe91647e95ca93918ef7602eebeb614c00ba73b8fa8575a3ec233e28e9eb1dae384946766867c0821bcbbce92df380d65b80bb84e8b340839c2853cf2e31ae03a2dd2904492a4ddaa77fd94ff68521ef41ed2a4bc89963d1569b187b4ec65d8652d8d8692acb29b0cfcd46828c9aa8ddb0c15a9cd4458c729d650e41ee03a2dd600c59d9556dae2df774cd354a7572c4a7e529cbeea58ad187dadf49556a230abd66318f68a5ea66f6573bc5bbfe396aa53f7fcd6b7ec2c036f33e8cc269c52b1d38b321057a71bcbb4c7caf4ad761bc1cccdac4cdfead22c3be9938267503b49bb89b2963ca8b53a6b8297e9da5bdb6dd2b6acab8defecc79cc8f7d24a3974dc7877658e77a5fc7437b66f46c7d5c48dd79f0faeb1a9e05171b7fee38a7dd837c5ddfa327d9fcdf16e05dee1906dd3759795e9cb402e7cce909c1ed7c791325c2347a8b8f559d7d5707349d769a1869a4bc475b6aa26b95f5a084228d3577e93e9cb3a7c63bfbec9f46415518a76abe227c8ca742389ff1c141fd2b2a712edc4ac4cdfea17fc68eea97832bb595606deca6e3355738d845a276d899f145c637ad73bd98dff7ae2a0be67a18c7d302f2d3ce941b6bdbcbc88ee494d569a0e8fa8eec6777b52f00c2992e12c2cc2dde9687821bd6071fb431851069a961868a8b91de35e2e5b4f0a9e01df96b48e67c4ce69125b13908267f061ded4076ea82dc136431863a4674ae5bb80e82b5031c59cbe7022909997dff42d93d12a2290c9ee00dc0cd856c6ab38d3fa2e0878ed0f190c048ce816f8800b8580b77e93b9eb2e743193e670e640518afde1e6707f78404c11ea6762a445448e4a55ee0cf9012f2f0a50c0010e308001c48861125304f8aa995c3145a0947efa1543692da0ee021953044ae9d4640ca515614a51b9d6cfdc3a2b40a51501b7e4e670b2a29fa1b9d2222287b3b9d4258199cbf67240f44dec6572e9756bfdd3b6573f5dde1a44ad94b224105d19d17d175e5a674d60fa344331c4c1b932af00557eb25d4d32c249dba619c82a98a6699ace9adc80fbc31f62f8128a6086c69a8991f605326603ee0f31fc1c55f0f1509d132287fb0333f363d4f813ac9ad42298a1b9cc7f98b9932581bc3cf19df5f6304d30e7348114dce95369c9b315cfa14e878756470d2d24c12666fa4c8c8c26b1bb5bd6701241f79ecbf4cce384702217c4cb229b9ac47d4575ce654ed932f574df6ff52ad05da7e6e9f5e445b7b0186eaebb035527a33a2250b00ffec13554d00f3815fa1938157a47b121bb56e85486acef3c2fa106d9a5e71f4e08be94b570e9c656b8945a0c844b7dcc39abae4d75cb38c508e1d48c641068157a4a9b5ec80f1f4da2d7c09079c005419dceb52e4ccfd1b44960bfee62fa7152f641698f26d14fed0c593cd38be890517aec331f41cb8e20fc657514015a0d5cc7ac8ecbea704f65ce79aa59f3d59a16a5d6034d7a344ec79a34dd12a71dd1cb534a27ba750ffa48e50fe7b4b07bdcd114fb08d5c9d8200edf11f56a1e47e34c6a524da2f4f5d9da55280d1910da40b67fcb6cd3d849e99be6d1679405f254e8619a690cfd43424fb18bf89029b9747b492e3d1cf2bc30d22dd4693dbd4e4d4e29f54c5804de5c3ae9bbb9f4959a4f85fe69d953a1879ae8a9d09b6893ce3a7f69f31f8fe65e367f63de8b59866c13510ca3306ad679012fe478417331152cb954dd668a1c7ba5300c135d27041704355f313bb56da6c8a5aa3bab88eb54a5aeb345c465ad4d245ae9167a4ba3a7d194de3d7af7281de2d2b7109c10f323ea1555a94af5e9b3e7f24e2f7a2ef0f47f2ef1f44e06b5258863d5dc210f4a2ec24316830484281a31b5a007d388424c13f2a185ea64e4dc290bb91eefd655ef66f77d7242c0fb4ec47bef04702e0e36e03e06dc17c47dcfe43e00dc67d94d64a4b216c6bdf36f9959f408e77c56e0684632f89c17979f2bc3e5e7905cbf1e5f9048111ed2e35ed60ed1c2903dcb86121d7041bc1787bcf7624e6deb89ba392e989979729fd84ddccccc3c396747fdda3dd78e63cd9d5cbb5caf2ebbb3a364a2995a109a967d4b4269c85ae7e160d527cc364e9c7a629ce959b4dbeca94367c85c8c8b111dc62b08974018df45f4e36b8c81a3edb586302699a6254d4c44da857d94c18b57d32d930a215674a4792e289f40d773c13e659f4ea6e863127dbe9160684ca0d893394db2ccc2e920ede3d1324ccbd8c7ebee49e9e3b6acb6a69ad8497ac7b6ce4e770f19dff10238d954dd69c954d9b7d397b6a72aa38c30d65c33b3331dc08b9664d32184104238279c304208219c7114a58c324231c421977a9d46a0915330890b823adc91a7e4cea55eaca9e91ecf051a792ad4df42ec64390423b46f48b432a091e7f26c0bb13513031d136d87ce90bd9f5f0cf509c873a999a7ac8881c5a50e874cf7e1034845f5782a14f55aeb057074700c768e611733a9ed15b9d4331f59e50ae31ecf856b322ac9dd5e1697fa16e3526f0875f7843c15eaa3e995ad4ebde7ac5665555cc08943aa1d911db2fe4549447ee4f832ed443b32329ae071340e9c5ef7112adfc9d82e0136c943f63ee7cbdee31ed5c99833cb442492dd92b8eeeebe1cf05b13d79500c68ddf5c892fa59452da1cf1d0be491619b2bbdd5996adb339e0379e9fe0f9f33a37d9e688b68a79685d57ce4d2a6a0c1940844e15709de8ba3bcb9672d46f73babb140bde75ccc4bc4f1a0ade567dfe5944c8cbbff7ce6326e6591ef1d2da1cf5f3b4d2dcad135a27de794c3c9dc77be76179ccc41db0a110133f644c34f15c98a0a1a1a18979114e27b92625e14cfa906dcee630ce750faa33f143b6b91dd73aba855d66bfbfc88405f8466bd287ccc5af34c93d3a19d3734316930bd1104e854f9dc91eb2cdd9189102c3f770ced7a811b1125ff39f4d7d1238566eb4a51c2578b78a79772716c8eb9889919f1a0a24b449b0c0051c439d92f23c6662a4e5414f599bc31d6aeeba24aa90a7d23a213fe57c2a6e9e873c0fcbc3b91dd30cec6906dcb35b9a5b022679c8a66f434c5f70823a0f4a5178eaee53c678ea4eccf39053ca3f1727ea79cc57ea939eb24e886278501e4578a74e9d1664a8b9eea4151ad75d67053920e16e435cf739499fece49e6bd2fbbddbb19c991a3a4146172f8b5b6badd5a2281af593e607e3ffcb06e09515c02d0c158089dd4401b01f0b00eb9e8ac766189db46bd7ae15acb0768b6aadd5568b1ebe52971b393639363936d5fa5551d70d9753b1b0bc1f2c34301ae5480d75cb54bd4a2dbb5375486aad20842548d1ee18a7b690d8fa130d2bfebaec46e34ea7d1f2cacaca8a5cc12c16cac2ac4c7737cbb402a5bc68c83f4b5978c67c979597646141b2524f69b362e9ee66e996eea9592696ee696261a1c162b195841f4e55732be6ee943912102b9f78c6f4e97d0a22247ab5a294ba8bd2aa02d1ead4c5c235e8998256f56a2e33d50d1942082194333a569e15a5ab57b8465f3e2a5e0d0bd790f45bf56a6efc3b535b5919aa31335fd75ba33159d0b2406dc3a151978f26a14f771faef07b7cb565e1191264a93de1834ea8ddd8e2d6361ad5b23c9c5b2baaaa2aeab22c2bcfd2eaa726312d7b1af5e0a4b3e724bd748ba7b2ac58c896524ae9a5692c5ca3521c1a0e8d998f43a301594633099128cb58b06fd395daadbee1d0ee75eb553b66a75544f5d2559d890987c6c2352a16295fcda558409c5285ac8644f594361dd36af66aa5babb4bcf61dd1485d123161234ce4718db96a8bfc768ab943951e6449913658d3ddd58cf3955c6c6be31927a49cd292fd337cef909e7fc46cd39678cf36c23f5b6a32cc6c738e3678c51d6cc2a227bb4a5f83e96d58f8da00fe89ad70a8e6a8abf2a05e37d9abb549c2ea5c5f864acaf4eb5eb53939f346a8a320b75cbe4b9982d8651ec5b758f700de9b196aae766ca96e267e5395f238561169bf198465f2fe1bcccaaf5ebba6c7579dd3a52bd562ad218638c54468871c80f92758a846e57d2d2ba3e4a2995e9a795b049e97ba04b3ab1293d10fb7cda0f175981507ea319258910c9a244dd234261212917a136acc88d9752f2b425b8527d2845dbce0a60f26c41d28eb0538f171149e9067aa4de4da9ea7c85c9b7950bb2156832993604a2eac330cdddf71e469908fc68d63d1a251bc61378720506af8c5eb172e14bb5ad5c4a29ccf215977abc62e5621486612b37567cc5153ca3c8159f06d9fc6024cea2cfce9a7557df9cf3692549cdf9de8cefdd94e731921bef1a47d5f3ea9ed11161dc79cc3d5807c6c94868b41b23b91047157b8a71be15aaa3cc8bc798df8fe71e71ce0dd25b9667de5aa93a1ef4899e950944d98f87d2fe71eb93ef69dddcc33ad43ad3e8439ac9611e47abedf989ca62769b17cbdb52dffae4272c8eeace3ead4c7b3a97d0273ff1e8e1ff04d79887559502c5a58fd6ca86a3baf3950a14179e9fe02778063cbd9b2c222823b9b1bbbb9b9f704ea5415ed47e40b8755ce6f279153f6ba55af5eaacc167d7ab95ce39674b47cd4967654a62d562947e7b8fdf7bd396e8e51f333b66c7dc4a4ab33bc64e7237c8dd3af190b6e74d6f9a3d379eb302d2f617fde8a7cdae6e9e33b38aa87f9885446631bb351fe33a59cc6e1311f101b9954af9de7befc9091ff7ab43ed7d4e69f110be5bfabaaff4ade273d17359992bcf4e2cbb2d5755256de97d1e5a7093794d6de93d9ecf5c8138cdd9afaab375c49c56e6e153aa533844d36d954de66d0dc5859fd4a51193dda69b792a1211752e8557c62be77465b453934ec2c046ea145267855aa5966559f3b22c4ad9baae43eb0cfa654153c8e51a78e3704056dddabebbbbbb9b7ebea76a62a25b9e8c333afa6eeaf3247237cf77dc86efd04dd38ae6e79942e014d28e7294f51ebfc7eff17bfc1ebfc7efb1c5a798628a233333b3075a5df3de0512cd996522d14f72d3c6d6ac7704d7e8b365091172e555ea7ba07cd7bc3f51762be75c1ecdf6b242bac86e22510d8c5ff6358f40d5428206008f26867d34a314bb89ee0d18769ba2074fec76131bb2b05f1ef72fcac8ad1446dadd3d3d0cfb2c0ff3207f7336cfe5a4b81c0bb3a869514a29a59452b6045fa78d4c4c9c764d9b9999395e1a2b3373f3cacacb8b356796894494d23b1a798675782db9754d4ecd9b2e5a727be7e565658544fa45229b1a7ac578ad57913a7422086fe6cc3291e82791acc9a2afec4be419f1f24eca29e4f24b615b040f4f1a89f3c96c2871a35b26750fd5e6a9d4e2c3acf79e2c83f51e175c43deb2ae495e58cfca64175ce3559627f3489c0b99f93db6cf96ac1765195e5bf2467221bd90d68bf4d1923837de4d69a5945276216f2417f23d89433fa7e71df3c82e7806851e2a2f4b4a0fac26cdad966559f559d985e42274bdd2ea5bfbc81b97853b6597142e0b7c4ce329a595d6bb801b0e87830387c3d970f0bb56b4acec42be3e8ae14ed3651738ac57d5d25092c9bccbd6e329ae5bdc8d8a419b2e08cb6e382afb8feca25ad985bca1288973a9eca24172e8864b2abcb9151b028563a577ef9d53cf7f5a7d6b111412bd6b464723e9c3bc2e59eec15ffd0b5eb7b80696754f697d5ef0e6c250bbb08ff7deb39856dfeb7e481a7a51c2bee3c2aef53d245ce39d21172d6d0936f6076fe235e1cd8defeeee8df6d5dfe8db625c7e2a2d9e73378cf3b9b1270fbf7ddc9cd9f4ae5b7fdf3e13b0e0af3f6d93168376649d1fbf02f35c9800d96d9e844cde7b87dc5262c72c24aafbdefc09d9130bb26d652008e5256937b62c24aa176f621f5bd0c776651141e1925b2fcbd2dcbdaecbc2de2bccf368d4533494c3d044cf34ebafdee83757bac5b554a77ee34dd2c248278293c4aacbebba2e6c9bbfbe4d7b7d5155d7b7fa78c77cbd32b3a8522b032fd49933cbaeeb882a0f7f695beb5c6923136f92dbf578fa94cbcac06bbdfad63a5993ae8b50b46915515fb2ecc6d242a2bab555ae4fd1c774fd621f978cef2fb846a56c7fc133e2a9bb14de5c9652cafe62023500d45063bdfb55dd4d0821105d920de19ca0fcfc24c3b76d094aadebb3db34a3e3c94f0f08a6df711ff5b7756f93a16ca94f29d8ef51946b50b24fa98d3c039ee7a7f7fedee127aef13e515611d79fa557e419f3c15fd78476bb7cafb1e3a59abbad3ded96364f69f5308fe12b16ea96e90ece73ad9555bdb37cbc0c12d2469e5155761423d7909ff8f23719bed4e9ab0c4f94ddf84579fa39e37defef4d37421b79c6342bb676706e75e51b0890cb80ebb4c8c9b93936b7eadc8a91ba05bbdb2a4dc675cfe5130f92daa354422a0ff3a44cb756aadf21733c87b4b2a5ea155ea67abdce5bdf7a2bd6b9f0cc966fe5d2062d8d3301a4096ed7a195ff3c5db9efce3585bdedb6322d66335b6a8b9d5af6b273a26c891e7bc4a2b3327dafd3697339aeaad44ed465c1486f455885444d621d76d25c0ecc8370e6e2ea08960d25982eb163b343a90d256c2c6103f3a866d95882f9d948b6a1848d259ecddbb96c6309e78212ddce8d9bcb8930220d455bc2c689c634547d137a31e13c2efa862fb4f1369488dbb38194cd8d87d82314dd0b8675228b6233fb44300eba732e29f7c08f34f75234e754606822cd3914cd0a7dece6965c07e5e3355919081d7fbad1561978a91c78e797e01ad596a8c74b59c953b6c46c97e01953daedd95cf825780684f444e3188e71391386a6a16827f555279a8b715611f2c6a47ab495c4c99cf37f11908f274368517b79efbd373fedb3598287801ab486eaaa63c69899e185e4b2484c2df2138ca45b26f64bc3ecf604126624d331f313dd62c53be62835772d4dfebd62f05570c9a4e4ed7412bed142cb489a04374612cf4822c0976f51f17d6e59b6da9c4b76cbdae2c7ca2c1a4a32ca6e38aa63f4932ca2343f59eaeebab3d8af63f05ab6749d9a0065f9090b09689f885cd578a8c51810c2d09d8f318220744bf1f4f58134cfabb35be8734b93af22c300e89e3f90e6aa568920ed5611743275a94d6d0bddea52543c11dc7f8c849f58b13abbc29c3a538b43f8c89c9375260fe123131fe1217c44c431d6737933097c8475f888cc3c5acde465f62eb3bfc73a7c8412429f01c9fd755a980188b49b8e2b0fb5f8c8333339de9544c8770e6691982c22a2140fe63d8b88eb9876317f72374277e11f64cd4d47d4fbaa3c41111101e1291bd23806f4f164d6eb890fb2d23cbcef482e8cebb458c3cdad5db17504bc59b74c0babd0ab96c6a734ca5611f49174a389365b251e4513b54afc8926d2d88a003d4c8bb4ec28dae7279ae7261ae8ceb2d131a1c3f46348737385c6cb1059bf5d43cdc23c07e3676e9cecadae2d783ee29bc23361159655c73ec7b0eb309d61d9371010184d4e5044175f8472628279387461d7f99e0c7b523c299e1493a7e5116c460708f41110100602496c4405c8032b9383b42dbb333a3010f611100c34b2c204948140d64d4037b138039d848e594f9126d831cc9a3c115e9e5899be26761bc10cc86eecf9c763b70cb33e0a320a320a320a22bb90145a369bd1615d24fa645d348964f33bae1545a2ec5366d15b728a2815616589b42dbb333a325196890ef344d63d5ae9ba1361229147748fe5c13cbf2eca3c22eb338540d84766a27fa6d004fa605384817272d2cacb8591797e896c36a14c2793c9149a40d3679a98dd5ea8cb5f5ae419565529bbc5d339e374c2940b90f0e1f20caed3420d3ad4e62a7b7daa7f3e9f4ff5cfa7faa7b4e3560e7e3e55755dd54c223f339b62ad5ebdcfe792f968db435ac9fa609f4ff5d0e7a1ea0a1da631cbfac7e43af60df4ab7a8acc747d3e17945f36f4ead7517e7255199cbe5d329a5899be21bb8d6086b37b32bb615745f908cfa86c35817aa9dde0a71df5e564a54d77b7a7adf3118fa7c23cd83dec394c57fca9be65af144eef1a7af560a7af0f81348b89d48f87eb2dcb6e15d3f3113ec247f888a7631fde7bef82d2c4e4105af09649e419cfc48462138a4d2836a1d8e430cf84faa595aa4965627299fca2aeea323953186326c7ce33a35ec913c72106f1873d9c31c6159f5cafb71bf35d87401fbe2c1b6334615a85b6b9fdde7befa395765cceb24358c157d91c0539f53ecfaa2aabaaec302fa3fec9ac2ca3fec9fea1b8faf0abe715f594f8f9565596c2aa8fdd463093d9cdb215351f84675074daedd94cc2a036ec6eabab99032dcbb2ce3956b52cceb12ccbb2a6c9aaa6eb569d769379599c1b13c9344cb3a65b293ae3115166b504c37b5d4d3a51e9289da6191dce4d229452eaa615ce393ae77fcad2fe7f68c54e3c16c824bb2cfaf19c602093cca2a28732d18927f33cfbc75e009fd089282546004e3240010820630056d3ec05100000c418a5c010a19c9884401f4f865d96a2368ab2b72506ebbdf8de93efddb27bce49ca7e9772644589f608c89b2494721bbda845f958db6e4cad572debfddad7dbc29e61575b95a5941565184b25d5c9d8e4902b1fe37c71aa26a7e88c804c37cd382335aa99736e9bb555dddab4d3dd2625575e29491a4717e9faf74edb6e2949a6c72f489051107931c403849275a0942d25948f75ec1631ebd5f58fe6c91c13b12a2b33ddf8884c131fe1237c848fbc19aca118aa93e15c7c6e92da96f5ad264739237411c6cb4ff67db20bba6137ecd449e6a4ddac539b8fed198a1180ca6e2f77fb6d945025cf360fe65c7913bbb1911bb21b34c23817e7cad0419f76e301dcde39171937b9732e0438ca9d7329c061dc3917037c74e75c4807c09d7351b900b4ab68cea99034e7540ca039a752008d009a0c6d009a732a34d66af6767b11800d80dd56006063d88d34b229763b8c13bb65d26e32f186401fdbf3a2a124c36ca52c2b13af7ca5a56a29ea4dd196f897d9271b79c6cbd1baea4839c2a9463574e74eafee46b4cd0df5a699eaa9d4e254e465afaa5274aa8f8054232b4a9647a6e88c80700d792aee163aac3c9e438b3d20bb356466666666b615f4bc5b551c5951bd149d1190917cd53b8f82c05797e90ac05752db463537ba2ce6cc3291e834f2a50504692a7a0fad5292409af7f2b2b24222fd2251c35190471fa722293a232055b5c518d55c8ad1ed2585741439650c1b2ab194524a91ddfef8c44a28e508e7d6f7deabec28c808c8950c318ddea35d5bd36c538a4e671195d018d12d0e833459641195641acf4b69a594a320ef103eca51104ea9ee24f940e33215792ad3776e74725e8cace0dce91b691a05c1d145ba089592e4522c95f0744c8329f25c5e5e565648a4ffbd225de4cac72925c98d1f05e11ad528488a0e458d6a2e9552ca51109e11290c16c01ce86f301a2826d7096b17a5924a2aa9a4dba36207a554bee9bb3e293e94e2c6243f7b554aacda9275aa4abb4d333ae4e994a7534e17a573cae953b7eb74bea24c594a299595a5205ba51d51af9f522291234fa594a1cffaeba297b624dfb4d69005514aa90455b55237b75a1425a594525217a6657f9ae89386726872aacd7fb4ea308fe935a5e0cb96e4add75f405c29b8c6f478b2e702efb1f3b624e9abb4e4ab86843feb67c5d54528da89963d15eb269a7b139b8f508a7aebd53ba7fa641151d15bab9452fe52534e33577f70d059d41fb7625d31106fad9ab5a664a1d40a83a2a09cd45b2214eba2fa030546b5aab3a5faaea1ae3e205cfbe4dbfbf17edc780ba556ebd937bde94daf288e5267c16a5d1e26fbfcb81b8c1f0c639232ba07868d012346c5f5c634b2392976cb60882c4bd3b585ee81a45d920042870ff7e528e124348ce4e86c6ec7ed0c41e3c25c8065a016641e22783e63f880a8f02613a010e80f211316989c7caa38f9c4a3bc8080bc6051018145cb20d231ace8101513a572cf855ff88557483b4c8456906d2f1df8cb4530be906d6e679b2d5b63314563d144da8aa6e2c19051c6944f18b2cded4c266c5e919d9d9d1d6793813354d72d20e09a5b724dca0c10226d0c847b308d119c1b9b259d835f6c08c1a02c6c707ffa30a9f74932a4c87381e767c43c827a99b21092f38a02dc8c68ffe04351649b33f2e8f38820c988b647b819efcfbe7c608d2fa09b1797ac5578850ad214fce31a3152396803ca03a47f16869bf1a89d3da2c27d771f9d6c7337324dd818c1373733f4630a79136fe0cd0d0d7838a10d372419cc822ce00c8921babce3bdd7ec5ebcb6995b430b49b08999e11ddcac04fe64c1c60b1b0e831736d188112336e69c73259b73ce25d9e68c349c18e6b9c8bf1bf15ce2d4a47849e106373827cab83b50b58103b5d908597643348d72908958d0e366a11930b89febb4888318ee969dfd40732bd6f39660222db9a19384910a2fe0bcd8438f1d3b9c010b254062e00fee0a10ee26a2e26ea41fdcedc5077773373db89b335273210fe690e40863f0811a7e78010c7007406c01270a353c74e2202466c60a19c4600d72c8c210a2c08798feca737140164cb8828a9c1a306108317d98e7e2b2480213867421061af0200e31fd249e4b0370e690072c6001061e57c4f46f3c9713242982199450410728d82066016668c10ac0608517841c89699a1ab0a1f298020b7d40430de620071b0401ea8006150f78140951c105e6023f5c4970411772a0c8208410562c8021b0e10311f480033a08d98153bc81055317d04007287ee7c590374494ebb61892852147ac232c794ec417fc0b23a0ebb470c313575eb7c50ad0206326c0096e3e8639b8a49e89a20f3588c3139840042531dd5ce4478c3ba02e60430b824c3d842e4c95138e0061f0890f52204245c1092c48a18ae9c4c4872d64b006eaf270dfdb62055fd09b2d64a0c5c5aedb420660b8db23139c1093c7f3aafb1e1a7e6be59efddea3a6a99d13629a64047ed93a17c47b6bbf273778af708a3312018f609a3bc5799eb2ceca591096005238e9a4df22c7c8fc4967e4182b8cd2cd2b34855ae184fc4acfb175ee21a122a5749a788a16ceaef4add14fd3ca95f255ad1ee35df50d58d6bd95a90bd051d43c45e79dfb085ce8357c6fea8f60e6be379d9a93faa43ea94f869714457d4ed4e690f023988980a31cab505db760539fa51342462744844e08f89c10af9d101d3fd996e2dfe361bad497af5193324608a7e93d7e87dd7756e92398b96da72907b67b4208fbd49b7a85da564d337bf6ebdbbbccfede2fbd57e122c699e57869638c18dba955e62d6db38aa8eeb42e68bdad0850b768ada89de27c73be4f32c6279af46467154c4f359e29cd2eb5f2360601949055eeef2eda8f217bef34de9ce83451ca73b6caf44b736fabcf2c3b3569a23e69f212c6e8966a3759750b94d24ef2512b8114627ea377b3275875eca2ce3cb4e009363195b7d0831076626a7b010b3cecc4d477e30220f888a953d59a13030e919c980a6f728cc4d4a8e343484c95556bfc041688a013536790214284c4545ab5c641a6f0e326a65278d0c3196a626abd830c68626af5052700e126a65a794092b3862038e811533124b44127a6665a0cb1424e4cf564810b3631f553b5e6bcb8998226a6829c165f6c01276687b3f9820b45980d40d440c36f48034d4d4c3da95ae32d7440849d988a52b5e69a015b75793603f85554b5e6eca0879d9a980a0346ca1e84a0849a981dcc6f8b2f906c2949dc9ce634cda9e15ffca4c1c7865372dbd81c86c1e54c935d420c48e6bc1b433127cb4f0069244f0a32f01132b4ce9c93aad7ab463dad3e0b4cd32f7b91ea75bd08774bd7e3294b630ed9e888ebf157a5286de6520d87e8f69f83da4ce5ce030d29e504a6cf1731cddca76def0ddfe3cc7d7de13403998d70b4e69c73e64a6d939fe4ccb52c3ca30ff366203318a4e4ee9b514d93e4a8a649324e31c2a74c2949ea08488ace2808cf98a0803e608f2689609a373759f328c84dd60f2699baba4b5578aa82b7e0f3d139345e562aad52578081c015229c627c36a1132f25949406a9c944f808e49c0b2f2584d7263dd122eb4ffc28a1d40236dc82d4c403d224f98034493eca4ea2fae9956c244f8aa86dccfda2ad502756b0818140b7307c40ac90f5b739ab2cc2806ff0049b98429a24af9c429ac472c736032b1c3bdd542ada6d42f17c5e2bebceb998fcc2ee5c16f26837dee46c5e5e565648a45f14e5e434e6076f6c9a34591a4a3297a3c3c2c833a669c7754d3ad922eb6f2ee746073c70f5c443ce0322815427c34db74e2554f284099d9311c94af5b07aa5dea2d349ba05b6924afe5d1a914664196495a253ed280864db5e344e1b699cf6c2088744312e83d4469450a7510d16190e918c6f1612c5b80cd228c8888a0b3b67cb7a07270bdd8b6e89d148b2ce190599e01458c029eefb2848fdd64fe1ad73ee1b05494972273bc99caa868a846d86847aca66b148b68944a225504de8609ac82df154f6f7eecea8e9188b2615b1e1226cd32d946d4e90c09f70daf8848cde15814bc838068cd38a1bb94811510c1263d1840e915bc233a285d0081769e281de3645951136f2399f8b3cebe122f7c5ccf29b78d9465a42e592385d5a6861861e1701b7623b3144acd396641bcab22454d5215b4a9b4dc88cb879cf72f78aac240fef46ba150908ea43740b5579c0e9e0a828bee421314417c5385320090dd850e2c69350272718418124346043891b57647c8da040121ab0a1c40dd2151941011b3148403c7743e2233ce4c8345d73e2234ca4d6a16e40dc6a52cc7242f0090f323e5b19275d46b790ba25f2890fea542dc39f40218b775d9dd4647cdf7b7ffc77f73ec4fbdf65bc9055ada4ec66f654445374d2da39391bda11093f587eb0fc60f9c192fd6081d60f4a29b590702b8ee507d532c7f2c3ad38961f593896898bba0d7199c66516c9c233e02bbe86442864a2e2d5f4147ca75d99f6fdb83c979fd8677dcfe9a39068cec3d0685c886252cd53ebf3232d0586283bc9e2c287404d1dfc74ab2dd17a59c712cf52ab65b12cb52508a939f9d637ba0846ca484bd1606432226522f8dca3bb65dcd8dda218f7bdf7bae70f961f2c3f587eb0fc6031695018429f8f941f2ba5b41b12d30eac91b2a1e828a69dd0a5168a62da9976604d4781c1f816822de4ce77145d73e79d9bd36e32b0c77bc6ce06c87e3c8f6e240cb66082348f0fbd6452d2504c3b4d82dbb46355d5b403806f5900be4d013cda8dfa27c6e33633d03d02b0ae55b2bf56e918768e2c8c771a31bb85328c3ee512dd3997d14f465a8ae61c0ccd39156a1d907b75cdbd6e62b7ac85dc4b64e35d6d431fd1bdac876828c940f29ecb5eff7c3cf71105d7b82edb51cc40bb73a3e019f1991619098470aebcf08c2078b9a568b32a605437a25ba205e214689715d22f12c5ea155622238ad0b8c7c76e248f15b1c52eadded2a8b3cdebaaaad8f5155fe306c4b672e38b6dd3366dd336f3d166a20e35e93d74abb6b91baa19b96feedc28764e1a060ce0a4653370c22e5dce74cc22e1727c480d2ae16e748b3ccc8e69999439ef6e9a7ea35ba08f2b35c7d3b4d24b4cb6d25f58ad3393929d243ad38d0eae11a8a42d98643dc9d4880000800001011315000030100c07c482e18838d2242da40f1480108ca24c6e5219e86192e49032c6184200c00000008000a0499800d2c3730312345a41b15206bdacb84e2b1f029f9d8e502d16e8f9e56813233a05d7e6f9c8d82ba6c3e017cb304a39141e336b391e3ddd9753d16ac99b135d53d35460e5c9d4d87b49be59f3cf10ed73be8c02e28ca0009158e6ca59f306c35e552500df3a93e1c977f46aa097b1a5348ae8a5e15e4a59949d7195efba0dd2cb502fe35239603ae269b8975ed2594ab2ef2d008884cd6708c21b7349537e83bd1c95ea4ef8508c587121c40d06bda614777b35ece57c29eb573b2c5e39897c65f0be5698e40cf11f4ba729757a4f707b57fe60cc5f42ac8155b70a1bcd4f752e784364612e9dbd2ee8d85b85346723e0c502221ecd1a6545dcc4740916040c75e432cc1fa2a228b470daca363049e2b5eda6fe879a78d3d6a3fbc1f772b2e3fb96440008a3a1e05798919dfc836ec0dbf9099c5f7304ccd142332e09710fbe421ee299b6b2a787e60fe0b62745cd66ded1553cf41f83ead56b0085dc86fccbe95a63f976d03e45f5507290051ea7a0d17d6f510b7137c179850bcf9744392e16f609f4f113e7141b2825be0f6e829c0e67d2815a1fb71f4c3ee57ef1363fec21af9ee9d7a7b6d93a30e144dd6a10435c921a13e479a70816f50b96d948fbfdd0cad29629c63fbb808a064ddbdf5f285252857c0103cf4bee02e3e05b67950c87a2b964cfebb9679fe16ae67807ac185d35eb265023b73ee520530cd95a3631b4bd85714d8561ca9b12607418649635443037306056badf3fc80a1d5e3c3c0078ba0e3d15fd830d039a2fcbbf9e7d065dc1c5f025fbb4045110b3b2e64faf077a995daa30a2f52860410493caf1dcf1a4b24c0f2fd148402567e9d823f9f392cb5db961b7ba388d1db9ca20289d2acb5e88b4ca0a881d2991ae4af7049156f359edf613591c5a28c7bec4d3b288a4d61a952cf63fda3c8104abe4893c2ceb4fc686df7cb84eca5422aee0c8fa1c05d50f2fceab26e40f8b6377951a2cb9e685760ffde5b4acf2fe30e3b506f89273b1dfdb8b2cfc03ce8bca3411943aba21d2045e22d41b7e5aa0722241431ca49a19f0a838fe78f4e4f0bf36fcacb4c416a46d7dfde6f65da9eeda75dceb65207ac21f8f8bfa61fe3b77e0a7493eb84190b88db1c52d340a04e0e25ac283a97f2c1b7da38d628323c35b96800c3baebe1380615ee94a0fc25f33e4b11332a53a01cb821c571da192c18775f599c7ac55dc161352378efe0869e2e10cffa43352cd755a583d4dd4188519a1f0495b647eed4bc186d94c371dfa188a1eb1a270d48c9c74efb4d43c21abfd81c3e981af146730ad2f8cb3bed16782e0f6608bc291bf6e8a58f35953fff4a149032b1aabd3688b405e0e5c3fa4bf3eb96b82f11fdef11189bc4e1331c4feef2b1ef1f467307b6fe095ae9b2755e5699579148032accc1eace3054df08fb56ec6b645ca7969382e45667f8d4372954896f0597ea72e32fe50145e8e18510798543664576976520555ccf44354df9154622a337427fa80c5e87a45350a18341ab2c459d9ddc171639e7d8f68c5d270a4a383210ea2eba3920708022f04a45507e3ce61341110aa9f30bb3707b0574b77bd27ac4c45ebd2c8b61a3a38b619e9b341faf3aaf399c3a9f212d899f9b7e2f534d9add4469b2d4397f9fcc2df99f8d799f5fac7bf69492a66143b80fb9616bd314cba11f48afed0edba3232e68e8d2654e0df4516a7563708b9ebbd10d82c95c8c6fb9498461f3d2788b6c8ad74f0991dece840e90c8ca46a2b7ff8d68d1d677ba7b2a66d72254b86cb1a32085e0569978c770c00683ea85c39c16c55ee0a3515d9205d1235f2e3ba75020a4da072d90618259b4d7a1e890e422efb3347f49c5e8e8239361b2477cd28fdb5f587d166b5266edd8212a32799f223b098268f14b9b7200cb1a85daa48ac8a3a71b9a75bcdd01f440feb3e3782f5ce66033418ff16bac6d312e97451f4747c996334c916b367156090431c4b8c2b2fb195f87f1e6cdc62e9c61122cecea36d525a24918ca0b7343756ba003ed99fafb9fe3cbefef7e92577c8e7a8c85d4733942deaee85588154a31fab1ab585f3c21115af0370eccc6c6fc6e146ebfb2b1f9a5e4737741cf39488af3744a43f4195bd5f81751919f4f66e505253d3e04db13c7ff0d63c163f94ba0517bbb3e38763a508fb4cadb14016e28a617072b3ae29b6a9bccb0f60f24370d93b3a0b6ee37ccbc89e3cafe9d451b4c7e7605930f74fbadc11f612e7d37f5a0db49dce6412738859d31f05f8209661263e7e54025df2030ecee406a058066334f82125c5802d9205d7354af750c9c109bfa4dc64e19751268b37bf527bc1906bfe9bc3d06bf3d8b14bf785554b3e46d68062de684c403f4adb71fe0bd69a27507af91a600a1ec38dccfae80295a8f3bfe4f707e300e7885c37ece307b775ce7f38d6a42e998411f4422ab2b2bd8c39ea86368432b41ef1e6c3b0aa2a6442b76a8afea7ff39ec1c3cb3f81e24c3ee05b46c55850828a1a8e269139d5fcf2d0ee87eadb8cbcaa3e9c67218c33bd048a66c2a3cb318ad97befab4cc05f10ee07f709c54c9f8782aafe31c65ebc5e590c4437cedec9a31d59afcec40f02ccd9f9e29125d747ed2cb669d3d5ba2414e19583b4854aaed797e51e6a543ab7fc63cb80897c30c4961ff42ca5df99d769fb69106937cf32018654bb3d24a3a8e2671fa130fa8d3ea44ee706f2f85d1319f93a5f075510c5d11793b9c88596802c48532cccc51abc5db62f942d97a18f20428fb7dd7fc9b44f85f3e026beae560246c11571579f0cb7da5dece975c8bd20fba98bd6cea45ab3e31a6abf5fd59a4f3fbae4108c0720d99b3e6b399e42d3ac95e2e52eff661b8905a17c150ba6e1f359edc0b2b2ef6e98ce0b7808329e33797f4562ba2cb85f3424afa7a1be43903d96a54700df5880870ccd76b970c9b06ae137ad74e4156fd40b53aae42cf87e9b7b1365d510b5a0b735d151e08ec28ab9c30378235f119eb2437b09e932d4e016ab76908d933da0aec442c204e436a8d48ff3521fa9a2bf3021ca717e0b019ec7fad46b3207bffa64cee6d83064633ebd431ab94adf8b14717dc2086faaf831bb0e6f25c05c811e53d1087f85c97bf250422572a9efe9fae2a2af9b709db20eec9f498f344422a77bb7f2fd0595e966f64609892e1880d675f0a0ba59006d55eb64600bdae4e503ae2a45ca9a196806256def0213130050c4d15e5a8823b9b5bc4509cef0f39c2e74cdfb5a953038f3bff437e456f8119ac619d45af52abfd48fbfc27497c1c2d73feb9c7edba0173ab8e2b47cd9665cda557b0dfacebbc4ea7032f2bf57f69694c91d64d787dfd0991956ee2be1a645e5f0b4b30148b3b01bc406b8551784a18c2efb3dc86af943fa3b40f78e046a6cecf5e0355a4ebfb90fa7b14244316d28f43c3b3ba143123281a61f822a484f79769dcbd1bd6c76e1ac8f4b5d8e2d439528d707f395c1ecc1a7715a6b431a0f6fd89b8aa0285801ac875a99989f3e2e7630c6914e8b082b4233a3636039949dc5c6cb574d3c5847f4590c821897d207a116f7e4f5c14846aa8ff8f186e47bd9a49c3d44c43515eb3f34ddbfa99bf462ed95f17a3496673bd525367fa8b70bf479ebe4b8847c4af3c799001a4304c0eb826607120e46d61bc52f1275161e2cc84fe91f48bb50ee3dee807373d20fa3a6c5a5a4b755fcf8f031d34c5af19905c962426b0f99072ac3fcaffd9b390335e242adac4fe9f60981daa5f3921fb0c8761169d05782e3343b4ab290f4289ea918a6f512f9b020e804f3a64b13b4c64db384924f591d52b773d28ac046a4b81df9d24d3ca3a23cb7499db77b4e339174cbfc628b6b46ece7eda2b026adaae926031f03d30dd64b475fa820c29cebf8f4c75bb0d94a73b0c96f8c40d15247f7491a7be9162c0aade681b0f2675951e43f1e496cca6e8ce236e1eeb535a58fc1075a399e692e36eea60eed8880765871c2b78697a233f7aa17a975df36dcb7c5bab1e905893c32a41dad72b8f09152d65e20bab56584448164c2478015161904c0191d7cced300c98b438b6f5c857c2207e066a3f5fc04fa07aff49c18e77e59248211845faaccea9263f58edfefaa4b511f98d2ac3e502315d39d0d6d67f72ccbca371c88e5f429ca63ec39548e20325d98951df6eae992fa9adc8037347c20c2aecf5dfd0f06a1f653a3fa82e318e7760eef521a67816050212cc15852623b4964d531e1318c4d4411d2468aedea76da63ed7f4a1f7dcd03028917654f9edc46e39a778ebae52991488043cfff9b716e5ae7b0a0218a41fc1d4329bc5f32af06dd2ce15ec3f1c3e6f541139986693891042874d6ad25bf9525e41d2273b1006e84514238141b1074775a74b98abdc71490c0c96f0ce7e8a938a355502dc7c29f206ee7461b7c847a87e4b5b77d77d88d1e0828f312522104725f0f311b662f0c176668966fd7c82d3ac63cb53f82902e16d3a3195e8fe41337e651e58b285ba66ad358dc4ed77a68e2ce34a06b09875abb4be97c3ef01b0e5536b8648f90d6d0081614c4328a988772313eb8ff5612170f15480b0fd826f0723aa141902173dde1128721aa7cf33453a5cfbc6ed941cd8f0b5c5d7410d76ee17a8d5112bd03bef2bb716f59bf27374d171192df29fdc65ae70874c5df4adeb7fa87f625f569c996b84e04faee6c017b8e0d927b7bf127c728aa2a6060755cb5d0e930e4350dc0fc21408da19b7130075f2a5419b86dcebdd1b1382d89b4a943bd46f0640e8d17ab7d0168b277a3d3aaa453fc3aa47c7e31a92de240718a50670e3fb01824386c019a4a04684f448b01de0901da054a557027f3851d17924a53b73edc52ad55493505e017320f83e6e57eb514b2a72cdf470d0e8ee173875194acd0ed91d65770e2172c6312a4cd7d15b20a3eab600bd928077d55aaf086caca49a0dd68a6d5b2d564aa0c38dbdb28815c3402e313f96ac8f40316b28e9d428aad7c7e44807800269b2435f3da5ec446610ae5eb39051838018fb9a7e8ec0a74bb6381171fd99de482c8e8bb5e3edb65d8f157c01e2f2965cd70c164611664a6d01d43afd9b4a1b5469c90645ea739e132281ceb3308508b039ed6e2db4f9e7e97bbd36599010c313f36c18a1bd3518489fe8ae1e28b16e980a8f786260ea37dc95c889fb59f58230482a16d738cd50b009efe79ab0b5fc2212502000e8bad67b3fcdd3926a04ada27444ae69dbc4debeff9758405f25504dc685f2a69b28b6e0050b62e6667c0c114a18acd5e0d830f3493f35ea05fccb27b7cd8332be79d87868df6fe6d6ac5f255f3a69107ccb28143ec2f2213025fb087a74412df4024e4c2fe0901f01148d6d84d96a9d4b03fd8654db33bdb15d77236ebd135b254aa86f529fc3372977d447afaf24377da1134b8a58d8a6a52c69b20f7c2c2182fba4414587e05a7cd21cd26518a018a9f7ea2a78d789abdad06c7b9bcb2a845863b23bf39b82d4ffaf616022fc3ed961f46d62ff0a575f32a915ed9f7705c22b5227ced444d5d1758c7c52f870cb6e65dee78d959aa5aa40d87bb33abf9cbdf601aad9a8336b7e922e0c3dfad325ce257842ccba8f26dab31312ea462abb91594b73595ca7bca129d9958710a7ac3f3fd121a9cb53f69c913c4876fb3f2fe92f17addbe494252198f2fdf09767feb85353ebccb79f67ad39910fc6fbe93e0c7cb73ee5500a3c81db5f208430f95512820f053ac814f2cab2cf7aae262a89db970da58d807d0d5cf5a287cabc1d4b7f3769383c4cddb6a314b69ecc2be9f35d7d305a4bd94b887dfdd121abaa897616f7e5a537461ef11b979c2823349b10db0361c86c0d0ac92ea4489b2ccc7c1522dd42463179151fbeb184ad8263283acebecc87c8f58833c1ede47913be93583a57755fd16edc611a4075f16d029b7af9e4af2550022b33236145d0ecd5aaddd409a5097626aad88a2133bf1f3ef6272979fda28c3ceb9a14919e78d9028b79e444bf07b3f615309a7d4cac2406ca7daacb996461a54f06f959d153cc60c25e46d3d09170276baf4b39d37d9a18f092b8c1ab2f99cfe9dae28c4534d36eb1b953354bc992ef2c4b501ad0512c372a0b89d3382340043118f43e502913c247a3cf02982b2ad82d1876d31edcd3fa09f9905b283119a088f0ac4ba4a5b5fe53bfefc108693d132be8234385feebff6ed6bda88ef6d1a4a4710fb9a6798240d3e33f1b385c20a221ecd9edae3e407547d2181987e22587dc4e1f6a8a4d7cef68dcaf04b0b697fd8a1068bbe667c56d10e9141ee5974215e6a08c1083546377ba5f7228f6b5121e54b7862f9af677897cd92ba8de74677a39f26b6cc83a8479e39f644258a1f808fb8ba7aad54dc90eeaaf9cc9213cd13a6c09f443e83c19bc43e82c197443e83c191c331d30524d2bf03efb7937f4afea8216701096a422c5f4cd105e286bf982bfaf0a454f1755f80653392c82371c7ba7c163418f4616ca4fd7c8d2b5e0b8d5cfab4e83d27389b3651acb6766d21b20530166f91033bf316e71779152568b555c6c4a4d0a6aa75c9cd7dcc8bde3a8c09949d0b95c2849b6c13ed9a560c7f62e04456389952d5576bd5e11ed6609a8bd8f3ebf647e19f1fce29182be444f0dec69fcfa249a98338194d9f2d5f14aa70d6df21b9d74d01a3b1e11c71368282949ac53352cd82d2a43dd679e8694edd19b5b1b77940b9c9d0bb321b8ecc01a3768b365d814848465def84783350d6ec3a1073279a687e3a01a63e6933206489a3bfb9ec7326d28dbe684ada197e82d452a984ae58ca7eae62510f0508735743adafe18d4077144cfd6957f9176ff49d8023fcdfc2b28b14cede2c456cb06787f55ec16d74c3876cac91c13bab853545e13781d1fa4130e689905739b0becc649365f083e5cbe9bd255bc3ed4b005b17ff569d6ba7dada8bd8cc6ba005737e80f5df14c4a282d7757648a3b07e40af85c732cf4b3ab5b4a2ee2d5c46c74e06bddb50dfcf5be7de0133dc7e565b21d68e8e23560f59ceed05acec5735a5950adc4ecdfabb0b2b1d1f468aed0427ce672d3e0a5c6ae31c1329ca09e4e4e6b0c50ca2135a1f30e2d5083b96c20d74d77755e20cdb04b62fdc48ae20cd2bf7307ed21f7bdf0e9602ded2cc6899dcf376b526c40e159f60ad2109f435256876f564766bb38ac6dc0446e6fc5cf83e2ff6918286461c95aa67e7dabf5ba979ddfd96338af4e739c29a2be051a7b05991e25049c9c7d155318e9c421fcec1fac42d5f971767e8f6cc39fcbe5b00620136ef80f94511af7751eb228d2e00202856f4d2913df71c2abf2b02cbabaebbe4108a4da91f1ac506d9728768ff47c0a59a735c1afab2b85b4d6ffeb4d96eb6de8349c4848a83ee7a0eeda83c12f9a0e51a6d5955295552e0688c3e5655502162c54bcb685f156777a7f095f5b0ed9a5aba2e4966ec49b6ed9329c7dd1bd33adefc20ebb6d174d9ed86126aca5162e8861ea7f21b43a53cd64c12935286c1a6d3a0edf584b278e91165c2af27c4d5cfe13247cef088fa19ebb9b50ed04c225fddc2bafa4012e7a1e30530cd95ca51d52f6513d54ee1838a5069839b2625d84043f5649f3a6af7d8def5442e3f22a6f41c1d776ce8f259e206ae69d5327c537abd30eb971eb7479f3e754f42b0b31c2710e382856b6af1c9987e3caa24a75a08d8af8799ad2882e0931abde72cd90bf8f0d4eddb138e6ca4c0de55121e1da4eae8bb616ae1ad94dc3a00de1989e995d837d5d67b839b6a0bc13384460bd7c06b0a3eaa00030fa81d8d27b4d2b617068aa1291a557f7750b6e626459caec50c25ba8b9c96f5beecc4a30bd570029621e0bb26f52245b513efc320b1ede1ac634f2ae668b9a175cde54ebbe1209ddffe70ff52d1f9cb14290b645f21799ade1c7a018eebf2e330562a6726949a215d2a532bbf5b918b52ab648cce52337f403998e82438cd2040e92dc85f363d977e8dcf2c958b263bee7dd0fe6b3cd9728c423e79388aa498be4665a7256f2bb8323143ff55532a6e9073900daea1255a6ec75a12a3a072d8bb05b311dfccb10859eda8be5868e18340c3c3846dc6cce73215a131b95602d3c3a1a7fcdd0d9129a8a396657908bff311b4d940e36e603b18eae4733e61430aff35ce431e5000456d0da32073dbd3a5c5b9a402b9a515d99291b1843edc6cc49c9e8e6cd232b8242361dd65002f0941254297863bd19a8cf32e2035559444a3dd0838f8c6585f31eb0f67fd5cc9c0f7bdc0f264bda06ffa52e00c5345309fbc5065e26b3fe190a74f106886807dca3963c0d84da793e31d630c16cdbf49b53495f996dd68e5e5d11f2027b73ae3dc8cdd33b191786b9dd4b84e4471eb4fcae60b347a0ad9ff1ba45e3e02ba8301a445724e772d51e7d5459d2538650ae414561f0a6d1f8e5eaf03ef2bad5ab0d8566e45287f81fcd9fc78c065a27a8a05000224e2dea7515e42cd053402c2fa2ed74762cc48e02b2568f24ac15ab297f4a0f5fbb2580507678b903f571e2315b450626fe4f28795c2143739e7c61a54cdc714a9a82d5f4187ff3154612a522ca7bbcd2649d92723d1141d2ab115ea2f4492ac6210e05100d510c05a18507f983ffa91c8bbd63e898d70e87d5f7f97f90c44a345339f319d56df9611eb4e7e915c893a88af4295817fe6db3c8d33f4c327dacc2c08b8ec1b9cbd3c8ed079cf6388aa815d269dc144770194a4ac0f91a2eeb59ae1caad7033151ce527bc4ac6a28834283ed82dd8fcbcc656121bbcb6e1b5aeb92188ca9adb400ca769b23485c65545ed95a55bb81561d316c1eb9f6cc5315e935defe7ae12dc33fa1495d6c01cd52bfd77c78fc681b67613be429ce6d53116922bc3d0234328b792563a74b2a614fb2421f43f3c5ffa356963199ef295415cbdf9a2811d60e93c105ed23dd070420e4b6e667409a3184532b622d27ac28498080e418835a30b5479b8fb0de499b1fc80e3f42e4b54d0bf3fd1851ec1fe92ead42d50c6ab54e781de310568ed41399df2d478643c5aa11249371596d77a86b31124ac6c944dd0a9145cd2b67ec0cfdf8e3b69a7bfdcc66512ddb7e657df1683888331d44e65ab17fddafaf5cfbb3e0362cce8bc66dfbcab67eba0536e88d5a0abdb266d2347b029cfc273afb498cf8954bd3f210acbedaf9a21ebdf72103b52a7b7102504d52dd0d20cf7944082bca52a74ff4b55907c48927b79e1e5f38d70b9de48bf0181ec28ac1b95139a3cd13dc57faaacd3c18eb45598612ae8e36153699b1b528ac8c5665b3e397c84137afbf5b479dc22d6ae84770f1b67c6c3262596178cb709cc26667f1d2caac1608772b6930cd23c3e800e084f019ddbb0d8de12532b1bc08406077a32bc451f22406e59fb055cf7dc0a16861d9dc680db19d93ac1ac0d1c74272821a1a6a53cad80c6c8e223f45b2f1e09ea79bc24b2ba4b56c8a7ea8213e341884445b15c6bfcf7e8166684a94f80b0ebdb59dae8faa5222aa6812877da3c7f4790375901c5ed0d1b152f42422e581ee58ca20c0ffddcb60c7b3795d5c989e6c647983237cddfca4fbd6f5c94fe79ac2633d15c057018713766cc4e3dc64048fe79894a30b3c0221f92d95477994c32ab724a9e1c66fa68e73433a2a89e1d08c712d56da68ff1512b5e5a36dd0c2414dbb39750751c7ab3b59902dfdde7664544d0fdb8d02d002d4917b4c39a0ff0301b600f2e0d501ec6111a7be9a7ec61bfbd5af0b8a9e9e28ac8c3d508d174a21b74f80f24708a9ce52aa104caa2e4fa38827c09908589d607e2928d8716b9675f6ff2efa00eeb1ce04719a4e7d834dd37edc8709f84aecdfe374250a82d3b488273a633f390a38a0c51f1e7d5d515b04d8095d866b8ef06e96691cd690a6825ae92dcfdda05cd5354d49f2a01c6ea20e0f28dd50b4c118fb1cf2957e00608d7ea0839ba8c27fef304fb29f36ca40695c98defae48e8ae7467566a2233fab24ad5df834bae363d6bce1b4639b3abe7e984a9a687dcc63a7987ac4d0506a516f41b2cd84bbe7c66d942f650e936242f191d79ba72cab6c7e970524c73d63ee116fad4d8b1f8658c3c48871bbbaec31d1e4059be678d3f4c8b40ef9d0e3e17776068636b7a39dbec899ced2a8773a28e91210b236b4f2be6c5368a730c016eb8cf649561b694aa72bf5f58ae1c63c798027938e3dab525819e7f44c609e1c5fe0a32f6069ce9982c973e5224f921f25388760d4ca0d8ce0386266351ca0e3c4222db7e72ea55638ad22c74a57d53ce6ba3a5f5e1a46005932785d0851ea1a6f1e537d145eaa609d0ca03530981532fd0a04a6b4309b85281156c6e700e536682fb7daa26e40533394de5fb501527aa918671ce1e3a1227b975064bf41ee59a31bcdbc37082012d470e5ebf79d9586f6a2274acf5bf8b24ce15e78395740a66f87024500d82048beeb7e720f354cbcf8941be0cc2c609d510e0ad3157120ca590ebaa437218e8dc088c4a431911caf014226ed4ee2ae1836329a9c0905cf736a96e72532009a9e612dea2f3a501a9c2064d6e1ed02464a7382bea98ad208a8193a2360aa30fadb820fc416fcff7f4782dca64ce1ea177968d1c20d0276ee573dd98f8e2528b313efb26a0c05f7df49b4229ce9dca97766166abbc567ca1ff8c73a75c54dcc3f231ca8eb99049fedb3a21a9d00ca4dc0fac401105520cf6c3364a5e223e46f7343e8e27f8f8016607185a54d8e957af3a3732c018026fb0522dbd01913cef0f0c9cd6e0a53fb63e2417420d97210f664d205e212860b38e7c8d58a8bda31226d781812307822ed8546bdb7870333d9c2383a7d624b704f3ebac798e364dd5cfed960d770fd34088628fef15362ed32bfe6dbf53d62052300c9ab35b1d73fd6aa19888d212f6aa1012eef5624e31c69c387c6be3154fe218c5903586961eeaa296f170b295e23317a1503d4adfcf20348f2317c32469765476976644e05e2a9b63be363aeda872c73205c90b7a8d312dd8fa2439ad0c4c04c77239dfbbb5fa6f311327c6d241dbbd428bc707c72e41f77ad2907c2351fd02f47029f6eba31e737d182f8f46fee73aa2f7db0e6d130745d3dcc2576e6c8bd9c37eff853a285e36d41ec7dc7f7964311f80cebcb5266db0a48a9bf2e7632aecdc86e6a04124e890d03647c9b029fb3cf4a5fcffd2e4fd379a34bcc5e2cc52f392ea8a7620acd8f4c548ed52e5d9bbf4ab4794117c60c38a30022fe932861f62a3cc432d0cea07f8c5e2524a84d37a232e870a81cc3522f29df0b94de6c83547a34f7182069419fcc6e8c5b0718dba8d8e1eecba729f4b29b58d198854d8db401cfea8905fb30883efab5863cd17430d61c3807cf4e03cd75f5cc39705436e1139a0509401349ef7e2a3560a585d8e0fde8733fc16dd98163e834cf2b4e34f151dad2f09e25fcff4439469ae678e730f2c6402762e4d184804b07c88d7df017e47957423064aef54ce6a30d2577917cca79c116997f237c82e34c1c91f152cb25e6cd8dc38fed27922ef985ac604065c5ae5bd2dbbb0513ae2b6c80f001d71ab882d24e294f55abd4b4c4fd31c8960b97cf4226d1531baa897cc01584aabbb7a85c5ec55703922db3fdd7f5dae9480501d8b66ddf6c81bb8e81be69387c1c85d61221685b82db91822d8e8532b2c77bb4bad02760bca09a9ea341e8699b22c8d1986bf1813ee90c1029613c5bc3462e42a47102a7ebe14f4100c7815f4aa70290e683a88d9f4c1040ce706487ffdfa86210373d926256ccb3cc506d44b9bfaf77d0a81ec20f87c744691588ee7ef1c42f3bd44c755d4661369b6c45f7c2cf8812bca8e69aa0d7d3f817efe793e07bf904109af190f093bfffeaba66b6f0f3b51867ed1af86f649b7eec5fd7861e1acb9660b422d91bdad796afeb441837f9d7182c8b670c4b546031591220706ca905003592156d8afa63f8c1dc1fac676ba257bd55bd3212643bb95a1162f9143c9c436be3701ab6d8bc496e0fbb9dc94828c5885e8d045aeb3884cd08a1ef822224387d02a8960d33eb872668ff53e340d99ba243ebf8db5726dfa52f3b9521d1451daeaa2cef858c1a27b5c092c2f22ef74091d58ec1ffa1968b316d5b597cf909e5a5c9b1d9eab2aaae491ad87cbeabbabe42eeaef7a48a3762abe8f13d63867405ae6ff25d6f6ef0dd729be01391a8b52f16cdacd4a5d24e9f798a5db48eae76435583b5d7e44bee70b68eaa78631fb0cdf66e21e510721bf7918d8b85c944c4746b6b4688cda0da913201f1302df90623809ec4d2e64fd50d71124f4a04e420da47b44a02ed2e1d723c0f9c7a960426cbe15662b15219f88ef463b5359f0394580d1ad666442bcc4c69d3fad2939eae3bd6ec245157118d53c6c845caac80d328412355e1c33bb8f66e4b7dfb549773cb76a260f36505222af4d58cb58b3ac47295096a29d644526b538c819a148cf6464c5d3d54e2209e5b4b688f62a8fb3a0b3922e1d3b945a5eedb3369d76d731f536107d0402f9d5f60d11ae067bd0a6df04ed9f8f8d216cd290a7b23f43e2d6524f4d17e94f7bedf803c2497fa202ddfd76b2271e9ef3b791ba4a014330465f6d9be68b70560a3c4a5c7a19d45f8c2782d61a5cdfd738eb4fa202ef37737d0c1ec1ac51afbe203940c978aba6dec1832918074ac7289bec5573ab937697f42af6cf25065fc532d983f61034dcdc45b5543cf1345f472090e212ba49f2e82ffc54f442d2629f02eef88b44c48bf18702dd69fbc61621fea404615f888584f6f007afda443d564245029d55c8ec31f9409fad5a27c2c54e8666bf571209f3f532becabe16b7ca0fb34f48ef9c36ab7d5ca3a1ef4eb5abdbf41da1351d1b39b7d3f16807995a501eda3bf6b110a5bec5739615df0078663d3e53a73efec50a1519f015b315be005f9ae2474be305a4bb1d2eef89c83c4280d5b7aa87eff4c36459684c37a1bd4a66659a5da343dd9cd9dda9507b917c3b11ed9c4411d299675e9b27134570a92b9b68ebac8c3fa0f8f166dc68193da21f3780464fd6267b634982ca6da1513fe03021b4c6eb1237235489af974a600430d3706a45c3b0e34199961d209e5442c85ac62802b516d9734571ac34c5d6afc40db8a7b88f156c329647d4d0ea01ad1d4b166cdbc04fb8de59e43e4f25577c05b6fbd28cefcaef16dab5645fe08ac572f7068ad2359fc9c3bb51886b640782344e7921bad8f9922001cf0a751fe15f7caa441948b870e2ce9fd6d6c803ff7892bffabb0c0f48854287916cbb0ae71890aceb0d73cf0b1a03af6ce96363e9ec46959a53869cb954d2fc5d068a90359cfd7fdc86c278b1d574657e0ca4685661fa81d58744301358e60c3a228626c4ac8894569892d2a8f1c71cde57a94b2a8a88cb9a2c06822539e1aad35d062096f816e3384b92b5f5433af902a2bfd7f97b02c7733c8f8f8af1e5f8d773326fc20d775ce34e9047c4915a725607157aff08f514d1184ce6928abb6b0d39fb6b569d1391fb68c83ecab34a7ebb76438db59d2ff6e567a48af888f60c27b70c4067b20f75bc7a07b5cbd1655a768de92ee5b2f5476bdd815a9736158c7c757bf4618d1d18d2efc32fda7f3d083354ccef84b7a4d1c457e9c5e9ff01fc0c2e7cab690277c5cc5e72d4ba03bae321472a89d2c54ae3cda7195a51b6168718c23ee689d4cef1d765eae266bf5426386a6af8486e9ed0b79bd66577de2b69bcf3a6b7ba12fd672773a6b6986d7fed0724e3862ce34c2ff2239903a2498ebe2e652b172a2e8a6314608ab7d5ea9137fa3223efbe7c04a4f23f0cd36a6f0529952c25951c458a83ba0b9de9f4b178258286bca029108e013362bf2312ecaa5b12a5a5c3b6a1f1f774d3dd4e54072f2f65d0e5945ff792e05173e191624b230da7a20aaaa514f8e0df5c213766980d38ed5102568916a877417dd5041c950fc5c88ee898473a10a0a342f74fa4e832326caa2a8f16a200dabd671098a36a9091d5f269ea23c23cd26702cfeab76dd86335730682f54d146dfde1c2ae92cd4863e4301edc51afa9e8d7190e5fbca1580053e714542b7248f632153d4954d3aa1c597c923b4252aa841bc45d124dc4c8d54bb48e89f3d48c649d31a1a988146fa72f4cbd7253f081336d624b14fc2b62b9cde8696bf36d480e1cf62a30424946c06aa51d93d0953aaaf543db15766020e4888014e6aed9eb87084cf80596cd3aeaaa910baf60ff55cb086c1a1a5ee91961627cc45889c3990fa842c6c08c76dcb2b9115bf0dd4c34f420ef6d927f971df43817d7dfaa2a75679756ab9a990e22f7054d1915b6ace483c12ae09b4e09964cb7724e92c928c988ceb063b1c6da6ca599e3aa1c064a6f00d6c3f39d6837e5b787400ed8fae4067552115681e3ed505d4c7fec01b0cc4aac186c962d010ba1a5c972e7c57430a228a4487497f6759152bcac87570e4644657bb559898d272fb04c9cd314c8700ad6c4917290cb58d34ba989896b5164291dba324f5af2339d7d9b825f4748446e6680f0db4e3a7d83f3175ee6a077c94801272c3452e7c679b2bc9e28a87560ed884f349675409aec70d5c53fec3f980bba6dc8e681d8d05b8c42ccae51a204e7b7cd8cf38542abe43fcd733cbc172a0473edf11aebf7be106b8c0f9e5bf52f14ff80f83a164a677c2cfb016ac30ae28eb4fc8a7a5b2401a50ac882b223f300e0b22f5fed4d99b887805e581814265d7e730bf1e57f41d3865bf842b4ae80632e004b1b8a21bde42c776efe64be3ac68d5aa043283e1390b21aa759d57d89e817e7454f95ed76bebbad9426114963eb162c92344b3041bf729bdbdcacac07e714d16b775d8839cb432bd9541e6873ee7236e47ee27bf6dd0c43cd01b40703b0b03bb243323aa34df40d213a0c3fa8caf5fbb6d3d04bec6e5ed2f1b2754e5be961b5e98c658fdea053561f7358a5367fc9f73f93161d0d49807b20100dca7da6ddde64a9e0f15e92b523f687a8745b8f11ece51d37dbd11a094008ef235c8326c7bf09e262759ce755f7936878ed6b82fa57367a53e243977509a0602b59b14786bd0f2ee2b1c909cd7bbf1f597e9fd55a8d5b6d87f07b8602006c55dc2cb3c3c03c1ada255117dadf5064f43401ece3c8c2eb69684aaf34914793ee5dbe7bf3a5875349daa6264b55f9e3f88ccfe567b68d3220942e3e3d54327fbc9329de1bde43c4f4fda2f5045f51ae7528ea79fc7be871c32a01da368e929bf31b7756ca174b7203fffbdc1cc0fa5eb7ff71f066530c5b8154af1960e66db0514d0cc0734bc5e7ff0d94ce19b97f4441d793e9eb496f480c4b29d7d2e4efb862c5ef4d877e6795e77cc39e6314a42e160ef51d3f16e90f75a9648c8a4e075135e78eb9de38db2fbff5cd203ffd4ae2304fd3777117fd4154d618579dfd2955f5c88beae3f5c26b892f6bdfd811c974c7210b4dc83260a5d4fea4566b5d6371b1fc2fea5a15c801a16fdf275e17014ba65113c77d79f7ca0ec170507da136006220a24dbc23949bd644c8a1b7d26fd40c507a0a328d8454b55596046ed3305bfc22f81ed4bc3cd88fe8b0c00265f7d2d83979bba4f33be987f2af6e6d2201521a06d3e805e1c7147237b309d9eb7ac0e9e93f0b833146d6798f3c8f2c5ec742b43a2413de78b9051f8aa22b1608f247d979663670a3e2ca54d187ece2734413d79c79e2e74bdaa9dfedfe2b9304bf46d5d3830a99edb9f9ef76a086cb06816d66abbe79bf711dff5bdb72d2fd4dd7dc2de0fe88b06dcbfb614d035904d50cc3ad799f7ddde0a75c7e081c8165c29b608d816840a5ff49e66aeb68a6f482b429358a8e00ead8364a78a441074e3183a9da92466674210cf93093c7ae62a175530abe7337c0cc21b152b199ff471071dbc1fe31d150089ff7338206fd9954711fcdfaeffdb37242fa757fbb192430e1559069b8f39dcab3945eb75b5cafc46c88fdb865366efe5fa516581bdf7301817f3f55e68c47ffa60a4ab336aa57e114bfb83d2e6fbddc5a1d9dc9e67f16a2fa66886cfb6a1b5ebb5ae8abd8a1e6824b08b3a98f9e9f8f2c2c20c8264f0a24334cf3380909082e4e9df7df4f387f4137cad1aefa28da7f78bcfe3964005225450bc522464aa646cb295ec863c1b06645cf590de5b344612639d96b73c30250e6ad691eb214b07b5859f253456c9fe757bc9f38b6d63a7d5341774dffc1d004359e88987ece05989ee9ec2b33dbd732a7ad35a267fecec16de07d321e16241ded0ba67d34b99a11bcafc577cb49ecc3d241f57eff58ee8059e57afeecfd766232a2c18cb06cf22d5323ad3708c77bc7fcabaeaf94a2ab3ef4f58d7626dd513931f69379479b74f081543ffbed38db4a61bca6c9c1cab30e5e6c07833f8067b3c92e216c23318d7cf677662da646b1ec91e9459d7367c03a59ca7f5abf317cdb67840fbb78ae39ea6920d49aa93449568a431686c9c8028ce29489ef977c7b90fd78fc58f09b7403f4c0430075998a41b7aa7d18dd335c3ca0a47d74f109bb9524aab6a57cc019ccc563bdbdc5d00ca097cda449f2e92f0459271939484aee83fd1d51f6a7519fc03945818aaf835a1ab726faed994b6b223a8341ef1d09085513872a2055b86d2eb9d20e986cc9a2724309838967271942bc78c68c6fcdb55953fd9da2e6c97d3791d3c1942967fd82424b6f3fd4a8db88c4f948f385fcc69934d1a195091a518b0c7e8fb35c60ced3fcc545edc9929c1a8ca165f59cfffd509ca85ee81d6aa3ecfda056b69b9defd0a19795dfd83c0498831763c29c8316912a55e45495cfd1d2118a2b6efc117b744ee1f29711a1c754660e570429c1829a5f8869344634a9d6b05b6c9644b61aa8e94985ea5ef59ef5a67b54f60a4c450b850a1b22391df37626ba5c8e2c0f2e9ffa14055513b47266fcbc83b94153b366864662646f9068d32575fdd73bf699ae90a7b20723672180492b2ea3525861ca0e6014cf98a8c9040a470aece911cf3192737d042ec851c9665b7f8bcd830040162c594b354234f1a1604ddf8c3105712f4703310f4bf5efed90af739c85e4bb8f55328f4cef5f9fc3bd2c11b6a751bdc96705af171f228c473e2bed244103ebc02682c633b3188389cf8b8896f0c847b2e3e460dc3aa4ca80f52812517fd9375231178dc73c78a44ba8873b038d030154c9faaecebd50f1da10f1eb7f69729554025e88dfe9c1cbd137ca9e1ea4aba164863ae4b34dce136292abb78c072ad94a57dc5beed0dd8d6401f7b527722b7175316165f47b75c0b072f16ccd768e90c8c45278e3a91000192abcffb4d21e8189852f8a3f949282b618cb34ad5253d7342799692c3daa5ad070bc006508fe1af4b74ae7bdeb856141f93e514cabc3c834c5ca1b8755e0b7d5ce1c6ad6b07df4c2a0e8982fe91c5c2a67643c3c3dd2549a573bc14c6b22f87631dc01d4d3a049bb68de86f5a04339d5a7c9b8ccd68c7013629a2f850cecfeecdda5f4ea36449785c0c2a5bf95b437e873a5ee7fe6eba6436eca1ae50c1b03f47d49325d2dc40efe8592cddb7b3e1b45e3026aed7aaf5e48da524b0ecc9ae23bdaf29edb767f5a26a331bbff04ddb492f8a64e2a83836d9ce136910aa436c85b94161d95e43e1658323f45ee2229960d7e7dbcdb3c42ca206850f93c62a62295a7c638900b107c37de0811c8840042eb0a412ebf9ddcd37589a3303a31c373e45d79aea6dc1f39aa54dea88066f3fc6dd96fdbfb359b780441d6cc55042f562ca2bfae51fc854271595351e4b8f33ff5676e362a6125ae6948933698b9b1a720353fa6efb4b1b62b3edf9da12240a9a401b47de63744d0c05f070c83f0246c98b92ba58facce6bdc873f1e23817988da1232887cb26115f65fdf03f32a551faae98d1beb2bcff64390b57d82b671887820715b043cf87728889ea8040e0cbc17f8e1f03d6c2eac5d8c1de7ef8d98e645d383be6c835f03bb300d58f102d629c47a85f8777999ce2c34da9fbeefd3659993b93fca6d8013323d4b37ef0934e7a53bed3251e78b36af1fc4d48fe3b09f6747c1cb5d60336e998aa2fc593a0a9041593b79d419f394d8eaeb4cc6981c2c7d80660134120b7091decfa710bc3ba99cb92b8f0a090e39aedfbdfd6ddef42ac24c5027b50a1c4a8c2720a8e51ef90518832ed4de913b6375c3306b80a7c065e1844f8faecb5ea5f55ff1e08977741f0e9e2fde7be3c0108e5afa93a3c70ad72163d4ea97027c3ff2aea2f120837f41f616b48473b79df8cdd0eb8892adc2f1b17f37980e326e1ddd21085693bde25b9a3ddedc0c0551af368b0b88f98893468708738500c1b15f5ace015796b38cba948e7f533bf719c3ae414f95c39a3841e5430f93524c3e38f2996fbe93ade8dee9fefe89b8e1e2576d135137f33e5d669ee9a56b9c61e05e97e61da3db18ae7bdf239fa96c8b4e114b97f02f430d02f87ff370f51fb3890ce9ffc9a58242d990a93e9584d2e98e2d9a473ea70b91fe43818552c6c2cc5c1a2b02ea354b27cf2f990ab36b0da8b51076e7c3b1639c7e81852c255b705b96df329941dc49ab8fd475f2549125ed27d70f306edd9a4eff8b79109506d9ba3709bea94fd03fa4b7924dfe3399aa09bc7342eae1109cbb5bbe4002ce11e2b38fad73f2abc6c86a7c521a1ee8cea929789d39ef76624e300ccbf422325fe99b69efb38c3fd420881c02eb3e4d43d3ccd6814721fbfdcd914a02f2de106320e7ada640e9668a54b5e32480f1a9da13411272aafcf202d6f3c96578c111cd4acc894319b27b94ae244d70ac21740f12432251071ffde208ba19e4986e01066f70ea7f67d8c8cc78c34f0378884362379fd124ce5d979152fc22b2cf4aa630d5bec3020204574dc975f7a1df3fbd243b0e934c6e535231434304ac4a291f5a2f4e725b0648b40ba8d9843cbd87c4f471980dcd35b18bf4e09c9e21852be7de289303183e7575f38444f058ecc4cc6a491cbb3bc0c2b875da9c8c05d66ddb09e4c2d8b5cf6efb1dd3dfef0768ebed33a9c4bc832b2239d0f10062cda84041b8882da16a23d1237cd4f70288638cd85330e97aaa90800b84f05eda706f012cc442f3dc3beaf8088b1f3145ab54c3f9a9558b23bd2f1ea4883bb64e8ee5f38cd25f566ff570988b7fedcf25c69701b1f48c7d96c2518754996f0fee2ea6f9971363fcf3cb7378add722801b5fb731e0a197e04203720dff274eb5ae75a8b91be936d5c2e0d1d78acc6c16dca9174097a85ec3108a03f1034f1aa45e0022651d678d0cd18a04a84d43d068ee2566f452325662d274c2e67900a85ecc0476f1f052f9fb2913a393f3f2c0a6118939084c9b9936134881acf77de67f3cc4b41210d4c984aaa7c0b5384c8ed97d9e61be5ad2df0e889c072f84ce64a5b875e32a7ee0403d843dd2f56613555f9919d3078cbad61f059770655b5644dfe3c05bbaab56b21c2a20bd15dc85fa56e6517bd343097f6bef4bf8e710adeeef020051eeeba7c10983d8e82d474774b052cc0484504a1a831a1a9888c3f7128251b95363f4b4c07d5a7e89ee555e1bf2b1c4e9c9b030715e849369e8c3956d9c654779ac06f07c1ec3879fc76a401a7f8aead108521dea63a252fc0a453387c2b2e8a5d9c267c538ace8fb66dfa9b21c6dcfce0f9cad69f2f56c2e15c35ada0937078fa86d689bf132f599c3ca34e4256875ce3745cc8bc7434581f9e66683e999369f5c75930980e367d99dc0340184c6771f4d0e5a3f9c7fa2d382716d2298c3e6029208c50b3e73b32dd4a0af8dc71ae9e85fa03c8ec81c56cf369eeb60faf7f9c04f8a053511dc943332018372729fd368840b925e73777a7f177018ae09ca095ac19eb84cc52153fb4a61384cc11059f62a2728a827c5ce390b280cce72ced14df6eb3bf2edd9892b42a384dab92a9e47f84ada74a2588d73a0e0d645885a81a08881bc6da7b89c48a16f042e18b07c12069ac97be7bd49740a5e61e918843d7ccdb41b41073670b798a61e7ec5126b60bf443b768dec77cea7f0ee89f921f4e20807f58037d0a9bacda27c10c385889bac0a0838a6ee245f69be64b956a368963d4ee034bae244579a5023b7f34a1c9eb63416204ea38a52d240a0d89d6e9ecfe38661209181a88109daf73e3e0d1107921c9f235e0c34f12db0134e090bb0b7c3f579e3e05caf931f31d3ce2b905ecb39131737f3facf5b26f4fe7e6b8c04c84a014864cac690f9189fcfd25db6f85b133717b483263b4d36e59f34b3a3d9103922c5cea5349db183e881c3ba97d0e5091b27a9eea32c62ff8bde0d526c633fd08dfe2a581d9f764ea896c77acdf4e0790d942b9aa8993ddb8e923e2d6f5c4109361aa00579472ddada7bb82390c0b8eb651ff5b1bd2604fdfe5acb6c4767ed8e057c01f34ae6772e8e8b23fab3cfc661474624fe477f4960cfeb884fa353983725b2b2b4e94af1a2c939f8f24ab8ee7ff36adcaf33b46eaeb29427c57c49ee3431a027b635433ee893538a2054db5641063858146a0f7f1ef039f70c0ecff47e31ffc53da337a302aec793ec52a2c510cbd57f2521645fb87a4fde6ec2af2958d13d462747a9a5a86fa9fa0b99fef00f829820fb3a38f2a23c4e38a468be9683ea87429b9abadc38c4427cbeff6b5ce6db791fb633f888a2ce1501360d121a3529f1e5e54070a837c9ca44efdf4667d6a7f2f235001345ca372c6eae26857ebe89973aff7b17edaa29d05af280ef3bc3bcd378f90d5cf7ada6955dc5ea75070af06b4b788d39f9b05668e3413db5eb15073d03f8afbf43871f6e0214f9b525d374b9f72c3bdeb6266c88c5c92779b2a27397014158985ccaa84069a064347df1c1846fac4d170318f5be1e5eb56cc61985bf5243c3885e1cc1449ab69f31c9c261a61dd8a2f0559c7bcf9fad0cb5ec185b3c944aeba2a9dd3b8cd83d838d3ac641599a72c89034ed58d113348ab64adb0d26554cfdd40986c7bf7e1f8ba2db85d7d5d3cdc49ac9e2f989ed13136a3f01a7ae460786347a082a347a9454141c718000c458a4c5febaa45a8ee4bc9eac82f31602a47c8c13d94be9e9cd3e741c71a6e2a90687082ff2ab3fbb5cfb09d95ed954fc2b02dbfe41ea90b06cac6a69dc218ce6c6193eabe4af365c0271ebde7746d47474c385541a698baff630a7e91322a6e425241a5686d6f0a21333fe0a7e87e1dcae29fac9545859b7e91c23ad042df0ffec48b03290a4f78f080e59e3011f13c1325dcb1af514eb19cf4159741b4befe620486377f5f8b0994d19991199a327825d5ffa319f852522c45e21683e32bae8e1304b46964562f0944755d64b45b8e8ada1ae86993fc95d9aa179bef28e74c30e2983628a85a36f4796315f514894bc0fa33971c25bc3fdef25ce4c605d72fce41993991b62f35b74d2c6c9d91c3463a35b3f384a57b6468f05c63e06b711cb34ce621d7e989ed212026c83a9d71d8fe6a211d7205f428ec50ae048e60651cb8b776b75a160b2ec371b34fca664348b5151b1b52a8fcb352f4dd2c264aa13c0f973c62a28d39e031ca875c1f0413cb27369a495baf622b519082946dd111f3256a5a4b316768a9d8da1b9e6606e279436b4db6781f676e2e51f0035944b83b796c4f4150cbd94664161873cfe8a8be4d6443f0aa7e048a08ce2f736e23df47550245c63c91bf0c590b3832c9acab6dae5ee7bf3f210175e4c9461f75c4ab93d425fc63387697c7d70ee5d9a38abbe986a676bed2fe4d2750fec5607418ebd0cd82e36d93108b9a8e55c6ae0fe34dc6bda482e31799fc2b095e332279b7dae068c8af9b01069cc3d1bcd928c1e3c815fe98e4077aefb810e66aa40c471f68375e60f8a496ba81edb5692b8575d7abc8c0b5a955dbe6ed69c7781343a891a59671f48287f466ec02e3bfdf9527290d00b46bdd9f84dbf3b703e55b97b9f72bde3b1dae0f419fa40c0468fb727e090600ed503a0162b711f23daab2d8027c75801e12355686594cb943441b088dce43c582f53177a4f119e97c02e9a3e6155204199c80832fef00b046fafc8b1bf4f56088ee6077f6e73981ad5a235adc22d79ca70b5bb6c3918956e8d27aa39cfa1876680302a58584627516896c36a2666db867f12074276f985ba1267a696603ab7aa25b2920b204c621ae740d77a143b0a95a6d264aacc87014a0610c1e92a695daedc44192b7c893b4c16aacbbb9e12c9c3f3e722d617f70f4a5af6df88003aa8f037645b70c9ad9802e788223153dbc3b115ef5ebc6eb1f2536bc8c9fc190fd565150ef4b2f46b79c4ff7aa256d8943c626631a738fa1eb6e7327a281b7a4bbb53fc340ffd8ab47298b52547a04aaee5d1106c81a9e9fb1b8ffc16d8a40d0bc83650e42485daeccdf108f363a983322a55c7a5133483af8609d56860e1ef5c78fb75e05636a90a3641366dfa081d836a88e440416cef8875504a3c5147ce98cbe05528a1e8e229b611e3bb1a28341e47a196931ae1fbdbba9a92ceca542caf4db7ad4a7dc99a58ab8aa0d24bc1429162bccdeb9cb30530b9e5cd3ad4d1618cb29fe3ac0726c71ffd4b19cbf61e1c8e3d0867340e6ba57340502207589c7dc237a0409bf1b1fc6520b372e4e6965bd5def18342a8e8c907d2abffe08e5860ba01de9a2edfed52cf2432975a3eff07bf3679b34e872138993a4e5310a2b1fe5bd48bdcc481a8bb4143389bd73a7e7816290b33b9b609301ea29380fe44ce498a671954ee342e55ddaddf8d2cb15c4a3ed82ba5c5165854dac4f7fc82f82c37cd77022438a517fd01628f515e4c872ae25d8af1d07310ae848c36651d834fe4d1fb8f68fdcd2acc2bb2fdc9bead38713e9668b520900f531cdfd272ccbbb1b72e6e677aa66bd538c4f82eb3a1d5d349febd312dc577458ff8d397c3d4883e21c8f6a30cc0918db0f457900cd49523b067973d599de240ec2cc72c0b7ecf83c1ec4e1daeae01773b839fbfa7a38d521d75e18d08799eb645917a6aa95e548e0d19e0fc516b1f962da368b9dc33585f4c6243334d721d31ec8e8066cc924152fb52297aa3099da70d27aea79f482559c47d273d07673e0be0178d90800bd57e979095688ce5380d063713cbdbcc91afd044aa169e49483034fa0b83effb162071b9575b18da5aa792310210cacd5f06b5431d8392813aaeff41b4b52c0d1b8a0fea18b84e0ef542aee8dcb2272744eb6d44849e0a1724120f39c9ce3f5e92ce72f78cd9ded2eb0368dd331e215a619e55ba41ba651779ad324bd55b3eec020df8b3c5bb073854edc765d2cb7b8626506cdec7ceaa61338df51e137d69575a91e9d3f9a3a1bec997cea751080ca195b19483ebe8ed1ecfc2c7af3ac0b33693f105a12def795cfe64f0adaf2c2a8cc04194d6c88351fe077f0d10c8af5cbe57d912203632bdbce89cba418dfe6a2876b287bc5fa8dbb21ea4bc167b19c92973eca612694972d2f9321ab8b50269c3ebef7b3310204942ab828a2087744b445c042eb69383b451454232fca11d333426ee9d234af604529e7899048f6a2490ed8a78faae832d20ce3f3b31cd1c08eb816c8654822aa6a7e53bae05db4ce2894667a07189ece585c684b0d66ea7f3ee24a565012eb132af3686c9cd777fc9deae96c5347e292e239509e9a0943ee7e2a677d0bede172fa9ecc2f940e8038c7e04583c1887021f6a8910b9bd40bc557f6c729dc6df6b170075f0e2df1a62225ee0ea55fcad3aefe7c68a56f73408fc718f0d5a28aa3ddb8252e50fbd6986788d8015e365dedb90db8873317fc472f6530aac84d869974a0cc69be77959a3529836ab2cd5ad13be0b7b99949ccdbc320cc3b07df37f784c5e57f4a1fe5f38e3758cde0743e07c7e419d97a26c9f2d0503eb98aba575e723ab0c22f97c7320c950f9f2ca8af1208814f391d1beb29463fa68e3e5fbfd035b745477ec012c51cc8269d638689392a2ba7e658bc84c5bc8d0a0841843e79795bd323fbf68259b0fdda0c5c952736c6f6ac133f5ae4d5472c9e3893ff81473ba53904506a34640e3f6b5cf32719923eb8200607aacbb821d97fc6bc2abe0956773d1f6c6713ae40cc0a806360e838d5bd9d515ad6424a6ff3fd04618fe36bbe06ff8ea461fa7589abaff81ee8d4507eb1abbaeb771043d2989acebad62c6be310eba069e57f0269b5dae895e26498b4b14bae39fab4625f31739611f7b6024a43316c223fb158db6b13b87b21166b7d5e6f7606c61a433d7d64a173c696a39ee79f5b3b777e20ee67e9f01fd73e2ce587bf0f6d52c77e4ec22b69481134d07dbd952217d3e835dd220d595cfa7c24768dd74c8a79e63391d055e1aa9e8ef04d0291fc594d8cbaa596df39fceb4bed1ea6a474f4550e15e377f9c21a6eb31a97c682377ecaa5882fee86de1b854dca73b0d9233923796d3364fc3c743ff62d94201cf0f30c5cd2370a7454d73489db1c13c76c5c0ba8d18984cc1515e005d13aa83f23a670fb62650a576f4c9c298357085dd8d321660a689aaef300024440ed6206be6c034dd1b63f2bfd5e192e592d1793308e2d64096bc57736e9b4433424fcea1120f7b0f90cc1c30d507e6215a81913301e22eb1cea93af7fee4621a287a00c2588208ec024d5196ad82f34a8317457292fda110b7fa235a7525e758365f56738fd180d5e1b48a784203e0554f30521a834e837f2bbf44a7db6b275be2e2d185d9dc7ed7cde7478ea523ec1b987edacea7de36a9728a8642729adaa35c093f22ea7aee4427e7afaefdbc27487d06fb836ca7c7944ee6d0041cfbfc9634ab6e2ade2c13a823cf00d603569a3d0c8d8b251688860e9e225e300ee3b5699d0fc69afd6e6a95292304ac4152311359429853824dc5703824eb29309d5781aba626ed73337dbe189629248a99f28482f4157be885429c89292ba5ab7b718c098b47bbd57928c8c0a1261602ea3e866d3113354b00127b2d4d123dba66bbc728f7902440a3d89e9c4a0ce39b2aadf6df50dca410d5ef42e3c19fba01650c2b1c3be5c5ada3aacaa78f06c4f06d6b4bb887818dba24ef35e48df618b74d70cd5f32216b07d68eb88c621a148fca0df027b9234fd6a8dfdd5c31ad44d622353730af211761c518058c379ee52fe5e48250e885ae5d70175d768f9b13e40e4067bd75632c2ac3dded4587d9575b98bca7506061b4d270827ac7fd859cb75b3ace21890ba35a4d0a69e4738beb255d10192f64bc13ca2042393fba8398b28c59ef80245036699da8fb95228e29f682fa549c4637b8f2276250e923faa944e10f947d7a4a821be89943fb9f1911fdc38b430a3f3077a4bbf5a8617e34f2299886a9441466cb2af85765f404c837861ddacaca14c32e31e5e5bdcaefa9186fd774bba26863fb2b8becf7253ab7ba019541520c81b154fc9fadbda940f61cf42169cb27ce500d9f0edb6f3dd8217e0af71b662e4426d2b3b0d7f37e935a94d17b8a4186ed544d6879ed22edabf946bc3a5f4535807f7670c007d52bd4f466468d947138ed1a847187adeec84108a1ece2b01e184840a2a24b07fe60cb0de83dc76a4cf99e3f4fa5b4a34b340fe9312bf305363bb8d97ed4973302585c773d97e4374d0e0d5fbf208d716a77d44d31497f5e80893fc2d044d48f91821264968f2d9f6f19a2a3be8421f4acaf6459b455e5d76610e443ca66f9fcc659b4304133d5414a8bb875452984ebbc5e703328864bea78478a5ed3897a296b0037d90d151db3f79c19c64f14adfe8539a5463e2548236085075002cfdc6a543719dcab52f9c71a67015aa0a0a295e5838965a109e79b2975158e2567c0cfd11e51fa9d3ae9aadf2e1f9bfc76a0d4968ae2ca1a2f90fcea9689578b8db443086fc17ac09e411eb0c25aca4ea9c58fbe81ae7c62763d02026f1c53048fae4135e7c500b5ebee3e599e29a735abcf5e8ae43be4878be066f9c37f96c727c65f7d525ddd273555e0abdaad4a84dde0f3c27ef099b872421b1dd1dc53879270dadb699adf06ad37c533aba059963a73dba4ac9517ee9e526a47282ce14e9de4fb2195fcdbafd5cd7be8fc008c198ea2f2c02536cbfa0c7d9a80280ac6fdf6743a28956477bdd874a1ab2ddc4a6b850ae75d5eb9a10a5a891562f62eb6d888b38cfe879a45efce135cf1397d004fc36a1a1809255c85c55140a610900de2a9898dc490df6e01c189d5dcf7338e2851455dbab25d94fe88def9aabef3334ee4a1abef1bd011b49c733da7bf1cb1111038889c82039cacea16ce858002eeed57ab682055cb78a514846c29a8387c863e49e31bc7c0aa4e1b83e52e1e40de5e3eb52fa43d61756022e82b26091c2c5171746ff28b227f119080392384a55764e35f50f1518384cdde3844d90da4b99eb4541679e6d063eebd9b7d75885fa6d73442a94be876ff3c8c45e67a70e9947993a756a445589a46a3e06bad3434a89519f71d3ea63c8694c583420b4d498e899637102b137e0e30f6c2ee779584a9655a31bbfb3838ed5f0184bcc8e1d74282245bf4eeca888ed708ecd35316a74bb29979996000f90a6e2e68d6bc75d689453be5b9d13ee6d87bc647f52fe98c51c1950dbbc015e70be8b4f80bcc82da7d5bd0dd9d29f4726a793bd6735c9e56c7f3b233e490325c5ee23a66441abc2bf3968f4e712f115a154576090055a53250d52f0d16536cedeb34e389112a25b1a0cdd0cde0eb101a37dec22546157704f411a7ed00175555aead7f0da932532adf7e8512a3dd3f5bd911eec74a1a2acf8fc699c43cbe7c54490b88d3ec4f4cfd08759d58c27b380d05f28b6d215afdc7f79a745dbe3553145e300bb017dd2f0a1d8bca99b2a939229c68cae867de88d8a17dc0d26ffd6440fb183516b384fcfdbacf27e2d0e6fd05822c886f872764ede37ac1005405f918b590dcc916089fbdbfe3266f7d0e8c453fb74308a736ca14e46e04e1645ada74309ea90cdf9e45fcc2b6b80fc9e420dc8cb90ab4f4f83655345fee478cd8b020f500be19eaa8ee3e741fadc57a06f81caa08204d5f98356eb94bfe786eec711683f89a047d04a6ea3217566f3f25efc9ffc39362e0dd5e37260139f13dceb699153cb33a16bb246ae99c2cc2ff6223b309ce204384bb946a06ff82c4ecdcf5b5ab0e8cef268af51d8d4b9a1a46565785c5095071e48fafa3875e2c297a01b04b6b8e2bb56a7bde31d60462e1e4e28e4dd360b762b694e17c96ea150339b417c6dc70166bca55cc2639a71105366537b56d93a81d1594215b46fd0d13c12b099813f5a176849660b686f5464995050581da69763eae0871cee2dd0576b62808af46b46120d2d572d049c2cc2cb90cad13860adc57c5160bf3c1265ec28f1741a5631ade49c354cb05fb8bcc2bda74e625c93a4e5a35d52f48de12b4475bd4da1e824207d520942d1a684f4ed9e6ae958faac307fcc16013c9075bdc351d7daab10d728efef4dd1675b94c4d0aab920afcf7b86461da940a8856be0485a6dc2ea3d33e246d8003948d2f0a5d439b7a8727988d3471fe89616c69bdd9ed831eb19ed9a95be1d2d77d6970ced3557cc0ccb5a0def14171f84d2e50cbd4d6c0f36782089041fbe7af430408d1579ee94a443aed3cc782a96dd1e8e6c6460b261026f4d41bba4f93a14a18af6ffe9830f2cfc341330626685c17b10c592e7e4df47027db918bfbfebbbfacccce51177392acc77ff964e1698a88166408d18600a6220f3b47a97665e2d451a2e6a65eefb6826fe9fe88d7585177357aa4cc9e27d7791bd1763f26ca6db1fb0d1b837a3304ab5965ecb647f706d71f6272977bcb7ceb8e2354db9ed5bdde25f2ae531848fd707f8f0ba7adf7f099c7a454dee7f856ea1c31b06d606ff97d6e2454cd366cd78bf04c6f22c8b29e440f9017c2d9181253d76ad9017c0c7c9f233f404c97081e913b8310e937c9eafa57d53b85d07447a81866fb17855c8ab2b8781466df59733d46a4cdb4472d77cc675bd2f074d9dc80d7b06319f14f4462c48cb6ae27dc625ea8f2e8ec99e9fa95c14a7b0619f82a1da97092b2b1527b77aaa7bf222358e4012f0cf65def2a460ce3213e77513c405587614418f68e66e824874803311df3f999ab7f404f03c9230cbb6773e8c8c4cac9ca0c603ad1c453633f902161170f784ba0f3313e311d89620cfd1fe5c73967012b81de8d1860266bc739139895e911f38ad04664f7ced96d4394630d4d28d23e40a6acfad442ef3044ea219504bf1380b1202b044e85027ba2f150b832165e90958ca59940ccd552aa7a092cc85eedf8077c908482494faa30d0da37ba05d8f12d69a0e0d1da25a451dd4720f0d25ac863a3d486be908a1d5a17e35a8aa0c89a0903af060da1efa8ec99c4065d726a22766620feebe9e9e74d7fb2ff917a279ab3e45ba2f5906f8d55d518fc00370f112a370edbf3f8713fae71fb2b2621786c335d14a49f338e75b99d6e514616244ec244a66d9e25dc3794f4b5bb52f92e42a309af3aab04ee66987a8391e746df02c286aa1005ffc7c1371e1cafc120eff56494869567b6502166b0293b089f3066603b042679cf92fffae2ac317fe16bf4b87841b23a1767558bc9ccc70c8d050ec6ddded14b9683fd28a783198366175befd99302c25a4e886b5f2de63122df975a704e1bfbf5b97696f6905cdd1b2b2035814663c59039b23ad60a8788b6816a7891e68bf12f2e299deb4b401d151425bbb06b4005d4f8c6d187399adf053163131fbd744851aa9deb41bf1b199cb9db9051d13350d9f75daf35e52bcd8a79fe505fafc960f09e54f554b3c2c55f68eeee845e9c28506c543c7fdbd95211e55300f1aa41c2f45dfbf337b2167c36313e879aa8ba21ea14e38da60284fb37e68eb58fd5b57a2ac205976344fb91e0bcf15d446bb32d85f4f70dbb6df52428289a5172134c28f8cadebe84984a4a6c82017f34a780611531e3e1a491fea603c54cac59924069ef6cfb800d201266c45eccd40e93adca972449c8a6672337b2c254f6e1e1adb857845b4d3322c6376406da41e0c174a002a13a5f0738123ea8218a1ca670d87f1658d0ac263764c48e23c3065d564619e05a68632052688c552a6f15e77cfc9f0652cd214f9c0044463460fd4b562031d842da2e40f58584614e896d0cedec8a69f4021aab53b942b259b39e8c42ee3782165f4dc43acb1332fc580fa39df89b55ea0f931238a557c5b6d88ec93291ef0eb721ac7d7bb33c74443644606699822e74b32c1de3fdf2530cf44cf1d12cdf76460be0cf8877a50c075648b7303eb9d911e959511b026ef40f213b1cf5f56fb3bdc44b66a49e4d627ce35e7e52704db1a19fac9350fdaf64c6acfde2c9b0633e8ae8b6be2ff36b27ac43cac1cb2515220e5a87738972f325824fd22e6b7f8885c69e3042b7191d61b004364d89ed3ea65a1ae340944628a3e6f90c4aa194bb33730354d7711b16ac8cd7fc94c1b6589b151e3e0d00d25346654c9103b9de31166288828e105e0ee7b56dd7121542ec7c0345e9014309f9e5f86dcf932b7892805d856171551ab8840559f3e7f0d24c63d900163cce1f65a5873bdcc6546902a1957a68bc1407b7e52e90cf120ca87e05d41831339834858ef80db09fac0f7ac672761bc048554d8f1f9d4a03020d27b1af27e3b2b2f981af778ed674edc8165745239177d9613f72d6e5d65875ad5085121fa920b6769a6824485b8a73352f602ebb4ba36c452beb37c52f0f6a8d9fef3778f531d8ca712100bd19d36bf71ba14dcf2c63060af9c3d73e58dd67da15029d97a6cbbc746a84e8600913b1320f4c86dcbf278dde947f9052c4a865af96426c0ab3629ea190de96cddf59552e86e151a200c5ce043535fe10adaee7a537a9cb3ebfeefcd0befee356719664f43f6fce44de17865fa44b430739caea90d49129b841e6b9840faaf7bf319c6b0ae631c28764c719196f3454a2619ff5db129616ccd6ea684491e83e2ecaf26d1a0c00203de21af9cef4509b79961b0c3836889ffaaa7eba7fe8588d691276461612240477e115add24f036438bbfa9d2aea987000cde69bb6a72fb2dadf4aa66ebe3892cd88c34840f1e11f6d92a55d90306dc44d5f2fa5810f5f76c848d2d07ad793b66137a1a9026e338aa0c29d87e1efa095773fc58f4324c506bcad8c3401bffab14a606f67dc5bcebe14af28a5d94c2cc2a112a4ff156a2a901394fed2889d0b1f2474792900dc0ce619cb9fc681d01065484a8e21402476a1cbb48ba9e7ff611d969f839b9259aad21b3cf08f6522a2a72fe6e246a9c41bb2c6a20f28341712ac448b9ff69a352bf0331921932c4be73e90d063f543644a96f76724abb6fc1c6ccb2a141a03b506fcb8ac4cf929ed51c084ef662903b9704100540b55a488356dc7f082e1f0975556658e008b1b15f165c7619778e5c9d8b582468fbedf8b4473b4b4f175aa128ac47f7ed8b81530b81123820f09c5524d56b03ac7826fa3df532f89b110c4fd818382b1dc74dfb5421dc351e03231a3ae21aa500a68583a769dc4c29e6254e13616fbb41c9315f02c13eaece9710cef714357ae4ae8ea14a27adb6332847ac19a906a97fe12f91d367911a4c470d6c7ab1e4778b3d915a93454a7e4e59bedee0e5e5a14dfff5a3cb6208798fe22ae54a128867ac81f9a4f452808111459881a02789f266b838cc1fe7be3ce8569d2d8385fa19449c9884342249dc2d6985199a74dfeded4ba3ad0724308d5bded47e74ddf8cb78c1d4ef631c1fb143cc168d1df724e697bb7da3b8bd3afd3dceaa3cb29d1c2aeaaea024ae9b9f529628010f8afc4130f8e3287688b8d9f2a823af8a18cdb4819bff816ed0fa95048cb5c6ea13fe848b468883c41a09f17e37cd1d018437d1df080f507c0c9822cec49734568e78bdd684bef6b8df10cde6d803aa8e45593e8bec39a1e80127a239975046f1b19c6c6702a0e8070eae103cfbd5515faca38f097102d22b09525c7a8aff0054f77eebf5fce9ba00a226cff44384d256d2cbf646760b0a421ecc25aa96d1647649435ce747df8fe1933272f44139f2d2f37cc721e013015885add011d0208d0795c3607bba3fe1127e3a603539c272d62708d52d2f37d880e3726b0ac55b7406c1aca5038d450eaffcb31c88b71e91104bfe90190e03c50dc485131f160bcf75811115f3f57a3c12c12fbcad9a25685004f81b3e4e422a6101282afc7c3028b86197dd7dea1a61b5cf1575e243dca003a50930cbc517e7d8538606233c32ba37f7d8928aeeb5d7320c237255054409c105c2f75c3c60a36d7cb7a1632b3353cfdab53d43d73773e9c36c5efc847e0a819f2a340fc9e49907797d535e31c8a651ba480af015c98600346e04a2a97aaddcc2aa47af70d8f828b86f11e1cd4712dc4c46edaada701d62dd9924d7bccdef6d304be2a85656e12e175b76a6f353d8f4c6b0a941f2351f619c5e5740e5d9aa1dccf99a2b68c5d50f3ba8d167840e3faaf3b1dc4d0ff979d8e2b090ec916845229d18725b06f597b2f2359fd06593c9057f1e8a8cc475c0e4a3fe745919b721ccca99b888e444423c3a1494559e9345a2a901ed7096db378b5127447a31c518acb7fccb20ea53b613575a3b078b9b5eaf24b045f4ab110d996eeda9ec15d1b7bf89f4d548347849549ef480ef0ce0bf7ccab20411531220a20d3d77d876e105e02cebf2f129e906106912fa1be7f020c99e30d35fcba4a8b5ad342a228531d257ee47b67bc45398437b6826913abd58048399c490e033b07a917075800359e6f8949060e180a35b7d82574152a1e9e7998391f6ddb5b157003f17ad50c40d580ae3fd5a320b30da6a9d5213ecae2fe8215f7d0a26acb85f0c772d5603438a9d0edc7cf420c67bdac978d75ae132a08e518c77315800db2fa4c52871450a2f44eb94d70eb3eba47c7a28e910077db28a2ce404a29a9130c61bdd24cfa06ab6df2d688d7bf5a5a8859098313a4f057165e8dfb73fb9abe802cc8690a9141a6e5dffb2f508720ba006915f471ec2acdce5aaac040438f094b0ac947786e4360e5135cd229fe811520863d45128bccb41413d17d32f97689a1189964a009e0caedd78e264a2341b0481e5ac9414665501bc386e657c79b371a736205b770a67ef25174176893a0c9f2709e14363252a92ec2e10918a8bdda5dd8db433e0241a3cf1062f064b534a8c2668dd5b7dd4b2c1878a9f9c510b55d2c990f819d43e438d8e03c75ad39ddab498ca308bada6d51537826ca755870444b49bda83c51b4edf6283850d3465a46b7a5918f296c0b5040934dd76874f376a83ac3bb74860ba07ac7a00b267edf2638dbb85cf293a281fe73d058af830aef9d87c0170fa790c7bec95eee2595f64471993171aba06dc0180a89a2e29ddb6674d1054186e82d20d4f8164e164b078ed49772b78080cd5b955ae49f7bcdae20e45320a4be59874e7f591a37b46303563e99274777271316c9006d44737d20811ad68ff462d7cab94318d33e936fa4cb07d1a5c3d490c72e7e411e18f0647400decf95bc540b27702313aaa60c21c28c608930ebf40d629b7608a4fdd962fe78017f0fb0bd367ff2b258af13bc4d1e0b7d625c90d0213cfeaa9331ca72a1bc70c910deb150c0f5574d10324b6c5b09156eca40582bec81027ca271e4b21d1af2a4585b337042a3ca8b8cc7da9d808051db1ee8aa1c938894e54e2d9e2563d4a59d467e2a8a357293884617148c947c58a7464ccc57470228e7deef8e70146530069aa49fa23975f9055aa6b735a27ce4bdb0783afa24a4adfa493e1543ce6a567aff2226ff3b6541860ca091171a33b7ca9f4df459e8903ff845a9fa4d87243810d57d7ffada6bb8f24d247cbb36db877df7bda28ead8721b3ddfe147185140a8e9980631625bcfd8e55893d103a32e0adbc6877e28a3aac50bc0e86c65378cd44e0d240f4b78566d92f83eb0992e984cbc4f286aaacca4d6dfae22dfbc0f543425fbc903478dbab3343fdff9a94336f154c06127f43db2c87d3b0aa52e3b20639132b56bf01d871ef98df05966afe3cb60c99d0b4c785c53480e5c6d5bd3ed563525cab0e6ef924a158f2eff7a27323fe8def7763762a41d9b92c8f5eece23cb596efb5683a44bd490cabeed49e87ffac64e245a3e310e50547fa21a2922e67ea2dcbb9df44828a9af319771338945b16816bc0cc70a2d8ebc166d4ede75ed2028af56841e943da9e4d0d5dbc7520bae4c0de828773fb53cfa4ac80d920e1ef9db2216fbe7dfd15777833e24c35e9f8a8d13bf9e11e8427e5d2c791662e4c930a6f22f54e68538cb310bf2f85de14b76f7d2072a4af3fb17c5f4d2184ab904ffaf6353615e06ecf0c4c83efa8fbf4bcc6e40328abaf1403c7885a5dab800f2083f4e7a0d415bcb8101e82050a2f3329c82a3ea96e98888330d5e9dad3926189c03e8cea2f5283ef6a17c8dd2e40c8b328a12981b867596143b095abb6203141e85c623d48a67ca8107ddb7b3278d4aa0d9e2618f7d9edcfebc594d5c8045e8e49668895f1b1f54feb519a6d3d2cccc4e8238bdc354c92db4078995de9c5ce02d49f608516c7c4b4537a2986db55369f12b72b4a5114139829fcbf10f08b777b494fbe7b5fc6c8c11f4758cec291b9905d25ed3863514fc80470f0f82f129bfe88c28fcec4333686526f389f26cea3a525fe887cea7cd5d4a70d44d076711067639138539097b5af5161f67cde416e75ce085285474e485d1d59e2d003bd3c778a78b023c7b1387097dfdbcfd6625f16e435748c521ea2a4f452de0dcc18bde63533bb837fd213265c38f953ff8fdee911abbbfdaef2df8f5de6bd9f76f56fd72f1f2398b9aecac4e32e2f79541ffdef3105fd5b296705b925af93376a68972bd882ee81e3f4ffbf60c1aeca6743664f0ee5133fb38472a6c39f6317835e28ace65e7474e99465bc0c235819ab61ae6445fffd0159f2bf11da187ed9c9cc87fe10b67319fa6bfdf630602860985ad4784a18c9a36ff3f52a61ae28b21c9feb6a81e05085eee3d8c6cb9cf893636e5d1fc44664b55f1005f35b4eb9ec3ab93c4a6c01926c85899d17a437b7c7bd745fa2d36775c80597d43845884747f52720bbd4d9ab2129b120fb5d222908af7c17c68453bef0544646bc9b52492b6d7851837ddb1982d42c6a8a0a735b8a6ad9ee4e346bec0143619dfc1194860ad9861a8d5a477558952781b84481085e6be1765160240e26137f9fc3ab7fa7f745cbd8e9f97561953a9c02f9fc2d6a3c264e2096479106d956a69088c54d11655246cd93e12d4b810c33d930d9524926309874200a913b1c2755119f3461b39fdafd86d726887a8b0218c84cd78b716a55e10ff5764990d0870a58df4a8ac99ce847e9d9b5a61d1eace785f2280f460481a9501aff644c28660c685ed057d65f7465504273d4eaa5b3864439f23b1cad7489e5dff0cd567244eb0e49c23141047e6336dd1046bef4ff17e949168a21df1453a62a2101b179e2fa1acbd5474548fab837d4704d8328ac181b4b37f4e491b9d6c6821578fab7807c8d78642eb09535ddf778dbf7e3c1a8174a7fd3c86f90547da5004f371dc794a1f6cbae88effca0a6dc590d4c3f4b31c245e40e4d401aeb20609b41528bb8af929ba5bc4003972594b65571548e264a9af1f6eeb5c8722654d6d81b4a61aca5af2c42d5db597b8126a1276dc860342662f8228c1a0cd2f13c0709c6b8ec68e46f894ef28c775ee049d4daa253d8c78c2c2f77adaa869f68bf5c2b83826c181ae59b73954f131f4c3651d7ed0bb09d51f5893565574741a1c9e64394510d9c233b5128a06a76382daca3e18b778f8be8b2febfe94ed782f5baf445c41acb8a73a65ea98d8820823beac0a50afd1252a8641fcb8800c2e0694e185069929b9f8366450920591506b440b95ff6d931b818f6c8539c125a3032e493343c194fd5a506e7de9717fe8b43888d657d63bdfcee3bd19c3d021238c803899fa60d24e33b5c8263c434c44336a63a5b11713e9d748be5db1de927c7603757e127e912abd8fd42d3f9b6ddcb4ad2327462d1964cca8bbaa28ebc296a5de7746bdf516e82bf3065dc0c165457d3845258a6d819350495b2d3e3c303961eb8ff2460d9794845e5494f731c49940134a64fd5dd0a92958eb91ca13814d0c4ed78ec0004a581231438b66aa117291228abe2f585ccbf634e63516db435671f803ac3157005de9908284cf932fe373d18a8f0e0277312d5c806b4ab5f665153399fa7e1278f3d5a8eea451ed8c5d7d85fd4da9d70af5762b763caf15a1c0e7dae15779c285ceda55081391b4e35e224862593d219ec2d1835022a713958b709ccebbef3bd89e9d6111c6fe3a2e5c8d04e9485227396fe34fbacc317cb738451562f292a12ae42b106f7cccc1369990b95e5a84dad998e1c953177a40076759502d224128c2b9ea43c984ed1dfc09b6693dc2b4f1b8e399cb3dc1ceac3dbfad642a883023cea85913966618ae1648a35d4f4b292833e63449e42401fde88ccfb66100d462c9cee7ff211da2c09d26e453b499919936ee3493627ad430b2d9667016a6e94a65cc4c46a7d90235cf4a585bd552abcc841925b3b8b30b46e3cb7649c738f38228efd0747e7ebac029992b97c52654b26fd0cccae9e896c936025c1ccb9c4005ad5213ad1afcb13e97a60681bc50c0519bcf70a1c1dd77590a2b86788459a47f16a97909f78dc73770ae5de15a8364bcbc3e35b84a64e5e26d857daf71dbdfb5a55985579027e7a793593e393a33e22aa6959641305eb1227f43937b592886c52abd4eb294dfd22475b98e3a5b431ac678a2bb10f9967a02625250431087e5d13e4333f6c00add16799dd0f2943a1a68b032e7804d4ba4cdca1c2df58d927e122987c62091c633e33f5b133dda892b25ce8bfbfbb7520e77b4b6205a5cb0e79342f928f65420329477b4eb85c1d876368726573bd84d7d16c08351f793f935eb6fcc615d6d4472e7f6285f9d1727c6ef889301f3839c179a7da1159cf1ad7d3d4d576215e8152ec6fba631113dc69c03dcb95e9f8a06ea97f596dc9ce39658803a35eeda7880deda2eca4d81560dc0b80f943842fa54e81d78b2eb8285ee472368c3908e6c29a822421d6e434c8dac773a62e8237d5a99d2dff0fb1a805a08bc23bf9c737d53199a02e7f9ab6728433720fdefef05a79659f9798e8436fc634998a6bf77a0921268dec01a29e0ad821600066705cda322b0942b6a5fde571a61e0678d80ebd0908230757f6142129ac318509f59d04041249c505055e7d62698c7006d610f7572f6cb1a025124cff694152481f4a062a7435eb76759c4c8c60b0906bb8230e1addc5c45fa645e1b0543e1711ffbbec4468b207ac1ab1a20b54ff0e79a9412044469ed2fb5e1179d92e24be3dca770398f794f6f5ede03d79a7108771b1d886fa7a997b41cfddf52237610ebe1c029a8f89bb211554a488387298a3c21fb0d40c96909558920b2d0339e9ba249019ae390ffeb99b7cdab6d33a392de967400f7f024888ecbf1115b3033c948c52663a79e840bcb3cfbb1d20d631fd4ff50db0f3a745bf8a98c6edf330c72eae6f61b93ac97b93d6f55359ddaf76d3eda3906ae0e6ce2465a0818cb55ef155389602bc8e4757075e18b7269a264b321c00ef58f274f599a77127041754133c5891c58ca66c9e671e7f465a4bf7c027dd1f34182d9fb153816570f6f40e602cb2250039e5999424c738698471cde073df46a8173569c6db0076323ee137b5164db77c1a7acc560d77c9177401520fafa9413bac9e23154b274c6023399fcb301cf901099bfe0dda78f8fc8db75765d3a857e4bfc5cb79295cb13a7a8c654250f9d6cdbc7a326bc416eca002cbceb30f4529d9dc36d7ca90788174e5ff26af9a45764c0a9655f8d8dc8458c4b2af0a92d75f33a511554ad465cb3ecdfbd45eb2a5e91a2b74f51cd9983bf92bc2d32b3d4e034bab0479304e559e908305fa7add04b986404372cb39033d9a164695ddcabc884f72108b6d30239d4f8434e53527a7aa8a0c6536b86029bffb9228473df97462d41de9d5838d02f364d2240f2ff5046d4c611860c8bffecc35ba2550a2c447d14185bc09ae28bd59f2cd1969ae4d8ae010feab22a71f5dc4d3cdc5d424ef1393799ed5ba1f23e33cc93cece99bea6fb93f950b377abee6c80505f0cfd23acbaf5117fd54e5634e5bfa0a1f1208eee8dcd096706ac748005d7c64ae940dc7d72fcb849f142ca3fe936e72c84d4d521aea97dcbba3a74a099a8a8cffe0f45b52b09391413883eb161da7c38efe86989974d059c9f842a7b144f0e168349fc571ec2553d549f0de50ff478fe5ea0a24a0f106700e8f56ce22daeed89574087f7fa6b634673eb54980022c68aed03209c423a4cb53a81baec9e4b44f91bdae3006fcf61c9d661e4d9b342cb5a614a10a2d8fefd473c3ad56da07179083be44aca65bd15d999173aa933c1daa50258991f1cab2efa04cbaaa273c5584b6113f6016b8bdf79b8ce3e62fd28d540fcee28bdc640725b7ca1448d8fcb7571e30e91f5a6ba0b23fdded28858400f370178722f5fb70538ccf202e6beb26d81293227c3b651650ba9d8f2f3d61acade1fea2463b38971bae63298a6cb2ef4e84d9c8f21b2680d495cf2dae338cfcebcb3150ca238e2fa34173d5c6409bacf91eae00dc8c4a906e06f86a41ba571961e79634d0ddf4887f9f96d291e3da9aeac649266762213a347c88db941d3519249f661915bc24e82fcb0faabb0bb5ac30f83ca7f1e826e9828e7cc1bf480e710d66cdaf124e1bf8a214556ee67518131e4e7bd54527d50c3e1535cfc449e8f5a45768845093c60e9b9628c233c92bfc01747eb181a64d165776d0b22ee13418fbb1a172986b3a20a24dbe1165a637ad3e990f32a50ca8818493c062e1eb4c40a562ace5e5657cbe31424ec248815330ea675cc0a291ccdca40fcb5831a5b7fe5f2af6a52bad90ec2113d19569fdcc3ab1f045427462610610cc211b83e8cc62a3274dda7c07faecfe5a94a41686afca89513f265207470495e741b9aeae82690ea82c3c57d854766f0b825037652e87902eb676a0cff77cce229bbf0f5f9fed23aad95b55c13677ded6cf1be087137880e06bd0cf71b8ed39ea289a2329a98f48bc4c44d4c54061da9f21dbcb5776ae3bb7a4b7c0baae9ec94ece7ec8a7a8b80a19afea7da117b641964c94b9667717175754ac80d26002f3736e1482db3fc840a5da348cffe13308c22a43f4a11dcb9d0800af0b7c20d4640ec0b6cc2342af6490cf3017a6e518a198f1f2290b11ec50db7512961467c6fa9ec01e841a5b84fd1ae0abfa5e6992eff181899e142a1662e529f7a4b96c2aa121b97540aba5ef9cdd14346ad3c166c7bd18946a2fd8a2e6feea7e5238a2821dc0059b6078120b2f8cc6dfb65de819224593a4dd40cfa811a210f8073836ae4e1da694e72e342718e7dd355256323c11ba386bacc59ca502e401e3257f9c2e060ae047dcc4ab0325a6088708a6433a7fc00e2f0beb063b7578b381001a8a711a98a05dd2b591ecb05b464a073482db1fa11b49d2c68cf71825668a3ad87e2521673128cb306a815548d5e1ecbe66c0f74e426c55e1ecb0e12b48ad5e5b1a44b4280f10aea59d290e27059595e92088cd523fa2db62275624fff44773993fcd116cbde923274c58b0ab45e32c1546c034a158e6a5b30145ea503da7996d0e7ad34be5c6d5bb8cb595a4b27a6ce13003b19ce0bd01fe258834645ce122ae22511c5161d628bdcf0f801e33eb7bbde4ff37afda35e0ad72ffe8f269670e1bee17d834a7ffce22d3bc8de64cbbda54c29a5cd0683068306346421ef166a21168a21c68f6b70842ab696953f9439628c514a295329a47260be0ec373c498715877c55239b8fa67a91cecbf37dbdc5870dc8cb9c17f3e5755d908abfdb6b586bca687e8526ef69c150041507e45a66d69c2f9f29fdc04bed56ab558469eb59b80f06b3748e56b3fd3600ac71c2a9a48434b46488db33538f252fbe79459651a354e3885a8475388adc110f08f5262526ea80f3b15b4dfde533b50bf7d9cdae19f6ac76c55ffd9aafefd981fff07aa92406307744a6e668750ca47fde6eebb6973325bb1ea550c72a8e1004328575709872f0870021cb2f0828315e011c5ea2ae1d0831516ae6931238cc023acfc35e933c3a44fac4a9f137b29a7c4a4f499c9a86931238cc02b50c6cb74333191b24c37f33134326464cfbf71291c8ce2994c866518f3fa67c2180e4de09fd96233d8a20eafd96e2fc60c931ebb3119dbdd1d6bd9b1bbbdbb1ba63bef86114497c8ed5162324ab92b252633e93353aec6a1c2f82ea5e4dc93acb56024c7c86566d8cc30cf231789612d774a96f24377f795bbcdf5203d62188661f10a0cc364c4aec062160cc33029b12f24e65fb29c207ac430b98aa9ebc36b5ac76b5631468c433df699e3ac0ef73634d98732aa8e4dfe7ecaeb788b07c4f3693048bbc03630b02768ed058bfc30293b66e6f828c6e9be7df8f00192c2e19f0f12d02984da3239ce2eb2931455c8b0218a183728e151d49095e090430d798897542e7ac9e0f0030350a81728dde0440d99b5a2640316a6a2c5450e95f9aad790c3912d9d53dd38eb423ba523575653829c4471648601c81083f8d188961aa7a89186276a0cdaa1a3e1ec2a73d5abc94436654a1c894804612938e245415eb34a35b4acdcf080238c948ce0e086071021a186b0ea55cd902a90f88113c8c30fb6a042b3ba493ff052032b66c8c28a1c9470c08245d27ca6a25543a6a255b51857a8ff8186f3851c5c23d001ae1c1274d21a657cda3851a671c08fdfa790a08cfa55fd313f7bd487ab1b9c4a617ef6d9e4388e7bcfe9e7487051ae598eece79c9aa6693eab99fdcc661735962dd89666052e622b9b73c3c9d628616b74cd987b394aedd63e7b02c2809a00cdd7be0423ba757e3f4d7ae6633f7f9a842a28a002592cf505ffe2a5fac854f91a90f50522a06e7ed38b64585307f303bbc5c2d23ef38f88e6a9fce5664212babdf64a4680e021b2ad2781f918ca53f9d7333f95fcf9cbc23e55f62c60d9639f4a3ef6cb6221fbf9f3fbc1c01030f0e243abc5ca3e955c96f6bdd7f8d70196401419b1921c3c3d0a68c8454c1e1134ec22958bee927f0c8df3d3386110f971510a09aac373baaee1efd81917a7d59d3776c7766e5eed0760c188d3eddedcedd47d77fb6777f7c605c70884b8bbb179cec8cc3122f18845cfc89c25c6e8ede8e87883ab78459432fa17af702eb6a5a9dba0968d3916a4ec97de8e8ed7fc40c71b5cc5ff188966dcd238f1080c74a87119290284225b106088224e45b21079d2220376a40b1aaca06c60ca860021635ad18e6e51036ab5c56be3820a27451732c0be90a2b58ae08ea4b80a2353617e4f5061607e12a930325ca9300f238503a62b402af51bced4144d4d7d4c7d11414da5beb86a4aa9e5434dfdae004449b16d3475b3a9dbc7eda79724eaf67448ddbedbbc58aadb838db3495f0c31c56e4e0c153930e20b220b787531c4c58bae4ccd9ea8d9cf8c0b126c7183c5f12e1543610b2432cb22801a54fff954c593106d26af0ac39c161796640386618cdd4036d920a59472092c5a920829a1c54b1750aca0b224d960050d590d65862c0d01ac494fad17528d3f6fc4f5828b11473380410e929c205a22882d3ecf2cae1ae4e83a0d72185feaac68e8344eccbe307e3a4cb5205269542f6848690c61894ee188af56ab55e428c9155c38f1e2cac11169440a58b0558c5695115de934ceb2fc38c3801ad2744982290b23598a6accc2881a93862003e84ee6933927457129129465d1b8e0500336b9f81024776c119471118286a804e362c411d762cb0e2dba48cae504397486147772692207def1d4e4353bb9b84068c7109c3a224e4a337c914a32801758d440802050545da519ba0ce0896e759566d0a244b5ba4a3334e598814969062230f0efcf565d6f6babaea7daefbad5c398e83ed7908584d846ccaf8c671e388732f3f22fe77c42f40b79a96e128c2fe4275c2ca5eaf093da8c04887d3c8277016d905543a061ece91ccec2d33898098e3cb1836e6d79c2b21fa76c19f6d987e9c4784171c207c21996a19ef63bbd2bd49199b7f21ac6da6582262ac60082d228652c21b1262645998c22d98c61034f4e46f2d46234d1260a45050d5d028409456d44201ddd8004885ed24c9c4a07b93fb953739566299aaf30169723b99117c98d932104c4d0122a538e9870a9182ba80161f63c0df2c8fefb917d3c7aaef037ab071acefa537ff007e9d8c91a769e4a61fe8e6facc5afa381b6a22520e2487b47b96b8ff25ef02f3a2f1470a0d03930dfbfc5878109b30f39f662e488607edbfcd9f3ce87931f11a5edccac82f13ffcb587e1af3dc752f3b28f44f40b7a16cc47157fdd4cd7f46b2ba09d1419541745426713db3eaf4725102f3e225ea1eb6d6d6173767936085a4c4822b3f79af92808ec6f0efe52330cc3b22fdcefc06f7ce9c110eb8ed8bf2c22d4af07a3baa7ea9fb5bf393d100790e62b4b284ab08c208a96111c69ea8fd9dfb93144897bf8de434b69410d57df030dbb97122d980d70659a8ef10f7908480fb53044c92eaf0024862f08d78486eb14841fc837d72de58361c762a93868832cd4eaba2a46432ca12449c9fd8341dad81bfe06ec092ff8172f3bba55e5d780bde1da5e07ba4a4f05fff2e5cb97da5f03168c2ab8cb4f676f646dd6a921585986d2b0d3b0659f61588c40acd1b1280463be61e9004850595789071c146009edba4a3cdca0c30250578987293c18d5f07b8ba416282dedb3e4ea4a1e1ed7d5de4041c36deae17352da750f32ce32b8cfcfcf21013a122833aaf23659a0c7d688cf41a8dd3132a7a47b60d82cb4649bf99918638c3ed1fda36ec4b634616caaf2b7ce3e9084adc19f01fa518bd2b2d758d3b44c7bceb0d8621b581c32c5e2f45377b1a07c192f624af582f2851a477bf911091071282e699cf9dd854ccbf862c47c5e44bf229814d71f7b0b68b8efad103d1d373c14741a94361290e0cc1cf584f9974dcd999cc9005b835f3ec83632b7c1179996b49961a856a2cdec51dacc50dacc309436330cb54ccb0ff3a9df1ec59307745d4f4f4f4f4f4f4f99cc27e38bf18594c27ca1cdc77ddb3741d000314954326d8d661b315a557e7cb23596ee8dcb9f93d2ae7bf94bd953f9924a83724a95ccbb9bcdcfbc179c911a1c82ae8dec896d645f346a2eb6067ff1c9de7c91696fe44b25745a098c14c6bd029aa0303fe3e5c72316274eb1a07c39e38b465acc17dad0afd5cd2902a500e8ba19f12bcc179960d080c6f7efcf8be44fda715e94050909090909098983268a6addfc4c3ec641937e554013348c46ad2a3f1a21b9965e4c325b63a590b115e4394258f2a390e74496fca8240e7d2c8a4d362858edc7dffd5412908f3d0b8e7d404d7a16c85f7eaafd88b25f96fc653dfb11ed9837a605195e0bfa91f7145846c0c2753ab51ba10723f480668b369a9d95820842d0d09f78dcc96b4ad8010dbb656f1844a914e60ed8c5485cb4af255751d1f217c3021abad04e7b933b6571269dd76aa99b406f2667a55ec8012b21d085804cda096d8dd49c9476dd3fd8af55bffa1583d7c407e235d1998aa6a061bfac6c4e347a6d0dfe4e0ba5c2688a1a7f33f21c9a45a3ae24ac3cc799bc26fe9c9476dd3f08ae564c948a100410cfe9d7cbc90926323de938adb2803abfea406aa30353e3529eb3d8a1a01da0159b6c036324f6263e17f109ce4a7ddc44ddc87368c450a1fe5da917a35517fbe411f5efcf3e9992c0b252bf291eee1909fb908b7060518a28d3aa5cb492de6bf7b51d0150824d6e1ba7fa63f4f7e132fe7cb84ac21094fbc17ddcc17d5c887dfc2020e5730a07c7d40a42eac6defc622a05d48ed3e9612e770648ccc004b57db8da334002864bf5a76385d7c2b362df2f5f074f8fd4549ae6c3473e906725bc447e10b94d44aa0c2212878e704b57ba90daccbc165a537056290456aafc1b8db33ea8f25dd8c1098b949ec2812282c68a83bd0c8e2ca502f6330d764464fe3958056eb509c12a69c815133190f27584a046d91648849478108251015d25212521185816ba94e2b81e68ff2a0931a9d8af6f18c6428da3d2fe3114e771d8dca67c2e224a3db37e98c5bd4c0ac7fc28edbec33e1b50b56a50feb2745637b06f6713e1075a7fa0d8739dcf2d240d2a69500a3528352bf46bc8462b603a66a6d0551212aad86fbcc92859888d3c466a50be00aa501551ea97c53dcae3e9d1625640e3b1044d793dbc463ee7f98842c36daa12ca12757e412410277655f9233f062168b84ffb1d7d7808fb9529283666a6d99b1eb21f7d4e4add6d36a45bb338dcddbf0f40b32bd95a93d2676262626abd8c3c92e80ae1fcffff9f3c74f0c0e44f791a696664907037604c1d9fe051860e51c60892cd33e3d91926a349a49991e1646a68e641c9b0e2bb86a780523495d93c681f3a7662f849229c4f413334b403ddb523c4483bce42317ef3056f194e345c97cf8ecbe572b9a490cf8da741973b0d6e41c3e9e2a01df6666f76d9fc4960760d13dbb922ac18f4536d1f4f8ca7458f025ac40202e35371d1def4c3c0dc97d0033ae39391c105c5d88a3e1e0eaa28d58e50fbed53ede0df9e5f48155277baeba672506fcbc2c9c582f196a5793cd4200a6c834bb027f433d1fcb888461ba59a4341d3aa54f854fecc04658287ca5f68233343433a8310ff1ef9df4f93fd7afce3f7f32384a948912d32d4a7715a1c0edebdc0daa06117b64610ae2964ebc2deecd3b08d0bec09fbfb855bc57ef1eb582816317fa78f7eaacf1f3e5ba54a75ff1117ebae52e5a8ca67cfbe3b85a3b32cee0fecb97e347aae8ee8578e4a49daf863588f9f3f9583ab0f4c642a476318b61206dd1b8975330deeeeeeee763b4de7d90467409b06411bcf46468ee338ce9b7783a1eae158f2632592df0f0858d46b38994a01e3662a076bac699a37350fb5715b2a7aa738b5198cf0054fe3540ecea3810395ca81550e47f584ea0ed55d9f7dbdbe70a91c5db9bd49e5f0caed8d4771c0487130606052746fd893c1d1e58895c66c31a8989898182d26262666c6c46431588c8c311ed3311c7302bfd8c50cf38446514336e2a1d496cd07206088edb3623cab8028a80ba7a7713819266e18b8f2689c6f4229527f884151a4d07c94204f9e2821c5b69cb9a0092b4840b97b70c5513061b27df49db3bbce93a06d65a3fb1d25879928534cf041fb2c15666ef6d2ddfbab06757a1ba73b7e389d7a7737b66f9ba0057dbd48e04e9d3a75ead4977a0f9c301a5a52d42038a345431eda6716d72747c4a7c9556471c2a589cb15c58997902926f880fa2c158ef254c3a74bd35788c0fbeb4a297d77e3faee7e3dfb294a09ba27ed966977386b0e58e065e7c60c1d68b82e1d3a74789d0e28ee2e82b8bbbbbb5f5ca675ce3f7ae156d9dd940b3c4629dbc4141d9d0f596989a61a3e85120528dddddd1d73772cce06fdf7c6bb2c8d954d83fbdd206f3bb3733132d6e43b8e8a7083b92ba0fc73ce39a70735f161cb8a4667db2fbf95ced3689075a46c273c8912585c477614bfbb45a8abe4a40b126c9c34dc3e3831738f06f97d70f5f1e17e0f1f3e5cd0d91b7eae09ede183db6edab4695d274772024ce5e70f003f9290cd86ab2c450a17b91e9888a0438cbcb8ffc18ccf04e59e8d836dd7e5f4fef7864a7bd8a250d73d46667e0c8b8286ab1d5f89c2737431f624185058517612d0fdd5f2036b4728818222e2729520690853e4c95a8aa281aeb866239818824a08945c69024915282aa65eb3cfde8c42775775f7bb068ba06b43164e51fc553d9fe09947d2753c14c5a1788009e7c46c2b3498f1a8c094ca39ee72a171f6092447955f5d7a340eadccad2a4f20d95243bea18519ba204de1691c6e41e5dff53929f51b0d12cd5fc5b430c405f2573ea2418dd3534087a2108edc5d623724e6ee2ee5638ca57030f67247e28e64ce22a8ff7f838d6152a83f867dc488e66373ce1857f06a7a31755d47b4f1f4c47f148ac79c3c3c5e3d0db644794124cfc67ddb1666af6def1e797ad9164476332fc398962512ebe1c2d7e8f9e8ae9bf3eb71a3c5850665d6c37d9cab2138d3a0fc3ace5eca28d4ff553bfcb3cf9a48fbe8691a57d983cb85246bec065b92b610996982020a8dd31f3d09e5e6666460cd38a9410d6d666823115aad5641336040436e794f31826469fe6ab55aedcdaaae68cc0f5ce980ab07e90c82814fc4cb781a3df6b71f44dd403f05ada599a56e0a0dbb89441123468e8a1c0d79e9ffd93ec8d6e0efe7c0720ed0a2096d203e9e0f8fc70edbe8a0da3bd9cf148e2835ef9be1ec695a8a086ac842362d90866090bd41816d70604fe86f4d0b7a544316a2c12d579cdc9091274f505f3c61c26408131f5e0d2ecc0be8d72a3289155ee136c5cdc1beae03f766569bc69993c77baffb81c61ccf1e11f68bbd7fcd7a57b520e857285f549957a50d7612342b92e4430d509200a19ad0cb01326308fd979ca67d7326314b46d33c63b5d7467be34e360b1115435328b122d4519efc3d07e6b51ffddb6bbfed0dba7dabd0bf793d1af427a18924a954654b65a52a5dbad544b0df9e7a305ebb521e6aa2e69ca86ddb8c3a339a935277327ad0c948a7ce18427b66764e7376dd3f08ae56298f480af56d3427a55df7afad3414aa7bd25ce9289bb398b795ea0d45f57602c6f64e1fc6c873603c877eeb35309e4e08528db37d1e6e40088c944783609bf6dded2814aa67f6bd4429c95dbaa687e74c963b35e8de46d597696ffadd488605fdfcdb8c21df0f9056cb63f3c72bbc6373de6b74f0146b65bef6bc537fec07c16ac45e9b3888b26d93d8172e5663cc767fdf3518d03ae3ea5cd1073dcca3c10e2af47ba401bf0f08743ffcb8bfa908ec77e353edf874b8c2d54cbc22290906f47f65a48c0da5734257980ebf12164b4cc2201ec64fa741ef874c413ea603f641bc4af9d9476fbf5583197ff9f2e54b10af1c0601f9e964afe3ada47f343a67fe8d95ce8e4605c90674ca84fcdd395b4d7ff71678b6c68ceacf23dc205477ff95e76c1f2b995f94b287c7c7f341a1fd27a8d28b51a5b74b489654e96d7553bb37b2ab52feacf263ca5ddce3c6dcf3afb6c68ccaafb33524144e705f0cdbb75e83fa580814a2a4fee8f7d98c6be6bf59669dab95484a438ab817b2f5fc0889939b3b78da41465da52737d84149294992ec411ba4f7424370b9719669869716297a9c148df3ae55f73abc867f7d76097c2574a7174e15fc4b5d50872ff9cb2964ca2ed5ddddf1812f35fc69d5fdb80abae8d75daa1493d1578809932f5f5adedddddd9ff6a8466d956e8f8d5a4dfbeeb92f1eca300c23e6a373c2501a44560d45436b9e0685a0daf7a980a23e5c0939aa3fb42851da2729d79e5909b51feb2fd4deb5cdb25578f36db291826a2d8b14b8fa2f14285d52529ea4a43cd12289249ee8d2c4d2d258c9501aee2bba0e349c759bb33f206ba571c23929dd710ffc81f21361cfafcad1771f6c20e857a41454f9cde840c30eabc293199c407a6bcca8b1f6f311b5e75c7d50fa7df40616e7c7829da385ac038a66a95dcd7c41ff8e42b9621f0cf10b7d364b8dcf9a4fa4b1eb86b74383d0b75016640213c8c8ec1eb19732945232b38c531e716c7759d37380809a00654f81eca380fcaa3032fae7de70f4ecb47f2b30b30068a0fb11e8df0f05546a0876529c862a55765f3c7834b83c1adce769707757fe569b06b7f31aafd9d75e40bfbf705d2b2846825acccc2c9955df2da9115d59798286da5f1bb1f7d0f323a4e74748ef7e1c04ef0a614dec8b086145212cd5673df1e5f7133beff66e2a5c5b2af69bc4e54a9dbfbf836b2583515ad92589b667ec53fdf601a558d83ef5a90f889b5fa722807d60830cce5feda7170aa9a1f6a86deaeaeeee0b3f2108e67ae033f13fb29fff237b08ec6826557e33a9f2db3ef3683a677b17ba66f6d042c37dcd6c57270e7a784a32425d2514e4b0bcdb02ca7533b804e599066bd720af409edf1f00196cc006a7084f34039bd3c2fad81a5cf931b038d10651962455dea6ba5d2a7f0536c747f658d095e734c19e2bf77eac2d53d897419ca05ca5122ace2dd719f639b22f7bc9adfcdc23f27cba867b40df091535d4910197989d6de1bdd2c44e287f051a87824ddc6ecb8f908406a8fda1571b209f90f168b0f7b5e2b1e113da3d1a0dead8b08d04ec09fd08c09e5731a0a83a27a5fc3d8f5461bfac9edec67e56ece3b9c1b59253583e494a8202a5698b1042114350ba326504fdbbbbaca40b13264aaa50a7d6feb033298defef1f90d7ac8a05195f7ecbda9517d2ee419d9d16dd8dceb4caa2a32d550175a13852523718fe905570a4a4822e5e18cc0b6630fe19ce9959b675f78f20723d7cecb7e6b01f52ca7010ab7f22848c0f50647c80a2a4944489a5244bfe5c8f80c2748416a10a0ae84f038b653f9ffd1f3e8ba5fafbecfba781c552fb53450985727f74f78695800285092682824aa8abb484117fc1822d4f9858efa44b19dd37c77f7fd0cdd05ed6c90cea1ae999f891e5ade195df8ddce539f15f04959f1da9b22fb514d82f5569d506d45daa61a8ee60e4853f7b8b880921a0404dfa81e2cf0f9bc90b1afafcecbde51ee439254041819af4641f1f0828eb57f64c2a16a26abf9f263dd8c7e79ef8fdfc3451f1c49fc0b2a2b601c58f5bcf3df60179150bfef1e30784bdefa77e59d293f1531fd0fc38bf75a075e2b2f1901050931eedb1073202d23e36f21a1ed201ea63232ed8a7da4f4581f9d8f764af7d3f4df6b517c2eaaf67fea878522f84c57d13150f50931ed473a5c04f10b3b09f8159d803a154fbc1d0335ffb7e7a780dff0496e5e3e535ec427db84da9cfc96bb2af5b5e93cd07dabe16c21ea5f1872d5419fb80fce7a7daeccb1e7b1632ec81e4671f0b1890d7ecd74b610fa528e0ef4abc865b3ee42da45ef29ceea55e1687def21a969605fd1a7aab72f7521f35c84b6dd420ff26a49b0a4d71bd76f77f47c78d0697bf30e2a8fa57c6f622e8462d647e75ec34b87fa5f2f7f2224992224746a4808179b98290b06dc9d6d86609d6060a3bbf79a8a75e5f714531c462c2a47154dc6fddfe432ec291eacd9be12f64241aff16c2c9698855a4c4941a32d2875cc4b193cd0940d3efa618bf947ecca7da3ee637a0dba8440ff6243154340300000aa314000020100c064422b150389e29d2247b14000a73864c805234944643591224318c428818420c308400600c101a1ada2600cfb45151019851a3f4ca9642e3cbc9e9e230c410bddca5922151eb6290133dc8040710390dfa9d5f2ee64468b80d7bbbf9b50c6a5f8db9db7bc1bcdb5b99a8ab1417d21efb8839dd7eef530afce31d0b0d48aba7fd31c98afc201dd4ad87cf68586ae87da0b73c0051f036bce1c9f10bb9d9ca75d0a548cfc2f04b21e143bb30cbabc158702965b9984b789d054b0fe099a6802f25f61e62abbcaea765bbdc3e6cbcc26b135de1d173f2bf57e8fc0fd30dfe28c902297d465cd2c6071cc1711a58b54da2af8dcd35eff98c8983a40eba74339db4b835795e46ed6de5bf7680a20161c46f356cd46ec6ace0e307005ee094ef35939c959e05e7502ed346a00d948eb664b84ea0fd76602d2c4df7c0c0e85432409a2e4ff07d3efac79862deae4ae6633d0f8980bedf9e1d6d4f3f185b9bec6e75b0a20ac2292149b94301ff592d1152560019f0896466a9bc403f9a3a599624420d5414ebcbb4642be8297680a4394efa251dbb909bfb856a465519e302c1d58c73c26f1cd072508acb8e4f6c0de5976b654bc022c0bf059154ec50115f6a43a7fe5d5c351cc885a1c8a568492fc6688f56678ff62d926b0cd78a9db13e0437b320f81ae1533d5d9f233600ba074ebb18800db48727f031e718641a090c8c3051827e9e649f29567b897d1d03dbb5b1bda355624c9becb19a793a07af76844b36b903f3eed7d13bc65189837eb28f5a6ff06a5ae00af533206d9a0b10e636db6ea0df0585da3706480490c8821838ff5b65cac4af862f75ab69fb17df951268f7ace8eca935978cab224883c18b96d60c48f77c51cbd60b0d162becee62040fe7e8f281813cd569aee986fa4a2abdcd66322ea8891ed04b10f5ace5e7bdad198ddafd2634dac9fcbd12c25e01de377a1280ad60b6d78717668c492518025b6363f5666e28537bc547ce8f0b61814684452c48ad1b77e60a60f81578d9710730185fcd868486b2977a5b38bab058db322207ff6c23a064ce0472356f9fb72e5d0769ce2d49b3690636f2adb9e9937e03fbeef0207049a13003c28153d0762e5eb25e380af784f8966daf63e9870d52d2787c02fac858b4c47d6105379ae144801d963e187d1cddfca6730e8bdc4a816e28752552286f7d182c57429cfdc376ef3d673a9e8e43080a275dba9512541f6c2c8bdb9bc08e030479e366609660917d9dc516f60c1694faba7be3b49eed38f89322139d6bbf14204b46ed3c8c0477000be3d3e3a8529c1983019e5b87b7362baee849a4e7bc9e5798c2979f3909288113db26d78ad91258c30585b7fd390efa1a9ae0ca5af938e648e1a06021a961ea51a796e5c29a0eda16a72c8b298aad7af5badfb3dba5fd94f5da8ee00ea751e8675a6180e552e03d9f01cd087876a7bcaa3266fc40f652ff305dc5cb87b22b7f6f32c7d0a69ed5d56baf6924935c72733ec42e7a5342072a5e0c7977645060151b4ebf484ef608807c17baae0cce493f20bd65f20f3d00cd5857f5584a05863760897937d0b04f8ea5d85cf263fe26341e0d0896fcd69d58dbb6ff00514d4cb0ad7cdeaa005bde134efe0862e7ae15dfab73e63d81905206e6363ba1a3475e15bc721bc90e92568481d88b641266488435d6d3dde216eed4fdf199359e04c5ae0dbdf5c3a50de72f2f452cba382b003b584abaab53659757b51f6ccebe345a9ee57ac148f806c0f7a4b386e32a765651a45d14b7405708a8d8c7114db2b1e13cca7e9ed21d465256c6c1a6d0143bbdb3600287fac95b9d13b4cc504ab3e4e5d97d5fd028ae8a92557592f2012afe7990db1b9ee1bca96ede4d3c4bbdec8c979ce08569112729833c93d108d91b7e0212ff9f2e484f03d297edf234fbb4f1833a5628b9a1add0ce938bf5b50b1399b8341c17ef00520c6a10bcdb878826bac303a286e00be168961dcc83115f5d1eff3521c85569ea590cb4da5eff5c2ccff80546487f15e8d6dedf2a81c60aa8e103466dc75bf52c691f731dbbeb9044ffe12da857b36d23007136e7b24f1d3db28db579c0470ca200692ac2a3bbb79abf16aa53d97c3d4b2dcff097bf68563d9dd21be546e641da3c60689db8417fa5fc6aead8d4484fea1c55ab3a2b24b851752fcd4e74ce7473d036ef03a3df503c2947de0983e82648e7c9685b37f8d246ec786157689df0362f91b6887737efb7f4acea4707cae198add6e9e176aae46c956fd416bdf44e8d4ef0c1415bd8e305e8c3b52603186061dac74f078d86f0cefad81b6524dc9e89cde71bcf73ad0db24c805349958a17922452adefce8cdddaa0eb1f553b006e6d8825a41760241c8f45e6805cf5aebb45000187fc99f2c91879aedafd7a8eaeab9db19ae57a65fb9ace508b8253a279d96fdd3dfdcc9ddfa85e0a7fb57112417d9e741625f337ce2a6569362e8f87e159952ccf799783c830d5199443e66c30e0fc95acb1b431a30ae451a56c94e98039899d9f2ea24598cc7b3f6d363a5b6248425be3c213165574a24b8c867a3dc4b43643410a826568a0e1891131b22f42006136368ad666e5d429a28e46473f157e98374559d29223b4a5314c4072e1a8b0080c1c1073a484f09504e8f30264ab5c5c1edc05d8e2f9fbcd4b86be5b6774dbf3bf3c10c51705cde0ccfe45f19c056288801e5768da31fb4d112fb4a0a827164d33526bad5c4a38d966731f36d792f3636c50267a092c5f52150b665896f1941f2d2a6aea15033805ea2465fafdfa94d2450d4acfb45e6c91bc48c2807b50da164cca7d848e8211656ab39d15febff3678c214ae11201b4beb9ae8b5f075b4e17a0b08f1ecef2dc53624743e20eaf33da156f216532f64a4dfda7e2f98be5241c96426e9a4dfc500dce2f202e276d59ed82002528555407d9a8b216d7db0e4c79621cc76579e6cc7ac2e8ddbdf2c1aaf8f263f0002b0410a50cdda8eaee3fe413c1d5ff6c8b55666e6de9947c21b952d650f112abb16af715c9b3525a59415724ac4fd808fdef64de05d91f43a10a36da60d2e847e3694f82686c174a00c84de0207f9ba02d20b1e73dd60fd645372245041c0be35f37a46cc77b83240f882950a6912e1be9de86b355c99d87d880cbeea3426c06ec937927c65f4edf5ed52dc224a3d280714ecb67490569c92db668bb78c7ce42e41e16f28089611362e5ae459d1f105d11947dee239fcc91350de0e42946e0f202308a80445749decebaa4a7c13f634acf318b3b0a74327ef2f7890a40162969c29ed09152804966498ada0e7cc6c2d3c6345647c6f8ec41093c7e30b0022ae3111e80efeae238fd5eb426c3c2cf35f81fcf370fb93155754fe8763d7d32880ce330beefeacc904feb219491e1845e96a950e2523a9e6f5229aa90132d071b8b1e9cba1e29d56fdaca15c0b940731a31176ffcf6f9c3ace50877b5f3e2eead764a2b447442af776799df1092c83f7bf9b561783321e18ff9c82fa043b7067a06a1a7cbeb3a534bf9424a8cd89ebfd375ddab26c0a932800dd0000d53d4ccafc649d8ebcce4a54fad78fbed1f4616ca5b16100def77b8107b14ab05fcfac65f23d81abd3e9a2ce180e3c10bf60352d6b1b460857c52c3210baee9715b94b39ecd3c97e95f5e3dd2d7babb1e6c4eec7fed7c6fa55d5c8b5d615314ef9e36c6c34427e5a7e8fafbc99343030489ba20af84c7c3fae2cff247a234afa1f9592ded8203578b1f80eff5c3a07be6d3c0a94131fb4c10571c8379d0d422eb743a993848abd36accd3ed0629e262279b3950f20061cf3d99d8afb7c0918cf1a045cbb793b1608205c52ab32cb6a89361319f3bbd6b1fb330595552ae19954b7fca5433bc9e413ef398e41ac00e08c220f8b58eea709e4b90f8829b4287a2c770dedff1278a6ec97d1900e3c3e84e35db91841e11c3693f44e867f51c2188968a1a79d24aa8e41ea4ec0b9e6c9080922e1b75d8d3f00dd21cb468cc23204180659cfe07812fa7b171800367e00fae60590120ffba117dbaff94556f5f7dbdf5fd126e3cb1fef00c8893c4f60138f6863fc4278f089e247add297f86dcf4aa5fb0156196639901e183074eda75efe1c40b5a87f289f2e6a21c6213a8083369a1f835b74d6c8741eff024e7f1852c0ed554881327236c7b04e18d495a8e99cb22289207518d8d36e1b0f98522f4b376f0b30cdb1bb326f77ebd949bf354d052a1e52dabb3d0846d2f12ec85e44b32afdc50b8ef43e4661ee4f8189009517b98033f8fba3e58155fa77605fef0a0a04d5ae9224236d0c5228c695a48a67eb09d0c5a998bd281da0115c50d438f19331b42e51210506418e64064d11d10700c5bf87aed1e270e2b65052e98ddb6caa101c20b1a9f57c880435a6cf0a3ffea5c83694f2bdf6caf32e183a2b344ed92d9a54fbbc2d605a78edbc3bfa02b57da010fd9725b69f3863d0a28fa9f17ae66acfe5240d072e48bef1426f375c6d6875d0ce3c044eec0daf61dcab54aa04cd44f97fba40d4d88f30ccd08f26d24db57050c640687a9a199ccb1c2fe058325a4b9b43b3860c6abb49a6f85d4f6751f25fde8eef2241c31844c4bc36a2fa1f3e5867929f37684c1d14abf247ff53b1edc8507c0ff76464b68db3c12c3b5889fcfec2a47d0a35185a9615f8c8be63c95a7aff06f8f3318e5a2141746d8d41363251c386f09f4daa7a391f2e4c1a82583f4cbc73e9d5de5271786e73b2e277bb63d4a27633c902c7810eca6c2db134463b2ef38b21749c708e2d949157d97a645b792db50f23e0969064bba67dcb2ceb7d5aae4dbd60aa3097d979d361341146a7d343b42e51dbbebaa4eadbc21ce0f2815097cb0508c9e3ed6d8fb692d466bfc1edf1b2758e11f00acb397041d9f910aa401c476738145d8e2da15821c87acc3d95589fd293beca5bb9fcd1eea4cbec0db7de335e5fb5249b89a1688d9c40dd884bda315a1e55bfcc5bfb9370a17476765596d25dda2f889b8bc66868d209fc8638e415f0cada750ea232c6a793aa64e38c0d49a7412fe9948f31f867a0e98c026ba719eecd328b73c1f954f0b63085971cc1823be1ef9148c41c38777fa21b1ed374064aac6778a8a9e3dab4755928af5025237ff98b89661366bd702e2f70be7d67a4608828d86154271f9349b02751e0030a4711abdb4799d80bc9b34527baa6a58de8a1bff5e7fcbb71c505560c6e70bcf5c58642045794b7e85fccf924caf469f2e83dbd4dce90588ead3606c12afd46c1b6587ac8aecef66136370eaac6fbf9142d344448c9fa7f29a44320d8f3655847c06feef6d65a2a26bdc25cb2081eb7f98bb3f9feab89c6bee2c457c315e5d4b0c80c5e94b94ce295a31990d6a18b9b4fa550c82f1490a437ce3c90f3ddaca51e892411f7a4eb3648cd332b2f81a68b7a60a87879997d748887d5dd3a6a6578a98e8bc3eeb78b9e40544a4dfbbe2903ec7bc879f51b00e33e5b59defa5adc3aa39e668aadfc08b42daa5209dab4b9dba5d98c6a3f12e00a3c5b455d1506e110050a15f135e06790fb49cc5259a9eb616e600c4d27a279d6ec272f4b73b5a4f8165c2350523a1e0aa69ffff57e54147216c7ee780a0072513c430a29a1ec5ca7cf4ebb8e4595162380a0f77861316828ca47374cd61e3393b36e40f7c9e5111ac710ccf0bd6b0815061820adee301768752f0a759cb219343416fabc042357fd143dda81774a865dba41904349eda712121c5ded7ef5fcd131952c3d016775cb5b61593625aba23d041568d31cc7d4132f8fd644770a4a5fc9deb28d073f225a8ee7534701ba3d240c7a6605cbfd8155b27fc6799a4e1239e29cf110db55ce5e20b38c33b3adb49987dac8a5b877f7d067cbf721d7073879347270a528733971e87ef318d3386de7a77a87a212648f2fd6778de2988508bd9f4f2d99ef9a3f461229aa1d3aeb46581ec0f2ffe2ceb08878dd9c599a5b25fd13a57e698c332135f3707b5b9d64a0da08eae159bc9d605b683f6802bcfef7fab771cad584cae63fdbf9521db0e066432d8e7f17685e5f6fe92abe10fdde2151d0d2321c2a8148d10ff4138f63fb9b1c862c5f2afa6221472d14db06f9770028c9007c426e18658c24f6f4cbd06fbd1a5182c920c6cc4a2a2631fa4ddabd21e786ccb3215e87f24dc2c3159c693afca6416cb3168fb200029b728a23549635c8a8943b69ea89a113f57a448ac548c1dfbc747c8b75d888451a660a47e1c9278fbc5dbab6e843918d788c66ec634af895925d9522e9a060463197d5d80613841827bcc22d714c8643ddd12991da40d766314511d420743b59187815e1b06e63caacb6f673a944b781ae9d95cce0a684611d70e86428c421fa6134e00efab882b4e6e468b2018f6d59be986a198225ad01d20ae21a42d6006f5cd7ae06f67edd443201c274e99e0099bbc47c022ba01c6d8969872a5183c58397558e008ada6ee4ea3e4b80d9285eb390111fbd2a773d5e487d08a0748b5848240edae13de2db1dd3f0a7d01d8a962217a92003db2046e706ad27962f9f8fbc141aef1caaad7de40778b8b757bca3c4d340befdd50aed43b7ac2e1613bb337982884b47f75ba9ea8fdcb1968f939b2ab90f8ddedbbe17d3f345dca2921695425eba9d61b48702f17395e32d24263299ea9a35de8c49fd6796ce5342f1a2d26300d90dc789e3679f4109e7d0fa9963be5cb048786ff5559c5596e040290f1eb6ad1f4df3f93a01dbcf4855514919c2cfb174cc4f03a1aa3dc2a1dede485b16ac3a9749b9420761dd2d70ceaf04f92daff4be6f03834cc0eff37b38177a171804000d5573e2b4ce5998fb296070879f9f4571e61c2ed78598559c5b217c3c7866ce52e5998655c679f43ecfbcd055ac48a81af2ba7d151d295eeb933caa58c9f508c9f86ed675ba20b5cc9e7352208f939a103ca2f164e658dd01fcca7524e5e963ec9ae2517be1f69ba3ccbe8df1f65e565197ff9552f1428b0ee1445f01177f28af03ca6f3434c120f04154990a0f91f1090e9a323f0bae498b91dca3f14eeca78f210d96303343ef4235037418a9f7fdd72cccfe850a6e4c47ca23e4eeb9b6cee1f83647781cce9277b4f41dc6b7793e2b27c4c8c186688da8d4ee1f81f44245a10577440406ed496edfb96ca23c636f75489334a81ea58c438270d60dc8b61b5fa2f0dc756fe9593e623bfcb8ccd5516c906f9672c51cd31cc452606ac662ac1fe2d65c18798f40895d1016b98bad17745099d8645c16016153c11673d1cc2d05d083b08061e66a5a25ca6c07bf782200aa82f36d6e282f4d6bb036938e819df0247060f27a08e80b0fb048c7aea39ef25874af96b7cca606731d2315ef4ffae78280016124b092bf0e00c6d94c98ffc9a9ee11b02bfa403c2a9896375a501464eefe342d519541cb33d807b0ac8036d5f6ccf85f09cd8f79ade7570b7bce9641edd35654c38c3cec3b67022c40152d6d00e8d340025f95bd64b0132ab2925c7929cc692b5fec458a2fdc3817b24876958cfcac8cd4d3afcf79de99652ae9719763e3c4ca6947711581a25062f8bab47dfc0b20c171db507f67df9a22f28ac5ef24552535891fe7fbea4ef15242b2c4ef31df3494dcd720c088bd2cca466198a44f03c2f4dcd9a782b3434cb044e5aaa0f7512ef3dd32d9537e098b55dd33c18de4f24f73f7af927bba3c7915e1fc93a38a5b9f9e993c1c9a17b257b86bf3077a547bdc40fc9474384b0b50d912523add5ecb54ab1fc1e48b7154a381f5203b700616d3a34796103d0c49eaa2864ec9e4b7203bb0a3a100bba733d18e1155619b09619ce756db14e6384d23c2b4764a401285b2cf1bfb32888a1077d0de9f047a9cad26f6fdda22c65b947c521f247367586ba46ce3a5c1ca6091c677e56a5e0b9af919179a6cf9366722dc779ad4458d5adf40f6f0671a3f78d54a2631a6abaa489f9603a82f4b31bf70738f1e64bace59ceae66640f46b6e3f25dc051177594cddb84063883d6c6e3ab2aa3e2f5bddb894a16b25c95970a630e6f2fe42b5c1f11901273876310693ca6e19ed77602a3842f1b2069c01bcb13b16ed80d0342bf3de0b05662dcd10da1f5092a38c5894639a0db6a0e62058b00c53abd56811f7cecf3927fbaac1804853a478ee0d1b52121110e52ab8f2ba79771c864de8a3526f5430ba4ee8decdb81d60bdea0181b56d91a6ffbbb4bf0442f1926b3e8e1e15e71005e8f1a20e27e35ea76cc162497604dfd9d0ed3b542ba8ead33dcd7b830e3ce1b12fd1f0353f1f45eea6d62a423502b9b364ffa6b92dc05bfd3ab1e0deaa79a2e42ecffc9d57647f1f3e01ff4a3a7499f8d863ec7a0593a0ea4d94efdfc5fbc38c996df201f174f0b32ff6e8af22446eb9c2002d4a7b30ac8c6c5d77052bba7ca078af639a39f8a470870e57bacdf51018363cff4233633e5490930d98ae9471750e915d0a456e7f60a3f6c646933333c5eec11aa345457c8517bbd13acadd4bc2773c03ec7652e80425c68e8ab97a357ee35312ed0474bdb5a1539cb22d8e10a87c70eefd8b9f26994e8b3a14fadf39450459e4ad2136e58c5bdd44a861db1d8892c10e1523774f8321dca50264f6fb5fc4578418546975e68332dc42d884e5965be52bc45272020dde40fa65a0f67add422dd70d25d3ed54a14c5618b7ad30beaeaf6d54b9cc6631ba176a3e7ae4c6d4f70a8e92f2b40493da63b7c37a98861d90f29a462a30f5e2c4a7ab9699b0d104b1aa8279e87831e51ee3bfafc1d3358cb9ea7e3694269954ec3e8705d42703d664722059c47c1bf837894ed15e247e23dd745e3d8397cb728204482bdb5c614de4692adef7110af2958dde7144e0d5fa696fed12354895d931765794e2e4c16eb89b5b2265444bd152914f62cea7c9330dcb37f9a0e32aa0a9ff651562924fee39bc24eef1e5189f7bf3efb3fa6ff27c0009890f2db33c298a22c0cf419e576a058afefc0a8fb3f9078cf344c58f8b063a683f833d2d2fbb057f0982b88a87d2b3155cc32223d1893dda8a207f46777e33bae1f58b6973325fb613fe57e8001bff08f219cdb20a9314de5bbea6225b1e781aaf796cef47c3e826c414ca71f0f85da08b7fdce7fcd7613823103f6a17f4a38a87e144163fd8aa5bfb6230ee684210bd70f3867ee4154505b74f00c62aba397d81e42bb492dbbe697de556dd1d33df7de63ad51e02ef888121854a850f93d9a222629591e19ffe309bdb1b9b9fd3eb25dc1df0e8491c19cd6ff40f2b2da332896c368eaaf581c83e8bffbe8416c86c6a6c34de30966865e927895d4b46b931f826cc11b94828737435dafa4f9558dd97b6fb0dbdeb7b71397c106de0b04edc022cf3dafde623e9f5481a6b7502697268fd49fbaa4fdce873991b553d36616614ad0a0ed37805522e4af6a952c397cb54294f4480fd3a06655c15d88f1f8c2612bc696f874a128f4ff25468d726ece0a80468e08a2bb16f9ec681365690b7461db8ffb4445adddfe973b19bad28fef28d812069e3c9a07c36698ac665c9a4f77c57fb7670f9279a8b6fb030739b53fadd4622d9323fe0254f06bb74c23982b0e2525db8b8d0a370cbb062570a2aa64c15210ba0bf5a19052dcb86ec6cd2936e927a013a45fb6914a3318c59041ef1d5ac6aa08b39c0d5bfb5cbc28ac0e7da844b0ccf03db957900f1952c60ccb413f53d801c15bec5d7678fc9f496bbf36cd20cd8068dba111307d93428b1ce410b3e2cdfdf5493d43a0b3a6881b0ee411a0b16e3a4e65350cdbbec972903ef25d18c8470b3b594044766593d887b211aebff1cfe9e2f022a56ec4fd6573a04938c9cc554569f3e8e8d391a8defc44bb3098a63dcc9595f43d73da9e0f41554fc9d7ddc23f1ca6bdfc60cd411ba7d8bc2c4ad05beb66e6eac530df71d59287b7ab247e52d74d27a61ce98a4aed40ade9eaafdc282a8e967e24043f299b5ef2705b5ca5c1b34707c75976d2b0a18b785b3388f8b6ca340a7d3d8a5f7ca1e40e7a370d48066eb8a0a36ec4fd854aabe6bdc8f7431bf22cf31fdc79192a4003ef0bf40c2c3f4bea46609293d7b0e3eb8065a5d3cef62c4dcf053f12c1a857e65bd9458605bbaf99a93b9d987accd003841a32cb60351735979967cfade3c2a8a69aea7e9a0788b2e779272ce4e359d2e5359086f79aa56417b722f375b3477af4d2fa2df811a15ca84e2a2bb0445a452e70df980a8746d658a442415ade9985ee34159d30fbe95817cd58b9b27c87a077b011e5e8b68602533556d20e4d9d057a46a697d79882911c99949fb1d659f521dc3263bcf4453dab3ff94c7d8b12bd81d17e22a144ddfa6b250d6efd11fc906b511fb5541083bff7c71929575ecd4d830a8eebf03a136ece40351c6b89c2ad14dd6413031c7ec8c5407604f4c3821b032b280914ee9be88a57ca953ba77e3c83884e912425ad2d8a15a73b8307a72e696634bfc6b74c8da6498bc9153e8aa15383694d045f325b0765c1ab48ee88558366e18d46010a3bfd5d7595f9944e2e0f39b2e02a2190069f3396bc04d66ea8ee1aa719047a175048150cc4ed6b8745d147f1b6dd266e896c5ea1e93b357087837864f3e88fdc98d4ece64b14a19736483e664f945cb0e38eaf0cb50af122620833064ff7fb307b6f06a494eb6056b4ab3ab84dd8698672deb25c390b0171d19ee6623e4f47b0a9e64b8e36fb3b1abc2210fdba6f3c94138f66720a85be5e025eeacfcb80d75eaa9918bbebd914f998b9c3ef581b465445cec8541b96ec4d9299156730a0bca221fb38421ad31a90bdee4b4a215fe8171f531900830a7209a245b3a6b8d02854410b06289263718fc6d08a492ee5b6a506985ed8138b7e00000c6f4b7ded35e6fcea4f614b8916161a588355a063061c242c0a5cac779cf927a3f88ded44efd55f142eb8be316649e3b7fdb029a23d638abb0f68358877423c6caed110e57a76a051c287f51b87000acad0344270991de63991ab3ade4738ecdf6bbf48eac914086397b7032f61f483d83f535ec19a4e4a5eb3bf6dcd1efc4ac50de291e9a8d2d3f99f6b812b855ef641ad9ac86a9ac6336929de869c9ca0b6e2bbccd1204dbcdbc8dfa470f4742d783a92513f4a0cfd22731ef3b0afd14fbf05b5329be949ee4e3fd5d76c59b5804127cc1ef2c7ddeba106b33858f2f62305dc5b75951c395f3bf0f1cd4d54251db70a39fc6b631065f70d83454f6b5517ea49055b491cb0ca561b16d0ad241057f02007426e8148d9d4669cc47f38e1948816e8457152d3b59a74b315772f5a11ae842ecd978b150c20f336f6226bf0367513ac98201ba2465b9e4745740f3e46a920a75cc052b69d0d41a42c46695c76210d748f57e889dd77c0706ccb7d629a946a12c7c21d560b273618333411114ac4e933bae43c063e86672463710b8b57b155f96b2a8fe0b7614e0f6cc8bc9d76a268328a94b5afdfd134d42c35e6e35c506cf7fecd518e311063c929cee93f701844925b80503fd58513058e7308ba981b98fe5e23ded26918d81137923b5dda76430e5eb6e7cbf53161a160770f28601873fc0c73dd7b843142ca56ea388d8673a8ce160f4908c60ef0b49d2489f225c84f3c208c0a8e719e201801c19205156fbcf6926a8d60cf69d1bd28f65f80893a0535b4023c25d713ce9be17e4c839505320c18c2835237fdb6cc5e124c766e659a17637c6dad1bac49ad6919c8b7a1318c687513f876386da7e77a99c001be4499642d9922ebd3a302cbaee4cf7f5a9bd322e5c5ac58ab0fd250d4ce4987bb213ab5c3e75f07fe0d540b6ebaa8b0f92bc6d84770def2ce2c1c905e4e545118fd15383b8c7ace311869db2e6d3ea488509ac157328547c8cd2e50c88fccc0340c00948899be0306ee576999e31c0607ce173cea4853fb765f444a0d753e47f63d7ea6be648c1bfcc60308abe7d862c68a1a90a87bec1b8b15ebe16128d346b6dfb03a1a7ba90477a3d81a3bf434a4790a5137e1c7ed64304d75e026467be2423121e955a87dfe82fedce59aa263baa83a1da5f83c2dcb51292e5fad1cf24a93472c58160964f139e3242db3f75ffe4eda4825c1bde6ebd7aa2b503bbaad18072ef1aee2932cb7c7d854b2f4499ecac1a921e40c8ffb8e6fff2450d2e3430eb9018f8c69f2dc707513cf522d5734d2acb91f150a9ea542e5daed3449809f8e76723154e3d0c76ee4a656d07df3bb452bfd872a270db53e5439706fb6ff2dd88c435bb113ca57f2ffe70d9fdcfdc41340ad89803bbaec959dfe9a32d8138f176793b6040cd4c54aea0a34525f18efc6523faa6b3ec7e4b39eb491441f6ca53e69613d3418002d92f9ece907b50f1a8e3fe1c77368d05887293770bc692b02640d9e6f36d47c00217f4d199fadf75066f2fac4bd3a836de016d9b669cbb31c41d05a5c8a00b9d69dd8d1c94ac1092b891b7aaaf62c2e7d22766841a3bebdf390fa669791f24559dedff72c32fcc9c97bb9b8b13445a2d4f76c6971daa55c2284c41851629b88fb113f138a6a5ff521b34a845eed5b2904e8f5ee2a2fffa07007ad637fa7519ca5a315b536c909aced28a720d6f2ad62ea4c7b48399d27a32a20bce288e8ea3228ce97967043e7e1e06295159ab85d7d805e01e86f312834bbdffa02a5ff2601a7b2459ea9f030eff49df6d3962580917863f2c89e32c66d68b940c424f894113aeebb6d3e857c71540ae5c9a0dd96c491c43295946ad467902f196103d54a33523529cbabb8b82c04a875546749a7a975320d0c201ee704dcb30e91890573fe6348a0d0f37f79badebef3cd1306fc4dbb7db1744aa045eceb66fa66bb2e171efacb4e1f0758fc77b6aadc819b1a7d94d389600384b3eb4946870b5f9680c28e6734d8111ab4dcab7e56511d375aec6001fa7dcea48c3236dbbb80836ab9b6b5b75f4ec4eebe3d2e8d64c5ead9e6c0e6d98c89f911de90ff118bb6e2039f0dbb55bc820fbf9b436071ae80ae64edf5d8cb85fdb7b7a0e21f02d24df941da8c5010b5a27db34681e704391d3b4d771d7ccb471a303a258955cf4cca0146459c903d21854a91373d06101419ee3b52976496710448db0ed5f4b557f670ed2cf5a763b790e18ee88a8e2aa86e03a07d564a394ca4d8c98bcb2f2c48b9903d9344c4432a9dca485a15277155bd38a0aa3dd34f3b5ec24580b8cea5c45b2469ab8ba6cfefe3e7e639082aec95ca0ecd616ab9774b83a099c0632b4fdc2a23210486dd1b6889c4825e3285e0672f88f93a3481ed4e0545b85fc4ca31a2c584a2b4b0fc27dafdc337ef604c5dccebf69acfd0763c6d1b26c665c0616dee4dee5d2d7b80cd332cf84586382824072d7c3a9a71cf02f3406b7f11cc2004822701108c4636aebf80d2f07e55b38331b4e496fc05eb00ae9370d33720da213a1dde48dc65c94eab29da2268a1eee83c5d6801fbf24152fec6033c4fc55bd14b56223d5c48da0e78559c6f6bb31bd2fed400bfd6da3311e96839a62a3527a9e1f616124751451bf8e77561693f0da1f0bd30dc005aadeec77d4070778f469ea4ba277d38c871a2b8312f4100bdc2dd7831bff46ad639741fb1eeb69bd2130c3a20afc0ea4867f04c80d112909834799749b25333a238a434fe1b9a947110d260bcbd01e80b69dfd408101180aa984e0a5f99f2f6e240e3e8584ab53766170d13100b7c95960d0cd37ba3c85cf48055414c57ff8f94df64caa0d624d36eac6d059f11ef76cff51755531ae9dc235fe0b3a55e3a852e73481159dfb1471ef6ea06f97cdbf859045ff4dd7a89c2014b4d4925b96179739f0724fcb445bc3296afdb13024f9eb54be0712671d94acbddd88a4d27850b90c1ac76a4c255a2aa611ca2d16c58a383f73f86c62b61ef2be35864f9bcaf1a08b9b89a7605b93e6edd011875e7ca6587ef6cd2305199a5c4030c6341e559ff7d4cc87a87085e69dc70c230ca46327e718189dcdee089f7f72581b61e314c3b376c3072d8e75de464420a86f7d64d8245916e3d71fa7b1021f1bb1815baf4f4ceb1eb87a8dc136f17a8130228f559f4637a94295e9d951f1e3ac48c1a9cdd9c26bd407b6ca7efb78206285b7b76eaf6518d2decee7d6895b3d28e6e2873a896b0bdb5b18aa822e68aa9d91f1f5a70c489d5e3b7dd6815adb6482a3e8861cfc9610c1569f967607e0b4685861e6cab162d4ccc78072c72fc86e6325a66168442461eb5dabe01979f07bfaf80db00b0109274506f0476588f7c150d3c6a377c2aff2e08a7b316efc89ddde2b8bbdf26ed0876f478fe224aaf9ff74e094834deb59bcd3bea1e64c7bffd439d85ba11a930c5d53843701821a772254eca30a85cd43052341e72d19c7ce1a6fb91ca23fd3001ab526c1b9c0ed518857d18bbc1e2caa0b0b3a35e6a7853ef283f2ae9a2572d1ceca57b3169313aab34cd6a8d920c2625458cac4d57df04e48bfc16f8b974e178909535e26b965ae2ca251c881a995c6fb6206cee30a49dfb6e91ef822780527430c5ade57c0572e37f43d6a86d6a62211061c1b27cfd824320963cea0bfdc0e6123ef780afe27f4c0b5a3472cae09a9d1bfd5855ca6c6b0e214f2a2dd0104b027b518356adfb12dbfda7772f26ce6f9c98f0e9d8ef19fa4ff34677a3d233c41c0fa424bfa7e34261c39156d7b7328100db7fd1f3242db62172e3371b2735ca7d4e67d2f3b98e04a0fd74b9fc3f555e3ccbd3d024bb482758fd9acf44c8d88bf73105031e162bdb9ef7c2f9c08ae7f771c32bd945a0550e17c00f8c66835e9d7970f9850eafd31107efc955143254bcc9a67ba36013176080185504228c705d0a4e6c7c8f2c1792c79163206efa5deab2ab97b2986c4d8248e0b1368ef585981b11045edb837d014d0110c64d9eb5d79cde7192ad70d86c1460063f80abbd69c944ec1ac1758e2bd239bc49429300054f4bb0368d0cb30213b36d14c4386892fe4d10f19d30e075074f12a507714a853bbadf4f633ee90dfe85fd7939185afc14ce7621cc87e178ac6b9622e61fc09d29554bb5186f23447d8a35e9d36f64b2a0390381677a4dabc577b6dfcd942772eec29d51e1ff351e4cb792a234694da0a8fa4804d0892f4ef24cfadcb93c767484cb52b912a7d4eb8417e19406fa99414cdb410836a53841fe26ef0fc68933af2a73170c7fed35108f01157df71dd1156ccaf6f7540613e8af39196dda838705d60f1ed1a1bd8ad7178cdfe6e9ddbafc2e61650aaec18fcec6193ef860ba31bc6af99761f5dcde3972e45ac3efb17952a1d7be1792b06dc11928f60b54d856538f41ddb6d57e24f53c19983b8518c97e321720cbacda5702f6cb194e83d0a5a3d2342d262767bb78535b96134196546d064c927bb91b50e7e708f01948ba39158744333d441b68cbcb14416788596ce5a2307638d3b4ee925298dfac9d96475727a8e26a7b950ca53242e88bef7dc34be4461c703953cc3c2fece071e8d8bd5a74ede4b271735394725c28f45a3671dfc136fbbd19b37e834663a272b8421fbfc15fbcef3d18a2cc8bb4e9d9e8cad0f9cc75450148377a698bb949a43fa5067270e6c3f55a5f79da08b0c4a9d0fe4445f82b37497837ead2dece261244d4535e765c6f9ba336fdecbd48c75966d0ebd207289dd62fbd4f0e531fa24bfc4791d8ed5174367a2e16a43840c6aad41e3b93e09691f9923283d1115a2b451efe8a527e8f89b1401dde5161eb0a87f676894ba5145f7bc8b2a2a08e69b940d3b9ddafa9659ff272874f1562a2619bd04f93fde11c9648779c592dea291be88ae8da90c6cba989d911d0ab05250118e56e56395f634c2e4d45bd78d936dbd70100252e56966554caa6e51021d605bd76edffd8f61fcd03606f2318f9a408d03a2605117e2591a326f317dff9872b30104391a0a4ad3f54cfa769f4974168cba0f82ba17041a8135633708a68b665e357e0ad0cd7b1caf45e84ab0f1736336d08a7808109210fc5ad9814c1796bd82db351a3e704b5f123fe9f8f9d30d5685d16f01ea9ad21ca79c214d0bccc97cd9556e2e8d94295bee1131524afcd01346b482f17e3be3be5a9d02c7d4dd9b9fbfd6edd86f65da6905c3f45425b8582ae89049297d46363b7f0a544f80f14905fb306bc7fee6ac69ae40e1b24d9811f9661cec821e7df5ef5110f88d312ac5339a50a1c4e35251d94e0befb8967fa2b906744b832845ece13c1f8e630e1c281789b60ef09e9c5fcdef4e543f042d3c058b5a066772b240b5d1506d45adb3e8293d7b247ef76b1372fcb1ae35a16e24884204d62882f78d7bff054301027a5c6bf0cede50987f0b8e7b1fd76fcf72a8055e76bc52bc814310eb2c9f999e1aedb3766178cb05e81ca38dec64576cc80228e00f1422688ae1e7f56c4f6718692f1d7309f99cb2215b997012bed94b2f08d6a9f4b47e77452d50f50557b6e63d4f524439d35f7a054332857595f77b1ef290b42d4c31c1d2d039c69592b8c671bf57275e5bd72fdb56129954bd5fffedbd64402d9cf0e23060656f70b0d0a31e8ffaed2aa6c2a1482662c8f46b11d682a1835811d0095f85b0f3d30bac7b6784c122056d0058ef4406852339d8141a44eb7a01e4b50240b0b16812758d7e2ebf621afd8508bf8f427f4deb467574e1e9faea1cfb38ad45f19932eea0d97cfe312ba4295a37efdd62152ac47677754d0fd71ca9f355274246f366a1e88cbca7970d74e65d9b7ab5c1aa2ee4e950486a4f71ef0f992546bd326236bd1ef11a692f364788936bbd5a039b8e11df8b082a80737d102d88a92b79a8a151c155a0ca04d2baecdc0102699bb10e6b6d978714ad7d07e092e3a5768598071c76e04e187e285c6fc08caf8563864e91b4cfc884e532966049efb50323ebc8984d8a1170f37ff312af579f545ead37cc8eef25a52796100ada781da94c7b4d5a0a8bfdc1d6f7d0abebf4af09c70a1f9e22c4953a05fcfde3b16e7394e2a0ceca462ced744272ebf47d16d6063e87f730a673312fe1f10412eeb2a74f33410c6302bb4c1b86c2ff362fec2ba113538167cef340bf120a35ca65f74bb98ccc92f6e60efaaadd78fd5ac41432769266e7d7591269e4da2aec889a4a51cfb69ed5f66dab4d38ce39d8b380f7d09d17aaf2d36f0b264225e733581848528bd415474cf066a03503ce3e72bdacd10bb94a5ca304b455c1f0317c3fdb9ef75d7857cc4797b1b37cb05a32d05b4a75bf579ff595025390933fba4df0c9c4e6f3e9aaa423a7233167d7d7037cdab0f6a872c4cca02e35669bb252485dc0fc066d5d13b038ea9a4eab91cc5cd1db21615d00ff7f742a6b8a0df1712a3a74eeb38da4dea4a9104f95f3fe8291e355ac9f4355d4426fa57ac340ec7860043d027ce62a152d54d94e5ed143590344f664f1c0dbdc7b9ad532c277d76fabd94ff85b7f5feecfc3ff9fbcc84c294b073903ed3d098c2cdff1b0f2ee17f474af20bbca5084ddfe2301f0b7152df30e6ed3d7f2bd1c49bb320050c40f7c4edf9666fa385b458bf0a6a55b34d45f03fef9f72c2dfba39890428084c51a675c2507dbd760ac82d69119bda9fb7a35d321ee3bf12c589ec01ed324e05f8fb22f0271660972e363313a355f469b380e495de7dd510fc099ad40ebb169dc1a2112be88a0693cf86dbf47e9b81d2444dd845ebcd236e35e9833c08ea364c4c96456e44108264cba85fed342afc882eec2a273e9b83c65c97a8bba1f51ee2f4aef6f07a96c79933ca373ad08592b8f3f8fae7dc427b363bd8974e287cfc41c8aa62f666bb993d92da350fc1a0284524364fec375f98b9a757959ec0934a34bcedac2181d2ce390f79635b6fe0d3a2f65e471f65e1a99a702a5572b3ed3bb71cccea078c5aa020ca489d505e833c853dd155989f9dbd5619f621c579412d7641ebee51c2c548886a8a9ad18a9b4d4eb102e780effe4f8c28ee094a08a60fe4b35be16eb9c17dddfa30c24e98124429bdc06a4ed71919ffecdec856cba0ab2130739d9ae3267be008f4189a38a1d5370496e39c27d8ba01e975b55e9cc7518654c1867193d074a24b9416df456504780acafaf9a033ead10aa18bbc673d4a562199d32c08f0932fec0c81b941d8dbca840abe1babc68698ca2456953b45abbf823aa18a85a35e66eb7307c9cd4f29c29c4ca55f7f9588a885b963415adb22d0f033fb980398171b15afd2c52a8aab933c2805e32837eef01dba94012a18901e9ab0bdcca10eec7da348bd220fdafd8f35ff27f4a41deb57d04cf8b7fc12b4492f401b96724808ac44f263c40bdd650e945862a2ee90f556bfdfc540c4d43e49581460b48ec146ee9676156feda2a23390a03ec5afc990409e48bde24d00e1167e04f8a2c204211599d378c41cf0dcab8364ea75885520ab190cff3b324c7deaf16b367c17862338a1a4955f87da0a1b5da4ec1cb545d060458dd60fce281012f13e719dbc4dac4ca7f052881123ad6d4136d22e2a4225d85bb8333e9d1d124eb6b15870f57f63664961bb2ec86cc7967940f8c92d04191f2f9ea3ec4f963038bb4c36245e089815874517aa53cb20c050d6cbe57380a65d74b3ed83778602f3e53190c7b21819cb1f2168aaf869a5c57a997d9d7cb2b4df98b2cdba73d1d7742bcecb5beb234b00b6a79415ac596378e61a5953c801c87f467669b355b31bd347aadd7f4f1984ddf9d1de95bab69f2393dc4526db9d8feb911a9dfa805b462cdd825a8eb15864bed323e516fa2581880094463fca5e5f43467cbf4102874c0f228bcd3009dd05c77860c34767e7b038b35034bd705967ea781efa816e9aa97c7e93b4bc933ae9d418ceae0cf2cf42e9ca82b4a8b87045d11dd2c244d9eac00ad4897b9b83cbffaf46f91ee00092e0e6cc7cb533ff384374e05609e9192176f7665f938007fefa9750ecc4ec186d6fbb355a974dda7d9d97d1e9d7ae666b5020951f2d56f9885b9cdffb2f1b59d39743aca9ca6cf1988369e5aa6a0f065b1b7b9a1a81e4f0b77c88a87d709f94af9f15ee23b1c25a28cfc944f4b3dbab1f336883d86380bceef246126f0228e6ea8aa1be83992b91d59e2188a3c0ff1ea6a68b0b12480bd52720e6f2e681cae1ad9b98fcd03eb5d2eeac5888d50a71aee9f0387e09b1467ac24b69ff0364f3ee7e531d0f846cf37a4e36d98e1a7b608feaadce873cb6ef24852cb88043934c3bcf28c6488edee100de2c38af1f8b795f207a57fc5be0f8f81bb0326b8c3f738bed181126f103f20dc8c0f4a7a796fe89858e1da184e7676a2a38f639eddfb9b628e8cca1eb313b10946cd78b4c102aeef53e503119cd142093924846a51e32adf82e51019d4b27598c28b9fad71e743d7d2356dc984a544a7e32a79f4664a7a367933fcc25e818369f672734d7083dc68c3ce667afc8f179fc3876d49948142ce28a279a32a48241ee59ef957c14ddb92d327130f14c315945690c21021db1b571411cd8ae6ae61b042c046020301e89080f673ee0eaf721152d4386ec1de5f08ff8893f0b6bf3a665050703231bbbb9e516f057b56040e1e68e139d38c7c00321b648ee97ea8cd62c2263cef0f4da533140f399631fe3b8b081252414d8a7af9ee09989d1845f4c719c0f031a18f96ec086c1b0383b143e7336a910ca8183b112cca18f2f0e35da8d8382f89ef22a47070cf204c7a981b4288f697d4be99e7e6658652ea6ce4d0f91b2827e0ef18fa6531fb66ed5991218f0fae7fc27967abef1868c4aba354227d4cd408b1fa01921f6650983ea133ebe354c19e694450ae93f9b2ca7297bb4e736d8fc3b50868eaef9bd86ee2ef58ccee62917978b3d4d00dda33a215dfba9328c029b31f5f4e8df522ad3cc211e7e0a988c803ffbc812ea5f0173a2a4f907742e408498191b5a6c767cb377870df4755281d5a3ff99ecac9841baf88b09b45ed6ce5c976e4ef7c7f56c162b9098620b922a20c464d1cbe20d34e637f8624deb2269184e9bcd345b88c40dfa5918a5e4798206cb82739e0b1c4e9cb4106039e3b1017129288eb15a09aa50cc0375c12e31fe941cb6918121a2a1fa188ee45caa997066e256c02c333b3edaaac90b8199ce11c06dc62f18a3a51042957146f2cdeb179c8171f73f41a2694d6e65a79c41a2333e3686486137b1906099395164c3d845c06a30d2d3ea12eff1a6da440f7dd34ff895753bccf3130122cfd22873a4daeeb90732cb568ef8771f321d1c6086049765efe875f10bb7839d43b7dc974a4e3ea6b063d171a9128e4e983633dd20f04e2cd64584654b45e938d7ea7f08e527e2bf0f0a5b462db45d89adb7fc61c553ace880d2ca49fd869164402117ac28dc87c5868bab71fc203b84f8210798e72de57ea7de9585ee7f910f4e9ad053bde203cf43640496f3c73443fe4a8915d2196053ac175500e940f8e8dd487e84b5bd9e107b8ab4ad30ef8d69632cdf039e433032622b0c835fefafa45d4f0c41b2233e474107d20b50485da81339fbd20911d59cc7d9dd4bc2e0b47f3b1b3ad42374c0ad08d40626c076a1ab66491377d3627a17b984ac04d13aeab1bd4e43040060903d391c4fef60a458438d7c2fe63ae70b38fb8840c2329f2fa43aa03e562df0e1629abe281f63cc7c2d8a5ac7b075a3c2f162aeb086d9e54b0c5ef6134a5b4db468dc77fc1103a92570c44e648ed4131cc630c4f03e4b2f9b7511420cb4c00a0689964a070dfde5cf9a82357cd17fd6f574e4a26db6d8d8a78142fd45b5575a21447925d7a6256415202a0ccec04bac5a174a843b202522cbaf25dd125310a691bf6c04f83ae6c306b34e697b8337761eb6eff4347c62e9d035e1aa30be9b033ba311bf85cb1494fb70c6f23fe780f72db9c6c8b4f8c8093c516fb6ccb982db2eef75239e5579868dd55643c2ebe773d84b4c3b53feecd86b8ae70ed562cd9e7b4339fda497f2dd35cc8c30014654864a1f5c7568bb31f1c20ed38c947d63a1b34706d01dca23543b96eecd5038aec014d893afdb0179a73e5d7ce0287213013b71d6a2b2d3d3329482c9903bfb397f17d6b511895c0311840c6a055b445ea38c1154184fc64d8596a1db590d56b5b888fb9ddff83c083977a57560821c66414ec6de11f15a98a0b3d853df49d1c8a56026226e7e1e9bb3c3b716dfb864773c06cbd39c5009d5abaf5509955651b9f246d50f64f422887de398f92aa79f5428d4be9006bca81856210b7781ae9bc5ac9cf2de3a22b4197e57a2fe3619569283b606b446cf0422d314058f148917e9dad43265a326e590a0451a8a35dd9443269d858a0666f34150da644c64d8e4745211d013009fe4f04dfecfd7447e695f12454ef5b7c9f3350ff8ed0761ad73cb4871e2d22e6e749ceedd5321ce6012cb316ebaa05c9dbf9d5234a75315ed5df280c1ca916e121cdc236871361097716fa3b35a660fd5729bedbd139ce34db8ab29c177fc656fcff5af6d21c7c4995cbe4e99c75a567332bd842c339971b63faca21959943f7d2ce2e374286bb8d06a5582151850c71fcb441b50bbd256f34a23fa2283909e6f34559605293d39015f52c82df23ed39f8c37e6c15c94554f3a5e7d4c593e806aea1ebbcdd266584dd9148645c521261dd70a108b051d936a9207bb082cad684bcf30d9f36355c13169c3c38a279e2e257dce65d7f8c60ea11daedbbec5ef894adf4044260f15a2a9e4a725805d866121f171f384e666ac0169d0e0d5afa616e58f48c693263559aabfe6ab7dcd9632b481c40770b702346b6148b74b6324cad32b362398b7dafbdbc8633364186bdc20d0881ad338f73b1644a663a7f3c290a1f93f7e0adfeaa1ffb3efcc3c20006b3a4b31cd1f5c3c01db6d2ad1f418e6e78a400cc1e7b2cca06f8a391b1dd1d9bd35de692a06888d1dfab601c37808991d79a6cc5e87bf936bfc090865ec7afd4dd335e745523f8803abb9623d54a3a666d00d9b0353910b30f8afcb836ff7c5ec5247425984460b62f64caa234755d85970bed17782fc7c089a19a544a880b1eebc14c363ee50a9114844eb83cbc19fa662c39d58ef1bd82f1ac7ec5b29feaa1ccd3fcf197647048c8c9791f38d39c58d454cd7b694fe84eb67c3357336af946ea23b48f154c5512c21b227e63bcfeaaa04ae87e6027a380a5b706a22cf853a51cee12fe72e7ca7ec50de09676fd36926998d16d33f539dc1fb59e43a824411497b2ceecd1aef0615a597ccf57709ed27e7ae885e49a9ae992c9b5aa05165db4b1315bb997b4906519bddf1c8976ecfa6af7c9b7895272c2c0972203eb4d96247568634aaa85fa93e304e375341dad0e19d94eba0e1774f4095f3fd82a187049ed8a52ab1ad9422dbf3d9b6a70ff0dc527b19dce49b7ec49a0b0ccdee5d529a4062de19ee1bbd980e6adf3122d599344ee2371b4d7f15435a527b09d4ea3a1f8ac5d5b2df9a01390486a5df421a7405f806e4de1de8f46cc9e137a1b0b7c83ac53e4205ce2e7206cc2bdf39b2164c3734dadcbf2b669fc5b15bdcf4ddba31871963fe457857ddbb8ff884d7b0399ef0c604df356decc4cd68717bc29fb78fc66a11b367c1efdbca11f4bae259a1da674f5be6580650ed7b5455aa49f3ff325f9b370acd31bd359165fdbeaa13f31a64340ae631efcad27eda700bb479aada4654d2a88d7884547ed4fdb5849e2e5974fd7a768d6a740140efb3b52115675ed730c5f8110a6ddb6b884370eff78261cf9ff8ea048b47e2765d21126777f38f549c67b10e06cd870b4475aa9394c50913435a7bbde803d26413ba908cec5550b3f0e1d341e7bc88c15eb715925e66b3840b8d2dfa65045699c60b7c4265fcfe59e7868e6958174d90177620f6e7429744d95f4310320332dde683bc5576d9917c72a4441db07827895c9a80f83b5c9bcdddf1529cad3d7b6d385da6ced6ca54c41058c45fd624ca45acea8d4e8d397a9a743ec6b38943659431c2204d7d180684136a4a3d61b446400d9de162ad632f6cd01b48ee56e0e3b8043fc1a37f38115268ec2e3712c7a263e27853b6bcf28006b4b2f05d8e945242de1f9ac69dc96b5ecb6a9b6cce2cb9e61f4647f9065079f8eeb26b1842f4f26ff31aec8c9d601e2f3d42346b2e39ea550ac438a2292fc4b852f1ae43c67b25e30f101f8baf9b6004e0604e3dd88f067c0fc3f2f39d960f1f20ed173674409b6597102a9f6e14363f963d7ba694e21e574b397d501c89d7cdc1f17017300a9605e662759916c8c513243f786bdc6c5204578db07ca09f7a6e7ddb5418a5838a4d07a3f3b98d9a127cb75865edced017030ccf23633533455c63ca68b6dc2b046797c117199f4e8bcb78bf24c970e1d95f25bb29436478e14b1d6f353603f5a1c09302dc040ec7051fd5d2b67b6cd6a2ce3404f7c8cbb61b1a4a4fb27722638ac0de2f52f20839cd40b3de6c194cfda7bd0927c9e03beaf13d8912f0ebd7323831102f814646ae0df83f72b5f92ca8b0a7d021975bba41e1a6d6aed817e976c5c7f1409fff3f569fd91be85c415e1233be46844f648ade9e60a445b7c6d9819d9272ba4547a88299e87fc0ca23f61050bfabc553cab042091b71d813459328534bdea20cf55de19499be78a1febd20ca5220d90ba80724205c2c79ed0648b31e4cb357f3083fa2d40baba705261d07e24f0bd49c01862379b867cab68c5e68189aca39acaa01de8a864375e2b4d643b1dd73f92a55d94232e36b7525cd921f989896137314a742c402658590ca1f0a0e8233745b5e90ce628aa07c5a839a1ea6cf5dcc0191129022a06384e9852b5d289094baad6e35af4bc7a79237e26b34095e11491c9dae86468baaeb2026433efa38bb1f884db536bfb337e3fb9c42bbf53653fd3fabb9a3a1192f0ddfb08c1dc13283062428c3a3acd7921d1bfe0b6f3680bbd727feea3a06b1d00fbfd81df8670de150805510ccee254adaddb9eeec820375158e95d349fcdb57d77e37e4bf8f220cc7789e8532f33a24195e72af28cb4dfcdc7f96ae906317410faa957a77335271f67a11f06c64853ae19f0eeffd284e11a3f514a12ba681028b22825913816cdf8eb59b488ef06bcb118444a79a668ec6d396171eb9ef03adc121b9cd3436c92c4334e4d811fa59e2882eee1264f48c86a20db05fe693b61a38a0f410cef60bee734978f2bf38972c021f04e14b240ac9fde60399aa406a1245f39b5ebdf993fb3bb137f2c3941327e7b91b54d9ed6b1c59c95eb0d8dbb473b1442af4afa8689b7c958dc4579ecb2cf36253635fac682f28801f37312373147c8e7779b52d9f63bbb70ba58372cbe43411137285a3e783f150ed9b68ad4ecca9123cdb5c1e59551637ef484616d76ddc85151c5a912a0bbfe7e7c98e98b0293f86c5b4709fd1db455d6afd9aaf89c8b1fee09ccfea4daa25df9816a3a06ce1f80a24bfd1eb9f039112771467575622a342819afa2460a1b0d6f80d6ec42ca711d76cefea5fedef7727f85ccc09486a58b542f52e823ac2f34922bcb3135cae97bf69cda06853935ad638d55046894c0dad57c8f44807ea144a074e2fea4a0b8c8cc2dd3ebaf9f4fb863c1de4cb0dd7203adfab18cda6e65c0da14d9b9d0e1b0e6b7e483c19aae9ebdc9caced6937cebd1e2e512479c062a11acf774e7bb8a379535eb9505f4b5e16e2ada1ce92a2e8927067448e958180bc76652dcd4975ed48bb37d425d0811d8f41b25fa6ea00c45dddd20db14b7cf3c0d10b38a6ffcfa429bde32419a6bb69fbcb70fe5f800ed529241314479b428dd0549fafdf3a55ddce521ec03939955a18cb8cda2f3550b4f3d9b53d8e8a9c22150335973beb48fd8d26a367290cabee0094be097d3410a44fb28c9a21b164bad8ebfc8045bd09eec244d3ca8e49cf60f0d8a9e8d05811d07b2cffd7533e5e0e8f2c4631802dd9cdcee2736a142c7198337cb6e919eaf5b8337efc1449a1266d3369992436fb8ab8225c76594dd5e5ebdb0b5962bd9ef4f9e3718ecc1cdeb9f53b494b5497188efd2aadd2dd8fb192bc5bf14b1de22dc4341ad54312fb0eed0f902fce205d55055fefa45cdff123d7e2bade04c8853db7f4195c8c10804eb691d704b96dc6cb93259a23ae23e1c5f1a76ae9fa9de69996040c94646b9c9579f414b935d84d6bc0f70ff037780dbf987c23faa0535b898b4642d5145ae1b472ed5b9f57ed04ad3bdbceb2665a8a3fe6bd527d34913685aa5640361f52e00364de62be7c500b1adcaa92310b880306f5c376d7ae82f1b050342f28a2b54e28e491142604a43c98ab360ff070e6f457e51a37de4537e097b0e3ea2ac501a63f8cf97f3d6db198f673c10e29d21c688c2898b4488903c6f5ac3c4737b1d5004d137a86bb15c0fcd090ba5e42219d026f8d8f2848d31d0f90dac423cb75ba7ecd3700d6065c7b81d237c277d8062459df83d1eab50ba865b15c117983f8e9c40212d6de1e76b189b0ee108691d763d20229c0051247c30dddbdb3a14e4d69e09f914384fd5550b55de90a502db8f81df3d0bf33e8148e0a265373f93b1af792de3b69363f11912d170b07665bc849aba574dafeaed60a471255597ea544f6d5172aa43d3333d9f1bb68f9d8eedad3b741a2bd21f0ce6ab06e6c947b91a090b85c764231a898e7c315a9e1768b9eca83827b92aae43a771b7d1d66c8e844d36540d67adb50e19a89c9184ce7c7ecf955e7caf1f454d75044957d54d498daeeb0dcaa3ab0a5e6f103f6027b0c8e21e30b7279f06c19cc071b98746b8d2c0e149461372b430b0d3286262156154ed6916f0c8a4820dc8562399e971d4a12e89690dab4c8d28b30be170f9c8a534cd91d4277492fa45996083b9333e9078508c3ccb690c3fd423d7fe2bf594c8489e44fc929831bc199a219406885ed5f00b362aa15cc7604a17a38e85dc3dfd092c68038516f208fc452fb4fa88c9176d2af8557dd242c7682faa8da1e730168afdfcce77760de5780615726b025590d92da3051193d013699a5203571153e4be4ef16717c6367b61fba8014a301210526258d14ed6b73d60a365c5338bc60486c92a44ce103f55260c9896a069dcbfeb0e3834e41e494cc4870481e025d732e05faf0936884af1e69632bc16adc7ab70a7f955f7f82adccdf3e84e4249cb3559a1ea8dab4f732a3ead954279720de66a152dd7e6ac718381f84c28b42e64625a040b6de681fa543084d732d64a774653e33588cc9c8e92788725bc928bf4a90d122c4fda2046def513f6aed96d24c363b31deeaa2cd0bbc2167315301aea8a320778ac59a6a9a866a0638f6b2c8192d2d19a5d957bf8cf51036553ac474634416e14bd66324d9e6db380c7b057ba5813acc65b48ce8abcbff74ad0e233938cfcab854af10e0873a8710a5924ba4bcd07b5f1b90a7f8608608215062251e48cdd1f3eddcbb7280ee1bbb873418a12688109dd342dca4a07739e5999988e8883d13f5fc8d3b1dd2203092a449ba500cb1e25a554558d81b0393fc46d260452ee645fdd18eb3c7b0c68dbb87034c38feb61d85b762e9f87362208afec3748291114f64d3fe7a06b7608a0668c95249a704ce32d88c3886c76b025e4e3b11aafc2c40fabe81eeaa142cbfc79506bf292848d26c5e3b8c034e9af8980fe60761cba49c8d53c8c5f3d691a35178c40929a58c0d32889ad674f36d3234154e44f33907290c90e67076c4e8ca7e7dd1250c9e2e1eb010840bd276c6ee25e3da6eae7d8e1910a4ac7a42841ac1545b3d5c144488e3277f99fc201f129bd3aae73bd3c85c32a327f013e3b6ce40ade0819eb831147800b5745047a04b2cb07ea5e461e95d7dae88c499aed0488a1e563fab5da784f92fb4751da51349df5320a9b459125efa30e5ebe0efa55e7152583ab3dfee44685da5a8cc04cb91cb817cf3ee65e22762dbb152cf4dac949c56d4857616d74877b790f203f576995f85e31eb8c94910113758fb0bf671002fff176e06c4a3e2a58bcadb903932b727ab31e3482a386a774d6af6b778b552e07c6d9660d3b416e1c9134f9441b6e1b43a30ccf40a611b868808bb9c5447720081ed9a43df1485b5182e9071175e05cd65352936e2eb53ed2267e83b7e964d6eabeeec399c6432f30104b1e09bfee48ca514cb383164318ef063c8b881b35921c0135a310ca4f22284b9d0aeae16b1c9ee16094eb5e5e827442296f7c533e65235b1e511b31dda7646a4fd2cc1d1b67aa716c32bd896979f4d1fac53426d34d45a756ca25c1b518fda847a511fc3c9ecb3a9b42e2eadacc210eb8599e19f4f7b71e05d21e576a73ab0fdb4b829ea4a3853ccbcaa897b277cb0bca209963dd77517e430be48aaf020228cbc70d6c42e926bc850bd313ba0f424619ec67d990cb5442a7a206aabad19580e64ae12a219e0ca366872c991e41b408d628ef858c208d6796989061538f736ea05dd600ef095cb8007e170176a6e3edb78b7df27f077cfaf778e219d27712610e2151542d873817cf377b25d266fd765de3b05891f83808c194bad871ff5d45514c4fa0db8cc5d87d5c6402e4c2c163e2709475783a8056e3182549847f899c41c6ff5f3d442a536488b12f76e84bfcd1ec95405c08a73c7183189d17a1f125915473b3a9998480d7256d0298de110854bdc8a498258f9a03fba0c802ca2ba1e8e3501c871c4a4a950314006d923ab12a39c5178bc049f02283dd1035382e900d8adc81581cfbe1b4dfb75853c010a30c3257eae070c0979180961061806d0918cf31643ec2d77a29679caaef3ea9854ea33fd34426e8abde615240e4cc01a3e8d4800837f290f31def003304643b8642447915c5a66adc13263b727f2a8b82eb516d0a4f4d16cc305648d9cdaba7e3a5a1d3e9a96e5bad58275cd3bf81d1f91f8c35bc1813e8a94531dfb3aef671bc5624212697c1d25ead2da6e586968fcbf5b9d7fb3337a9cee9400a5732ab2e353e42438e4a44e818b7c48891aad87199c76e57b38213e1739a0d46ee5987504810d96eb5a42a589e717cf832e2a675aa776471aa3e4d6625c12affdb37eeb0711babcceef5a72e38f4848e6b650e7eb20dbe6197bd18eb2def3e16d0ceeb0bdca7cefe194f6884e907172b2f1eac18ac62970b06f62d56a2e169cf025c13ca1c27dbbd109cb2f0862b9394a981ea112c46d054a8ac48587dd59b92c145da9d122203ee412871598332254ce4300794d219981f13db341aef8c36167da1fb862583088ed70d89e03c38e4e65fb44ebd12046ba4e5df539b5c887801f22c47e611b477d61c55b2ddd94557ec9fc865137c2b0fa1959d6e2ad0cfe4213932858a6cc4941509f2f20193f7a940768f59e400f4231657471762e4217a1253a47bb7ba45e0859c082553995305ea5937d36047e1040e5be54c21c578315b553fb39729932c57ec87abb44a538dd2e9a14229a96f0c866eba8a520e0c84ed6cfa1e57e8f81a8db4a70b4bdaa495dfa1c976e8b5c92f2e59ed30d0bcf266809abc7857e795951c06d80deec776d4067d1553fbb6a4c696e46ef9b54b54bde4e9bf90bb68a952c89d99cc7cfcb00b050be0c9a476993c2c49e4ae5a54505ac4c3104e6fb995cdaa591658c4ce02b5921d121247224a14591598328279848a05daefc1a5290e0741df15efeca455b86bd5e615f233006b94086960c088b3c70bd6f972c89f3bc2e79fb93368a3e7579bb074880d0b51cba2a4658cf83c6a6fdd6d3fd54974297738b2d58be18c9e120174661d656a45fc2ef974def5c93a7b2db5e24481fb46771bdb1b8c1e1d858b84bbd984ac13cab19dd8846c14c643a83721093c112dacbaf87a74ab723909423cbff584dc07fbad16f981dd60d81178bd76d23566bbf766e77518cdd350a0199ebb6bc32dfc695e379843f0dd301d3d046e35a51fd7ed9ba4fe1e9b9bb5689899ebff137120af01a2d1dc68e08bf4e179c9418883ab82112a553cd506e339a1b48782c8891071796755dc713eea0c20a3855a69a2cd55aeb93ef5d442b139f8e69dd1f2dc78a4ceee2b0c9cf0df3ae1e9bb61ec21ffaa567fcb8d50dc174e343eb0ca3718312bf16888edd414a3ddb1d644087ed395d10767031ed792e0cd591a55028828a257d4abc7656ca2fe3ea0dc6ac609176ceb92fd629c28ee0179723ab8d174c821cda48a91a6c317e178626e53f16fb20b2742b8dd73800df074756eadda83af3009abcc19eff36b80488a527ae8bf5719a12c3b0bd4e5a98b5dfc04ccc31c23df32888ec1fc197d26f2e484c5519114dee59529425b481906e0cf3239858a986c0d9e93cbf28773a4e1f133444ca12b9b934ba6515239551f4dca89652285c2993d0f4360547b30f20e64548a4ebf2ca44dc0b481faeb59ea5a6111907b4ed2d1fe84148189c8b1a8d84a4cee667e06b1e2d2ff677de30e70923ef554f175e9011a373be6e99d8a8299c13db923e3f2f234d8477eacd8ac47a9c56b97478431c0f7993065177a1a1522cfb1c88c1e47b9a0d8b4eea8b9a75d35432957c5fc4f9a5b15d6b68d0af483c50d3e97809f782f9bdfc025c575ad7759546656dd39357d050de280852c6a4d3f57e037866f9838ae595f637d4bb5fed90a38fee1c4fc12baf6db24e83f6b11756a203904db334b6df046451ff267de3bf2138b61bdc5269b538a7e9895e59411a84bf147ae9e98cfd0cd221f1c40e9fa7383372a6f3ca5f88d43eba34290879dc7a9f69cfe3cc2459b819b61c627243bf58aa5c6a7267ac78cf042f46853d9b06c963057574fc01a8db60a3dd886596705cd280d543274e3b8f8e96623c1ac5c866ee533667f6497c312ad9ea725ab6f53478579fd871235a96181e1193637de84e80dbfc105e7572cee58b0188d7f1f6ef51f24e8dbcacc0232833af1324339273ae3eec10f8b0cde8cdeffc02c572ec49010786319d463ef2513f320146103ba3b82745c308eba9a0ea58266fa7dc08955740b5c605360b57c5f66d484a679b773ec9080c49501be08c87ebe00cd3cc310ec0ae14caa4340134e3a5eef9b4c21c36e17e94fcf1adce9e476981795bd72a191e668c416d2f6eeb6e59652a62465070740072e07dc0bd93a300572e1e675c7820a9d5bdeadd42b485ba43cdd82ee47b89784eea7d7fdf723755048f7938988119095cc0947cf74aae15538971cd6420eeb7b2794d3ef9813d40cf8a98b8a5cd9d6a71df5baec791c28a43eed7674617361f251c3c6b2a4c54e9a2e29b0ea59df48848afc5bb693c3dac9c9a9072ff221284f5072e64bba27a8b09d5af4204a1d095585448c88a8fed5bd9cadbe71f8ea42229a9733ecb416815aac34208f1f0e7b5195eaf10761fd2afc593deb71c8fa9fd56af5abb0c8ccaf1e874054cf0a8918adc21f11bf2a0c419553b0e3708ad11ef49d195d56a864e2985505c6de6254ff2510cb8d64b26e92a6d3ac67b319d5e32d79227dface5c25c03b64c6913bf325173c36d2152cc1489f1476c8dc60e44e3f09f43da99346bb81bda5b33ff6960fec2d43e099bd1f7b4be88386df8e077c3b663e410acc7ad58f8dd43497a8dd36afbf11bc67f2d175a9cf7e273bcff3b13d15f2fd043b157a4beef7b8e46e2cb9bf91c03413ad7f0a5d216f2473cea80b55d4471794b885d39e9528da09a8ad74522389c136a42e22f0d8484923914ab57aeba386af1f8d444b809b16cea816bbdffe8065142bc98f51921f230f4722d60799628c688236fb2912b29e1516f99945b4223faa67fdcccf204da4a22b27122ba4edc17cfcab1f659415385ce118831d366b4d4b93c98fbcc621817d24d67e8eb65a92a4cff6d652912d14965a1acea4a31a064f30004699fd14c8811df772468374cf853f463ff73b4ecefc7e2a1cef0d2507ba30806176286228b8be9cd95a6e6ad16e16c98643e05196152061f6adb5d6edbfdc9398f80226db2ddb9f5062748fcd91fdb9c5beb4d6328151629dca23fb938afd293f13e48e0d9f6a9db485912dd26802bfe8b3dec88c035fd47bfa9ef7ac9008ebbdf0e7fbd41399f93ef53faa13f2ffb4de7b16f8d33debbb1939e03a0626a2f91fef67be051a01e99ef53cbc87267cf92b9933a3d77d2034effdf673d6fe3fadeffe8608f09ee681784ff3fe3f461e02e9bef53fded3fc8fd116026985f77f68ae7d1a5ab017befc573ff3ddccea675e4030eba9ea59e05773813a2ad44c1fc7182c6746f4f3fee52110eebdd4e3f881c493c91cd61cf8833a288158f6a7e028ba9864b2679e91ad2b145d4b29e58b0a9e7276695a7eb100a7e020a5e38c1aea9e9f4535e35c629ab59e13706ebeca27305db8508a23539dce01ff7ff53466cc7819353443381c314e38ba38d77fe128aac21a8e327f854953fa1196118eef5f138e622b1c63b5a69921d6100e41f07e27794f083812e64f461613bb7c275d1b7a0e0040d9b4ec34da2686aebb4d7bb282c060b87bf794ee02edee6edadd9476373872b9a7cf321f8539d9d32d09dc6b4b8f05842be12f5dadeeb59dbadcab7d4aeb04ed579a6f485d2d23309db2c55a3f2d787e8e9672a72f0d3fe70d2cc051eb53aef56f0872ad4a3674c9f5ab7cc09b7190476f8a1a92100293e96fb8a3a8354a84926ca5b243aade106292e9d35aab8e1836685143982a5c706156eb0fb9d62f5799ab0cb629d36f117ed46a24268628a2706109125866b516e54ac549ae55860f4383951c198431e7c40cb6e97aa93db208da9466004388f67042b24c5a70a62a044393a002212a65c9dcbe6cf9c2a54eab4403112f6c36c460c06022d7748928c05e9659b278829100e36499258ba83c62f10ba727b4e5cab20516368f3fa5dca19fa3ed14789c436456b42642f6bceabb4f2993974c2514322d273c00859fe0cca950f6e7a3e33ef5db4b0fb73c9ceaa1bba2543887b660224666aa4fed806b1e9f0b7fa8c2c0e31ca20d557082a13a4818ad4d010593964c8fc8f4471911f4e7049a4095fe03ba47cab7639280c9c2e9697ecef5ad222929bb97dd6f985ce9095276e9495b949e38653adbc79c20384cf2a0603b09da4cbe6829207bf27c7f14b05fcfc969d1715accd101d71f71b2879fd3a23f8665ff6d0478944e3eba7e8c752e830a5dfea20c4a64f7d9b783c69716dbdb3e2549292500b2a5d6565ba96f1b121dc8a38b07198490ed1e065078c4221358059afb45e802dcefcfe19fe2c8602f13ebedaf17bba1a45f0fbad1c740fba04438ff948729d057e1e62977eaf75824fbb70d652cf4b721d1fd5a6b7783a0088f3733d92a53a6d054c184a60a2636d890840d33ccf032a74ed1841f1434814e2174ce06cc16a5218ec5feb5041e63fff37380346cfe30014ea5607c4808f12121440baa0d50903aca1160a2d86dabb556bbd99e5270dd68583efd1b06aee1ab7fe60e63e10d392738f64474cace19043583dc45e089007beae7e7108147093f80cc94edbad40c21070f1083ad0dc4116d282be18710f865503850ae6c99504a41c19f9b5639a7a4f425f09dcb90c8becde958770cbb2b05430d47fc426db7dd22d28be12f29ed6ed99422e1eea8975d38b4c56e2a84a951151b266fc3e4cbbe9b531a7ad98244f75e4b3d69690949949f63ca29a7cc3165eb88f6e30d30bfeed4dda5b4a981c17db395baa49c51c3454e96b5c67a6d6d12d34b73299de15adea52cdcd195a7faa8089f8a8ae0addcdd6ba5b5d64a3b9c929293f24ab939b53555069d73f21081ce10bd6d72a6f794524a29a5f2f502e1480d1b192175e10eb9dcefdee1f8fa1173987c569eb456bbdd71ec57e5afcb0e4af9d4e5e3ebe6da79524a29274d4a19a502a594524aa9d7b5524a29a5d4fb542b3cf37d18a86cac5c18a75836683c0ef42eee928b044770aca19452997f83b97524a594524aed6d5fdde01aacd68c67696ad4dc8a5975061c5399db6a64cc70d9bc6478121c0130c3456dbaecdfdd6c90fd3b9c9ef18d5073879edc49659f8181cb868deb06a76ce4fe8e86c7b97eec1feb3bed9ae9775d336db029a5e1b5b9a95123fb77e1cdcdab064e8b8667737f0700ef29695455cd8df355708ac320a536b36bbe8865595d4d4777772ef07c1fa59452ca9aeab5e54949b3497a299da192b2384aa9ace102bb7baae54eb5dbbdabcdd6ceabb4aabcefb374deacc32465e7eea56ef348c9b1ee8c47371a8f4a4a6dabd64cf95eb3943b94565aa90c8f4aea140a6af4dae5dde6a975ba3ba6b9bb53bfb91100986aab9d9133f65f5f0f6c29ad332d1a302d9a992ff6267405405691810c6a6bdd2a4e8d960694564ab3b0f645ed97d60be31b3b43ab9db9c27ea9f7d28e56cb62b1baae7bd985b24c9932b6be36d059bd6e7476543796565ba68cad3602b8e1d9dc8875ee9303ae034a847670894c892385060e0f2c0d1c0f78aaad0183f3e2e9a1d5bfbe2c0daf96563b64da4a3ff09922c5cde3a4fb767476a7d56e38346eb27c7a656d819c84d940a062cefaf007c3968c97326a70c277587f4d173c7ffc57e80a4000bcdb354d19c8c820834f47fd1a35d4abb5bfd91a2d0dea8b34d4bab442e3d3e12ab0228c7e58b45e18c33cd8a7637b1b1b78392d977f5eac4c242c66789b6c6021a12934a9e0a821f349cd04d54766470644f4be173f1daa176ddcc0deeabf1e7d801956d779988ad7f94af50d994fbcce0415c8c88070a9af0d7456af1b9d1dd58d8ea7a323bb4957d66e98306f34ce104e269b4835cfa46945c804a1c9ad5e304436b9e4709c5b643602b8e1d9dc8875310e3a0eb80e3af0a4f4b9dd003c297d068063436a1107081a383cb034703ce0a9b6c609e7c5e3d1ec49ad25266ff5822ac5faea9161b9483497c93e1df46545b2cb200cd9b639adb488a58f9037fa93903bf5034f4a1f1f4f4a9f248c5d5eeb8dcfeb66a63978824e0eb23f75f798f489c91d9f14088cf1c54e0bb3c316960d3c44d1f4d0d492e202950f543a1fb2b84b5d23aa218fddd460f21cfb293799281fb8c8aca7cd63e38a79f5d28725eeeb28f900743be83a294de48e0c2e410f2f5c2994789062edd74f8725c00e284852da61092d1b614daf88be3a8871b5e8a04408997e875d2efa2e7a058728a40ce145174e66f4c5e6a9405cb152e562af66091e4516f20eb976453a28c1c9f4ef3645173599fe96938229327d6a37a5211e32a55fb9e4e420e50465327ddafda083031513e4e042a6ef395ea26891691352e0f18a3a50d8cc8cc04d578c1607585b68a0c4e0021e9a8122f4c28a5e160f4c544d2c612a4e3e033411b5520af29c545328e94690f44141810ba9273c2859b8c07550bab80618c1500a4a18306c475c1420254c51624862002786a2387161a916258a0b062041541422036ca145a1c2845e2e3480134b51987819c53aa6650b316cb8803924b028304cc1ad2cb33cf9a08114d826cb2c4f48884cf08c2cb33c49914197272d32e0e2290ae604af90d4a8823f2736ca60d6908d21f08a080d76c038a9c613be4c3570c03335510b5e6599258c164c61c0a8410553174416b08d013606e69e9c00df285b4809e307518c510d1bb097651631546a1c65119374a41613b3c5d6a493392924302bcbaf5f18065f292fe82370bf510a5aa048ee14787bfbeaf7d519039d4722790b715a746f5197c5c4609fc205c4eda2058a5db885f108c214b1618c714be90616dcf09447fcb48ad32d98eb965d0577376f5c33601fa9c733a6e011a7bebf9b9e6cd93e02cdfea927f8738e965212a9beb08884a285312420a168610c5af6fb94e3387ffad465a8c54240e58e87f52be55e8242dc3bd9bd48909ffa1da9972ab8a42f4122cf41dfee0d456858e7f841ca0f600b12794f411cdde37d7f2ce6b21c6070151ef2289b7498b8269d2b0afcae16a58bc0c3257379cffd9bb70db4a0dc3102cb5047eec8afdd5feacd5d0098b08ef4997912f1a72111fa5eb885dfe22482df3f4ad5a9c019e5b04afb81c4b1c3eae3f7503aacfaff784f7f23a13ff5fd2922aaf0e77bff2dcc6971ae5ef58f55ac577d10d6ab56ff839f151209b2fa51fd785618fb9574588ed81830f4ab53a039a32c14a1e14f051c169ee0b0eafd98d7f6347c6d21fd1ffc1ed2573da534a4d1b0c8cf1c72587dffafbe9c85627b30df7b2b68ad8f630c7d7f2449e87b9fc4ffa3ef3d10ffef5b416daaf0b5d5d716fec0db130caec0090536cd61f53f1003e5fa9c18dc42f5c330b8fe6c9a4935e9db42da6227bfaefb0de43e9532d21f391b7881c7f76a10264196c9aa26ecca4d690946269d4128773f16c99386eb8144e40b8018439b11790551153902055ea2663fdeab422233cb0e3800cd8a7020050c41b38e6a0ffae5ac88e442862a42332fec0f9433d79125a425ba24c70b4573b2d2626f791d61e9deed515e774322ef91bcc76ba4f99130f34c016d246107da88c2374273e98ffb7602c3a979c6761abdc8a19a67742427538b1a3b6a49f38ccd25b7182ec678ffd5c3bff63bd27b91910374a11f8563913cbfa1644079826d942f28c3d85244cb0e1a41e28129cae40df49745cd33bfc7b778911fcdcde57228177605d1bc47ce80f2903bbd8ed80277c2118b39798f87c31ffc1f0e5ff3677e5e53f541583346e16bb258af7a396b16e84e0ee5b0ef3d509643d603112322ac377afdf03e0172a6fa9aa74335e0091f58019e54cdab7e944d56d0680eebd5ff1801c1ef7dff83c339e4b0a079e4b0315ff89a0b50bdf740beaf098918f9f41088eabdf766dec88c45f35f8df747e6ccfb1f9a703239ac5f334ce187745802e4cc0487f51fa9be6936318da999504d5fcdffb0bcc7615007d15ef3ab79ef83d4d484aff935ac67853fdf7be16b862f04785ff341bcaf097f8c80cc7ccdffbcfc695eb23e48cd4cf872ef83cc3ccd4cf8f29ff19ee669bcd6d3d474d00254bea505ba934371636067f2a5169de64beee454d4475d94db432ceed44950ee1464f5a3fad53b943b2d60155220a73477f2aa38aacd3ea7e9984b290f94339af43ad2d1dc21e9eebed7e5925e28a5f5012dbabbb7839fc3eea639e48efc98ecc529bb3bec965da48d7877347436c7032692e6a18f3f2665b247ce205ad417292515593e0a0e90208490a70e52ac40210cd5202ba58aec3fa5587fea604576b17e92303ec78657c8b54c762bddddaa6e7882dca92fbde46a240716f8a3c97348183dfac0989412e63547f697b0fa29b0eb8fecdd7fc20b914db7392f40261ab4e840c68b306ea8412cb14d7aa82f7ece5b31b48527bc58b550c33cc1b48277d1c2e54038c3ad6d58704ba48262b663b3d25a690d16f097a59210458c21c4942d4244b13428e91c2658760068be27440bb93eed5ae9bf8e00aa1845193d512962d43f2f9411982deef9a51941e132bb7928eddcfd7a97a500168a64f76e760a159986f386e3ddc2117b8bbea82c042656b64d22348f540a6229cf20bce45492d29424733ad7c4a9e3155869bd7a3dfabfb3877bf94f2499c8ad9e5ee656cfd4864cee06b2c78625348c3e0d65c3c601f08c2040691ecf80a4995640fa804e7d053a54c20f1e4bc6abc210155aa443c20a04812f7d2f2e2a32a514082fd1a73fc42954ade17e377b7bf9e9f0d1dbc66ba7bd96c6451e71be933623df9f136886938684472fdfd4bd9f0af1a4f590835d54ffd6d0fefd8e227de41d7bc98ffdc40b7b68389f72bd3fadf4fd09a57f7669f55d5cb66071519953eea7eed3200273299003abc0f38fa84dbe3f6fdfa121fcf23bf768173cb7344f33d5ecbd6f5fcb3ce21291efbd6f8ff09422af0b04d8887b276dfbbbddedd29f9f2c5f51facc21b973ffbe0264cf8442c29898b46891573ef8401441d0c686c5baf77edf7b7f9cb4fcd7730d6dddb5928142fa90c3a40fcd15cc60aeb5d65a9fbb628bc0435ee7dd6ae55ef0e762c04745cde3ea82bd86a5fe0643f64c2aa496fa4c4c5ab4c82b1f7c208a20686353b93c674deed4af453e44471f9252e4ceec41faf4d76642dea85f8b724861ca9d8aa536538bf53beca5166b95d4932e0bba1916a64c64cf0974932dcd5b30ff205b876cbb06dc2b8041a579f05bd6db6f26b2c785ba903ddee430e943b34dd9af35acfe3e0b9c605ab48f417b05db22b037794f7dfb2e54e59d496a81d2619b17712f7031e0f9d43c76c4f387a25412b875381572c73a90f441923e7e8473c081b43890088236360e2404044e026f368923913bf6534dc224789c4dfdf3de24202bdb5a3b9de40e7d9aef4f02a3e030fbf762ecae1702ead30f529f86488064b3995772672d18c038bfc8f6bbc8f683d0a709914c27c9817d25773613a2e0d65a2640b98588b2fdb63fc14481ddc99b869ab2c5d247faf474923bf6b3ece91a562061f69998b468b922af7cf0812882a08d0d8b85b36dfb6058fb36083c7ad9be0365fbd6eb99a00cae0041d320041843d90801f6c068f0846590400c836fa8d0f0430f5e7e1012bbf80106b10abc7a0116633420c236592a159d40dc01d764a954c484175434d001b3b2542ae2c1865091932745405ac4d8a0c953161867a944d4e5044426d8801605080606930649b863a286126c97304289e8034c4440d8d082b72c958878f0614eff6eab57473a6520696459abc9f293e5947f6c88dcc98084f573b1828c269cbdae7379333a9547af87adfd6ca5ab16f67ce5ad4a2ddeb6b0042379ba2a75f9f43a4ecea7a33e6bce1c8b43591c48a704e1d69aa0a6bc413d29592d55cd274ef73c2a6578d2a3299b1befbe365b43c16d9b7f73f391306987636978423a413940381d9d8e3f59432303261e0600e87e8f36a98c192e9b9b215907fe8694fef0b1e6914a4a185dc9743f980274c515474041c152a58244169dd36ab7f196b0b91893f993c78e7443cafbde5bc311d370e6de5bfc28b7f42479073ef83043972fb490c169e61ea81285cdeeee2d031e316e9c7657f3c8dcb31ebabd79db7bd2f3878c6a356d4e9f41d3c1f1a64079f8903d43648f321b903d3c96e691251a1275df605765e50196d0b0f9dc93710ee540bda039e49ec354c90c85f69caf21dcca5269862a799c41b98416271641997beefdab7fb7c999021d227de66637ba6ddb6fdbc681258077ca56cda0a01fd913812119909e0464cf1087bd181ce571b3d611ab40f9b5825c0a747a9dfb5bc2b7433e51f70d689ed8090d6891c70c2b37067fc63a416207d528d149efe92b5f94116a7532bbbabb7177775f8735a6d9eb6eefeeeef65abcdeddded6058da4694de48efc9512980cd49353d214ea204a29add45b4a995c1aa294e21a9e2f7f8eb329cba7b44b8bf273b4982b78caaf1183e5d734a5d49b524a699d492df250f711e0299b5221f49fe60ddb2f3b245264e645ba6750e041b55aedffbf56abd5fe3f6989e9ffbf56abfdff77d004a189f4b964ba073b3d413575116e72393d54510bcdf0ffff1f4c172e5b269625115ca97708171dfd44ba40ddd3b55aade8a8a8a88b7e740d045dab0975a935d56ab55aad56abd56a35ef367501438518649eaaa8d56ab55aad56ab79d01fe9ec745aed76b9546767f267e77d95e33e15bd57b5f26da3ab5837f32cd9e4a2d39680986a28788f283a2c0578662061f55960fd16f22ad21b8a0cc8f6eb513beccda709824b9ffbf26717f9134b6c224d2bcdc3bdfc7ea6a79b9ac9752fc62ed72ff912153ca548ce225a4fa12cb97f9c4eb2fcc9448230b1cc1bfd92e674c57c856aaadb50ba85baa4165241518193502fa95a28053912d63d0b94123697963a550bf92a945d03f2fd2976affa7a7c4e85aacf87ab64119e3fd4505aeceea1bb86b6e22aea1bb078ae610bf50bf5ea1b81fa1337fc277b0f9617f39e6d06b56a0cb0102247510b5ce00596284f3851c4154e30e960adb5b6061f5cf08219c22ca104083ac9cb096e1212a37ac55092263b34f1a4cb17274e6c5189b842cabdc208870eb2b8e00b185b64698111f5083741e1c15eb1c24cd312375ce1845382c3115a94184af08014461d02045c962748ee155090d45a6b2d81184b0606ebe58a1a85972c668a349822040690c00287114c11a6c9163329a7796e9e33c9262182cad01412601ebae01b9e10a203415d82a3329f3d8284e65176c90e45a61ae571d226d05c32859c8825398fd34af6a67214953d004d8628ba72e5ca0c2cccfc633c4e9072e4055f4039e1441033ff19348b3cc9aa8e58248bad73e0459dd8d6850a76d8c24b91951cb4f8a18bebc08154134a6e70128515485e70e1160890baf9f385807bbbe97dbf79de77537f5f08d86c98fa1b522e05e688b5d31008f75dd87e432e1c63a1c3a6ffcf7dfbc3fd06e4be0d8170bf85f8b3c02c937f8ce8ffd84ffd6cdfbd7cff5e08b09f7a20f653a10864fb2e7c8771e06bfe1b995d30f5f7132067ae90080e2be46cfbf153b65333fbdbd726a6a47207676fc0097247be6784e7c75a942f71748fe01987dc915fbfc0217da8b4b96a0007e562381a70824c862079b6cfb593390c662061dcadc9a59e2c3dc81c09997ad0352a1a19302053ee3db04648a63f45ee7b0399faf07cbfbf03784e4d231407acc608ee4d11ab570f87f4a13e3bd596872cb616ac68e10bfd23a4ca6502b422b43801921034e952a72c81258621ea0b2e822f5c1430d45a6b350192db4215a0285a40e22f7c0ece52e9a8288f1fbb5e0800093cbefccf1175ac064af866a97434248e81b72c958e6a68131c31b9329924b11c1df132c6568778ca5d964a4378916189b5d6da301f688d59d244eb8b314b527004e83b526bad958b0e1c145c8078a116610598302ab8428c099284f1c3064518474a66b8ae219686b052a543681e2ee575aa6f05f290b0fb52ca5b94650f7658d3af3209bb72c9089228e3910273ae091cf852bc2fbf1ed4f3f6f8debb59db63ae902b5117b61ad65a74a28eccfed441c47aa7bf43e6eda6783856ddbece3cae3ccf48f6c231a65219c92a8cf11bc9d88570bf92592564f51cf72bafae563be4abbe7d16a8d330fb1514b9d48b62f35831d63cdc5bee6e7fef9c77daaeed169dfd252592f288979440ca7666bd68cac9f62f879f7e3a2c70819953bf43666ebbb5077f5c0a9c92b2147024a9a3af7a5538aa8c641a8e3ade774672178eb1affbcf48fe7aacc6ef57a191bc0a475927a4be4a0a517d55a55eb5a382ae56ef90d95efbd95a6b3710079939ef9d3766a1aab413cf5a67752ab3ba2783a58023b516a50bc7f2c764217c9db34e20e89c73fad359ebac4dab774e3178fc1ca7230e32b5d6d818f27ee02bc834ba3fdf2bad94d254caa6524f53a930265bede05d1f62caa72395024900755cf04542cd1ee851fb77bbee479c5a4cfdbdf47e4e419939b0befcb617f5177d9a690c31269c20bc796013d162313451327b05f929229d88528299117d2f7c059929303935cde67b2ee6a6eb240a542a0bdccaf2bbf995febf101aa02fa8b46df844b5643403000010042315000028100c87442271402498e8c22a7b14000b778e3e76582c1a089324c7511404418c318618400820001162184254441c0020516c50695ce0c5a843790fb716cc6ea340f88e8727bec67ff44a591a7d4a03d016515bb9882701a944cf604088a9ac816dfba7aebf6559b1951f11acd87833f99578132e8b05894b0396bc3c14fda0d81c251ae4becb11b87d6df5b3b22abcb0321eda997ccf0553aecfa2271e5203fbbb049c307d2ddd77ffdd1754039b8b1d2194851b34e639d94b16d7181c34417a142328fc0043766f574ed165c011b932275e5aa5044c2139dae091585a8e578a2d1336986dcef41d8a343a2909289e66c6fb733806b46ba64a4123c90e2d87cd49fc6e03bb9a0322f89e04b7144b6a4664b0e235b373cc9dbcc5d5e9d5fdb4c8ed074022da12347a37f75f2637d809ff5aaa49c1207e4dc0ff36febd6f733da9323a466254a02390fdc1ab8de241832d2227f81dc8894000d566a6afda11e08d31ac4a34960b097c22b653a056ec1c9659af2a2c92d5f952168d6d5986da6a861728ed695f7c6c98bcca5dc585b20d0518e6d7556507c6ccb4a8aa2567ab12d6b5f718f3e062835b4ed068940d137ff25650e8471bd865f927fa139ddf988d7bf7af073e58f322439d70bf6c7bf81e675361d6008a9efe03c9fedd952df8c548de5ae9927cff1c0ede0e57e01cc7b5c0299081af12e7d99a239d46af049179cd0789f2245cb38d45bf2015786f07f8e1a444d1c025635f92dbaa09a50a1de1fdeaf02ea3ad1850150a7045f6e050e9a2af0c47432503e80f843ffd477f8bce44b7a47a9ec4daced89ff4d5e0b1d45d5fc0c678f68eacf4b061d677700538d4a1cf10b87e09d69bf802f9217aecc4edf23d0ace0ceaaac108501a41eb2d5ddc178b53990499e3bd7b804cf315ddc373618138c396eb1b57f2049a2483ff4f90f0322dd830fd256ff00c58a483c6fca47dc0dd3bae6e76f484a42bfe1f7a8d396f725d1c9a65527795a846f3d77abd5516e4b1c1648c87d555170d21316494f28c21cc8b32eba08697c5b3e01b72b4be9a80c61682a1861b4266e0a026a09947b0c78eed58bd7b674232d34f3ee7f09b099ec69e57efc7cd1c6a0907d1d0b3299df18240ac9ed79905926e52d70c2b08e8326c3dfcc503b8f21d7e589eb1260be009d1fce33223a67972f8dac80c55953eb04bfdd6b53088b008f77a3471df79b12c164b189474cf3efd82833d3db6ed2baccfd79e45b364011f2ad740de9a8407745e2a8d7de6218527b48a82ad9e5979aadf0ad542059db4e4eb07f06d3b5a0f0311f719d8e85d7f1080d21523f8b68c310950d4300d1814d8d7b32127e42d4b5553eac0874ad205acbfd234958e4a54458423f57cba213eea0326806bfd7a5852a4fbbad310b100e89ac16834a27c0019f7406e91b94b91acd056b1e086f0326a5e1fb51a64bbeaa56bafaed72b597588ecc825c9f9f1d18b473276ebdea571e43284a417ffad8d58c788d207cdded3c885732d27e8ba41f2c5a5d03f1765913064f5e9dbd73d28da823dbdf12dc756b1106e6793d369c239adfb7dd33f786536e4189798ec9f9ca3cc61a638e4a5ca04083d6548ef7bb3e1bab03d208abb117d6662c2e16ed826661bd35e3aae3426342d13bb8e7c569d7d719931ec6d173374fb16bcecf9b05870168fe1508c6eda0ae5867260ed3cbeaa26c4815302c657c4915a5af1328cdcde240804e073031cba83425810c6b8013a379c53b30b17e3527a427b35937213b184d4132e9948f5438601f71afc250e2c874f691eafb9a1a88252063870888bc49ccd9e60c85ba3651afc0b875d9e0f69f5910d01be54d96a5bc92d9dbe7c20450de810987c49b1ec4a39c71e988f3981762514d65a19446c0ed02a648abf4b43e7910c4ee677dba24382c020ccfe9f8c90c81c12fb4c9a675a66fe31cda40caf4f4698734d3d8d1041ab89e910b5c700634d049f665aeb12d6fe1c771995dd38518b11a01f0fa0a3ebd4437b8733e2628aff07aca3fa00d3b69c9fbcd178bae094903a04265bbc15b8b67701065c920096c17a21aa166da90b79884decf2d5da173f54201b7919997b71bb9ab38089fdfebe4cf5c88ad97802c2ca559d966c49b1caa2065e3bd18cc909659a7da867a78ab4566445521db5e200f5698186f40151831a1404ba072a1cdf1ba4319e93458fa4db89c9679a2b4bbd895ba381cf36372b3dc9bb3500e6dd863033007b6874ab93f0e2d795e650d0d768e9eb827b654bc44a5cd6b404ad7d646d3ca8917eb37868c8174fff3eb4372d147d9d1ff188e24667fa9ee0968a7366c10e2c4cbef1adc26085982e28947bbb1c907cbf8363e5a3c4a5daddcf20f8e96edd4c5060ce4b4d5102f4dbe2cfdc6b523f559a4b7b4df7592db24bb0fe1038d4813adcaa8b42055120979520b5ca66ce2dfb229f4be442cd08941a1591ad89622a79db854716fe4a94c5faf8e129cf94de03152c15338c9c68a0790bde558927e4fb6f28b26fd68c55a61a1a8906bd6302deedc17b2b996b196186e54a13cd3d7c2c407a9e284ec8dc8add9b6fd1049892eaa0451f25be43898ef8d567697653862cc6bc1628fa5672906520457d2bc90a4df8c8ba0d041aad13904562a33b797b1bf06b63a33bb5d9602cab57fa57b4c9c729ec3691d09be1f09415dad8cf364190135a7898d270a88c1c200671b8e1c767971b892a02dca774301a69c277232c08c7739d1a0ea04b05e44f67a84c08d1900afa40c3b704c9b44bbef45b57eec3fe374b339c86451ce7300f0d58c0c92cfc22850e9c33d3806099e4dea1b02589b7d8a2713799084703ca7f4e5ac476d70fdc7a6979f264d810747871fca9237808392b5bb4ca721f4c99a7a82070c65e7794c4f35bc4bd1aa66fe42e76a6de91544f5e6a63d7d77c9e190d0f5c00c91a5bfe856dd3770c5e8b44cc5a6b145eb348b578e9e2c74c6b9abf4e4c67c473c8e91b57f595d54aa527c8cf69020f5c195dc4f3cb351a8ff6c5aa761bc46aa706c7a7d915363791a760476223edf30a6ce021b82aa8a7c3aa20603d009d37640a3d91e0e26b0c0eac4d5165ac679aa2884cec34761f38dbdd1dd2ec38dc3a31b4fb88812546426777cd3f8d24dd4840b301bd1f0f7945cdc8efbe6fbaf30fcb3f6033def57b0520255f1126e4605fb55d2544a1d3df0f77c64eef6a49dc46d89373c6989547b44d06925186815edd9cfb0197be2352f67b36f602d480af3c620ed5a206320a36b1529ce2d9b5038061bf04e5de27b0eda846f6623c4a221fd76652cd83572c9f2391b4600e92d9e3729e0c005af50d79013f851d7c98144ec7d9733a329861b046ae76e4d228129d8d46fcfeeea1580586971509264008285f2bf81c6dff8e9b3efba76dfd97bfa8fa2400e1b00a77a75e2278d42852a52d3037e8897d437e1afad513ba13b24821b0f604640821f003706f93e6f1936c0802995ec54d54ed25b18e5a9e4877c72b7e3f9b2e61f8041f3cdbdb019f7f89a0e1af3fbbf76140ce2bd03b89e16b36e0d52b1704d020a129bb7339b01ac4398c614162c0be8b55792b8cba87f93bb602ef2ae0f499b9191132c82edaf336c43a81e142947d037e217cbd06c9256fb496e75d4cb0a48cedd2cd3ce05691a418996e99ef4734b59626ff43a8677616ff544f830985dc9ff8e4668a5ccda95efe497fce8b890172f6ed0d254119ae31f69affe67fe8251055c84bcc7c1cefdfc6a007dc9049518ae28c4e559c733f96acb5e5ce305cff268f0e234be81045a5e9ec4530f2ebd060c813ccc892bf88d395782fcbbea4ecf2f9e95f91d090f47b2c9d1ca48058de4fdcf60ce8ade0916b2cfe757f6feb9d2bbd9f2f66990ff89d46eb16f31827665765909e4c5d2dc21d2706cc273b9e69fca00db21273ed7c06effd3a3de8ebe8506f5c5626f40927f7b3061172ea62c176c449fcbd5c9f41e30c4f8818017b9ef54531cf731415c7e875f283e601d9d3234f4fec46018ab325e6e9fb0dd8bd58f741a7f7832f8bdb81eff1b8e30bb2d955ac7c7643ea6d1a99779963d6a4d811629cc1975b20f9af9eac32c67eb9b67ee3e18d48ba7c6d8cf7ffdfeee7fba579caf0ccaa756587dd14e6aa8e49e8d79062aefa82e723228a2aac0da806056f60346e1502c376fbc55e1c7223245e9af5b09312f819981dacfbc1105996e88f27b6d2a260f2b6ab12d9b3386f80d78b0951874f8cf63133dc63bb2ebbcd76fc2e8805d8592c5685ca52edbd920df6a4b53718ed2d791f9005e00d1ef679edcd3ebf1719f808bc9c700ec06ace9efbc31d32fe3d033560c3a88cef583e0e2ca13b574c13fb9b297b9d74effd5a4640313abc947bcb48235e330b49da7720cf9fcccd159616af63ab41f5bd0478a8a602d9bc9345c76a1f2c768d0070bc2df3b9762e401c97e8bb2f1d1c6d19058897f729c16fc1cd33a788d110cef8c3e94e29b425e7496b49b33c89321d1774aed8e672925c966d7903d63a11b64323fd284267a03a1d5fa3925e58e785e51b5fd4f6fdad90eb72e7815b31d30f266b8c2f81da0d6983ab8c9e22618eadae426de7031deda7ca17804ef99e46544911d6a769f6ac7b23e441bc96319da1c8323726704782029267afd29635a373c2f97ff12136392efd0528bd44f635503d2b6a7aa3dcb7de011973d9547c7339209d46e40af776701ef86499c7628ba36146d1e12433b552fe630ac42bbe30669a6e871ef3d47e93023ee883ff5300c865707eec9ee9a041f818cd4188046798c741828b83c06ba351ac3a22b6c5d6e905d38ae6e37c40f0eab05871c69e0fcd2a190eb4311cc53219b458caef1b33cf7a71a8e80fba422cc9bf201ee431f7a0b6e77f411ca25b0cb22cdec8c9042bf84d26ef4de0256ec37278ac8722e894c203f5feb8ca2797a02f9d3845afbc130b3d9ec75f427cdd27f7d0449b07dd2a95f73c79ce9038fb03d2af94f4745114b63693ed184d4443adc1c26e7d5f5dc574b4ad1ef626146834229e5c9ed63185b7ee020c950d1ca715589b0a95cb61a2637b8bda10120a0335f616e821e4c2882b6a2bd8fa25bfa88924d14d7e2292e54eb4f7233ace3da17fa6f32ecdf3bf3a4794438f3b9f832e73723d0d393d5596eb48501bfcd3280e11c7b70a73b08927a43c4f28ae722771f07780a46e16bab5c3c937e23d8b55397514cb3a5cce89459f55b72b4088b91caab967ce8fb007747b3f38a3377c599d1fbfda1d4a7ae65002face8fdaca2b083553e87de3f5896e02805156e0d71ee5944fcc450d3938016013a8d0d709d97fa9948ef9207cf2e620eb3f2bedb7529e3901a75719cc88517f5102c4614d6253d2bd9d7f3ef1a96687742503a0360a71dc85094c76be8cda0590c17f0f5856b6c8e9c04d9816f8fa53b6c8394a6c2933e093dfc453042707d7f22f6aa79bc4e0d6fe2cdb17eef233ebdeb8570bbf30a952a69d90df002c1a0480005cb8a6a12713e7de42142ff5848b3fb7ca268e3e2a3b68876b6393064d894b7326f428824b0042c324be77ff4145704f90978a4a6277695ee7ac18805e2ed13220491286fd1039bf11f3b1610a83beb79f175b014af4ffe380c305f36abd6dad40e8e3339f4190bad78145bff7d0ab424c4e3724da2d3e20512c82eeb3075a5f26fed40f12974b1644aafa62b1e97558fc072255533367b0746defebbaf63cd091f31e5b1f0a80e5c22c4c34e1ad68eb0da9b6e09e9df2e4b0e440f8f10812b210395bc14e20474f06d54d54ad78ff27565432b1ac53dd1d64e3d7e9ab7f50875a3c330e759e76a60d351619070e8a1437715316f07157f0333351c899deb20820ea568cb675b71c669325247b479216461feabc23f2797848c42651ab3f4976d9de701e71d5df03180524ae6cb38a5c900f8924638d9271e1d4aee733217a2220062ef1ac5a6bbc00a09b7bcef4cb41146fd734fe0021f35c9287fadb76cde9ecbf00a4f8639982f1e20e837f12e970b55d1111850b10aa575306cc6c88937e41ec789a0f81da85df593a2c7ee0d7185a37efc0d726ef8a8daaa73a9f1b88eda2da7a2624a503349499692a1686c99990affad100801a63f31e2500cb32ed3edd8d85746625b5d94d4225971d6647cdbe4bd87d8bee7d788c2e16218e7a432810dcd67bc6a09266c149f3522282231aa885afc0dc742dbf2a0a645f40e10621d709016b6dc03aa38218ff47f8449dac78300e3abdc899cc161122be8f82e7d86395571c8db99ddfd8a92c2efcd3c0e9c084420cc8b2aa7d4846800d08002259b3ac371590cf50b80d50abae4dadc004c6fc387daf60d0f73e51a4ebbdebd725381e06c13d8afaad461d4bdac6dfb347e95fed32dd84707d07f32ca6244b938a2df10461f6158af9b71d3a2c966fd4e73dea272950b851a9846c02d36ca02d0b4c621e92e8d7300e05c198977b57e34aa1f504a2cca1f7609b776c55828c90c35a604d1f1af9e1e7815fd1dc88852026cd817d3d94a7aae6155ff30f6903703fc50f9ff9eb9f32fe84aae19c40179be7c0e0d927fcceee2312394cab7500696461cd20543469c71922e4c15f3a2840d5407946cb9c13cca6667b9bba34ef5563a2fd26b26adcee9eaad40c506deb068c87c28a25ce4ac7193fb1981c7e03c56ccd12bf8caafe96371002092766ba901f13c105ddae20b71281e304e62c78ef5ff360869eb60b84e979baf76ded16721e89990fef9757c959cf270fdc9007a92d0fe5860f744b21dede2b55f9f9facbed30acb4f27b4623add5a6a1bd44b4074fd531a3e8219129ecc41d81e185dc3b0467fb2b3193cbf141a8f30baccbd51f155ca065344ce171ace7d4a80585a11a6c073a9e3282a338de6fd909d7a9acd2c9685806d11f6b7a7ec843690d08de4758ca4c016eba7dc9475158dd36f00990189bd5b07a54f0256b2b59f1f41a361447127df7aa29af93fbbb1ca757b2b221c4ff0b4c464656ba560250a491a1fddf9344815e6eb19820539aeb0d3aa57ad05424a6be231b5624c67f5a3d28fc18442dd08512d909714dc8874a1c284a204882677679e184128b933d9e96c3a196bc83fc902ed313405ad257de8eaf0c1ef734314afa34d22b70319cdc419cebc698275ad5a7e0f7d0e3ea6634d65714e8183f24c12e8eed247cc5246843acba50287daac8dca394037d93e7e675890364fade86dcf4d2f603b7ed025608e698181ade8fe74a183a460f203a03301d1b6d687b5cd9af18f1266299f29bbebd3d393958679948eff17f5d158dd1457c15827d625e69fb0d0994f255bec67998c9ed902f3154110514b6f2984cf68f5cb7832b6808238148056ba51412fb86afb38d65140d111bf3e1a0d6b5febb1cf09dee7ff98f06b893b65b05a6871d696b1708848668c8621a0858a0aea2316c3a20e1e9346114f45f2c7ab3ba6529b167b7dcbb1f478316de045103127f2830ecd763d92e2372dc5be9d1daba5e0b5dbec18763e8256adcd88c32cf1623a6f54e8bcb99bad1a52ad75c164fdde84c114f6257022b386c038193941422130a3cfdfeb95c416c53b25ebe54777de417e7a79865af4a207329b3f84f366d0a115a3919490b917ef14941df2c6f27cd04f0aa8106e628e92c76b386abf9a35580c325f239808d13633d2359c95f935634f16862110ff3dbb64eda2e78e8b3408b41df9a142ab8e066798910c42a2e2c86f778a7c4c39fe0536876d398fb901f780516ee6f9ef91c001a22391747873aa6dd654e70d66690494da4be7e5a218b911f7c3464ffff6ab5c1ab906105991e9bedc147b01a25e2358f3e3eaa9f7e2cc1d9d06870495f6b00a236a19e17dc205baece553bc2f94b87286bdb113a4d907e11fb802b7fe0dc3748c6ec3ad468e4b3ed691b59714e2f8d78834f7b986706e245d9c5cb9c345d7bb1f6a1137232585459feff0a33b540bbe0f55bb801b70a63ee3423c03db16171fb19821ea326dfe2b6b058de401699069f75d3126a97a81111305bd5b336deb48c95a6c1d60130176523c1a6c1cc658912e047c54912e0da4c0514ba39f9e0cc0d06cb97dd6c367b37d6e4b20fd160b7ab8bf4bdd8fd4ac9920bc6742307d7814a0d64e44f9b0270d492111e8cfc43606b7f509b96ef2e9b1afea5e5b380a4cdbac54b35c5d77e0a53649601884b4e9dcc7265c8e498f944bd43268364c9c57306939b6bc52edec8054d740555c151c6b366a55014353356c4151efe858e441b2afb29f095e4aeeca0a9ac9c91e50b5616c75e515fb0bf67b528f3938124b02d10729b82cb0f88bec6836f3e3548a278eaaf5e6adce52bb018bc2404dcdbe27e4ffbebb16e9d44cbeeddea399ee4662674a28a2ed795576d3dcabc62044de2618792823058d130f0f1509dba8dc43108731970f7dbd05fa5ff17b93b6ce01e5141f63c36b34d11cc29939564804b9cf98fa249f296e16bbef9e1a791500b98c12d3713c4ac9a4cc2366519616a1fa155cd1146e33d8d35c111406c1e900cdfeda1e2bda1602fdb3479910d1254cce02482bdac45fe2188feecdf23492ab460f7765237debf4fa8f7440004671866716f439c3939aee079ae57790828fa349bb9d263a6fc53de1aa65f7c8343b6522fc59a19dea1efc54fd92e99485c3eaa8bc392d5adbe0d2c742cc64d08d007bdd0274dfbd7e4e16846dd8fbc017e984929526eda1fe97c23e71d8381d45648df37bf40dc991d9685a022fcb2430f73a8d1b755e18dc7a335c21f25552c127023ff180623d74fb8dd498c7c0c53986b17384ca4e0b1a67b96217030aa7a24d6c39dc41cb2103491bc06e0cbf638e0967e4d8961d5c5371bf354eb9a6a7529db08ae3ecd5bf60a94215cac55d92a107263f92e2aa3d2f82b120e70737471560f7b132f5d6195b82ceb476ec9a9f86afcdde12742402a5c9b227e582e934e83f8e04cc31d5072c195b491a00ec454738a82b297e36e1b334539516d6f86356708a0ad91bd17a3e2861af30ca145f18c7c98b646ad40de9478993f9918c256e14240ec424ff2200c2c2e9ee77c057e3cedbc9139e2b92032df6e4764cfc00cb65aae672077e2949452beb6341536ef657f79690eaac86aa564a4ee53279d7d0d1bed754bcbc7a245f24a7af98b0d3441b6a1916bf360ebf583cb3968289a564e3bee2055ff209388f81058b852e52243c1c49d7bb9553d1a7b649ce25e6c4a9c335932c39808f37026ea32410be16d7f918bf9d65221268f8996c39bfde4374b02342db7ac237feef2f9ce33994f69f633361f40cd70a9e6550e6c6c6336706df0950c26c55525a9f44bab34ea4a8afd1217c9e9d685badc00a47e5b009e6b15417f3c4591815b1640ce00f2774ba163c94449cef009505adc4ba48b53c434ba1431f1f818916286484b6ccdeb4f76c9259676a760d0f2e9c4695fecdbcd208b0e41e48ed125ea7a28d9be7c7e9565f5e8c921f2bce7c1fd8b03702d2831c039864015159fe7ea8654fde8f5fbce48815bf8955762b616da05f0e0887f2bb9f543611ccf635d94c3a751da38183f71316d079c35b84d7a9e628466c05a04bdc88d3979fdc3fd67c08e578541e6bade0e3161a7a8670a9d294c18f38dff319506a02f9bc8ad80b10d6cce1fb2e68f083b03d83cc02ed8640bd439808fa0e902e9b1bdb51c9db84a41534b246d4e5c3ca981264787129b1164a8d6456cd57d4187f155311b785b7f2de477dd1147a6c114e445221a6ce380101048e1501d44f5898136505f6841ce181730c0e68bda980f9804f9de6be6d8c04235a470124c35c3275b6b78017d61b3f6b8d436161f09091c9ae7db61feec1a27c02bbef8b141dfb41c8e1e268841a225e1fdc6237f6fc61461c18aa4161d06920ffe6744c87bb25d75a6308343d378e13eb44ee71f45f81b16a12a7f16725efc8cb585028e814547180d708f0a2c98d102e0f5a93cd99ac08949ecfc28accfe672a8b9dc0b44fcbad8fd1d461c76a4785d57f3b04ad5f994c4f8a3f60829484df216ec4399961eedee8111bb59b041e9232cb2e5993bd508f2dd3f02caedecf428c0189316ba87f4fa5819c0a9da6a8396dcf9874c9bc4455af3a5263274cea2697faf1f10784c703a3a8079ccc0f26eba12497080e1e73aeb9a8f995a63cfe5a93ead4e1d7ed9921c0c21b78af7ed9d9d516ac8d00726dc9d5c7922829ff2654d64ac3df22dc3e9f27f78b38f3f6a80d63e1ddfeeb59c42768c893168edc5435f85e6a135ca7173c5eb892df138fe7099c7c8829fe128ef49ab75ebc582d3fec530e87b688670d2b3f51a59b437289555cd744da04f10a7100f8080d8d13915d5029a6771b63da6340bc2c2b6cf1e7d87b1df146480e60fd6c53be531c02d7f31a4c50820e5319c61b4931c81b57f89064d8a1f5351c85386f431286892426ea9e95c099215f68c23817d38315e580e39936975036569855f2024f0f339652b4c51e85c75740ae3d9fcb882437dcec022489ba24b4e6993678fd4c85cb6493e69b4ac192fd4f77afdd3e09c51749d9b93a75d90c5ece0c6bd9eaa3a37a5612c74ba301f3eff94add6417bd2204c220f90dfd1c927d606604f87ca2dea73556214ddea13d917414d96099315a11c3d302b2b70961aa432ee50dc165bbba49cf4481907e71258e3e5a0734d19c2f008206abe48c8ba99067c19fadaae9a0899c96abd2ba3ab69162c91a215d5da5881e614f751c69a74c5d8ec0541a44321a03bf1bd64ee391915cd5038d361e37ab2792ac553080363067d2aca54e2722fc544d63423332d8bf308cc08e3d08c33f425ce8e346d51f7e7d94c3cc1d1b7fa20bc3b0b457824f69f89454ab1e1384c73e0e64fd7801919cef697dd5c24df6385aa71062d7e3a04952949e71af3804bd0b3d400cd8cf99a4d4460f3a05c4942d15477e4143f86439ee2be46286be9d90229b1d7881036e0aa80270a7e47164d5b8fea73ffa9d7657d06ce2b364414c833e08604ae54943f49c1c4f7c89eb0bad3a643f4a7bbbd4814726d02b7bc29f6731ed9445a2060d0938178914b0beae8f7e099838356247ea574a3f9f003858424155aa5ec5f318ac715bd218531d2626e1eae94eb99eeb1660916db862ed52f8fbcb132f1c00e3c1376729e78b6e1d22f022392c56cb67974b5fb413a1cb33ca5dad651c35be0ac24951fbaf1c6a8b0e93eb9714428b36af1a3c5f6995523ff86ca18ada0e1b6cff976b0cbbdae3162c284d0474c76219d3142c86f1a0f83351ba91fc487d863d747aaf3b0da2d72cec230043712e2913822629c2d91c62a5338c173fd7228d4769866bf789bc1e85307bc81fa78b8c26c24921b415ef83f2ab4875353c289c387a9e613003ceca0ce96edc0430c8f7db88a81a27067ae909a2b2cd2c8b292459df237653802698c8097552afb80ca8ce6c782812248c4bba259aed93063395176eba28cc17072f5e74c42e4ea9081ee104b169026353b9b976470f4c72e6fddd8f1e26616b5677e805d3d2ac71d51f895544efb86f0793ff0c8b699ea4626fbb2336039e2fc34ca11fbf1aea1ff22461fd60bf7d86bcd6f8f9ae30059de7583b8205e240f05a6f43b61d1a23545c3d531801e60f5c0794345072ea829a7f5084003caa1404b90c9ed84876b9c9a7499308a3e0241a4715f779a33cd5f302756b22df7357fb1a26bab7bf02d2aeea1db427a784fe1a9d878806a85b1fa13fb44416ebdd04746a4245ac7b06423ad9b21e193d5bb0ebd73db5fe8db522014398110173f5bb90341e0d9d38ac4f0990d553be5215d6da88cc15fb5145562bd38466a40dc320aa757493a26e4bd8cc12c5200f4c601ec99795c9210c916bb8941452bfca5eab46cfa7f1f174f4044db3d25c38b3349c5675e004c4d29afccbaf0a363e9610678b55dff82947071db794d94d186aedb80f6ae695c2194f3c7cae24d635670899d996977f0b4e3d4ef54190f2e9eabecb611d8e7836551dbc35009415cbba97e50b5a864094a55b5f20bb49b14d7e15f64cdb496bd219f8267b205aa024299fc8a5df6a7f3f7e94a12bb25854e64b6e281aa943854dc3c31a41a6450c3e1207acf8af9259f792fa99350769d58b6df6dbd1522e7596b6677b66a3f76be6f030e06acecf5f68d8a40c61d20a2bb01c22d8006f467573cc7b600f9bf859aadcf1efbaf2efe1590c3541f316428d05647046be359a52d6328fecd3f17c93f8f6847b2314e552497b4d47dfa1d5c91966a806d1636ae7df95be10bb5dc3d0c5b3aa1157770cd26017947593dd2910fbee83996c68d2ae693c959c7a732c8f3d5e9298123b66665c4cc6e24cf14022179dca80aa8292124653762758480566c448f9079840b2df1d0b4a2b50f644264db1291326804cd95baa7bd0cfa24e649777d366b895cafd16a72b0208812025fa3752c8e5bc6818f5c8ebda7fdd367d7bcf3558e3c7e05de9430f1e5672e579c507279ade88a4b255c3e593f410732bdacd11f0d6ee8464b71c0023ef79ea2a7a406dd5e1be32e97c074e302f73b5d99661b0c36efeb5c721d8297b8b55f92ffe75640d633ccd3a44a2c29f639a6361e462db691cf6b32444d6fbb6c88dc21d63b8db2cda2f012b7b46bbe2b253f4a63e8d0f5c2f637fad48f901167ef8aed89c56b4e7bd5f515c605b809ff0f41fa93b1eb003b85f02ae24deb775aff054ae1a8ef034aded829c7a1f7ccb718d58ff522da9f9393dbd1f130bb1dd5cdb6ee61ac3822826f9f61a678d6f207f3edf9538b5b9014848674b5071b07307b715b5b6f93c871ff56b835457f63366df690e1f806609675b9b6db0af3571b0f04420ca7bff53cb0fb062a0c609fc715ebcad55fcd9497e4e898693c690d7153509f252df84b7e9df9533c8d022876f93c39e017aaf07be45c268241c50b613a830b550dd77e7c9180ee43bdaa5916cd223c1566e96044b96e8053556bcdbe2a5c3b903eea33055eb817d7c36aae87d795f168247f29f19c195617b2e40cd6179ec4bbc577f86cd74d46fc1dea01a4f31f0cf07a7851a87fe99d472bf65330d376ea7cd3a0fe1071380d19a87dfe20e16e7399a10ef84f1560b71b9edc08d4e2d22a6f78a89e383b1edec4140b84191317eeb39055ebe31782fec44a591466b45583cec81642b3a89a6c32881be04c743bd5483b7d9757e0cbc73c3eea1d1155f35bef6af62a5a15b48e58589cf7502dc6432c0da755dbb264a596e9ff0ea95e14e0b0562b6367b27442107acd36a6b2ada732efbb8346349a3cc2b148f8e5894cddd2dd0fa54087e800e8bcb067228008870660f41e9614fc98335cbaf334c659e3fc72b442c32f9f9e23840b860f11fa5bdc2bc99beeecb108f33be8fc359cfb807a56b5b661fa08b1cfd2ad182b3eb3d0f32cf68dc0ba23bff5e92fbcb72b133c1497be6a76886014ef1fdd09dcdd1d58094a7ca599d2c0fd99e351d9695d3dc6462e97fce7b823665d7c94140b893c51efc054de99e2fbd28fdd14b80515a91c98254199a9724b94c61a4d07c3cb19c8ebabe8e3d1fe79488b4652dfe9c0a491f67094c6b0602ac27d3e8e59a6bae0f71147c1d6da1bdbf6cb046d5f7d33d07d225e9cde1d3c43c479ec8428192e2563bee28ff769ab87badaea5a9cb2478527cca698fae8bbf59ac49fb63b13e712d1bc2591f2ab0abdaa9d3e11d44521deb07cd5705d453de9339dc37128e7ed3a52a8e8f8ae270ff56b3e9aa27b596aad85546b9f393cd7e05cf82d89f46848855f0d46a375b08c35fa8b37023f32bb39202bc853543d2b26be7e00dc077438d16d4adb5ca5d8cc13ebc0edabedeaab6fb9229a9cb80e6a4ca9af6df21142f93cd4773821d122a916530cc504f05a0e789dc6b5c4d45c0c3c587944c4178e3685b2c496e4f523d2499a8ae5741501b48646f4bc853c7d6ea48356c717311763a3b16e1e8119f78e78835681cfcc4a1d88308e58659ced19cdcaf467c6383ed4f522cd1292b6d920e4a3e8890df8d0a0beb3729cb54ff02580747172ed7e1a816d35123e32e336c26cb58e608705a78c6346d54f105dd93b8849f1a13da4733d8a46a65b54d2af3399994de7fdd3a6f05446c6a8ddc0e9908c15dc15cacfe11061ac56d0501bd066dd121a212dbc5dc880b641977c325fdfc57cc020f8ca1555e45de688208b5d3533425e706c52bed8dc4a47d5dd7c4bdab9348f25d3cc78f00d0dd9dcc4eba2c731b3f2a7f822858930eb8f8a5b24c8ae664f3b736fa65a9d7cb44e9d7f287492555acfd877544a9b8e83dfd1c2c53a7eb1f48fdb7adf90333a803b247492f5212cb69552b7c4e185fe58c45a12eeb2975309a4cebbad6fdcbe1b25d57aefe23ac25cf7464591e8abb495b4a31bb4ba73d06e290a70055cbda55a452ad41dd15add8b1ce9f8b1158bbf5a5d183bd5280393ccd0e3a42d1779d5113d01cb1539dad3aa061b9e30093babc42a2127fe57d97063f7798610b747f02c495b55f1f4a03a38c706466cdaf789eebf82cca093071bea8499e16fa2c9b57c964415419fa240267b33a50031f358b83de58360e209e0bfb43fc69979a47a799f8a5ba91165129a9f4f59e2d30d61fd6787640ae1cead847455f7d5bc35eb7f29ca7441ad3964ea300e5ef3ebba2bac00ad87d1886c8cc178bf4a13493b29332a54fd01f60405551afc63ec6f9fdff2b4a75c95d80d8d12210192192c6ba568b2d93069b8a8956c10b867d5e442e179426a2b88b213bba8cc037687aa499e0aece384522a29388718309f40d5f82942e2a0f337296f3328f75551eb46ae97225411cba07b7e4892d3331b9a570f154ee6cd99293d4e7d8525187915f47af3c6b395a6270a009b0b258fe00cb0dad6f668d1b71a335a551ec3530321c3ab8a04085574af56c120880866cb76a6587993ef5350a9642e810d2f4f32cd927575943b6834ea1785424080958a12a918d49d2a6be5c1a84d987a5fb3aaf54d8c51aa439b29aeb7d901c9d0107f42bfd1833a87713aaa22570a4f5f96103419c0771f667c33e5c4d444c38406c5562f7b2c145ef83ed86bf8913f5f070f3e0d047c5fd9106249524af2ce9f384926023a33fdf978a4c6df9a03533b524166c5c83334bf89bf4937ff87a76981b750070583c7919014c5835284a422a9cb317cc2fd629746718f3726df44b1c9198542d805a578327e6f1fd548ec43063922866ab83303c1ff9275319f10729824c1fc63a4a9d9b0c89040c238079202a7d0ffb2b69250761152e280c439a2248a70ea2cf3a5a03139a7509e1e3f7f59b602039686a616b4f5f9205e13084a0715fc243b0b8f36239c78bcb3f5fa7867569fc3fdf250e8246dfd16d9601105480788348641dbda7250e6dd392e8bace96ae0ec21c21ed4497eea5da02408dc13a9481db8e0f166cf55f9f01bdea053be32c85d1fa2fe860ee6aa0b9eebb58d8812cff4b624c8a3c1dd43d41e7dae38e94ff6df8298a7fc060102b0fc378415461f26c79721b8faa27f2bffc059f603501228034c3430c865ca3def301c5462462777aaaecb279418d7a7b7d688cc9574cc3ca50094ce3e4393100c51ba8d026eb1888cc988c6d6cf36d056b4e181798d92b630d43b25cf3f02195aa0d4883828a997c9616601e8cceecbff89af12881a496fce5ca5c218c76cd7511add428eba094f587f0fd928198e559c1583e3cff159b1f98af8d2851ee7191ed3bcbabf45348451c26d16910c2932fed577670a07b4308c53ea14ccda7d415d5498c8ace6a6460bad15ac5dcf1967edd2f14610e57630a089742f8a9b13e549ede8ec60dcc72d5360c1dcb25d3ebca23e3467b8830cb08ebfdc9d125fa27c2e588d08f20d2a06632d94224626f56c524e9368bac3a26b52c9a6855d47d72bf04ec0044f52131a431468949f7251b3589fc7549a89b931e9df73ca42375802ee658763eeb567e0698187ebe5f7c15843b7ef6c2f9b375341ef43cf77afd621ba74be86555d996fe834d8c11c1c753d0789ba37669a0996e68b59e35ddf31edf2b04c571cf2433c5727a0b32b1d159f77c60e29e556bb81bdfa3b6b3346f88a0d55a532364d5fecba74da018e715d91c9128acae6558a70269fc85e1d904b20b0aef87fb5b1566f1123053c9dbe3db0d4933a239d53170007ee0119558b90cf63d961f5c15c6992ef22c95b022134317106c7d0c56a1036ac8e167b40d2a44a4c62cdadd5d3c77b74a513b7401f98c682b8b020215be21cd5111ef0ae699946c75f7bd5577ae152761ad8ba03fc9f2f097e265a379b954e2fca6575a2e60391e2e84fd160447724e743ba2571b85126a1c76fe514a1c3de9a781b2da681954eb25662ac8715f2e5069ee3752e78185ef019f9cdd6da7c7dc8a6723ec04ff8f543f441d2661d9a808dd914b8cf7530e1d6de2d74c6a9de31cc5036250388ee29851f0e85112066f01a04fe1ee405592049484b0793105390ab6a5dc7168210d89269914eca8fbfea500c077f28a69ce1a366a38fad2093d0cb276f721ffe4c59c1ba6126fa8ee071af515b3de22bc96b8dcf6a4ade847a01d7e4135292718a2d2e0add0384d7a79d3e56cfd25428d885e55ffae1f5556d0ee2f5587346c220e8003bf1a7916dc3ca915a4c8e71b2bc18b5edb5e934e8625bd7c7c29189d842c36baca0a7c06b4c1ba8f1a3579306f4caf559f016df8a5c5ae96a902a7c040f91e3c5fb9848df1702bf09e365c663061b02fd199f3d162d24164533affc4c8f6f8bd8bdf3b6c901e2178e43a27301a1c5902a1eaf1fb4f85e50cb5a2c85b4c02d20a4a5bb47b118072765f140e32963e40f5557b9222666ce8641b8bba8e5c592efdf3d38c801c5aaeba71183ee74c05d48de3da28b21bf531eac910008b6a7c3baba9e60560f036c32c16e6bfd7deb9d16896f5369d2579dea22aa2186a3869be52b3f636f34ce97c0de6d9601f8bc195c59288260b8228852f382aee59d7b668a1b763ddc3134f99113ba7afaeeefaf674025afb1db183dce84c915782a9228ca94834e4cc1f265b5fedb66504aa60d1cd82d548a830e8dea02aca52ec47fed7cd5d296e693c9f7ecfc67a80cb721aa7419db0ecdc2c08d6ec1401428972bdccc593043a5aac9bf824b70ca074d7f63aacf9ba6e72c9a248f78753b509971f0aaf4e79f386e7c1811e8699d46217d87a31d101becc98f8f8c757e510dcf7826f05b43f969dc401b814051845c36cff8c00fd1331ef31efb95bfa324c0cca391282cf75258585e3346cd91b21fe5da95ab2caf814a6784396b7469f4acbcb3603d5af5bcfb15c84f3bf4c6754d404feae786d2f176fe7783effc714a0f7910cba6f00bf6bc4ca2da359ed3734c5f28aa257b84e3a0776281ce2d7902a65c96457c311c89041abf41fc61ecf7647f0712bed908daa0021b0700b1b0c68bd720bef443c118f0baf120fe7c5fa213b5d23c017cff4692b9dd95df857295628c29cdad5c08cba7ce5ba53514834d74a4b660f9f1fbccca1e83e10e89ec0578c0959668fb436e51189053dc331d42a1607c679e4090c6017192103872cfb02f300d47343d7ea10117fea905532dd6b61630d189c501325e06b64d53602cad5aa31e1fbc82c2c8682fa16dc798b0c73216b402a849b564a524e27e620e0855102f3b91be8434700030511c12e84a21d75dd77f95f2f05e1de40da2578d4875106cc53a0864cd573bdac96f65b36950b00ab1cb04bb2e6edeb1f6c4ba90ee0cf09bc347dd955379566a24c742f3ce626edf6fb38ef185be73ece603ca1d3466676a39d692c74f04436c495d269b866c09281724f914bfcf6d0d5be93159e8abc18a72206403c0b50e5f271d7d66a047584f1039157516e222941ec506620025c6981f4a6585424d87751a7eb762dce3a2ea1207608e229a3c72abdfeb845a2660b28ad6393c294f5bdd3ba0527022580a06847c71c7d98f16454a88799e90a43006d69ddcbafdc6a5eca74524bff1002a2ca910682fcf5d991e3173ef3fe1fdbbdde64fe6b2a70ceacfccfde4aae81e146ae88426669d7a754ef29fb52315b25c48e2d84d65d9bc3109bf3c852af1a87189891c9e3260989ce8920dec1fcc835c959d088fa1b5483dec5a5fb397cd273d77942f7389a656c00fec3284ca0fddedb3ad337e8476c8b0eddcef591187079ba00a7a14e1405ffce9f50580e6aae652b7f12c1fc4d514c239bf2a95559663cc0fc85be6c58b023bac754404064b778205e52d894c70d6b31377ad734e5081d885060aca23e4dccd3403c9d535b8557279fed82c690aa12818c3edbb64742ad8f092b6046be6148ccaf2e0363c7d85330eee4afa7237802a6820221863e51e3fd6f9f5c3989db6ebebad5017e3490e1b5a9cba19b40dc91b49f9e914a4ee728e6a3213f33e1c94be3eaa61781603e32ba41ad8a4c5afd5cb9a9f3579e4eccb60e4f8a7739b1432a81a63fc3b5258f0e791d65c7cc97c94bbece688256fe0bfcca66596bc717d75338d89925da126fc4b43e28b0c02d6999af0c197f7ad3d15c4738aba0092ae1952f60891813147fc45c8589f74aecbba9a0827c72bf14fc06253b1971f276c75eb4c1536cc634eb220177d8035cca3cab29519b34cb2d55100f7498bc1f79da8533100e7cb7e9a87b35b5099955e5b47300d6a5fbc880aa020b7096a66bfd34ec19ac5467fdb43552b501ff4a4de5548a9385aa40b3edbcddd0c6fe3702c6137d40cc2dc28974692ea53048e60ba53e777e7ef3f4ab010c57b996431925994d498b6d43c15960162296a1ccd0a4499506644b98dec60f25e7e3ddf029ff067f1b499d4537ee4627537e3b3adc02a3f46cb0588341f116ab5d428cfcd860aa4c1e0d8ab668e0e01471d9597e7e0c7674e242dff7bf02a161d79303d0267d6ffe279dae4e8d0a9be9d9e6c057c8678b79b8afa40e9ea24387e2a217f6c2c4a1e94933567a43242d3a9856c3eb5a175d445abc9a8d09a7b5c586b22d8d0f535a88b6c64b46b4c2f7206ae474fe843962056d41c58a70fa86dbc83c875a6ec6f9cd9a879084ed19a3999aff795a996c9c084b75b33e88f5f374fa92e1e03193c6e45a02ffac065d5ae1bd7d62232c4dca862914b2aeb724f14f498f11c528cdb68b16bc46482c5e5b3d13634d3ec8e67c3e552b4664fbc3cfc123082dab5e560c1aff0aebcb9f4b6ec8dcf5b1b231baa59c32b5578ccc54b109e43e7160ea7207805dd334c63cf758e04362c69d093c1b68c6ac2de3bd707cfcd8da8066765ea5bdea941139c0db092dfffea54808cef8a232694177ab17d7f5c97289389347b83cb33dc72ef157b298766295c4111f8ff25f8f1b38ba00af6074eaee86b17e192db2932c3165eddaa1ee46d355232ee844456497ba8e103a5f6e611e7fe72f900798b31747a88eb6800d09bbf09d34bad628dc7a1b00e1f81ad874619b5f1a8852aa0aef05fbb5b5990e672ab6332d7a0fa638c14a0a0ee024549459dad99a125d15af537c977802974e4944d1000633b8fb48cff0945154ee69047c5c1050e0aac8a581f89c3447aa458d114fb42239cfbd132abdffb87b08e1e15f3354e4944f12f4e85037394897ca3d0a512183ffca8cbf1092e98d3abcff28f118a3a72a0c4f6ee83db674a0647e513684846c39db1c6d4f061eb3b6a147be006d31a3eae30bd86082595a0f136d6993e0cc071c81c9b9112528383107648ce3aaddb6e7be075ba1f4012c601a514368008dd85b2ea506d8719b805112227ff171b2a6c4aeb290d42437939b2442592cdfe67a48ea5227388026a0b21283a8f870281d2fe97973738efb8c499aaf3ded77fb2819a82efade8eba95330e93e2405fb3b11cb012bbbe3a2197220eb55d9de7d63af674dbc1064eb63ea6facc21cb214a1fdf9d8e96f05c7946005ff67294a825168fc654335ba99bb381fcc4216b76da9ecf19989e7097df11dd7e6a4915717d7f8b2d924c35506e02318ee603c74061c9fcc813ca58c1af09d21c4ba754f020bc4609b728edcf2d7c2e4a3248dd5405719c9e98df80bbb63c40c8e8bb99c233688a6dda36e873189e228c9574d37099dbe2dbb8f318b86af32aae615e67e46d290b256fd26a398d4fca71691f8ca390b9c7af221f079b2e02e1072bea6b05be4bcf656704ff2a980bef27498ebccfe51e289a86fb44a365419be647ebd08c180e2d256aadab69c3080a499f9030dd9b96f0779117d964c0c8d0936c88f132cfeee15365592e46daa6f1f5c884264af51f876c169010a69dae6fbc3382f048de9bf61338b73f4ab5f02d2ca32f84f91c45a7ef25a34a9d4daf98d36a26a1592cfc366999369f75d1fda2262695fff49a071a14afa7bbbe72385e9be60a9b21df9e09f435e88c09b615185c564375cb2d1433dda29d0a9cd5eca59376dbe4ee6b4f467e2296a18aa4f81ac02213296990b283a1d36c579e8dfb8f846e4330d139c598fd94cfa777f3081f2bfca1cda029e63da1b946f213f9da70cc6e29afe479444673a73ba945a1802fd87f7f299165abd1499c79da2684f26c901677ea1e453cf7a39e774b128905eee31cc996dbcc17c040c9359a9f1bac8dd063436c783b225e722f0312bf93730a1f5cfe16de425ed030b6065e85f8fdd6d7734ec1981d52205fffe8daf6d5224b8137bc05981ea3109d4fca1be0c810e99307cfb8a4e131f1ab357b785ae0425e8868d71724b79f5a71cfe61b8cfdd9327de5a1431b1bc77fdc804339982b96e026d4ce8ad1f53cc98001121e2f5225b4fb84a22469deab4fd2780d8e76b3703d467a465634aa08f79f01e34000bcf3f011b009c28b42c75a45111ca824441c147a89a7cdde1b242cac3e6443f8c2dbe8a20151f4962d6f62364420d65fff06d5f034d2da4b2746818b286b09ea7bed83fc13b256318e407c81384a7063382ca1f8bf6bc4e48517fe08c6297b06d0cbd6019414690a29fd30cd9c4342854e4b67f347c861beedf4b02b3d424cc0ac0a4b78410952cf11b4f2166f90f053cbf38fd104af7161ee364fefd5211423bbab5449cc5e7f035f2a2b1bbb313e110d0ee4d1b6b58d44c1c3de90c0fd0beb54ad1dc064b6b787c8ecce420137a3ed3417039de9765813397e3cd8bdb4d0ff0a2b7d9a6ca0031f1950fd96f9012f35f4973175c656443217d9fc8dabcbb458d9f112ec68a7987a40ca812b17fc5bd67f6ca70d89df2fd88d6cbe9f44f2f924f355860541ae6f936a94a6fc65b636c0516b10c5029573b44d9a529926d1ee84abaf68daacb8d4af046de4cb1747fb7a8b9d23052118b534a81f5bf6078bac85b7666cdd3e3f5294c198a43cf0e9edc3279d288bbafca0caa7ba44c50d432ffa00869c0d3e1a859c73bef7c9142888e02a6188e5aef0f762b117949480a72aef49fd642f2a7a2bcccd4a20a0080b249aa1608392fdcb81c6249d32d21e83c2d04c65f5542243e052756976bf7243471efcbace1a614f4ea7ed4de64a7ccf7a5900212a51db03b34be2f41b563ddd989fd079a732d01569dbf802727ab65aec2fcac2df7a1b7cfd05749930a77644d4d55c136fe5aa47a2dee5d9004a373c0136c9e2385c666fd415dc1a4e4d3f0061d313db364f6294f60f2f0ee974bb3662bf87ed336634c4531f8b3d051a9fce19790eb924b833ebe8c045ad312ee7825df5b41d45516708d2f9ed2831f2ca1739cdccffa17a318e66b94011c975c1721d8b63593596450b23d0e9b6cfcbb9ea1c1285abb561b1cfbb96417c8b4f922f6ab7f2b0ebd44b9c3ea59178d252b384387f44bbe22e05b00ca713dc5e67367f98fb8cea641c7e803d7493737022d1ac1da6b41f48839342eabb19687401211ce6f77d45871e878f9d2c18b1b837d4611640dba82e3fcb827ea1bbc432541546c2bda81a01879bb2fcff748711895c0ce8d47338c150faec01c85fd8f7b8707f37707474b9fc378479f3f5b93e593102acce44de8a84fb2c62c350716904f1ebe596ff6874ce5cc800a16f6af99dde74494af689128fa7b4b0ea2d2b986504cdc4f64ee8a74462ac3b51824b59751aa3191bbb0e70af3a16a865604df4356e8b3157aa03b55f192b45f72d95fc552c96e033a827c6f5937da44d6b16c78c5d43824603f495ce7d309ac420e9061dab768eafa78c0f7bc4cf3e57ef391bfdbf7e74aaeabaa204e8152e0061a6c2a71be0e8aefa0fc6aade9e994bb5439b7ba8de53456d61a84d1d59c867e50ea969df1cebd011d801e9a3139ed3bc2d0524f99c2234461e22545a408d539650b381defaa4f9a35106aaf89c038acce3623a0e9d0eeb3d3471246e03720a60b6c748f3368de922502319eb716bd260d74cd03a364c97f76bcb97c70018dfe9e26f6982703eb3e3ce831deb0a2dacc92b5d8576e358da850fb49e084a202fdf5d97f57dd4d145e48068c85a0fa46ab1836e560827aa32802c61544700fb0e0a97206ee0dfbd650645e99c0a686fc7b5f2d9fd95f693ff61dd34ff208cd4f3c26eed4a6267dbf574c3f60e4aa680e741271bdc522d21eaa5ac46fdce781b6c9a380766e3ec3372c75f2c57014a42735d20ebdc007bc41dcbcc3a808ddbdd24f99af727c1e42b24d9d9505b3973164e6068ffdd8d172f8b1204a558a34d38a743e5cb88797a53bc4de440feec468754caf0e2c341679e6840dcb677103d87f343db996a5996a20e60af6355c6392af3b5c90ab0fb180c9a20960d0e07efe1df80c242382306ef787514f4c186bdb9a514f76cb587dd556e793f36878c9c6e725db870ec5e7c5d06244cc3e4e6d1c64bde84779756cddd44f66391dd7077618d51985ca45cb8010681b75d7112f4e423a217bbc403c3e4432225afb5356ab59f57109fb3ebdcc919dba08b8e073123a789de7669b91a50dbdbc5b866b23c783198f4ba3b555c71f2ec457c5974f358a687724f111532c3d9ecf3c947ba5c1476720ff0fcea5ee031a0f282ef3e319450b873705f0a12d108442166e4494f4d82f2d89c3288c7b7ac5177037682bf9d0e0f404071f1f2dd1848fc8df11f88a1f5be4b4fc098161b2233d17c92acb861e5e78b83d2add5c58dfe591193fcf52413ef7bc7fc3102feb4c87d8f0ccdf64177626125f357470ee2766f9f806e8ca4bd79e2311136ccc045bad10ab2d691de1cc6399433e4b1f77b2eb47f3f39d32a98f2c96a93b0303c96fd8a2d8ac0a37825f07da91a8d6a7a270f0d43717402620713050032c60267abfd294e53a0a9150eb65445455e32e6ed4dbbae7858be4d8841e28ae254101843e3f887e369e7668ac383c38924ea08a1eea05051ac7d754e87324c60e805bc12766e826a6c7082d65a9e4be20c7ebb4511f6a642345129e55156d5d57442846aa5c83387d82cbcd64664cb737a171cb1b6ce97b174e37166aaded1ef2358695be1c94ccdb91495f6692e1114ea21bc920e6380fd997057788767c30cfbef53b81a9f2289eca0a4804b048f7150b844cc93e49c3911e6257f9a3ac2ffbd669a9064ff28556c04215c11ee35d110c7b555b0ddddf12078f2ec44d6d95e3d0686098a6848f3c6a78b55845443ba6b16ddfeef16f8c6015328ed8d5c29ec088ecca5dea9d0cd9b68fa4200671e553c2955620e651ed6fb4efef1846a70878639ca22622116f5fb8b7617b348dd54b60fe3901027444abc18337eec0936a3a880b01a74cd97ee2be11d8972df3af7b2f2d384b22fc6ff64264f698a3d0ead5aa4e63d913c93f13bedb0ba8a5f7af021e9db01fc76c5e4fe944ab6b7964baeebdb6dd3c056e20b70615296a5061126ee1c6f4947ce69e08c4b99c4aeaed95e91b99aa0336c2ead865cd1e507aba16d2f88fc695a47ddf946fe0c19f511602d98ffe48b51ffd11f3353dcd139bedd76969ce674cc201d681c2ebb7fc5ca21e4bc53864de4ef0f96c8c1513cd01e26982aea0bec34c8791f0677bad5ef617643321e164506ee4c16cea4a2070bf64b42002c34866ab19360ddc3557576f9add31d6feff031b49eb6e490922dca732e7a368e6b131910092f574b5573760ec0cf788a16a40dcb9bcb91e2e1bf455e3e310563d0fc8997bf67b76f03b109e46e862bc27da116018ca32887896bda74a05ea5c111daee99100b11665670fa740cddd8278ca3f9eaa110385b60f11db22479dc7c6cc85421681278dd2200b23cbfa8fe618d275137688d335111b2823082cb66c37f76104be175c918f9fdcd86cfc34cd8065524ddc8e741195f7a9785b8b791d996dde34e1ca109887ee18def52ecfb4df4b759483442f4d0112a357e35321dd1f325e5e30eb3c97d8230d1e84c5ac2295f54f12608c78391ae7a69f18c647cafbc20832684d3c06f12e8443291b8072c4c99e1b8cfc1720bd5e19beaff324ae5f874cd0af84ce694d00dd84bf894122bf6a53199d2ea8057db37e14e9a057be7a7dc82a36a8b50bb9243e9c61b9843cb8867c50ef273781088640da142595f80997db8b485275eae9ca772ded5f9fd685ff701d2ed3314de89634274ffb921639ae2b3b2e6dffd395ba0d77c0722060bd2d94ca323b937e2b8056ac6dcf2afa5ff00be75fb102e9e7c947066001e80c7a519c3503a727a3df72ca339f8db338a7a6e2b974d68b5e4a2f75cd283571ed90916b2c619b09e3c9f4102e74fc9b479171f05676c35ee8b2dcac462c8c223fa371d7b3c1fdbe4b04d20ec20075bf13ce68a7d1fe73526ea8cd829f32d79e0b1eea0ec7b7afa64fc135f9c8cc002d2e2a90351102231ec9a2962fb96d8d8f4891e2246ff9130197047cad5adca757c74437d21bc9c805a837a4b62636b5149e15c02e26ebf6ac42383ca48cb489a5c08820deb1bf9a309e0111b3d42ea3cdf09b581346ea12c69a80cf47e7b427fe0d5c641ed1e23538b315cd23d267931875064a8f537965db436f47269a60d6b6e1464596d9179e3c82ef4851c9738c34062613ded7d4cb8298c60c9f7a96f4b109bd75dbb9e2620a1a9e8954c3c68034ff67fedb3adcea225a5d96a5e03dbc81934f53406b997f454af585772711a7b3cc9d3535f66c80d2c12cc3e3d1813975321fde4493058b784769d137e9ce2a4a66e511f2c327e93334e40cc3ea1fc6f03c2aea330ceb0dc3e340073948f5d991cbdb0d2715dde35a11949f013bbf3d4d90749db3b2849907eb584edf1cbd951787be304de7989053b9e384ef79278f749267ab4c62c946a260eb9e66fa223992b44e564ec5c45edc0355c3c0370a9524e4429ed68c90cc30d123bf40994bd14c25a754510940cf2ee9c14630de2b52efb7a3b8c7781f2ec77c2193a8a0941e37eca682b2fd337c74a4bb12a0f1477758d9759f3f07424488568e1ae9c706c6b08ba1b8b868a9146b9667f85e41b9b7664fb433d04d67ff32bcc966df0d2044ffe35ef26bc05ce25917c1b492822e9d4de0064696d9df6bd8b280e1dfb7610715349ed3ff83da7639edb2896ddb0ac3be364a6369e6449a0ec7fa322a11b6d66a83c205378391d746bf7e12bbb1c7aa988fe8c08be9a0d793ef08a8f3ba56f32589d7a2303d665c4568616a7e477a2975a1fecc8ae785e61ef148056da1dcbaae4f2bdb96d37bbe87894292dde0eec39c426a342190168a17698ca7ad319cee9ee5f26a0c174174588ba1b61959206ed371367f505759d6481572db2376a285d09ad2f92378797e10881072dc8463f4a2e00d85778c46642a0895f65b071b1803995420fbc871ad2a698552a936d99e7ee844b306c450cb021fd073532159225a4ce29179c47c506b9429cb28dca138eed324291084cbabc2c4b3c724d1977d463dcfdd439435132eff08401140358b5e7abcf00decccd5df4012ac2530a2990c6455664eb910c589bd951c91a8c30c7eeddd785993d835d1000f87fa1f046c26fe7a034b14f9beb1b1e89d68662092e629c149e423a359f7659696f27457496e3e2289c1d84321e371dcad42e5ea4cef279ab217b78dd2df8eaa6586f08b01a9ac77b200206e079f6ce107464f3568d586e9375f2d383a182132f99ac15ed8c2d15b75cc4e6c8c3148e6e3699c12251a83eea859cbb988ae03ddadcbce8b49d04372a319a446eefa6ee2da51c6342519363918aa982b18bc5700a4a5f8a5c1a77f38bdfc67fdb089df5380de99ad73fd168234569e22957c80e214b52f698cc912a0fa817c4ac45cf732251e4ac8180c015ddf2728f271a0bb63b40ede29c23487e5dd5d7f3b75836693ac86ce070aa6def697a6b13062f5e6d6a0822a5143a14b28e60ad60ac30236ef71e96dcde405d68b3071941b79c0f70cae1905a78e7ef9c73c4c167743621afff5112adb2488ab866e35af5acbd6bb9e0fd2f8174feb0e3e3dca055ba9429705d6c668d8ed95c88561c50b84e8fe5c69720d7eed3a83237963f461e8627a0b1ff92d492842afb7a14eb436686ce71e43df5b7fbe7c4948ceefd6dda4509c836d46d619f25690c2b8cc1f2a69a20456607c8da030ae6f9508d85508c22eebec9e79505504022674a2a9ffa6bb1e54724326aa91d41883c53648b077be2e9e5864a4d5b5bf29bbb283db8a055020c877aa42b08a957206b8b547f34b5b692aeed043340a3332b229d6824575088f84851072afbb648f8a0ed3ab031f3134107ca614880eab57acb8ff718a2d23b6b9b0354f76a1479fe00fc676a4659bbb04e03bebc62c60ad9f56b6d4b5e4c959e430947d35a1f75638c200c71644cb4485941e2756dc00f9df4ea80f8ab3f86af5a7eba9481116bca9b7d24b74cebae16955fd8ec94c1d3a2d957684188824674aada8da4f87a5d10683a8860a50e1e9834c6ff5544dae0ab7be4280a713ace8cf28b405f8ec4269767a74649e12ef07b5a19050d218c530d6c29ea1b18d2133cdab7f0fa43661851b6da737116e2dbc401d208b2453be61488c657218efc64e520466f1c21892710ebad3dd9b8983ae22c92ab7004ecfbd06933ad5d31d3094b0131825b10499aac357cf4908b374efd10c81b5fc939b6c5a3107a2ad3b5f4084ba4cdc24d13e43c57e2ede44e60a3bab70e71f709c4c0a8dabd805adc12c73a9b01e9ba9f4aebbfb478677b6f6460bb135297dce487435f47bea5e4532e3182be4d2ddd3f2f06440a93005e4abd6009eaf521242c6fdcd1f2eebb3d5dc853f591835907b414ad9b16287f084e8fb174dc7a696d70fcf195d4a511c921dc79e00659595b6550edff40083121a4c8ab8ab7875be3813e1c34e63877092b656882cc976f995a34cf117cc30e30844707e4164eb91bdff4c166e262b7dc128b2e87620fe26d3fca32a9bad41a95d1df3ce2881bf832416b5d6692a128c3dfa0a1b31136f669b4dee3ecd1a7363749172cffe0787cb6870a47e700f2259d43515406836181ad5776a8ff3cf5915910f586ad919cf875cfc3d35a3f814e21c9f4d921956a29a1ecbcb9033b54a817eb0725fb3931db55a027a8fadd840dd7e0e0c691a67e4c1adb61efacca5ce07ea28bfcfe5112d0e6c896e5687b236ae1f0c949f0c89ed968f07fe49297b2680fe27428de7411d3932f50a040d2dd4bd89d172d49ff3fbf993857eb30d0e19763662ee4f6add3b37e273ce65ca70b2693b88e508b53031ac7e5290d114abdd77432c2f8a7636ea85a2061337365374d623ce9812dea8d0fafc9a660aed715a386562846ed94a55f3868e0a151c186032f68fe65d038118f1b94e1f8fc3ce80f73af3ea65834d8556f459e9929086e65b19a44cd97081fd46071e82c841a3dcf2d76c1b23160f54ab5cd0912bfa3a23af989069580d7429db033ccbd7d5a3f4fb66f258b8dfabf16d52cbf992472b16cb8a193456e3c322d5f736984f7daa2fd5b0e63d3c191796954326321b8e94766e9644a5f79b3ca394bc1801a8abbf45241e6a3b0c36dc59030af7e385591bff1a54e6b622f888d034051a56c7c3d650ae8431f405021ab8949c8e750bfcfed5b3f1bf58e174e9e43f295198121a2fafe3eef746207baa44d77e3eac97d47a901e7cdb769e9144942a282cb7682351a744af2b8ed865d21ac51a3c331b63ea5ea00b35610ca36a66e9cfaa87dcb546d6e31684bf197221d16141a81455d64e628a8677efd0479cc0c47ba845def81d7e79d86864652099ac6b02ea28c40d10aa366aec23a5326b71b5e1fd66d78b813324008538efe2fff289e51c461a7cb218a7c80f1ba0869f89334564c112251219d7d849c944d57614ae5bb442268e24c9bc069058122b911e703b2c24c3e24dd65bc8bb350eaa8aadfeada52920d779f13e11b2687d73ab80044965e09268789a6c090969da3b0cada66c38bbf1995368660b35a83d7ae06a7b843ce2bece287ff51a02abdc6b378b9d65199ef0a72d20219495fad061224d241165a544a7d7df22322786e74f59199b682bb014a98c170b1a39e52e9ee645184637613838b0bcee7f792d0e03dbf492390f1790c107a2174864ccc009e34995b029074e0da5cb58f52282adbb03e9028c0abd48f6d5b7c9f01f98617ada1e93d0d45a79a2718f3630cb1e3c51846d0612e8c08560b304fcf4031ae96694572056b24a07159d088bb37ab4d38d0835da51aa8c37e30f5a145d4c1f95f6dc3df41cdc7f89ef4d0f2b5a280998d1ba9eb8412d2862063671b8617458bcf0b2f0f1ec2812f7f2761e7dfffffffd4ff6265bee2d654a29052f0909092809ce0c050a43f9ccf8d1c44ddcf4352971539307e1f0516742ac3d6a5dbd42724b7dd9fc3ca8fbeffba17383d983d887bd51c70d75eab85023759a5d17e2f0e1e0416ce54aa7ea1eb041aa30871d390e0a6a3f053d67ffcb2891992425e1cde6264dd3b4ef4971d4cb90a3529b73e0d8337e4ca0107165e241dd771772538bad43863772541f018ddcc568d62eb1ee9ba29a9aa2a2fa888df6a14bd045f40aa494b2e3af518110203cedf9c9987f64f899305e3d5445e1ad90c4a9cb4c9849163281ea611f1c877084a96cd42d1ac2b6d57449ed1f4965186973936ef5373b912d6cd01622691af600e23853bc71998a780884890e15deb8501cf3e9130927c0a30f5b1c72802465044a9850b932f11828bc02ff0e063434a82b266aefa0f6e43250672797b75f9ed05f000b51a52376c09efe3eea3e2266ef9fb94e0cade383c7beb277cfe33a23d5afff0e9d11eb80e13430e71b9c4c46dc83ad48791ba31fbd1a43e37c37bffbe272409de73136a845b01d436aa2d322d890b29d76f2203e8a2151a49c6e9edff9ca2a223b5fa444f3f0ecfc0fcfb42cdbf99dffd1debefa1d2794f27213c2d884decb6f0731d3afbff7dc04695e32135be11edc85d9c94a759b1f3d1e48ddc426ec02d6bc0b1b74816df917e9d80eac2316557301998f79ffde52cb473794783c3ff2110f0fe223a46ec23d3ac63aba466a529d06dc15c720d6b907af8e7ef758cb239a221ec4aabdfd349ff0003ecf67df4478be48892cdc164130ccbec33103b59f871ef96ad7d91d3ee1e19fc7860f79c2a29eff4109d80b75e67b106aa05977f5fbde2a88664f5bf43e87178a586887e71b7cc2f319f8c4033c3c3c3cdfe11310f0b0f33c08ad6a084f58d4423b3fb3aa31e11111c3802fe048a3e24153537c446b67db59366512de8a65124edf18b1947e32cc69f2be7e75de56bf9cfd59fb6ff8851e73ee5e1385c73e4516575cb982a972303844fce910c77149781c87f38437e79cf3bd07daf371e1ae8be33ec5fdc671e17844acdc770dc4f5d4719d3490882b8d3571dded5f778f66d6b1dddd9e725f9d205efbbd7638f650a9171cd7dd3dbbbbbbbb7fdcdd6def6e6fdeedac05dc7577777757ce4ca3a9996974cb34ba750bd26dbec875edb7c1d1aca7af48a5964d2a25d5b2d9867b1bee6db8b7118458d6d3e7ba66f681d9febb1b11397f58477f90ae1b4d6faba3b5acb8f087cae933ebfef17136862e071151e1bbe1e9f413e9d40bb4ce6696cd9612bc5977c90a2c5450c192153c5802133db0024a18fe194b4e9bee54ae7a93744529cfa49487aee88af2d015a53c5c4ab2945366736bee91fdbae473727e952bf0ef6b85ea95ab0ca0ca5f06d23ced3dee91bd7c0d7cb1454dd334eda56a487b5074e2699ffd1845f65ef5e4d4fe47b714c3355442fa7f34ab8064ffeb929f8121eb604de1f5e414eb90bf2579628b5286485e5213545ac1e447e218c21be9d10976000589082780810410d60b2a595260858923a27cb1031e1891a9209531690172d5a985b15a9af2059309aad49e9e7c8a55952750a8f2fbc91be9aaab02085594f09c78fc19674870ce3a42c2ca61d3ce5e526609ca30c489976551781e645dfefead0d2a00b7fc671886ef0faa3f0c3cfe1838d411c22f9f439db9350b695a74cf62e08d2c030c91610daf9f25a5f8f9fea19c3635ad8a25740828a92a8c84d08670da88c888d0429b9060c6b42a6210845400115332294700e19222796b992081028a60f2a2601a9c24555125081a58f0e4ada50ff3c34fffb444e07575ab40614104d4173e8881020ea0b4a0700694127c48c38725218c98c263eed147abf6be1d3e2cd981ded7a2949ffd942c9d78f2b746e1c9ae6357bbe31eeb7d2357395d7ede1a9ef410c90c8e81100294cabf2f50d58f2ac74ea344a5cb4a6e97fe3a92fde55355551f1d5413eb9c90a830421dc594142a3fd4714775679f3ae006f81085038fdd3d03def2e7a4e598f66662726a402ca5c494b4af557b47b5796ef1cbbbcccbbbee2f594a29a53fbbcbe94bf8944b48ba03954ae876ce5156ded1d7dd7d6ed7ed673ea1a2f639e62d89f1111bcd1a780cfeb64422146a9af1f33da97ec8321f7461fc90c4053318021b48b0f1c4162ef025234820fc208d0dc30a2c54502e62204608360c2a94e820a2a80111413461c51629e613543cc992bc20aac9921c3861841c2009c9d45da2e2045418415997ec52aeaffb0fbbfbe24ccdc9a5e694bed3478b3b7d939967ef99d30f86393316acf4f9b548a9d47c6a99bb53f7fc05e27f546366667a84d37eaa25993d70f70b7082f0f8a1b668f16056ee53cdd9c185bd9d7c7f22d520c1db976afcd775b787fc662224b23e89e92c8085e6b3d00c8f3aa1f93a4160aa3f4cf5704c529f7c6086d45beeee04b1723034cbb22ca39452174cf1831a34955fa3495514c10a57f9b31774107e90aafc13092a5e9040c2a0326f7142e5a5f27753073989caef7d4a4cb85229156b4e9516540e42f570fc9a9fd54032955fb008c112a1a5e2a3eed2882bdd3d0c222485a12eb8a89d85d3c3f1abac22bcad445cc765ea2534163ff6c5aafc3204d9170aebe2e7df262a767fc0b053f97128eaa0258201c870aa2cb20462142af38e0dc76d5a29a1b0af7d16703b65f33c4de129970bed7aa8bd7358973fcbe51ea52c5072994b1135449f2975dc2ce28e9fce615ffcfe1c730846731e86d7bf54c695daaa20371e185eff4ef94d4260d2fd532e9722597cab8ff53378fde1f91cfe04d90d77f8ec87496818d2a2ff0c59a101dc86212d36ebb4dca1c8779ae8209ea45dca12abeeee51aaf7cb65225c8a649101240da4e3d3891cd471b354c7411d774bf528ef70e4a3f61f4a0668a0558281d2376178232321212121f506161529215f7e92da034c93d0f65c4759ddacdab1fa4383194461243662a7f6b3d20a414a93d52285c6af528e924003a1f954cb32b044a7a713b51f072ee30ac99be1c849d38974007054e0c9dfd1416c44b776ecf0f161b1562b24a4f1e767859eb61a74eb679b81f7c3492218346852e43b25fa026fa49e5786a7d33a5078d5078f1778238fca38108166566c70813ea7d2c7f3993eddd215e73b28579cd3bb5d91f967bef2ce8afcddb6f85795c70fc2aabf6ae367086e7f59e342559875f9b30e73577f1fa52ed5ff874850007649698b231dc5a4388247f5e75e985e411d3b987ded7bdf60e99ccbcc54db750791cc5dba31f306aeb7e6fc49837431b8658d3f9472f85e1adeaf385948f0ba21b4940fb2094b5a1c5551a3cb4c428225253021e1042dda50c284c2092d2fe20c1b6981b0c61426a2a8c0093880811a501c21460649218f5220b865ddb4c06b4e22c47df645a9df3e891038c45beea4d39fd2e94f7d12a1a26d2bcab62442dbe72d29bc19c6accbe927e4de7b19702a9e0c9d0af94984f8a5b7fc930811f156f69fb7fc95b0818b94b0617e1616cd90c32cd4b1613eff0c89784b4847fefc2a3cf0c75b2ea512549f413f713390992a85711b55d5811ca8937d12213ff256160e31ea286fd14f228484236909a698d00a29c14f7f8557c286feedc322ef3bea578876a863c3f6fd423a94071dbd6a8067ba4c7e5405a5a19199c42d7370e3c3dfeff6d53bdfbcaf9d97cf6a480fd3d81e9cc43ae4b7e49dffd13796ec8093665b37b887f6f2c66fa0b7e28d1b52c78d1bcf205df1c68760b7e28d1b3f321255bebcf1db3be8db167e6f7f23e4a31691963012d3be364a299ddbb67d2f1fe6c79eeafe3d4339ccaf6b1f78836907eccaf2c6cbf0e5f7dc06eebce83fc6e0f871ab39defd7380384016c89f55bef1db86cfe0b8559877d5d08d23620dbf55423c90c5194c2085cf71770394350c290cd34ef4f1ce55439de893fd8f097ec4e1286dce29a17ce328979a1af33b6683c6872aa79cd27307bddef847b51d1e77779e2b4c13e4df9161864fa337f0805ba90c2e77c04feb181cc51df0d33cb06b71d5373031adfe7b8e763facba626228bf116e9449fc49c2d37e14abfc61256cd00c0bc5c43d6e60daca5032dcc03d90b00ef9854c4c5ac73c2a21abffe8af7e5534d0ff543330c8460cf5c37a16615ee4466b78e34679686407362ada818d36b063207701398a8bfc22483c1b703ceb7f3497c4f484373253124331ed0b2ccaf13afcac67a1acbb01f67c08fe6f20f845907096653e335343f33b7f464ce13371fc80be1fbfc7ce8fac9aa5006edbf2df0177758caeeaffb5aa8b200aa0d370870682edd0ff5441e8f3f71f1ba578c0aeeef473be2807eb7960d1ff582c168bc562e560e5c0f139fc7b5efe4bf0250f0c4ec334790dfcf9687a402f07b8dee209e98a86b09d704c5257211bb528657e5d270cc7233caa7f4ec838e11716edd0a227026f6428661e3e70f0f8f1791f8e276fe48e7117495ff33c1c373734a43720f736e098a3662111d780e357679e061cbfce844c0c9594c450ab4ff4f91199f5e327036f6c26947a1eeba9b34050a6004419b2775d53aa5c2c90b048da97d6473eb4230dcf816c6c5f3eb89192edc147ac43be6cb922d3d03de297c2470e76c7806ce5a4265a9453fee769cf494ef695bdfc1e9c6f633ceba16a39384cbf37fb1f9e038e3d95be0d387e5b48c4ffa37b3ea9276435a7a38537a5140f62b54f95b3d2df2143d1fd354d63f99016ddb5a11d2dca9faeb9bb873f5be53bd287513d3a3b365fd26cd3380c9a492dd39848c76ab93e4052feffac06daf9d5cbf769209d97dbd39ac7f9554991b23ae44f1b2d6782f46dc0ec73b80de4ca03eee2e01c58ad9353d37eaa86e6c3681c27b32c530dd1988c66dc38e0c8aa33f593079cbfaa4dc3c18356dd62a9fd9864f5dca986769e53694f44fe88e3959f06e7573c5b0f76621d47583943783684445a944f1f07dc791e50e7370e6c8b9df8e504ae727670f1564fe5ea6f562b1cd8487e28b32ccbb44cd3f833d6f8358d5552ee93012a0fa932540efd351b671bed1d84edaa866cfe47f37378e4a7fa3bc80fa312e2cf6f03f2fb88dfc762411d83693f323bf1b8789a114e72a285fc1ba83dceaf6a933a60afc0de01fba88d5a94eb922fd286ff9ee7a438e1f4c0e3183bedcb5f7e0fd8f32cb474c594aa42dda5154851b9addb01717e05faeb8039dc64555936e7bbf365b2cf62f3733ef54c56cee7fce855999c9f116bced36cdbca79991cd8cd4b1b4e4543f60cdafcaa82646ff33f5a03190a47d1ba09a640afad0292fab9deca09c7ef8bc0d7e12f4a22d4f33cf43c0b656fd3036adf420c0ad13e87172a7fcf73cf3bf8c4033d3d3d3dcf604f58d442e0ab6af8079f9be0290d84f3f2198a9ced2585e12a6f8f6d75f07b9f037e20b860e76d215d1787e31766fc37515a942f6d42761272528bf23d203cd6d802aa1afe8bacec9798bf87bfba813776ac911a481ef991d956edc11ab0e61d1c8754c93d0d38f654999f01c7afca844e440c038e34f5a563dc3b0c3f5a943fa481fc191c7f5b4d49234be5a74758425653d230a332cb9a00af0784e28d0dc55b3f2dca90478b92478bf25755030bf5bc149ddea1c435cf6c0cdef632b353daa66c383938211b754e185bc22276c596ca2a205d659ea1b8ff088e58aafeebb4c9cc99f7fe6ba06d669b993321cf99f7dfb6779006fc544333cfcd8032328fa45dc667405957b56d1f64fef632a091e9acc463a175550ca9f79e9b41e6b7e75a45c3cccb84d1a5cafccc732fdd107dc9fe12a4f9560991f9992a622ca937ea56f1a24b65150d313133e10e560dd53cf7a3e5fcf6b481669e478b3099df3126a93ed4f0c69f6a0426138e49aacc1bf991097db4e8dcecb6f7a09c9cf047ba8536e07c4ef8ab67214ed6e0502465e35024bbe4c436b0e655aa20335ff332a08f167f1a0816c3ccd73ce772e7737e2392b3b393f3ae1ada5435c83af3379f6364e66b5e82453aaf63130a89f91c5ea8db1725115a3d0fab3066cbf92de765c0271ec8c9c9c9f94d27272cc2791d24b26e7f13fe34d04c081b3949a68aa126dcf1f38337728c97c87cccc77ccdc7bc3fd79c7fdf8facbaad827e7ce647afdbd374d00f6ff96fbf3d6f0f1c5887ff168e5e8bdfe69f8dcd8dccff6822fe3fef8f03ccfbab54bfc950c65f158587f3dc736c5f32ef3ddf0703859301b932946d731970ebb675db16ea6c32bf2dfe688ec96ca11099f0090f398ff31b119c2f52629bf99c9c997094f96d7b9c4d666395ccacab4200ceefb66270de655ee61b88261cb91ad95edac8af79ce8dd8fcf7d90e329ffd28f3313fee506dfe03479bcf6a6ade553170ddb6c604a9091db0dec27919d026ac0147991f699d792eeb6a40f93423d79b99979151e2c1e3e74746e6c7af9bcc8f5fdddcabf9ec6dfe47df803a78bd9101475a657edbfe876b5566bf81317f038e3bd49ab789a9b951d1c01ced6ac0ad34b44e70e498ffe13bd418702b0ee88123ad5be8fd0f9fdac3c4469a3a3214aa316d3101de7a8f92670403f2bf6eb8aa21bbad9543926d1a94825b16b7a5a0042f539c52cffb3ef932e54ab7e422b74899e5eb0ca5d3944e9eb73a54cd19c6d055a98e1fe52d8b7d71d9987642e08d1b535454038d2f53b234d0f86969a07163aa3d76571a287b62f251c4a819aa8de8981326df82249bd857ffec0bcac95bfd947adef7fd8fe2d6a5c5dea2dadbd868a1eef3e8a0d4c684d5d1bf5bd4133ce9d44057f665d4405b7770f124d4cf23f7a02dca5bfd0fe54bf2984c244a3deffbfe9d6a3fb7eafe76344de8b180fc37c5bf0522bc19760eb620024f470759b587c1544d8ba241be16eac0d57584f0ccc0a548b8ca306aebe2a481b693500dd42e7582c8ea2fab87230f955f9e6c946852a71195e792cad3a8b2ec52f925970ef22950b349f5291ea4925d5cc988698937d59e46ccde5289246d4a9bbcd5b4c9839e9a9a68136daa4dab872a25dad48637f2539353652b4e3c51a88164f7d41bdf206da5b3ca999fa90a4a5b825b964ef6fe498424a89365ae436937dfb351aaf245529d3fb27cd449b5ec4a9d2f756ae8976f43bf0c8b9490df9f8536f06f61913f7fd315ae5ff66c9dce699cfefaa66dbaa6bb1ba669beb3de3ad55c77adea97e6df51dba7368bbf797e67e6fb69ea841dc30947efe36791b986959861f8a90bc78f0bc74f85a398312b51de58d2ea8423ddcf09470f271cbffd2f1cff261cc51fa7ba5f53d4e2fe0ca8e44f1ee4635b1b138e9e172ac184235585e3b79f0a9fb670e45179763c6969387e9b71d4e7ad56d5aed439e182b4a7bf7150aa53bfaa2156b7b4dfc06596377abd55b603c1f9737dc415c5d868a4557214b7bb9ee4634be14029a17400bc99a4c2913a73a92c95a5b2549651aa75777777a7f8658adbb66da3f9946af324ea4d5a8c62448b1eb6931671a078631f31a9de40485bab9e38e19653e0ad15509c547f19c340befa56d92d10e13943e1b6527fee2e4005b8adce5e554f5587ee45d60eaac2b4aa838caa7b8191b158e5cd6181e7deb5db17112b551db2ca441cabb0172ad3e0c52a7f17846395b35851c6165354e134c594de6f75ccf046f1f3544e58562d761005a255baf2c21bc5da3cc43a859452765048291bc8a594325c4e825b393993383314fe2c41b946b8ed9b167838bb5c6a531651a0c8236994e549090a6fe24ca2b858699212a597f491962c549438899b7489aaeb5477fcf0f30e6d28a9d4556a719f1966c7cfba606ab4f0ba37088e1a2dbcfda902c2e14ae9d239ced65b9bfcb232548bfb315ab89549b2499728272b4d4871245fb2450b1315279dd4b12e579ca634c1463012d491cd42061c33bc6d91856386275b5cf6177e0e351970db6266f9d2259581d7ff5503b9bae4cf26540cbefa28a954964aa354aa4fbc9c107851bc7eaef25bdc178cab873eab7e1fe22a5fd65042cda50b78231542142a8b5027242317eafabd1ed491a6f60f03e1858bc39d91b4e2806cdd17d755128208f56b71eb2a095184fac1248cdba83bd7c5ebe290430242d65d1a820f940d982d57aa4a8bd1db252d4cf503de2e699952f7bdee929626aa6a5ffb75a3b1e2cfebeeee761590cca0d2dedd2e8174b8b29a823e5a641e73abd7f3b36d7bf6766f21799bb144b62a866c6edbf6ccdffdd9d63c5ae4267125b81567055e566f3450fbd75715e466e4d4151ce3e12d5ecac3a5cf9e3b3f6564c183673b319596c9679095131b4827487728d6fd4f12fa78a27d87eff3f2c9d127a43d4df7ff4085b4e7ae8f635d387a14d6c7d18f90f6fce00e407b6625d57d1819fde009bdb000e077615be0ffe11352c2c31f2db6774b2e8389b68294272ddf500401aaf2b3b80ca4ca3e95df3d26f73625b8e94ae4b2ac331f16173ed78c460b3d18161b48cc5695b3a7bf0dd45ef7aa81565e85611fd5a3f9eaaeb81f9f25d6293baa1ae232eeb79c4c35a48519a53506ae0dd31da65823c193a31f5cc8074d48891c64edd8910f42b481bcbbb329a56caedcdd9bfdc0c1ecacb265f6655916ee77077252ba37e7a3d56ce53ebbfdb33a5d35b47582dad66db3f74bcf54190fa6bed4ee70eb56372584558b528aedc3ca2ab7fb6ae7491b48ae9cd23d7bd726336bd9d7dd8d18522ed7ace1f1eec32491695cf71b854152a5675a8aeb568479f985d9a1c2bcbc84635195a9aeadeac027319c16e92fa970d795fa1457e9ceaa2031af814f62429a6eb1af74b986cfcc27959abb160f975da35a66c8eb9a5f7d672699596acb9ae653669a9639e179443eb9be2b3aa774399dd022ad780c6e2baa72c8b60ef0949ad4b215674a07b0579c9916b2104443f2533b32cd69449f9fde8d61607efb1770577c81d9647d79f9ed25942d6ee1762ad949e66457aebb751aa4924abd279ec6592853d02e8986fce7d3ba99f4a9fbacee4e93bdee2fdbff684d0b97abd3cee2f187da04b9669dacfb72594e4a29cd6896895e5716b981e68622abefa3ccda4b3976ab59e972911b5a24227be0655cb783ebc6d5cb8f3430d91371a7f09f488b383fc8324ddb3939aacd15a57ce75f51be0682caef330bbb06da90dae0fab90685c00ced48c36306c2758802631ca1e145e5f746fab4051043489a4ab324e5fbf134ead9ccb299c2104f4d68e1d2930b6a963dcdb3b2503c42cc5b9b83079e5677e989c9138fd65d7a427a3afaa8189c94babf340426754324fdb520ad90a1c4b63e4aeb05174d57f895eacb65471db70b0b7564231e3275e4265a38195577271b388d01060bc05063290c2a6218218695165c811a03690c294b6364c182022c3ec0f224d9f8f934279c0f599665d90a7c985d202105d2873356f0124402b6d8c1144b68d962898dd9832ed030a2ebe20c1904f1a403277cc185ca954bc8c1199feb8b20787c51459defb3088d104fa4c106133c28411421c9832526b2a480f036005ec0a0cef9d40ba73abd061a797ecbc593359c40a50d17b0e08a286e708457c45bfced130b31d3acbaf081a6caa75e0aaafcaf8b23bcb6041e1f7fd44a0e9614a1c9833cf6ac5071842c82948c045e84a869e58a10bd058a9c568850e7e4a57286940851bab54d50283c2a5f166fa55b5b47b16a44b8d2add57858e16202056c69e298f8f85341044870e2815753b70a12889043081e4ddd2a4868238527783275ab4015b1c5f3ea56814a4205243c9bba55a09c48c251168e36d0ee4eb99276f777f713ac245169beb06e953482f018143985952080becaf9ca853ab27cc61d3ebc1b9b65b700403a2f6123b46052fd084b5a3061c907598c60698b2b517680c552d3117c588ad20265898b2e4b3f687a028436765f9303759f7a0e7e021bae00c2084f0841064ba060022107180801064f28d9c11231777767ef27ea589cb999b9a04e46537706132a68a209f729f5f424babb3bbf3b3716777777ee31a4bbbbbb73636131199e497777777632ba63edeeeece3f72952419eeeeeecefd947999bbbbbbb337167777e777e726a3c570f666777777eedaa18e907ef9cd8e458ed14c6e021f00d14c58b25041d1b4250b2c47685a38220b348ed020d1a8e623e6880a0c8ef8b842fd8a91f6d405c9080b946c09131b40c1b263c6c90766ecb822fbcacfcf2b9c94317184169c2406d44684932ba0b04829a744c2fc058371449447c42f852e66e0c591ef8a966dcb931b68c142fd4877a4f3b94182cb123e57322fbb728575e8a93924e12da8c00041451954904c0ef2138cb043243d91f4184c2f4da62481090b1289448ef15333832e68f073659d382e74c0649db0f0a05e83c838b1a2081e481c898fb16259414412ab7d67e993f3baf63cc2922112e62b417e0ae9e124dc9ff3eeb7ba5b802b929e01d7aa96cf2a24bebe2a863252eaee5ab7ad92322cafc1254a149410c75d837c4512672409ed165cb4408a10e74a9a100613a11e609a8a580444f08249a8879ea4c98458194a423d30b310dc72309d8163513582a4ab94a10e5d8d64e1760db8658dac04a9f6732fa04fb73e160aab56fd4b0f1cabe3a543d104de56191aa13c84b755d0b852fd99634cb1260fe21897e618972eefda208e3df9a0b168f4732c8d6d6d9555352cd30f269efc6d823128a02835d2902a20502b14e1414dfe4c6e4a8e9a5889518ca981baef29b6f34fe6a7b1ca1c638a516951c95127c18561e49852ed576a208d4a03f9c7a05a037d939c83f3e52526a67350a3a99c0de7600ac7c14ec74155652d1ccbd262c782b0313354313cf1782f61b8dd8aea493918199b1c1e8e3d79100cdc77dd4f57a7027df625bf5f876b7b541874e8f87170fbf96129030c04e851a7eca01fdeea1ce4aafb9299191a9a2536526c6c6e6e8e7096c0c1c9c901627583d5cece8e6a28e5cf4d9e4c535982fcf3532ee5d6e01f0487b891831b2c160b05265010455185292a743e5a3ca8475d1d66703e9d8f6a48ea00e2ef9896da9307937442878e9f9f12b0a003163a1654433eb1206c10c7a0bcf5145bc22e618376ebb65a50d2826a8895ac88f0465612eb3a72ec8963593a8895c4941cc5b6d46625310f3aaafd635d4d04c1108e5d1d57c92b22a80b520d718c4b8b354835432a1c532f3ff32d16c531a8a6e71897ee59462584fbee635441e677e1287f863a466648b7452da8a35ab64ab1a8065a185aecef5440becad0a6053eba3ae3820bfbdaea23e48dab34e4070c36c4a0fa09a87d71c7a55e542f324625c47fbe2743ca4a90b8f6d105c7ffb5b8a4c509f3b79e9c224afdbae0bc1b5329ed53dfa9972afa23f7dbcf7129493f05d2163b74da1d1a91df8554be67dbcb37229fa6a47cfa0deaa0d5961ae552dd214db19462b917eea6b6712a9898999aa6a01ab685648716611f0e4131fce392bf2135ec36e5e8403118a98eeb86e873373743eccbbb2fc78a1ac87f6a6fa4a808c9b64313c996524a0f2606a42faa0e4c894016c80631605b41439c01433c08b62d1cc6f0a0dc45a08c064e4c7184ca7fa31ae2a5eeb9a8a3e361705ab75a655a7c299e9d8eeb7878523ed85628a26763aafece5907ad76b4c52692d57f2553d9fdbf00814603c1182e641686345fccafbb71e3c68b239dd4e958ac1c2b48da71e0d869121bec720c29c263ff1cacc5c3e15540629cbc71a1c623ab9a3d677cb4c41f899452ce0e0520bc8eb1f68cc4466ccc190d278aaaa199f14b0ec7917f59cb40e92ffd0325bb8208542891dee7d1789e2b498c2580a18329a260d22cc836c0860b90886289255af083904b41a35377498b1234b8c815aca0026ffcea2fec0bf6420cef3f807dc10600c3fbbbb02f980b42efef635f301f3fdebfc7be603d06f0feaf7dc15e3ede5f00fb8209e005f4f283f6050b5a97ff8ef707da170c685dfe2cbc7f00f6050bc0bafc7fde7fc7be603bd6e5bfc20bd682cffbb3b02f180b29bc3f00f6050380389ff5f375ec0ba6635dfee1fbafb02fd80aebf2fff777ed0be65a973fcffbfbec0be6b32effd5fbabb02f980aebf2cf79ff14f6054b615dfedffbb7f6056bedbab49779ed51d8170c8575f97bef9f635fb01cebf27f797f1cfb82e158977ff7feac7dc158ebfa1bfb82dd58973f7dff705fb0705dfed9fb83fb8281ebf2eff7ff7dc19e58e02bf016086770fc0c7af9821101e97dc18864f8ecf705230af2f4f705232ac0a77e7bc188847cf7dcfb67fb821119e05f7e5f30a219de7b98178c88e6b77dc1880ef0365ff3fea97dc18868f8ef6f5e30a2219ff338efdfed0b4654c3af5e07468480e7f99df77fd9178c2801ffdff3fe30fb8211d9f0e183efefed0b4694e3597fe3fd63f6052352c08b8fc2fbcbec0b46b4804fe15bef3fb32f181103dee755787f9a7dc18888fc0aef7aff9a7dc1881af03fafe3fd6df6052372c0b3f00078ff9b7dc1881ef03bbe0518118f07fa00bc3fcebe604437fceb05f0fe39fb821141e07d7c8ff7d7d9178c28023f8077e1fd57fb821149e07ffc0befbfb32f18519117fafafe3cfb82114de0617802bc7fcfbe604414f8187ee861bf2e7ea20a843f2800f6ac8b7f0220cfbaf88b803bebe29700180150675dfc100073d6c57f0388b32efe078037ebe2770068b32efe068035ebe22702d2ac8b9f01e0ccbaf81700caac8b5f0160ccbaf86d0061d6c59f00f0655dfc080055ebe2af011c0272ebe2a7014cad8bff00e0b62efe19406d5dfc0600b375f10b010bf041405f17bf0c60af8b1f08180319957fe885ca0f0396ca4f8001547ea1312a7f75a1f2ffb852f95f18801895df851e95df471895bfc7abf2bfc0a8fc021040e5e701eeba824220a7ca1f0070d7b5036c21a8f2b3e045e5070050e5ffe9a2f2eb00775d2b80bb2e17b8ebf2015500f953f841e56fb150f9452e2a3f0ae0ae2b07b8ebc2118e9eeb06b8eb0ac15d1708be0f2a7f0fc8cfa345e5df59e9e46051f971c0ef8aca7f9342e5b7b1a2f2d7b4765d33618cb7c4ff52a5f2ab72ecba381c1b48a9a8fcda8dca9f4dc1df2b0558d1c8525b485ba95c79090d2a756bff04fae5e98c2c6a4edda53396a8bce1d45709e9a91c7e8ff3e4350b96089113cb51f2a4d440dafbacfe924a3765e164e5e94af54d4b6d0f37264a3def7b9ffe3e4aa78731f4fcaf4b675ca9feefc4240a977538aa746a71eba26d51393b24f8be2d6a6e514d9452598ea234715c9840d13d1941c9625f502f46e0d07fa1b28b67f4ed6f514c4c4c4c4c01a3daa884cdf66441ec10d1080000004100c3140020200c0a084422a16028186ac2b07d14000b869e4876589889c32088519431061942080284106008010081a99a1a00f9eefc6488e4606f630c03b257007b312e2ae872714fe80b28e7b11eb8ee7de9fb51e6850079288c27a492b5b8cc4e0ca9bb0b089bf9989a40cb37aedd12c2b831f3c51c25944241c49080b87349c3b3196f2756f4dcb3d198e2ca92cdcb0142ec2e6d9a85122e32f3b3add43d7208e66a346218d43b459036438066a326c6bac0197ec1a6520c2e8177586b9871c38a360c139b33ce1da8864f61120b5b3b2150ee3873c08193f2949d54853ac1095ba41d9b08498ec8f5c1727ac9b53ed393922d0d19372d94e093d1a003614dee8426b5a2ee7a151f27bbd18d3abe4f18e3775fdab7e6c3dc5ab68d610427098dfca8290f6bf87df1fcb8c19f3f5470c50ab5092b3b91e26fa60887da360a52be693d1415a9a9b4578876e59f20d6152da1bb68e17b847b02ea233e1e05fc33147ad4899561697016d0ae5421736d6450c4788038dbb671df1df7d0d45864706ea12ba9637766a89a6a626c072680ae5847f7d2207541c40690e54b32c3cc0b56d824ac5852bb0c6dd0736b673ff1903c942b182afb33ac6d1d7227518eaec7d4f2b6ab2111680e17dbaf76c521d58dc44ed52898414bc34162d8b886d5c17be1d1913a10845f76c69d02de0d37eaddc0b966968e51ece602eb2b6e5dbff1c89d1626cbc02416219ac459e80dff86eeb4ea4f6f02732c4450bb31ad8aa620a833d6f18fc5c2978f15c36c5d7352b7a285ca6c824933d01bdbc28bafe835b5eaee12535a7d930c75ec6812c69bad96de61e4e0e1b876a6dc03d3df6eca4951ba959ebc6004dbdd9e79529d42d151f3ea4da13185da3ededf38b31a153b2c55a8484415f44dea024194b51e77933876df34bd09b06f0266e5f9cd888db8d8d18c699f7cef8b5f12a243ab83e1628118d96012cbac3b7782f5f40b66e9ce58a3252305acb9042a757bac77fcb6d75c5614eebb15e9259538483d592525bd64ca04f641689c43cfe2d1bf972a108a94a555e3fce690c34696ead7ea767bcd61f08ca4236318919832d3828f02b1e4949dfab3a0afaff772198230a1883356505b8c45802ffe1a54d5ec1362a726f07c98c54585572940f8c54fec247823cea4e16379e0e25f19ac40c7eb86c431d1572332914274e5def29ca91e70cbfd20513ca6683ad34c2ab64ada6bc3620a8784f67158cb47fc9a3f3aecc7bfdb47d4d2c5644e5225f7222dedf70bae09f1c2fc1432f051c83cc8c3dfad0f45f5387988768efa311aa88f10c9fc5a2ef726851c20bc7d2e4405d39d057c3428967017d04d98284bb7992f1d85ca071555b65112092d52c7015e4ea5d53aa95f27498b5e20bc9be0d88f82633bbe908aab84ec82d91f496ca4ab16bcd68b6f144e1c46158a7a2d738b6dd9b98489e7b655454444b1f9b044b46977e7d1ad5f477e067e20dd9a6c3d0e364303e33c65a092e9b6f6ebec860a55f0f9de0ce7ad3c54d0f9513bbc754574b23e9f157b04780733720161060a77eef886c4380d5a3f33540ecc2dec2015f41035ce00ceef0460bacb043f6b0f7c27b84403513f0761dab0b0231a8b42dc3889983274a0b525c4c89a73b6982dc600d5be0f354aee607f9493b4f784887eae02474533726db297d12ea77290102158c9c490613faf2a861e75309ed024bbe9b9c708a79da204ef695ff0df6a74b70c0871ffd65672ac0b7eb68920e9c031a3f461bb613aba7b1a2fa8b41d178002e5b3ccedca14dd865f281f9078b7f50a41029688ea389303ba059932d58a0663e663b275a8e13b1df3f734a14bb94ba7c33799d75beaca92a1d490897e38b2cfd64b4c0b788475362577926fe0921033a0949b9a22bd037894db162657dae80072abbe851d93bfc3e781b07cbc2a50271165bfc27848db09f3f223c43227d07a412d214578360a672b0f9b31c2d5ff4f74c88baa2ab6f141d1521525f4e08e9bbfa201c89bbcdaf1495af381bf3069f145271671a8191b17422b12292a9a961087402df67bf614660199c9896d6f5775e7c567213d4c8ae730cc42221055ff0f402c902a7e6c875859e566414a9f56b5a1745a81122f0dc94265205b401c0ad2b8ecbe818f4854ef8ab42a0b53f3cdb4a84f755b75126cad72242d20e5c6337928e939902c24af9872da09704a499f320f751f0b2fbd832427214c3cc2118de8bc28425fe1f2d1690077c6a9a7f59ca0a2bf3172667840627f53dfea699579ff59f7928f3cb946c22cea9afbb0032008baa6b79ff8a00c3667ccbd3fa1c8282c180202ae064f858e3156109c5c79c3778102f78806289ae434d4485e0b5f18a4f82bfb40c60191411f01d0631d3dc190ece090fae56035c442ead1f6edd0803ee7b953be3077b134dd02c65c163b7cfabe11b0569d68b37dcfe6a7e7699d667d91793561df202c12728d18db0161e2bcf0e4dbdc8ad74542cd6c3f0811f2b1a6f2a40ff9c8073ef5299ff98cf1b1b468aa088745c1f8ce38da69915dd4134eefef453338ede853eef7f2941f48609b454c5cfbef3eaf2ea21db2db879d8f3c39f2b4c2cde497c9b1e84f28535a747aad42ebb249aa31c0cf213141734a510a31e002355e1d03902fae08c22ec0859df5a90c8073145ce05762c85fc8c7cde1aa96b76eb26fd81eb773abd2523acb6dfce923ec8f9bd96a727931cdb5b724e6266825226795d48c2d19d543270c2ce777f91524644dc32433de2f6153f60fcde82e95c01c379056fd61f34ca02cffa4a67381aa0f09d244b816e08168f404fc930f2c1f9783abf0d22a948bdeb9b8376189f24e6331993837c1b232eb140589a9429fa5e4928e627a964c2c97ef85d6d8a3dba18156d06b42cf0345ee8e120062bbe6888c552adce5bd291efc0618875532201727df082ca2faa11dd46262c9a2070ee5de89189b5fa9a6d55bdad20d79369f620b1da05ccb366b3a37aa27dedf55a4b4c6b25305015b29b0323438fa08b07666eff1ce21d398e0e83e00cd09196ccd0ee46de74a5f1cb01059ac03a3c9a4a082b65a3c8988b9eda1108ec9403b9c5de265d8efcf13a387866484fac43407a92385077f9b643d9a386149b17b7a477750ba42c7c2a9a77b3e4b79e61569902ed7d4173cdfe2b54a31dd6b819805667954e5a4751965ac08bf9e713af8aa85f2d6f8ac1b78bb0b1ba07cd5bf08527f1a4d294733337e618f0bb259f96bd7f2ee4a32a4e4295146287d4664c82e39a09588b403a7178b9aa8b91e14ba3511707660c2c703e306c29d199f0d9d953e5ff625c53fc03eda24dc81d0b30d537178b1908e52b171b9009f3652a26dafc8a5cad5ef8a7f1be640c8037b92294ce3a51dee1eba66188313b5ce45d8c357697b607e24e153a4d91788afda8fcbc09c134498c4e589928bec3770c5a6ecdfdb99bc73cdf0a911f4ecb0e75e5338b93557f2f16b1987ac160e414943238aafd7bfd936b1792adb65449ad6ac6bac2bd8fd289a0211dd0b4ad78ce3258a55d24560973b48cf55e5051b32432411b9d0d4b0e67e4ed9f9937aff6861c7d2d0352edd2cdd760ccabce0e70198442eca8df812948d8481bc978264c5aa9f26f5c01f5aac7d9cc563c09d4e1b70bce7c3b1dd66e1c26163b609890aa0f800ee322bc22f85875be551597deb6eb7094ec0a4eeb1945136be237bd1e009d463c8ee43488352c73cdd96773a7dac0f8bea55cba42d0794b64a73d2e980816cfbaed781c6aa06b51f659dae1c81ed85d36e153b57da9885a525ee9120489b23c276bea0e895b697f72c31ed88575475858a9e42afa2afa1d7d053e8d442676106e7c8ce4888eeb66149ed97d5def5d62b09c077714ab6dfacad816f1a1af166b6b2014583d5bd93f5339524035472d1d75871a9e68b6a83a67598284b1a2d176ccd7d9f5456268e12e4a6adc6789792ca3b01f29e3dc857202a600d6d55de5c07273a86788e8ee1edf582cb9fbde07caa546e9005ac7f1c9138edd6cde523194bb7fe258c6fd7f4a6ea0d409ddf62d6a53ff0b4c264b89dd520ebb6dcb16594959b863d38ae118b060b7cf4c1e62949e437cfc78e46c6ef89393f728459fa8ae08e4acbe62651f2c31c513b49db553df2185d9f12e23d6127341507a0a3dfe6e74889c072681955c5cbd2e4b0ea8e0430ba57e159d157ed6a156f3ea0d2edbbb2ad3181b4dcdbaddc3870acb39f0cd9c57024c4870ce01f883ca9b2315b980860476fd4dd4cdc5284bec02e60e95ac48fbd56ba5e71c16b9364bab8ff688f16d61625e28b77db4f7f17612f7b76e3798f95c03e7fdb8a4cad466a36e2f0a3f52cd2251e51432f6a69521846afa678f18f0b8e9b6923b4bb1188d79885401e82fa8090cd7d53d2a6144687172a51e6572f10cd5d1b0a13c8b9e2be11aed72f650471983eba2f1535dc0b3d3841947673bebc42caf1a57723072c3f0a6fb4e8ca8ead49941efa7f452b5128c1d8a4bd58be2174a2349c0b0d4811bc5c51b1898b932ec9d5e91f43e6be20130cdd2a1a675084e75c10e0ab6b8c2c1f6320bed5bc0ca2ae320472303e345f7d0639511a2df7f264cbe7d245bcbc99f16ba304817cb57daeaf0d8508a4e8f431f7b351465902aa68fa5c8c919d158e6a1410bcc3cc8ff50773182a89cf92e5dad4bd7ef09b1b875d11bd1dcff16f2c3b5907dc0918b1a86e341d3cbd05ee0ada485d2cae7e3a288b879e77c1db3cd04210bb2c88f55864b6304f44879f79473446bfcbdb62ecf68020e12d51b7e2398502e8f3f006454534f913778b33cfb280ff6af11da4a0190a74ff92c27e8a93da8379e5c5c9a0b9c617aa27d7590946cef564bffffd3df3daf8689e29810456a6243810e2f2421cf3c708223711eb42710fbdad89b38cf2ebdc78dc3d188c833fe8b4626611c9c373a4b3c08bbc0b51e2bc13a76047a8f26bee0332f72d3889a34d1969809c242d351106c2b97b1b23cc816693fbff5e52b49ddbe2abc5793a96f369318ac083a04b383fa7148e83e71a0fe972a368d910649f01642683b900a7d4abb50013c72ac97b46d3611471f6a87d3ed7b7204c68729557d883469f62a96e911e89752c798a0f2853ea596b982b4ae8dd6d92cf90ad3cfc796d05965b52a91f2e65a1167079043ea34ee9ddd40a19d7e7dfdef008e5a3b0745bbe6439af15b14b07872aed34d68bad17eb2c3f4fe27223222870c5f48a7f0066cbf9136387d53d7f6ce32b8afe50e4fad9a09c812ab3f0770e1e01fd465b212956ad9325abdcf3278a81633b8fdef3841db66daa5d6eb4a26a418697355f3cc448bbe0bb88c6d37b2c31f0aeae963eb307395c065d7321c459dc167b20b9882f47e5c56b8b84f6a8659c993b13b5a5c0bf7cf641ebdfe3a0fafbbc07bc76636ea1c0579078bb17eec81cf79402e009d68279e7506d4d13dc0556c98dfb0ccf3c855cf16ac55626658f47055e77125a488234a347f862ac785f936de0c2b22459cf21cb8b26d8da80ab62aebbaeffa78a291f15562c46bcf813fd75ec18f7a7db6044e4f70b4eb3707de20844f64408e98b385adb9a131800987ecda89bcecaa57ce810c9e6aad1575fc8296bab0e82e36b5ce272f8a36288a8b36603e951befa3c4578390ba6dedc086f83a2fd7181c8c3b3f17384b050b49a0ee78f606c83280616e6a0e7d01e8ed0d48312662f6a6933e2ff3bf89b2d7fb194ee0f1c374ab69334e65ef795d9d483ae21a57115084892259cfaa7a995e7ce72d8869667ca217b9399047bee81d797f5f5b4d657372620d8ea2f08460e0c1f57c4c78c182b517e6ac1fca82f6f5e736feae807622129a7f861df57a09c9b5bcd35a866bf7ba81f2080f8db1456d397d0ece0d0cd29825a5c344ca7ae9436abd65e2f0c290580ffde2ac9a7339faef3a930fa94703e1df9b91f4708eb086f1e44fdef492ea567e4f360596f88547a110caf8be7614b347c9f11a1b503794bb29ba52cf13e4094075ab0609e0922a7a35540baf0fc774517278eb801e7616336123d375bc427dca20a6673344a030dad468aae6260323a6ba75065b192d897c8049da355bae2c6e72a98c6d6a637c26009113c63a9390fd61cec4f583d2141a9654b2f176a6c257885d3a3d0044db333eb8f8a5f60f680fdce7e72e702ac750ce9b221047c73de797910218ca882e3a21c5b78fdbf7254d489a291d089a001e171d6e1fbc2897b33f193e3463ccbfef423bbc8cc2156d37e6fc46577a1132a1bc2147c55d8b320fb3c9093a92af11a55370945e2168345c6173c748868676e4f359c901e68214bb43c883d94cd7e793cabf9469c024c5ce585c0085f6734adc0eac894f07303377bf4a1fb731db83346691a8e100eaae3ff91a7862f5805ec70a94f268f6c4b4b942e933ecbf6406988f7acb525320cbb83f08dd27df781403de7095d192e9833f77f49ef347b4e57d79862a600c790a5ee528edb0dcd28be1b930e9aa98a96e3527adf0afbcaf029dd8d9909650ffff17a6ed426861c53d0901ca0f56fd995fc04008a7eb5a290c5e235a4de9f5cc5a7767743eaebc0b36cec8ccb52c71ef68625c43253dfd6cd2a12170cca252f22b3ea541cb23bddf0db0065a3fbf3527d97e009a4d3f4693b3e5afeca161e0b8dca863691ac7364ff9bdbef4820134278bdb1287da0da96987f3028e000bd93145b071a3582fb980d2d11b57b5a7f063523dc6dc418188916a990f023b01ec20d1ab4d1a31d2be8c791276c027eebaebfc6e8c83154e4e34618e63e71bf851bd8091b8e20f6aacbf9031069ea5ba6e9fb3574ab74a3c760d72340d2004040516f60e1c4fe96b7b61dc0a665013c2259e69954130e24a600814d502fccf0656d7d697d818afd17ab08558deeb858a242f58851649c3644b12144d55cd3cbec6a5cf4a6098aefcdbcd0bb6df5252a9a5e5faf3e9695d7cebf410327438924e63f3670631bdd0e432434e0959037c2f8a085447e563b3bc141bfc14b3d95f66cc0cf1ac0f1d7658426e743742504d482462496d63d8c567a5ca3473b1ae488ac243d002540ca44d1c8817fd53b41231731fbd8f1c36eca96727aa78b6c256dc5182638b420e7787dbc626d2b03493a9d27ff280718d0f376bbf4ac6e576101885938487dd9a3be01d7b92e1559aa9e2c2d53f02f91cbfa691a0009618a2297326c819b2c350636d6938ef01404a53c90b4a13d05a548a402c87d8b4d4aeed19f0405989cadf35f52538fb08f31e29f30a1f2e17a226628b4c57a0fcece4bb0caca823db2ea24306f25a54cb41831502f5d94c510dfb8c1313ba0063b85282bc10edbb50401ddc3b3a3b78799412f20d3af55ff7e300c06d37a8469944c8c79f4187411f24dae4ea3736ce0ce41049476a877264d28e853add467063c518011a45e89baa3d09ebb847059b9a0c68148071253fd7a0844b3bc830f27b3a937e3ac187cd8e8f3d9b3fc559d6105d540dacfd4c69bdce8180a8ef7211e3c2731cf0a6ea0d29f3df8ce2089551465a32a1fec8e9724caf9f6b5960f9729b56d51c26c0e3e64321589bd428e8c7338b346e4ac22bb360fcb9b89cca0be226ba870e6c32146304991433a06a222bba8e49882772dfe9541997fcfaff30468faadef75533e3845f7cdc7970e458855567e68bbd289b5349ab79cd19567fc0baa93894b2d18c4188e445c66d1d323de802cb1a11a251acd0d9498e2dd446fc4d0c3032b15ff8c1301fa474c37f7a646c9fb12883b3450af86a2132bc6de7f53fb7c01f90797ee618ec40642e1386c2a33ae710d2ed616c613b77393be485e45a6bd065a55ba4b0bd7febacafa65477fafc0855ce0cb18124666cae0b747b40243f07f6c4b6b26e82563d7528a60fb4158d90d82cb7f13fa94e5c4c7a7f3fbf7ee5ca1bb43f4aefae641446f00a160fe3a54671802e122e632010f52208b5529271b60780c328eaa1e11dcba426f9abef358139aadad7193bcbaf2216e9a8679489d75c6ccb5766e7355a5144c388eeb661d3a1b138623075a7ee66800709e73bbcb430d2ba48830cd610c225f002e4bba40621c78b67dbce47bb925eb7d9258d548bb593c4a2cb1d0d1034e53d4e79f0979b90b795defe507eaf8a6c6f9347a97a86c1fa5035042ac1abacba4341db92d34b8b80cd509ad49feb9c9bd6e4bab7db0086288d704be611d42ec8b1db752cb0b84fcb012f0080f68cbd8b8fd6c008c7aaab58195b592725b2bdf0faa4fec9a63ba0bd26d171deac847696d21ebfab550aca17c8c3b5f64982c980c5cb230a0ffa18bd6e545e63dbe763b1f8a748a9676e61565b1e0870538a29d9a8bfa545879e246441969c4b8935e6614b1bdbf9b2d45e388413cfaea829489c4b3c8b83462c5c2e2b6d4d35aa9e8bc5baa7436fa5e8a9e88637e4022c06f06bc5106e48834a5f8b07400c5ebbec14d4817d86add15679174dc482a01463ad6387765bc3b23d5dac8b73578e6f88714638316d26c6c540c8eee972d4a22acd04483ed7d9ece3c62fb5b26596004fda624c29ea860bb85ebc04677dd4b37b3e9befb1c8bad691081b349b2695c2d6ccf483824651b259604bebfebaef1b5710226c97dcf9e0803fcec037709fd757545eef2ebc770698043b3bb7fb08b120876bb88e4cd6d678dafb77e31f606a0dec0b4d71635500deb1650f55eca1baac3961b0a85cb556d80466369c2952ab1d9af45676986df38c404ab0304d4950f0e7469758ea3f4ecae494704e07f55ee1c0e5f74ed884d1a6020efddf5ada633448315490f69801958faffd25bc17e1d8e00702d1909e01b6e929a79626b5e0f25d62b3b4a41ecaace592cd78b07d17c818d903e64d50ff820dcf75528e8773b7f77c27c2feb6fd4937be255664ed8e79cdc1e4d50de3ad3a456356b6b550d66c17bf9a01a5cc836b08dd355efd7914c136a56b960754f56021268a710b282c072a260f5cc2c506b3d223465acaf051036f1962ca6ecd3b769c40233ea1388c8e27e6fbff44390389a7af60c7c71f252f993f11aab8b1e74818753eff1c0966c55a6fcf94ac237d3469258e753b08f6de14361d6ce50e58d27634ed840f71496cea0793b80a128414c4fbbfdde27ffa2897c94d63edf2fff9d097c4cb3bddeb5ef7bccff66824fd3b6d7fbe6ff34d9f83038ed2b5c8e81d8156c1687d78e18db2f055087f08043287082b4b061b5bd211d224a1d4eedd93f867b88c25fff88dccf87bdc74cc690d08fa162d9b86ab650cd8a6ae295561a750aa2a13070de131b7a55913ec3dff0f4188bf5748954bea5c7e4eacf81bc17a6a184ac632bea9420901a2d108d1a380d6cbfae33d0342e108d1928512e9f7469a0695c20180df06dcf58d73d1080327a3e3291d77ed418a963466fabe6b6d758370e63f6fe3dec28ad829ebac279bd8c6d838de95e91f98e020ecee5719a5246ba97b8f7572dae58fd0b6993affcdd6a43e983f20c54533237d132dc12ee4f8c8838502e70080346b24d697d433ef0b55d11624f2e4cb651eab2c1fc2896ef6ec0010ba55a8e820383439e3c5f42c6a43dd4362c87a3cf1e50bd6bcb3e9194e6f164c1642129d684a497584ad71ba09d1dd0635a7260ee724078c2b558bc5be82d2b4fbd86175717a993dd06fd12db08085ed7467c0bcd872cdadab301ff6e27b9101f2a6ff4d8ba8704312e2095f504569e87822476261e61e809778629cdb5dc55219a2946ea6374db0376b3f2904cc5dd2b501d07ab80087841334518dfc75f985c4a834ba4dd6e863e4345e3ed98341e5fa42f858b3294dcb80bad954b8aa8c0fe13c8c8f704239f5d4df293ea6c28240240bc637b9070d9bc2d7d02e32cd697d1d8521d3d2e34ce46e7003c6ab88e7a6af2a4021ee0c984c62ed3b927ffbfb26e8c8d6971193d2f1c5c01adc17e631cb359c73015735a3eae6f2c519198ad9f42f9a1217a964898cf6f7ce9c45534497db944d5e99358580c2d5b566e2cec050a3c48bbb12c1a8ca3e9235e13d1444a80031b9d362b287a3143e6c86eeff4eebf207160a949dfbf273bb6a794cc701077326da9c3e2fbc208d63348daea79e08a8a040b10d38cc7da4ac492b6e893325bc6b0d534dcc3a4a6188c6eb580b53f505fdd798893acffd0b1deab8767c53cda342641ebf82986382ab531eeb875fac03c1e8f4418d170eeaa7df3247727f04c7c3dfb3598a3c33e50ded0bfeeda9c0b0f87a0bf7d06ef03c474ba2048c0a2353b7c85b00ea7937bfc48d442c7b85f3e65037fcf2415c7d38d447983fde0323c115b45020b2800c2f1b14df26f9f93c250f0fee7c367c9fa13984509933d653f685a040d3ebbd8f0f91e6ab89c003b579254c758270fb2e7984c0d1c0239059a8e74dfadef16ef2864d250b6d7e33c902b11491d77ca0ae35b33e0a07762ad06037a1244103429a3c19c023c42c5c0412101076d6988d04ae24d6129fc7301cb7021fda98d6733f9d6d968d4ef1c53554ed63959b5c0dbbc4f4430a9a1a288bfd6a98319824ea338414b42bebb84a2a42dedba3793234f828336d83c8c991d386084a60598a4ef671d412e5343367a5daadbf539272c0c67f323e6aab78d833b378144ccce6264d4ba0f5f65343588ad626f51f6360087e93cc8e82986456f20173ab4fe75cfe6ee70c9178ed24c21561a7415c89cecbf6e3d16a51063a45aef0cf534dc7ce32ac8de356cc528a5aa0fb6ee16542842adb549669c141a50ab2d4008777827f1cb8a4c106e3e4a37eac07689cc40192e910d71d5d96b911abb75033b6b91a8ad824ce7c6331af35805076d3fb0aeb20da0432deaa61779b3fa0d5eada633e1ab410bc4e8ac05a809e4e4b90f3005ac1fc6e0d34e9154ebb6bfa300022b28ed9be72e3105bc3640b19595810076f3aab0314817979526feb6eebf7868aca4ad49b1649a85f228a1a7804f22551fe9da5510095888600f7d6abc7303420398f1682242ce20f2b7dfbffd5eb6c215bafa7ba553f71866b0eb4e47d257a1810166960450917f769c6582443126c0241185f7372e1cdb77ee061c6c2ac43a0344b65f6387e83084712137e20fc2a233360ddb18b0cfd10acbcd5ad41080985d9b5cab7965c2ab27a3f0529d9dd6d07c1d6bf0d0be707b5d69c683b6eeb6e6a9e8515e42a6efb75a62fab2361f235fde9080fc7d07895a7d65edf77d9f1fe52ce12c9de1a0570ad7716088da90b9fe7a8527999325dc9bfaa9078197efa95af252bd39ef924e96d1ca8e0fe7cff1d12270d396d09d1b160e9560181973cc70561c65eb6cf8ffe3ad236ee7061c4f02cc90089e10906300fe4c173cca890436a8ae6899cb0eeaa6c99a0fab25716e367ea814df9f2ab2ca5abadf652d70cc591416564165e9860da457d370fbe2f69d219ba14f6d74e2c4cb42892c0853e1dbb028cb49694f4f633eebfc65a14fd4374d5a34733e288e3ab314e922e33104f9bce6d137edf119de8ad5fe4bfcc22b3dbe2d78f515b9f098a768d2c032bb5041026579e46e422dd6640d27d802f2b92bc125b9df5b2bb9fa36a640290f1d4caf2fac484cc06236dd14edc48ae1c028f7a0513cb8c233a0b153021607eaca4c94290d816884008f728fa85c6a321b595b8b4fee7701465e0a887b34ce401ba93d93866cd9ba41c12c99b1ad32d7919df403ee2cd9e4d40491a4c55eefaf5108299b0ccba5c24e16eff6cd88c545eb8166c8374c73588d8104aef40806354900dbbf26c25ab866665f424995a0fd5cc1b83ea7ed4b9c24426875f90e66e8763a71a01e15c60261a70648579dc3bc55228bc8c31903350a34c1fb31e389824bdde9e6fd45e876931f54e988aadb434e8553a6fec51d1d14df848f5b39525bbffeb45ff408293a6fe090607702248804fb3b8400f2ea2ca89af7211fcae41bf2676c57a254770fc9db0cfdb4551fd382cc2628738f898aca16996fbcc76380bfa17438fc9bbe21123c81d5e0fef80c11398cf91c94905d6a8a2a1ded801294f22383fff60e2556c549845dd1848b96539a212f87941a02d6e15c16f6ebf063f91ba840c4372152220b171057ca18ac6e01805915087965ec6c621196193a9a1e285012e516de7da1591166c516f4d79e720d1fb2578fcf25941304843cec79647009dfafdcd3be4d29b1b2ea47c4b8181d8a641f01297f052c66c56f9dc7a0ae8a8547dd9efbf6ad1c9f356986143b7ed6504582b7010423805e114f7142bf1351a616184518425104a67591dc9a5b04de73d42d29021b34230f542f38442d10a1fd4b8b9c080290bb801f7a4689d90cd6d851aebd95457c39e807a13caf6ded826a85a815ddbec8100fc9228e3ee8588126510eaf84bad0015083c719c3956636e2d921b4f2df56f48b029de0b48ac5b236228fe083e031fe0f925b77bd26c6a6053d0077be8c6658728823a3c2b925ad82a628f658fa5f44b3ef8b478b8d51c85152c9e2587ac7f9a7be4b101a953900cbe45b246b0e34cb082187843a752793cb002710253fb2f7aa45e8da27edcb3ddb313f7b094c9f54055d2b61f501351a5ab2aadb0b61cc80ef314ff4ab783a0ae16ec626265eadf8c5d71f89a7b2a936209dd8a3e5779903480b159f6ab0451580983fd2e747f12d1c00943483d09296da2690cd5bc545f152fbcc022861901a4da55b5c74bf25bb09feea946bb3bf94c7b7a96c5e554963638e40e088649163bd41b05988490131af951b80ac287f9aec86ca7a8faaaf0e88ee6ae090972ab5d8b3134aed521416ff4fd5d64871494439f1009b53c67e7f9181dbd68d047b05e64c0b5a89446eb7471a00abc6c6db9c0cd4f8c10b8d1fe93c5da0d2f0c9a59ce4f5bacb0a6840fa2a669ce1425d6b7f3577b6fdbdf667a98581e89de94c9cac8139eda2ef1d769421fc202d869e6edfbe74a0629158034f404437731a2144f4e03293122851c5941a96f9da3a57e59aaada82cf5ae4e13266b0db0b2704ce674a03cc99b0829bd35d88577db9ffa83b2d461955140624d8cee3723c44ec857eafce821e9d5585f6c414d0f90103cd1aac26e5b0b08c69d0068e5b59df96efb50fe27f9ea3aaf8ef4366f8c884d573b9e7dc819239dafc88a3911cd3294966490a404cfea21b803953fa5398b60796bbd86a070dbf95b2b32b75d43485c8c0b8e7cc67cc4d6ba6cc4ff5989701e00d5968a4856bcac825b8b51e9533d53f583990c3ebdbc70f0404a5c05fc604ab73b245eefc092023d94a49998255c4c165313985e2651f1d8cd9789b77cd9ec772ff2e047c46aa9819c5ab461cb052f1e04f5e8764b08dc882b70d2c90241527f53de8520f1b451df0a5de2b1ac3fc70d58d9de121a887ed0be9f4181363c6ed3d346a863cc3faec6b19e476d29e134b7485430c7bbec1949173d0dc1500c2c8df96c029a073ffbc2e9654b9785beb439d203f0b96abd44a63c551a581acc088cf3d18d8e010e72c18a0a8a238a865b74fd47940afeb524338775c8ad9f0bc41c15d5fc473d6331dc94462db9443c20eada804fa2dc046ab03c1d8a7472e72574f924b621099fcd72407464f46100c1aaf40ef39ae23eb92ce237d2ec071ae441c2c7f43e8cf9dc4cdfa1b16336c57a53d474cffb718e75941df08670953fbeb05dddf38fcc6432f2dff5ac80f736077746014b75f77f1188a117bc5c42a69d59b33f76761e6bd636ac5467b723eaddae97917767a9b4764afd5ae239f9d65e9a5ce982e6357564dc40fae15b92764b568aca946ec6685957f99140b098d067c8149877d329fed61511c444c684c67664ff362fa85b76b99fa97cd155e3e94e0ebcf8b22805e28cbdd8b3c8da2d47106e2cda75a6fae759f71e6b6c33dbae16a6f3c947123311dfa6717883eb2e38f24867825917cc6aab32c8a65881e22c628a0d51d2f6aa66897b70e4afa400389ad59c31c530f7153e5a69a6fe296117d8d9d60775020f4234d1be5f5fb11ad42fd944ada0be201e1c1f9d32d42c4c9c496f5d3e10afc540f02913590433038fff6f909f74ef61af49719e4e273a0cfed51127490d9c8831cf2e251ae621c9b3cc53e8192f969047d187e9225b439058ef584b3ec937d948644022d099179b862fcacdbf88cb4c385baec8d5470ae8a43e8b2d04f843cb829c759f153ff2f2962ce4b48d0ca6f8c3187436daaac1f8e763b3acb93c5d36b28ed82571a1dc23e18d28a75fbbd163c5ae51e9ab74736fede2b11c86ea792d4b8efef8d806ed0723ba9b9471a527a34ab574044a22ae4e5e23d36a213f221ae8f0f7c3993b5c3999c2b7b859e0386e4065195d9a1816ad0905950254be89e7b597604c60b385e1d40832e8b90d5782d6bd600de17050476f1492aaad58c33d5c34686b9fc297aef57d8d7a29affcd6801e8539980ab61dfc8cd6474e18ac0123c6794459210dc763d8d939564974fdc4e1e48de9e6a72059717bfdf76939bc52c2ce104d519e4be91691e8377f29ef45c7d4ffe8edd2d9673cb86eb25619bbc9e40df2d2dd678427283b4e69b4c43ac9c8905b8ba26113031ff381999cd07eef14b27e39cdb7c614bb39a7e1e2a7e831f4af16da5dd432424bf35aad0a28da8de7039738c735a39c71f0d3a02a754b3501563311d701d5224692fb40fd43466b81d53748a6f55ae58cd1165ae2016523d31a5a7242e8ed5a11f162ae0ebd0f94940eee4a909620d4154121c507b01d38a9093cbfc3d1324407c5eb5927f4b349ace513f906fa2af708d88f9dff4ce2e78e4fbd4a9d7ec3e2510e63eaa1227e220f6b9ecf112188bd95d213b5e19e6d9fdf6be208c62a989a31dce9c06cfe66e2db644597fca6763d424ee4896f7d69772295ce5413d14525c0b9929e7f8c39b3c742f8d2bc5796080dce4187661fbe67215c35a0a610fb03da8374b0ee051102b9a3b72ec66798750f3c7bd6c874da0eeb750085235baf4a645800c479a2347ac2db015a27e236485496027de882f1a8b8a32150bcc60280231d6522e1d20651d591f0d4cc1c0ce23bb0194a414f4186120d5bc6de6d8140c1e2a8b297624fe124c18056b02c346988291be19e089615a37e2a1b21b1ca01e6c1694345f49196f3dde3785cfd9876f8bd8b5566bf0dc185cd26a5b1faaa41d8e248cf76aa3ab737bd5d1d83182d7456b747cbead6c4494aaaf93848c4d7a80695d5ef46ce766a58fc5ab40b44f5ed5d46d83a280a243f1a93bd0938acb7c0a5b2d1e26770c65bfd2e2a149c30e4fed0ae649fc5fbe306a77fb243e2b01a399639eaa23922e23ea13990daa8922522c6c3e94ac880d8707606971fccdd7aff6bc30fec947b141df86c838c9c2392b68d30ac6d8d3bb8e0a86b319d0d2502ba6832efcc8a5600cd1586d31bcba10ee66080482abd4fb46ea4d3678279c018a7399db99f81233c39e5f0723cd8897ccf467c89260c326b9c41e77136af26a3b972cc61874bf8c4fa6cf02c11df424022a0f00776400c49c1b0ff8c630361b9e3067239549e250dad5be14361bc20242bc0c7886190eddaf7e3e3a9d63ce6734457035d02ca859beb04cd0841361c4b39a754a9d33376287d90647e625951b1eac1c5e64b520509b9dac34e5fd657322142fa119fe1e7eaa9dac1a44e9daf93cfee98e6398c1f4366f82c4899f97c3d4f1b8b627244bcf13c62399a1387a8bdb82c350258edcb5509b7db00ef35082bc9c1cebfcba4d5aa3ef6c79442b4ba809915b16bd346708c16a02a95b220dea6abd819ef265d0e83cef9ecfca8e5b6a6467c9b167d18524e2bbd37ae05fb700aeb5a7f74f5d9bda2f1d686b3a54a254926db7b17427f85de99e442425fd723a0d5f8359d604533f0bbf99a0762767fd89941ddd922539469150aa4753110acd9bd52c35672de04d291c1dd17a0c4d01086ac0afd947be46c289eb8480c0f9ce12f16b9ee07b50d135fb404270aab9db50cb3a73bbbc1df7f4b29db6b432dcb6e3c1b1d261f091e5eb83ad5fa6703565567b9143a2d0fcb79a1835801ca29764144a769da946381d69d642d555e26c064ece57ecd1d6c11f049a8215fe35545e453868bfb9158f693c03f737840bda1e72d66fbbababfc4a3b0280634c47279a531fed08030e50186f01b0d37590781ac41eedf8c50ed160954606e26334f8bb34f8afb3e953390b213b55e6c436f557667f7e87d0e53f09d0a51a2efe167df0b362f9ecf0b4587864b594739c805c61428054fc40127b4a89661979808036c7a8794548fcf7ba76c9d6dea1990fcc159177ce34ce0fa9ec2b6598cfbb2c8325a2c49321714be67ace643539e70efa3998992c2f235c4de5c6e6be17dc873345f5ab9f75d6891de7dea3e3c7d89dd2d13d6d03ddf6ee1fd6763cb8a4014623ca256af7e7f9dcaecaa487e82cf163191d5d54322ac0673119351ca4380ea6d909dcdc5e6953246b0bcdae7a38a2ccb5ecba7521fc310656e6359d155cd6d976689036dad860a40a57f2be2c6e1928871182acb859667c3edc337d3a1a25ffb5f5f0a732c4a2f0adeded62abe871816273726c26d89226a3fe4c612ba633c329a9f491ca92faacfbe3d5a5d399a7e0dbc03af97d0408725fe74458e2a2db05d05c96b03e33d064ee358ba03e3df399962640acb927cfdeffe993716d7e125269755ab1bf500ae9624dd1c881bd8b74bf0b0c49959460af1adc7da2206d70dd8dfdac74415e3fd1011d9dae8b89ff0e04ff1344b303aad860aa2d248b78749548d467b78509e4f92c3e61a2480a36486c41fc9c3491cf10418d6fc9e82c97ea2e9819bd63c79b0614c82a4c1ff79746ceb4b65fea2baa6f7686a7b9389dd0ec2647332a50de73ac11c459aea451b949579cef6fe9af50ff37c36fc8f61ab484d6907c34fb994e3f918e54264e03064761fa1e317abd33d2b74684a310fa876e97630a6667f9e23ea211e4b1c6a494d5a74aee9a7bba607d657d74f96b735e3b0f5e21f920bbffe78866833c079e538ed7f96624d4bf98b94a9c9b549321ebf313e745555bb4d53b4e7cb48fee313b72e64b6acd240d2277fa2e695b538e76ce6cfbcddd61ffec232977ccbabe80df1c229ce2189856afee5741cd37dc6b6df01599f1ae6fb789f14e9ea2b3871271f96141b69cf7aa061dcc0d2b46eb76eb46e71980f9f0d53484a1fe71f77dbc9a09476abec4e3ca089196f10850298cb63502ae7878718503bb50bac7ce8586a7ce6e712e63f225a52cb6e6012da9a3aa43b4c30ad819c30d789abcb9177a902bc9a40c9c079ce4db71c2dc429f3196468a3a7f13570ac5b7e7d63cb1992d602c7822ce274d23c17de3656245b06c6e4733f265ed5f361a9431d276f45f8dfa79953be544377398733a8b3e8f2904452a6b159cc54082a3907786326d1eb864b0bc618e5ba79ea8df84e37a42ca9aaad10ee11249b1a759817247da7351d3c9c7b640560c619f23b30ff08e68b9b18ae2d94053f5e9309478f00a222c973ec9279ab53c7bdc16eecb89f53e3aa9cb38444403ef52d35c69be5a828417190d2fc315e30299b6991193736754659db25f16763ed5e8c37b0c0ceff456c5570a2a578741565b825d17486694306f2b6848069c7f3c19ffae0ae87664bb0bc9c22c23257741b33c5b8186fa8a03125861777e034ddb2e8b2424f73cc9725b118dcfb0065ab64f47061b7d7f45323b8d55aaf60e193cce5c104249b33513480b0f65bb87803a4131f839917c738295de37cfa3b1548e584f4198c055ecf23b2c837321d9c861d1ec439d0a0b9b85d8a268251248f1c329dccbc1c2f0272abc01f145e784d1ac05c1461688a5e2ca8a14ae494fbd187f847c62446fa52a20c97be9415c4beaa69a7b8d17f145fceb25db941fa401173bf618cfa47366b00249b193202eab9f1e80339d2159859333634f1c1a667265a6653b75356c8cb6f4400a6b884e60ec1dafb7aaa79f09320b3053e8d3559b0d68e7cc4d785febb8c0cf02eb979aac9e07f12566fcc2a9cc8423c1bb77f95c4af60bb1fe945222d1207a64a44c07bf8561c7122faf80dc0c12d1dcd9d99beb7b2cf80dce237424df2f13e63f1671430d224003877c21cc7b4e25e5501c36fa1d11056b5b866a958f3b9e20b43f03d5047c11547958962f6e96447e5d1308d720fa774ff67314f8cf7c973667e5c673fa08f6960d3f243d74f777ad2036253e2d492ade5322851df4407180a00189368b1b858417c7207a728befefdae6bed13226e41506232d28e1bfceeefa4949b4dadb720cc85424259ad5e858d8f267c43c23c660fdfe4566745b6addb15be8c03240ccf353dcf0fabf7b7947200e9a52dd02fec5a454a152f00b10e24aa89810ea6707ee057d41c883a5893dc933a704e1134cfdb2768f3131234582a2a0975357c0e1a5c058a6114e0ae5b06ae7c1267ec5da3da86ff8ac861ccc7791ae7cd5fba1fea287c2137456a51030fd60f62db750358c84bb708195afb69116ed09ae13f963bccda18a2dbc52403ee6fd48f4f3403619a30305de273ee783dcf033d69b5d2daa58fb56832d3f28ac9d869357489602e0e52dc5804bc5dc684abd43efd682e71759858a0020c05c8b5188538817cba910d721867af7dde666e9a1b6209a54fb5d8c3f4656a96c96ae3830ef2a2c41b8da17e75e60a8745f52bc5934eeff30685508be9ac185c7d9c4979de4b33cfb266993eb579f21eaa0018725473368a422f0272d8f090c677c8099493c16915ab8f45e7f88370afa20bc714c21b6d028e51b34b3607ebbb00005c5d4157a7b1f4908a9487937e2de75b33805eeb6817b144d4c3b9626f313cacff3f7971a439a41df490b29e3ecb84461b3b8fed352aef0880cb1b16cafd3d618d5e63fa4f09e7cab2f5399cdabadaee92e29e144bb0b62416b958cc0ac4dfa72dfcac18c97cbb75069d0f38149f81a7be1a98a713ab792b4eaacdbc7d6ecfd19d6f722386246f1e08d84b97fe53724865afd5408f2248b721480a9663fa88a55418b77df3e1cf26d4f9cc126fbc937992084745797e5a44d326d393dae0e221bb09a19c4aa23cf8a30a8d30b54e4fdf678cb82df834773af527fdeaa13df84fa2308fd1196985623f755911e1e0853ea2d9abd7d469d82a8cb63836592715f5d8520755b9832430a508fb476aca2d9da8c1bb0c30fa3981b39e7834a456e13de0f19d37c91a241125f35a34077f4b328638098294d7303092435529df441595886c160ff2f558b5e0c342b514f32736a6079c11eaec23e986f50ec9ac4d70f91a71c5587758089e17ca857412b5832f899641d6aedf3209cba44b3082a7ed574b3a5dfbf5369ba002554fdcdffc5b1f1507e686fe3d06d6271f780781a386f472400fdd5abbe9ba9747e9322c562b18333406326806f2dd31636407a19246d2f219e56435c7a72bd52d4ce3aef8002f82e000e5ba7694a17744ace5c107913036adfe8237d697354714d5519b848ef6e39b13a9886f333fc674d44ca5f130d57c2798dd83a30c5f3336d995cfeb58a4af7570a735fea9d66e846693ea2c75a102b63a0ae7b953c51cadb05fcabdf84d4520b692a74b840d10b099f327fd283559775c30cdb82fa93f2762f95ab04584ed72f7d829971a3cb955de0a06046020828b9d32d6de7130ba5068031eb9f055ecb91fee8c58eed8e9f9cb88356450c620ae8eda543c53666c267d839389c32b7caf1e9dff661cd3b842b6e8b64af819de752954e643369b669861a0d29bc5d8242a9caa64d9ffe1bea94687fb2169b6d3a82219d95652f8e78f95ac2b41a57b2c9a5512e7322b526640345b9200ee8f54ea0a91278ab849e943ebb390e30b95f1c6ab3f0c3a9eb7df16b3d6d570e1f99c7e10ec65fb2edf08a97cfe6acfdf911ce92127d0eb97d7050100cbc2a853b91281f56da2a38b8ea14f4f9fc3439ede7d2c1dfec4cc9e5320c4ef15aa351b02bdca1831248d2042bff9656cd2dcd4e619fd11a66586a88d9fc3447f437094efaba76577e1eab4e17c4a56860c9f989925b8d6e052f294a2c8e4a0d4bb535b82aaebd60e5f55279a1d314ad4b18d9b10387bc3694eba406d60f2085258c387575991f709dfba278ec8db674d2e9ea12fc2bd0c30d742977bfbee9920c24e452f4d45169ad7996779d2b2a956a3caa932b94452f3894a59da1c15c3bcf77ec6353ca6e3381eb121492cabe9156b8586d8b5582b33bc53b03c8c6821626f0185873fbc58bbdfb31072a9e4f410fe1dd8d542f735eadd3981eaf29d6ac3dd1323010c1b94e258d27c215c088933f81352bac5decdbafeb3abb243100f18c609e140d776682e93b57efc5db13c1df64417fe89c6b7704b08fb51eeaaf66830c823e02938845456ec538a1c0ebf8f91e6fb31596c57c49140c6370d7c153563b69f935d05ac705b60ffac7108d45f33ba436f4beb6f436563d80341fcfc3cac5e266cf8d564b9a1d1c897947115b09968a23d4e30b707d0f195c3060d6b71d4b367bfb7656258a767185f9f7f69d5bd825384d7132cb5b87fbfe28bffae397fe5c4ef46051e00dd07a9b72cd06f573dacc0b426b42981049a287dd7bd0b1d41988cc027699e6ab550e8fcb445759a09890773e4fc8541236f1bdeedcc7932b8944e19235aa3c65956fbcc78ec85c6b0fafc92d61fab74eb0b2d2ddce333f4289e91791a55070cb537a64b55f53cd558af5dcce24ae30b68b73e6429842836f4b35f9eec1f0df48beeb6fdf5ff79508e830683c8007c230a51dcbce0ce2c22291080850ae5a9a1349436b0ee3ecfea689bd1b3c16993fafe59a850a2c034f02a9a71f66873529b74ca318c8834986125f6795bff498e8a91e726fff3ef0aa3ef3b5fd028d23ccbf3e07a125f8537812b694e828edfd95878b0606db73339a4979422b5d64f42a01a68e1b8a16641203f01443b33fbac2a062a9f0b65270cb3e106c84f502b823cbaec2dc26ed0a8b698afb39c685ecea60e51c35794af2092ef085c1df74ccc3cfe188c4466b7a37e0f1d310e1b438e10b2c7eac248594d3a8adf9c1a68796375ce682d452d32f7091dbdad105a5581c8364013d542e0b3a0e528987c3c8d1d8fdb4693f216eb4ffd5db84e4be09f79b95f1d6bf87b529fbeb3d1327ee4560823ff7fa6c4b1202ba1e4e4794ec472e7bac40a610c451814a77b2d950146816617410804133272a09902bdc75aca7378202e100fe28eedcf19d1d13477206a85dec5cb72b95bea22189ce04608a39f02a6b45dfd3e68b8532076d7e7f6a90de6fbb242999b890612b057398dc0271a9d0be9c0ef2c88129d0fdfaecaa383f197bd731ba37ea5738ced3abe820f9e804b1b588368dbed309e1a62c0a5a3c71af07cc2039b7f183fe40351d6d82a0785e085ad31593ef885a53358b990c4cc2c650462a05a3e963a63ff2b5decd164022e07046205611a485f3704ad821078410afa13af1205963767094a23233c585473f1002b79e8c1f22d12f241c48078826c36a492b0438a81c414541668aabc1c3066eb36da4a77bf7234336dddc5402a03bf0fe3503de1faacbbedc358ce719212712d5dae67c294508a4cf7092648e738be41a9c4a48eda2e4f386c187c851255390630029e21a92caad7d54c9cf048138355a38408d1397e6eb4e35e259c95e271b815d682e7f2afe741052d1b70c0876809277e067c62211a0f3a2921b2312e4bcf4f7aa44d0b57ec3e1c8fdad372e13a94aa9366747c52554bf7427f72c586b8191145480a7cbafa2c47862783a41a0fb2ccb1f0036d0e9faf5e5631a35668beab75c36fd5d6e827f05a6a1e5c714f3c493870194d35993218a55790d5af757520d484c97bd9640bd7422bb1d42cb2bbace5c6f5fda69840d95b4d4e097e657fcded22a9d297fd92507d8c0ec7cd9371b704133acd1db8bc6c3e1ab79f15e985a12349ed035bd02ea14fb539fe51233565156a9bd6df98626cedfbc934b9257554472cb75e6b35c986a20b89d41e4039d0f2615345015fd335187337d48d43a2b32094087f2466356aa54b0099104f0a95f92591cae96be5761dacc8c28909ea7b0296ee4dd651d9557177c6fbac2b549f9904303f652d8e808b85051b3078e68c524dcb64f4b61805f697948f24076667af59af26696e0e4cb59581497f9828fe61a48e547c60f782a4fc67e84fc9ac9784d42beb0881345060d544fe5fc3cb0d2846e732b3240caffcc60ea17429cfc9277e6515170afc4b9ac4b4f9c93f81b8e556af197bd5bb16186b690bc9f1cba7d2a683ea5deab15d10ba4d09c66fbea91a03c2242a4e1a0733c2e029695a8fd10b18ae74ef255c72a1a9ee9fd161d3677f3bc4a2ce9afb6233e0b9f9aa8b98325776be92498eebf9b2e4e443bca3af48c4c57ec280a68872e52edc9e76caffbc2d55b7033161617880cebb31241eeac80211643066b0cc04e1724e48dbb60d545db168a55e778f902971ec6de93db1eb56600532ac31f28fe4133ee902d2a88c2947907d036080d4da0d35ec811ea84148a98645f7ff9716672dae14c0c0561d895b5c17f13ca97eb0120987c4c9dc08d0e10bc86194f71e7ff8b5df8b82253d08de99f58bde72b765908d4ba5cf493dc15783cc46e435e4bd14a02de3bb1425861674c903a3e884e8d703294f68ed54e7e3ea95038b2cde679e91d7b25c33007a41acaf75ea2f0dd5f75ff8393fdfde6bbe300d66a95618ee036f975ac47e8c9f4313544e0f3d2a4287b82b1473368304d21d1914f5a92e2a94a3382fb9d29008950c7f70a5106f36c910d7d2acda31404a656d92f8186f27fea35910a43e22fb2377254bef888ad473091d7b51150ac99efba4b1b6c0c7889c86c27c9cead524481344710a20e5beb252cc380479677690bd9d633141a8dcb3b9285304f43d390b62e37018900e3b512871303f60e8d9cd1fb6c054b902417934e01f3660b0cc8886ceeba4d13cd7b6bc7951553ae520068b110bc1cce3711aeb01750c8c1f31de6ac7280320135f0fb5197c40f603a46648e7325d45e3df7e21cfda9d63226d3d5cc2d810556150fcd89d32747e1913d0237eafa57ab7646a15e1d0f7e928f19cdabaf10c089226bf661f41da524553c29379b763949f8585561392d604de93a0194701a7ad4824779aab316b452c3d61245832b28f67b7116d684d5ee495a49b4676028abb3cd18a0d1a44946aa0764ab0d592f2967c8090f4c7b3ea737598e7771a59d6fb5527eede2bbccab8231304b8eece0870966648aae87450c12a457ca021e76a7c0419551e9a6da4b6cb07fa53cebfab1d381b577207849e829fc85b26aef139d3f02ff6a55276b53ff6826125340c15fddf869757b7585e72b217e43af610c81729876da5020a81615e65d4b392e02228d2d498c301d7be3350919efc6283a51ec580136abd7373844676835c2acb575b4de25ea6cbc245bb31f394a93e39cb53c4cb9312431f58c4b12cf24b3e399844f02935c1b5cf0747ef74256084628427e5dacd6a29898b1d746b20bdb7e6cbd32a00d5f02139d3b679195c22f74a63dae4774b4def34752af12978848b33aa92f47632375db472f05732adfbb2ae4520e6246081dc2c79275daee00d32d8bb1176d7ddff20700b2ce913e8df552e4c8610ccaf03bcc734c04bc3888264fddad1985a9cf389d56df72e3335e08b265773dbb273742697d6ca04f3c1e7411aebe8d56b428ef06e3324026ef17147e11dc17f68635cde19596806996c501f4b60b3f6fcdf898db9086ccbcc8e37d87040534d3ce3276956c96184a04f2026327c26ac9b083ad4fa37749affce8c434f65de20c83ef62926750628674c9c2d8d32fc49e3bb0461f0486580582636ca890fa84f202e097926584d4e496a7f3da8f5a34dfa565df0236b5a8aaa117f773d2dc3899d9382e9bf5cf07c429431fc1392ff3460ea28353cf8b53ae210911b72b0f70ae623fcfda213b4d5ec7de833dd1b9c8af60948a422b7a9c1ced2a3151c3a4ecf657f91ecf41bf5a825611c50f691d1ad49444dc6a8496de21b2568062f6dc6f7dc9662eb9d3302d316282b22483012d595be867f40f69feb582b32339b2b97590a509722cee918e409e8daa367d5851d12e23264d3f6d073d81c25bca2c2f94993046b571b3a636ca93cee0db21a27a90836831d103b22f772a06ff5b61e4e074f00c0cfb8fb15f108585960cff591eb750f91365622f60a6788b460b253117e2a5055228272f06c436e470d56ba961789dbd2ace13c127e3ab9e600728ed4acc51c0e04ac2dce67312a7cc8903b5c0eb3da16b12a7f1dc40d53f6242491a940f0990cf035cf4113c12edeaa9533426627fa8207a78af9751f09e4c9c6fd8bb039bff2382a027b890b7ca3dae0ed1755c202088e88e1ce8384a66e6a9a4b46261e0de6f02b91e7e38a373aad6ec7dc9b08cd31b0bca184963eccfdc0f5f321c9a6760b933a73cc00cd59c16ef1b35506899fe830f02f00a2894948c36f934d6a7ce046558d0fc992182c9ef8322cf96d38da0e2cb9561306a7b8c48ac0f55a54d48aca0ef32a8dfbde94b278398bc645e2379dd76ac6981b2a4dcbb994c313d167d6468a27a8aec462031529d543d7be62aac314d036c2dc252b905344a8e278ee4ee181f3097f7edc64d289b148e67b3e3593ba59eb2adb7ed728d464a9cd06de9a410c2d2fc9bf31dd4897ebc9ead42ae4a8d201cbb50d207a7429acfa30347616bca4f497715a2523bbe2f1cc1ec0631885ee1352fd4e5885a511f85674a423598de4df2edc6b9e956f1ed77426b83825d444e461ec128b58d25176648b07f82e6269aade0b346da6781fde324a19c029e543fdc5382f8557046ec60be8e9fce64b36d20f9180f1ffb07bd2878f522628e6fe996ebd7cae35a713813d0b2a6e49b4b0d2fada5f9a6645342ac876b2aca5ea064fd13d9652b007a365370ff13f0bbbe7dd010fd7b294d091ef0de48e30193faf6d0c55e54d3b9adc1310ca826e64261755e4d5034e56a1f0d1aa13fe38c5af61105430fb29a09188e6bd23ab2b66819a5c20155f7d1fa011de8d6240e76808a8888ceac6e5bd67035e9711a26a117d67c5c14762f3f94c1e0ded36adadf680b3a5b28325331c9ffde477699d0f03dfb813176b8c4e7627959d1d877e474a738993f46137ba1a297b2534e75e4f908256ceb87792aff2a1f11ffe99ec0eff0e2aa0e4262715de4b79833d3eaf5226abc5846bd6cf061bfd9583b216cf248abaf1fd6070913a3f707ebb26ab86cb0b130871b2f616e8f5141378eaee594765b8cf649f80af3fab7be17aeeb753aa64ef8ec49cd32fc20dd5d1dd96c27d3cdbb581712da6fce8f987986f0deb441f3ee751339d439cfefff96560b11842f861d5354ef28079106adf7eb8088560e4a6b22074a849a588d5c75042203972e32b2da77bac9585fb23d7db17d42a57bc60b7d08054d953e64554de39a04b9c24d7945ef22d7cad9ddb5856b03aa400feed5aabf09d1bd60d06f089516383c311f7f78ac4c6acdb68c419e039a6150bec2e09046c2e4995f5bce65dd36209c3f4e2cc8054292f9f009e5f2288da554c560d8d024430d22d8b762a16d92cc457243442adf25d219a0fc89b78a293fdefeccc77ebd918629a947aceb601de8258fd35ac83b5fe228a0f328dad21b3e75efaade1081ec3b5a89e615f2489d72261356f43faeb0c0e02484623fae1d293cf55210752c0ddc40265ec0bf90613c142577b0c4e5faac573d715287bd2c21454401ceecb45722f1c144530374ea460de1e6fe0c3c3f2b3c9af1ecae2f2cbc3f5ecc10060a080a26bbeb23e1aed0ddea806df98cfb8fca05e9257e1139cbe7210e427d6af98b5ff0494bd4edffa01ce8d848efc1e34498b8a9e38e8c0d05e87fdecd368ef87d9845d2b0b34706cbd67c2331d22548aa410e88f2a7596d4e2df9d59d165b2bf4fa973386d8a6a7d15144cccc38a436554e0399a74a854e375d2faae9c987d99cb436e7da3ba0bba64821e390098571d8c2fa65af64681e570432bcee2003ca1c0b2d0115e87648948fd30b6ec6edc1c05bceb6d4154fca13da8b4df9208be4c1f33933efb2556f88715ff7facd00044defd8cb25a65c1abbeeb4656146fab35f054ce56ec50f1ba0c512c52aa02e5688c5069e12fd97d802895d459cdfa4c06c71552f75c1fef78f1b2e5911ec819a004ce2ad3c5548b49d52e09e9dba0907351bc4ba62911eff30bd56a95358cd3fa08f3e9201e85069855657eaf5834d5d52544248e08d387d6f75c58d4c02e2c021044fdacbe06eb5750c4fa1d18631af2d6ed49d79098774d4f6ce2a6e44d3d27709e05331b8de89c57a76cc1c0336b35a70cc4ccf58047d204dc7a456bfba0041eaa8e35992ece03f2982f97fd0c5d640d1c550c4f8b8ca071dab771364b32407a967741b9ad744972005361f29fad3d36a36e7b7f476bb8b6a6db48e02beba9fd4b2415b71216ce091ec825515da0251456ca44f4a2cfbc00edd6507a2f44890ddfa91d96c234117f87014388b171ada3bbec39e8109a96cb0a1bbd6c9e2bb6223b64762e0be0961b7e1805e82993ff9dd181f5d13e5ecf52d67a763cea9859603f27b97bc54ce62abdd9d1e18a107147be07c8b53ef2488c208ba23abd504c51ee8796b24ccda856bcdc24cd2a82524bf032d74b502d14588dd3b4ff3b7e1bba334393ed6984406714eb0a67192dbee2ba5783f6b2c20ccc7f4d0f6651059c548f99e65287da537d0a7ef056d5be81031ccc2229290053dd106232a517d40013143ed9c40a191dd8dcacdbcd7a85c0ff0342ec32f8e2f65a8ad45ae53bbe4500cb9ff783cee8bef7060d1c202354082fc8ef0e8fda0b09f29144210ab08386d30d85872c603442a19fcea13d58b25af1abc43e1440c2c1671eaee9c9b8fdfcfe78e896a0d3a08917826db2d815eaf9751caee6230466f25fe00ec3f7aa2ea033698f68b830e702c170068b51c3b80270ed68831eafe352a5bc4d5f0608808bf2300d4517f620976234e846852c629bf5c1f0e836280f836d336e0e674de2d8e953ca58ec744fa4ce0f6166a6519d8881c37d3ad4babda1f1f06dc81746a0ba281d85ff7815c1d35d417fc7a2997f8120d1df0ef67dd5ad22ad6668aec5ad5a2d240254a74faf79d9f90ddec61d0f426bb1828868af387edf13a3e87e0409092e6564f80370591b80a078a2479aa6024a7223417141dfe94ac6b0ba87632773762db9676db70b390f0a2df2f63501c39195c3ac463f1aaeb0e3c05111217505fe3d4077b33904d06fdf348aabef16d160fe25bec9db8b6501ae4cd50fc9d038904b932fba76e68eac89a9e675226da5bf35e16426a86ba2398cdb5df39730c6697d5b0062cc12f256bd78e83b295be22181ec09280621f256113204f8e34c49acb713f850b5649eeb55d9580aca660db1ce28743ca196f7b26afc5b7b6b6a67ed140e4713c37b3197010166d05a53d27f5ad16b86491753d3e2f391a48359c400a1fb9a7403735323392e539aaca2e5cebb545a5a32017433245e5de1248a1d6955e09edd3114a9a459482f356280aa2bb98fae329aa57f85ab969fc55c11798291d3cf59b994dc555557b5795c9b32ca1b9442d99c19210aeec001daa39d94893d6a1e29a831f34a613c8da73600255999931d4c7390e64ad457f9b602e980400572e39cd1b88e5c9f052fd930db7b13e5016718384b370cf7edd755ea75a73c736436a19d03215fca359f663c7af0f16818115b9033cecb7072ea4560f21de6d44a0ec1abd6d9f3af81404a78d6bb666b5912105d921fc65febcc9f272db2d30002b616d477eb18e714866b6e41890aee1f3b4061dfe4b3d23905a67a98a882833acf6261ae426d0b4344795e1748248bc3e89ad48af708e13caba08cdee3d3b94dbdface923b309005973861868e7c9295c34521e0906ad854e2a1419a4e5b10278da3345fe65ee728c81a61dd348e2e3604680285d2402085b52009a98e1d4e61f75e17eef53aaf407bff9bed5b07b891a7030d7eec01a3c3289d749a6adec6f78b930b702fbd3a8bb0c081cb2e11cefa88c0c0c3e7bf036aaa59cfe626990dfd3e85ecff37a0786e25060b91933a266451ca90d03c73b174c7f00641e2999a7034344cee08fa7d44043dc7db3676a00a5dd586c4e6fddaaef302db3694e511aaf3302ab443525587ead793bf474c7d3b6e4a3192351e83275319fa6cd042f962cf82aadfded240c0aa2dd9da2a41d60c8ae75441575a7d1e638a797aa512c20ec2acd380c3e77d321660ef8eacfa32a4514a28fb601e8f87f357eb7d82cd167c45c4969a3af2a0b6055d046d866c5d9ad8920eb90e64d7a2d4734713c0915f12444d9782e768aadebabe43373fc139fbd605c4dcc64ed934c2e1130b2ee25bba24fcdb1d1f5559a55543bec4c60fa68ca079ddc53e9dd7e4f447052dcefc61ac20f8c0da7de6dffd62328740522d9e5e7e8cfb119f86009c0a0c72dec3a757ca64c64495d9d16a1550a3d74bfac7aab8221bfb6163d45b0a53009fba81f259d09fcff4a9ee3f30b4303afd87a23789bf1a63ecaae08578d09190ba5f68de5efe8c920a922c40373c139ad601506b2f4bc60e2129b78826b17ac5d954de1ac14f899a603bcfa2ca18742b3d84a66e23da145b4a3c42ff5c773a62226c8d6a8caeb50a208908222b2f601ef3c37599a48fd505bab6b90436c5cb2189641dc542603de80c1bee938e68a0c28b48e6857c5daa05ce25c4c84b589b3137b280c1df8adb5f4417a497947f05217dc888f684f6873793d12caf19dbed38cc967e408b900d239694a982ec62b7abccaefeed39feeab13aff90550e70e6e5b97c2f664e8b09d49df95b3729ac67ae5086f03261c99ce9893e7b7c1972822bb50a06395a4319405ec18a632b53ba958dc67ede821bb0ab7d7b36afc78a9722eb3cf92ce6619701f55333e845b22969d4a896b8fc739ff61ab78b66242f3041400e8045eabfbc66ef5c4082b2c0990b31073c1332480aad092714d30d082c5ca6a74b9128c413c873726cd010ca3ad4dccd442fb8551afc2fae2ddb82a5622677245814dd6c37342af69c895da809f94c4db3ebe4232ee2198ff218b17b8fb9cfb36747aafddcc32a02d91ce5baac5fec92107d7f2a891baa738867a0987a92f8c2407c8f54d74a05e5310a2da05643be465f374e90f8324638d86e7aad04f8e78e58532eb0b1baa849183849482f33c2660a9de2f5e50b245b417ba2ea706a8ce83c55543fecfaa8816301d98f187670088c9d9566cacc2941a490b470867085ee2161786d1177d07f673e2c0a8651d868a4ba2b976e0f2f8dd06f2281c2291b6a92844ac498f929687965d36d896adb294ce9c643d0435c05979d56d159ada4a441f6101b69b8bdbc114102f63bac7ab7ae99d62f3237d4fc4fefa46e8e44b0f64c847cde1ccd209f135b8c391c4a441bd2c2813888f62b903e46e6d6ea1f835818cbef94196323d420f5a89ba871b54982115415735db870d14297cf51d844e6c059e8fe85d6edeb533217611da6b19487b3aa91d41a006447654a4eac0a0f286982eaa3f11d1ef4c4309ab532bdd7202a4fe76543a2c481d450055fceb279621e445a4324b4a30cb73bdc817d6e160dcd84ce914226b992d106e291267e4824eee77c0a9d465bcc8caddcacc50b1b2642c8448e5a8a0f826ee8300e2e0890ba7c84500c22a0380a81c759852983bc24683ab87be4814ef38e2ed55a3e00400c3b505dd96238d178af20e18b40a622bf6974d7a3a95c01157dff989f8d2e2c9e75312064cbb8963ef7f34ecc400730d482c3e4a9aea1ba95ac8dfd0a264c43694b03542e04e9034f85736c5a14a6741115453c244c33d87d9829f102fd9f2db3546e166b3fdb1ac0d4e7f49e0e7cdc3e97e9b0a9d2b968ebc04edb20bfba1da7b56e33d8a51345864119e91be84653069dd51201cf312abf895271e2a37311dfb3a9d16df93f669992c6dc4b208a62254e84a5b65377632bf89ff7083db0ff0c332e9064eaa61b39512645774d0e229333b48aa845b4f4eb8f93b8e69b360db8639100db2b50ea1d4b0c76b8b33c4b620cb528162665dbb716581c7759d6c9d2cd8d631b594a474a9e21bc65c048c9f6716cd4b9aaae4472329f49a7b9bf8c5b7dabb606cf6e47930f0df472f604a2a62e03118d07ddc31746b9aed06d79387de62e286343f00bb5fd56bb02373d25c62eb8b9cd082689b50bcd40aae1b9782406b789695b073c271d4ee38b94de5c7d178b8ffeff91d46eea483089603f37804bf83962e656543c2324689a71d63423f88fc2dca29e319045b90c6050f19b74da2b9845723bbf2924208d8b65874a13aab6805db757a398497e9a31ce5f011d3076e49c6a271ae7dd147418b061602753ca51e6a2f7f4e366c2ff4b992719d174bf3c21dc1b286800a6724b51b1097d1912d3ca829da55ea9850e2fc19aab11bd571fb743fed9285790b98402741110da9e3899321f0647c243d5cc2c7605286a4475108446b0d46c2aa985409b083117aaec0fad22d080401735358cd4554decc2d09f7640b8ca7a719db6b129f72d298b6381d24f5ec83e4e9e861300fb2d6c00f34fd4d78b619383106c3aa5093274bebdfc230b8255bf44c49c6952e1414594f66af4361cf24e1734a3e36553297e296496af7d8db57c5af27243b959d51f20c7eb4654a0ea2593852adb900b5c90c17d03aa8bd8e6b9954ed47653882157d694853eea42c8cf59535e1a81f7c0567c45441d5a9b4fdd7bcc2ffee32106a88bf1921d66970313ee34652c7b2db0c41fdeae14d3c0b93832d497bb572bc004cbccbbbe704d10f2c7018fbc2aa4b7ff151e6eebd78d87c010c88c11c2e799e9273ecebcd3b2b4d7eb3be350bc15a8ee8d648cc49115a99c775ad63349caca8e261316b716a94b99dcc9b00a72dcb9cd8448e470cf5d90e9c5a6883390eaa4bdd84baa353b949145c98e6ec8b979ae700ebb7c70b0a2f9a86cd3d94bc6188fe4719afcd7394afae850b8b8a57c1ed6ae883a520084b317667408b69296bf68a92c51e0b00910f11c1a066361ab7cc40d01d83cdcfbad8efa6400c7b2b7df9cb84b6049808a74d860d18fa8f347274977067aac57790114c6ab32bc74e8039b06ef158cc5ab529e8b57b9147575f9885846d0b365ebd0e54b3d60171f0bfe7ffc2445f5c610b8d00cbce00e62b43e14dc55d2a32d63f795746c0d9c84a09d19b0720b6522e490447cb42b4619c3fc12d125e0484836180364b16ef6dea3403c74d9f92d93028102134dbfecc0f17c46a4d6317c5cfa69ff395aa84bef9d4ca8e4a81fe5b9e387e8663083d098f69e666294620842b804e0b10d7e5f0fdb2c30e7b19c5d7ce9b0bd54f5f5c4ef25fd8e83d22dd6201cf5008a0957ef1610e8868eff4b34382ffd76a5ad167718a0970451fba13a108728a21e040e8ddb9159e2a4d66990f6de00e9f4a49da729bc994f32fd21ad4379c602b13edc5ece29cd88c161fb53e7b5bf221fbfd1544b408cdfb9b69738c0f444c38af947f04eef7224ae440e85ce81132ed20fd6a08b7e7c7a22d5d731145bc1af3cba061f15d7ae04e76aa435bbf6d5a20cd051450cb00d054926f86e832992c800f82a449879454bf11d111e40907e146d6827956a0d0b635c054e844b43b8b8155af0a47b7c1b92f9c177f588afa6a15e7f2c318bea4268bbc11af70604ec9be9f6165d827ad68d513cfdeb919beebfa6f2b92d8692d4abd2c7e1c109e6c2513504cbbb6cadb2dd4f45504b77f8fa26581d6a7f5d18250f8289d705dc1d8bc2d46c8c8b56a3b6ec5ba60bfe37b8cfdab5e744706f4fadc4814ebcca050dce2a784d8fcc6c994d4854f977394212aaa46f915d9825b331f921ec956e6e5a679d0b0e4a4a8e3b80ba385d93016fcb835f415f4ae21fa8685c8df21ccd8c4ad0d20dc4cebad442240f415d6839c597d10f8117d059e0533017288bd86258f90a03710924b1558970333af678dce4bf782cddc68e6c849612a8cf84d7ee199579676266a383fa729b69c1bb3fcc99e42506f55293193accfea1ca602199655b13b20cea5849144a48da0d2bb7bee180f0043134c7496603a65a4863ee49c0d77b724096229b309eb6101274202e2accda05f0c0c3b034b533330c6ce3b3149bec663e2ff0ae78e2264739ed3f79bd4c06cfc0f54cd25f655cc5b857b92be8cc846f037fc398a656843de93789529a672d354ef5053ca722c71a628119cdbc89539adbc011256f4ef4013751bf94622331b18755b188e32079e0059158dbf2fca29fa918ef5096a93e27ea1f9e7b9586fb0db0e4ce103fa71927c5a30523a4a1b557ba611d5181049f87b5d3578efeb15ed62555c45c95e739dc48d5d89b1a19346eee9649720ce20be71ddf7cecec471e3790bac553678cbb848f0a2321d57063ac65bad11fd0fea13d44d12222989482291bd690760084e07b0073203ca3f72503621eac4f840c0f5af379d7e867b4ecfa8437fe6d613874d1a6b4a8fcc7d55fa56383125ac63d7755dd5d0dbaf32f63663d6630880bbbaf247949a2e65159675adb56fb19bdc7f89497bcdbe0848763d92f65fe7eeb57addae6bd332eb177fd8d192f0b2d30b76e207f8e362e211f4b1711fe311d1043bc62b95abdcd33c8d5ee2499df89c0d2c184a1d4b7b9e3427b566fea491a86661463b9256423ac16234e0e803a683e455310fd8ea0f9fa828ca96ef590587e2cfeaa3ac2af0a5a2c71b04499ae9ef859d197961cbaf681bb1b634e92f866dfa6d03024aa53e6f67db7fbfb36ddb7e1b4a42b76cda4c992933fdd7ed4c675baddb5002bcaa3c0b226902acb7d62f86bdb5d6643299be6867d96fdbdffc75fb9a724f19f8b587d956b4b79c846e0dfb2cdffc25d998cdd56399fe35bf7e90846e5d61e79c55aa6acecf3dbab027dc39d20eb955b9cf97347b8e30aebbb95ba77c2eb54a1527f6c42e480487e4c79f28a0860c410d77ce96b342183d9797c72eacdcf4da2aab8fd10cb3f7fbea150e81e14f5da137037d78402f7e0761849ed72a6bf4aa2a75304429c03ef62d60df02b744ca92eb97d4c72e0da50e108c5eaa8a1504160a61bb7d485eeae89fba62c04203e0eda6674c8c7388e34044fa56ab351d0825c4e8b3aa755befd65b5e1c41ce96357abfb3054bfd59f875cb4737d473c884518694f51656cbb2f4071f47f4e1d5e73edcc1e8b6657dc51b96bb68647d9dd6b2acafea4c22ddc15495e538ea43fdc1b774a53f77aaa30a28a594d2ea734faf023a84d0e974a702858218ba6c8f12dfa330c07a9475fa8c925616ad547644e05aa5cec49565d518e3ccb9d785510cc32686490cc3302c6298631886c11a42955583449905b99910d72a8d6adad4344d46d7340de20bc3988d0eaf0b5bb7d6420cb3f6664259a669dbb64d6bc7971046cf9ac3abf9b6c19979c41056964bd5d0b48728c8cf77fc32b05d6f189b4c27df3dddcc8c27b42324ee1cc8d309e108899b833cf06b788c31c618b5bbfc19a7749f4b61be54b992f4c481982fb0d003949a77ce2b39135ed9baeb6c6c6c6c6ca2436d03521fbb00906a3acddc1e39a7ac8935355e032fed83e1749a99e1381a9a1a35f0c6aa689de130e73457484d07d40175b1734a4353a3464d4dd779363637372854aa67e762685574deb821a35f35375046ef6cf00dbe12dab0216dd88836bcda6442379910148ee3407983729c6843dec09104ae40638ef9835be24ef5ecd41c570e1682bd317f292171dbab23f3349d6d07e6c163c29b96f15c1e8b5d3c3cd5e27158a37d45fb5e871107077338703e5b08b5ce9183f32204f403c210421041870ecfe33a211d6ec70e1e3bdbcece8eb6b3b3b3b363632313ba2184c3a3f615ddb89109898f234772dfc91ca1fc5c177de7e0703964f41c392aed33a7391c73721cd29cf5a633a11c5cce0de17a16e48a0075441dae83e66428cc9d5474284f803d4f4767c70e1e3b3f42266421beaa954a553435654c792a958226ed2bd2e1e9e87411da910989bb0708f2b83c78ec509e29a3f3c0aa7d4b3c2f13e256277ed43a3b78ecf08c20a343c8b343661d3dc6e831422b7ff59bd0dda7363f222866f3d8b163270bc22313a23c3221d72828f8bb0e631129401581e107459e11a4ec4164fbc748d4790a0001c884049009c11eefa9da5734c2087284e8b0070a85d4beb1a3fe260081262c8c6e44c6996c77aa69a414d248e98c926a0de91473ce49941373a0110906d260a7f657043f3772a31d03f6f73d938804c03be0f8dfc78813638c313a86151cb2ed1923b7a5ac01f5e855abf5b562dc75305715dd441ec444d8092184dc7dea5cdcaa28a5d4a97b2c62d239e5c3af43f2ab6ac99773da9b1e2f289d93cea9ef3c83fec420c5bf0ef94f2d44df7277cb5d4f49abdc3306ab307f5214a8be728931a4958ba4f690fc1bebc72b095b0f777c5a7754e2db7591d4aef4d07c9737d88ffe0d135809dd951ea25aeaa1f83ec3d2972caa940942861bb24c1720e1e1080e2e3e40022f5d0081cb126362161d30e388279acc3082262418244a62e0a5035998a84103369c71045a31a241135f9e30592209337e904598264884e942c90c2906121b4c0cd185164590994195320a10850c252652c2fcd0c5bc922305195e6c20081f34d1032ae6480f61c0600b285ad0031371cb912d3e948004484835f8820c19908104298d1ea028230c2c494954073598628a256a80d2039931908821a3054300010aa32f35d030530922c8a032c4132c64446024c34042811684e940131fc22c9d012684230f0021cb18198ac082e6e0c8ac02c9092ef0618b3159a0e10130a81847ca78312687107421811552fcc0831eca50d9e28b333e3066098914400105151a7ca1e18b1c03893efa000f9618d3449829611cb1028e61860e70b86203165ba8902408c3064e0091a481249070010e8a8408c1126472c032441857c0e8c10f860801164258018510f308119668a207625809410c6e9853e091a9a50b078a30438a1f68918418f40bdc12850cb4b84203661c81c313934a1a5794a0063878f24412497c8104822993c609c68ce0cb1667502fb48031c313204ce0050751ba4092c2165d6cd081862852ac50a5235420819409242d30b1850a25c48069a265a6801a01c41622e822461844d01b1c992f80687c6982e54910aabc400772043f88c00654b4c00a0e5ba2e002890c63c268228827be58c2872d907c51c20834c290c18a3368a05e60900ca2f040822bccc0e1055a403252762042074fdca0c50cb309241698e2041fd042891b82b0c2060f38e38805629630a3075e680d669214e3e3012caa4841175e84d1046a11812aaca46183204ee00507ba1c296201106980b105193a5cc981d200491454ac30da010f1ae08013740631d00004305ca0000733a2805e661648341bcc20450b30a688810697b802314a3ce921cc0d42d02d47240f31474c3027619eecf81188f8e323c6075a01e365c7773137a72c29fa7895e84379b0e3fb951c36ddc1beb82cd378043525c09f2bf952f46ef08071fc3ff635f237778d370229c6ecbbebe6ed7e6642366f6176f3a7fca5f6e96f7296bf157676cadd679928b5b38f9910f69f27d5f8a4d3d1c912f87327950cb8c6bf67416abec607c90aa3973d8ef74eff383e6234faab1be37e467f7e0c247f6ee898e1682875362db5335dbddf6c31a569ab54e9d93769ff883ab08a8d118b91d43f5ec7bf7127db7abfb9827dc79bea3f586503f9d20fff127d28fd1ca3edc41dc7cc97c2c09f4cf912944792ab9faa554b4a86061a68f0bfe63412e44646bea05de92fc85a7de7db9e31188707f8835a64f6e3ba6ac5b8ebfe33b8af8d999023f1439628367d0c6a195221f14396a44d6b75749d4201eae931e14dcb2e10166310474675fb58f153138cdb6b6fb529b0efeddefb4375fb6aefb5d785b3bd32cc6a1b5c98fe946127d3fd7ab7ec3bc3aa1635acfd479fa86947f7de7befbc990d2e2c135a68616484e52f67635fa3cf497f7557bc4df0f49346e3199a65cf68d9333371e6bf222af42b38a33fece929fb36e5df387f38f6fd4dcb593ee2a9093108adb5461b5fa6ea4e297dabb2acaa48ce105007faa81fdfc6c6042f6c19718e990026ed6cdbf3e3c76967d3b2aba4b28ab01859b08108b344f73697aac9356832cc33d955057d4929a592beeb9ee8590f923a99f0965d8b51ea4facfcf564dde34fa24f7d8933b5397fecd9137f8252330aa5d78362a27814291d8a01dad388cbf9fe010155203cf9032552f4a9a46c229bc826724acf8532f341d18b3ef2639229e22cd0d81f8dae2a897434f6855536d4017fd5dbc7feabd087c7587f75d39aceb47fb00aa55a89dcf46da5844aecf38954cece0edeb4eca6a20d49db6e94e6bb1b98053f2adf649bef724d9e791aeeb5c76ff115b072fac32793ddeae55996657fbb1aefbad310d6e81aba66dbe38f3f61968d31bc7dbf313621faf8e3a4fdf2a7fef7fb7b47bad8b24a4846f5dd49f4e2e32ff873244792187c17945c3fd951cc4cbc5d2cccb9aeeba29452eb9a3e57a67f5dd7755d9665ed58182db263557fe5b96bbe95b66103feeac4138a65f1a665106e1d1d1cdda6bf0eebecf8f6b2177677f6ad738b9d1ccfc39b96edd8186d88db9b18d9d37f75c67f382fc1f4f4b993def8b7b75b166d599f3fddb608ecb2bfa2287b28fb216b6b96bdbdaeebd22eec56edf433f1badfeb2f7bfb417263d7ea0f76b96e3fbcdf4bf06d6b6233b7aca75996595d62972e996bf9da7a5d6da30b2875826203287655a16f3f888691b5828454a7acb08e38dbb9ed9d9bde5d7f443b1bff7d7b73c5827d63ec462f76545bfbd6d3fc153931e9aa318d556ce6b4693965d921eb33df9b56e464574af5e6dc78fde7f4f70259a0ce71883afe34436aed3b86d94c04bb14814a50c9a1d276a0ee081503fcb90f108d1d7d9cd817e4cf49fe489de851fa0d903f3fe857ab8ad3afc3315be2aad6f710faf5c3080c922a92dadf0ad8dbafd25fead2f067ef5bce74fe746cacba2e4d94b3aba34d8ba436d54377a691fd4d5dde4e4eb5d65afb35887dec83e2951fab3999f6d95c4e4311100c981e860c98be060762d24b1c88e9fd6bc41bccde94ddca4bdb2d7fddf79f8e1dbf7e50bc377b98ddec7abfd7fb755defba48ce1eb2bad3385a89dc4355d71b3d9ca26558014365432b631ced6e432b6178b095c43d4497ecfa18e68e25895b49c5f2f5156696c6dfc470ccc61ec3bece8de9fa7e6928a7d4fa44a20fce1ce74ddbb7b6be045e637c35a6ab43d7f9f0671ff5634d4718c40509680fa5cecf20cb940122e5f31fe265caec21a222ae89fca1c0102475744aeac82aedf7dc00266d7a85942c530648a6c542f7a3eba856bde97b0f8aa345c5b3735b6b71b6cdc9d976d3b2ebcd222cfa0e8a78d82da59f43297efa3350fe70dc9f3ecb50d9cf3c0472d24b5099462960db6666def4309cf457f73dfdf60d98d1a687d9111666fea497c02a75502b68da3b10fca8161c087e07f2612d053564c8fed5307a1d04a2d5e8ddaff9734ef4b0d4a9aaf937ce237eecf40001459d1f55918df10808298c5fa94fe833dfbfca775da55f5c8ae042c49e1f87442e457079b267915b5d8e31613552814dbfd60af557814df557813d047fd2eb3fa81dd312de2118e052041727732b997beaa8efe5520a5ba38f125a2bfdfdf6b1d0a36f037d6af4a27dfa1df4713d7d6bb3fc18f6f13be8436eecafdc411e0c67571fa1577dfc0cea602c75aabf740779aaf9357fdcd657578da315ee64dbcddbf53fe2d88ef9176dd75f7d0a03ecfb8ab8225225e697ce96f988efcf8fe60f196387434d9dcda638e83bfc0972273b48fed4a50fe370ff00d4891f97e24ffd751b092edd80392a9f1f595d58e8357f3dbbdebb2fb72fcebe39fbeeecfbd04b80dee36a9b4d99c6efd94353c61868918d3108ea55911d2058d29e32fbaa7ddc5cfb8b3dcdfe16524a7736f6f52bac6aec87b2afb6b705c06f59c11e33219f655b5dcf8454ffed6c0f8abe594b29a5d4dddd35f6d907492dfba699fe7636fdc135fee0bfd4c24cc80ef601d285ca9a73caf8517a9c310a71c2aededddd7166c09f57e9cf4a0404747a82458716649f69ee37cbde5ffe9c2a9abfd4dea6eb6ffbfb35b9060dd6327ab5ab65d909706b7a9e4cb46e5a6541e4cf24d5964f935465ca94a95ba45160d93ef6f7d29b7d633e5950fd97fa56d8b362d8c2ae6a55f267554d19b140daf32bfbf153a832feb9422985a8953f98a4e5e200891fb69450e290b976717dd79f7cfa36cbd7d72cf74df6dadb2b13d22eedf2781dd92ef616dbaedd58f6f5c8d5b2b77f3d561fbb6c9642d1ce78e2ae1f5f72ee9c007ec88203cd2ba41894b6f555cf18eceed42184103e9c4257fe9ec89db8932ddd0996f9d39a724a6e4ba93f4b3ef6d8755ddcf5f2edcc84a4f4cafa2a3e5137777443767029824b94524cd70594caf17672e4ad79a6653ae5ae6fe5c5393b2998049403276e3bef964d6ffaed31beb2148ab6696b307ad7d34a7bc8331fee9f3fafbd30fa571577974f63956d0352749154b1d839abdcaeb1733bcb72db78b1b86fb2bfd7da6bb32cfbbe70df6cafefb7d033a1cb923f6fb8bb7c1a7386e05029e38b0a0afd59299d4bd38bd8bcdc9f385d010da3870202fee6290575fc973adc45cb6e129654df924f89e694ef50cca5c3132cf214e914f1e33b3440922d9fce4dbf4ef74ca88a2f33d1dd3152ea35fac49f918a20ec0ef4240584b7c3e3e04c20993157aa16dc450a47f33635ffe10db91f1f38ffbd0f8eff727c6efce7f9d8f0f15f6a93f01fd01f798f12508ff2d13dd41f4dbe79541ec0771967d764283e5fc3fee4018c1166cb975c0daacb10cbb6e1aedb6578c5e608cc4a972115b562dc75ff51ee141809fcd5db6558a52607e049c841de4716f2353200fe270b3d4e4efd08f9c6f7641c2f808cfa2e432936978f709fa4ee1e6f6fe4111e47ee795416001553173813a2b12e244319244779030000a1548690077a3d2cea863702576f97e10b6480058d11f8abf8d264eebb0ca3e09ee66d6cb8e7381bee761926e54cc1dfecb20178e872016cba7499009c179adbe51fdb5e81bfd9e5126ac5b8ebbedf9e974a755efc6420df651fbb264339c0d3fc7c8d03bc09f9e7ed4f36e10f90a3bc0700d2d5f0b0cb24d828e3f4f183628c31c6184f32292949fb1a244934c4f8f8a2143d2f38d9bb401e2d5227cb95ec4e64a70279b4d871e6e3cc7f914b0277f9a72607d4edb20f764597078071d1e59eec5f5023f3fc4fde8f93771e95773c8eacf35d16c0b6c947509fa46e1e6f3d5e2e43086b32843b43b8c3c3eab143271f8190c7480c465be7adbc34b9a6e66dd4bc083535b3cb01202133f1307100f149f857c2dfec3200382df876394526ea24e16feadbe51e9c14396e974718d3651e202575e37cd0c3e8e1b88142039b508f7a9ae7dea9a03ebebd910971a8f7501c0ad3649bdce51d9312feaa08b7cb3c1e6254f6c9f931972eefb071464dd6f135b2f73f39e8bbacb3ad4d969b8b3128bba703d3641b32b5cbdeded2c58bd29718268e893a34206335c1dfdc71bbac236b419745e87208d6043cb7cb395b086a72085f23e7fc4f2ec0e3e41c7f23e74765111e47d60f9409f05dceb1b90cc5000678287f88483fc238e9e8e82893f025641f06c84c7ebe8607f2a3a5c02772f44bd857a91c513942bdcd8b40f3dc5b2f13b2d129146d08211a9506f60821e7e402641873e89c6d641f99840ca30e01725cea94701712f28ff7914b781bf9df06d5657d9552b7cbb9ea80bf0a80dbe5d7b2a58b8f4c4206ca2ec665b07bc40f923f36cca872254bd4898f83237b97e879c9aed4651c1b33a2cb37503de8b95db6b19fcb507c7c7e7072cf002e0e6a7b54ced91598f3b95d46d964a75293bd4af42a19e06f76f96673198acfd7644fca5e253b8d8fa692e2fec6e6f43701f93354e213aff245208e4c2327b3e35f2f351379141fcb1f66d4a926f2285be2e003d296a7a29ea8821166694ce1a5ac17766528d80f134e889ec49e524a31aa6d76c01fc678d04257b042ca0b51ca082c44ba1c5ea864a4e3f0822c2ebc07c2d09903936de32f5982e1143938b1bfbba39414fa70337607b168f8ef5f1915c4fef5715f9f659402f0df4761ba05540bdbbfb5305b80c6850cae040474420a2c044d89492bafcca4262fa015b000da3ffe05f9037f85e853450cfa1416b629d1c7faf8275c81572ad00f79cd8b5ed575bd705d4a1ba752de77152e2d0002712a4878bbf4bd9db0c5f8180f49f71ee194c14058941fa720825dd522123dba2fe56cc72943e528c658f557d5917429ef9d4424104fa6e094c147181416bacf0b6b8555b6a29765458b69d9a11069d179a5624aa6a495722c4e2eb6edb2b0edb3b7d9b6592793c5f055ad4bd334ad5a18ce9f3fc9b4ecca6a666536bb19ceb62ccbb2ccd2d6c3fa4b6dfe24ea443762c7d732a49457bbced2d5aa1615d2487fbe67fec6dbf64b6dfb0169f64d883f2e7cd5277bfb37b20d1c8ee66d7297617d5b6766ac9a1a341cde5c309994f0df87d643ed743a65990e7aabeb8e968e8e96e2d1921b19c9997884d5ac565c6b05dab5d628d68575524a5f51ae2cde188f8ee2516675448a4947b5bad157603086611886bab1e930a3a5a4384d3e20a57af294d5ac2e549fbfddc88d6a8862845305555512f6769c28874a49a717c9d94352d7eb2e830d4af287685403e6a287f990b2f43fbc292a7fc6915ffefcd31e3b7a07218ebf6f3f3b8e6cca1e7573e2a287bab9c16167ef4a5fc6ec48b323102612c986a92a33cd859d6938af945856e997bc6a8555b6cd43f2e7e7568c16b6ac9a1f7af531a62f3d87c86da94091c4c0202c9fbe3771a320729bc0ba419c49b5a6c41f0752ab13d1a3bec5b7446f8a11d047dc4044ef6807ccd5ffb0172f4b4a5e941cc90b4e5735aa732324952b55934ac2a95143662643af8c3f85d4a0017620f3514ea267e56ac99c713a207a2c78730758e6d0e03ed4d0e2f5442fce1d60a951190b90e7caf6db4490092bd4f0823fa8e4829c3ef4ff5fce6a42f4cac0df4bcf8464cc9965e01863ec2612d6d34bb8fe8b615bab3fab8a12bc8f5c9f046fe83dbef70b277afed8855595aed14b5082f711ff24d84bf0aff9bd878c1173c1f2adafe40c5275c35bd66412d630849694f2f3f0756537d72a3a05014e10f0e747f15f70ab7a3742637f750355f94a4a5dba402db54a596b4de29bbe53aa5128e8214b13d144d1f34ff544cfdf03d890f9c5b0e5c3f0dd0f03177861cbff70f67cf9f2cadff5f5ad4f6eebb3b6f51f8e6519b176d543d6e70f495165af28f0bd37a386dcecefc38dfd25effd7bfd7529662de6ee1935c4fffa4b0f5dae3fd410b92f6d7da67fd56b7d51b9ed3f5fc2e8535541719b3b16e176d17477f23bc659ab1860df9dd481690499b3aa26c8137fa681e15bb9304cd74b88dcf5bfd63a2bc9559dc6950a70bc4c948e3ccf842b4c9ec0401bfb947b54b06f1b23d0864040de8ed6dfff07bb482995e613f80baf9eb63f99b2c72eec8d0a78e5aa441e992d5fd62c5a556cd2c2209b69ff75d8572630aa7ed1ae4bb0ab2a1c24ed6f2b2f1d117affabfaea11df56ad2c9d84eeaad2a82173573f77a551d517ed4a9aa8c636f08728eac80f6242068e91df754bd004a5c90ae2334e8d023ff6d2eaa21731fb1447c88d5e9cd782f46de5740aa13f67177db069adfe7ca3866c77ecad22387b08c782546afa714e3b5fc87ca1ca55747ab155f96bfcd7c33b495984bac936b9abc10eb05d7f5516d837edb1e7d7d05f0f0e68467fdda95613ceaec5a84bd9337f3ec6b5fde7799ef6f171601830b6d01e422bb6a6e1145ad52c4dd31e4aed09007f807e401ffe9aa601c91f1f03ea646000fde748408e84bbee3d0f2905b4c3401e1b4db0fc48136d0c7270c54a1949fb53fa7120622cd5d002fff5d6d78f5fef95b1871b7ec4aca1f9f3ba3c436168be1cf26c5af353520790528efef75fb73b1b9a69b4faad0aecbbb24c58cbaec5ae8a54c99f52dbb6ec2d8b94dbb66d407b4b6d58fef89498923f15f0b2457eb0e2aed3df7b29280668cb16ec5db4681460ff20e9ef4a385e680cf9c79f6f59b7aa1c8582fc0f921615e3c4b6d9d08a182d56651109817b88481691f38a9842d42e54a99e05384c7221b53dd79e9f702935addf58ef4f5d000442c48958fda0777d1b46ee6e79162fc1dd5d471b46d4a9ae286d1245208417e12cf01e368cac1feac3a969fa23c2b099da1ff6433a1b811afb548a2815c4faaaf5148498fe52d0339dec9fb2b7699e55d70ad999a960952953a68b3a7115020ba10f9a65fb4b27b6bf10b7f24892fa4aac4f808c53d704500d210fa5b9fa2b53c15f3e66c4dad588b52f25c3cb7677f9f43d53c13315dc359e720bf74be812eb2d4705630f3314b09dc1c03d0462ca309c9e72798994164e6ffad44e459f4ca36af4a2ebfa033b03957ddf042e34157d3ea20b81cc3c0ca6e79e9e7ee6e90ba9fe7a9aaf8710d2ba29b5374c600ceb88ecac8361060629dbc3c0bd897bd3b3c069d36f9a85199d653bef299bae7d135054a72e30f884a01c3a60cc5941c41bebadeabcbc04140ab24c19e9310cd6706e8771155777568fd07b58d1670583af84e0b437e2eed6ebbaae58aff40266072f607630da514341b1b0952923b7f5371b71abadb9bd4e6d0c2c25be5bbf7080ba14e7e1bf1dbeac2afb002a239611e99e87c059b763d1726256915f6613e93edfca34c3cc1a328dc8c801998618dba4628819620b104cb144c548ee6049054488913421bc4288a5a32962f4306f589268c0a008b7d86cbde3b0fde368e5555565966559395525bbeaa165d5b7189df5a77f16a4c26e5996cc558e87392bc3ac5b68699f910f87cb84dc5dad2bf3b72324a4da15f2f8756596f541715a9635bfaa2a2d334f4fc86642e49e9047e6af0add29f3778570853c75b31bb66ddb766ddbb6d56db3b66aa373935bdc7ceba12589515828a79c724a09a3124cacc0ee417624ac2884b0a3049a907ad47a208f9d99901f417c4ba9a1f65279d4244621843da7860a42bfb9e1a441023838314e4a679269c54208218410429f16662d66ede4ec09fd5a95fb5b1e71a2ac2aab56abaa2a286755559555ab5511e14c5ab9af555b4eab5955ab56abf20a7ea5616559b55e17d600cfbb989d93e60f0bd19cd13c2177ed866ddbd44429eba729ee13ce39a7432ef037b53cb21ea594525ed100cf23d275d67e73cf39bdf2ceb2e6acaa5a41f841b128494cbab88b5d183666f81ca574469c1c58777777d71046f85083b156021b67430821c4d9fe9002a6d40fd8e3eda43e1d5c08db2bae77c7d66cb14ce796dbdbe9e142a8a263621633995278f372204ffd4c77367794dbca9b6977c7dfdeacbdf6f7b34c639a96f9be7342c8536145afc82b433420a89431b32102a4e2a8f44e164435656648002000000043140000200c08868442c168381c1266557714800b7e8a4280661fc99328885118a48c31c6184200000000006064a6888300b99eb317ce9b79d38f19cad04833b1c8ff42131b0f32e2999964f16c2d046d4001a38a3cc705b6129d10be10723156099b1938d7682629f39bb180e7a4e2d2c460f8679ab9eb21c7e75aa9be2a3f29444e4abc12c4357b7388ca019d6f0536016a4a6b6a2df0c952d5a04727c83bca2fd4a46791d9583fc0bef459748f5aad60cbd08f630ecd1bf3e78deb71fdb9b88a488d7e56a2c31190e808912d857b89b2e5e7d88d13b607671d0055a047d0112ab65471546478f726fce304b44115771db376c2d161300de24a17c947635f8a08372eea69f7d63874235ba36f11928c8102e2d83a0b319f9605352a11ff330506663565ea2b0683e34b8480c03cc22410f2d752dffdc6a6e75f2e6f0acaa709710f641e7ac302d9b58d64e7809009f169525f499a0da11d9b2ebb1ed9804287635a3f1c7fd481be2d9f546e5f1eeed2beb031d6df1e17c534c4397884520f796cefa41de72489ac8634ded1b5de383636fb96fdb0e943039b398741ec865e9bab63873014c78a6c603fdca883ac74969aa6a9d9aa8ecc840eb18fc64f4cf1ca82469952bc2518cb80b12c5570c69b39e85843c18d4e585596eed365c90fe498579799d9993620c0be9121b5367b38a0d0c3cb5acd341f42a2ac1ce50681c68b60529cea113c53de7244aa31abf5f90f9768e2fee773a0046135783a1854059838adfb0205d481ef69461b784496b4b469c571a4a847451729075da4a38519b77ef07792f65f062481d79fcd0e6703ef3f37c09551b96d0539db6e832cb1a875d2e681078783515811b70ad77d8d1c89cf7c22937c662279d179915282dfd73d2a3b7cf2202943bbb2cb2d4b13f2c5c28ea5780ec033a514246f39863c5c889e1318a98d2dafadfde32a76da48dc84f0bcc13cb4493feb4847a22f2efba30b6cc1a396d9d191460f314011d98a13f76eeff5602776c6f393fe2e448e64b5a75daf31342dc435ad5cf831aedcc2d644f924464787187b896bf375023fc83fde3f1ac645db2f41ffbf09793fb3cfa13b42e9ab0613846b824c7fe87e11b8dc976e4e808d1f310cb5cc9e4bd099dc2dd6c06940dc3c1135fe64fd42cc3d414af1711f4c34796904ed35fbdcfa61bfc93bfea10bfce4db3894c6441230c26656b60c249f3234bae73084f2544aa2db933c51a9e337513258dfa1885f5b5bed36ffbbc3a1a7e7016dcbddc085219ad490efb794af754e34e9ad505975b89d5fac7fdd887ab1b4f8c858c755db5901678ca35840a0b4119e2298d90d5393773172fbb46fd5a961e0d688d0cec930db2eca6a999b6e071aff0beb04c9ee8c0c95f3c12e13583607e022c73030038396d0e61a889e38bd82727b4a2abf82ac1534fa47d426f855a50ec8e4e2f12a1be4f82ce814035c0d9b00139bb218e4da797e182b160f42a3f7fb8c20078fba474de297aace375ceb374e32a84ac996179336d731afd90a967f98c835f1e143de1950dd86014171af2ede66eca02362cc1ea2846a090c39b9403360a76b24283074e9a305f78815c42882e18fe63cd3603647af0bcc5c1e49ce8af8cf5e9cc29fb524a9fb6e77d5ad42601d58caeee6a8a032ce33af7fc2af9e3ff3aad83fbeec2a253ae6dd00c5a444f39b125891f9f81be0596e0ca29a5e9e95435912a4390fc43289bf5c651cc768ebcac84453f2e569ce56dca979aa0c914f794878f3a62793b09037c8f0658015a81bdbd83e4578e37efbf969f1f71b770750dbb8f8b92c23d1226c15ce474955c8a92c7717c31513180820ecd1ec0d0ab7877d414dea391fa0aa6571ddb028d2725bdbc5958877aa48b31983b30f7d51d3057e84db622004103688962f0acebc063ea55b806c152345e113a8fd096f542a52b1960f9c9f573a08aa1d73c2656778a9c46df9ef4924c5241a6f9575a5929fa0c09dce942cc689dd8712d33a3dcecd4a6294e70a0b718872d5d055c893ace9e74008cc0ed83dfb78020b32bec9ef40f9312bc424b0cd0772891755d5a5f789cfa31d18a39210624270c0857d85b2d561c35eced9e04186a19499dca5c2f7cee1b4ce2c1aa34269bb43f8872143c18010635beec9acb090f30051de30754d3f0e70bda9b70e090dbf10d02a1c7f87089890d07b41056c2e479760010c25e9d9e62725b9cbd0dce946b56b63a577e44c0c64f7206fdc814cea47594d266ab37e84946bf68585542299070162c63e4509677e0c98a657df302f302e024c32be17f36483ff47a3c53f933550398108b945cc74b75abaa3cbf72c5a99a5a29c1d57a49246667e07d462b05820099f7d848fa7df70dfb4ef5a8f4a5a3dfdeeb72041b424d620f94a2146e79f187527959348c3c09d41d7521253eb3ccdf8b1a7fd8197393eb51e5d3ac04c6f35a66a584b3a33edb06bb365e1d271761049e28a04105ba24588ee70c2501b55507d45dd9361ed1cd26738746092115dbc9e52783e22590543ef18ab2b15ba1038bb0da8329f99b7f505a6ca8c99f0774f1ed00ad4a120a05295abd4408bab8c22a04956d845c58de8fcb3e42d46657d10a96026dee86c581157c78ce6fe1af30ccc2c4209d449ca8ed025b0b2a8828a945d3b900da61609c544e00af4a0bc2fd827862831347c7983c0b6acb92d0a1a6badf0ed93b7fb35a9a54c916bac9767a5bb71088229472fef590d51dcf300154363d3e6f33a833838d8c0c5e05866571441ba315915654d5a51374998c18d2ded47066e692b6ec8aa9c6226f6b9effe8709b402ef81f9251552bc7f7d59498d17df6c8642fa5422ef28569e8909afc4484b1ee3c83149ffc643cf156f24e1662a998da5dbd83b63a15ff86e8dae5e0785f67c39c0daf205cbcbdab1ee3ad37ae23eb915083bcb36e4ab4add7f87fbd8b71946f600a6d4c15037a06bbf43c00b6813888eaf5af34d9372e6578394ba6a64ea6bef3f9acabd656a7ca6f238775e2895965412c414f7b75fc8790ab7a9f3ed5a2c8945523b866653396dcec6bced98392eedef3e3cd05bdec2b655577d1c431e6061be6cf25fa43591aed0a4db74db8fce72deeb19d48a7d12eaf49db8f5f983d23369a8fa23a3231fd638dc21f2d2fe3ec882b6a660085d3bf9810e5573212b061a03d0dd510882336cf1c57474cb50d0b29e912cf67edf09817affeba1cf1349cd885e5bebea78c52b8fabdb94173621213cd04802a45466a12d5c880f21365115fa914a46d68ecbe500aa537b818d82ba52567b1693ff9af1e5e152645a3131b42bbe5bb9eddba2dbcb67c62df50caa35210c1946c439ba983a79b2a947d5481b646ac4e25ffbdf552f94a9a67d78d9012e7c2489e89d861a81362ce9832a7315f1c17cc2154816d4c606d58538f178d0f528d3f70c47c9654b586895304d42c6d77a800d2e0734b0b9d184b89328d207056a4aa52828b35f72b626fe6e626331b166665148dcea3e85f6721e9206d083212db6773841ca4fb34a442cae70e4927d3053187a3761842005ece952c91b224f74399dc3895b2e7cc32079b63a73d256b987a4001df2606a269115481a06b8286947efe218a7940cf896e017c2c8eca100f805dbe6afb6962205fbc03ed798c61f8a42f0d423bf2145f8c70f32b3bae9e46735e195a4327cfd05712b6221138d9cf86a76bae042b4a5960e389bede0d80d5341f6c129fc9318b13308a012c77fc6ad0f0d95853e0a77b262c970e43631ba11465658b176e0e6450d70a08754bbd8b4c17396aa1f0d25ec1fa5d591a37d72fd9eca151a8d4b8801c78ac45912942d8c9e5a4b46f030f055fde15f343d7d1e6fe103e639254b342ecba69e5048ab0d605b88f7d32df24ef3869de4cb0268a0e4fc9b544e651846934d8703235f9d604e4cdfd15e6b4552e15f44265cf4229449ca9430523fd125da087ebbacfce07959863acb9a9f946c4f5b91106167cb1f4aed74661a4d46c48d5da407058b6b02e64568fe1cc45433f51a7a74615a83ca4ff58e4f070796cb4ce4c553b88a59205c1517d1c72e607e47e09a4d009ad335a5bb846d843e41ea5c4f0cb9f1c36de3dad3c67b9fc335a37e9a711222997e0d20c6e13b19f04a08718b8bb8c77da05e25088d777661c588beebaa10ebbf6e49807b008215a6aee5031f8613a160f99f6310140c9b29794b6b8ce91b8d4cff4ade7a970193267470b55853777f6fdd953d74ecff7d8a001f26bca7761041c83f35ce36697f865811ac6b5aca776b035307a75432d9a3b72a17fafe854d44aba7fd5243203faea55ad071e492b27403a554d725bcf3aaa2905dcb9d1bef3cf64685d80fce310de97b92be5bc2c3d55a51d4973fd60e5e9c3600f6cae970c2f58830511fd5ceb40ba50a0e270286e6067a65d21e7638e193afe5b3a99b59f42a9546245ae2dc99773b291b7d85fc537bdc3ccb8c9ce9825ad4f8a18c2eccf386f476d9702e623ba28083251ef712fa083ed3598b4c90182d71612d14465182f8b0fd49048a27a5e091747e47682cd8e6197fe0366e25378ff345d531e34ea3b761aa39b545cab93d7d040c2a1e254e1d9e3a68906140dc237eca1aeba020c6ab7ead9295ba8509164571b5ffb10c1fb6e3aa333140f870f647125b07c5d17a18e801c8aa3d6044ebe3718f2c41daed1568968ca540a3d78733678246244a2b841949669e0d2751322adda0e6a0ab14785bbccd4151e89dc61111695fbd254b1d5a33b146c9742f811e2e30ae5e63b370ac12a2f51aea517b17c23adfd0b20c0bf6911b6dfc23b3709d2f3a59c59f1b6dbf40920d05432013844032d413c07543425033e30ee4551583b62f611913e2e1de56c4cf1f6ed9f5aef7bfe7bbdfff3d3b25de134d3e1bf7e79df8433831ca605975b997e295c38692004043d0c0fda08e9269abd52aad7ae03256eb66053fee125cfabb04131bc56aa00ebe350d23629807ab4e9e93e5afcb42fcb72f5c0c545e2935ef17d650ddca3b1719cc9118fcfd62dfac7664cdfb0dfcf43403b69de86320102014c4fb0391134d6463c8045df4c8f118411a308a2fb4fcb97190a35d6a83c199195ee22dfa342ba317817db3e4c6595828065c4c700e9e3d37fcfc888d7ad85a30108e776347a70386a9281160f82c1faaecabd40d6c02a81b2345c122dc7644cadbc3cf8a23114216312da2e0a3a3274f0d942a73e553cef868a0dab8a4cb1795d54ad5aeea151b603f65af270c2ce2dfba6725056b667f2e2745661415e6a5a26b69037f9527bf9e5da708e688c5be8a6cece7e94ae555095ea2dad49c0f30628ff1c6edc840b1c5a4b3f857b8a573e35de19717efc83796a945825b099d376eac2cb9dcf76a4c687396ad4fe18d260db60a976ab88ef6080b33941433723fb3d94971571a61804115efae603ae575b619e005e72f04722f589b30c64777dcf4d79763fe9c06500464a26aedefd2075f0c007e64fd8b3200c634b369cd22a3dc916e7f2ee4791474a33106c0c8fca1b4d70fa81e42ff989e520362f7b0ea08bc9a0ac1f420e0ed93f06b2a99efaee2893e45452fdb27d1c8df09ae6daf40936a894bd4880d933b9648ddc14084b5a4b3c3845c1b9381b831329ef1445e1b13bf46df20888263197b88666f2c0443e08aa31ef3289e3764efa6ffd91ccfb9abb5e4ceac0a71ff0637368a71e6d315c7260f435dead76b200ee3db34d02c05a8c01a231d4833b4800748787a364938383374a19c602ebffe0e4c8d497e682708440d0c114aa444f93c83e03b2a3ddb3d387319482fc62a35bb93242726aea90882c53aebf01fe8191d93280eb6ca556aa07b20e088b78a880c24bafede68da0b3f9da7e5e91b32f19b32d839d2036f1373512b90e7d20384f1300c8d23835382d70ab7a1b49b048f96c62fce14e5caba34df71d8591580454c4931acc9e1019b6f512848ba03fac040fa15eb0fb372369828e71b5e5763dc6921b32904060ae63f7c2032d783465e2c1ce4d013c10d5c4ca996033c374527560dc0981bf81a2688abda9421d62e30c371a99871544cd46fbb822c2c444b5f10a8096e92f74d12bc56c28eec9fa581c4e97062e0de451bd807edfd68f5b234f880a90b46841b08fc2cc4924204e8eeb1015df476961d99cc607b1cb1271f2c55f1c3d22208306cf99f3bbbdf8c29cf04e3c57cb047346c9273645e07e726be99d0f7206bca2a0ba926f227573628e295b2dbb725d939932429412b5d9868c73579eb1f24e3da71b8a47baa6cff968723b0c330ec95019cf7c1268c658d2975af238653650ca84f80dc5c86969ce1fce802c5f84e63158ce087ac4053b31d11374fccdbcfc6b0a4693293693908683faf26ee7f000ba79551fdcb208adb2be718f16ea802b1845462cadc7be00c8905a4cbdf8b07f2a8b900e0b9807660e760b25fbaf890b772cca97150b3b518616ccb0d02361d86341226fc53a51787348aa1d75771a7de437cca05c38f75608b73c71f1112d81e90b457a3b61544d7a928310091871ba15ce31815084dd0e590bd1d192b1a29bc187623768576eac95178635e9ebe757c92518a368fe143d9bb6920278dc3360568a352359977ccd59112072c3a91857464c4952a885f30ad5cae12a4100173cb1600b552a63dc0883f5422e26cd4ac6bd044d1e63b1ca9c6d1471c60bc40040771e74fb11a4b23f2d4988069c9bd276e7773b437f4f69fdeefae14a5a9924e28a063d97b42fd843e81ae8c34557a988ec6a210719cf8ffdb5a9f9e918d6694e64fccdb915fcf98b62af8b40b79c6cbc2bdaaa6e4fb1c8a957c0efc09c61ba19093b07a1516a96e858fba65a05e7cf16a70f117cb6487704a865c6bf6edd606cb5eb6344be7f72a2ccfe9fae24ec93b1b3e5810146af75e0653b343b2a8897fd398041c9eb9f2f537a96e27446ce9efe98e1bd72439299cfc46d5da6bd520aecb4bbae01212b0c7672a600ea6295f4db58a5b9c363d3ff7349a0317f5986a70e9bc52f0edfadc2a0f61c0596d3c50413f50f56c4e4c51849ef403496a1f22c474d0812a73b586921840095c093351bfd29d4bdaaa840c94052670729b7b40064a28609ce26f3362c4b603d6360be79ec1b67847b69510db70378f9230d845b106f5550753ec23b87c8591766494d8fb0552a5e4a437bc62cea06ad937d72aed82a790a9d03a589ced49829fa30dab9a35e96e6ad6fa1e9f8f9f021fc7ccb921ea6ee43700092038f24a1e337dba370d90b869ff2ae9d307f92d1fb7be35ba88efb60f0bc7b32986fae188ae5c990c747092ac447850645950ff40acf7b93f4210d0090f33b9e946821a1d5c3fa50f20d2e443d8933ba42b6be7d9b8a6d3858467c05e47570f207ffe1546bb581f7fb3e790d838adca144639bbed26a8e629ba878ced081b9aca610b25a2f001626ebc0eef8823620ef356405cb6ef2dda04dcbb9968dfde6a8d82d50ae1b6d153c28bd3d4580ee532e802c3ff26f42013bad61da5c54ab3ba5a6d42ca5e482813c52473c6913d35f3e376ec87015947394d749c4b9c952ec50a00d13668b62656a7cf703b2a5ed0e628dc196e80e35b317e8d1b07edf7cc1f17f6403319c6115b3a28e01c6757dd4509495c6d60b61d83fe3e921ba351caf987b34bbdc5eddadc457f8dc06de9f2a19f8971bb7517f2459166947dcc8d516e5897956f5bb0b02d13686d46bc44459cd770a20d7e7c120ef074212e6a1b6d41d62af94aeb428f4f4659960c88ecabe4ce91cc9744b8caa596e6808e89c9264577dedc235dfc2e66b8ded6c14aac8e166e0a37ecfd4b9b83b12a52256a4322b04359070c7b87ec62bbf0153ae810ff32777f3e6fc552af48fe6da06b8ab2ec8370322dcd5bfced48497122a8462e0d97c7d401267cc8fa43df07e3c35bd7d7db9afe734bae24029ee0f27a69cc7dd5b41dd0904c73dd33898f49ce93ce0985b73cc1db77e66f112ac2db6c3cca9b49dbeb188fbf2c66ce01665839d984c87793e28c1199f2ce136b82f3af6e4de777e1e3600ee06ef1b56497220ecd0edf2ee279fc5bf24ec9dc835c4d55adbac878ad7485e442dc44776bb797ad79ff97aa0b763a72cd57f766af9ff69ebff227ef453661417b9d33c53f39f7265c8db667a99ce3c5bfb46e3df1fc0bf70b88cf2fdb59950ecd9eb1b7d0043be8a7d956d175e6116aed345f9ed2ca638f9d27bf2558aa7d8a7b840ad65f87d4d5c0481553dc9f81ba16ed72fbd7d053a7b5897a6f46d1f94e27a675be71ebd5635f1962c2a6027a97c44fc68488a1c14dc378bd1cc3d1b43757f4ae40b2c9bb5853f0a0efacb75b13c8aa0400672655c46f05012db3faeebfd2e088db1b738af8d0bf1fffeb628fc38a694b0fcb91cc544b7c32a4f60e024dc5540bbfb81024ef48f48392ad571e17da4eb69201c47cf5c37b87df77f9865eabdcb2d44c70049b4faf25d220b5eb80ec617041750e855f4e6687628bcfbb9e2d741d68b61ec99b0101206dbaac3821073092c0e1e00ddc3457048335214471d16b07da708ccd965efd74ae15c5135d172c4d36f9b1be0c47b9698abfe904614cf3a451c92d1ae2b0d5a405c8a86f2ffc54b82689b2b0bc7f06df474055da040295a87235304419a86fc42f93c77d8fa26f1913df8d8885a5ccda66f2a322958d80fea2a472f6a333c8ab66761b5e7d776527224c0185361e0ff97d92a8c89641190a0d6e2bf100e1d733154fefc33f8e0ceb84d06c8d5388c831a512508c03593a29fc360c5332222cb47d3f76395a54c96585b46014d66816d6302c31f03888f08e6fef60e99c347083d686c53e66014b2d7f3aa6a40faa7066cb0941e9fb0fc1e45105d6661cff1df877487dd0405b62e07650c704de170a2c4350780848148270b78d4ee5dbaccfb8a3239655fc7b1f97c5e4d79314af7156063ed6abd8eb567db3d7bc64e0efecb94ee6bd6a8da21c8824d6a8199b6c3d3043b27e8322ccf665126cf77e56be0f99b3e618cc69211fe20144a515b5f5aa9f992b7ffb08b36fd95e7aa3948024d7d424042529062b4fa592370b355b3a743591f9916b06aab3c03760093de1c6d4aa12e17cbded4f4ad9969d1eac0f06d09fb04e4c3868323b3d3b247a144d795a936f5a9fd5ef8e0cdce71d4b68891fe4ae046f192f3a241aaaf4ac6a8c16624679701a439ccd1c58a24fb31045d3f84914bc5aed122851dc2ec9874e6d3c0f0ce4a1a4bc05a9b532161dffb13fe440406735406507259db663d2d1fbed42a564a445eacf62a7cbebe791c0723e718177c0eba5d032e1e7a681ef1293f6f9f9f9fb9e74bbbc24eb88a70576d1a05913d5606564a3214d94198050946bb09dfb8657a872c2274d67b2b9446c74a6e9932d4f91a1ae45108d83d450ee37037e0413f360a6660bfb34fbc11f74b4cb2c08007cb5f64975889cdd83df3af1c046ca98eeee5a6d61757272902b513c50c2660b4522956a22c7ca859b1f2f19563ebcca604d34ca5a279fe6fb14338d2cebaa445b95c36a16132f750a5b38c7119fa504d877dc61f228076e56deb965cd3c1e0a119211cd4046c72f6467375d0697a549ca60617b29d60f5f5492e6d24b1dfc7659ac44e24f69f49758507994ee1cd5c3203c2ef441026c3e04a4e54c4bd04c8b18c8f294d41142f20a1372e27e07c48897ec7b87c69ad28608c46eab274141075611c9d38140c4c60f4567a4a086028eb46c3780ae886344e649a076edea083c1ea3f66a7a9bdb8e21aaeba4947bd3cbc2dde0764b28a744d622873cda3f88b65a454288633935a1addb590eda51d04548d0cfe976f2a8bab00c66f16775034b13ed9e9aa509a3ab4524c5fb58b305782cd345a4eaebd31076fb6fdace4916229def1c7cb8029da8eb939d63f4fad2000152b351edf71249f0b2d17eaa263f137a89ad82c5a94a9a388441bbf20f4f2a40694d54b500853cfb16d1982e2c94ba1e7b2e1c0365cf71c696b4d6c848b5e3240fb7a071f52a9ed934c56d2479fe0abd077eacd60bd4dbf16d451b6842411c9fdd3374184ea5215e4ad16c20da9cff2a005f3036617eeb33b50718bbccb46648ba5e2f6a16914d6f9ad2867f612b81d50cb9e5d63acc04891900a0e311ca91a9ea5d606838622777f96688a41a97c7fd095d36030ea05c5840a13ac48c9a6d45dcea7a1af0349f8981ac4b6e17c616e70d19f8a5e73454c56f498c8f2a29552c826c0066228a5008ad43bcf2395da2980ab23dcd8b49732ffbc7773004e1466c8b189040c3e7f24bcdf8ab8452df50699f1457bd4988ce941aa1e09d2cc8d30c99d8cf6ac6554f2a53f00842131021c14ba6ad314ddd5c912f12d7173401e16f04c0580875b3e2f45851d03f7296ca22ac7a4aefe6e919b5ae5c49f7c0d394b66b17f73ef2ca732b269e4c17324fad68ce4e6d4cf5339f92c9ec33a61afc76a573073b9c661845a32b661e746474c17fa574f194da3a76733f944acb529b7d0255ca7ae62d01b9b7405cf08e6d87f48277b60830e4fc70f893a247a080211ebe3f12e8e3465f4970f8a25adfd4531368b847d81a59200693ab4bf6bba2157ea81f2fa4a4aa8b672282035ff49e7511867a59b150da0cdd51e9ff4f52d4efbfd24b85086ef4994d6f0a495c1493bf36e8bc3a1a818f0cfdee61b623c248884acbfdf6c4500c074121a98e1682b0f7a1b366a72e5ba45101bbe0175e32e8b134bc5ed847435a7d06ce14023d7dcd0bbf2cb716b88404a286476b8419e888ee6beb0df853519b89ca7ff6c0366936caf064b1c5f1b2f8c09457d92ae1a8146142001bc60dfc05023f9127aba0f7a2b8dfe5e64ee53f29c31e3893a12ada442423e190911514cd040f2493563837a0aba541012651739564d2cc57b86a75661aac4a202eda38991f8e126cf74099a4222ed67d22b3e8a06baaac3b294d91379deb6fb5ec77c179b72631cd62460902ac8f34eaff4c40c199c0f6e75e68638724bded50f8aecd1183f4ff6d92455a4009857d2b41778faea65b53a570489eecf07d94b68013c3b296a59ccc39d12e420e02668a4873157e32de3645bfcd77663916e80bb8c92e8751f4a03a071f14efa11c01e42332838c8bd8d3c3aa7f10fa705f2ed537867f7101c6f82257a0b7552da28b4473ce54408706adc18fbbf7049ca5b4b511f4d1bd43438c1d6abb963db66cc378caad73431b1e2de595eda73bcaf5e2ff872fa6313c2bf673621b85ea366e315ca38520d318445b05b7c4585f40dd4beda6ff7847d50b6cc0b575d391bf8f083c291d288568bbccc0da89a001d5038900a4ca35f3978b4dfd4e064cc0945b2532c3e799ce52e36b46ee4cbd6f36b1a1a6da315d56a3b8948e87b6340333117ba62e80db55389517e5eff846210f3b77159c687b3f68bceb817181695fd23fe7470d719566c0c62e5cd69141c97c4f538d56420bda604900f48525179c7d4cd514206515d5722697c14c80674af95f37f6acffa2317ac376533e787db1009c49bb48f6acee3ac2370b2780630aa56862cec984b12d12abff05637521266f7da6ff97781e1c869f7298e320c31c30b296c064aeb5356b6d7d5ffec855bf7eea41e4bf1936b5de845e2975dd16a0dbfd44d16e8354ec76341f35ed6d7f795e4739b9eb7c8a8864d390286deedb7ebf8f97fa790713599f9890a2034044a77dbed0aa84b375589e644650632983e7a4e5d035c56ff29f2ce79181ef32bb67c888c23d85c9c360328cf5126c309aaa97f041f04bdd4c3be3efce04eba510afd55f7e9c2293300cbcf32d1d082dfbb7953b114517b3d2d16fb6f3a4b31295a96fef3606c1468a376fe36ec12cd93771112feb1a81588e040faced0ce8f08f3b3931211b40556d5e4b279831a0c0db6d3f612cb82e252c0487c6a115aa42983a06b41c2e8d05c44b5943163e80b2cfe5e70fbba3aa8633cdf268bc435cc422be60673819c46d75897712e1bf83ae2fe7c282eabc82e3a3588ff984eb3ee7afd448e789758a6f6776c4a27eb335c529d164741b4cd6a2a4c669fb64b7be6a7b83684be167ce376914fbeccbcc322577810241b0aae424b64580d86e1632be5d05d3a6b7ddecf61649b06b3ca4e44b0126fd6d1b87882acc47b88a7f95748efa7480c80c0a2f11a03d19d5e34b9d4aa29e482164df30021f1e272f7972b44aadaf7b9297af02f96a4eaf303a743829c675c4b71d777f6f0f4632914e31edef7a3226fc32af38816dd7e971f5c4a32170517f4941d766176a1014161807efc3a8a23e5e42a1d6eb8b1714835eed4de404eeca1349e3f077e09da66f80edfa9d8b82b15acc897ca200ec1d68948387bfbdc01e44b4e13a768dbb7e3102b7aaf6369f5f280a2d45e14bc35638d994c44c7c71b0006ab9097a1db7ce419150debfe9798ba93364c2dcfb0f909f71855f232360e6be38bc597790cda887e00278f5792fb53cc61773040782e728d0be49021ff68ba4b69f574b9d7d4c6184564d08850dc2788a90d14755538412278b9fc8b340a11ca64ab3edb14d95701c206ae1ee36d5d621e744d4394a99eb0002bc498d67e81faed6dc91c69f8f5089a68c8b01551edd80acf0437a7e2b6936387179b38e1fcc1d4ea94515abe0d3fded7b171ba5a72fea1fe1a1201947383f525cd41639ef787c5bcd22bff0982949d6ea7c152a990b94ba60c4fa0ea054102d1ebcae1d0da2af52b94424e229e2a69ccef43a11ce71ce7f8b19e05eeb1e03438afff407d122c93d430d8d15a5dc3c8d269fe104ffa09d0c7d6a1640ffd7aadcba9e5897d966f91efd580ee2a3757ea53955a5509b3d65bae22210e0c0bf9520f11295a53a4f573197218f5cb167b5cbc71b8ea2a3c3e3103dea21c81f6c0237150b7b75db481321fa39c116886ef957f7b328ae5f74bbddca7b6f5344fd09b1db1c69f820d503f49e6a7cb8810ea6ad87ff290511670a4738b6a0203b9eecdb116d4d80646f747c8d97ba311c0764581fdf98ac28c76210d4593d81b3d23be4a37ddbddee67e5470bacff2761551f00ef5d47aca184cbcecf6296137e0e37df8b38bb9187a6345336572a1cc34096771ae6a8698a68e5d18ae3d965cb178f347f606939b260e2acede0644bbee10189ef89abe5b0d7fca0d4020ee4dc8338d09b4d6e17ed2aa611683e6f5420f1da711cc5f5c9c86423e28253eda9832dd8db6233bd6e4e7c468f6cd7c1c03f8d53889e816f44629373553a1cdab5fdc48851c0d0b5c778784fa7e5c85a3e7e72d91815f6ae51423bb985ba596b1dd28ea32d9a9d344300bf54e75bd76bcc1d3762b57bd9ea6b90afc445764abd8fa4f3adeac6a892ccc91b7ae8b56ef599b0df8bb4e384470be7ca10f866194b55b90d12451406af1d447b14c8762f36b13e5ed937500a9463462e16ee2be628df16d1ff7855a8274010fc8e577c65a7e8cd6f2b66a4a2c848b5b6ef99ca7967ad81ebbb46ac16fffb7b235b008b1f89e20e396955e050c60086021833c3fce2d4e36b95a4d8faa574d76c6fd147a1e04702d3da269938fbc92185de559ee53dd0db0fb96eac950f01b39454317cf454fbc75ebd1d7190f5bdb394bf997386fe177aabb6f60b4d9a5b99d464f8c8b10fadd7fd029483e1562dd22da7874694d392103f92dd7ddbd4d89e804e6133495d48b0a240c97b9978362fcdb18ceeb8f39c64d4bfe4c58e6f7c7b69d73ca406102966e160743cd8be15649d6408e4aef42162eac6fffc0de44425cf5debe7de5534a3154e50e3a6a789d965242217c8b464480a4ac41050e96404913441f9b13611192773423fafdbaf6885252aa3b019bf35f325d3a5ee30295fa524e52ceb100b5df4bdc087e6ee439b2b2186581e0c7049abbd701e89fe00bda5c7c2795d30026b24a464b5e654bdb507e9c9c482a6654e759c998c8206b71f0a9627f59b0344f532792b55cb50f4f796c2b345b33940be328a27e1bccd1298d3ea569848652542a314acd926cc951e4229d1ddc4b2f728c58248f6258b153986ab68417fb008fd6d3a58e3a8d47249d5b055cac118afd30adba1a9e04107d04b5534c5cb77565ae04958ad52a709af8af0cff5ee8b715ce97c08f821627b17537d6008684f31de2a6c09c05655ed87d315a36394669f10dfb07d09f1008fd87721af0aaec924d82c8d246d20ef3f158aea12687d5c5f4d6cc1e4ecfab57b42e610cf870a9433781468f94fe50171b35da3fa1cf93e5a3ab3e8faebddfb1d566becaa841e0980581981fa32c9f8e6db4dd169d66052cb9d4925373727953a7fb8f19b14d0bbe703c93588e3ff35054398b27302b087d03fae6d92bcd29596840ce942a8edab1fcf4be58f3e3db8b52d91b243a8620390ae971908242bf7fbd5360faeb19c70baca3e96f3a8497acc08cf6df4992888edc6c67244a065169c118df4dcc6be1d44068c39e26693fb64f8df61f56c6c079e551f4ba93fe60842be5f61e015a21e43884f6caee37f962d3540c8d0bba43112d012f6d567f98d9fccdf602d123a249270ce2f59eae36b2a1f6bfcfbca9d9f7f44b13f70612366125fd13472b1a63708cd7477e3eea693d7e4eab06f3b971e2e519b2220189c406680668f9e4be10558ff819b58bc65fdc7587de86440f1623c3bc5baee3efed42207283b67a2e2f0f4f705de34ffdcff4fc5903d9aa358c3af4ded11743fbe071db7bd98bb9ce40f9d18300be2af0bc2341437e4b240728bfc42d66fea9e9ca77024c2bb671dd142047885293192ff78f48fa582763f3428cab6d6fe9770e90833b1480c914f88d0d77ed73aa3cabd85e101a9d2e8f109ef134893b4c840c15c06298c97d590831b28be4cf20710f89d3bbb012ac1459616d50b2b4c221b7f363283ddaecc9690e66a419c52fd5e84c228681300844ba7925655bf98d010006feb986361864ac1cbedc63a4139ad3a031f8181a0981e6a182dc7ab6cff79496b8aa4aaecb2b209f2ade21197413dbe7c7fb9a5eff83807657af64416300935704677b44408a6415d523fd027dcdee8a19bf969c0cebb8a776348c7bb627022a84d873bda054c5a23c1ecf3224ab2719fbb9740e6fda9626cf229d4ee323809d66c30e1fc9a3bb683c0494ef7f95fb2b060258a7218056d589be600bd8fe28a151581751915c782674e6ffb623294023b30bfe1d5f9ed3ea15c0d94fe2527148a4b1fc5458522480363b82d0aa9334a239eaebffa5eee83c0175c09fadf69180ebbda91cfb6d3c67effd3a7db74d6f53fac42699e8ed4024b1e85e3ec528ce53c772d9e483b249c64757696a3a389ab7562028a671ec60ec8329305ec4a2456d9eed294f0146aece6a59b79713c3db73ea49bcf0722ff33eb034147ffc5a175387e5032a4451d9947ed8652fc01f44e7f967de58c7c94f525712e92286d57397a9b19f63419089c836b68ae9e0004c2eda55dd4c82c4859d3ece3e6ade01a78b614ac3fa4ce12fefb52a0f552221b57a08184f021f71456ce7cb3371d6d94cb69e04f2ade483c7091360807caeff8e204a482e4181d2011410c78ebbeff126703844f5ad32e4aeca8b4eb4e3f305b8106bda8bc873773b81e7941168834604a42571596ea245852fab2bb293819247f52353bd9ab2450510f710eb540cfee3b50952eac8f0ccd3ded4089d4e2603691e8658832932946beb7c4a02d4db161cb8752858a2ef236c78f807a5cebc38b05435b6b3c5616304469a9c9fd245612bdd066308232e09a94485708497472ef2498e0e875d6707a68e35ab7f4a22633cd4b8f69f1128ffdca5c0624375e6e8003c0191e48d08f0cb659b0d08f7ab0950aa1e20c897c561a85630a3e2b18f8d37bb1f2a756ff8c927198d2d24584099fbbdaabfaac20274306087bc629269af20666dd7f3524c1bdfb8a1e49541d1df30b53459ce64e6cff92050837fd4fd93cab47c80e3b431b941267eb4cec6720534528d3628a6360f53144610fc4aed0fe1f931a7ecc9a39c2cb7ca603651d14c1c2aca9bf0c61069486d708ae2882f931f39ce619a5e70cc87e6368cf38ed97131c1145c8492ddef5676bd56a0cf659716638c7e7e8df1f1ea5047a45f8e5bb1b6045085504f13f518d410c7892e1a36909c9034fbaf63db1e0896337418c11c686d71d142bf4b445ceea2daaa91fc95fa69610f6a1950f02ac5db4582b9e472fc78f5eb896880b4a74e762342b0145927d6b5f9a6e43c6683226958b02e0fbbec4f0f3c96353da961fcfd1c39f9c368c2b0cc4797cca794037f9bc06da7db7bac34d203a9c06788649db16d1bff2077ecc6220bca84de9b2c183159f0ee2b5280ba525bfff3df986157965284d1890b3287ddbc664736a5ca7eb25e2afee50a940fb7e3a882586f6677914fa48ed865154753c7c524d63b785d374d4f53bac436b9c1760f55723be6d3f9d46604cdf32bf76160427b338587d8c0f46e06d367530f2ab4bf0b2e69b446f177bc75da7185d47f5dcf6ddee7350275e65fe0d8470bc5623a3ad6a0d0902bc21b06dd8e2a3abf905cd410de32925bc716a3d86267c4c04115a21a0d20dbaa7d3e96df04d8c7598f0e8fa15d2b742657e1b6fcd4fe14d2fc39f9aa6219ded46e4d3fd876e02e4aa7e41f148cb7181b6168123b44401b1188c7ebe7271d44ecf7c42c8b6eb529970e9557c202b4a553411367ddc656f85a06cb8214a4b20f7e934128af6dba4fcb8c23dd2a5bb15385262aee30602d13390e5f7af58d0bdb01366b3675cdde503164b9a75975b1d96addf1bf02bf2be712c259b7f3c498e77cf011663fe9e65bc98eed0a458490d2e621fe1cd87008a190b09c2f50e68e5167de078331734608aa5a3efe994d0b832370f99bf3e3a67a894707f98a2faec0dd8cd48a24d98f059a23774f793bd33bb9f79972a0059bb340a6489185a0db6c74e76dfc0e08e0621e56143b0e0f1a6c2298c1d76a3114510528f2e08d901b68d07772067170a05718fde10d2476743bc06d8e34a317ab2f4bfa927a1507e1ea18ac89de1e33d2c3f6da054d2c3ffe0291dda8851f1019d864128ced7bada9239d9f0afcd9b753e2c442eca4bd223bdcc490b42dee88b6f63edf4c94a4505bf8da54c080402746b217832c831e3d587e0256be3a82a3a9c2906f22298e1e395d5cb4131c5ba91657135918464e1e18386f3cac20591d5f9b8d1f0e89904fd163f3fcb631a1cd77bc082e6599a3f2a4f4c8e26954c7600a3c504fc05f7d167290b1774faaf86c05394b553805b7c4d70865c09230a43aafecfb1272fd4284419521b5319b03a598629a005e26c8fae3a9eeea510c3d761b0f53cfe1b4061d42431f48c474b70475b4abff4b99820163596fb38a4d8af197ba6832b606c1c939608cf1db118e3cea5670e4d1e0fb2471cdae58a626f4038a684686c68ae64a9f2bd74759f0f6f91ae0add030864421f0afc8def56f58f3131ebb02e99bd18327ceb0c3e7ca22c08296a5318ba31a0868a3e80bd4ef9ef8f5a63f2951efc71bce656b1f891b766f0adf619698aff31d5d11f02ce4e93022296c7abba33da3e83aecd24d791d24642ce0f88fb6e8c8286ffb887d22452b4fc262d5a6e915c72cd94c424cc98771194ba74587d8984f42dd0f5d2cc1a7e4b32d7ab0893de63ba3a20e54b266352b800dc2de80fbdf33598a68cb54ab9f38722c78ae0b425ea6ff031fd51e7fd0b27dab233ebe41e1b892f606ceabe49ba1cbc6edc9d2fb98f7b57e78297d3d6e086af4466bedacb4ca09776a12ec2b6949265a49bd4b6ddce37d9bb20aaf44b7e1284f9c4f5276ff8aacb3453fc2d2ba51c9a8e0c50e4fdc278ea5d839140e527de30726e8089e3c0c5c9f7d4b3887ecc5618b53da00b078a5e2bcb0c50884356eeb5594a1c595c8f74fcce6632446fab8dbd306c6d2aa59f99a01a35126919bcae6cd7a825a2cda0b3c2e542f41155747998f13e54c38f75d9e281205c4796e2ed31a08154c99653bafaf9d7502c69dbd0d3c3a740f3ddcd3b3e5f2786ce0c42f10d8e951c2d6e255c02157a94093cf4c4619b6651c44f3046cd0a2bd31ce0bd40f8cb2151dab3e13ff7acf1d2c3b82198abfbb861422461d3066cafbfe77cc489a52d3981f62a5c766ff6c2e29f3349c48c1c0ce748e2255e85d70c4161cad2c8acd3528889158ca05248b5e30d933badb774cc585c0a187a4b5424c9b15a322e0c5a6320ddd445eab8881fc7e34a7d751bf20a0a4f8fa6c05b55ac0e7eba2cfea298f5b3939383c24ead1a2c83bb5346958a5fce57c0e299b4fa4fa5601c06b96cba86185dd0bc115e215c7c7c9fc1d78d242f5cba099283619e7cf8aff8ee5f82ddcbbca6d33b869528fa4e3e598ca5d14b6251ae4ee0dfdab080d825abd6d08b91c28cc34cad010a3e6867c87c0cd14d00f2546d75e027765f88ac9e3dbde2858920ec6c6575ea103006f19955c3ac3cb5a8d41d33b8475bf17f05853d1b8c09a1b25784a66307fe7289388ab84bc438a46262f1aece39e3ca57bb1b2abf550d063334a1546812ea9d6c8a205e0e45b6ed2f6e115819a419c9578b1f2d1afe888c4b79b666937ec56d2b3144bd26adf100e41172bdaa1eedb2df12ad8006a66659574c006c344702e24b54fe09a3fd7d2a8a87ee3c55161467c80e26554455d2a0f0e4a4910c4bdecca2485707658734a6fd64483de1a901caa2984be1d108d66a9b5d04f6c2326b6cf8511ffd7a049959e3383604068a3e375f950850e356f5d2573e5f77a4ba2c04d04ea1b20eda36b88ea044f3706abbd37840b5f3787ef14094179129b54c283393fac80db3fd317a2b8f553f6459a7419d8b158589f04c5c70260255a1425be6a2de5dacd88961fd5ce8f49f278627b4831eeb3a6d735688b7a34124f935e03c60714db3ae3fcfdad8c8dc6ba4ac3cb206fbb7c4cd9310bfc0786f1b5e815b5360c49ee7e8d26f933823f05675343d7b9d53e90602b2aac9034a94c55c2e3210a6a9b6344e6d2ee78dc77e31fe38ce639f862654488cf0bb548eb32fc4be9631583c6440edc3327843cd80c96d27cca7cce4094cb60e3a701f845b02e9c91fd189dd9ea29c9e1e832d15084b59fb9bb9b213a02b70cd81c4328748b9a8893cd0bb1f845845ee25b9c1854f0166512cad266bf874687e298b8f42785c2ea1014d25e3b6565a9116941be22b8cf919327970bd956cdcd3dfd226c80e573079116ca1b223adca1264ab3962ddb96d0693942c0f33dedb2c9a662b9e3d0577c2f5b220892cf439be7c91b9fc89c270bd4f781bda9c1b97a8d5e650afa681abd0bbbd8c4c49641c0912a1a558a51243ff8a13fd7a1e7d0090ecca7eca19726b082de1cbf65a747b14a77889e1e998d769fa068f6341dfc433f85a41a086898f67007a9579ba3c29b5a899892221078faae6fcea923cf067a7d4484c1e2a412fd7ca898cb1eac519c3e00cbd8721b4ebb99dee40857a36c4db9ca470f830d13b5893788356ad0da70be61b0cee21197c6e74555fb5dfda90320a4284ab13daf28b1517552f50773421aaea469b2233b54bb2e7a78f526cfcc56c4d6040394b9ff8fdd1640d3b2bdfa797e66c22d2b29a155a2c25037ca0961dde875ee5f547602c66c609e8f6e53138cf986d80c78d0a5e8117ac743617797dd99970920daf81ab550f6e0a4f1caa0fbe1ac3f52733169a8c3a4bb8d684958a8c5029be4e821443a8f4145a04993ac4e20948642a2f35b6bd54d477f704a8ff3c7417b142b2b2e8591a6c0cec5c2de996ccb2c042d81e137e5b8c945e4cc536e678b11cd5c32be80e86d2f1ef04c897dca657ab54e4e4defdc425742c0dfef9383cb34c07b4ee36c5bdbeea8b84b0d25f58a3593b61d9a80eac846d89e50d9518ceec09ebfe11ac102547149125790c512d72ad759a36de382e7843f62758ea980317358daccb191184678632b5b5f1bac28e31ba1ac35605bdecbd9940ef1c7f252e73736057c43dc3cf543f284a4252f5fec770561443c5da8fe24e2481dca7fd0d38770cdc8299ea63a3066033626d8ad96b5393541a5b873aab6b5d53f8e911d02469ffa36e8c19df658716d0bf2500f3513811b7613eeb49488d02bb490858e2e017b17c4156be46083bb2b4e77d57cd1a716d0c249cc14ee368cc830c5698020ba66d958a59d0c1ace285f2072852158d12a856e9f31df085ba114c9a721e81447a0e2b93744e94117352b29283f8b541a1bd92f38221b339b3cefe0855819315b104d4cce7cc5881ba176991c26f5b3fb845416b30e7a3b2bdc139da18904c0161c42ee339cddaed9e88933bbf4c101925da4cad0ff333ee312e0decd57242d5f2e6655aa4b6afbe36b2ac9914e7bec2dbe0f8cc107113b5576f3c8a4ff7431110e59b26352e81c378118fbd9f70c1da569b62c64c8c1fe47da2deb45d10192a234d5089fc44406ad98596d915e87864573f2ff3f8484888c8fc5bda034b998a2b71450891b70c2257aff1a81f5ccc61aed5099702ec7b60f12985228763492c18322534ab3afb11105febb0a3f394a5b1e19540ec401127a76b16707273e39e80888231e373ec35a71c711626beb21d2bb07e413926454ad3d4cd8dc9381fff122a73fdb05d54b0b02e4aacf22321e2ff19a7e6bb9015f6293708a953d7c16b245a55e17c946cf08476fe4a0899f6dab3c14f7a6b284cea90375b9f3b7724dc781498297a398cbe274eebb29077002e863af2cba0c82e31562ac05ad5dc2c86331251ed000a1c830984e3c777df04c6dc178ad935e7683a4ad43294d01f6edb9e1797fa15c9191f88f6185992dec6ba7ff961be0c6400014790b17d50850406bcb019b0d0eb628f40a3b4366d68d7fb4d0cc4aa706bfc3c8f4030915b645af3957f1b469189de2cecb86f5236e225db0696937b7d3d56216548358530a994fa7fdf2276ecbebdcc42493b4fcd2fa5c71d9d6f166aa0b225b37e8031f67da4fc222164e2ba52deba42aba3566fe4a6105214376d70d1751f284ca131d213cd879792fd7ff1f2e9b1aa9f896b8924ef7a8e45dcd8fd97b9e92032850cbc3ff76d330dc40b45d46bb3543bf69f051c598e303b568a0e1e53a2c5542e8ca32f4336011e36a9805ea5fd446744a4e5ea5f55bb7a773899e43ea13aaedc9b53bc1a1073c3fa01dd01da8830228726146c8de594f386a4c920009602807bce027bbab820c95335269406bf82e703fac04638089b38fb446ea734d1d178fde7f1c4e940d2b52a8e68145445cc38fd55968e9fa3d8feb9b676d080750fa7b698947971088f12aad99ddcf41f1a5c93ab9ac679edfe8850c6ea425ac39c72ce2b5b814bb3adfb2f347c3e54fe9adccb4411f083338eddfde64ba2012d45a5058ff1255163dd71e4fa4ae4da46faaba14297ea9efd2e6baa41a1edb9508e3b67e3bc6e8975c0a29a2fb28fba630cad14773154d2b1abba50cbf7ea2108d8e0a8ed1593cb19c506dcb42ee260114e6bdf8821146933cf7f5e3272b13dafda40c0169a98218d85eb79672bb1b2e1cd0853262e944ebd01d21602514a05e342248d4b08e22eb43f8546b4dc430cf8a8450393ecb1a31b9d0dd8a2a61da570f94897f5beba7a462c9f5367805e043f235782e7e537c70eb4531f3d3c3f1a39be4fdaed6ead26b1ed761e539c2230655b14eebc7541b234a14370994e7d6c78af4d41ba467807ce2218c4d82fc1087a332d35d99b1176ef3696835e2e40cb4c6b7ebe60edb414cc331e8be095a3ded7e6bf81c5d0dcedda76d04c2aa7a1a0688db4fa6aa98f3c45d61210d974c0046fcb5d11904094c6700b73d1c48cc20eef16ca8dbbc0181e88d532d18ce1a2f74b5296c1c58ce32491535290fe453d41413d9449d0cc5fcaa79b88d8423569cccfbafa3f502d44b056b689911612580699422ccc95022fd7ab5919c285284bfecbff3a04e50b7614d971b542b4c4dff36a5de5de251090899c8a99b8b2ae10121dc2224a5ae9e0e84338545802c060681e0ce5893465ee1d2f38a883f85865d4b43c2a240dde6857ed476803c60dbf578d8dd1fd2f32172a9d02b3f94c95ae5f2cdf2b065452615b8d343d91a915516b930730a58147428dfa48064e4a99fe91d550bdd03812a92333e4b3a78649d1f69b484fcca9a5371c6367682e864194a4ca01d90eb79ceb9a35e34e9a58adbc528268d2e1580fc197a89b6b03086588fd187cc073898f437bbc669cb128e7b7cdfff8544cf517f2b833cbe1233a9aedc78a7b9f446d3530d1decceb6e3c1e8f5d6419cf025d289d75badd0f3e18987558f50b526cafbaf35a6d913aea65b16db180a0cde4c0ba6b463730267efd591483f515730fdd8c224950870f1049d3a0e0f1a4c4d2efc3f125466c1b318c394d0f134d919c289fb21801438fb85ee4eac5a561d20cddb2c176733a4b502370d1ea802202948f44349da347a7280f466c96c5242756b710a85d2e88f0251ef70031e3e85342a0a960badb1a693dedda6da76e02d2c0993235a9367a14e38902903663f6b3bc7033108de9c170f68418c40a3f3b9c90254f7f4372858715776d3905f7e2cc4db9dc83f2c9242f4d73e5cca68273ea8a5e9048cfb50091944f7987974b0d8d9a89fa6c8e81456c4f5e1240e889f36a26f526b753ff549a7b483c486407d719eee4855cf8e3d6da9b7c4ad92e2cac7612ef1ff41f5264711a8a797d6d424921319638aa1652a77a4c109a607182f9a0b22b2baff5bde75c20b990697cd60068bedf5463181ca2f820fba50599e12eaa09f97cea7f7768f1526c4dd39c5158167182c1fe9b82373865a29ae35e1d76956ba68ee21428da18121c268ddc9d38a2364d695a13250d139ac47f5619fb8afcf04fda0ad034cd5971e1d06038e18f431e4c07c3953f792d40e26c10cdfa523be712bbb263cf089c353df708a60d1e13ca5ad964ddc07e979b15b208471676a0bccce2238b2d5e6710a175d31eec4688a80c66056ff03fcd10fc64244551556fc2059a7c5058d4124fd39a2cb493a13309f1e49d3200f6e0436e0fca00fab147443b7fde8158bff75a24eb7c0acfb4cd047acbab1735b61a0eb6d61fd81f9e606a0cbf94a624f30649adacf1c742fafc048c25c8e1c08543b105bd7f576b6d38834673d34abd69007f76c311c4e902bf80464f914ae5acea4a4fdf20c1a67a41e6153e3c87ce422ad85c3595663c108bbac3323f791d275387bcfab21666c357078436d9a9f9ed2208320f0cb6322c32125ea1673579a3eaa76a8f0e726f9bf2c0bea7abf25aeef491fe22e674ecbce9a7831453771a1614cb67187d419a1ecbf8ffb5c108b085d29867d7e9846d4eb6653d4d99dffe46352533ea85e793fd39386e312ce8fb5cfda468903db37e52c3f3281d889acd0f2df8afcd19bc29b4d8aec5f156941432d679804700c38d9c07941fd17d5b43139f192effe95247eba61647b77caac4fa21584ef124b0bc24dbcac1adb18bbbe264dabaf339650dfd09f5c0f647915c15be98b165a8007e345274b0ae5a72883141e56722762750415c47d6f36ce0b0da24ceb7274ca6e1be5ce260322b2a698ba737bf7050fbebabf344a09f1cbdce722e7f566af567dccb030fcd51c9f667ce744f900b22ff84fbd3e87dac73e0035517eb2668a14726758cbd9710c944b9d51502442be1db150591dbe1b078e3d7dc020030b32feeb27c281600c928b3a36fb04ed2d077d4dab56e97e9c2707a14553b158d1692640ee8345c3fb2fea77d25e4a10ff8c2cf10df133e888d6e9f23f14d0aaa2bb7731cd578bc5bf541232736022dd9d0c7530b13059465556cdd0e5a4fcbf2bb92021e21ce9f4da86dc3a93f3eaca39dec791e11a7e6ca4f37594f36b1619221e90b7df84ddc509b920a610b61095788677c95f09b4867f988e7e3b10405f19ec6f21aa120c26cba98f05faa090a50d14288d5c6542fedc914db46f093dd0df6c61bdcfc5dea94ec72e647af7951e8e884701024296417074d71daf1f269bb7f6f077f76a3bd82f272c6849719cf20ef8b0bf9bbf56f7ce92ca2c17f0a217082387668bcfb0cf272312155d8a28a45d3fc9edd1e733fdfe1168a96657cce44b4f891be357f75dc98f826b4d4590925efaac589ded1edde8a25c4021928b612cbfd7c1bf46a7ac8f8813818112eee90017cd8a2d46436b6ff39e169a8869f69773f653ecc2032f57f0725745c9b986ee452a7f064284628f32599d3a88c429bd34edd4a489b5334f1f4dcfea84badfdf5311ed0cfb48d2bf4a9535b3c4a5b648e8085896783845bcd0f53bb3eee625082e383883a4d0ea9b3912c088eebde91def124e4cc76f808787156a62fd041cccd82c79c2d1ba2401661d22787125542e19655782b635b1a6f99cf2503d7f5fda5ea6e2a73b6bd5d291fd5e916418aa11fa78c2c68cb6036805224e562df0ac5ea32d3972450f5bddde9f68b7087328f846fb8b6f81b2ffc41fa3e1ff6e3e52a2ba4fc56eb8904b832a4dd51a31799e4aed56acde29f080e65f6388dafc04e0929ef018234fe9183c41b0d41694070ee547e18e77758a574b98518e1b5fc037d11a307ffc2af06c03dd84d68cafd7129c1dc855b0d829fc163d15bfa82fb13a929e3223e52b0a8b46e29e0a57618064d62d5bb301258ff190132728490fbb4aa5a45e741eead75352ad2bce7dcce531e20b9e5cd2c3390f1d2517139fff5d6b422e383ce9457571c8a1732fc160e02aa97816230adae105acac57345bb50959dc3f1635194c467068c4c05d4aee649594727181f8d8492e73862f5cd477f5e1823532ea548c301e85d372a72c968620546494e902e25d7922ba2029b7177cb8296b58e8dfcd16662e0d878c5b33c769df460822a6dc6e9a63612c2d439aee9bcb48bd332f99d1df7314a01f25e35cde0d85e89150e2039b0ad69fda9642c5095cc09f7d8ed98bd01caaac4bdbdb18e4c8deb0ad1b632198053546057cacdeee19b503e455d424c111852c65b1cd87dc726b9c5e6218ce5340d446150fd3e2317479120f978ee9bf60420033c040dc3d667e92885c6ddf33763c4dd15164c7803158194ce2194e88e94be3548225ddc1bf29625cc0eaf498d97ea822cf1dd7e31e67ba4d51a94dc327d85c4cfbf17340b8d99b73248d3c3cdc82442b338271a0fa01897b4489cc5a2defc5b8bcc00842c9cb252a60a03588e1294016b3da55fe866df3509cc94dccf0a410ce99e40afa883971bef29944c619217975196ac4a78166343d899bc0e76f87842695320178999c0ebd8a241f39fefafc583f2255973ce4c27776c36dd1bd7d78d1105686950561e9dca5d172ef96908c6ad7ec6f563fe314eead35309ccc54f983a0b06aa39f68ff588a982c3e1b23b03d4a7732a8324e2ee50ff43f98b3158373e9b470794c9b9bc1704340c05ed490fd03050e0a1f91a2d4831d4db04ae16db5b0117f6e5d81a463f52230ff8bf52e6797281089b4015a381fcdf019783c291b55965fee711f1437089a28d338722e070e8e3e71909b1196ace829e45fad7365dd8270f4d4e6a327725a1635b33b8c4a6734da08322cd7397cc6749342883c7ff136f0932286e41a5120fb12c2d1d18b23500c608bda0029e41bc0d6a038452a12d34641c28c6d42193ba12bebea464eb1fc5a00ba6df921f415ada821f2c65d87a254dda1f4a0fb3c9448e3e8fc4fa2e8f39ad8d20a91f7bb65f7c4ef62417feb761913fd68860b20978da8e4133a3ceb95e2388ad1a5bd10388a795d9ae8ed3cb979763f42b912a411cbaf22842607bd27417fb7a200e9f61133d1b4402183267f99bc0369f42580d9e90819d762e5d5b5ad0182cc1acd4f243f5fa1de20bcb921d5845667c453ad3649be0316e54d17adc98bea1bd4fc46a303c2ad18d1a81f721512be64fbadd6ae367c52d6c91f663cbc41ff79aef786ca552ba820e01280617a83059db9430f2cf0e9550dbc890f0af1309cead5e0f209b0a329b5f315a0c8df0408780d40f1c876dd6d7d973ad67818a0734da102ac34aea624e3bd6a54815e895cfe6f32a9f460d07b186c59cbe7b0ffa7b91aad31ba977733b4f2fc3bdb758fcb9c31eda20f69c346368bf1713100dad1932d0cbea5cd8ec141e68b5dd5e8c5d1205eb830dc4a78fabc0b80ab1698ce5fbc7e96abbb2a629b74db6488ff4559050c79b54da564e5305e21b10f799cf54b5e347b432ac60021ba63e53d0ada9e384dc2cac71afc203e2f180773c5a510030765143a7319a2bcd86513238227c10ab23ad11fa8f5628e27a555d548309017f61a685ba17ea7f5add012607a1e9ba3ce8f4999a6f12526628f7ae8ce0e709867e7c550d026ba9728a9d71a31cc110cc202d9dd4a61f091cb7852730fcb24b491e079198a4913b26c2b0f32deba055cbaba8b184b8f4f5a90900e8942e464ae1e00b52ac29f3e40b7704d9d074ed8dc368e08d46954a53ce64e0f3d99daeecf4af88acbfccb9a7441958494d18cd0e3f3f2bb704815b1c595937852a7a26c058665297d195f41b1cf3fa17a3e7f66213741450116e043025b6a56c1fb837c641b00cfc259b17f47b367be1fb6949582a0a0f8631f2bb1fa63f3b6f089b3fae8acf289451ec8bc2f7c832b5c29e415efe905d3aa3527b5761b4473b480e00e244d990100e3e88632491ee5d7bbdfcd69adc481a15098e42cf36694f5efe0882b005c5a41903f0f7f905296c1d3787e00282f164c2aaab966a788770263f095adfb748fc416d63043e45fe3aebf159352364de4c8e6275039b1d6a2e124280a03f5e6d26529d855f7aec10f8ce40afa49054606028dc465c9af853b3145dd61d875a0958a521a18a55f6d286e60d160b83f2cdc27b4235e650714ad9c7d00e0c347e8071a1927b880596e745354b28e82ffacfffc3a59a006e236586cbc74f1fe1d3cbece560e7ed8fd1fbf98f0313d3c1c0d9d34115e38d07e831a8f87f01b695cfa39ec8c3ca4908de6abad71b9e3b9c9c24e05358589708d413934ab1bac654ed9e05c96f3ee89b8070c022d6d61a6f7c55592e8c7565323c1bb0fc3e30781b485090d0757decc9ac2b3d09a1894aa213b74d18b588cf2f935528e8053a94f940fed7a03042a109eb702513fd9b57d467c1a27f27d9586d09c337e34fff214cd8cdc6449dc220d581ae25e2990d8e407a66026338b64a1842d57c292d466e305ecbb87580584136b28b3b8b95f573e723498e2a4b4313e0fc3754fc9b31bdbe7e1237f30aba8b6c72b66f3cd4bcbe2e01ed602c88bf20da00410fee28c37def869f5d06563cb232bd8d245f06db57deed11d1f59849f6b2ec8cb075e4b9c76c48b8ed47a1818884d306f2734aa8389c5cd28fa0dde97c13cec3c18cfad30cccb11ed9e213c79b95124ff1297b308cde9ab4ca097a0fad72e480b95d06784e572752ec1d31e0297326dad5725a8c0de32ccb4ba5d6f2af6f0e0aad26e0df52a25eb01b054c8e62e68081bb606633821f73d84c2d02df1dbbe98a22d453113448873f34e875d329e502a743acdd0e6f3f492f5874dab25d3c9a13b9237ffcaafbed1e071443c3b9eaee983586663964538018b2e12053a147584fb5fdbf5e51bea540c912f75cc332acb2884c1a3cd192b5026abe19e01724d8c9429b6450c14f4dbe59556c33d4e324345c14af86cf84c17bc26d1971752687f1f535065cdca38b7ca3a9b9ff6986b4f4335f0d1bdcaf6bba96482bb56384b727f5ea82b01ab96f86ce556012c03f06e4fac0e551a417dd43e9488869d55929df97404c29da98ac4c1d4952b0b25294a3ad89faad5438026399620ce36103497885a595b3bd4a0d526a04480dddcb233f07464ccd0b1e362a01365516deecde5ee9e28b329e2179504515b1930b6107a437a3d65a866f206708c879d88682c74b673f2f1dd99d24908c68604ffd81056a82a2b315b8abdc828a735b3e5a6e3dfe66e1917a628017a0f2856fe3002574b3c5d46d5f5b48a971a9063f1ae592d4f456f7411544c103d578b3d82be3a40c90fabead4c326b2e359ef86d07bcb7fa31ffa43b6bc96dc750aa05c4e7b3b4a4448457d806f9c8df1a5b0f53833425ae384e48bf565ebb45d119414456350dc8bf033dcc31663b2e0fdf523d8406bafa2010b2002b82823f15af74a3ad7c4c3e87fa4e03b63ba54465d5af2ee74988cbb32ee29365ff2083e21d85da37efc84024e6b51b541f8103a3f4eab92172f527d12360c74691acd3e77f1106849b51ff7f19a932900b531201875b719acc448b6b792741020ab055262581e78213a028d13c3d901123aa2c8ab098271374096ce0cd3ce108ee55f5e145c1f2a60157851359b7e5308ef576f08e3e9227233e868220ccfdf6ede96b6344f3541a141d1044791d8f08c30773a50df496cd3c4ef93e014870475091b88e36373e984e89994c5641430ba57bd7553582bc42ab21b88e179354b733c2e6ccac454b283ef2f350e02b0cd887fcb8bd9e8cdc70ccbe8024598fc03ead9a6019e866a41590211ea6a1efedbb79433e6020d83d6f690624e7ed401d6e90384a1e85d993cea9f83c199e16e462be0f383150186cb789dbe08f7999985d028b0b328708fb49bac9309f99266a1977b450abf80e5e59990f0690ebe02916cb5b2817982e40bb403afa0cba3a58f81ec7827f61484fdcf27d1169e597f2252c2188ddb984c8f4f0e8514f1fd90aff02e878401efe45b92dfb6ad4a317454776067fba0ed215a01e9238790280f33bc782272746de898dcdd85436a30814318ea9410618f35cc4877c7cad245548eee207d8225919594a024b8afba397e6d689bf4c15e87501e923e810d234799b415bc869a13fe4b1fa4deb99234ac7f561894783a90e447654df6faf1d98a9877f61a148aa1b2ba37d2624babcc86cd63497393681e70c67bcc959407ccc0600dc1f20f8770953a4f87a539206941ca30f24cb7e9d6062f8ebac08d840688818dc5ca9f98054a25af61310817e05765198eeb76e7c86487bca056f582fd1a39671f70657f1f59ba5622000e5443f6a3c442eb4315b6787451321f0e5efca5d19bdf9d0897b2e71d4c2a7095c2a13bd7591e1f55e7614d9deda69170ed7d1111f2c6216d41e8ed050bee96c7cfdac1318086c2915b955bec2821441269a2ed0cb5b114a82a416a5e61e2a3aac6a16af8a4854c242cde70c27ac553f4e939288e5e85c7a1ff319e5ad040750a69ecd917cc87418fea409359f757f46a28160fa2b457e99fdfdfa8ea7070adfac3eb5edd733c55e929ac8e364470da2ce336b8db6f55f3276d9da172c8a1f397bf59640307c2679060b7a183a6c1f4f1a5ecd19bc74c82cb7883ac9baad7a4c11cae903186766c33632bd780681f34bc6991c0233310b9e8ef70f6a946bd1186ad330b1668bebdd19cf5861fb06f4078f5fdc8df7d4893f208ed8be7a0050a5fd52f76337581ad61b9a967105e5cea8336efb52cdb3127e0d3152d4d1df52a94cf12a23076da06c5f63c9e725a5c23fdbced24fc4c8af680a56196dac59d8f2095124c0ee825b54ffc3348b5587e075a6fd6aad72b19a40aee821deb17be888fb4c0b3eedc467dc76481e01a506422bc1f2d977a98160923d3a75300934132e2184b80ba5d93b93fa5fac96db9eb4e43057bed1654203c2f3f2baf095fd335e970772e52e69418d363974d82829674ba0a3c064fa407695fcf82f1e691b6297df41d5312b8e67adbf4b2404e9b66e747cd3aa25abb9243111ee1f82fe560dbb4bbce29d9689f5f6da7e59f96dc046a7f7d85633b7210e684a767bfadc5ccd200f5649d0985229296971d5acad8fffdc2c1afe5b8627a8437e16f754dcda395d1f49ab7189988e3bd9fd26618659a50ac43b1bae60fc304e0c02ae1868cf7834bdaee9a5c7fd0cc6096eea06d17e85ec997dab35352eb77af98236451ca72018a5aab42ae11b02fe99ed0bab03222c82022e1bc0b2b0267f7572e3f8c4f6038e82642b023feafb046d7fd3c116be8fd7da587881c0ffc5ee8796613ddf4f82df91398587a629961ffd65da28963ed2eb25fe33962bb4b86b97849f434d415a21b473e6f0c9257ece9bd99ccc9cbc2c04da63a093a1cd6840617407ee5ad5a84dd4296d09ed2c52ac376e4de4303a4e3bc4aed34aa1aab836386f7a6658c3494b9f2dced9d9a96186b89c889d20a985266bb8aeed13de92a03e903cf33d54597003e49fb427172f988ce4aefff334f84f213eb76a2ca398b8c1135fa2d70f74f5e52a695f9d974c3dd69f8c473f5094dad7fc92e092cb212374182639e71cf99ad2fd4c9b97dacfe3e367ac6c5438de6169c7cd4dec5551bfb1e06be18cfa45b146b08bd3f47a6f105e54496f5301cc358aebb03d6ea5f7919a293cc41fa6c4305a75379eeee9080c2b402cfdeded5802e1c7d0e3dae484279350e1fadb6206e12b8c2be0041666ccfa3a927bc0267371cc849cacefc73b5ad89295708113ec15cf83efc0e76ee14d252ce68b2072b25b8814c2533c9b387e344dbaa3aed98fa6e886061ba3afaa42c566ea84e61d7ee0a9e1c3dc5eb74a5d818ac0356675715d48b9492ea2f7f18be5317227d7e0bd8163eb2cd7cf018379712ba3e23d47afb61c270c7c4cd25321da3669df270526dcff1a489fe1db9f313f8abf0e3dec5e7ebf5b01693499b011fa95eee93e3b471506597d4f4ff37e0d2bc9f1dcfe9b259baacc350f4d6ed4bf7b891f6d5500441bb3aa3a9fe7c8ba49faece7be1489c463664797ce8e279a4464162c22706888345828fe810774e4f6b38885810a1146e84e845bdac08a3eb5f35fb9916c73b0b1ef4e3e4f4948d3272169977558048fd795f11c6519b8b63e2d05d354d24fed29f7be3fe302cda5e24c7a52ea7d27b4f7988375d48b66d4dd0fa5da3efc27b562ac95d895ce51ffa7715566af1cd69f7336572ba4a7c5280a15f3373635aae65f5201b6b676c86dc124d85f164dc759da2d5fa4efbbbc5dd1c4f91413854a15876e3f748d2715f98068581421b25f8ae29ad78c69c4416895bdca8c46e03aca97be88e2ae480449c2640df963708162b07b6200297c07c29f051de67d817d3988db1a879ac6167ddadc78b4e61b831095e4e309a7082784d6afff3ea16ae3f35cfd7ff1288067ebfcb284b4f07c61e6feb52750c79a069a27398f4759838e6117290eb37fdce596cce00814bdf6fbdcce3af8466de3fb9da66b9d2cf9e09bc2983c0071f28ce3c67513f8ce561ac395ae40a1d7740c6545c667f94ab2301b361dd6925445b4c558d02a2b7503d6b185a5026001f7ea6fcde53a88e6f9be701b5280b5fa57a98abbc6578cbbbbfe9183ffa71d3de546698ff0a3dd8c85e19de7ec210443d5e84c0f774fb699c25ee8c20210c51c28f001037289f6d27f312f5f45fea8006b110f44c100fed60034a299e4b9b35f216d905418041a35b26140e196fd72a06c77f61cfce704164598b54f27b9959723aba4b8b2205a086141877b223f1cdbaf25f172565ff9b7cf077cad9163b10a1b68809ffa3fde074fe796546bdd39fd8138c5c8ebb503d69595cd968995113450f87beac4c6fe2b66251029a43adc74ccb5d5fe21993315e3434ed13f2d8e81ed7dd60e76fe52f347feb704f036470c720c28b965fc656808c2393c0b6a1b517977d54d17dadf34befb4fa25ea6c7cc0a12a4cc00aae7a174b443e483ea686f414049286f627a3aca5589e935fee235c3518f8f0c7c20d2319e8667dabdac051178d4a4cbfe77ae67cd2ab45aee7dd200ea90920efd30717f8bc367b01ffaa0a6bd3c0d8b8bf8550dd81ecd80ab3d1f4a248d2a527386223317471fca78cf6b619ce7e36f052882ec1dcd68b212727de8dbf39bc9c3ed0226a910bbc6ffe5097b28a229220a6382841d653707fbe69e03f6bbf280dc353d887b88a093c403629fbebf695022c720887bfa65772233ba09f782c8942a90cb1dfbd635c59390297111e4e646334a669c5e573f2d1ea120eceadc5da012b584acd9237927a702ea2f97d172d4f8fd0f900e6a1874800bed1ddfd771d644e99ee54c58c5e32b500b8787e6fde59eca28b8c114d14f834c74a1f8546fc3d3bc745ab9b423b369353d0b73a2b9c9c1ba3839b3b91a557fa7173fd8ee029698c59f0de3bfdd4fe0f70714aad4d743b6657f1ef7fe7f1e794d2b33d068a89a04d8051c858f90b14f647c5b1214e25ee8b68ebc1ca8edb6e386dd18ce9b45fae10e1111317114aebf4051acc57b53fb8812c68a8d00deb63f130f05896aaa38bbcf6f563aae9004a3eacf21874f74a4120aee8380ad2e459c28a3ada04ca520391d832e2d83e5de943b110679f3a096407dd3de0ddf802b0d98d3c1d82ddfbff4e7f3dfaf23a888e3b917ec717028395ce7372a8f05382201ba57d1fdc37126be791e2f22feb0777d4663a940561a2c457d575fa57cd5596c99abb3825d187dcc7e42cce4e7f2f644b6636cefb479f7f9012b7f0622ce5fc033c7fe846f076808a11918afb3e4355d223abb820c741f03375303b94613a16f926beb660ff832f46db3677982ac8967af136b65a8f5dad46a506485e3cf24ba69791961704161eed3413c376975940a190d2152e5b7f3cc7660bd0667adb8063a90d72da36ea8017647547bf07ae857f5b36d55e23656493ce74b4059a409a71b054a8bed97acc3966334cac1f98706240204f14b433e3d261a7b1d08a6d73309bc9fae4a3451991395ba6e565816f8ce4e752c7072d440a41fe121295398de1760865b178e10515e3cc3608139eb711df2fc9543a2287791342a4ee66ce97d4967d1b200f549fdb3a43479195541896cb4bf5aee709e8116c93d40eb0ff3b53519bdd9818bdecf69e7ce0013a4115715ea341b746a4c0260d3faedca6b0b89a3a55c7080054764d4e7147c5193e900b7400735e040c24e0f2023266b9f33d4d9d4a037b742a07ed223ff4640d512125c2484caf71e5439097ec2555377a3780e788f266d9058c33919017843aec43710e98f204fceafa42f6c1d528df1e2ce2084958060c6f078a4db164b9a4eb7c3e2ca2bb35ffdf49b0df7740f21f0c80e5ec59367c2d524524d09f32529eb4d3af8dc0f08e65b2277c3f2fabe23f3d347d8e3598a110d1c66860b2147e1e851a07270c4b052460c32cf4a3381f13e79b39ffe91962da126af94c9bff80196f0fef0a525eb4ec9f2b63b76bc2ebd3df1e4a3467fc88c12cdb62a24ff01b80eed8303564a02463c0989b52f669f70c37045823d470b8602fad1a40681e7b23effc6241df80b61be2369bf1580f260a414b5c87343b26e8c16fd510187904bf8fad3f5b1bc2ce905416e0aee0f64988f6269250882cf9dc832ef83b4cd21e035f7ed89c11d351c9a2971f5517c515e88eefa5aa76d65b90c5752550bf9bdfd0e3ba634129c3c5af487f11fcd480d82db932caf0fe43defa070a5a4a099ee2ee033054002cf5a4cfa7c97ee8eb9afddfc0dcbefe3a8f56a9ca3027669060524e79a6ba13c3eedc87cfb051346b8146fda85329ff6765a983fe848ddeae3048aa8911f322580e5a7dc36fec224d47f15a324e43fd4a091c691c28f79828c20461c14040ad48a9059305816a503f2460d49daa6f7c11696a91b2ace1fdec5ca0e4acd0c517debf1827a4a560c79d233ee01188823eb83f6e31fbf2120e805054e012fb5b9acd453c1ec3e0a9eb42c2fd3a71e37b3d6882464efbdb7dc524a99520a8b082f0924096ce3f2fc31b04de9b7ff0e70f90bc03f7adcd45c8699a91835a697edb1593aed47abe99f085a208c03472317d2f3921b3f15395a4d0f84505115284d8458b2fabc6b6a22c4922ba4be4b57eada51f1539ef76f32d5486986d5ee5372499fe3ee84d25a4da67fcf4947619af8a4e824eb2d7f01763cc4ee6b14dcf859eb8b17b232277cd1aca2254a04ab387b6444a21b185525ba0437c227c2aa91c58151d3464ebb1fb7286732a83097871899263e864512f5e3160fdd4d24953f3b69647b0bb0ca83a898c528dcf848fa870f3407c6f1c18403e3c88f5f01b6a11fff48ffd070ae8f6f3da83a0263e81f9aa5ed237299fdb88b25da48025e82bdf8f448fc4863afe0466ec59f338051a7d5712fc608551bd3f931c79d71fef5eccd39d342340c596760589504a2f8474ffb4892823dda477c2c7ef4e6523c299aeaab3577592d05553d3c444444695c807dc48f11034c13ffe32624619a780315d5488f7bf157c840cd3ec5d33f7ada477c9389bbe809e34699e44d5a4e44a41425da673dd9fb50b9381ecdcacfdeb9202de9921d4c7630e91d4baabfe60e37e8313a6c814629c76fe6523691e88d3e3f66dac7052ea55fdac1a4b27b2ef6f3b9f4b5b8757d7dc7924a5feba6ef14c228e3c31bede773c568dd7a2f97872e9699a664bf24977eff88c1ab24fbd5113733837b300693bbf7fd70778037da1c6d54fe90cc5c223272965984069fe5535aab49723ef25316f56b2b577e3de54a2b526c2f91d85bfaeda5cbcbef2aa5ce887bf2b7aea7bb0148922c27b9674e015c6c270de49efc1b3ba8d98fbe81b6e81e67d93dadc76db8bff131ff5118d5cb5fcc46476d2fb76deb71373bbfeb46b40d712eb9d0d8f60ff9b1c42a0a51f1a9cdbb17fbfd42ec42edc267c906e055fff0cbb4bb18e5d1f81ee338d3f4e7a1d806e2a061fe75d94fba8feb2fdb3ea4c52105a5683cc331fe57af9cec45469960a49561e662988d8e9a636818e39c6aa8cf3d03483ffafed6ba5652259d6a7079ee8bc0fce874aac1e5b9e781f9d1f3fdb970dbece95443e9b9e789f9d1dbc02b2641949efb20627ed45c90530da577f922257bdabe74d28ac4d8d3668b909494eabf3c4ffd17eb43457b1f97afaf591e5289b91d262ed6870a8fcb97de06ae2fcf3e80eb5dbef4fe3563b8d8afdf6342e8676fe4eb217e3d3414961196e632073d7a7818bd26f486a2853806b7213dbfce0c6e537a664e7d8c35f22fcf8d9cd47594daf5144a6bcdf8923aee8ede2c7bbea2b615292addec575df8650d5cc76dfae9477b3ad5b03df745467f03b3ff6e341eb7f93ed3b4ec6f80c0cfe93182047e0faeba2114037c1d0dcb201c753f2bee7f5640dc8395079eed39bbd9c02b1db8d91c1f007c5e610e2d1595dda3d67fba64cca5131a1fa065646ea497c43ecbaeebea2e4a4d1ea40db1c3184e5b2adbf90c2fef27949ea394de5c8a7d89d48d3a4dcbb22cf34dcbbe3b2dc3fec22c4b8f269899f9e740154a6b894f4eea4e3e7a9ed1e85fac0fcc8fdee7e549ffb3d26a77f25277727f97fa31d607e6ebfbbc7ce98847edec8e1849a24e08388126a1ee94591e785e1ee679b081573cd8007f87ec6de095cbc3581f9f9f950e1456cd66f918cb2b98b7a71d983f65d6065ec1d8d4cac57ed7e7c08924759dbe5f3ebdd4f1aa76bc2219711b6ae3cf41c85e45738a452a85d16b4af786c20a2b806c5a86d16b426f247c8c1bcbc8fc78771037373032333d6a6a328c5e53baf715db651b8625faa70ca334cba80ccc81af33037c1ef833f0bd0ca3b445c506ee132efccdaf0c5719d79ff20cd72c62422b92a71d86fea477f9d38ecb9f6ce855e94f455625fb3fab51fd6a3fd2e8e75e2fb3a4d27f7e8c310c7b86b0ca0863f04415517c981bcb9847be6919f642ae2d5bb6b461c31f39055c9ba9d248230e3448c37d1b3532a1c243df1d601bac2bf935eea8fd66bebfac0bed3c11f981757ba0173e7f462e7cc242725e14cb8000c9b0ebc7bdc1000244757343afd93df03c39af99197a4d197fdc3b8ad643d492c633d767d9c32c756fe0f82ccb328f8bd13c26bdc6dce8bb23d92fb5731996f83f6ff4fdf57af8a774a07f8fc949cdcda8f99db94392bab687a8eb2b0ba1761bb98ca2d55c9e7fa9a82a7bff1e32c398dd8b3fc81fe87dc557493f320e7c5a03d9356b3e1b172e818728855dfd7ab8d1e7c69883da3f82bf74bbaedf5ca575596cfb23a8d35205f81a1ae754524ba7bb41a51fd4b1419dc1a57db40f7f26ea217aa21d9d19dca6a18ef6e1ef704bce0d4ced238afafdf7a0dec0f3c1ee3bbb8da8c76d3ec67283c9543dc6de41c9ad37c4a836fe31b84d9b4c2c1d45d4af9a58cbb2c630da5996cdcf4e32649f39d76599f6cc651af69d61df18f69de6f33dc1e73bbf7f7e6f9bd6652719605b1ffc9da35b859164c4fe90c48e59ea4efba56e64c991be1b6354fc517c2ec6974c13396b993ac22b47fa909b3b8e2285a8332ea4d18778e10ffe23bd8928d643ac228a262e57a106d1355dae420da1abcd8d8aad52b799736a327e47db9f034f50a532cb94aa3019a6653d1cd146a4116544ac1e5f613a355373a660ed69222d510888a2101951374ac9d0b40c4208bfd4d58e348241240bf58854fffa7e97eeeb9503b9209ac6715cf771cc6d9ab669ad75d3ab75f7f5fb302f0e3ecc8bc3f51a65ce24e3dee6d20b8eefdb2503b45f920b3fd2adc298e6d53db7e95cbfd60da7c5410608c60584fa994c8f6ddd551847f56bf412aa9af6d95fdda7b19643ea6acfdca5659ed1ab65dd977d0ea98b437c987539a4e86557517825a8661442088f5c11218cdf18c42086c53859e8daaea750c5fdf526a822fd75913a18ca6d5e8d4bd858857d9c5807e328f818db4a837a59ca2b2c5169d462a4f3e1351f9e88f80cfca2664f214c72a1fde80ce0d7f06f866118b6759122b9f39b5252f4895009245ae7cba9e5f2155f984194032713b58c101a11bdce06f5bbb9fe566aaabbbb7b8ada2374990bf2566ebc1ed7ad855951112c9229698b8c7c84ddd9a0fa5ba9fe1f17b5cdf7503c0f591f640955a1d5242474bf2b0b64614ea06ab2202a42b9110b9a72b5645e7c980b6efcefcab2a36981a80883fa4d4dcb8d3f599355194ed68dbf234ac52edfc089d01d627141f108dd3ca8a87ff9d2c0f7cfcb57d608e2c6e7314585cf438a28acd13dd078e693555a1746eea018d48f85fa892a04b1b4206c412bb55fc0838aca97af44410dac9abcd48dac0285a75c58c19310b0d0a47a603e6149994058e124f017ac2c454d60c284279a587914ae7f8de222faa9824514222d2d289cb8c2440635c0019117b3ce14c040e3410aaa002209fa53646967a235c512ba5e6e4d31c6c52eb7a638632ee1964401cae2074638e2889567e00b368a5a555650831c1011456bb68c52469413aabcdc12a2410b51849c702688105b422a9861e880460f5cc084222ba2285d6e0941112a020241ce979fb4d5e553f9358b269c70a5fc198f16492a09130d88e81a0c31c485156674b9e58328acc009723425891478a1c5d009b24c2088b450e2074b10f14bb2c052ad27435c78b9f5a404330373085f620330890c942e7c53ca035888f0f324063e40620c278e085263b25670834b0bf9de9c5860190209126230c61a5b8c20011663e0e00acb77b0022e8eb82e27818b9607d0b8dae5561223b8dfa7a4179ab713ef543a33ec2469263ced7ce3369f0a08dc72bf4dc53852de7a250a625c1cb77a97ddee76e8eb4c033f36a1ea406666da1d8bb40bcb5ef38dcab95ddedc15aa5cb4bf6ee6d2c138ea9ad736394d9bdc77525cdea53341d4f59adc3431aa76dd8cb445bddc26fbeb395bddbbae87a155e15ff1da6a37ca344d7bcda52bfda8ab245bca3ea3ddd7d787783f1dae666d0ff1cacf58e8d22b73c9a28114d757dcc69d57d362db42125d8fb7ba0d13d10008d7b3d0d80b26975b5d10e072ab0b2b3709f44117f785cb2d1f44b9def6d98cc63b2e8344bd5e931886595ae5c605e1614acba8f32737445eec35312a256dc184228e0b82618df110ef11243dbc9ef934db360c8b379bd0b351f6b48cfad55c49ad8431044693fbe3728b4807d7c3b2e36661e53211164358586935717d5c6ef580755b5f64b9dcd222a8a585932bc513222b54b4b0b4a6bc6cda18350ca1fbc2e556184eee4d182c30b4c46ced3736a216308a89a2a0445554a22b626eefb8deed002304444caec96db8d583347a6006902cba3352ccffa2890b80cbad2f987891c665e172cb0b2d2ebb4d0a5b771fc52e04eec428655a7344cd6e6efa0271ef86c76fb0ed65b820482ec65650d3e5bacb7a7c3b172b3d89e3b867ae318c7bf7b8cff127759fcc2565309051b1efdf3ccfbd1e34602f93511257847d003e54faa998d83d17b82018666a1c9c69078b5aff8b97f437489f034725faa4cced4d7f4f8f7b2cc3dd998c2646cd300c4686de7284edb84d66638744cd7ec4da9e3ef6c17041280b580f0cc7eef180e168c85e875b3d381a6e68b820a4ef3b391ab2b7372f7041483fbb9fcb6e43b296723464efbd4cfb7976db60ed788897c3be2dcf65a6c1be2fb533f0509da7dcc51e062c286b815ddc90ecdb520cc37e623c37dc10eceed434e99e59f36c2b526e3c2da37e3757cec76c534a7fa326f784f808a1769895916f4fa0d27bfd8672f98bcb2d2eaab804b8182764be96795e4d0dd6a3e6eb713d0ec37e731b18c69118751bd2f76f15a62717a473903ad2b7979e392f35fd18a71f439b922aa97e8d89e962ca9db9dce24204976296ed377aca29a0ca50a737eb4edcf315261405d1ec4906ece963f6c4bd3d8d9eef0e90f41a471fa3db69f4a3cf3a24a30eb39799863ed67d29ecfb3199d49d76c6bd1bdde584c56245b1cababe64308acda069d42dd63031f9268ce2abc3c51346f1fd523a5c848069f83601aed61aa715f5b071d7a02f5fab8fd9cfbb18d0165d5c9acbad212d9752a1e532110d9e98d6b032a58563ebcea75926c72c05d2217194fcee8eb8279f0764c02b81189151b8f275a070bfed7e3c04733f1ef28e6ef176908cfe00714fbee7d5d4f4a87949d57817e769cdcdefb6c0b443e2cdecc634da0f89b7ed28fbfeaf9b1bb245f7346d76231b8d44b20f8485961c0dfdec5e4c74d3cc8ccc0ccccf984c2d34c60d696cbbb98921062031b8e4c47013b99b1e82ddccc29045fd642ec66dabca588692b80db786547025bf9becf4e830ce842ac85e3ee16adaa6a3c3c3f333f04851fb4bcfdc901dcbe39eff484ec7bdc805e9b1359765432c3704dee6283b8e4c4c83bd10ee694cf7c120e9993d86eddcfee6b9d9f76b5927432404e532d11466dc7a99688a1f5cc62244e6621b0c523037a4da9feb0f611827db8128f9dd3b5095044ec93458866118cfed1bae7342faa74c872475373bd37ddb4bf7f5f880dcbc97bac9d1d951f18ab254cc758ee55e8d769ecb9739a2cadcdeb62d320efb371df9b8a75ddb75514a63865858a8c609d13ef3ba947bf27574a0b6b4a9aede6064324ee9fd4d2c73b7d7816930f5291629a5305968a42f94d2178a75497cba6b56a963a6d9dc2ba27e48646ea5dab6e1c802d4dcce713a9c2c09e2b849c905e976db4cdc93929503ca57596e531b4afb111d90b88d3b71c20549c283ea0f01b7d97a6e30e2dbb68dbe63b8197e6ee7b8cde8e5c7e03693dbb01386b59452a68a6c6580e8ca211fb7e116104eae7c20a8dcaf9bf8fac9958fb5c7dbf2c1930bc3e5561845578b1c91fad4a9b3cbb847b226a6c9b2ecb70e89877141bacb76ae7fc605f1a75dbc3cd63b24a9cb29ba318e0fc72a258c922fdb7e321c1723ff8b49e29efcce89ea2f547207cc40cb1642b707781b0890107045a5b2986480b52a314e015a6700310d544df93e3ff0184e3061ade2fbfc302d15f83e3fec006a22c54a5a2afe3f9c90e0240aab68a9f4ff00bba7bbbbbb9bbb25d3305b33d0284263e85ebe8246153097afa041e52a216a30714a64326e702ff6304dfc1e8269e23ccd06729b18372b56b86a004f3aca57a144acb287b8f163931bb5dc6fbb3d04e3cc797ba02ad54050c580f9f282ed610c685517d1a8f8b451f1dbfbacd5a1c3e57e0de4d240d9fd98a853b8299864ab6a1c151f4866858b8a1df5e9b86dc3eed9fbd11437451d5a82151d2c97c8029b3aba74a3971df71adc5c84b809aabc99fe3143fb881fdd541fa6bc51c9ce10493656fbf9e5712fba1ced304d7c6e8afaf2a4d7a24296444a4d6a924f44462f474f6464a52881f997973d2fef43455a986abfd14bfb1d692ec8e8e50b67bf929c82c0ca932f6af6f1055a7c0d08e3909e5f875f98e8729c139e7bf0fb53504260c6174330e2076aace07f12f5a331a298c62f147d9900d195f642dcaca85ccfa50845bdfea3345c598681a88078afeb3dcb32bfae8797e501cbb21f825c9d0f7e31c62c8c9b7b1d8ca3b668cd6235fb88b3df79c8fc877b79f7d34b86a88078331ffc660c337b2f8e645cc805d9a1b708f99f7b7549ee9675356754aa79ffdcee7a80dde44b72e35f5434fefe1d30a8dcddcfedab76221dff41a02a56b447f85b33619c7e93cc9bd6e034cc30fda076c15ad498f821c0aa9fe123ee39048c98a0f6efc06afc68e0be76b5fbe8b23a308d3c03890b8d647152effc9ca2a09f73e67c966b8822212834212673ce391909ac1b4ca9c22ac210583810ac882d253cb04407a49452b2e042621221a594920821823099fc1586c604a65d6e2da16289152d084153de4c1ce932839bab73d30e4302872e5fc07ae372134b5b7ad069b55a2d1aa79cf26504f5e316141d776fb54c5e8eec3c881a39a1b5d3cbe436476f416186f0d84eafe8b4af1ea259d0dec1851f04a1402743bd03cd6196805e58e1f5c743bd1399a81f0f0545c9d181aaeb31acbbb9baa11eeaa1dee954efd01d541fdf990981cc936ec26468c883a8388b70b0019310a310810842601d6c00160d018628832068af92f04fd22ff767ff588beb115a71dd9db280b852807e35ad8ca3dcb4c5c4ee43d0428b085fe8dbbf75ed4c4878c1002ffc0a9a8fb84b957697339c5e466e1eb033840bffc3b94270e749c5d2156239c2de11a8a233720eaa2a1ed94280050b96200e64a1290e409287c1e9bb3c2149bbcb091c1a01bd2f6aa47fb4b310ee13d158a224d1f2b11653d5125f9878423e8d523fd6f24510be0c909a9afbb1961b8ce4403a618cd02e1731b61e333230148608cce5089cc9d832f68b0e3e2ebaf0a111f814c6ce2463cbd84d90b15fa8162ddc6be92088824f9b35a596244ed4efdf29a5f0af7f9d2450e55df65dac549ac4b3e2a5303d519bd0a2458b162d579a802549171742f8b109beac8d10cd43a935fd27a07f6054a856415a523fd306eaaa53b7673810b921f4d239a590decd795d7f79b2ebe109cd34a99fc908f5335d77db6148d4bf9f77eb90c4620713a66a6194f34a82d218e5bc28966914ab584629866159a66d1bc78d46a49ac154227db58d1bf568b4916238eeb71189546ba9e4e2f2f2020313c3059111a2a670828a0387c9044d2693a9965c60626e4478c36fdce81ba5928bcbcb0b0c4ccc8d1b26538e6b4aea5293ea1b3f986e4c381c070c4c4ccc8d1b3870984c3972e8d0b163c78d1c384c394c39749cfa9443c74966470a9d5d6106002cb4e0a15ce0d1a3c7d643cbb01e3d7a6c3aea0623733ac9ec484185ffaeb3768515666600c0020b2db4e07928940b2ef020f1e0c163c483070f1e3c78c8ec4861c78e1454f8ef3a0bbdad9d2315989dd9f9bfeb989979054e86a8020b2d78330480112c1851ddb6d082e7a1502ef0e841e303a3970f1f53fa88d07db40f1f3e5868c1f35028175c7081078f1eb2478f165af03c940b3c7ad0a0e49cd2615c30419927d5ad0b1c91be3d54b0525fa83406a18931c2b8bd20534475eb23150001c0d030d0d0d0f464a1a57604d0c44e53ea2f4e48b576f0f3217c1d05b043085d4c103d14fbb8ac89c7b46cda0183eaf282faf1d0ced0d0d05016cda1472882ee7403bc4cd47ccf347acdb75150cc8d989f4153b02a49146c23ffc6cbcf1903f3da283ee98b8c1e3e09be125237e1dec9dfad40d4dcf120889a2e7467cfefc4a8cdf1475f04fe8b55427af823ab840a0fc9d257c2308524ea07d52fbd074155a985588539d1f532ae1a9182b05041198c93cd3bdfb340d5280860f0c0abf028a8b7c0b55c9aa983e3a70e5425390255386c433171769b1ed3311c754d0451f349dd7cd9589ce5ded472a73371d4f4a02677ce6c0605050505ddb933fa2015044d79a9228a4934499fe32f5d5771b1429a329af34b9dd441fd3cc8a3b8cd97bae236e1361f5fa9122528ca6a742364481097c6c3863e83e80d44314ae97f24034c21dcdda1b7684d027ff83b3d146015cc04d826fe02d440b1d70fb91a78355f8b3fa80b80377e0ff6a633b88ce8232957bcaccfcfea212a7632399dcc41a5514606be3ff48f1f87a40fe66b0f5f4a7dcd1d0c5631f7847f869771e79c139226e9739c3422b19063c1e17090a036fc18db4ec76243afea9b60ec72523b5055faf93f02aa71554f9973d6e0ab6a5b0b44cdce594f1c08aabcca8c325f9b92cd06a276e55560155877ea8477be5b619c22a88a6fe241c5825671a7c6927d24a53404898afcacba055156b8379f347fd4cd975bd4cfabdc6e5d2b6ef3e1b8f3e7d756dcf9f3bd8a3fb7c324cec7c13393bad684c65544612da6ba4d216610f793b935f08a096ac70b2adff95feac6eb239f986f7c24442e50a2b8aa003db46125b2da38c2fdda89e6644b116df3c16c3d4666701b6825063789fbc9780aaa4ca6f89aa9b6a03244c123d0623fffea4e6e79307bf213cff51462d863cf2b2a4fa8ee04edce1188e215c686ecc4a81db12098213333d727b5bb9b075a4e0c53d2bf28d54107a8468d393ab80d5f2918041c85d99c2c4e90a81bbdd839295e161887e03e10830b4c8c1f18218740c500aa720835a057d890c17db97c850d297774f90a1b4a18418b9bec4c321d17449d7115fd7adcf8f165fe8377dac89e64f624c3bb83cf9d94ba0d845235339e4926422168d7f5542c503108e96bbfbd4eab590db400d6d095fa555335fdbbfdbc5a83c6f0bb9b7b98377b0cc3be31cf7e0713f54b5d8ca35c71ef9cf5f961c57d8e675d0f06395035ceea78a0726bda689d00d1d9d318994da5eb73520b600da5628c99fde0cbd3c8fa6ccdd1906d4fe9e8475d6454fc4c067a3f9f9b3d5b0fc69a5e4a0b0002e6e3a108bbcc651513ae818529a7f90f4fcb8fefe3a7d89dda9e6a80ef5f24beb44aac1225fed002271afa29e9a1dd81a8f927cdbb93664f0c900f5fd3ac0f0bfe0ff195a4a43d69f37f569b3d6996071ef9dbfc9fd5cf8acad0cb27fd977a5e916c0e0e2719fae989483ffdb6bc92160d2a27227de9f7a5f644447bfad4e2405fb35709159ef8a45772d2de2a89f674fd4923d9d365315b44c6f7374285f6c045d7536b011f08e143fbc3e8e147ab0344cd6738e1977d0ff05e492ef673aa21f28c3ebeb4cd8a3edba44ada096cdb411035e7d7a021834ef4e5a9066a79e49f78e25fb6ab448e75bf168aa27e9095e33a6a8450b975f97e70680a54f52a0668c40e75997250bfd8795abc15523cb1c216bb16b819cc6cb16301005bec00a095a07e94852d7633a4245ad862b74266a57e3176b6f542282b958b6e527f1b680713ea4763a782f6248a4381414d1cd58437c1638bdd8e2b3b29177d618b9d8c1604510d3482fa511f5bec4edd35907b4fdc6b92da62a7e3ceae9d74fdc45103a0976d2088f214aeb4295cc805811c6f95d413d032cd4308614321681042c834d43d18a78410324fe9ef90f414fecd5950598a00ca08a10cf54233cac0fae95fe1cd1ea39cd7d636878e085c18c39ecc21810bbf3df93206870bbf2b506fec16a31c07cc3108eb978fd3598860ea7672351216da404848a1ad0d40b91f674983d7b8bddd0b060927eef5f17a0ac4bd9c105da6a93a228b4d76a3e988a10bb3d48f7d84509531704be2800563a8e1a40652ca78c14a422c57c600ca957fd9082f74d03ae204373ebd62239ab1e2c65cf9b4827165cb881604910f85145bdbcc98429314dcf8728bfad53bd345577e943b50a144171f8001129240c51cc2054f5c90c78d50dc184d26d642064a6c37625f98da848171c42cc2093542965611683c2122cb101ae04887208a39d064060d40d1c0086628424803538c98818829401b116f6ad305e594725e39c38b39e7dc1202477114da84a3e496275cba90e58c222967248104356bc2fd6a3555982b50d0407d31a668c1779b1391f9e3c49dcf949a482e9f753a5c10051fcb16edf7e180848beecbe700affc972e076c2bba97d5b1a4c2fbc5e81c14a8327dcc8dff2a0e1badd501deecbf1b1c94dea875c441b9f061daa81f5774e18f9ec3c238d9c3e7cc701b9787cf157164b88d6ba5aebe465f7244b08ff2230dd84986f8d8c7c7e1e5a37cb12719220ef24b2f5febad748a5648e9e5cba7f44b5db51f0feea8e3a12f673fbad9af9ab6a2cb5a6f10420cc67252380a72562e8c10890a3f76f386b6606e6ae5b2501ac08c4a9d97e7cb37995e4e8c820f63fc669c1e1a4aa9fe1fe58860d76d756bea72300d7cd9e948d598dca66e9c05f5fbd44d0e8cd2f6d0d9f5cf201bb186eec052fd53eeeeee5f5cf525821604868a6a6aa3eae0bfa30815a3d79411fa476b819fab83ef284265efafd4abc0a1bf01f601ff45d32e3f64557740882ea264546a5ffe6b630cbb54aa948c6114fc43328e0a17c20ba1055282cbead800023f16b2018a0f3fe38244185a2be300c13832e3867037da8c4a85973929d9cbeb7229d910fa57f7f98df2e3d55bb48b034c03bfb92119957a5d08c4ae99465a23eec5ef537c5e65ef2ca86e84280650b2930cf179e2cf3dfd4cc3256a0ee318b98171e2c36f00ff507259f500154ca6528961b43e4c036b9ca480b88d3b61038cbae3dfe3957d270b1620687606b59f4f1e1f5a254a564aa215b2e255bf9351bb655ba8e3a2b2ad1d79a87340c6500ef291c02d5baeb4523cb2582b0821dcb265e55bb6a8608d1ca4c86732ae14fe359aebe118e0459ac96032c84083e4af792785452507ffa692833fbb3d11e9ebfdec3fdd16883aa51b5f23c9e719165c22e5b4532d7d7ada81d60451713eb5a79db9a24fbf57d4e12ba1d683a808df2f7b0351d1e1f717f16739e40eab10c10c6a53aa5258f2990196158b48cb8af6546415fbfbfbe10f90f084751b0a1ad30cd1a8db44d88d80160eb2dc1c97afb0c1ba4360528426975b4320e372d1e5161945b74504a13b4b77be469acf3ebda2fed12dad19a36234da229ee7d8bb5dd2abeca36522c40156d803f52a7b13f6d967ba41035a1d889ad9d78c7105d9a11f29fc48bf5f89126a7b6ac66022fafe45a875ab258916fad7f350eb4385c7bfffb2ed478022d03750901decb52c5a9f5e65dc8e0645a3cfd9688b5809a201f58abe6619a278a0f56122c40156f4817a757db44b7a757d0d1995fef5f1a137478fa31ddabbd5a27fd9d30eed55967daf32eb43c5065e3151424549665b6360581a0b44c167ff22bd62615da06e50e7e5161144440c0115911842689d9999bd2111124a184550462a0b8d67be54b4ff10de80c6348a20d283a296106d04418408c804d41aa24882c0d426178470c6d0d51982e8679ec0c48d975b432cb9dfa7588fb385c6333836f84acbae8ecbb0e6d0f12e36bbbd020f6a578710be91d9f5ecb8c745468ada4a670f59da9caf75bde209ffe32e43adf3558a21b7a062d6870a8ff6d9fb68f2a177d2c8e415e43c2baa7dbfd8d14752b677ae48af36ebf3c34ab3b36b2b3d05a2e0639d110aa9b568d4af592c0a37eb2c6d0438b6ff622ebffc41ff9b5c4b9bbd69cde2308dffe7c275fe991856997ef20fb9b10d86b33d7f896db4cc740056298027c09effd55120870ab00f7f78861ad79f70dbfb180ad75f07721bd75b88eb708b3567d4ecd93d6e48f6dab5c50ede03f00eaeeb34ca3921432e4ec80e8d456e988d8614512087f6e17f791a5a9e70fd75988debef5bb2e06b00ce0895c2fdeca400d115f7b2930254571ceb466b290bea47a9e6970d349ee12e8fa3e27677e20a4854f8adc58f85e4e7b88c3d76c73d2e6af721349ef99ca734b3ec295da59b7094f7138ef215a8807d785b7fbe5c109bebdbe569e116f5f3a12952aef721efc26da277e143dd41f01f541e5a87fee14a149181eebef19477468eb837c56de077fcfe243a40d5cc525d4d5a0a520a1da6aab8d7c409fecf8516f62a767de7f714f7fa79056d80ab695700aa2d5d8ad1ec2b01b48a95c8821b072251e5f54fa42083fab5909523f0fd752000a7e00d3318eef90d91bed31eb9611a2f2280d70057974d419415586ab75a0868470e2a7f771087304608234c615829478e48c1a85f4f99d21e1dbe13582ea0ae7b8eeb5fe93a659c78994bdcd59c91011e3a08104ce3ef4c7383f3fd9b4c371815f5bbbb3bfe8fec2b0dcd538c43baf33dc639ed29cae799ab537c25d7f34b5b43ff7c1e2554a2e5e1bf5e49ffbc94cc1d58d47e36991c06acb5e646a0ea9a454a8c1cb9809309b08a7610377e43a14d8b2660e4889306e2099742f1208a7d84d11c88da99445ad48f8b8cb8cd478f40c06dba280235bfe61bc7385ff64def97fd67d967178bf1bd0dc6a4c5987dcc3629a1d45ed3ec69085fcdd69c51a9f63f37a319ed7a80f7b25d8415282cb8b204145ba4b18a9e8a25d0e0ddfa87774b54e9efb90725848e43fc1901bca07aeec1a4b5a834ae9574410c15d1000000004314000020100a86c421b1602c1e95cbc2de0114000a8ba0447e529849a32008529842c610600c2080803100032033325b05e52e2b6ac05478bf273b1cc876a547901d81ba146452eef7bc0a948c6ed2dea62f4c9784d52eed030910924114fa59e0de1db03f7be46813a14b0483308478a33da0abdd88f57483bd0929767d894aa9d6a74997a1d1efdf20adb8322ff4b9f2db32957ea26f2727881446ec4a0366981f409e52a16cba27c834a97f45c2e8d2266ddfe35961756aafff73427e714d0be498bc34156c2712b34a8c19376272f61ccbb04846d1069abe353cffe41950d37bd97b971f906e73df893077e4af3278a08a15d69543ee8a40d25557e39c1447ae6f27d6fa8623ded381c5db8e2645ed5362123465a0da19a66d735cd0901b33250d21d3a40c601e869e3a9b7e400274800cf624a71aa248b5af2ddda3104e8262d332a7d4534f1d695510b5435dfecd623eec499ca60a19a64b673854e7e8b8351a8c1ecb49f3ec57b9cfcf6218b3142dc652067ee3018ee3f99e4bef8a6bd3149fd698085d9b26191563177429c4204ba735ae485996d66c534f02d8bea5a5f99ebf4df263bed1a7ea3db6ddcb779e5035886f68f9ad01e7e6a411591c11a285e9d386e9b95fe3849b3b131296689b60c7047fd6af67300e35afd4afdc8b1af0cc57d479aaa5bcc3b0495a6ebb1a4dee9fbba915a5e6b9a7b7a83e7ca942115f6a4c7636452c6cce9b2d3121d0873852869c1acea97138132297234ad9f71a7036ed93dce4a3d06876107bdddea8a2497b7a103032e60360b535ed44e2f434a3f286c8db3040a7724415e7855431fd9d2550691537de0b6b9ac00cf6060fe1dd1914837aff900d09e14cbf9b34ce17ad80f44f4cc1c7bfecd97eb4ccf1e734863287b6749e0a597b3217d375eea163f35075453223b0ad0463ef194305c5e3ae9d5d9bfb431a0b34fc277c567413af7ad0516f20f7526b81b41c14f0285746e9244f91818bdf417f1fd299aaa46dce45ec861de8b6ecc22c1f9bb604676a3429910131b10bb7fb15b3b27f806bcdd4dc9918ab7e5c3bcc653d35625686ca8a00dae6407f0e3abf8444079703b0dc69b0aebec2138ed0e46f218f23ed8fe9337ccc1d3174d3f22d25120b373ebfb55aaa7927d9e457a984be67937bd4400b158c16a7582a3285187737220644d1674744542e2491a3f12e3e2c208b0c3e6a31cdfdb8db67d6d421b0db3c3561a3deaa9b3300382a6375739025324c9f99e14007fa8255f8a775a6cd7b7ba1ed1430fd3e025ffae9914960d95dc21732ccbe6af91a7d969d7422103823d92b876a54989366723d29155b1b652a4d0713868417e99da2230a84b62b9ffa95df646bf920c6f5a5a209df264518f62e82fd04b877ec21c699d05a8fedd529a529a45777e211905de71d67dad532308ec29c450f9704cfef7205cc1d5b01fabdb8235f93c6b229c1b0ecd0316a9a37c2b468962deb93a00266bd779b973fb622e9455b014f10e126fde906222f62ed50787f916944f8b3c326ebb16f97c21ef00c3a881b683c196137cd1dd2181a9b61d00cade4d67256ab6c36811520dc8e8f598eac6b96bfa24807d0a526715456ad9dd5392e45d278fa52db44729ca53d27f8c746fdd628e7680b1ac639c0b4479ea1832dddffe9310f7cafcde26b1ce83ac0aba9fefde4f20bdd4a697e5ad76b4658292129e9aa3cf3a3c5e64808cd35d65d1ff1831043dfbf4e30da8f62e853e320e2ebaf6b4074bdadb306c5de1c6450baf472f59d1f579acf9cb60c940737e52f9529d9d54980e634f15b3732c56dc00204014a399d294e26a748e514f939650c25c9e4833f71bd3294c0602053a530d90abefd540f85f5e707211f476e865f51315c05ff6706376ac6b493cfbca1cd613bb8704c1c043003fc100f0b0c98d6ebde89a300ac9ff3cb4d9e179da4e307e3564725bfa5470c94d164049b5828ff385689b94f3f892c0f8a4de70594968634ea62f95b603392e10f934458131cc2829fb71b91d5ab7cc5ba8fdb090bcd6462d6d6b7112c209022d00c703b61ca3f70769d25dd7ec93c91aa1a3aa08b1fc2618dcf4bfcc7614dd6968549b6da939444e589d17260dca0d9defb984bd573771752bbdcbdeb245fa129d25aabf4e755a6d2ffe4a6070ead45120df5eb2ecee3b1116a37fd61d0bde355392efaed4f917cc8029f80aca4a44bab6f04824e7de31648a6a7f1bf33665d0fc8547a8d0cd6d5ce61e82974da717122f615cef89cda9cd04100a3f4fa2fc88e870b2d10d7a4ae535e15adaf48b6941a754789547fa6a793c16fcf49acc54866c396dd637c756f06d458caaf97b08192b89a957564ace6fff982c7a17a2e31c0e4393eaa2db87b007be308595948fcc286d4990731ef073d9cb7a3785dc08ee79f883b352a2f98d000978449cf4f78fd59966e09315f00af3fc7f9b408bbfd74fc03ae091c8e1ac83859f9efa1d1f78f1e10db9accba489de6a94231165a627439d5e81455eb98cfd404f86fe605e103c650133029087cbd2aef653dce4d82f41264787f5bc94d02006231e10dfb31802e9d52fb3d96277c0add8219480b9ec5f6b7a21d674f51b46d88d0354a802d758d6d430bdc4d9050da6b49b7f4b30ac0b552c13985651d3339aa0c309281050b4ac8cfea394236cc0da609e7e904b2159195e69959fe560b265d7682d212ed3065409136028c1381a0a6296e0b1c7c812f55d46b07b0fea6a3c346c3c451c03b24b260f8fef63aa97325c0246fd5ef1209533ef63d32cfcb5606d063cbed33632929786041d91eb23c1b6ce4f8538f013c0cd045ac3a21e793ff965ec171bd0a0537e42b9642b34c221238dac2a9bb72073ef45cf5f82a757abd14608ea9922b491ad78ba3bb9fc7405c6077e5c40193d65d9d5ff7e750ee19d2e361655c4e5dcdc4e5f09357e400891556e5ecb61c11823acb329a7ae7e864e5c6c8c23d75f74b9b5ab47844fd31d2aa0307b2dbee95a1d4c53cd2df7de0159c3283ed866c9232018ee686577dd0adadac3724742074a9a5f37a41fab171400a989cfd0c878270414f62927f78d20875e2028ce5acd0a66db899a666ba5aa361de96b9da3f26c5baa4cecb276a4e5b79978f005b3c25b44f3cb2edaca9b53fb08fc9e1084eab2d037ceca42956fec090a18a154383bed00d6a7d03ccde11317107e09c2351e99af5eea103af304365ec0f94b65a30f7d228c5bf72a36afd4c24c1efc99419f3a0c0fe5db33dd2358f60f78a87c52402324e1dac9722d94b5dc62f7543d5a09e03dc74cb3ddabe0228c297a720f54a740a663202a68d0e04d1367602598a391c92ff047c8d34f4446f95dc3bb60e0e5b86a49ce615ff5df72bb576a04f11d13b706aac6f23f4c81e540d31e5c0cbed861ed42e1b2a948a2111fe46a8535d1f168f9de235ca0c1807d8cc2dd870b0705520a0fc511a2fe5d442972e5d88a1ff98e7965ac31ca22d3ad1ab59b99b12703389017d6c1ccfe2df1abfa3da2c94e9e106b9bd9b64d112e9a703b389c8b3c9170ffd7ba022d5255ba58b040b37b066a79a934e97b8c14e99cc02c64d5de8051d715edc14114f4821039c4a7103750fab7d994471a32b9934018ed0c73b1637cbdbfa5ac8276e26179f5a8826018534ef1b93aaf04b00ea485c9d93accbeb24b6854fa6703077bfafdc655c67cc7565c94a39ce94922c5d64e5ba933bbdc1727df3818fda7d1cca32445f04abcf1be64a10f3d70a47026c02201fa35cec8c5692b88ea2ebcb178a51568d406e51b3a418c592a246fad460028ac0519be451405a592bdd065125d37818f459c1679adefb20963759cda88b6f52afdc628c9f1bdda3471d5b02344d492da4a48a83befa10ef1b8944782701b3c16360662ebbdaa6564130847ac848941251c5b41301c42a43d12e0c6f3defb328aaf8287fc051846758c866c5420f50325ce3a81b8c038780f6f81f11b83250b1ed750f0d2732f332abab1f854f780c34ec4af3db42b048ad3377828785e680d43e4da611d579e97de4b8b2c7c7f8e4caefea89e321b5fe868c617e68dc3ad178bacdac9c04a71a9f4f6e0005d1755752d04bb84a239b5ff2cd50865596899ca1cf3e5fe2238ad0d87e60f9316e150c8d873b08f7a08cc86576b2c79d5acc09b8adb4009c6528a54041815ad12a0042d1a7f5e3dda474554576152339e9ad1faf866494b9dadb37ced17c7c4d0ed7c8ada71d3202246697637015ce7c71d3bd6f1325abf119eaf2fef79e2c15c9fa7325a1a638fbd5028136684fc7e76092aa31c3f3550255fc22c9f1c89817236b743bfb573262098a462b22a4596de23e096f79956d744e9026aecdd18fe05af37ca753c6136534ab3de739f19054798923a4bedc1984f5e92e18a090ade04e7c8e8d41171e32d38e41514000bf47d3b57a52a07405eda8a9ae0bb5f2f329467fb89c10164176e2df92ac84c578c384f9bed282e0b07e3e5a46505e2d0f8e6ef0afda3d054e7e86908b1be913253285f1115b4e9931aa0f7c11823936d2cac2d05857e0b4bc0f558f2523a93f02dca963fb21a3eac080c54cda404946b72f727cc8fc6990d624b86f2d92ebc50d73eff95e6f3d6b9774a943e9c42f027669b6198a80fac4bcbb12b6df2fa333fa408dcbaef4016c3860b18274903728e23079b04d026968e5a3a07282190b052f0fcfc130e0d433a8eb485c318bf20e6d88ab6205521991bbe3adb22fe3c67eb88676c5fad8b9b3eb4a4fd405bdeade12df9fe364edc2114449d2620257ae4c46d534e2a41e5d09707e814995c550c7038d47c7249db13c408c308f782bf85f55d97f897e37a61e813f28e73824720d7517e9a17cd5320f8edb31ed5980ce787d3bc4c490b1067caf6c20448176731f37f323cc8a1457c04f7f26043a3f9d1b8d814e3c62b7c454b36d158da504addd16639b109602714fa48cbd1059970e4b7a2d4cd4e07ea37dfdf7373e1a18fc6a9d5b31497adb38cdf641a8837ae31fa397d79a303731f4ead154cc48aca45f0bffcd6d64684dd7dbaf5c7b87b6a04aaf049400d48c1a297bdf2621252653aa9e6638a24d39c06fbcf75ec2f87d72b15614142d422db44cfeeb8a15c73890a5b597664220c451cb0524579543bff334149951337c918623c4bd5a4b4f2327843ce48cfd78e24b716f18e2dea98361256ef990714f5db2f767dc5343ffb88ebe8f7861d07c9bbcdb843b66bc696174c421a27bb6e98b1b114fb515bec98854ac57d9040de57e57130816135731b67295d3923796e16aad075132da0947464dd314b4b2646d4e2ff48089b4fea90f0461d6b4cbfd8100e64523a02773ce0a3fab64e6955b2dc76ed4eb52e7231cb328c714bbe4ffc9caec215593343167eca95d80de326b113b0f1352add7b31d634103b7100469be7264a03e31a9e18a44eb0432510b6ebc53bad80323f531a8108c7accc67da2c573fce609ee4bd78cce03f17c6e24a31f37f2594b5d1ba0d4b573b1a4341635da765363f2840c748850c44c5abe535e0cafafa284cdd83facf9ea77ab4312dcfbe7079430c314c669efc11fa9730d3cafdb5a700bf5c1dc58443b76d2f1ef700f9935a57321f382e44e6b92c3b700ccfa43e6b9c4caafe48b19672062a126e26f3092168983a888cceb61799fdcf46b207075d13fdce31ac66a0905b6bc7fe3626d19a51b461b3a6887be4c55ef37f25a431daaedbdba49a0b14e9bc0ce4314c2dde4a2f7e8db506d6655a851ee2f2c350a78a5046b25dbfc326643802370ece24a4e445d7deb158c71a9bcbb02e6e180c00fb9eb3859c676d9bfb5e6415e93505454adaed082eb2810f364a619b37a69daad3431e0cc185d5fd28294b4e01ceda81d819f527f032771e97324cc8c94387aa6b67617ad4cfacf611eca215866d6355b14a6013cb2dea0c203d685bb19a6ee84517863e21c9c4ffbe2eada1ddad0430cffc8b49a6f118ebc3cf73bf846dca495129d3be32f45be73d2b126c500fd6e4fac65e5f9c7ae21d922970e43fdb2c32d507c99e60b2d67a5efcc1125302bf2dfc6217123bfe65005d9055ca9659c0fe162ac480015502b28d1fa26fa605e6a1c409096c70e0027cd9d214c8d5c82b8ebcb06cc80c05ad7e8e18cef5974e9f07032f889f8656e7a8187146f73911058b549f4d673f378e07be6dcf456db0f6168fd51fb2916d6081703634833e860f601737315c6ba830b14a3212b7e30d3b7d9b7dd7ab340037b2a9a60715e175acd103c6067dce1cb6e65127357410a9f6bc4dab2980c3bb30a911623d193d1be1162243e4447ad47455db0e3eb7e036f1ee08bc825ff2f43deed1791a4c9484525e3f4feeb73cf85a3cab289544c588f452e74beb10ab51bde1d8cdf162cbe246fd0a4958dd75713cccb3ccf6027f71144df0263c46fd652f25a15c81fec0739798a593dcdddd56db573a0aebc1556b45da8f826de5bcbf40b3760f6c8ae86c870c034fd72dc27333da0c62e04b858c1b0bc2e04896a7edb1bc9716f065f681e97724d7b653f8952b3ef9dab0fcdc95709064aa66041c19153ddb10183132ef5700c1068ec7669da674b56f3ee2111fb33e8d02ee44f8fa49353011cb0ecb865e52d0116480b9673d063f9ca93d33cc429259b33dc6ceac1d09e8bd113e80957871b327b9da37c9f1a6eb120b46ff416836669400c587eb62c3762c35744c22494c6c97c0447ca67b6e60c7ce7aa7444046e40849b290bc8b37208c395251a26e843977eb2fdf64a9cff1aad991be60d5a17d1f74248813c77863f37420065dc4886ff338bd69cdb46346e2d5107b014f6ab990e7169760cb9b9aa42a19f6428ec8fc640a8978b1564427dfae96f63602dd2646a14efb2b1bc191d364bb0c8ef68f1301de8e2edd98260a2a98034a2606dc383fb36e208524e19d799c18a913ab05ddce6e89915e29a26df4be867b87379d22af9b0b60d54a7799782ca38a1f390f5da577087def7a70b9b501729ca66a08e7770fa695aa0e0789415d7e6dc901ca6b75d769a52a86bb42d8de711fb3b83c4931f07638bccbc113c2b5de1126a45d0ef455427a22d79c5c22876cec885b88e80e40f6dbe3cb852057e0610bee421d5b02ff0f956a1a027ce331d581190187118a7988e594c16429df372c76704bd81951bcbc5e109fc56336b71d4caf960808092b06d3bf7301b4839954998e16f5924996e79cb5290c81b96a34d6e067f894cadafcbd2e2ca672cf96352e6064ab72cd3c7be6aaf35a9896b76ce81ec1afa927a30c2562bf7982aae4fde3ee893ae1b137d9c01cf19621788ceda0073592ea93b9dbcd4eb9f8697bd6716c6b3a9cb9efe994f1924f8306c34680f71042b0804f4dc0f600721efdea709803520bb08bea44d79e0aae25534d2e58ab3e564ed356b5a7c4bae03fb3e8683e0e507b37f7e9f1008ff0384017ea1ff45f2d46b725c10ac1b457e8c0dbc245d3b630eeaa26e7177c92c0d3b02c7a364e3ff33bb0db938f51de7e8e5933ad8ccb64613246d12899651599b2d35dda96e99a179bb4b15acb1a3508d1f7b556408691c5f169123abd9c66237443d96f9d4d148bf5c199cf283b5db45b0e7183e884c43865c7f3567d2f7e937198ef87a6266697e3daee88a68e2d374eb7b4636acc77b9e7a8f3cdb7a42fb43b1d531b2011d8aab383c5ed3def1059c01245a681efb10486e94570191376bdc20d663188519153dd063dfab66bbd551373c0672a3d9487d029634cabc5876413b4c7785c51e8ae70dc11f050e3b1a64d02a683094124bf966628b8e068390a815f7f79358729a59ce44697a9c11d2a43a5cf1572287d3835614391608cbefedccfcc730b17c489ce03c5d9954f2f7a24a11236a346feb1d3f3250204fa0eed4e8e8f45bc8e8ba9b10aaf9cb8c086137a75589328d3657bcd94055b85de9971b430508f1f824e7b8fd1e969caa6acc22aa23fb2e904044239d1779a0bccc0f6525acb21e760b624ffe5a645388865b7c5db599d6096723f1e0a11a8109a734ee1f21e84058bce70a939426bee69a1026111c802593595c890746b195c18cd42acf43986405f82389520df7eb85605b81c3d5b4516d771f22a6a89824fb651eba0a60b624c77ccd50a1249b6ad692183f25917c96e447cb60122b5b911c774692130347d8deddf74d9281a088b929047ffd07fddc94f6f59c8a249a7d0137f038bc0c7ddb825a6351636ab377a54217c148ea145fc2545f779b4181b8403fa22a92389685c9a8542682534c26bf4a1847962bfddd31fabba703c94619ad48e4c982d5e71643cef7e1259a7109d9e5a7d281a0ebc4347120a4244192985f3a5ca245e0f8ae86700ed946f00a02599e9bdd1d5dd3be72c471b0f3074a15461616ad8f8048508354b727220b2959104d84b80185b159302858c7a139d2b17d0a32c9594f4207ade5b51ca0e30eb67400cc8e85b50a5f28feef9b5be983bb277e40c09fa40520957205cbd7f3e993383b518d2eac89c107aa03299086ab82c94002590122d423526b08d0e6fdae4b4b2c7ed2b83da3428fcd8984030eb5bfa2a093a9203b6954ea25cc151d73c182564d38022c89a43f236e86995f82b923dc5ebdb0402826c969d42fca782b95fe01ed3379a50239446922317e67563af0033351bf28416815746cebc787ba436d66ba23a3d0308a2346ee384b94bb48ba865127928b9d220b48c97efdca93fae75e1433df6f9802bcd50becb760302e69177285054448c61ee5f76b9d570f9066220534a11d86deeb35f7ee18b9d82a82e06721c1dff1fe039cf0faad120edb8aeddaae051777bf11aa57be06d74615d0772cd1783234d8fdadb3743057f6422e6ad6125ed2292834d149219f63e05f7cf258f0c8f5e5148409116ab83d7f731cf02a553f81887b3903eb4fab00aeebeca8cd29366ecb3c91580ea15adb83aa02e02e07184df61ef5f15985e1ac6db9d976616ac85673fb471c2eab814a2d23c4f83549c1ce7c0d8dfbe67789fa2b0b09ddbb01ec673e709059306244e9db32a7cd0f4f9f2cd4658c68a1fdd8e6010e1d026bce66ab451045e18f861c0735c3a60d6f2bb220111e90223f5125166e66282b72db65c4f4f581eaaa7f2b79fa23e0a33bfb27f561346031fb0812a2a1c6155af99e406a80c33baaff903441c69d96f0a3904c56c7e35ea3901fe440d13c6716121fa25d7e49448a88157eba6f650d50e02ad89d0e8dc02ab765488e049a1e701afb1061de9b4390aa12428020f21bd9a0a23f1b73bcd8de32a4d076c4ed6d0edc60c52fbc1cb0c4cc7850f1d10755faed489edc0b925868d0981540afbe5ba5487bc28d6ded347b0d0a0137d4732e5cf996161685018e3c7d2b900330f2667e9a82bbd074b4ce64bb85e6f2f3e28785e6b0e2b99a4785c3bf403eca880bc787965b5079e63f5025e4c4b3cb3ca4d7dd53b4c30c0322b1370ce06fcf188aa477bdda064c09cd63ccca775558d45c9d127542f3b63134b80f82a53b75091b826dd0d446feaf9e97eafbdff7b7eabd33366b5310103c652141d439f577892f5d0eb154eecc3ade4eb8ad9c26eb314d8ea205e12d17077b752e21292bd69a9e3a5ba9b2a786956328eac0d35432dcab5b009d03d35f7a34fe39c42fa9e49d5763a734e8b0d3f9539d1bd0c3288bd6c26c4d6a7c202286ccf43145d921d206c7206234557603067703d32c5257bef912083ccfbaac09bb3846417adb8dd823a047e19bb001633d6591ff6565caea25db2121e10ab7a7b25ce6b28b05b821eb41b5d1ad819fe036fa53e8817df628b4b7681810fa8dd9f2eeb6197ee37f12dabe44791c2063ce607c874e79683fd441243d54144fd2a40475b772154dbb2be2330df1fff6db04ffb82c39c8bce50ccead992c56c6f09dc36197221b7fef7ea2bea65b7206237d32430578188a4ca203f7b1ba94b012d16bcb1485d754912f53749c8d760aecc70fd7f8a35b346a6efb530aca2d1a7bfafc3404170650429b07f09f72140ae078798680edd8071c8995d0cb9796a691907975b6ba8168d7e9973c287397dfa401e8ad47bade0eeab76fa47a102e707c147d960aa870f99f494c4143e571ccbdf32f79cf6134187b3170f5618ce44d5be290d31d9a19738319a00e66d451987c1acb5bf2445fb02b5771193aecdcb086e1281e6c15c8c13c7f8b9bddf936d8ba73c41335b3807f493a4e581e8b7f8b066c6405e0562d0f9737014be10faf2b3f36dd0fac95ff0022083e00425cb96bef9b6477dca946fe1466c367662aac4e83c2708b9ebc283e4de28d92316d62d335ea005fd531c96dc34d10e36af8e8b3d8b6a7912a30377c8ef8d0b7fa914b95ade0855ef8457a313ad35bac31ad48059abda2ffb4895598d1ebc2bf805627f193a4b2bc61f2280fb75aa655b0e427a14a0e79abd5ff2344c24478885eedfffd461216c5627c268089e8b5a16a0e5a41027543e0fa31480c212ec46cda9dd4797edad82c9fbf385825214d9331362824742a45970dfe90b3a21d9ea124ec478f86011689493cfec428f9e78477c42340c207ccfd9088861f9897815185850117b8fa94e9ca4b8684746816948d47485dd40708bba1c218e0da74801c05b190e0412c20eded8216d4871d6a4b869e65a1ae2462f1ff983a71b757c8c42a8dd375130c6a32121d22bda395dceadca9d2bbbf0677efb43fa0ded84bb0f40aba920317f0436b35f96c0d76ac9be17bb87886d4c745cfd416c4e1b10aa370ee30174a760ea796a2d265af60eae5f6a6245bf28a8c3be279d4a1781e7e1893158f133ebf1d0d7460817f465765a0e545c8d61b0d2547cc023e62ad2ee741798cdaa218bd753b6595c6076c8d1f0da89589ec7b07f3671d098a0479b70040fbf3437cbbb81b60433434f2795328a0e15f58aa42a61654e29332cfe10d6f25efc1b5d40c0520b94344d9e463a501b9393e6cec1fef15a55807dc181bd0b75faf9d0324c9c216ff41813fd617de51c93583ec0123982bf6c1749db84152357d2ea545087d48b89a033f4f54a8372d4ab56ce3b1ac450d81f69053ef372d379a1c7a0540ac7a24114711e08f85ead3870bd92d92db746df7cd7ba24bc6ac19eb8e1a08caffdeca19502f4c90337077113f211db1055bc0dde8fbd8d5be02aed29fc06962e91aac9dd3d8858374f40dc06db90f9a9e588e6f6fd90e20b9063e57183cb544e726ec5a94a02839308859f2cc3a609639647c80e81b0ce86376bb8b1085080f705295010f1d3e3912634f6b603d158acba7abf7a9f815e919988e16aa9020e927da69bd4adeea9afc705d5735e81e5adbf47643e88f9629a46b3971299bedbf2e05d1c0ec7d4e7c3219b256500df450d9042c2b2db7fbcaca9fbf282514d673b03514b03c706504d281c1fb9af02419aae94e1dae558341596867ad56a2e0d3a98169499b61e9c095be1ca01b09be153adc014935b2ad29b40ccb45f52c2aa089d9288f5409038acb2094078045267b96bc6596e498ff730a34f6a4fa6e2c3828de795c649a2866029e009382fec8a0d92e90da0cda6c2b84992ff75dc7be6b8e5f39be7c1ad5c4fd4ac5704bde5a2a0ed77edb3cc47779770ff44ac4f7be53e739bd0799a420f46217d1e6a9fcf876111c796708b2a508b37088aaa3975ca087a05ae7c259fcec9d83c3153d1f8f5eea9f17a8d6412950c45c04e91c8738793e8e21832d7a2a2b52755452dd17b53b1520d6868a7119f94b56ec3bf9ec27754e1f8ec30ee56eca4bdc4009a60f05d3618ebec78d266e4da293bbec28b05999fa9cbc8abf8c2a95634d1996c1745d8654e0580d41d48765eef94679790861f22f428872c64180283038dc0c741573e28686907140df7d5e299e6c5b8a2ef05ac1ffd1950ec858bf4780ccca2bdf06b42c20c51df415976a08fdb1dedb0fd7d021e3e1c4b2dcc5d5b5d77a24e671260a4237b29981e0a5c43558a1b56e636f97ff5169966a2ef2282a1ee075b6e00431a936e130e9a820a8d9ae34191240e7102eb753c8263f83afcfe1624b4065d3cdebf60c476c1b852155f6f8fcc3b2bafc64d9382d1cbd11d6e59c36f1272adc52ce743aa3c3d9c96b99be2f071e2704b32291bd74a80c2ca9ea9a26e25475cd658f864678efffe1ff456d9276370dc58315333e6096c1f3ffc30a1c4159a64c8591a4b997c24c3a32ce7c1bdfe84eaec3a07d0b7b6fbb8e374864cb49bfc3ade10d9babc5fafe88279ba5ddb805325d88d7bda0e4f229cf694e2a2187f894df0fe1465bfa997d8e10c66a35ccac58dedf0d3a0010b24e6a2c12867e83edcad13cf7663ce119bb8d48c0c977e3319fce73a6d3fb6e9b10a7fd9893e3d5d236c9cb03b0b0ed3680404075212903fbb664189ab5b9d3c5489349dd64a81dba502dffb2f9ffe2e171b36f98eabe52934f7d58d4a893da075e9cfb61d7f80d53668f764bbdbb2a4b0822df2df6beb583810601d36bc0c180e3683e3cbee52cb4ded0e4587c4e86d9237709c9e2c93c93e133136c4e3188bf25b8665368e489bd87c0e407faf38ed0f8f526d25d073aee60fd01071defb843bc933eaa99d4c1a5bff5a650ec5143ecd050a360f9e75cddb7f711fbba8ffbd2df4e509f0d2614d0ef85602262ee633725de6d102101ef6d8080c0fcbea500ea1fee0f981b53ffd6f77b735b2a5522b212d201f8a7fbd79081ce748a4f95779db0aef77eedc3afe6fba12fe1a6414c2f0ee5133726827bd1dd2b788f759cddf5b215878a2cb3aad2d420a6574352d733d389c02d19788e4bb9958bde5cb86dfcad33c24d195d56728b15614ea4a4553e290606bc8f0103ff3eef8b7dabbf1cdeb0db1273f37de761261bd966393628017534dccc4f3204588bfbc37760dc4a263944fc2b35a787acc4f6c6e912c458a08ce238ca2e104b6f8d7e7d43dc03bf26e3ace8ea7170e18a55256cd694ab3f32a3d838351ec47add1443284f26f0f13656efdeb73ebb211cb726b28c5f1c6519193212b8dbc8042873525d136da06596a3f4cfed931766ee502e6a1968b5ad5fae3e23f41aa4eb59ddbdaf57b75606eac5d2d8cc14adc5be57b75738d49248e2e611e8e5d88034b2aff775df9f7d36f132dc2cd385089ac4e61c331d30d995144211ff08eb37b85f8aba618c6d3102971f07c0dda6646de24e3f92fa323a029611f0b4f9a5ccd6e14c1429e4e10948eeae99f1b40e460a17e29cad00a11d88f1a4fe7055e0131a7b2091cebd4d2cf1e0c08264fe128cfa2f95a2910b37d4ac2c86ea313e45e02bd49226c3ca7c0e8e3573b788deb087f94337b62c134b12a3291de3d35848974f950ec4d77822c8d0fbacfb3f814104fae5c3c46bdf0907617a07deb27bafb0cf0e82f2a103c0daa6897e9e017d988b103842dd3c258b4b5e7a99f77ce3da4985507132212e56558983ea53e23c52ddb4fb149daf24cdee054df3e3f3863e40450f2ff1d892306f934d98e029fa929fbc799010883e7f5968d932bae83613f008043a3abee220b67315e0bb8c6a89941de6d4b90e1664d88cbbf4c9a78eabe9ee1809fcd8b87cd61e8caa50b663e6b308921fe509f29bde6deeabf577cff906883ec57eddca4d29d5bc4ac010ac5ce2a14ece0fb834e5e18b7b26ac6bd475119cf9f0421625071817b146c5a0e751b952fac022192f78050370ea198513055291067c37b37dc3b51042815482f41dd007a5b7c80fff57c941e1d7b1f01f0b196257e536541f3a29a0723e718a19a188aabe6a20d630a466cac365d1f95be9484035d100b48b29e141afa16df78d8e3f0f1c9e534489be19d2ee6389811e86207e601fe5afa1824d730b7665c0ba55958d68f7af6a7eab9ed802cbc32163a2418fef7276d2eed8210729d0829d63b1e5a5222f55dd2b392a8da58b34754f3606cc2b723a5a3ece8f6389baf21c95d91d4743e1666643ccc15969fd5141714b30a9a73d647f7dd4b4b6ea2380b9b2a33cfe202e2ce94f615782dfe4f4a61c0868be12d6debaf37318f32d3c59812542576e32ce58b4aab773f2d24ea282acd03fed7e727bb407b2da611f8c1f59ab4ac8cb515a1cd96a39871e5bf0cd7237665f2b6e7e3a805839e3bbf2aac6808e8b0434eea516d7255366e13754cd3cb6439b6dd03a5d1f62aec269ac1cf670d4bfcbc297d4418e823e8d63f2a256a142a31c327f3e6ee40368f465e07255484f8068a1a46f5401c78a17b8a4c0c39402de3cbd71cb294f91c5a3d578fbed0207a363d35a8bf7fd5ebee5f7f3f5737adcd4c7d390e04a24b87137b36a74dd91ec62d197570a677cb4bf4b626056b51ac28632302761c27f6e8f4814ba7f88ff15fabd97bb8a4f9872cacc1e970f12b118f235aabd43fa8d5a5fcd509abb03d46c26b300ad24488c9291aa43a086e0180947840f0f5775e8c9b4e5af33e4897857875e22c35de80b0d249c0faa929f73ab4541fffa518549d436de8caf339b1f3a6456b35eb199cb6a05c82fa9e96b09a68f930e635e204ee9038e280094a783348feba6158fd8b41e3f8c66ea32e071e066c0b9d048caeccf5be097367484985fc5a843d5b0f001cec072df05745d47957a68a1121b0a7f94ff3d732f865b7789400641ff9a545f2cff2a750601a287c880f6b7276af38c4c7582acf5f41461df3fd5d2295e864e97a1533bd725654f94291737eeab7629ba4750f9118e8b131fd0682a253097fd78fe4267b9662cd7acbeebc82318abb7886688a835b18fc85b4ec91ab0207a4afa13f6ad192c09808fa5ceda217b17b0c8d5e7e20ccc7088ded78678f66300a2a982ea80f0534290694b16ca53e9b8e389480e7c2e2d733dc9e8a2378b7a3157a0bae8233885003ad7ebbd501fc96aa7cfdc08fe688c06dd261dac840704b43542b9e5389422846d5d27d1950c6a40e800f03b07900fd9c6564cd312480bc880d428ba8fe4812475a41c3f301b4af8f19ac43d371687a11cda8fdc87d4868f43c9991e94a9b53c51fd67b82d559c24451933eb22e9dede2e0946d9c61cebf2bfe09d94eee6f6e410c595d2e770fab529b2a2f9607b9b2280e320d7d6b5ca1cd6dcf9850aa300c5714f4dfcb6320332552bb45667b9aaad4118faad946cb3bfa1c3daee34b99756c7eb681d116e418fc697e0eda2d872b2962701caba7942467c097f3bba2068860181e3f935d04292c19816a4d46bb1dbeccede72b1b00474b1de160731dbb3029763efaf1dc8c5c6a2ea43e15118896686563705eb7c364d9d800912f1447dbe0a5ffd5fd92234eeb1e312132d7f1c7cbc80065252137e7f842598d870d800fe2c540285449058c09ed2f1b7f5171e8ad80d18000caf9840ed78eef4e07914efc0b3829fac53f21ce40d17bbd8c2ffc9ace978909d5dc244d55fe03bdc9e1844696b4f4d801ae426b0ce8a86ad3e16ad7fb324039be10bd8162d933b09ae8d9520be283a500dc9353fe8898b70bde56d449fc091389ae4cbe96d2c5ca8aa791f838d40dcce19b56ef6c92d88d79b0c9e7ae87de26d47cb540487b80ec513c7793d904038891068f0cf1698819376fa8b352ce56adbec09293568bdb4e099a58c716ae617b69c78c731a7038166a43fca05c2eaef19caa4c425053f957a47826175372a125220fdd58ab6f0d02b12da8b56926e04ec4a8edfe9fed0321aadbdd501a94019c2bb96fdea3ba2645d1197841b2add2fc5d5c837b3334714ebfdd60ea9b6d021fe7fd468cf58edd8c6ed1a90222c9874f3de69a26b74d322bbc8942abdd1fa622934526a0746b69b2483032bc7a789fb33bc94d826ae63769222b50a0a67be7f804ed819eb556fb35bd260cb2857a50cef32164bc6c414a78a1504bf3bd08059109cf57e9611f55934e1179387266f1ec47477506e326f7dab99261d568f659379fbee0cf38ae81c0cf988e250466cd033a70de8dcfbefa0c58c2ef707448cf1aef0b7be9415b08e1df101fcbe2b49d1ba5e1c22db2983ed9aae7a6502af143a479cad1c3221750fe03ebc24057c111f856b36dcc3b01f127bc283c69a54ea4b423767d06d7a535f4c51d648eaaf655343005c03e4713733f39715467c129436c627b526306527dc8d965421ee4921310441ebcf07dcee60d92a87e0f3c11f1d436681e176f8e81a56f78b20e07608a114653800c8241194c14217bedb270d0a85e61eb993a29576cf77cdaa2c79a4c9b5026e1172d0a30a9c57bd3236a770190846d0be519b60d058300a18481c07cc0d342691179e2ca010aead2ea8dabbb103a2a14b3fc8aea0f9944f75cc2bc48cecbcd0d254f89fd473f2f19ba1c40cd0e2d26a1b6d98fc92e3d585aab68d2b38ff988f7a16c9064f9bc968137ed1c73452c009a228b8ac0d224352ca052617734cd24c610cb1492250854adcf81469a4701f8d0d02efc3e944dff76e86efeedb3d8c8e9124b42fe6c81a946841abc3490341ba4ddebc39dde83466e3918398f393d66f256664bd89cb8b57eb423e425035bcbb8486a8715445c80fcd6c8dbd335465fd4530abb41f6105525ab9d83cfe30324fece74f59123eee3fef4f25fb25a9189124b55256fabe9365ef435e16b48bb78e1b75fa6a0ee1e4c383514446b4d72e95c2e36555a3cad7001210e4fe7a67c36cd58cde12a657b1402ead77dcc32db34c1dd34a3628c9b518e5c2695c437d9d3e60792960a7ed673411feaa3cd07209dde7e6c0156283eef6dda6bb9aad4c57dd05c1792c6b607825ab0b47e4a9e0c267748328477920056abde478941f12b0a8a38fe9bb5f695b84b82e80f24a74f13e96b1a8e0b255022170b2eafe70d3ce53f65c9afc4fb8348b90598a9617b66591634b525657e3e24b08710c06c5969bfc6ce0d24ade764b4c2d857ef0db3e50b5196f1c5f1a827ceb5c7cfbce58ab28d37ab1dc9ef3a0c8ecf252b806c684fd4f75b18279bf812e51e4350b4069c9e2ae22dd8f181cad06258a8c4543d88f35bcb540c95e13347d560a0ab67a5a1c135ccc23c490c7fa3c3e934020ab6b3652fb1c6b5c819c514b582ad5a66c4194ee2a5f4edde7d824fb48e8371ca629667b84219cc30b0fff6759aac367349d83ef960ab6865acb24a6a7cc7eca1e8452012f01dd20d2b467ad84f033c7881c262fbdf4e60c071c112a9962102c8002d3aee0bf2378ca56f129da8bbc9c049330010936b92dc63e9f5a21b998630eb5882e2b8bd01517c0daaea8af9aa2b2e54dfb53ad7852c95c3b32a3a46cfb7cae9fd5340afb0171f63ae53744da451796bc30f3aba41f2bb99bcca0099fad28ab7a813f54677c639b4bc962b5a9b77b24e0852a29e4a0b720a926bae75202b9f2a44d811e7c823b77d8219fab97015e10d8e549aec085aa7927df32b558c02fc4db9c5c7b81f5f3d9a29663c3cdaac81f0f1c167405ef2e8e2abba60a463ddf80d1337c55d133038429ab6217a81908f5b9b9b23517b964a37fe090ef1efec62ea9bf2a14fc7e18ef3165dedd63d3f1bb2c64b925b6bbf51fadd04de5836e74ceb5cd57e2cc8a741b6d6e24145e159d1a852235366816b938492f085d98bedfa8a955d58c7cd73d9ae548a7e5ce6d0c8b7291548280e3263408800231299049872da1e42116a7bfb7afe14097301e2d0926116728eef9db938d209d888921b8aaa12993f6570e728081aeb50bda2c6ffb5fe9e9d98e33bc7df9d952a43e140d6a3b06e76220b769733d9b81bc6c2c7b74e81c33fa1b31e0dede5df22b7c189e1848f704dc7051eb83334187b2112a43bc0628f802356719b0186d1caf84238b2af6cf719e61a27f640b3ecb06d33611f929f6145050c43ef8718cb099ee9ce4ce008bdfaeac68b59ebf36024393e5cf679ed5271f8d53539eb40c316ede5009962324cb1fd7a8beefc1ed507d97174cd7e7cc5a839f133dc90d0fb171a8200c3fb463651dd033dab012b34415ed13a3afcfc25ddaa462d1420c6a86410be35776359938bf3ba99cd195eaaef4709754cd6000c7f0e0ab62f49a92117f2ba9c603ea143f24ddf45069b263db0fdfa2f09697ecdcb2da448f9d53e0c029e068e539b8c2dfaf76d382f9ea8d95304f57c5f0171224e85262052032ea7c2f1a0083bc4822480eb55e2e09b504a5a8bff361e3378c38fe8c20151cc774a8af9558cfcde866f858e6459fd3608b1e13db70ad36cce5298769b27a8bbece2c99dc99f91089a506e36e42d6baa71d396735f3cb2abb0b3d6250b83c0528c2b412ba00be3c95ce0c83e50ef944f05dcb454bbf7c60ab8ecc2ae452d0beb89693385bda25e7f87e19a0cade78ebc2ccc1416076092a42edc1b52ad8f1bfeea5ffc8f91a245cfba7bc607184bdfee0033361d118fe7371b061395de9c712bcc649b4a95dbec8a29ed3339f83d5418484730916d243f7a3237476e588dc8a5f6c72e2d4aa88b29159d5fef08291ef07444d588221a63af7992fac83ca35409e09c5bc23a72ad641221eaaa098c90cf6383dd0219c6fa8a6efc24cead13fe4999642619c61f7858b484264fa17ae8da2ad05e86f1a50b537f1fc47ed14579342f1db00b1b85d2cb9cb5b53590a0878cd7423866961ad5b776c6828fb819d78f5a2ff62792a53e8ce6d2ecc94a3a1cfa635b8bf9a5a3fb9e61888299662ae648047151c46e303264c517b5447c3a095479edcb64c65b76cc7c5d98b6d191797d9e9605b5b4606f379761fc669ecb196aa76c9165a8e80e2c021b36605729d9243c2b6f0419fb9ee1a905cf82adee5bf298d297156f1e6d943dc70a3fc40c0e07c59e9a9866f6b3119c7549b05bfc0c1bd3e652f4751b8d56cdd52060976b4db19fa827e895efb7698ecabbd038c7456e29de81e1e061f65075f4c8244b8d4c004943b266402deab8b2921e55c63c5fd751782cd0201c78070b68a5ae6a2b21d9fcfe3ec6ed896f4f3386c4365fefde1b6de95fd9c185238b206ef6e10ea6dbeb4e1f9ec4686d6c5270dbcdef08ed73bd33053e2f84df5ce6bbe5d4678c07df817f9e0f9a9baf629483209dfda20577bc5192c09c89238e8c98437e22a4b46692f003028a86f8fbd06f251d6ffc0e9207daa01de51c1563843888744a73d8b61a505fc576d26265e4c5b5d232b2308676189173f20d26127276e98d40b9a3ede0050b2d7c381b7c157555bb16cb36a9498630a6aea33564bb99bee57596f0a92de5f3da3f8801801161375ac220c96acd41537540fc6397098681da7fc45d7b1cb940959f229320d70ac517ead4c59077e46e9abc8acb386008f2474e8adfc9162cce5f7375c3e001e84f69498b4c7b67b64e62996e033e9ab04d7b439a04e8ede2510431b08729ece639c07ec3c9e5d7dc4ec82668e08e1b7f5d6489bd065e8fba125f505301951b0a985c7f66cff44cb49c7b62346c0301fad1a61c6db6f5b09ef16ecabb60a83a24398412f43843ca833f1f363f847155d5daa59c17728f8146b315d12ca8c238eed165b0fb01141b9bd65f0e6730a32b3b6aef82aeb4be9f14b993e7041b327fe9f6142ac7fd3654c271005873a6a41d4a404bfbe05b77c3d94abb1003e7a9daa5f6e52bbdba3eadc26aaa4fa43be755a6634d5cbbc6bcc87668b4245d8076af5defee1593d2e71e0ae0b269b18ce6051a6758669b4eb5a6276d280d7f870245c3b185c92166d43d6f026050714332d109fac8ffd3ea3ca511740b6d1d0e4d47ca048761a79946aaf5177c8335c3a622133500d192f412973a8160e464548a00e3261c8ab390fb2474ea18dd716bd9b062261e7e8f6e99249642e9aa618289a3fd9f6d1b925067b0580ef27587ef3fb9f23db0bd91b3c166d1be5e962b9320261cdb07a8f9df29fc698078a46b9c200ad9cfa94077537d8b1aba332f3c361bd0f8fed83762cec4838dfb2d861f48f1dc41636994641975336f0a5e667964951c40aa070a4812bf1fdbb01d8d0b73b37c3886837a06522a61d8f396e4509eeb0d238bfacf05ee7afec6b713a22be268a8944d7f0f0a44e3480e922bc0dadf40caa44542c5a2759e4331a975ab10f9094f1b56bf23cbf8d15386ff9d0c5c47c6e0cae4ffe5046c4da0ed542ebd3f8869fc872b1b71a866add2f050d7eab7d293eca5a86b072db2db7283091c218eb969220fd5a3f3d18253a23c0852fba7520593d00fbb7b03a783bbfacfea0b50c41d4549a5c3582f0299f0d5bfd0f8724f06fee71eaacc90724271b09b482a3ac4ab3f14b5c4b356a0b87bb83c55bb812130ac77fff131eed246bbb5575c355c241787232eb2c85c09079d01d20f1dc3f04f58df90becabe2ae8e4dcbb450b3e207d64be969a4fd136a2f8a051240f38a6f65210a14e3ce9eb575fb0774b838a8341fe90959a29a80a892f5e86a819bcc41120162f2248a13da26ef90785f240bd398039063e7d748fd124885cd07ba3536280ba47baff810a84a828e146b5219bfd08dd867ac61d67a3a85ae181f3be78e15d4eb74737bf7f79c168cd836de2c8bfb2e21d4fcb049bfcc594607c425de3ac4bb1459e07dc1e28f1e02e547007825fa1328034e7c2e18d03be8b713b4f21a24cd132e14ed7cce02537fcfe7696eb7b95b8ae96c0b6a8e003c9948517fb617be3ea21f5678336078c62c68b460a88541e235890a90b7282ebeac89c44b700d3f1513da84e1c9b8fa5819f5e6dc916acca2723db81fb1557659c8ccbe2b9e35b997347c4b5dd168d0ef4113a60c1e1216114d7d60585ad20f651c76abaf908d6da96c20017f26f6702ae133d2cc70bc65c43bf1e65f697d2e916007cc0c68de275055c71b0b4a35dfd21fb7d64633a04db23f49d20bc194fa4f72c4a5e08be701d0f325a0b1340e3ace5c979606571cfe042cffa80ca1eb922d362d1b968f8750f1b95d200c45e9ddf396b9f5563d7b47a1f1fe7db27d31bb6f415b9de9f32950ff0b443e35bb8d974d1fbe2029657c4334db586e8c440021b1119a8c87a3430e6e8d05978a21ffbb56347c176834fb1eec0da0a6807743e814e575f3a1173d6e11409af62e7ed7d160ea76499b3849dd551ba9ebab0a1e4f7e89da279e443c112569c9ef0848e9b88ff4b72ffef58c9eebbf0073fa80e4f38892c6fddf1e9ed68a44ec631e06fbc12cc8106d7ce3c89172f5fc37e65608550fbee699a7e788cb95e0fae5c8a36ac4f47a6207fd557fdaf3cf465ddf79da157652a67562f66683668990200c75138a4a210e439aa8a249e804423807e69890ac91c33febcbb36a947dd85a2106f22361e9d93bdf7a259a9c8f9b4e0818e432ebf4ff1290b31e282237ccf5cb17f42b8cc57b9e2d73db46c8d8175dcac384283f3d841c802af8ab43051b9c9ffac2148e8da667ca6a2b10ba1ff67ee4062bfc5fa66ae5d7a542dc197bd3bac25055683d719bbec07689aaa7099c3c00558745e7c1cfa938e05ceba3d5ee9cf2e0b7048750045011b9133d8d63ab2fcc076c41fa26bce3caabfcb5949af058951d9ac53c22c838d68a4221c28b3180d38f1c8b46f3cd4d9f3eac2b941dc718d40916f8311380703518ed721c1f042d7d18268f6e2239166001ad003339fbea7c3fe9c9a203a50e3433c8fe633879918975a8cc8a5774411bd959f69d573b791a2360bdb8c1ec23f7d5e0427b7e6780199c81530dc8d21c12f14a024f03e220a49b4204c88012c48397306736c16394d090c096fc0d75f5f1347e128077abdc0002016900d5fd6ff70e360b6ffcc1f2bf3c03b6d5e1496cc58e8ad0d6e162847c1eb282b5909620187e6800a636038096b4d4cd9f097b8d2903e531bf674e9fb159e34b1b1050521639f9d50f083fa5128c1ea11cff78f022f2b9c6729a1732e93258cab6f88502f6d7a222ca9ff41cb81703726a7f250193ce455ca70f3f918388562e19ae35e374d6aebd4763d226caa9bb28915577eafecde1ba5f28b47caeff0fa4ac42608066a6ecf646ea4231001d0386743d6462769f81f71967deba1117282c90958d42bc335215a451f3fda094e5c6a927a10c10312188944cf17a4706c05ed4e344c37d3f3e0b50e6f3abf3138f3b5e2401c84e10de31f09754988793241dbc580e656837604d156e3d5abd96dbd549e9d31c04b4ec33de7418904545294910ed2f60c70d3aaf74325f38e853b9a4beb41ee442ba49525fee31c2d4e4f2acd9913a7d584a13e6d793818b80202ed4571a626e7bc3e4e9fdcd3f44521049f63bad551b6c733f37545abb4dc07668a2f51e99f35d4338de4638588c64d0a17619c96f6920884441bf7d563c744681108fa96223862ae7bdc4dbf46eb1c4adaa31a40ec489ebed66921e3d51de1a31dc6d9aab594dcf94eedee1ec71ca4196edc8a7674ec33129bd56a616339bb502113e16c4e888b5ea4aba1c5520051dba1b438f691deacf598c3c9151c28df5961fb637feea239dd576582a441787b5f364c864fca9c4aa1679fef747ae3f488fc032921a30be9ec244585a2564eb7065fc6150d1b621b4026013e5abf5d057b53190f08bf10723373487a637355cecb13dfb6e29313157f248c62d3dc2308daf3f254f06f3f70238e671e7d9440d80e6a8da5ab67db447d51c519121fa412fa23d011afff5f8c5c0be0fab2b2da751d0d16adaa32cad97e7b753a7ba0111ce340114b38145c66af14b10f34d600a5782e15790f72b7abe4b214d040f843e9472679fdc9df40679c7da2177a6b9cbd087dac25433e9e7e549df68eda3221fea3f30d081914b7c9a204986c846db6ee2941661e60874f8b752afa147b6440c53965c1aa75d3dd457c9afd7dc687829e85c384efce6a6b0988789320372eddad3e957c20b7c03ea4e777219d0b636442f2477f060dd6385946d2df75bb47cf4f7afaeecf1e57b74ed179e9aa025a29e435fe1e7f7b7c3e8aad1e88c6d608bbb49bf0c07457f9820d8c9efde01ef6e8e72a8441f6f4b98e02c9a527ba270bb0f922788b11bfdf93fae5645dac0a6352bf39ef36729244a0245acf3ebedaa4089bef9a624ab56d18f03e602f773d8e6280ba3635f55db76e6a00fe2bf95e564bd954f1403dd3be0cd9ec81f185298d9ca704de1ea97f7694a973b1f5899bd67f12efe210fdc0a670cd4689cd43ed8e56383b01b84074205f22f47b8933f5954018ac8d98e61c6573372978f177938c1e446a80284e0c28d23103adfaff4b27d24329d1d685ad791b957dbfb0fdce9d208adeb927d9874aef367c0004c13ae0a86fc3fa18497c5fd8ef2d92efc176feb21ddddb02510e9888070ae8a517ddbc7742bee4b3a1a03a03caffdea17fb3c886de783adbd0750e388d207babb1e7de82bd80ce0bed9e949fae977dabbfe6614a4e881d0a51289672a5ead9a75dd32238660e11b59c81e48df6a45407582d593f8b3f34f79fe26aa040c5ce6849287c31384326c94edbb2744472929b3412b4b084b996b987afcb18c24b8ae4e0550b5c0eda1110111a011ea270c18852e70fbc38b29722e43fb0db79bd7736b1f0fc519e3ce6da2acb6f297bf610f9a7bdc60bc318ca762af290043af03e799962b1018f497b132476b87515dbebb7eb14cb1c28e587c58cbce3d33d66e9c90ed6b768795c83542308246582d4333971824364a40ec7c3990e73bc0b9f5d4ae59145dec0809fadc3e0160475703aeca8a9088530bb7c95d4aff4b6ed6c9d421240b7b815248c823f03397c85e2a41c29a94eb3eae0232027c3d82c9265dc480afa612fd78159eff068e81da3acd5a3aecc341431e9d86a610f2bb8e056707cb3b9f044aea4178e78bc7f0d062b51a77b41e6932f133d11075b4861ec78b9c2ed8994e2921597a07a488468ce35fa15ee4a5115a5197f62a66329a7aed8962d0e4fca1e4e3e7f92286fb70cc29f96fe414f43975e9f1379323f2cdabd545c5e6b6391afd1f2b30ea39c5affb62ee9f89ef15277f7dfa2ad35921f0b3d2b7b87df6922f8dc7c4524ed7bf955a554bd5ab27b7e761078daed1dc56bff2b50643c44ee6a54dfb705469fcc90078438e330365e89996268fa47d9792841c7b09f9df2ec14074af02cb26b708c85943cd94364167e06231e4ba6c31e46213787ccb67e6fe47cc5e3b6bdae95d6741660898ca966bfdc8b434b673385ee702dc321c93e04563cf5cf29e95e190411f7f1519b0a3ce6339759d0753b56028f702dd83be8c7db0893ab19dd503967060607b7425838271edb2cd2dc74dc530760483186771ffd0c9bec7bb086c4f420bed030b5424c1f781f3f9582156f54cd54a8eea0371bf2a39fbb647a9be623314c706390d2f1cf636b883c543c08ac7ba16aa77ad9a4667b93cbd15769a0cea2c7e92d600cce287f8b73c11497ae1f04b54a482e9a7573cf022c468a2a8b5b02a714cff14ac4c7bbf127c0fcfd47f23f367226806faaf7682b73b178e13429154edb5e544c88fe63f4305ff4baf5e7b95d0e53c4885053be32053ae00db3f4f052d4a30b05486a1dba7c1ae2aab3bf215078dc9a632442f09d8b08e9b7f5106eb72db85f72d7c493624505abd09c32e6cd49689cd0273510ff736057bb1d80471be62c7fc1507c11ffe57ee1147eb8d3e2cc2dfb8a3b6006d9fdf8bf67270535d3ea01fbc055c7c3640ffdce3a9cf878b0b057517d7fa73ce7f752a731676979663b6321f93e6c32cb615ef3c3b2892e16a83b1dc250f8902d28ff9163647a1b2531d843be84368ddd9ae942aa1e1a912462172cca85e91c173703a90ac2d0a65266a1828639a47313bc239eabe79412b44e96743a004299cc418c7a733d5c1d5940475d0898c96274632f5811cdcefdf03ec5b1b852b89a350eee2b0eba0ba749e872bcee48b8991781ed4cc5cdc4c5c7942ff8429f3cb818307b3e9e359cd3dadcc8dbcb3e0de0dc05b0bb814d065ceda06f2d07149510131107202279bdc7e3bd2677d51211f5865da3c003ba4948e5160db9404d879ef3d19f6b420c1613f10a2dd068d0424b18b7dcc36535aebf215aba4ec8246fb4c833dce17c83a06d4a1d00960bb1c51af5d1c57e5fe237a8d665197b2e42c956f8a1b262871ca2e791d1a93918ac3450284f2b143197a36e303a9bf624a6d445384457a4cd8bcbecc86e83af04a31bc05723f1e6cc7728360f2905e2586fe02952dc6489e33859abb869df56b6d6a46ed518a7bc9d221e58ee918444c0168e74ba8ea96415cd1390a56837a2b41a6a975af0c830bfca70a4f25c644a5c83016fc3b945f40b67c40d4328fba9aa4e6b26acfb27bc3c9ebcd8efa820d133cfb260101ea5b83ae634200bec90366eab172bb63cf01838b26d2004aee5829c1fcc1269863bf9ac7836d1f74f9e9ec631a9513d2012752c610043966be300618ed5aaae82b05e2ab33c1e0297fec247169bce5b62ffac3614721f4818abd7943eb6e6064fe2eddaf09c2f31572e26ae93bb008b7ae3518346548de1db3676bacd119f3c2d2c9d35e3794bc0d95d788b785627f69534b48c82b073d39ec9621821f0221cfb998d3fd1329e0586fa1909553da42c83af706365a35db5cffaad4e830bb5c71f77ce9920a4c7029a406f6bc022fd1a3faf7784e6987b8927d4e5e382254cb38320fc2b8f2a7491b29a5f33eca1e84fc073936b6b53356a808934396c738ba00034b8786e6a8868512d614efe9b33c8682ae3e56efc4832a1b4cdc178b0f865e3eba0e0721ce80209ee56f076ea7b622c39981a0243e5cd7e378d8832637f13891a76ab7fe9d8a5774e5bae530dc96bb60eb81ca340177e51a562a3657b6d51286eaf050dffa9845889ec3a9bed78fae9c0dca40e52b31e04cd752aa97c6779f0990afc40e679fa3d10ede239c3203bf17464b0366172fcc7647c72ac7097f79a822194c0e52fec351e9664096ab892be59ef697786a5d9e1d91c768037d13b4a289767bd53f241c499a13f13baed4b7a09f44ae5b8f2d4c74f1e259f9fcfb987e33772e1f0424e9d0470486df547e10617e8a08f1fdc641a83eb4aedbff2a2f9f4aadf9f6d1503719b862958c42b4f1218674b47929b136aaf84cff9de88cd10954e2ef9481715f941bc38a8db262635971e359a3b1acdd6856d148d63696151bcdaa1bc39a8d67e546b0cac659531b07b152091549c06cac0213b78e07aef383d4f5e0753e409d1e5cd783d6f9c07572d0ba1fbc0e7cc05be707af7bf8ecd479e30e1231514c69cada36dbfd902c8f19a6143d8bea66a014fd10a01debdd63e222e0f2b33930c137ba7be763440d00c7b83d756c89cc02a6060450c696804245d50ea43794cf10b03db03f21ea3c7a1b122e464cadf9ff1400fdbcdf1c9e4f7f043b4da142a898c56af9454af79d857782f7636e58b4c8b5d41536c325002a5be2f4f864bfccf4ca293b152b5c1a72cc1344e64996d167ff1cd4d774134e2176a01ea4f9f678f3e5ccbd83e3343782d9f1c87dd193828aca06ad874e712f65d9629f929ca9d8fbb16ef6b4d4cf2b12e84e91ba20281cc94adfe7db2bbd21509e6e482e004853fbe03f5a0e422173e95133eaca3d979fa0336f0477d478651a9a9011f48aa8b053e1a00a1cb6cade011b03225cee9cc0227675e31d3e16e0fa102c2568f577d0a1613cc4643c24d0417a7e0b52f1d038a361f0722c10271326eebcde6236144bd1f5518c3dea46eedc3869e90942de91ca9bc2ed7ff2428c6e79380a3b1abfeae5dc9a358887f90cb10188e164e4148d8b97594a01b85f6815e2a483f19577335e4d91bf6f784e9e0ed0d97dad7bcd7f0ea53afb6be6717f8e79b6e86161245a8be2811a339dfcac83db3d8e4720baff9e0d5936b79c75713ce2c68b5ef389cfe8fd9d683dc112fbfeb2fa5415c74e265e4e9fee8663093eb4b48bd4f681800a6d6191d17351c52af7ffc8d2164001a9c4b20d9be4781ccfcb0a8ef2a54725d3b9e00568bc4a818cd38dd5005abf2ddc3ea2b79378aa0f48424ad9e0e7a09c8064d2a20c111afa95d31ba7113aaccc9067e6c8549d640dd307d79c53727e6e1ba9b854a3204901ec76db04eee47e17540c092c4eb500ad60e228b8a0c6d5c8c0ee9b59526b2128e1c33253624181c06b51f0a09fad74efdba1c2121eea0239cc40e9130028bedc45ec61d975ec288fd0e7d2eb5af9274a0d6f91227d9b1ccab9d0154845b639b524ee5b5a91b2eaedfba29c82af83a616b9d31e6d8efc9dfa4d2513e8ded4da8b17248e2e08687ba6189f3a96ad847a26de7f3659b89c77fb972868e1fb547e080edb9c42edbbec1f422f7d46eab45d1ab5713b516ad95a22875906ee8c2857806c4ee33823fefcd92df0cb8658ebd950de6b58be2a1cf4fe9aa827f06622307924c1bb4b1b3b59e7b8d5ddfec7322387820884cfd860174813567db4bd4027a91a49a7801504782f37806426f0e19f74a4f59c2004627c1df0ee635b2fa6b20f3a82dd761ebad1272e58cb1d82f7965c320a0306b3d767ece37077d5cbba293078d32f357f0eb0b78ed9cdcd921b5346ed56fbc43e18918e8c772875ac17d3b30658a5c90c0621b22d2e4ae82b8648c146bcf836673f5eea9ba5896051416d84268f7c3a5f941d615f3107d763a26d914c1b6f04e59fd8b3e88967ad9f94fd6f455cb8b571ef473f5ac9a1e44b760e4f1ff15ad2ade6ee0104a53a98af813119d4aac13624fd6a466195bf6505f6941f25d7730bcc2e08bd0c15343665c2fb2fbcefedeb848994b6b0a927819873583a27c61a18cf353aadd06d2426825469a1b4c5fa3851e66d82aaa6783efd75b88738e2ca7156e209f8d75355572d5a65dcc617122f112493ed94f263033ca4e908ae38046c3d8f2bcce0ff1ae2c1b26db62f4db4e2dfe08cfde841dfd2ded1a96b6c15ba2ddd00ec5f49d6ae60496bb8b36806469ed07a2391d2d692bf3bafe08aaa1b2a5053eddd499dcdc9b323ce93997db5123135a8bde95285883f3e3d0c5ed3856a52fb79ef0cdd06914d52fc9c1c00bfc16a9e9248b2ee7f85ef7a1c1775a02010043139f828239b722178474a97876c431302dd573bc85f357eedbe6d71a89c2d07ff155c62688582d18cd591e351b3faa04b17b142f16ade4a93bc6c1f01c2b542baa8d92b59e11a88d34d0b6f47a7665e9174f7bce57e62ef90f7c939f2a87266f01b400788defaffd5aa46631ef391bcfa234ed8179a9a4b8a74d19bfbfb87a122abee14fc047e65700e2a3c0c3c3185edcbe20c65318278bc1b90824ab1de9a32e1f805afb2c00c0a156c5fed2dc98601534e145903518c896071d02e65a9f7e9453e39d1914a78d11dc2ff8390272e0225a32f75dfc239f938ca5ca29e568e99ab18a301071436ed07f672e29ea893fc1aa78368964a99b69a4820fa1ecd2b5e983c4b1685dce83d01b301c3a146ba672a763dcaacc96bc7be4ee0d54dbb35bb0c4a23f5be655dbc8e61ab15f9cce82e750673df208d78ac87fe3a149802951309f5e7b247ac1eae45d263e8905bba61a51ab771d43c2d23ffc00bb0a4fe9a8b39083b31dae12da68c408b61a00328687fa847cd8afb8eacd465fbf054acb2c674c2c244ad50b4af5afc9c1f666eb836545297a7060bfa7da8bb58300e76e4d31e5224361e4b5e45ea3b3ea172586f46a95901462ee15ba77bbcaa867aebb39b656523f6ddeaa9b6a9dcff8c12433380fa617996c1774ee499986c7e6b141e37f1d095f2e102cbdc4b06b655d5e03de7990250d3f478879ed20eaf74d9285be921c1f3472befd87120eb9a968e5c6c3bb772ec329a369376795351a89aa0d294f16eebf4bb50418448a7156dc385a5d5f5f8abdbea74f13ab2681ad49d4a7bb4d4d406c0f2fc3f0993b498cefd1991b1f75c0858f96c2e49d0124aa0e2ddbfd5b0c5995db19e23d02a222db6978cd045304c266c623fb5e4311df671f70dbacc03fa16ba58007701f6374fce0ca1d8772065779e287442a30ee2bad4e088c503d85d2a4e71d2d666d170dfeaa851a38188c399344ff04fc168f902e9bb9237e159d3b48b5c5f609f147826967f05526b550f06d5c2cdb200126a350ea6b54c84bb185876399602e85fe9a3124f04dedc454e2e8ffdac819505c6d02ac0949ef4f739ddc36733a6f7520846d4dd4aa8e618977a2343b2253d0f7e617bddc79f12b0404b6f6ff839bfcb00498ba49afc0b3f7c4001da0e7556418c0bb4d5cb3771c88573a6a4c8457abfeccec09215eea152c4831c1a024f20897660fad3ea0d2f678e9dd897f73fe8ce398babf8a87a00650a148de1e07dd59ca1433c15ce95cc18e65dd55a26f0776e51225ab8584abf80752f44ee6e67c046a10e37360e196fede0fe1038b5d2b6d1243d8a5a6a5b8168deeb0204172cd553ff26861d5187dd0b1848a192f7efc1e73453ba348e7f788f76449696fba56f674bf9d59818f58251325a4c5f10aa2812544c2fc806a14b370b9c446abf86adc2c98dd83ece888a78a8ec7407895cdd33d8cea1b9cae92e7f9f4e8fec81232064bb7ad8c37f6258d6dfd0a760ea4f4a695d734fb841b760789b1ad3c8e7934e5b36cca5bdd53dfacd927a3abad36fd7122722d0c614e4d282b711281a1ea444275157265c6b7714f6276876c5d34c8ff3ee5243f800eef3a1132cd46067b39caffaea48409536fdf4b09acc148472185d6ce77904be2a7f25e24f500527b43beb0f0efa1a4bfacc3c92bfc63a8b3f9c06759b2fca2297b65984dfd4ea47c62db8a08395a99193686375e2f4ab81257828e1069e95f4fa12261ae6dfe55896bf1c4321eb401a6945c98e234b312fddbc527e367ec353fa9facefaa4af46d8d4eb4376dcb97dbb74f90efdac7656938555eb49b47ee78eb81456501ca11d6df07c29f19acf71c75d9868d3f6a346642aee4d1701963eefec5ca446370d11d7eccdc098220779e359418cde4527a0115c1b0b9d3d22800da87bca60184d04a21ca40015b01a21813115420377200e3284805600befbbf0506e61c9408ecac7873d75c36d222463fed21a0935694e159c31293b6adac5e28375b6e8d8f8ddfdd317467251da698b8429c019584e7e1e3c7b62b590d1ef9396658ea5ce3080697b2d0352da18366454938e8e7b6967489d75e70628bf7e02cc134956693a4e575156549ba2d2607108bb34fe78186fe4723941d11132a799e7b6a6e3042dbd6070a80ee9d048e7ddaf19ac4bccc37984909e4801772b7cd1491def5bbbe905e4424bd8e6bcc19a2d7e7cedb793d75efdf173b0b17ab4944fd7cd7143fb786b67a3d1cf298177c0cb21e82c95fd0ed039786c5240eb9f2b504e5262eac612f9872fd781eab41004a72efe87ea9dd45fdc17085569afdae8fa4fdd1cecb5e8685b544831171aa89cdfe478ecf517f6e464fde1987cb019fa3ef4e83f6a9909f7f879723085aea16a374a2f0ffac47c5980711b12f8676fea2e752ae33252f626df3419e7e358a62054335d447329bc43860836af0f8b7154d2c5dc0ad05d2af46092d0959208cdb6d5bd24554fb94bc2a9dc4960d70bdd673d6e03d6d1d4964735fec078158822b7cfe44e99ff5e8249854b11a047c18971a49cce6b061069b02de621dd49060e9d8ef2749dfbc1a3d10ae775dc7d9ace45612950fff995d29b26de8c6bf1196d4bb52e9126201d4878155131f45d15c2d58207387d6fa28ab1772a5aed866f4bb46bc1f16894589191d423379b27b37a5ab4f389a49a72f728264c92eefd8c04afa85e8d1ceca4eebd7a1664b48ba68ae99cf01ad4b861cc533b83bf6d4d679bf2e113030fb2be0079832fcd115a8324bd1a7fc6a9b45723520371f3595b21c95c067040465a69e7387bf96265d710d6cdb4e089e35add86284b09d46b6f3a5d4f7c7aca86ec6913dac00b17b00975ad8b34c07a2deba83bd630542f280b22d768e9fcf7c2a4a3a8b86da35da3e3836a0b71281fb687de0e6abb54440b77b599e58f4eb163433985b5543dc9dd784d428a667a5787a3f0a11c931011e137c607dc3fa9f04ad95f6279ba63957cd576add37bb27cc52c0c127e25f7ad67ea4db2bd43fa52ac3582e159d726c0d432201ddee8e36eee44a53ffac797a95d683a9b42488f2c1896a773af7aed21c287b678045a99f16f724b3dcbbed1ea075726b40069a31a8bccf178e12cdb11dc3aa47f494ec00015095e3b0c586b79c46f0ad7ce1dc362f518d8ec4c628270417c565b6d3f996acb7fbfad6f81739681280f7d3f2e1ab93fad83c74e070dc4e099c6db654e9a0f7811ffbac96e853990481c833092b788cc624b0ecc0557a529b771573f664216a4462a5af7e7fe9f904ea42112e75f4fbab958a2439ae0b624141d1eb5a4e5cee7a38934fc4b9483c8a1adbe2bb51933a21adc42b1b0245cb42825fb5c6000574f7d0f86d41695d05aec3f6308fbd3b3de47f17e23446f2914cb83c462437a373c8522be3422a96532bb254e3fb80dc74cfa5f5af7075db85e8868f85b72e5a9c114e8bcc5af3d9680992312a0cb90fef5e29c0faa58fc72c973c56e8e24169171399cee3359587e7ca71a225d0932131587174f4419ad995d433e24abb8b156eeb38de9515448ca6a820aa9beca337b53cd666b6503e5b01b08925dae3d91ed9f878895ec6097885c2e795acb11913d93a80ad2ac4e2fa2a3ca209197db4887a4909664feddd79f97454ed22c4a02d9ce0181c4d466acb828b794773819e80f5837f6fb957202ab6410559a32a97643e40b927981b7578af8f4799f19178353ed0a3b41067743e46ce76ce3befb6bee86c7d80f32595c76e7ea33d4ec87d8b19c6fa9b1a2d3f69858db9490e2400ccb71d7fa66cff7c1e669711abb1bdfde74c14fac9d04a126caf9bb5ab5a84110d5ae16007d46b15fcdb46c0046a1cd50048dbed5effe502b5858fce71fb8d55686e6e59ae21f0477f687e6f33a4df7e6805a1e4176049bc7f297544ea8aa4915b5a6730e8b2c3b2d200ff0b2054baa6d26cb46cf87ddae15aaab8cadd5c1e2d835adc7c0fcd81e42a6a72698d10d889395e4d6deba38a0bc77ff9442122033e0e247bfdb225b825f2e1891dc57b958e57a83b61083da7d1829d235e5983cdb253ae86b32bc4998c9b00a664e471163d80cd352c8066528ff34c1943a4a07322bc8176b3a9946988d3f494fe5769b9d97ebb447a4b5f60ca80073ddb6e324b8fc73c959131f1b5823bfbb85c27c4ec7a25e4f846b7e09afc532386c77ef36a5ec108e9a999c0c768acb0b653be3451f989dc2b83e0dff812bb86fcdd4050be19bf70b5ea9553e10b134f642f1b6ef2fc1ef0aae8dd16782ccec29588fb37b4fcc3c58b6ca06a948dcd88198ded0ad67cb45410e06554f9856e51880f1911bf3abe0c4c27663c7f8480754587990f23e01ff25920c8996177d652a2b8900a8c28d61f7ec89caadbd843d1ba7792b878a7dd119ecf37845ec9267988c0f3947af2ff6e118355ec3aa62bf6878c5bb41015b3491e361c151fe2bd4ba6162b93872f4cbacc439507509a418f1fd05a9aa2e77d5fecab00554874638061349471f2a0b9bf4058dadf5fdc8aa236e62641a90c2e5ee315c377f9f52d83811a97721bda5ea6a326d397cdbd17be3a81e4371ab8e59dcadbbc9ac94da1c50e4b605d5431338ce34ed9aefe851cf15f8e029c702dc1ba355f5deb0068dba91eb2c3054b42ded2ac2ba15bdb3baa42259ee1cc50844f020022deb1c72c3e7233dae06c19eb4dc0623c3b9fc9b05e6c4cb1f4cdaa33bfd033fd46904275c5bb873064f6cee7a422bc8569699f39adb506341c6f0fee328f35d9a966e9320e4ecdecb3045ad2ae246714b103951e55031a610bd89be241bd8921cec4307d29da4e6e03e89087a28d7af8a104ec1c0795db59ed657c459ad73a005ef9759977a213b95ccf20959895148d969c988825a75e0da30e990573797d1a16adbc6372ba1ea149dd10078a1cf817db91b32639e9b7e4e0d3d8080818c1dc44ac37572aa5308ebbbb9f804c85136290c71bbb7c17123bd4e8c8922294f4a664ab15241ca9dbc1fb0e06850c7d4208f48d1b3b3baef8bc2a6cab91ee60a7a8e9424968532d1af40e6c872afcc7ab75fc08e27784f13dd4f729502566a138a723137cf026ccf275cbd4c05bd7f5ec14e24ea7fc0679e5acaa1d7b01a783325b9b1c5cdc12e30045a1c4a8b5328376b252d93c700544bf93c224d4a29661e074e05b80c997ccc3f869b27287a575ff300205abf720dda05442179b15cc62f4c1e7099b664b095743ac5d4e0953298ff7526950c1a3c728750fb93a77abf94e66defd6d214ae0bdb7a0fd7085bfb850bee5407f3c9dc1a973cd8a0607edc5e042939c59c49009bd84e2e5886427c7b26864e1e51e53b7a2be111be3855370a067c22f7a65af10c5c7307db899944755676ea0fc52a3511c8c302bf6c2342369bef5b265b11fec35b850233673cd70a0491b91a777a3ef3d634db61532158695964da4958c9b01b66e08b0dd44eb26c744535939c9865445c80b2f6421efe5d75299afd016c8bc60aa1783bfc0a356ac17477b2a85da4622d3cbbd496feb5089a7ec7b81db171f97277dc24ba4fd3fc464d603c1f49ec032d08e742accd7542671d5914c163af8208d1aabc614d264623ee8ca4c44359921a77f9ba92928d607815b8c6461f983db426d1d0616b5b333ae1dcd392977ecf181d5258d5550d4b6b39bfdf14596b19bb7b6d77283fcae385eb5f1e2363cd66987f2774e6a3daa64230328d1a8ad6a8accc6095110dc05d4a52b4cf7d8d6aa7e849c51ba043e0a823f57295f66caf769555c3e24df49850f388912941b94648012d5be687e576d3f5bb586c56654f748b48b26195e3f52f18088fb0beb82affb87d7aa0df53fa49ca086edaa16b4614b543d3d6652bfec05f654725d0b9124c03d278efbee4e6ecb80875e511a58ecdfd7128ce61744963c6e8f07ac783cea320dadf749066dbcc391fac9a9bdb651ff26838c9747b7cd4876ee717610ee7865ffb4f6cc853bbb5f6db5fc7f0b89d4af15500f2db06518de6939a10af925da60cd3b235f128bd1aab5e070d1b7643cc7e2b885be673d3c39ef359c6bac70c3104a3b5f03f3121537c78fd7a8aa6a4cb3fa77af704301b0c87f2fa5224f87711772e62e2e9747e52b7edbed1d8849e03facdde91592090ba9216032cb8aa12f76621d24bcbe42f40247e91562ede15ca60e0e73cf36e34eeec7d0b972db486382914e00c06b540a96a4a1a15754213f8e9aeafbf78ae17fca807ffbad584ce691ddd116db74608a126b4b2bb7b07280925093009878f64c89faf29e986c70870a36f874d293c75f83515bdc9e1e9000e7f0570780e85c363130e2fc4e4f0480270f82543874761c9e189821c8270d8a1cf811c5e861f87aff201d209494a9492f0806489c861cf7d1c7af097971e58f038fcfce8613db487df083f720880f31c3ea6913f5fbe3efc76aee3d0bbcee12597095485c69c1c5ecbd20978890471e4a60568a5c75a784e6e5280bec94d50b4d2634f7e23372140b372d301b4d2632a7c959b0aa0b9dc64a4951e23facd4d457a2be0262ce040501e04010f3ac08914e0468c7e24173d96b50d4977412731403bb9f4177b082edc85ddc48501e80fc8052231fd0de0db85105cb811222e0429e0420b88b5a0939c72dc8fc845d82100fdedc75010daa1a9e0a024a7adbf1d990206a03f146e08f73bbef7d69f0917da424f7242417fae8b1082fe727e11427892d30efded0bc004fd091d85c75c3872895c2341416e420b408f692a5c0b26c472dc480b381ed482b621c9e94f720aa23f13de447fb10fe024402181059d9400edd4d2dffd072c18394c53b92c10799213131602a03f120ec402d01116989c080b1f0480c883b0a0bf20076ae1421040c2139de484a33fd881682af73bf2c308d049582204c87fe0273f9ee404a43f58d6c2d07f682a9789fe7edc25b0030101e92fe84234150e48c8939c86f4d7fa124d05ffd0df8d7fa0a9e01f1f007d48c8979c04168280e80ff600682af7c87d0284c89320fa0b3a094f8290f0242798fe700ee4c9cd8d3c810179921311fd053913fd91f0007cc80186aca0930ca09db0feeec7e33e3495bbc29127399db082fe863c4853e1562012e463051efae37e64051e4a8e9cc80afa23f2a027ff29c010157492938dfe4ef85ed74712fd057d08921f1f9a0a7ee9cfc77b682af8f524a720fd21c99ef4d0542ea7bf1e370992070505fd04fde027e9a1bfd579f4e0f1242724fa0b7a929f23f990158c9c707d5c252a10d19f910f5181c89027399da03f9b2b51c187fe587fa9e0e3f524a723fa23f213f437e44a5e82510929e8240268274d7ff73a9acadd4d295c9e148ca460444b21058d3ba2a96429e8efc88da8f022994ab69b8a4a20d29fbe0e4de5f2e828c11629c2a3a960ad3f9eebd054b036a2bf9aa97075ae692ad7d61bd1543823468a1829f224271d3afabbb73a749ee454f567e4b5c8ed4bd054b2dd9402bd3c97a3c21dd11f7d099a0a77a4842739a9f4a73a47c4a33fee5a53c1db8624271efd24a7a9bf239ffa2be1f442b3c90004800293000c2d394149122426e4111ecb247c67a00b65213f9247780999841bc9402f92859c481ee14332095af2205ff0411948c3ff64215a02215ff041f2085a2ac917bc0879e72164efb00c0290ec13634efe23effc83ecdd47ee79650f64ccc97be49df3c8de79320074ce5566cc894e72ba863bb47422efe826a2eb648f4877398ebcdd9553cfc9d97172f7d46fe48c95b7e39cfa2a6757e50ecba6a5969466cab4dc225fd066bb021ab648b36bce48a0c4022936cd330b0d5034d833db1d408006061269861b2b0390fa059b1095741312923f14683bec0bbab7d6c3251f30952f68067fd08c9671eade9b5f73f6744d3f037fd04c14970b6321f9032bb53686242fc8577dde00a65f50845d1152cceaba6378010afc052dc52520848290148989813c3546f8bdb0a504a955fe1092af0d52f943deec801ffb87760ff5845b9b457bcacc9eca1e94e5a0fa2053b21d81b9a98439828881bfd4a68f6bb6fc96af6ce71e10d1ec18e26e9ac0b65dca6ddb9036ddb659bfd42715e035e814358928d6180a5f767d9124b33f986606f8bb512aa828a5690618459f484a67a500d296b3d62921851b9452eb5c00471d0586cfb2419ecf428966d494d97996edc44bc9a4e4de235fe9710f7a1ceeec42d2831ee7b81e3d1ef34e8f2cdbe9d123fb0ef723eea8c175e7316731c6b8f3e57ce736eeec1c764a72ce390046edcf4a972d25e731ea2931c61863ddf9dc3bfaab42b9d89d9093f3c5ed8212235f59b7f32c6f3b99ae54c897dca94b70c8ce65a6eb17f9c2227f2a14cf79e83800bcebe438941cbeea3bba3e411f8946be7ee0b2736c789e9d9d9d9d9d9d9dd73452e0fdd5331b03816f7cdffa3bfeb9f60ede3bf9dfdd3bfad3baaa4103f757d15435f2e78cfc992ad04e908a334e789eebb8771c5dec7b2ef00936fa3b9975a83594af9defe84a867cc119a94a3fc121fa3baf3c348ffe5c00d03af487f74a477f7773ab1c38f42757aae3ad755dca75eb82bf8894f445fe7c53693fc91ff8e40509b67c85923fdff2144afee0b83c15237f762e4fa326508fcb53a50924cbdcdcb8f987f78d9b9bdfc854e97a87fe5cad7f5309c7639764e7b0a34ad04747850257285d01b0843f59e6c975f91e19caec3b5996c1b98efe2ece3dfd619ce728f345de8bb1cbf5bf5e30d817b423ec7068fde5dcba32dc391fc5c91fbd915a608837b2120c9407d7a78f93576518625797b8fdd5a5a56f9a994a53c96acda30bfea81255923f4b6ab63c851b045ac86c18bb376960798bc42375aec02f36ba2ecd6a96d5d71398db10ca026178d8c00221d8df6f012b78883ca899b7c0123d7c07353c3019ac70c8384f63e424a464245314d04d0c7e8b2d180c16020c0683c160416021c0603098bc71ef4ddd7befbd5ca4f04e209b9818f8a548908bb1fcf9512395d3470a31126675030c03fd91baf7a6eebdf75eeea6eebdf7b2388ec25b44ead01d1e3e71fe7407f2f011a2037de25d96c3ab584b1583e7689c18771004304c1783d3255f31062790168313281583f7d4c01d776f90345832cd73624ccdb4ffba344e182c082c04181c026130d85dd96b56579140aceaa81d63d448afb592dea803d35257e75e1daf6b5ecccad5f8aaf47256522ee3a0bea01fb0204499e783abf38ce7d2ecf5c5f3ea51af65b97368b7f66a2909fba0c72bfbd537bbbeb4529adddfab8704cdd4eba5c15ef5be226dddea7a65daccd125a95aa5b5d2d77dbd347d656e9787069db2fe7eb384d43f1d7c09947d2645ed6618a31986d938a29860a8992a023c85fd9285a065032d6e9cc0dfcd1004db4b93e1533ed205914bc041261ba1b9c88aa399881accd13c643765d764d37da6f458762d27ddf058a6951ebbba6a164733097bc7061996c803f4d1b265cb1c76803ef2ad2a7006caf121ff08c1e1c6bc82ec1c8ee61176d0c01fcd22d01c420e8e66187ef2389a4168858066203b8dcf179b067f540747f30f56991d1ccd1f442e5aced1ece30648981182b504d30d24da28022bd910a1b45a228a85c40d2a2598f0129d1250ab2d565880e34246b505aa025b5354b7050515d09ad0705bc4e021c504d4b685064b978bb6a58d1e889a404a82071fca1041c46529892474205ac24c1250e84094849a24ae50524a02044a444c984922cc0f444d5c72d0783f2c1de3964b2703d2019e293c2df98a3aa49981926ad75a5b2e18b561176994f100e9062f2c69d6e841039cddd0a305b8ab800722c02c0cf808036b4df4e0a00a2270b621183442e0031a5bd88059649090907e40a38c1eec5cdab08b36c6ecd71768a4410234d668c9c10e5128a17936c4062184104208218410420821841042324284f1a201df15f830836dc07c8044163d5650851558db100a8926a640c28331f0dd100a09227ac4e06c43282480f0629352ca29a58c5766526ee84329fda69c73d25aa994724a29ad94126fb9240a4a4965a694ca2ba794320535958b0a0c2184104269ed9c41a6a5f605a370a296ffece79cf39bb79452fa694b27a573ce7fd99cb37ed63ae7dc2a47d3e06c2aa7def47b0d01ebfee69c733e421ff8cd39a79caf5965a5130758d21aebbdf495c4a5524e6ae9cd6c5d73e9a51ad2bbe6d24b335bcfd09bd9bac6d6ec525bb333d5da9aada1d7d635975e7ae60cbd6b2ebd34b3f50cbd99ad6b6e5cc9ae94935abc532f6c5a6d16630d5b461abbd45a6d4699905e88823489b42012e88b16a01fb01e286f8f84e5095165d2c2c46491b0543da318242c99ec329753a9a65f28e87649ee6f778284d9ddeea2180245a6881441905ad3bd1913d2182631910b8d484abc540ba1cfbc4d9a8b71b4914b47648184d2768408761602117e80f6c7ed6a64d7236e30220c1641881140ec29718c1016f4579669b892704a08e12319f8c988a495b5d6c2664f7cace2880d5ce18123a8382266add2b6d65a6b6d50d06b7f2da62c76e02f36e5590113103d6bf0878384d9456c20db6a8004f3bb94527a420c3050031a41d040882e4a88c97410812f6c43c51a5bdbf2fc8837ec2f4811f8655b11ec0f8eb19ab59dfd6177aca5d6c62d2dd8918a6db394d9568b6d7fb1eb2f180cb67d90d01222226eb0ed9f403962db4779c1896d2f0306ae40d262859219db42282268c0a4650c9722b874b9b22d84ca0017f6622f62b6b50fb2d65a6b7b64e1c0bd9d076012a679f1210363260566071ba6cbf562881a0629c352460e148bc572831fe6089e6a96a40bc826504f7488206213305db238819b8c008d7429fd8075288049d8186a18e1011835baa8a106163d30c0aa0dc1a8d1850f23f0b6211835c078f980ef8660d4308303141217c8d9100c1b5b94b0fd6bc5bb6950a2440d0b54755cc76198109109a2cc182595627e3b929b3eca5e77b6b4cdf96d9bd56e75d65a6bfdab6e72665de04fa7428922034483f47a990934ed0f50505faa8e1ff0847042a8a5c45077f698c2b4f6846b179a98ce16a4b2473e35c67ce268ac8184a54b9d99cd7296d15c245f2ca4745c8a4af0009882aa81e16397c472306315a0062ffa090cb56f179217f38040ad0c7fec06c47d7e3e19c357e5bed12f587be27927962e775838252ff504f89387eae2cb9697f67572437461c134a286e002239a2070902a03268d96c833bb21b9ab974a5d0e490b16c102a1845862df6cb92447d8f2d5a60ea14fe5eeb32cd24aebebddb093ef5e9044c70f986e4be40fd556432d44f312263045a26b75419f3a035c796409f3f5d556faeb512d1443227bea5363e827b00b0ef194c46d2b19ae0e6838d82e1b0eb5d65a71b85d34e104c5e102693629a5843e74d2092f6574c176e50f84b0a0bf30b51267905286b1d18927d0937618a38f59529b669a3e92f747f38b503bc618e352f67b6917a3d0de69aa539a462c942e118d80116ac9eca187b14d6608a554c9cec84a4ce84911282fd4280c0485444949f7d99388b6db0c6348287dead2141b78098cc92529ef0b6212c6e6375967ada78f59c4e244c6a6ebb387c296b4826c7d1ae36a4d2a8416586ed8794eece78de636bfcd6f9e91fc7699394f49dc5edc72c3edc566f6e2535e6ccb5ebcd985a49682cd9eec3113ddec37cb32884642b1411e2fc2a889ea679452a289346c90e766cf3aedc5ec475ed41e91ea29c098eadd8faa38191d6557fdc8a9283beabaa77495edddab7057dd4a0cc660ec1ec6b6d82591303c8049dc148624f644a90bc978b3176b517ee23951a9b25ffb5de9a3ecde8bda48fbf58c52d9bbd76d4bcdab5c5a50c6068e422505c1a691524a29ad144a144a29a5dacca44501a5748b0d0689b4a1b673d8c01149860914af1ad883da73729f7ad17d4a577182af72e474a43a3db2bf87faa83ef5953e9a3b5be0d5aba84e6f57ba4ad59e13d5e9bd4d17a9b4b73dd1d7a752afaa2b94fad41ebc7609460536f8f0840e19f822765f349f7dce5bed44b347fb4b0d342640230c24ccd02296a9741558ff647595a96151474e45a9cf1fd17b2d2a0663993e4a69cf89fdbd077591fd7d51fdfc07d33ebb14622c3b9c324e95071f4351f6d4bbc77db3077fe4b4fd28f5ec474e9d2ea2bf3fca9efacc1ed41ea73df84d17ddd31f51ed412d03d2ecd17428616ff336ed39493dbb51ea993efa117dea463706b5a6ec4252bbd7525a5cb249d4ad84edda29942812804bb5ca5a291492b5d6babdd65a5fb3a7ea084d69eb6b985a19207f3eefcbf142945a6bbd078740b873c021f465e8195bd40287c82a1026f100a39658041c120f213c03a11816ece18bc0a86311d0876660533172cc025f458cb1650c228b0cb6bc05e08b7e0661c6968f715f1d97a00fb5400db67c84102ecdb02712d22c6385495a3a2595b27e61938254920542e3820637a8ae6c61c5997a450d2ee98cae0733d6e4d0829a43adb5561dd81c542c11a8ba484d81820c18d134031bd460072796a05e10517be0806a731b4205f1441a323d5833704825692b488091c314293893431850c82eaeb85c9c01020b986146cd813e08a61fa99b1d90b698316306f26c6e674ebeb07cb9cac03c32e6e00d4d087da2a69312d9aefc81504a2965bdf9fbb561841d84a2505c00cdea05a00b019248427290fcf9a07c8970f856ecf0ae7d781da1c3bf051e067c012f177e2800f6c307d97148857cc18770f822120eff04e8f02c08393c94270c48c0a144913f5f130b4f1d3621e0d961910f3924f2a0c320ff6152618b017e806f874d2b3c75f83515e0d9e157a484c34732f2e723a2e5927cc11b397cfc42fe7c418a1c3611bd0bb596912f49867cd517409f7a9d31f017a3caecfa28a64c7d952f1813c9c817c021364731d58ab59672d9edb35b2dc3feee69d7823e57c7a5ae49a6a5dcdb674357dbfbec6aef664deceff1afc6f28573fce14f71ed7b3b2538f8114b37021438fb1797602a95c588c56adae52e6ec121705b6db16427e4ec387f566f5b8ae3ba221ccfa1ab38d9c3fd45d9df1457a577ca989a65bc21fb794d4a8fe178130e3d0395426892147243adec35529ccd53cde56c9e69e4eb862ad51b7942654185c6d96dfbc23d51a8ce091597d516ccc4d26283e50610ada51b1e709472925c9ccd1509c71a39d4786974bcec50a1a3cb0e343f93cd6832005086e70b1e647a8cf120ea25a6078b0f9ca05c7e9cf1e16c9e6640d802630a418b085846e06ca64004e16c9e68e4ebe69b10cee6f9245f37f7d10dd93cfb06c4470f10204080bc80dcb46ed8701b10203e3e5aea0201726f06044896d90a8290114408418810988f8f8f90880195a6bfc9ad9c314b6391af8a5bae1db18c9005c3583d527d646aed2cbb37cb62a09bde52aca97c6dd9cd0f80adadfa223457f4aac8d55b6a7596c5b8713b460d73b4e02f46c52f7ef922ab8f59764fafbecf3ebba1d68e5f84dd907d2a73406b47fd4dd9574f69ed98e9f845fe7cb41b8a5fa895765a0a63a6fa64d0da3bfad1fd4531bbe6c8f214d8bef1cb06a486fa4a757d9623d1ce6e65c36e5edd85eae805880f187f3a9773bd76762ecb2df9aacf9104cefe71bb56224bb2f80241807b491623803e707f5b48de7b513856ca6eefe918357beaeb925e8a51f255731481618cd5323beacfb5a18f1af88b513baa4645b5a40757789c00771b42618145191f5c808a170a7085c203344d6460c134051630b0580a8389ef2d9376564a2b9d954a2979a49411afe6953f334a29a994f272369093569b5ff313c279b3219c509b32c29b26ab66361a279a29291a0821a438986dc468a6d2362a3d234633319aa9b48d4acfa06a6cb322118295ceee55ede479e6b287e59bbb2648d7b8eebd37621a35b95811850ffb834f104a0c0a9ca298d00006d03cc1c36cf292e68a2536231ac8ac5146cd0d67ac985cae5043857ca0a905300853060c282618b7032ce056adbde280167b75ba5a750087bdbaaa4bb282647457acb1bb735d920e7eb9820a1d5a3069a82b7088612079e1e588e8851559d02ff78c0d60993744696ddc0d285dc08b316b54c181304e40c5ec54625b0e6cb16d6a5b6badad628b12363de5a1034f154d6c7b2d151cb0d65a6be9611535dcab04864958e67401cac53e09319d18a14622c91eb8bf8ba948c1929323a27898c1131531d062861717164a2a8049188f1164a0870bae1b82d98193193b90c247961d6851811d98000736c2e031c271411457ccac59139b37aab7d393a79e8c41d86403c71c5faf18c5e002671b424df18507434031850a5c504a0821a432d628bb9871ce99d93a29a5349b76d639699c73427875d8a69c137eca0c3999e79748e78c311ecacb28c116e99c93b26084c1e61ad8a54c770a241ec86092228d1cc6589a820725319ea600a20230589ac2081ec6809ac2e90632a26a193268c0e4400d17186f08260d1df6771cd2c08018692cb1031ce016b918bb18a59c52c6edf5028128683e79f5f888446e76fd5dd3734a2112ba604bf92412612182208fef16391a6f2bc7c2b3a8c50d053b5c601965193c378c0c782106195e908f686478216628398a9297d4a7f6b844b36060cfc33875f001dfc727e910e2834f332249b821d004726965308d724e55d376d919c9d8762dc7a739b9cc1c9880f69cb71b45b24408004a48d769bba9018ea773de9c118b04c9d79c954a092f9c3d70aad9828a405953546ed5d4da2a9b3ec218dbb2d67cec7a043cb6ba2b48fe84005fa99ccaf52134c15be60440583369a780ba014e6d0825451a3e8690e28c1460ec6e432829a2aeb665f4a9d4a65d0c8120dc5259769ba57eb56b7a48ee2f6e6fbb67543f9f42d5d333aaa74fa16a7b6f964d2b76862967187b6b96e1cc663c5b4afc7876566bfd3785a7d6ecf6fe8b99f6ae1e82f2f54de1d936d6db5cab151ba70e5bab556374b58838216a2bf5dda44024983e9e9eba4610a3f6b25bed65ba08ce9e59290f4f4f4f7018f18293524a338dab9e93ca182319b576a952d62e55c71438be4a69350c744f3d05b6e52c82ca1b1b3480e1c3e0cb426b0d1c2fa7f0ec18e3149e3dcf13a714f16903f7e9be60eb42afb843b463522960e9b63293598aabf976d92929678c12069b3adff13cf2e7b6648fdc1c2e93590d60f9ec35f37cc600d77f98eeda35a148481084792a9b64b2ce6d730432ae7602d011bee6ab6c4277f6fbabb1968f99eeb867e4991ab73c805fd76d60082505d37e9a3fd58b33a4e8210db659e3c504c6673e4872c1fefec396367cd0805b5b6489c2cb52144cecef4544e103de36848a62a9e5a262a622a5f44a09e79c73ce39e79494d26cd23969add44e29e5945266f2be6094c6ef7b5dae9b35b0f8e037ac5f26ad36bba9596bb5f225ef8f311827ca7fb5555fabdef5663745b53937eebe6ed00666760c7233b17bea267bfaddd45aebeb9ba7347f5987ba5258bbd93247a98b7694d65af5a5db96c6255f50c5adba24f05072f3aa99bfc9755be0c8d9dca8ad16a594bb9956df0843d549c9cd0be16d3229dc340a21b4787230c0f1355575f637e7cce8cdaebdf207de4a7180a5a473ceade3b0d8b009f8e5527265e008e19cab2cd35524105b21b1c6524b2b0dd4d635965a5a69a0b6ae5943abad960c5bd7d0325450c69a32ce9401633c53c6cc4119136a4d171c37395a5bb5569bdda036752e417e7435501d2c9ab05bb2cbe2a214a4c496ff766cf81d48246e8920c821104875a82ec378263b60e7248ba57494d9338613714b4c8a4848a94deb5210c5002865b48debd2f2a203c5a170bb255b077b71af1712a15be7352d15bb244d97e7aa150eee82b9588129dcb0eebee068c375e1c2850b17c8850b9c40383155c76d5a54266f78c117632c9960192424a41b9aa0816b820ce73406eb092b5450a4e0c6179dc4b277ec8fdbdd6119bb3bedba64815b74832203504f8800a7f9b89db556e044164e423441868b04504d54e00699a14698113c098162424c1c038a1928818118bc98c0024b21934503496819620359d81c3c80a4451f3a5cd26c7afabb04984d8f97b0c1a63c6c8051118c0ecfa64d6b36e5e2b4e95d9fafcd8383314a9c804c53139b5eea005320586bd3245ab029941248b82e165603aee86a0527581981034427040e2f749cb1c9a085458e0dba2daea441a3b855dc242db57ad84a80a30dac04ce96ae0d17746d58e1eac1b526cbb6869a6e0d3170769093a56bc30cbb83141b2758ad41828b46b5668bba0136d4746bba986bd4c099a00d1b562658b3858574c5f502098acc0b1acae03594e8aee83ac688d41536c4d8aea051c65e69b9726c08e5010f4499800607f07737f528de7e105949795c3b50603829fe04d20e537fb2e93fd134edddbfdea5bdab6f2c51460aae6042aae2a4e9abedb38bb9632e45027be8efdd6c96dd669aa76a29b019b5411e3c81644c27661ef9caced26480716c18e80e627d09910bbf68d3de3dbd8c3ff29c5c6de419d9cf6b8fba48fb165347927b11eb9cb6124be922ed5d113ed71dffeaa26df39cb05e5fc47ad5de2dd2eeddec292df0b32cfbcd32d6b58d9b167792ce98bd5eead888754d7b29dd2435fe91bdda357d548fb5778db6b3b41f79f746dab973fa086bef6a8f88c5fa1136d2479c3ed2ced2de2d621deb2a4ef7ea22acd266cabbe7aef69cb058f89c3eda8eb7eddebd11fe9177b551f7edddb7145665a20c65f664d7f20bac55f62ecb328c6941b3278b58e42b68674b4c536a4d1be4d956abcbaf3a1b1b9bd56ae5c47b77239823078e635d25e7385ec57b8e5b8949d8c91f79efa0777ca39cab728e737ed4ddf3debdc87b77a98b72367c2bab17b5be7afceac6b1ae62f31bafd2bd752b31a9d25558c7afb2baca4a0c77c72fea8e2f8f6daed255726ef32adebb5b896115cc717c231c57e9a39ce3c8398e1f79cf7118935d124f7b91ebaa17e9b46ef491cd6f9ca5bbb7eea55e74f3d58bd4c70c7a4ca27dbcbf70cb6faae7dc087f471fe91c3f47e7f847aeab72b2c77de730e6658fd39e13d7736ea4f31d9de7e8fc4875d7a63d4d3b715d7503b8b4a7dd4aec06d0d19e86bde39cbbeed2559c8a5cf77415a873e81ced11b9726238349e3d32277b9a2b7b5afcedbf6718cb89da8b5bd7dd888573d63b9cb37e74e369ddcdbb1be1b08ef38e759c1fad7e93d24e6ebeba016eb497ba95d50d80a359bfd15560dd9c1e91cdbda2ee30c624de7eebb2973a8cd9642f05e4053d4ef51f8c2a923d267adb2cc53ebf90a1e46c639927ba70810e9e32ed31a1b7b75a4ad534c6b2a2c9951a2222e882572f3902cf675789dcf544f2e7a2205ff0dbf69b67fe22929ddbf6cd6e5151db3fd8e6dab66ddb52598bb0bd7d9e955d13c8357bb61c047decef9c73cb36752d9522ca02a77e9ba4e007a1b8772b9b1cb77803db1cdf86e3baaee362ace3ce3a8c6d94734d208eebba23d6b9c318c775b7d968c7499b89595fddc8c6e62b7de4347fb4ba11be8d66d91cff88f5d5eaac17adcefad445f8361792b24b01c66e646f7e35e75cadceba951b87bf916d329c3dacbca93a4e952f9e3d54c70af0fcf743bfbbc10e4ac2a8e9a106259a6a30c40e492d08030653982fa830636fb03a2d68c286304a6394400aab0318558c1b5610b5c54c0d586ae982dbc2cb952bb6060f2805f50086085090051a25184115b11578e0863ddf72cdc3a0b2508305582e13e6e2ea722faf27a8a079844e912ff839e18c9762ec72fd305850107d3a3229a5b4a5c33329a57386286f1adbd4b822f88b4bccc7bcbe809171e67e3a1066308319dc6aadb5d65a2d7de40e63174e7f3344cd3066b395da0f8aa182c6d7b64f368535b395521d635652334869b3c43441676064bcbef818971809effa8179a0b4caa0517391b09274c5a5a02818547c8a5d2297c804d1ecbab4e76193d8658628a6e8c40c63b643910f0a92d0ce9066cf25f055efc248544c970be309e565cf29e1ebc99e8f51863d9fb62836388120661d679bbc719f6bab609324ffa26cd5b56c73b86995feb46df3450922e7375025e0b259cff1b2332a809be7bce626dc59df62d62eb3bd0e13e09bef759800cfdb6b9afeac703902d31b8ad175d80920eaefe611a05b4a8edbfbcb62e521eddc6db04d86d0475bb1ec6a65594aa46c36e3d8617baa57aced3677dc37eedd6137b45dcbdf0c43da59f66a18ae24d25c71336c284aa4ac0eb7262db4812f6c7889a4bfbb39dd1d4b24782eaf20d02449ebddeaac434fc926a5dedac36f96bd4dc45ad4f4070314a41d03dd10b0f138373404ac705e8e81f5ce1b92c27dbbd552585f5d062dcb2d7f43aac3a8bf21d576a1b9cdb0a36c2599d35f448236f90171d35f44da753b772119f12a07cd9774c1107713d5211c426f1f5065775f6596a6b79a9eb03a2b4b4969ebc5572fde3ea5691886b6738f7a6875d6ed3f2b48dbea08d06df5d097b6d552bac32ee7782a47a4cdda3547a42de5e639cfa199b09e73d90ddd3ca789eada6dd6f2eab06372f39c9c9c7d31d055f68658bf39eb25c002c505991d332e764d6e76d4526c0452dde0ec7532de2a8abfc16e88fbea36774d589f8da68756d71a2b472fb3dee5cff5c9b0216641c882c75c406d94bbc9ac1bfd459b3f6ce1d6c9707299953f2b4838ee23d2bc4b37c9defde6f84ede6e471638daa7e2eebac76fac5fad752931d0ddfa77e3f0f6563f40eeb8d29fdcab6f5cfea06c2e8a2a43f1b27795cd0b5bbbbd97a1fc91e190b5ba71564b47206e9ae48b9bdbdc856412ee5df6ecf190ea9e3debabcf72df70b657e5d50ae7eeaa5577782e7fac7faa73d7b2c7d24338f7549e6a75f89caf3cd5f16d6eb377e3ddedb79c7c739cdc3ac769f9e639593bce8da6a9f4d0cd3d8ebbea387b9c1e627d75789ce377d95bbd3bf7cd266fc7695d95bfb8556f1d276fbfb1d19f95bd1d6e57e5ef861eb2b9b7fa567a8875acfad665acca71af6e337e97ed6d32ebb01b6261fd5959e91828d7e5edb06312c28e31c429735b1d01b9777400efba430b1c0fe7032c7c96e385663774b3e373e40e33738bdcfe5a0f889b76f837e32ea5303563fc1253293d3f9d9de97ba189e92facdcec4ed8ae6961da94ac54a7dd085d707c2a03c2f12c098eacc304584a03b27fc39de9b8458b7c55fa6d76f84d38eeb5c7b93d0ece715c38872e1d97628775131c1db1e4fc669c692109378e2cc9903d395a96e1e814570bfa581d976aa10ea894ec98a972182a44230000000000d315002018100c09450271300e26b2aae90e14000e7796406c5099cc634990c4300a82206300208600630820840064942aa20301946a70aa9e4126bc9c963159da9b7e6a1782514880c1f32f774369bf5052c700b13e82cb399fa52af277b9f0d0be18b0876bd0d1747de2522fd6b50b1a412694da9fa8f606ba690ea60c289d1859eb9757a711b4702dc182bd32a8bf5bd29f58d408607197163c02efa19be661da82597e4de90c15f52dd204b4dccbb155ba44abc55220889d5250d440e75fd6a27da565ef7305e2b31502c2c19f7d8e10781857526cbfaac8d603e3898e6577258a12a014bf51ec1e95ca69561c00a6ddc5a608be431d301860c8ed0e9787ed2406c2825bd58d10a623630f58985a1801676ad2893ee0aa3da594a1d5b4b63cb02e826708cd6cc5497ba94dd1aca2a9dd5dc3dd3ebba452329d7322174473a262d4a6f510c7818802106581ca7f830da512e18d059778e5591a15aaba37ea057c195b8ab37314dfd9e7993adb4ab593cd51fa3c57d402a5b839d5d9a2492cc4404247883acc4420601484f3c3e32509d7f4d2c15b8db31be32fde779d62291ad12f7c08e24d5c84601ac8688684c6819f30fa0b6392a7619a5db3e8078d97710c0c3f517aaa1510eb405bf551329e288bc2ff9056fa88ca11fb7dab724506fdd8fe764cae53dbd5447e6898da82e3324e87191b76b3fc09ad65d42f271fab29f0b484c439502f24c003fc647a0bcd03911591df42bd02406a38b8924d50c05a00f190840ea00711de30518268952e84556ec3413eb6469482923289a966e568a7dc7aeeefdf159baad3f4b8d5e50bde370db8674310eb77e59379d9a708bb8de482ce0fe90e0eb41e9f366bb18a15b55730320d591aada7180f4708bae3668f6e0678307549de09f455d8c0b6cf12b9aef5a36b5c8e461425e7cbc1261836083b22a328e9ccd70fe11aa5da44b57014ebf535d503372bfe085f122aa26f168e462e048cae005da3d801e6ecdc0fb443e894dad8b204ee41b52f491bf611459364f61598c5ed6f56646f12232159dd37a3f51e093754c77ff125fb62f8a9a21c86073ed636a8306528554bca2a25db1278d603e83e8a7aec0f352028a6792710d15705a2807129821033548d75ec52cbbf0c7ccb466dd056e40db05d28c9066c9710da27c56ab21b26747771cb5fd6ec1d4afd5824a310322a27c516079ad0322ba7f33d30d6d017b8c47e0c635085a7904eef619e2333c063995a1f648d4af8bfed8937aadd61cfc061820cffc6434bb763c34a9469f74464d9b11014c0d82b88f6c3275a18af3fa2b053eccbc81f34f059cf05e5fa10286f6b4eb64fc53d442c55ac87a72a648b153e835fb66d132b61ad1adae757066402db534052afde3751c88106a10cadcb854350d5eb2d0a31d335feffcc303e46f324740124ff816f40f4aa2d945578ddda388c22a4bde6fe2942a09285cfac04877883264e0de93c8f505097a28be9c0ff28e7fc4ac6c8de4b23292e46474a3888090fa88f0a431e962ca8fc4829dff3d90755f0dba504acb0ff256e4643d7c8a090b63591f5d81e4bfd6b04b0041be29c93317113bbcfbb55815384933a3291b2f08297ed41297e88123c8732329ddbfc545915e56a7550fe97e658ced39b28d4099f935b00b0f5e443b20b0a2cc3f68fb1b4e3f42936b35be4836c0877ab9486a0f5081f347c59d72f0940ec17b1deb8107098a7392149972c8dacab1655b33e7f99a6adb094374b432c0d9298a45e82d9906443b380d9063ac1eb9a80363b5814adcbca7232f47d5cc19b98fc726f8ae8f807244683456a59b43994f645e2bd28e0f4ad7926517f646f4998c70d332c7a56300922c1a5e3797e0729fb9d1f8aff46695713a835c773c1451123e07a2a04b04f943c88c9ee0b687c1d6aeef18e71e4a3338505bf8109201099ad46bbf7c2837dda08a6ab02508bf0b3d5a1ae930a8ef2c208a23340ed3ad630e46967a73cb17c45e148f5c1c9a9cf4065f9ec912ac3f9ee6d11830f61eef026e2365957a02f820415dafe6ae30738c188b31204a109a36d95b03b2215fab322183f36f5934ba754137d1b0ef3c4afa1758f90fde37819d434b84c74011bf0d6f5883406a5742946e507d3c0e5bf204f09860bd9d2f2ce7326f982be1383b0d8438443745c9eaf514c7ac95db1d521151327b6c8d50063ba8a5882fc7372186824a45a886b788000e2db420d801a31c8fa1d76bdf45f84ed82478a347920e89bf93e1e4fd84ae03e90aa43c32a7c4da37295fdb19269b69b50c0fd179dfbb1f403f33e297b3bb1df44318c470ba591bb154592d76eef54e5b91e54aca063f1505188fefac26c045bd6d53a82b32c5d48e6995950a0a5161dc71ae261c9772400637b1f6bd1d3a8c2c58516d98523e787c62e072c7f421e206552147ba2a8286f120fc768f8504ddd869b109e1929ce61a2c7315011398dc6b07cf5f9f80647806d0d56fc90fcbd6967940dee1e67a841c703847d26dfc27babc58244805092230346d4b6c81c9086625d49577f793a64fda86db5fabc144d5e47de5513b60eeccdee0159c5786939a7224193acaebdcdb915b3ee50f2c71720b3158c7fd940343018f99931b24577086451b9856323104308868701b0ea87945cba099cb6e789a1fe861cb7a2336cef279581d2e13c1b889714b908074e2028857e04be0ba074e77f7edfc0d4022476e3c2034199af049d206ea9da807521d3741495685d4d77ce4dea8ce1854cfa64592bbce8da72af921d075f4fae73a15beb57742f29773af7c84e298ce4496ff7ad524ad47b96d3d46057b4db5d3de2bdcfae76123ad6456fe4feff92161ec38e7d4374d572448732fdc518acc302e148ce9b98951f47d092036369e59f3264b60ee3423cdba8bd1c846425ba95cbeea80b7e3e296b0badd524bb8dc4152fc7fa8e9f95434e31c54367177a2960930e2259e490e9b3b03298787912c0303d3b43585bd119e2686ab6899081d3b6bfcf5bd4d23a10d760879f7d574848956e50e411c831b2e5e698828b9b6171471dbbcc1f9f03ab5c84d9d5f7760b13797d82e5755b71f7017e7d60118f914b1926e8ef11c59286b602ac20fadb597cd132fc4c40c4594d3b7acc7e809402db5066463e7e5d48c3d8bc678e8519807a0a8bce6ad127a1e24d452d4ca096b373390265b2954b8ccc8d4b974fc361668f8b47580d2ea00c879dc83e700c917592d8b91167bb59981a29817f69b9ee6a806ff97ca8c821180d09468c0106221275b05042773577f7eb8fef0f3fbf7d489b68645de51e027a1a9b1c9ccf2616f613e654ecc0082bc844467a52a42f2c00c1ca99479ca6fc297dc4a235140cf204ed843676cac14cc7e770000d6fdc65404f03142fc37d715e945950341ad1c755fbbbff3702e311cb9450f23aef20dcedde5e52e6f02e4bd2fbe7fb0c6882ae633e0626e0f7838fee265aba10dae4817d1eb425c0d77b1a57846c2cb6c15bc93833a7cc250ee94debe58db9a8c0a6d83a014bac2555eef64801b548eb46f7ba60d2993688d86fa79cabecaa0721be4eb4f521df625cf7fc864c188afe2baafcd7e99e3e17730515795485e99253cb35f7b10075c878086ea5b58931bc33e6260535fcf1cea904697353ee7a66969854768685b721c4c67e97f950891cf6631f34016c8004ffa45ff2561350747fec1604d219e3b26e26de4a9882b55494af9706cad4a88f73e1f9574cfcb85db1e183137ccafa14d378701222c9be12f621639bc9480cdea0707a13208a91ac6b208c9d1f20981a3163c3da617b87db3a526af0625acd3331a73e0960c6110ac8fa81d80baa82b6b5480ca1353523f79f5f314ea0a8334e2814371860230a1ed33d3a98efb10b4a7211e67aa1c5b9908ba1ca54c57c877c42d66992ca5e601bb3ad8c34c9d8305b6554552cf3de2f6f15a1ade069c88f83355cf4a839a04d83c11e395888b6275f71518ff1a0679768233cf483ddb2bb3d3e326e6166defd884c6c16b208ed2eeb989469529213ce01b111826905af023fb7fd6146df1277b309dc28e102203045ce2080d9cd81677fe30b1731997effb4fe988f0b34f96c8920c117e18485cd32eaaa74c1c1f84dbeea2cf5096d66ab9cfde0e65cb24c82554e9165476e9d4b935570cb0adf7fe7c15951bc03c26e12295d8da204220424782647902575b6560e172535669f034f5664e8d9389e9d93f58bfeb290c4b5d39084f924bdb2456a75b7dd6a568be9531f0a69d372011842c20567a6f1ac496c63ae4f9b48bb1d285a412afc67284a350d5bfe18eb049f43268b998e6980155e8f231c49a5bd4e8d4e8aea4b2ea83d252c156b08c973bffc8b4498bc9ab33bd5b0fdd317e160b031bc5753b6950367b082867da2d11a5d34c5355dd642993c54b5feacc3b1448cc72f0ad4df1159ea12335115e7bafb71bb0d76af44c9bedc2070fcbbfb36fcb88ab86684929e1053925736ad2e88011c731b293e0fa73c202fab60adec36dae4cbf0252d6c46ea76cbf8d2f59122ba5c01057595955ae2d9acc87ab821c423460fb5be1034fe9aeec9561adc80d95387d82b0e924c6ac4af58f31a20541537ea762b2fab57422b684ca95204188d823d2f7c9c900e0ea445863343847e43520938bab887d81538e8eb936bc4aae9b8a9be5f18cec1ad2cf1a767b2030d5f1d85bdcfce8bb6d21806c9e7f0b9f77b86be6f633d91ae2ece2e826ac4c4e31b875e25e476b2ea89894b6805d349bb99d41c1108cc84af010bea728dc5768a9dc8a3d8f977299e0f76b3ee3bb3d4bd727c569fbd855e410b93475dab51d61e42a40753011e3190d58b53e4f93b6d64fc384e2ecd106f16fc0afcdfdd70849d953a037b60e9eafaed1768446fb468287d11f4bb42601f8e3e41841ac58826c6189acda3fd0a70c9d7792f368791418c8e39e4e26eefadf0ed092784ceef4799be02370b075032c3179aa66558db0a2397d5c8a87b50ac49661d149e32ebeda5b0edc419afa4c63ba19e6f71eb3a1c2d2b41d5a4e357eca4c3974bf00fd300ff66722210ebaa53fc0bbb239ebc3b778e603c36337ef5deba04ca0c9d388a917907ef7539abd1cc32f9cc4f364449ba01e3b7c11dec29590ead6254c078bc35cc368b88a9074775575c4b084718b99af999e57599e1c1f619a740200aa6caadff73508544da8729054cda08f6c93ec723ef55e7a737fc8d35c10d6d8ba7930755c01014d1a930faf638b151c41a4d93a982645264c9c6d1a5dbe08b4d937bb900e7acb4ed2560731fe6bda0f946cadcbf4708fc2e0a2b097b0f259ccbe97460416baf5dae28bce08d04050bfa6cf886cd577e3604a42af3c3507587519e0ba5dc98eae3c1e5e95925a5de75320d65ddf7163de8d203d00d12cb197c4e1093638564893641620fb3bffdefc88119cb59b7a4790a5cfaa07e76f1d71716da62bd8c250e082ea9470df3d462259532917fc00b5fa8d9f9eefc917de2483cdf2fb5f6a34c0fcc3bd0030b7fb0661486fb452f6c508376b55ea3c0512aabe3cd9e37676dad4f1119aa4cb12574eaddb5ab31a4f0caa7bb268493cbdaa9e4ccca2e1082565e55b6a3d7cb33282a6a14e64b95a7c4272c5a6e43b1213e360e6ed236d447082d97eafa04a58645371a6990a78a2fda40f12ad972e1e5d6aa9f0cd3498b93096ac25c89594dd6f262e006f185e3a0e811ce53433dc0cdfb887b3856044e7f3e105b0f046f564fb1c9cd8820c381dc287e714e0cf0e14289fa7db38944ac40bb9a15b285aff73643e5a83edceb5cbeda46b44503638bd7fdced406e75a00f1012f6742c4395dbb78d0b62073c117525475de6c41a9979a659ff6062790c6cc20101e43f59026320631cc26855fdd56bcfb43692f9e85e9390b9e10d720b74c523304a049f6d5a25595cbf820c52a41c5b683af0081a627181712e3597b6d002a123d6a054bfa532eaddaa1f9c2fa43297d1db09da529ba77277c7fec848d095121bcc1fe0ea2e4d71b7804deeb1194f65b3a3defbdeb6ba0e8d7be27454f985105883d9f19c009c25ed2f558c8552055d4fc4e7beb8673e5feb4354df06238859f31b5cd5ca2c1985e9d7dfd6ea5e4cc78b32783196a30052813c453d402707c9dd481d22d66a6c454cd65959d106b3961c1fc04838219b66f3a9c0d745895f849a2d68e8bdd2768ab90099289e4ff875b174dd9d0aab3844220aed91f4ce8c8165a5cdf54cdd40ff0b4b683708b18ea4264ec849a159cf2500a62320c49be9d0908afc423d8ccf40f6f16927c7c9e029ca1e27ca8963c20a8f15eb27cdc542102bde92dc18bcab89fd3cd6689f698741cb659681d73beef9a44d50cabcd6ebdb92a88f164b6352d93b05d236848089ee5f1a07598f33279907e2c1b9fc55bb73df30945321dad79a141916b23296d07b9d2170dddccf9fa146534333a9985739dd620fb3bb3c88c2822f7bf4133e9fcb6cb960605fcc06cde5e5b94186d045bdccd248845f7298358e49832b4a3ce2c0238747aca0e883ae39af6f4963ab029ef3d78814e6dff8220f5ba41be765470fecd3209ba44955d00eccd9fb924ac175967c264c6a445f8fc5ef76651d571fc7e4ff731f0a564b408835144d87b883d7aa3f24750404c06d78c9f065b57a7033331883a26fa1d3de69aa65f453f6f732b623b23a21d6cf1fd9a35ed77b144ccc2cb0ae39a7b744f8eb4856303818e5c82d2018bf22a3cf078e359753930dea267f48e4e9d3db1d5002706c724e494e462ad471f7eccc734b7dd02a384c4f402b662ff33c35be93c06889897d57657e7977dfce32a0f6d02ce3adc77b34af9f22263ab404f88d1d9573e6a1f1b1607927e81fd79a4d1e8ddbf3a2c8e1a92f8141a22c1a22554bc88ba5be93af5a54ab608d1fd8cf2ef04404b5f8aff50c82779c3e0e68150535ce4e04bd97aa28541bee0e214e14a204708356bc113cda25fee0b1e50b9c00645de6cf6ae8c113225a3274a6303b34aa7408b8e5c5e35c5cc80f10f24cdaa6c87f18b4774405a24e301b712408287d9e48a72daa726d863790fb46dc3543c8b7cb7a3a1394b70afe84867141a6594d2d36040908abb65d6eb539929de81e27217e49450411fba87c8a175df0beb3f81c64559f45532bae17626adfa837056872bc8f51628726817274d0c17b6703aa0c559397133aed1a7b12bb1d6029112b79cf5a26529069098aef22f0331c814159d4bae0cc91db603c5bb0e3481b479f951c67a06f075937d19a4e2d4cfc7fc2e604f59c383a88f1775fbae93a4c22c529a4581a0ceec498a782cd6bc6991f4c08133f7b14a866a7b13861ca448d738ab9a8e60a2015dbc2db192097bb1d87df887f85cfc2d462cb6e1c54ca4090374bb12e91d331c83da119cc96c8dabdd859546c3c69be55a6dd44924ddc6941e219f2880595749d9d70f9ead23a6838d09a5c48cfb800aefa1d9978105d344d13eab180a0e578018e103145a6445950fa86728cdc7c59ad19a7030f34b25f27f7fa0651f8b667db49140dc1596c6fb969a6fd2b99d1ca04e3b380172b77aa7262d428127937d0d8dee9f40ca82450a11a197bf7c4b5db0b1bac56f7f28d629cde4694893d7ae88b29a01bd2a2944a8afd05fbc0adcd3c32e58047433ac6449c48f360bd922d28f180b8c88629b92a95bb77501769136a98b3f2a12eeee8e53804cd74351a6b2264c2444a240b25c9330580d820ef0cbd726f6e1749f6faf279e37d1663976312a4b485f1e18abe117d2ecdf162a1d116b18975bc27b6e806df24cbc0618574485beab41b8dabcfa9e0530fe93d20147ea837038e13072a496be7c23ef60a074574888d979b6a690a4cdd5b0f67921f20177ad9b782d86ac95c2b4acd297fd34d84e81be44750f0503ae406e6d909e9d0f46a9009484942124af377600b4a3037f68948f14240406a38f501aa1257f4936d3a0736288938b80a2110c6a2ad1ffe29445959a62ccfa95f719235e4cd94c83a863f75098cfee97cf6c7d5b0dad3759b35db5ed8128cd0322919e2fab0b7d08ecc302708b99df12232d1c824344fe3670a0c21534f89e0bdd2f7740dc2ec794de2728657cf141e0456cbe33026be29b8e544f6a4e655bc6506cf9e9540d80a3b92bfc78729e5523c8f06d4a942d72fb1bf7cd3451a01c0904e7980ee45956d23cfae32144941d336cd397e37d509e6124216742ec8548210b9a6c9cece18671639c6d704f63bb6565f7690f7678721a690af9fc2987d0548595fe30dcecabf6192d83c78f8189260caee6bb691d9e5e1c388a1a4089baf06861450ecbcfb02efdf7cbf0a8ceca30eb394388959f2f2375cf46470a9dd6671e306563d697e89c7b427bfa7897273292062565a4b0a3f85fe76a015cf2ed6e4e33417aec98284e41dd54f517c69324cd5892b9cf478a8440b876e37d2b6bdf2d6833e91cc56071aff6dd82038f0a88bc643f7a64bc074518f8e200719813b7a096f4e435f632ac612c6657a4ebe74d23aadc5b5134dd160a474a1a0034352b1daedddd909917d152ceb277cfa11a74973f15c2803abc6d71fe45cf1a879adc8824246f99a8c3e00db7b29c5e1b3058b7878fa9db805fe1da0f2aab3e50f687b5aac7023f69c779d41110cdfb54beaad3db9b7e139be161eb7b381debd203c96d3b71dd5820e229067e67bc44cee6f5416fe2043f70a46a9ce7a88a4a41b037f501374cb9968144aa8606ab69096c65d3b6a6d6d9f9bc845e2d09011a0961b64011f35a737b46b4679b68599013b56e54b5e277eaa384b819ffdebce902a64b8d002c094124e91e1f17d4b2bc8c20d23510b6c9817e45ba782a94284683fd4dc18e474dbb636981adead3251354106dfa25c1ce77da0c0130ad39f1977d592629e1125846d6a56336a105d8fb58d1ceb641ae013772cd3ecaf0b48acbc4bd3ff9b70565709f5989960397a587c4812e8cee5d01e27ece34f5b16bc86c37312ef8cd7307aef4e6b6b66ba1fed527dfd5ae2d9c77f3ae61c6378422f422e9ccc85541904d391dc4fb7a0153baf24700fb94965adf575e1596c694a3d3a381c6d2db755f630c490017e9a4ddbc505b0bae695a6d42dd2a492782cb59c5d5bf5922af9b5f3202120c53b3eea8c9f2021b0dcc3c943e1ddd0e843a7d9a8ee0ced8dc87a668f6deebfa164db991e1b032fb462585933b6751032b651960d0f2d026eaf07565ffa40cb8b25ed15fe84544923eb111e29d2efaffdbabfee193a5dcbcc5c30def70bd7f585d37cadf6f2a8897b0a5ace33f8302b64b284f547a59ea976592065a23280b35f2780231becc3198b035913e200e6e78f38a3ef9ae646877463bb09c326537937639be1320652dbbc72cf2b645055171bc9601cbdcbaa70eadbf64c54fde5f78c42f17d03351f529b2f3cc55b1bb9466889013c6074210694ba8c3944ddfa8722929e668ab163625f7cf03d3a61078fa779879d71879d9f35c1829c26e55e83adf9cb255ff4bb0ff7fa237899ddbeb2b71fdf93fe59de5f6418793464477730cf1faeff90781cd1ae17df7ed625dc71e3b4256547fd8586a819b0f26dc7f49adbe7f09fd7260259d5845b50c43071a2b2346410b054df91ca0b1ef371adba99a9d556be71a95ad49980d26185a8c6ae7808a999a34bb9375b423557648d6ec92d1a68e8aeb3152257fd3573477ef62471562ccc4474707c056d612e2f1863fffd44a0685990876b1a7c1a6c68fe27a1127102413b432700ea794187c6f042718ff6f6c0d5a532514fb5c83aeae80856d64f0d5c169e4119e56cff1e2f878855bf37df1a5fc22cc0c6c98a933efb111054a7538bc1c32976eaff63040876a34e60eb67e442f4c126442abdbc764ca1673e9a8a45a766e22c30224a2c41bc9a86b10d6d741837914eadb275ada129bf185b0b9c46eb35afaa91f133d5428d1fc0d251ea7e8e1e9db869301e22078810d9a459a8974cb822724f588298a4b0b25c69fd6888c80b94df1086714c726af358b756f1fc6360b469571aea4556fd16e8a2760a2507d92a05d2eb7f6e35e9ff1ded52175d7b163de694a05307c59ab70071fc791c81f0b8ff979e164e3d0e1bd3fae6d44677e4024273174119f23bc87abf1189d5a34ce780d754415e295301f711fdb51c80dac45cbb17f40095220a97a113c50aea2e979e044aa17161b2ae9289f408cea251fc0a36f84174c70dac9d7d4aadc4c3ed722e7c2ab3362e7e02751cc9f7145af7821fa032d5b3aba9e7fc3fa4e358501eda77ef6138ae9ff0e0d1cf1bfa184a350a85b5fe1e75293357819acdd3afd62137e1ff59077f0301d32eb45ce0f98d46a4d46727b091a64f9a798093b97b92eab9c249b00ad3674e842c58fa9329f1378297a8a75f1f41961ba3d9ebaa2ac65354d92af723edb1140eeb2b557117f04bff12fee3807f9545998edb4cd24ae37ffddda6a15eb750be48630bf0147a7c0f44ed909d96bddf04658fe009600344284124d14327f0724732cd16d26d9c4271653faf0646318bd4c9198fd8a7014341a0a8bb02aca93268aac4b99da82c7e5587e2cd51c45214cb7229cf9b43ebd20c72bfb14f73978d1a42c23e4a19434d1052cfadd44c3b45122ae519d2023d8bc19f61fed2f1cae851b94ee122aed9c09884b283524967ef9e0f80fda203827de0562e198c2e1f0936a1d0dc14c53e4a64e2de08e5cd384e32caf568e4954579c32a2fc83b6aad4adaa702b0e8d64ff2ba18973ee6d49a35f3c805393b71a1c8a3429d2ffdb623b166801409c82f00374482053462dd309db084a50b73f5ee42de462c1d4faa12d3fac9ea167dcc4b7803e2315bcca7a75154f5fe1802291b5eeb94647c580b297d485e8cf17d47b74dc55632fe149cc098dafa4a8c577c0d713db689610726ef5bb95f3e4ab1efff63516dd143f51ae6766f91c826df31f9a80e75b5ee97bea1e04d80677ea5ab55e08fe736d5854746185d1adc0ad50f3867058a3439d6d38618d85018251831d37007818056263c73993f21dad787ed20e203e3673dff800071902fdcc2089529557c86a5b842e7ef5c7f84022a1149122a8e17a059c551802f07cc64bfb93b69b116c247f26b3e6bc5107af75af33383b87313d3ebe6753b6d0682f12a4ad0b79b4e23a8760a8bf7d03fb4cc6e65c954fd578471313115ce7e2d22898892ea363828f9f1a5980509bc78ce5d32e048a0d86533c881edb05847e2e922fb12283e738f69c17d79229f848e923062247ab94b8d17ed6012d258695917cbcdd64a1913aace0b10a61c6c947798f42ec81d84f2860390d48ae9bcc269998f2c79e66ec5bea917a849283c3c705851b90043dc9c784b8e5762c99b03c4696258c194991e64ea43ae20dc996f1f86f9db8e670e56054d126a679c15eb911fc048700299b6ef609c9719e946381850d8129079a058ceb6252aa2322b2dc797415e196663f7cd40c5edb42583769dd8a547a4a6cf0a1d7f169796506bb6cc9eb1e6ab4badeb91d4335e6a9f680cdc4060b9e2fbdb87fe950ccb19928ca1742f99aacbb63c2c0a64d7698f654745d34155ccfa44c18c3a841390b6d38c97c0c2cd0510582ecc6bc3ad17b26ca34a2fb215b1a6e112ed79508be134e09ecf97a84ea5fd9eea2c610e4aa977da1cd9011207630af99bc0ebfb13da475e51a8b92bd80ca80017c1adb0b53d66d009cf97e8598139cc072c423441a75501f6f45ad4c1afdc6b7c18ede322a5adecca571632a7ca23e259d0b3aa7f207305f23a17e45d4a20deb6e684c9dde60ed83b6e121ce158c704ac6ee642644befb05667a4b5fc4c01dd37e4d476adfb6ebaa138e93648f17f90c963a989aae13e793d29e1488050d44ad528692c5ef8444193c4687d984ea17efedf49cd452264ff6916c5c33a5306323adc1f4859fc30df9c4a09dff6eae7240a7ed4d6885fcb63ee56e975eb90915dbe883501308aa36b0eaefed2da7d5f5e7f10e37c544df6f643a7611c9947346b59d71cc60c46a1d5d6c41d450dbb410cbf79f17e202c43788d89b275d838352962450fad12b2348404315c347c994688b95544b9f85be0cb3ebea3d961b99681a5b9bd13c329aa23d0a6d2ca80551323394e1fc76ef27787d0eb4b89606161cdb68e5f538a41c7528bd9b525624db2efa1dd18be7f14e7e858cab45b2306e726789d1776b30347fe90d023495b923b74d674739702c9b9901cbcb9a4e7d3fbde930d6ef6c1775597df630baaf859171dc51d1d93fad28e8a452ff234801a9ed7d2cc2b1684453bb99527263b9a8c11d654ebaa5c4d098099e49332a29dfb6113293932dc50d822bd19af295c1fa8265262dfa0a5973e750e33ecd037f8c76538ad373ad9f63b9e40e4dff4b85e67f79660e27ed1e45d10d710ff4b92e0e0a887bc72c915e5fdbe6a5f2648ac95f163a8edd061bad1be3234b27308c611b91043d99acb0f64ef6f6ad04d56bbc4e779248775e1bc128fe0118e33d3d6a44c0efa759e7d857a77b3436f6f03d455a29286c20e6d9162cab9a5a0d24d1c31fc7db8964be9f4fb6d7435a0f2d165ba0f50010af81e0527a6170e738ac0d3f3c1ffc77b2cd750627a768cd1200c86597fc8d7671a41f1fe151ea7437534874612c25cbe5a29bf7192c5670b807de735659a91990d10938e0cb80e9a3ec6d5f53401f3670b9f3c2cc31ed0e6cc1311a0eea6989f92c9e8ce89ae97073a0e84194827076ed2e7e2e540485e5c5cd3c68ba16aab9b28346116a97cf101c815257cb0012250658c798a256a8e8144d3eb0da89423721cb0a25132217968207a076f8e0d40dc0607358a35963e6e74ca502187012cd8405efe5070064d9f403f79cf56f66a0c0225a7c7a1fa97d0ef6563bb6a42564e43539fc60006a717829a05547a3b5af02c43cfbd40f196ccd5c9e4f037042c46439e805dbeffaa7ad0b5d3018f2f3dc72ec8521e1c5fb974b90503d5c76b1a80404695f710028f69e1f87d34deda7b7b28058a70ad53a5f74eb429c44a52f046500f5fc9eba780256c6961d14835dfaab413b21fde04a2800dfe89096bbc878648bb6880680d9047479687fceb201b1d57c0fba429aa967c96bef8e6f0ad7136670656078e3ee3fbb4d65cb0af1d4f2a0a1b85fe8e0862267f748390d8d45eb1d16e0fa3631fbe0933de0894d3c9697e5ada267cb8c050bf80906ee0cf5fafe4517cb801a1951b17088ec2512afa0f4be5ace3ae61c343c627f78e354bb97cd0629d1a6e924571008a63440fad7d5f69cb6378a2f3f456d2ec4f617f5e8ba8504dd783b650c988e5b49585048602970a1b5642a00089405d71ca4f7b40f617bbf36185784fe04ec4d9b5a83ec0fc96e1c76868e8ffae0e7532d6b7402e5864dc77eadbe9275e403bbea8ada205f2550c50880e9b0342851c5c53007b7d8520847fa489c60b3541aa4c35a7856af6496392486cb14bf83a271a3b693f742bf102c2635b03c601cd23efa33646f5fd9b46fa5e44204727ccbb221934309c111ff8758719693b6ba2e89d12a3ab6dbc7b243f4bf6c8cbbb5d257d00e40f3e1fa92a9b8e9e46493256de71d1c9163922ab0b2a7d0a9f5cc9a8ae335d000918099ca029229a66de2aa651815c8428bfa1b94782f799057549f606fb8ad3d58cf1a37065da603094eea4653bc593ba402fbd7b20a3366c246981378dd291aa7b44442e78bfc2084ffdf38ee82b8d612c7f020babeac14ce5e3ba1fb707dc997652417564188382db5c25be645a6d41b16e817488c1a5120fd866885048788d075226599c81c1df626c59c5add1e5fc1962baf239237f6430c0fcbf97ca33111ab99144d798e18e664d5f8e852eb48d85396620b0f19cbfd12e0d867aec51d53cb01a81382e184fe12b8e90f7ba568dde8721f7abfc30ff322cf097b48b8eb1ebfd004fa5aa9600184ba35118a8cad1620626be68c7bb9592970a2785759d6e86b80a0d39ba9ae6823d4c810a286bc913df00452d023c6e0eb2f04453fd514b413683505c662c005bfdd9be192be185add7af4524807145492000d2ba8426b0bfd8f5de09834e0ea1f36cc59e79388f0c9b695fc273858ae101d3bfd2464bb53854f9a82418dc01f374dbdfbc5655b938c3da8dd6a0a0ef05a0bdf496a7d24a919181709c5ea58313e4f5aa1c1cdfcc38d146b4d784bc92e95c47a132b7023b613795646873fdbce42803e05d0cd01a9456a3144b18020e76e185d232c6edac45aa67b135c050526101ef051fbfca73b21c0a02cc5a9516dd0e04ea10ba00e3fa2e674c251450122b9f63a24cd1f262344f9350647719dd8fa4c24eccbaef7c4768a043cae22a5bf7a659198f14ad7cb7533818cac48bb6fab60a25723aae79572e14d3ce7bb56f96c38ccd7074a86c5743ee6ce79036e66c7dcf7e119d5cb789e85bb10dcab84b35900e4d40d66c1c34c4f2f821968b3923fd314bdeb55be17aca04245380daf4d6624866311133b40e4993951ab5630f9940e8ae0502f8d62678ed5278773c3faf6fdf7721aa02af6bd7a7f8cf2f71adf29087aa8b6b77715765826b9f7cfa73934d1c16c50e8f9101de132a073a7b3fdb97ba216314bef4a53bb8dd17bb72050d5e4a7951a176a57d6a9b4eb16bf4aa854210b7496ab3a461c29ca6bed739e81f59e071b53447c40be7ac99bb6d166de1f99e073f392a193bdaa7eba1ef3f7f5bbe1c9e92e063a8a816e8ea3f3ff2e70ae67c4dedde7c332d6b01fa00b3e8c7b168791d82b8be9a15d6118cee92786ac1743914515100db77d168a298b3034ea20e4a4d5d024a470048598a83695829585f56d995eaf536ee0dd0089fb9c28184563dc83f1436837b83d7cc3729c3e9e10f26fab415d501835712bc23eda7a28c49a63a5d07d202aa2f6fdb1da32dc38bd24110eb63c8102e11d5ed1280b7ec3f741b7da61e7eddd1b044a973750132aee7b96c2d839e0d3d41d506bc4e2cac0d001170cfab6e2aa593b166b19b9140a4f472f02a51d0b38e31165294dc7a274ea029eec584048b2332d551be042a60c59cc91149f59b46162de580a2dd2e2e7d225f60a215f7b96b89968390c1496c075d1015fd598842b8612607d07212a77294fcb0a3ff122eff95e06a5a208bfd4a6a91622d34518b43f5c869335d82009033422fa0383c9a47c21a2f00a80dd96aa3545e1928fc0e47935e2305da3e61e48ca4d281fbb197c0b91c43cc1696ad70d51197847dad972cf9238f10ae36552ea649d176f99f987554654a6b24eeb74515a2e909a2718594f4a3b47b385aadc00ea8c6ea49e2c2f67233f66e14014592f92cb2851836052b393df3df7690ff668a34144b2fe60917fd8ac04d177c3669d12cff0be796aec9e94ccac0f0e024803def499f42c8edcca491055984141164ad60c442a9e344b62ed9d559095745ba141602fad45d1b0562d185e6bb8421ea34106620010d574da18ccfae55d55f6a596afff2b474b8ad57793be1d888fe579e4eb6047f7356e68ee30c442403bba346bcb94d66620b8d24ab0382e818fc5de51b503c6f8485959aef311a511dccb861f546a9f074dc0ed2028b02a44805efd094051c4a1e01d221b7bbac524a60cac58667888073bf6c4803e037cacbd4736bb1759db6fe3ba8d48298e8adee76750e04a2a4cc2c3bb2292f3122468a9b4774e4e91d088fb524ebfd01d29e094cde2009fc7ad0ea755dc1048f53dedb49bcb3d8a128f61c8f6ee56d8ec2355bc5af5e0672a9a0f41349dc3a8abea87c0d9deb8693180736adcdd35e07e75c98941db24d6fcf50bfa9a76055313fd48a8b6f5e2ff3312b9c492c18ce7a02f6cae990e7705512441fd1ce32c511127be3b5c6041b76d3bdb196affeb68a85dd6ae813cfc7ffdd8488ca98227914a2bfd21edd4e80e091bc8c3258540f3a9055edc0321476f940732778d9108ed69971c0c79a603cc46a5530199d638aacf3edd41c8d3714e6d4489f31aaabf52fa0a0d64743e87ee2e5d8f9b1b56365dda61731c39f528f477c2d232d62c25ea7bca7eff94333e9cc22a9c127b9d5e46fda01fe421fe41d7fa742c5a847bd351e9681830a2cfc31ef7dfda2d8583bfa70189164754ed51e284893471c2c27277a98016d5a330930fa3247ceddd90474f273a09f331eb38d09bd3152b1c44f5fba780c90be1682f4315836691597fb9f43e8b3b35240b80bee139034eaf42672b3b19014954e1f04ce9552d915dff0a9492a37f6f5337d4df34fe112d808bdf25ebc349c6f39ecc1cb74af5d09c193d11b3c798f07254258fa60231e6994b609c0a8688d707ed82bbc1f2c86ccfe380785bab3864d9de6eecb703f2119491ac75ece3b445323b0eb24c81b6890d5212664a8eebf31639d2250ba96994685805762541f83e458e8f92d603c08ca8c17ed410f4807b06a68ca6243052dba3d3e6a6e4d7ac1160f9e83a6c4a9653e718fd8a0d5d0200db4f5695ed3ce9fe5d74f104b509e917a9f537191e36ed33b7b42100bf2eea794d8289967b95e7e37d79be102ad82ae718160f1afa88c76ae2b6a617f7e93bc7db88e16793d2ae0b400860a8fc6eda1952c21931799da4d7475828ac4e29daef9c261d69c4e04aecb4340959db8705445ec0069dec6130f1d18a097102dab338325abc82800d14818e9924d351f44f95773d04f1646dbffc889a88bcd28467d6eff739443b8823d9a4cfee693a96fdc15da5a0c17566ff6dd7400ef44e48088d52ffca79ce68e2e23d73458f65bf9467956c74bd504377b207b4e605bbda5c8e6750d7b5d7dff79339e0895e314a3b7bf063d8aed54dbac394b6efdaf477768559e5241082529a7a1208e2fd5ba55d85e992ce90d1c5e44a2b47a97ee4887b4ca778d408fe721d0f9354bd53cf17c969f398a76e721a2f92e0b68e4fb10891dcf060102b484532149295345eefbd4759c0db7d8cf3dc88c6fc34e8193e93abba1622f89840f2d21f72ba4ca447e0b6f73222a32e56b5193ae4f2d2771120d0228072d7218ce77ee8197fc01397ed084346eac458ede2413e411fbc95b91e78da772091de8592d8b4356d43e81d1aa8651e463c219a120e154abab04ae4568b463f104b57296a9bfb39100d49c28cf1c719806fe0d79ee3d5e32619b9fb41c510fe83ec729f218884e7bd181eea68f415fa688c4bb37316878ac5c4c0d666a5d8135a3d6c827a00e2b9433325ceb6d7c0696d8feb1c950fb150ed54a0dda88a563a84df2b5e37ea0b678cab460c84411f1538d0dd65a3ec5de4cf0c3ca8b487da1445c6e1a02b97982a719828c486b34c59ec0c16f140e44813e2c38e1da7f54dcc7c878281ab1492167021ffe40a9b5c56715f051bf525becc89bd97e543a5120f916aed56d69019d8c1d703d1a19ae38f1791c4da632f9d0632d000ebae327488bf46391d0abc3c1e98131e95823c083dae1a30860761062cd2d3cb9c60463cbcb67953f019077f52419e385f410119636220194d6d1c48cdbb04d933a1e591ee8f3df70d33a92841a57383610298606a421e121aec7e35f1222585328614fadf7674414e635b36459bac721c5660a70d9293f4fd64d9ab6265e7a4de49c205353c8f20327dfc910d531231da5a562a7e28ae1192545238bfad2e616d6892532dbc09034984b5905956b2f2794bbeedfc3678764ec104f8507feffc79df90c00d614914a394954f45575f67fe4d6a2f823bd476d5ce8d252b55175f698d725bada9424d08b47413abf077ec37c03dcb1da1303b8d97e9f1a1c227a51101f6d75921294074fd37370a0d65541fb9fa4977de1d542b98d94742d08211b97a483ff63e4976a36f51ddd197a4e865ec7c3bece84d88fb3659873e5a2cb75a18288204276614bf7b516fefc2300761dbf29007e1dd84db6a51d5d02dd5ffe26010f2ccf569eef88e331d4d6e9b1b6d3be695215ab6540b5335691721decb8bc1301c0e4eb547d008dfb916c49debf5e3d5c77a5b97cf756459c5bcde33af75a1c9f5b432ee3a79e77d36bc140971d256e6a211d5fa17644a06cbd00e7ab791aeb804920d8410b5b79b4e90cb72a6b29aca3cef5576e268f812d75bc973f604e2b6b4e5327194ce84fb7b284d560589a67898df7d06f950f1300de90fd34dc1d247abc374610ae63c971482350d986ce88f111571a4165661b91800b72be620aad9fefc82310034053811a08f0f0aed56a4d8f9206f11514d1f0ac16db842515c04fc15be54b047ff9dcad7be144dc765ff566908f0044293ae69f991733cbe38652dc66fcc9413af71f4924e36add19a907756c38b3b5b801a561953994a3befbc082d13941a26ccd8e97b8fbe9d9edc7f1e827b0ae786657d97e9fd106d8f91e6897ce945c81932437b85ad516698b6b1447bd8a5298cb87cbe8616e69017a2314f53ba2af6c6ecc00fcf9a0da605a1dd220f483d14593ff533bb2e92cee4746b4a833330c9cd3bc648982e176d41d0e965ec1318ea6809e1c64c63417f87983714d25950d26e0e56fdbb8550baade8448fa485cb2d804b12016be1d9af962fc6f715af9cd141fc0b58f3912f599ee1f8de42053688b0274cfdc207c413296a3a768088e1f4e0bf6e45a89133932e978dbf5e3a42f71781a845be8b484f40114be285a63da57b6e9815bfb9062dd707f8e1716f7b527550b807bf6285b2707e9df9de14134906eaa0e7409bf4043f20671926abfc3d6b417d748df1cc1be5c688fcc91349a224196e9421aaeea1bc67845c58843e1a92e37fc903ef76e52f1b59018f1e4b1178ca28170a622bad08664350191cf3f90500244dd754327407f8ed1b3629dc3e8c7a2ef525899a8ce551972cb290ce4b0006b9d45e44375039b0c194d1ae29381500e3e8c51d3fa971bf48daf18c8e8b9d0763b8f141961e80aa2f1ca4ea20fafba97909c669fa4fa9db27cece60092e3ac5c7349985d925baf86db82c86295973d183cea0611eb57b4f9170d6a4a8f066230dbbe15ef97d14f22308496b62b16423af6c4e3d32d97539c01735a25548d0ddb49119a6989196bc81f372e2ede51187d0f1d1c7789f744de4a87de6d0112206268057e7fb982681acdeb6511bf2da70ec3a391f1542228c3a23b9025c158b83e00f03da1bb9e3ec6c2fe0989c519a9e9e21b4f0d8e07d2367d1d5aedafb38e87be4f808da21ff13417f8be908181af67ab3b51c8c121e8174e13af04fe85b93d4651f541f6db745b3718883726a25cf9a0d9283d1e1e8d598d121859e8b509da3e64aa798ad086e29028806c2de4438d3775a060943d0af375bab9284e3c3a131d981c8cc3785faeae24622e5f87b06fc83119f3f728400fc7d790e70572dfe909d11013218ec3e5ba52884bed9803797f11496292f73d795ee0206ed23225b5af1a9e8c722cb081cbc97a68a450d455e382fd2755aff05da5bab498c90abba44b3f03fe9257a4cbbee1291429d986f105d3d8aa736bdc624444740e3c744576994fbdbc7a1bf949ba99eb113cb3d90ecada91d6b758fbf07fe79c56ced06962a3d51181d8e47ff0a66bea5d4fa7f3d4d9a7681b99b497e57af3c437def6360a44f3ab9c8b7d3ba0f21d73eb093336846324a120e47f6537f532a8e7a328f53a9a8be269318f31ceaa25304a0c4db6e0ceda2d2dbc504cd174ba6f864510e628557f13643afd593c2e382339ce3c6fa24c00221250cf1a9e441a35af53ea6de4d014e37a7cf5484ac45156453a4c5565e74369115fd505e2ff7fe00a296712612d3e9714a6a38dc4bef3c308f0a62f5095588d2957f362fe5f440d820d94040e628174b28450f781771ab234b03a282a0b93b325fb5ab4456a32e071ed83b539efc35413e5734fb527a73e4e094407fb8e1dfe2cb5d7e6e1e4335291f5fce22afd1661185211a5fb0f6497f331f7ae3b061313dc274763de4ed1e7b9feee9adc1d319fb2874ac162d99cb4ca56852017cdff765021a388689ce8ac35b771b5acedc6f12e8d377a3fb10c126e1277a503af594d6976c6d010158ab9d8023ad011742b7e035bf9c29d113912b514ac01eef3d90a27845a4094ccf63c8cce7c3abd5aea13aa45a18bdc4aeb6fb72e489b2285cb736f556e712a6e1088f977bd27c953385a4f1db7cb1a9dfe14774f3b4dde20bae242d388c90b4ea63fd515330ada29a4b0968873d14cd98d0cc88d20a67f0444dd8e9486b0a957cad909885705deb791089b40e5e8dc4f21d830e9aac746c093d2f1923db53ee725f22da3ed90e0121ccd0a42e169586e0fca06c3e4e9fe7dea2c232496c625f6011b3b6bf8e21d2bb61aaf28f7fa3afc03b7e15e5bc40f858d723d1367e65871d8b25b8b917d8009084e69032c0a618e7b5b218928b01027b4cc8786dd2f4d6a846cd8e22f585d985e0b8300710396beeaad4cf252a27576f1459bbc3e4eb7c5f48cc44c1d5c1adc721c538c18a432293a310e9eaea5a1d0736bef4bb64c6dec56fcc2a0d75ea141722fd2f8f9ef1e15b70ba4d678fdb167356613e4e264181fef776b60a605a39629ba7c8675c456fcb211203b34ea72deba70129d399bc749c0411c7722cffaf43359c113454c07c5dbfe846660e374bdf84f022919ac66f9b73c3defb6db5849235548dbd857cea9e3005a31a13ec81c7a08e14398ee23f54beff73d8a8eaa0d7a658ea1142b219033070b373bfab879f5e5ee9a9dbdee9060d68f5e04742a65365c23685db4d5ada6785ccf70c96c185eaa177e407236e27bb4d29b011a76be2f323601103524a6678d4f88df32e5855b3fbe59f0b24ec285e85576fc6538a7e9cc75534e70816766729c05198fddb6e9d6c248d4cbb5492f10f8df502029027823f808dbe6b42df07953648d789633607a5f1d9eb5e97c54abb1c8f74f1fc14279eedf9fa96a2090083751e866af3c9ee394fbc464bb5a5922e65722ab1523502c0e88077f7700861148da0410fabbaf00ada3c88eec1de7667cf5be321f77838ba587be1414e9ff540ee4b1829d38d06930369fe3b3cb206157aacdbc26e446bc21a14d49034627bb476c9b620091431ea590dda99280725277e81532655e7f1e910470eb26b33373e3ea08d0c76b4424ecb0d79d78734df5934b548574b5944310697556b7bac23071ad838482192c44f7cf829c1a449d4d4661ca3a6862350ba1078e63619c5198378cc83fc1df7168f3d4b775a923c1287dccb4b8dd6280c5294ba3e59dc04adb14f461c1e5b7de9ea9aecd4550b85b681b66c6b637d8a607142f2d69ed1c25d6ae0c5525b48a63a13ad597303b451be63ba66eedc75ccccd40765fd9fa853a81e63e83292c2de8c6d6f415d8e6bb7d6c4bc070eb9a456a2cb5a6f59c532aab890a2f9dba868a1125817231eaff7e59268376eb51a2dc920d182d176897d5847b49c217f0322e22c0aa6ce63d67110bd3944a982125e1216505da7bd61cf036a548197034a7cc58612ea387a6a9dc9fbe14908908f40c06775da13e384ac2ad72e404435b387fe52237082e8e708d87f29def0e6f44f89e9eb85f3560d5661139281699a8f970408881320c1402bff78c3569c9484e13398030a464d8d764f6f70d137c341d5fd111397a9cc0deb4fff2a253a6148fe01ee9676ff1ad3db52c073537e72b869c4d247ee53461987b433d50c176b1b26bf032b8384944290d5fd8f6c7e9c1e90b91b1c15bda0eaec5dd6aa08b9ec32852c60ad47c4a7c846d6954e88da3586bcc26f1271e90888266f54b54e3bfe31c02a88a50aecdca378cd81c02189c8d46436ebb4cc9695347d33536bacb80d6666b0cef3f3a3a16a4b631d197ba1212aa92164d61aaf3bfafa3bf7e691dc2363f121db81e95c49c8f84ba8e26f54ebb543bc7fcc78bfd3e83d550b30b7e55f90b1864aea21c4babebeb3a09013c37a02b193d15697104f8bc56fe431f655eff81170712f0f269812600215c68cc1ea446548186c3c86c43504cbec79a8a53aece6c9d683f5de3c5fd588ae52096e3d9c1efab578fa0aa902257546d73420bf6b84954d7b8d9997e9f204279dca44742bdbe9e2ec542e69ea41927bea276dc091dc6409ce3dbcc514944961ca08e5be73918f6431acbedbbe3ee1443345a5142eac0cd457fa51671150092f3f9137f83866abe5e8a28079b36e8cf042c122d723f56d7808ecf26b1e2c3ac53a12c3247b13a13d5c0790baaa883e8e696b799b23ba58ead308890676b35c466106442e3201418618589c805b7fc2fc2a6b023d8471dcd6c083c3627c90964ef5313771e414cf48cf4afe6b6508a99202bc95eae717769e52ed24452c267b6a789329e351aade4756027b14949a248aedc23aebc17afea089924e913c6830cceff3a670460ba0fd0d1cc6b96e0cb33ea64ceb5b3ade67303547b7330c0d9ceeb6b2f71e6d60cdb2081982483567da1a1a7f0a413b4c6e720035550eaf902f34594addac78826b09b7196952eb72d924782296790d6734e0e3c29b414224564ecf307fbc8466b70ff638238977e6b2b1bd0b60dd0f1949adbaedce51d778e3a92296f96cbc047007c457de78093d0c6072d4e61430cc89167fc073d2dec81923acec6e5a896ece6307b7c4a62c542b4995f3e16a81c6fcc70b58c596c3e1879fed05c1e3639ae61504c48ecaea18e2f255ff09ce0568f1ad9ed298022b27980fa9da7b5d2a84e4be56dbc6f3813bb443892bfb698da902a9d7b3f85a86b9e6f34172e6be038704ad825e8636cf341e9a5b1c34d53b7636be62e2cc3168fdcf99c6d84544fc280918134a5a6b35fc3b817da4dd28711ccba44864cc4f74445278c841be91d4f8f8a6594a5104199e97575938dfe086bfa4616b742409f06f7df7da00ca54b986fbd20bed4bc881050d7b5c62a9633a778d15ff959b2832aa5c5565a55c5d456193ff6befde5f7be58d0054210fd9579ca64ab835cb1784ef6028df3a65c236c56ab5e960e1d8b1c7f2503f5cc5ac4b25e58ad55b452917a9f62d98e94d1fd58e2eb2a52f9269c14826cfd2e983657f83c1536b25cffe5e5c753aaf6a6ceea7c94302949ed7fdaee5feacc2f5d4a5659dd673d9fb45b948e8c36a65b1aa1f2b90c94a973938bc185a87d8563f9a9b3beceef98d3b4013b31f4fd9c92c6cb61bc65617aaecd4f5ad3dbd49bf93520a77cd506e41c28226aa6dc16f4c25bacd16bc889161b9ec39446b1e88e9d65b1dec8d575c568511d748d1b2e3e977b3fc91f2fc1190f0473601628284d2814dd681197b9a5244f379ef286722203997978cf5f830391ad1acaca6b910b28a3a894f807d02b30bdbc8a2bfa649b1a0b10956c055311facdd3d5ade6339834c085543ca553d7008103f43b58cc96a4211f35f0de33033d0e73d8c490e83334d4e7c8b0a8dd8bf686f4cd26e79d191a6675ed85f72c52b4a86ebda19cd6ed01692fa9263ae453462e331961b2a862ddb0b79a3341cc727fa27d4202a0bc98cbbe698848b58a0ea195ebcbcd2b58df7e628b69615ccde5aaa14f8eb9869769614c64e55355e7a64fccd48cedfa2076831a0c0420d736ad59ed31a65e55e15255729e2eacf88ec62f0cb69476ecec16a814f705452c5ad6902f72f8e3559a838fafb4acf35d5edb502b9e5f2c5c1517b616a1eb76c0f9d6240b76bdc5ebb0ea3b40145eae000fa9d42412fd3788d9e7817185b930a6eef4895c61c37fe7cc2e3f8c71e5575cd44662e08381f314e3251e35a24a680b97af984818d3eb8871967ff84c0409c89a1c70511bc3455379204aa6f2764eef76652335ad9a6d1632d782d3b955081dc72f9e2e0a8bdc2a42c95954d9f7935d0598f104aac431b09d73b58cac47e2a36e4e207fab3773390cd83e50fd37c0bcfb587ac99b6f30375e980a840260b203b79a7afa81823cf02287609d4fcfa146e6ac642b4158149f7a4cca0557a69d3ff5f733edf3e06849a0845742e0e11432d494b6bd65f3689b2a67d531ab7c5e82fb70ad2340e30f2c49a264496d0759224323f63a1895a43fa3c44c83073d943648fd414b3f74f10e46f770adb19f5470b7da00abf5ced32b191e3decac62d7a97463ca5244b40f915955df7fb20f662431676038156331062ee94e1347c5ca0f181a65049218917bc12405e33cd2fe3ee1f468e0726b0c409af029bf214d61dc0c0cdc26955765397c77a12336224854e61959e735b0be7b501e4271f0f19b2d6b570a8cfed4093062293ec7c2c18e22c7cadfb4e2fd62f5179b32e60a376cab08319b6a348108d2a9deabbfc07b9526d75a32ad05085d9c3a9b9f47e6e0410948793a11c96bfad2820c6dbf540a60620bc0efc338dc9522be3e8574c422f7b0f4bc128fcd30dc95fda6a4a73a5c2887620e5192a54339703d79b369117d603c9e1a83d924215c7aa3eb12bed2a3bab202ec14067168507376f9fa2dc4cd435fe57559a934d0d50e8574f5b811ea881ab579de04b4d46a55539326847741eb13dc4b400b5cdc55367a0dbd46060ace696a280f638c7956480fda1a8bd91dc95607f2bc00c2247b9a5eaf478eca8d1d8bbb312f9de172b5b6f120ff914c48eb7de349a497f4461a02f9b5e5eb43457bd2240ba523ca04570121b817d007aeeba11c17e756ddf3364bff5da359806c705dbdf8cee8b7e48dd417426de632d27fd140a53aeaa62293c5dccc2d8b6f4a9ac9b0734216294d209a58a788fa18c75ebfdee7a92268f108b12f4c1b83c9d5be8fa4e346877075b41d51a7c6c5e9c548b83740995a87fca255ee89ace12a6493c9486eb7dccc9b02d67f53b846bb05afc56b1a064d86080258d6175492516995a19a634c37707721209125d6362cdd600adfea90bad40b0eb3ec7f8d9eae2488f5a86915a29d3447e7597478530a2f086ceb2d4f582cd676467804fe98e280c381dcb2932889578ce6a8990d57710ad256a6c8398ee412649c14fc7fdd1a0f3a848d482d2e3b770e00d5eed8f26a12f044b8e57578687d4c93bfb88df125fc104de081b3a5b801e26e2edfb4da4e3257fd7d10515a2ef164ff78c627ba5380f704c3bc0c093d9b32cf024487e491f4d2beb110b8aeb8ce70db4006c240088f4d1a60e414a84d851501418b21eb542bee74d24fd3a6b7524b19491ca8724ecee9ba9b96b3f26d3e4776ffb93148c45d493a789d83de6bebee24461de41e017039d1980b67eca5c8489f14a4a75d2221bdb6d479b6bc9814e5b312d2aa485700190a83e0df213fafff6e158e50cb05c570f29026ad700ab9508df1c1c10abd505952ca0e6c0c6bfe4ae3b9ad7d5110f11325650a41cc050c28e90ce815c0ef7fb4b1e327a5cc2fe24afdf46e4db41517350372b77381c69b8d00a98b4ccc451814feefa516035f0b2a91bde09db77ca8057d4266b2951775955dd0541cb34d74a4db39d35de5f9291f4655c29a7babac2dacdad8cd37033b9cae554f05da38a321b205ec0a0805b85edf40966b9acf362ebb585c58bf467e4d5025f30dc1d52b997acaf80358711f41c4ee3da5c7df582e4d87029229471c5d06ac69cb5f138558ad1a91b2c7e5d5308856642827eb4799233ac8a58048dd2ee3a254a5a13250328a35ad75c505aa6ed342d53d0ae11b2e91b32f97aab90b0318a6be6742987eae3fda663b44812b8c924db6c539a63e74c1573b22b4b52dbb1d3a6e64c2a07248e0af5c7f446470615049e9f6cfadb2989eca66c4bd6877cdc4286f4d0eee92ec82a8185af5203ee8368730dbb0b9257afeca0a34aeed888672ca74b2900ff8204b8cad939d07df4c215732b11d4fddbf0fcecd2f41bc3028674bad903e4b0e2e362dbfbcbe471771de895363937a63cb5086678e3594e7c09cc29ae4bfaf2137e086d5d4c28a20aff0e24777f5c5aa0587a5a3e82fc009a9a873a1f3a06fba77772716228f1c7c5abd2a1cf38de455ae8bc2c5b08e9fd2e469c4ed41bc27de3caa3f82ce00d8f2d76089ba66d4f00d13d0c5c57287aa6b9fa1f758f8b76caa09b662964fbd719488ef500197caff04c751384a5a83e4efc7693bc727862c04231f9d1ae15b38e70cc710ce6d4521bf6e4e7b89c0b369aeb0c8c6afe240b22d814b5738936b6495f33b5f5cd4327e264a1acc9f7d2080038694af34dfeb4a69146e8b872917c6b5ad755e4338b3a191fd6ab53f465e571d18f5e8cc22f4633afb92d01a8408247e5449f3a41eb66c959bbb9ef416a0a790503f534801a95e41dcf8284b2ed1d91f2a4bf174d264a33ac7d82b188006c8510b0e394fe60b84f352c8f67029bdd15829bb65413f0a650ce13170c7a52d61ce26cb36679ddcecbfd34ca9a934bc5a801ffaa8b62f78a2add22ce17015ad01b06cfbd1c5c1c00ee4b7129ed0a142394784535ebb24f2028d9632d3743c63429e5aa5ec2f0bf5939632a569cc31faec9c0f962678c64615f7eede107911a7feec98884f94160e2527541c728e620f708b647d54d96e3c4e55e85807783df46bf7b5a9640f71c8ca1b7f35d369817625ec824efb6f64aaeb98a11f3d5197ceaf3f2129720536761d3ef4e0aa6e9cd6201b5393e55ea6570849cef792461ea65303edd41e202d279555107e2a8a81e135be8acef324c421d19335d1f63f7b612623b46a182a1d38e9f8e0475800e010f586ced1dc8dbb49751023ba70c27e4a7ac8c6cfc045b65fe54d7842b9eec6768d024670413c49eda57d780e3a745bf8fed7490fe974737a943cdbb9a1c7e309fc31148f1bd0aab135e5adf6e856af3383e1d7113491751638caf37f2ea9de3917e680c77fd255c9d938a0080bc9560bd889ffdecaaaffe432e4bc8adf53b0f99015756ce4c5e435094c5742e751526a59c212e9042967502a53cac0e541ac50fef424e7b19bdfde79c4d13d53e467892c91edf86c69446a5940ce242a0bdb726ca17945544e3979aa8591a090c27534cffe9a5aae4bf50b39ce66468bdfc7601e2ef9d47ea32f63e3a91c22fa4960332565401c977c98674d675c281ad91842aade990dd7325360aba6a77b60ccdf76beea285c15a22233906ce039b524d730af213b3c5139355e8572ec045d2392c05f0a1c82440b3df97b515d912de448646f8bc63a710dd7c05481eae14e120a25ce9490f7000d134fa9cf3e5904c7203137e5c6b7999d073950166a931c06454014f521c3c5280395cdf99786d0877f51f800b92774853c0f30059c8423771ea84e06bfba1610257ca8c989aa7ecd5e73def82b538d2986bacb6b0f458c067934cd29ad551ea422742c3e12924a7fbcf1165beaaa039cb5fbf55eb05c819ce95f3f4ec4b11d2c3655b856b53e106607f9e9c8cdefdcc88cece54b01c5f81b46146cd146b7826c7d9ad93fb9c186cb46bb7e258e5e83a905348171b0b0824e7aa121c53384844e542dbca334b7310436c0fe4d1365a2301e78f79c900881e124fe20130319dbce3d4c68b73290677495eedba5caa53f8ce246a400412f5f1f4be8b6f13f6e575c1571d5ff6c274a8064591eec224ca81146ad772d3603b10db186d22c6839597d89e6436fb28c4d8677010e7458a65651f928567d4dad0d28e1c4728f056dcdf30cea688d929f439986247e173c685394b07bf4b8d26e916874af3e0a6e650a39e2a3fe4a9816016d5aef84e3cd99ce6c1e93d7d56238f53ad78dc0f4c386a5c21d45b243902607a9cf730e4183518bd2d968ac6ca82b2fb67dfb2f46bde8478e5c10a5cd7167221e392f8478ffac9787408f35c64a3009e904186b1179b94d571a5e01d790dc684eec09828914f9c05facc660b003d1b98b9301d722f6198d040377f0b3e8000081676ccc0add35383e5b2adf3d3f8a461109e678e97697666712eac072090eb94511f3f97e905186cd32eaae0e6f196db5c1123437884480b2ccdbb95694bdc0feaf1f2391f020c9457b02d1939c83b386759c47316d2cdbe8c765f2e25df05995f8a3eae348d3c5609642417015d966aa991974ea66ff3176d08d00849d88808a21028a8b6ea396daa24d99330cd1d3f390db7ca46c0b810be0420ac4957a0e14a453225320501ca580345cb71b3b567b3e487cd764cf441fec6246e89b129004182b374ea4df53bdd15f4227dc88ae00c8216c184d75ea8aa4a5d604b0c4403ef80f42c7152bff9ba9a22d30e34487bf0033c21a29d6407154ad64e87e13cd4e2c0c6d0ee0d59421f678252840cc19723ab54803f1adb66eb9aa56465c079887d09101e62b23c4e513242dba9994dbeb241ca16fa8888617b6cac2258d507a4bbd8e428dbb8ec71d341c186257cc8c0a657392a239c9e2c15771d14e83fb8818757704d07e07887e106b37587cdf9dc269a007a31d5fab398ccd4a09549ab9718156a892aa82a26327347da40a065ea5838f4b208fcaa462f29f718d981253f769071ded21064702f49697ecee70965466d56f6c4e961b2317f379f657ef561a6d86b05535726e79cb89a6582ba228f29402913164dea1580003ea5c17e0bcf44a26d21dc189f1b5996351ebe9a9ba9eb08675d167208e1f7b8f3c655b05a67468ea6c7d8612ba0b7a7cdbcecf735568394b404c0266f480d1800e7935342272d346405ed2077d4b16529302cf50be2c4150a112bf770068914ed6ee2cb73b4ce68c80e087a31dcf01f53857ee3f04bd3d6385bb3fe4eb47aa682a9633f299ab45504fa30bba25a20181ea50365fee81889443650d29450a0329046b6fd2852c97fd42a8d6288a74733fb5daa8a5734901a1e8b0e40602a430d721efe6d486786ce9b85da93d80e8c0c12dcc87f72017ed466d1482344eebdb72444ee2da54c3205c10a8a091d0a1308cba1b64dc68eb0d714614bf5ab5e0e1d6dc5835a870e09fab0e97dfbee9de3d9e45bc132489ce3d1114e7ff1e30f3cbf6f228fe7348ed55471ba8b0716decca75e101c250c8f1d613e9bf0c40b7a03968518443cc142842221b0603efca00584161fb21bb020818926c876c08204ce5dd4576ee07e61b1015bdcaf971280d00de1d323134b99ea51a7582855d0475d3ae9bb4164e7c60e2ca3b1ffe43ff91f6a471dbd02d4e69c6d4347af002f4ee3a04038effb86fee6e104b1aa94ac815299e4df8c73f6c0b1c8e284216459c214ed20adcaa6ac3d928512848a7670430dbe60507c5005113ae860adb5292f70b6b8b1e8a2c5931f9e40825112580f561c618c0c0c1d72d87a10460cb8f8c1890d37f01026c9078717d20b0b24271886611804a6c082071f2051f485123e8412b0c801ab825a11461068b0c10b0f7c40a58b2864c000dbc1042fa31f54f811f358688ac30eb04ad3a04783fb25c50e1842083d5ea14165ce89655224ad70bfa4d062d24aa552c954a158cf81af570babfc8395d3b66d474cc22affe2b61991b84b8da37fdb5880f13b8f368ebe24b0fd7a15d5c0fd7a49c14f8750bd94e2c704710047588afb2545ab251936e84816fc19c5129cec203d4631466683fb15450fa2c892443d5284a31d18010544c85206abb528acb8200b31b4a0610c1aa81811a910e560ce395357c06c81c208cbb75108a9748840c83be79499084dc909657b944c53652050d1875e06fbe1959e11986300810ae718700f7c7989a832c5aec1fbf4522b36abf2e71bd65885e3c5994e5e3a70b53419a3d795a42cda0ca0d71357b61cbd9ef882014df11b29425ec54aabd5e1e4e81568e9538161bb10c202a0e8af4087e025136ec0b1044b107e94525a81a7115172f4e6681cf355c0b3051c6dfa663ee7cd1c3f5234d5e444707cf8cd99b95e20220752be1062092928c0747882f900290618866158bca1e70d3ef002888d0745d002872776488253ce2909a0c3133e5a580cf7cb892710c087971361d897135f946007a9c54910aa1356387105899a52428c51ba7faa7eea2e31eca252cf11720501fdc4169824a4a32d46af22a221215710d08fb7c024211d6d317a15110d09b982807e602b499118601812a407cf0ecef72a4be30d6d9f2224c51525080ad0931f9fd90a03e64b9217a42e475cb66831caf2ba526485a8cad0142129ae284150809ec81fe9235b6130982f495e90ba1ce1c8c5bf2d5a8cb2bcae442b18be4cac2273641cf20f36a055a9e7c0c7b056a95494cec7eed481339940972b68d950f6370ea861d80fb3a8ab2ab61fd288f147e3801826bf3bdfc02adbdd0dbd3b5651a9e774e350bbe9dd6982edf78657409fc6d1bf42c2c6306cfc9294f26569963efb5aea52e931997d2c956ec81c52874ddff44b69a5c280b319638c47266e2fc678638c5147e3d0c2c647c2aeaad8f89d819f4ffdc78170673103b2f1e96331fbf9547ed693bd7c2a367751cc30ece6ecbd2ccbaebb32170aea9bbe34c677ea39100ad1385429f78edd1da571c0d9ded0c334170cdfc6dbf48dce417333f5af1b626424f12fb61552cae8d0217c6c4305dc10e78831c6d88ee35f3f0d42ad34424f7637f41a6608a3c396d808c4f16626d82f74e853d8c611e3f412c4be144208a97cf83146195d89fa594a8fa671cc19259533f60d7a851b8d634e2d621fb10845504d1822125eb1ddf276479af50eeef9a7083d6b658c56222cd5186354417728638cd325ab0eee170f5e30f5dec6bdf8589884e49f8dbb5f292a65b15008ba7ed502d4bef49ce784fb2ecbb86f4c9534617141b8cb7de699ae474d5ce9b94c268bf52007f227d8ff86e14ffcc77390fc5d2e21fef96b5e10ff6acd1238ceb3d38b306dfd80f1561218a4a4a38c3e7dfaddf46b2398443d4aa9c948c42068235cbab9c91026d246f46256544158f82ecd4d3ba8f33bde28638c32668865308319cc604e49cc331235ffba6191c7de4e187032e45f3b0cfe3915eb5ce94df533cee6f937717f1edba1e4246e9e38afbc99480a639e39a9fd6da3b54b395b7677cbee38e38c33ce39e7752fa2e085ad31d41b05a41217f221d991e5ae78033f85969d0f1f7ef11c5984096a7002777f1912496929ff2004821204e4aef81e04545d5268201272f9073f432ad65d10097ae9241c5da631e2cca49765524a8a69190644624d85b9749ffdc5a750662944c77cc8d938e263790458becbc611fd739904991cdc638cd15d42f7ee6e82c148c559d3e590869e02f78b065ce0eaf0ab77a418ca17f2414b4a8fbdbc13a09fbd054a8ffd122a42b02ffd92ece92fb9b01597d09ba16083758c29814ce800c40f2bfb2aa9bfcf9f71f698b3747bbc9218af0a089b2110108540f1e6aa58603304a28fbdd35f82fd5c42450866fa55fc25f4aee21582bde9b1a75fba4bec53ec210a4eb858a5a75fa262601727de380b99a784092c3a4a428845456585092c42c207894505aa9480503c080bbd4277bd826b627705e75dc1f916c03e7b0bcca793e54a661006146fbc95c4bfde02817a2b02b56861f8ace935cb814c4bb877b7673de7a440d8ecda60118a63d21b8391a3fe61de0e367f37b20da689db8e4c857d8ac2ed471388336c8ada36d555f686e794aae9bbe3f4ad058861961dd91eb44ac76d9af7e8b0e96df60d91fdd1f7cc945d29318d086dc77322c690a27cdf7c4079537e63a39277020725580d840314d6b6040e9660d5504103ab9e208955e32809563f4ed4a971031a585dc50962c0eae7893a359a3062d598020c568d2935b0fa87449d1a47f8b0da280545ac0a861358fd45a2ce0c0e5ab07a0c560f01074fb03a0b568b210410c2b0fae11735b01a0e5181c2ea87425147c715376cc16aec0a56aad503ab1f16451d069c008a17ac6e2e4760351080c06ae824071eb4b01640469820b0ba817004563f4c8a3adb1090b8c2ea8760a2ce0c2bac2d095b7c60f5fb4fd4b1f185d50cd0a18b1eb0bab9d081d5efaea8d34f6869620b963ff1a18b18b01a5e8185cb15ac7e278a3afdc4d018276075562507ac7e7f459d28041a7c7e585dc760758d82d5375a2005ab511083d5ef495127e78814b0fa1d4cd4a1b185d5363becf06383430c58fd3128ea94acb04e5a94f8c26acd05464060592b395ec1dd6ad5d062e598c5b672d412434551abd58223b072ec82f918b5688062c4cad1cb5cc2a8d5e202042bc72f9468a8d54a4207568e61729c50d46ab5845859fa401a865a3e43706165f964fad06ab55e50042b4b2825318c5a2d22a22cc1a8d5ba8207569652a018b2610b2c7260653905cb51ab25e50656965588306ab55e70042b4b2b520747add6105958595e916206ac2cb35001d46a4d798295a5162cad566b4a1656965c8060d46a4d9982956517295cadd6942fac2cbd4cd751ab65840f2bcb2f9507ad56ab0824585986d14ad06ab582d0032b4f9f1db45aad2d64b0f27c5284abd532e28795271428865a2d2a62b0f28c82671449ad16951e58794ac15d049ce794c8c59b121105064ab8683084137e68a1e086ee07a024474a10a3862dc2d0a2450e48c440e1435f09e20b134e98f8011440604f4a0003ac8a124cb181e27e31618299c54998cc09866118564312a4644e5c590d4a603e3870e2653a6902f37182c5886c87ac86221f319ca8c009941a56e083854fd0124e843003ccc70a4c8ae924cb747202d30ab61ab0d87c98e0848b520d5e309f273024d42838273d30dd60d2a20626947cbe2825ed207d8c40392182fa184d2758780d48d2490d309f32680d5a322735d48004adc2e704196a092c2b4a90c29ad86ea0e2414703550fba329ea072123334c1dd2ae6e177f7f5bbdb737aedebed89790ecb486c68da69d358d0fe64e266688257a8efb1df3dc779317772777eccf7982e1288ebd7fa266f65bfbe49061f9a0fee63bed63aa36e35dee4c1168ed15a78f3f29199af41e36df733347e06024d5adb68fccccc8c47bf763450dbf7a3be7e4dea6b6f3dba4a205dcc57cd43691705adcd3694d679784b79a798467d95b79bdc6bfdf579220daf717b9ef5aa97a1501268bcd2ea6bf5b91b33540e50a8dafde9f439a6c66bd7decb4570e5acbdb948cd6ff6e65ae365319f9d22865dd73dcab35ce5b6cf9eabd63eea3b7b5731319d8dd96e8fc6797b24367077572894e5663c279379ab1e8d536f3fe6372f23b181eb5d71cfd53ae3ae667cf6b5a3a152a95434ee6a46ad3277d575d90ad5dce937191999e7644ed9766580486c60ae7bae7b8ecb2bd423b1814fbfea90d8c0a9bbdab2df32eeb355f7dc67dff6ae50b747e355ea7b621ef5a998477d4ccca3503116d5bfdd1e8d4fd77e67bf7b6bbfb3dde59ef372132b57546ee308198d1da9ccb22c9b32fbeac9995189bdc96b20d208c43e661018f612a9c2cd07166594df110806047b1963bcd9b1863bf8c1f027180c1f8b3ee6bb40b38b4120d35b09e978e3f21e8138462410c326d4593ff328eef0b67137f372924c71a642666e8d6c7bcdeb18176e5ea279a8d7bc7e2de6ceb83083aa713bde7030cb31cca83f83665e04647ec6631e90eeb7afd0ab368a4a6fa3c8bfd69b9b208998fee6ad7cdc9e52c43d343e2b7de5beeb7adbb29ff1ead665decc0cdd4cf79907b9ef381fdd73d9e28c898ffa5a7df8dbc60477db37ae5f2fc775377fb769db6b703b3dfc158faec77ee32311c2c6a1799ce7318ec5dc9c3df7ad3dfc2c4391163e126b66840946b1e038f38c408ccab8ef47fd8c77243e5cf9b83ddc779fdd1eedb7245d9793601822f5aebb5948d73d4fecbc0c5bd87ef5320cb82d77336cd9af50832dcbd16c07ea65f5f2aba2f5ecb79b5da8f1db6f31a713fccdd3eefc2ce2d376a7e6f59c2e1288b35fa14ede0af5d99fbe5e197c74cf3deafad85efb2cbb4822ceec0fce6e0ffc7ed8c21a677b647eab3f63860b333366cc98e1d1cf4af565bed2e7b22cbb19e2da5e861477ab9ff92cfb1a5e6f40b6ea75f576bf09e12ae4bcecfb67b84a5da8b1c9788d6be94b5fc38b1b10fadc975ca871b99bc84526b2373d8f73dcc3af35e67b8e445ce37af5b2ee6b78b546eddf8a6054cc968f64db8eed396f957d97f1787685d4d8be765ec6715cee3ea37efbeaad3ad40af5fd32df7d7dce5b718ffa98cfbcd5e9ed675f65bcd4b6552ff5325e4dd5cc6ddb738ff2561beafb538f7a6b7ffb1ae3699ff2627ee5cda43c2d06e5c9004f57c8ea57ddd7f899cfdd1552e36736eb75bff2666a78339f79dd5b2feb4d488deee6263337dbb4ed884724e2ec22716c4309ac09eb0fdf48f64fb1d62a4ae501bff4b5e4d54e48295b21f6d27853aa9f6d6ff2b8bb7d7ccdeb29bde94f57156f4cda735ef6dc9b5cb0b7238d3726edf6946af7b5a4752e9cdebee6753727c10f79e2f6d27ee769dfdd476d092e7d73df516e2e9c6ec79b8ebb99892dddedf4ad952a8f92e7037ec97a27ea82fd936f3c4a3f6b12acbdbda5ef2fd19c04e7fe23910eb14bb0212a0ff826887de6955694529e689ade95b4a7268ee39ef332cd4df0f63909debc9ef9be65bf651a7dd373f44d4f4ddac5b6db33bf6eb908cef47b66dbb671a026d99163c0d8e72218bb997e73df83bde9b96bfa8e01675fbf1d7bb941a0095e75a6ef4ccf5d53fbb7dd9b99e04bc4e9a58e3d5d7afb21967510f7b6a374794cf8990ff8f3963c8857a65ff9b8d8c49e2d51b7a75f79401ff4e13b2e79f9c31a863f4d25ada4693717f91efaf135edb5dbfed5eea10fff74fa7af2b20a9fe8d7a89dbc06d2bdfd9277bab9082e55d5e312f7f2e310acbdfdb8eda8df7d8c77ba9989bd72f3e19876d7f431a51ae371f5e2ca83be0ff854f3aac903a27dcd9007fd69fa7ab3e91e91a5928f1e4cf001302feeeedeb50df6ad7910620d279401e2f852cacffec88633d99836bf62a68961d83542b33b03f63360d894917a0c43a876dd104a2803c4fef1b13fb2612cd29f5e9c7f8d6417890772130c679833cc4772c2f3ce00ffc826af1107c3c33ef6d682ec913e9f05bf0d53c8472046e23fbd8629e0e8829a24a043f718a59c13c3324a4bfe512ad15dde4ca394d11d4aad524a391ffacc4d5a18c2f70f2787841f3ddec0813b50d4b699c1ca145c7ab9054a165cfad209c3557c8927865b32188768290e15c5a1a11987e250f63568b08da314fffca97fdefed92d72cb9d9fe116eca85780d86112eec691a11658bef4f6a48704627a73fba77dd98d4798946a8306b604553318d2b6adca703fd5fc53f506e5b7bb175092a8e76834bd83fb5337b04fffc3c154985723088bfdbc99f6883a4d55f87495746f6f4b2e36f76b02bd820c1070fc20bd02f522bea3e0c5f2f817ff42b1f187449d8e415e9166c8e67e0d7905c1b4927743a757a08ec10d48f6f2d634c1e62638cb6872608564d96d9b1e4651d5793bb17ae9e75f5954c1a67f6c2ad53719cd943e9f4aa58770276e3b7947339db49d9d5ec171e95f88c173e2973e01ad43e34de96d13a552a9542addf0aff4d0abf793a7496347ed665aa2115e161e9bea4308e3f6a3093679d2bf4ea202de6067bc7400d4ada3d34d5c83de0f65613f3d21de6261df5e66821b89c4f3573ea00b4f29c4b2b039e52502c3bc8e37f1a64b8c3addf166d88addb171b401ac804f98e8934e13db13bf33ee221d8630c49006dcb73d24b2850ef767f92b1f262caf912b300ece5d06ceb1210bacabc0426323b00cdc6d44766f2c50ed8533cd6b074838ab6854dac9f60a2aff3aa8de48c10e58c01becc45db443165f149c35ec7d053eb1f0e59d510bc0c58d1e0a40040bbfb5da36392bc231c26d488e4038027928f0f78490d2c60f16c3cfaa9fa803595a8df30a8e39d8c679fecca9ddf9439b5a193f3e1d22a9a492528993c373b2a7b452fa254c353b7fe68fcd8ab227f03d258000d0c5ca79058531ec7c41f8f13dc720a04f02277e4ae5396129009ed8f70fca1f2fc31ffb36b039fec420cff1279e13dfdf15853c67e58de1ff60f8ffe339fefd8a51081a57d81efdaf69349988afa5accd9b70b08fbb0847881a7c7181e784dde9d18f43a343759fc63fcf47bc4a1370de91b2fd5f08ebb9ecbcaf9ac2e66f35bf1ff03b6e780eec07ecdf63becb2fdaf9f58d63c9e2c252088c8b0984e5f4a1819d3f77b600f0c4629fa7f7640a24dc2f2c493970bfb02881bd28ea74f424cff9e239d8536aad4af59f7dc99330c6f82c60eed1344deef14449e341b192c6e873ba43b1be333d27fbb983f30c4df24ee6e520b2133774d8c05624e227bd817d9c77200b6cb6d8230f2a9511a4607f9a96299bf96d039bba0afe190faa3f4d0a435e09c8a6704bf1830d70c0f862849f1d0ca8c7173b3a3a0b3684fd69686cbadbc6a87245a11f8233b0425f7441cc2dc1660c0828eac496c4801a03c2802612306582c568c0fed15f13a971fc7847d88c8393031ba24540571c1afa420bf64f55e9621176e872211f7215fcbd1b6c76210b7d0862e853a80c611f5a41c83f77a1298dc387a20f6c8e4371c8e3908d2245684a169b5bb168b6aa0f95f9363c0bfbb611b28408c75fc5c07a44fc359fc8c23b44deffc1c691cd2aa3e789371907e70b2bd83f878a46472aeae0dcffc1661cac81f7c17616341ae8151a0f11e239f05a213635a968a9c0b8b0bf121ff9363c8b3e0621ccd8c4300cc3ee4ce22a804912755a9c183653087443f5b1e16790abe02fbde97215fceb0d6c76232ec95aac1575e43bd21637b253c8735e5f68f11c0f8a32c5b93061734cc2fed5b760376a1cfe52e6f862e1169cdd08c98de4c55aa61cd86c53d95114b66dca46f3a1225f95020c6cee97e5c2661ba5b0d94ee1fd1042082184dd72f6ecd9b33b1e51c28521e7c3a3961747d83f55e408f491574629a38c52ce38b18a6118065d49112fc93dd247b08beb7ceba936212da24256db7047b0340cce30c8837e9e508d0642894285f5f716ce306805bfbf0a2f84b03fcf8e0bfbebf0e207b3dc85c0b9afc8ff6c3a1fd82d7ed34714c926a97a00e65b7ed33c55fcf80d069c80f19c24f8e0238e6790b874c2400d40b5f2c40a352712c28d31d0b2e2397d8597271870f2c573561870f225eaa0be7bd95ff2eb8eac8b78a20e8e6f363552d8fc7f6505406c38be6f3e6a188c79c4255fb00e143086cd4712c2fd42e27271bf9088f0c72094e765e9674b64e1e72560b07fe45183b1db8d63debc2409e725449888bfe21005fc3a0d540034c2a25aa9c23305431d104ac110429d4fde07f0d44461db891b965094420bb500c718a54c410a9e7640eba85a075509f46bb0bc9988bf70bcb4461296c61b252c8da276d47126e8c0e5d55852f033c452d2647c91c31616930d08b6a0f809623181b003b56d4cc0840c8e581546814511ab8d78a084114b053c60e16209c065049722569d5ddc40882156c54cb04412ab662ae04110ab9b8002c688d542b0c16788d55f04e1082256ad5af4025084a41b92584a04d022a208442c260bf029c20fabb1f0c20623d6f7050a767f1bcfa1c1fed45ff3af2d27e5552202564361042d7e586de3d1871a1920060f492c252a5811c6118b09aab5c5ae8448251e049630462c29fd8bb025bc42861118575094167c253d7a83a10130a4b67130411404ce1667095f46081d32a1b60d2d515a8247248636efe0ece8f01f9e03b1a79023855ec133d3f7a75cb31ff4e4767568b7fdc6e10374f88d27a015d0381e4feb04ec65af5083fbb71da58f1efd92e7a3e1675007bc3ba723acebf09b1d1a50b025d4b6f96edadd6472ffee99be898ffb73e933897dfaac61449f4253e9a6fc939a855f189ba9dfc08fa988fdaa1a47b4c266faddf0bfb468e2a07ae907ce340e7fb8b1007deb4ef9d7051715f42256b547d7a9ef697ed3ad00c8650c9c1d6741f8b0858ba3219c298e9716a17295ab5ce54fe3153aec57173dc0ac975b64caed11f6039d8a4aa148e44352e89314abe1353affef31f9ec43ef51a9f9f69c9a87b0a606974a5a95534c2e29bd42728a7f9e9442fec1cb43c2d2974a39353fdf8f681d2ba7749caa79a5506e304afc9b9fc4bf195f06c1d02b34d6817d53f3b34b566a3ea7bce6b367993e64e3fd08147eba3fbd816d024f14bae0599ace05db76d8a8f16abeb71d36fed53cf4e4973c16e04b1ef03188829721aeb936fed53c8fd7ac6116b96e1c352fb51a221f721b5658d3ffc0ade636163ff38691c34ed6c6dbf879e239415127c99c70e298b88753382821b5ee39350fe1eae1b683e6874005603fdf850c748ee9e767ea7db618d5f0516ff2627ff0318f0686ff1d84355e8e2f74d212c6e3317daac18d855a9a621a1212f2a12a442f37f22d6ec5b3b8162f9a9e93b10fe2dfec998209492121cc83b8cbc67536de8643b75274c58750f81a358ff6d8781920aef9209e93e10fcfa1475a2ad745f1cf6a5306c9201b33b0335ef5331f5f0a094921cfc15ec7fbf9b268d69f2fab78ce7605cfcf320b9e443d1febac149242728a1c62c1b124a2c9a7f1d987e8cb8b04d2fbc33f1b354f1040838d5d3cc7c6cf8f4851e73f3718e9aa79d37ccf931b0268b05906f504f16ffe11887ff4c8284151c75d320837f42af3a14729b1e9e62518fb98e4dffcf7e217bf99d9e7f6dcf322cfadf837df5d13859b29ae71570d2f435ce3b18d4786b11bc348b1f0572ff333de87b46cf19c159793ed52cfe334980fcda743f2ae543ff3b9c1dc0008d702f73e047f760b1c1288e5cdda97bed478c653d1f088f89fe1c9789e0c30c6cb5ae643783eca93211b1267d723eafc9ddca659f8df377de502c8416d1b79b2fe4de95311b083cd90c8debe90c8b30f3de939ab7879c4b76f79649915a845eb582f30169180319965df798d136fb0a7168b5f33af6b11cdf4321eec9bf8292fc683561a75ca2ea47a94274f39822296619909c7bfcce413630cb55608f405679969ca2eaf2c528be422bb74af2b451c07adbd48208fcc73b02dba544aab86f2a015ffb0c77995ca62367c605ffbcc7f8eecc582fc27eac43cf60ec573a2788efcec841d798e7dd4634018f3208c611fe36547d4b60c83b3f7417a82b39f5070f676fbd104a3ecad5de7446cf0ca08c4a74722717c231d8ea887017591407cba19da7bc3bf18fcc39e03fe61db860027367b286ce5348c728d655f3b9e7c3c27d3bab6297af705ffb0a71a3d71dfafa32f3843220989b85849ca6d74c57330ac888655cc84758fa5fc9b10a848d4517552c47060c0bef4190da1b044cbaaba5ff58924f19cf8f57dd4afb5d65ac3e0fa4d1fd6d7d115dc5e70bfb2d8822bdce6170c3f460d7a595ec1b008e248875863187d2638bb32a9be464fa9571657f0fc1dcf51f1788e7ffd1e5555359aaa5458efe15fedbe81945ef93d6afdb6a9b707b6b0252e300327607051c51554848912813862055bbad8628b11c48041104198c11170f02148881daaf051c1ccc28814203184215cc9d283186300318f3065052a3f4f4822cc183208c2420339ace04b0f2508eaa10a96021370f92268e04cb1e822bfd287d269d432460361c4a8ff0c4db089b5d05af0bcab161cf3386e8241cf72e79c73ce3c21c5f36146fbaee4cb246cc00afb3766d89c73ce09348e7e991c6c8c3d5b7ad1b7146d79d11d5e5b68c1bd4516dc2d01937c93d79b04a8cc62fc58a2b494655966929b04fc8bab52896634e062bcaa69b6b5afdad7faa79b93606fab45f0f6f6330ff59d1773aa7faa9f699bb6755e6e125304f7ccd3e87e86c6cf68cf3df184c6411a35be964a5f4fbf51ede6ed2bd7695fbdda6d0fe16b5f3da871a7aafd8909e65ef37c701f03bfbb99d6705caddc37d6b6ef3cce9ba1098ef99819dcc77c6f5a0ff68dbf4298bfc678272fd73fc9a03a542a95abed6eae1f83656ca5b1b57e198665d8845de68427e88261199c451815a51a9e0076d12ab53f60aa2382e1cdf32b0438ede38cf7d4335ed75d8d4b693210aa64361a3366d7fd065f06de4c24055393d31ece7ad2b4874422707af8dc77deeaf4f5bb6fd7b4d5e9725fbf3e470477b0a630f7f0747bb6ef52b8bb4452d86e3eb6db2a1a57ce9832a914d4b40e7615c22e057f42a85d6ec26e42082184282f13c1288a632c8e89f91a73baa70ff51c17f3a76fcad9989f93a6f0bc99480ae56522a98efb69396ea6344efbe9715caac3f3bbc97199480a6b29f88021449a0834006207a926020d80a08208462919341428385ec16928500e10a1409161a0a86cae58e9bfa3809e9ed669321675b279a1fbc8c5a44cf6a22e774f73ce79bbdae1a8a2a15aea53aa97b1aa4f69dfbda6c99c7ed6ee352436b47a35cd7efdd879b9ebba17509db742fde93b4a354d5ba16efdd39fbe3ef7272fbff0029e9afdaebb446cb8db23a379446cba4bc4065b1999542ad5a53aad6adfa53aadaafe55afa2e9ba17e87ff5476783e21ef539aa5da5ba99ce90b9a993bdf99ffb19af370834e11ede6c83b99b89d8745df7bd751de7e5176c1e431a0c6930f7f6db7354d86bff50a9d4ccc39f79eba1663e26e6a2ec678feaba1770ccc7c8e7bc8c7acdcb2f74977be8698ff24e27cfb166d3a3bd041a732fd8f080386b3df51df7d6a3b14d2662038548f53b48e0e265b383042ea4a0368bcddff78551a1e70fdba1cc44d052e7b7077fe51f83707c611eaf3202e1f6a3f8ddb862db8e9ed3ddfdca7ee9d0fd219c4d6210c4ad1939b09926486e2d10a778800a683ca1d7dc10ac651b9a54d6f0b77f98b3f67f088637737f02623f88d6533ffec7496562a6bdfd55894ff1e5576dc710863fc385e1cb7cad70d6c80186cd45f0f63602333ef5aab740e055f5d4b75f3dece373430061ee51588668e1f9337cc4fcecde7e05f290831ce42007b99f0fb98ff172fd917aed2377737cb1f36bb511e87ebef6a7b7945abbeaae8fd3d56e1e82e773f5b31e10a7b2fd989be38be5b8db937aedf6a09e7b1eafdef4b2bd443e9c7a5444cd78f8dccd7d258d7b2462998733785cc6cb4cf0b4d23f0e73af453c2390ebdbe7aef4efe625986adbb6c3f44022de2260aff48ffb7ab59be11f893be66b0fad7fde839dd087faa64fc2404c587beb0dc1311fb71da6b6c11c4d4e61eedb5f7a2af5b6dbe9db3d4f4c7d90edff69a0642490d46dffe03545c0f4d56463eccb08944c9ec5e202171ce1fa36428ff3f210cc7d47934c8cea3feaccd030c9a86e7eccd1b83350375b999b8ab9f99f279e3c2410c73ce765d467eff6ebd7efcd879579ce47cabe7c6e0886da43eff4315ef78e4f5e465d5a737dedf49c37c487c675cf133b2f33c1f56a57fe87b7979b29fee4264343b0840800220b128edf48208e3e64acb0f99f86d34082111536f70bfe8e0e1e8feeaf84a3ce6df1bbd83d957aebedae92be4d58a62bb59b8fc4a01804c4bb441e2250e4e19b51a21882168c833b8a214809426afb90d5316f9f55a800ee4d5b3ee2700b6c6bc184bbede7c642f7f4e186e439d86f2fb71d5b103679361fe79c318495dc4ff9dbb7a4bf3ddc1e6e011500f1b67ddc766c4d7694baae7b16fcbbcdabcf794db0c435cb3cacfa54a27e663fc76664b1b4c78f209e331fbe0e16f59aeb344b7a2688e49f8ccf04671e12962859706309a20b5e006e2c41bc009f1e7af9886f9edc76188165e0550bf1edb310dfcaac04fb5b8ffbdebc0976ef8863eec22d600a5a15ac3d4fdcfc88ac127fde8629cc9743fe491f700b9882fcb943b5b63d932acdbe09ae52cb3e635a9db89a30186b0eff6edc10e0868773d338fc336f003005ff8a6d3c20748f374e4f320cfb52c55a0bf1b3cf10630fe3bde11f8df76b1c3c7c45b388aa695aadb53ed5a6cc5efb1a3dcd93d9c758327daeaf51fab546198e64b8745be832307d235d06ceb2c46e8271082c3070cdd77cb09f0f1f43081bba3c1b9e05855e76c8c6095df1ca30f11109b1d80c5d2f03c42e1d58f80cf879d67cfff7b781d3e61bba54345909be242fd8ff864dd9e4584db12f9b2d24427e5e6343a737a85654060e4e5216ec9f2388902e3aea9bde2524e47209b9a440178ecbe58a49415651d8243c858868ad120c12f2cf8d8ca04ba607d005849424c465250616167e4c7a127bbc7afc78c0d10fd5878af419b5ee1e416c606310608f30ba60ff1f3f640f56f3cfa6781e8025684a1ff578ede8c83255a881cd36017de34f593b8dc38da4c80115acc900230e6ca62d486db05118f44d5f4d1e863ffefdfc98624d0aac114fbc811f05fb13ec57608741a28e6d1fb48ee91d628161d185ad7ec1332c77c9a8a5fa968c116cc1a4cc08368ca01bd9435711ccb3e159548a24b1f1163902049b3ba9086c9e8f3aa55799262cd18bdd8e37f9db51a4099a8b0a55183e54a3a13bfe2561338d5b6cf7079f8c2a5d38fb910c024202fdd01f22ea47447e9421911ff99117ecef5ddc0b9574c88f2891fcf123223ff2a3272da5ab8bfa72c7e3c934efb8c7d71be1fc38f39ab08ab2ec2ae97893a3500c6ac28a40334dd878e54b62c1ae2c8a3744576cde21a23f06e5080494654747961865099b77e27b32409c77faeb5ec2365204f2276ca6389a3472c7be4082a14a10215d62908b0ceb4f630516c628d115831ac74c1376826142e3f0998414dd592e5bf18a85374b2224dc464141f3c8bf56bffc7bfcc05a3d5430ae42eb09d6679eb0f0711cccab83b0bfc4c971251e6d61f3e73f5bd5874abf0dcf2abde69f7b3c5e0f256ca6168a221838c00323f6b1deff82fc117cb0bf0dcf03b4dc20826a7ea38ab7fba879e2d314451f30700073ec042d4ac148c2fe5acb070a1582dda14f6c862df8b303ed1476b6eabbe969bd41a2e9be406fbb7fd65f94f0cc9dbb53bbb0721a1164084c0f2ed8ff07929730ad658b43a65716a424239b61bcc2e608b47df7a7ec43d14571910a84bd077424ec434343eefae2d50822253dc6c1acb77e1cc883a0f52050bc29e2b697ab8bcd146b911221e43f2fa129561c0a7c1b9e657a77a1a12c363798f8039bfd487beeb3bfb68fe1155f18c78289ade8f0667be1960c07c38144b6e1e6258937fe9a67823ff1860b9b29a65a12f58c09306058e9a29ce8f57062b7c4de1277b06048699982fec91dd8577545f6937039d0904b4a15a3e8452b6c7697bba45004fac1591205cd90416404042a8c3081135b8001f4431345c020c51006fb13f9b2a323862265d84cb514582f5d5aa6a0f4b420db02a42d43bcbcb0ff0b54a3e932c43f57c11f853036d3a8c5669ad48497216fad228c9708ec9b35b10d88ee8e2a15fc197498e7f3b90afe363c8b4a868fe3dfd71e4e7ffefae2dcc0f95c857e1eafd16b6bbd0461ff94a4f24694c1c1e6ef7e9fc5e68ff6f7e9b8b9af7cd8480b0fca947ec1fe5a9047f129290bbff2d830f66a1cfe364a80b9a20e46146fdca3640f92ed4921a2a82387a4101196539e0c2baf0c722914848786a43c9248f4775446b082fd69bea688a894ad7585452d11d10c0000003314000020140c094422c168241a536565fb14000c93a248745418894990c32084900100100208000400000088c8dccc00bcbdf5763e6c71bb01c0cee3087158de58af47fafc668d52d7008b50c11dcace6ef541765362c9b20775709e16b79d1e2c8ca5fd113d585aec72495f95a9b562d016689e6e6d922c58f60627a7e5170064bc88a92bc017595dde71fa0805c6b5fb5338e888b1ce8242a363b4dae59a0cfe25656837fa81860b6dd383116b0544ae81af24ce2a5bafdc4a8308f5741483cc46319365a504c6be0e5bc65d12d3daf2fef471af7f1d91f59de9ef45639e56ab34d38417e9494cb508995c9744f9449a6a3909af86e09a94982a0690e6e8c28aecbde3bebd5e8a9f54cf5e83dd01c61ec3403c0ffb3dd6b1f750f5ee416ece557ddd8b94243f0ce583c9acad7be96f3249ed9cde7e4707c222cec723d0bb89738586c6904206add0bd82ba833c64027d57388382da5eaa8340c150adb0b3b07b53699df40684ea7d299eabbe986c4f7d87a0c0d05cfd008b8dfd5d85f6025c6f6ceec522e21b48633100332bdbe1040cc59c693db8a589a7dde0c756affd0bc1a6fe293560497f05b6f2870427302c2298b9c9dff58a90c1563f85691b21146af1fb6b6c2f7efd8b5ffc321fdbef62171035ff6cc51c694ac1af619b8a96c0c9d84000fe920376504d4acee79413ba024f8d9cb34fbcf2da288c33154ff8e28d18176376dd4c91a0c3e4969c85ceb9476e2574164263d7395f3a9fa3a7686eb5a79cada1dfdb82fffc84143d670e47677262eaff857ff6532badcede4f8f3ebc0f8aff899d6f4b46d11c8a819d0b96ed2a7898ad8b98a6f6965b06fe988f04efaa17a1520d020ef7cd69d983ee35621a4ae0d0f997742e366d3ec9c6179193ee51c54aff24ad0479472076105a47773dce41488748fb927472b8eeb82ceb988796236ab76dd152ce500cf95dd060a41556d6e03ff9323729cca2f563c671790b4c4335e868ba18d520c042d23214509e5718dd5e9a6a6b566be52c1852624b4e9a721df7cf094106ed7919aff9f1f071f06bc886188a6388081bdeec4f752ebeb2879cff93dc511e1fc92ad38a3511a483f971918cde9ce732846bc7cfb927631b868a5571f61539dbb0e13f71470ae4ccf9b0769b06edf3311b561bd0f337c9982c39a77680f6fd7483b10eaf55a387369f519d6ea5769b0fa9a5b6b0216d737e565404e89a7a8625a9343e25f753b87941f2bf64f38148b0bc512cafd94440e136ff4c6901e8a8ee9e1fa149503e02fb40d9b1476046497a64fea740bf5c9bffb48fa9756d1e32328ccf4af0be8cae66c24fe16e3ec865fc28df801d155298633e82815a526e2f779ffa687a0ee25a9f2f15c9ac3c0e7a65266f3467a6292e638f1ed0745895ba109b088a6074749acffad589c30ac95b854add954e3dd31e384c874ce359f09ea159a19feac963e71c660c392a1873510eea586f5504ccbb0b53fa2c2ab43d3cfd85a7aaeeab5785cf7715c6534b1c23af9b221e53910aa53b475a07810bb32476b1e6001b5817cb5c9b17c719a6736118962623323c10e32a486a24fb9cffd444c3397fca3a52cd70f0bea66e38cd39b1fbb6e22acfabcc9ba169e7e45f97be0e9711d0337f89ef6340cd72ab1e21e29e81a0feeda5064feb16dfb9bd6b128c405ac79fa01c6955df03f79cfea36f52f7079ee5b4d1ec9d50f149f1c0f6dd86658f832d60e088d234e3860a66423b3b9be9cb60d3d3a2451371c8bcbd32bde333731b619d906a8d341f009362dab908ec4980607b93d3a94001305c7d0bd5822e959bbcd2868fb30ff3b0dc88b74dc559a8f328fec37a1f39bbd06da88a34b31fb030b1e5cffe26e22af74b5d1e45a689c9811d4c58aec15de935c61d40463f52c8bf9b1330fd0eac0cdcb096a69c0766b745a810a546f79e91cb3ec8fcdebc8985e2f7bd05cfd34ffa1b62dd312df30fdaebddefe3d495d032dfc4496398498b61ae80bc23e89e1fcb58aee1052ad20d5aa1cbd0993abb70fb21fbb735605ade496bc58b80d1963aa41803105e44a49e782b48602fb8a26697874799b3c4a71bcd2988d8187643241c341a6166f07156f5b41303f713d488e69abe29b2d413bf940df1e7f56c14a7959dacb56df8c9b85dfd5e4b14cee8cf8a565d3f9fa11d3bb9457a3a782f12227d3ecec7b87b706c9135bad7415c47a48bfc682326992b439349301585ac1023033cbaf14586a7dffa9d1d17bdb975cd7517aa8c37410cde23c208f28783a0972997a22f00fea8051609f5ad58e1d8b47ad8ddfe1c64ecd3a6a119e75e2a1004b24f15a613991bf90411eb3461a34ee642dd4a4b9ed255e4ba05c64ae9c8368c2ab8c2c39bc6c44bca8aade4cce4235c2391de27b35db5d113c27251a382e4336fe64804d8ad5b13f161233d29a034d2257cea0ea8664e0d4b7662530a2d4a582a7de90239e8486faf5dd8453ef9911ba36eaad8631a5131319769c4b0473e57bb92252b6490c1cac908bb23adc8a9e830e91abf3a24576d7ebe5d8213d8ff942ac1c5c074a675942782b2ddaa1cd08605b3952af210c2069706d119893499d79bcdf9018dc59d72754d0e398e86f3015909e70d13423543ef2782ac923817c9059df621323f33ea39e7e5b3c4c1f614dceb990ca6ba30722ad6a7e183dff41f72ada08cb49426c0531f8c37a211b13d1b5ce424212267ab333a4fd7c9819b40bcda9d15516624df0a46ad4ce98e0e5eb5c8dc636fd0d2d58ca86c3ed73cae0d307d72b8d703922c848148d41040c6e4e7a1f48192f34f5ae45f79215c30df061682a07c3fe089f2b3b6754cf4635c5d0cc6c70501098278e8de5d29c8f0c6381827bdca12bbf22d84217eff3f7404ba81ae8afdcb818c64d9bcdcadd521281e284adbf2cfd9904696189b8e11a370e9c2fcdec7b08287d4a26ebb8f0b349121f2b9165ab0602a2a0ddd4bea3ba918c5381042bbba75d0cab849d66b1851677f2d80ec9ddb9d3ea4980451ca5baf77e003fb8a0177d2a4505e439f5cafd53ff5dd2073e1150bbf84366d79bde689588fee9ac52ce67a67446aadf09bc379cb106d1ad60b902956fbcdf3537e9309dab6be41b135e86034955f0a108bc753fdb584fbe2dc2fda70029cada1a8dea300b986ab35f26a03ca6853829c84cc864ca023c3d26752c1a2db0ad89a52ad9e3932a3f0a7bcfb5faf5c7b9a7772b708dbc86b2f6a66e626975a836d85f676f12e4c2227ed68311f29d812191224f0517526739bbd30cbef7de5570093dded20bfa76daef648e194abccde1b8f0eeb6ca48371f62f25929023190d0981f7dfa946767405ac0cd840bef0dff841cbfec4fbee1913b65405b751e6c103957595c9b2024437de8685632aefd073825c6127d4bfabebb3fd24dd3337302a9e1d7e48a7968fefa6b015bea15f37216868eccb46c37faa5b790bcad875b6c98d3dbd9fea891a711a50f77f2399c0d73ec528490bc1894b0eef3582d5f9f12c76f80e10ace64b4fb189b09d1f3f8b397d0ba0dcdad2f84c257ebe2313d3b7e9b9d2e98cb80ab06d8a60738f2ac258a52747b5fd0050167f5efb745223e512fa089e6d2736205c34939f8592a478e94feeddae146de36c96159713b85f8fe6eb75611f3a376884071362c27414d16bce21c536c7b2d54e2cb5d5c94401091f497d088d88202bf9409590b3f67545145e7816932e7e7afe262efa42c874d4c136b94fd46ec2d565ca8acea621ed3843e4d59bc831c4d1d554254fcd417ea6d0224f7ae40fc02d4fa587f37bfc605eccd990f8d1f80e95a4f83a15f4d466f92c87b1372befcf7ff9bc278038f2aa00aef575bd28045660ed57fa98d93bada5a14562397179cbbb048769f7bf888d8a8b7fc6266551d8c396b35b82a09c8514edb8854076b8b7c82f29a46b59812da87560ea2b934f9cb062b0390be579df51869a11aed68f06cf40fefb0d1e9db875a9edf413178213c8e717a8967780e5fad8be9c27926ad3438e85bf8d98780fbdb35937a0b571d0b755f010c483c97a16fa67730cff49e55b38bd615560da418c0c73fde0cd06657b1b78e2b86ac45efe18ac892bfe01d0b2829039f75b80f66c172ed913235c221dd7b2ce73546a9adbad89667b466603168f529acb08d2b6b12bef714af6437797072a58277e402ea2c9eb7a64c4ae5912053ecde75f5497957eb98f90a0fde91251e4dcc12f089d4366610ceb8178baa6ed38ee129f83955949ff37ea7dae43456ae2d875a9b26a37ee2f69a4c97c3fd42873c5ab026d9dac78af3337a77ea0b9a094913b0ebb9c840379795e061cd88b5ad0229745c40b9cd824967801d4b75f53b1c6574b57fddee2d9209c9646391f643c939b48fc4c2ed03753fae15da873183239cc943d60dd7e61e1446f4b66b653b7cff29f481b0398b82c434e919aab04f2fd21f67c097f71fc3651b5cf772545614f3860ef8251b76da66e435a68c1a913b511d39a9c2f141d4c9f44dade3c4f0cfd2c4bba2443248d45bf242836440dace00c92c106c5597cede299364e5248cda8a02c2179dfe03365ece914bb80090b7e3367a80c1b9452014cf7dc5a1171cc0af17df33f618557aeb01ef14a7d529cf190da28fddd1270d7f1bc4773cfe665b1f1d9020c4a35e32c55df1d934b98c8879ac9d51943632a67b0b84c77791f813833f906deabee4894c1793655dda5fdb72ff2778aa0828ffad5c6b2d03eab0210fc18f385bd319d0b8a4df5d6af1907a2030e497c9e104110740d0423410c5c126983222aee559ca093b5063894843abf799b46d943b2018431edf113a6e6b9d47c30aab91e2760ef7be455040c9596e9637a9d061dc1bef7ac06a4bf5c0c05155a5bc5532863557ba890bdd350f3b81406a042de67f8b320cfd50d4a1f6e1c478ec2ddfe7e48f3e1f222d4ca2313b09b39b4cc57256056d8e760bee7cab961b9f4ca7fcb20148cd7dc0e39a87e6169ccfab6b10537702ecd7e60c503edaf671d5796319db236c3b9432b92b621053912bf51fae699800d6045c8a5c0569c5664c6959a02cd172dc55e5e0a7c29fcdb450d10658528b28e9089972695584dee4c89f1602616bc765c57aae40662de3f6a216e8218678c9c6f90718cbfb40625b2f377c262e862a71af1afb431405ffee10f17d790b14c686fde64bca4455eb755a360353a81c1c3f3700b7c40bcea213a0a2aadad071fe16a37ad5e8aa28295b4aeaac4891f26fb2d1f2266da1f73181df6ad8cd76c2d89512e12cd2a498dfb0539f8146072f58376138006177472f901a3a5e885b5da22c7798e0f82b50fc3ecf53486e84f3a499d3444211220ddf027e64418f8b1d603227ab351e564a486f436cfc6e5f4ca98c73670dacea3042df1a217343a6d97d8693a6b115b9a7810af3b4432b8b167804a005135895d1bbace946ba8bbc199f6b0dc2c333ecd2e054db3b4bccb5f0a380a776c05ca1dfd8bcf55984a9785581c2bfd0ea79666325038ad436b5a627dac2281defd6a352ea7bf1848033b59653e9986eeb4b173e72edaf015fe94d1406bed8af9b3185a865c34005460c67463b42ba4143181da0d584219a0fb6d0c2b44d3a469deb7e3e45793663c837ab29514723eed0c88d734ed1f3960a04536a3b023b5021db3f3b05acc76b3194242a157414c37920258153cc9aa3cb1a9209224ae19f7d222015d37313c76662a8ded9bbfcdd564ded0c693d2b7f637ec601481ab1bd8a30158782528c3ee190db110d5244089ea11d5b34e3fb196a644ec97acf61598ff7e57dbae3ad27c79be08f85e0b4add6e2d845863c3a4e5e361ce03f3f60b32d08d97d19efb6f12aa4b6608aa2bde3353591ea0e855429ce829d50d9fe7dd02c5d4544472976b9db3b89073241d899236e1c7f021f2a31f5b1bb927d6097b502c62ddbe9f438f32302f572774ecdcf25a5e62bb7f72762781c8e28f32d056642de8fe2168be17e77b96c26bb44da5088487794177ec8fd1e3fb03ae797705db034ddaa6c421e090be3f82f805f5a721520e54922cfc4584c2da675761f0b26c800dce8528ef89ab60d8e6c962edc2e8ad3b455051ac350795f55b49e896243569540e38620f58ae9318c82513425a4e5a0b00c880c8df865bdcdabec578c65d31a7766013a319adcd5e08a7c393744c04124ec55506e093e8a10bc81a1022c500660c2b6e11372a852aaa75eec54f694ca101136df74a591fd3076d63eb7068186711e3fa62100f8cd583044dff7717b4382a46fa60ec84ebd6de0e5ab58759a5dae8e6dd82be47991b72e33195b76a49ce5549be04329ce0a5edb4f4a441f481a1fb6630befcddb44646bc7ceeb49e0c1051c04fbf9d1afa108e789b22ab61284549c6d3b43fc8abdb64d5ebdfd64b1e2239513ffbe136deea5e41cb046ce5bcceb09d949d60cb224562673e000e60f28f86ff0f64a4eddcce9b1a63e58a0d2dcb24f89df13202f5baadf62964d6fa3a6bd092b9b516efc9c2361d403355beb7a7e7606420f968f991fb279cf536cdab4310324fe01685f5cddf0882e10a6b5d463668a61ab986bf8d5cd9876a11f6f290dea7f2980ce94485ab250dabe997c02a473e399000cfabe4ae5eff783f6d281e4f57e909983c250cd3d1722b0d6c915d326b4ad57744ab6fa07adb81b578de5fb8d3cbaefaa4525a8e84a9900f2ee7a4ac2f2fea36137964de3ef2a524a30aea830f4680ac29618ec860567873e82c30bb54cda869e676758b27a360bfc99bba472b505dacae2a0c2b882413f8d737fc882b57f46e09950adec77578cbfc8c4a9facc280644d60b5d49be8ffe70479d610f50422f813aff62050c56b53f3dd860dc6ee6d37aca382b673f09aacb9a195ff80ccf6fabf93b6ea79212a0dc37c4c7db5cf95978d429977b152adf80ca9956d07cf80fd6fd3a69762ae4fd39d382e540e837d5d019ce8299178db971b7dbadf2b5a39fa342607eee133fd1ed9dd0414efe3c47acadee50ba6205f69ef82524c4cbe793cd73bfc6628b010a9344d626f85076b62e41afa88b7811101f6bc02d89171c79145ed83bc87328ae8886ef772a31fa4270d487c97f6290dce582056b4e3da0b60e666a9f9251ae843591c79cf7f4d519e76baf6b7171a90326ded473e6465785bb40eaec41834773adfc90ce8ae00d76ab1da3f16433b84799c26d1b9090e65ec19bc7dfae3d403b1a8f3592b02196102399580887b4117cf8a324fcc894e4fa4adbb83737a66e5157d0e130254fc2c0d673bc48b34fe46af4cfcd35f8ea6f8981a7afc32f3c592dd2a37cb879a89a1b5a54d112b29fa26e5ebc95d10bf443a691e3c1d91040fb3e5477f8a8559acd64c14d970bb17bf02b04184d426a068df17a5e31605307bdd85f1542510732b20ff8dcf39427563d9bd147c5b2e0acb2e8535a6ffeb11680671d62126e5baf9784993ad0f50d23f98aa56755585898e16d2623230f584acee1b1ce551b3e32e007a2124c4afca4970c48f646725aa770f7976c07d0a817a2d7d778fc4f5261374483b5cb6eb46ce340b68cbed4ad9ad300a86d5ae59da4132340a3514911f7deb56f4fcbfc88c940eae3893ddac04d0990c616f49d262b7bee75c2269121d9ff9bed49af63703d6238d4263f59163e2fdac8cf598e628f80b320517ed7ef93036e27b3526daa65530063bb707cb7eb5a018f28151b090f053804486272ac002764ca34e2a907dd091755b4823136a525b5c78e90f95b171cf8890524394912bcf068447ad868f0d4444d1474e4e3bcae03968dbd503c16797d0542aafcbdfc5201e26465560c2bdcebd33d0eff34536670327786342855c6c64e7d224eb00091a5fe8f9631c4f575754657f51eb2a4ef2ee780a0c2ffb13400af9484d3b86642649d00740a26fd0c0ad8d9c26f56f9b83bafa44f4fb7e0f6d93bd4b7d034f95636ca01566e60fd584c4fd6676afb592e8cc86f6c016c4b6d2c31ebb4d99a524dd063a7791de64f796854799a825ebeb537c10c91b49023c77594625d2d36d3e06365977e2863f29f8f1e6254879550f54a9b90a64650716bebadc514d06e3384380c9003b5290e42989d4f28ccb4bd733a0e5dd88e08edaf1aabb02aa09ad3ac24835b8043bc7c580bb9d061971e4fb334402ac542b17b54a641c47696988f3ebcf9c33980bb39c73d005b3b78619454ff35e1ca763443958441a1153820de26035086c0c012e787e797f40351738703850a22f1cc198a37ecb3a07e2b310ae52b57db03ee03fb27602d6530dcc1955b696b2ff0c27646af7e21fdcc14589c2f3caadfc98b273c9574b1931991549cff4dc5b657a51419e2b19135b07caba82a574c092313188015574fe605c3e05a275603f3ad7a0d50955e3e29df7ad8d91a28372297fa11a1f45249fd7e173d467f7fed9aa699621c1509875e2096c5ba815507c32d33a99ed598f5a14830fb4d4ab9fc1392cf97043e6ee82adc5a8eaa91af973b7dd19381a2fa81957b4f921144d9ddd6bd61cc4f18f432e932fff65d4088f85827cb1c5e2d34ba0267f52593aba9deb026229772971d928ca843aa407f027137dff4b13eba0ebedd147e23ba8a02c03eb65a3dada1bb84205450a7a9aa25d92ef5854d54e783fc2fc445dbd04c1fcb8bc73c85579c12bb271be3861fe027c39fe5b1cf080a4d79cc7c5eac2e896aca823fd8eb09e6b0704c1a086b54d9f463540e0191e000b74442d695a1799a4e3b955ebabca6b3034eca7b6c2b3bec138022a5b25c8011c6f5646c81c3fa844b9891597dc6539987ee13ba184238f0f2857348218eb79455fbdd88e500d5ddd53a9ba62c881504abe4cae3303daf32d9113bdd196a02077b24c919c2015beaab82960ec3b37578aa4de809a62bf3e8f7c63ba898bf0c9f3cc26914bfa0479830785cd17578ddf70306b4422bdc151047fa90386e8089386adb24b6b8d15572c7fbf01026c5af2de7eb0c2b5adb36c25b9c74dcdbb061b131e38e0bef894f90c3a36634e02851212fbbbf8ec840a06893e00d5fecd986cb7f6fd24c5c473fe7f5f66fe582c52e2b7f23935f19bd81dd0961016839db5f21991a58d70f893517121404f8a5622d4c0a074c7bf6f150d3b373626a8c88f27d5308e6d48b7594147a1f16f88f3c8f173a5c8e4390190d6cbeadac1e8cacf980becd5e9ba39d3568cd8381cecfab96dfa91b10b7b58bc89da82659afc7990b1e3e97f1e035e92449c97c5f6e7acbde920b652f89f785207e0b56b92c8db69d80064817bf5ba94a32227b959755ed526e7e05e98581bf23b9e3a8368b03508ca034e49005c802cd4490aeffa99db98a33bb15fbe8f836ef5752b14eb7078a1c43225c3d2fff9882b6895c4a3bab235804e6cde26d6bc41bcc6bf0cd72d33aabf709645b3829428d9a39512b1e76570af0822f8d8f878203b8346174a61638943c54c4a2ead1b40e4320211ab1d5bf0a0868346d582dac8986ca3b9011243c7f85a851a72cefc6d019c5a82893f5b84222c512f5763c73473ff3577a9274791eb64f101b1953e0c22ee1e30b918d815690c3836e779d011d1bce269ba653c4985b5b3e2ef479d2418b081064647d19b84aae48b889e39c943316fbfcf47ae349b2417dcc27eefc2be900cdf9719d693be3695664a53771fef8654bdcea05cc41004c378fa12a2cddf50ac98f43265e3e29328cd8a2222dedd8cb2d0a96563ba029b66468c7b8a56c1f02579af90519a0d2ba936922a254094ca8edd7ca4a7ea9f0807a074ad8dd9aa03098d469fb5df074d6da54fb92968572c024cb923006c87a22fd81fa59c499a3d0e773b4e68bebcc2455756380fe895e78b014f0545d3af69778e40ae15ddd4532fd3460808262ac9d30ea1994c422785cca3e629e9867ecc1855d80d799056ec73326366399e8656c693811c8ce653f1c07756c8ef1097d3b9496f1196e0a00eb7924743b2b8152a4953d11e42ad9abfd39499f4be64a833dd70daddab9d88e0ea1d46c50d83da768497574e74563eca8bf5777be0ac635f584cd65b9e9cdd064778df888e18d70f92a1574a904ba7209a61ec8e9ea2db350b2b764bbb78114e8c4c40d7828399a097ceda9615b2177c239981cc333a1eb5e75b14eee591eb486f87e41559658fbc9f3a83840a72f79dc19c5f30544c80212c36cd7c633c6064d527e3144907f87083da6c76fef47c49d85837bf7872fb5a3fb68ffce50649e11ff3632f2130de24fcd2029101c40a517b8de2ad59ac9dc7b5e85b514e8b47b281ee310278a5a4085633c5b16905ddea50fdbc8009913260e8065655320de44257f6bb86c6424acbbac0fe8839895d4fafaac62234d33125b83082864c40749d805fe81e70d4e9f6b67c1574e82d0ae40a8a829adfbe0100cf122ab347a56239a0052a5d1c1734141c1667fe9ec8817d2f6d7c62db5e3b1726eb44de3624e9d25907093d8080c56b1dc81858b6a36d8fe49cbba0291713b03cf99ee70030e00f3468eb2a1231d51f18abea950ded7b3a59c28714476b38e7f8507281315cced5d2130ed5ce20b5bd82004b3836f98b6e3172d971ffc5ea0b3276e6ca3bf135c9dcf49da0fa7336b68ba399708c3bb89836b104fb69aab8a9e3c431f21453c013b37a21d25ed2f3aade04b71e1133b36184bafe1d4c119642d280d81677c5867ac4d418fe2358ba8296ee4a8f0f2cfc9e9226823c2a5b36b1558fa19723d5f3723dd3cb2a57ac4cf185e93a7d91bfc4d4833c9b0cef64222965c9577134b3f5399c2e4bf5a6d3b74143bb20a04530371fa8612cc16e2c26a279553eb061504b860e838d85807a4fe685fb0b8ebf112014bee891d7786eed29ae0d6ce127cda968be7faab74a86761d727fbbbfe483630b54e1771a59fcfe7076762c00f27475f9d9bccd1456e65f64c9f7952f3b8cf5a61025961ab9c2f28f9322e95daf5de131c27f026755bee9f136230595c0e9302a85d1115ac6a8e785b4db2cc06b5e55282b81c720ccd3a5c6a4aa2a7c3661de3428b94782e36cf5e2dfee4b58777f38496da8ffa05483c22cc126d4c74af752cb35d22981a3147767685e515267b275320877ab5d69c66c8240274233c04771b59d4a9faf952ffd8b48a894e59087d8609285a738dd3faa752c2ac53a195dccddc5e6d4c9089507e2a2bcce59310c2b7ca15aad2e35b2f302936a0207ccf1da58143e4705601ee50c6919e430d6b039d4d79805614ee1db5ac9f2e5e0efc603a3e9b17fe90b60f11a781038b1eba91949c04bd49e4ac62d60a8fd374d287c649abe7780482399d05147a29113b7fe23bd5d3f9723fcd6adf25d5771480b111e7cdc95e4f538d7d6b66a95fd994256aa795bdd59e7f3d59990a36392c19baa6b0f77280f13c45eb0d73dcf1da213e1883256b7c71a00e8480605c0241f5e8065ce15200203d55bd87f360ad5b640e84aa34120614a0a5e456fa942aadab667848337d5cc9a117f10897d8cff7164300889796776de4267586dc7f647be27308af6aaa74147b31955c9ed5d6d528db089511ee643ee422b8c68ba8daa06c463f175a3639439fea3f1eb5a9422d6da4430b93bc9ccfd78c1868216c745cc6a865a148185d86a13040cf8f4029e99fe8511e69d52d974ced5d8737f24b5410529c3de2ef4221231098eb8fd4f42dc92ab85b027a300803647f805bd1838a707658a76f8955a7300dcd55539970dac5466345b9b697397dfe73dd8a9c33b6ddc8d7c5a0e74c6964fd7bfca9ecf1da92efeae0fc0c31f741c1ee1771a9ffd78f0c66d009e1e0e7260029fad0b242cb3417ddb607f20b204b8b8396f25249e18c6839e4e9a76d36fecbc7f813ade0ac4b68074a615c0c2d47d98bf12b1824e6187dd0a27bef1b0ba43e257624aed64c7ebb66f6539246cde441526fbcea52afa6485049cdb7901db46aabb57e6862af9bc93c51a4e104384a9e8f41c5b49dd40afbdda07daf023f8fd1dcc294bbbb709b8a42dfb07e46a6696e7f6cfcbff343aa54e471e2ebbac8a2144f74fc6b1e3cc56a71f2f34c48193d6c9fdb8d6b1f21c27ca74adfb502a81c0916ac79861090cf068b4a77cc07dafd7b65d18973d3b414b658d644a66ceeb914b1502de40dbc9e8d4fec7f214c11a8bc0c940fb79fb2b3bec90e0bd644d0b0510df7e7c26e759e8e867d657bdddc42a5b3b713154b64b94e0037a05f18e46afc587760a6c5bdd26b50d74253749ca59afbaf37c90bb74a37bf2ea46b37a9b0418f7bdead514d04fef50eb1159b99dc9e881869e071350f4fc21ab915a0da775ae5f61d4c7e2c5b3bd94cd5d39678b511b3c546af275cbf2691c692c7d48fc04ea632842c16549e632d3f907199d84f9caaad40bca46b809f3482870ffbea262fdac543f19d0fb176238dd863018a7a4ba2bb6b025eda03a8561e7b3f54ef0520ab683e32ed13c4e085d00845bc5580747a032c29db7e65d5e65dee425cbfa1a170810b5d1b0bd6b21ec90bb9f60c6b2e1653dc07df8b1205419eb7d174dc09d8b0a76111db1d50996385d3605e85885d6464ce1a0136eab729452b5adebae5addf0e1aa1a8bd61388ebf57a69f3a1d59fd4a2305cef3d814beb1dfc705656c003a0fba8b0ccb9e49e5bc2ce10dd2c0289b9509bc925e431229628ac0f26e2a95f59aaa7e188a2ab64b8a4114a8212c8caa7032220c07f5ea13a4e4870f92f2f35083443bacc68ee1c94b5f9f0ce784b5b2b6673be54a913ef889be364e1e2313464cab6738f7a797714894c3f48a1374212714a6ba2cef2251871ddae1abc1196146178b10a6eeb7fcd5a0186cd9475960133ec2e0e235c485ccf1672f6b4d0c9869979a50bd02574c77e36da2eb2c85cce22f3a4cd6eb00d1191c93b3c1c0af0be5965158e153c873ff8086b5a05a2d06a3a59502a2b98b7f7f12025e72fe85cc511f0396fef2053f9875a4752e429c7a11097edb0c56e0b0cf8eeca88ca796bb13311fc6cdf3a198697e5aabe7192e1f666cc86c08cfdaec702a506d8c46e03ee9f3513c9a8002f3786cb5b4fa83234bf2671c32b65745007c99c02a8827da804deaabc33ff29c39a25aaf6e7ce24510e7c0522cf222ecf793d018e19b4aa639e930b9df07879c1b9891306daf1eacd6b0eb9164df44d6e2e033de5e70173815c310626679f2b20bba7f03d0f1830856d970acc922a04f4147456881ca0116703379429663df745db1ec3c4bf370390bb00a9d8df5317f1f0dbf458629d0ae7ebd3c1632f39fde2ac412eda147d296acbf6f681de73b78c47ccd037090f51511208eb6d026e499af8196f6467ab17c0ede3c3f50b8e01f1d626d49e354c5e4d8ff9ee839061b92079a77b9d6f0372be558dc652c0f9e6a788591f64aa93abb59cbc014459c423250e06835f90e624b73f5f5d1a1e84c37852edb3c26c1f4abd664981f2d5852c9e377039bf01de7918687c8d901eb3a1ce1984db8f968303ee066b6a912c51c046fa7832df2b660ab588bba9737dd33d6c15a9bb5da75246c86520a8a0490148e078ce25f25b674cc05fdd1514ba073408252f414eb4d3c791845aec4424770b5a4513cac9d416a67be8e075b3dc5925ce50d663e6108c4eba29144adc2b08eba0becd5a3d2f5e36683e7aac4f453150863669c5072472bd230db33d06bcbe0e6a8eb602257c4f10cfe03e3f712c238125c587ab72bcab0cba1f21a2ece27431d3eb12c760eeddca04f41bc741179c3f211619fccd0ae50379275b4cbfc4ba6570262bdd8ba3face03a6e65d2fc6bd9c1fc4856a279de8a0c5e2ea58304b7af1b95a5ba6c2098a0debe67315acf99def2bd16adf079cc9532fe3f50be04123445ad2cf72e855eb36ee3ee3af5c958ea6d4436f397bf106727bb8dacaa0a0a044cb31f456a3eaa7e2c96800a3c59b6c3255ee8326545d956c9119c2a0a697168e06acf621abc8f4b81b49d40f25a1df010bbb1c423a37e0425cad5b2012ca5d4e3a0a33809535c4a730221ab583f478be52edc5f740adda94558c02a05cb0b56c88690e729bc549b94abcd6c2c8625ad95f31bcb22ecbcc88543bec00ab75aa7dcb1060bbb0577317bd8cdfd0a967d2654543e5eaa9f33aae3e901b2e4f1a97f7d374918f86ed083bd42c5a4b996d2739b7b038bdb46bcacaaf79bec7578ab39d64ad25f73f65773e859e2256f225d23fd74ee4ba350e12455b79330890dca9b7f42e8415bcf418991255b2df27434257b5f79831b7f2c19d930405c1f06b5e75a503e0e68398b1b0023e21f1923b34a75a1abc787cab4f2f71cef7d63915d4f5603d508159e12379ec711291f68b16399504dd2b1467a97397febe16770c0f2be84e1070bd7fe1e8e1e5ed91ad8d01ff3d9fda9380a4549d1ff03ee8e7199adaa900de48ba7e9716dbc5037dfe3dfcdf8287e58d41ba0b0974b342d201c991870db7aa1025987f13d1684998c2349877e37d0870fe0afc7187a0cfd23a91313c4e80ca78d029708da936e8b639735f06ff3dfa3dd4c0b88b836295347dbfe18db44f88f48083edcb1bf8d9b6e631c8c024199ec4a742276a570b12d7f6d9817a641605708c51d556f44f2410425b799f17c9d0e5598c89c75c86465e1a7c2fa137e45e7eead8a23058afcbe34ae1faa1797524ea3d5ba8cff0d807ddd6186280c5d452a60ba9286dafaac4d5462a6ce0accb9c7f2d9a2dff6f8e655d24213e46593ae40cbf59ba930203b0494d8590ceb027611ec73cb4af2da26f59d3158d51b921011e0513376b951babe06657128980117b3236b8a07e1b6339518c4bcf802621f2935e2541ea1510604ed5568a79db93029ed547322b7f491d814cc97b3dd98e957eb595f210c2a6291a01afd7f7322ca4547445fdbf605986ebdf5c1737dac4e0a070ba15efcddb901c24df73ee1cabaec7fdabbea8dbb7a21962ba70d042eb7eaec4d3d6a4b2c4ee8f17a12b7ae6057ae1d8b7f5bc74eec9501c25193300e1281f59df0099b98d44595c0d89e54c7ca284127fd416fabe89988564e4b669135d83f9ffc5c8b83049e2f0e8bbc813640e5953558df94f3dc627e1da26a1230f6caa37681bf48c951748b61e686c7fe2737a89680c6356ea4ab9fe392bcebd71d6439764467b3cb33758bdb38ed7e5dcd9d5ec9826a81febe0f5160696ee01bd105f2d693e5b3607a3e60b370fc8213065ff51080ab42c1bde746d3be6cf51ff385a9cc6b6a5ebc25eb4f82265ad6debfa04af85cc0433e6bd81dc9b841c618844604312de794c2c35a40b00d44f295f7fefc42d6245c853c9700dfccabaa12921e732e3bdc3316ae6d2288b5229ab0994ae45208d8106fc81be67429b16e51b58c2526a201e87b0c3b592b449df3c577d71f8a04539b6db1bfadd365e8e1ea1f857b310a7269f8ffca013ce0040e0a94402d721d2dcb7144842230d8ae5ba6096a0ef0e385442a06cc3a4fc189cb29ba7c73f01bcbe4578f2220fa8e9d8eaf2b3b30e44bd345fec1f4465cd4174d36df8286691f7de610c68036a1da277f4f4b6f0dbb9af096e28143741fab33a66dd42986d0325d7db58f8f3f1aec37532b5fe98f4f6712b05132edbd7a267ed2b61497fc5326fba562c135c5e3a7cf6e69b5c79d986fdeb5b5cc4dbd2f2feb682ffaf7b3db72c769a910c38a84479df4e6f44c7d965313fdfec9d38de5ab865afc6bc2f54d61391c793408189158dfa73e1326506638c269a3432c8a6a5e419617a7703406c8ecfd28090fa106b6fcd4aa0b694e2fbd71660f3c158f1ed1a71dc6308ce5e20e554460b5b6aa556be16f32fe045605dad9f9284a2bed96c0b38a5d4e3dbfe65669253d5ab09fe7c3f11499a8fa8946ecd4a614920d903daf0240cc858b286627860772bca0fe65cebf983a77b7e30b505f9f441a956f3a6dcdcff57d8185c2a02b625ac154d9a0c6bff61ae24d1e922c4356b5ee11a261034ab120f1c0d57b0e0ff17637de91264cbe05dd5bfba08aa52305499d3d066024c992e30ead93c16a2518dfa4021fb0642e0840e5b278d7b83130246640a831e05218332971a8f3a54f534eb50d421b7d53b055a6bd8278b46dfe7e5815cdeb6246eed85dd5fd7f696b988dd8e956345175dd20d87a952fa740653813bf5d6b61fe75d4f22cf02fe8b6f174f40e3fc6f5bffb2c390a69b8d8d4c2b57eceb9ff0cd485ef96ba1806728d714ecfaea3ae799b20a9005f3097fc71a5a35e225b8ac8732a79ccf701472f36e3f4e4eea47516d88cc64c1392908e19247c44fb364024b8d423a8f38c2fe59c47dfa238253a0e6d79301d9d776320b921936acfba6ca962596d9dd78b0988a802556666f5433b3e2f6eac21af4ca7913798aca6e28fc208aa14527d3073a77d12624deb7b20815ab75e1813c3519c1c5c37520a20b6aca1725d068671cb5ad166759d49905853a92e6c2490f2178feb5e8e7a215abdd4c4bffc239804416b105be934b40e1541934858416ea4cdddfa126f4038608496fe05cc14880c9686f4cd2e5c720282f44893c8b1ce3d65a78dc57b40bdaaaa452873b9cfdf65f872bc031a2c0c70191469a362e29b856639a90f17f131393ffeaed7f7d5e60bc82c8f7b1aee3fb798511eabb05e370cace1a987e43fda50243f5f5e7af26244a28e05f3d530fe25feb942c82d3d846b453a21f02f8003ea688a09eb4cda85f5db4a84b92a203adb2b91fcc1e838beeda0a61bd634bb4d7f3e07d81e70ae5ec0bc7e19f46d14da93fc3aac6270c213b42de1dfcc2214826946a151df09f67e61465d77b315040663a254059eaa2b2f7442217898c44e916ff6930ae8632d576d72680681391edc4aa1070d28a6984ffdb07fae5fe720a84e655682fccca14b3b95fe45e3534d2dfc9a8c33af0f85e9efbeea970d7ea6cd67615b3cbd1ae6fa268b3e944a1b257542308ecb256693482c425a72058f851080a90de600d140c17db9529c5f1ebf25624bcc4fdf21632702463ad80557089eb12bb31f885231372294c6b89be502b9fb67970b0e1342eec0f2e79a978e3ece3da45e3710375d4574a7d37b7ea180012f55c028287d3f196292b8f15cc730148c01b945c159079253081b0469f3f173969d10373e8fa3e1551be375b6c7130257dd0f0c64454faae33038fc283da2728131ddf19092ed4cca205bf64b58efde89a5f2588c80813b57c5eb62935436ab33317d14326d6d1a8ea568fdc2b6ed08ac46ac01a7c6947b5bf12d025d82b0d09a51d51b3706b8029b2db32204e8c14c5419f7277aa22177da15b9548ef6a1a1021c546c0a7ac5a55624793ba578bd21dc25a704f71dfbb7e00f0bd3a4d66f2052810cc522e9e6e2fd1fba9b82b60aee239697fb49c3c5d70552d7f5d19bea8bfabc0fc2b0ddfc9af698f200d9eb9c36c24743ffa456f09b23e9e5ed53aad1d7fd0580d173ec03e6ffc819e846c1b48e11ab6f5affda2359252d08c1d6e85e3b1ad4d54b987a3972609006169090f3a2ecd76e36025e1a63e586f9e7e3ac7056dee318a69c14d43dc3e8d10b3979b0a1ea2d5d295e1158f018553ae51bfdc0dce2773b4b5b40dccc626ecfa4315d5ceff2a04fc9bc5cd17155260dbbfb6aa4d8464d7290cc72a8b6dcbedff33af42ced74343d79ea8b0ccceb708278046f390b0e4de0174542c8b348f49e974dcc7fd668a3b60584681de095c4bb2459a0b4137e64a3c14254d453902b02a538db34632bfe1b01ce2aa901669e666a5a729a3418750525523195c1a880397813006ad911821c16b8a8036775d650b3b4171eeab7e2bb31cab766b05f649c881a2ed1e7c75c14f31b14128c4612a88809e212672cebd6e33722be749fc0802a2327d7cc5754ca6c4ae7da09a891c1f0fe58f9b454bd4e0a51af5e2ecef75f772b497423c4c649c12251070f9ca16cfa0738aa38968f569de57e21d23ca41e19f2575b819719b570ba228fd43bdef991de75303c8ba5293209598e9ff6b0f526ef6fa43060f12746dc9a07c8b2a5280506d2d499218a00488ce0e065ad8863dfed034bec077bfafc3161ae11163f774c9ec139cb2d5645518a76590f1bce60bbdac2d1cc4fda17e58ddb79968b07490841ff343cedf3ac1a30457350b99fdbc68e947c76eb6f11f1a6e0a5b5ae848e1bffe2dd4089d334657116ca14ffe2eb60d124ad10c009a9bb07005b3bf789ff688a22326909cefa80538a43198460683a9e4471b1a53bbd8866e349b387703335543677d9a4a54b02491062ca06643ad4a2f7f24b43dff7cf10b6143ad67cb1b94057efa53d0176317d56de1f6e281d8f69de842ac03dabc5548a7c980f8c8a21f6b3078814fee14aefba6045c5be1901993d17487fc98217755fbb946c6c411329b65a23f1beaa30c486814c43435bb9c359369b3f51b18f1a93f5dda68888037f42830fad7cd6950c6a76caa3eb0aa1553ec0154a844d5500273429f0f5099cf157084e086401591b370bbb965798bbedcf959deb54a07e91ed9a85943f7859369dedd6d94f3d6544386eebbd81189de3d5d7e804ecb2743fc9e2b1f55d390ecbf8923ef407b8891b187cad86a4859bbad945a5bd79d6a2c3dc5ea744dfea26af63501160e57cdb707b757c2b6f7aacad8fa76e36279837d4b118865a31125bf98e4772b2bbb74a397d1cd0ff53edfd81498facdab178efc1abe1d446f8d81074f6ed8e0e4011c36de9f15ea607049fe08e1a3d5e9edc7474ad2407c1d239ff4b0bc3678446e9122070ce4adeac8f87b5959189db3099b04c8eae02728c87591119273e30f7a02d5666093552ff32f35887b66daf533ab82c2988d4c1c6a5beea8a25a66d08982e842b471793713aa60b48e69c0a2a0e8e3d844e287e928afad1e0182897b98cd191355c60525231682082aec10d9edbf30243d076d89a3a9b10b9852f603b6d3bf65bddfc6dc7a9759f11715cca376b9d9d5e6fcc3b32da6b6e8e06ee65eca0102b82ff39f059c6891caab193a428729acd9d4bfc23b7c215c7358ca0f72994cad2a3636f244bd555399c8fc738cd689127fc465ae80fb0c14a23cffe05e490e4b2a671236d64b7f8bff6dc556664665174097238b61ba621725dfd58a6fa1c5b75df1d7ae3a10174c558603399f5c3ae3c0f5bf15a307d5c0cda1fee964db22b8f89768254c97efc8142d324820a856b1a00ab6aa4cea9bf90a75c5fd2f4e896c198a65b3b502722d5f5f333c066deeaf55da4814831026585a4bc27922c3f4b2b3c3ebad9fee018d5c454a7f491b09093edc15283e58d3f1f864030d00374f745f38ddfe4c28dca9943c9f5b9c3c368f8cfefd411a186a12862e4cc28f79b594c44b30f5b3dc42bfda773ee74147176acf1a2b1589a03243cda07a9508a02c9fa7d1b3b9b79c96b5c9f2d3f5ca7f88896a7f1f652eb43708d58a65b5b9db09456f17639dda832f0996f46c15450a8c404dad293f53a5b51b5201d72fd818bb8cd000d4da8c724eedbe4c84fa14f136676a679252d945d2c7e3f3349f7a94f9beea5afb334d341079e415b691620f70f04e0dd33a974800f6a81b68fec66b060fb7b80f2a6be16d0c484d78c2c88a129cb2caa3d7324d82d42a70328bf8262d72271a79dbdca2c1827292b4bf4c19cac9dd90b150d1179c4299c13a65226bf94e2a25cb5e0a44f2739f49c932539721a425806efac7923b20e85931eb52ebe109ff57261b7e026e0ed79eb54fba47504a94089da386ee0975c206cd5335497ded0352ee7b17aabefd6c059277c127397212d0a2619d6a3ac15409bf529a1bd7708ac51218b7ba7a4385c83bef7c2e2c74c0d823e220c930507d243a2b9a5c2bb944ce17ea5a0bac841d96af901769472de5ceb2dcea0230b7cdb19d76207f06815eaf8a6e9cb98ff004b23bd05db6ccebb87bcce47052c18104589be143e2523e7c3231874ab8ebe862ef4aa39405b87d512e4a113588aa315e72a3ca3ff692951a38e7532738c4f7de9f903bcf4b49ec12115caa2bbc765a706b32d9c3a7fda899315ac053a1b9f0882519ae659be9325bcbdcb0a5e8f781b88442d7cf0515fd7350887d2243e28e51352adac496b8d3f80a11d5de5f029b6c847d5929c985d20ba849ec6b29ff50af08b7f8936806281d2142383a45c1193efeb21f025b3581d5c3e2c2a025cb32e862812469bbe785cc8f4c9f5f33e0bf19827380f193fa5b4149fd2cd0c3da989d7130f4090fdb16813f460681c915ddec339f0ba91b75e50556fec47a8f3ff98d20132a371b23747458c783c76b3cbb991d5b0d65124b21711f927a5ad4ec04092a709b53c5057dc5d2996b50ec75a134e08ea11372f79ff577607c973cc4f8ae6a659d700b81d517a2e4c8ae86ae58e270cfd8730007945a36e2a961a9ad62e910a2f49302f72e37b5da2b96509ed24e34108def9699c60d764a048f4b15bd8c6dc5929832bbc255281f0d1b565b3437d8d5f79c38daa64e202f1e2486b6a225d84b6fc8cd10c6a1cfda57615c56b56493c513528e1db1f698336880c37dc6f28f003734293ec044363692ae938aacb95063b6e836df1a150ae99e4b620500ffc6f02d3c2c5ab76eca4e4f5f49be4b62b9d8429f7b119dbbe8f5eaf32378c6c974d08dfc816a3adebea48ef26c87f6a5a31ef4baa4ad2c5711bd842fc4f35b5b6bef928bc034772e29d7d12fd3b3b61cc39288ce02fa2aac3f5384d7795d09e161981bdd706ac5975169f5564fcde8730c8e9e333aac2f6b34c82a265896aa1f0cffa2c3922661c287dc70d38775a6102b0362580cf630bead344a7151c89a78b38b32e14e69e7e9225651d4d5e029c1e3ca3dcf644d57ba33a68bfeaa1a0774624230c57310576a5763e20461afe83d0aa7633b40abe05035e1227f91f23e20b2d2fb35738ee96a9b25cc1f2b4d5fe9e0b721c03c2658362cced80d794c73fe4987831793fe54fd9e8ceec69cc7f42d1ce401f9ff3ffc46a6b4a3def35dde3169f11afe2f511bd129bd3b98cb50a044d759978ccf24a5b2c36735f4a8d1ee949d3a7d2b2e6fa6e04c773cd9a9095188c777ba2faf365212be1a127917c8890e51b967bffb5d795ea2530742b83ebcaef03f0583b5a4b25dacaa5b0ec576bc8c8d130cb625a00fbdb9280863228a6175d163175dc7bfdad5c8e0f0d3bbda73b69623b29362c63783b428f3d7922a5199dde691332522cc5aef067f2f08f5a50081e761c4f2913036f95efd24994adbcbcfcc7b67f2e954c773e824d3d95f8aca04cf5e52bc671387778f56ceb445f671dd88f421e7c434b4977ab40ee5f5608f9b7ea08b23f2d870dc6266c3605194e09a9d6b9501d488008e1395ded04f2c8d0d744e23bfa87052621fedd6fbaaaca5ae1b386dcd2261468c7f76b2c289ea6e72743e3fb43f8019dbdf0b4504878d7b69528f44718ae4cc75d8038a4c2327acdeb3c6a6c59245c59c82f2120b46149093f23a21709d6c33e8c9df6fd25c110e7e4e248f7e96b1f914a6a53c431b0aee78db8ee06874dd6367473594005f6165249a87e8d5393cc1e1ea229a97170b82a5690513ded5b63712d0ce5d205d0024198f17a228d8f22bcec62a047a6fcbda1963d5d21832ed074457f62a30bd8f21aa1aad4284515117ff9607538eb51d51cc531d0fcf88ca9900bd28a07ef11551a114a2e691d76822e62a6c6274c8a57a33513f4f08d815fa6d6c4e69cb8c0fab17a8f8ddfe12c19a92aa13223213437ab2c1a8d60f4445a4017f2939598dd3a66ec29b695e89d79a5856594134095eca45f19823022a4c667b5791d28359c317c523090091f4f931db7c78421370ea8a7db22efe62cf1d571faad191899379ede566f02ca7d0c66215a9af4e8d8eaee682e4107545233283eb5fce62ce0149a554abaaf182ce649a4127df77911efb59e15b5ae5a98f481bb0ef1c99a95952def60ed376b73996903c459aaccae7f91011a30d6f7012136000dab754e0069367732339d2facc095341c57c88862ad0834fe7ac044dadd64adac246ff99569a120d11ade2f87666c8f801278075d0789038a7f70966c77d3e2eca2ddfb93524ba5b7b7fcfe082e6f3d6886b3b42137225509d7239e61520e98c0231562b6c1a48bfaa595b97eae369d9fb867b9d2b518b5ad89d95010aa1603afb5131a64f2c77524ef052659fb2d28398a995494ced22d049a22e76ea742391895acdd52ad57392c0b5295ea0f3188329614e748262de426f468b782a8be5fb653de30e49a986083863d93a004bce83179b28551d2d637f9ac90c28eeb637138b582491f55ebae4caf8fb76fc4614bfa141f62bb84b3e2ebef9aa8cd8b3479500e4b8c90ee94c49e8568d48f70a97f810b3f92a302e475bd530d5287bed51551d208922e93ae7dff3826546786d01ed0187a239ec9b8ad563622c4d849a7e5f74b7e1f2d1d13eecc1f5eab5ec6931d34ae1cf0649b4cf3086e85c48e6af65d3a2c97ce4b90c21c1048dbd9f76d47f3d77303a7d4d4228ed7329207655185cbd133a401dd27d6dd8936dae049bc6fb4a43a661700d94cd8ff9fd2a72a5a1037d5388662543abbf6855c2bcce3ff48a120208fa26491d12899d0c65882f715ee6e93f28bed2679a5aa7559b3ff172a82a96b1282f642d40fe5ed612e91680c93aad62000baf15bde39069cea3150173aef8acdd9c97784c6adcf93b5dfff574021eea110f85e88b446ac170a5293dd211ab2b12ed2aaec3114f309c2b4c13e883d91327ff45e8421ea22af943ddb9c214dc95a94a7624dc40faa378d1ec3c755e25c30329de3398ebe0327ee892ceff16b5adee16afc3806f8b6bd25739f23907521c06e90320bee22d3f754551f31555653323a9220070efa5242b183fb3365a7d8fdfbf8a95a3138cc71673b2432bb2b54ff07c12656c1bc10066a6a0120fd437e91ded602f30e13510dc192d657d4e6244189caeba892edda033d490732f8fd562c1f85dbe9310cd7df7b12cec8c21cdd4c9995de536055cabe1913b4d1d991e154b977a19512cdd7427b68c9d53bb59be4fca63a8b4d4fe9ea2714ca07cebbe733bf3550b1a9f62105ed08e7e1b329fb0a9c4cb7ff26a9470a29cbfb283543aef326aae261555569bc0efac348f9677f67df59455ac5755720b9d611d1b571db4b1086d59b8ca443fd1eda4197616bc8657e180ac710c3d8f21ba56cbecdbdfc4336755fc215f552fd1693e37cced71a8f242d3328456d0ad64f2ced4c33dcb08fe1dfb71fac591a99c151c8fc9017b175a21a04aea05ce380dcf14aab1ecf42e4487a57329b73f176c9b87ec17108fecd0480ede99343ca5caad7826f11d8903cf63b10a1b5c2b917ce04001eee1a7fe8aea78e1c32d0cee443b16e6d785111ea8813960469687e1eddc4d8b979be86295df22e6918045cf3e533e9f93a100ac582e3bab559e8bec866405f9d55369ed8768448232a148336d1253f6d3debffa81da1069eb1de59a8d955f8e00ea8168ea8658c16fd9ed04892e7af2f523cefff25de209e56e9c3b4c448e7e32afb5718778d306a9bcf61e6677aadfd604f15d433a567671d63f43019e94204a550f4b356273e5133f0aa468623bd8944236aab1c5e19c449aeee9c620bd057218a9c6cab1e1bf80d0e8a6ebe48a0eb35204d2e951bb9c752c71acc3259d5567c8f82babdeff387965e59caf39c86c53ef1f400480067edb79b70f388417f09ee989d306f35f8297908629f13459d2094d4c45f252fe6eb9212cb8d77960191d71191c03fdd7aad5d5aa7afa696e89c99d120179732aa8a3e6ac933abfae0606fa0e078f761c1f09f6b0cc64f0f8e167545bb22232e773fd268bf9695837f8ff3fc90e0741b4fa71a50cff68d9e460e851089ca1cf66640038782fd8c80738ec6dc1855f74d0cccabb4d84e5f2af83a98a44f2075759b5c23745d0e33b730cebb73ab9ed8c8c6e0bdeb4996982b13694d66d6bd341074e5b7e56a1466e559807ba23c1a2e2373b6540f3facc01aba690805205a8f11bfc74d4b2701688baabf495d5b87938f0baa45fbac3736f024880386b85009edba18285e07a8b46d7355d246a1bf846934a464a611e3a230512fff853999127e3ef347f88b0c563627502fc3de9b11a4a80e01e14fa6f1673c824eefc0b7d3f1aa1a8549365a63a95ce8bf166b8c8ad282a1d9a5b06f0132059517569a5a8a2f7b534f822c7315536b0a88a930a3137892a6a06c86d2522e013a4eac9832fa08ac24e462417e40a005208eb86b691d58f4c8bc82b1b75fc6d07b48f56854db1fe061ea5617dc1cdf3417179056abf928eef12563a60360d563c9daf969cb9737a525cd4d974592f16594a4375480c2eb41978b41e03fb48a88c0f2daecb9376ef900d4d47a7dbf7d1e3f7e917f889a3b2b4710e595d386b1e1a0680de56021a9487e3f9c613075d839febf48c5c3744ec44fe6552b11a6fd6fc485290145bd831a9497570557013b7067486df6ac1862cdca39fef15d500b7e28c2595923735bcf4e3ab95509bd45e52a4bc3b9ffc38d25d3e27854a3ca8e4e26a4866eed9c6e3604fba0db65a6c91029707e0067163fb52f72abf86deda90c7de18237fd17660ba92fc427806ed598d4a3359729750abf70645f8d3cdc5634d60eb338bc2281bd3710fbccab1247cd3eb7963c9c46820da15cf66e1fd5cefd9ff7f562f4a72aaa15abda7be8dfda8435662052e36ce1d1f4fef6c1111650267f682402ef3f9b97737c5af86db8c0c246ac0fc99c43995eb8cb5b4353079463af2a90b865c2041a111916ce0830b195f0a00874912f3b771f39631836bd29057b5ad4dc71ab517c396cad82e9d31d86a691e82afabab71340dfdab0b2677ae437ce823723902a3015b00edd6639b1d36f669c67934554ed04e7beacdb6372fcccea641ca77779ebebdd308ef4c764ab61f71b27caf467fdcadb2d36bee49f103c4df75571b4257c2cea459c15a2bd52f2c2bd7df629ae20c9ab853f25890be9dae831087d2161291cccc48d6bfd4143d19bad2922a20ac0316f29b277dac55017002327b050ba836131257ab0db76aad90d2a17183901b325c6cab9861d6b593aa447dd3ca07ad9e4658af4c51d782308b1f83e892b04c749ecfae959d68f12150cf309f90e8247eaa7234b68025fa40728422af00ce7d27ae78c646ddb0083eff09f72450b0cafac998427f618cd1715ff8c18ce3205cc47652c2c993568a40345f5eb72779b0004fd86eb2c1764525afe3d44d1e5ef3add97eb3ace00e9347afae4cd5f9511c33f807362e6f855098d3aa38bd3d26128dbd8df44bd80fd95ebc643f328a62e1a2f2421642a0c95a7eac4e85ebc41002fa5cfd2f7b40de7aac2c749dc7b65400625748c463add68c337ea116fe396e13ee1ab6ca65108bc8427dc1ee73983942f75538651245b4b6ec931413bb4c13a6bd514943fd65dbd27171183f6aa2127c8449369d30b6f87c8142f7be3fbcf1ead38ddf0c6157b0df3f852c1172663c8de5823db9b351429a6b176687428203e0315bfde28dec6596b15ed03be9c8b32fa4616dc8424a332aa680f9b53a1502df5ddb13bee822c83ae4fcc2f332e1d3a57fd18a5892b6d5b8639bb5f1813560d19240c3b4810faa1d8bcabeae02916d83b83474920a261d51bb09a8b871359647d173a61cecc81336c525edb5dc713e8d37046da3dc58687a93811c13bc4c0ebaedc5868ae89f85b59da4b02d751af3e7986556a75119e41753d10ba14a1116a127c62bb841a668642b763eaf92c03386436e1be91e3d10e6f83106a446e96a338e2ea698738bf6b8b34349e56c0dbd9d4994f4633ba2962f0cafa978140ad480dd24c8a521004c373f3797faeb90e1e9ca4b3e4b5c470a39ceff250c59248714e0d0d6e8381986fce4c510c3008725e6c1e6b04fa9dfcf572e5f1a120721472dc512c74d2ae082a4942fcb8dca9d6b3ee1764a0f3c4c212a8e30260f3d098575b04fae84a67f97e5fe89ea784a0279fe26f784848a2e4212b492bd6e24bd4cd5c14d0cc2a3616202fadbc1622e94bdd5d7c85f9b88c9a0e8ad273f0591c67ed80e626bb1e9135e137a0a49ecf77ff6cd310973c6500ff9bad5b5787b15e49179987fa88f077fd12e32e9c04cc217b587fbec7ec833d02a131e705868ae52eaa64d83aab95dd497c681b0d2c7e502d371e776cb27038fa7b094286daafbadb96429dea74f4d8e8f8e3df30e72dc6120509f172383d77d235c20373565d566be43eb966f8121fe23cfa3824e1ced9bb1091631be68f79f7a0670446479b462817c02eb3c32172d057557dc3172b12dd868099eebafcea2e6e738d213108a4faa0a7c30d39f5e9552e42477fc0704b9314b14cfdfdbfd6854d00c2d4b08cf33c52caea7c264433c68c41c6e80c51911c70e93f9c6d338f50d19965bbbb6e6a37167c0d70f2669d5d2feb413f7245f90ab387378d8bee0dc4a55fcb5760f235d0687b51b9e2a66cdb9a2b76520dadc3b58b101da6092bdefd940ede63791edcdd93bc71e82ba79c579e631e0760cba65f32417d977cd339660b4ad3698cba07bf385b0235fe192739f05167bc26f23b33cb891db00ab20dda7aae49d8eafb080829705033f324db6eeed74e327b98c736e8d91ee9c98ada6c686ac3e406771b287264a3d0e53095b835c723a4dade439d8e51682676ff8860b94499e1407dc1d523e8640b7751b2a0fd376cc50730cdb65551bd5f64dec28f7179538337346787c68e0ee50a240d563758714b06ec483e2486885d943d65ed65292434b69ad965271caf1f97d62380345602075bc3a41419cfebd0d88a681c4342b9b7753a3634fc19d561ec449598621227c032591e40ca818edcc5dfb3aa86450c4416c3c92a20f48bfd1421a9b208f56ca8cf8e58278c6077a3f10ba37413eb63783aaa089b217e755692f1b0d1e6d7bc4455153b60d3e8bb420968181183967b4b942fe0db86b1de6a7c1ac63dc9c4227a5ce1001950b6bd1c65cc8ad1e67e3d664a06bdbcf820e3b473cb09567a9d6f93bd24be0880165ecfbe206fcc5fa3e2affa5b682337a7c16c377e9c65500a7119f621220c68d46d55e57975a25b5ed45184d7c6e1cd95432db77667cf31cc57f6f2600494c1fe51be80184222db904ed2861a59e36fb1ace1ae02c068250ef9f4e51c2c235fb2f94b3b00f7f1802f962578723dcede3ef035980bccb6d38133c7936b2e3eb49ce18c9f2c0965ea153260e59136ab627c154b84c9403d45cc58e882e1cddc92add480a26ce86b8372848c3ac8aaa2e1c320220b52a8eb08eae20ae68aac994e2a88824a5eb791afe1447d443447c15852a16dac0f102f6ec6cc8832924983f4070cd22551e7ebee86646707b7e3b1d7fb08b816a7f77a68d9e28ff43d3264efe0497057676198446de33f15baecce729ccf3cbc77415a5d64af8d3a0dfac6d0c042ec1c811d7ec4e973049dc6a0eb9e0b04c91ad08fc7e0f4c08df76e33986c8da0c7a97eabb891fd996ff3f02e104b5dbdf9b7831c0326b8c48956b200d8b95ea7fb30d3f345a0447c39a3a5db56a664420fbd6e4896346f4888653f7d72e813cf8174b385feb65679c62f0f95d0fd3f88c4601165cc71f47d43f3b801a4ead5876e08903b2f523ac97733e25e5f5e74b757406165397a0045ee3b3eccf8513ad704a08c732c921aa775c7e36c469d20e97947026abd1778493790367dae22b9d70e04cc6ccb76b5faca3e5d6844e0bc50b7c2c910c53cc872cc5c010874379875a83cf0abfc92e2c4a57b644fa0ab02ee43c7e8cc328c8ef1cdc04bba8a29c0ead76d08963d5d089c0dc31aa4968d634f6dc803b7f7ca42fe10656ecbfef6f7f98faf7024a6d5f5049d3d16a97e23f366243806c58119d2b20188d0a9a209512ecde8fb4d6a1cc3b3c12ea4980a19eb3ccb7b53ad52209856cb5ccf01b73e420ec7e213f24e47bd9198f4509f9548ed496250749f49dad347e4043f6dce0b9735826d4a554fc043be7dd4d722b61aa64c7ecb3fca0eb59da5ebec9664b5c3dc4755d2647e4d41aaa9aebe9753804e38b5028096f964fed9a5c86c68c642a3b04a10df45d79cdc1a4641170e84b07d7067b07efd713c11c3c08bf401cb185ac46b4d4f50d69c5426f180f5ea342d7cc38e214d112c21a5b2affcaab8970480308cd3289c468b83a4f5b8ed822e2c2bdadb072aa5e8e3c1f399ca90d1de3f4cd9a00d474ac42e05295c43e51cf4320db89f78a8a59caef7f688d9a20f42d20065d9a19d3db3c9555da4680ae3562a7e2b612b7d7df47d5e447ba40e166d365a9a4b61cadbf99f16c3b75793b43751df1fd5547fe2fe44ee3824e85a54f30d0fc0f0fbaabd656a87a197625e1724737c18017109960a68f042148cf554615361fb46909140dd9ba5e0165279211b909a8d0eae444f9a099751d0cd60cdfe4b604c26a05850d247587165af630eb2688a9bb0e86a23aa7370408c4fe739bae2f1a63ac329eb81d076a8ea3f57c124d6355b44f35a2875cf390cf4f62a8bd1ddc14b825e4bb18a4fa236a949cd991efbd6651885f9b0caccf96c8e504be8cd53c722ab890870816744bd8ba37b25b59503a92ea64c13b296168c9d25de7104601d726e6559e9eb466d1777e1f79945b63eabf6ea511694d22d915b4313b9fdcb34ad9c2d9d5d450fcccbf82d1431bd991f9dfc05cd95d4fd877473e8b5614859ece1d79584ee30ded1e5676c76802679b69fd6cf9c9413feeeec8fff29c5b3dda9972977bd7c096cfc83ea76475790f04a3de4657ae229b7c225facc13ff83a6599aac01e25a8697d487febba0df9bff4339440462996045cff0245aa5c7d69b0dd04af41d0e238f92be64bfb4624970907077d2029330b864ea99315d9811858d58ab58a404bbf5485161a1612bc47e6a0676e451fbd209cfd024146d456f39139b50cb5f7df726be05da8b039bb246307542316fdea80fd80ceea02d0657ce2028021626f9abe05757bc020cd009a7a764ae70e82a917ad45cd24a193cb048c8d14be9445b63b7dd5f2fc084f309d1bd9b19d093e7b09b5cc927894594ab1a683e0d2ff510e7c414e30036c95d308c5a04f88036606ade109e013e48019612b30097e425c282368b5db048b031f201798095b0193f00be24099410b7002fe0638206686e358edf16bec1afd8d4ee3b7f16df4373a8dddc66ee3dfd869f48dbe46af1adb0dfa763665178128689b75b0dde187220af485a14dd085f09939e78cc17a9c3c7e66ce21635a4e93d39722d798395b0f13e3e7c89d330d967372fa9cb863c6d1324f18be47ee9861b60c13e677e2983246cb71d2fc19b8c6ccd162e6e4287d2e73206724d8f2a17f52f89a38c6ccd1629e18fee1e0486e091b4853770f65f1f97be0ce8c9375aa895121d573ef05cd9e76df3799ba14a82dfc5053b97d38009eacdad67af1c8c53e1d92883a5ffad380b420cbf229f56115f427e85bc3d2c87f7d1f293b507bbccd5667587ee23b807c1d60933f0325954c18f2ef11e725acc54a522370da8206f7435630a88d778e2b60aab653263f866d7211eb82031e018b8231098cdc8962bf5d82a539c7ddaf7494f2972a24d1c04eb3012101a0f3043e2959d42764987ee2f5d1e11afa4ed1dece78d48118c83b8991810f822692371e713fe66b6b2912e3e04a4fadeb90544590d3e7d18581f773e1e56f61641acc0573de12d6af6a0d78a59f4037767d25e33606496cdad5a83d215993fc27270dd6d22ba7927499afe0f3aa77af935be6fa7680965757c7cbc57c42cee0ae6c7833cc01d6b72eaaae5180aa3e852b02c973a85c017094b6d0f05bea797a0247fefa4cc50a5dce370471b0d9f6d465b6d002af78089e6aaba1dd5c56279b79c0357350f8a2eee06d2084140c4b1d805eb670f6d3bc43f1e54d8b391898aae102146e2d10e5e1cea833c895fff409fab2b184d9802e5cee2483544d2aa06975b483180a0f4fcb2928ee5ab0c1c775182f8ba15a882bed8c18f54483fac31f9bfd65d67c7d3c56f49194a88e742f9a92bb641c829a6608558975106ddbb6dda87a00ac68a70d12e5e061d2ee0674031d836b29db95eaf35676312dae63eab2f5d48c9ab1840e06969e395d80ab766927e3475ee314249585a80749d980c51c2e0f1d74d63b9e6835859f47ede59bb2c80814173d427d94d84741945cbb4f7d1a2a3bfd01fa4b512d40e1e36dd8c0c05554378ca76f78865f39458902a6f3071bb5fdbe7cd5f86e2511f5b77b2efe85eff72f5f65ac020091516dd31002f052b539222fa2f84127c6ad675d7b505b1621173952d648942805f969d7e4a3f8bd9cdf338b5f42f5f39a80e50345f3dc5504707b78ba7328379374be3c4344101f7b24e78ca78f6002977546776606c0e46db31b84757f95e10959184830e28ce5ab43250401e3b022f7340dda7db83bbd4d4e81456f6f82d1240da1cb35d077cc185d141b1c7ceb204581407cc6a52c813b618a04c7f806caa8df3d09b04a1d1ba57154867fe95318446e12aafb1b0d77cdc0236af234f7724a65454ab80c144f3775c92cc15006975936124b1c7cd40cd6c4ee3013195452dfa1341cb50228cfae44bd87812e15a0e514f5ca09eaef397dbcb84a35220d686f59b634be8810cc306c03170223c95054b99b8f33c1b14b20233cb3df430a868cb390c1ec34d3644fbd6bdfaa555697d7cb5cb24726dee2f5ada3c4da530ee15a693ed31aea1bf3a5e937adcfb1d68ee301ef9e76773c0674bad3d45a00adafc360214523581fecdf8464a40481cb22d541abd2e40b8ef0c6b2c64f2bd60ac3953522a148321ec7ff786a5cbdda9b39a791e09dce1fdcefbc08bd787c5aaaa79ca9602cd6e0f78b959163bef69198ac99e8cd7f9a8db0ac46df5df67960829408e2fd72ab370d786214cd223374d57cddaa898df01f7dcab64767004b9bc907a697cf090f10447c46b41506910d18ba78b4920dc3924dceff96b412bf23688150348a0d51cffd1d413b1aca1f142394e3afcb46b02a8682fdc88b15ac753d5b6f2163a9e5b1c492861478723700fab7aef7f9c3c7859627491a888feef4943067df6c42040a9ba8c93acdbde4bd03921b6278d39fa69e13dad6ecba0b7464c6b70ec34b93451b05f4c4600098e8b600b4681109a2c7340ebed12e62b301a936349fb7dbf7b0e4e7cd1ba284a71797a4dec830c731b37cb65adfc25e8fe8b27221b9debbc7084b026a1d9f53b0cdfa5fbc066d5d2d97311b27c8ae715085a4cd42080cee17c742163be37a9c00495978f9124df0075a2d8d77b3b575c96568a64a454c20c733bdaa3108d771c809e8d4a577d566f6e071f2e68ce086978f01af5eb88f80c990bd1154f98c607d6944bf6ca5984a8f4298491569d55942a62734836f07b17303723ceb98880cd87f3e0a82094cab9e73f7973ce217cff33510839860ea318856af9d58f16ad101c2a22d722e456f77c5b5dd27c5e22230a384496832e095297502587130b11645065f821443d336a74f310b4add2b779c18afe515f513abb14f1aef373d4f20532f612bce97183c56da0fddb77ece6313092d8fa1fc45bed5fdef6f0dd3b68b82024aaf760625dcff38a9a49c8c74d0cf8e1e574ec4e614a12a01905863b599398275b16f12e3d997c5049550196a893bb4a2ec5f5b6eff2bdea83b986d1e7a94145cc256979b5f956bcd9767498fa281c368248c8ec512a762d76aaef4ce388c4527d7c7b7fef2f5ca4de219be1f66189ec17409a0818efec1e3b1dd77c15a05bc63d0031041439487a46bd48e9d05a352734f3ba923d262d0af8a69ba2b4c1cc58055932742516311aba55c8b8196837e8622e1fabcf89002496e234019ed7deb3440a910209f8917e2ed152aaa86ed67618de87795fbfa3cc32e15aef20c1c46cd599cff0b030dabd2daef1df37ad186a75e2ce2addce2ae876876c3c0b823b30515f434243ce88baa3b9b881a669ab4a75630a774227a03a866ecd04f178be1122d2e99b5e00d5e0d343620347ad070e341209ea49d52914ce47111c809b802aacb43b88bfbb9a568211df44629f642ab2401623ba348d3ca60ed8e619005e1b9290b08e04b2ac7213aa7440a30e903847d6eecd39f7580eda3ee9dce0ec220c05fb2c51dd34725acc8ce054226c6426e942f7f53f24efc8b1a4605fb4e6b86cb4d6adcaa8bf53a68512b1814773b77557d8f6f32caa4370198910a00f99e9382967342e214d981edbdd03d83b91513fdf576152a2e7e70500c63f1ee95962dfded85fa3047526fd03398c5abcf3a3e1f02dcee7dd60d1d2d0884dd6631de69037414374dc5667e1180790e46449e10b637610e78e4600cfcfd6c7e1207300b0e1dd01c7a1923269269c866f8b6f075f3d5ac56904516f9ee9c5937a2002e66a0ff7c9c4c18bc9950c9a489974581e781d2779628435592d6f4b6b998259e910b67df459514a19f9445601155232449e94d723a6f9b92ab9d6727430c99c6282bc79944a43f2aa476efabe79332e9baff489d26676a4ef05f07964008361b60cfb10114efd31a910886d93d72ec3605762f722b55f26eb894e91db206d060ee4ea8e9238b974c465cea1c14a6fb06543629ee1165a34ce39bb1ebb617e96d80219105c3d35e3ddd246e2357a1c893e4f660cea2398632d567c28883d2e87d99baba04af7bf04542c24b2058ce767cc05232b48ab9d61eece5868b05533401dc2ec8bd7682de66ab711e89848bad04f56732803b2c3fd76080f299e7224e05b0a9fad8fc250c608b29be452ed8d8b6306556acf9f389a1270836a04413609a1d1ab6e1dd5d9d235057235390fad6faf8e21fa6fa9fabaff3fe86ae8e16ede74fbbaa32f73ad664d9c495ac98eea0e279ae266b9be1be102fd47c6f91570a91938ee7d3b926e76de3f3d7ac2ace80d4cb2d12a735769c2113368f28b44ffce9649faedaa6b98b7469a2fd3b5664608d66d6154ce85e4330bbcf3abf9d513c40d3d9da9801482019abb7fcef4e749ca616b0978a982d3e9c866bc8dd77f93f510422bbf4a5d47502761436d0d6e951822e396c3ea2f8e02b8c2b14d00bbae9f9cfb97c9d4492166458be0e3ca2e31a663b048bafc4cab50015039f67ffc3ebab48fd1ad68fc7106b4f36dd6f69e6b75264fc11c5b0c791de3ce77f9ba2b7239feaf4a87f7afc0bcced94842ff29d82192cf7daf49dcb93c2028b56ca886177fd293591807e18384558ddb900316b04ec3d623754250071fb8b6af2a4d87d18fedfdffb807cd408cc80f380030762e57a05d375b465a73f5fc798c68f54b4e809a4cc519618f7af1a468e126ba73d1a07906addcbfac2296f0d03de079189249d13c7377b9968a38ee2e0a2f6413a0c8df57327b2ba920f7595cafdb8fa79b58ec9a0ab4f5604d95ad1f697ff02e33c5f76e615fe588546fe0645ba6d1af5b6ca803184912f778b0db503c8e9b44ab8f98089b7294ef0ac01a60a4f1187a34fe4262909f561fde3d3ed1e6a5283c15b9964b198444d106e50998092d80a547d492e12f41a0c023fdc80ee111c946dc629081a3cda10a3b1e85c424ad107a4f6dcb99cd9811e6b225721990f41add00ea8b35b85387e09132f7e05e3a0ac49c9362a2a56b63d10f7c511b4c20250e9cde6d876114608e5d05eef5fef43caa203487dc81f6b805f97c80a0569e57b159e399600614a1ecb84c013930e49a7f4a9294f5c0b51e682cdb43676ce46f299b344ff2a8ec0b8dea68df35a3b10d5a5498a561a9f73f8679c7ad9fbf213321144d11ce971fdb9001581a8274a7003bb88259a7079903779b33dfc77dd5e2c4e247448261498158c4a6e2cb858a29cffdf2449b5f66584447d9a0381680f490accacac57bcf6c0ea0815357ef47bf7427a59d0de069675a8c7772d4ca9b6f6489b1efec5849c33ab7fc125cb50656e7ebecf740ba9ce542581c42a27bb853517d283e0160e445096a44577905f4b75056f4f86ee24e71e7a26fcd67309053f7a27cfd25d5e25cb7e152b2593e52db08390b96e867ab683cb6bdd64de1fe0f3d226486d5260e21c98a3c1fdecc460aa4589c9c7e2fe5c773c307d0a126c0ac11a4eb59e36214f7d9cf588b5da94fb963e3ac5e1690bfb9e794fa207e2a37bb1c92da3e0c611e02c73c9800c8abb6e3e96e9914e449d4ef6a1f531cb9c04b8bb0254dc6b99b33726e85d243dbe6afe96bddbb7364db8f90ddc2c55c56b7a8787cec8f99c2fb3016637cce6cd02d4c8edc45dab90e92470757516ab626ba967a81fd753c543e85630b70d7af61653abef4c880877201e7686d60c24773bc15c9a8fd5b4a2539bf3570ed1794069d31a044eaf39408a99bed0502aa6de4356809527399936eb60edc68b1be4921f5bbbd45c5ed17540886310de573e9024bcd290724386bf95602391dbf5c2a3b3c232d9d38a67422c80dd2a46f04b2baacd4b89c52986a90a5bb3a5e41740331f57e28f4acf81b60769c1e4302319c427dd1856f10704a8457ea09a50d7dad41ea1b7cbfbd428f3c7c2baffe07804800bcf8aa33785bcc42c8c910bb16217f466c237eeb8c9650d606240dd641329c2c4a641807a5cf4af5c070b261e4e3b3db17af687e2f946db01cef665837df1cb5ae982815b0e072ccc5eb6ea4820a553460be7344177a439c41d4eff30d84d8c69b360cf1dcc3c571b4b37b685ad6af7e7f30a7cdd4bedbac884bbd3b2d6eb4dc4d68779abbd387eba064596bba0c1765171b336d0e6c69a4be90223d0bb6f287b517b76b7e1ab65690b6e9cb6c2a71722ee3be095a78b3d4187e205c97e13b2f9212549ad7ff06a72ff5d0c7755feefe737097489ec6006b38a3414c8a8993f9f10bf5a5a0e9904edfc24584a06992e6de2c6738370cce0ee463df57aa4b77a59aff5ac9ed54fe137e5c6bd996ee8e6546481d5baf16fce1b74e3bdb6f7ee656f0aba21de6b1c017d88b85367f14f656a5b0bffda996dd180b98fd1d16854290a47847a04939bc1f9f6081828da7351104faf120eb2338274de14f873d7a7a969857b31957f1e323c82184b50b6abafc0b446889e2712db8579f42dbc752eec51e7a1bec5de6a4b7a27f678dceb3128d7b4a897e49e75b84352cf4e3d9374aba3be893def7c9f20fddde25ec7a05edd92f6b385b3eee562c585c2df2cdf2f41fed0d2abe7c2e2fab2e297e15907cbc50aa3f4e3d27d89c21f593eae1bf0acf657c5ab7a710dc14a736771e5cdaf90c060a5ce37dc5c518c66dec5952957538a577ba599cfd2cc4bb43206654af16aacd442b19a798b2bb9a8a614efed95373ea3999768259a942dc5bbb1727b60cd0e45375756db89b7f24a54fcbff2e8e8028d9f433f905edb8b0363fd5fffb90dddfe47466656dcf036f171a95ec15a377913e0e325eb8a5517b4dfeb54330b3c9e039aa3aa855b3052aa9a74ea14ae59b46ba470d6de23dbb6e9045638eb56919daa4b16edde55cadd2669b5a2c429a0621a8c1a841fc2100400529608e28a8c5c5e1ea20781e27fafd7eef55e12c6bc4fe8b1caae37b3b6d612a2d636217b6fb977e508e4071a08d3d5c93063a6f70428304134ade323c3ab90c4aa726154ac90fd26ee31c4ca02051e68c07c56a746a353a650a1d2f05a5792fd581347f922b613726c3134193e653493647590c28e0c9f2309f6abadec35b9d845c49f179b712d57aab7c34b21c37755ccc8d0c464f8ed03351226c3a334f003a10e0a199e7b7951c67824938ee24ffc9155bef803039213421d9ce10f6764bf0afbf1726e86af49d8afaa60049d3c8112447342863745f9a123c3bbd6b0e172d4ab65b75981ab11486402f6e8d33bd12cdbddc0cad938f1c795e1332e70b82a71e28fd59125fe1870f3848f8ee943391ec77aa932f48c92c68606f6822a00e00a226fb644596baae596ba6a3031352bc4d4acd082878367430cac5981082d980183e3f52b9b34934930482f47469c0d334a22986143110e36dc60030c830866942237ff2cacd79ea4b36389b2560abb59aa5a666a1f1d4c6c73de4c2980f6726d75777777b79431a3b3bb71f79d73c6ee8ec51e514a306c7c3f4208514db8bdadd37bbc72856d430c55518ecfa109413e44987ca802473ccaf111c9a7a5813a56ee5e72779883dcbdeb7e1022773f80e1451047b0c1858f4f8cdb5879dba8e46dbb0d236f3ea4206f3e4d70d00417b090b5c336d0c828ed912965824fa64cb041a66d84e00a0ebc9a1fb478811442190abde4243cc9f2564a964b4862038d2ce5490a1940b104a38d04d5b26125890c18174c36583093e784a922724ae8000e9450865d2204f2473a401cea92e59328813ab03f293e225ff211952f0db046fe88c421007cc93560f2d540470d24a5b5ad96ecb70e2c0cac819747f2104e2c7b0b14d8efc740a687e99b4803b38940e4696d8f1e666eb6daa3ad4ce7040206eac82f85dcba17038170b1c7bc95f1e6c09a590f03759460a58c929bff4e799e7042ab65ed5773e2ec0e869929868135b1f4ec26f172b64d579c2c5cd77ca90d3b7f8900b9d820cc566126550b2c0e7d13719ba065467b1ece0c4f3ce95c99613fd86bb5b6d592b03c3529365894bf24b0cab550a7b521ad8a7603ad8a5625571f6d48aba255f1628311484720df92675865fed9dbfb0f8349b0b6d24674a8854025a5437428d3a436a24374482bc106fb86cea6d995f436195ac928d7734a49a59452ca7e46339a6536349b369d4d2af31349da858c8c12d205ec66dfd992ba9c4497a3f6baeb4f292b97cd3eec322a3749adc8ee6e39a7fcbc72ba9e645795bcd3f2ba1c7541a6eb8926a59cb3bd98156d104688124883d50f5e6dfd633769ab924e94ecd47c581626d8278cd504ec8985524694230e803a992764e8c29ae8cd63aa0242424242a236dc0013e20398902a3f5202a56f909090909022ac616541ac0c3c071c5720f08aa214a1a13caf0cb1c168a9a252b56aba9d97e23830fd8a515830b231a2318ab245571e08a2427a91e50d07884068769a8e3d22cd545f1401348f4304d234d3b2c841ab2a14d4920cbc52d5aa66da81fda051a402eacca01ca240b1816ed92dbb65b76c198dae1a72c2e0c0e0ab6f61366258179113904498bf885d432ebd7bde943833d6dd46466b7777d3ae5bb7d464679dcdaa6514d367df289d31993541d5ea49fcd25efc8095313c0476ce395bad5ae984dddcc056fbe6dd314653de24d7a5bc4d4e526ec21a9ae54de3b2ca69336f25aecabc99b8d2c699386eeb60e84f53a96ea7086be067d10661a6076b20aedac4301bcdfe699aa6497a654728259bb3c8890decc0892644232072e287a8893432972191134300b52a154750031809694058102106900d8608030968074700418a15238080046486116140e9170c324018525a5fb4b42108815404243c1a08f10321bc60d2da322412628bb90358cb22592003322db0801416f0895181dd32240a228d9717b6cb902888a3208c0e932bb89665190f8ca094d23190fa05c748aa3efd823ffd82325158ae06444dc0c0082b55e4cb5b020bae341124234413506cab89272e2840c05a9adc618433a0384a810704bbca70e88c19c83439a307af32ce08e3c76e190e9d518433d238425249ea17f4f9017232001b3ca12f1f9200449524606087164970923d20609905329a65b406233489126589295714418a200769e4e00a1499cd3ab0840c5c800552e4600b1870f144e3828b2856605944404de45386444045e4cf7e8600a21184d08f1292f82162090330f1092288688827800c1044510928853434308411c4f8c072190ea521254a1a53764c61b30c87d2c8c11a6914e5c0b41ae3bd980426d7971a6918e1215c202221a55f5068a84a919101c038a23979280d339a20c1450f9080381a52034a9e191201c144fe9e63d6c46b85268d6a9a0788d08630541a011199107caa0a8aa05682b42b8698568a321a1021855045be604dd2c18f5012183f0308824f52108418c0109eb4981cb1321c4ae3072220903a0ed4564ece6896d11d32b02c19121921450b234600c508275e51ac29432223909899c2d60c898c18228527b6942191113e438a48aa7d038980e0402bc321352c906986444c9068b083ec8b21542a08c328096900d10408d90b8260d37082524a29f5a10645449c0f42d0807641240411911055e45586444240c9c0061be76bd958637422e67863582d43a21f1f3c614b39466984221aa29f2d887e84b2cd90e82708099d26c020065460618231b6b002762101318020c6154a88220650aae813642ea0598d28d410418449b135c321353a60a5e529cc73d639e9a42d3bc3f0cacf4b7b764398bb7be291a452ca86f204310a6a6db568b4c9df12aa840f980fa9048da22961e3db4a53ebc369b610c6186b8510c28cd65a82b07ea74bf7eb2157ac69a734f6a8a7771a654a9f4d082b841aaeb7f488187494db89510c3a3a12231e5589c10e9c32d4ca964a14231e9dec91ccc596b5167f47e8e930ebd262eded6157e4845b495aadc3c0e9dd5bdd3bddfe74b256d5a24552743b9db6abeec7ad4edf4eaadbedf6ba52e75028570a0f3992ed37fc1dc991db56aa956d657bc2495a79d5b276b3276b397bb2f69e77ef301175d90531ad5e254e8bea36a53aac3dfad445fd645d4e27a96ab5be242d7b249fbe42a14ef4747a94cac4fae9aeceba4356ad2399a6ae32e1242d4a8f504a69abd59242c3913c7f4f4669e960043a20410ebe324116ade4562283f84bc2e5c943f6194f5e6997b48361e2af475e6d6e938bf2ae3e6f5744c5624d6b97b4ecbcfac7d2e4ed3798b5c7169c211e8b1aebdca7655d6a3bcad5e567afaaf638777ade263a224a86441e18ca5ff421f2405046d939ef1019a1c6d98b8a1135c48b11e3af872c53af29db4b7872fd112526539b5a08cc8d75e0c94b622e9d967209efe4d4c07ef028d325ddf23e7d9276a1e5f44794f0b0b9b0d8b05fcd137a347449cb9123fb459fe8d2e28297b476a54a9c167c8408fb4558e4431bdb108158ad830748d954aaa1d6fa392b2cbd5edbd0b0255c85fd603089e3daaee5489caae10a68e7b473d8b51d265fa68a2319b0c6749369337da7ab15ebe1b767fae5c242261cd668d8e9d4116ce9dbe72b761160bedeb56123f334ccbb4c97788a02c0189379790ee7c897e93058637a16b604435ac24876d305c2f4cd74984dcf3293e9f14a1384d2643242c34ddba0098394601f83ba54a511cf8305b5621739d6b05f0705b9b8b05f0cb22252d12e98b029c3a69214b2aec0d22089bf28f412d4d2500029cd32186986a70eb209547b2624871cd8c6a15a39270b8311c2881f10a3917cc9d2e3c53da55f42edc94fb902cba47fe44b66b87ddab30200f892bf425a6e47ca1848338c0e2437f87a81a82fc5580f733d84b53edeac529afd19968f6cd8cf47218993235ff252ca8db2b0618d5a48ee0c657767a8a83d9823cb1af68b463627e7cb89460be897bcec97b4f25808b6d7b0972b38326219adc07eb625676715daa8264cc861613f2e77e9f51c9c0a308a9beab36f56577d536587dc94df917d6b3abdda7b755557a6306c0f6733645f222f12ed11ef40b3499b37562b1c93a53a0baa57f2f3f26ed9252b6a3ad4bcc34b86404fd62e85c0ace1782a6fbab2934175d3a5c49bfdbc29752d85e54d513b2755df698be52546a2ba09236149bc446615ebf5dd11c95818ce4b16d4ea73b58a744523356997a7ab29f134e16fd219e349c618a3f693fcbc277b59f1d7d3b7f6a68baacd5a5d1586556ada94f3b0a39485e55feaf5a6b7ee57b36bda670c167f3d64fb1bf47e4a3255f19055acc3c669b1f0973afdeaadab24abf08704667b61961d0c31b3e01d2646328964d7aeb14e57afa7f67e3c6493bce9daab6eaa3e753b6b37c99bba260cafd99fbe25d2528c7a4569d9e3915ccfdd8f875c67d681874c7db2e9d9e9ac37ddd2dd81568c645ec21bbd7a02deb8c2de6897da391b141081c01ca3ea281c2916d1135572e9b36bd7ab7a765195e5d46ae138b1a42a4b6618c95ccd194a574d24594eaedf2267fa2667e3c0588643eb829c2e0fbb19703cdedc48bd85e5b55e53ffc63c0ed527fe9278a8cf241eea15856754c9d093f56c62d7eaf328d5b3ba425d7595eaa2eab74e6567611b346c868ba48ec2486ebc9378291c6f1029ddc02d38585866df49eb1b3559e6e3a90b72fa9ca8393f3360513f1d09d667f774d6955d90d33728a5f4b2d56a7559575d5befa26ae16869c1d1ab54b7565917ee7476d865a5a350cf6cc8cdc27acbadc471b93cb1d81676d9e17ea96f6f8c2423523a0a6543669d85bf245e5f55cd70afaeaa73bd5f0a73a89f90d4a3bad6faac7ad945827ae7c6daed4e579851f7f452a705d990b598a9e6d26737a41a3520a7744bae971cf339ee4b75f984e4093d221460828a10a0e4d96f400e8e6ef96122216501e3d1e4c05e2cab8f40caf4ce6d6b1df6e7e4e453a491461a69a43021763ba158261c2d2d2d1c374c2cac154a754ae570ddd01423aba5595690f59de6b8b3dc387545b673f61c8d34d24823a5f6f4598e7e3b6d1cc77d5ea69c7d8a3e753f2179bbbd9f907cb2dc763f7a14b641c352ccb19c4b92f3519c2427af72b8961ba7e75a386e64f6593764ce701a2267e04ef614638ca79310976ef58d863de72454876c9556d1234eddbea45870b4b80ea5cb057fb505e3b8815930cbf330ea2f3939a7d3e92424c7c60606a3a1f13c1898974c5329fcb5562f2f17b645a55eae4afd2585ba769b3a9d8464d555f84b92934f9fa7f77e51084d5d6b734e54488ea739a79c534ea6393d14010911410e0c511221c892e505dd7769d71064e8eeb6e96e9a39a5940d9bedcdf92d838778d2b477f9c93cbbbba59415ce43082184b0b1b0f15edf05c3cc9d638edddd52ca150864a073ce49e3e1acad496e42fc13b249a79c3383c910692279341952da40e69473ce09e19c734ee9cd39672c452a71b43e73ce6932ad86a8539bb46693d60c0b4d8cacd6ac0d3a6bd6c69c342b514a33adce4cab6d64339b5ae50e4b39d59229a514cf9969b50d9ad579941dd92c7bbc966571ceda4696c11e95873933b9711c47b336b6d66446a306bd5a67d775259ab55192198d1995117758946a7d9c8f5aa4996cc3e462b29964367358b0df4c6c3dda68464a6fd9c41efdee121482d58ce4c4d2cc5a3768d846ce49b312a534d36a96d1c09bec309842f7ade3b49c1cac65da2cc5eea62cd8a314a7a6695d106d562a618fd852cbb21964ce88c879ad0b5232c98de3b8ada78cad96a6698f734ec945d3a4997c74c969c51efdd3a90b92fd3425ee6460e3b78823ac291d962e21ac29cd5caa9ac45940df007bf47510d0b2a1c8b4997c5c6c6cd94b86bff0a646afff132b371b6736246a398116db0c7e3a289c0c32ece0940c5b9e6d6db0f863b9521619ce3bb3ec5ad66d935ca9656545412c323c4b140875e0155d90599a32058532540520c3774d562e4c6929b2df64e9b490210bbc01c4494b0cfb554d27c7aaed08800c9fc30cfbd5b354605d707060c07593e1cb0a554c3fc86153e558c0bef999f4c7cca6f853653287f98e0bbb212fece1af872cf3ff5b22730a7fcc85d94b017f3d5906c73ce6dec3dc2f49fe51b81f0ff99f401267c624fe4e6f18dfcb7b7859f2c539173604fb4da01374c49e03c809bdaec7ae4b629a14a357fad52f2161a7933b86cdfe4da01a76dec265574300ee32e2c2f333e6891828238a50cc85f7c476e4cb85b9850b63aedb933f28d4ba9f975db838e251cb40c3e2a359dd8fa5fab4271348ca513cfab8fcc5a389c50368fe68527f60ca03a894dffa7ad2480b6d5c402816007c172e8cb57061acb5b0df4b3e19a2d003d703a45f58e2b90f757ae4fcfd55582925cc95dc3832347d03899c90c102bcf92a111368e43e0b5e041998729321511257f2869af09008102726c199675c02c4c185fd9a8ceda6331d8d3c3d2aed75dffee263589c21911256e4cdf428c4952ec5e50a4bcf4deed18af6e6e9277b6dd0b0d9b9974ea58e08fd40760de17014eac9aaabcd60061f108aad2e8cd13c69c8d917d608eaf4c82854de2e045ff35ba954aa37a7944da1de57ec65b5e74a61183aa7acf4913f4aacf0a489932c63f3a97b031068dc1b7ca4dc1b7cac189aae2954faa6bbe89b2c0bdbbdd59948891f64d8d1c0e43a3460fbaa734176dee83edf4e248eca9a7092770343c982f1178b2e5ff47da13cb5d0679b08590e91e74e9f2ebbec27eec6a1f66646e9bbcacc0a2091124ff2cc3f4646454748502091123e793e5e699c199b2c325857a816167633c8dc425c5724fa904df1ca7663924b8cafbf7081f5fa2f096c521c457fd13730cf2efa665af1a34a1256a41c8a55da9b309b88058c859cf626dea13312fbeef371a86fece72395be41f53773f7ee1bdc9a333d93c25dee54a8bd69cf5dfb93b53826a16ebcd2836c833a3023319dfbec21cfdce1ac339dbe9ba1c3a58b8496cec52f2ea1444edd3324f45c9472b3675be4b8c89db647a510d93e01a3bc3d0bb97604b0c66422c385c0a13cdfa44a864419a0424786444d8272ed23230b54f90132f1404a224a1bcdd9423e453f5434d013560bf58d8b0623edcd33c9f3f0eb22f2bc227f2ff98b4938cc17cd204b398b57fac5a47f7a3b71d95dd4549a79bead50c9f33d7718f9f8f8f8008990b022e94a9e9ffcc9f3891a59e44f2a416f2a6531a96fbe5894e75d70664279beae31b90d76a54b848abec97a32ddaced8264575dd9d1771d91e893296e9f7825265161a54fdf449f3c332b4d46dfc8f94eea9b2c0679beaf40ae0b925123f8ea8250a23272868d1660cac1a8e298c48124141fa9c2da2e86ce3ac4256425b0665e754b5ff0f0d0de844935f47970a804c10ba1580f2a2d84388a4d91447b16a970451f1f2aa21441e30fa7ba5b1a484231d8d1eff4eac258a4a26f287629311b294f3aa393f6e6a3933cfb531e8711c2f089b5d1eb0914d4c9269d51e66b03e3d1c06ce8945067c6676159edc5576d6641676c1b9d53ceee081f4307598cd0dded75c37477b794db0fdb766d64f2e7f23e578d5b6c9b9492b694b3bb2184d0e64e09d31ebc9452ce9b29e74d7777378b1933c6d8ddd9c60454d671db35a5a8a9b4954cdbc695b614544d2ab1a026163060177a3108c8b22cbb1a8dc0d4b030418ffef480d2cd4c3b64f938e98dd09b593725b69c34d36ac984ca3a6ecbc1d40d39caa6a8a9b4954cdbc699784add90996ab5d412947153c1958eb449b5504a0f4367162fa66cd8700ef98a93cd9291c5524bd544e965e9565abb212518fb5431a52c5a76ba32bdeede012b7f704a6b0651b4a1812a489841132bb17eeddb1f7253a2223090e5a7a4d99338ad28899092270df294b80cfbb5e2df3712a7c2e25b0bdb928d484404144ae1b4b48b4c7f8fa8064e64d99c19064174812c88886022cf4b0ba02053fa6eb528a5525079decce844885ad9204c865289f8eef21b0a36b0dde3eb86c21636c3b300e35ea49cf234f9949d7e3a9d8ef4cd119a4ef58f85b3faaabbb0bdee50da0c7f47724881adffea4dff2250ed2b9111488c3f59266529e31131b4296fb0a87d72761c72b0a1872f720f4639fb7a28ca59b7d3ed451fedddd50195d39d7d3be12fbba6e57acd27d767328ad4eb5d40e3a4b425fd2acd9c83c499b1aaa484848d4eee18361e0730723f8d1f2107e1d45bd256354dabb5d67af85a6bad75d62adf46d0d7d80a81e54037c9357badf3d5f45a7acd6a56b39a55ad6ab5e5663a91984b47b0116eb29eca6aba34d55a6bbdec82546bbaa9be845bedd563262c4ccdc0d0b22c05b046fb27a59c00f6d00e1b6a34b0466b6523ed69dfe917d92f067511500766ed3d05d499d71ead0415c52fa25133c9da95aca19135326ab536d33ad6ab430c30974e24e61aa98841b046bbe90856e62f0611a9efbeae7e4fee21f55ddf93af4bf3b2a6bd6a1046c3483a886eb141984f46d3112c15ed49813a11eab4f27c4ba9711e28fe54b15f0775901179be89140ee4393b0479ce22604d0e1bd8f8af6310ac99e768e267add606750e1227fecc39e747137fe6eb5733fc593a23eea22b869d8f41918ac681735a213527991af66bb5e47560fb72f6105bced6b8cb69ca696fe65285cdcc46515f7e1ac9043ca49f33c2181ff19c734a29613361d30eafd596f059649b854b1a47083d7d292332893fdae96dc0a16ff2b6c939bb66edb65cd23b3932c86e4913994c91357cdf896ac27e1d254e429327a641c80de050922349bcf6280d0f4f90c6dfe4c951f69671a5ef745f54910cc7d64aaf9f37498b7cf759fa2cdadd8dbf1b3fd21569ccca6296eab3342e229f1599d73eb34f9361f5794de2c8c5db1fcf0ca8f75177a1f010ab952c863cb95fe5b56f99bc0adba061255ed2a60c23493deb159e384bb57cd62d9bd5b1e3e4ba23ab2fb9ee2c4efcc943daada4edbb7fa4af927e92f6e83b3db26b181b84b19fcc9f39334a5bbe4f46c8cb1b833cfdb431c3fe30899bd5b2b5c4818e4a803929aab0cedbb9ca93ce3927b637d0c70b0ff207f3923f1a14963841a66f7d8c4c899cb8608923583c60bf7a030d00654a89342094e9bb05b1408a52831f2b404145d91414f06056cbe5d01c019b1865589eb9c670c6457c10d30ea14f64d84e296c1499cfcf1623955fcd0da5644d395bc258fb2666b03dd93489ad5619bbb9da77e609a314aadf44ba34e37433510961686c5e28945f6cf4924a29a59cb2b1946163d19523c8404198ad8b36f1944a7db04e75ab92f1b46948d8fa79170cac2aa652e7696197a7700bf3a45218d2ae95da5c6e4fac757b622e41628ed7aab575f26a0efc822d8cb52e8c9d7e52dd0f16a9345cbd7e49a011068a98f205ebdc65bdf6cde95bbc2c1dfe7aa06caad4bd9cfa25cedf72ed0ac75d375c5c386e6017015a7f790d2ecf812bd07297bfe00a4c61a4e52eaf80ebade85dbe4e77b956be4e6fb956be526fddd6679363927853a943a39cc22cf5f67eb08b7c8268a4bed35beaaa3ebb20aa14fe6656d9afaeebf4d5a395eb3adde52f6f5dd7e9ade7b8ebba4e775dc75baeeb8461e051866df9098f462f9f393e1fab481c1d9fad4f97d5a7eab3e5fafc093a72bcdc54aae59eee725bf7e3c9dde95d27bb225a0ad7f6ba4fd995ce42dde20f1a65fb6d83028bf2e9f5d6bbbc27d6faea56e2b854980626aeb7bc75971b69a9cee3c2aeee3d312117ccd3825ddd7c4f2c5691afd9c29607106c8ebffc84f3205ff3e799c288cb5d7739cf144674bc75285f2d98670a232d3f01f3b4dc8579a630e27a0be639825d304f118f10f99ad7818f84fec12328a70bb6f2650f632d2acde578e9c9b09c041659d4d5eae95b6cb53cde8a0c893cf0247f3143220f00e59e58cbbcebb6bcf59e584fcce5f6c4b6e65cb727d6727b622e37c65a2db885e3c9f4ee96be23bfea1a1291588dc3044c78518426a18c13e209e50d7cae0fd7cac9adcbe43241800f251f175a38fc76f9eac462219cbc850b633344171197eb30bb9eb9767cde35249b3962279c4a29a594524a4c23941c3972e4b8cc711d394eaf0e281ddf6989c216f69b4a344eec32c05c73d8ed38cd611784c7bb570c8cca9c1e7917c9eb3043188cb91f4da6df646ee797fb45a21f2b59c7656afa08befab5f6511fa150a878b4d91c7641fe83dbd1d65a9965be513222520c71f3ae87e311ac690e8af63428da13584393b2271914f40ad499aad3a45bbb6dcf41c57eda2aa35264bd7bf8f3be09e4e32426665d0c32cb7ca35b0e1bd8d3e351f7f2ed41b01f4d0282afbecd5b2d2929a4d0accbdc06aa3505e1514ac66ea35c03f50d8c3906b79356a2bd0934a5f44d6645df08411deffd7905d489691c9f4050a7f51f38fe1d078e7f15c7eb61c4a142f2d527cfe5e3f92ddc85ebf2811f50c3ce33761969c1c7835c88cb078e22860be02f3cbf2796b1eb0139a74236f807feeab1900bc3bdab09c19a7eccd5ae006279e1c2f018ee0b177235ef76197605e8580c587bf2c2d5a0c070352903fbd52a4faa6d5581817d92dbc763de9f494420548dd803ea7c22017500a09d51b54308849e71d8d5b07397911682e0d9c27b62d06524ff85bf8079048067c62ecf054304c0231b30108a452658098af5c4a6d88f266dde8579fb71e58f1f3e6e43711bca1be7eb5a46284ffda4f336b95f16eee30279ccd5b97763a645126702c9d71911084da26a4420da13ed45b4e88cdcdf00c0c2ed27b0a60fe43614edf575f2044aea6b4f2290ee40ecd11a4d6a0ec09a06c085f9476fa081daeb9e026b1abbbce7bb30f3a556f40afd88a9942dec179de0098499b03782e0a4f0afa270085bf986cbbf13f28df714a813f3be975957e15f0bb30efb887cf559ef22fac6c7bdb7cdfb50e7c76ffed9dc7d857f35775d8f7f9d4f873918763504e02e1862f69ecfb34d198a65ecc289793e0f2c0c1c14c5f25d784fcce64ed81eec5bbe3cf18735520014eba19e119be2df7e7d7c8b3f5a602294f3a54b10e113f37161daa38771fda211c80d5e017f35f7c03117079c041c913834fda277a187c1f4f42908d15f8c8f54c05fabf56da3dc0b7f31bfa4e7c93cc7635744c765300c33af8bc47bcc3bb286e63cbcdb93775c9867ee47e3c275d510801674f02314e371e13db06640149b42e29c980b329f919efcc743963bbc1999dfefb4f43c997fe6c2bce3fe97b95f4fbebfdf2287a5bc0f791e314efa464a1e972a7c02f9b8845d7eda5ce2efc72790c4d389777aefe27bcf3b4cde07cde58ecbd3ae08bd5764e63318c21a19f997779a5f7632d47ce6927aafe3d79534a7f7bcd72576edb8bccce975edf8cce90e3c44e6339f91c1de77a4773f99a3e0d57ca729cdf13d8ca4e6331809ecde775ae62e91d9bbbc5f0d7ec1fe7747e4de7bec86c03054012f91d9c7e93dfcd97c3ff01299799cfae0c1437a7f7d7b5def255f3352e6de5f3ce469cca5f45e9799c11f95afe9c48977893f27f2530999c71c097aa737862686493e8f6fb18361067f3d7966077ee11d352c9acfdc14bcef348ffbd5fc7afdf5172eec155ecf778a9ac3ae480d7efd15f37b1849cc656264be2369ee4e7ba7a7f9eb13eaecf8ebf599d35cd8deccebf51e3dfef1f83ff31d77c29a99d7ef7d7b5d24b07b19995318fe7ac8b0abf099fbd93c739afb29c934df71d83731f7b1037f4bf28ebf5e7321ac79e18f27bf7ce04f490c0ff975d8373f6e73087562eec3067f3ce41daff98f0bdbabc19f92fcf2813f9ebc037f3c4ef39ac75c086b6af0b724bff0c7e333df9134f757a1e630c37ae01d62e621e36124f432f732f432ff8efbc55c739afbf19067bccf5c9ad7dc1d34f7df71fb93b907bb22afcfdcbb1f0fd9fbeb4258e37de6e55d99ef38cc01a13ba8846d979435eb149140000000000315000020100a064462a140249808bbae7614000e7a9c466a509c0bc44112c328ca20640c308410020800c6001821a21901b02068fa44c7b603af965f4e0776b3e92439e6ee0df3f9043d0ba2916888a315e6157695466e2f4a16c7177c6a1cc7c508d3950d20e02481be892c2660f0d4ef419fdcc044cbfececdc2511a38f95a2efe2825a2e2ed5e42266650b9a123184c883a5985dc84eabce2305f065d9498a27bbbecd7322f50b349a2c92f2e591998dae67ebbb9fb5a98498346369818f17daa06af4ea3b9e2e3ee3d1b2f9240adec3664146f8bd6d5695ba63485d14ca530f552cb4c6fd15505d5be01c3bc03cfcb9d94e9788e729dc460dc8fa174560f28a237f4f44b96f716055e376589a1544f00059fc8abca1c349aba8ee5ec02610197c6f217aa1735a350b00aaec080e719a366ddabdaa7ae547d03a1419b5dbbe2c0c01dbe09070e1549ecf5f3cb5f819cfee76ae6d199e2757e38286671c5e0f6022810b3f32a86e6c3fc6a4e144ec95162ec4bb6bf2f85ef10518b454c17488d565d4221ff5f65c52cacfc016970e7b3140ee3e25f4865c7613e5397cdeb5c4db0ada37f9bc309934cb518f52ed3ff0146e557ae35776bd7e3deb7018a63c34eb7b4c1ac7d263d249e85fd60c762948d33bbcb8ce8946607312a51685b29f83b344c73b300da18ef91478956b4fd6377205d8c0a72dfca52cdc7fe47a5e80415542a9c802c4f94d679a9716dc78ae3f102c1653b2adea0e183061f3752ed685a1d88e2bc25dcdd565f0f2a1b81964c5adaeb4266dbe492c2269614ed8c80b0fae7642654bd006fefae302f749c2c96a2d873b9cc1786fc2e482c6326fd0c2e36e18618dda6b4aca0597a408a3f78815d2e9a00590a481de70484cb6f8d6ba4d0023d6b0c22a14d5876ee92f73c7b703c28d6ba62c4a9beeee1ec4a3e06d529de1c31e19c342dd879ccda2ff965a389b5c5ca79d834cb5fff56df25967095f1ff54a70d53b8983f5dd55de7cadaa146e8916d286eb4833f1d1a123bf24e39e5db4936262573fc28fad5369a46bc26dec02a0621ee02b1e13f7fa5896ecf3609c4c8ca5fa93695324f7e2d138916cf3f7d57d070ff0a99d71ada9e80ac8b9cb366cc399dbf0b8ceab1f55c7befb385a686eec46363e992967f1ea8416963410bf4f09ca5601112f1a0fa208e779d3f869a4493b048be70835bd1f6d6480cdbf0f75a27dfd58dc3f32ada23a9bd1c5b1ef15fa442cf400bedf203dd468bcb41c911a33837d941f71a418a2a96d3daa7e235fd29e71ed169f77381e86b1b2a5cd05fdc0896966360e1c621ea85e291ed2810410e98916b25f054327e2d7a5ed50d5fe8f5f3b5a93e52d6a6ae004b79c272918756ecef181daeb60355d748f975a7bad227bcb252f700e5cfaf9ecdb6d44b17144c155e2ef25f6eefd6fa166ab5fbec9900b17b4a9ac4313f0ef70c1dbe26a7469db161806c76f41e4f67550a101151da22ceac33fdfacc80fa9db3da808ad6479a05af102851e1e1b840c572ebee8f06eae4a6fc0eb4ac65f7c93144d98fec669b216d1b140b1f974ab36eac82fd0e1247b03bf2492b7237e6b7412b64f566d79c3ea4ddcd0e41013ee3a51d10af92f9a2771245d1d39a4c4a1b8858dbd38402f77427f1fdaeec5575d6dd6c5fca8f9a092f760863dd6e2b4af47e5f8e6050396de8972cd01d24d2bf9aaf82f4b1f9b9df5f217a21f4a22244b7f4f0745a3d5250e36ba70c5a592832e39960c15793debebce9dbd577826d60755aad603239865e8e4cf58851cc09ba5c8e6a2581ae77dfc27739f94d0cefd8e5c96bc4e10c3b253c4881138c0f4baf9f441e5c16a46130a90125618ecbb923494a6c27ad25e0d7c683706c3b9fb186370fb4c813e580ab3da85243d3b67d57b34da8f1b473b214806209dd225ecb78840b1c15cc7bffc78cdaaa108af8ed90e48e9fd1c7e6184bd1d328bc8153ca03bdbf3c2de2c50b60b5d06ec36080295bdf9c1c01fba71ffc84c06f67102f109780e0aa37f88b7c4e105db150b328c4fb0daaad6fad8368cc0b38a96dec46ec059bafcf0c56faf5d683a41226754a5ea094c6e05dd889b59bbd0a39aa8f870af1af6c19575a83f98d013097e00f1dd8c1745a6588e4b5c8fe8cda2b5d1e092a7923c62308bb7b14e8c8de31908216d89caf7a5524a030100143944549212aef0b9a0dfbbd7503f78003bde88f82d2ab8b55c555989d7efbf6b3ffbeeb98e8cb23644c0b5b9bcd2baddf06f1798d07b484cc6a6ea7f38099f162393b6867c91dc844cf7ab68e200dda96fa22b835aee20a135a349fc91522e4939b0a2248fff9b982f7720d0c4a1ba5a004eafa3c4f48776cb6027ad64715d879259c02660d2cc768cc4157d78e33a7c460b270cc8e5f372459b094dd6f9e36dd99101d1a3ad0370806813ea517d860dbd89995a2ef3aabafcaebcb0b56e293ced9d4aeddeec9d84856c52779acc58e39ee0d223debf7141e440ea059713e20bccb8e292bc0f0b51252ec61ca8663581f1280f81c245ec1cc7977418b4216fc57e90596fd21f8ea9c76d72921bf110a570a7d5aeeca8678de1425c72a6fefc3c7d526a557aec32801de6effab5d326c49950e16a56915182b2bb77ae37a2995ba27d7a5e7dc4cebf07804ca590e512e6f0497cbc8bddf992f8351c5013befde93cf3ce1ec75530b77946a453ba6882e26f13fd280c6d2c2a9b941e8ece17a4150f12d0a7861796e4461283eb77ceccfff0c3e4119dedc9785e19bb5b232c3f750967d825c20509f3090bd2b8d5592d298de1bcaba35a86998f366f484e85c9f790aa64e1161b65e314c551255ee1cc975f91cce014173bf4f6393e67b681cfee8571c3c82fbe7287665489203ede7879c856ac0ff738e169c68c47ae597811fc1a97fdc31c8ecbe470604d8c944003875809ad1f07001d117d4bf41857a92e9257b229b5f0e3318f1ec45b2ac903f3a4572d2136d37d2e0ba93bed7949f719b95d5fc55e45163092bd1fb729e78a9157299862fccb460d12b24c9edd78512a725aaafaeac63dec0cb282bd0e7fac500d7a9d9357058482800c6f5de20d0034bcb860b7e178165ecd39d90e1765bb39e3f82694a29ea30589469ee19a8a3af6d06a1edcdb574b8238b7d1b60a1ee3b0b02a37db4bd5f068d36cb2bc070cba265c377010af6c8669addee3d1d16a836e666a2a1e439307d036be7ed505033db9dbb60918a99360b296529bf9fff472ff87dd20283145cb3452e47d540833cb244291429029c3e71855ee3cbce409e16553e1baed26a875957b7270910a90ec1e021015e6b8836af1e01bcf6db986d23800d2c0b5edd2f9467b2e5fee8fbfc4393f15b763e8d2d9b0d1c5d9d9223cbdf06ca6dfaba08dfae1b9bda5d35eef451dd920383a6190570c17d03d64a1362ade067b8e975165d3825983264cca8a17eaba7dddc8a3b0b63bf1cd0cfd4e28f2b275a0ca6650d1f999e4bd822715c4148cbec4da862377a0679ecc77bb38b5ca3082c4446d5af019ad54a74526c3de0b0d1d637f3ea900bd0f1e776e66b57f97a80a3eff39d57c45393bd6a2ced250544e518cf086299b6b5f296d4130c9d9e80b9ec55a27cbc8680cf4eb0b55512489908ad637368b41bcf4ca700ee22c84696a5b73ab419913e9b3b64d6ec5603fa793f7fb4d24cbc5ada6f707b029f8e87f8f574cd1590b0880296d27446cbd45a38f532e4abb51621b40aefe864adc4ca0be1ec84581f2b0aaaa036e86ca1876bba5a30556e50981cc483375721f0149ca674291607e98ef668094e200ac068fa3bad6e6d046d1ea357ff37f743fbd16408c3e68d238162ad19d0b4273742a2c842520815cc3954bb9b2e0eee5ec8ff8a2eb86463dff758d25182754e764cbac00124b950667135b4e9a5f1b66eccf693dc8e3cc8ba6709a8ff8c5668af6bd15ad455dfb8b1cdcd295c4ca9937db9b1215cc07faf0660a4d0e9ab56fc481a6482e17492508167ca0041b812cd62b4eb015061120f2f775a1fca969af74d37da81a5bae7b8a318a6260329924495bc617cab2942392823ef4bfecb5de493a6162049225133400d3c10c815a0824a8b937de7fe7e836878d9a13bc5cce7a15dd2228e04148aae1b38382cfd7fe21a922fbf24e79515d01fedc6d677c81caf82c76976e8a55cdc40054dec6a240019cb5180393b207e357076f05cde25057d3fffb7181a273dc280cbc4260b7cc1356b76e249b759197ef93f1e3638f7488af8b46adf11bcc19887e8fddf322673de1c7bec2eedf12f31b9ad0a3003836452c572b3202562c8e82cde5071ce422396c10ebb4a6168742ac850a430f8affab0182c4130484d95e7d199a629c8c8cd73062c2661c4d143bd218c32e2cfe99f07923d6adced813c0afb41d836ef6d6e6acc09d375a63a1607f0340feaee97def24ed69acacfecde6dedae6eaed93b15677143ae87da89da0792582d9437a7c23be25ffdcaab5985ae65e26fdc262683c3c0fb892519ac27549a32d5271919e4676313224ac2755b6132e280956ccf6c6d6a6ebf2072cde802a3b5b0008372c4b6edd349408e74106f5b222d6136f5d6add4cab9350698107c1e026f8ffba6c4e75f070fa84cdc2ddb1bfcefe156932bddcda48abb79370f3b92079d35c9c4fa50d24a344705b227ff5a50d2e83c26088526e5f36745e30d1200a407a0147b889d7f05cf5825fcfb53c4c60e3388327a471fe42f91dc4441349dbe205e76e9c993feffc43864c591212b019558eac49692fb46949e6242d63bc8cd57b5e14d0170c27c569abd1cf025bf65a62b86f5a6340b4f03e265fe14ea937e51715f4314ab830239220c504c15615a643da015781eee3cea4a943c7f57b05a409245b93a1985ba856c0b50ec4779fb3e55425d4fa3defd0c5bddac73977a50543c5913b672ee039fc54e3dea3524caf3b7373dd9a4aabb657a603293b800b6e87d7b38dfabb00eeff5f6b28af5907621c89e5d82b6401403aef75a7de21a7538cd39dbb3c69b81cd452e8bb1e510025d04e7358296edad4e258137a2146c36a58731a9a9bfffaa915b4cf3cd06329012428317524330812978d47acfdc3359eb2400a5898668ce2807413fc3ee2570359c260d4c487debdd38bf9f07174f7206f49e23dbf6fd5a8490f8bb90ebb97af23ba7373ca85e8fe1ef1c3ea5b5df1b44952b850b67d9f68b83fbfc760b40357cd3eec28f634b25ab5c358176170cbb1c00bf74d4bd3f7f3e1ddee2417c77bcb0267d55db500e398c3cf6a05407ef0d03c9b04243cae235c4d319a76cb26e007aa40bf2122abe7e70c1a1d3c308a2c523a7fb4d1a351664e9106cc2674255f7df56e8256ce2dfb03e8079dd127b5c9c36502a9562f163dc76840d594785978433128b9b3eb835c2992650d156763670139fcc2768e9c2cc7056c7cdc09d8928f7b26ce7904024cd3a34c558df59368c563f7c917235182931c448d523f278dda44f0a3712a8a5ddb87809d2d72478bf5d1b466ae39f83c648959e191173d04e6f42705d6a281a6bfaba156598f58034359d6746261e1439e3865130eb07452cf218b39cc5334857ceb5bbd33c2e35e7090149de3bfa9c5340b9b646e817ed0c5bcd0f36a3cf1650b2490ffe9ac2ff05cacd54208e80ad08e9dec17358093dc7eed1192173e62b593286525b865a646b09266633336c06bcc7ca48504094d935cbb6290e1436ef075fa26db2902265f3d46b92937d2c7e1474cc8a4b5771279cc7a595153baf967ea9a8b50c84b2eb41e30e1dc1d4d99da4a5a8ad4c1caaebcd144ccb6b3846a04079b56e73e02e8b15d7d334d8f40a4aceade42e3333d32de4a2310b14f1a3b91cc6007b42f46b25a11f4839db46db88075cf5c01dae1af370580c601577ba06bdca77e43b2059a15269ab2c48f70d7d137361cdfaa5fa53c8e6292006722b63822fa0ca3b6be7dadf4b1d3600c70a77fbd24867202940b735c04813dbee21bb1b94d696eff9d7b9bf0168938580eabd7b2ad8911de8949511bd92071db1d0dd4c80f95b09e78f637f06d112a11ec9fae82a42150d667b55a4c03d8d61cca31ec1899993ae5a66bde19ed685e210fbdadfabde97ff5e01991a81661a227ba94641bf9da21095867aa1579a468f3fc187dc2c7023a7074548ac090f68cd1926d27aaad2ba709d2ecaf13d015787526ca3e474016e9aae3c5950c2d581805a1202cf5ff54e16a601d422065c4baba8ded193d825f3e9ed84230d7643e5b94505a732336ca7756ad47549f7cd06185dbf17312c0a285cc36d290c8e545dd9f63d9a7ee87b7f3d761b781cdb58abae61ddc99c5202d804353ba22c53cfb79066e2b4efa603fa5edce43bb5f4beafd3f0469f996ba161a78c893b2c28f5da804f84c0fd615941028714f3133c6692220fef1436ce0fce5d98a6aa38c16cc18a850f2680326aee68ba3f8d9d53b6cbd69167b98b7bd35e992d88e27813980f32218a3a66a0ecbcbc959db9661bb004c98596bfb91a61358d87a099b3aed0c4551a5cb42041149f101aa2e471818f793feef44f1174d7555b69179b7571af375ab28ac8f8f1a33e31c41335a8a18d8cfee8373c7845d5cdd3975e7350c6224ccebd87c3e70a81ddcc184c8ad6114159be29ce518285bdeb5808fde507751b31807335727d4fe4cd95cdfc384f6a4d002ec60278dd209405be92d4259a7e38229f3d50980c40e8e9141d44e2592c092d11d63f0360fc83232b6c074b7fafa265ea498d337ae6ff9349807e688668b5399d690292931c86fa51e33ca3202a9a77d68a9cb326945c967376a97c3d3938ddeb0952a492eb3b16652d2d473af01a4b0027858bcf837a424f989081634bbf7a11b2aac11f86eb03d31526ffac2b82dce9352e8b5ba1f26aa6d477b641a59ae62d7af011feb251191a627382a4c3e2ae2d8c05c1279439ec1793e4081db183ff46569500a9157f3970f642a37dc79bef4ad142533d43a0a24d75ebf7fca1d8ea65b1438dac006a74e6d7a8b238c64e000e846e63f7bd08eeb1f1d3e4ed812c710205c106fbf6a7e2d29d03ee7cbfbbbf11415fa5430fcddc99a95bb947153dfb373db0c0723c299d7cb3673fc7db6e4ce7a3d0076f7044b6c39667bf435dc5cc346d94bcbb05960045cb5ecd32d12a29dc4f984ab8c199ab97e51f77203b22bec7795071792321d3603af129574be29994e96186e7df2f5c57c9cf9d4cafa34e47054261e2bcc6069f094e5c1e1b1e2cde17e780ba90d113b305d8d9bb5913f7f3e489c0ba1d9868f3b816b835bf242ae9be4818099c2c8e6dc6b17e31235949ca12b9242b1a05323da125b2816710255280f0cfa6b768463bc4017b82305bb6815095324ccf5750c2d829552d0c38527c00874bbb6d6a6a4ddc8a65392d3bfb1eb6418be3c7ef0b464bb3d42bd982cefba7cbef003e4cb4c0e1ee01cdda7a0298854012a826b4c9b61cd1d4d0351a0415a8d810ac275c3e365563d8004ee64455b13e044e1c8951f8b3d8f37b0fd057da759ecfbac0a724e6abe63d01c662df91d42b8d1ca2bebc0b9b601fbc0194f49a7ad2fe5fe1a9136b0abc104bf2a2056b15ac89bfa2ad91e0ea53b116dadc4b4467d3b6bfbeca01e9172618f2654c615f4c61523f7e0a7ef9ac5b0430cec126d63c7af3ef0e0173d0c333437380175f68f096ede2f42b81672d3fe4156ee26a6c8dd4f241eae5b2f2a2f7cd8e544cde8813cf45fb96031970ce7632bd0820f2bc77deb00477a490eb47e2701d83456b2a08c4cf3158c455c8e217301ad11101fca9c80a1ae0da80ce68928b70d70a6caf878bdad5736d36a9793d0c8f605101aa4818caeb61806dc6ccae7bfef71affe90c02583e6873a1e1ea05319952a6561f8631750ba03c55f83698dce94ae5a8c7cadc299fac95d54e738e22b0e88ce40a330619c44a720c1ba2a844a07d6655dbe62e5f40fac450ec50d9f22404c3b624275373288065db41ee54921d27e4be57e1c0d8bb01471d7149a452a8d0d5a731ad11eaa1c37652203c88d2bb84f393f3f59898e48518f0ef98d9d6e260fcc29323efacd3cd5c17d137939c20b20040f1328dd98e33579f201d04339ff4017c95d243df3aef5e566f25224311cc6cb073d92f584e4ed94d0265b53a1e0208a6a4c996a3b8fea42134c42a6bbe74b4545c31142fc9ff13a08b0c0535486eb5928b4681b92482015c14ee9ff7d10791b55cb8725a024ae8c38d0f449205d38a198195d0fe63bd72f6f408b626126c93dc5353752e1a3c5c591e9efcd33efc937b4f128f48f9228457932695c3cd7f27004fab7508d0b2d3d539684e268f4f5906eb96337fb7aed9a89eb2c1537f7471053b9bc4a0bfcbe488d6f75fea79d30dd1793b00480d8e8c3da3e32acb1269a1c0f7930e89043dff22ce348f45a3d783b239c8e22967a544f998fc0b06275fdd92a0ea1a06e1f21bcdb68dd1f2f782f8db3df79af89214f2aaf20ac040f0f7cd3389357ed953df2767015479284956ff6900536feb77524a738ff418aea4c04cab2bd0d7ee14d356ebbc9ec07f2a7dd0a7e1ab7a65bc64d1bb2b0863835b08420669ea0407c0e3d37ce99d460e0030475e0ba4a470a07903d82981787ed991c565652e4c4ed6c156852f305a749e46c241e848fcde89608f68b823d08013dfb81342acf7ddba874dcc144c10d8257d24a3bcc8d2a936d7978bf89f6efc4db972e6321b9060a8a59c671348d3d9a2fb6b1a6a7da31c5a58bf38e01245e297108d0db23e060e19538eaeafdaaf8cee62f1acde682e041baad57d55b2f4f10773af3bc098c0772e45f4e15f8f4aa3a7714cc5c6b3ab22fb5bbaa1b16c11549421803cbd486009e5bc2734f3059c39479b6e7a9cee54d42fa56b67af70513dc55fd823c2b29111ac96247c4b531478a82d7102555114ad92185ac0b1cced4b084bcb20c5cb8f27bf85738d7d99ec2da8f5596cb5f5c5d250148adbc8634a17e68fef426b25f9797a85c2c6d9e175e96258af56656bff9e820110769060218a383f7f02a9cb56a5200b0b11893dac17a4d84dd2de42143ed0807201cc328d97c1645d4a0c6ea9ab7b8f7e9c09d3f13b00ea9c812a860af5fa1641b171e032aff3c8755b956a38a8f074a79a3d3571a1dcf10450f997c4c3a46c4485dfc52ab59b1216b5428e5322824b24012066cf2c857f044744156537ee79ed3fc9a2f94a8b18b1e160bab61e43df306368d30594f25867e4b220ea4640e11a64fad3fc3f94b537fd1dfc1ce268d1ebc5be5762a03de9a10058c137f913ace1121e1d11de1c1139693aff947e1fe9d734244b0459dfa2efc19e1fdae752d6c53c2fbb945cee06b882210c5db15c132d2f1f619bab4a734b56319aaaa1ff10bc0821d6634c969b0b29fa06432f2422d1dfd82edb74e482df624d0721a88b846d28d9296402eab19d0ad6f0a9ddedba7221dad00c84c33f1d16715f9842b007c8dd7231cf75310cabd2ce5d3dfda69daa7ffa79ca9f23c1a64eb1b66c070b6f1c7b9a909d4cb830c9582c6169dc100b188f1fbae69450c80a319533d4f2efa2e1803250bfbc6ffa61216af8dda157763ea727ef9b7a5173e8a884f39ed250ffb64153316130021725882b3752a37169df64b16c88ffa1b9cf1b784302eff90f006f02beb80e0bbd760fca8a2cd6a235d85d9dae54e384484f1220ae12851b8514e69d9e6bf1a475a8adca139b8fd7443aeec2dfab20ff7c1aee889e572817ded39fdc9229e66cddd4fa8cff1c7bdc5e58c43f37f9b6b7ccc79831451c53b3e7a17a810a42d1b8322da0bd8df1aa3e12ef8f305b1dbf8fc5a4c54c7b360b3de04785e97f1e9202b361949b3c8aefb3f1da0ed894a45e254bf20d0fe716ad321ef782fd02bdbebf3f25b27b1a66fcaae62683f6c8cb951222c03274dfa0736ed5a7e117b321e3fe16a034c40517aa4386d4e1898d8b725f298a99cc4eac79074bc99c1ec31a638c52eeb8ac6f48ccfb245831c612e81b733585c6c0cca2be6507d9f05e52e7087c64e004a065c845a7d724e786a5f7528abd56808b91b04f644d54aa09e1e5970ccbc44a36616af429b902b2c0e3e461a6cd492c69f0367446c9da40c3b09370b00f9c72048bae54d2b5300c5753c87389a2b65f81d636b5f9836751b7e34be400bc29df146bf35e8f78be6ef5219699d05886a315acd0c828cc63de998ca30c6fcdb285d05322c03e7d7f7a2a33ac2d7f53d2f063ab9a360511e721d47aec7e6ecd3ca3ffe28ed76bc7ddb89e0a64d3be9073b22654564acd9f9505e75c2728533a9671a127113cc9256b1557a26b7173d614d5144f6f66157bc2ec287672b10b1d3122f1f028a79bf6d4e74c7d426d2dca4e086de05401b0a9c8ad7f15202132b1761682ec6ab4a0264ad49e5c74146d40d4b92880173d9576243f578c641d63289eeeb22eb9e12eea32552d3ec026e0e7d89035155b8d5e47d7b607eb2fb2bfca7fea2c81ec52f1182cb1421d057a9079a420ea274a93c7b6fafdd1d7dcc886e4c8c3479515faf485a07082d5780992f524a3a674ff01523ac6010c453978eeb06417df9c72f486cfe88e826ff24ba2738c39d218b395ee884b772e14aef9bd615bee5cc1e9e8cfa7b4b627367733e755c44ed69e2321107fb97c68b39bbd40e54bced37b16655271c9a6d575e433156ab80f9e2be2d1d1f55ad959d87dd4bbb1c33140088f927382363dfa681710517d850a1171589da3b5df4b691404f733070420c7e9bce730cedbec68f032d352d868a815ed7ac43ee5b26e0189f62aa67989423d8c0bb8240398fef46469b9d016e3642f6a976ebacc63a2b6de541638d8ee5ee16777f78a7b62ceee5e71277752faf85a78c82f9b38a0274678964e9f056eb843e9bd5b06c50c8236c71f19ee0dccb07b2cd311affb8b83b2e4bd9a8ca6385a1494726986aaa51c2959e791f1720263a2e3e1fa9b26be238ebcd524fef1443a5874a3bf36369b7dca90f3969d70b869a6bd68374844880e5fb849704073d16c0877b35539f94e6cde74b351828d87eb4ad8dcda85cb84bdf3d8623fc6f8ec2a623c2df5025c666ef5c637f70b8ea471bad36d909d54676cfe99e56e500bd3c984463082ce1c58dc80aa7e577ec9ca3f9c73a0582f13ab5a86cef34fadd02fe0935667515a2a17bd6146f0fe878faf163c0172ff17f46eecc87192d23e961fb4b711da473a2166ffb21d49cb647a42bcb09d98cad42f628f4bddd12d09fc8731322b9f45c7700ca2897761e81f98d03823e4344bae104143574ca3ecef34f0d048f48ccf5889e0898df0527f9032b0a4d62c094f23fe38c78c9d0b9ff6a31c6a73cbb06f09e16d81b28e34703d869cd234532a4f90a91968560edf633de1ef7edfdc02157632debf0c71108713b30e143dac30d5ba72a55027b9721b7b04818d46dbacd8c6c9b2c53e3ab73f1fb2232118f5e5e35353bcf59647de5e41347aa9da68356a6df0ea20a50f236bbafc3eeb0421e2832e6de699a4287569517aab185b5dfa1502a5ddf6324e3428c90e97cc5c69f8ada10252c49671b277a116af7666f6c649570e6933f58211d8d7f50b91fbcdc36b0b84c89f42a7e47d68d612920c454053d4b48bea5f94481fe43476c61add25f8ea9ac634726360dba16e49f002fa64b70db2232dff0e020c940c441e659b9eaca5478fbe3345b2afc961b1418f01f84c61c24fff478abc556c8cf9182e7421ed7d5ba3e353770f60fe5d15c4839f671ed2c816194d64a588a24871a59e6a168a314b9d714db9310d6f99573a27c7a17be654ac317ecc9fd6ef11cf828a71c7b4e7f62d3398a759ea00f9dd82d94928da72cb5fab68da11c2d21e64d23f96d1834e0d0ce8f97aea3f24cd735903bbeae0cbc36d66e3ea96e7f028d066361c306aa914119015c316ab6617c0f932d881a518cc22c708cdb77157b96dea6e8935dd7243c271045fbee044ff88336d1059092067ea51342678ba9ad0c285de1165632fda90d50e1b7209c69d3c275404d3ba2177f6eb63e3fd5daa5fee0a7bc8ee9a1a54ba4d7eb2358a2048f8019c16bcd7578bbfa48488b59b8b87a188a0ced4358bcec8d86599d973899c02c7e16357dcee2d54f7aeeedef295685a3d2aa2bdd8dbb4eb3293755c3f02b6f76166dfa9d94157874a8c48243785c590303d3334a8841abb29f287841b2fa7cbc9ba280de3883246a91ddedd47c67b9d013424a055c0c24f28cfe6cdcaeccd56c5c744b812cc1ca50a6c27086ca610830def270da47468cbfb4c4d1f4260f208d36324787cdbf27a666009f760f4d36de1d9466dfec6052f80508e3fd17981a349b40e06ef05400250df235f6a9134a257937875bc11bd55f52dea1ccd927c51489ed4e8948ca5b86a8315e913a95b2492e725a029d69a13cb646b044006c93233672c9a586a803109b6d0d208cbf8def49d2897b03ed20428c4e2b803fa0cfa37d435d31aecb57737e76e4bb76679e4c7435d2302f77eac817650f735f069730d6cf2cc64c052ece401cd22eb4e24f2f122a6f0c16f56b95802d516a68a017cfe9d50d00fe396885d529006ccb32864d1a8b3041c149d3514a1800609f430caa7e3775e45f629b8a8b882a0a627b9a791ddd3376b499bc5edd20c2f73b3963876665434767afa375e1535699096bd9b63b31e43a846fccc5a99446c9259ae26cd2ab6d046f1b40f136ad4c9085c20323959c775c575ff12a1a7f3ea338f991e65822458955ac38f9bba68e34235e02db4c68dc73a70ccf4cff33636b02f34ac21025084bf42048332e1641a4c6b4b11caf4187808d510174c997261fdd06a5a8a0443051edcfa0428f94c32db3e7f89fb140aaaec66e2d2af45d4f7ef224d488cc488d17a16615d986c76682840f6b08bc44e66c60e8b0c75e4710ac75354783c554631a8a3e0607e090157e3a476069d920ce3440351e175b960f5d542362d11cc6f10be071d1b4ea4de1bc554402dd9c9af70e7265479ddee7aa94c8b97b7c424e666ce5235b519c478fb450819519c2f1f1054351eaf23edb19092dc5b96b674fe8ea22622481730f3d955183b5b66d663753c19d3182b72cb8344e63ddf0d4da719d3cbe513d6f13ca766982648ac48b669072157753abd61ff11ccaca0922c0fb28790db39378143cde2983d44479fb9c2fe50e87e83f11078ddd623f0694bd13708784bbfbfc46b46c17e0b5fe87c210bf3034dc3d1a9439ce9004019c138be7d6f8ec5bc010b4aa7cf01ecadcde2477964810d87c52c609a25bcc1001c0af10525f9654138dbdaf25b24a58a22219bcb2640f26cc4a507aa8024ab04de3a07f34032307e1b8d11224080724be7bf4cf855ae2a95e5a6701ad534149e920bff64a31043b415cbfa7470091a8105091065a4af8c7dcbe489b2de24858aaa9245d8b287309ef17f86b1e570cdcfb01c7ec82a2f61767d1c94e47c5f0bb2c7510063b63298a1e8457e5ac23ba3726d85015ae83ecbd60b1415e9c94dc46db990325e022cca6de063ea9215a053389d7b49b35276a49325269d0f94e96862821ca4c655977251fcd7fdf6ba895842c782c2c89addc2f89a5026bdbb9f48e23d942273621210fc2d5046a07c156120e6b04926d83b593e53469c61cb736e6259f95fc6576fc78722a05a1382c7be2df1fbc8bbf7f7237d0c775af540046d53ec7247c0de200c70150f7e7fd5127390442da085bf0367af3ee2f89142a561ea05d4775c4463d821d92ddcf3bdbe60cc776d97339e25dee77bbed116f4da22da6a26e30bdfaf36318b528263d71a2d07f1db31e18421c5d6a1f02c6ae4c4ee723489cee042e21ceae0c3b1da6acf9b2d3298ddb0335d2f75bd9593006f22131c6fcd30f57411c00f4fb95a6665edf27979c6e911387be4322767c88844b431f1120b5fcc595fcff81e5c92a3d1f8a1a64df3e82722c2530a8f817d481d231590ffacd4420607df6ca37fad9196846ea5b51d62f8a9637c40ad852b5eabc1aaabe12a23988161c0ff30bb25851089d8641f11efd7e8e7146030800a750badb7e4ae18910b9c796c1039d656c806fb38b0a3477da4940519c800c473b1dabf5a9957cf236f97eee1fdc002700779783379cb577c7cb3b030cb9e56dc00fb7e7c265317d7e96533ba78c01b4544c1e7171b9758e2a465950559ac6e902574571b553e8c0033933e7750bab6e785ad66290e0699cecd744f86cc1e3a28a2a3f6e6abb557cec7613cc49c33ff13a82b127e2865005563a44dce0a2a114d523f24f03f4b372ca2c40f5203f5858a9d3bc6e97b31600ec94898bd3bbc39d76dc8ee513aa7588ee3b152790822963a341285685c9c8cd095020c74ff3d1378ff9ec6e52d80947f723b438012d01590c2d897dfd5cb778ee793dc5ca7d7e6e44da4c0d9eb2f5a5d6f376081cff9ba45175677dab13255a6c0498c3320b53353ad4c9a4e18972ab2831e9ad7b4608657b1add140a8aafa3d4c923c04558e1e30e362219faa771a5592e01c68b0aa4149cd86873a8805a38f69008f1747e6ca3b6589d5ca524ae4ab40971520ad293c96e01ef592188f2ab977f674cd1917d30e911411ef7aeddd3732fe53c5bc49b72d90cbc09f3fd116e11438e061500c0abf121c5926f3b7f209d86f4dea6553c5692fa0b903074b9829b1ba0d1261ce7a7bd9fbcfe69521f1208d3d313130b21bb95cd5965dbbf549d39079973a237cc393218359cac66a14eb71c414d47587a4d8ee6930bdad911a3a2e72beba01293ae3781f4fa442d440edaf36a75999aa8373e565d65488e42e2f536031caf9e90a05aff63a621e4ae4e7c41aa42561db13cc50b353bc08d8b1625d33e46e6325b3da2058a3b98eee5e0566518a793842f2665cac31f32e523728a45c62cd19012c11b8877d84a0a6cdb0e74dafb450ae330a2317d174bfccfeae03fd09aa4e264f31df64d28dda21578ca331bf8738682faea06b7d45fc36bad03f6d4f0dbfd44d0697933e5577d1ba6e4537a7e6b7a89979c155b01bd8dce5867e287c4c988ea7d748e11df60c9c40e5bca48794f546268fa8ed0b068b197badd674c75db7d335694736869e557a6591859039cf1bcdb35a2f3239c29c3818457d8308a623260e56370861c5d1f91b7cffb07648ed4b3b5d51c3115e4771725986c33512f16735a5d6da85a040cacb2e84147c8af0e3c800fc722864991ad49259432d75e0d729a9587a681ef98d242b4db20bd95df1f3c079d4c98c05958f809cb3fe9d9e487c68edece4c489b6f2aa1887976fade781c44236e1d71de5cf59a64bc8f483384264f9ca1697dc5454c027811d29ae28618af915b62b2ac280d8ae5705d879103afbf99e0a86bf24f0ce7798d61d7efe5ec7a26cc95d0264e6f24300c491c89cbb52b144d873072fa34270c1aa25d3d7b4e2c4520587d9ed06126198fbe09fc6d32ff3f786ad29a4094c015270f10fb78cd4c4646cf851f903162e8608b69dad535a02040e933b1676c64d675c64f21e70428cbe12c06be37838bca025caf060850b217c46efc0f86c9a8478af759f71cd7ec9d5b51060d755c63e8e1761fc1feeff4ef3c93108d3666900ca89856d0c8170045850dda988b1122a50e50e5dd94cf39a98d28dc133457a230414d86c91824a4423498512fa1e9dbfb1dd1467eafcee2078e5189c4c2c131d3c7046eb1777f574ca7660a84a895625edcd856bf7adc61de7ee5806d28a399d54310f33a8acfd6ffcaa719fe13949f2b2af71f2df36043920a3abe327558193ae4022f196e26dd89ba84ca78d7b29e2487bed123cf01f32e9b392731cd0af8bc7735e481f670ee52c263362a687f60ec00dcf561020bc3fccb073de519e08e5c297242d6bf7f9ee3fa434ed0269f7ebab64e0a69c72e693e48204ff1f3e55ad59cacaa88f7cbd226fe11796217ea9eeceb06205cce67c2d12bb05ca7c6eb97d46c743d4a6bb44e4b891c5c32144610dff67612ead7ba95aa5e9f25d5b32b3c55197abb85bae026bf2a252ac28b79eecfe6096b08acf263def8fae9e39902b6412e5bcb3d5026d78d6c28a9823fea6f3b4c30f3b862c6c9ff50686b06c23d6f72f17a17d3735a0a602976856b086f53ca34353ae9e4bb0cc4e4a153e318ff55ca27c7219f7ac44db6f2906d88f3fdc382f4711c6f40dcf25a4e4dac4d6f6b1c809546c234352bd805bd5cb222e031824e07913aadccfb5737630d89c8c78d0ff87abdca010fa12ef0bfb431563d8f582bcb6c3a809af0d6f8a492e84056787288dc7f5f1c3e50b0ed1847cb7ae2ac003027e04d88047720076c46f32e11259137838f68bfc98c55637617a6f6b4aa570c0f182852f01be59242f525a1eb54f922e38695a99fef75a40c7f1140b6eb9665d30c3dff2a948882ac700c83669d8c2cfea21fda7fc2582829ebe923a810a8627b7cc7962eacb7048f2051344e2e656e357d4992d095e60ea0a52e7b4039e535bece44a7b42830b45468752db46c0ffc7250a71b8c26581bc3c89f9f4ede2b8843847a8e64e504352f117f026a5561340765a7901a71221d02bb3fd4c64a65c6200c408ae71e751b924bb92d5482375264e8ef531ae536cffc09c4d2fb3bdd1a2d727e8aa5c428ff47f69eeeb22b65820d1980ea8acf7b479e20747cb207c2a3b64ee49982346200461b8280b5bd1b0f9510214348582ad93b821f6dd69451c41356c323e9b75ea2b891071e1a858beb05e6e7658101b743013801297888ff787758c0adf91a5c3b4767ae292d5673c75a418c07ad272457b4f4740e103e9778bd15bd741511526fe62e28f6e0965b50a829bda3d69a6d4bdf318987a8fa66c76cd228d2e540dd5c4741a095d5b02a417fb22d7ca4292f544243fea08c42567772c28485b514a16c2077a4b9c81df7a8c57497e01cc5291fe29e05f2a640a03262920b5f2870432dde660c4d99f10a2f94b640c972c8c5cf27d4053062884958f496638de088513398203964fe12b51a08ead32600d9e02e4f50b177073b25152e53c876add683812f6ba6cc44c87807939f048baa221d200735c02acdd02c58579a01e5e3bef97306c4b79bc58eab3cb12b513791822ef92b84211318c1566f553f41fd7108b495d87a9eac0817ab9a34f3fd7f1bf94f14ee0a834d0c01340af85086367af9b47d4f0b0c8a784edf9dd8de2e697a7363d4d925402b43ad4ab08a619f6317e666d504fe06a2622f3fe449cb6cff387e49f59c641d7aae56cd5025246d896958951e4ff1ac80e83f35623d37ed0c517612be47d96f1005b21e4b680a6d6dd17492587add0c634f0e67488e10c5edb30abf2eb7015daa3fbccb94d8d81973174ff86760dd78b47bfc3a957977c3a7b39ce558e2353183a50bf9eb72802f3de1c06a7504608a4cdc8f8bedc3291ec6152cbb71603d0155684e29a02d218925086c97ea100e5c280458e9193dd949230f5d4d081fac95e9d0d62a7916e8e271dca11e41485e6aead38da1b65766d3d312fdceeb28c6fcda1142a1f7025697f436fe71919bc47b9e6e91723b6096b4833510431143cabbbc579500ac15ac664ab0d6cf3b43ca2a8d4c086d50b9ac8ba65b5caa0300aa23851c8498471038afa8eed0f78acc1dcae0ff851e530ae22cd32580d46c1d26a3e09deb6ec72aef402e643f63fe0e6054d0c8f413c9ba1a209ce7cac41a742244785f58f30f40edc3180cd98d8136d3e816aa4209d2d46d9edaf44736f1bee359fc8ad2f47913fa4c76dbe689f5d301211b528c0e8b364a790039c228828df3eb460a982b5093f1f47e5f4090a0dd1150440a2f26b63562c8da0f0dfaf186c8b7f7868189726584eb56f0171e1d4556d209b84360e97fd7240caf04885e2746215c7a09b157a0cc8cee307bd4db08ddb649dc1e8f27e3b81bf5d42865ff07fe31f1f4230c11f4d1bd065f1f9f2de940594cebae04412500906897d400312b36f1145f372e23175646693bfede6891f9816c10c2cc122219fa35877b28bf9b92db5f4d77f1639cd12fe69dab78f3b7c52b83b6131daddbf204978b220001590833aa0744408b3b1092c12aec207b35fb49b5dd9eab616093d709a4280510b3bd5b3eb02d8b5d5d75507a33d981cee236ded3df00a67e0bb2b56512b5e0e8b848a81e34547675a0bc88bde54bacd38062981339358f5d3b43e02a5e6bc004813b2c5baedf4449b2f7ccaa56c40889d1656f214b62d79feb3638b936315857dc31aeb6f794a93765dbe470179e4f1e17f0f452540dff1538b0409bdfa08197c51a92418c91c86c097f50b3b4981e293893b82a8fcd4c1e3a693c057f480f40ebbb8e0e5bbe72e07cf8d70d1966672560c79b9362312ac623b859f7c7e6fc3c680808d344c82946e1390c3f94d234451a936954db84095cad206d7a781a89c8fd6b49dba45fc32e09d5705717a8d1970f22cf3b772f4e87bcf483af6f25200a0b6e6bb250ccff9fc4c03aba70351910fd5b42dd293e999c0d3d514a698b27fbd689a62411a68d10255931f0bf940fbb62746ff45ee238a300d02fb11e2b85266122237119c0c4b37f18021f015eb2d6fbd6e58cd3de1ad5d8156c4692fd01132389a3df001b6200eee64b43dadb077fc8b0f8ce3d714cc26a764f8b7a3d8c30ea04bef18ab8f6189687f6e589ecab22b9f0349a61ff695555571a8de1eb2cc07ee3729e393f83c4171030d7321b65e80ea3cf71a1c7740b20400ba51c1ad3b3f122a4f83cbb1021d1846ca5c059477d89feb81d55dc74d389b4b7abd76d56cae32a9506c1198a8fe2a168ce27069d16a0105b19b226404ca39010dfa5da48e4b2ee27545c288d96ed643118a6b0916e459889d14a2105bd6ee75c65dc7c80b072f989e913ee159625eb230b2b30bdcf153092654f06693475ff7bb51d5906b3f9ecb74cc67f46047f98baa8b44a7542ddf776988762a6d66abfbc8dbeff6c3314eaeb9ac9d12971d92a689d58e8fdb0f93b395008433ffc876fa4ab638b874e8d404867da41955b068b59f990f265bfce2466899584d147bb16b96aa568e3ff2efec3ca73a8d27db14142d66577e4a0cf79dd634281bdbc9199e303b374ec928beae8d162c9c81ee96ddd9e5ac6ab35f88c46fb0753e7658b17253ad62039c6f843b0dad17eccc6b7bdbe6e7b8e5ed9a717b9c8c673e9370d21903f4921b85e982afe49396e5bc35686eb499d99cedb4becbfab9442baa14d200f6e8e7977a6db458b86eb143a55772a9a13856371a73b8fc846622ddd61d4cb4fb18d4546665692c91697b9719f22e9ee7d08119f76dd3267b8b9337e836e31894a07bc41ff9a84739a00f8cf91b51504ce4d6e538a214566a8ff2dfd355433fb7f1732c358a4409d01441dca68362e22a257ba5d723f7cd04669c09b47633c8b25ba49d3bb5f0b8f233ebb875999759aa1908368a33d068415394fa2e3481119c00506dd26e8b4e1c6d3177e4c3e75e14193bf933887d798a02219676bd71429bc1d10e176765f71cadd8e0fa549daab12193139a263aba7f24beb642d7b1002c13a759c30840978c4ba097c62331d61b281db82f2eeb29b92c0992cab28bfa9be1d52ce87ec06ef848f6943b6d2b7f872d19753adfbbbe95037d2d4d057872be6993884a612d24eac7fd854ea7e87548e05b595085942e0281cde4194c39d88d7f681dab247acf6d412885346f4707ccf2c5dcdf7bedf5dd002c03001d3bb957538db3ea7fbc793ba2cd37482bbbc3466aaf1344226fa3799515777dc0225e1fbb54e22d921ec33654102ac1e8a2db9b7bb4f745c317ea8bb296889d75e19692f86b76ee90bb266d89a2c09fb02520a1c581378226878b1474f50660f78c3eeaf3c260a4b3f30c2c23f38a1ae8a8ac7ca9222b417a796a021582890c817ef97ab63fbe5466255a0c3f1b684f8fccc7e6eb3c47a435fb8d1cc817421557bd5331a2862134aa7dabdf5e72c4f595aaba36d8447ba617722ec28f9484738ce3f3ff8c3543c9df0120c37f9d303181550530b6d36cd7ba0b719dc0eb47ad0c4c9f2cbfc1aef7b96e80d215f4426b34f6b2ffe33bc2a1ec878d5cedbca4060e06db58c129fb3798ca7ee07dee4914667374f93813afff3f772b6249bd649b781d2941f049832e3771fda8c5fe1d0c891c991778f63a7747cb88b3e05b8b884828885440f2cb7ab021d330bc4d4d0d96ba6e470bf7318e6e6157e1b3addeb2eab7e6b2299743fad1cfcf03fdf026213ce48fac7f91693d229e64f103702f3b1b62a033a274b08c765d8c3791dd4db8f04022f28f57ef4cd9bc71616db93d1d07d7207d3cfa3c83a873491095ba3acbe5da1a05d3cc29f254508ceb6476a4a1bdceeff6ae9f9f31450afa97f31667e1004329f9a9666ede9e806caa4ca1efb2351f7a1af6b378ba37507111c56c2e4d76b5aedcf944b9b6bb6fb793aeb088513836d475a20fc2ef361a1280e1079d5747027a5efc5d623941d4fd8d3579cb17dc42f13e538f5645608cf85ee5895c195325e247e5824e31ec5f83fd6d5b868036bcbf4f2c24be4100cde8178eaa66a034a357c9a1920bc1d70b238ed62e33cf0e37f42a49b8b2f9752433711d94a3e6ecf9dcea9b7c8d4ddb7a7c0058ae04bc61bfbf7a05bc7acfc1823d559be4dd06428cae8cd392eacb5896f2a6a4100b3012a8ae9f4f400cd1c88a02c68eb916021891d882afe5e623dc27fe1abd55d1c30f901e40019d65bc9325c10ada4dfddf4b59dc19731f2a0aae1385ac302c8f5f65aa73bf7a4582881b3d27b467d367ca2530b40864f471b57d13809a7dbeee4461033bc99819a926a084b735c70369f9e61dd347c97a931fa5167c3d51700d7bd79ad25681cf152ab9668dc982309076927a1f85e08e6f551a3f89c10add3602bb2f5e19a12321a0f204f7bb8d8ac5a3be4eabaf01cee1f687a29b7fe33e84436926005e4dc311ab8a44e581cef9c88638d5fb11274d8b1ef1e6e9064f409ac0b992d31e99d324031e09a1cd0f82855921d2d2881f0f5a4207748d10a403a04d465c008856251c91b0f3af112b6afba0332f621c6d25934a273234057948019dad33947af6d962e226857644bba37e0c03151cd3aa38293aa3ace9e2a9bdd16469e5634a4fd987f30612ae45d6a067edf7e51e56f10016a4752208096722e8fe6dcac78f34a975250869359c87ca8eca7d230b01e659769afe11d4fcbe4c964269734cd7da3598e3fa6f42303b19c450f983d1b973ecf774aff043864df2a2d2b31d160b93824443e4907bd8ca5c3f07c7912101510bf13b734a58d86887ea95b5b9baa27c38c487151b07d3381db4c56fe65b49abc9cc76db119fca588c8ece62a6aa28b00273867918bffb8796bcf3f0884287d8d7830e4c3662ac45c1823f34c4e5bfe6a98184e378fa9153b1665be9e9f0fbc610e34754aaf5c86a9f03798e2487d0c61a53413e0dc849a0080dce9ec665a04b63152adf34737d9d3e6d4c582d593dfe9c2d3ace9634555f339d3ee17ae4e295224c6f1643bd99d04eb33ac7416d041e9a496491c241ea668a806534e925a33f199a5cbf83392f4deffa37239ca8e07c7f171358415640ea4683fb80cfde05c6f30f3e8f9d2f15b8c3a0e0ca3b73f95bda3705858bcb4947686fc51c2fae87bee5726642c8b1a8154990961250b6cee87f9eb1a32b3657cb5ceff8048d9bfdd0a502ca5271c0c56e3b237a782496ba620809eb15efa34e0afe524a1a0b56db7c58d066974df6c1dd24a23b4a0a48bff6a10592abc339644316129611fe9c49c0f751c44f88195fff0353d69731c0a444e4aa0f7ee350e1fa18f12e575978e25beee04c2b042a0ea206ef51fbf0cc707e40a904a83e2a19c8904d3d8bea774934f138f720bd88871ced7fe8a1811a68d8df742a608849aab7fd90b95eb8a6970698430a3c720e05a2fd3b174cb6345ccbff282d7da3356d364ea437f859c959b9d10639221c6133c94dd357d45080d9645b1e804ac5fc24e751e624dd233eafd9a4bd46e45faac314e108ec77b940bca00be9caad4671107c91883dc79078ed9d242214bd5696484d8786fa7bb4b303263b8953a8686a2c1f07f9e306d844a4afe6c245fac954f8d667a09b1026cd8d67af985fbc8f969efa19f0b666fca97553a335a06e12df3b583f21b8583a9a79e8372e1a40c805c70fa402573beb132faae42ca492d80fc1257952c24ff524025716a9dd5461c89af73c9bbcec7ecdb7b990a85489c9d9960c7bccd8e745b880cc709e7687027cbf02702dab7260000df6df86ca3314693964a7147de667560bb3db2656ccb2cd1b7493220a9488305617330ccad252db6eb094b581c2a69c06cd773c3c611a33ce5bfbda061378a657d1f6c31a2bd1f6092ee403156ffbb3334cd49a67e47a5ac9b8b751f2592ebe512c3da705d99840d246dae7bce7d8154c2f35f9483d0e0939d1b4ced99b6a47afbd99a0d3c4a6036e7af1de05b4f4d2d1b32cb7c45d198aad21d3fc484e2c0307b89b8628dee366ba2e96b0c2a1f580a38255c17192792aba80badf7e978e30e42b346e8cc93474df35e2d0319199c0200e2f0c168ad9803aa83408ffd9c458802d226956c41913c17490fc5003e00e67925de798b0cda8d5eed7431f7535d0f1d0f052c5841f13396998c49a48a37dd00a4dd03a4d29561f9b311f436fa1e5740ec6ba106f1631d0e652278cac462e6afe78082a2d18d0109b926633c410153e54eb9beb1a1ad23cf6f1e577ac8f1b3546bea0c6d0d01cdb98cde4e356ca1cc2d0d0f897978c6d1a91fd319ed55d914169d32c343406945bf228ba2ffe2c0c7ca5f888b19f9742435946d01731c45944dc6d2c665625f0d6587ad2de39716aa244fccb73369412bcad4ccec3237ad9d0aa63009eee0c9b5a0f334eb31d73e415be6455d70917d28b6dd632fa973a1a9c63df2d45ecf2c4a921ffbd9b4235e441a568c8abe79927889bcf7e7ee417b2f23d3c98eaf770ea9cae755ab006cfada004af056026f401e18ab5b5937f0034641c92b417f59c627ccf2539f2bf5c4064767ab39ed6c01dcdf8594085856064481b430f8b2cc1c3d167ec61f22cbba8890d5f17baf63bcbdc505776797c635953dfb126624cc7a9ddffd784963de0f4f3b300ae5728085a8e8f2c2ef9618598eeb1b8daf5b31e6eb67eaa46f1521e250257b1e3188758b78a21f7f1144943b7e4aee978bfb1dc28a95ea03b6321a0a0e6b5f53cd1d10527d4176cf93525085e97427478cb5ee6abb5d6238462df3a2041b9aec01d99f20219a8f00b011409ca22a7909f239b1da1580b6edf8571af32ef8874c0a3780302b83c41f7ed57e30c5828bcf4bd04b8d9b293a31cbdf05516803134eecbc0df37d697382baaf8c66f9cb06621c23da3ccd14edd41428af45302d0a0ca353fd16f30f8f318c0fce43a6bdfee2c330f8ff0a80b91f3273e37b6484baf67a1a3945a394b944f3d165931ea5a4858c560800af2eedd82e9c3812977377c6c6339bad9351e3877cb5864743b44befb2a1a98708016247f8174b1413d82efe76f887630f660ac3039f4101458cd25b5c6a05e7bf31024c78d36f3ca53b5c91f672a964956960c775e80228c81e73171e5ca34c2cfb15d98f78b270a93b82191a0ac5482d882884c4eab21ee7f5a3f3158fcf6df191a93ce10bab165b5cd33eef7b3675ff2b2262ac5f2fc9dfaa9f5846e0a1c8eb23ffda8e459860426f1ee2c49a5f4d14b62d80d48d6400e6a42fef3c77862148924258fdb7fa4b0be1dffcf25cc8ba475c7d3a78f051c20350c4be802608ca1d4fe8afa390bf45e03bb94846786e42e03ccc7b7f842cca21545df417eba1e7469273ae38c4e2117f81f772d1acb24c4acf0c707a600654b21d96f9ee1cd82577d650c46b2fc243fc8a92e9c4377f25c8256b981afc17281a2d977578fd6e7e5ad2d5567b2464996508dea7544578541efe250c95fddbf958a373b80c57eb1d04fcb13b14cfb3b5b8bdf76e83713d1a4c320406af41fff1ee23e906deaa6c0041f1d9adf5fb1bb56237f607866b7345c6557bc119774f7dddd676aa0b1efa4a5ba8f10d7b6741c67311991d239e2318db93651af27e587d3f5604f5a0675d24b71e931b531c7245fe27d248d5d5ae8a9a64d62b341b039f90ad395a99f7f014a3daf22f6b0d24c1a38686a055dcf94b2d8572cf6d382444cd31ea8af32c1bb011a98b8b69df8cd243511310e481bfdffdf59dc9b4013ce32b72a29497f527c0be9b2393813e7b55cc0f5a1d3f9037950fbc53af8b0c185c411f5f880e0deaa51287a719fa18b82bfec6be3c1af461ac16f981cfe7ca86c60f8110e3ea286fc0da5dcf294058f73e5e3620cf552eb074a766e2b054493d12341c299afac1e4037213af44a8eb785b2b4bcf3e081c49b9685d3e7e0c0b7d9f4bb50861e4e97a83216cd1ead54f12f894667136d05abcaf09dbab318ff0904bc0368e3805ac82d7df57b57a76ad048f8a5c11c11c23048cb810c0515f63d8e3b960a64fc4d09f8a491301f0eab4cfcc505a86df794c892c095af8148d84b48d4635bf7405dd5ae9f35fba1de27fc18209f8b924e0d9be53e172ae94aca3bb26dc07f650c12614c479b1163dda2d08625c1881272be2a36c6e63b6412a67d85d9452e5a126c1f46d699b1b1753ea684cdc30a4777a4e520ff0610cfc484ff24f4d8c29219f33f660737182befa6e623963890ff53ca1e3689e9a0509311ac7ad383a17f95a6343234573f5c62970c9c3fb948fea27f995fffc4e162b55896ed0526e9fe392c077da2082c68fef00e433168ae3ae8fb6109908f0ac9b6fcd409d415e45375f0e6213e16533d626911fb7b5360c10e328c04423a2ab6c106f94ae59e35bea3903e235a29f4f10cd642ba33b09bc7a88e4903ab6157cac5b255e161c43f252ea6d26453128a18f4cfdf3b68e8e7cd61abba085f7c9d99c20f4b9116992f3eb36331f599f6845c4a8825e3d8002c33164799075bc1f9f3373ff49771179ab89fc7aa56cc60af0d474390761114c38d71870fed3fb9462bd63c736966c78b45263d7d26e17981df2e1baaba9dda2b24d2bd5591fcf2892f9984d128084fca1475467d2d1da996848948c52f8e7de949b9e03cc46612ed03d1dae1c704d17998771ce7af4ef8fd1188882497323dae7136732c6332217bea2bf2481ea3b4e8a7cc0596333c5a5a274e3f9e29096d3ab72b3fa231d8415b2d65cf362ea20bf43e3141e62f7c3312b119d79d365a93cde83494ef914afe180b7178864592e3fb6dfbeec3fac5b8bf680ab6edf411335a55e939597d0692c0bee89402384896516361ed06470a3e325e9d9a4279a1cfaf0652067a2d413f0471c4220c5cf8e8291fe8369f6ec633c9f7d9477b07aa6a7a10bd1da89565df506f25718716080a2a123678bd00e1557fce34d72793f8d1885c05f00ced1cea309cc8f0c69e8003675230a0ff32a552f8270cf5dc81afbb35ecb5274655790030677e8dc96474a0ba38e6661b573a873f4b0d7d4f75b9cca52cf29005222cc8211e194710899691afbc33017e9d5948c1cad5592f100ef1c603d7aab6c80e486f191795922c5cd3ba61dfe254adb74e76fff95c03f6d2e423a9c62298941ba8c1a2a42a1411005f574783983b6fb1ec8758318f35588fa83e8dcb112ad1558838ee0693c06bcbb1a7ee5461f882c292bc6f415ef068a64a889c1802f195fb3db1526494436142a5d3d894e606c4c33917721928001a5ec743fd55714cd366a71774b0df8211fde296c86eb9d174b1347cd51ed7fa73309e72edd4a93e3502cf31b1bd00a71e6a0af65dc8e4030e7d4a6ee469a0c67a9bcb2e24873e972ddbea021d65ee11a67cd296a4e365a0fd13e1ded90f219181ad20ea7d3ee2b6e773fee709439beefd52efff063776bf24e57f1cb9e92edb54a8bf904b46f70efacf844c4415ecc7413bf5711a41c1e12f9044b6a882f900facd184f0abae86dfd84de4169f4c508162492d16d858ffee2df7f7c4bc6ab0b45874c700c4636e706a283db902128d610e55e1dd3c41c694bdc988cdbb592f6445495c64cff52e3e37235c3de85204f6775c82a0810f39b0968993e4b7b70480754cccf08ce92770d60062cd4fd68c0dda4472beaf89fb2cbae928892146d4643b8fa367f503ccbc0301a83c190aca98f5c878fac41bd25c9149e0cb4c2b6247dcf99f859d307ed7bd2af9f3988b1079b751967558c42ef424eeeee43e5439a00d16aa98f9a727c699f033a7cb2618be02738c043186eea545597050865c060f5b0a154e494974daaaf0daa8ac4c2cfe1dda1074565c41412902e8546d9e752d4c352a0b4b5d1f4ac3292b687153ad9fcc93b2c3035532c26a96b2a7e69c5f982dbfdc2655cb3cd1f889a2a08bbf883980fc41b454b33572fdbd6d9ef24cb080a03f8bb92a150f9a53c12f4b393051e0516cf233cb9583abe0d26385acbd5bc1e9c67755112a739b9534f4c00c9a55c6aef0621824767528b11e3c066c9adb185efe676fb347c2a860ebe8e58af54d300a9b304d17b38fa486ba36bb7b61cdd655091451bf55d2143e1ec897cb62a5d4a3456361824e428517f5af97a77f69e580dfe6b82842fb89d0c49bd3c5f36922ea7c890c55de4faf2e7c02282c159d5734bdc4c45a84f292c721f2f36461b9d5ef6c107663cf30426d4d1f3160d3f86e101dc7f1642b7b092e4c2ad91c7b8408935282197bf974c975d201e95b79634e5c33864eb958273f781cbc5c6a11fccbd9a306e048c6d425338965f9728ef992a969720747325af16b48884f3a87aaf8d438ac9bd906e97b82954ace7e2ba378db35179f949bb09854e7705fa1fda630ce122e880b457c68670172050ea4ca02f2be8743135c77d9e740bd26194ea78885476dd6ee42125b30eea87102aeb10c3841073436a7d1402c69206f4f0802f9baa8bd67f39d0c27de9db3a5089818a9d2fddb2c348a2232dbf7daab43bf5cfe4d2f73f32a2ed5c5fd29e4a36a25c8eb6d07421c6de2a7f485b98f9baa861050cd7ccbb541368f73668e93208312138a528bb2336d5671a429747517c712e452e0cac4c18d9503b5718c8d97d6eb3a5b8e5923ba106039bf4dde3ebf2a01879ee3b668d9e11ca3851ae06bbcc74802c2393c0c7996907342b4ef20606cb52a39cf591b3fe72d67a34fb3f681de528ed701f8a40e0359db72be58f12c337f8bc7135ad3f3f15385a6148d2255d7a1e5af3c5387d494c6b97772bc9a7b974c46576719db46d5e8ba12e6c15fb3e4294428170d9e4866331eca07f2872ae69ecccc33456ac6855200a7173fb0aa4fa828066652ac1827ea4810e6d5daa94aa30e134cb9c841e6d85d961c2d86c38019dac91487936f77e5658c3234b54addab6502b8870e91df3b38a00b3e41417f55f49b9a956ebc265b5722dd684eeadb3ba279d0222b78964d9e685846ea4a80ef7d10f575c8ce21b51a29e81aed1a935341ad84cf4ea799281e035fb2f6e81ea599950509d224b8ff372d1997cef86eae563bb0a3d887a737045930675553f9200e48c9dac89d21c1a154bbbf54cb9703f29899032d6516e9dcaaca79c75d2dc761816fbb6875ab6c22fb79b9917451dd6bf9ebf0ca8ed822489056a3befa110cd8f5c95225395cbf0157bead8683939f48131e5e76ee3528a20d8323ae619288b8d77dea8b9964b1c1b92d2c49c459614ad50190616339b8281391a5b6bee82f2f8d098c9bbbcd9947caf711366e345c126f6a2ed9852eea45175ce0c0c07d089e70b7d8ccd3fba09f3363311ed55904aeeddef3f00dc3352bd18e24c433ec658dbd02f3a013893885adf7b96b4e1d899bcc91e0806790dd4978d8c59db5d075f40e5744f576255bd7816d8217cfb58c35e4a16f4b1018d528fb3468b5f4163969c78f45a0d2d5a32a281fe9c492870eea5cbc3d9d5f151380e46a383add0c5cf1ea679fd026ee68f42dbbc53d973cdcd530cb381aaa910daee7822e423564a6a757f0160745033b92854ed4133523be8d1683d369b6d980fc590606b3ec3a3b201e6fa64b4b1e02d3d2097291e0f54b4a059519a7b1a4347a3cb4e288f8125d357dae726638b95d4136e5222ed1cfd3fd5c62329f48a0fea5a1553a2b14cba21f55dc969ad86f1d28246d2945c719acf5c590412df332ee4e4fa1dbf6075c46b058f1cd5d873c67333c12c91662062fe879d6aa0e4fe330ef1ed06c92e7a9ed6f74d8d704b79fd37f9343e76962267ce9b014d51604557c3cf429fb43690f4891801fbb738a2901c86a64fbbb08825c7986052786786dd5d414c32861f2ae4ec2e0d0438c6a146764632a3dd25e4e3791f9b3d1e35ae7f4ad6cd17f0e004475781549a9c971954390f3ef0b7d310ded069e6896381ee5dd8183f9d69adce7f222380d918fd70435e5088df77150ac73d820c7d353b6a9f9a8d2a53793063242643a17385555e0eb9163b147fc9be7e208fbed7406b155c4336afc7dcc7a671a89b7daebb6a8574a95e3af8d73b7ddd688df10d0c284a0afe6a64299ffca6beda704ccbd12b24b6176eb888cecf2219c7b0c04b495b334cbb7fb2d82648229856f71419bc62f494d51b6dc9937caa690394fe598f3182d11fbb527e12b1a8017aa004f64ad4dd2f9721d88a2493abf35f94b65d025107d0d1c7a466a08e90ceac13eabee18337a8869507fd1146680ae5c66162aaf64134957c7592c485eec09a15fb31a56a6ce48c54daaf542b2878383b7687b2e63a7f411eb805d1700bfc56d072c9a651448073615590c70eaacdfe158067512cc79e6e3261eb13d55663b82b65b18282c8508dadc1b36776b196890e47cda38bd521ef61fbcaf201f432218df35bbdca3be2280dca04fbc575b5fec3bfb4e45505e6f4e03dc5a2295f2cfdd929619c3a80a92d3ca9e799cdcc6ddc2bba412c43c568aefe0909857824b6176f8728627b898e99b1683b124c65c82bed4cf8e5f177a87ad263861a0ace1efa56d171ec5c5bab5a7d70b4b1e609e70733ff1a72eaf1516202ebbb2517c1ca2a5c44f9f7e72282127882a977cf64faec89a235592698c73bf6dd6afda36cc6f5a9f31220518e956b3d3ced3f35157854c4925006d22bb394e17ac656609acf1f69b0e8c6ca12d63b580cf1336f733e34ce992a713ecfa3184e506c80be221e500c383112008750e509a883d70e0875aefb2029db9689a9048ab9bd9a1cf5955682669f85e164ece85ea1b3296e62edd4f22654fb26bb4758339b66f242faf49621dbb644b5a6399ca344099d9fa48e17aa0bbabc6f9f2c6dd1147dbfc777f53df961eed49ddf126583585efe9023743f14232b1347a183dd76f3a45c5b0afd89896bb12d5b702ebd31061572c10f894cde200b654171027b610c193ebd95e82565b5538bc00f69769f409b40709f969a6530d984e5ea22e0f689912b09cd6f796954e15e4e91fe09a862fb2d35fc38a34dbaa978511e74d0a26011b121c07ff2dc1172a23ddbb6303233f2ab7cd7749f54ff2723673d173225d4daaa092af0b4158830397061b2b27565e1ea7fe2dd456994f32f5690afee26390ebdf8dd67776d0b53b4634bf81e2fe734580efaf1b8e96d5dfcfc51862e12273270167a2c6a8ddf808f4f8459eeb8c0dabf70f39e347a38a943e073375aa435a8b6e69bfbee85320a82952e32d3839f56d31d647bde2c52422dbbcafd0d416c3a80956b1a946dee704085f4266b0a1ba43d043a1a1f9a5a305c15351d9981a263f758ddd46dd4f5f7dad545b35ba6d52a844a7eed36a439734fa8ac5fbd02c2071e99211c00030b60ca0084d1bdee9c330ad85c00f4001e6d6bf884261f632ffa08f661bf35db96969a889051237bcbbd777309f508dd0914239d623b3a15fde41487a563d4bbbd77637b775defcdfd60c3180cb3d664fa51287aaf77d7bb1b932fd5c5342a7805bf53d74d267b8750f94ad783e8dbe5556f5dfeba3eba4eba56377bbb6b92e3e17615c3ac35997e14eabadbbbed9aecee8750c117c7a651c138f6e7d5d464abf295df2136bc826d64fb9b7cddb03b664366d1adf683e817ee21fa867b8c7ebdbb3e62f2752ac2a347f96b4423a625d2e57997bd2eefca7e5d5e67afeb9862ec2a81bdbe1bdac8df65c3dc1f3f44895e5f595c9c9edecaf920f27e9663ef2af8266fdfede554e075f1a86511fd3159723ea8264ab668717c1aec42e52d4ec3f2abb46039b6d1295a5bb438cdca555ae0d8a92156b00a8ee91475717f69bcbe2a6f7ae9d977baa961ee53b2c6a12a571c62217682435b42e17bbded1db9fbb7b82c5fb9f82ad7050f5c02eacaf18750b98b3777cab1727c1a95bb68f17b9a16bf2dee7f4fc3f216bf1f82a5850b7c67963ec48902c22e30feca695c541bfe62081bf00b5c6f8bdfe4ebe2aa1cdf95c764adebb29925d75d931c0faa99f9af7c0896ab5c72a71cffca698e574ec382af72161617c72c180fe102636c3b557f9323e7ddff342dce72f1f1102d70c4bfc9337366aea8dcc7c8d0468ec72ca52da9948f3e28d38629603fd891ac795506512a67c823396229bbf664a98a41a9a44962cbc21695d4c28ecc17f9932f4b620a841ab139383ed6c7e463c24c39312726873227f644ccc7fed4253144512cc2d86861478290c8217246fd15521b65117246edc6b2882145f4758f75aa5fdc920c6c1879ec44a15e8c883076a6e2651147f0a1961563376e1cfab8f9aa17e56a5cafdd5267bef4adeb32311cf3b22ade262a66091c8da1666248bba34b84b13145fb6e188e9457cf7c8142cea0aff5f2c93ee8a504ebbf7e4171f9cc970b27d72b93e0e8d4fcb513031b4a9e70e664b90509836921ca5c4a228c4a7ece0de4190653155450c8533221cfcf9c1a8f1d003aa6145812c8224c66b060c8510b39c6cb0d48184c6a000231d65c3df345093e3972b561244f8ee461e1c99949266a5e20b64c0c3420a6e6656a0a24301561e506e6bc0c19b173c74513368463a7a475b16da2304f368526b5276b9e4dbdac96b4256d29a93c6273e1505a7d35166874935c6f0f36543860202f8bc82132070859e3001ea6c6b14d727cfc04b2a625130bb547faf03411190a9b086661d60ed9b2e843968caa92216710892a18a88e3d2e35b0d1464b53c5228df1891d72bc8b0c1adabc0559289040598749fbd8a64c122986c35196d8ba381eb24ce32dae064663a634d6fbe2a519d85035b34d548c14065bc91c311f1a04ad5eabd7b5ee9e3cf29440a84b72d7b48f8d3eefe8e3a3ca99528b3e78a6009d74e80f5d45ff4c54979460c3b884dcc74153f3c3290575c91591bb7265b3edb4ab8b4c14bdbcb1f796bb2524d8f0cafdf71160e3b2648dfa0dcf5ba169337368d533a07553c919d9eb89e4199fc81816976057765d5886165556bd33131533511876591aa31ad81e206a7834cc77611bf3a5071c9fbdb65374eef0d2325ce24be8b3ba648c7b56ef4dce64c81821cdbae488645765a2228d5844cd5bf333da8ae1409bf8bbd7b78b75915c37ec93899cf1913e1fd2d19641d2bff9e678c832094f2cd4209d7b64428166e9922e0ac644d1e310e110f349c0cca523368c3d618c0d1c34350ee01181eddee9b7399a30a589053943e659ba71a6b267573681bc11e95abce88626f0d68899043e720ba8f524d2eb4938147dfb453a463a7612965c0244b71fdd2f8b6eb2f5b66fdc76356d6241a289f96419a536537b943342df5ef1862d19437be56af4e9294743db4626194389ac6a9a96b56b59bd1addb6ed35e837bc4d99b357ad46f6d0bdc9968c512d2a35496f1039ecd3c890af44af9b8659c7cea4f36e44f6b0d570e863b368bc62be2293f9729d0b5dd355f944d5dce1512ed1c0d277cc0e13e67b3daa5e1527cc37fb56c819327296e87eefac6bd866e4bbe876e02b26422126f23562f6f0c9be07760f63b7b7b8b83d729c8f2d6f585a2163843eaff8a25e28f039e964cddb7028a42787dbad87b887369abb6fe7ba6fddf6cad5e87e3d05e85444ce88b9eacc977a9f1cba538a89a2efeef49928ea44a697c3514262c319c47ddbeef6942be6cbfcf614a0f912f3f6530ae40c99b7538ec66671b766d775af31dfede4add3e6c6d5d8cedd9bec63eee40c9f522063580fdd30e58a6c552443e89e2c57b161ac6a6dde2bc6236f8fa21bfec81b0ebd87a4b6d96fdebf7ffde1d0a6e6efdeb4d8fbbc57aec6e71d7be7c8193163de2947c3ebc9db75514dd4f579fbd25b6fec920dacf53a7f5d47c06579de64e27d2ef1de24f0bc7b21fbd0354dfbbeef35e6bfdf84cf1ef7cea6660e6fa11a44262e59f34298bc4acea00fa9f6cc85661a96216364af9d3bcb4e391a19932caf092b31f19c3d7b942167c89cb964a793f220afbd86ccb2d06916bac936335f58868c41e911edba76dd38b1df647ac3f3c8b15e77562c63a63b4ed98436fb864172bce24d8eb74920634c26b9df37979439a031a714b0886152461f9b2c420e298249e3585da04523489c884a62f013951811224f6c3373054cd9c694b3bc917202bf028d2db438b5162da24c8b162c2c518685656525caacaca8a844191595d329ca9c4e2929512625050525caa0a0984c51c6643a3989322727a55294299548a42843228d4623108c32202812451991e8fb3e6ba38cb59e17653cafeba24cd7715c94e1b8d8b26db165ca685a9645992c0b85a24c28145b30ecbaa2cc75595694b1ac5aa34cad94764799ee39a3cc9cb145467e5ede486909c104e8a70a287c789e48b2736489247472884821b26c92c515414b9848f12325ce1563d12bd30341a91461bce28a44b04215991e063d55ec9e2aadd78609c33353071a4329c5e982166d3062c3f853310cc37eb09f8e91e590962c8324905c226be426251356e630027b2387c8481f1313132fb52ceb9a40b5704c471965bcf53246a5ca22d7371614f3d496b1ce6add1c88b0b5946d620e43582343b055080707e41a56a1cf4c17d4bf19b1218dd9b558b3cc14c7999219111acd71c26c745249295529820d9f290a063da57f31bd2813e7fc8dd6f5a17b93fbdad48c61193246fdbc8dcd46422ddaaa181e949cd5a2966559169667a439d0faf29a942b298388af51e6ccce224f6b725f0338808359b81034777a16d19158c43c859846e44924cf2b7c4cd49c3c988e649922c655cb25661892a3e4287e01e3666640cec9040b47004a120435ec4451038b0832d87440822c18c18a220b491822054cb010638cb2bb37dad87c99b13b7637a594524a29a5ddb17b069452ee1b1762f63eceabf21095efbd76ef09bd61e9cd25a0fb09c342144d0e4bf701239f4e3b03418ce9ef3d39dd996949890a9ec8f5f4c5fbe4f4c43be9520b96d2574a573979a9f4caed78711baed9303f14141b504c9fe92b5d7b71633295dc0fd4647aca0d6f72cab5de5ea484348b5cc0604fdebdc9f4dad47cc232640cd3eb0d5db2e9338d82e3448d6ebadf090e61e412e9c689d2bed1b649ee878d3b0fa1dc9de3be594b0303857af1827a1e087ae1e87b41a905bd172f6e9c29cf761a0d8c9b0dd7d36b2fb237fcf0c5855c476fefa581a59f3032f7d0bd4b031bfa80912b07235399b78d865b16343747727cc46e2002d01460dc4004202964f93b6d3802f7892c49c581a3ac54ca48230b8a3e8d52cef328776f87ca4f1aa651c19ee6554e3bc7d1c44e698f9daa9a17d6ea795ead9ee9a4e4795da779ef3c4eeb3c1c59f4d1e93c3a55ff712a1de90453b92715fbbaee386155a72a27e26ab5a2d368441ad9fa5315590e3c5591e5b8d355c141a3824fafb59eab1d47e34315444db3548612c98aa84a011d38ca4e4e4a99157db5d6d1886447b556558761d69a4c3f0ab579efea3f6b2b0571d0cdf36a15e1eddfbfaf6a15f7b0b5b31da992ba3a1a8d46231044a12794aabe4ff483eaeea24f54323d364c4a8aa9d4892cc5a12a77e0c88a4ea3118ac99e946c6647d64a1c22eb6d9b8a7b941908c2714284aef34cf5dc8e2ef33653ceb28c4412812392c7ed40b9a97298060577f7c07b60e76d998769baaeeb700ff01e281a91482452d7913acfb3342654d7ed309d8b3b4c184b795e77af13bd870dcda277dde8ddb59ee79148249287c3eff624d2f72e7e64459fe9a298ce75dbbbebdd5e2e9ecb36d3fd4183824d9c0da5d96a48f32b83165f70a2ce3ee3911b87d9bdec72cf3e10147d190e4dd144b1567bab918636b0db87ad4ba4087e66a6b86061b32cfb68a3413c5b20e5a1e5ded9ad9769efd7d6b2eeee5dcbb2cc46f4ce3dd3a8956937d432dc63c4d1daa36c949548e006825a9659dc0dea43c85d7b86411f344cbdacaf69a73c3051df1eb8043c466c27e7dd4d33ddb3a311062d16711d531c87439baa51aa510f8737dcbd1ab0dcdb02325b9f5a9665f778e4d6de97bbb5a91aa59a46b9db542eb4a959c371cba1909ce1117978641b7a808b92c06176a2b089e298f0de81af4cd64e940ef41e078410e00d6d3278d1fbd8d75bee3a3777cab2efa60b66a2ce70e33851deb6813eb64d2385b4921dcd9ef49d466f9525adb7eed4022d32053cef74020fe2eddfd6ed7d8fe0d69d4de313f813f8ed21963f7c02b18d981dcc0e3ec3e8f7ed8636fd6dddf67e05718fd2777d6cb97bdfd062afd495e8bb114923913a52e77d218fd49fd733f4ee3b9d2fa47fdf356aff99b87bdb4874b2ef814dddb9ab8936d2a5fdafffbdf187c1cdebbc5028cb361105414a3abde1e85696652f1da4b7fb4e0f7e7be9f6f840cabdbba29344371c611f5bceb230fbbe7df47636d93b78698f0ed35b1f9ba5f7e8bd631f9b8fad1d00848d9cc1143370828f2d5b40ce608a194c71b0061a8eac659444414ae9290ebb6f9556db3d76c39470889146f560b5f5ab187b2aaf44aa28f444d64fbb77dabee3f495ef60b94a47e9874f1b5ec1342cf766da0bb7c74feb28d52a3e59ed9eecbf6b9dc9844f169f729cbe729a130d8eace1d0541fee2152a9448f128552cff3a84769ad59adb56ef68638b2cd40100c5119040f5ef35431df907f1cf81e7d2822d2e9f41da313dea182a3cf36adb7793872d7fd2405e524238128267b52b299c892ac5da17693f1047e74d2cabfbb912ecde923f0e65059b122ec43a5cdaddb56aeca4f9765bb3954f0cabd4bc382e35576e52aa759c12a98e684bdae533e545127c7f88855953c8f69a284e0bb2190fc715c08a4e32cb5f6d64e6d3be9edb449a7a5531c8a9a36f77a8ee34eda28e57ef8fe59ee5e73f6961702c99cd55eefa9c3373e0d73d7b8ca719d394cb9136cd35c49b471b7d72c672d77bb71da6739daf566efbacce4c9effb6e770bea903d72a14dc665dfd7894c9dac36fc914db7131c3de68ee3344dcbce5dd2b37b83c4ddeb6e3df07e3814619bf6ba73b7bb373ecc7157f36c9ac33e7e009196069ab76d17512cdbcff4774578b30dfe7b87b189a216f7681bd2bc61edde64f086417253d228c3dad4186b1c961e47f4deadb2ebd63fd87ff8068edea3f5bebd36959c0fdb1b9fb4f749c3372cb5d76ebbcff2287e05efe11ee06ddf90721ee79d50d268e4f5d6dbd6ed7d1bf5d6bd511c1beb9e7dc320b96d08247b07ad873b7a20f9fb4c77789b280f7cf70f6313e5dd7bf779d47adf4bd2edfb3cba7db4f33c9499eebede28d5b6cdebee9dd2eddaefdeb0946a1dd5a6b6d13e958f2d1f6fc1d0df39cd0b92696d8be93bea7d97dcbd5b9a17cf8536f3f346948eecebedb52e37ca9d62fa10f743fda9fb0e949fbe43e529b7f76e48b377eaf0a7f23d05d7efd486dde3f70bb4debd4b6b101fbc537cea4ecfbdd60e9f72a0fc741a144ca375df431a3dd605c9b5b35564b75b7ac38aed462da5d45afa7978d451da7d1ea51ca59bd5a4773311a5d7d2c7a3ece88f6ed6729f9974fbe928df7142d9918225f8a8a23693bb386b6d7c7d77b96bf6ca0e7ff5745b7fba33fd598cbbaddeb54fedc41dfcc87e23909bd67ea6439b69efccc2bba1c69dba7fb728f7f41a84e68463a3fcbbddcd91627f7a6bd7c65d8dcbc20c64edf494d39c3c1a149c929e6ac319b50182591a24bf344fa8d0dcd5b0de369bfd13b5bd5eee9e69db7ec8b09da82d7236d43b098d28c64a1ae91193747bf60377efd96bd753876f70d8c391defb7743eef16ddf1eaeb7eaf71f3ed4537cb2a7f7bedd933df72db3f806777a79db876da8e5e11ea25bdca3f4ed3393bb9496b651a4a40a8259b6d18df39e7d0343d9768fc361dd6a287ba8de1f39d4358cc966fa0478b8628ab9eef7ae7613b5a139f49885425b88f36e2fc7891eefdd74b14e79f8a10dcd75bbc6dd1ee063ce32108719c8e049f76e77431eb9b321eea6100e79944e4a38fc91edbf874c3814dd8b273547ebb32c3bf8ed8a0ede1ba21fd9e3eed9789b6d34ecb7cbfdb8c16d59e761198e1385c30cd02c7328c3a1cf4c798ae3478e8f41fcb0a4f949f1d988c9d7f7e9d58ae5f0d73729babeebf2baaeeb3c7c5dc44d527a123d985db71dd2932befdde34a7ea661bccbdb6818ee339d92ef6e4da77870d8466c628a4159ca08b4e19015b6626ca27866628c266dd22ba48dd094c5b044aed6afc6a185758e8480340c860384a988cde9db68982cd8503ee1c08ee1207285fd66c523ca707986308f4ecd03e9d4bc69e60cb1c252175fb0615cd2d6112bc051a2042272e844d949a58ff53a64be504bbb8f9462be08315fb29989f326a6200b64976098b526535c92b5deb488fd0822c2480f84423f3a4513c0c5a01f5186cbf4fa44a04e94b1995e2a1165ae402f8970090399864c1fca3164fa5076215329852ca74842a65c963ac814479fa892a9f5b09deb126fd7bc3f36943a2af43b3586c416fafb043b846297f499424829268afee8a09a3cc844a9a53a211d580b63132575e4a9951b1882944c21043948304308da27b70fd044054d54c7051b4aa06eaeaf4929e62402a353856c222ccd3e5186abc2a2204e27664e9461c9fdd93d6530719d3913d55fc9819539081334dcb507d98e8368b72692b9c444293175e6763bae260f620b1aacfcb952d83851f28a896a30581994fb73620924a1882d7d202020a03ec6e44661dbe78a4109a494b25b36edee96e10e748724ace1880db15c84d6311912369446480dc417cb23c8f4024654c7c49656c2368e4e755eb9810d634c0d13638d189638606b20a22e53080af632c1cae7d0215afc0e98e4013be325cfcf2000888619000160dca0ba005a1ee3383cf5500eb18e43df7ed8f8882d3387088a066c3873a65c71df68e623ca649f8fc9e1f34088ac8cb758394bca63343d4610dfc5637f8fb1616450a772b827ed3a3cae64dc93864f3964dce53a72b80e39dc25870bb1e1321e5777795c692ff029870e77b90e1deee2722101b80e38764ac33a5caec375c0425077390521b3f65006659f993208c705c6f8c696f95f20266a3e07193776aa050e51319d9a2c388c91658c1cca1d142a0587bf099770682d883fdce1cc0396c31b96475c1061b55010190efb584e177ca8b0c72bb30a071c7050a954383cae04704f9dbaa7c6a71ca994000420800bb1e1a947ec12464b4b0b0cd461a00ee34202f096c7d50df7249fc3e32ac63d497cca11e332aee386e7808500e0375c0616c2040d007ec385d8f0183711a0c88c1d260a35800be3dae8d4fc0d57755b6e8c8bc3cd38dcb852ddb88a71e3ea861b572d37ae60dcb8ba6ecc03a83153b7621bc6c400f4c53200ae0dd7c5ec7a9eb042cf135638810f0c0cc330152a8cb1d1c34f8c12248001a358ec819d748a9e3040a6101335491e2801b69a31cadcc0fb94353632c6943f0d037e8a5aca020cf96a7b289bc8f31207d200db470fe5111964c5555d49ae069781c4969969c17af77bbd46c05bd7c8106c057ebb427440b5fa3ec4aec003a1848a9f6c3373c5272c6f39c87ca9a71cdbed4fa1930e4ff4791e0d730a611ddbedb7db875227f450e684b045c2d67b8b74f7547fb3e2eea9e209d07057756abec34150d8e3805cc38a09eb71b53d443d5b6df71e9aac0d441932e4c981f842447cc9260b268e9c6123a708220c378fc8b3a661e28a1447b2c995a27bade65db9d3a91bc496f9eb4a2457267165114964a2e63c42c3b29133e4084a105b72e8ca5c8361d95a12a2c2528cc3c6445d2558f9309b1a0c8a80c4bbf6ffdc4a7c7a1082247890a80286945236866158cba6dd2d553ba07aa28ffccf44c5989999989923e4e4d0443125f24420030e7549b17a58d775cd5f3c72c7eb560f375986cfd20b368c3e34354772297354a2842a72d330810d314a4513ba20a2020c83a80917801f20428250980daaa0e9a805d49452411c74c5c1c1c189a886b1d13895cab91a89c086126789d9b4e79c162a478e20c6e80b4b1c598279491c216cf8bf982d67cf77b71665a62414d8a9c4199ee059459410d8b9842a46a0b3924300421474565189108ec0596975a3777ae0034728b2babaf0269f6e5839cc40c630264a7e07497a70566d25923f471ffa5b3fc1d573f55cb5d65a6bad97cfce5cd26dcd25b5a7f6486176b7a58a735e2eb55eb556975a65b89c40c7d2c9eda3840db71c755a4746ebb44ef5913b5902c9242a974deec82676e4ce04ca5d8449c4c2049a4016106850ae3ad3886d64a241330434880659249e39ada83ca8a1cd933ba886a7791ed03ccd9306ec48c67ea8851db17ab6755380381ab3bbad6e7aeb5eef3bdb6a2b05a84522c8735a279d2b03d9c2575b97b6e0a433516dd5478aa38c98b47a685c92650e8fb8e4013c2a0f2be877af29b6cc6b328a177cc0a7872592f8acb4ee001337f05969549ec00849f05969b5e7a70547569ae5042c663064a55d5bcf112772561ab60149c1b3d2b0adde134d0d129940e4089e55454d948cd911988004243b44622044d5348a61d8abc51e0a65c65e6f45f7fb41cb189edb7ca83ececc8a6d990b43f7369bd1639ac5a4155c8dcad19076648a17ddce46928c5d912790b442c6980f61184603bbee0eac0402ca92abd41a4111180cc13ccc091802e8ad6953656b94a996dd588f6d974e1486d5502814ba7693af4b2e4e1476b2b01d65d942a0efeef3406fccd7e79b9614b8ac895dd69453f6b02c7cbaf1d97362cbb22c8c7aa19a2fd3b22ccb0aaf8ba27f81cd2dcfda018cca4a9bd2534a69a5b23695b9be6fadb5ce1ad82badb4d25a2b0cb6a2d9a78956276dd95d67d3ee39273eddb8c2be2c8cfe4d9b36a530daaa1f9bca6682165f8419a5216d02413fe9a7920833833a456fd109058c760eae4b42b752a0dc9f411d6d6d7a051b5e38b92b9389eaba24b6583d9dea3fd7ead3934319106c587d8e4c597daa143f5950cb8699ab89335f84c064bd62a6ba02a9c0ca26dd6448ee954ca9414d727f0275aa59a2b0a16c02947b7234b02c9bcc972c70e68bfcb5a467db208727d8303619126402992ff4dd6f988a598093a392152891c3d81395a8e08a091357f3a1b5d1b9c646c300d17303096c189bf467a6cc01d23038ab6e15489181f851d3ef1f551d42a8923a3c35353535353535353a74e8d0515353535353a343870e1d3a746056a5d9d1a91361d69af00e150cc334b15335db6aad12c73376fb7d1688873db1a7fba14caa4e81a3930eb2a87ce5a39b43e58461262ae4a715dee4ec212b6485db0f1277214da35aadb5fe264b59bf6119f2862ed946c3ad6eb20cccd95e10dd90268baec53967ca34cddb9626839fe91f7b4513a5eb94bf5e1a581819c60c7dc0f0ace63616154a555cb0bc45fccc2469dcb56ea41c05ff403ab7e3bb218cfc7ddff77ddc51fe5d7b7139eb9e4e180573971edf1e46b724fadda2f42b2cd7acedbb28f8a44bce87ef28f8548f727bd23dd57b2761584a4a4acaa9621a1bfe22936e714893519e82439a9c72edc5a9742747a3f4931394d3afd3c9c9bbaee34eb89393128e13757f724d076fc82393aec9cd0613a613755fdcb89ae97b4f9484618c4e718fd12deeb18272c38a7dc0f856e88a0b96d7d3b75061c1a1cc2a57b1d7ac8ab5a00f16ab60dc8df644a09d74eb0257fd66e572c36962fc86cbdf80c3553808ea383c48001ee3372b19f7242fe337ab1c6e8e1bae3acd0d575d5ea5ba0c1c0400573d880dbfe13738a860c4b8a1c58a2013c523771afb25777cb082dc30bfcafb53672a315fb61e1934711ae6f44e61d189325c6619819d79f495539ffebd61b0563daade84ca4c54131657465ae982275dd19da09b8e8e4e5ca5c4d549461d2327df3c651fddf4947bcab08ed14d271d2b4ff9ca532eef094bee58197c7a2ec98e53ee12ecfc699fb9a46156c209c40903e28a470d5e7918814ee4e36af430fed8187de561ecc98d250f228c5e4294913bb12507730711e6e43d97903170d00521c288c087272b57f248cec8c953ae3c5d693252fae476581c9c21fd8e28ebbf574c599749b4f46918d23b943ff2d3a7979033641216b7b85e4c5967b12e77a24c8bd8622d911b473c7ba6ce9da73b713ad54fb9132574d3a87f72a576a513dd133b05fad0c82e87b49cd149e4feaa74e38a74e36a74e30abc713564a56558eec49639244485c5b0c4012277e2e6dd78d343a2c51761c5e9e6e9d69945bc775c983af3257a98c5a2a9105b0a39c345c628437c41437ce9236223117b07b17d109f105f342a2219e48cedfd1e4394e1de2d3a0bd974c58b1332cb3b0849e40c1a19830511a6a65344fa501841471379896cc402b1a53fd7106180c89cb9634413816147c4549f67e6d24397f4eb82b7aee8d45ef2ecec441996fce5fe7c22a50925a223cad01314f9294293d026624b9feea89cbb31b69cde82e5ca23220c7d424c519f4e5135649ac54579764dff9158fcfc5891a3613ab9d65ba649148c541a5deb596777727a826e42a49b944824d98488dc44a0373a6dc22b92441699454091682659913c512672356acfd979a73b0d439774aa0a3983662163ace02574872ed9c9134f21f7357be71222aaffdd898488f291319634cc8c22a65a362137cd625291db9b40b1a53f9f0841c1ca1e9eef4b1a66a3594cda853c0aa91ae47da88fcc51395d79651228a66b335140666a1ee7e7e4fa285d1ca4db0316728604628cd9303444be9025164d64938804223662cb3c7861c8ef456c51cdd4fc8c99491a8bd8d2e76e8f21b6f4b7db6490319e1051fdec3615b1a910532e72464bf1e284dcef20c4543f0ba62b4c468022a67710db07b19188a8be75fb8888eaeb6822d3c8199d8405d146ce6822b7409f202ff1851cce1d34c4598688eab7b8f3e72ec9730d3175c41772bf81763ad56f2372bf89c8fd9d9db91345c5595983145738d13384123d4284a1064e044d9c23e008e28c789f997693b10a9ad812438018bb042b63da0c7194fbbac194410b42ad71b307c7449d64287778b7a7e9fe5dfef3b0e9662531695d550c8aa14924cf1c2c3bc2863268c917ecc4456822163f57f830a9a24891bec4b00c8aab89716856c8162a08c68499420499a4496654c3c8d5270e0cbc3083b4287a767777239948827690c8254c41f2874221c2483004fd04fdfc502c836415f45dfb72466155da54042919423e620a9f385f26206f83e509d8d82c7d105bfa920731c684913b9bcd0f28acf56a447bc368414131413287f1c746187d76421782854e8f248b7c801c95d820284b4e869e5d8876ec4242cf4e7368c7ae23f4ec9403bb761dd835eda1ec210d9be46dc8277cc427b2fc4c1256eed022cb5f3631280605d13c658eb56a1017689d97143a4a7c8ee8d66182c57efdc77cc18c881a4684636a9a0830b84294a1292da74882fc81d40167a36144efc7663981053fba10d149affff9a9a9694084912d883f3a37b042981042bae8f5a7799ad1c1d3902e7ae44e13e718611007618206bce83a48d8060e0262535c31a1cdcc17d90f0390e56d8833a40a628c3e6647a4cbbf8832f4f2a4fec804da9823d8981d6acc6067cd34733eb4c8da8fb78ef4a4adb15d5e9e6e5ce217b1e593f235629638a4f9b352fbd4dedd6f363314ea50167746091595914e8e99b19161a973d56031ac424dd4d502454d1d6f762fc8c15982176ee0830023da6d4c549f6a60c3c86363c665c26857990608f20307a771e41ef33e54f9d2b02f582c54354723b47d08eeb153563643eb4395352c6b59166ca4481c59e28989ead9d34f744ff360938707db393251488e44196ed607f1aa77337faad66bc534df411ce47b909b5588cad67462727227b6f4e3ec79e4889c3187e496526b91687411e95e0983251c4464799774633ad5a3eb7913d38c46d6da8b623ef06a7434127d640a32ba27bf5b9ff634e02df80f07b1074728d14d28d3e88ab0195baae4ce13d4fd79c57ce18932a1dcda73b6b68d63aa8285827c820aa89f9bb9e9c3710f4598c9d3a966429e3b1665b673aaccf950a5f05899b54f80f61139033322cf6f9916ac7422893cbf5db3b6d8309e05bfef8237766f573e617907af63748b858c22f81dbc8eef2016c2040de9e085c44e7d3ac07fffb01012963dab4943ca9f3cb17c42c3fa137d9f083cf7378c45babd90d2c15ba4dbd3906e71e920b60d630fdea29cc803ef8db090efa35b17f54b570eb10dde3b0de85d748969be8fb010fb9177d169bc8b70ec14f8efa11c228b8097c6298777f034de413c318dfd085f744ff3403ad51360405c7d380810f866f5b8b28f40a25be3ddcad8192957ce876885acb5d44f9e7a2ae4fe09a70f0ff3dcb7abcd356459a3bb7c8dce872a6fdbb34b6dd2d0b013b7cb5f903b3b4d828096fcf8c81596f1e4892d54d81096488e4c54b73c92fb579ddb4ce9014e963b71623151f44d66d0bc42c76727f3c1ce8e8f4f94b93f55e820622193cc9c91800a9c30740089945276cba6ddddd285ba58392af14952440335c6ce52e4f0b109108ddd48f639e79c73ce89a53c92e7e90d6dae4c7ffdba82f0ba2f735e71e412ec2573a80ce51902a28930f597e71ab2c441c835e41313d8d02501d488f6992977e6cbd430dd7246392a392f68864fb28fd91158ab4a9e248c01a358b52eed9a9846bb8957d42bb6a0601cb1e13699ac0d7d62d544c584aaec32511d635355a1abc246faaa186ddb3ab3b6b7296742b034dfd0acd6758955666aab1709565e073c2d833e7264a29640f54347e20c2901349b0911466aa18166048a2d68b0611fc97d7aa49768249d2476f7916f8fab1cddb7ebe8be5d88761d9c90ed9926638c38fc68ecec9eb28796cb30131ba23cd61128a04082fe749289a2bd83a491ec20a1d612b1859a7e620b7d88084b7f58320dbd4c2189f4ed2c456ca1a71963622d1c62cd23c40ca080a20a3aa0a2044248a1831c244890f8f4b060618dd0914148924c89058e13990faccca14492f9c0ce1c4a2448649034431259be590645999bfb210f6820f73128260a934155d8cbe201425225164d8276ac8462a2ba39196465108c9e257a7a7a7a321250613be7f280165f348f5944eacc588247a684953953c26648d896417c8999a8b89a1151fdda84c7090b6c189b0c6131c1ac41c87a6b96481aeb03e9543f74b1192d83886aab890ad5c407045fa062b0d288c61796437070e490a6e8a8740d97b4450b158d0000000083140000180c0a874342b170409ce7e2201f14000d8ba64a7e4c18c9a32087510819440c21860000000019001860b48d00628607bdae1afb40ffb997e327352707c5c08a31b0c6489061496de9c085263ce1ee420974353c2c846dddaa2970138d3b18366d0fbc58a44e6f2755c2a99ec67717316a3968f5c2933e9d4a07a9509afff7b4d8c0072a1b06556ee68ca99b16357f77514715f4bfcec3981594865e7c74ef684e03124c027f2215aada7ad1c71c1d48158e77b03cd4fc2c5f47fca94f3a3b503a6f068dc3a14d770f61384a75e19e8350a5c96202734b3c1e23cd2563cc4858b4615c368ac40e99074db6073aff19db91e526668a4a7072c223bd6307be64872dc40879a83d1ef899ce4bfb6b618c07a9be7434516b19268ca6a26f768c7541a9fac9b1395b16992975874c8297f399d93b2bc8546075c5dbb88b3094877b48c6ce5ebea85d175ac86f32b60086657cb4dcd95ba2c0381608813623b9345baa6bd30eb626d18c83cbb42ec939fb0fc90d535306a2a58205c5c511a1a5091ca9ab75e852704458f038fae6d9bf35f610fee3ae4ea846008f79f9c09d96d92200c10fc09486385854f58036b3fb8e650b2e1ed5cad70fd2614b82dbc82c225195a5c037425d75298ec532e34b3dac180fb07c17d37d9907ced04282a239fb43ab9e2727a1fd3026154f51b048ac9ef95c035f76782d4c597402d3a9d849ae540749b0f83a42a8d6d90c57e6d61464600f2a1f95574651e19dcef569e2995595c1efee95463d23adb4e1dc57d1a2de6e3917041a4677841e0d66b28ba49bc5175b51c8543c4b9f85fe166ed878dea8ab12655e8557bcb1afac9ea702558d69e64262721add1b9c861405efbf33ff7f7cd13d4cfeb2c795ac646914ad58a8ccfb8d15c581c7a7d40f073cfec2318cba85327ba13f730c068da5b202a9aaedfd3268591242487227c417d30b10c7591f0ac52c27b329bf3c217d124c148ae91b67433e3bc51c1ed8744d2289ab68817f53249a9e0e9ac40a71fd9266f51df2eee8a13697d6c8a226179a17e5640b9319b345329d930945838988a6d2b1c567ec232cec72f6ac0c7b9341589517e5ae624c635207b53de01dee30683cff6824f9fd8cb44cc91d345bed990a0c8dc0dd2545aece2162ac058f5990a5906c64d92d397ac8303eb0409117a34282b1c09f12035caa5027c31cfcc875681038f0e955ea9954fa93db312722d52529df8292fbf3ffac215e7c5615f635306ccabe11c97c65045162946e63c9057a3898b4e1b6782efa7c93a4ec95be695438ab73b740398d623f8d223a59820819336974526c021c28877a57bd7797f39353d1fff4350d8e1cae2164946f6acf09304d23b83869f0d0486503b7be90e812aecb82af5ca668363cd0a569900275cfce2ab009d49336b63c6a101e24932b70b82e239e16bfb2795cf7261e54dc7b53e49cced8d0e171a252640fcef3768e04be57755ddf9627e0143dcf5d536e1254271380209a0b18a602e8cf3f9c4d1efe12272acd42c954ed60825dca15a191e53d4a3a7385ba96ff26766a173d0794cc660df0fe26156fc029fab5ccb1262bedae6bde670e071cc74896c7f38fac9d5682547ace9172d764fed0504e834d9629ca27d0201d5c920e42c882c6485eba7d9224c6940e44220959dabb4a007a6eafea42f4b7b83cbf27bfc8705919388248198133531ffadcdcbcd56f9abc1822647196122029a7be49bc44c70f27d12df41546118e97af53939bf11e1cebe8340b1782d65e3b5875633abf152357bd10787073e6740d6ec3974ff5b4e4dc5fbab4a08ad7b963ee6b44f8f9e2fab6e2a120ac1ee66b8079d50d8bbeecea329d7f8f4cb4abcc816d77d9a3a407f0c786f636303394212d41cb90aab2a242cbebac4f6fb8b68f862c64f8995485fb4d4c566c09c6c928cbf6f4f4f775522e4f0671122003f418dfadeb5849d0ce0d775d16b852b500ceea511325f59d408aac02c3eaa75fdcd034ee001821539ffc9d73c79918ed6f981176616bd19494521bdc5834977e4466b16a8493e390eb3dfc251ff5ba78d2f1fed70467b114f50dfeb7969c8561238d03f4af733406d58a33b385cdba9062060e76790c65d4e4a652e92536c0249c3bbdf6cf9bcfbeb8a2317257cf0f0bf72bf651548189d29d586198623adbdb8329db4b4102da44fc92c9101fa8d40734f338817a3873031052d18e4e31cc6ed614822e4ee1fd7330e85259e1f6bbc3a49d534e4ab8b95882641385884e24e4cbf0f57a1551935c6c313910e4d24d957e54cd17522035c54238519f022732cf265b1fdbba166561e8f75912cc26d2389e762fc476b5eba6aaefb2cc6d87fb7742ab16807a8024882462a0b81f5f003e853a8af3760165530ca366954ac30601bb138321b6091c7ab1771b82736818a41113157ac72e446cdc877a21884d9e049dcf0a1c8ec227d75518a4baf78bfe9c60c8a51da32312b2bd00247b101c3a0c83b8677373f1b5cb4c527dce9df333139d690971ba4d263c570d21d7e14e22f70ad95a12d3710215d0c4ee0bcd3f475c2aa0550934d93feafd5052ab294d3885f34e0a33c1aff9f8442fcde8b8288da1144f2dc59cbd148f0ec47199e49684cc99fbf0f9d34cb47e86d0b42124188a2a9608fc1412ea4dfdcaad5a170a62428036542499f762a7368ea7b4ef9929636000e27ab13cde83b4c686b35f60d700d9b92b8c81684a068730b64dc00007587f7651d9316341b6707be0d78ca87c031bc46f60ff0a6a3feb8fb1b15d0a8b3024a0c20cfa818ffd458f5f386dd84e71df6b8561f86bfa9162384394a0fa5191dad7fa402ceb7eaee813d7e708a166012100651a13c761f4fa95355414d5b00e99116730ed2ec688d398b195c8691212905c3604e4b3fc171aa9098f86281bb1f2fcc8b79bbeb33a876a292bd1615ffe92f6875e6bd4e92e30350bdb859a6a6c30ed5ba14932b74540e29e3393735ca1805634b22e24f749396948c614e402f7221eb8341db72904d642b8e90f9d81b4c19e7dc8c6b9044f37755eaf65836cb796b7d5b2f7a57e79e95bbf458694503e43010ecb7e15194e2e5e8abc69d410e9bdeb47da050e3cfebed7bb28d6a0eda9dab852211e3f1c8aa61d4a6b87ecc2c0cc3d96200e086cb06a057355030262593a3aa3aaf06dcc05c091e4115da068d87211e456e48e8670f61537cffda54792aaa078bdb8a58f804948875811c155f0c5c6bf021162b14b78f017ac709d942374e81675084201990bc04711fa700eae9bb4139622beb02511e0368077aeed34718113eebaf255c0cd9e84897a0216f8f0d80439c42ce08b641eb4609550c1a8dc839c583a72b46c259c364135cbf95519ba2e6c07bb1126cdebd02c29e35c413bc09f3d2ab7192bd49dd8322d8c41e4246273c63db828c8c4a871590115d0c47233742654423fc0565dd3f745f59ad2800020eba82f74049a69fbd2ae31f4719b8744594a360c7053e621819262fee971119ecaee6417c5a2e40c984f8ba0511ce55283841a48ffdadde6034f69a0481da5356d607128adf1239e86c8060ae2ff24a230a3cf6869e0c7a1dacf47a5d7b523542d17349c9f5512b4ed8d9273d23684e6c953651c35a4aec9ad9d232fb29ec33f26213e242950131f49b21870cf5d13e943f498db245856e3e20631ef9e438027d07f35b8f216871591b2498410ff4cc5c2a49fd6cf44928ecd20a970d1716e4e060066dbe4465c5475512cac110eaa9ccaee36bcce727f7571b18b702ffcbf630e2d839008d363dbbb8c04113077513cfb21d616b9e8a57975615e217b90194a05f6e20959125dcc43562ac889ef8f15d87f61d35acbce8484a008f1b3addbec08bafcf7c5252c390ea0102a4d8ad9286f1c33b23890c77628a1f1ede59e88e41df705e8c7800435e2a33026f0c481eb8fe318112365407d4361c47c2fbc6afc9ff2a0eab5312528a3a090eb894341c9e9a56c496620f617703bd1dcd92d05b2eafc65caabc42ce362a121fd3c8fbe59c3263abf8dd979c0a25ae772e1bfb55a153566093f4dede7ecceeb347b07d90ffa5c990a1226ef0398666faea318efe3bed2be149e85db476684276718c4247e04f7970af61adecefbf5d971c639af891e5e079eb98e8e3eb27a8d1f540e37fb815a27205661236db8425d2c749e1a7fb1edad2cd9a9ce07ef05633e0be4c8018196f2f738e1f1db99e8a3f21655858e9309016c50007f9f38593bb32b81286d4ee4771a64bbc1b59e259b467a845383acd5d51a285d68e63e56ad0c58c1819459aca1af798c53cf05bf7bbea429fb01759ecf44521394c9f69b1c1edab754c8f752eb80942976c1f2ab15ba9f956d347d036d9fe6b1674dadfdf48c127bb2807d227612c209d8c370eb07c5297abfb93d671c7969004f132f4c01a378483b45fbe74bc9dede740bbc3a04be43c19e2f6baa03f662661e28360803f26592a234abb6c8852f19dbb10db288c75f89ced5494a66da9eb9e44d4bfde85244d64702f1182a9b867d22b0cd8690b37ecc1ea0532650ffcc3a03556e49cb0ebd03d5851b10fa199244231dff624088c4a9f6d8f622b14646a672e4c6fba9ea28bb27e6734922b49398f15d37ec9b6ef7f94916abb4df63e5c802d0ef67289a5d157aab46832c5f281bebba26b1228b94baf9bf8f8240c3088c86c6f089da104c7106f78a3d13aa6918e5811cc74508c82ee0b472d6e55421d64ac22350535c4465ee37cb3d1d062ad3bd5e960ccfd89905b62684f9f063c239536c8f370964f866e7715ad2dde7f03729dfb203a4849d3320dfe406bada3363f2fe0e9de3d9a1928d06932471682d598db0abd0e28bff96ffa41b966c8b162e335c1ffafe241bedbdcaceee3f695c9bfe9381f35cac15b0c38a578a0da2760fbf93f4eabd2d1ed969caa04709f57dc274de1b35120e30cc68825660a31e2a5134f749b2c25fa4273d21a51c7a8aec8987a9780c1a4c69440a37745bf360220bd646fd06a710c3f9be977b793ed9a10a89372cfcbca3175001505b4f2dfdb4dd6c00fdfc623299202b95e1492935e4eef5241c75919cbe1d62ef7d49dcd22beda0da22c26db1a98c3250207254f40e2ca469788abe28e60541c6219357e7cb6058521b352756f68d28c883f70310fd94e01178ca2925848cc952f7b55fe3f5b2e00592b4a3e900032d46d1bbd40262c05a78ba3619e26aed24bc4b681ff97e0515e909e26fbb8270a4c9d97829df39d22f1036834d31a7b06a9a398f6018cca5a04df981a30ebc332ee016527a101bf9f537ac8ef50cb5bdf83d409fb1a96d72608da24b9993687560c33879029266a53b397bd6621856e510280ae19da8dffb1da775a51857979aee9c1b2812f7287873e8fe6b8fb3f95dbb15d233a1f3ed0a818ff671c3a395ffd9f954674800c3af45f2d94b8443dcc1f3104766083b71082aeef22f40e8abab5208af1f79ebcc19fb841b0f3c0ebe5ca636a3edf111e79404ff15cdb62c9cfc5a3d39d76d5f8297a13fc11d8da2e40ddacdb6f4ec0b52bcf098d0b544405b1b243131c23c0d48e9fc7e7c5febaa2a2875a8e5c421045d6dadf5b904944468f5a0fa93a71b5c41dad3fe19fda92723bb4dbd86e4f7f3429e66fb326470daa4d047c3eb23c1abdeb3bf91a16b67e0fe3ec023f76fc99c329c2ba05d75812b313250beb0c05a049c04dd74f9222db0bc29c14a2fddf76a60012114f913498285289cf7f96149c1e66bf8ec66201a80ba7b479d478ac6fe18aeaeb96a692bf36547c78ba32e97f59eb52fdcdc7f1cbfcd9677cb896fac05b718cdd3492336468dac9da2705b63d08ebb5cc8a9e52983358621c5c3ab6701d80e7480fb10966b6a3624d1a1bf94f7862477df7abf62af5965f984398216d8f4930e3c6160c0b9c9bbb771c5306be56a5a10b07973207dbb42afdca03c045241077a37151104085067f980f54cc70544b16187d45231a718018fc8131182f3c429908e426e7b8ead2439d1d4761b4d516dc89a71b6cee25ca89b3083944b19268bb4b51a2c3d49c020d9b1d1592297553a38cca8644e2231983fc526bd7f9a15cb36888f5f08a6a8e21df4c959b1f6b6784d8dbf7479821c47c27917dd804b79cfc96986ec1df61b8bd04d7637ab6b39469a773acce47ac4d34f072c54466c978692a1e3c85a7975f90fbba33cc38b257638f1069cca3b47ca15406fba6af7e8ed127de7f3074331f232fdb18f12a86e29e7f86ed692c710c6ff74e07ee390268572264eb0df42e504801827821136c2c20b0cd670e9e92b5fb730ecf6c6abe183253916875f1c37c40f035befa1050afda8adb3fc28458aa113810f2922229e229f08c299d4a8a8ce0ce1866d1a0dcfe7bb27f21acf24c43033d295ea8fa097b94c83f3816eb19045e6b1b39ea906d251993d53d55480db661563b1ec6b0cb36d03e55a016cdb89292da34e08e179e2eb28818d95ef5b881cd035c3dc559934b9d8bafe4bde69b865cbd9be2ad4ca7fb234274d95a2b7325618d106e54d8b4ee736132f0e0854727c15be2794b37c0414a54d89e60cda5c7189f213a28025646c555f2640759771a6526538db1c2a41c3f95e6e231ec59e6e0c64a3f9d590bd703af29e7546f8c8a4d680e8bc4a756e0557bd719aa0a885a4583d9b1653f6e01fc9e65b225c12333a3709809e431f8327cca9efb862253c64ca2683773eb78eaacfc1c07bbf07cb0b987f0bd82f2ae3ed7ccd3493b4151d7748fb640b8998478008edc8ea9c746ffa54703f235349a9f040e6866b1989113d064d0bafea15a88625ea7d09c923a8940b74944c73bbbdc9ca18a3ce4ca53102436e24a8bdbcbf7e2b9ebe3a9db201bacfee7a7fc532af8e73a1d7f5917f63b52bf9c36cb5da2c5f4c8d90218b390ad98579f7f661c2afc818015eefd707c9386629e8f4147ceef50e4a4a9de77a574980947bd891146c0f88fb6636c1025c3491ad48395fc1104b4f819124354c26347a5b03230cf0c0eaf54269bfbfbc7cf3ec23480a6a9909c1727db3c0392993c332c9efef8565624840dfcdfef80681c5d803009cd2abc50e0d33a5c120ef1b93ae73756945ecc203967f25598a90c845c2049f5fb8da3bb952187946c820faaa7bdd84f24bcf7d6b3cb630d2302aaf334651025875b762363f3f0d896c0fa43bca885c1725411b32619c47927d7cbecd6e16e4bc216bb0c6e8fd85fcbd9786abfa4fad9f0803ec11dada9a971a319c17e5f4266ac96251ee9a30beb28ce8d6cdfbf7c25596a48ed12112499580306b3425989eb52ac3439b96916467af337b6d6831de854af6e81884c80e187b9975ae6ad9cb9779fb310ffe17c9b2efdca7a835cc3532883e36c444b9909910108a65e033abbb7b050431f5ce27049108b97f4a3d8b5efe5e2fdaaf340429b8e4c548468f1bb312b12832c1b8dae39db1a438b51bb4ef492594664aee7e694c278b8a7b77de51fabd9fd938265dd22289ad49c5d340939f9e950a7e0d14473c7448eb6bc8ad2131223cdce37689592259ed4e6dd0e32e8a6344f88928ff66a1f5136c9c4b980693be0de0af7fa5cb0919523d55078a17eb8efe8f6b5b1965d35f5ef237eb8e46e2336cd437c57c892393259f241705b7bee0dca7b7a80cd073ae8aaea5d8a6dc89dde5109be94a2ed11b35b4d8cda6f8d61c055492e92517aaaec534ed527c0fefb482c8a2288de0330d6ea5094ad2838aede9c554859fa0c22623d18fd120166e49ecf970e63a1357ef70a7c830a8ca64cba4009d94639b29e6c95e3925f522bcac6b91b4d5ca75ed383f4dfb5063cb3bef9ca551454c044d29f618100a7ec1a78ab22582ee6472829230fbfde79cd54fbe284d893b5e5e2742b60f43b91528f91a1da137d64a4a9585be30b30e8f77eb1be799d8097a8990c6ec04c9d6f7f1f99e8678cc4f21a26f519aa3c3a16091fb9470f882a95957ef828c85c6415925cdb80b4b08b706e25dfacac1748d2cf3d77f96db445be5aacfd4ca5e755606e2601f042c45787794452f91d7a91bb4f4c5e42861d542b75ec6a10017436a247dcaaffaf751cc0389bbe19a40991c3c33ae166f0617d0ee1a013c49d5c4159f1f068f1456acbf894413f8330b027bc5845d93c84a5666e2943cd39b0f4dca5e87e38cbc53aa5e904d6ef70bb21f0b6b2b3244161b990d808a66826d04eb60f50da8d071d7f47e4a5c3fd2d9f7b4e1e0d8c0bf8a96dd7bf4b0d6c10ec1fd0aa18f524d97939b2749e4be3edd4a603afbd8be4312467102d1c5ef0f2107d514bfe681f5d5b64702bf0d4aa00643d1e13b30512ab8e61400949639ce12063e6dd402666e3ec437a24aae3e864835d4fc6fb38542625f60d5ab26bda6d1806e4b70f85b872819906c3a43f5a23c084962958adfdc1eb9a84ac70d4ad690306ac0c33ca56a76d1bad5bae88feec72256ce13578550e1a6b895ad964073ea0c2d571aced296e48c92e1fb358af3f810656a0da77c47a681eabe1c36069b4c7b0299b0faef33ff828eb1761f7f75e2a9cfe921d882ee73d262050d383335e924e0588ec6265f1b380b7b3957ef0c9ba0af2a51729a0d16484c9263d7c2a8e960707416ace6a1f31450c8263c3531beb2ceade9f05737180cc2723685368ae1302cd054111ad9e82bfb0ac0054c1946e81c720c8f83345d749d29562debdc520d595dff094aecaa3b71307017e3665c50f5044747a4116feeb6af777ac391d60735d04739d6b6ffe42fe970f01aedf0d308d965cd4bcae1083d6b1fe7428e8fe6e6003702571e299da69044f30f6547cc7565be556c517e9680ad87fbd339b48bdd93afa66873ca2f0e3355801d64d7659a050b7704fe37acbb43a237bafa8f573facad95cd93aeb74e850ef383f866db75ea8672014e23d2a1f217e984d2e8c1ccf85dfcd9837ad3143d3931867fd56d91f118d5888c04267a79cc408890d8739bafd490bc3021d5738497ebb59952fb28d18627692b51125a36858dd7f121ba7b8e2533fc70e9959c0188057b24c853c5597cbc484fcc741d16d30d35a69abf55471ec44cef6a7c28e04134105488fa66a503d20253310828d89aedd00137d1c24a6b311603104696dfce1ab0d69729d676acc8613b8c2e718e601debcec66092ee4727784e94355b6701d42de6e0605d90a983c6635a74dd9027bc5f57b969863efc1f6328fbbb1c8f2f1237382bdf13c01b1a68729fddb928b73a23e579b9d60d9f6f6a13348218f7bd20819e9a9293ff7c2489e4a69f98f77b12eea61bb57df466960334794f41589fc96261f28e7cb3c807808f18adf09c4fd3e6dde7500590712400b0d3cdf905a24b1c5bcf9a63134aeb1827d71debd7cc6dab84187c7e3c379847de41a796567144b00893d94b39df68efb733746b0f8028fa83640f158ed8b40bda609cb7f53436cd55f9499a6daf7662cdcad645e721b0813e3f4bdcb57fbeee427ae10ad2e9ac1e852588cc261603e8b984f5e4e94f3e97f9d8b4f6bb44d2b0ff7e9f93468a8612a24f0da13b94874f1a0096eb23763961a99116ce80cd3cd1ffcefc8ca8b33100cdca2f4b0091a4c05800a4a60914debae28d5707451154a325447d4cdfd6eebb9488225ec69cdc962f93b7e1f952ef5c6ae8f8326df8e362d6c1ea2efffd7579681734c23b637824883943b588a757eef5de1181081c07495c7c3ac01092c0baf4d648a54adf7ae347ff9c6359c213b49a81a795f64a14400b5a8fbdca5333b80122195d96709f8c9e3042c2063c8587e3ce9fcd1c3ad0527144b2d99c95cb1966b8c2648c9c11c1a30ad7c5bc46dd168aca9d4527466b2862991613f10fc96b8b225b8bf5a0c941e0a7a47ac3b19fa0f02b888ae93c6afb0729b52c1a3bb038a8daa25b73695d8ca4a960331a65267c0c13ccfa0f234134ae8696bc7846e37c744859718411a7658fecebf6c371d1ba114dc6d7e19e92e2bc772bbcf076fefa78ed5bf916c7431490e0c49801d2eeacf3d8e9f6bbbd2673c7836c4db574eaa25fa0626b82085ebeb8721e98dada40716b49bc47c77ceb46a40c6ed8e575e75c3f96c3fc186e328050d687e57fea9586bdefb1f29b32fba775fd5f7b2bff3f5f109d243b5f45516ea67de051c45719003d14b7940c4f5ae016faeaa00e7d9cf900309370f48f76973a6d41817cee190c4377c18e37639673936e865ca289b498a64f1457e8ad064151e87ddbea0268786fb15624ff1b5027fcedb9a1c7919856653a2fcd76f5286965c6b5c284691e94edbc98fd19cb81d92b1f11f9202464084cd3a645814e0d0568396e02ca72e64709c0fe891678b2a280d78ec435b5e65cf80faf27b67b31ac960098bc9f1539f5ddd76829adc8c84f529230d97a601ff8831dadf23a927826b169b4fa450678ae6876a81b05168381c21ead4a65a8475b657e12fed4eb040ce8e4358621e61cbfd79762478f948c4c98d90867d244b10dd3dd917c844f111f683a39922a2ed0c5665b1f40c17c21c4f5e34d4ec1202892fd68cdc390336fc7635f067121eeff5894d696bb22615b9ba04b08aaae208e70056b5cfb3c7f037176951f0b42719a1871ae12635ec3faa2740cdf1022a6c7597d0d09f243a19b2320c4e4d94d6e1bde4af0e310ec4796b178af415b80ba4780f045db65a3b8484f65556d88be28624466a675d6ed55844afc335a9b6a35c14d5218257b5bdb2bb28f481e5055307a4792da78ebfa5e5bb1b8aa77c55aeb27c515ce57739dd690ed3b77348150467808aeb64dc2252d8a8cd83222b599a173363ae9f40c1a48ec84e93c0009f2acad20fbf9295d03cc597e28ccb27022f861b8e0d895b28d597ead89ad120a269cfcf71567f984c1e29071bd6e4a46f00bf793a16770f899f2c5080287495df92945972b825897c96237b2d42beffe64621e9068ea3d83d6b75930d57d40ea0fc88dd22e5d0571ad8c181ebc05d0ffd8c7aaea29eadd323c57b405ca2c5045ff53aa3b12870b42ad5af5c69376ed4c128213ae66dbd9ec3d4444fad85a7075513bd444e0f8a7250dc0a3741f2b4af687ca3251e9acea3a5687e4748f00a06e4e490e088e40ce20b732a3e7ebeafec9a6711db1fcec9333660171aab313aabd25696dbdc6443e820a5f1ae43a3a9f411b321e0ce47ed072aed688ba36cc6052fc231427974a93e83d91d25ae8d9322abfbec95a875df97fcf56bc679ac7f062584d3f244d6e28bfaaecdd78c8674e88b55c2c97730906c3ed27d1cb97a1566b9f0f00ebdaec9019df914719de311e1a98010012b04db445539417487928dda744d5a72daa1986921f625d0282e94fb8e671d8bcb76380a8d475df23d3d60e7bc83e2361d860be83427592e15864c454eafee81397d5a601ec49a5fb5e79ba18722bdfd556f7978c0afc7bd15d0b01b2c0bea72af2383dafdb9f2729b2d976b71f28e8ba86b8c6e0bac7febf26b6e2550aa2810f2efb39781981ce990dcae355caef5f80f62824cf324f901c8011b404c708997a1ae19864e3f11e050959ec6b15aca471b17fd62a46ea7625f4e1b01cbe02b3a511a185960a715306f3b6658e3fb2fec74a1da54ae2a8132977bcf40759617e3094457ad059f36a2446e1f4745ca015cec3ad6f1af4c7c899d258af398b07c484b9040e249e0ec07d0b7cc1a4a405824a1e440cec3814da7af763aa0c42854161e3979b5d74de5a4449886ff8c36e22859072351901993ca87422fe7ffe4193164b185346dd82b89a2f7ccf60237c3bc52241cf475fa2c073fd639869f07a89406f75bf97f1d6a2726f1f6e065e382f700c4b13977b02e26542bf9608668310175ed9f69ef3004ab41a3994319a9fceb397b3eded87c3942df923a102e913e92d9ade92d6e39c7a95b3de92eb6192d5d3e2a9e81df30a9b807a51a4ee4e89afef2438bd146341b5b0c21b863b821b0a6ef4c36d104ea08f9d294e93059400bc9e9fa5387ec31f9f1b81a21e331fa0b96054e9c554f867dc40223af5cba662018930334467196fa3ff599e0dab1522c9beacf43387b0cc8b34f033627e81439d3f8fa5ee3729c3f57ff6e937d0952150ef75c728b3e6d67bd9843482cf48f9aa1d004c24977b56aa024f7518ec7d283e83ba8f7e511f9c0f50baf1368d791f805f52e6b8822f98d9bf91bee8832ec104233cc007700b6cd8d8852a9efcc9ff5bc8fef8d4041207a7795af176472fb0da6aa9a85f8502b70b41c2fb70ea286a1424e1c84537da386753c3c2a96666c521defd8be2082768e90f1109e677c4c836819cc88d2ae85cf5431a0872ecba05c421d0c3ab473c0e2c0f7c63a9fc55839a70b0b93e8e51c25432ef1032f8eac30e43e3aeb7df872e8a87feb378637f7104746ba3b77e1a6b3304ce5aa88ba42d8532bf064a911589b8eb8436b988a4bcf4174a2066e714d105a6cc8ece993df3a6d91551d858603c853e88fe1ad59cb64540e0ff0cf53da6258c87e5862b8d8edd13fc1e4713fd16f2aba3bbd356af62574d3c0139fc55559a6066d908551a34bbc576e5cb688cbff6acd00cf49cbe1adb5c4397335d40b0071e247c903eacc0e4a68ca3afb62e4c4a650d775fd5e4a4dab5ee27883ddaab2a1c0b5dd7d1998270e37ffed63f220eb1c6d9915a78c5cd2b3954c3bf0bfae030874e8fa17b5bb59c141046e4c724c2e20daef4c82e1306484923990bf7185a4bb8c2ec5595accc2e99605b865ba8dd15e0891b57da8264a71ab3fc267e1a32d2054d1817993d6b596656c65eb635a8cd0c2bd255b381dd6ca1d73753f20b59178cd1bda4d6a612fa15fa6f62419f5ca5947a5f666d32d790e8d60cd064373654ad147a47f401cc37d800311dbbd2ae7dcfddd1f2f8d95de384d6efdefc55e3dfff87a111195be01a1b59166d8016ac40695e8b50e30e34f1ab02338901ae5f101f011bea97f90386dffbef87a6de33b64b6a6db42cdb134d1505cea1aba117bff7927b6d32c4d5720c8182f699c1d3cd073a68e6ceeac122c96d1eff180ece1303b0ed8c254501da78a1c2f1abebf8e9124fe81bfb08c84469c200b715eef0d7ffc7871ef4ead83eaeb961d9602769c104f6d37284f4a7a5a9cf13596bb34fde37151e8df0f21970a3be913f52fcf9fffed0943e4fc59275d2291a87cbf3e71738b359d5b7230754b68a4ce85709ebcdc98f4e6f52e66a02f01daaf1d512a416a375982d138696206c89f31568c8fad663078d804bd53f657de6c7287effff7de84aa063fbb8e646cb808da45d12384e6b84d0adef87febcf70c9891195d08d4e6bf58d1a21ae983a01ff8a0c4b1a59970aa892722f4976139dd51304fd15b291e05178d4a63ac3655845f23bcce9e1ed9eec8026ec74da1fc3cc12fdf59df342160e1829fe90286226758fdf284e4d6e286b1201e2161c1a7534bfee7885062c1960d390de077d0ac3d5895d8b43af33c4287b34e5fa7841ba73722972d566db4d9fd28276ae28c3bef3236fcb4c6c7466057fcbb73ab9b2ff250df546101e259bef6b91b9bf6fe354b45660c5b05c36bf9e78c7a9c7269cd1ffc7648b285d729240b1c183bfe36c9dd348def7b44bceaff1f1b43ba1e94878722fd1744e24097a2bd67a760ecb8f31b1d506085028f63562b716581ccce300ed36f9b87d78498bce9cc63ad17c58cc6da32bda4a63132ea3cec0de5534c770c4facdccfb73f97245a2700929129aa3e774656b18ce47f44f5ab4a89ca086265493e1f45abdce1cb727cbdfe9dcf90da5484788a7b330c3d97d01c7bb8d4e051b6a87159079599b4f04b15e7f08ca4bc7cb2128d018c2ef5ddf4517ae5f35f05bfee049eff138a9bb8a717997c62ceb77d91cb9b1f517c0a5aee084af9f7e22b586e210597d33a5d392217f97e95cbf30337dba09ff5555631668a87ece94740ed49f475b82647209a400fba51baa9e12efa475ad5a456359be11f2f9e7180a61dc9943d5ca236b5f9b4cbf7fae8be445cb1d189c310ae8275e6b24696d1ba5a9b2c12ea22bb10d80438bc79af361c4066492b3d4ee12ae3b1d03dad55f78803a395e30573ccaa678c54cc6aa92cceb5d90d5a90d4063f7794f3d111c8a413178bbe4bdec5937e668268f2b3dc8fd5065313795b6a25167e3aec9de7c9bd1d1b10b817bc2c34c375fc71f479d3051bf6b562e013f9b0f99c2f67a2278e4cb75a7d2be0c2075fc8b5f33857a54ff423922f4acd89f8ce79e3ba4fdceed7719ab91fc361b647b79dd671175dac08b2e50f0968619bac5659c591e35c8f6d3e9a935b8ab8d5d82e0f57bdf9fef91b9fd6c0ed88a20571c619c9e5eaeb955db03e94eb2b1a435876d38f8f767c4d0366ffe8963e8154ab042fc94f4001a5397150b12e169d154930ca42980c41945b31025369fc40b839c275517cf4268e84104cbb83a5e85478d22181537209e56d0d37fe4af4d162ae371aaf6f63991f8233d77dd2a9d2d66c9391cf7f2af6f972b82237780303ff0acd31be0bd5eb1f37711868d430f000d4a338330d917ddbc8f059abdb0581005e13fb645f1af29088ddb3457d2259898c1fc54c83b94bf2faeec7ccb34f40df3511c88549703c0b361a7b0c3261dadd19f960e093f01abc235983152a9e14ca00e06d9cd19220170d90b8fad7e87b68a6b64611dce2ecf05d54ad871dd4684cb57330e5c0a8b0350e1610fbc593125a338fe97949ab427fb3ae97f33d08e12e4d3b74302481691c06fdd3ef1ea631b3cd7ad9ea1dc2689081e4f609959359d9c5c4ce268ec23f967cb2ef53af6f9d04029f05f7fda2d4a22646cc26cdafe5c0892012fa0a6753407fd671c1a59d73890f6481300c04121e5ab354448bb34d9870c1dc3d69c75abe124010becf4b456b444d0921ce64463ab12e933c971a930ccfa1678c86b9f7ed2eec857214f463b43989008a5c165b0c24cdfeb7e1860990b7135fb8319a7ccfd9a1104ff3ad6b5d1aa3ad51a734781d1e33dfa5cdd0bdbee9b26999a3f776fac94cd39ae19914e0aaa0744eb422e9b98d84ad5fc7b47da148c88926c916331a1d51c616352cd4111ba3f3d77949347b844432210af0d53efeb1ffa78d30b3820a08ec9913c171207c56a86a4e3ff364a4e8774fcb1c30c85fcab65f4ee540469e1e85b4f03a167940cb6099cbcd566e6197dd6f7110bf087ba164479c5fc203fd6c4661836b4dec8808a7597d8ccd43dc086d3c0fc87885546b21b1c58df4b1409267f82b4c196d93924b4bc5885fcd17d97b2b751791fe64fa21c1044c9b905737769917efcaf510a2b257a2ed5d197f536a009bebfd82c5a3c754fa5f365daf2a075875d92c9df63dad3f2c8dd977803a46c7363eb45dffeeedd59bd2fab8dea7a949aec59f3fcdb58610d1ea35957e249b3ffcf39491e4cf50b9fcb75815cfa3a6d7b6eebfc61e8b226b054f1347bff07d3c681fda6709ebb1f54b5a2eaa087c7a48ae7bacdd8a6012b8e866ad8e25b5d271d11a369462582a686938b79162ca33b8581242c40f8e623d274b6b030808daddf556787808c28148457a3f4195d5bdd4c60d8ab9d2add4fb49c1d5ee8630813ddd8d4ccac2bcb5d479db2f8d0756acac1e4b84db705d3fc54d0f78c16d343ea84d8e4f6dbfe64bd6ef6982dc2814e19dea1e8b442784e86bccf37118343ae302e95a26005381d43b4846e5873e1c815c18f456270f1c5ea4fb9601d01bffe4718745561397f3e132f14df213d42bae99ed8b13c4bea4fdbe026ab82c345d19429aaae2c00f78dafa8a9799486c4faf4f487c91b1f4f0de324b9f580989d0631f4f74cf6d63f9dd727a94a94db30029a06770f11be353ff5e71d3635d47592fdfb1bed6d1cb940eebca73c01c0ae17d7b9b803c7f9ed8b1e333aa6deb53a72b804843a31d10fb74375d378843ede6186da44ee83be5e8de78db31e58a1180f0f7957d4e21e9c7e5ef046f6e2bb291205ca674ea22915aa36ce9faf73a856b63e010be1d8e9f5924f6668d2f144c3f3f35614dc808101c0793877b3f53a7f8b96c29d2c7281f45450c27a3b6f62ff30bc51d3667f1aaccd18179dabeff0746117c47247a905a4b564c4bd5d1e5cfd2b9667fe657498026ac77dfc22df02398351d82f4982f7741a6fc9fc790bd3116b210c020d7941f7404a4733e950453dd04a8e9bbe48f3c2eb3ed7def4be2f172fc69eb551431ab0e9b530c4eefa7b5d5e42f7f26c7973f3eee7dd5c65becfe7387d9b2ee3f6fa907d19c2df3ec01401debfecb1d266eec8283ab30401d17d462a667df3e920ffe9af30e2259ed8967a65921988c96850e4786da3f083449086d50c02b9593441bb72ba7c1b66455dfeecaa1c79f021e3ec84c1b580d928a2e3901fcc05c2f43eca28fbc12c3c8a33a0ab94ea3e53f52e270c024494b9010c2fc945c5e11b3641c7112420be99459fdc2cc9fdb7336bd5e13882d6c2954819a04a05861710c4eef55992a978acbef0e040a0408c836dbdbe4061a366c36fc6068e8bfd9c7ec889af00e72a81109b0482ccf257b660ee7b5d20f85fa8abc3333ad29e1a70f8d2221f6989fed0a4951e3d663374e388ce0dff6fe171507e53cf8a8fd3c85db761ed251fb599d7d7515a657a0e2400f20497fe7f51fbd8ff9b1b8c67c145738ca58c57b2cf38506a243370a3c71fa9d5637a337855a8b78cf610613c94c419447526ffe84d9226c102d2f29daba57a780f1831d10264baac003bf984b3f47f18e37c37cd455781d7b3a6de687af9dcf18ba8086f1228f9c49dd73818793ff97715ba3dc67693fde399a8c6f0ba498ba420cf2420135214cfdd89011f710fdd80af0f288f4061b62dd24175967fc9045203f01e7ef298092ee97d64b8db07fbc335acde38ea0e201f83185a3efa0d87aece6dc907365070ee5dc5e0e7c5034e9fea5a804ef7eece687d6f088e7adee2275b2b888bcf0d510b3ca98d550fcfb7811306d8c9bacdbe6109c66355965bcf819a678996009a8e8a10b41176a1e368bbef54ff0a128b2e8c2d4a52b31243704101d71beac519ac3f10aead0e9ec6a5e4550fad8c54151f35e5e4b5bba53fcb20abc57c413a2607db266d6b5be8511dd1ee54bf7c83313acfa2c606305f0c701fafd50b58188ffbe11c71f50875c5e9201f520aa7f0b6a9dada402fbf6dc3548b15317fed91cbea69c8fa3a1f426e206c5bbb3f7506002824bbc2b834f28bbbc6689fedb14d6e14ecafa532d10b8f328a1cecb28402affe93b5664f5302a76bd085d124d656b6ccab8b85d1ba21c287d68a1284777de096be4ca8f89e98e4ed65404f5293f966d179300708f97c7c2ab961d5e1202afb389445add2318ae66b554b8d91332a782e4e49e6a473fb79e8466b34e16d8f3e4864a31e53b98840a65cb50c01c8030c7952966618d8a530cfbeb29764056f2c168efc00774512338169e582347617ba91bebdf60ac71b8371066e1b3f5573d3c5df5641f25b57fcd4b572f8a5a9c9b5fcc57ba58778653173d5fdf71aa87e8a8e7e8a4baa0002246c176efbc41d425ba12db094b8e64c706865931268c3330fad6effc93ae9e662d2b99ce5b51c1fa265005f25f15346528ba902fd30a0e3066b24608d677a850a14373b904e1c38412ac7fe332266b245e166301a26db75baff4a675aacfea15b9c64cb9add13b2ceb5b588cb3e7732a8546d53321002a384013319da24ae808d02b761033a6ee1fc57d430c54b4a0f8689c344e9ee9e5a383a832c54ae5e65dab3a16fc56f200970aef5687587c055e35a41d4af49dca9425950c7b03fa04eb8a665c34c1802e257ef3df5b002ee01a709584ce6e7c230ddade4691b50622da9d0f65cb4bcaba29b902a2da60eae7a467a9e71ce51632795416d279872e267b26bbe98396b9ea6760459fe23eb1af443f024f4b47fa5a0b4ec2766ba9e5ac8701ab033b536335917aa21024947d324c04057eb812753f8b77fcb0b0d490cbdd5c487ff0c1b916fb1620e4d6353873bc7775b755626f827352dd3dfcca7057d05e3db356f8519708239e63ed51035742498451878dc444eccd3ab5775b6450cda8742de5f380548f5e769fdab294ab3b4356fd91fbf0a8bc10c2e7ad3e2e55c92156d046af0571d9da3b28d460074e35478c0df8d7902e12012f8c61454b8399232538206deefedf20b0ef564a4eb504bc379ff4fbf80e38d5fd03f37a8cfc3b853f7546c879aaa6d21c99c9962555dddca49cb2715cc86f28fc868ee023dfc724bc89f075d7af1d81ee88bf4fada419e2e6c016fcc5073369c186f4427417e150e2879c86112c13f61bcb9a97368832af2a9e06f182ad3556bd93b434f03e8bc507dd231d7d56de8a0de4474318f9b7a613ddb4357ee4b37be0333d0f2c8d747ec185dfe7f69b9084d5b6b53910b01a74caedcddf79bffd3f035cb1d900a38739d7f45b29e9f7418fa07353f7a3ff07025d3fbdba2621b6c7fa0569e0a74292fa6d792af2b25f804176651387b73b181ef324aae94168a8f4f81d318f06f9ffd617de22821bd28d1b9017c6e7bdf0ececfbf18fdfd7bcffaf2bbadb522714c3d67e7aa12bd20299c20507abc7e2867ca6b39d0c253ab94ad8ccc02688fc7a887f802fe5f5a8c284a3be640362fa8af2c55a9ab38e923c4246603c39521a751d04930b043ad947b5022617dd64ffd8982c3dc153abce2937d5c544994cd69a2d54302e69e97a99e9f42ee2003dee33c67545c6b4e57b6284fff0344c7dea9bad1f014b335d7d39e2a240b6183e17dc9a0db7c17ba5cdfce15eb1f0733d059251e390353211db06071e909907af6ffec9e52e02eba2def6e40e340cdd5cf4dbdb1aa9c3c257cb22930936376b16ef0507963a54570e8f02c7e0525e83430889f33ecfb024ac44cca9937a9bb746a8ccf279e5d7f748d8558a774aa7e3f2803f86b0715d49345fb36724d06de20f8b0606a18451c662bd35601dce441b86ef1907022ae11a7c87341f62d063e5dfd6be5dd1225101f5412d340003248945c9fb9df7fa265e84679e600a1abb15c0dfbf45c050331f43675d8ba296ff00530754fe991a46137c216298df5706588bfa80fb779ba20a3f1f94c14f5832e6ee1afe190a1708c773796878f9cfd4b5a6f6ef531a31ce784f5d531c9ae1cee7c6b611d17f328e69953199c48cf902f5a206865b5ebff55090c66710084e8f0372f80c51419a77d12b388c00cc840428809a6b83050a2a660e3e5367badc8572db4ee333beeedb0139d72e103c9d9a03ed7bbdca9d9a06f9a17d4eb714cee7ed62df778772e8a81896454a1cc8f58c34e3fb74a60b19691bbfa238691c624279862ce434b8ac9e786734e2fcdd8acfc085860cf992eef37b5def6085accdf6f284a824984cfa1600ea710114949735afee0951e9fde04f09761c5a8a6e9064ab8f69bbeebecc5ceb070af858e9837c0747e4511542e21cdfc99556051ac94fa44ec01cb2e14b5641e5e33a229dc858246dce5339f74ec46d44a5e1dc8b45cb5b51e075c6b40d395126c5883bb87a4c62cb13c2b7d9a25a47afd0de4122c6d15cb4578539fa51a43f1cf6721c770f8fa4e41db134df9fd1af59a4b74cadc5c3420aadf2e02024780ddd1e320a1af632b002aac3635e75000feaf41b5758cf62eba81783bb7a3dae55af842964ef46d1747390d3f1c80e774e42f53fc760e7da7f097fc231942e06a91deaa8b8d18316e7d610a1aa27a73a58cd04381e30222c033c3205769b4be4de8545371a9fc4b2626b4b165fa08a7d0262ef024a1724e06077f1b54c6c4ee5dd9dc6f3e6a22b17df717326f689cd014fbf1e14800f14e1d4b04225288265d303ad3a167951599b43ae2d0b0a111cbebefd654926a4774eec0d3b97288167f6bb27e0b96a0f82faa8b2e13d0d4b8301b16aada9478cb8539d3da5797ecd60206f6295dac05a809b266ee39965116d346fc8aa4e2ea0964d18336412a14d1fefc763590d972acfd70e39900602942324b7ffb2142a1abc461dd50717125d06b953373f88bb64c6f72c4d5ba14a740d68733a11c9a22f386979ceeed2653c5d5b13b61b8fb3c67560a0a187b443e4fe5aadf7dd9dac47390c4437569894e779df2b5a7f57d6a4ba449ffd8ac9438e11fd3c88bd327378b4dc410fd3c2358455f1a9bec3241dae84b3ad5b6e847c370b47fe2d82feb88387887595ed99bbc1ce21dea7b189e98eee403315b48fdc1dbbeae94f72c9cce4d8a6bcf420c57bcc13265fdc9ab4954f52aedab343de063298f3ae6d2cdfb5ddba3ea6e27dfbc07cd807f2f2b817e6cea1f9be30dc53ed779730973c903925c69df96ee75ad45c9e01bebddd27b72995eaf50f70be3c6eaa85dfaa490ec1aed418531475c64231c2eb5fbb9b070da55a27191703502c632eff3fb6e8fdea0fbd0866568105b609b9806587af021b0e1f2f827354369587d78b5e7a7db95e2146887f4d4ce1022c670f269a2abead3b17199fbaf0ceed703e06d6e56891d6ab642782e7708917fc252d0aa663a8c3e63d8b5deb91f1b548e56c0aa7192e82826544aba0bc698e10cb4e9d1c0eaf9bbdea40ceef248bf896f25b40c7fa8b762d7572d197f4ee686e018bbd064f29f2dbffa32ed90726d183e05cfd02a84767336a1fd7c23663815093f2ead7620cb68f0760f0c2d736c9fa79322dd66f5068770fd7eaff4da3a96c887ab32f2d00454efd616e464a4f3518491fc0c24d2dbe0acca9aed5fdec2becd6910dde915dd61956685374929a46573a2dc0beeb81cf90f799a1adcd1324f547d5650978a904bc17270f8dfe584f6d3e8c67a959eb2ab7b952bab14511e45922a05547d128d1ec686145c53c3ddeea28a36bf219e18a95800f6231f833e113c0c832e21bd480e6a906eae3cfa060f8831e3856be25caacc7f8e24f9d68a18cc001d85722fa9463ac83eb58945d778c474bc1713df6a0b7a00877ca660ce3842b31f2540288ecd9f263d6d4c5d7739a968edb4aa81f7b945079434c09050ccfb2052492239d0e509590c731dc1ed1596780c94cbce128954f3ed4b5f2f16a280d1c5a0ed3ef01dd9ca46cd0d9930076c4a36f95d15e4734f7473e9918935b63e9529d79562f4fd9876127d95bb6c3400fa97d2b756856e6ca37a645c25da54aa1d785afad3c78f5763e4af2e1b038c02e3e62dfa549d230206f6db499367703bd96645701b1b82f2dfbb5fedad839168767f3ccde49841f8d901be51c2369ffc9b86a7b57b58ea47aae7996c80ac16beb51ec75a8fbe390a5f1d566c03947540a3ab66f7c0578ab3c5cb3d1b599cdc572d6e425665c1122b3cb52f82073c679d6f8ba987c3c56c3aa3d9258e10eb988f595fadaf7a8fb714486cc032fb53824922ec3d72f13613dec139e19c86297f5b1b80066a3e7c6b3d875ce6bdd0a5e4f59512ae4fb5a830971e8ac84609f2ebb0a9ac0c1dfd7d7e475497d42c11a7040ecb5b9e4f9087bcdf643fadce4ed61e6c17aca59ea785bd7f4f6f9dc3eb675bda3269cbffc212d62b0920a4a947815ba31b22a7068032609208024fd1420b86fe928dcfc91cdd7b306f70a6c75397da793aa2eb240ac0499aaba8ed640acf6ca08ba70110fda1c68839b2796014ca340555d0ea0bff51a555d06b2453cecfd1c3fe040457be16ebc0d967fcd158437846a4e39a6d094294b018a2e3ac7d59e105ce86035f05c938f245ee1d730298cdbd17c55a4213fa39ea93efaaf8e0212750ebd525b97b5eb24dbaee862cc7de73d9020c85bc78cacd74e6aaf500ccbb657a9aeeee9819824ef74f6558fb850570dba49f38a33510ed58d40eb5ed181a347e8815abf4e7caf5707b9257554d49f0f950c76b047664e448687285da13d0eb8850b5fde767208872ab4b66770be68a5594929f497c64a65d2658f007b70c17ad8e28ca3949400a8b369b57b595bd78a5a56e12c58fe22ab7b8a15bfbc2cb33c4fc03beb67cf206bd86809d09b7d98e669c3eb26ba485f8d5f794d0046fc360aa4bfab02a50c129b7b390b56414eea376526659e01b9f1b923965c25b1404c98bec2b654576aa70b30214b4c6070acb71ff7e8dbf145b0a912a829940c6ce1cb2e8da003060d50118ba6de5946039661342c445000c91f4bdaa7a343befae0498e685e8c4be658eea3c939322d3177452eb0c1c2b39a13045d07f336216b33435c79aba815469009191840ffb406c6fb583434b3643d5d921c4fc5408de8e16430590a4e6681532cc1690ca642ddfc79104b053e859b4645a9f9a1fe4b27c7f07532d8588b512e0124326405eecd1c5377b22619c6e24f29877f6f36a0fcac1a7a3f8eca614067a55ef421497d32506443d5b1052f479eb164e908172796206286dd576049671a6ace25607663c262a0a2c06cc0246b4a1853f26e53f00c5ee4e3cbf2940560545c9ffdfb9c60f2daa22d0b2ac7977676e6ce159411b00147a51a42c7f7b4c9e12cb0109921cac212b9ccabb2e7b10e17f570e5f2b2d95a9e511a246461eea60dd847b70645d1eb8536d01bc0816dfbe3317f74785ced5409624fbd81c53c49520c4f0ac13555498f97c38c1eeea51ebd20fb2c126875911478662a22565d50071a8b85e560781b0b50a49783212c8c65af3650693129bafbab400a3790e71d65a16d62a00cb3e64cc0b36f22d665a666f73e28f8accc080cb490b026795f3ac4a49995f6f364a2c1c8e4d2ab97c1d2faf12f4ab92d8e6b6e35e2512f70c67ea236a05c55a67ce2e34ba708f324a21ef50609567d910cf2d0079b6418a758138f755a1e848d198b9c1a763f244436aa7305272fc5a708df17fd982ea707dc08045b9a2cbbf2a8a9f3adad3bae3046e42ac0654b468366e2e88943cf33a363f29e51c17639f5cfecd9916623415abfc58928428978cfcdffac16600477796885a2e3eb75ede17cbd1ee4d2923df5be3e94dea46e47261ff987827c74050368e6acd15aeaf17b8301f60905ecbf50274d27dcfd40cec0fd189d9ec6fbc1c61d593ca8701bc32de304eea365189ad683195fb42b7c62562c4391b33eb960df11aacd957d11955671a741af1fcd1834ba832506110a51453387c7d68f049905550120684db6093fc2e376ab92726e944272f92c54ed9f108de09ee8b8fc8762bb926c04e459b476d88fb4b9304216b5c2f738def7589368849250026f14ba30e2073c2b83d8f75f702318a42ee8aff18fc6306c6f73e39f63671bdba214045c8c508936db83d8ef349b7b12aff222a08295618f1222b40a2f30b3626fb3930ec2c8445f902d689761d7b71bf445006e3c723c1a40a505198e6285807898478a5d12763015ba061bea3341ab38faf0fabc9b8b1232c2ac4c5a37da047491907e910ff3d82c66e3320283ade7b87a0fe48aca078952b4af222fa48e8a59577c7a9d49e0a814ea0b82d1db792e2a218c9a7dd92f69d556eac2a221d430443c53dfb9e766a07821edd4bb66400be005511986dc2ded50aa9fa4f5a4c466ed5ab0ae34a944f40a6c06d4862b848df4b893deabd4920a8f9a0dd99345a665923bf33790b35ce07b64b2e8f3f6d2aba5f7e75345fec4630164643cdc5f41fdbfeef62384947023cc67375febb2cc75e5c83c21424a5fe24a15b511f98f2981306628ee197baf77d7830c298e7df2744913a80056b9d040aff9af96896fdaa437b7bb82f64e0ce61aa06c4b6634c180a6b0da2d68caf2c1e633ee9cf704655f48721eaf962494d7cae0e7fe1cb00eb4d298c873bc6d761568e661fee4fa06638fc86d5cf25a607ed1d53a40109cfad398325e70afdc48ce9bbb6f093890f3967cc2f6d9b111b4689651dc209879d00e4e68538da47a9f067d0a11f1a0ea353cb93a4d182e363d673b0d3a59ef13ec08ab6c4898f8496a8a09f49e9cb728284b1844df4629c47d09c90991d20069dedf75f889fba4704c0963e27c7f9a4f6a7d06162dc6ac10cbc07f4fd0e0200f34cf26bc24d782d0a026e0e30e8445e9390da239ff4f00486f162c45b86da762ba40fa36896bd03b190a50a06b04d0a05ecc379014f4937e6c98429938084b45ef3bd2efe03d19879148692429ee40dc9bb4e476511231e930bf054e5474032daef52d61adde609f9a84973890783277862188dbb69a8613969f551f6228e2714fdc8df000ec92a988d1882d865c8ccf1ec69b034d2cef704ec510890e845d099d999060f0e96b5a10e88d556060745c338533eb7d0b838116e555818cf009735b56cbaa26ee2cf2b4a897de93cbdb0d1453af75f5abd20e2619e15369dee064b555ea1113a1e28c6e516ef465823c781c9b073600539376c9db1a829b1b0e4db98fea241a1d81857194f9f0e6e52a1b9b09c49f46c8b08623865ac8042a58eb62ad996032f86fa38c95a5951aaa39674f83f82cdae16468429e2c3282c63ddac98c38666b076d704dcb4bb72bbdaed64356a8c56000b5453fc80ad84021dea26fbc9483b0bbb0f993408918de67402877a453224672508dd36972c00a78adb2004df56ecef3139d80ea9c2c4099563738dc152b7eede3413f938d53a7c22acd1db359070d4795498c8cb2330a5ae21e56ec9d6d66dc590ff49c0441879826cdf5d3f5d89c8e8710f178e135bc1ac8cb24de7fd23d350c2eda84b01a6214a746efcf0dae462686219c3805ff66494ec4d69cfeb7e608d87619f9f3d5ccbf019e5d228c6a1d9a15d902b60dd4a6d72ebd7a0c0eb6710e5ab013f0613faa090afa930898c25cc09528b44030d2af60de0c8834a51370f849cfded966dbaa61bf04d1b1d4fe485f1122b3e6252513bddbbc5a3b5264c759a49941f7d7e214586ca401cc9d4d4dd1bfaaf32350fc6486bb0d22d0e8851afa22dcd0dba8f3d0aa60190169b0980216f34252187a5bad08b7b19e2a2f8e59233f69cdbe925a2e8bbfa635071575e30fffd6d2ad0dfc864ee86d9bb14513cc8202aaad7f82120d525b00626a906b7d852c41a6df1c17bf1073e109232e30f3db957d7e7566b7de694d0c673754298e8765a9d97976f44cb0773e0566740a1e0489d405219a1ba19fc5cc9f8abef8b7423862d2779b8e9abb19b109dec7b5079a253609afbbaba7879a03da8612221f0c8a2c4c3d204cc7ab3a8f1965374388a9f7a94c1f2cf022b3fb5cff8c0a35d7ff0a51d2f902a295714621d819aa7fa60c1ed787dea6ccb3961541a26769039be9e9ee6b7c0f1469ed8030f9d64f63094c4ef0502b20f1fa9c513e65e66829b1e7936b18e9eb9f7c180c80b025c96d49c22feae016a16650a5b099f2c0ce4db4bf5b86c97467cd37345403060825cd333909978d93e57a066ad6899acd09c5c517565202812342cda186889f80391cd41a0799d657388749462d9ce25138161b505fee4938ba17770d04c3b689eecd51159dc0c02d0962a71e14e0426f04eef5ff5b22d4d1cb5546b1a58b26c0e2c2b5bfdbe0992c51cbd7767600fbad66e6c5dd182681fe9c613d68f31fc00bb00b39c681e411b2396d125b852c2e0adc29c04541354499feedd46329229b3ffd412ebc37646075fae66368eba2e237ba646c61e11b8e14e1fcf9abb1495bb614d1d45390ae4414ccc2c991e6b0a1c6fc20eb4e2c3dce8db1998ceeb607321183e4ddab3ec49bd2e94de4965f43aa0de3b6eb7632f8ec3d8ccfeaa33a502f7a015d0b79681ca9caaba5ad6d182d27101bf14b5b0786cca9a3ba025ef9e5ff4df7598d0462ed92cd46a0bab22793148cca27b85b1ccb470b05261f0c3a39c4406de6fef7f6386116ff5b0b5b56b752fc8ef18194ec4d799fcd0c0c6f61ba22ebb374a01783dee533df1095cb6e91d775bf1442c8ad7ac447768f39eafd2058ab8e91e2604e0bf82e4405b386e92bff7bbc11f1dcfeccb2ba3470ee5fb8b9ef2f550dec104b991c325075686ae4284589c69a07ff948f9d9e4ca544022a7f6279ccb2ed352ad4bae9e6e65e9bf34e6de1941209e93bd3507acfdab285d961d473b7b16d9d76fa0a5adb04373962582c83098551d512a6baddfd23ea4181e401647b799c38dbb9604072d617edb9601cd7bfb6dc912f96f8f19de6a01e4f61806d986737a7983be290e3b417a45dbabc81dd355f38084812ee0e2fb66159fa67aa63efbbf157044ea181062b9a85d29d26de6301ede0d1c096a9ac16141850e834bc6905c6ce17e12c0096a28514463fc576be070ac037da5e30454d24369620b5dbd3b4ed6829d3060bd02b5a9fbe10b18e49eb926d1f2f6cbc714cf49c2a0046c6da30713d62f44dd7d71e53bd98a6a86e1f446c325bcbe1290d598476aa1a3426b62a7e248559bfa573d03268f9d2a8fda8138efdf7b7276ec25a51ed1567265414af8631dca963e38631e93df9e6a5be373a672760ac6cc6d5f30662dd7de7dc7a75784fc02bb9fb157bc3b76d9027bdd5e195905163149d795bbe36538c00287f67406191a462c6db3b3d62740d181fb6a7697ddce33c50bbe574df0c624085791db6a8fc3a482f651fb613f562eae59d23f3dab0dd2cca8ceae4cdfead67e6bd9b05a2c82b832e1bfd75c1cad825e7d2550b274276740889b18e5819529a98047cf3e73cced1232151afda058c6cfe5bdbcd6a230c3ec0a63b332769a30124806b1ab73b7945091b308a3c8c7c452a6ee2526d2d1d043518282cd1dece5b1a778d978ae3a1eab2b96352fb124704ff7a6e20f3da9a1a6123f4e984d33e9517949eb17da46825c5a83e4215446dae239a015512a7851632a3a202f0ea8f8b186f4356c6bfbdd05a87e0e67e78f713334998990ddedf2000d18093088372202e96f22ce482ac68c11d239c5076952be9548dfe642824905b24ceb58d49995ae0214b655630b44473c0db8b6f4f15160d936cb6179b43ddf380acaef00875f0de106c747a3c88d419fba00135e3dd579a71346f4ce33cc2d7a9dc1f1c88d2d585d74a98a63945003fc6f9ff471db7ca582098327f2217c099843bf4ad2f82e12542fd4b2900289a3aadf1e81c745db4f50aea27a196057d68c0e7d450f4ff72a460a512ca60a06bfbb4ebfd1d844c5a9c1c5180177d86d40efd6ffdb47310cd96230babd22ba62e5fcb879e39193a1abfafbab906f6b0c14fe2ed9f2f15e76bd84d2e078da2b61cb13023e941725d6ca63446eb370ef99098d3ebc9c6b2e5605a3aa24434ba202be22bfc9c10ab01f110e0c7dec7ee0673a087703cda24e68b33df6592c62b3aa55013a49306423b269b8db14ea2ed051c839ac3c5b57bd01d717cc04aadee10dd53e30040728e723185b9bc9c9b813fca7b9d8f0e06b665d1add0390f369e31f0034e6b7f93746407abddd81e54e05c8167e6ee2c21a5751680d6d64ce0925647a50ae00c9434c80bc34224273bd40722b3680fe26ed73a990f20bdfadd20612340a0f8dec82262bdd910175c53c457f4534a14351a4134c213965c8c5fbe9e776fc1abb9c9072af9616d2e934928cc6b4d46ce86f6bfeeeaf059e3c6c67b726f3ec960a74dea364ef2e607e276bc10512b6add49da43e47de84f6a1686cae93442a740109a251e70463d79bff20f6a8eb31238b7ad0fcb0f425a1bcbe6a83e1afd11173e365ab8b9191c1b70eb3fb979fe8a4f0c959993c44e68789a89f52b2bd3cf4d5a19bf85575a9c97f5f66adcdd24416185ee936c340738f68e3b4cf3b06ffa69a74a4d62b966b18387311fb786d6361b53a2d4ecb7e759011afa0b6ee86103548f48017d5d3028df992e21bd264b033edbb0a1f2f70f6323eca4a85fc15e5fac1d3d047fc5e762490255ebd8c0683976a6f2e6451325d6e08bbb8340a3cb871b26693c6796e268d926e5d54fa1a8ed277989e1fd86b892e152a106b2d6417e4566540040ab1ed099818015dcee788d7ffa55610d63a31507e66397adddcc35d9f9a82ba9ba4b5b1e0731d63fb1126b521fa7d758c329226f029ef6df9ea5ef787b25ffd3843cebec7b7111714e06501f4740d5ca2e61a24ea7f7b42d9ea8b1b38a8e001d706326a6015e3dd6f77604c0a19c532661406c4905a5cd5d616c483c7d1363dcbc505463f97652e08ba17326a1e807e3055e7b2d1ec775d54f668799a9523cdf8d2590f9bfeea4de6c2cf8c3a17334da1891d57a9c42d8185e425343f41a0ba3b98ab9a4d003e5d0a4f0109c5f04c6dc48a289cd85078539ef429297428f5061c65325528335a7b20c867f0ff38dc455b583bf1f4d83815e2a96eb34c966af1677e36d9bd6dc5ffa9314df9a1c9e5963ff85f431f4734ce22d3a8be55e9ac810016573ac31dee82810be687d8c0d45d439ff32c7eee9c34a55f6f20d116701b08a3d48aa2b99feb410a90abcfb328ee655b6f6f2de5335e95069c10613c8bdd392d08e77f629cf6d068b19e4146e5d443b48153285d633f9d1f1484c2dc75e62c4923b74f392afe401f215d81d285dc9aa5b8bfb6f43eb2633613a4539e1e5dccab933bd410f11c14853c60d2f73537a9821d230d7ea0c52f75ec64ce11d51cd4f19a5509c462d18f153d5a56a8f9d867827d80eceb02e7d439177a5d3071049762228f7d6d6af60f1ed7b4829a2d053e1e683cb2ba12ab57227f894ead70204618ebe08d246c52d11cb70f15e698302ef7b87ce31c5aad0a9090aad6589160caaceb93e8299f27e5715459967f98e577a20052c2bc96f5e5a4df606b05dbe961d90a68a71a55c31d8903d489d7078f8a9c683ed70d4352430478fc095c57ef58fb322560a1501ad71b809046a763b8c70a43cb983ff2a7a1415c6b07e991cbbc1a7445e0798aa6859735428ef049363016f4d988105cd61e3c9908c4676badc587b6bd1a26105057fdbd1e699b9a9b1f2b12c526c2ee279ca7dacaa990049e7ad63f0c53a9914b010164382c2f9687fef7b7af337077beb9d640a1c9d9cade1a972b1ab129efcb9fc912a52078d03f98cf330c7afb64cadfab2b93477788b52f3184fdb6bb6f712f86982c7c1eb2803a4362f3cd218e2a7ee80c7633ddb64b087092351ae700b38b5465a057e2e8efdddfd47a2e367af903a313d9a8df4dfe203169e7c0df1f881c4ad6ffe63d2a1610ab2b147b47bb9af58d3deac4771d64a9eb6e89e0b2cf20e683958653a18e49dcd69c16b36cd39034700d28eae67b15f05356c3f3d701ba69e71bbd9ce66395f1915f92039c0135790dcd492719bde78cfaecde9c6a93803e4116c52c67bae250e605796c7b9cb141cdbb8c85aea434e8388f9a84357182de00297eb62e88917fe1b4b5bab71fd839918ef48d6022a5cecbb706b92b56e1c9fbe49b9405a88a2584340c594bdc492908ba41e7479c479df6d3f6b75ff88a4b86ea6976868d66378587596ce93faa25c66a837795c27511c4cb3f6fde6091614f4cd567bab274c4993448de70f80044f008c76ce7174d4f85625fb4dea6f5b45a28eee96122f2d3fcc4ab02663687036bc3d9608e9ccbdb0773dade8cf4e911884d9f1572870cb913caa319ab42c45804a468414f3d40113d1bb04950bbe93bf4ad809274c76ca502b3c0e5db2172b3e172e239b5d163c60f578dd934100b62fbf009bc3d78bb31b4673d7213a46da687271ecac2d04d388653094dad14c81c147f4a49ee060f38b5173b4128b3474eb3a81bfb1f5846c48801ac068f0e3225a38184c1cba33f91a0a09c61160974ed849622312589a5c7da85de78be4768e1363ed1fe5218a26ba0905f6dd7fc7b111f050e9408adf80bd00f8deafae2bac60f19ea04b664fdfd9a24b9ffeadb0ce78db4a043b8f05a8f178adb10ba2232e30bd5d7cd80999be2cdb89ae1b18450a5a40a13373c2f232e3774c9166dca8eeff625504c8d4d5458d2da0db043a5cb190829cf5d090b3a5262a181075bd071610f1a3febc70b38e6858714508a25c712b8ca430709e191e5605c79c82abe3f5dcd156b99dfd7c53c0da886e979373e141cf8977ef2fd280df6c977a83838d08558e78546c3d0a93c57338aeac138c06c26172fc4fe4b38497eec5f834caa65fe4d5145b3048fec4f812c0f66b37ea11d201dd0029783b900fb21c0327cdd166a1e1c307c84364d012ee39fe04059112dde1ddf05454a7871238e45e69645dd649bdc921f060a2de7b68a8d7015350333450a3e5cd57187e5228cc9b7de5ca5d428bd61c9fe64abcf1b43bc9e335a76f3885a0ad906476904b1dac781fa9db05a3d1391be2daaad449cabdc483a79350e909847990eca042c538c4c83b74ea1063a47112b6af25ecc3add7cc6dfa563adbbadfc63e619d9b063a8098a819cdc45194f70bfbdf7901696fc0daf5e407784c158506d370564b1a814a4a7182e2509ea139beac8e44beaccfbde739b6cb3ecc6019af8ac6d115095cb56f039bc2202868f644755abc9c21e60cf48b503e853d535f417c9171757d716ebfc30520cb4648437f9ca3963b04c7da77e5fbf4f7b63ebe14bd113afee73dad00557547482ba7a5e0c46efd5af86e44ddc5332bb1403684b537f1ad9d7da06d00ce803b1934548378d1d06cec777b0befe9257e14d327260ff3201fafdc7444f5b15c546e9d55363a75302ef6b184358c678c7f6afea592d017abff6a67ae1df8083e75667a423cf2033b83678f2051d98edd63f56d3c5953351871486e5bca5df552b7f888f53e2d087ef1457f5813ee8529386587a762adf2c802f0767cda402916ed9586f5f8bceee5f433adfe7ac1119f656aa0ccc4cb046a18348c61471f7986b2e84af3353c60215037d5b1386b6cd95c5ab37d215353bdd321fda85c6637626f86294838f21b3bcd6bab439a592784fb83247345c51894b8fc83f39b5db053107132ee40090799cdc41900f577d627062243fb0f6ac2fdd021a828b48402c46ecf090dd94978fe11bde4d40d0f00405340280df5cde43f1ed2a025657a744e71c22d25e04bc201ddd20beb8eaf32b30f690d6fa9a1a02cc626704e8b32138ddbda631c9e9620d70a3a3e83280dfb1487bcb16c3ce81a810e1611dbe675f6555d123ae87217a27095f18b47b8cb58dd44e551eb4b54623c4282a69b88d54fc6e04e0a13d51dc9461a938f931f7fde18031bef785aa16e3278e13cf3dcb712a447432570cd78707ac98661033c6fb22fd44e6adce7fe30a1e308020506c5c73d25e0fe75814dd831155cd7dde542a6a4f1287dbf9e1ea79ea3dea1e78fc8d4f20c79ba0747d187d5a132024535fe86334aa388f762eca0e4ce498d978576f0307419e74c45998ae3e73ddefb84de251dd37bcfebb579b95ce8664d7056260f5bca0e3768d01b607c11321a2cf2187c2ee4f318c7ccf4dcde900b3c659727747d2ec528f3c9c13e76208f4020778d0a3c0c51e16dbe653346ec71d8cee71630ed69b4097b9f78cbabd0bb05581b8956dc853cb9a3707edc49227656060c34fe3f60b994f6e487e1b1047f105487e8898b30f3ea1cc2bc8e78922f2ae82126b7d7af5596316c4180f1e0a1bedcda9be7e82dec06e8db6f148030b832239c6b5c629afa53225ef50b4f02cd8bc965270fc814b67f08b76dccac8d8f2650da286d6845e603a608a455455ce66a02919faa01612c9f7535ba7fef713309fad078f2e157740116d02f17f14be0f4677fc5931c5d9de49b251811fa03ddcc4c5165136e41bae56a1d3ffe83bfc800a263dc6082fe2ecfe15ef5353567a824dc3703a6afa96dd0fa395758603a064dcfc72d8c4149eded1841efe314a01e9914faec47084272cade2bcefb0ef7b4d30ea927be12b1551d2849b4664d955a381db40757e530d7b4a3f6f86d33073ba4333bdb907fa2a3a63568b217bcd641b8fe6ced657055b31fb9f037f706094d1df567f60f39850a936d0ca4c81aa4532e987c72d30f9e59ba57406f7dcd1b84017affe2f9af56ceeb8fd45a3d9bbc98545a65bbe48712be9fe960c63a25ab6a6999b54bbac29e8f1f6315dc302541a060a3715bb2f91a949cb510e48ea8bcf4cc1c21768bd3d2a12d40d01489c910140c869bb9897594601820ed3f3feccd57b7b3c503c0d930f1182b1b1a38aefe13ac206cf910035ee7e4df6755cd09454b5b642d3a21a09040d6a0c42cb6721cd91a8c894b148c232ac224a41f697940ecb4aa220f73b001efddeacbb642d4f56053e67b2e4c560e7377047809fb85ac622c794c212b85f435ad6c4884e132f22c474768b73fa5ca69d763c78ae74192ab88f7c8f67f8df8ae381ced2769d67e23f6ed00d86473c003609de6d07a3d884a32f9ccf8684652eabb3dc08e0b99f7e7f5b31b83d2aadc707f536eb9e97f682e46509262337d1e5e17c627f8ded0148b15a6764708b00601e4615de3027212e4321abfa73c622d85317c88e5d9584614f4cf23680892c1c506c11a0908e7e6b793ca49191ac00038a7775e6ef0cd5f3e3c7314ebb16ea6698dba5e947cc808b48b300d7462956f6a3aa1a49db126d2a612b3022592ca24638010569d2e69d43843621e8ab09f4cbbb66b8734fe2d8df62807f20e17b21502f9052a101e44c87e5263a40021faf533bfbe313974b7661dc2598055c55c0c83a660f9b1417aeafd372fed6a202344e15e4c8e87fb0cca3869165ef0f36ad7170f57c09cfe824b671be17166e360dd040317fa65b6bbba50083b3d782d8eb48692d646700f431793e29d38ae8df0238a4f5625113e79b98e672130b4b8a0196464627e1edfda6146ec714f906083b54bfdecccd65223ccbd07fd86870cb4656acb541007021a7bea23027c6be2f6e0d4f91d98766f042fef26998b50f52a2674205d22396a59eaf2b8c71649a8e056189c0deebcc5f405355333ae3419941c74c0561774b0b14007ba9079ff9f40c4df4d788a094bac77f5fadb24aab7074d76622e47f28370887aea4c6d1dc87d523b365252d9efb86fc16fa321900616046ad41515e26c6f49d3dd3f560ccf85aefc5c48a04320019bb596fb3c901c766bfc86757f4725176382b301b2d360d9d120c16180ec60b07436b371757f4e824d53132653417600e15775de6f1c8e6f36dd5f1e21f71d0f50dd116a059edb803cb789d03c7b431c0b003ee483bcaaeb971b072382b703b2d761d9d331c1d67a3577078b18789a7b940f17a643429b7192d3c649b89951286f1275db9475d55cd21a6796a68ecb0fb5776e0e1eaf9f2a76d808360ef6b3c51f76bf1d768c7e56df7d677018c76ff10aaec414d58fd882dda02c230ea249ae1e0d1b886cf1cd93d5318c4d7607b577164c8b95a819e4487e99da2763e6a6d55f4159f66f186092d80f93a8dd4e9d8022f075cc01b56d424518bf05fed964fd8423cae7dc25478968f5ae8448bf6134b1d89731a69c3ba730d505987a8fae1ee1759272f6c5fd112b33a4ebca4e122ff67475f659e562a66c84ef9a6de37436a4acd1aeb5725f8c6831416cabcf8c4ca3aaf2814fb5a7a10e6f94a77789d01d2b71fc9396b3b6d38003be261f7290be1ca2c1018f432c0951a0f1f2a9e1208558e4563227be3c332da12d26bdac7ce02edc29c34da7344600448b04c3ba059dddacf0be424eab0ef2cab9e4800eddd247571cb18ff6d07d1d4a2c01363d6a8d19872d748e29cf9f26b3800310769dda6ac68319c5263ab0711c9a0fbba4d271334baa9739e4ce4450e38b4517d572498585b54613a9b5ff94ddc35c1ce11d13f3eb60332962022318de3141c39d000b03d84039d9c00ba60b676d997d99223eaeb3fda3f2ff36f3e0df25c58e4976536b8b3771073a59215f4aba9c2e3e1713bf6a659c9a06ae6220794de25fde6555341e00aadbc806e442260faac721d9bacdd710e887402d99dde28284ac60dc583f0d36f1fb2aa43b8dba23581ddcda33e26dc5ae09ad356da98940681fe519bcec25aef6132e54087f437ab9d941695d9c92adf9d8d904e15246bf2d9cca2146a29b7738f71bbbaf0f9a44aa8564d0e717afefe421fae29a841dd9b1b7f6baf1c1e688d7ed23f47c0c8ce5189acdef3422ce7c58b01177494da04dd31ce7ad3ccb9f78ee1e125d2db4414f5d15c7f09ef036ef9f2e94a0f80c402f0264d44fd9226a56f229ca6c576e2ff71cb86441f1c689b06b8ceb0dd7caf85b82e3a9efbafacf34591dd73d689fec463a1f11f2a85349c7294bc99a6585c1032db728cc08691d99dc5888f081601243ef02484e938af4ed38bbd6bf0d349e425800a2e424b602088d67c8a9970b158dadbbd2779026fe1e877e036eeef79ed82f258ad63cfe5006174ec9da4fe9d22c0883be069b9d20eb127308d31a363b7844aa5c3c3e405bfa6ac2dc5ffa74be0c58ed62f1650208b0cde362cb9708578904628c80315bb0d521f79dcbafd177527cc690c702d9a16a193d0b655f8c3ab92bb22843650dc74167205404713f6ea64fa2d0b70e8a0098af23d6ede4dbe26fd38a02189654ed8c523fb3d12bcd3665345a071c6159594a84044726ca62012d9547fd9c5be115c85b1b8984ce0713415773c0a51b8e135aa4dfa95568959eddaa3266dacbd5fd106935e285a894a9d7d0a9e5ac28d63aa3a4ab7470b29b6e1cadb0a3111127f96ded162420edb795c13991dcbd3971ada597a0a4f0e895dfe518776e1e9b61939fddb0123ba5d75501ba1983b5711894ad4a4ed17edcf5fa9a442930c2630f23d80068ef6645b7724e9c3b0f1318a0ae8bc3a7c02672281edc9b16d630fd4b1d84de422a783b7ffcd758d0b04c684b4854a09b2f0a39470f2555c858ad088f6d57cd03a9e676896510c15cbb44f2aed2ac5138c3522b54cba4dd5a53bd5a02f34d40d61f254723b05557b0e291faae9aa6fc056b6473601f8a882a261567979df3b08421dffb10ca6296e84fea9f1c5bd3ec6d011bbb6f4924a73f39c3ad1cdb011847ae3e9b9842aa654f4edcdff8a63e17280597e2b2aa5ffc7a0d8ba7b45c68dff41ecc6fd99c4a75f56b616d9109c7b86978b11ac9d8c1a4e4ae280b9712024aabab8b22f5f56304ea6ab78e6a3b029d5c0a2e61234463fe89506b44a4af04fa3874c86f6ebd0ca96fabb25ad8fa0311906e00fdc65c0785d9e9a3bd053c9952e5a34ffcc5d298a35cec3cb9562123a026e8f1e4e0c3839cb042afd09d35ecfb25c61f332521359aa7f6c9240f9cf03e82d731f9f5f487c6352aac0314d3021adc555f5d30522a9b0ef1e28426524ca8ab663d160dba674e3ce9ae2b07ef3299aa251505685066cfd96aac86c2e88aebf742986220d1c260a817bd5a040af1300a49a1878ac3a36ee8c6b98ea1cfd6ec45363dc2c3881006697befbdf79629a514f205ec05b305bcc1aa6f321d9658d2df45ec244bd23699d3b4134d6c46b5ed88924d4868a64454341372f992679b6c33da8e6c421b0c969c6626d995bf139e127a45f589e44e9cc9694e482152cb9d546772a6ea3f7da6cc6936b02bff15c3f3292bb72935e47b20a7acfa2f973306ed4f6304a095181512d28c9413261f274c4cfe32605e5c5a586241b11382fc6867fca9e850f00d7f15d19fd819234b125144900aaa3f92ea7f1a8d6a5852044be2b02bff203e1dc6ae8010fa41142f96e462497f1fee7994a652ff2c9a5ab650a5a9e536096911c36215344755152ad86847a5763763a2ad7e63d0d94d6b9f20744b4edcbd930e688082c61c6b7287059e1d9511d485c9c3d3625848335f3e561f17cc916e8ed067128428c8d177baf9afb95bdce11102ed6f74706c1e4f3c7ade77ba59c0d25800696767fc4b7e17d072a1b8ff8e1dde9722eed0817a17e6a7fc875ae1e32aef8cb747d5c3538b5bed10d4b7f1503c3d288ebb33de7fe20b5c5346158d0951a211954f51e93fb15869a7917d5040594dfae7657ff81e3e2bfc920c59dd0a47f73c4a6b18ee0afcf04330f47ed206cbc349b2bc479c26fd6f9af45edaf116bad5dedddd9ca404a9cafcd73e511f9c73776fef2697d58ac024454535a31e5a8c2c94b6265ca9d53c218618328218b80bde82c80b3943414008f1d9284dd6090e2d6029bd89113257152aa8cf76581097299c4d66a276c9486c1f765de735c88a60f275953b13a9b00d3336628193daeda4b6f3a6b03577cae4c632c54293debec6a063f7919055a8a0fdfb251b19ed380dbf7896aacc7369ce1d168e2a3f4fb7542a03d134bc03ad856e6dd211231fbe823f5ad2911ad42621a63a7b5ddcca335fb10de81ed5ad658afff58d41474fa401dd2f3d5a0c18f5ccdcf4fd295dd0929b18caacc9229f752b759310e8696fbeff6e44108340552b8c0c60dfe6994273543e4785a69df1dfc6f042cef33cefdbd7f721d8034e15f0555a54a15248814853535393d89432a2787ae2a94997265331bf339f128e5fa94923b1318d59bd99a8de43781f48d44bda08e56d14f6964975eeb899c29c4fb8ac03dda4a127d5b9981e4dce9f58932a1650fe79b58ca4d2f78b240ecdefdffa8790eacfea968f9e4769ec4b560a9e47e79093ba4944c84ea89b34645439e6349e47692af54fd24a52c7d6f4cf3f000fa9738917069dd58529764cf56b117b8ee4bc8c2edfd3f2348a501dd7e1f710ec979f2c3465748a1a9f54c00a1d17957548175dbe4c81638f60046d7997f7173ba6ba89fdfcf21268f99751022ebfbeea98eacbdbb467e4e56d34cdcb4f16d2ab493a6be46efc948b4aa37e98e73c75ddc19973ce39e79c5d4bd7c9a5630a99f3873961384ea3e226a7a2f2a8ef49993eb5e5e72e94da32ba5646fe11631c63ffc6719a14d88523c37666e280f3e7fc9df96541b7295a4165a6d71c0d7474c7409949e8349acd8ececef8cb0826b0d32c74eb7bcfa18367a88e584644cd41d5391acdc66667fcc313db6c0daa04c28279192fe3431aa2ea05044710550fa8f1345ef532f2a8f134543cfe47f8df9d5919550b68797e7e525fe8ba81ae726056fe960752b728288bbd33a597e2400a1be0cad230ff29fa80c9e543661a7f5ffe357e5ffd32aa1ef05fe379fcd7a8f13d22fcd7f8ff1f7b667c8dadf1e2f3f81fc71ed5ff8b63cf911cd5ffd813f335c67df1c85166c840cb55a25e8aa6c02e28aa964b5bf958f8de4029632c4fd1b2352c5ff2104e78e28c0354dd405751dfa807bba0a7ca309f82498daa1552fff22aa4c66d52060ccc7bfff240eaf730e2e732f234b9b38526b75a001c3bd37f125d402cc460e0892181681d4ebaffd00474541ae2be4610f71523ee4bf579b5db978e163398a63fe1cab8b8870c031428309cbeffb3719ae7fe24daf8f046da7b11d2041b279430734300374455f8ac07f21280a80a6f7c8e00fec6877fe3c6b36ea0f040588fc2e7b01e85f1c71199ff71c2b364c61cd6a3f0288c3fc86701b9210001bc0922eb4f106f3c29a2f0366666666cbc09e30ff26dfc8f137ee68198f0404af89cd597f0fe2500e04d187f98f000f81f25fcea81bcc22e4124c09b200ee04f10713c2916e00b20aa38a44d0735e941429b6c9b55ffada85ba51fcdba45f4bd1f756bcaa6d256444b9739cc5d4602ba7de92815168a0afb44856dd2fb243b653dc6e6e019ec0d7f0fdfbfa3fcb04b363be34db6a66b939d014717ab9e8630b963d89533d9b08e01f1a7a880d5324505cc886398f7d33086a1612a1eafc2f97124e75ba972def3bcb1c7cb540dc0717df58d2e5f398f8b391e4beea1fa566bb8bdcb33a5eca9dcc8403be33f846e23ce78d3e4d65b1647449894c44ec0036cc9107c9061a526fe61d09295941aa502d7fd2a003c9abc05ac96bc05ac763e36af79881562613db4ccc51b610d1bb94993fecb83eacff15619a5c29c356c14f79d08564f754c0bb5ec09a526bd95fa951c1c42a78f4749c29559d7d1a36b7be609db85fe685ee84f6ca157fe9c98819df1f7440cec0d1783765defa679c2eff9fef43de02f9367e4ebf7449d1ebdf2f0f4dff784a7ff9e47f8fde9797c7f3a7d189efa1576037a5c5512b45c261e4ea77b50605b0758d27fd4b133fe9b8b72bd35e91f9c1c96252519aaaeba494900a102cb8e81205210c3d49834e121d03b2684fbc42488ea34c94c63e11a93a6a1cf29292a2a2caf32aafa577e5f3d2e9f32aabae579a47ccbcaab7c4fcba7742ce3ae8cb4855d46d95c79069ffdb949b7fc9be55bbee507cb188295f108f840640da482a3a3de1f48ff27d3e4c3ac44600625163908d5e2096419d3f1855ef17b3bbe62cec72783944f797e1ce620670939978ce4a4b20e8bc5c2c961d96091a806a3bc4e932c43b8bea27aa139ae7d7aa9c7acf2ebec740ba6f2c340e303d68c80a23207618450e5e7e1b6f6a1f2f3ac80b29af4b1355bb97befbd6edc1718841a89fdabfb7e1b4dd37127f6e895b7d3640fd761b58d6e7d651f652eb8011353122d60814cc935a51a55e2d7f62f5f4197669064ca508ffc31095ab23c2f06ceccecceeeeeccccececec3f4d9ef8c1120c8911c90d03bcd9d9bddb1b8b203e3423f18a27962cf919829f109205121a9ccc40d4440a2366109a2205480cad00c80a211560b14b8ea2348164288a228de44807283baa7852e4480bb890a17a90c44fcd071b92340144d4440e4ba408c202206a53d8c086fe6a30248aa1708a2234253f0005315bf2e467c8cf2c92439325419014418208dd6700ad0ea9adf833ede73add15ad6eec93d965504f3407da64044db5251d74380ac2c2892896242931028a2555bc000914330025d54cb08276e2892f7a7bb777bbb7677bf7328e6ea5e65094a41cfcd0474562dbdbbbbddbbdddddbbbbdbbb35318a6c3e0b850c507a77b4df6cbfa3cd26de6c37dddac6f279e38dc51bb6d971c3db363b37f34df3f6f6762729a9010fa1fc2bc3738c7065ca19e379a9909190883890ff78fe333dd2c53db72ef315f820f8a7ef091fd503fe49f56d2dda6256dd8af1c7798977b12b7f1e5487e24cdc97ce44c55951b36e0d6d6b386762695a881d52ab25252d13063000498ae28c192b2bfec38d2de33e3128d7909a74ee3bd4f729323561df09c249b757211cc1ef1b4bf0bdd1d5a40df8a50b649b19edefe19272cf7395bf837ade7bef5ef7fffda2bb54f7dee55a66eeef7b15b67e63f879cfdf89464eefd234a7e79ebacb5bd79237c30a8ca458b2e1081b64d58b8a8a8a3847c7b89bba514ea44612edbe8845ff6920224affd91a21b666bb695f9b118d8b84d0b29b98748be35105ee69547d5fe2201d107eb79db8686b9886add815c91dbb2b716d0c42b92fb9569980231379230d328fe6b1c744b4d3149a327e9616626139da1a2eb6e5c5b638116cebabc1c8b652dedf89587f626b54dedfa1e01cf4fdbd880dc261dd8773e4185547a2820a040f41aa7f87d151fa07953573691167fc27a69e13617e135f9e672d24d4b3ad49a9eecf21a12b5f6e34baf2e55caa48ec846f30f9ca7ffaf00d26a698524c89c608ad168b3565b2297317b896dbb4c9362396d191c21431e651a2ea19899db0f44c8414a1991251d14c28e64b9ecd52336488f0cec4d433522966f2e11bfe2c4c3ea713cf58624eb3c9b4d81c9b11cb268bc5e60c605e5e3ad641ddf4662e2d2cbf4b61be9a49aaff36c36e22d84d86b186a5d964be82718ecd886ff8a302375f10a8d731d833099529e6e8ecd6a07e64e2d6a854ffee616bb83fd6e4b83bd3429a746ff6a91ca549e6906833b1c307f2f2e7ffbe0fc71fdd7f3fc0f776290a98042cf749d79f9f213fddf7ec13efc1b11b7f80db0528dbe709a862f04fcf237cd4d8e385370c68d7bebc574ee7ec8c3f4369928beaf705dd4616e99afdd5e0ce35aeb112d7d6a64316d25ce3a52e7f546ee4d919ff79946a22a209e7740bf8fe5493ffdc6ca265ea26f5a38afbd2b5286e544057766d0d379ebe24ba8d3adea6d3f188a3d3e9743a4de634e93839364dbab7747af8f42ec8118de3d435a2a0dd77834968d7349bad112b5d9f5f14fc83782f7f478d3a76e6fb8276638a8e59501f62b6851cc303cafd4682ef32ddeacacd61836ff89f3e9c4d22c0726d8db73cd82e7c7d5d8532154b20d57b70c7b9abea6f8373acf646006ad7502453314dcae040b9ed8659d8db5077aed2d5bc28540a503420f1135b33674a093e12c40e218bdfebe8967faab7a6605229a430bbcbc36c9ee3f2309ff3f2a95f9787791e2e0f33aa1ae665bc7c6a54f5ef4b064c932c1fb67c384fa78d85d296959516951696efb422d2d08517683d3d7f8f2728941304ec8c3f8b07d81b2fe28dab6b580f964e53fc0441c50e3f4d3c7952cbf4459d7329e5f5c8d3e4e4f131392e683fe9abb94caf81e5d91a5ae7b7b035f3a7d75d6f403dbf471e2ca83fe934fb9aaedaa3aa7ef5b301e5c61f996c3184a157feac49a2a29e3957f967673ac811184d5b88f301d1b32e6a1943018202e463c856bed334bfb8891d08317bbd66b32e6a23f07fb6860b4f10083f3c8da2e72b70f4888a7ad69dc0cee76ce65238773559d433577fd9b36de49f9db9b1a9cd3c31361c20f8295ed0a288ac269bec221a6d224d21f307e6d3640a3893b6046d9395dea4f96a095a4ed884398d7bde37c392aa3fe581bc548d5219fba76ca31a34977a3661d2644d9cb48954fd5fcc1535bbe8710a9593c6cfbf094d19bf50b7d8f368bb029f859a94cda029e38d43a5c0db269b42e537e9a22f35e94bdd2a276c0a75ab74da1c72a739ad5b4bb37103fda269a949f70eb717e107da2f739a09e3718eb359396130d50ae1cf9f4d544e581b9934186dc2605ddd7fc07ca1c6d904035afa12adbad3684bb425da52f5e762b4745a1735e9bf421335d9335a1bd168b4179a2bb139788cbde17f7a7f37da1a5e62094eb21d25cace84e015d33b5117b05998000a190cdaed395bc35da38c9c9e51356c666666661e4b162ac1064110fcd0719af410f652056511fc0ec3adb9707442b25b5d99b9bb9b6178a1f3b156734078cae9953f07e27c238b6cb21b6348b7626b38eecb0e22e18ca3d3834611fabdf7fdd327f4f91ec461f38bc27c4f0ce2bdbc07c520decb27c8bf7c82d01b042867eafcdd0294ab98ebe58de2aee602c6948ff499d0d92dc5e41ca8baefeebe49cb5630123ca33d763847dbe0c2f6dd871cc74d1f581141dcdcedc4af9ab3dddd45207377779fcd9b37770af72278639962eab123b2d0a47f221d83065a0c4124690a307c50aa0205330cc1233aeb3e0f5fdd75980ff90816b63531b1ad99df0b09e14043aa7b91128e6d0dd7fd37c28c72dd976a1b550ff01e7c1ede83e1e63d0f301c55db6824e5f7857af067b5cd27e6b0263b51b571ddf6df7be1d8037aafdac69c6f546d1f760f82dda8da461cd49f3ce63029e8fcd261dd7ffd4593ee305fc5be316837313549035af64c24a2a5c3981cd6ad6d8288a0ea5dfd55a40d87910e837143ecca1f89fe61a2a9899734a9c32322adaf4e25082ac776c67f08e5d1c685e49afdc1a07bb7fbe60d04b76d034fa80de4f0b481fc1bd8830a4f1f828f7a1ee0a3c653f827149fb6499511dd9ef3d8fbf80b41af1b59a4cb0b9237293e1cdf0a9acc24740393d0fe44564fd9944da139d4db9753c6c44253c6513e1aa8ff2e69d26bfe7dcfa32379edfb5ab7befdbe5df9f721287aad919a5ce2481f7f1c92d71ca95bb56e95dbac2ee99697be4b886aea085aa66ec881fa6fdd7ea8032c00aaccac270d9b51032d1bd6b186354109429747fe1f304292c5308ed6675d9e688114a5f881996b35a41d983908a9492d46c3a0297ada2f29cecfdd5d13d0fd263a8201121c363b6e6ca80eb45c9a0dcb85c4ee76b1a9269ba363aac95e124ed0316c32202de1e8baaeeb7e7b9bf6bc6e75dec6799bd76ddce62c1da5efaf29d5f28774ccccbfd3e4bfd840cb55e57fb18167078784176c8d8778f8197a9be69a060e9479773218364d34238872111045b3a259110c4533a2d98ca8685624039a01cd8488848a8c8478a1fc30d18edab9e4ff264926654eef6f83ecd6d25411ba35cd02e367cf903fb5710cf364a2fbada496293545f4f62be02a2a189ffcd80e0aca485d32d2f6cc48ed791cdb5533d2116db78924c4b4a36ef5126666e6187b50d8083f0943b48f5033d0466ada8f44747fc4f184d6401032d2cea800a41af1cfd95e3efe08c1cbe5aba01951cf84d0b2675dd4b396b5d00d347eb2240041f702e1ab66f469aa49268e8a08b978d3e4eeee6e775721039224e1323bb7cf8deb3ce5846e935bf3e6ed9f8668ca555325fc50c20f5984ac9202ea620141f73dcf474f8905eaa72eebbd238e4e4d87524a757056cca9f5eb34b7e1e8f8ceea0f4b70bbbb2c8fba76b89c481d22bf9c39915f8baaf9208a154504a55c43d4c7225e607676677766676676afb150e369a106456c8a2390581f77a03d7a23120b78109e7f1e8f3c9367a7c9de259eff7f1e5fda6181679b3b7ec33bcdd3c26c6b1ff3a9d41441d496b400fa82871f9808a5bea281f2c840b3f907887fd88128a514e88789fc004d77ff719afe2939c63ecc3eb13f516f7e6143bb45a98bb5a36f5650a9dcbbf8a09df84d6e2e624c933d95e09fbf7371b04df7418fdece30b703fdcbf4b82bc474ebd4a44d7b0cc29529d746b7b6da58afd5bf2fd336627ab5a586a0278f8996d45bd24fb57ca1ceb9a47f7b759630d4fe90674bddfee6474656b7df19cd48a86eaebad18c92d4cd6773fb6fefd2adf9dbafcc06841b76288285926b89134860f1ecb25ed014093950fe0ee830ab22072fe020ddddcccdcceb62c540ad20e2c4122d6214394110314c6f6b31e0d06464440f458ab868a2429644142a9210516406126858f213daa0ee7b1c6b1e19c6318eb14f73cd6db1e6d9692a22abc74393a7d960fe556c51cb57826e1ee7799dd771dbb6b9bb4fe6cda793208313473b14b5348184431bbe4e23d34bee73415dac19ebc00721eeeeccce1b4f66f776253da91d014612417c3cd07dcf4ba57e64f0191181388c37784ec42b8a9408519188a00454f480c81731081a628914454a569820091a9e7c5794a0464407198d99d99d7dbabb7378c40a21b57caf1ee1dbf438cfebbc8edbb66d7edfdc260f68b948373898210521995008a1b933cfc9734e9f93594da8b8412d7fb21b75ed535a9951f76f7cd53a9aec6e1860e4d3344ecbe9d636418488466d76f473bd719a6daf69a71a8711ef594f4bc5a880f21351e0088d2882848e5e30272087a39a0d6666f73ccf73f6e9ee9b3405915aa650e09344b4248908a8d5b56c752d5b2dce61b444cc0aa35aa66642c4c2f6be267a33bdfbbbd605922ddc87de6cc9bd8f364d36c77936dd363b96f3fe9bee5f990e4258eb13ed0889d6b414122d6c9e328aa0f375b68679bb14de4057b98b421c3d7030b033fe2a4ae8f6b3396cf20183073eb035cba1c0564bcaf3a8bcd3dffa79bf4223639b9a7cc8f89e948c6779fe1e984f7d8f8c7f7916984f7d0ecc987a1e735ed8c5260533aef7b7fc0b035bd39e4baa49199514d1d5e46260c579a2a48d20d06d3261b174f7245c19274c4b5b33756bbde7b8aedbbca02ed70a3a4d2ccc1d1a45481a8dc6756291d3eccbc325a7f17cc543cb223cedd74bbdb494fa9c7bdd9d4be19e6b7323f3cfcec0bc1bb613ed0889464b21d174b6c6bddfddb1fb1c705c5fa57ce5cb5b4a1982da8ddce6b51729c272eef771db6cd431f55b3be543433ea55c4019b56c847bda743f25e81c3d1fb706749f3584ced5a4ab28a1deced20f1ffefe3b3c5b73aafe18d89aad66becbd4251c4d93d35b4d3f2a45a69629d269fee43852622d656a7f7f9abca8142e3745b9746846020000d3140000180c06058321915840281c2d7a7c14000d77984c724c98c9c37112e3484a29638821860000000000002a008188010df3fbc11416fc68e1939ba6d428385c039439c70c73e9987a22a438b8b27cbd3f0ec0bd2f1f22d8870c8ec036211322c125d046ffcdb2a9682ecfd7848c359941eb62eef31ea41a0e9b0f22ecc16e6be837be6b49fb4794791d7be959424e05a7ff7975cca5eda5be88d77d379a1029b74aa3b986c2e6ab6052ce5e6d389b260c3852d523674af5e37e735140f685ce331425c46ef50458db95b84efe0fd76345e183d6e036bb9725c2e9d85b0a114569fb336e135508a236340e3d4f9a84c68fbdd4043d39cba62339f6697f30b53d7440adc6af45b42a9ef1c7c420053c20e4b87035ae92f842a1980ca84a01b4146da423fa5704e52259f53c57affb6d941f5ca24f58482a051301dc8b753579501af73808271fa9c0c101de25bb1341a86e21ba0df56907a5f7602ee0ca6f61158c2e1171b889bbbf67d5decbf929e574fd363e6f34f6f033bbe9d0ce6ae59df543f4b5ad0f5cd38eacd8882e9400b8ca96134338d0060ed4598b28d11be4b90407759965c2031640a104adb086765c590900c830007eaff2eb4dc9aeebf581a4dffdbfdee4d2df10eac3c7f2dfd6ff44e8faa60729746b02a1964910da4b533abb72d90939ff7afb5f288cbc1bb2c8744846e69967ea7750d08d87093ea4586b234ac576fb484b9a2b67f5000dc66bcd8d11629fbb0868d2861964711ed1c7088495f57397de8d4a309629a1d60c37c9111f46aaa07df2f60a789a99d601eb52b2b87eaf928d464531cc7e616f056b63c4425681df837349e18ffe0665ae9fb253da2fd7f7ebedaa7053793adc4433f30d94d30558bcc756befd89445c16753f59b64fa10fed62d23c4cbcca728eb1fe505c37a1dc8238ce0b6547026e71310fe90e73d0c730e421eabe4ca58f290e85bfc7207c840ef50cf28491560f6d9d8b4b19799f6d4d1cbf5296b7227dec1b4af47bf42b52f3b52852821db91d977c65dbb011e82fbb65e80d1b6b753668d8185d961abc42463504faf64a8ccd40d40da7a643e0f953cf77738fae3b8450dc3f88744e504222eaa0c036d13661f55d427d44c2b46cbcc2279e9fe2d9e92494a6bbe651ccd1d5af1906c83f25a542fbbecf013867219334dfd11a35417be63b4c2bf85e68ec4c21eacfdefc7902456f12be23e185e177779c3f78d9a0803cfbd8dcace043d3c748d10c6cd1fd9f34b0f55003326deb343fe8dae37e632b0803713f5b0473dcfe09f2d421053924c2eb654f1ef0897079a1909bec637fee543fec201de7c8caa3ee2046af66d309015204a001c4ea0f83865337b95722c98f149e227d09154853184e3657e2f15662ebeb3477047081690e22c62b91c12207ffbd4acc6a948974686815598c5a787fb28dac43ee0d361bbb0d3e945ac7c283e46ad40634900dc1350ff6f9fac9c285b9595ad7f4c281831772578369256fdbae12c7c01f0a86554d72faead2dc2d584589a82fd6b3739ae140685a093398e39ab6da2d3aef3bdac73a219bce352b3ed8a71a64741e8d500f011dd18ea3b2a211737d0d6b9ceeec07f7f58ab2a8bfd17484cf7484d9f9edc399df64d1d8329e6ee816adedde4596aa0ed2ce129ee8ddda18fd757f64023078535d1c109bf4eace3aba2b11e824656104e1bbbc0ad1c7206f3255041dcac6317b8cb230a81ad5ad58c196afa96b160506dc04acec05d3350029c34483d9b8990c9d32aa309adc08f7b491adcf3e47a45ad764f6024d1ec84dc78dfcf17038cd800167c74bd155f586ee9a626db3ec90c8a89cc5695601388dc52059cdb936c6c1281642042e301eb352ddb5d6a7af88ca9bd6fe37567816108c9eab58f80525ddec093759e7e9ed9d5f14954a5b9ff4cb93ecea763485445cd3ea8ca0ae5853ba7ef3fef741627d1fde17d3ebdcbf5f48bf031a2b2f27bd360a4b536e4efe4ddae0ee84e3b314c11f98ae123c429195f4fdede52e9e6a7f7c0d867ae158eeda51c704bb242a5548f92743812c2124edcae58c59b47cb3a6eb33ae1aa8f309153c7bfdc3c07f5f9129f16ecca4e9616d0ae86298611aaf0939b63e3e16cc5811e971dd290654c5506ea473c3c5a1a21434f1e1dd52a42951a9923228637f30edce85fb6e42209967c60848484b5e8db2a00c53ab31863cece850edf8ca16109583c72b0dab416c0f9bda585e091ca3829c40c0b9432203828fc4b3c3db08ff4093bc61e8b02a22a75de6e7e51fe8a4ebc88b6217ca056c90ba61ac70fa9372bfad57a9b937d3aa3fd8088df73cc272f4bd6b96fc5aaa1dbe4a61720dc781225d90b673814afa0ce53140d51ef58cdf15e7533dac44f8d8388fa25a89b94f235a44935f5e75ab342908252fe5c5c0ce5700a8009cb8061de7a99d0d6a56df6dc767e725ef29978d1e62294b940a6fe088b1b9f29f3097127957996fdc654a89a6e4bfbcd04593f2ff565b9e794030d3d9d95ed54703e7a0e4762f4a05f10174f4889fe5126645622b1e311eeef268d62ed3555e1c38529359b29cde014619720c59c0d2e8f7a17493a140ac916335708ba24eaaddf103ad728f2e7a10b77b5c9a737b76026b17acfe11e6f6779852dbf661d56762db623cbf2b8050ffa974d53dad7aaf9566b919b7774c0efb0212a41dfa65e84c27bd2b5ca9ae31ad02a34c7a00db57b5b2d81f113350a10b5fbe747f8a51f74e02ab8b3a6238e47a8b877c9c63a66219e6b0e440e35ef9379467501042493ab185098993d052fb57bc502c01e9f2110c4618c72c4678947ffaf2022cc0d86cc64634f68bbefd1b0fe8a74ebadeb1013db6b19a730a24f0409a85c80e5759d0f8d225288e0430afb41c6f48c8d9bcc1d6acee1673388346128589a3eb01e6be135d13eb4c042ad5b1fee5fc7b8407ad6a8ac11778a785105e0da8ccf8b86155908791f15f11c93e4dfc2c9617e4a0b246a3cdaf7d7c8e31800d588090eaaabc54490705670e4f726ad1caacb41120cf8062cbf3e00433aa2855a9cd4c72aaaaf9d85c6f015d7001194346ce6a9411a74fc147068890c2715d6fcd06e5d36cdb157f6e206062edce0499fc2468dad53d73bce1016f06a5d534cb4b9b227ef86445db74de10271c7a88a014c344e6911240ee78b4c1621e1b1f7a87964034a6f5bb9a7b5e8d3a7931a1f53a748209e099b771964db42dfa653315290639f3503b06347def8d35d579c9e0a6fbb0978615f728d1eeae36e6da27f945cc05c8b29d2b0752b68c04880232cef1f964e66818f6d1a2a044030d23928af467772af42de8023e2f503a37bc2972e2ebbe8cbabb05f130a2f4db22b6f4452ba201ea3c16d9737a898de8413056b292d1e93e18b393624f1b6af4982db65dc955ed442d92fb2d4c44295480a50f4a6763c960f656ab6d82737c5b4764317905846e2967fd1fa144fe84e828ef904740b2d3509a15568fce0733469a0af51749040467c9d8abdf3ec86678da489a86c51ccdf20d9bba9c9a10a21493acefb89f4124a01ae9b5c36f2a21321b192b18c7910a134bbcb8a326d3a6ce1a65a4385aaf1b0b5c1a8130b925c92fdf42c98eacce4d8930dfd0459bac17a15c2275d1f0e214bb9edd2b674fb403bc41598286f41ec868fb086ebf84341617d1c820cd5301caa7eaa34906278e4d4f4011aff783948690480b6e30b670a58955b24a82f8e8a940a2cb59dd548066e16a04ba71cb36f78394bfcd1453f49415dc2855ecfdb4f42d28849ed44c9f51e23a53a25ee003a6d933cd0781ef91d7573db0f63ccf87cf0ca26be8495eb1e06d104eea5a87fab87cd974c1e626a745ef4685de7261b4496e5a49462d3b67568ca821d8f2f65c9577f6fd594ef10a414bcfaab2d96d556a4f8fffd00cf0b3fe662de8b9d178203e0c6d861d95f4c70e8913a75b38f60ab00e3abb0aaf7b5de3629a8d448297982a21e20a019fac1db5e10a33ba3c00cc301a40af6cc506deaccb982b981ffb64f97a769b91b4de11acc8ffd8694e505899da04900f87f65d37986004c1222a81ef06be634aef422a700bf783c7b3500b2398d3ebd6024a70cd67e3ed21f1c2c27668981d293d9b0ad3c9b59fa1a2b38b32c5e18ce0e5b9ea9491807c5caf9b7405f5e6a292ab53334be0f03f8d750f7f82848de80519b34628e62fbdd9585c772fc459802705df60fe0831dc399ac70db73c6a3e542e320c9fcbb80dc4a3e29a010ba6b5bf5f4cebccc06ac54f1c33407e39a45507e2cfb3bd5dc2e451e36d7e1b5950cc3640840e89bc45c0174c59fe31a22486cf2b62dec2fe1a9ac65ee04c82ae9c3946d6ddac1a8053ec01a19a5cfab8afca6f3e0a7f9bfdc03c568a5f12d166e503659993e619d3b145f11c7254b8497961848cc62c47714d43cf7f7b84e643dd1c2c363b73383393b10324bad722fc410b60c6d38b44f009ac425500636acf2d180b34acb4c72b3b0a31f2be2eada2c785284742f21b81938ca1a52f7e3dd27412434d316947f9c2457ba69b9c5ac75cbb81ced1dbd0fa701a19c76d3942fa5e381f2c0c4f274cec4458c4987c3d8903458e47314903657956fa29af88a22cc49cc08ac33a9678c5f318d4074689d12b56c90daa79cb65e40025946822e6103e18c8e9b8910e7a59fd788c31fc30d51a9734eab0f25e9090e6a26eecbe8da317d7d8a8b99a60e2dbf698ef4bb406d391976a69f7478027dd3d5db0ca93dfcddee1b8892a4ec8eb8ec66fcfee2593efa570ee13fa7d26b7d7b6145899bb7c0ee822460ab2aeda0b219cbe3d678f6e3de043e3d76d1fd1d233497dabeaf31cc47d48591677c3033e7b0fde8047fcfd1d12415b3dee8d6f06199ec55c04904dee665234f66f59ebf7ba840220fe5cbab3637f4ffa9e8a9c59da675b25001136619807f7a5acd1319ff2ce814bcbb01c3928bbc425c40caa166eafb78278b116879c98756018b8bc8a94922f4a8eeddcc4c5c9c3de741deb995dcd50da11232bf78e242916cba97ea1fcb7ef479d55209e6c48913ad83c8f110446f7a1166c44bf180f1bbaaa104158ebbad2ea2a4236f44e658f9821884ff8f90cfee783d4a161c9a0d12386d3e27fd98a27448748ec9612ba99a66258300558863ae49d1ee342b9be15b06d4a4de1246d8adebb57ab312861647ed5ba9034fd49c4971346cddb1b47501dca38fd799ac04c0cf62a765cf339815d62915197eba18fc5959dba18e731419e55eb081613cb29db10f4769ed8c796a4fa5a2f6df7708aa7ad6b831efadc91b9013ad3c4c976ac2c3894096a117aba338b63d1c61ab4e049606b054989c751eb89c4bbff00a5aff4339b6c29e421e330014253f3358bc34926ada2b54bd483e12a9800e9297e91bff59abe75cf90fa2c53779cb012fd061b25e5ce26370ea529c42a5ee0bb88961a61f4d3dfeefee4c03480c6870bcc18e42830b5bf7028eaca7d9f6c3d50378d47c0f7b354ddd9a260e9ea118e411b644082e9a92994e94e665bca2d0670db440672c70b0027a8ac42ac6437f400cd99dccb6c74089f382f314dc486a2f5e3af36915360642600f87070e3bba4c06c6840b2179d1a1003ee9842fecaabe753511835db8df110998418100b370cb6921e37949d9771b3111c2dc74a86fe276d68619a752f332201ecbf315138f377eef90c7761d78c6e268ac2b2b9a9299ca316065f6a1b75defab79ff4aaa3d1722a406b0fae6686b6ba8ec1a621f58644ac702182bf5d9b274b863c83c7c608df188a437eb6823b2049135837851a590c1c728e5b745788eb0f4b5808975b31701f4941b40ec6e8133b80ee02a69e14e7bfc1149fdfd10a62a70fed82cce1e707e32ac6a11f59ba9ded4e25796024b1c729b0e9eb1a9e5f28f7e29ea2a7f2c37474df742470a44ddf75e180414b8a10290cfde0d97237c67395e942d233be269c6410554e2dcc5ab313af66b608c2aeb861556b383ae4629ce308778595f389b974b24f5dfb9cb8ac9019650f80ed15f94c67dd048a858f6ebbfd8551b393bbfd275495eaf6c4229bdc9bc885bad1a13312a8c6e73cfb003b18d924c02af490f4e6c86d3b8cc83b8f493a2f89a22380a5d9dea0e47a68d950b697ea7bb8f1a69878b6d870f14b99c446cc67265c2c78152dd674e4ad9ecb4c76b62b77c0d0f58655eb1b1a0144150a7926bad4a49c39b6ef8af0218c05affa96b0e31ef895f9ea0a684c072c18cdb7c3a6d833230eb9a91712fee75167242de473aa6e5b35e6782982ab068a5984aa944c7e9c85bb1ed8cbb05e5d140e0736fe3b4b774fb72428d714a7dadcc9b5779e9b7ac2c22d0e35471af7d2a3ec91bc49b5b58ed3c85e415407df96cf8fb67634b8b35901f299d421f8d7da1041f09580b2babb23fb6e8c93b16c1ce6eae2c60720211843db7a5f857c7b1ac0a4a00515a138934bbf88774314ade4b2beb1ed3f14dbbe19792a026dadd2c3451881689e228cd57800950e378647520f372b9d0b866d953312e1b8e9248cc12951b4cfe3e32940a3911efe1773dc191f220a154fef99848803cb8784cb8d8c882c8bc7c15244251553d13167e196446b554053df7da43d06042e5ccb7a30b12a6e9eaa6a988c2f6748dadea5c6ee8313657fe6ec84d5567cce4b24ccd760fe080f4f465aad8147d8fe1a317803c6d2aaa841f9e8e85983d9dd9ef13ea14b104248559a6d4a790ec178f57fbbeb14601983daeaef49c06b9658d34599b596b548d7d161482392eec030769aea81d1efc9b2a77fe0ce54394775e9b9fd4aafbd44db4cc79e8787c862e9e8b3c794e9200521abc41c4952d3ce651949685340ffa65219bfdb6d9801c26f58c9eb53353e5d4d085720e2d445b17d90551572648b6941544171101571e88216b74b077384a465568801c5e6ff331bdb352f2e97a7539c446949560dd1516b092caa3603a946218a40b8d9fe36957196de6869564abf3f47aa19e833ef78e90ab46e1590a113ee67c415576651f3e91e76481e1919c35b12d2a56755b8e5a44127162cc2abddb09e09052529cc6cdeb3e58cc03cd0e14fab33d0afa33a93e170c6a0466fa51114a1f5f3768c1f23e4815cec692d8662a0bcf136a623067a60f1c9093d6ef8cec51d4b3f65217b9a9b6f8a5ae6598004943279803464c95fcad3a3a000fc1f9fbf002f3d26873b4406d6224c261085d7fc4c1ba9088031e5b0e5f1f483d7a1a4ea80da9083a8d0bd1e397ac591886f855b2de7c375f0703b5398e0b0a3440b19f3cbfae6e09f492f4328067205035224b6a4fbc44233d78f18cb43a13970949f5834c4f40b1495b8e548efa78bfaf29955bdf5746e76aca1ac9f4b15e4184ecff0a35fede4c1649c6993bb28136b88929f0dc17260419ded7ec09d8d1e19b4037e48f57d2de6ca730eef147de7ee11336b3594356a2ab2657f2b1e720e69663d3fe36882c5ce9daa39a988880b0d1ad0fb73f660e15f6ee0e6cabbf6624669964f2d1207bbca2bedc8997697472588cfb9bf14f993adec19cd118909c29f31416200e89b843e74d79d0df5c610ac3c5f6ee48889c7e1fb01490cb1a8256ff117f837ed28fc761e81049eea7c45f6d130b29c52a065645100c4b000bd424249490a1d37b6443dd88601288d22f39b894501d4c1c8b64495c2df3d39d7efb21540f646cd9be060fc7c389e023752955d64bf53cf5da8b7fdf5552194bde3925aec7d23d1b46b814bd0ab50e82da3e777a1d6b278b71ae994a0ab2e140e14b0659979a56c2d45149dc04231f9b1dfd1942fc36a95864d4fd4da580e187c3b36e400fa8a70f193fdf727ffad0d95248bc1e2ce03ec11d5d8d3e1e32f331c047cbcf737da00bc35460330e473ef7166fbfc75dbcf387be533b00e9615d86a430fba7663af55690463d2f715a8715333b1ef6aa2e0170c4d2e3e912df3221e861128efbc10eea160079bd593ec5bf4af22eb648c8b45bee1b2da6796d50512177a8bf1025f1a4da4a144a5d8341bc40d4d8837327f36fed53eb1eb9e690396539f699cf9ac483cecec692175d619371b974e3ae5de58e2dc082219fcf1f033664986f15bfdf4941b48686c549143012e42f6123f4d8be8c19c510f3b506a1b68c1eb5437dba20277c11d94bd94a671b2f0f071c5b43c3c1dc2005007022e4c1b5c45564005f5bbf67b8a09eb06ef25b36b38945730f1d903fa8445295c71b9a706212cd02cc04c9a7ba73025dfcab49faa1776fd64cc2419501071d20d37c7b001b5b0a4b21955be26d966eb4a731ad37a0b9c8cddc0cc27def34a06a00cc8edc2d982c4eed931cc894cbb3f4cff3933b7151b71dd7f132a195ab05f9e420f3f6ee5a6bd2a189231887b9bd3b46f3a7b8864df31537c50ca7500f13692fd427ddb1453dbf872dc35c36a7f88bb69668d8672b9b48c3bef9e99e9a5e1e4d2101ae32bd079e144039325070725f0609aef3c552d03e5fa17041e3825db33711064a59eb06c2f9b7e36834bc715a4dde151641832f11efee1219db1419c1000fd6f221b4ba9f31cbad579905c6ea7dbf142c9da8950065a69819f99dc4862146bd2ce2d48c2a83d5ce0b1ba64d7baac7fc7a87254fd1ee0f762e0aa608338393eec2424f6fc169a6a6969a6a682f07a08006a03c797c0ec2392813cf6e75fda81bf6c3c93e844b61747a1c5d72b3bcc9982ef8af861e5299fca2ad589ec227ca8b1030b63a8e83e4bfdecc7abcd1864be4b3b45267731dcbe4e8d9752413689f2e1c50f009f438fb9ceb0e39296c816c124d44caa09bd2161db0f8911a094c1b487471575d552dbe1272e996a0660d2daa49fb03dff9b1a1252ecaa70971217b4533a0e7e59d8f07871c69f8ffc3399cd04af434440a8c30ffade43a287eb3117bc9116626f4c1005652d28f5468ffbf4f4a3f17290e27b06c1a0f4a37760122d4c283be28dcb9febd4b063c1a5343f134177e152e99bfda3fa150d25c15b6a18c69b8a46c953026731f4721853fceac236415266e898b105db0a3121b4d682d90f44770eee7901096b539863155e3e28b8fe235e5d474b4b0529f0611f060379a3e4f37d8e0eb397c932a01ed678d9018242fe6eb4b5d36be482b957c0d11e7ac0cd842261417289430d12c5d081227d207facc291cf02d22a75087ec0d9cbce192600c32fc62c5ed331a8fc5e463dba0d4a0711a1545b4a50acb31a43f95991d9b746d162c099f7fd8f1221224a8c416fb84a589056def4002369655ae7708909b982b4e7487b6d6089d9d0a9f7bf113468af5364ff749831a6c407cf782f2f99927150d93ca91b8587ef3223f2693fcba2074ac93fcdcadb7e89ac564c4d16a83975526e813790aef8851ac4b6adff1e1c41f84ba7bdfafa026da3e291802810610d78c34329825710724dd9a5367515d5813ed59b5c8959392ed4c462537da136ee3695e2495a737e5ebb0508d569ef820045d693719f549346aa410975f73a1b2f062bdb21da90df7b420a55a0b5948b63133ca6bc586d5c4117d8f1877f3f13832b0ed040127ab0873a05d20fc06e857fd5d43400a8e6623e5253e0a8ef4d85087bde4fd177122448e6abcf6803832ea731aa1c95fdc574f60328eee7304754f625f27681a37264897c84df8cdcdff3eccaeb95051646187ef0b716d64b5043189928a3710ff9e2763b91841ce42b10489414382b319a65ceb0a66571213ca6d2f546df4fe7d8668188389035e5b435d5d719a83d8c44079dfabd196f61fc60c26fddf345c7214cb6cdc80050a7a1212e9cf3032be97285421af45af006c4a28bf674e487d13653d141eaec1b729fc085faf2d6c6f3dd8769078bbe3aa86fb8b4258f6a344a2cec17070dfc698413a5db57ab9ed6ae9850e6b8e460b6d6c08853d287950af928d296fe4bdc7ef793f811a326f74a23eee7166fdb83971e174f140f2d243c9f98a33cb8edbc18faf98fe2637196898be92a3c94aed3de3b5a30d233ff5b4a22600a5b91174c649e5e956cf66becf2f9b741132ee7f8391ca5ef43d3f45f96f64a00b50b9e087589e5c15c2f42d57e0a95e1ccfb449a032b6f75a196323eaddcc37f24cb75a1060dffbec358a00b0fcecea97d04d09a50a578f14c92c71ae60ea816c4b8daa0e43a61c9ecb19c2b557b2637445416e91b1ac0d7c6bedf4cf8298e1d57dbbeb25a25e3321c2af5803a4d1a14e3921e4dd681ce948d9ac27b82a43f6f23119b0de4ba31108cf02ec93c53038a7163f2539588f0262eaee92e66ed030cf299fa03dd74a3f0571c66b5e76f95ba204de9d3b955354f53bc7509dad7f8e7169de94c534c0cbc3bca43e853482439b71d5c67a01bd0d036d65d76e5fe1854d0e923985cc151abed7e4ae614cb4f20aa988924f0b0bd7ec597629640001583632bd388419db9e27947ba6e93427fc3082de2dd24a2546cf3b7024f9eed1b42df7a56b588c888e88816a1dcd43df2b0793856693bcf97abd227ed703653ece68694f8d2c07495ec490c722d02331b960d59c9c0fc7ae2b55c4da7ed976918924dbef442795c2cc922f031c995bdc79173a291c0e13663f964288efb98d839289a615f8ca700101a22c7ba52934bec4f54fac46b11f955469bc14bed644e40184d12a353945c624a4c04f2f8ec36ba18b1024f4b01698c1e5f644983216ce2e3af9a85e2206a5c683c013c1e9c06ef95eff5ae4180e3c9c923eaeb40e7b57180702cefb6d368de9b81f2f6cea761bc7a4f55fa60eacb19229e5026e68e0892a7dff4183db1ba46ce0bcc19e0fb994accd11e87915984c1a508e2c3487fcf240e721b0cf35b1439a51757118b1c1481c0014e1c9d78d7303623d9ee86291ff9589d9a82c7e2d28b14955a7e526b096a8b96df6bd71e7dfdbe6a0968bd9d283bc7b347c39854eff2d18407e77e6d4365230ae1fe5e3e35ed5f49ee1e0b8465004dc2d0a3a559615b511ecb0c0d88487908ad1b29f9969cbe2935093c030dfebaca2454ee37322224fde714d23e4262e08f87f0e063a0bc9fb98fc9e2aae10812e2202da38311851983a9d9c901408159b6ddd435b87e4d29698496557762d9e16bef2b71260ea3d507a08db74187c1e8270dcda32bd8a543a47b1705df594dc0d1cff4e0e3146a0fc3b0778d912e4c8e34b56ce63e880558e2fe6263a4f5a80e963e5b0ddabd64c5bb73a6cdfac1bc260447d243aeada03a64d8dd5f094a2636bf62421f8c25d20b4b26d913508c9591420143211f55929e5b539882047029dd47d7fecd7809fc434b1c3fb8a4a940e9115d2081023f38bc76faf1dcfa48b46b1e20e6915c18ebf4328ca5f54858fc2f4816df280569903e81e6f68db31796c12d24223487aa2a178297a14e4ea390fe483bb8660f24e962dcf05687402390042d30a2c35818fa9de9316b3c79627400688daccb7d23d96e6fff42d7f63dc560675861cc35f5260f6236c922dad351e69ccc0756f8ad67b6e323a13faed0408200a0fbc0dc3780b22e7677cd3b232237aac64f862f33f64084ae221348546aa298c789a0d17c1caf968d3a262a08ee9bdd7653747dcdedddc3dfbd79be29c625f919f786811dd8ea280a060b0631b69941e50b0085f1dedd87ba954b097f5cf7304b2cf63160351c78fa4ad3396b4e58de021136df7c042e51440bf92556677cd630be115e14070e272fa0ae6a6f9fec24bca37cda4a40ddc37c9c204abfa6af193787b6718eaff64c0ebe362171dceaaddc6cdb3b88d92613cecb7c832ab7ce503aee2a0a64ded8c213b91ef35556b84f542792f9b5321002197392f180ee9a78cd21cd98333c305eb1f53372745721af6deb742a1aa622e7dc1964e377dbb9d319ce33e94d11a5d211964bfccaa969003e1d533537ea2e52d46f98bf8917f57247a4fea49c91f6711361f04bcbb320dcc97ccc81c84eccf956111de122cf40fed5e855841a1b4546af842fcf0a4d1645c3fb9505e887ccaa61389e4825dbb23ba77335633c895b41279e46279e02b18e96f566753825a7fe98c2c62fb9527edde51e43ae85263a1ba44096ee8135f2030c7efaf90720e8a7cf44a58953d3d6903d7390dd5dabd20ee242877b680de21fb206a75bf68834759d4a87d31dc2719b513ef806da4519b6271411bfe9afc5b8f7b1b6a0cb0ff02895ef908066ef2609a9730be939a87ce91cbb273e7c442f724593e24b06a9ed26d1ab4a009e67cb218ca5798f35c26ca5b71a2b065c7f52070d5f5f6ce7389f3654b49e888bc081df70334bf20e2c7b2276c07dfc2dd78e0fe6f260f2205c60f882f14180ff33400f5b9badac39d18f13ae12cb7654028ba0d88209d560d02dece6ca161f31249b7282b149b84d973de88b45044d236c23861fd6bc3884989f8a667dd7226a65b7419a1be57b9f50d40c73006ea32745945deaa4a7cd2cbbcddfe101ca46c72129a295db4c91f21895fd63dd4bb9cdaabecd500475633b252144fc64b93ccd6815bbfa47e73833511ac69fd38559a9a08fe6bf67e6197f2fffe35d51b0dca43059e8e54d206b7ff5fed050e71462428f233764f9cd883067ff7477984140b0acdcabc8ed97b6c001a6bb506571f5989e750145cd7182f8217b1e786469987e171b8dfb6007d39873a0c2088b278a1957d20d06073cf723b09c01008c52f118d5886749f0625dd612e5681f8ffe209a0124e6d0df07a9aca39029feb3de5840e3e61754e319a7628628ecc7312b19ab64cba12aa665c25348be574315432a751907eee057ccb1655b97718795713db1a76ae05bbeccb77395c9318e8fb539bc6790098a7190775ebfeec78ad4fca06954db4a18275fda419023f85bfd0a2fa705d335333ade35d661170fc0898a8f0759d3b2bd097a2080119db3d99493a626e3d0c5e23e797225824442b5935c28e2223020639764006eef088eb8f57a9d129859025f2e1d5cf16ecb8a6bc6141866192d813765ec3c215f2cad6c0de3cf190d94da301551af1847db2e0796aad32049ac830c25a10fe15fabe4fc74af39f9285fc19d6be8a76e55b190609581c8d070d0f708b8230bd269ea6c1f2d7e9681009511c0c9d4394a90b6548963b35399633bbb9b054a6b36c44f28cbb1860b1fcf65998b991c981b528b27147e7000001ef66a784360cf301a1bea9274bd7ca70baa9ecd245bf84fc825de6e579c629aee8f7ec0e867b30f742cdc2e45a9edc8c890b5075a8bb4e7c2df6c7e4a4159c989d941d59451bb67695a00dc60474134656936efaeaff697739af4a57f9272a9a6aeb2507b4b536be4643ec2189681bde910fe99dca4479c6681937a77e4f1432261a064efdde8819d950b5b00a4bcb1a4eb5b1a696ea43aca006ae917eb0ff5922430eb1f772f6b97ca30a578b4ec97585ba188025fa12ada180e563e3387a2e2d875e6db425555f31b79dccb1475a24fed96d52316aaf6a5cd932f85cb107c7f9824835859b396ce9302b104951c9c736befb0704ce8f5947894f4bd204065d4faa47f212dedf21149a602d261954d7cc52a896e81d7b578b381f9c0bd7694ccc7bbe1806537cd04354c002680976308d4f637af2d4d988beee962611a905c8319e3d360445f3741e7977eda96c0678465a7e08f367be9924f75bfbdafcf078b89221532a0bf145e6b5b9454498d4b35c2f993a346b39bfe603c57969a17083a49d724b09b6e2b92adf050c6e40aa8f90d38b5bfe7a3385764c05096cec3adb24e6e29fed5199b2966911bb70dfd6801ba3288ad9728f00ebc8aa431ee24fcde9f0457780e88a57a7872734befd65c282c5385c13cf1b7e20dea9f92ea843e015f2553c27a8697e0de286f011d7de2e5f185bba452553ee65bf820a04309bd75dcfd79eae5366060f09a9836a0723c4e9beaafd9f59ef4c2adcafaf8d0446cb7f84699a7efff1d32411d807e771e2e36b7156613f36246b20cc94ab67013d613b6b38cc7799445b435f1f8c0ad3e8d2a051575de7f44e10f00f320e664aeff8d9fc5f4ef2eac3b64a6db536b18d5e135d0dcd30746fd57fbbfd3c5c26fd1062e76e9594cb2dcc424cc8145025b79eff727ddfc86b24e3bce3161eb5a3471a1a60a12333c7c49496ea072ebee09659f78f7ad3dcc29bb7dabd0b1a4233f623519f32b6604c9feb7391181b2f6d304024dab983b833dccafd795e83f1817a87d00618d12008456ff77f440214ba82fc88143e5ff403c07a82a3fb39ddc2544d7d45ed2ffc267034b3a60291be53480a266152a8a30c16789d4f90217a19f7e5b4fcbbed992bc6b064bf494888e01b2b91d04d362478b4f6a653f4b7bba916655cbbebc8bac47745b9a16e34e4c709b8b05ecc39eadb585c847a02bcc593d964e63c423e414ead3113cada04b6fd6db9fec86f951f3a7b51193ffd63c8f81dc27106535c05c26c0efa52303114f43ac43a16f757a8a9e67f4d85f1f5cddbc190dc4f58f6f6333e0fc847ae275addf512e75c638f9bbef4461a0be4eece9566d315e9aca6265c8ae288fdfcf474c3e4fe3023cf1d4fb04e1222aabb1920cc118b7f489da1a1994649d644482b00764d04064ba7d23f054957b666d8012eae22e413485bc2a8d3ee75fe0a8bb80582f50ddd3f5d6751d44c63f76344f6d220aa133df4de18d86b5df2fe00c6a2fdd0233b1849b5a644dd3fd3b3d137f1a4597402c6faa9fac072a9f9c55106cfa8f4a36d3be334585445be77da1e8c072b20d8da1d464ec5053cd0b562f183cc8d8f1a1363aac40acef5dac70985f2842507870bf9dda91dced1a5c2c9a74eb0be67ae46e4ef49945208933da97b2a177ba5525859524f4c394295cf25fde937e1b4c02441d128a4345dfc4eab765004af4a97e88343dfd3e93521815972bacb25ca5b7226feaa98986cb2a1d4fa6634f04232adfc92cebb9f66b7bd5373c4a37c323f3301fd88708c52a01201ea30e6194ff2109128b318dae1af48bf420f4afa8e5b18236acd8717fbb265a7a72bfe1c631906c4b794e707b5ba2f94d243709a599da6e28724bf5a080b193315f9bb3f268f3f0a2980aadeceb715d091d83b5f048556b8c65adebea09ce19c6a526c00f44f18cd92a7ddb288bde3c681a513c099031b9af5da8f94388e36d31097f1dd3c128b3a88d941841c5afeb9cd295752766d3e85353ca02e3fada6f6c785d63f715bbc51cf480b4861a3feb90280b8b1276aab953290e8c30654f6fd3d11a6dcd1891dc51e6a51e5859a49c7e1fff56aa0fe80d9eb4d97cfca6490ba583f388702a3a41b23787d1b4d6aa81546e6eff9cb013a3fcbcb115e3fe7e068d8b21c420dd364283e4f1a36bc68e9139476546dfda5982cf3aa138181aaeb04f7d2b2c49276e90ed4d438214bd8d471df05f61c706ceae72ce548023919a98f7fa3169d0d467f982154a0f714c1f7eb547a58e98b57f43c4c5f33f6ca381024499232988d1b58b565ab2435e6cb9c35f25b1209669968f2f587d4a73aad5eb9144dcce87c224f6e78cc906b9525cb50775048c6a36263452d3af46260b8f72a15036431a1e6830fec2f8393935609f21f119798baa429fc4a201fd789dbc597fdc1691e8114849d2451cf3772b9178fe2712b59c9745ea4b8cb103924d3b7db400e3d9ca1bfb912daa478008c21c2345ef9aface9f66000388bfadf97ac2bdd523d7da6f48f88e828bd30a5bf9e5751a096e5de821a194d30a48c430c34da648eaa5bcd34ea197d40854be0e927de87d5e3a93a8519f5b56e7a978271d207eca08f90e0197bff84adb1db5c48c1c899540f2066795462ab2d86a01870eebea1f67cf280b03ba5ba14b0ef7cc42ee7083aa1f373386abc9160c50262d10f93556daca5a180bd1213564d6bac95973d0c9519c0d8559b38a2b334645a554f2d563069e7b72e3d3bb89a89ddda15b31c30c07c373e39b5e674863b72ee4e1fdb42265febc6c16a9df5f2f8819fbf7666f967007effc78408f46fe50f619187349984d3f59c7ed3b46f27bce1d9711ce83e43a6f657d05a47f3f5f4ca39da20a6a947ebeae524270ef6fa44fa952dce8f527eb6bc8818319e73b05a063723d673108e2820b30285d8f83eb689e2eccf6ebcf2ddd63e313bcfb3e9497f814993a251420e79efef3004cd65f44cd16ee16c4777dd44abd9eb8301342b3d53ff223973471d2ec5d2720810eb5e1da51ff9d583e1deac8d97aa84da47e315f31942480d10b8e3f7aecbd0b160a11084df7b12259a0d99ddb6e606f1439551202b33c5bec2016815ed70de6b3009901855c7a3e90c515a8662bdf4827a25ee665ca178c151ab0ef90f464e42b9cfc00fe404e2629087cdb0b57210d77238fbba36f7d53bf5d302580c34805f77a32ffaaa06df248fcd36edf08567e5c99286b0ada10138bb8db9ec1e7917e5303eac1d3b7165aac99d97095718f43d1e1e21f961c8604360639657878cb8d2a988cc6fe14b4838471e93d9b5f4000d6bd16096b047656f0a3c4a6fca24b4ecfc37a1e300fa3b13b437eb3db4112ae99913a82eb91ef2dcebc719aaefc0e0301a1d18c76b31ac25d20d8837c504df01834f6a7a03d248e4bef6deb4e409a82fdbf2cc780073f4c748503d9a881cec4005eac9951d46c53b792d3c6c732168496899510370765aaa9ab611210a35bd7bfe0938d4a685ed62e1ac8a09346973a91a5a8c939eb7243388edb0db00673a351b1733beaef82776b4b567812666fe0114ee0617e2340b0d4f0d4358080c7a09a961f25cfdcc539ef61621ad90036cc9e15c009aeb6b252452f3e5d3f5d3094ef5c23e793a22fe130e3898f7632c0278ad9cf005ac99510a95d48a03afdc33be9ff03cc32c40af01b2832ea1f51d181c14b186f5d155afefd093e31f94be008be92bc005260751aa4d83009b20357749053ec65d5aaf98f595c1f185807ea0ef0ae10572e683284cf7f4dbd88b4def0249eb4f946a578153bd4866ff0ffd085d7d6768c37c65732b9355e67356034f17a9079541f243c462b031951cae285944be967cb6148781a62b03fa70a7d4dbc7a1a755c2b4d1e90b0d47d97c14c3272af5edfa3a6fa87f3c0a80879883c2a4cdc96c406b3e461c7281a6c26a1ea040428e70d2e74caa11eebbac4639f8decc0edcb82ce7b68c590a9b4dda57744bde3d7cdc9e3c274ec5b73db9642d10e3f47cccb4614017154daaa39991191e2f27352180cb10faf3cceab4dcfb10e5234038d9f61c4e06106ec690af1cec6921170f0c623e4e04337a7be0ef7a0ee1230da2734211c5da6a171237cee84686c0ce14fc6553531cacd0e40bf13ab6a12841f6833d39481fde961702522b84588f44be52b874fe68e5fbb461d716d7a9b49a923f02208ab0f55920afcede5c53f3ee39e083c9e01b997d9a6e0f04021e8678dc8f6a3648f8783e7734c6cdc9b8d7dd10a4e79435b3fe402733bdbd137db27667a7266538da8747be52d6c9909721f9b9a13bbeae1c7b014423a14f18913403b0b1bbd2ec02f1485641a9286ebafd37018471432318e0871b29d78683042d07c6bac0a083c06014dee087606b92c2e9219759d7bf85673c7a398e72682dcf681f29cb410db429081be670285e91eb4ac28c70d5a9504eb9a502f6382b9f6f77c250808b97d1f5071b1015d55002acf2f9f3a09681050c58f9b70deefb7addfc0d6b02057f60426e21f6236cedf3d9f54eba4a743f5e29d1139ea8ab6681c02bc728848c03e290bbca49dd959b82ad7defebb7c9d789696dc215215cd533684f108c8d24b2016cf0f39e0636645258475393cad28f784371b83c5c3f7772a4a9f7dab0d241694cafde3a086230b668b27391220a6af86bd93c4264d9a1b676c320626ab14187f51caf9a374a9961ad5064400834365d01f6f43405128d12353200506d6d3c3bcbc184c7defe8346c67f45a8fb83b1b679cec59a613f762c992583b577be8082fca01b3b230b4546301e02e3b389326ca9eac9abcec968451540b68171a2ec2b6751f8218e2063df99b88ef45c76447dc1c6a6bdc886ee0fb7322578d10acb78ed89f2a9a06890b80ad54e0b48a6dc8ac41c04c35019f06a57bda24a7866e461ccf5055832ca556880bd87a418065eabbd111f1f6006dce20aa55efcda4387ba4ab633d31679eed833ea693f82c6c6fb7a9b826fea1b3d3d1655b442cc4fc08eed39567688d5a10178a766d115b21a1f2e59dd32e0f7c6a0d7c4f06de1659aa683b09962e31a863dc582b2946a1de2fbf5c5aa4d01df379e4a7b78ada380cdd52ada2fd737e043546c941d1407e156953a217cf7f7711aee380bf4a8c6bdd176efec9010a614074131beec2b52718696f623212a6c01d18ed0e23c6b8bbd3fd63e531999baf804e971e1de1e4dbb439446c59f9da1b097a2a95ee30bd0b2c7bde9a7d03c46d8e6ab01d7a59e5267704fe8d4668b5c82fac7192d91a60d547b123dc8a8255ab43672412f15b0f1db95f0479fc2297017f4336fcbd9faf54bc5495a22de5b0d359c6c33e872ce0fac226d0a1fd042d0c6448282955b92cbefe9844d7cca12b4a19167461109b20552387d25d3a7ade56ebb79441d50497b923651be1551c5eac20100e88492a54bbcf211861b0e41204c5336671b5123d2317e45489b45abc79fe55e0b5b9972d21f0199994d979e8111caf33ae07d13a15853f88aee26a0460522a3f9615954e35aa7a3d9fd064951b960a9a15914e2965286d56639043f5d4dd29a364dd73414d0643a9550dbdc940e351ede8c5bb304db3158c28dec2445cb016896227985d7588fb225afad8707771f0d78967d2eb09f6efe21c8c648cc8867914ce68e5590d396c74bfdfd20fe8aa53cffa8b14b3091d466139a97c82b6caefc0ff078818a18f8ec208c20c84fb214b2fae3a80d2ca189b181d6f2a9850b5d79920069086930a0298df90a71ab052d52fb2507164f3c1b7518c71fbaf4ed5e12d4dfdbee5b0199f4b7d0cf1e237352891439c9aab3852ddd268f52ce00464f03b6443aa40e4fef5838f2f5e90f3dc05d52d8a9e2d7d279615e5eb321260fd19105023763005ca06728d2bbb5620abdd05a5cf0cc8c0c24d8ff86d5ad0223b3b243bb50ca3fab25bcdc39760c04d8f2a0bf814f19c68119b5c8f0fdaa0bf7aa75274cfc30b1672c1810a7c42a0f9ecb7c8db58786ee6a34b91f792ae2f7a19085890aa653f182c844819aeb445b387341bfeb21129731307fafed2e5177b3664611e9b805e242207a2090498f8d3b41f7b4f03083e21dcb35713fc0759fa9ff6f67319c2f6377a7a95895e2fa699737cc390bf02d15be435e2ef4eb4678aec76e69264b880090eb241c04488c94ee9beaaa43e3f6c40d6a8d637a048477170818d598394c88540d07c155a3b1baed30fd878edf0828862e5dfc9147aebb178beaedc8e3919e2b33e5493cfb79f8c39267c8a8ed757a6bbdf93bd0d2ba6e643d076fe1fbb5746bdbe755cb2a665cdfad65fc150f7058cb38e7190095fa859f9d51abddc858cd2c86330b585d53f80d717af937454e00f735ecadfc0ceff89c2a0d9e196ce794d25e8d72a55f18bdde7fc8ce1943b08721bf63789929805d48a3ab52276c320006f6ac1e0db86b8703ba61986ee8950a2ed1be38a44defb2db55393de7aa1486a1e02cfacec5d1465a63007fffc92c5af01fab2c09451eee72fdea689806842475a2a518a982df3aa8fe691cab893add33330d7e8a17e1f3223a4b0c414303b7415d90fcad51693565eb4b3fe26812a25befeef5f5b73fbdfe182f12bd73c77061949c82517d30cc1e22a49dc6198c4211af38838ea5b622e5515568b297eb1eeb2639e09582b1a3704b2d636335d85e916e08a53b1f8f175155a098cc6330e6307c7466f8e790833be31ad2bda23d935b7fa5f68d74062a8f1a18c9fb7b0f80392ad1f78cb5b40f61a7220fb79caf4b80eee42b0f6c17df375e0b4fc9a7100af0c9c976cd33a37189c9ae39d853e4e9603537be8c69a6eeff1522f4238208c0beb20ff3d474a47196b0433ff0bbe60ec47e1157bda2b753de0dd8e0784761f146a80949dd0bbf526b87879ad9320635b3bd9df280018b3dc1c65f7c848dde78b2eb20e7981a9ae7ff7a91f2a8f5ba347680408afa6b659749bb26c9c48f72665d097445d2e7e4dff201c0ff010f48fdc207837713eea25af7f158f73eb610e53462024c2c9fbe75ccea90d13bc7f1e448c4b36cfdea86c11641f7e1922d00f2f9e1d4864c91d40607c97ac8e2d8031ebc7f5ba288f5e1337dfcfeaf0d3d5a12019c0fe4c76371811ca54069801aba595d32d7538ae73707f3612655ff26c88d4cb4d8831d5afc0833563d4ac2039d2ea97363434801717a8769013c11ac0ed6ae54b034d4eb059503c60106a7e21fc60c36b599fc90ef24603d84dafd0c4176e38c3ce392f7fc0060960cda47953c2990e57ae671ee8378368294ee13b3d59439897668c106385d9decae81d59278fad64d85ca62f08228ceecdb38bdb70f3f1197f809e9a9a30a6234447e6526f07bb7d535471cc348e7012623b308df1ac4816a19b529cc81bbba2c438872b0da2afca4d3496a304c56ad403a6070ffbad1d02dca4c3b05d90f54f1d82f20c09a1e05c7bb094bbe282e06ff6fb91bd5801229eaba3c1d71676d787b026f485785e9c17993d7ee3a27d53736e86c814a754cd144ffe2283c1359bdbb09422b45c6d29f592cb46da5285927d6546b4554da13cc65ee1fa22740161bdfedea00c7466b2643f0c3005eaa968856b49ad193fdd639bfa7d1e3674c91c92b9aac2bb01bb26b0a6225e6da9ee4f4ba6dd4d75d593ce761abf0998d6bd6cd2d9d54eaced69b7423d572862cb204970875912faaf2350f53e0a0d36e159c77a6f91603a4902b2519dd0d93b259571604dbf3d55765335dc752fc94b23599b08b050c2ae0b5448f0f97dba61425e89fe7d4f692c3e57d0838fca8777e9b514e9af1ea5b4e804608a616539000d469c7d6b33ae34f0f729c360f204f912944639c82ad312c4f31eedbfee0e00b7834297eed56e23388fe37b328d8ae927b4a8efe216611d8d97d8b835619f899c9581c2e427ec6915b2d2a4ebcfeeb0bfe9f9801f4c0275d10144548d8bd19c13e712d93349e3141c881a715d76259441ce4a2195ef70f99707f86991fe35b0a36561d9b11ca3fc497f68c613581ac83b8cdcc3dd9d1bc6eeffe13dddf0f6b95c135c8fbae10b46ba6fd8b91b427cbf79dce92b382b5142dc4469d28a65ec97e83913bea81ead74abf065ad254eb6d3bebeef60a89f5a25cf5d00bbd09ad583fdd17e7a6f186f8179df9d91919469b5c82e9045c8dcc59aca244253ace5f99963aa04ec1b91588041aa28566a89a220a3da54eeaeb5f889d87c1d75796bd00f5437b901c80da7cceefa3254802e8e2d62050984cf78fad896c8178049d84be4b4e1d6a1960795bec6df3e9be32b2c7ae6d80041627b398600d9eb6b7d3a25f718d40b5f18f5384d27782b4de90bc418b5c232b1614e4520b9fa6b47f5700806530b95a170921e1a53c4fdcba30f9aad59ac8b28710208d5860a529e1a1ae1208dac52ccc0dacdba22230d71b63b32c857fb1ebfe939d5fad572ae0828836a8d9fbfee7b880cd3a4278e5a3463b394849e731c6ddc8387ab43e443f6beac6971730dc49f700632d089cdc7e00deb0593caf0ec76d05df7b192f73f23184d42b4f7ecff851adc419d75c077eeac863014de8a58f9fb325ca546421fbad6c62aeebb8959f51e7a1ac9d29b9910ada085c85d5f1837e1b57ae24b4b93f5df9997cc73e04aa36d6a07e0d550ae270cdb3be37da01e4af63c3931343b912cb7debbabadb7b522d5541c335ef0a5d0c712d1e5d38de53f40df5585322467df7845f810c68c76dda9da9fb5a6b7d92fd5b00e9019dd88f5579c552ff95aa491df6dd2fc09cad9ee085f17ec652a4a385ee91732c0557620bde0b8b1a71d7e6103a8e90330d7f82aa9872d9202a630e76ae9c1737d1b658b124a124bb19e866afe9ccc25ee99b0e00a8214fc37ddd4600b27354bb58b332c9d6d78e690052955f4abb8cd7492714c59e1f1a848db44fc601834a812196c18189c36c1fa60299c464e1b246264be61436c4dbe08be8f782c1d1383b32b84e6fdcb922d348c2f6273c4c8ee0524989d1646388fabdbdc56fda910ed365a5cc8694d6bb314956ae4b39dbf999381cd7623de15b9becbede367f99c1db1d373769d30db38909b162e4339603e18e8fbb08d1b416463454ba419d9045a350749ce859abc5cfa94364b688a6939f88b325fb96301319cdaf405354b9cd62f8dd2c2fb9b90189a60bf9ab11f3108cdb9bf0fb5d7537f67aeead166028662ca07aac57fb86704e0d83217d64bd7fad12acf24dfecd197e25ac6bf9cbf0cc65c9bf148ec0cf7fbfd71dd6ab89358a7510a4f014879568fbc7aa6c6391c19f026879578348a59c7d35786fccac19f0bcc5a7d790080459e0b63d50606a551bce726cbcae2c01949aa3d35d47a5aa461d5301fd0b5069c03439c8304e5e76258283ffaa5b01f32505105f740db868ff561dbb0a45b2e2b72362250481d05083b10862da728fb926bb0b8ddc35de8cf87d4169562febd1a524e9b533ad75b41e59e1c8a7c1cba1c9fdcd16eada51cd5d86769b9073a9c442e7acff625a7dd10ade5c05fd17f1079c86334459d97ef4ba29007a5b4a64d804ce84b38bdcd8e02c61d1f793d50c60c7578cdcef582ae4dcca74625ab6eba6a2828937c2f9e6ea9a56ada503ae4d900b0d4ff84f7b01c51972891285f8676c659227ae3861b0efac63ca07668524c3264ca2d3ae502a0a342f60856bdc840d4a0d81f4018378b36c0cf7805f6b52405f25a29b75417622f25eff1ea2337f286acbae0bfe368d0c4580b941eb97328ad4623d743de60613f6cc48f248905479e7467abc63b1d0d232c3cbdd3cc0b05a7d93b49cb47e1bc20b05e4be2c807df9dcc11ce60e8f85c6d8b2cad1e9fd424b5e65078c778c41de4972bb1136dd8acd57fcc7f5f62d57585eb39d43d807705ddf6e0b25bbbf0ad35e417c713aaa90d1e75a3e9e411b583137f019b9453bf00d948ec7e9b88bf6e193e0dd3f8286bec8f32ef8ac2c8588858bab1c984295b7a44a0f43be0a3bdd44cca25f2c6e344304047e94ca94bef7d4567f71e1cf7660284223276374c01ac173b543217e095f77ed05cacff9b88752b540c300f6ab1612f8c8009e470f8e2b7f3853244fe9342640b5705949f58279d57d5a41e2b73ed2942981cbd13e6aaedcb0cb56dfdac427700bfabe36698f757af72b8ad9ba5a25eed143c1bfddaf0f0a1ad613d3857212e6a152a0bd13934a7f9fd567a5230516468f2deb78fac82a90909ce81073f2ec935291c3f09b3279609283f490fc758819e09d92de5f3ebce545a35d564e576f67f45158da1d4646f8701bca2063db25cb02a087817da464a2a48102e3877e02aeea535fd4da1651a1dd565618dbda9c8de4c4fd77c41818a9050688b2578ccfd1b4e23c17de61ac40ed2d61167afcbae548a807fb67c010eb26b9fbb4ce3791f228e70e06b48e8bb44086dc5f4072352bdcd1456582f206bb3c078d09787ab047ef547eb688f07e30c7dc30870156bbe07a2cb6f716758274632606f0089d4ecf3d73658cb392a0528a80f19779e538d600323ecab97a0e33e9a25d1817902306e131759c315b6857453287c0c46930b4e80f0a7fe4ee082359b21a222a1bc1d4566762e9dec8f5dae24eec8ce4ae9b51d492a20e4f923aeec1b74660d4b5afa370eeadd288e63943c6c25806f60a77137546ffba9091b0ccaf2093b6ea353abbb5cd03c56ca06b08a4743232cebe01817d8f75aba377972b0c7386814b35c940b5b1243e75dbe67d8f434ec204223092f4630adc1ebce4f276c2604c0b9785106138d63df3fe69681d790d1a054d1c18d4ecc2583cf7fcb087d5311404e5a8a51613f932174ff93e1bce5580b80abc9a025281091d46340a90c63a0ae926344f531487a6dcd78a6df4dd7fb8b419a6c9d2ca3031aa8c28b5d30ccba9a0ec5922617dcc1ebb501475a21a6bc70491b98de1303dedf668a235f05dc25451a34654439ef38be72d3c3d1e6cea9a2f3a7aa3040a48afb45665745254483e64dd3bf0f21a021ef8af767beef6fd2dade7b6fb9b794324919670867084508159ce241391f8a15cce82573d99e4721215b0e69f32116492f872d7b82b1e7130e23ec1d8a6c5761cfa71cc4d0c721fdf555917376396f38e47c05a91b08220404bba6b0ebcd3b8edbf88d0d39a72b67a753994e4d3913131393eaad16325f2b538dd5e9baf47495313131c9549ccd76739bdf820809827f88030df156557df97d9021df97f3f6e921425c3349fa97ced70f5299aa4e22e71f80ccd720383f3ecda87134b665dbbfdb6c1accd7f82017e69036af43dedc5811799099f7b75a8c968b5aa53a3950c5189732ba36d197ffcca9413a362f833ada88be74727490ea2269527551261a5d8e32bac4b54a91677454ce5fd6589783973dc3ecf944a508ce133991d3245a8489ced3292f60a638207b782bcc2115e044b3ba847e7e5aadff71ccb97e2ee70d290781726f8abb6a1512fa11125acaf4b9a319cf01e3e75a2232d7653ae21163cc43a61b7f0d32027feaefbcc7737e9f66e1b0ff8d7bead2e777d8b1483211bfc683c4af9f45b2c75d78f44e63f14642f0e78526267470ba56561a0511b267ed7ee62df339dd6920d3b6e72cf2965bcd04ffc45fe441d8b1952157ad80f1ea3ce6398e35dc98c70935720005f53eb814972e5251f2a42f4f33c98125792b47d3189d51fd64cf9f547bcbee40d2d122cd9921cb38214f5697e9aa22fe39ef794e0aeef0f01dcd2ae2f99de7016f686e6e6e685c2c0ae1b5f3532ce2f91d6dc4d22c9adf791e2328453ccf7a239da74639cfa3270d196408c9d344a6bb88e76368232834cf13e38f5e34ba88f53bbfa3ffe8455af03b3f027ded3c110bf45797b3a6ce4011eb6368a30de60b5797ebdc6258f05acfea22f5cfbfe6d14444a014fdf3b09ec86b9e8fa17d54d78e26b2f33c12d8d19345b2a69e3734f3e666ded0cc247b3e157948223188fc5bc062c578124a510ccda32d2089b0b4479f8764d17c8c9faf1d9245a3591aec3ceb79f07c0ccdd2af2745f67cfa379466521a1a4a3b3a6f665ee88d66d2190d79c81d92488c67e9fcce4b20e7799ec863901a5717cdb348223abfa369e88d2e799e88cec77831e7795e7422a6b5e753932e36bdd5a0185fb67462b030d68941d2a51f37dd79fa19c88393a44b3436714c2239cffa1d92f544747ee7a994148ed40d95da8941ea3c0f99f3536469a0f33bcf43e777348f9c67fda4d134a665c89c8369ce5325a7b11c927271973f5905cce2d0db796fb5bc2585e3230da494c65458d08fd14af3294c1b3594066b01be699ea563ee3987687e262fd190b5c8f4a15f436dd414260dfa744697350434d3a7359cc77ffab331975c75d618095c69a8a555afb5d65a6bad4cc250e7ea129fc5037cf1411edf8f19c4efb94ed0ddedc67a02196f501a9235dc55b1cba02293d60aa91a214170e74136220265e6dd841944542f3083beba6acab905de4e65a02eac204e2f5e359ab56386e6c397919973cefcf44b9a65e67c99cf794e994c43ffc7ff0f22c4c8c78cd498a5b254760e09aa770c31761e78cf3d11d5ab5eb45b728e4934876ab63f03e690b7c73999f0a5cd73439e7bbe549ab5237c9f2a529470c4fc11e44021777b4fc1a713739cc8fd383a753a6e6f15f520f248407ec99c95166a6cde62e17f244b0310d4b3ba42fdbdf72c1edf7bffe9210ca82ec7f97ecfe25ef5472f4fb32e0f56f7e37bd5177dafc29d2e12fffb4f1b893a08a82f77b923a77dc31d44e5ac95dcd37d1fecc8f287d57d24abd33c42cdc21f3eab7bf18f5e1e8b8766618d9fd5e9a2f0456d04a57ba30ed447af8f7ef0b3af2e77f4e81de09da20ed6dcf66a16fd72d6e8d482fecfa169abd17e708cb9734f054a5d8f53e720f27c23a55b7da54c1f865cce5a8f1e07b0f9b2c70e4bb78dced555675ceefb9cc39f9a6c2197bf417f7fa10c727e19199907694d4d4d4dcd1fed1a7286863cdaf4ee194d004a23d778aba7ccf8f14f31973d1867f0bd05eaef896a06d2336d8fbbfcfd26230579bed338e7654ed81caa2d6ff5a81c9e400298600c24597cd5ff84b5a6227790020075eba706f9f8eabcfdfcfcd4e3fc580522c6d179297871dc79a794cd49085b4af0e18a06e8a65fedfb73d0cd2f69be317dfc9843d5fd68535dd20c4c1acd8714752a66d55bf365a871a0f11de87bef6b70e06e0f480edc8d835f4562ee31891f879c791539f3204896cf7a500764913a640e39a74b66becdd3901eccb77970d2d8d0d0d0dc7d43f33536244d8d98f34a8be2ab4abcc3f99ffe911cc99ed68c1a42b46cab8c29b91cc739c739de382e019c3f7b621ea3b573a649ce9ded4fbb4c707eaffb3c4f5928b6dd976ad26cc81cf222ef3feff1732c0dc0ff5e02a09680a785b86f85dce99f96c692e7972d1c5626cb0586a6249854d75a16955cfefc30115fd4f993a2b69ad0aa7c9a55b40d0ed9355c7df82a92a5c1eac3950e593c444a021977ad1f8c1bd4e58e0d64dc5de7e9ec2debdb3748c351fcbeea12c8b824cf5de6397acbdb75531aa30375da03efe9db0781fcd8ded34969800f9640c6fd7df71fdda08f93d2a8ef7df7def4967f4c545fe341aaef6ab8cbe61a845ff6c7834106152239bd14402e5d6c5ba06a332c539c644f9230c59468d294182f37292e5136da6ccf396d92284e2f66d25470d3443c6923793e408a0c14e61bc9656b0aa1e5219583214186ccdb10212121a1214184dc820819626b90213ecac965bb73e9600a5187c900ce9eee098b11d410eae004f9870f4c6f4a18e7dc026343cd98261f64c4f063e70e358c7bbed39eb40c310224ea8fa48f15b9be9d35deca795e1921c8f4e73741f10ceafe665fe5eaa2df91a3eb31d32c3cc9db3be77c3badb5f6ae6ec77d3727be42ba7d6fc79153dc2f338932c05bb5ce5ae7acf34e3be79c13055b6bcdd95b638db7eaf8f3738d07e15725725d9b75d639c588961662a081d6724d87f1e8f3bb3927ee640c81a95bd1b39221b79eb4e2c7176cc894882cc3c8c4fe018de145a64bb116688c2679e09772d9836589d326632b4c1a2cd86c537559186c069b59d8ccc26616366b22d3a99bb764907053ed404377bd12b99cb01ed56dfb615b9876a5f6a9f745f7056e194d7269c19e2419e791abd5a095e6a654535c4d9ce26ae11457fba6b8da9411d989da2e51b9be6572a0259b85b1a5551f32dd5cbc55bb484d9fca79315dd56a6e0a964beb54dbdcd4ae5c6d3b3950978a85ab511bb689d2a8514c1b1d501af5837e385057a5e610f7775251a718b7e428efc2843113a5b3aa5845f705fedc4cc06d39240e26666afad8bc55bf036ae37a3169d4af5bdc755740c5ae17cce865d7e7b22b4db25daaab3ebdddacd3cd3addacd3cd3add5ce64cd68969774c9cf8476fad2e52a95e0cc53ff2de282c0a8f9ea8c2c96892cb7a67170bd4add52099b7b65ddf3a554bab41aa9fd9da76a95b0dfabeb6987e698ce524298c731ec77f0ec95bb5e438981279979cffd1e66033651e3919b5b134673427cb7a756ddcb57132991179cee6d75dd65b9d554e565df53137e33e094e46c1e92d3b9bb1e8ab9e65ad18beea45ad7a2222c521cbfb30b47615eaf9b29a45f59c3ef44b9f85abaff9c51aab41add68f63ceadd6ff38ca623333dae803afef3fbae5ce2e964b232f945f6bcba49591d689b4b4a66d6dbd55579daa4cada58f8d49bb3e0ce39cc7f16b9d7948642a65f3960c156c5cadf39514f58605164eb3d96c369b952e639a61ecb719bdcde8cd6b22d74a4295aa37f0e7f392e99e52f5bb881b8cb01a3366cc181ef665b5d1075eb53e91db29de72a95d7acd69d5e518e73c8e4bbee42191ad936df296bf0c156c939d551a387b26b561bf14aa957e65a25f659b665b6bd3a60f54ad2e511a54575d0a3975ea692157cfa272d6d65a39ae723adb8c33ce18678ec6808ceb679cbdf5b80616ca00d32c0d6f418328eae1ada794524a73b05f605c6606549c39cb71d776ff5383ba9f5151c85f98c277b2eb2182a00782df78f366f8148681873bfa8f45b6df3d7d20de83e39ceb541ffe286c485211a50e7e08f93c1c9233dcf579b88b6cfd430e7c70e01fd698607ad8aebbbb5f5b0f9bb5e500ce1e5b6f489caf64f717e4549d4af5e148a9be8eeb4221e28d215ef27df1c3f70fe242fcc12eab9e95f3ea698c6e0cb627f1f126c47f08927f5ea998e03ce87ddd6c776fb5c01dfcea5578ab5ea5cb957ebd77e28dcee66b74996b3eab9e136fa85636dd156f745e87f3385ff3e5940b7a5651ceeb60b104ccec959375f6911cc9eff90d828f7d71c89f19def2bf194c1f7f2297e55b3b20eef27a83780b4847d627aa371e791dd7dae5c774f95b5bf30c360fda58a82120f84bb9fb297aff1b74a321b025d9932948494aa0f55fcadc7758b2f7436ebee36ede717e14ed88f3f6e7fc71fb569348320e79430e7120f0e983460e3491863890ccd33772a0fcf4296cf5d4ea00bfe671805fa3774de99f679ee68866c65b2b585efd78ab355d572586de83159c02998c86d050197d42a750249a4495c0ea59b0bdcf14e73c8e38eff842c89e0d91db904614667443da10551b4cf66c8e9c1a3284088aef518daf9cc0492bb520644a0477bb373724ce0be15485c1781b57c8be3343e2663dd7e49d913aab1625a34dac69a9537aef0d0a83cb65655df5bfbdb07bcaaa7f854f5f2b4bf3d5caeb05b32390ea8bfeca3aad766ddf03b5c5813820de739ef5dccee37c0f9d1f9fc82f4b039ccf791ee3b334119d1f3f47138152a4f3a376223b8fa367d5e58ebd7a276985cda119384f593c5fe218ef896f693528869ea00ec9b279d61fbd7648968d6669b0f3395fb4f3396f63a38b749ea58d705ee78dc6dff9a3978d4c4d6263e3394c55a66b4f4a28bd0c8dcd8ddd25072a2f9102aed24d427fd6d97c5961369a01f4d26a9095c9b0954d1ffa443e3ece4f7107d2f8384f6b8ca624b0d826270762fdd4a035879f0c84223082e390d7e62f17072aadcc81eca67fa11c683e1d9164d3bf3507cae9726f5436fd3b75c5781012387b3ac2894d9f43f2200b6637ca81e653d4d4a67f6d35887bd1a7b1b19c549303952ec6c9814abb64e640e58dd1689c9403b176143d7120aeb669cd61534e0b962807e28ad8f471988ca903eaf6bf4b3568d4383fab0b07e779d02f548680e16818cee3e80fb09e48901fb50f0dc57ece8f5f4e2928464a694eb39ae7894c7ffc9c37c27919231aab2efaf9f3e3905df2ac2e1afd95ca1c9279fa76c981689efe172b6f2c77311b2edea22fc5066fac065d8cc7f1ffc67c767963565f30a60fd78593f2168da64f38313b2b12c86772c76d2ca7ef359ce791f3e3f3c0799636ba800c45886961d444a014e16896e76896eb1d398ff3b24f72c891ac49d5451f87f4c0c8b6c9ca2a8c3e7943f6a79756832617382449a18b2d7ca952993e14ca8322df9a7e21e72faf8d78634647fed5e3c8bffaa36d146e9ab7214bba6d7e454e9fa2dbd4c8bc2569c8b267cb4cd7add9ba4f9f1317d0da20186dd583dd8ab55a55195285d5a4ca549ba6d42ab5484db2b2dea9de82adda5161d5b54556ddfc7d7b4356a4ebb72679ab223d0e79539d36fd90bc01c91268979706e4d1c7974683705d6115e6f75eec15565dd32515c67947362e002720931927f1cf880f6230dea6cc271bc46cfbf84bbaa452894856eae9862a9b520c367dea54836848e0cd061836c5917a9a12934da1af12718c2fd972308740a03bffe775b853ad38ac9736fe6d2d7e2297799aa791c9e48aecd103f45820f87d0ffa3528cda6bfc34707f48178902a03fa440da00f7e5ec5f11b8421db3e91ab2cd8f38efe434bb69a49d2bf66de897c86ac71ab500d2b43de0c6a58fde32d2a02ede77afda9d57fc22f403c5b38f006c1687b886badb5d65a23300218a72a3e052cc24c728f1d38640ce8272b70a9a21e357aece851eb9173ce3d7614d57614f5b876470f216fd11d0ed48383a639a3d4a9d42541869111b8121a62d304304c774ab3830e5ee825a4160cc8c129a54e67b0369b0d2ac80bb974a6ed4c381f26a4b0810a909cb0c194131352174b4b92a49e9cb04198272b389cb04117b35188bbe7930964bbcc2f83821fff01402dcfecf954430e4872def3a9862700ec90ed9e4f3530d16252c30930b89271f67caa610a0cb8c8377b3ed5f005064932b7e753939809983e882376d9da4118f1f3d4e4896df77c0a22cb2effc72211c2fe8d6e416f357e684de6533f326a432693c96432994c269b426cfb348a6ec102de2aeab8dc17725c48e61a2e871c076ad61742d1eebd31bac51cba975cedcff3eea55b68b227f7094b8a9555d9cf8fec3ec634aaa3356a1b41d4dfafb26bf316a63525b9fcd9f6e7caa2b2f7fe6595714f3c8846d9264ed31ad6b449466bd40ba5516b5fac179096a907f8c1efc41cf8efddab2c32f7fed88696cb9ffd8910d0811ffc4f977401f8131d007e1962f2febda4ebf89e7b1c9fd6e57d0ed08d3f141fff10f086d8032f28d6f01f070aeb1377d9fd5383ec4bacb24f844c65a0906f8da38597546dcfd21a9555998ccb94d04daac3b4265bf27e6e8cb36c2cab7d8c7f7e644b41e66d6aea66696dde682d28e7f5bd87dfc3182fc59498c61d5a1bdf5bf6b7a53177d55fc232d90f77d5bfe1f903ab3f4e5e1559a65ee89615d4cae742d16899e63d7eec698ae57b0c7edf7bdf73ef69968efd7d9a45e49f8f92ec3dfe3cefaff7f83d7ddfbb98c5d95a17f97e496b58bc55033ffa6546a35e6acd05067df095a0bbdc4235c87b8abb77a1246a63ca31c65dcedc385eed49d3870a2565406dcca7424d55897d1afad21cca40d51cc7dd0feac05df62decde3fda97e671a636a6aeb6193d6748dc7f1f57bf7a5939be520412fc05e5fe07f7ce9996dabea44f92cc913c4f644ee7b195efbd77ca5bd6ae7e7a6f6b49dd9747ae7e5457fd624e306bbdc7d883e9a0df7d9df2d6b4b86e6135551bfeb2da7c78ec8703d9c718df171f3f381590c59fa28efb62102bd47c78cb86399bb6e9be242bc7fdeeaf76240c2359de6dbc7b64c873a685a9fe7b5f6dd8615ee891d5b38fbfa55c4e29cf61db83d5a095d6512191579fdfbfac369b03ddb78e64ab5230aca914b539aca43fdcc81ca298f3481c7acb72da6132b070da5e68f394a907f7bfefc41cf7f183dfd1ac412b30c4a2f844fe7da28ec9e56e100c6d9e72a981a3fdbd0881fbf8a9a8e33ed6e2026e0e6ecbbca72120fef7a07843f51e693748c57b498f043db2a45946836086035446fc4b8a1f79ffc7c6ef91e5b83d2aaab4e7912009641499e417c9efc03359b7b8cb3ede3e6a107e85d5e642f6245d4596b97924b8b915595f1ea9da5ecbc95671b54d1ffb9f44c67fdf6e9b44436de88420b5648bcd1f35e847a806e159fe1ab3dfb5843cfbfd2f91ab6ddb47807d960eeef1c330fe74b5551bd374d9c738e7d1be85652772e96050cecb3e2659dfe3cb912cee3bf10698b3bdc061298b124eb25011c5cbcea72a4fb6ad71e40f3773577d1aae65dbe8f597dc559f09cb72d3e8447ad9f57b68c81ea334be8d1d40c5ecea91de86c1e61006495ec4811c68d33fda251583e9944c88c3ede202e866e5c07fff6a0a06a4625e3dd645f9655e461be53f7aad7e54d74c4bd39ee20d16d644afd5e7bf1ac80cf3020a609b95c36efc7663cdd241a996dabe02fb2939932b301e2b8703e87b9a95833bdaa0b8017dfdd08dddc8f4194012d89edebada6394467d0b033d00571ce6489e54679ee4451ce6b0fb778b035d2ae5405cbcd6a25d5a752ad77f3a356d2dda6ad1a9d61cb25ce89649a5f6dc6293e026f0290d0acbcd974c706ebeefb857fdd7618efbef31c73ddd9c7deebf27a737ad0762fc16bff79da8c33ed656b3ec7bbf7aef891c7b7777f0c3813e6ff5f777d4a05c5d36e5b4edfb7bda68511a57e61be040f9ef9713887dff670ef9ecfb42431910cda1f0a7456dcca8d1337cd34c99e11bffcccbc8e819a51fa6192b34cd4aa1cdc29739343708923e4a72f8f8c507c3f0c110fc50b374ec30fc4007a859e0afb417053e7e9508be07fe07824f37087a9e66853f37793189c36421fde3adabbbc8dc7f24ad79ab7b16dd5ed73dc61df54269d06f927151497775e8fa56037463fae007a0d8179f7b20d6f34992bd0faa4f926c27deb9e3c8f34466d9b7f9a317cedb7c11cedb682328f68d6c6eb4d1cd8fac1cb583a37df7557220d5dff1ef5359cddf2f2993cd25aa2e990761dae821c481c4eeef1b7d39b9d818ecfb3fe690b53113640e797f7f86f418a5e1e37ed09c5b5cc5c53dd277d7819c7843fc2b36e0886e8fa43ba434fa3e6a1c94f4874d5f6a5fbf403cb12f9d4d1fea4630893fe78f5e2c5c84f339361ae7b12e1a6ff4f8472f1cfd63247fd8903e4a32cf13f95fadeabadd83fa4afefbde5ba129b92626eae0bec43177900f381fdeb24fa5541e328194feec1e634d044a91c703130175d6ef1d49ceeab2d406f63ecffbc00982a27e0f5561a87aac33febe7b173ff171f7de73f841a29f5951f75e0b3f58ce19f73d66e9a2efb1ce2208740c8bfbf74816a73350e4fde769efe70b7b9df6e93345d007d0079606dd7bcff2c7f8e3f19e03651d8a1070cdcae16fdf6e513adaac1d451cf4b01ab841a78f156ff8f4b15fc5397dacb621fd942c9313cda93ab5e122581da6ab5aa71ea65c72b53974041735c5944b677272a6ebe4f489495cc935683aae39bcb7de516881426f81d3a77ed9ed59bfbc78bbb73440434f674b52f04aee3607e806627549b707f641a863c64c4ac3f334b65ef747bbd3737bdace21ea85d38ec95032379dd2b0356ec67536fc219716466f30ff0a951f67cd894bf7062edddb126c093687a610484df5a32a54857258ccdf22b92d525d04a424d8f4a9e1835f86f75683426d911cd4585bd86d5b98087259a796a6e6d017d446ddc22d714b4a21207912ae23389dd93974c31e11e492dee88dda006361b0593dfc341310cc5d7299bc75932c29792b367d02fe2ab29b2ddffe73d2f007a56a10385dfe17cc8266fbe3f8dd89053092bbf7bfa26692f42f03fcfd02a0904b260678efbda73a039656010510720e4a5597006c752a80ab0a352b87dde1db1dea92c89ef2d6fd21d2c5b8ebfee7449dbc75df0024ade2aefbb8bbe0ad063d2875bf8252fbeeaa2b92b7eed7f70fc37a54c369094b407f70b5e78d1a5bcc9e9e16a5e0ea468d2db2f59608d62099caa4b6cba0613a08e298f3fd0390867bcea8135c89392ed8ab8a63ce39e7cc60cf05503de7a474ce39ab1017b470410b75bb2e8d4400674f896f168c07e125eef2b762ac1824a4224536bd4a5769d3db2eeb33b164cf2b7b3ed9a43678410bb509492e31d4f6c7500e549b1c33d5251f6e870ab515e32d5f926d937bc923b67a1e554a4df8be7e5fbfafa0934cbf76b5ab5df7714fff821af205dfbbaeebba0f042b58a93bfeeebdeefbeec16f00bb7bf0ebc00ffcbefff48c06e85abf0026f4743c20d9b2c17724501b7c47e26583efcf3de824d39f18e76c671096c9d9b30024e4fb17d490edf7e0b76a1087f3c61bfc48b2bcdec23fb14c8fb7bee79eee398740a0377fd101fee0ddf4afce7101cde10f3e48410a6a0ed00dea06685b0013aaeee1ee131c0c91448230823852041058182145f45b1533850eb31d5e68f2058a2ec9085937ed0e6f29ed700205296870d2430f598410a22b2106ef488f274640a2c5114d767842c2b64f63bac0965841142f4628cd89050c2b4788e08624685c3a101851041fb1e285d203591246872637dca0e48a0ea966457ea56cff61c8fe5697970b058630010f5d58a01dd1a41ba126e5dd0bc05050124b0285a8147422d46c58cbec06a428aec49a88a10ba196053c62830d2928a288305844d0a183d576a0a1476a0f15a69890984a32c6c68da94de198e4a815ac0842052b5d48490aa31685b3b956259a8070fbe2851794623a7814b518564990a00b1451b4c46ee0c0f0e891da0bb7c9044249102980e1e94b1556c4d490d85a922a27a93e4e8044851121d030821b56501be132a9553bc50aaec4906a21c4f0851630d65afb46f28eb1ba8ce45aa9d0ca83521213145844b0a289175abe702e7b1b8a5411831329a418a946b4508195b4446103432e47ccc930048e0d159640291155c44a186e4acbecbb4942a0a549971f6eb089208c161cbe7b24532d33d0e4249e444b0ba1529416116c8ae06265e566518497ceb3057ab86551c11547c2e8418a1364594060c20aa618020bd74511537858977e6b0a9e84cd051b0951bc38c20ba78222b6747ea4c90b51b531379cb083162338304520e1719574627b62427241072e382e94ace005081f76f832858a6fe96e96215172052d0460a2102326054530e52bf32506206e43d41053b205e74b59e856d17a1223c4174d285061845b1125a86ef55202272a2588218c089c1663b02b390b3cf4c0c50909214449ca62e64802bef80085890995159c705fa400b9903282929426b65ca14316599210a960295964b952801e9414e1f4830a9880e15464a1225ac942823c44eb10173c48d990c20f27c8e2258b920c9309446df1c4c6b43404150e6a0c9e4018148288d5848872e3ae80020372d34a1434ae64950081ec3df244834c0aa72b2a4ca9370c111ea1800e26e410a50a132454b1026aca4a890424a258c941845b9410705da0986aee110a85e403b27e641a51220cd314314f5e64a9022ac67147fede7baf9523271494e0e10729da123a380aa0eebd7763d764cdf4f1b7b73c87ae8bf92c3f846003942861603b7054101106c621635cab942423584871e10a264b8480438117d78fd401200166892c4e8cc0040e5c88d862ccd3c7c6841a5875a18b2b218922060726aaf8a2045db829a0f08e14e96207134819610a14332998e8c00c332c524ed084165d4411757d3a81029715580821ea85239c1411b4d06a21e20a771d8718931980b08202a530382888a8c2390d242c9488e24452d416dc13449400ac4cb630c97828e10712e08965b6f260d10483ad8a2a49ccc09d40866dddda975f212289c68a063688a0092648c022b6026e0b11307ca9fb8c0bf188148d5b6a654631d101d97be413620431b0c005942c60a858640939772b26e894acb5d6e71347381183a2e9052a489c280178a402575491c2298523312e4d2c11876841c458487001092e464040e3981822d6b9d2bdf37ebe3fdeff5b45b02f09dfbdf7823268c073885e24c0ccb09e5c266b7d66a1457d7757cade840acfe7e47499afb676de5c75b02a7cc102172938114105596c4fe0287984791de167937a6489ceda24e53273bf4302b660e2842b5d84601ab344ad6b22e2e7a8290c122eac70c10a09342580105725c83e5f2da8d5cc5aa11a84adb5b26de8c49624820f25f060c5cb72496cfbd4c3b65fc381eeb6ba0432330bb9c4e37629e0cc1864e1436b86002c11802f0090426b842727d70bd99312002926188491710c00a892710b4764156a7882b9a2a4208a36050094c8aa3d9f68494cd17ab8e04bb6d9f38956c3055eb2b7e7138d89b62484ecaab0f29f3dd9b7df696387d2a0efd5bebfbfcf397d7be9e307d874cef93bd4460694067d9ae9fc0ce8d379c3891c4fdd8e727eabb575fe4cbc13a3d571f7bd960e28dee8eecd1cd97117efe018db6d0f95ecf70904573dac7a08c1cfc3d539bfe00ff7feb8add53bceddbde3bcd65abdd66a2bb5ee6ea79d6228aa9c521a1c9deeee95d269c15a6badd6ef9c40f54bbc7184506a963cdddd67786b3e56d27577da8eebf0c59ef5be0a86d37edf773f50bc4f2c8ded8fc505d8aa050c7113f3fbf9de5d3a5b5dc6a1f50f745eede52e77b9ce76b8ce983fc36e5a71f8f8b10801bb3d2ff41e04c3190ee4aeba4419e41aa48090da30402b4a559d70b57abb7aa562ae4106982e7f4fa62b69585d6b9986331ca8c39d9d1ef550208e16dfde67163fa420b3fdc71f9670cec7ec72e5cb9e60268df98c12c1fd73eab4e79411255d3869f20313a957d41662d3a84d8308c116df3a90d0161f146f882a104cdae18be2e73065faa26a47fc4fbcb152893a0376871ac89cdaa01e91f87e9635fbbb32667fdf13104aec0f0b94fd3d166f7ce3f6be136f7806c0f80a958da5367e4ebc8127d00092c00cf083086a96d96c5b5cf36dafa8b7432b0a12c25851e40606edd2d0848f4000c60e2e3c4d75310b02091fb6503a6bcab3f594a504b1fbc41bdd986d1f639ff2230863892b6ea0e104501c314495afc3d16996945cfeb7ae053b3ac4b6fd6c9f7c90b22dce6073dce7a80d04051412dca0786284941767c4e6fec781b8afc1bd02e6e68e0ccddd75dba78722db5a2156d7ca0c3be9e8e704166d267c2a98855114f1ba9802b338018371fac29410ab12c6065cdc02a103a8942df6553d0b11d90800000023150000201008054462a160349846caae7614000c7f9e487c54968ac324c861148490310410420801000000034668688a036d8f710c200871e6e8a3c2fd99197feb07902cce524cafefd92f2272bcd65401e29fd44a851cbb690287d35105a34ced90c269de87d3e0be909d91bb5fa76f679e3117fbba73089e70420eb9c6e748c104ff861eb8ca2b4f51f3746c329ef600837f76a8b554fa6763110b7f4471eb75b4a8843c73b2372d6fdd865942867896a2d7345abc89abcce20d52a29b6128bcd81db8c86442338ec234cbcb83b6365398fedf854fbe56c2e36f1919cbee65ed49651a84b2d2021950d80245c84933fb059f494e33b854c2b17733857119ffdc11fbc0a82805171c16ef79e67f9e508bcab21dab9bd39fdd34e89117ceffcda36a55d60a51af47ead2570ff91d6970548457d049f538d49fe984f55a7448217630bbba23ee863dafa605f916929aa8c9556831477fd2d67fdf87a78a645e24d71f83fecb1ac1c4fba479b8a441b2ac63d25686ba86877030a0368225201cc865e5de05230a1a5068326f85ae1db86da83a1b84dd5ac66478224ce7c46b31354232fc493dd4a20283fbc2611d6b827ceac5992aaec1f014a6f3c4fac1a279c44aa76864b811808fe53ba7669060cb5a591fdaa5d1593f25a4afaa50e077acc90d1386c54e71e81d4c865a2e3e2766196e6a177c2e6d2aaf5f70402d7349561510db41f2151cf10e2a10b00f33e25c212184dd76d121bf4b8884e12590f16df0aefe8a6304f006d9693b9f6a73f5e80ae38a013717e144eefb77d3705dc29d984dc27a6cec0ee48796056bfceaedec36043ca5fb045d17d472061b98c4feb21138944c98a089c2cbababfa11c4827a16999e6a3b28b1b1342e0f87680392c503abef768825b451e818765757622b81ab5e217f49e4da8db92182f14121fd66bca5ac8726f3ef89b8b271097bb930e24d9eef729921c195378342661f36e92d849eecd130e7c7bc327653beaeae6f6845db752730f65a72a78fc49768ce0112f6225a100578128f489e79d1885b9f7bb00c1b0dd565cc633936e97440197f426c243ffb76c482e9826d733c0e3646f34fc6c67222cd93bfca368aac23def846c5728ec3b129774bec3e2e4d0b649c49368dda9644eb1b9b48bab135c1de477c18ee7221620335ab8a53350ca6867735764d98a5c238056f043fb133de1817074fa4834fa1297161212ad602aa122bd622b67531cce05f4db869de9249d103eff160a216b67be296351a73c72c2a1db5fd7291fd89b5a4b3db780b28a22dd354c8dd48c5db792cd964413b400e6d521bedb08fa8aaa006b988ed2eeb0ce3d13c48f88270cdf57794d4a4a5b0d35288332432c4e6de9dd37e9323f52637ea01d43b4b4eb213b224211288d915d5192c82341d15eb23c94591665a3b6007d41f901e3af918fd4be2e548e833b5c30ab5d456b8b90d58a1b11e01e170cbf870024d1e774975734acc1670c4f50496653161b7488c5c799244005f420b4e0585e7466a0e51aa980f59e468eb3f42eb36006b50aa93726482f5569b95312cd5489087d340e3b00d339839f8f88fdad053e7ea13d8c9031b388dc5256f34874541a37b04672d2944331b4eb190e0f665ffe24aba897b774ab1170dd37eb49c12b83ebee61887d905bca2fee42a7b5dd869d9725bc5f8cb96d3af5258c4e73e9759806f80bfeb254a4e61cac8551876fba88335ab9cac5c2ff0bf3d0910cb132763f313fe432b2d06c76b958cc9398e9a4694c911cb32c6168567e2874c415115d534da8e3d836bf9cfd92f7521fbe09297a3dea4465612352a76cbabc51d4e78925eda8a98a86291416b539ad401209a7864744a5a3013003c65e2ff738b6528d7b8c404ff0637ab0bb45f3b8a9e4cc9f0593981256370007c416025a8ca3f3a329754d015ea4ddc946922488b0ad28efa94a8f453a8f6657241b86640952350a862d412d01c35369833306f0889643f44a46a468659483a5d84ef7f2aa297eb72a8aa46c5f7b63215e395ed2948e3d05cd5e3f2a5ef6bc28208d2186b29fe9fd4dc77494f40476dfa33314401025e02da5111fe31baf7155acc08219680ddb1a54409f1b2510cc6ee9d202e3322841bf706824106fd43652eb3dcb47c204d3ec8b905d7b1b2f2031b13439eb7f887acf40d21a70fb149fa59c93cdf295a897643186806b32be00f7cf31ce2bc369c9d4f35356bb187f51c289e4b6474b5e2062c6114f8d95e69919c89b352f09514d282bc828404c2ca8e753cc7b705dc7b2471c693b62e9420a6b981402c1aba62eaf8b115d1f53d468bfafb6d517d1d9d6a2501e571d509a3eff881e11de5b7463775a0002d7093b55b24ca71acdc3be4b8f474a6fa64bd24b98a5aaf99027aec3e0ef6c4b7833c81ab30b7edea79ecc071c2ea37038870a228971b9311b9ea2ee7910f26f5bcf29655e4b85e89031b5f81381fb279dcaf80242a0bee71db5506125d5285062f242725ef1e2c30c78abdd8e7ee8b2d374a91e0243d59c7acd54f46d2be44c0b7b27cdf1ac684158ab40c58e6df6a2a3ead8469e3163be4178ecfbb53a6a43b7a4c895246d9109f0e0e58dbb7e596217ab5804742e86c292728964f7de04dacde186db7f09d2522751f7e021596fb0d4f8da8e5df75449f170178618fb34b60a24c43586d6217183e275d9325f509aa248e94c9cdfd6c1c2bd2cd3ed692ff0da7f923146fdb2b39ed7a835aa9d174a672adec0d8936cd7222935e0cf19db4465f0c99efc30418fe5b15f8eaee5f9021154af5e8e330ee0c2983fb1c0d811c7a2bf6f744ba0d54b9108a13630dac02bab1af867a87a5d53402da985c12b9dc7c25b8eb96024a864b3988bd2f87b917d19737f8f2a2ef98a492d7085fcb34a90e9e09657061d901522b85e4c391ed0c8f083c7774841bf96ef6b9fbd4aa248e42c3b4cc206d5d55040124989029dfa364c8432141044e462f9f74329e06031bc263f792c4d88203bb0841ddbe2c6815fe09d01c2ddc6de133771c4a536bb97abc1efe29c7b970dbeb30e7e6d6a9d2a88b8419afa7c9d33be8092e32fbe897cb11a2308360a465724d24b35cb3e7cc167193fd0383b9144214092eb5964e8ab220d5c4385d6a15620befc840c3f1b6035aba29d32d11e33a14a7dff61bb931429c3931f29a994b444999a4e25a0114ae58f5e406f947acf1e494796846c1c816dda64d6729874de08856120e43a2db6120af832ead6bc970323e358fa5358b5cd50e8f194f9e7af149fa7be620ed466a74607c66621292f0adfe88aa038abad0086538bc9038ac66c41fd1fa31be8901988b219a5bbe18615a36fd6940097221161d7a7175c87f99b85e48026aa096c8454404da8972d8bacc0ca388c5d64e5ebfc9d16b448c68be0e1d2ba9ba2e3080a23f41623edfe3af551659af70b9524380efdce306a16f46e3c409195f195e23ed018fada946f30f6e871461c0b732d16f356898f072022ead6b864ec4b721944d809c6ad3728e469e0f375b4ebe0d1ac2e1f8b82f02de4f023fb37ca2466ebb0a0c5c7da2603bb893e566dfd6dfdc1d79dc6d2f4e07e197703dc5501e476e68ce57bf2a323faf2f08a6f86933d638ade6fd8b8b7e6e78b81f78169ed0ce8a3578a6676e518006674c169481a8b30be9c541519ae1972961e2bd8b729810dcafab18b580cccde253f6bf5386fc86c44e95071b47f632f19fda19f2e805858b8973bb426539dabc414195394169b693549c9c2074ac903f0245e0da0ccbe553bf07821208bd1f823940bb08e175d42a68ab2e4faa8588291332694c31cd210ee6e3a96ddd2c4d5ab7384009e6ad5a6c93ac577593037626fa88e7cf92672d52d324c5d6c96088c37a6f5fb5bf00b9543cbcced90e4f84904da2de0d46f60ed4415fcd54b8fdcd0435a8d16d5d4010808fafaf9cccbb657014bdfd651e5adc7c5cd75d514c1ef36529c6844ae9b31ccf9a7c4b6efb3670e11f2b53307f0923963de024dd8fb8180deead008069c27b10d299a84d9ed1be6d545e560681688a0bfa8a030a1995f838ad76724519024bb1c4a5f9af344f037cc6f48859c9c2f44d5925e65f0d48aadede6812dd5f3b77e6f90d6a38c5fd0cf474da55c7b768a6b0673454eb32731f17f4f8140ca2846a640c6d2855876d4fcf9b4df27197b167e251837b7e175aeb37d945980bcbcfbb3ab07b350ee533fa234d0c4bb22ba140fd9458b1fb63029c5ea1f7a37416250e553d6b7eac8f53d4c79154134c91088c5c19ea7276df25e519326bcbcff9c10e93a2a7ae5d11b3d7a2bfed0ab03cbd130a10391f87b1e8562519ef4f5a46be5e5f2ec1af93ecd8ec786104230bf4db371927ab3b0323c7cc853adbdd7bdc025f08887230ad5144f855e8afa121cf0a919b6ed61a1ca4d66ee6ad03a9374ae0b46a0d7932b700191a815394efcebea5e5ab7b783845ed7a72fd88c9d95d35b9fecb0080d36a5f92c8102a6182c0380aa1d61f3d956818174caf9f764c8d22b1e5039bf27844b9d4ae4d8a808e08a984a384dd3c99ab9a21b4bb9ca29dbd2fb3aefaf0ed3e4117221cb8d9a42c72da1640e6a6667c0195d92b54d14b802c961e4f31e7b3138245b85f9872d36624cc29f254d617616ffb5dc348850184f162305622343c7b1061ca69db8baaba312471aa376df5d78327dc650704987df93577c0fe832e32dd2a6cd5b60208433173a7d41bfc98947a727c0c726d2d70278b9899ca3be51271d4a9eea132d2b7be91693bf8d17347ca2a34ce481958b9c06589e7329b3192160634a420ae91a14d62b01c01622994da47ac829b4159762d5a45c456d9f5984fe08070a2136323d20831b3f76c492176975158148989f1064b25d2e6c660a7f8d6fc1c8d2cf8986483a2963671cf3b628752e265acbd42669eecbb6217dc5acc344920aeae4ebcaf63252835efca55c6054d883699aab499087d42c14f46c96f0f94825e0519e47aa38d7816db244346fd4cff28e9ddf5fcdd81cb525e7457deb5f4de4af15bf410d113111ac6b87b493ea43948c2422d4417143680a5f56073cec1b177d12aef3381a84079785f35c8b02da768ef2673233a18baf719a00f6b6049e897a377604f01b510a3d668df8e7ee6952464396a451223ca0429eaf7efa3d25e267ca04e83dcf350563cac94046e59a8e3679fab9f16b02813ae0d4e98d5f65743389611621f6051afdec4f697f6fae3367c7fdce313fa19100c6d596c33937d06ad2a875b2a60d3bcc90433ee06e44162ac5ac41c02f6f96e2ca1e12958893104793125b10c0d891577ff0c18c6c4a21573dc159cb788c67d8862f73604cb5d50e75421a14a4147d62f6e2f0f92bf7051aa4721a58e208e31c49037979472d1557514b7483534a21550498bcc95d88d3f813d5127d82d786263e77939904e550d76f72e8b74aab3607942d9eed3e7317b1e98e5ab5cc178e1f1d01757f49bc3c20cb1ebc546d66004f303a981333ab505889b7320a029cc63fc3a337750a876c65bac26e82976778493a943deec4bc73c1ebec2c284e57a6ac0cddfa6c3c5ea55ac1c7dfcce9b7a5780e535be8331b323dd7286d8ee090ba4c6c9cde7d2996a38a0698cfe9813f3cab6610d4f974c964e41d85233a6c8b8c05b673fe67eb04fc31f19fb36f503d51f3679933c137fa0d0290590c18b32620155b1023c388808b9de48df91d1dd87780b6c70426da691d7834550a2016158e3256354f58a082b0afa78671a0423808744059d32990555fa91b6b6cb80be5d9a7b599c764450ac90a4608ab145f80308809adf3dbec8c2d6146286d9c7dcbaf1b07da8e11384f603eba4859326d156ff6ece92da8c6e406bd3456bfb315eeb386146708298679951248c8caa31dc0370559407c32e899673b52922a7dce31d52d7d35f0291768461d326722c9074c9b64618b4f26f1c57f17bc0a5607e0294850ce26dad78e7820a866f2973e5852f79bf3cc5d1449a39beba67408b5a42c50c91d054e8ac9df40b01e2d20e212a97d4259f0a88808cd0defa879ef11c3e4ec28e9acdf3667fdb86658a08cd11da9e81610f86ec02125e81c733a6b3491dbc0eae111b6050e594da4dc28310bc0875902ec4e1b692ad73e984bbe83a601910115b6cb3a4ac1dcd080d3951b941d55914e9293b33aa02730b2c232694da072e341105a699575cf523ab14044927cc8c714c0e0c26da6352e627c76670cb35b876cdb04c24ab7584d07cf6041830cd0578f380df3d9e0e0586d2fa8a1c029703d6429317e6cf0dd08ebba8cf243c9646fb3b6969c97a233816686b72088732ab2044209b1550a309dce7722289f3bf8aef8a248de09c7fbacc20e7fb775ec535b86bc58565426e5df5ecefd09d29564aa41a5f707f28be0d1531fa17c41e87dbe76a74b2ce9627eb190a5a8a62f6bc2c3aedb778378f18b5593477a45942b6da568eb2615c47f417cd0a954b3bcd884f680e96754dd20e0b0577dbdf039682875c0c6ebe801c5821a776197d26f9f5337b4a9c217155afe6708ac80d55f9c155915b68ab8730983025824f3d712fb8d787780d6b4f7219c21b77e2e5e32579e63026066d29e68d3baf8e919e54e1800edbcd8e104662f69437f217d768c58e7d09e35a09c23748251392646e1b56183cedf2b3a44ed73d74c160e6f473f2f002757b0d4a79527641cf89fac7b4202e9c9b4ef1f1e0cfc59b3ce9d87cb3fddb6c8be1ee52c5b2166d063fa64b8913abe39e4e27288cece83d183dd9fc8a1c6150dc0045f2eef76a206b60c154580e39f4c5ae5bed93c282a60795905a2aab3c9fad55e4960a30db96ab82d4d91c3f93a36168d8b5c703c2abfc37c69a455de463d2c31596cdbd768bab16d060810665c9df288da236319d763910b5cbc549f4a88e04ba39041d55be33d1490bec296e9bd74f3d27f90f8c8a7e595693367a8ab7cd19bafa03a9e0b1b1072df9014ff2d91874516160e8035439da747e4e3a1de180509e3660d077dba87dfc185a2a0d8d4b01d84ffc279123ee7fd619cd553baeb6348341f391c6431515367cbfba8a4f9abfe1d345a283880dd26cc29bfb4e76e2fa68c3eca4518f1d4594a1e6d2edd7c8245ca90735dfac80dbacf99f58d063a23f884913f47516a157106a122cc9de5d63460ecf0f6565380e9610da6117378590ac4ae726d276a69beaf2fde81b8b0c2326492769a6fa57af0a62ab5105bdbe3a765b8dfdde93f5f89c762a933463b412497cb0c4659c673050e12bbea44ddc5e50432b690c37801dba76c973f096484723726ea2c1d3e1730f2ce7a06631a4b0f7083a5261888fc691d3843f29f631781f6d4e475490e8111fa08a3c28963a52ced91484441c16a5a5c1e1abd0a7254b621fc7c7c847e975947de3318d52667add960d7c1a659e347eddcf6d36a3c27edc22a853d734311198959d471b20d6ac00148c48828c90ea6cd7142b83a520e522fb7f72c89722581cc1de63af0b058ff6dcb86ee09f0237fffd486cdbd1e4ee818f93c1f8c99b44632beb11f998a9d16e79930cba43d691729bee0379dbaa8058d4dbcf45eb7500e267dd3e88bc696bbfb1e2feb6c60a022a1d7826ed24ea77de0038578e82809238578e88b5a93720dca22235a9134919e0ea949a0f3db03283b7b0bd468f07b143f56f1e0073ea7fdba5d85088ba210db497ab80fd7c68dbe409c4c1853467d0acbb5cc21a442d49cfd634d1118a251884becd7c27f63b002b979b1939cd9ca0937248ca431020190e2fe7b3d10090ec1a88b3117c7a1b0ea28bb3a391fd641c980ca5d0fe5c4c90ad02a7915a9758d28d42538e3fccbe117adc740e3acad8caeba6a4a6d3414a39850c749b4d2703bc6b244b5d830c4ac647e4b6ad74d7a785acc28ae0d5d85e1e90d589e64755ba6b9c6ede53ab4a89b84b358cb82a794bc2f8faed871e0a7685e059ecf1618de400afa4526b43ed5de41d767c6b827cca2792d3112f5b5481cf86527919ff69b064935feede3e023882b2361c2548e8a9c66ba34e0975bbdf2a5285366762239fc725335b4cbc2412d1018e336c0a484834e7598d1eb147cd7c46257178b34012aa80f1a9c306c6d63d4ab613357f47090fd42844e596a824340b3680489457bf366085cae375733d30b61e4c64f4ec6d833d1050e120badd0259df9f1154de9865955b733738c8996aaa1cbe091966e68cbf13be8d9ca71ce17606a9738bffebd651c38ba6b23410425d1bb2b8eb91db957a96409c33729636345d9281c1b320651f8427e4a8a97282cdc9d57a2d5ad34e1e579622e9e48504aced3c1bb9c804e5d513cceebf69c67b6e6efb63c9ab0bde412b46a6e884a53f98cc2d817215302c7f5e804bbb9d7434f551f287c419635faec5497de2bb7fd319265ea31cf8bcac5f4b9fc52d5c4c60dbac2cc244045cad802b64d0310881ae4b811c7d70e70a167a31275e12185fb901f18dd254b79863a352ed85dc4a1dada9c7143b189710bf845c32f5685f872cc34921775abfb74f17a32f85fa7ad99a78e0d9f502dc5b479043d531d84060c454ee33697f3fb87785225091e6460b48997a89bde974e202e57caf7a6e4d84b555de206508655deaecb02956bc52a50b9dbd102b73a2818ce8d5b24fe28e77c10969539505d5c5a9571139882a2d2b9697496914335120c26fc917c3ccbdb1d4fa08a19f9755be20e44409fd7fa6a699198aae6314c2be68c8d17bfcd156043347c335804541a288e0ed573177f9fe336755b2394de9bd9a6046ad8fffc825de8b6507774001fa222dc46ca404ee0f9ee05b032bd900183d587158c4aa81c80c5be47099911e36dd6e1ff21e6cb36c258895fd616744426461f9c441e03bc8920a1df2034eff5de2a8f6b554c61a437f4cdb552a04d6f62b2672f23dfec82c71e57c5c2ac5d60812d353b92df92b41877bc289423a6485b3cfdad755210248ab7324ecffae6f0a30feb9b26d0a4f1749dbe10464de05c20fe8e58861585010b50c6ef69d84438265a80005aa960ea610d425c433f4fe86dafa281860e27b5921346eef35596eed0a3372324e98a3620e684096b49b32cfddddd03423b14ec50847c12480153070b4923fedebe2e9e74e29af29fab189b643ddd67b3af9915286c13e69bd5c8da852425db90ef02af3eff628d3513b8b90203de9c28b7e4a2f191b4bfafc65efa0db26fe78dc60ed5a95403f28f231fb05006b75ceac5f1cdde6d47c73058480bb8dd6ea5d0527854994cb35d99842b634249b01e9360aad971fb54123f267a2cb78c90bc9394f516543d0fe79d5bcb447dee6d13ceee72470dff088ec66e67981b40b50bd90f499452480d9be1220c53d80eae6d5b1c362f4bb8e3efcfecedb5fd621671e7c32dadc987abc3a51eeeff0b86c8097eedc06210d4177a959c6aabaf0ade1332c7abc33e267d1f9cdf0af150d87347b4804e15fee3bde26bb4760f58f5efd6733b47b7e21b781886eda52f2d20914c871bc9aed6842218a47ecaad0932cdc6f4a71a44166db01f873b5db97ec511448ae13d7a18bea9c14ba4a004400d9b9f4bcd59110ed1b8ce6c0ecd195dab4ec9fa98da84adc0c37dcd0ed9cf2f82625d90449a78d34d09bc7346f579e981ba7d21c29aa748f7815a5aa8c7ff6a16fd90ea4169237690982119dffdc63bc501fa4095650e8f6590e6c34fdded79eabf797beaa983ad183515369235cae4312ca01e3920db2a510c17c298fee689afb94f7f54fd79f05a8a46f8ff3364549f1a21af4224c9bad5faee050c4fbcccb16b4c832243f7a493e8a71c5c26e910bfe08dd322572a85ea26b5efa2d630fcabc8b54bbe817a72fc6981e0ba285f55524ba2113cb19a009b68905cfbcd6757fb75f569f14f297cb6ead4c7402c301262282a644081a97b35e0305febc42eb70e132c9c7e2c6e9fe1db2865f796e8c4fab8062c16a3e8ac69a2749359f68c465a1a42dd3de2de2af20e473c0d85f6df729b69cda455f6784f4eeda12e1f8008b436405e5877b2d2b2cc2f71e1822049cd117660f86032783d892b040bc52111dee68b8fd05950adb710b8dacf4b0f3a732622a22d18eb841f0df15a70365c4242142dd0670cf257db043cd878cfb6898d3a49bc27fe859db052d47840f8e4f406bd7ecc599a93533928910dbcd45f871475cf839fc643b470fc8b1c89805e226b100ac2fa986710e1720266d7148d2a55bdc0e70f8a2f10c19320f05a9ece04d13631599749bd954b9813ab11960385a9e55e04090c57b4a4a0e4318aed26a947aeee94e360a72ed4eecee06e7b04b24722d5c4808e647bc6e8e1dbeb3d5c5b7a4d842c4b7c2e0ec7ebe99137fb0c238238fd34aee8b21c45a280055da9204c670a5df10901c8fb228b38ec71427dabc1e54c8b2601ca0d9e4fb6198b08385011c97e4f74d6f9811b17237cf0d2db135a188c99ad81736fbcfffccfefe6771f2a60e98ee426292b92543abb636b1a2a8244106f2ad7721fcd19ca66171c6ed70322bf162a705ce8eb7a95a2d0494881ce5907cc328df0a155cfc453c0057f405c10240ed393e898e8e507e2e443f663fb4508a9679e70984d6dc598c4f1d603b1e5e8605d70a05849059e6dd6caeedcd5dbb051008a81fac4513f74891331e5bb94150bd0dc55a87e6d5f33f7740e051604109564b8b49c4b9c518b726aa45f460c9aa33efc2335ac8573edeb3ddceab85a4a604684ea15248d4ac273359b83f45032c7ebfc7d0d568557d261ac2ff01a42f0f3467583837a6011a62634323b59b107957daf7f68fe3fe947fa2ce34e591dd3491890c1ee75aebb9ba3d90c1674814bf8a5af169e4bf4e00f1e732a78c9b0cbe05bd01b8a704d76777bee7c267219ecc7b5affe90b02bc7e09dac7f4d1975c9a8e7f6e66351112cd80bf16e44ba13011d2a0f5d011badb03789366574cc8f0e60d29ad93cc40f58360eaaf619adb6df42c4d4e0e6639b429647c9f0c4672a5ddcf7c7204dbb1b0d568e08ca0dee4b5acf3ad746a0a13f6f1600d64216c34e69a920616891de81e515d884b80f49f9f44aca97859e79b42d3535a1f2007e83cb70d247be91eb3aab89ca9b357b0ee84f90c9fe3717480185bfb7da6c27256c1fef6607b6346257df31eb705155d27bd341647421e26667dc98482ecaa88ec4c50c84451a0e4952df50c7c540a09bb490ed13b0fd6686bc1e92833c1806c67007f1fba87f10c49a20604eb996cf479a8543bb003111baf87b8c4316620f360d492dc26f11c4101cc274653dc155cb045f9f9bb90f17b9bdc54aa84ede78f9837e4816ba654c213634e5c55b8e5a0538baa4a51584f98b4b14186a70563ae4965a812a6d290fe2d6b02b933d012e6e06d53a259777a86a5c8d40c496c8b6851db7a7be7505d74193d4e86cfde7b5b4b147634eacbd96f0ecf8373e702119357b6dbe10e43a51887a52d75007cf1ac203c162f802f77465d6ff9257339231577b7e4388390b6a2bcd42aa2a7b27d1462df3dffd00f92cb372ee8592cde9fc4db6ab044308a4709dd38d85bf319b090fb53011ddea6dd4d703322f8014f7dfd7c9e42de6a98490dc36919be84b09625ff99593a81607a21ff99d80ac5de1086828d5e10a45d500f5de27d91c041e03dd348c7adeb04aa11efa968eebae1012c79cea5ea6de996c4f8b2038dd579f4afc71873c4fd9dc4302854a26e5557b5e2cbc0047f9249f269fdfae83388af2e5909f79b1b2df13b2f104f998009dd206140519f8267f284c80fb535634f289f81a81d49e7c2713afdbbc5ecee769c2e26919a5142cee8669879c467d6fee0089960d84af82489f0878742b61a9ecf9de3201609bf453f482a6171d10d7516f0e4c93aa75d629435b71a352f47e9f08e2d6c29838e9e23ffcae87cd3b70886581210558242de111134bb7584a2ab3f9d168f18af167059eb2a2af2a461f300c7518b33c56159d0d978a51a1a096389fda3df65dfaf59488c862d2be5762e1a34bbd652ef43a7355b50fa7e47f5b306c6c6816d98fe1b0f0c6f2e12f981850268419ed92ae5ef29308c7377ebb7d1c9ccc2cac28edd3cebed585c3fdffaad14f085b43e78ec5b1274e910dd72e11720a054e4c117d8c4954d120703aab5f42ec2c8fa5ae455e170f61d2e59e288d21721822ba9a6d0684f015e36a60cdf80ec50d28b6dde4d572dcc6263cdf015e40d50374952f8f8adcb41e8760b9de7213825123db2978483f9d22c1106894c9e850c4759a8dd4d592cf8e3d2b964b1ae1a2caf9571701cc2eac65e1130bea9d9dabec0c4498f4300c721491b3aaf95f3d54cd2a2342750c8beb5c35c289d96e61ecdf84d482237a4c233eb4c9bdc5005b92afd41fe9d2bbf6fafbf3b38cce7250f592fbc52c90adfedd5fc4a2ad5d734c3858a0a06d553a0de4f8586b8655321dd980652a9bfb8f1586fa61d3332d3948e1b5738ec7a2a73542aeb36efd8ce806025c2a29fc21db88138ab40109526f1514ff1ab0d35d9f323265f4bb09d59769acaa6288da21b3f188e0c62f4c7307ab466a6daa1518cf375a9b037de6743700142c23d9f1f11a01a78ed735104ce10a45f78ded08cee6d4e0cfe7d5d8af32e258b43c82de6ec22cb43aaf3ec33ba4b19752d4f8e5c04245623e415e17b55149b63f5db00889d8a451e158ba3e867290d6816f33ea5f10d54bbfdce0a6cef939db5c694646f85b0752aa6428a2d05d2ed8395e3d3d476692809a7b044f0d4fc417fa741c5f837c609934722c0bdf518599a7509ca75b4ab4539c6cafe484a9e9610bcaee2d9c17fb872aa0c23d26b1fce5c043a0d174a5c90c33e3e50fcbc34438f15fe7c3b95b637922d2cd4448680ba54a3407d3827765301f7a00b8b15280a3a4fe5327a6579c31b81c737b192c0d0eed19486bbdf532d4adc63d10e6e79683d98583213522c0c08c1528b88f51dc9529eaa5fc2e1959a28385a5d6a48d25e891d8b033f378695c0eb15523f02267cdd728b3fd08bb42fa3d8f07df9cb5aefceca2cdd1a106ec25185b75891e00761a78160dddbe03e88d7597fe0613a6e3486c341343f789d68f7f2e372aa7688e9bae12136183f6f7a92bdeb67e881bcc38582ae26fac4f8a9329fd751e93331d5fec6c7ac725098341daaf34b37480f8e9cec1f59c9095d9fd1354461578aaccf2843249973c4c9ddc9bafb33ce3e0c4d098bd079ea8861a7f15a019aebe7c62b0d4e242679592eafc949b84f04d7e16b89b3da40c83d607c218d2c374e74023a7f44bea6810e14126926710e5929b84f8cac7fd6b59fe2c936915d7f633cab9d400fe0cb3d2a1b57a5b34e332395453172e9e05708d5e5b5bcc39c1321df7f071236380fde011dd26270500aa519b2731c398a384696c81d06a3022a6293b5f7587d5ef3112ecd748bb950237f4937be3b3eb206aff085485e5dba38446925ef4ba835a196b0cc0126f1aabd4b4c07823a12ce845452d334582f6bfcb6a1ba5ba612b9175990eef9606d6f47ae4661e97868a89b4c845f1bf950d4f98fbb51b1ce3305a5f893dffb315c4cf95900a0c2567a19913708405c0042e8dff254dfa600fd76c4a242dbdfd08cc06eee27fc3a2f10048996755b18b67ff419c1fdc04abe3c3341c06922e83da7997058857f7e79cc50b16018f309056fb7118caf53fa5061bffd8bfb35e9dc2ee93e73f235c1ed48742350619c3e99fe321c4f96731288234f801a076e7ad65a7944519f70dd3d4314b5a5c41c1113889da04f23db4c87915e0124e066ff9ece35104f7217cd2ae131abd9d335ee583b9abd66b0b56719e0bfc242c98ce6cb8ec78bbea43f6a8667b20ec84037fc787dfadc9c0d986f8d9c4d4339d0ed4bf86fe7e543297569c08a71e928705bee168d2412a016dad6c2b5345a51df60f9288080b07b844ffd9cd41998a9c7c7ee05d5e44d0807880acab4b39cfaa44157fac4a0e6ed29938a01fc586b3cb3a32de53117aaf55b650441a8b4bc2eb179fcc87e1f50105c177cacd33b9751a96315a4869ea779257f4cc9a4865b53ae60249db0242ac9d83e408940675e22347357426d14a74b68d1a18c788e30f35c0706a322bda97f2069b571e51f28e3c3c59588d3dd24a8de4c11af3a939e9a0e60248eb9b323fd064f08e88cec5647d2b14dbf99473c914cf2952982388d60b3dec2124b78d2119210d326fae7e2e4988ee40ea7f138925e3e3ae884849fa290f00b62965ae31db3c2bf13d05daf792a7f51302da1e2719613bee873331678720367c6ef152b7b34243a406848074f16ec6a3eb40a7588a6c8e1f4de399b899eb807402fcda1fff38b1580eed0f5fc0b47da9d526e8a4031939f4801d10a3ae242a67e66c24116065849233e116d74c9d8033354908aae13a73cf137c6ec0b40fe464836345c17628dd7f586bdb45a4d6c2c86e67286234e548e46628595d2e87ea12ede97cf2c652e54d99da85b20c150309211c38717f31e3517a0ed4f294d9055bd3459e755e2bd1bbc1cc462fe1198a287a27165ba3c6c10a59050f91b319454f80e72f39cde84183979a6102333f9c403b698f9d3fc01c2449bc8a46d3a469210553b227898ae1036e5ce814b4cc73c8a0d6b412a79d769b31f7a1fc869570f75c4212e5dbb6be6b4dee99c5b4b656376f925d079fcb70605cb936096d0beb93639e115ee4810b271ca59cd55edd4737e761eaa7ed90a1118621542011abbd9e36ff4a9964eee76ce62b6b17f7b1dff4eec31a7bbcb40c497ec175a81dce25e7008932facbd713030ce1f75030ddf17db37a56af37c0ff28ca8c1503f526384ee4a2e04fb1081efa6fa34d1586de26c6d6f43a99b08e0737523f9d47a0bbe20070cb23cf04eff3294f8c88df955c18ea2cc91b263a9fc7026c568a586b4c1ae78e6482ee154d1d10c95170db63f19dae95cf08871d959dc56f2837cfa66a9c8b1d61f012480822d831165960c4ff9b9681c566472bc60f5fa520199de14d2bdedb624cca0a9c8d24ea21c26832b9353a48729affc205c5fe039b9b1ef52f305038bd97bd4b13cd7b3a247be40148927f1ed4c194408965c0927b7a2966d17a4a178459b16c01ebfc4fd4ae043cf7754bba6a131c080c9a2151799a1870da1b79da09a2583f4b3147255ee66c6e23ff9454b20ea6726b97f6614c139a376a49cb8fee32ed2441c0b4154da16ad885eeb4e2631b5da6c40d44ad475baeac7f2ace1e7901f2c465957f8fd929f2df134c6ec3b0b7e953e5d0ca45a1a2a43480033b8811c3bee2f2b29f62ba5f36f4c293299c9bedf24fde4b11b4ea9e83001976ddf4b760a07f4097bebe0a562f666018eecc31bf67823dce1c02d7ac28096283a0d6342a8f4a237a3e154bc52d98c381082ebe1fc17aa6169ebe3af05d0aa35b2cfb4efbc6a88c006471847dd72bc4c3057498b1c79f5da2db6386586ea2451bcd500983385aa7233440fb126f352068b06e1b50b477579e7e81743a56f2398a65494fbfe15409f4bdb829b69e255c26102675c3ddb8c3d1cf0805ce6f86251602252c366eb4d3397767b4a0a2279118b4a1e9b34336dd679666ae3ad9f98ce959b3ee4180904ee9a40c511b808025b18f71c55d43457b8340358e3e8aeaf2a28093633020d404780d89b28eb12bb999098cd4091f2cc2dca0bbc39e5bb07be190c7bb2889264dba7bd013601dca77ed76debcb6039a9be329c2257d709fa004095c8666ba67aafc0e63f8e0f0efea3718ce2a1c7255f20f8e4bbb7459f480e4b1c9e7e910f99625da242c64180a8a3c153519882b1b836ba19244e1170eb94c5b3145507bbef996412b10a206c648b716e1fe9c085d9f7e660f2e21b1d1fb58ecdf8721cc9bb318067f9468a91efaeed88462584c340ccfbd9608ff46fe2ce7f6b39030bb6ab2f1ed2dd3fb61794d48131a17e09b664753e3f60bfe441597d0125773e75ebcde6f526b98c0e0ec3d59a406d51da3d1222ddb3940f674c98bece6fc8d38531f23f876e598b65307b66eb3fc1d23f21eaf406b6467dedc07dfd10ff36d0849b4262dbb95a172c39251b2c00ba2d109e0e603eb0addaa1a21dcbec670d05917ebb2ac95195d35d0008fffbbc0047fdf8cec334e9df575d3ce6cda5ead503da56e489d90255e0e872d8b0db0635adec800fbcef58138c39c353144012007337fc63f38dfe4e82723ed0b09287ea2ba6bedbe05ddd4257429aa3304fd764c3b47282fe00bdcadf3f37b730193c343da06c80b9015536be084d3e341ce2b225e037c9a0bea2ddb76ef97d57cec9d7f2601802571fcf5b4143aa35183cab80c6b7ce62fa25c557e61009e72ce9fa5898c6578572fbbeb6591cdf5de9bbbd48ce89f1d0389d5ae22d465b6759d17258453577aeaafb9c6750bc155a29f144b6cb68d014c39ec1e4099d201726271e95ef2e811eb047bb971c1688fa4e8d6eae1350c50dd60c3e296c1a2287e4aa14e3de4c5de840284a9638806f3d0206871856b14f8bd48747bf1ebb7cd5283b09c94208b37a71c4cd38144230744ff9d15054e5484f795c05c7d25774bcc89fee821d095070db7592ddf18a84aded3b59169696daf60c997a2a8ad2847cf72bbdbd0232f73882f8ccabe44aa102d2fc61efda093fd21e7b57180796032d3c35e0d684fa1b1e0bf83fe84eab8d3f865ca56b54128c8328f77cc936bcb65cef8ae279fa62085d34877578e0c5837b374dd106fbfa35f955c40bb5a5f87ac93d3c1ede77b8ed85368e9c14ada827a898b2b900ccb1c7876884e3d3f5186c5f31ddb8d2e9393e277034bff8a0f91dccdb00047d80aa1feacccf1e1749e5940c5c99f85eb4ac1c0256abbfb4264d07a77bb1f7f3d7ec6a6883b937fdee1f027cbaeb4220d814e06b66373768c580f988796132ff93b7e9f2f318133d286e78773f058d0a8d5b46fab4ce94720adc581fde2927fe0ce443577c50a7aedf8fe75e21d98eeed93567833bf8c878b5b088131128a7456b593c21c7f0b8c80dd0012cd65dbbcf6d3f132e097081f1cb04c9385e1444cdd836e2f019702fc856a3ed1ad0188af8637f830320670f0b331342fead9091f1edc33c5128bd259d9a8ba89b95afd984e6411f7a2ff19440657edf17c8fd071a119901de9faccd44b07bc9197b5e8d72bf587a583cbcfc096054f0f78f0f43686ff9e7e95457fded4ae03359cf0db5a98844e7a5b563096f92f0c96c463209a51cde59c5ad4e3180628b7a2912e50362801433629dea3d3a9e41438301fecdb9150bed31b03751d5861f604f33697378c396867988f925953a2994b93cad955f42f8f07048a81f58d47f3ed931cdccd80ae8ad54d063ea0a0c5d3d19edfc72d777276cb652d90b307f2d1021edf9212542e54b1dd7c3d2efd90f81831d8801b68850b3471536298481492ed68d2940a140f8a2b4796cf91d151eef277e2eb0302c64212eba6fa5c0b38a1570f309a2f79e4372d09dff4ca193339f9686c635a7cac4929764d1fbd1a1d09b29416b72a7d3bd0e82567842730562cdc7e6ea759d79eed85b0ef9591761af20ca076700e276985e25fb12ec662f0db86c6e801504857202d6b50facb149a6f445449ce14f62480ae455eafac6bd218873b10daaf77fedf387a71751418bd7a9df80501829ebf41b4edbac835a7a602b1cb334798d0bc7f30eff00acd3502fbf153a91bd66e37a372ed3e58ba073d2a06dd1fb539cffa98ba07cfeee901e1ec28e121069922a5152793c5cf9fc180804a0e726a8a308167989cc9654b3805762c194a693acf66c3c0e34e7dbad11850f1bb6fe1d408364c4cb10f4f3760b686adabb460bf486844bd2e67eb69a10eeed5599f1bfe41e11a59110451a1e914d6dd4e0832ccada086a36bf620eecec50993f63be23304cf04a0cbe725a35afd39abc971d049b65e0c4fb18f285d382256260eccfe056b839b8fdd70b2237f7b060b32932aecfa2600452425b2009bcff687be3814dfee877b012bafcd10b851a9e44fc1fb135408e9b1f9f3a910bd0c1dd88c9496b45fad4dfdd97bc51e86265d863cbc328b8ed8c18e511264f894d4c668d178b5d86811e6bb726677296265f5e494fa9a15fe058628c06f87eaf3bf88e0c2036eac63e0c91ef34f50b0595bbf4072f7224f83664695867ae1bb678015bab4035e2e109b949ecc6d66a341839dc7a25d8fc84bd3c739b90a1be9e3ff519571d624952e46bafff3ef676debc25ecaf377055694cacbfe9acfa7703c946da7a0383ea2eea88cef330c855f7dd8a107b31e45619a4a9c5b15cdadfdd01a5891c289b70372b6837a44517e56066bfaa205928739260e66cd3fa8e6925b1b1fbce097d3e0aa33eab0b7c5ea4c07e422449081da0cf1771b30515bc63cdbe82635e3025713ffc0f56d6d1900748c3244887d7c68d9b94da5cea781599621673046ff43f8ecbb14e53ea300921b16e5b03deec222193f52b3b325dd9ad631c6e933cb147d83cbb355ced395242260f66e87059cb03568922dd0c4d4b20ddd90f3594e823af705800bc4b4ca4b46ed4544e9f3ec5dd01fcf74e28426042237b53c373fb7ab2ba08d7784b2ee8dd6548c3a4f1234ae6b8e3d630b52e61ab4f8b031c349f124caea74ad91ba16e1ce341bda6abde7b1ddddcbad2762666762cca329da72292876967ee170366736cda2a40e9e3c2b3cb523d29a7c4bdab1b8e130d5b493ec3d7dea6a920dbbeb0e51a5c55a6605b7125c8d0ce45db87ed89582803e338efff9c748e30ba310384fcfe1af1f7268c5fc5f7d3cc280d6c903cfeed9d66110a02af41a2661128815f02498b1d48b0d8a9eea79a54ddea152b552b4e566889b5003f6069e273e49ae9437ae5d59ec71ec0cb865a135693202bc8c646a88256a0cf712a8b1d3bd57345b148cd4e53171af122dcda5d0af1529621a0edb20baad2accbde7b45ed1f02433195802c0af09bd866e6fa8fdf9e2ad2690dac35c5dda13f24f37e2b91a3b890bb53814b40e32a963771978f5264235dc7f63fa82be5645ec084dfd211f57c5693ddd32ef309ce0526e2d226a56f498962c4b7bbc054e8170d8f8855dcff4ac4245d64811a2e580dd662575bb33a2d72973736a41bf55830ad71148335787eec433525e068093e8cfb2bafc5b9691c3ce2397dec4b1402682a8103b420be13475ad71ba9f8a9aed8d94f7f7f5061dcf987eb2d3c592253378fc14d0a3aa0d10ca2cbc59fc1345ede6b5e8b9aec74194974712a33a46c853cdb52d61c6343c784ac5e6f77be5263de5ee219e9bc670346edf8677756635c386ab22913393c9fc2ee7916b130897a55e2b9d322a1185212556c16b92e45ca748e0eb0b0422e27503822524a7c9d23db635a49ddca2b07864f2ab00c0cc0c97e212e2d35db65102fb97fbfbf135a6cd391078f7fb81c85cf2b7f7c9e36b0d39161ce7f4b5ec9a63392126d2f3b1085a10500c2cc860c8b24ab5c14b996467aa3c1a45cb8f48e3d9935ec51df6973fbbeae3ff0bd2bd1f2d42386d183c2ae4d966796a6773e4da07b73b34881c627ecac67a7bf3ed229ed927582558d1c75fbe91588ab00b2c160de0a456df45981f73dc98e95be68899d8d13c7acf6017f02802fcb034e168560d1404c5ff9eec40adcd935180b9c33ffce7eadbf6e571d741dfd3c0e92403a109ff6ec9b7f70535c6df2c1e60537fb3fafe6c99ca6c8b0acd6c2b6756b410630d3b060b3a58d0937a9b042b6daace8bc39a0f87d122c38209d96553ca6c745d74c6ea889b7dfc20508033b81c9aa083a0c93874038905878fbd84463427651a32acda86d16cd58f92e2bdd0d97a46866ebd28cf428accd2463049144cff229dbf3368a6867c3c2b90efd2dd5199fa10f547bbbe1e50e0951c1bfd086d5947976d04c2fe4977fe644319cfea2112622176327f4e129714d5dbe33cf8bcb95237a7e510e1668fb7f5c51023ae3db2b8ba49ddf9f0eca1efec402cda3c2d054fd682187693578281022468b3a6a604adfcb66b6a718344fd0d5a1ae03173449ab78a1cc829980e0f6dc5d91f8a07d1ea32c31b1ad785205e776638523f788c314347c11957bbbd80b374ef397e5d3a31a105daf920493b9bb3beb701ac738bf906b4fd03ccdbe4b09f923e5551f7241f43381cb5a27602af570624c14db3774dbf9747fd800249c192e67e9e63aac9cac9e48057fdf155a577fc35bf9134317099b64b85a8a5744ba9b440872ef8e6d7abf35acbd04861c2d59b53496632119b0007a89312cfb97cff6d4f57b2fe35793677261abe12b459edeb996f74c30650a0792119ef9700adf973c00b3537aaafe3c9b448707c100b30a24d3f012d414f36cc291b6af2ff94cdb0f76cb6ea6b129f466b702ccad0fd6d8b99835ed8e6cb3b481426c2bb11e57e117fe590091c4229924c34ef030c1144dacab32ef4fa807afda534eafe958be8892b6e843f0deeba39d2f711851a4aa693feea33fc437744459e105712a2160bc5eb054c35c35b424fe6c8760c4bc8f925ff452b7913b4e416749ee48386d36e3e6e9af29d9feafe3ccf9cf42194b2d24774e9da182a59e14268bc9eb81cc2dc0cfc232d5362afd0da1862d12b0264a62c0a9ccce61648967759e0359ca7f0ddc99e25682de13876c551f23cf4336f5d88716008f9526af3f14a99e1514872ca14569d290c9d9f36f655040820b1255fa0e97b3f80e17417959aac383f8ff197638a47624a058f704e1439c13fdab94e900836fa3911a13328a2347507b0cb4ff63c686a122e23b8ba0ee8cc21966aa22db1b92d58c913aa876ca8a9dd60853a4dcfb760ccc9e50e710b4339eb01bdd9344f2a30cefa95317b017965bf447100b703a07451085657c8df483679788121d675c2820ae1070248b46284036925edb7a06132ce2a943e111b585123be604d8ecc0b1777af93a540bc5f9e1e7cdc5799c65d7423fc518a862fdc698c5be32bac20fbb1d0f2dc41d011d034319fe02c2154e064cbd204fc0860cfed60aae55a8ba9230780f31f8a9631c9acf94ee20730242f7b695fca20b002086a4e04a300166947cb6d7812f754e5a83d5c76faff07a0072b7500c7b125e2e2ef15f6bf2498f4b7812d2e83149ea24a50185e09ffe5078f9da944a60a391365c0ffa96e6055388fdcda03eba851ac03e5d736651ade4aa54529d0612cbadc5c4351d28a5b7dcdd890d0dcaeb5ad2d8b048e1cc8a4466c149b577aaed0a357792bb1c26419fc750c681e2b5024b1392ddbbc84b1c501fa5c622ca68a4ecbd62740e5f96c65387846bee10b14382e177af167c12bbd6756a15e64826bcd3df531406022af9e179ac496343dbedd3cb7532cd23c6f3f429a5ed1d0400f42eafddcd34a6776372416486b5009cba5ff45a70c3104aa7eb6a54d66ac272bb83c786e4e3364e1e786f57083013d89721fa7e3a192e1b8633c40cdde621615498ff3c5f1793b704a27bc6f36580e6a2a5c1799ecf3b2fb1c6a516ac4a12c45c7ef87f19bfc750cfffea3b64c34e9d7fa75c8b7219b70d92c6cab6c13311850d18eefceae8df35d00642f3a7f79a8de06605c93fc23a9ac45a419e4308a89382675c9e79aa7833d9f52f895b26b0309938a7af24520e061c984d3276a136b5d094532d36d452537325942e7e7ff4c6ceaafa25ffebdcfe1b5b0cd7e1fa084ab3d18713cc8295edb83c64abe890725728f5459c01f9d46595013c41fa752db2c6aa6653bdcd0552384ccf118ab95d9d232c06df5ef249132161791026c1500853755faf0fa6caaf099d90526e7859863de08dcca5a5139b1ee568ae9d9e7f0093971d883122b9900b382b612094d05ab9746b332212b5aa40d02003f66694b1a77f52af97420a43f2df22bb29a4111a4912bac8fc8bbc4251de925f96561df87e38875e6b9fe69c1053c7c3019993f1ee0ee11504cc0f19810b0a43ab4fc2b76e71bd1fac498cec8a12509e856d6011e9881304cb23cbae4f84b5aab03de24141a7fea7da0389e61e37497a878addc42b5c8dfff061727bf557c580472b3351ace57e162b1d731f1125c5ffef82e93bf7bf6b7b4de5491f39cf1de74aae13d6e1f1fe30235a49080046aef913925db858efa3012f9244bac90106393713e26cb871b5f27171c1dea719074323faa6a5d900409e28500b0f057a3b576d045196118a634446f23802d29acb8dba93922543e846f905a3e5b1470d30c9d95b808c913a6ae0178d0cf0d8481e2cc478250ca4b44e333e3d6c0dfd7bb8cdbf49be5833198708041afa67e2bab4ab2779fe9c34c4b5f5f3be759a5eb9d9ba8d50671bb81231317858daf82ded9663245d1dfcb4164ce8d738f02ac146cc7d008c1fdb7f54c0f4803a0dbe5f8c3e605f2c547b89fe3339864ed1b2da0bd991ced317c40376c5f2a354e4627881315db417eb20a85c08d1bd5c4c6955273084307a62b9e42af0f55262e54c5981a6e110df34e8e1fa0b9904628adecf83e4fbb2866f491c85f8106aa1030aa96146296543ec21e02945003fba134e46f6e25f393dd0a6612aa102cc58965e9550e48c389c1c04a326470cebedb427e442f8b848df82a8c5d55eed0d1446c6e5d6e0ccdfa2d219019ad3d400fde350d690cf04d083844adefe5069c7066b0ea24854ef3f5853328d7bb2ea735b370eccec5f0f777a467c98f040c423fc4c3df237ee8b1e9cee6c859c860c0297667809ffc0b73af9815b01384834fcb56d3e782ce11ac9124345a3d34fc22ff7e0c3149d66f7bc8feb9743bb54405ea88902011cfd4ed07ee19c6b8e6de6dcb08e2e86427e5e675dff052652af14d7af936f032bbbe508c54fd4dfbd16921e7b1c1471e96f3a521b911e32a5888b5a4083be97a3ab843a1dacc19e60f161fd84c10fe94c9952829da6979a83ff25faea14df6f6d5c876f3103a8a93deb51a3834c9da185355a8b189585f7c71ca082295ba29e326e60b9d08ec5386deca533a03b903541380cdf616135e348c6b09a5cd4a074d7c2e3d794e44a0c4ab8537f3f53b12ad2c2a996c5ec0a1b6d9a25d920a782bbf2120262a71f816a66ffdfedf5e5dbb868d37517607e880d697720a0119077b19df4e9e8709a177bd25508b00c6c79d4b1c1ca7f607aa7b18e6f93e40c8ac9d8705bd9deec9626cd4aa06491416430f1e204177b62d1bd18e9fefa0da4d6e032f785851dcfdd3e2a2058b1811aaa976c30a067d9accbe4504abb7c2a39492889fe518dc529cfb481320dc05a785cdac3fd225936716b149620ce252d079b0f14a947bd7efa17868935b6483516f7653fe108e5c1da91db5a58a3aaf920ecfacdaec9cb997d80860e966fbc4c2cdc52f41fd3dcf8bfd70fc4a28f99128b1b5e0d412c91fd59a9deea1d9b5170e92e1ba12064847d72f9ed9a58874ce906252c6679851b735cdd5f3f17e35e0ec6117e83b9718e85bcfb608428bf03df02e2950a07e80844403f21b8b0e6ce349c5ca2c260aaa780949050d2d9fb90f890e0d33b4a8263b0f3ff72d06ad34072f3567c85a6e301d5b374d9a78a94e5a3523735e3f9c2db0734aa7c7c5787879687b485f1fce35966c742b896aee8f0361d98ff221b58f0746a0bb4ff1443b1f21eb26e1503187f52903a842a278d3cccffe3328876cada9acb5f109f1679265c39ff58a2f5f63162117f63556389d00b7ddb9cfe0346c62344ac0c9f130294d0178425920cf8c5623e09bd387d8f1d1bc4a7df18f8f38f20680ce2734505fccf2d7e13a0fa68ae5f7f949346bce6896c992cff605197740913534fc38ab50d679c92bdd04e6682ffb8581c3de476b13bed9e72cc7807e6ae6a0f0fca5cd9a03086c1a5971991a7e0a074c128727a4fb8e63240df8d4e87ba2077b50ca0c1de5ca6b4a09fd2d16022aad1342b0dfcdf706d13d433db3f592bb467f911fdd09969d1fcb4fbe4ac156a4227dfba8999642bbb7239cc6bc02d4e1cc5ffa47642171b9807bc2e62027befda4cf5d0b994e36b110580f40ae0b8505bac989738219bc3deefb4fb85037482687f8f196ceed78ef556907987d952b042016046c57e36e47e9d5e4c71d5fb7bd2327809e4663d75a402c9b6d89857d2d07375273e3142dbfbd1c4c658fc64e2436ad5d8a714d9a626b8c6a26c3ca5cd8b7bc75162e5ea63a1644e4365ed6b16107b8462e7186586b0b2c43f526f0656c544b70f5e59e809462b1e00853cae8bb57e39c55abe0e2435c53bf68c0dd39e3bcf6da3250f4ad1d47f1e9813b22b109c9f2ca6b06b362f8a0c11774cd90321561ea5633ae94828698a5b87a338a0a1ee58aa9e3759a68ebce835ab5bffab1cb564a704c220e8f451d02ca511d3a61071e59d7a638c6eba218fd186a9abe7144e21dc862d71cc14fbe19898710ec7321917cb26df10994c2d4980eae0c9c512cfaa4068fed52d0c57c9dc3fe75b51f333210839a37ff90e8508bbe215d7fd50cc4c90daa00e10194fb660fb38b9a85be80afd5232edba10ab7c98dd8e5ca4eaa6fb7828b529711682b92e5c980bc877a83b9d7f0b848181110e370bee7ad434463f90c954705032d56c0b86305b83f61642daec190941c8b687f46d70c0c0cb4d627c0af930844189d3df40c1ac2c5e0f19e598bea0d6405cbb41e35fd850f26bec7aae8873c883ba0fe69c268839681796ad11c090e891f6cedb944fb4118092d8b4397dce87fb4755b1ac74217d12597496c41370c4653df24c3df308c2c9605efcaa3e8fb55250eef97ba85bac046d6aa82d249fdd348bae7b1f6e658b8072a2aae3dc22920e419e656810cf8f80398bd4dbabc4df89b4b46328524ca43edc03677156dc05a215d2c504db8b28e876a1797ae0b57de85f634151a8bde6002948ae1f540fe4d5f53186fd979992d4bd95c2fffdaa0d02596e17b439ab392ae0f50e6bec0af1ca9668890801d5dd1c9fa69c06ef9fb04b9b0260e8279bf93f1fb0de27d60b0c0d07329f986aa78e6660a8d0785903e7bd71fa74fa1ad87a952a22ca0c215d035817ef038624b5445a326d84ca96a7486058add15801596906b1d78381b9092f504db0008628d32fbca6471359d445a248c0019ff3b8f6157b7b45c14c76ef673a927ac5e425c0a2cb71cabda5b2f323aa037543ffe1c84c1833ac61c016bbcda50b219bca8b2d210914e2e6aaf5483c943fd4e7c68228b26bf751cb466667a66529cc4c19812a8306a25776f5ceb24a601baca327cbaf470a61955474f3d9ae0aa8fedef83fd62d1d1e843a835c3b993a00f09faeadf015cb28d01b01fe5ca49864b667ba0cf0ceea8439d39cb2a9ce71f7b3a5a9b2774141bfd68baacae775d48ba40cfdeb1d1018f77ec090a44ca5f4672f8a1b6110421edbf5014dac6469e980d3e207f43e25353c1a7d4d010974e145a7cb8a5e05d7d79c7f4eeaacd410dab582adff9b9ef8ffadda3682651dbd8ee69d60464070908bec020c622cc00cee15aed981698ca7d413b83b78fc1a2e6c85bc11787374342b243093d26301476c94e671d7008c7f076dfc7d5ea5d765cc4e82b0fc85ffc8c6637909142f4f3fc943170002ee6e4ffb8a3807970aad74a2aa0faa7a3bdfe4c925757497aee9bd3c1ed174e3aa9ef62d6c8df963d0272545e3a19aca824d7ebb9e22d1818f67e98d5dc3e1b3c45fbbaf8a5e053db3fa77af51d975a22ab70321bfc40af2e3828542f4236adb4755552c9437ce84d39332588d33eae8fe5119eccca99d74962a3c9f09ee67eea15f24e58fdeb5536db348f335c67ddcf19dfe848cb1bf5f2be87f5641032816376f9dd3a983822463898a9ac4fa1c88294747715251561bed2933c08be3c006f05a7b3fce71c179e9fc1bb1de53392ba96d0080179c058c441b9e370714526fe5a01dd1ceb43fdbd75efa6324d799955a4cf9441f50c25e456c6436f95fb183851782552a4e3ba51d2597225b8f2b84dbd01ab4bebb18a49712ea84e86297c4be4e394a3d88646bc8da23d09373a2534fdec05540253bb9435ce0f9c1ee444de9557f880d3bc81ae16dee47085dec4022057b0d3cba15569f542939f58609cdacadf9d5055a9b123be4fdde7985a8a4eee0d37032769527587fa1e09cc7122c8323d1c7ca23a98dd63e970031d8545288d6224c9cc034e60731a9212a89fc6704e67f4ff3638366168abe7c5300fa1dc6b95f56e079cc9b97595750031d8d346244a5619031e924c5eaa8ab82200032737621f4e5684fa19c40de1ac18cc6d416ca42dc59e52b07e1a69f3dca3ce63ba55a4c1a3cc761148f83808c62b840b9252ec3fbb2060b9e7c75f6d94891722056d24771bdc8806d3c5124153b2e07ccbb16b02987c0e0ad70a29b48ddba6a3201ed15f4c055ce2b9e3feb5a7ff082215587c9d891c9c02c2eae1c5efd8625c6535ec57be13465f5d4b5acff1945f0a7a11b0e41546b1e8f3a3ae85fff4ec1c89c2dd44398d04e7689464ce2c631929b4652c9e7645684a0857d6c2cbbe2363496c88a5d05050fc76d488ba7f953959cccb5ce8e062c203df001a542cd5e3ec4fe97eb15619a9149022c9ad71b9de36a3a5d257a0d3ccca684666a703ded560df69a53ba546dbade63093831c306d04bf0ab91ef00f96e22edc0e9745ee374693ea38e7c9a66f766d395be678036af3520d65e817f05c7a9e4b5ee15decfdd2c40e6a75789c112a2cd02da7e7aaa27b57b50626a8f989630b47550d39efbdf17d08da5e066039e2be80c51a0221853d0d840fea4e5d0a818de468b455d1a99b98b69ba89c118ff0bdcb250fbfaef760e3eb3098b92512e0cbf2cd32052281727ce17a1d55824fe953029190dab087eb179c5981c1e785a2400bcacfb5fd63025983d3841b2123e21b529bcae8f9162068db42e1280053dae8de583b3b713f2f78738df67188b7a01f40f0918fa1e51ddf85757ce251e903bb996d87ae4c845a420e6333e0a3c292521190d1318d4840446166d1241f4a837b47179ea554e144991857037225cbcb44e782a9c08d58f166da0e7dddd3b05ff2f7cb5ca53e445a3e6c06a1e3e03c7912619a8418606b4b5a6d8df274ce2aad313d5ac4305024352e9219046a0ec8ff68f6d7ce075490b9bd41fc9940f8a73fadf6577a4742f08d0524f72500d944e950ec1a7b45d2bdd46df4bedae251dbfd53c97a4d3c746de80214c46675522ca77fcbb13500597ad629d5625f9c2ea4c38d1334225b00ec20b9127dc4a15d65f129f4f95668768b51b02341df16c8430c163878ea13ed24b683b993732cc35b987c78e2bd25f1fc6ee4e152bd489baebe997a247076d380c092acecb79c91213a29ab370776cd2c3b3871204cd156e2ce3ff091fd31b65cfb824f14f400f6d9bea7894b8e2744e60b68cc0c05084c024e1cf64867a132f7429c9411fd0c9e225f4828bd9f523bdf3f5a8c21b09dbb8f4770bde3a488928ebdf0ff3d2c300bf6f4eccc94c5b1e4551ef25d144cdf78fbab3fbf37f01160ecaf91b153e6a9322575c082c4eefcfcb41f606eacbc87e9ad7022a0916ca782ba8a2bf4f408d135a1605c85ba1e211a78747ffbd1ba7c36589bb7cd801166efcf55a8e2e9e24bc6cbcfbf1ede191a777fb4a6a67a39bb92498b8d06b287882c859d668a7757716572334aa19f4624fbd7dfb3cd42a34f6f12da60c850a21a2e9998bf4256b961200e57621dff71ff89860ab8f1388b889e6836fd22f120d9f42e08f4999454c0523038e056404d989a3dbee88cb59a57efd7c5bd3827bc85a0bc8c02953ed0d7dcaa108c115a48ebe00c19ac6a0b7daac1b1468d6d8252e93f061bc381523fbea0f248d4de1945c704fd01510d54aceebfe791ff1a44852613dbeddecf2e7fdff1e981cfad3c615f65ec413546c787497f2dadcb2022a6a2aa463bdef07ce1f303b06c8413357261f8d662a71d344737504ba69b8be1ea8252e6838ca8936dcd7041dfd6a646d1cc0b12436f3c89a7feaf8f57fcd34f860017798b1cfb22395d2f2836dd02988ac37178f82e5c543a98b8982e59a0729168c866526ce53173da0b9300e6c17ce85a74032f052a82142b290911a0edb93bade04baa6e061678107143823fbfdbf3c06c0dd0de671ab6567cc3ee3a657e7ecf6d10acfe4ecb89f9698307623643468e0ecb86d9d9b18db9ebd3272d674b43d42784367f2454b3759ca6bfdb30a9001d8b0ec48ed1378d40a33524c3a81de9f331833c8a3e9cee970f651dbfce88b26ed8f6a4240fa2907529e11a44d4b35483310d25e3c006f2d7d51432acc216d43a4de48db275262f925ac1669a7e6e9317fac48f5a8c60620767062e78bc4d93c3fbd5dd47a332512d2fda7447f76a7badc77f862f290ee4b89804280f591a6badc290d3e128c46b681e69d71c3ed2a3b6cc4c530e0479309d6287b692e08529de31d830126afb4a4652a8aeb3303d3547d00b93b661edc1b226d6d79a7761fd1e43264a090a0d8e9cca3454ff74b8257714e299ed3c6f5b6648b9c26bc78ff09121b9a485282e4c5c2b240129ac0819c8532b0b9cca4472c180836f7285d09386581375779cb546d4c8ac6043b3255ab1035c1d6e07647f453130bbe2aaf04e5b7bf49d0cd6474c25a75c67901a23870ae77c32e61af3ffea207f8749100649c3cc054c36691d4127bfc7ad18e1f018ed75f0609001dd83e41d6e2ac66964c248eccb2802c378c9252146c8674ac23b81fc13b0089add0152a1141a6472370df94ae57e54ab1c3a26c55f24a1dd0ccd360e794f0a63987a08d50ffb84a76d3689ac1211ea5d8917dedd6abf81476dd0ac1c7017aee6abc9ee1a41e6f5edd0b89b9d99983857dc32914abc1e20c29c2c2882c21923c947c980e43393500716ba97ec56ce33fd4d01240988636baaf5aca649f87fe606606fecb888b6a7c62dc99688774d648982ce1cbaaa3282467050963b31d95c29f55d427d4166b142f767a695ee5be116bfc9455f405c12a1c3e7dbb14564f94c73dc0a7af0aba2b89c172b2fe5f9c059c0a51fa792481ba1fb6f97faed51fa1e1857eafa818290875f34d876e2a17e5adcc7bebc7b01b941b9934c2e4942e9064d836f976444ebff2dd6c52f44fd9132f4a4a0ab659f052f5b80e6696d217568dea33b7a90302d011384961f7809b0238ed7e26a28492676e4368ee5548a3f5be6b7c3f4342ade03db48e82bb247dc95b52638fc38802881d0c2691f2801d0be3a66700ca06e22070d3987ff4d44db8f952832f0a74e43f77b7874bb68fa67435fffb3a5d98b034ae7766999e8c9563366a70d86110deff01dc7cfae0391be8ebad2fe2d816a06daa82ad16587e43c91dcad74b672541420d12c50f82f737de005ad7235436f404e87ae5b3ac732a92a34bfa3c20f267fd4c7ab07947232044ed716b52a0eee6bbd8388d7e4d15c904a4ac17bc8a7c57032a9e8e8a5c30ceba4a078e335cf0db5a938e3233d9e16a503d741755da53cb2b848c86c25199e1245000f93043ed0b8ca80200a4d1cd64118869789d5e90f2b393c38faf9492f91051c29563e737b8d7c5c704dd199696ecbdf796524a299394015b080f081b083dddfbbb0e92e54cac171d082fc24500c43d3192e533573280171d8acfb0e33fc3cc2ba48f17e79700bc38bdd079718ab17b78f8e26c5abd38b570f0e2740200fef30889f313080d369831481685caef5a062fcea0a9e47b518a91645422baa2362f4ad98e17e5171e456408b2077fcd8b52a900dbc50e7436cd8b9f6366bba86dff1cc9aa4168760028e60680a22e0104c59bad251901c5cc0050d40b004700c51b8d480450cc0a00455dc4a5116dfa2180e2cdce50208062fe0014b50730a84d3f01a078b3f3880050cc4440516f10146f68363a0028660380a22e402b1b6dfa4240f106cf7c4031f780a226c06bb6e9077961261628661e50d41d30316dfa406694857f80621e00286a01f88cfe8ecf70cb0728e60080a2d631c2ad4dbf87d175ba30baa20f0050cc1c80a25e81a2ca69d30fc7bc012866ad0128ea1c5054c1367d1c50bcb92ebaa26f3300c51b15088a2afd81a2a6ff44f90614b3e6018a7a0798b46d40f16657998cb26c0d28dea87480a24ae70045adaa59e300e9cd162d28de6c51dbe055ba1615499d99a40227a67136b3e19bd31a5112b09766d4d42475269426457369ad198cc2742a8f5dc49c9868100d923ad9680924d86ba63edf5c37cb3564a1ecca2d2525a9c314862ce6e4464652c777b7e1177e022761240c0b1386c32d5c05136121ec72fa7c6f4e6540c96257264c8a3109690ae5ebba3f5ca32b044605a9336363665032398620757cdfcf375791ac601a93449c2d933a54db5c446c2fbccc10238707fbf9ae9f6f4d4657f445215949636df91d8d4d8fa40eb67c20b2c73f67b1ba7b752315f46e7bce0eda5fb6a9267b2d49007b326dad71b66912d4a63ff67c516362e747142005d8b283098a40f6fc1f76fec654c294404ca94bd3d6db9f7ef69c2a5a7a983d147776a84a2582ccf6f7917252ea5cabe420875486568656665b9e200fb1b0b267ce13a6e7d3393fb9bb3d6d0e91aef9405461026da74892ec49bd6c31f7b03939e80955ab5beab9d30f7e53eae1299cc4113ba16def4bf92738cb47bf50d65aa5fa705321fa725aedc559dbb8ce4bc9e899ba6bd2e66cd0dcc081812a878e1a9b1d3c6efec3ff9bcba0cbc02b92b327160f2d0e4e475f3467ad73cc3407e3ae38a741e7f3714c74e57405e6a17d24586ca645cec5b99c27c8593e6f61b287522ec63ddd7baf067f2f0777f5f7de7bc3bf37c8fdbff7de7bf3f7b22ef8f7de7bbfbf97e7dafcbdf7de9abfb783cbe3efbdf7eef87b815cd5df7befc5e0effd7175fcbdf7de1c7fef002ecddf7befb5f1f70ae0e2f87befbd37fede9d5be3efbdf76e7faf8ffbf3cabd7706e0de7befd5b95368e6affe7befbd3deebdf75eeeeffd1000f7de8b736feaefbdf73e8de7c1cd206783202c9e0e80fc188000767c0440a7070034c0d10087831b2b1dc20d34c8c1c9c0c6df70cfdd703540efdbb8edb79b8d9bb1e96ab66db3d96ab64df3e0766cdb66b3d56c9b8c6ac360db3ea523874c25c340e6d1641be3138d8d0e870e372e8d8d17a7c376d452b9361db455c964797399ccc7a7f18e3e6ee08ca6b5f6cbe59a1dd49f6f0ee394cdeedd14f7b6e7eddf896526f9d898eca1201c398bd26a85d62b58b687f3de572ad2a702ad5eac55b6f7b548f684ef7d6d39ab6697e76d6086f4a9473c2f5234b677f35e7dbd9e5e605e514ecec3a30ae953953a78915ad1247b3e2467d5714c1ac791e98af37c11d2a73e0179911a01933d35ef3d1d725695c968d191f754c87974bcf7148af4b1403f5ea452b6b703ca59d6356b79ef609cc7e6bd772fa48f3d7ad1c1d81e064bceb2af57d3cbcbeb69741e1c4e481fab248017fd0925d993e3e52c3b8eb011c953bdf7ae83f4b14f3b2f3a0fdbb3f19e9579900f156d2fbff7538cf4b940d3879d63c2c89e1b31675d974be68272cdb6477385f4b94701f0debbafd7547a2dbd9ab647dffb7984f4b94ad387d5797126b1bd1aeffd2472d61dc76934bebc991e2fce29dbbb4fb23000785186b1bdcf80f4c140f3bddf80f36cefbd0ab207bb64ae984882b3b0cbfb22d2071f4d1ff6a5922702d9de6b04e7d1defb10644f7def43e749bd062f6eb0bd773c7ae08b747b9f237db0128eec71161ee9cabee7fd943ef869fab0ef79af81e78197b4ab8bb2b8eaca711d4d1fce0acf1165715cd5ae97d2f4e15e1d286dbbc964a36c94d5a7e9c30101a94fdb7e9551d6368e553656d9586540d3677bfa01e4a2acedf572bd5c2fd7d1f4d9940670f4a2accdf57abd94a6cf762400a56d35996c948db2a7e9b301edd8a76ddfca284b1b472b1bad6cb432a0e9a33df900725196f67ab95eae97eb68fa684a01387a5196e67abd5e4ad3473bd2511a292bcb64a36c948ddbfe7d9a3e1a508ffbb4ed5f1965e571bcb2f1cac62b039a3ef90900402ecacaaf97ebe57ab98ea64f56e2e0e84559d9e57abdb2ebb5ed63a5e9938fa6064a948573d65886c76d1fe7e39e9ea64f069a3e641508c8b7889ff653d9531995ad40fb3494d98083715634c801713200410ec659d9f6736e523c38ee75f3dc6bdbc7f9bc97714037321e321907b4ed6750d3e9189f6a461de3f8b4ed833b389beda554b3bd746c2fa56dffc360c3b1b9b6230c36178ecde56daeed68dbff1c9a4ab6016120c321f3641bd0b67f6323e7f1c9c6e88d797cdaf679dcc034da4ba96ba954faa5b4edefb8976aae23cda5b934d7d1b66f53c3ce649906d4b564b22cd380b6fd1a239dc7a73c8ee3530d9ed68b872fa5acc197d2b6cf693a2a9d4cbeb3ebc8b52d78b4eda738a11c3e95641968fa6c2328aa545a63d9ce40db2ae98f7b926de3f4e1be481ff66d4bc5c5b4903a761bb77d95f7816f1930a78aae9b6cbb93f3881369c79c47ecfcf3ef590478fb53698e7329ecaa8baeecbb5c1f3817fbb8274ee6a22c0e8cafec87d996737151dbbab898d4b13ba78a1637d9b6bfc99c07cc06c5c168ce5a4b0ec90d50b995742e666dd6aae7643e2ac3e2dc323f559a0c78019c1054903deeeeeebec3f3c0531f0a1e62145cd91c6c990505aecde974f373ceba757fcf885377b73216dbf5f3a79d6ea79b1e50fb1944e1c62b32c116e6b6e005a48cba165fb88eb65402e8aa3fc5acd0b10279c57568e31ab4f15331d2474a1fdbe3a761644ff7acc9346663c7130a8cea098bb429f519ff6cd2a09851e0e1d2fbe0c88f15ea7419e5219612fcd1cd8fee681af7daa6713bb6d7669ba79b1fcd5aab7e0cf7dfdc600acae7e119a9ef3b3c112a131393b7349d4c934903b9209d134dcc06e3c73b4c745535d734cdb70f3450771ee6fc6108c4cbc60fa429c706cd01e92efe1adffcaa5d8105bd2b2075f05340fac05545592af80abf93e8318fd9e0094e210cbc22149c4473c83d83f7834c1fb9e3e1bcdbf4a9efb258de728c93e1f08a5cb07a78856cb3baedfa2777cd5da76d910034dcf950f594898eae83c81eb977360d695efc1b3830f091db878ebec2ab1b9a46e5ab95d672784634217494d19ebe9812e9c8b4f1774f71784552600b73cb8062eabbd75ee519d1de035b981ef3108b1e63fad1ea400decb4ea7d0b75e74722b3f3dfe764073e7d8e7e3a609a82f0f45e58464270b8f3a1ca5b9476ef19a1413ce4412226991327041584ae38cd30464a2e0b8235d1592daae17970f347e319c9e01c0245ff4964348de88bf7690b48c82b72535c900e7ff8af52693de60ca1ef4feeb989bf7b7102b16b7846f2fbcf18394f77f49af144c8294febf09b4393a8a3e338e6ef5e14f2c022fe4da26f0ee550c18f82d4c1eeae4e88b350a02bac04b524674d58ca1fc0182d4e214b97a40e7efad151882f31fc9f23c7cc0c550167d7b450b73f1299edf9b387ce231ae1c04ef4d745b6f7231c38893238877c0a4d21222e7bceb30905ffa43c6a26a78c02a5ed15f1dec116e607f953ef9e7f4e7d2ccced81297846dd0764fbc40eb60bf18cbc4f9c401c89418c266c638c9fc39db79c07c85d1a7822e4f7bf224773d65a2ce4be14e877812d878aa64b7404e188068f70e0053cc4cfc2dc1b98c28f17f0a3e03cdb63cca47ddcf6e579c5c6184856d24baa9f4c94557de5df650d631ce2e778ecd3af7e8d4f888c64eefc3b94e54fbec20f66e3a8240fb33106daf88336fe1f4fb4e87f57a8fee4f8bd22146c61ee0c6ab0fb68cd15c6390b37701247ac42bbfefd797fbed350d09eef5836fd1c22cd45a9e09df781ddf9a5f529377c737cd022654d222faa26bd9484ecc9811e217dbce88acf5c70e127e8338a44dff31630ffda22f3535e91f917949bc23aafc8b49bca7bc11e1e52b08e30412959142657f591b4a45de98823750059813ee2ffbb3ae82fe93fc41dcc41e8191235729ea35a93f66d39cc75643ed2f695fbfaee84ece9be7e37df03c5e9b2bd790b98bf7945e63b9483f1996c86690c6afa741a8bf5a0459fedd8b3524f531f7df21585499a7a5f39d59aaae87f28f34b1ff19887f55998dbbd7828ba93c3809c4774a75dab4bf6c8fa4960c6a830bbfe0f18b4e84eeee43c1e73e9d291a8bb23d125aa44b160f19c4daf7858fdb9499f3cac150884e915c8c34a6352a7be10fa087d16a62355094495c89eedb9dfb6bf9fc881e274d9e6b0e8ef3207e361fd9c1e747d975587c252a9087675905e79ba3f63333663dda657a897c7b111298cc2fcc859da8d5ce25abffead4857a44ea558bc68fad023a48ffa957af926d592a64a49489dfaa2e7b0eb733f5c5aa43198f388f4efd72fb2c78f50ff90c8587fa7a1a23ddf7d3ea5e01cba9da8556eae503757bd4e596d8a7a719e1e3416be4ad39f4f9f648fa493562ed5f99e9e8775856a77f6d01271a0ed3b149c3c48ee0fd164687c04c9058f50f07ead427f86eab306ab874c3879438b9656cb3af3429cc77e0c170ce11b2104e7a9b1e007b66efb41926d2b0d61841c9f5c51f76ad4ae4f6badb2d65a6b7561df2c575cd9a21ce5df0fc179ee8fa0a239abaefc6ab0fe21839e2d0fa5644a638271cf33342e4a29e5e74c8f3e2769473f107ce30fa2895cad0e4a991227845215826c0d04d96208fb88fc4e0c617bd769da431b5fe34f903df9ad9e2f93f26eec39ffbe8d1a9fd42627f3a53e51a5f70557989f0a415436dc092dd0b267befdd944f638cf7dfb53c8ce2b2205c50f6c79c54e20e731c1431baa54f2e7bb6690ec9992fbb7765224e9c3bea863b59c55f3d321849e20d878686d9289f4f22d9d394fed0312a5f3d39f4f73e6e867bf15ac7d77495fcd7befbdf7de9ad4791ff8bef7de7b6ff579e9bda9fb61ce5a7b185e9bc569698ba1d427482badb4f2f39772b6b4f33895f1192dd55a6babadb5d61c1974adb5d65aadad44b22db35811dbf6a5d7df62be9fdcd509cb96599cae6cf7a6b8ed59634f1d53f64c4daeecdb6cc73c45db97dbbf8ad98413ee0ff10bde90e9743138b9e5146999c50a2b5b66b1e26873dea9bce8a6a524d1a7a391d9bc907c2041640f1a6364687fe44abcb1e9933da93742d40ccac3a54d43038af5b52bd0ae11db63173127262c5b6b50a4443bca630a4316734aa540d199f6eb8924249895dd75a0e8aeed5406942cf6b461528c4948dbc6e1d89819942c67242b98c6a42b9bb625dad93b5b4be36850dba62f725bbe4f9e3ee8ac51482964382b1572456b8c8c8a85d64d4f0149f6bd56a98e7bd22dbd9a4445b28238e0c5da43035eac4294f0623d8204aff1fed40cc942c1c88bf50506bc589b2ce0c51ac3086ea30ac99a2e115ea42950c08b748b222f521684e0ba08c99a30105ea422f8e0456a020f5ea45912f02285512892359d10f0229d81c88b94ca7e91f630c4535e4896b70ef0a28b618017dd8c02bc485f1022e38464f9cbe745d7d2f3a2574180173d05415ef42725193209c7599208be3a68d0f225b883657b9c33d775dc10cfa2de19c43f846e1e601ad504a7f6947e62b735aa499f6e339d765ad5d1e049aba6b1d91857156caad56854a1a6654da3d99a06567b6f9d9fa837e6b4ac69793e0627c6396bda764268a9bdd652fa73ce3927a53f2db5d75a6bafb5d7da69a7b5d65ad05f033bfb48926ed68871d2d68a55e8c40e23a163bad79b820e4ed061462bd44de3e10d2d7a6aa973bf86ff2a95be5ef40929489d8b8287f77384d0a2def763f7fe910d50d6101530207d24307ddcbf7f5fcf21b13dafd8f367128b9b4ff82183963d74df9f462fd0dfee6f1c0625dd91308d9fa6e0f7526b41fc9c6704532a653b9b42e5e94634d28b1bdb8dcfc627e5782754eeb49c2ad5dc4013385054a924b881db089a90672c386b8cb2868c4e20fd46e0e40f710a66106824db390f96c9f9358953923d9e13b22725f3a91428cefaf2b8fa929d95ef7747cd987bb31b38db665af5219ded189d51564542ca39d248cee37bfe48c791ce2315e6e1b45291ea8bce26fe5918a82807b3e7ff8041d797f36cf4079a1fe22c1af071e813f5329b3c9c4b37b468fa1cfd56a8938629da602df270cea4ce3c729f85b96945aa583aea3cb282a92c903d5eeabdedbd979f98023d707b2a6e4f917eeefb5cf7fdc61487c1b2ed3737fe56f02d526a86ec997b3e3d63b26a8caee6cb6098d5c99e55863d5bf8452057f34db0e767d9136a4f2e629dedf99c5791a4cefc9c299a22c5f6fcf91628569f8a64aeb9fde63c582e6da24e1e4eca654fba14c659f3e9cc79f03f8eca662676f3e992cfa7239d383634b469be3365cf033ac58abf89e59b41334916c6de2966e447328ac8cac67fb7ed3e12996d04ff055b98437cfb8ed0df6610c8c29c51b2a788b3985a8ae9a455fe10a775d3bf20dd860ce930eec08b69e8af02de2dd01e73ccaef4936e7ff6f0d07bbafdfc193567d307c8f4d1e56c247828e5061bbf9633b246eee654fd9c01458d6303c59f3efa3529545f8e5c6dafa596bd3d069f137b7b1c05d8dbdfe8607b379201c59c02b78de6dbecdbf87e6c3ccd097b1349d81b68e3e5a64988d8b06103c4913a1b48f372d31f9a772109119ab79686e6b7ef7aa0b5294d0992880d319c2158c1eefb8979cb9ff4ab88b3e55b210090b187b0fce9729e2b7fb65c30611b412a09d9b549ea95c8a46472a8294b6b194957a9d4cb4c29864bcf820553f5c019811f28394ad1b4ebcb3ae794b5f370669a5b3fda39f6c22581edfa72f7d8f291d81739b03d10891cb37fb0f162fdfca1f31cf13ef450a652a9542a053ee8396947322b985f4ad943aca037f39904afbef74368fdf29e013d1089f6168362b69e0732bf713232325aa60192c8e55effc63da765b4d6325afb8ef33eb1f380842593c88dbff1338f648ed95ab6f748e698a5ed3da62fa33f2d23da2da3c1f7d0f33c24f6c5d4b740f70f1dc0f172d71a8fe3fb99791792903003fe2469251909b9806078a145e4c7850f8c59420561948186983144665e49122233a0129abf910291d8f7b81f66de7e343640570e22336093999f81ed0cce7c3333df05e8ca312801a9e3afe399408b322684fd99b742ea27765063066ca222a264e66b804d32112599aee42b513203bab055d1e1081b6658220a23221f904e2f314a9a9eaa4843082292aee42ba9f14a667e03945503d47425df41155dc997719926ae8a2a3bdd25655df79a4384ae4fc2f431926082ac596bf7604a1d9f2931498d8273ed39b779f9dccd6bda8df69b767301674d28bac23f299eb3e6757c8e573d063c387edea0791b357ece6821431210c20824384f9680b3fee7a7e03c746aee19d1344d48065050380370c240700a7da0e6f1353cbea6be6351b4555b66c1026873b5dbf1dd3cfdb4ffeffbfafdf0f6ef979ffbee771ff7ded77dead3fa6bd4781a9ac7f1dd507d187c8e4ff53abe1cef9f8eaff9fc6d3eb96f7e884f580db6d9f1e1afde0778dffc64a2fff8e70ed0a6061473ed6abe9b9f3b87082d4ea809f5a263d9f8455762e3175d48083fb7e39b9b47cddb7cf58cf0f89aa73cbee639ef7688c0e36b7e88efa8f95a987bc7cfa8300e14f443fcc6774dfd0bc8953f940cc5d9b2e1f1edf8b2873b3ebb6d3e0fb4afc1afe39b613cc49fe3f39687f8559f0379881f83cf5d9f077988ffc6e79fdbf89cc88b3ed79fcb7cfec2ef7d0ef32b8e743fc792e44a1e8efff9927b53f61975721eed77fdaeee5aed27b5cd1e11623577affed683ec5aa767a4babbdb26772ffee4b328143c6d99a5cb95dde5685b6b6f68d1d803c1e737a3b0bfcf3c0cc63b34e7bc71536e5cbf9a9c358c71ee7276d0339d87136a688a21595a9ab131c638632fc8e59e833b7586fb09e53cf9797c267bccf846b0a0c433aa89640322d84c318de5f01d408420a58a27050900e931e29e160eb0852440f2e0dfbc6eeff0fb9187dc73dcbddeb4b7f7b6efb64f4db1b2e4bd8cf6a7d3fbd4adb53a6ded3ded53e3ce4fff62b132b494df6508b33508abe831d163a2c75a942ed5d73b897414a2ae1e3836236da21e1803c18c93e331ee7307e278453658d5caa55efcce73ca4459381ed3590d6d882a1ca03f81220d0a6f809906f428edab0ef41507e617f3c679de7beab74d6fdb96da5e664b6daa6ddb3ec8b66ddbb66ddb96e319d9ba6ddb64b6ef3aaf03c189e319d9c0143cc45ffe21ce851dfdb66f6e0dcc86e99c4c9db75c4dbed7a14a148baf9cbe90ee47a9481ff8c8431c16491dfcda4789fcc96555360633141415a39449f6d0ad514da323dd9af653fad071fac0afbd967a24323bf5be395013b2a54880edfd8e8cf7da93f1bcd17b21cec3bde7b3bd2780f43e88ece9def33ccf7bcff3641ef48c78329ee7698fcd3c967951bfcc8d5764060cad56eb094d4113aebce5091213bef6de7b2f045c509a26fbb95694ac3c011440464b3c26d65a6b9178f295041365021261804c482208ef689a1a3f4b96905ba8c0b0d87105587111490912ca4c7ea680090a98c8518a1f7cedbdf7de8b63df7befd52266b6efbd59b4e82c29a8416ef1824836114608cacb154ecc96f0e0f262975c5faacca62934686826f304370dc99e5cb9f7de19165f49a5a526ed01332f610d1dc0884571c117504d88dc1df67dfd65df961833049530c43873d7f5a2a8cac507345cd5015c185da24a45174552b80294305151f282285230a94c38456152b493f1c516638ccf10a22b99f3cf0d32dae414443023308808dab6018c600c125f9c44b0022074706d3238e9321be221bee00756748318980f485ca1a105dc1623c238d9a10902a8254304c929c080c26310e957d1146ce402261915d43003bef6de7baf962186f6bdf706cd24b0d8333a202bc5ce40492042a889097624c3740415453a218b714eb0b04e8860ad566b0a26da320a588bc849511dfaf071feef903bd18c4411bb4e6890c517638c3186a2096a639cc31014add2345adf5087cea801430e5880d1058a9f31c65011c20816dc07ec300baaa207275c15474f3efc4802821611484cbc10b1c5cf84c2618c1fba128ee0a18624ae1841144ae6932e320419618c711090af649091a021adea7e5250c49210c8926a80a24395a11b4034f9f071fea160cce42e859f31c61896e42b393239d905c062a110205c3c18e1258b2b58680f5d8af0ba94c0a5559a46eba5314362965c308c31660213b431eea1cb82461951b41f262e6ac03180382f78428b2d404c61e50b26921859c0822c323198145d2c90c08c20ca920ce30e328da32516482d58985c18635ce5c3c7f9b7415aba5cb10d6d0da0220811784d00e921a78d68cc9596eb0b580e38074b74022a122a87555e2b4843a9e80730309528f785289632e00a59138ca5d8bb64ee501c7c1e91341fe7c3c7f9af42450bed89b5d63e31f2957c6598465225fd183ee009d34e102fb90aa127202a85dd42d3b8269a2685144d4dbeb811205e55a986a46ee9873a8009d7bdf732f1d68e945454996d8cb355420b0d8c1d722ca850c2894b8a6108638c9d6839c00917187ff2f4848a1374618124c61833f9f0713ea84b0a0aa32219c688fa82a50c5c44654c92a6699af653e42b7964e50a16a5127e9670184230f1e104569c0cc1840c430a1745d65abb84155fc92b198b56522dbd91259ac29d2ad689fe9a74efbd5a64f0b2ef3dc2044a206901c58c9f228c83982c9a946c0892df5a6bc388f94acaa08a84316bb98a4009e12064c87eb44ad3688d6fd0966d015ddc34848238e8d1c245d40ba2a2c002862e36fc28a1699aa66521e42b4964f482212519c9624ceac249ebe2cb931fe20e5cc64c7162cc099e98627471e24a54f5408c28ad20664c5c60a96734a518d074efbdef23048d9a664ad012941d6ed0678c3176f94a0a11d9225b18fd1845c8b0a488a84b1337bc649210d22a4da3f505bf20995165a8082943d8862dc61a59b640810e5f77982e8b2f166ab55a31608c31aeb131c618bbb6dc2283d0c6d8b593c060a225017df83817e3ba25cb0d395ca37ad444ca3d62ce643269c8702706891d8b2fc618638c316e32c2cac6d80a4d0ba4705ca0c829622fbc6028081fc4bc8892b840c92243030e5aa4f03065054a44f105d7d02445152f0a0d5cb23c63a4186717bcc08698983fc6788c2669204dbc61fb846b63998d31187a581b20c62593f029484c1c146f26c5698b202fb27851a362c0d7de7bef55c0102d4dd3d2c3089a3811c2e8c7059806241f2a52102e269911cc7849914c235dc96cbb9c819dcc2636bc144394b404132a4ba4ac00cb11627cc1642597a525268c317e828bf6908d1248100514315aa0d81002a3218c5a60b92c1947284a10dba161009391d5b20570400206298a20818bc98aa19264c91353d3981fbe98155130b6502e387cf838ff4d59c420858849c489549c1882660b4b2d529c5ab70a30568c2a3b425b6a88a2822f4870c49319943c29f1a24a9221588b0a0e60ca408a61280bce0b4d0372460f49d0e0c44a165e10c153367e5db497e8a00417b2041e8ceebd178acc86dc321446b68778b652f45333a8035e18b5ec4d4fb49c8a1f2daec75c98e84ae6265aa569b4963286a6699a56e42b7964e50a16a5a5052cd19414dbf7feb8039a8062b2538788f94a0e21cb4340e921662a225a4f842bf42efb4ef184114245f98bcc842f505a0b0b70d0863e7c9c7f210fdf7bef76b7eb5234dd1054a150b282a12a6ff1c518638ca950a2b531c63570d1fd6895a6d11a1301652230553af8c08f1645428c71c4c513938c222b5eb884a317141c143f0049e1d2c36c630c055f7b535130ba925bbb4b2d8021480a1aed892c964cd932cbe2880722a2789112810a2334ae931ff287f7091a829aa2e81283c18910d5034baf2d34887105891db00c398c51daa116162be2e1c3c7f9bf181812a30727c0b852051522b7a6b12f0e44eec5185b0d4fa182102c696202511469e143154fb4cc10021aa6e4f0650fedc841e34806335e512ef8c20823820033b524b19480a21ec000d3da320b8356d1524516a9a0d1e28b855aad56138c31c63936c618e32d474c1be36cc7259a949d291cb64f348d8a29464f90f8ac598c313ec3e52b299489f403ce3052bd6be609eed2e2a29950303ea93c542e4442331d232ccab862044c284144858b0e2e4e8a1aa880e2046bb55a4fae6482b2e2c485c9101eea92a4699a06f395444a1a999c620f1843e62bb9c52049617297178a6820818c66354dd3b4fb9ab7354dd3b42366be922d971091d16d00122f8ac3fdd162888240f518638c957c2597624dbe9256ab2110415aa569b4c68106dc84039525fa6b0c3a1830851394fd7b31de72451a1bdf8dc128c4c4ec96518a14a37ad444886dcb134948f91d7c826af1c594a9d56a51c118638c319eb22d9bc288da188b2562d8b62d4cd0821ae38b26a204e1189ad208639bc64499819e41b110143f685439da4952e4840f3f28e170839527a6174c70d102a858abd58a6225153324410521021fa298587c31c61863df18638cb36c1ac18f56691a4d0375103e4041b1a40b204d9f08f239676cadcdf9adb5d6da28a85c42d4ace51222ca259061a47d9a267fce5a105cd62a1a560933d8943a672e64bc76cef96d9ca7dbf91f27eb336625a0d17a2c72b6399909d56ab5a4dc2bb534d1b4ef6c37b9768d2c6440fd7815a3195e4489bd60c51437c81dc408e386fb2f7b780e60c6921b6078418b491573563486071b3235b2e4a22b99996427185ba9513c11e48442b9f77eb7afdf7b6b2d4307269e68594195344a40e46229fb76a1b20315306b5dc539bfdbb8fe9481914559ed7b1cbff2c5108d0e3f186f50687124b3c86634bc38bf7d7db981bf2ffe8ca1f8e2858d9f461546c9c66fe3aca0c5a864cc184a7b9aa1a90100000000c3160000380c0a064442599ea6499cf5f614800e6596526c50369d86b224485214c510a3000000000000208800829073b4a3001789589a955a9b67b75d52f2f90cb9b4157bcdd2c16ce3e00a990a31292226c739bbbd9835c20adcc6afa81012339a8037382fdd96c7f08b065c974661e27fbe4b6b2600cee951ed6d1c1c96205aba8556c83643ff8511e10c604d7a368661f77c56de01b4617dc87331da1eb9a09829d58134a28a237f74e4ca32aae8855cf3505a7cdce072f6b98838a5d6a375f2bcd63d2c995f60756cdabdf3d30f62ae806482f2e47fd2d0745d633cb442a43114e0ec4bcc81e0860d4f474b978ff8c71f480d3364e88b3bd2e3bab5e32faf69da18b2cec5c44bcde9d49c5e95099b68a5a701e4e6baa1272bbd14fd1e7692dd4b3bc99b8fba5a9c3c8ef5ec7a01abc045be1013800ec5369816f763a72e882d5cfc32bef807ff526d70d39601b99b926465357582a9a4acccd80c1d7c0992d1a68bfeae692239d12300edae46f6ab7ca0bb8d1ee94cc9925dc131abc92cd9dec37e20944b2766e17a123882e69f99e7e34aec1c67275835854084012c2b051d2f3360ef867c98be957e8668364aea0a8a4054494ac64b56fa0f73e6a633ffda7d13a6344c142b028d257aab535d8cb8d4842da4457587a87159ef481344ed96963c519c67e13addafd15397b633a8a08a34b8f0ee2193806ba69aa9f7974550bfd34c867623b14251abaf7165845690ee8d4aafecc1a9c3d4cd2b5efef7c82a8e9adb37d6935613b7d97c1ec4c8d7f0a486aca200fb12e3a03bdf243d0cdf6b57e274dfbed096f8dcbef9150e58292f0d7dbc28fd5854239db3400c10d241b4e16e47881bf28b7815201a36e38c706f89ee09557e7df2edca497860a1da903fe008c478d59a620c59a6ba01f05cdb7e18c0433643bd3feed737260631c9e07d006b5bf63808adbc7b45b7ef99aa0e5083a693e85183120e430db11e3e40907ea4618c467097b8074336ebf41d69d1874b8927312a54df0b10ad126090f2f62175a70ecad31d6ac2c30535e3e16a8ddc8948978012eaa875417b41318f703dd749607b67573e026a9e06665b282c4fcf8e299fcdc5c45993af3108d9f7046db141719d84240fcfdd6f09f3a1a9efe7603bb0744354e9c20019d4e9f5e7bbd596b9fc885e9e5e36f9fc8a9ab77be6c6a20d05a692df0b1253154b6dd6d245696b2afc72accb89cbd07d6ff1f4797a35be9f69ef5debc61b848a4c37341738aa729631219d35f0b839edb3b0d2e07523ea99bcfbd208cffd0ea2b9bbc9596451aa0dfebd42dc888495b4cf1db9a9ad6a0e38963ac28bc74e88861bd68a7ff8fdefaa4de013b5af3d5f2a02ba7e43255b2022065fa05515dbfce106f54db4f28bb7552e39881a4cd65865cf8fb0c5a1b38338633248e159842ba32e12268214f8a898b87fe3865ee5ce60ae80503f560080caf3abfc94ba346cc56d73435b2a66abcc7a44d1a1cead361b9838097d26b0ae0d8c8740f7ee85655c34356d631faccad21663422484ed4a4f5fde07582a2273f61178228dcaaca68055963f8e756ca37296d4b64cd06f6f05d172a7ed8de872a3081d11de94aa91798c980f1db1d6cada53246d0cfb194a6f62a0241bc0ed903f193288c7ca587c734b5be99d57619649cbe0f4c3333ece7b34b58c9b4e27f03f5b974ab95e9c89218d10b1ec4939bd4884953396d851d368ddfb7f13f340bf227dfd1741bb8fe5af4f3ff34e5bc49884ab6eabc5254af84399184029c3e5f463426b2c7c695e5542f3876a1597d79e0ffdff15a0a423cfd07b6eaa2756eb4bff2e7696b6fcd01092b9f5ecfa9e43cfed87ea1b0cacaf0b63910f719b5b5424e60ef026281698ffadf90c95bd336d7509676ee0250887152e543fdf4d0ce9b2835c2d8cd087e5b6e6f6c4aec81e1da1d356a58ede46d3f906226a0e856db6ae22c73f686e3f4bef09d476619aa291edf112a6db9eee92f22dd96cbfd36e35c315f161f0b46d324b0f879bcf98adfd8eafdeedccf22c164249ad8ac917983e181f9f3915ee441bfb6ad680c9b45468589bec364fc56c0eba51a864602bb0cc7161784c4224ae9089b7914eac4ac63d78e58190f1d462b80638e0bda7f4b5021af785c2d7805526776e6f60c979ce3d52ab4432dd815e35e4a0c4f94a25c16741d6911b6896fa3168042e74e8193560fbee3803a5716ef90d40c94fa423e994f9704d4563e9c484af9c5410bd89c4d94e3b1fb3f4e0493d562533e9b8a33f7032a42b646c56afb7b85d5e98267d4435a07e53b1f84a77321bca95925b94017437c005b39a486aa3415ab3194553288c478e017678604c213751d05da19359bc4f7ace368bbda50b60392e5b505e63b35aa39bd0d7fb811f2ee6a0c232cabdff2f178969e5c7fb3bcc63d0a5266cc2af47b925b1fb997088f34e21bfdd7ad8fbe7c0d518a52d68a54158b8e57d8d853c9d7b41062a71f60a10af8796db6cf4f0a7be6c8f36d4c199cdead3c01f747b2f2b830947dd087a8940e63b820f4ce65f5fc8b2e2d0bee4bdf30ab550cee9425a937136018405d5ff245d7ad8c077f4018cddfffab03b49e78750b570a49f50eafc38f9a12d526bcc88b46059a4c234ad28fdc13291b2e6cc106f6b4f5aaab4a50201a6842fb2bb6ded57dd6ee06b5567a8dcec04917816a71c1be608e44bc836ebe3958ce016c3f9857777952765a778f18874585ff4b64e6cd430e319939db0887f30c11ff5528158b08e1792ea4cca196046a792fddd925973b6012e7c3441355007fdabc21890579fc706e18737901ff960b62c22d05b65ccaba1d3d969ead8a4af0cb4bf12d6815562c66d6f3e13f2c54fb4b6ed0eb74c3e5a099abf3f3833b79d176563c9530bb040f2cc04db2c351e6f998d0e69b4396c79639d498a5b2dd351e306d8dc62280b9547fb6615e3cd399f5be9f2f5b9f7dacaa9699a7068a0361a48466a4c4cb17476da2f5f47ea44a089e4849c94e3d0d3597d7afce5193179f4ebbbb45296fb3e1e059b747c7340866b8e310673e1d5fb4ba63b2911115dbfdc595574b2fe99dd5e26680acdceb8e799a95c836ab0d95ad4b2b908c03427d96985045c49a4cab93d0f609765b4210d4aac2933e935c8d6fdefbff8a8f753c03b457ea60173cf748bafc448e1b4ebc7fd64d839dd7e7d5143dd05c1b32ee9e004b6c6aa99d00dab977667a1bbfb1ea856257b7c49ebf00824f1aaaabdf5c31433ff30f503f9635521c3bb9f506bac5431512b0520d378e0aaf4d90fd8022f72d806b13fb283189e59191a3e6c091c75543cd6cc87466b42842c45c1c1e8d0e71e93536a3fdb4d1b8b998dba6df603ce243cf117eeb6817d587d830e262b6721cd541856c8a0347fd4edc940436c308b33634fb4e99ac15d2d5f6931fd3c1c26026f0389838850355c373e04e41188ef2f9f49cbb6951ebca41ed52f8cccb902750158c937424795facc0867281b3268eea29f3f3addad0ebbc8840512141a9eeead73452003ab6759f4d68225221076ec90ec1668c69650907f7fd8ee3af136ebf9e2b6681b7dc42191c1b33dc6e669eaff2a3ed0897a3808ae34541d35f771594ed5b8ee6fb618a21cd6c3ea4006d6783b9f9a58fe76802bc45df94f7f5b16767e193a3a9af43cd6f0968d75e8a554bc605cb00399ff6365158bfead1b489b280ebcd5ed20869684e1de3128354aea070461f9c7c2c9634ce70001e97bce1f355eaf9948ac0330701751cbe76efb18859098b1b79ed39d974a016a58dde34f0e0c39ddf12b8ecbf8d7b40d7697e1a5424b94d7f062f46e184889e7d4be6b0fcf064bceb37c45909a679d3826a0cb8936ac8b26a0e45bfb0a4d22689f3ba237fdc72e41bfa32b6346ee399f6e9bc1350b6a9ab827f80fd3cb6f2004a13f6e02d567ced5c13344306bbdc43686c24447436d390603ebdac40a0a44c8f375e1f30a5d02be287f97b02fddc2aaf64b879c398ed31eac6f900ba8ab2528816cc480fb4799602d3fdd8caad6684898ecd63211cbee13733b51ce5fa9c21b97bcbf4ab59b7497cc855e666d904deab169136a81c1b34a455218a8a74388eaa106eb05050d23cd599c0b1b91e4e39464527a120f8fe91a612f693794c90321131a6bd42e4f0c08955e7f4d9a2db9112b83faa8317cd39fac2cb94910b282f74cb23dce4143925841abad3ca5f1dfc098e2165c3b5abd46d07339e8b1737cd4f7ab84d3250058e04982db947a6231d2ba7698b342020aac7fae284ddbffd43d9e816a87a3de6dcd0aff6ce0db0546392b5fa8b0e9542b6e5fd3c944ef5eb794f6aaa5a3589b13d059de1d2c71b6ac6cf0c0c5d72449d795f81883f62dd32c97bd8ee704a7d4367a014b589bed95bab6110b91a8cf39d23635d994c7c8780437ffbd4de259f678358f3e0e2738adeb753e3396dafd4ae5a3b16f2f30894027dff081cbe640300bf93240ec925b0bf86a6efac326311762adb8167f316cc358293a39821bfe952bbd81b4b6c2dbb51619cd0d6106261c7323a41ca0dd5667c1d9c7f535caab2da27f06787de384f4ecfba96b6fdf15f4ab0e08eac7fa3f6cc713b323c7361bac2e96280bec301cea58518c880e4db1cb61e9ab1488abf04ca7c0920c8aa3bd7984ce1587e6660f2b0dfa42bb0c5fb48eb78037d22bf0aece3dbd3f15c8e073605e04e427f4de09dea961ea93b2a98966c2607436d0a554619bc09bd9de262669ced06e1a2b0cc061ee782dd2e0f851c74df6467246127020c73703a1ea980fef963cbb9048867fd464892f49cec9a1f5ff783117af870030c73c4c37f5d99daae862c3cfa322734c74e760c8ee0c65b4ea7fa5e74934166754317c63ea0746c6d434b585eebf15dc4697ed53f178dbdc65a672853f4a6ac12e7745b94e53429f3bfae444d989a450304f4a46ebc9c491fe7c812dd6c941342b3196dc54fdcc9385e2939da9fd842a90cdd0fbd9348eece2503f9592ab468a8f864f6d41ef735e0380ac00e84e11d9ffc7ccbb16b35a83b6cf030a042873c97dea4a22394a1ea657ccff9d20b2515e133c75741df6091256d2c206b8510ac14ede483a066513e26213128eb84d4a4ca4d9442134063bdfeb22e64e774ed8f77b9be1d70e9bf37454037eeb53ad91c6bc1df58342348ce0ded737d76df5a3976edf231b2df75e38dd26e397f2634bd9acec8cad7dfdb84fe4ba971430111f13619fcc9344e55fcd7619dcfb4b427a1da24e10cab86da1785560eb19d8fee95ea9766f3e71c0b87c4b20ecc1f8e572973cb560d5d3920b951670218f17694b82b30506aa73890abcc8b7300384bf6b258932d1f9205c1494e44d981b7922db02a1742397cd3d8f66379bca28a990a2f9e387fb25e16daebe96fed5a79e729851c9eec0ddb79f4b673b6a9f4ad2239a17ffb39897185b4c266d39778f7bfd4d4ca694d5c2c3b4fc2dad44465aea4297525e633446c6a57e5f781983ee1021776ae690926950c4d6095ab7620b78ebc894d4f8a1339f109a79956ea64caa05acfddfd52c5b2af1488ecdcb0b9982297219c97846e9c14f7c6b2d561059da05febffc313935ab09b6e3d3e6fa69bfd06cb36ca4add2df7e66cd8d5bcb0a6f1801d39b5eae9b1bb218558193518f763a38c698a702df231f8ead8bc9d6ac55cb495488b18386c6ae39b58433ab9114de31ff5d1f4b7a727aa9979e19c75de1cd68f2e01e3e4f3f3fcc104e5361fb654c0c2c0aae4c202f308f370da17e580750c075e1c2cbcaf86101a7eeb99380aca3a15c0465b9375b20b912bf46c4ce9dc691f34cb057d28f458be7b3b25956b8b0669d234d2497ed1122ec3cb84aca600a4111ddd0d13073647b901ffa5becb4a8e354435a900668c127176ca3d40301cfbef411a268e7218f7cf23e50af1e0e4e3a2b2c323d3a4312265cae7a124d426a09dfc6099eb50a25099703c7da69b261dea18cbb6455e2a6cb76d283ddaab5328afa244588b52ad98df7ae3200e1558b00b1cc95fe3fd5ea8b94ac8b1f98ddc17581c780394bd45db415e705914c22efecce660f107bdb2ddbe618168781ddd0142890026c3ce6f55278c0c5911d3e6f9a371e5332f3c5d8c707217a9529d742266b51f8cf069f3471b78feb66cd8cd56ad1e78a873e44ebacae533e0ebbdd7e118d785a67286133ca6023264953a19ad6a215bb961b7b1350058e43a35e6b22619893a16e45c8e0575ecc3cdc1aff031900e37c9b8fca8b1265fe15bddfdeaca365ace8cf540189f30de1ac62cf4688007a52a0ca3199eb76b6180ec718053d6cf00b116c20b9203de1ad8cec04d0b8dffd63b28aa32f945bf6703b0140272cf50939a40f93d342d2cf143c3c1d38d573d0599cf963fafafbe1672d7587ab6cd9b7ee641f038dd12cb9b93f94cf7541290d1ddb0258159ec7105697facfea65202212d3f4c6549731712c6186ddd32888562aae5a3aabc151fdb64ca73b84b9180b1a753e9da5ae2eec31adc1440d814ac76b75d0510f7251a633234d0801f812dfb00b73bf1608c6471e0a127edb5fd6cc403d0c30cccb13f2a7918a6428428e11f40c90b3bd7121d717a5032e5791c714fa966e258c99c8c529489ff5606aa729cbd7f865836680a8edcd0ff887766e65ebaf81f215009b466ca1295afd3626468d7bddff5af49e8840da54e7901691308b91e6619afbac60f621595c6c7ac3ec7ddb00343c1e4824653b9c6aab38b30c052236b0a39910517957c391bc801fbbd8505b9294fc0c9682c53537112b056537dbf7bf2e6d752d349a679f0a021585863183dc88d5f02faed84cfeeda1fcbbe2899e2cb38098b5d815d408bb03d3b8b5a6052841f0eac59b9914e783ad42ca8577caed35c3eb485be09b41c43d08fe53acc92b763a1fed1f8a453de2556860c3b521adf769252364068ed6b730789fa7a0a66fdc475a61e1a93c0b8046e4b6bd11aa54726faa50ad02f00936eea76063a81c2a22e2350dea6d6d595fa30916d7f1e80ab7fe82c21336cbc289e3c5e08a6c3f2e0d7426ab58e2b6b953040a60bd8376710b639f5408dcbcdd1ecdb3501a3564ff3beee3a5d7ba0a6758bca2dc81231e0233217306e6283071a93875903b49955ecead296480b233d18fd9e90dc1c06dc621c1e1e37c8f6d7bea717f5a48cebeec09a7cf974ad3eebdf259f9731ffcfc732855afe4217b9190d7473185ec11bcb2e56a42cf4d57932b7a5fbe4fe0900e4e1c0afd7ddd3886e4564d801d9bc023ac63181ee9f913a0c6e013c317474340e8fce98d6e10837a197e636f782fed760c1d21bcbc473f8a18e12243a15aa9bc69124080c97095f74544a121e55fcf38c4de25e97d7f9ac047f3927910d770dcf00d0df614e5d3aa0537dc4b695525805eb702025228c0cadd5f7bec55e0aa4b6b64d4ab14c6e41ed9771f07b6fa135764ab2585988bcee7ff00f6d4451ff7f4ea4578244f5a848d496cd4ee1dc9d14d4b6109be34551b7d781d92058c43b8f700ce53611df569fcc1f615479b6b31dac4a62899897dbd3d066095a32aefaea928bbd9ba5e367406dd8359b9ed0c1a8c15ace934c229b0e8f0281671b316184261549211124506650e851c03036b1ea8c858c428de10ae205115a1cee0a593d4e37ef14eef1582caf7a8a96c52291772ba28a51b5df6ed897527aa45ee514a6641fd3afeb29a390247d9ff9a3b79599ec9b38301b50ca505f8e5bc9db5a69397e36a663db6524bfe555e9ee726bffce6352a8877ee90a17ed44da4f4028892ddb5b9ac9073635a79c7a04a62ba8d3a196654e07ee37fecd2d94a4bcc10c81923b420d8bb30aa0cab28f384d2e4433214219d123c72474c1e8cf8203d9ae303a22a5d0c7c8a29cccd9e357e8711dce9d01628d59a5f1019a24c518c02865ae754996d5877c66ee5b9b8128314485706ce39a8a59f62198088ff674c9db5304feadefddc6a53ff5753855e1743124bae4215dc1df5786896e80330cd8205ba3921a1f7800b16049dd546ba937b7b1b06e0d92f4e496c2e5cfe16eb2de57032cdaa0c92840d04e98c5c58a05821d4d29b6370000bc76c7bc9a303d4aa336b6798b0dd11480d6916f8c164502c38a598bec0a4560a6b7ed4dd5fe37343951320dced3e2af9c44665ab358d9dd4466d9abc90e06b32119e3ef818a82536be931c2c1bee502b4ec8d0293c78c5e78707d370b2495f52c60149a5de65c05897e1db3aa52fae888a47bea337539644803957c5ecc7969473270fe7ca7022678b75e6447e7753b296166e8c0c0288aa5dcbae9718ef1003f5b850bc0e09af26ace3b98d6c94e5e6c3b31724f87091d8f9ff2d1892afdcf6f28f44b0a4fb1cb96e8f9671c840c20a00eabf249c1b2e4719f03d3ff9216616e617eee4eeea27dad466666b181fbd87a26a0b9acfb943b803a80ca30125506721cabfe288e8defa16688228a8e977273afbeb419d400ce206614c5052b257976b522809d31aad04771a44ef1235c3eb4022135ba7393fb944ee74f767f899b392605a93a7b2c1d6ed32ab85699afa22194e6c840b680acd09170a72357f7716cd9ea73dfe565a6146de9384834c24d60a176df7ff0e7b1fd2a2d7272a7bbb47936f108cf377e0c157eb8ae1a27278d613ae701dca901e1a567bbf152845744d0c5df4e370013e3dff3c91aa8d91088d25a3adff19d341e0423d33117bacd8ac2d3b7c5ec8576c8e6008227ca1bc9c645bfb190970d69b54b11993041dfefeaaba69ef6f988e71f4512502626b07201d364c84d56c90fc3f619a9b24b00f2d19eef175fb6c7c9db3703019e000c10c5ea0be93c3699fc5b94a283ba89e13f2b5a8afb2a3af5853d5070ffe843a1e9caabd8f2e3509da9316711ce0d398dcc19c3ad271ad5cc3475b5c11107f739ef604550391d957d662fe4a50e34726a73fbe47120a1e247b545e8def59e39976046985750e79abf9b4c5477cd508286e1011c309539850ba6c9520bc109b265b6302a0b170a0bc35f4f59ac0244cd82370abafd888d4ec14f56e502d53ef24c03f30793c010daaada864dc5aa204bd4a30b7b243ff1152533a945bc4836f89cf813e10fef31c07b5b7d0dacd43ccbea61880c8bc35c5f0b4f5e59630a8f1aeb822febd9320285119d72f15ffbaeb11a4324331e2ce0a9347af1e9101209f680e00fabaa0b4645a4e04ceab5e373e54acaff45d57717d929c69cc0c14fa55abbbe0312b563e829e464aaf3d6635ca1cd3b2d2de4a39e79efe3f55b847fd947c36a13447afd162213f1edc32e61caed08ba90a20b5e6da074b74a2621a0eb29e6541db16ab48534b772cad16738898bdfd3e842b890a6369c79b399f730a6507b4087d1c5eaffa76078fa59623b9aa813db321c290032deab6718561743f2eeb1853ed0315344a00ab4a423c8cecd8d146b1535ed25c0a9ac2d15cc31142e7ed4cb4151a6dee7a89c36cdc3dda901a771b5d23654f2fb767d2819d72d20c37795e493fbef4f9add9c6aaaf9103a6c179633a0c10d7b176b265ad039a53e0e4cc37057a2aec74f6061e2b3ec963f18aa9b0c74327c9c80a1afbf5cc133c2e890ade8ec574fe1001752d77b49e83ae1982e88f0516961b742e0d5044a4aa62db5eee43b47da06be9839efbb397d0bdd8a174e4ddd364e5a42d54b15dab354199c7058f06817686f30a907385fbb0ae55d72e44564ae994bf3d9782d1483d2180633772d4bc2d742488b5eaaa7fba0027c3460ad5b487be964988395d633cc33a7f3f94eeefb22db89413618f0502b875abe51a563b8950aefb3f57c4bd270ef316d762b7d7ab329e93a19a5dfd506ec63d200ae5a63d6e02d985611481c64ba2613238deddfe28f1eb0b2956934395b06c5a61c1bdfeb857736a3fefab01756d581a4cd30b136f763f6cdf2569456f4e04439f20fe90c1485031132a9552fcad82a3899445923a5edee0307867e96ec2e7541d3b5897b0de141b01703a312e0c2a543d9e50df7434fde4857117dd54a436845d57a7ead81f89e54ed113903277db3bdc2a233deda93ad255f118748b2ff4c9b8e190aeec224a0b0ec9c8e3aca01beca1f3435584fcb9dc421c808410f17601c3c4622cc40e481dcbedd3a18f464794159791bfd98168fcf5e7c9a2fe2a88cd955f853d0a690e4b53095c1b83fe1f72d918431b218f9f94f900bc624bf65f6e2a5180f95bc259802aabbf352c83a2a2cf586b3d4cd2a5282cbc2c96aa5f402954d7db7224c611a442429c39d33b0b6c4f57f077afb388b46d666d8a9290cddf9df890856b65c71ef967e03d316ba7301edeb98276a745b202e45e1eecc6ca12e68804626431a4de55328eae00dc317887a8d28a234beb74a7cd19650fd06da3ae4d006c0e850f09eec6d2d5549e46f0180a21e6ce0c8d997e327787723caf2e3e346b23a9d309f0f16e370ff47e43580429d0888ba247ea44a034f1a7a9588982170130c0c03edc250f928f669734fb7c1e90bebab943662ee26c2344357632e7aacd0cfa5d47c512edbdfb70cdd173aac1e70427c81f74970889e79110b91d80c3d6440f49bae8b98afa20a27ca8fefa46baa837ff42a94f952f15342798e8ff3f9fc773899dc29a00336144d71bf7854ba10142ee4060303af38e77a3e5d3b0832ee792228e2c707b03edb572382678c336979426834a5d1b55298f91296e9cdec3e6cefecd6c0f43d9308b54ab9c5719fc0d9062eca721844d4f6eb6fea7e959d720a06d48100c4620a3274615178b1b4a4d7b53d713f0139b51a02cb46c1488b587051cbcd70cad1674047382e9234828ff8b460d5e15e194498abe6e51143f6516eb11859e6c8e8e8dbee3c976ec28e408d81c9a5d390a75e5a5e2b06fbfee77d4d380ece5015ff9e0d4b9154d3160f627fe2bd847fd1298ec42eefb6d029e91cd7f2060f08270a56b6c04bcac807ea68e3537b2c4d0f1d4ae41d0370089554c840b586e59cadc9594dfe893119d0acaf1bfc1f65b83392ccdf8f1b847644c04b4d6ad7fd5d4ce17989dac28253b6e2f3232883f2d8ccc30581a68a5c21c1b10bb1c93a8936a55fbea790fb8aa7a1b8a5f31c1e39e040d2c5b457b67c3bf7e4870f4677f4a19c58fdd3a6c82da9929b4ad5484d34d8219db0c9a4cbf5a606232c40a137fb50e0c2c85488b1430c5b39f72674c12276e356a270cdfbec9fa705fa874653a611ed8e245c7ccf69f9d1454faa1c3dd1d6a94397de4c79d2f0902f3a5262a16274edffcc87b631b3948cd4cc2947542cae2104d86ac5f896115c782a00ee4a89177da304ea6ee50ba0aad21c80c5c34f787ca23e1003fba884d2625b3a4bee767a0f10b2747ca10dc81777d797312079718ec227476d6550449152b3daa840d252f6f5b10e82f25bc9c17ed61e1bce605eb46ce8758abe9f0dd3911b66b212f1390d0506d2c11857bab27525b5272a5a4b95a0357ae5f0d2c4a8350b2e8042d740519fbc09de395c010ee6b4e22755e694ad5df71b09b033b765aa3b22d527eecec48cfb47e39097770a09141e36e45d12736344e32ad630361134448d3b126e990337d485f2279f0fca461c0fad128f530fc15f8b923ce006407785fdfe2a06d5f4194e016d6f3c57cd5ac661ec10a9a6a8f7ed9f69272d136376b182fdf60abc24f497116f4d572a1b636f9eb7e026ef184484e35a07eab254173a83fbe147312c6106a646d9ece9d448e440045e1def6f90b74466721029b409240a849e98ae9646342e3ad809641e74ff6c92eab02023255043d1f0e0e67168acb766272c1506bc14e2164b4ca7101ca09d33b6c3361ce6c2592526bd50990ee93235853096f573040e6daa11fe543f02558e453fee17af8c669890778e7b2c887b3ca9af3f419347050bdd07088063703ba12c100239ed2e9d56c1ee7d00a832a0b5713e5c0f2f45fd227757aafdd15938fde3bc5b417880b7e49c89eeb35a46a68d94468f7249077eb55d1b9a39db78d86de774aed3e3e7b574e61363daffb5bbfcc7dbb1f049b3aa9e1949dd566bf9d31c9ebfecf8b1c2fd5a66253f62d554c874cddf04a4e879f30f0428b6b9990b36d68f1314dbf3d1070c1ea71745330e60fbeb19ce7f9583de72b7cbb76d79b00991072505162a4c4eb6d70444ca030b88416de653057f9f1c6e1df800e13ef3d456c6ce9eaf825faaad51d7031f2a06f51d23f475e89a6621ed9c2d6a9c38998ac10d1fe344e90a106e41843d1176883a62d35dd119102fc7428eb9baccfe4a786dc0364c5920501a97e176d7316969f876f6739c4cbfab26e1251cf021cb1dc48bfaebc7c2a1661e27221c05315d1f41220f8c2835dd4bcc4b78567bea10c8ba4090021bc650db5232ac295337e7d40d43896e5d733f5fd8d95117c707a8d5c662681f4f3bb9bfc143d06a2d248108fef9506536d4cd3980881ca12035c8604f2f32161027ce85c4f7507f0873e2e7ae53bef9467828504d4e3675b22909502c79bc87394d48cb7bb209d60dfa89234ebd8eb3772631f80f01c85790db234ef58808313f398ae307c6f045a3f1ebab74bc9d09339e7770b569e744937bc2763cc4d6636d3bc682573ef2b996d96fd699dc7cda1c7c6ee590c6366666636cca774c5156e6813420e5816906a7a41701fa0dca1419b42d543b2695d649ff95f67ba61807f370200635939b47dd3c23f4ce54b1e5c2e155e9496418e240f31c7b2462efbb7579e897432e4a1664e357374a246216ab4426f97827616306dff2c7153692b3a8f433e40dd47ac317836e98ab48158b0daf241273c5b1998eff9c2728ba6575a8de0d4e5506ed77fa35c0cb61e4f899c3888eb247b615ef28ad104820a97474f8d5b2c430c2560f68b9e27b8411fe0fb85496d3c5b508c7828d3c3a536412607372ee4ff630671c31047b250640e72ed825d012aacabc7950998774a54156f78dafe42781fb9a8ba666fb8c4ae8a4f6de0e43508321dbb0e0a243669528246c8cfe34f41c9e1f11295c46ed444e1825b8a076b0ef8376b6d321ae0bae95d83ee51f95336304fe008fd93f82b58b36cbd5f822dff0c78d63cf1eb2d40e9d4aa7f365aa688f6072bb28f2643fa25816012b3d328a1f24e638e4c016f43e31856744d88586d60ab2c6072f897fdc64f9f3bb1850bf400f4a378dc6bc46833dc661b1e586a0a869c826b54d5dfb1d7c2c9f2a21bdc44792ae0dbfd8ac8095f69b919d4f58060a2e88f988ab14871c0cd63f0efd42403d717cdac51f26443a69e1933386744ec296d79562831dddbcfa541b5726ce8eb1b64cf3ad9b35cce735e90ee36865fd75c97e4abe6aec350fd9e043835ab4b026857d392d8b09cb41d5a4cc9a35346f52abd1d989a9bb0d62829e6cc4ae43ad77095de51a73fdb46afae55203c86bc182cf1e1f22981e93851ee4e88e1b9a7ca2ca8d1faf6a9576bf6547b6e63d40f188b1c52c48ac51d7c215ba3fc77c5070790c41a409a2541979493c9320b851a44767df89a11912e661a85acc95f226283ae522b6ae63592fb868b6b74a622d80e80e96d4d9663eb78ed2a40b2d824a4acd9540db9a81c3831b0a06aaef679994d5f2e10c4d71264b7d41e3d9c67035789034f91c479d5410df09ac25deab0238987124a67770e26ce4a54e42352334fb10c9ccf3a7d0b00c34f3a2e75fcf1e00e52678fc3210c6228fb8e510a0318075a6c0082fa8b8ce72ed2a54fd8904734f199c77ec18d217a34d1a225c2e8c682a60599f0aa0af2649974306992da04e251559a4e7382f1fd3d8a4ac6370e46c20abaf6099d2d84016e9f2e7ad6b5cff332fbf7abeed81798cfefdf44f2cc700e6f62ccd5a2006922ff8461dd0d892630f3709aae03f3b36daa95e53b4b196ceb21ad33f81ef200c2e57b83664e44279bc9f4fdfeb5e6fc92f408298ebfc144551ef4304019ba7b583111f9c30ec66082de8bc081b90ac28d273857f285e61aa311ee13b676c4961a28d3f102b41be004d188ebbd6ff37feafa90bec272ceb2e1ec33a0099770c744416d9e5341c1ccfc1a588b6a8ed54fa65e78466ec6995df8db07a0d1e44a801adf1a85fb14b19d30befa0cd0bda14357ce81536c29445604f3775831e43504717de0ae52972832c8820d74611b1a2bf0ea6483dcad463f2d0adb56d6a45b6c4281e32c715e9709edbfa7089629dc2dcf70b4949632ef32dd77f1245a60c9c48b161fad4c855ede1c7ac0604324da651c362a776bde28fabcdbd30c5108855420f776d40b10c9d5dae25c1ba3889f8cdcd54dac626df8064bdf56e765519d82faf2bd9124f804a58b2fb0fec80bda3bc0ec798848dae2621a1339a1bc2802a628f5259cf00ac225f6ab086b6786278532562970502f380d49b3954da170581d96b3bd1f79d34afe3886eb49d9ff2287f1b5f94691089d46fa9587799e8718ee1789515ea918f42f8b11bbed6a10451ebda1d12be87cc40b3582971c9596df7827b1a32fd45f3d479967ddc34d3370f8e12b0c43f5e6d49a87b2596c20a6f47a4612bee31ac43da2f96ec073ac1da3bc56b731fd774d3f822008ed3969df670b48d7223108c3451d193ff1dfc9de0cb000642a8f188b5550118ea17c95b21f68507e705d6d125a078929fbccef65f63d16e3516e1cbc4e80aa894dd00c2afd388199ab9de1d1e7352d889c8b6d3a637453d0ed844ee3a01ba52fa16a147783217a2029cbe4680d14fa0b5ed0d8058073c18ae9851a603d9fd02b8912ccee92526e75f0c42d89309de25c7a3dcf6c3801de6550e908c58537a9e41864310661c61e94672375efcee09389dcdc5f66717c86c744ee8d50940f54c85f2fc9a8ee2824d22b362c507ca4e9b7dbaeb0c80864c58a0d3358310b769153eb580d47913127db0287d75c1e84dda7f1e8adb3c457e010231e23be631a2b806724ca20ed9581920fd857b32ecaeb0a1006774e1816b983bbb29cd0351c6d1373aa10e8923ae9fc94ed108a52fabc4b0c5f1544c59c2e0d4447e50e5db7d8d07024d204d597e0e7ff9a4fc7a9e5b64c171939c21005819fd344ed80529addbcd97083213b8783a0d35328a51954c085bd1fb7416e21e4ec2218a2423634bdcd969cf5a593beb36ce4cb7b0354c6c42d0e4a870332fb0a4b6da29f5fc4bb5ff2a6c355ba6825addfeb60bc0c287e97e6c951cb19be1371a419e5bac0b9bfc3f28690afc62aefd0e9f18b04dfad528291efee35fb8b4c66fb9bf954b9118f2ce1e1276385855ae0a2267e9f8e665b2c6cee23a5d7b4b9a7d82409c1b1cd2fb1af8f0ca03442e0761c8f4e3ea25e86a46174ee1ebbe84613534f50e4e1ad2b01645d9122082cf84d589198c717c228fff447c95be7b5e558a85e52a2e94c55eea20ead7fb64e565d32b50b7c110bf4b8505bc2f1e07d76b363472db05391359fb902cb97dc265c6cd52727704e6134297bcd346f58d4218dda55f9da213796d347867a569c5105a40ec6f7ccf046aee230a361082874e115264bc25a270cfde7a198052a3c24a6e8e4f40cdfa66e9cc0abc9410fe492b4cf60af66437d5897896d8e5592e86cfc651ba058f8c87d90d4cbf6270f1e46aeeb1c4a3e77847b169b27c339a87b91d66507156f3e87a6331ad5e4e22bc89e3b6416739dff4813680a8d0fd9bf9ff9b52191dd985754f271d4cd9f21becb512408d8531304d380c80da54ab02291326d27c6defc6aa9ed1cbdc51c05cce30238fe112e2f3cc326877d6aeb472b3bea01b9909edf4fc2c16a54d9bde746590652bc643185dc07f3f15347bb2acda8dfe1cae8b9c914d4a3c8e767840c7ffbf0381df9c55ede8ab9298aa18428d5feb46410f388b846ab63da3c946309471f5b0a982686a5988502d6e8f1dc74c08e7ff1bd320bb46e1780776109c2208eb1417dffb95a487597740497726180bbda7dbb831979ea8a51b44d70800022a8b4223fc942327e7c5754739388a7f76d4c397805dd72887c8738756ad7ee74939376a8d49d7cacf858bf0a08a5aa64ca0caf348114b309066c67a6868255465d31554efb2bc42748dd9e69484573a032d9a0c880a90e3e12ad2dcef8ad970d8b04e3eb8bd48e347a658a892c73dca1c9748488ad029173fb7d58b753ba7dc33005f4e8d3e5f3e9e442da81be733bebc9733b95d55ece240f71e891c79a64bb23a8647f0778a845858ff85ea61aa4a926cd5bbbb9d924e76017843c0e35186f0aeb8ae12098c4caf06b2a5331d83006b47d39f6bb84f5add049e7b46c744ead670ffd58a2ccf22a618671783c387bb810662f1957d4e079e2de68f1c421a6ee779019008a2e39814b144a6578d579e121819799201ae4679499b01213c686037a6c28c35d5a1b686f1a623c89191a19358ec71bef62f6a04c4fb52b9e1399aeca00d993a5677e3d460200cc2372ef0dfb911543e44165453f1f23f6b787dd77772c9734a80443aee6a300da711e271c9d70960df3ba5f5817321da3d434d6c1313365f709340946ebd6b458a061b6eb73eb91459b00ffdc300bcbca89a16068d22d3e910624543c395fa9b28416518f4acb060ecf8cda51427c5f15b8a63f1c0262cee1e8a7ed95d7264b5f43170ada9ef062fa6a3f3bbe428ac9b42bab5bb8c6fdff66310611422fb262f6c5e1c9bea9a2b3a45c6b1dd8ebaab36ccca1a99d75f82fe1d1bce7c1c283ccc3db84842ccaa34245d895d7f67fb379cfd6613226ee557a368cd37974f8eed68e8be29321ec737d5b524c1e73a25f64f1589679b2ad1318d6dd2d825d27e5abf1dfb89b8587bc288d5015315f5a54e28041e73749d522a92db017d75e1475979b91da947d821b21723f3db9295671fae647e0309611ebea3620bb31d7f0aebd4655df43ac39515daa521dc14f926a59a5177e338b6f2a38a4459581af11b73f58b9cb2e7b05797343ed813bab7d56b4576d41f3bde6e27f6b9ebcbad079f650b66dda0518f4b2c86db180d81e8b5eaac61da76509846def8b79d8b64b12a4e735c16af521cec3ad27b15cf44e82c46012ead88bf4485c5b60fa94110f14b54f12c21c3ad3e7114782a589e79025562d2ef3a5d33cdaf40ced8c094d900824663e18ae84263c07840536c220a17d5c43a6e85fd2cc1462bf1bc690f48c273bb01b4505a8da50464523e594c34734edd07e31e8f93163955c7ca056a1f223d174272c59725bf2a6ca33084abbb765355a19f9839c3d6d87f7ff2acc55a79552b52211d1acc5017429875516336307e3fa8fbbe2cee7a817f2c1aae411eeef09ac0a4ef27b4ffa4cf3a58ddf9037fe984af5d78ada657a779e3eb3ee20aa910e1ab38681b03e1ec76e7613af7ef9ba47350265158fb494687f2cc55bb6a2d67e0b53a334bf585243e13af5c2452c5e0d2eb6aea38cd91c4275ac567f8ac729d47c61335cdb6bbc4317e9679436e5bba709654e49d96763063ffc58282a4fe1883e4a7046913bd508344e2e4a2bf6f6b62f6ab44c099d8948988d3c214179389f9bf2d43a42c5ac20ebba0d56865a292f1ff3c93d178df2ad6b311021af1c2d871aeaf2ea40b1768c0ff3cab3da038b08a45e1019ff77699096470c044a48d727bcb7182193401574558fe58b61b56c7ba3585a3f4400c4720206ab3b0570e881637a0ecb05885458c5cfd7929e13ca5a14951b18982e92945e1579a6ae36884547c38e0ce353195ec03e374e07f65dbde85b2e8f174a0603a579e2132496c52466d1125b30e68afe2d96b546135cfedb8adf98e8e882f2d5245939ca446df3985394ef080dc324ab9eb061d30873734f572e922d3abb2faa370f4fa27d59b1362fe09a9494d1c1f015120e0219a610c8a582b160178c142eda3d49e2f3e44eda428ffdb546b7af3b13aae2e80822c3752c041a3932aa0bf2e94492939a6cf95961328a6450beae94aa1bf0b5effb754c98cc1cf492edca4859c5f4b26fea5cabc9692c8dab6308091691426542c378737db809e28da8cc34a699b75427a76e2f2e6493c1958a35fb75665b9efa57297b107468c987c12031b34fd6b47084b59f553e9833bd42c957faa1125fd1981e644fb2e738d30dad10c473949dcbfe1d3855c3f0a32a2268b990c7443ce0c3817ffe1d0df8c74428ef154f0f904af5799954bcf60d85137fccf076e31124610f80cfc1131cf42225945f469c878573509c0702920cbd0e1ee56ea69a7d490580e0aee677ef78eb05020282e97c7b2548856e825c67f0c35fb6185c23da3777acc48636401519f28c93c93b875e8c09ca28d092315189624c1deebe190746df0fe88082551b308c6303a3417ed682c9f1716b94adc72b80787f0697a4062e6f891b0701a7a1ea5e5bd66c9baeac354de33ac65e0d995e98d91fc98d79c350e29659dd93c7c1ffaa83c0dd5e70312da0137d228abc1f074fdc606caea84071a0d1cb0869d705137135746e68c05260471ee501b31bdb490e6cb7d6a170a87274cf30003d1262642c2372fde55b048486d2dcacaecf8cb280fcb530a3074bfba8b8e823ba41600428cf91605641879aa3d1622b5be95b98751166a27011f6debb0803dda2305dc5c3120986da95839ed014d2fbbbc92466991ab207ffea54f17231cb2fac40d9682c2e1df2f48417e11feb2679f20465b474202cba751a60afe8651da7f84d118e50b4d38f275aecdf2ef7fd89022e3968074dbd00d14e23ac3c533a82c1daeec2ad0a729c0ab65c5c0375c0234fa9d0cfe4b4a89c8e3e20cc522b18c73c56d62638b19cbc7f3a0b5d03b108fd1b912e0c5458b14f3cb6bc49cf6158a035a77cd38af323618f5c08311d77298ea4324f08266a6c561c0a0188136c4f47b16ea3603648432f45764eec0b090b0ba6fe03bdb057e1474e6cb369fa78a2ee484a13aa2bcb88452d7977b4fdca0d28829ed07f09d3177fba494240d11bf0433cbaded6ace02fd2d0e7303f0634a00ed92a6377e48b14a0483d560bb94ab55a4adaf5a34e2338483cb14440e9f8c9b172d52d59f31aee3f7b73f1f714048fe511e496c8550e06a700ade3b983a0b426d5cf4f6e29746893c8717946c88f5249005a271637ead003df1b2cd41f41b08dae54c00d2d4d8f42a3b100aed136485b260844d9927126265f7a1f05d301499df38d4a003d27a22e4ab0f382b559f66a87624ded8aa84e7e623730f26da39f20075f6231852f8f1004b1cc032395bfc362aa9c067209ff305ef02d2c6644579a9664781a903c2a45621d8ed70839ab84f3e9a952293fa5e82915dabf83f07de1ce2652e0b5506cfb20f1d0648ea33180f477c69e451a7b58856312409bea0f6e2274e65dae8420d8bdc060adceb745251edc9fa068ae23006276eb161b7098a5432fc9d81e81b0ca498b24820e5b53704462a4a655c0146540ca16009db6b9c5af9b52d23b05752d548596c60834878fe92e070fbb5daac7ada19a6564d4fcde160b013f20ab5786d29ccb5d05ec4d1a10368c2ca362b935d5b2aeb19ca10120f34403efbf78b6f425070ecfe16ddbb993dcb5519adc999da7da9a7e3dde8c2cb9dea2fe843377c538dac473e6c06f812ec5314376ce44fd69b872ce849ae27273c392a5965a03674da7580a229b73263d4b7f48bbff652cbb78b6e69cf9e0ccc71363af5a23a084c6effd28e59ed35dd98ecca00e2c3f866a7a692665d3f89899d95e8ec7657a7955f4498dc06e62a4687655cd99c119b468e804b0307ac311e44aa3b007e680098e1f1f24d4c8dd9fafb3676a45212d7986a5e2cd3310c09ec7daaccac3590c8a3677ce9c10e20801d47294dc0d74da03b6fc0bf6bc22e6cf576d1ce6d25c9cff9c2369dcbc99732c72dfbeb7fe361fbfe4b2c4a11f8fc51ff74f4e4cb51c428c0133020a005bc4e94807c27f921a0c8e82b8154fb2df29c56aa6ced8abfa6439b8d02d55d3fb5b4f381eba5f3f536573c7060849301f96ab71dd6cb24f59ee5103ecb2c426803595d3ede6979f9161a9d7c2aee61463857b7f79da891926eda4b73b87d794c9c6be9f449ff19141cf65b29d4e93b39c77cd4358dbc4cf6b4d517cc52b61382f91ab660195aa7a87a4a28926b3237ac437c7b9502c91e17bcde2a847e4d19b0a63f603da66dbd57ac7c11c74ae130db409f89e336cc4d86bfcb63bb3f062b255c54cd7d6356656dbb3c77997c32b36b126343eebcf0ebe2762ddcbfa9ed03166a55144d630970207dbacdc3d072172b9feac02046e8ee44ad24d3caccd7fe2491cf998c16061c78819e45952a040e1d1a17e56e8661cdd292a7b6ca1c27a475d1e0850512388f29063d46ac41f2347ad28ca1f4129104685b2703c07dbe18553a8225655971bf1fa2185b414fd12ab568ea40af9831639ac47532a31c62e9f2c967eeb4290c44de9ceb868fac83a15e4b8e5125163c4bcf6fb7ef57554d65dac7da1c15a03a4a981c476086c201919aadb3931f35609cafd067ca20fbf98879713a0c87fcb299d710060c274cd3da7f0a4f16611cfd6873c429e504474b25c65cee202c2779de260b7c42d202609125f4a9b6ffff35b97f2c3c21fc08ad1523dbdf64bbf65a937ae8729371c039b59a97c0ece0c438c2efecfcfaa941f96e0802a464ab1f4fa931d03ce0c07040e0c03f33da93132116f6ecc5dfb9fdf9a94272ce8802a9414324f47e6c14617fea724e5cad009c310fa03073f5e46c3d218a9c7cd5f5c94adf2d12f26023c70f70131e2c2be3e2a3b8f73a62123ff1f9871f9e7be742747d5f8825d5c29868c6a5745ba28a55d7aba30fe2caab02f4ab7638107e4cd629aca00a87abe0b5b81a86ee00b7f5d577a38b2581b1ef34ab46c47e3c62a4fef2cc02977549bb691b55619ea0d80c6ec46814a159aae992d400ad34ca3f5d719ce9b97f61a0186be9ac02700494bf4e0acb11ab2cb4d833b76060475e49600c3a30df85d221107f8c3ab0e485e02f41907a1be6cc627e90974060c54c7928dc3b5b07c040823864549c52d100acd95263c0f78405389802256be0f66d36d0a78a608d909b4236a5f59ff1382fbd2b7fd5c5bb6d1586dd9399ec46b415f6330b2bd9b83c2ee55dc045759223f394a1974dcca9bf72ce36ab44f7f0671f894c47b836c4819b6fc47916d9d20de9a727d8342682d80d22e2ec2ef56afef612ccd31eaff59cb6c451c5c2985c50e836b65d1e22e05513bcf83be4f9d9cb44fa54859d38007174068f305513f2e00d43cab5abfb108c16e39c41f6cd19d2ac91970867433db8e17be369ee72671a052ae556f8466aae55ae132d5b939b7c2848a6c884fc50cba5ff01a7e942355f825d8340bf000b202c2be17de0cf0bebac8b3f6dedd69c0640a7a8118a823210440739526302cb9c47706f50dce50934dcf4e5cff93c5e8b9043c6d9d9c18ee15e8431b4f12753f2557882fa29fb4e80d72d8db86877e4e17bb135f62fbb3fcf9539b0307ba32d1fdb14d561a464dde926e626261c9c63608303157b68143136213dbb413fb2d347e396f2f048c2be045b059c60dbb255171dce29e764bf8e961d12c4efd4d83365eeee69ca83635d7bdf185ca86af01fe972df4ee0ebf7fe2c84a98cd2d52994131ffbd34b39d8e5beb60312312743946e10dbfbd44c0aec1412fe265fd0a65743c52366c4989bdde2dba576777ce939bd132a6128cba211076a45c070b5f918942b7d5e0b9cfec2695eb6f8ef4cb36f98ffc4faef6a661a64787d9a9f2299d0f4003d375a29d527259a539292337adf7e389415ba9f73135e8416c589ce0477dd9bc5bfa92d3808fb5bcef1284ee3082c53efd4b3bfd2feeb99817637b8857f14a80dab7840ed30ab4584c087887806940d1e3d8e86201e9e97112cc9c7c110ccfda590bd825742733f437b9888f068a70fc23efbdb950930ab81f9992c341c47b73638827e0ee4cece8e3a1ad1a63414e0e854143102ea69dfd75ca1741496ef2bc9408541e1ad6f6e58b93217a3ca8541dbf4585e282b4b277e7154b9b805c43b33bee0468a650914f324feffca65063107d770b5f3e87fc931550b2918af665cc91d180b2f51910b969b2ac50562c16996c9fa0a160c22a19ad734759747afe6cce98b9ce9807b07601fd8fb05c51f4c55f46f2fc31bff122e712e51f4d5e25cf58b52d07e6a9e51cf1c1c28803d4a330bbc883a08d3840fbedbad55a1f0e4a89c25f42cdc8cf3a4a862eda5c0cdea2ba741e00c31f218c94231c64d475ff24038b85a09dbab0692342cb30685a5618a3eb5fa322e613b896aa3b90c9a57ac0ed2adcf4ac64a71132223222e5904a8cb391f1e1f297da3287cc276a054a4fa0cb2e24a1166f2be2ead1d03a55b84e49dd283c387f91c0528166dacc5231263173c48c6ddadc01f0e8aaa79dd00a2ac9c05ba432c2057ca72b9d51fda11038fbaf546d558ef17465bd32fa4dc1484e63006ae48b113c60c6a5f0a440af934349506a7b57e6c002493214713ef762b9b0c4dbe15f63115aaef3af893abb55591063996f41fce58167b74a303b0d5df7780d12d558ddd0ea7696b8bcb509b78e1bd8fa9302a5ba3943fa28d9ed46234e8c621174829e22c835e3fd34515e5e55d2b65a4075235543d58028c4c74a64f28491cb38ee45617fee85984c42776829f537c0be85b234974f6a3e8e7d613c0015b817eabf2ba2fdb93262bcd16f443c0ede0078550b362e849f31c4d7a3fe6420b6182177634c1dd57f3aa998a01651bfe33b0b81fc7a18c48515870c1a1ae88b4158b41b5244f89dd9b5159237a8123be905a36e8b40e5a1705ce35fb74df9f8919e1132b2fcef2458f05171082a0327818affad2fa20d0bce082b0305728a008c03a5990a1ba9b6bcea0792889c1d62c2890f4042330bc71a81c19be930b9faae1356287928f2351867c811ec40c82fcfe44ab8e5f94901edab3889cdeea6c9aeecfd5506af9e849d2f79cc765952fd6cbe79d9588ae3bb33b1ad6df653e0e9086d6a3dcb84fb6f2dc9a8637996684518f43e2672995b6424c0936a95b3e3dde2669353de7a2d140923018a452efc8e2f4c1fb4b6bfbea0150c701788c07600cc1442f73586dda14054a97bc2fa5b881d9014d8aa4971fa487da281e617020c0b68d4e2c48bb381965b63c5e0a695d5c58d0671cc496e430c787104e6fba2fe6f29d34f3b1fde236579f52ff44ce57f7149d8bdb7ed3f7870428ada5055c921dbb3b466adb907ec6a1b6a990aab0d7ac04e6e6ce6df49eabdaf7ca43b7b1913ca94e8dd1b9401205aa90c4b36822b391329320c9539478c1e071d77e8d011071c3becd8a10e1c39e668393038d7adef08be63c71d39748443c71d3be8808372e0d6a1fc3bccf22a388987f307072ede4a5f8e4df8e2cf5ee527baad4a855f9b59b98f7a82d4cf1756ae2955f16756096d056c75e1f012c1cb93e7d6e271044171d4e2a96d09c04545d23084a3152c267480532930ccaeac78766da09b0aa9159733ed4c092e7bc4e6c2054a1d9f2aca981eee39afa134596875af74774bb8d4ce720b594e5a73d6ac07eeca4a08adcd9a61915b49bb949519663cf0165b85b26ad61963ccd6d451d69d31cb8cbbb1325a2bb366bae456d22e656586190fbcc556a1ac9a75c618b33575947567cc32e36eac8cd6caac992eb95525a83c1a7048b33a1bcc50f975c53ea2710484f4fac26b5b69d5943d2a3f105ecc467fb9e913c3669e39254a7be09664257a951e954720ca3c00de277ae9b976411645e567df59ff5acd045eda356aacd8969bedb64b6c9a756dc5b4ee968bb56cd1ac552bd6fa719451d959f12542f0dae8d7a73b4ae59b87b22701e66a075f90242c2ec653ae791a9d224235fa72ca738273ee7261339b12c2afd6d63092bc9806aee44e00356d86b3772f6569b2e05219310f0872115a38928b10d4dae0e17ef053494dc4c5886c94901ec8213a50ba90a0b39afb1aca722edb1c801b9daa513fce47ab708f90c2aed1380f51b362a19c408cef9e9874b45376036ec1a2f11288c07ebde8948b57a4d2de8c5c019e18db290e1cd28e50123eb0fc2364b962b8745071da645ccc002b69a070c48e080d49601f1cefeff5fac933fcef1073cbb7b33b9a77ed0a83d1eaa8b6316622d4bde0cb1f03153adb0b1f4cf6cfc55d3e9c019112e55b38ac7e79ad21a95f930bcb651c0bbb24528c474aeb49eb00b2ec22fa981d676968a07b14c55cb54728d31e6d130142b838df9ffe0773354ea5816e40c96f5bddb6d0eacab6daa465ec3e911d378ef8d33a746ba2439badbf72dc0dfd020e980ef23496df2a0345b899921f73fe8cd7604be6751d89ece9a2f97bc57929c985633c7c3203f1b5fa81a056f8b952d0cfa80fb73c93a50e626335b61c70c40fc813ac5c1b1b8e68552e05e2e974b36c32add18447b2d2e177b1d14f05f3ed31042e8eb8dd186027b4ac3e2e4edf0d7bb2b2b84f45a5b51d9d1b0f0511bdecb33a88fca40ccf9bd601d2772319555e43858ae9794786a41c85f1ace26db60e4a73da45eca6d70ec50188855603818ee005100c3cef92308b8db5b70f11eb1e0f0ca0dc758992a783c8119affe8b87871040649c5902be2e2e4c860ff47b3f0e1e63bd38d9c40720139bcde1ded593f2bff48333edd8895abc437d7825be87b1976c0d15a813d4f22055293035db3e895038c1c31e143361404714eb59e27aa7813d3d2085f61e18c174c2260689f317ab3d912e5f0dda6e9bbd8985d3401a4059e4e5ba0f496c36008773ef3e4d3e2d298947882372b6b5cba7ee2a2709ee1b1a3672fb4a5a1bb124d4240fc64afbaaca3f0365acc1f8b03ffb723ddf4431bf3e7430b97092c2f7dc31876c101f114c3abc90f4d2f6252ce98149ecc5ed8acd140defa71dd636ca1455be13cb5e9cababc4def79878e231e33ff1d7fa33cdf18befab12f3191839a49dc568e4f3883ebf7b90d9b0b1d63a8b95c5b5b20afb6fa3b0cec9e160773cad9030412343bfb00b5ef33206a03e5d03b661e7ed88613431b2040eed0aefc126997e7336ee124fcdc86cd858e31d45caeadd590575bfd5d0b764fcb8839e56c0c02099a9dcdc16e83f6c40b35061946a6290149643b4578388b4ecfcba63701696bd947ea762ee6861bde1a765ad8f5272463887f756cb8b3e67dd97a5715df29a0e0c5d339a223f3d9d26af0b3b6bdfc5cf5be095eba5a84dd27928140ca026cfdb1065040138038fcc890b0cfb159dff8d76385cef2e880b7091d06da2810da3b9d68e30f4be18b8deb236b5d16918c458422d83c68bd878e9410a2fe3a4a76ca4709e7c62febdd8608748864c5e6a8c87f49e25193061881e7701527d99d4083633f1749b4a6d86baa84ce8bb79a48577b58b8f866b283c566230a3840b26a7150ace4181b8320e06c07bfc1b181cc8439aa33ab0cb9a890238d60a96bab9e0a1d157a152a09f17e4ea331a96ed1e031046450025809b16a26ec3c780a4eb9485aee49549e7a9d2bc505cd06de08b3dd0ee7d9a474bbead9791b69b68b64d0a23dde3b17d9a16bacf56ba96d857b561310c53ac43dae331958f2b2476ba0e0428ce6f3417c19b8258a512175b58fe9c75f79909bbd4ecbf0033479461f63dd19fe943dc395a0d6e5ca99c2b98f5ce3ce4f9f3a60da3ac0696bc84f04634c159501c5515f4eb2b7ec8b0e3091a739a0b8259673959de6cced29d11c561575e34588dba84c7a76665f90decdbc1f9d8d841705ff4a688e0d231ad4ecd6a1e8466744b1b4240a1c2f1fc4cb86e19a0ee2943d448a0a297ea7b27a9e96da16edb608246a4d5d3c1fc8a7a5349aa46163423eb0e15fa8554454d60846a3cf767a340fcd2f0b35b456c44282894150461685fea1cef0ea0f316fdadb6373b7e882e835b7025a236544b84e753d6a8c1abf1a60940dbf970be16f8cf7b5a67139d8adec08bf3dc1d4afdcce654b21a3ddc8fc4a9741cf9c29322507b176991554ef53a71ba7c6068f1acad74da87a6a47856174631ed7e5a20bb122055ba38eaf43fd69856bbe98d2fba8cb8cf45e649a08c3f767101cc014c46aceb07561c4c04a67a4017995aba4c3790325af2b52cddb4fd990aed8464981ccbe9c4483ffc9f121c579047ae82c9282ab67f83394ca0b2b013c5d010af4dc355770ce61750acc7240ae50e5c6eed0e64552951712ddec19e28f9907ee30612477136af386f61118d7dfb570de7c4c681f1a17cbcbe442e5640ae7627934cce10ecae6a60ee50db66f3adb8ae077af16e826774a726fff1d310353034603bbd91abffc38f9013491ad3faddd27ebb42e0a815ab25104e6c8c69b1841e3436badaf84d45b4a84c494f20daea8dca3b05a62389b43522d3ea7e8c72edbeceeee454bf596369d4f280845d13751c939e77c216eb5eb2cdcbae49c732e06d55b3a241a8fc8f7504cfeeb160114632a525e623a322358a5206f51e99218d7dbbfd8b1ddb54dab893df7fe5ddbb45a4b654282836539f671ec9680792cbb1a42d13ccf6ac2076868beef8e919022393c2e4f366b46f1e60d14026e7c26b97d77f7a757bda5c121d108e2e9f84074adebb60994b4ee09aead75dbaf623173aa4ac22c2feb68df5f4d0a526fa9101152fe208959b2b4c64d388e3c5e3d40215b8df242415b3846476f06a7d06050573713ac8cdad0ca2006f3ffbf4b918434501865e6bddb3e0b93c403bb9510dd21c32b47a7a9882964f4a5e4a4fa78d7366def7ffd9b2ddf61fcd4bebfceffff1fa0cd9cdb2521c396bd01f5c13313beaa6214a198f8ca5131817ccfeeee6e347c71eebcb603b1a123693161a59c734671aab7f409fd0f28d1dc1bfc0f29c3e4c7bc20cbf250396041e15ddbb4bd8bf07b767777a42c249c7b4fe7eebe33a1213a24472867e3c50b628e0b0a510dbe6727e672391c77777777f7202e45a2f1c4b907714076e7f9406f79efd96b3877770722aab7d4a839001db5f6271c9c3bace52ac6d58f7a25963688745f6cd88d301d399ad1e5ee633f50398ee4cca880445afa1191437d91c15ddbb4bd995eb6e9459a59bbd62517311185a42a2c9f2a1f8f9755c60739b2e433f4734b5c9beb2ae97a9a58aca666347d718506a31f2490e5a91f8447166fd9658097845112381fedd004dd4d582da26b83dd12d7e6ba0e5cd15a6b2049f5962a974de7f30408d42b70cf2f7067edc0427304deb54ddbfb573282918f530b41bc1c434b30a6b2dcfcfeffffcc1d1edc7fd631710861884168bdce05efdaa6edbdc232a237e3e07b76b5c5dddddddd3d884b959ac4e02f75bab2345592daad2e40b28ebc5ddbb49deeffbc5c89b95c4e664d9734904b66d48b5fce90231f4515d8e8124b2fbb62964400843a939503ab36b304cd8a22b49195861d58402c79027ee1220691e97892e1f3b58b8699392504b24d5b62ef481ccdf07bee6469ebdaa22accc2ad8fdd1a6e11b78c5bc72de456d24ddc8133eeee24c434ce4ee3c01a27d6383425232e30d6955b3ac4c6c7552583a9b5d33484daf9704319c673e7fdb825aecd759943ddcb4fadb5f6edd45b0ac734451e10bea09c73ce334cf5964a5165759dcc889dd0ec5ae5114f1844e697ecc17a1159660c3073d0d3c00a9c94183c3830ef4e366ab1b5c23291c31eafdfb3bbbb3ff5732765815dd05299624083d05411244c4d5490cce869986293dfffffff6f2cc5b890915b41d972c29b8246997fe55aa429168b3cc5a0a25091a88854646a560928eb55aa9135dbd1b0f1003272411f71244e73ec4312791ec1c4258466bc51878ff7eceeee4c285e9c7bf03dbbbbbbd18c13e7ce33519fef7a4bdb15b7c4b5b9ee9531c32c1c81abec98e80549015271e532637be0947307823005757757712084ef7d72090af311c3062a2689e297fdff3fb9ded20c9c7573ce43e0213bdffb493e7c21592e930b38764ca86b6b63e085e6d18326b2851d764b5c9beb12d9620f98bec1f596b659a78265310192e20aa9eae7ad1a3e65bc8899c96514a2ac788ebef0aa6924516e4c315b286dc9744f392ec664f411926819ffabbef5c4c9b80e69261ed30a0cd06ddf3f5725d55baa5c660e554dd7b9e00c9390fd40babbf3dc6cb5536f291ceb132b1aad81447cc35313fefff7b9998318d0dcfef37c81102dc6863a44468071d9d440aeb04a61ec040f32c566e728c4696cd8d5530ca291330386870ab6e20945e5e55f07f724393c1e8ec35ff332a5ab088bd34d915a109d56bf3361c38eac6b6bc788ebbfecdf2d716d25399bb43d77f7a41a1a9c3b2cab81758ddc32153b7ef944249d6822a1313d323306486fa6f4815f1519083da22dd39d791585553c4392a8de5263e6903cd60280ea322cd3911bea04800a0bf2518304588f1d3771115186020d4ec0e44a70d960690153ae40116080686c5ac134d9fc40be2c19309bd1110ad205f463e1844b8b1b0818f05a19723c423da990fd789249326aad354b53bda5ce27d4034b34e701f8aeed0666d2bdf5e9a6640a366af6fbffefad37c6a06cd8cd1ab6407ae4e55cf9cdb8d0ca11c118cd84181ab934c1a69c463f6c58cb2b513d97ee3f7548f4dd5f49885c386106754b9cedf45a1ea9c771a8b523f366b311ddc731eb04a3f9822175aa01cf02459c197ebb756678d7366d6fd7efd95b9d5b92ea2d55b61d5a96bb16c248840550aa0b860dd205fe2970fe42585860435081e637b10e25730f28c011fc6cd7a312523e7777f7b8c697c117ad91c5c1f596b62f3976b76b9bb61d8ed16affff4f51aab774d9747e90f2f4921b37d3188b6ac75a66c2ac20502df4cceccc3499c68c18728c6e896b735d1d31b3fcffbf2a12a45e51ad183b6ac4dc58a135c3bc514fa6920afc98a4bcb4442075df33d5e399a6ac66b4d65af7bcde13f49ea1f710bdc7e83d47ef417a4f32c984738f73ebeefe434abda554595d1d7e88ed3a54c15fc10a6cddf663fdcb56eb0bf4c05ddbb4bd31ac00b0ccf994002061c7468526a08f538c98b8c5c56d75feff0fa2516f699127731014e4debc0ea9e248584700f4065207e44a41e8e05ddbb4bde1155c7777e5abded2e0507fa0246a1d858348486444c72b16d1b2820aa8a753cc8a698d94a8962bbbb6697bc7231d4c0c77aa663a1440129dd24e13834ec693526f29555617089e18887717ab42761d08817db4708a95814b24b0495334e9da7819feb9b2a45c87a477fb1e4e617f20dd3cd98e3094268aac64ec70295dd860b1462c60a5bb3b8f8010402eaa601848979ca1e342e28576f4d3f56c555fee9085d46dfea924274bc6ffff1ed3d38e16ce3de21bbbdefbff07aecc2fa432e92b6c967da0146559d98b09d22763cf2f6719e6d3028d4c0c7725aa9bb66b9b5693edfd2b091203014530203a3e2b462ec213575f31173cd08d207aabb0686c5878666830069deeeeb323142b091316954284104aa68965450015cdf32034eeee4094989669c8e9be6bdf1febc50a6ea74eb3ac36dca25f1a172e71906a5e1362553f532b869e47096a6473584efcff2fd930e2fe338fe5a9649885d906a7d74bc3221ca524c1403183a973f4a29725fbffb96877241ca872ea0f1ff9c99261bd8481129f2d0f832e25a70b9c17e371a5015de6b480493acbd199cbe55ed4232e352221750c03ba25aecd75571ebc382ebe50311383d34c8704616c0af0a0e9d803babb2fed1071eebed4a38cdbf7d7f9ff7fb9ded256657bff40adb536a2516f6991274808841191bb3bef3dbbbb7b8ee77a4b5bf6cbab60a092fb3c1c5945474bae1b37b61e05ebdc1ded162c2a63d3966dd7a089caa45c6f01adbb7b902cf596767d0822b683e30c7e84e4eb5d5b12a77b5cdfa3891584172873f88efc766dd3f6ce3f150709a2a88c651485081d9c98c705ef02f72fc40264bde00b3c7ce01da11a3122d6236b66246548887ae755ed150b295750e7b925aecd7575bcff7f9f32c33107e36628e377241bf13462e7844c0ac2c5b8c2ed8861924437a42899c2ffff41f70e46a83becb2cb215459c3eeb8c6cc96505fce395329d55bba6c3a9fd00da8a239126954acec11ab2073a28627a6451126299e8f4ccc8acc8e64d218f62ca2a43453d48f180e50345b9ed25b2533072be5762e38c32939e79c6984d45b4a84c494a2cada40d38562b66b9bb6b78f75e69fce9945a2e085988ddde9ce5b89ab556ec5d7dbb54ddb7b85317410b582cc9325684515c49a31a26cd95d31c3da646d7a01bbb65d5e6979b1c97b4871746df091c8c26e896b737d85b58e987a4b77704c53f413238fbb5e79afd65ab740546fa9f1884c9eb4a074770756d07ece39db20a9b794294595d505828dd8575044f8ffaf9273ce5f39f596bec121d178f4f08564c36e9e96d4647c75199e81f550656042dac84e988830861eeba64caf67be20d9a35733f6a3455cabd81234bbb6697b8f2d6742d7bfde0ebe829bc54ce8738189e853b3719622f524d51d0a115b2a502d18797e85d602ebad0fa452503174f0f8111183215b412648cc1fb690d1e77f001b2e7d252f7cceaba98feeeebe96242aa6ded21ddc012cceee6e8d3578f0d414ba2619a880089d1c3b7ec2c246a4d0a79b212c95f79edddd1deb897307aaaf6b6389818ac26f23e9aea991109adc340d64793430674eef6c802e6bccffbf12972a091571ff4a9c056a9bb36fd7366d6f1a361e324052d21328b97b81ba7e5804edc080250cd103244aa80495a36a840a6631035385d09d64ace4ae6351d82e8851c70fa8488015b7c4b5b9ee53f0c52d716d6ed4f94e09470c39edfc8f58002f5b6eba444cc6bbb6697b67e07b76777727a025cebdc689c84aa70ed912aa3ac4a54ba1e7cf4ce5bde02a0b6c05a99899a13fc2c8604442a849e83e29022c5feecacbab97e37d6c6624651b881cddf3d1901808804a1e42b2b0cc6617785cbf614909b7bef7ecad9635b5866bd820789221634a450c142c1b303f6a52b462ffff19dec761e2d803b61d8ca2be357d6a0d7b5390f2a8342d9e46c5009d00331a041c41c3401cca12b9a6031480070d8890bc7888d02c1286c6c180480c0086024100180c0602018140202c8a817096ca62b805e646dbf3bd2e64f64fe4f004eb23ff0e699e3247d24b954b5088a40ecaa685d8258c2a3eb4ecfe165df5168aaf83b3641af522ff11f7da40c0a2cca02c46d2efcdcc6a1175a1daa9d70e2a750166303407f0b645b3fc83a82b1e4899184fb508d9357cefb368f6496662150a6f7e785018b411225e0e15f5890e2d8d344d1149d7f438da024305fadde9c440f6f31737f3568755bb2fe44eb98682b9ed86ba66f98ab4db8a862750ed262b4417862278d552ef5a1ee7874ac9ff53c3143d4951a8845e4981874b338fdb6644167f70da9070c9695afbc2886b3fb9fd8c545bb6e2da3c96ac914c53d3127a343d6fafc05c2dd69c4ce918a410957a367bd3c9241d7c1218cba1ccb4637b47115544336634360960ff0568b26be93a44a1a2d9f59b24d4d66695674084fdbd875a244b6e018a06c2095e2dd4ab8dc170c6fe37ba6bdbdbc1e8b152458909ab6d0d8a7ecbca1261aef5c8f04b1c3068a2b35b45a74db7b089e3dd78d2b48c6259262ccc5d1dad46da316394643eedd95a6410cd1e4fcd54fca74e1f6da5b8bb3250970d8d5cf4a4a195d4643556a2188b7bfd5559311193eef6871797c02bc2de8bc8834292b0731e924411129b9ca537a6ceae2e270dec2c56a22b96e463f562dd90156539a401cfda7ebb33e130c2b32ef4653f2413e0940f5b53b2c237b31677e5fd1a5ba367da9a8f52f3ba211cd0a86acd14aa4534574928ada454c5c91726a7a4cca5c9e68a194a25bdd2e1ff64f5ce58c21b4eaffe332f7dd0630929ead5abf96f88b98f4712bb4d25861070fa396f6c3f228aa769d1bef21e9e5f3ddee813d442ae61f6e8103da1331e1fa9e78d1736369bc1bb1251fb2176cbdf28b32e55ade7e471266c81a4dd06282c44d1aff58c1627dfb68302d90a51f44d311893b313a8307cd6fb1475788acc3457c7b4fd399f0880683d5c650b11cd9d249aff68132935cc4ed966f320996adad48ae4546194780947df9a4e180080b6741118468028346c2867ff5c8cb30a14e029c09e75d282ea573c268928293a1f81872649162790292cfc5167a458b89fc6f0fd6686b2a058e8390076939b60b212624324df61daca31cfee89ab31cb4570f2e01b2296c28f8a721385c653b853610477395dfa84c8bd4a47210579b988cb39a3a2c755a18cc1bd73f346275a053857a265e82b441021e8be4a6224d4d03359ca241f3d7c14887a47646ca2c411139ff02fd8d3318ad02125e321b6237dee5811d423c8a9a8510786e2f6c731a10a01da3d9a5796898a7ca49222908098242196da2adf276c85713d91c840af479be33dd44a5eb0e00c6ea0f66ace750ee1db88d1ed6f050d177a8d4d6c6088a44ce2b2a490949a94b4b2a527de01514f2f3a3301a46b8f2609de770961ca6bc649fd8aa25cdac6883f60893904bfeddb91fe918bdfef655f3c8e517069c457ef5e66a650f89c7757ddf4bd252eb8bdd1c0613bdade3b21caf239f0030c93d7aa99a04305b4a17589908f2b2fac28b7981b3ae9e762258d3f881e1aec599b58884cf5cc63bdb190a6736247b98d5cb9fcd2610614e180a3298dde507fbebd8deb27dc403ec12cd41cf3fd70695f9192f71dfbf654235c6e90353490315fd6c832bde9802d0853ba985356e9db8af0566a27858c95138b2db3035d7c7a3a75dba3b647d4c995ce53d2c5b4d91dc8ada94cac2660ae2d76e22ba90317ed99b94c64fd6e32287beb800bfca12f1d2a2218ad7d1db5ca5d3b15a28269a39f7cad6b19a4b66f7e239af7f89607a8a796e0afd971daf7767d82898e207218b3bc828092d7b227d770933e0ce683636435391513bab68dad1389cd709cfd3c40e78d02454f3c51050c97d335cb8a9278364abbbcaba81e076ad8261218b934eccc8c43dff240fab4aabaa8d5c6efdba7c461f7be65bb39cdccadab8549a5b52571d0cb81fd05257f52bc54670ca95a3f890155712e5ed711a3a30a6ddb7ff721dc7d60c33917ccde9916c22a0b4b04d0af2cf4d33c4e6e10b9e3dce44cc35e553ab56df458700e79afb0220d95858da2acac25d9fec14943b4a5a1fff0bfb26a4dd03fd1d0b18b36fe593955a56e6c0b044fb29e7ae1b62415fe0edb3738f03ddadf16285f195300a2f2ee76deb793c71105df2539ba939f5340d31ede2c94a4d025862142884f01f8b598b61adddd5408ab29283531086f384921340b5dd1eb61b37b68394340723ded2dae6516f96f14f7a417ab1907ef8f3d8d002807e59119c18490349de164614cf2a4d018c482df8a54fadff007d1eb27bd59e53fb0f0af55089995afded158869ab33264e0d9ec7bf7a2abfb5b2d0686615895ea0b03f339048da25177b97eb715f87d1b76e542097067eb609b821735cd01863e577b6046e6f6ab46eeb5e81bd192f6d9586dbe510289c53f0e68887b0360b42f22b057fc969c9d4526900a413ef5d1d03f08bfb46d36078b080c9db4de95ca92f557d53820708327b4cadc8b2892f67e0abd2f158e8c14f38877a6bc6b9c4f3276af85a56859bc1a55a67fd2bec14f8b438d341d5082006a530ba240c0df3f9c5422ddddca3933d61c22138dde9184ceb36a9cbf6fb9b5fef5e3ad28aea8c716ac000560b91113db931cc3057892624067762b3a6a9b0941a5a9c4c7ef8dc2f56ac24df912b4161ccd44b5ed0e896a88f89219c826ce8f87bde318ea29d098ca286bce340d0a3ea2b03a4dc786543814d0d7e91bbd61729a3651746d1fa26c0c61c4f34605d342b5c3ac9f66ac3c78bad3d11a88b7ddb2cd19c17b8dce701d600e729e31978ed283e17bd13975471a3cc41380f61b06e6398572c969e0a97c8f0e0e1ffc1e75de3e8ad321dc86edf9aa0ae222941c5ad99472e7b497fce170223b142e1d9d710f84883ec8f038cf50403ac8bfa5be213df902c8c309038fd2b8b108378a2f35bfbd9111e646f33569271d6b03fb15ccd2e646434a6bd7d12267fb3cff5d27d2e98334a71d985bcbabddebd1423a96cd10e7887b26343f81de4cabc0c072afa62e8c7cb05c6aeed6bd1769bf89179a93f1a6cc33976e5b49095f86a79dc57f7cd358d583071d03968b122cb8d09a05fc47adec2af778011f7c542ec21fc2ac4299c316b9b112b064e15331e6cac305901a167eefdd1defcaf6816b685ba73f8b3cbecee1f82bdd2b89654323073de92f0279361ddc40b851462f2bef68bf7c6c788e0b05565c089e13c681f12679ab7ef9ba9ff896d673ef47529ac26095eec0fe4123407ab6faa661484aebaa842b7201eb6dfb528c06d760a637fbae62f1d3bc14d90c54b814df5806b6921652d24ab8e6143eada637b0cd72fa85511925f5d25b5019bc983960a35c72aef5d1235a162eea205db3afa039ad0d2e604bf6e5f0aa5b5d8b602d54635bd41d408a472636a64855314e8282d9b4bbf573350423b6d42693728633f2df5fdea4fc962764d5f80192fe48a89bfd148273cb239add4821e82f9643abd542ec7632e379c8cea7bebd05e38fb9e072b7da4c52bf436734d31fba1ec750e77db919b597124bdfa5214b2c8ecdf37ee72fc8b79da76f87306ec947a989a549238b1e6af86b9577b39aa4d7f14d3acf0d74b922082611b0eba19c2f31d3580b2505c2c15283ef06b9132264df40f716c2c541561bac5bf141f24d724920545cceede2df3f42b39d5aa37946d4b5ed98f05e1fb0e30bee5a504e93f4498f0e111d342b496ad2f4e1f4ff849c982949182dbad8a5fa4c9801369e0f9fc5680685ac05030ad4c4241faf9eb0a0e17b0b25f92004ccf3f3f5ac6bc5d61ab9e36c80a5b3397a18d538253934ee2c38bc13353534c1106bfafb9dd6d6cb96c74f050444df427c6c0ae8fd0b2952172f5f981c4cd6d23cbd4789c704e0d6f09bc12e080065c7516174ac9d4a35b5035767f959234c16fa345d631204cd16fc04323b557bc95c8ccc5953e3abab2b23c449f7f2660da91a9d322a49ce4fb65751590f6623eef1398865d64680c9156e7910a949b7f4048c7010441292de7129ce5036b030541da3d701c3fce1c711ef2e44b0e8046bca4094dea630ed38264db66adaafdbbaa81a47cc44616ce544e1419ac089e82c1be936dd76769eece46f515713c1f02649320b810a4062230def881095b3f4937fe3b0e8c6dbe3ca7818253db8ed10c6d2eedaeeb1e1ab8f3be1ff8f77209a1a6e5c21860d572e8f0300173fc6c2a2347e456ba045efc66b1abf12b2d76760aba0ec363e19c1a04e44733a3ea7bc8ad605d8e9725d0d49fc0c25d494e0344c50b616f398b342edb8a1894229c75ecd67eb20a2d7687cae4c330d13435ee91c21c74aa81054cfd8170ac3306e3fb097327717c6a0cbdc5de3d921fd7ef7a56c2e839d01a4b883fe558446cf79df45115ae624eb16c1960813dd326f3cbf8594aa969d497a53f2030e1964eae09908068ffb047e7ffa76a9d4564c424e87b4d7e412f2dad17699342f204022683428ec9295c3ca27e0ddb0c2f6e11701e9cd20969fd2f6c41a10902704f0ac8769bd1a50d1832c23d4aa888bf3c5d6bcda86761f92709fcb0c60c26f20e1ab9a0955c7a446dc5a28e9e1e371b81126b7c9588b349d0642927c3c733ce462d4b41fa86eddb5f655e5ae883ce7799b4156466c33b15f4e0f4cdd142eae599fabe121b1cd09c5fbf759726074cb015a22dc7dd33f7e1dd1ee44b9b9999cf6b7afe8b95e1331cbc12822a14a6b76411b37f65ffbff06f45ad9a19d4f7b3dc8c2ab945aed68f4d6a80bdddb98040e8fabf9ea2e33939ed1f67f68f7711d1ba6b4090d8e1ad131584f88aa1b87b0d1794ae4e9eeffae272335d065c65885e150a41a0983350131a91f648dd8ed9750e39c62b72e532def6ea17e0bffd88aaa70451cede72200c471d3a5002c5e0f6fa24180d1471824492dbdde688bfa41fb4029e138da56dfeb755a3dc949d459cbbc5a31c0aaebfade577cb36c49acf1af887f6679dee08e0e36bfa2d64938bd418cebe8c1067b011ea30f7dbd88d884d65e340493895c03c835bc0ba48e1c402839721a7e20a414691b12ef4ca1ba04fa31f71ea6a357967a29919bc7e7fe5edb61ba0eb613ccec12d7779d4cf61a6380d3dec324e84529b72deeb6bf2ae9b31323744956ab86e8d7bc0a41493c245c0ca0ad88cfea98bf6a97582645ff908de9a238ceb9c1415b68eadeb2f8ab10624f72c6559612ba7fc1323dfeb15bea4a857a0f56ec1353ced24deb1172eefe871e56575a0bc12c3d50b90bca175f125b9a3da0bf442cd46a68e06a86a547ffe5c17cfa11b977d968e4a02fbd41d07ff9e4d54d866965af5736f497b826c02f6d9d3e1e9cbd13fab1286ad5c4965502d99cf32622d97a200ac8f446cd0a477a938c0c13c9703a4dd57eecbcbc742fa1944608a93744ce7051996ee05a4239cfda769080fa6744df4ff541f1d08e784b07876778caeb692bb9e788673d9b17bf49fc5dac918d70377f1c6c587b8ba233cc12320a303b55b31d2b34a115e96a5eafc5da000152a60c3294c4817b3077df6cf4f3b60db39983e05f13e7c66e084105d287db7ba5328224be105f81cf482361c6d34632366b58484e8d25ec257da93ff08871708b6dd9ea121730964a1b8ca3e88d1063efb192853e840942130a0669a653da7d2df75522648aa574bd3a29257594a111c53b7421b60b088916063356ccf5d84fd6432eebe295c3552803800da55593b9f378fc8ffe76e2371bd072d3193c91b24adf9ec7b751630309762c578eec13a747e353128e64daa4a423933ef1e90a451973330c923cdfee5d7712d0ac9426173e69ed3e21c4b2cbc82d5fda3292b2d9a5799380030ab75cc9f823bcabdfd466e66a4f8ef611c1c7583d93470ed5c1d64217769222423cf278a34bffe5e1c513f0fcd84146f85880f415c520cab65967690184994116c5216fc10793b5c5c415896083570e317e7d7ddeb3719e333f36ca82805985976c9e4b50f355f9f194840ac79abd232f7d7d32f9a6efbedbc36b661bb782ecabbfd9ce877b745b38e77ce3e681d601763490bacf0a99d8c177aee097ed7eec233aea98077c7ac2b979e385d474805fab5aa88bcd8a964ecd4957841b07361c04408e03909bdb6cf698070725ba56209131b194cb54404694c68f6c36a071ecc559dc54e5b87c7c05264aa022c965107a3ae4cb2f0c72bd56eb113534f7590d4dcfb928264ebfa28f548becd638e42fdd4cd72429abde6d3bf20c95220a5c6a481da5ea48ed54da96b1e8577c332d98bc5a6b6d73267ca80bce40cd021d4447ae98300aa46b93c2d31a2d2246d8c45411993f7cf9215b7624817d8779a3c2db8328d10db2204bbc787500fdbc5ebc9bcd71e28038a7da15324eedd453fb6a54e921c908e3694405019695788ecca1f3b46b20bf381b859732ddd868edd1a7237ade96a05a5cf12e093438f1ef7f3b33b5cc7436835a6db765cbb14643b682b0ff9dcd4e4ef8dbf1af4097881b93880b6456dad962ab116944774b732b3f1c45a0520ab8514a0e5700cf36510c31584b061f1836b699c521ffdce1e99c0e89b5dcfea76c532f34f0f92d811440128a9bdfe03e2f4d24683d7fe8f183977ea8f2d944bf544358e0918041d55223dc07b43685381e118c6a3ba1a4fa713d1c2a4a3a97839c994f20c3013ebdddb59b65bb0011f6051f586c24eaf547bac67197cbfb47e939d5e9b7dcde3c5d4ea20b1f7c060741c76b732e4bda7ff60d96ed4821e2b971b86bba909b6939b71f8608eb662e62914c0d4b538c147a086beee2d3dafe979001300568cf821027573870356c330c6e036badeb53df3d357b97f1c7f9d7d370119e77913b12bcd79dd62c0785216292327e3a6880af7b6d7807929cd3342eba9283427020456e980d1d643f21d73522a0cb0ad4482931688409d813baeeb6ee34f654c2cf8cbe81eab8dfbae134ec60deb1b3ead5e5eecfc8cf8c804c49a988d5bffa77054d3b6fbe58bd941948de3e200e1fc316a70edbb85925d469c5e2897465d7c3e5c010646c36e09f1593e3f51735adc6bee6f9fa557169481a8695dbadd30c6f2dee99e6513c54376ede961d573c1f3cb16db9bb8185c3b908e91bb54be0225aa6d51efe24857de5891a7709bc9eee680c756461af9753bbfb475daf342e6ebcc6fb748536c58fd5b7dae3d2d8abdae2af7f8a116bdad5cb00d4a8215a349bd917ff1d450cae6d3b975f40630270d820fb983a30d602c66dad4f0c1cad0ec3e58a3315bfe59bba5018e46b956bbba8c77281aa25360bc431f499e549e8f928ba59527ac5cdcf39c07d3042e86e39d6a6ae8ef0f70a08d1fde3f7ec1bf6f66b9dad0cf8ae90428b8444168a90c0580156220318e5bf2e8b5e70e2bc6ece9cb04fa0bbfae26f607b804aa5736168509658c609c86a0cce70ae5daa08b14feab81e48c9bb3c59c1b0f62ddf690d91db364ea3286cf219e29f0f005579897d1bd9a8a1c97a41b800825c44be6c736fe3bd7047d0a2bf3124d921b7254bfb9d5993a440c0954d4c6ec53301b96e1735344e1c425a189ef90c7293dca0312772189f5c57ca07e950dd954a766d5779a191922e19966174075facb6308c5726174b9510075770f7915f3b06f658ce2a5c7b60d86ebd88574fc55cc1c02b4ac3b4320748eeea6132dca3dc6f5ac179fe71d6bec523be767cd55a9f31f6289966041c98313d957871d67fd236e24cb549ee258f7fe3171f1b09ce4b8f4d696fea15fcd087c75248bc919c76e974643797a90056c9b6398a340bacebab26a790fac76ceec942170938318fd9cc51d85817315db8580f5e34d1a00c1af6d05a5cf14e76f8e84477425ec910a3dac1e6c098c1f147c127e95b3f4bad2e01dec8c35931dce2c7bee53598b6bde7973071a0a6955d9cb9972566a80cec26f0e8ed81e7951a4efbb575ad6610a864e58422045f40d1f252564ec548b5546695e831bfa1fde8b6c5f919eeb6c8ac9e52753d0a6c678609984a35f7b19cad9d965d343a2b71f34dc84040834cc3d4e2fcce21788c995a6662684ed2a4be0e04f9acac09651a0754727b7dbd694d2a53536b13af58c89bc8f73397012d16edaf370a3bdcf4a5328e898a1626611c9f10af07b53c1deda04033e1b81101daadf8ff6df92ee534e5c8c3bbaa20b44253fabea55b28d22d2391346911816d0d8cc248a2140fbfcd8f2d0fe273d0e462acfff6244408d2c5b54e63afe35b07bf388cf2d7daa7fdc18785549b578d659486d0fb1a18d1809526af40485a1a19d2139346285d54edaf80860de4d4ccaf17529a48a69c4e4122edc0994dcfb1a90fc88ee511332d5337d4508933a67a95d0dd4a23250ba18c0c1235783de853b9011daf25daaafb7eb80b34e1f5a26cc4d3512b453fa11825a5bebc5a20d0910fe038ad381bcfdd14243566610fb1b5a3352cfa6b5be72c1704e45c9c956ee598be33456ae20458f125abc95b84b80240f89842a3138b5ccc9822bf3179799844872390fb597743cd1aa9d2b44d4759fd48e2d162ed7fb41c0bc62122f892364cd6b72927fc6061d4cf26958e1ce168a1919b6d894173dc8d85412268b0d379eba4528ce085e30955786f12d57962fe451c2d523d51cb9baca878322bb7e297b4bd87e43b7f6801cc12245a7bb8d7cfd9ac8ccc44795035eed38ad0ed080afb4c3c5485a52ee4f5e620ba11240addda1868e97c3bdcd8a83282330f2597b97030d425ff6092396afb002591b82fd07892c47c68bf3f62e4081783b7a4d67486693a735b34f2eee3b1746714ed4125aceacc82d19c9b343f54535b23619509c2cd0420c1cb025183376bac82afa30eea09ab0c9ed51a644b4ae5e5a863a63f7654adb046b295240b0e88616e53cf40aa602bb033d908a5444e5a8b78adc19930591c01946db369fc3f6850c874119197ed6d45624fb2a56890498be906d1ce405ab12ff4ac82ce1e23002c7a366128a2f758c59bb3d6bd306e7f4e8efbbd3d244b555c0a5192564390d69a9711fafb7b379ee72889f1f74cf58806bdfde655bc93d6b07831bf75cb4c71033198f2e8058f188a297a486a32835104968cf14f3d755d9bdecec0f94035c8679618a245f22d81a0461ad0e024054dbe3016f1fcf2a879ac891fd5106608ffbdcf3d11f45ccee091dda2cb13f2aa44f20f1ab83914b7b0aa2ba97b88d928a4b8cc0290f25af77e643422aae968415e4bce91a313487745c8d3c0505cef3be10c1f036a336c9eecdb3d4a6cc3d0e51cc8d0cd274f0e7242fe5f3139b383ff3f9515d9c97c000128f1522679070c725ee9fc00736a3c7441915bbe9c3c6ea7bc38e42b1d2d6f17717519c1b81961ffe69773e700549e494b90ff1e010340a9d813f2eb6df8887acda12fb90000e0e505db744670a3208f4c0e7e920f7ce35834657f4ab8c0184cab5bf9f0232a88ac0051e5798174988806eeea46858b5ed68cae539ea970199c98b3207671c4c270452761cfdc2c7119139629d19215776be4531642195195a6abfe50b50abe36bd26ac4e9b72536890598f4ccea5b5bb026c21ba3eef3f14875f10b37d783f7120bfae425dce01f2323a04515a6c9ee957f91dea4811d11b7f188ff5a272d89bc507bc2eee213e03917cd2c8c8fc27cf6ac5fc6c89dd8b629ece1f6a754feb15d595bf71bd6efc3947040427ae02fdada3d6579900ad5d668c16804ea9309ec56a54bd70502cd7a8a787833923604a3565d7b5fe2ff4e17e53cae04ec8f7a783b4fff7744826a42f38d87fc31c88239e828ea71d96cec115c0fd62a611daf325c5b310ee38c6d306358bfd6c1c6943b37aa6463083c843acf5a56c29e8ad8a2b92972d33d2ad507858986e49f9d4b578d2d02bfd5bdf320bb32fca19adcfdf3a1ceb49f3b1066b5af0165e8d449fe64a3e206270fbea7495ee99a4abc3eed2d591e4067a1a5a47655eadf13388bdf7305abf9385585130b1136a61b853b6e18118905c18629862ef04ce1f9139aeec31c2b763aacea6371067789a8f58c305fef29f4f6f8cdc789e5d7755120169e858363d8ea82ed17da2381a03ba9a4d94a8ec3bad452f278bfffb40a2879205aef144deaaebe4bcf2ca13d15911cc682f0a0cbe43c023f742dad5ea478ab83d98aeb6ec983b57c0011f22db7a8cb99f2782e7d055ec5ee8288f62d240627c95521277bfe3d2e121ceb296baed42a2fbc8819e343492a39730a110977e7d1d8054f6fad40ed6dac8c31eddda1205b087243335b323b969591237811282f7e83e6639672f9ad9fc553c37d93d946de542851b058b3020664141533e76557d75ca8fc5b0ef810ec596079e81d1460f3091bbda7a7c1efa3aed6003185ca144617f87e3a7ede9f743e6e977786f6fe53b4fea9a3619261d783f946a13c3fb9114856aa06f18b8c3be73ed7e2866370ab06f7979a58c16f7af20ed76d2d6f91b0af738cc5264d6f2c6a786aafc1c01d598bb8fa84f6a7e454d0348b8bcd41f3ae1f7b028337faf664209272fc7ec0611a8172dcc269acd9f607e26acfa24ff16d8e772dfda4283a63a73a372ef55226ad58d19144a526ecbc8419646485e042106076b482d87c9648963d2368ade1b834caa97552b417043cb900136df1c242e3f7eb56d79ebaf56bdeb6e235090f971905b7f2e182548929e025697e2edb295f3bc57b63a16f9efa707c277dccbe9ba94087596c46f533dbbd05ce3a6d605f37f1d3358776ffa50d7228d4a5237d2ed02d77a834fcfa7fc44c1102aad4e244a6cf26724aeb15dda5981cf8177623f249b8b763ba4edad621d119c4b017ada842f58708e25a503f6a3b75858eda21f429f7aa0d80f9444ec0bf5ab0cac03d0c682caa3257748598db2963fb767ee8393d7c5f631bbd4b858b236b4ce4599c576b9d8801cc9dff2af3ee5d67be05e4a5137c263b04d64f6278490f802c202f70230305157835e2d6174702ea87ecc213b267e7070ca091e77e6726d5951d6937555e6f6ff3bb8c59c9f73ce990712a59949a5071e4b9b07a42e674ae95cb0544f6722bdc59c1e8e471d4986c04cced04526e48825672ccb4430a78fffff4d2ebe953f97b541d6065a98a7aaaaaaaaed8ffaaaae1106d0e6eb05aa295befc88f891210a6745865536c5cac54244229692549abb2964c2477944a301972b960cdb411c2216c8a563645f5c99868533389a46555d814b635eae3ff3f972e83e0eaad3f9a6be0040fae9a96872786232aa3a3af1ac618bfb428cd7c717a8084bad60e4d702bca7ab2ae555b582d0d8d20451897f91ad2605eee91f9d329019cf1d8da8367b0bbbb3dd1bec88a61e179c191fa6c01ecf88211c312e300ab0cc74156db5b51d693751dfbd1fdf021d5c2939c2140d61b74621372a222a25122e1c2ebe3c6a6a6f6bbbbbb3ba010629cfea829943526f115326b5dd30865d5b2a2ac27ebfab076002a143a70eb122f898b369b6dc5995c318b5043c9169d5bd489546fac0a9bc2b2972003ab13461ea28c32ae13c8140d63580153dddd352bca7ab2aeed29b5b505c4465c3f13292ea09e8fe3865b7777d48aa42e2b63570dae271ab8da08a9c4058e4b77b7cb6229182d3696dc9278dceec32e5ab66c5ddbffbb2af84ed830fd9284c0d29a5e52841d2fe5ad47940f175dd45392f4c678ac7954ddeef64c8110774337f6ffb18e28cd44263d60298b584b9c333fb843b537e79d4bce39b6d6387d0504f3ce30012e3039f4aa0ce994450301de8ab29eac2b0f2de608012128bbaaa1a94645950c4de4d443b49112e0032a9d4bb76b8ac061bb9935c3929715653d5957fc12d6c7ffff9e77e57fa744f0007d88ab592308930ddf970d163234323864f87f14c39c7d5a5c162e276fd99aa41bcc38b6c0a2cd669b494da72041e0180faebbdb4ddf0c052676400b30785cb07462109da8ce14c12dafeeee0f3d1dc61b5a93b6ff33862494663e19ad368861eb1f72b1f2e7bc588c802220b960ed9011290a6a1933b8009821769ab090d8de7f96ccb53bac509ab9d5e56187d82c67360d4d76dddd6d18aa4c69a6fabf10d562fbff4c4294660e3308a662ce6fc953b2f7df4ca621b6a47a6b8d6cb8f16289dd97354f0e8ec063d0e45804b3a2ac27ebca7b9b73ce594594661e91496587aca5ad8396eea58fffff3860702bbf0e1b2d8b8cd40c59fa4b793897125d379272c920998f1b215217f15694f5645d77217cb6a6b6e4a5bbbbc99029cd549f32fd60e175bfacf8733ea91411e3f0ff8150261ac4feff0dc00986d588592e07dd750c09142f70090d21239a351853b06c77f7900fa5993f6088a160568f6aae45edbe6aa4436966cff7fb6004bc0ac618639c5bbabbd95a46a1f63be3ee6e2b94666ee10e325d286ce35815368565310c4ecdb1350cb41a5be3bbb229dffd4a5ab56555d81496c5ed77523d9f6d5d328258b2c26b7ef9ffe70280e9f6ec51eeb8c4136d58fdffcbb91473d3b7b19aff1fcb86d24c5d4f032cdf8f76769e865c923bd2610fb2fb6079fbf8ff0f2534b4f2b7b8d6ddad944c69a69abee4803cb37703c09b84ec171b390caf16c22ba89996a797946606cf30ee8131c637cabe59368ead71748dd36b1c5fe3fc1a0728ecf7ee09fc727158f7d41dc7b52a97aed89d7b61cf20dd7ad2cbba36f310b6a42d8ec8e7f032e7bf55f3ff2be9509ad9f3fd3c5002fe3f6f841a5b6245239c747c332335f5cffdff3d6c28cdd4f57cbf103d805db37a8b31c61877dbf296addd880132ba8e242ec618d718a234b378442695226a2c557c9382e2c17b51067892b62bca7ab2aebc921b43160c94d01325b613b2947104caf7bb3141614609163bac5e7e3ace760ad8fbea1b3b4598c7aab0292c5b03005e77378ec40b39dc4995245b7c97430a9cab1897c5fdeeee6ea916dd4a37c61d6731631fbe106be707a29e9a33bb73e6f1ed8992b1f4f1ff9f461289e4089b9e8eb6d7474b12a511bba99c730e16519a794426952182cb1aa7deeec52da705590b8104494f46ab7bf06efd3d4f91c32c901b784f8b218e9a8c68a05c0cd13a8f3b7eb83a154c62329634f4248f43ad087684305ce398f0f471146488cd022bc8f811923b2292c3e3a846850efbff6f3184d24ce1f0438be2ff322b9ab44769113c76e1fcffc16a5cdc92654a33d5d95bb25c4f36e89eeabc227470569fab730855da6cb69a99596c912872dd66deff77e8c043aaeb5f1e6753532f898a2bc8c66206f9b1e85249810848d68b209e196228fa884ecc540437f0d2d5e9e888712372bb3efeff5f97338e8cad29221a6c36ba860d163d97a5006ecc38ba526c94f08731cf3d41f410b6d8a4694811efc61e308dfc5a862472445a384ee494d0f755c345219b825d5cd50659dc11917839a71042af8e28cd4482b84afe38ae942b3760e5baf45dced852300f0613cd6870bb181508993671ec97ec7e79250930206408955717d111e70c4eb930f2faffaa224a338f1eaa9039dc345ce668055f1ebeb12a6c0acb0a91f4b4d7dad16f7a8325af407a5891347700cdaaa189d1825a6e93156528cdc4b52f4e4f0816406d8117071a8c31c638aa09001a7528aba5458f251c48bd4444aa5154342d3ad478a4fd7f18d44be97be9eec6f86d0b3f2576ba96c8ae545c8105d970c09df8cd7a5cb09afbff9584509a5994f464eca0648577aaaaaaaa8a337bdf5a95daff1f86446966324cb9862d51c46cac984e45ac57b3402522449e488f9501820792373d2db723c1125a472d406ee648ea5815368565956adb4ef0eed4d0b8015b21c319b60454b26abfbbbb7b92509af96414d16385c2b6dd3e3b2990a2ce8ab29eac6b1490b21cd54562e66c81a7d301f3824caba8c914d21b3143c0d6d4955113d412a8e753c4cb811398b2b46010f278f05801416163fe08fe3fcf645194c143bedc691221bbe15b427edd30b6d2afd8c7477d39c77004df6e47621cb16952ca51559574238a2498d24cf56f4dafa4f9012a996b915d581536856571cbaab029ecdb4c5d6663d1c7ffff1cb61c22872e6723e4520c1d442f1518bc69acdc7835e49d36ec9e2716d030a88fffff01ef8fcecc06d23d4368853c3e4470158cbb0257e002a6c88b5b8fedc724e34176cd7a39d7c7ffffa82572e5ffdbffff3bf5509ae9fb013308a7a0caff12e0e4c379f14ceec9399b90455ecbaab029acfae69cb38f10a59943b5b81e51902c083e49959a8bae2ca6254b6e68d316f5e043974b956a50ef58153685655b75c74077edbcf08562c44c52d4901f27b058b28bc2b12a6c0acbe217dd993986b86555d814961debd66505807a594f742bca7ab29a6bdb8404d4ddad43820bb025b29b2043390da51563657adf740b57c3d5fad121ca41e4f6c562654a33d5decdff5fc48d62ce3fbefdbf4c12a5994a0f64966f115343195239bcd8755dbabbdd54f9b7c45bb0375bc21155228eea85ffffff15302436214a3387c52332790f6cca9fe4869f7ae07e1cd0bcf58aff8c4ca78fffffc5b0b295ffdd4035030fd44c6f85f24d81f5758e7530b662d724fd09d6201fe3a2635a35e6fc254df00e05feae0257316163238af8308a0103ceab86fa529aa97eb744db59dbc7ff7f61cea80957336e37398ad408eaa7e12e9733054d3e2762f070a167c609d70425263c7182f39bf5b8bcb5d4f8432cd5b5efb74f27889baf1baf28ebc9bace786b075e60415c42e38e19352a88cbb3bb73a8cb8b0b7c90a674c4909161a49b8080b93881bf9b09d9ef37c36abf33eeeefe4262115fc995ac8acc07b79393d14cfd55d653dec0dadb060e54b5fdff1fb72c0df81e9596924f3227118d12274a4b48079f8527231f1c28ca48109934f460d0c1579ffbff91921ae9a9918c8d64d5485b8dd4d548628d54968998ec54555555754bdda563099408c20092540449662868464cc786d5ddff3f0a08a5994220a28a5694af92165e50f514b946388854a72ea6c80cfa04b595ba6ef75b53fb9d7177b71630a599eadbeeee96b7cfee99931cc298d8e8b101b4aa6deb1a65a4ca5bce2df43ae59c734e12a599ca10394b9baee7fbff16530a08885b1c331bb639e79c5f21946616059020a8946ddee6c40079131a68040d0371248cd31863001400070c6a94b4787808311687c5c1a0480c0484026130180c040040a140182c0a82d068aeaad17800a9362d9b755087dcf8d252e1468564365bc5a23186ea284aae53a43daa469d13895e5178dc5b2b30f6db8c5b8ee015ec4a8f461befdb5090b46549080152a5f5c6c1719314fdc262e01b2f7cb846499bac1e5a5c8b5520cd8497002e3e611b62c8d6356057eee490bdaea48a573a2d93e28830caef4f278d631235b561e51fce0ed32674e53f5140a552cb7c0d081c6388e0e53a5effafcadb1e9bb7b2e6da0865e6d8d3fa48fdd8523785e51f71ea1a27128cee1c5d7b313a04ba1da2b55f9be41aedc5ca165f290751cf0590cd0d4fda27e79761ae35b87b26687011cf31c28ad9d213cb6344da3e3f74b2b3537c3c235bd069f7683ed20d21d4b088ed678cb5fa2a8b5490f1b7bf61818323e03ed030f223019ad1775bb4d2eb1c7b0de8168040063925f1d163b92332dc60a11e8fa243ab93c61fa4c3ddd46864a2d2308e8fc72fba05207a5cff261d3ce57fd7f153a8add024690786bf3c69bd9e960280f148bfdd347b2c4e8917a4c69317fbdbe47b65fe1897ca90aaf0343c7295c6066ae25db25a775eb1efc34f746a1c8bcbd876ca1a2cda61554b1aa040360a9311f60f9eb859eb6db7cc115a2a1a8a6941cbebcaf6f168f51d1ad31f04589a44a940b87979d0107e60ec29246a8ccc420d8fcb4e3ea5c9ad027bd880c3948e6b7159b4a8a37f4cd55e4911a95427b5d31f4d2e256e27bced380dd8d246cc8829b585e8f429a07f12dd81c90e4aef2cc53877cd856996c1478ea4231f03dbb9cde6d8de7297ec59b50b45e032049ebd53d24e41279dbfbc974d67b9938564044581bd86a8ef7d6cdc08a29870510420372809173a9fafcedcec4568d34eab4f895b5024e18176a716b453bba8d17c4aa98641e0ade052f9272f7b879a028af2df79c3a056ba73b0dcc0ab1dbfbb3ecf2a45e574a9214208b332241ef642a9b3a700c8f059c4882a07b51c53c0c4c948530ddf491f68f199e39d885c90506d27e3097393314eaf300cd5dc2bdd5d2f3e57a48999a80f83cbf9c362786b75587cc2c110b6df4957d4e698db840b57f3990871489c67d1bb9709db69cb1d53706044b9c4beb1b1adb6a704c44f90b01ba8672f30afb5ce0a199edd47bcb8e111e93344e453b4d2244f262a824b6193cf528a7639103ac8b8f2a9bf48c2343523120f50b2cd953e8adc09dcbbc14975bd51999a584ada2ca8feb61edad30207495f2dceb01a900e462e6039dc910c907c662c6d15f58cd2e8df6e596b650c42f533dd0d81d1c710855ed25db4128e89420b34545bcd5aa3e8d1c07cf9370547599d25c9fc3535068d70d49bf3178596ab1957e640d3c1c9ec30ab08cf814acf3bb05ca64ff945703c097977487372036f25de21d993cf004ee36e30c75fe07c8e237a9a01dbb35788df885ddc18fa956f48bfe02d9850367135038276ad7ac5cfdd5aeaa97facc69751b681d13c3fcf0f0452f8018b861cc8eb837bdb995d8d04681627cc7ad38588b3024e671d9ad1941ac2b52ff4a94ff9ec9119c77e26f4f16b2da84947bae7c04807e6d7896a4eb000169b8967d635e87bccbb421fdf28d726084833494e7f3dd1f6aa5243fb3ac63ed839d08a4bcdc162b3595e9d5ebf4459d602799f8bfbd5586690b47ed354eab043c80b429f3b4ca1c0e42edb66179c066fac66bde8536217815d0c77fee1a07f688191d7f3b54a0584cb0b21db23e415fe7ad635084a5e405de7c966d880a6746f69be38a57145cbc3f38f131b5b21e5bdf0498a9e2bb907d5aa73183bbd5e33089b4311958b675a65fc285b577710993c27a5231644a4e96ae90a487ee4b5f25548fd8b6d66f546e5ebf31b5b22d90630e8e9505e9479a09a0b589aeb9267946fb14fe12e4b5bf927e8662b339ca794bcebe7924a432b6b215078fc811dd261095648c9f765445061abd52791a68bd1ae7496b0272b2185476bc1989a6dba82cd1e6595ba632c3c2539e2cc4490fddc1983701b68a2790f7ff8a7b6f3504497669a34a6b5df26ac7103b1be2d273be43d06cfe8503da2511ac3b9093abf2e5a23c034eb8629158e83605bf704cea275cba29d285a1868e5d6848115adca25851956892766d702a8f8df05f238a80c2a402072804596d9116cd5da5f2fe3f834001ac6bb2609735f829a9729c75aace0d836b8065dbf5c8df4e036076bdbc0eec5596eb839aa9f283ab945c837d4e89aec18423f40e74d8cf50c31ff70db8457a528c77a3e540551713c65e776e3272224a12720a9b9e434ddd663f81bf7a6ee289d5fc5c00297698a96aba2e380fea4cb7fcbfc438db3b037c9112df4f081eff2c5bf86c1c8ca5e279d4970ce10ac5b53260a9c2fefd849d37021d84db480268086fe18e2e5b029c72a3852341224da2635397b4231b8fbd5efb58bf18e9920bae9463a4980e06a20cf274249c6005bbcfe7ce8dd18c24732cdb4ac1bf83d11b657c55bf551d7b85cc81352d7a7c53e89bb842e069f8b2c124a6af601f9b69bcef5e6740a0ce981c6c7714b376ac1ed6ca411b2609a0d4efddf50162a9a18c4213803c0ed22e26c04dce7b9032a2229a2c083b04df26a7f4c657e471792b80fb7e08dcdd5298ea718e1805344b41e197f95e6edea21c20a06b24c5f28922d3d784a3db550c565354db5df30631d0935751bcf76da87e0e9a011f121f4da51412404c9d533ea8f1b47c2a766ba97b8751079d3abc46d9e1afb396038767c27d5737cd76cfd19027c2517ace2a75d1f2d7da2387c4a568d9c5904311c9fef21808ab53b5830728ccff0c1a15829d66e8dc39a93d514b76b89e25e9d555cb043cb9d3a0e67a77c8ef637ae9e59c1be788c702cc609d62950454a5d9c578b09ceda25e6bf646822edea84c8e59816c400a69df0178f8bda50a373bfb87b442a100764cf27fa86762ddb6f1c5aa225543fb481039a155063cef8bb3ff2e592becc16f12b8f93d10ca7bd85a644beaf8ce26b7b20a3ca57a6780188e2f69f9d7eab8449aa11e447e81c35a2a2c7771cdb03c1d4f793c81db60088efa7525a972757d5d2eb1776feba731f8830be46903f5f1411464cfc60e10d96c79d2503bd6befe426afa55f50d91c298ecb41f2cc0f06dd7fb4a868b05a8a9ef77b074e8fba84274b104ce035f24e70b17b13a5dddc4b3ae4afb24ae106e84657b1ff6c49fa936154f1752f996f6ea52be089cb271a71c6f783c5997e91a0552fac57f96413a7df75af1f4f8a66abe2e4135ccbc3d8d8d6fca963f9f533e50307e01cc56d5bdf4feacc7a481144a30d3c7c55c6ab2a5c9ac38d13b0cb04ecc556f816d52db834b498546e7824764d532fc61e67023e4d178d2707147b0092326e06550ccb01985b2a541513973be2ddf77c2c98099f8990cf5b973b5286c9544566989fb38bc5247f2d5a1236d6beb0cb0f494e67b19d4dac0e73700df4781b55eaba76e47bf70066d446295b25417f50d0814e4b3530c7024fddb0944d737fced13c0d7468f2a1cae92ba079f3a212f1c0875d95c9f86399f8bc530c36c8a3da191668369fd1b569cb210f73b09820cf233bbe24d37d370caad446009b2e668b8ebf147e6fee3cac7025d0a2ead12c4e9e4d048658313f79ad5a630264c542096ffffcafc920a94d3ded10ef4a19a576f6e80444ec71712de5894aaf9d467b4a712365766e2347beb00c4b98017a2fd4955a3ab7285639dd392b77110c9c1c1b2d12b20a6db882c00473798ffe2d7b3ab67acdf9581ac9484a5000817f0b57a48b9ece8473f75d62ed4be91653391c90280e4be7b125992693464a0a244222174232851f3db684db69d822b1b8c75f36af99cd6babc646e9796a2a2e1551f9862c5df57abbcc8b6873a900b24ce7abea3c9078941bc4807f073d624a9514c8b2146fb8ed92221633ea1b5444cd927035792ae8e2c22a206cac941f7da4616aa0e32cb533bcfc704b421a5a676a2e93b0505c95b550d4c544e00267dbb6f72c08576e2350e1f469f3e98483749111862081de8772d4b56e7a49e96a234abe8eeea3e116b5c24746bdaef6b7d3493275a86ddaff53e254618fb4a19fb07b06e30ae735850e508df75c9f19de0ef29821309f3215956c124129bf0e4098b807229ce8086074b272accd3281655a57a501733a1da0399981da2ec635447792f9e548724a19f09c3fdbb2b78e747385b38d78a995c203d80254b4994420fdd4e01a32d812921ecc8b9c7d183ddad7d23d1f49477977a961f6ed52ee658fc49db2bead3b00d4445d8cb97b6af667936aac950647d04f7dec399d5bb2afa1d386b5c29a41583892242fac073acee0c7740470225faea9d56a87c6215b60c2c7ca9734afe6bf501ef2b16a25b8c64276475862d9a795aa5e5e334442f9a253d1aa5a930b88a83970585559b7ee75ca8a2fe119d85d7b8249c9ca40a079b1b873568e1b5551ca752b629be3e06ff7eb0faa4b490e11f169d15fc97c4dfa13f10fa031ae24e8080137e5b3690ed6ab8a7ecf87c7577fc2d8ad055c8214e103cc8920ec43fadb5e332b4e05261adaa0a2413b37b1ff24c2b81ef63b9bdad754cd1737d28904bb5670779d624f5bc1068cd0801e6001b8f0306d27a5957f15f60d1f3b443ec1b2d9802710178009518133e01a4fa23257e2302ff1ddff9750f6fc024a837c6af43b46a17aecf7bcc0a5d980bf7e91c36b631cab928e7652a3e5395289179e82399b02c978398c4e4796c2efa5a6cf4fd704ede56334970e33d447d6146bdbcdfeef36d319c0d40d3cadfe267a4bc688acbc30c9fc52689aaf22b132504da6328d3d259c692c8614c6f114c2136c651b2849ed57681cbce5d7ec868975d13f3b22e2bcb18c369a150158f43c588f848518a1c3503f525491444e881a8696f16b519af71ccdd9780c76e973e452fa293057a143030a0b4e6bd895823cf05a6dc82cb945740fa2e2e85dd61fcea1f0fa746c15674086a9839964f7382b9a0ffe83fa03816808fe035a21d6a7ca3675d7b1bb7c16eadd24b159d2d42ac8cfdc552389d1980bfda9ecf64ea08426a51851b7d24f05511f813af01fb2d15ec806d423e72ed88249a22b5c3428e0e51b9d1d6b3b180430513c2b90157403a533edc59300a243854217afd93138c291a9d91c861a66597f1c0a75708ce831bfe516e8a23f9eead92a0086d518d7da90b5e096652efffb956a443fa022a07dfd5aca652255b4bbfa4d6e7bb38778a0ecf9441718c9fd6e352c12b38112bb9575bfd5bafbfcc2bee0b8d36cbdaf4d8a279fb2f2c4688d7900602553a9d939afb7bded4c3c37a5d2fb7bd02ea964bd9a69a5c263234759936adf5f51f07cd2cdaeb75dd5ff76b4902adfc34dfa2ba87d1eb5bf0bb7d3aa9ea8308dc0156b5ee68c85c67cb39352aa13391e126a2308ca6a4d75e5110b0e9ae17cb0c50de55f41dc61f0cd5ca6e79715841d7bc10692cd9881858bc51c94e9229bf1992361e2e2bf02015ba3a9b1cb2f04f2ec93a44956c4af931d28f597f0c6ca20278ea4d5888d53971a147aea2cfa9aba84a0e82fed663cc3f65ee777e3e125eddc757ae872a6b7dc2560d07201882badc1fd2affe4b7775ef80d45ff2feb7cb12a9121ddd54807c1587bea92c8ec3bb40d154828071b6e417fbd5511957577aacf68db03863d4776bac2cafffeb84b7b9182131aabddc536355432bcf0f696a9aa126619489e1c2f837e56090a568740e2d036e1ad58ddc669f3eaeb25d781b0ca4a2309e5ffb034be64faccff6797b8a4fc845ba4f183033f1ab983220670ffc2231999ae83ffadb834c048dbb4d7fa5ccc3bd941084927cabb0c7ae5e10f7fdcd441232723b42a53c91c716cfd60bd1371d858f58b717353649911cd818916db570b2c071169ebb7653c9c590d438783eaab595ea2702f0ce7b618fb342fd2e44324ab75a30a4e6d5d41dd8d926328e96f99d871e4a368dbdd0b747bb8532b48be47f39a153c69b843532a8e93d7af5d643312d8e5b5a0c4a25f42219acb58f2a70185476e6e08384c5c6f49b77819579789c11ad80cc72568b6c9e9ca2dce874dabd6bba4de1b94886a49fec7cc5493534bee914bb968949d4e9831174104147cb09ecb22bc02aa12f5f38d0b5f26f0053046901c43f244c279943ba89b11e1f1c79b935d56d06f6bef29bb9aceaebb31884f5044cf3a013a91e663af156b02a26eb6f83c8cfabb0ba9646523a610d6fc98009973a394195fe11da460de87f866fe5573402d801d4f263ff9965a7280e28bbac1fb3a91532b116666f1014580a361bcd554368c3ca907f8255487d14c049ee329f36d1c965f0fb871c65390ce44bb2842a5678922df7aadef656b933226b0e5f49f1a87934e662483344f5b90192273be59a78d50521104002e0bb4d70665d566e48f7448cc15fea67bc89905dd64d560c9edc3772d7fd0fe79f04e1e16e153b4c198788d4958a48c5bf6907e77553abddebc4d936111042d296b4a8cc2094514829e441437056cd6627d8e24d3402595c750e0d6bdaccf61142b9eb40d792fc1263427c75c4804ff7a085386eb563553020d5a2d91f2b938c451d0e1e46a5e477f6fdf6230c4eafbddeb1e129692601de45a6c59a2902133e5f6a230745579e1ee33275b7949954beb877d6213b8f9e936bb6029697b62096eca3b90903a67767f7171721fad61db7398a629fc90e9e847224950390feb0d01424edb4a4e35b638e838aa595cb525d25225e5b021ec60f55019655ea536c72983be55d13bd4e96587c7ed40f3b4f505f0768d27f3233e3826a779b6da96ea128905ab30ae2dd9a9274f0d2b6d99e1d25bba5b08dce4414451e17b3fa4c6859ba8c4afc647dbedc69b6fc8b76d45f0224eba4fd5c40dba0b542bf719df330757f504b21a1aad7f1d401e2a5f83d2c6d2def10155855e5956be4409a483234b7c34f32756ffc36f090c50992fe760a384fe8b8b759e16c0e65b8ce2469aad7cc75aa3126b186eb7be7f494dac0d612e66872435f5ae50ab6971f21e6e8e22a4029135a61b7984c9f5f7c4e18a0410c3badf31e95fac7cfa3d154312c3a4682813c11462febbe9dab5402b434a4f05e49f052ff85a0d4f45bb7192106f45466f5b20c3c70847587331ac70b6d0f4bb56230fa6e66c50038cfb4624fac635162f6fb87cc1cec3726c00722b670a1efea68938df478446285c70505ffceb73aa508ecd914b96c4918556a269d38f495a8251b2b0be5adb91bfec46f849b060967363139e2d45f127b22b0f8439cea55ae51766bb3b92cfca3f4180bc8a1ef7f548bd86c4cc348b8544cb3db6ee5cffaf1929356d9288cb80407e847082711ea1d233184ae64a78a6a46ae59a4510ca760ab19d7d4e0ca3059ec005c0e864e5589b654150b015d2d314b519eafcc0b80c768df4e54836a95ea3ba878b035b0a05ac8826c5306e3659bd8126f5a261dae5b3851472b3cb8e118dab83603a556232584de2ab5d5cfac6d967120e469e0a249c2a84e7c2aa22391db067a3a275dc2a092b81d30f0fdcbc34faaf08bda5adca3346ec6454a80d366e899c2f7cadb8f4033ef6801f4ce7505fb9f5e9297932d4b73ff34b69074d344473edea2d1c4925f5c2b53c8436839466313c99b431c4a191275219dcca464842fd4a8352f4bc28ca6816e5564428a218d1396eb5f4fb77fd978bb38af36fb6e95a205e34cd60cfdc31d8d3139427e3707d7c278e09dc9b8a779e465269b1a008776d0858f259f86cb188578370b958c4bb8b76a169daeffc32533e6dd1c2de30d379e0bfb66a448b0f3060859cf1e061ee028af35bf19db4166d67846564c600ee1b32ed8ce2f2804d5646aad46f6f8777af521c4dd6a0bb77abcdb88c74ed3e9aa987517d220108b1a922ebe9bdd0598967c5d22003d678dfb92172a40a02c641e9346e75e2312cd96e7ac7691062d74ed5b2011007f14b9d6efae4e95b3ac039efac873f07191ce29a3a77aac664ae8246c66268b102f78c60330563d7a56c026214a8af6f2dab6207bcfa4f7edba740107d51fc2eb52afa264c2ddfe1827d1a1d7748cb4445b2f45b4bf953239bf7e60864399f74f5d24c1561c1176b8b564bfe086fe44fe158da0ec3a66ebcda0345bf73b5dc84a4698bc1c3b5bf5181f49cf3c818972d1d5b58802a4b7314b83be9d99ec89bb4015c386d96e87e99b3ced7eee25b9a7a22986e0843d77aef9caca912b5d0c88f55061380ea1529cdf84a222eff2e5864596c8cd9124646384f0cff8ce257aa2eee2dea3c3845c968e7b1c794963ab7e0908141a0d262886a99bb5fb9cc2ecd67c5574ffb4e7cef3e257c8aacc503f343ca9f02380b6e2726d982d1591818417dfa0ecca45fde0ed31a94b84e858415e52e22f5b9766a6daa8ec656da88c25c5c79700a6b9a107647fbfc45bd95232a2bdf60db1fb6bdf309bdb0ccccad1f11efb5dc1711d7cc3edc0caf0ca1909cc8283cf2a0042aec2a386cf7460c95d20944ab34213b702d777f31df7d266c3b12e63de1627802154a13eca949db37729d8d5ea9638b3e2706bcfdc5f20f2f822940ccc657083040464a9f93aba30924406880913b6f50cc7c28ca331d8d1d02f0e1def8a485517c0419fc11c39e23914fad2699e57923472d7145fd0f06afc16b379d8bb8a69cd0273254d470cf70030ce3fa02f1baa7213f2c34953515ac2e0ec98348f36fca03d91e8697cfd74614cfccd74c7e4798cb3d28bfc961136e2ac71ea2aebacb81bbb0829a0c07f672be14b67c03d8d9f31f0e2f079bc71de86b8b96a0d04e057fda6d35a7bdb49db820fd89817a7a9a28a5521eaa2d59858b96cb65a380b589ad04836f715661cd76a7eb5fa6c9f6d0a2d59634a960fc11538d24812af0cd6afc0d4b093f1801b6d001c24ce443e21590c524d303000805b45bdbb0e03447da1360ac21ad213a6027bc06c3e10587b4e26967b33564b96b530a58e6a5a8051ca179fbb5547e2e57a0d43287cd018565b6b75ee05ae07b8016948de2c4ca919a920991e025149b093a8c2fdc9ff78c7cc9406c25da988d7193b2bbe45cd379fed3a6ca7c322b05e4bbe017f1f2fdd3b2dff9d641e99a3d566d6134550196467e4326a20f8d1b090b8009c3633d80e776b2179d52854d461e1a8929d1e5096dc8743cdd1cfe7ca31ae14ad046ca127e58a3097e81c1dc164bf8e17d4829cd8de665a551a0b1de6c4d5e094ea71ee568863068de987841de2327e4b70d7b87d846fc1e05d1939bca72c93146344659f71332aa2166e1ff3417077cb28429b10d1c22da1a2ffe7c673ce6ce8fa1e66f22b1e28fbe63a915a507b095a8aab9bd16244cd369d39451dbb5db4145a583f48c2d2a7365424c4e77ad4999163905a029b4ae74f9a8720f310a7d4012a44aec6af7f92c71f53f5e9a9d92bb8329157068338468af607b2e87c5e3a455459dc62ecd7a00fc3a18cfc04b5e46c352bd863720b26a9369ca080274574e2766041555b8cc21515907e700c78a89e0f619a757e999b034773ba04951e3f7b70ddb668d91c8c0698815e16abb03d03ca9813aabf069f6ea2a1583eb4ef5288d43257e704ae86f80404db7822f605e894c5997382d6adf78ad1d86fec29589e76e887142ca7caf53df09fd1390b84365b0ba89bebaa1aca0fc5510538954961b137296bcfa152db73535223a74a4ebbf9d25eb30c726e450229ec2bf5a7d06026856c6281c0a62e534a486ea8f80fd2ccf5356a8e50f54fd2677db304d5220fbfcd29548d41b91a9971e84594ee5bef6577bec7127915eb0d24ac0c82b0d207e565d5b130d4bf2f1b50230b381934c79ef5cea9f8ec62c7344b17c91b3fbbf0f85753f70ebdd44d7629623304549ba870cb87bac1b9343d114855e38c4d9ada3d145541990aeb857eab77e2f70e400ff1a8bb12a429b3647749339e20a044d26bd685974d10be43e38266dc96e9c543670040e9443eda9b180d4a8a7d95f7d05ead92a4ac3d23723de7658e57e3d5693a945dac2d5962852c65fe9eb597ea9b06b3395f5d1132bc756c03a1b5da16d1e87705053bd9ce85a9d73412ee9aab365298c5cc7b0dc456282424934ed9746e084c088c62ce9467c5b0b06338b6dd9215b763372b481fafbabba955234d57fb24d9e93bd9e06afca8855a6b057f998b3e58f3d5902dd95cca4b81591a7bd3c8ce56b2915d27dcd51679cf75d43925efb841a040bf357f0d0cc86abcafe2456937483f7d5b58ddd0dac538fa3fe2342ae65669f760a288f9f523bbfd1e24dbc76b196aa82164a287a63a2970b881454a346aaa0dec14f963cc01bf266e801828d44584e73d3b94320fcaa79691c947539aca8a24bf6d9c9c693876e5f9cf7cc807051bb4d4c21b53bd5da722bf7f58a36b964d03786e4f165e04faf96b68a74e0f09a628f297cd9c348275c32d1dfe014aedbd76714faef4d670835d13d71bc14a868a5249d5c94c8f9a698afdca73b3a0b8808c4ed165f9a5552a9774963112457136bc5be16f2c70510dacccbe8a8dae3b917518f6af4a772d573e18b947a8af60a601823eb85ca0d83d429d7ef7cd186b6f555203a9729c067e422178ac293c12158962c6c03842f021ac12960562090d1930e50943f6b202ede345de177ed4ed3b36f485cc931ca5eb7bb0efe1be5bfa857a41381c089f7c31ab085328e55aaff6455cd76bdf74cec0ad2a706c47222ff2aaa7de08e034f88fdb6c9265b4a29a59452060f064f05e8056fe9929f4ff23cb951a8526506cdb77ea32d50a8e2350d30dfd61da62ebc4e6eb2a432f6d8715dc1376b49e5eba796c7d66bcfadaed88e55d08d22ac42d349a0c736271980c342bbea6cad5334dfac3fef37eb37fdeb60db21ea53fca9befb767e4c807dfa1011ccc62113037aede8fa0875db05e091c8f49f3a6680e9c8fa10127c18e2c310128c48301f307d82286c1c8eeed8b4b3761405c2911d7958a2322a53b59487274e4960c4a06f735d8ad7a4d2086b243e3b0ce86bff94e8db98f08baaa331e85f578200d37ba309f37712d276eb49d5f1f873c276eb2e36055d40a03abee3766fbe0c76bbddf62bc6a027d0d7fee3f9f5f99e6f9f3fde68c2f6ebb5ea288c18291ee79194c18cbf30e6d66ef7495777dd5eaf1e23e98e3f4a736b0783578192086b6b558cf17d0d773a9fafa3752c924915063d12104186e973249201a62318d62740ffdb19323d86b5adb5adddee2b1d79b0c9a0153fcd39270913ac3e4511767392f0ed38518281528abf5efdc784f9b583bd734ad5ed18e38e247debdfce6ece4942f50e6e9500d46f55013c6ab09b9384e954ed2f65e1ef18c3c4d7516b521b7c2c4c9f63d57427a4d2d26eb77bd2a25d8f419fc4fea3a4a9ff589faf02d3579faf441f8fa41d2140abbd38574defaedbbba1edbb51706e551d7a77ea2675e10d476ce709c9b945e2276047d269cfdcc20ea356af7834c13a75183a9f9f801d61d09fec30ee6e97f4934713b05787f143fdb6dbed7e97f809e01146dded766fc71feab8dd6ef7e16eb7fb3a9223d8ed76afa34ffed011c9d365afab4f479d12fd3b924c33fec77a0c134f3da9baf730ee6eb75b7bdd8f1d91ee6e8e2aa04e794cb79a3e7d822e9474da6eb77b3a6a65ea79a14a7053880b7bc2f0525532bc33be513c69664aa03ca7f9d9c0565a6b6dc38dbe23377e7829a648c1a1e6879427301a3b8ae8e0338315192bb12d3562778ee7799e1785a40a4d1db4a2744520ea4bc8961874e4889385871a58a21c3132b342738351394dd92f1b5821f6c2b2318354a13903121c7632c49adb9c1ee004e3032d8d0b61d6c4a0e5c0522bd346cc6c5d34ba72be72846c25192a6709c207f69ef09495f6d219e79c73c6b203c9e76c85735416d09c78a05f727659da861cb6160491fa9a210c980db46e121b1ee440eed54a6b1cd3ca87d5102bac2dc46bba57ceb060396d3569af1abb26298a95f31496016d870796730e2ffbb53515f62009db4c59e51ea2c072ce5987a5b185c5c985fc14e2c29e708642e4d01e58df7703dfd05c36ec9448648e95225934cc98c1e2a4c79490106c8cf1d8820108a719dcbc91e2c3cd072288e3a508950f1fd28cdca0851b865c2a62419a3cc881dca93cc881bccae9172cb2b04748539c1c3abc6e13d61286858700a283e389d5cd063872ce19890ecfcb996a4e7d4d894d8d4d954d9d4da5e170ca0ab03a6269c8c25b6bad776455a1b9c585e5c50eb01c84f7de7bef1d984ae692cab173e50712ec39799003b9df9cd6749855c656396e6c9db5d65aeb2f3055689299e10c7ca179d72d87f94e799ee7a1d1aa42334ad797d818129ab29c6f50ac0de5fb0a2cecd13da692d868c0f2c2ce9a929c73b6a17b6435e51db308980f6b15e2c29e30d4509e3170669f51f3a4425cd813864fb58a191f39e79c438be79c330e1daad0d48ae2bdc0d1e520543583f2eaaaf185c52c3b612a32990a4f210085302d64de10b1b1a6254d142968b059ce535e235a588295c52a889919179048299b52662fa4d0bc6c28d953daa3d20526c4ca856bb5ad9688588098f51045446dcdeac992303435ed2b2aecb1c156b69293af88e11757c6c23651c07ec0e94aeb41447b29e1f182f274b5d65aefc0aad004436676811d5a0ec218638cb1a8d010c5a13144091324374c512f4faed8b8e0799e6725aa0a4d1d3e866029c9ca19b0b2b51583b132ca0e0d8d0894a3acaf7cc656b87a54b3a979430e0f7220c7e15b67adb5d63e7455a1f9855ff820860b71614f185a5d1e39e73cc40acd9d33946faf365f61cf5c43c32c076160a69cb9b141a8a992b3508554716ab86b1ae7d9b5eb8aead2f1f365ea862e555e806839d124376429bb6d74641bb6daf03ccff3920ca942134b49d6169705926091e2f9408b0c8e140e4da684d1209f3d0ce41d75f5ef08f28497f0eff2b8bf8bb3847ff4e6e23cba5f0924eb493dbe9d82483dbe470bbe5081e98d88befd13fd8ea4ad033109e7b89194f1382fe15714a3fc48bc263cca8f4437218e4b23584186fbac215c17dde623d82b562775fc7a093149c9fe2091257cc745d1667331898fff884a1d8ce4895157bfc7af9b709b97487ee867a965f7624fdfc7c7250fdcdd472499dec74571e90317dd821d9081c293f8b8530a177d042b8a4f7ee45e41f71e9164fa1eff7c4423a2bbb8820c0f5c1c771eb8e8e2e89404b799dec5a524db93e0760a1fbf8e134d8ce4f5126f93d1236adf587cf2230fc62437e711939464bc55a2494936075d474c02475dd55510c484369f7f9de66c5e08a4aede4692c9366d22dee24cb28ee9cbc84cb8aad3e6b3bba7064d1ffa219c4fde7e7efed56fd4d5cf9f4f1029467decd99132fe3ce72ae2cff3a8ab3bfee9781ec9251df1c98f76becc32bd9e5d0b923ff1b3fcd2f2dffc6c37193b62f6273f5a41860374c61de83ba3d3ac21507ff2a31d9f479febaaf6efbbe988f3288b641593643d2e25a5907dfb1e5d909d8e3094ac2efca414b26bd7a30bb2ef11468cf0a92e7c3a82a54bffadade9eacf1a34f7d6596bd1a2e0a6aec1f036ab8a15412b705668c807ea4655450e22fa6e5a67d7d1c93fd6ab1d9a12e2b04854837c070d4109f5a894e2b5ef3197dd8eb80d4d09adcd37ef8f7e2ac8a3cd75f5ef6d86b7f91fcfed5655648cb348a9125dfbc93e9f29b7b5bbd8a31e993e8be4d267d72299fdf6e59b8bebd86d48b7ce4db36f6dc2fc3cdee8cf1984abcfb086b5d65a6b69a5420ce5a0eabed65df53beae8db71522f59ca1e849f6596acf7448d5d5749ecd5f55d7a6facd61393741583fe2dd9e6f644281156f0a044b0ad306b089e7b62f5db6f9deff883649dcaa84cbbd6b16fd4d5ab49fa4e3576edd397e8d2d31208aea75e7dfbd6d37c5bd259cf2fd0e9acdb3c46f53ccae0698ceab6915cca696f73bc455db535ebea6b9cd3da27282655a78e41a48ce9d674c4baaac017d709d66cc23c81aedda7a01e93aae7d18278d7a01f3cce5183f926d0f4eb79c612b02f62d4c7a3b52246ca4bd8b5679164fa3c7f89f41c8fba6ab361512242e8ddee0f21f6bb2f98cb9ec5189e5f18d975da2df644a5f95a544af176d4d5af172ca12255c7e30573d9b32761d7d5cfe3985d571ffb1ec9ea7be9eb579c382425ac0ebea83d385bebf883547dfcc17e6fd97707209ce59b45cf27b8f1c6f72798a95ff10af200f8595ea97aadb7f92dbd90bcf5ebdfce0ffd10da2add493afbd775f5c9eda0ef7182255ca4ebb691b479f5adab6ff36f484a9874c78b048a4950d8595b5b5bc339bb4dc4f7e623ec55242fb9f4365b92aeeaea83180841ffaa67723bde23597fbb57a3fc0824ef7f1ee547d701e0b8346b08365f9a3584ea37af3e82ad22769b98dd139564bc9d3f95c4a9777cd30066429bd5818b5e502e2d67470146418e0b6fd43eb2d38d58bfe3dd7fefbd3731d6628c2fa698e28bf1a423a65c18638c31c634bfd9b1d65a6b6dc5855f3dc6feea2754b7e35093903ecf4f33326d8ad0a8b1153c61da396647d2da91720de120fc7e9657a27e3a53a5b71cbe09e4d488d953aeb20a98a75c4fd1beb4a2e4c96dc5aca472f6d689e8eeff05e5fae9942ad13525a0a74e9d9e5ed15987b2c2595ad1a4a6547ebaf59b751c96b78ec2ab8a59768179eb406fb73c9559a4442d28012ae5afd73bd67a6bf5112a9d32595c914e9945601d95f653b7930575ccc23781b8688b4a43389d1a992c54a04e4f8dcca2e92c54a05366d1747a5576ed9e725d3de59a2c5498b3684af93b2a5d9172cda239d4249ccfc34565b2983f47af348474050a55b24c21aa02852a5c66d07cb2443f4b32459e0ca7e0286e4d787f966488fc0b7808cdfd2213e47159645ad0f2659f40b4524b2bad14db4aebc5bbde6a2badd4d24a2bfd284833ddd4a3975e5ae9a596567aa9a5955a5a69a5d8565a2fdef5aee096c5695500e66c0ac0dc5cc19caf259c787bcbb9bd53800230972911270073db04604e8f71a19edb24a802fded2498b3360198f35a94a08e718d4004604ed7b1253c2200735e084ebc70020463521f70d3e38131617a3ae0c5c381314e466c80c4cf72cc11129ea701132898f8598eb132918131347830b07381bdd366a72ab7b0402de1a54405c05c1633a5870245ec1056e5cd981a54da1ccd29b4ab5e7c5759c504ae18279f04c05cae62b04a44404c90db096272801e04c09cb63c7378906e6b6e1e3601cc691f311f17602ed7305478aa4ac881396db5741e400298cb340c92f0280c91efc3f4b079de083a57228491d2a9724003be2b068039af0518c209ab588039afc502324f199e2a05b0b02bb6f7c5236d2ac09ca76d08604e7bde170f84045c30595870002330a72f98ad112c30402d401198cb3e477c88866e7845000d064810cf95e709008c140fa90390d33784131e01c008e6740827bc126d0827243da7c9f4785ed61f8039ed0198cb148c44f103e6b415a2cab6b967f34e8039af0af1e46301e8f916e96b1325c09cae42e0f020096a16b807869e9e1c2484d8f1d8353b79841d03c32f60b71d9d9fe5172a3a399d45ca93c57305f2fc2cbf64f1dc2e7804ac9a5305b6d9b6ed67f98588cdfba263c4fe3263a785ae56cd56a9c837a3e52b15f866b47c47941961c190a0ae6739fc4892033956a094399a5368d35ba5955a5a6da5957e14a4996eead14b2fadf4524b2bbdb4e8467b80436442ec57af303ac28e9b2cf06ba2a220be7a5151d50f2222fdb3f4d2f57a0f81391d6a855a679de990171bb6b641606e5b2f572ee8bda900c0dca640800ca06616f20bdad620fbd9f8de3aad12a2ebd7165e6ab8c06f9de2aa21604ed32d04e6b4cf522c2dbff53a03055dd41643d54bf3be14b616f583efbbddbecf368bf22cca0e7af0ad9847da5180df9a2fff5c151de4b107abe63ec102b7efd58fbdb5ceb3487b9e45791669c7b328cfa2ec9e0952bf76b7534509d0451e730394313f67d0fde1d303e6b405261b1cb85c59d2a6c6d8d9d19c42db00604eff6774805b058180b9ed731655d0057d17d6d6eab9972fb5950073b69c776f60b75b09f8a9d7122d7c6ac8155ef580b94d02cce9902be41971afc29cb61f0f5fd501c19caea012f08ade28a8048401cccda2ecf7bb4734053df75e679db5cf599447bbb5beaab3287b9d457a1665a7b328fb9c457ab4d9abb61f90efa330dcc03c6e16dd3cfecf52ccc757c73f4bb12a1a0474819f7a16e70b600e8435e1ed672906f533df9eba531f6bbe17d605eda12092756c2faeb859441d378ba6634ad388cd781223e769ff2cc3da8461664d62c29cc48499691213d6252c882c61c2a4a6be84b130f5258c888d2f6147a4bedc301e5e07a91b0bb69f651891c79561476a7801ea92c5a52bec8bd70416c407e6a50bd7ee82a509acece2e6757e965dca3ce946f889cb962d624358b0167bbc25eda98aa5a23df8597249c24506babf608489ddb834e9b02a3a5c747e965c5830c285446e7b5c452969e28252a48b930b45ea7a9003b933c1ee41976aa77af47ba9950b632ebca1f1264d7339a27180727707b23f4b2e3c9e74231c85b9e8a0c1858a06d63f4b2e505a3603669415fba8dc5256966a4358f0254be811e40895314ca444d16052394790148c703831c61ed2788c4bb0a7c74d47f88e55762ec1d6bcf7b30423b36686accc6d8354e0b2f9da7bed9b28cbc6a986383acb9e565c7aefed962599bf77a82b9ca11df3cecfb22cdff6b32cbb7096212a5f52004291b5660c884a0a463e346839928291d84d6bbf9e97b35d6d133ded83745d7b76d6a09bf6fc529c8fe3dcc7e636dbbdf4ba09b789267c489be3fc2ee96a7d1f138e73138e53e1a3a5ebe95f2d5baec7b7b82392f7775c4724975ec74391a42a489453412848823ce15e0e020c10609ff6db7bb494bdcd7b2ee882e9716e13afcf6bc9d0b7dbdc8adfc5b93b6e0cd96755412fd5d9b75e7dee7105ed19037a9c56c80a51eab75e2919ec2d3390d82d631f080a7806ec50ef06fa8e488fbe0956a082db77443aadd075901e55318b7e459be79b45ed37f18a3de3d4592c5b763e2470bf7c73c6b85c732ac0569a53bbd3715352ae613d39c5f0b55bc7dbbf4058fdbb4048ddfaa66ef6d55c830098945d19fb414a199b1c46787864d4a2e6b8409416465504d60f31305c3655a9e6e3ef258a23809fa5da1335264ee4c08173f3195182e7629c091d520f4ee40e7676b5811fa4f8f974ac93f0504c5b7b6830a76a3787aac6d69c1d95cba91116e1b4d3ce9aae579a9a1a358d0cca2b2dcceb428b2a02088e0808341f3888aecc1e7eccc131258e952c376c1c695d706940e0f8a8d1dc1ac104fc00132210e44035688407a469a5657d0e923c693425f4668892064395b42a1fa8421ca449ed90e694b5c624ce12375c663a1041c31054c2d42096c3161c80e8c1ca13ae1bf8a0c4890d9868e98065c30d34fc10e222368478089220497c34b1dad2c1c3d4912828729ca4c8d975a53d6944e4240edacf6aadb571cede5a3b9f9c5b2b6e1dbd1de28c11051152a15cf587195fa3ccf8ea1fbe5dbf275010c484d6ad6b3047b30e9b3c59648c9da4d41bafabc0f4d7317d4ae10c29e3383db9b3d0b6beda6aadcef4aa6489b2d8fc6d60cedb1ef69c8e6412f6ebf9d314c479dcb388fabcde2c7a018b152b40568cea0aac2535d850264c0d607b6ac43d6dbd600398dd0b6bcedce00104b5e3e7aa488d16d09c9419b3c58685001421bcdcdc20062e3548dd70e81143181c9c68b88216150000881b6ac7d5e981c90e438c64e192b59f7a44e07186eccc17133332ec1aba0612235fa4685185d94e24ce3491e18c5a94263a84d84d3ce8931f3eb2667003856ac8a6915d20a64717acb118ca7cd93376806ca95135264a8d72ef78ec10e04401b91a0325e4c99a138979099b51840d5f566a1e600992034c4790afb1393c3e48116707355b7478128395b41461b45a984104d85a0c7276a000f2c4860f1d48ba1479128707cfd65690355a3b9098ed008747070d086288ac356072680305ad040a2e4dc2d8a80147899c227cde802468c264cc4a0e6590b81971f6a19064ca922142e03809d2c684561a1498304b98e4c06687b766876d6681c34406316084f8f2658699587821082a24438ad090a5e644106b80f08222c30d333748c3234cd3c30b674d5ac072068d0e9117998eb4af1b67dea8e932a22b4195cbd75a271065b26d88737c31c645583dbe3d38b28a7111548f2fc618bbc9222a52c4eebe41b3d68d9bc73f4b37664f863e2767a218c29c513833f33c22ced0c0d24d0d1c4432e833448c8800c10043d566ce72d04424c428c4b90715a0c9bd2900110539d33ad3218a5e7b56c313d190eb40672c9cdd78d28d6adc13fe555ab3ac01332b239a5aa39bf4106bc8f29a34529b524aa9d2b54e73e02caa3e8baa4fb1cdee6910ce928dd9d7323f59cc59e267c926cbe38a588326c566061b29363b9ed8f48022b2c126091b18b2d7b7066dc6962ad9ecd03f4b363d2e9ee19b75d61e280be41ac1b71cbe9f659b27f98631c6e2cc5d2bb6016b436593f859b621a36de46c9d1fa4fdd6ebdb919cc1dfa68fa8ca66d1c5b4379e9f659a1920ee6799a64a47fc59a639b293a6eb71651a227c843f4b35509ee7d93e355b267e966ab04010d4d9517306809fa51a2c5fcf8d8afeb334737adc8d8a297e966633f4dc48902041a2c7a73413c34d16277e96663e3cce6ff3fbdebe1d4915be7a6abe59777e6e21b3f138141f02ba6e10451901114519a1f1a25243d3c44a0d8d112b35ff59a2817af0675916a70c08b5322a6a6550d4ca70a05686835a190d6a65576a287e966536ca769ad2595429d2dded763b8cabcd741a00dfb7f43f7cbb31ea67a46b2bb53adaf588ddd65a9f1819ed8c88661035116146040d22a7b5126564b839738ce600cda13866bec8ccc0b9beefbdf7cd073fcb3354fefe2ccffcc0e5242fc1676a88ba6ece5c455937e31918a2dc9c6921cacd191e4e6e7269268d99312b381c1aae88331ceeececccec86eb41650ee4d8882dc847960324ab01e776ef55632b23d3579aeebd60ca64b995f172a30c9781722b73a5ac24f3fafcb3249bf2a41b8140d839555427edb573ce592b8cfabafab5c5bdf5ad935557bf7eb55043656988208208a3216ae08166082238d00c71e3bf9fe5103b3321ca6895917143e68ccc1632568e944132c496d9c5f7de2f7fc9b4fede92cc87bf40d59691d1e17702949ba8c4eb9a2a6a1022c50810000000c3170000200c0608244194244110835cf8011400095a924e543228a10444a130140c8581280a621808821004621004a3108603599e4379006f08f625a52f948835d9a91cf4e87e805b4d6f4df601d52d4ec33bcf3d2d3cb2ef4fa9b91f13e453a7286cfd7e8fdac537da566343a7491b1cc373e4b609d88932d64caf92684f9c1034e1d0a249b244afb01cd0faaf5e890543d89466a24a107bf452882f2f7655c21e63184f5a1211b5b7854fde71975188f7dfe82e7626de93b73ab7205a3e88db850b9ed2700fe052e8227d43892d0f9e0a890df5a8292dfcdd9c319a368becad0b221fe3d33c420a543c767b20ddfe5c764e092255a42feed35312f4bf3144d892cb770951a74d32648585e0da50e8ab43760ca2e7ce409b4da4706f4b8b06731862c939f45b5a5aa71b3e8867c6f5ac641db00cd6ce4e1b222e12dfebf302f45ee3e2d9ac0cc6ad6d7d4ab823b4b06a5fdef9ad22c8adee66d72d36d8ad786c782661414b245898c148db51440d011450f010ee8398131faff942ec5208f7e5ef2d1ccc21a262a20cb37a500841a3031097ad9f31483a2882124a7d18101198160045036a53e505710e7a3168e594c5dd7f64d1398afcdb0fdc23f5ba786357702997c9c5ddcd6d5dcffdded81ddeca7bbaf9bbbd6df7bfdf1bbb83b7724f377f376eeb7ef77b63eef0566e626a3f0e16c337fbaf1ffa39f18cee60f6c5246bbd2b22f01f85bfecebee5079eafebd571fff9aad298321a14848d670ec65890022d8cf7d4f62be8c0b3618661945fbb2a405c71d2c938fe25d95ba286e9d4f2331374906c68f5be2daa789e8528d054e053941107c14d5c678e05c3ead5a18ec07b3ec040230766313faa8069b20c3fa51d5e9eb27931cdba7796860e2f58cbbe8ecf560470f7310e3cdeb508a3d87de9a87aeca0e102834ab3e11b9296e0a3a9b298010e095f65f4ba53c2c2cf8600b69d2458dc159b07a96aba364a935308e1d0268d2e6f9bf189eb43cb4d61926a1c0073c3823cb6b7d376abd199cb3532de9876240c4c7401d9f8193c9b93ddd927f3807637c0cb07eb8e2639ddfd99c5bd22df986b29663626a20a30ec9ce7826e278953010f7f2300f5556f619473fcf97638470f9d64532c1b2e142876991e660667e5105037cfacab5670b835c418e009bd1fea3aadbc60b0118995b0b90fcd06d804e1eaa2005c4baa5e0ec0a7ea697e289f063f44252ae61e92d5069a44c3f3c0f2c192f8fa8edb0c10b20be72a73b5ef8c765af2c9941fc0a8db7d2d321d8214fe2c548ba653ec3cf7c25dba3ce1155eb54748f790bec9e87d2d11f41e83414c1a35d1a17c99e47ac3bac0a1b3757a0258a3aad9b1f0551b16ddf8498b0eb2715daee53d45e4772fb3dd9fee4368de2ea00fd45bf955bd2b4dca24bbd71975b113df686187fad43635358bf0fe976cb36f3cf86a3de28fc03cc35f141da38c9e6450a1f4081578f3f04301d68b7d5a2800960bb15471668714417bdb2039d7b2d2789f11ef588a2381ec7f122d7eebb1c3157087cf1e884ef48f14b7a032a4e607fb04706330273e0dabb033e68fa6725ebf0962426a4d04df6f55eab0db04f1c406dfefe849aba0c61ea22ffb307c79d75940ece2f8cea004b9826b80a72533d1a795a3244c3fcfe326120233d650a87a3b4900d8ee18e7b59a8f7ad35e513acafcdf96cc1a5283cea440c46a326f85bc4d489b05d0de1db35b54b76e4b31bc76b159c3f7ff51e1660e9e326cfea4e88e5e376b2152df47b7386967e694e57f1775a680f416f8bb63f83ae6219b423a1f5739e91e0f645fb4b84a2fba1039459fea0e70a618044bd52f66be2a7c6b2e2f8b9adf6b2a3fe8a3f2f3a7ed93d59eb3fa9eb137a246f69f18415f05ff76397fecb955367a248a54519099e6bbd81a0b21fa5270b0b85ff6e7d993e6f75b7f67aabd8f9ed41485f237278ade530d445bff18c75b85ff7fc2f9de27be68f78e665fae71601be0dccdb7ee91117f18fc46ee142690239f18177ad42eb53847210a930bff3a0d56d72547cd9fc03a30dbfb49dabf82fc7bed842ea0f92e9d0f90d41b320c2e329d4690cf682e8ae47866d63c0c00bcb07237ebe1a216ed20cd2e9570d3efa86ff968e2f962fa923e2b15671157ab70c8fdbaf07bb229e33c2d132922d035f529dfe292dfb8956c26c632bbc66fcb21e435e7409d3d27da04ed2aa043ab300a267fedcf7a96ee874bdf6ab1125ef22a33c8a36cdfaee5bc0305c94604e52f2a4da592a6a59c1f4ca2c583f0c87459c07c344b4a48de1dcfd77d0f08c464f42ae4e62002637cf83a0eccf104d644ec545c9582047d19b027738d00f2ed5510b93c27be604146f3d95e207f8dca8eed6cee43786779a57831fd86de207a99c683182ee11bb6e1acff97e521abdf913497f063ca2e616dddb6a2bfac013dc1a982ee576bf4565af01f4cefe7412c19ad9dd912fe737913110040c4de2d85ab80db42ccab34779d582a09e8522a70104c8d88d12751c020224d481dc7651f0bec65e745638835c539c06a90165d6def00526e1a641277fe3d17aad37c3229f345c2deee09107fd449ff066d17201a95e194cfcbed970359ecbd949f8a39a83fcebfc10b75d046603bbf8b83f6dade6e002116f63d82f71f9c3784abc1c3f2a252faeff43631d7818bfc486e057c117587713b4b5b11c6989e10ae4f565520ef49d5811721a5e2dc8033c90f31299b78b83721a3a39dff6dd94a441374635b66b3ca41fa23fc105447415c0e561e45bc2755ea714402b7e2e1bb4dd55a6866781b6dcf21d705221bc764621fdc95844111d660191010ae80eb3170c3a47aefae9de817d421010892f9af0af0086fe30884891fce2f9f14f4f8cea0edc00bc96bf4a3e32704131b6aba03055e1135c25687890a19cca4b8b63f20e7842048daa4534863b80e3d39a73c03d12f49e8f265262a256f36651730e8c4872ff782a1200097d92203e24e1156ff35937922443dfac89d4b6ec80164959c4373830417aaf5db1ad5df4b2561695b89b5dae157857c1f0b69635107800919e869959546152853edc074579282773d03043e8f9ae5d1e5f4163700e5441bb6fe4c9de9a663dd70d03e7b0915db4a6fa5c582c71db6b0a0948c4ab3b4bdf01d249a5cb5b38dec3da6f88c9e2186f95c3ad0425ffece3e04e380fcc166865285e67d20f4c6e4c4addf7c05fc1061f13841a2982ea494a8354d27827790d5589d111516ae393bd6087192577c8d57dc9969cb9825debdfdb12fe70b5134ea01b85b7f14ac0bdacc11adfefd5baa661de989898fc06e6592c00e29700e0b32ed9bde950fc166dda832ad7ba4331239a281e25a61337fd5feb61900e036470920aca9e2d67c2aad8cf4727f4e613dd3f02c7f802c19318df719d543fe6d3517ac181a6a347b4ebb2f9507367149ff3895d96740aedadbdbd2f44066c564a8036f731457f571b4c0fc706b476c29b772ab2aba1e8f62f9d43a716fc497b602f17cb4708555721f80ca5a46a001f17dde0fdb01c7b771e1f02d3cb73b833f601f8d5d108c43fc9479017dcf36f242a7c4ff8639b13585c9cff49e3d24fab2e47253d7f39cc9a57ad2546d5c53fc6f9516a2b14f1c31f832dee4196f1edc98d6402c949e3a1e7cee8bde2880bce3a582f209ff609c7f1e285ba2c60c6886b82d9b8558c6120451aeb7bc254adc7afa8ea87ac48a52f2b949173130f1eb32d208a10671872194d3cfd8d79fec66015f1ac3f384426c6396eb9eef3144e459c539b68e9fe79d8f0295c504e78d58a5e0377d513000b0d28dc92b67c765a906168544ce77bcdc3b5ccf06758c27c1641103c5b86f0f5483424d44cf614894a71e02801eb2fa757bbd5c0a661d40047c8752ad9087c3aa2e42ea5990d41a63efe3f40e15f44b2258e3adca0c7beb74b35873a70395eebb7b138ceef7e8c02f9e26536f1c4ee7234bf51034ce338f65c04fdc1c57f08f0a72a884b225e09833430f5d2565566edbf0f28f8d7a16097e31711f9859e7c9815c63f17e6f5e4c8b3ba1ffa74e64f602ce27fd408967b8d11264c8b0f283fbcaf3a4751981e45d2ede514808974f1599df6516e71ad2c8a0ede32a0350d1abdd6d238d537594124f384f6dc7bad8172ea026a376b5d4ce47b144f6b861249c80af9949c9807850ac769d6c7d57bb00960185c899fb79acd3dcd896756d5842fbd2937c437d3413d517f06d79df13d9d0a82a310577f76115cb7ce8f183a0488c29acfbb2270c5dbb873d63e651fc08a0a2ea50b9300430fa204f4d527c93bc13a78f8b181254304aec9919c15a1b27cf16e80fb954c301857b01e7f438effe7bd7d9f1d9b77dc9d3fe6ff58269d59e5df21f3bcf57f2cdbc4cc43bba61feaec9b6e5e360ecd3baec94f689ca7ff694bae5b1042127e91897e3842438bfb517b16cb48c9194b7d7785cd6354bc336d879323a2355751bf1d66eff21d7393752a040f2103d5635c1a8ae0c790ac8de30878b64ef22a5bbdc5fe652e9668de6c7744b258d21e2e7e9bcd199effd4858c2956fb182175e66c579809dc0b0abeac765d1b637818b6f4f32510c672220788b7a25b4e2bdd2e430f69d893881d4ca51d274e36514a3550436939f2a9c0bd90ec3c53fc63664a4c3038714a5ef0667cbf5b318b15ca28eca3c3c5cf206da3273f211cbf2e9f8dbf5bfc651ef5021145594a72cda05965ba0d5800692a8b220f104db55839af75c0ceaf16f4d499025f029762a8276271c3413a21ced80f784aed850c286ed166c69744c0bec04b0088202dd3f3cbe6a7ddab11bd9e4919eb08510d48d32638a3c97d01eccf7aff0d902d7935616a35392fd9ff1ff6c3d0b05bc362c63d466f0f087015abe01b838d07bb5ccda1a6c653a6d3d912098b8414c63a9bc263260a889259724a895f4623008181bee3bb060e97fb40e9a1c45f92876d28281e855352949800f2f41410638338aed668bff597401d05a4b7132d88b4494adea600b8e511fa8103bc62143fffc39ba50b69a32f1811fd4f05c3fb3f45e312e8aa374494acbdd5ebed202d3e5ad841e35568e081091c1ecca26a4fe73c74c644301117a3faf662b3dd8dd49055d05b1691958eef1a7cb3e95455d8712745743d274070b67654a0f242ba1e3c5b7d94333aeb1886256290e8b0383326fac8cf4d4f6855316046979c9c705c4f6d8f85dcae983952f8a5a37466220985a8db6c9c79c81308fb1603f8afa5f631d01bb6b1ed0910498fe369f44cfad48fa7338dbecfff4aacf5b4af05bb3ab2bd779c46c139175c39b00d03844580f37bbd0c3974170a42ff3a77781003b754ffcd2c21e82f7461f0522396e0d3592ed83ab75a7ddabd88ed66f08e5b48c6124963897a829c8792771e13b8ae9eb53f7d2d3b05188705678a5f4a432cb55a7674f5cf23d34994b377aea71cb9c5b570cdb2c60fd22103c79908875410eda70aa732f0b9f997feb18761c70c9362f0d8ba5294b580f534d3925f35b0e7d3d9a1250d7f05830894ef2e45d06db64355b1fe17b0a388429ad61e864c93b72a1ee94bb5c48c02941a578ef17a81c0c965375f333dce1d7af1b58a1899265dfd8d866268ed80ddb500f320475d38a06459d4879be976e8fda7f657846a8e822293dedb4e89a93c7a965e48e21b58df6d4f019480120112204db01082eadea8d3587279845f21e9fca1ff6ce0425adda94afe106f2b3089ef95e088eff329b3d69b1e68ae5c78836af78e2af38f7bf3cebbffc7ec138bb4cba69fb5fc3354438a394d721b5b2bb9218d98409ca79adeb7a8ad271abdc95e036a34de06410d5187e480ef7719a17902fdcc970e27903b58d10171efdb31067d98f72605021ca9ba6fe8316d59588e410edc4e21a5fd58687113823b94f49b6f8e67d06391640dde45ece52890794aeef96927d9c6f826c584b880d8b25c0702b888558a8896dbad6135035c70c2826bdce0f8aaee34beba7df23a229628c9487c9b814fbb34384bc14e0f9d1a8b25519c376017ea0522201a9002ec2f0ba8b1d98903c7ce8387106e0485fc0bf9a25dc0c3028ee35e65d53e7a0348892393e599761292b3b4589d231998ce01d7d70813711dd4e8543bdd9c631aa84d51462dd4c85dece81a6baf4791c0f0c74fd7673827b6e8068f4313b96f4006b7061fbd7e7bba679b3c6cf1a3984d9d318b2faeadc4db92dbda621a0f8fec3b8887fb4332ab5dc64aac7d0e9521cd3a3370c6867b3cc5846a21a1649a76734af2ba22a2852ce15b0ab53b6022d3f6f5c2c5d52f6d20299302e737ab6aa4f788b785c19fdf6284ab9bdec3d55ca22c9039e83a809b2cae9ca098013dbf489fc3b7e8a3fd68ad92a2a47ba26e478d49f9c55c0427a9e2bc970e8c80465b30ae794be41c338289ab6102a4d108059e03500fc88a65b5307f4efff528134fc3bf3ed0b3f6dda14faa9a5218e194d6d2beeef229795c8534313b9be8a29e56f3d0363cef8814a31a13b873615f56cc4c4ca0cca8013ea56a1632e52de396aa9dab565b15538221aeabdd3094e22f9554fb6d84e3e2d39fbefd30adc835b8d0b9b7b96ac0ae194b4e2612a466f1078bcc59e50bf17330882382284735daf404e55a5e710cb2f92e8e21269efacbfc9171798ed1a39ad5bc23a59613ede5be283750d64b3eb62cc2b49e8201a62a2a3f255668d4f75585913144c832becdccf64a1dba7494d94716e6f695e73185f0529457e7c967493cfa6fb365c50df115c33aef0eee52c07ffe50384a208a9662347cce083e28c48bd4ba36a9f185f4ef91a3bd85fbf97b6e1c96b10f9f59ce03468035899bd61f9753503a4d74105935ea8c2cbd206ddb97d5a1fc1f4d4558041f427a0c8219aef47a1e05109dceb79e3eccf4090d4520f599ed31346247c5aee8e09fcfdf8b4d84cbce98bf32def5a5c2c455c672ce30c1f31f2d3fdc21e5be3bd85555052d991f125e4509826ab9ff190ed51c7b959d636456f20111a569fa29075d44c58df552227a5bc2815abbca36f535b5ef380d14ac95826688542774e5b7bdd7f8675e6a0e4e9ba85368164a4f508023811c835df08c85fdf908c4f5f5c099ea6225c7a1380914a33c65c5287e392993afc3eab4a91baf82c4947ce631d09648998f534f2d2780d4f4e8b2464cdabdc7a5ad5995735a44b080ab6b82ddab0f4f36466665929a9ff34565ff06159becd0f696d7ac246c750e36d7a6f7854b9df58ca295dad97a2066af1ca4c706b341b8cd5d90c5c5dd3f85042707b66e47405c19ec9a37a7e9fce015207a761c932f11cc6aad441341f29dd6b6833d490d4c6437cd36947fabf40cf55ca5888498d774033adab5d92e766807896948cb1dd4029d3278370a24e8e28c8884117195254238d531f6ddf04d634f8239745707938c581eb95658582266563928be82482a1f22c86c4994a14c3c12a01d70d827703e090b0caabe13f34cee6e1bf6ce3747ed3835589e7b1a0e4d0207e3bf03baee1a4f88b1cd9b9f229ba0f47be70e85258a6759d36da31e27c1f017480295217f2a5f6af7b026246696c99a7f8bf49122ceaed3c258514ee00fba085f6a2bee10d69f2574c27be352b5389b1f7e1232c055d8fc5ecba40e36785dba784f59696f39dfaeb18fe6e738f2896b3849a3122cf36292fb9ffa108ee0a140b0a5ed177c06939de4ef1db3b6708707d16b094ef7ec3059a454d8d443da37d1ab0fee2bf4c0cd2c31cc6a667840df26d690dc65c78e14d956605ba29beef803b87e2bd550e101b0706cacf77832b56674d5bc429d5b9fea85a919e12f74d64ab2851f54821b9f84789b187dafcd813a4d73f9bb7a869ae048d031eacb48bee13485b910d88268bf068d753ed9b9bf62d2d2bbe9229186e82b3a24a3aa10cdf4045484ba4fd0b0c96119535c5835fbe17d821fa3e76e016d5a67755f9cf9d98010b50c95ebda505f2754c3ee2d7b38bc398dfa81e9d4b0dbb3a38c0cf2659db4ac786a216fabb604639ca7833e7d39011c742a12c7dee8cc14a3faf8b43d2a29a69c6bc3e1eeba9ac3469e4dc672b360dab155c84db6df08ef16b263f2ef264bc56092583431252e1bcd0c7e4b8b689535d6cfebadd0eb04998ab505d93e3c2713d4f74ba7fa12f429b674c3f3fd2b11369df79667840c09d0c53259edb1b9e99ed7c9da418b9ce3346b03b80d8d5ed68d36745c12339eb03bfa0f9f47581dcc67393091525429b08842a16d53c57211e606cfc9d2c64923932bb2560885f8ed8149b09ffc2837ac7f654ea49ea2a03fc457fa3c98e78cb4113763aa6cf85a6559f4842269fa96b19026a33e0a93f7fc4f42405eaae74f2f9b3de7582af42db3ad747c5ee6a72b28e36ad50bdb5ce98d2f9043b6e42de9954e15c8f4f1686ee2652273b9ec7527b800e4b2279dc242d4c653b7b8934d6bad3cb56fedfe5ff560f2328160d4ea4f30704026f3974125939392d595cc7624476ae9f66ee1997cf0d3e395e67d5baa43af7dbf596bb3380341314081a3d82a0726006ccc1f4c5ab85f70585d7eb402f2a13535776807fde8cec59141882cb347633c198cd31e6a60664c4e749f18443fcfcdbedd0e52c4d1276440c47d8ab9dfba245bce3681f83f552db95d4e9e95883d007032b2638ac1cc972e6a796f4852c5f3b69b7eaa6ebb26ca62b54bb181533fd6ee5ad331cdb711227589ad63b43254284f79fe478acdef813cd26b0f86b3b093325f2412e1bf68589c401080d833fb97113e741d0e427dda0af9721742e2ee89badd512d9effdb9cf8bbccc1db77103974f07ac4512ff07e39473de93d8593be55cdf78c88fc91575aca8e387dd5c46f152ea3fd14ca040e65e1d7e48e74716ec3a4df6ea7604b5dba0eabf15017cf221eb846a7e9545953906e3d868f366017f08f76d53dbdc550363c6ac6f57e19cb34d19acaa6e8adf510967a1ecfcfc00bfa2667a78103d3be1fccef7d0a61a66ebe4294c7563633f99eb50c38c4dee1f1fb9558e67478e072efbc257a454a716cb1fb7bb1b9905c2c55a9ce7e0f0110fd853793a1c8082feed4e65462e3b9e49eec511e0da82171b0baec5ec8073600c5abec0d3e1d482a71f73c42cfafa8f1dd0d63fa3ed483dc1b8a87698eee95e6b9323dbdb1f2bbde05f48d0d9c7e4e596e30da07422f458b3cdb8827b41d9c9d3089bd1cf1e9dcfa429c6dd5c2f8fe5f20d151761a73267e07ae3df15aa6ec951b0f65d69db94139fb9c76ac6ca00db0893dc880b8fe81e8e1f900787f90596aa97dd72acdcb00ef67438046e38096398c53349fb95a6919efac8d03d14c41b183205d5568cf86f7e36ad2ae17ebdd3abe6ddb00ab775047d3cc8807c21cff016025ff9f145ea3b2352e975cddd8bae00f08a0c123ec9cf2f31ac75f45d30ffcf9b5d65d7e7e338ff5f400e80b71ba45eda3f60be08d71c484c8268b26ebeef92ffb3baeccbbdbe0355bd5fab1220f29c08eaa40c96a8aeb53fcdf4ac84585dc372e95eb1e6060ab8c6730b4ec04d05690966679167e79862304a8fb717f4d05432a9ab6082f7d35e8646cdb3eb69a31bba7868870b7871ed44826d4fe400f1c5c43537f80173a49a1088f8abdbf171f16e41368d3dfbb8c7b1cce0a85232440e33dbae5f61fd7ddd17ebaafef2e5e06617880c0054e000b2030fbb5ba4a02073aca13eab276c1e874c376e2a2b76dc7d4923d6905b65245297165d41a55e95c30e623c0b2d8815b5c9986bcd801706f6b9261fa9b0d26c1ccdb8e283639600a9d283cc8e4bbc4b9564ef7df332bc4f9905797a26e05e5cd7af38fd655260c32ff83a26ef1746433d23dc61259ec835af1322767f06703f2e6548d858321e4ac4939f8c2c77bba97c91677b3607b231d0c774fcaeb9394dfdf96c9a899341421c90f4e14758c8a9a048d125aff20669fed7b0d474bd44caf74b52a336a671c493db06c7c92a8c1f379fbe2a8382bfac44d244fec0e84cc0d61a7c30798093b78c538158017f884aa3347092aa17ea04a0e3151fc40fa48543b01e00b85d8a71f6aefba7a299a49827fbe147f9ade3a0f052cec21a0b5de196599f4fda1f050e6633fbf267be3c63d997e12c00f9c84e322d22c6b94a226a31dff4823267a748cc81eb9ed25589685e524f629c5c69ea8a3fde99e60f68bc92739b5c6e76c6dc1adb3bbd7ecab4897e753241a8098f1c2b97dba8bdb0adca96f9ea5e608509c4d44dfcb60eb73f40254aa577c1bcec7eb270f9d07b4e5dde04b9cfb41df49120dac2efeddf431725c44bcabc887a98bc5d5bfb7e873e442bb1dee089a00b955970bcec608d2851637fa5d0c11c88b5727c11fd2becd04cbd493c666b77eef24949390b5df72ce0fadc30eccd3027f67a2363fecbd4285becabbba57688e361fc1822ab6d1046d67ec5c44ee785a1eeac309296fcfe39b33c275e7e502372bea67d7e4b8899a573198e0194ff835b19bdfc91ed42687dff87fcce6997338d735b1c019194e72f9efc8aa4a2141f45371790d2a6a4c9b5b9dfddd693f556cf28ebf758ea235268d712fd9a9f1ee0e7efbc51f7ea49e15ff3cc3a138c00ddd0559e6c9d93f649937516b4d630667a2fdc345c1bb1c1d218e5bb96f924271bfc2c359e6089f136c68330eec2d46c3afdea2ef18aaf9c35f5b12281635f88c8a6ba24b62dba60682027f826b3117365b3ac7b37da680a707a9f955f98fa417fdb1589e36a471c4b7c7f66f9cf73a619885618466a4db06782bacf095a564ee030959ea4a0c4e18f861e0a61c657c2afa8ee3a97b98e67bcca8bff16d76769cfddc16d37d163f74691e65e79b790ba4d3624cd1f3afa601b50cd72a52067077d31a24145638b9269ffae4ff9564d2388d3f63f917a95d3407850b3cc464737060a4bc6bd79937ce2498fc21a0f56963bcc95b34e578621b9246604a6eab683367bde78ecb4edb56aff1e3f11b71cc3d5bc75279babf9bf726c96ee469eb290793d075066e2142fe4d03c09f9e4da606077404f91b0382baebe1513a7c9e78fbdc9fe4d53bdd50ba2e3d8e2ad7039e61d23928247b29ed788c7fbbbf2748197c4dd173c5576c6443d630ba44f702429924ff2751666fe2d34e266eb3234fe3e9714c66aa2bfc16cd54bf02b827a6f16e41a67bb87c8a87ffe9233faaf8c79274eb1ba74fe85fbeb8c2619975e415e60df508bfe7e8c8f4cc26e34f0367aa1070505f414fd9897f828378f7993f380e0f7b2d672dd2fc5df4cf200607f63d5a4b0caf05a001a9932a53b00a8370802fa03830a95e4ce2578f304746103c5d9b605f0d6bc60793165b214dc65e507c31dee160af1f207ca541d98cc67776368152f50ca6fb84ab326283d00f220a93e7c931e615feff41bdc56f73a73be4ee12531407f25887fbe693b0a4b6aab279ee25858e139838c1ab0404cd9407597d45c833aefaa2771760946c16f1e3879a9b4f29dd8c95d8e713f11a3a49406bbd7d6d828e0bfc98bd62cf1d1bf8e36c4725fe19941dc9937e89e32f0cdba3b8946c7da54063260ed9df879c827c92a529796c412ab0c889999c50729d28f042e0112978e7811e2a5c42fffec9c68668d577d89fb78229fdd5d97238cb33259b33c700f8ca52a25209ec3e10c742618e219105eb9bb6735cf6f1fddbab1bfd0c8b05c6e9484ce5599a819779a6b81c386730a87e39ff12023df3427bb02522f80456bb8e2c7bb6d948b8810d8a80acba3a34ccfeff4e31bd1c2671b0e555abbe6b498deb0a0d7d07ea096fef8ce84e4986eb8b7004141642c85faae28193616c2fe7b76b9de48db86600b8981c5f6ef747df083382c2f47aef577cb4346547b7f43ac0f41a7372332f2f3234289daea64c95c769769895c7340c38596cc9f5e31bdb5526d9bb24917b5ce6d354c4186632a9d6299e0c8618b5a2fe36eec5e37f2801fd6d84e7ca462385a1ac58f486fc1c9d1832ebbbadc41a3fd0f82503eccf798388548c348210cf69f4dabcb6f3e70c332acdf7a5b54a022e98a81fadca535bc7440f4a6e2aa361d68e3cfc733f679cfb2120f07f63cdadf67f5bf748a71d19d664e555f76a3c7e4614c97555f232439625ab73c0d8feab4f534fa91354acc90dccfa886b3e71e3454a0ad183c0a486c219122dad0c7488d17c88f88f53d65ceab9834eaf8166a982539b69b8bb82bf0c3b30e9a2e61ca91202752277e207319a35691a4f347bf1d6fc56190a3e43cb59e447c41e2aaa2054d3fffcff323a42789e3f6218a4c4162bd1e574121b69294acb375c5da3b70b8b010bd8a629ae64054ed83d63802813bc8af9782146efca9565d7d32ef466cce972964afc1b6e1190708292ed48ba12085844f6b3a9d5a31b0b2641271378b5e5d216568db0e19c735932d15ddf7ec63e91a59de4e3797dcc628ddbbffa20af29563e64e78313e4f2656c6f57ac414730df464ff451e603e5bd2d2b8bc6ba62eb3b2e1e710f20faf2a0c232f4f4c2053dafdb14bd6e4fac6b212e81d23f510a4755e8dab7e8f543303a1494be1ed505b366f28eb0a93c476f02605e0ca082c928a91057112c11d02a602c7a37623cbd4d599da03434f1884fba8701b9323c642f0dcf983e39b5f682e014eca3ab06d1734aeb415a714dca15188dd88b473b5b06c985cc481f4e96ffc4d54f1774d75ffa9a7d58fa7bc53d5bc7fc4e465a9d8e105900ad074a46ad711521a3d4d5bf278acea9a887ef789d962b17d91dc082783d0314f67e4952dc5e0cd507af0d98cc92ad91f6e2d1b14b395c70f22494713ae3cb38ed9e6028e859bb379fddde512295d8220cd7d16968dc3d7db1e81f6575a7a63988839cca6ad3857f1198b2054c4a775f756d2c3fd60b922ab2b34fd3065cb487ca5b0f19a0ec198a45fb2b4b9efaf8dc82a260a741c148f22acb2aa7b6ef0909eed5f7292bdba20195ed81014e2582511b88c7c30b7a0334216555d712149fa73c7cf034a6363c3fe1e18687ccc22fa64160ea2165933a4a7a09033a2a4f71945ac18e70aa68be25493f37e19d9e2adbda64a9b3db6314c47461ef63c69d024d5d1c9bf5ed32a350ef6787b722bd483e131a1eee097f49508e45fc519b2c0780bc95f0caab77379de21097aeab9e2cfc5720f47fca642370e17de94b0830632b1ad3a28c98c76776a019d3708d0a6cf276777330385716cc014e04894fdf4c0b52cee7d30bda21a1dd22d4756847447b57975ad120205f30ccc1900a5a0b9b439e46428b168c2c05350ee1c4061e7c4de9284aaca9b0e2ad5f19fa3314c26ee93a79b560a91645ed7a6774a2af802865dcd6eb6ed4621f96ede841c6434803764c3bcd27cbf92ff7ea5b76d77a40246c274cd83f37d7f3ed70481a387e1fd6deb790004dea14dcb062f3f5975943ea801e12887f364a76a8a0ece689b2c1d589ad60fbf6b1e3105bcf3b111cbfa39f6b01af73e4cc51f2162631e79202452c805423938ff5c1685e26ba5e0882f6d9e1eff0c465a5f571f3a181a20dcaacb49078dfdb9bc9aaf63d25d46c9cc683c352e40d1e19a929bccdc4a6b5125d2a7929477d57756cbdc1e9a3e72655b5029aede61c395a29f566ee33bbe66b0217b04c2597e4cd0218b436abbbe6d024238d08e4cecda778d6e3e50a5754689d3bb4aa8668f1bfa0a101dcec9edbeb730c6dbc1e83264ab96b6ee75f7ca748c876f72e3bb75f053c879497bde09092dd653237a79515b4d856563482a13e969ccc9d37a8627d7227fa78a7f8a17939bf92574aede9e7658a80dae2439228f95b2e3e2d26e29583da6b80d3cdd3d23f025729a2322dcea557d531583ba9112dc0e061bda12a9dc07b420d6f7d9ed44e0f2eb8eef8fe34a96180e4ff7a3d51a365a2cdf8add5a7569f0e01a2398c1413d3bce43134b0a43db1dc09133ca6b7b4813b7bbe553aee80265f375a0e8b0219bc710255e9c52199b9de6547aa4da874aea2d5ed1552e3cd13102ec625861fd9c0d25c9b7908440c582613b4a061d8b19611b0b25eb7f1623a2584ee9f5a64fb9165047756f7edfdefb841b41844546f918e694e2c46b278f30801e370da56434239909ede42d6f5b61276759949c9f9ba347ac972de480de83d49d55b2c10749f41da528f1750508b263a956a5d3d3b35417881bd9044a97dbca8c956d3719e38f34a9767082a2eb3a299381ee90cb65485f76c76848bf3f47ba156fb9f9f2f0c869f163b54f84583fc84e74c1df5f0e5c708afaf324d24dc20ab3f8d0516f30df92f869c4a4100e318abba7540d5ca3bac2424cca56c053f0a5837810712f9462fa8ae765a5139f4005d0b460f318aabff72a651fd6b4700946804265eac12461b7703386c04fc3e4904925df87d8d7e35e9bebd192d8fc1c04854d81f9b94d4c3d2196e4498f85067fb1f97fe7030262991fbefd912909e6041cb7def18c7e8ae85aece40418ccee42cb1f1843327d60f1ff419316584a2a67771480e89334cbd1a6b33fafe419f10d55dc34c597003f2ba75043be6a725f83aed41ca91c8d709fe780145f4201a76a54bda0cbd22030350e89a3116da16a6a6ea7b763eee767206d057dd10216c39bc1a51dba4d007b23dbf2cd6325c8ad3aa82d6cae6a5287806447dc143273f500998b85400cc27b350c27c262e0e38f0a50033e5e4a9cc95587d6098fb1d2bcc104df3f1f5e8989c8dae1a48540532045e742987591e2bad48df05036d30f35ef3aee01c10d983dbeaa944ce5f3406a141ed59d5fcb1561397129c48323a965dcabd89127ee444b01ecc83aef5a2466dd2fdc4b59a5ca3abe50477f42bd881bb9abef562a7761f9eab54c04f6af33eeef4bf240d158b0488c4c19376ddad59c4c01e8d59bb022824539e7a00c67a8ebc97a3aa9f582c3ddfede0fb47db07f297a6340f0a8e9651bf416fd3ccabfc12f69ffa81ab0cb04817cb566ea7c6f2e98109d278cc6552492bbc8b6aa67b885e9f38694f970f7504cc35091f20a97ec324b8e912aa3af3d03701c0137826aac74c548dd55a05c75323a0f950efd6d29717d2ee7414725c5da0660791248fee222cd0b0c02dfb61597e0ee9e51b809586e01c1390c60564554f1b9d0f1ac86a74fa59834d0ccbf386a0cc6cf644fd97b4e795990e53a5cca75f7a86dff1ef33b8deb8be9290a7da49805921d3ad50db89d1a7b3ad1c7ae03e2ce9642f69993c144cd8e5965c9ada5c5360098dcb008d84bfb33e10002b73616e34cfc076ec826d8cc02879b42f6fc94e501723797dbb816627ad5c48f7e352794feda0cf77fc1c65e4dd6e4010efa061c09d56e7ed6e8e114676b50a14abbad14cf2a664127b9199d42c543e5ef4692b9ff5821da9f9b6891bc74880d07a0953d504ea3b5d27fcf6d062d1ecd58f495a60458a4061ee440dfb8713b34cb5065eb18392851c69c52420a5b0615ec80c0ad1e54b7297504273aae6a4c434b2b83ebca82f80870862959315e11292a5a8414c99d6b1bdbc7ae66ac0468a39ac90342357159307b1580b2883b6ff98b4e0caf6f8816f94e94a0390493629de113ee80cc56670866aba0ff70c43057b0921eaaa3a313cd090d8862b60ac688c16f2731051c1844eaa168335b6e884fbe093f1ddc0c707b714d750aa4909a91523a8cd9504a2e3a20c0bbffb753ba4212cbd3c3e0e0ebdb6a6be818a149e114c5fbaa9831ed830d80196a00c4be9ab8d4e2f3c75266288936cfd0b27fe1adfcf500f4d2cd736165e80b765598297a57f28ae75e54480c96d3b4a39206f9f900f993909c28697b553601a150d33fd921d36425483618e00d07b953ca7a5eec7b9e0cbf187b6be811a159d0d30bf94e3e03f209d3066dabc90a71c92ab37bf6c8b1726ebf32adaa58b8a9ec1ae9d3b0d5df3a504f2df55f72c2c4c7d24405b55f81430a339b74e40e4ba5adb599ac60b1934a785ddd2b7a8140896571ad23c2038464c8f087d4d3c81902a14b282695f3027ca72add8388c5d21b8257243d666eee44ddb1b36afb76c05361bbba9087ec58f3a9f5a993fe467d2b8fd674a66cf05264c09a52ed99342145c9615b3b6e2eb85a6e2ef96fbff37f0286fe2189325627e8d9338f4805d089edf52626d7be864964406fbd39ac2ba5e3125592a7a338d4a5808e9b3961de474701222ed554ad18bea31b4286b9d2f2f2a19e34f0f71ce6136cfa5849f05032660014660e830cd012dc1445ffe19ff4c158de1216496446ded1793c296578baebe6c4d2e07faf117cb0a52250589914f2da356311186b53bb6bc2a36f2e43cdbec8114489f9e1e128f0eaeed7b59a531fd45e91f423b7a26e3960ce64cdff14e48898f806366b1ffb6a00468e6095034103464d86b589ff2bca59d92467f245fdfc69b034df08ef5f56445abd9f50cbdc19e80f0e55c6dcfc6d19ac5bb598e5183ec69d7767f5666599eb295c1ac3bdf2e735d86f094955746592928aad4b2ef59cf815107248a3cb00d62141aaae8f9c3a84322e25f1802030ad5114f6b4c7f20ae4d70e1ca57b2725e2ea060e5a49fca82bad1a209e6508bbfe56607cd1ea35ceba58d02c45c036ab4ae8e5710400b398d01e149323e741ce94282775c1cbe664cd0cf78bc3d3e3038041707c220e96dc40f08e2196ce00e3a9c734bb965461c169cfc91795d7063c9ad56944c24484b530c129166c027bda4edbdf7de7b4b29a59401be0976083808ac9353cd9e9740ed11037f37087ed23e38a1f688859f341d4faa3d62e2ef1663e2276d76729eb1573e727cdea8f6b0f7d159a07a778e3c69201557b7b97570cbac0320ffb02ecb3f9975200bde9083fcf31d1dd6330e1c30182c76e3062c0683e1c071a29a33396e1c7ae7ac4c26dd9df31da24a61e10db7cf5d2e3dabcc759ac970bb7c5cb7d9e7f52a16b9ceba158b62076db893797ec5a29d83532c729da8c6ec9c7356ba52d9f890509c89e26c0bc5ccfa4c0c75e48c0306c3913fc5a29c43aa830bc3ccba8ed0d20c7e9073ce3860301c19fc3399e40330b3fe41fef9160efe65d669fe60b00ff67ddf7798e5e0cbac73907f7e7078457b9bb778f0d3e79c33ec200c070c8623e74c2679107a99750fb2d65cb805688bec9e58c4fd070cc5a22d003828166dffb1c71d2091615907aa1067d63bc0f63f99836fc9b1bacdb1caace7c85ae726a918ece02a1c6b0f1c27ed66c57cceb3a393734a4feb653528ca681f168002a954e32880cdadb3f278904e4ac18f7aad95ea8626996c1bda27cf99e78c757bbef29c2e9d3d653cf94746ea107aed613faeb85015ce5d69f5e34f0d975e6350e0ac330093a513b0b4e795bccc4f9a5417327016c648bffa9cb3e452250a971780a85d239aea140e58a26d57e2eec46927416c192597a62d658ce145470f863e51b1b0ac3d4b2c2eb858cec04e9b0cdc0e9d6a082f54e28b022c431688aa3d4b1cc850b5b09a325e61853eb488c81197d031b353f278d153e61003570e3678814eb0a8180d3e586cf070830b8e4d887360f297847e224727c50f7705076b3ad8ba0000f8464606101a1ee810e703271d51661b0c415c0d3bbe1c84b804a0fb22002ecc00c6f0d89e00c14c8f2a7c64f183734300170c6d6200c16414603bc30059d608c1298814224e866d032dcb01b61f10e079293242842d09214c8c5066081509e0b020c28502362f16805fc0806d8c226518d9c106475c20817bd28028231a1cb0617980c743095d906c4440e00813c444800909909980190aa0a9c01516d0e2026d30f045065ea0013cc606c8e0001a1de021ce094e1e8842c2705443920d870ff48002e60202292525588204d298149e4832130215a8508a60e362052f580869ee61043d8841821ed4e8818cae5645ca55f2a20564e28416319b3e5c4ac3e446dcb3d402a7052d3770e173d2c483a1e9b3c1c9d3f224e5c40828259e744f4091224a29650553c0a062c60b3eac11e504860f86186e90c1d352456a06303424514315ae89ce4a1457bc2a6cd8e2062fb0747b963f8081c30f64e4f0031a3a401967a9c5cd9ee50f37e8b2dc273b6c5378d8828593a187eb458b962a5f36a53ed8227eb8466ca94870b967800869a64fc6596e11b3c970d72d68367d1844b9e58a2e21cd5bd4d02e34080a04e542b7d01fa80f540bed81f24077a059a80e34078a03c5426fa036d02bd40aad81d24067a055a80c34060a038da22f502a740a9542a35028f40985a24ee81375a24db4097581b64099969828d5483002165610810a21484a0169891210a0f0812447a4074ee8000736a0810c60e00216a800052620810898000124253cc001460d20e18891220c588002882460c80842442842c001689b284808062800902102fcf0d103041e03104000847604cd747ce001908c7ae1e1059c75f686da4a3fc51e33d35d457a2a7a818728b168993f188b0ba071e88efa5b430a640b412eecb20a75c80debcc8bf16e3224aa219e43ddab8cdcce11118990606fc799c443ee3eda6e0f762156a1ee6e88bdd4aa30d64becee463bd61280d4623dafee7acc5927903a91e81eaaefe69c75d634f0efbd07f1ad9a5cdad75e9188266dfd148be6d0b5b4d2004e2a83fd5662a9b2377c70ac3db66bbf7dd364bd1e527f74496ae935d3e6c7062a6e6c90e2829b2b6b5ca141b7512d464bc616639581b5026705576220b45d79c10ee32fe3eaf1c5f89663b86779858b2cae5841668a1d5dae33ee4721acd4cba8ac041ab88ce5952c54289c999a2b51b212ae4071569e5869e25aa8426f996ddb368ee3b819a2700933581967e08267909a82c50c59f00c3e34c1a2099e5d51420d6f3a2c35c0296ba001951916698466694a19d29431b86056451a5f182a2aba1b64f8029732bc6046c5ce9e659518ca2a4d68b629a680e14dd40da228226c6226862e3786219a988941871007331886336270010733314811c312294881d099281bb80045d40c9e405146a9894243e687bc67f608c65946899965d4112fa0a1d2c5940b9a28f1829b5bbef0c54c89d59e651497282d4d4b44e5f0b4448e3dcb176cb0c73dcb17c0a863c488f91123342ba2a4c2460b9b4549c58a8dca1927a0d4134ebe259c7861ba22382fdb0f984a96a74bc586272a559ea85079a2d2c2940e0d318a31a24c61c113a9295c40494db1028a14b76739e54c9d22834ba3a9062e70cad2a40627dc7456baf8c270b20418181833c41a6160d0c50c42d4104319058fb809d700d54df9d24319a58c32ca9319988e8627700aa6e012b426103540e9f095529e3c990921658d2dee594ea161fb01bc1dbdb7c746ea78fa88fb778bf591fd7634bf4ca4de9b9b7ea9a3f489d9974a67523321b66a032f332f5e84bc04f113a5890da0b0186f9cbc3650d438e902a58aa72e50cc38e952425162df3d4b284868f9d12234fb014a540950ac64114b285252663ef4f024ea095409e504ca05a129a2c062b6eb02ca666bc289a7c56dc249699b70c255819b70e2546736a431830e0a0264bc18a18316694c896206275f6ca5131840cd6ed061fcf62c9d14b1c96719597b964e76d8e438db611cf72c9dc0d093c6c66620b15a40fdbcaec92c90fdb474d746210b641f8b19e14ec2a43560d2b8739ac802d96fd6dace02cd1891796d2fa5df178469f12908f668fede7655f6c5fd7473e380f6a5145cf66bcfd2ccd49c7a0b1313a918fd3c08f3415f8c731fdd237a3c841eeb9008fdd535b479fbbcdeb269265228cc4b5da1d8fcdcb121b7f4a1ae22117a1bda9c635b6246dbe79ea209760d18555aa06d5a69b440f3320b546f81de8c732bb92cd06c02aa8fc58c6c2761d236dd8049dbbee96981e683da4c9a1bdce68ad0951fa1d1f5cbf0b57736c30c66348c76cff22906fff9f62c9f58507d289fb4944e47ccaadcfb11cc0ed33483a17c9262877b964f4ccc62289fc438cd6098c9308bfa89aa325b69207419bef85219b93d4ba72f9bfc65253871f9716ab2f19e65d31a9bbcd0396e0665e4b8321568a229a149cd78abbce9a87432b8b965d3174db328a3d093262eb4000b16512e3811830b61a4b890830d38f62c5b88b3557b962dc8c00550dc38712a5b58d33473ead9b36ce189eded59b6204605b3a69f0a52f108f7edf786650b58c0883922617ba76bdd9ca25d1dadeb1ed3bad7365a775288a375277f4cd188a3795bb6dbbc853b087ebab644fbdee51aed4e8d7cba0947eb6a4e4b340e09f77a63f2aa71c47326db66d26efc4ae90de396b137af88771dee1b99549f54ad97c9ba79e0ec8d966ec62ca60a764ece324a28c7594c0fd2a9a9da23e73c94a3534aee47b0d336932fede9efdc3724d6078d7a3da6c91e982647f1ae1ead8647df05e05b4d0ec1c7b714883dd59eb524ec1bf73a1ed9f37c251609373ee5a2c6bf34d9b3d2a2ee71e9284bef82e915be4a14427fe469f122c523eef44bdbbb7af48ada8b21ceb2c1106fa1b5cff67787d9de7e3c6108c1675d27733959759ab7d71efb23aac7bb73a86bbd63fd870d7f58efc7eed9e48fa8f0944671e948a1ed79da1bb577f26e6f0c0a8414dab85672bae101c27888814f4feb022e3dbe97c9a4290b747b7ac6118ef72d098f1d9e4cc2638f5f9d14da5c7832a9b2b26bcee83b5148f8a35193747b07cf8945c21dbe262d816ebd3cb6f79516f51d8302093599c2d2f60e7e78db1d0b1b1f9cb4623c04dc9cbe63d01d9b5e72d17341c20b12511b5c81734271c76f1229081e6311c4182b31d97e1f625dfb8e7f2f88cfc4fbbde045503f714a4cbe5fcdf43d7ca89b9eb8dfc7eca1ba8334226bb311fc2f7bb9c9aac39f342e370942c3bf796efa096b16ee2d65f2d11a46100e73da16f62ca90ebfa1b3377416c71c42c281e3c61c42ba71c3c61c42b261c3670e21f9f8c4e610522c069b434830d86b0e21bd5eae39abef9943483d3d3c73088967ce26d2ce8ece1c42d299b339849493d39a4348ad166b0e21b190c639ab5fcd21a4d54a358790542a710e218962388790c2212410fce610d2f7797308c9f3ba39abdfcecd21248edbe610d2b6e1398484e76c22dd399b48d6d6398454e7acbeced91c42a273ceeab7d85b3d972c135a2f1990f6501adbb40c23a53c224b50963065182c5041584a1388d977cff2082c6ae89a103b6dca54bb9174ed490b9f73257c235a6dfb146b58d76ad3027137028fb7df1b8ddffe4d7d17f5953252bde36e24fe1ee37f376a1d1ffcb273f0463adf3e6a1ae57d3c4b8fbab675bac6b9f97eefc11b71bf1775cd5e4aa5299a9a94d178d55bbac6b4bdf51d4dbfe0e7e85a4bd754ba268affde690bd4a48cba83e7748dbbea2c4db35820fb51ff7ea56baa4fd76a9f91dab4405246dd435d0375add3a3127b0bc46481acb54016ce54944bc8cd97f11d1a8e66d9e074a3cb0da74734347c995a4bb4764d5c3f46a130b2ae9b6166ad79c86d7aa2d56eba6bb69bc8d24cf72b3709427b95814dc50e956fc38656a25fda75b777b0c87b2b9374b7be4cae003ba973925a391232b7f7bbc57b393956ef02e77e8864f4c76ea4e32f5d938addc675bc6643d79ad0383429fc987efdfb0d55dfe1519de7b121aa87573d3c19d3aebb32a94335c904c9e8f51b37fa5f52484636fefaf5d44a2f5d7bdd86a66a5e474b82ec7c09dd54c78680e739781eddfaf89dbc84b28680d7d1b24dc5a2159c39be79e99abd05b24216c88e87d16c82a6af9b60e33cda8c9306804f1accd69e4e833df65786caf1d89b6c5091083d08c66207ab88a4c9462cf69812130e0efb8d14f05eda266042f2d2359fbf0ecbb5251aec20169134bdcea483c360afacc4c4e730cde4f31bbfa19b9e72fcf598911c87fa39ec93168bdd464c3fe5386c72f0bbab26b98b26e8e72cd1a658046faa49d53d4d2f8e5a05bb49d93eaa43b62dfe836cc402d97b909158207ba06c010b642fcb2758207b00acb0c90e72931507fa29c7f57f72932034a51c9a05ad270dcc643da23ac96eee5527596ac58a15fa653fe5c75eb7b0db5328ebe3c6ed6fafcae48d5cbbf1a77c92aad9b406fb537eedf5a77c1baf0cf5bacf6119ea751bbf91a15e875dcc47cf50af4f0bf43c693e36b2a7c9240bd32a6c9bfe95a5ae5e1264537dd47d4e6daac6fa88b9b946d0a8b0ed7ab049109acf6d1c6bf0b0dff807e5a39570fce1b43e9e9a04a1e1b88f37e79c739ae08c09ae6cf086b73e9458a0d1fed833688791a46194582ce46e4f937649907dfd84e3361e821aa9eefa271c879df44e52355b3fe1f8eb9f263d9d6477d52a6cbbd35b7068166e5c93dde8d22a6ce44403b393898d87607da48fb6c07eb7bc8ef1abbe2ad3066f9e531b9659989985d7412a1a79e94e24616a4fb1c8c84b57a65d7596782a2c0a905ee602b3eb7dd4d8f53f3a8ed8f561ddc048bab6cb045e76bd8fcc882abb5ec79d4dc0596957e3f515895dbf6202d273f182a67a7963a5a0ae141a2c55c6568513d309f1c6abf20d21a682437c117e613262d75fcca22ab3fa0267acc222224ccb4d0e1167e858d929228c104f11687a8a28c38505cccb8912c08ad8f58f95e04c47c4aebf4f09c2a835f4e9421b3f6a0f72b442c75a6537ca6c602465bb04f366d7eba8a51729bbe6791e26b8d689ea14774e547b6253f43951c5b1e553b1e8a7a27ef7916635f9b32b185234c1449b4cfbf5a0a89174fdbcdee6f8eb53467afb23fbf0a7f6f8d1640e9d446853fd7ad594295f8b5a8d4d93aaacca6ed8c011e28073239f60238c18cce7f3d1590255460fcb6ebcfdfa2b1bf5f0b83a179a9e3c02cf199d9c1d6e47ebe49ccc1a5b5b4b68e4a1125778a563d31f51067ee10d35fd7c3aceb3455e38e293f786db8eb3cb41555e8461776b10942028425a64e0ac207532762fb08b19651735e6ec83336fc410420f82b5522b82dd5593b2a2dae96b6fc539a76d0a620d4ae9bd58b62ad65a8bf1ec02a68b178a8f29bddd5c24e8e244e57400679d73d24fd102f1660d1067765dc2da0fcc998228c38c2f3679d7ec3341a02008306a04a125082c4148d9358816bc33d000c128206e00820b07486a054a0a65a24db5246befbdae15949cc0711cd759dbdd7bb9241aa8b2eedafbce765df729165924dd08f75a6befbd5cc6c70aa8b28a801f171299cc474703fbfa24f1193b34ac74a3eb32a11f96c88e60c422b11a489254abb4494a558d098261245dbbf688e1df8df127ad8393e3f6bb37009cf4d931ee7773dc274d567bc4badfdd019de4b163deeff6bc4f9a071fa1f6887dbffbfb3e691c042a9fd5b1988f5c958d7cf46bf57195c4354e98365a693289cbba88f6bc975e3af2d49c12a441900983cc1764d69464d4b852261921c818b15d5546a689edaa32b1c85a7b2f1932656243ec26992ccdaff1043ece4beea990797baa91867c46363ed212da66e38b30db10d96a4fd28d978cd9b0bda4c3be22cc36334c2e3d41c6cbd681e76da6db6791abc95a4c84f94d54afb8648526175a60fad1bcd54b6a9bb47bda1e829c18a3904481c1519b4e61242b6c1c45a144d1a8bb46a98413a5182e3c6e18bbde314a3258ca27a22e1c7a4b409b435caaf0eb36a702d44981602057870c757e18bd93a110581098f1de2704a8d36a08f5aeeff8e0b66d0fa8174f42bda897b6973fef987ba7667b79d6183cc1b4b977f4c87e567104a23d750a74177520f8caf6ae6c9f936fde41b3b9c788dc73bf9af41e3b5704e3e9ba91bcf79c80b3b95b27dcecf017f69b7b6ef34a2ce285178570dfb99777deca4721197e7c4e0cf6b95d1deb5d8ec1fefa3c7830c788848f3d7c4cc7605a84a5adf31891d7592cfbed3ef73cefafac7357d6794f2655f7ce938f5a9fdc773419de7b8efef169e523eff9cb3fc2107bfa7b9753a0db1efcee0782ffe07c48df93b60dbaf9bc10b87692eb66701ba3c3fb262ea03b772b825095ddcfa9ee0a38c1dfed6e9be5acb55673f4cecae3c7be97ead4dfe625d4356773da30f15d749b4353cabbb5dafbf42ac5f976d786f0dde25ff6203123f93d29f528f5b890e46e3f02026a8feef63aacb5a30b88917e7a5d9559fb201fc6b9ef9c33341c131a384ab0eec2a9156a0f4ad636f7a9497b255c469a5465f5e1deb24e95e12b49f2a1da5565415323793457034ea2f10b51982f15e3cd23d41e56d7eef3642b1079199520203c3d39d11059fb638739d4138dcb5569d78dae5fb68530bef435c90f5a65ceea83881875aaac5231922ed797129cf48571962880736febb69dfb100410cd213a87e8a6dc11d7e31289454b689ceb537be053fced604eeede7ab77db1f16344ba6fd779eb5b26bb93db5597ecbed3d444191b0c37b1a8f52e8ff7597d3b9d7346ce59158b6c45c0779a5c0a7f445184a5cdba4fed71bbdf1355f137c75acff9d4f94efe740e5e47c75a8f11112fd2a0e60c00d9dd9e2727b3deca222c6dd6988f56faaa7c24ea4d35a867956ddbc34dc7865c2626bbbb734328d3eee8c6224c279898c02e2fa17190964c384c4c3ba9b5bfdba4707f4a7687b424c84edab687e43d692b6281dd1dc792209b8a0958d2c16972bbdd0e7ae208447b4e1de417525184edf76ee19cd15f1e73ce48d52e1a3267f44ce8924eed986e410f0c2d78ee734f8fbcf7265dfc39758380b43a317e155e0cedb55693dcf157994719e3eade571f3fc5d57857f7aeaeaa0b37f86111b8d77349b8d6a515b55c942870a3ea3ad5491d7cef05bf5d95799431aa1e923faaab4ab27baaf4e78c3eecf2b418d3d1b600ac32da755dd7755cd775f73ecf3b97bd9fcd6df73c6fdbb67b9bee964cf0cb28fce08cc24fd0970dcacf4f10f7feb85c5d5c231365302106136b9a687ae1327166cb6a8f0e0926c4f8a8341b54c558c97ba918708a609c251352f62ca7b26c01ec598e19635b4003dd2d0aaa629c5546492a72b4e6a02de3fded829a18f161468c6a8f4b373ebd32268c7d5f05382b7ee7bd83733749adb5f66a926a926e22916f7376ee3bc7b845b4cb0a1861eb98b36a64e69187919c6fc8a9a6ebc6f122b993562a543fef18368b9a33f6f72c91107382375b68cff20447ec316bf6077b964ba0d92092da63e277dd3924f748a2ba3c7af7529d1e46fa2934d74c09d41e36ebd833828cab7707df913e36fe23d341f270ed1177e1a827d7a9ee6a65ad95816098b9306fdbc3fbb56dde0eebc422efa0e775a0d779777361b661ae9b2a1106d9a031e3fdc765cfda5a67fd06054f2541bd7d77c73a3cdd778e431d34c448ca36d639c639cf39fe8f90475fb14887874727e11dde8a444810274e1c347bdcc93af9ee9cf0adf0ac1c7ecc2178fb2ed424f80d1cab6cb4e1528bda34c0ef344f3a3339dd6cfab3a9fdbe8368d22c99710eea2f1f71ef4e43f2d3a4d0feeaf45d587d8c3e58b2fa31cfbcaa3a1eea805f69f23b47bac60dea2fcf4d392d748500ed838c18c77b9ff60ad9b9432b1689a08eeb6777dbb98fe3b88dd3dd9220e3eebafcd34d9ab78d9261789ac9ef902e0972ebbd7462d5f689d0ed4de669f267671f8ed3a40edde8ddbe713f8fef62c662d1d6d11fe4ea0ebf1fd60785a25142412818e7c711bad1e5e2b237c5bbe81673901023495baff5ad30d41d9875aa6cc35e4ee2dadb7de80873733ae9120912274e9ced537bdc5d6b5556c7aeca683767219971aca2111c0d1262acf73e394c8ff8d1d212850c3f5c497eb424e19b8483b4586a6d9b5b83b4586a2bbddba7a236b80255d9674feba3155ec79539906afbed765b47df6da758f2d177269b66d2ee0da476bb1dbb23d0de6f47e03f91ac7583a326936ad781dbbdf86a122fd536ba6d14cb26f1bb7c64cf64df7c91d07724adb249bc7145c8baadcef656e049efdba6491a3541bd6992d3db266ef6dda59bce57c786d0df22f4f74828140572bf697b49d6712764fb15b7eeb2f4d86d611e3539d708e93eb1c803c13cf7ddc07cafddc11db72ee67095bd1359ba21494aaa6412ed3e7d74c9ac43a15020780d39d71cdd6fa7dfde515c414a528dbbe3cf7b2b4f0b744cce351b7f03bb7fc7502810aac9ef9eb7e1cd6df7debbb94d53287407be4ce892aa8e2640b3c34d4f8fb388b1b241d8b34cc24d125fb66ccf3209a89dc4d4067778fa338758dc75f66c82b067013a0ea60ff0cbf5f54862309705c1d0f33c2fcc47dfec3c2f0c5fa75f62f751f8af087da7c9babf8727aa96ce2cacb53f569aee8fb4567bfa2824bd935693176f4b35262b6cbc052c30e24c9318b65c41850aa2a8ae6c19d326aa0d531a4be8a06123031b19b059019b2deebd3b76c0dacc0e1a54e082cb1316fc0046091a3a2a90ec1a356bdc4cb1a9114cdc7174d924467aed9a3454054e382976c884146c9a9cac0973860b35d600b1c11cf6bc55765411da820b7c31be343466b0823245b0f1024a67868d102d3653556ce0650d2d35f0618935d6e852c0e6068e0d0f52ba30b808830ba61d3e44c1268d931d336cb1c69a1748b005182da0d831650b279aec88d2dab3dcc2cc1650ec90b203ca0e2818632c05638ca1f0ec596a41841634dc90051a38642186942cd66481e60325c66ffa510b5b4ab1e73f5862ac65137bfe0331e5127b7e0e81dc86b76ddbb66ddbb66d4bb3831b1a7cd12587285eca8889aa200c4e64740146142d5aa03853c375bcb8811733dabc81c1541764ca266219258506db0a153da8c1e50657b0a07b028b3328166840b14135c801c6932e6caca81203369d1358783143100d9ac61a039d2d60d8d1640cf72cd350b1c3290d133b9ed29c200d1120ad61677de0d1de90ce3bbbe9cd29ce1f0f4ca0fa273218b6d0aef5549f80c6483fc27d9d3540cc780e11374e614f7b2bb52a72697f01ebd7b4b36799064b53cf9e651a2718c400c60e4e51bcf083161460d1c5c3020cd4fd7f8ebb26ac7c3c3ce1eeb550601175b1a8d2744518ab2b6c3083156058b105973328b5e18a356964a046898506563c61c598d91560e4809ced79f2677b9003888ceea827b3d783f4117f58a07a12ef793a8118a13bea4998b38a4fde15c8790653b7da24655a9190c3364281502cdd28f3e06eb25b6d72b4fa225183825bbac5943161a140e814dd515fdba841ad78a18939ab27690ebb0a608d917e09bd00d61845a05e689b393465b95aeb69166b7b90581f9f40f6554d0f8ea9c3fee620538725daf653db32794d6698f16346694596b20a2382c8b0e2cb0b3228abb0a18a2a33801304a78a261ce26af18558bdb43359497a7f846f871c71f7fee17f07bf4ce3eced1fdd2038456b6b772ea9ba6ad326d58da92882e0e7ed4f18aa549fafaa9cc71849a14d647d048931f250a9c2f0f334488cff541f736aae3e7e3eac218c9ff3a178f04eaad811f1e08d446da4a2713658c322234da29126279553a8418dc6ab1d0cc02ff6f6895590666fc74b58c80d0fce1ac2ea24f74d2cb27d92f6e2b7af32d4694b35b216c24ad76aab33991584fa5941507de299c32e5bf1f75ec81d4caa966e5cee5ec5a2ee134f1d23b22f96520565ec1558ef9e3cca18aba55badf5081fbfca2024c4a6eb84c04e889b29352bbaea446e953b0be4ddb31b05d7de7412d70ec573a73a488b91fcc1719947191dd771b6be8a4482bcb12a166b6419b13ebe356aaa5b44c273b1d811d77b1ee3deddf66425969411eb3a571a5f93325a5d47d75a5fbd9673d57b726c7b4f6cd3b123e3ed1fc07a8f566a29f5dc7ed2d46cf19c5256ea79ec48cec79bd0eac95259c9953b0be4fde6696f6cb2a302873dbb14c447815ca8d2b5255a4d8aae9668abe9810ef62cd164d968ca6c3176c47ebc093d67bdb33e4656cc84d65937caf99863d43a4bd728ad4524dc44234daaaf94d493747347ec5937a1e7741cb7d7723e6a23d6afaeb5ced25624121ad9f9dc463cd7e9b119dfb36e643f3e288b31545a29f55ce52adaa4c0abb292ea3b42c4779abc9be3b873bb23855c737a625e42396f87ef9680d968751dae735920bc6d22110fae08e20a9ee7c87890314e1a8f96aadfd14a5246aaafae94f3d675b492eaab9332234d4e393ad6b5748c7352e9d8f758a78d8c629f3ec2fa65fdc61e30de7ebc655d95c757d15b8dbac611d9952ae9824b5e650d31c5384193b7674945952e69446931861a4c6a58d03101a6c9146fa6704393b2076b56aa9f349b4948816eac5370c0a435717772128456cf9da8727702c598fdf6bd1a71ffea3d13ea3d5da3b4dad43d8c1df13414a5c58e78ba064569debb1b7d6288892cd07d988dcc32e211a11ad4867b585f754d2a76a49ebb513da76b52f635ababeef4b440429b6bca75db0dd27a410c8149030f52bc55cede493b9513fd6afd1ac0e518be9320340feb23f49e56a29fb42526daa7d8804933526feb9644c5720488c65a29a6aa684489c93df7cdbaf0d138cd74bfbd8e31fa983edaa69598e0dfd18ed955335d3d2d90c5126693e3cd6ca9519aa7c4a4bbf70028136a5094d6bd09a57577a13b372f53a7a5ee39cd8426556b914d934b8e92e0578d023ebd127c7a229b56825f7f330a98da59af6a098d8302be1a85fa7a2676c9d6aa86d01938e0f77df105f7867b33a788b271e61451db942cdb942c47490cd034b5efed99333a4abe8d82019aa6b635f3e628c9ed42aa33b366571a7669146e17524c5b8893c14c83022e87a926db9ea51456ca28b49465c204855146b1840b416bca3371ce9c31069c3f9df5517f4fba40fa39c1b97acd3529a31004b591ea56d7a858f538f220e3fed34d55d7a48c787acef3daceeb29fdbd11fdbda7f7b491eb56d7ec5dda8805e24e754dc802713cba46a46bb740dc7534f855a86b52de6be1bf7bda687515f7d5e9a90e754d8905aaba46413d2d10ada7f5352923faaa6b4c54d72cf0da78d6d428c4faa44d375ceb9346395ab8cac9352923f02d5da334f0abb3b252f8ef635692320a35cd6295c2f368b3d29a7eb1403cc818b5524d8a8449c3df3e699f56c237d2544f53c0250553fb0fa0344c9b3fdc6ac9560e88a02dd86cb185150f82f7de7befbda0787aef1559e238de0b8aa2a8fa15c14f111441711445d678a20a8ee3388ee338b258add63bebe3f5d6c156265da35095b56eebf82f5d65e32852718e5a3cce2c16164f1031c6d8a51297c2f054960f2af1b67e652bacc9d541bccae291ead4b5319e26c05658a54ae2529565b8ecfb9db28c15d74ed8c3b3dae8576519a8bd7a584271c6bedf61a9be8a81ab71c43ac6d23150c7b491cf61f778cca408ae34fec6fa8db10eae56ac1b815ad4e409fb7e458ae756392a955e81fa28fcea44555cfd86e1d5a46ba7876747b55aa956ab202edebc11bf3a61b36e3beb03f6f1e098b15ea9ce3acea1e8da57f599335bfaa56577257189b48442cd06bf7a3de7ad1c4d8e2f55a71abf164bcce40946ad7c04a65de3a793b8c4d545708a4531f1ac079cf4a8542cb7953d4d32a56844000080048315002028140c88c40181482c4dc32c647e14800c8b904c6244154a22418ee32088814806a1184388318600630840082169ca46001418201158a2d577ecb846043cf14c7c438620918a066b84dc99b810adb5b4fd522608dab7562a9c3434482543684e2ae184f7720053e0fa25bbb099c630e86ea9e253d24e22cf2a5520fb06205a3b3072bea38bdff101383d761ce609962d3c15cb319fbe29163cfd34a72b841244ec1567e48281e58e78dedd6962e25c31f5d174f9984e107ef44b6d9597dfa579430bb81e119fd5e5ca611fb0048bdd20c01136cd6520cd1d5d2f7680965d00fc0dfb2ea7be4641e0fde1537a128c00e5a801cf37a823355a3366cfdfa1373c326ca6440f74b9ecdb7a7fa4cff0adf64c808f8d8e820dea28595f6a786a5019bdef8f85b0dd0b91d8ad6f2c15b117104d2e9800f1e4f54331d4ee7fb973f5dc16bb608988c721082dcb6c09157725a4d5ada288a1613cfad6864e2b49e5e6d61884974da39bb45d670f293140fde30e14e353c9c228dc34b30adb9e86469172b7108f28f01d92d6ad27832cf6c4bd1e7f026f380318cfa1f1ea6857111a25e84f96a5eb799640d1836f89bda1c3b99c4b4a188072fd52e4225eb2eebb54dba0bb4e5771a738717151e011e3e7822503212650da0f504e75b55b6d0672bf9b9e38684aa5d5780923fc4ffda11e942e141755b0d4c3db57c73aff42cbf65bddf4d9ea6226e14a93d5401862af123730a1d581ab5ab4540e6fa0a46e2ba4cf3e1ae5568aef82369a1505e04df7939b6f3a3a9ddcf5bba07370867aabb44bf228e799f37739456c8c5472c455441d03e73192f4679c9155d22dbad5bdc11690208bc3a31a55c2672d0bda8157957f8dbb8e178c961c6e803e4b1fa72f35a52243dfba9e6142873785c9643631bd9acd931d0598658d2f025e1ae4e36e6c6bf4afe3e3c0b4654e3361da24632834b6c04764095429bbad47d91ab1e92b163266d15577fb439948d46f0e6b55dce9a6c32dcde79c6521aed209409fe2bcdefc98b4cbdbc5b23c4cdadc6d1c3b8faa7ba3e387c6b1bf7f1193d675f9479417aca3d35c84145139815c5943950309f8b5767069cf5a6c828a2cfe29f5dec48261ed07d416bbb18931b4a70c3b98aa20924623461b92225dc71330e809ec9e420a6cc45abab3d36c9055b31d17ce2e59a1ec4f3fef3fdcddfbe8e784dc7a03318a3bc16f6965cebcabadc0f45734ba6c0a7828239a31d0d5e29b2c83ca48cbdf03a5c1c0dcc573cb47f073baec4a8579203466d78788264cdb333e353061ef40b0976bcf502fc2a95a18cd877b695c574000df50501315e9905e2a0e0d0eea9d868795231005a79b337d7e4c7bfc50de8315579b2ef2cf93c9feea000cf22632f0a3bdd2f7e7db25ac11a9f2b9520e7561eb6794217968bd43d754cae53266c9ba7a84cbe3e823e2d4ef9df0afa1d6b7fc9dc719a6933bc89a3ea6075dd69131473f3a15c54f8a59726ac4cd86ab6833b4c77f4a57ddd59ccacd97f8e81f52dae0a6feb685684bd4f798dd99eb0b492d364b22304da8f2fd6a6f342a3ee8cf2ce8959f6078cc9615537dae85888671579d11596cd552a32ee40982e86110cdbbd534333e5b4b0d4dd821d83fdb99434342e0d6a4220a5d991cd6ed3f1bd32355552cf0455d48161ec5eca4394e0d91c76b41c0f5e86cc5cc808471854f70a0e83bbc80176579824aaa1c05a121d56bbc80abfd80d42829f246270492f334d6590c0213fc29e1630bb7ae9d2169dca6a4e62624281c0c7cf88ab8d0c95b4e12ddcf76474c59a4cd54918fd262a38a67a4ff30278d39a4cc396b0773f2845a70d8dc884a7a4e94ab1f1699e044458b466b8f7926b6762e5cd44647bc7977d9600407386f4764cdd8d3fc5a6141246a6c1916c75713d117a8088d5c0911d5589e13a9f905d9691728878f3716430500992e97c55ecf3aaf48426eadf3816bd7015f66d469fc836fa6dbc8bc9763f9b34929ee790370359082575303bedae2ef7100ea15307c9124af2b487f4c36988dce6dc4c1110ff6cae36a44dfab582f39bae77ed0bffda5875a43d70b39df6e266c190b6664732cd8a59dd5cf99af8d22c50550ded7e01e467aec7174e46f0eb511706ec5bbc1dda545b963ae2be154d4867522a3ff6c4bde7ef707051ab4777b96d2e3796cc529c578f57007023492e112defce4105e17836e5dd9faf2392c9e152b364d24f29196bb3eadb04e26c8b120eb458e02d5570e745c8989a860cf2bae2d7c527fcd78fffa2a0ae4a0cbcc3e5dd689b4b15e4395bc90a990fe72c06c49d8d57a74a838c16f50a422c023201350c8e2eac4c65ee0b6ea579a611859be6da66b3a8ebe99366857c2cac83d6303b83a1beb989b578e79c505a0896315688a114a406c372fd4a36d40ad32c24d29f665b90db211a8b7311484049be543d6035c27f10754b1bfe2ef3dcc57923dab2819ce3c2de0002208ccce3a89c81f3ee8d88645bc2c3bfaefddb1c286269d6aaba2966de2f305a97b90c64bb67ac0e0933cc4cdd861d27f8c54df2e4d775d8d5ab7e48b825ac5aed491819c0a74168230109b7220a1ce231a59dc2c77149997806544932a2f59d4eeaeb15bbb1d4f064949f863e4ee640babec0d969ed3c9f51a1721015759d104e9b6f83bdd3f2f4eb557ccb8e9ed8afa8e211a48defde0c42e55bc44ad102611e5104370eca4a2b28bd1216debc0a0bb659fe6a8d4b40f2813c9aea27cf7c006386f049395bd50c77a0a83fcafbfc79600953a9626dd3ddf0e30ae36e7827ce8aa93aec9a146e04ce289177cb2acd8d38aa80d2e7da2f6e6bc688c46ff53b5494260bc9ac10ae3b9ad4bbdc0c2ee156e737dbead3861741e58f12b03402c1bda38ac4b9ae58b312b468cf7e03e7a3d0769724fd7a24c2b6c37026158e80ff0fcb65a31cb1031f471dce4f2719bd4cb56773b013326b18cc40e1b982a374ecf29673c75364da7445a747e6e2bdf2428c8e7137bc5ee923c60526eaac1d7d89e77c983a9469a43299272fa4662f8786957720f988e1e49071002f79c4536547ab25f50cd969ff643cb502b64b0a7e70668926d1b86d0193416498134febbeb97d571d89e79fcaf044908a129f82e9b0e8911ec39bb08061abe4e224f8487ff0394b22f2f46de9619bcb45042bdcd3396b0be0d337dfd1433444775e6c17be52892cd9d65428db381c5879bbcd9699cc0f16190c1ecdf217d3761136ca413878bb2a874f2c5a5ede8c4c1940aaa66946eac4789163c02dfa94e3245aad9b124897c8a9098e444e66e1aa93990f1437d62b2d95c62fbaca8615e7c0ee5ac76887f2eb9865b3dd9b837adf70c69bc516efa27db985e04bfc04944d5f1d81d6b270ad73cd80b2a72c4f96c243ad7c57014fced287e3055560118a88f8c4f07c266528686030f458f58dad06d2e6e5040b411213eaccd3a820bf7d82fb109b8af28b7b86361445f0488940b6f7ca48fb0fe93c716b6c3eb253888830e42681674514552f80242fb5d08dd0752374e9eae6ac68387d7296c62ad4340909c900f0c25bc84b6fa74884b502787256d75a6a74d780ea423fe456ae079f0da730ab43b0970d0e55514f9acadb6596ce46841effc8a0494421cd83d84da3d50952ddb4e9f3dd2cd4f7d13def6a6960b3948dfad36577137c589cf2240a95f60928676ac26b6f03c1a0771839728595c2bcd42e0c4b0d205f38d120e534a69e4dc4df04eab0a3160a6b81b598f620b8313bd4c660ca0480f4a5313b02c324a169b45a5bbf506fbd36b269bccfca182c9edd56139f1bb574c15569ffee7097b54de6cd526308db0392cdb9dcbe6586a013d4d54b0d800c1143cda812d4014206724322e23089c2cbb3dae362557b0d5fbe0db21a4b8cd069a6bb435313c514b6cf1bc984758b9054a5b741be6a67da1e3f13d3b2657633b216297ee20db866a7ca34ad6c9a011286b180d5e89d450854d21e6e26f06008ed6b486bd635e50f6a71a04467871806996965195405b05586ca45337cc5245210597b0770d6c9fb087f0841c896650604d4a5be54db55b682d726e0045e34888c6cb3f44ed21b78e5b7583dfabcf1ebc46138f6b59a30f816ce2ec9288f7d129591f422e1264018696828b2e5498d2738403ed8f280b071c74dafeb0ab27a5bc22b70c1214301cd0abe059225c572581aebe581c7b71ecf2cc7481f0acbdcd3e8ca0f02c829f2a9312c5bbf4573783cdee6df8aa512db5e418c11b9840b975859a9ac3bb962c74f92abac648af97556b435159b6f83a4cd98651fcf45633b749aaefe26ad15ba565d3b922c927538524f2e0686e6be7e3879f6a88436a4b798bdebaf461c335563335d7ec4d4ef810b524d4c883cddd8c1656fe480be8f63bb03569ddddfaf0c2880dc1d17530d9a832a5bef9ff729aa5cbe59c75372846a79ba3102d47cba719215c25652ee3ac264fc1b496ae668d85cb7083d4ddd77c79280f4f5cbc19c5c1dd39b1f92d3acb8d83d865927e873aea288941e04f51946ccce313c62eee9cfc26130ee18bfcc5a02f4ea19eb3c0f2f4f740366abb1fc199d0a603c90fef13c3b3ede3d4422b714dbc150ca278f50a2f7132e0b6c3d68dabcb3af5e2bd93ddd8c013ccb24e3e36cb483ab1f5fad65ae8a24a135aeb4516cc29349de02b2334fc42e92ad9e106674ce3d4d0287d80293b2897382b954f8f040e67279e4c1f116b6b5b777b51e2a0bc80438dd2406c2da00cb04dbaa2c3e9ea9cb7315022fe5bb03025fc85e4b853e5fd49f7ae0f83f83addf427630dafd03c5ab391734f255510e166c3adec2325989a51810d715e031979de12e289ec574c04536aa56cac1a1bbab7de94b918738cf103b427c5751e95da33b2a760d41148c411674cf6a0542954a44307ebd4bdc65a653af4f80165e60df92850dec7a84588959b929f99fc9432ea48df5a593fce625d3e2ef433243ece4230cc3d015d578b41f183e8d07f1e999aa09e8beaf6827df7cd003e430b11a8a89b2097b84662b77b1a24840537f1906c183a34f7e997689597db11e924fbe94c22e443fafcdf2050040fad4d9d8ff043643a136fadb908f8edede1bd265b7cfbd621eb9676d934917726cbad248a53a33caa5bcbede8cc2901136bcd575940e08b076b0ce328b516f9d496a21ec416c93249275e8db92d267eddf462c26b36caff620ec9ca86b48fdb624a6fa65c2b86b59345be98ef171ddc0927b6c6e009c42d0a32b06721b798e82b8ae916435f93fd95bcee28a8b64cbf8602d11f48bb5bf78f10e331701629ec2117bf278912667d8c628fbde47f0ded3068d6a5c4c575e7b581e920ab8341bd7c0d6c424059a490321185c70336757bdfe1df9c4ff85f4e2d9cc6dcd82c54375667da9f20bac3464386d65da88e5a709231f7115be4eec5059ae911adb158b5084448aa5fe3426e4a2e492af50ab050a146e7b89ded71c1d5938fe3fef170b84c08ddf2648905bd214df6dd94398980d2c6ef7ca0e8f35a3b4d2c78dd6b95fa31a7d9fabb35f215dfadcdef395905b1389aa782d163e49626fcbb8b8187ad981b3800d331f2a384198b98d4c6e095db5e76c31e0949667014c98efdc882d184551cc1af8f608d2c18aab8063491f0aa27206ddc796aa0891218c583e67588164e6ab23f3c18160c143ff67638d85bdfca873ea2b7a95262648cdb8a3b2cf64c0db22fb8c848d455c6f575d2e9af63795b44b10eb773e293757b14c4ed552517f9baacfe780932df19c18251201ef67d5a56666e4fe7e06c3d622fcf2c6331fbbe5790353ad622191c3145436e43e8b33b8c45c09db93f80b77b23ec31f25f6148c466f41e4d270b04d4c0beba7f6a7788f79c9e7f1b4ebcb06634dbdb20ca283ca8a8596b28053e56bdd4723943562e542c2c88d73689e50b096d78c74f04390e3eb10f54097a91ec29928a9207902b73b037408594195ae0b9658f3cac217002e5ab71e5b448a32175e4cd164e355f11ccd26441964dbc3db7eccfb27bbb65679789a10ec109edbc60a2e8793c842d7b0c0a2219ec550c8d9d04381a431a41e1d4e5c7f9f9f192be4b2f188a223bf0f9f109396eaf57f0c55a5e063b34114cc9df22d8ae2ddb49e0c360079a10bcbe59624c96bb6202a50bf6428c4363d516ca8b33e750614ca58e1bb72717060220fa2d2cf3a2d4e72de9173a9eab61f8f464a1e56edc1e1d0280a2f7594edd1abe3c6ee2c8ed41938d4feb4d50574d49b1168e2bff7d74d76e790016faba103c30900278d58d5ec2327bd980dca03c7211585f13d78f06df3a7f54beac95a8fed34d49db5a080ef5d4242236ef2208d0fa9e731b29c10e500972d776aa751db54ed50a79e232b253bc4652656eb74386e08c5931e016adbb3d46d735d1172eeec6ce23b15a4de1c318861f5621cefd514f798118b52766f7245f93bf269f7a6eb501837f38134c470a4fc591c54d0fcaad7984f767351bafcf222cc1916d1dec2bfa0f188b2e62586309ee71268d6e4a2c8307f44485419bd5e3e36a4737425d4ffa2078ec0366bc60bfa4e0d5179b05de949651af3ff17f593a07442d2f407353f0dea9154f620deb7927b5854cacb40566bf67c592d5896012f2b8395ee4cee2f65a723ed0c776a90c2c24ca457be678511ec67cd7a19410112c472848eac9d020e5bf6c0d88b2606806722dafcb323325703efb9b44ce6045132c3a5cf93b355d1d4762dd8cfb590df85e192b8d675d8e54b99446e915ab480321634036277003cbe49fe2606f5366955787a23ab085a59306b1f3d3aff61b5ea80a2095ba25936e8b6822253b0155ae797262ebbbf49253568035cf625925c07087d8494088f983d8a3b5ce31749d8e42ea0a01b4892c48a6224a17904ca21798c4ccb9f12b3cc39b9d8f756701c0d66aba6c60043a012b81f6bfe850ed993211a5df900b6a8f473d762b778680b7a049ff91ab97d520cf4924d5b01d6bb42c4466d4d2c63725f83ade648f3bea9aab74f96b58812ba31876f8d054f32d07ceb63c4127955087ed1b53b5f6b4d753d274d1790d3795b994a860002f97f369ce6042a8c434111caf0ec191b8b171e505abe32883419ca136ed99d77e3429cab897d5b2a46f77dddcf15e81e4c292fb8130e094a1b13158b4d315fac1cb56784f8bfa8cc4bac21793adfeaf43e3b72f3b458d8d81066fd9d636d490f4b733ef160cadc8d890592727e5fa6a393977b0c57696511bcb776ebd7f976f322db442186ce6fdded6097697a686535d09cd98c0f6a95f6885d761fc7f1f105d377f85584261f750591f1f94249139367836d1387dd25ec235c1d700ecfe4fadf44e911faf1df6bc5e12eae2961050a609f99fa4c3f66239bb980a2a492b5a64eae164324b5d7761b49aea69c8adb37d832e7032d0a041d402201e718e29fbfe3eb633185995e1e848da250b7686500c132733b40c41605077dece7c5fcebf10c1b83976f9dc912cba624a08b64cecf20df211a3490bed2f093edde5fc6d7e4957d9c74f09dc88626a6136bc3cc55f607909a1e9c5af38d4d9ef16ed6d92e2600ee55d130872db418fcbbe23a8d37bd4bac0e688f2d669858b4f5c258a5af97b26e5440b13f7ce517a9eedb4d6ad897403979644596a1d306f02a277e1c9c76d89e9353c1d7045ab90ab6197a0647a433a6c21218795b57bd0d2427962d057c1b013c2b03772ed100242fe40818444c4398293ffd87422fa2c9f83548d9169e9e7b578569a05c89b245e22f59f4c55758e942fee57c42db33d874993d496263fdd146162674343e5852e65136b23b98a46ab0c7a907e3c8d175e76fadf384bc60993bdd784fe919f585f6d105c39b299b80f39cf4a4b44decc421371c1db23d7cc5ba70043f73b4501a47e6e43e9cdd6853c182e69d57b657a370a80ce30ec4d81dba877bf005bade09d84f4e4ce24c3d47d180b4a1551b4eadab3ca8c0bcd111501c5ef9ffceb915adf368f364c0f4abc48e0e32325eda3e139b904a2b01293a88c8bf8da8b50b2bfe4da64433c66b50a7ba47d56882b81ebb733b8a4aa5d16ae8de623485ada78d5c87b2e001c783b8b84cb4b0c2b8964e985f04e0218c4e8da8fd5576ad25735fe70371e065101982f061e9197b75a5fb87bcf7871479166c1eb420f96985aec42e9f56c01acb10d7c091a188caaa7758449fef068c420ab9fa7299618899fc4d3a0dcd00b8d7537f400839e8e28408d55f9a99fe6d0050a5de6dcba337544c108e2ae71e883e3aee780b812f88edddf472073c377c5452969952a537e5de6372da1c2689c18fe038a472ab5e742ad61c7d4606b30d98d7ed0843d7ad4690f489d901fc333a893a3e8fa676dfb51494a94665d6e2f3f213b8c04f516704a216dd47c6cf2162085dacf9c06376fe60f9e688d35e4c97c8d20386185cc48f556f1cd395c7f3a492cc2e136959a4f05cb0be84708ac56e1aba75129f1456d874b74f1788db8c8d1da72183a5b24519d0264eb7a8ea863d96b2603c76e592c25a71cc0d22b7d0c142d047a867e43d4fe21b39216dd2a2d4ca4c8cba9f5a6bffb1799bcfbe3e6e5e41dab005d285e6a744d39e0425250b4528244b80eda2ddc4d2686dcdf4120d9027b14bb70ea2e03c32a68d71cb586feb421fb806ff089b90a9eb5a809b96ad9aa8ece3166c7f415c2dad714fa14c6f344155b567ebfeba835b82bbb06578a17959ec13189e44807354fd6eac811dc674ac748c28b3b6b20eec3a97d42d948f8456814512f440eb16344d79c5dacc02f9e5859afe90e051e8cfaca03218c6695845968181991f5869fd9d57fe7ecd53f5cb2c7141dd5ce9d9646954306d07efea29fce502535de8953d5ed681b1872241eb7589ca5c79f0d42ceb08794c56b7ddb869f75fcc8a28245ce3198d4875b4739b02ad28384c65b8c2740e43914d591d6eb064ce622f95feb007592082472c02a5b44ac2da580f5a4ca73485803f4e814ce40b65b71586231de1829694535980c02ba85566b9e54bfc34a81277f0bbef96e4df60546382f8a1dad379549136133da853646684e36bd9993cb6692668313700ebdedd683a65babf356e9436bcc67e513221dcafe34a092d113bb55223644eca266129da8990c3140bae2af9f6a452e28b04298d988139225646683112c64be939c2f7e5335eb328e265744103723aa3f30c0c4e1e1c929a6c96290177cd4e06d2b44a671c0d8b45357cd1134d57d81acd39bd0ebf62f3765038bf621448d10b0bdbd858b1073cab64a6c1bf7c39ed10ec1ad36c946bb09c71a66fae7a9fb5a013aa2f45e4c18d3a3e76d9ca9c381eac3325ec67f2eaadff6c01ce2fc0ee08744a34d447fd0a52467a8382d2ec745f8bc75cc57ccf53196000aa4f6da565cd8faa726d0f6dee6264bbe46400bdfd2f6ec23f1972ecdafe860d76f397bd135d3a74349767d5d7155dba54c409c15e6e3c71212225a1b0f2039acbaf8883a7d6bc0e09903a2b2bf518ea391e897e4426c454dc570946fa7440bb3ccb62e9225eed0ba25b35508f137627d46114fe3afb1091d85f7e5c1a2d50ea3d4993aeaeee101d7289e74b8b40716756b27ae4c9aa5e3519d059e303878a9cf7054222af30afdbe743ad99f53058152c24586b06133f836c6e16c0cadcb9ef41fe50ad84f7829f216e08a0aa25a3828c992d92da3c72a1eac348f9a136935711fc83913dbef91e4121f4037749868819045d4c97e9c8df1b348e8ad724dc0f160f7e9ac50b7546b45fe6d72cd91b88b1180b80e7e87b261c17cb4c3fd172dbf078f71cf1cd60114342dae02810f2c390f9cb920451438b811c93b68fb0d8dc2878833930d27172ab53ed1f6176e1bb20513727b5ae557f3adc57edf1b7800238aa988699de524570809d18397ba7ce4b30944a91490846d550d0ae8a762cdce2df65f7915191bd2f275245026867150a18a51223585513afafcf13481921fb3f61dddc35b4e5454d6d11762f2306e4c7e0838f05542207a1254bba376137115c24bb7a4399ee50e2f7dcc668fb888ae82f37e2d594ed567387abdaf284d7ae0e4e1c56fd75d8f5b24eadd3a94f107b02f02d37c226f679348cf3d3c0d7a42491d21d3f98171e75e0c208a47ab4b4a32050c3317757a4cca29fd0d8c7c672e94eb02c85696f8d985d79c8b21f624c31febab3153aabe275b1729248435e6438b9f7a8e2e424d5754d69b44fc73afa6b1d23a7f19617c1b5a7130a902a267740a5f7e5da973969ca48afa4516e34ce2e1ad9b4f52a6ef197030bf27663a34d673fa6ced37fc82a044af5f214149c2dcf99b10834866512b16db42ea2f93ed44376f88b0844583791ca04057545e66cbad13d2384b5ee738c47546b64c9c765ac6cbb626e52401da95f315a172a284a8e4eca5aaab700d9fbe90101144068ca09940837a1a5ab9f3f494801776bf5a9750230c98be899d98b6d8587f7e5e2915a161287170c9689b7da15d99a01a9a3eee6422deaefdc265cd65504531114fd30d800225efd3311195d0975b448cbf4928931ff70f1fc1fbfffb33f8937e2c85c0a241868329d434182959e123b420dc5004580d120fcd3c8eda29a1e98ce03e780881d06124c559fe0ba64058d82ebb831732dca707e54ee41bedf0d2f02823877d015d998818a3a63cc845f6afc6c82023ed95d8b90925c6f7a18edd906da0a5cab62c85ae9c04c209225948b3c4bcc5c53ebbd872fb3bf281e5b00721f9dd2344f0c0b5a344f0916d02e4ed0ce40a38e6af79f156083b35e1116223d5eadc98ccc9b3816b88257e6187a0372709f26f9f2256fe744b7a49885e41b434e0264b441aa1a98f0e4d915d89856d1af9179298a7654851da3b642d9cc4131c9a52efba9e1683e772a793e4d2edea95b20eeb2883d212fa42b4795be85e1580f71ee2eff8458e3ff2a1b49fcc1a0b4da76e04ea6ca9b90507104d5bcbcf62318b2877c62c24cc11eda5c1dc9c1179412a4054b4f2028193a67096d2095256e9589791fbe1edd128ecb805beb82a37639c6b0c243b351f93b0fb0a892061eeaace2fc0256c84ef0032e3a8951d27d1550897b07a21f5e2ed31e671fa198c76d5bf12ce1ff6f109c79cc48f8015af107f77f2b862a9a3a12e48e4a6b4bcb74968be534688958bf6cbf2f694aba2c0e50068d2dbc9978acaf21e33c2534a48ed044735b1a57fb75a2abc68a317f0beb8e799e3aecccc5198f7b39cfc1f330c66583ffa7c3f66122d40c11cdbe53818a97856daa051e6e2b03d221f9fec210822bc8705fe26e20c0433a41ea1082d8dcd79e0adb1b623c78257aeeb6c79abdfa428b436ed940c64f0e40ce61e20dcf14895f1c0cdd80a7ee22a09d3fa91316219b1ac3725c7559b18873be6c730d65e7e2ac1c2ea6c228920531adcd85e66daa411384fc76f780ed06837b331607c8d0d1e18d6363e6e5075eeba2212e985b6af168ecd439794c183d38cfa6b4142e04a877886f80a578642a1a55ee1573d5ffd61d682ab2cc57dbfeb234915dcd13bd5ed6a2d50a8022a2eabfb118135086a627c27016b1ca17475ec31fab5c73188e67bd9c1b540984bd4a70e46a62917a4500f0b5d058c995c74d5ff2676f897d837e0cfc11fa8a408061feac5a8724dce74cc41c91eab62a48e2be25195d66a7f841ab135a56a5bc9e64ce161c3c156cd9bf707055bde6cb889c28afab349a93832303c08b6f82b7a7572d80a0c0efb6edf9123a3c5a9513b53b13eebc8bfa5da07b2a5a72f7391849e472820bae446d0808d5bbe4613d4d8b1c98adc4e6206d90840ee460170a9cd28ebf41cc126b54227adda5dd26adba8fd874dde316852a6f27d7441a2a3221fe46ebd5f780f21d77abe0916a086e4968c964efa937f2f2486e014c3094dfaf186054babc7864af938623ed3c0be3602dd20e37b11bf5ec588c1e1e82707d9bdc922baab90d8ba78c96e0e45556a40425d639e3e4550ef3c0698e541046c47b85917b521ebc18c8398516c0da2ad35f0ffda6fb9abaf0b8b6f5ff2636e5b5086537a6f512a2137c5b209bb94f7b092102067e52426d02d87622c3a86d81fdcaa9b571fae25c5f50aa7f2111859b9bb6b200f838fe36486b935eaf20611f27381665a97afa43920ce3013b62f0160dbb52e64dc9bd31675567b4c8b97419fbcc1bbd80e342847de462911897583dc57898ddf4fe3f9d2fe6fb75187b1021ac35c2c10e4dcb3a5cc2b15911e1812b921d79b3e9d1f39d5833c9de929d0d06ac6c9b71bb0caea6ba90cec9f5b3977d83fcd0412289c800703161cf40b7c89740f7fe1f03e226d97a30474f851d402a88cbad3e16de4079f22e0baef28003cd11a8a82b8f489fd9df0c9c713fbc348202e48f3e24bfd4e8094701159a97f35d378c4f926f535a11c251c7372b0bc6b527fded5c4f3de11d6a120bc44f0525858d99ee036aa3062ef140ab6355000098c37c14e167713f485c28ed1be2e35df98fccc84805f15b74c262beb35c9c148656086a540e2b027f491b6e08ba409b070ca0386940c1cace44f2b4e4a81e4d38b404506adc094402b6beb329c24e578844e0b0913398bfa3741f64e371abf3bc30b737e6cdf1da88eae298f859b5d5937d55cd680bda55811f9f24731b4997168de5e896c1dc83032712044ce90294a54a5d703d40ba73523021214e29292fe4217c53ef313c286c0861ad0b424b76606c183cbfb0af1cfe945b0d117e58ad30bde837887171dd11801ec082574f8331e29ca3bd752582cf4e6559644af3808580304f0c2fd5343b69c9807705fc98db600d52c9cee43af5de176495ac7ee9abb7886f31a1ec5ee60321c4096bd7fa513d82d4de573ad6d91fb1dc8a57ca4d24509d20997618879a585f0a06ee639ca66ffa8a78e5fabed09cfc2042f5ab71e2960df79936d1346a4a1631ce44993bcc6fb53bd2efd5770853b081dfa6944879d822abc8984a6bf1d8b4b190663a001dfbb4dbd2379ec5c21a0b1309713c0a63ce8e0db91079c46525d0f27434e3be2dd52b9dbac8d9dbc5a0dd613d5a3fbf8bd279679fb019ba519fc7704766bc44d997eb98efce58bf02a2481eb83ddd23259b14a9a92bcfa0af23e4739264df77238e2c25a0a26c3fb564b2a6aafdbb514917559c7376c07c62c5aa3da013b9a001b7f19b0db3e6d8fc0727cfcd26be6929f721f204e40dbddfa2ffa45797b08f870f6a3f0ca2738507d98be8a80c2ffe0b8a07cfd80dabbb48b9b9ff9b7eb8ef113973307e8e2c5a50f261097d54c0e435f6418148c733281cc31bfc9ea53484ead400d4462927cc812c5bf2aa664bee315ee6b409900cc7e71baa640079768b7aeed6f41f22efed0792493dba054f7e43088ee9332c1887af7d4e2f5edb9511294f70c4a1f4ff82e3b5fdd0bb3666d92fb93b65590c7b068cfa378dfe5e653f8be329e0f86d60775bbe4fb665c6a20be4d0c995f0e1fa060d1328802fb0846baaaa88fc736bc6d73986c94f9234ec521ddf2fd9fc32aa851b38adcb575cca8b61bede1e81bc531ef2f194972bd712e8a3b807bda5175799b2f9693261316525a824f99b7b0bb95483213ad8c153ed0da04c353399c26f23cf90aaa2c0da4db07c1272c4db047acb8e39636a9dc0d61e5d2bb3b4ce8321146e823a6692c3609fc0b23ad060024c7c8301d99a05f7c418fd2202aeb1724ad969fa5ac66761b1a4e0dc0bdca8d5133f2a5275c4f6fa6362f428a18149a8e551fd49a90263665d82c88363c201e451f79906f5047ecdd1409f959c288f19a5170cd15a8265ae0e43a8c27f52811da31f5a4292ae01acb9e990e333976597e3324061ae3c258069a8bc1696b102014b27dc607222621c7c2c37d3a0185c555903dfcd69c12cf7768ca6643a59887417ff0cd9bf90fe8d3cdf14ae074e56cec4eabc51e723c51a35008124d0a4234a4240003701b3ea2d9639847f2b468a3324650f5a537071f70f05c3ade0bb071beb12c6cb7ca73b24bf4d5e6f4910a8225e62eafe155730cede643cd362247d42b5a200e23f7b6fe46492f911b01f910c05456c0b210c0e697e4a4ad432094599e1268a7088cc5ba9a6ef48b039e418ae512d86e96e86e7e50608d3bda774984e2faa22e2703fb2d1991c2a48c4da7b80dc28d722d83c3369a57ebd8a96c5d88deb65e40812872d43cdbc2707d0f70c67063f06c878010e11b7bb58f863cf545b81818dcb14d6171edb7e4a2f48ebc81d9d1113d95ac78be7aa964b53b0630e680307c42bc2c1fefe16b8e0e748685d9719368dd1b7ae53774e14bc11cb22e6152ceff88ec343e56462344d79785e60bad0a081ff058caac14814e8596b977c7f924260b502170e58d0a3c387b50861e4c615735f69da69301e48159cc60fb238ee2b378e51c2537781bc32d492a0f57aed8e12f296e20da5a001e9094b0e312dec8d0bcba0a60a0efe6044ad3a94553266559d86c1a3a8e4b451fc065aa24995ae40c5ee381ed82a580d983d865d83b9997bdd02c570f0a9879d1158ec059c0010569831e78eb3c482a77f2c1c8fcf227f0d7128a0ac460fa1c634e4e1d84cea337ae915392ca23d252d320cb611511d0c9febd06795c54e744f2c00227959a67029f340f8e8bc51837478f2c4aa5503a03774e03926419530cc3c372fb8249a7a2e5370b22cef2110712c2ba151dd6279a91a8386cbb435bd9392f22c508304b79fc0ee10b5497b4a28594bb697f01c4caedb62fc3f3be271b1c092dab0a4b8a3d9ef890bae7284a0a562b115c5ae8d86bb508878059ab170ac245ac291c1406a79c1edc7d233d20298fba9837868a42848540f6ebd8a06b04a1e91b07f4900a619d8012c4d1145edad88f1c07d49214dc5b75b516aff81fb237d2849890b5b3a711bc7c661e9635d44cb550ea8b883289ae737bcdc871e76dce438d2c415080d4eb8841c9ea3d72ba0d5a493f81574e256bffa7ae6848ac0e75aa0e0248ff4a28af4b49396290600a29a8dc88f4f47ebe2cfe06a2e2049a02f4e45dc4bb1801dc005347cb83ee469e32bd301f2144978a5a9018a0b6494e7cb6bc4918437cc82fdbde1139989cf7856ffa11e400901b009f45d150d020f5e74c15a2fd1a4f830e650225c31604b74afe17d662a568173590ba710edf45edd4769a5f42a709901a0d9132789c77a19069ae3f5e19aa37ab47cb5ee3a3047a6c36059a88e5012621737dd004639218ebb134c45bcf09da211e6dd592972bf3f44894be9ce4607014e4536dfb343898762436cc712947905cd7e8e725151bad273cc7e134bb53544855bd903e19b4e200cfbe4527594d5733937b02e171e311b2e2cdb5bc0989af370095f9cd03221dd0bbbc9933ac862f377dda023ebbe4d1e940875814da93074d84437018cad2abc1a484a26a187d5c126c2fdfe460b46c89976b02857e086aea2e61fba5eed0e4c4c0f1e843524aad3723f5d55180701bb94b87229e9753fee6d56b03e8966697e69b605b941574ecf0a733941d86861c16cf935a2a514f88ef40a870088789e811a43462a81e5c85208021086f6ca5fda9837051ecf0a337cb68ea3c136762b654279c8c54e590041f968e371b802038e36d8c5df3570141671b5cfeadbaffd7fb269b428db56d31174064b119508b971e7917ce6fb5497195a05ce5ac8975bdc266732b280638fe83968a65c7e88e62e97e0a9a17fa728824ca35084c55d88da80d7872caa71d091774707b2a8d3e93a2292db0151f5734402f0008db4a08b7c2d8be43859c006a62f0e7fb6537f6ac8fc43d09b88f122d7c5432d06460b30c2001e340fbb4a0f323c02b8b412a447181a116844e1e24e11887971cfba6638ed6d1bb13062e85f8623e6f6936415eea6fd264d9a8e3551712ef325d48560567a96c6ffe962d00f5a059d7bf33da7fe2279eeebde8433b00ad5f810d7fb625e6b8ff205ecc732434406f51a5b86a62a33b3c35a974df0d0e128f47e5d49c0d2b856718bc9a30451d148c5f51e77425fd6a1c37b0d797cd6cc029a8ddedc020518f7c2c102a34a8b416dd85aa7bfeeea400ec3eb47405c0d611547925780f6a67cf6ec26464b70d8927a20d1078cdc01909d1be1d52a77707355b61ade20b1177861d8ccd01c435d3910b85906c78e6879c02288d5921ee560d7906f18223ac797160110207082dbf5ba5faa0203332d3eac7534ef46162a25742a440b13a882838b091e2ef1eaa0ec1c6286eb15f18c57b346dcb058d93a085ca04d7b24460d148395efeb08993bb5a67c800752d4f2067a00798f67453a921e5672101ac6f0b3dcc15e6cbd97f3dbfefbe76e5e2768d2272ce7782ed67188bb5158f769771b323e4fe838e566a508e3f8bdc84d1475b449da6266a665c098e195ed38c7d54408c954e59b78ae1c0f2528d779380f6a502cac503f89c02f5d1f46a8c56867e5526b0e604dbc1a2195c980d61831ff9831b8647e20130c5f3c900259e15d1da5695fc89aa2a0b1f3302c3adb87f068f868465af72d2c264a28dea23538cbfdacae66038d525c9e6f5b4b1dcae87ae93635308431adb0f887b8494c650b89f5b33d25ce5f5604dcd87cfc4448ec077ce6a152d0c954489c8be4909575b0052fd516c5305cdd9e01d9294878a4e01ed1cc185dcd43f318c79cbce8d09f47e57e1da7fb1741035de0dd0e2f4fe8dcc184da5b4977dcb84f94bf6e3c5c1ad2850e413d075c1f59b376cb0bf9c3ba1aad0fb4870945c70a4f376f67e24b04a640d0c4504fe5f13a292a32e54df1e396046768c641766cd5bff9ba508fec52e54ae1b05a46090004a69995b01d1a754d3c2e4a5b686f413b5a92e2b62130f37f1dff12d29e9861366a1d379a08bcafe3b7665457c56508e642bce2c202256dcf200cd7488f3348fddfd88529b0ab754fa9dc12a5b545355fbfbc65dd206635f5f44009a1a6a4bfb99b0d5990f33dd67207c2f14b220012cebec72616ae02f60420ca6a6b861e9613d4413977f618590e4f5849a82a09657ecb51477076b1826a6861c21755b9e25111417c13aff1d109f3611102f514487b92700d19115c9d0a24593dea658c53a061cdebcc2f93445565d83a1eb2d8fb8e5a300a98af15b30618237416ea8f41902f6f9b496d31e8d6c24cd8f5e9e305e0141dba80c835802e8fd4a86ce0517b2b90ead1103ddf455a75e664aa3c13046eb53eae20d1f0ec2171e531245e571c25da123dc77e1b06063bc2d890c870fb227839556505a418331498820de7f84d0a7eadfc689f63095fcd0a9b96d80e20a96e04d79f109f59daa0dc831b4f31667a84feca68d2c9bcd0ec2df902f0232e05dfd8f80668f0d8863105171586d83e878d3ae9e87562e2e0be0df4a7540bb1f62d22b28975dcb143384c9ffb7051a7377fa848816a1a6165216f299ac9f0eb3c13379a9a65a37c29a08f7b5ca60e703388040ab2e0f9f9edecac72f4450fa95024c13532a6b7679e1444e62fff8a9f4382d198aa1c0e4e7d0913fd01dcaaeacec8411fe98e9772d2690ea211e8733b68e596295fe0bd30851e067f3d5df139d10e04f95182923dbc7a04d6c17de6a5f6c18103cb4ba19d0a5262f85faba3e9aca6cb5fd9b4d3ffb29ab2b45afad0a6d0124b57629d0c0b1e2b71e859fe745e9254dc898a282beed28c409adc68705812561e10ff93b62177f3a71620b2aebec38c32ef21cc0a76591b5d1a22674d002a87203ea46e237119404ed6ce8ae1b39b961bb33f6eea42d498ace063f1a1f2bc32a123d865c1ba36d0234e472b9a5f7bc7d37d40cd10b08742de7d0923ddad89ea3a503b838009acc9561881044293aae5cbbd4a19190f23c064e97eed720669da61f7c0752ac2a2cc7886e6ab17453299409a888059330ee742b6322734b89791f550bb40bb6cd9998ad51508bf2f47e660dc2b3f922d45e58b98c0528ede4515d416b711c7f4a12d30532aab07aed285075441aca0b029060f93b363fdd34e704ff392c5d88ebbdd9c93f34a06842252d65b63b1ec5ae10c3b6d76c35bd25596fe83515d2423c979cb01c199d2c657ffa60acd52b6dbbb5b5cd6a560155c79efee534d6b158c0a41811e292878cb2f01e257b200730a05c943054e2ae1726ab063ea6780f3838782f41d8cae302566cfe669a47ee88af71320e551e06332a6bd73038e08f24f55b0a01425b1a2ef917f3217846ef50b2dfc6ebfbd9f105c66568c5e5c7551da47065e5d659cd92415b739257a668c958701491ec3bb4266a9061dfbe8be448852f25d525debec0316cba2cb325d1fe09dadcbed33122953fed9b0fed4bf6319f810f45f6b1f58a5ab2dee38b6e777161af5b8ea60008d75154d7d7354ecbbb6b7d4de39877797def1affd8b7ed4d9f0fbf43e43c7bfb116b76ac33932fc27d4107fbc987e42fb8597d8c4bf8cb26af6418f2102cb245a9792760bbdecab359e43905034e646a4affada4f844e4536d3c411e9623ab415aee61f215922b004d98c18e71b74ec2cd92d58433287efbb9700ad523cf24aece6b30d8965c4aef6cc41972859d0be6473f5ed05f476295ee252b5ce5fceb6c932d3e2bf695ba16716b8507a87db37545359747b77426a969d7f10f2ca4d06fbc73bd752949be25b6a56f1829087827b2d715ae272b90d5bc20adf6475fe1aaec9cd74790df01e540f8fd3e93ed9441a09eaeb52c73dff7b71b3849b84ff893a0391c9f0085702b11f16aaba8ff0e3604fb50835b140af2a742b352179c89bfc0d4e013a98bc0d816f7d9c93f37b40b68d3b12835b3d1a759f50c8fece6258b5b11e2bf0bd0f9cf160c5d162b51755ee79d26218120c03909aee1633c3757a3eb91cb3a401a387ff8b24c18f6d31f6c92abff1b7969bbc4ad2d5b7d45c2cea1cfa1e622935c00539f6475204b12173b017887401e4be0ae67061c874d90b05495e68ea178adfcd1328ff7c08f01d61e4c389f1efbb1b462ff8e205bfe74f3c75362fdb5626e9f389455ae4caf39b00088fed13b1c3d43644eeb04f070d57e6b620a6c7cfebb6016c0897f4bd7568dc50cf105fbc9311391ed6bc3f9a93467a151c353986e030228e5d69068b9111dec876a91f4afc5c1c13ad3b90537f38bd235e915eb0b85168199f58b4c6474504bc562771f0833b41a632658b5bee28f371ca848f1636b73fd8dbe0fa1bcd66814b7843ed042d6743ebdd707dcdcd39bcb330774a616614f698a01f2617d236e2c8891d4860373f1917d3d4de40dbaa2076d69394033d8dfdb6caf37d1f53a030955cec1be6fc131cbe153cae0df6cc8646e5cf289d96c4e7f07bf035d10702e39742cb724f55299ab3509009c42934188929030682a837e984135e84bb8b08a481a948e63016477d93a377adc2a804cb3278fac40387bd6677205f9b3221b2ae8cbbd43ea3965b58c78be4f09c71ebaffc76e524aff609021074ef9b09a274b7ba62d601d05a50c31869fb23315d6c5d195aeee1171e15d20454eb4da390970222290fe81b0c9c795ab15a48da09ec80edf7067dcd1e488677b3546db280fac43a7d1cf00af8e7ba02538e711329d1623d925bff89b63829990a1e878c38994d687d46700e2417f18d087ea7ea9698c432e3101b16a0a4377a356ff10838e9c358a38ffae21e36865b199a215b9b2332bd7c920603e27367724c6c2df1292a9b13160282cfdda2518838b1098ab036b4f3b0b1a2fedb939fb6f3e4e5f01317da779f0e780538334fca2ea1bac5821f8385ec1f2ec32b19140c1c6b02860fdde082e5e446c2c08060bda3223c2e8b8d5d2648744dc435d2287c97e31d4ecc088fc2ce16bf4c05a8acd1d59071494793b80ee41d44432de6b8480b664df153a8020e6c140d182561b8dff0edae34acd750c18336bf9edbabff981c2ab4ef9b67d6e16ec5975b93575221e1a8054c811da5dda424dcb9a37c873d6d48c7b3c885fb395892390fb84e3a38fa142fe24f0ac0d434ab14c25072d2de9cad4943718fe1b228592bdd69964c789abf7390c69c1842ae08ec325b6422017d5d23bc69484b70815219f3077b966253dcf87cb17250b4ef00c621b25e1f5cd123c30f04a99516a831e3ade53cb3f224cefcb900d5207e26797d4a44844451c0d9b067485f68ac6fcc03db623dc99bd6395cde143f0d2a3744eeb1597435ff1ad5bd2b50e8a5ed591b170b35415414ce271129aabfe8fa9558876ee508f92e94eabcd2d755986d5793dbe36ef83b1117a7264cc4d741aa6135894c5f5cf751d4965fd55e3b2e17060d33f45a91583d9f08278e4adb71e0e26e864e4e079a064d3583d96871cb60053f611c0284eea9bbaae7202df7cb3bb10e8565aa827c05b307209c890f73dcb4ea156dce923d578fa16fd5db779597454264772701fe9e9f858758750102f7da75791a8a1294e206e0658efd6c26e8965652d4892b7514c70ac83f0b998d7024ea34d515ab93f85c82ee17e43d01f5b7c48cb13b687d1ca54b1640141200800a2f56911a8b8aa82853069ddaf66012cc3f6c1f8a340bff67ecccf45bfd6a9f031f6f37f87d6d963e7f2e93c557fd3f7b3b28f4a672c4ea00829584abfacc4efc1c1ff78574e5b02a8bf9ff229bf1e50bcdde0603e3cafdddb374f19a5dbf4cdc7ec994745951d71ef4f39946dedf04b483c4e8d9e39da357bfef40ee0914dafe5369b2ebef0cf18d4535cf0ee296ee3bfc6bbe9040f71cc361bb368b68e1f3b38a5d0f35b357d1f3e7a54792d9b1af5a84f94d3616e5b9c577d42072adf36e96d8ce1f56151f7845991e93cd2a5f023c42e254cad1be990a36396d0200a21116a7afbf10c308dcb202fe115a264f12084b31b32e1988e892556aa14b68c83d657cb9fd74d80fac6266c19b17aeccd579c48551421065f59f90b0eed6e51a8d381e3ebd2a5fac1e93edcc52ba959fe687dd0bf15a62d271691236bfa5614a2d4bd80a91900b91bce59b227ef8b8fbc2bb3c221b1c9d4afe1926d7fcb90a5193671d2c0bc7f0f9fade4a8c742d8e9a8252056f937a771d53cc75ae83824c404fdefb0dd6dd4ba93acb1c6fcce3b7e0770705d6cbf30c9cdd9a02a6158afa4d92043ac6a2b05dae97856fd0008e417d6345036829d8cd37be6322a20bca1cff5ae6fd08c525c8fda31a151fb1661080cdea5858a99f3a5e25552b194d025048441370bfd12bd187aea4f08d8d340512e61a7823723b48770c7fda02cd45101b1c276799180bc375a6910383f93b60e62789c3407e587322ff0258d8c25b5ca3800a59d5d61655c919dc3ec1d2cc3de6da90a483b23c0587dd8060f586c72d02525b67f6d3857eae8e80ff881660026376734314003ea52e3a3654ea6b3c8b0877266d6239421926fbd2d53dd87ab40df0c19e466c623534acfcdd593eb5f72af43b400712ab7799aadb6f6da7e95c97310aa43d9451097f077dd6cb601b6a4724410864696511d90ae181b71b23af5bb7a2d0129da6d43ab643a93748c6768b5f5e91128106a363e5e020342a7661e8455dacf528d5b876b59a711597cd26110a0175b8daecfc4c646b395342debe32b4028e4567b4d7533b4a5bd22a7eb48187b1257b53e49356e85058dbe0f02a1d4fd1508319bf588ad3e4bc77a04565a3e27353784a3469f0752ed1bc76b49bae667e9d6edc955c53ddca6e9bae21e56dd0f4128f38ce76875ebe3238044eb5668d0e0f730a5b9e1bc2ea5d57e226dba3dbbaedd866cb4ae57aec32633d5fd150cb1ddb84aa5b77d4a686f0a071abf1ea6b5b74e579274ed0fcf408150d359f55be735298df6b3274069c3edd1752e7d732bad8f8f808110b3d94fe1aae62789d6edc95522bdede3293020746ab6eef674ad7219d6738b9e31a7cfe01564f314eda535a6bd02c2d161d4a8d18df93344becfbec845f89fd4a3acb91f32e5f7ebdc5e2709f29f0cadf0bc7dfc0759f5707a7bf03fd90a0cd1dfdef8db5bcfff255bd090fee84dd827c9da6ed737f704e010c4e42ec41f7b77e82f320b1ea2d33fc92a70487f7ba7fff4be1f8028cdbe30b103431fbaa0ab7fbd88c6004fb9fd4af5e0c1be917cc85d73fc4163f909542ba244883507167566c96021699e0754e8d9fc0f5edac2c2d4046b4a192a2681e1430b18d11d2454965df7dbebe52e9c90fa5e0de7efa61f5576fc316a36a17166d84f674080348781eae1d840772156751734d28d90cfd8bdc2cc791f874dfd7afcb572f7bfa39b94fefa9aacbeb2e6d8b11fed667f56b07329463e306c5efff263ac4fe08deb47c963970032bb1160c1d422119b9ad2497ed8a37e040fb983ff5af2b1fb7f80bfabed6dc251e13015dd984f99769bbaed1ec83c941d7e880834c29eee585be12f8bab6978e8f5ee0ea216f27e9daff5079901da399756d327c192f6a48365d869880322e18c572370fe3a0f724bf22fb7abc157fefada15473cf55fca1653a56a0464150784821d6fba4b0b0cad77b38815423bde72eaa24b5eb38a67eb1549061309d134405e7b9fd1d8a27af697beebc6dd580c624a21d7acc42a5624a22ce972f16a4a7c9c401b73501a611e07f285f42747c157ae801b8a2de289924794f86779ce4725a62d91aead5948dccbdd752219682119b45bba2d0c6854b04919639c40074ab1907f894662c258b4c6268f2ce49acc42c9cd23a5c674591dcb8bf0476481d205f8dcc8e8d0f3c89f0c2b5fd1619be27f8accff0745c3f9525a6865b10885b359a4d42f1ad2ad821a1a64818cd3109047398d50be4a96e37b6f5e9262853ee67371d1f8fbfa4e4d0ea4c31cfe6bc85dee47fc7439fa2b78ce2803172d9c5b5962665b162b28422cb943cf1b5b9e78b5baef3a517a9a7dfb372b6a7b8685c5ef8fbfbb21e8000d7be14c738ccb66a631ef7584aaaf4860d0740bfe0fc21dde115d4374e8d5da5d58e96d319179a91168d93c79f1d621bae6d1b792bd9f90812053ca4ed4a90502cc2536cb80008f171fddf736df8a7a62986899c8fd7cad17028b0ba10d08dab614602261ae2b98f31d3f4c47d68de2abc3eb6a4656437eca6b205bea11d53e8142ae95be95b3da8cd18ef76ddec7cb851b7622d506a87aee324bf452277d932e4b7f795e41d434ef7058459d3d0eb7ec64ee8d4954ea0c4ac23a448a20d5794dc2c380d9bb3cd28561104a0bffa92c15436b516a7d459e265472d9540c1c849657fea4b25db5f08d377f8b0a1dda891a8f582d5a585bac33aef7026b17b73e43d8e1f540d990ebb9fdaa4399a9aa65fd4b406bef88025aa7a191dd2554c88ab39a93b696307d3656fa01474cdaa63fa00e04ef19ca1d428e60e2daaafec19b7b505fef43dc6731a6c9e3b8bde6953f40b7678c6970b825e62efd77987ac940706b21f5bc8b4e69a19b717a4bfc659f88d2579cf97781dbb9134bb82dd5ff48752606c331234c1a71bf3adb953b59c563fc752e0fb1e3982f83d01845e654fca040e700e69b193ec82fe3e38eb87f456078e88d5390f0b20cdee94b3ec55c343ff114e57efe2fc35ef73a7d62848ff7dd405f6c6b769349df166b12aea1338054674c358903cf8d8b48bf737394b7f744544d2feac34c37e72c9f5a59bc2d557d23962623bc62fd3efb72b6140e3abf81fb865ca7368ed6d46a7a85f224ee5e9f6884aa0d9164302b3f80510360bf169168ec1a5d8b38bcf19e32d84fcea3be09d1bfc7d701b3fb9ed1d0fd27d9286928501bfca543ef61ed20a1d4bb7631c925b9ac320c5830d2cd81df5f8e8e0bedbcee622a6ffd305a70de82a53b876859b3abebc5c901de69fea666d7e609a0891b7ff40f467483b87bd967f0c6cdab30795e5d715d559c9fb8fd95b789651ab5318a1b92cdd0db88b63736c3f12e009631799c125d08ea60d12ea03e806a438a3557d2fecc8dd28524555f863638676a8df56ec46e602e7122d517ab4cc876155f1fd07a70f50f71cf09a230f5c8864f3f8cd2325a822734953e5bd85aa3ed48d4772516d543e691a7c759ffbbc39d0375e4972e4a8173d7edb990a66e54fc1212888ba79c1581d7bd47e255084917dbf56f8d26058f929534ffb48ac8c558bfa9a8b9db2722c52df3085e1ac2a87660af55c4d5685d8c849c8634ea0cffda4d91ee1674e2018cab89a554a6f8a7d974ecb45ac30513631651af6660f9f45c7b1919bdcbe29fe62980ea659c28e58ef0f6440d2a59b764c30901cbf4afa9d72b9ed69d275310f02fecc99548619ba50de5d1252ceae54035be7437774dbeb7799901171b54ad0d6540098b1667e450fff2ab2e125998ee843e44e9a6ccbaf69aa42a7108ca0ad3db02fd1ce0ee376ed3d0300b7fcb421f11af3330032b4d9a7f22415f3cfc5761776e880566d7ebb32956d0d9a33534d1c3e326b9faa744da12c1a491fcaa50fb5271250a65ea70eb7a5d67523797dc0ac05b7593602a46634c29781b6325e36949c508e8af3e76d84f534a897ab4ec3c124abaa0e367cdf1d06b97780efac5528e477e88ba1b87ff8cc8901babf44e0b19d6f2f0e551212d12a7c995638ed8f86457e555586b1d89ded3506731853815a27fe195ab9dd25788de93121aeed1eb4bf8172ee91990d8b7c9b3dcc48e6ae6456b68386e3c91761d6bd0d43371515b4134bd8a59886633ffac12576c5f3a09d7424de3ffbbbf4793efc90446aaf3684ce09a50e73430aab60a5e6b588c99da6fbe825c7c9ff45449df600b20bf77ee9d039497d61e2d8ab6ed6ba045828635d4907ec5c7f580701c3049b80284817bcca4506eb12cc7b54e97e483c21ebacd67e2ca1b565e119d49c6e84813ffe9da21faddc3c4099a151cbc04f76f22472703e6ec03f218c3e5722c66d3e0988b2f49108a13f32f5445de7e68b10373eba433ddda86816c6bf2acdd40bc07d9cc31f4fb93e4f2c4c0c41d57daaa55b40b8eda685bfa3be43ef755d875e4150870f48268eeffa84e9f725ac38360fe6c036d711cd0d67cbf85522a2c3788fa84d802e485ecf7b241858c48097f055432227d19ad9b1d8a0046ff16f668c50a9961e4d69fe24f2eb0f0d8a215c99e104c785c4f26970e14a788c8ae84f3b3cf111f016610b17805e6bfc7509dbe5111a3f69f7281235e1e91ec8acd47d273ceb0b05740cde61c2c8120f0f110808bd24ac59d11dc3821aca83849cbf868118bf0d7d3f98633f4a407cc4ed7a43d3ead57bdaff4eb2e5bfeb932fba6af2f7bdd0bd4c60deb887a738fcc0dca647b4959d1ec76ed97f1e0b72edd5a63924e0119a1e0bda7706e1122d0d72c3b7e0802876cfca8714a0dd5fde04bdc655a8b8a984e063bb256ea33c6caf8017a2d3b6193a868f6494b506c944c51740c6e1fbc69be9c859daf3f16d2584e374f35fe6b8521828f6023f939c68842198291ec47d82d13c9355a837cb49d75475a6af0c81b1bdeb81c42ddd4b186ccea18a89ee699bf8c0bf77c626501dadd9e59c4ed5aa4d9b03b8e89121bc67dd8dd84ba0f3c18014b75d6a7d5f0eb0981546063bceb4fce36e1d4a869a4d35e10d9cf3b03a7ffce7e8dd94c45f83688e1fe1a4f8f0b3712865e2ebf17064cdc3dec5709d3a1a1b2b2426f4846fe4c19e7791b9b3116a2cdc3cd84cafc528a3bdd167a63b372f9721a46aef15663c7e7615d6023ec6f3a368c1c24661a128d0fb5f5ef0a34fb7a68339d0ad5a78bd3a1fcf0561291ada4fd1269709e02076abe9eb848fffce711b73ddd557f01aab18e773dd45825174035165107bdaba788abae04bd3b2bd56fe1b4107deff3e2e1eea6bfbbfac25e1a277c02d4eaa3f9788a02750468e6b09a77083a6a047e7945c50f979a82f21c49b4c537359682549599251ce618b011554411cfb1b244d6980da2a69a45ef3d1c0a708003e96e4de7e4796bc52ab1ea4a2104a50955d5cb989469db0f2d83230a7024c2be5108e72a04fdeefeddf883ebd6abbd52f757d6d7f25e51b7bf181ed348a838d86c4a54d208a2944326018cbb01fa3b254459404c31930e92f708f42ca7254892a7b48a3d650cda9c609b016bd8103ecf350f35795247f6966aa65ff1929d68ec07e65df15ee9a609331e46676e78508e2bf29a6564abb910a462d88c01fb43d329d436d964efbda59432c9e20370049f04f603021aca40426d32bede257ec8f48ab60a81aa4157d2ccdd0d10cb4ceff566b5e6b9905716cad83dc0e0d21ad9839858a2bf436640a637cf6a0d93600bf996dbeb02ac4405742d234975e5402412c50464504480cc5a6b2d50ad592f7119888307d50e90fb8e186480ec430681206dc82fa0404005f88024401e12db5af08548ab2e0d13bae60908b556fd839229dfe8960a7c7001103ac0554bca21df9c3dafcec16bb797dd25d28a446b06b6edec1b570f6cb01561db85a264ebe11066b6b62052a135b97a259feab4d43c2500fec1ed5e85cc64ece02c6b00aaf7822ea2d60a921c3292946f690ae2fa976908fae1af59e2065204c1592e69e41bf8a0830efa0c04414b53d15e10ec85e400f2e74852d8735fb200638c31c618037170dbf75a7b814a24510014cc8081174a5a59df2f94958562c837bfcdca0ae2b6c13718d61e5435e811fdb7a1efa5ea1544b523093b8ec837f06df50ac2da0dd5a94e6bf7f42fcdda06e1738c3fecded841f7f97dd8bf8afdd6b63e0bafab9318804c6f05d885dc640d35087f4023e4a96e8bea3178aadb92915dc8f549be799341ac576f1200f9067ead20da0b05d666da4276a8d6acd76acd0a69c9e550adb5bbde0cb97a45412cd19f33fdc412fd3fd95620529f8c2485c9183e02a86660cba50c456c2e324f7568bc7ee8a90e0dd5d3f184f74563165169108d8038d3695175104559a64e3d3104aad72b8ba73d05b22003183ef5b61d54b7ee8d2558fcf55bab5bc763071b209ff644d7eb4ff5c1edd55adbc482f6f5c8ca245f5a85aaf20c8492db6fa05fcf17935c2298e905bfc51f13f4afd3a00dd7e96f28d17fc90bbe4978d0cafdb70bbec1bf8086d000742f19e47311155ffb915f4692aa640c1f416b0637f0bb56514abdec81d8b5efaed59a50967cabd5a8b5f65e8bb3d50bf16624297b9d00e2aca621f25497060a83270106d5da750e252e3b10870aa2faad59c1187b4c53d1df1ec473ab1848ba3456df34aae3f27a3a5692b41949aa5a37d1dfe51ef770a5b49a91a4aec7f01152d891a4c09a81e79e974b39c8a3217646926a135da29f66fa095d095d39096146bfa4f0252a84995013dc2b70184c82de0a21279e8cb434835e07fefab58d2ff83cd208ff256f69895c8b73a5dd80fedeea1863bf98620dbe1066d62a5fb71a84e2e4b6d6f6f5be77f6445f3fb982f06eb55ab93a7decb5d6ea4454441a7433dc5a9b0999c94f240a29c9ed336befe7e16bab9610bf21e857129156db7d868b16d2ebce84fd6df6f5ccd6d75ab5745a37bc445aa5f840d2e5caaa2b57c78b935c560a4ecef4c89a5241770296d41a158ebc11d3e58c1126a9ac5c162e86317cabdd2ed06d696eadc5350bb0a4990293142142c40319c4636a6510ac54e30585cb26c34c149d39c296d284174a2d28a6aeea6f6e53a273e46f6559eae810512acb058cd1a93107690e4ec69c11c2847861533170d812dc0d9382b3615c706594b892c2bc4018be5e589a7d61cd10bfccc890993ab2b9954b1232ee4165c303abb284bd345d1b52eeac031b9351c360e0c8b026187276883aaef7f585f565c65a7bf157d8979a6fe6799ef7816036c090c2300c65229810b01e198c0aac0a98979f9f9f9f9cc1bcc0d0808dc1d0a04183860a464adb86e9086b12755f3f92bea270412878aafb52c266cd1bdb13dc8604dc068f0fdc26076e03f5c2060449f925c3502e99626392e304cb41222748154521ded49299941997b032615c1efeb4441b95af1f5f510f546b12f8baf1851bfb1b18f65427078d9c3272ba7cfbac922410c3e8cc419a830b81ad6a8a4d08d5234629cf17374ecc4c098788e001cdd5e71b449f398b111b3e18dd8782e0504dd0af510f35eaa1c120d9c7212888839d7d08b3f73c030db924914762cba5ab0a98fc817cab0501790909faf1d5f38826623fbdb42bab6bd745064806441b946c6b926f05b8304010e95714ba2e23d6b69567344457ab37f26c9c2ffade888271f6edb55b7c5104dec8fb69916948445addaf83f5da10883626b97d66abb61f41a5add65a35bcf55aed07272c6a42d040c66b3d14eb060b55cee6d14d74535a67ae0d9493ba99727572907b01038f4a8e474e890c3b27d8f9e5ac9c2470b016c02a1255c74a8f330e948f25a7184e30e70372755e9c7abaebca19811c97ad3337766e39c99cb95c97b37339b293f8e4a29c5f7250289e3a6387c971a08d0b4d6294f92145eca90d1593932cd725b40e387dd4545184349533399aa74d2873684ecac6022f098a4e812125e5f4713a97b301b90cb9761246bfb8fa044aa795a8988db38d20c06a03a60db927670b66fa85b3079133b73586926918b4502f37627a085503e6dc71622585c8751634e700725761de50aede42d784625f504c60319090ece82221e754e46c3a676ec9d94072d4ca996b1c58ce3267063406addd99cb79d13bfd8467860a678e3e69ab14ec60da0585734c379d39386067aeb3c6ce386797e91044a95c600024272dcc7d9d09c869c9d19d9cce33078637540addd3317427fdd24b754c8f8c335752acb042a72e1b3bba8a9e51e3e53c72fe6893739c233820c849bb7214a4f172774e30c7845ea15927f5b2878d99d30590294cce496cce49ab206970d234f77e3afe63932729cca163e3d52442209783a2d12ed66439c3a8983387651627eacc39e1ce38556270985c4c9933c2c3f19ee73645de9b31c2db21a7458d156c4128141b9053a4ae9433945983f554b726ca8f4adaaf9a286974e50d3b1998e2844c580dd6a8e60c53995b03e4c7a7ba354ed5b6ad55e55936954d69aadcbb01351580dd76c0c2097df29708e3ae569e7a74f0a07a49f5d587a27c78fe8d627d6dcf6f50ad559f40b68e1b9344d7f189ebd80357670f63a9b57660bdbaadb492ade5d75dbcddd7fb3a514731c1370dc4175f4cded103f286ffda296289fef60c3654d043105c41677fbdd28a0278b4c88ee8e08c5b688a02ee9ab01cd1d9d938c106d49c393638f8032fbabaec50129ba366840d97bcdd7a20fb74c794f5796a58d1c082038569c9c834e5851bcc0404000e2822c606cc489a1f7242aaa75b421213d3d10c0b4e06a61647f7de3434dc5c11588d45dd71fa121287ea6a6c097735c2d0b0b9710fda3181799fa73ba62a7ff35274022956a8844a035a98e244513903c74992375e5ebba5b1dd52938d4d8804a703e378e06c06e2ca1a720e8fe07078876b4ab271ed70562f80a73bdc1010bced374afd5a15d501df5ffdf12561bb9ba4fd2c6e5737698ea041a3956fb91a5df022b0d0a0dbc988b3938164cb1af2435503638cf1ed70ea94f1c0b5f8763392703632bb195ffee7e96ec694a4322cd8c6d8c6ec94bcc031afafcea12d50e37e754aeb0fdfda1fa291ad1be991d65a6dd0c7ba881abe25e9102e5bbb530af3e2d39d52162b0fa8c96262430718205be10a6d90feb651f29eee94aadceeeeeeeeeea63a6a8d3e25bbd80a6206d415a8167d6fbd679f375a073fafe14802246bed4d4713f5ad8bdfccd2ec539b01032e7a3cdd291d79513692189293c3d184b54e7a60146cf28215db7bdb12b5c57e6ba7b576f3a8607baddd293d398db0d65a6bed968c9fee9470947894722b28c9f091f7fcc5bb24342f7bba4b129382dbb2dc005b0ecaa15d1294b74f77494efe56ba90e46fa5ed04a932861f729ecca35c799524c3b694d4428d18d51b130757a9848c102fb61956d23ce14155fa50a19c03048a470a37cc183196cc3c315e64b1c3244e0a6aca2e664a295faeb0983daeecb460735ac1dc09f92ac17684a3ac8241030e0ca43978ca3a5f43d8985c593274e52e0b10296617931f53259714be4c305fd0b10389a9dc428a619a90472aac44a16b4c2b29cc912d245009d3c47603898985c8181fb67387c9e6a849c99152a9678f39858e0dca4d0b68ca27634aac2e495e306f58915162a351c47c8342c906aadc72be98612be1858b72471d17e0b84893a38c090396c9c295f20428659e25a610236282bc4082798e50da71812bb5b838ba72078a9c2f6bcca918cc2c30b61830d8784429a5aa4c24165018d2a3470c39b0d43099762d605c19b3f5009b6a23e74c29b6339b6831974c797281c891b284a812cc092f9c6cb83d364cab3d493ef4849993c5ab44b265961163eee11255a58472528a49a2470acc0fb127734dce84a1474639a6a785ad8598e9e4cd132e3364a47809b3624679526651c551c13403a424c3c336c20d332acf525925cf0b5b0e3b5de2984e6a82982959f8f294432c5e7278651aa932674c955ea24a273e969e909c34c696cc2263472ae0090266f2e82acf6cd99ec6bcf0a2bb6233e1aa6c5255de99ba1365d2f16112792a879c65f02cd5c073545ae1319bc06c4d5d65922daf315abc9463ae985e57260955361c53e59e28b3ca8789e7a954e1b4b9b8b364cbdd392aade03901ccacd2d5c25679648cb98217dc9512cd559baa335368a24c2c1f2d9e6c36ce387696ca37768ecc1c1e9b0e302a5d495b25d718938917b3ce95d2cd559b2a38536ba24c2b3ecaaea71a67589d251b8c3a475478cc12c04c2e5d2590ad126c8c69c38ba974a5c85549a76aca1495a812061f604fa69bd34c23b654fe103b3212ed9e5bdae798835aabe5bf0736509d12580d3a005aa7510fd5ab530fd53fccc822ec065f39f8aa0297b556bbc90e94be1d010d61bd7a394443d0c7b7471b4c82bcbae184e71774a72d4f773ad63c039eee743071acf7a7bb1d475ebc333be219fe661eed5e0ad0f71cf44b43d06f4f71ab8ba8200e7aef44fdea462060f1f445d4149e57cfbda741f6e2f0edba672f066b2de8b1cc2fedfb482b0b41ecd73dff2ee897e679d05f32c85aaa3abbbf5eabfcf5ddd31a11cf9a7641152b8a3eeb4645df5b3ca2c0d6abd75eff76704c7167753c71ab4822530fedf4b675f2b9f7f50718d93a55cad741bfde3444e8177c9987b4a29f6fda4d067afd79f8b6980e281db86ff7c6beddf37afa2c76fcf8023cdded40fa158d45b0bd968d24ba7be620f8854dde46bf79ee5303123978947a18fda3c93c9016f41f088e34702cd16e5d846d1c1a5ddc0dfa6d44e1b9d7f5236ab7fe91e2877b3cd1ee919e75fa91e8d0e4adc353a71f60e4a29f6feaa1dbc11c93173d0791a72f6281c23d7d1c632ff3d0739079d143bff9f82d8721a9211465b4998fa1e8216de6e38c06bdcc43da8d05d8e1cdfb79a3fb335f711f03cd380061fc83431f1f692038a290b948fed06e78863d4f45d1087e74a3eb9ee823f369998ba3e8230d4d84a4e83ea2288e331765b4cf7de8480b7a198dbacf38862842b0d6c21926c70e2e7bc1040791a7cfe28b3ace53fc2376a03416df23099ae74d54bdfd03699edfebb74a3159d46f9d08457bb56c70407d88a7bb11b27ee714e694f51d3aa8e8dbe79ed7cfbb794ec7122568d1a2858bf7c8d9075ceea7ee7d14d3a0ef403d50f77639afbf4ec35aefb8c147269bb94fb563079ecf3ae4b16d588915fd9f7f7091653ec296ff5c7683cc5ff1861ddc121b464a650ecedce83ea52e8e764421238dfa3b45ff8cbcb5254bb47b200d6560fd3c046927bc15fdb3b65cd7ed05afcfb07b8e6d4561dd5e9a11ee6641b463ef89e0f5d89b4c1396af1e3279bb3b897cf5d0c51fd0fb1b4d84dd32df50d44fdde87e7bd1cf37e9e2471a759346fd94bc591abd61577122bf08d543ff42af5eff0b7d457fe8962422896827784abb854e43af2e86e058f4f32250eae1665358f2d63145f5108734a3fefa3d82e486131f1149547d453f2eeabf41441a74fdc3f5757077425d10cc65592b55dcbf95290ef04d0e0de0c38d6cade592df62aa00a7d4baf776f616c4758f8487e997a2c5ea15df4a5e3a14f68d1eb0f803807e1d743c9e188bdaa81a358aea449804bd2c22ad208aaedf0bfe54500687d935cdb94d5d1f3edd35698979156a674349d3111b53029023a804cc983162e8146d800093160000180c08060422912446a250dba90f1480076ba22a604026a74a0261280a83180662188461000040300060100041188ac11854fc696ae111e10cd10d4adfbc73855d6c5157cacdaeffab8fd83d5225acdcdc68de077071832af5d2cdfabc90ca8e2f7f8c1279d154a6e33d9d7558cb590c132fc61a6a10901aa598ce0cc1f20c0ccb2640a9b6728ea42ba70bcbbf03fe651d285140cc105c091dacb07029941d5b2f1e33e25c8b669a1dfc76c6e6ac9840555cf00274f7292556e0b781ee185bca54e5e5559c2475ee2120161b6c648dd381deb760b75ee8d7b9eb6ad3e9a0d46f6f4b2f1cdee79429846ae5f5beaf9532df5bc74d7d3181fd89326ed2c0238d99ba2300cf3b1c8729d8563f61c925b8630918259a2b756a1069717ea2177a486599dad36d5b4743f8d45b02eccf814f269d4916990b8615c0150c1805a6a9cbe9367557b336dc615b3773ee07ec408d282987cdd98a249f89508a3bed15e2d030f1b7c65196289326d671f83f4c878ac08855dd3d15145450e449dcc2e46af93e83280e881ac1020d2cc3a45c96ef1714c1c9b4ce3e988238eb9141308294b8486afc40e39761217f810a6ce77e0eb6bd62d73bb0bb5e9de13343551cfaf0293203fc8ed9a3d3179c0fceae403a7d1ed6aba382889dd9c365da81c119667005bb2a6264678abb08f9c4f86c8377f47c0c10759f5adbf434f2d7a12ac4ba24b2c88528832468a6dd6d7603127a32bc643541a8053100f150193110540072110aa43d4d604e40eb86f280a677056eea8d98a8091b66bf68ac3d5bbfce958c2bc68ddf448399cb0e2736b27cbf2c090e7c3447f81609b8fa5236dd012b3b2e7092ec10984d1d100d3e4cbdfacc0a81f6b55b82fa622ad9fc8283971daacc47ac8a602cd2167804472ce35b200b78f860d56d07c8bf43cc5c36226dfe2e8603a3e007e1fd3ddf6f00b8a51595b6d6bcc8f6586c39f7f950014c6acf1d7ee5dfc5b21e7639f2faca85c490d85232a757185e1379443f4766b451b3978dcf28afe121259f5a428cfb9b8a05fd9dfa241b6f91df05bff4a848e24d692ed71484f1d701dbb6240c88174a71a434aad0b97aa508af2a69839902773466c15aa40a7e8ca38ec26fb4e9a88d3ef3543582d0950342440f1d07de537c36772a18692039a61e08724eca09b2e20a6bfe040f4c0cd8cc82f0e68cb5b8cb10f300857a0de483f3e358fafb7ca02f03c68657034be02aaf97dc25cbe11021142143908d6ff1517bbb0380726303058f17ea7a30baba110dafee98c9a78d0289b6ab0c425e5b131539ea8010898a0ccfda467de2acc708de1b9305bed8fee4859cc9b998872d7c3d40427dc96ccc69cd5f37ea15ab0c19ba41203c47439b7dca07b3e5849fd63221580870aa7f1b82d297dd3be103b97117fe3305da99aaa26500d855c84a1bd93cf9264cf7434dea47152942bc4684482632cc0d2a8da1d03804eb8638036b6985d590f6dc058877b64e9487a434499188dbbc8fcb1a8e226da167e70e075fbdf7c048916f998a9f18a96f32da0bf692e218396ae83dc27fa11a79077bb774e01c0526fdeb10ac2d3c9d01d230d23de224ab256f81d95cae2704eb805268241aef58b49834cfce937034b68750c284ef428d3655ebf60466ff44253edeae876ef04a7308533c65f3a2191604fe675815ef8ad254ae12403751020103a396798a16f409de6c177c113fb874b652893761f5aa8c06d4372431fc9c64b4394024a02263f7e842c4a28b36ec22ea43c877f561526c6d4223e0ccaaf6eab4b6d5a12e11af82674ebcdb3e5889b5ee4eb65b828ceb40c77c219825f6613dcff4ea2a0e0d16d1664db8be1aac149300db70f56bd3b7d8406a156b11107e30d626d10ad5fbb75bcca7bcd41f140fb3421d85e5103ea54945bd62d5749a7a8423c7360205160497a5d01cf00bbbb96cf0a03812aefa0931a6d6917321ea4591dd0b0511ecbff0c3d2f7b4c230ffb2ffff626608b94c6fa52a698bdb39feb55787a42fef2ae9f537adb7d501c308a5bdb9b989a9fe6b57f3b49ae23be0e1cf1cb01ddfce3921218a2dc91280dbd7b89357640a411a0b9f52a181364e7790298afa9213bde4ea2c53f71d4bec974d3e234dc72a791404ec71b1136e8c7613bdad0a6905f138d70b201d85633374c3f9731ef882e7a96f0939c5238d25c881cd8050ea74cf1a34c6df452c976e59fd4e40d99066c1ae90d6dd1352bc401759f0e42a8abf4adf5b6a0631ad27b030c6507a22a05c8971705026832d817aac4ea137775eebf5199d576358929b989bd6673f3287903d8509ff64299b3ef273ef634a9e55c20e7dc0bc7199779071513d208746ea4342d61b51297f052a79c589f141f6b48fb5885a62609d4de4aba808de60b2bea5497b2599df07bd949890766321d1fd058489cf8c6007b19694f57d25fcdb1a1742cb12875d87a381db63700d6f236b9dc7a2cee5c5e7f93ff13bb92852ce48c39ae53f3c1440ce67f81a7744082950d5d7e2a51a26fc946437189e0e40de978a6ab75ee422d02036efbb1b301b35b071867907547f39288f674ea7a324062ae8cd21a2f510d52a46d6ffa945b3991c109be2ec2d87bf52471c8f25b4c44964ac3864e66c12b6cc4b21198f8ddf31b33da55434e883a41ac67fa30a872049cd9cd3d8845b4de12aa4f25ff08c414f9e142d4bf7ccb32ec6b4830a392ee26f58b33cfd46426017271918797bed8d8f4bdd09569ce95cd8224c843345b67e4d1bc6643d39e1813bfeb1d249249c56e445d599ba67895a07c43fa7164723078dd1d15c1e9a6bdb2759666c06d0a48b9cd36ebcc7aaf844dbe2783cbcbaf3826f36b7bd63331829a9e5a261044adf67f1cc81a01331cc06ee82b106540203e234cc3e20d36c6c69d5ac98c930b87f633efcf8945b08d4a0c9a8a43c37d30eb00a4dbd7b61a925a5ac77bd835c4cd7e3ed79bf85bafc44ec9d609af201db1c6bccc60ce906ad489d9e9674a526cab6d1c23321b4c097054f62f65244e6c0c7b559d85a45a8030ea72505a4fdb5ad856177eaa9005d99a8b42a9885af4d202eb0bd029488a5019b0f31abac32b9376389d784f8d4375dec91a61cba3fda995a65e3d32adacb5ad33e1819f843c288e2cbc0dda463c69b0653cd530da60a1c59792b1ecf899bfa7a9d8fedbca79893e047a31e925855e70ef875be3d1eb4294eefcc6d1b38b092d854eb75036bc24bb5475a066ae517b0c869eb91caa8a24442f68899ac572c3a81c16eb4921d276afb4ce383f741f8086f2210e3f8797928702898b743a53c5b4d59d8141c420e221db033f651634ecf23cd438eddd1b3d9517f1ad3301b7d514b68d7876e6fb230092a1b5eab1f8c9dc942364eee66e1732b188514d13dfde661ae15713916075a818e245c694e46fbad8a73e80f074caee4ec23398a30f83b0e76731f2524a8e1893fbbb38cee05a0f159ff844817bb5e22801c6eb222bdd7b528476a6c1920008cdabace58c39f5035be4f5afcd1a294a801a6f74d42b20aea1440aad492cfe492a60c503f4eff54473b9a1bc1aededc5249cdc72c7d5bfa1440ab67ca8f334ea48c93f7616a9d4b9514357a2e55b32c4f63e698d22d754b10bfb81c97966f138222445ae6959923db6693ccd474dfa64767cdc863f20f2cd1682b1a82f03e652a9c5f080e660ff75e4549610143e1e35dfa75d5bdb1c1bd982873057734dbb6530894b52e6c9912c8b9d45182d89d03208974d0b8749a1099cd4a3c3317a5c8bed30eebaedb7dac9ef639f070642bd6013df7b5cd1e3b71685bb1297cc5853610912173779da50f3f5dc400d1b30f55208ef98e7e401fc5044421fefff76913d8779e11e93bfa38059a96cb755ef7878214bfa9d04526be9866ec0d1c136fdad2da0d20b60e4d5c5d73f35dd8684354afb2b4a44994f63846f3a0d3b5222caa64010772638ce33f271a7f03b649bd8ae339b5a2c18fa4f87398839c87ec7cb41dcda1fece1a80ef23c340593706486b07b1e18d80f827ceda83351477e8ed76d2375135df7626abda085130034f22880e054d6f84f18528d81c5adb32cd85275d11758c30ae049c7225ee1e0311d04db57dd4af396edd1bbd36be9ed649f12c82e1065393afe5f314c8db69cc2b4f8811ca4e63115843018ebdd64a6879c86fd4db45b5e452dd8c3b58490081cd7b08c9d02482c9c20c3d9bcdd15723bdef419732b5c417dbb7f9f63d471a287a80b8563e2c19692e596e5038abe631affae8b8866e02085530f33dc65ef6031ba69c318ee631cbc0515c723d82113835ef1d998c264b4909698caf265a53630897a2a495c5c716d5d8c542e4233ad5d542eb18eb04f0d00791e082b988b574bc3f128f9704ead41cd77a9426844103a98167d44d97ace544a52243e87c04e2d94d18cb89f0754e6b9a69b19b7c7bf4c58b3a37589bae0e8c8ac3e927a4b25190d030b0bed72c0ba734409e3b68097504ae3b1f8a48ae31e323b0fe4e2a4d7027d0ac60acda63a2df71d58b61c418ba08b0ae987e774c204c8ec405126d35e30b300a838fb01444b75f7fda0e2838a3c749c6b9c8cf04dd644420a278bd85a41d38b81376fd08300f263e09622509dde9e1d751835efe0d7d56559986d160d432021dd8df83f3e41e32a9058c54e60994f8cb24978289123316b9679a738c056994a4ca0b0aef3fac7013f7057a4bcedc14765d0ef7dc85013dec130b174e3c13e266cfe592d74496f1decd8598c8db4763abcf863c878c6cf804f4642f306171163a8ee22ac2d1ccbc1474467f20f508bdd7098f732c60c8f41b303fc6113cc74afdb0d8a8af79ca06ded9c1497f6b439bef2e08d0d36a6a03fc0888bd6574017c5c9bb845aa2723878d0857f7ad68bb4a9695c7ad8f94695d6d7e4a38e520ac37b7c7c1862419144a37df5c014bf1a6af88d38b2293b0b2792c52a82f7c90081a0dc47cb1760521b1e52259aa8452a46de052d92140987b1349d1c58dd979e0254d7f54ce0c772c3dc9f5364f3fdb2c89de47b390fe3c268438b06a516647b3aba8e9959401ed982bb16b901f496afa453e5d6b32bf9171c93f48cbb3a2acb7c85c2ff7989c71b011db0e9b6d61b62acf96b3f08619e84fb1a0a5cc13ce9aac1bbddef4f8ce4f285c1b975271cb9c422f93cd869019817d34a5eaa920faf2d4b24df84e4a0bfa8670911c6f3a2c42d6d46c198a021dbbde9d046e1451c5dd60c5b5bd27344f4a80799f54c7526c7f4b2746ce44bd45cbeeac757c26fb9660a3587353c0aad0633aee0e4964d08e25def8072bfe54b420b050d282a0c3aa32fb2b721e96d09bd1f9c48d66cf325de169cda579b32f3ce64c525c773d0f79d54b7e17e0b17eeb4ab505d72114f250d61c5645b96e7f612524deeeab54c6a0bd71bd661864fb08baa6e2a078df09d9c683f13249f2655f4d018a83bdf4562e57874e1e34323d47a49e67cfd546deda6ff61d1130b1da5694c65723f416081d3b6d89f2a7cfb4b0adcb46f6e4fff19877ae73cad32226ed0458479ac746d41a3c22b45f1dd622856eb457ea1e4a0d283276fa9d91131b4e4e02072a17cf9c2b6e5d4953de16e98e34052b61c3edc5efdd4a22989aef84692c3eec2171efac1a43d46c4804b506a4cc3f20efd2e1a8383cd313bdecb2840899b0c49d74f753eacd82fc3f1cb1ee71cc385a84837be940b9a5b16da816af903ffcece73d13f6e993c40d7e9b9190d917046adddec151a39315bc2f9550c75f0c34d67d42321da1b751fcdac4c4de99b907358a19584069f280ed63ae55f3dc88eb41bc1a75abc9490c5a8227dbd6a79ee2d481c4fdc1989d3c4f751a0ae5e14b9dbf4ed15de08ef136c73e517c36a28ff34f6b5e3a4c940e6f5c07990eaab578b23c8faf347eb4acc01177534c20596a8792fa5661ee71b96d0dc71419a2fa94b71f0641058859fc6273452ecaaae827f53be886484806f7d5764fe0c38ced1bec1763a8c6390b2563ab10bd05a245b66c9af386e6ca65d23ca45d8f8ace2fd12423e62e9152fee9079d7cae11ee0c46404c63f16ba36d3269c5da10f215e23e5cc3bb1bc26bedc6c97e77903caa6f4933c07629f00943aa6f11a79c443bef83a0bb521de7439a2e061cc09ba5d8739a15a5196e7d58c9a45f178c59dd9162efa08e0837dd0d3ffdb3f8dc0755158a8ebd9e7d482e1221b461966a1536855eb9333e1abc4a5ad08e5771fbab8389c10e5d13fe08f5502abc93735d579031df138cfd4655067855640cd072c7ac4b62673cfed9288feaa01a539c6e1c2d0783946eae08666b6efcf5ec235a83213855303ca62777f8a70dbd9588bd7b2c55f4702e113a1442f600ebf58410a41a685c4d8a99dcf81693aeb1d7fe9647aac1cc74fcd4f9d3a40047c4d99f562a720041283d6325943605fd7c171ddfa2bc8c82cb737beeb172c02b4ceb2bc618e63a86bd1c3d95cfc93ace95110ba10286d1830410fd85efc91f18a9cad9363b419e3a28f62fbedd09c648f5bd30095a7ac99ec7fe4e9ff83502a40a6581eedcf45a2d591bb0bfdba27f6b2f27486ce5a095102841bca9e1c09043f23b71d2aaec20dff05c63c222536acb6efa65c672062b23fb3f3f334108f6d36e2ec5fe0df601ebc87ec3a22a4944b6e0f34256bd081cb00673e0c6fbb9f47ef25965bb915629560cad0a42028f607b5905aff98c05a7e2ae8f57249a5040da96205f343ce035a89809c780b81e47aa17243d11083460aef2f99e399fca13aca616b53b2f895e37aa65efbf75a30277b8834fc5e873149fd7c666d2a6fa281806736265093ef5ee44c3ac18a198bd0e7b582d253388ec7a630ec1ee924b60721f0b48eec1851c2826900b68815eda050274b4f6dcc7c6dfd4f1e0cea735a12bddbab9a9b3d977907889782200a117f75b1b8778b816075e543571dbe5c96d11384bce3f971772bab81c616dbee9f29a78acfa3c5848b5837bad7bf192660a403dc88ac997c4e941c812dd4889402a349e02ee3f56ad1108e8c824c58f2b8ec01582ec8239e720f0ad16f10b5e14249364631e181e626ab5b04dfba6caec86a3f05f5027171c62acf2e1c2246e4487d39655f218faf1519a4b6aac9eeb5a2b1de13c2a8591c234a89fe2e04891ede138eb07296704451920370205497dab2db1055167210c6345eee3aef8045d2997921ef2a240d9fa8540b8c183c1ca36f44d5e8dee48a79a20a5a314609e767159808b47a4c2e2c0389ac983be28ada68a5be3db009d2e233058a0e9eb887203061f5b0b1a567ae91bebb30cd7a3dcc9b86782b838fc2509ad9ad6cec539bacb0970f19ee0d66d95ff0a3e7de0ac74037b8f9e73046e59f95bdb146499a176687bbc6f582dcfa49013d47a66a0a1a393c10cc2efe68854a1e66d3a25c4cf8854409dac16c0d82a44de006faf8133b9c1bf2ac77aacc6809707416b037a94ace98895a81e7f3b815a2d03bf08f6be3cb2a5799fe1d46fea7c61dbf9f74fd86549e24c686199fef9275c49ecae94726cc59238b2ada8beca99b882ed9c6b0b6ae9829ff8401b8d28edc4d3996bb17f209fb07f446e0821b00f1dd3b00c78c214c09d2aa3d769ee8539a846b1dce63d83e93ff6ef37b4e932b9fbdf5c5c807d02bb9f9e26ce61c44a3184f2754d61a5e791cf609813e68d498541ccac3e5a4fdc134e8fd5062fc075cecfead1b846be30f65e15a95619fdd85a11fff33eb5866150176209bb004aa0070190cb867409e6b01e969569b10aa9d9846f32209423de08368ec038fdd46d29217c11b408c08b003499c526c21eb776ae72370830e2c7ca05178141f819de12234413218bdf0fb2ede2e903ee0610af440143f41b30411f18e7609abf9dcdbec32dfaeed8cced654efe54bb2e828a2330709f3d3816703eab66bd880b27ac724df5108de342f9d13936c40a84de311a120854373bc648049c15579f3dbaf3e13ebcd62e703e6de78f8816e64f1a9712e2fd08ca699f1a6a17899f9a438b78ef5b01c1672e762ef253aa0e43f7332c07ade707610e2808fd8b66c29c115f81fa6a47418e0effaef627bf0e43fc33b5250594d6bb759fdde53eab960702882158e43f747456e07faedc73417faeedeadde2fcc039822196112f840888310501c1a7b97370d11fc372d02e458c7c2ca89bdd92d667b0bd25e8020d2ef19e789ff5ad0f4231021f041b44244255841e842322c5113f0df3cf9a2d0dcad266854014e4f35e0e63f629ddce20d4053a8ebb6875e9afbafbb2959bb2deb13039ee79d52811bb11e088c0207c76e05820f8d49aa54400fd7f5cdb2e9e3e076b2c849fa4db59c43bc4388269884d107f10e940203e0283fdd96c592128a09a7411a6407022d409c102e1134327b4f8437351237e1055bb5e7e6a49ebd6880b7d29979b870bdf02cbe7c78d22744238431c8b3081d08cf823d485c00f016c0486c8cf789d15621f89a344ac4e88a0cf4f7b4b4704a04f3e436f17a84f96ab4680475c422884f808210e61265c248dcfbf8b17741c250cc048264bd21dc6c2874edbf6574b3446a74892fd915f8731fa99de9e0262d16d5c68ffb88f352df89f8a70319da245d6c7f706a31118bacf263a16909f55e383501881f808b598fd17ec2673f70e2de957be63c06e932b281f8c5383c010e88a37ed6c8422e21191e35f3721fce4c2816a7fbeb462207420441719e14054a1502c84b70d32a2c5c347e39e42d4e9074dc999136707f904ba154658f14aff68b140cbb5ef2bfcd06e2915d1e2ff09b6abe2f919b7092116205e208e20cc204c1b01d4f7c96afb84a0c2f4415a3739ea936d6d1174b1baabd20bfbc7eb680c4a1f49bb5b5fe573afc98b70401446e023b622a0405040ec8350cf8816a34fcc5608840294d4900db0df68a55fbafc8c65cc02f5e43cc54d5b118213f14e0446d18706ce0a854fad43477c10aa362268fe73e0e221c48df093f823b841019416a6b9e1c4533e99561501200816970f953a6a9d3e15d92e923f2bd70da13804e0d715c924b9f94598223623a6b7be0844f976408d98a1dd828db8618c9cdfd743e1db1d73004ead119cc5fad16eac880ac4dd0807083128be19027a4b71258e1ff68759f0d66c994b3d18a323dcd18cd3fd406a67b04d11f9a6ba33f81fe1004676014597d65c88155df8aa582d9ccbe104f904bbc208e5106e448a44b460fad41c6a08f17db5444ceec813217e562e078218818f48d60f8a7db20ea351f273e5ba1157fc73551fef001839445f18f8bcd0e4a3d14d5431848ef013f80fd7883081ce1ad144b06810c67adc093bca4985829345bda9710f90e7d9e0b721cb61c9668aeb3366c6c2656071dfc0de396942d496aa8534524d91816a37785ea7b69e1632d42c2a8082f6c12f6023922e74ba70508c6c3d8dad4b0feabbd3855e720de3e7c033df67e219269e088187828f76292525dba9f2f02273c4fa3e72acaeb1f17d5d06ac51f942519e752883cc8c104a31ca6dbfb0d0ad27056cce2c74281dbabf04b164849eea78bb0d563a40e03af63efddf22790ec5ae19baeae5f51c9ac1cae8a9668937d4fa622593724a7cb20ba44965d7a2e73f0a75174dc61806c13c60756e02f90537bc085b4b5bc2f02329b9850037f6e4f22f9af210dde652fa91af1d5f35a972d2c2f29b3ff152ca6208cd670a662f7f9ce18c40877aab9f5a23f04a4b4e3013263b42d0be41490b6735c105bb62f59e221a3f7835e5a12cf6781d742643e8c94c4581d6ed1df6022d46aa8a570c44372f61d8473c759e464480cca582c34cab1a7341215aa45f418e9bd52486a3e347a6ead63944e7dac11010cc17783a52b2d843d0c56cc17d75cbf045e3773eb550c54a4d7b3ce7ca5f0c3b308e821abed32e312b104f1977cb2ae372e25ac8bb2bab65c1bfb128b14497321398e3de11c120044641a31b42fef43dff86cfe76fd9cebd7f39cb4d455496019d4b289f5da96e04d061397a11243a1cef3080f5e1a9c1e15da744691101c4795341f017cbe057837d3978085c2387a53d0c06528895e1e428fbea0f59518a7c0d26fb2674c41453445fe7e7beff06ea43a92e791cf61584c5adecaae6922ff22125a0eefe3fd6b102809473f59ee10b63178a7b177b358d86db064f65b867ca6e8bb5002a921841ead9742607aa4d03f7a8aa58b66c18066cb0e22572294f6ee02d45289e277b0ec81e36d3d36863c9566473e18689a202f15a576003f8ac00f240d1b0fdb6bcd0857a6e7b86eaa8d277b99e50c9399fd48a1cdaa10b63c57506a039eef84e4e922c267376159c66abaaffdbb186b6d4f691e88e01096f081af7add35a6ab5d5bd259549e9672d48f7b1c8be26f6de0cd6fd3eba1220dac1b416752d3a4b46ac7713fa55b3ee3f300c2df0f08eb5992ed682098e77128e86de69978032b80a0f26b909b04c3b546eef6e727836a12daea981ff85d0f6d3e385c7668be1d2e422a859ec0e921e7dd6bccf144ec4fa805fdd037905708732b7f5560810661d6678496bbdc706201ecd62c2b1a02302605dad60517727a20679aadc708d1023db52dac037851174654d5aee99c8c1c633e150c39a0cf06aa4dc5e2cb630f4d492616b288f3ba90cb38dbae6ccbdf9e038dee09d196ee63df81b309f644277cac67154cf54da4eb71fcd3c1f5789e73a8f9eb08d579e2b5bef842f0330ccaf29662ffa74787ce4fd8f1e29dc46133088960ec5cc62528f4dd0109f5720d5fb88d13a3415c1be9241085cc1bbb6c5e7e13cbcc1d5e340e91037b99f62001dc4288ca577e6586e5fc4861e3290fbc9baf51d78ef7f46720e16bd840c451e99ddcf172f27a7b35c6fef2e3c82535c9aa6f9d92384ecd130a49f6454c16060525529f68ee21c439ea9b1193f8a5cf7af1d0a09f4516a905b138283c05ec1c03aa4ed05d274155bbf5d5b7fad5b1ad1218788d6646543b7cf5d2b85cd366c53ce0e4fd7287047c7b2bf1d2a79e956f0af1d99ae73c92dbdee061f71e4f661646b1c8003c4cb356b5f25524ea1fe5ea07196b40c2221dd2abc4158059b9122be16b618c64d05a763106bc07882ddd768ce7bc0650ae0baacdb227a7514bffb8336b7783c048603927abc8201cc87214e24a7b0cffba678726b8d4dbbd590124811b1427c05fc205d37730a9914140ddf0cbf8573b05753da8b48dff27b6f7c7dd5679db2f1dddae9c7af267c218c62fb9a7729c846e2cf29a0f11140ecd658b5ac6e36b8ae8490ddb84a07214e22824bc1da031cb9fe4549ea348434b81c43c153a70ce1cbd08a8bab1c8cfe4b0c052d17ea21f209e1118525c287ae01a8dda41e658d16e8f4c015ba3fe94002a376311e901a18d15a199ab6e16c874089284775ce7594970a56836ca23ce68963c9fec58e96590a81b41b37f17486065e0e3f472549d33683d2ed59d6f968e08e311ed075b19590760400b20c23aca3d19ce1aeb9e844a68602b4515855e5f1b24ecb1c2d9aba5dae071fe50b4863e3e9723be9fcdcb60da082c68f3d7758b48333eff20fa89bc0aa46db3fe58df6a19f7d1d46ed781522c7cc0abfeed35736572dbb640fdb980e604b4ae5c6aedd02051adae4d77c9e3ee6985cd7542c50bed2aa89658e9f3522d7f47baa55e9f13ef23cd98b79447f27f1192ef038aa2bd2cbb70ff4c05e27dd8c645dea92bd070675cda7d7ad8bc0c2e3ce6193428815ebd698c6700de565f4ce8adb9812373582755924d124f5a8dcb9d81b2f44eb2acbb6d73c2b272bf310bb9e67acbdc84f8a6c260a85344ae80e3850c9a0cd28d2225f0bee6bb3023adf19fe1c224c16d3ad0c238b5472fe0cd50963c0140e592e9a25ae7489ac89c109492c885595f80b538264b2b04b96e74b57b9fade342c1c9b6b18c9149665edd7698c8e446493459060e618d80a9b8d6619a0b3c8b2d621f75c598de46004895960b53f09fa9d8cfc9d3d110f0deb8ec5521d51953ef6f5be2b1a2dcda9a5c4cd3452bf3f13190916eb4a5e1d104f1506bdc8e8cf770ae7a2bc2d6ac5b79eacbf4c6c05c45bae4f447058d4e1fc6e79769f0624ce03b8d267841ac2d2fa3bc7c7c62e1a634660ca15eacf306932c5462a6005e08aaacdb4fa24818b911629ce0294f3d5026c1f53a640ce2ecf177011235d0b119c3f957e07f1b41189a265c89d11c904ea69bf9c3ca62ad86a17d9ca1adac34d2da70756712e90dad7a4a66fd6bebd694088b53e77b6ac51a9396af2356a77c5e67a6c53abec0a6f8a0526332dd61942a4cad5bf7a9a8ab88aa5e5fdd9bec59f9a216d90162e1d64b5742ecff9ec71695a1ce4067978eecdfbe9e02a47137370bf21b931963b21002dcd74eb6d227419154b8ef69a70eaf013eeda25eae5e2137cb7e56337b32615bea5c5745d20da9013f264ee084af59f841b34cd65228fd7226611f2827be14ed1b0f5c84c56f3af448be1e6facb0a9dbfe1dd1c8160d56824dc12f5177861c7496cf06868e4106d7e14eedad125f216b6712818fe4ce48606fcb79d6f31a56606384d57d5429394dcde3da5c62259d35262b5c5e6f89c7694e03dff1adbd75687d829a46809679488135536786406d6dc269d4c0734f04f1478fbb1cf39facdc42bf87cb10450acd1c9fed1f5a10e56be65eeb4ccb19f4036de83023047dcc2de521a38ab690c6499c113c0751a8b09c73539c16030e9689d52bdbd0cd8c4e96cef17b8b7fbfed1f6bcbf61f9384aa415394febcc05b1522051710e4647fc027e8be625a2133c691e48a309e6f03fd81af657d13a0b243f5a37715b31d9af8d0e45d98122c0d1cc3f5371bcf25ab655a3ba0aafe770f0ea8d463f18220a522b0827f52685695ffb9d470335e896d8501313ed174b78bf98b3ca6bf0a0f1bd34a814c4153ecbc4db6f4835aa1302b2e41f15cf1d5604b730cc687f502f73dd15a84d490b298c8e9d77cf0d3e78199f63084760959e1ec7fe0158ce978e22e99714840f1f425ca2e3fadcd58b268eba294b89f5a6e799b71dc4a42b47376527678ec25558a98ce88fa1d0db7341bfcfcbb94e1c520e5c608e6417a4ac1dd03d6c6143097460de87e9c5a3d880b770a294140ccd9b4fd4ab73b3b4b31833a4350974b438378614420676ed08f09d0db01b8360f6d51a721ceb74d91bbadccd14c122612c3388942f7272515262179a08aa4d9ce0353c46ea7aa09c4609b7d4704106941a5687148bba795e1ffb2cf3e922ac1f3fcc448131cf3f9cb21b157d88fd6bdb633b8e216e4b3f3e6680d689f11124a8fdf78506f78682978c367354e234dc8dba6ac475e7ee6fb3c9878e62f9bf09bed28b7899423c99758fa49ef322b0851fbe24ebfd2314095c9ef755895b25439a5f7db90a99521d1e7947db30efe84c51b5983329e62f99dfac60327fea0790031d69e1f3fcbbd2b0598b9c6f2d318f26476e15627e26b0d6b27ad027a50a832a892f1abb7cf21d4bf9a6fcfa05a62fd4da6aad5ded61ddddf405196a55fc552a782d2ed840a065d0a925a1b626cc83f3d737e9d09f6af0f678609f301efd750755af7efdf383003f0d10df0322547aaa1cd2c0c19598951da7d35d1abeb3ad4b720f1dac250075b6fa5010573fb8efd79ce826e9c97cd73d78f088f4a13efca13751095d35d816235ac5ec0a324277032bc9034422e354cfb62c12218546c9896316b456f2473f0647aeb29aed0463389d1d98c92518d3081c49116005ed6d9011d45049c448fd8bcb6fdcdf94545df8683984a5c762654b391d629b68ab236b62d1c3a00e42eb673a2ffb48b0b36bba70dd2b1789431130b0bf3837e302d1dcc45c5bab0aac1204fa193ba45410380b4d3a958292b819245d14f8bac8c1917fc8f55059c341d6c367a511eee873a983b4bf2a3ed17923ad32d6439de64465637772e31287f89281863798f56d40659be0800f7dd3d79b10b9e5de726f296592329909670ac40937dba261d3d9a871dbdaf463fa7ed51fb5404a80e39c9a0a95e63eca79fa33cb856439389ee6e070a19c108643c7d400c7c775e792b0bf5973a1d152ed32d7856e48ef175e172d154887a8a492baaaeb615a6e1ced3beb51c93796f6c1b723576553ae0acd48f92dc65866abef77a16743997db9c71fe21be771f4bcd13734a8c72633aeca0bfff74fcb3876b1ab5cf66ef7d5a6a676f797d3b2ee3babf1d55ed85d3b2ae1b2749c032fb0fcec72bdcc433c39dd75e5b58069f4fa4e00ef9c57ca4efeb679dfcdb0e3244fd7fd94fa765dd8fda5434a1d97e4f518d49cbe2e7aafa79267be9cdfcddf5b379299aba352959f8bdecbdc79b7bbf7c7bb3fdfb230b54a2ec27200e923c92453503b842d6b59d66cec1fb54ab6b72114fb5b28af8b339425a994f2503a36896dfaf82505cc7621ce7b99658a6b997d0eb69549d9f7bd135bd68e58b3b3d0b6fc62cb9a14135b695f7de9f75866297dc251dc7648f7f73f5d44bfb189b8dddd9dda9724fa729571cfbd7beeee491c4f8b85116be6951bf1d453a5d0b55472e4fae34de2deea3185238a084ae26e085a0d8b02fd79eccfc3f982d18e76958523a02240ae6ee0b6dbc6e3658c87de997d12e028ad8aa82b1c7fb6cb8ff8228791fc9c1cdf2d6d8cf3321fc14ec04fea66521f078efbdee3f81aeaf891d2211e5248cf04627300ed6b0f6bdf56ac4039394d71266772da9a356ace9c3143864cd69831565bb64c59b102e5e43465324da64953523ac104139628519204638c43115ca445d2470810fc187e8b35d00fe06b6323aecd0487a00892c867cf2417381bdfb81096443e42a08b509268680ab94c336b9a914478d31d379bfe5ce342f8a9cfa6ef4c2e347bfa3e85be4349229c4d71a8f3de4b99d6f94ee31d7aa6af8b5d8ed7d1b2c739f04bb13e0f7d25cf9440ead7d7d1b3e994da5f28a54ff534ce773ae7b117a4c726df0f0e7e9806f1fbe3e8cf458cb5f7327bb77ab5de2d7313d7b6619023c0515a1d7121efe90dcceb91eb73817af4a94dffa547579edea6672e6e3a08c8082af777e40757bc53eb48c2c65ff147edc45f7bb0be17e4a005506e22225025bb3e09bb86586afcd3d34d7ef6fd9824badbb669201dc0ad7abf69ece9b1674cb26baddb05e201dc9eabffd551c9c63e5b126ddb5699cf86c02f7fc7f8af27a1c0b93d97f52bcd37942ee2f00ea15dbcafe0ed019c7b0e000fe0bb726f38d2edddafc3b3da1b5ec18fc318e5a143d208080bb83dbd1fb5c2dddb755dd775f75eaeebbadbddaeab33ee76dde5e4b66db7ebae54aab5c9acca29a59cdf757a84edae0b9dd039b76ddb6ed7dd6dab72e3b83be6a36e0451f472c582e50ea516fb47abb848ab1938366a6b9b61cbbbc3964584d9f793b90817e2efb3fab571feac9e3a838da9576aeb66b9ed726fa7784526c6e9c938c40fe7f85c39477ef0f1ec9bde6f3bdfd41fd6f9808800a5e8e6429ede42a4ba9dcc36738a0daff4f164432892f77263f19b1a96419e6fead92b16f3f14dbdf33c3f32d2f7d5c551a9aed9536fb0373dd6bdbd72527e309481cfc4beeb651bf77c5617b1a16ce328f97472d1a56fe4a31c7a6175d1f33104785dfcf14d1d04fbc13ff473f2910d83f4641b4e282b59407f11007065cb9c645db4e19c62c322cffbedc73905cc36248239f8a65602802418c8373509f9c88623d44c70912e01ba027a930c3030b5d28e137000bea9a1b8487f837c64c314c40db0074c216d0a7df4779aae80738f730aeef931978e8436f87c88b988ef219eef878f259f7ca423c88faf271ff5841ce8f80048073f40be00007d2b74908bf806e1e7f3f2277dbcc701f8bc2ccb49de6fa1ccfb9c2d807ce4e120200fbe39c585f2910df1feac96b522cad838d90bab6be3a16f4e11ca453ca33cc4f7379fe81be5232f9c4f2ed6a2a6eca9736c1ce483b2c7a27c64c3f9f461cff3ba7cefbd2e6eb337ea0d0e85e1f01c311d3ab2f9c18ed9ec0339a55c5b28a54f372a39256d3f43d9f6397be72967cb8ca4fbcfc52bb95bef379d7400e586dd0db65724833d36996d5b6d682483edf5f3e873ba0bc79fb16773494625db86b231ec579bc1a65af6499ffab216b5c496fbb5a996b5a82eb675b18636c97e8eac1151266733813fafdbbfbafe74004309e0323b8ab69d8816ec9752ddf5939c86b2ed9fb3e9d109e1092ed207c12631919ef084e65f7e1550ca70e3a8d4512ff67ece106807d0e5d2b15d86e30cd39ce459eff364cedbdfb8017e4cfadc07f5cbf5f77efaf3eccbbc05491f294baf69d57cdf7d1bbfc077bf7428632a298fddb8db79f8cbae1778e30607862327474c878e6cb6a3c7eb10003b1f978106df75218efbc73df9e8761f11b9bbf0473632dbb46953e41e4fdd7803f1e3348f8f1fdfa6710f8fb8810619ec0020d4dfd3c36d3db6d29e1e9fb2a7a703977db9c61e93a4fc15e692e75d15419c01222a0832fb67cb5a10426c22b0f68f2d6b4358ed4aa368a896a5965a6aa9a569aca5340dd572217a75110896ba58b508404080a3acb9bb13b9aa56abeac90ad3f660cb9a1058423c6d71cb5a106bb610521bef4f6be317de91b01b2fbfc78774bc0b71372fed4bbb727264fa755dd7510976ddf7e1f8d98121930fa46946f052ad3ddf8ef2ea7b6b434b6d38564aada59b7dca86e65f615b6ae948d5d8d1777e3a522dcefbd1c30f36a433431a8e124be7836c33e7b7e1927b414bd350ab471c618e5c84bea568a6106badd61e73502dfb99fee4be28165a5d2b1ca19ddde7e40871507a63c9a537cc09c710c78d90a6a94fd65a6badb539a4692690ede96fda7e1185e91b389a7bfbb582e04534cd8759a25813699a2c5114459aa6880e2da13cf563348d28ce5c9caf43bff32c916662a2199a86a6a15a340d0ed7314505c22116fb99b9bb3b9d651ce642561508876a95ea17f5b19444cf66cf9768b6dcb20675b5e57355f6ac01d1b4e78fdcf7c409b767524e09640338fedeef42236c4774a17dbf3a827ae4be43c23df732042592a64a6f3b241989fc2d23a13fff0b6b0d61341fc90956fbd3e624fa3017a23f5f3cef3bcffb8e8aca0a4b92d9f275bacb5926dd7b45bad0b3dd7f437c6fdbb99fb9c8e52e0ef7b9396673dbe6c2a03520f76e2b13ee6f112ebca18ccb479c6f6ba3ecdf2a5137d0e770b8dadcdf1a7dfb03d5b6bfe16cddd6c1703a9c9b0a62b910dd32270f99569b0bc7efd6fb7e7383c97dfb37b2915ce4de2bb77411fbfef417dbf901818892254d52609af214e5bb3ece61f317f5753776df9fc97dceb7ff26960bd56c64d67ea8dd5ce4825f918d7a9d925ad7b47a5599f2016acb5a0f637aa8b2ab13285c9b366dd66c7f2272bb162ceb102c1dcdf61f97760f4ddbff89cd7623f2e73be1b6943e54c909b7bbcd3db513c9f61e72db943f7fc2c07bb276ae7cabba03399807529a10a6cdc659898d4327af36fbca073dded21ff57b68199e5f0ffddfa34708f5df8308fde043207abc0cc77ad41e3ab1f04b1554b024152ba2bcb2658a45318abdcc0890463a51ae0bb1904a4ec223c849d8564145159f638d2063abf3bb15d8aff81c8b4cc2ec672f33093b7e470826ff949c646dc8491667e160430d5938d54083163748f7e123d320a50454a4f80c4ea6ea471650ba0ffbf6addea26ac76730339a9492006168b31f4880b39f99843034991f10022d480d58440218275537f0f8d9f3d060709e879ee160d72f6daecd0eed248dc81dbfe3f10e4d250c4d4a0250e1f13ba8ecf8998f2410e677682a3c2210829492003cc21b763c952aa49404a062444a49801da14ccaec67dfc6c63cf4ec77e85908267361b513fb1d58da198cfd6a3f87b222b2cd76fd93d1dbf997b62b63133871bd077a6cfb733a11c196d7f0678c35dda2d1b0c676db77854fb0abc853a0d16834fb3a44dc477d223323b28d8d671a8cb5386cec0a9fe4d8f604d73de882a33c3e831732cc204399186488e18ba6189ac080a10986305e80e105332ebce082184c2e30e5246cf318519cc9a3d88c8216d044692127657c06c7340bd3d34c775dd179aceb8e6969a413429946ce42b664d0622f298fb3e0b49c9471194bb1d7797b060296684b46b12f721dac6b2ccc4ecbd8a66085366da05161b6c1861950d8d84a23823342a005822d47432a85ad355c05521f58430d5f81d4133562e06aa43c100336ce022925363068810b3048c3054c69bc604d9417acb1f90527a8b1066317e4a46c711aaecf2ecd819b972e6e4d778d73dfe04c1758db829c84b385c1065c9fed962bbc925b7057c06ca43490df6e99915258dad98575dd32e7f08aa43c210b7252b63929631b831524e5c9af66056aa8b00215ac01c31bbdf04650548086ddca001b18f0362e205d44c3db54000d2d9a05fe7b54e0c31ea1a43fb472923d232759cc0205ce48d3820969cc8852821968982620e98ffc92fe40930217249082325ef8644b76fcec6558864309ec0867a1741f2e970be1327292252327590c0304c838d314813328888104148c21c303a4fbc82fddc71862cce00031cc48698099306818210c306a6000185fd8b0802fca4c5140192f46a0c48b2ea824a08b13dc808013d49c0e20290fe5a99900872492f2982087241370a18301b8d8a20a922dc890e0089912ec60a4045af050002db2782a9245560f44b2b0f001098b2b7e18225d0cafb0c24261399a5600414410578488b212d3d583ec635ac410f6b1cb155abdb4b17f33898b5c4ee262953792b8583f3f969e8b888bf57318640338b3c84778661181e509b847daa6cdb67f84cc45f0cc9a581c1185c511565c215584155255606131a20a24b0b2646b8ff86a7051918f6eb25c4d8184540d381f7531b3f1e3e029e4141629a6a28022892c502431e6092590b84f28e18418a025c0515e0de990479ccc540d60ddae2b464b2e62df158eaeb7a1554eca3fdfa56b189cbc25090fc2e423bb05cc124a80c94776892f390967259af8c2449516aaaa26bce4249ca996e8c00b972e3929632e4cfc74e9c2252765cc0490172ef9e8a60b5513df9d01a832c02472640ae926101da101260d47c9c5ae9ffde64e2154f9e8c64b133909e72a2e1d34f185899c9431123924529efa92a80322457d44fad4072285a414698844f2d42e57fecc3dde2b8998c049782e919332ee126609305bbc7860b5258c962aca23e6d69f5aac94f8e2123de8eb111b1209a201ac5b9c4a88c945ece770cc8f13ce2472120693434cc37c3a74acc8330637ae7141b3658dcbcf96352e519b880bd95dff48123a54d5d068b42b46b54af2c831170b242379e4bec20bc923f7d863d39f4ae423bac19619ebf81cfa4a8c0b9badc196352a339b4b95edd4a963225ba2327d22d3c79aa34bf9a955c66fb5efa598c662635aca5e17f3c774900f4486985319091124f21056b224b1fc9d452227d9c7e1a8c2c63fb34c2c5336768242f1053d05fd008ee2ae37378f6f6ebec8a16c8c839e408bb5d537373fd68d83c3e69ddf7600a9ee1c7ed207f64875db10c7fe9c19c97503f637b42ce7717cce37a166ef6c596b628a7d5d283fd012201d123de7cfd13623c1be1f2fd6370bcee320995bae8b593e9f8b29d68735ed410178e3c3cdd7b7f928e79b89251f49e558943dc2da27827c005f145db48fc371ee6f1e9191e0178dc8491c11172a221fe530c4633eabed7e72f71756176995d207052570d3ef2410fad3888cc4ed22425991fcf4732829a51308293eab7d06f181fa4aec5fb1cf3199b18ee9ab6ca372127e1b32718d4bdb85e9148fafe424fc396492dffe242227616bb3ae547c56fb967428f6ddc7f2db70d6a8a030cdfab0e6f6cc45ece330874cb6d436912d59bbfe91fa236c41b3b7ffbe9f511909fd2f1c71759ac5949b9d572af519e552aa45946a7b39bd7d150a5581ae50976075ae20065886a1dab2f6456b6f59fb5266d620a0a67489d6aacaec9b2d6b5557bb56455535a5a5caf6a3a5cd05cbd98ec82389ec960db1db7fe3426b61dbfbab412fa007023501facf5bb70fc93c8c19e1b7fafb5c8cb9582b8db65ddf4ecd8b43eefbdd9eb761e15e8a73595db57b8abda7f4066dfaa6b0c7ed95e81eb9f7be53a2bbf33617c445a0312067eff6e4f442ee6efaeb026a27773f99edab9da4b0bde7f413babdedfd7571ebac68b4cde94ba3ed4ddffd4387ae91bd4c8e65e3fe93443226f37dcf876d39cebacd761b4b1fefaaae9bfede76a48f2d22bb33dc913e1ee4a27fa7f78f2b70bcdd7cfaf631ddec36b739e76c739e73dd7bd76dd37a0145b5767d92e1d844d4a25a55d48698aa597112291a9aa6a6a5a996c416d5a25a5ab82ca022c0ed81b4803a404180e38c7dcee7bc0e3438723cfdb94676adec1817ea1e470eec6b3ef26ecd431cf6f6efbdcf7d3afefe876327e771fc38db76ecd9361cbde7381d1d9d7abf3ed2fd1a5a3dd6d9cb8c64ff5bda9e92ef998ea635176948cbb8e8e1c08123680d98f3f5bb2e27279cdbd373e7a836775716def8aa618fb7afd356eb6c998ddc8761acc70aa4051c41a70ac79f8df3e07f2106bf778c3d1fe5d70b17d1ac713cd6399f8b1f0dc7d9867d125a5354ec211374100c5f5f445f300b1ba2f3301b8ebfeda8e4f53daf8eb36d4358ce17b98e7d986b79ff3dd6361f61dc853223dc778fc47df74bfb8af9f3b7bfaf7adcc11ac77ff5084966d55c04847deda7759ac0b685ed1b8e4db6cd099bc070be623ba630e2502a0e6c00c759b3db47abaaa8a4a4a29e9eaa5029540a6ddada62a3a585a64c991a16d6555515959454d4d3531597e252bc696b8b8d96169a32d686b34c6de642937b202be0c855e1aa38f7e442e0d3e7a05ce8f5f4392b2e14c549f9d08ea7cf6d71aeca85acb8312e247bfadc1587e5423a4fffdeb7d6eb3acf52ab54b74c532c2b058d8bb4aaa96bea194f5b9a65b2525ca48fa3ed14eba46d156d9fb485d2d68ab65156ca4e511e5ab35476ca46d9a91b3b65a5ac0e930b8df639269db1fb6dcb458ec907d07ef73a9e4917724cb4b9e51c937352c66c66e88666d35243e96f6c249113a5592e44b35cb45496ca5a55b9500efbf629968b54774fb35cc866bde895d534cb458a44b13ab9eda5575859b6b3d862706ab9d06d92443852aaf8539453f995a37136be459ba8942af48946512a498463775c0ca0ff5d402d0c3261a009238c23aa6a5848dd1a16524e566a5838cd1c2cb91ba08b332b5844050d415f5a3b6b5830edda021a3a0c7c7a16f5c349a3dffd5e6e8519acac8dadadf2256baed7ebf57aab9dd03b34b73b739ab5da61ae2d9c5b538d9a352019e7a91fc6983d4edafdda69b1c3a8daf527533e723dc2c0dd645ba7ae5f7fb5cb0b5fa112359cf6a68a4fd87604f3169e3102c7993545d6aeb0b287a851a5bb3e91aa242ed465b1eb2b39c1ae3fcd58b9c806f4e6a472201880f42f1d22522489fcc798f8b3a590696602a93f694276f8ba726d210ec71f3353881751858cb1ebbbf628e953a79a1f57388aff0a69369c520ebd201a45996d8cb070415580726fdc1a1c7e21d32b1c63e36fe12882e1f853db4cb5a16a63d5e6ca6ad74b27d977e9fb8552896e1cd2bba51ac923ad607369924736491ee9ffb968b9ac8dc071aa715aad6d31edfa738d0fb9118dc9df3fc7d992726a8f5bd6b0ac6c9d1080b286e5b41d8b861a16d38e6d55b165cbda14517b0cb2eb1455f608ee3973af428bc27adc6546eccfa5cf6b54646d599b226b0aaa8d5fdf77b511388a9bca5a154f43d4883e08b4d61a7e77cbedefb63d2ce643f7b77fdfd95617b9589fe621419840b9e70701c185ec66b939e75f0bfe136c848282762af5f7e2a12cc0192c1d6389a574f7395f4ae91ece2c5f414fe058eb9cd405c614b425352cab3b9d56bb71f7ebe494f73a4d9973765d54b54229a59e67a9acb516e3acefe3388efbbe8d8bfc755dd7e56ccbb83e8c3176b9ae18af2fe79c5fafda9519afd70b046b5756b5ab346ee7f2170bae685bd6a4b032b4652d0aad8d5ff2af5700ac4541668f5f83c114ef9cd86e345f7e10bb85a00dafd89f3a0853d31bd970c779fc03c179fc7d0c326100e957bda38348008e4182b87b6d02120314e6fbc25550068dac7966bbd33403f40538cea63d2ad15d5fbefb9979668c33f30c972a141403388a206c2db0cf19fe7d5bb775e307acd8b4eb2cedbe7694d6bdc56d928edaabc5dabc7da79bdea8fb4d2fe0d5c58a28cd493a7bb56cfa553bf1dd81a57da5690046f73b2da3f7a3bcda307a611add67ba51b8f04b9ba512b828befaf241d8cc797e5c4cb3ebff0405b9d2f446f7cafd2d518c19b3062881ac00679248a604bc4f7feefbfe600dc7d8f62dc4740efdfc70027c62b713dac6cc9e396c10e6b37eb1988d7d92886e0973ebb9c8cc61d7a7da89ef273c7607969ee4d8f49d706ddab4b195e6a68f42a561559b072cbdcc24cc9fef5b14dc753da514767fdbb6bad5eae0cc1d080b1cc59f2049c4fdac2ff6d46a7d73f73bf7fcd86ff6b9cce51acaea2f6da4397fec21449440e68f3baa3f28615b76bfbe33f1eeca9a5f5e6e47fa6c9bbd57ec09b29bb538a410bfe36b6ff7b7c7d4e3aaacbb6a99fdedeb6452dff7116cd372dbdfd76df58ef4d9dccbbc50d43d4175c666dfcf07619228ffec7e736baf75ab5d2e5babb4dea7e7acc6661e7e0745d49834dbfb3eff700204bd2f3ba0d2c097f9e8fa3bf7d51f77daead82ff2a3ee6dd697bb1bf7f6feacefdfe9edafcecfe9fbdee7eebdef5d7bf937ddbdebfa786edbf6485ce8bf415142ba9ff3ff1803e6f979168b6dddcfffe12eb75dfc713636abb7ded8ec9f009df4d8575e7fa5c91abdbee7c7a9f72f50cb94bcfe755f19ca12a3d7cf4c41ad02f85830205dcc21942546e0cfec7f5d1a757afcc2d07bcf3dbf9e87c1ba3b5d77d01aef7bbff7f3ffb6cafdccfe557a2d0a2b1bdcb20605d5c6fe79cc4519c39b8fdf96b1ed5560100b402547ba1eba9c471658ee602969bd2ed211047dfb21e667d69d0f7fceeb2e0491793fb7bd3f2ee49bf7d4eb3acfebbcce9b92a86e32fc7333b1ef9f93b9f187d508feedc96b7f8939d7f7957c63efbbcf7fe622fe4b7b7ad37f8c01f1df4fd7a357de5e7e9288e32a955523db738fb47d0d47285fb5b908c65daef5b1add4529713baeb7363de4e5d36fca4cffc4ffa383ed38d9956b3d2799f60da9452f167df1e637b661b561ab0dca9d1f98db5c89da87242ca2e722149eba54377da5cebf4af19c9d29ebae62217fdc56c51316b36a55fca88d932375be9f41eae710321dd02cb2ac64a90f9b9e3ce29a55dd7751ded3a988b414f200a75dbcf5ad84be8c7c5faf25f624cccd39cbbfecc56ead405ba58ab0c226b566a86dca8fe111772d0b6b1c3ecf1ab5f3f4912dce5234abd7c4429ce479466bc6d5c7e24b97328733d931cc402902eed51696357e7d1a58d75936f7be11c832949fd0ffb7da2b6bdd6c07cb1a75fdac5bb74a1944efaa4c7eec0d2ddf32f165de817b098569a26e8f2055017d8bc617bfa056bd33bdee77ebc746f5eaf745456570da7d432f9db1f3901de97db6545c227a3127d3752e48677055fdadcc9c0f8e5e3a01ec0b1eeca84993d6bd8b2b685cdde9ed2bff47195d6c68fe3ea9edea7f46fa6d8d3f9257e9c70ecc01275590abed2ddafc79c4fc9ad808293d9667faf74f78dc7292022bd2ac80c084686f3f6f38391e184b58c04c80d7f0952011846963ff63a1f46e7eb62ffc2b139e76c6dce16678cb1cd365b6bede36cbd4c11e369cb9a99293355b6179a1a8b93858333b6cab8cbd4d660cb5a97a68d7f83dd54fb22b5ede32f4fdb7e96b2edbbd850d176065bd69ab0b263574e4ca8d9221a34b52f5b1bcb28282d5adbd2aaad9da9b2367efba5ca6ae3cf531bbfc501bb954f63fc1e95876cfb3106f595181157a28a30c28b741f477491e222290f16aa2c4d4817916042d21f534b24b145521e25b4685142bac8c316aa2a2e5c7838420a4b961f9000337dca9503ebd20587892e436cce63ea60e4a4d585f3765b2d613739385ebcb876c8593e243e15745e1a61397d4ae743269da598c69ec467b502965cef3e6424dff9259e5f7e25745c3ada6aba16595db0776b5d39195655758343e501972e60c48409e3250c145658803dac26d0e36f70aa5cd92a1f59d88d0d9580b09d93f3312ddd0358cc9f90d3ab0be775b434b25ac26e7270c488717db9e9dec5e423d71739d6d13257a8048412d32ac87eba4c014b46b247802c64922ded9856c092512cacee817d9a91dcf390b9f3c7ea7477e96c9996ee8195696984a54b31abac2ed74b23aced0e02421de18804172b4c1f49a295489ffa405bee85015d01ceb0deb6cc0f98dde0389820128459920990463a0a582241152e545c3eef522527611d7212b631adf3ee057bd5e75f72093dfeffc3303ab8870ee33ae4e0841039e0f0441038388d0142d21f3fb2d30d5040f90d4e258a0f7e4c8192fe90e2ff6325488944f645fe2309b0c7cf5c421835324f20043541628045b2843051be00a1b5d63d5ee6231d5991bf0e424a22f4837fa8306af43f54086a663eaa40987f0da5ff5f66134230a343203e94edd0e37b7c91b761a4a3230b7bfcebab305162efc29291ce13a11f40219d90244aec75429912ae8d91ec9ba064239d5f3292329d708afc61d404fe1e8e75bb7b38e7f436f0fc9f17631fbb41412e607777f79d9e0f8c92b57b827e071673ecee2478232c71f1e8494a915b6badb5d6a7136d322961c0c5265068d4cc336e45e4c80ee0085e38ceb6f759793e9a735a2f66f3519d765aaf42d1683423b46a5a66b4d00819414b8d04729565b1f5e1c393d9291380df0c7b5b5a4ea0d6534c8b494b4a9bfb094d2c52f4979edda6d068b422d068010d19d0a04234021a3b481fb94751ab055a6a481eb9399e3d33cff65c25a536d3b96d8865e7b6e196e88564382bcee30e05e55330169ee246bc9f4ebe23d2cf0a8fd70eb97ebc9e8fd9a69d52f9c80b4f00facc50f4846ba7f62b1fe3ad61e546bc87e2a27b3e6545a1fa6ccc7d77737ee5629a315b5e6d5933c3873464368f2d6b66d036fe3e97669a3fb5008d3389ed3fb148b712f233ac7462dc6fe68f227948e83fa19b89fd8c94df4ece1bbf90fb201d402617b0ff5bda198e998100fec044cff3685704841446d8534f2bd1ed791b80ed26b0ddbdd5f94bb3c6a6d9b26730d93362c860db4f73c6a6d1923cd2676357d46bcf252490d7e77aeb0a7d0ae509a758a1e16e755535c6cc1ebfed55533e45737733cdd2c52d33aa064a1771b76409a766842556b5ed242c51c3850e5506e8fdfc51a281ca5ce8563e46cb6ace3d4e2d2b9f34b5340a75e70f77958e4a3292b5f6b367ea0e2561560922c58726564f0f0dcdd0dc02bb7704c31915f533f18e985f31900235e5d12268115e28a5cfe7539268066d012671d15fa96a2ef4e69c33045d7a4a398ffb7bd46ef2cd4d697b3fe73767c6a15bb9e86fe4542e84b587dcc87dbb4f8d0ee5504d5c68eec7e1940b4df7749369bd30888b6eed2cd2b6ce992409c544927c01bd1fe5d591efb116c5fc9ee7fd8b5380dedf1dd145ff3078c10f9ccd84c6ebc16658a0f75d6ce66fa3820459017aef85452e42d9f6c799883dabe9ecf909fa71d1843ddf5a1be4a2f778fa0407aa021ce7cf2817921a251a6b59b027d6533799f9d4389c9eae7b84fdcf1e61890b49179241c41fe95947326c596accd4d04c810ad22148871a1a5a2d055653413904e11054058a4a5a535881f3524bc194329acaa8613f399dc97232d85032d46c4a51b0b5291952bbfed46345e228a594ba4615b6529d61a5563018e953ca29ba65ad0c2c9bb3e252ce329c8ef02d6b655839ad428e81e5639469e26063bad96f62ac2579e49a2bc616c814932279e4185434d8755a33341a2d8b917c9b8f26077bf470b4ef36dcdcbe2f06bccfc43ecd48740d9540a1fa371bf1df68341acde650060b4b8951b5b777a92d6b669a6c186cb4dca37fe6be0ea003c1796c102d37b2db7eec8d4017b228a8b2ed1ff1a16a44b7fd98b51f34b3f63d23b9e1f6b022efffb9906ff14f6efb757ff5eb827800ef57ed142b5502c980f49164fd5bad24b25512552a89a84b22aff5c8927c77a79bc317c6188763936f672028c0b933d52f7757f8737bf5c35f6c02f1ffbeef8b4d21b319def63b0912e19a91e8c63fbb8ee7f7481f7fa035c0ed69917b7abc3edb9fd317e62edfb66cdba6e461918f1ede6aa5a5096c4d1318f6a7be54270a58eecc2fe809b41873e198c2fe0b8e31eb2485cd8d2bece984dbdcb67163fd5a819e00e757f965297db52bce34f92e8dd66ddbb6edb73265f6b66dffdb6f1fb4d5f6c664fc1932b15f5fd8c9acf4058fbbde538ee3386e72f3bfc97d94523ddf6afad16f7ebb8eb0c96d8ee3b86ddb40342ca5da7e2b18d097f6f69b06b29a77537d7bc0f3fd3fd8fc7009969503e36ad39f4d341a7403385429f79de6ae7451d226b00f89d79cbeb052466b8b6d6cbfea4274e24e02d938fab8bae4b63d92dc8ad89f219322f3392ebc2bec51896e2e8d335bd6d638eded83b6aca531b5a50bc9dfe8f66c48916c3849369e646cab4d60347db1820d5650c8c64e2551ec2deea4101d1248fd106c01942e521ffa55fa50243982520a906e7a933e4b9b7e5b248fac926324962423cbc82fce482934c217670c7153341acd8b9114b265b6954a81c1a80206141851604c491ec964fecc74d2bf014ba01580b2e6c5d31ec52dfa9549840f41ad54216c101b101cd4fda1f3c1eb013f7d3ce41d5c2478550175b891c30d0e384eb01b7050c919418e29311b74d4a043834cca6c861d32f088a147d3c3a05f085d0000d34e940c5ad060b2b0c1a4896d78daf0c1c68fad9e357cd4e0200640d8fcc0a0833402f002a035412ef0a005422c18521364051fa880080d215a209c21803403302304344529d865189141803322a0e0688c2162209921124611300af085913247bc40d285014e90544b6282037081802d124046490914a0c502b26040d6085834e00a0758f1002c12aa80001511984202574ba49840142540418131263c5101272c802f6085811032308051004c4068224403441bf88003414e1872228482071d085202f240009e74f0819f14808080835d1f87c067d7c722e881f243051fbbfe0f5e816749dcb40d360b1ab49041941d2600b810bea061f8a61e31f09061c70c3329321a746ad061436c4a8e11e450c17103cc0907879b1c6ee800567991c06577701ebeb99f640fd9872f88cab77fc0501e107606918fb60f62012cb28209f105d1bedeb007a80d38deda15185bd6b8300387a53976fd118888ef471275df105d6c15c5ba58b3ebf704a92f42ad9dc069d75aaf50fbf381da502fa4587ae5036aa3678b3d3f364a04da026908c406387f02bd001cc51e203640a02d10280d50ea88202a178b67a9486c53d7fb6c46a2405be07c117ce886d579b65742895a6dcb176c59db62cdc69e91eaa661934fa422901ae0267d828c00fdcca7e59b5abebb059979b5658d8c947de9508fbbf291e8a2ddf26d81f948144ba02575d8b2a605995d14debac45767be5214a108680d90fb1da02cc051dc3bd37ead61b5e18e0b855a8cd9b2a6c5963db5d8b2966566772085dc90407a7e2491c51bef0f943e1f13f9888614480d900958133954312e3a5d66db66a9171e55559f8f6c28f6c400b4f38bf82504b353c36860258af1e144cf131c8cf9812200510449217415640a222a40a86200584556185d21021643b2886451002d8e94c00064926c8180cb8512132ca036c2091cd00509d38b08dc324bbe28010c13c2b080190c88318ed104051b387302192894a1948227685230230469a09cb182160d8d1654c0b48217d434b14086164871410d6ba6bc804a1a4e30c8814d9518eca0c6d31a3e6c41b111441b56661b2268512c18d18254942c4c532e28f1c216189868a28aa18b0c5533809162458313358cb1218a295723a0820ad60d573865e1a0450e6474e0a24a8d045dec508607309eccf430860f677e28030a0d106982d012420556d40cd10222d65c49238a4d116a18b175c46c438a86a5852c4c48bc30d594840c4a48d152c396294b5061c2a9891ca8aa70d9a1cb93171faaa0be0401c64a1822aca2c418e184d41359c64c41a144145ba460e28a6a8a2e5454550106cbca0a27ae1883451459575950a1055609ae2093b585165c90e9e1221fd1508c02e93bad76e36ee7e12fbb5ee08d1b1c188e9cd90e1e3d5e8700d8c940830d441e1f3f7a7c3800f2d3410080823c101a0af201911010043080108ab6110144381a8244a448018c1c416280a42407404002942860010c18a1010e78000910888004964ca0040a9850010b5c000319189934d1c00638708213143aa0e481271f480104211001141556589ab4c9c26c6146994cd385f9c2846136cd18a60c73862965d2306b9836cc29730493cabc613a4d1c660e538759659260ee3079984fb387e9c3fc61424d206610538869650e3189985766d42c621a21e71153cae5c40719fb0b03f2024a3046a9ad3e04969f9535b140b3e79c73ca39017caf5b05a4eca854ecd8e992562a9a110000001a5315000020140c088542a1509806622ee61e14800d86963e6644950844511aa3389261209a310600838c013023403052c200e2bc81b72899f9e7cd6fd94238a6202ef7316b79e56720c2df59f15d4193a3422d7f5c7fd6e72626066d5eae68c65d70846f165ad570db2644f984d2952ba1f4e0e586ca8c371cdb51c4f6f77d77b6616085a60f624cdc9e0dc6c06f929dc35e5b3213203a3748268a061ebb5924a00487d941f763060fc7d3ba613e0a555fbdfda1f2bd8633d15304cf0398122568d56bd3afce8293915f1dd891b9ec8eb639b13be4a9e945db66fa17a9b3bf4a9e6e04f2513a4d8b368716b6dc3fe600652f29387dbfab43bdd8c698d5a0cb29b303139af69d500d30ed69d5a0f3cc21a78306b43c8ee9eb42301d35d3f111b422b84340c03e52ce0800c03c5d1aadd1103ca840326ad89d14edae928aeddf06655fd8054580bf7fab038a354b85f296a9918481b5f28945d9dffa1c53f85bee953d5863a4601803ee49643661d45e041ff98531af7f5613b878f8d5d52e46a3e2865da20efa1102ca37fa4a4e02cec7d743f9475a8dcaf0e14e6fc3f4db09727d561b4b742c5a77bbacda1dc07866b5a3a32988de12b71c0b9b48dea7830b802e65f00dfc029ad1f82f5f7feda24371e01287d1db568c0255e39d00983baff1e7269ddd2618c5bb79c63a748679a82debd2c32c79b9ac3f2f755277b8fc2ef4a11311a5c8c0e2a0560a138217524d607c503ee1a4d9efd70ebc87c96655eb7040837e8ab04919e28a6c623b96b0b54313a53227d26357a8ceeaf5450a9699dc13a7d5bc691205c0716e5b6d42ba580d86ab6232670c5c8d1a06b48a0d346af5be24a4a5440b3e93278e1f1e152bdd4b198efd6f8cf45f53ad1aa69852b31c8d4881c38146c0b028b21603bf50a8f0cab564026c09f369ab3b91f7c962e517675f7c23f9f3c44b7c1574b2e6799a58d462330eab8c25dc34d6a9b2698575f9c379eccea95d9b3ee5c14cc0d3cdc078604a30c0aa075d0437c5c5d3c50504ef991ea190c5ee833435e538c176c606662cd193aacf527ee6cf4fe6a2852ff3d025d218a75801f149a5484cc8d703f25ccad9a19947fc4b56dc33cc3a60a2d88f42a0375cb49e7f4a18c5f6ddcde3c3b479fb9832bbde149554f6f0d7f1ebe1f3a32f3d722c90bfbfc9f25d95ee9fae61af2f68cf847731a078558e5f9858d84fc4628356dab389a8d38cb6d26c8fcf6311a43a8de227c46dba0d34b1daec67cb564618ecf124c93eff025b4955a2d3f738915c805796a65e3a6e0a7674ea6a89bcadd5a89b3be58fcd3d69de8f59370814fb7ea02cf7f1b00694e9b31fd00fa807b07d10fa4e9f0447df7e93033f2e0c3c36365993e1da49fba9173ab4eec947c54e6f0f2c184d855e9725ebf48be60afa19053011a43a0353fabd99c4b43676c5610a55ea1bfa35ba5325a750f315f2f13d06b113cc67a18a0d547a5e85b02a76b01b1da7c35eb0871af840d7b91f2c60b1ad80e5351a6a526f49115c3726f0ede861559fc900d65b5c675bd0e548220760d68d41e127c26a11e1aebe2c9628fb2735676dcd6e423d1303d46a2bcee761964ca712c3ef1b58f8b12b74fe0bbec74da5bfeef9416f90c34d028ddbef4c31a6a5a39e36fc311c9eebc68dc756398c1eac625070c1acfa8dfbd737ca4d600064b03ade029a51040f6d7efb1ad94241d662dca5776f80f9518c19b154c8b064b1b87fba8981f0bb3ba40fae8dd4c0c74c2c4c2baccd0d9c97446dc773b4d53cc9a60d72383a78acc78d4e598702bccc80dbe41e740e60ade3c209b57cfcee2a097d661a57f9788353118e2e6944f81a68a750c34635025b81047c3433d011b8ff9a7c262bc1f383761486ba3ad7cee4ffbac6ce04e405e454e9695045dcf28706c5fbfca4e6948cf41cb353b9d15b983130a1099f708e693f8e1add347df153023559984cee54ec537866262c8088731f39283370ef6c9cc245d2e4962e3f09646518c53bc3b61188f5c044e45e91260fcf9b7bcf6a06df0c35902601bbbcba0a0da24986afbd612de7f7720a8f1cd5145cc91358ddb0bef95df19f6dbeb02135836a1f405dcf40b85aa04e6ed39e907429dec5e1cdea3472e0b7ce4938b47012a8d0755857b8e80ad7632944e3f322ab2a7fb2d56160a9f3e1358f8584c399bdd8b103afc04ef958704f4eb73bc1ff53b89a2782dcf13efebe0ca17bf3957df2466148761880605472c82f24f3dc662575c9cd8dca3e65f68a713321d67177de77e55a965644712ee600d17a760e724c5da0da5d41a5a799449b9370c1281ff496e14dde1f5069be1799405be2554b72d4bbb836a9e5b06d31288b464ebc5a6c76569269ff06e52a409b6dca59a37fc7a102e8d9c359d447614a880409e8c5fbc5bc7c3c46536103e650ea0e0856a5aac4a5e1147c4fa46e9d7eec862e76ba00664cd79aa1944130162196065f914d019bcd1b55a00d5cc12efc0b9f1fbcbf48790ecd4c5ac4ebe89ad469c4bfa4479794b8114f1cd04db45ac61aece26bd43c51e1156b4c3c499faecec5349a97c9304edb9dfb44140dce5b07cbdfa8abe5fa7869ff93e38e09b24467a9970d43c77e62aa7d2020c6e613183d3ef7a630ef56446851267735e272af9fee95ec17c39b3e589b41ae20461847f342c8d22c4b3c28d6d1d723fc7d3c8d9ea04365266ca2f6dfaeeba9662e91c82d820bc157e222f70abe265dd3ffbb236990c8fe485e66860d81286a402ab310950e700f60b1f4ac262a068b292b3e3cd558bdf128a0643590b7aee983c538408edc7dccb1a8ca5791f9ba5212e63b6a3bf20e51151184497ada94a07f3c1c2b4d0aaa2422b4217cc9e1cf4eaa66a8bce14cd267bd6e60d13fc343f221852206855b9f71d7428936b37c0411d29eb12fe61da96cc93b5c4bfee701c875e6e79f4629f42ed817c38abfdeb87d6be6d82af3a342e3ed8b8b341776b23c5edc42fc1e9db4de12ce3d93c9159b9f6b6465e2de74a3d496662d0290d8d11efbc0a94a7da4b84d63838671389ae4aee356740782152d9565383ea3a22288649ef2b7045c9c5db760e1b05e9e112b6e4b50e0e9fdfa2cb9e79d7204a42778af7b0fbc061e16aa4ff9ec28dd39a248feb2d4dea6e84cb2b5c6d4ce19a453c1dc51d0f40c3065f7913f7323b0e79122243e8f6e481cc5058fbcaad7960870327cf722ff0947a260c8e5f71c7f72670f7883d64ec1a2fc45c88a2199f84e7c5f49be80d1c1392259b7580268f38fd5c41b06d0202454ba5e79d5f6a98bb412b6639ff57020da4b30d7a13a7b6d0d86685a55a629e10c940a8d2f58ba06403abafdb4e916c697dec40ad9b6c2c336a1676e88c0f00c65e445ba53614c3064658fe9c261781e36afccd7884808c97604bf4d485be8198d19e4ba3134092864bcaeb80f29cea2973c17e3d7873cdbfe54dd48ad7d311002e1c9365e0cd7bf4ed9d94620f6528c4c2cf3ffdc6dc82efc1a9a1cedcdfc230ca473f5fd7e83ff62834d36791115cba1e96a503af9d223eeca1c8ecc9f830348963098ab221fadf84c87c2a765a45570d4eb50d7f830a65ba0157e842a23a8f9abd0c9ff73348735d3ec253cac949a5eb40bb5ff23568191d0b6c02e2c8925eb976758de3e6fa4d73c2b409207bdcd096c1f76a6e06b30217eb22772b8ad39bcc819f97f91124240384ed84733141a4b54d5b96759bc4e90b3312c9b7771e8f535c8986d931a0a9b365b101920956af64c19f449ebcd678bcc7efc5c73a92197f5fa5629227d883c4dced4b2fbeb1ae49de71f6d6ff052c815d537f8b087b7c6b0cdd914b88cc104a10355ac69f383d3e3d0456c1cb22d3772a750b3c1626011eb3e36191baf8de2c459599cefecf5b8602917f15c8eb3596847b2f1f21b58b882995023a5e7cac2767dce1a8f9f16a5e8d95b8445b4e949ba84932f0b90cd15320fe3d237dfde415e6ab17d9f3a3afce9cca17b5ae3a2e706c0faecee3750f125cc104d5e95a16e6e481da1c7991cb9127801e43c3e0ee0280ed0e1f276d93da76783df2d360f54962d0ca421812e4269b2fe3b43f86debc6bbda8179326201011e62e6fc5fcf48ff268e83ec4cb3b1f44a6e0e4080bb7c3f1bea8720e7620f45f87cf35dd3e05e80f357f87f70db8b095b917b38df685a4bcf59a4686a3847828a571d019550116edcb2812f7e9a04f0d6267380542503804048a6ffd2b3b8f38c05db4ae9f462cc0da1a963ba847b0df8a0ec775f7817b3a7a24b86c7e57a0a4a10f19d9509415089557846623d1ddf938e1d72242743114aeb0e4c23afe0d7e56638747dea688a4431ae834284bda82f6cd161c620f6601ddff296d6c65c4a754e09f5ca02692d57705c944924b46aef351ee4bc2ca11bfae85e06c1dc4c59de534875e42a14c499a5a0a55f213adf2d4da62c1ecd55e0dafe9756133e86b3a038b7ecd0db0f32de7e3af94eeaa0d57653adf62e131b085c757585a7e0ba0be4a25a8a23df3de50d8dad786cef7142b2bdfb24d4b1fc205f8a450ed9e858d3f8240ae1972f3e906080f852a926bf25315031950d0f1f66720499f819ff31da02143f676a5318a04470038a9f3288bbadff3e00e028cbc9d1077b201bbe547be96ff810736205ce889171f2749ad182003d0ec8c8ee2a82b395a41b3e8c90b48a937605a0d90a3b8da2b575fc5496e2a24e04a4c2c8465d34c99ee11cd1c7d09b3b97dc65837547222c25eb5f8a9b87095da22870a2b1475c9306f7134a6a23e3893a42f69249cbdd3bbf97a0cd4bda7b64a8366971b6c215494d6fb841a4116a5b0f9c7c68cea28f1c973ff276566544fef557c389b13846d89d572094f8786e6d19858c4538697eed2dd0be18d2a14d581137ac04a21fef59a7697c6b37abdfd733a1c7f5c9aaa69d9e1e69b6b494ed95eb4f1a577683e94b9bb1631cb101284c2c4c9bc394824e1c3354a8215b9f512147e5bfdb71c723a7bdc60361c0aa41c676d00a2b7db66e93eaedc344839167dcbae76bb076d3d1beb383d8b5406233dcf0439af87f7e86bd73d42bd63bd86d47c2c4d8c7eb223f86c400b902ec0d55e3bb744eb2fbf8da782a49dced8137292f34623b034ed6c9da3588b1ec938cdd0b894407e1f811d5ad5d61b84ce5f9bdb8007cfb3520d857f9765f62d8ddda5f0973a9ac2cd0839190a434e5a62c7f67ac52560c47e2a2edbe56f6fa0660d8652691841966f69d88856ac048b93d1538e7ec7012eaf9d3af9cb716a1c13c9e20caf1c152ca5465a1be6df36b7b05d738c009f4dd60d720526d772375b058457cee3825413b021663aeb17fcc26b7759bd0f5e1f1022d7623bc47ef50c86ea07c5453cc44fb9452deb8c11ee8c535b52901513b031101c28efa7dd0fe62b3d53bb53f5a6a8a5ed680413c2e722bea9e935c6919fdbda6d5ed4bb8f9b891f8f045b60e77ad31dce4fd096011ec46a95f1ac1b7ffcf39184ddd4eb7bd82e49af45c054f568bc5f22626c512e397ddc93e023e7379d357ceb73a6447e5bea952f206553409643bc7bf357ff60860de76e6716306127e580df9e25ce2524115b0681bb4344bbeb76f49f7591f842b1ed698e26b480a78f6f0c5eee593ff2c5a8114018755abcfc5bbd4f11b3bbc5590882f8cb82c1e00f614db9e6b7773ffe1cb84d0141a6fcb85cd7101dddf7c211de38c05756ebd0b378884e28de1ee3101cf398010e5242a1f2d58fc81bdb937e76c28689e0c743ed976bf23de71ecdd6f501adf74ba9f0e4f00849b98371b3e330e49506bc13a37c5520a5bd2c3b78c3c9ff1ece4dbb7c87c99747627de3941dd0703a1c4c19c42503ecf6edabe189d8f2ba864fa9f052585fbd82fb9d863217421de006d2200b4377880232a199ba26e7c39627cb2fd2d1e16c81f96a5b044878a8319ec215b2182df011612e3bd1e3283997fd82725181bad0e48d7867d3ebf3312aaffc0fc9b8d48f61afbb590b197aec69df6c0968b90ccd11e45a560ec4aec522bd5440cd43d3542b37aac71db94355e8cea6583edeb465684b99178d30e2de6de19a45224584c49cd531e2d81d3bb95fa97569d2a56c39e38c9e89e46ce130e6de1867ffb2e5803f9e8805734a705a699666bcc0ade326b6236cbbb056289950494bdd34f0d2f6ec26f88ad67fcfe028954557a8a939c42484bfde452b644e63fd2dd404e6e172088810431525f89f7026e8f6bea92a27af34032955d78060083fd40e44bdd507c011c4e68eecf9a13ff40031b102d60a7abee8bba18a57076e3a3c9b070b03a6ca59684ef810ade6638bde1bb863bedc0a1da6a8278429f41e138a6766ae122f2ff014864d3d6ca0e17293d5baf400209a633227e9e824737576cace05089c6daba68a0600d23d4d72150bcedd66a158e2265a85445830b5532a67e9f000436edf6ec90a8d2a3554a1426c38ffc750418dcdcb5db40c1241bab2a1181c2b5cc243f4740e146aba55d3856f2a44a050928486596fa3f0a0ed9b058b242e1a54eab6b910102148cc87f67d0d0ed55ab050444d2bcae8e142a58c948f07100176f5bdb5a8522250e2aead060c1744689df83c0c0369b9d351c5ae2b0b212092344638cbedfe67840e0551151c5ee111b76faca9262327e697e398f59fe54fe1c3e196f39bf24df2cef2cff0c9f14bf9ca7bcf0c709e9d4a03d30f960487ac69389d2e20bb9cb21c9f288f2346fc273096c34f946438d861c0d3f183e26cc20b47168e390034347c38f84180a371c6e18e260f8d8f0815046a18d430d861c0d7f53031fbb670c01afa0760822d2aae28824b125904b23b04874faa18979ddf2aa5a31b7b392c7c9f1d406517e9ed0ca538ed43bd82b53a4e23010c6a8ed15ac7b5abdd874b0f7fa61cf9a1d267dc9025c633c5bc5855a93cb13c5bfbed84e9eb51c0ebb85fcb41ba980c40457629d764d09904b9800ddd7060ec6456c11384b3c06f4d4da0a22b942d551fabc8ebb6e6d0e7accd4168b6449114bfcab358eecdb0c0ab0a07af0e4c840a755152d8af1cc9fa9fafbe5040d191a1d04ee13664c132867aa8f079898dcfdc1db1e0f60d73aa542b75e860d72dc2df1020cd8652a6ec310cb6f143ee63b848df5ab40b254ffad4f3f2a33bfe7d88a3251630d93be51cb333c6ddf6edcc6a862c3e450da8ac972a306e23b74e8275117fad9d89b00420337c66ad01104f15bbb5824a4c4c608089730b4b0c9228075365139fcd0b9bedb38704fe1c7c28c4e80c7965d3751e6746038fc9409cbf32ee2f0d3fc911bc6da33ed04c7155800a800929c3763ea3f2deed7fc97fdd3f61686b14126a995f074949e622156fca4c88333ae414d1fc8e6b0ef9b1cafa978458d0174dadb79805743ad61ae0c068c5d1e7ed40f1767232ed7067f004ea14575b20ca0f04898a73b789e1301394b4b8b91989f38d36f6bf33725890bae0ee3994de5f87c60b6b68fc5df2999055468af7e00003c1a99682e2bf05b6ebb6815f67f27ad51976159dadeb8de690cf2635a9f8ea67d5ce848369a1941e00e2f815c8bc6199effc3c70b000b79917fb1a6107ee7e2489cf11d8446fa1ce223eb29698b484d47468e3f4a828ef49aa9277dbde84b6f0fe436f6d95bffaf40d592a58887b1c746a660df8a694d0ac050a9d01e1b38cc73e80b7ddf7aceac7c0139de9883ffbd9ed2ed57bcd4b91e6f24b0aaf15a6dc124b271a91371c862575ab3fe10f4b963211fbe877e7f6f09ee3d72fc000ee43370d138c5291ed3cbe4c73a4c3acb9c75145916cc3fa9ae775443c177584949c0c7940090525dda2343e937ddda34467563d703d0e30d8ee3a0b80e8af320380c80d360dc0dc671a0b8078a7b001c0cc06d70dc06e274509c07c539001c06e16e304e03e33a50dc03e2a807556c9ee940dead9fbb2b051206fc950220a85b2067c91b5b9d3e5fd100384de83a9aab7509608f2a5b54479e5d0aa28d47495720adc03482d00844151c5da0b402290aa6100c45306ac1a805a4149032055cf4c2921dab2f2af9fb202f833649ceaa9749ff7cc89351331927b5c5e4bf3df264a899d079cd12a97f8fb655fd42c9ff4ff9996849e4a8ba90f4e7b3fcac9a9338525924f9eb915f56ed449dab2c90fcf4c88b5d6b52c7b58b257e3ce0c5d42ed969d565a9bf0f7860684aeeacbea8ecef87bc0c342438575f26fdf7515e468d091cd42d93fff6cc2ba306d20a26e0a4b298fcb7679e0c35933aaf5920f5ef313fa686099deb2e4bfcf2c41b5b534287b5cb657f1fe1c3a42dd1a1ea52b9ff0f79b36892e4a87291fcdfa7bc4cb51371525948faef395f46cd491dd72c90f8f5cc1f5b63a2ce5597b5b487f05f3957a2e2bc3a19115fb4094434904e5513d1fcc07e9720f58bce8c56f56f9a127a3291a103a03fa19da6a481d1b667639227cb94274dcc3f9200ff85a5f316e5e2547fc8d7a281cadb2300401732b8b42a4f28d77d30731258b5b647e1639700835fd4683b59d99a50a28e5a8506e2133753073b8654689ed0dddd208f95f159f51caf8abda5cbad49180528bb7ff87bbe4df882a563ce084310b3b3e8b85d559ae817785064dfb9bee6ccc6f8b3965aac4f4fc5ffacc6b04bf82d5949d24ddc836a211d4a8bc5d6aefb50f9e3c058a910a429a5a5ebee014e60014fd62ca0e52b2657c051464d83270715eff06f62ed35be36f0d5b534eea3217368f4729b88ab505f70d821e26754b37f5e46241b30bceed67a401bacd48bbb2eab814d5601040e0123b3b23009e84f17a6931a59688cc6b20992d08210e88561646c34968f540c471894321444c60e53ff66f4caee184ed262684ae6ecb0bb45065b056c77c16eba925a13b11b582562521fbf94873d619eeab70531e24714acbe94356bb91915c0fac77c542a93b488724726e8d6fd9e1a49216a7631e54a89d4da83b200cc283bd4d5731180441606e3d7cc53ed285a6580eb22dc7c814bb801b0fd45c3a95f1d881aeb23c85cbb818bdc1267304b300fa1931a04c97265ced83100e11f14e58db4695f7c1c8f9154906181106d9835d501370c59e9948660ad847152050f176cf790761b770943a707586b658461134187b090bc5d141d0b490e01861f715c3c5723190abfe31685d8a2f60e098b82359419927ef08cfa9f1257c6a0c43e8a1e375b7a460c2084c5c8c69dc9315dc12a80a46e5eafe083b67a826015c0ad9d26a66fbdbc2035ae9cfb0c37387c1bf329c9827c7fe557029b6add91d76d70298e123ac84fcb22ea6ba6504c237bb872d875024238bcaffdc7da628e79d15d5b93620315093de0b9da45ab349c77125e0025d3e14192ffdddbd78c992ea16c449f177c70db36dc6ba90540e44ad7eaec08310b4eed30a3df91ac1d72625c5f80f1e1c68b700c63bc1472d7fac01e7b1e1e1d5cab15ea14c89bb6cd3f14a7e2074df41270dad480aecb3004e0041681fd598297d441085ee3104b634c22c2b123744afdcc0a9ad4e782f5e7edf042f138c6300dbcac674bcb1c1aea0445cdeaf7af129f5d9a11807c3999068be878336933957d889cd239c8a5d84869ac317676cb639f552d1ce6872a78a7c307e1282e4992e07d906961041e389fb11d767dc59235451f269a33781a175ca40d697112c4019f772636dbc157e396be82e5d36fd8ce34036fc3d0e34f1824c5206f6c0f7ad4623cff513d1ae8b997598678ee300ce48f30125de34e5ec7ffe71ad0a71b18c0b9a297fe0db5c3cd66c66b940823ca88e66194138a1c93d979f5c5497187c71a826d3789886a1e6723ba6f82a1c11cef5893ca3373868fe4625ca454c482d179f2d961b4724a0d372e84e8e47f24c2c08c32569dc1d69dc6e9f000d4939d93d25b814ed3b709af4f6e2132bbf7ee55157c27c9fe51f9bc8efea51a8bb93aec27ab903a9c277db20b8dde60a96d149e539fade01961f450c9521889251468649401d99e3538308dcd721a4092ff426d1dc4e52de7a05a902bb29c8e6cb4c6b400021a4be749c5117954894d4bc38d041c2e025eb89df769703c125d2fb449d3b9f825e20e0aa4cf309d77cbdef8d99d7d19fc8be3c44b942beab9e2dacc55fe5dcaa3cbe4402a6a29edeb54433a59c542172be559018c2b2cb972441f3078cf0f478c4b3ea98573cc54b9d39c7a69c7eb702ecd5ba52deaa59da39c4e6db914b92693c743facf9cab8481815aac13f7d9bd8cd655aaccf55654a1fa188a5167a1dd5c7da4214970dd09aeb67dbd7e6de7b9cc72a491c6d0e443f655c03fb3c9d27585162f326ca2bea75cba0676aaa1f7ec5661c3f898862cba4d0d6390992b98d475930ad4219128f516753fdec5e9f9a3261f88c3d61bf3ad11795fa5fd8d13bbed798f3ae5c2ab572aade07c861c7199fe5de3e246d6bcd7685c0c16cbee624bf8358efe934a0443d68be4c9be174e730b76c0261e92439a23dd8562f1e627c3a72067ace8fcc744fa54ffcf29a98ac765225a52e5c64f165bd3171e2256103ea07815e661cafc66621aafb037eb88be171d14db7b3fbf322f2ee8ccfc69e40cbb637fa6716fa5601922da82231017411fd955f291ff5b60f9e6aca056464fbc8ec546f582eca333af1de4f8be44004f5f49e37d8629824a304d5736822ee25d045c4a955c42cc154e267ae73830f73fb4400ca8662a96ccac90561a3651a6c19723c0b279ec9a6b10c600ffcf6f08802846d2358ec19624f369fe6c05a4f5c5fc70f1737911e444edfa7d1b5c79630f852ee8593381c1572ce2a01bfcca1b7d0d2760d39e25463f917a216217f95b7480f8c35d1ea78fcf2399c6e8cc74486bd29a4ec7aab838a5ddd2da8336f85dcdca54ef3e71ad737f8dfb02eb7cd92a0bd07e861bf766d8a1f898cfba50b5f9da3215224b78b2073b94e35e81557b6a420bec86ac754f18d25a279c6753a20e9cd8619cec2ed7c5e40f3fd0d91deb6d5b695c30839cef5afe5694ee893bd8c98ee16837e97ff8619d76678fae59038a343171f6e48881a14ded0777b8f31d467ddf88c7396e3c28b5a0c0b1130bdd357d4f57543cd76bce087367ddb90aac059bb9f7ad5b7b7864e05dcc0912e5e001fbb32cdae097e6f7dcb8f8ee8abc40d111d336e43d78600ceb1654c6ee7a2cf58a117111ee599ca301f8e51d390694c6852b1258436e3b04ae4dc61b19948414e7769919d74d76466c0c5f085272b4aa891b5615a2158fe04e2c0bcf9947c9d22d1e7c08a194ed6516285f5b22743f1b3219755b0ef53d2de56c62207b9865319c97aa71205eb1a538f1dcc31bf7d1acd549d4316199187d44f553d8f4ca4b7b37148ab57383e182e2fb1df4660fc5acf0218b81df436baee404be7a864e0456bec5e71e16de4a6da1e46a3db9692ae2cf9b3eef3be15c99c5d270273c2822b3fa32a769a55b1bcfe708df6e2bbf6b0da0711953c2b8f0c994d21a2b6a0141ecbdb3461eed3f8ec0d40fc4cd5f41728ed510676822062f80bd7b6b3303fc0b6abd4c540ebe99cbf3cae1c2406285d4d2d8e196fe5e32471e96ad92874b4617179ffb70175fc3faab89ba677b890e7b54eecd7b940de69829815257d0d18828705ecee8d1e1ada10e3c4ca96662d1987e879c69c5fa8ea3006da4a3acc9ad13b02cf6c9d79cb094ebcfd47826f4afcdbc443e6cba6e952acd52dcb85b5600fed6f06139ad32680b4552d272c4125d6f87e8d6a10aa2aeaaf64b83f21fbd4bf11b7135ae9e7160db71e7c092d171641ddd2210aeb44428167e1b1f474942481d646991391424788d606f8a12e0544bb11edf5e53413b556bda8acf173b43bf0a80d59a65678c5435a356746fe56990bdab94a57142e3d472623cfc1d71cbf21da931ac49dc89c53c667928155a945770d529bf1335a7869bc80588461ff00e7a4b7be008851b841f29c2050a0aed7bf5d9c8fafcc42baa72df290ad1460150a57c55699ea612977c7200c375657df1acdef3a79437858f541ac3d2dc8702ede5f19fab9913ab0983f77e0f4c5c0a7842fe316c6094f303cc84707f018ddb5fab080a201762fe80d824b7be5e314a8c0d071e20ea23f470162765fb29875637c24725d919eb3c9748025432e9d100f2ff89c44757c2511ec3fa40c4f2fd3f78bb6640696eddff515e7e79e9d2d2877505dc676e6d8f20375f7c126739b5d634082f53d68a29b1929f526bf701604dca66981f86a23af3e80e264f2750cb38731807453791178c54456fca431418662feddc54784cc29a18e5942485f609b4250c7a439553b91b4ac79397712b8c711e8dce38a6243495c741de7f4ee93b3022dd89e03c0ea25463854c1c6c11c6be59a07833e5b21d671838420c4a23d66dec9149024d0425e86718e431fa799261669ae56685a03c2b8c21199162637f1effbd81bc538df7cb13e204bd2470b042f2371b542231ff1db1437efbb1a7fa53dcb25a1213c96ce28db42568cca10984c75a1a8a2c27176572da05cf340fff011c729c307ce33bfdbde6d7b315393024c2282bc5ddfc46814a12d41760ec5f96df39c397d54adac182132eb666aa8766ae9f5f680128105f99410ec7f50859c95f61c5269a63cde2bdd02361958a9f1ba3bbdbe5197113579560252aff0a57119a638af448cdc2ea2fb021e9dd586c6b519b73d974044fc3d1619f30f3e28219e3efa78f54990ab470b95bb035c8e01a31421766157e5544f5c5d615890fa801adda41379d19b1c5a3cfcbe92128644abd19ba41779d93590e6492c8e906e7454805da0cd2679ebeaff1f941a278e3e34cd2cb76918dd238faf48b943d4eec898381394a41bc3328518124d8b3a954089d52c9088ae045065fd54058d9bb60516b11a76bc3c24389a0901f80747210278c631e381384edd8308b1c7f866b30852a49bcb74411cf8fb2c1901729206b55b077c3ea573a6ff8d26e6c808942ccb88c0222670bf09b3df601cd76e344a20d53feb9f016cd34d9394412dabbd1bd7fecc750dc6aef2a40230633318f76019b0e4c89b19a17d3c63b6c73b3ef5532f67942bb4a7f4a16c16a0d60c412b311501d0d51f3a5a0aa8d692539b87eceaded56ac132e2acf2d9738ec4944a45a44c40a1eabf38f1149be81277190664186be65eb12f61b027c3d3a0c842819830d212ab7635d58c976c14784e414aae792c9d283302a792809b2c02e5db13afd385c2e6625d9f79c07d58f6093bb4653d3d0c172a51c94a49c0756a9b7f8533499bbf3384a925b153d06169c6e02367f8d4ae0facbc659ffd89c3121efbee219445f61dd6eb9a057e199a973627288034013206dafa58b194eaf76090d801219e77cd01df6a1504d5f57ea58d351fdc20be8a9ad5ed4f2ec78320c47a754ee8b0ec4617a3935ac5139d188a575c3fc01f52334350e14d65891dfdd2615658da107bb3b5ef1bd177828c96c3d9df2cafd10487eca304507ef4ef022b157d4e2830eaab088f6e5151082f7f43b0dd0a983acd8d50862058db0c3fcc3fd5863bd0c7578144eb4e42431c2c4d6f435ce6f795adf34e919c367bae02b5241a32e451c8db62e7a1bf275780b85e7e0b8996a0127d920398a6ba60531d7ce9cab62e3d12c634f9cfb015cf027364827718d40891abec56e83e4ab53bcdd1da577583d8b2ead4380bba0ac41e8b817b310254a56957e14255320257693c97fa87266b1aaca70d561cb397bfda00dee61f0488c7e01295375aec4fa7483532aef4c6d1750f8b9e2f56d1816fb3aa83ec428485c02f2170249b52d0c24bd5854c8e3a46a92ba5410b709952e55c3673f58c7d166d5bc0bd547b7a17347ae9cae38e121b5c4f182a955e286be5ffec09f1032a063c7d48784518df844fbf46cda52aa51b1591514f4ebc0e1260219c372d5cde8c922ef99c5e5f5517c62d73d0591626287b34cd1ccaa6d35159c0ffa71b16e8eb13bc702168e33ba90185c946dde7a7a08c46f79d731d7a6a0ed0c1201094fba0f53faa6155be8053aa1b1a7dd85cf350332a20084b86c4482af597e17e3b3920fa2cce942185c9721636dec466f6f93660b7464c04f861d9aeea848617792ccaa7c5d520381bb1d360d38b2794b1ec9d9aaa44094ca90593e9ef3d7f15a0601477cb852a8294bcd4545727e98fa5d138ecf05f86c6f8723e886985c09fa9d6491975fa00577529f7b638f6d086ad051e3d952f215771cb4abab01758fa1711ee5313270165c8bcfdeb63c8317068d9268b0f7f6f22108a16bf38f02697b873309489b038c6c40280bd28bbaca0486a5adfc90dd0017ae736ab3bb0bdd306b8003c5d413fa2809168bc451b6b61c310af53f64b4d784bb43c532ee440d5409dd25c0303b4402ed7b67b94231a0a1d86afbf5398a48a2c024ce33238e93e27673f3526e87da6bcf9a16e991ad0d13c81611f4d5650d77366a17de0462de76d02b82db9357e23171c269c65dc92b215864b5b4e91ae6dc23e0bc3643a90103b06dc0c450083bf1767b2875fa0c7c3e264b91e3a5c0bd58727282493c2f87f4af126172e39992b8c331ed13e5048e8fb5eaa3efb74032fdd44e007273274d3662ab306bf8bebdff987815ab0156a6b8ffa0da1c7b79b86ab5192fd30972b1c2032eb2db38e0809c44c76538fe910e1cd1a4e785ac2f5150a0752d584b2bc658c8a01b524d339a4bb970bb5b6ed43e82e986a1fc048f9e2a491cd9bf2c78b08ef486aa02e3917217c8b671c7b45f8c8ba700299ed127c3d0fd3f12e8bffb7c03647876fa96552241c9eed3782df6315a43252a4508f12aa200cc080c7e3bb8ee8b8810b8def132f395fecee287250f6e7bef415ff10119afcbfa5ecd1be4add1ab234fa30b8fe5350c13d8c17908e6728bae1ba4fc1e1c072b8c94f42faf58efbbee59de4348271fac73e1dfe7d33ee46b7558f5c4d20bdfbcee3e82cb9f1618256d501a2e0e9a81b8d8f0d23c04dd23fb6990c884b9e026590f985b7b1d31d6cad366394c811a88fc52544147dafcf8a57bc068a26949fc0c26256b9fbc7c3f503fb9630a2dad9f2802495eb3b898cdc6aaf95c1c70bf3630edd9352a5faafdd8b59c78aa4de6a33af874ed960854ddad1495940564679810673f13cae7f9cf014664823e5d40ffd8fd6cf0f053f6d4fdb8a938c9b6784c72659ae660422036e822910a608c50087de16aa0243f3dc44511681a42bb82d9d608ec7b59f56da555af749f0f1a524d28e4610ecc15817b9f4da8370a5f98e3ae3911b0fb12bb3fb1ceb70323214537a74f0516aa8726468636e5302645dbec7b1fbec1f0006efc71af65f4c54d84bcf7b33f71ce6e233ee13c743f169279595000270ca94757f4f6a3f2f23f636b40bd317fecec2243fbad6db8ffb3dbf1a50eaba69872cfe5c2e5eeb6c29d2637faaf37aed8639fd19f8bdc51f9b1341b98ea34baeab3ea9689dbb02572dcfefea6efe9eba3ef0eee9d9c569472deca19cd46b1040753a4967e43b4e22243ace19a2c03e5d295f28df8435253d1f85abfd4dee5736a31ab10e155d39544596d82845fdf3aff5fd01e9a4ab2d3409ee730406192df3f389f53caed958614f1bc1e69361012689030b0ee149b52d508ffd7c21905d1a9050709f6efb9c53884318428c4858d1e84bfd64d10f1d6a601f320ef75dc27ef429e329a90884e58fba1f772fc0f5dd7c210f3bbdc3ef860851841fb59f2a26d249150129dffdcc5ba1fefeb7fa19dbc64b08bd8e4410b456ddc15b59862bfec4086dcafdf66f97f538585d9ade8b4735f8d084c9407525491555cc01a798c5cfd8d6915b653ba1421e095f9f36d36d9d54314e842dfd3e4845af1670a8b444320281f2100b47dcaa3cd6e88f414716585a23bcabe91afdc83aa9fbb4d781f7cf4a93931f424cf7ad41d3f7e9f84dc064ce7c3166bee18272e8d234196161b5f3700aa67c2cfc2473bf94adbbaca9a9a5e6d2768fa521fb6359db929bbe74eff0906b27e5654c0aa82ce381dfde34df49cb993be982fd633df33106db0ea409144e9d8af5099a657d6b3e7048111ef0a8856b7028255e375a118f55aa4c75ac2b912aa09fc79e8ffc4b9ec686b2b7c5022ba457fb392bab81e9ddf9cf7919a07dbda1f41c7ee671f4473deafdcfb01f24ec3d74992d38883508a31784d8eb87d995275d791bf8975626935584fb06f55c3fee2769115e970228f6b7f4d1c2c6428dcdee9083a82026346f49d6f21927895cdea9b7d85d8e79b9e044d38d72e1c925f6e1fbd26958299c4a6c2c84205cbd03a12a57526383052cc0c24c90f62dbacbcad10c44de686572c99702552f8b1b37a9bee72d7f2e7e20aecdd73046c95c818e66b66e6142a8523679822434c4221076fb208746202dc2f8abe131d096881c366668de033d150164ad7ba27ba1a3ae5eaaff0b994323413ab7198536fcbedf2ff627a7cac37bc1dbf624eae3f8b7e8a8805fd163144ff5b9356c87e379eec00102d365a4fe0fbfa650f0708340a39020d484505342dddb0f04658d637f106642c9b55fc6f26933468a51049b8ad3e59b05efe56c047357d553e9f428c4b44dac044f4485e5c85f42a394f96532c795071021e297290f51724e578b741882ca0d4832bbb48dc05ff6f542601d9414462538b97e3df592c901a4e754b7e4a4a76ffce0dfefcff0d54264302a83fff43d7ebade7d0930f5fb038945503c360d5bc206ff5ee18369bc7aed8c57d61fd12f04fe29c8a97c14bf6b434223105a7694cc71d795c315f3e37c936a20cfcc42600d05e0d0b936a2059ad9eab76815c6a938bba286fad6544e463b660065cf476d600ff0fe641cf3e1ecab36ab16e30892ee8ad8c18a724b8759a7b718ce9ae94728b2dbdad7198cc3ad36fbd4eeb8a1855e14d989888b6d65b34be223d6a152d3757723621886ba44e380f2ed0082086126310996e82ec742d3d52045bea78dbd8dc37c5303e583f18db09f8e075586237f08860662393fadc0fbc06afc49a57ad50a7fe9e7e9163566ff93850b988f75a1294bc1ac150be1f449883bc9590124193dd51410463aa68afe6c1b29f4509c660f86e75dffdaacb14f93188543f695f0ac49d11380853c84e2edf88bd83ed99dbf9012f91cc251a6856a240eabc5755dedbb71e30b8330b80b41a75f5c40bbf3929b7e99a8ed341cbe01bc1f824b8c0701e3c00795581cfc9bfd4b5f7de1ce533f9e60106009a1748f5e1798be5b3184dfd696dbd4249aa32e6846cb5817da8280d221e03288b93eadeafd768f4b0d2055ef2a32369e6f71eff7d8db951a88c2c2cec294842de1a62ac0a7c47ecc6f3c1f9eb1337935dab2fbb8e63637cfe067084ef586d862e2e9a48d1875f9b2df6bafa846d10810d6ed6422d8e3f3115f8168597f6f0d7d87bdbc378da3db6a32d2d162502a0f9eb7940ddcf532ab6182f57b7bb62317ec7cdb6ec463d6c802747482951a55bb7842247aa2e847af215ea81e93afb1095cd315b839e4073a97f717f9cf251374fc192ac190390c66451f1769f2b895a63fe6092ef8f8d9ec09a793857ac85684e0df92bfcb6a8fe11b69577b23b0addf2a6cb3806c7c643397de7228e16ff1b4fd8f3722d5450027b652fc7c48804c71ed239b773c48b72594db00576172d345b50f287abc1284ab52c28b818b1906429594439344c6a4e5585a229b40c51565751d52e659851fa1ab908d237e649808be24ea99b0405e8ababe1ca765307343531db4187335b096c689d668d582edac7047878825840ed90a00f8ef6681dd759f34462992265498c09e99f4f779829895e02041b45d43b525bcafaf8e600b33fa5b4f8012059284992b1bc86bbbea350597a498abdf3effd8d31ec6852fed4bde085665bef81ba98b8c9777450c473bc033efc8b7ce275868d1ab9517abbd105b9fc2504db4476eb44203a62aa451ff06f8c38697b7aebc416cf000bf6c17772f27122ab280afed2a2a81705c7fa12754d087973f7011c960e17fa3cf4df062a10882a923b035edc3893ba9d2a77126bf1ceab18b383c53e3f0f81b0caca25b0ec797312a8d57c1e02c096979b40d9e7e625a06c2b6884f990776698c2a391b8cdc50feb8773050fe4c8112f919d25b08647e972010000d2fe751f230b254e1c2e7162f552154ee96b0376523227ae1e8f3602405e3d0d0769043b35c76ec6ca95d9603ba2f8214038b98df3d3e65502f5f3105616d003b5d22e35a91563fd0b2630fbe67a14cc1c130240859c88d04e194c0db43c3cf40cb408ac76ee7e8a761c38c3e90272c712d1254a4f63d9dbb663c7e4b6b7c6ddcb6f9b45779f73fb6b748f1469e55c5970d2fe586e601b75ade37bebdae9fcde5cff7ed381d00f5c40d1876f5b79051c8c040aca7324ca7f83646348f48c1467e15e19cc18e4470b2d4c73acf9d72df9e3c8a329b951ae0da3d18da13229b40197f94e5aac6a58577c7be682b66955bec4f2a0c8aafa07ddf5efcdaec4f35b793f17395d791780630cbf6fc5fa5f1e5d15bc7baacac304111f49b7140c2733d98166e027945feae464ab690e085f60a729981d8975e68c2cdd5fec1ce27e964d8f7b5d8a0a9c23eea98c323b36287297a4bf55a67a6133a7ca4dfdb90d42c8b54f4a11f9e76e4ab3858a3828a9bddcdaa6552b7b64c2571f0464898c05b6f6a6b747b4b5d30c156e5abf1f956f6e26914dd8bb0f42cd8eee6e9c5f2529d9e66e27a61d76e4e0ed4a0196af29ba99ea099453bc7f5529d9676ed2d80f9f270feffd5505c99fbb99627f78de6cf8f75728257fd66d9ab2878c7c52597a1a983d52152027aabe702fde2ee6f65f1539d9e5b7a5da9dabb705fe7c1489e497bf9568f7bc9e1d78f3a12493bffc4652fb734d6fd84d8111480a44b634bf8ba2c214061c08c5c742db378beef95f8636321fff326c5b249c0efa1d682aff0dd9557bfac0739484e920afce4f1c01147ed3661e81413e6fc4c584a48ac7a54e9d3986cc87a81ae2edde442ea4632ce4d0a6929f5856a6af0f56eddbcd9ae7b8a668129fcd2d23a8c9bb8da47d4d16ae987099d1db582c719f7b87d02c20cce0ee19113ca715f61e08b0510174da6ff7d18f7956db67fb09d7987d98aad837189535117a8637c0f15d67009477cb2d6ae2c22e01c5d8d892456885dd30340a6e327eb032138d28c4fe50594e6c164419638a1d74c7afd4132b53b7772d8aeea61ce16159c97867544ace78921f2c1b4168eaf6506cd9514622a98eed4cd1ed3ad55269e2382448742a1c7689484db4c011bafad42dc73d5d64f93b03097a0f9ae5886745283616a789d2f1e5e0d88852acdfbb920581066f3d28336ba02dd0887a79f7ef3b2b055f9bada3d5541f4fc7cb708a3a03c112c19c3d868c525e4f9063946c7740195b7ca0a9e2ae213f4d720ea413b9a2e3abaae397ab33b06eaace27b8c3dadd840cbf5ba6d0dd6f19d8038ca627b818e3fb9d4951c7da80ed3bcfbc046910776a87389f367dfcf3b24c0c1312f8973796161ee298349cd2b5175cbab35f89372a179fcf2ddb5b798ec6f9f4f6f389c69bfe99a1394020321916afa277a4bbdf2486bd5f17d1babf8ebd59f4f2f8bb3bb7719ea973d7edf2d2871e6c796df39fa54cb17aa50e6a6872d4eb9eb8e8e8be4a6a24cb590ab1c5e517c7b18625a022387c174d22b6618d2f582ba289852224c9fc69cc3207ea084305cf5fc1301672e2a809331fa7ffefa04523a67b6fc43bd5b5319c4ec73d10cf44d74efacaf7939a755aa0a683a1aa5db6388174242194fb1bbc69602a23241a81cfe574e5245c556dbda03eac64ece5a5b19461225e3006aed1ea401a5137c07a50dde03604889e7880917cd7da84df57e9e70b41bb5e2007180489fa8bc11e4e8b5a407ed72ae35b15c0df7a0d3ae4a532504696e61ba6f9bda0166b2b8d7fa49ffdde1eb2414418e1df07ccba396dca45d2cbdcfd72ad66c54a74f9c87d2d8fa006e1ced177a8645d7b171f1ca95789a8413de4536d70eaa16e1c24cb1066947de1f78a3bc61c60d43a7a259c3fac2c88ab1acd05b89d7fca604c872103ecd34120ade48c48ec79b0f934c07e47b167163ea3fd0e07587cac6b01923b6ab899ad380eef4221f5b25d736e590f5e6754b8b526b3f3ef2b0f3607c3ff3e8ce465b32826e98132d27039d605b9dd9879f12692667763020c2f10976797c03cd1d17181f0966b1c28e3ecc02f21e5ed3c5e06af70544eb89ad87c4528a41142a17f64ebf53c37b596fe249c24c05a82089e627cfd0833878b6f0e42fa30154bad0e8e60d86d917d300a5813967eede2371672ac81cecfedb7fb665c905b4b82749747712bae563e28afd0464039f17d232d581f42e2d11d6fbb86ecd97e88c260eed466455c4509de45dff9b147036af7b13f2224bc02d95d399279ac5e4be329a76bbef6cacf5135988aad925d772a87af5a5edb0b4afd1250ad4a816ddfb33502d620cdf8af3cd12a99bac594440b70b449a5b9cc554a2d346a41f6a66573fddd506da59e98bcda9f3fdfa4f2e0f296c427f320db8f664ea695a14c39e5fc6ac557e06d6082f62a185e6b46028ca4cd3f5bfead0113ad9f5c5481ded52605c2253d698e7ea006260b63377ee59c46c62e8f88c628c09bbe306fe2d2976946b51eb0c6ff710e08db721f1385101ac163a52149970892eea45666c2b78e941ee62e6ec7d9a66828620fe053b607fb5bb1634a5f4a4890028f14b8b4a835ab988ccf2159ce73eea956810dcc221f6c88cc43f70a8724c6c748123940cc95ab39ad8d70e47aed04d303f3aa07d87e83528fa008618157ef03ed4dda648927cadc3ffcc0407f0b8d66c80a6b158115659586a5ecd8b68814d246a9fc4674578da4299a27eb1618fdb5bd4fa8d188b84116d4e4df7fad24b449f54d696d5344f4a3230b29e5db91af1d6f2c6249146b1f09444db30add7f8e88ff56644e834ca313fb7cb25e394af3bce32102f9b362d73aaa16b9cde0d4357fb3e5161b0b4ddb7c351321cd904626be85561da98739397c20339ec68289b5e58b83e0467a0ce8274e6832eb6e43650224bd2974c867ffcdad9440dca8c9fddbdc8b6fa701206ae776e55908691fd9a2842dd136482f139e1afbb4272de27e0b43df896a91e0fe088a4b2c2bf2d33f11c30c68a19e196cd3ca97331f742249d85e8a35c6fd685f28fa3e66afd842b8e28865035e071ccb12f62dc7100ef6952c032e1178f8db0958fd2b20fdce1b5ad8c04d65410646bef32a6b28709b5d8166e302a6e8e97742e158b353e26b0e9adbd6c951dcb4fb6155f24c93f5eccc17bf9f20b8751ada81f2a1d1d2489ecc3df5e8bb7c288fe91be75c22d6a4b3a33e58de84f6bc2b01a637ce05cab51484ed0a166bb966cc23ee56431200c1366c6f18f4fe64a382aeb357c7c9647c9340881f6ad95b6fb66b2d3e33e6aa1cb041ae66024b0e03ddb2fb17ee287be38977d06c267ec9025bdfcf9f347bb9f1490f2e492c788910cbf486a1b5e87588f4b4d6c31d4f140be49b8d0c689adb3adee6a82e89e9ef1b96b3f00a4b3a81853186140aa4cc599f61882a55ab5cb8a818acdb15a6e6037f85eb0e411a85ab26da0f994c16cacddbd562dd5d9c11b64e4d297bc70cf39c32c39e5b514f30442637573a2d5d5bc45367c74168e68a45e830e72b165b66288af8e19d8d2465a255c7d966a3ae693f92f20269ca9588f4ee5130c91f8cdb4820d022723fdf40b916b2d1c06cb2c9e5708e35c726644dfa2b90fe627befbb83b30a5a59cb119d0f6c663d7b69dd5b4bc410ce5050685387610f70f983f45e5d798b0bc6845c6998d7888412bf77967103b6e399099a41feb3166a887ae81b1b4e649341c9c9e51e6d6108f3bf4ad754598ff0821673ab777f87f861a09fa27096be0ee0b098377719fc331bce8bbfe02ce9e2b24f767a56402ab456f37e0eb21200575135286288306fc9c9dd4a10ef4572a7341cbeabf61d6d5ddaad70eaee1a23ddab6ef09b9c4d1d61807439282c37c798894d692030d16e8e98b9e18e1e7a28934b626b4d105e22494ce31642600badea37e18b34866762aba2c8f9dc4fe641e99c38045b426d6e40069e08378cdeb32d0abdaebe8851edf018661d4da4f875ba70ca42fe75b48cb0edb58e8952f04d181e5ab76413902e26fd1a0e93382b2e87da7a5aa1402b94ff02cc9d2a13d9b56b65feca5f5089f74598e42a5c91869c25c432482fa14f218b60dabb5f6bdfdec9cd2df10ad2d750570728fb69e244ef6734612630215ea29ae0c0c02fade927e1fd177ef2892b95fe9392f13550ffbe0900c9a6f7603e2cb13a77f70ff1fed2b4f4efc2396cd00dcc344809d8ac9f9b0517ef6b9839430a1ee307687a72e588fe8a926da4aff893636ca2f8ce337c7d8e30e7650868e440edf1e1f1a0efa9810626673372228e1350ab8179ea03b9dfa94e9995b3a3b6121418b48af77a4a2c087fdb014601fe736ae80cc26181978f466b221967a2ef7351d60c7878c2353c8141a334c6ce5521b8efc5a15a0b31e6152ebffb9dd5c3ccd35a5cc4d39979a1db6c296a171b5b4e62a97000ddc05b6f0a9e93590eaf8d09468900a2ba254a9dc21c8579009c427b485e96406b5ec6fe0d6ddfb165eb5714aa64036b1d99db667b8e66cc196c64827d6d967c693c8bbc9015506b93b05b317b76ec0eed64889fe618dff9aecbda004915fe88aaea7d9d06b4332245e660571f4fafe4da9e84d32261fb3216bf3c2355cfb18396844186eb8f55827beec0530812aed470a68ab3fb9442c9de9ef26b3a405bca2ad5e97e4c352b7c45cb32e890c498bf870804eb68013a0b3f8ee810182e4aad47d1d65213d3ce905b966726392ce69cf3955198bada521cdaebd77d538b3659c6ea428ad96d7918ee5b3d5d50289add16e33378f28653fda087a527ea08f33e8a1b7241a3e6770f32f0d9b78acab098f8eb1529553e88daa6d68619337a1651ec27659ee9683f36db19086fa73be70e04548dc10235a9a29c18c0fa48d6c04dc134dede492089619a1824587f1a9526397483f13dabae8f2b2172496b66b8c5d860d940216313742f3323a9e3c2b03e59dc7ececc679c49407b056d6c3806b9c8d0123913b6510314e2de36953533ae63e76a5d125dea4da9c5ea42e9f3a9e25599d958b216c2e035c13f04b2615aec119dcc812a6b17b1ee4a09340acb1846521fd056a366c9c7479b49c20731f886a56c21e0796d5ee19c0b6fa4547fd89d653c56e0cb5f3847c15b29eb1b9863982d94f20be6507823e57ac3e92ce3b10a5f7ec1398200a1fb9555ac267625f9868d5301a25969ae2a8d7bc0d19fe4fd8730eb7923e30c06e8fdacf345d2bfda7adfa2cc5652b8abd4ebef29f3190c3dc36f85248876fa2a3387d544ff00f64df30534458aa0381028baed1fda57a5b329ca2a628a30e834c6f7e09af9178fa2eaf2fc49348dceed4f9417717142be3019b94ea5a9feb4b2fd082e1b099ff8350ccbb653b8370b4f9ea4ee77cc01a4c9f4894453645944cd7019e4a09f647024e843e4a0a06f1b639470944c3e9b5f40e28d49858f86dbebc5db762bea9cddafd721e09b8762adbc1eb3f8c0a026636e1a943874b406804ade017f5fdf223a380321c5c98618afb3364209ac28d130f3471e4628473d2a3b23d6329bb11e2da10068d1d6b8374bb4f740919bd7f8cfd9a5de82236dd38332acc8e4440060f8be477c7209a745a4665b8bef4d7629a18813d7bd24ccbfdfed9021c0227a7fd1ac755f644eb46bc9d18c8ee4da56d2abe4595594fa68b54c09502fd59694cbae8dd33929c59fdf546020954bc63472b26f28b3e321f306c91256be8c02a7cdc99e6b43d350fba9d24df29fc8a93030f93776590a357e49ae0d03c40b5b300e499e90a2022cb8743b9e1af3834b633c8a8a6320f34c5d9ca0f298c6a17738ced89c2b4a1f826a3aaa76fa93303a979e3a04250ae7b211cebd2d262fb4533c9796e56d465e1a4f4db56c5027ecfec255186b21e31b5991f615164b2682d3706374d6caa680423159fea37b475770ec849f0534c9a516922989aeb2e61bd965ded4210a2b28e7fb21effe49ce119ac426e181f848bdf3fe6435bcdc9e114b5a6b0576adc87231ba064798107f311f292bde1e62a0f6f79c33bc7f61820d90d4ad01180a4a7096845f8ac9c2dd09c941843688cf3168216ea6e8bd5203853f6f6b5ab978950258a90b2bcb637ec844f9a96e8a0dc4ef08e4327e8e4a2ad493e1560b2da6645792b08d316c40bcc6c2f442727679eefd8fad4c19adb18e07f8bd74537f06eb9530330c0b992a91e0d95d6e62b3acb7be3bfa50ea9d83ad1d00a0b594a813ff505bd01f55381d386c0978bc589cb4028ecd7519d91144ca24b8b7e699c1975c5d5193d697d0240a382051943c2444c1a58f5867f364cb8927cb55b475c0b445f5a91821b175456bad3a4617d4e09ef4ef756179c06611eb4a49cdc0be82efeaaf5cdac56d3fa1507e285155d40212bb8af207b8bfde03c4956795f187a121cef8ae1750865d4e1914bca7710927441933b80c68ed16cd388ec6c8a132573a1e7abba1ad17e9f8e0b9a93c9d0db11e406c7983c42e394f500bf20bed9cfd781c9d57c2c3798e3b52722cbf8e603cd82c3b7692b38a02f42ad838a2ff4930ca63b8fe6cf37a56d9a48cf5878d23ef04178bab4855283bde449035a147bb4d108017f1aa777a72272aa7c389fc5a8db2170fd820991d8c5070834a17edf818828da398614b6aafc9629e4bab6c1547801a826dccdb79f78ccb38b8eec2872c5bc7d6a605831bb2c67a8c8052a65a19eb049a63606a0c1c2b67d82685dbfa6a9b3ab76dacf611c516c62fcfc8de84825393a6fb9d42ee38d3fc3c53da8557769b5a98c6528c5a50146c61927cea5089e9c4d596b529e74ddd3d9d13cee41bb744db68b753894486c6e897c2f5392e1baf303290dd72a530b8192e81c25c66cce8dbb0ba02196aa855bab08ab92774f8cd8262c3ef04f0658f30bf56142999d0f75997a18ace4045b5d1da4716ec64a3b3725e6f252df4134b2e405b41a06d669ed010ad204fb250861bddffe08f5486b81a01d95c5e5dbb01022cb05094c981e73a5c9cb5e9e5d03df8d04cb8129731b93d2f8f9916c2303010f75a17ba8f54f05a5508380159ff21084cda8d5a55e31ea9784b666c4306e82a2115d19f9ed4979b3774acdabfe5bfaff6874fb5c24e1053b42fd5892a9bffe38901c8ba110319cfeb39a03f769b67aca52710c7e88fd75738e1aaf37ed04b2b295326cadaaa6dd7346e530ef88484b1bfa769f50f672b3b82feb7d11e946dbe8c050cecb6ae9a441109ea7a17d7ca98694e4dd149d1e292123e28b31055f320b0f4dfee8d3e6e2520ff74245e1bfe344a8572c5b441172adc12a8f33b393bbeed8c0f7e2624b7bcb57b7da8a1f53fa5c8b599b7778bd85cb1e8b90cd987dea1170cc900c5e80db6450acc99fa4c8dabb159ceb1140a9d2aac75468400494e733781294e93b38273324cd3b9260fc7053b0ba0c69d78bcd230467a9a4ddc5d8c06fba4da7e2e4983aa63498dd69c04a5feae7a93f49c8d25bf83205a2cc0f6fd176d32656387f33c83ce4eb96275f532358b9e45bf6a2acfedf0147f17a310f8549884c3bfd80eb110ec8ce29cf41272220fe960ab2c59964e20a9d4d2186b84b560c40167412c0758c51503fd0ba4d3ba864308742c75b05dde782ef0432ac37deb30add13dac0e6021705649e82d2cb8e30b23143e04c643738ac69cdda9cd97f97cbfa1baae2b076fa78c3feccd32962bf2e9339893301b94f30fcb31e8564afb067320608bf2fc177624ceb4a1612a5ded969beec3a10e00b84db5e8180579da0abd40dcace57de8705d80ba468a365ccd0c8c29397fc10a58101a0b71c4524f8b8e3e85d6b720f08507542e71b29501daea58601a2f8c9ec9971cd07b38a18f3f2bc68ff3b6c7532d9de6c7f0a9a69637f427f2bc787eb8ff8e40bdcc9bf18ffad53c3610eba57a53abff388e44db0da5db1367e80b51fa709a30323c59ea2e0c4bb7c9b4ab335648d49149bd827e9d13fc7e7c977aa5d38dda79c7b9cb600b73a115989527e80f9759ce975fc544bf5e00454763bdbe29c47f2cc7d97aea1368fc44c3fc5d9115372a9e429188985911900c62fb737308e290cec5dd26a37a1d835414d620f17167cd15dfaf2c91c911c26ad604b79195bf96023745a32cff21320bd862cd4b8c382d92e8d1bd75e120e27905ee7e1748507fcd0fbd8cc395c46c641b4d881e1f4a7380a7abf9d64528ae1a0bd256c41baab928948172a5ea1c50862454782b70148575c771211488a495cc77e969c74b4fafe09711c6d7093ce993e1f190e4bc9645352354517c34bb8ca173ac6b7f6e91e56d16a6ed899020cdf524af9e93dd333b09b48764117ce6eceafa4a4a13702538e667f8b04e99ada0b28902161f7edd4f0aa5d13be4582d4553e409425091f71ea261820277a1f3b392e5e7bf6857c3aa5ea07f07211f31203572012654e67223fa74f351475492bfca950119b4a456c0d9a1938a56181b6ece68e5cb76509a6ff4ed0a797d5b55536190baab4be3855014104c153e9e00853e9596f5ba6e5fb6ba70a6c279c878609faa35744aeffcbcf3e230a0f945db6c042ca2fec4ba59e8eec387f50a2dbf815c10a229a659ec44b63b3f866979d17c97ab4d34f0e0819ae8f627bc5a03216b7c1738513aa8905c8763ea82fbf15d4a5b2e543a30a913880f81702e8531d9f9e3ba5a2aba1cc21a1c1201f9d6d3984d6be271c24567791a708e638ec311843eaa32c93b89971d0d0b948d414899597b7808d7360cd5cb10eac20be53dbfa3ccf25984240e3accb26ef25a55a3d4e40f3f83b978032d24a33a07c78b3973eb5ef8f7dd4c63c8c2fcad8cead4589323cdd8ad1a4ad21b9d087f2154d954c959ecf3377c2e3665e9adda15310fc12d38cc20ab519f7ae365737c9b6ff33512a8f82efc44c9b171fa73f85b7fb8241ad0a4d545ddd6c606cc18e70006e4e0d534815d66d7911161ba83add966935550e28e1d90841a64e494143b21c5ce32e664a6487df95e2aa585fc49fb8cbf32bc2be86957dab37855bd4c99c45799a1d39835a02f47f4bacb97aaaf3b6f19a82816636a2f80bea9e4942e18087dbe52b1ec92a8663ac03fecb21747e7b0d2da2cd2e9bb80cb5840c0c27960a577b4cda60e26dd948b112d9ae621d81e2a56f2ee0aae1a270146179a6593246baad2a5fe5e65d097c66e90eef4d04a0c2d4ca9f9863fcc54ac54d9065758b8609d958a5c65b7c49de60847170dce5e6edd6590943189853c27ea5d049dbb21ec523d46b5e0d14a8f528ad5c750ce35580c3a61b4a6e6ff68a6326b9677178fa67e84c60b15998e339492af73ad20005e7b0ae34c7e1146d7ecaf4874fa4ce97dc541b26aac593349b32020a8a6ba57cf188cf3607170fb101f86b4310221b0c20fa290d96e9c42111a286e64490c3dc45f2e8dbe1546fbede92aef6a51fa8480fa5b21785f59571792ad4ca1d7d6b3a5117b5d20c728eaf627ddaa20034a08e10b6538096375847427270c646ea1a797ba6880a0dd36e5d00490904022f9643f0b8fffb53ccc01546726428cfde3313d66d98468914c75230fbd51e112d38cc50a9c27e6da079282c651f9eacf760e907890bdd26f1838a9ff1915e20fd357008b0a166934f8bc4f83d8a71adb96ec23c6c25d95812a28d8924e8981bad767ae1e8e426b1af0dcb24f7306a4617d25598e3188525caef981c4dada077696cb01c2d3edaa301844ab3270a22addf3e2a8b59927e4faefe39db21ea7c8973ffe32ccfa1a245895c513d8f329c6a5d25126eb5e215f53554dfe601e5032be3b7725907d4c5b9c3f96995f5970c6a2e353535626c7e3d8a60b4f402efd6183a6cfee9139c5724dfe2bd5ea8e9c70c3f52b2e91a23bdea04675ff7651c06dcbc35215e797ab1df2a2ca2fd6f0c9aeed0700e01f5127578e807c3cc1d86d41f79f355b0124e0af71bef97f0b3bcbd17cb0078548b656eee0daa5cff37c2298827e7bd3b03050798b2517c069ca36c644bc8816d6c0875cab47d22fe0549d0bf73fbcfc44bd25020e502b0ddd32022b065a4b9f7daf4964d86fd3d8584856001e6c480cbb400da434149dc4b71f6b0d234497f840b36ff8c1da4638dad478c276773ce83ec65074ffc67ff750c22b449b4c40c040cb4966e9b7e56456f3cff643a34a5a135f976773473fdc3e159be69b6b87604e4b04385f9abe759f4b7a5859ce79531880c78018b2277113bec70c9fe48693c53402fd4c1f8cb8c4a371be0c46cb074312b2a2a1f601608bc56d09eb47c9010a0a0cb428865d521ff17b757f6c9cd25a9cfb45d0cd751bb4676869d73aced65105a1606d94c9a023731cf4c01e9dcfabb27a059678697ffd48937d81dad0bfa98590f977e248b39d17aa2d9fe2edabf51a2283f8583e17bdb0241992fd89a9007f0a923ba675320a45daf41b7f0b00490a107115362aa16f1570b9acefbf06645a41a3c868774c7249ae2b77375c94e93c4e9e2a29d8c43a60af2c1f9c3dfaa6a234810105db3795ede906dfc19b7e9eda26225e4eed4ce43e4a4e9d41a71556f507e78b55c018e6a6f6997e3051bda142d4b84c530181b93920c8e258c4991ecbcc8a06eea8408184b88def4fa906f59d2eb096532ea2ebac20f4cb79efae1814086516486f35de3459bdeeb8d9f12d5e95a08141638128c063bf2b52d044773427ef5dee7360270b4a507bc36d37c8881f5a86a99ef3abf51594c9bf079f391b59464c96fc2319644a5be30a1c009ef9c205b86ac903c21c11092daba944714d2d997e18b2e3502a7ab56661501c4c7cd210678f42b6ede3005168d7b55e3c5e70f8770243f9e1be5d489b090f30d9ec24a31eba25be0524fbe5b710306395bb930f7bd3ed4ffe0e2091be6495f4a40ed063bb2bd5ee21193836273069e9a82744d37c9d31b8d10d8b9eb4a87d6c8fa47b579519c85ff500f592df69984d18d40ecf2f3f593aae4493f84c69a6f3b6f09b4dd9bd81d3ea079234cf6ee08281cb5de7c6f1894c5d35757d598535a83aacf5352f447abbb3ed109c1d3601122ef7f6645bee1426f1039aebefb95737363a73999fde4655c093872dbfded9053c4752d364edc0a1be8668eb8278004bc7fada6e1f286512219da67f59ed3ee4562b4c3ebeed8c9522d32db4374feeb79dd4f9256ab82104d13267d0d5d05ad4de6c21ee569f310158116189063624cf8f687d8da80d2ecfcfb5390b568c8c941bd30b7d7d2ff1899dd792138601cda5046576ce52b82a112745d6948cde41b28493571dfa3b80b0ee792468bb009e9c9ea63c6397242dce0cc71666c25deb59e1b4f54ce16c610670b4343bdc5acf74c36b32b5a06f3e6cee020e8493935cadda985761b567cd3b394ea7a1a9c19cc3aa64fcf817e4a96a7e7fb7c81f6860d66213cf187bbc0dcacb429deaafdda5757a41d02918a122103cdaf0aa6558747fa4c32569e9ae490913828e10be0e6956c7e1317ce5e46823f9df6f275cd7eddde90f2ecc1ad638928e4f89d38beb5d7d661d44c3c099e22d5af1cacb7ceb3584d095a579600af5e8dcbe0aa166024377debdf49cc82cf03e2b786fea659f3e58c55917ee649b530caa93a3dc78abca9d0addce4d17bf5e74f34719e58249863107751ab8e964acc9749b568e811bc71c35d67faa6e904397d57165c09491ffb2bc69f7394c9923e83cd39337bdf7982a9ddb7adc1603da7e9b98b91a98d0f960386fe0dee54f01f3e8ff3af17690af8728ecbf7ad2baff247d9c9cedb8e07e04c7663cebdfe8f47d200e119d7a1b43d2e482ea8d9425f27fa32746a3a5cdf86fdb034d182e5ed8d6de535a8a16f27f361ffc852287fc1f8ea312737d35a0dac8ffbdd4b044ca5b84f3299c900854576290dbc266c830baa9966ae14b4f81260163ca8e9d0020bae9b32ee93aa93fbbb7a628e23782bc002c1846b87ccee32199a208c6bd33bc004c92a42a56640fafb6ddd2f34567dc5d606f117c5a6895aaa5708cc2909a761bf988c6e033be00accc897f2f0000c5a326d0771ec4008c649b4f25501305f7e2e6312c142ee4b47615bbd649479bc2be7d8572f091acf1358309109d61e47651738a4ff4d5d619cf0e6ae30989833ef2377ef907159caf89663eff8703c112fe00f10e93fcfe834addce21061a032aee988c762ecf6cc2a1014b9bdda2f7739425e0bc25a0818b2860b16ea7377aef064ad52e85f7ea3398ab808374d3e4efd9028028085ab7be4002b38a09266691bd868718505c36c11e13478ddc35c7b5691b09300c92ba25368fbe11030a2bb832adc916840d5069d92514c3cf50ca1b6083100c88e92b7cbf84051a7877033a754c4391a4d0316dc0f41308a79af4606db8bfa7aa8b00ee274b2b149cae04722bb7e0c701a088bff2d44399191901c69a394b2988f32b7e0e20fd1d0fa8c3772ea557c39c9e8fb553327e8bda430fa2aa3be8334156dbdddf01ad0ea21eb0b9a107e84070f1be01080394058be145811efe5a5d1502fd37c9082b369c40dccae3244282c08241d092872f204ae3aaf7b21fec48530f7b981f29875cf7d4a0ad91ed091ccd8266c4e45b93acfc37d34e81965d356ed50aa22bc7de55b26f49642248bdb744605deb38162d30fc2a0b24502df0c95d031fb3455f60964987088fc992d80bcc52f55c66421d3603ff9eb1555ee0e9ca4117ebff8adea3c2959c1ced5f0cb049613168fedb8aeead139b57284a1e5a62b56fa88ccdc54ca34fe7675d0bafb6831fac4f96869a717b688fe82f71f4117b846d1fd80eb692cff378cd599ddd4a3445fb898502a00abca687187461f2d34d8fc08ab5449785e395947e2ea5d6a817860afba6cfbf0723d100163adac3282cbbddde96d95cfeff4e85da9b4b6965bccdc1ce203c10f64a5fe6dc33a09439cbc5eafaf7d104c26d36912fbe55a7eb02aa0f260e9dd0f763d44753836033309bff29aab095be0fc70d944f494f170621abf4184f908d78fd945d44df28171fe43d50bbfc9cbfe7a7b45478e3d8c0712c9e6f8e509a5610cda471e6dbc1ebda75aa44ba0821262b16f9fe71f2a616940556b7d116ec7c0bbcb560be6c24add594b559094e0234e9302a6cfe8e38954615a3195ea7cdea8b36929506b793e50df0d3b98a89a6d823d0ea8123815e8f297250d33ac85ce0df2e55f01c338c547450abd85542382cec31a165241a29098ddae78129196488981e1b5e9995df3699f264e3470feab7656598ca52ae1ea71c6cd1c3f60491026bc4dc2bab9bd929fa5bfd00c1c893f6b7b4f04bcdcd808a619776144c89e308fd88681cfb309bd2dd7203da1ddeb6c08abdc051ad34e3adfc86539bee35d5a423ae301396736da34189d96982adbad2b031ece7ce3939af8dc4de689fd2aeb2e8a9ac6a2230034d6bacac920588eaad65a4ec5eb0e39891bec00a59b7cb957a0a49cfd0e2cb21fa43bf2ed23174592a41d33667ef5ddef028e86f899cbcd5b78873cfa6cf27c1a918cde36ff40d0ddf646c9f7d339e1a0ac0040ec096e5a64adad5b347fe40038bfcdf95d9a99d003dd8eb5185e0d9a7b31dd4decc53af4d2856649e62ea74e2f2ef373aee9d7cc15889473d724d809b2bbd45f7ae7a179ff682f29aafee556925d1c3080bb65f3db3388195d04958d674fef3b5528284231c95991735aa5d1b64f9300c8980c749d1cab0dee9f89b621299be67cc407da1e058d21e7df217ac41e2a559de995930b10342bcac95d02c7c2f981011cf505592aa2f9f4bcd1cb3028d1b2a82a79215daef167014ca99949638b3ca5903dc073ea50f486c695a35b43b98b6600a7cea88aa6ead88248013b7a48320c1bb1fbaadf40177dbfa50d2f32ac8f04bb85c2942e50f9a6a0e43d208616f32c26b98bed6a34ed8da24071facf8e199ca173602a6c233a40268bf9c9b4db9ac16d0580789f42cbd13331945f54bfb092aa2279e4f032e92cfabd04805a670ba89eb29349e015f36d34d3c9aff267f90f45db44489d070f39fc787de66dda5e6c32f371451af3c6a68417f6de7a4ff622ab3367dc64acf039266559628ea6a73935560b439d2750418678b18588647ec1c7a3cc4307c32f55ebf73480f7b5c43fb56d8c49871374d85a4f38c0fa2df8234b5056efb854814551030ed6a3a0c581bee38d40832fccd155c40f303b5048c0ca7d3e988fb81d36345d58afe29c46e29194d64174fa891b4bb45f88b4f249bce8df5e3f3b0b70b13abdff33aa42b5203fbcd31b4fd40c2ba096db2770a1216e814f9125e91b7f27c3c1b2fc7f3bc27de05dfcdcae5bd40eff33c98e7b52cf87a78e0e7b140cfc987e3adbe0bbcd5eafbc00ff49c7c9f17e4bbf16cbc17f8799e07f3887c37ae9507be40cff38aa8f703c90bca6a0396b7f26c3cf087676303c3f922e402af08e87d5feb73bd1756308463c5f33eeff33c2fc85d9ef30fc8786abca8e1d44b0f6778e185870c1174a96328b1458c303c8a47030ed5c3041eaa4ac09f7aa04287271e9c454b0f61d43855a229587ab8a00456ea9021273dfc107252751c5124868e91229e1baf89181e0a9accd6ecd084a6c0c7991c1704cd88f880c2100203d121241bf000b40606339a8301f5b1e33cf000e333560c4ec132bec17d5386b72c77ca8c6a7b8bbb23f98b9b1e87a1741eebaea5ac65e626832daa5c362e1b50c7ab89cb66452427ca84a69e974febe66504e6ecf0c09c960cd4ad74562298a6cc0d552d1d9fcb0604d22162a444d50d979c1204d261c2472484b505f45a50185015054b9258e6036f402c3f27a802c10948bc30c163c1440ca698f081415641398f470a6b832faa5a2d0c9ccc54b0e30885551513005005c4a64b4e8f9c1e2250a920f7d2376e5441d936556632842e9b950e4b0a54a105135ea08e16116fc71213ccf0c106c905ccbcde18808e0f873545743901affc17264ee0c1f2b9a172a3410b041089cbc90952f450e504235eb0201c32a3436259e18a2a9cb38643191d253b3c2e43564f5c409a9870e372d2ba79e958152d555911b9a1e246d58d6b4907ea65458812951b1b2b3950251429aa7c80404d6e5a301e3aad1b1ca59e1084a8ba7959b980c642156b15b2bc9696d60deb490b8994239cd3e6c8cb4aebc6054427c9c608d864e3a3c7100d825880e4b5c195270d4cb8798dae253a4b8a969c5c39a02b080bb66a6293031ea1535c36ae1b50887505349ae2b184ac7858160cd9bcc89513a5273f5e3716d8149980d48443f4f2018d80465a465421d10126b136605d6063041cb223c98ac80955a390b7aaad82c0156b849e10046005be4b28e1051a269630028815c89040a5a56a4fce4200e1030fb86c8172c2d2811598d1121f0d322842412c1cb0660d1198c181940c7a820071f110012e8610428b1207302215e4e0b4aea0220149103104103ff4c0830e5b7c8e088d38dc1005b5660e13d03e58430d05c8b028c30bb626e5c98d8b88186028b2c9409a2288803969e2a307cecdcb35440802a000e1cb2c4d1d2c5151da21002a0060270c26552ca1841164ba70296af2a30738012f4ac0454a942636ae56132924c0091f6a10000b231460871d5ec8d224e5c9911c4f8e551cdf1ba01aaac6770668c627062b0c4f031f06be0bd87c9163816f029f043e2abe26564b7c526018cf8887c18b086b880e90cfc75781d743e4c1daf9442f04757c38ac9bcfe6f5fa5c2ed6077a2bcf6bb9ce8e9590951555a00b5520961612eab9da302114a28ac5ca7169a00113c01e92803e728038a2b5421588c5c6829b213fca54d978013f585d80b35b392f2a2fa3d6cdeac98f1bd61655af28aa7a8060824dd14a073672c0a862ada962e504b94055ceeeb1a2cae6878ecff58425c49ae14c053840067002d842d50e9e1d3cab2051e8f5435c73026b8397910bca6ac70aca0b88aa155312a1d64d0b89aa154e2b0808849364e5813920d00d15d6062e2fad20ad9b56989c1e393d6c7ed858e0f2b242c109ad202b264e60655195411810476519100161393b5a22e8ad825648a0538e8fd6e7eae212e26a6255a0c36be1ac5860ce6ab5fa56aed56b657333045cb9b6b8767638dd88ae96cb5bb940225008f45e4056424cb0c1807544950e244c105ba09057d209201827f4c8a8af498119194833012f2090c569838a0106a5230ea214e1bb861a4247c21d2fd7970fb234ade9c20214c0e085211b0630e50630302081072800014b0c21346a50c3b95fd0b90d12a8e1c0171670c001c8941002081f7890a5a90a150c2ef061011553905942891248901119822f063ac0f080185cd59a149cc00d10bef8b040c4c003b0588002100045132f04400559085eba64695a9240175844a00a1bac6c4003127880031460851040b080421912a8c1c0170ab0820a27cc547db9a424eaa829830c3020e0802912f0441131b8f0a52c0410be7459527a02fb117524d0050474c02106335f86d0c11215a527301d3aa097418604bad0028b2912f0441345c8100033603a588af204564494e46747047d4d196478400b0860e1802912d0441132c4100017cc8c210303020742e31c7260b9b243470786c0d0020b1e7419f2c10516765449d8ac59a5e043014b8e2f8ed711a0115f11df109e922fc96ac81b7182561baca805187c433c21ae202b20de0fd08767810d8f9d9d5508eec8d111ea04c9018233e446b471bd5aaeafd562b1569e0771bf09739870779dc73769755f9b73425f62d2de9388bbe7ca31e32d0f73b884394d618ecf0ff5a1f44babafa5dad26de9935daeb9de485a2dc57103878d10870cf719b55dfb371dfda151a0509f2850e8b5b6a7e13c11e214e13ea3354cb5a57b4703338ee397252bad2043eeac273dac23ee8e818738465ce7f1e6dfbbe684f20641100457abefdbc0431b316cb8b876eb2f29ddf852fdb8a43f3e4fe613ebd046091b1bbcbcbf2bd5a1873654e5fdd0868a0d1135690d539a712dd7ade9db6ecd371b50e731df48dce3849eb4a6b639c1dd2f70b719e185e6b5596b7fe61f77f771f7235e194e92502934e79344e2c489919322274d9c307142e4648913254e92381972e2c4c8c8a8c8a88911132322a325464a8c92180d193929322a2a2a6a52c4a488a868499192a2244543454e9a1835296ad2a4099326444d963451d2244993a1264e9818312962d284091326444c963051c224099321264e888c888a889a10312122225a42a4842809d110919325464b8a963459c26409d192254b942c49b26468891325464a8a943451c244099192254a942849a2644889932446498a923449c2240951922549942449926428899321a3a1a2a126434c868886960c29194a323434441ba21a7a7717e2a10b059d47dc798536aef6199360dc5d03f0cb0d90cf8d0f0994043a02a54037403723504a2975f70cdcdd88bb17717790c7354461ae9c1908c29606b27077201eb69698cd28ec066836a3b05d7b93d29bd9cfbed96ca674d7def4995158f9a6ad355da34489c2a3ff46ee8aebe1095b3b2a0a74e408dd95962f45da5b732d2777582bc8dda9872d1da7daee9346a9b67fdbfb64d2e19cf151c83ac37d1cbb70779787ac07b072f01f0a050a4de243ff34eb149dfdc54d335ae9c574f6e393ab59774f18ec62bb735966b47cd3ac240cee3e86e01cac9355bafff8e4b735bbef974b9bfc30b42c0270f72e1e8273b8cd82977bf9b88c6b66c5d1a4a52c45ee2ee4ee50dcdd030fc1289d474de6ea641c0a2a2d0edafa62d2dd7b90b9923966b3471847913966a424c9eb7ae4ee3cdccd7a6eb296bfc9cf51296d6bb349b76dbb8f45933976b39df82a6ddcb47192ed5ad3d61cb5db399cd2cdb2317eda5f65dfdfdaea8bc9bbe4ee629871ce4a9ff1862a7fe7ce9c3192fea9fa584a6bd6a9bb9431951ac6d9e97e95ecee501eae80e83cd2acb933a65577dfe1ee3a3cc7dd71dcfdc693c1ddb778f899e177fb16e0ee14a6cb7b621aad61ba4f4cf196e93c0e8d49c62441faf78e26b4448911f94e68a513274a9a90e42709c26172a49db76d6dbbbcb5b57d16c2b65cc951a84a89a02d4ee871f82644a340a1fe7a1955e0e1477d5b33a7e96cd7d98e879e09dccd1a840f0fbd27dcbd87871e0f1e25bfbed6dd75dc5963bcadf358629c10f953a1e7c191bb5be0a107e4eef74d0a853e8d96e6896f9afe506d7d28d597d7d29fc2b8cfb25cd56977b771ff4a77ffe1a107ea3c6e5cade5ee9e679cf3d35b69f9379ffb33bdd8eebaefe3decce12cddb6e64d6dd7ee5d7119d768fd5aee3ec443a77277d1439fc1dd75d8ace59fc274b72d597395d479247f4aa6ab5988cc5a88c4a6598576b9669a35dd9db502ddfde3c0cc17073840151b1f6890f8410004c63875c08aa89a0488d0c831957c784060e4050fdd6b8cc3061134992a006163d4f35380245ef000b2c2b8cae924231c843983c20faf0a00a98a02c7d15455c57c05c48c0d38384467bcfc4b013473c6a3291085600d2b72de3e622c1ac63525c5a25e071e134355d5b3955a3d521db4284b0a4b6b4bb5a817fb5c3ddb8bd9ec10426506779c1d3478d4eb99c1a3cef3ad78563c5b8a45bd954dec6bf56c2f06ae89b1c01e2a7c7bb1af870a6f35021c213492080defcc19907ed4e3317306ec49420c07522b2ac6d174c159519c55cf151c5f8959992f332798e07df403bd038020084a7dd4061c33f55156cf5e51d62ae6d1970be49162f5881913b3e9916a51d69415eba32fa957cf981808ae562b70058220b85a510ff43ceaac2270dcf3bc559817b5b1a1ceca1ba4ada98fb6280be411f32326f5f578cce31163c58bbdc4ac3cda23664cccd52305d28fb65a3d62563129a71ea3ae7365471538424000234408e9f5c011a265b5e3078f7a3d3e780a30b3a26652203a62d13154ad332dea3a5bfc8845cb90a9aa02573cad9e174f1488b3c307779ccfd3f1c0a945573cad568be2b8ce961665f5ac7870583a4e2e123ebaead2a2df9702092dea1d7d2e176db97a52c869b5563c600a24b0a87704521c9c1565f18c2173c43a5af5a4907304d2291f4bc989453d58d1564f0aded18e35472cb0a70aef49c13bfa7aaaf04a687d200e38ab2216d107429042c1a1be2ad2e1f9705639383cded1475f3d551ff5e88bc78f7272a88deb06a4371ffdcc8034877a3c24d850efb3d1a17e94c343a6aaaa8a27050e8e56f486c7cc19ef684553e0e008a4ae23440b487568d4ea0887474787dee0d033ded10df5e88bc74c0ec5f17848b8a19e8d4749c0a15f4ec8a323848a8bb6a45c3d43ec3edaea1962b7a21cbccce0d033d48c0e4d811edd504fa7a76a453deaf59859d19b9e2a3329d0231dbad2f940878784125614a7a76a4575b4e844ade877c363c373c63bb2a1383c6652e0e00887e27c3c3a2b1d25215a40aa433f58d11cfae23163d385cc914e0f0994841b4a020eebc686278524c470106b51ef88888d508caf89b57aa486d87d74889d102d20fd68d48a7af4e5b4a274f5b5a4c0214a23fca84789ca086d70848000867aaf55d19831257c74454bf02848c72411e5a22d3ac6cc197a14654359b48417bda13e26057ac4ea1953428bdef49ca1472b6ad353c2ab87455d3d25b43ccaea29d3f26e06aa8858c3c31a1b5060460df0f33ed002de1c4f78ab700e1318f17e2001fe00636172629f8ff7792b2f470e325e46af550370d05cc941220e35719cc1c6cf8e385a8863863872880388389088e309c7f158211c73b88ee741ab1d8671a461f580ab1c560e1c5a787050c08343031e1c6378dee781ac9507470e7000010712703c010715703000fc5a28a0f15eafd70f9082a0d11b676220f8860dde8a7e3a5756d4a3204501e7fbc21ef405d27ae0f84794055116a0e7795e16edad413dd08d39dc308197e6042dc4da30b3a24f629ea6046956ab96c33cf6a238613eeaf2c0d8176bf57c445d84ad9694778515868c7f06d820063aac0d11ecf8d183c562adbc1ed08d1871d88f188b4533f0271e63d1230ef3d80cfee36de4f06a0388b00d247eb4f1046d638a232c26aaaaaa8e38720aea286d10c3017df5e908332616c67b85f9562c23282cb0e5020816b96898bd22dac24c122b6a26057ad4ea49e33908e6803daf2f8ad6ebd57ab53c25cf080a96b0c7aac56ab58c5a2ed7b76ad196165e822c3e1c56192008b672a07c3facb0022c232deab2f96c40b0f5d2c971b9e84b47e7f4540163383d2c0f02691530e6eab90163208e0dbde159c16c28ebd371b128c8638487d2d0c5fa7c86582c106c5110a42d90b66e22f0b2f93e9beffba80d0fd0f7b32a8aad98b810ebfbc0d647592da0cf670512f9a409d18055d8785ecf8fefb55af5f8b4284be7f54d59794e73404f07a43d3c90b27ae440f3796872c0f93e96fbc4b4cbf5ad58ac6fc5ea01f2201608aebef0c2c603592005592c10044116c862816a8a7c7c7c5e2478c3f5234c8f21b1154841230e6319b91c06d2211f209f17359263c40b968d0dcb8605d2cf676504054b0fb0e56ab568185713578b7a8cc562fde09902335005c3ca87e903af7c14a42c5087e5e2a161fcf359c57af8be8f8705027d31acbcd56a459b4cf97c5661c80611abd54b07908d19b13044b195b7c3615e0f140f5a515087c3be1ea75032107ab18fbedef83e8ac3e209c3a11378432c4a8d7846565febd3f97ac2901a617d4394d230fcc162b1a6f8a0184531f2fdb0582c168b0d13c4582c8ae5e5c35a7d3e465f8fd1e7c3a25f0fb562c4a250b084445f93152513db1ff5629f7b01c6c7a24ebf8f05ae562003beeff3becffb28a53f28b85a7dabefbb22c4f1becf410aead06a79200be4a2f5b558dff7b1be6fd5fabeaff57d9f1cacef6bb1582c568b25c4cae359ad56463cf40182e2b55a2d6aa4b55ab5807c82a8cfe7e3d35ac901ba3e10044110044190822008822005bfeffb7ad0ac84f0224aa91b3c0c7d4386b0f156dfe7f91a3455aed60742f1a0d52a8afb185d11be62af1e9607b97a7a8c7c3ee12aa4d4c8ea034d80b302f220162bc87d5854c7a31e0f088a7a7c3f2cca3a0ac3f8c45814e88302bebcd52a67f5d1950b9ee785a18a85d92b4fe7079c149c112312f33428382386f3e540f97e563a4a203562a4275c03430812690152d0e7c7eaeb6179d0e7638445874e80650804b1d547575f48519066e5a373586fe01039200c12c359812b6781617c629ed7628134e61ae2412bfa83e54d88b8cf7745e831d0d56a40f8d12ff662391112e147411e9607b128cecb49c00409a220011a17f298072420c27f5ce90b12033d88f5d9bc1810b25e37397ef4830436c45674489832622b8a839383b3001d1c34e1ab47478e8e520ece0e1d0a087758118a6115e18e4845c863678a1e3c1250410f292ca8208ad0870508087ff870203f5e41807c3150489055ec3544089121de054430b8c0631fc580877a3d3c457a3e234532300245e8c5400d32008f68f0f239f2c5c01f9f55ec85e4c7db0089c73ea00dbc20a06f0c3a40e8c5c098d0f8443824648030c9902b49e22d51f2112d71225c31216aa20993a22646454e8c604e9ec0a03c8902454a140ea4f8140e9a884d398a211d252129255151aa42c54a95252b1d2c79573ac07285094b13539626a72c9f16a7272d504f51505ba2b86c61225c75e1e241172f1e7ce0e5cb07207c01034208606421cc647546ab24ad24bfacbdad76b3b9bd85b152619630a570e6c5e19bc36272598cce5b9f7bead44d51e9765422ecbc114418330209634a20814c0955644ca83ac18432279829838299145000400a6700f0a9706605155858a105165c6821002ebc10802560782106186488410032cc20001a66a8810625c2d5006af06c1800016cf86e20000e37ac72c041871c7c071d0ab0c3c743017ae0c1871e7ef0c181f82108203c2182580d210411437811441851847784112b248ef0d89704125e6ca544125fcc975022897015f3623945433e6f091d252442228e083feac57c3e9f1f5f8f9107093124844e15108cb55820cb83be1e222342cf0b42e7eb212a22043d26dcf38cf08ef090f092f09af098f868921a38fe799fe7b570c6f3bcef5b83873572f82e80e31f0e0f26741a6081173b40b0461b62190b66f011f3346a8c50b3001e70887e48a3c61b3e9e6d0905c230ce819847b178e1feada07c3e1e1aa02120cf89ce84de43c641f0cbf11ea0c762008ee779dff7b97b40e0e0b80750f0267f8ad69f9bae5660b028baa3d1f2f77dfd39f7d98792368737adf4feebf6d3a8edda5cae32d1716b6bd299942828331cce358afbdba6da34edd6f42f7e1cd6f47525e9b574eb334c0d07d9e8c6970a1fd1719731ee7141d7d2b7e56a562ed8897e356bd7d2d75697ffb63149f712cdf46934ffd45ffa19d73eff6d97b7d27b526d29eeb78529456569a263f925d574a4589b95026dfd369b44c7dcecf7493ed5cfe88e46f743d1b17cad9fc439476dd73e8dfe6c4bf1d64774aee27c68ddb5a49a8efaf1a63a579980f2dff6dbf0a6fbcc99f547ffded1e8b52399716de3283a262de56a9ea4ddb9e668bd96ee7b6292acd434cf1afd5b147d5c6d223f07f5ba7e26ef128ed2e57f1395128e7a1c46dae6596b9f7471d3be2746aafd13ceffc1c54da6a5629a158965dd1d8b874dd870f7809cb9e97a7b7d52bc29fd1237a13005d3665398a64c99e264cad0142153804cf9e1394c7f32f0a1302a447f32a01428030acb610a9401f5a1140644c17cf912931c8c117290c58f4f95c1a8b62deac98baf0c06d3175b2dfb8c492d2b7feb33ef7bca7027ce5e8b334ffd7947deb7e5c7bd6cbfde16473bb5145969a6596b325b5050d0eb7acbc9ec364f9c4c26cb057d142ca25c41f1a67f96b4527a4f4a0d308002a8a1608a7c09a354b9e3bb7b29ba7b29d9a6fa1b46c1e2ee3f40bb97f259dd70d3d5ca0d06236dfefbb6fc657d2bdaeabf5f85fc1cd49317375d6c757e2e545152e4df90b4bb7ff1d06805771f8f9268ad96a5fc8cb73e738e7eaef4a7bcd527ffbd16484bd5cf694c5e4c526d6f9bfe131393fe9bae56e8f8e3f3b72d82d574dfcff944a2e3c6f8893e3131d1ad7f572cb4525d6f95eef24f298d74eba7d1bfedfcdaca68f9a59dbab6dec86be9d37de4e6bf45651c6eb4a3c6fdb61953fd53f5d26ba9ae375ac3389bb8aaadac56dfa465593fef5e4af6b65b6f24cee69c2cd737495892bbfff01006e44e6174574af1a6bb975aade1c4012ec3597cca82aeadfb9e1817f4a6547e5cc6e1642b94c18510c5c3221e34ce2f02b55dbb332fa6657d93e24df5b634baef5bd2d66aa7a6e5ef9abd69af8bbb971e36190a8baa0c2d094109bdf5b6a9d66fee6ea5fa71b9ea13dba9cf4ebb3e6de7fa379d475a509322dc71145f8a420e6348795cbd34474f283a8fe49231c9b82488fc1293413f65779db2f94b99aea65965baca6ee4ae34d99319d77010ce864cc6b853d89798a46fd2ea8dac9fef49cbcfbfef5398596ffe7dad69da9a7e5bcdc972f56fb2fd5a4b917f2365fbc45f6272bfa6b2b5cf3999695aa97d7fea65b76d7532a9ec01c0ddab42a14c0aee1e0965aaaacca040c68cbb37a68cbb7782bb47668c092578644a70f748f0c6d8b48a0cb183851934eeee1d8800cb147fd99866452a2de692df342bd2b5369bb3ecfb534a2f55b7be5bb6ae26762a5fead6276d62ec84c34d17db8d999ebcd59a666c6b6bfeb6b72eb66b37e662a72e4692ca15f74fb5bc9fbff64fa5696f4836cbf43647fdae1b6a6b8b25ffc6a7187bb76cd356d9e5df1b63c93826ad73364abfddf7c44736abdf5671f6b3537ef32cff4642d9b8fcd36ebf2531d46ee7ac49e5a74c8ca4f55f1c2e6f7d322b6933deda5ad14fdeafd5b2ecf24f6152dba4ddb67fad79b3e096707942e94dd6bc2f46dae553d7cf513557de9aab3c0df74cfa7f6f8bc361a41bf951a625ef89917664cd24c67d92dde6c94415b55febd8be8fdb55a728ad9fb4e55dcad99bcef8b6cf580e57b7a6d5a3ddb6a6dd5ba05aee1e0b74f756eedee7ee9ebbb7668e14b83b0ae658b366cd9a356bd6ac51e3811d41d07490f3317a18a2e6cb1743fec5131e8a5c98809167c1030748d8a20a0f9c8a2b2e807326e70c6f22072a649600c37d882132f8788115ba0e4faab0010d32ee0250535ac00010b0e22c2469428a32f3e0279c004a04d504463e8213aa31608059c0b59a2b72222079c271162c6dc1ba800baffd60860d178dfa4c86a812c86069c13fe04009ba0000f9866f21a10d1548f0a83be5a4e87abcb8c2af2ce14060e072e15598406181230120e1484e85788c0039073750a0044172e44f9caa8457c4c086177571802a3868428d139da06404272035e0496c38a091a901f27184391e20440a667c032a5e90522543e93f1a4041e29e1eae0102e698a3042430c28d5c1eab2f4178c07ba86c81238384294ea704e141024202fc020fc439c2a8220a1fd2c2075cfe00250fc281344e24b1011138102a1ec482a478c07d3c008c27b528a15b30fb3e1d01c2f00a74c24c816abe701e5d5c4089129070f8ce0f3e2230fb32858b2a8469962815e021990330a143180df88e146e74745140e83a70a0330001c305ae630510358cbcc0798e1a45e028536081aa1c243b6f728348154e0e618e38be38c36f1ca0c119392d3e54ddf400f5883aaa729b33150880074b44f8eb0d165a0841115ff82ba705193d607155b94810a2f000244bd0b8a83ee019c00808d0b85c5ef870ca41cd94960e26151376e4d0b49c3cd933709929ac0d14e172058f31ce3a018513725ab8d0b0848c24d1c1ce195560184dc810430b4f54813588a1c38e1826d0805a2e0f4e4a48e26068010d60304064ca8a0238802047192e61ac6c6040991fb43853b5a26db9917a5a4357421828e9e18703f44b811a2c3ab88d876f0237a87066800c0f9f106c48e0cc000c345f095ec430c48c32fcf3a2230401d040c1ec6392c20f09b373f6f5f8f184c36ecd14cf04407851c314aaf23090e3816c2799e24d41b48117b10d26bc1ebc0f5c5314a8f2ce7c30479014270c79627e7cd08d71a5cafbd265ca122c47428f8a042cf000a80683b784840278f174c6cce3712ae10c1a95175ed8442a031c68000f9e636004cc8d4995ab910304264dc8aa7c0c2a940082891639ff620b0c0930a2829167214512d59305d4a9d800174e78651879134d883184a7a5ca87180241075128e0e43a3479000910350b9fe1234de004151f67e18887324cdcc08497711d893064051e7c042b535ea43ce1e33a056084b89d271c572400739041430e5e63c283924106239fedc0438d15de08fd83333c2a2a6aa2f02d67beac41abf0c29d44708df0050b16f02b5130a9c1880788bc8a94595e8304261ce9450501243471c63910cdc05de08a0e7fd2a584264c200081177d41c68925e220c389ced470e4869b1c3c096e07270b8ce1858f2600f1443411c2375880181d3cd57082ff6c808010c4f18305ae01154e5c51039a13dc4836c1cc65c108efe9c00d0fa080c790d3a4d66e882e0bbfe00b03dc2813a5880f81010423527c013d481844620fe8d1c0812c4981104769ba0f2d1ae04511111db78096002f661b08f10a76c4c143842058701e13e08085a33796f84e1020284981dd719105256bbc1a21f0d0040490b141d7c37700600425eca0a1e33a7230233785180db88e021c608610379e3c670d288268c30584e76c500230644fe538ba015356d834f11b2ca6b2448004a5df14b111b1c11983dba83087084a700002fe82c30711e05c89c25f622680a68808d6b88b0d170604504214eeda6df1441ab013b8eb75844d50ad89b776805541f24410de82f58862c464c7591bc8c0136b5838c1596592fc80033480b384b0c0608ae6c241319676590c2b1c1c404e052b601839a8a50d204168910107431a84a4b921f45505766e5d2c5184af08a0040514e078e02b9a15b80700b1c65742277c51f2a307ffd630d930841948f8370136b42461060eff8650b23519f1c23f3217541942c60dfe79e172850f4e49f8c7448b36c41cac7f3dbce814c1f1807b2610634a097e28710f034a413ca00136f7a6085341014258e25e0f443d7007d8c1bd332b40a14651927b62b8ac50822139ee7d31c104213ca8dca3e20606d248d9b9b7e407d7132ad8dce3d14ca0f161cabdb08b0a42ca18c33d9782c50c104bdc49f00309317a38701f230d921305d871ff029b2957f0e29ec5049608634607ee54b08145911cda706fe20164f0e8c47d0825286e7c2b771d685ef8a2729fa1c72b19e1e1ce02540c60b2acdccbf85072021408e13e4297d3070514e1be73e4b0dd10c51d37f40517ae22dc6b54907152821ddc674558808b5c18f70f4a108ad0e4343194c6b9a66fe6ee4e1e1e4912439f949f4f9bad5d4c525ae94fd51bd594d58618fe73f34aa0e1f6e4062ddc2b4107a327554adcbc12361005ec880b508fcc4f1a2713f821c22303001b8ce038c0cd2333471646432870c6ab72c1a9484a4f149e09517e349931208d77828f344cc8a489c22bc34345c4030ad47866ac0d4bd07031f25090438d1230aca01e00cea049d6fcf0f25688319184522b9e0b47c218e240c9140f06285e42217441e3d1b0c3692c41270bef865a55900eb8303c1ed8b00244c5088c3c22e60863030ee8f0c273228d131239a060f0ac20c11b4882e03cf022a0059a1f27ba2a0f8c149ce1e3010f67786e6c21e288ce89303eb10a2b1ad470459a6fc9076832388006a2f840a02167c4026fdcbe17901051c4043aac7c1170322bc2834e5901f142448f122546ab290578c1a305ca6c8506541a9aa372063cc930c2e0052726583d51682e50e28334ac36c4f048a09aa2777fe562abf543d9f2ac17e3ecd32aedd66cb35d2b75f34fe12af96bfad61c7571d3eec6a4aed5f76fe4b6529fdb45eda87076fa421f23ee9ee3ee373e3d7c42164280c14f664139c2dd3d0f244001267e80f1450ceefe79c93d1df1458f352570f78f081f8a70e231451645eeee0dc101047a7a9082e2e6ee1e07327cc902830a3a50e1ee1e0356642ad0810544b8b9fb0780223d0af0810cb4d8c2dd3d032841731d2a84f0e1eeab3646108213483880002370f70f8b120765b070848513b8fbaa8217bc50630036504101776fdd40c31b9e05602998e2ee1e196dc430668e017ca0c8dd411c662e02dcb6080386fb97f8067d89afbbbb77640677271281f727376871b331ce3a8f34a12ff115ba96e6ee42a8c119552fafaaca84aa9b2af7aa2affaa7c55e52a54390b2cb8dfb88dbb9f715fa1ca6daaaa4ca8aa62a1cabdaa6a85aa133c03203cf0bcd048933baedda52f6bb6e5b66c5db1d86def9208d6acd75251da99b95c4cd79b53d4932ca71f57ef266b0e87916030f24b4c4e2959724a91e5cf51559c14894d5a36ebc65b4655715415475a7d6dde542f7b5d6952942c39a1e477a2aa387ca3703d61f23b69184c8ac4e69194f273399bb786e174d541c9e2218f936ff273c624ddf86a4a6b96526de9dfa2e893992c63d9acfc9bb6d7d668fed2b4e791cea3de16674ddc6fbd73f79e7c6bec846b776997f1aee5ad4c66cd9fcb62565cc64de5ae3ae9f7829b16e0ee57dc1decc06d75531b8662d179dcd7e2dc9271282809f9608ce813a3f38b14287a579dfe6b32bdab39adab89742377cd699ba47535c92efb66b3afabc2dd3ff010031a4c7bd2928c49462541b8766dd09b95d4d766b5beedeaa4f36856b382e0e105398ce37864bf09b4eb671bddb8898e9a9ab59a27695692deb6d551dbb5e53de9e74abf0bccfca9376555df9a374ce7f1a6ebeda6eb8dc81bee3be39ba618ef9bae370a7b9d7fea33752f7f2abffea7ff4c85d4160783e9fb5278c3605a9fbb6ea8276f35ebd1c556e7e702e5ee4b56623c5eb9b4df34ab130e43fdc54d51ee4ea99090d0ef9ab7a69d5a88bc3b1d94cb5517b4ffbea5e1b008414c868476dbe69a2bffa6ebed9e30d8ce38973bb5ec7135d7de5633de1a067b9cddf7cce1101e9cee4a7fd7ada9bb2be94479380448e7b1bcbfa9fe89bb87e0a1102afcb7fe2bcbbfad0c87734d467e4e0b913f25b4847c1a49d6222325342743b4a2225a7d2323263f4454abfdd00f91b526444e6aff4542e4d6671612c283bbc7dc5d5f6c37f9a692c6b926779fc241fed24ee1ec54774d72f72858e8f772f7206b0441836ac8c756a39a624a58b264397a52aaa214d5b4b47454a569e9290a8a4629452165c182654bd393d21295a5a826a5a4251a85a4d4c151162c31a5a724a5a8d89312d3962625232a515b94909a94b66851828a5282226d7edcd9e4c424b6f4381b8514b5e57136aa7c11ac59f3dfaff226cd6acbc5766dde504e4c47417ab8fb17da9465292a86b484c5c92906e40cf72f146989ca12929213545094074a514d59908044e08af23779e69fb2dbe26cce012102481021901cdcfdc78782f94295a2625c969e9c1e67a37ed7242af74dd97d53f6bfdfcce1307997cc4ada8b6f252f6e622a6d16772f2a2d2e6d16dbb5f9cb9c653f5496fc5359f297f59fbec44cb61af534dcd964ab51eedee4dd9dc9ef1dedeaf095ba5b6c35ca76edb515f7d9dd85ca2f31f965ddd5dd898c6a7b8bbb8fb6baff342b17775f72b1dd56e39cbb2b49e2eee5b5523f427717bab8c9ddc7a0c761285f4d0940081b511039c8c5b54309a50deec2401537ac983272af0cbe19c0121470971b3c2c8d300a59e36b44e0ac1a58285aa2c600f7a810d70ea008ff704f96e860e7e3ac1a560d58a20113677d6044d20898a8fb8f0b090b1b487197e2428b2d6a80e15e03c8c0e044cb8cbb801c81450f736471d0660133c81630e5ae14b280018438d6784b0b4e8d92c51a7757fd36151ef817022b63970a38714781115560a6a4c1a24dba18038a35ee728205c90394299c65860f330fcd8f7b44f83ca9e056e12b262d7878a1fac1bf29381d1c805be32dddc203a6ec74be9240129a55d593af9c9ca6907440046fe13083064e90c08b7f5128b102ce41c45d28d0204415961ddcb546083954913373ff2288395ef8a183b7841ce940070f4c38d0b559b3be0856ef13ef2a160ec29dedaea66ae62e9ccb4107a378eee2c12b59a2e7f21d1ecb024f87f7520216f96a06f002d7f77ab1c095e7b98f6ff4cf3d2d20079ebb9eb07c47cb73cff3582ca20fe773cff3569f15cf73799fe7ad5a227cdee7b93e0b9e3cafe5b9fcf374c6d5d76af9dc500ffc3e10060ff4bcefc66be3f36c9ce581dfea3d2fcce779df6bcb27e4f3be16f87921f83caff5795a3c1f9eb7fa5e0d60ad5c3a3c0b3caf82d7cad3c1fbbcd6e779df4ae67de08d0dd197e34979792c23ab289eebfbc024ab9beff37e7634f1460093e05059397d0efa178407ae7c40d6e7ad9c45833786e79f8761e89e7ba0f7796a78af0f89e77dacef5b79de124fc87b7939dff77d2d24efc8f7819f37b41a7180bc34f07476827c03f0581f100ff4569e7f4e1fbdf140ff6ccbe9cc7361e53c0df07c0a16dfca6b79a0cbd3f156367cdf0bb6f28c56def781f4cbb1f1f1589ee71a02936030e47d37add7e7f23c98f77d1b58b53c9b0f5c4d793ddfe979ab20cf06e7f35e2eef9bf25df05df01159f9cabd1d5eebfb3c1d305c811f90effbbc9607d63c1b231e0eebf3589e8e2221df920bc7e6f368af1cd7e769f15e9eb7fa3cd0b3e211f99c7c433e9ccff5b1bc95f7791fcee702bd156be50543421f3a3a3d425146868bb212b8285be3e26c878bb31f2ece885c9c39b9389bb938d3b9380b808bb302b83863c2c5191a1767127071c60117676a5c9ca5c0c56a818bb5888b55898b758a8bf58a8bb58b8b9574b16a176b0a2ed6195cac44b8589970b1a2213244489070274890ef0499e23b41b804a9b9fbcb46c78d8e17d0452f392e7af9e1a297222e7a0172d10bcc452f4a2e7a6972d18b072e7aa9b9e885ca452f29b8e8e50517bd10c0452f45b8e8050acfd90152e53b4074be03a405df013283ef00e9c1778024e1ee3a383b3b7038e3210e34788803101ee280000f7170000e5e7888431a0f7108818739b88739ec789843110f7320f230072477b7e0a54347c7cd6b473cc377c414f8ce8e10dfd929e23b3b3fbeb353e43b3b567c67678befecd07c67e7face4e09beb3d382efece0e03b3b41f8cece12beb32385efec2cc077762010eee84143141ed2e0000f69c88087348ce1210d6b7848031c1ed6c0f2b0061e1ed650c4c31a843cace1098e0d8f9d1c23dfc9a9e23b394fbe93637d2727fb4e8e19dfc91980efe420b1c3fdc78d0e1e54f4e10a226a4972510b948b5a4c17b59871518b005cd4a2838b5a9a70518b025cd4420117b594e1a296375c7ceae1e213918b4f4a2e3e7171f1e9baf884828b4f33b8f834848b4f50b8f874858b4f5db8f8f4858b4f1e70f129042e42b180fca88085325c64210e175bd871b105212eb630e4ee366278d3bac9e942878b5dfc70b18b222e7641e46217555ceca28b8b5d8071b10b9b8b5d8871b18b115cece28c8b5d04c0c52e04e062173ab8d8c5102e76f1848b5d38c0dd71c257053b3b3a628e4e8886150fd180f2100dd24334b68768a0e0211a347888c60e1ea2818487683ce1211a5a788806181ea231020fd158e3611a403c4c63030fd328f2308d240fd370f2308d99876988f1300d321ea6c1828769d8e0611a41789846123737e08e1cf10411b87842095c3c01052e9671b95886878b658ab85826c8c532442e963172b10c928b659e5c2c535d2c835d2ca373b14c1917cbb4e0621902b858c687968f17a8f0f0050778f8c2161ebe90c6c317d670771d3d6e76585e7c8765f31d96f61d16007c872583efb076f01d16112f177a78e802110f5df0f1d085200f5d60e212b7b8e2e216d5c52d762e6e11838b5bd8e0e21641b8b845133a3737ad1c7104352e8e00878b633e17c7ec70718c0f17c7f0b83806c8c5314d5c1c93e4e2982617c740b938c68b8b63662e8e315d1c73bae3d8bc76a060e03b5090f80e1426be0325e63b503af01d285b7c070a18df81f2ee9ec3c383c4a07818b3e261ac8b87b1301ec600e061ac079b1cb101402e3680898b0d90e26203aab8d8002d2e36008cbbbf5eee363a44295070510a175c9462002e4a510017a510c245299670518a2a5c94620b77efe13f2a403dac00918715e8c0c30ad05e2b8400063a81266a8490a8d2dc3059c08f9a963339f8f0717777cd016483bbfb8e009039e3ee3e840511d2ac59f317ffd7644a5e15544c910029bc6789300ad77934cd271100841705029e78e2092928b2701b28c078d0dbbc83b874a1a3edce92b22c3d2939c994aac49eb24441c9a2b06c8951514a82c1727a0645df56a5ee792369f974dcd12815a48d9bcad7fdfda7ba6bd2efba93cadfb8a98673c58271d4a6fa7d3152598f5c8c15039c711f67abf9960bd25e020c50827b5036cd7a84136fb048276208aa4eff547070e215549af646864d04e167d0d6b5f6fba4d9bc77accab479e8ee3226d494f8dec0040c486552f91b731162d49a56690d676ca7eaed69f4379eda3a67fe6dfcd9d17cca5c6b146baae968bb16db2ea6e34dd75b8c8eb7df980bc6517a772b1314b08912403ce58b60931841120a4802091f7f7ce88f0fd57d936f20092cf507210f930091c000121170172a4205891328d535a764c9d2eb5a0ddb5e23f1b27da6478441614fd69c3ec201eef4c17ca1528228982ff4733bbce9085ccd1141c4d027f74d992c4a141a8587de376532234e30a274f73781a8b6541bf1b9eb46fd9a6a7be2923eade633661bffbea675679a95ea53dfbfaff18da4f9c45ee8a8f5b96baeb95c4582a4eafe888e9a8a036d8b10f1fa4244263384156f8c33caef04429c719caeba7de456a41b1d6d9646f1aeb67c1cce527de44d5a8dca475493d8bc5f969696718d6a4bafc566ad7c3deafcfb7135d71cdddd8ad35b6c43667dadaf7d7dca64667d0dd31ac774e44869beadd1bf6d5cc6356d561a366db47c6d29dd991796c3597a71d67d6eb7ebc5b7f699ea2bdd6133f7a5ae369dc7cf35f7390783e9f0b087325f62a4f16963a67f23a9e829e69f70ed2ee174d5c1606f9e2566c2e9dac5490b1e8c0c50001378a9c10ca7ae9fb7b7410188dc33093b5c2067964a36ab754f5599469df1262b95aa6449794f9a3f77a464c9eea5663f3f148802f9f8d4f006944867d6b2acf4568ac9f29bb45963b849f754308eca5fe62cb52cfbcca2df66bceb52fef23e958d9b1e67a374180bc6510b88000e2f57c2d96a22c51e57c93f0af34fbba5376d0d0349e58abb91f78fe898df29a9ee9a34669cb33b7fee5a264a55cdaa318e665cabb4fc769c5d3ba3aa4c33fd3a6ce6cfe54e6a566cbf466d75df27f3e7e8ae4ed726e56878d35dae96b4b5bf4fc3367f8eeeaa3992d534fff6b7a829c6f2cbdfd18d6f4977369374fcb2e234dd35d1ec74972ed6f59fee16a47f7a2a4e4e9fcf5d719f9d76d54ae9706c9a066848a26599818c7a8ae12242d10c4453ae8305dcbd04016cffa41040e841210313ee3a94e18cbb8fe6b87ba90de8ac5cfa2b33fab7dd4b5d1dae7a26bb78762373fd6bf5a92dad371d2d77eea57e4aef5e4a1fd15d5e53dbadb79bdda4c5e18bc937f3974bbfab25b1d631dcb4fb2b7af75770d391f085ecb69b6f32a7e285efbe08f83315aa2fef520070eeeec2085c9861bc27ce9d52189bf46f51b18d9bf25f5d968d9b5e6fb94b1b37edfbb7e2f23bf5f0705a00c2dd6b184f27ca9701c0177a9f4f28d3ac485a7f2ecb98cbe1b3f37d2e2fa80a095fc28211cf8a15b058817a73783f4c48e107ef042e0498c0a4822f881745dc9dc943326276e009cfa8f11d15ceb91d6766d079a491e0eebbbf62cbb12b4e001881cee3eea58478f67ddcc50e819cced92d02a0072e4fed1545e1a6b5091d200510dc69d50be241e122582d82d594fe94dd41543b482827a3da55a6fbfb39056688c0e9aa23c778688647ccc657f7170663b2b979f2b4f1cdb3c43819add63ee746f2a97eeabe8c6a07bd2dd71b12aedd258d9d6edb76c93867a5ac24954529eae97fe3a9d2c432b36a5bca64af710ee7dc3d339695b9eaea2edb1cd5cb76b2d28410689bd54964b25c95e92a339fbc95a495517e69a768eefec3dde570f72cee1dc0ddbdf2e9cebc5d4ba38672756b9cddbb97ca670e67ab49fee75afeda8bf09f6bdae284486d7125249570848434db0b220c770aa871b754ee4454b80709c15d47c8033d9c2f4410a3830d170fc7784182061437e93c925fe26bf3f642afc7aec434fd4487cda751d9b57a6b6c45ffb53b87fb6b83e89fd7ee8b49fa64b773b820bacbfb3ecd616cd28bddc930c3dd87689428b403236cd179cc7fef99938c433058fefd391725ca58335fbb7b30fc7801f40260d2ea3e71ee9e0b345a4b0884225819afcd591d9a703747a5b82a76402cb14b9231fdfc53621c257d28addc36eb38e04e3ca4327f9f544b5419bc08f65a9c2e8cddb6a6d54de1ee473cd4cd4033aee9a0cf3937743aa478380543fe6b71e114964c472ae114f8fbcce130199e599c30c0f699dbe76ddbf0c41285d2b1fc6c4f3164a5b5b367cf41cb3769f53ea53b8c4dc5487321ec5b19f43947a376583fb35208676148c9994217a1612029108549a114262b479ba5e9253da4fc325752db9202510e804c327320cc298cb66b6fba9a9a0295f7c435aaf3088389a180bb0f7928c6875dcde69fa278973785c9caf277ae1bca842abf0c736ae8d717e7f4677a6d7e27aaca14f526ad72b15daaca346afa5275eff6b5414f5e0ca4f7f91b4f51dbddbba0fc4e6599abee88eaa7af51f356fb7c5e5b6d957ea678c360b32ff4fe943e546f186cf685d69668d55495a96add5fa02cbabf663dc53ccd585baaef53d9d6274e464fbc3be98977b4b644476db505ba4b74d457874baa3759f359526d6fa5c553555345e5bf96e969d44772b8dffb75ae9a4f3513ba757db33e0e88c99b395ca5aa7f8b2a4d7cd39f6f514723544ffebd9fd64375bdb6f6e514ce395c7d5d6f495f947136a3d54ed1fd1a898e6fd2acae5f2be9d36cddfbc891fc37f235dd996625ed2d57b30defdc2e93b4ee23f7c926bf56ab3463bac9cfe19b5f9f41789f95de5cc5ed5e0af61b5f4a85755174bcf8a4b66bdfb4371d9de959141df5dd42c75d29ce34cb5bc35f31b9ab398a3f1f79dd6f7b8ad15074ac7457d376ada6f5efec5a3a9b7d9efd0001f9cc806274fcfcb7b2fed677898e3a6c6a9bab4c3aff14a6dbeeaae9cecce1acde96026d5d73f4c97e4dcbaf541fd9f5b681663f3ef7cd71465f9ffb48173a0e01dd2c74dcf5c949abb634f7a4b65d8bc39b3e8de24df5e53df1d3ec0bd5968299cdbee89d79b3bc2dd75d7eb6fa934cb392b4bc95a4e3c5b9f3fc530c05ca1848cf28ae7ede3a77d25be9aeff64263f3f8eb45be36babb6a4362013e34d6b65d097e6597b7de65fa23b3357a52eb68bb354fd2e9f9d4cf3a4f2e79f5a9276d569e37b2b92d67fb7ed72234f268ca3a06a56b25d9cbb986645d2911bdf74ae5e28dbb55a5b268ba39de5ebb069c6366e32cd4a6586048ed27d9502c0c26cc954107931ed6ec9556762ec443ba1f643e5306eca65d16fe2271363a7fcf72e99183b955fe6aafba7ff4ca5bcf82848489b18e7645756c4dd7375e3ab7154b9a4dfc64c249d5faa6e285db352b984a3cad7b5cf4eba66a55a96adef92be18a966a5bb74d3d584cab896e5499b9d70bf9732a6a243305f5c6b96f54b0a547ea61bd3fc5219ebb014894da120770ff2108c096688decf61301f086c80c001770aabbb96753f8e0251204f05af052077cf04ad71eeca721aea6302fb86dcdd8b8720d8b8eb208d735748ef70b833a944dafd95fdfa9f742e577550faa9fcb2fc1975cd5220f2b9d0f281cafad98c6ddca4f56fcc0587f7ad3727d94fe92a1ba01ce10708f88008779fe2432fb696eed8aec4347acf1a0dbab8c9abc20f2c70f29e3526e3505090c5e9aafbf1d9ed1cee65da8e5264dde3a62af5e36a9396959fe57118aac4b88a69c6ca9fb24ffe53e885ee6836363637e5d32ff46f5136363637509cb68c5a9b39a08c6bdb6aac6b19db9c8b518fc9582bd578974b5c6652a432d6ed6f2abfbc273e82f2a7989acb923f97abb9cb8ce27ddb676c46cb5bebeb2850c654e858e9eb59fe5d8bcd3e9f24599fa65fe3dba6ba52a0197eda54df34fb5d7176eba75a7fb6e19cab74bf8de24d4d5b6bb4a4ed72d5fac98d2fcdbfab49ffb6819e3c4b9c73b6ea28ad5fdad22c4b8bdb9937db896ba7d5f47537b2daaebdd7da3e46475aded7146f2a85a93eb22dbd91f6a6a3f9776df757ac94bf2b69cddc9984e361d400a27451d89dc27c288551dbb54f140c857d110a1acb2fff2f7d1add55dcd66798b2d2181defeea5e8678cd3b66b6fae5dbec44d4bb67a0475a604a81c42dda066545bdd5f0a446d9546f1be96525a3e982f3487180aa0868271f75a70f758f054f0ce3ccde1ee545b2cda568fe8135ba595b6746f044f51dc7d2c5f0c1d6d954677556756baf589bb3f656d5b5baaff12d37490b6559ab6260cb6b53565da5669b2500b07dcb4b5b4f8a6a395da2e696dd8a4ee4ee5a11610f49f5adb1bf99beefababe99a34fee3fedf33965f5fdda97b4326182d5d21264ccb852a730ac1494131a77ff1a7d6262ca389c530e7ed3678e3e313189c185061e308ef93535eb7971497514e3306ed76ca92dd04c8ad109857c2e359cb1a69feb0e67b159ebef9a1f775e253a6e6c6afa38bb6979ad548c8e7a679cfbbc7b29aacb8cc9cf949626bee593ee72c5d99cb35d6bd66a1836654f310f7b5aa555006480bb931e4a796ac279c8e484dbd8d8dc8c363636373f423a484893b80cbab6e284b01d474de2524808a6737bdf7cc0e82f1487b73e916c6c6c6e64b251976f9a1569772b13c6519576ea5dce2c31ce44da412643132770318be2b5a23796c0506584a2260f9dc8b0883263de00983061019fa6ffbc946f9af68aee9bcadfb5cc6df9122369fd2479425dc9c07dec000519e7acb4e4610740b8fbb8a3d1a7d15b499a3f47f7ad36d729fa1723996645723262020535da4ab754c551bc69fe32637aed896995eaf095da965eaceb3fd191fc9cae26f925ddedfc399c73b467575cc6548c9868dd435633f7595b6ac4040a8a96bfebb559fde5a88fecaf426949e34be1a96be9ad24d575d712df74b5b275b6b5adbf34b10fcdfd4be128131d7127ce5255dca8b5ae340ad31ad02b7ca4175bfab7d9e7dbc6b5bb14dbf8d29aa53fa50f7d6d562a749c295972cea8b67436a3bbde36c59a96678ea263f9f773b97aa3e7d6b586e96c369b7dc61b8a8e5b63933e0d47f579db369bcd9b3e8d9aa6d5515bb31b5f8aa9feee8bc99abd7fdb74f6faa4afa3354b5f9f957c1a9dfd507d79978060b0289f19fddc6ed37adbfaf36f6bdec8fdb51ac6694b6dd74a9135efb77953fdb6fb536f5a930cda379b35a9d661d3ac54db5b141df17d129bf46d95b45bdb6b71f9f797a6190b578765b8fa5bb65fcb642fc3e5a9c5ec828725b744312110438628a614f3843940613f35a5bf335e1f10718ebb2ba1484a13e72a798af95246fe9490f65ef8bce4bc38e2fe49e02ab96f8b532a31d2d23be17e5b3a56303318ac66fe43d1516b4bf749a3d79eb65cb1e05dee44a8e498b3b129af54cd6fbb18cbb63636f8a62b6f2d1f77dad0efa269362a574ab1aeafabcddbb4b5963bf5b6f6da6de96c47abd1ad31d216b6eadd54fddb94121dcb92ea4a6b56a73f8916d1389395de1387c364d54d615aa51b5f3a96bb343fef4c2b423569f9fbcdba2b2d2fd171091de9a8848e48744c4261356c4d13933f4f5e7c295069653e375d6f96becd9b522448487bf1c617e39020a1556fa01d8dfe6d9bf55a9bb555b35631cd8a83aad5cea37de66e3bf749a65962a42f31924e2aa3f69bf6d625632afbccdd25a827d2e67094d2b5f586849b4cf3a4929431d25d2aa38ca84431d94eda27956fef273d796bdef7cf7aa352da1667b1ecfc53ff7497c6a0cf3224d76314121a4537a0982ee1ad31be91b4ac345a4fa09d69c713ef6805dae7111d3d8831c1604d929cf5f3b64d929c545b1caed666651d957c316eaba9d051ef74c6f93fd0549569e3a6376975e7f26fe4894dd36ea81d15cee52795d7e20e76a619d37d13aedc0ff5e6f9a4fba62e11e8c2c4c58d25d3ac485495699c5155a6d99b38e7cf69aaca649ab111cbd3165aa919baba6bb6d18bafc6fd97678ddedf516aa3f8a6fbdc6ee39deddff47d1cddddfae689f74f05fdc5d4acb67e50fedcb9f357f26be69969d2121285a2e2b4b4dfcbc64d3bd37cb25d5b2ad55d7395ab63e56f6db16cdca471bf97ccbcc5767f5b4dfb2ee58dedaa99d336a9c4b84a979bae56dea455bc9fcbc64db17a64bbf6fe94adb27153d393ce4f83884e1470c2c2c90ad1e9004e41884e40388d426140b4e695e194e41fbeaec99f326d4def6b6b5632eb59da29bba54cfa7878728011b35bf29e98fee2268c9f9c3c3756529e54053c046207aba52786942859a2ab4fe512d59757ebc72200bcdf5e5bde4ad3b67cf3dcf771b7caaec56176a65965bfebd49bffa4ddf8caf67d9ceca7acedb3dd52a4952acb2ad32736cfdc99497dcfb26233777e8949d3aca4aee5ef1b79e2299cade50b097959f0c690103b7811820086b20c93c8c8156478f192c6dd573a579c33775f5d40e5f396086854a102549859d02447142d2531a85a491c54dd88415e8460c498c921012bb45c85850e0cee5e1099fb1702980f0423d18a189d472128f2a764e5c3609f3129cb69a95c10ee06d5f29458850cf7efcb0b5e9a0fbc78f075f9b8b8fbce7a678854ae70779dc71c2e7285ea8b4d133b5524291263d9d6cc4195b996b76ea8df780a069371d992a4757512937444241744a4a224aaca34eeee9333faaff3efccfc5398de4a81b0366374acd5b08931d2182445d61cb575a5328e3b73df273fd37aa3d5762d05caddaac36128bc2feec4587e632ea369ebbe4f75b6625e5ff3ac690d54c33be3dbd36af8b18c6535ebcfaee17d1fb7c97a95c68a4dbcabfaa7ccd7b8bfed29bccdbdad492b7ddad20446f3d4a6b9edcfb63e7a8ae21cce4e4e331a4433a64f6633255dbb945b572c331a4461fb7158b775f97febb67fd3edcc52b7b3d570c6a4d604a81a233f7931b9b48fdc99121d69f7a4f71655ab54a540f43fd7be56f5eea528d0d7ea54141def163afef8e830962326282bb8a97cbc9f0beefc8b9b366ec24ddf943f97db62bb387779d24ea5d04b551a853d65797a52a2484b55b260d1e57d9ba938e1b5c0840c77a7957a669830e1f92032a1721f77884ca08ca5a5e9884473e0fcb9dc8fb8484445d21a221094b84844dd475bcee0640cdee2c5c50d606711387c8002359ec64712fb16a21206f82c6a466b67eee24e5d6ad3d6fd49356f2a25b39a6f052a3feed41723e576aff5934acf830ae28fa954774dc2b51b8583192949a2c3d72693ddf6cbf096555d92ffb6aaf5e364b693f6a59192244a5eaa9a34a94a922fd584891299927ad3b29baeb7276f95edd732bc652ffb8bb7a6e1f0d6e1f2b36cd7de94e96afbafc9f096ed9bcdbeae6299b632d9d5e19bae3799b6d9acaff799bbf677ddd56ed3ac3625667d9dc4acab28442053e7f149f9629ee81367b2e2e80cccd47dd99722b39b9cfe9d619f7341bb52b6db7667cc24139150e12fdb6d9b71988a93c9b6ae35b3de8cf74fe1cedfd5f6e697f7d45b5b538aac264de6791f8ffbb883e0e29137968c4a928c4341578733eda6ebcd027b3582149aaba44cf7d71b722f26664085bb5746ce4a337a8f84a399eb538ca340206ac085fb78b1d5a7495ebb6ded4247ba2bdd57d4c0080d78a074a741d5b559adc1cc5dd4c0c8dd450d76dc8dc62441e44f9966c569318359064614c8dd5b2e66e043cc20c7c81cee0e44a94a0ba39534e3702e178d84e114a6716f7ef95f9ad8caae8fcb8fcb1fa5fb262e195f9bee9e99aa32514d475cfea8f14b4caf05c2f94530cd9a7ba99adba273a76cc4fbc7a7bcf8c876edc65c46fd1b4f9176df6ab3365a77b4ba77ddd5f2e223a47147ea237f73a73e127480714675a54a546250b9f33449aaa740e5c5e443d1b1e24ead2bdd99db92f76f2533a6650efa916dfd3459c5b92d74fcd9da874add9a736790a634466177898ee5ffc65c70d3ee5626fd1b73d1612cd509476dc9475b9f4cb92d4f4875d7a4df98cbb54fe2902cc4214cb88f60be50994c1c8254fe99b740fd99a5b4d5a9441282852b45e97ded587e06434eee9b95866daef7494da1e89804a6ab619db18e3ead029d5a5bd95012ba35c6d1bd8792e0bda3d53069f7e36edbe659fe9959f5adb3fb393ca3b7da5d7310de417a2c2d3d62620c4ad9f2a76cfeb2b4d45a4b8fc44cb3e69f52a29d9afe8d02d5dc89b38ddec8aa44c7dc897395af3d0e9354dbfa64cdbafc396cea2fcf7b8e26c63d8fab3629dd436bf8cc659c4d8c73380cde26363176c251da76b1f9473bd33ca9ec6e0c1f4969fbb471d3c64db66b77386ffd49394bdeb8e97e2ecbc64d5a5355a6b7dd7a2bd24f552b1b37e9c7494a493b53eb37f33b55bb7375422abf2c632355652233fe146e5756243a8e74e3a6b734729ce9f09dcd92d00da89e0599f54baa93222b8db630eaba504d9d5edf6cd60ac651e597a749be49de2d4f92a73e731aa8fcfc3977d7f1c8f880eb74eeaee4ee11f1395ac3f4f5e7b28cd9ae2d317995caa5fcef4413738c728af889ffe29c9576db9af5d4a2c3587ed7a412e32a5787ef953769758b8e5155266d2bcf0ea82ad3c576d7a76d71164b69bea50283ed70ed2e5dc0bde8b1637f3ee428815781cf480aa23802538457c3cd8a1e2b7820031e2b42308128f643957fe57629bffc9c549a59ca2f6d75aa59497c69e1ee321955c56da1aa4cf9a576b72ad1f1a7ea0dcc175a67b66b67d91ac95ffba4fb53dbde13d37d62a09d59b37488e20db4a3d15d6ff868fc9a95f23be951876f9ace76eeccb42ab35d4b9ee5e719fd4a9f6649a819f95cca9ffd6c9631ae6adbadfdbe35d7d336bbeddc97b2202a85cec61f97aaf9e54ccbca1ff3dbcac70235a34033aa2fcdba7194ded7c2664034887e99594c858e3b7aed98f1e7988c3f3324549569e6437f664832a632f3a1fabeeeefd03834164d69bbefefcc7a2bb5edda7246e2fbd987eadca969add5309899ee2f0c96df566f6522ef4ed36b75a59d9896b6e66ee489d3959ae6ebea4d3fd151df9ad374ac396ffd379bbdd5fc407a06863e91d9ae7dd9971985697d32d18262f59e3f3e54e34e325bb2ccb8ee68b4ea6ebaceccf2d65b26f363a6a1a1da121d1f97bb7de4d6ac54f3436121fba3675787674d3e74d4d966697496df29e3a81998d9ec4b352dce6a3ae6af2d95745baa976efabef92595324f1ad561d3dcd12ad53847a544c719989a95806810ad59e9cb8ce6ff817dcd4f6756a29c9492645e9eb244412d59998d60661a067bb2d6f2ef2ff9e9583e59f3e7ba2d05ca785b0da5c337a09a9f966fd6fc3b303318cc342bd2eccbce2c7f77ebcedcba62a1637e5cc6545b186c46afc59f31131d731547b59dfdf88c3f3e7af75230d8cc9a399ceeb30dfa4c77401bdf5aed4b4ccb16e86737dbbd946c36f536efcfda666b3fd75c5a3033aafab76dd26ad0c537577137bd3381b22df76b8bc3e4c89cfb795abdb7ea7cae74a16399abed33c5b56b7be84ff9a70fbe14a8b65471b61587c3e4d32ea6e99e1e5abe6956bdff6efda4cd5b7fa6f9c4359d0f35eb8d3e79f3e77ea7ebd3cf47767fdb9a92cf65898e527467d22c494bbdbb313ae2ecc524d5fbd69c1d6fba6ea88d9b8eb2ad4e171fe9cf98093749ddf386244562f36ec14d547054cd4ab52ce58d416ddc74dbb94fdae95b7350b66b97be1e95f5c834ed0d496ba41da2c13ae38d6b29d57f061a7a4655d6569f0175869433a09861821faa2d50f93ef43735a30a3372a035bf19db8c29666c60061133723405d259e3dca5b4fc0d822940d082ebf0a59a4661b319bd5689cb1254931215a5a4b17e2e57631778088271acf9a16a7ed96b58195a5051861265cc8037fda1d7d26b6906e60f0fcb3075191c543347a3902187b364cc408600dc69143214400d05f3e5068b6fc903bed50616a020021068a08a3044f02b7a946002d896d21381980fc75c838b18b450830b2118101ae2bd207073772c4b3bb2da1e8bf6606e029dc7a0a08b4d0fc5f02f314e3ffed24e6d2757e3815b7805b4d8c0e3e113f0882ef00037c3cbc019303ace4330a090dd6ae66460fc70778f7a4b55996a98aa32d1c7d9a8f167b773b8af9bce481a4493cc7ce88c9cd16dbfd27476cae66d5a5aa5e1a7291dc58eea789652a4cd34ac292e631ae776e6d6d5047a9cdd77fc793d9b51bc4fbcf301ba38bf083b6d6f7f6aa1e3c5f4d637cb5b6bdef7b7a53a6c858eb9936e7c81a4347dda8d7cf25a283afee84cc378d3abebf8a3f5a1e553d91ad5554777399cf73531ee326b4a12d434a33b13a87c2dbb78f69a6afb43e5890bad741fb9b8f431cd1cdde55a5e4cbea65abf794ffaa479e6708e3e4ddbfb9f3f476b96ce1e87a16654ffec72cd3887fb283aeeaa14b6fdbeb6cea066411e64e91245c7d9d08ce27dab69d68bf5dfc8faf966a1e3cc4a549526252cb2a82625a62a4a50b2a62c4b51485b9ea2a09ab220c99e94929ab6e44e5ac3d706e52fefd9656b5babe1a02f6bdeb4d297aab88b2d6d22eb7daaad3573b94a475dbea9c3572ae85a4c06557a234f4df56b9ccb676e97abce3f55566d2b694dda99a3fa27e862fadabced97b2a60fd5f6b3aed476b1997fea75f84681b48949bc71ced16bbdc49870f937dd19dfb43eb125ad5971b492f74fb376aded5a9386ab369a712d2a4b138d82dac274920f458bd01109926cda7d4f3a54feced479d7abcbf2c5f01d61e9cc34add48c664c672f55f7ec46e29cd24780717fadea9bae99a4444d4e5ab3f4c95f4cd4e4bc9138f72ba92caa9800cf6c637363535fa5a7d5239d475aa5790165bc56e8d20c6e0850e1ae67d44966bb7647d6d296b792b227ef89efe729d997b25bdf24711859696526c639d9ef3771969517d3eac5b4f24f99aee6f2b6adeeff7f5773b2fd78bfb63299aef965f8ea376935ff35cfa96b65fbb5ace697e9fecacacff96b5fcaca8b699f6fba6e2dcbd5cf52a495d2329969da1b89c3a4ec5a9c6c67e672350246221024022fba7ba9f2a730131721e0228b17c1227151e5eeb66bafc597c2fe9e19c685c94554adbe49f16ee2a2888b0cdc9dee5e6a579aeb9b483a8f19870bb798dac26e11e5f4a6eb4db6efe79aa354e31c85edd7b98a93d9aebd67ce651caeac32fd26794fd97e9dc5e97ea58d33677c60c226c783591a16a248410a6e3e8454d0c3bae361a51ed6261e56260f2b081e56ec612de36125808795080feb023cac1c0022a651e4621a486980e0621a615c4c63bbfb4db86347f8c4ccc327c278f804091e3e0183874f14c0c3278cf0f0890478f8c21a1e3e8185874f7ce1e1136578f884093c3c802706c1710de1808b43d47071c81a1789ec7091088f8b4490b84824c945224f2e1209c14522d8452227b848c4051789e4e02211215c249200178960e1229108ecd0218e61c6c5316470718c1c5c1c430817d30071710c03b83846152e8e81c5cb25fee02efef072f1071e2efed0e3e20f485cfca1c8c51facb8f8c316177fa8fd70baf80309eeae73a4021dae1c20e2ceccc51d9c8b3b542eee14c0c51d225cdca9c2c51d0ab8b8f301177748e0e20e1c2ef270177954e0220f1e17798c2ef280b9c8e38a8b3c40709107ce451e23b8c86306177900e1220f285ce491051031bce262287331a472771d56887cc7ca91ef5861f21d2b5c7cc74ae93b56c4b8bb8ef08b91875fa878f8258bbbf31095d81e2a01000f95b8c143258cf05009273c54e20a0f959880874a6cc04325d2f0500939dcfd95138a3aca7051c7085cdce1b9b843c7c51d405cdca1818b3b9ab8bb053f441cb68b38ace0220e3bb88803142ee2e0007767f9d849dabe93b4f39d24169272707642f0c07742a8be1302ce7742d0f94e0825f84e082af84e0835f84e083cf84e0840f84e0848f84e0850dcd8bc5ca22836b9808b4dca70b189085c6c22878b45372e16edb85854c4c5a220178b602e165d71b10804178b6e2e16e55c2c1ac1c5a2165c2c22808b453fb858a4848b450a70b188022e167dc0c522365c34f27604a8c4a804f06da5999a744c213333321009000000931200304024180bc70312c16c9e86ab0314800372a67290521d8aa32849415219c20c0100000000000020981a02a5295a29c7c8d19282f33e01009b2b0265b1c6599152c7f19b177053c43555c0be14b1bf9c5fad8f1a6dea9b6020874aa802915f6811ad2cc131fe698eb2978a280d50a1ef92c4c70a46efe9525d1ac4e81034e235d5337003df3edf50b9ecdfb7fc52a17fd7f4086af45247e6af2f529cfe8e3149cd0db26bd903b6e488f4226b19e01250a3e9a2110a17132954b2729741f1642cb47251420a7add4522169a8e46a998080f4d3c70dbf53a0f36dd9ed1c8f0df14b9ebe397d2791b889d13924dd5ccfa3023e766edd6e5f676fa397900b4def30b070fc2477525eed178d3873c083c285cff25a8309d66ea8a70a0cda27360f908165e7a25aea728e39205ebc3182a9f66d740cdc774053a8fc169e04bd9730ba7ae045646414bb46fa4aab1c482844d99f544e36a4259f867339763fe05898bb9a20a5658329e25a8d15c75f9d01add8f8653879714a8aad6362c8b67c86edf38147d9b817573d83271a1192d830a836cba0e6fdba0230b64a236790111a66f81a5c10025160bf3b1c71baafe84642c27f24d5aa5b18e4a0d42349f848a78a8c5202d01ccbbc8193300d990b5dc5ef3a30dc7d2f8c94a8fb15806e435a5310fe768b2f226898bc334e1510b7a2d8832e01c3ad6a8577600183ffc3dc1aea0c6f80a6ea843ac6c2739af045a022eb631c4714cee200558fa4f71291f4ddc0f7c327e2b8899b4e1cdb3329b898df6cd3ab645eba7a92d95ec51ede37df57e99b801ed5c31978614f484bdf085cf2f9379c6af1120197c6cb5b66bd50fa4cc28e8bc48e48d19411a1545469298215a4902f6e8280b71a16f6ca743e3034371caff99d6ba142902ea7ea1086f52c049b0fc08ee310b25951c59f3b14f485ccc16fa5ff90fd808deeb3a1a08e59eac455db4ab051a1e400c887887a0bfb39a36a4e01da402a3c3a68f6a2efb681b4cecb44ec43a9ebffccc0595e83e47958328886dd0ee15aacd5d04cdba3deaab3a039a5dc52f0f519ce93515b2dc2513e911cc68f85a50fbc8fbb01215320a1f629f5a82146128b840010e72d8235bf803c66df8c2769a9b6728b807c3c830ccbce0954bc0b7a6c81a5479db1e6b6a1c1ab2054f8ddc9786ef7c608c6aac64feca2dc8299441eac3ec4006dee5b87a887605520c18f44abb9208536d5ff3a004775f8087e46a35398e9c9bd99239b8dd985493b305d7bc1dfc36a84680bb83712ea93ac6e77dc19b02843dc5658d2a48c3656cdee3e633a8652e69e51d218c104c913ba5229253f3b5f86fe348a62ac219d79ee8eb07221073e3671eb8a0e38b5b1be86b644f52ea8aede9db96da275c18687ce2625a8eaca81e37b2c1ea06d007a0eb32feb6e9ee7fa8ca87d8a12286ba76c42793dcb7842e72b0161d36b22fad1f79c893a5cfee9a3e5bdf39de13c96632e5a4dfa92d310fe400b42884e1bf8bc7d66877da31a00477e4e039009220603780f1dde98ee7f890819d0022e88a8ae4203cc01a21c1e19541288e058e01e7a016e78c7dd60600bce0e888096c3a436ff7ebe513b3f3a7cb90bd6b244751329e56b5e45f5930781b959a41239a2796118cb91708a260dafb8158d5bc416e3d8ad1a2e8eb9a4695851d5583db437d32eea0098e4efff1c8538d7b75b7b179ec8909901f5c4bd627463240404c14ac09ebb49dfa20f840094e90038886fcde1a7fcc3dc8ba721a727db6f1d62f32803a81673d13991381179cc736790a9155f57f35e2266486d9f7b1bca38de118a5c8eb9098f3c9de038e6af2da766307d48efae1b6e13f86d6ab2585d86dc3276cc781c28cf08a2ec7501620d10b0e2bd1bda1f7c9ec93531806e46d096a4521a3ef7fb00b084a6549150e5f2463db5db0e6da1a1c2d439b35f1c7b7062be2c5a844adeace61be787c05ebca890a291224cf00fbb807edcb6cb25f99ee38d82d40af621a3611f1685c7b2af18bb111591b4158ef6f0f334cb1e205439a8a88f00483b1421695df54f7fe4cb310dbc651faf56b3c6089113f87bc71e8011b0eb24cfeaa13e71c87319ac45469861e8ef0c66dd44eba1cdf368ef2a4a7fb53fee63260d5f839034786a9388b3d635b10174966d94df2d14686954b5e877c1bc53e2f96db90f8712979933cd632179ffc90b229d0bea9c5472297da974a00976f8de68b1da90c550fa7f98ae401e0ad26dfc0612ffaa83cd97de3432c98f8e8840dacedcd49d146b2de82944d8bb8ba11a581bc28573335f946148b0fd5aa7bb9162d183911dadefa20fdbb894b5578203e7524ca6d1869e0296931f0cce558f1431c54de2ce131f31149e4445db510120612a2a2ff227d3811547ca8f1aa21936d55b39b3ce73b42347802869f2287c36e9bd5e58c0b13e5473b2f08361a2e82357501170d42d7b3ad97a92ccde36342c70b4b442b8d351931650afa7340eb4088a34907604de457bc0bd4e77e585d152591cf9b366dc3dd46ba6b64777e2fdfc3e35e71e1b7cecf0730156c9c5c9ab70412c47c1be40be0da9e5dd53f4e357538d3d62570ada641da09a5f071f27c4aa9ee8f295d61b1aa2025a69a62468270ceb18b6def77924bdd6e97ee68d29cddea60a01cf9f529e77fa3498499ccc9dc7059a0bfa99d54fbb93fd9316266891df4f2429432624cb5530787f41792c433c1f2100fa8165b49d4ae8fe60fde9ed641140538a16078310cd2bfc96f5447273741d92b0eba157fccc94a8c22483acc34d222f5df2324e2dea7fb0367e354e8d76565969d2cb84dc91aee3a58d28ecdba617dddd6fe34f64deb4455192ec92b02fc8d757f90caed2538567840a37ab042fd0f91d221e0c22ee41025aa123f5a0a6703855edf03e4ec821f2a06ad04872b03046f0edc776d0035040448dcc7f29277cbb9ad186731b0ef6556859b9da7b5ae7651af672ec568a241597883a16f9a553d031a5426d87534edd71fc0d8c1de4be2c5630cb4781a1f40c770a345bc2e9d3cd23cc154028cf0f34efb0e84beebae9ff904d60ef88098bb49138caf8d30e15e2e8cbf035939a9ca1c1607bb793ad8efb3221f86c5a0e80f85e9ce1b5b36f69acfcb5890cee7b7043de4cd954f378b5c218a1a5cbd28585f7f7b527d303f92c92a5e2b7ca3496ff9cd2fa7fe91b3db65acdcc4df634e483fd35507818e0848bf0c69dde68d580e176f59aa23de20f1021f2eede580327e2963e955e0b57ee1b1bdf42cd74bba8149927cc17d43a69e12d0ae8ae63b550780397835ddaa317434d1eb604918909ad781231636d1140c1b3cfa67530fe761ef9b2a98ea0cde1c51f1769845824feccf0f9fd54f12871cfd878f0780fbf1d60f4ef606df7e0d4e16a36d6439c62a20a8a5cd7014a828e69af6a1800089a0671460b23438acd3796f99864be1b682eb30f5d50e90922a99a35049934a92238c8dce91cff51de3dfd934b783d8ccd7be13bd319551841047369a7d41671cedac2ff1c6da4b0f8922d4a394d442de5fa35c64cc6f8fcd322245a92cfe6a7b5b7fb10e81ef4e587994876fc98b3a2fb7c02863ec020dcd82ecde9650599cf0ff767e152b40d0b1cfd91b5007911aa8834467ab8048eae88771918c100245fb8d2c3a0e110169673a9b96c3fde2ffb930d2019db13224023e8a27f168e14d59166c8183710ead7229bc7a3e6b3f780111488e81897b0aae6c6116883ffc1192c84e6890a92148352b2c5d35466abe150e5bae7c34ccf91726ca13cb2e3f1e1c13af06f3aa7260736b08ef9fec83988549592c14a872ec98e69e05c11ef3e9564a6d90516ad899bd304b88d8b75a480ccd2e1c7a1cfaddc05a3f5ae3427d6079b01ffe349e67495e128abcf630ba66324532bacd578adb9cd99086dc15994f4d1f79a4bd85eb9359e6b0df118198f55d99d841e54f7fca270b7f48e927acf9a7daf36a5cac2ea0974045d4811f97e21a61c4d30177074876aad26316a95eaa476beaad9678bb64a326752da93c346c878c071edbd15f39636dc7da9621a8a6ca71973297c94afa2e5580bb27f5a3e5794f6be7c5dfa2a1f71477a0c5b8da0461d4183de6800c3724a4f023fbdfd1c70b9b7acee58d28cc2ec9c81996e13ad4e09c771ed94503fbe24b97f30215c7f1cc25315cc01b6d1e7bb2b28b8c6994561c4ba5fa605b35f358a0518b14159140c06934cfe69cbf0b86730630812fa559818e81608a55a02af318528ae8fe3d5c405708c9329bd78c36b00e3a2b45b31c4982513dedd629875a026822fc2e54697ac53b636ddb016519463e1924ba9640b02c1e42eace837c8b3892a7c0200d97d54de3ea9cf1c38d6e8b5695142abdafca574dce53086fdaaeb4bbf67690fe105df6319a1aa8d3acacf51c58a8b279faa6e7688613f822b87717733da453eb9ca6b52861d13699bc35d3a4de762515c1f0098218d6b8c82793f899343cde6823fa06f12a2bafe42185f8897a7b8e0f944cd0e510f3486504eb821cebbc22068640a3160d34c41f0976cbb3e710bf957012a322cf32e4e8ce574d1e4a2a404484d2f3ab355d144a703781422113c92238adfef0f48c356e9017455a77464921212c1cf496a528c66333d3c7804435da3d4b6fd8dc197fdb3b2f43908700d5f619ed33ae395a9925361f82a7df1bd1e8b154139c61cd3e8651d57b2cc48ea71a1411f29084c65ca89fff7661d0d2ad61a6de140e82448ca7997c066fec0eaa7b58387d7108a8c1bfafbf54e8bd1299e2608764891abf95f6eb6f7d5c31bff1a49c216b7ce8aa00773547cb592c57ed96ef8320ea846810ca8a5ef45e64ce028663af4fb2586f22cd354a86750cd9bee1b345ecb213e36ca183b3b538b928a54cddf5484742e46e920ccc42438580f71cb8cc9410e884c1e95191796b0ff55f07024941630d6ed2450a90c5cb8d3dbfc41b8e38126148635e3460901c2e9d2e3dcf22f3029c1b01a6fa8305524dbc8b9f52c3a87ceaeb3ed09a74221ecbd19fcc6e4c21d92855e936a902aa6a724cc817c08e5668ac0c7c10c2bc4278d8e57ab0c28094ba3ac20bb5692f4b7fb35c30aad25a952ebac0fd084cdc29a499d1b74dc2472f23089ea343465a12094566a9ae347fd5f38a78b31b62ad89ead323a884983d1bcd97328fc3d08081662bcbf0c021e7594624140058de19c854f9fc248aa069123e25218884fa4905dc1018f523c8e05c9ccc241f143a17b214d4a7099d7cd4b381c603b9cc94895d58970422c182626dc44197544388cd6b92a9b0612f683084a53b114c91094b2e5dedb992f2bf4de0005bf6deb0f0bdc143b9757f720778c692b474cb985d1022d2d5e7c9b639911bec47134fb36a3160449ff29823dec41d34c035476cc4406363d480de3e12220242b653421a15a5ed521f3d89e95da810e47e87a356a9c0837f19d72c092b2912b33a7bbfef0c6064828675706d9994ab3ae7dc235d9cafb852356300e951c8b662b1719382a78dd900856fb9d6b6a59557f38f7516ad15465e469e3ebb1707c97bfb060e48e71b39e2f5173985b27242d4c12a00d755a50f7336bd665bc125e8a756faede236086949c3d5ec911ea6a0b6dfd16e4fb2e4050686c38764a35275a0506f65a920254c173243675610d5b5e36404ec005e93e43a3482972e500fc9ffe124a0133690f08182e830069ca1310c66bf2dd407e8160034ec5098caab0c84a1297dd45d59d388093e9710b6fef01ec03556c745ebb103c72a805f058bad4de22772743a34a6d4c4d3b8a1116c7d4c06229ff4a5fb9d7e28dae5b4915c2268c0b9e8632a5bbe78913f569325ad9b329b6410a3cac52b8927548bdc64d00652796ede21570f3f2fc5c0cee8c0a2c2a3f90b051a11d7812b1d30b1bf8d544e381978b903f008cdbf3a0d13008bd1d80b0bc40cca00ee27d2fdf56a677b1bb9e757483e09a2df3de737c18286dd7813efba4d9525309b54d313ca9fc01779acf153291250225212a284eb69e5b521a11fa2ac38458338725ba40ba2dd9d7b7ecaf0efedeed42c03007458ca80f6185db70bf1d59b0faf906fd07a821fdddd4189a1cd360cf76fe4d8a46823d16726e2715b68c6c74f826cbec7b893f2ea5f48abf73109c2dd111cedb1816510885154d17d0935d62bde262898d45c5c1265a7bca14ac19d5d1a5ea251592828a246d17f9d90cb99ab4626480cc614a8812004f88ebe8849a830f6c29d754bfa2c732f14f3557f4060c2a4308b93536304d19626656af1622784cf0e78ee96bef16c465465c3d315e9055dfd49497c12f6228da394f56d95bc0f0644260eabdc14bf0a7ea4142b713113541880880405656484c378b00ea9bce23bfe17c4116ac23c0d8be3ae81138d83a533d45f311d0a10f8df7813dd3ddedae798d7243deb938ff57541e3625036effd654d855f8e459b31b83bcd6b08a6f3946899e113c9bd1f119318063906d6e2f0b3ae2bc9246e436073a20b3061e223cba9c51d8d7f7ef76e02e01e14faed7d77e2cc5652496d850520e96f86ccd3df7a03a946416e15e72de9fd83dc605516721de3767af2f9e518067105f4f87bb4572a7bf328fd390f1ed2b3ee51894deddc090188a1bcc2f363b2bb2f3d307254c0d8243056c789c395dcb1562c8b4addb53942970d4da5fae223045644c5fc6dd31697d648f048362059b5da8dfc6f652754ada18af960e30de9ca989bbd83c97d301256b37c92ee23bec863d9a7f9b07e28fc754c189a50bada349e56f95e326d75066dde76b855e16f792ed8c0178aa992cbbf7d0b14494d7e85ee60e9d05615d92c0e4b16f6ec8d9afdf610bf311c0a31f23db028c46296de47355db2653b57562f35a8e905c19c9e126a43a0e07adf810a5d66a12c9623ebec70a1d69a5ece3edab920b6360099a9df2f2088a1dbd2c8e0dcc9d0fd5e5949ad024d0d82c402a506ab8fc4d25290c5f20548818bf6683d12761d566adc07b26a6231f39ec1c5b1e26af7d594b17313101fa188fe718b009677dae0c8d53ae3e04142da5f6d3bd4076c54f3775c792d073cd84da7d7025903c5b908cac3456dc8c4a7c60a16af90159fd6ea02f0744b2bc702f1ea05646683a67648c7981da39354f4d258abc3aaee0abb458e39352c0e449282c57033d189305ab766fe04f79c35e02dba19dfb56fc3e6a75b3315c59430baa303324c0ccd8317482ca5842d23251bcbff6fe5b585b8762c5b906cbd60b16e0ca0ad2a837b7fdd86047b63e1b239fe2267bd4b61eddd6bd0da6d5c830a82d1035d1a30d9fe73cac1120e86f1fe8948764b9e73985de4b542c8ba75b98b275ca4878ca9025d8a3b40299849f41b7f01dd3f456c11fc919721b9c06c0dde4b6d9a22ad7abd2da1e99729bb383bef075e74ee91e41f76695a467f1596ca92900b6d3064edd5d3f33a7805935c02d98ea99efc922966d0d2d7bd6bf87fda18937316d5e5b7c73ef4978c34e4ad41b96fd4beba2507296ead3a778bfef7e1b4e1be6dc856dc3d9102304dfe139a2fa8680e5de887d3cac6418ab65f51f03b3e7c47f57320e3ea2a16d5b660270189cd275fea9d6386a7d5bf491c161bc28ec2f3663446fd0e4601e832257b976a08b631a4df8c9c4e6278c44038ab781e02ab1a43a91bfc2e6760464cea889a51f1970bbc07588a9908a7af5807963306ad4a57cbe6864d5d85e2598b9c8e5223e1ca1a1522f338edd78842ebc824699e8697f1f708252b028dfc4c7165e8a56b0f31da73ab71eb160569f8a5b71d8c101e79754d5d26230d80ab5d7a005ecdfdcca1c203b7f977dac8744901efc6069cb10674d2884baf10111157f76a10c3f623bff044a0d7f271b4d4e12c3590628806a43f3c2a88a87f84e9949369ccdbaf68a879740cf6f38e18b8e5247558f734a9ac52ae94d6fa159bcf5a3d193898c4349298146b8ade3cee785f7691027815cfa0690f7751e856517e1ad27ecb6fc44c4f48ccb1e6fe45b00b556f1f8170afddc15f31bca3cf78a23d8569ec74f8b2022f0700f7a62328a11945163121b79decdc5156ddb05e50e01c3aef189b61d1157386d4049098b5b94f04cb4046038145a6ac3fc1d144bf9877d9da82955461304ef72d9cc75ed5d81013f92461907c8979e11cb2f301250e0d1a05dbd317312b6711f344571ec461a3f7455af61413600390b751107c90c1f1affb88c68d3481071dec063cbca549223b6d34a1631fe1d2ee644cde5af17a06352bfe0fde4d7b2da0e3daf5ee2fa07f196c15974897bff81d61e435d489b27d2af986be6e297564e520c167617d323e94d1c6de1e859962a4b32074a63d8c8046fba8e3eccbde89c8c65a8fce93abf3db8bf2dd82a68f38744cd98c663a6c1e643b47b8ced4e8382f4f9232ef24801e6f0be047252cda4abb5d78bbba4145b2c6dd810fba1ebdd891ac38ecb7441ef62625bc5c86ef723965af821210f2ac7783e20ccff44fc0d60b258be4f3078499040b033918504eccfd647ca4f410a1c7eddc080e3421f4711933928d5af62f489dc09087393bdff1431ae54943b3d88a8882e9b1292ccbc506384b963915fc1610a1ecd41d36504b7cb8a14cd5ddbcedc487fc7600ee88249eea728ac6b8b78fe187aa05e8ed8216f9d107452a1cc0f05c0483074c5ff949301f9fe3c3942b6b80cd55ae5e1c7e18401809a5ce6b1ff47737540aadb96f106f7691e931709ebda44839852ef403659d1583f5390e5cf83280e0be6ee837d6b7566c919c95696ad77aeb91301587bab76b564f3088cea47caa69794445f5c2f74e4d1a034c3661a32ec8270d2d45b7d9bccc53204e57eb8874b932d0c4933535106e0e10593c95e13bbf42342209fe73ada9948470098aedf8ed810e607adfa7a7b37a25a17ec5dacf3fa4525d3f1a029b7ac08b64068cbcded6d7266ee2a550e8df04a1561e3ea2b1d9c0e7f1782f3838bb49441119ed74bfa7702e54a88354999ddd77af9325e073465fd0628a627dc0159a7391da9c322a6b15d802af107069d5ef217338767259adb17310c4cdaf9913d82d395dc7e827fcd0d27c493887247a9cc9a157c373f8ad9d76adfb503c03e44a795f499b823f7ff69b9c479c23a7f11f776436915cf735b96f07b2d63a52d7bc834f581db62c36a43346d7d4218025550935872da447019bc06232b34c1f710005988010cdec2eea65df145025e2c6b55c50b77a467b91901ad36056b203372be10fc682d64d7bc7fef30cfc0c0f9d20dbc14aef366739e3f9677c6e3c00c371de4e70dfff9369a230c530db6293c4fdfabd16895bfd64b44f703e9eefd42f8d3f165140316b529244787d0f11e321e4d840af54b0e2de66df5ed6eeff61b9825894d7dab9e9ef31b2a5b3afdbbd81e9ea7517154725317107ae2b530838061a34f0c546a1325cda3658f00fd7858e0c3a476796434d16f057d1188cc3dcc9b0341b253a19a2e8965e3f06f61ca9d3e8c9ee6c084ff5180536f3052eb38543076843e08fee0d3f62bb2d7bd3baeb27528bda8f39c927b2b2bfffcb9df83c96302ed5e82c4342e42cd9f734b8318aa69be2e9e201d47d78779840c179c8ec37a76d750e09dfe7093674021b4f55b708cff85a11388254d88830d4e6d1e8f63ac43b2610f483ad4bf95309d47e3583825bd10104a1ba3b5ce830e8c5808930ea274284c0941304ab6509c64e90f9aa8d8382d3c3bdc88ea2fd9486e38c93772665d353d2426e32e69778abbe50a342174d4b25ec58bfe550f375ca786e6c8f3d5661a1339ad41c227f8ca18f476bc457257d6ad6b6a9fcc564c6dd50aab81b2962ff5e3d034e1447059d00c4fa5d4936ca004aedec2fa03259317e05daa1e5d04b1f77063a4b314a937c0d04426cd991dc05f68dc37f99f151c6cd4ff7fab42ada690df2332724dc168ce9c5d33b6ef201b358b764b37c51f6ffaf884695caca94f556087d26e82fff1ba2434af893b9052aea6fd1d37f9cc490268535e6064f07b7682dc8f709b5bbab8867e940df8fadd940a8865de41ed839a63290e35dd577dc2a89ac58824e8cb9ce37a64243fe5447b68ec3a56a96202232e77196bee9f3a8db17f7b3854dcb871440b43855bce9d6e1fdc9485f59b2b33f8a8e1f8a8706aba83fc199317b8fbacb1f8b278c6a92558ab7b3c005a71c22fcdc766d71416c50e7e5905a02b4b90ed6350f22cd012007738df16b0d473c31b4676dc1f4a837d15993193be17cded6e673922f043bd2b455ce4807ee8e2ad64cbc45693182239433a83d44a8648120c66247c7a530c23b4c478600878b14c74686193f5382e921ed7c1d5b97d1bda96c1e2e852b5be654df1ff2a3ea0a84efee9c70b20909697a2e2a6ebb2200de5e82e8600b5b39261e9ac22b41706a02b0d371c344ed7e665bcf55dbfba1a78df805f1431059b499fcc9bbe0d835470bcc224458a89bdaefb2592531535f31b61ae10904f533be9890e0995d93590fbb4cf5dad08d3c16cf2a8c5b3eaf51b19e3b66331f55a2321e1158f985955991b794ce182d52a4fc450bf54ef735eb7c7d84f256979b6cb24b527877cc01ed758ae28850e3c514fbd9848f15135ae7feb59470336d008348c7b7f293611f6d3c439060297ae29016f12085057487388e8dc333b500d59a0cff3f2f3cf5ebcd07ab7414cabdf15406dd99e22c629cea505742622f121a21d679a40b559143edd23041c6866d33df1a1460b79853ee318666455ca8abe60c2a606b3a13f3be46d15d59ccbe4db48fbcd19ba517b3e9dec272fa6b200154117274da09a43d9ccc93730626ef9a6a40b89449660c03f8285bd03f16652884116e02b876ed62e183f5789a580763efd60fa8feb4aa6ada391b93c868089b4658c8a795fca8e4df7c20a5ec6bce3e63953df8a0a5b2593690d0f061fb9b0e8a13d4626ba5ce5f5a2a5a120c4e9f601762068c31295ac0c2206e6090f3758f163171fef3f1842c8e48ad21118ed83fca30a53388987fd77bfbf0461ca7be92fe4c77ddd27d3e381a87a8b3f93258be15e43481f43975df687af40b743d6c5e87766cec57a0d946a6f46fe9118f6cdeb68fd1650bc74948325fdb5de23901345b6d7958747c262e79249b88b3c423d5eabf767a3fcd6ed80060c1759707d24323f41fab51405edac29ed4ee103bf90c494c6ea381954a2f0c268f69aa394808472e0f5c64bccdecc7b87e8fc34a6cb81ea685140ace3d0eb36cb8f4692786da468aa84572b06655b1d5d488f4c35c958def19a31f7a3aea1fe5e3376f8238b79656b54a668808c7f043e42d4209f85a9d95029702e5ddc9f5ec38e4b09f8baa002809855e6c21c15883c8da6b95acbb99023ed0276975052022109844d216872252b3bf3a2dbac0b2d46deb08fad4fbde0d980c740147fa22b8dc88c8ac26ea98bae55e6215caad98a84646105982c15b879c83c5b6b6a8faaa4010f0e11244c8125e10aa0d6aa80d2b0c5bed83b554f813bf95ed2e54e6fd845ac6106b32c1921e06274280897936a262bf86f8634b023982f166a00a54fb4c3a23609327e2c02c00021fc19350fed96e111fa48912fb2a250b2f0f6c850fd698ef14c7ee9e764451e50ffdf2e17cf86cb1d4bfd56929639387e1459e3f3e4dcf0c2e0f7af233b0c90ce49f0a3d8b26b8ae43c4e2ddc4e59e3f9f27c759afc68c58956d3172c0967a3413a231430834807f85f734459b8552b33b45096803bcad2a1e04079fff6984667d0581ba0221032500c173da12f621606b564b00e5f5f57fa64cf0ed0c350b1357aacff45c35925f29476bb652b8fb606104c07245fa575a5fd00801a03361673721af9f2a0031cc4510a6488b910d985fe560062a65f8833277ecd0a9baeddec616cc5dd8334fd1778dcf4f9b66e71e69c96510f3cf0ee848dbd73d327092640187220e451df2da4c531a1022848296cedf69fcd50f6bab042bab36c68ddd0843d2612ee7c92fb517ac3b1ab37fb99c57d4bcc02d743d985380921cd4d8b0a78063026c720af59e05192c973d36463a5561db939423df2fc5999e89e863538df06fdd8a42fba346be291ba10b16b35a14ca539db0b4a0317a9527aafc05c147bf80f0f39387bd40b950c6b94e84216867f98e2c59e5b53e8c42141a0eb32016e1cb866a25451a0e33444f390a87babfbbc1784f54092a41685c0e78eb9d8413eacc21ffda28365bab4dc0023aa64e725a35d1698995aab2f268dc0f870650701717151bd860b4f962273e50936f6f2bc733a8091e4583d93da75b194b724b78146057eacac9c35f93df546c7e14bf3dde6464f85859d046faa98a437e8a136e10d0df5b95365939fe61038ca788038162c12053a60223e8cec033d986c11e02b17a56e5ed2d9cd7e6d0b45fefefe86a21af0a9f0e50e7afc8ecbafbf25c53f88264ceb4650790abc7b6a5f7cfdc8ed53643e16586f4125ca3cf7af1c88a9acc19e2951c78d72f2af47020c5b600cd8fac92f8a22cf9a270caadc88d1663a63e3289f304f3dffc26f1ee79af36ee4d6d5a5f05fe6d75ff65473d26386727715ca204da7eecc2453a25101afc33901258cea2a825223368c13db01a4135105899ee2a4a0c0b41b70cf2e4cc974c380401f49c30ea7b270aa0d922db7c72ef27ffd4c8bf2a10c9958422f7cbc2a7b94d0439d6a17157284c1e6725a338d38c1ffa4f6ceaba03c1774dbe7a3e0bc283c9b2e44c94ca1d16f1b7ed85cb1abb280b6bd82efb3020671b682e071e8cff8f38afdc68ed8470712fea2b908eab5433159f53314f28869f8751afb970bee9bb769db23d8f3b06a392e7bf5050adcf841c8ac1f702fe0ffc97e3a8ea77879e991765c2a20d19628dc69f6782c1d23ccd5f75ce1c8d81b4694894d56f30613ede0cb37262ffd109043945b9e6facc2238a5cc47f61ffa5ccd73988fa83629c6cac00cc7fb35728253405745c91a11380e476bd01618540e8443c3301ce825ee418ddcef67f09d70bc24f44b826f41db1c6698cfd4b8a046bea4450f0891565ec3b7efc550d01cbc8f300cd2dd9ce388b43a3fe94b0e85816c4b92f8c33f2b762a8521d962dece5df34e99a3ae686aea1f168d201c65c5cd273962ef517ad83c8cf6ea259c75b28299f3d9e9088847dd365240d0c0734b6bd91231d00b3f5776475ce9265a86ca4c13d747597ccc9dd0da897b14a3c5e46227d697a7ec1597d018b325e8fc93e14d1a2de9f4ff22066d7ebb8318713e3f4fd977f9ffe94b8c5305c8a2014fa309fa3f7e410d48b954e88fcff301ae85e1ba3e855458789d3b197495d069dcbe936324c46a5cf12507e2bebfcb98329c3f8f941bd2d8878f47438c00d5f879db370569e0f13740d3e1d798fde52a9a633af5e5168ffc88013dd2af1d397cc8408672a1ada8905a9d0d8f43412eff5a893fdb6a653d768199ff98020dda889ee9081c043db59e09e789622ac08b99c87d03407fa4bb6de3a7579a5d756014a710d591b516df34501135fa3195bcc6d6b198c86e44f54ba4738af34003c85ea49be5f70bc3f1c95296b6e049b8b88b7650b11665de106ceb6fb48ba77e81f07e0bd69a1a30f4d12278900db6d4cbed0a950addbfed611966407a91e0b7461c88332bb0225c2905ea7d2552b2727ac332268ad8038afd2d9685fa15bc6257f25c9423e3aa1c4b4b05db0f7b122599f2d4aa430957accbbe8a243246c78082da2211fa9073155e6e3e1bbd688058941d131c0e71cca84b24d41a9ce4476a2e290b02bb835e86f4cebe786a56429d71619dee7a0c04930af14e4bc4bf45dbb8b19e0a057e0d17469b566f450afb6dad06ad08cde0dd414c67b49bdd490925af05e1d5c08ca5d518957ce39354cfe2975a2803b6e949bd61ab16cd77db6a76c1579dac5e7a0c17165f7641277bf11b86ed5705bb66f1d53b2f40fbce1f4b3e55f8b0817c7125e4618c93b9469e8609fa82ae220e50c32b4322f0ace8bc800167498234a4633da9a717111f984f0719b405b6fe8a3ea66b181591baf4e6dd4187ee0555fddb0100484252ea8c8711728073c74dd47b45748edd9c0cb6ba028f79cab38d5c97d478745e73ee64b9a52c52ab1657a56c75cd312a9df548e5fb084b7db3585e0f0756415cae17b10c3060eb91889d66d84eb365c658c16d856991a33b2d26cae66a0e1367528297d40c93e77ec10425463c878289141df2661ad374005698e2544870302e0655a32f45007fa69cb3499964240c02658fe3735d4907a8cbfd17daa80e3afd991cad35748cd248ed4a973d3c74e716215833df7f4d130283269a48c9e662669c56e964be558c0d2d7bdddbd4734880e341acc2a2a2fc26f1bff619414ece0b6c247799d31bc6ad8cd7af42013d99eaf4cf7341580c909502559ebeed4463233df5606c6e8e169c3edf2a5410cbb0d13b5ebf02ddb823d7abf05e932e93dbee65c6aebef06db71442b8c1c4b0f1ac6098d32d017a05d3cdd837f7ffb335020fe2db8d0fd4073af82a3e40213b5421f9700fa50f747603a8e5fb7f82da1ed61cdf3d6a57bf1efe4e01f40ced79ba5426ce7ab5bd84aa783ff5623453afbf19028615c9610b09e4813b39bc662dde8d5f5f504cf7cf2b459a7f30c2ac81272904cd1ebe600ab92c0bd12b2883eb7164b4d505b2f27838b1d66398d9a10eeb9bd212736d555abae41bb441885f7a070a6ec6b68a951b37bc7f63eada6ffe696e460ced8d05e2bd6ec8a8186409e63b762c2f236e9e9c2b717e319d33a5c6c172d0e36b2baf0c677b868039bef68558d0ea381006215d09174a586def6f309a5d7d209f3ffe1685938043bcc2ca972ec7d4a1e418e706da36a1dbafdd4cbbc0b187b936af694f44962c38d8ffb3a8386dd50b44ac7dc2c7298cbf2219d94cd18019df32477eeb8f7b62dfe99f268b8616e7e7577db0c83b93f2771025280e86ecdd9ac94e940e99141778a53deeef584b99a7eda0e0def498a4bb9670fe149a97305e9c804055025720ca0821082141bec4589030148c093200d5ccd98e49409ce910b29b1821af64a1d473c42e17fa713576cb7a620ee32b3fdcfe3c3bb38c93090c77370547a5e330f368bcbe8d46e54918085506bd7c6ec03db423a7d60fe0db740796d211ecb51d640aaf1da43a753c7ba4d14666da9bdccee1b4379881776473bd994f762fcb4f211d0af5a3599f657408536ffafe15f666b3a4db544744e70f22fd63f446d3a375a77782aa2fae9c93db612bbf508e0212dc1025fd5b93f5865bdfb7fc48b7193399ce21dc97e1b3e839f39cb72d824337b1c926643e87ce835b1cff22dceb4a87874dc790df12b5bbd334f5a471b3ed70c9d44fc673156b727256c3ee0b961977936f068878fde313fb0e1e54bce3085ce62ab3cb4037bb3d57f51def027acc4c8ec5a2863d1fcededb5b38b2d94c322176edb135fbbc966f13fe2aa3e4eb4497df8684f75affc4765eb386969828de234775d3d9f203c60f81829f41cd66a1f1e523f53c702a5fe2e4d9ca33d022fd2bc09d2a517772cf978f3edb8b107ce37a00cd5fa31b67e7bc7a6a6fc1cf48fed7470b5d70d4c68fe4dde08dd4533bbfbc28bd725c3176663e1319e90792078e6b7b6672cf569f8bcd5603749053dec3b0c60ba9861f38cef523974018f38c52f7d7c3e2fae39151f5eedc5efc1b78916ff651cff13cce3da58b657774e2408ee20a74431bcd75ada8c51236e86e0c89f600d62fc1c0d81e6b983b8147fb5592c3401f0ec6a17be3969ba705785e6890c735dda9791b9d3115ebdbb77e13f13e5cd81345aed5d5d9a75ddf41ee8e17c48f9ef3c7e98c8ea57e24983283b868b6d44683ca8bc3bb347f4f6964887dbaf1aad183f2038ea4f6972ef2db371a470c8f40700ba284ed93dc75b7541c299694cdc976beab9b422a9b147a1cdeb716a26bead34ffaa7655379532637ce0aa6ef5905f9a5b229947a10c60d5efe6b51c0a5913cd40376036200da732f84f50952d1b507adbbfa489f58d49275e084cc165a62d3e3f7753a1dd2baab16536116cf8d9a73be3957498c471f407656b3e80a730a3ce280b2fe5f88242cf636e176dab073e0fae4e3e0eff8cc41b097b8225706a2ed68b355626c1c26f2f16bee2dd8f55080fdbfcab60d43d0a5683984e2d05eb88a773ec27d18bdaf3606f1d6eb9bfaf4ed973b40ce05236283cc90e50c98f0f94ce62675f0bef5d522441e03c0633a3e59aa681778b8c14672e7714886313a55ffd32dd99f9b9e7155d99a052b48b7441117581af151929d5c380ae0fa916596c716889514e6925ca2c2d739df4d4d8186d4daefef2d5add409eb980ff670166d286ffbcedff087ef85a2971f3bbf96ba315f9d50bac0c7fee089107e0cfa54abcfd8bd2092baff6ed93b621204b8edf9f3b39adde28cfca3bdcf40b2d06de1b1efe726a4d878171acd11f96c5f4d46ab9da20ec2040fc42a6d3d8ed1a7fe9821dedf2929e3c10f5590510699a2328a046d545c71d1b8aa9a953c046a8bca0115c3daf4707caaaede9c552515ecfb40e7690a7bcd10d70b435545248b87b957a74d8c4f1320c7bfdba0453ee320ad832b2a9b3d9da7215b584ad709469a89ad272663efb4b54c9b1ede8cd8977e7d9e3f581caac677e4189f441ea59f96bea003f8f7a5b22838e38786d7fab8b2a40c8ea29801637f7915ee6731535eee47acf4a88646274d3280edbb8e27706b9c92550e848662ec0daff0b1c5b274765223d376061f2328c817b6bc51c1115e809ed41e1edcd1e63c2c2a14dade148688a15b881ce83df9b4ab7d0149a3c8e2305f02fa4f8ef2e1b5492a8f97a0f82728a0c7bbf0cbfa8dcb4882658b950fda246fd78f77bbe7f1e626492f60ab6da1a02192bd4c814121cdf169af1247bcb0e4eb57280993ffad34213398eef69e547ce6a5fbb643fc658b618eabf3898b37d7a729168068c786049b9ababbbd4d964eb22adc3db0c78c514eb6360402687ac02ad42644b14d07da89f1d07f101f3a42ef5f5e02025ee41e4bbf0031ef283323d2257b3ef8eb6ab03c2eac79a2387126d5b9f4b1c8448131c169cbf3d9f814e5881991d6981750d7dbb5df57ed15da96d5b333a8a1f44d56b0b4325556c44f56111a95e193b7c713f21de7bf791cd82f09e0118b0d22132ff9a6ab406a27c82afc57678c33f41a36c019c952e4a8e0696a769bc0416667b7a839d7501864fa622639e645c764a1b9609f371cb2e18e59fbcbfe1f94b2c1dd66e62038a4188247a2d3d999fc99414b307c83d8121a80364597fb125187484e676fd793e69f9b9f93b480353b8335d7f7d8d3af8319e5ec694568e83799b2ffa553f2b8dd2ba1606a53bbab07a16b2d99431355320e81004f18c73d851504a19764c0fb9e00d860ef5ba38051f6cf9c5e3a9155b5e5fd240463cec544eeaa23f5a3b033faf9c05f2efe42f78ca17c3d63ee769c74b0dbcc8cbb10b199d4b250dcb15e1a6aa0f0772da15690f08097ef239b7492d8a1f698debb94e03cdb3c28369afa037149f8ef4bbba748bf3c47542a97cc6bee1f9182dc959e4a1d1f6cad492c8ea5a8509a0360984b01ccdd6650f8e56328c6b3ffc0c0da123e321fa79e017fd1ed75d84c446df576aa241e70dfaf73dcf8708e62bfb84ae18661daad9d9689e9c2aaf5c341b8a861072cd961f8024576615767c78f70bc63139d4f19f86e7adc0ec0c2339821441b74b9af4de5c1a93056140e5c3bac990e692a75b941b36a33404a069ef2a30db953041beed4c08f4da8046696574d7e16ec20792e87c885034ebc1c272bf7f70b5b3dbf0b6f4aec9b742f9ff569765300c9489192f01a9236798e51abeac7c5cc7aaccf4cfd142ccfdfb37ee800330ab03fe8e5df92b2c2ebf768a463040f8d234759f75f0f96b6555e161be384229cd65450961bcbc5f3ba0196283b1a2b7bc33312d396ef2466b515fdd3ae713bc7a5ea1a7b3f7e8657112109210fec788e5fd705799f8fa0b286c401ac754392d14e3eada14edf87ec881d5fc1e90e3b097a272a56001773c1b111003232aa31d44491e80d1424dc182998d79c3387b1d98e63fb804d8ac59a41b97261b2ca373ca784ab9186e9ac0cb6cffef6e283384d810e68afa646a1d528ded0da549e686940755a125b2f6488ef2a3a1d16628a31ba48a9d2788c519956598e695a983fc583011f136f64794719e7e11407e40d0c7362048550f8f2c49e4130373a2016ebda8eade3804f73c874fcd4d53a686ac7e2545c803340477034d120ef7b369b245221e924194d7f587bf62db6767f45df9613ff3363510db929f8aad83befc91e50335bb13dc8c3bc3baed84e10eed5e8d20c8d099ea33e7a79819e237ea46cb6c090cb120e8c62a59a9bafc45c69843d3f0e7cd6e22779455f2fef10f2a367abc72631e57084d20956a8217c0e0a97792105d830b85038883b0ed2d4886650afa0582e16b677c4267ba46bc3571ed7491a2ccb28621892af552c4425ad933d443e878ceaa7d1b70e16e0ddb0c78c10c63602d804ca208e3b348a987e44d36aae5f02c0a4a505ee5ca9d8c8bd5c631ba0ef37f4383aac774b6031d0fc0baac33b83e95b1854fdd261e0c45cf297ad9c931e4c04100a25b4289dc5959fd48ccbd4f426e0f8f7abbe16d32399f0a1c6325d3b6cda2ce53c73bb7f641542b0ef8bd7cbcb39c4c81831c987d7ab380b40e91813c83c561f098c6fcf7f0e97614476c763f0950a7448324e155e76d4c6f4b685583befd23575fb8684434e26c0edc04eedbfe6a8bf2e9a3b1307f29230005559742689b1aa1d6414d5b422e0c86332a9c5a857c6f1a8c5b911c85018d6b36ec6b5c83aa75f9a90c6c7c025e88d7081adceca07ab1613cb4611869e1d622f3b33d0a5d166fc4c3b4f7b42ec46b76c1e34305359f33268d43b3db5ff2800889d8f43b90380b22f19c07c7c38f199d859f41e470d4501c5e29c51dc9153b76964a2cf7c054d360e472260a363f5dc859ef68eddd7e9ec5c1cb127396a517be0b18370ee509558817a622035347efdb1935ea02cb9e654e1c1ecb08eafa78e2287c60c9f4a946be43f7d14adf8c303315983a86d7f4e4c1588a48064eb030cc05c2b66eaa3af6aa51b8f32e92f2e6b5fc55a2ead9fa72138e2c547cc18ab96ddf1794fd0bfe13306123fe54476b906d5423cd05f0dd72b90841afaa149861801cd2cfc0895d1bf2d0a2e65453a2d2ced8682e78e3d8a76255da354846227be9eb18a98b346ad7266fad0b70c9a1f7cca00484c79cbc383ae39c3c4aa1ea7992ae0e40b0c94718b95171c0c9c00273eaa24f81aa11a341e6210048bcaccb07b8c73b735ee8dbd0796706df803e2a5bb8b825991cc2dd4da543c110b6ddce16dcd2b81411f4f1a3b5f5dd1e5f7e8613e14dccdb32c215230d72a949b41e5eed74c1e2f330bc812cdb81211a5bc16b02d97a547bb3d5dc3b1521f1c308cc071144d6d6195c460c0080c54f561fdf70a5607f8a7090edab11e2dbdc60dad6d8ba940bd975438dbc1b6c0b595d1538ebae52b3860f569ea786b75cb7e4067754b2479d1ccbf9886dc2da6cfa6080d14efa3dd4a952d6fef83643ec807b383a9d65540e7f0252f8456e1095527ce440565152fdc2bae1bf1da201a4d2905021e33ac0692e300ce5acdc4cd316cf9296506fc0c3d1d9d1d0c9f936d9c0bbe7515309ce20411ef4ab77dfad988c38d96c74b1f0efab33fcabf7eba317c929b71704171e13a108714b4f45e09cc02406f961697747667d5db00adf870a115ad4366c96bd72bd009f6a1a194d205efe8adabda68d96a526d1d242856f28d6ba70b9fb7142f2a15ca1201ba572d6f61da6836c2071535accc9ffbbff37b71e5ee5e5edee8c941ec8482ce04f4c7fdafab9978fd0763d32888e9803641e18e78dafc0f89791dd08f4764140ddd6cf2855cd408c6dbbff117ecd2e82c05444805e57f703ac8222720321cbb4743efe56a76ccecfc226e4b287f75a0e58209f974a5da6a4e5d0eac8c74957dac09960ebb102b2b05ed6738adb4c24c14b24ecc2da436df960103bdc5d2d39e5d032fe162d205b7761cd49e966b83118f74bbf010cef8286790db3396ee24ade17720f2e2670b2083e1a069941b48de58a1872ab0116929b5bf1fcc9cbdfcb1d61f22a0634d91f48c056184f9c99a92d47c840469d32dca7c0bae9572c9d082604c761f0af30c1a45689de4dd4482653162324454e0d226407e1b8ec08d57ea9abe7eb3af3d5768c1967e091af01da1edb98c8ee581a6a2d3434328b5aecb9c66bff89b60d988ff9fbc9488e514e828fa6fcf1cf219f3d49ccf2805c09be8fe3a3da368f5319d4d16725733f812ee8b187621449b8a1ddacd7039d180022692aa95ada864c78994f97fc7220eb1ee1c762dc9e4910859c5d5fe7e133bab771740a063f9f71ac03d32c138b13d2872d569b58393b6cc5734201ca4a6820739df66ff041944444f4bee59ac051a33610f49f9ec1e857b61eea2ef39eb73425aaa73a69ff871be0d795f9efa9d52b7a8d40dd1cb2609f1e3b718c531f416de2d142ebede5edeedf53586e907aef3a54b333579c6b677ee1f6ea111aa616ac05d6892c9234c4f348de55abe4633f1ffd9fe1b55b59599d2f0eadef785cb0d419779b2e652d1ed6bdef3a9d57e2f4b98672ad88a3583a936e38580fc2dcd0ef8311f79ebf607c8d611d9554674dad6c27e3c05d8d318a1ce1f73188d9d327b10fce1a709c2368b6e1049d0bed51e2913dbc2de7d348a777449a5256cd1158d40ffbdbacd222073591f572df5f1ef1239254b17e50f0b7b0e88fef73a091f732733cc95d69d319241a70422e1a6525239ec872f0bf670b7337f5f785c8efad9636a666cc0046902eae8eb0e95d6e40f2c023d5a405726a77d1a7ad3ee9d6344ab4b48c2bd441c1b83410bcbf7da3a89fe3a26bdb079c9199a4067c9616c411af9cd97309b7122ef1e1fc7590268bda4837bff7b4e4d9a403b0cf78bd09ea63d5ae74df5954ea57d6d403cde7415d33cf365f921354f7243645b9de900480f177f983df3e6949b79668679552d1870c5968ab79bf751b1337c6eae8089ba8262367c4867d8ebcbfc3dc470f673408da133b67ea51bb93ea11abccd5f9e7735312454f604c2a692578ad619e8ba324dc5e849a3c8ab93c8466f0ff22caf67bb8b03f743af0e5830747c67be40c9c28ea584d52f69a869dc0dc14516a9a2b679244b5b70c1f186443f3257b6d146be78958decf68aa1b9d2de88bc908746c2d65a31a02dfa4ce02af64e38a295d83ecc49834e2f22df173c107213cd41f95e3e0453a6d536599b52f11941ef547b181e6136390ea8e8d4824321dac7fe143211af79e4903846767ee2f2d6a78433fb2af5ae29c8c930d2f16616d569d7824dbec08bb7108e9c621d364af3dd3f56bc7afaa03ecc232c0371532dc033fdda996a5d51069875623798dc94b4273ce6192e3a60bedbb3c0c7f2d487656edde1a2cad5a8ff7d34b27dfc579c8de7448bd2621ee1e47ac6d82d6b8eb90576477c209541c4f6067e7a0aafc1ac90035032d82dafe55f29264b4863ca5ccfd383357acc6b9a4c69792b4e14e30aa08f03854509e9040e5b1fc12e42ac6fa66c32324352195138f0880d86dd83d12b0852c75b5249b91bc339a5ed86f98330d064e11b449be44439a0529b556b76ad7c3405388971cbb083eeadd1b07b67c9fc660e852260e7c6bb686a2c095cd023a630a5bcf38a51cc86ac7920d3adbaf9c99a44b61033fb25e53366c67f1856aa6bd5c574c1b55f43f0df311df44b9e567a0350bc32fd8699f1ec5d2fc03600a2dce51917278f94f71e429fa273662ab5fc250af96b6854d99075458e225c1cc0d2fd5435e2126fca7aa6ba7ebf8e1a74f628ef71b98487bc11d4a3810492a14f09a113e6d191630d1eb4d44ba4d8380844e851e4881f208d21176c3d91509148958c6b5187b140afe3a8ce1380ad66c40f17b1b82a876c7d71cccf2b04b588de6fda296e84a71bad0c228d08ddd778a89bf075ed3326795343d7e0c046479c779d8013d217e559709f2d51a02024be9d861ef1bb072e973c62274c02aa6b6a49502537e90913c0e17c504fd6e6a586209b0452e6fb48ba97ff8cb162aade0f0d8542de017ad79d37979ca42e03c8ae5bc556faf2510661216cd6338e474481656d039c04d48eab98a09f7ab2c479718bbb6624236832defbe44cc122f5c36c1a178c1245b09c7bbe06ac468f18b085fd9fe21ab917d72c92f31e4a5be48bd2490750084eb4ed06a9a9d07ec6bcb4e34a903f013e7f429f25f71451659edd2f975ad0de32e05ae3364bc0979a6aafcba2692a36c79ea44041ec40d0059d5cf73466e174610de40335c9ad48167a0f7512d97a2b6cb335ee992d83b639c01d9a8fb01a9cb9598629172829f8989f70a365bddbb97d44aa990c5947a9ac07e671eefe3c8682017850d75f460afda209e387084ad8e11ed5cac5ec3eea25bd24443ae1869b030d6f41a6ff573048a19f45c463c7d122ec16bd7e32631af79e16359464da9380e800373dd4e5e844a5634bfa129e015663540ddfd8b4da3c5b9ca7f01131e151dba39a208cc56adad9cc70182205ceb56b9046ace1e2d6a244d548cfac5aece3a0077990b9915d3778b7f2441380f9509fcd89f0af3dfe54d44d05a31198716265637d75b4c5088be49930b08333469253f64dc15ccb9b995e15433d0087eb869b9e8d4dedd2bde5d1bb4eecea9b20c740f8c190f076dfafea718a3667afd9d8d9e2b2ce668ff6d346685a307d44584684982ba84cc3e8a213e005922b7777c50d8d3720fcc5649d9219d065e98d212ed5e989d10f96a7aa5921a5ca3f362c30c89d805e81f96922686377e4bcc5435b82ca75f3587758440af27687a408a0b6a15625424a9ed21c1ef58c7162d7a703bf5e36c061111adfee4c099351537b5d2a355cf4be00cb17832a03893de4543931d1f6d3ebcef84ef61f5f609ff7fb9f85d2793a787df83604b88b2ff7c6ad2f6598abd4d39596271b930005e23f602d042e4fdfbcef9174fe0c2b061f35472db3e97f10ab09a1f4dc3565231b48d39e51e002e5cd644a08e18db7a3be901b6f52571dfea13e6c7cfe179b52f8ef6423e3919905bd5e04daf08827c9bd13f6e1488cd0a04cfcd850443d5389c4ba251a3c06365e48cdc1ea5c2af27d262eab393745d1592c211b8dac952a930c3a2e24707537033da6f8d6c2e8fb07f3b0b0e6caf8aea09c8a105a8b99c2575ad3a1a4d7667e7344c1e6bc1d247c65f8e9770fe0c7a9951b645167c9cd1604abce2fcfb9b30dc15cd9993d5ece2203dc7a0a8666ce3dfe87c2ac8a6fa67a684e012f0a9bcc5ff25cb334f4fa9a76ad3514ff5114664557a32bc55643851f21ef644b0992d4f28e533b3ca43f8758cb88ea7f989d96dd91b965ef639ba60f14b892ab6de99bfba5c437dee44a6b5c485be7cc82d4a8ca08bb0de5c7987122a566589bc661e62792fdfc168c0fcbdacee2add9789f2e5ebc0ae92d0a235ecc7873ce1b40bcd74d1c3b6d5598aa0ed5b5f5007e293e395f2c2921a6e7f446a836155e4cafd075b2f3cfc60ea07893ef8eb40b9d59309b0601e3df57c2909340ce8089e9ed2325deffa7b310cab43ece4e4d0d27c773c10075228ab59e7f8182965abd0dcb6b652050b2d365e7b1d05f649b19ce7b62f47ff95a31d052ad4ee397b2cca64e292c6cb37dacb1aeb0f547ef44c998b4b1d7980441e01b7446e164fc643aee74afe9a6c5a8e69a0a34f1829750167641f1749da69f44809109a2a4c5d0312929049f38f9929fb7191ad69eb2da3e357757973d86362bc6c9511a347ce88106bce57e35c4dfe9a33d5d76a1a6d7cb74766356456b7a15a66b7d2e483647cb594768c48402704e09206985cd644a3e61a51bdf1c1f451a55910932e37e1d11e7e3d60929d96a29f93c7c382870d29deaf4666f9c6498becb1dca7a0f03a63998377b82d587aead568928700b483b71483f53a2543c1eed3b9b4bafaf2d45e10ff99da3943aa77ee5c2e1a84a6f0578654ed576171308d00096ab25c93f244ba3104662f94298bcb6a7fc1bbd7f3bcac219b574146ef64bcf0cd1feac4b74bc276102781f62ca04eb2c6d085012e0d06a2c2412ab1be32698f304d73b0a533c64920d8b33530b65e16fce14b4d615f1bfb236fab226c9c90b9448490db19bfe5d529963885ff0938a175e112d72c6c4327cef3f44702cdd7f83ba63ddea8565b001d6a23fe51eef3471f828f5568faed064ab3e2390c86882b5a6ee8782f0ec6c37d98acf968e5bd613da46c36bbcf9f9f0707590a19c28a509b27a8bfbdfb730032a64bbba14471ebea2c398a506612b785922597ee76139034cee2ff3e74a4d1eeb471cdd7f43068bad806a26c8d86412362793c7823e1e500fc4495399b0011a6988eb76f3be8047a849951eb253ab9bc2767db88e5cad1100b1fe331b68968198a2e033211de0c804009f95c409a4e13210a30cf12d725bae62b6f6ca513b8e7d9ca8eb0cb9b646bb178847fbd01b44b4fe1e6b15b0ab7c2962874d5fdf70a455f03d2e4454163e89b20e6a1d8033870e1e177cc6d856457c3624dd76227bf6b5d4f0c2243dadbc11235dd58a95a272903af1ee6671b636d8f47e90bc36d5c6e070d9067e7d81d504f566d040c3f193aee5b48195fc5910ecc4926d1ebb121c2d451d3e99a2386a69104bb5c15171ddad5caf8e09d7a051b33c1db342cc4ec3d81e59ff6f19983a44ca609a48d86a053d635ea49fd90b0bbe55be786c28205cbdaee73e6ed957f8e93b8f2a9209555609d3346a1b044750221bf76b3d1c10504ab8aabb28c0aeb89fbacce4dbc40afc27e0b3b9e86a3913cbcc9bdd343045e0ce24e72c6f52b6852683fd9a61533e5994c107ca65a0d81d4ee5322c0f7168e4c2b32eba8a7fd783eec9ef68d7f20950595988bf1f857bbd3e184aca1ee2e7f5f71fd30a1075e59ef1103345a8835806dfc6a8a246dd79b7551c26a9b16a7628dc65ea8c930abfc7a7cf04f1e475664e1373cfe6ca0396d4c750d114081f22d33d7981eb536e60ed2d3ea5fa72cd046c5fb110fddfb14466f0d8c35b2658eb69742505e7d1d4161f1d4c1b9af6e373fc984baa35f81392bbfb56c201ae31e2b6fe2a22680802d51d9ef98e7ea830eefa07667879bc93921d4bf4f117fe0d328d1586ad150b58685eaaf61e704a2fc6ec854d19ac27a9d236d88a1fc310c23255187c88a5e2f7684a02098fa671d68a592e2096466c5b87191efc3163193123feeaaac57b4fbb7d78352b01f5ddf29563946a45c325c74c70e2af45167619af91d10088f0699695decdea4b41d43be14e0b0fc95c150e122d56dcb90ced5efa1ec926bcb5eb55287c855f215bf7dd0159a7cfffab8b8f897ecef49764928f3792c5e100c8a3fa3044361276a2b987f57624a509b2a119c12a678d25791101d182af43f1d44749055116496fd0ad78598cfd78bb185d0a5b02fa302f3559a5f952b9ca6e639da088792470e04ce9d76c431d94f0633b7c9893c3a72e01289b8a7573e60cec814bd2e2a553eb1728a9f629cc9324f93f7e440a11a39a437bf3ed1ed4ae684904cdc4fa3546e583adcd55d48a8d0ad228e4eca534dfa0cfe35dddc7b817f9a01d9da79ea45cc49915a2935d6226b7e0b99417c55e29c070eca6c394f3994026fdffe5382a05ef7e348dfa260c790b9549d5ee560c7a83c1ef7f413a46885df2a15f14d81d83d4fa51c709d5ddd62a34b6a8d531e04c48920e525e98875cf188e8c800876a3186d081472c3e3c5180eb3f8b1dfe1b2bd18f271262211601f7b0a7ed0620c5dfdfcb981ba7a33b8b10af6995bf36b19889b9938a460659e2454ab63e1e0d423ad0d984d4d3c0874aba21623d301d12f606fc3296c427dd4aa1bd6dce71c0f8b31b1c2be774382b8db3f518ffa883b97da0dadd6dfee0a647ffaf1e89515ca8a6adeee729e35a3a3b43cbd4826397b4b7b627e41ca18eede322eada538090e4b924104dfa67909d1a4d4941ac4448d911e21c6068c8d094fe3359bc8a26ed66962bf618c6c93f9177d5f93527789b89ba3d68a9e1b467d3616e26af40dcf7e8e71e6fd1b88aa1340ebea1c0e8ed4400f13904be8e90cb4af01bb7be6b8843da9f878948cd705f2db20ff131ed1cfa4695d6352b78a2d9bee47e45f19a30cbfeeb561853cbb0ccd307a5c95c9824001f9e74ca4cbe5ea9448f3ad32cba1087603c3627ec1c11ce2d2a8692240d650735dd67199fcf92bfac80b38d535d4c40063632bb63ce185a3c5aa992b7a28b761f0683010d3a3c058a07d8dfcdf7e9714c9c639cfb4de8a8ee7bf4efff8c5fa8ded4d8d5bf9e00efe6edc2ffc87b886a071b6e65465192361c76ef37897f7eeb2d13fc3ed6fb02bf2b9b7dc973d4a5239cef90bf5e60fbf5d6fe601963d3d39fc92451d5fccfe61d8873bb2ec8e386d2752f7d3d64f3f01b90f6a8b13ec9fdef7842f7d7efeabb2e6dc7a2279860fb434b71fb32eb73f0f199ed35e4832a03f1409b38eb0b76df9f885aa7d741f777b24feac604b4dee56aa9412461c5784182c78129ade4459596463f7f53eac7e8eb8b15c2747a3dd1a848c6a5ce7974a54d6ded7b739ada83925ab0a1c7cf2cd2a1871513c77fc80f8ac1c8b12ee425bbbeaad522e8670902a42a597f04db17ce3394e0a1423ec869dc9de9f790da539d84cdf51c4b98c5803a02c6141d1b42c2fd896e4cdc9b9fc2854f5d67da69304f70bc3c4dbafa5354a0b896c60de031a0fceb8d8c1c2bebb7ebf1feb0d549dcaac1ed75ab7e4e6ca0842ba63a95fb17ec222dc836f37171981b6b15f6680a67bbead684b46ab654d35843f036b0a51c24a73d0ad34104b473c59cd7f6083cf94079024b5f18d50b9515dcfb63b4440189659718bd1e288348ecc7df7d80a9e8f65a8611049fd9d8ce67e831283a524fa8893c9d0d907c05fb8ea777c015a1b707008dc17fd1c2646fe9e85df960eb1e8c00e6dec6603ad15190860e1f1cf1f61a332f2df442b7a48e59fb5914ac307fcccd938ab4eceafd708bf0fde6d8017ac1d2e00cdc3c240978173f357d0f80847edc43d1498c1368e8251fe4ad885606a0078415e17dd3dd3ffd23d1385c5a02fea1688941bd1dd7e547001ae785bed2b7d02b117b4b665ce3306a37af2017009b41e56ea7b23e8a7c0f8ec0766a690f0d8dfb105156ef8042413af70ae21d1e75bbc6cf8df1017a144d736241c745774935344ee98b7c964c2e522ef4d2f71f7560704a505b14fb90e5b1fabe63b43a17c3c242dd49c46135d9cc8e1e118d401b64410fdb89d04b851870846e68db8351733ae52d52bac06fdb52efc13c8ff37187a755dabfc3018f6efc4fa1fd06aaf544f0f2333083af3dc6f335a957824187d3988ba57e605e43f68deca71724add64be8cfb852099ef7382343ffc9fd367e881f3b0aaf60f7c4d7d5c7b38f687be5027a7d675b827e4aab8856986bf77858fb039a83dc9cc4b10d281a01b026aa81cfd5ba674039c9cc6301ea3a7f32a4f28bfb059bc530d5ffaf4192a0a9eb0fd1137380a195ee1f3ffe308843862a6bf97e4a071f00791d7e7ad63f83ec2b22e3ddf41437fe96f1f32068481d3108e6b47849641eb7dc8e969a596fa374e1919517129d9d0d6d78056508c39e0df6b9eeb2982c2d98033193aeea3ebb47d7ca0663caddb4dcbd63fa8f6fe4e64427bf2ffdafdf4b89bc2625f4e9fb31e01e894321a337e3cd977aa1dc8fc5fe3fba2d504dff188d77e898ab92cf566377ff837fb106b8bf986c903053ec44f263acd65661423d30c33821061f32e594110ff80588f33315b06f6bb1893c25fc0a031cd0cbd3370f532c5572e06dd70ce7f3e9a1f0595c6ec10f5de3b2de433dd9c99e5cf1c6ee3762f30dca011f14be2629f56322724fb5f885e3785914a1bcbd017bef734471916ea0fc99cf8fe21fd6120ba7fcc1466ed1d7d570ae0e4e5dbc7602331de15d9ecdc821d65d79da065a8744cd47f37eec88287f9a1f3e8db1fcc7c88913afafdc66298b6f126fd1bee2fc3b0735baaaba2a324d607ba179b396e830e238d8d884e8d7bc018e1d731170dd447bca53a2b5a7bbaa8fbcee62bfaac97eaa96156d67395cd5140e54c2d2a2af27a7e2441758528d65e5ec7de319fcdab11ed2500de72962e81ea3d297683045dfcd54856393162bd9fd2a25313003e10d822011f3d30df0994a752c692c6233f60b2c8b3c0529bfcc878685bdfd1aeb6028971a0b16b86dfd40f6f34943cb19d1230e2ee8be4b346748377b4dab8de3a2456c22e06e0c0c72a54207fb0896fd02538d305e53d20b0ec8b7c8d506cfbace3c43a778f9e60b076ee3f6769cb070ddb077bce84044b24d69a8bdfd91738f48b62d1cdac43f20f7f56ec55794515eed0367dbac7d45f2afb47c04491455d41c5be1b78c410bdf11d4ad2a53b4c854f9b111babb072697727aa0ce0fb907f1d500f8436b57fae4511fb63eb9f84bb327cbdc939476cc577c11e6b4fb6c02f5c122e541003e2feef34b763424b3f66b9600dccd931e38d2475b0edb929f1288515b644abc3327e2136944d835814498caf7553c3f724d4c102922a772db3536562766d0b06b8453ad78d139d426ea5f882d11d24bdd728e1432ed77c77f3fd55b740c29187dd6f2a12d94a1a9f096f5cdbd00d754f24a23efa621338ff70c9aca84e4c8673e6c20c630d3e315c223fdf15ec03d1968a67b7593d1fd6676c5b586a40352270eef173badbc307a6be314255c84414134650469a960f0978dd09b711ad5d1dfedadfe916503e9c7d2b31b170012a7192916e54d541ac5ca57a4571c5aecdb0894084d0b95fd4673c630f7b5d55681174526928b8a9159fecd90c6d8e50c5f2285c1a10de52e5a3b8d273e075bdf8eeaceb75da6ad8120a90e252d9880271d9b61469d08c8fa02b4ce64a3379c1bbfe1fba817488ae9373e425e0f1974a9147efa9ead2d4105662eda3737edea4c9a63d17a8e567aac50897a0ecd72906c28dfc2e41a5df5dd61c17d7f6a60604fad402c8cab492d26f551585c095ce39c17e0fc598a3140f34aaeb6e486b2ac5d458a2f1cd1c54b503d34623dee4b93c9dc02fcfbab72f621cb0e90256ad537da4a4afdb38ef218922723d1551b8bd581027ac79c5578695975b096d0200d48b0ff1aa6548badd57fadbc6b60648a4f8f4ac2699d98343e7dd3d0632c2a0cf7a6b3813a0e21e8eccab9cda6a91dc71c3c42f3c2f564d9a998b107b93211ba01ef7abe7bd8e991bb15daa16745427db628ce4cb393599bde748c1731260609985c0e1b3dfa512a42f051a7510dc3e26a387ecdf236569ea6cb1b469a72336489fa5e9576c3d93fbb9d7e4b44216865aa75afd9c27c3fa497910acb90d1e36d3e958fad04fc2a4f33e25148ae183579c210fa8bed9aed5661943f52dbb362e25b036aee90ea2a23918228e466e645d878670c81e4b1f2669c1cacb0585afb9db3b64b7ca2f948a48d8204fbfdb2994e1e87a7d2a8a7bc49e553f844b86cefb2a414972f2a95b6b7dd650b18298de4122a258414464a5df39e162e4cd4d4de5aa5340605813ebe403367d7f157a93793f595f53aca8e2a4d7ee4074012a02cb5323a417d8eeb494eb0cc17033de1d08d65c4a4f9ddde4cbf28698699cc94163a910f1de124935da8a45019f05898fd4fc183863573b1f0d67572e29f8b97d6f2472f8b711b7cf173ad7f50d3a810e506a2ff93e270281a5ef40dde744ca6ca4b71e811c76d801457935455bdcd5f855c3d29d2a7d3b9d78b5c48b88df16362af28d795643c440b4be67229f7ba80c4bb4881cd168195b3a196bf2e5531c60d60dc6793fcf3866d691cf8cae131be330ac3c01830c027ccb88d1527d6425fc37f48b27e8afc958e277c4113910103c7d274b61f22b4a04f7b0c975385979fb794c20dc9b2ca5f8cd90be81aafc8448fe77ab128f429740b51918408ce4b4f3c05423e52a0347bf44ef670812a7a9c1a9bb93ad9854f1a5af49d0bff294229004042f513808a35fdc15d07533ec9f551ab32623d2dbfbe12029110a141e179e4d2efbbbd6e4212fa114b78ee6ad47d68534d195204d625040354bcfc573e98073d8bdf549a6d3485c382716bcfe1ac369898258ab299ab2c1d1ec2f3d79482903038841b46663e68ca4d6a4789f0ba25598530bdafd0783c2bbcff336a54a995f8f67d092546acc1150fcdc49b036bda364c1042cd0a88a19b9aa890001178a8b63edc7b773707e26ffca4bebd34c8cde6362a4afdf31eefb46bd79db3f49ade0b7a5a9e134ec2c5d0104d3848607b04818f2d42c7f07749c4d571d550c5023442af41bbb78512eab19f8f7674a126fd20467509033cd228564d178596f90d0c55260a20e153a6f5c6da7e1cdcdbc5a192200bfb1715311b7ce8f379c802673459710d3d2682b1ace45be05d605fed6552f7f77a6de7f6eeab7da6e7ce8f78a69d67a3fc478bfe9d7fece3df9f8a13e95e0cd73cbd49b3e371230cde67bf52a34799f978baf0b5ab12e5ffe67c2f027a8cb8d59e610e749a61eafd76f165cfc1649ef71f48647b7061e1669de833b89d8b5cf95e3384ec121a1b741b13b7430ed13e5307ac34fa1fdde82ed4f34bb3164292f40a57dba8d8a34fb76816e746a2c1b85197dc3081273fa7d23c6d296ab2218b76353f59388064cca506d4d95e486ebadab684e182f53a84d851e0facac28a7863c485c039e862ef22a152e74c17b250a9a10db26196755c0938a193ffbcc80e62d93468ea1998481dc5062a3d89ec69a2ebd7e3cc9d739145bad5a421896eb7db228eba4d5869885a212a382dec9184fb2bb12f43d4a175414e6eaf22f5c77ddb3488e539a920284462ead356142bcf3041cddcbeb22cf6a8f9c5261f769f22b5cee8f77b3a0580b44a8f0a72ffdf1251abc5ed4926ffc98851e150de81ff441238c21a8bae46611d933c3fbb94fc198502fc0d639b45bb04137fee531b1cf9ea4898b52fe3ac9f0ef9004831cd34490ba5b957070f302c8fcb117076f67ae27d846de2ebf9bd1ac7aba319d39f3b362c774a666225f58652f7dbede7de62e5d5d0858dbd5c90be6aa5dda51889584019af8a9ffdf3023f686ce85acf977a6e2cae426bfbc516c432f6cfe1bcaae638808e992e1bb47b3fcab9b00c75a8173c74f589730f38f4d6087b5440f413f12ca5612e095125ac4b300e424008c16f6fe99898d129bf596bd25b17060ffb061b3b00d5c43454bb21f063c7b03d062cbcd6be4ea4a86b8deab28c7bfeb87be73c8a8959890216864a6e34a58ee9ce02d5999ffc9decef9cfffefba7afaf3d92b490efd4a83c3483591a2748b66228cbdd1e7420fd46f1d26b0d8dbd83601e15a5d76087b89fddd684d211da4fc42a611ddac22dcb3cf6d6fea51dfc20f0cd3c3eba248ea9967fd84c248ef6b434b16e0b50447329e1ed4ad799b1a0e1e89dd434cecae57d6949670520c67c9398ec2220a77efa2e1893420bfd9afb9d50b2d8e5173236941285a45670292538054ee4fdc9effbad56206d54a78ff9d12916ea0f1a44f8169e209a0a3ee0fa71fa1153ab5ac683770a1d48e59da4ff59a8feb9c364f7a99d25aa57cbfa45b76a010cede3ec6219965f0550bc1443f8c6010a8298339343a0da30712d740cbc81d24fd937674451a1993bbd75aea251f0b43e76a4333aff96ac2b34df28ec2a9fcba1d5a87884ee61645558b3074812f4f53b0884ec568f5d8517cd01cade1e903f784c6e78869bce9e2093253f6407452ec3ecd9657efd68191d648124c2392f0597022c91ff866a946a2a1fe2cf37d61b99ec177a85efc6cda315b1b3050bd70186123a8d1695e5d927ac39733d84024910da51c09a72aaf082471980db826fa885d6aafad98aa269a65cab6b0b2f992940c0fc6fc1fb6ba1e1d79ca2bb15c0580bff044d6076722dcf7f8cf5fba79411e6319ac2686fa8d19298074af70b8bf8a241076ce88b093cdc27699b66127a3031be25b6d82f0543a5006033d02d5678a3870635f651351448ad649e90092cbbca12fa80262b42a9c2903454e30d56a1aa586d20f2494347a5738cbb5aecca0d6b226a7be8a595337738b70ffbf523f47c815732b0c02682e417c3bd3f3d5984cc04daee30c98b5d497234c12f598c79040054874b3ea8e01d91b50080a498c2025cb49d590dd207a6ccc7fe26321814095f28518458d7016925b4b39413882ea1fb1b2580e58fa7e69bd549e1b0a1648440ede71cca2d68f0fba44283f498c3c5acbbd885a187888050677f87728a62493270134ee7ab158ea1da10e82f243908e25e8908885a2746b8e448d3a02c9c3d0026f36780c81cf052efd83b1c9ffff815fad11688a308ce38e52c632eb9e4cb59c26e22e8a01d8cba3148c1f7af3ba17597cd95a3c9b78865fdff3ad553d340782be52f929d83f6f4d6044ae82731e51ddc9ef43bab1e4ae9a22bdae4e98c7bd3de47efaf2dfb54719408e404da99e5c834b5f3b8183fa553fefccb5f2bfaca3a4e5338a7810b4fc1d0f97a13403c7599a607bc7bd121beb627c83fd37283487df756ea7d38b8db9fe57ba7f9ebcc6cab3ecc7d70127a0f0e80a111b4309ee7a6118085cd548e8b797bfe2c4570a9ebdbfc2c44cc8852f45d3f7a7e6778b553f42a24c6c299b5fd959a111cb9c97b73c23a13dd7e22b980c645e40cdbe23d0ed56dbc18b95d03ae0e698162182c9f6ba881a4849681c3ada9fb6c906e7eecfa39e3d43780852e42121622f84235255fb3f7db690db4c3d1fb8d86e8b8c4eed38e05864fac37d926c0a29c4aaee6f316e37bdedaf8eb1fd3d957b9d0a24197a3539bc9bc76bb314bcff9e84db94bfded0c195e28254e6042e6a563e8bd12793134a919d48d012fce325c9ba590aaef758e70bd43757a60dc65a6a9138987008bc14718be687ba42bdb10654a00bc4a644f65e00a61238e892a70ee5d56d89b1345789a6f7e5000c82e5f9763385e62e1cb0864e1a2e89a7be3073adf92c4e8854a1b336c8c5414a768f3ab4a9eba29eeaefc1f221ef954297e597ba3615d3e3792a332ac892a0899fb259039fba984484cd435c1d8bb01d4bd3e63581dc277440eb28be7f1966315312ed1500e9b07a39ba5e6ad63ffc146f1fcda7aecb8645d2a29a7a4128243041bc1bef1618de2f9746160f47c28f6852e466e2558ec0f27607e9ace220347b6ee85d443c8865c1c782c88f2cee8556f6d37b7a1de249d3a3c52ad60b4c7fc83fb3124a6c7da2a1ecc2e9a1f0a17a5568287e0404c60c9b108cb381325606fc88043352579b5e3c11e84478e8ee72d9cd989e4ff6e3aa1234f7d01b6cdc03fc7c7e1ce17bee16878301c8d2de0f64de9bedddfa953e85570aabc00df6c5e8844c4ae92b82b2001c16a60d582f960e73514e19a1d7d97fb1cc82ebeb0acac2c1960c8144a571076c28caaed6cbf89f803a96254ee3588fb6c5169025046de87a04460be98b2f22da176a460464229239549091ff904654dac96fee466eccb16247b4bf75b0e4fd1feac1a67548d055705e75f82921562f76c5d3fe9823c76702c33a8b0dde91b4e9de9541882b6dccb1d4bc1fc8bca7d7bbf5e930f94caca5a7d455be1ff3a05b3d3b61d6c5736b9ee8451623d443bf977f558f425bd6b9ffd58cabef15e5f6e491df483d4e1fa493d5415ddfe79e1de7b0a0030038ce77a30822d93ff8605625319f6d363f81d237836a2ea2eef526c53c92d7a43100f0184195fe42e0636c0d9e7dcba9f69d905094cf23510a63003a30d874f7aa670566d89ecfadfd4622987d5e4ba5223828cbb662ec7c2fbc881f427c354261d028688879378dd18a404fd82784e63b983968f3a8af2d76ac10c66f8c8cf336bcb4292ae1bcf565d0ac5760f324bf0a78084515c034b32c8d71fa53f670d0cd479c43f16aabce9febb19edab9b60eed8de41cd5989a2ffbb5bbf1e32936f805e0e3845abeadb68c05ab6b8205c860b73f76572c45da3cccf247d89249ba60d3c72cde0ab3ff9ee1b025b3948adbc6e02179905eb6365be80ee3954ef3a69bdebee464ad0f1a49584dbc88c496ce703b18436259bee9eeba3596a13ffbdc222103788ab1d322749016a8879f4840f52841f018f87f09efa5dcecd0e34932d73fb92ba4b9580261d82c63eca0c56b0f1a6d25d01b70f661fc0f7d7ddc84f14d0addddb46d8cda3aaf5c2a47152135280cdc9bc45dcaccd52714e209f848bf84d1a43c37b8fdf9f834334f65e4ffd1f6f18bd3a0479d008bd179c9ef18c8baca0a2dd1e4d79d85858304dd3b61aa7d5a69b3910780cb355f8d01f33e13f4335a95a21a6729857bf1b2397d9e2ad270739354cf8c06a3137d6fb74b872ec25ed45534881cd5818e044ebf5b540210913abd90a0b29c28b69d1856f01e01eaea889ac3f67e058ea8d83d5395e3ca98a89da33eec58ef9ae016956c3c913a647632e87bc54810966d85442c0050325cc681b9122a2fc5b842860491fec9eb277a0dd3ad7958d2ecf91bca76bc0374bea8a1caef412040258e846f2ae86aae6edf2c96c7f6df29b9bbf1fe39249cc791304b4b8a886adcf68af96bf853c6df5a1c3d48289ea36041113896880178dcfaf39f10422de08a79af3272a95621dbe26231e5e5e9101d632291231d127fcc4481f6238640038bd525ba5dc0e18b57661569bee11712711cd0bc4a70394f55207e7464c7caad5888e680baffcb2810c7d1e95314e322b2dea7e024132565c788b293162ed4b586cf327b7c1f3684161d21186f0e3b87f160517884e9f2c9340a8f485ffef92129024c15cfc82226102e74560bd567fe2559b679526acf95f6b8a75a0601b81a91dc6382f59f912bb40211609d5d8cc201b177e7695dd2a8b5bc5fa7c19cd92c024107dce6a004d031f217d68d86fe4685c850abc2fd0f34a6b6bcc654317b0b125be78b863494ddbf6519b245f927a4673869f7213c1458717c6fda6b884862e74b6523de7af15634197513fa2b4706da848ab6bf8280de1fcf7dca7d7b127075bea38de190a33d7812ad6bb09f05dd500f75fa9a1d3eb76a31262f690d359d82e437d4b752c4c904872144c847f0c7cec02ceef18bbcffea4f7b79a966c6b566bd0d5278d48ba69a2e8e286422d8df8647a78755e743e06bbc19cec962033237b3134de52fbdb470be8c6f2de7fbcb0619fd679b4cffd9c6f830bf0f2fbe19fbedf0d8f9ce85187fe26d90b3af33de3c6b7d269c1a6b474088596834cedd819c29566442d925481809a5c6b4177062179634d4c22ae52cf659f28ce0b52d79ead2b242e74c2d7e4e30ed7839639a4222cd41b90e166592ca0659449e6a6634cdd459b24487757dd2c21c77f6df3ec3bf3ec2e2d387b0f9f7115e3e834e4b58fb3143e564a689acb3926e42062ad3d4a4e6b0a455dd81427059aeb8977ce9f16e3f1b51cca924d96924abacd385d081cc1435d724ac695957a0094ad3d1b2ab3ee3d0bace40117453a2998db18a357bca834bb394230b9b63192b760725a0399956ba348d452cd889640fe592d9a7794a91810db18c25bb831c109c4c539ac94ad6e92454a033859a6b0c2b5ad725d004d954b4540293ccf7109555739550b61be7fe4f4eba0919a84c53939ac3925675070a4137194d6c8e9558b333a880e69434a791acb24e17424750e3bc1aae00be0f86ccf0699a5264b349ac63c9ba5aa0074dcd764f39ded9f7248184fbc73575917b750977d619b7d44d6eaa8722a0a8ad3148bbdcdf5cafebdcab4bb8b3ceb8a56e7253dde1ca2a742c21ee650c6ecc1c6e9299b89629b83393887f64ade69b7fd83bc9e214912771c7ffc63f1eafe0086b5bc28f082e5ec50dff10d7e8bc8fdbfd092eb178074f585b126e05b0b615f7fe437ca3f33aeefb27e147a3e5a5f873c6c4fbb8ed5ff089897770cb7fe10743dee166c6ecd51490eddb390e4ace73c4fc1f6b8b8cf9827d49277cf18a93cdd959fde0010f925ded112bd606cf3044294d4948489649e5bb3486bd5ab11fa6877828302ed88ef0f3ea1012a9c89bf504ec3ac41e20554768931d9f4d430457f5ee328c897c4a044650281a3c60d1a0effd447f59460569a605c6fde96aa58ba462391e6281c55872fa8c1e5ea89deb10c3b21e8a41a09d52a1cb95c9bbc2b30fef0a0cde320669cee13566186bed2ec1385ac7208d6cdfebe27d0fee09dfa9e73bd6594a84a343f41b6369736d6285a7da9cb5c97bd1a77b56ddfeea0293658c6a7ab8a822d0d928237b5376fcb37fbec6101e2be50f2ce0dc4e9a390a62ec6793e8a3ddb5a52f6a04e5a24611d3526c86af495d23553a16564e4c47e0896825eff448b00616d7d47323d4cd928b92ca942754a2e3fa3e0025dc855e2cf29b51aba72f549d44c1f737bb9c2c5594a073c1673a9dc41777b3bea2e5b7e01f8cffc4dc2344dd65b5ee655a95a741f750c53c74b722e582528b03d3637f78f320a84c0eea6dfabc1b095776570d3546aa9f695138ee05aaac3ef8427320ea2d225e279fd407b68ba4e017de3b4957a877b1080c2f051a1c6ba5551048cb481dc419bc348900023f1a70d2ce4fdf84b8eb9df6510e60c22b079c4043120119812f49dc52926d915c2b2169114b646ed29e0609211eccead0076a416c002b2fa01770a7fa0615ac3aaa63748516f17f0adb09130a980a3838aeca18bc5dd77954a53e9a51be0a3df0aebace697fbfda8fe68b65ccbacddefdcf601da65de797beb5423e9a2f5d12d2757eed2c530fbcf9ffcc5b2bd4986cf0458d243576d4f8d11da57ddc9ae961c6872e70edd264ac65ecb3df0c2b8d308d6fbcb75b9155cc26b355893443a58b31a7f3a75599fb99e50db65579976c55da23a4afb6a85a6aab12098d1b62d2194d74b7b3a60b86c12a366798babdd9ea9756b42a9192eec3eeed06fbf0bdddcca042c50c0194e18332c69421a68c31baa3cfac4b57e1f06dfed9ec3ebf024ae424d10f61cf6bcd6a7f6cd17b20d2acf6a7525b43a544d622fdb5b224a5f740a42246943c8c2fd1bf50cefdbf507873ad94087bb652229c2dcad67befa3f7655f53de2532fb2db942352c3dfae3ca9268a88665139c9344951261fc9277c9d1e37fa1cfe10fbd4747f86d32fac2e13b9917dba39cfba29cfba2f09de0fc4993626c33d89add274a193fce0edd3fb22f2cef926cbd24fc7368ca6f72add03c4ac2e13bc9b92fc24119cb218cbf7e964393063d96b5a30c1acdbfd1bf59223bab2e9b4c5e5aa593ca3e4868565d299b31a234be343dc2bcd336627889a1274615e3bb6f6ee8cdf5fde6c669955aa14fe9055e3aea2cc16c86e52c4d01d304992e3bc4a0bd048004448aa040aed140fb73fbecca9f245bf993e623e54fba7d76c5f09dc4f06dd70a11a28ab7cfb7cfaed8c2dfbf13bf471eebf44be7579cc5940747acb2455569be4d6687f287def7dd3ebb3c9974abfc921e83eefaa4ee3d5ca64386b8cfac0bc98f85e0a77456892b4539ee1ebcb9f3786d4c4d95272b8d6294b31c83f2e806e247aad62659fb82b1f0537ce34cdaa4200d13001105036cd077809d04e80691d66b2608d513021d700446741b33ad0292259e4075d37ce145172a480117345b74d3a0a09b468b6e9a2c684e1047b5b30faa61d9048661f6fe1518be478ac49c556cce07fae8eba32fdc17b93efa8a2f843ffa8a1fcd9686b3f3a3af88ef7f1fcdbef4b42693f53f2b3f5ca9a4b53cca2c27bef199f7387bb1f7bf5dcad670ae4275f39344f8a32fffe86b562a44530023badba34cb24799cc479af4e768d21f2c148045cda4b14963b02b76982efa933dca247b9489962068a2e0497f729228d664927a3497feb119efe370a6b59fb53cdad9ec2988f112ae56a852a248672beb37f9615b338dc63e866996f28abd334cbdb791c6eced66675428769dad46422e2197f8c8eb0fe524518cb7af9428563b9b579542799486278d75391daed6c3980a7761ecda8c3f0fbdc7577ed867f6976492c7db673af384132350a17193fe5cfae596645bf4f466d86799edfdb2bdfdf43cfbc13e10663328619e857d36cb608fedfd037cf46fb5b7cf343f9616e67d1f8865f47eb0fc2118bb59fc38f9d10cfb8bfb0afb68fe6886658fd29e1863bee7655b675eb0712237be11e360ef8fc49cd50d4bdc8a0600432278234b1a5d9233b11fb8af3d941450a7a8544a7c94782a37292acf7e88c5ba4679f643eeee754a023c3729cc0727c0a287133a28f199bdd7c3014a7a9c086c7ad64b05783c691f61643c651713f9f06841135dfaa7ad364de41e22a0e32b25f169f38148691b1080b9e1e5026a1db580bcc7739336089e0d088874cb1b0e1675b4f083046614e008160d267cd122c7e647005f0837365b70c084b0e504590a5bba1b8709299070d1dd3925a460730c2055595c701b264ac0305aa5b78ba6b100cd966e1a22ba692ad0365e9eb0f1d28566886e1a217ed050a0bb939e38f9e40df67f73ec9344fff7f533dfc6cb0f9a0948404b10516880c8d29386668a8d07c8687ce377cbc9dbcdc603583acaa4cc03f3fe9267f1916e1b0ff858628d25ccb0b7bf36cb2a78b3ab70ae7f731a5fc2a73d4fcaf08d5dc2609b2e46d41061d3c547171edd3518982140960b588002361d38e24193a569f5d2257abf9f1fbe6dca58b6d5d2283163eae59957ad27417bffcaaadafa184bcf28ff0d53fe244182eeeed136493c914406922022891cba553e74f4721f7af272157695d2276f3e7fda6e9a1fba697ce8a6e981c70e56a620510211708056e5e5d1f11586f114a1cd87cdef217600432e3cd02aad34276f2e7f89cef8e89623061b24b2c81fd84356c59cd4d0028d378de7d96c4cba6964d348a16e9a8ea6a3194233e48e3b66ea98a923d2c0984b4bf3a4774b867e5a4d805a4b908a94b098a167ae68a1674a3053848117bef131b06383012246f4002f790a158d80626344ca8801747b9e04a2c99beb3d2a976455f23c095495b22dc22e4f0281718110ba3d49b34f4fb3c0025eb28d05ac74871ead66d95f1a14e463b3050536450c4002a12e79fe937830c5f773efb323f452eab1d9d2753b2be64be6d36832f648f7eb7ea8f32ca15099ff4ecf7e2aec2e7894e577954e11558e8e5feb39ee954a8cd155465c55c4553a523ac73b478a449dd0cbe5e4142982e9928d5d70becce7774790384dc63c2f85ca4f63b1304dfeac1ccb661da6c9d80a77f73fef6bb6ae4be938919cbcc5146c885341b912254e45c789b84d4a8755f865f4e6bfd9a7b9ccb79b95fd7579b514c85df06871b95a8bc32ae5833c5d94165152e7337bffa3defdafca5c65be5f6e89bbe091266319fcfad96796055bd1db6398df57cda75e71a6f826674c93d42b8d5641b779ba3068e9954b8f1dc3e2cc7b8fca8c3b9afce96832469331a79e57fad3d616ce49222966b2348bf58a81b8a6052e4d0071c40608158008a1fb87357e28e3872b9c855fe52c95b3f04c1126f460b32442f704faa186279512c5ae739bbd028e8b704e12e516ce0ee57e5617bec92b8f28ac064c0f45b8c70e363c84a184fba2595d93c6aa92cd606bd29f1a356c32571750c436991dca49a218b1e3ccfa5f52fce8ebfe0cf2585f56a98dde9c52c96b515e2d0dfa4993622871d7ca68fede869dfefc5969cc257e3a6325ced4c7424984729f955f9f954b998a27e6d743cfe3a4313086278da9306ad298e39b9c7bdcf288dd7966754c3df0b63c1e4df993946d912d9af68856e9a43fd916dd97df24dba21e3c39393aee13c3ed630a9a7b1f533cadbee7c99aac7da030df8af3dc3e671eac4489cfacebc4af16e623063ea414c9968c295048531540492fbb5628683e4ed65ef36ff25ff3ff8218bb80b0007145cfc66e21bec91a715f73046de8367b9c2fa34b5caa0a72f9b5b90b65337b7f26a3332afb0f4fcfd6bc3ace0e29d5bf62af90bd7f004ab4642f0dc2b6a85ef0677aa085a204ca0844402a105298a94112e166670e9b8f88951e423e5cf727bfc62ac015dc2cf2c4be9ea8c8128bb50a4960135e0943c77110c98300c346038a40e3072c68f01044b541b865279834e90493725fe494e86e3bc1242c617682303b416c27886d722f2cdd17d809da092675c4b15902c35953fed03c66a15736d9d780b08cfd9d5958aef6ce6095c232f8d1d8a4b10a56f0b35d9a15fcfc6110c39e36c12a39992bbdd50bc696a82761dfbf0d276b19276b394676565d33a3991146ba5608e36ae9fd59959e26f1cce893447866942b7efc1403fd3dc232cba099d1acd449f8836b5836c1ffa13cb2b1d6edd259b541322664ab980bbafb15b127976e577aad385f56d0339551efcb2df1886f3878cabf1ff83689cb5582367806eddfe82be2c7587e61ac52da0eb1cbc91b8bd5e1ce67f3bd866593297f3c0f149af2c706d9972daa4a3c623550f090000f20a850d12828b589ca2b7cdb6781800089b406fa570b622c73ef3b3a0e8379cc347604c9ec2f52473149c1d2f8c6088038df558332e078d5ba4d37a0d1dd9efde48dc562b16ef0a1bbc3b7b13e4b0f577973f7096e40e1da283ef8f4ec105170ba6f368946abfc759e1c0cd66082e2a5bb3114af4d5088f4943f4d4f74e81e8a0003e2928d659ccfa7343dd8bca691297de9e6a1bb7fd4ecd0d77e4a44aaa5d8a3b61b58270cf6d59a5e4768495ce01b33786b05212347072963420729734337120bdd311060862071e4749038987490388ae8207184d141e2f0410721a342072103d441c8c43a0899b08390e1d241c8c0e0841d4e50e60520657c20c34577f78905091c7577cfac208709a94b371bdd3c4052f57c7af38f0d5658ca03e887470f8f1d1e383c5ae0d1c3061e4348613ad28126073caa697c230e903146471adfd83e42cf65cd50778d931a665e5034c50d13d11bbdfa51d3240662d8877fe65f7bef1213518d690807d350adbbdb5947aaeebd9965ac1e7a354c3f21b92664e66bf8a1060538eb6f569641eb2a9f954aba8469f78c0b78504dbc709171d5c01586fdfbb96a7ecfa4a08689104f7525b9869ce50ad2a48d2667b8ca95a8f09b9a2ca0490e98fafd0f66330ccbfbb6080826466c214573400b031020f4c5fd25a3d09b42551a87358a889f1e59729b91c85064f57364c97d566e6429dab01cf258adcf8f859eb13caa2e5bf4483533f0aed29323a69878a2e8eec7e050d1ec322c18acc8c89584b4e4098cb56488204c3c4033409a0ed30c3998173cfa015b70b48ed841d2d5b06cd2b9aa4a243afe8519e59df4bafa1bcd4f73339b42c5ffc20cebaecd3229d4d1e80cacbdbceb7c663d3a69d30c5cba632a7c1bcac39cbca96cf689abd2ac4a33ef936c110c06833d71721f6662195d0a7ef56f13c66306043128306104129c2146890148e8ee26a10914ec8c5087aaf66303b2813811471620345657c1e5fc280304c48d12ccd8c93b2fdb4ece4e096d4aa2834e12268915d9da0bbbb71b976e8cdf839992f81026c9dda624af243da624deddb0ff599210baedac5258994ea3c3f49b9064e179d24b7723d9d2f829121dbcee4672d4b09acc7e4876ba1b89b70c74846f83c9904577c3bc744faaa5730d93618a0c418d6132a01acb4042f791326d3a32e648982360ba1b049a235b1a85361df1da6d9ef2a77b660440aebdd787139311312623b51e130c5a4c4654353324311999b2d35d93a4bb064977cd901a196a33b12504a2bbe6484e4ebebf54adecfb3a10ae9874dec03762d8fd0f859a15e8fc2fe4e972f2f682f7782a276f2fe0584179f4658ee356ba2f3362ac718236e56409ab94535a2ff43c82d276d718e9ae2952b30202681c60abcd1a0659acf91567f4d3167552d65da3d35d9353b3020d269c283d2606b18c68648a44daffb332ec1566938f930f85860634ab15cc8c11868a0a26a0d04256c159a6339f71c244a4892e6284fa1a3338009165a6015f835313bbbbeb98d4c033dffb98f45a33249850748861425d81da407763eaff85d883504add5d429b502d136ac7934b30130a05d3cd0f6ec62ce9ae5975d7a84c37b91a22606682689a134c336e74175d9051230210244c3144c9d7621a23189248a1ba6b8644dbb5b3b6810986ee5ead5635a91d7f9cab5ae1948f849348dd3528a1992a6880e8aeb999b688c55a329b19d51f2c6b4add9dff8ec3e057de7cfe632c7576925c480db1751454d44262626ac1089bc9c3e8d6c00c2a7423a04d0ed44d5cb7cfaef7645509bb8432b64df21d3c985800405b9af464ba323d2a6a12667a41138da9b1a4cdb4615ac1d5b44a6158d2ee2f59cfb348b95ef08756a9490535babb67f4e8a9a4d1bfbfa4bae04fbc602c85fa2b3f7c14b1ff1205f151b4c9646c7efebee5319625cecfb628d779a3fe5ece8f3178c516cdb7d9a5478a8149f395804ca09da5d32a55455a7c57e56e3949e431e7bf791ae1b8acc7209757e93d8d4fef7fab188823c6a0f739ad3732398b81385219c5f247ca6287531e9555d0ca3c59cb56455b1eebcdcce538532131100bf186c082863b31b299e66c8b5ec816853619cd493130e85a21a4a934b11dca180c9a8fb3b32e71e52451adff592d8a14799c55aa92bcae73f993e2ce31add2d9cc76dd0d0a70f7f1e9915906b9ca553e3d3d375a4bfa5c89bb7b029cc5727f8f7e372bb3b5eb3ac7995610574b1f29cc7452d00afd25eab5be7f27b44ae50761dba6005c117f263118fbd05501f0e96e619bcc0eb9db6432cb20a41e21f868757748e7675b27fda9c940fba4522793fef43099806820aec29bdd6b62e8ae81a1bb7fd4bcd05de342778d90a7f73e36fd48c3f4434c37f1e79c248aa177a9b4510ff765fb6149636e3d70da5b4d8637e36237a31eca6aff71e7f829feeb441eefcd4c1db9ab1ce5d1654d76c14fc96375cd9f7549c69e87e9129df2e6821936c4d4800e1edd261e6faab181a9264b4fe08c3156b0032d32d0404031470a4c8ce916c8d1ad563830d8473ffaaaff199966b484d79a663ad34c4e77e70fdd3523c2aca09ddd6861f3e7fcd8ed592cd887733636ab343592a96d30750ddd5d73c95af2a62680a97fd8dc5183ee2cbfbf77c880ba03053bcab4b3e67dcb627df8654a76987ae98232d0ae6677a9d2d5ec2e09213da961d94408e9c9acffe5c79e2761303a96ba8215fc8109dd1736a78c81ffb0fc55603110c3e694b1fa3110c33205adc84147cfc7a00b06ebaef1ee1a166a56e8eea0dab291e34877c7db67174c8e0c0bc118f63c09837d36db94a1dddd3d58404607dd99e2ccd01ca9834c945e7a2f16a320ac200e3a6ce2e002840d1c62e048011c5c781873ef32818e0247149b37c6d8bce145775fa11856c359c3d94d33821ace6e9a1674370f1a30fab3d9bede4801cba1ee4ed9b80fbc9ca8b3cad1dbea671247a08bb638d2dd5fa957a91b5984a159018f14ca0d2c1550c2c68d26ce7a18cc0d1368957ef1af6ca34c1b61b8bd6d08c10adf066b0347168bd5060bed4a3c7c1becb3d9bfef41998edf835c0fbebbdb59e13bc9580ed9d7910dcb97cd608b8d31366c4051f36a69fda1f09de424910f8eecbb2b499756ab95151c9c9b95457a85de98cc15276b38e270382124331c41e22c6751e956ce7a59d491c103a5c47469cad5fd259b3d59ff734ffeede6674f36e95c7a3e458e20d1d1c1e97156b543808e907c88bf52e851ea819fe5ac9f69ec7e92a8a893429318fc2bab367cdb12a2169290db5cde689cefd8560cda5a845d46b3bc59f7d9cd6db6f869357c2753fe446c33fea84ccac775df0d8cb9ca2679ccf5b1771fcdb8eb3ae74911711e1fe244fc7f0643b912ff6886793ca98f6694cc93329812cfef05b2e658d65a37a875772833fe25ba74418cbb01aa5b0d31dd1dd5006352234babd175c720d74b8d02d8000536f8bae36ae63db66e031ad22813d3e09246678bd2d8498384ee1abca03b66fc93c57a4d178bf59a140d2bd028020d20344ae8e28c069cd1a4fb263fe31be954761ec6fe2f36430733aa98d113432fa9a8e8f3ecbd32ae28434b370dc6a08107688044031766d0c50c8e98419319b4c860838c1b9021c4adb34a79a3cd64182143003220a33b7615c459cf6bc94028063fe81203a518dcc480070cbec0e00a0ca674c72e7f52b53486de4dd6ce57f1bd4bd5f762fc9bac281fe244fc314b7ae0edda99981b88d932eb1864c6d0c018750c14b410c38a5183182fbc00062ff0d21df14f1cc69818861017d8e18211b800e602a216906941981674a005575ad0d3dd75b250de640dd358579562e881a10318303062981c84f1120601617aba3bce2cadd24a6fb95222167cc10213b0a0b6c3821f2f1bab5bb522be76b602225680c30a4e5f50f1c5952fba2f72ba6705595dbd600c96a5175478a14377ec028e2e9ee822d645933854a0c4ec3a0f63f86bf95a9f5915ac5240c7ac52958214c890821e5c8ce1820a131755b828c0166d6c91832db66c81650b225bc8ce579d12c79dafba148e2b8f187f55e2b2ce572ce944fc73222e9335cf37e9995679f31bce411b82b3cffb9acb0367df85f86bd9ad2c625a05673eb3d251d04201102da2d0226b21d3c294451d597c208b2759d49c004c77c7d0fb259cc398bd559c8dff379bbf0fcf5c33eb5dbe16e75d8797c47ce5b7ba3f3b410a587081851558502c6cae40e38a1eae306245195680b1225b81002b7e7477e4e1f9190dbd5ca3516f5639b35765894c5001135013d06002ef8eddfc2bdf9385b55502232588a18a31aa6041153854714345185460a142670a1a4ce1c4143e4c219b42680aefee88333ff7a95ac6d94b7bcf6619b4c4abc4602dbfac93996669bd18abc39fcc94ba32066f61959daf705f3b5fddce579dd792628a9b36492184149f143048f123768f71dff92a1a01918008cc1d603e00468299218a39a24041146114a88eab0378c6f6f318fcef91f3ac32b647cec23f2d51f6308d753ff826bcd91bfbf953fe6cfd60896716090a16406105144140f103858f66c58ece269db4f3afe5fc18cb59c10bce1cd3a0fb572abd557a9b128669e8d303c3f46fb2ee80d893372afbe9c957adef7da55e75cd87fd05bf6b9f10d3fd04982770e82cc312f704932748e858cbb8af2d27c2b49ce812e67c4ee951aec526277e447c932b6d89c0daacf23c1164114127829d10a4417b8f2ed12b65f83d09e4c362bd90e8809e040a4100be60f1654b47fcc5a6892f9ac02156fb8519d6ddafb6891540c00508bc74c77ac1f94ca0c104154cd4989031410213ed65092f4a5e927c208d0f68f9c0079078604cab5498e68f41f198315805b4a177f706b4a12b794c752c5606bbbf494c5561eebdd92f61fbb5fb3356c37f672ebde2e497e481214b9cb1c40596b86189205dbce8027639d279f2afdb7a1fcb9faef3997d7545d1debff2d11aae76fe2cfe0533385bc90e88a0036007541c0883035dbafb63b055942914be3435511c686103606c4089fe9f3ea361ac2a2951a6af28d17a43031dd000150d0809230908242193084006ecc88017549b32a083acfd05bfdb79540ae5bef355adf3d52ba793208dc66e12d3e9f3bddbf92ae20b7e5d18f358e990213163ebd9d69021ce6252e42a426a418917fce487b9c4c1e5082e52b81c718981cb09486cd11d59ab18e66432f749ceea609dafa2c73a8a298cc2b1eb280da5f7352c6b9efc6b67d585c40e1226f4116558dd1161aad1115f3e893b02cb6c1d71a46593ca28988401336618d0a11d031d064830c2099311b9eeba6b8196c4dc1bb113bb9fbf7cc2b7791e8ddd3f9a5616be932348409f77d223fb271790e2025cbabb94ce055edf4dae7fabf6d2a5d8ed316ec51e8a05e6b0c0062cd000a13659a0c723b6b30815148183a9889dee8ea197a3e1db6220063d0f193264487c1bdeb2c496275b86b6f46c4161cb08dd6d439b88a882082b2622a274f4bc1bde0cc6727d1abb1410caa873d94f2bd3f1554cfd12c595c5b214f6e10ee55d2a49c7575d95b2cebba4eea795012539110742194d2b23e2c7ac550133ba3b7a1e755281fc49157040a6b7bf6f93444b7c5e8f65edc3f8de252cd62b8336acc13e9a8730a3bb7b882fdd1d6d6b88af3b0e41430f4142377e1a0dc42d21c07816220bceaca09d499c10b58f662148c0996fa280151d3f9a294081ee6e1f97ab6a58d62630c50488304de0278044026848c0879b1b9f59a44abbae8bf597b494400b125a685a9e680940104f04d10501640a0208103e00c20820baee9066b686e4eeac95cf6c87e4441ce9a379fe95ade21092d26a6725f45272e93c1fcd3e5d75edcc57b1be4d667c63abf3e0befadf2c931f3cf003961f8e7ca0c387287ce0a28afe61eb01f52066043d2ca0075b0f4d786883071af000040f3c3cf0d8e14b775d90afdcbb944e902ba6ba6c6b18fb68065d915669b7fa68f66b69961964b9c294e5872c48225046048488404f0472202006021a80c01104801ea0830708f180dc035ed0a14c77f833bd506241beeab08a85a77ca45890af62a7b37a75917a38d3eea3af2af35c255375afce67b6eb522f9451e7acd057b2ced67095f6368a3ffad12057d77d20ad6159eb7c15f363ef64a5511ca40314930e26981c40c6015238408b036c1dbb178bf5ea3c097aec5e9d7bec96c48c1fc4b8c562bd3a49143f9a5755d6b06ce283fa68f6ac8df9e0994f0f6c7ab6015da84c9132c5a3cdda56038e7832c5612a53eedb09622953fc6baf06c4d0dd3e2c960fcdb1f4574f4fcefe789e9455068460c262069621b034e978bd550c6dfe5aced622e9b46901255840071640846901411d73727254393a4ec493b2cea1f82aa6507eb3b7eb72c0410e3030e570450e52e4f0c59483027208731082d3e32efc04f957235f455fc5940ecac8573e3dee4284c1c2b7d909a63adcd70ee5b996c1d674bd600ad0a2805a6d29c08454f6280de513871e74475c0b073034f6c2414b96d3438943cd16e1e009a0a39b4902b848008d558ab39e5b9b31f5982901347cb5a62b7774479f57cfcca88811f04a92e98a90e98a4d38453833852818e47ac8f5e44ce88ea99cbca1a848c12b9a8b5da7137f62597339fe3ac7d9a3b43a3df4268df14c1aabd4840b010e02381bae8437565de7333be94a4ed312104b499608005e017a31af62f628cd56e9ade1eca53da67e671ec154764186c274f304bace57b1abf4365b5d5ccdacdb1a8e564bf3f568ae14b472ff684c0b6fe9ee9609d3206bcb8483442aafcdb92ff2f161b15e3d336b7b72f6a767d6b258af6b80394c564670adcc4c565c307d68983e2e114b5a938138d5a13c530fbd6ae3f43c8aa357be4f2bb321a6379c307f55be124cd60a4b3bcada376d2dff4d16258dcebaae5aff9877e473bf47f64f303662b1eeb5f72e995557c6f6a392536452296224f7b39aea923beea0a9b2a68a88dfb5428d89c796377c10be0dd642cd1d4a4b92d400d15df3c38f0661e8dafbd3d6f8d05dd3c30e5e6c65ba25ee8b90b051f1c4649bb1d5335376305549e3892a5d5a70531559054a15a52a475568f09945b9a9ca0f13f582461163a62dd8ea59fbd5d430d558505b8195dfb54238578a69f227633a24677d5a6b6684636052f8d1179e19e17fa1fa776674ff0393aafcae15c26096d70ad95975cd02b10afacc118fe9e98158e2686de12fddd486bb8c2f99abc4fd3aaa4229e912c694ca149594291e5b7707532ff2fbc38a98eef82d2b56b0745bc9e9c6d40a09dd31ffed6693be32f10b135ddf97eef881b64c77fc9bc5368b68bb3e591ababbadc7a46a46fd124ff5ab4e6e6522a6556a8b3730b1bb69e9be4589d35d372f4c4789ab96b63c2f318fc86687ad4b77bc56565b29980a63d6b6d45502cdfe7e458c803e3e3e9e47633e3d30d80dacf4a32fd4d0a8fd5073d57e9c685bd0be8ef16fde7558ba2a762c56a5d403679947e2c752f68a5e77adc7229176518765eb32066747713c6fa6c40cca2c8607e3c33732679065c6a60859c812203b8a5385bdcffee73659c436c7f94b3c761e3f36b33e640828cbc9592d0c56e9adf321d1b152ec8cd817f914c786ba5b4e40da709249240c9d19dd0aba06743bf16b39e71a8de29ae4a924949187d54eb759e2d0c3f8c30a23a33baa42ef334c0758d7ed081083001f2a6c5031e244c501548ca880709a42c51423a604650c4ec7d2f3d31e3683c1baff507edfa11c5bdc4fd0dfdacb5791a8eb62a68ee3ccfa077a0dfbeb24650a293e48497280340e20e60058ba63175699aa602765561b4351e966b5b14e8ad2077673b66e98e30631372871bac1deb0a372168eaba1d410ca08e9069b28248852eb686b38e950ea800206142f1eb5b9cd2ea3352cbd2416eb0514fd890e9ec8e0c9104f983c01a234859255a2e1c5c6ab03afdaeb3f2976b453d54fcd28956a531dea97ecad73cf935ffd512c963c253520099624c209490d24213a7bb6aac0d47cd9b5286fb9bc6fc318365c4002363cc08604d87073b281c7f48c705fa472564a07657474e5c87674c4480d232e464418796d8b7c151fcb5c88a1f799568afb7a8b70d10aa7a21188a42092111960684888a125a7a11f273f383961c3c91627312721505183d7ddf1710d37a337cfb6e2fb9fe36a7f2af5d5575bc39e9337efbce54358d7c80e61e5bfe1cef3680dbfadf2ab0d61d662f9d5d0f1da2c9333294b723dd11d5d374dd4e86e277d6a72812651dcfef82aa670b514e52f17916b88c56a6599cc52962a42659abb89f86d762d9838c164034c8c60626322c4440421129c847c6867392b7c9b1773b5d22848bbf26775f92aa630c558a23cf452ab47422d096249cf92108272109446d0114114089205bd10040290088066402afc74f19325623b31c5adee7ff26b47ee3185f2bfd253b44a510e942a4219396bbaaf52a8228c3262dde8cb5771465d55a58ca7d6c9fbdd953815be56deff501efd985a55b47e68b14e34a841030db918daecf8bb1139cbd62b71ab866596f7bd9f451a086080384e06f0a2bb23954e26c56c2dd24feaf2a1f2be8f8f8f0fae96e2f91f88e55d5229cc47f64f7c70765298cfbc4aca9c947451f275b712a39e32dded3d61bae74bf76cf57c7dffb6ea53cf4e0f093c5cdc2ccf96ce8fa94cc9c99b94293c94a784ee8ee04d4d965bac2d5897d259a507b91cdfbc268db1765077b6582674f70c635a3370d19156e90c5c66f8669801b553a63b565a74dad9d9a911edd0b0e3dd3149991693248916ac94e48bf3948486a64bd5d6561215e2949f93b78f666cbf8be408121264104386214e3230408624477870440547b074a78c3e85a967bb1667248d93112f46964e466a30c2a373f29693b7979111124ca7969344119f8ad08a149d8ac4a0b3860e17295fcd54ad3772aa38e53020474999138e08706e3845701cbf07ded96a76dfca5ac6740ac524e203a2778a1f495849715a6d49e95cd00ae1292deef5d57ab5b39bf29b74b56c631e58eb4995864a081592eae644040d22491099272241447a9c8684b1be9ad56dc67578d29faec3f6fb4963d77a0e7f2ebd4306302675c40e29a0532ac829d5a82650b7136aa85340734a2020a0506256f7f91483173160200629a7184e80410630100183100c51062f2c717a819e5e18800b57b8705d4841081742721d23b61983acbf85a00d6bb8d847f387b3074e6ab3ad97d230665b48727239dc8c938fe15abc8a13b90a2cb880852a58c8e1c402664185130b21ac208315905881ae50e4a44299930a635410e2a482014e2af038a510c529052c93c67c858d7c15696c0524023911ff4101d9225fbd8a948c806041ae1f589416d18ce2e0dc6f347f96651464f44279ea076584fb4a8432024afda08cdcf3242b0534692b56c1ce278d5589420e28c8503889713ac18b13ae9c4e507242905301d028c00f0590a7020831010c139030a1869309dda99f1f6cc46d264aa11ca3dc71a655fa9eb5316ff9cabbb04a15add2e92aa992b44a63b5140fa088d3001230801f804e10344e415e700ad24310a5ee1ea14f41989c4a80a3041594a0815309b8127c4e25fc3865713a8de0a4c3c97512c134839309042713ccc46363039b246c8a4e36454e2490712241cb4fac208dfdf8ca5771e20c5a8bcb11488a28d6f26330dbef6b407c15511e4595c293c67eae5d79b77258b514c368d2d2669593c66a93c662fe389aabfedad9941d15c0152701e4208029027861041d9c465062040498fa34c2d0083f4e22e440042544304284a153087474a7a238113f72224e44b39e1371229451ea0865e4310acac8a3e749998ee7c9d4518ac869d6431911a18c5247ae4a619413392b7c2711678ac336e34c6f3e3db3525b085d8a42c062429f42e86208a8b645a7008411becd6f96a8f74e70005800401a27004cd1dd51fa0400d909003e27206b9c8050e004c4e7042484c6ff85299d94a7308892d19b20975f2b3f96547f84a71f379c7ee89c4088e3044218107c388110e50402cac719271f5dba5993fae79dabba99d1745d8bc293c2c2b7b158387c2791669b6387c3b775298c0adf96947b1f47f9b1e7a1ea635b3bf9e858ebd4434c0bf34f3db8749f7ae45ee8538f26ddddaf530f7ae251a61b9f787ce9eea6a0bde1c4034b6ec9fec9a9a6cca9a689534ded54f34204fa19cdf2963fe9447381eeb6a14f34359c66e838cdbc4089cef2874439eb0f8919bcd663759d0f8956362476b74e9f664e38351ba7fec0a96ba7ee4ebdc21d34b8838a076de8aa2cfbfcd3edcb3d8a551f9db922ce14cb1a823f77cc3b64b0238eeeaee0fd3c7365f9df5f3bc0d881a5630ae51fe8f3df8e9d2057cb8e3ac2d4d1a58e1a4e1d293a78e8a8f9c11a3fc8c00ff00f52c8f5e947657f577f319da3ce3134470b73f890e38b1c5de488d2bdaab64a582d0b95b1658a9489a1cc0f3260c848323b644088e38b3872dd9d42a95878e56e957c1559dd6757b63aabc37d6af51705cbd622dd4c2f18bb51ef6b705c01c703e0288203d5ddb9cbfdacd2dfc06f746fbcdee87963006f88e0031df860091fbcdca8c30d319dc28e33e523b98eff04f92a56231df0f619676bebff0ab9c1a5adc56eb11b51badd50a10d32ba636afe12f5da48a20d0474c7d412f550f331283fcf37f5faf8b8aa86650f8ae881941eacc00619dd5fcbcec6b371840767f0c0071eecece08c1d04b183243a2843075a3a666b6f8d783aee2b6c66fcb10ef7b5bee761a69fe57de5e4e4e8d895ecda9f495ca3d1da4b9b5d95a53f6d4a9a7f2d873e3d19d3a1d0a7681665099b486428d2440724748fe99883ae65ca010362a5d6e69bbdb31cece4e0c71a62566b6869adf175afd1e4263fdfd648a12785753878a34b9cbfd461896be1e02885c201ea961913a67b4c97a431b93eeaee380635e6479c4937b0a23baf79a8e413d7fba0756a4600002028931000003020140bc62332b16c3ee9fd14800162b856b05ea1cae33cc821648c21c400000000000000461b004c9b09795e5624098c79f82d8f62a2db4da8cb9481beb753c7d4fbcc0011a86a0442ea728843db6e9ea28405b06369186c3adf84313ee780fc84c70dd954eafb8e16a8e4389d4f1da75f9f31a087b47002345f0c1bbfd168222388e873103723ea63ca1e609a996a569696e0a3f60d3a08c7bed33fe313dbb6cab83436bbd4b8b9952d20984220b5d43340e31c519134d91a32b30f0eb627444280abb4106955136c0a1596c7216f454370f684804fcbee4ac7a7682ffe0d3458cc1405c2943dbd27b3325f10f50d2f5aaea27f2d3b72e4adc5bd847ac9a6dfdc7c27041afe45d39257f942171e1a335331236d26797a7863c63e830af8a3e51cb410fa0ac629fd6f4a50cbcc48f437a1c08bf086cf3f58163f9cb40e3945e635adbc8350628b3b7b34966a4b2e01bf64ec1854e4a8e051e4bfe512fcdcced905a14b317ac6a40f5b2cbc00f80c190bd944b6bb630ba7f03118c8a4273cbd22cc8f9e6087bddb30ebf7a6b6ffc12d590f83dab58de83b9a3782789ca57a4e0fcc97bf2ede6fe54c018879a7dbac20827cd0cd8d97e935d4be20f409bf7581c2daa8bb29a1107bf20d7880db2d0f844e075c715f4eb36a621ebe4123aa00c065e400bfb096963198a776e239c4eb1efe551a5c82b0586a3f708b58a917a50281ed99a5f7e1e5e2939348ff6fafd01272f01f80fb315c175e3f219e0aa4f88ee3094e8e263e282c9b577ecb4e8a2d9d0496310523ed58a01061e5acee370cf5a07ae2c32029e430d5fa0cccd63b5089984902d232b511ff0eaf841fa90869876aab058e62c0870d821609caac5541eabbb8e42da37086971958920080bab497b46cb2b4b68a49260ff7573c5c9d89804227f2851aecad918ffea473d6ccc8985ab2d3797b4b868f9e5d6af03906a6027d77b8d71126b606831de9d2036ef4ddb4d2f4ffb2f3f5b5226bc027741a26d284f4251ada6b49e69f9378b523f9c12ad2b5288de3218940d0866c2fdf16cc6fae6b6c14deb20bab4735188e10b5dd66fba11123e901c016571bc6568980c9d96d06a1d3181a3a6ccff54eb129946118158fd231f2becaa3123e968f6fdf47ba0de7d2268d9c0903346c1cfa6df49ba212a7a520e919f5ba354cdf68a17b40caccfa6e7e030248d47b152b4c69a91594906cfc4e562844088dc11cdc1e242e82275d6da4b42adad609c6b36451a54abf7dcaf966c0c7a723f476e66e78f61e497f9bc700caf7dba1933ad0f604b6da4287284346d1e129fabafdbdd33bbb7a329a50bd8a029ca7472185f82b83e1e5e16d4a754b7fa3b3ce5f9761c0c7563518d204319a113d57f10c8c30d5714727695f60e7b8e66bf57a61b0b7b0f366c1791d5fbf3ee4fff9cb26c000aff73799c37f20ff7f192b7afd4edf03f814d57e358a5c53422421669ca69ce5550840b8475b1044c1d1c204a61b61af3ea82cf487e90bb4684b045599e9afb1bd551b2f6f1571255d2bea727d2cdeb2bc96045e717d3c866a2afe57b57e43f018e35c37a231220d8c2e3b74a2fd2bae8cc5cdf5f295a3ed21bbdb415af746739cd5a5afc47932751450118c85348455d352f8d61138536c4f6eac0829a3d7c85ae1dce77e8477a2180176e6dff21007ec543ba808a8ee9014fcc8953ae3228ded0297b856cb8babf4bccbcc238e5646c06c88061f154331648b9e51a5db10e04805b189393d592bf228a6764f3fc123a1f6bcb6a5c7a0b6aa078491fd3a65b78381de1687be99254ec0937347f9568980e70652b0fef6901549db3442fda73af177c3e07d5a6beee297f16a4fd0f942a58447b84fd2f8c1d8f721c126c6815bc626cb88eb2d44e92f2cb828aeb9b5f82120e6f7c5ac12ca49461ae18b69806e75305cddd443ebc832826b65fcbbc911366466fd5b8621399cadf3f5e59c04d0bb89475b7ef43ff753e0867516c47ccd4881d1921591c9c102a82371eec375745867e51916fa99dc2ef666257c8d665e05d9098a59788388babe2adf32103ec6661d728f40c7aecc52defd20a2a640107d9963c0abfe1497f9ddebf50b0fb74a79d9f683d5b094760ca50883e0b9f6ac473e7b17535ffd1b6f0e1991841f89a8253278c4953d68994ffff131bc4d17f5f3db01e74df94e0bbb7a21b7821b5d8ab51ce288be1a8cb9a6b6943d252bdc6535a151e6693030f5faecccc008e18042b78f14b4b082db325c21f58a5c85e18248ea611059641e32f41414727278122948112a198d05d14091e53d46074dc24c7ff3b3e3ef8246c8067eb55505655ce1ed4c27ba980a17d52fb6f41352802a9bb3c69248706bbc8f96cc7b5fa03c1686a9b24f82ca13a9491cb727baa70f123f5fe141e90cedd2b2e3c112cf6c86699d24c829ab3ccbe3a4d93b891e8bb57e3dab70076e508882aba4b2e0a0235922f89926e5a59bd352b65343e8c3e2682fab57b36cc73b18141ad8d69ac1149820456831eabc3dd96f787b163b4c5c1e7c5c4e4219c14760a74eddce611a3a7be33fd005236b1242c368becff57eaee707e31740bd999bc1afeabf6508294894d57b3eb7aac9f5222ab1b1b314731cbc2b38a914c266d9ac507850da4109eae721ae79ee1b2c222c20306ab08e04d7af322ee1382f3520da815a522ba98b7a3b82eb643363bfbbb2d4492da5980923f37153be92be0074007448856a67883d0044b52c135dd7ec6804f2777ab7eb848773adafab7f2eb8b143ea30cc60c772ed3d6c97f38ac89cecf23fc41b975080550e7b8bcfb0937643968804a77d67a1757e6d004bf122554b31cfae2e3e7afcd5226e5487be980deeb679523c47f5b715ff96c69ec96f56c5cf357b06ba36c2afc30df38c1f57417ec03ed40913d6c490e4cc3f70e21b20913007c888aa63a7b39bd732ca1be9c8482b151b7c2ccd78c1db6c7483d6c10f7bff1dfe091db70b4b1903695e0f56dcbadf44e072d3dd6262732ab6d0f75264f3d6c7e05533f3988b9599cbe3c4638ff120ee6d0859ad23d1295689043680d7892691fd6444ccea62717e8e11849571c493b2dab75e7b62c3cab656430ec5b6bdbc1363b7a5cefa14ce5a4abc73a2ba451b333158e906ce1129bd9bcdd1e5b524a8d35d43c6f44c633564bd7a2ec710cbe008e89f9baaf3cdd27b83306d68ff1f85598f4139212a1daf97a94d0c12b4d0a4fdfffdcb86cb3a4dfdc78911fdf2d661057422739c62781c2d0985d66a70e40df538c2566ad29af2c75c90aab6aa4f1b2244e2bd1ac5f9f17f857f34fa692e8a921e8bd5762c74db758e23555ffcd8c17acb49e3f6fa41d3ed2bc42b8b2711fc59d0f4b787416f30f18b05db9edd3faad4db22f21e400818c6ac4ff389c9acbf67242b0da4652ac9968d101d96e2a158fcfb819c7d6a0a44607448150a16d1b5a7c3d4f53b09f2174d7f1978512d3f7b1bbb8d3d73c28d627108b76cc98403cf6e52374c0b976c54001eb770d821c59586c4c3829a9bdc765c410316401df09282195f8e2cfa066a3bd912201e8423121ce11b38fcd9853d39991269b63d2d0920cbc629603b68639c8175808f3244162b5fbce135e046104264f16a336f290bf9b339e6ea99f0e9176d0c3eeb11635cab78bb81d04db82ccf3ceef2fc97ddefb3b8ea30bcff557f003c8a464687bac1ed9e4d251cdea62dfd71a2151bca4a6bad751afd2e36fb60d4f8f69409acb329b5e58a8418242130bcc76cd4ef2eca071dd23d1c053a50a6594057e1567f4ada5be2ada1f1e206c39f7b7f80402e3da83c594d87ccce9f0fb74a39f900aaf5d8c2db75db186d4a3f6a4394f80193d7139710b50a59bf463d213963afcdb5058605e454f6891ba1d6c6a3e1d1046b47b83537a0c44f3405e81cada1bd7dace161a3ed676abcfc717ce3ea444b70c194899ccc8d3854d2d2f9445f1b2d4b0aa98da0b0c6236c8a88d1e7b0d38222057aa45e223f3927064629209da4cea3e7c5c1478817588b20202c5d1bed513a0af75aab15e24d40c8ade1cc8c066517a460d5c65d137eedfca6f9a86449a200ec12cd4ca441a724e24eed47e21c414093faae6a9c8b6ad50eb7f297d646637a810cf7f92c0d3f2cf7e8a0df0b1aa7bf03aed13bae12fe6a58bf1947ece4c780918b3b7a926125b1610b56ffa57dca835baf1b3f54c82f33aebdb9f1f0c9840c83e52b87304bda75842a3f11007bef835e8c4fa3358910e54d7c1208fc2c750bdad7e36d0bb3d2a8d60a5defedfee6fa28ccf95d430085705e03f890b5b2aa871387b1e1ec19123a6fdb1e0d3c319625fb7829b804d957a0fbb5f7f926de6ac6ba994a8e857e5e8cadc3885a4a0f57d32e040511fc3dbd86a160765cc251aa9188b267a5225cf23b20ab391cf41a126d70b0867016a3122e3f971308aa40eb913be0750d3522f03e6f0642f503202a4706f973392abeb9f161b5da47a2d82eb47ba57f4110ff5fe78366feeec71fc9fb21195d8ff39228cf55f4c0c2fafc778e1ed5e6151ca79d71ef52ae0a87f77015615658d9f4915d35a5f28d2778bf43ced6c6415981bdaae586ad182137c92b1b65ddfc9cc0ca2fcce039fa81e6e5c9adaa7dee49f4996d696204042871355126cf3d6c6cbda28c33d91fc311d9b870b6ebacca7a96d6d9467e0d4b366a03c535c1b76c11418917969af3d5040807b4588f90868a4b018feeaf743cccf0e72001013396fd42102340639c8353a9381b9a2797224dc589ab87e6d184386814651341e8aa616742e8972eb20194156d2c6a0001100648761083c26fd712a3c8e0a9167a70c6b8da4bb00f1b7ec03d352d2a3ef1399cd5cf3e9d24f970f773aab39edd1e9f6f572203d272b2a361977c81856a0291e106a298399c6b6c342f1d661690a3fd7a4bb6d46c180a99ef183c254330c2e1b0398110e7f797ff868dc323c632afd0924f195c86965285315e907e92c7603535db1ef2a7ebbe6b31266df92478a7d9547246af57067757511f6340dc8e2819414add8970566ef7b231e9a860fece979579836775f3f27af5b0a106eed61c579fe37cf4e40fe09e5d1b3b9dc9dd8a344b3baf93b51b6622b4b94309f6710c0fa7a756a2aa4d90102e4cb31b21b89e5a24a8bc4a5b73bec3a56bdfb82101f80263a25b70f83068dd8d1e64cc98e63b3aeeccb78d6c9e3878b62a9c41abda9f32e3164453e971e6acdf7f29f55818e7dc5cf8d5c1a7bdb1896fba395692a30dee4dfdc509a42c658e854c1bdba8dddd1aec59e43b8a2c0a6d0fb8865c98d269cd04b978eefcf844f76d99251a999e2df85daa8352343c13bb49a0d681ea4c513829e8131c939ffa81a34aec3aae07773adadb9660b79ee1f063b8783e5f4a833a405deb1f5a7991f87d0bd131d8f8168600ddbd0058c3eb0017b83c1b05588996f8ca7ce0562878a9a8266d889a03b5cf0f2fb63be78735f9544ab4cec7ac59c16dda5e488b185b62bd528e9e19ffd4a52e5530df56d0f0a407be88f4de93a16986c0ed4e3e6433a8158e71c20d23c0bbfc107c79526e4557e05e681754b0571f8e8a5f7b03bdcad40d29fffbd6ea56a614b41cea3942dd73d6ba7c347ea9471caa6ebf7d7ab348fcb822b808929cf9dad5741f9556a6c73af196d4bf904222325a45a9e906976e93fe647b8d8adf09e5861e510a821b54adc469d9d3eac678229742a0312da848336eb6db59955c445d3f376f6874057af80d7dec8bcd18ccf140fd6b0831148c775656fd9fdea9c539f62adbfb21f3bd978e3926f4e64fdfc806779260b650e6d6cd0a0d534449e428a18620c98e070876f9a3daa5e5c5c8363ef1b6f4bacd049ae85b09707c1a5eccb2b26e5deb424523ca53d307b01855b4b62f416e2513eb84ef45f6a4f2f4d6d03edbbba4b05b8501561907c58cf8b106d6e2ef3b4bc1605a2ab601c36be51116a617b2c2eeed06e44027bc7b1f4cb023e3aa5de92803782256b75c5a0c7e9e30ae6c0812ece56e00b160d1a47562fbfd22db64204ea2657f713ff995cfec26972b056dd41671e17bd693c81feafbad81f73022d5f5e955f13a1de1a6b2f4fc4b975d0b1b21b4a213e4c67850abd75569df51a3c516d11577f2ba23d320b1b2e852469f02d762ef1684d514a8de7c7c7c4068f2475c52d2058964a6fe272491712c254e183cc293667605b9afe4c7151d6b79d3c4eb2f493e2fcb1afe4753e212fea6daf32293597b00035c4a0d08268ed71fb9deb84b5e5dceb2680026cedff5902994a259c44373cf7b15ec29e0893994772278f74280f5068023a0ee7b7b03393f0ef95f6acf13b6f4f3d3543124c867e5ea070a4fd85fdb7ff604b8ed13bc6a747abb9843f55de90478b66a21861d86efae0a8e53d0fb17fa9d055afe7a9e2c8c3f007c874fb6814077fc863f66f4141a48600ff7236b7602666a599ada2d22e6e0a968c803153acc98959906c20e6aab31be32554f4719a89b1a2680d12e9dbec0255699f3ea87214c999ce0c86fb1a23d7dd6d40c225bd449265bf500f6d6a01d7b50883eb7e4d32e0e657b50e39e36e1118274435dbbd6b30ce624509cd7894cb910836478f7fb2a15611ca792178d57f78984459496e97894409337b6fba4fa1d807f21a1d930801ec10608091e3fd4768f5f4b513906c11c750b15e72d4e6c55ecc9f87ce9f4100a29ed52fc29d936356e72a82f24966ea33213db9ed55439f90e7fc720c516a68e6a740d0c08cbc83f5aca4259cba5b2adce4b1fb689ebfab5ac149ca9957a6c801dd93b64fc75b4fa8f9ac3930145710c63f3e78ca0fbffd058d447b941815fc38ae182c1ae539b253bdf1d3b43829bce332157d12743c76e2a30826cb9de44a8415097f876b6822c22d094d35618045444bc515aa0ca28f3f14c24f0fdc1e2d3e0f6d1410f37c88e1057c35d679908e8f50e40c91e350472d468d34590ebd05a11b88587b8da6c8a2be46370a9bef2b2d42cb30e87904b5f6e345d335336bdac3f37781f8abfe29f85b9a4cb8d450a78cdda1be4a18b3f31908f2ce85805a0365dc7677793ab8d68b8c7af6438afbd211ff9109f0d322ed630f462f2f954b63d2408c0b2847113a23af6d434d0e746ff24299f9eeb1647e1fa4da63849f01379673dcec6875d470d284a24f9db9ff890a47b1fe0b55755fa998a6b32b88102dbc84f4c5796e7fd2334b6f15335baced92ff0a4cf253a6676c71983cf893eaabd3e93cfefadf56fa4da19a0bedcc46fc5b479fa7180307071475cc03d73cb686f2de4c9fcfb87d14d1cc2bf4d99fcca7b2a3127d1d0738579b8651cc32e3778afd3c698c10c4c1bf2d64a1e41fd4445b1cd10ad427cfd91d0630578aeab84ab548d00ad4a03d85d04edc9f4e8def432ad47ec3ef7ac9d20a44623a4aa3b87cc3a07b14fb0c07d313d02d1bfc704e01999139813ef1586549aabc0c1f984d3cf7df11b3e19ce06f67e36d4093110303fbf0f4668d8dce7a512ad94bc7f6008c98c3b6c036a0c7cb68d983a3c39a7e0d0d63c8a0ee75c70da24dd1d3484904804ad6e1755c92148c51b8d9e90cb9289cfad2180275a015408d83bc7ce12207bc48a61d1b9519839e081390850d51319855e220c5df296c52f1fdb01e25db2d048866b58de962590ce337cf77f986eac751857f1392a64f79707a3ad42bf6f1186414c7514cc5a5e2394c4ce8ecafa598f4f0740b7e06c982da5f7f6c866e4f12b07db104ff3f264504643826048cf83355b0323765b9330293837056746fa9cfbfc423e7eb7e96d0b784e53679e557bd2e24199f122a1c849de09a72aac58c58a18d1f44e116fa914c129b325f1c2e01cd00a4462d68f2d5765cd794064c37e278b90f351057fc2beec202c946bab29efd3693ca8fc6904c81a8ef85de40e3c3811ac6442ded8051ec73b2c8660982b8b271145b8d68477764362962880474e9765358c39295a8fbbfaa0c74cc2a2081888d02b6f094f9d72a9f722fb1ed0731a00ae9d41937ce9a420b850066b515d6a96e209c03433857fce0c51bed1a1cc8e8aadb4a60c999b8a894e7e351f5d470c74a5ce15c1617dacf4cd5ad97d738365df496fcabcf37998b52604ac87304a0ad52b5ed19b720b66216f59c48e8ecf3dbe906b1b271826f2c5872c55778ba6cd9a6ea1a42fab8ab515d39f6c23ad107179594ed09078d4ba3c8c7e104adc9881fce03190c68cad30b398d88c24f4f801f46252b6f12343084f844ada05d13e1b33c220904e913a2dc63d3dee26f15c4cf27533a8fa7f8e30d3da3950f93229f4da06748b773c07c24bd0d59a0ea502741418a980389a52ae296a3380219457e9493b46400291732e3fe7ca259a25e8c58aa173ef66abf170eeb4bf1f2e591b4952182315a9860a117c97c3ea7fce33a1a9334d1b7d7862fefdff14f68c0f1606f2c51524bfec7d4297fcb2d3100d1a7aedae7e05333a16448d3a7f0b4829c60b330e672dcb38c356804b8790c478ef74f61fb96e3c90cd01c19f0ae0a6094b7c3089c6e1cc396573d8c0783d561b072a6a3bac71d8a391e69be35442737055691335886d5bf2b264b7771892920140ab9c1ba4d7fd81c6f561e8e1344662c1769566d87101806eb9e1b9e5eb21a7b92c2e5ddc85d98b758e8935a37dc86dfb6ec9f460f80feb6ec7c2c5b929fd6faa2d7d692377f3b8e4bb33c898942c2c23e3a332f2796e88e22f720af86f8650e7710ecaccdc5879bad1d5e46c41ff96ede80bc0b69e64d3dd167915d149ae8e7c3bf8cb5fb0911f2794ce0bc68237a881231990eb324cbddb9b575f86cda0678d39c0aa054a20b2521396f363198fd1acffcff81585cc255115c2fbff2e3bc218afc2b4da254ae2d337c4e1faefb532ee53d8065161495441ac587cfd391717979bfc274924a39e4dcd2554ba1533a888da1cb52a47ea8e082b4a18b86e48cfe3acc54d2f4c64c82d22429eba88b1e9e663304b95df3e22509666551bf971dd3cb5fc054a82b2e0212600e549b476e726010037c6615cab92849bd247046008e9dca88207ddc5cc36310cc88bb284d0836a66cd231340f36f3ff6fce1e5bbd74991ae4364442d04635e6a9d8fcfa52a4425ae7c82df238a8be7e63217ffd6ac3104c988e2894caf1a12450da86b29599c4fb17097e4f9a8e7ee167d164d1990ad117a08469aedaabac3c919c301b5babc1fef4e135382f3849deb3aba67a045319c5b2d61d8427f138d741b8179bd8f6d36e73e4baabfef963e208ff419e65143c7a028394e227c53502eec93591522dae8726ecc0d5baa77e73f5ac39707c27fb1004ae16bf10fc565d31d4eb381c6cbeaea0e4f3b99ab9f6e30cb455a017996c0fa7ae1eace7dd644f8f6ed2e9d9171461403977559dea507539d8157e52a698a82dc88ff53678c3d0af010a441bb0107dfbdf19ba403412bb3a41bfb7468b6258a77f2d1e18434b97e09385bb74e90b03abf7a9a029d780ba2cf0efa68700a99343152dfa6adad5123f70c3d9eb4c85e3ecff798e54045b3dfe0fffe428bf31c611ab08257d3a75b296d2da6d7b94c2af28ebe1fa78b4cfa6a24762cee53b29b85cf10f3c42b401846fa1d800e6e549afc70e9884237f520da7a68a0bbf765872b57f26bf29425e10c0770dd192a94944d50d6a0654bd62e3513bcfa1648e339abcda083f8a522e3ddb0b4113c5b8e955f267a5065b64eed0c24c983cedf3a36e101afa0ddec9e7a2c607abab235b13f794d2bbe88e585dcd959693a93cb0118f8392a649b26f16ef1f93232a1fd95c522c740393310ec318d5a37dc382fc3ad1fe3fdb64cf44a71053f0ee0cb60b57efb47a683eec6ef4abff5fd41d8b055abc79364e2b960376d26ac7300ee4ea583dbfad6f2784362e8a9489aef24c4ab262b63df667dda2ae6d9c3eed0ff5a445d4f031369dabc861db4a74b0c5124f082e864e3531d483c780c009c2a66de1d0be999ad2deaa746500c2ba2e4c797ed4f57376ab2d2ba017af1ccdc1ff343105e4450dc9172bcaf03966a065669982f443f3cc572154758637eb7b02f3c396249699b59a461a74df339b3f967b1269d1f5551e78c8a40bcea004cd0fd216664868867f29524eb75efd9bb71e0f08f9f21314803697c583e9384ff5da01b7692606cb6c51356ab399e3a41130e782422102cfc5a095c3a918b06b1e2869730590f408d5d478367f5721e368d54e75d727594a778ac4a3e188a44305f0c611cf1c7ba90b0f284f52a245ac0e5667b3bfe9bfa32d077124189fca04c8fb7fecdb48c99d96d497c1fff7945c48c2a13a9c4ff0885a25d5fb843e7f80e21b7234335141d008ea78c3df60959c8467398beb19c997128ed67b122def88facf5c52f86f7aa1c65ef017ee387344a35c6e2bafccd256f35d5ca195cc43e88deec202bce1fcde419fd59d3abf12067be1d67d06c07adc87eff05ef3ebed3fa5b9621f0f3cba6b19d26009952968f7596f313dcdcc0ca6a423578720a1d430582ac2908a7bd295c8992353bb14a092dbddc4a2b9c6264a4dfcbf26f0e8fa4bd8d64e97081c7d1477365f97f79f950df70e9aae1224462120cb029c635b8cfb39b3653f13f795e3f2094937cfeffca4ccc8c09b8334ffaa1ae8750024ad9fb89fdded472fbc6ab425f20e96dd2aea6acb4f2d15830889a0531cf9dde2bcd713eacc09648bb7609be257521d59f2532de6198ee98cdecefde9a1751916c76494ad36020b95c6b8e0a83680eb4f44297ce15fdb21c6be70a170f6b3813f63e1eb0ddf1b239e80e95c1fc49f25672cfc0d90f849fdde9c3bf090e6da84e30e999500ee7337e691d71eff4df09e30c3bb222a55c1850df266e1f74c2af02c69bfc06c2f46d8656ab10151600a57737588e18e3ddaf228643cbcbe77487e3b9b5f14d4c8464e7e980d406efb926d465f5cd51d1c1dbbf12fc3d8cd4e43cc8eb91bb477679b47d7288e8f0c3ecbc2e52df50d882682b8911f6c5a05b27bae01988015d59ce3c3e032ba4ef2d7c2d9514318021404a9cb6475c559344fb1450b148bd8de464b2ac2e2b89cbb4b7ef079424a5b4705817ec876363262181dda41d8001a071411987a54eee566b1608ba445bad5ea61eb6fcfbb219dbc2c5ddb90a2c502cc9370288ac84e3e6d54ed60c690f1198778c213f9466fe8dfd7037a13744da90bca11633cb1e4c23776b90383b5ec52abac49558aa2e7c74d1bdbfc58e39531fb0c312705d4ead7e6f1ecf709a7173a8ab4e97cfe5ebf2644cd4738a9dba58f948316fc4dfa301186144c8a801ca7f889ef6091c811d108ddb5721b4684acad063fbf0a28c1a1b467ead6d45d7077af719219078843f3885a8e711b4be17123ace7a5f845b8fcb4da74ae5c847ca4dd3e49b65eb28877f1c89731902bef392605724ae61300a5f573f53a74f6bd9ee47ba098e2656df384a4a1a1d9b04df1d000a89ab229448d7bc6e62f9a399e30c89476593f5116b67484c6396dbfa9c863342f2af43cb0ed016852c07a1a6e94290fd82a901d2f25d0940a4df13a90a82d156a0c6db95e7ac70e622b829da16f6aa1e3d6d50d491d735a308de22af118d610934a3aa71189c5c3579f7d256755cc6379cabc02e5941225aa76a406fd3bfff7040381c01ba0fdd52395cc6567860ae2c47b31d62e9637471072611c886201253897644fbafbeee42b7512381d3bcb76d63bb465cf8b52c0bb3138ec68f3da34ef533edee7fd38877fe1dab45308da756d0a0d4dcf636d6cd5c09c61114a4cc28548121e9775b72e9fbc6ea6baf2ebf2e11a650ace454382e9ee75185a79e4e1e8cccb83f9987b3ffd946391d1724dee56532b60fc5e9c304dcffc8fd6d7c2638e87b8e0c89f227f28962fa9aba2ec7daeb5fc9a309d00ab4e8e0c4ab70bef20077f5d47794cef872f463a70f1c2cd99f50c6a176febcc741c9c1751e9892c73bf40be3b5471fb7d01fcb22397aae5dc2eb5f86bfb5d1ae5c85a384c362d1f9e58ad5840321e911bee8c449bd489bd07ff9c7442defde6ab9827fe8b20c4b105750d5be9fef585193b761faffb2a82ce4b535f8fe30c77b2ebf178dde7f0e484a4be4231e00a31dd514806505c1c46b3e6882fc31305073cf71b490a1e6eca614fee30c70485a97d470e1711e7759fedae6a25efc99d7a2c7dffe2fc7ffcd17be07d5ed178b2611152c82c69181fc751cf77d3b7fe8a93c7a9c04df6d7f1dd3d3e7fb2da6077bc637cf9b7c880e21e1cca517f0817da785997eb97c99bc08adccfa5610b78653c20a12888404470bfc896d4d03d2d9cf6396434126dd326a97733998f11e82ba88c456a1a897bf512aad9fca3500dcb2528128101a395e63b5bc6ffd24c069b8f5efc7de3710f5f458f48e279e9daf8011b60936c982df8733c5c275fec22222a7101f5c22c985ad1b890ba73a82fbaa697952833745d871d710b49bc5730a4189c90c14dbdcc1a0a49c3535a6cba9d394480ab004d2eed7acac25ec33c0eb3cecd59e98d8db11a1d84c15b03779ec0bcaabfbe04939211e48fc40244dd0499c3e075753e6159e0df8b6cdcdf595fde2531b193e435fe0fea9aec993d7f0b6d492c656904fc509f847516510e3109bef7f93e5c441845250ab4cb3b3d2cafb7c0d1ddc6990f33f94abd402c1755ea57a2996e1b774e5ab144b454742140c7243f8fbcaac21a2308baaf947f5971ded9372e0203b26b53c379d6fcc30e86de854320554b32e889bac7396b40561e7276de5c79d3c871f33878f984af500d76cc73229b39f2f6604cd5035d96dc396174d9d854461042fd80edd7ba511eb84f5bce64f05efebe22d3d274f4947b5a12a2002174ca5ccdcfbfff1064f612a49116e17d06b2332b310899e8e04c2ebc55e15523d411f7bc3249eab2d3d0ebb311dd86f9fcc5fe81ea109f8bdd57aa0030de1cfb89eb916cf9bd81e786e29bf627709d335a20bdfcb332a7bac7b5bed134b90e9e094ab1c2c654c7898a5ead3c352b313095b55ec91cde6aec6ba0d4643a65266cb22668dd9b8cd8bb333c8765ecad3a86bca291deeca48a15d7b24ebfa96954f699d41d1b624b03f55322c605b0d3f8f3066b79e53d2c43315e5cd14b0d8411a5378a7afc745c5974799a74e13c5500e2831a0e7353d91b0fb64a2e4f7cc3ca6d29f06f489827243b0299d19665a3fbc1e1a4e3922a7b83177e5cf012601c6c4bc460676ef8dbcc47ce367e4dcb2efd596f0ba98d688e198fdcf488c94f6fef27d368a419684b3aa1024f7c7c0d884aeae60f66996b998fa8b29dd71e46d7a2c6944426dcba89e9447d30afe444f69924c9cbf9986577d0b9929710928da1cff9a8b85cefdb79c1b21bb12c513119bf9694884c8eaefba81dd4893c93e0d97bb8b70ab0843e0d36a24d17747a7e7dc26db9bb61316f94113af354b21e46b608e7d6a57b3aaadb3402f68b8151cc740aa0eb10ee8da1e3003bfb004cf0132ed0289fe784d7c8af65ebce7d86ce1e12d438219b85389e7c67d727c9be6683a12871975e3785ed7ea43f3275a3b78b08c8ff8bd2cf4c2d3dbec2f39544dc726493ab3ef2536f313e6a77bb6d623d8e8e1b925035b53a66b429ef77111b22d3f9db082c9e24d5953a28d818bd47ff27b602ff680bf42f98461e12166a841f4e1227f83a97d0ba85f057257243dfec59ff6e8a16238188228f8d416be52ed655cb0f5b8d7ac508023a981cf238d385a66eb102647e6e2185bae0c4568c1efb09af0cea464cc2673eb0dd5263e473529a6b66e643a68bcbd5a15a0d817ca9a10997debfbc8bcd4bd0ccece7fed8b3d5ef0492dfe676c7bfbea2b52e792204566c96c39154b4a62f2c031cd0761a21ac84a8a9c694d53251b544315675a40e9b407f4807b8dcb229be9a54fdb4eb0a8e58ef6e83f64e60c5397ff2e62448ca933009c111b85c53b247456a8e0cfeb56f9f0f31db62cfddcb24cf35a54951a7724a5dea6139df116a6102239d2d6b2734e0b9762b3e0d11cbdb7ecdf3ddc8262504ac39e0fc33de223abea3e3bffff553220fd7c449afe7c0d88a5218d28b0ae7c597da4638503d427903917faaf9df0df0b526bbef8ca7427706644f8fa3e83610206378234a5605d68ab44f7549f7bc04bd3786f33948b60d25225c619da3fad7b76b38cde5bb24ffbc6f36eee4d57117037851707b10fd5b2345c786340c2156fb785fd1a24277bfb9a82f52be0c448104281cdf1dd4fc44bbc0ea535b918cebccba708f78637e2fc23e67849ca2da7055977fa38c8fbf2420b3d68df73d47f10afa87dcbe4315d8fca16bc62ec365f7ef8584d43be3cbadba65bbd11889596c90d8765e5f632487329acfd2192b74c4bbce73869f68da7e364b1d87cdeccc48547ee376fd39bfed6791e9df7fb7618b71342c74d4cf9706f9a4cc4c7daf4c59e5159eabde73f4db0c164ad5b5986d614bf8263ac728375e2a722c1db8ea82cb74aa312b5d85b66ea1fdf6bf2a6c8e781303f51d0d89995364e86d46b70f72baff39b3e822933376bfd511ff4fbd877ded65a629cb433e8cb1b313333bc0336ea17069d8c460c9dd54fbe16ecb198563e4aca3f98ed055befe295a58bfe05018819cb973a327ddc44c0536c1a8aa511ca8694549dcce404661bdbd14f915df2c6ebe782e73ef988a31b96a025608d021882b68244c841ef86217ed97146e3d59e84dbc61290cb312d4c20271f55f2a8931a4b1491113401ab6cbbb94e8a0151282eaf34eb423b31bff23745a752e1aed2fc57568ce222b8efec217ab499146b3741eb9433107137326b8c5d3411ce467fcb4fbad9971f5cab0334025f33a6d5eac4baf8caa953fd20418f3a08296ed1e9c69ad84f9f726c98465cfc0c440a3ea6b57fc0f8daf160dc557219709cab043432a9dc01de9f8bf4f551a1ab22d802d66793c887da0c079b3a2daf731cbaeb58cb648c6e350b3118bcb80b5be4fd7f2dee182271e7935c0466aad2d31a12f339c0d52029b5108d0702b9ee9aad2c1d0cda345408f90cdd2d60ae9bccceff4f921a8a323d3d5ac6af26e61db8cf7e8a0d8f00c907cedd730ed13a3182ed2871c1c9a2e49d40f5454eb101e9cd94b7a805120bd0e948d34bacac14f96d8e3dc6a262f3278cf3fdcb0e460618db29ce2df78e39e83d9c7773b3ee3f8e24f4e985e78ba3e307972d9fc277b0687365208ea4c1d38285bf1b1ebd6c386055c20145d8e6060d297c67962d049aca38828fcfe5bc8786c74cc5c2c21c0424839984708b7170cb78577aed3690e62041bd03748448f749d169cac92db3e24de44a5bf5f108c379599d42cd898235c907357437c2367167ca841ca4652ef32556f590475586821270b2cbded67fc0786905064d14c580608bce0255d33f21d2949fcf1de07eeb63ac3ecf8b9e8d632fe5baa3997d7c2233a9c37bce1c3052990fe6ec4f1a84fb037fb17a2f0ff6e90efdb52eaf07a0aedb8f3facda4d59fc12611e01a90f71f3657abdc33b0f7d3d02e772f32cc8037ee3935d6b32935830d69c034a1877bb73da3844a5e4a9f5fc6cc12692ba6eecae7c89bccdb462dc7c81edb0a65a97ab965777f8dd6bbed9d734cb36d2493d64012589bd6f529b157c893c866343f17bc87021110dac1ccdc560f257483b5a9f42ce5645f4b773fa84462d7227c85334834764c2e65d0c410a134b5c82e0aa4b35ebcd80987d907ed47ddc5fc9a3552e80bd0ab51a1201e2468e1455f3e7b1ca9b63c6f2dc1641065dfbfbda817b65e6553d74a42479739426c495dd81ad0ece43abd657f564f1ad5360222c8da00d1da0abd66c88176dd4e9ccfa113630606d7817883765665dd308e3ffb5a44a99f0561c2842e3b4e0cefb64b6b01a23f18e5f6b55c04d5b2202091eb47bf66bf19093e0392c6b0c16868cb8e698554ea7683c516a9e6ca7848de0018b77e31d86dd3f06256d0dac0312ab5bdcda836ab8e7cf663a01a2a1a2fd0cb7d5c5f1a8e462519e58642d1f4ceeb9afb76f59f7635fb051e116f555b1378a4432a0633ecf57368b993ffd94e14407e35f9711aa62fef293e824035ddfc3cd5354e21fc9576326ea79121ddd05e12a268064e07d0e023828f16fdb72920c5749765a32afe788067d0a16f8d9c09ae624b065d6cef8e79bcc44c02675fe54964a8236fce226ff020aa951bd64826571ea289017e424a53997be347341abfd865baab5c76fd44475f885329fc7457d2cd24c4bef6163c0b0d294905ca9f3569945a2bf191f72519a05948d7a60937c73628493b0afcb56e30bc0cb43a7eaf02f564dcc00b87a6f18d3372cf3d795b5082e9151e0854d067ecb439a02b17b352ec0374c31177da92308e8a294a00f2b70876d962f6fa30472e909aa6ca540627c651e453e8a3dc8be31fc86b78a76d527596768d9dc328ab584ba9c3a838b71683ccf914184f02c9b86595b556edc67e27d003ece8525105a4497b75b2afa1729b6b3cc5fbe8f03bc7adf08bea68d4f1d1f0691b3dccbc1dc52b44e9247326ac61ad3034e66d3cf1f648d0e1cb3cd89df5fa1dd0d1703be6c78093da98bad0c6f1a5632415cadb8ee7e146804d37f48136a81efe221432bde0a79a0b524c56db635c5dfe6220524a5e2028cd055397a26f85545c7eca12b78ca10faa0b2d88717032d7e816bfea16f0f16b589770f19b8fc850cd2e4e84f8717dfe2433fd774ff40c53f428eb7b89e4d52010334c1f9d27944070c42c64b59251c2eb6117f574bab20ae84404836b346d8391b25bf4236dad98b1b63a7e68ec0aef40502d4f8fc7261d7f63444b7622a10816899e8b8c770db00027133d1cf56716172b3f639b59a701b37af34dc76a7de4776ca77cf504ced0257c27a57e77f274532f4b217177aa9cf28b6bb5523adaea03985391a34f67f06edb10f13e83e7a38279b893db6647c8845a4c0259883577a83e4d3e1c945f044f3d1cf1e687369c3ad036ddddca3b6eeb42dab8ee7b9b81ac8f13750324d9583a1b8b5322b47cd4a040cc5d9f823fc517cc2e3e405aea619c281d02727987a7b134a15de2ff0b560c1d0791daf024011b7340df5da612c44e5eed676debec01f2080390883290a1ca257e103f15a8288c2db9e230f0b004600f6fcbc0b1755ceb073cafe3745497d4f8867d2d109856a73e8d16ed037e07fdeee6e3ab7c67e6a59713e8197ba7a7e8282b82e7a0f9d5ddb34e82c20a3bca7d42a3386c233825b5ecae0800d821066169f955c3effc34f0badefaca5cb16723644d00e4c3e3c564ee266c9c53a66a9d9c05dc2106b15f0e4876d42e342641401e4b8730f323aefc626b4af118df949e027c187f312f8240545fe6f7f14f15fb70388da8805f16d27abfae51cdc10071cbb678b26f6f4299ac1fc26a500c0e9c5827c737070880462100695918d3560ef30a3a41df5f9b433da349de06762e0507e14ddbbd0962c245dcc2b9a060bddd3f41aea6824e2a160b4ce4983e04ff88a1e524c56677d71305ebbea4387e46b28dcffbc20fc7db41a85ecb305fd5f204320f0182fe34bc02ff9100ffbac7e0a6a969b621b1486b9787d4e4ad0543bda6c5e43debc84408268df2b1828d14d0bcfcdab1bf52051ae32df0baef37ea77a0e311b0dc817146643c1b5eeffbe85ad49c757291895b08b65ddb39dae54bb1e0639fdc948440e1a792e7d12cc48bdc7f5bca4cc98f8ebf778de000e92bc5e805a709cd9cae0f9830be3597d545561d3ec418e3a8122188d250cccc578600b39b542ea3e1059c2b563486c897842a89b5196a1c35c480847eaea307fc1ea0ec38d904cb0224d2cb8f5d53afd32b917a4c7fea376030e6da56750540dcf6cb23d760149f7c16344a42f7607e097a3cd985e2b35fd77afe22e04fdc5b0f1c2e483e6b7a05b675c9f6035e29723934d60f050c43d381d328247a17829cf025431b8e7c803561508ebb35091b790b72fa5539927a21ad090e2df510662b897307a424cd380cd252f3f231326bcef276adb13f3d52e461ecfefa94ee89fb3473afbb62b0969f73ffb99d67b21444b644e207839278c6598a96dd5fbc1a185e1abb6395ff4927d14b707a2f1d3faf58f85ddf6ecf5329d8561f814c51de8f6c1f19e07f32bf9323ac5fe6f5bace5b476c4ae403085110bd2ad0585b891208a40b54c1fcb84d33d8cc3d9c47cdce5ae1595c4f80007cf4b1df3b644a123076d9adfe65f2d6a1b22393e3d01733a7185b04cc5f8b6204973269affa3494a963efb2dd603e7950d6056610685079e5d95db507a5c935cd306f02398d1564103613cfafc2a0ecdf7f793f0c21113d2686b6362a6e40f22773b24009ab6e91ab26964612cda4a36bd20cc1e9615cd0f73422a2148ab3116537ecb468e4371b3b65c2042d5b8778946d00c8ed0f8ec2bf70e329b66bf0fd1679d88e35d1c72361e3a30495efc0ee9712edfc27f0b6d6fe539bdecd1d2ed3f40e74792e74ef74ee3c8704ca4347af6e0f44d7a622aa6c1bba98f4d14643754156300cb84fff44f40b36835090dd16e719fc99e694b982988d8f24e9c3a8dcc088d95a7862d863c426fa48724bb0b90f8f78096b59735d7ffd708754e825fe405d3a71c2dc42eebd6099e514dccbdc75ac613c194ac9f0602280a83f98a7563bdb7ac498ea6d024d28719dc3ba132f4a5087a1b8d5d0dfb10d837a17150d1877b87eb3689fb6bd60d373111ddfc6a434983b6a5c0533ad4195359510df316f64046c7117e19b31685e6c60d4d875ce1f216280b00a546b19307ad0e381d007783e58b793a3b5b0e6406c992d0801d0df6c99ea6d6d771d9256ef949b507887a923bde54b2eef110861d33c1558870321d30100af179b872abb3c207d311b7759c32ad6d06daeef3280264afd14814569eb10fa9a18a25b78ef0e2aabfe2660403075a0c9a1c6fe3cf9fe82d8dad96ffd3f407cebc7ed4704c8092e5a8d95cc2e438cc606ac1e092d6ef72758c2d60017803caf0ad413bebd45eda701de08717c768da7b440b433d42d04dd0f6f973df16506a246b2032cf24e01e0826a0262da609b87914d4368bb16ab0c35c16c8cfe3a3cc738ef4e3a56a810c8c62cdc40bb121da1aae6c911907e75f42cd5e0a756212135650e0ead81f63ac5f8c521e522d86f0ce45eb8485f9281bb138b93430395f5e5e7db556b46dabfd0b15a9a47f75d65264f5123ab95422c8e5f8ccfbb55d481f8532eeacedc4f45d86da88a31ae93a0230cd3e45ea2e91624eaa5bc3b63d74f868be2fdedd83c1fdcd24f5c9407e7eecf780c5bc74701b792c788a146dd1107348c8f4cb69a39a93081361854d99546261afa9f2e7cdcea7e3e361063ec8f54e47bfb5cb382690b5036d20e8127437e17053ae7dd9ef5f302e3ac9dadcc197e37a346b3845d95e50e2f023fb184c9948a2bd441d02d840b3baa551082bc50f6c2f5591eb2f94ccf04e2e92aa970d2a53ec382f09c3841f15452f331062e3a5041d89eaca6464d24171c394f3f568962cb119a292da9d6d0ebc0836bc6a791260feedd878947863fc2f30bdb908a479091a50f70cb363740add9b19a26056101634e84226c971caab804dda3fc9475774245ba63453bfc01d3a1ea4771003fbac56a7d9ed25c1032ad0a72d71490e9c0f1eb888c04ca2446af89f6debaa211f1cba467c66f9b6a7f4f541587414fa11df2593eaec07e4ff0702e3716b723e172a41a4e58738019e2c0c22bb8b0daa92370a6c2533899dcda7685b4878e452d22c3a679a60e4e8be9e9c57eacd51d914a3dcd28aacc2b79b2e19173d3bfbc47347ad9f79b704e82b4bb1790546763ebcc0e79965aa6b207b86922d1b24279c28ba44742bee3892b74bad562fef0477547190f8af031c33a1a2a32dc4de3cbd3ba7fa0141ec0d55fe0ddc5f23d423488e13811d9b7b03356a9ee70d1e919252d542f4534ad0836817c53a76ed9dc4d45980654952305b73a36ee7964e7f94c7f33c22ae2e9d385505ea0b89fde8015c7a687840029af9eda6b109a4890a5a8ee18842210ba13602811fbaed726eea2d95cdd7834bc9df1db190db964d058b1f985ceb10b50f94fe1a7e65747bbd457b9dff8f80eb00539a7336d2b681619eedf33a09e5f4f96ed3fe12c6e93a7e259386865e6bb8d0778ede5c08c95939e6958adc40eafd8189cfffb2c65f99f4c9344bd7b29e470f32c874fd102b3dccd6bcca3e9c191ba38e3d2c91a0801a2032907f7c2c920085ba8a71b7b9939a0961dc9f796c0187cdbd07919eee538f47a6bddc982cd49c4ffd129e76933de8e158f44e1353c704c26e42891897f58cc8b2349a67859289c30e9852c974c4030d398932ff5a1cda80abaabba6ce93ef20d8d8392d4a0a3e6c7121c9cc24190ab68dcc762df4015eef827acccf11f554ceb6594ac7c2cb6e51ec7c03c3e163b942a750bfc7f4f1539c33073c142f0b1be9a69965399411dd3f6c4df9f5d9912eb3ed09e1191e3093dc1496e88ecd03654e65bc1ecb14ed14a60ebbc913cef32bff7f8f063f43a242e4b3402afca766719d56fd5325b3f1788d49b7fa3742d5e3d1b0c8c7a1ad9ef0100035f7d10a50ae442e4d2d9c6c8417fdd3cb3919b9a2bed815238e33b1161a69aec9ca393a875fd823e8ce9221a276e2b6c13b3427167c99f768b31db70f8f56648071e73e257eaed4756bcf9ef34286b3661a23f93f41eaff6e00b6070257eb736ef34aca3e06002ff8ebfe27ef0f3d65411087707822f40139e3223cc1cad7af9dd21afc0a6632e0e87e838fc3c112a695e1634eccf67dea9e761fcb4c24f0a7ffdf576b1b1c1d5c6734a50b3621a1768330275714d8ee24e91dc05f7e6871fbf2a20b1a7346fbcffb614e251bfd8fef687dfff77d06dea4d1e09ef2fcdbeebe6ffd56f4f9c84ea71e97255f819a5ce34d406435f24d75a1e1f2454410768a5a780d6cda24647a5f968b418c5739aea413e21c8739680824e1cb4f2e23feb5c30abe397e0e0da979fe79918f4bbecee5ebde3df7ec169ff1001f6c8a8410eb5c146d2caa3d36e11c7ae20a651ff4c49999c0c76e19991ef4ebb247fe84970837c9fef1752cf4da64df791adee734ccd1703b1967cda82c63dac5979609062423bac67a1707e7dee077330c40e557b5dfedcc785a3621cc2fd423cce8928a314575b0e3c4765335e778be730f55decab94424099b482cfc29def59c8a7dd88d6799a77390c2fa3af9a6d7d60461a26be36525d32ea93333af46bcd989f50878685f61081e87d42ef12d8c8572eac67ec459d29fdcb1c19ce4429163f726b4d86de1cea274d0084dad4b33d7b1c09541fc568b5444593207912ee3023feffecf97234473aba21b7232e6a497f003be931e5542ab8932dbb9450515ce2daee75b64cdc541981cc18baf1dfeedb6d3c76b00d84f9aaefab307b02334e24f24124432ba8ca8d32b6a51e62bcdaf707689bf170571f2e647c8e020d5a7b0584127a37f91bd0577dee6cd8ce19ca30d65a629937811977d423b849c5be4b3871194d13d1c0030bffd4091944b0a488022c9de8898e1aef743643b1f9913d2c2ab610e470fc6bb314b7a80763ed6ee8f8a585721fb1405f6d0c6472c96c81ed766bd466729178dbd1808002445f9ada8057f9a205ff6d03c2abc99b34f9afec32d14342f6343a02656981d58fb747a3b75b15ad7eb40ddf5d366e548869d231f900e85fd774feafe173e23977d2211692c3a9b67112808758cb1c5a6003548a0d1dfca9781e5a9086e9c53be47ae49a18d2bd0ca12306c2ace63d73dc5b9c2948992d06b900df6206930ba312049a632877b351eb4d9846f5de4c543aea061be8bc207885324a38547e7f3d59349d1ec99162d72b78372230daf2a88bd5458272240a729c737d4da7e4779e26221f1b77df5a7cec0b8b205dbff86f71732eab9423b990f2900a7f1d7420bcc7ad82fed3c1b131fac61c6aff72897c9d01cbc8e3e298a00e480e129cc344a236a38bc6e2616df6abae7c1523bc294e4853441792d57728aa18e234c195082b140f8b73d751f18e209a04b2d246df6e50e78c19e752146d54174a780414bfcd8ac2722d1b642df67df3126720a5e47f9f3749f790db51967dd570d05a50559f8f2308532720ed24d2da0840cdf964b575daf006cb5ed43f0f4d53c03f0962c7ee926d6dc18308d79b6956489fa64f7ecf84e123eeecd35f91fe55b3d8a62828db98ac44a27d72186deeee284d268d951fb1a5413bba5d9885737b54b19fb039a29b2e493bd6177cb8b8b6cffb5d130b4c9653f1ee3046de38b05db5966be41298d0179713bd666bdc720a4892d6656f8abf3d8b0f072d070649f09080f687f63c1ed34b7384c3e6b0bf6c18807109f1cf2fa67f3bef9d16c1ea1c6bff3498f6492b1267170f56c789b957ae4561f3d123af3600beafe857d945e7c8433463dc1e965b03ae85109ce253d331dfa4e3332bbf5d443c29d1936e7fd37c0bf41226c40c0d4c3f8d923f16cb9c57db5f1ebdcefcade110f8b40406d8e4f63d89b86ef0a199d8e21b224d3394322833c95ce1c12c20c08dfe018b4c1e5dd42c29f953a1f6734af19240f4632d01bd12c897ab7af67a58e7f75430a8a4fe6ecab10b4e8bf556e4c82f1bbfbf875fb5986293f516c9fecc4cec5bc439ebfd7e16eb935f111e5eb20012fd5b9f0f9033421c1b6836560065d44084758f3bebf9a3db94e3922fd9a1e4d3fe7f334225864bb23f7b9a8597bc0e627669a8e7a748c09b83ee7b26b630eebf43485b984f6fd7865ce6359f7623d119bf6e645d34e58e2fc7dfc1c1d4baf8c543a57ead500ce6d6a38657585975d34cdd9bfea4ea6b2b46243545f914f8f08d8c1e1e15d3b0a6884813e0947ce2a3a53c628b9fe87e509a0150f32cbe9d2e8b056c2429538326e4bfb499ddc79dbc203f1fff4492d53b02eeb9320ef3195dd7994e1f8c1f293c23a76a3fb13fce83dab58ec091e667b16cc1c557abfba1adbc852abdb1960476099d3b01adadcb883c1023492aae49404338730b75e4834e12c3a3573219da09d93a296ae4f6b7f5b127dcd245cf2549c714a24ba6f411373e1ed0be7516296514a96c6ee3c3ef0a4de11b38ba7c6cf9af282cc9c45b69803e45252a35c5c4cc950bdb4b1764a371a103a0454c7d43a1f60a2ae90b246f9023a2b642382bed9b0c17342974c85778f0fc67fe577bf8d1f944fb70d7fdbc589547c5ca4221772a83e7636c87e29b9445d1186e9b8ad585f1df53b2c92f788251689fe36e5564806ee450c36f1280720d6147c027f2fcc715ebc7ddacd1a016730b03f637d519b31a17d691d0470eae8bd36f944f21317e1bd2cf1c27a8b00bd7b9040b88341dcab28c085564b7a37b6f9e9faa9416db9d1e45f25056c49b8f81520f0382ba1ff8b564f2b0163221e13b54bbdb745c8081cbf9d5a6d94961862696e973f84a009a309e5b6c4dde339dca1df35a2d7d09273e32b59fab9863c03685cbd98454817f395cb899b8e4a0650990d3bd7585807853f12c26e50e1d04168efe08843b49fe8331c15fcb0b7df197be691182aab05bd0de73f9b45fe874654213e93079b68b5515a7db956066df092ecbdb50856aa976e3434e7e0c6f93b478202574555744ad7a67412f8205e6fb1fa7001d2b8a78fdfd01455303b797b450d895829a4d5a2ba62b02a1699a8853e8ceff64576084917b0b9bd90a708d8c22a469a245c03c9c4e8b4d608535eec1c0a8d28c9d379f8908c7a87c2e3792c55a697ceaa1530f66e05aacb55abd2c5e8c4ece658bcbc22a63e6378c3b129887dca929ae39155d9d2a9085ecd049f5514f8eaee2a50215fd10ad34070b4698b316dc88a65f651acaa023288aaf4644f456c886a896ad93a369334ca22e6370f1ed929d48417e0aad3612bc022e0ffb52a21d1fde6602e1f59da088ee4558519551150a59fb4baa4c05bc67222bea465a8cda8e81f897d27dd35dc091c96972e69f0e0744932bfa36816796d83262378ba47ceb4e25915c68eb21d1d56840d6fccc3c681035d0a16d31e1581e10ac338f0db408aa5b29fd4b0ad1b31536c5a0995a976bb165d6ac0f90be033ba95716b36a7482315a9cc79e97827b1abc28dd232c2156f70c4d1a3f1e7b18b5ed02ebffaf7073bb015020725a9e26fd291d43a3a18f2800f2e61b1f38e9b76f9f062a093674dc951eea14732d2d2ac93fe0ebbf79f5882a7aca7ba57e0290a1ff0a15c5a1cacaa78d6b2a56bae3b79a1becf7f837d8e4cf9ab559e08fd3c8ec1f34e48ff4376525defefbf46a85f2325c913adedc433e2e7a4078bc5e2fe9d90b6f62f781a914127744444b7ba0bd67e38b03f38eb4c50fd659e75f6c0983368ffece99a2392fc42e23e8f3b173d7922ef3c1eace06bb8748c0aa13adfc19b2953e196aab2b7834dfdd04f0520c03550bcf6df4ff5bdfb7ce30adbb27adfa0ccd0e1d6895745a21682d5fbe0ad39f5689ececa7d1bdfc8c1b1adb9286a6f0e9793671841244b76e723e94216e9a4ee6f8d2f42843eadcddf36912504bde40e683a38cbf970af2d4183f1c78f49d92b364324dc35b0c75c8cc00bcd02b8f818ec91e1f89df735f933e4ff81fd7c2cdbafdbdfefcb6d2467b0b5910aaa84a051780cbddf3d5fd52910d31be47256e5be39e40fbac5965af40d199210a9f1b7e81ce6c47a4f3b6427ded880db6007a2bedcf66b1ba6a7710dfcd079f5176a00fccc25b12c2a66c371a271710c3dc70cef254c0c341daccc062dc7800570be1c12b082bd63d4c1f2ad7cdb1f08b5a30e1b8973ff18040cbf1320f0d0e95b564fcc94dd68d97a455e464e69c1062b85679623266e3183c94e06eabfc4332d634e727a0038e59109ba347ddee28c068d74134992420d2caacc2c1bb8cf0d8f14dcf8c930d851b08ef59fd13e3ca3c2466cd912a0091d2bceae98f102f065a8566b5068b2b1f5da2edc7406d58ef240f780b45448d432d8c780d68f6d3e0b11a2c07fd6859804c8e28ad5342c666102510082c025e0238991920be52b21a3356aca954bd6eb9e39318701395325c5930271206a7b6871de2a5c37037e45e07ad5c55624f14416063c160012a0817da1134829299e3e370e3181a17c6054ffc56ccf902c36a8dae8d5c0fb6e9ce87d395963012805995e43275268ea440accf2617620e7f14573de637b27ecfd117cc1e1541bc859cbab0158238c5b54da9561aaba7d1875a62264b7650de83b32e588c3f0d0716acb3a1ce6e6cae2a080bbbd4b3e5b3609234c41de6681ccf7f04eef61c9030cb22f65473feb7fc878a5f7fd83475dd2f4b3ed77815ac595867cdcf9a9060b71672024ae3609cadd62d5cdc24483325c58e1ad90f42f012adeb74eacdc1e8021c7470fbf122618bad4c88876ecabe808d531a85de449a8271581be4de728f73f02db9adc53e64d674b90ad61994a4dc4eb16d5e3eb8c20e997247413a366156a7a4edafe662c3c3c0801fca05799c4f878301ab0e9c9fa6cd40b3e092b26788189c625e59e2f69273501502c1a886cb454180812a93f269addf13657a67e282b59e06c27a0618c129497386c99379edd48c6b8a8a8ffbe982ed66f201184e1fa0d8141168211ef4568c4c4720404c893fffe02f92879edc8ceca3bcc7fb6bd62cc4368fd2aeeee7f88f248694e8e7afc4a5c0f5bf8d61625ed227a1b1a0b9e9358b1dcf92f2138fd483127ea5046888b389201555cee98439f08df19745a69e9792057a21b1f4e75e447569916d1301505644f0a8510e970fcf3427cf22ce6f28471d88cd6bce768ca7f4d0d449316b9581221ba501aa5d9fb58fe4d84bb068c8f5f20af2e6fe3c0a3046199a5ec2ef5d6486d7355a76cb5f8790b3415c0931ca7b32ca065e36174280a6ce2ddc919951a7464ac6a4db61ff61de1f8e6c89eb23ded61bf7ddcd32a4fc7db45d0d9891684cb414f759961ad5a41ad3bb14186261fced6feda0479b05bd99a78d639a3066df1f5b08dbeb0c9c27da8f7744e3d98b9d4082b17b10a5f0593119e0cc63c3cb48e253636ee70b3a84faf0876ef0b387670e641b5fd2577fe838c920e2e9b9cb98ac698c832c9fd54f5fef3fff77c06c41cd73346751d4a7c70fe5a4e41a05cbf9bf8fa4edebe16a52c4c11b2416d30537691bfeac03b28c85341cff57c7fdb21bb1858d14aea4e4a0ebd69f1df88770e2dcfa40450ecf8fa3951eebbfec871d043295c0173ce751af4e0650e9842a69f58b0a1a0a1e795cace27e05a821cf4dcef531d31d0ad20f14c75352f6c4e1af3d57ad52fd4f57d52992e2ca6bedf1a7d7a8e97ce59fccfc40976264c844f881b0cfa9c107f351ef2968e53f8c84ec5db6e40adce48a63ea09bcdced80cdd57427f643e15e8f862bb02adf726031fa2653ddfa1a30f9af08abff25da4b45bb8a122dd3cde29cdbe1f6b0c24b32a94fe483420c91e8c130fffcef401fe8f9ef0451036638f6650a337da5bf11d1237f8216be2b09f3c233672c1f87a57ee27fbccd3e828b72172c5f2872dc487665538c96e1dd72ff394598f69e5896dd3b81946ccbd295032d9815f83a0d026cab3c541a1594bdd3e7818b743047817e7dc11d50b0d01751be0525324fe270d7e917acb042f3a35ccdcf27b9497a9a4218908c3ba264e88b02cd43e6b8938f3c13f03b02047125f5f327d0c6e2125eef895aa3d7e66013556a4c56cf3494f20a5a6160048de5ff8e33f605367c062c23f17ce7f489e6d517ece617e1883cac7730f69baba2760b71484a2723a5cf6aedbe68a33ddc3ef7791279d16b785e094d6ffbedb998f54fc060699a373c7dedaeccbaff5c696ee854b6556e04505bfa761079b2c0cad0ab2cafbac49774a7050348adce7584e07df446ee95aa46ef26a6138641b099895f97c90120d3320d098259e62c2ece5025322272071f92a95161fccba3b73d18f0485d3ac91bec90df3b30dbfa6410bf50aa7e74364bc4f71797cfbc681886eaa0621159c0707262a705c8f42cbbd165fe83d4aa3ef8686dc3a603e7c4d192587fa809a7c19cedf30cb51ee58875b508918bc411dc98ff163c9d7ab2f12403f440f876fc5d14ae2cb624a2e7f11c15fa9f49105af3694bc88fe1b3e49997df81e58fb997d339fbbad324e626a583282279cdb5daf409bbeccbc080f91cfb4c576722fed3bf574d918f7846d857245fc73457e6532a1cf991f0c9a41429c3cd33696396a092f4f5aa84ee710d89e9020cc064c670ec4186b427f2c1e6cb6555d4822578236e48d70ac0ac04ef7bdd330ace409a38843ea2e4ace31979df7eba9fc74c35c149c7c6a88b357b92c1b75d59d512013741b45969c54bfefb89f7cff1c35d858f0f1c2a2519b46e33937f56263f6b9ea349760dadf7993966e557cde75b29ee0cfba9d3d7bdc41aa9cf9541695808b3c7833d3aab16352fd8b749e9bd5c457edbac0f92d4cf71a8d96b47682a78edaa0d467ebb9f355e6ba5e65f9c7ae668e30b29dd089ded68f6b2df10fbbe472617596fdda6c8e00e664348a25d8ae7cc4af4c7fb7ff7368f3b1ec0cce33201ad74a300c39067802f3a7669db71d875bc3afe73d429f74eb2cde3d2029fc82e867610dcb487ad1df03d3a876e38c496bed99c4bfb9eb321ee7ca7c8590839b66fc3a4ec78c335bd79153afc23b0a0978f052beb25d714aa11caacf44d80d0b8b97741b5bb84406b7a69c8d57acb06f0f064f9aecc4de8a2c2b95f1d8b8b508e9da3ef637028582f5baa7411be43cd8b143887693c4d2b0c7ca28b3efbf27bcbdcf19be83a27921ad519a6e411e9970957d04374d9d60f8f65774d1a760a9c1eef61ae07a425e66ca735c7cd0ba663982e23600c8f8e287586cd41f1a886d5c21b03a283976332da9781a3ff87885cd539b0077701406a6d62e6515da9e2a048491f05c48a49f0d0436c6a10b36708bcfe0e2df91f851d7343b05ead9dcceefab81dc74432b84687ffcade5b3a5d3ba8744fa58d2fdcb4a366191ad292ae840b9a71855db2c1c3fc2a88ca0cffbcf11cc12ff71192b37b5ac15cb02a1b8247516c52ec9e7e1a0bb82aea480619518057c8ac85799c60c7ac8fd8ec3eb611a467c273ecd9108a56d6029db0420107618de084edc93d09c83b6232f5434949898ae9f826433eb3fbbed52b1509bb48cc084c5acad143b0d62c03953bb0f0a17b7e5f7e7c63e538cb505172b98fff2e166ceb5fcc525a9866879c87dae3be5ab65e3d8d5779da23cabe64ccdeec47d382475412552e0541d460bb19a65a2356f27acc394d441341416ffbf8572018183ac46cd1280022115bb1d51b776c61e005559738821c67226b73beccbdd4b6ef9eaa10df43f76d1d4489c59eac32c2c6977ef2157f84ff7a1d719fb681090cac6702e9d914d36aa8d6b5f0cd2e6378bd83d943bbe8376575b3cd78a7ff63b4424e9a1f7ae415048ecb6202aeb020011108fbebde7cf001c03300ca0135a56044f35a84502ad4e68082de90e6006ef0f5e8f0d1e6480d4025696375cc8dc4e9fed3799e21edd5138d627152ccf01e411dca1f8a83deac5df4ae736aedeb315b8cff43add3ebc97408300ef9c59d20277f77a5b023b79f6979c1f13f8090f613de7b6869cf0366d9cc7fa621b1ea57a83fd090ef76c3daea76c43dea3c9f91b78f84da99882f6db30dc984856055eabcc486a2a92919bf9c9e261a2ae020f53d35c8397e8b5d7fc5d3534f5aa68ce4de91dc068d8fee3898c95bf568b4eb06445d9e806805570ddf189d08211827e90559cb7d4d2dd2b9ed79a2363cc42c151f3077a339b3e2b5512316f6f3e4a30921af1d37ef4c42e1b9888b700fba6ebd4c7483dcbd6ff67fd50fecce49f1158149a069dbf459618efb2d401fa8109bc8a305dae68341ecd47146d2345df8f70dade6e8ac94f78d7b746e660a1f93fc6bd68b288970c507fec3cf080a66f8b7e45ce19bb579a6cd4ecbf97976770074c45be6f7b3c9fd32caff7bca21d921ea418cf19fecfd45d2ec28f8dd8bf4a4485e4e16f07635cc1ff84a0a0baf69aff2f6df0e27aaa28e13add852b72f69979171b47ecc62669807c24689ef34caa5e960c56b802be3338cd6f81b781918f17d670d4ed66358fcc0bf4341f8ac9327f340e67e400886ef9ba03330546d586b71068bcd17241d7270886caecdd8db48b953c1a2a9d4e25bc696684801413a57993883018f478c4838160f4b193bbb62b401cc4f9b35e8388aace39f82be8a9cd704033a7c68c657bb1034802ec60969e1c3f11963c37473c68a6eff74dbddb4e5bcd8bcd8b00f8b0f0e4b8feacbcf7b51bc5ab13675e636dfaacd39606b38f1c24cae8765a027b26dd44da7ef872c20bd0d36e8559f372c6dce3ad666c805258f92336b79cbd96340710e6b1916d0f391804c9846b8860eace1a39cde73784533ccddc1be5700c608f21165eff24fcafe7069f08fdaa371fa84508bc1ce1d89c1c2beeed807e77603e7716dd0cc9824d07c00c829d82eb0da413666f2e1b0eca2ec4ae1a36c2dc6672f0b2ef442e5c0b18ffaa917fdc17d56ceb3512cca352d659dbf9b8629d292cc1a7a630c2648b0998e1b3c3b9bc169a521a614138d89f579f4e7c2714a4f57f57e38730707ef9516f753130d44403af3a277cf413dc3f762aeadb0c918fb1896acfb4c189cec9c36b4671d8803c5be4f1cc12d1c6983e95d8f10509c1f9a61b491ae689195987e856931eb384db3e9688029d3229f7fdb2f27e092a098805cb6e1a2323a63ff6c58f370fbcaac70a1daaadde1c5bc1eb3feb0fd6e68e44fa0280a9897cda9798235bc188622bddeaa401af18f60e2e9525250db8c7e56dc54cf00f4abdbb9a71e00cec93505a1285fdbbc5187567f5acfd81e5cf8173532db56da124a29938b7a60aff8fed7f4bdff67148cb38c6ce416e21c36d0398a1455cd037f537fcae49fa79de829905732728bb1ce510cefc1cd6cb389fb3e35627ad3767e89c03bd2ab8da14c69f08d76e7ce7bb97d941dfdef5061746b857d9993f835f9e96075ef911d65d05cd3cd09419c0f2efb7d9f05ee94528b1cf6006f30158e70a751bac1fc0e9c60c03c231ca8f8f24e438d3a3f3e2b39e6795a452b6d870c0b1f114ed9f5c61c267c4a377600b301b50cd29d29c585b386f9f7439b375e6876d44814710c1e2961aea3e2d23f6bee6077d02b6494e67003cde03953666a98f259340f20c7bbda9d183eca7e0eccba974474b59f00fda4dc586bdf7c3f330fa1a60464adcf296a057e58d090a406253483762ffc07996fb9ac58672030d46deea411067d60afa0aa30082949d64497def516a58d0e490c5cbc86f11d3042938f47f85cbc7ab6fbdffb418fef709f5e52a25cd0ebc5552b1ee1fbc81d0dc764b3f87d06b02e49043395e7ce3fd95393038f3334b41dc55e0ccd7cbcd4d9af5932f58ca0c3ef9d34a670956596bfc06fa066b0a1f2514c4d2f8c228a17c7ae2001c967b200d1ad2dd1f96cffa2edd21836bb2d4a7effba7c99557e14e589f79d6679eca9682f1ad1d2a502b85e6a682f3baaf030bc79814dd5cfb23a65a6cf76895f992fbd935f4d3832a668799d9c55ff087c8f07cb4faa8446f164ba5868164d647f95818287bc120077f3704d6a92257ab6947f809c13bf407ea1f26423f41dd980630610e391b6463c8076c1474e267688f1dd068b5a8563bf7b465d39d8ec1ff8f3a04e0ffdb4fe1612ade3cf00abd10010af1570a6c690eefbfaf256ee7fe32d5c6489f9796bdc46ef0d5cbe7728e204a234d273060f61c74b0219cbe5f3d8da244412230276db2585e4839d71f58c2d0ae270c02b9503a1ddd54aded0afb711f866c0f46a4e62f184104eafa95e47872f3b482b3d35beb1f62fb1a83d35440b05395d0bed173b63fbe4b554f8ae7dedfaf9b0c4a415520446e8a6d93b55ec9c418a45dcc9ac5850b2105d813b8cb335e6419e2b2e1b70cb20c928cafe61c73da6d28ac82316c43db0cb004c52a833b51e6fac2a23c4f88ec53fbe0a4ad71e6e6729aad5070fdc393ed6058b627b4b42f407c07ecf72ab91c237b6345136849661a57ae89b3ca933c68dcb8c5bd0a549ed900c49c0086bd60c3ab7f5379ff5df1148f98e64ae1ad1c24cf0e6fae5ffd9eb852a718df05ee56dac13c675092d7c664d98641c83d45c39c913f9b063670b5dcc9c5adda2103bca43e3b2e36db3d3034056e672c5fd5325e193acd69dc82c58b366769484d6fc2efefa31733418de6b12c725d15277a975623540f84d409405441ceb02a3f84108e8b17712871e22c16243300b42462384f391027f3e03955f4cfd2dcdbad39464a647a90755dcca10644858434f2a12fba3855200a6d8ddee54fe960e70195f3b20f5107e4a1be91eb88f996167dc6e232031b7bcbc85aea537d5907c2c2ac0fb13037b96baae283f6e3577dec72e23adf2de724ac59f52d44ecddc1b6fdac900cfa7528c8371e88296364d2a02c585638f1c759d942493072717e875bd3accd7c5b431045a9ea9900b9db2f06d2a04bda0088f73817ed04b7be29370439d2da35708e2898bc5d1e8434a8b4b012d971087269393e6fd0945ba1ebcd4c687c8ca50eed0767707f7c8b979ec26d2eb1f05620381cc40c537248f49b2785f133cb86d397b8257640dffc276e9462cfd1dd4233f7a95cf01293460543bbb6342ae6c798b95c94838a0bf01ea961453bb899edb63f59e6aaccaadcd2bc98bc9fb30166786921e809f45be7fdded8f031efaf70caa77b06b6882868ae0474c4ffdf190f3b364e3ac4a6fd9f9c1bc2274bd7232c10e004bc03247390412130923c92e5c3dbbd13cd8f8d4598ea616448e8dd4f8195027c241ad34a23ce720e740fd702af0cab783832304b91f2c2ddd14d68cb07c56eb1384768cdf40fc68b55a8eda7e4c05d89475419402b1c3faa212fcb3dcaf9705f55717b88629d5bc7dc7ec3b4b82a734fb62eae974ea7ec1e939372d3fd6843bf3ae60c6fddcc7953a769f7c28766dd1a9039caa2b6fbc75d40b75d87c5c1fb91bbdb8db5000978ce03f7c78aea767600cdc74ea6ae8bb8899979a6b513ef5add17b2c4aef417bf8ef80527fb0cccfd8173f562c66603f99857a2d572bf5b38b7615900ff334b8c9f717c05a30a041b31bfacb9008957f44679bdf2e8de7a12c28739e0114fd40ba21db041860f5686f40a2817b86984f6095d4c63e513550fe0610ea3be5880c43d8c48740ec34b0389a0aa9507f10c7c5640a1e85c852ee202a3dc9546ea9531e90b25c14e3e0b16709497e9ecf5888ca573b30f9f4e5a4f4405fd47fd3a6cfe3410ce724d1baf3117a5b6c8ccee50aa282b8e1b745dfa940e07fc8a8af4d2107f3d808309822774a502a8c774d0ae71b19a077bd704211756babcda608e0d080da536d642428221ed66d949b4d390b44eecb73a7ddb30c66a11f7717f70800fbd11bda5db75cffd68c001d2e7b14fcbae6475142fb33ed76a699ae0c5c2ae54f8c2b25a125d1936e9d707b0c24dfbd62579750d0d1d3c0a92c991892c88caf91ee918e458fb27e1e2fe6b462c873d84e37983fb810cd76204e8d328759a1327456b38336c22e0f34b468807ca5fc79946337fafcb87b06ae8dd93f44bd37771d3eb805d997e9e66cffad20ec9390d31c7d9335c652fb9c195d8f7708b7d3c0f394f828e25f5a653f6ef00d3eac410f65523a9448c30b9f7c8a7752a078ea248be98036769a119fc97909180385d6dd0b431add4d463816ffbc5b72cc680d2b859491499cc680474ad490b7e030ad92e20bfa2003d6f2e5614304cbd4acff73a3565a6afc5e832f9c654a53c645eb08a7ef13a635d5402fc780ac0dc541f1c593a3ce01e5b09cf93d664215400d3fa3f153c44f47e50ef988c73b4abde12e46d3b7b9197b6353204f19d91a309444a528c9937361dbf0f4df64a1e2fbd65ee327cdf5a9bec94996d30700aa5ffb25d664569f736d85cedff8d52c01f623a3f08b6160a3c6ae77734a1a098aee24e2741c28e010788f0042dec0653dadf42e945ae4ad1a18a5b44eb0335deaab18c19d04060dc417ce632aec07f8c665d8c7f40cb0398b2ad685483051c50fd7c580003130af0f687528f83cad622f55ee82d20de0f0121d0eef55d3cf194d91c074fce47e1e9395e4741021b2218996ac9ff71d463a0f083d3a013d61fcc7eb3efb5f915caf4e7af380fa968448f2f00841d904ef2422db4794771c33aae3105f6c9c4176480313f6083cc9357d424af6e74cc213b8186314a3c6020ad52a825ce16027342e446f59e58c7055633d468e1c6d4d578af479390d9c4bb7707ff4cefe279125a3613fed160f8dcff7aa44776fcc6d3323e38842910ea3497af7e54884712f4fecdc356f63752ecb27aa6be4a6ec6380a2e659be18d4f68d4d9fed9e5a8789413c52171b4512be72c62b9d7ecffce452a63ce3dbb6ffe7274b4ac0732cd900e281cdcd95b5410f126a3f6b0bf1fac1661da073b5d55c5423b6f855ff562ce88c0e48b523dcae35f47ec573b5f4d9a168bd469eb9c5eacf9f6b05743ffc6d643082cccf52cc3a94a793a844fe40da8a768c240b82f78310b1a03c5bbf230ffe3646378690d4687e4f30fc06f5310a1027e570be311b8669987c9257ef5eb7e7bc6850fe0295315275e6a37aafa8b1e2e5f93dfb46dd10b43f4bbf9141b116275f01556668f6c3000d3456f49cec0d7fe65a1e113d5893f0848b0da91b3f1208608d0452362081c5dce062d3e7c303b0b40b26c67c1a64304e8e56e1b921f7557650bad38e59faa5c9d741ae8e1fbf504c067f8b1a4071169c77a23e610dee5d87e52e3f7f2cdc9889b928ef06e4e2a78a1785ce1c3d4fae09febdec70c1fde4bc45c1530a4d106cf83b7c7b31d8b7e1f318520ffab2d78b3a68d7f0d28721c373606be86b8ed81b8e7b0dc0b3d5e51bd3b9a10f1947e31ce1514c95753893f7dff997e8f1087993118763012ee3fbca81edb1d72c413a856f65eb13d7613b2be67efd60bee9022b52cbef3bfcfa3539c987d7232770f142df7bfc557b977dfc157cc3be421948cbd6c91fbff204404172481d9d8837f127e7b7da2eda72fb9fbc224b3f841aa948e2d07989b3035c12451be793239f192bd7718137cf4a065c5e3603687393704326dd4abce59986f9c74c59aa6524f6fb490549e8e9e9dec42894d4e5d7ec5de75a538d320461be86979a201264f33f251c39ed65ffa74c57f7bdc803f0fd7b09250c61be7796b41c5e17231fdd706fc5adab8eaca494cc5f06b205c105ea8fe923273db5bbdfea62c3babffe72e5f49b7939be7a9910c55c8e32dc7987ceaad2c40001d5d458728e6a3d676a4aef296d7c3c255ed79a7e56ac50e9c0a376210be388a8676e121a7bb7da61d5ef0c6fab88afed2bf02e33854c43e8f14f1b7811021777bef2cd3f5d965979040b6e09d9fe5501c1612892933f30d23d529de17ff9d4b4718b645eae623f96833ed5452c8ed039a50779bcc665439e7db8f59fbd1325b36fa741d0079c431c1c1db25530e8cba3a7ce0e1bf48776260e1425014cf9a86ae30fe6c5a3fd0144817d8066da3b393514d49d025afca0c356f3e2bebbf8599632b4df74e8e8c52350edc41cd72687ef939269764f6c45a45a3fdd73483778f22053a1d9fd82fcf549d308a201d8dd126347e405a63851cf5554dd6459b412b3e0abd19f9fc9bb42614f1ef7d328e919991d3dcbc8c62bf7971ac9c82ee101a7eaec4e40398b264f35109cab8514d18ec1add6e04f127ecbdb0e8f34014ea340b18302538d95b8a95566678bdfd03213b0138676c67693367012f0b520bb3113645b62502929a944445cb53b08d1915a850e0b18a2d05679cc5c2c80e6274b638d80bee3f1c67572ac9d4b3e6c6ea95606d4c3bb83ba1e4945c240f5a1913ec683e8e9cb4209e3108ebe46ad5b055274bba1752fc606c2bac2b0c6128ca910499571d3a0b6e4800e42404b5d8ce49128d14f5d402f7a25bf298bd6ded4f8cc1d17bbae658bb05a8b69d3fabc7ccf20e173e5b5fe41d3b55dee8ddccb15e65b40126fe786f84eb4b036acfb74311f884548179b0d88dd246306ee42df5ea5913dbac269594b8fe1a0d8f0c4a39cc402846ce941393a7e4e45b0e2173dc1495cbea2913c46467068f06516dafbc78653be054e8d772793582e80e5573e00339041e4788185530b4fa7747d1b236c25581ab3462a235f4c7ada43f5c032e1d63651a3c81bb45f3c7fdf2311e56fd6f2b2f5eba59daf453d338ef5024141ea92b94ae2e79043088880a099a45209e52dd812415c90debe3f1eaa2a3ee8accfd405b0c06c7057ac396f2f92381b338893405fd2b4be98a37a1a9d89c5df54c54e3e049c2b1f8a42af8a58f0cbc272d887e89816b21fbaf5898b8e2dddc58f0974c68f3248ed9f7bd30b566b478d5a96f127eee13c13b787673953e0713a76005fcaf35ea7d3da343da225496a3634f65c6b6a4c8b8a393c9425af20fed69df27f6650ceb5040cff7d997c3d7e722792722472af730b8f55791ee78de29414a1deeea4462be62f9022771d1c61d30739f6db1bd0ef78f0aba2db2131d4714f7f1760a5193b1ea823aba146ebbd1f88d43f90471e5278526966f79bf03a676a11839f4a83cd80eee6c2604723eeb1b4d4b95538c6fa0067993d4bf8d0e6168c414112698bd7b3a35ec98144f245a99aa827d9121c92745ed7ae8b61475f5dcf69bd21ca4bc90c0038b53d5d2bcac6dc8225a182c671c7a3efec9b7e1387aa14f56bc9561feb09a804797f08a42dee6dbb652e90878330701cab614b1efecc9a69204ab859be2826aacd9a27d579634ab888333cfd319354c7f58c6856b583c536a5f09638506b864146241246f2dcc884cb61fe0463229d78f6f0af3857d09c022a59f30b4beeaecccc0bff4f6663a0e48d7dedcc8ead42ec383557f91d86f1e08b3d42fe10605b22e0c7280c69c4ae670eb61c3cc5e7f6f15c5f9f03a07a71ae2511c7cbe54675926f6b96c06b1f8aed70724122b720203d6b18c6af7442ac29f87d33b666743521c1bf3fd36b5d0ff730aea22e5d664280116832f8e16fd4096f24ff6624571cce426066098d5af78d06da04050bca5b4a060faa42e0bd156557f1600ad9978f52c3cd8e4a879910e7c320b971e61b755a2b930f2f150d9f548377769808a5afee0b2051a677b8b0d4d0daec9bbb78cdbc4d623bee1e224585077c7eeb458aceb118ce1bd49e43c2c578c11e2d0c6421f57380d496442893077cc7f0db3b5421d784c86c45f4ade46ff8a008467e4681126f6e4c912778e0d10f9b7dc4bbc4bbe4a0674b1dd0fc83705171cbd12a9f6467806d10a03b7c887c943237333891c99b03d6eeb0466d608ddc9ba7792cfcdf5062f06be7b6191a6572e1a8195aa1bea7abb550969534f05b369a4e882898b79accf58443d5e62c476898c2dcb768f4f348d6cb36b9aacef65658d2aa0a1297b734990108d0ff144c06ea1e9d3a7a79ed58fa3e1745da88a00b4adf3da41ed247e8d61dd98dff68352a157fae7efa20c175eec2344b088a00e030cd14225b4a4c4fee992c1fa7c64647977ae93e2474945178c9765a649f8f8549305e0196068661061032a37093f304c80e11d44eff503e3473bb1ced4d820253f109972ea4794bd0c6bc76410c1be9429d62d360b8ca2b525bb573c591988ca65452ba3b249a03c7d5199ebcc3ba3f79f0306841bdccc34623b5ec71737d06ae1ad642ec13ee393f4741a33a667dab704be3c037fd20a512b11862a897a33813738693e7920a2484f0294ec43eeda8812b5af0b4418387c53144cdc4d9198b803e933dbf23f6355e9d372589108e12f4e6c3c32155469f5eb601fe8537a67dbff3b3a24155ec66c103aa2979cd852421ecd6da2468c03729fe06b587d949835d7a8d5020d62144657cbe1e8db1162206f1790d898a8946f5535820074afc2ae6d3e81c7c7de63ab55ce460c56c2fd3bd29a366f3979e4c6c1910e9d9c9e4931240f6e8873a63c786aea91d678cd96e2d2400d72dab983c2da1170bdeda68bd359dc2f098479a449a62ac3799fdfc188afd96f8cb74f4edc6ee227c0152dae700c436082842c265fdbe48dd5d43f0e99e8b0ac4c6ac640ff3b931a5db2705a3a1f4ba6efb1a15c649eac8230930abae799eb8e2044df54f474a6165c47953d5e9a0dbdec4aba69671f15c776902794dc8557fa7513a33751b3dfb4499342edea0e97d422d196afac73e35e03dc38e2652961dc4dd1d46273574ca5c4b3d00f5b4c71ff7471e4626673f8cb59a27b9c6c8292c5606f7333a539b7eeca3a7ef2a938220315bfa5bb8f5b882723fb7ccfc19250b8391d431f4d1778dadfa3666e65db2bc5deae4a2e02e28f07aad2764d272efe0a6fdc3c0a3cf3808810eeffb207bbac00b5c0870a07283065e6fbdffd7f7fae1ef12cc9fc1eabbef49f286c28cb2cbb3025e866de0448b8454b7e744648750ca065e95579cc1ba156891bd3cd3e8059d2b861f9485e25c186263956337ce10619aaf48aec5e20a5a43524d1971b6200718c18f9a73b25e56ef73f3fceeaea66a0d3c22260f4886714feea12b51e23995dbdde924e184f8d5544a613e2bf43b1ee263a594f70ca88b33059a1d04df485e573b6f37bce6f62adae609afba7c489b67436e5cf91b6936cfe350441439e074e6a7acb27fcf33bb7bece54650d601d3f3f7fe6637504e5ea989001eeede4d6bb988ae749aebab31a933df7bcf6fe32f450b11b76813c2785ca84399329697a06aba3a4d5c69ce27d3985ed318e51908dec231aa343afca754caa305b714f8df450381e2e9ef5d8a11329228775d7cfa59c5b065f36fb4cbad2c0e7282e0db0891ff35367f512b39308b5d25f4804487e40dd9a00cfd71d9c3bccd5597287ec39405dead1d50d6904ee96629b0a3756f30af27d9ecaa8c937f99a1d70391834e10317d8e00e6cc09b4a253eca8fe42e68e1098d4ec9eca411e015aff630791ba73035858b2d043246f0139fe535fb1baf51180d553939dcc56ff930e39c2bcf6abe5ed7cb15b4c6a13fc95b0475ce69896fe20c6ad987d89e5562804f1abb452f2d9dcd16b5b7a87eaf54411ee2c48058d08073a67b21a935840adaf02496c1ca2c3b618c2432f4ae1bbd3e66b47a516281cba014abd6f58cdb590238beb88544b8c21c8b6b6a0cbccb34715fc85cda581604ac8822a1ed680ba9a5f922850f12b2a6e51ec2da7d557e14d729322db62739129624d114ea15c16027bd9248cd706d73b984cc59be405b25677b91f60d61c3aab7867078390c6a0c7165e6cf1cae47f9a68046ec85d10748fe4cacc3662f60397e856042c68f391de94d02cf0b62b2af4eff67bcef61dbfe0b62f061dfaf74ac383ac6713b4c1657abcdf52467fc4bb1b8bfdc25af84f6286864e1f695fc433d2d40d7adf5fe5f55572304c16a20eac4aa45ed8dc1410f65464b82d20b8587e0eb023324cc7709cd39bfef1f9458ce0a4127fb441ae3a7dcadb5c41e834e2c50b49297bab7df75aa39a17ae37d7441915c82783ad0d8fed51ff672f2c54e77b0da6200ed46cd4bf377248a505066426a17eac38ccafbbd40603a88e4a48bc596858dca7631d4aaa02fcc964f60c46a72e9a9f649e90926a4738292fd77f27696de0eece6ea6e89075843613fd5c5d2a413795c6b646eb9ad866303c9e953a89712ec529a41abd9d105cb0e77fd951a7257d5f668546204b2f128799dc7e662c73138deda8e5dc53358a67044e256092a5445f23be2e7c9dfd856439861cdbfc25c1993d861cc0aa05a2bd1e1a924407d85fbdac9d6eab266aa4082a751bcab26887d146e5ed381fae7f7cea4eef8c619138d470dc2c6faff92a762bc1d3465f041e1ff32e1611b303b2f4e49ebdb04744f8c96793e69ae0d27a915a4d966e7977d33af21b425132ad6743f6657d4cd6a786a7b902bfa01c038af536dbb3b7f0e5dd210b29b3b0d3364d57446d131de5510c0fad9987c8d6e0e1d81ed2a46128d778eca411b49539eb548024a13e7477d9a6f1a6cc3dd879f3cb2c89211594b0645fab966b05188b2d34a5319682b1dfe544a9453dbf4d31f6cdf9c4c2ecc27ffadba746cc892f7d2d2080ed858629abce0ef50d4771b8570b79ac764a3ba03b81436a25f4ff4a9b8bc928855c63fed5cd8679a68268751cddfd823cb78f65d74373b2a70334760bee2748c3d55a0a683e00f7f263924afb67dad80156710d28527310609baccd156f6c99629ebd3006aa8559f63448908188386caf629a05306aad3a0fdfc5135858413a3b296a1f1a75a70e1873618bb23f639d267a00c0363046d1d0f6391499d4d8f03503c4debc0e6225a40f20747ce70d8f2b00ce6cb04bec57233433ac958a570759f7c43842bd0c8ba9fa4e798d373331108f074f319f2b5f2771cea7907e9b5a8d4469b9f8966c2b803b47f080fcb5318abe4a0050d08941f0fbf5e0a20ca4cf4731f7263a1a8b7ed32281303242694f007e9846c5fb368421272e06a4af0da5c452f21f9c10acff627e0f106cf1328030aee69789010b87f1db4796e57f69118c9e062d80ad3f06d65c1b6729f6eef17017521956af10e77d6cd26985e5c00ddd29db6cafbb6669199dafb158af4e34b1a46736994323c3e2c09ae7f9340f955494e2758e5e1098967b15cbd9f46058f3ada060ee40d7191ff0930371c6c8d9fa95d593f07f1c5fe1612cb11d00d4b26d343b5fc63548d41007f961f1434dcbb0b6b9562e67deb7b13e40cfe5f2df99c26f7ea7882cf71bbd092c9022231e52feca39781e50e03c8e08e760ff9d9a8efd41f82637e7f93dcf41ffaa7276dc09a91f4ff23c0fe2c1ed4bb5b387ec18809fe5908b283064db48a392f60e03b7eea7f0e12a6dcb5c38689a8b24fcb7eea8407b8aa97afd455cc1a4b9ddfd30dde064cf35ccfef77e8034d494847b305d9598337baf0a386c909e182e67f75bc9f57c58398201a794c4817d3837b580fd4101767ab197e8484e8875ced2d2373bfc30c1a1081cfb74b6dc68046d9cd784d688894cc8d5113b9d1196afa6cb8a28df82361c53300a003000a001600d000202a00800316e91e0f0a564ffd00da939301c9295966a752d0822ff881f14a664ac5b74fdd6f1ad272e38b9576c0b4bcb3f4fa1715eb7f21ef2e4bd77cc0ec89d302fde0a587e1ff9cd07a11de95afdb1b9acdfccce99f743c7765aaad2061437e72fec1559fbf84997b9d05a31708f52d674c775fc479f78485597be3d64d87668f771ea4f2ea9ed6e36783b110b3134f1e12c4bee6e186aaddd9509c5ae859f7affc40c4161df2678c50a5f8a3b43b5586aaea1200dff9e224c42442a9edd96b1302e7ea5f1284ba70357eb185c25963fa94823fc17609e66266a5707ae96df9025570d34c88cc0fcaf6abaef588bded6f29d3f22e03b579db8e1aa0bb317896db3c237893a0323d9c7d69d6f232e807bff04590be0a8fbd74486dd8be2468966ef68ae1117ae4003cff53facbea2eb97aed4c0dcf57b225ed0c3356be957983021d41c14bba73a785a8ca7ab3fe8f0c3889fb2c7a1c96cddced5e6040f2bedcfe41e98442a4683cd01550f49939b4048b432009d36ae8b4997b2bc783546bbc569d8ce64c761937b151fac08ca1a091da6e21a3ea69940c891facb6d6e7ecde2b55a439a56290e2efe33ad89a10dfc97197486f74e900861d0caa6e747a47f9224d33b9d6492d87f4bc42ffd9759247add2f39080e72e8e01ec567dbf83b708d59a351ebec73433a1a19b79e3f3662f3b8ba729afc4a57007e80f044bc4349a880616e71f1c16002b6eb08f9f01a61793b8c133e1f72f1195f30a8a7db4c037cdd850fa1f5014edbb0331863d1692d65bb4039d29d812373d4896f70420bc6a3744cb43d0aa2d5f4f643997ad4fd98cf81081545c2cbfbe90635dae8e75eef2b695d77578390b350fa1fa4b64f226b4be7c54b066db735e4bb027b6e95900091be946d33e0f37ce0337a01e0b001e202d80c8e6bd3d47d89f7585f0b668d5fcdb66a48c0ec63a76ed0766d576f695e1aa12725a40ba549b1bca02a5a9db5038407ecbfa2f05aa8e62f37bbec4ba2c60b43b29d5c3fed2c8ed617cd6165afb60f3696f04baa98647eed8efbb8687523deb0abbb48a85fc20047d12f629d84826dae0a30c7bbcb3bf3787d186d86d9c518718dfcb49cba91be9ce48fda10fec5a78d40037fc7078a23c59e32c8f5cdea85e02e24d989370ff2070ca087a1617fc81867bf855c986b26163deca5bc745f4a25295a061db6d4819d8047cd5545dc66e67ecc24af55fd00deca200ff46dd0c43aa9383ca05e924dff743af420182621c34a3b465cb7b5557d3cef8caa1a8827b1795c1267ada3f2f37a0ec884daccdeb1ee61d61edeb3677d2ebe59f502e99ce9ae652883786c1fe657887824aed13fa852c1e0ee5c4706d583a0d884b1b2ee26a030eb44e9863b5375823f4c12b980dae77dd7c448a0228aea726f4e5a8e11759554f8e6f72e7592acd47a1620dc3883d4af230ca975ca87f03ea13a7569f4aa63687eac28d6dcf83966a546487797c452aaf7d9915a649d01f690bafd8d8558566bad9abfed313e293023d1490207ce971d6d85742566568e1f08a802d70f4f2070acd5e2e8f691b955fce22b59fe94d49bf9817a29c58c74b91a16c5ee50ce7bcff5dd5be05bf250698626f290b9d943fe319d563bdfc712fab57ea2aac38ad57236ccfedc378eae9046b09527d02b5aa5ce8ea38b6b3586e6efa2d7224ab0de5b2f36cdc05d3bf5e6f9ad6921d1671918b8653033828fea71a9bdd92a4175f42c9f634055cc4a89d950e6809350dfe8940b137b3c832672ad4e5664f9ce7213e3848e3f7d5ee88be2e9fc17aed09feda48a3a3a1dc94c9ca45ba0e500f9dbe231e90bec78f91b89336eaf70a90adcca493b67b44c37f8fd6a7f21afd06d6164c8e8af28c726460fd46ef795727b8fb030e5230ba72312dd9abf5ffa5099c1d3d156e1ff43ee649857417fd628c53ee78aa6b8f7fe23fba21da1bebaeaf183803f4dbc7e4cbd9ac0f34a9fc1aa37ea20bf8e78348beadc665d08a469d3d40ed5c307a17140c418ece6fcfb70aa1e43feec6a49762c3504c7769f27679e5fc682a5ecc6749acc043fda3674956f67f1eedaf65b29da8bc899db6d48decb44278c3c0fe17de1b663f4dec396d5d5d1fd352ffdd5426bd2cfd4fe38a026c32314c11deaad8548ab284a6c20abc53952dff633f99fc6163e15778f72314984d5417106034b0a671ceca2ce9a2dba12559014c2039c19c399cc55a4849ab99c565b14b74c0564d2c49f04b910054af2c500516ec8f22538f1456e06a3f88e7ad5f3675bd422fefc03405d594171ed4f9684958f092a8d16c987c84c3862b900a46b92444dfcc108ea44e249a6568dd0b4567ea70f375a5d98c25f4b9ed900bd76eccaebd9c376ea35bd0e073ffb2b7260509f3fbdaa26dfc1c1ca92c0b6f581078d86ada9f1a539a5f36e7f587534fd73078eef37bcc1baa69253fc724d6336c7e261369ba076b2930f708615e32e6e52ee8258a0390d242506cb011c85766f1111b00eeb07a6900b9c6b44f1eed594386cc0301d223a919cec928f18de709dc7906cc6cd4ddda0bafc40e6147381413d96932e97f607c9067754bf0ba9578bb21363e445626ded6c67766f33deae67cdcdc97571deb4eaf1901deeb8f8460ce4e1830b6bd58035c1869862e5e3a55ae10387e61541eaea8d4d6b861e3d4d4b8aadaff30ced160074544f941648e41b72c165d3160538113e7d031de33d89c4aac68c714c13b32c5ac1a8673028090762cc6bb893853f5e2c5dfa13e9ecdd6cf990fad7067c60194b585a11a5e68a767bc8e2c0f0da692d2703e6bf1044a329210dc9335291db43d619a9f94589665dfaf5b59adfefe88004575dc67276a00cd40574ce6c608f0b963d53801030f0323bbef84767988951bf0075d5ae995f86c8affe0bc9898e33bf4496d10e00528e30d669095d0c0bb68ce281ff04fb968bdb2263e8458ed215dc3bb682c916b70531fc9c1e0c157859f4f8bfe18d65ca7676299d2a06a3aeb1e9829a67c904902eca0183f5aaacb1a14ee40898651aab968ef6b3a3a94a6b3e86b8ba60318c08721993225d72840d7e651f5f014d87d6d96e3817a3f9cf899a8a6f40fb39287c8802825df1d0e0cee488399646f1f78a266c8226a73111a6d60b32de2cbf0cba142a640496f90a72b44df20bb41a179ad6011af9bfad62f4f5681104eb31393280558fed38752617d6d43eb2b7a02eb3f50261f4262225a1c49b4bf6ff3f6ebd6abf3457862c8369ed1506f1715d2a901c633af4cf378f757747ed57ddf2c17c445b910d7f6cbf789cb609754c21beedc871aa5ded75ab19f994949d93d06b880788353d908854c21f7607480384b0878fe0d2d4bccfb9ac9d7f65d318f71d4524aa5adc74b49306d200cea4952d60af73b817151bb5119effb0c3bf9429b77c11b19087e89165a951b743e7a9688a7c5a04d813d414c90c78dbdc0425c0bfe9f1293052ae88df1b9a60bab5f7b883ba0c312e234eb026fc0c9869898d982a3ffb2a98da8be4b5308e94e1cf72938a5a7ca0034cf14833731a4959cd18aabb95177cf4c8a092609044b4dd5ccbd49760b6aac03edb8379d53283e0e47e5719b7596db74f6d946d72a6b2b523ad5162aab117132d50ba338c69be3ef4a1f62f50702c18eb62971b8fe5a746beec7b0582c8c127ae69b07f7e6a1f8f4621fb8c1b43b0d157d47f948c1a7b1250c776649ccc9b3310f26110ace85c76a04db80604b6dd06e40000bb691e6a3890966dc50301df01ef9b2c3d2fc4f419f7d72d711bfb9d68963a972859b7972e1a0db3e392b576ca6e23147a232284ecd9494a75bd0e3cdccf63bfc7bec32404e22524557ac751b2dc6aa33cc3929397ec75a8d290c2e0a82527eac5b62c43e3b384ce3eb5dfebeaf86b55fd457161df2004d4c8419a4b3d24becc1f17aa2e288db63b55a96b3416d4a3b2bfc9a6c6bb8c7c1f1cc0a94273161888d07a91227387c33d240b17fb27c8a8071ade1f11b4073e6e869efe27347e52aef54cd3d482767a30b846f6863c0ce6d6c026d835300db594635392134032552511f85b82150d57ab3ceb49c803916248c1ac1cff59c1cc29504c1017d1d7b6789eb8858c545c2f43f8493a4bfd3d9ee9894a5d6cf8e5400f8f97a69414e680891cb32823e8113adb154ad77f02ec3174456121aeb04d15046018c376791155f2e45f02f1c3aedcdb5dc9d3582a3487ccd9a4cc71ed0e22b41079b1b70cc380e5f47cd0d2e627368287346d0efc433084183be92fef49e0cfea93d7ad341f119dd2feec3d19156250b7a31133e812511f34dd00019c5205934c22527f2ada2e0f99d875e3a90a0ca489fa42ccbd732aa3c99939183dc541223fd1839c6601ef004f51495ce73e86b17cd991086d7969f2b2768c1bd5d72c79476d491067443438ec60548737cf538081a99ca9338353b5600db9d4a3ec8b9d0c568965908e8d44f3467aaf654f592c9b10ed32b65e690172fe34828afe285e994f115291396530f30c82e8c283dd8a8f1b60427a928fa3a756c19a676a519c079f0a573d58551edc3dcd2fe69c78cb735dab07decb3b2781e6c41feb573e1f823ee2c13dae7e46444e892cc49ab1808c3867bbd6ca0746be316138a0b7ce661a87d183b083b75b922006caa161c5c08dabc0da06a64a4edc96c4ebd47545f378e40831468b4dc659a272ea6ad15b7e891c090933ef3371d9166b7dd71b0c4281671ae24bce535ddfdb13e43d64d500b1c1ca476a362e189d34ac6ba856c5e6832fd003e6783fed439026c0d2eed3e0df85fed9bc6a4b7f1647f30047706e58dfeadae31d0ba81d5db7c2354bdb3dd4f4dc8c6448a9c3a054a93268f4e1010f08a3ae782dc87c35491ce8f784e11da89c83a80c5d90e3aa1a20cd9e38d46ecdefebd25838864d442d26409117168fc07a14d71813ca0313502a8f3f9935d3c0017e56a77edbd19147296020709ba08fc083f94c955b36539bb7bacb187167b80792442496a923d747b00fdbfa5bb9d3b7bd5e38b1e4ef45092071a792891072e8fa20f96ba8cfb69f2ed636eede3227367a7585b8bc7173c4cc0c3c42368cb8ead345bc02da557cf3d585e7ecf2b9deaec73d19e8414940321241588fa5026fa438788866a0734a6776672d5cc0cec3d5f2edb3b9d65747cc99cd0b1778e4d3303cdf2f27099c3c0325f1f9615e9cc7f1cf378e6ce5c46c7d7352f121daf79915c0900faff7a479cff577247d6d21d64eeb863c97fbd77d0ff9ae560fdbf1c2fff55ced4ffefe424fd57b2cb11b297ecd0c20eabff5bb5a3ea2b931dbf7f3b68a6ba3a12f0f55647ae0e10eac8311bc5af0fd37155e938a2038239103047d57fed73fcc431234e135f75712c90030f39ccc831460edbff5f5d1c69c471260eb2da0b871a38bafce01082838237aa78c3ea1fef468c7778c7bbba07b41456f91e73d58d2c37a6dcd0a00d30da30a18d0dd810830d16d8386283c87f25733f9dc6bc5c6692e293dcdae7eb3db4e7f25549dccfdcedd945eb14cfc0fd3b6919cc6d1228cf3d074d1d058e01e05c8143548d7047b27e6252ef9c797127896bc2916b94fff5b5c61035b27e4113d79d1a55bfa3064e0d9dbe4b6a9e9bea91a601e783b9591a61ea2b0daa3480bebefa0536bdd9fa7f73555fdb74d1a6375c7e466f92fe0d7d34e2fc1f41e38aa28146d2ffde261a05fcffe3805863cc773820d667d470c6ec8c0ecc78f335783985555377a798986165860a5f6fb51a53c5ba9c1913b8d17243839b10dc7c196dbe5a736f6e69cfd645310f962f6b5df456a332b294b15406080878a30e297d66afd2982f9b1b78e0c185b26420800c27c858818c236db4da00d1864a1b2063dc31069c31c08c011c2303366cd818c18604362f31ecf8af3e6c8444b7aed1a8e005c2f4595eb39f48b1d8cd325dbd63b1255deb144669b02471faea7031a64aa7348dc26ad944352eaf2e9b99eb74e5dbda915b2b064e0c08b4cad0eaa245b4c6cd9aab355cd64cad317280ac034c1da0270c337e08a5d5ec3c1b199dd0173eb9e9a22f17ce5d1d1d69595e1cacd67307c7cb474b751f3b0e97b94ba3741b0ac63b5dcf3e8cf92e5896b7e3feffc9ef8401465613ba4d30ac4a30a66660b8bed8fae2ea79367b5fd88efb1117ed5f50f3dc6ad0d06825d550a971a901e285d6bf17545e3cfdd71d2f78febf6661bdce9b84acaaac5e9652175b5f499ca37c971878bbb8aab60baa97eb76d105fdca05b9378f7281f55c503d142e92ec6c01e7ff2bd98d6c81f5ff556a8baaef37975b24556bb7e0f94f03e7d360a569e1abb532998c56b4ab15e9b053afdf1e59d68265794f4ee6232da6ba163c5968fda6ac3d77308b25b2b05f75a6dbe4bc2c807c182361610725710e8b3075ebe0a51a0baaaf583cfdff6f2c8ca071534ddca55434366041834343bfd64ef2bb737ad3717685d68cee4a7c8597285d7e7245ef8a0bac00e3bf623ca356dc6085b642c87f1d476b2d76aa028c2aa8fe2bdff49298ac42c97fede4ace451aaf8af5055a854a17a4685182a6cfaacba29d89822ccff578ec9dcf53ed2f593da296c53e85ce04c0a3752c4f0bf779a16852e8a09b0f2c052022b0b16396ba2e3d010144d401100282e140a3cd1e68584fa130738a184134027ac13449a98a309ad87a242c76ac926e8993767ae3843c3192c678aec1860ebffe9489b68ac7724744442ea2b65800898d062020526624cb8aec6b8c2ba0ae2aab6441f4b44b1b384124be09608a2841925a0fe5f08f338fea12f9779713566855e38a11ae47a9a29591ab34a3d738f98a7338f635fb7424196ee68fa1c7137a374bbecf962a9ab53827b26a9f1d8318f6325252a78592c762b9ada4637895c1240ae7e717ba769b1d8cd8c16334264202103124596a4658931797d348b7ba6be74ece9cc1b553b62ea88a32388bcf93b79df298059000facdeec58dd600582d50e01b42040553d3a72d52ceed72816bbbf608ef69e7b3717ad7c739d5dd4c6a8b975b9b9cfb74d23dc30228d115346d022ba28224c114f8a08abc5fd5aa1201f1b2f771b840b72535fe0b983e70e565cb38bee1eecd22eaf06f5264fdc7f9ad4b8a9e30ec4ba4c56193265a6ca2c512a83001158b59b3b445461222c113a4368e9f41056bf330497ff1f62082021dcfc5fed08c1e5ab105688255508325aff64ccfc3f991ac824fd7fbdc11c19d74e105a40bc1404d54e1049fe7f4c9cffdfe7183463c8e43154ff558f791ae31a03e4ff81c8faaf647680a07a2034c6393176ece0d4f5c962b11b8ec4411c259391b458ec46d27cd8a4c562371f36f300fe872d7e70e107a31f787e681047b94cdce4030b3e3cf940c364852153751800f4c0460f34f470f64079d88287137818daa18d1da8f87ffbca26ad1a197d3a20ee75cc77dd8773b02cc9cb31df1466764cf28e9976180213074c1260b28041327193ee0bdff982bf4ca043153ae8a0c3eddf87cd0cc47a27073239ec7278e500e49f6ed3d2a0e9c5031cf6c081091c64c041041cc627cf5cf0cce932effddae80d40dc3075c3941b10b0818d0d3fecd8e042b52f17f6ed8eebb9027db8675a8bb3e1470d65d400a686df7fb5380a47f14d69808306313450d150c00c59cce065062019f2e842063132ec6428ba3f5d2673ce52580d9e395cde7e06cf1cdd669510552d544955415545a90a12039a188c88414a0c406f7d96c2acb61416f3d11faa712e667bc71a0643171892bce0e685245ed02f8c6fed6e53174c178ab4a0a6053228b430a585a11682b0f086ef1d16645de2e8f244972532f89d2e5e9ecb175cb47009dae14264cb165bacfebb111f36f316ba821d2b58b1020b2b7cb002102d2c6861d2e2da518105159a54e84923052f290420052b296880821d2850f15f2d7f5d9792de0d0507042080140420446507950f54552a8969d5874d9c3b61eb8434279c7042d25f18660a809a9d009c09802e000fec98b08709624cb0b5f2d2ad29edf9eef26ed39789bb8b9ab8290b145978960c4a18a3041e4a482aa1032c6760c1fa7ccdab71b9db5876825004b30461c121536d4c113175c314d554d15712e782d707abbaeec3666ca6c4fab0992dc53025b0d8ee08a8052c03840262f0ff3158b5b6779c0f9b198731dfc9e898e49499e7c691f9fe2ec73829a0ffff73ebf4f2ffffeafd8c72fe2b812931b199f55f7914f36be4668e316d5f03663007c41a87cd608ea4e1cc6f64c6e1cccd7e4da86242583335b3c091254c35739991b29cd546963b4b922c40be92b8842d96c212aa4a48fa2f81ab81c5eaff93b0f0d059504d904bb0289cdafaaf98df5e96d77769309c9af2f23f65a78404734031802c84c0df3fd055cbf2fa3adddba4d966525a7c2b498579a9258ffb792475c05712632cb949e7738b93eabf9e40d59cc2d96cb3dba1994d093a9cb093397b972a77c7fc5696e7ae93df25e07038d6bb5bfef45f494c7b374eaff4ccac6d57b45c09fab9c9a56e9b94c4e5ee7aebb6e6b34a86bf2a0ed35bf378b7dc456d29fd4bf235092c5bca3b73bf7047b17f9df274e69b735c37d04c6bd59da69ae9f17d6c7c29f8824a389803758eaa1dd998e8cd5294ef5e3bc7529787250fe5d37f2d79f6521496e5dd7217d54394ad5abacd282015eb4d827944c209ffff34db8c9ae5ed32fc0bde623159bf49b25b51afdf244ceea3dc940be839d19ba147ebf1f0e4e0e9c0a3c20bdac5f9d1e2acb975596e3df21ca9716ef4a9758647a51d98ffdf25c16ce01db00e47109259ffbdeb8bb38f0fb526dff5ab336de4944e8ace486e8d9c0d39107249ee19d789f05eb943f787edc262b11ce0ce0871070871617022e08258d9c38a15cc0677f98399fcfa6ea71877fe7cb7d77b758cf57e6985b27ae3283466cdf276e0e554679f4ad22324e6714b7d6abf3c9ea53e40ec4387d47dea3649833a1fa94f235aa1ec0f85b2b7d7793a5b91b242046a0d9497af3f6cfab02e77a8a1ff7f4b75de65cc7f18a94a5905032a5c5099a24205c99433a6bc306584294323c019a1cc085446d879d2aa50169fdcf45d12fbf0ad665c4d9de92eeb4b2994d5653316b354f0e9828ac52c151d27b7a9bb519e76788222a58fffeaa27c5639d6c0ddb30fc9d7b30c93fb88c453b7c44c25e65b174ab1752914f0947a86e224c67f9d39dd9c8e38f544c9238a9830cacff24b61bb5cdb6d4ad238b6349334da8d707c7323bc8d71eb12de8cc29baca98da61a6aa7dceabddb556fbd7937172c390e9663c799efdba33d9316c7bb39730a6b29cc7fb1d88dbcb857e66bbe9ae8e8e42269a43e374fe291678ee3b2be92215398df6da6a9af4c400fdc5a0ad37f15818cc63f8ea5b69226119644789a8900544500f2a1cd46c35732e36c08d4d8d4ac086b586a4098ded3b684c412d5925e02fa587f0529bd51a2416904a520509480c2a5c248de84e39d6db216eb274b3cd13d59e0ff13f8f0c9014ece70428493149c3439095ea0595eba7b79c78a6b1e6dcf2151589fd919ee86b41e6859425aa6edfc7f0c86ebbb4cba4a7a4ad2811202560821b83e98e3bbc95613344daa824d9af03071f353d7c7c40bf63149fa0f320182e4e6bf6a1cb5790ec9cb77a4a719920e3dd23afaf2ff7db7cdbecb232323378cc2184d31d2998151cf1da43498d39bc463e79bc4313258f6d059389332a3397797785912b524b6040310b4fe6b4f4fcfad5663022129048101d91ab21e42991559051f50f1726d4ac30f46f80082a233455bc2a2a8a29ea2204a7aceb775bbb414d6d343af92590c8f308615cb12c66e1506f3000b0f82a107503c3820c913611215ea8be2dcc5598a73b90ee074504407be0e8088d80889b2422217be9eba7bea3ae6d61acd3808830314420ea6381832b4c5d0008644181a82440d922d2192a0ffeffdfe28ce71939e3b6871bb8d1b427da8b5f487da20ae772138a110d6bf9097ff1a0a3d09b978fc066585415e8292aed9cd73cf80f8d81a076f2800c180747e041e39e2083f82a4ee51771b977c9bd7d21ded0ceb0b35090cced7cef386e9de83fac25008614d962ecd926eb4898912ed469930d594e8528d22318102657644991835d1924899109293a7334fe711ebffe48d5575b43fd2ff89f3b5bf30df3e170deafb1366b77f7a0fc4bbf087672f853e702ae953f53ff3b17df5e1f97f655d20c7e42c7c51e5a8694467aa8486afa7af7c53a1dbebff9f977bcd850574bd50cd9e4b59d1d4f515d152c4a988920dead8a08c7003321b3411e183c812447e4490febfe3123635654a595efa439bec58e6a89a0db223ee6714dde39dfb0e29c09030e110010c5132a4811e37c21e227aaa843d409ef6b3b4514a8fa6d01f3ac555ab18766948efa057140c2d814285148130833032a0fa7f4a474b61c172f3607ad311030f3058e002362e18407881ed8208849021c4082150421c1823b4404d688196d002a6d0820bc20ab0082be8153c5500840224420ac6841448a180011e2e7882b3232a31ea437ff02e97b49b3956edaba9a976a4c9ba8a58ababb4c955b3e3d854962e9a7b367f2f17ed14c6b7edb69fe58f8ed6065118b5bb7cf99e1569dc03ea7c7de1046e3e9cc08bc98d7c38416f827e811f7c28419cff0f253042825e28c14cdc0ac5abffff99c8e57f168abf2ada44a09ba813c609432d8c9b8464be29b4ffe3a74eb7c390e73fa82fad4ae1ced6ffbf041fee68853b56e14ed5d71d9beb77be2902381170f155262b9ada463257eeecb9b343f0e667101ca0f326d429a383756ea18e90ce030fe8f1c098f0812af505d38d30cb64e469a781588fa10354a103b6d0010dc206daf87f007cd8401a0d50d1400b0d9cd04053d8001006900819a8aa2f1bc451b8586c577335bd6c94beba111285d50e8391e5a6d66673d55e40ac5db41b099a3d77769be33cdea541dd1788024cb840090b38850b1c102a7044a80009a102b250019d8741d9bdd3342ae4f599b6dac2203b0c32250c127ac0411092da010e81680981140199204c008e300123c204aa9ec952582e4c20294c80e7bfd69e3b7b8880508840901001044200688500480300600800a010003e0784718055b52f26fa439f5c354b71101dedab89c95a8bf1aed697cbc4bcfa72f5186c9be7a53897ef0fe3dd2ef3bd9bddd0003d20f8d080364203aa080d20131ad0141a208605c829404c580094f0c71e5f7b13fd9d662c76b33e6b4baac4c992fa863f7ae18f26e18f22e10f0ac28f23fc1dc2ef127e511f73fa78f34fbc3e7afaf83957735298639bb3644e057320e0e3007c70a99dfed0266b852c85551826b70e669f6024bfbd9e3b3bb54da40bc62d138c52db4403fcfae868fb2cce56128d8305d3671ca93849ffb5cab1f535cb81f5726cf9c7c921c611a7963b0e20e29012c70f38848083eaabe5b1d8367376b769af3c0783e5b9437a63cd1b27bce17a230337b2dc38c18d1f371668c34c1bbb366e6cf4c1061998f34c831948ea4b06e99847dfa8738977b4dab9c6baa7cb3b1aad5b6fbbcd5186b1e4a658ec46c7974c26bb15f1749eba4ae62e9bcc5d768ec98b7b38d90b4ed6c3a98263fbafc00ebcc1f935b4fed7a046746d8daaa5dfaf71fb7ff2aad1871a6dfe5f8dad46086af0fc63a9edfb5d60532c7623c96bd338401a574f92b358ec66e2591ab4341a78a3554d7dcd29bc4d9b0de228fabbc03755e11ba537ae8e0619684c8186feafb6fb2cedddc45b771c44c3e88c38ff729dd1cff0c08c2d1c745d9ece52179739ea3203cb0cfb66e8287193e5c6ea9fcc6e7a5fbbedbb7db91b9b797d3d2bb90152fb2ed19441a68c5e19495f06fd100173fc63c90878820010c868830c2c3254f851a23c9d6d647c1b356d826883dbdc360d8c71660c2fff97e6ce265a6f6cccb0d1c286890d0562a0214612627431686234a0e546cb072d520b8916903575ac19c01a14d620bd92d1aed63f60aa313149bad198c48c90826ccff66585e80732a1207d79eec5f7cb0ad122eaa2353c009230f608638e30be84f114c61130f800c30a306000e30a1844d27c31c517515f846a9a08d574351a7841871761bc7812666d3d45027bd9209b750951a35dcdba68474261f4655f41364b47fb52a231eba25d88c2846c76b7836c19ef603d93678d846cf48706d11f6ac44f3b443ff880be5cb1d86ee376e7b1d8cd5294d69ffa53492c952f90e29cee76bd33e6b9cb37a96f173c74a1d445045d24c005125cbc10858b0bb808c2c56fb1660b14b6b8a59993c68e304d99344f698ed21cd1420c2d7cd0c2a605d0ff636dad92ab666db6bc9472a099b9ab66e9685f4a945a1b106b6a97ac925da23fd4a6041b5279575f5fcfcc409d0e7613f3ca7387f9d541d96ea95033e39ec9bbdad2213558624ebbb6487a5792e29c35c546f4977b1d4b658143165ab258ca22812c7e6041c4ffaed669cca7fbf4a9ebb3d95c351af3a1584ce98cc592ffaf4634163c51d0c4f90fd160fda321533b1a9d06628dc656fb4e86e68a2bf20a2ef55783ed25aae48a5e7805fdaf405c2c760bada8590142156b54f1a58a5d154e55204085175464a18257ad893b8ee3f245a3ae198b59badb2e5a5f354bb3c1dc1dc912fb7254bfb7a87e4d199410122a781eeba6d8fa29acc229aa483c4592ff1bd5bb146ebe02b18eead794428aaaaf522491590a200fd35b875184717f19fbee5254bf375914bfbf611421d60b2b0b8bcc7f25b1a8b096604960a9d0a8ee0beaad6732ecbb4b396866992c16d365287e2114c127e0fcbf9ec07aa2ea770f183ef1abb42792c462b7279cb8aa79e704d557276c5f9d7055276e1356df9bf8fdd7739b4d2cf926787a3e03a7d228ddd2992b7e86ea4cd21903a0b906e08275ee66802524135b4c50e193d1e8c8040357695ca1f9aff6cabcfae08a678937d5363d29cbdc97a05aa20325e850828750092c4a24a94a5e58eff2528e8178079c254146125e92302109a1248a98c93223e6ab6dc2516b668a191090d8fa4ade1aad7d4b9133247a40a206246648547044968fe9887dc4ee88080ad04601c014e0cafed19ee9ad1b89d2f96cb2978bdff2cacaf21ef528dde5264e675911f6e59b6ca4a302231d473a8e244d26e36637bb912226dfbfdfd9713afb703afba4f879a4b38fa7b38fcb64b7225cfece5b910e3b9134dc35228ede4658fdcc88a96a499a35e2a9067194b9978c20229b6231d9ef37eb9792b422cc22ac14a153268d32539479a10c07968ea31d6db794c911264f9eb86ab632a92e6a7b103fb14f98d01ffac455b3380546d998e4ec5846c724671199711ce31fc744e8f4c221dcfcff0f613544d5104f43f07c0d85d8aa24e6098146882a2184709181f35fc9585532543adc69bf3d324f644232f4fa82082308aaaf63994d7de61ec4d3fff374ee4100d97a0c1add49eabdf518aaaf24dfbbdd1d637f0c2d331070f0145e02e2ea4320aa2a1053ff0fc4d3ff3b01e17a3170423157525ec4f4fe5f2726898ad991117120945496f7680a939af6dbdc3680cac60f667ea8e187da0faeaf967c59ebf281071f62f001c90707c2b8e1d4e9e5e472da2676da26760aa31406d6431ba49b73301896d23cb8e101061ea2f4b183103b60d9e1680720601000060d982b606c602cf8d2e6cbd5971cbe00bf98ff3e3e58aa0c5edfe5586ac3603152df1d4ddf5ab1b9a5b636cbb3c328df74dcd1be00d5ae83153a78d161b799e84b9b394891430e403958e0058d971fbc287929000702843854f5dbbb4cb72da56467bee948626b39c661c80d5aff7fc3ee06211be8b0c1cd5b5c2c26bb15c5629d7e407fbfd0869c0d3a358c514398b0862e350c551286f90f47031b210d6668508186dfff101a1a98018b19bacc50e5eb8839efd25e5ecdcb4d333020835628830ea10c31c850f4d5be8236d0d4550d5195a5ca15c318313011432e860d609803862560c0c1c0c0e5bb499020e5ed3d9ece96eece1cd69bc4658e5f1d0c162c83e50b48bc90e505272f087121cbdc3bbacf2b5bc9c6c18bebb962734bd9ede482052dc4d1c20d2d3461610e16c2b050020b1bb000a44b01c22e2774f1e1d2e675366229ac1bb13dd3b4a7a5e696c2fd2e792468660da3946faa2487b90b898b932d7a6c59638b9a2d02d8e264853a56c0aabbcc7167b2244fdf6a07ee1586b4bcd1c2464b172d4fb4e8a870c70f2a2c852a8090421cf54561fade9ee9a2f6f573d52cced158497176ec7987b9e5e97ca9de3b5a95c2e6b9353fcd8e83b707afc6e6760a96e535352eaf997f578724ebd8dc4eae221d7632b7d491ec6a1cbcb25b51efb25bd10e67f6dd1b22ca587267e7616ce24e5c96389eeb3e5cea868832df53434439c84d8d8590e4b31c22cafdf4613e44943970731edf4344d9d4badffe0d11e5ce7326ee57f01051c65a9bbc21a2dc4fb31c22ca389eeb9c24ef10513e8788f2ef72a010923c44944ddc71a5b9f91051c662ea8688f22e0fe1424872278788868832ae3c7d4344b93ca5323944944fdeeb4344b963de105136310f87f5ee976796b7e338fe01b7c6e1a86be27c9bd49793e5c63cde71e5d56133981bc27197eb2c15cc54a16c2c86cdcb75960ae5beb393fa52286ba990d804ce64b7a2a87e6f51fd9abf6dca8af4ce26c6923bc692bb4c96a4f3d89535aee47025caeff71be10764a3b165d84ab41b567a048d812fce9b66e6408ea536b6b493c1d2de0b84b2b15854bf375f50dfdc2fb0d3f166caf73571184be636aadfdbedb8c7cb308c77b01d895d514633e35c39a375ebdac4c489765b6272b444a32330cd6e4c966a4ab4b6d4ed91af26fa8a945c94c1b2272aceff88cb5fd6e9cc7fbb97f7776a5add3d58eadd336d6c46ab99e92f47f5cb6fcfccc09c33a770bf3a9d9b4499f9a8a7a82424504102d557acf78c840c721699cb07f57d41599b92a5e2a21c2be5a7cfaeef6d7deda1f9ef55fd7ab6b35f1dce057baedef3f8cdfa7f1e99caa3faffcab3ff95b7e4bf8a3c9dff17776f7ed7b41b773d580d9e0143f90a041494548d90783ae736ff515a7905527eb1ce5076bb475f2e2b927890498864183289fcff6a84448325cedcecd9c5dba58f1ebba575ea2ad99ec72051e7842e8c4ed44d904b53cddb67d602b1ee3adf7acdbb73622ace776adfa9c5dbe526b93f360c6b8275e1bec059e19e7042ac6461e58c951e30bfa8505a6969de71d439868456116a0050b52a7d8855e254d1a14a09558a50f182ca1154aa7cddbcebebb4badb8db8974ce8c94d6cc79e477d72ccad796e71ca11e21415c42948532818018dbeb8d4970c8eb080f894c49395a71f296048a9bf0e8542599cf93be98e4999f91e8fe0deed37ab525e4e7a38b989e2459420a230450921ca04e2ad0af12680db78b340bc01694aa2c98ad85484290b97386c6e1c2e868496a54f4aed3cfbf8dc6a4b3e3e4386d40d3429edb9ee97ab48879d38362fee4c404498238255b9f9a637dfdd4c04aaff1ad4358940e4ff83b960cebcb8d3992d8eed8bcd494d4e4dccd79e9981dbc49ad43bb779335aef14a6789b1788758d4b2d49b5966fba1467a9ccd20baa0a952a2e1fc7becd77afbdb4c4f3d55a7a2989315752bafaffaaf4fbda332731b72d51d2f9af50b2a090f99f9308a50765498502646b2d7d323d21f364ea959e24119fd0cab1b99da2f4e54eacb6e8848b139f131e7b2f2ea948eb342f2fd27e220db869409292acfe6b52af2cf72f842842582184104200a1091c4da2109bb8f05f5ffa02b18bdad7d4f5b96a96d298bd348a4da6262f2672884cb4b699b7be3491c91626529814bda2f4e5389d7d4858482820e99018f8af51faf2bc39c612a5af7991c423258eaa8eecefb652946874c68804233a93f3ff412fcea818ed2b88627ee998631607afa5b05b734a1d072f0ef39b9bd987aa32ee1e904a153ae35982f55f73bf4becff9913972cd9b6253a48342a82c0e6ff65b2de6f7924db42d68228db1fc08ade145151e4138b9a8afed25e9677ecf82a794154b24509d0ffd77d448c85896931e6daa2075b3c30c1830d92b4e1bb031fc40e70073a446210392112e54054428ea8894804fbdfbfda2d7596c26a59ee18a9effed5b2dc3f3af67bc4d3481c407971688c212e434890e481240b24412444840e206445ebf5e532854ea10cc4a03541565f839a7a262dcf6210d5ff2cc8f6ff391168ebdf5e8ead080444f55fe91581aa1c89e3089afffad219783919e4d7d467b9a5ee91a96d1e713a52b134ce2d8995cb57a0ad1689b03e6056db0ceaeb824dfdd77e05935784b96ab97754cf9c8ae31a2394ceb3d11c5db573acdbe2cfd6bf5c74f663f5ffe20f95167f6cfd3cf2e3f249f37a5d26a20f113e4fff7afb344f8b3e406ff3f9e7fbf562f28a4074a1a93c4d45579877f5a0acc65044174f2d6f9f1981639a7bf75f0d887591208a9c453610379043dca0890db46c30f424d67993a0f1af168b592a3e35d31f4a49736bead371cf14897041248b480436248c2154ffb5a7a7e3a82e45af7939e517d75766aab9781687040d59a027eb2b25b3a53ebb6dc92cf61cd1404b832fa20651a20656340842dff8ffba4dfac2e11c6e9bb8a89c897d9857a1b1dcfb578362d8bca645caa04d062f881910612007063a88184c61b0c3a047c4c0820bacf8ff0f5ebca0cb05572ea0a2103942d87411b2a3512c79dc3bf6c2bd3ca4f2285d8ea2243633def1bdbbd8d7bb49a3b51bb14214b0c08c68410dffb5dc9b52d102a50af0a8c0870a441029d8a35a8b710772dccf600efb76a74714740a9c8814bc441e3e78c21079b2441eaa0a65b1addcfbd7cbbd6d531737757d306aeecd34c19c09d64ca0459c60e8ffcbd24742594b652483b8b7f53612253842022ba20440a2688688a5b099cf2b9d16659769751cc7308e182a218655621882b8a3c70e13e24e0ce2ce0a3b48c41d0d2248f32486e1da35597d8ee890fa1a39d6510e411f22044188105481800251e78da86346d4b1a2ce4dd4f9213e50467cc0870754b0b81fae64d4b40a65a94f858ac52c15da7daaef42a13ebbd3dd7de810f10110c4079644076a70a0141db0406ca08fff11caf672ef1f2df7fe755c2779bfa54c762bba9c49cfcc527ab965b7a2cb316e6b8e4b1e6f9b38736f2e2b2a37c7e6353bc7220329880cc082b911e31dcd7626932d90c5f3e20256e20253ffe20274b6801515b8caa2025bea2d881931c896204d82182002c1128178f9aab798801e62024d245042024e0944202220c78c8840504420c97f0fd5992cd28f68de4bf580350e10e200de01444403f830e08c015844034ad100971a05882940271640452c80e7ff672ffe58f3238cf843ff18c57f437c23c4078acf81f83a5f3766d273fd9dc192674aea2b85f671c11c3ce6383107cb9c2a73329813f2a1c587152af061850f217b68fdbf6e6c528bd03eda6c2dbfb406617b04d1830c3d5808f540410f233d84e441471e0408f3a8210fa63c20c0830d1e5ff050c19cc23d3ddba419caeab214ce45a96327f5b9e34568b0dc5ab395668bcb5693ad5702da4840990470a9346629df774c71c70d77ac7007d21d3f42397bc8b9928345ce939c0be4e8d8f1851d63fe6bd05218ed99f5d06de619ad3db3a7278a6f60b6ed7293a0295360a4632c265ba2635291ec725c47b00ed7ffd77be940d32fc7744c753a9efee9006e4dc93a879939707324fd575a350eb135a8349545d458aa19000000500053100000181c24140dc8a462c1644cde3e14000051b47468dd9836d1649d54c81863600600004000400002775171a3e24156cadb10d96309df5fbd43f80c71507817fd707ca2c8e3c1d2c485cc87081f139026bb817ed313d887db583c563a9ebaeb5bb7465f92774d263f8d759f1c612a3d75c6e395969eef524e684d403039fded06032b9b8b89b1ad7039aab78d2d2f47692ba1e789b1137e6601a9be07bc8d895542b0971e36218b2f75be69489b84c1fe475eb70f9ee2f68d428f3f249d366b89df4583a6d4774b7559d03c9bdb48ed737f74ed6c625826a0006c7c21caf0724b86ad3fb229fceec5e1ccf3fd0df78cdd3e6eee6eedee483f8216b7e4a2dd6eeaaed2f7bd3bebe526a482e5357980d1cfe321c504e645716361f4761349d1818a174b657cc657a067877a3280ac2c82cf37b81a2e08cc74e7f20c4ebb55bda8aa05e39fb1f2864b60b424dfe96a000b7f94d84597095048a0101dd28cf37f4742b1717e4d0aa7bb14e47820446962155d27e3b9561af6014400add1ce74c2806852823a07782bd282522c52989188714c5fb60f17be64700c3be4e71ad3e92bd352738e569f5248fde93fbd02fbb45553ea760903b68a5da9b11740df2c9d7b33225a60b18279bc82351f7f7f974a1683920d4c981b42fe32395ec054b2949f6a39a3ace33cd21b2e356352a0a25343403a9037cc39166fedfce56c18b2b50eb9f6b8dbda5265a0e0bf4ce92e6aa0aa908736a8a57602b8a15f037d8171cc42a87db3094f7166539737a90b43a84344dc96d1377cfbc4f181761ebf30d4837fed1d28f2f0b81a23b59bce23fb8fa34a3fc048d61b171cf93ca840a4c69395ac7b4fad4e17b519e9ef94c1f3936f56fdff8441122b00ac6e16696e10909e7aa894156852d1bb91404fde7f1cd93c394617050641433236c309b9e31659f93dbaf9c143e3626036d248dc84a010620012796412a8d6661c6ca4a8a81a74b82e95e32a80f3d7694369ece556fe2148be8bcb1f3e2d4ee2f78501e83e229e331eae567489bfc48ead1b6133be1b837cc62c0e0de3a38a284ae8509a241e0ea0ca3d65b2d287c6e38d0ff6c5cfcba3375cd7cfc2f82f6f26596c900524ef851710d66d278b03d4903f76b00ddaa26ef7fcb507a889d598e915baa8ed2bd0fc63e68aa2cc46d96b8fb92625caa608a42be71154f9808222a06d62f4941b4907235e5e0cb6fc428297fa84e3914fcb8aa21f35eb1f4e3efa48d33287e4b1c525426070d5ecbf09e71ddd2051dd77b7b0d7dedda1b2cbcbb55ab504970ea21c04635b7f6d536c203f3d8a4cbead514548e382222dfd9723479271b35cf7887374495ba6a099ee386472ff770698215588c601b4dba6a8c981967ffbda66cc348bb3639bb1bc38bc1bdd7048808057c1bf480403ad0644329cec5701f92c861dc4ceae7755e8b3596465cfcc913fdfda9e5c348a921d980833cb0aabf0d0af2d233ac23c7f743e86033314c91709ba6756b364ed92bdc9d52003e54953eb85354500b251666f971fad0521fd20812e405fccd99035add92a61782ae43bb93141232aad6cfd8ad71087158ccae296b54447278c839e8536f0e86a55e2ad13e7c86df20524abe12cdccd9d45b144ef69afb4d6b1e0d50b99ddbd7187b808395f77aeb60e6f042c8fd21e501147273969bc6b4abc81744d90005d96c48a4b57bf18b91fe7c1d7a5258fa78b2879d15b9c6491b336d8b5b549573ee5c65930f4049f751bb77edb9bbf836980e34317c2314a1abcec9b11beb4209ee15943d8bff61b0b6ade42d640bd7ebe44ad29394855fc3fe6b19ac91b4d55002d62887bfe83fc7f431fbc3b5354f67e420a455fae7b4f572cd23e2d8a22cdce13765a36c309f4356977becf04e0cd9ebe9644c939131b62502b0676e4b20201db11e5fa8758c84a2f739c6ac1da4462c11ea5d729b9e3a3109166e6da97a247816fd0dfbc9a49a4f8996cb12f007c272c1dfe870ed836a4bf793e00ec2728fc7f1ed814d35f9384dbb6fcad0cb8eb2adfcc713b22b5b6f167a81ec187402bdb1ba080fe264942221a2b9067714f6e71dc0067b42e36b36ca7fb45cccb6739f75c0773b45bfcc395d0435eb8f8a125d7f1cdd1897982fb7c2b5a18919b3ee6e490276fcfee9631ed40c5ce0d822c663d996d823da258e0405d234af66b570e482f394e9590dc7a45afaff02e5bb4531429ab89aff67d69a376a83b935a9ca5b8157b7549994e1a09b8ab34bc5f63f2414f08829a599f4578deee8e044d68354970f442b13b9614a4ae3b7781411e13ad77fd496a91b72490e754019a7c78aa39782a073d3cb5efefa9d2f2d5905dc7873499e343c3e61aed628795593bbb4facec798bc7a4496508809e61e024b2b314f4fb35136312fad3a05e615c1b9eb706361f10d2bd919d7f1ba457288068e3db68386d44569b480dea4d8cb86702440cef39b136f09491398c313d2d8696d268582cadc5ad2df883eaec5d9a6c72eecac5fa2358745988923db4f7d585aec6ecafd99015b41fd0c2e393d81f081665b89158d5f39410969ae340685babfbfc2049d2fae3a3e76fcad774217616dc9d659dd46ea19b43661991db2d885eeca836e411f7ff34c034102160019910e831b48f54bc834c59e19962e952f6fc48077fcedcd2695dd280a687bfd30200ee1aa37c8448a0c56592691e48d459834139723e0c74c8bcb420a655a3e8d01f27b54ca76e627b8df283d809da70153c5483cb63e9801cad5057d7d1e846b512f6efcf1fd9b8a00210dd8cfb2af26287610d0e7096d6229e759c87545c77429723e4b9b1cdba6d30f74b67e46d8d73ecb0640e483c4007b1cca60ce7618a8bcfd7ca907090b16dd427fcfc114f471bfa1d20c8faa9c1d37bc9d01bc9e746a58ea6304698e5c5cc9faaefdb5e0af3de64831f63bf00451cc1bc4b68fcabfe1c62e029ccf3f9d82edafed7b461a2adfd28594cdc9a18e47af01d18fc6c6154cbf9acecec1d4d94be7769cc7f00cb771f49cf6463ce00169763628784172b58858c64f2ae55561ac55372d9c8ed559df71f0d0449495c81f12b77fb3391c31cc647d091c59c437387d3e0c54b4a1d3cc93572d6f4b942e41c83f67f8ef69f30fbf3216acf155facbed553df092374dd21211adf1331561c033774120c487b4f8880993e186ceb209eb0f2ac68b47612e1b83851d7c0ce61f90e669b2e3e364659c236871ff0ff5ac45d51904d0bb8515b40d6cd2c2f9acd54917957ac0dfbe845c9e9c915a753c5c33ce3b6ca9297faf3d6c8f896c91c1a58492b36934b3ad9d0e29898e4353a958e67a98c8c5a5d29c5db1f9f28ad797380010600a83d13176b3800a36f1776b94916e4d9b2b86448587a40c896b1e266c4648e2ba99176ba86e42b251df4d19ac48921d7283c834d02be558bf76b9c06ea22fcfaf6a8f7a3540c46f73a7c2d19dbde919c49c1f6f5ffb217fa421fe838393009cda0d358f2bc242293f1c0268eb2cc6a534196bdcee5c5358662e5ab1db400c9441768d050bd24ecbaa0f426f437e03b94ace7124ac2d667106dc9df2e05923249cd50e949efa52ce557ad99edef7ddc48831be8926dbb9d63299e09a350d4acdcf7034745fb19310180b52485c68306ef97d896f010ddc39012ed162bc5c07e5b47d2fa307974227a5cd3ea77b1351e0913563034fea7429e3f0aafe13a349e4ea1412db71df8200fd5fb4db617c34b842bc1b500a60c53153893bc8c74039ba79115da275b0d949c9f4c90521b9337972eaccc7b2c007aa5416e163665b51d3b22c405e61bbeb2465196277331caef2092e6f155e8b4ca1a8fcab8415f3d73096f305cc4502bbab3503cd0e90acebbffee6f1b5d5cb12c8c37cabe37e2ed497a4c9ca3475bb2a4c285638979b04adc41ea3405475cbfd9afb140bd7f899c855547b425dee813824694dde1038c6f22ab98cf4ae5923ec5709428eb27eaa863dbe40fc4ff665edfad82effbb1e811a7fd2141a9c46849f63063689aae5ade2d51bcdda66e335856cce2e66b1385d372393463290cc4e9a9490bf7843ab38953d2ff9437eb9d27690c0cc955b9ba451ca57a628ccf47709ae496133c905cd751494ee9a4e68ac14618c51c11cb1e6e0b83a90547542073e137bffb261c59008a99f9ed693070adebacb8409c5c4bdbd3d27303f4477e9e2f4a1cd4671b03836165a42d5a18b7855600ce7183eababb78327e1b097d06df400a421d9cb6afc5d5c9766e943f4f2c867d4761d840f4b4e09d6cbd0ee7ff11a93d81a7b4103dbcb8639c4e2bbc198667a3af4413f0fecf1b029d757b60d9da83476a2ae7d4a688b5c1b249e3b0ac94f3b97d71b690398ee64a46bda2edcb2981d1dcd227cf429693721c9efa560e9fea303ae39671d1df9132ad776aabecfb7866319c38cc495ae9568c30100ec09e02cc67353e868ae452f3f8683fb73a630ab79ae08dabb7ff4f65b683e4423ba5fa1abd67126c0346e2c80c77f0f634ac16539f8a994cce7ea77e7f3d21cf518b871277fe1923105b6bb9191e50595aa81c0604eb3c57bc109927363ee99f2c4db9ddb7af2e2bb166aeacd4857962b18ec4e1af6c5398b7e2c97edcd1853dd1798e86900a7406967194318f950c7115b2277443e2daa6d1c028af35fb91d7268857122687b0fe6a8b21c962fb1e371d6406b390313748dffac8394ef2be8e7a8a5409de1790880aba4d90b33f9974800c05cda41e21d43ac572d5d9dc1d3d301064d20acf204e6d44d8a6217b63a8c7b095cfb5088f12e2821d6d61719d13a82374022551b8f6bcc56c1b502b84eb9fa0deb0814eedc76308e83c3d2e493c2cbe96d7ebde5269f457f3511e7efe6aba1db8e6b1a106ef1f64c5845d9d7cf099e5872bfae2c9fb752a057057997ca3a0a203e12308d67fbfd4ae34dd9bd03c9fbc1184e3e866f7101569c4357808242985f5d793e9ad5cf91b69be5817c2f2d4c8f01757861d62f4bbef7bdd043f8f8fe9ee1fa8477ac2d2da62ee0cad16e9aa10ea8a989c909c7c5e48dfd7d5e500721d07a527f4f860ea3c92b3a65223646357bde4d1d111ac009c065ff50e68d6974e32227193e0c0dedad1e35853ef3761b1e029babd9cca9af399e0061643c11a65c42af84f2f8e3f38aa69d045a7f38cb18302b5817eabe5248a8b8a0d5d8a3950abe3ff237c4de42d16d2c614fafe6f3007bdca9ec0d2e57a4e82870a06bb56bbf3c1329535beb2c1773e0f347607daf93c2771108fe77073d8abf04379c17bdd89f3fa896df8890853ead950a3b40b1d200d72ae57b999796a75e3aea310c8a78e7533ce3b9467b9b0ccdef0c506464d5d1c46b7ea7a4d48d721375d5eb1b055dcd6c676562305f499efe83791985f600f54dc91ea511b0a93baa7e73b856ed206e6321a3df0386b1367e058292818868e4bea19f844bd6f6eaf38896e568190de16a487086bf3ac279e482b0913d5a2b4c7d0641bc48ce918d1ba6bb1c7e9c0d58a0eabad985efa2cfe7b04bb23f5d800d0de0ffa4c6c5e5061c192d4673fb5dcbee650739aecc817c64792f6ed9a97705d75d475b0a908aade2948910662f85acba260d617191717bd2f8326d92fb1728e93198d130b6006c25fda320d32351f912f832869a9a6c31af5d04a038160b194a0480f692195dd948f07b848ff42b3c378898d22b7e33d4f8e8f29a083ba70a5ba7be9372ae7acf753e42f5ab88762d25e0810f847d7b84e5f73506562bb5c6d815c74b84de897e8989dfef4330a7c0d06ab5a52fa8fad16913d2df9cea779553a35c2e7f41c6177108fb31fb5bf953128530674d1d37c8ad88b7c60a051af84d8437a9491fc8ca0311e78646af93fd18521f3e609387b117d4c0207c35d0efcdea697cc0ef4c96bc7cd639c9fd21619209f11cf635a92e17fe39df11cd2a0f68d87eacd8967e5a0feda6e7a7b18ebeebbd82e5521f98aa9f50763b981c3551b22762ae161805a1223a55c5e919f2f36b4272c0bc229fe64781a91a46e0e96256754f077e090855b316b7c336060cdea31c33433a5b1c6ca7fb66a2ed8ab44a8c6e5196458403d36aa07d1c7f0d678c632fa7993b20b0880d58e611b801154ded240fe3e649f264bfb04bf377d89d5da43e14b07e113b3770fbe69a3ffcc863133f826537c62f555f0ce22ffc9d84326de3592ff116399453711b6978da7dfa4105a5c2e7518740990d91f297002b88718ec311988a157922a7407476925ff325bffea886fe94e54bf5a993d0d9ea1c02c81682ee1d388a08579d75de603b53f57e78d5d53bf0c5927ad7891c9921482b5bf6892c995e6810109197b42db6f3e2e72f8563c989a865370f050b332209c40aa0b273d0c923bc440dd7c1708ddb98e1f1a3174e25ca082a96607728e86c97b666696c4e776430f37f5a754ea6f5a73648f2462bebaa5167c23ba80065d244cdb18b10fef334d91d1969d8ca27721b25e90b1233e8b44b8e4894912bb698b6d680d5f77dd81c4c02065586147f1be5384c36824d550cce5194cbf1c42d3925fd0cd2e816ea209b06bccbfa55dac3e78ca5a4be0e3f33181e3c6fd9300d9031608c73927e06285bb8075bd946a51785dd4a9c6d5d7e7e32768070797707b9a70d45d5d2c74f1f708d0a69eb50c231a501c6702639cca7f5c09da976f8d914230ab5c5ff788fc1e4a39481a49d737408d115a534c344c763d94b459879174a05bc8240b439153b372f0d516f89da1a804df2b65a78611da9d1ff922afccab36b82f6eb30e6f850998fd335afb9d29e4ece7709b55c7f7bf8f5413a0cd236e3edd0187dbcdc9455eb35bf0bc69d785d5141e92c219ca33d09d64b4c14ed0d58d9f02233dd4ced9a379993c0c8541c35c79c1af4e6c60982dd8cb55899a787534a69c72c00822bd0df36734805a65419fa87c7103fad03264e11307d06e614c1a34aa0884ad300dd5e5308000caa68e812df133ca6f14a8abaa185ede3ebb59041f6c566af611c46d5fb7d2b24b1e0b92d9ac577007b8489e6f41927a38fbd5b8690328c73b8a4e65b65c3c01c205eabdc3207c167e07b08b88a2b7b26b01fd1725cff7774df0920f5b76275d8fa2e0d9272494260db19a2304c01aa9ecbf699a21e7c3f6532cbd6ce926fbd4ba2c3a58be347304dc97f99783cd174f42e53eb8a9e2fee9dd2a995ba554d7d4e8ea475725390888cbb95119d9012b2eeb8e64f749d9783c902ea548d2bb17160b0e9c34ed05e1af04ae9403d7cba9588b0f8eb7684796e4b04883fb5580f6142338d970303248f4af43fcefeaa420f86b4630fcda9d6bef478c15dfc0fb2e733f16cc0848d3660bffc3443543c2c15ddd13e7202260bf07e6070f035cf4de1bc80a33ac174f870f8c009c64a57c4d4e34a3a62f5af16289c8a69550c1bbc7ece2631cac9a2001bc1400549b4138a051ce3c0f654e360fd2c0dabcd50b0b7da3bdc421fd7434b0f43cacc242138f5486a040a41b465cdee75ee1b27733260234e164e529d10e187ab413793dbc35b3a1979ecaf13528bc6e65e358dcb53c725de6e3d370aa58e04f6993298b87adb167187715659b2e85f755dd0648a3f3f5f009cffd81647764e134f8f32cbafdd79b00764ec24b02dc02c582b23fad89c39ac54d531bece98929bbfbce8c08f4adfc8ebc0911c5988cb0df10d8feb99ae89fa8f77e0fad3a8228d2299db807a695632a047f8457efb1e535990aeac15be2d6573cdaf0f0cea54c7f0baf0d5280815c605470119add45f0ba2cfe6af5c18ac63c75377891f458381eb3a14cb4ba9ccc397c67584e41a7ec17ee2207d48dfff7060125a1006fb1a2096e20e94d75eaaa0771c567ce85aec684b405ce200cf429c702508b899c74eecdc95ee08005d0fe2feee3b15b07728535421f9ca401a27336aec80bfceb6872f72865b07b0f343909ee7457d4a96142dceeb161a727d23811c0b71b986bcd54d17977f1996eb6b293b896232303aa8200c3f277cc5a79a465e127647e49134bd2b47b7c6fd1e2ff863dcd29d77363deb15f098ba98d8ab34060ee7b3ee1e16edb09f83953dc9d3202763e673a0653aae4a5006e39edc963045ecdbab1495c2e44b36dcab62694f35b99f3552ad5d3af077dc0f040ad48206eaaaaf22020dce7f33153a31f1f1e2cd3d6a85973b15f320ea047616cf67d2007e6d0e8b924fb660fef00f2451bcedaf860e5389474abdd8f06e40c1a7ffdeb8dc6c189c1fb6c74ee7a0c726b4f86cbc39ff1cdb88584be247c17e4bee8a1baeb82fff42c1fccc3efc857047e721870338954cc167473ecec22a7552e3b16b7d7da5b82189fdff58b3598b892907ffb496f919a471590b04106454b22e490a7027e449ae3379193e4670891575e9dc661796a7063ff789883ffe7b9962bb92f4ed55520a14acdfe49ee9c563fcb1cbc006097f2a2da17edc7a04e07d17137f3e483d29f0ea420143c9c43ed173f52a292aa941c611f9f579e0282501e701c5fdee386bfa7e5b12ed140bd15be54913c94d358d95405402762f0c4eab6e2f2c21baba3bb722887ef0ad7eb5157ff07b865ee2525f27263101adcfd8e7c9369304c8c2bfb4de777bff0387e31361c5e28a65ebd86ab835e89b22c67afab7c76e7be5fa8cc787e40348607c3e0b3cc394e1453d098fb14c9e8973f5501d72077cb3aa1f82178b461a087430fc62f06163ff6411eabd8d7dd19f4c6ba6c274b1b1b016edad5c87f6fd16ed7267d70777ef19b19d8d40ad560d5e1739eab8cae4792a7b5d89812ad88e7c475a8459d69262be10ec1f91c3af1d67fe77a6fbf7f0d4ebe6ef0bd166de7dee03761812e2b1858fb944d7cd5a22edb8fa5ff83fa1be9c5ba8b8e549cec2505023d195758713388d22c7035dcd4354d7aa33767aebb2a2c587b7f42f70e337791afd9547af8fc8c4bbb3f80d2f36a96502ed3e965fdcb566fea2c8a2253690b9f5a3801996887af6e44c10340469a7e4149407de51ee2e9eab83fc854b5612c13d0140c2e4d01afa309a353d007e0442283e07ad6fbbdf2507d9cf056ab1de56c919c71823a43ad718a1e45221dc2ebc43873db969d036e0950df683d9d3273c08647089cabac97e551e043fc87ee82edca133daf03c00070603a4fa91280d6c0366f347795597334fb68ea882d87ee1f87f4d1a9f638429c3a75637d78262143b10903ac4123bb1e8e36a56473c15d490fa19066d17e9c45aac5c838cf4c8ec5ca20208553c672184ab065802d4c959d3c778ab4c5d1bd93f5fab5fb0e5cd2d12dd21cffa1c1bee77e29327577669c64f005ef8fd06d8c3a44e0f032b233c7fa3fecc6bf2ecaaf87948e82476a97ff2ed5a830af9df585ce74a097dbf04e306ddda7926c2217eea6c8daaa92a33f95799daace88acc0b9aebf0f85cde627d9a58c003821ceaaa52245c59670bf8de4190600af0283af4d86cfe59a8c7f90edddfbd9ae15ea04021f3c0b8bf9259f6cb9a454847708755e370094511e715aea178c5d3ce2fb3afeb3456f891cebce1ea3e768a49afc4a7f6828d8036513cd1bbb5d07a327af24af4c7d8daa816a3c1a9be94ed60f70235f30ae3f3df0e469eddcce81bd2c8473c1f8d3ef02ee93f93367e53ecd005cf440cabf0203c08b06cc135c0e892ea47e571af10615223522013ea483b35137b6c8eb492810c6fc6d2c2dede45c22ffde58a3902cc5be61cd95100c3ac9ccebce100a3ec1c315640abbddae20eecdcb04ffbc9c58b7be1c60a40ddb15cd640b1b048b6cb462bb1c0b055d29a27d1391f7edb4264bcf52c7c9a9d4ee00e8da32a0b6876e82b11f41430552363e3eae4c4435218d95a09deb2f576df0efd71b34410df5a81ab656d6508814cb4702e1b0ede6fd08c03d1f1499ad31e046632a0472d03297d86444c3c6bfda8a4b8bdb748c683edd71551b1e28135637e064f00dd2720206e471813d9908fc5303d37916a54fe4509790419baebc00d33afa6aa037eee719b95f8eafe38f0f1267393fe60c9c8a1ed911a1443522edef65e21a9f4d90068a878b7855c1d50fad3ad9881bfc14ca70c4602352e27fc991ece95b7be797939d6f2e79e94c41bb70c2cc7e7433d907dd7ef882f38ceec0a43e648b072b19efafb84e60be3f5ee478c235385ee3fa59a1d6a324781a1b39fc67c9d1a956163e20c2fb873e057ca0703f6e1dde9acb60bcd2668b9b4a21763feac09557918ffc4f4eea0a4f0d9cc44eed83429381337c8712718eb9a927ce6cc0293bf836cae45d535a45159196d4839700f6cc604f3d2d8c584c0155e30cda8c8c01717fa0c7e5d9984c4c14856f7767a6f730538e669de833de781c1b271fb9a232d15700145b955f363550b57452a63da8dcbe91e46a1216106cbd184e90eee6ff0d15acc2b25ec79a74aa4f71d6b3a5005fedac263db7ec10f5071ab64bca6b59eeab8e7e035c4ee68396e79c28f6cd911798ed0d31fe99f342178078322a49077089b0b03864874150a5c689190c20ff20d2022679d1fa1c6d34f62e26ce115cdf2599e9cee7c1793f4dff71a43a40a56effee4d863233d7a6241d1fa82146042cca02ea20d2d1602c6eae8f158c5a0a60be1360dcfee05a38f682a99749ef3ddbacad74a9d813a1248a4bfca18e199e164b58a4e919862a287aa91a63fc07f7a07e88d0bee25109f496f98955ca29a89738fb5b3c33a96f1d3ad6b2ee027dc4170a339cc9b6e0713b9bd628f098fbbfbcb1a3ddb9436628998e592f72548ca331cc564ef923f4d834cccecf4595071a8c235c1fde16ed8e6823b9824be2b7f030fbe256b0dc35f76eabea2e804fee81c82dc47e262610a7697e2a5a4bce754320d4d44c30859d1f49b848b0403ac81841b9c660718ca144d3a039da6e17c39375be90011f2099cefaa288f46623856d77f6587688b8e38a1a8f5c204ae9c2d88ad622e89ba77061484eb283625d18aee09a88d852db82dec238b5803ba6a9309297e2a37ec457b29273b2be5218752f5f77c2b86e755a05613055ea2625b407018b5d088328b92e49408263f8bc8fe4ff2ac70b06d4006baf4c7afb1f389453574bd72162b12cc8e7f173226d165af8735e024371b730f4674135335e63f0b25d131294b529d9db250a9fb84b16c7373a116b8c16efc1ef63525e89a9063e09d8547781d7a24126d23bf138049d621daed9bf5b70e522760cf5816f23b2031adadd6ed6378beb1d596f3f7b6c509eb57dec36c6f78decc1c7b4c1eec68941ecf57ea3d5881ceb14220d00d948b310348ffdc03557fb6184df31324ff5504c56f22f8c056410f922c32bc1990d1ada45aea152e8a52aa58d591da4c0562c8aee15182408f5172f8f5a35675a6776610ea051930b52b39d65da2d341b02fbcd7e84508cfd7e0dcbb5b4054b936d41c91948b89c00194ac8f23d087ecdb4a508ac1265422edfdaae7bd768cc67fd19fe75b43f70a8bbd913895cd59899e4f020a1c64ef2ac2cbe46064637873425782790c2e5ced53bbe8e83ac5f56f15de66ece8a748f15402bb7d32bd70246106f97f728e36baeba596034846168b81921bf21f90e3ade509bf411c9576281979e61851f85e5afbb1b5f591b0269582223dd51b073ae5106852a4dfac27e953fbb4fb873668aa015113c7613d56bc3524fcf02918f95fbba16661198676028f3a0229a68883a6ac6c8d8c77e878f73fbf84f54c5ec37bfb9f25ff0aa00f76f9a96217d21a23a3d627edeff01e39000f644e6bfffd25fd1cee1f1bdc3de6bfd0010708781f28d2bb777de718c22a6c5e4c6189a11719d2f24a18b55fbd02b3db45270d4488aec686b5f6a7afdc2d132832f6b947cb6250a0e82204d31e3933ea780b8e90b4238a3ceb483b0ffe4760b0abb85931f74f3211c33cf486ad7c7b8cd71d6662479c8487b6b92bcbd9c81b3236b497911f132d8566d0a07de0f8e6cb0ee0c80bbce90dd211bd0439d123506de95391bdf26379c641d8e577281d7719aea805e5a0661576ab69740fdb5b5f578eb5ffa614b586c7bbacd7269afa70ee2abeb92ba1587c5c923aac7b87512589eb92d1bb1404c9d1bd2b4c20da610242f4043a7628c21827249f6ad51ec799c2018f0a6c3c0b501008f14ee6942152f843569b1ed03d866d0945e3b9fb819e4438006513695915a3035e1158dda51a6393f7be1ad08ef88673315be260c55a88e24a89dda96c308afa221e0a10d08d933006272088972d2dda687f27a873311c30a3de6573ae3561e996e4b0b688e29e6f40b32f9481d70fc4074c975633cfc71a966f0eae175e2e74e3026fe4c9bdb1ad0734061de6d7e0c52af17648faff0b7b861f19a8c50e6fee04514f4e4d2095157f5366ab71a00495ac353a5ac6f6b0b0c56baf80080356e16786042c5e72dd5e29da871dec73e6a1f68148c7117a84bf6cd00116143fc865b4d431edd449b5a2963e9748e6d88908f7909318cd48fbaa201dc64b87d518596ec00372cd3638f7fc326b623a1922db1a59d77be8148428281aeb063b60dc8e0a91df3f2a49d2304575a5f6d9c2cb8e7baaecbf6f5961d3117436a829a43620b859a8ac4de1f2e79f72e30d08122fd0ae2e3447e3ce626d4c71f1a7a7c126a4f55ad6fd380ba9e99cca42a759bae5304d26f4cf1b53d88cb112269b547d035d482990125688a3082401a8f1ce8e3d20ebc5517888c4d180d44c5108ab013f55106fe1c8eeb4f4ad70964ae6dcae3b82c73fcbddefe80dd4280ee3818bd4ae4bde751b8a3a0747d921577ad0f7936019f23378bf850a6501e50b19344e7734cbc462e0f492c2d36343c13785988e617429b96166108c12920791a3ef18b7f5e252631831a9bb7664391a998455aa7d742fa6b49fc52c7c759d63e36152ca18c6ab846148dcb351b07606333ad7668a6ed69f1d6acc9a6ecfaa8515845469a426d64dc7483d4d90b1e35e14386036d680bca3632e9403f385c2b463dca9799a3e57cc31fe40b633744bf5f7cb818c5af7a8f27c9a4d88b7daea99ba1db01bba02002d2bec3075796991db30ec1dc2f98929c0ef031b7446206c9454ad111226f19614f391eccad26ca805f039f6d3a4d712528a00408045172bf502b5a5c90488c4f2c6356061f01ef33fc04763c086600e37b65f581bd24a27c9b39a7f0c71b9cea5430e36e091998b19afed0741a66bc5c06089689e8111aefcece76e8a5c3ae27d1913ded3d60f17c989d019146871c37bfe619287d227453baae9b2020f46910b821c276fe3266707a64679050650a22e2133aa7a0f16b34345144c4ae87134dacd0e1ce3abfeab8a55a7f9827b2d0892a369d4051bb0c3cbac10d04f254f0215cd1cb4438293c497cd186130cf701ab42e94ff165ffc43310fcdcbbbe5fc60a25a8546e4274199d30d213708a60f739f2cad37ee467e370a3d517bd96ff405cfe44406081334a00ac618c80a681892d6c77852a57ea8ea3a0184b8891f25277d80e941b4fad9b3959fd37e1b4af560bc46c08c868fad56c0d58baf73e6466d959e7fa4047aac032ef09550d0c748b045fd1799dd0d5a3274c272c7291af54c621c1d35379f8b17b5ee8ccfbbe94e88ce136c3d990b9c0e2e7b2372080532e836a6340f730e95dfe9d74f031fde53835a19943bce7b52baeba50b8a2111fa65be1e97b5b46c3c0f2d16105a191dbb0ee22cd5820c28e8020bdc2cc92b0021f5bbb78e8d5b1045b43c482107b6cdf2d0dbf8f9ba124e761136e84a1ce9b0094d484fa620957fee615abcf8441348e477fcc64bb493316b0984de66e4d773e620a22dc8919621606c78ffe63b4d3db468688a05d2c5060305e203ce78059c49118577d4548c462680702fb76910eaff70e27419cdfc7b1054d1da93677efd4ca53a0becfea6f2d33880c4c117e2d057e322a7608f7ae3323eff09622bbe1430ae4eb25f090470ed5684ad9d119235ebcdb3e3c2724f2acb589d57fd55feb38c51f5ec2343e1305a75e0660c875c17f820675af3a382e2c3e47e5347f4172610855131b863296a1f0b887fea519a57bc76aa6df23d7fa723d3a749679d5f599c76d130c9f97a66f8d83313ee7c0083fdf5caa5fd459a72ccd671c3d54cdc681cc82f6982ae84989e663caa45ae7346adeb36bb7abcc2736b763c7d827a97c2f701992f11b90791307ea793daf7b20d0b57aee07b39270aa754d980a0b600946fda80db8432f6dd1b420ac08242ca0196960d12c2a00719c1ae439b94d43082d2624046a2fcdb36a93826956b827e1c2e6ee8aef4a5c5c2d5442252e5fded5a2fdb1715943b656dc2e84643bbd1d7e85a66d55d6678c1314461a71ec7635e8f94acf22c15f903c2fe3df71203d07a2bcb2b58f76d9b74f5ee302abd2a0cac12ae0abb0ad118db49ee5632a6e3afae38cb07831e5fd6243aba101d532e58c70c5f5c4e6f9a30a7600e75254ffd463fe55f947ca6d2af283cb5f3c4e7cf1afff93c707c4d037723a2be99b4bc39e9940d1247c9f48752772e23344cba813cc76b9ef7dadf50b7f51e76744be74741017857c9357cd9c09910f34ac55caa1b5a768163a6ebe8b289e315c090769dff8c983ec2d66e65a8b3131cc81812d8336c5170671867990015d7d66d12ef26c17c48d40d686fdd8bc8c7f07e87d4dbc7583a7c3fc85ad396adedb961bce0d497c2384fc8432ef0ae40df9b45d5b09e811a1aa5152035b26d4f396c54cfa6661389b37ec2a48711c33dc258a1f53ae0281633a98083bb118a7508d114fd003156cfab92284225f7c9f2c46db167386f730d7ed1e99508baa14c300e337013a6633fea98b4a52602153186d869acc0b44461b8face84c3be8e1856d51b71f38908bb1e57b09aabadc53ea2445fdca47913840bfcaf2d2854a0f6a18adcfdf0167d4ccf450e4a891e3485f6c58837e983a25d310392a5ba70acf99ad481f1f830a3b256ccbaee8b8227a35e8a58b28dc0d1da29a6be70ff16734d580b26606c1bdf3afbc7d2bc21ffa79928e43bbfe1ed7fb481db9d1b1cf91c7d7abda83ff750db30fc7e8bec7cbfb369cb36fa021e943b6b47ca28c9c56765e9f7c61e5d5110d898b05918bc778c726a64ccf68a60a4d446e104a32af659fe3eab134fbb3193f83b3a9fd39ccb32f2e2dea2da23cf9abbdc8f15f224983506056f87469511bff2f01b18f25c9228f152fc2310529a28c5553eb71a7a6801aab79a472f5800c4608be08b59f9e7152e3687309383a2d174abc57ba9e7267c834e657d741e73709fd77f76c0289d568a7adce14331bfad9a0f33a4ca976804efe23db5ced0182e968224ce30c924bcd082e995de57faf2573d4fda0ed66eb3ae0d759865d4b7741dedd3c69981fa17dcf3b8ba773bfbf75cd2445f642225fce3203d24f965ddda233fa41d66710b6f154cd4958f3a32a819881fc2ff1ca757d3386d408db447a20b68774b0820074fb97481611ec3bf3e264b01481fd107025c770081994c532457386e1dde683397b8f28d8307af81e240eacf4ca8a513044dee4ab9ae80e89c23cddde6ad871345553c3cf5a80cb29106d71839d1085a4b710fbdc5bc82c37f033d2be65661c56f33cb905bf0c12b4bd18c8e6f786430357e35daa5693099d67aa69c036416c37519b933c37ffd02a5f63e7090771abcd90f7d9e01bb9a3ec919a7cfa5fe38c82a80a59f5ad1ada62613959a2c1f3a7a0b7dcc2e5a2a32fee6e3a8f58eacd2d840b624199f7d1c640bacbf639708e3c9025d19c9bfc6794b5c0bd33aea9a67d79897e8c0e48f2854e44a3f0f6a9928c3ae400e01afc26acbd75282f76e5024b7af66fbd3097f6081cc020d62773e03438bf0d1dcff01f272f36ce1de013cd8e10b1279a375dcfc95bdb1fc8361cbe102636390cea7808793be4b2a13744110a504731e6dd06f0b740d556ef5891368763ffa4126389fcc256ab8cb9fe69d47493a615559a3cfbb059f7eb8e1d77859acee4b6c48a401b60123d4ef0296a888fb67afacb9cc5da7f09a912beca4a62b023f10b3b64bf9e28138d9c01f87c3757cc8b3cfbaac6358feb11cf8fcea8515b6268c34f672a3e83de3ddef7f2c5b5488546d26108b28e01074f50f180133bf2ab757ce0aaed3793727f2e987fca522f29e8ca35ae335544a7b9cde7b8013cb9992d660560b5e3a603f48907773a405e70f56685b9c36504e30181c096a0386a98a03aec70705033154efa3aace2c4f39474751e3d34b084f692fe2b0069179f0446d012fa9ad591608cd8da48a7d9c3eb06721fdd00e020618ca20c2e9ac66c59777c38088cd9ede70eec1ecf8ceda63d73edc792cd4414360d684bf57241b5d2dc6b81b5ee4956a6313fdbd41ad6d5e8edd070a21e755d6528af5865961676dd9f5940749f36c41fb8fd8e51b83e8af26d88358526b2ca4e1a2e1bdb7f9d361e6b33dc095d18ed43be423d466d004be044083623d22633eec7af79711f9bf9b8b18b47c4924fa9aed721ce2663a7dfa4bb13f9138e28f91c9d05cd88c698a00e34a80d0cbc402a7abd1f00457f2807404e5fea8e51103140ae88a2fa49d76bd4f72d6152104376652bbda6fa30dbab2c25a0e3417f61c985d7c90af74313fd1da67ce86adcee4955ff4fc502d24b0bc33cbce06ce002b7e5b367d9de5ad44f6b676cf27db35901071670afe22d54c9b1233db73836c4e6ac1cac0090b5c3a7f4b51db9de5d1734c631f49c18ded45dc2652548a659f19baa99a63d62f5cd9608b8661cf7fc88ec0ade0d13568d8cc4091e07c7d9d8544b4b521e616ef141187ddcb9f4caaec7be8d90cb66ec8ac2f78a19c48f7d18b55d596b7e6aeec7c3ec1222fad3d5bea16033b6ea9ff30f94e97d661e922ed23bfb9557fb1742bc36dca6b202f9218b2ff870b64c7aff4acd74513fcb8b1d456c917adcc57a88b77c978093edbdf8a5d4cbca0319f731c8b61253a77077ac2d575cc29c65290174ab6bf04860b8168737dfc9102903df24368f1f7b2e178eb3a0867537fbf301dd75b00070e5715cbbbef5f1164c30a0acaf78ea75b958af893f4cf76def228bc6ab77bb89d7977d26dd07a957c35321ebeeeb8e8b784947a4c5c44c85ee3dfbbcf8cd429f2cdc161c5203aab4b572b63f2e40759197311856661a94e1cc9cd9aca266af0489cfcbdd653a6ca84cd1b70175bd6ce932840f5f9dfba39dcca3b15b8bcc9d7a077cf38b4e43c2d0579de4186a7db488367c2afd8cc8732d7b3dde96a334335804c0bba48fd0465286160129e4481274a79aa46b54e93c2e6b557fb2d2e72de5f0f92079de6b46cbe80af70ddc05dbf944d01ef405129b75cfae13b113425d8444715edfb667ef8228415d7cecb2402405401583d9a714aaa3b8afb9b9b1626e82f85bd8d23c1677f9be212935ca19d341b726495f50d178a17db767ee7b105b922361938e6ef2420cf5572ab2cde3a05894170bb10df9a35a2e5a0d9d5a9078f169825924259a9ddd8cf0b7284105c4ac8453aea54056c6ace84413998ee6af9e2d8cdfe06af335164e90275613a357765f1c55c718d037941820d837b766264d093bbfdc7b703e589a9db324df79612fcef727e912acd2fbc12c395e98c7d8b1278d5a3facfb2093ba0a2cda2da673c300c8747da11574389142f859a588005ddb716964efe42cab10f97dd4a04a3260a5a6026825e1129294e92e7f63388d2923e31d8fc74a34a0a42857e41f811d3c74131ab73ceeba63417c3b902d4b962a476d8c8323527f6af03dd7aa2add82d9e5d21d4bd3b63f8d5508cc8ccd55c07a3e10328ba0c51bcbb616b001141ad6ccff3f3a52ae6bd1fd4ca26c6d2c219c7bf9e79d7a2e3c7ba9257c7b5092002ecd22082564eb9dc786681fe513752b2064882ce7dd52c19c32984ee445399c00e09bd31682a5f0d7b8268c65436ba0d4356018998a8dc55b108c85c25e42587866757b4341222cb7008dfdcfb23e80fe0352dff5687b3b98ef8289650de50556b045ccd304befccdb98564b82a096291f8cdf2760984f3a5290a44e3871e8295d4ce30812799d74142d12bd245dcf315f4b211384f454e489e87a80855f5edc06f7ba2ebd1219103f1ae4c0ece8e9e7b86b196566358b05cc4df733a2ca3e5cab2fdc14807f1aee61f8988252b09f975d591c82c0db757b294e16594f050824badd4fdc72bda7cc0988fd65817435a9cfc5ecf0ae843a427087ab7c2fe99ff5d4f65861a8bb8355a059593c638fecbf1e3a826ecba88b6706a738c63869960964139c3d0270f6aeb4a99ebbb0167d39f4efcbc8d84c7b0935899900a22b627eb81ea21dabe8162c59ef159e27d7df1fc13d46305e063c08e38fa1a2f902cf4a1ef9a9283f950a2b9ce2ef5120a77f313e7e5b123c64f0262a11e2327d243d216cc9c58fb1ef7b3994793308c3bd16c10a0d18170e663db168a09583b91ff6e79fed89629b3d856c6602382e5409d99925aa9c119ed429896044003f6012d99094afd538de684beba6b7652791a8a5cf3cc39ca1b042183b72a4339e9ae4c3196da559cc8660297bf7c499e329fb91e7279aa905c9257458f8b6d393ccb510c8b509b941841e1961a04bd5ae7bdad1b7132039f8d7582d268021d3a9ed91be2b17950d7a099dfe963834521e13ec9a009ef037c908b8fd40e854dd14a69eb2352ff34b3fc44cdd4cfdc9b2068c69794998649b60252d9ec53ce26c30323a7be0a1d9d2e8dcc9241d66c4f8baa1878a66b4c3d20318f7cb8119a5a146e839291b1a2dfb1c458b63f01f802ebb396276b7631605d285d631b0245bbb3efd7c7e23feb5c8456d6cee8430299591b9e3b0aafeae5fb0349ee5408ea192cbb605ca9957d1edeb73c077b7f08c421c4156c966017978faa5301bfeb8174e71731e1e08101ae94f23449880823d054c3666ee2df0d44641641d218e3c297868bb7b60d9d0a92abf6f012d403850546b74f4f85c1a0b4216084a12aee858dcb42edffbac874d5913fc4c19c893c06c9afb179fea443106df3a19bee90a03da1acb91ce8bb69102d4fa1c5c32eb3bbc478b459ab40428ea0d9c4381b988e037b5714621a2c733015a3240eb88844075a1807ab8be0318244ee29076f71d9f8a70c88e30f36c992efc24cf97666adf3d19bea51ee0ec446856ea36020bab08b7a543c33ac54794be993443b9eb60dfd9e55a112f64bd2ea993a220a46dca03c0d79634f6c63396940b1e7b052747d1651306971e7ef68338af2c5dddbcb20bab86bba3c2b43348c31284d9b759c7a62251a47203ade31ce59a9ad379f21f9b8279d35140f3b8c1b02a0fb61d1c10f7f5f8cf8fd72dbf29fe5c51026a557d536d2eeb105b53aea8897aa7a6f0670429f948c44e550a0d914072b73a8014b2010a6188e915f83981895bd3f5a0a3493aa1dc054fbd7f9d990dbefee196519f2ca6883d1118b85ebf42c4c50b655a7201d13516671a134d50284bff0ad0bdb09a642f3c149d889eb587d73424b1a32debfac2e237cc88176630518141aa95eff800710bbe87ba9ddfbb24defd95f2b706d96acb173bdb27c42d9b5a0198b2eabbc80641676ba36470a070db368460d3923af702771e00ec74270081b3a0bd4e043147b9479bab7ffc6c287bb0f5995a3a23f49393ee0dc99d4f9c6368b10a22322cc73741c13e90ad22260bb6e01ca9849e002338e225d1603c0f31949bc406f8a9f5594225739d39227158c362c3708b0ae5132b2224e2d300ee728f9917ced6901cac10590fedea57360968d08e0134e50abe98d3a12acfd393e93a526b6d6cdd88673aabfe7bdec8abd88bd6d07db79c2025e19661fbf91cfaf830f763b38f52a7448f1398926105ba8e4df2ec3e8b5089a60e6be3b649181c949eb2f9852670ad6ab8a9b538aa4b69d0ef48b3b10b06dbc8723b837ccb1d522a7ae506a04b72f50cfa0d8029744da6d3633f95df991d2dfe04842c66a06639cd166f741b5d9d5c794fe3761022f13ccda325af6e7a574a012bc766bd3f88ff20248afee366c2787572fd475d9f2a9ece7994603213016e52f93b13429d82d26d13b2bc0b584a4b19a5a664cc0bc5772d40f77cb956666e67125ffa396f8927a77bd2512bfec6ce210515b81ed8f56b4be8b677895b7e98d3ce2eb7959aceeb05926b0b2cf7c47c32c93cdd464445b4983eaab69ced1c1e33e60aebf28cec6e2f957aa635516e881ee6ef78862e828859161a6f2cedba7422d1f6b35d7c0e6be66e29510698b73d202c52dd1e043800fc32ef58e5b08312f240765450dec88fec10d5131b04d83cad60f921ebd85b7379cc879a4f33ff23ccedbc7787005f55e0cf19c39af55315289af8ae296630e85ffb7b3df5583ef8616a39011bf9e3008e02148d589c904ab567674b2c46ab30be054f9ae23201323e58848f789ee48d6d5f335941c3bc54de838887327dbd702d2bf7fa861dc1421bf8e76bbb4adf1207a43a155ed98cfbcee1cd6cebaf351d124c1bc1179d3eadcfde0f22a88c8989aa9db91cb79d54171d796877822c3bc2e1562a2443edb6ab0a2a7f37a14e76b028a6590d4eb80c30ccfb5bc114b4c4153b94e122fe565db7be43655d8b88053aec5eb9e2f65bdb00574971e4b59cfbe40db65204821fc04df783278f6e99e77e3888ea5591bbce12810546d759d278f5c90ff46e33d3f2ca3651533e0122c5e4135590d486ba75d4c6c8013cbeae0786b06c4aac200f828c8a6961c6cd8b538a82717996fe49da94f8233ad294faf9c3b24ac6737ac755b44be07c2fc96f6b688663dde191507238f2bceac46760f726fae51697c06e7ed9b5ce2cdb499388067a40388f59f7d87e37cb9053921ca5a26ac03b1f533367da375c4a86d21d7249a66257a9f6bfe3ddc0c35af0d945d7863fef070007f71c151e1e22bdfd4494841a7f405a87fe6214276c71bac5a6f959e7439650973e4072467a063cd51174a4373ee278e1eedc3b0525b8ba74abbe0a51bd950ee7a0b7f58503537e2931561179fd81f6620d96d05a1ce12a9588bd09bcbd0adba6a3b836432dd3950c29c582df42872e21225f9ac6c24cc0cc81add0518f518b0745207957b9fd8d4f974dbf1367bdfe6a757b33d6a5507c9ae0bd8483e4a5333d164d88fb4bba5d5280b4fed5edaeefcb198ff614ce7a3cb765dfd6a339b1d1a97f9a3e030d8c540eb64322bdfd77ab8493c5b1804716a94e973faa764e88fc59f9557ff259c8cdcebc62c6630904b0baab372ed174ebc92128aa5f1a316defeeb9768d8953f195a8a08e29185c56dd5624f975ba1c500d9e21e82ba46343579b241998baecd1d9d840bd48f094573a6064612bb4cf730c76199051b14fa2d882af6c2bccfc70d068deb1c24dc1fc5ced0c4f967b5b58408d1e0475d7cfec7395c6db77ef08abb88f7bf2aba975dd7f733362a3b61a1dd84d0af2fc069d688b404d460a4661767b7c6e6ba056ab141ffd59e5a39bb96a6adb350989016f8c6d3dbcabffc3958cd035aeedafbb0f1e6976eaf42cbd8110a3dd8b6871779a9b4d39618158b0876567b3306c12a1027ef9a5c4cf74f486c6e4d4f808d4656625e7c05754a54b499ff679b9a9e37d376f67b15f10001fe2faf3fd9f89a8df44ac7bfa64a7901fefc5a4232201eaf8d61ffd33814e7012e51a7bb1847a35849f522a00889dfb618038d4a35bca21f6a1292a921e0e7c6b87b77a73d00585df2a559aa3061a851f40c4d2d9af5e398a792f09bdd8b72dc03b4f648cd2b31ddc8610fda382040e8a8262ef3100d158888fbb2aca235482c1fd05fbf5f15ed8ee0e39bd643f3fd0963e77669a72f86f04157134a56a59404fccb4f288cdb5dd6182523db42524102b46662d011f34240237a017dfa56f857e732c8071e6ed4d9abf67ecee7a78162ad46393da94945bb9e91291b15d63871848a79122f652cd1311b5fb1d6e0d80b47c27e9179e7fc00651a8a4573a71ec348fa120d90f27041cfac1a3c3df5ca7fadd77b0c1f64f6bc62af40f5e47eabe93e4cbe0e25442b0043e3f55b12fbbef210827b03518f8401cf9f7d2090fe9c889bacf0c3b35bdcdda4e22a0c098a72fe06fada48220109f57d30a56a498c6b5060629f5c0859d98a5a6735067cca06c44e9351d531a26362006264bfc8c1bceec9111b157d582abcef55cb9be5241628dd22bbb92931ab09409f9d5e04f90250f9b4f16c648781d4abdc988716255429a068798c64497d20b22d0e380afe29ba2ffe570c9f2509c434964869e4800366b89bbd3950233276fb561e940276338d5f485953b494c32509e14b7b584002c889fc6cc68a92f262498fe9ec3288d2eea7a4288377af78e6f29a8e2f68501a57d0d9cdb246eaf32240cea76f93145b24a11289e0a143346f4f09285e8cb6d64799a83b307f8ff50d83c2de70e4d73ec80fa8bd6f689e53e57a6f6e5dad847d0c0a1168eaa546215fc45ecc8662427a15e44c356809791542719226eb21977f46c680c0bdef68f167b67af47b7d8bc8128e0d5b1a28e854d252f5b20b081af2a86369a710518a754092d1a3330205341c31279a96fe04a60c9abe2b97d9b953978cc7a12f30d2a0226f8898f7807285da2268f78cab075cba6b367af136caf5024d717a5cbd15f99e441c3afeed3c6f92130c2960ba487250a1538e7e1aeff17ae4451a27d51bc6943a6b1f56f41b27a56c8914944ea48cab098496f35ea1b8d44aa81615db4328fd9aafd9488c5fee59d2046401312dd60b3efebfd18f8f156168025c9a1bd64bd79303716913f754b8f8ed156f617c0bb6c28e83998f2414b0a0daee0f4ee3b0ca936616c638f3022ca543508ab108d4bbd342cc4845def43cb89beea0106eb8d748b6cf4c95c017e4c4a3ac25d17df8f525dcf903650e8eddf931554b6de7544e8f751ed159c2e2f5b82ac46240f60867cf508df4a693813f89ca9d0dc54851e27491527c16f83e5249e4b3f22c2433080ef379b5bcfdd5cbf44648dd9559b52a95dbf395aaec5ab17a56f213c2c69c2bed246f161dc1cda431d606573ddd67de005b2c9dd71c9d1a8f2da9bb7d928d76431b95f3e60fffc6c8a52f4c534489db616f207aef8ace4b05e8267287cc63357e603e2c377b98e2470a7f23c7fe7e86e80df2c4768e64ea4952c696606c15cb24cbc32a69866c524166c55d0f81e3e46fca39bd4e5651eb01c90935ab000ffad5d6735e85005b80a4cd24214a5d6018ea4b858a2e745c7552d999ee40dee0df7ef9a01208c0094b1794871dfb90ae984ab469038802991a76687e68800a764ff3123b3f0da7a4fca4540b379c45a779a0aa9f935336a453f87ec801d8b00063867ba8be5487ba668bc881a6a704154756625499248912dd347e642bfc949f7e801b158a3444cd9f06473cdc06faa139a002c3551667f22136dde5ea14fd273509d0ea69e2a14712b6f151357c87d1c558c75586f548c7b871d780a425c14ef869e8816993695663e226573700d9006aa4f4535aa75505f2a144e2ed4134376485125184b1f73a9da58a34b12226c12265a0ee0b4ccf682c1b3779af32bae8be28c10822e4a027948ac60f2b20d974c32afcafe314563a939ad2d1a6bdd1553685e0ea359defa12224e5eac09504edc2f99e3290860633f9e4b63bd8f6e6aadc1ef4cba681aaf996ec242c3519e4a2fd64d78c9c8de488e96853f347dbe9ccd45899765898c7b2e59ad29ce60d2b43c5309fb2a70446e1c0e13ce58bd58ec20a69911d7655e984ae43f120684b0f702d870c6a92c349d949e9b39fde5c9b62978d4eb8a43f6bd41a996b60af63218ae4403cf764210cbef154efdcf6df34debd58f1b66ea750079f0a97b9368e0a360d92df70e09365714acf2114971e912dd5777d1ccbf2d2a83d5c038001846bb18837b74ce525150e30bc0b079a353eb1b27183372b1ac0be01fa3e7cabd34f92318d3fb5d33e6e8936787da645c29c41fb3cc03a235a85dc4bcfd6b4e98073ba2d51f14a70b65f5e62bc007e76d90b3eb086e91b6bde38fdbe70fde2dde1272cc665b4677ff6f5b6da432aa221ae4217aa11be315f9391895f8c17ffacef7630d64537896d79abe4731db3dc2af978b478f43bc7bae44e06b61f9a528035598837062f7807e51108822fce16e1727566768a157565b7369c6151113804459f7495c46648bcebab6d8e187149d98a2e3360a0ecbfc0b607ac48160418bbcc1864f2845f26712844c931945e73fd3c819ddb145163bc851ce598770d4fc1f1f298d2f32d76709df7142bf3f29c5697e7c421b0baa043de67baa9e14043062b53ac425091b395a975447678fd136746f08f592427478487c1e99e52e9c75c2d362938bb478333b6a3a60d518f8f15222cc17690396145d0d6f8cff859aeb94371b12cbc0dbafe8e7be138020143c1444d0211f3aea1f861ef1922d8a15380ba9b46e141255c15e9e4aa08238d9039812855e3ac7bc5e9bb84dbd3016c94430de1a0d53ca5ce8c135db3fffe2a53e44e1b0f29b629bb4f52fea7c0ad3dcb59a72b569a43bfa804e05d07c20b7813f1902fd2b07983cf9a13fa8655fcfd937344779f21d62651b891d95ec9520a409d2eac6d3d22466c8be96b65512de6fa4f6bc0b50b6e6c48394bfbc4362d3334812f328ab4fb6b372949f6a89a23f8b2cf6a1e5447f9e9a8854f462853215981056e5ac11ad9384ee58cc6e3b0c79b72c800288a01ec4a0172092cba8cdf5df0787ebbb0830296ceb513f491f2cee7e01c5744800d66a7436f01106966c5d9ae21142efa1c065c260d18fafb302f3d46fd7a010c6c546318021e1ea4167b89c43689bb7ecd0e6f6cab5fc5fdc489233b6ca24a210eca212d9245d1edb0b80df7ea805d6564a3ba0271283dc611e72cabadc61848cbbedacfc66a08d84716c35080f97988d217223aca933289717ac1cb605a80f7e692225504f8951b3bb4bd4cb2a7f62459bf2b7c976f4044fcce3a76ac1f7d4bdc5bb0b6c5c2976fc84b5e1047cc41ba48093ccd7b6b23b43ab8812d90dad273891877f558444037165d04f67b00027340f337e0ffd68836ef72be029b6b089f8ac86f46f9403b40cc267b7edc5e2ddb7815bb72bc220bb09cf91bd00828a0c3cb79d11b50e9dfed861d15e38b6341957f32f5f19222a18435d9d02bd3eea26b622a74bea261164a8130d977000d9f7b855c4ac05f6d50d43b79336d5bf7ebccbc5fc42f9d5049035f92e095fef308da00045dd39c8ff63005e488b29f6f7683210412896e631445f1d7fced33075cd402215a67d31767fb5c0eb2edf1df30dfdf6b73c85b3ce93cab4ca9be8c67d9214073e821d9ba578f059ea87c4f921e4fb7e69110ecad840ea011e9bef87ad8de6eea178256ba846b0916e1eb12b724e04014598780899cad7fadd7505c3e55d10919c0e0613af22f526e42ffe9b8d149ed9b1b003587d2f46038100cb3f93b4f2eb618df9f49af6e4f322183db85644a1bd13f333c94d7b4a05745cbdd8ca45a613c6f6708a0d7d0ed603b03f98e95f33a923d2909804c77dbce2aad0e329603fb034ae7ecca9e006104d4650b3cd5f81886f219344af5d823712042a726a88b301d5784d40c67f20f8b1b2a8e4c93dfd5496581505204cb7fabc772f393bb4c25117b5f322247d585cad46044c9c3069904cf25f91af792840dc898a0e8c83df7039bb17c433d929a5919a80b974c4b1823d9140094c82cdc17a800ab6c1c85127f9b7b9accab494194f216763c21c1e1297dacf22fc8f2f8154a9acbb2f662d032964aad0c98de9320da00a936efcba3c934657f2903ba410718864d78d13fc9014307a74d05cdd6d77ca055831f94905073b51dcf0b571360728311f78ea3cdd3ac35dcbe453e28906f9dea726dc6181ef81eb513c993ac531138935a3c10856c9418accfb0314997413689337e22407cd0a4a188778d25a5b557e141cfd5cbd13f5d9dd114be4df070bb01dd30377ef16675defaa5b2634d0f9f97987d9a33c5167e3cf8226c9c2f57baa730d3ea8b3be75ff9c7f51929643a770c87150365b7a15bdad94f72a526ead36c52e26fff75dbb967b9eaa1161746e80c62192cec76a7d5538b65f15af7580513134284d11eaebc2c83f319e5475980b605d152f8b5c0a34be43317ef664f4f00841135a93f1336bc9240fe752d4564ab1d83bdb21aa396d925df00975963088900745b080a8f6ac7217839cc4c8bd65e9e862160a12dc36bed1a7e0191399839c92099c85cc943a8474c0e4f0bf8ea04a10b36bb9e65460cd9306dd48258cd62805136a6dd0b5cbb9def29852689e3b7aaccb20cc32d14225f67be7ec94a1b739ea941455cf04b96931dd1d410387b557f9949b18da4ca7531d311c75b5551b744f20181513e250034d67b528ef99023d58a2431a8e0ac195c3b38c6731b279eab0bda61e37c29974c14ef036c25629c674eededc587df5bbd40529f3ef9b98b7f889ff056904943b07b805479bb1c6714dc8fa83c87a16091107cc1f4a3cb187f15c074e071d96b3f5fac79af477aa3b8b1a8691cfce9784a0bd73eb8bbf9d8b881e44fcf9e8a86f1167a97bc54d2a7f7b447398e33be97fd2ece3f8ced7c835f2aa344dd2a74f6ec88b2b6e177875c74562ab6567182bfa4abeac052b6afd7ab7bdd2fc8d364a87afb6efefd2d7eb26227de664942bb6b6f0191c4df8ed93d3e5d5c1932b08f6234e3a62e1ed49ff07ab498e3417b7920e17eaddf159a7417e6ff63cb6f39eff3d4ff5ca89a21120611c5677c2c0efa2b78ed6b35a444797dcaae8539c45a2c83c843dcfc35f833f10091418bced14e3eb7fe4c7d2baec7ade52b2ea1ed93f351bfe02d4389f51ffede91f5c33f66eb2693d0e98bb59581da7cbe951747105682d232e78f46f578303436c2c6c078afcab31957af13d60c4c31155cc97894273366230e0bedf8963a423d48313e250b80270d828ffa5cc9b50a708a4be5bc2f0318b80d5fb5de2d8425d5de2dd5b90eb5127a8c2c9956388391387954b1047aa056b6c94b13bffced9075ab059ee96ab4614bdf341e80abd4efc7d122f28787ca53ccec0011deaaa704ccd2c4215347cc34da525b4f937188dbdd137df599754d246648e0bc791d0cb215ed9e88f70246779b7db2985270a09812a0c40d4fb92522b8b2155ef3f5fd4678bbd58767fb7d7a5a7b39bbbc7be735d04f61887bdda5492d3a9d645ad176b47cea41a26b120bf9e2c9f79c5d0faa7a164d383852d3fb7ae5171d8eb4f77898f1c82d1a244a3e2aedf7932d4588f267d9b10b85fa06dcc4473a8ddf1614b88445a2aca1cf7e9e9706bd5aeb9b000a0434fc835404421a97a938dd017a82c1826410b590f457b284bc1fe4de550c692b20a31223dcaf1447f70528630b14a19b85d4fb48458f75ca34b478435fb83e13edd79c1eec1de17313c867bf4e00b61b56f633540552c6f0b9ed45230eeccc4921719c470768c45e48c209bc6fb6bd4c38afad91fdbe308fdb24a5df4b28d739902a4a7094286fc968438657e99b1d7b621f0c7affddaf1c1938f18db5ab59907114e60c06a24b861be315bd0d15f5292d0d9ef43215a895f00bdb1caef75b614839221d5445966ac0d030d9a4233b4156d8f0e83aa7860ac7967e167b21bbd7586e4965ac9e6a4e650b0d9aedb944d9862afffc270b5c6792c84761ff155047291402ebfb7d26b906b65c371e07a4a065cca6f8bb7f1d4183244c0c606bdc9ce633cded1cceb6347b3670433a942f2c18a877c536f775072677e25ba9cb2dfe0642d7cf8a9db7d628a69e15d4c15a28e034c8a3f734046b3d09c57e364b0ec4b2ad7bc36dda91f0ae51b0545a1a8efc67d5c13936358bfa6971c14239db16d21aef2944785371bf53c47669fa39a30ab98865b0b007c6eb1095dbedc267a820ba9e56cc3b9ef24f7a440ea970e0899b57ea5258c43b2b4dc02ae620ff65f0c48cf0c044bd330fe86e80089976599c3d91aca0a6a08f5f33df86c8e10abd7ecc1850b3e7fb7946f2dc763d6fb362db58a970cb7dd82e9aa6b81f0fc2f873a204bd35b6d1fb8bd43cb79cce8c6590e1c19e14154b2becb426cb685a6b0b98ef9e56167374979120fc4493a4275863c52bc41033175cf4e94aaa6944722114712cf0f6a571e31cd8144866aa2602879659a307b675f0e5793877b32b6d6db7a2db3058b1471cd270fd99ac88cfc09996f18dda4f9bd73d08cc72d39d8e54bbef4509a2f758cff232611f0474e336a6c42ef9779de2adf6c8361048a39cff98ac3eb37ffddfff2e68d8f1387678d839be716c4af8abc66012702f504edd87b227dfcd4dad71c1edc236beb3308d4a237c990697e194a0aed0f8ec71c140e90540bada5e1c19629d76126b2c858ab6370914598e68c71b026865df9d6043d2c591a2fafa927212b69666cf539a47b3906747d9feac5fc6e91621454b08c0fdb43ed0c0899268e16597986216fc83c79e1b266cad42b32d324a0fbfcd501ec044b6fd181f3e7142969996d0b7f93e6149955e0b9309fbc3f0a4d70a1ae6389c6688453b4c4f2a85e85bd0130ffc169b8583d694d565e58330d125b22d0d961c8638919991084f6d9e96fad1cd844977596160083fe7814ea6d4456389982b24a0ce6a39e5df2c53d1f7162c93d8335bad25b36898ead329848e9b6c5325d4a8583bb3ff00495d4f138f7733816b208edbcabf7a5543fa1764a27995129494895d02de29a10f12db1a7c950de8d31c2a86149c1e0396430a1658ca220a6755333f9178b21af295fcc8f5474e081d83e47975d77374b325f68d8e276672783ef168238e7683c8222e1aa601108ac7edf415980faa1e9f9820dba28d4403e2d78767564a3231241206ca6d12496f30314253b19a1a477e314a16dc8c0223b60ed823606d2a0638b19178a8ae690bdae60c403c76e46d8c97b1e010a485c9f062f0cc4b88deaeacde714e84306296eb837140a8785f9dc6acbb879de001f2517801d7e0ece131774fbb692932c2c92be824928adf23c24a68e7240bad554aa12a44fd5d4efed2d96b4766b4902bb57ec0afe0fab1a2ee770b191efe87395fee284ed376ca7aab68ab2370a6b52e49e10614dea151465a99fd761f89f31392da2d55ee5675918b0c1b0493a83970e6238965149d3bf6d3c16bc093863db6e293f31678f18073938584531608ed6e5a1b11c3b00228af7def4593494e9b00bdb3390c955554a6874267852b4b3d5eb5547fea55f2f77f868bae4ff4b505913147da4f4aa125540f128f9cc9b2e557583e0b1511cd3d8d1a96ad4b6c5d90629780f618e6503356159ea1121702eacddf6094079bef8e1c792cf95fa2822cc46909bc4e6c2c70d4c0b1075e4d9aeaca18d2422c1bc5033c84a2f2911dd956b7298c26f1f17f41b0ec0ffdfa1b8dbde474d647b59ea60903f00c33b44a6d190f388bea577c344c753b47766327b9f7bcdb80bbdfd5b309ec5ae66917998478a3c116f60c389e00b380f9b6a80ba3ab5982be8ccef39e30c396517050890d877c72f816e541d00a7d7c070bdda59408ffd23875ec2a0ab036e8bb7090b7c7e08e83d32924d33d4ead57010e4024df5fe4b02961ca44117c246cb442071c95f664ce7692e4be280d625adc9d3ff73b846a6bd0c8f73ae0a417ee7204433b5f92bda4c93902e46d6349945a86ce54c2b3b96f3ece4d505d971c0d73bae610f82c6f3d7d61a3fb468b8386299edf0f5c7ff3bd3766bcbbc8ab09195a66ec34c41c251ebe3460aa3c1eda404d33d5e910ca065b363b8e5de961ba3ba00d74dd0d5943f23b1c55d2a45e657e9c63833c2ac3e5e80591770503957c9e2ecf8dea6bd3d2c56515a273ec8994cfea9b2a9cc8c27b764d3d230c9af37f03d5ab0a57fec6cf4913418d66a8a92629d34183be83f700749106a22c193416030072c9cd52656c8a15dce2bd12ad638d1d9148861aa9df8aa1b57996af1bd945e52379a333d1702b3ee9bd5e73e993ea99ca998aef496b4b1d2297d329490ad0773e89f5ab38c9f31ebd7d136ddc87f4183374e182d6dc633f9f28de847ba364213c905f323dc221ee8f060e99fb33be1d767afdaf25b084b012850a0c6117e2ad7dc803806a5d2a983bbd3b2a23c0199cca25af2b66dd9f4780f617aed3e8fd8f1b9d73ac8f59415db5e97f14c204f710ca44e42139bd39eb3971e13e9de3f48772220b2f1cc517abe155643f8ddce3bf437dbd5184655cd8f737047e88301ce1587d069dd7f0521e476f29a9856def84c282c3f87103e0a51b9dc997cda9e24890a496869e1c444626470ddef2dadc6a5a2bada4ad2b7d2cfaa7d539c6c738ccf82df2b1627c28e9d729e49ab071459e1fdc2cff09cf47bb8a77c2d7375ba2ca98aac738f18a55b372b122eb19dc42d29aa356fe18e0ece19ad052083ead5f1a17e996a40ecad1a68e683fc9b419b27d8c00439a1448d8482e1029e6302b525070b7b67b4e7aaf3cc6b9ce703c04671c52c98689b35ffeba2aefbb6d6279cd0b6dcc88b9180d2a8e0a663e451ce733850a38dbb278ba4fe9482b2508d9eb164fd37ef25964e9ea7fbc8446b6c4346d51eb234b08cc5fb4e57d49f737b9b6119e051c1b0ba3d6c19c40ce64b68ac04fc9f8a97ef972ebaa0ccf017399af2e0815d518b8ecb4d19ed7db30e99dd62064b136f2d96e66edfc55fa20f1cb3cb70a12868ee1e5c17722654c15e74da7641728005b2a138e9f4b930668ab5163d05081f18290e766d24a4e34609d8b235a4d420dd1b54bb58d90e3b8f4682250b8f4f66c1ddd8dad6cd992f6bf1854a8bfc3a72207c95dcdaccbd2a971d28ff0cf690387235f7203a1ed4febc7e8a69e4e73b58bb264b7c010139df84c80f6c8b63dd277d0ecbcfd8ff93d66d66583d29f778b81aed1c11092868a1bc72e4634889b65040830362cd2773fd2efc38bc9457c8c75bbd110a079130f38d0057fba390e750dbdcaa18ab8fcc679664cfb0345eeda3b2f90f2655e8592b95426e1a91c2a00b1e91e1478d618c3a75343489e00789b311aafd4989291a0f95b05b6c642e42eceb6be82e3df95e1b1725db9c3dc5d4206686cf390f1875bcca454b5118277196222cdf04c5d8cb1c8a23f35844aa329ac10753d02dda2ec5f2b0b6283c4c91125f2b64c9ccc000ed29f756128551caf52368aeca6465afa203550640fad21c79714a3d0704a13e2bec7a89efb63c57664343a3192d43caa2f04e49ee2022e85bce5bd810358fbf90487e8d4011227c199a9c483066e4fb317dd8af46c6187e55b70762e63bdae226802d20f3ba3f6055e197465aefa6537acd2c0dc78c0aebbdb2d4e8b34ff00070e12ffca9748dfc6764482b1f0937080e4111de8b9a400e03590c3ba718e1fb7568d627b16bb52603751f80af05a79024ffeadcb24879fa013d7210ec6b5985e63ece346c5e7ce9713fc40bba189d7cff44e5e228a01952785593b31469b3269f483e48a30f1d0ef2ca75aa2fc2b4ccf56fbc90df8ea4cde65494e49aa01748521a6763926ac71b1ec8c26f66b06fbda6e8b43e43bb8368588bc61ed09c5efa72b309ba37076c0a0a4e1b04ae2fa4c2140eebbf19953639284b67cfe6ee3e0ef1c82f154431071650620dfef846d2bad030e6624b8392fb2e55cb192c43d2f0e373f7c694d1416a3350ad63f58858e5935823efb44ec484c5db24c452080a90cb24c7bc9ec20851b4c1ab90edee04e973809be5f748cef2f0758cf95ba89a71ba13d27f13f2f1db1885a56447fb79e260c56b8131905e9cc36ca676df6b4f7ed31b0f3f7413da720b83161994d5137459b0a6d6f2193ef3717cd14bd349f8c9c873fd594e7c03543139071053086089904502e0e9a41eb1f7f5daea68212ea0d6e9e42e04c0542ec969c7631ba49f3e443aa5c7ea96c40c60bc2b175abbed4e0ceca35945210f22d773b15009d9f5a616dd92946eda518b4ea9094c22157bbe71d4b0371c88e8e9dc0a79fcd14e4ca484f1eb7521c0aee2053d83f0b47864252ee1e983dc92bf798490fb7f2149d5733ce3db3fea3c905ceda983833cc07f319e20eadc69351407965adeb381ba45d80d414d21fdef32d062233d4b1cea905ce29676e99cc79dcc002e70d380e60f388d51acad0c5f778107c23e500d47371c9ca5e596ecd715ec4baf0d630a23a4153af80891a4e3b4cea2342969a125457135710796961fbec09a93075171ca2a98ce2391f02d5c4bbecb530930aa5671ff732d6d330d42eb82dba70d7bd5799b888026d53c5ab0a5d63c97ebe2ee2ac6a7bf3d85c8bb84d481306364d7401f76ed5e040500b462780616bfeb441ede9055bab0e410d2f676e68d346a4e5297b8d3ed0d239ab155728d5e67fe5d722154bc1cdc60f8597d7799987c0b1021a4c82c9f826b7a7e0586079f36d3c184be6796956aeeeafc66a0e99fedf0b6fb5de52c42de6fdc1e6d5c013a43ed71be613ff6fcfbb2164dd16d0c0765cfa9319d7fd0382792d3eaa2f2fe778e949d62a8a1c9aecdfdee82baaffa125b5522a0ed833d06b20aaed71f446628125747db601d03c7314140f8aa2005e64314f522ac6d7c82e36f2a6265467827e2935ed017e610229c13b575f42b2866658a6c36374b975135a37e9fbe7db4404ebf810ef7066f7c62ac1cd8c8ff3c15805370bf3510f2fbc87b34b4c557b11db1804422f332fccbecf0c39fe8571a2be6f35692121d960c8d8bd8b76e2b2430c9990b4f818fdd60b00337ca18d4138dabc61a40d575ef55510215882ab47bcaa44d5a993a16da446173d044a06e9511c83c2dcb63fe08db0127759b4cdb011cf1cc5d68f902cad88424948ab067009ac9bc3ebb62151e3b9a5ef92c99243f1d795d8407f7de18354da2b8c9b7349cda0487e7118927ff53b2dcc54a776222d502092cf93c12ca50910cae16bc8d57bd42b489d87865961a7f769bd325c4a068c36be9505e65500e453d827ec9b6effe16901479d78b74a816df89abc9ca93ce477c3af117fb5975bb11deaf0fec06cef16b86b68ca3f13f7a60b1e4929178d35f5e645def10791c560c8f064e3b8c3bc01ca74bd809ea5b74dc685b42cd0bc8b3994778cd912511cd0850069afa8d23162dc8609c82743ffcec06969408df0452437deb35614db518556999ffdaa311586cf7173c55ab77db58570168c273b829072819ba2c2ae355484aa6fbcdf5a553bcaaf183d194fd8c6ce51df58e0e7746272561ab3478b01145c5dd6a3746551e69a5cb75361dbd184a6fe3b65f92bbba6988cacf130407e37c99c6d57fc276eff14c40b3045862e63e63b5b9fe81f583f58d03d02ea1ba19c849d429aa79787a56ce6e7a86322535aff634a644d359889f0475f8e6b79800471304cbab32f0f3ebb733b325f5edb8da95df78ef6ceed92377486a88ec81b0c37257ca3cd9fc769f23088c3ba4cd3605f77ba308e97f7fa6766dd4603c7738c356e1d7b36f56d41f3c25a083e72dfd969a852fc190891a74214349fb69562ffb68b36aa231915512658c3ac9f2a2c1377712b50cbcbfe52403268c1f401a565a0641c7bb1ced2b6fdc09e4cc722ad83a687eb995598f8af59720d3fa01bc85b4833563f096a0caa683741f4cbfde885dd89fb7b20aa2d7024987bd188e5416825301d86123bc0ef39135c7a3f0e28dad8de98f4e02f0240554d25b5ca6bd76bb6225fa5a08e49244dc9988be5d1965fbef9e94495a6747298d7f33b9b8a84e2a4c9ef6af4b802acac18526987619e09ce86e900b64e83d96ddc3ff6cd375ffdc58c9f346cfe26d2f7b48563c37796df6593b274ffa3dc35a4dba545f20ecd6b2e4874bc55bcda23ef12f39c2d1e7ae8015193df44460618157465b60f6c1c2c0fa5046920504bdc10ed654508c4bee9e00bbd325f6d5deed02c32a53f3296e5654372cee007721f13b916e43657b06bfa66ea1eec0e2afdbe0707a064bb731f5e5802ce3900d8c0603d1eb5ca11bebcafa0bdfd3ce04ddae776707f916b27e8224557f806e17745ae9df26b413d83013ca511e96027fec11412de148d4b673ceb0c5df0d8812c13890d2e3cb10ebd460f9c620e1a354d58a36fa9dd6218ed939b02cb23cc04b087a7d4aa6d601d36f2e6e1a03e5f497c969e1744af136b51761eb3423f91c20b35b9f02bfe6d0fc2af37f68aa7a494d86118295b40236dddfa892dae337cdd2bf1cb1e085deee0d256d723d979fc74fbb7bfd8eb2a2eb4364ce95c63f5b742fb20ff7992cef6f2a22defb1f747959718a0269faea870ab64408df838c4c3edc618e18af691445f64fc382f84bee2f8b46b6285669de8a5178fcbeae44cde5affd52197f54c8ccfcc8468a53f1d66024a870b6c71664584f600e83029839cb8284bb774019a173665ed29f11cebaa0b387c074d6803c6e52bf083a5d2a0715f7f2d370baff7b35de4f753582daf8c247962b1c85ffad6c891ad7d2d0e22daea491500a4cd5a0cb525ac656598dc4c18f8e27eb90f719f8c3f6e7844d2a477767f7b869ff1045f0e6e938810d02a1bc4103d7d8cc204e075e65c47881b10398a570b50961b4cfdac2769c6ac3d388ed4cfacfe9587e5c4e209549684760b9f7d78afd8fcf98ec27b63885ffd7bd74a329919a57a104109562df538d05bdc067cb4ba46ea178ecef47babf30677fbf34d273537726702d37a0f97fae6d17443908af94a4ea457002e89d9d1888a254bba1eb5b364f4c80da30050484b15bb7935a06056143f32895225ac77119d25b735c1cf6d71a71f101a0e0856443170c834b344c18ddf5323e305d9db55f7ec5939c711334dce1d64f44787aac03a04cdbb0156729b40b64ee7e3e570a709b175cc5b8a7078bdf6257a4d434fc332df57ae191e7239899fd77cd598ec0fdf31460d4b49885a68c97a1933aede95cca5614d5e34c4cbd26c372d82f883ae3cea8a31789941f696edfbd6c7525db9858e0f82de4d019ab06c2c7d89a52db13867b6723966029b6dccc12ecdba90843093845bfd5b4a5d859788fd1d7ce6e28cbe9a5b40a8c3d508cccf6361512f47878637af8a7810fe61f306dbcfbf6bb88ea8d7f16d2ed48133c8600660207f4525fa236fd107983127afc36dc24bec5649912fe65fec13941415b07ec3ad859b05a695e7b2791caef5e49d0f508bcfe4783cc251d8e1af023c236c10456058439025a342962b3ea7e763610cdfc6b3a7c96a2b945cf1ff2cd2c835485bff97672439f2a9fcedfced9f106c32b09b59bc60703f6470087f62dac55e77ef457b53cf326127491e571f026c2f8cde2d3604c52e2a45832eb7647a5e2039d0d1f509834ec6e9d60e26ec5f37a2f7053fa29f1de51e47d130e5169de4fd461cfb4b76b8f8595c36b7bfaa07a0896a5b6f466a79f6c5b4974750c7762a8c2213ec2176ecf59ab0cc2effa63b113caf753d405f610b415435aaa3da48d75b2da2bc2d1dc3dc3c7e9a63e3cd6375da722ac5a73c4dbb05ae8fb602e85c67ae8d393b3ef70b5f8eda7eb93ae4aa0f824d540de5e91a2fbc4d25bd07d721e5e629084f71a04f1d67416b7d7185c53fe39dd436ceef9d01241b4cca952c3cb46bc2e88744d153f34c0b591fece10640a87211a2785892114c0f1daa26e722b7ee39cdcfc1c147f76efa76a07a855f3c3f0955ff9cd65fce8e24e9c973db5887632ae7afec037a50e17b02a799f2bff9685c3f5ffeee702e99c4dfc984bb58f51d1658103acee5873bf82cc3bd516e2e85dfd7d3d755988223f79699b9eb3125c3fa95ff5fed1500ed2b8b0cad571dde47fd5feac1b9f776d5c9414ed8d26ec04b2651e1e1f0b10e48119f9d59ce38dac16b6b3a80fed6fee2cc7e474400abc0e5875da4d4c40277101ff9cb3d6564ca8f6f6b5d4dbc93eb17f586283a6c2c33f036bbeae61e8008c62e7fadd92d151a50697c1f23c697d7a8ef38a1809ce5a69f39ba69f017272e7d34e2ad7b7620fa1baaa9e764079928bfcecd5c4af617d4ce317d562ea232a23b1b19d479d083cd57e87f55053c4120317557b4ccda8e3b19f815b119226dfd7865bd680644aaf2cf33a47da526a0e81c78c20910fcb669efe452401c53b57356afd1229afccbb99c9331148439c93c643d72b861838efc8adf50006e88cc8be415b64739d55786d83f641c97b685426640deb180c454e1372228c6fc6167e80e01777b975a22e3c48356b74ccbb399994a6f8e4fc32bd91d26d8f0e78c91d4c853c6b6ff35c18ed93a3b40b71789d0b045299b29f37828daf43d3d1ae705526f0c3d3b42083e847471f66de3cb018c3f50489aed65ea2dda7f8e2511eb6aa12388fe80b68d897db7277644888d8f7e84e39ff78e03bed918b727ad35269335e68555d822eab7c7b38639a4139645f8205fe88349326c8faf2e7737b74c5d60de2aebffbccbcbacbb58df7a5a74cdcbb5ef90aaf1eaafd862cc67f42dab73855011c043c78873f3af0216ce1b2b8032b5c23b0a43e3160f9f0e6e3e8cdc07457c6fa3628dd72b5a150cf3fead105bbe9b841bd72c9d801227a29e7fcb7288f12289c730bc2a1ee4a6878e56c9f4bdf2516239026b88d4a5ab0817411aed08b12dfadbc76e53ddbea7b615b9d87a4cfba4f9ce62f594aff1a30721dc374c2299f390fd4e3e9108bdc4281f85f068b8a832fa9bd64e712544b2315b42d81c3e335f8e5759ca5865a1b45ea466a2a7efa82d7f4d421960fa6c53b11215839e20d65ac47468cfb7fb1f333b25292d54f7842290e8ab22c8363d3212f0b0a165237294ab91c6f58bfc88300d1b0baecea2cf5babc3b6ef0f973a234ec80a7a2f5b559b7d91c99f82e45252e7a7b63f69cb0d278269bc523e16ef2d7dec10883f6a2220b1c849dc731d13abb920d59fa4bfdbb18d8a9abe71e2a31f3ee7175388785d1e44a69fee27a820e5e7785031a05333878183a4168480256406890125fed87ca77a1fab4ef6583b4cbecf1e7b2ff2b604e3860bb679a11e2ddec7f993abf2905e2ffd5ecd9b5711f0ee042f22240af2101b5e29e62985b1a2ac0c51c7cef44b62476410e3976b326db1fae13c4ab4b5f5fa6bc1e20d14d2c83943386dfc4040db1bec83fdf3e7ba7e1840ba74738355ef57a8aaa2712822247c9e3aff77bf59425458445e4a0a92d6992a7d0c22b97564f83ee6ca33931389186f759faa395b644086654bb9affa5301604f708e5f0af2441b269131eaa518572a2272d148d9ad32f56b5ace8dc96093c4def4d2a91c33998e0b18e09cdb1c2a228946655f69277224fbffe10881dc344261664ab005d0224308ad77b84c5e9e7ee7b71cc40cabc7a201086572bdbdb6d7a5b60fd90e4daf25778c7da75408336e93e00dd5f206a2e2de0c24284fc1b0a5ffebb36b766c8298ce231601677bd04476a86efe144fe6e580f904020ac9d228061f22136a093a343c3cd442a54428f0e345849345af104f6c0a83cb44f1bf76dda9ec758a4623a120612097c74aead060778dd39629b6c4d772116b48bbc5c7ed4986eec15465201aff25ec63332beaefbf9235e2162e9cccd5c9ad9a08e58c96d4075488d5e383086d58f1c2dc002ca94e09339fb901c3fd6cb747486cb37fe1f20041f9c6b2ee6cc746d28590a2bcd01fe04a3a801f081d6d00769255e584d7af5b1a043e4d700b7560d405557c3af67f1838427c01648847cb29d05c1693d5ea04f4ec3bffcd8fa938cd6de857a49193dea3a1050ecf5a0bb94213abce7934f31bf644900e9465cf865868edffa4ef92bdba5a16dfd48a997cc6c4b2b6c4d616b4d074c74e166dec166c9a4af99ed5692aa419485cd3d7953e18698e139ec7307b74d8b84c9f94d86fac73a5dcf407a2b6456f4a7a111001d3a48b06a881e15f171e6f7eaf519c813a9264a86dc2a7d7d45c702101366752bf26ac066cd33a337c65c76c93f4e1ad7fc9bb0f0ca43a83ed7cf35fe9ad932d7bbfd79340c3fd8d61f84b8ad4c2cb605086ed891c5fc3da0381183866a179fc955b0cf88f1460e620b492de69d53a151c8d44e35c3d65bdc527f1855f13b07d45bc49a48362a2d64512432c362492671ab74b91337fa6590b739483e3a3484a2c8eeffca75b0461628471c25da07ccd4db3909b85e5a20df09d85ac01fb545625dc9cbdf78806796b5a38e21b812851dbbecd92e3b3594c4bd8f39e59085cc642e6b5a1b2356ae15f4a00ff9cba9e7c3ec742e760e0e4520d9c3c014b677cf5aac74c1c9500b94b02a98a106d0e8357ecc2f2ab363ae0d8c270c9a543bb257f33469b02384bf1a4843890ab329943bb10c43aae35e5d358f97d5a2a8f2ab8c36b86dba276f9fa4e607b04afdcc308850fff9c3eb46bde66026c08c89dedc7b6d96e91bf5fb3eb550182b39d5c89ac7554bb8fda0037d29f89f9392a2fb35c35b50efac2064f9f540fa8b78307c3d7db0a0d292c602f23f873220bbc5a34c2d3b6dad603b50b0934c05a6db27e46c0f85ce7493d98bb7ac56b24c54e94675d5517a5c73616e178eb40d5833d1f021fa8baa4e86160f1bdc8ce0d0ca102dc2e36008b27493dc0436c97d6e2976212f229713a2d33ccbd13921ce0decc6adc61bd398c989b4b37208cca4d57c9e524bb6976d7042811595439f4d58a85d98a36dad3f4112aa44b13601d13e0e97de50d4922c7d6f3508147c93e620cccd4225c750a539c3e482707112e5f8a79a89980a3ac6f993f7926f7ea959970a7c94d8a3b11e52658019ca09c0e7d8a0aadc2f322cff6707a65bae011430323053e7d3807a01f0cf0a1dfe6b2641a0d3e2e63111e29805f95cc3475ef3115dde93d3b0933b2de91a73d8df686730cebc7942549476e81a42bbad9c89a9e21a23c975f09d64bbf2f92fa5db19f2945f723c5e6d825ddbbd6ad9b96dfd7d510f3092755dfc7b759d08f8c37aeb1ab8bd445af960d8296961397e063418a41c36275670e65e10332b7a43088218bd836d5d3b702575a052f31d340034f64a2941f261e537a311c2c56ef4fd539915c0068d7f1ad0145acb88af7daf1c6ff510b76a405644c84babd7931bf1c09855705f2985beab880d6a30bc9e29317e3321726d4e10220cc70747369c4cf71a2fb6fe4c4c8efae276959a4ab33cb909a1ab307e6639cc65641a55badf6eb734199213c440289a37a1d936d0ec9c870e7514c6eb1cc3130ac659382816f6dbfdcda1bacb3b0799a61feae3be4ee21dded12048e4d5766a3ad9237d2aa62cc636a761a28868d1be495206466d1a99266bf9ba226ece9e8484b8c5676f1e1cc2986284aebb60c94b19c531931e2d0c23f09a471755ea49d3d53c4e3e4125db8cfdd7a8a09ee1ef9a7b61db2fe122cdcdfa9b750dedc7c2f329b574ff42d0934dd58db76f6796fe59b7312545fad99b929f4e29f4adf3f5c68827b446a87e28398789b9c98125baecbfbfac1b74a0103bae63d9ada8bd72c8291c22432db0935301e7cc2cecde1ca47b27e80f8677238210fc86a624c34042b68e1589c71df730c42a3bdfe2ac27d7ea7d15ab1249d07c6829bd2a9bfe710f3df6a8621675d990677b2f3381fe1bb132cf352a36b557b608bbb0bc13adaa04eb7c196393fc09f5339afbdc647e8b6de66672fcf9a9983191de3ba96133dc3bc2cdfe9c73e3e8c8cf133f7f46e7c3f2adb80197dc272ec44f95176580b6eabf159b6cf45776244f3e96c8c64825a6eadbd29e3851ee3ae106dfb0ea304b973cd4a136ccbd70dec7a5a6234fba70b1ed1b5a676b78fa5e187d8ffdcdbf9ef083fbf5f0d1e07028fc955efee2d7d1fb0f94716cada0a610c98e68ccf903a4ef5ac467173e8e0771d39e1a2267898171d47365f2c2000e6d93930dcade2c56d3cbfc620cdc2fa9fd29b960c2aca0295fb176b1618cc8352a9b6f160f80d29dc29a3c1a5138d39c97c36c9f0b59a1a5769ca450cbc24067dd65000898b6ff3dc41b19bb9a17548f2c9cfe2b30e4c8b2a1eda017e22f884e5697aa8d89640f0ce10dabb4132c001baf860f070dd2581e1b286c89fa8eb84563483ce08372c6cf1310218027c28e2272e927f46be9c444dbf78e27846f97bece201152380c2bf774aaf6d50f68721f1044f3e7837d864233c4db90b40163171986b574b2b258070b6e8b1284763613d792c257a12f5ccba391b6e26d06e7c5ca7009ec4837cc0f98192a9875cde1ac1d229e59a765260e8fa4807629311d01c4fb0316ba857fe05f70ebf8e0f260177d9168c8c03ba732f4214178f0f8df92a3f0fa73962e6ed2525dcb49768f51dbb442768824163d6fc7ffb059a75f8b8ca49eaab4a2aa3e03bf66f4ffd91307d75c6f1b09b53b29f2f2773c4641e4323296414a83d773913d15f593cc07c0c1bc4abe486aec3a48c1de23164f2e229ecc48a24cf20581ec64dccef38491511f79c852ac2d5457bf003e89662a48cb5dd23871aefe21f155fc9ed8bf6fffb6c9e613f7289c68b3dca1b0ba294ff6b0b1aebfbb05fdd8a65424cbcab8e11736776ca3b3aabd27044f949b970509b732cdfd4c9419e22f18c266172026148d51f6cba006608e035fa1b5cd74ad4666e463c87ffd0d58c173d02c2c9da43bd751415925df6cc2ba6f68d1894cd38e44d079e7f596d3a42d135b5f700188dbefb8e25dd83441e75d385006d239978968ee3c0d183bf9a60efee98fb78d1a50347d084674944f78781216ce77ea4f52a0cf0aa6c264507f34cfc54517b4e07a13197e3c6438a96d76571c93f0e040591e4d1ffed0f1c2807d2138269246da0cfde522f38edf7b370e03fe1885db5d3539aeb0444a6176f4f24f9e4c482aae8fc4546870b12f1b9e418abb48c41e71528a4474f881496cfa32d968522ac9acfbf35d9104338a2b2ac0387d6f44677dcd5d3453f318d89ae0abf4c88a724eb73a803aad84b3dbb4a355ddd1eca51e3968df81ac779318bfa61585f3c38c30c026a08e033c06955f1e4b743b38466b6b7200f8c9252de85ca491888fb5d8195e7d11d8596e4b583a4e63b576443f446b9f46d8f5bb4949c756164730496240a54f85e416a5552c9a93f38b5929706e2903f52604077f9623bc7927081cb9722a66b81389462b8acd7781e10a9880b41a3882060036acc5a371ee26f7e29f71857d73a257ae7b90c09ededd1044da2dbb2576052ab6a51dc44f00a6982a7b38a061c59ffd588498bdcba05853faa5d50cf4d03960c9344be7fdf68b44b56f65328e90972c10f748a35251b4812bc1b904d68e9d055a6d913860a1e2ab4a0e87cdf0bb89c67893cb8203784e2771183a3da68a319a39e15347b13af0b8d0392dbce9dcb6903a4f25b359131cd9e956c935b0494966438932bbbcaed34b374730e0050b5ca3f1dd82e8db25ae72db57d744c1741f18b7377e17c6e9186b6c71a9d46313fcfaa0026b0fb62b601f708e860742e567df188f44c1597ad8ea2fb0060346cebbcd0387c1f17b4711abb03f3ae1afaf0f59df867a4fb5767efd9f8cfa9259dd29f5bbc90cd7873cc076ec1f6c3540bfeb9d723929c4aeefc02f265d40f2ab9c35692d6cb3ad954cc7021cdc2cf875084e3dc548db3a0c774dbeb2315f3a9aa3221c33923fbad00b692bb984f67a437dcc4802d6e93a801442f5a13234f487b20bc40c5edb0d280878305bfb8370dbd5b170adfbc6392bc396106b3920bec0d3a63e2c2033c9fc41cd79282087d46019bd0bb17bee52c833d998db6b18100a551887b080b3ed9442ba30af4382a5406abd472328602b9f5bfdb65ddc37b6eb419bea9d9d3756f8d384820af18ffa02e32de964e0a5d3b1b75fd048da067390b5fdffed94e5a53099495c3d5d728d05cff30658ab80eb752a323b4b3d1f06677e858183d0a433c031451d9401a9afbb0bfa563ecf11cd2922513b52f79f0852a07daa5fe6941863a300160bbe07cfc5ea23d438fad2e4aef262ff687dfc376e850290e472ff55ee8107d4e8466d68c8654c9b9fa35e1fbf31e1865c5d1a5ed887d13b32076d49b83099286c420ab69043b9db3ed1810d97d372869ccb53d4e0458170aa6376c4126be983e4f3211e049619299c475e2852ac42daf960112153a46dab256f426463c17629a436362b00088a953ce04566d900a2a0cb62634d9bc22a05c84791fe1af05493bfe59243d8024ca91d7b0be5440343dca336a71fe205e02b3ca39b5efa0979f162addf292e995229142f627437e5882d92fb9d541538fdf9cf9f5ca790272e12f691da14ff1c3b5a63d44f8e3bc9c693e68c0cde53ebcb17b9e30fe44f4866f60e23632bdc692ee9cd6a8e4e0a00db836e89acc0e44aee9197261569cbb3766c6c619d376df36fec7a77f083e6343de3121c4276efed0c43340559604083e7e68d21b07f1349483918cb0e8c651e1711406e492e567cbc09e3b8ff7eb25de7f14cd2e20d1aa2ed42eccf34610a64d2fe3fe11b723a8e36e3a95036bbbd5b8ca76bf44764f657add728d678a598299e53ca7736ab1c1a39fca0b72c3f40fd74c6739f5caabfa60afa45f463d5ed7fe4b88fd92bb5a411de657efa3312b001f2edff252677969e19f3b19fc41eaf9951efff7144160968b7334f93241b6074ca902f16d780a143c294ecf0017b86d03a9bca96822c93b9dd085038196fb82e81bb4393c175cb2a559c92545c48d346b5974816a67c3017688439f9c1c6d1263b7481eb83ac581a88005559d73ccf6f68382cc7800ebfb65fb879b4b0334235195ad3e7c9c3c7f45bec6d044c54b3cd50e8512ca2bf71c10888baf14f4223d7455ee945b431e23b01ae22af99b58422731fe1cc4dbfe75a36da9b44c0cd1082e941580fcc7b6df20cea445ec9d5c8ff0f318f03c0506fd330d5db6cfbba23c73d296a4e49ed8b9226b631b7e5d8fed080cf5139a1f8842d25c35c5a5c23e34329fee4e64a12d79ad01697ae68596979b1016bd13d6cd40803c147a5224d2cbffda67902751a154ea2dc10ebc20df068d429472e697b60b67ac023d8ce6723f457c78e93ef87be2421df03fcb841f8d2ad5a5bb9e2ccf9d3032537fc9db16e1b27df119aa30713ea5962850213164d32c4175e934c56c5a00613488375c4e39ae1176606bf79e1733750fcd8aff65983642ac60d1271a9c4365af7d48b59bdc1e062eabf4904e181646d49eaca52d071d65c4bc436d00a7b94237404953b8b444933c3c5ee9b4d0e18de4813b507a58ae86a037aa94e81f4e02b6b5e01972ee68d6a711c85dca653a5799247a10471d5b0fb48dffd0f3caf5c90201262df96240f0848c02f5ce82dea42eacaf96882c58dcb4999c35753b733d6009ac80e9e49f00cbe633b7f4249e947bfd5618130e150d292b12e36c6b3b3fe8a0b8159cb5a2f160e3ea9ec271daf9d3ce3f82055384b3bfa081b78486cb6846601341db24867505cebc9a508214e07167bcf6877ea901102ff99b0a21f58c92aab856ee4e5bd579a34b026cdc24d09807177580afc0f5d5c210ed795707c6101d119c5e7ca334b4b3d7e7cf664464994f7d44e74ebd8d1d6e0166e75cf61df8a3bfeb605b059bccc8b0ca65a20a6cd62f9c9017e62a24bbc887753fab15f5198b1318c4318b57ff4f6ef39f8c622fd3491829350fd765e3268684d40510eaf26bf68b3e1da64e26e60dc1f402dac64f6e3517ef51b37073c321db4fb956c14adcd5f5620d565dd8e7ec916dd14ba60cb51ce861c55b7d31892a79a8e0c42ca9c32e0bb82a239ec55ed3113aaecf5172492f65d26c135b977a4f5c3bb396c4a2c33355918da88d80b852c39614db94a9a3b95d4d7b16c813911f5710c38fafb709966baa9ab6b2da64b8e83ca4dffb33ef12e818405686cbf32597c04e114191fea64c5b398c0901a17d0d540cdb23df83ce0d94cb8d2c1f3a24df6af2d18776114d16cd48a60bb674fafc53bab6ba2f75e1325f3148ac83c0c91d02d02bf81f86fc01ce554e7126966a937cc7597ce63f86ec46cecedc21f1e08d3f7992d834505bd0f1f9ef2c2e03b063feac80bb57da9b4650ba5eff7759df73f074a0a5f3b54630b080448845e4a90df898c4ff53d3c02b91e5dfa4d67acf9f589cfba25d377407b79b49cf7c787da3caa93f42cba758a78a42797f387394a118f87d9efccf2c19be11653275633fa849eba096c8886c845fe5f922a2001add80ac2d6bf306b55a8b15db4d0c1b1c39ff25ee7b8407aef21772e783e3bff3f20be2f7441c6e1bf1dc012cae1873f57389863dd240c335372605a187f05f0b51dd69678d452714e151eeb2dce75c330186ea3e0c9eaa87c632218457c4cd1cf2316e70717d81cf5df97421f6d3a41cff1916b89dc4f50668c665ff0e873254b417eef95a88066b2b0a1f1a2801890b5a78e117d3ae1450981454ae09c7c8b8fbfd1c8f92f839bbfa2f89d816ac57d12c97a677d8dbdacb261310099b5c319b00c49ca4d73afae45c12e30dc4d9dd39f0e5c5c7aecb3df1b9db88a07577d01ef7cd9ba172eb0bbe82cc97b1dfafc8d216984c7e24c3bd6ff2eaa7f3003b4abb3b689b43c81d423a1d80468ce64115487d9fb35098cfc4fc6547664a582bfe94a28a0b97c97a839b7f49f4fa3aba2e6adf8e38de90e46a7ae1f7a791cbdb318777264646f27cce7f8fe9c0c73bbef402bfc7234238dee234bb1d1119828359a5665cc715b511f9aad8d3810a925fff520615a6f687d68e20a7bf56cade375f389b700adc6ded373abc4a979fd23f54663213c91026245d1d814a9bd63888e3c78d0a44d00f6fcd0837f651e3cb3760ba021e151cf9825bb0608a637bc47663e06bf29bc3cdcfcd8b0f1ddef13f684cb859cd9af580b17b0c4485e82202d43e92cf8ad3116ac168562507a57c0d5789e525dc108160f8f20c43bae08fdae24594b8351f0705162d86ab3ae44d511eb11052db378c42b1df8c22ba92315d217cbfb95188d58bccdd13d62deeab55def673caae5271cbe55f020fb7993320054d2b4d27ac59334efd384de0c953f08be8d05d437a831aeaeadb1cfd02d49371000a8af56253f53877b1b353163a020c3f84a68218cbb6c23150b6bdd57da061720e3b70d26efa31884a5b627aec0fed84cbeae4ef97cde04cb5a207a96b6dd9c7fdc06e54ffaa9f737306dc943173f3d601c58fbf0f6d49152e4a6f346b67487bf6665c3104efa6ef4830ac353a9ae0bd9bc3f38e96cb60dccc99ef8efa64d43418736e5a54304b9f54eaef8c625cd8f5d46dca98fa81178cbd12eb52a2b74f4c9993bcaca369af876fdf36f64c717b0fb0364f27f3fefec4d9e44fa666209d5e21f24bb1bea1ff16d4d776fb35f9b731d8a5a981f0cd0a413ca41fb8f77479faa48d542889368251969951ba302a8883b511d3b5e37dbf8d713e579e4dc836781d3b9ef11f707b708e7839720fbb0b96d48b57fae034fdc875bc5f6682fee2cb87cda41c214b60ee573e9240071bd34b6817729c7ece5122ed824131b1c5b3f25a879c3aaed700addccbba69b3cc1c830462733d7e2f489d511766038c2a30b982c46676153b1d7d6e2470c8b7e90748f9fec97379f5b4e37f9bd3444f7e9565246f3ebf72e2cc45166ec2b4afa3b94fbe0edbae7e6cc19c5eb13112f864a28da29760e7831779b4af8c9f0e44d6dbec2368c3d1e3fb6a7cb31e3c3246fca7a6671080f355fa489f2b7a1e9c9e9e9ef17b909b3b7573e3c089bfcfe43395f5e35ceb1bd5e99a1c7226db1edb4ab89e450c49a29ce64707b2edf45123baa59ca9f9f95988bc289e3b8f549617321f055105a6d94f6faaf2164517b99c001dc9a1504aee55acfacfe4848951e81af6adb30bcf3d80aadaf1f17337df4aba7560f0787fcbf823c9bf9bb8b761f16df481d6a36e574c28a5786c7acc41ad994eb74584188f57290d01c1db457e4f49ffdf56acec90fb95737722fdc70cbf6e286b37c985f63e04bc1786f2793a929fe4ba9b7344cd1f47a61bfe4b8419884a42084c2bc6adac46ffe216ea2cc2b487ecec9c9caa2c4cb35b5dbc3b29882886452736b6536e9e973ef4d4bfce1ea3229f9442034d148be8b1d00099b505b74cec877a6d39082da9a35b96982d5d2d894388b42d4ecd0cc66bb03daddef08ecdfe4fe53eda98d70ae0a236c2038ff39e4bbef85a79fd1a75dc4aec1527484d31abc09829951d01876d9c777abce7dba14e04df89b3da386516e674b95bbedc8a48b6276476dcdce623da8fffa36dc95bb6d22b621f017d544404265c8a9d81912a6ace036db7d5ec43347005beb8097a434662f5f56aef1a6c717a9d98fd0d4ff958a8bb2ec7517b715901d4a9e22c66b150451682f3f1f52743eed71290ad60b41daccec84abfad4971c5a0a91b2d39ffdd199cc32f16161ba7978f447360257ed3fa6f01fb61836dcf9ddefebaebf003890d54173a07a2dd1d9d28d1a8fe2fbb1936e63687ed46a6cceb1610cc57006e48b58db5ca9d1e6df1259098702b692f7bc04b1e357f78920405a181f95f726e017849b17939a7ec6f494f288fd003ac2f430612e4fe0fa86cdf358228fc0c9cef4cd07759a54721c673c14fc220aa51a3ef9943422c88e7919580f75b6eb4dad912cda9781cc3f549caecb61c387d2cbacbc842c13a8a6a3cfa8f16c86cbecd3fe9a238992301a8c42024690b88ab85da58a1d5ac5861a7d7bfe786f3b8c190b202c3893c2a1f8d53606984964fa073d6731a241e7729d37bf301b063674fde91b5007dabe42e897041081184c4026feec0313873514d6a218d6df6c6f09356ac950f237a65bbf48c47d73a038f210a1f15ef1214f4accc5fdbc8bf1449c390697b12a9e3d9b99db6621a356ea273d833057ac2c58ae0ded3678c378eba5e4885b4266441fe9f82e3c119ad0118bb940082701f7dc057ebd9385a42cf58cda71d1266ddfae9a1d2e185274c7cc8c006ab160a9cc5d8a77e263bd8d98703daa52ec1080cf71251f70cd91efb74ed4c439721d8d7b0504ce0e221f2c98f6bd60e3d5a3f002f91c7588b5d20aa8d9f7f6fe25680c3563279d903ac8a27f69de517bd162a07ea64dc775940d1594c7fb642f8e258c62eb9ab176a8760c1511e67df24267084f1165c137aca9150b5adb093275d9a5978904f79eb638219568df090c4167dd67cabadc2a432625d5032648b2d7a225dd36a031612326cd45cad626255d2e6b66dcaa4204f8521b54ff25a91d29e5b64bf1400fe25f98fdf1476e1275ca024f811947886ba212108f63403151e4f5e6484c3230868390c45833821890c36432197a253c51918d26e4a3af8659abe29b807034a2fea248ee37db7dc064ba3295e4b626021fa79a16f124e16affa3be43d057ff8042da38d59258e50db158bc553707ddef8fd270a0d8fb431992203e768a174c81b58f96c9a61cf8eab72544ba42bfb0be70b8e93c0ef131315b12d0893d3982dfef0df5e80ec8c231546eb1c066a830840c7237097f307b3bafc85cc1a4fc92491f601af9eb9c3ed07d767b92c98ec53ee9f0f0e15698c05d985d06d3c022ff0a8a8f17a9b14747da009c1838901b2ca8aa4938baa8c8b037e6644150d4410a0b5491bc3300c268688858a0aa6e8608e02b668392d8b1f5b631b8d9a8da5db4aae6ceb002fa27907dfba4d782bbe000f8aecdeb4339254de1dbac0bbbdfc5687fd24eb0f9e0cf40b27b08d139806494279d00c8aad3a5c9c401e9c402128d5e4fc4099aaea6bf5f12112f31eb922faac502f1a3834831084a8a2b63011e232e19c70e288609ffa2071299274d2d438695438693a3871429c38cb89af13f62389ed54d01f585c1c0d93054ffa0b4f883ad6c409fbe184c120a1301038065c86c704d3b448304d2440a1003b610938d69a9ba1288f50441c8250c3f2801ffcb0871611c5a2a1c415419024141e705ce1c58b66103d7898cf0c555b68261045753279608200ca8ce763c5264eac70e3c40a2a7cde43c50e1ef645d5858d2124e1a48a227cf1a3d0cb5dd9802811e599a128204a745205c70d921bd5733fb40849b2c4668a0cb02469faf0c614202a64bf9811816250088045057a51e5630a4754a1e9640a3948523592240d1f2449e3461b7b58430f92468d3c744213094a4c07e573324514275340713285025078509101314e9e473a799474f242d2c91b4992c60e92a4a983544d219d48b106a90627526c7122451927527c21492c28410a20e210070d1d2449330749d2c8210e1faa23d2c0419224cd1b4033f422499a34dc20aaa82d4e30c0058d1b346d90240d1b2449b3068d1a502a7081345688b2271710802445218828d488020c2751f4800349664c9219731285e8240a21ede1c0c49e1c1440f9745072447182b206499242a00f553f1d29c78989154e50c43841f1e2048a1440bcc1861a7690431a6b38031a50cc2a34d5cf48e53d749e40f14ea0d88024492b404149018a67164922d1605f860a8528fa441c9e08c2133778c206663c918227a82772fc139a930a2441b20f060a16d5dce20b97203980f00372949828c2119a3224a20f6a98d0c1640e6e300943124ca660c203144c000092244d5fd8cf7f811213fa509dd9f2269c1309404992649c44401392f41272c14904825085a659759470128129aa1308b4a00a4d473e238ee8c867347d94884e1eb0054962142b8ed455f93839e18124893e584c4e12dbd9545888a88f2864ff379bca332b556931252b40312314847c3c68e6658a4fd5794bb180a80f16270db0815485a62433e68ad057f652568846d40903129172c2800e9c28208d0cfc60499258208303b420018628590423dc2841a3840c2709f080a4714333831304a821499f190d19d080a20331384180002449bac401ec19064822499a31942000094728421124c90c498a410c66408624955146a8c7013a1d901a450a94cf7bda09013c484a1620090e5042ba42152e70841f42c8010ea42152910e50e064001ac9ce0fb91b09400492d448363c78542702c81180499c04000e2a50785c8a0a7d4c47b4b91fdaf122430101557054bf48d501f9a83aa0e901c5740010872405917a9c00a0049274292af4c412de529f138d0f4e341e49a2b6902aeb99eff2a12133f43c78d4ce0cc9d65a6badb9bbbbbbbb33c618638c31d6ddddddddcdccccccccbc7af5ead5ab57af5ebd7a758c31c618638c104208218410bef7de7befbde79c73ce39e75c6badb5d65a6beeeeeeeeee8c31c618638c757777777733333333afb5d65a6badc531c618638c31420821841042f8de7befbdf79e73ce39e79c73adb5d65a6badb9bbbbbbbb33c618638c31d6ddddddddcdcccccccc8b237cae396be62266451a01269a2049d20cfd15b5633f44a8d01b99f9a105c5224379fe878609a1e78844d4e7a3c1424b45b1549a2b4892c60a92a4a98267cad0cf4c21148b2469a820499a29485290a459d92a2515a0cfca8746a2d1ed4c8a220a7528caf4f18caaa9fa0a0b4aec9024cd1992a4818224699e20e9a084e40449d2304192344b508224699220491a244892e60846308134b2e2b2d1426ad1051016b969e9a2a5456ea410225a74c1c5c60b1f5cf8f08c2cc5051cf58879d10a0ce5e901472bffe9c07c241049b44092248d0f7a603731a3ea3d33121c2a764892541201a9e40c48a8a00a4d3374535513a49141621f0c142c449ff9e9c4744231a3cf3f220d49b222029a91e4197926b505cca7230a51d407ca147a84171a2f44204992a429a221f2224992678aa68a23b4901a8105fba11e709445fd2226f0e69c113ad0c1082f6c872ab2f220a8cdb8a84494a772375a841792f474fe506929623f3e66423386f2c82402119224c95c217ff8f8214af2a32e3e2b2a2d459ece1f9588f2b8d8a7c2dd08a50a77a31df552d40d21516929b2b92124a1078d2a44b8808ba8b414516929f2e94ccf10974a543dcc10106856a3ea7308151068f2e0b1015552891f2428c40089219214620cb09988008c20499209241d847843920a1137f693746e10e2708424491e8f6322a11fc283c7065411c223499214253ae288e30d499274c43102a90b38dad0a1b079535d5143d515b523fa1836723c8223d83c723772d781636510660091248d073a20499e5048564d0f0ef0a7f2418940332120a24f871a8281900f04310641481a0ae808440fa27080243d118427cc084403a44a93058fd04bd20c208af007454892540249072056159a38a209ba62468485864715fa4e0b0a473441281e8f0f1e3c74fc21057e8843871f5c241d6fbc21bd91224992157cc8826bbd850034259274828d1b3d9024c944d2c1072aa4246b4dcdd3b2c20ae7064842e181d2c5152b6e0c91dc409124e93d9d3b61664c1b9a9024e943a40d38d440d1b186019ad0860aa436bc90daf000cc075aa1f242c48a0fc582d286244928f6d339c286212410c5c61924141e5c8409483ad84832a4191b3b24c91dca870d014892f459d983225078d88e1c244972d1b18726ec218924edd88310499276a07cdd438a24ed40d1b1870668828a1d6bb081c223f4301d6ac5435923079224893e6b8024141e6b7821556baccaae610022920e3dbc21e9d0c31f241d7a1084a4430f71d4cf4865e6e38362599124cd8e25499a2ba4c98a07cdbc4892a60a49d240f11e3ac3e854df22499a0d5492a4d140cc7bfe41332f92a4a16214b3a93a92a4d93185243d6846f4a099299a97925334b5d0a1468a068a0c4892a491423445530b22208a054451422449937257bef248fb91a11f7725f443923418780f9d2fa11f9fd04824aa1f0251212d5c8288dec5332b25e4ff25886752ca1344f42e2a2a2e10ba40e842c4b10b9166765242dcada8a8c0662bd0b1bb15cd05242e64a8501049d24481b222491a2844d547923416a88024aac20043365b7916214244414441840869b6e242e483345b09030ce96ee5598408110511051122c4dd8a0b910fe26e050cd94c4524a4998a2848339517d24ce58334530143ba5311e24e4514c49dca0b71a7f241dca984e101d2ac59b39595951517222b2e4462ecc747b3955017cd56429417cd563c2ecd563ccd56c2f00071b712860888bb9521ee565656565c88acb81089b11f1fee56425db85b09515eb85bf1b81009715cdcad784222aac5dd4a457d346bd6ac994ab366cd9a356bd6ac59457db85381f1741e883b9510457954dca9a888aa0fcd6771a7220a81e1e24ec55a1fee54e8c8c59d8a67c4853b15241d2ddca97c3a5cb8534932b970a7f281e9543320d00c89a059339715222e2a445cdca910a99f51e8c5dd8a8a16cd549aadb8ac107171b74204c810772acd5456dca9ac346ba6e26e45f421d0b7b85301b284396041b21398c3169224e99803cf410159a0a0f0f80284c24556111ff6635eb412a2427280220e3fe320461cd6e4c0a18283186cb3111c5400872924a99a28554c33ffe30d492469d38353cd2d50aa8992451a37e022312fea4892460211903e8c4e15f3a24eb3d187d1a9dc504992c4bc38c2e79ab3221f1fffa1649e45a5ba1f1ae2a1286abf873b2af4617ca8cf045513e4c28621fc70598321d63004697a149967594305663649dcadd84fd2510951a23aafa53aa1ca7efed38179eae97c0d5194e77244309f0f813af55b5ee4121a0199992c3fe3230d6974a1230d4310511e978fe9bcd84f0704f6d339928646431c68d041094494a7aac27e3a47485082890a2beca7736487fd748e5c6ac60382cfcad70972b1ff79501792a46180660167c8e20c28d2190a80c22326c60c1f141e9beac87cd006049a3c78446ead435519a620bda8806086783a33468aa84e0b7d117826cc0b7911757eb8d64766ad0f02d77a725c5c6b4ae6a599cc6c6126335b1693992db165660b6c99d9f25a66b6b896992dad65668bb7cc6c612d335bba6566cb6a99d9125966b64096992d8f65668b6399d9d25866b638cbcc16c632b3a55966b630cbcc9628335ba0cc6c7932b3c5c9cc9626335b5c66b63099d9d232b3856566cb929946c8e0802a34a181051d687840071a5248d218a820d98f1955a339a4fa8e8e31144092c4700669b262d8c124aa3a42445f8961b2341b8188e488e34554910f513294108a7aa97218a21092247dba683602c30a2429471c3e3e44e0a83e3464109294431081908e544a8865f91025aa428fc443b9f0e0f13c4413a5d90845542728e66d17782049d28b2824ae39eb242ce43f140b17c2f080debe67f36174aaea61266853553d9a8d389b23758ab6108298da114d198f6756fb9bcd666dd6a68baccdda7091ea5b3c1e1fb5ea70f1af22aa3a9ed07790c0cc1f1f335d3e2b228a85a5d9880a7d7079b11d205c641569c6a92687534d4e911e3da0cba2191177a3b754eda1630a389024984f67c6e3f141b550a224a5240a0a40a0128ad8c2195638a20a4d1faa138514e83843ea3863c8342945015285263aaa2469650a1d5090c3ed702a8903137540c1495568ba42f4e98c603a54f4e9c074a81531a34f35d7c44850b8d0c113b220bda07c3592410e9327c427a048f6613e2820aa330249059c8d740227882449ea694d8c44fee8a2e5c5e58b12a9e48c922a343da542a2aaadf8743ca18f59430f00804d384392a42fde43911ce984ac98f9238f279f9615309427871a9294230f9294030f928e2688710749929078286a088b085a26912042beaa7c803a2f9d992454a80865472e40aa17899ece1f445cb208514078f02080ed504578f0d86c389b0e686e4055d58335379bf6139a1155dc3df8916c1c3333f3e2089f6bce9ab5c86233b3983fb2783a29f5928252cd2c8aa05401820d920f81cab084244d2865a0a1a38c468624c870021949282af428a03ac880128a8e17c02149d214eabca0063a5e9044aa4414cba4e3053b2617a4f1a1444f47d7053990241d2ef8a2ba940be01896f850a11f238d313e44cd9719832349938e31c650c0141fdb411103109224e910430b301f2a242302205d7c18a11e3d7af4e8228b2c92503f363233546d92cc98169ca0058f0570b0e0062c60010ba658011e56f082158460053b2469a258a62355473402cd78aa98993228339f593b9f09f2783a321fd3114d199499cf7c99a8a876a06840031ad08087a240339ece8ce7fe87faa8600d1590a1024b89503ed6043c787c353943be2001ca4b0a38a1230569e8484111244a3483f29c2f5270002fe808630961804047180f987184247d159b8dcb0c0f663a90a410497ea023892889053e9d19125d41a1cc7c6638a2102523aa461765a68a992f3ef6333955f8c8a272a95ca8f8fc40a9c2435174478f1e2f59802811109922320298bef8e20b2aaa0051a21d4190b071a49a2324399024c98a1085c40b898241b29084466c48f3c7080cd38fd18f0020ea822846644575081d151a3c78d8f6565e2e4ee765bbf282992f5d94b8415af66e2fd6eae8fd67bf0d92e3747ce3a48fba4b091b9e2ffa6ebb3e1f7df72d1494ac414edb8eb60b19fab58e3afbe98000aa213216a35b2e3277ee3984ce756cb7b9da1546cb6ea64136aeac513bafc7dbde9a25689077756dbc286d4a2b7d7b06591fba7a6ba3fed331ea7ca5c40c3246e896ede6aa776dff6590933ebba6d768db65bf22192475d335b3e5a8bbf442ca7930f3659a60a6689a426f210b89406848469fad85cf698d77353a06c990c51bdfd106a97b3dc52097d7ee56effae6ebdf711e83f11b516d292f4152c0901fd37999a6f788e8a89aa669822c4636a39230c4e55c8bafdd5b33d36b9bf2b2b539eec7791ca2904ccfddc0743c9e779da4040cf241cadcf47adb85d0310a5d48c917647d4799473a632fbab8398fdfae1620912991e843a2aa138a2f255e90eddafa59bf1bc736db7bbec3f248a8d09069e2caf3968ad9346fa2a40b925dbfdd26b79f9cc7d64e6b7d7c3ad41039d97f420917e4b3f6b167df5e6f8c31dc826cef3d76ee55e8d6c6398a619e1117d304f150a205d92ab5f1d5d78feb43879cc7475a8602b52c48b7de366ef4beea4d9f711e77362130aa9ea67783122cc8cb6ea9f37a70c549a95322c8cd239d04255790cbdb9db596ddc62eab97f3787137e86ec4dcf3a2c40a72b6af715a5b5fb3ed68398f8fd409f2364dd3e46e344d9ed9097d354df6f347eaa4d3e4af648c922a48f8d5c6d870d6f88c4de63c7671a1e999b57247de33ed23098daa6316239b1e255490f1ba696f2fd666b3ed6f0ab2b276bfa953c6d7be8342a6490af2d2bb608d6f756bebc209af88484854b96331b231414914e4ebafb459c7d67dcbb4e40c16978d913176b4a785c2bc7632abed1032af469f10695bf79cb9eb6ea55de204595d43b69e9b9fb6d6604913a4dfc996564ae9b3bcde723762825cf37fbdb858ec5fffbe53b20439e17458bfbfceebbeee4809d22d8495ff45b7d6b976dc664912bee37af146e670f1bd8ff3d8dd03c574181224c7492b638f526699d796e4b708bd0c25a44f507204d99885d727bd9479d53a61e747094a8c2027bbed59c7f9f3fe6a91c8344d53cce8e3588c6c684911e45bfd1fd9b6ae0d3ad8bc8408d2b9e172d4dac7b859ee583204e9b8b1061f5dd5edba0d398f65fec342ef1212b930bf90a862254290d7d5fa2bae7819df662fe731bca251ac60485431561204c9ec91ef751c2be5c83c66f379cfe31910559b6da3949714da4629b1bf0408727d5df4daf92cbdb1236d404a7e20fb56a66d5fa41432ffd91e28f181bc77ce06a9e3c990d1c8af07f25f84cdb117df9a3c5db49ff71f253c90f72d7d1effc5d0260629d981ac4fd9eb59613773bbfc79cfa69b16253a90be7c460a99df3d2f6e939303c9d6d25ae9bd1cdd2e4a398f1d8744150ea4c3e8d0b6bab8365a5be3bc4dd5698e253790ce46c673c567c8ec98721ebb8ff9c6cd6fa9daf98cde074a6c2029f5eacbb1b3175a873124aacc90bf9cd6d6e0bbccbdd8d44351748b921a48e75864af51fad1b1edd53490aed93aed5ccb456b9b35b72e99818ccdadb9536e0ed7bc8bf3986d363023fad6b50c24bb9fd45b5cafad5d6c82d854120339db71f7e2777456e8cd79dc2a2530906fc61b9fc2f916b56b3dcee38ab2ce2d24aa5c4919d25a16abab75fd5defee9221636d7d2d6d2cd2551fbf921748c7b5f65ab0a3b3b3d92e71819cf6db3facf6ff17f7978c21ef7b5debfdcb1c63daae084ac490b741d89aba836f396cc779ec992198177d3a1b3b41cda1174551cc65b005eeb11dadbe2a33ea9cf318368f36a2980b250b2a8bcb276d934d7addfc7436ee461be798d18709598163754eafecf69d3777cee3e6a202e91c8cccdd9eb35ddb6a5d2990acadcfe82cf79b963dc679dc5c98a128e6b22cc2907efd51fbaca3fdda99398fed6f9c5d8b3392521629dbd6377ab3d4f9b073c83455143a16231b9824325af85c7de83ad6c9e064ec3e44d59691357e7bee2de60b23a32e3616231b2f9044760eeb7af4d535db659b91640fe16af5c5791bf2f5888548c6e5ffdc8496357bec17e77105b9923ca17b6cebf5ca666dcf79bc61dc42f2fdc256237deb9cd1c89cc7ad0a3024f7a3b76f8490b9b6064110bae7acdab5ea4706d9a4a4f78c7f67846ed95bb582623a8c7e248c77bdbf8c3efe5be9c7c8e6f7da2ef66f6aafb7158f7431b2b5b05d643c672fea7e566ae733874cd36331b2b9472473ccbafb4e069945c6603e9d2371a140b63867b7566db4b42ba48c29d71df93d59c3aebf5cfcd79a3916239b1270e4336ef7b95557a3d72d384d1ecfd769fa108c74b6eb55f6eb32e89e3ae7b1ed6c1e34237a1f1fd334f3998cc5c8465ee97445ff45ddd1e66c9df3b889626e065e72858f3257e383d3195bcd5609acacf7fa7adc7ad2ebd3b2247605e6335ba6e9612a10b5e1c76264632b7b6c113ad8cd1d8b8cdb6f33cbef4e4ae36ce6cb79fc222425f4a29569fa109069b2df0151759aaad08b40d3cea9178744a0122550099fd97b778deef176fd50f1eba78b8f8a831588e231253f7b93a17b945d74479d6331b2d97cc19c37165fec059941e8fe9c57637451e775b1a61fd98c3b8b914ddd480b1985cfc2a60e42fb28e7f14c4804ab1af2e1550d4d8f2c46367e02c79039e6e6cd7163e6a037c3d8683b1bf95deaed1c13c86fabbbfda573f27a7e4b20ff3d3285b63d7576d049201bd7faec3ae8aab769dd76a88d6331b2198111f9e89cacad5a997afbdb11c8f8b6314abb1d737a1715e285f479eb57766f74ccb4af08e4aaf7c5c87e9bb1d58ebdb4b318d904292299766cecececb3aebd4d53880a857e9adc6331b2e91071ad57ece7e05b8b6133638fddebf2e833c2c7cc3072de344d93f3900884821779a3d3396375adc6089d398fab23f3411bd1c344b7d9bce748e86336f4486dcd626403c4455ac8de7270dd672b6cdb388f31d022adc717fd3686cfb5785d0824e3d5b6a1bdb4bae7f035f3907f0f176d96d77cf53b86a00bdb5e7cddacae56af375b4bb5b02c06eb738b42beacc245570b1792553759b3fe8f596ad9e43c4ef5d80979104e7eeb7174cbc276efa113c4ed0202796773b4f536befdde6d9cc7202a64797d405e861fbb317e0621dfc979fc1fca5337cdbc22df3adae2bbfcdef557e63c863fb6801c39bef5da41f61673b39b6290783c9364bb38cee66efddddb9585d1a94621ea7a40319d6e31a30f13c55c9920b2ae8efcacdde9566bffeea53651888a7c11bac3d791c2f51cab52327b993a870dc6bf6d4db7a285b4d32b64ebae5b61b376711e6f18b3e3fa48581740e46448adbdbed8f3d3d99cc79b66278ab9ccfd903e9f8b753ddb45db5f1585a0077cc8666f3df36963a4efadc579bc79d003d21d3ebbfedad93e1d759cc7905f072483b3ced5ebde1827e4c9792c438560b87bc837eb73cbe6536eb0c5cb791c12551c90ebbbf56dcdb173cc59e43c16c5dc48240b79dd5cded0b98eedfa659cc71bfb991bca72bf116021a7d7472b37eb687b66c879cca946a04d88ba1be7230548ca4bca8b9094fa45ea23d9c8ccd06b2c46364278c87fb345c8a8e5efb72ce43c0e4d4eddac491473a7e9435415816814b3598dc5c846045142b771d186937a3be793f3e02845a52525e54548cae6d3791d1281d887a8ea2c46361c80b23e6be37d675ef9bab9388f43ff79922e08e7746fb5c5ed59ca795cd9ff6a237a98c6292f41aa99b27a94e2324d33e54548cac6238b914d890c5c6ba0d9d780f3142c02dd14159200531a5812b8c2025304aca04015bc6303ddb91f025d400313a082023ba498428a0c5c408a2b1aa5f0e6391b0a60c05d052e9084921159200a0ba040e15a5b80613307a502cce3e91c5914986202f3433b2430f347aa88c01410d850f10051688aa638690ce880e954513880ab993fb2d9d1002918d03154dd6cf8886b0daa5fbd056c7628000309d86ca440c026c98c81e20030946703f3e9c0c0509e081820c60205e0cd87ee2644892605083000dec44c118a00a80880fdaf36170040ca13950666478e8dfdcc8d9bf0460325bca93a9b8d28c96340f249b0195028f998f9d1b0197d304001a4365ee0081fd20e7490031cdcc00666d480063390410c605006192f70c11862b480052b50410ac298495285c000519f18cf1114743830f76da5f38bcd094c500212181981a4a30966483a9aa0891c602880d4861860f02179200090e8801d24a96a44079248928402820e3c213d128a7aa8da630d3d9a207a981e64f4b05af448e9e1000e48e2840376c082c4811c70400c69118a901c6892cce2115920e2d3a158baf359c902491643b2a0408924652161f1862461e1052ccec02208120a0f2c7220cd7c7c4892261188a82e92260c27583880872624942a78acc1c30c28222a08ca34adf048398421a4dae1804254cc8c87026d409468f347664c54c34934038507caa72324824ea2094ea2072449a26207ca099aa2a2024ea02002af979d8bcdb7f84d19c8da8b5a56d946763dd218c8c9f8dde7bd60b35f87815cad39cea6abf172ccbe0c19977bfc98838d23fc66c9901de17d089d6defb5f802c9eebbceefcdf68db2ea02492b6c18977d7863f71c4376743a2b74d4325ff7e51043daf6bede8790a3b3d16b27a475b4c2656f9bbcba3527248bf1cec88d2dbe90996e42b2c5fe99efbba76fba2664e4ebe65cb523a3f4ae9909c9973e65b7b7c18e7e3121ddaf576b74d3c2d96d5e423ef7cbfdb3eff64dee6809c9ff0c5a0717f51befad847c37ce76935aafedce2125249d8e272fea209b4cdf2464d759f9dfa22daefa4d1292f6578ed6c5b6bf6024e45d8db2e59a29bbafad07095923bceece603b65661f21a765cf7fbeb8e0a5d61192d5be7fd9e4c9b339d808f92cb3f1da767667d76b8c90d1bd3dda8f7b3d48d91721fd397be7cf672b5f5a1521dd178dabf93367b3c144c8cacdaeb5ec22651e9b2142b69bb536b798ad6ca33d8464af56dbcc3c9b568786906d1d5aefe6f6d9dbba101246d6737e74e8cd1242b2c81ddfe30b59838b3b0ef9b87937bef7d1d5ecc22163bc4ddfed7d2f3e1d846cc8b7c5b6e074ccad1784a4cf5ebfceceedeae61c0819db9b2c5e7ee88dad0a0849ed83af419e75c23be31f24f3361f7f74b4b9c86d711ea7bc04892c46362c30f1839cedb2f5b1ad7b591fa4c74b1bad9332b6be46ee37e46d9451f73042e66ed15a01f11d98f0c1dfd1775a1983f4d5673898b821979b96dee66e7d5f5d534f790992c20d0993362adf5ad9fe7dea1a3664c3ba76ddb9afbb6e03fb0c267b90ec8cd558638bd0aba56bc89f8b3e9cf3d2ba685d1c4df420dbc15f347a9bafad852f4a1335e465bcaaebc7deadea6e1cd20224c5ae4cd3102129ce358b918dc919267990af59e85875f6dea06d95f3382482292f4152aa0f202922aac8e763545a5266422faca182091e24eb55fbf1a4eed141fa9cc77e0749996de62284ce1ca59529133b48bed4ad66f0ef7ae89cd641ceaecc7e2f76fb68ad7490ef6e4f7e6ea616421add03267390fd60843edf84d6a77b4b0ed2a34fe66b9f3d52bf1e0709d74fdadc2f16ffd566e120e36cc6ccdab61a69ac363233b4ba0b9337488f90b6f8e6ab2f360b997f98a421edacbce663c691d947a90b17dd5b98b841faabd1328b3e277bf33658039336c858a3ffa38dcdd896b187619b206c901056c8bcdc5b5edb83eb6e8ed4190292029b47292f42a6a95a839cd5a37dcf986b0fdbbd1640305183e479eb6c0f2bb5d6d1c7d2209bbad66ebb471a29f5478364d5e37acc395a5985ebb9c919e4740cb6eb7a5adbbaf96e4ccc205fa5b6b93fc75665ee1e91212665903c394e37a9b3962f7ded8c98904132c71afb572dfcf518da24d48f69b29f84a2f0814cd0e0dbeeaf1fd20b6f739cc7ac81613206d7fcd88b8d357d7ecc793c93840a8136949da6bbb1764e5367865e9849224cc4305fb5b45f5bac3de77d6854519e3a4d53e83d9e182aa4b21e17c2240cef3a5e70ae581fb4d13d189c7d733ab53d2b6cfef00b72b1757d7673fd66a5de9cc72ee525488aa7a33245c1c40bdc5c65cdd256a985b1b92e3c1bdbd23abd4dca1ce33c4eb16f9412d3e154139214fa4629cb45265cf8371facb71db37651cb792c1ac540d1888b8f4adb026c6ef56aedb9c6dd1a64fce69bd746e79abb4e3d9e59fda3d22030d1826ccb1a3ac8fc9f7d6fb61504932c4867eae6643a2b6d079b731eb766662c46362e265890cdba069d4dcbcf98f6e43c66579071c2bb38be7bef627f3d04132bc8ffa737fae4e8f7f97cce635705f911367ae15f375d7beeaad935c82c46362a26549073567693f2c3087f7af4782610b8e13805792dc765dd84cdcd27749cc76b39becdb118d9a4984801f2eaf62284efc1d51a3bf77dcf2d8fb53637635b6d1205e96e8b7771bfb7cbac3e108b918d8cc91972b1e5a08dfe1e3e9bd78251b90f1328c8cb3f5b651446fec93a4ea59f201d65dc3d2f53187d42a6448e7a6113274886f6e73bfb8cb5fa2ae53c8636860aa938c1a40992bdcba67dac27b747df5db498a669f2314dffe9dc3b231bc184097245a78b31857cdfb4fe388f3715ce783cf34e936b7d642d41da67b638ce18e37cd52fe7b112a43b07aff3ba2abc0bc69504e93f9fddc5fc39caacd6161324c8f962534b5dacd4f9b109f31f47c4e408b24e678f56efbecdb6d08701999a1841b2b35add63336be6fa721e7f189de8854911e49dbf9a6bcfd1c5a87d8b08d2fdb2d141fa66753152e63ceec7ae932cde5c5eec5a1f7116231b6b3204e9bc5ccfe9edf2377bbd0c132148e766ff73778cf673b03d4803932048369fb2d71c8b6d326ceeabc919f2363c630204f99cbdaf6db40d726bb5b24cd334b118d9844c7e20abfbaf7eb698e3846f721e3b2f9a890fa45b3a9973ae9741d87f7b205b7cd545fb2e65d6c1f64c30e181b4363ed61ada7676f19dc90ee47aba28eb782174d7ec7520dd9dd3b665cf368ff152931c48777b2783eb31bb22e3e7e2c28184ce5f63ef39dbeab3fb8603931b48fad839d28ebe9ef5d9e00e4c6c20eb8c2ebef9dcc15ae77aedb118d9704ccc90efbeb7dada0bdfe4781b6e4c6a20df3167a753da9c451b8398d04052d88cddd2599ff31856cdae99c5c80688c90c6074ce9c6b7f10765cabad685babf1aee5fe276b9cc7d3544d5343622203596f7d75dd8ff73d378c233089819c7f9bf9c6c9e8746c2d0c644fc60ee374ad52669d97d1984318dd45778e5f5bcc316ef1cdf687acb137a7bb266448baeec3ba38b63ae37bd85108262f901c63cfc50dd6875cdda10f4c5c202f75edbbe7bafda86537fec0640c392b6dd4b67737da7cb69939649a360c6d6022863be7b55c73ed357c9039b8daba8d5aa72f42cee3fa5564b5a413322ee7b35576ca9abdbf9c57411e259c90ce36666e578d1f9aa3209e394dd32446c926243f1a1bf2b51f1dfb47ab91688aa6695abce15a7562dc394d48ea169deeba7b4e48d933212fbdb1cec66e7d7ed15ac79890942dac7fffc218ed9b7665c3979014d2e50e2ea74e7b5d670969af853e9d9dcdbe52d69590df78be77a947cbeebc8b12f2c50b639d8bd955198d91eb570d48ca8b9094990701e4c59bda11813a1ecffb24e4ac8bbd236b6c424948e7e9ecff47d79e832ffe480192e223e545488a5b33288984ecf6565df48ece7dba2889f4e1a20510394dd3344d90c5c8268c1248c855175cb0dd9ef436b695f338446d440fe30c1fe347445f0df9f973065fb7b51c33c7d5f4428ed4fab5f03942ae76b7e79ad3679bac9df398ba9fc842d983665e5e63414923248db0b1fb63f3dd1779aec0c808591b65f4d9e95eb7858e721ec7182aa4521fe4b2796c11b2d969335bb718b5cfa822646cebd9fbcf5bf516991b414922e465cf1d72bf35bf794f4448f7e5fc6f63361947f74a0eb19c47e8abf98aaef16bcc1e650cd665dfbdfd9ffe40506208f9d37943d86075866f7e2124acec99bfc5bad967e12384847f1dfeab1edb743ae390f317736eb96773f6b21eea8628d154490192b292f222240534b99826d08ce9324ae090fdeee9a3cb32c83aaee83fa41907258390fe587baf7d9dcc7fc21b75502208c93f21b4f7576366cee683665e88501208c95ffd7f51870d99afc8bca9420920249c175a667eaef7f99b4c09257f90b5698dceaeed175f73c779fc1eca42d4104af45999a699d0342d1794f841be65b66e9b8fceda16bb73913ec8ca13de1559a3b732636f2624fa4817672a94bc215d64fdf74e36d763cb66737c908de965efda581d8cad35b8dc90b5fa7dbfdab1c6ff1c4e9333926962deb03312e656286943ce0a61bfbf8bcd7e3d1925fa6c28d1a7232a61433eba383a6646e9622fd23dc8dad6dfadaf1f46d8ba398f535e82a480a89016d304a242769aaa69aa8f6495ac21efe2ff77bfac46dace2ede70e56644bd84123dc8051775d6ef5ecabed52f324dd334239aa6b678c3a2cf9b1135753f9d2794a8216d63f1babecc2a3f742b461894e441de6bd9a3ff36ceaef7effd16519dcb8c123cc8562be5fae0ba6e417fb889d3b4d9cc696290c5c80649c91d2483d646da5f27eb1669b483bc953ebfeb75ba66b7da3a48171964b8ae57ea3532ff50d304598c6cc028a1434718577bee45065d2f876f45c6b6319dccbd2ea8d292c24222d01c64335fac358badeb7cb0c941aec8d7c26e8bcde96f31ce6318070929bb93f6b4bc22abfd70906dd6196d8bebbdbeb0716331b20941c91ba4a55eb9b11aebbc0c574d43062f4252364d038d23649ddf3e46c7ae1fda081b21a3ede9bcfd2dbb191a46c8c8eea3b4c50b2df5e7e822a4ab8e99f7b20e6173c740a3084967b5fdeeb17395e1738990eeba375dadad5dbbd5102161eb0bafed09b9aec9da2124ff7dd3f5c7387dd96a08e922e5b7babeb5dc72ad0b21ad63466f7b3769a5712d186808e1bdea8bdcdc1ce1f78cc3c5d68dc1c8adb1e7eeb56efad6a5ee3dd8e87c4e82060ee9ea5bec5a7737725bf7721e6faa8dfd7cd556a019847c666dc1e7bebecd5717e7f1a713f3a4a011847c3376376bb0d90addb46ff10d348190ec56fabe3d63ffd673721e57b5534dda0c9da0018484b75ad7ec6c43e6f15dcee3c647429408182f012841f307f9f8adf8a2c3469dcfc63e0fa2366f0a1a3f48db9a2db7dceb56576bd5e480b81d15347d90adb2e50aadff7d96b5c9dd469a37e48b7ff9b6bbfe3d5d35721e579bc62548d0f081a7a57143bef59e1bb4f645ce63c647d0b4215bc3778fb6ab76cef63c76e5d3c5345547288ae3adb5d6dcdddddddd19638c31c618ebeeeeeeee66666666e6089f6bce9a81a4acf780462f294384a42c6631b211800e346c48f7f6359bf0d9e9cfd5f620e3e2bfcfd56b3d46ebb8d9e84dcd1a92ad2fee3a6f63ad3646f520ad3b9f163e74ecae7b5ba3c6f2e570b1079b7384f1c566462773eaaea3f63e7e1102aaf8bd409307d9d3be6e3cd9ecea98313c48c69eb7fb6bf6838e69c71f9a3bc837db337e34fea26ddd0eb23a735e8fe9a477cdf60e68ea20ed73cfc566975d66f05a3ac8fa3ddd5747e6bfdeb47390f15e66d4c27add5bfea61c66f3652cbaa6d4c541def637c2e53436beed3138c89eec208cb3ddf6e3c741346f906cfb7eecf726cfc830529f4d1af2b5b61c6cf3ad7aafabd70dd2adffd7cd93da36c87f7d216dcc3247a78b970d32b668a79bf4bed77adb5d8384cf2efbfcded76c9dedaa4146660bf6856cb548df6f1ae45d0c23a4ccbae69af58b06f996bb95ae696b3357d73d83a4b4f65b77c1cbf0f6bf19a4c7199b7de7e5e674fa6590917d652dda66f6b9854f06f96ebd75dac9dcc70ae1a3212b5cdffcf15d47eefe31c8f90e63abebc1d8dcdf8a4142eabca67f43ead1551b06d95c5c3fdfa37ea1756ac120affde6da8d6fbe38e9d72fc84b678c76c667de62acd50b923ecbb4f2ec1b99fd58bb206d6d8cb5eacb7573ec552ec88e76b1b5d3f67df55ddd82ac8f29336fac6a41b265c8bee9ab1f6d8c340b92cee83ef247cb20a38e6241ba1aa15738bf3d63cbd12b48f7e2bdf0557bd77b736a0549ed62a6edec73dbdecf2a4846db32ebd6b3d7cc7d5241be5358df7c5fac7ae3390519d775eea96b8fe9ec35a5209fadd459bcd4b5e7ed4641cef91d6775bde0d7f6ce9035fa85f0d508e1bbd7452848c8ce27bb6af92db72d3e41c6b710d6bf3dffb2d8a213a4bbcc42a6def4459e2b3641da47e97ad0ae09978b8f09d2eb8490f56d0f2e415a7f73ad1721bbf3de0695202fe409d9196de7983b4c82646eb3ce7ed6dfcfcb201264b3f9bcd9fa864790d1c5b68d56462773fd4690ce1bbbf894de7efab408d2dfb608e3c70799ad4904d9b53edbaaa5add9f8e21064b53ee76b8ed54b2f83429097b63b57d7b7af36c320c816ad5bfd2e7f9bec1d10e4ac90f9b6b37bcc20fb81bc6e3d325ff7e9a48bf94032e89ec1f72e75ffdc3d90f52bafb69c756c35ca8f07d2b5f6eeceb7dd4819bf1dc8f64ddf23adf6efbcebe9404ec636c6c9de0bfebd3990b679edba66a50d69b338900debb2eead577703d9ee3eb76d5a6add84cfd940fabb5f6ffd67f75b73ce8cda6fd1afd0b9d740c29fb0b27a978dec6f391ac8f6ae5f9fbf9beed29f81a4f02b6bcfb1177b95817c7ddfd7357945b89c8d8174cbd8ec4921bfad0e0319ebfc6f6fc50927645a86f4b71c4f47a3c775a92343fe5fbaa24f1a6d6d97db0b6465cdda36cbfc2d57ad0b248dee35bcfdcc3563c8bbd8aaae27ab1ce784ae1143fa5ddc225bff1af4e8bc13f231d6e072d6debcce35e7847cede8dbda70bd5ed57d1312b6ed78617f378cd35d1332b6d7ec3ad8d5bd789967423e6be3ebf6d31b42cb1c13f21d73f5fbcef64bc86967bd7e2f83cc685f4b4867e17ff7476baddf5a09f9f7bdbeeb21656e394a09b9dc3abd0e7a7bc70a27216f3fdb9a316ffd6d1f9384642e3a73cae6eafb5cb348c8fbb73e67f359e7e6650609e9bafb3aeb1f6b3767f608f9fffd6ddd9d73b62de608d9dc3f658d6ffb657b1b212d85ebed5a333257fa8c9090619dff6b45d61eed22e4735b8b5abecc5fe354846cfada6d77e337a77176222465eb229df0355eb3672342ae49ab6dd0a77de65cec43c8c5abf6834d27fbc9b00d215f5bd6d969d95b685f77212474b4ba181fe3f5e6432684b46db6dff65ab3f5b28f43d246dbbdccad166be387433eb62c9b0e5aff87d10e42366dad5d6bad20e473eef2f4e8de318d3110f2efdbaf8fa3f5c72820e48c6eba7f0b36cb6dc23fc876aeedaacd9b3af3e60759e16567ecf274f7f0f39efa48369173f441322f8f6ebab518f305b90b39de9073725f9eab3666bb32c879cc2c0d39f8209f3d5ede7aaee777bdc779bcfa0b39dc9097327bed2edb7541db57c8d1867c2eda6efc6fcd79a333a79a5b8462b828401672b021d7b42ed6d77cb97563b59cc7cc43c8b107e97f9fe1b4eded5ad5ddb5de629aaa14205ca4ea6ecc626463801de458433ea73f2bbbcfcf1b7cce79dcfc1239f4206bd7e598ffdb4ba9c3c979ccbac83475403e9ecea7936eeaeb3672a821e18dee28ad2bde08b945cee3694a22da7cfdfaa13e33a24e10d1344d53354d4080cc70e1a323aaaa8f21326d804cd334d5ce34b9223f3621ea6e3cf5ed34857ec30800478e3c48e71832ff1bdfbc8e617540c88107196df51a1f8b34b267ebba83b4de0e3aeaac33c86b393bc8e5ee9dbb8bd55e16610721471de4bc17d267635cfcdcbf4a07e9ef5683973d5cd6798b73905c9f33b57e7fdd385ddf20871c64ac77ddff07637d74d6fb221172c441fe6cb7cfaf9baf3ebf8ef378f3e01839e020ed8ab3e19dac2b85eb43a056418e3748d7adcddb207ddc2b726f380db95ae40bd7a4d429576b398fe1e3400e37c8656b75932f5dd4c55579866eba3f44a6c9c275841c6d9097c1fb1c63af45ebd41fe7c9e460836c7575f3e8b1b24a1b6d1bd1c33c167d9098630db2f1737e6b756bcec5feaa417eabefebfb6c0e7fd99b06b9a83b5ae3a37da1adeea241526e7459fe37fffff93d83e4659fa374da7663f4f56690cdb3f931b33ce7b3d396415a0bab63abebaa707a5b32485ef3dbd5699fa50ed9a221eb9ad3ad6d95f6dbbe750c92b5f77c7dde39fd2dad6290b12fdb7fb4b938b9d21a0669179bcb2984ccd6d6af8241ae3aadc73add3bceeaf50bd2b2ef091757e610ba55bd20ed74d4b2f7ac1bb37e6917a483b6ce7f2dde8e943ee582b45da3ffe2c5fafeb2740b32aec8625cf6368dd629d582b4afed6b5a5f73cbb549b320a38bfe91f2adac9f6b140bd27eeb369f3b579f2da35790fd2d7a5dde627c0b32b5825c6bba8eafddd51cfd45ab20179bb53e66deef61a4930a9299bf76e7699db519e714246d6daec6fe4ed6e6d32805b95e83d456d74ffd7bc628481a1d5b67bd315cb1bd78866cf76c2d7ece277db52314e43f87d7adc77139641c9f2027d308fbbd06676d6b4527488793c6f7decd9fa50f9b20e743f8d8f3e89c65944226483b6765cff432537e0f2e414ef7165f7b87b335e7500992bddeeb7132d88bdb7d49909399478e70fa74bdfa2141be175d656c99df11a4d3a68b3238e9f5690469d7a2ad394bfbc6d56811648c8c3a868d3173ab3a11243386cc9e5617d7a3ed86202fadd0b6a5d3df53674d0832bae560bb752dc3176310a48ddc6bc1bf0f3a770804d996a3cc2ba476adc6dc7f20fdf662d3ef5bee6f6b1fc8fbccd66b117275372ed6037919474bb93a7b7651ca03795f73436bdde78b0d7b07b21973e5c8e2ac1e2bd581846c9b356df3bde5eb9c0319efbd8e3fb275f7d98a0309e1f467b13d7803e993ffd6cbae8dbf9e17e7f1c7cc8faf20870de474c7663fb61665d3a319b2df556be7d7e991d25703f9dec5c9fc60b3fb5cbb349090adfa1de15fe89abd33901e9788a864f0aa959196a22086310010425949150063130030302c1e8d86a3f178a2287af203140004597e6a9a422e124983c1500ca3208a82180662100008208410628cf14a116e00c03ef6a440347b8ef61d6168e8db8d0df74bf5611d510b68ad2dc4e0fd4d8a705a5d0d20b5810f42cc59fd9f4544d406b19c83a5727210ac88d8bc7a22b7f22c74413e376766d43f788a5fac2fdf055a20aaed78093242b7db8e7c7791f20bbdc6d4e1d1c0af715c1647479b78593ce764b6f93fdf909a5f5470cd7fea27029f280eab52b3137df15661e3323b8ff7015830f651a7273da49283635c46bc941e5f330b5c53695aa4c414c740ac11cc8cf434f43e3b88e4e300cbcf1b5855b61443e3b7cf3ae2f58cbe3a857309bbf341814fac97189f5c7dbbd563afe96028de3f4d559c637775ef79a3917c321f061cf708f244ab71818e38d3693729bbadf51eb454afaaa0d78a3f4d96679d2e21ac2a4724c040e4260cf2b64988d8840a4f118c18df8bb57c4b12d0f1378c3da0aaf7845d991ff3d2e20506a60f0aa374a0c8efa7fca2a0a21527897b47f660b144cda256ae37b42d3e55cd014e24343b0245cc00d7683431844a4d024634b43b04256600d928b43186524d014344b43a0635a600ad515aa79145472ba4a62af3940685bac813d562c2a15454487a9b188e64b508086641d025fc6b50cfeb6ff590124f46d0febcbdae95a0e40be251b52f6d3c1b83e9328941be548d995566b1a4bacbc4fb17900195418442a82bab0fe602070a2030b4eed4f5c941dd598cb823f387efd4d4632b82e965e5d48ddeaf1cb73606e2728a1388010a05ff86fe03848fab7cf105a2e4006f4b5c860909ce6cb43b4223b61ad1179b067e396222d21b4b2fb206a21d49117b35622ed207421dbb22a26e4e92315b2af3bd8e0d743812230636e22eb60c9c3ab2a2440bdbb494cb10a390de587a252ed413d3d1fe6ff0381dd8e5b83a72928c8a309d4fe6985bc7bfc47c0397c5f1dbe276fa2f2b5ff4b24dac5c183104e9264bedc585d4cb8a6f1d058ca38db8ce6e276d68cbd03a55b24bd0f5d2245eb95cd7fc4bcf0aad93978332a153c81bf241fd5a11d38da48bbd066e1cb1474aeaa8c08413c8ccb8a5ff1bcd97b5b4daf0a490ab1173b17d4c28bf2cb7e87f9bb272156230d209961ab214a29b2415dbcb2d9a5f38cb4feb8525bd6b510ddf74b7417f656659966b0d9b666a9e068e85db46721620ba2f4a001204182f961cef46f5396b295ef6f0725dcc37df84e951d1da2c706a31db74f290f1fde9e2a18c31dc6c1ca3fd8cd71ea7da9dbbdcddb6d970c5a861734295122e6558f85afbaa0ced3d0e494ddca948262bb01a15bd7ba69d12db681ba49b30cbdb7d19f28eb2710b7b85237b6b0e9d4bde82f1c80913ca03e9e787d9c605cec4ea6c6783853117b6c7ce70855075dd0ab7eca674514177509eea1601f155d06c868f7e9ac0a2bb4a93744b2c62e552a7df82c7c80e9410c6568f1a106f5926ebb53c43f68cca8287dd6264cde7ba3e28ed5506c217ce7c270e662b2b5907a87fe8cbf965efb3b7b4b5c7729ea531371476482df40841102bfaf61c052b0f0f36752491b2b48b4d352190a2dbc7847ac805d697dac9d4db56be954d37ef10cef6614f290e60e834e594ac79483a807ecc9167e8b4e7fc17e64d6a7197a7ffb60324d2c0f265701d05829a8c5336af89c889c2e384a5052572bc0366cc4b3f92f636866a4a0ba2bb4e41041b08b68d12286dc13911d2ed884c9befd5c8c24c76df134c28b0aefdbe99986f8071a010630bccc416981aba14c7171b16bdf4baa4b93303585488bca03c33f1fe37cec4ed5e7db1cd7835346c12ffd18a84c2146237de06cdcdc199f64778ebcd2534020bf1c675f868d73e0457b31e2ec063f3fb0a85487dd6f5fb2fd7689e767eed5744420be03cd8cc05d25fc961271803032f9c728593fcde6332a54317018b5a471ad5e0677b35288e62d90ee373d126c2e93a29f3d340ac41f68f323ae6e2f80e81b27bcb68aada9e470c4716f437ef848369151d5cf6d460e9a38c27532573379c0dfc3517c428f52d4c94ae18c3bc42254650002d2c6493ba240c163a89265f3d0fe4f44eb282f3933c701949a201f1c217b46b28d8f5f9340f6559debd6f3a3d304a6926664c1c7740d4ebe62c7e155015dcba450bd716f65abdc3fadd02458bd856f5b550c362b9c58c56695bf06b51864573ab2e5ad8b6b8d7e28755e416315ae8b650d7ea1a16d32d68b4e06db55c8b362c9c5bd868f5b6c55f0b342ca25b55475d0368f1440ef9b59d3bde22f31d0369abd85d6897557dec455c4cc6a0f8559e314a7dd11cc36957b5cb6c70c7015b75b281a61ea2d4062f8d92666d82865b3a2cbf715deb6b0cd46144d7a1ffad2adf582b639a0c6ab5f23da3b046c3335cbed52e8d6b32de6aa03d6be437b4d3509f63115927af415d07ff1a85606d26c3d91b16695c36eb171bc86dc4df0d3dbdaa93b17e8d9977d0a5959b8c626fd8908db0ce78dfdc349ff6e9ba2abdbc22ab74781919c3ce111c1ef12dfe652bec7b42cb849dc1fa7340d3d0f77f6d6337f7df82cc9804a31b7468715d4016c709787d4f16e4065c7fdb19eaa279bfa83073765a6739bf1351e54f40e22a2ed8f7640d0d477fa262f489c1ae543fa3dad1213ec7a51a841cd666717e315c756d879077f10f392723212f29cee423df9a0c0bc3faca117b65bf562bac05247f0d95d89e1da5722ffc705194fa79afadfc08b0004faca5e3497d63ae05195f38e2262756700962671bde531c050685e24b445c7a0a995f26d17990d010f188d9b926e1d70e778b0f1e1411ccbe087cbf73c6a8274169ba76a8ed86ea20f28f3d7f27e94f2ec26f5cc5086c13f48d54e9f2bb5f0e7aac40cdc85e5c5522d0d07c8f135a0d67d9ef80b87cb7c8ef882c1dfd379e4b1ca17ff286936d98fb4fcbfd43a428c3b888510f14cef3f8a1228446e62f3ebfbf801a18e91203712601f84ebdd7b4c8d53ee143988c3ba2e7cf07f0de2e122141d06a40c9bdaea3c5d667edada6624e0edd34b520922ba36ff7db796b15cd379c03b7eb0cb5923ea410a9d47b0e2f223fa4fbd6e450354e7f2504f4df5cf4e1ac89b8eb197ca51d44e6c78fe0d066e627ec8ba4549b6f0a72cd04ebbfe59cf1eebb1e294fc75bedce8f02c3c5ce6769e661f1af1366453ffaea09e3e2c3dfb8dcfbb9def19990f05124a4d3bd87cfa9959ca9249122ee17e94c077ba424750a2a93e1fbaeada94959aab5b77616f436a9c6f788db4ad2b58c1a6d0e684530461ea6ec69e43b661f939b7b3cb02792844409aee219971f726fc7e7d87c8991a18a7adac404bb843238f551c28e41c55f69e772ac4eb54eb212708e75e70f176c0addba40d31567ed46f177816bc26d2282a95b7ef80148e8d3b689cc47ce52f679a1435fca2503b85ef17607876b7f92923f06f74b9908c0cc0730b031422c631b3e7a26ad511bbebfe0a908d334737b839333df9933a4b779edcf934dc68fd7432a623579ebe5cd3188f5d1aab6bf1ce093dd198020139c92dba6a4850e0596c1f317978aa487884803257c71fb8e8bbfcb2566fc88572d71082992bff27a380da0e51382d7f438f4070dd56fa239e89f7e4888d5c9ed7685e2290dcdf23aa6a8c02fde2cd94903d347eb7033a77246c998f064b19f922b17855903e69d553d04a0f6713a78de139d6d1ceb4694ce727a5c27ea06a3249a2e2a559a6da78357142b20e0089356cc31a9083ae55380fa68403147bd78ece1123224cc9f5dbfa4b07e09f8bd21a114249896b4df49dae845a4cb3cbecef597936000d8be25cd19e5b88bef4a557c398606e21965771450f4a5aa10597598a6fd4bf570190c308bc353d738c6f7891c4f12ca7b93a81fbc00505211291fffb4fef73b01f66eaac5a1bd1756c0818ea8abdee109d333e504cfa007d240142d0039dc1dfde81437d3e7add96ce88716644aaa3e275acd46d28fd9dc73f345f6b3f66ab40446a8c05e06ddd0845d07bc27f6b7cad87d00408eae632c5022bc42de5f160def1dc433bb5fe55d7b31e80aaa249219f58926c5970b2ab480bb6f8faf43ca4d833d97708dd997e0897c4ffe2efcb8f305b23c2015a9f70502c42bc0e5242403c3c90272dba7f8fd2538604a5e6221148eba4566f9af324ef844bee428366f32b279beabe6d0ab7e9c63c7dfc2e59e9281e8305eb71f0391a8aab77a1fb73db179e58d100ad2b09be65dddae58f344dca000f71200e27b63e0e7f9563481aa3dd2143e80d118a5aca32c02782db66e6439c9cd38c4fba064de9bc0de147522bc701f2e00f04212ef34ed702e017b623e53f9e48fd659da91e073b3ae75d2861cb3b41a77770d3627fb83aa75a2e88907482fd8586f69c8acce86d35a3b515a06c59c3e1e16c5944bf4e1718d6261d46e2fec908b569dbee34e195b6d751e188d3c60822849889cde55ad4c92d74111e0ac2b65a50683789c797e0d99f3b8b9398b744d2cc17c366868104f1b9f9db742325431149ff2546b7a51514829021be68331d8dd47b31d3799476ea3020419016cdb2c37e6a0a96dd19bc7e99a554f2a2ca1227f5db47b7e749526c9d65fee40e3fa2d6c0a6311e014c430a0f3220de787861ea4478eae17993b2ed31ec8fdd1ca7884d399f2e31fc8c9fe12c6c38890fd6b190bfa1341e63dd6f167abe9986a0853e59c434b30c1582a5385524445e2d7beb7176add1b8ff3d1a26b790c03697bc14646b4429f71eb20ae4db9a8e6b2d5d05e33fdb4e71caa9d35f692746242f49b6ccf5d44df5fd1011df591a66e3b9ce474156ac66113d8332499af1a49a1bea188fed2952c70de93d1b7779edbcb4c5e51b5c3816a728bf0308616e637cef76fa6d26ce824c5930dcb0dc1782df32613e8c29dd89461967585c0073f204507682b1cfee09e7cd246e0259b780afbf3fb8e297b2df2898245b5ff37a816a148cb1c185a76798c4209ea1a6cb3bb71fedf267553e622a49767e724aa594ffe57652577ca2036b1429cc9e7a528185d4302b9dd17fb3ef69c66a59620a9ead454d36ba99a88a8b94b1ed22a5677ae3fba95d37a179571f3d4ff693c1de9a1a36bba217ac15f026aca5ec0e28188eaf2cc243f89bb9591c44da6b52e9d773d17112fd1eb4b9df655206a6b87a074a0c55fdf375e319590e62e4969c93b0e254a792ee253a25c9dcff4d506ed53961066aaa304f2b18d2b4f965137a6f668f9e2914cb8b78f8590d852023ef7afb80f030d5659ea1613b2dbecb41277da0def3deba0051b1f5e71c93259b7dedb64d844c61cedd5a8c377739bcf408afc50546cab65551eb3d8615e6f1a500fa5bad569a772507b12a557abbfef016b4e869298811cee56683b7be466088f2050cfbed4cd922dc70c3753a04dc841acbf06d11da42057d57e45f57fc304edf0d22a84a55d982864e8c754e09c40aa1fc9e134d83b965702b8a48bd9075ee7108fe36a68d18034e3f5bf1997d1bf273880807d32fcd6487bac28315d286ed401814f921de50198bc57604ef4674175d442492f921d0630d261ab364cb8057aaae69a6b334aa85d99754146b59264b6cf27be1b87cf894fa7fec72f3d4be3dba0344647c0dcd4fad9a0dae4e20a12947f02c2f33c9ee5110e8a83a04871538980d9dca4b797ecdc32a735a53528123741455be5d05e27968fdfdd2cb8f81e75d2d902be426a9ce9e718a14bf41134e6e93b4e3e0ae32dd9e1bd8cc355dc6c58095a4e90d8b3169fb0ca5cf2c76dd4b0cc5bc19b54665370d63e51191cf0c7863d68ebbc1f22335fbd4247b004a43ff3e5e398e32b2b5b00fe91668af55a94639d340bb836564cc5503e18b7423fbeb9204554b9b41987bbcd82afff1362d666b76baaa3beebd58451579bfe256c66c5291132383fe50a489c041394b6fa2501b98b8d9ad5cfdc79a3a7172817c0be07f91154af6125638cdfa772e5390a4014952440686d30e572d1242c68d4fa8e1e4c381e1c461badaeb023523944d8d49a3599240faa8fa8462137b89c17a6117f2b3a9114421b9a1df747148b22681bbe9617c0a6647584499be813f8474cb31fbcdca8572c269770c1fb721ed75c3be1d0bf36bccc99d533b007ba7f80ea2035f5c5587f28bc08da9185a7e80d62ae65e90440ea2df604b2fd2b747feb45eee25eeedff5ff7228f4823e108e7506d4b0b8a864065686a2fda4f6b056480ad750c41e436abef1444eb1201061109633e14a99f081d0df7ae3ed84a69f8ff8095191e9f35e7a936588e3bb6e518b1c8dd5520ad87c6662381c920a44b1368709cc922e0763574ad0f8a5e106b4ddf2cf90331013318ce0698922771336c3e778b6f92f8298132ed5519b82bc9354544ccc3d8413997b4e641973c296e87ace7f9d26cd58a13461fe902626f4972106d7c1d4b87e6d33ef76f8a840572bd0762a0273f4beb07e74e48e481c7d61f3c6c54e758dab93d8525966583625153c95e472d537b64b9a4f532a830b43043700aaa39c8a7f6e54bb1f3185200f12e9e24e31a827493a4bd3e44849844d0a617b77304829c986729ec4b6c0b0fd58e2703e6fe4d990328d6c30f0ca073a0c8da671939601005ce50221ba2c4a5375e525649a12d86d8d6b67dd4dae83d82f2d4e519410a4b7285480feb5919d995fe3bd95752841aad49190b4d809316bc0b658fc75b9979931c9eae19279e5eb6fdfca417fb9a9f6ea5efe4ef1a370e67c68f2e98a3695be1d099f8731f5aa5f5a14b534368a4c2b4c7b5b6b542709b4becfcafbb8e73e6ce0f7e61edaeed2dd28736ebedf03e8132c3cb8f3c917e0f95cb08c28b3c93fa4e1a468a4e967e8058ed173fff9bc1135503c50e7f6aa0b6a80cf1941a4bb1216db06d8a5d9387c8451f889420a5b9d78485512e496d262e2c170c11a5fb88abfe294daae3615c6234a3b443ce6b7ccf98abe848e7cde138095329f9bf2f591a577b1954dd07d5a278048dc3eb1a1ede406bb26b7b8def94b67fa1e91a49291c11225936b163cb38a1b24b1b2504ae35ed4afd2010d96493f0a2e8c791a596fad4dba977ade6be75e6b32d8592363b0936cd8f9e47c9e3a6addcfa17fce0df7b885d27a64dfd6d8b2ab779470afb259403799c9e50a4e2024d09b92b43ce18776002c5799925932a561ea3512179400436170d10ef6866a5f2cc22b97c81cb495ee77379ab21e4c2c4b5d150fe7c5327dd6bb1ddb9275bd95cbfbd760462a798f00a2787c4366d2942fa8c2a779441dfa3a40387e1b5831698a9b4148380d157dc25f9186455146cd767dbbf4b858576b03dae235e5e9bd54039e34f55a7e26c60b1ce8a51b4de9c0d82fc766a2d032de07011ea0732a90431bac4dd5abed3e11979e3ec6614d12041bdfbcbe16e01f370e9e2c3887385e0ea7f50cbc3cf6e4f2dad01c243cb7bc6267e100b6c01ab62b2f0f0367287fee581ccde8adf52ef81fa2a5eadebbdbc21888550bbbf25b110b3e8f17720570f2421e5ccb58b3c687f050a20eb9f853c9d23bc9e2a2c6a79994de238040d1dc7a0f266158d08a800eacef02346932bc301f712801f068d24a095192310014fb0d1723eff46c802169607eb100908fc48247546758569e9f109b1ef79c5c4a72cce6c4e8c841a88e3b278426c307c76872285f3a058df5271786c874c2afb1b2f8b1fc73bf7d72d1b341c6585f8f9fade1b6e5d6bdf442ae84a7de9d14c82a49bcaa16aa217dd2a1b625812c352cc0ad60a958382702c2f6903eba36872d22582cffec8d4885a1f7ea2a8c21083effbad3cf83d14b75e746c67a69c74fbe61d8c6be7e5455a24f92c671b98117011c1ac04dd9afb756cf440606a1ac349509f3bdc171f51fd526b06fa21d41a74176fc92029899cbdd311876cb419644facd1d5765fe24e06926bf1c2a3c5549383c287d49bb9340eafd09642634eef18504e04ddf0ccf62b06bfc0455f1c52e2978cbc105507d43c5d391fd6e60e243005886e9082a488c80f09564067f9329d546ce0b47435484e53bfb8a3010bdd463c8d4901bee7d2d21222f618e5714580eacbffe81fbef2739c0713a880e8ba7111650da432a158a6ce78f77644c1ecba2cf34915f50ce62d35dbc9103e0aede0442700e43935d1732f89e9816ddf920a10589d0502ff690d3e25663d2e84f49ed758909865c01fc44c568d0b8bba6e1f9bf59e56a146f1dcdf4e4d458e841d5836a6a57c2ae2e04f2f195093c09372dadf73ec1ef940daa4603f770d4ac65338e0f90cd03d758184879c4d17767de5108b0d4f22db99048f10f46f0d321284058a158a716c077093ca5215b380644d1d922e1145a7dddf716015dfd7499a381be17f4ab2ab9fae43d5db30973aaafcc5223883940d0d3b0a7833903c90904293c4b7b88c7e6a8fd734f5428f0a29c4648c418a6e0357f2ee9c883daa3135e28eca0a75e06b18b51f8081c452114027f1b64006c59047e96c200505405f048f82d108130e593f0190a0241d0178123e0b64200c7a9f2fb40a87ccf1755ebcbb25c509d595394aaae116e3932d53b538c88877f023f9863bf09f61898f179bc670cc5efec43c1f319c1ec5d8d737aac1a2286c1787242140145936f5397db79dc31f8626dfedff3101993725363c3246bbb538d2c454bd0a25cdb69cffb77f6130391dc204e6d7f6fd2bd7aaf37f649bcb48f6ebfb5533becf4bef2e5e4530a49a088f88fb1581d153fb0200621229d9f3b6f87b6d007c589f3e4b8241b5549fdeca443fbf6fdb5f3ca34f45abf8368f47e269ce28e1091d392f91a755e647abcedaf931fc270206837028b605727b0649f35f92ff79edfef7f31971628892ded4412ffe68702577d8c0a008cca2b21dbbdf19ab264a423fe5105c80880bfefb1b04635a45ceed05040a342edb74ab7298c817ec3a69fce4c638ef407b43a4c022839aa1542ef34c57aaa6f86ed755e9199adc08ec0cca900b9f9055148b23d931eb70a9594e72389e1e639be4641befb49b6283b53a6fa2b48a27bbc90dce3cb532319a6fbfbb9c132e1ed0e52ebd1d627472098d895c0fa10cebf8d7f3a3911e0e5def01884ceed6d2bd854ab07808e83942d3b37b0feeaef0f36f0a87abde0620696634cbc1466917b0d2ed67e70bfe1e5e0512cfcb27c80e8d7537cda2a9d93649fa61e2fc705df0b6ad3f520bd8faa12140f6b52398b8b0c503f11a6eda3977e60cbcbb8fa55b389668d5f6e258d8123608a591d9cd52dc24a7f7f8debf662dfe958de04526bd4a9c8c37b8c44b1b7ca7bbfff6357afdf6edf047f13988dbc4cb4641bb9003658e1c763c8fd206b96821d1281d2fee0be074c3b4b56a48850e09a8eb9c165631d805d85f6d238b847a676428dc9b04b3b742021d7dd890972be0a32abbc913558a4f417fbfcfb396dd189dde5623fecf9af4dda686518cbd2db55081fe335ad8081db398c83421cdcf230ffd96721e7d8d921092d617cac5a8bf4dc3380c0d83ae6f739318fe3936f4f021b45bf1a112c9167a48a04079b8422ab4e70bece405eed0cc0626fc4bb1e5a1cfedd31c74abfc41b64ec5b6a9419a002fd88959e72a605ed59206ae936b79ec0a9743f981e128e05f709a83521d048c3fc2fd7f9607042476c06ef5fabc2332c583f68de3c4bd884da90996ff53012dbd7e66ed4ae4ca24c7e5461b4221fc0e77752678ee914ec852658452bac7c7320bcd5c11f32b09bdcfa49f714cacb9a2076eaed96c46b1b95806c65e154516a08832d769fea12ed0504340d1f8799d77757b00f3a568fc137fd06346bde0d06ae1f50856b6c0d79c1ae930ae85c9b9ce4d3d83f6bed66187a6a6703346b27bfd6bbcb0daa3801ea1cec5af7b85a76c7ba94a3752ff3d6083e5f4ced826068453092c869d74847ed76ff96f6b8258b2f752d1041431af1d6847f51ad9911ced22d2c5ba38aa970f63c7bc28aa647caacf1c0db3a612a35d5fa9b74efc917b9cd8d727ecda576f0fcd0f92fe45e0be1fbcdeebf68f460d09511647b6448a2a791fe7dd2a392defcb3d7e461f68b0b42ad999d645549e2411ffba6f120fbac7af9c24e72d818e96a8884a75b72eff36d0e081ae6b030de0c3037d1fa22e8a99b29616cc7924b0319346d756f3ce9eb78f62d9fb0a6319845546cff6f395d16e19e0f370241eabb1cc453170fdeafbe019f0130e28814890900510e15cc9d3bf124b28bd4eb0018a8aad49acc320cf08d58f7d32f486ca56ffaa2c83b4b394cd1d5d9e39cb303ea2de75b2a3f5c7e3261a345f2a3919d2ebb0e1a873e9a76d568bcf8eee7649b5973acf71bfea9e1be04c6e36f387bdbcfb65e5efe2d1a73c70e79c9569724cc3fcbd7ced46ca039b2140a46307f86a172b558eac56da7922d72378db41c14ba8b0d02f70c436c623a01828d724342d000c5d6dc9e70f40013035e4d1c9a5559ef39bea42c5cdc001c6e735390bb9370ec05e99fd364b6b5068be035e66edbaa08b38db961fa35dbd2ab754f1f8dae74c8d07cd36520447eb6d52e78981a22dde389761af78e72d7bfa7ede68cc5cd4f175b5b6817119e9db4c71f2d4298bcd5223f37d85d72e5dedd8466ce5c0679e85ec930bc8da509be3654062107f0dbd5789fed93a1e2ff2398ad48317786135b7b10d3b8081bf62b3bf4e26f338bc7a38b8727e083d4ab3839bf8427135efd0d82895bbc9f9e5397b117beabcbdd403fc0c9f13006e2a699819352b73a9627ece9df07df6b4e93e8f8a3bb9ed5baff4915f9987dacf7a409549f77ba0f8e58b5354921994b0bf061a32ed41e3dfcf4d534caac4356eccae07c98a338af9245ae7e1addd5dd6c0c534431875f09cb334c344966eb19066d6b150b8198f40a6d66afe827fcf8cef3f3c3b2f3a31c992e11fc1fab3f4d802e4071ff7f1dda64cf41867347a4d25d98fd5557a34bfd07b77efd1796d92ffbf28bcdfbd3b8ebb38ae393879a8c44d60b8de1095c7462fdf67077bacc80117e78ad2c4cc86081f24fcfd1238d23d1d018e194e50f287ed4bcbc51aa836cff51729b9a019fba6ebdf979dfb7656ac33a5ebf12f9524af9d68ee00f30a1500ab688edcf2e495afaf7504a8e340e5bd8f9de33878933691f04c72feced32bbe92e301d7550b2217708cffbbe632094beb5a9bf23cfdbf5aff71d9d8556ecfefbd326ded2d331e1ad67f25f966e604c89445dd307500817c9c5f9d5fab86d44fa7ed2737c43d3782e759da40ad9e8418cbcfe50cf36ce4de3e479a4ac5e23c690b73b69f0d27c5983ba79f37d4d97ac3dcca5ed0dfcf65f11b6a7862decce17ed67689dda38a4df71563a9329991b1db0887b720a30f28a74ece4e1a96ccac07988f462854e67f9380c242ef09a8efe95a6be4c02706f8a767765b67a7bad4e8bb479482e163264db6521dbaf70ed6bff9820e3c1f850a06e9b37b2eb3ef95956ca3677c0c84ff827c61cd492197eb3d2e0f8910ffc73639e9fcc2978aacdbf453d307f5788445cd48e339a0bcd69e4693bbb078598b3370fc9a99ebcf8217dcbaf1e6df993c58d2450c4747bc637db8d7d6fda1a3beccc7b28ebc28e5638da8f94a997f6aae02aee6953dac94fe83a89800394ca57f00c68c63dadfc0476428cd7ae79ae796f362a21dacbeafe232d827ea9b47b8d88cb18f9ce661148c2dcb03e7aa80730bbf4b12c9b38e77db696593c1b9916ef633bd1bf164a9e70353d5d73bf6d4ba405b24700917aaa4076f11d10e9ef21268077620b0c9fd4075feb4d4c298bd85913b18d854e909371b241a2b4cb7b6bade9fb7fbc8dcb67f631955134197d30f13b7a8fae12b7307426f55ffe6c477d4bf90aa352da52402608ad4e91f14d414b0fda2cb9567643c8f6994a6a0d1704e7bbb38e9007cb4c52748e7b575960bd572b1cd338a900d8dc2f4b95a2029c99579767e666e17b98f2ae3e438f99c46a420404039b0d0cc2f151fd5359a1ce6290169a330b9f5c73b7fc705ec9831fe2b949869b74ec5e83adc3101a7a6886a72fe89a748eee48d4f270dd00f1e982fbe3da37c00062b8bccfef710dc6a81764d66f5d05906166d02da05b041e7fd4e890bd5fb63d717f5e03f6f8271f8e32fa46e753c073c878a0fc3d2041f4b1233e3f077e6e22b99265becd40641939794df96b46c6c78810fc45949b6054245f53ca2f71e2dc14f97b32007710852f07930f0b2cd3403c85cfb83e58e073719f05728cedd3bb2b3d194f96d3f0bdaac5fc67f3d782be3c84c7fba177c6ca61f307addeaf3931510fc45d31b9504ecb6baa7c2dcfe637eebd6d6203863f3fe95d91a5010dae7950ff0b6c14675dd77f8e2bd9b37f727af36be013e00dfcec11044c80db44288f783507e69878ce26e0a9c6e29ad5c8e0a181ee9ed023824f12035680596bb80758461dd835597f05605ef5756d2edfb8f1ede05351ffbc2752e1f3b016ad321a362abcd28e251fcbb663d246d1402f1e10990faf604733ddf1ecae3a66649f9dd3a1b9ffbd132d4bb1af11ccc174106ba9df3dff558c03489ec2446776e2e52190492e3677fbc865a4dec930d5a14d185ab7bc0284581a4b32fae82e1b384cce3317d7e8409fcc7201be49c10488e2288694d029070641f57a0f8142b559a5622366c4f91f8f41f315b905711d18a3fb5b310107d5d000dcd57a641e325a7aaa283301becbaee001fd693f2626aed0ddd517d39048fc4abb656841ed2e669be012e160271bb44479cd8dfc83ab08427e845060c849ad94db01bd5156a8de42c76f236cf1920e56b8f7798c61d1fef9a4588147b4dad0d3ddff7afc5bb02f4157ca808cfff53b0dd86a760db56cac048ee18e3b6d0887aec975dcf9c1aed39ba265ed82ae74101403e46784fc96f9a7af9444a96897f7a73e2d8718abfd497ec01215e841d0055022443f0d9ad14a05e097e12380a508e89c760496aa059c03ef8104419aa3f0292f801b06e1fe6c81832d45054316c108901d5428463b35885f8a87009726a1b3da1078ea367016ac071a0c6b8ec45154b369f48538087e65089ea88a4147eed153813ae0dca8722812429f1ac56f4503e04bf3d041650468761b3a8b56ab3bec12c0960d73d3631b9cb6c664d30b1b886b0d58535a0d22d42a2890e4319a7e519017c1c320f662000729470184aac04f835c000b8bd09f0518a0141500be123e0562210c7c927e0640a012f420f00ab85408c571e0097a9900c0cba003402be2d02329c68025ea6107c2780a84746a541044e419b9839fe63a538285e0e1ce0686965d0606c5e0fa05f9317632c0ec2a7f75871c9b7ff2569e640323df9a8af16a107e6382da6bfc5e59533c6f14cf03a726b0ff07358e2aa814a3fc686a78aef0fcaed790115fa9eb3264d024e82abd80d0f7a74acc55c46a8cdb3c593cf95fd08a08b6a659bf02883543418f71d2607bae5fed5207952f5efb13ee73cf597cb8c58306bb16d4c7f59d25c23ced72a6bd04b0ed87e2534233e2aaacdb04e9c0c77ff20235d952b1d9e69c8c7abbcad49ee595ead1070fbc4a5938bc1bb1b4ed431185dcd7b92dfb8d04d4fd0ebfc0aff2f17faee4309abdd8b1e6f2a995208112a5ba83d4fda2cd1491bc9e199bdca4223522bb30dbe198844c06cac52414a4b7f46c8bb4e74c9d4fc90483b53c348ffcf9ed89ff800ac23b2957a711031638dd9b21751184fb3b7c3924499647a200cf88888c0ecda7d14584a7eb5dbc02d64bcfc80eaa3d826c087a67e6c4885939f74f23cd37808172a3ae9b79134c040da756d6da5372617d339c8b5fcece04e71cd32cf605d7cb84fd98a3f5e10c6c844207c88f2ed27e838d0d243af92d9e7aae63909863d5493ce0e0ef45560a0eb9ae0243cbc74da16d171fdd1bee46a23f07c300cb726c60dfc23e271b623f185f69049fcd4921e50defe37c4ca777bccc8174fe80797015468743fa65c57f7937ed54214694d69028287e7c7552e976a23bd5c7c46f7f52d1b3473333e136048abd60f26d47fb65d7ed16814a7eeec98e44274b5229637ab96295fe0a579da178f26631d94cb012e0e1fa37facc309a51be243292a89d42412680d2329ec4b901747be18fbbb520f9a4f6e6c181881ddc5bd3f773658c9a160475b9b520a8cc5fc6c470c55e364bfe6263a07d44c8a7ed0a045456992116ba411c0caca952377d9b58b27d6758c597cc89ee5835f0848af387dbc8de13765e2dadce1fc03fec394a6d5b747e8040e08010ecb31ca4db31c7d985e7d054823549a65cee90d3d9afd64ff61b97eb7c079fc453a55c4d97379bc2bea3b92c6496a265b012a3d3f35ab0fb09ba21d3422896065612374eaa805ccc417c6c2f8673b9c33c8b5717b042d9e0db14b067ca06c4ad2f42c00ca7ee9faf87c7b6ec446f8243a85f218f4fbf77410c8d741d3b0463046684fb8e1af3991fa593d1693ac60d1ad5ab4e6b0982a20abb6796f9acd62ddc323d76d24f03bd37cec28fbda6430494361afd74eb3dac0c9bb227509b51b0cd5e4a4303844c641e091976e1bdf707114ecfcf919b0688038a73a1cfa39c050a4a4fe8c1403fefde5d778714353f6dc412f727c54a2c4a9180944588883af17b55f6644e906f7c5de55da56464604c647175a2e28a290ce1b284090410b8f990650c1da1771adf39d831f2cede93121b745fcb95b8a20d428103ff73d7578cd646f65c869b86b44f0b2be734b387fcb464ba2c3fc7b59f8cb0eff2c6e92e05f6cf5dcb173df2c5084ee3ca5606abf07222b057178d722d3fbe2e4f20e277b6f9fb3b4de253680b48adb05a8bde23242d1270b66989e17f365d2d3cbf7c22a1b11b52d023f1ea4119fb2aeefebe5bf7b7d949e8abd0e57048dee8979fa8f9a923689f5399e2691e91dfda84737a3957358218f174566e5a07857b28656c36f624bf23d917ecdb60b68fa859d0b0fcaf511b0deb591e137131542ccb16436dbbf1a3aacd7008e7237e8d58f9d026932331668169d0ddf7ab3a9c8d73c1fd305e7513bc7f12f2182f9b58bfdc36a56c6a6679f3ad8875b493b2c5bec3aa380788a6d35c4ce754139e74f2627efcba8b838ac86085f3ef65b12df9145656a71bef88ecca6ee97a02b79e2691e0e9036be9d6a3b10441186b426bd7338ce79e806733087a7b8f37e22bfb3247ba09399f6d696c85bea41b139e723c22f918fab56ac96075961f4b787ac1d0a70bee3736d882b95246ed29075db870b758b8e07e7e87e6c4852e3d9b45ead8383c59a08ac2851b403557dbc3b2237556e211e8f50affd7bd30c6203da89b9f022e4b267c037bbd31ca665aed9eb1ac7dc62769928695cf1556b17d16ed57ecf342bd483fff7f4e80db65973fda918844498c6fd469154941a01bb734d950e6b590129eb34626b0e3b2f6079ab3c41d6ce99f330d782e76499e23e6fdc18535eb0889759789ddd6b3a7af0a74a96a5fb37bd9a3c6c040ab2441f66a4d0ed1f14d1dedfc59af3f68d8fc3c98596a859033d7bd3c167e4313fb2d12dfbcc7067cd2308f02e73bbed98e412059b129f5a73fc6f8785c1708654789d09d28b46c747021d65f592833b9a7768bf3e2df0a397128f9f090b3011f5b5eedf548c04acca020192319d4c3f77d95bfd5f82ef1b2f96b37471c2fa0dc4a5a7c1cfa211e378e223b495d0f9cab91d85a2614bd1d6614dee8a37d496ab68538f788d73d28c9cc3cb1eed4a5b76b0f335c9fca8e68f37ea8d85783e7a935248f05bea224f1522797347a3ce77445a3434d5dde8e119f4fda400cbb37d91e6fd6bdbb6cbd441afaa21c1149b5fd04fedc83bcd6caf7b9421462761a29187c126ec80c68bf04de83339e9ab521fa28750d5bd8add669ba83d2fdec9a1e0cd0823f263e7fa25a3ae301731c4aa98bdea0d95bd4eae0e0630b73f315007b71ef4ef344d7ad62ff171abaaef55dfc82abf1d53f136cb859108cfab933036d3372c1e5b90d022737efe30c27f2e1c833fa655ee2ad5fa0cbfcf895e60dab807e3fcd3861b0467e3fb6f007658af778aa47a66a5b18ef77897989756c0c99461874aea86bce804951f47f86cc8e33da5f59f5565806f18066aff4ceeeccadb52e530849838132516863e7c44c6138f4f428cefd85952202805b7df9cff2fc7a9d502ffa304763b8ff578efc5ab580dc98b4b99fe5f090ec1c58983e340075253120916f10e6e496142b1f4d6627434094f714a40fcf3f8524de0ad21584b982bc3d74b3982e3c0647d59b471906934a7820f8e65a48214948b4b3f818b5af0b451b610cfac76ca0c2d301aa7eb92000a894793a057eb8020883764718075e0e2761cb025eb0b91f5387eb73c44c800038c182604cc096949dd392206804592ece1bf5ce6f195d83aeff758142cb7a8d19bccc43b4366ab5834638b1db7c2ba783db2722bc811b1ca4c61d0b14deb70fc48d8ab896aa50a18581f37c38dd83254d6510694daa145052c84b78a53020b2117168deaf9663b72d18e6adc5306662f1005a338e0a04020598bdf848894e1687f356fad082532d63e4fda3f5c796c836a1f2441b498767a52cae94b92207349714b4a7d3693e8b6f0bf7fab665db7ddb0fdab158c4141a7781c8a4c672f57838789925b812de7aee0f053ca88232ad582e98af92bac36f3943110cf07f96c288d3df98d8c515a29777ecc10c7aa2b976b2490df83365a5ddbf1994991e9ce856958325024411c9f7f78d02b50bfd9e73038af47bb1480d10c2729cea20cf4df1979f3535f3ba04f0b63c352d62230ee4e14c7032078026815295d3f8014b0bd366f2bbf5f91101fb2388f7217b072e05b41f270739d5bef78bb8a304265a9f32b153feb9dbf16be6046a15c917445ee7eb310b12b2871e156e0fc5d0c9c26b6e571caf9618b819e42c33a82b583fbb44c150ff333737b1439479f12b51352983688060b7c29cc260962432318a955ef92b2e811b2e89f6e75f20e1708b2022414f8aa5995ea3a15b13c25c6d4fe327aa2654b2798670ea8752c07fb5a47c6592fc2bf5a9a52487afcf7a2051d3bd53ff175527a0015553335aca6c03c55c177d9f94c88dbcfd3efee47bee84d36bb7c282354c7c0f84716084b9e754c3ebee02f4d027df4b08131311d05504f5c426d961a24e72e3b8bc0d717f6c3dd9a3991bfa53f4f2c448a18701cef19701eef285d252a85edbdb9b502b196ea77c5a95567de216097a34ceae75aef3c1360a84a8244381cdf0edfa73b0fc76958cbc2394c54c11417bf479dd86577dd4a8cf4bb52848bb9997263cca7bc9dd599ccee7d0aec1adfad55aae38cd38c5eb40dec8ae2518f48851129d3d7e38bd9d767b43158c59e3bdceec2fb327857ca6780227ff3937d393272989a76592999db2ac03af9261a0ae45b6627872a0e528b6ce6921c0e974678d446887821ae38a8798bcba3706348f6f0ab780b6c77f50f2dfb0ffdd2874a30b7a3ea6cfe38b75105bb34a7fbf39b482e9fb1eeeb700bd1a9316f6acdcd3ebaf6349460924e130856920974aa020d9c6295f11a6b1ed8dedfade8653233aebe4e2c0399aeef49169b6da154cc2471694a613ef60bf7cfbfd636dd1da0b5bb05b259715543710af6126a5242a6f7d4d7e324887a08578eaea5c8938cab7c5e3e4317122e7d08aade36614c01a1f5d36a54ba51abb90a433add9247384874e7d2e001d86c6600b85b2343b0f690e310b825873f91141921d9ca266afe4c63a244023150a57accce96947b3bcd3ac39125d4ee472e75bc831becc3c7c651aba627976598f72bb75834ab83ec878012c8355abe7ad876a2ef96c630fad84c96f710c1ae2f59613d3c52d38f054667c0d2a9259ba576ca828c9fd632178973386afb6e845c8a2e1e3194de0af1a16a4b04349c9d154a4ca39a3f8d8c4f138249e41d77179a99da09f9e4a73b64041ac16073472fdfa89d1ce7c15946595f0db3f9972484f290a9a91fdffbc3c114eeea4106dd91b89bb5f5f99d01323385ed83d1b5693733a5140b06d832977036e2d03721c7002425845bdff156c3f519d064e1df2873fe72a8375a50c6d5bf290249fa7a4dea6b840f0a6fd5a8536ab3238eea474bf74ced4771158a8c7ba1f32401cb8481bb0fe5d259a16abffea8f8ff1d15b0542122741c32088b7a705e96178daf28379ee9bc3df3ebf3e624962493f6750cf6e82009636c24f15cfdaa8620dbd945875664ce01688cbf318c2500003e9246495a6cbe91a0e0a41399b4d9d6c26509ace35442075ccf188d29dae494da195ae388e3a6c8bb29a1dba574a1130845468714d97f91b879ee28d2768960740bd49d43c94b0c002e93a52e3d07e0a447b26193ebffe2a10ebe0cd518d0221a2b118b3f6c170b0f185780880d7a2f324ae4e207539dbeb167b6b840281de93191ddc5d9afd9ea50838d8c3c64671047c4fad289d5b887889ab42e50731d16cdc1e630742bb263bffa6a56cd445766b26d1f7640f296a4bbac8404307cca0176f0a51f0d8983a0a7560f38095ae39b4f588d0de5ab01f419454c424064854ca8845cd36464300e277180bc74933ff8b15e0d4d47344e9dac182d686a1b4390bbb68b10ad57394f83cd480c4c50510e3c9038f56bd4d061e82b60681ee5fcf9a1c722a4e39c7c01d7ace184b9f2c38c8bfd5bd99682ffe893650c6c0f83178d0064a1bc2ee449e3ef2e71490b473eb80ec1efb95d5c3ccbf35fc755932528351aa6c50b38c9ae5eb58e8fa009b47be9279b5c3fd1bad68b95960841197d52ae062e0c4c865701f26f59ffb419571fc3c056cc86dc3607e4caf2406fd5154c064118a3482dca517d7dc6f6aca2acbeca999a3e5ad0df9cde74b1e9e728791ac3180d9fbe230c5ce73ebc309d457532e1d519a20b491f3c8282cfe2ca6765117c4c92de8c08ff9fd11abd2e5e1b186dcec0372c8ef3d1542a7cfc6a5344b15a56d13b06fbbcf2a8f9d416c98ddfe04d96a5d9f90d8c8e9e575d51b772302c41b3b16b9bc2ee9f198863f8f5ba4cd7603135dbc961cebfb34b473ed4a367666adf2b07e44ab1fcb10d4217441fbabea1eb428bc7045f6f1ea9e8aff9db94971de26ff960e4226aa964e21b8804d5536cdb05ba46acf8689183624aa0ef0465c2b963d1ee809379cbfd6a98831af3dd9d6629e3de56a084277f132b67c17717f385cda1566f9dd9a1daa4def780d35d5827dc0f6ac2639ab78f7f08a480cf18bef0e69e34ffe825884ea2a015fa5c5ad34d1f623f0822e9a15450cc367dd8078bd75b71002969a06734dbc47bf613a4c744006e8aa37e01eae1070041b5a119fc7e0d822e04660b21a16af8c077c59ec97d98f75350bcdbeaa548c3006da4ef08918ab26f16e1f8bb5bb88638a899514e0009573196ffbf510dd0981f02c61c569aafba7f025602aaaf5cbe2c517cef47a219feb00eb44119ba8b2df1109b655f1eeba3c4e84b80acbb2c7b5df040c303f311758e22928fa2ade189f1eb232d4940ac1361d17645ddee7fd893a1095d866e0d461201c08d3562b32ec556b2bbc2fb01db08c671fd1ff9a64d33d082889a0ad53af4d7ac0f02e01fc703a1baa7145e2e9123f903c5a185fe094233cf3bf18521960b11932b412bde418e556843bab311212ae173b6f0c1e11e2192d86b89ebe484df2f7c56215151f96afee4eef2eb1f225af644dc578821727cb4f28e19046c0a0d1be5c1bfa490fccb8ae8478d2bc424df6d34d6dc9ed8387d41702720df1c382c0d44bc3fd423cd4be54281e88a6da4192870c43c1f2eb7fa711fa4442a66543ac4f81e90483fc3b1bc5351c11557552732ebb7ef0f4022ac4d17ad720b3975029daf394684242fe4a03e94421608fecd0e51a0ecaa5d6e82e08485352503305ac470adc8bc90cae9820008abd270a8368871721f487a6c518603b7a5adf1d1111b2fb34196d35286003d19dd652f979e137d79ac4932d541ab2a0fc05855515bf0a132f6d5b1a3d2a21bdba1e6732c65f9d5304853839942e90184c5993db5c4a4a22a86cd323a89becb26a4a6de39b09ee77b798957db5a105c1212514d3470fe412d64979222d99c49e6114b1b7bbcf2a2531f5cded156292d56923e7e673d475040bdfc54c4b6b95bbeff75c686dc8f57d2cb7d496686e896635a38627e83c8de3abc2787f0b4e801ffbfbcf33628e816baed975bf2c60987ea3c6babc4c723c0f9c8cb91514deee9e6947246f573e4c7d773901e0ef79f91796abd65e0d5e732a3dff06a842fb4d2c9d8b8a7629190936c3fcf779fcf36f1451d55ca24194ce40fb5472cfb10cd51c69dd9a17dbb6ea4e1ed34f668e20ddb50a1142bfe01bba81df274a3855aaac96101f9ca0ddff95549483c6ff9abf6960f94b206c1caca4d548acd3f97588806bbf432f73147ea954bbd07f457292bca089de8040a0e69277e07e69a1cc9af124c1ec0318372cb8045ec7a52953c346eb8728acb1e2117f7c85401f322834281cfb982f24af2431b447f5f27ee579185f6e7c6e34579bb27d13f53b894f9fd9933ed8d1318bb06ccda1221af2236f9ef573e7ad68d6309f988a028ff863c275386c425812a24e18a80b07df91b9a316228a92e2da39a3e9f48213cadf61dc25647a16a2141a996a69d755cc458c321aba0c748f666112400d473d4c11617e70765e82832b0869b98528a33ef8ace312d96f3f4d25be8f2c1c66d07dbebfede4169174be0153cbfd9568eaac4f9ba065095786a87e5004f07fc71c085e2f5740698113dcef8f07738ebfed0dd736530d3931dccadcb8b772f68be37aac959a3ce9dff6180941f5ce55665c13324a037185720764f3737eb0030294b91ce519c05f3467e76f8164cb9dbd287e034b6b012f93816d221ad8f9cd68a03c2e3a8ca14bd40d79bdb1842e52e7cd094c7f329efe79e02981def22f01d1117b0650b0e04a2be79ff942c6bc751309fe40f7b7fbade6585f772c617e3c890c2ec07f980b16027a68b46c926bc8f205613c4f1acd35dc9158a4a6b136f745cda0901ea9624cfec022b8f034c55ce20a3b1a3badaefdd5e2602731221807a2ef05c68dfca3c88caeaeced8f973ea59828fc9b50b997d27caab83936ffac0de02e87b25b9e1133f12a90341c7df3917d21fa7ad18eb89f7b300c75f10fd712e6fb217bf36d3be4d8cab614ea644c026ec29e7f087a1e93e19bfd371fc035c519289a1004ba914541b5ff63d786680f7da09139a6397226c705bc6279239afba6c7f53a6416556abe8680eefddefe3795158054039e9c1095d23da86022bc49b07d2abfd97a94574d6626026768b21148068095d7669e8031e242a81582f8597aaf31325312bc2b8c975020743d0e22c9c47846e3c42d65d4bc26580d1ce392f629568d11d74456aa8609ddb3af0d9f72be147300a636c97b0aff027282e449361fb3c3d5f8f26978d09eaddcfd37327684eedda2970b8bc13608a547a473fefa09a2b242cfe106b75ce3c64e6c34cf1c6ca183c19e4fb92e146f50496a4764c443b8e7b2365b7a912454b50b02015d7244a0f66c5bbaa9a50377524a0b11e4a349f3720c2f4ad2e64a749d66aa9ba0eda7194e4bcd391ebc9977855fe2c9cdf41bc630180861a18f308727dcbd0d39b976d37a1dfdf904f77a6a40ed06dcd94738374389027d9018b1943c5b713325dc8b5de53e34db7cf819a55ea2fa52b11b05b2f06f31084fc2a47a1f72d6098df6e66181ceb8d40135120f055587a63e793dc731c3439b83d9ad34d6c234c11b5e368983e17679ed558a5ea7a3ad33d5b9ebe300778ef8b8f578f6e30d7363c82cd9f03e1d780087c4c182d72e0319acec822f2de2a32f24733f57413f6d2e693c7de3ded77e48fed03176d03e7629c68662b9410a68580f98cd4c0ade2e5d113f8d72379e78ac6038525b81ef549b934f85e4714425e6990805ea4f011f7e62088d86b11de93ae990135dfda335ba4d6899d2cecc2c7cd8497f5226b3c59af0264c537de2ee237fdaa594788747be37d35c4755475ddb9647ceb63b2066cd4ffd3500d1c8e023e5a04220b3760b46439330f0f0f0f0f0f0f0f6f4337426a6b9f908494a454aa976679010b644a29c99492d81dbc0b9c99f87466e2d31546ea6e34e301030b400bd30a89305b754ea153cc4f17311a1a68000d2d6854c0c3c3c3c38bbc0c801a6220c214d28388d6a39e7fa625c4388441e5edce5e2284ea63058d011b39ba7880214c3a9430d9298b440b63214c21c78b914df249fe104218b465c813f91f15620cc21871e5d6434b9e902208e3440b19a91e545479a2102310264f59952647c8881a157284188030a5e777f438191b6b016084187f30968e74f988efb9a75363edc3c647c12d4b31fc6076b7083243e465059386161e1e5588d1077357fef6f47137b6f3c1246eb35ebf9237ddefa26b68c06fd898c0923d186de28afa0e1d3d18e5524823aa3a7f3a711ecc5f174b955267a972120f8697a4b4aca5548086062440e3430b1ced12c891000b2851438c3b986ad27c74ad38f91b362002e50a31ec60be0c7df524667bb5af83792dced6c4fa09da6e3a986e5baf64752ef5e139183ce54ccb19a24a29530e26a13e57b8a89e9519d6588b83f14a456cb56ec2292538184ef6d8c9d0918488a637e8337975ebd52f23c70d068ba6bba5847e25f3b4c1782a629b087a7ad5c26c3089f59c82129d3c8851d7b09af89d69d3fbfb5d0dc6d1f62762470e252d4d83316757528ea8f360123418f542e3924e6a44fcc81990e79e7592d8f0dd88194c9fafebc329b7951896c134e23e23f4d998fa6430bd560e39a29ab0a4d9180cf2246987284292490cc69ff9d4ad94264cbe6aac1962848131b7d9ae20536c3430587a3cfe09791771fc4272a23de2880929cfc70bac96e87069d927e98241e9d349674cdc0575e242a272ac3d2f919152bd05decf52e447e9f4c1d58229e72454dae4f24ad5c982c94212972fe88d05632491b3d1174a4551b942fa4b5e9f1a1d4f3c620593aafcdb1dea296787ab7067cb13dbd46a6255a86052e6de267ddd4444740c31a660c48e14d192429784670d0f69267f4761d7125365924b5ff250307b2425df15c2ab3e9e438c2798cebc4dc6e52427182d8f7c87f2fc155d9b9078710fa1cc4c2618c4b6044942924b583ca565c7d2217fca9460b6317defb0d57f214930f68dca496adb87f00e09c6f8ddf3aaba54b61ec1d319b135ce74881ac1b8af27c1be6e2c9f72885104e34a34a14f45869e1e11c1f41971d72dd4ef538660505921e5e715e517662198aeb346eaa80ad2471b0483e855f79c4a6dafac4030999950b9206db573f20786f7efec4e7af744f6d00d317c9068a6965ddd0373b6c41c939397fb82789007af3e53a24f9c24edc024277c56ba206f92b6bbd8a26f241d982aabd675f47091d29203c385e7eb087bed220eec0992b642527cd9788353fc38ba446f820ef2183630ba6e8b6e0fdb298aceb521460d887f49f4d7280f950662d0c02ce6e13cae598ae4a1b121c60c8c5e3aa5a81246eeb8be8618323069cefde76f856889c5ba9f53d8cfb8d2aec1c254276ef73aebe597e91546fdb4edca31b57923572073ca9369bf4a2b0ce7a3d4bdc8c6fdafac30dba7baec905ff2bd5d85c1e444e5e6fcc83cb9c69aab1960a8a2ce761792852429684f2accf196653997fa4d1f15261d523855d7317e3a790a5418cd4ea2744c5863ad057e820fbe1b3672743185b13b6591f11c23966534b4a0d1821c5ea0c07451011a5ab4e0867f71011a5ad0f02fb8680ed0d082c69db5c02340430b1a76c39d8bf3850d2df3a251f05186c3bd68418e2c85414f7a0f8b2426297b5218d56cd4a8f4f1f6b98fc26c71d2cf88c5eed35714c6d1e965fdc36fe49ba130cfbc8f288f7b8b2c0185617f3b4be7fe2cefdf270c2e4946d0155a3ea25d066078c2a04694e5ed59d7fabf138614f22c56a8958afbd4d80d745181b3829c30870d911e72e6dfb29cb809e39c271d99a142de4713c60a7af1223444ae8533611049c5fbe69e4bae0f26cc79c5de7b74ec10a2a55cc214b45c4d9f92aa22644b98d46595136182ead866f2004625d491cfcfbb1682caa2008312e6a0ad2797ee5b93e1f8c8f3008c49186553c4055d59e46449560086244c1529ec8e55d808ebdcb8617608302261aaca9ef8b521b2eef187106040c21ce36e73278b47109700c6234c6d415f0e42bba9578405301c61d8b7aa2ecfb7b0145463edc373d8e8e24e05301a81d0191e3e6444790306238c713f62d1e43efdeb35d63e10522f602cc2544ae26e9b84a4425a6aacdd5084a954764cf86c3fe67101231126b566592e665c46b4cb4c000311066d912da851fe41a4d3210c7f61db43caa5b9681bc29ce467e498a51121a51026e5392e9f449810061d134a790ae141982508f5385721447a2c087329ebef2f5526e60f8439ce6ea464656af2640161b69446be8d8a21e4db3f987d62593c6bedec52fac164f7df69fb631f4c29ee6e65adff50b3f1c16049eb6666df8331458ed029b2249f5735d672b4e0468eb5ced10bf0e223c905400c30f460bcb4f1faa542ce53aac6da471d0d0d34600b30f2600a6982a4b82e5539b45c808107f3e81e93b318dec1a4646858588a4e96658db5b230ec608e26579b3ee26bfe5263ed830d07a30047af200130ea60103bc23f8556eef5c3737c617e18061dcca924a54fd2f75ba489e760d64939b722bf65cfa68f3b030c399844d8a9a0ff63df851e0783a58689a7541bfe4170308e507955fa6358f5fd06931033ea6bb47583f1d37376b8d5aff8691b0c1adace3e87f8b922369882fa4cf652daf4e49035183f2d98fb051d6f92d460887339fc7327b17f8d8b56810d143806baa8000d2d380dc6d02222d553f5ee99ae00030da60cfbf57af7703eca3318b7be26ee8752224c806106f359678b37eea9457b30ca60f2cad24946844f8da700830c067517ed83b4fe1ba53406e35ad871cbd7e3b29be50186188c5a5b37bbb67d9d3d6130a7883fda42ae99f6d100030ca6b3b00b914275ea60d6ad01c6174c9d5444af9b8100c30b86f43b97bffd9e7459140230ba60ead4157ac7cc264b8ad987a11c6070c16cdd162752f27a1bf9ecc3181030b6609049317a1e52d809920f3336c0d08229291d26ce8fc9979033fb30b5d2038c2c98f7e2f3558a8afee75830a8591ecb3d59bd3aba82f9564b7b5cefaaf3b582e9b7a3e413d23e29bd55c1f4c9b28856bb5890142a9854e764a53fbedbea3b05534d2c7d77aae2e7775230a9a06137d2ac24465214cc7d1a298d2c75d9520e0a062d93b297d095ad84fb0473cdbfa5abb658eed209c6d5b4504ae57cf6779a601a6d61ff45878ffa2513cc6992b07fff8ba054b40453ec0bd3d6ad3fd7394a30789add480bffd22d4a8239e8a860fb5fc94bad483089bb9f117942749b0fc6114c49d99a488bb011cc11840a2a87d1cfdeba08e6ad6c6a3f4b53438f4430682f11b211f3b22f3f028c21984bece28afc8a259df6f0281f8607430826ed4eb1743e136f97140473bea978d6ecd68d05046377f5886b7a7779f903c3488ab964a13a9f181d0e183e30d75d075d6e32ebb33d30a8b9a43d7479903d2e0fcc155ad41d988358499ae02af945d68131e4c73ebb49c2c4e57360743b717eee57a16aa3a1c58729da62cb60e0c03c16225cccc98c8ad40dcc1f44880525f46f5ad60626fd172d47dc9aeceed6c0702a3e8a4eb942be80410393b4483fc2d7e4251d9d81712b23a7bbd58fd41d18323005a97dff932a8ec9321646d3f2380f23a2bb25b0305df06afbbbecc9f4fb0ac39f4732f3d167b1a72b4c62a284dc5e893551d28286161690000d6d81005a6148fadada644c92159b5ab10b08801546133af5abd492d72cf00f1b393ef05620805598c2da6ee7d3a810376320005518e4e7be3ecd5f68130502488529ed2911adb40987aba09d8b0f1514c31b282801a0c294ee84ae4bcb97eb2fd2028f403985c9c427ff298b98c26057396e9696ecd1430194c2204566e6ff7bc8be202408801426f7bc6769a476d2e6e8628b1a450b0f8f519852f8879265f7a62ca6111e672887243dfc2e5f7c7461833b8ad0610643d075973fa67a8f9a40e828c32a2a3ce928a24e7e51e82003ee5f5e9d25954612133ac65072bb2f31cdd0b30b5c4287188ebb9611cf7f346ec1f9280b833945131efaf24608dae90083214938713af79c599a5f3086e917ada2aae7c4e4dbb9282fe8f082e15bc4bd54e42e186f74ce695ebac73fc905d3e4169973514af6f45174d0b105939294f522df4d9cc65a3098ce2945c991d4a0230ba634f12a4b92e4ce6663c114f428a56c47f44b7e35d6cc6868a0010ea0a10109d0f0f09041c7158c3a493c699153b357a264830225d9e8a2eca4a500083e0cd0610573a4ac9491a89d26710f0f5e0a80e003004ee8a8824175ca972e6fc99354d5584bbbe139fc861766aa800e2a18640979f398e421775330a470175b17b4e335cd8f0e29184777ac185636f3f9d482060768584002343aa260f41c6f25c5fd8ad599066868416303342c20011a1d502874864861fccc3f5d634d058e010f0f15f80db41b39bcc043c7138cdf5f51527f36d52d7e31812e18e0e1e1e18163071d4e309c502297969610c4af8e269844926a0f777e6a7eac4da18309e6642a590ea1b53721a9c6dadbf8e0251872a86441f95a12d26a724a30ce4fda14f14f27d54c82797420c1f82bea25071d9f4ec5fad071044350cf11092a4a90df8d604ed1a5478f96fbe6a4a308a6ce26259d8aa076f5c2367410c1e861c4e517216774ea5e740cc11442cea3152d76ca2d4bd02104934a95e6d564769c488d0e1d4130c7121533b2e59ce3b36573e80082b12ac6071ff57ac2439258213a7e608a9d8492d9fe8a7caad436b8f0f020f6611b880e1f18d447f47fc7fa5356730f0ce2a942a57c499bafc63c3047c822c67284a9b2c80ecc29fbe46025569e832e9fd0a103b3e7fc1232faa774e7e4c01cf793f3466a383084dcc93a25f5ff0df50d4ca9ca7476dc49133a6c60b29bd1f7afb14b538aa1a306660f22f9626db8458e7ea18306e6206b92a3ed857ee5ac858e1918420a7bd723c553493a6460d0f5c1f452ca1efb7d2c0cefb13be446fc8bc8c2c214b73d6ae7707e2987bcc27841ee5225a929617b579872aa3d15272e88e7a915e6d6cf9654e58ffb5cb3c21037437755ffa2e4945598ca3ebf8f885615a6cd946839e59c0f6aa258c82215a6cbbcb99c13ef0a59a0c274ebf6e154485b3e39a730c7ca4a4a23ec1b3958604c61f0109552ca1f254afea5308ff04ff18d70fe1eaab19611c88214a6109479ce3e7d7a71bf1b4116a330e58e7b1a4134925b4a8d355118c54f951eb57f2af13d01b2c1c586c270e2262d9bb4acd0528db58f0485215e4acac38ea8c6da65208b4f18546d3dcd495acff2d558bb40169e3065ae97764f1225bcacb1c614c8a21346fd9113ec52a6fd7d1865c1095359fc4fe2d69ddb6235d69c8bd37622c86213a65431d789fb6ec9ae1aab09e3ed44f5b62dd3fba61a6ba90b1ba78b2f361326bf8a1f275d5f5ca45a70234762c26041a50b2b571344446aacb5e0460eb2812c2e61fa9c3e2e2ad5d60879324b98455987b058c23ec4a2812c2a6108b2697fa6b273ccd696035950c22074ec7394093126ea933086850bd1ba6a24ae92306beaa591266143422261bcb738a2539daac41224cca2428c70df0f6a52e711a6ab18177cf257bec91106d331e4771aedf183dd0893f214e18410c16cd28c30e78f9dae5f21f5b96511e65329fb9cc9274f9e2ac238ee3da3edb7f2fc441862a7a0ec65e554658908c366cdac8dc9da499243982cce9ccd07194bdd19c2b0ef49cbe6c2e4d9ad1006d51ac22d564ce6a93c3c70b8172dc8714701107c0400085910c214a367e4d6764b8a21b40fbb2c0661bc783d31fa395996bc200c49de09f123b1cc4e0d8461ce65948e8a1ff40f0863a898dc172d79c59559fcc1fc1366accc52fe3c310b3f185fd2986f044bd9c9f7c1105b2f2595a4d3635e0f0f3164c107b3af873455d11e4c41c8d1f1e446bf4bab078369dddffd8fe855963c184eb52b5be8feed13c18361bbf3fa95f60ee6ca932d9cecb0371766610753aa121242aace33f70c1059d4c1d439e88837fbe5a9743a1826c6554ab24d5cead11c8c6f66a3abd255e4242407d39aa5aca7a7d42774e2605c0f7796173a7030ae99d9870bf274c4ce1b4c25cbb446abf55da5dd602c714b4145a9ba384b1b0c1bdb299dc50a1bcced3b22ffd55e94145d83b14ee48aa74feab35435183f452a593339c8b7d360cc095ff91192a48b241a4cf9447eca10e6198c6ddaaf636c9abf04cd608aee22eb352c9a50aa2a64510693ba1b212f7e4f0653ccb17062d26ca6c8c76036212df34b2589c17429a87e1ded15742585c190d3d6efa4ead494243098b33e77309bcf174cd9c4a28a27715e757bc190824a3255933f7ba574c1ec7f9def42902729cb5c30968e6f2642b21ecf780b86a81f2584b0ea13e3d582694dad72fcceaa77370b463951a5f379b29b5ab1601cd5599613a24d4af30aa6b0fd59478d6905934cf68f3b4a8ee79454c1b835794d7627557d122a98ceab3f2b9a369192640aa63d75bd5f4ac63d77523056866817f92267b68bc2b1c32585d1eba0603cad94ee53e8cc0bb227183e4e9e30fa932cf79813b4b2cf394284ad09c66d131e572a74d29d09269d3e2c89c6e5d32fc1b027df4dbd64cd1229c12446477f3ea1524c4b12cca9a76a5fb3c2642498365436cbda826b5716904216473075e990f354e794e36a239846082d22d4cbcd7f8a60d056ada0e324f5e7b03040430b1a75011a1690000d2ebc40c1166a4430afa7d8b6cfebaa1492c30607ee3e90c5108c3732d64dc7ee3295f5f01082498e65af74a3ab1e4e48c82208c68cd1d9a16a9ea51d0f0f0058210b2018eed273ec4bf331e12106b2f881219ad6aca4e2f4f42a3e30778970abafb6d037d758c3f1e1c517391cc771163d3077deceb58dce4ab68d1c669b050f4ce13f7f6d9b8b0ed9da813925fd6b5e39393e6f4ac84207a6246e23f3126543c63930e851973c6f527d4bd60b59e0c064f5a542b05c69a7a31b18b4424f87da883a216f210b1b98438e962bfa05a5b4493c90450dccdf9d45c4cef7d1b28d42163430880ba7d353d6f0ad9c8442163330c44b5de92da84f56a2608b1b5e98690bb2908131c3b5d4d743462ad5be102316a620d1935cb45426b65b2ec480854925c7d3f5ab6b4ac5f415860b2a26bab64711f95d61cacd4a4a08f1126df256182396f8925e49cd66b816831506959c4e091d4ebfa4508d3557c1163752a22ebe78d2858d2db640018e5e0189b10ab3255dd3adf5d5afcb3eec0f315461ba3c2b39ba92f2a7570b1a34b4a0a1050d2d68380a9a021e1e681f568718a930867c864ef19239f10dff40157cd8c8f171e3867f78d12858bb618018a8307f2775dac6235e7ec8294ca2d627a414e6bd448708314c618813d383e4b7fc214f928518a530a88dacc84ff13c7c0e298ceb4195cf8fdd859895e9284cfea984509d5fc4a5105198a49afe05a11e4e3ccf408c50985c4b948c999d94da9a82c21c44d0cad974fc42d0ca270cda542cff7896212fa29e30c514d33457b7c61a0bbee80f1c5be017313a71c8a6ad478f87306d08313861cc104965dc566aacbd9f0b000e626cc23cbaaccf36de1aeb802e2ae0e161ae88a10963eca7c8eecec494adc69a2f51c19503c4c88429eb7b4ae1930af3c13a25c4c084b13be7e87ac1930c317b78e4c0b105171e1e1f312e61d4f6bb0a8babae33046258c2786f229ef77fc66a8f5109b39a9a4e5ac3ccbc932861d0e72762446848b10b8e2d100bdc930d0a4cc210627f98999af02177bab0b1c547310ec4908461562b89bc7d593ad901312261300db38ed725499bb68504562161160f13df7212de1344ec1e508256805a0e1c5b70413a10e311a6bc2345655bc8b11c2a00f010c311c61f75df31ae5de72a1f311a6150dfeb104ae9deab1703311861fe523e267f2b4a387b11a6ee7c29fdc65c6dcd0f1c5b281b6228c2a49f133f8450d7d93e0163b06b542449d1830c311823a41c429a2d7d1f2936920d1961309d460e22d7c608e1078e2dccc820030ce6141d11f4b94ef81a71f105938c116df11452e507820c2f18fbeed674f67f4f3b5d156474c138f21e724bbbc3f7cc05639cf7288b2d5241c6164c414372f658bb5acb6ac1706739548a3769cb436464c1b43d49697dcfb7a17a1958308f34ede929ea46907105e39c1c5da645a78ecd56307c96be28afff6cc184b6c8d1393290041955c827b5d5cdfc766190410563ffc80e1d65259ca59ce046a3c06f988c2998d74cf252302421dac3bccf838a7714cc637fb1f6c2733e8f0d20030a86744a6a990433e1697f8239ccc5eb15a1ca3b742798723aa19d3dcb92ce5213cc7d715c46a911b1549860b48ab5adeb4b1eb46709c6ff5db7121f3c5ebc4a30e7d332d5ac78398ff20b2f92606ecf2d39c6073569511948309e8e246549e49bbf1a20e308a68b37799b2ef2846f04e36f4bfe2c7f8b6711ccffb13e92ea49189d08269d3121f2c63f04839c5d8a13a24230574e9ffbd485ad6406c1a0276a9927395a8940306d9747f8c85eeafc812927a1b4cec49095d8fbc06413a4a48b1727e1ef81219dcd5dbe9ede34f1c0785abd25f72ca47c7660d8fdfe55af9589b60e0c96a735442cadbf951c18e4ab465c9771604a29172e37b981a9cf45b72d5be77236305a4842a5ebce6b60aabbb3b3f78ff697cba081e9f63c47ca5f19e272193330859a9d9e58c182da65c8c06842627c7e512c0a69a74aecd30916862065724e69a7571873d5b63582d29bbf2b8cabd7a9b5a6e4b8a91506a5ea2fc590eb131756989359a7ca4dd6d3d9559824971e95f2f9a4e0aac294525a8b7ab721ac4d8551542f5c695d2935418539dae81021a354c7083a85c9545a5c9e780c292253985b2624a16c4f98cea15298f2670f2aa69228f9218571ad757f3b72eedca3309f49cb232f8bc2581d3af2e321556c4361bed355ca666ebfce939fc87e9e13b3f309c3856cb933e2d7f9c713a620d16f27db9d30f78ccae1479eb4b339611c3f933549ba095376bf2d9de029775213a648e17c6e24ebca9809b3cc5c7a8753553a870973d4eaa4bb737d0973c8a7ce5a2679b4ad2d61ce96ee44c5889c9b75254c7b41b99d122bb25953829cd47d98e92761cafe9096462d4f58256110d671a2e935ad279648182bc951dbda175b59818441ebe8d121afe7cbfe11e638aa6639976fbec511e6942645e5c4c8e26a238c9246a5b1b29326228c305f2e616245a87b087911865827743eed5811e68bebd039f57d3e281106af78ed517911612e4bfd126631b6c73d8439480c15a1d22d4eb88630453c3121d9a38414dc42984c77c87b77a5d7c32584a9e4984ad162e5e4dc0ec2143a65975feb69782b08e3e7efa7916d0361cad0102994a97aef0161d0b19444134a5abdfe07e3cec4cb0e29723ec90f66391d7eef7592eeba0fc60b25d5bc2f760a5a3e187e2e74a5e0374a64750f6611a52d29554e4f52d583c1c7bc52ce97e6c16012827e7d13d5764a3c18fd4556843e1d3f72f20ee61aa5ef2ccd6907e3e98513b93baad696753097ee7ca53da659793a18b4a50a573274b2d8cfc1ac716159576ff1477230d7249b5119119205c5c168a64ca8fcb1a363070e86fbb871153335b6bec1f8c1e3578a923b65d50da65c7a674ae9ae0a4ad20643caf993bd7472b6246c30ad5bb8e59b4ee126640de69a942729495e0de65441271db75fe43f9206530e42a913d16bdb7244835135d3eb3ad8095bf10c8637a1bbbd3da2f58666309bb4d116452b8341a8532989d1cb7e2a2483c1cbd446b8f14aed8fc1bcd75eb27ff296c4c560d24baea5544da91c0a83b92be8d23679bd94c0601ad393e2cdb466eb2f9845ad83c872ab1cd50be62de91ff183e75eba601053ad8b13b96098a0a4e54bb9db82415bdcee24cf23f93a2d18f5ec27dd5e9705d3e44fada15d39873c164c5db2464e5e8d35f915cc296f217dac3d9492158cfa15b154073597ee2a98e6d449b5f8ad242e5430b7685321f2650a06bd9552ca69a1cf220573300f3337d9a260b0f568d95c8382d962786544b9f330da134c41c48f7d2a6d04cb9913ccde25545b5049c653d60443d637cfbf9ebd6f6782c97eb4ab5eec4e3f5982e9edcb7427794ac98812cc27d62992b44f72912418336d6fd5ec73f61009261521a84d2b1dc13c5acc549424a22719c16ca67eafcbdd4254044390977366d224c98c08061d41ac7efcda11a91a8239e6c4ea24a2e71195178221659985e510776196060c2008e6fdcea346628dfd2801c15c39e4fa32747ed07d095d42dfd828aff8c0246fe16ff969db43ac0703e8814196840927c663a97d82ce417630001eb8225a3d5ef54d773430801d68413582ba3ef5531778662e18800ecc152c7f0ab2b4f7d44bc630801c1854687c9e5c153d49968401e0c060276458fefd907be1220ce006a5a553594e8c906766060660039365b913ff3c9e44258930801a18238e4cb83c5e0106400383b6163f378b1eb4245be011c0f5a251d00511c2006660f814b157d953ae08fb00646098d892b3e85d64b13716e652da7c929cbd4ab1030b738510c2bbea5252b3fc6f91f6bae315e6385b11827b52f1f3b7f3b000d0a0c315469dd176399c9599b66ed8c0f131015c0f74b4c2a04ce850b245e67b973a58619e1ba533f12ec9885b598549479f12c24e52d05176a14315a66842c768951f9dac4d854962a90baf734ad829e585a10315e42c3eda6ada276d5c1a10011a5ad0708087470bfc0486868e5318d2861a5f516df9c46f0a73e84fe91e762d8579cf65ec53ae3c499f5ce8208561a4f5a5edbc7aa98238bcd822070e2fb6c8310ab3e9edeb1055e31f3f36d217386ca42f7088c2f09f3b848e3bcac1c51625c8c1c516250885d9b3529061a7ce521a14a65425b98298c849253f61dcb1742aa9cb4a2192c40a1d9e30ae6556d76aa5147fd40953ecee70499b862ccb55a18313a64b6da9fb713d04d111063c3cd00d12746cc22827a731c2df83ce1a0f0fe42cf0227468c2149a963aeced99484c18ae3ae4ab8aa2924aacb1f6710963f5966ecd975029a325cca6e47ad2a66b47e95f09730cd36952ca497815d558434a943aaec4728667cb4551cb4fea63b44e5de77f564e051d93309879b614725ee949649230e812b2fa431821b1bb8c844977c88927c47dd01ff6a00312c611b1b3b7a542627798071d5af8cd9fb7c311c6399d45ed9aaf97bd1d8d30fb8cc821653f31c290e298bc93ba16473bad60e8588421a94b48563271f72b1d8a30c7b3fc20b612ce4247228c1d45f4e6a868a3bbef408471648a3839d96bd9e24a42c7210c3f5252929b9763fa39011a5a78785c87210c9ee22eff25154eda1d8530bf5e24ed22272f84141a5a94a183100629a3a346ec5bcad5a20047afc0c30305387a056410c69c18395cfecaa7a60bc22841b74cfef4d1d080046804c2ace2b936449dd5870410a6ce1dd15ab1c6d5f407d3c8fe68932bc70fe61479da4542fa60ec0fdda253ed7c307827a184b49c4e5edb7b30c90cdd2e916b7e62ebc174f9913b87388d3cca3c184fdcc9951362c2e50c0fe6dc503a6cab750753a40bea2145b285f8d9c1ec21ea46f588141d3b753005a9262aa2891d7430d8c955cea542e660d4d3d972b59a6e179283219e69b7bf98f99cd7389827ce5d7b4a952d7fdc0107a3f587d0e9fbeb7883d15484f82f67ca725248e87083a9b3b9c90921049316521d6d306b4891756a724e1c42071b8c23f4b9a4fecdfd0ad0b10673be7b48296adea7c4c343081d6a30da450e56b9fbc34b5a63cd16e0e19106537ebdcf16561ae72b1acc957209f510cf3f6ed6582b868b2f7038063c024320c0118c1dce577eb535ac7335d60a4d312010c008e6740bd1907d93f6322305018a70acdf9b134135d66a060420827962c65c14496241da359653172671f1858d1a19f0f050f3d3c7120438a4d1129773dcf25e40002130d97ce7b2778a1408100453c4c9aaa7957b963c35d63e706c0104536ddaa6c80b277bb25c70f1c59fa96941801f3cfa6dd573f09c6404475a00f5cb81003e58b4859121ba3dc90e6d81a38b2d6e786a77400e82003d30083d96a654fdae530a1608c003e3a57e1aa154ce65fadf81c94d52c8d949d781396c7c85b86f93accd81d192d01b42c6a4981207c648f941282182b211961b18dd2dc6842023cdc93420800dcc791d22972c754ab849011e1e384a170850037396c7fbe42b42bf9b6860b0da89faa193e9f119025120c00c8cd9a7eb525b3dbe3402c8c09456d2c5504ad5079dcd8885416b4cb58734a977e219b028686f31939fa4bbaf4862c7965ac4b4f60a2965862b4c25f94cac3a74098b7e71c38b3b2d683c400b0f8f1b284001eb0f66b4c2f82571acebc4f6c7ae3061062bcc15752429d5a37b3f5aab30e5709e52b2bce7742f0933546130ad8ff73948b7a4c244c28c5498f75dc38490ab919e438419a830887deed02927a475afc6da47b261a3041f38ba066f91805232cc3885299b8821c26e5e3efd1a6be8c3b9485d740db4a1811c5b24bfa18587070540f0118055cc3085b94d564e720a95752a2508334a61906b5a5a1f7e56749881308314062df1bf54e5745d4af72fb8680e8cc2e0b1bb4327468a284cf1f65772b04fa1e357426150e2f4e99fb662300314a63065a1174f277ebe19f88451c6434fcd44519d843c61566f730d99e3cee884a93c5aa4582a48eaf2ac31274c17c73fd207314956ca26cc9dc27c5d8eb6260c3f6e41e57abd9f0433615a7f397539ed56ce1f264ca523a83c9d439f50e94b9854c6b8664d48726fb18429a730e51bebae61d14a183e68d16e71d348caabb1f6c10517fdb11f357278e18905332861b034361e33cf547d28d38c4918c485e420fcd4b6fe481286b5fa8c74fa481845a724f14cc84bd69119903049ed097f2ab47a9a6bc6238c59fa51aebb43f423331c611e376634228dab8f90bd749fb6c61ad96206238e9e949794d1293fc48b22331661d2f0d1c82ade9e29a24b6a62673b2dcab22bcc48844124c49b0da12d9de820c224fa41c49ed8ea0ef321cc21c4eab54a13dc3f8630c4cbfec82ba33aa46c214c6ace62d5fb87ff132184494e777bc8f191a3c8660cc210d4098f587922fea28d98210853e8f5f8c17357ce1c91dbc38c4098b48ce714237eefc68285198030e77fd3d5bc325d769236ccf883e95a457c7ffc770b397e30a62761f1473c7f64990d33fa60d6dd970f337a3e98c7a45c9e442d0d33f66010aea53c6bdbde776f01175e78d1650333f4606e13af1fff5973d619c18c3c9c2b54e9cb18dfc030030fa694ee1e543813415dbc83b1b453e70e9f676a5a543b98e5834417651e4f82e4f20e33ea609891d5ad20f3437b8c0ec64fe95325516225a56c0ea69ce3277a2521621e948339bcf7a99b7822c8ea92e461461c8cfefb123cd672bfc739cc80834967ad9cbbbbc68bf4e30c33de6090ba1ecdde34bb196e30674b2929a5f4a53af56a6983c1e44d8f7eaf173d6283a9e3e547ec3416ee396b30f5e82aaf48a5238d5a0d268b1fd352750d6d350d06b127d4d5040d0d660fb338a9973f652d04cc38c30c3318923e09162b46cee69d32185b82969482d0ea53693298743cb9fa57650ce6d8ad11f546e66973c56050ad7c51e24388d96130a5759ff0b62518f0ed9359f51232e30be6f7d98a97e45dde0fa9c20c2f98438ee36d2945081eda195d309a1097c9e15752fde68249bc24b595976405af6cc130b952c5113bd24ab45d70266668c160a2257e4e938967264f624616cc9b577e73dab31f52f81133b060b6d2f37e21be2e9a0d1b37881633ae7045b2deaaad9067d5580fd7c2bf7174b1013531ccb082d9459e4ade39fe96622412985105c3d749f556b1e449785430078b71b361af12664cc160da258267b887ba902fcc90825154e5d55139a419a5ce8882e146aa8d6da90e95d70c2898f7edf4c7c64497bf673cc174419fe9a0ea7f37c6194e308c9ae751e1cc53ec74130ceb26f6d7a2a9347799607ed32df12f397ef2dc8c2598cf530e167b7a12523843090613d367128c3aea3c7f98f03f2b418229ce4d90f5249a71046368b5af390bd2427f8c60ace4d9a9ae7253f45904f38f989f50a7afa31f36127f31830886e855317b524b3afd0fc1204baa8948faa6d46f2118a4e4594f25bb73c26843051f36d2e69811049376f80f6159cbb72540306957123331e5a5c4f603c38b49d28bab3835a98fd445670e66f8c028294e6be59ce6b39e7a60d059462387d1f4d12e0f0cd73a314bed8a4e4ed948773698b103f39f8e45d62b91b4bd3a3049d9bdd0c9ddea7fcd81415d794ed73d75ea331c184e828c982af777756f6010bb11271baa849cd00606f3db53e9f35ba5e86aac7dd8486506336a60320b0f6926b95a142d0d4c6aae22da08f5fce799310383eeb0ac9c77a13b5f3364601259fd2c87285af9cc5818bc732e1fd7de6ef5790d3260610e336184901ecb40c62b4cb51a6af53f25774bb36980d440862bcce1d923495e6798c4c8b6c2f4162dc952ff64a6a2066e68218315a6decbf5679ea6626833a0058d08d4c0d10ee0f3a25180850220f878808c5518649f24990f931a6bfa0719aa307eb07c75a227e1625f63ad0aa981a36b905418dcde372ec70e16b373c3c6ef7d51010f8f1a38da013570740d09f8163734208174c3e3865742062acca2557a45c9ca2c55d758ebc286c93885d9920841a514bf7462de43c830852958b63f616b6ed9ef52987bb393474ba9d4682e831406e9177ca2ac6d895491310a43eaa0b46acd9808f9230219a23028eb683149e8b32482a130dfc5ea4f3c29aab2ffa10419a030041b4941ded7d3e4e41326eded53ffd6371bb9278c92fd846a9b14d13ea9138611caca7276b9cb71e38449e4544984d39d4d94d3bd7388b264d5adba0c4d182fe4c497efece51241cd8439f6e9a03bdba6cb24e5c9c084b92ce7afec98923c65370d322e61f034d244551239794e3901f21a5ae04186250c415b2bcb8b76391369250c7a4f9ed74bb4d0e651c298a15ea2a85c8892a449983bdeaafd841589b949c2a4567e31c5437b1991309fc895b311ae23d117820c48184b5cc9d1e6e31e43081f619c147bbb43a538c21467fc83887b712bc55690d108a3e58ab6f9113a5e486284a93a8c2ab91c3ac8b86f0a321661c86ef292ac07f3b858086428c2242c94fc7c0a41fd53321261b820395775fa3071224106228c1727e976bcec9e2dafb156ba90710893c5d0115e2d5d3ccb8d761c1f072d20c310c64e592f7a59b6c46cb990510873c81d2689d029abc70961f8339dd5889eab84103918c81884b1439cd50fe5b1c2bd9a2a9021088396edcbba957e3ccc390619813029b1772d3934d34c650908a3e8ac9dd35a589c5f760b32fe604a26f258a7dbfc60aa0f594aff6ca873530b32fa60c8dad1d2980ef3c1202c8eea76d0f649d92bc8d883e1e36513225c8a5631f221430f26257f2e6c6e555b8c0332f260cef693e38308614cecd9041978305ed6f3964b09a2fdc30419773029bbbf102c9a0aca4576300839313546e6a9520b7274f1059aae40461d4c215a58cde94ff16cd3c12444ecadea8fde1964ccc1a0bba154a7c98a8fca0153461ccc167496cfeddde229d37c830c38987b25560ad59fb3dcf806e3b9beaec7d3718351444e7a4433de93966d30d74f7a75ef9c9316b1c041061bcca2f4baa9f5f7e764ca32c858833174e4cfe78e3ce2924e95c544728f3a4a83597d3f9dbd550e6a3b1a8c9a753a9728ff0cbdcf600a71d1d76fa10bc8308339766ad3dff1fdf288cb601a3917226ad4ba332383e1e4255987ec1faedf1a6b1f3612a640468d87a8449165d2581c0a8542a130280c8360f97514c3130000000c1e144763f1589e29bbb20114000442343056343c1a261e141c180d04e3703014068403623028100883c1a04028748ea6700c8b0f2515e935d557e99e1353aeb200d9fcc6754ce80c44c8119e6eca14f2955f0f1c331dc4d506d130fd1664da9c86913a19b432400ec18bb911457805b235891c4adeb651768091eab5d77e70eb293d81c4e3c2663444d433d431c64abd4c5e2ac4d1c74d6a65fd83cc3375796e80d929b7b27a360695d2efaa2e71a4927e3b85bf4b25079595fbd2e12d5ce34315756e9604bdbcf2447447949e31e3d015327d4ce6ff8eec4b19a3a68e3a2824240fec1a0c4a29cd8fb6e60e69df702c238fdf5a221c2e4854653009cfbb492309094f03eaf9fe9a44aef6c32dd154193276cd51fd88a713bc8bbb72614d62280f0dcb61821b33646137b0ed5c93179a1cec5d49039ba3d9b0fda804b3e9f375fff67495c531f413d2479b2969aceb4e308b44c3595f73e813bb039d68c5d33d15d074468af96cdc2007853353c5e872a516d2328d89ebea6ff34492bfb54746e9263e4f46a88595c6eb656166e4b4ff48995183760f133699db9bd3f91713e84bb02dc6f0280d3e028b4cb443aae45f1c59f868e386af9883444a0c3313163316ca65789f5ea051f15275dba98b19f039901ed51a26979dcee3cc0057f7ce0115f98c7c50561c4c70dd3a131d688e4dc0c8dbf95b9318d566b8c1a7f13a1820aad3e997bddc246f0501819d6dbe2124d360abe4e6f8b9d368b0e6c9650340fa75193d3f6165c390a5645f63a4630ccf23d0e988b646e2c50832237d45d706f09fd133460c2820c85317b4b310e3f2236f200911d6195baf9b946e95aec8046f4bc1f070cb369f9d994f47d747526de2682ce100b47127ff8a3d2a827fdb6947e9232edde09dc9d118655613024789b870a8c4c4a9023cfda92f006b7e5c2e9d26fce8d3531917d86936c09666eeb5d85105f5d96a1285d0cdc6088b5a9ce6545550fc62a55a82a94c5285fea0553886d36acb8394807da585bc695904589de91399533c582c41d09282f086e43284ed66f127a2d58407d58c66b9c3921c44d3fcd24a15ae568a5ebe6f550257005784a41641645c8feea284388cb28047a9670165e2f8fb11a03a18ace39a114bd716a330bd6276af016d6933466fd716a0dcb83e56b4553be0fa08563cc701c9322b365491d6fe6e067f4ba7832e5027bb66a42fbf982ccc6768fc7dc748ef8e74372037cd9c2e33969a5a8ba4340cca6fee1aac57efee90f26fbc8d5fed521609bde34a2c38edbe02fea1995c710f46cd8926f3ee054665cdef666013642696a1346dce3d9b935fa5dd876d522b5059bc58d8f7019d0b133494c18577e1ade092c4b7e1b12250b93e882fcc097e2ae27503b3d2c0545f0c15adc5328f93e951e631230d6579f7ee5aa358ed8e6ebb9f50ef288a543c45723ff414f08891a6362b4a7c585477a951373813a589b3513eb6ddff4d1dc76fbea8e4b03563d4f4bf6943bedc84aeb862c66254a72fc70a4f997d631840619285488e43d4e4b0618555bf6ff7993cd9c8e83d4507d42df8ac79ecbe7cf2cd1c8d51ef005c319d1b591c3dcaedeee1909129f14831e8e934bd575423155c6daca0b333ac0a6288eff7190aa94d26df0fdcf706f610be82a7eb81c69d36165f0f97435d6808c0b1cb38c91ef6680f65f2e8219ef2f12c2412c80db41909203cb5da2bf76d21f0a6edf92ef1be0a0dc7415ae763989a43686280f82c90a64bafda406d829e67911fbce7e50f8c9d9e4886e2a7f0ae954326d3c32b98d18ea3780d645642a76850a5eb633d09e8062181b846d2463553631a11bde2cb0b24489d5c41f0e67fb1e1e37159e99ea2a66f93fdec382ed9b60121641223d50946ac1edcf085e577a3607d2305510bc6127b38b6ce897021a09a554ad83c3d3d47a05f281ba95037af91c7229f145b624c8e36600b5adef16bcfb3e1760774c91ec83d9675d492ff9d7f424f813ec8f343d935f6c7aa7cfc9c9ad4a26408f147452bee24bf1154bc1421e669da917700f30d08c8414dc3d346bba0a73dd70d13a03c2c17d109ed09a71b79f24fdb04b7e9f589a33452ea6200b3c60c75e108fb01d33f2326022f2babacee5cdd3a9dcd48a8142f5dbb74c2bae7f146779f26c070527dadc04e5142a12d06ac44d69c68bf20ab902b3411ca990c250ab4a8295f5cc92e01c46c6f8313e0730889f94103c04a271a1a9668810665cbd920688daa2ab0ac9089d20193eca01b8c49e910e2df46f68e6512ad5385b1363d016da0c30f6def5453d35149ea2f30c5454043b06f36702f4f07841ed2c652a2d80f84f250e051e9685d1b9bf4710af4ddd3b1d58fa546fbb26549d5cff4339a3fe2537e46cd1a727a1f3f31cace2767cf447b6a6c2b2cd19c2803d01efa9f731c22a779f5235b4e70027e715161c209e23408ee15fe61c60367185730afa1e881b4be630e3034af70f8f12a7a902977fa47676b95d68889364acb145d639177c06c402624e91f0de01b5dc7d81f6f3157d71c7eaa54ed09b7247420260af12fa8d1892c80b00edbbf50cff96ad8f070f160ba02ccb6cdc5422419fe282f4a314fc05b20ce8d96f4f17d56882b6ebf66059e8d107135521051db202c099b7307e57c67fdc9b27b44e03c49d1c0c37b7104c0a645017d4c3bbf39d81951e3fd03ba90de3ac1ec34e460461009e16a010e9b2fbf61e8843fea3b97269bd44ddcfcef2e4f50978aede1bcb4735261489dcb44ede40c69ab926d5ab441563a5cb5cd513c0f480d8247ae1b730a9ca315ebd32be660f6efd4c762259ef8d71dd7b3c4ccd7b401479be91147834f9d154b8f4bfd1783a4174d4dbe951736a5e4549c86cf4313a4b6b52a8645720a692995df1f2ddafc3fca341e4ef76ba08b57f15a397087c02db6ab1caa3c75426fd433828c9d4dff765c57a22196fac2487ea9d1ec49c876ce273a353ff85278af8ab87510bd80ccd5a2a3672c6a1cb965cc4b0ace8757a1d06370430b48829dc1d645c47c30e91d02628f193ebaaaeedfc51f1bda6474eadade3e208cee33da6295565679256c4d188b64fd6f31b0614a508f9efe35e025317eac65e6f1b12ff2ace24a92b0a39e8e280de735f5e47a8ea2a9cd582c7c9f913def21a62c0d9708ac19216f7f90ec15018c5730f95e1f3b416bff1787514842ab6e6242c89073f69b261dd381c169785b0928962393eb211141e728da5a1147b02fdc6cf000f60b8adde605862ca16e03b1bf6e64e4f14ce7584274415967a248abb91498aad5e26818ae60c8a3985822946614154bf53ec087e4a9f42de02d4853b0b5020a2650ef0c9a8866091ddb41163b0f292e0dfa48426251b06f839e40f4b681606e5e4991057489c916c23a1a10f111120ab4a0eea4af2f70dddbfec18ac75d8058ad40d59ef704ab045c8e0506e67794163844b9efd8016364da9804ac9febbadd75aff27748af82661223f915301a21dcc370238d0a602024bd1fd430247b53534b3682fc35b9613ebe0830be262ba420825ba247918cb8c481a0ee359042660b38e7d2380f61c534dd182473045b738b3bd88d0f7cee823bf926103a40ecf63ea4bd14bba392e0725d3e2de186a6ed7d2dd18c0184147882d7d74f20a07f02b5e7c63e49b7d6586fc4b740f60a502dc94fd264c5691ed44e71655069eaa4c6a162a7f9d272abc898c52f2ad1c7f8a443fa2a18d66d8e95035cab372cb177a34618be41c976fec7648352223915586f21a5d968298ae628298b34cc729542169ad6216c156184b117d152582cd571ac306c5c6660a165f72e05a864c8b45e53dd71d6e8f2ead82e65944f5b7e0a3d16f1b608bb280a4b308d129e041a9c05d1260d01661bba70b3bd1596006a0c0e61dce18377031308211085a10ce0fff7f2d175e34669d839a773b2ee70f4e5ac544f1096d2479c1c3d1e8a42363e4511da8a34528dcd5a5986636ac1f1e55b5597d2fb1c7e13d4884e80a663246dba34bad54f32c81aa4d1a664651e8ab850c73c754189b59218b021d5a99db2c9cfd4eda91acac26cab18ad5c587f90ea981b8b1105e91d4b568ba85fbeee8fa609f2542566d22726436032c6f448b381725f00d7f6da63a51e2e5bb3f2080587eb64acd05a38f7b5faa830ccf81e6d83f6050098080b0a6e49c80709e02b988b6e97c2361c40a28eb5bc1f3cc321f7b2dcfd0d10510144060a3d04a1375e0e0825c87bfc2fc3cad2be668e87590abb907db333a2fc263766775c14e4c38ac3f41d5effc1410dcf315b1eece3416c9780ee738e6d0855aeffe1097e9329fc55d3e9ca9087c6df6b80a17e541c786e827099ce4b58a149e602dc906d8922365610ddb843ae98151c14a236db415ee677135d1b7075275f7097a2c7db3723e3d758d21e5462c54bf262b17e835eb50eb854909cddb05de2a3a42e75a28776ce6f754706652b4c3cefe11a91deb97fe26dd998a738d10a1fcfa3090139df3e1792db3d3792fa1a799d5734fe19a0ed81c15a46af7498e80f9e7f4dc8631d6f358b4fb7ce6d8ef496d391fab6b460156a256ac6030b05a1b43bfa89002589276a70e0e265de40dc84a84e5c84865a088ac1bee1ec06abf228b313a4ebfbbf9dcf8943699c0804b3d9fd09db19451f95616d378139a8d9e406c494208525791223aeb81cf08efd360eae8862706d403ae2817bbfe4490fc935d1bb4936a7d0c9544246d4d18beb20606739bb92e84044a44f27a1510d425446305293c1ae2b314d6feffc1b34a3638c94be379af27d12542d4045a5dfb6c7b559947740d5a75e6c831d8220cd4cf8a7e00e3812dd86d3fffdd6d5fe91cdcc08177ebd8e7c15948781be697d412d29e519ede69afd26dbe7d7d40ab6ba565eea80e62448f634b9b4d3ec6d36086214007381ce5e45158e66f6c7617970635580749fbe6003ee96cc3aa74de57ea131aca128ed9258365d8c49e1ee9bebad8baea4ea045a1dd445eb9aa551bff1f35282303aaab55f3159c040cf6999ccc99b2c93d965f3a952315162c2efaeb5d8ba5ab5142e77a35ed59e91f440cfe965d6baa7c729cf219e87ddcea44aab19f5662da7aea85642e55cae1cac810e8ce49c94c99ccc2dc588be5b20033a670bad09ea292df6aed65a28001fb8419a0bfa913f9782bba69d9c96ee5889373a889929155af5a87cd6e6dc1f13309c0064880edea01dda712c0691a2bcdc7a8dd32fd9d35ca9da2a44f5592f67f7b44a519e663a2d9c5b17032bd5cdbeaa0d0a7d36e035512c2eb62b309c35cd4b9408d1eb36395c47f42b69baa83781988d9f9af68c9693d0a2cfb19685467f9358aec464b1a400e3e90b4d15b63f6c618fb20b0e7bfca8b3d223538cbe49551a50f524d8696eaa54bdecccda325b59721ad7040b6dbd9576c28307109f07c6a45f02ada4021f4c27c70ad3fdd457f540fcd71ed041b90b96e85629e021e26b91fb357836a29e1b315ff8a662ceaa88cbc2dae08ab4cab5781264a89cf863656dd54a781afef003aff17b00b649223c61b3fc4ed93210d4083df7f2054ad5f8916a11250776bb474afcde8070a03ac3ab4642a82fd0d8b21d44f9e76c5f7b4306a0afba43828c8f86006948b2a39793e2c5fb67cd36e357a3ffaa4b5257f13d519c84c7e16c014db804ae7b16153b2ab5159a22ee0a8e47d2fcdc0c58a6f5bf55b235a4d367064e0e4dc820982ec17c53e9e09d18cea18a9b89ed4cc921459958cc60da9cd53225ff0e63ed03076fc4a041e6dc7b4e4a14fac99986f362dd8951d8eb7b95d7a28611de36663c2ebd3653358ca005f881c3d9897f0a16e74072eacd5f118d9b2a5efdb9b7b9e891cc2303021a86e3a6c8a1e43f0838d29c226cf57ff04dec33e016d6a36252c36ea35849c8b21a9763f5cfa7921011dab0f91be0ad109e2b39683674bf07674f3dad160c776503f680490ccbce93eb4cfde05655613ba1a611f364a06e2c4a0adef6d9cb79d12ba577a44d7295a8af828c9cc08b0db413592262d83227468524b572695a32bb50bb6910c25f221d1e459e6ed04a760fa838d2590b68433940f58691bdd1f17e25022389e0ea0ca70c8f94b603dae629bccf5a3dd7fafa071d093a0b6d97fc204a4c3ff45e90b1cab00874ad7d756880c480951be64e1ebaca40f0d107a5da0f1d81d059d59379131bb2288c1dcc769827490f4395a5248b4d40e0a1738c6c7df960866c8818bf2f167307a65a474d0e4e7f121d42dae258bd8e368c5f2520a4508a530495d3ac908ef6073ff0c535069c532deb887e8605b2867889a39b28730467b1df045fe000e47e3989990ba1981973806ad4085165a4bc1593924bf2b67ee49a022238f35b57b614c78c50f3931289fbcca9cdcb914d25302c994c1975870e2564a21ce049701d4afadc798e713ade09bd7411a40a316586aa3726e33c138cac22a532ee7c0a93fc9aff14bd712bc8ac13544d8efdfef2e7843779aae61ce72de0f97e7088bb782d4c6e9896a9a7632a536222338323a231b66e690cf92f64e8bbb466abee417ee2713178169814ce3f3cab878fa7828da4eb68c204976587778f0215358ff93d86c9f1da7f5c1a562049cc6a3435ba8543f69b84b781a58a98b04a45c9bf1f81e90db6a5a88153d7df27f23b4aa50662c433b04c5b20103079344120d91c52b119c1bb22f9100ef26cc7d746f92798e276ff8e7ca09fd068f4be423fbf992c0f99d10f7766b89b22c683c64dc34cc33b35d65871eb3f821d063403ed749c9bc0d400fea5c9ac30075cf431c69a462b1a7b219f68ba782255c7e683e988dea42343b4deada812efc2515b95025b3c5dfbd1e36217cb6fd280f0ea49fc22e81368b2a4fc6950ca1ead6c41c756b5cae6fda17481f4cd02a363b2c0518ccb650065be36a855cfb91c4d72196970e151c9429e25dae3d601bcbdea7a8468b85b3b2dfcd06e1a4d8f62a5f9ba3c8de9dd1429530265b37467ac74b3bd920d6b3e86f06b758f4fdc869a213da35b2971ae65609c05d6d6084e0d06e1c838a1dfeb6e0e9981011a7c0e427f88380cc0c2cacdd5752df7ad611a0f182d975ce17712a9cc292b30aa502c2ee3732fa41b2645d9eb76b7d081b0a24508b99c398440d7745229514a28e27a06002167b822982287535039c5f900163da00abc06453a610cbc71752de78db24f47e2841492a81119999032364964a5acf9aec81ee548df6ab3843717447163c286d6a084cfcd2b9f4dc1449111b2b9368afbc09e623171271f8f9ae165710844a9f0f6990e8a43c38f90d9b11560ca380ffe0eb9b59b411e0f65e1c8c6e28f2a1e8049692e181536899aa314129127804e3cbcbb56df21fd5be2c03c036039669bb355c3162a2d55eb00a0c9ee55fdc4e397f151504888d76721fb5d70e156d8a1258c6b39e6bf19bfb5130b57122f4b3b31b9d227e542b7e08768b3ddfc906067efb8909062ae0341bb0bad6e9bba5ed97ed8236beb408a1c2934f37a12f3feb891a1600f14ce07c2e6a83553293ff1441a2ad5e526a9a1cc1bfaa2e0a0097797cc20903967660c36109c602819029fc977350b10d505799971085720cb2c3d0cbb9cd37ba15ebeed57a3444fb18a2c4a10f80bd3b80240124d00086ba8f8576700a84c17239c5732c7a5725b5a22133aa23f7a9d9de905924c9c82c19adb4ea2c5575e61bc497c11f0c04cc23a32fa9a003cecc551d9ea042384a5f201ad5cadcae108a6f41aa960b032dbbaa1a7911ac62da0d819b7e744fa4ae22652b694bcd044772a323281d90205c5d5ee210a6b82251577c6ae0d70c99148ada5170d36751954b0bca23d7de4e8d8a033919278656d6e21f25c700041b0d6296e629f5bb8405c4ff6710ee00e56c1f7a4763b50ca5f061362ceef80e1904b2c69529064cc6b7c5c548fb3b64f259dacf03b36d9ddf5429993ae44100a51d35c2596505a5c040501a0f17751d00d8588369aac0cb8094d3e8b7ae995e87a88d9a3154c393762ef11323a406759431b868e3836867b8756c5dfefc509d8b75ba9614bb62e242becc15a7e25a13b623c0906d6a7a563835424a72c5f0f24e9e428b113c6901459832a3faa68543122575a27282e598e4acb2094be296b260f68461de88f59a22f600c0d4faaef59df66ba38876544c45fbcba2a6fca748dea1c57eb3c297f76d2004cd7a6d2b1001d19559189f29df22407539e9d4a396221bde703d8a83f2aa3c7650da8986bf9018711c782343210861750e0a1ba40ff641ee85635ca4642a6950fe3542eaa1fe3fd05ebee38f56d829c4bb9774623c4aaa54368ddc6509a01ed3334701e80e6774965fd7ab1199de4f99261b602e0d6549df6895d56053b1a492eefe45a0f23c9e58b5eb4af03fa7d6d9ef477a23754125a9b0a8e48f0253de535443e94eb0d9603118d0079697ab395ca1f16c9160c73600dc4bce18130aa31073abbcc1853ebabd656e8d6b432b42cd0597b70f674ca63111b6a2ce57ce8a60fe24597b02aa58fed7bdb80f5343cdfc92a225e8b02fb39eab7c6ef4e5f3cfbbef25b67bf053f58fa5fdab7c4ef565f2c7d4ffaa6a45f91a57df278f53447bbd75979c211925976126a1b251a27ffafa7fb836955d0e6f734b63f4ee894414c595b994e62f69f5dfc09093d7a5a1b410e66c398bc6f4b47a5a07eb14f0cef5a8ecc660f3f7dbc9226d7409b5368f9eff0b0b0c6bc9ccccb0347cf5c992bb49e631458b127ef44c6eb62acd7b203d62621f2d79834a481646816d50cf5669330dbb8d911dff6730373b8ff0674dbd82b6d95485bbf93ae338754ac7d72adc3897e2c41f29bc42a124704c92725e30bc7044937127d24963712a3a2929a8442e22bc9d625924d8c4625518955ca5383447c24aa2bed158073893be9c9b8b4a6a3edb07970af3dde535c082d078f661e3eeec771f892a7c89c475d1e2d3d08f5f8eb61d543aa87411eee95c77615349bc7c523a687821e1e3decf410cee3fd75b7ab207afcec71d68fed4d21c73a7b1fcb800ced88ae215601f185c8a9718ca8e8fea2304402136852e773ef5cc6dc38154709d11ba8328f2ef69ba23cd8f38e0917f7fa4d3b17ab02d6d936067d42722c0d223844530d6951c4dbaf4996653eef3684b379659624809d510afd6d024c57b6b4c4f39aa96ab5c3f991a6838adcf05bd98c7e00db019324c72d133e925ecab8105380e606e7c17f6d8a48295206ef1a84518b7de68e2e209810874e1c2343320a40f1b4dbc21222d3592f062ed80ae8c9a5e8611c534ddf0bacc3d815371278144dc15602ca81bca77d12b599654bb48d3530dfa0894c2a0cec0a33f31ce4b295491e9a716dd2b44043f846b544cc29aa5b420353b830475b0ad4b1d921f2742b8475a9a468637eb2c9724e430dd83247386e389c7a2d01701a0b6127b160a955e938c289cf05c7b3e2973a37ce871adbbdce2e1ab2114a9165a43179437663c6b010db77abcc2786499a1254e337a76a58360c54210ac9fc503d6965dd62437cf0db39b438b5e38219f22413635d0cd2dad7ebb4f8f680eafc362daa48e534991ee59ff25e409cc2097a5bccfdbdd82d9a0af8053c796d80d2482e28b3e47db119aaf2e005942160600ade7379ecacbb61b786d23e501ce9966c9715392a9d0c443b8730c07e787bab84968c58414d7026386141914f631fdbf871078f5baf3e6d6c3d48e16f255407b8e434084640a7c4716e1215323c2666ff88b68b6bd9b11a482cec660cb8586519420036266ed50e4a46870e6a49be064bb1b2fe617a189964cc13a7b6f55350c9e47a48efd563925ba6b746bf34499f85b1ff15f89f6e9148fd39c4839b8f5635a0226184a7aa63ee8d26ee9b4522bf0612846a6fa71cf5a4e7e95cb70bb944e8f0a2083ceed422ca8bf291d12eadd76a283194730311534b83d63c31940547b61049726078751186f9f6808515936e46c375436d78272173d80a20eb96efe242572ba38394724d3b7affe1894e34c4a46804be6ae3a2ab85007f400f4d00ab092d0c802ee0f9f1936b154aa37814cfa7de1542c0e2e67328d7387b3b7615ac044b68e4871e358000f4eeb2736a2abbb01501f26812c729f5cfc034b281e89c10709c5000e29e3ac5c4e65a59f09e34a7257560d1493dc1669ed86e005e7c7c2eed258ffa9cca61f7ae1d1cdb600b5bdb86d501c78206f056b279093c4bf34f53a9f7b40f8065ac623c7389285355f30ae06b429715bbe542a81fb1db278e316c68bd5818da16cd9d2ef063ba5026008fe0acc34c156710c480da7fb0e34668e5876c504a10e8fb7c4e6f07238189ee2d273f5b785ef929d876f94422645f08290457f9b1233676e2b6d51c6525448b06c9988d009923c72398bf297d971300f41a14f2951fdb95a06c4961c8ada0df257e68371bd16c010e43fdc3789c5f671e770f36a86440c45758b44034ff1b16454adf482ba65c0f93c26af075296796c02ff744904ef533db4090cd329522b2053bc24489a4ce527f9c783c227482d9110368caf03081ed464811e98626af381b718793196e6a3439e036c48d52360bec0432f046263ca3e706345dd7c283151ac431b06a5d9bb21278077bb5be32ad756c55b166646b427c3b6a6adad3b7dd5225b3b9af5a103a7d6e99d328fa5b986427b6484f5c5b1a92390a2607ae0a540a68a1f5e8d9193a4fd969267aa04b919c53642753ffe937704d27d1237467a8bb68d66c881de86f74dab694b0cc64ca809fe4a20bb3b4433a4e6be4a3e31d41d3fcac39078512da528f71927d7dc0494c51c15a490fdb2b8eb667cf9e5898d82f57384295f5aa0d761a55f0915048f53ada6d1515c04f93a579fa1d761a47a3639708c398914f465a8e4c3061367ad1368a6cb4da48f46070460b041ff58eb43d232355da918aeb9cc26f9cab1ccee9352a83eafc84869b782abf711c145aff6ce44d10b77ec1ef51193420ced8dfc141387e2c201fda4046f30455b2ab0ddb4036c4541a4a690e27247c29e9e5bd67e90c1627d3e7302ada05801bc118252935b9d6fd729c58552b9d376586f1308bfcccef22092febbd8ed82b390135e3154ea3e7e0fae5fb6a088f70c5c0f2f1d711ed60598fb8e9f5bd388644d7b493591821bcda8165c9ca8d95185676b71ace0a438e9585b482291764a89f3a65e8d499d080b48c851b94e44a410f8d8c0407daa6485209474185cb1711ee3a1cf3ea0dfc4645478157512e0433e4256a180698ce52c6e88255648aff76ee29943c60257aed1187b9a5be03a71ad645440c5c22a8a4542ea834f2f1362820b55135788acba4ba50956084a7ef114a81f87eea84e022f79cb9e30175a4804c444969a55df25710177434ea8a4fb48337c90f0dd289c71f3d0f00214229f0e9a381ce1d38bdef8056cd6e2a67e19850308a02b5743f285e818c56861ea407b2313bf1e9cdf8ab7193622de702fa0e09ee882b84e3c2c085d42f326fc4c423f783fb2a93b223540823bdf4f3762589803485210cdc40243ca219683c6a0a372b6b32ad5fcc174375c931adb1a6d58574d697e45a66fb79181559c8b71f816a90eaad50be42f3f741fdc7057f5e9544c8b8e4d94acda85b543398d3038c13f3de1697219b3407b3519b8d266024ecbcca858d4c3d2788c22b0ddb80641b18ed807b5081df10982f55b10c4cc49ea976c3cff91c73449f665d5134702930e091782ff2f88d7e5ad6582a0d0492edc0f9c3a52f57c00fb20f08e607104f2d0b7b96e92f97211632e90998c85d0fe722d2adb6524728f97f6802c85ea002f3b884379fdf4f23f8dadf5c0582ddce2ef23de637d3bcf6fe6e7b6b495e266b758f847d9d83dd179e38705a9ab87fd8fefb850bb4038a460987e2e52746597357b121ba6ece14ad9c14dcc082aa3d8a5320ec01bca340dc06cd1269c3bbf151efff71bd48901bed4d84905f411f3baf9166d0ab7cd4fb7fd40b20f4cac7bdf161bda88f355d7706d8eb7d4ceff8b8f11a2fb87a852037dce3d5c5bb25d156d5c92020d886c6b87290b213a4308548b3ba0cf6de6190751fc72032ad26acdd500fc1a720eaa4a762a274048c70c3b8cc2c3ed7b7deeeeffd78ffca3dbeb3f8ab9ab7579653a85aac3ff87e421a62fb19b6d99adf42cf146c9967a0e52381cd40bc2d0b75b7098c37d644725581eb609e8cc5c044ec81dd044c49389bf0a85165ff8a24e593f4fff04477fc0c5bb2de8c423ea20969dfc5d95a4db48b8a18bdcb601bc2a6d66c0700d63790155d884e9b4fbad5242e16906233635d2d8d453fef428faffac90deeb00840d88de0dc270024710739a621fc6ac206054925b84a81d3e89f10961b21482f37482a0fe20d0842ef222aca9c29825469a7d5bdf6bff881e13124dc0c6e5402750450015da19672fcc76340c634d8037cccb65a58caedaf501b047c3c69b794a256b5857c0881648784ef3e1517033a6d15e33111774898956608481597398027af7cab65075a5ea87f8909b13ee98a0cf1a40c443a51fa3c0bdb119a11815c7ca9f7ef86f13a1c6fb4c8038c7961c2320aeeb4e758895cab3cddece684873ad1cba72cd9aa3a40283c117722a0d197dfc71833ba3b1bb164a52f4fc7a1266b8a840937a33eb338f33360d475859b1d0dfff8dc3f88190fc4a014cb31b55748203c6ab6fca35a1b1e64c1a3eb2217454abf630c48495fadcf049f13e3306f652bfd225de84581b01bbee778bec44af16e551a87014bf6a1037c61f558233492dd320cabd87ea73802b3237cc792d2e520fd46380fc17e089cab21a84e3aec1e561646071b01731ed38f298e59c784c6a4625ac65c1123505716eb5e22e8ce81d03a7019465d22849273208a9b5b722f77bd37353bb48349da92b91bae90a610fa435d58f7b4ada1e16909c43de3fc97e094c3de8843355c5c101c60a0767679c823b7d6b3b7bde87ac1f262c0196de7c755e705b049e05096ca9a6cdeb141029844fe645fe976a0553c32ece269c82370576322f4ab1d4d8858dcdbef59f6e2ec0370d2ba9f39b8ae1e30766c2cae199eefd86c44759c75f43a2eeafc5fa4092f909c967278f689a8384cf8b0dd3e040fe03c2598811955d1301ebf2c6985e70ed978b83e131afa13c6af2b5cc25ec6e97733292be305b9a537430c2a6ccffcee4904c813933dfa228373af89f71aa0d6d216dc6d2ffff748a2bc0c527ddf106149a52584fbf05a780b8f179782300377280716d916ac67813ac52964e22bf1f453b7595487f3fc078e24c4f35cfac6c27ad708ccdab1bf84a8969bcb8243482399106f3b0a3d280e4187136b8e65811cf974eb94ab2fcd433aac47ddcb36e61d4c0f79f2cf17269290f1f3159e2f75b1f0dee813eca4021e89848e0b3660b46439330f0f0f0f0f0f0f0f8f3121b5b54f48424a524a4aabd75247e420a524a54c2989b7483b7a3a33f129a6c9de6498f8040402c20bc70b970ba529194ac5532a28a5c7a80127ee5f214f5a8e783a3168c07a4a297878ca32d5b663164c8ed729a9f85bf27ae3396c6c60c60ccf614305336698a143166c66448d9d4468e4d7c4823fedaff9a34760c189ee1077731c9d745baf489ecac9cdb74757703a42ca15730a19947dad605f82662425ace3dbc70acecdc3d44790ef216dabe0934a4a664a4e1e3cffaae0a444492b62a954b09a76a742aca8bd6799252a785bcb1d59a994498c769c82ffa484d211377595af29f83af9a33f9b8f1252540a6ee2a65df797284953527016f4925c3f4fdb3419052f2612c54f6645c1f9c5dc94dbaf34e8e0e1e80805abab13420e25bede9b147480824d136356ebd99fe0d4fd57f637992df6da800b68514ed0e1095ebb2477ddc43bc1c41c925f98162dbe419c603d922e696b494d66cf2698e469a1e67e5737d2046fcaf467d7f6c7c8e94c70494fd9e40ea57dbfc504aba5c77b83ada714d24b30392c55292d1ef27f8a25f8ad0c169e1daa76639560547559b885790a756180c60942072598bc41529c1c3ad4e23e6346c724b8b5f8e31b31eb3eac1a6934eaa6d021094ef848c8e1679d69523f414f60c60c2f3a22c1d786082a9a6b4ec999ea80049783526d2288fe11bc8ed021c7ecd31bb2c8118cd60ccbef49d4434f7e8398024e021d8de034e4dff43da943ca0d6211e86004abc12b8bcceb9e47c72c82efec5082418722d8efec7927294b29c9b023119cea94dd4bc6122ef22e0e175d74d1ef051765800e44f01526d3c4cfd095cf6c41c721ceebcba2eb4e372ae83004fb1ad2b43f3c2479ea1bdc51082e67e57491a5ec20042ba23db5ad8e490a5dc0050e1a9e6c98391737726cc720f00b49a530e5a2a26e0c3a04c1994ab595f54d67aadf11085627e5b2720b992de21d8060628d797b55a9945448c71f38a1ffa305b788ada1593fb06fb62629546366d3fbc05fafb7794bb0ccb4f9c07e8c6cb2d4b4072eaa78aa4efa3cbd5c3d30da79a2e7f4f595369a072ebf267597206944060f5c063d12ef2f596a767760b4268d3177ec16f5abc30e33e8a8c349765042c7545a0ac90e3af03958c88a215f4ea2b21d73b0191d72603fc9d131258fef9713904003a0868e38701b2c8d5c1711b225b57ff1451b1278c1c50d0a748e66c0052420811933686400ced00107f672f2159d624cea94ae60a1e30d8caba958a752c8775d631b3adcc0d7c7e049d3db36f023838aa0a116717b3674b081754b225685a05e035b6eaf6ea2a63ffda506d663cea1be7e3f8f9b062684a42fee6890adf92fde810636e7e5a4824cb3b45981a0e30cecae8ae6bd3bbfb69c02860e337071623ecd1c3aa59c45eb858e32707f994d591695e4c46fd0485e943b420719b84b4dc143b2181c5c181f748c814d31668b90f24bed88e4b0a182d221063ef2fa8dd96ec4be48018d30b041481229e4244fe434707071050c5c98fa4d41a62b499e44838e2fb09147d4d94775f111aa91c44a0076d0e10526ad28d15841684613e902a7b5b784a4bb50a1830b8cb6eefc93906369e8d802a74bea5f67ffeef4592d30aafbb3d783e7deb4d0d09105ce72d04188125a648c3916b811faaf6a21bd4d4cf10aec5a0c1dc945a9521347d46105365db2fe0ec2bf62765805f6ddf4e7385eeb163aa8c0bf7d324b093a22f7d33105c6826e0da9e33987d0b09156061d52e0af920ceaed453fa64a0abe880257a36e528aa8a3aff324b0fb4107143ccf5fb5fa136dd0501e743c81f7495a993a7a9ac72cdde81518740263df1aa4c5b1bca63d4d60438f6bf64d4a3d05bf461adea083099c1cfba469540c9a7a61435b80bca0000ae00e1d4b6092d6e49a827e97b549097cad779654913faba808858e24702ad47b2d54590ee16f193a90c0e71044c8bdb1f65dcd11b864392d57cc15b91742860e23f0b529c4226e4811f8c937713787e7583a18860e2270c94a9d48d14e770c818d1fb1b5e4256971371a2dd00f740881fb4fc24e488aa03cfb0e7404815359a966f235d79368aed001045e34770a399ba44e3a2b56e8f80117fc3d04b52153238d469d0e3a7cc076a4944a074fdd7b658db416acf5800d21966bcc53513dc303fe92f6ca1b32d4b10326e6a6354f162fa7d420a043077c090922ea256f8624e580af983daee4b30bcf260eb8bca8a34fc449bd7f75dc805352d3fe7609ad4ad7068c52e33b4144936be91b1d35e03c09fd697f6b9dc65423cd4632d322030ec841070d18b7affeffb190aacf8213622a88adbe27adb194051bb7bf2bc62ad3696e0660c4824d69539e64ab1efd9297b0e0bdd7df630c39e60418afe043bcb451ff25e84b2379d1e45cc16669ab6822061932556d048c56f0371e36415465d18c16197080b10183158c655325a3dadd5b560b2360ac821dbd92ae2fa7a42a7acf8dee95ed2e239b0418a96054a4c9c9f2078931a660a082d5089e9d95a2ed22458b2db4d8420bf30818a7e093d2eb2d49957809cd14bc4f4e5bfae40499925a0abe45e69d2521318690cad17e72dc80410a368b7efd90745809114f41c01805ebd9eb7df1828aba9fc11005fbaf41dfeb4b67356d8d2c2c1a80110a2ec4fbced39b2b928ae2e8030c50f0ad31c7d4aaaf9553e4e200e3137caea67753be9a2fe8a400c31368cf76b24dda453db5000010303a91a7eeed0ac13c5e3f80c109f6433669e5c1e2a9bce826b86c3a98ca21f754a4cf8dbe40299a6033fe691f9591f2f51f061899e0da6fbf52abe4fbab6082d3bfa395426b525a62b904ef19724c97a24e12ffa025f810b47defc40ede2eaa042754c794bc36e9a98a53820932fe645162b973266b128cf726a96ff142352b0926ae7ebeedbcf4b596014624f85361a75b7df6714220c1a5b6f4a4b324791e458f60f3ed72cc19b9bf73c411e40fc1bd73f746b0a63ba3a6902445513a23d82a4b5dea679d37ca4570327da9a4529922d8a094f64f113dc97037115c5e6f48c132e76bf8886025e62b7dd63985db7b08ae93e98ca9534ba5983704db9382f9067d39f7ad8560ef93daf2b28d105c3013135372b389b006c187875022b778cafb7bc31004bf195ff3dd0895589a0ec0080497f306cf3c75a1f29a040b3000c1e48ea5cc2649f78ca32bc0f803fb9927e9896b69681f0330fcc06898876c17327ddabc0f9ca5b6564ca67225e52f1060f0810b9195d734e7db905335d26ca4f4018c3df0b962e6deca9962d10327a964f2daf423b7926aa4a5d4346c24d30318796062aac98a936e6cadad9176c34990bc0bd4010c3cd89ff95fb91e52793968b4e0468e25598071076e82d4d518d592aeb809fa0476605c84ceb7119279bc8fe100461dd8d2a419aa555474a7d448ab1bc0a0032b1a24a49cb2eaea8e36ca66ccc0d145172968c0161478038c39f071640ae197b264f2a01a69280032c090c3b61be32565eabb730088028c3870494d44dfa4a275f90b07f6b3a62447ff7f48ad1a09da8b968041018801c61bb8f83d312ff807bd34ddb08132100b186ee0b754a760992f681c2260b481d32f4fb596db647c370301830de5a997875f673c598db4b741e3d0c05803a7329e92372a4e022fb830247f80a1063ec4cfb94d6ee6268ba681ab89f599a496d22112c3051868e0feb285b28d24e35ab600e30c9c45aad211a692d000c30c8cfd071962d41ad174712307a2d18243a30cfc7b99672b4d3949ca910c30c8c0e6fb243379cebf51df301b03373ad2bd2e26494a4462e044040f7d15d1a46a65038c30f09541c8b6104769a81b0c7c753279426e48a9319906185f60fb5fbc62975a47fc6b24046078e11113c9fef9ffaa3287d105b6d428d51f5754d0ae6aa4599a4ee003341200830b8c48d7a98269ee18ca13dcb8a10005cc98817c035d74d127c0c08c195be03d87de9e28e1e96987a105f64cc7d041ec3e30c0c802e721079545971a4d8f1d16d81c796326216f185740e74c1db28bfd56e02a66f68a0ec96973ea0930aac06bce6221a6f206993354e0aa468b0aadf89a9d62028c297039a4d32a414bff27111a0f6048814b49640ed31b31e8e93900230a9c087a2fc4d39ca43d9f000c28f06a6a44ccc94d5d502a3304184fe02ba69096f49350e67921c070022342321d794253232d078c2630f9c72af37ba8a568aca1000613187915d4af36a95cf5daf8c2d1043096c08e96fa9873df35d26ac050029faf3fad093d31a5bbd448c3190148f068059bf52d66ef901923bf1eace06aaf764210b9c72a188f9ff4c5948c9a6378e0a10ac62a77084a4491f719d3399a0137f04805e321b2c6b0efaed31954b06dea962789a6b47c993123070e270117094fc16a8af92586a89a6448c1c0c3144cce7275f3a8ae79548f52f06ada31a4d51f7539b413f8000d16789082bffd0e3dd31e09ccf01805eb39da26ed639d5b4913f8008d2f3c44c1a68bf729df42279d6a90808b1b34be7037c1bd4728f8ecde762a4ba06072e61a75f22d9fe0f45bea88dc9954d248199e073c3cc165ab77d027833c61f94eb0773a832cab0921c939c1b8baa88852f24df0b9e2080daa214df0216c7754b724ef0c658293a63ab2a6ce23f53e98e04ab9e48b1ad44ab29c4bb02151c342ecd38b765b82c9a92a497ecaa2c6dd4a30394d7e68087aeddba504374a2d26097253fc5d27c17f8dd08ea0a5e67f4a82cfa8adf7613196dc4d24b88ffeff9699ef7e3190e0e4782c31cf1174102a8f60d7f3a71ba5c4930c298e6035d46628651db61d6c04971db7da649fe7df8e119c4a4149b3d32f82ff68317ca32711324811dc774e7921672d119c8e57e90c4ac8eab210c1a9a484d4f862a534bc1a695e3c0dcfd13772e038880bf03804aba1f7c1c79432dd202f52d080b3f430041b736f8e9c4699f6da0bc1e656cb1d25d64ab6122118f91d6f7d62e6cfb11e04eb112be9d19f20b80c49738f504b1de225106c929982b0af511b6904045f7921f7e9789327e80f8c6adb68c7eab7d1cec30fbc67045922aa059dd85d7af4e13cf8e0b1079b31060f3d9c7aa33fa5e47469c005b420c7068f3c9c071e583d3df244526d2a6f907fe1450abe01382640812db4d8a2015a64200236328064021fa021804a78dc81bf0d6e5b25a2259196871dd8fdd7f50e0f41e3df1e7560cb5377ba9c3f5552e2c276e0410746e926d55deabf23a95c0088e03107ded42c4ecc7d3284ea75f09003ab6a31d364c7a0db937160d399507949b5396c64408b2de0c05bcee94ba998ea2f21273cdec0e7ce23fc94d64d88f90624e1e1063eb5e670ef5c9a438ab581bd931f6a4c4653a173b4d8821cc2830d5c9a103fe4f4e59f7d6468f0580397b32521c57cf2070f35b0d92e53f576877c927273f048039323270d41b99fb7bf72f04003939406952f23581eef68b4c1e30cbc66cb6baa63c94b9d3703139210adf71d595a82cac0ae07e193840613912032f09d95425afd6360f2e4cd21aae7564c550c9c309df933b7835fb084810bb5b2d21002031b9a2f495745be53ff17d8531aa4b5e6eceb96e405ee5255b6d6dcd0340f011e5de0367b68470f1616e20227d2eddc37d85b6074eedc9c72b25a60ec46d5e999ba9c72cd0223ccf46de5a6e9742616f80f5a91b3d66fced75c811f11f57e5267d660b202a355edfd29248f6d972a7059416d95ec8c1a3c4205ced6f2b628d3794c810f3993f6bc9162324f57800a1e52e04b480b3d5513a4f5ed110576f3e514c735a45d4e99c0030a7c861063984930eb9026e4c2e3099c9b4e22688eceaafa3b81dba429a7984a9dab83155080210ef36802579b635df44d954ce916e1c1043ea46c9aa563e6b10446dfaaa6bf4a15aca246f050023b4282dede5df90725d982471258f7fe2816af3ddd5624703bdea7bfedf4678c68c1e3089cd064fb7d2d2286c9088c29c91a52d4eb0a1e45e0236e6886c7495a821c041e4460834c49176c73fe7beb31044ea60a91738a71250979088111312747b5adcc23084c122aa44cf22a0f20f02121c7b6cf4954f7a6465a0b6ee45063c3e307ec7dda34fe39a66e30053ee0dd83728baf21dd644b8db413a4007909bce0225be0d1035e350615834e212c49be465a5981070f98aca24b34da6ae51e3be07a5dff4ab958238d460b6ee428393c74c0bd8f10aab27257ea9f032e5db598a794e57a4133669475c10307bcc6fe2e3d6ec07e5433559bf2353da7461a0d1b393c6cc0267d6f955c9e46b68b9c056e47c3a306dc45ec51a5ac2d66b088c08306fcf7a6a74ee9e324b8d135d02c181d3529ffa859324991460e1c292841eaca400c59b0f9a2b3a59be853da353162c1c64cd66964ff38a41003169c46ba9c41ad826e88f10a2627156a375fd4158cf4aaec20820ac973e7857371a3015a6cd182193368588c56c46005e36b1152455256a95b05d7d93dfb3e6570f71055704aa64bb13685f869cc18a960c7dc3666f7a9fd9ca382dd08c94e6737113b055f6661f984c590738818c314b9aa55e52c8dd1d42ca34ed618d26dd6766aa499c0868d1a34ba485cdce1214629b8bebc3751ea79498514c4f4be979a6246c19b50eaf52b8735d2708b1a39b8e0008e2eba5080165b68a1c5165a68b1851618d0220311d0824999ab808b220a46a407b5cba6a2878c8682cf2721265332573140c1e51845e5ec4d9a945e7d88f10946342519ef3bd4b37ec4137c0ac9b736d6a89887189de064ce75fa3ce48f5613ac430c4eb07e9e3668d9654e21493818b07088b1093ed3636a11a62e52e50a1b626882d7789692a9a568b14506228003c71a62648295e456ee27caf276d4628b2e1a139caa84549a218f5ec9b900a315625c828d25d4a5b78cf55a1e4b1435a9d363414670e4701c38ba125cb692b13b6f55de2053236d8d023128c176fab84954526692a449b0976152d46411de16920497432af9313b4511033122c1a9bb2074eea0b682ed376cd0b03b400c4870d952ac8b56e3997edc0208311ec1a70f96a643e893f96b4770324cae5725a9d9444412a3114c6c537aad47a6f4d931825127db2f4af61c82ed050d37bb8bb10836e91c159328fd0e221e85188a60cc738a693fe2798960f74d88a4d01ef48b880836289d79b2e8e468216bc1a1c145dd03ee109c8a95b7c4daab9166086e4da84ea9757c73eac210a310dca53549323b48fa3d1182f114abb64f445cd42fc41804af6bde71b437444e108c972a59225e786bcc6ba4adc0861781e0be53d49ecaa2e91ebf91022fc40004bb9e556ff1b56bf207fec2bbd2c8bdb30c215088e1074e864ed0aa8c90009f10a30f5caab547d172ad97748d5c420c3e303a6811e11b74759a7a0facb85568868c9ea3c50fc4d003a3217bd6504d4b22796083f0902e3f2fe95c1762e081dfd35c53c29412ca3bf09691ded36f8e88fad8e18b22aa73fdf31a69756077e455363b9d0e5c5fd4117aae29a84cb939f0f6197244cfb9dc532907ee2a6dc516370b1762c48133f5a733f7a4706064ceafb42b421be30ddcc4cefe65b981bbe0be9e326d884fbe0d7c1c25b24ab610830d7cee0a524f6de7b57e6aa4ad81fffbecff4ce376e5500397634bae1d93c68d1b9e062e9d4efa13cfa0611349f7ca83e40c7c9410724e976fd4c5941a696660e4e94b2252ccad0c6cbcbe9c734ceb924a9aa3b9487e821b9ea39c200619585189227d6d53236d0c671e59694a2d0656638ab9c9ae114134b00431c2c089b098f64352cc3e18f88f16169479ab4d8e91408c2f302aef87d2ccb92d6e9404de8517f80aa9dee3b9f1235d606c94e609e5f5e29ae4029b73cd6d4cd828114f13630bdca9f10c95a216626881510b651d923784329d2cb0164310125c628658e0748a3997a8a0235ffd735760b29fda6ef2743926252b701f2aed2c998a355e57818da59134354becd1392a303a07d3f9da3b2429b11a6953e0c2c7ff3a6a6ecaa954234d0a9c950c49a7ccbc4446a2c0059d114385b4af13d51a696b218801052ed365ccb81e47984fe0b2b86aba31218244538e14d810410c27703a66a769319926b0a33d3f54d289099c6b6b277dea2cc325303176895e9126253022b609ed96df22799e04fe235b4e503b2652be91c0a5da65151162e63ca523f0f6499d5263954da79206621881cd74559335bc7b3f5223cdb010a3086c5ace7fb7691a3452fb8d3b33821844e04352a9e933aa246b085c4a7731e9979043525c084cfed1e29152a74d9fad915670e4c061e30c023182c06afddff5be8554c2d222030ec84004baf8e2040f68c08c19ef89860abc701578c176851840e02387b5c6d5fed1efb161e302c609317ec0a59b6c95b4e9bc9bef183ee0eabff7278d27460f38d339692d57a8a044bb80183ce04d73e59113a4694b290d2b7a88b103463d3b2fc92b0fbb910ef84c32e68831b988a63a07fc6bce5477fb49e4d662e080338f9c5493f73760e409adced33f1862d880039c08cf9b25e97bec3e158cecf15477f5a5af4605233f6ad67442648af6145c060dd994b6ce501353b01edbc264d2e9631d96825196ddad4a65fff6470a3e68d2ae4e3712832419551b05ef31d7c79052ca8f1aab91562307172b30d645a30c5170a9628c1d42893a335d8db44caa38b6033242c1574a224529710d3223a0e03ca449572363b02ffd27f810ddd5d77c927d9072514c8b0c38c0bbf8220519b8fb820c4fb0994b748a87529f773a199d6092f0fba821d489dcd5066470821beda5bdffe287fd65a12063138cfab497fd2fc752d76568824d21fd6eb5780e299a8c4cb041bbc44bb2490626f8bf20e4e4d23b694bc4041997e0fc3b8752d7cfb5ce58a212ec45d7915ae973ccdfcba0047b27c4d742f2c89804fbaa27d126e73224c17f8dbd28cfcf2163908c48305a2a5f8f4e823e2a03125cacf348224ddc2ec87804bb7efb5927e9e4b9ef0826fa9b66cbbe89a7f346706bd9e79a274670275f456d1cb9d79d5d04f717ab4aa915c16529a5cc3b79ca5ad944f049e93a11dbdc537244f05555715b63a52c113d04679f4fd4784ac92b260dc19e7a89ff1d3b3db68560624413797dc44ea247083e272539550461f69a41702129e5a9b7b1bf4e10bc650a2a684fd5039c2023105c7894689faaad363f37640082af3e15f33af687468e147c91e60f6cd75a249d5367b3f2981fb8cc1941c4d5f4411fa5566b5bf36b5c1c4f34bef01b5fe05824c8e0039f2b55ae05197b40aded84f25e53da480603197a60edc5f4b49d87a4cf3379487b9bb4ef3c92aea3810c3c305a53e4a9ac216e6db0469a17ed5d2075818c3bf096d3856429febb586d59906107f66a74529d3585a424c70b1975e03ce4f3b428f21a8932e8c0765f2a33515a3f9ad648f3c2067216b8c998039719d6d9e46a726074f342551c292a6e70780964c48153aa72678e1fd93c66ec0a32e0c09a0875a5335310163926e374c173bdafe3062e89147c9372977c226d603de22515c911e375cf062ec8f83942eef1d0a0b30626f88e760941d6e566d5c09d4649232ff4594cc934f05d2aa297ba0822f468e05cd2441749f2abd233b0e9af36f456e4aa57ccc0e7a9feab495f414e481978d33962b628f53e3224039b33e62c495a8b0ce518380d316ed5e8ee754a254186183820230cec6d8b16111fa920030c9cd20d79a695a1fd5f20c8f80217f2b95712ea933686d0f0027b1a3e3182b264e0ae0b8c12215510dae45c60359dc817af94b6c0e8a79c1bb5d4f77aa405de5cdb74446ada484159e0765fc732af57e70e6181bbfb492b5a934e10cf15d8d4ea262ae5ea50aab502174be68d21a8282ae25a054e0615d5be4f757fe7cc9821830a7ca84fc1c44598104a3a05b65b35f6a4cea14d4c2970e3253b8ddb8b484a13053642b45819dc4424cb4081dfcc1e2a8ebb2425234fb82f67ee04eead83762a4fd9bc824d6024e75869344529e5392694efb3658d29a42c81db10aa4fb608b5053294c0d6ededa72f51d1b93256909104fe5350a1a35208a9420709ac67b869485abaceeb2338d691d35ea669047ed4ffc9319d9c31e32c0e328ac0b85f36ddd490085c7f705bdfdd5279913104fee45e0e35bdb0b31b0d3284c069845c55d922230849ad749dec723287175c68e0466f607b200308ecc4aca53f758a3925f90363704b63e6dd1753b620c30736c368c8e841c9e0017bf162d555b56ffea406942063079c576b281d7453788f3366b4e0460e2f3c083274c06a66cc3984a0e1a6fa1164e4a0dc7e3175ff8e051938b0b345634e704d31fb1b6c29659b670649deaeb962c84f8b20c49b820c1bf09ab531638990242765041935e0b209194b8aa56c70c181e43366e0281cc8a001972a7808edaca79de41fb3e084243522869cee8490f990056b23729b50e1971c7cc482512958127d13359b5748830f58a0ef6a820aaa57d493b49a3ccb1e4d57b062a7720a3ab5db0a45957a48c242061964057b3a66cc1fdfa4986a6f7cc102fec286aee224355228212fbeaf0a540a75de49fb099954e03f298f28212accb415c93ae8ebd66e9080d8ad59093e4ec1a78ed0a31282d0112153707b766934c54e29188f144b7e1c99b4a73429b80dcb2958688ba697320a46e9fc60f92a9ed3591fa2e094c79f9433fb72d3130a56744e4a59e6a0d1e20414dc79a83e0fda8f4f1462b28db1fcdbdaac91863a840f4fdcd9ad734d35937a1df8e8c47d7082ed3ed11925d5fbbbffb10956c5f24788e62e2ab626d89cda749490d68f4cf031a78da619417aeeeb295070021fa021801b7c6082d3a172723b9d3ab1342e6ed820c11962fab804671da3c6eca492363dd6489b3163c68c0e68b1851612c08002dc1b90fc4af161092e5432f5ddd6a07f3c3492175cbcb1c0d3096cdc6840f2828b06ac81e2a3124c3aaf9843997f8e9bfda0046ff6edfaabd19304f524f8714dfde9dd2aa693241811c5837787de3d8f44824d31b9566ae7cfbaf003126c2ea5520ee54978883e8271cf9e2cd3bf594efa8723b832fff8fed9f4d108f6745a8d765c8b91941f8ce07227b73f09f93a7ef063119c8668ca4c89a24ead0f45b031f55b5626a5f9d6fc48041b64c829e59cb4acaf43b6f0810846e555d08fa1ea53c80fc16e4e272187e8c3106cade68e8a26f4c4d41f85e0b3a6ca9244559b90dd072158cd49f976f613fa921f8360b527dae9d54b3db9fa1004db16d4494c8baffdf98f40f0e1c9e4269deb0720186dadbd1d524c117ddb2f3efec0a80d322c5e103d513f303e29650e1d7699bcac83c1471fb8b8d7975797e927311a7ea38fe10337d69de4988a8468e11e78afa0df752ff8a107ae23951069554bfde9e0f8c8036f1f2b92f094f4c64e1b5d9032047ce081efca6b394dcfc23bfd710756cb4d6f527f69418ee6c30e5c52634adde8e8764ca903636d52cf723a912fda0f3af0312499f39afe1f7360443a2d3f21ed36c6fc871cf8afa064b2ace79dcef2110776829d483929992a09990f38302a26a1e3e8c9b13ac67cbc8151dd793ae712a279ff0f37f021ae96c689e2973c79818f36b062ff914c722af92967cb123ed8c0fe27fd1b542acb7c9f123ed6c0c9d8a984d20c491c5cac171f6ae0fa4d997e0abdcf7da6c166d4f840032f9a9521585ac82dffe30cdcc99824050fd10f33701e296f44cdf6471958eda02455068f9653f0830caca4d8c9d5c61f037e8881099af268efcd787dfb4718d89c967b9f2fb5ed8a3ec0c0e7a0524a8a9b4654ce7d7c81cfec761df32e5161faf0026feafea22eb21f5d60cc3f075315838841eb35d2f04a0d3eb890a6a45649e70d8eae912ff8d802efef9a4ce87e2c65f91a6938b8282df8d00267e95e35d384605b1678ddcb11fa29c898597917366ed0c002ab959b4b42eeed3ca181830bc2828f2b7039989652d32935d2f0c30a8cb0cbfadb552724c96ba4e1e81af751052e26f389969ade23bd393ea8c0a99c838be7f4a9c24a16828f295c7d4881539ffe63786f28f01105c6b5cefb92e9943bfe8002e7aba669924ccbf59c65c2c713780972926f50c92685c8096ca520d4468914dc6296081f4de0ececedcc474a0e8f0be183097ce50b3afd268b153f3880f0b1044e54b99907e996dbb4317c288153f25ce28d6b08258307868f24f01394298d6216eb24db850f24704974344fc1f25d2afbe3089c9d7b56a8a7f248b9113849933798e5ca471118a51db47eae8e296e0c143e88c0462e2d42771aad1ffd6bc2c7103895835d8ed61b5397324008fcf7557592a3a2dc844a193e82c0e8ed52f23d8af85b3a0c1f40606f54cec1e266d3d3e7fd80310f26477f1041552f1f70935f538af8d9470f88de1953cd552cab32b6c7f01c644a2aad91f67ee3cee40a3e78c0beb678a50ea6c55fb4032e551295830c2a4a2cb50ed8108fa2b565c9d19e02143803906f60c68c1933707861e32307bc85a45719f69124c4940b1f386063d6179d379fcc6a9d0ca4143e6ec0fa96fe98a23fb796f861035ea4a80fe22afaa8011f16aae3ba994c42947af8a0011b928520ae51fc63d299055fe7aa5e2a043bb1943b78c88211a637c87a3b8b6beaf400128b42a98d31e8178f153c60c177e8535afe1921063d7905a752b44eca21befe8ece156c0e52fbce621c25540c034660b246ea4d3ddfd6eb8bc0d9e438923de514ab9e08dc55bceb9359a6213f04467b7fc8dcf974d0bb10124a973e08bcd65f32ede974aa4060358a12aad631acfc01db5bd9da366cb3877cc0dd081935633c1573ba075c44d752625a76223c60bbdb2bfba885d276c0be08116c475d94d4ea8037e91fff4348b12d25079c1275e341e898f7c5019baafdb5d2ed4e94dc80094a8688faa7367fd006fc8e8b0879a38abed48051a35bd9399632b402d080514987fc591b29f7b3e072c71169b34f845616acd768659094c782334d4987da0e0bde4d4f92a04fc96bd32bd8db20fb3a23858b5cc1c65115720e21d3d256306e4944922521c81c6205ff12ad5acf4c4d735661b2e0aaa9fe2655f09e7f6df487a454b0112fa994dd3c882c49a86054cc1e32675db749d22998ece1a7b326b72c319982f5b8a9a28fe54bafa352302a640549dbe2dd3a22053fcaf49b0a32e42073340aced33f9b3ca5ee4b098982b3e0b14a864877a38442c149d09031e974b92642a0e0c736c5fc63a15f1ff409eed426a6679ac674234f70597db5bcfb62451a3bc185a8ee649ba29e082758f3ee64ff7b3a68bd092ee55431b5e8e4f94d4db019fdd3645e6a4f4d2638f59758ba2ca9fd10136c0e6e962aa86a3ad9253879273f830a5132a7902538b7aae41f9a45f44ab09f16646fc85322bd9634b7ae3e097ee3faebe9cffb133f9260527e3a2d6a234acc23c175d61c2dcfb4165a487015761f43c8a052c4a047f0174476915b11a3ba8e6037e6760d2286598c368293f43ee249533a9711ac9e5a456c11a96d2e82ff4a4205957e2ad75404a74ac6dd74ffa85f2682913104d1a33aa2990c22f8daa04ee792f9c6c2738833ea7bc7102891b1f772af5308c6ef53e9484944ca09c1760c4aa8d1f126c02018a55df42475775abd092008cee4673a61fe23e4a809100836bf490d299dd4baa0260020b83eef0d162d2c784e13e00f9c68eec578e9cb33dd04f00313f226dfa46356fa7a1d40803e70fdaae555793d8a960f7ca89c83c8a7ddbfee1ed8533a2664ff27c9ab1e182b8d225cbf4d4c9a07269e59b020647b87140f8c502a478a3596fdd33bb0218ae6ffdcf4aba71df87fdb10849e75607469124ae7ad9c7d3af0a92798a64f4977690e5cd0294ab6502b21c6c8811bdb507a648d3e691cf851b5a3e3a83c2584032333d3a95fe40d6c599239ed836ee054ccf27b450c53b10d8c46cfa4bb535e8e1f1bf8f4c9a37e1b9244afd7c0ad5e4e509e1af8b48dbdbb9252779706ae425c2de88b896b8d06fef365c59c381e72aacfc086dc78d994a87863b51958fd98eb4fbf5344be0c9c9b4e4fe6fd92813753e331df6fde7d770c8ce7a9241649589eec8a81c99fe65a22dd30f07e2295debed62475c1c07632f97f7fba5d93fb052e6e9eaea02c45af5c2f70be25bf53ba0ddd97ed026fa6f7d2225ab0bb2c17b8b4e69daa73251d25bb0526b59b97855467fead16b8cccc9723699294b4cd02af31fa885930192fb558e073e8eb9ca87fbafd15b8ac29079dc5ad2e7b2b30229e43b036e9fdf12af0df1dec6490ac224a546033849482f9a46c6a4a3d8d9b72ab921478d39bb3461b09ea465160db4fd53ed8a649395060b37c54f0c8392ba69fc089144aec4bc809ecba68f8abfdff649bc09d90e857f1e4df4799c0a88adfbde5934a2f4be0fc42e5de88d257224a606cd773b0d34147962481cb4f2aa2aa4dc5844860f4a5dff020fcb67447e0f45a963693a4533d3502e7172632fb7cb3e6b4084cd0542d2aaffba54d89f07b4abca0623f0436598aa2eb34a488bb10b8917ac1f4aa53043d089c85a85dc27320b0eb5b17cd6bb3b9e807ecaaa94b0cdeff29f201df22a3c9c8d9267fa807bc5e92d57f5726f38707ac8a4e9a4209ff08393be0f488a42dd557c8bf75c004616aa7195295da39e0324b1635ca2cb969098003d6c6a4e8e9ec66eb12e0066c90b4b6b6173b882c016cc056b0983ea5a8854509500376cc2f5945ca909f24000df824c382e6537b92ca59709ddfa53b424a7e1759b076a6b641c60c522bb160537373b5a5dab44ac28271ef60b28469935992af602bfa75bafd75c82d5dc19767325532877c3995ade064a41cfa3cd5534a252bd82832e56e92af828ff77f27732d784852056726fdad3e948e3f4a05639bf756648aa71ea182cde5162258c58b203a059f47f209a5644a326f53b057693de7c71cdee952b041e5181e942865272505ab19644753fb9c951c05ab9e7b629be40e188028f813e969292d9a90985070f9b369b3112aba33a0605df3080de9ad82b27c820d9ea2acbcc4ed2a9ee044e3998a1576824ba52767df585fae71823b4def29a538b6fb26386df17b4f838d95ca6882179d420a3287ce142d93894e49ddf7cd31c18810fd4bfee8a5892ec14634f330f75882d5887942eeb7128c58048fda796b2f4b09d64b42889663b77b26c1f6ada5e7ae24f5488251da368904275cafa4e45ff59c16487035bad56b928f607f37a7183db9a4be388213b2bbc472d48c498de0f2ef5a2df3525c0923389d2ac4f4b499b4bd4570a579d3798cd1f46e8ae0bf2fc6cfd024a94f04134f5d4cc92cf305218249e199cba2e6113987e0437f4fcadbcf905531047f52624816c5358d5e08c69274fdcf55999a44083e95a70f593364af67105ce6da82e0b296ce9cd492403021e8da8b360920d820f9435dfa482195e40fac961a651994702d11e2076e74aa3269e5153b47fac08a12cacf54be897d113e70faea6a748708d1f13d70da293394e4e49a263d70d9572b4d06397ea53cf0ba397a7b42dea04a78e0255be5a6e5fd7fe80e4c7c5f4d13f3b8396407fef692a759882d1eaa03ab55c2237be8c046fdfb1c648890b4670e5cfaece6e37127e7550e5c921d446853d58b6b1cb8c929489cb89722513870912708cd19a2e4ade01bf894e9bfb265ee0626a8a50b12b462d0126c03972a752911dcad830ed9c0af7f3c0f31e5f59ce11ab8ec987b29c343c8ba1a38fdb739bf47358ba932810fd020c100d2c09659ba9037d9b77fd0c0a88c1c84ec4dc163e70c6cbacba944e47676d70c4cfcfc94acc192d4b60c5cbccdf849cc92a62819d8bdec185449ddbb730c6c4a691e1273c8184d31704a2b881034ab4ac78481ddea949426ffd5b380810b1e3d8bc48e6842f805be4b822a617b810d6d3a5a43e78917ec029bd449cd1e6348ae8f0b6cc564a62fb40546a50b6943c94f0b40184016d858395c6428a1165387055eaf45555cd7d45777052697c7ee4f1983bb6f0546a89b8a14325ee8be0a5c341d4beaca2df26e546034d9d88754973aee53e0b54308b9a69b774752e03c6ccbe2e6f5e09e28f0d1ca74a6fa483a7aa0603372004fe0b3ed56d079438a41ea047e937abcba4e96f45e9ac04f2e254547caa55e6502e7d9efd746dbac93b6047e4350358f9272168b2981c9196a2f51f34a12b124dc5929a8a44c6848602c990613f61ad2373b029fafd6f92a42cc296404f63b6e124ae494497e8ac05f87b2e021a6a63d4418c0106c86090620044647b030192369d6741058fb1e151d2d6e9206022f4a74fc983b6e08fb078c48e2f53d9a6f93d6075cfe911ab3d268d5b607bc9a0c5db595079caa0afe41f6968cef809131bcdd2c7e854cea80ed986e25541c5d269303de2f8ffe18623a6d161cb039fde37a5ad0a32637e0f7b73f834a9d43fa6cc0c9f7cd394ac6b425ab01b79b7a5574a6d8e901d08011ebb4ff2131df320b269d5abf0c9a6a4177a11690210b26554822a5309142751f0bb6ededaa72c5b0711d169cdf7755f06841a8ca79057ba2927e4ac2e30a3e7de6f2fe2b916de956b063aa6962bcb4b7cab082f532939e2d5d7bcaaf82932cc1335a44ffdb8a2a028daea8b4b065e2481c0e0643c150300c86e193d305f31308001838268e4582c188a0c9c27c140005462c344e3c2c121c2222101a87832261181c08048461302818080302c140201c0c0fcb0a3d0f70ba8f5f491016d864f976f89f9f6cc6117429941c168278c0b9b07d0815e404de0c45821520e670e1e5139aceb8b6510afd64fcfb39e4ce9fbb2013ec291e18f7c24987cb2b154ec964de2daae97b54239ed0ad7351dc81fbde55ba856e92bb72ffbb4b17c79a275646910142c82f341eaa41b97b68e27ac682828f1c8ed83a29f60620933f7c98077ff8c5c23660953125fc191e84fbe020fecf5a5be93f0b2486d02df86a78cc77b6b8e483bdd94b2bd69876c18ea9c3e9b8bfba31ecae906f3034c80c7a060782f402fb1d7c662be5a09df06fa80eac0bcd3aae9906d46562c1d45d0c3f2365681b6c0181b3efa37c48116e0115b0e65eb8022fc6863fe4a0d763f8b5de50f777e8caca8096f7719c8de7cc137b751e9237f21e3cb55f4d48255409658606a28d3c6a5412880d5143821c3e4bbafbc486aec342c3dd306a78126e0943c014bfdf2fd9ffbc768945ee80761076b837d7b9864e17dc05fc42e2a17a082bb419ea09417942cfc88b78ac3db41025e402cd790bef83b7f570dd4f45ca0b35c1c20e81b9503d647a987a15f4198c099742e804a3b7063ce5b68c772b397239073d8303417a81d3ce2f0b9484a6c08f50cbb5f9557c4a2e5edb70cee08a250e1e1d374c4933347bc6402890220472ac522af9fdd060527b71f1474ca16e3143847d0023a34a28333400f989c245b4c8f72f13320909325cc1b101a820efbc43c2d5a4655adf62fdfc53d0f5b676af1c79cfd00bfe584299a141e82fa41eaa87cc1aeccf08436b9da1e03067d8273c02a7287f9a631cf4bf3f725e3cf5cfc5a076eaac93f035292c16b610ca441f2f119c84a661ab00cc102774121209354308a15dc876c2bf01dc48c5f7512f285ee09a81af08882f2eb120a570cf3f5ac4e9a94703e96d4c5ff2c32cec270550797e4294904b8893a0065426c1af2b1c83ec1fb8460349ff27e0a12b72a9f95304a5fbc2d961f4a20629415cc068e654e214fdb546c9c891cee1cca69d54c4a07118669813ce09e1de0915941c0ce00fc382eba0d3a06cb01a44014e82766a5c03693bfcd7112c0272d12f62eea86ff4ba7b6fbec6b15e309a31356a6562f1ae8badfb56acadcd8aacd5cc747f2f97081490c712fa1c5f8a39ee7d7220591a2265feb4b715eb5f0e2ab1021add3c48f29fa4b4f451ff77bb3c8e8c08701c73b9772e720a97b8b690712a86b69c3875324825807cf72b681be8888ad73b25e053ec152aa72a4f20447dd9e25f5c4f910f5f588d9d391373a491bd0f4807514725378a640fb1cd88b9917cf0329a302a1ba8b535dba013232201cf5a5b87e2974edb1eed80a2aad8f699e8aee1773c94cf5df2063acc00c022b9b900db54fb2fb96be32f8bc82d66c77e572182a8c777095db6e84879f0c1c4b91fe6443a4ad5e4722d66fce13534d8d5ca091de539a65b59985e316c2a8cae81fbcd2ab326f80100310aafd155cb3bdcb99ad4ed9a9cc445b593f849c592be9de4ad3ae91a3ce030e74ad4a5e55c39d6b5faf9597614b79322e58f91828ee657da92d9531ffd93648bbd4a812cbfe527ba142e6b4ed819d968642400a1d9e8150b031e7653e983d2209e94f8ca91f889e33ff6f624ae3989c830eeed45ef2dba9d90422194841513e6a2d06942a515724111cab1d812ff6057560d02cf3f4a90b1ec6bb134bf5bd0732520061c29e3113b1bc40f61607a7a08c1848c4aa153b27c708c8aba0d9dbc9f713e81d7ca9032d8af3396d032ac59ec61a1340280c58d192117ea89176d1b7b498168928e093ce7eba743e3ddbadb95acadfb5ed98da9af6ef7a3db279ce88a6a7e6af10cc06cdd5f2c32456c144ece54c0cc9190028d80926471a24623796b91389ed04f6c6f566d0e16ddcc8959a5fe8e509032ed539b38d83c9c803d6dd24db586f08fa8f2eafdacc79eae9d06860c42e295e0d05bae40b3e46b314daf094539bf80180c0ba573ba1835ce2964cac961a85e3c580c5feda6dbcaa94b5ef2850c357302fc11dcffec3860800fca504e407b72fd923b7cb1da25148ac503fc90d4b3b4e0464ff9ea0dcfd58dce9ee043c6f49b1ee0c1e9239c8c5a547805f3d4504601493944bcf9307907d60182d40802b9a1feb9638a14165650c081d046848e0811270465a18a423908f9115236217d0a9cde4f16ff327c68710f33dcbbd31c94af58edd4686cefffe637aefe4b6a405483c7499cc2e07035820a26473d083cee6b561c953d1a211529e8d3ebe7407ad73fd316328e48918d144de870ac3221ba37b63165834b3125ffeef762e3434340140c7273b808311b62dd835191475fcf0f3aa7c5aef663dbf6b955b3308e298e85e3acea2ec7bd46a2f949d805b6492bfc63818d05a83342614185ae81061a9a299a2851a5aa490088d80cae64deaffe05217fe3b47893f8664bb16c2835e803e8e9d1f3927aa60a5aae012d3c5751a50295019481192141219ca4ae09b6469bcb85f67ade63210000e10b4c56ad48c66aec4a5b1575b37196a23dceccd8811d41571ec328ae81eca57a7dabe1a4f635b5a10905ac8b32611af6ec7c027d574a090559633b95de2ece656234bf422f2f9621e535a6e3940b322791f5f99c4ada6ea2e1ec3e5b4e715a660a646a68faf9cdb92f5b36dd7d602bcbe6cf4390bd87626a1618c7d9751a3f40a926835c23d525905d5d5be3b9ad2c6d8d02256d755f6692f0f710c054064598e0df5d47e94192eda34b7c1603c8732d6deeed3e9efc0ffbaea61e78ecfd22a2214e25ce8150096d90ca5296849ab31629926554339c101dd6f88160be726314416170260887ee0f4834dd18684c104d2fdaaa53e351d64c034a730af7c3d3c8ba64a11d6c121aaab4919fa90994ae1d7443dc4b69dbd7daa9054592532b53c10e36207650e0630c1776d9fde6ed60a97a248e40f4a42ee555341d860e64a3d13955da00c5b9eb23d732a908474ad49d80f2b0d767f813add37042b30ce9dcf8eaac7d7f82f1100cbc123cc06206fd97e78d155decae172ae58a8f6decc3103587d4d0cdbc87722ad7f9129bb66ba0954f4649f4e224c362b9e31fa9f88538d8c39d3051d2b68475da531fc0094ebd60c52ac2e38170526fc4464d64cd387fcbd677f3ad0cf71031c179b0a5a1ca049b86bdfc1b55b8d926340e1e42c7e6d3f9c345f84ea7e75d7f9247f8e116d9099db5cb9d53ad727af78fe0347643149152c5e665b8b402a76cb87ece60107201bcccfea7e5df35d6ae7f075186a3531c667295af6ed3fad1e528325c56f5dab99cbb470d78c502bc7c43a63199b0b8c573ba3a3b6669dd25074bfd4e3e6b6241135cf710f0a496b9d9fa1f89d68504cf65da483262183aa10a9080a7f95c62ab7743b55754495ca2361141f35b27d13b898d4fe498819789574301584fff2be37d434f7dbe30ab11d8f603c4648e2a1c5e36ba86d0252a504ce2408cba2e9338bf0791b6d2c2a9af4da5d051c906d5b2f9e86cfe91abdb7ff281adf8f188dc48c15624d70f908f33d9d7e288797b41b5846f0dafa65b4bc8d81653346ebfa19f3cfec6e3c743c8306255eb6b4addecd55feb25392f55597f20db544e1dfd3260d71cb5d44563c657a365e580bf8df1f9fb3383ff4d1923012272d67427be0d275922c2da74581c7ca846600397a2e58ac1548343cb0b75d07a946ce2ca9f2cd5fcb7d3c642b1bbc4a9890a6e16093d3cc641443b7464584612baf3bc824341458ad8e02dab48a833d4b6bc32822a4c17e03ed5c4b0fc9cbb95968acadf06880ac2c6b14492faefa1769b704c89b202b27f93d3d2c675951c6f32f07d9f96718d55285f25be7973aa2adc73aa46587cd51353b1f17b3f2f5279aa86210b5a9c3b18bd4fc878020f0d2ded14f6011188453b857bff2161ba5a6c73040350dcac56f6a0611917619bd9ad03a4ab53ac8e737b327a2fcb86e38ada87f115058f64b4fcf2798fc10e690bdb636c2adcf0355b28b9b09110c19455d8aa6d7121b28d76797d2cc6ea797dab4b87c376127b7167d51d2dea67d7f288b4d10442a9a817140106ae9e3ad25041c94e40cabd467172548b8e5190b67346aaae4ab45253f2aa68cf3104d3982c2912e086d4681bc55984be9b8d2e578e69a8b2364dc8c56a038cc7d7783b5f67493afa521eaea6092d4b764854f9946100ddf67b775b42cc84245dfd1152893d2d11a3a28c42d52a72fcb1a833654a8a548d5854e725d4c09611b9f77b0356fbf4cd4aabe061134a0247667b231855219b21d394e66a3a8fc3b8d330aa1c60fab3379f1a93d3c2323c2369da8493e746af60547391ad642ca084c4cf179cadf35ea3495c2694ddb220395bfda006f6e31119c7e02d0d66cada4dade822b09ee8601c3a8d0867b09b7a3155749df05fa874d12ce557e3c9f9fb2518c31a1e86686e597e20a72b5a3931883fe62671244b3ebba5f291dbefb72fc9190ccb37016c40dcb635ceb0587a3758a6a3cd6543d5182f1982f0347fc3da6c69bde2b636f27cea1a4fe6d8cca77e0a54e961bb4a01164223862dd4181010e353d3ac76c414c3d2ba574f8a12e4d0da148bc0fbdf07f41f85b2cb699ea24c5ce5e8e9d0ec10cdcefae347e3c4f2dc7e1d36e182f5c3539a68c01c94a2d2616c626236b221ff9280f9840b299b1dbddfce77080029fccecdc0ca27826ecf4a2d2463ba44f33e3ab6069f4420ef133784a51e4c966cc107274824dd62d0caccb80b936b01dc483035a216c6c4a3c88274d5a2179f93c3c06b42c1a44249a90c60de23bc4314f3b316a0b0fa55568f668a8aecf609d501e29e9277aec0df93c809f9638c40d766a7efa69528bc9d140d52a9b453c939f6571c095113098ac0f2001c41968da1529510d14f915c25bb1a416e5de4fc818d5769f94a55746ce3b499e2199309f965543ea3a25cc87d35d8aa2e8528e878f0ab7bf9eb488947eb87551dee5515f45554a98d2edca78186a4127ff35ffe5b4650e75d940c2efa3f9da2572afac1bd884f1a87a6ca08cef4d44a065392a0264612ff45c229b3818c49a86d28f9ed3acc37400a2aa010450f186d58b103029dfc21d456be086c0f4d8aa5c8f75d79209c419c3a92dba7af37604205779f82885c043791c7ab58cfc4e5686fe831e62cc821d84a7a992d3dfd1f5528c0be028cc66a8d13b58b59a959639e428cf79b244e13b0143ca6c568e55000a3eab6220ae32552799f898ba569dafbfca371507e0799f2a873f1b8590dbfe9104d72f481b53e1264eaf7d617691560a823feb120806f0c38bd6f81d6b029e9fb0fcf1be4c6e8cb494f8ee4894ae4de48857a17a64ef09a06160b6a3cfd373f8b0564f6e364625a9f698e29c4770d7e58aca888c1d351af4496ecfb33ce83a385656ab9cfd8250d6171474f91b92a3a9f57312493ee2f895f6d2b591cb849ca9c4ddd2ea73e29dfc7a3cd7e70a9b08a601ca7f4efc11b1ee83965cfd819e3323459c45ee23bfb0914bf361928412b0956a130d3faff8a0a135eb985c1f0c2847f1a0dc1160072b506076f8c347a7381852e0083ae2989217dc6b735946d5e6bc029041e780d9d72b757e506cd4e08f5c7640c65c997ff331ca9a0585f63b76c38715f5dd4f15c82ad2e68e1e450d5ce7ac2df7d175fc65a0158dcd02dff4565d8ac24ceeaf885458782c7cdbe78407d742c099b77d4c3a3405b58223959807db53f9a3e62d9c1ecbe31fad605cfdd4778bddf4a4a8cc8eb5b4bfcd18880d8407bc56ed43367b6e37332ec8b9b293d5abd92aed8ecb341c526874dfb6d3ada44b409caa6924df96d72daa46893cfa61d9b3cec66cc096d72e42e2721e7ccc2ab7d88e336333af546f03374c357f152153c391abc353c518c94055d0fa1c072bc965cefc95e1c6471578def335f1a371d63f62217f7423ffa45e36d678c97c265598ee00701a19636308103c6bfb6bd220e5d7b71bcf61d3e83f1efc7cf9169ba9330c7a6330cfdc88404af186a05be6e90e38524a116786b4585acbd4026c64ccd092acdcad81640469df7fb0c38d690a107e1cf7a305e41fbfda779e4aa5a3cf11d3f0cf208d4a2d4676e2d123be85a9b62dfc6205ee359cc382ab5dde4ed6dc08fd39666181df734747610c207b2d71158fe8e75b64ac8de9528ef107d27ee5bdb83d88d6c328de948c0d92b9949b6c8e4b0ddd6662041da419b333240515dd66718226336a9728fb205414515bacda8e0e8888833465108b42a7da409b4faa1f4da78b611c31ea4d42fcb76736363e651c0ec1a097d47561b581ac3f580378ac39db31f9eb50cc7978e8a95c76dc702a4f83032a80f3721119e1a5c15aaac7379272073e52cc7079aa5638e3b0eb673c46c6031a58323be060cc195b388f0e45b1afc45e0df96f3ea6e2a955d97a47343e62ad193f6391301541db3ba6301b3faa16466351582d9444e695a5d178ce842a6bd6f7a92507c2f9243a3425df218082be8ec18f288384d2e073ecb93a87212bcacc7f4bd470f2ff7a4aa70597f52b4812cdb4ce79298246b2a6ac9b1114db1674b65f44012c6e204b51476eeb1879683190667d6e73a00158102033024595516da4def680cc36dda08f18113e6abf6124ca84915a7a810125d4bd0b78316ce44c95200b0f154699820411dcaf534c49b214ba6a218b991be40ab3b5e383db51972fa382deb818902d46f16ccaa034dbd26601fc97e33b5b536570db41eb00dea66509be6dbf65fddccb36194bf20b4cc371e0a080969f0fd65060bf0e64ffa3928e36ef5fd246cbce35539384836efd3d5ca23c473ebcdae16a36878f3cb06abe378975d565e0390c76bb50065d890dbd386d07a044f6354f9272812b4eca08bd9365b47b1be49de0e3b3886f16cf314641ffc15fc508f46efa923a094f3a8bc375bef412450298879b4d748677208e45769e5c8992e75a1f5642b2aad4d544bf02a72efd5d55e7ddd022f8b0909962a9b16600607cb0edfdbaa4b005b6a2468d51549d2cc3ae5764747baf8fa223eefb5e73fb886bb6b4137f7368b34a78fd16ac34eea55d574c339c0b9b48e37acb522f50dd37859a2573afffdd9664864ad496e8bdba7da1b36bfc3b626c5d212210360872760727ef30da783335fe8b1737c41017bb00ee45401ca59b5cc4eb9e92153326314b4469b3556eab840fd0c21e8ed94afc1585c2b84d973d007ac707ccfa198b0e02a4f1858a10a54a08fe0c67c9d61c280cb6a0b72649f15b6ba258e1b2ca093042dea9c5f46394541633b2ec86a17014d230bc6ecd105b753cbb8cbee3c07b59bb7c800fc0ebaa46f9dc0335ab5c13546de116806b87a2bddac8e24c609c0b6f5f9304197a0db82d6a3a4eb675212685b89d1a64972b656dc9c6b691f30713708628147ecddefc1a18aa860a8adae579c01463f9a362976d069aba9ef7580866639c7481b9ca9933445abfcdc445678839157645b6f9949b0dbedf07447f3b78b9352915dcbdf74ad882ef2c6054bf4d017e90383a1817fe7c9c5bbeb3c7a1976b22874570436d64332500b67a511d6308ccf9f1230493dfd1cd4cd03d3a6cc3ac93e14145b7e368d87ad4fa8b21436071b910215b571658a16647bc7b64e2758ac084821ed9f00122b45dcf4bac0039020299be99987d90443e68be7def628975479732951dcc4ad6b315e19519b3f7eeb329adb56f0af64168e669a8d7ffbf51d49a5e20c3a1abd676e73ea6c0ea9ac04f7cbe3efbc8007f219f69d05deb114d617d0ad815833ba716b12c16467222189bd1102ff13ffc759ead670b5b18868dbdac8a85750fde785e1a23def49794d5621f06f9826b78c9de596cacbffa02fc41a3e0797a160bcac175a710e61ef9e5fa8e3df44590bb2951fe048140cc9afc38a1db64005f3c8bf8006694eb8abaaea883a72ec2b002eb82d5d394c87e29754bd29403913b45c39169d5817400a1f924614cf8573904e5185fb575d2f4ced6d452fb7e8d5086676cb48efac17063a740666f0a2993ae9a816535792355a989eeb3265a1c62dc22de1a4a7648672edff76dac6724b005471ab3f62cb282f46b975eb4097ec61a16b15491a77c17fbd01163f5f219c1df6b953e4ea807edfb3813c1fb4ce69caaebd4693e26089392e6ba5b6ce4c8173220bdb8762ca36d53170f2f1ebc4cea5e71a82a1ae95f4ad34e81d1b01d1484fc24f4e9df436d0c73a204297ec1f716922e77e7d8769c61e94cf51c2ec5da082290d98c83304fb0060bbf7b33abc96cab0ab3117b1bf6b125671e7bf5a6bdcc532752be94c66d0c0090750151f90bdeb24ee63c26f540fe6020cdfc12fe2f9eae2af22a68d70b15ebdc4fe626a6a0de792d8a375e826f45a848181888b855b1b73b213ee52e0843550179e1c0a68c6b44b0ff3c07f309406e75fbe33d904d2c3c940c24281a6a46aced01dff8ff905128a46165688380e0c2d209a4a109b1bda1614a5fe380d4101eaa14780a43602c14358b6567ad16b58007a1a23d433124b0d888c6ca6fb8fb083f403010f3911c06a034c033b82162f797a4f99b7ea3b6a41c00053b4df0b803d0d99132ca704882dd4d20ee014e0de7e708f83e974657f0f6da0f8c8adc6455792fd900e69ecb115f9185c626d200a45851c6ee269deef68858dc0f5309ca795fd5806d6aa533e1d03383b27e1d6b300040f2be852349237d1ac4fe182cd00eb1a5c73155c35ee949e4846f8d95a89c7d556d082427b686b4fa1e5ee01da1a961ea52b7588836b10e6101145db80d327d0584393592bff00c37d0c7b0f6cd9805d1ce70bbdaaaf68c1753477dc7a175ae0a0254471ea334755e8f07104d2733614802d63b2772c7727e22a3d2e369b53f5a8eaff865a68f90844a65f474e0ffed6b9848286a93331f8b57a515b1aac94f4b1c4b75e99a7c5140efdfb2e82d2a4a08adc40b01779ccdedda1a5fe6a4727829a79a5d082742a0771ec88b82813559635d0e758ffe82c80991473f724bc61ab29665c8480e53e4d4bb24ec1da62984b4b7799a3c10a2c9bab4d2be89bd0b971d8af469aacd0673280eab61fef85d8119337f68795f02571822c5606e764a197534e24140636ee8299a2c66b4bc1f019f9aef0a91619cf8258f972182f4f0032c9dbf71834c41905879c655c06dbdc0b4f166f62b38f711c86952943947da12603096f5c51573db48947358515143519087ba37c1c07d6be56312e29414379b8c4e1882f82fc2da19e509e400167febf68daf17409795f045f1b7aa9a09a5c25f7f21e0074921f1fd0d0f7a35dcb91a0e1640aac10c004c131175f4e93fe877897378ee476b417b1d9a682edb8b454f803d681e7df350bf4bd9e082b48ad60e02a032df1586a11a4b4916e19803ac6a0e9b2f2ec24a1e0010f0b3e12d8cc7a97ac360c586bfda0b4487e1ac1f08601acffbc4f291016d0f510368a51eba8b8574ec2184e4eec92c311c486bc1188fce8027434708a46c2c3f21e23c47e5d5a49e9c20448ffe258c98258ca7895d89905580a01ab089161b1942121c3d2d154492e6500c30032b7f1f0734b2f007f97e089e18f657d045c830b8c63b159a62c0e2360a3081bf0668c8ad6004dd9ace0c15601571b14e954c64e65133f07cc87497d7548b2f2f0e484e2e7f795cd067c464686548668f8d81723b8427d8cf85d74ade7e3a1a36cc6d140f73cfba4fa88c2c7df0548762eca7ec398889d69e9440bfd278419e7bf81350c4ccf000f2e83a5e069e2839a6fae4f8faf1f1f24be217e5438456928a1835a9f5d02df7973421512e1c3a6f7712b583ebaf2c02764d7faab2971645037b17731bb2f3d408e4cbe348a730714c7942f01ea9e8187ac4b320e20c24199ed9b549900952562fbd7434579645c1788b96ee5ed4be32339a3135f52b209c90ec0fff9e1e26a908642c74a17b79081190970517153859d2029c148c457c04fe99d3dd1bac1961faf4316f2f30c221a26846cd1b0486802e63df3143f6144555c09349abe3b8521638cc37993c48555ea5f60de1f857bc366d711f17f6890ca5a22fd6ac4f332cbb5ff5ca6a9c1e77c98c06741a34499f44d8c6ae074715a0909283a28637c1f24f5e7381a1293fa8e753d36ed198e9ea70023c3cb8be0e7f7046382b1d38d61b4bbade954f907d3c420066a9cc37c5906bc702693d6f7e9d0666e00cf7d66aaa58d5097c1b63b20e192e11214076b048b7b23c765f3b379a00b0471a5a260aab879057cd630cf0acdaac222a53a9866da61c97841ea67050addf463d95efb1b46b06a21c717624864a23aa2c512c1087530c60549623a53df694afa694df24e9ad93fb6a2b5637a187d9bea30ea90cc0a245215d26bf8cce53497bd00441e1970918924562eaf68b547b0ab63d760205927ba5451acd96d80c51edfc163247c3f0d7fe939c793bcc06601dfa1ddb2274448c3a6279076df8b779753685122d2794a99a2598b14bf2c65b7a1645aaa157a8d002eb3304a59e0412cf8d3f8a08c283ffd9ed82409897e26f5c4828772659ab347e22d7e921a3237b51b16ea134909f332474f7cbb3658a9f57bd4f5e45812aa9767b7683102993db0616192740fab0809566d6fbeec361733b792e475d96b7b26bd2553d603da20f78400fcdb5965fd0505473174ef239cf39407c7fabae2f6662ac2e3ed5f07184584dd223bc8fe908a4ef10182ed367f32da45153e78851d45175cd954598b5263540bc9bc4dd2c14ff169b1d5aab148f0d0777c1c321776f0d5dea17437a111371e9e61bad0aac889c7a93f09693fb519c96b452a7e486fe9184ea4e906a35619ac5fa45ec82e07870f7090cc049ecc624f37516cd9107920635d45641b65b45b4a1ef581807774a49f31104e6971d4c71413156b29b14f39d5fac2180d2e6de38004296f63410232d95ca1c11dc9f5b546423f6e9dd8c6e4bb659b254bcc2482ad9328d1c44384237390af69c2b65413d703c9c9e78d588adc82415b55933a0d42d1dc4e4232039f2d369bb16ab214b2869ef1ff231d7f26ce8456fde1e559af494db7d3df30e3beeca0eee54c180e6c9397894c6afe93330ba25821e23aa9edb29aa939cf10eca3754da50d4c6038edb04adbc05d7638680318f5183cbed609baaf7e3c5bed654fb335ecfd76482a56b98005c10206fd665ab4407a525087a29b3d42e122a45c9e3f743ba6ceedc466a3e86305a39808ca56c04cae69a7a205ee907b72092d4fd889c33e105ed56e485e14bea958ba6f6cecc7cee673cbc84bccddc662c2bdd334752d9d5b1f0ecd19f8e3a01e69f44a27a7ea05e16ca234905d243840303498212a83f9615a984abb1309bc07eb64ca98943818b9de52ecdba481e46d4b64f61d471af7e0c7b0e054be389a8b1b7635c284000085d81684e831b977f0a18532dec98d1883d7561293bb43949408d057815d420fa1462d3b16f417dbd0d94474016c3187d406a14dd9cf2700f21ce0c4dc7d44e8ba2d66c911484b059e29392c845c795f5e319ae10bd6fe2815d6f15787f08118fd6047ce993441f85648e3e44fb802848429e33eb08096d46aaab8807f48ef8e3f79d602445b4c5816b9942fd7075b7336709e2232cda8415e9e224dd891441bf4849f9678362744983b0e2348669bda4206986721d6649afb7817dcc1f6a50f7a411a2241984425887dcc03b83ae5f7ee320f4844dbab088553f4058b2771226037ce7faf4073f0f6800ef4a8d69f73256cb707b152bba4e470d57ce9c142d9f288fecb1e41418f2ddcd5e9e5e4d3bab4a23833d5086bcb4d97e6b549e465cf603643e3a523b48e83b7ea2f3a2d1fa015f2779fe271c6e7efd34ff100048dd842571ab924add6256e142d5ff9f192349151ad215129946e8ac62263165f27cb58d0fce9771b92fac71305d48e56a627c91dd530e6dd2d8dcd4c2a8ce0ffdb1038e75d33e7cfaf85ee3fe31e21ccd5789d53c9c9c8ac0e58456e81ef08203088b04656a2f6c1772158a21602fb5ea06f5b9a85e3d033d9e616343ce928487d5fbb87aacebc0323bcac3b41faadb610aec92a3777686a4f7e9b72d358e7c388055975afdf31f59935d8f17d9019d41cd52a4da3755bcd07dee3829ad370808726e96a7689b34f59f2b93b0331bb068990770b5b7a74abcf79241788ae04de0a3b1225763ceb094535841f5e22a9f26efe845601e7f0fedf8c0fc8c4dcaba9c98a06b8369132df4254de30e5e641ba45ea43acf7c410001e92a8dd1017c4ce3bc09fc4f7ac11769b14e0a86626c7106ec6c498ea7bf3e975eb3d090bea00ea65dd7c91808b0af15221fe364a398b81bc02c4fa6c5976088717eb70603163870be2e2010359a1b18472194128c47782a80255c8b1eb3486a8122aa1a2c80a870b1d24842ed7367245a1177a0a670dc2e9195354056fce67b608ac6dcd930e007c873bd9a3b950b9cb0b634b7fd8ebf2027fbb1e8eece5b82580edc5fe1fb5be43fad4d1c4c235f6b8376124423c2b2ada5cbc80b0a23a3f571d6e9f1dc132c3a6f0c5bf03c5be074ca18c266c9ebcc9da170bbcdbeab38ae09d061c7060f1886d5c6fd292ab2ff6b0724683b17211393e8832ba08d6544a4094ddabffd05cae4206813246f5c6c20d134680dd3a46285810fde053033d8eec23708a709b17218338e15af105d5dc938c2d4c52bcdd903815630bd56ab09e79a1c0b437343d4dab09e282a56f8ca297a8fb409e3eb22c561ca4b9a30e5aa490f90811c5b2718c290d9b4f040df8a3d01e70d4d8a0581103cb713db0d670efbe41ae8dacb2408d2d1987938651a2c2e850f523a642df26a789abe881ae21d07fb17059c355cb0a945840866309e783c5b7590829ebb1363f7d38d0cee8f05c27e102e268d47c7b52f737e0a8f942846c1f1abc1a9ef4a099dc2893f1ca01a0458735765c8c3f08970e59a4a33c3f41b870d23d9d772956e00aac8276152022d503d578927b9a4d0618425d3de94bb6ff87601e68630b21ac07eef95c708b0ce07d90a80dfca2ddf3c7213140cc1568a30596d1bb093fc64f85ee6e68ea7292d435e11ee041e13407c11015a6a07386ff668ef2bc26a7af9467f672845016982dbf37d55f368487ec60853ae288ec3037bbde789fd0102a4b25d120210fee66d60370fa2c5cb6b03832094ca8b7c5db58695a0f55a0e8b80dd9cf61ad05abe543af922d094e8f9bbace9a66b18e8185a2717ba8f94cb303dced1e55cd0ce2740a822a44a71fb5625ed980872cd5af1f126f16f7dee4d591b142ecfc77ee26d8f89b7aa5eb9794dc1b98c7e3e473a04ca094ddc8f92abf9147b9dfc9939a32441ddb816c551eff16163beb5ac283990d0eaede71a5b27803c4e21a3fa87c633242ec80af7d21883296180f29751338d08a21072cf812ad73e699ec72b1f5d7e2c62d44ebd65a7540a0da1c514da27e5ac6d3cf13ff5499c161d86876f49659e7c90043b2324730db637430337939a52f5fc28fa2b870066e3b1053fcc6b80dea7b5a179233b810443514a2bf0b5eeb1f533ce1c9c3397cee5b0f5a3cde27d6db953bdf87a7c99d10d165ebe381fe6829f61f2c60890eb7956218a0d0d6922033f802638d5076bb9489a376b6aa8ac67f25c4280922dcad9819583756eb7714b40b86bb8adfc21bc4268a4f8a1cdf12708080b7b98456eea30a55a6ff8bc5097b9e586382c47db412e438de5bfad90266ee2639c3dc2bedb3a94f9a84dc0b8859014486015382105ae040fc2514ec7802fe4044df0a3760b46439330f0f0f0f0f0f0f0f6f706ba4b6d6368024a49424a9adf153f8ee9029a594648a8433d417ce4cdc86362184d1863fda080d02010bf40ac50ac9f499f2b5ab325cc1873eb19c2fda07c868051b529a92123cf3a59820b00219ac6064bd6b472a993a476d6ce001362820011b5bd880c0183256c1a43e4f3166e855c1c61acb9f53da53c19f680d31c8fc7ef9265430f92ce750ff21afa77b0a268e8a96c73bd8b6ada6e07a77f46be99c25eb2d059362481a6aea99de1e29b8ed9027e4cadd28f8205a9265d09e29658b28f88faf7fb6d9d3a67c2818d3f8666a440c146ceee8b952b0de0b1df904bf25748af61bd2a8c83dc1260b59c53f923e25f24ef0f9647a8db69fa4fecd093ed8a866ad64294a3a6d825162c9dfe228799a9334c197902c5a24277bf55226b88a215a44537f25e208136ce4d0f71f73e275e55c82495a21e85e907973722cc1badec678997542094d25d81d913975ca5ea276a504b739a9c99e96d6f58293e034b7492b957eefc59304a373d25ff59e48f06d25421242de9f881448705192529f839074df23189521287d9e2a6d8a992378492a85a44935b6ed8d606c5c536806d5604284119c34d3bd2d79a47fde8be0840a26b2e45c5322a22a824f1354aede4ba52e272611ec560a22654919e97b47049b738a0abefb15aed14370c13268bbff6032a225c3109c14d1993d665536e11582cfcb9f9d2ea7641082dd2cfa73cca064705707c155f610e99a5434b5a80c41302a7b6be39f84a4ab77b1c3e8588055faa2053bee003202c1081193fbf9aa3db72203106cfa9317539ac4913193f107ee4a4726c30f4c12eb517a55374ef4f481534ae8535dcf49883ac4088380a12351061fbe14f5141a5e3a4765ece1f275d3b496255af0764d20430f2729fa2495b6cf6a870e301cf0001c376e84c1011d1798808dcb01cc41461e4e061e4c9b335a1aef0e8c48cbaf1284251d499b63c781c0160c68c08d1ba87164f941861d72edba183a090bfabd066edcd8a1038c3176dcb8b163c78d1b3a5c0c2efc04376e7419c3860d6263d84036c6172d6807e0d0e16274c18518a70b07dcb8f1858b21c6e9e24b11400c32eac06fd22554acab15931ecf72d482430162635879e15e14d70146ea800c3a3041dae44f8d7539863e073ed6c64b6152f3c80fc981f59c444c1b458e4c37f9e313e8a28b311c1007d6439d44cf312c37e370e0369ed2759d296508a63770c2bf4f3cb6ae471cc97003b7f77f9db263ee48a78c36b0c17c63f9a70f2d1dae2081a12090c1067662b59f8c41d449f30332d6c026e9d95c443019fd35db21430d69cdc135a5e995430b87abe0ec28c5011969606c4dfb6e64730c32d0c05d4a2633a325b520e30c8c9af2717dcde61b649881cb9644fd5f1acbc0c9143f5bfecccb5d2237c820039beede4698f24befa731f039a434e919ba83369535c81003e3be9e3f8fba06adc130f07d26ec5e82fbc43791db820c30f0d69fb55792f294542c878c2ff0232baff6f208870c2f30c1d4b485f4503131c8e802bb49a8532143e9a867c220830b5cf4283107a53c684b627761811b374c05376ee028db838c2df0d9f71b3d564add6b818f29f7c40a53da3cd959e0e249cd8c604158d0278b50be279e2bb0fa95449f2e09c9feb50297525636f7f414f42a70f1541236ba1a29c5a9c0aea9905e9ffadd53700a8cf29ca2c4b558c890023f4a5f27939f4d57d089b1838b09686087efe080b9848c28705e22483b9d37275a1e0aac5b9ff6e54cda4dc99fc0e62611c72d74c6de9dc087bc632da2e926b0aa96eb25242526302a3285ab9bcee8c9b40446869434428852c93fa4045652c81bed6d97174349e02b67b4b43e993de206097cbc48e3e621e608fc85749aa2c734b333023978deb6089c58a848a9b359f24e128111a6eec992a8f5dcfd10f820737da759c960260aa1282a276da7c552818c2070f6616363397dcc07029b2b22ed86d2b92ffb03c6f622e5ec5bdd26293ee0c23f72fc1b0f41a67bc0e7f8554a1649a23b3ce04df379695bab8f15db01373af39bdde4a4a242142043074b126f2d99262707bcfb6637355183034e729217e468ac0e326ec06b72b7aab497954d9561032ea5bc9a9625dd0695caa841b6412b92d438914103aec7473b0b4e7eedc8d49bf290052bde954f23668dec522c18bffc94549f62400a1eb0e0a44790f69af335ad690b1bc40236b6b0412a60630b1b840236b6b0412660630b1b4402362e30011b71f078059354c8316b4816cb84af06011eae60bcb5caf2ae294f9e6d05a739ad24d3525975b783218616f560c517e25b5269d15d8f55f02571729694d23278a8825dcf6717d306a5673b20031db871a30b47810e1d607c9123edb871e375a800061ea9e082ce6f2a29e615edcc0e555470ff1949b54474d4a46a233c4ec1abee6866f28e872918ebd4fbf020ed8292799482bf0a0dba5ba204bdfc48c1c90e161a3125798c82cfd5a33e652d3d9aa31ea2e0f562a5fa1c52a964268f507032db574590b955bdf40005a78334117358baefec797c820d795355ec8b1e4ac9c313ec8590d247f1d31325280f101e9d605490da994da8bcb93225ede0c109369552d1941d3d356463f0d804bb492413dbfc1f3bed9a6025d9e59dd8a273867960f0c804eb6bc18205d1a14665c5e081095427a9f157c97e31868e9580c725f88c3e22c326059d7181c723e47d06cb4be5183a2af15bd8bd9f679b128c8d92b9baae3777d4bf1843076ac063127c0e91458a5bbfee3872ec18230cc22848470c0d6c2567815f053c24c1061f69226ccd4830ae39a4a037dc8404a3e2263565ccce27fcfd82c7231889c1435bef7604b71f6a6b6ff75386c9a3119c4efdaefba57a30820beeda9b97443ce0b108268888a87f168c828722d8a4f4c42da12af7c41c143c12c17d9b56e9b859a445cb0311ac046d77cfdf158eca83c721b890f2cba2ffb628bffa0d1e86e0a4d999f87757082e87c6ce924e242f21941e8460d5d3a59844dac9fb111b049ba2c6cf79d46c33d382e094509bc54ac4f2897904824f4127a154f4e7c8db01c1d7a63a9d628e1172c5a6e0f1072e0909aef9727f52e843e0e107ae3704d11b5f1bf5ad471fd8a0db69d48be9b4343df8c04b0ed3bccb252478ec81cd173be8d254e5d0c2d17d881d142430bab00b00103cf4c0468e6629b45f27ab5efce09107fe93c633bb94c9e2c8f0c0597253bfd1be6c7d2167048f3bf0716d2d2d640e4916ca2d78d881cf509d2ce5300d95d781d321655656cb972548b4e04107ce7474bd749df4e50dcd811f75dde65532d6b8eb21073eaf280bb2627c8fe92e81471cb8bc9e665f59d4697239e001073ebf9a8e1435291e6fe06356341942f28d091e6ee05bbd72fe0db24c9989a305270c331978b481cb394951cfbfb1aa325f78183bc6d871e5c10626c9ec5e4a94aa1ceabec0630d8ca757f430b563297335f03149fb8e96df64d27f0b113cd2c0f765fecffb3d61d2c62c78a081c9299a9e2382d23a4967606db227a146d89ec528163cccc0b82921e26e2c9f1cdb32b0c92f467190819139e93791e4e7381a2a24f018039b338410d67b31256d1bf01003fbaa498a5d503a3b84b6048f3070a66c930c1d47b55f0a0cc7943456d25d2bc1e30b6cdde8cde9b1cb74ee385aa0430cbd828717380f6a7dbfcad3877ebbc085d7a9884c4a7bd0e102a3694925e854b7c0f9980e52e2297f53d10a1e5ac0721e0d2ae446aae091053e6fa8648d1d1ad444565df0c08297aa479859fc0abc84a851cb46895edb0a7c90dfde2e32fea9a90adc066d7df24ab8fa54e03e43f57966bacb4e81f7493172aacc4ba18ba5722995321f055e3325896aa5172bf350e04db3f376d929a1db7f02a73a7947c545855cdf09ac5eea076dcda263f49bc004cf5144aaccd39f3e133855f12c4b0aa1f2cc5f0223dcf472c9cddf48be12b8142237affe78d6f093c0968e65bdc89b62d23d1238b9e329c935f99ef547603f256bf650933ea57e47a5c949d34a70e71d84ca9643095633b86bc8ec24f88c9a63e79f940497512d491db7d4798491e083ccd9d245de8ed53e0d4864aade848aa351748f821d670336091a8f60848c5b413c54e7c71dc195345de7666a04bbaee7495e75868a0a23f8d0ab20624417c1e7a9ba20661d73f614c1e54d0db6b9f636b49208b6d2e9688f31b6f588d84c6434134a7608c6538a489fc97208779b8b2d0c0d43f0d9b549ff540aca275508464e4a8e11062118cf214cc5d1bdafef0f824fbdfb510b7241b01e96dd3546dc1f650a04772a846c49f99eb6090204ebc14699aa49273de9fc81f3bd1391ef3c7ee07774e3d5fb875cbbe9032f31644a9bc6bccc357ce0fd5753cb93660f5cec8951ebdf54e8bb7ae0aba2a8542a836ef6681e8cdc12cfd7e28907ce92103d31787ee91eefc0c6ad1c4c5abed8818b39cc3e3de705cfd78157cf9f8489c6b4392b3af04175ca7819a4258d990397530a49454c264a47090b68c8819598c13e84150736554a4ab27a8d5b88c3814daf9cfbe1f71bb84b4ae78edcddc089decda0cbbaf74edd0636a6ca2fbe9577da64d8c075ea5222d89fda5e740dacc8f6d49b37a806de7f84083958c839669706ae2496d03946fe247434f09b4262d299fb5eac7206ae84f6cf6f1e4a249399810f22e554d9eb32b06e19926d940e19f8902c54ee8da977947a0cac78796bce9253a5b41818bb3ae175a623e78ce068810e31c2c0ae47fbcd29497eb01218b8cd67a9fd93f70556f32af57684c5909917d83ae59d25a9c9415845031a5d602ba5a6cf6a4ae988991d6870818f9c45e8df36dd10475e70b181a5b105ce6dd369519a94e8a4a3052ee5e7fdd5dc1d92a259603746caa0eea7e244110b9c5b6acfea96bf026312526aaa7117216334acc048099ef267a5142f48a30a5ca5bfdbafbdf5b594a5025fb16c83690795ad73f431ba382ac017d098c2e291228aa8a454d19002b71f4443d787a8161b1b78c016c50b34a2c0a9260bd1b41e9e46690c1b1798800d30d08002175fad339b526a39b883c613381135bff42e7a8aa71750aa8481861358df4f0bdaf55354d57194c181461318b5cde7fe1a732c956101183ac240030d2670da83c48c6e4a62eab30c3496c029ef13eaa9367b4990d15002a7dff25f3bd2e4895d0e2d1c6178914a79b145175f58804612b8d4eb4a492b8a042e289534ea0633a55febe31928a510a071043676964ef622358268530a348cc0adc44b7a22e6b459544da051044e5409cf215b9e38a944042ec35a74d774567c1110680c81afca49bf52c4abcc7aa9020d217039ba74090b324fe62a08ec290926c1454408518106109890e495e89646aaa0fe80afd69c534b8714ffb328d0f001574aa594f4ea95e9b422a0d103ae57af92a6d2ec3b960cd0e001db63a3b761c98249d61c81c60e78136197ee62e80fa937020d1d70e2ff3175ac0b3adf99432b0c2ec45893018d1c70390691d73dd3f512061762e0d811061762744103078cf63bcdba1464a040e3068c77648d314516c976db804f4b216b9b29dfb7c91368d480dfb6d23ebf4d3d7dd1a0011fa459fc6c153263169cdd9bb6dadf376139b2e0a4de8e48f2cf34cc8805ffaa9236d7f2657fdb033360c1495131534fa65598f18a728b4dcad2d9aec00c57b063dfa52b2c58cc21cb21cc68059be49769d0bfe725439615ac66b4ccd851447432550366ac824f5971efb23e6dda76862ab8a483074bd974275d71093352c1be86fa4dffb9fd928f0a46435747e750b9b5834ec16d52da1d4d57bcccd514769e1434799fc508334ac189ec7699b71bc2724a0ade54667c932034e576678c82db6891fed385cc1005a73972758a9332a599a8302314dcc8bc4d2a5eefa5e08282179dd926a9ef6b62ceccf80497530eb641095d5a3ff7049784befc38d2e4a77d3ac15f5bf747b335c78e0381d3199ce0b46565fe379dbced83a3ca143163137c648dfc9eb7ffda6a08d8d8c2c603b6b0c136b6b0d1802d34c1675226f72f7dbe3023135cda10845ee650113bba0516666082b56c11746307675c820b41648af9f653841cb28019966062daaeafa0aeda2cb4b1c5186654824f7192501339c434da86125ccaf190439b9981044617ae6312dc067da6a794d6955f39b4ba0b303e083324c196de0d495e3a1b21ea48b0935da2e64c419060b2281d31974ee2a6848f6025fe577a9852e121770413728aa5f8e9d35a4b663482d31bd916538f8e3083117c74cdd74e593daa25bdf02202691b8043cc58045bd1ef2aa9529e79438ae03557f2aec816edb42711fc5a0ed9d6e2410463216ed01f2166d6c839041f84c4cc546117ed5a43703e7a3a53e45821b8d0e3993cab4fd54d08ae8450bde412f39f84e81003479587d1820d2462c62098a4b1d2d5f34316e90b82abd49bd9ed8329b33b10dcdf6e0ebab29724150182fd78edede611f278f40f8c69ab3f75b671d32a40c1e62366f881f5ebeb11d2ea2c5abe0ffc55c7cafece5515743eb0669182f0f4901df2b3072ee5a818214e1296ffd3039b4c3f72929a5ef3a57268a9000538fe781738ae3a2001731580e185eb08402066e481d39a1154d2a022a6d5f1c05d06559363d21a9edf81ffdb20313ceae474db0e7c2cf1d7b2cb1dbda375e03705b5187445f5e9920e6cbabe9873fbd69412e7c0279945e65dcf4cc927a6fd8b15580000aa98210776426e491294478ec98f0327b2e385507582039bd386beab3db7d1ef1b1855c942afc8f7b6f204ed08c60c37f0b59752c5bcb95deb6f0393763d5f48b55945c6b0819359b2fea8fd2079b26b60b744e8babaae8d9b570372848c41e8e86f1a1899befdf2539e986488063ef6e556aefc9693b2cfc08714da64c87631490d320397829222476b4f2caa6560944ad31084480c79f46460cdabb35e8292a5427e0c6cfb65a618835c0c8c25193a657dc8b1b31e0636a7dad0621a4212afc1c09eeddda8d2a72ff079eaa3a36e4a2add78814d7709a61642aebaa60bbc78784efda6e102a37394741fbf32627e0b6c0c4942c98c76fad1d50223536df69f8e27c966814fea937ecd251618cd88a9be976f17b91c5a27f8828b1d3ac648ae03479da0991414665c81314f2999e5106b7df3de0596cfb002a736a7ca88a12be860e238c1175ca0209d40877b5186821955e0728e223d847ecf2552ba382ec60e1c28e8620c946563030f6080316f30beb89f41056e83dc8865a332ef1de98b8303477f7170b0808baff2850e0bfcf109883106056edcd0e128d071bc281670f10503c0831953e04678091169d3bfa2648614b8b4416dc40b966d6b93436bfbc60d0e9828b0af395993ccd2983a0a057e948aa62a3fbf3c98f1044e099154b9b27437955608339cc0bbea086d79a46e507130a3095c08491e6b27fead884ce0a3ed77e7cededb9212011da7033798b1042645ae98aa4c6707515202e79f747d103a1dcc48023b69b494bedc9954f410099c52724379d01dcaab37338ec086c474ee1743974660527a8a418847af084c5caffe4a3146df9815e30b2e3870e346210263fd357a3b9dffc5b0cc60c61038916b4cc4d19f35e9940b6608818b7d2e4a853ecf82c0a6aafa87851ac78e436ac7026a3003086c28c949691fd359321983193fe03e65f41cfc7447440f0b66f880519372fabc37cd49e66c1166f4804fca247aba8a179ec61d3ce0c7bba36fe48ad88e2f8e0e318a0161c60e184f6a21aaae9f04e1660e66984eaa246da9949e03be72c774e1a9ce269970c097dd56ff58325def8a0d66dc80112965b1a0aeed554b1b705a7931e36a8ec9d3ad01e76a75f913626d0ce50c1ab09ade5a33a485560b0319b3b0c3b36f5398c9dac5f8e2a4d3012bb2d08245b5bb78569b2423167cde18740e1a3b5870a79dbf6486e0173b5d84e185eb0b64bc828fb12f0184e025c5531a565223bac6c60626604307c1ba9f106db59932725210e64caa83d0fb2924ff77081f81e053df5396a067396777820f40f0f9bde6e33105b533b1e1e30f9c773495f75250093efcc0c7902fa5595bd9c79429193efac0a7d7575aabe8aea0c307c6fddc4a3d85e41e58d3b4906741add6d71f7ae0cc3a06f724624a4247ff9107c6266ba747dcc9a22d1f78604c44fecf154d738595430b8cff820ba2838f3b70aaeee65e5ffa473d36b610400e3eecf0f9a638d16dc4b31c5a2b383a70b8bfd58193c147a452f1e4093dd1814d2e6abb746ce7c0244d49f7a27b7268e506bc0b14e8700a9c073ee4c0a8512f21670b922cf42ffc04a6031f71e084ce6bff4da1b36f0a072e2328ab0a96477aec38f0f1066efbdbdb424e11512c6ee0bddb46787814d16fdcb831838f36f0e6c9d2fac95117526e470e1d384e7050290a6480021420a6c30b2f8a083ed8c0e68a14a93dfff4d28f3570b5d9be59faa5e5fb871ab8d6f02c916b64d221fa9106bef7bf9392b42f42d51f6860474566919474d37bf6e30cbc89a6cc6a29a6f4261f666063652d4d32bd9652df4719d8a4845f977a503a499e434b4df041065efbcc1c03dfab66427e4e36494d7268a1e08ba303c78718d84b217ed9b985d8df8ae1230c6c6b2e4fc1c3b4cfd361f80003b7a75f728ed61633828f2f90f369ce21626e8ba60221c0d11f5ee02bac56c453e66f497268e1c8808d2dc84717b8d2bd110b1d65ee1d2e702a9ab698d47e47af6c0c1f5be0a2a5b8a9152adfb82106185decd80f2df07ea3465e8be6230b6ca51c44b4ba5ae4a4fdc0022337d3b78eaedaef908f2bf0315f658ba57b52d2b815f809b2cb3dfbf85105c63ce43abbbdd2967e50810b5a2c988f58f89e3ea6c075468f9e3a434a7c488193626a9d7a2df2c75013cf131f51f880427e31eea952761727c761e0e309fcf9dba64ebaf7e39999171f4e602d87aadcdf4a11d9a2253e9ac0240b21656b089120a41f4ce04784452dd31c423c1502bb858f3bc894d2561c9d600ce48de304607461f0001f4ae0aea35958974aba52b4c24712dc16d3bb112a6e60023992188701376e4ce103094cd011a39a7dae12253f026b2e4994c80db5592123f09573cab896828e6b8ac0a9acf02836e61584ba880f22f06d2a78d6d05be1ba6b213e86c08798be1f2a3c4d16c78381c330c013172ad0e11a2895237d7174a0cc0d7c08c13d7d6abef7dba1a4021d636c91868f20703ab3b957a94060af445bd03b293d7d82838f1f305a216d52952e59d5ee0336a88a646eb71d64090350838f1ef0f93de7dcc9d6d5d7c4032604f53cff705bf1b1032e8390a20e387d4164c93622fb8765630b1b5bd8e8557ce4809718ed3bb73c53c50f1c70c2f4a4511d947e52495ff8b8019354445f93b89fab83884de0c306ac4d7a2d21847077cd7ed480fd125943ca8bf9e18306dce8186a84ccd8c13212851ab3e0a2272931c82c416551d240b1430d59702986d6abfcf70c41e9c51874a8110b4e459219a9d75cf72758a8010b6e75344c52a6e41eabc62b38e1f527b45e7ccb9e0b430d5770414da9c896bf2b06b7157c6f1659fa9e55f28face0e257084144ea5bf09c55b03569432c846de88b2ab8eca0294216eba81b4a051b64c648769a6dfc34d77109811aa8e0f5b44e8ac1cff2f9478c8370eca9710a7645c6cd8ba233342e7c8c1494aa610a3e7752dee57c8b399dc610354ac1e6502a8927350bcac73cd42005df159a6388aea87aba35d41805efaeea2198f47cf92d68a8210a26ed56a5e5e46d691dd60805e3aaa6f9d53e3540c166f178d27cdcdda2c62798bce973507ad74ba9c7136c9e7cd283dcd4e804e71233aa44bfd0a12ca8c109fe6d3c27fdfb20121cc46a6c828de6f76d3aed4454870b1d61580d4db07dffb9419b094e78d69ea9742931b939b42a063530c17a301df3c70fea4daf4bb021d8764848a633420d4b70aaae9e63142537422cb750a312bca8f98ba81af364419460ac430ea62fae5aa831092ea4cb9433955fccadd790047b4ae8f04832640bc2ab1109c673ed8b9ca06cd4cf1c5acb831a90e0afbb228f0e41dd9258e311bcd9b8aa988b0993780d47f0d94386beccd22c4ad70836dc4f07651d32a10623b8fc20ef42d59563c721e6801a8be03ae7c5494a868fba48166a2882cdcf5a9b58969e16fc070347f72916811a89602c2421d2d4acaf236e705003115cd22023c70c22631138e3a2c621f8ce7b4994d68a212b65085e23778f2cddd933a61405d42884f9cd27082183493381d15b83108cdc284ae4f4bb210779d526a0c62018c929df7e754a923e6b420d41f029c2bef2b90969a5d608049b3428a549281b108c5ac664b5ead6f803dfa731dbe990fbc1ec5e55bb27cb1a7de0b49bee7ade4e1042abc10746b48894d56a4165f76aec81b37613ab7f6b7d8d1c126ae881ad4a6f13cfa6b684d40535f2c0a778a523a2f7d608ef0635f0c0ad69932631ff8d3af91dd8eecc3156d96d07264b0eddcfd014a1461dd8607282bc92acf59dcba1656450830e7cd6c5a45d42e4dc9e9f0397eb94ac499e9d9bcb814b9b344aee7890691407b6ec4dd7f78dfa2c7138b051d34949195266c4dfc095e63d91e2686d44ddc06778528d1ce936f8b731d69a8f121bd86a1d393a5f7bbd92d6c049c8912bc4a44d7c4b6ae0e32569a93508a1cb4a6960359d8bf6efe7cb104203b7eb163347d252223f67602c47d2bfdb1c3330e66e5b1dd275828897812b2522932599f44b78c8c0776513ca3f6dfc0d9931b0daf9b2978f0eb14e2306565f5d6f57fc523313064e2591d7bf3ed7791c0c9ccabbe165ba52b4e80b4cfc1b61315a1ce99ff50297d466536eb92ef0a7dff6c13ec7acd4728193d183f9a515a13f64b7c086eda5c62879d2a6b5c0698aa2524fa259e0b76b6d62c8799983140b6c348f9f4765afc07af6fc31c7d3a52cb4029fd3f44893a0a24d50abc004212ca7ec954ac94da9c0bec88d39a81016c934054e66bc1249e74b152229f0e51a4183c8a54382320aac9b8514445fb9a832a1c06da860aa2c9d89d69fc09932adaba43b81df51ba62cce1e9d3a8097c85901acd6702a3a642be3caafde359021b2fc6603906d9b7a612f811b58ff9fa25940476336af85eccff202430a24c9608d9edb45a47606d2f7e0eeaa1e349d008dca60da57ff222b0317f478e9913811f573f9554fa29350e813555710f293c21307a27679f9c267b8c5d1058d5ca9072b4030267ef218b12964564d00fd898e29d2afb33a7d0075c6ecf65b2ca2fa3567ac0e9602a7fe2a4f080c9a93b9a49ba3c95db0ef818546dd7064df144a603c6bec2444595d4ebb11cb095cb4a72f6ce66711c7041cf7c736faddda56bdc805327b2a434211bf09fa7314f87906fda1ab0935b47ecd574f4b4060d38f513aa2f79c5b59c053b6a21efddc9a8db952c180f12e26de6c7b87e2c1811d2858a9be9939081052f31497c2f9d4235f90a36bbb3baafe94a52bd2bd8a0932e765d48a14c6b059393ca9a83b5ac60fd4cbd0a3e4b08376d49a7cca2a30a4ec5dc935372489b924d055b7d49988e39890a36861092734eedac693c051ba92208d19ef89f33145c0b6898820fd26209095ae3dbc74bc1fee668427207d34c2229f8d2f9d1cc64879c9a8d8253dd88792354be4314fc6810c9724d3779c943c18b44fd4e32dea0e0a2c5db20ba235d2bfd092e7708393c8614c26ae409763be4ce58163a69e67482ab144bef7258999887138c6a93d9e4ae4896acd9049b2fa6ee3e32a5c78c26f85839ebb3c61e69419960a4efe51482f4d2d7c18449249172df622ec1c9143cb3a6a5aaac5a821149a925510a82e07d726b5ef2afa0f94070266408f393f963ed80e02f89a0a1f4d286eefc819164eba15ba134c8f88109f69e3a338d7eae7de0542da7de562b9129c6074eb4a63d95bb228910db03233fc7de4fdaf4938e1eb84c5a73c84fefa0993cb02ad613634af1c069c72da59eb9acbf3bb0f97c82767fc60eec06491b5ca3d8491201831675e03a8a75e79c2157254d07c63206a5936c9115f4670e8ca7ca206388460eecd686cc263c64d17be3c0dfa8e6e63af9164385031b24e80f2a47c9667dbe81b549b9574fd44c65ee88e106f3fb6fe7f70b2e8e18ae23dbc06ae44c3ea2d3a7feb46003934efb95fefabf3f79166bb1063e8b07f3ed77b38fab811321e58a1213d1917e1a98e42243772cb9a7bfa381b7092149db889a75e93370417bd0d4694f3b7333b041a8bc1a2f8bd44b3965e064875b2acd8999364306fe4ec99222bdbbbcdb31f0b931ad7c6442a08518388f563fc294302d790d037b22af629b0c4174a7e4d04a2dc0905a7c818d18a225a8e4926397fa85165ec01468d1852b560c92cb2aa5985482a50517d2a5ca936184716e145a6c814dba6b9fbe628f086e0e2d1c8866630313b0b1636c60021cb05068a185d3220ba605160a2981165760b466cfdaeaea6b8bb50019066861054ed6d85dee5e5125ea2ab0de952e89f85a323df4002da8c0569508caebf2efd42b052da6c0ebfb69a5dfd96b74a5c008b541837e8f16b4a951e0b3e429b5dd5947d4f5042da0c0572af51aba792d9ec009a54330a1326f94667368556d2079181ab891650c5a3881b1caeda7164f4de49bc07a0c399e3909372162029bdd2445123a889ae812b8512926124f25707d2bb12cc34f021b39078bb1d4048fda2381efcf9e11d7fa2370595a7a1f9407f5593702ffaf49e974bf6b99ee2270359aca6dbcb75a6b22f0515f84a5ec8b7eff10f8d29f6ba38a84c0c6b21d592f9a93dc04812b619bd12a757e3281c09d4c3a7b24d30f98a0397ff04a412b7dc9077c8e7977cf54520fb8f748f5fd67a1829e079c1e57b318f1be436807fc4911ef5c121d305a2cde955273c06e0a1952c896d702075cf95edc4b934ce710a4c50df8ab7c93b694bc95dcd1c2065cfef71ffd8a17f276b4a80193269824cd7ac9bb375ad0800bc1268594de654a6d66c107ab7849c8989105dfd1ba946c9360e9df587097b935686adefebdb0604f8b8b77d03b4f7b5fc1267da3b39ff0cb5b5a57b01a74db238af58ad0b682cda3fa94d0e21f27baac60b3630e65c164ac28d255b0e1a643f2dc54f1185505576ba7b3aa8d7e8d9a0a36e29dae1ed724ed525470273db55fe490ad969e82b118628c94276a0a2ead56cfbb735ff452701e528a112dc7cbf9430a2e4dd4d39eb37b8898a3e02a2fe535756ab52b290a2ea58f299d122ae2d6a1e0ae4774c49c82f60c0205234a63f013fc089946a8969e94a3e8095682870ca242ec049b3f2775a2e3a7d61c7282cb7173b668fa4e63ea36c1778908955384741e2f9a50d2c84efe37964cf06b9d930c15b1eaf498e0db43ec4b37e61fb376093e76c8912442fccaad5982d1c8ba5582df929a9ac3cc7d45a3042742c42cd974c658a29a04a34aa62043ed2da8b52451b220e3a75e5224b8d6984bcb74a9535a48f059e47be8603e828f29b2950cd13cfae8087e35457d75e27b758de0933c53afdd63ed298c60a4879c91b2bc736364116cac521a74288b7944882238cf9932af3289cade26825395af6a3bc9a415728a08ce377656804330c9e42695f431c5c43704972ea69cbadb7527e71482136b112253660eb23d842863b0b89a9b6206c146755d13a1a729a95410fce994d74d9d8e869d81e08465aee6d1699f441010ac59778cf92b850afdfec07936d7bffb2a15acf30393d44573d3362de84b1f3899f4f5f8ed5e755af8c0b5bad5e40bd97e54ca1e38bfd431b5edb607ade881310bd3e6eb77af21250f7cda969cf8e9747a53e181abde9cce844a4d975377e06ceb742b857765b4ecc09a4850d1939cd4b2aa0337d1dd4a3bdd4a448a0e6cb699aefd909a03a327eb5637269996037feda6e63147f41ac5817135dfcd6295f47be0c009fd953d6955eccbbe814f4a081f0b4ae77817379823c970cbd136f01d5b37828a101014800dbc29fd418479148976af81b111af0a3ae389f4d4c08a0c7da79a9a543594063ef44ee6cd29b134b268e0f55465ce9ef9b7ef33b03af2ba479decae1833b0d53157363dd2b72b65e02b68d357593793c4c8c07846091e54ea1bbf740c5c9fea335da23fec1403a7424ffe5c4a448b2ac3c046cd1959ccfe4566c0c068d0567b4104bfc07586e0f182bcc02599428a88f9eb02bf751593d2f47181b3a4fbb2ea2d85e5650b5c65fd20d3a4ef85a4a205bee295d41331bb4c2959e083e5f62fb10d8b55c102232c8ba5ce26bb0227b3d4fdd52651619a15384d1fcbdcb2d9e8d1aac08d4833952fc92a591915d8da167df7a4a64c3d054e7f571231674b0afcb6bd8898c98927ad28f0f9233306f118a3490b0a9c485c09b9d3e94bb39ec0f5c79c325dccf3f5ca09ec579b664b3781b5d12d66723386f299c0a9f79026ba2a33be043ef8a4281a456c728e12b898ff944e891f1e9249e0a3889853c7cb413f8804b637447e5fff09ea1d813b5da739067d79296604764c453ce6a0725e844ca000456037d4c9899e2775d7446093d0bdf5214534290e8191e32124a4f6244d6542e0b373d404d3d0be292e70b818a71e508020a0955a52ca2ac1c3ddd328fdace06b4105000277a2471c42017ec096674ada92bf55aed1d1a0003ee04e64d0a1f35e6efd0d0705e801e7a22663c7f1b8800b0dbca0003c602cc80c936f1253e5ba450e0ab0034e9dc64b29b5c69c357643074cbc8b41df69ddf353b7a00039e02e549b524205c001ff1d430711537c741670e1050e34c60e6501175ee0f03f0628c00db88b1eb3fb4325e8e5779c85c059060a6003ee227e964eeb9492fd05a8011be2e94f5a2359f20d0b4003aead455e8a36d3eb3139b494371815b8fd9805db29e6383abd6e0ed5f9172b00030718626091057cc8828b933d66f4ca3e69f7c1b1e3c610e368a0051fb1b0ac7478081e3432f880051f4b6b8a93ce7292267a059f49a72821c6f6c3157ca5c66c6923ed06f9b582bf2b1d2a241f3f58c1e6a86f4274b86afed22af88f3c42574cf1c775f4a10afefa46a78e54f57ffb2315ecb95d7896d2ec6b3f2a18ddac9b60ca7d349a4e510ea6378a6ade146ca90f1643bacd91d4a8146c5b881ba6695dba37a4e026b5f9dec56e14fc8d9dcedd561105973ce8cce9db534c950a056f6a5f5782bec9a0ef0728182147fe5f0eea4f70797793fc623e3fa1798289924d4bc7ddceecaa13dc7a2475f31141098f7c7082cd223429996983d2b13e36f1a109bca13a3e32513e30c1c5a08386c4bc5832dac5c725b864ba7372fb6b89d1cba159a47c5882bbfa90548a64f5163f8756a9faa8045721b46b497dfba0e91c5aa4b6bcc1f8e21af04109ce638c28d174ee9849e863129cde04914d968e24d88a112346bf10178f5d043e22c1eaa411adb316f7ff3e20c195da7595eca08f47f0df1b838cf963b6baa00f47b031e45831a51311a34a1bc1bafb687dbc5c9bc6c2850f46b0934c5dbca4758c41868be02ce4adb4bd493fdfae08fe43ab55501ac2e123119ce6fc1ad48990d32d09116c12c1f7538d8cd4f71e828dd949dbfd53cc0e1f86e0b4585a2abb0d19ca367c1482495ebebe6fbba5806fdc08c38b84868f8c7da8a4f024e25824100883a1703810808102e603e3130000000c201486429160248db465fc1480034b2824443e2c16281c2014161a8744c24028140608038160180c0884c2e15048201ccf84bcfc23fccdd9b69cdbc999e79ce7382bda9ccdcd90cd990f73c6dcce96250f9f0356c899d94abb0c693383abc7709596ce29ca2e9d82b9731b616f895c47837bfccc3d8f7b0ed169fade7f1c99303dde814deb1166c45d17335dcd2866080662750208a22d4acfbd8604ee0af7cbdeac53946a23355256678910c3f65c9854a1168be89b326a1661224fd6afd2d834fa7f6ba163cc780669085c05be215e24f785c3c2091c82a5b011009d7eb9d6810d19965687ffc01b79050cb0f5b5b7672bd90d49735ed176c4c29d8d26ff6656b1e3c5e68d6ccf32d42c88053d878cb4d89b356121c6e908fcc0d1bd5cad382fb3b985f4189e1093ff24a0eae6b9fdfaa5c7a996959b0743986eb3e77bfe4605f12f85557bcef57a853fb8c2e504163bad26ee3c3ea29dc52ec3ff66161d54e2d4b1c5b3e2b1d8a8fa2dc1c74d655e42884f4d4810f3bc45686720a124b49317bc4b00dd21d03b6a1336613f500a90229a4311fc3d17d50eb0280a5da010519193d28dfbc28a775be808433e704c21984d39b0c669aad8aca0c5806e182d8d867bbadb9df3cc3f86b525e4119e3efb0c8d706a78dfc143abb1fe5c0be0c2c521203af53ca677c9ba39e3cbeca9f2bebc27be75013e16e90f2092a199c3f5820ba5d5bac5913d05fd3d76a36e59f99f62c3158687dd53c9fd0d0f09e2b431be040f1436264a3ab96e5837d71dee86d59bb134156ffae571f766bcf11e8cf7cbbbf24c79a93c40de9537d1bdcf1cfd78a3c48f9d5008e8e819fc591a6ada7061db859d298fb06cbd5afe4de88881a8bb791ade8ab79f6fc28c1d2a15f31502527a13e44de07ae7b742f73c0bb357ef11f662e12d4432e6e2d6e105279c8059942ec486ca86b68539070ff4f306dbbcfb8c7f6469779a9ad6d6e460e0f52feb163274ec32f5c5b8c9815381b6604c5444de1d710bba30f9860b3a6929b90bcd9de75673efdc656e3f37b43bd4ad706fdde56e6f37843bc48d7add0ade9271a6ee3e7ea8e28d8a169d272a257e744752c67b9c5f0aee9cdb39a6a5d6a90aa9876c593a757dfb6dfecde67b6c4b5627db17d51a7852e9d76d7a612591324a962f1a4ac820d435cb2b47c6a3885148b1210d1152344927471f21a5202279479bd1ecae196a8e968b5c85bba4161d4103d0b8457b982332b1d19553c8189acb7927775e74317ac0cea48f51a9c552f9a8b1e799c1364f4e29153cc4d252a0a897a4a537a33a6f15869f05fb91614864694b76b2e641ce1cb30551477508c0e4932148e488940265835ca018c424be145e26d16c32e43082fb265165683c125a0171f9de345d0d14722bf73ccf4b5eef8122d7d0dd48bb5130da3845b20b0ce1fa21a9263f386e59ae48006dbd0dd2fb4101030163b313ad0e806b7b9135c8d4e8b36d2784b8b4ecba2f7e6fbcccb7bc7e71d0cb1288cf4d76b2f0555c40df0435082727b1ed7296cd0a83ba6c4df8d4210763e4ffece9e133f723b60a90efc57503079ee3f01ea559081746cad4dca70c00ea7d8b58dd8bb06ee401d05e25a05eb73dd78d934ea15db7a1745097603af90d5070b4aea9f052948fb361c7552134e496f19f0c34dbb77ce8c0d557251e7cf83215a122f935e5bc50db6d668269bcaab06e8297114998b432c92ce1d823e6783c1aae200af5ef57218fa4fdbf9dcbb015d3dec5fa2e8ab104889334ca906cf1b43a385ea9c07b2c09dfba501a262c88e36d4460cf7c4c3d4c0552c389c1010e92b78295a6b1e5d9495c0afa9a342b588eddf8989866462f8b5b2440cd9061b5c69132b7c48b483c7767d28780369438019d780586ca75b854e7d910baa21e6ba3e173eea11140c9b570b904fd41ecc560a217958c710becbd45d5389aded202876af974244a67c73952ad23619c2359f59b6dcfe3bf27b20851dad1a8b476a1b437443670d596c9630e547ff648a3749d2e00722ef2c6299394c8e993409bcd1d51553acfe093925723dea2900c7a55f6702e5f1f0a5cb3a2e8c8da7eaf2b330320861109db08ddc8add9f8b2359bb21ad000cf634ac2f598b19572b5d7708f19919632f6ae6ee4c0193252aba1ef3f8d4c441fb35297b165a611137747194e85e0883819076371a71099cc6adf9bdf4987f02ef182fae849bcddee61fa210009f1bcf999142eb03226982cee916ab5b02d44c8638000b246e30d3df95dbfa1be68858ae49e3fd0867190ea866edc860df2691ead54994a8555a2810f9e03a87b8adb40b4b81bb791cf86d3baad762f010aeed10190c80f89f19d2021873ef935831249264f3377a1dc9c5696c5c95484ec51fae7c0ed7a521bd037d182153ddbb0943d6f5440c1bd0ceca4fa4256974d0162b8b551462b1798ef7f3d5d5f44ca9d8686cc723e80a2c24496afa0f1d15133b6cc24fe824cfcb0e117cfea3abf962e31cb05af36e1be6dda2c07ec38d240c0761465fa1274c1a449b078c7b17401a5866d7a3468687e756852de462442d1c01cffab5d7f9e8b21c98e0b29fb214d56d44b4e6d41485d8d840ea2496a5dd51c30814c6f83c87ada6c8dd6980db039807197050b388d3433f6c9168949cd2d6bd8e0a70f29b7535694a600fee9b95fe98d8f1a6058cf8907852b3ef7ce25afaf81217188683c5459a21db11b15543cfeb47038fe752987062bd70956d0fa79660bfe538c4d10506ce825ca1ec9f18ecfa36c6a13045040410b2442bd5599307717502e0e697eb016517d8b090b497808392dc5c5a9bc8bb9d83fbe2f26606ab7520f9aa8cab5345cef62ea4796f45b325e6350c351528a86e3341311be125464182f4c566fbee8a3685c6452dec82941eb71c65412a74d56baadff13ab9b36d9c4a1ee4ab0575c83e8b488d15d9d3da1728f98bf1c840d621ffefdc294422da4424ba5e55013bcca5d07a3841724605c56df971d060567a16871405fcd63ae10619c3b8a9cc4f2eb4f6cd9182de961267e1278c9d59e06d00f5ad3a38fc3f19846635b4ac57707981c1b374094bb306cd73a02b7ed97a5d36822429e2c784579fda9809789b0e06ae0114ffd2da224e36f20126057b42f015905e4e28c09a4c915f4e2cd73f5ae06e0c45fe7bfd04b68f4267c235863e814c442c77631c9f9a34274e0b1655836d63fd7febf448e5ecb4e9aa1f103b0aa1bd456b3727e60278f5587faeec1aef32fe58362324bd29f6e4d061b7a9535998d0965b54089746c243fc63d7214d999f9a7f864c94e08ad517a298a654263eca4912262adee08a1b85a85cee0b35e8b67ab9c8e60216e5a5b67aef7004410477468d6126bbc8a81240518a7332a8a205f5dada0225f270174a03284325868ff7e2e03d05ba1b6f23533bf0a2aa8b73ed36dcc197ef27d2842010caa5538c60eaa81338aa1a559043f5658963ee5da999ab2847181ec470666b9ddc796797f29e3ab2270833f833991556e4b030611163d0ec60baac74a6faa4fcc27c226b87b2700c9e5a6cb4379bd3aa6b8cc9254b43eddb05e61c43ee4a91a1311891fe33f358e8da3178d6b49eed1ce3ca810fc8f4675039a7e6af4340a0e8440a270e14efdde9276a19776a26df890ee0ae41030858a7bbb4db02d4ea274cd846b7151ba7449874a4c410dfd89112d21f9cd127049c80c59dbdc98e8a95e8d72bfed25cac77c01ffb338001e970f2beb1e1a1c812977ff27238001b4d8522051521641e1e23e3480896fcfe198f6855ba8f995bf1a80e8bad7f4adc6143967bb1806abcf8e590abf26801b2244ed42b22fc25a3f248712961bece57c951a7e6485e4e4553c6ca8e61dabaf409bab6bb65cccf867e69054d0f621b84066e0f219d3f34702d9aa420139d0e421509e577c275e59fcf874c6acdbe1a741a6102e9f9464c478da4f748e9e83c6c3853edbcddaadc405b6e3a0bb8cc7f1d1dea915fc142bb8868bd9366b852fd7918f263e359a32d118704358481daf2149749c8e0003034d731cc498f0963b52301352e8d97f3528518e120c98f967812fdb5e7f95c63f57ee74bcf85af6a46e4d019e8a4b4318db5023c221cc603934afb720f8d4dd6fb2ed54700339a87fdf43379ddb237eb207ae32695bfdd68bfbc8fddec44cb117b95a286d37e49eb5ae809417641b0e7ca3fcfe6c6eb8ff424da114e99c39f4674c7c55376e0864a7e7ed14fec299d727f223e655b7caec63ab0535a3d14e349cd31247c70b4f472f4577851691f627052e77b25932965753d54abbb43e051ee0082c9026c74c450ae42203b2b47bd9c6880c284a0530edba2796dc8962b62155ad3dd2d6f16cd0e7036dbf80976396180a58f54e25c63a46b57cea14db74d96ab12d3c5e754a7e3991a0f3081a5105e3ded0cc4f3e83e9522a11daf3d8876f3b1eb4da137463fac6b2858bdfc14b1dcb80d0cc2dc3ea1e6c4c21fb0db448df5116580b6e05c40590d9240cf3521a4e8c2352f837302892e1a94c834369f51057c6bd385d786d3c97cfa524254632d407bf81cab69648308f9bb6c81c8b1daffecdcbc1a04c040d53b12e167491343c9244bd10ff11e5f2049c6a3621a5dae536c88de633c4556d5253f9d170516d98e0d5b654e72527d520aa0f16ad7903bfd25a5b1837c20d7ee24bb6e640e5cf09d0f98883787fb0cae54ca35f87d3bceb2f08857d634e990ff8b2a32daff820fda3a9423459f74c0e662ec0ec29b68fd39ea8c840160a94ce98cf1dcb405cceccea4317f8c473c0ea007198e6880ed9a8fcf4a83c2fab7ebc7be473aa0136eec07269d701849a0563825409352a3b0104a167275254581b92f503b8c2ea8518f386c8b19623ac78d146d58447b1d32fc08a355c93a9e77e16e99a9ccbff2593a2afcd7911958e9c2a3aee748522a3927e5e8712f11214ee84a11aa37e3a19365e9fe1746c86a377a96207a4615932a55eb100ef6ecde046f73e6a2a5b309e53ddcef26ebc6eff80d1e1935d93590974c0f1464dadf78ac48c95ed67f996f064bb784496ccc348cbf448aa313222be76bf78f292e4b81c1759dce6bb36adc3548e6825e20dee8fa622b0991e17915b8f8c1fdac02257dccc73dd8f002ad3061af9497b795b4d80b0084f9db04fe7247c9c0ffa97804feea0a05bd04ef0a0d7a6287c003033e40aab411300e60405b63ce460cbb452481bbc0e7c4461c193649fcab96ccb365aec8185e03c7c7cd79c094ca87856ea12ddc224fe4a8652c8a4b7126d55c0a6b7d70d25dd3b9e0711489252245dc9bda42d29c1290e7d5744b9225d4b01246aa98074f3b4c08a8adad3d23eae3cb180425d25d24e5ba7fa1392e3c45e92c7298e5a96ca3a719510ea523a78bab45a4c5d484f9ce679f5c7e26339f24ab053759973a37cce2bfecacb5361c0c0bd66a9fd3105b61f8e6837a87f8a2254a290ea10a9fe2d1aa7f228595dd2fe6f670b2389c9baea04359da53f024271ef25fb93fa9aa5be2662a96fff3e7696a2686435b2fa4a152f89a0e49a7cada4b30ad8c48fb003fc8158cfe90d24b314a0efee034d51f831a85f8c61e2a596954d4d70803ab3f3ec1b4d73a4bf8e55ceff43120e5c184d88d16054f6790590ff38ebf95f2201ec106305819f1beec2b43288995be639f3cd3cdcece819ead019ed9c7ef93eb51cd0d6f8f755420932c72769ce1c4fe8f14356b5973fc67714335cb4f3ec88ec299de90970f5dd73418865d253dada3aed3f96b829bf2284bc8cebe52c673a8f426b1888e493ff4cca36103a1009f3ee2c537e14fbb89d81313347fe8370035d514c86d40bcd159683b6053302ff9c96d679a30d68f33e669c78a1dccb4f0320df894e9a9b54f462d27ec08834efe3e400d221869df9cd1c220c1d7e235636327b4cdcc1d085beaf1c2113c30cd4e495f32e2bc5cc99d1bc637da41ebacdb543a2660bc70f20e9df33a1ad3566dd64a21b5475efa082e88b0bdf3721601ecee0025e3dc4deb67907de0c53efef0de38b020d7a42e71d4c8898673d0e1125f36859e1f51c1c6c185c7eca1c289c5848350a435c048cafb790486545e2c1e61d0c5e7071b13e7363184aba2434849911e806b327f01c4b58117ad9a256c56112184b25ff1187f54210d93ce74256f0f48ef5393044dfafb6751e71d80bd8822b506472b54caa1199a8817f15dcb0165e31a1a9039a00f9797536944cfbffb99801671d38f2e91e39a4efd422a11d0d8715c17562f42613a7461f90e6c42f9a74d86309d63c1c4e4877bf145f5a7a25256d64268cedbaf2c7661ff060d8207405e31db6c642717a6316b8cc16c27e944218dfabdcff02df4ebe2e7e7165934937e983215e16314a0a8d79cdcc05286cb6cb894de0d24c0069a9d852e14bcbffc6077234a2366823ffecb7f598eeb98c6ee7039c5a890baab20df2a49e4b2a59766d26480ac8330726356198778953cdd4b3eabb5400e8ba341271c30578f3f7a18a7a7d6dc6837beb0659bbf598dc4109112b7251148c97a06ec0dc844dc50f234e5258b828d78a6f364ac3261e2d2a60ba478c32af82743548901490f42eead5dd515a1f97d7a11704265f15fb8b7af19608aa9fe8509069d66c172e09f8291af272c3effcbcab6ab9fca97076e60628f93afe921a0b7e52b3748f14d5e1e3491281a5621d096f04a066f9fc2e306481aa260acdbf4067db93ca7a3f06be8e6a61deb5a681befc1d310b60a86c2c443a03c720aae06a260ab51bae780a53bd0222ba3cb4f927769fc084178f13aef04b12f5d1f74e43c118a49a0d519508a115f5541c00fc904813f3300135cb35c21c806ae3ee9111634d7f9d8f3c5750c4f84a06b5f3c9e8744444e590137f527afc65c7a02750d0a08028c3321594737515e0235dc67f10339f949467c24a7c3d7e21eb99a524dc37867bfc1af616ae3613652010d5cd4d05b67e0b2165a472b8e07e0f35a4914234747f81c67fb88684cd24e66ef858f545da8249b63525d37ffa641c20c5d6bc0c7b14e0d3155cb7ac6c0c5bd7955de2430101f3daed09c603d7350df9f4c09a813579cf234f9feb00117b9507bffa46135451bd260b384aef457b1bfc377943099bf87753ba518e0a2795d583b017f217ad58e18ab08ef3c2757d81348959b1630a97cac9c233790d84ddcbd94a404001295a34115cd63ee9b6201c79d720014110c08f40664d240566c2bda1b5c7bfd148953a56a4f16fe1fad1a26eae501b49962a50157555bcced0460fe98e3ec22c20ad98b7c8aeee7c284df811bd5e36d021a8defa91af1177e25391ebd5e27a6946184ecb8845aaa2951f2370586cd6cfa5fb55a6b6f9539fec900388af9224beda6a9c2c8bd12d56f7431dbf5a701948eee12f1a36fee9997f7d1067ef4accef88a92088a254f5a39287927a0af24c43f9d9d54bd043c404182d8a7eb26a7d6c5406cb700b7b47ee9d0f21d5bb3fea7dabd72a92a41f5b877318f729aac74abe9160a25d123c13af47541a53479e17158cbccdab65970878ced3a0ec1bea7c997ba7e9f174d73bede04133368b3719b3da7b199f52df3696e6f7498992c79b6561aef1ca30198f2338862f1df0a60a61c10156025dc54297d3ce78d848d3209c8f49b24dd8a036f7e6f96b1755a8a19802e735a6fcac53c7fb899137b083b22e5edfcf46521b0e6530995ee7ae497010c462ac6d2ebb119a04487be53dba42083180fea1454b32bf2dc165dd439301729c7d0761e49dea2717f64673411f439057300b270c39fb61596b13d0c10ac48a4cbaad4a80c7ce6e4f80ecfb72a8504071bff29f75dba42709c43424583f4f57a6390c7ff28c4dd06b91eda67e497bfe01a8edce4f93f612149436c2368c82bdf9b7426716ac4fa1cc5e176126f9a76516720f119d6637f51bf27e1efe978aee0b513920d151fa2928031df16644c42b622dd6158f8274e2512872bbfd6feec1e0f4215e0995db5c179d4924bd25543a7bf9906fca12504fa3a394d413a56ea2c47a4d492c343f1e5b2f90241e66455d70d44a01b214061f6f862689c75bf0d80b1ed54b150fd5be1ef1757fddffc72716ba1fcce9a4f62872cbda99d3a80cb7f213ca5356ee6f36c016c52259fffd302f28b13cb23173f0aa0030abd1412f6d972ff5590f8d67e45fc7bdbb6ef9850e9b93b40caffdf968b97165dcf725c360df884d2810084e85584c8374c4b5c6f59b75c4362bd01d2ce02d2e8c9d662b640b0c0bf76641ea4d0b637b0a97b2e958f0160bdb7b17062151805156602f7013067b7541e85119467240c9124e239861246fc75108cc77596c5d5e63b143916f5e221175ee1295ceda8ba483f321bc5c275aed647182b655a0311b7fc4da579f939bb29e154340e7468adc46f198c96c64ba9e3914954704dfd6f831cdc13da1f1281a46879db31a3a5a9afcd38ab73d52521ed4a191a7df8d845c3b2b4fbc06585c322c4e4e0a2c48fe3833cdc6818b6f02ea9cadb61619c8525302055b594db7de4db4ded5b1e8442bdbe73a756c65d56d089c9535301867813d5c8efce87f78eb745981415a0963208730d204e2b912d1627c7a48e4163aec994d160e678a7bdaa9ea4e8659b924114cc5d9270d57a6e4ed1f34dc5889846260fb2b16420688ecd0408268014ebe2600eab0f03a790612183687b195f9f6975fec47c3146a7f816d1d1b23dd610a23acbbdf419c90f19c8f7028fb0f3b1c9a64a25cc2a7944d9bfd29f76aa05473cdb075de04f6a1ef2b809d816080d885c6036c25f7d26f9e903e1c18d9a2c690f2648d8bb050da8c4a2e310a61b3e61f9cb08f7fc46528ee248d68174c490fe837129014ca4e0ec3506b9f0efbdc38cd5b39be743d4a8e65d5063c1a880685899f465b4784a730b496863443775f0351153267d71300d5c79013346b800889fba4d8ee1512c6f92b317e50d753d76e4c373c4cc2e10cca8ea7c2c120471e93a32de5842ed50479e062816ac6769f781a2a47fd5d25b9dd7fed580f473052298b8770e50d566d2f9c0c8ff2aa036f7d6a48a1a538a6258e581a5f0e2cbd3fa9a0249c8d6122b60b6aebc811d2797b44cb80ff27825e2120ceb43e045140449c346dceedfd4f5ccfbc488d65ed8e282522b6b2946f00fb59979609db58ea6d03c2569ef1a1340719cf51190368b557ba40fe7e21711349b696b1dc0012241c428b9420b7c8811f71c35648c9da23ae92f952f8226a848ed611deeb90a5e209ec843d614df82dbc0a3fc2acf05fb8164e0837c2c21ba24cad43042d08b6824f43da41fe44ce9a6bd66a111c7ecc8a84100c0990f481cfb0b0754382a2fee9bdae163e7f2c24072fa4ce9450782f33fa58c63eb75bf7e2c420476291243c88091a2908a405e1bb17f54f675d08ba7c96204fb097dc26bae259b41ae333a5ecb4be0415020b24eaa09301498f69898642326b1d2aec9755f26846ee8cd210e5bd491d26f8cd808656e44eca690ae33e9b6882188fb299327dc88753a326de4eec2913dc8e5095d7dcd963872dd4e95cd56468a83bf42586b56803cb0063cef42b41c5c863e691d22102acb329ea2d47f5018fff59caf96ef219e525abd6a29599aec65dc650b04c327c1f454af352beda3a5e22ba32eb0fd7e44d34fd07b5d2b311def030f7caeede5acc3eb5536a2242406faa2ef235099680394da385e27887c3265959f760f80980c611fd3a9566627a32ebbe6a165d2c00d84aba57944f1ea4cef4d592179623fad97d2880e600e635311233b973952902bb62b658a7c5184a9b21b370b8fe60d56c3236b2a00327f4dc556746a4323b0d17559d6fa49878230f58eb4d01f3faf44d67e5009c7f33dc416c018a58c551848797444988cfc275a8bd2da85a363b0a366d9a52086722cfec3b418f8d4702f636938caaa574259fea6148382440c79c528fc09190b0edbb0b9cd02c8dec1fa66797405aba8d05a58328e3ce3b37804b24300a9f3b875a2d8345be2d0c30d9e2e40a55a5e0760de9f02a66299116412797f21adc770ee9c3e5edea62d19306284a0b9fb72c65f5c1d14b54ec9cfc9a5080a5c162be5c52eb15930cb3faae303323fdc3ed1780bab1721fa05c9b72dc1e01a1c55dc7bf16a804b31c75b800dd1c6df8ca914b40022f0b26130c1dd8083c79fc546fd6f8eec49113e4ace29fe1dd1b40a255c412c0986827e8ead4a25d0b36f993f9e187574e9167adc002ccb28fdbf0f1643a3a91621fdfc0d7e7de909600e8d9cea1b92abde5460f34b0d313c219a13d62137338ce96cf2c3dd6c07601270d178d1d95e15d042d8ac35a5f2f0aa294aecf4c2a681fcd1e92da2e6b5081f766f281bfc4d27af3152b82f1b1427a608da3dd2751b35b1c6f9ec44bd57036974ca64ea777ca0e7c14fcdb91942455d7dd46300c973166ce03631fe6bc8cb7b801a0a171ea0c086b474bf6786d7462ce501a4161b1cfec274839c29599c99eb10b2542a10f52fbecb082e9ad4b52657afdd8670043a599568836db4903b1f1b225dac8686c7fcaec5c47dfdbacf94954e506fb6013f8decf2620b111829b3902b0b1b5035b2d77c3d79ec9661378b51b25d8016c670a4cd0e68813d9933f8d024e4d4eec4ea895fdd6966ab3817a726cbaadd321f029015a4f65bf482190de98a213feb9815a65caec141e687189d56712608243c6982c7eb0109894967865003a63b1f83f84f39fb1031a1662b3dcee42e2162940d082a25bd3b3513a31b20c2530e9477a4fe9c056a49f9f5ef36461daaa946f289485470061560fc4b7bc110253332e90621105bca9d8d9b386a7ad1a675b15206daaa00a2887a7558d5e9e3656bbe83bf25e8964558dbdd2344a0d7c7ac3ce03750bd054a46fc29e8bc11d97c13cc71aae8cf9fcd03d8c784aaf62f39f438689035ef0f96ff406b4e4b98473cce6b9579eb16ec327bca6bfbb6499da22364a10312ca2bdc5b08344e0e1838797d282b8043aefdf2611f84e3d717e06bbe1f6a6357fa453852d4a6407f4f52ddd4537c6982a9e2af7c5901d2c43b1092f0b3819ef564f37a6a04a8d4d81a1fa7a346187a5ce904d719ffc6efb74deea9ff6106e4907577022cb1868ee833b23c5cb608cd7b0fd308f207e4b9491538069991c3d1e00861801efa834f6a89de69b647fcb9e648c231ae80cc31147fadb619e1b480dcdcb43b58c1cdd65e0f8a25cb4e25cea6123bd5ca4b60eca7b0a56a92c4bce58463ce48223e21de84747f308097df3686e91605f7971e1e108eb7b974b29e48a93d903d65bfca9557523a3140b35d7e12bb234064d7dd704e9e6df68785545f580356d1cbc54e2e53ada37445e24b173370a360ade6dd16cb994b1cc358c9eae0e1a2b26361b66ca45216dd374f8f9d13f6b8f871bdbb9de2445afb3b04104b479fad1779449a092b9f154d4302cdc0b02ac5f660fde041baa3162988bdbcc002de380e0bedc3323d07050045dd3c6beb68208850196fa08e75719335321bef6d8bd7a22b784f4e1712167cee0e471223c23a5c776ddc9249a5bcf4a71090dd04e188f7949481e21f33ef96cbc8c2b96db23b55f6f6358347108e185d2e4f93f0f1120aaaad6664dc4079e945f02553df450e07a40e5f8ce3ddca2ac00b6fef4e44e6a805d241a167ec797b702a0880220491597fff8dc17b098f00bbd13516c9469b39182610e92e02899852cbff53c19325697d34d573cfc48c76771155b178a3cc8e56de086fdb830923674d9707a3186b617b29e04466c919a8e40dff20c41baf878c79bb1b11c7ad855de0864a0d5b7200fddc769a6364a32d9c922c56242609419430db85a12518c273ae4f42d96cde2c90d7ce90f47b92d44821743f443ebcda91c62048588b59c67db69e7d45355e3727cf0e42ee7a87382c09f94631427b910681c5330aa82c01cdc0767ae4c9cfae5467371bdd3aeb85b2ad2ce4f864a9db95ce6d71ce22d22188cbe5b4132374ff52f40495c1e914d66e03ab65cf49f79dae419102e5c47305c04e98ca4da7c03ad1adc0ef4e3f841068dc861f24aeddb62b85bb83884f1aae70fa0d6100b6a087a25ae0098821562d46db8bac21b4c62a9d093abeaa546543429f02ef404f1a7d32a343cf94f468bc9798a594756c889aaa314beeff83a9a44de5efcf9ec528b738c7ff559be327244aadb8b67bf8868ea7a808a9767929634c99556563cbf7a72813e570ddcca3b8b6ae791702e38d793270b2426dabf358627e4d78f777969adbe8af345a845d211b3a44fb070cd139ca575ddf27f2d25f23b67d48444357ff888f60008015f90336a8d59969c005e0cbff7686203a95207121f3ec5f691dae75e29a5fb83a82d9fce81cc6e1f641d445380deb97657089c741218ddaf56d3b1c91493041bd1aa3386feef390d8f724f0c070da501787f361ea0be9914f7b08de820ce6d645199cd232cfdfd5df43f76d37ded55b4c512dead744f18755f300aa1676cf627a08ebb10e0b5645493d57ff93381ee7efa7eabca6410d49666e884f89ddb65ce67eae91725133a9cba5ccae5f4ff8c3ddd9374e14e9be46e510c54cd9abe842384b8973010117474ea30c673f0e0d6928b5ab803de511a18d851dfe4253c6ba6182d9398c2443fd5d26954fc1c60ef59aac3f7b9ba9bab19796e229b00dd517d61ba51a1ec230af124a97fd046ab2e9282a8d14915145020663b0634bb8f8b29c0a0e86c23145514597781bea48cf03f300daa13dc0c5256806f8beb40b65fa3f8503a59af32ba7fe79939ecbc315fce4f73ae7d539fc51df5c81f208094012c89023e1bc4920a3150b46439fcffffffffffffffc2836884b6196b5f2699a4d43fb65e9f93292599524aea8a507fdb7bb1adce6bb700705002370ab70a2a0b6783f633402006064ec07808a3a48a09795f762b7b3b7018c25829438599f9948102331e8d11b081a310e628ae57faf7251fe28430560a3955f2e8312999580d1c8330b9a85c29994ed23e98046112426bde9d754e218a0261d07d7969a132cd4407104693e521f7d357d7e40fe60ba2e53fb473d4b2f8c1a0f7df345674b793d70763e86041041737efed2c1f0c6bd97abda71bd6e93d184497ae9efc5c8c9f9881430f063993f263296112dd1603471e100d0e3c1872492a49b12d6b2a5d068e3b20871d8c132f3b826ea7856a1403001638ea6078ad98aedfd9a225a7834955a4eb9a373122c77d1b9cbe2570ccc12c794be95eb864acd982430e5d8bfa49b2f3ccf19a0c573150b0813478607860666046197130fe7552e3a1974fdfaf070e389842ee11d52945d7f7eb0e1c6f306e8dbe9896f466a204898101316c6c1b38dc60125f5ab6e106071bcc7d7593ef53487a13101070acc1bc9ae57741d7a5d21b047567dc020e3598d5c45354f6e3ed48c958ab71e36f50461a36520d1b67a41a957fa38c1dbc7f192420f63ab091032788230de61093bb64954b86771a69f49a064ca08292010e3498b387c52461225f83be41195380e30c061dfe9e2fa4b012a5b4c1e9b7810dfa0635920d1db0251b3ac0097098c17055f24d25a70b950f9571018e3218ff928509db5056bb93c13022fe95bca4c492c818cca9bbb2b7544c072c050e3198a3e536e1f14708cb3a0c869c336554cd4704638ca154e00083e16db4d5271d9f274f38be60f894945f9dd6923eb91a26070e2f985267c7e40f2a2718630ce50347170cbbebefa72b574fff655c000b1c5c3057906a7f41733150000213ac81630b465739bf1b09deb5d7c0cf000187160c2178fac64d9e4923e1c8827135ecc297b84ce0c082c12ec7df8591db298538ae604a5a44856eed2748638c31ac803c930bf1c55392048e2a18c73e575e388d3d1351c1246fb174ef6939a6604a634244106627cb13a0148c56aa74a9724f0d237044c16416f1da547fc4fd13148c21737f36436f434d4f3007a1baa7f3236278de09c6ebeba4d7e72618f29d0863ea7cc276ce04d35dfce533a14e657909a67abdaf0f2b17613d4a302515d45e5e11d2c328098657fb71fb2072b86023c1d43eb69eb49e490e3a828d911c46e02882f9b292522907217663250229824ee710cce152cbbe49eef0d86e091c423059ecfb750ed7dd49b5040504c3a419174f9d4812820c0cc35f28ebd2ff22ed41c55cd0fac258226fe4dd30f5c2242b2cee93887861eaf91369e3ad257476615041d72bf2a90b53c8ad203ba48d94839d0bb27857c8d6a6ed1e63d973f4c5195b3109e38db791831a4b06a100bc26cc7b5d8d7c0b835249453ce7d71686fc513c4c8749a6c5ad85717f84cc979b1626d9ff9d90d35c3ca9b33059c8b8f0105516c6f8adc94959c82657120b73b00ea33fe8242c0c3ff163c40e93d542f015a60e5a34b55baebfe40a536e919ebf9f43c9cab5c260c9266dc6dd5cd28a025861d0cabe52d12ec53dab30a8d9114ac7fe51492e551844a6bd455c3f1559292d3fe975428521dfa7a97e855c21994e610a23fb22a27fa776c9146657b3acbb5ca6564ba530a5ad0cd1331e24a94f0a43f851ba4cedcd24ef4761f2944d5d52e5a5f14561cab75a290579288c7212dd84b8bd8bb183c2e435c2528c2c132be29f30bdec7dee2f1d2996ee09d37e6f558ca4d309e3a5668d50677db23c9c30c7a9d23fcf3e56a9b30993d25b39450a61f683ad09739a8a093a6974084225135ad70861c23023f1b2043ba9e1954b98c56554f6c92c215ac268651523e71257c20c5921e694982961708965563a65ad09f224cc7e966c7410af2a2749984f6915356b3d267a244c324ab456f81bbfc842c22897bccff28ac7fff61166d1eea0ac3ea7a4e408e3248addd908437e4f759e57216c4698e4979658f2751127a1bc3c8408524598724a1059eceee74b4d84513f449c7017f4e85111611eb9172e589ce8f9218730cebd5d9e53223f7c8821ea1b359284b4904298e25fd8ab6f5d8e242184d145dac5f828a195e7208c25f47da49935152a8230d998aa88b6a022693110a6549e4ad47f29b32002c21841cc6bffff07c3ae78ab5ebeaf1ff9a130eda7f4b3de0793e88fd65fdac34b870fc6d221f7e2a9f76048fe313c62877f5b4f0fa65879a62f25793089ffb7d3e21659abc38321d7e4ce509d456e7f07838ef2cc0e66754f2289b7eb60f4a03da4b42cdd4ae12328800ea6ec10dffad91ead3207b387d6940fa2a5c4dca2003998fbf24452c943e26048dedba17f3412a4a100381872342de35b6fb9737a83f9822ef5f0e979544e6e30ac6ec9a888ccf5d1b7c1a443bcefbd9899be3e1b0c56c235363cc6f885d660c8b9f9e94ca538b1e36a308d4895eb2fea6930aee47cf1a9ffd3480e1a4c419c9ff9aa256db13e83d9a468c93035aa92d56630ccc752132929cb099532982607bb6b13e299a3420663878430a6372a5a5dc660f4dc29463c93c560f211b978fd881bb286c1385b51422a3d35b925188ea12a1b694f5f3077aa7fb76a7fc88f17cc4976bd85a958296dec82b992fab64acf3f9ec305a35795aa0bf5313ebd05e38d57e70fb95c49755a305e3a799eb3ea3afd62331490057387e4b69792d2e94fc282b1ce3ac9f8f824e2e8af609219aaa532defcceb702e2773c96fe1155c17013f594d4ff3c21712a9884d6c4b4d27fe94b5330e80af627642b05937cedd25e9d4c27d95130bb752cb3ef0a14be74332f215ee509865b8f717146b632632798f774cc12fd9eac83b609667935ed977a32c12cd721844b30b5b2e112cce925d6de3a68195109061d52e6bcd905e1d725c170fed1c727f9aa9690604ad53152f8ed9e9c1752c01130533119c170a942d07d9db37d9e8a6048c27a72ca257be3f40a208241a28ca88a91ec29e7153004a3a96895537f4a59880284604a9e7a3ec5d472134ac13088a50b297e47c0305d4af2c182d07809fe2f0cd739d4e979331dfefac224b353a530b7f6c278313232744f5e9842faecc5d83995f3db85715de5e6f279498c5917866c15c53a56f8503a940b53ef4e8aee2192880be2c214645e97e81423a8945b983dd6fb920ed726c01606196d73f772511e24a016c66eddbae461e634946861f0cefb984bf75039cdc2a04c58ce963c5bca7564611cabfa4c11722c0c631fe729fc75953861619411ca530435aff6ed1506f9f3a554541235b62bcc2dc122a41ccd3071b5c290a3479a5821ebfb618549fddbdd53bb7fd87e1506cdb8930f2a5bfa5d15c64c4d0941881cfa74a93045319d5efc42a830e9b85fa9273f8541f25cc85cd85870dd14a618e1d44ebf530a8350572e661b290cd1f6dd763dcde8708fc2144edc4589708bfdb6284c7a31bba183426190dfa1e6d2749e561914e9c4cbded922fc09935dce8e16b395728a3d614efd6a3bf2e2f5aed2099356779ccbe179d3b39c3049d4ce92266fc298b7d6313ff5cb6435618aa73aaf6d24874f66c294a447b1d4b09c53b5983025b30ed94a5bf457f412c6dc52625da3a3a65ac2e09f442e91c4f38e48254c395da570e96927344209e37dd09fb2e53909e34bfe78a6e22909d32789332af983a57889846946470d4f199e119c10f7d596c118caf4f2ba875fa64a06c3ac794839e1ef434cc760fe9338b23ea204f5a71850296c961695c530983774de5fe5c748f20383d1d2b8cee7ff0be62496e339a8a4eb6e73720ae2b36c85e5d105a3c950932ea9d86c2b3db860b6d149c731d3cdf46f0bd97552ab164cb26eaa652b5ee66264aca14fc306b2db814716d0f1f3224c23076714d3838207164c65256e94e7b42d3cae602e65639ea2468ab896580d53567858c194f74a4df8ab2c964c457854c1f8d1ffe2ab04ddce122a98cbd2c80efba78318a76010b2ffca76c7837b09111e52307e89119b76f9fcab838228182325fd9b955216f0808239c78b9e9f72f48f952798e5ddb479d0179961999d8387130c3329cae51cd63bc96f341924f06842422fcf621c030f26982485cacf7b48a3a3843c96607a5753b31234069f87124c51547c3cddbc637cc85813030362dce06d604c108210f095f64882073c9060be8e707b3a3df668c97dc1e308c6fc7cdb17ebb81c3f848711ccd142463df582ae24d2078f2218dcf334846bac6f8ef2e0410453e7aa4a975b1a824988bb4e6ff11082e1a4ee894a21f4c54e308c7dbb9643b9db48f081618a37b12e59857e61cc53162d5b12b71c725f186b3ed552c3fc92e5bc0614111dbd30ca8b0e49bd041d7288f0c2fcb7b26f21780a964cbb30d90911b4a4a02da8ef7591e75cd92b9872a1e5647fb612c7854105b311b9c27912b2dfa21c31f2a70eb3a0c316e6be9c5417fc24574a1203033d18630c5344472dcc9d35dbce9456684f6961d02968a8b78549299a85c15625260b53ce49a7d873652c4c3ae5ca93ccbaed14c2c2e069da74ce64e5f4b98e5718bbdacf7792fe77571dae30699af4371d2a3ce7dad10a434cffb8dc69647f7d32f6d3384304638cd1c10ad3f864356bdb5c0997d3b10aa3e5fba0eea49e19e85085e174e8f939c041a331023c0f74a4c2e4329f7b2c8ad0b1827fe84085a923567708ba7c63c5e544c7290c9ee6f24254ccc841aa91c68d33c8404d7498c29436fa417c45aacf3db071c6096eec253a4a614ec173e62d78e578925d1f3a4861eebf35f959234ffe2cd101d1c1758cc2a4c39d48e695547aa92c0af328e195b2495d0c1da130689c27bbcff2f711ae403b40610a955eecf3488aa1b78e4f1824071d545937de0639b041b6c3132695b835264f85d1a771e34590fa848e4e985e23453f51fe196798e0d4071d9c305dcbaec7db0f196bc4522a2303d9b10983f6a94b8a569d674732d68e8d336e9cd6343e043b681390232de8d08439f27ff220642713863989f712a29fd26562c2f4c94eb2dae9507fed1206dd79424a8f9c3aaab584aa23e62b4db850072a61d2da2ed692844cd94dad83128618579683b02c49e19540c7244c62419c4823e37fca27634d67604619356ef40cce6a7448c224af575db2bb3fde8f84e1841ed562112b749f206188233ebea894479867c4430425b28e30c6964e12b2cc8d3027dd2108310bf3fa3123cc5d2b41ae04a1e5aa2dc2a4de2ddc27e6841cd48a30b6c77f92e93a237212619ee41255b54584b94aa5646f7934d0061d87304dfe9027e6892779ad210cca2f0511b9301b3b29842959ff7e8ed157f33c210c9ee3e792131984399a668c87b06d7d16411864e4a598b33810a653eff944673e7c5e0161bc4e3aac94bef422437f30be75886a79b0cde81bd4b071460d2074f8c13cd79ff695ef1d731f4c3a7ae3734c5d7c9b3af8601eb153224da7875adfd0b10793698951e93f7e435ec618a30c1d7a30bb8952ba9245ca65e7c110d79385c8e94e2733e1c1bcf93d16376542cc10093aee602eab8a15254f7630e959f96c48899192b6a30e86a0b23fc71ef5cb693a982559306de95547a890be3107d365f5f021e7b782fa7230460e21fff563bca6280ea6b9601eb7930eda3c380231306028820e3898fbb44d77fa88625f7983b9e3267c7b753adc604aeaed6404a196efe28e3618741cf16f3a5eacc975b0c15c322a5b6a0f95f8411d6b305d57c8cbc147fb5dd5a106534e1777429851c971471acc29b376245af09c67d4810693b89265f1e2d67106731e0f3ab23aad7b3a7598a1a30ce6da8e961ef9e62fcf64302755af9274cb8ba5948e319894a5d457d9573d9a5087184ca6e25e59f2bebeb07784c17cc97b84ea297580c1dc9e6309d9d1449e24ecf8823154dab0681ee75e6387170c42f99ce890e30a7474c12caa62c988ab7570c16ce15497752a756cc124776fbc453fc2850e2d18af5ef74d05fb3897ecc882d9c4086175fa43b0bc93b156b2091d583078593ce541e92041d664dc681bdc48cb29745cc120b664bd8fb0a07492c6df60247458c1249e9752be824856e111dbbe362263ed460dfc8c8b4207154c4ae7f34a7491ef9b2103c10180091d5330c9deee284b21edd26a850e2998d2547ab31ca794fe3f0a86ddf2c841c72c31f291a1030a26a12a28efef70161d4f30d6571e7d227a6adc103a9c60f6d4a347848409b9e464ac1513424713ccee275e4b54aa850992b176b68b0e26984daaff4eb0cba3bb97e139406f63cd3a96607cf5908210da11a14309e692ffd68cdd8f5a0d6446d748c3df868d331c2f0523400108c6188334a22309df46d01e420551714400f0840e249842fc3ec9ed18255f54888e2398c37b12570949449f91fdd0610493d23616ef2f8fd277923d7414c194ac2e2bfdd9b67ae8120f1d44308b4851b27c5e8e4a7a1d3a8660f8d7c8edd194086b4f87108c592167f4ffb94bce81812318c6eb30c2e2538255489bc0010c773e8ee46f512612387e61b60a539dd86eca26cbe10b47cb9caab16ad4c0cb40a30c397a61baadf06217c6a485928c355e9894f6961c612732d65e0767d84083ecc2fc966cb764f9cea582347270460f1a0417c8c097610305638c91460e6e705217e6fd78b23d89989eefb3326ca060066694a183336c90a0ae56c0910bb3e849cbeef87061f25c953c67d3e9d3ad5b98635bf0cbbfda41cdcd610ba3951ed39da487ad7a6a610acbf38e60e1bb744c0bf3b55e165521b48fa924143866610ec26b525239fd39aae39085d9de544bf4b2da4a411cb130e8b855faf6179f4212072ccc398654911b59626285e315a612ad4ed656b6256b0e5798f4a7f411b4b3f5c511472b0c2ff973be37915cf671b0c26c2f42eca8a45444876315e66d13fa626dd35694f4c68d37430f8d326c906abc0eca4011b8a0060018c1a10ad3b6c9a7f6df6eddd2e04885f127d68358c5b67d97a83064b94f9f2646d0959392e31486590f49e280c314e6f46b4a59104ff1692e85397ad22108f70bf9107c3446200606cc18811818e8c018637090c2f8f964a8a8898ec214d4d57a5f885887958619efa2c83cd6fe509834b6d4723c670f7080c2587ad243d076291f1232d6d0b6031c9f307b780c612d2f7a47ed9e30a5bb1c1fbd7119a70c393a618e3197191ec2bde3be64a0208b15383861ba60e931c7b38854934d18437877140fe1ff276263e0d084b9e4e64f503365c2144786b22bd3bfc08109c32753b1d2449aabc0710963aa9ff097fc1de32e352c6132a1449f0877f996304725cc5f9574ce7f2ea38451ee2eb6fb6dd44426b1fa9998ee08faf693b1468ac02109e388ddd115f73f1a9130868cb8723a1f27fdcd0109a3e9f0ccfa0d353a35ce40c6f10843d2ce12ea16ff53ce7a60e3735002fc0087238cf1d9b2875ce2137034c27c65daa5df7eeafcba4119c8c1089350a224690ba14347ed171c8b30c8336d51fab4894990220c23f52585ca3825a3cd011ac57024c274255b95c389c958eb341a751a9d81b3438439c4d39c471fc958db47b7349694868d336ed80dc26883594250dbe1c43ae80f1b4c6147aa4593abf1c1b20653f64b951f5613c7623518bee3dce28abc9d531a4c924288cad0a2c198163d480b5b9fc12022e6b283f97d4a9ac110abd2fd7bd3329854dda4d86d12321852f27ca3151e4f98c6600e537fcdcf5a621783b9de47fe23c9ffcd1806f37cfe9f705142550583d1de4b46f768651208e30ba6204743ab68ef05c3c758b270739bbf6417b0ce26d404317a4789b96012c9ea2b56ae101e4f1b67e409630be6533284058fe4215ed1824988faf82d162b744a66c11027cb4e106e95ddf5c0461a663c89411858305e5b95eafa3afbabac208c2b983a3c5e88e65ba1d5b182f1f397d896ac963ba5aa60aa160b299274cba57c2a1854851439cfc147dd3305d3dd7b1493659182f9530a2e63428d82e9f4d9aa7cdfc51625148cb17f925372fb1df5134cbdd96155c24b92f085e104539ae7f5b0939d208c2618648616e126526ecb1e0cc26002f6de273bff787f7210c612b09453c4f7ca49fd26c377108612cc7d236e7e157ebc2c1784910493fca9d3eb9d173f289d9186191d20411848205dd6da35753a0c8871c836d240037b10c611380c23a8f9e93a240f855104d34e6e65ec056da4814618443098dac9a93a23faff52e36d80c60dca40038d36e30c33126da481068631041286104c31a2f5f3920e1f3a45c69a06c6182318a6687d6e23929c6c42fc018c740827dc7d2f4670f0f10b435061ed93529523a4f6c317c6f413c9d94ea6ff5b7a61ceb7f0218f5e0f0b3f2fcc25ce639998eff0b6efc25421897cdd7186c3872e4cb32729ffc80e2f415d7261f6eb38aa53e592f4d4bee10317862826afec736b753bb730974549410715a4a6986c61aad634fdf079265abcd4c2ec914ad6a79fe546190b820f5a9874d8b8dc7df92c0c2a7fbf1fe7e9e2c8edf0210bf37cd995ca444b2cccb61e210513172c4c25b994b6607dbcc2b415f9b5a4e7ae305ef0fce941eb34444a2b8c559b16174197a710b3c21455a26bcf9fac45c9c72a8cb2f19fb2a8bea99c25636d35f0a10a735f9a9790162d7a0eb1c0472a0ceed9f49da77b8d7f64a4518619638c199851061d3e5061a7305d4e397448994fe2ae0f5318258e38f9a92b87b7df818f52900f529852860a9d6db370d9761406d7d1511db449a9f0210a539e3d95f2b89e1825e64728cc215c298b1eb2a030b75558fb089553840a0d1f9f30ad87917849a924af2f9e309b6993eda4e2de32a265f8e884794543355efb635cee8313660f3e3a8470f98f4d98ba93c8ac905532d66a70a3d3a8516ae34313261d43cbeba578e1b3f6e02313e63d19c1d2363624e8c607264cba7d9dc289741f3e87c6c7254c29e5cb49930ddecde81b669c618605c618037530c618a800c0c587250cf249a9eb590f495755ad84c96425bba4bf38418614111f9430ede8a5511d2d859c3a0e1f933024cf8ff6f24149bc21b14f99928cad8183bf71fc1109d3c70f22debb95c6dfb861010c70400c0c8821821168a007e4111f903048cf8e2621761e611295b91a164e7bb54a8b0f4718ed3bd88e078f7a154d679c6183046cbbf868842145f21073f11da45a186110f727721e7b89f7e5224c4129ad7f31354518feab5a23774c909927c2a4cbe646cfafb347bef081088367f7202c99de05391dc2982ad142fe4ba4da785cf830c47d14c2a4a56321f444de9e9d091f84307fae3c158bba222ae4c2f0310853b84bb5753da7eaf282308a7653e13c53d72a1bc147204c2d9e1fc94b8aecf00c3e00610a6d12dc428c94feb7910334ce061f7f30ab8974fa6247c6a9948cb51ef0a08c5484061f7e3045494269fe763efa60922c626fe9bc2284341fccaaa6246509eb88f51e0c1f64549c9fb01ecc67b222f2e7c98339c99e252d953db6bc2a7ce0c174f59323c7506175d28f3b98b3a5eb10dba10f3b1896e245855d4cc6da1563c1471d8c15cf4c7c96243a986c52994d1a1532d66e2033fa0c4f061f73302595836f9c0e231ac21ea45106213ee4600eae5931b392ce103a7571c074459cffb87e95ac81c68d3a7cc0e1f5eb9873667d51926f3042ce7c3593967a4fe30469860f376479e27ba54c64d369433733f14f48bc78c992870f3620ff392c8d1cf93da99e1a3ed690b2a85a97730a4a203ed4905645f0f865aa19c23490beb6f78325870f34a0426cbce362e9ec1952a1ef74e912bd916f0d1f6628ccb9fccb778847e7f0518666b7829ad193c2a8c4c08018221003052010030377f82043aa6a219e923de1630ce82efdb394b23664031b29e0c387183c73dd0b27bb33d20b43aa2f1792b42fbe3330986639463b2baa46cc8ad9ed21044be1e1e30b065162559e23e9875fcaf80037e1c30b0695b3e4eaca5df615ea8239a8357517a16142ee5c307ae9f270a65aa9287c6cc19cba2d651bedf92ab5160c9264f68d05350be63c31dfca7a7bed2c5830298df89aee6123c6750573be8e2ea2a276df3d2b186c4bad2aac5527cf84955f86f041059350495dcea65bef43ff988229e74a9db746968241626b8a897a11d1520b10a2828f28782962425a8da806cc28a36d6440a16008ba744cbace4eec0b0a1f4f309dae382295b897f0e104939abd0c611e84c930d9f86882c707136ef4e06b50238c8f2530e0430908f84842033e9090808f23dce00602f830c28d1b6f038e8f2214e08308370881013e86501f42b0810d1a0310f00886033c8051a30c342c40820f8f5ff8e2d1195e2307bd3880072f6c6083f60178ec82c3431765a06181303c72413c702186c72d08e0618b5a24c08316350ce0318b1a65a061811b3638e30c122cc043160ef088057bc0a2461a08f078c58d2fa30c342cb0810e0f57d428030d0bd8f81ad83863056178b402fd0c66d0288880072b6eace2c3431509f048450d0578a062001ea73080872908e0518a007890c21c2ce6e7be2c29d6ef0a048f51182f646ea5e4c87fe692b1766383e0210ac34910d533b146e68743612efd1a4943e5010a939795bea825f4f8842188fd91952304356a2a62a06003c80c0b8ca145f0f08441447a4bdd0a69545f88e0d10973ed6b856fcf17365f74c605dc8c1c68608c1f7870c29055b4e38ea4cf61271e9b30d7759ce84e5ae5c08d31c6f0d084a95b2e4fe4f4f1eb7c076760608c3170e0910983b25d55cb63c00313864b52dc7c3b889f1cbe81c7250c49dec48a914535f0b08431aec4884e1da37b66b5107854c298a5433db59f2861aa39cfa5b233099387081e1f4aa83cc2968479c4c4c68275f49461240ce7f9644e529ed35307097358f12e91bbec3995c7234c62f27eec43ac7a3db081027f1d98230cf9449a96f9eed108c35c3c7d532fad6e71469894322daa1ed4a5057711a6bb0fbeef29238ff03c1461b2e8e2315f65e75d7924c2b4399ea59727951ccd0311e6e46e2a4832a14584ef3d018f439836e5c3488d943394da109efaa8daee17c274263f8f28bbbd9315214c725ff9fa3482463f195c1e83f0f36c49ed3c046188752a0e84498a560c08737b96f18963c2e61a68dcfdc1a43b82be9b14fea94a7e30e8181f6fd4c99cfbc4a30f06655afcd26ae8755ba306fd364eda7af0c17cbd22136b2f1278ec616d78e881a453120b0f313e66f8028f3cb89664a747ad8ebefd0a3cf0606338c2e30ee6203ee94f6ea2ab82871d4c7bb22fb6f809cdcfa981460e6ad4e08c336cb0251003036280400c1480a0e8c0a30ee630d76e6b13a2e731d1c17c67d7af1e3c8f39182f088ba24c720a49a1871c4cf2f9ab3a2996a59c338f38a4071ccc39b669b57791c71bcc7daf6e2a2fe8f627b3031e6e387d8affb63b95b6e191a4d54b2663cd6dd4e881196d34f06003713f69d3b6ce93dca0460fcce81a37ba3230c618376cd448e346bb193b3803a1c71a4c6fb9748732a9c1aca743ce97143cbae9a4c13c729d2a4c84892829683097aa8f92e44b1471ee194caab2ddd26a78bfb966305f4dae907a30a9bcf72123e6e1bab0248456c933e1c19c435b78cf967758558488d2d9c15cb2ab73964f12ecc63a98828758212b6685db74308baabf8e16f2dce53998e279793cc92feeaf1cb8582faa447fe26090951622fad4a8b41d1c4c4905d7fbfe10cd4c6f400303dc601cbd922d0989b5c1f4e5397c2fc60643983753d3f521a4656b30ae88ce3ad594d3613598dbd4bec47f7acf621a18800693d07be94756673044cd0d8b55fb494290016678bf52366de16bff736528cf579678f82af7c9603c393975f544977cfa184c97ef3987cac8adff88c1c9f1b63dd49f9b1e065318e97a39444f0c910306639d99327f516ae4ec2fa47223e547574b222fbca572178c3e422871cb664a81015c684f655d4656ce16ecf3a0f447bab72d5d0ba5f39c6654d6d6fecdc2215bd6c8cd8b61420103b080a7d71c193978fa5ca1ec17747c39252b14d143845827a2df2a5c1e7794120b217fa860921842bd6be9cebdff144e7edfdad1df3a2978c1647b4a416707191085435ab38a58595a3b28607f3259d4e49ff8099f095f1d8fd59d7342365676a31d235e450c6802327475989409e414ecd4bcbdc29b4b40bde3ed56deecaa90014af0d2884a27843a71332009a59633292a0c4002f2e3c595fa08c6d1972c45eca4b4b2114cd1f524c50929025a548a949245b1141b110c42c9f814bd7df259870143b83d82bccecb16b34d0c10824107d321b32b899fddc140e959f809d3253960984388da294bf40b436eed911dd717e6f41c948efc25556a2f8c1bdaa176262fcc1f734df4574ef1bbdd85af615226e88aab31e922bdf1a32d5a59bab97023e9911b5e41f85db8f092ef9f0a8d6fe155ce3cb3493b3a5b90e7f5926ab530d8a828c172e4f7f8d0223b1d2a84d12c0c415285121e4c59a43a480b1553fa7b2c529193fe38963b395868a63eec45ae3a855f61d2397c8ed45859dd15caa46829e47a044b2bf8be5049c9911c2b5afb4e6a3f8818afc289a9754a45d57454e1f75bfee55829ea5498c2e6a4921d0b3d294385c14743a7687f293f7d0a934a21757eb1cb7e2f0a0b30853959c69c8dd2fb29924a610e93e396fd8c07ad3f298c7edf4994b83841c43f0ab3950896c34b4dc4f84551bec88c89cb6b288c236eb3a22561541228cc412b451555a14f1892cab7b9e81f12f5e3098350d9bbde743e7afa74c214cf6d5bf2af085d36278ea434bfbf4cc90d954d18cd752d9c12b226cca73b2cb4d794fe8b33618871134e998e1f36c5c47a1d2c7c76a77bb92f61d44d3d6521a7a4476a0bb0844949cb4105f949859754c2146a65f2c84b29615e8b2264a77021494a27815097f36479fa699230473bcf22e6bafd4a9130e48e94cc2f04a57d26244cd5e7c1eb7de7477f8471c259289323c62b4447742179b776c5d04a23383bcb95ad14762246182ea2c7bcd32dc29c6d5bde4f8a307f9555b8f6dd5b3711a63f53df9e3e879e1043c42bf1b4f34e0e6a3b4431a9bb5f24ba7c0c61f48a704a843f1d6654089334bb4f2a2949f22d5563c1b0004218c2e85c219b31263b6510c64ba373d2058f2823fdc2020491cea8c9d9de06820f12a2e7ea7ad30362dbeb2c1ee1dcc72e7f5075745ec9048ffac12054bc4f1f9e758f9b741525870f86a0e452b22e8fd41dc28505ec61ad2d9110947a3858d03e696363ed3c984f279d922aad9d85090fe80c2dfe3d498864f13b20d2da32353b989386fa89abd317aeaf83a9374f74a8d27fca79d405cdc188223b25650d9197433237794b88fba97148a86ca9f0fb210d07934edb177c674d5aed6f604288a6748aee92f2c80da653428a9c644adb5cde0663a968699122365c2aaa04b9db1accf9469efad8cb97ac06c39f48a583103969b83a42b85cf30a42868682cf758844abaad319ca67deb1b47274a66d06a3e5b0f859d75b6997c154414b87d2ebc89029b12be93194b52fa6a9899dcec2627075c6b32aa4340a83414e6acba9d34c4f70c1706c91ffa6fe73aaacbef004b112c7d2f45e30e55877e99d4a871d912e6031c4ca88a813ff5f2e9c75733f29fdf3d942e761f611625eda73b5902e2fbfb2c05fee4fdee69d16164c61299994246bd7737905254553a3c368d10d1d2b982d455d2e76a4492b56613797943ae8a95088262c23a94e5f9a42e2af33e3ea2c2d05d3e94b252feb8b422259758ab8bd408124bb4edba40fea53fe09a674314b926c277095527487f0f14b13cc2656742cd6ae5a9609860b1aaa4f65848fb3b6b0802598c3cb271de4eb93ec4a30bee59b28426c88d1a62474399ea1e90290505297bc69c9439ab5802318f3928909cfed93928c6038b3f8cff98b6048dda5eb927b2298820a226b5c12b1da1e8249567cc9e593ead287162004931e35af95b907031193456e74c0309d9874e661ffc220bc4e47febca4ea7c61b6cb23ed428d900b61f4c29cce4a5744cdca5e7861ee8bd61d17f35df8f15794c812d68549a84baa77252717a60b49b2246dc28529277b95ba5ecea2ea5b9892127fded52962a98a2dccab7a9a922b5c0bb34dec54c14dbc63480b438e53114b446761d2799de593c3b996b228ba08eb148e852a13643c448717c1c2bc13b322aec809dbf815a60f4946da89743922ea0a5365bb9c9cf89c2bc55a61aa5211b34e1d46c594156978bc8c972454d7ab30e54ed172c98dc892a20a9398e0ed274723473415c6f6cad3a67f54186b52fa58e74e61b214bd6db9f4fd2a628af7de53bcc25218e5ef629e5d69e47c92c2789f5ac9e36514e6ec14bd7f3d8ac294963f8c94a82a59140a7d4ba48fe381c268ee6945825be8b57c828b5f732967957cf27ae21e2d173d24ffaaf0e984499f595b291155173d4e1884458be623b409936e957a50353bdfad268c575244c676eadc936782ff2a516d499830a9bb49f95a5498fc12bf889b0ec94410a9f49628ae47bddd5abba412c6f932955a8424fdcc28717cd3218e9787f52661d05177bbe32e6f7e4920ae3e4685302281c93ecb275de6d49030fba85239151fdd6e91b1f60843bec8a62e7e658c46df00c370049eea6147dcad2935824932e691bdab2a8597a0a1e24f55901f7ee5a61d86c10893a7702742bc24f36a2fc2e83977989a7db310175b43188a30277d229e68b1a04350224cc9f3bc696d57080311064f41a9e77ab50baf1cc2f4621e57c3574318249d909594c8dd33b24218b3439dc97a09cbde12c2242c5bbb6ea73cb9a04198b2754f6586ba76d205611256a35f94481372cc0361943c4997d5a5957705100639a264d49af40fc6d1b553f14ca77799f8c1f8b9f6e1aa651f4c91e25f25f93a1f4c49a848496c3c5c2e59187b305ce94e6a4bdc30f470505be16ae4e9f82935100d61e4c1702ef36f957e9382e4cbb081827c4018783068939fcc4324a5aa5abf096e9c51469211c61d0cb1f77cf34cbb8248dbc1a0643c3b9c97e585b80e26ebed1cba5e9e1cdc58d4811f844107931239e9fc217ba553a13998fb23cb049192eef33a0c399874df53437785187799a9851107a3e6884923adee924e8283713635df82ee1094fc6f3024cb101e1e73371843a7f0ba038d5ea8f4af6652612012070402711c045248f51e00c3130010404078441a8bc462d13c0e85e1071480035228245836301a241e18161808842351201404844382502010088541814028240a27e196ec03ab41f74a5cbda0cf38737cb323ed8a86cfd25657810116da0600aa70ce296e6ae67566a0e70b7654604720f737c5c02e0d64724730741c6dd034c8fc50bdd6880191268b4923507cf74d766582231df89f0599770a1a4c373db28b2b0e747984ad00cdafcf08c0997b5e6e6eea267b805f181beeb6aac9539bb444f24f37fc683c9ca949faf447fea535fe479cd290c5f455fae73b6e1d5cb06d98220fc824eb376fd0c1de1d4480b743ac6e74a47b0f15e183e4091e968a808de6f2541c8e584911c341ca0bb86b6c938d8b7c3c2b5b544b4461523983f31de5922592fc69c79a4524c8671d92de4c7e09eead39f5d4bfe1a94df4278e6c79a33ca999541f6dbce7ee7fb86a418d54ffd00120f8140dbc9d22f28d7ebb9f1dee3f4a15f72cbe0681c61d3aeb4ed422a08aff1d39bc1c530481076fad49d9cbd92fe58118611efcd5e88ef6c36e3b08c946c14b908e148a6dc8692dcdeb6d7b5af9ff140f940d20c69f84ff2d9748fc199f7c0bb77bbf8d53bdbeaf305628eb7dd3512db1809933c2bbff7a5fda6e21c36a472e0fb4d899ab41175cdde6bf844c934671899fafe9b6045225aa6d60af4015ccc7662a87ee9f1d9487cfe553ed082d1c63fd550089f109f0a6476ec7a7ad90111def3be9d273a26aa725beb92225aeee3fdc6b4808250dcc5ef550e2b79094d8a6a18a5a039dc6d8357c3774190f03370365a7a63c1c251171ae9748682c174f23718da31b7e8203a5cb808e5808638d4d6dcc72b807b6a18fc51b26e5a233c7511c35f57d8d463b36ca40ebd4c484661f9c80837d1b25c6513ac446e73ed07f0e9d13fd339a4114886b7d702ba65328781a479cb5bf8ce1ec300d47a91f363af189a59d4e56ea9f7b9ab99c439bd905f5c0513afead53f1b3046c811da319a4ac96a56eb9ed2007c14672098d6710e0e0debf6e209b3fad0c9146ff7e6189d501df8bdd8147ca7b8f21e8e05ea2633757f4e6f3966859bab60e8bb5c1be05cd7c762000b61b38b6124703725a8808cc2d040efdcba015185262701af9e67ad7d2d63104284feb64d6eb5f0993002109aaaac1112dd71c4e6e0b4bb5e4d97cd9d90ceb3f0e98260ce2bae69033045f53409dfbba11a06654e95522090e53da0559ce056640975de35c9600f50932ddd94450109a84a94701587bffa21592dfb9e65012a0fa4773ae11140ebaafebe8fd28132685d21eca13d6a10f9ae18ec94421dc56084c35c66e1d1eca59547ad0fc0ec170bca1abe70d078bd5c17ed7772e7effbd63e4f37c520dc8aa5b2a5dd5887f3a93080e6504827ece1014f80622f0586fd0d16ab76c4055f7ffbba49c96edef3a47c98e35851308cc6ac01b602cc3fa2f23a0a7e6a87f02ed28826339280daa37f1d8ef6e28012ac3b7992e2db11c3c4767b0fcd54f9a2def88673a7a85ad3d44afb14ac087e5771d3c87903115f818a8250e062f6d1ad0383886173cf08a56cfa2c142da31174c58dd48e3914fd2ed80b49b531898070f7670907e822dc10d19421bb4d67440104da63b2a891a3ca4d51acf651f3c71e361870a357836b71da9ee74a069a5b6fe107877373c9b81ac41405283634e106755661a13990f1ee43a58befc278558c50436c5fdb45d569720729a7cd112c1206b628641d3171a19641d5baabba99dff00902c5ce031d27cee7732841421211974f0002e3e1cb08387e50c1a123dd7dc2192f560b40032b1c1f30413780ae0e0715db9d5c76af008ef83c6ed0f548e6a0d9ee7a387811d6507cb7d0d40fdab60c7a3f11fc20d9ec428864318099b40e6b307b4583b067722f1f9925eb156d5cb4058ea76f8be871624460c1a0669aa32683c0155cc4212c68ee001f6e97a29fa702c27bb2822a855719d837524ec18bb7678848d649a3dfd5dbbb5ff0073e0de55a38c9edb7b04a6dd12d71b34ae2dde6aac54b5f57a3d1efb775e284666143f458a510dce73dfbbec702304ab4c344334181886046dc4a1c66408a01c8b2d70ae21424e16835246a5346d0dae1894169478c33b565351cc4ca7e176a8e929d2614cc0e98350313f9e1584987a8375820e80054cd8f0c08b0e06505803113633f98021e3e088628c88c30ad93daa20163c484fc40afd50a4bb448f3255450e5a401a0ccca1b83c4e32bd7500e94f16a58d3b472e6c8135694c26de69913c7710d4a8ca034d91f673434fd44fb3e5691d2add2003467379045a5d75f175d3db4231ae012afab4ff57c033658c6d6d4f6eb167658f7e374eeff55ed2110f629d4a028503cb647c662edf598abc8f49fe9b384c8d9fd8c05cd5af0d549d3c550297945fd5da01e83faf6967c602eef7ba0baa36279709254d0da59235a64a31b69feddba8ab7b6a2354f20fc11ebab08f3e441faf066b10ad9b25ac15ca5516837a0861300f507c4e244389afa32cdffd7e37eb3294eedd42b1644ccbc68a20f37635b74cb661cf4e9445865d99cbe342c009b91a06000b63ff24116ce487b11a992c81c9b9db81761434f949930bdaba7bbd6c038d55283df3271dd4e7520c73008b4737df2c31aa1888f3b0e1878b1cf0b921327884844bee5a714bccac1ea25bd7f0f11e1b6e82f1d96dbe6a0d516fe8d1912c35f05a0e75b787ed813de8600d653d9c6b17aef7d2fbf5809de265ff366719869ee80311899639a26019e509f8151c866ae27e19840b2463f1408e11784a253050c4c141771070e9670e5cadc8b03d1c743106f610bc51c4fb0a2262485030b4fe61fa81a9fcdffce8654d55a8bf96213db4db24e8f92428c50414d5f7ea1db0927440a7dc31df51da2554386a7a54a906b88bc36eae965fdd8d8657d007f771fb405e35798557e9a6009aef56e2fa71caa281d2d71190a7f09990632fd0a90bd39bf0d50cf8b1a02981f8f9c18c838a061083a9012486c106702d84a56ae81d3e989721f1561cb282b4b0546640a1ea5e6d8e9deb6e2e06331afcc76b697620892e0bbe5e4b2457166de73ab573f8611a1f80b5d6c422c073900b3116aad24de0f3a0acbf719c3ea3988b7180b8014c160535c3871bc6433615e2ece25ae9c9197d090c624b1fd1c0c0dc0a8286d070801706b12c6e587ff95a8150da4896b50d079916720ae98d2bef454ed81c969944bc4257c8bc372dd3d215fca33f816fbabd579cd2d0d56a60667ef624413aa08a31415638ea0526713b34d30661cb537620f9b9eca9e0ca09059b34e11691a16421408d55bfd206f0b868ebbe6e9524a87530e7eac8c8f0a3b3d3c0bb8ec320c000eb4b950a0f5a89df0e3def45b0507e33fc65716c7f25654279a5fc2bbb791669c662cd9ee4aa39ce62389a39c175a76af872761a0d7d6ba436037aa1d7973c62eda5b1aba73eda03bc29ad35bc4e73cd0d34fcc2344ae4f6ea2aa4ceae9b1271ca760f1dbc0a03bcb7fcf552b02ae762167f9c545a6a41dc9e7235f35e42152451c14d5d2e2473e2bb1a7663b038cf79f831fbf1a41399f39950df4cfe176f8f416ac5a09f7c098a38c98b3c927aa2fbb697f0b31de0df2935f1839ad316e184e6e2be53b26e8ecdd88875969f73193c263885ec0f809f6c4fb0f29ccddc163e0a369d4e211774edd66eca0ba7a4c3ed95a8ae40cb70c1c693aca14c43ed386b24c54a524893515afc1fe2048b2c806b04fe8bb54d320e34542fd88ba4066eb37e8d2dc3d1c5c0eb4aac5923d9a76f3f610fbace67f550b5203e31a6e93cf4aa2ceb2eb429338628bb8c8d74bde9079364008916d853126280f980d9dd74e40d3449a65c58bb6e46b691fb52791582cfc56098ab40016e046131a182c29043533120706c40423b3d7a72b4dd417623d49548ae078f503e39425e044db78c0b65a8d5c12b5968e9c4897ce33b75f273e1bcb07ba86b3680161be25abeb05cb2cc30ea5db9a3ae57f41bbe72e94f6d8cc3bab49f93700c6dee1444990c542a8153af88f10494ee60e068957e8b5f945f483b67ebadbff389931e049939a0f6dca66cdbcc92fc7af95ad9d400f09e415a5ddfaa0ab5b495c9848644c8e68e964b84bcd453f28e142b58ac7795d12f3f0f47f20d966f0252cbe851e5e4eb152a546cb880600923287414314b9bc651bf76675cb6ad8129fb192e57bd2a386935e1352ee250d3c45bc5b02d53f201f0dd3199001ac0c98be3486af99261294008cbf83dfcf5f828e8867b750a5a3f6199b715c2a3b2e9fc78cf446b11896e53a15d74145014079aef2c1db5058166d1039dae12685e5f4e9caa0f973d08ff0af43e3310cc9a5e573052ff7610ee045b505e49106ee9dba0a4070bb03f007f417c967e3c455356bbfadf7ec49e47a40c2852004a5ddb1ca97bdc04e43cf650f8ea68bacfd829b8c90f0c9b24186e76fae090eb90a0007ce265734afa1281e43bc97fd59f05333e36138d5b1e2f802f83d18091015291935b2a23e02553970a05e55fa032c6cd4580f27fbe48db17a7788e5ee6f4074a331de655c63453a71d691f68a42db119e9c977de2b076dea2d63df8373c0090794bc017fd689b3bd7bb3205c9c8b9b60ae44a9c961ecb7a156be601ea334a873a870dd16fde4c2239bb8ee4788ca3b839c18cefa2c59b21f019f0b37e30471098be5daf339f81e07688ebea1e0a691e6851d422d3b74aac8d33de2ec6894006daddeb1b0448d6165971ee04a4bbbb7465093ab6950bcf93a930e7c00f8356e9d1bc67da851e07b79e39a579b39caddf4bda6333dd9c46c2a72cb2b034b261e209c301231cdf434b7e828f2c7f4464fd6cde242445cfc43c77ffb02800603bbe3c6fa133f04203b8a7d5bd1cec0efee9dd082435a3fc13bda89336040fa736b11e51fe7aa5ccfc20a6507c42bdf69fab2221e1e382593c02adcbf45b5add7a506c92e9ac02f51e620d37209ad315b59ef012ad22d3b3bb85ae67a4ed1f1a4a12c901c2549273db085365ce1f769958c7b0f1bc64a66dbe8318deabdb8986dda60f4b6e648a3dbc21263225b8b325402b39f406b7d23937360fa309a5bb68c60d1beeb67800a3100047ab552c63c5f777bcb8160ed2d0bcf74bd604723d4fa42f45b13874e9e95186c43835b3b80b5b1028acec69d0f71325de08d5327e9d8e0009896f340190fc7232b2991e1bfd1ff4133eed2cb74ee46c98f7b2a170847355a911f9cdd4c6c13ce38cddf9f9da12caac149f750c72238ede31641f0183f2e2bdc266a4f1823b01a888fa2f31316897220b27bc7461daa80cf6fb489f53d9f93ff6482e016258325523d4ea4d421566ed4384a3db5f5d987aa9401250734f5b7352f0d87befc1dbe41c92a4101e73a0b485923ccf99520071d634a14a8ae50d44d118de7a11743a78e936444da33f07ce3fe6a5bac02c14ee24de0752df349db8d0b2c2ac6960b8c58d3338be231e3a0a641c3a8326240b4593cde9804adafed63a74f0fd12b1a9ebefe57a445a814301addd9afe8522aa3f6f7206153ab1e480d043dbf52f9057adc890c5942f3801b6852d1c845a1a404a83efa945e3860990f826ed5a85574fe5182748320a55046810e52e0494a23c9f83c18c71a462c071b3903cd222be6baa84c8b9e44de1be90a54b6ddec20ee637e4e31337b734f05942b1e473d587bf3a711b1ef22391f2f6601cc8ebc6a92d684e72b04a1c99113ba37d665d60d8969bc13a5ab1da250b79960f23c0eaeb799deb659c22b917ec462a4f3b1a2b332cb16885033f106b17d04d12d2821d354305e6d04ad0b3bd3fe31488089727e858e118a5882e59628975ef7ad0529ad1d58b22b32c00a852d7d66b26225fae6fd03791dbe0992d2079d71b5e93972423cc1c3b2c4750307e12b136b6826583a11450877eae119c3ca6d26d6660276bb2a2d51445e14743b1465846471ebc9a8820750ecdd4133e7956a89034b7b6b427c53840f5ba764501366f91bf26cfcd4f040c261466dbbdf1880781125f3c2a946a936a61697763341490cd65e0ebd9c712e71224408a6210b7762fafd5faef3a9a5871585a6e94033c199d77f8e7989771fee7191990da6b5afacf4c3f5c67e0fa39af96315f44d15a02fd8e7cfdb37831e87e930a81e882b293284689ba1a5c3e7126bcdb4498c5b045ea120e4abbff1b4eb03c1799ab56e1155ae0fbad636244d1a9323b50fbe84836e19a98e52b5a490432a88d2a294441f4d16d1ced6ac6e02040fc82a20cd1b63b2a87f13c12441a199da27b8da08a9822f645096078ab13d8ba83e78a970596418829f786a24274aaac14ce13bb6909a26a42ef5ca50e4af0810e51f85df0ae9e7e0f9a9e749fca9f2a7cf816abced80cb722490ce22b75e441342ef96ca933641dd02cb38aacf8820ddfd85b9385822e5bba7ae972a817df8a66f96db2666e915ae768423ec88f188968a321d62a8178964af08cd2e104d774a34a87c4d4c00fbbb3834cd3a8b2626b0a015b393137efc39fd82249d0b67ad09043473ed2316bc27c142f254b0edde9f1805ccfb2986eacb51f67499b124b08405fe7f824b6b39651a4f9d9ba8753a5b525b5a8ac00b4ee70f035ccd38751480f8833a71680278183e8aec9d776283fdcf445b71abbbd05a6896653bc7d651ba5c680841eedc27a3266ccc67411c0b458d67f63d5a6daa13f31b62eb8b55f5c155ac30873801bcda2c0c6726a64f54527511838329578edde956aa40ca0d8db018d20f5a86401b8f2f8d5daaf7edad1667e97da463b3451f9e66606912225bf228fdc820ea3db5d6baad7c2905e8c22a22ab237645cdaef6db8b36dc9dab536a4edb4b8fdb24f3f250daa0e47cf7924e1a51b890ba5d81fba2d363dfefd2e90bc52a74320796f53465c2683f8be470ab5b2739c76cd445a8f2004b672115ecb8a44c7e29e2a04b4b5c07a8201c512357b4297056ba1eb08f706e259408c3fe2778bfe47e5cfdb356dbee57a0b07a26938e43e3c81147328375778c26e7706c74920e3f8c416dc7fe525b4b781f7de7cdcfd38649ffc9e71914596cc2a1a8a9b1ca11d31346982a5e898880c5dc092585f19bd2d171811440a85995b8fde6b4b1646a1e6557e3f4c95479690c1357fda02fc43e872074bdde2f020ab9647e6c9210bd745e1fd1f98974459fbd8cf1eacef6fa9b5513f524b8e203631c4d520f7da9f0f27153f976a125374edcabb5ee2b6024c33b19fc9fe2bdde45f3619a50912b174cb0603c186e61e065092a62f25757e7a7512276899aeea41c12eae45a019dcf612222d2c1b0d273a91d172cb93288c354e1c76293fcc7d6058169a804abd08557db0a5ab1086082fc9a4b7a74bc324dc109486c8778003825dc43babf0f8f04e2df4c69863747907ce3acf49944c82032de235bdb5a32fd364e9f13812a59aa92c1471b97eb3374791cce52a1e011231eda1f1b87bfd4b192eee36f40b89ac4525f0803108f2738964fd711cc844025c304b5d48020616223bdf31aa4dd557ca1931068551223374dbe4f2668037d05c35847884055e3ab5c152ce466865d15a01d3d5c7b02f2b1c42db858cb49d39143c96426b9a6551b5b90949f2eb87631757679534d21a64ddc36db3dd172c3ab28e378646efab7b6562cb76fe7e54c62ad2d6f12e008c49df8e2525a89169d3f409075e6221e99a93a6a7f463960fd47524e9954df4f609c1ecbf7f23e546e6c04dc4144778635ba1794c04b00af52d6d32684898e9317bf3b460627abab17cd42a055b28fd6e2d58f5a9c6df5b70d09596a29272329197c07b0433454bdfc25c02934e00115eddbd462e4577f2ceb67c44982d2c2b84eca7652f46466548bcd9fb28a60eb0f2941fbb67b2bbfc6d21be3379eb37bcf56c6b44ef24f50861b00de64cb3d6b0c060d955a50f5582222eb2802b3ed1de51bb8af2867d5989c45a92e7c7ddaca24fa404690d4bf5dfacfac2a22c0b7252f2e57fa74e02eea5a1b9797490ce100e487ba3bb892dc693cc60c27720aabc9e8057dd093b5d4d20505918635a1af736eada7b781254afbbd4a94c720f1f73e786d85e86d327affc96c1ceec4e1b28c70b113a61d5a5d15cf859471f435ec632113db6421abb55c6dc95fc8740acdfbaca88f5f52cb5bc31314b791509b1598e3773dae0ed3df6e13fbb43d6b91a1609c5d2447dfd4c8032d083b921e4939953e954a1c63393416d3a1d83708a9cabdd1e34b7bc53c4983f97742da9345aeccf5ee4f454e77c883d2314b1c6c65c2a926b63776e5f2b2c95f4d47ffba37c9b6f722cce51252cb2db3d87c35d2e5d25f778fbd950aa35a99f94556eeeabe5e60212c8484b072b5881cf2791bb6e618d4a407ac5841d1d84ea0053f32eb4d4e4abcf8dd8adb4b8f7d8e4122b4ded650b64245d8363663f109ed85315872e1c3c94dd2fbc6841a0845564b617d80697d51267c3827b588a48754838bd51abb13825cd36b931d0aac8503dc661e99c20946f185361dddab351e32385fa2ceee6c618b20a4d58cac8efd71478dc3821f1b44ad685a1a1d05bfe0087ca31db53adb69e9a4373a72901da6b761b2d5b04a470d90d312607eaf6189a71e1bcf7f79b9a58cd4a763a225197c3578f2f79646cc8b05c435740658e9065bc7343a21c4accf676c40cee25ac331941db3d2b6e27b3a44f56a9019e9e3586225ddd1bc29dd9b1a29a384e151a30ead38fb03236ca6dce87d46081ac9c54ae9254f70d22773c86f2b8a151e89f9c1fcd37dae479dac3207c03324a6dd0a65bbbbd76482a02eba30b02f58699f2cae7246e94b5e2a98c206435dc03cbd31989c0a83292745c8b5c57ff0749402fc3ca04d964d99a6fd5797b90ad30eb9b7b31f30b9fe80e2e666475596f17709dbbfdb54212d0d1a99f1209dbf446610e7b7f15370c45d8af465fd70c690045e0540c0500a3b81f489fa60bc869957c5f51f10e2e3d38beb1f8cce010c5b01ba2422421045219cd85c8ff667c460c49a519b94da79332ae6af53c562859499f8be6ed3353721e334b5087eb2ebe2c1114d9180e9779a9d3f1ca20477a6ec856c423be0232afd67689ba661cc549e08f75ffbf24fc42d234994e66470d1ccf7c48f86a1b48a81c4d61181019518afefcc281180f5d19c45e3f59d138f45c6ad546715851dfb6b8def5c350c277d8af1b072bba022bf1b1f7e1f8806df8ed2d6f6dcc4b30fb6e1700ffea230b5874bc89e9102d1629c0056438c1dd1e08c00abe1c62cd1e48c001535326ec0727683cf4b60bdfaaa56b9f5ba5064c2973f1fc833b148588970712a192edd4ee483f698fbf81a6fac471423c4b97aac52119ae5af7846a74f314cf587c0d12466d756890513df5c7fa9fc18330832df9f8473bd3ad7c1bfb6e6207ed183e4d015c58b5fdccdcdaa1fe1e0dc8b9792fe1c8c5933d91811967c0fbb31678d3fc578f5546f90389e232861b30088774d8a459628238c8554700599994923bbcdb7137eedcb76244b70f044c59f7e105a3822bfbd42e8e8b73b93f2c54cda5835738b51af0782c0b50fd6464177b85e414aa2b50071e2949954e43b0d24711abf56d6e800ae6cf8231d20a8e9ef672128b1fd670cede931905f65c8840b4c0c99d70ddef68663272021b8bb387ff5a0d7ae1b24ba65ab0783ea0235f20b54bff568acf1ec016e7f6e4cf6babb5914c03d55299e6c6b84bba1e92d4fe9254b982bc3f76b53c2bf3a007a6be2e3d18c0b3c860392acbbfdeba93aae1d1957a59f1a809784e3a791f428a3fdf6183f99039506c64624ed6e74f263aa7c19e14d1dccd51635f5e004343aef20ac11ec979936715701a820f9b34733b456e29e0aa83e6d540ccd037f7eb10c9620686ff5a27ac04f2a71271908e01c6f6a07bdb7cb16d84d8c1c7a18dbed310c2610bf5695c3e95dcdda912cacc075c44714d4bd0a775f65d6a69ffca7a7e3977890c910ed3f27fdb2cc51605f7446d9fe5a7e13c48c921b2f34d70f8e84469e6d9b43b4ab2854a1caccd81ff6c2e0d963dea992902e5144288d16d0f8188d01ebf147849a7b1e9b2ebb155f8f2902cf5a7f4cadd768c25fb907b97319fd7e897ae89caa42d9b6a8c066fa17e3b3235587a0376fbdc7bac3afc35c8e16cc58e5311ac5beae69e8ca7e94100268553f4f76a5619f0c8fdfa18eb468af8d51b8928dd351ae37813c47afe73c7cbcf928c808df3ed395a0e7e0cafe003dce4eb74dd71cee51574eaeda133b1fb0a3442e710a6f06ab29e7f33c0b31ca3e3b41094bd4c48548b8cc1b4259c8330dc00a3dcd8ae70d0a77a6669348ca8638c116ba91e9658d3e85866f77bcc16400438b68a58707ab1fd4b02e53814a3c7e2ad4542224d5c597e5842224290b9ea7a9edd8978a8c8fb94f85f837ed90d075b7c04992a167b3fd3e1795b97d87c3a225961b1f4de9d41b6b81f11ee6963a14bc8c048e9e54260adbef3537cbadc8df12b7441ae6e1aa85a58130094f186aaea06607c1cc3d4bfa06ce304b5c268977b03d6416a6748ad3a5d9d4ec8fe94ded80c0a2f0d0cd3d052a69b9129b217819fc2c4150192bc729b5edc0f7609d31a936365ad1f306a6aef0d892ec27834b9ab217dcab7b3a82fbb2dc5c530dd7018b2e102b7ea288afd850f1aca3927042afb6c69937ba552121f5b2c9a78fa21321eb629054e83eccbcfa490ab27717d435126ef5c9eead9964cc3376221e000aebeba8c9d3b3b041be98e9073aa21758b5ea04d0832f04fb99377872248c54a67ee7bcbe82db24a0edf465d8654d0c3ab5c41aca66a2533c05496426e11d3c658e0a773ef5358348c3526acf586ed06d857a2b2b19044522f2811db6f5e35f22f0a1edca8c8d49ddb32fd47443d2394f556ac9710c510ba4d793013f3063c7e78973dd0681cd02a6209a0b4202b596720e93945e4ed1ccdfd9490327a9a90d7fbc23832472af6e420b18759fced10ab618baf16c4043e94d84e296d3e5295fdeb09fc8ccba2dcb41274cc62b9af00f95a0885d51521fd9727c9a24ced543ab38e436ae80ccf88c4fd2ab1f58046132470bb8058387e098aba5b9361a140c824c8ef3ff12dbb787c9d6b612eae4c248319c3c865dc3c913a47efddb5d202d61f45f921ec60513803fc70afb50bd64777b10f7d649554eec1335b980054a1beb72416d78a871fc323589a6aa87e89d07b6f282de5190cc753336c96126820326dc6755b92e70ec41ffc6a47856c204223924c42f7d67ffd792fcc3889e63f5c600258311b93510ee600a2636b2579357ddb745b8b6489dc1ef29703ea877eb23994ce8afcd7f6e66999f30a06431f46e14e3e5c1417918ed5464d2b723fd0c527ae1e8b04e8e6f1dcf5e2b03cc89088f7271ff5317d2239d87f25df731f2c829d2c8c5e57912ebb159b72827ee8389b35f75f29a6ad16fe6e16c44b555aa9944dbc96ae0b1604d59038216957ef4fa29f452b5b27657431526f66125cbb6c2a03610ec9b82d0147c6cc12643f1143a270b9dd52d57335adf404945093315295d7f489ff562949a17b3bf97e1c08ea044dc581cf06d94c156f831e137e0c928ec018772da783813678286d8a0089c0a3317bc723dbe8bd8610a045cf614309e0257014c5b4cfc82688b70127d68400c8a3305523bf276903dd471a6a6da0faefaf07f25d0d97c713c8c1770ff55602d7dac5ab097b26206133af8bb155783333144b45dcbfc574900268996e2477bb7d7fc3b8171a2ea12d04a465af84e82a42f53a555cfecdb13fe2526bffaac5de2197c3a5dc993ebd7c9c77f14b3e86bca1579f2eb38a490b700e7db049e685b4bf6ec9e23fe9910db357521408aa0978d43b66ad8d80d075f49f89147287d0c3089df397e27dcf21f70f82567237c0dcfce6b85f3e3333d4eeef15f53931641e927830e7a0cc89c5d11008edbe92f904218d371beeb1b4f9136828205f1cb710e29b8115da70396a815cd9112791a240742ceaea4caa9a962e5cdc1a7f753c20cc7e89026850a342758d04ee47b4814b43ceb5236fffd5cf328758afbb723f92557fdf70bc16b3cea036f2deca4f4aa2bf7a1576b33d79b110a09f6b292885bccf7c6805e21b0748488ab60025184a53a47bbee1fda045ce314cef2e9067044434ef088a12b3d6c1ce270f2b378ce9436736e21b38c92ca8244ef3ac14a3af6e5803cc8d4c81b0f3fd412f3ef668e34ed585b62603322cef5bd8fa79aba174a447c8f9498ebb8a951545a2a735e0662bdf7fd29cac541eaffde43b21c429ffa4b86ec1725d6e832116c3f6d979641778a698848cb70ae22b03b26abee697fea238f8f6c61649aaf73a199e9d72fd3e4d4f126a17c802a286803884131fc5d0b14e93fe56586d542ab511f6d0e762e83560a930361e55fd88e1a18a7cd2120fb875bdd120b73f3161908119fa0d709f304f9d87efc53a2ecab3f9055bba5a70524a91cd3e0ee610e55bf8be531d90db4d7d949ad615151ae345f0fa522bc393c02a9796d7bcab3fedf26f1e1662e319c12173b200c6f72cfec3913c7cfc58c395d3b025a6ae4a8135baddcacb538e195a2b5750f1cf7e90227273684425e01d8fc67c35dfc8ea2f3d768c3122bff90187d207738ee4d758b776e53cd68da3118d063a1d0f5bf2a2234969fe0d76416fb69693b1e6badc9160d6b36dc69121fe2661911e704be85a8ee1c6d30bed5ddc3398bd76e0180674c9aac92531dc4ccc3c3c1ae721c152258507a92cb3dce4c6668fca56ccc6348c7cd6dac295010453725ee9694c2ed040525f66690b823115f13838bf5031d7827480bba37a936e151d4a45215c147655c01b5ea6b2cc3928c21dea76594baf491c37ab402416b2a244c99b8ca18046c01d22a03828946c15246708e70106ad758347c2f6728d04028a278c5bb2fa491b30737aa950fb2482bba68b5c12a7435a515a8e890088c4aa2a615a804cb91d968af8a7a82ca2c455794fc53b357193a46b1ea1adfd640a53250b7255d2eeaba76095e6744c7463c031de7330c3d83434d8553522cf484a1c3a19750c5a17a5147a51e88f5c49183cd373afa0afd1ceaa9a3b094f7afcb701488a8655431d4b9a827ee08ed15531e869fca16a84cb08cff9f241f4ba8f0285f65c42f346ba943ab6fab32d1a244b1652b6c987374c8dc11c732ec5ad6f2fea1b02efb1dd8cbd1cad184519ce80fd09c1b9db7ef07ea3f7432a999aa46d44d422bf2c4f9ade8553db582f75f8fb2e47566af15f565b95b560d37a9a72e109848ac3633f5bb2a63d00c882c1a059c18ca30c54ba7284465a04e75cb4a8c8e4695416dcc018d169f8a942168a6d486701d30f79b58279cb5db3c09a632c18b06369a218be336273cad4b0fa10a9dc27d41bc0386ace2214127f248d3a4f32149e19d6e89dc6af5f07cb95bec3cdcf3b884982df87ad8609e354a6c08ca6bc63dc526c36e88adc6c68645d2d8ea6192838fc62780eb764ee5cdf44f346d2f41cf5ed6b0dbf0b46dc734563e5d6730a2d92ce4bb2a5c2a8e601923ae4604a3e05c13e81eeb227c5a918498e897caae8a611a735141f7b59ca22138fce786949d91d9c831b418506c1ca03fc8bc5c0c63da50c17a462d56fd724401c0d66e5c85d05a5e48ca310c2b4ff902402288e3a3f6030b26694086c9ff4c1f0d4e066ec3024aa10591d94008b37af412a40d7a0c9814b8095871b0d817a845a4831f3af5dd66be611c05b01d7977c159a1431f0dc1763b774f348c8326176d47460d8c9014bfc7263c1f32a0284e12c6a2b17e64a36932d79cecbdb41a4feb715524f2011b14790be7073739ccc10e38335c4566fc709bb14a447a85e0444b9b597196626524361376c9ef1038ba6cae039b315e6ca9711067e837c3661bfe0a721bd86d2cb61191d80cb6c5d5b9bd91136c399ee3d8b691d98d65e51887534f6c6677d6be0b9dd88cc9a128cdae8d7af166dc144cc86ae5c8c6b46caa02beb045f90d3660b0a4900330333333333333333333e3ca4bfde37ddc1ff7de8d60c232aa45279a9292921209ac35aebce01de7e01dbc8377f0d67401ed0da10d1f0e4d52abe0757486b10e62c41ca48223a94327bb321b1fa7e055a63ce1d2e660724e0a6e8ebfe737785c565f141c4b1e13738c50991e149c94426d5585f6a5ee098ea47c5b29c7098edda4077297396c821f2ed492e698473a98e0b57d479bedef79094e698ae918f197b1129ccd6695ebd2243829e68b15296548706a3e6bf050691b2d3b821f3ebb9d49eab09fcc08cec713724cc9f4712c5911fcee30daf6690c11bc4f93de1ee45552ce109c24b143ffe8393cfe08c10f6311d467d6233d4170e3fb6e36eb2b3b0304d7b3cac52c5de59a1fb831ba6a5f7ce085cba91a626726b7f4c0b188eed1d5b47a5978e0a4c6e6cb13d9819344ea6732248f611db8793a3e87b4505a7e0ebcf6d0217ad8e3c0cb4813d66e3c546ee06d9eb7cb1f04b081ab5d9eaed2b33adab5f082d87f94ef83acb569e1b6c725211d3c0baf652e4731480eb46659781b24180b2779e6c95154d58c312cbc489a7f2bb2fb8faff09225c9a1f9871c6deb0abfe3284a9fc754af6d2b1cf97854438ea7565b56f81a3de4f918415388aec2bf64112d4398e081aa0ae762aeb8acfee1a334156e69baef49bf7df944859f3a948ea297a7f02579a648ee5c1fc4148e678f9e2d867cab580a2ad4c986258f144e942011fd330a5f2ddfa71ccdc7cc88c2df509a156982c71d0a377687f7e8e0592d28dccc21dada625dea3ee1f49d947ac8924b9927fc8ea12558b020695727fca05eb3a74cc509672285e718de849325a7d4d392ae929af0439248513535d57932e1a71c4ff89c35740e0f263cf7499b263269adb984f763ee36d1e953ca58c2dfd80c7fdf1e5fa412fe86ac1e49ce9a630f4a38496ab2cf5c26e1ada698aa6221ea2b92f067b3860f5f8984ebc9936d65b5ed0f020947cee6db72103d6df2083f847f2c094f911e71847329dc86d481a7a46984532187240b33c2bff0d03767c851c72ec20b29592ffb304554116e064dcfaf19bacf4f841f7bf0a0437920c217b90b73c1e3104e6a5bd6beb74a1343787fa163f3cb66e1e342f8d32621dd29ff84f0c2079d6254f6993708af3abe93f1141fa515841b358636cf5aaa3981f0ca3c27bff1f3ce00c233ff20d774567cf40fce775027a942747cfac1f50fa66346abd14efbe0fde5caefb1458b1c3ef871920d8f7b0f5eb7e414ba23f5e0556bd01a3bf3e066a4d57469ed2d9c787043dc6f23fcc776c13bf81f77297898e2b6038d29d9071d07621dfc4f39cec17d460acdd1c1f19caa3e883707377c10739a433e084f0e7eaa34ed992da5b7581c9c34ab9eb482e58b191c9ccf9c2db25f8c31526f707cb2ed322d37b83982abfbaa4fcc698333f39f4288f6d92d1b3cbf98c2aaf755e6881220630d6efb848fc963560d4e48993e30b7ec3fcd64a4c19b481552485ff5c6340c178421030d4ef504dfd8b0ac40c619fced38168fdfcdbd449366011966f0524e89acd441a357b803168601a30c4ea4cc1f59c425bd5eac066490212f937073e943c618bcb4b8decc95a1ff3b2eb6bef0a28b2d3220430c95e6b0fea3142eb68c8c30f8e21ea4b4a9089721cc850c3010c3fb2455fd525f30a656c6e688be1788e497e6735e0b97404617dc0e1b724c4939d892b8e057e7cae361477af1e82df8ad193faf355ae1046468c1ffb19c3286adc6908f0c0332b2e08cb77a78cd1d7e230b032fb20232b0e08590c1be821ba92e68f274d1257fc8b08293c26a32976da4bb8e2fbcd8c2aca08b14aca00ba4808c2a781f89a7d45e953cbe80046450c1df4e9273e8925ce00432a650351620430a2d230ace5cd0147a26c3c5568d1a99749001053fe23f3e5189b858be31c87882d31756db2d212d4b8e2623c87042d540818c26f89299cf238fc2cc4dc6c542c074f1850714d72083094e6dee4de7d31a1daf8c25f821cdfc440c2a5143274309e590638979a2e3586720230947e6f6c163acb83a073290e06dfe9c25a40d1f117304c773f81023a6c4b88a11a86ed5f4f4be087ea8b6cf1fcfa9559808debb89440ec9330427cf769c329a840bb1230427b84b47f3b17e529d20b895dded953d40f03d677498f0d19c477ee04555e9fc99c423f73ef05faa8349ead1d7647be0bd664fd61ee450226878e0a4c8a5327b074e86f71073c4e69a4a077e900d39c8a164fb2293037f656cc35598780f0ebcaa8c0d9afd22e3065e4a15edfd4b82e71c45860d1c8d1e5f4ff239f8e8520b377264c4bcb1ce63b2d0c2b9f6d68aba6916cec9c7b45923a1a52bb2f07290104453864f6d2516de7c8e3b280d8fa25705168efdff6726af8e1e79857f96a5239f9493d4872bbc1e4d4dfb186a3d6e8567993e9ccfd979b4125678eddee5a1a9526125abf003adcc9a93d554481255f8697d36e498c35a8224155ebbc75a1d9ed9c1ffa8f04c730c7b4df6e6fe9fc25b93e41d95b973646f0a7f2cdbecc77394c20fb12395f0b1a884b449e19ca71ca588ee8d3b7b14defd871134ea3ffc220a3f720eed22c77328fc10ed339c87b1fb9941711c99c7c19f70433e881e8ba6d58678c28df6618794365c6ad209d7cc2549ce0ed207ff72c28b5531df99d4a3fcbb09d74396ca13a2ab09a7ec2a64dd0489566d26fca0fe3ce68f35cb6a30e1d9bb745f889472b0f5126e1e0d9fa36bb58417251ecbc420e991a795f0dfaade3e085f29524a09a723db7d32fa78949293f0dca26886895312fe69ae0c1e1d44a66846c215d90ed70e2b64c925249c1829ddbb33a5922e1fe1a51c87312186565c948e70a23e78e9c923252936c271cd718a5ad4a41c898cf07d653a74e416633b5c843749b3e414b25d21a1225c4b216ca203a99839897025367ddc610e39db7388f02a5d468a9eaab4ce1dc2ebb40e54428721bc1c237d20e139469314c29b4a3f214751199226841fd65fab669f2c293908af2e0495a0412a624e10defdcf0709afd61e7781702b4d88b163f848313a40782672f75761d2a4cc1fbcdf902b85c5f62d8b1f5c8ddc954f34d607ff438a629b35ab6ccef8e0c6584915d6d91efc389e1cba87b3ec74991e9c98825d5a87fec9c195073f84e8108b1dc777b6f0e0e794356f26bf15c6ba83ebf669726059b3a65776702d6cc2255955072ff769c7b9a347e242073fd688ec40dad7d3630e5eceee961e678b62b71cbc4a1a25a925264b8c83f3f663f963ea8bebe0e04cdf5f86fb4fd5aa4911e30d6e05cfa8e571109f330911c30d8ebce6ded0b8b4c19f2ca99307f5fd5f151bbe10ce53071d522cb9585d839ba14722db5c4c88a106bf7c443ab6b7480d49831fe608319a79ec65f5e130c44083a795455624bf60887106e72fa9484bcc47b61dc30cde799aa7e89872989ac528831f2d7325cdfeb125916290c10f324d6fad3706bf277ffa24993e77c7108317a1e53c36c86676334618bcf940ae03cd124cd3c4781c31bee066180b2ea576c966e20557d5524564bef34f7e17dccc79429c489ca70c73b1759683185cf0da5375852017184c83185bf02ace3f36cdac11fed1829bb53abedab6919c3fb64819c4c8821fa2e2be3d858ea7432c3897f264df1837358f71b1750557d42c64a4325bcbf62186159c1c6677dfacf6f5e657c1dbd8398e3368baf78de162cb84e1c50b900831a8e0df98faddfb7de0999c8217db248449a99e66f2c59182638b300c181d460c29f8fd3972d49c3c59c48882575953d7696da9fd5070d26a44e592cfeb63f182055b1ce58a184fe8b25648bbe49ce0d5f747e9552fd61a89d104275eed82cfa4907e7ba18156c46082779b43878f30cff0314bf0a254f5775039281b318612fc3084075feef9c24d6c8f102309fe4fba0ade59eab23b48f0d6fe55a5031569d31cc17f995eef0c8911344611300611fca822fb3f6a6d086eb7c79184c41cb9c4b5841842e8da73bfa46304c18f4655e5644323463e06100c125307296ac80fbcdc71322dedf8e08e37a6c5b85c7a40e6efcec14cf43cf02a25252ace63077edcdf9922bad681a329f2479be53843c639f0b3e6385eadf78eeb4371e057faa0b6de73032f8b86908378897677c6b0814925e7ca746731520ba746e2dd2c2b5af8173dad66e224327766e1d4473ff389b62c6e93bc19258e85f7e95aaeb18485571da444b779b5c89157b831d53be6945f336c5ce1a470999c337bc8f05be1c7d6d829bade53dacf0a37a510555931ab36c7b10ab7831c72982c5bc9660f55f83163f9b6844db726a7c29c474af2c72e7563a2c2f73c1fd541d3fc3f7b0a377dac1e3d336b8a536ed55c653e61624729fc6c39bf5d7497983325851762dea8f48e2c878f1c459646f2460ea273bc280c8b312387394a6ff443e1791023e4b01550381b3165a3867cc2c9f1519e34d2e4709527fc888f91d6f368ca612736fb73959c533bc6092fee4f5bc262ea33da8411368410c4e4628b0c03d08413d22f7d1061fd539e4c381f7afa1c652dd9670c261295d26097bf84f3398a9d27ceea52d2125ed234c135bbd587a152096f43fa8fde424ca97228e1e7d618553e3aae8f3209e73aad87906f3b7f1c92f0b27d881ac3a5657723e18739bd234374dc390909673407a17a62e411841b4d6e12e308d77ebd3e8a4eef5d69849f2ba78df0b072dc3d23fc8bd5dae571ec5c2ec24f7f4babab15f1796ccca525c2d97c215b9e17d91c8a08ef3f6b4c1faf5fe6104e84b7dca14c5b6df20de16be5cc8a9d42782a1d45d4ea3808e1f6dc6f068d109db3c7208e209e839298d22505e15fae79fbab74200a89946eeb3e8e2640387193ed347bf41fbc8f43e71cc9a3fd4084f475b91493c7edf5c1b5e47f29a7cd714735f3e178fb38b6700fae87afee20c5d5839f83d89a87b3bb8418427454f93e78f0ef53761c5479e41e7707bf2c2c7c799437c729b583339a3bb68cf920eaa30e7c8c8a31e530c71da3832ff6ff9dbeedd5b49c83511573dc217b8614b61c3c2fadd70a9e38781f793c34724f761e0e84a87cc125f75418dfe0cabd44ccb176f5c92c089552f02ca4bacc32a131c22878193af41c778c1de51c14fc8ce91d85f4b149774ff0c3d08aec0e7382975324f6f6868ba135c1174d299364d487d162821b7294a3e4b496e049fba87c903257564af05245c8d2ecefb72a097e10527aba8b69ec4307129cba0f59f5417290d271042faf5fba8c7418c10d1da607ddf3299d53043745998c670fa34d0e11bc645d15dc21b81e955d730826590bc1cd1965b662d9cc1b0427be83ba9f9b6513089eac445947da4af0fcc0f95c1f7da776b3cf077e84a76fca6678cbf4c077b94f159172ff8407de5f8e63794739c00efca8e3ad4992538c8e72001d385ed6215d8b79b8ca0172e0845039ccd9c73f29e40038f03dca41c2a6567b0939c00dbc288fa255d286f2200938800d7cd91c2b74476ae1d846b9ca10ecc3e769e19dd684c7f9cd3d3c66e14713424c394e9bdab42c9c9e0876962b7786742c9cc91bf75148f9c9372c9c35efe0ad738ae9ef573817c3c71b7c57f8693ac5a887a487dd0a279d44e720e5ce97352bbcdb8ad6395ac50a5985f31f4a6d6c8d4aad0a37668aa7cc4a332ea7c2f76023a36999dfcaa87063b6edaccf1fc7fa148ea57bc8a19885aa4de18d67a57043fbdcb3fca3284941858cc20df691d78c2b0ab7deb447c35068bf390812ab8282abb168159a7ec2f598bbaa247b2a0f4f381a835cf8d8eaf46527bc28293ec55776f992137ee8f7d6482321addc849b3caadf9837849b50135e8478554e294cf62f139e4d5d761c478bd51b269ca834d9a1b2be8413a2dd87d1375eea6a4bf8513a97927b9f94a7ae84eb2396ae634a53c20f52ca42e6ca2c1bf524fcd414434e1d95fa7b24e1a5d4603967ef38b427126e0e326f4bf44f8b1e4838993654f6795f34cf233cc93efed31ec5fa8e23bc10b52e6a348494368df02bb52a4c76480b1b46b8151a953ea3c2ad6611aef4864647b5390c1945f82942fecd914984137a2a6787c84abe20c273b7b69aced4f09743f861b0581fc28518b518c20fe672fc9bb3570a2185f0ad627658dfa7f21342f8311a72c60aa61d4c06e10762ad599f20fcee50bff271a1251208afde526c594b5c0f083f8e393a8f473a4dfd07a7cc3ca60a17c362ef07afdc36c264fae065c8c79afae083a7c9c6638cedc1f114317f242322293d38f741d24abfec6a1d79f0623c6aba089ac3e8c08397af4e43dbb22ce60ebec4beede0fb658ec3b5c73373d781d90ea483db95b263344799369e831f74bc695210e5e0c6d439fabcc6c1dfa4b943f1150eae654e92f9dc342a7d839721d9f12de5414abac10d1d87d9632b5cfb6c83671a39c741d2d431996cf0ac5243541fd7e07465956c1ec658caa9c10fdb614e558fe9bc4b83ff7190c3b8d5d67cd0e087f07392dd3378bdedd1a5ac0e0f33381bdd7bc3bc6570bd83f5b05346062f25e6495932ba778cc17b4bb9376214afaec4e09d057b0f6518bcecc8476390180ccefdbf77c871bee0877e29671b8f17bc145273f061da2c962ef85a23bd31fabbf35cf06354262651f1efb7e0a5ec142cc3460b4e6bc654a9e262684d16885e1d7c482958f0b5dd6247989bf82857d8ae6445836a0527749810217c7b1456c14bde6973850a61b64205e754623a4cade1a932055742beec41ecaceb102938a15fbd3af351705cbeec3f780ebee3a1e07b0e3b753a9fe05cd01056511b6639c10f2ebae5ac9247e99be06594778f3f8c0e1a2678b933640a1faf5b64095e84d09b11568267f769f1ef9104a73e7f1c7ae88104e7fa7344f5f4b1cfe3084e0e3a42bc4c99dd6d044722653bb06c566a17c10f513307496622f82769a93ea423cdd921f892751fe628c71c9b2b0437e58e62f28c06c1f730735467962e4305821f27c96129da64f8c81ff822b612c2f47a10a50f1c33fbc91b246687600fbc4c3158a69b8f5b451ef87d1a6fb9fb8314b20327d9c7a1e7f9dbf6381db831776ba596f9162f075eb4ec100f217b640c07aeab4fe6685bb63206b8819b5fca26967d5c6f001b781df97a35c7e553d7c20bda21244d7972eecaf058c93ccc5acdc2f98aa134e7cd70175938123d3bfe2894e68b36165e7ce8133d473e2cdcb056a1736d7988cf2b9c303194cb755ce16a85bef4c85208dfb4c28ff6917fda9e70b16185d71f555cfe2c4a8e55f8d7b1c74345b0e05154e1ab767c3908396ab44a2a9c9e994b97b7a35454b8f5a9c25a8edc29494ee1e49bdc418839c8111253f8ef963c8e42be147e8c9ddd36ea34073d298a985635cb1fa370bd3ecc3c7fc4ce1ea2f073ecb952ce23147ed0724b33d11dc530289c1ccea3f9c935a7f127fc1017347bc7ed61c69e703e481eb6aadc0937b9698e6cd2478d2c27fc568f327290183ede4de09303a9f50fd584dbe9cd639294cc5ccd8493e67148ee9a63d78909ff35c2574a6dbd6dea25bc99bb54b163094f428eeea38e2cf66325fc28b6e3d764172585126ebabece7c7196fd49f8c1d29b6f4f648c92f0d652847f0f6be922e1479914113465c57490f043aca6f031e5e0ed23dcbca5da97426f089a23bc28a61d474937b3aa11fe878c9d3c3a9ec830c2f30e3e9c644c49c3a48b7025b2cfa25fc44c114ee694e1eb2b89f02d3a8ec73c06117e0c3955d33c840e630ee14a6ad792397b558d219c7416ca3fe410b92b85702b7518c27f74ccac10c20da95f4f7910aea5cc9c42737f50124178919e6adff1658e914038e3b1fa67f324361140f871d47879349dfff3073f6c9c5ffe2d898e1fdc10cd41a3c61c65f4fbe0c72c6ad71d84d2f0f9e0e5a9081297ce93f57bf07269d80e2b7f90cf430fde86ca520dc9fb3f79f093bf44a494c6833f371e9d64b21bb3efe0aaa7e710edae1df51f695e8f3267b90e6eb7664df1618e89321dfcbba43ed391de4a9e83172cfbfc6a2c073fd2ae58173193e5c4c10be396fe29c2fa0f073fb4ed896e1e43a76f7025888a7bfe4e9aad1b9c546fed39d536f86e1ee788930d6e6cb986e6c91b9daec18f3247fd1e199d326af0a312ef8e47ab7325d3e0fbe5b0535a5b0f3e687025ddc392cd61a9e50c8e4d6a0e22df9ce4308367f159b56337ff0ecbe0498cc86f6bca9a0c9eca4756f48cc14d93261e3a2ec570598ebd30b8b93e0a9ed181c18f88ff5af7dc51e60b7e468de778096abf17fcb0a93f66c4f4a1ed821bf37b5cfa7555d2b8e07768161beb3129b305af42a37cc428b5e0474c512aeec982df9192da771c2cf861e63c76472186d4b9829fa3beebb11cbaf35638086fabe0a73877f31012fba6829f72ec9b704ec189704b69a191829f3b9889cb11053f7b700b4bf93ca40b147cad309adda33cc1cfc93d4c158ba810e204a7530869823716b3b2e4ac262d61825b2949aae6ef9827bf045f353a7b234b18f195e066f449bb764bc93992e07de68f526c4ac99303097eb2aeb5f18ad27e1fc17f9ff6a8e41d7dd846f0c27806499ddbaec345703bd88e93c6f441083311dc9a8ab89b5893cf1d82f3eed2df9999735e85e05884c672d70e490d829fb286c98a09047f237bfa851ca4cff2077e58e40c8b613eaef481272947c991e981abed9653a2689685077ed0d1367fb13f0eb2033f567c681b3d126975e0ffe63953150b90032f6cfec366bfb2fc1500077e249d9d255d3e89ae0037f023bf5c3612726d8a15c0067ed8d7f93cad3286ad165e6cb41c2a365af8519a986d9259a7c92c9cbc621d694bcef943167e858995e314652bb1f0d45f2be7e8520561e1b84792263d5fe5fa157ef0dfd3ada66d63b9c2d9f48186fe68ec2aadf0d62b47b0b14829cb0ab7630f2b7d24e12adc8c728b2947a80abfdea227582c9b8e3015be5fd545e5303a8e0851e104fb0efaaa62adc7398537f641ba2bc7b1bcc7145e6dc4d4ea94c2ed305ad424e37711527895434f72f5d1dd3c0a3f4fca986286cdde8ac271f30b17257d6a86c2eb3a3593cd80c29fa9d7f8cc7cc20fedb183af142a2d9ef05288b38b3df127e984177f412c956685ac70c2ebb1f338a6ca26fc186e42c2868c29af09dffeb2df8924136e6a8851e22398f0256d5427e98ea27309cf434b59f5bf25fcf451c75399551ec757c2491f6d78743c259c143cca3a940dd932092f3c580a9e9364f99084ff31855812b6634a1f91f082a58b1e3cb49608094fb3624e533fc289fefb0f153bc24d1edb46f8514cc5a7d258b95e4638eea369c5738e83f02ec29f0ed3be43c7b1ab5584efa16a089dd22a443411ae660e55d4a453f78a0827c4b4f92b26a3c27a083fea682bb93cb5c7aa21dc786bf5ac4d9e2f2d8497aa766df3b9ce4d42f8a9b9d36b3a085f543d8a09f2d6a320bc694ddd51bb2731108eb8e4b8de83b4660908c77fe5d4a492471effe074a8e17fd38c4f871f9c4a135bfbc32746fbe0044f95cc32ed933c3e387ee1de7bed324bf6e078b40ea2a64eafad1efc73efeee8687bcd3cb81edfe6af110f7e0cefce76d91d0ca9af52f6783b90e6b73ab81e5ad6e0db35b92a3ab81d8748afcc1d2e85c8c12b8b2995dd2671703d54ef8f573a38781fcaebfa63c8aa746f703a7a0e2ef391f345e70657d2628769a80f2ca60dce46878e1e877414346c7072868f6369bf64cb1a7ceb0f79de72f5fd6a703d7be4a04572be701a5ccb7739c75f4183bf2134a4671a0b5e398313a33d9121a6ceaa98c18fead0d724a40c8e89a7c5ecfe4af927836f39ce399aabf1a8ff3178926e2ec4f42858ff6270c2fc6d75dcbacc1f066f2a849ef09863c607839f525ef320390cf71c5ff04337d5140f29217d78c18f3653b8ea4bd1bfa30b6e48b19c2485b372990bce59f684a40f72d0f1161ca91cbedfbde318b35af08367faccc741d566b3e046bb1cabc574d074b1e0d55b78c755dd26ed153c099b434d9f90c9572b3861fba543e47ca779f1b0a3b4c20d99a952adfb2353cb0a672efdba8ac52cac5556c5baff63ac3437d31db3a10a2ff664ffcf9b6e1e7ede48859f2de95108d73aef3750e1c5ca1aa9627b8698be53f827d33d99f2fba5e698c28bbba41eb2f3c4985429fca0f597a23b59be5092c299bed8162dd9a370a3e40fda91dce5ba4c149c654578b95876677cc7a1ba22caebe650b829ddff7564c7b61cb2010abf446c638aea486df9849b428ed581470a911896c28627fc8f5bcd42a8eb550b373ae19c78960e82b1c50a0e521d48c20627fc2862c71d346724e0c5c6265c0f1bce43e227c7686bd4d8a270b0a109b7f307edd8983f7a8f63055e8071180e6c511b99f083905c6d5372112d4c50e92932965d1313193652f89770babb2445788dd259870146172940b584bfb221b572b08401461717d8a8847fd9f5b17b4e295157b4997d887a7a109d7b42cbbbfc4938eefeb9225473f6201e614312cef976678e241d093e4e2675f9e28684973aec3a5d5269afec1187f1b87338c29678abb0b70ef70a79aff1289bd036c2550be92b98472184ba1b8cf0e37c1693a6cfb1087f725853eb137b091b8af0673d7c18d357527f4d02612311fe9a7af9c7f9d307416344d84084af6934c2a52c1b61e310ce8c4c276d172f4def8621908fb78314a23c0b001b6c14c2db681e2ce6d01d734cae0e3608e17b1c678cae0c51a9a941f821a4b76c99b3e5941e82f0831c66cc71777ebd06a292abcdaaacaeac7c5e51228df87ff600e1af44358b31440c6697fdc10feeda2b751cf7e4982fb65081f9628b177451aa0a3b60c30f4e4ecb24b12f52c7aa45b0d1072f870813d9fbaa2ae40d3e2053a7eeb61aa6d26de961f4506334dfaefed88d3d781163aaec9f8fb1adc2c596bd0bc0c0aa056ce8c1ff402cb43a0cbfc8835f21e4683347cfc596a5800b30b6b00ae374c10518c9800d3cf871b9a475de1cc3a4f9c25841171f3841170fa851a3460dde2d54e08215d0c61dbe08030c177cb1c51602d8b083a7f59623dfd47182159814a4e0e08264d5c129b79c3938952437aa0ba81eb0410727786be6f76b71f54e7080018651c1165812d8988313527ef3205c7a6ffa2a0c1674f1052939f076112f2257259135356f96b3db448c1e0bbce00d6cc4c12fd390d992c1a3a6145b75a0cd7bf1451860e80aba48c11746058a81116c711b70f0f387db0c39763ce98336dee07faab75f8c1eb9e106ada32eee4ecb23d4253eaf8a791c39ecb68f8160a30dbe7a6c99f6d1c63cd9dba20b161c5b18166cb1050646b0458d0d36f89f39a5c89363b61e8b8b2d2ec070410a4e5a60630d6ea6314f79324586ac1729b80d3538d61dfc88bc5e5ce02eb091062dadd3ba34c35633cdb6e66290b953b58f49738213787101167881811a354ee0450af2be0883051b68702c9ac6a0622f7e1ee4622b055d187206ef425b7cf6278fe09a2f5a00066e6c98c1f7d850219fd4d25c9e8bad93822e0c29832713730af3fa4bea09e38b1680915c8471a80055f05da4003130822d686c90c1dba4314721746757c7e08ac66cfa7d58a11d31f8315b8e223950cb09831f7f0ea2b6e251ee3060f06cc6265708ff3959bee05784201ff786f178c10f7334ef318dfb8574c149e96f51e9a639940b6ece9ec1453ad58c640b4eca665b16ee344cb4e08b5d6a0a92d2a5f6f70e26fbdd7b2c389d992ed9edea9d2b38b235bfa1d6a3d86105e72a778ef139b09c1d557033648d930ace9b7cb470e9297819fee73cdb43b1b414fc9118b2759028b8b6a93f8378471681821f89c6a658988fb59fe07ab86fada8589ced044f52da48f1f19a857013fcd0c346abc87124394cf02d36422563489163096e481fc12347555a2bc10bd1c166869cd2c649f03227b3489535d521c1f5207fdcae1259b53d82e3a5213ab5467053e5e8e314db577711b4cb9ed006113c3b931ca6979cd9d3b3310427a70c95b4729c3aa4674308ceca7fe4f164f74fc9b3110437f465cae1a291f3793680e06d0e391ef994424ef36cfcc08b6079e22323692acf860ffce875de4198e46dc1b3d1833f7bdc23d1e581131e9f63348c45b703e762b4f7adeaa0a203bf62088dd530078e7814e9adbe0d1c789fea714ef213a6be8d1b782aee5d975ed299b7610327b79a4711e9e31baf165e8a0923293b8ed26b87167e471b169ebd269c7666e1857d1c449ab2f02a3c76670a1b2967b1f0259a8ca51c62d607165e0e136b3ec7ce9257f817f239ca945aa9e50a27e714d3e5dd61c76985b72efd59c3c692301d56b85146e3fa833a4f59859bb54d3ac5b8146355f84126c5d87452e15f7d6b06f3a0c20f16730aafc7dd6352f630a9620a5f632bd67df4518a29851bf31e2ba490c2b3f0968c12320abf26b4c207d1ef3f88289c4d3d69fa0c853715bd4dd3dfc620289cb6912c62295f0a924f7829115390a858a9239e707ab3739035b30c914eb81aae1e568c8e909f134e5a86ec3064aba0fe26fc38720fb1f3cd4bea356125bf9cda1f4726fc54291fa61ef1f83c30e1a6ed914b96dcc2765cc2e94b1f65d7b425dc0e72b678f88e1ea42be1db7d18d971e71c7253c2d39c695b622b33d793f07360725922857f9925e149c664f69fce718c23e1c61434e7ce3239430c09275e24856675966b1f4184fbf3924d1de17d14c226767dd49a36c215f54f6da119c62319e1a8c744d5ca1e4de722fc8f467324e36d174e45f841d2491eef12e16f4c1aa53ffa87194484f7e92d857d203165f0107e040b734136fca268083723e51842f028c28485f0936407a9912384ff39b3cd86078f633708df0397bbedc958a320bc8f2aaad53eacc50a849783b07eb36eeb6105083f9c995fd6fcc1fba01a2ac37399871f9ca416aa434da60f7e289363f48997d0c8f0c10932397d58397bf0a37a771817a207ffe8c129cb9d3a79270f9ec6589f6c62f0bae0c1afdcd9730cffe023e60e5e7b7cb183539a3b2454eae0873972f4317d70c1a583ef992a31690ae123998363f9a3935c297db372f03de54aee7d1c9c742ba6ea3d1c9c90439979a455abbcc153f5a0b28accb4ef063774fac852eed82dc7d106ef5d3eb00ff9f38d071bbc8f4e6a9dd3327af41afc8ee73ebe540d4eda8a9d95638f2ac569702673e821cd46839f912c26979cc149e7a3d616dac3bc197cb3dff064d3e797c1495531f75493c1b3b33149511d8393c94672faa468a38ac1491be722a1d3a34bc3e0c9e4e06d29f64a8e04832bee41ff57a4aa07bfe0f95a88d029e8052f7b9691986ace65ec829f6ae1e319f34873b8e0e7cd9888892db2b92d78b93fb5848a18fd3a2d78136361426c89e7c8826f79f278967df96b58f0d275fc5a26623969577022222bf67c58e295150ec248feee5855c1894924a6145eb93a54f083c9db1e3705254f8e9143450a5e6a5289e935240a6e482ef2713c1628b8c96da225a67f7c79821fc6c58ccb92db3e27b8e1710ed5e2728cd56982bf39ce379b63cd39c304bf54ec249c4bc8d6c743865109558ccffa7c26094e8e2a4729a305099e851ca61c5cf9d7468ee0bb472166e690b152c4085e08398e6899c2f5e58be0a73c29c7131e4470f37d184663de48d13104b743c81d875e087e5c21c79572e430dd41f0e3102ec7dbea1db440702d8450267f3167f3074eea891dc5ec286dd83ef07e26bc6358c90c750fd61c2a5a2c0d0ffcb2b90e3a8ea6fb8377e0e6aaeb491e1df8a6ea1f07570edc8eab3ca590c581f315be56ed0dfc1c269329f769481060033f3e0a59f2abb570724c4134a6ce725269e1c76130d114d159f8df79629ab01256230b3ff020f7e6138bbac4c20d19636bbab78f21b0f027d8b5759a0c96bdc2f1d86453b694ef2a5de15a8a11e71f6c851fa6ac3c6b6485133bf038b29854307115dee638248f1682670855e19bc731a46473ee38970abf5a3e920f2544a643856b1e473139fa3cfad829fcaebc21a5c542d29829bc4a2e5b29973f47560a6fc42f420ab7ad4b7286ef706a915178122b872963f7077922a2f0abb327c4431f0adfc3467b8efe79c20714be450a0bb93d5e8d9e4fb89a3656e4303a5a763ce1dc8da758673ef1309df0443458b0bc2177a4e1842fd9999673d4ea39b309b77275889af346b2144df8914afa8e3a997574c9846fffd92c5b65e5ab60c27331b32c0f3999e6124e4ae7ccad29470cb18413738c1243ae849761fad206cfd9b194f0d64cb352ead6ecc824bcf4edb61d7e49f869528cc9b28f849f72ba9c3e9258110f48b81d2654943693db8e47f89e82aa457438c20d29738e432c6af67423fc38fa2883947b349a66846b729eb2868ae93e7a11ae67d9e09f61430ab5229cea286bca5227c28b219484b31c45af20c2b394fca14b88d6371fc22d93ec3996cdaa8a21bc0ff5d01f47918b6c219c1c4426757c84f06bdc73902a1d8493d7c3741b9ded422a08ffdd53e64eed953b32108e66ef9421de2ad70908cf23654df0f30f5bfec1d7709f29b2e32d1ffde0888ba528967a7cbe3e78a9352b92d1dfb6e3831ba135dd6a5f9c670fde64694bada93175f4e098650ec5c62f36260f4e5cdd5a0ea3078f030f5ea61c6bee204436b63b7875de1f840caff0cc0e5eb40a390ec283c831ab83df1263989842072f4a4a39889123c65b3f072f7d98e39e88c90aebe5e04627390e6e4e6917f5beeecc818393c7db3f9387cfe50d4e270b6e91376ef0ede5235aa749744d1bbccb1c25a2648397c390cf18d5e39e5983e3817f320feb715d8a1a1c1b19f1acb1b672d2e0fa892509963b98074183932ae7e6317557cc193ce94e131e7d33a02165703c89aac5e8f155f964706ce63c8cc1f2e6c818dc48313c3226710d8bc10bf9d80e3eabc5360cbe44c8299face4283bc0e085c9e123491e31a45ff03fec0e2486da94587bc195902991a84f92d3053f4afa63c2528ec25cf02a7d18973d795bdd2d38e9fd2b47f7214b460b5e856745084133250bfea754b9b3ad58f0b4cfa34a41bd8297572b86902243f2482bf8d27188ce548b746615bc8e9db3974905ef3a96d95c15ea564ec1cfa27541baa30b0335d6e04fce29a79c3e31c73fd5508313323b7a98bd37c7d2a7c14b52eba1e71c26b9bfa0c17bcb29575a98902c6c6a9cc10fd45c2c977c7e50c30c4eb5a492d58eb5366519dc4c1a1d7358ab99f385b9e200c7e00bae4106ef3dc8df352b1d440f1a83ff95917cb3e5387fe41083ffb16dff88ca61f0cb6d523078b162eedb58096a577dc1691993bce0c714d27f7c1c540cf9d305b727d347b221d6e0829f43b68fffac3b47c6d4d80256eda66a9fb121993a72ca9152430b4e287f0f5972eef5ecb2e07dc584a5a5160029d4c082d71e76567d566feae4158c2dd917b493a68615fc1cc40edb516d35aae0dda58739f8daa648550d2a781d9322f685cad86b4dc133f1b39f4b661f41ab21854a225cbdc4b3db3f45c761f25ca79428f81efc6f76924f179f5f64208c2e9e6a40c189317956091ead553abb45d1a0c613bc0c691f9a48ac66ab38c195892cff0c25175b2970810ab01650a3095eead452dede71b155bc50c1162fe8a2aca67d00b7c81a4cc0446d6525cd3d6ea4da530ea15e61420ebd1a4bc0c3ab3a66a4bd1a4af0a3e418d523bf6b24c1ff782e33410d2478c95cca23357bb8ce41358ee07cd011933a0acdea670d23b839cdb6f2dc45bf0b1d1f6a14c1cdad31720ec254938670c0053588e044f5285ba7ef188217a3d4f26d9ba7206b0d21789b377e7387641070950bad2f0f0f912daf48d95463f0fce7670d20b8f943baa5af508d1f78317d1c8597dc686c54c3075eb28a3c217610f56bf4c08b1dd39e03ffe0f3b13578e0d6467d798efe0ebc4ff2d7b93e7fecb8d6812f2556fea1c8f9a6a9460efc157b8f21fca4f848db410d1c78221f85b49023dd6adca069cb3ad5f07899f56ad8c0e9f4183643566ae157a7e4db964fe7a9a685174d93254b9b5938d1cc276f92ee78a3280b37326bc5dbe5dbbdf3a20b1ab1f0b5bd43f4f54fb1013460e17c14ab932f890abcf8420229f0e29c8374e0cd0a345ee10a67a4a245394b5be1c874960929fa8b4a8815a0c10a3707d6410aef1e1e73ce2afca02124e4281d55f82d39e88b1239346f4c2a9c50cb7d11613c5f5950e17cb04a1a73189e39f23885e313293964ba47e9834de19da4cb5c67bf1e79b0145e5aaa0b69aa228597f2f45cc8d1cf7ab246e1895864b5dbf049461285e7bd1d9235191de51e0323d8a20b1aa120bcbb2ea6e6ccba5c3a68a59453d88e06289c641d2264dfe827f6ac4ef35a8f9334f3ce41e5f65852746c3ce1b4af64acfc49245cccd3e8841f29a7f021f6458f5f2a3438e15ae80ed3d6e6686cc2f18f5972e4f46868c2bb0966131fb287d9c74cb895d583a68eee474303c384118307c48006263009198d93b4cf6040e312cec73fd541ce1c96a024625cc2e34443e6b633ca448e9b5425dc4822f9bd2e4c0947aa7e23c3497e406312ae6a76da761b25e175745e1725e6bca69a48f8a1e55053884820e1a58491508f5a2585f8115e24f7ff984c39d2d83ac2f7d0d73c8e36a68fc735c2cf41960d29d46784f7b92ba5c71d5c4461e6716791f1e63dc9c358af082f04092a398eee72611a89f043aa7b54f76977c88108673de6f83dc474eeef1cc2d99088507eb51ed6c410ce673b0fcb3b3afdef42e4b6a22a59ef6521de5539a8ca1e2ca5c8488f107e1c7b5699746d15680cc2f3bb10fe628809c297ae18a5a7c3e88f628158a542522542d6ace63ebe903420fc384b984e9321c337f8072f49769c2b578c4f1de407277fce2629c4e8e9238f3e34652d27ef51976a5e26d197eda5154172f0c1fb38233eaeb2ecc1b1b4f133db512fa0a107d73bb67e992a4d1eb677061a7970ad2622bbe51c68a08107278878184248be71e3d1b883375152d49e790fddb71dbc8be930b2265407ff553ec8418e2a74f0a34d26edb183e409cfc192ad16abd6146f49096b8d918a395a0ece07a13f556d44230e7ed2ec5959b4c39472c0c1ab8fb6159115491de40b2f24805b031a6ff0b2e5ec9d3199774cef063f98921c42da1c297ae6f8c2ab0d7e1ccb79ccae90d35684061bdc482a41c634668af28a69acc1cf1e39b45384d5e05ca808b229d633a6541af2940fb9cbe9a3c1cd39a38f7a449be990c6191c09e571ec2853766c9bc15b7ff140727f06b9b60c7e871c7a90c10fb2cdf585bf1c61b531705fa2219231657116eb115b44424aa798187c390ffad42a0b4356b1769e325612369f11338520f6c126248a60f03587f8ccb3e182b8c00b10f080c617dc54b38f1eede8b56337a0e1053ff9df588748a769ac9d018d2ef8bd1e7c5bce2c122b840b4eff871ea22593c61614abaea9913497d4d8b6df88f513a9a6a105377518bdcef3a65c9366c18f5268cf97333b738ea48105bf2d6a7aceafb973ecb98213ca254be890ade0a5a70eb36c39c8c6a80a6e5db8e49155f0cec1a854f0e353796c6c7aceb1e262eb042bd805d098829fcddd33cdc4b8d88ac1910253321540430aaed445394b9675952e5170c58309e91edd52b98602776b5b25325257e3a7bd91557c825f79c343a8faa8734e2f136838c1ed28933be6b553f9c409349ae06a872d1afdeb3bf630c19199edde90f925f8e9f279f4b14b3494e067ea4ce96147a6393322a09104ff25bb47c1e3be889e41829b7b735839a87d84466dd553bc624decbb3607afacb9e6e3a36104b7d3ed338fa56814c1cff1f44732398a06117c8fe9e3991ccf07991c34a03104ec3e4aa6ee89da808610bc770d5e1ec60cb1262708defc4848fe7cf141f00061ab1b95956c2dab8de84afe33c973c77624971f387296d2c5687e631e4cc3075e0ee222a5b1e84d6147a00b347ae04a38891e476a8e83845790041a3cf0d64224a4740bc933b883c2d42a3ac6cb5536694c7a69e860cbccb8cb2e29bbcce8aa8c14c22b648ec3252eb668e4c0f9d06f1d7ab686988368e0c0b9f671f1ec48534e1b1a3770fdfbc4a3d9102eff84860d1ceb9cd13e6ebeac4f2eb6bc08630b3050701816a05560462dbc943752c59c6bb2f7dc8119b4702d3349aa68698d1a555f80b13366e1a5cdd41dbc86b270227c74f5314962e1a47c9329c33278871558d4a215dbd52255ee362f390e8f36f2fb0a3fb4d0719a438e2bbcfa9446f36d8c291fd30a6f4a63ca9d31acf05346d8a8b461269255f89dee293586c7fc5155781333bf59678af4b1920a673aecd248539f6c54385d696424b8f97d4d4ee106af0991a9d9716a4ce19987ac3158cab210520a3fc8ca07673e299cdad05bb79d517877122dbb32224f8828dc1c07eb21797684c2f758631e73ea008553214a92b3530f72e8f8849f2f8f6f867464966a4ff8416ffed0622abadf9d70343dc6b2c709bfc62b4fb466e4ab78139ea598796e6e4d38e79fae836c33416b68ef50fe03137e0a2657de1ea690f5125e4a0f35f96b7dea534bb8e13dc8c16f07aa15530967d5633bda9794f03ab68fcba1949370726945cf1463dab428093f8c65f9bd031ff1c922e105f7b0963fbe20e1fd47e4d4563fc2e98e93da54d48e2b48331ce17534b39e7e723ca311be79d49683f530a964b88cf03b70e9e8e55e04d9a723781ca33314e18b847ccb895ae78c6724c2c951da76d0b1bb72cc20c2894f95b3d2d9f57bee105e0eeff5ca1355529a0ce107b7f12ab318f3854e219cba0b3174744f88b32c4dcb3be32ea55bac374d06f3c8caa4c283f03b44f1118bc8917546108e66fed01dc2a7e5c01208af62d68890feb2ab2a80f0eb62b68f273a3089fcc1f5c966b13d9ef8c1c9e01fa3f45dfab0923e38a5d1b3797ff0c18fd44335cdc27bfa7f0fde8f45cb79fcdbbf7d3df851a4bf27f67fc5c89107ef3d0e9d2b4bee8c4be3c1eb309447d25cdfc1ad30f93e779ebef1d90e07d9265b07e7435d75103ff2331ddc181ea6e093d2d46673703cba972441e33f2296831fc4b4f153afc9cddc3878722fe629f7a4dc3170f06efb93f4ff779027fa066f2d438ee4a7e330f36ef0ff7d6dc2e5c891c56df063dfc810739633d8e047464ab9af424ed98233d6e0686c984b31c786f7c0196a288b787cb2b5310dbe475f479d91ef230dd1e084b449a288f765ca9fc1cf72c93c58c80c8e7daa9ca9528644580667d663c911aadc543a32f89d345888cb6163f0358568c65c89c1f14054b335fb6c0e5918bcaeebacbee4e69a0383ebae5e31878acb53d517fc943c0a1d741879c1cdd453c9c3aa762fcb8c2e78ee1b62b5fa9f7a79580833b8e0c7305ff9349b2db82eb2c12635a5091e99a10537cc7868a5edde285f169ca9c98e3e87cb2fdb61e1b2aa78cd4e891a29ab37b96e91f20aae45becc71b48c153c559f8f3fa70b39e5ac0a4db47c4aa5c7cac7bbf95f7d67474a05cfd3d7490efb7328dd14bc34bbd9f00831a637430a9e7b581dbb07761f75a4e1408d1a4e9811052755858d51161dcf57a0e047592343d966b7cf3cc1bfd41922d3d638cc70829783ce1f623af72c95ecc0173498d104472c46df768f8a89640613fc38b630591fc7db12aa194bd02b2eb6eab2264e666653c7a8b4fe511382194af0725dfada0cd28c24f4b35951ca2f8404cf2ab8a85a08d6a8b10500dc30e308acc86c744ad6c59667a894657694a24db2314930c308cea44a9875190bb57946115ca9243ed9fb23bfed10c14f512de5b29bc71e3d660cc1b35c29b7577d9c334709c1cda1c3346bbad4586d10bc105d913768464bf00082ef71f420da27e9f3b366fca0ecb2aff77439f5d841d4af48ca9fc2337ce0c7fa383b6bf7356a7c61460ffc9aa88f1d59c87970171566f0c01b9f0fe5993eca5d31e2c18c1d3839fd85e4b4195386ac03bf2ea4106be55353c766e4c00f36513296c77bcc51b89881033f4d4ae49f1ce5067e2c19daba932c821936f02c4c6c6b8e8a149d530ba7430ef28dc84f0bacbcd2eba3a3dc453c347314a29d2db3f0e3e389d948933b458981116cc1820d5938dd414cb5a33f547446868d58381d33425c7f59f48e030bd7facffb7e62c45ce52b7cbbf2f90f993762785ce1755de8988ad8a874e903e3e10182c161c16824128642c1cd7e23006315080010541a0c45721c0792381c7e1480015d1e1428281c1010120e101210080a120a060806060008060606000006080685414276608e65301f113ffb4f02b53e38081a6d1e2e448eefe4e0fb5cc5a118bde5a418ef40a7a3ff30dfdc617d9b34ffd7f073d12f7e1bb37969b31c27467445e227f755a721f8aaf4ed82f77e9665f5bdba1d93731f72fa089045db88560ebb5199a4d834c95ed3e0c3d8e404d1a98cdaa2134f16942e68ba9fba41b2ba300222fd6a06b1c1ca6a896b6ccfdc63360f18c3951a5ac915597f4aedadcef6e00fc63a94a3a3b4606bbf1e2970253b672a21a18e88f40dbbad6a3435a3816bde8308bdcfcb169b680e54db13f5408b1acb24ca84317ee7365b9dbc93794b5579120d7a4ae5240048fbc521b26c423e8706e73d5f85f5ac1c5afa60d3a589fa8152aa14171dd0cfd013d14c91443aa1ce2f0943e1a836035a3a983c7980437517be3861a1f8f79b8c1b1f927fafd06f66e40a472275af5edc8473ad22bf37e0afda5492f7681368876d3003b81786e5f64530fec6c8e0351b39ae5ce166f2c92c2e4f8d4fd982f223b601fc623f544a3904486588ffa2f4609c33ecec7c0752a2af78c9e50cae72365db4ffd4d9d5f034c4951e28cf8a206bc3158b8034ff1d147bd080f7bb7c5215e1bf86aa9ef40ebca6dc46c27dcf35d31a2dfed9e13d1ce94590fa7dea84d510c01c78a5e7e03ea7262b79991f097b16d45de0bc047f6bf565f0d5bd5466c0150d689bd21e2d4b011cf4ce4d925ee8b33a8c9d29b4da52c74554706903e0f8fc281d6b396f1f8c7a4b0b1c7cfe80e15baf1acb1670945e9f36ab648e2ae2c6d954997c2cc80ddee4ee6cb41a4e12ede533a4097a029fa4a4ec773ec05976c55a48b8f09349043b5b4a28a671479ba5b3069e22dc94788a66345e7fb8cad240ac505a4a328a82ff007dccce8d4ab68283ef9412e3b125435a8180fa0a4a56afb162ed4be7443bd5c403962e29574c00cb41c01e849dbb75a9b68cf96f89d63dd92d6eed27aaeca953f48c9963ea2c04db3bbe3d7f183d25a25d32a480d55f84827834a980560455393d3e25adda443cc509046da84f6a044407c91208f7a3f80a52b9c0cca6f2890cdd31822bc35c105bcbce2f53bf4d765625b1393ed2d44b9268cd2bc06ea4e09b5bcd5bac084fed0034fb21abf6115ab06e62168ddbf0feb95e4f7a4ce9cde2074d78a9d21c6d57f7b5cafbd44dfc3f328e2e5b5ee76589391d0fd824bbd2c3b7d43c9e8a2ad048888d77a5745e48aa7f2d7e3a12101ba7a136ec898891e432fcdabccf66ea0f52ae4d4dcc70754345454b8a8052b684ffff4a5f26add98134ee9460064916abf75c718583de2c9ceb02e2b4e15afca12711fe70cba5fb1bc39e9e95e39764a8cbcc907b0dc5c5486c44c9ca42be1102f402ba5b95234f000fe40158a79905ffbc14f40d2525f74f40a85166555322f1f70d2f4c06fb2b339a1b2af326ab74f181a4ebcce5d6e6b32fb9051a7e9cc2341be933e18cdf05087ece950e94975163b55431635214680eb1e45e63900ed1901c956df73349cc845b2a216ab50ef40049e2a0fc6b9bb803e146d5aedb7e4fdc789983c9ed8817ce44849c0ca78be6c68b159b3b8a97609dc37edcd8158226241d48b004d8f039933a65a25fa0236cb4cd74d06c94966ecad561f4a198f8487c8518669a09c76cc6ab824819b89d942325ca44e8dd2f9795174188ccc62a4d2ea26b5656cf15d7b2eae7a0bca35a67ae7e83d26ef945f036f900b1030d8f107ec1700caa943234993983d18a22a49650d76d20897aecbc70e29c154e2578275b2af301cd9257af42bda9126b6a1b51d3cc92457abbf8a38e9985799d8b2d951ba41710f283d174e059d883163a0ba2b624bc6ed34d99ce504e31b2c173a342ffb6f102b49e09585ad229b0cb2bed38bff2f439d37a65995dbae0abbc1048961f62ee362f04b4d213c22eb7ac8b7342784be7ad77a30a41233bf7b46ecb290f83833f9bc307696ea4777580c982a941c4f715fc34589d90f834a4adbccef9fe469290344b86a7dbbea28281f0561a5fbca2408e420ea552337eac8227057a935e8a52d892e0334c9ce596c635652108f790a16cbd412e96f3a9631fa5b76cdcd1d096178a1bca5a55a454cef8f0f51949590312af52fd24695dab7da521e9811855046b01d728180095e577b1c659665fd3208243b8f42903c07959e8901640a990bb89bc9cf2b1b4b0a014182183ea944e1013da0aa376dedf002b4136c0533c1ba5ef98054da57ff75b7a8ba7f0905690241fbebabec72460bbe53b34434e4158a7a4c3bf7172ab95a54de9030704f411f2e3560e193d60d7a90b8a68fe143a8300f0acaa5600cb64c89291f98d8fee99156c19c26cb4a4c86c005c5b4c74286f9e05416ed8adc9b0443dabcd45031a54a44c719b5c5a3f1d93b47208fd96a81c9eeec29d02c5bfb7d31cc52c95b380ce2b6ba652f96cdbd52d64d609064a090f33b5bf85ac07c2019eaee010202013b6c352bb2ada2e5dbe4661697ff80a0678af24fda14cada154ad109d768a34502f1ba57b035dd4df1e3662e40725b987da53ee41685d6fde29cc4b342adc9b43efd6690cfa5860dedef1a4361a948e62504cde6d35ba2d5a49d758aa21ec1439e477e9424faf023dda2409af5aec88c2b99ef188836c7cc52ba3de648ab5b38515a91687abe5cbc924935d37f1407150cd2345a7b90f4f2e6af4e259950ee6a07676a7f2301b1c4df9ebf65ec7e7ad5133889599596d0595e355e213ea6e7bf67101aceae57912a7985c82d11e8475c5e4aac4c3f01d09cb25441a6adb32a478309590a6e8a47d3a1c16a3c61608f78e70e7b7dc2dc45af4983f1c94cccf2669dd08f98f5563319a15505053770e6f11298d706013bcf3c60e3c727feaf918fe988819a1a215ecaf25eecb1cfe29232477c21f97a611945678d33728766099f9a14ab62dd78cc888b346b0709f917598638607ca9305263612d850c308be4401402ec908f0454546af35427ec40a97580069739498b124c803d968a10f1b8a7afa46ab84ddeb2511df72a696ca1b55be0bd0ecd58ec06909711c7b5a46a28d5547ee7cf1daaffc286401a45201e09ad4cec8b8c0513b6d0f097de3e6358420431f80bba358630827fa5459c551b535731f80e59c2cde40c25e39b763f82009b4f293383d5ea81074fda72bbc32106e688a10450914041825764d7fe7f58f2e0081c24e56152e6e8e475250be06c6d984c32752011dbcc593b5fdffbfeeaf99c5022f40395dbe3bec2e11dc014c3c3a2311c13d063a2f0fbad1447b00f87c80490824da5260aa5c85ca450b745158e263cab2ce3196d4056012db99b102a3100c6a3f99e76a64bac0e628ae133b3aa59006bd2d43959391a90cdacc87ac62a02ee4288121dc11159330b63de8a333fc1d77968bb7faa4b0166a25258b4e4310767b7a0ae651928a396b91d6d7048fc6fc437a0ef7237ccd4d4e66b00dd59f29ab01b4c9373985b515a7d989d8d5c8afad9b9b72a3054e9f8e195ca45e01c234ecb5d4994779a860d15374497bdee5f84618095df991e2744ae8a492ae497b846f48d88e4b58ac7ab46dd8912832d97873e79925ef0151a2d5a415c4b0de7a664f6a342d0ee6b501e22044b6513ca105ee3ca45117bee4e33cb01d461e78ed9c4204f99127636cd27ad2995adfe6206925d63354a8ce1679490e0f7895f46a9384f28f8c4a9cea12b48b675492948cd1c96aa7a9bfd9cb71adf730b7d83b4d41c28781d44e55213cfca21db544ed4b01a96fa24c8bc80f16b34abd5dd1b6899832e75082d3261a560aef9aee4651f5a150498e30e4fa30acb318fe21e917892ff3621c4646ad88b2cfa491a410c4a19df7c6091657125e3f49297b7a29809c2f7812f1e64a04c27dc801b6248c043de9bd5094749de19cd6007d97af0837aa29414e5148890be1f44c0550d3c8259770c19462f8b426bc3daa66ec46d72955555e0daf4245bc289eb0c5213e4353d5014c141575761f954003e3d0381c8e60a9a3fbe47607feab92f4dc8c66a6edad89ef52645c7d3f5570a112f49ec6a26e92761f6242c5ff7634567ca4fc4754e64e5dc591501639fd3c03633e8a2c63ede1316ff31e4988257ef77ffbcdf7a1690f58f47c9c42d73bbde0e289a73074cea6149252022552b3fdb1f9229034ea5747a56744e6707b8d03ec9245596b9a45173a2e48c1e24a0e1c0a6c41201584a458099c7f64a85d894fd7c98d51e352810e725f2a163144a8d3750888740a5e9439186063ba8a88209cd34aa2f4e11e91e0eb79f4ddba3e334eb5128b6cc825536940f9114ab0de49509212767c01867d7b918bd325894adfa7fab8669db630a03f7f3ea91182dc083cee7c83b1e644a082ebb1ad0b8ce949f2a433e7986f08c20120b1651fdc53667b0d20fb9a07bd532eae5700d443a401ba89f34502ed9f5477b62a52c0c666ae6daa0a4c659fdca3d28aa184d1994b09d9ed5661c919d488dd708f5cb11803e6132da66803d121633adb0b90039cf3170e0b37e65862bfca93611503c61074734b1535dabe239326746a2902cd32a92a0ad1aa9dab303e5c74bb4b2713989cee1cdaca26c402c1c868eaa0249d7ad4af0d6795e3d3680d09b79dfae20410ca217cda3c1760ff686ac454c08548961c5996541617154f0b87333c72a254de1e097bb386516a314600e041c444a7699478e5b34b5385e3f226ae00461af8b234efbf4b22d1e89710095321397a22a98179e92936eb336ba64d1bd35f7f30d84d07f344595035b30978e9b6c9311cd1f7723ed5346591f1188be49540c62932a08be7228441999a9d7a9075efd56ce0034a8c000928ca8416f91dec4a7433f24562e75db5632be999334f2a6726b557845a773768d8c9b8495dcdd4e474c6913676198968f139478a3f7e4da5a1821e8d25c52de7dfb4358ab744c8e44ed8a2e70a3a749341c53b230937dfde8cade31f4db385b80239c1e65f29b74681c5d8f5e876f113aac87ddaeaf0da31c1ef83695c3253864d4d8329a37741aba91c3e8a664a83f0b7eaf34b87b879b1757469a62410d51059f44711276347a1c5a3c7c7678d2f3a75368ba8c0174a1f834c1dce04c7c4fb5455f438e008cc656046e1ce7ff5c44b86bb6ac6fb3438021ecfa34b8e70ae7718788987121100e52f5b6300cba7ae0f7e0aa7d9326479bd643658ffd181b0c1f01042f5029cdc15d051113fd001a253c10c78b3f10357907dc7407ce136c8ce71052a0370a826f2a24443da59a7a38c2807410f999029f05be30586edd3b7c76dcdb8cf23e5c88df94e1ef26c93f972c6cc04283f90b5cc8f3afe258b0f4f9c19d1791ae707eaf9df318fdbf526fa68cdb9756d9f0ff85c2b923ef549a5ec073d4ad22f2904404ec439f7fb5898e27ac347a2b0b1a1500eb7f6f5635118d18852ac24ebeb50868c9efa0ae0cc5d007a401778f2e11cc6877d98036bf02fec3dfaeb801338993300e53cdb670634730fc83c9e28b1e80f620745123475ea5a4252ff5d807aa8542fb0c6f03bdb04e8525d45e9e91a3ec93c55016a322d8a7f02e8aad2b2be3d708ddd5d779dd63b89385111d5d8367e74d0f44be72d9280c1cc985debc2eced4503d3f7878fcc9b1bd1904df9d9f7eea4bd11db68b4f84df69ec13e23c66896b206517b34ebb6a6faeb6aba287327fb50c167388ca8f4cbb17044f47e952efcd10cb1e9d56c017fc51dc959d88c5bd7fdaf374f10fc9dfa2b812aa11ff6a9280e32e91b4a558c522727a8faee1a7ed56d7f00d2debcbbd3d9f15524c4491ce740c818957da3f17700e6f4d2deb0a37628284503368c8ad4b4a753eae0a4d637eb130700519400d800ea3c0c686825aef012d8b8fd9c8ed0b896918621602d239a05e24b81cbf602b9d0fd0b50000d3c38c7af7b035c6b9d8b56f782f5957386eb766d713d478c5f23e3e2507444eb57a78817369d02eed898104002d7ab2bf811f05f0bf1ada8770030925b691310db3640f63a41718a91e4b5d5a811222daf022e668e0cf15b5f4c1f40f4a14d36c3c7a7cc897444652ea15844500d1bda8c6fdb8c9946f094d1a96906f6970711a21cd58598c5d391bbfa0da0d26207503a85844ef6c57bf8683cc2400b9cb0df71e41fcd2ee2263fe17adaa5ef808f106af4cbb2a01c25b09da9e166c64c1749a1a04edecb6ee4285d50607d1a546040e8f2671d9a63500dc6a8577bdae4e8dbb37371dd292589c2163477b47401eacbb169348e6f2f1d141bc0ca8d7d2aa6246e56a4949c6e45f2ea7a064eb745193fd209a9c2fa0f38a01437e719a862ad0dcf6e347ad359e0685f6c6f138a069fd5dcc685f5d50031d0f9607636e61910b61e9e17ddc846dcc89508ad55a9045e1b13b70a17097c4022216d2102e80c3c17b6772cdd19298762b73ebbade239b2146a8db532eaf6d378ff39acc89550a640a46bf1fc8d04f7105280a6858c3e9100aa50b2f32b205fda164ed2faa9613b8b34b6ac1f1fb26e684c67f17ab955bc686244bd6d2e4124e669db06470e9c2f1a9804ce35a3eb54d1b3137bad0f8cb6d1140f8c235c56955be911004ca25d810472a90df4b6d1d0cc026440b77f83d2da8f0a17e009b6286dfb5d3f32e22bbce92081572c018b5839740794c965b8586434577dd6b4ddb3b36c6a77ef30745dbad89608b3ffd70f06d442ec0da09164087dba36f038c2820d3e6088079a6821e09bbea05c14801a2e787160dd9db28b0e2414990c6affd7ad95ee64fda22f1e1c8d6134e2054b4a7956ac8d46f5bf2813e45ecba3690cc10991684333e92900dd4fc9aa2980a385e63174ff12f998cdb4b39dd3cd4a9aa56d61e93c5113eb3473ec4d9a4c3b55d865d770c1dc69a5b6a8810e91c955d32f3208a86098500cbeb1628c9a93aa33a9b4eb22af1f7e33e77822d73b0fc3059bf9ba5f0f0726fdc4f4b639dd30a748eb8ea9e93e55cc35969d6d4b6c70345c5d16588c8233799272522d2725a20f106f60950a3eac8fc60dacbbf0e0e270a38f44f1820697be78ff8630b20a7386fb94a5ea3c5d11a0cdb9b79a743bf6f7f7de689ce18a6eabc4cfdbc4062011cb263a198ad9f06dc8364a2997469db87f15c8814167893b3c7b649e7c27ec59825a18a57a6c71852b23968563e12e22de09ac620a5db2036cb0f2706a4b579c523cf402a5b41fba1bb72953e281c457604453293ea7001e1b9147763d2a8ec587c2563f7ffb65c8f217c7395b56d648a779bbd6170c0e9b99337bbecd9ac8a82ec1b880eb4b33a5ee01484550b3a2456a02715a5b77c2c3207c6c158a69c578a549a82c495e5aabd192f10566b7a9c85941d39c1c580a6883081eb744b320304d88213f5fe64b0012f0e665dd7d62d9be9c345334a2fa71305ce4e2964071a768b7506f17b670a94ece1ecdf2e17691168d6c3ac277e2347525738196b25356f602a42400e3682b33f497062515a4bf4fed6db51d3933d5f4643451866922918cb67fef684d5022948a3515f854ae1d8e0530e84e7f274041d60005b25faa0f7b9e6137c68ac301c8dd56771048f7a4ab331d60a333053a139c4e21eb48a94dbd80872461441c324a515d0e0fa6c52e5d70e7d7e1ff1bbf41ab3d5b778e0e8c355e323b6fcec0eef53063b366676e23a35971d3510999cd83d27721f01e6ad1bb7b26d37ab5f8826089200e8fbb587294f18deb220b75a1b437dc747e26912ec11934b95e1551ff8b22e060eac8c09ae15d0b4b6be9afc75dda0deaae5e190305338f758410ce49ad9b9b75787b61a42e5dc2cb6a147a351df04e35d38c992bf985dc1cb8e87808ad4e54012de7ba0d2a593f142807ca71dbd6c5706194d3be79c0c6c11e99a2190391dd1970c88e76ed7dba93a5913e8bee33e0b6b32af9ba6f62399a6649ab915e1d6381083dea087d142d8171496ca623808337a0e0ebde307554e19b96ec224d0e9fdbc74834bd0a4a5f8dd8d93582a7634660a9a11252200046da4066c5bd4298b9669ee185d029c790179a43fc08b2ee170beecb6d3f57b19ef4e9e14720867500f83ece013679e5bc5ed613b8cbbbc4d5c9664aa790984b227b2d8df330200f0cc0a16c167a0225d6e1c1bbf3623e19077a6fb8fd20941a0b9309196968477e8c9a12e6cdf7c8ab8498509b2e7baab63fa76c25c4a5cd06b5069e952157203c83654f51f5a2b2ad1a434ed5ba2842e875d78d06dc8f595d91cb28b81a0bdff4da939462c9e045f8e914be8d359d3eed869d42da1694bc64ca56acf6000486c8e844982ca2f8ef43139f6e93d76016772d40177d16d7c457651ae4ae45dd2cd16a30f8b8f2dbf30e942c9011d8a2ae5d2a2dcf237e24e84445b37dd8435f4eeca89af80e7f6c0386824180445586f6ec821d866ac93da463624e075f1772cec40b134eb44786f78a96fff28e09468c81594d4c71260676f3110589e879aa0731a888f3b14428a4d5422d63f4076c15a77c2862b420ab1fae43b6e5f0c2f831379bf3af7fe9748aac1842d262487139e3550d54e1801c63445ce6602a56b4998b828a0c49a5485a24d2fe624e86b88d66051cc1a01b960f1cbdbe3cfdb50290400132a07819de3ae92c500584fa09beff22efd3cc9f6d7db49e5516f0d70b15b4168441806c818284fa3b031d5c5251a70e21e28e4a6ab554bed883d617c2418cab0310a7e6aabe1ff60e9ef71c54cf7c51e99d4ebdd9b48744321d5d1bbaa2ed6e2f6de673a1d97bec65d8abc57b7a749727fb5fa28cdf46bc475dd2fcb79e907491f6b935b90eeae631bb3f9576722ca14b48b7be2ee3aeb1d7bed76e5e5ddd6fba1f5dde7441754de9fa55bacb8751de8913bab1ba82bb94d37b5e0c1d5cc7baf6d3ede5bc2a0b435a4e2bf2eeb0372daf015d36b5bbfc43963ac8d635dcade75d23bacbdf7895d9ab6e48dd1ababf5c776b650691c7e9c2d415ac4b52d74e177a5d64dd8abaca5d8d783dea8ab3dd42e87011d2eeddf4d6f476e9f5f0f2d405ed9aeaf5ddbde744cfe0f9583720d17dada1678d5974ebe93ed4fdd7fdd55d10bbaff990675408ede6f4727a7d7a817a35ebadfbeaafe2a66b9be1facc689bf8c930abca77684f8956c0b8e719c67893cbcf07acd96a53f5706355fe36225188880a23fa090a0983b42efd80622050158e645920a3a3e79efacc0535e24664cb277d86a2b1fef7660e7f141ad76eb950045eb3a80522ad1dc22b8ab5b73c6c58ac4cbf9b9b927bb5045957a867ff01ed2017181711feca5a8f8696be0879c9662ba0fd6f2b3215cbedb600ebce62638facd876494f9e84ed5107e8e6d857f580f4dda4797c5757f5cc8de220280f2e4dda454c90ad1cb649e5d9b0d7d09af97b2e89b99a867dbb64a904208b51fca950279fd0046d09cd38f5ee40d794bdca940b38025a5181532d6c071840baabd90215e000569667e851533f098d91226053424ecc8565812c46ba5997b570300abb2970f659d5a6d528fa2578736588e78d00ed9a2555573bf7ac19bae4736776cebb85ef1df6f67cccd87173c51671ffeb0b2a98163707103cb76c5f70a4a6f42e04897f5d591c2bfc5ede80097d1e43b30ee56f59ff5a4fcab15fdd6cd74f8927b0eea5398ef55fe7d3f44d6bd641fff3c20beecee4ec0903f129e187add46db60bbd1da525e3033eec967aabcf936b6c2e49fa8003dd1574f501219874cedb2632f573b05c430c4b21e2471ff5086a4e74c6934d3f9b8368e66a687fb288eca34891b8448e8e2cc1b5c8e438694800864e62d8bb3d1cdd1b9f2ee83b8a2798a4a75dae39b5d0fdb0f59b374aa7e72ff32137519b284623602b02a7755a09f82ee10b290d1be4ad3d814fa6db0ccc198eda902a1181439a20f48686f5f016d9334c4c375937569b7ffd5523c106436c2fd8c75bb943e57a0c54429001ab84a78230814c789c1732e94046e8c4c017a30399598114fa5581e2126808ea8e405601b80c6418e6bff97423c83457052f37c1effc7dacfedd74108147102fd5fa380bf3ed070668e82ba913204d78e6272d5ffab557d7347489406e20b7e00a411a0532ed422048bfc0af00a0b1a80be0815509bd41ba5ee0270aa55ec546810cbf0722e39a7fd5ffc005aea5af11c90288bc48f03209ebf526023c0f64b247505134a600e5d7a8e7194f18a3d485c363d1b58e491b807a3bfc3748fc143b25120b08c5999247fcef837a74fc149423b1c2485860e00632697ac8ab9eb3c1aa39f64b0b029001c102d902b6026481a4106432498381eb0f049169b06924441db2e7ec6b6ac12881c31a647cae7bb34108826c1f85c3707edc54d8f600ad48d08d505c0632f9a6f40035952023490215d22cd0eb60a01e373c18580c2ebb02610f4d0913f8410135124ab856bbd78c8f1a972a8155098d446776e00d44a7a92750511cb095f42fd205d9ab573352e50bd60dac46cdfbf659e1d2c7807d94fb0ef2360932c11d28838bc08f1235000187ab2ba806eaadba654f65ef868daa2029c195d1347b68a1c87aeaad0b028ab53b972f4074904207f003fc003fc00f20db0889adb5de499429c9f2a95e21e722534a29a59412c3d7751fce38df70a4d134079709030935092849abb65d984491a3fee424a6e2a73fd8564f1746d50dbd3b9fb4051d2acb8569cee2bca8a43f8ee75de8c00597d4c6926c49cadda2f0b4af6ab999afc3166693740853f7512dcc277ff20875afca26b409c0600436669420081f1011392cf01a20e03043072dba55adbba8662db216c654740a22f24255981db3308aee1953e2d9202965094420821a23344af0e8a4ea90c58c1a353c7410e2e181808e5898836753caf4336ad4400974c0c268723ed9548b5f613a59a7962b2a115718bba40e2f4abea9e9a81506b93f71fb16962459b3c268b296ebe8f419f1d32acc419930419892df249d9781d44e154e03e407346e38a02315954e6a54ad96f11e21353c6c9c19666a830e54e8f2d9a6b16919e3a5599f3f5e44ce969119a9e314a652f9920a6d4ba2b63264809c8083c314a610a679b2c80f35cbf9606b187494c220bedddc454cd0771529cc7ae55f41f4543d3474002272a330a6dc29b92d1fd5ea1685d94de9c99f243b140695a49473d4149d3a897fb0257a07288c2e6245895ad3232ffa602b9f30594a1f269dd88e12c4f484a99389df9315d64f8c3ed8d63a612eeba4dd7992d6a5241f6c8513a6b53bef52ea3927c71f6c3a3661ca3b2a558a73fdea8cd584c92efe255325ac8e124a5948d09109f3ff870902e19d0688475a0a3a30619244d733bdbea47b4c973069359ddb36276809e21f7458c224b99f08ed163b23229530a7493a8a50514c5aac3ed8da2861ba50a92f9ea75caaf5c1662be89884d154c7bc18714ad8820e49984e662f947685f3794522615272ca387d79623d27618384593fdd95595ee41e61d0caf124b784913dd20fb6e208636f9a6625a1a4dc973fd8ce4464d89801f27b35403c6c887434c29cbda2ab6ea92ff7920e4698edaea477d30f223b7e4de85884a9c4f1f867e1977c4c14613ad1392de82ceae78e44986cc484e9a65a07718208533a5954f81cb7435cf77176b9adab62a525cf8ea13f091ac27c27ae5fe5523a9e2d84693e9c924d90760721cc5616b4bd9f18b24feb1884c184ba98af5d259bccd621089312ba3a84b0a04018554b892245ff75923f40184b527be6268a8fdd3312aa20082724e4e81f0ab36929c7cd9c5bae5c8c396b3bfc6012dd52a85a1377f4c1e4256a46f498d09d8422aa821a78c4a0830f26f13e42cdc9792fe5eb83bb6f64c8888d8e3d98b34bc9b65e930439793d98af32cb3a85f3141ec22c74e421f5c935b4db1380c1086ac08083e30735424254d0810783ca89a73b18b6949ae06f723c39be7630db6a9f60a5e44fcb50471dd00c2b4bd72a97b36c2ce4f88f2a41caec4e07f3dde75d0e6929f44c47c4d1eb113ae6605e7d0df5bfe35e6b92834909ea5f64b8dd5f34fde360f44ee2cd3e880d07e3096af4fb83e90dc650928e39a69d6e2fd5e106d37d3c21f465bb0de64bef954ac5b4adc36c30fe8d09195f4b0d5f91d0b10663854b265a54e6684b01e149c0c10184ffe85083f9d6f32fc813e75d4f3ad2601a17bdcc4b9ec3554783712c8993cb44cb9a1b9dc1d42d26754bbcd196630683ca9757fff94cee313bca604a2f222da7920e3298540e65c9dc741a135f0d19cce81883297fe7fc8d0e3118467aa83269fd92d8274e4247180c3aad5ce5e9f99ca7c4c376091dde9c86cee9c4afbf600af1966eeef582f9c58210e7e9a4527717ae7ab313b7994dad98756fd17392439570c1a44dc53cb1e537efa28e2d984d7afb8fa6e374bdd81d5a30ed7d527ae6dd3fef25c4fd7cc8143ab280a990915dead21d583049a635cf4787c99620918e2b98326d2d3ea592d74e4ac60b38389a091d5630763895b3b37c324c4a47158c1754c5d7621d543029c9566684c7765653c714f28ef3ba9495d7935f171f1374523ba460cab1f4e7a81b2a5ce88882c953b0f6b8b5143aa060b279cf13f3781e9c196a19e8788271942499605234f931718269b404dd1e4c124ac95213cc3177fceeb3f466e799604e41899730af6309e6a09e942cda2525983a9cb8f87e9a76720a868e249884db074f7e695b4307124c723577e4ee925462551b388e619254924cad9cfc388c61b439658276ecb929f972068e6298b4f4092bb292fbe89318a6f333311fbd3bfe05710cc334b7a2ba392ac9deaa55814318a693175efc4d46048e60184c67c9057d9ae3b10103d31d3c484be62f4ce2e2d45ce9926f2ff4456ec9526d56854b8b7535f2b282f7961ca6ed854910f9568fa6b2534962c3c6c13b0e5e98cf3e872d41d8c6077b17297da5dd84fd521766f99225d989df0825cec59ae95ad1dbce62c75b5792df4f52427333345c98bce5c63ea5a758da988170057de6020e8e5b984ee85293db45877f12c400872d4c7262e1653f6ab8273fd86c80848c88c858ae85b18332d554911686cff6ea9372b8291316c72c4c26e7e027a87d979c9418b42cccd9a4a44b905ac99249e2e00003472c4c9296539694c8115a270fffdc12b4b980031606a54774897657c2c0f10a634813b30f0e5798cbedb35af34c5a61bbdaca96b6654b75cf3ccdeece25439f943870b0c23c6641fbd4662e5c3ee158857176f4a792649978b104324315264d0f4ad250f231482e70a4c2b4ed39c4ce84bac0810aa307cf3ed87c00e21882d2672f23b951c34b1a9ec224dc67c9ab25c94a6599c2ec1dbef2f7e875f1bc14c6b724e50b7d5143059b145bae2eabb4bb751d9e3da51c1e85d1475b4e59beb38e2a0a8385eb9653ff3842612e25fe277f89bb711d14a6ca72594cbcb44bd18280e313be8f4eda4c505d042e9880274c27b7569cf8160c383a61545d51d144ab50ed45e0820924270cfa4d7bd28fe979d2de84f16af446b343cb9e18248980b489c80019b9a109639d0927c73b7b763765c22cfb6796e34149e0c084a95285ef94175fc2f4a6cade74ee78be74b1c16109c3e79874262c8921c408a4122629dbaf99f820b231250c26464428256f1abf4dc2b4b26179b115d44d2a09d348936276e364ad9f6bc9038e48987a2c6c54ec29c9b40477c00109c359b0923fc1843c1765d4a891c8e07884415e520aa9e15102b6906f157038c224267928f996653fe97cb089fc071a39333c6680848c74c88848238c96529ef49dd6f296bc0c3818611e7195f7d361fa10bc8d20c0c0071c8b30474fea55d7ab83072545184b94a45b4f8e2311a68c7867a87aa8572f5372124ed7111019365ec08108639e24fa872d9d43986a4457f024491bc29c946423f3528927d7c85108e37bed5a901bba73bf1c84307a0c7593d5ef20cce339f24e0ce5f971148449a92027ad053d9167b22aa881c7e1088479d4847eccabd97ad00d191f62839b0310a6d8d9d3e7fc273d6a7d8c1c16e4c7c8b1914118b9e4f80356b1ec6a634cbd5bb37cac73107e69a2fe317258c0c1f13132c2c1a17e305f366972beae9bc5f203ac0a93f6492ac928413ebfa930bd68115969c162afa830d8a7480b699652509ec2a0e24f990a52f468690a83dcc53b154f5c44a530e5ae20eaba39290c361f74bcaaae52988cc21cd6a669aa4b4461f435dd925e234a6a4928cc967368adb1d4410a0a63c5d2f1e3efafcaf409835dda2755923c6192c4c4ce897fe9a64e182f48d1b024cf0983c79ccfeb1f59d9df84b9a468116abce25aaf09d3499fb9519e4c18f6b26e9c7c4225318409839e494ae91111a7722e61b293827a7ac5e7e558c2e4392a8ad2719ea25c09838a0aafcb2f254c6fb735df97c4f1741226f5f9fbbe939230a53f490811ad2261bedd5d4be13a90308993d352546d8ab6ce23cc335b7ada29b47a92234caf7b4932370b96fd469894f849a8934c18614e25c9b13bd48a5ece224c175774db3d5bd88b220c625e45ceec449872927e6f225dc562441877f4ca2cff9e68da4318845736c9f7358441e4986c117ee9e52c84494a55c1e5469f1426218c6d3909ba94386f826c10a67c26eaa912cca365451026d94356c6c711e656098439fb870061b6bffe2cffa46256fe80074f1955dd0fe6fa792b15b7b5d3ee83c92e8e0e9bd712223e984e3a0be1fe274c76f760d029087562c57ac57a305f8b1e1d6b1ecc2e7ad4f9a5783099ec15bff6bb8339c7495a449576305556f2ce72296bb93a183fc95972796c74481042c8f3cf5acfc1f84969a8d5fa3442d57230c9a8feea8dd697521ccc696d9f544576551c0e462f9d4bd408bdc130ef234225533d4ae406937dbc29b96b0f0fb5c17019fa3f8657149d840d2651c7732baf3598048f3e7b6aab4e76d4605092da2739c53b7785d3609273eace1f677f5e643498a4554ad94f9413d9f1198c9fcc44d39db1190ca7f38c302fd9affc32984ed465a98eb7e1276430783c75d24236bb4dc6603a7949145d256230e5d35af154faf76c87c1204b67f3e3c67ad082c15c2697d2299a4c4ba25f30765730c94b5e30ca999e57f4e4ffc92e18ed635fb7ecc5ff920b66bf4ae2762ab7600e7d1d4a27cfa99d168ca2738e995fa7f27559308a2ad9e7795b2c9884efe027bbed15cc2ba78458e8c5d69315cc41df8ba59baa6052ded9d3b253d03351c19caaa37988eea8ea4fc1d427e90bbd242779232918ece4caae2ec9841645c1dc37faf7f6de2a28818271ee5a4d499a6ae9f20483bafaebce75ae753bc19c3c44aa5eba09a6607f1f3d9f5bd033138c6a32c593bb4b30d78f4a09a61b694a2979b424985c2d0927f2c63d8a86048392d23e8eeef079bd631877cf4ae82842c6620ca3afa969db8a613e41cd7897f061b4a6c43088948f32ae0dc36c5eda73ca63e8662a0c734e1f2b6997eb9e4a83612a532a0973a6835e1230cc298791a7f3bf308d6c8c7a2f6194ecfb829d7dcffff47b613ae195f37249d0d6f3c218ab5aa12e8db9eabb30fdffeb29f9dd924e7461d86ded24654f2ecc23f37bdbcbc4380f2e4c2a9e3b4e7dd2fa975b18fc527c7f4ecac2a5d8c264e94185c9762d4c6a61f2c930a13e575a18d552f6f924ad5baeb33096bc54a7722a0b9370e287fd598a99672c8cff7ad2c68dde37818559c5da4d5d2e5f613893f2f44f922b18b968af1ea65698479aa5ed9c7e84fbac3097a68a7dc719b39c5518ce7e2df4e4ad68a20a93a47167b25352618e514f4a33541843c9d36bda97baa44f915222fc047db229cc39a6e9f025a514e6901e3474b2f029aea4305f92426d864661364918dd1f11da9e8ac2dca33b4ee8bc1439148651da4de78a7cba101486731925cf7d8a957cc22016432825c7d013a68bdbc104a5c24e184fce29e72f53c1c7424e98e3bd5cbabf8739a54d98d5e4fd88993ea9e49a30c82bdd75c29e09839fbd27956f553909268c71a5f774782e618a919febbea48f53b184397e99c99dfaab84f9bfe4fcaf4b09f39e64e296ba9c525027618e3f5acdd3f98f1825615215524f4c353bc945c298f2a9c4c95d694d3b481854904f9d5a2b9cccee1126d5f93d7ad6aaef758e30e82c3541da9b6c5e5d234cf9f49274ae7e57d531c2e426a7ff1599351b5a84b9b2945cea278a307c8ad7e9de245549893056aa4ef52375748a0883c9a57b74c58a501ec2a0a4943f076d6782aa18c29c93bd5ab6ba10a6de17b724ec57384b7ff1c38330d7985c2e72bfab654198f2a4104a4e6a5a9403613e91f1e649de2f95058429f8772595a42f53d23f982d4992a0e412f4c48ffac1bcf9bb21d45c929df6c124d42939db9412cc523e184f8af638a54a1247b907a3a9f423dea2be45d3f460ce4fb597d3cc83d96d47b6bec9fb56e2c16079754dafab787f7607934ecfad346d3da9991d0c3bea92f4252c8a685607835a4bb24952d492974407c3bb9fa0533acdc1242e49a1bfe29efe921ccc9adb41e9949224d57130557b9f54c2c16469fed2c28434417f83e164f9fc2eba1bcc7e552a4ec5d0d1416d30578d8e2174101b8c57733d622d073fd11a8c9f4b2853f293ba6851832997905d49fec84a953498b37db455caa2c19c4cea6798588207f70c86ef4a65a7543318e4fa49eb6b49977019cce9aa372cc5899592c1fcd94c6754f2b4dc8dc1a0c45f0c79366bb75589c1247f0c154d8979f5255961307dca5652f894625fcad7402f984281c1b836d23a97dcbf605dc6bbbd785ac8c5eaf86c51f289ac4982ffc1565e30499d8332fb924baeb5aa0be6926925593e8f6122545c48aaa7aff821ac2d187dc6e74eb9a985bdb2775da6c6abd7ebc5d3f569a9da56160c2346794ef9ce55410d3c6a5058306a48efe05a5fc154826acddeee18ff90154c67294ec6e560150cead57639c2945052904851c114dac376baf2d3693b3505c35eae79de393fd8a4600e1b65926c4af688b61f6c782021231905c3b5883a412e37c6836c302828982bcd9224c90a5a6e4e912718f54a3a4ff2f555e96bd47082b93dc6a68d58dca86e06d504c3253968cb6ef557ca144131c19cf27a4b92a4be874e9ba09690a4c52a2c2518c3ed7c734dbe888e6f25c1dce7a6e494d57bb70b09c66cebb174c24d10fa3e3b86495909fd1e5c94bc26c518265982bef0dd9e2d86717b33440cd3a9ecbadb6d7ec8304cc2e30459329e1fc46cc230ca49f15db9aea4124f1f6c3ed0609843094af283add3c88d326098e4fb13c424fffc5c930fb682444066e42f8ca162414bd6764b612e41872f4c62e1b405ab245b762fcc76268a67bf796198bdb45f8613afe3a81ecf56124901e2217d1684ec5bd73ed8fcef5806780793a4bc4a76bcdbb8bc201a37928709d00ee6b0aff77bb2223550d7c1b0196332342f1b403a982dcc7f4e594bbe2e3938076349fa4e89e19e1fb3837230d7971c95837e1de360f0a482d041ac2465c3c124a527a9f49c341584928d1a6f307792f44dc5995cd51c037483418f29a57298c90949aa65886d305b3ca9233f55de6ba0e7410d1fd0280107870818816c30aa992c39467e7efa6b0d66d39ef4a8c5a806b34793b55cb2c8fe5b300d064fdafddf4af2d1602a9db486e797eeec9c3318deabeae7e33efea56630088f23f65bff83924f1a60194cdadc73d6de3edd514206939ce3def3d7640ca69cf3c8d28ffd95223198fc3b89bde25fa353270c0659420a06a3b598b0a1bfc42f98dd84aa28fb9f7126e805c3c45ec3c552b06daf14b4546fb6dc74494bd205f3dcbbe9d91dd11d6711b151c3a3900b66ad68d5237fadde1d8d238305885b3076f05379f1839ed3e1c7a1164c999697fb3e6300b39055d66856cc5bbaac7026a79cdf4b59c482c9d34e094ab89c2b18be6409bae72dade2bf080216a040042e98809a26d00a7cb977785d6d886c85d1258daead94c42a2c77a544f9091da9603cf9ea94ec789eaf94e0140c4add892daae45c4b270d11d0484f402998c410b95ee27a2b58ea83cd460d8f432460140c3aacadb3cefbc14603a1602aebf58a71293f07133ec1d8714d977f3d22726494ed009d60fc142cdef67e12bd0f0ac22698ca2413cd32edb4ad432f036482410997bd8ff9f62f7a1f888c849c11912598367dafa42474b76cab1aa804a3f89f244c8c8b93ea43a3c68c1935108660124cea5795df7f1dd038211e6a238804e3a86579f224aaaeab814064bc40051c1cf908448688d9cb4812101a770c63a95c6277d06fd501a146e2c103746424e5658c243744560535f0a8c0196359ed12844a7e128262182fdd9e891a9d2742ec32561084238651de2c98ba4f0dc33c6362c9134bc7eca84e1826614de5557ad4b5985f304c96f2626aa2c5c1c1c131850386490e7d27c99b17edabe417c6fc53dbf9a2993b8dbb3ab116eff255d3f13b7e9e9ccdbb5e1876adde4b12345e183cfdbbdededc85712d49e275094a5d1894d29f4d10a57d827a2f1706d5d034b58f7f4a3e8b0b732c3ff1e27b720b83e7ac7897bee6399dd8c2942eeff5d80515cb502d38d178f9acbaa07a5bb93c7a4f0be3e7f50adb4fa5fe4274b859983edb28397d9770b230f889a6ae73f0b8658a85d1cf47ffc84fbb9d5f5898ce4407b7bbec15461bebca15a6f30da9a2f7d30ac42e2cca8ce5504b277a95b4b2fbb7362b0cb282ca13254fee746815d65636bb9b4ba3f19d756fe1ec842c13cfa20a838c097f429c1c97479c0ae3792a49e7d36e264e438559dcae4b924c7a8a4259123f5318ecb7cc47c7afc4b74b61ce65ee152f67cb49795214b5bb3aee2bd7a76dad658892b398d5a33075da553979432913af1385295dd8863eb19d47edd9830b85c153570afaea2bea754440e1ba5b8a5a49ad4f982fe9bf699fd21f4dda13065b3dbd2b4149272849d7097357b8a09fa4ead239bf5e384e18d46bc7b84ba10f3619c7ecdce881b94d98d2b7a5aa9cdb7388f35d5034613aadfde741492f13c6aaffa417ec04214a4988e1e038210f72983098a5d56c0f51f273b62f61f4b10f4afea44a091a42219c258c9f4227259c9c4feeb815e12a61f8b060a9c3dc892fdaad0a6ae06183a384a9848659c951547616651c25dc24cc2f4ac57512164a9c931cc249c26c52c5933f6ab288ae46b848942b5cca974ebcc141c2a04baf07a5fd5dcdef7b8441eb99de7aadf4f88f239284d59ff8a88db811e5fa12b9ee107b7b59cd3ce11a77a58212de3946982ddde52aed27d494d8224c9e54f80a72564ded451179892faac43bf3126152feaf972daf890afa21c2f425871357f62fa9b97708c355db7fceb69e214cdb77ba5784acfcd10049f60a61ec38d144b124e57ac9470873e6b789bf3519fbfe06612e3be526990ef5d3f69f208c26331fd5e402618e3ab25f8210f5b59d0e0e10a9a552b1512bfb0aed4e69f13c07d3ae87bc0e745043c62d10ee0f6ec8b9bff6d12b91c1f9c1fce147e4ca8c2cf1751f148bb714626e25df16d54a506a3c4e759658f1f8603c133de588aab894f3116e0fa63ad94ecb98d827057170e8800648c88888c78dd343fa29492d0b7342270f57b2bf92d5925f94c6e121edb157d24299279d34031b77874cc35a5ebbb3dae325b19e46bff4ea23221e36446670eee0ec603ab7ec7152086509ae0ee6ea4f82b613db5309277430aa7b8e65793ee751627330b7c94a9e2773474c2707f3f625f18adac5c1249ed2d5c1c1e849e9e93149c91b4c49861026ba17dd3de706838652fa96a349137f5d1bcef8545bb939ab4b66d244ad6851d7e4d860165929cec7d21a8c76764950693f4689abc1a4be453c76c54e17940663ef2549c9374283a99327c9c4efcae549ce603a25bdc74fd946891e3318e647c7d22e6530ec08919e7193c1d41a97b28dc1fc39aec991264a3ea518ccd7e361e6bc8292c63018cdb4fcdb6779972e81c1204dbb2f1844ebe44ef67bc1b027ac855c3bbfbb0b26a5d484e90b71c11cd482103b275b309d64668210134f44470b06b9962a3c56b260d0f9d35b5d8d05a3e737256cc65730fa5bba7072ba24955ac124447a6ead4fd258f2ab60ec92fa79a194b426f6543048b91735da340583b070c19485f2517a2918f6635ce7fb5130eaa8d86f224ab47728983ba885dc18f917fd09269d24bd52b932490e39c1e8490aed67254d304965951e6b4cae799860104ab4a52429f7a02f4b30a7a6aaf6f77c4a3089b85df83709a696d71a1d91f2be1e124c49990996963c865174cc536951725bd08d61b494214edbb675febc18c613f6c4b3b29c180635af1794cacfdaf961182f9a7af219cf345d18c633f5f3e8a76098ff656c642bc030a8feeb906f3a55aafcc214dae49c4bb6a074dabe30a8d0e14e16a1f2a8b917c68bd6a2836b658d14f1c2a4ca42dd785dca268a7661146149ed6249b2a514e9c26c99a7848b622ecce19df359958f38e1c2b4fde14d56ad3a93bb85592dd693203d4e3c6d618e596257b9a96ecd502d4cf5be7ae2b9cc2749b4302729c5ca836cd7d02c4ce13c78ee139dbd735998449ed83f268a85295b49f23142b030456dcf35695ea94a5e6110aad54a1631492eed0a63bf9eacdeba15464be993480baf92c40a838725f511b29d6f5e85b184d01f5a7c76b316d8ba80d905eeea22f0a103101a17280e5e0ea34001021084e402fe22228f6a84d858000046446eb8800001781d9c1b3aa0716420400022218f6e788d101b09880100020000000040000b00000000a080f71a342e20d2ef35683480012b0262e32c20008900808848c24100019c91e31c0508c019395e2384e300001800041210f21e0c0040001e708020d8e005828cf800c477812023323e448e87470252173666a05c24af3123152071615cf53c13363d086dd25b00e1cc4804485b1c206b812023211f22323c3c1290b430c5afe8a973bdb3307d2749127a61f2a7bd6561aa3e0b2ab7eccd95508d19337e06cff8199bb1c8aa64f9bb1cb38166fc8c9df1335013168906c88c54807c050d90198900e90a933039efe53fce2e5e6346fa1839337203d90a0419f11a336e7878242059617259339959b26398f083fbecc69987bf1040641c10f436448a8dd00041111a202332406e241e212dc8558cbcc88c9f61805485d798910890a94840383352011215083222e3c60c0f0f04e4294c996b623fc8c714e67eef20634adaf81db314064f5be2fdb32895a693a41885716c8ac2943a7b10f2f4e85bf364288c9e2dc8bbd7b7fe17144611622354e446e315e4274cd2579f9f245e8ff484493095bf53fc2a41cb101b40f84e9892bc8e4f52d65f7a13274cbda6b43de8b44f3a64426ec2e8a62b3c090fa6e2b7d4c4952aa558a92e7d651bcd36794866c258f964dc73ce0942942270c1041213e664b2c7eedb4a55335ec264f52727597c63d52a6909e3765ae94f59a98451fdc4932ecdfd9f7a29611c4fd13357ee244c954f98d60f3296ed9384e1d35c0a3e62dedeb48c44f2f5ae2297d6522be4b28dd07ba71adad9848439bfcfc4550ba33dc224687a16154a6bfae97070a4238c955f6ed1ac64bb20fe60f3b05163cf04d908f3a8df761125c60873caa8ee9ce453d7cf2fc2f4ab57823a71f74b5a146192f784caa23d904c8449ae54ce9ba1eb732d8c08539e7ac9a3a64b16cfa143983aa7e792f25677bc3b6908e30533adabb2562a540883ca1bdba5122184f94bdb9b0e2ad7c120cc7f5549befdb5fc1c09c270f2e93022fe48e3200361d6bea43b7a98db5c8e0e006170cb5b51a2a585ca655243860e3c465ea4d81f8c6392e82728a52ecc637e309ca04a92f298c925057d1fccf94f2a4916bdd926a7201f4c3a66265f540e22eb0f6a84e8600fe6dd3693c3789204bbfd834d0fa62ccb97041f59e447b4069907a3c55392924eec9c04b58c0fc183c984efb2587ba972971b7807b358e9854e2e27fd441a20891d4c1e4caf6ea7e8880f505a1d4c9220ed9467e9d7ce061d0c7736d25b3cb6ce723f0793a404d9498e92fb602b72304949dd79cebb566a486226838c8371b6f333c7a46839367e4424657088c68d942a483898f20815d3c193f20daaa8979c87a757fecfbd56da04991d0e0e37184bca33f7bf62b6e19465477f967daacc68241b4cd963625e0304366c9c909155410d3c6e906b3065c4c2dd67cc254ba5de56f24dd492d4e239483598d693f89877d134985d3cefa9ac9dd4c8190da60c75722c693c4b797f06c37a9c1394ecde0cc63329995c921cce949c530673573ce9697d2383612ffcd8889534f623442e30432167390663f52561f721db90111b2906d3e7effc24491eb530988338c94b54f23269a604832673c962ddad5adec5ed5a56944eda7112e4174c3254099e37cdf482c13bb848f5f4c92e98db243769bba28dff13a8a0061e2e482e98542c754bc7452fc73fd86cac6dc1a467ba3d94ec95fd93c8d91101c1d4827188c0059d055350c2633cde050ba6a454a509f369547f2eaf60b090a3f27cc765f52aad6036314ae6b3831ac82a982ca6c71331f53962ccc54052a1b94aa55ea72d6259ede5144ca17aefe24af61c264f2998af3ca5d352b28a783ca360ce3115fcb2bb75be100aa69caff760a97c82c9478967f1b2934e30951244454d5213d7441f6c2320890648c88708da07b209869393eeb3133da88f950e24138ceb2979c96df15c82179eabe7243d359e0f360fa3412ac1e8a59f6295ee83d13c904930894b7fba6e3a5b094a9e4622c1bc2545ff1e773fd8f818a61b517aa55f9d52461f6c42e8c17b84241e232033decc18e6fb64d9d1c35a9f30fee0699462a0426c8ab4301a0f6880bc203d80c43056ffc9e1243fdb123e1f6cc330d8a7cf262bba73e3000ac3a43fa4cbfb97efbafec1e6f13e001939323ea42e18d6ac59b433710fb54ad1732895a4e4e2df0829d6c030f8a8784e2a5b481715d1b8210210fcc2e47174cae7259ed2657c726478388d2f6f230830f819274404692f03847d61d269eb63ae27a47fb017869357c4ecaeafa8517961be8ba6d2a9b57117a6feb292e2093a8a757461182594b01667920bd3769f24fb4fb034b9425c187c2feba756d589ad6ec1c69bab5a0adfa51dd75ef25e50137eb0d53822201c1c323e3928e0e07819203666d4401c1c2c40c1a22d0ce22bf7c2dce42446570bc3d5c591abf849848ed1c29cfec4ec5de66fba6916e6184b4a897f0e29a69785399824a8fc21be047142b1306a7ce509164d4ed21f58184c5578b4e4c19368e32b4c9dd4ce6d4cec0a53692dc93636bcdeeeda56186dacc489134dada88f082b4c925ab14f4ae9e0a75d5c853989e96c71848926070668daa80a9368e6a2ae63d2dabfa9309992b257befc537e212acc16a746cfe675d78d33c0536061561d6fb39d366aa77da0298cfd5be779f6a4507e82a530b577f04b625ddf4ea79014e620c65198c3a5d47759944461300bf5ef24e93db92ca130697a0963a269e75853c9fdb48f50e169003ff103f44410b013e911a7656aefe43349c809c3b48285db8ba5ec953a4775f1e0260cdb167af5834c13c6ad784947e4a5f5e83013869d5382dcd88c983086502a7e5749f2323b9730ffecd58e7f32a5e7ab21a3aca025ccf296e3f2f9c70e0faa0496bf4af5c196dc10c112e880064872e3053b05a484d1eca4a9f211da4eca380993b0f8d1c46e64953c3ed0c899718792304d89956a374c3ed8426c00e13d641c1f7c62244c76af5fb515e4724148ce1ed1382322344a900609b369114ff3a21f7e1f3e42b170e9dd6d2e887a59c54fb2ffef9ca90374844168d7b21cd637c274c19364d7297950254698e452be2df33f96b4651186932d5b8a3028d3237af47789308baa8b735751829039228c95e4bcfc5582fcf2d0210cbab492fca8723f416c08a3aa0725cb4e8cebfd0a6174cfa1795a374218439ab60f2dd5208ecfda56595171d30ad71022ae65dcca4f4198468bd82dd11d1716d141c8f1b00b84c1646a494a673f893c68dc08f1a8e108085332d1d3abb5ac05ff60fc2d495e4ada154ae68a7e30e9132e9fe8174fa50941807d30f6de9d9ede356444d33c66dca071c807f3788f2511d332a2f4b80783b0b21cc6b41bf22325b002eac1246fa851f2a8fc1425f6c126e2a1c6031a373e46540598878951a8642c858342d27030168c44025130105236cb0100e312080020601c8ac502c2509ecab9aa071400037044263e3c242220180705428138200a06c3602028100604018140301004851e12b5466aec6dd202d642c7d1043a3303790457422b52b1483765c50ec603e390758149ef1a47ccd51a256ad7a2e30d23725ebd5c390a40dda5cabbb9717f88fa83d8b896bc0928eac4fa97dd102efab30dfb58fa3bded1b9d10e8546d76a118e1c7db2e8731f9f7d1d4d1ccaa4110e4e65f18d10bd829455e32ffae1b30f91a700bc1ca8a529d8343d6a8c7151890a723baa76852b405a0c5136421b3b0652fa88f6dfc192d60c7b43bffdebbab681df7f89f73aea123ce3b6576a6073f0fc6250e4f2cb84ccc00f8aced3ac643766987c360ba84482a1b0f5c1aa89f0bf35e10272e09a962168652212740c44ce96238fbd12658eda8941beef21a08cd2a481450f73a0818bc4417dd0255067cf95fa01007124cea80f88831e7652235a0a50afb1d7e731cf341e044ae71b71316280a05e5c349e3fa2d75c7f7a3f2d8db63885800b15fbad77d2f0671046049a64c10145aa098011d16299e65000abd35f9542496231ea457845d2a067cad9e46a030ccbbbb8ed374887fe5c083bd8fc8e6cc4ebccc5cb17862b9da243a72582a8118a599d8b36ba711a87d89898b4002a655995ca2be404f2a23bdf430e88093b2a0690be06977f38b56e30d0fab96c7ea6cc82c62cff16440f2171544c2d025c61f1925ad00fb72917faa9302493f43b14ee2a6f4e310a7bbcef9458daa0e7863a7c43752e0fe720907224f53870c716e0a3225ffb68efb1cd035717e80f26283493f19f6d3b39b8414abe59f047bc24ef9d6d088edc2de906c7843cdd04319a535bfd982e4459fd26ca2b9b1228e28e41497eeedbaf08a387f5a87a5e51bfa44cb2b9465972c196215d675b0f2e6260dcd11756f37f755e2c86b95d9a01d8102b782d16da29d22b8ae7b4e6f8883ad1f322e26fa57c80bcae8b747476d411b7adac62c233c2619ed943a4b876ea232ad1861471462392ef62494bf68e048d312d54568079b57794281c91f827e3c0a18f157c5b0e1c65d24a58a827e17c1a5378c930ffd84f3238cd837c11b905fcd88eb61f864b6079f339f45faddd987b29f6f8072eaaec4800ddb11689b7ecd78fb5204973113050a121e0fac233b40a106490989d6fff2515f0da8486682c5b705cf471df6279ec4965f206ca8896e32b9c34d589a659f18aa264672d106e0e19b5d3b1c66f6390c4519a8cd6d17f805b2f8677b6a7a8bb647356f9bf3effacac6914789ef01a39d5d775d634ec2c8921437e56501c775ea6f98e4ef902b0adf5ee88f9aa49c5f7010e6b16e6efebe134896b0c5d3c43afdfc09ae7f0588987216b055276cabb102522c103b7badfc9c42befd4e2deef1f42548e55c7de9985927e5a47be46ce1ddece4bd331a29b5a9d035deab7216ddc26c9261fe9920ea204740d41889a950cc5561d63b0070a4f8848e66172d69fb4f4a9ef5ad9a29ac9fb3ac05e14932e6ecae241ff586980da5d5d4a733f2f2a57d089ef538953137aa0883dbbd042f48f1de869728dcb57129f478199153eb1a7fd9760b4d585c6c808a537107d605516310bec2e7388d483190439d129e099ad6b04d5548a42ce1982aba0223972b107efb78e2568732db94ee9bee544b10f31adb6b1f9d8867460ac1bb5c450e40a5985c0c316ff80aa34138a361bfb291b466255a3210c72f296335e37c5073a314e7775f146eaf05ee224dc4393f28a7e8ca114448643bc0083899467574d3303e26854d5aa238a4786530804fb26961674882cf1a3f164063260b83eaa32e434b781cfd15f4a93c3bf8358b63dee87d00e9828574a92a5d539b45c37f24bd7a8c5d683da32b2f45e6859b6bca23221cb529d871ad042bda4cadf28ea4ba5bf07521e0cb0089868bbac1be6d46010ff54b331c81164211d7baa4711a898b9b49a27257f7e4017886c659e9aa19e4f9bc9bdda25c66d0fecde1dd224c7b9eab77faf1fc35dddf7aac41fb3b8102a30b9442c76cb10dd6b614bf1e3e692041d902e9b4e035a1d82665a484b778bd1bbebfb73897f9e8e0f23423eacc2d750314760364849fc49bfe1496c7f5671daec006a8f4b8305a75c00b937b20c78b4a94605cb0ae9324c8529847636b603f7ad512d5e02c681621a52f767082127b737acebb3b5b11fd93d8039027f1a47afda0ee071645304ce4bd77e458ee384159e6b5b587efef9df2066adc1e2932155486c8ab88e3a39f5616307c6ecaa44b573ebc61c2081d89d8428e997d17d016ef43d30b788b71182ab1e471588c1cced97288a4640029a6f51a74a070490db2c59403c751c0aafbe6102aa00dc361b6bdec27aee50f94a7be8695ece5ec5dcb98a80a8e18d4dd63c68bfd2bc9e14d42ff2ceefa39cef1e11084f0f1a99495a9d4c9f412748abb5e2fd1e0f45c9bd0608118b0a4460278b3723903530dd94d965419d70ee3a751e3e04a9e15008f8e51223fd921cd8a55f2ca5702231a0f64920d6b8679e79eb2c9ae29045d1bb37d4905abbafa59cbd9c5b197790ba6fce4a497be58a6a2f7a1cf12591b29226dfb22d392429adb9abc66b59f03ee64fd6d081af2197e63f971f24841804c03b129090293e14dc23bdf2f50bcd29f3e25e29e31f0b9ea46ef955319c7d788e140e97cca1ad466a0785adee2a000653f7b5b09b13463c8368dcefebbb4e761c2941bf36b6dc215e57731fd5c6633297dd722db240eacc4c98632c89e6a23d3e925db23fa3c0d4b176cd1cbc307bd7b22f6081302011e1eed53f45c63cd3d845e220701a9600d2670f78b802e9fc65c602827741b57fa7653382338de1e8f7d485d20a0bcc46f2472c9fa2bebf602c1e04ccc41210268a32699e42e3b906e50bcfba8837ca9235d17958ce868c2615f02ef8e811ae58cd7ddb196f550b521519713a543e5f8a62024e558258d37082aa6938d7e701d01b83d938945a8c84b4d1cd167b00ba7dd9edfe07c50e653f2844167133d42fd970dfacb889930514cc0581bc948ef89fcf0bd66b7968021791b468518ab65870c72a1ba2ce420d3bb897c5a55d275278d0fa7f67e638e742e83e872b2302b4b5f7bbe0a70d290cac1ac56c52d24fe589f3e1d3afcb49127ddae7004546bff062c62ca2dd8885450a3219cfd50fd84e4da6fe0fac56bcf6f9c6bcf64278b465a209adfed5c614a057ededcb7bff2c0088965aa85afcfc4d04273366da26af227c9971d84092bebdbffd14a074121d1ba617910216d1bf8edb6371c10b601340450413381867dc080cc733a50fffefebfafb7f80b51b00fdb7cdd170e0f13237e0679bac452723101dc83234b5bb1196f5165dc2aabc208994c186295fbf700b7d18e255965977a86f0eef1a2fca416265cdc114473f318f992231e0982fc26a1f35c3f8f7f5a43736b3dbddb3d1056673b6da7f83a3b609a38a86d8abb86a566bdda4413ffadaa1d6551aa6a0317812f3fc1c7769a3b8417da10e8a08cad44af99a7a8b45329702d65d234dc41b0d419d5e12c5abbb88b95e9f8161b439610ea18a474f62c40284c81380bcdf8c038a89ae78c34098f036c5047fa69d3dd1b878c53dfe695b5f8864d32d390a5d7ac2f38cb4d087e5984056ea6afcfa9ee0234576a10a784af94d92fdc6f56543da896a18e9d798f36a8506ea22f48f3eb5c22052a76de41527395f18b92e0b41ce1e4f41026061715a73fd0ec0eed3ffc31e1fc66525340bae443a40628a57f349ed51beda8ae2359c5f76249fe3f9f8429858fa18208315a9a298333d2380014232466f68e3d545191ccb7ab62e2a2984d5bc7ea28cf47c366a6218b6e0a8f67ec25ed86fb8b580b2cc49d5d9fa7647a0ad14fdb25e430260a5c28218c6e48745e3c70a16aacb1e4f074503a254cceb27b9cc0fe3cc191a1c72d1771522c51ec0a18d9cd7b6d9991028474346be9c31ccc2cf988bd23c0ee7c4cc1f4f6ab499061df36abf8824cd42b292014f9be97db9a9331eeef10ee40cc8561cfcbe8e4d364cf0cd954ff8d7ef613bb4be68fc195bc2ef2477dc962cc25551bb74b22d0477100727b0964eb70bbc1ac0baae647db86ddc9b4ab7cc4d0e12f150e764f73ab808b767bf438e3a5d42f9fa298dc7abaa9639303301689d189b64235f0eb415965d1ab3d466d6c6d1b07d4baf6075793f83dc77e41e28cfb80885827f8a506d32265c5918d036c3b23798a08f4b8268671e8435a73d7d9b09eaf040dba1459bb5d3375286baa334784e1864f848bcaeaca8607d2d18571c48938125c65eb8dfec2fd33904df9d443641eea5c250f71caddca2882c2824851a965b2751e525cef9efdddc11c54158d7dcf74f83f29fd681d17852d9d57f3948befa84fbec052cfb8109234973ca65d8d9e6bcef4f9854e5803b3aba0f2e8abad37568cc5464bde14ca3c5e76839ae278c151449cf0bb104080756b907292fe9ca1f72a631ad64e02e3066e31aa73d1b795b1c0ac4939a7314e94416dad496d5fb159fe49f9a1e5eb428c573b8aa35b47385f21441503d741872fd1730b2cbe066093f3d511c0dbe264f381361cb6f93e62da6e55c6445320de65a10040c8cfba98f908752c813f049a27450466a0517d21ce714b064cff6992cb05c330ad441f9b7862a904439ac5ecbc22b8e72375c6fe8d7c955391cdb338bff23904a681f7176fc53f05aaa07bf301b23ee5bbae34a9354369c25aafb7a39a7767509f09f5a364eb3ef5918d91ec179b9b594392f67a8fa435de527bc133ad6b489b2cc523252e7101ef287191f1f1b9854e4d2b16034c533418f616e6c3a96d426c1e246a90e70b8edb2bcd8e6e21fba0dbf250ba4d465dc788d6b750c00cbfba7e2477bf29fc19015786a729b9e3058c35d4a87b0236f7c74341f05766b4a6c51b7f990ce6736332bb7fa53b9e2882e5ee4ed3cdd0379cc9711b47fb751849d1f75f8bc1b060da4c1fadce78177c2f5c4daa6ff1c6d23eb9d9aa9b6e71369f96e243fb31702478756c77a7bebb81d6d48d478dcc6f9b44f43f9b8f29626f7d994b2fbfdb7c55d4f231dda56dcb0a04bfae52a949e6222815543d7c8a555e8241b5bb7173f9dadb2bf16c6d359273bda357b1ad603dc39140a0c02de290e0ab967f7d379854037bb712fee010c1b6e6b09d8e791fa9f9cb3bc5e60486070ab8986d4b3c480dde0e139601c63c3db6e80381975661f74cf32d8af7b38a2c15aa16710675ffa66547743fedadcdad5306fd14dd7813f249c0ecd44af802d327629e3f81be6b1e6010e004cf56a4faf4880a5e88267aa3a6143b4023ba0ed8f2d6bae6b3be370c09e5b89816926aa207db24e6c87cc073a506722c5a2d12d164a4fc0b025df68d9a52341d4142cf498c1505cbd386eea446a0dc7d8882e70b3adaac404fb45050d1eafc23d4576b21188fec0d7a55ccfc5c0b11104abb3bef167a6e10db4168d7bcd61d62c2df5106c33f57ce2cd51f9c26a0010e084986ec05be05b01c67d8e24fa75201be42b8ad29d07e5531891819b74cb2e78aa619632a0569c3b08210530dca661705a0b594a0f7b21cf172b7ae737aa68d87521b74265216d15274714d8592723b617e08ac5b7080ff010818583fa4619a6327d301130e484633028ec95fdb9c1e4906da575af185d373bdb36a85b4544b350418102531123f04398b8476dea4aa34d8c916dc5766f20dc60760d6fa2cd0aa41b9241ce69291ae44cb7ff4c2570c5b68a30001c1dd0fa442f211b1033453a6a1d3dde5b2298cc981ef9156de0659c54ab5fe378236de6c201e347b168210166de6508e669563220711a4702d104c0553efbb62bed3c724155ee6b7833365d579124d058ef11269c5f0f9eeee6ee19ed91bd1bd456d8ee55ef52f6673fc3bdc53f5d15d61e617c144c35d3752333791a4327592d30f0bb0da70f402e6e2790a3fbf842fdaf8da4b15611049a6b1f4a10f5446041f13edc03c0ffdb413a5ffde64d99e149fd68d044bc15b2c549f6ca4ebb5a80e1a4f9123eee4d989aaf079c113557af7f72a2af066bb5f58bb64e75792814005e2040221f6560e26ba7f67e8f86d98916a0442bc6a16464423454616b05976c11325b58510740ab5b4e222030173489cd49ebc29db438166d9a4dc29c8dd41a9c909833e22a67e56fdd3ea909ec3134f92edd68f6fa546e32e9803d93be02884671a1bea34854efde78ec6ecbc2487b5e2e6e48ab7731f0463cebb7bb9f6705b7651e911ab10027e22a19c9dfa324bf79f58f9550a965bda60f8fa030a6b25d7066f22df78ab82c01273d5ef08059ac93da83b522fc007601385e234f9207022f1bf4d96ca922b3d0fbf056b0aa5917e05a89962c79944fa505135c0339cb9c0a628096b65abb3fe79304a144fb142a8e0eddbbd63220c0f5420e1245927826e4124f7c2df0c75c9d6bc512680fb4bb91bdb0ef343ca5ff242152ab8f9c9d92af3b9913036e290d36d60ed53254d15ab979b5a2069914a0bc11fae5477c133419a3f144dd01704a3e7394026ec52d8f0dac21633949149988a4313cf04aa59ab45a70e03cbd269034fa25297cd3f4cf0185e94cf02cf8def2d91642c560bb061377f9ac56471eb2e908e0717acf103b1987701ba470dcba4c3147be0a26cc1915c99eefc75186ff1252abec10e15a52c67179ec0a4ba586ea31b0642303260191e6e2d1d19deda9d37e4cacde5ca9526068caaf02b6233613aa1d21b1473d9ce2e5d95ce5fae69681356248550d7eb45ce136b8028cbe1df541cad7953c25b197ed3adf32d3f9dd3442552f7767fc5c25f445c1a7ea7461007a2e3c30d76123307ac379982cd193ec6cb1d2a109ec509f0588a1b70a4fb0def95285a750f55987fd7460a90a46fc30c4dce33ff4b000f0e63bb1298c4681830dcdaf23c8a67db30e028f07db816a5ea9606b94f235838a5aed97c9fd322b9d37e887aa7596c4d79b6c5ef6715f28c44bbc4abfa191fed1d3e4527f0e0ca7865daba8858234f57140e3cb1e754f5c78370c587dff4c6e5d8f2418142ab553573f18979b05f95c489377cfa275a50118d20c6a33bcb519bb26b5e2c495b9a3a6749b6b4f921db042f860729ba77af44107b6a1d676c4a7c99b86565d489f1b302186761f4bbb386773373ad5839b53dc23655a6bb4d20cdce7d4dd7c0ab8e90211b3cc0cf6a2308ebfc83fc0c1e834d6dde20581862b576c5179b4ecb5f6a04a3f784bb73543a44b59408ebdc6a1ac8031710cf5c31171493c14ac4c3f9abb283cadb04a5adafc9bedd363e5fbeba67692caa69abe260c0d791cfa6d37e1055381dec62006db84d9f47421ef5e7268e5f2a85b3cded468531775db7d6c33763add8c7f2b89682527c30070e44b4d54102b476757c037d26d21613222918291bd762089bfe886d8172676723bd8c176f67a69663d59d06d2ca0babc54bcabf570a740b848f8987c959eed4a236bbc73ab7ca7138cd3962e80565749aff806cebe8bb2168c44b8d2d3c1c2c7fe26078956a5e887925ec48289f394a19ad789321abd6205972db2e6144671c9ad757a31db7fd97091db7e875762db7c01b601e4862242eea8ba4d980107701b795616499789361055ea7da88d4b1ff4c0455740b9cb2290e2d6c69268f7596bd5889b86f0b92823b0e43c4955236ef6f26c6dcd4adb9917de652216aa62b551a55af86dab96f4263fed1278db316990c2ffc914b2fe6f424254cfde29d37699582021d6708ff2ab76f21ed6a39b13054b6b3fa60e9ed2b681b050dd4b0af3efaa0ec45a912e549b4b682d289b1df507464d66ff2ba8f2e45e9d3bb6ec63c10fbd82dd9a6e49c945233587e82da87eaaee4490390263344fa1660982dc1959f12574ffde37845983cca07922fc0f75319ab217e664ebdc79b194e02ac958ab816519587e1acca4fecb0bd963aba110cc0a754e3b1413448113ce9cc9dec2b2c9880ab7fb3fc4098a8d445926786c6669651713894f8ba69b0698d636d372b785030a76773c2ba0a11dadacb9cc33f18f76e9134898c88705e007f12d45c3f696de4481a13c4486fcd568b47437371ceaeb5c3bbb211b4f9aaef4c1e3a0f96683ef45aec90f51bf23e2dc2dfb9ed2d2cb7fb80c7520b9dca4032174de30e58bc7f9d9eaf40e869664e87d170c6953c16d12b4758d79324d47c9c34f97aad2aae7eb61c798f9af34c2b96625e0536c5b0931fdceedec387b929fb164a0d5715f16f3d2de3bdd5f7d282223f65dc46e093632d9e08cedb10ed5d3554c263aecdea0540a43a5d83c29314bad4497d3e7f1c1edde729ec51d853d29c15977801fd36064ec15ac8fbbd59c7114f4dde54835c9ecedef3255a250cbbbbcc45151c92a692a04141c321052343bd200faea101ee8c72d9e605146904c45061c7a3acf1d34627048a871c6deba7dd1a8e9801162eb2b0540608481cb0e7bee262d2b89f93e462ce078802405eb63f2695d4edc9d3cd5c02a22b6c7bd95d37407b29e2a113da40679f1304aaa5ca92aec08acdc985f77f232a0b0f9de32c0fed3bb13b859e65913248b6bc2b71c186f5ac48375fd05bf7f45ceece8ca65b4ce327e75264d1d12486b1b6e709726058d8a0068a1107ac1e01a1b6cba60b1ca0054543059e9b5da1ba58686329ec3245355cf99e2d04e27d07f2446e8fab54a0ee41cd453004aae1b66c5d69e7a2a8a9f87dd546f7321d027a2c7aa358d0405fec0eb110622567ce455278607f05c1b032c04f3f1220deb220e2fd5f5552769bcde517a988ce1354fc0425935c8d220ea3c853bef1109994bebc66f2c26c29614bd832f0d890382d35814224e0c173d2e83b37cc3d8c8779e6a272c324ff5297d09e2f234b3f3c256219690a43d4c2d585a94460249e5c0c09d9448e457cdd9921bcef82f63ff8c0c8ca4b410345011c01f28db20a6d39865840299fa90757222b5f0da0331ec443241d43b115a342ef2a6c5c3395ee0b243d2bb52c3b9a82fda19439d382d48894b31eb3a24fa1cd85f42983a9c3dc992a52230a8d91e0e4badd33f5fe7471d01ba4b7ae89b7ee66e220b4288403e51640a34a984a3367834bb2ac8db6bce2341b144808087bf0cc3de51b9b0abb71f75d34f1b124c4a6b5b1c95897b20d828842804c2141cda623d4a2ca134e219d7dfd0f2754e25900a3dd8a30f1fdc87e27f58958cd7af7d8446a7fb3d96ade5e1bcb3f015de47e3d24db8508579347befe9324125afada274e2981d0358d5248a18122e124b615985a6c0eaeb99689270c2626c2868649c5ba7f6f17a0c7438e648f89d0cc57e7463b43a9262f489b0e650b9fa04306300b20632a90e1b6f4e3d69b3a4417cead386a6ad8bac776f04447afe5c4d6868fdaa95000ad5e1ba60af4460e710147baf586fb7a8816adfc98bd6d43932cd16b56e1d04d9d5d8bb032f57e89cca12d3cbf259ce0a8b4e00f8341494a94aeae4915a8f8bf7a202a3ca1291fc211451a6326810a12e25b1e4f9b2b41b44eac41bb016ac6c0d8c19cb8558052632c3892187a008f60b18d9471c356e8082187c6c16af703249cb6ada558ae264398b686694036bfd2e64d93506574dfac010bda8652fa7792b4a1032fa3b77e7db3e9a9a9d665b50ec1491e483b6b93959870cfb8b9a3e2c5d724ab616f69b970a425ac3aba6fe3677558506eae0262bc934d8a1ebde696c56230e5b55ba283e9c44c117a9e745f38e26cf98c39a435e1254db2813ed291394a19e866139934a3623652fc44808d60891689b3d2a35be87ad5ebd891bdf0c03d1bdf495c5604e5461b57736aa4b802a43d9b406ca00adcd9f337f13b8c64a7e58700aece3d08afe38918b9e9bacbcc02e67a94d16abba965ec0c53090747b6e93864c03897375fbb6ed9cce93bf84511dbab07a8cbd75abfdcadd7b0e099b19bf371dfd0a", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0x3a6772616e6470615f617574686f726974696573": "0x010888dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee0100000000000000d17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae690100000000000000", + "0x3db7a24cfdc9de785974746c14a99df94e7b9012096b41c4eb3aaf947f6ea429": "0x0300", + "0x3f1467a096bcd71a5b6a0c8155e20810308ce9615de0775a82f8a94dc3d285a1": "0x01", + "0x3f1467a096bcd71a5b6a0c8155e208103f2edf3bdf381debe331ab7446addfdc": "0x000064a7b3b6e00d0000000000000000", + "0x3f1467a096bcd71a5b6a0c8155e208104e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x426e15054d267946093858132eb537f105fe52c2045750c3c492ccdcf62e2b9c": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", + "0x426e15054d267946093858132eb537f14e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x426e15054d267946093858132eb537f195999521c6c89cd80b677e53ce20f98c": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", + "0x426e15054d267946093858132eb537f1a47a9ff5cd5bf4d848a80a0b1a947dc3": "0x00000000000000000000000000000000", + "0x426e15054d267946093858132eb537f1ba7fb8745735dc3be2a2c61a72c39e78": "0x181cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc208eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4890b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e", + "0x426e15054d267946093858132eb537f1d0b4a3f7631f0c0e761898fe198211de": "0xe7030000", + "0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429": "0x0900", + "0x4a83351006488ef6369cb758091f878c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x4ff3897794d496d78686afcfe760a1144e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x5c0d1176a568c1f92944340dbfed9e9c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x5c0d1176a568c1f92944340dbfed9e9c530ebca703c85910e7164cb7d1c9e47b": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", + "0x5e8a19e3cd1b7c148b33880c479c02814e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x5f27b51b5ec208ee9cb25b55d8728243308ce9615de0775a82f8a94dc3d285a1": "0x01", + "0x5f27b51b5ec208ee9cb25b55d87282434e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca0b6a45321efae92aea15e0740ec7afe7": "0x00000000", + "0x5f3e4907f716ac89b6347d15ececedca138e71612491192d68deab7e6f563fe1": "0x02000000", + "0x5f3e4907f716ac89b6347d15ececedca28dccb559b95c40168a1b2696581b5a7": "0x00000000000000000000000000000000", + "0x5f3e4907f716ac89b6347d15ececedca308ce9615de0775a82f8a94dc3d285a1": "0x06", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe700e5be00fbc2e15b5fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e": "0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70e535263148daaf49be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc44f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0xfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e13000064a7b3b6e00d13000064a7b3b6e00d0000", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc4de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d": "0xbe5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f13000064a7b3b6e00d13000064a7b3b6e00d0000", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a000000000e5be00fbc2e15b5fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e": "0x13d4fe63a7b3b6e00d13d4fe63a7b3b6e00d00", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000e535263148daaf49be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f": "0x13d4fe63a7b3b6e00d13d4fe63a7b3b6e00d00", + "0x5f3e4907f716ac89b6347d15ececedca487df464e44a534ba6b0cbb32407b587": "0x0000000000", + "0x5f3e4907f716ac89b6347d15ececedca4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca5579297f4dfb9609e7e4c2ebab9ce40a": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca666fdcbb473985b3ac933d13f4acff8d": "0x00000000000000000000000000000000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a000000000e5be00fbc2e15b5fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000e535263148daaf49be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca6ddc7809c6da9bb6093ee22e0fda4ba8": "0x02000000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e169030e5be00fbc2e15b5fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903e535263148daaf49be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a000000000e5be00fbc2e15b5fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e": "0x13d4fe63a7b3b6e00d13d4fe63a7b3b6e00d00", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000e535263148daaf49be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f": "0x13d4fe63a7b3b6e00d13d4fe63a7b3b6e00d00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade980e5be00fbc2e15b5fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98e535263148daaf49be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f": "0x00", + "0x5f3e4907f716ac89b6347d15ececedcaa141c4fe67c2d11f4a10c6aca7a79a04b4def25cfda6ef3a00000000": "0xa8fdc74e676dc11b0000000000000000", + "0x5f3e4907f716ac89b6347d15ececedcaad811cd65a470ddc5f1d628ff0550982b4def25cfda6ef3a00000000": "0x00000000", + "0x5f3e4907f716ac89b6347d15ececedcab49a2738eeb30896aacb8b3fb46471bd": "0x02000000", + "0x5f3e4907f716ac89b6347d15ececedcac0d39ff577af2cc6b67ac3641fa9c4e7": "0x01000000", + "0x5f3e4907f716ac89b6347d15ececedcac29a0310e1bb45d20cace77ccb62c97d": "0x00e1f505", + "0x5f3e4907f716ac89b6347d15ececedcaea07de2b8f010516dca3f7ef52f7ac5a": "0x040000000000000000", + "0x5f3e4907f716ac89b6347d15ececedcaed441ceb81326c56263efbb60c95c2e4": "0x00000000000000000000000000000000", + "0x5f3e4907f716ac89b6347d15ececedcaf7dad0317324aecae8744b87fc95f2f3": "0x00", + "0x5f9cc45b7a00c5899361e1c6099678dc4e7b9012096b41c4eb3aaf947f6ea429": "0x0400", + "0x5f9cc45b7a00c5899361e1c6099678dc8a2d09463effcc78a22d75b9cb87dffc": "0x0000000000000000", + "0x5f9cc45b7a00c5899361e1c6099678dcd47cb8f5328af743ddfb361e7180e7fcbb1bdbcacd6ac9340000000000000000": "0x00000000", + "0x6441fb391296410bd2f14381bb7494334e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x6786c4cec8d628b6598d7a70ace7acd44e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x682a59d51ab9e48a8c8cc418ff9708d24e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x6c63e84bfc5a0d62149aaab70897685c4ba24bcd9ac206424105f255ae95a355": "0xb104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x6c63e84bfc5a0d62149aaab70897685c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x74dd702da46f77d7acf77f5a48d4af7d4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b150e5be00fbc2e15b5fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e": "0xfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e01be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f00b304f91831830500622780fd38770500", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15e535263148daaf49be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f": "0xbe5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f0001fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860eb304f91831830500622780fd38770500", + "0x74dd702da46f77d7acf77f5a48d4af7d7a6dc62e324093ba1331bf49fdb2f24a": "0x02000000", + "0x74dd702da46f77d7acf77f5a48d4af7de5c03730c8f59f00941607850b6633d81fad1867486365c5b304f91831830500": "0x01be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f01fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e", + "0x7a6d38deaa01cb6e76ee69889f1696272be9a4e88368a2188d2b9100a9f3cd43": "0x00407a10f35a00000000000000000000", + "0x7a6d38deaa01cb6e76ee69889f16962730256ea2c545a3e5e3744665ffb2ed28": "0x00020000", + "0x7a6d38deaa01cb6e76ee69889f1696273f0d64e1907361c689834a9c1cb0fbe0": "0x20000000", + "0x7a6d38deaa01cb6e76ee69889f16962749d67997de33812a1cc37310f765b82e": "0x0080c6a47e8d03000000000000000000", + "0x7a6d38deaa01cb6e76ee69889f1696274e7b9012096b41c4eb3aaf947f6ea429": "0x0300", + "0x7a6d38deaa01cb6e76ee69889f169627ba93302f3b868c50785e6ade45c6a1d8": "0x10000000", + "0x7cda3cfa86b349fdafce4979b197118f4e7b9012096b41c4eb3aaf947f6ea429": "0x0400", + "0x7cda3cfa86b349fdafce4979b197118f71cd3068e6118bfb392b798317f63a8910c174c55fd2c633e659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e": "0x04e659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e000064a7b3b6e00d000000000000000000000000000000000000000000000000", + "0x7cda3cfa86b349fdafce4979b197118f71cd3068e6118bfb392b798317f63a893e73123ebcdee9161cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c": "0x041cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c000064a7b3b6e00d000000000000000000000000000000000000000000000000", + "0x7cda3cfa86b349fdafce4979b197118f71cd3068e6118bfb392b798317f63a894f58b588ac077bd5306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20": "0x04306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20000064a7b3b6e00d000000000000000000000000000000000000000000000000", + "0x7cda3cfa86b349fdafce4979b197118f71cd3068e6118bfb392b798317f63a89518366b5b1bc7c99d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d": "0x04d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d000064a7b3b6e00d000000000000000000000000000000000000000000000000", + "0x7cda3cfa86b349fdafce4979b197118f71cd3068e6118bfb392b798317f63a89a647e755c30521d38eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x048eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000000000000000000000000000000000", + "0x7cda3cfa86b349fdafce4979b197118f71cd3068e6118bfb392b798317f63a89dd4e3f25f5378a6d90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x0490b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22000064a7b3b6e00d000000000000000000000000000000000000000000000000", + "0x7cda3cfa86b349fdafce4979b197118fba7fb8745735dc3be2a2c61a72c39e78": "0x181cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c000064a7b3b6e00d000000000000000000000000000000000000000000000000306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20000064a7b3b6e00d0000000000000000000000000000000000000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d00000000000000000000000000000000000000000000000090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22000064a7b3b6e00d000000000000000000000000000000000000000000000000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d000064a7b3b6e00d000000000000000000000000000000000000000000000000e659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e000064a7b3b6e00d000000000000000000000000000000000000000000000000", + "0x89d139e01a5eb2256f222e5fc5dbe6b34e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x913b40454eb582a66ab74c86f6137db94e7b9012096b41c4eb3aaf947f6ea429": "0x0400", + "0xa0eb495036d368196a2b6c51d9d788814e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xa2ce73642c549ae79c14f0a671cf45f94e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xa37f719efab16103103a0c8c2c784ce14e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xa42f90c8b47838c3a5332d85ee9aa5c34e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xa8c65209d47ee80f56b0011e8fd91f504e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xaebd463ed9925c488c112434d61debc04e7b9012096b41c4eb3aaf947f6ea429": "0x0400", + "0xaebd463ed9925c488c112434d61debc0ba7fb8745735dc3be2a2c61a72c39e78": "0x18d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4890b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20e659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c", + "0xbd2a529379475088d3e29a918cd478724e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc632a5935f6edc617ae178fef9eb1e211fbe5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f": "0x047374616b696e6720000064a7b3b6e00d000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc66f2e33376834a63c86a195bcf685aebbfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e": "0x047374616b696e6720000064a7b3b6e00d000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f308ce9615de0775a82f8a94dc3d285a1": "0x01", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x0040fa7f398074858a02000000000000", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb30e5be00fbc2e15b5fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e": "0xd17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae698eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a488eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a488eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3e535263148daaf49be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0eed43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27dd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27dd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", + "0xcec5070d609dd3497f72bde07fc96ba04e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19500e3a507571a62417696d6f6e808eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0xfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19505905fe216cc5924c6772616e80d17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae69": "0xfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195066b8d48da86b869b6261626580d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d": "0xbe5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19509d4a4cfe1c2ef0b961756469808eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0xfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950c9b0c13125732d276175646980d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d": "0xbe5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950d62c40514b41f31962616265808eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0xfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950ed43a85541921049696d6f6e80d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d": "0xbe5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950f5537bdb2a1f626b6772616e8088dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee": "0xbe5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f", + "0xcec5070d609dd3497f72bde07fc96ba088dcde934c658227ee1dfafcd6e16903": "0x08be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25ffe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e", + "0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609": "0x08be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0eed43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27dd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27dd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27dfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860ed17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae698eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a488eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a488eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", + "0xd57bce545fb382c34570e5dfbf338f5e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xd5c41b52a371aa36c9254ce34324f2a54e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xd8f314b7f4e6b095f0f8ee4656a448254e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xed25f63942de25ac5253ba64b5eb64d14e7b9012096b41c4eb3aaf947f6ea429": "0x0400", + "0xed25f63942de25ac5253ba64b5eb64d1ba7fb8745735dc3be2a2c61a72c39e78": "0x18d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4890b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20e659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c", + "0xede8e4fdc3c8b556f0ce2f77fc2575e34e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xedfb05b766f199ce00df85317e33050e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xf2794c22e353e9a839f12faab03a911b4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xf2794c22e353e9a839f12faab03a911b7f17cdfbfa73331856cca0acddd7842e": "0x00000000", + "0xf2794c22e353e9a839f12faab03a911bbdcb0c5143a8617ed38ae3810dd45bc6": "0x00000000", + "0xf2794c22e353e9a839f12faab03a911be2f6cb0456905c189bcb0458f9440f13": "0x00000000", + "0xf5a4963e4efb097983d7a693b0c1ee454e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xfbc9f53700f75f681f234e70fb7241eb4e7b9012096b41c4eb3aaf947f6ea429": "0x0000" + }, + "childrenDefault": {} + } + } +} \ No newline at end of file diff --git a/zombienet/0001-basic-warp-sync/generate-warp-sync-database.toml b/zombienet/0001-basic-warp-sync/generate-warp-sync-database.toml new file mode 100644 index 0000000000000..ca78ee290c41d --- /dev/null +++ b/zombienet/0001-basic-warp-sync/generate-warp-sync-database.toml @@ -0,0 +1,17 @@ +# this file is not intended to be executed in CI stage +[relaychain] +default_image = "docker.io/parity/substrate:latest" +default_command = "substrate" + +# refer to ./README.md for more details on how to create snapshot and spec +chain = "gen-db" +chain_spec_path = "chain-spec.json" + + + [[relaychain.nodes]] + name = "alice" + validator = true + + [[relaychain.nodes]] + name = "bob" + validator = true diff --git a/zombienet/0001-basic-warp-sync/test-warp-sync.toml b/zombienet/0001-basic-warp-sync/test-warp-sync.toml new file mode 100644 index 0000000000000..ae2810b6ecccd --- /dev/null +++ b/zombienet/0001-basic-warp-sync/test-warp-sync.toml @@ -0,0 +1,30 @@ +[settings] +enable_tracing = false + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +default_command = "substrate" + +chain = "gen-db" +chain_spec_path = "zombienet/0001-basic-warp-sync/chain-spec.json" + + [[relaychain.nodes]] + name = "alice" + validator = false + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + + [[relaychain.nodes]] + name = "bob" + validator = false + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + + #we need at least 3 nodes for warp sync + [[relaychain.nodes]] + name = "charlie" + validator = false + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + + [[relaychain.nodes]] + name = "dave" + validator = false + args = ["--sync warp"] diff --git a/zombienet/0001-basic-warp-sync/test-warp-sync.zndsl b/zombienet/0001-basic-warp-sync/test-warp-sync.zndsl new file mode 100644 index 0000000000000..1ccacb2e6d038 --- /dev/null +++ b/zombienet/0001-basic-warp-sync/test-warp-sync.zndsl @@ -0,0 +1,35 @@ +Description: Warp sync +Network: ./test-warp-sync.toml +Creds: config + +alice: is up +bob: is up +charlie: is up +dave: is up + +alice: reports node_roles is 1 +bob: reports node_roles is 1 +charlie: reports node_roles is 1 +dave: reports node_roles is 1 + +alice: reports peers count is at least 3 within 60 seconds +bob: reports peers count is at least 3 within 60 seconds +charlie: reports peers count is at least 3 within 60 seconds +dave: reports peers count is at least 3 within 60 seconds + + +# db snapshot has 12133 blocks +dave: reports block height is at least 1 within 60 seconds +dave: reports block height is at least 12132 within 60 seconds +dave: reports block height is at least 12133 within 60 seconds + +alice: reports block height is at least 12133 within 60 seconds +bob: reports block height is at least 12133 within 60 seconds +charlie: reports block height is at least 12133 within 60 seconds + +dave: log line matches "Warp sync is complete" within 60 seconds +# workaround for: https://github.com/paritytech/zombienet/issues/580 +dave: count of log lines containing "Block history download is complete" is 1 within 10 seconds + +dave: count of log lines containing "error" is 0 within 10 seconds +dave: count of log lines containing "verification failed" is 0 within 10 seconds From ea3ca3f757ff9d9559665719a77da81f4cf0f0ce Mon Sep 17 00:00:00 2001 From: Anthony Alaribe Date: Thu, 8 Dec 2022 14:47:13 +0200 Subject: [PATCH 1449/1472] Move LockableCurrency trait to fungibles::Lockable and deprecate LockableCurrency (#12798) * WIP move LockableCurrency to fungibles * rename Lockable and LockIdentifier to funginbles::* * fix imports further * change Lockable from fungible to fungibles * reintroduce LockableCurrency but marked as deprecated * fix imports * fix imports * cargo fmt * add allow deprecated warnings * remove unused benchmark import * fix some of the docs * fix failing doctest check * reexport LockIdentifier and LockableCurrency from support/traits * reexport LockIdentifier and LockableCurrency from support/traits * allow using deprecated re-export * replace LockableCurrency and LockIdentifier with a module alias * Update frame/support/src/traits/tokens/fungibles/lockable.rs * Update frame/staking/src/pallet/mod.rs Co-authored-by: Squirrel * Update frame/support/src/traits.rs Co-authored-by: Squirrel * REVERT removing fungibles::Lockable import Co-authored-by: parity-processbot <> Co-authored-by: Squirrel --- bin/node/runtime/src/lib.rs | 8 +-- frame/balances/README.md | 8 +-- frame/balances/src/lib.rs | 26 ++++---- frame/balances/src/tests.rs | 6 +- frame/contracts/src/tests.rs | 2 +- frame/conviction-voting/src/benchmarking.rs | 2 +- frame/conviction-voting/src/lib.rs | 6 +- frame/democracy/src/lib.rs | 10 +-- frame/elections-phragmen/src/lib.rs | 10 +-- frame/executive/src/lib.rs | 9 +-- frame/referenda/src/lib.rs | 7 +- frame/staking/src/pallet/impls.rs | 5 +- frame/staking/src/pallet/mod.rs | 8 +-- frame/support/src/traits.rs | 1 + frame/support/src/traits/tokens/currency.rs | 5 +- .../src/traits/tokens/currency/lockable.rs | 48 +------------- frame/support/src/traits/tokens/fungible.rs | 1 + frame/support/src/traits/tokens/fungibles.rs | 2 + .../src/traits/tokens/fungibles/lockable.rs | 65 +++++++++++++++++++ frame/vesting/src/lib.rs | 11 ++-- 20 files changed, 135 insertions(+), 105 deletions(-) create mode 100644 frame/support/src/traits/tokens/fungibles/lockable.rs diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8c4e70c37d8c0..44d8e287064f9 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -32,9 +32,9 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{ - fungible::ItemOf, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, - Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, - KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, + fungible::ItemOf, fungibles, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, + ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, + InstanceFilter, KeyOwnerProofSystem, Nothing, OnUnbalanced, U128CurrencyToVote, WithdrawReasons, }, weights::{ @@ -1003,7 +1003,7 @@ parameter_types! { pub const DesiredRunnersUp: u32 = 7; pub const MaxVoters: u32 = 10 * 1000; pub const MaxCandidates: u32 = 1000; - pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; + pub const ElectionsPhragmenPalletId: fungibles::LockIdentifier = *b"phrelect"; } // Make sure that there are no more than `MaxMembers` members elected via elections-phragmen. diff --git a/frame/balances/README.md b/frame/balances/README.md index 93e424a89c721..d32fffbf0e7ad 100644 --- a/frame/balances/README.md +++ b/frame/balances/README.md @@ -57,7 +57,7 @@ that you need, then you can avoid coupling with the Balances module. fungible assets system. - [`ReservableCurrency`](https://docs.rs/frame-support/latest/frame_support/traits/trait.ReservableCurrency.html): Functions for dealing with assets that can be reserved from an account. -- [`LockableCurrency`](https://docs.rs/frame-support/latest/frame_support/traits/trait.LockableCurrency.html): Functions for +- [`Lockable`](https://docs.rs/frame-support/latest/frame_support/traits/fungibles/trait.Lockable.html): Functions for dealing with accounts that allow liquidity restrictions. - [`Imbalance`](https://docs.rs/frame-support/latest/frame_support/traits/trait.Imbalance.html): Functions for handling imbalances between total issuance in the system and account balances. Must be used when a function @@ -88,13 +88,13 @@ pub type NegativeImbalanceOf = <::Currency as Currency<; + type Currency: fungibles::Lockable; } fn update_ledger( diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 381a0ffceeb85..d74de37e993f7 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -79,7 +79,7 @@ //! - [`ReservableCurrency`](frame_support::traits::ReservableCurrency): //! - [`NamedReservableCurrency`](frame_support::traits::NamedReservableCurrency): //! Functions for dealing with assets that can be reserved from an account. -//! - [`LockableCurrency`](frame_support::traits::LockableCurrency): Functions for +//! - [`Lockable`](frame_support::traits::fungibles::Lockable): Functions for //! dealing with accounts that allow liquidity restrictions. //! - [`Imbalance`](frame_support::traits::Imbalance): Functions for handling //! imbalances between total issuance in the system and account balances. Must be used when a @@ -113,13 +113,13 @@ //! # fn main() {} //! ``` //! -//! The Staking pallet uses the `LockableCurrency` trait to lock a stash account's funds: +//! The Staking pallet uses the `fungibles::Lockable` trait to lock a stash account's funds: //! //! ``` -//! use frame_support::traits::{WithdrawReasons, LockableCurrency}; +//! use frame_support::traits::{WithdrawReasons, fungibles, fungibles::Lockable}; //! use sp_runtime::traits::Bounded; //! pub trait Config: frame_system::Config { -//! type Currency: LockableCurrency; +//! type Currency: fungibles::Lockable; //! } //! # struct StakingLedger { //! # stash: ::AccountId, @@ -171,11 +171,13 @@ use frame_support::{ ensure, pallet_prelude::DispatchResult, traits::{ - tokens::{fungible, BalanceStatus as Status, DepositConsequence, WithdrawConsequence}, + tokens::{ + fungible, fungibles, BalanceStatus as Status, DepositConsequence, WithdrawConsequence, + }, Currency, DefensiveSaturating, ExistenceRequirement, ExistenceRequirement::{AllowDeath, KeepAlive}, - Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency, OnUnbalanced, - ReservableCurrency, SignedImbalance, StoredMap, TryDrop, WithdrawReasons, + Get, Imbalance, NamedReservableCurrency, OnUnbalanced, ReservableCurrency, SignedImbalance, + StoredMap, TryDrop, WithdrawReasons, }, WeakBoundedVec, }; @@ -662,7 +664,7 @@ impl BitOr for Reasons { #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] pub struct BalanceLock { /// An identifier for this lock. Only one lock may be in existence for each identifier. - pub id: LockIdentifier, + pub id: fungibles::LockIdentifier, /// The amount which the free balance may not drop below when this lock is in effect. pub amount: Balance, /// If true, then the lock remains in effect even for payment of transaction fees. @@ -2131,7 +2133,7 @@ where } } -impl, I: 'static> LockableCurrency for Pallet +impl, I: 'static> fungibles::Lockable for Pallet where T::Balance: MaybeSerializeDeserialize + Debug, { @@ -2142,7 +2144,7 @@ where // Set a lock on the balance of `who`. // Is a no-op if lock amount is zero or `reasons` `is_none()`. fn set_lock( - id: LockIdentifier, + id: fungibles::LockIdentifier, who: &T::AccountId, amount: T::Balance, reasons: WithdrawReasons, @@ -2164,7 +2166,7 @@ where // Extend a lock on the balance of `who`. // Is a no-op if lock amount is zero or `reasons` `is_none()`. fn extend_lock( - id: LockIdentifier, + id: fungibles::LockIdentifier, who: &T::AccountId, amount: T::Balance, reasons: WithdrawReasons, @@ -2193,7 +2195,7 @@ where Self::update_locks(who, &locks[..]); } - fn remove_lock(id: LockIdentifier, who: &T::AccountId) { + fn remove_lock(id: fungibles::LockIdentifier, who: &T::AccountId) { let mut locks = Self::locks(who); locks.retain(|l| l.id != id); Self::update_locks(who, &locks[..]); diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 83944caf9f7ff..44a71b93257db 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -28,15 +28,15 @@ macro_rules! decl_tests { use frame_support::{ assert_noop, assert_storage_noop, assert_ok, assert_err, traits::{ - LockableCurrency, LockIdentifier, WithdrawReasons, + fungibles, fungibles::Lockable, WithdrawReasons, Currency, ReservableCurrency, ExistenceRequirement::AllowDeath } }; use pallet_transaction_payment::{ChargeTransactionPayment, Multiplier}; use frame_system::RawOrigin; - const ID_1: LockIdentifier = *b"1 "; - const ID_2: LockIdentifier = *b"2 "; + const ID_1: fungibles::LockIdentifier = *b"1 "; + const ID_2: fungibles::LockIdentifier = *b"2 "; pub const CALL: &<$test as frame_system::Config>::RuntimeCall = &RuntimeCall::Balances(pallet_balances::Call::transfer { dest: 0, value: 0 }); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index e5395c73d2868..f4c8889ef05f4 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -37,7 +37,7 @@ use frame_support::{ parameter_types, storage::child, traits::{ - BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, LockableCurrency, OnIdle, + fungibles::Lockable, BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, OnIdle, OnInitialize, ReservableCurrency, WithdrawReasons, }, weights::{constants::WEIGHT_PER_SECOND, Weight}, diff --git a/frame/conviction-voting/src/benchmarking.rs b/frame/conviction-voting/src/benchmarking.rs index 117bb7fe22989..4bebc6a97c49b 100644 --- a/frame/conviction-voting/src/benchmarking.rs +++ b/frame/conviction-voting/src/benchmarking.rs @@ -23,7 +23,7 @@ use assert_matches::assert_matches; use frame_benchmarking::{account, benchmarks_instance_pallet, whitelist_account}; use frame_support::{ dispatch::RawOrigin, - traits::{fungible, Currency, Get}, + traits::{Currency, Get}, }; use sp_runtime::traits::Bounded; use sp_std::collections::btree_map::BTreeMap; diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index 3ecc6e56be94e..992b532fb93ed 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -31,7 +31,7 @@ use frame_support::{ dispatch::{DispatchError, DispatchResult}, ensure, traits::{ - fungible, Currency, Get, LockIdentifier, LockableCurrency, PollStatus, Polling, + fungible, fungibles, fungibles::Lockable, Currency, Get, PollStatus, Polling, ReservableCurrency, WithdrawReasons, }, }; @@ -60,7 +60,7 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; -const CONVICTION_VOTING_ID: LockIdentifier = *b"pyconvot"; +const CONVICTION_VOTING_ID: fungibles::LockIdentifier = *b"pyconvot"; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; type BalanceOf = @@ -104,7 +104,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// Currency type with which voting happens. type Currency: ReservableCurrency - + LockableCurrency + + fungibles::Lockable + fungible::Inspect; /// The implementation of the logic which conducts polls. diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index cf954d4800eee..096122cb1caa5 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -157,9 +157,11 @@ use frame_support::{ ensure, traits::{ defensive_prelude::*, + fungibles, + fungibles::Lockable, schedule::{v3::Named as ScheduleNamed, DispatchTime}, - Bounded, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, QueryPreimage, - ReservableCurrency, StorePreimage, WithdrawReasons, + Bounded, Currency, Get, OnUnbalanced, QueryPreimage, ReservableCurrency, StorePreimage, + WithdrawReasons, }, weights::Weight, }; @@ -189,7 +191,7 @@ pub mod benchmarking; pub mod migrations; -const DEMOCRACY_ID: LockIdentifier = *b"democrac"; +const DEMOCRACY_ID: fungibles::LockIdentifier = *b"democrac"; /// A proposal index. pub type PropIndex = u32; @@ -234,7 +236,7 @@ pub mod pallet { /// Currency type for this pallet. type Currency: ReservableCurrency - + LockableCurrency; + + fungibles::Lockable; /// The period between a proposal being approved and enacted. /// diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 165a8fcab429b..13190237ea784 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -101,8 +101,8 @@ use codec::{Decode, Encode}; use frame_support::{ traits::{ - defensive_prelude::*, ChangeMembers, Contains, ContainsLengthBound, Currency, - CurrencyToVote, Get, InitializeMembers, LockIdentifier, LockableCurrency, OnUnbalanced, + defensive_prelude::*, fungibles, fungibles::Lockable, ChangeMembers, Contains, + ContainsLengthBound, Currency, CurrencyToVote, Get, InitializeMembers, OnUnbalanced, ReservableCurrency, SortedMembers, WithdrawReasons, }, weights::Weight, @@ -199,10 +199,10 @@ pub mod pallet { /// Identifier for the elections-phragmen pallet's lock #[pallet::constant] - type PalletId: Get; + type PalletId: Get; /// The currency that people are electing with. - type Currency: LockableCurrency + type Currency: fungibles::Lockable + ReservableCurrency; /// What to do when the members change. @@ -1274,7 +1274,7 @@ mod tests { } parameter_types! { - pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; + pub const ElectionsPhragmenPalletId: fungibles::LockIdentifier = *b"phrelect"; pub const PhragmenMaxVoters: u32 = 1000; pub const PhragmenMaxCandidates: u32 = 100; } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 5a4ef92b1c874..2d307a1a024b5 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -620,10 +620,7 @@ mod tests { use frame_support::{ assert_err, parameter_types, - traits::{ - ConstU32, ConstU64, ConstU8, Currency, LockIdentifier, LockableCurrency, - WithdrawReasons, - }, + traits::{fungibles, ConstU32, ConstU64, ConstU8, Currency, WithdrawReasons}, weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFee}, }; use frame_system::{Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo}; @@ -1185,11 +1182,11 @@ mod tests { #[test] fn can_pay_for_tx_fee_on_full_lock() { - let id: LockIdentifier = *b"0 "; + let id: fungibles::LockIdentifier = *b"0 "; let execute_with_lock = |lock: WithdrawReasons| { let mut t = new_test_ext(1); t.execute_with(|| { - as LockableCurrency>::set_lock( + as fungibles::Lockable>::set_lock( id, &1, 110, lock, ); let xt = TestXt::new( diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 2bb01baa0cd3a..551628fee9159 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -1,5 +1,3 @@ -// This file is part of Substrate. - // Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 @@ -68,11 +66,12 @@ use codec::{Codec, Encode}; use frame_support::{ ensure, traits::{ + fungibles, schedule::{ v3::{Anon as ScheduleAnon, Named as ScheduleNamed}, DispatchTime, }, - Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, + Currency, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, ReservableCurrency, StorePreimage, VoteTally, }, BoundedVec, @@ -133,7 +132,7 @@ macro_rules! impl_tracksinfo_get { }; } -const ASSEMBLY_ID: LockIdentifier = *b"assembly"; +const ASSEMBLY_ID: fungibles::LockIdentifier = *b"assembly"; #[frame_support::pallet] pub mod pallet { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index c22a2bd2d1f77..34e12fbcf6adf 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -25,8 +25,9 @@ use frame_support::{ dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ - Currency, CurrencyToVote, Defensive, DefensiveResult, EstimateNextNewSession, Get, - Imbalance, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, WithdrawReasons, + fungibles::Lockable, Currency, CurrencyToVote, Defensive, DefensiveResult, + EstimateNextNewSession, Get, Imbalance, OnUnbalanced, TryCollect, UnixTime, + WithdrawReasons, }, weights::Weight, }; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 8fddba2150370..fd0c494fa6723 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -24,8 +24,8 @@ use frame_support::{ dispatch::Codec, pallet_prelude::*, traits::{ - Currency, CurrencyToVote, Defensive, DefensiveResult, DefensiveSaturating, EnsureOrigin, - EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, TryCollect, + fungibles, fungibles::Lockable, Currency, CurrencyToVote, Defensive, DefensiveResult, + DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, OnUnbalanced, TryCollect, UnixTime, }, weights::Weight, @@ -50,7 +50,7 @@ use crate::{ ValidatorPrefs, }; -const STAKING_ID: LockIdentifier = *b"staking "; +const STAKING_ID: fungibles::LockIdentifier = *b"staking "; #[frame_support::pallet] pub mod pallet { @@ -78,7 +78,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The staking balance. - type Currency: LockableCurrency< + type Currency: fungibles::Lockable< Self::AccountId, Moment = Self::BlockNumber, Balance = Self::CurrencyBalance, diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index e5ba98fe0c5bb..3a831d9c27cc6 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -20,6 +20,7 @@ //! NOTE: If you're looking for `parameter_types`, it has moved in to the top-level module. pub mod tokens; +#[allow(deprecated)] pub use tokens::{ currency::{ ActiveIssuanceOf, Currency, LockIdentifier, LockableCurrency, NamedReservableCurrency, diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index 48247b6021798..29603198e9a2b 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -32,7 +32,10 @@ use sp_std::fmt::Debug; mod reservable; pub use reservable::{NamedReservableCurrency, ReservableCurrency}; mod lockable; -pub use lockable::{LockIdentifier, LockableCurrency, VestingSchedule}; + +#[deprecated(note = "Deprecated in favour of using fungibles::Lockable trait directly")] +pub use super::fungibles::{LockIdentifier, Lockable as LockableCurrency}; +pub use lockable::VestingSchedule; /// Abstraction over a fungible assets system. pub trait Currency { diff --git a/frame/support/src/traits/tokens/currency/lockable.rs b/frame/support/src/traits/tokens/currency/lockable.rs index a10edd6e3e874..5b7cad3b5c1d3 100644 --- a/frame/support/src/traits/tokens/currency/lockable.rs +++ b/frame/support/src/traits/tokens/currency/lockable.rs @@ -17,52 +17,8 @@ //! The lockable currency trait and some associated types. -use super::{super::misc::WithdrawReasons, Currency}; -use crate::{dispatch::DispatchResult, traits::misc::Get}; - -/// An identifier for a lock. Used for disambiguating different locks so that -/// they can be individually replaced or removed. -pub type LockIdentifier = [u8; 8]; - -/// A currency whose accounts can have liquidity restrictions. -pub trait LockableCurrency: Currency { - /// The quantity used to denote time; usually just a `BlockNumber`. - type Moment; - - /// The maximum number of locks a user should have on their account. - type MaxLocks: Get; - - /// Create a new balance lock on account `who`. - /// - /// If the new lock is valid (i.e. not already expired), it will push the struct to - /// the `Locks` vec in storage. Note that you can lock more funds than a user has. - /// - /// If the lock `id` already exists, this will update it. - fn set_lock( - id: LockIdentifier, - who: &AccountId, - amount: Self::Balance, - reasons: WithdrawReasons, - ); - - /// Changes a balance lock (selected by `id`) so that it becomes less liquid in all - /// parameters or creates a new one if it does not exist. - /// - /// Calling `extend_lock` on an existing lock `id` differs from `set_lock` in that it - /// applies the most severe constraints of the two, while `set_lock` replaces the lock - /// with the new parameters. As in, `extend_lock` will set: - /// - maximum `amount` - /// - bitwise mask of all `reasons` - fn extend_lock( - id: LockIdentifier, - who: &AccountId, - amount: Self::Balance, - reasons: WithdrawReasons, - ); - - /// Remove an existing lock. - fn remove_lock(id: LockIdentifier, who: &AccountId); -} +use super::Currency; +use crate::dispatch::DispatchResult; /// A vesting schedule over a currency. This allows a particular currency to have vesting limits /// applied to it. diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs index 05e109b870ec0..d11959fd7c5d2 100644 --- a/frame/support/src/traits/tokens/fungible.rs +++ b/frame/support/src/traits/tokens/fungible.rs @@ -29,6 +29,7 @@ use sp_runtime::traits::Saturating; mod balanced; mod imbalance; + pub use balanced::{Balanced, Unbalanced}; pub use imbalance::{CreditOf, DebtOf, HandleImbalanceDrop, Imbalance}; diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 0743e3031c467..6cc6d70de15a7 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -33,7 +33,9 @@ pub mod metadata; pub use balanced::{Balanced, Unbalanced}; mod imbalance; pub use imbalance::{CreditOf, DebtOf, HandleImbalanceDrop, Imbalance}; +mod lockable; pub mod roles; +pub use lockable::{LockIdentifier, Lockable}; /// Trait for providing balance-inspection access to a set of named fungible assets. pub trait Inspect { diff --git a/frame/support/src/traits/tokens/fungibles/lockable.rs b/frame/support/src/traits/tokens/fungibles/lockable.rs new file mode 100644 index 0000000000000..185b40eae9b28 --- /dev/null +++ b/frame/support/src/traits/tokens/fungibles/lockable.rs @@ -0,0 +1,65 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The Lockable trait and some associated types. + +use super::{super::misc::WithdrawReasons, currency::Currency}; +use crate::traits::misc::Get; + +/// An identifier for a lock. Used for disambiguating different locks so that +/// they can be individually replaced or removed. +pub type LockIdentifier = [u8; 8]; + +/// A currency whose accounts can have liquidity restrictions. +pub trait Lockable: Currency { + /// The quantity used to denote time; usually just a `BlockNumber`. + type Moment; + + /// The maximum number of locks a user should have on their account. + type MaxLocks: Get; + + /// Create a new balance lock on account `who`. + /// + /// If the new lock is valid (i.e. not already expired), it will push the struct to + /// the `Locks` vec in storage. Note that you can lock more funds than a user has. + /// + /// If the lock `id` already exists, this will update it. + fn set_lock( + id: LockIdentifier, + who: &AccountId, + amount: Self::Balance, + reasons: WithdrawReasons, + ); + + /// Changes a balance lock (selected by `id`) so that it becomes less liquid in all + /// parameters or creates a new one if it does not exist. + /// + /// Calling `extend_lock` on an existing lock `id` differs from `set_lock` in that it + /// applies the most severe constraints of the two, while `set_lock` replaces the lock + /// with the new parameters. As in, `extend_lock` will set: + /// - maximum `amount` + /// - bitwise mask of all `reasons` + fn extend_lock( + id: LockIdentifier, + who: &AccountId, + amount: Self::Balance, + reasons: WithdrawReasons, + ); + + /// Remove an existing lock. + fn remove_lock(id: LockIdentifier, who: &AccountId); +} diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index a92f94baf6cf9..226f539a740f8 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -62,7 +62,7 @@ use frame_support::{ ensure, storage::bounded_vec::BoundedVec, traits::{ - Currency, ExistenceRequirement, Get, LockIdentifier, LockableCurrency, VestingSchedule, + fungibles, fungibles::Lockable, Currency, ExistenceRequirement, Get, VestingSchedule, WithdrawReasons, }, weights::Weight, @@ -83,11 +83,12 @@ pub use weights::WeightInfo; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -type MaxLocksOf = - <::Currency as LockableCurrency<::AccountId>>::MaxLocks; +type MaxLocksOf = <::Currency as fungibles::Lockable< + ::AccountId, +>>::MaxLocks; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -const VESTING_ID: LockIdentifier = *b"vesting "; +const VESTING_ID: fungibles::LockIdentifier = *b"vesting "; // A value placed in storage that represents the current version of the Vesting storage. // This value is used by `on_runtime_upgrade` to determine whether we run storage migration logic. @@ -159,7 +160,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The currency trait. - type Currency: LockableCurrency; + type Currency: fungibles::Lockable; /// Convert the block number into a balance. type BlockNumberToBalance: Convert>; From fae9e366eabd70000895cfd5f52cd1cc2afaacd6 Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Thu, 8 Dec 2022 15:09:17 +0100 Subject: [PATCH 1450/1472] [pallet-assets] add asset_exists(id: AssetId) function (#12782) * check if an asset exists via loose coupling * Update frame/support/src/traits/tokens/fungibles.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: parity-processbot <> --- frame/assets/src/impl_fungibles.rs | 4 ++++ frame/support/src/traits/tokens/fungibles.rs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 6e0a9ac08ebb1..b10b8c6b10755 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -59,6 +59,10 @@ impl, I: 'static> fungibles::Inspect<::AccountId ) -> WithdrawConsequence { Pallet::::can_decrease(asset, who, amount, false) } + + fn asset_exists(asset: Self::AssetId) -> bool { + Asset::::contains_key(asset) + } } impl, I: 'static> fungibles::InspectMetadata<::AccountId> diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 6cc6d70de15a7..045ecd05134c2 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -83,6 +83,9 @@ pub trait Inspect { who: &AccountId, amount: Self::Balance, ) -> WithdrawConsequence; + + /// Returns `true` if an `asset` exists. + fn asset_exists(asset: Self::AssetId) -> bool; } /// Trait for reading metadata from a fungible asset. From d0540a79967cb06cd7598a4965c7c06afc788b0c Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 9 Dec 2022 01:18:51 +0900 Subject: [PATCH 1451/1472] Introduce sensible weight constants (#12868) * Introduce sensible weight constants * cargo fmt * Remove unused import * Add missing import * ".git/.scripts/bench-bot.sh" pallet dev pallet_lottery Co-authored-by: command-bot <> --- bin/node-template/runtime/src/lib.rs | 6 +- bin/node/runtime/src/lib.rs | 7 ++- docs/Upgrading-2.0-to-3.0.md | 4 +- frame/babe/src/default_weights.rs | 21 ++++--- frame/contracts/src/tests.rs | 4 +- frame/democracy/src/tests.rs | 4 +- .../election-provider-multi-phase/src/mock.rs | 2 +- frame/fast-unstake/src/mock.rs | 4 +- frame/grandpa/src/default_weights.rs | 20 ++++--- frame/lottery/src/weights.rs | 58 +++++++++---------- .../src/default_weights.rs | 4 +- frame/offences/benchmarking/src/mock.rs | 4 +- frame/offences/src/mock.rs | 6 +- frame/staking/src/mock.rs | 2 +- frame/staking/src/tests.rs | 13 +++-- frame/support/src/weights/block_weights.rs | 9 +-- .../support/src/weights/extrinsic_weights.rs | 9 +-- frame/support/src/weights/paritydb_weights.rs | 12 ++-- frame/support/src/weights/rocksdb_weights.rs | 12 ++-- frame/system/src/limits.rs | 2 +- primitives/weights/src/lib.rs | 11 ++-- .../frame/benchmarking-cli/src/block/bench.rs | 4 +- .../benchmarking-cli/src/overhead/README.md | 6 +- .../benchmarking-cli/src/overhead/weights.hbs | 13 +++-- .../benchmarking-cli/src/storage/README.md | 4 +- .../benchmarking-cli/src/storage/weights.hbs | 12 ++-- 26 files changed, 140 insertions(+), 113 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 1d0e18d31bf80..938282c662b5c 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -32,7 +32,9 @@ pub use frame_support::{ ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, Randomness, StorageInfo, }, weights::{ - constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, + constants::{ + BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, + }, IdentityFee, Weight, }, StorageValue, @@ -141,7 +143,7 @@ parameter_types! { /// We allow for 2 seconds of compute with a 6 second average block time. pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::with_sensible_defaults( - (2u64 * WEIGHT_PER_SECOND).set_proof_size(u64::MAX), + Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), NORMAL_DISPATCH_RATIO, ); pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 44d8e287064f9..a754fac1da7ab 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -38,7 +38,9 @@ use frame_support::{ WithdrawReasons, }, weights::{ - constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, + constants::{ + BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, + }, ConstantMultiplier, IdentityFee, Weight, }, PalletId, RuntimeDebug, @@ -173,7 +175,8 @@ const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// by Operational extrinsics. const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); /// We allow for 2 seconds of compute with a 6 second average block time, with maximum proof size. -const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND.saturating_mul(2).set_proof_size(u64::MAX); +const MAXIMUM_BLOCK_WEIGHT: Weight = + Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX); parameter_types! { pub const BlockHashCount: BlockNumber = 2400; diff --git a/docs/Upgrading-2.0-to-3.0.md b/docs/Upgrading-2.0-to-3.0.md index 7540e0d5b5b8c..906018db9a707 100644 --- a/docs/Upgrading-2.0-to-3.0.md +++ b/docs/Upgrading-2.0-to-3.0.md @@ -100,12 +100,12 @@ And update the overall definition for weights on frame and a few related types a +/// by Operational extrinsics. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +/// We allow for 2 seconds of compute with a 6 second average block time. -+const MAXIMUM_BLOCK_WEIGHT: Weight = 2u64 * WEIGHT_PER_SECOND; ++const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX); + parameter_types! { pub const BlockHashCount: BlockNumber = 2400; - /// We allow for 2 seconds of compute with a 6 second average block time. -- pub const MaximumBlockWeight: Weight = 2u64 * WEIGHT_PER_SECOND; +- pub const MaximumBlockWeight: Weight = Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX); - pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); - /// Assume 10% of weight for average on_initialize calls. - pub MaximumExtrinsicWeight: Weight = diff --git a/frame/babe/src/default_weights.rs b/frame/babe/src/default_weights.rs index d3e0c9d044883..f864fd18d86a6 100644 --- a/frame/babe/src/default_weights.rs +++ b/frame/babe/src/default_weights.rs @@ -19,7 +19,7 @@ //! This file was not auto-generated. use frame_support::weights::{ - constants::{RocksDbWeight as DbWeight, WEIGHT_PER_MICROS, WEIGHT_PER_NANOS}, + constants::{RocksDbWeight as DbWeight, WEIGHT_REF_TIME_PER_MICROS, WEIGHT_REF_TIME_PER_NANOS}, Weight, }; @@ -38,17 +38,20 @@ impl crate::WeightInfo for () { const MAX_NOMINATORS: u64 = 200; // checking membership proof - let ref_time_weight = (35u64 * WEIGHT_PER_MICROS) - .saturating_add((175u64 * WEIGHT_PER_NANOS).saturating_mul(validator_count)) + Weight::from_ref_time(35u64 * WEIGHT_REF_TIME_PER_MICROS) + .saturating_add( + Weight::from_ref_time(175u64 * WEIGHT_REF_TIME_PER_NANOS) + .saturating_mul(validator_count), + ) .saturating_add(DbWeight::get().reads(5)) // check equivocation proof - .saturating_add(110u64 * WEIGHT_PER_MICROS) + .saturating_add(Weight::from_ref_time(110u64 * WEIGHT_REF_TIME_PER_MICROS)) // report offence - .saturating_add(110u64 * WEIGHT_PER_MICROS) - .saturating_add(25u64 * WEIGHT_PER_MICROS * MAX_NOMINATORS) + .saturating_add(Weight::from_ref_time(110u64 * WEIGHT_REF_TIME_PER_MICROS)) + .saturating_add(Weight::from_ref_time( + 25u64 * WEIGHT_REF_TIME_PER_MICROS * MAX_NOMINATORS, + )) .saturating_add(DbWeight::get().reads(14 + 3 * MAX_NOMINATORS)) - .saturating_add(DbWeight::get().writes(10 + 3 * MAX_NOMINATORS)); - - ref_time_weight + .saturating_add(DbWeight::get().writes(10 + 3 * MAX_NOMINATORS)) } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index f4c8889ef05f4..f4cba0c85b083 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -40,7 +40,7 @@ use frame_support::{ fungibles::Lockable, BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, OnIdle, OnInitialize, ReservableCurrency, WithdrawReasons, }, - weights::{constants::WEIGHT_PER_SECOND, Weight}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; use frame_system::{self as system, EventRecord, Phase}; use pretty_assertions::{assert_eq, assert_ne}; @@ -285,7 +285,7 @@ impl RegisteredChainExtension for TempStorageExtension { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max( - (2u64 * WEIGHT_PER_SECOND).set_proof_size(u64::MAX), + Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), ); pub static ExistentialDeposit: u64 = 1; } diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index eceb1a3400bba..41b279035028e 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -77,7 +77,9 @@ impl Contains for BaseFilter { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(frame_support::weights::constants::WEIGHT_PER_SECOND.set_proof_size(u64::MAX)); + frame_system::limits::BlockWeights::simple_max( + Weight::from_parts(frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, u64::MAX), + ); } impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 8ab7e5bbf733d..347a4f19185f9 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -239,7 +239,7 @@ parameter_types! { pub const ExistentialDeposit: u64 = 1; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights ::with_sensible_defaults( - Weight::from_parts(2u64 * constants::WEIGHT_PER_SECOND.ref_time(), u64::MAX), + Weight::from_parts(2u64 * constants::WEIGHT_REF_TIME_PER_SECOND, u64::MAX), NORMAL_DISPATCH_RATIO, ); } diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index d66f4ba5663d9..b67dcf581ed97 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -21,7 +21,7 @@ use frame_support::{ pallet_prelude::*, parameter_types, traits::{ConstU64, Currency}, - weights::constants::WEIGHT_PER_SECOND, + weights::constants::WEIGHT_REF_TIME_PER_SECOND, }; use sp_runtime::traits::{Convert, IdentityLookup}; @@ -37,7 +37,7 @@ pub type T = Runtime; parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max( - (2u64 * WEIGHT_PER_SECOND).set_proof_size(u64::MAX), + Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), ); } diff --git a/frame/grandpa/src/default_weights.rs b/frame/grandpa/src/default_weights.rs index 4ca94dd576fb7..ba343cabac622 100644 --- a/frame/grandpa/src/default_weights.rs +++ b/frame/grandpa/src/default_weights.rs @@ -19,7 +19,7 @@ //! This file was not auto-generated. use frame_support::weights::{ - constants::{RocksDbWeight as DbWeight, WEIGHT_PER_MICROS, WEIGHT_PER_NANOS}, + constants::{RocksDbWeight as DbWeight, WEIGHT_REF_TIME_PER_MICROS, WEIGHT_REF_TIME_PER_NANOS}, Weight, }; @@ -34,14 +34,19 @@ impl crate::WeightInfo for () { const MAX_NOMINATORS: u64 = 200; // checking membership proof - (35u64 * WEIGHT_PER_MICROS) - .saturating_add((175u64 * WEIGHT_PER_NANOS).saturating_mul(validator_count)) + Weight::from_ref_time(35u64 * WEIGHT_REF_TIME_PER_MICROS) + .saturating_add( + Weight::from_ref_time(175u64 * WEIGHT_REF_TIME_PER_NANOS) + .saturating_mul(validator_count), + ) .saturating_add(DbWeight::get().reads(5)) // check equivocation proof - .saturating_add(95u64 * WEIGHT_PER_MICROS) + .saturating_add(Weight::from_ref_time(95u64 * WEIGHT_REF_TIME_PER_MICROS)) // report offence - .saturating_add(110u64 * WEIGHT_PER_MICROS) - .saturating_add(25u64 * WEIGHT_PER_MICROS * MAX_NOMINATORS) + .saturating_add(Weight::from_ref_time(110u64 * WEIGHT_REF_TIME_PER_MICROS)) + .saturating_add(Weight::from_ref_time( + 25u64 * WEIGHT_REF_TIME_PER_MICROS * MAX_NOMINATORS, + )) .saturating_add(DbWeight::get().reads(14 + 3 * MAX_NOMINATORS)) .saturating_add(DbWeight::get().writes(10 + 3 * MAX_NOMINATORS)) // fetching set id -> session index mappings @@ -49,6 +54,7 @@ impl crate::WeightInfo for () { } fn note_stalled() -> Weight { - (3u64 * WEIGHT_PER_MICROS).saturating_add(DbWeight::get().writes(1)) + Weight::from_ref_time(3u64 * WEIGHT_REF_TIME_PER_MICROS) + .saturating_add(DbWeight::get().writes(1)) } } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index c0936ae6c8073..e9ee528cc43b8 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_lottery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-12-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -67,33 +67,33 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - // Minimum execution time: 53_735 nanoseconds. - Weight::from_ref_time(54_235_000) + // Minimum execution time: 52_479 nanoseconds. + Weight::from_ref_time(53_225_000) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Lottery CallIndices (r:0 w:1) /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { - // Minimum execution time: 15_065 nanoseconds. - Weight::from_ref_time(16_467_398) - // Standard Error: 5_392 - .saturating_add(Weight::from_ref_time(294_914).saturating_mul(n.into())) + // Minimum execution time: 14_433 nanoseconds. + Weight::from_ref_time(15_660_780) + // Standard Error: 5_894 + .saturating_add(Weight::from_ref_time(290_482).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - // Minimum execution time: 45_990 nanoseconds. - Weight::from_ref_time(46_789_000) + // Minimum execution time: 43_683 nanoseconds. + Weight::from_ref_time(44_580_000) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - // Minimum execution time: 10_783 nanoseconds. - Weight::from_ref_time(11_180_000) + // Minimum execution time: 10_514 nanoseconds. + Weight::from_ref_time(10_821_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -103,8 +103,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - // Minimum execution time: 62_088 nanoseconds. - Weight::from_ref_time(63_670_000) + // Minimum execution time: 60_254 nanoseconds. + Weight::from_ref_time(61_924_000) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -115,8 +115,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - // Minimum execution time: 64_953 nanoseconds. - Weight::from_ref_time(65_465_000) + // Minimum execution time: 61_552 nanoseconds. + Weight::from_ref_time(62_152_000) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -132,33 +132,33 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Lottery Tickets (r:0 w:1) fn buy_ticket() -> Weight { - // Minimum execution time: 53_735 nanoseconds. - Weight::from_ref_time(54_235_000) + // Minimum execution time: 52_479 nanoseconds. + Weight::from_ref_time(53_225_000) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Lottery CallIndices (r:0 w:1) /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { - // Minimum execution time: 15_065 nanoseconds. - Weight::from_ref_time(16_467_398) - // Standard Error: 5_392 - .saturating_add(Weight::from_ref_time(294_914).saturating_mul(n.into())) + // Minimum execution time: 14_433 nanoseconds. + Weight::from_ref_time(15_660_780) + // Standard Error: 5_894 + .saturating_add(Weight::from_ref_time(290_482).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Lottery Lottery (r:1 w:1) // Storage: Lottery LotteryIndex (r:1 w:1) // Storage: System Account (r:1 w:1) fn start_lottery() -> Weight { - // Minimum execution time: 45_990 nanoseconds. - Weight::from_ref_time(46_789_000) + // Minimum execution time: 43_683 nanoseconds. + Weight::from_ref_time(44_580_000) .saturating_add(RocksDbWeight::get().reads(3)) .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Lottery Lottery (r:1 w:1) fn stop_repeat() -> Weight { - // Minimum execution time: 10_783 nanoseconds. - Weight::from_ref_time(11_180_000) + // Minimum execution time: 10_514 nanoseconds. + Weight::from_ref_time(10_821_000) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } @@ -168,8 +168,8 @@ impl WeightInfo for () { // Storage: Lottery TicketsCount (r:1 w:1) // Storage: Lottery Tickets (r:1 w:0) fn on_initialize_end() -> Weight { - // Minimum execution time: 62_088 nanoseconds. - Weight::from_ref_time(63_670_000) + // Minimum execution time: 60_254 nanoseconds. + Weight::from_ref_time(61_924_000) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -180,8 +180,8 @@ impl WeightInfo for () { // Storage: Lottery Tickets (r:1 w:0) // Storage: Lottery LotteryIndex (r:1 w:1) fn on_initialize_repeat() -> Weight { - // Minimum execution time: 64_953 nanoseconds. - Weight::from_ref_time(65_465_000) + // Minimum execution time: 61_552 nanoseconds. + Weight::from_ref_time(62_152_000) .saturating_add(RocksDbWeight::get().reads(7)) .saturating_add(RocksDbWeight::get().writes(5)) } diff --git a/frame/merkle-mountain-range/src/default_weights.rs b/frame/merkle-mountain-range/src/default_weights.rs index e513e2197f1c6..e4f9750fbcba5 100644 --- a/frame/merkle-mountain-range/src/default_weights.rs +++ b/frame/merkle-mountain-range/src/default_weights.rs @@ -19,7 +19,7 @@ //! This file was not auto-generated. use frame_support::weights::{ - constants::{RocksDbWeight as DbWeight, WEIGHT_PER_NANOS}, + constants::{RocksDbWeight as DbWeight, WEIGHT_REF_TIME_PER_NANOS}, Weight, }; @@ -28,7 +28,7 @@ impl crate::WeightInfo for () { // Reading the parent hash. let leaf_weight = DbWeight::get().reads(1); // Blake2 hash cost. - let hash_weight = 2u64 * WEIGHT_PER_NANOS; + let hash_weight = Weight::from_ref_time(2u64 * WEIGHT_REF_TIME_PER_NANOS); // No-op hook. let hook_weight = Weight::zero(); diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index e022d81c5b5bd..de3a4eca6308d 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -24,7 +24,7 @@ use frame_election_provider_support::{onchain, SequentialPhragmen}; use frame_support::{ parameter_types, traits::{ConstU32, ConstU64}, - weights::constants::WEIGHT_PER_SECOND, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; use frame_system as system; use pallet_session::historical as pallet_session_historical; @@ -41,7 +41,7 @@ type Balance = u64; parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max( - 2u64 * WEIGHT_PER_SECOND + Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX) ); } diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 31dac8d51d3b1..8e4256ec3d3e6 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -26,7 +26,7 @@ use frame_support::{ parameter_types, traits::{ConstU32, ConstU64}, weights::{ - constants::{RocksDbWeight, WEIGHT_PER_SECOND}, + constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, Weight, }, }; @@ -85,7 +85,9 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2u64 * WEIGHT_PER_SECOND); + frame_system::limits::BlockWeights::simple_max( + Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), + ); } impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 16e4e5ddd7aa2..d3affda05277a 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -115,7 +115,7 @@ impl FindAuthor for Author11 { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max( - frame_support::weights::constants::WEIGHT_PER_SECOND * 2 + Weight::from_parts(frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND * 2, u64::MAX), ); pub static SessionsPerEra: SessionIndex = 3; pub static ExistentialDeposit: Balance = 1; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 6609b9087637d..78429122d00f1 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4365,9 +4365,10 @@ mod election_data_provider { #[test] fn targets_2sec_block() { let mut validators = 1000; - while ::WeightInfo::get_npos_targets(validators) - .all_lt(2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND) - { + while ::WeightInfo::get_npos_targets(validators).all_lt(Weight::from_parts( + 2u64 * frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, + u64::MAX, + )) { validators += 1; } @@ -4384,8 +4385,10 @@ mod election_data_provider { let mut nominators = 1000; while ::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) - .all_lt(2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND) - { + .all_lt(Weight::from_parts( + 2u64 * frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, + u64::MAX, + )) { nominators += 1; } diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index 5c8e1f1c86e9d..b68c1fb508b01 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -37,7 +37,7 @@ // --repeat=100 use sp_core::parameter_types; -use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; +use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; parameter_types! { /// Time to execute an empty block. @@ -53,7 +53,8 @@ parameter_types! { /// 99th: 390_723 /// 95th: 365_799 /// 75th: 361_582 - pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(358_523); + pub const BlockExecutionWeight: Weight = + Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(358_523)); } #[cfg(test)] @@ -69,12 +70,12 @@ mod test_weights { // At least 100 µs. assert!( - w.ref_time() >= 100u64 * constants::WEIGHT_PER_MICROS.ref_time(), + w.ref_time() >= 100u64 * constants::WEIGHT_REF_TIME_PER_MICROS, "Weight should be at least 100 µs." ); // At most 50 ms. assert!( - w.ref_time() <= 50u64 * constants::WEIGHT_PER_MILLIS.ref_time(), + w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, "Weight should be at most 50 ms." ); } diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 1db2281dfe488..ced1fb91621f6 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -37,7 +37,7 @@ // --repeat=100 use sp_core::parameter_types; -use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; +use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; parameter_types! { /// Time to execute a NO-OP extrinsic, for example `System::remark`. @@ -53,7 +53,8 @@ parameter_types! { /// 99th: 99_202 /// 95th: 99_163 /// 75th: 99_030 - pub const ExtrinsicBaseWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(98_974); + pub const ExtrinsicBaseWeight: Weight = + Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(98_974)); } #[cfg(test)] @@ -69,12 +70,12 @@ mod test_weights { // At least 10 µs. assert!( - w.ref_time() >= 10u64 * constants::WEIGHT_PER_MICROS.ref_time(), + w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, "Weight should be at least 10 µs." ); // At most 1 ms. assert!( - w.ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, "Weight should be at most 1 ms." ); } diff --git a/frame/support/src/weights/paritydb_weights.rs b/frame/support/src/weights/paritydb_weights.rs index 344e6cf0ddb6e..6fd1112ee2947 100644 --- a/frame/support/src/weights/paritydb_weights.rs +++ b/frame/support/src/weights/paritydb_weights.rs @@ -24,8 +24,8 @@ pub mod constants { /// ParityDB can be enabled with a feature flag, but is still experimental. These weights /// are available for brave runtime engineers who may want to try this out as default. pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 8_000 * constants::WEIGHT_PER_NANOS.ref_time(), - write: 50_000 * constants::WEIGHT_PER_NANOS.ref_time(), + read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, + write: 50_000 * constants::WEIGHT_REF_TIME_PER_NANOS, }; } @@ -41,20 +41,20 @@ pub mod constants { fn sane() { // At least 1 µs. assert!( - W::get().reads(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), + W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, "Read weight should be at least 1 µs." ); assert!( - W::get().writes(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), + W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, "Write weight should be at least 1 µs." ); // At most 1 ms. assert!( - W::get().reads(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, "Read weight should be at most 1 ms." ); assert!( - W::get().writes(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, "Write weight should be at most 1 ms." ); } diff --git a/frame/support/src/weights/rocksdb_weights.rs b/frame/support/src/weights/rocksdb_weights.rs index 4dec2d8c877ea..b18b387de9957 100644 --- a/frame/support/src/weights/rocksdb_weights.rs +++ b/frame/support/src/weights/rocksdb_weights.rs @@ -24,8 +24,8 @@ pub mod constants { /// By default, Substrate uses RocksDB, so this will be the weight used throughout /// the runtime. pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 25_000 * constants::WEIGHT_PER_NANOS.ref_time(), - write: 100_000 * constants::WEIGHT_PER_NANOS.ref_time(), + read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, + write: 100_000 * constants::WEIGHT_REF_TIME_PER_NANOS, }; } @@ -41,20 +41,20 @@ pub mod constants { fn sane() { // At least 1 µs. assert!( - W::get().reads(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), + W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, "Read weight should be at least 1 µs." ); assert!( - W::get().writes(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), + W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, "Write weight should be at least 1 µs." ); // At most 1 ms. assert!( - W::get().reads(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, "Read weight should be at most 1 ms." ); assert!( - W::get().writes(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, "Write weight should be at most 1 ms." ); } diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index eb95b699eba32..54d27c5b9e86d 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -208,7 +208,7 @@ pub struct BlockWeights { impl Default for BlockWeights { fn default() -> Self { Self::with_sensible_defaults( - Weight::from_parts(constants::WEIGHT_PER_SECOND.ref_time(), u64::MAX), + Weight::from_parts(constants::WEIGHT_REF_TIME_PER_SECOND, u64::MAX), DEFAULT_NORMAL_RATIO, ) } diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs index af9e730fbfefd..928080d139864 100644 --- a/primitives/weights/src/lib.rs +++ b/primitives/weights/src/lib.rs @@ -47,12 +47,13 @@ pub use weight_meter::*; pub use weight_v2::*; pub mod constants { - use super::Weight; + pub const WEIGHT_REF_TIME_PER_SECOND: u64 = 1_000_000_000_000; + pub const WEIGHT_REF_TIME_PER_MILLIS: u64 = 1_000_000_000; + pub const WEIGHT_REF_TIME_PER_MICROS: u64 = 1_000_000; + pub const WEIGHT_REF_TIME_PER_NANOS: u64 = 1_000; - pub const WEIGHT_PER_SECOND: Weight = Weight::from_ref_time(1_000_000_000_000); - pub const WEIGHT_PER_MILLIS: Weight = Weight::from_ref_time(1_000_000_000); - pub const WEIGHT_PER_MICROS: Weight = Weight::from_ref_time(1_000_000); - pub const WEIGHT_PER_NANOS: Weight = Weight::from_ref_time(1_000); + pub const WEIGHT_PROOF_SIZE_PER_MB: u64 = 1024 * 1024; + pub const WEIGHT_PROOF_SIZE_PER_KB: u64 = 1024; } /// The old weight type. diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index 5a67b11f494f5..578158d8a2356 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -18,7 +18,7 @@ //! Contains the core benchmarking logic. use codec::DecodeAll; -use frame_support::weights::constants::WEIGHT_PER_NANOS; +use frame_support::weights::constants::WEIGHT_REF_TIME_PER_NANOS; use frame_system::ConsumedWeight; use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; use sc_cli::{Error, Result}; @@ -148,7 +148,7 @@ where let weight = ConsumedWeight::decode_all(&mut raw_weight)?; // Should be divisible, but still use floats in case we ever change that. - Ok((weight.total().ref_time() as f64 / WEIGHT_PER_NANOS.ref_time() as f64).floor() + Ok((weight.total().ref_time() as f64 / WEIGHT_REF_TIME_PER_NANOS as f64).floor() as NanoSeconds) } diff --git a/utils/frame/benchmarking-cli/src/overhead/README.md b/utils/frame/benchmarking-cli/src/overhead/README.md index b21d051e9d44c..1584c2affe0a3 100644 --- a/utils/frame/benchmarking-cli/src/overhead/README.md +++ b/utils/frame/benchmarking-cli/src/overhead/README.md @@ -30,7 +30,8 @@ The file will contain the concrete weight value and various statistics about the /// 99th: 3_631_863 /// 95th: 3_595_674 /// 75th: 3_526_435 -pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(3_532_484); +pub const BlockExecutionWeight: Weight = + Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(3_532_484)); ``` In this example it takes 3.5 ms to execute an empty block. That means that it always takes at least 3.5 ms to execute *any* block. @@ -59,7 +60,8 @@ The relevant section in the output file looks like this: /// 99th: 68_758 /// 95th: 67_843 /// 75th: 67_749 -pub const ExtrinsicBaseWeight: Weight = WEIGHT_PER_NANOS.saturating_mul(67_745); +pub const ExtrinsicBaseWeight: Weight = + Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(67_745)); ``` In this example it takes 67.7 µs to execute a NO-OP extrinsic. That means that it always takes at least 67.7 µs to execute *any* extrinsic. diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index 8d1a369372721..c54393d200bd3 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -14,7 +14,7 @@ {{/each}} use sp_core::parameter_types; -use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; +use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; parameter_types! { {{#if (eq short_name "block")}} @@ -34,7 +34,8 @@ parameter_types! { /// 99th: {{underscore stats.p99}} /// 95th: {{underscore stats.p95}} /// 75th: {{underscore stats.p75}} - pub const {{long_name}}Weight: Weight = WEIGHT_PER_NANOS.saturating_mul({{underscore weight}}); + pub const {{long_name}}Weight: Weight = + Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul({{underscore weight}})); } #[cfg(test)] @@ -51,23 +52,23 @@ mod test_weights { {{#if (eq short_name "block")}} // At least 100 µs. assert!( - w.ref_time() >= 100u64 * constants::WEIGHT_PER_MICROS.ref_time(), + w.ref_time() >= 100u64 * constants::WEIGHT_REF_TIME_PER_MICROS, "Weight should be at least 100 µs." ); // At most 50 ms. assert!( - w.ref_time() <= 50u64 * constants::WEIGHT_PER_MILLIS.ref_time(), + w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, "Weight should be at most 50 ms." ); {{else}} // At least 10 µs. assert!( - w.ref_time() >= 10u64 * constants::WEIGHT_PER_MICROS.ref_time(), + w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, "Weight should be at least 10 µs." ); // At most 1 ms. assert!( - w.ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, "Weight should be at most 1 ms." ); {{/if}} diff --git a/utils/frame/benchmarking-cli/src/storage/README.md b/utils/frame/benchmarking-cli/src/storage/README.md index ecaf4edadab38..f61b7ba1bddd0 100644 --- a/utils/frame/benchmarking-cli/src/storage/README.md +++ b/utils/frame/benchmarking-cli/src/storage/README.md @@ -69,7 +69,7 @@ The interesting part in the generated weight file tells us the weight constants /// 99th: 18_270 /// 95th: 16_190 /// 75th: 14_819 -read: 14_262 * constants::WEIGHT_PER_NANOS, +read: 14_262 * constants::WEIGHT_REF_TIME_PER_NANOS, /// Time to write one storage item. /// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. @@ -84,7 +84,7 @@ read: 14_262 * constants::WEIGHT_PER_NANOS, /// 99th: 135_839 /// 95th: 106_129 /// 75th: 79_239 -write: 71_347 * constants::WEIGHT_PER_NANOS, +write: 71_347 * constants::WEIGHT_REF_TIME_PER_NANOS, ``` ## Arguments diff --git a/utils/frame/benchmarking-cli/src/storage/weights.hbs b/utils/frame/benchmarking-cli/src/storage/weights.hbs index 82e581cf990c8..135b18b193746 100644 --- a/utils/frame/benchmarking-cli/src/storage/weights.hbs +++ b/utils/frame/benchmarking-cli/src/storage/weights.hbs @@ -43,7 +43,7 @@ pub mod constants { /// 99th: {{underscore read.0.p99}} /// 95th: {{underscore read.0.p95}} /// 75th: {{underscore read.0.p75}} - read: {{underscore read_weight}} * constants::WEIGHT_PER_NANOS, + read: {{underscore read_weight}} * constants::WEIGHT_REF_TIME_PER_NANOS, /// Time to write one storage item. /// Calculated by multiplying the *{{params.weight_params.weight_metric}}* of all values with `{{params.weight_params.weight_mul}}` and adding `{{params.weight_params.weight_add}}`. @@ -58,7 +58,7 @@ pub mod constants { /// 99th: {{underscore write.0.p99}} /// 95th: {{underscore write.0.p95}} /// 75th: {{underscore write.0.p75}} - write: {{underscore write_weight}} * constants::WEIGHT_PER_NANOS, + write: {{underscore write_weight}} * constants::WEIGHT_REF_TIME_PER_NANOS, }; } @@ -74,20 +74,20 @@ pub mod constants { fn bound() { // At least 1 µs. assert!( - W::get().reads(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), + W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, "Read weight should be at least 1 µs." ); assert!( - W::get().writes(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), + W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, "Write weight should be at least 1 µs." ); // At most 1 ms. assert!( - W::get().reads(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, "Read weight should be at most 1 ms." ); assert!( - W::get().writes(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, "Write weight should be at most 1 ms." ); } From 02a9deaa007e358a2aa537ce624497c3ef3cf2ca Mon Sep 17 00:00:00 2001 From: Vlad Date: Thu, 8 Dec 2022 17:58:52 +0000 Subject: [PATCH 1452/1472] Checkout to the branch HEAD explicitly in `build-linux-substrate` (#12876) --- scripts/ci/gitlab/pipeline/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 5bbc3fb8f751c..2f8cff7b3ffa6 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -64,6 +64,9 @@ build-linux-substrate: before_script: - mkdir -p ./artifacts/substrate/ - !reference [.rusty-cachier, before_script] + # tldr: we need to checkout the branch HEAD explicitly because of our dynamic versioning approach while building the substrate binary + # see https://github.com/paritytech/ci_cd/issues/682#issuecomment-1340953589 + - git checkout -B "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA" script: - rusty-cachier snapshot create - WASM_BUILD_NO_COLOR=1 time cargo build --locked --release --verbose From 9a0644ca46410613d332d7a2754c502d89146e2f Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Thu, 8 Dec 2022 22:15:14 +0200 Subject: [PATCH 1453/1472] cli: Improve pruning documentation (#12819) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * cli: Improve pruning documentation Signed-off-by: Alexandru Vasile * cli: Keep `finalized` notation and remove `canonical` one * cli: Fix cargo doc * cli: `PruningModeClap` IR enum Signed-off-by: Alexandru Vasile * cli: Convert PruningModeClap into pruning modes Signed-off-by: Alexandru Vasile * cli: Use `PruningModeClap` Signed-off-by: Alexandru Vasile * cli: Rename to `DatabasePruningMode` Signed-off-by: Alexandru Vasile * cli: Implement `FromStr` instead of `clap::ValueEnum` Signed-off-by: Alexandru Vasile * Update client/cli/src/params/pruning_params.rs Co-authored-by: Bastian Köcher * Fix clippy Signed-off-by: Alexandru Vasile * cli: Add option documentation back Signed-off-by: Alexandru Vasile * Apply suggestions from code review Signed-off-by: Alexandru Vasile Co-authored-by: Bastian Köcher --- client/cli/src/params/pruning_params.rs | 114 ++++++++++++++++-------- 1 file changed, 75 insertions(+), 39 deletions(-) diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index 2da1de919771c..7e50f53d7169a 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -23,57 +23,93 @@ use sc_service::{BlocksPruning, PruningMode}; /// Parameters to define the pruning mode #[derive(Debug, Clone, PartialEq, Args)] pub struct PruningParams { - /// Specify the state pruning mode, a number of blocks to keep or 'archive'. + /// Specify the state pruning mode. /// - /// Default is to keep only the last 256 blocks, - /// otherwise, the state can be kept for all of the blocks (i.e 'archive'), - /// or for all of the canonical blocks (i.e 'archive-canonical'). - #[arg(alias = "pruning", long, value_name = "PRUNING_MODE")] - pub state_pruning: Option, - /// Specify the blocks pruning mode, a number of blocks to keep or 'archive'. + /// This mode specifies when the block's state (ie, storage) + /// should be pruned (ie, removed) from the database. /// - /// Default is to keep all finalized blocks. - /// otherwise, all blocks can be kept (i.e 'archive'), - /// or for all canonical blocks (i.e 'archive-canonical'), - /// or for the last N blocks (i.e a number). + /// Possible values: + /// 'archive' Keep the state of all blocks. + /// 'archive-canonical' Keep only the state of finalized blocks. + /// number Keep the state of the last number of finalized blocks. + #[arg(alias = "pruning", long, value_name = "PRUNING_MODE", default_value = "256")] + pub state_pruning: DatabasePruningMode, + /// Specify the blocks pruning mode. /// - /// NOTE: only finalized blocks are subject for removal! - #[arg(alias = "keep-blocks", long, value_name = "COUNT")] - pub blocks_pruning: Option, + /// This mode specifies when the block's body (including justifications) + /// should be pruned (ie, removed) from the database. + /// + /// Possible values: + /// 'archive' Keep all blocks. + /// 'archive-canonical' Keep only finalized blocks. + /// number Keep the last `number` of finalized blocks. + #[arg( + alias = "keep-blocks", + long, + value_name = "PRUNING_MODE", + default_value = "archive-canonical" + )] + pub blocks_pruning: DatabasePruningMode, } impl PruningParams { /// Get the pruning value from the parameters pub fn state_pruning(&self) -> error::Result> { - self.state_pruning - .as_ref() - .map(|s| match s.as_str() { - "archive" => Ok(PruningMode::ArchiveAll), - "archive-canonical" => Ok(PruningMode::ArchiveCanonical), - bc => bc - .parse() - .map_err(|_| { - error::Error::Input("Invalid state pruning mode specified".to_string()) - }) - .map(PruningMode::blocks_pruning), - }) - .transpose() + Ok(Some(self.state_pruning.into())) } /// Get the block pruning value from the parameters pub fn blocks_pruning(&self) -> error::Result { - match self.blocks_pruning.as_ref() { - Some(bp) => match bp.as_str() { - "archive" => Ok(BlocksPruning::KeepAll), - "archive-canonical" => Ok(BlocksPruning::KeepFinalized), - bc => bc - .parse() - .map_err(|_| { - error::Error::Input("Invalid blocks pruning mode specified".to_string()) - }) - .map(BlocksPruning::Some), - }, - None => Ok(BlocksPruning::KeepFinalized), + Ok(self.blocks_pruning.into()) + } +} + +/// Specifies the pruning mode of the database. +/// +/// This specifies when the block's data (either state via `--state-pruning` +/// or body via `--blocks-pruning`) should be pruned (ie, removed) from +/// the database. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum DatabasePruningMode { + /// Keep the data of all blocks. + Archive, + /// Keep only the data of finalized blocks. + ArchiveCanonical, + /// Keep the data of the last number of finalized blocks. + Custom(u32), +} + +impl std::str::FromStr for DatabasePruningMode { + type Err = String; + + fn from_str(input: &str) -> Result { + match input { + "archive" => Ok(Self::Archive), + "archive-canonical" => Ok(Self::ArchiveCanonical), + bc => bc + .parse() + .map_err(|_| "Invalid pruning mode specified".to_string()) + .map(Self::Custom), + } + } +} + +impl Into for DatabasePruningMode { + fn into(self) -> PruningMode { + match self { + DatabasePruningMode::Archive => PruningMode::ArchiveAll, + DatabasePruningMode::ArchiveCanonical => PruningMode::ArchiveCanonical, + DatabasePruningMode::Custom(n) => PruningMode::blocks_pruning(n), + } + } +} + +impl Into for DatabasePruningMode { + fn into(self) -> BlocksPruning { + match self { + DatabasePruningMode::Archive => BlocksPruning::KeepAll, + DatabasePruningMode::ArchiveCanonical => BlocksPruning::KeepFinalized, + DatabasePruningMode::Custom(n) => BlocksPruning::Some(n), } } } From e6bbc53af99458c87b6fafe02314b4959b8da2b0 Mon Sep 17 00:00:00 2001 From: Anthony Alaribe Date: Fri, 9 Dec 2022 11:40:59 +0200 Subject: [PATCH 1454/1472] Revert "Move LockableCurrency trait to fungibles::Lockable and deprecate LockableCurrency (#12798)" (#12882) This reverts commit ea3ca3f757ff9d9559665719a77da81f4cf0f0ce. --- bin/node/runtime/src/lib.rs | 8 +-- frame/balances/README.md | 8 +-- frame/balances/src/lib.rs | 26 ++++---- frame/balances/src/tests.rs | 6 +- frame/contracts/src/tests.rs | 2 +- frame/conviction-voting/src/benchmarking.rs | 2 +- frame/conviction-voting/src/lib.rs | 6 +- frame/democracy/src/lib.rs | 10 ++- frame/elections-phragmen/src/lib.rs | 10 +-- frame/executive/src/lib.rs | 9 ++- frame/referenda/src/lib.rs | 7 +- frame/staking/src/pallet/impls.rs | 5 +- frame/staking/src/pallet/mod.rs | 8 +-- frame/support/src/traits.rs | 1 - frame/support/src/traits/tokens/currency.rs | 5 +- .../src/traits/tokens/currency/lockable.rs | 48 +++++++++++++- frame/support/src/traits/tokens/fungible.rs | 1 - frame/support/src/traits/tokens/fungibles.rs | 2 - .../src/traits/tokens/fungibles/lockable.rs | 65 ------------------- frame/vesting/src/lib.rs | 11 ++-- 20 files changed, 105 insertions(+), 135 deletions(-) delete mode 100644 frame/support/src/traits/tokens/fungibles/lockable.rs diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index a754fac1da7ab..1bb4dd6f913a6 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -32,9 +32,9 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{ - fungible::ItemOf, fungibles, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, - ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, - InstanceFilter, KeyOwnerProofSystem, Nothing, OnUnbalanced, U128CurrencyToVote, + fungible::ItemOf, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, + Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, + KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, WithdrawReasons, }, weights::{ @@ -1006,7 +1006,7 @@ parameter_types! { pub const DesiredRunnersUp: u32 = 7; pub const MaxVoters: u32 = 10 * 1000; pub const MaxCandidates: u32 = 1000; - pub const ElectionsPhragmenPalletId: fungibles::LockIdentifier = *b"phrelect"; + pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; } // Make sure that there are no more than `MaxMembers` members elected via elections-phragmen. diff --git a/frame/balances/README.md b/frame/balances/README.md index d32fffbf0e7ad..93e424a89c721 100644 --- a/frame/balances/README.md +++ b/frame/balances/README.md @@ -57,7 +57,7 @@ that you need, then you can avoid coupling with the Balances module. fungible assets system. - [`ReservableCurrency`](https://docs.rs/frame-support/latest/frame_support/traits/trait.ReservableCurrency.html): Functions for dealing with assets that can be reserved from an account. -- [`Lockable`](https://docs.rs/frame-support/latest/frame_support/traits/fungibles/trait.Lockable.html): Functions for +- [`LockableCurrency`](https://docs.rs/frame-support/latest/frame_support/traits/trait.LockableCurrency.html): Functions for dealing with accounts that allow liquidity restrictions. - [`Imbalance`](https://docs.rs/frame-support/latest/frame_support/traits/trait.Imbalance.html): Functions for handling imbalances between total issuance in the system and account balances. Must be used when a function @@ -88,13 +88,13 @@ pub type NegativeImbalanceOf = <::Currency as Currency<; + type Currency: LockableCurrency; } fn update_ledger( diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index d74de37e993f7..381a0ffceeb85 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -79,7 +79,7 @@ //! - [`ReservableCurrency`](frame_support::traits::ReservableCurrency): //! - [`NamedReservableCurrency`](frame_support::traits::NamedReservableCurrency): //! Functions for dealing with assets that can be reserved from an account. -//! - [`Lockable`](frame_support::traits::fungibles::Lockable): Functions for +//! - [`LockableCurrency`](frame_support::traits::LockableCurrency): Functions for //! dealing with accounts that allow liquidity restrictions. //! - [`Imbalance`](frame_support::traits::Imbalance): Functions for handling //! imbalances between total issuance in the system and account balances. Must be used when a @@ -113,13 +113,13 @@ //! # fn main() {} //! ``` //! -//! The Staking pallet uses the `fungibles::Lockable` trait to lock a stash account's funds: +//! The Staking pallet uses the `LockableCurrency` trait to lock a stash account's funds: //! //! ``` -//! use frame_support::traits::{WithdrawReasons, fungibles, fungibles::Lockable}; +//! use frame_support::traits::{WithdrawReasons, LockableCurrency}; //! use sp_runtime::traits::Bounded; //! pub trait Config: frame_system::Config { -//! type Currency: fungibles::Lockable; +//! type Currency: LockableCurrency; //! } //! # struct StakingLedger { //! # stash: ::AccountId, @@ -171,13 +171,11 @@ use frame_support::{ ensure, pallet_prelude::DispatchResult, traits::{ - tokens::{ - fungible, fungibles, BalanceStatus as Status, DepositConsequence, WithdrawConsequence, - }, + tokens::{fungible, BalanceStatus as Status, DepositConsequence, WithdrawConsequence}, Currency, DefensiveSaturating, ExistenceRequirement, ExistenceRequirement::{AllowDeath, KeepAlive}, - Get, Imbalance, NamedReservableCurrency, OnUnbalanced, ReservableCurrency, SignedImbalance, - StoredMap, TryDrop, WithdrawReasons, + Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency, OnUnbalanced, + ReservableCurrency, SignedImbalance, StoredMap, TryDrop, WithdrawReasons, }, WeakBoundedVec, }; @@ -664,7 +662,7 @@ impl BitOr for Reasons { #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] pub struct BalanceLock { /// An identifier for this lock. Only one lock may be in existence for each identifier. - pub id: fungibles::LockIdentifier, + pub id: LockIdentifier, /// The amount which the free balance may not drop below when this lock is in effect. pub amount: Balance, /// If true, then the lock remains in effect even for payment of transaction fees. @@ -2133,7 +2131,7 @@ where } } -impl, I: 'static> fungibles::Lockable for Pallet +impl, I: 'static> LockableCurrency for Pallet where T::Balance: MaybeSerializeDeserialize + Debug, { @@ -2144,7 +2142,7 @@ where // Set a lock on the balance of `who`. // Is a no-op if lock amount is zero or `reasons` `is_none()`. fn set_lock( - id: fungibles::LockIdentifier, + id: LockIdentifier, who: &T::AccountId, amount: T::Balance, reasons: WithdrawReasons, @@ -2166,7 +2164,7 @@ where // Extend a lock on the balance of `who`. // Is a no-op if lock amount is zero or `reasons` `is_none()`. fn extend_lock( - id: fungibles::LockIdentifier, + id: LockIdentifier, who: &T::AccountId, amount: T::Balance, reasons: WithdrawReasons, @@ -2195,7 +2193,7 @@ where Self::update_locks(who, &locks[..]); } - fn remove_lock(id: fungibles::LockIdentifier, who: &T::AccountId) { + fn remove_lock(id: LockIdentifier, who: &T::AccountId) { let mut locks = Self::locks(who); locks.retain(|l| l.id != id); Self::update_locks(who, &locks[..]); diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 44a71b93257db..83944caf9f7ff 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -28,15 +28,15 @@ macro_rules! decl_tests { use frame_support::{ assert_noop, assert_storage_noop, assert_ok, assert_err, traits::{ - fungibles, fungibles::Lockable, WithdrawReasons, + LockableCurrency, LockIdentifier, WithdrawReasons, Currency, ReservableCurrency, ExistenceRequirement::AllowDeath } }; use pallet_transaction_payment::{ChargeTransactionPayment, Multiplier}; use frame_system::RawOrigin; - const ID_1: fungibles::LockIdentifier = *b"1 "; - const ID_2: fungibles::LockIdentifier = *b"2 "; + const ID_1: LockIdentifier = *b"1 "; + const ID_2: LockIdentifier = *b"2 "; pub const CALL: &<$test as frame_system::Config>::RuntimeCall = &RuntimeCall::Balances(pallet_balances::Call::transfer { dest: 0, value: 0 }); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index f4cba0c85b083..a467800dfe15b 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -37,7 +37,7 @@ use frame_support::{ parameter_types, storage::child, traits::{ - fungibles::Lockable, BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, OnIdle, + BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, LockableCurrency, OnIdle, OnInitialize, ReservableCurrency, WithdrawReasons, }, weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, diff --git a/frame/conviction-voting/src/benchmarking.rs b/frame/conviction-voting/src/benchmarking.rs index 4bebc6a97c49b..117bb7fe22989 100644 --- a/frame/conviction-voting/src/benchmarking.rs +++ b/frame/conviction-voting/src/benchmarking.rs @@ -23,7 +23,7 @@ use assert_matches::assert_matches; use frame_benchmarking::{account, benchmarks_instance_pallet, whitelist_account}; use frame_support::{ dispatch::RawOrigin, - traits::{Currency, Get}, + traits::{fungible, Currency, Get}, }; use sp_runtime::traits::Bounded; use sp_std::collections::btree_map::BTreeMap; diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index 992b532fb93ed..3ecc6e56be94e 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -31,7 +31,7 @@ use frame_support::{ dispatch::{DispatchError, DispatchResult}, ensure, traits::{ - fungible, fungibles, fungibles::Lockable, Currency, Get, PollStatus, Polling, + fungible, Currency, Get, LockIdentifier, LockableCurrency, PollStatus, Polling, ReservableCurrency, WithdrawReasons, }, }; @@ -60,7 +60,7 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; -const CONVICTION_VOTING_ID: fungibles::LockIdentifier = *b"pyconvot"; +const CONVICTION_VOTING_ID: LockIdentifier = *b"pyconvot"; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; type BalanceOf = @@ -104,7 +104,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// Currency type with which voting happens. type Currency: ReservableCurrency - + fungibles::Lockable + + LockableCurrency + fungible::Inspect; /// The implementation of the logic which conducts polls. diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 096122cb1caa5..cf954d4800eee 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -157,11 +157,9 @@ use frame_support::{ ensure, traits::{ defensive_prelude::*, - fungibles, - fungibles::Lockable, schedule::{v3::Named as ScheduleNamed, DispatchTime}, - Bounded, Currency, Get, OnUnbalanced, QueryPreimage, ReservableCurrency, StorePreimage, - WithdrawReasons, + Bounded, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, QueryPreimage, + ReservableCurrency, StorePreimage, WithdrawReasons, }, weights::Weight, }; @@ -191,7 +189,7 @@ pub mod benchmarking; pub mod migrations; -const DEMOCRACY_ID: fungibles::LockIdentifier = *b"democrac"; +const DEMOCRACY_ID: LockIdentifier = *b"democrac"; /// A proposal index. pub type PropIndex = u32; @@ -236,7 +234,7 @@ pub mod pallet { /// Currency type for this pallet. type Currency: ReservableCurrency - + fungibles::Lockable; + + LockableCurrency; /// The period between a proposal being approved and enacted. /// diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 13190237ea784..165a8fcab429b 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -101,8 +101,8 @@ use codec::{Decode, Encode}; use frame_support::{ traits::{ - defensive_prelude::*, fungibles, fungibles::Lockable, ChangeMembers, Contains, - ContainsLengthBound, Currency, CurrencyToVote, Get, InitializeMembers, OnUnbalanced, + defensive_prelude::*, ChangeMembers, Contains, ContainsLengthBound, Currency, + CurrencyToVote, Get, InitializeMembers, LockIdentifier, LockableCurrency, OnUnbalanced, ReservableCurrency, SortedMembers, WithdrawReasons, }, weights::Weight, @@ -199,10 +199,10 @@ pub mod pallet { /// Identifier for the elections-phragmen pallet's lock #[pallet::constant] - type PalletId: Get; + type PalletId: Get; /// The currency that people are electing with. - type Currency: fungibles::Lockable + type Currency: LockableCurrency + ReservableCurrency; /// What to do when the members change. @@ -1274,7 +1274,7 @@ mod tests { } parameter_types! { - pub const ElectionsPhragmenPalletId: fungibles::LockIdentifier = *b"phrelect"; + pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; pub const PhragmenMaxVoters: u32 = 1000; pub const PhragmenMaxCandidates: u32 = 100; } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 2d307a1a024b5..5a4ef92b1c874 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -620,7 +620,10 @@ mod tests { use frame_support::{ assert_err, parameter_types, - traits::{fungibles, ConstU32, ConstU64, ConstU8, Currency, WithdrawReasons}, + traits::{ + ConstU32, ConstU64, ConstU8, Currency, LockIdentifier, LockableCurrency, + WithdrawReasons, + }, weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFee}, }; use frame_system::{Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo}; @@ -1182,11 +1185,11 @@ mod tests { #[test] fn can_pay_for_tx_fee_on_full_lock() { - let id: fungibles::LockIdentifier = *b"0 "; + let id: LockIdentifier = *b"0 "; let execute_with_lock = |lock: WithdrawReasons| { let mut t = new_test_ext(1); t.execute_with(|| { - as fungibles::Lockable>::set_lock( + as LockableCurrency>::set_lock( id, &1, 110, lock, ); let xt = TestXt::new( diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 551628fee9159..2bb01baa0cd3a 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -1,3 +1,5 @@ +// This file is part of Substrate. + // Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 @@ -66,12 +68,11 @@ use codec::{Codec, Encode}; use frame_support::{ ensure, traits::{ - fungibles, schedule::{ v3::{Anon as ScheduleAnon, Named as ScheduleNamed}, DispatchTime, }, - Currency, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, + Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, ReservableCurrency, StorePreimage, VoteTally, }, BoundedVec, @@ -132,7 +133,7 @@ macro_rules! impl_tracksinfo_get { }; } -const ASSEMBLY_ID: fungibles::LockIdentifier = *b"assembly"; +const ASSEMBLY_ID: LockIdentifier = *b"assembly"; #[frame_support::pallet] pub mod pallet { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 34e12fbcf6adf..c22a2bd2d1f77 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -25,9 +25,8 @@ use frame_support::{ dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ - fungibles::Lockable, Currency, CurrencyToVote, Defensive, DefensiveResult, - EstimateNextNewSession, Get, Imbalance, OnUnbalanced, TryCollect, UnixTime, - WithdrawReasons, + Currency, CurrencyToVote, Defensive, DefensiveResult, EstimateNextNewSession, Get, + Imbalance, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, WithdrawReasons, }, weights::Weight, }; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index fd0c494fa6723..8fddba2150370 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -24,8 +24,8 @@ use frame_support::{ dispatch::Codec, pallet_prelude::*, traits::{ - fungibles, fungibles::Lockable, Currency, CurrencyToVote, Defensive, DefensiveResult, - DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, OnUnbalanced, TryCollect, + Currency, CurrencyToVote, Defensive, DefensiveResult, DefensiveSaturating, EnsureOrigin, + EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, }, weights::Weight, @@ -50,7 +50,7 @@ use crate::{ ValidatorPrefs, }; -const STAKING_ID: fungibles::LockIdentifier = *b"staking "; +const STAKING_ID: LockIdentifier = *b"staking "; #[frame_support::pallet] pub mod pallet { @@ -78,7 +78,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The staking balance. - type Currency: fungibles::Lockable< + type Currency: LockableCurrency< Self::AccountId, Moment = Self::BlockNumber, Balance = Self::CurrencyBalance, diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 3a831d9c27cc6..e5ba98fe0c5bb 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -20,7 +20,6 @@ //! NOTE: If you're looking for `parameter_types`, it has moved in to the top-level module. pub mod tokens; -#[allow(deprecated)] pub use tokens::{ currency::{ ActiveIssuanceOf, Currency, LockIdentifier, LockableCurrency, NamedReservableCurrency, diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index 29603198e9a2b..48247b6021798 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -32,10 +32,7 @@ use sp_std::fmt::Debug; mod reservable; pub use reservable::{NamedReservableCurrency, ReservableCurrency}; mod lockable; - -#[deprecated(note = "Deprecated in favour of using fungibles::Lockable trait directly")] -pub use super::fungibles::{LockIdentifier, Lockable as LockableCurrency}; -pub use lockable::VestingSchedule; +pub use lockable::{LockIdentifier, LockableCurrency, VestingSchedule}; /// Abstraction over a fungible assets system. pub trait Currency { diff --git a/frame/support/src/traits/tokens/currency/lockable.rs b/frame/support/src/traits/tokens/currency/lockable.rs index 5b7cad3b5c1d3..a10edd6e3e874 100644 --- a/frame/support/src/traits/tokens/currency/lockable.rs +++ b/frame/support/src/traits/tokens/currency/lockable.rs @@ -17,8 +17,52 @@ //! The lockable currency trait and some associated types. -use super::Currency; -use crate::dispatch::DispatchResult; +use super::{super::misc::WithdrawReasons, Currency}; +use crate::{dispatch::DispatchResult, traits::misc::Get}; + +/// An identifier for a lock. Used for disambiguating different locks so that +/// they can be individually replaced or removed. +pub type LockIdentifier = [u8; 8]; + +/// A currency whose accounts can have liquidity restrictions. +pub trait LockableCurrency: Currency { + /// The quantity used to denote time; usually just a `BlockNumber`. + type Moment; + + /// The maximum number of locks a user should have on their account. + type MaxLocks: Get; + + /// Create a new balance lock on account `who`. + /// + /// If the new lock is valid (i.e. not already expired), it will push the struct to + /// the `Locks` vec in storage. Note that you can lock more funds than a user has. + /// + /// If the lock `id` already exists, this will update it. + fn set_lock( + id: LockIdentifier, + who: &AccountId, + amount: Self::Balance, + reasons: WithdrawReasons, + ); + + /// Changes a balance lock (selected by `id`) so that it becomes less liquid in all + /// parameters or creates a new one if it does not exist. + /// + /// Calling `extend_lock` on an existing lock `id` differs from `set_lock` in that it + /// applies the most severe constraints of the two, while `set_lock` replaces the lock + /// with the new parameters. As in, `extend_lock` will set: + /// - maximum `amount` + /// - bitwise mask of all `reasons` + fn extend_lock( + id: LockIdentifier, + who: &AccountId, + amount: Self::Balance, + reasons: WithdrawReasons, + ); + + /// Remove an existing lock. + fn remove_lock(id: LockIdentifier, who: &AccountId); +} /// A vesting schedule over a currency. This allows a particular currency to have vesting limits /// applied to it. diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs index d11959fd7c5d2..05e109b870ec0 100644 --- a/frame/support/src/traits/tokens/fungible.rs +++ b/frame/support/src/traits/tokens/fungible.rs @@ -29,7 +29,6 @@ use sp_runtime::traits::Saturating; mod balanced; mod imbalance; - pub use balanced::{Balanced, Unbalanced}; pub use imbalance::{CreditOf, DebtOf, HandleImbalanceDrop, Imbalance}; diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 045ecd05134c2..a29cb974fe450 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -33,9 +33,7 @@ pub mod metadata; pub use balanced::{Balanced, Unbalanced}; mod imbalance; pub use imbalance::{CreditOf, DebtOf, HandleImbalanceDrop, Imbalance}; -mod lockable; pub mod roles; -pub use lockable::{LockIdentifier, Lockable}; /// Trait for providing balance-inspection access to a set of named fungible assets. pub trait Inspect { diff --git a/frame/support/src/traits/tokens/fungibles/lockable.rs b/frame/support/src/traits/tokens/fungibles/lockable.rs deleted file mode 100644 index 185b40eae9b28..0000000000000 --- a/frame/support/src/traits/tokens/fungibles/lockable.rs +++ /dev/null @@ -1,65 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The Lockable trait and some associated types. - -use super::{super::misc::WithdrawReasons, currency::Currency}; -use crate::traits::misc::Get; - -/// An identifier for a lock. Used for disambiguating different locks so that -/// they can be individually replaced or removed. -pub type LockIdentifier = [u8; 8]; - -/// A currency whose accounts can have liquidity restrictions. -pub trait Lockable: Currency { - /// The quantity used to denote time; usually just a `BlockNumber`. - type Moment; - - /// The maximum number of locks a user should have on their account. - type MaxLocks: Get; - - /// Create a new balance lock on account `who`. - /// - /// If the new lock is valid (i.e. not already expired), it will push the struct to - /// the `Locks` vec in storage. Note that you can lock more funds than a user has. - /// - /// If the lock `id` already exists, this will update it. - fn set_lock( - id: LockIdentifier, - who: &AccountId, - amount: Self::Balance, - reasons: WithdrawReasons, - ); - - /// Changes a balance lock (selected by `id`) so that it becomes less liquid in all - /// parameters or creates a new one if it does not exist. - /// - /// Calling `extend_lock` on an existing lock `id` differs from `set_lock` in that it - /// applies the most severe constraints of the two, while `set_lock` replaces the lock - /// with the new parameters. As in, `extend_lock` will set: - /// - maximum `amount` - /// - bitwise mask of all `reasons` - fn extend_lock( - id: LockIdentifier, - who: &AccountId, - amount: Self::Balance, - reasons: WithdrawReasons, - ); - - /// Remove an existing lock. - fn remove_lock(id: LockIdentifier, who: &AccountId); -} diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 226f539a740f8..a92f94baf6cf9 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -62,7 +62,7 @@ use frame_support::{ ensure, storage::bounded_vec::BoundedVec, traits::{ - fungibles, fungibles::Lockable, Currency, ExistenceRequirement, Get, VestingSchedule, + Currency, ExistenceRequirement, Get, LockIdentifier, LockableCurrency, VestingSchedule, WithdrawReasons, }, weights::Weight, @@ -83,12 +83,11 @@ pub use weights::WeightInfo; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -type MaxLocksOf = <::Currency as fungibles::Lockable< - ::AccountId, ->>::MaxLocks; +type MaxLocksOf = + <::Currency as LockableCurrency<::AccountId>>::MaxLocks; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -const VESTING_ID: fungibles::LockIdentifier = *b"vesting "; +const VESTING_ID: LockIdentifier = *b"vesting "; // A value placed in storage that represents the current version of the Vesting storage. // This value is used by `on_runtime_upgrade` to determine whether we run storage migration logic. @@ -160,7 +159,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The currency trait. - type Currency: fungibles::Lockable; + type Currency: LockableCurrency; /// Convert the block number into a balance. type BlockNumberToBalance: Convert>; From 90ab4fafa0982ad71cecf451e5719a53346fcd32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 9 Dec 2022 11:31:57 +0100 Subject: [PATCH 1455/1472] Don't indefinitely block on shutting down Tokio (#12885) * Don't indefinitely on shutting down Tokio Now we wait in maximum 60 seconds before we shutdown the node. Tasks are may be leaked and leading to some data corruption. * Drink less :thinking_face: --- client/cli/src/runner.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index f6edd8444735a..c976c319708c2 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -22,7 +22,7 @@ use futures::{future, future::FutureExt, pin_mut, select, Future}; use log::info; use sc_service::{Configuration, Error as ServiceError, TaskManager}; use sc_utils::metrics::{TOKIO_THREADS_ALIVE, TOKIO_THREADS_TOTAL}; -use std::marker::PhantomData; +use std::{marker::PhantomData, time::Duration}; #[cfg(target_family = "unix")] async fn main(func: F) -> std::result::Result<(), E> @@ -147,7 +147,11 @@ impl Runner { self.print_node_infos(); let mut task_manager = self.tokio_runtime.block_on(initialize(self.config))?; let res = self.tokio_runtime.block_on(main(task_manager.future().fuse())); - Ok(res?) + + // Give all futures 60 seconds to shutdown, before tokio "leaks" them. + self.tokio_runtime.shutdown_timeout(Duration::from_secs(60)); + + res.map_err(Into::into) } /// A helper function that runs a command with the configuration of this node. From 47bd959c1ee12e2083feb38bf118fa906ff6fea5 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 9 Dec 2022 10:38:24 +0000 Subject: [PATCH 1456/1472] General Message Queue Pallet (#12485) * The message queue * Make fully generic * Refactor * Docs * Refactor * Use iter not slice * Per-origin queues * Multi-queue processing * Introduce MaxReady * Remove MaxReady in favour of ready ring * Cleanups * ReadyRing and tests * Stale page reaping * from_components -> from_parts Signed-off-by: Oliver Tale-Yazdi * Move WeightCounter to sp_weights Signed-off-by: Oliver Tale-Yazdi * Add MockedWeightInfo Signed-off-by: Oliver Tale-Yazdi * Deploy to kitchensink Signed-off-by: Oliver Tale-Yazdi * Use WeightCounter Signed-off-by: Oliver Tale-Yazdi * Small fixes and logging Signed-off-by: Oliver Tale-Yazdi * Add service_page Signed-off-by: Oliver Tale-Yazdi * Typo Signed-off-by: Oliver Tale-Yazdi * Move service_page below service_queue Signed-off-by: Oliver Tale-Yazdi * Add service_message Signed-off-by: Oliver Tale-Yazdi * Use correct weight function Signed-off-by: Oliver Tale-Yazdi * Overweight execution * Refactor * Missing file * Fix WeightCounter usage in scheduler Signed-off-by: Oliver Tale-Yazdi * Fix peek_index Take into account that decoding from a mutable slice modifies it. Signed-off-by: Oliver Tale-Yazdi * Add tests and bench service_page_item Signed-off-by: Oliver Tale-Yazdi * Add debug_info Signed-off-by: Oliver Tale-Yazdi * Add no-progress check to service_queues Signed-off-by: Oliver Tale-Yazdi * Add more benches Signed-off-by: Oliver Tale-Yazdi * Bound from_message and try_append_message Signed-off-by: Oliver Tale-Yazdi * Add PageReaped event Signed-off-by: Oliver Tale-Yazdi * Rename BookStateOf and BookStateFor Signed-off-by: Oliver Tale-Yazdi * Update tests and remove logging Signed-off-by: Oliver Tale-Yazdi * Remove redundant per-message origins; add footprint() and sweep_queue() * Move testing stuff to mock.rs Signed-off-by: Oliver Tale-Yazdi * Add integration test Signed-off-by: Oliver Tale-Yazdi * Fix no-progress check Signed-off-by: Oliver Tale-Yazdi * Fix debug_info Signed-off-by: Oliver Tale-Yazdi * Fixup merge and tests Signed-off-by: Oliver Tale-Yazdi * Fix footprint tracking * Introduce * Formatting * OverweightEnqueued event, auto-servicing config item * Update tests and benchmarks Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * Add tests Signed-off-by: Oliver Tale-Yazdi * Provide change handler * Add missing BookStateFor::insert and call QueueChangeHandler Signed-off-by: Oliver Tale-Yazdi * Docs Signed-off-by: Oliver Tale-Yazdi * Update benchmarks and weights Signed-off-by: Oliver Tale-Yazdi * More tests... Signed-off-by: Oliver Tale-Yazdi * Use weight metering functions Signed-off-by: Oliver Tale-Yazdi * weightInfo::process_message_payload is gone Signed-off-by: Oliver Tale-Yazdi * Add defensive_saturating_accrue Signed-off-by: Oliver Tale-Yazdi * Rename WeightCounter to WeightMeter Ctr+Shift+H should do the trick. Signed-off-by: Oliver Tale-Yazdi * Test on_initialize Signed-off-by: Oliver Tale-Yazdi * Add module docs Signed-off-by: Oliver Tale-Yazdi * Remove origin from MaxMessageLen The message origin is not encoded into the heap and does therefore not influence the max message length anymore. Signed-off-by: Oliver Tale-Yazdi * Add BoundedVec::as_slice Signed-off-by: Oliver Tale-Yazdi * Test Page::{from_message, try_append_message} Signed-off-by: Oliver Tale-Yazdi * Fixup docs Signed-off-by: Oliver Tale-Yazdi * Docs * Do nothing in sweep_queue if the queue does not exist ... otherwise it inserts default values into the storage. Signed-off-by: Oliver Tale-Yazdi * Test ring (un)knitting Signed-off-by: Oliver Tale-Yazdi * Upgrade stress-test Change the test to not assume that all queued messages will be processed in the next block but split it over multiple. Signed-off-by: Oliver Tale-Yazdi * More tests... Signed-off-by: Oliver Tale-Yazdi * Beauty fixes Signed-off-by: Oliver Tale-Yazdi * clippy Signed-off-by: Oliver Tale-Yazdi * Rename BoundedVec::as_slice to as_bounded_slice Conflicts with deref().as_slice() otherwise. Signed-off-by: Oliver Tale-Yazdi * Fix imports Signed-off-by: Oliver Tale-Yazdi * Remove ReadyRing struct Was used for testing only. Instead use 'fn assert_ring' which also check the service head and backlinks. Signed-off-by: Oliver Tale-Yazdi * Beauty fixes Signed-off-by: Oliver Tale-Yazdi * Fix stale page watermark Signed-off-by: Oliver Tale-Yazdi * Cleanup Signed-off-by: Oliver Tale-Yazdi * Fix test feature and clippy Signed-off-by: Oliver Tale-Yazdi * QueueChanged handler is called correctly Signed-off-by: Oliver Tale-Yazdi * Update benches Signed-off-by: Oliver Tale-Yazdi * Abstract testing functions Signed-off-by: Oliver Tale-Yazdi * More tests Signed-off-by: Oliver Tale-Yazdi * Cleanup Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Simplify tests Signed-off-by: Oliver Tale-Yazdi * Make stuff compile Signed-off-by: Oliver Tale-Yazdi * Extend overweight execution benchmark Signed-off-by: Oliver Tale-Yazdi * Remove TODOs Signed-off-by: Oliver Tale-Yazdi * Test service queue with faulty MessageProcessor Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Update pallet ui tests to 1.65 Signed-off-by: Oliver Tale-Yazdi * More docs Signed-off-by: Oliver Tale-Yazdi * Review doc fixes Co-authored-by: Robert Klotzner Signed-off-by: Oliver Tale-Yazdi * Add weight_limit to extrinsic weight of execute_overweight * Correctly return unused weight * Return actual weight consumed in do_execute_overweight * Review fixes Signed-off-by: Oliver Tale-Yazdi * Set version 7.0.0-dev Signed-off-by: Oliver Tale-Yazdi * Make it compile Signed-off-by: Oliver Tale-Yazdi * Switch message_size to u64 Signed-off-by: Oliver Tale-Yazdi * Switch message_count to u64 Signed-off-by: Oliver Tale-Yazdi * Fix benchmarks Signed-off-by: Oliver Tale-Yazdi * Make CI green Signed-off-by: Oliver Tale-Yazdi * Docs * Update tests Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/bench-bot.sh" pallet dev pallet_message_queue * Dont mention README.md in the Cargo.toml Signed-off-by: Oliver Tale-Yazdi * Remove reference to readme Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> Co-authored-by: Robert Klotzner Co-authored-by: Keith Yeung --- Cargo.lock | 40 +- Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 21 + frame/message-queue/Cargo.toml | 53 + frame/message-queue/src/benchmarking.rs | 204 +++ frame/message-queue/src/integration_test.rs | 224 +++ frame/message-queue/src/lib.rs | 1308 +++++++++++++++++ frame/message-queue/src/mock.rs | 312 ++++ frame/message-queue/src/mock_helpers.rs | 185 +++ frame/message-queue/src/tests.rs | 1092 ++++++++++++++ frame/message-queue/src/weights.rs | 216 +++ frame/scheduler/Cargo.toml | 2 + frame/scheduler/src/lib.rs | 3 +- frame/support/src/traits.rs | 6 + frame/support/src/traits/messages.rs | 202 +++ ...age_ensure_span_are_ok_on_wrong_gen.stderr | 6 +- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 6 +- primitives/core/src/bounded/bounded_vec.rs | 7 + primitives/weights/src/weight_meter.rs | 6 + 20 files changed, 3883 insertions(+), 15 deletions(-) create mode 100644 frame/message-queue/Cargo.toml create mode 100644 frame/message-queue/src/benchmarking.rs create mode 100644 frame/message-queue/src/integration_test.rs create mode 100644 frame/message-queue/src/lib.rs create mode 100644 frame/message-queue/src/mock.rs create mode 100644 frame/message-queue/src/mock_helpers.rs create mode 100644 frame/message-queue/src/tests.rs create mode 100644 frame/message-queue/src/weights.rs create mode 100644 frame/support/src/traits/messages.rs diff --git a/Cargo.lock b/Cargo.lock index 73effefc48da1..41c641cf05963 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3117,6 +3117,7 @@ dependencies = [ "pallet-indices", "pallet-lottery", "pallet-membership", + "pallet-message-queue", "pallet-mmr", "pallet-multisig", "pallet-nis", @@ -5322,6 +5323,28 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-message-queue" +version = "7.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "rand 0.8.5", + "rand_distr", + "scale-info", + "serde", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-tracing", + "sp-weights", +] + [[package]] name = "pallet-mmr" version = "4.0.0-dev" @@ -5709,6 +5732,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "sp-weights", "substrate-test-utils", ] @@ -8397,9 +8421,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8980cafbe98a7ee7a9cc16b32ebce542c77883f512d83fbf2ddc8f6a85ea74c9" +checksum = "333af15b02563b8182cd863f925bd31ef8fa86a0e095d30c091956057d436153" dependencies = [ "bitvec", "cfg-if", @@ -8411,9 +8435,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4260c630e8a8a33429d1688eff2f163f24c65a4e1b1578ef6b565061336e4b6f" +checksum = "53f56acbd0743d29ffa08f911ab5397def774ad01bab3786804cf6ee057fb5e1" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -8570,9 +8594,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] @@ -8589,9 +8613,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 12f2ced0d1d03..eb78d5e104486 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -121,6 +121,7 @@ members = [ "frame/offences/benchmarking", "frame/preimage", "frame/proxy", + "frame/message-queue", "frame/nomination-pools", "frame/nomination-pools/fuzzer", "frame/nomination-pools/benchmarking", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 02a2ae292d83e..477545c9ac332 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -75,6 +75,7 @@ pallet-indices = { version = "4.0.0-dev", default-features = false, path = "../. pallet-identity = { version = "4.0.0-dev", default-features = false, path = "../../../frame/identity" } pallet-lottery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/lottery" } pallet-membership = { version = "4.0.0-dev", default-features = false, path = "../../../frame/membership" } +pallet-message-queue = { version = "7.0.0-dev", default-features = false, path = "../../../frame/message-queue" } pallet-mmr = { version = "4.0.0-dev", default-features = false, path = "../../../frame/merkle-mountain-range" } pallet-multisig = { version = "4.0.0-dev", default-features = false, path = "../../../frame/multisig" } pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../../../frame/nomination-pools"} @@ -150,6 +151,7 @@ std = [ "sp-inherents/std", "pallet-lottery/std", "pallet-membership/std", + "pallet-message-queue/std", "pallet-mmr/std", "pallet-multisig/std", "pallet-nomination-pools/std", @@ -229,6 +231,7 @@ runtime-benchmarks = [ "pallet-indices/runtime-benchmarks", "pallet-lottery/runtime-benchmarks", "pallet-membership/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nomination-pools-benchmarking/runtime-benchmarks", @@ -282,6 +285,7 @@ try-runtime = [ "pallet-identity/try-runtime", "pallet-lottery/try-runtime", "pallet-membership/try-runtime", + "pallet-message-queue/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", "pallet-nomination-pools/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1bb4dd6f913a6..7cd42be73a19b 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1135,6 +1135,25 @@ impl pallet_bounties::Config for Runtime { type ChildBountyManager = ChildBounties; } +parameter_types! { + /// Allocate at most 20% of each block for message processing. + /// + /// Is set to 20% since the scheduler can already consume a maximum of 80%. + pub MessageQueueServiceWeight: Option = Some(Perbill::from_percent(20) * RuntimeBlockWeights::get().max_block); +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + /// NOTE: Always set this to `NoopMessageProcessor` for benchmarking. + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor; + type Size = u32; + type QueueChangeHandler = (); + type HeapSize = ConstU32<{ 64 * 1024 }>; + type MaxStale = ConstU32<128>; + type ServiceWeight = MessageQueueServiceWeight; +} + parameter_types! { pub const ChildBountyValueMinimum: Balance = 1 * DOLLARS; } @@ -1699,6 +1718,7 @@ construct_runtime!( RankedPolls: pallet_referenda::, RankedCollective: pallet_ranked_collective, FastUnstake: pallet_fast_unstake, + MessageQueue: pallet_message_queue, } ); @@ -1793,6 +1813,7 @@ mod benches { [pallet_indices, Indices] [pallet_lottery, Lottery] [pallet_membership, TechnicalMembership] + [pallet_message_queue, MessageQueue] [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] diff --git a/frame/message-queue/Cargo.toml b/frame/message-queue/Cargo.toml new file mode 100644 index 0000000000000..47d114902f52c --- /dev/null +++ b/frame/message-queue/Cargo.toml @@ -0,0 +1,53 @@ +[package] +authors = ["Parity Technologies "] +edition = "2021" +name = "pallet-message-queue" +version = "7.0.0-dev" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet to queue and process messages" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } +serde = { version = "1.0.137", optional = true, features = ["derive"] } +log = { version = "0.4.17", default-features = false } + +sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } + +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } + +[dev-dependencies] +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } +rand = "0.8.5" +rand_distr = "0.4.3" + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "sp-arithmetic/std", + "sp-weights/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/message-queue/src/benchmarking.rs b/frame/message-queue/src/benchmarking.rs new file mode 100644 index 0000000000000..c0ff20431d00e --- /dev/null +++ b/frame/message-queue/src/benchmarking.rs @@ -0,0 +1,204 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Benchmarking for the message queue pallet. + +#![cfg(feature = "runtime-benchmarks")] +#![allow(unused_assignments)] // Needed for `ready_ring_knit`. + +use super::{mock_helpers::*, Pallet as MessageQueue, *}; + +use frame_benchmarking::{benchmarks, whitelisted_caller}; +use frame_support::traits::Get; +use frame_system::RawOrigin; +use sp_std::prelude::*; + +benchmarks! { + where_clause { + where + // NOTE: We need to generate multiple origins, therefore Origin is `From`. The + // `PartialEq` is for asserting the outcome of the ring (un)knitting and *could* be + // removed if really necessary. + <::MessageProcessor as ProcessMessage>::Origin: From + PartialEq, + ::Size: From, + } + + // Worst case path of `ready_ring_knit`. + ready_ring_knit { + let mid: MessageOriginOf:: = 1.into(); + build_ring::(&[0.into(), mid.clone(), 2.into()]); + unknit::(&mid); + assert_ring::(&[0.into(), 2.into()]); + let mut neighbours = None; + }: { + neighbours = MessageQueue::::ready_ring_knit(&mid).ok(); + } verify { + // The neighbours needs to be modified manually. + BookStateFor::::mutate(&mid, |b| { b.ready_neighbours = neighbours }); + assert_ring::(&[0.into(), 2.into(), mid]); + } + + // Worst case path of `ready_ring_unknit`. + ready_ring_unknit { + build_ring::(&[0.into(), 1.into(), 2.into()]); + assert_ring::(&[0.into(), 1.into(), 2.into()]); + let o: MessageOriginOf:: = 0.into(); + let neighbours = BookStateFor::::get(&o).ready_neighbours.unwrap(); + }: { + MessageQueue::::ready_ring_unknit(&o, neighbours); + } verify { + assert_ring::(&[1.into(), 2.into()]); + } + + // `service_queues` without any queue processing. + service_queue_base { + }: { + MessageQueue::::service_queue(0.into(), &mut WeightMeter::max_limit(), Weight::MAX) + } + + // `service_page` without any message processing but with page completion. + service_page_base_completion { + let origin: MessageOriginOf = 0.into(); + let page = PageOf::::default(); + Pages::::insert(&origin, 0, &page); + let mut book_state = single_page_book::(); + let mut meter = WeightMeter::max_limit(); + let limit = Weight::MAX; + }: { + MessageQueue::::service_page(&origin, &mut book_state, &mut meter, limit) + } + + // `service_page` without any message processing and without page completion. + service_page_base_no_completion { + let origin: MessageOriginOf = 0.into(); + let mut page = PageOf::::default(); + // Mock the storage such that `is_complete` returns `false` but `peek_first` returns `None`. + page.first = 1.into(); + page.remaining = 1.into(); + Pages::::insert(&origin, 0, &page); + let mut book_state = single_page_book::(); + let mut meter = WeightMeter::max_limit(); + let limit = Weight::MAX; + }: { + MessageQueue::::service_page(&origin, &mut book_state, &mut meter, limit) + } + + // Processing a single message from a page. + service_page_item { + let msg = vec![1u8; MaxMessageLenOf::::get() as usize]; + let mut page = page::(&msg.clone()); + let mut book = book_for::(&page); + assert!(page.peek_first().is_some(), "There is one message"); + let mut weight = WeightMeter::max_limit(); + }: { + let status = MessageQueue::::service_page_item(&0u32.into(), 0, &mut book, &mut page, &mut weight, Weight::MAX); + assert_eq!(status, ItemExecutionStatus::Executed(true)); + } verify { + // Check that it was processed. + assert_last_event::(Event::Processed { + hash: T::Hashing::hash(&msg), origin: 0.into(), + weight_used: 1.into_weight(), success: true + }.into()); + let (_, processed, _) = page.peek_index(0).unwrap(); + assert!(processed); + assert_eq!(book.message_count, 0); + } + + // Worst case for calling `bump_service_head`. + bump_service_head { + setup_bump_service_head::(0.into(), 10.into()); + let mut weight = WeightMeter::max_limit(); + }: { + MessageQueue::::bump_service_head(&mut weight); + } verify { + assert_eq!(ServiceHead::::get().unwrap(), 10u32.into()); + assert_eq!(weight.consumed, T::WeightInfo::bump_service_head()); + } + + reap_page { + // Mock the storage to get a *cullable* but not *reapable* page. + let origin: MessageOriginOf = 0.into(); + let mut book = single_page_book::(); + let (page, msgs) = full_page::(); + + for p in 0 .. T::MaxStale::get() * T::MaxStale::get() { + if p == 0 { + Pages::::insert(&origin, p, &page); + } + book.end += 1; + book.count += 1; + book.message_count += msgs as u64; + book.size += page.remaining_size.into() as u64; + } + book.begin = book.end - T::MaxStale::get(); + BookStateFor::::insert(&origin, &book); + assert!(Pages::::contains_key(&origin, 0)); + + }: _(RawOrigin::Signed(whitelisted_caller()), 0u32.into(), 0) + verify { + assert_last_event::(Event::PageReaped{ origin: 0.into(), index: 0 }.into()); + assert!(!Pages::::contains_key(&origin, 0)); + } + + // Worst case for `execute_overweight` where the page is removed as completed. + // + // The worst case occurs when executing the last message in a page of which all are skipped since it is using `peek_index` which has linear complexities. + execute_overweight_page_removed { + let origin: MessageOriginOf = 0.into(); + let (mut page, msgs) = full_page::(); + // Skip all messages. + for _ in 1..msgs { + page.skip_first(true); + } + page.skip_first(false); + let book = book_for::(&page); + Pages::::insert(&origin, 0, &page); + BookStateFor::::insert(&origin, &book); + }: { + MessageQueue::::execute_overweight(RawOrigin::Signed(whitelisted_caller()).into(), 0u32.into(), 0u32, ((msgs - 1) as u32).into(), Weight::MAX).unwrap() + } + verify { + assert_last_event::(Event::Processed { + hash: T::Hashing::hash(&((msgs - 1) as u32).encode()), origin: 0.into(), + weight_used: Weight::from_parts(1, 1), success: true + }.into()); + assert!(!Pages::::contains_key(&origin, 0), "Page must be removed"); + } + + // Worst case for `execute_overweight` where the page is updated. + execute_overweight_page_updated { + let origin: MessageOriginOf = 0.into(); + let (mut page, msgs) = full_page::(); + // Skip all messages. + for _ in 0..msgs { + page.skip_first(false); + } + let book = book_for::(&page); + Pages::::insert(&origin, 0, &page); + BookStateFor::::insert(&origin, &book); + }: { + MessageQueue::::execute_overweight(RawOrigin::Signed(whitelisted_caller()).into(), 0u32.into(), 0u32, ((msgs - 1) as u32).into(), Weight::MAX).unwrap() + } + verify { + assert_last_event::(Event::Processed { + hash: T::Hashing::hash(&((msgs - 1) as u32).encode()), origin: 0.into(), + weight_used: Weight::from_parts(1, 1), success: true + }.into()); + assert!(Pages::::contains_key(&origin, 0), "Page must be updated"); + } + + impl_benchmark_test_suite!(MessageQueue, crate::mock::new_test_ext::(), crate::integration_test::Test); +} diff --git a/frame/message-queue/src/integration_test.rs b/frame/message-queue/src/integration_test.rs new file mode 100644 index 0000000000000..a9b6ee9bd2214 --- /dev/null +++ b/frame/message-queue/src/integration_test.rs @@ -0,0 +1,224 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Stress tests pallet-message-queue. Defines its own runtime config to use larger constants for +//! `HeapSize` and `MaxStale`. + +#![cfg(test)] + +use crate::{ + mock::{ + new_test_ext, CountingMessageProcessor, IntoWeight, MockedWeightInfo, NumMessagesProcessed, + }, + *, +}; + +use crate as pallet_message_queue; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, +}; +use rand::{rngs::StdRng, Rng, SeedableRng}; +use rand_distr::Pareto; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event}, + } +); + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); +} +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type RuntimeCall = RuntimeCall; + type Hashing = BlakeTwo256; + type AccountId = u64; + 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 SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +parameter_types! { + pub const HeapSize: u32 = 32 * 1024; + pub const MaxStale: u32 = 32; + pub static ServiceWeight: Option = Some(Weight::from_parts(100, 100)); +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = MockedWeightInfo; + type MessageProcessor = CountingMessageProcessor; + type Size = u32; + type QueueChangeHandler = (); + type HeapSize = HeapSize; + type MaxStale = MaxStale; + type ServiceWeight = ServiceWeight; +} + +/// Simulates heavy usage by enqueueing and processing large amounts of messages. +/// +/// Best to run with `-r`, `RUST_LOG=info` and `RUSTFLAGS='-Cdebug-assertions=y'`. +/// +/// # Example output +/// +/// ```pre +/// Enqueued 1189 messages across 176 queues. Payload 46.97 KiB +/// Processing 772 of 1189 messages +/// Enqueued 9270 messages across 1559 queues. Payload 131.85 KiB +/// Processing 6262 of 9687 messages +/// Enqueued 5025 messages across 1225 queues. Payload 100.23 KiB +/// Processing 1739 of 8450 messages +/// Enqueued 42061 messages across 6357 queues. Payload 536.29 KiB +/// Processing 11675 of 48772 messages +/// Enqueued 20253 messages across 2420 queues. Payload 288.34 KiB +/// Processing 28711 of 57350 messages +/// Processing all remaining 28639 messages +/// ``` +#[test] +#[ignore] // Only run in the CI. +fn stress_test_enqueue_and_service() { + let blocks = 20; + let max_queues = 10_000; + let max_messages_per_queue = 10_000; + let max_msg_len = MaxMessageLenOf::::get(); + let mut rng = StdRng::seed_from_u64(42); + + new_test_ext::().execute_with(|| { + let mut msgs_remaining = 0; + for _ in 0..blocks { + // Start by enqueuing a large number of messages. + let (enqueued, _) = + enqueue_messages(max_queues, max_messages_per_queue, max_msg_len, &mut rng); + msgs_remaining += enqueued; + + // Pick a fraction of all messages currently in queue and process them. + let processed = rng.gen_range(1..=msgs_remaining); + log::info!("Processing {} of all messages {}", processed, msgs_remaining); + process_messages(processed); // This also advances the block. + msgs_remaining -= processed; + } + log::info!("Processing all remaining {} messages", msgs_remaining); + process_messages(msgs_remaining); + post_conditions(); + }); +} + +/// Enqueue a random number of random messages into a random number of queues. +fn enqueue_messages( + max_queues: u32, + max_per_queue: u32, + max_msg_len: u32, + rng: &mut StdRng, +) -> (u32, usize) { + let num_queues = rng.gen_range(1..max_queues); + let mut num_messages = 0; + let mut total_msg_len = 0; + for origin in 0..num_queues { + let num_messages_per_queue = + (rng.sample(Pareto::new(1.0, 1.1).unwrap()) as u32).min(max_per_queue); + + for m in 0..num_messages_per_queue { + let mut message = format!("{}:{}", &origin, &m).into_bytes(); + let msg_len = (rng.sample(Pareto::new(1.0, 1.0).unwrap()) as u32) + .clamp(message.len() as u32, max_msg_len); + message.resize(msg_len as usize, 0); + MessageQueue::enqueue_message( + BoundedSlice::defensive_truncate_from(&message), + origin.into(), + ); + total_msg_len += msg_len; + } + num_messages += num_messages_per_queue; + } + log::info!( + "Enqueued {} messages across {} queues. Payload {:.2} KiB", + num_messages, + num_queues, + total_msg_len as f64 / 1024.0 + ); + (num_messages, total_msg_len as usize) +} + +/// Process the number of messages. +fn process_messages(num_msgs: u32) { + let weight = (num_msgs as u64).into_weight(); + ServiceWeight::set(Some(weight)); + let consumed = next_block(); + + assert_eq!(consumed, weight, "\n{}", MessageQueue::debug_info()); + assert_eq!(NumMessagesProcessed::take(), num_msgs as usize); +} + +/// Returns the weight consumed by `MessageQueue::on_initialize()`. +fn next_block() -> Weight { + MessageQueue::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + MessageQueue::on_initialize(System::block_number()) +} + +/// Assert that the pallet is in the expected post state. +fn post_conditions() { + // All queues are empty. + for (_, book) in BookStateFor::::iter() { + assert!(book.end >= book.begin); + assert_eq!(book.count, 0); + assert_eq!(book.size, 0); + assert_eq!(book.message_count, 0); + assert!(book.ready_neighbours.is_none()); + } + // No pages remain. + assert_eq!(Pages::::iter().count(), 0); + // Service head is gone. + assert!(ServiceHead::::get().is_none()); + // This still works fine. + assert_eq!(MessageQueue::service_queues(Weight::MAX), Weight::zero(), "Nothing left"); + next_block(); +} diff --git a/frame/message-queue/src/lib.rs b/frame/message-queue/src/lib.rs new file mode 100644 index 0000000000000..9b976c48245c9 --- /dev/null +++ b/frame/message-queue/src/lib.rs @@ -0,0 +1,1308 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! # Generalized Message Queue Pallet +//! +//! Provides generalized message queuing and processing capabilities on a per-queue basis for +//! arbitrary use-cases. +//! +//! # Design Goals +//! +//! 1. Minimal assumptions about `Message`s and `MessageOrigin`s. Both should be MEL bounded blobs. +//! This ensures the generality and reusability of the pallet. +//! 2. Well known and tightly limited pre-dispatch PoV weights, especially for message execution. +//! This is paramount for the success of the pallet since message execution is done in +//! `on_initialize` which must _never_ under-estimate its PoV weight. It also needs a frugal PoV +//! footprint since PoV is scarce and this is (possibly) done in every block. This must also hold +//! in the presence of unpredictable message size distributions. +//! 3. Usable as XCMP, DMP and UMP message/dispatch queue - possibly through adapter types. +//! +//! # Design +//! +//! The pallet has means to enqueue, store and process messages. This is implemented by having +//! *queues* which store enqueued messages and can be *served* to process said messages. A queue is +//! identified by its origin in the `BookStateFor`. Each message has an origin which defines into +//! which queue it will be stored. Messages are stored by being appended to the last [`Page`] of a +//! book. Each book keeps track of its pages by indexing `Pages`. The `ReadyRing` contains all +//! queues which hold at least one unprocessed message and are thereby *ready* to be serviced. The +//! `ServiceHead` indicates which *ready* queue is the next to be serviced. +//! The pallet implements [`frame_support::traits::EnqueueMessage`], +//! [`frame_support::traits::ServiceQueues`] and has [`frame_support::traits::ProcessMessage`] and +//! [`OnQueueChanged`] hooks to communicate with the outside world. +//! +//! NOTE: The storage items are not linked since they are not public. +//! +//! **Message Execution** +//! +//! Executing a message is offloaded to the [`Config::MessageProcessor`] which contains the actual +//! logic of how to handle the message since they are blobs. A message can be temporarily or +//! permanently overweight. The pallet will perpetually try to execute a temporarily overweight +//! message. A permanently overweight message is skipped and must be executed manually. +//! +//! **Pagination** +//! +//! Queues are stored in a *paged* manner by splitting their messages into [`Page`]s. This results +//! in a lot of complexity when implementing the pallet but is completely necessary to archive the +//! second #[Design Goal](design-goals). The problem comes from the fact a message can *possibly* be +//! quite large, lets say 64KiB. This then results in a *MEL* of at least 64KiB which results in a +//! PoV of at least 64KiB. Now we have the assumption that most messages are much shorter than their +//! maximum allowed length. This would result in most messages having a pre-dispatch PoV size which +//! is much larger than their post-dispatch PoV size, possibly by a factor of thousand. Disregarding +//! this observation would cripple the processing power of the pallet since it cannot straighten out +//! this discrepancy at runtime. Conceptually, the implementation is packing as many messages into a +//! single bounded vec, as actually fit into the bounds. This reduces the wasted PoV. +//! +//! **Page Data Layout** +//! +//! A Page contains a heap which holds all its messages. The heap is built by concatenating +//! `(ItemHeader, Message)` pairs. The [`ItemHeader`] contains the length of the message which is +//! needed for retrieving it. This layout allows for constant access time of the next message and +//! linear access time for any message in the page. The header must remain minimal to reduce its PoV +//! impact. +//! +//! **Weight Metering** +//! +//! The pallet utilizes the [`sp_weights::WeightMeter`] to manually track its consumption to always +//! stay within the required limit. This implies that the message processor hook can calculate the +//! weight of a message without executing it. This restricts the possible use-cases but is necessary +//! since the pallet runs in `on_initialize` which has a hard weight limit. The weight meter is used +//! in a way that `can_accrue` and `check_accrue` are always used to check the remaining weight of +//! an operation before committing to it. The process of exiting due to insufficient weight is +//! termed "bailing". +//! +//! # Scenario: Message enqueuing +//! +//! A message `m` is enqueued for origin `o` into queue `Q[o]` through +//! [`frame_support::traits::EnqueueMessage::enqueue_message`]`(m, o)`. +//! +//! First the queue is either loaded if it exists or otherwise created with empty default values. +//! The message is then inserted to the queue by appended it into its last `Page` or by creating a +//! new `Page` just for `m` if it does not fit in there. The number of messages in the `Book` is +//! incremented. +//! +//! `Q[o]` is now *ready* which will eventually result in `m` being processed. +//! +//! # Scenario: Message processing +//! +//! The pallet runs each block in `on_initialize` or when being manually called through +//! [`frame_support::traits::ServiceQueues::service_queues`]. +//! +//! First it tries to "rotate" the `ReadyRing` by one through advancing the `ServiceHead` to the +//! next *ready* queue. It then starts to service this queue by servicing as many pages of it as +//! possible. Servicing a page means to execute as many message of it as possible. Each executed +//! message is marked as *processed* if the [`Config::MessageProcessor`] return Ok. An event +//! [`Event::Processed`] is emitted afterwards. It is possible that the weight limit of the pallet +//! will never allow a specific message to be executed. In this case it remains as unprocessed and +//! is skipped. This process stops if either there are no more messages in the queue or the +//! remaining weight became insufficient to service this queue. If there is enough weight it tries +//! to advance to the next *ready* queue and service it. This continues until there are no more +//! queues on which it can make progress or not enough weight to check that. +//! +//! # Scenario: Overweight execution +//! +//! A permanently over-weight message which was skipped by the message processing will never be +//! executed automatically through `on_initialize` nor by calling +//! [`frame_support::traits::ServiceQueues::service_queues`]. +//! +//! Manual intervention in the form of +//! [`frame_support::traits::ServiceQueues::execute_overweight`] is necessary. Overweight messages +//! emit an [`Event::OverweightEnqueued`] event which can be used to extract the arguments for +//! manual execution. This only works on permanently overweight messages. There is no guarantee that +//! this will work since the message could be part of a stale page and be reaped before execution +//! commences. +//! +//! # Terminology +//! +//! - `Message`: A blob of data into which the pallet has no introspection, defined as +//! [`BoundedSlice>`]. The message length is limited by [`MaxMessageLenOf`] +//! which is calculated from [`Config::HeapSize`] and [`ItemHeader::max_encoded_len()`]. +//! - `MessageOrigin`: A generic *origin* of a message, defined as [`MessageOriginOf`]. The +//! requirements for it are kept minimal to remain as generic as possible. The type is defined in +//! [`frame_support::traits::ProcessMessage::Origin`]. +//! - `Page`: An array of `Message`s, see [`Page`]. Can never be empty. +//! - `Book`: A list of `Page`s, see [`BookState`]. Can be empty. +//! - `Queue`: A `Book` together with an `MessageOrigin` which can be part of the `ReadyRing`. Can +//! be empty. +//! - `ReadyRing`: A double-linked list which contains all *ready* `Queue`s. It chains together the +//! queues via their `ready_neighbours` fields. A `Queue` is *ready* if it contains at least one +//! `Message` which can be processed. Can be empty. +//! - `ServiceHead`: A pointer into the `ReadyRing` to the next `Queue` to be serviced. +//! - (`un`)`processed`: A message is marked as *processed* after it was executed by the pallet. A +//! message which was either: not yet executed or could not be executed remains as `unprocessed` +//! which is the default state for a message after being enqueued. +//! - `knitting`/`unknitting`: The means of adding or removing a `Queue` from the `ReadyRing`. +//! - `MEL`: The Max Encoded Length of a type, see [`codec::MaxEncodedLen`]. +//! +//! # Properties +//! +//! **Liveness - Enqueueing** +//! +//! It is always possible to enqueue any message for any `MessageOrigin`. +//! +//! **Liveness - Processing** +//! +//! `on_initialize` always respects its finite weight-limit. +//! +//! **Progress - Enqueueing** +//! +//! An enqueued message immediately becomes *unprocessed* and thereby eligible for execution. +//! +//! **Progress - Processing** +//! +//! The pallet will execute at least one unprocessed message per block, if there is any. Ensuring +//! this property needs careful consideration of the concrete weights, since it is possible that the +//! weight limit of `on_initialize` never allows for the execution of even one message; trivially if +//! the limit is set to zero. `integrity_test` can be used to ensure that this property holds. +//! +//! **Fairness - Enqueuing** +//! +//! Enqueueing a message for a specific `MessageOrigin` does not influence the ability to enqueue a +//! message for the same of any other `MessageOrigin`; guaranteed by **Liveness - Enqueueing**. +//! +//! **Fairness - Processing** +//! +//! The average amount of weight available for message processing is the same for each queue if the +//! number of queues is constant. Creating a new queue must therefore be, possibly economically, +//! expensive. Currently this is archived by having one queue per para-chain/thread, which keeps the +//! number of queues within `O(n)` and should be "good enough". + +#![cfg_attr(not(feature = "std"), no_std)] + +mod benchmarking; +mod integration_test; +mod mock; +pub mod mock_helpers; +mod tests; +pub mod weights; + +use codec::{Codec, Decode, Encode, MaxEncodedLen}; +use frame_support::{ + defensive, + pallet_prelude::*, + traits::{ + DefensiveTruncateFrom, EnqueueMessage, ExecuteOverweightError, Footprint, ProcessMessage, + ProcessMessageError, ServiceQueues, + }, + BoundedSlice, CloneNoBound, DefaultNoBound, +}; +use frame_system::pallet_prelude::*; +pub use pallet::*; +use scale_info::TypeInfo; +use sp_arithmetic::traits::{BaseArithmetic, Unsigned}; +use sp_runtime::{ + traits::{Hash, One, Zero}, + SaturatedConversion, Saturating, +}; +use sp_std::{fmt::Debug, ops::Deref, prelude::*, vec}; +use sp_weights::WeightMeter; +pub use weights::WeightInfo; + +/// Type for identifying a page. +type PageIndex = u32; + +/// Data encoded and prefixed to the encoded `MessageItem`. +#[derive(Encode, Decode, PartialEq, MaxEncodedLen, Debug)] +pub struct ItemHeader { + /// The length of this item, not including the size of this header. The next item of the page + /// follows immediately after the payload of this item. + payload_len: Size, + /// Whether this item has been processed. + is_processed: bool, +} + +/// A page of messages. Pages always contain at least one item. +#[derive( + CloneNoBound, Encode, Decode, RuntimeDebugNoBound, DefaultNoBound, TypeInfo, MaxEncodedLen, +)] +#[scale_info(skip_type_params(HeapSize))] +#[codec(mel_bound(Size: MaxEncodedLen))] +pub struct Page + Debug + Clone + Default, HeapSize: Get> { + /// Messages remaining to be processed; this includes overweight messages which have been + /// skipped. + remaining: Size, + /// The size of all remaining messages to be processed. + /// + /// Includes overweight messages outside of the `first` to `last` window. + remaining_size: Size, + /// The number of items before the `first` item in this page. + first_index: Size, + /// The heap-offset of the header of the first message item in this page which is ready for + /// processing. + first: Size, + /// The heap-offset of the header of the last message item in this page. + last: Size, + /// The heap. If `self.offset == self.heap.len()` then the page is empty and should be deleted. + heap: BoundedVec>, +} + +impl< + Size: BaseArithmetic + Unsigned + Copy + Into + Codec + MaxEncodedLen + Debug + Default, + HeapSize: Get, + > Page +{ + /// Create a [`Page`] from one unprocessed message. + fn from_message(message: BoundedSlice>) -> Self { + let payload_len = message.len(); + let data_len = ItemHeader::::max_encoded_len().saturating_add(payload_len); + let payload_len = payload_len.saturated_into(); + let header = ItemHeader:: { payload_len, is_processed: false }; + + let mut heap = Vec::with_capacity(data_len); + header.using_encoded(|h| heap.extend_from_slice(h)); + heap.extend_from_slice(message.deref()); + + Page { + remaining: One::one(), + remaining_size: payload_len, + first_index: Zero::zero(), + first: Zero::zero(), + last: Zero::zero(), + heap: BoundedVec::defensive_truncate_from(heap), + } + } + + /// Try to append one message to a page. + fn try_append_message( + &mut self, + message: BoundedSlice>, + ) -> Result<(), ()> { + let pos = self.heap.len(); + let payload_len = message.len(); + let data_len = ItemHeader::::max_encoded_len().saturating_add(payload_len); + let payload_len = payload_len.saturated_into(); + let header = ItemHeader:: { payload_len, is_processed: false }; + let heap_size: u32 = HeapSize::get().into(); + if (heap_size as usize).saturating_sub(self.heap.len()) < data_len { + // Can't fit. + return Err(()) + } + + let mut heap = sp_std::mem::take(&mut self.heap).into_inner(); + header.using_encoded(|h| heap.extend_from_slice(h)); + heap.extend_from_slice(message.deref()); + self.heap = BoundedVec::defensive_truncate_from(heap); + self.last = pos.saturated_into(); + self.remaining.saturating_inc(); + self.remaining_size.saturating_accrue(payload_len); + Ok(()) + } + + /// Returns the first message in the page without removing it. + /// + /// SAFETY: Does not panic even on corrupted storage. + fn peek_first(&self) -> Option>> { + if self.first > self.last { + return None + } + let f = (self.first.into() as usize).min(self.heap.len()); + let mut item_slice = &self.heap[f..]; + if let Ok(h) = ItemHeader::::decode(&mut item_slice) { + let payload_len = h.payload_len.into() as usize; + if payload_len <= item_slice.len() { + // impossible to truncate since is sliced up from `self.heap: BoundedVec` + return Some(BoundedSlice::defensive_truncate_from(&item_slice[..payload_len])) + } + } + defensive!("message-queue: heap corruption"); + None + } + + /// Point `first` at the next message, marking the first as processed if `is_processed` is true. + fn skip_first(&mut self, is_processed: bool) { + let f = (self.first.into() as usize).min(self.heap.len()); + if let Ok(mut h) = ItemHeader::decode(&mut &self.heap[f..]) { + if is_processed && !h.is_processed { + h.is_processed = true; + h.using_encoded(|d| self.heap[f..f + d.len()].copy_from_slice(d)); + self.remaining.saturating_dec(); + self.remaining_size.saturating_reduce(h.payload_len); + } + self.first + .saturating_accrue(ItemHeader::::max_encoded_len().saturated_into()); + self.first.saturating_accrue(h.payload_len); + self.first_index.saturating_inc(); + } + } + + /// Return the message with index `index` in the form of `(position, processed, message)`. + fn peek_index(&self, index: usize) -> Option<(usize, bool, &[u8])> { + let mut pos = 0; + let mut item_slice = &self.heap[..]; + let header_len: usize = ItemHeader::::max_encoded_len().saturated_into(); + for _ in 0..index { + let h = ItemHeader::::decode(&mut item_slice).ok()?; + let item_len = h.payload_len.into() as usize; + if item_slice.len() < item_len { + return None + } + item_slice = &item_slice[item_len..]; + pos.saturating_accrue(header_len.saturating_add(item_len)); + } + let h = ItemHeader::::decode(&mut item_slice).ok()?; + if item_slice.len() < h.payload_len.into() as usize { + return None + } + item_slice = &item_slice[..h.payload_len.into() as usize]; + Some((pos, h.is_processed, item_slice)) + } + + /// Set the `is_processed` flag for the item at `pos` to be `true` if not already and decrement + /// the `remaining` counter of the page. + /// + /// Does nothing if no [`ItemHeader`] could be decoded at the given position. + fn note_processed_at_pos(&mut self, pos: usize) { + if let Ok(mut h) = ItemHeader::::decode(&mut &self.heap[pos..]) { + if !h.is_processed { + h.is_processed = true; + h.using_encoded(|d| self.heap[pos..pos + d.len()].copy_from_slice(d)); + self.remaining.saturating_dec(); + self.remaining_size.saturating_reduce(h.payload_len); + } + } + } + + /// Returns whether the page is *complete* which means that no messages remain. + fn is_complete(&self) -> bool { + self.remaining.is_zero() + } +} + +/// A single link in the double-linked Ready Ring list. +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug, PartialEq)] +pub struct Neighbours { + /// The previous queue. + prev: MessageOrigin, + /// The next queue. + next: MessageOrigin, +} + +/// The state of a queue as represented by a book of its pages. +/// +/// Each queue has exactly one book which holds all of its pages. All pages of a book combined +/// contain all of the messages of its queue; hence the name *Book*. +/// Books can be chained together in a double-linked fashion through their `ready_neighbours` field. +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug)] +pub struct BookState { + /// The first page with some items to be processed in it. If this is `>= end`, then there are + /// no pages with items to be processing in them. + begin: PageIndex, + /// One more than the last page with some items to be processed in it. + end: PageIndex, + /// The number of pages stored at present. + /// + /// This might be larger than `end-begin`, because we keep pages with unprocessed overweight + /// messages outside of the end/begin window. + count: PageIndex, + /// If this book has any ready pages, then this will be `Some` with the previous and next + /// neighbours. This wraps around. + ready_neighbours: Option>, + /// The number of unprocessed messages stored at present. + message_count: u64, + /// The total size of all unprocessed messages stored at present. + size: u64, +} + +impl Default for BookState { + fn default() -> Self { + Self { begin: 0, end: 0, count: 0, ready_neighbours: None, message_count: 0, size: 0 } + } +} + +/// Handler code for when the items in a queue change. +pub trait OnQueueChanged { + /// Note that the queue `id` now has `item_count` items in it, taking up `items_size` bytes. + fn on_queue_changed(id: Id, items_count: u64, items_size: u64); +} + +impl OnQueueChanged for () { + fn on_queue_changed(_: Id, _: u64, _: u64) {} +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + /// The module configuration trait. + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + /// Processor for a message. + /// + /// Must be set to [`mock_helpers::NoopMessageProcessor`] for benchmarking. + /// Other message processors that consumes exactly (1, 1) weight for any give message will + /// work as well. Otherwise the benchmarking will also measure the weight of the message + /// processor, which is not desired. + type MessageProcessor: ProcessMessage; + + /// Page/heap size type. + type Size: BaseArithmetic + + Unsigned + + Copy + + Into + + Member + + Encode + + Decode + + MaxEncodedLen + + TypeInfo + + Default; + + /// Code to be called when a message queue changes - either with items introduced or + /// removed. + type QueueChangeHandler: OnQueueChanged<::Origin>; + + /// The size of the page; this implies the maximum message size which can be sent. + /// + /// A good value depends on the expected message sizes, their weights, the weight that is + /// available for processing them and the maximal needed message size. The maximal message + /// size is slightly lower than this as defined by [`MaxMessageLenOf`]. + #[pallet::constant] + type HeapSize: Get; + + /// The maximum number of stale pages (i.e. of overweight messages) allowed before culling + /// can happen. Once there are more stale pages than this, then historical pages may be + /// dropped, even if they contain unprocessed overweight messages. + #[pallet::constant] + type MaxStale: Get; + + /// The amount of weight (if any) which should be provided to the message queue for + /// servicing enqueued items. + /// + /// This may be legitimately `None` in the case that you will call + /// `ServiceQueues::service_queues` manually. + #[pallet::constant] + type ServiceWeight: Get>; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Message discarded due to an inability to decode the item. Usually caused by state + /// corruption. + Discarded { hash: T::Hash }, + /// Message discarded due to an error in the `MessageProcessor` (usually a format error). + ProcessingFailed { hash: T::Hash, origin: MessageOriginOf, error: ProcessMessageError }, + /// Message is processed. + Processed { hash: T::Hash, origin: MessageOriginOf, weight_used: Weight, success: bool }, + /// Message placed in overweight queue. + OverweightEnqueued { + hash: T::Hash, + origin: MessageOriginOf, + page_index: PageIndex, + message_index: T::Size, + }, + /// This page was reaped. + PageReaped { origin: MessageOriginOf, index: PageIndex }, + } + + #[pallet::error] + pub enum Error { + /// Page is not reapable because it has items remaining to be processed and is not old + /// enough. + NotReapable, + /// Page to be reaped does not exist. + NoPage, + /// The referenced message could not be found. + NoMessage, + /// The message was already processed and cannot be processed again. + AlreadyProcessed, + /// The message is queued for future execution. + Queued, + /// There is temporarily not enough weight to continue servicing messages. + InsufficientWeight, + } + + /// The index of the first and last (non-empty) pages. + #[pallet::storage] + pub(super) type BookStateFor = + StorageMap<_, Twox64Concat, MessageOriginOf, BookState>, ValueQuery>; + + /// The origin at which we should begin servicing. + #[pallet::storage] + pub(super) type ServiceHead = StorageValue<_, MessageOriginOf, OptionQuery>; + + /// The map of page indices to pages. + #[pallet::storage] + pub(super) type Pages = StorageDoubleMap< + _, + Twox64Concat, + MessageOriginOf, + Twox64Concat, + PageIndex, + Page, + OptionQuery, + >; + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(_n: BlockNumberFor) -> Weight { + if let Some(weight_limit) = T::ServiceWeight::get() { + Self::service_queues(weight_limit) + } else { + Weight::zero() + } + } + + /// Check all assumptions about [`crate::Config`]. + fn integrity_test() { + assert!(!MaxMessageLenOf::::get().is_zero(), "HeapSize too low"); + } + } + + #[pallet::call] + impl Pallet { + /// Remove a page which has no more messages remaining to be processed or is stale. + #[pallet::weight(T::WeightInfo::reap_page())] + pub fn reap_page( + origin: OriginFor, + message_origin: MessageOriginOf, + page_index: PageIndex, + ) -> DispatchResult { + let _ = ensure_signed(origin)?; + Self::do_reap_page(&message_origin, page_index) + } + + /// Execute an overweight message. + /// + /// - `origin`: Must be `Signed`. + /// - `message_origin`: The origin from which the message to be executed arrived. + /// - `page`: The page in the queue in which the message to be executed is sitting. + /// - `index`: The index into the queue of the message to be executed. + /// - `weight_limit`: The maximum amount of weight allowed to be consumed in the execution + /// of the message. + /// + /// Benchmark complexity considerations: O(index + weight_limit). + #[pallet::weight( + T::WeightInfo::execute_overweight_page_updated().max( + T::WeightInfo::execute_overweight_page_removed()).saturating_add(*weight_limit) + )] + pub fn execute_overweight( + origin: OriginFor, + message_origin: MessageOriginOf, + page: PageIndex, + index: T::Size, + weight_limit: Weight, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + let actual_weight = + Self::do_execute_overweight(message_origin, page, index, weight_limit)?; + Ok(Some(actual_weight).into()) + } + } +} + +/// The status of a page after trying to execute its next message. +#[derive(PartialEq, Debug)] +enum PageExecutionStatus { + /// The execution bailed because there was not enough weight remaining. + Bailed, + /// No more messages could be loaded. This does _not_ imply `page.is_complete()`. + /// + /// The reasons for this status are: + /// - The end of the page is reached but there could still be skipped messages. + /// - The storage is corrupted. + NoMore, +} + +/// The status after trying to execute the next item of a [`Page`]. +#[derive(PartialEq, Debug)] +enum ItemExecutionStatus { + /// The execution bailed because there was not enough weight remaining. + Bailed, + /// The item was not found. + NoItem, + /// Whether the execution of an item resulted in it being processed. + /// + /// One reason for `false` would be permanently overweight. + Executed(bool), +} + +/// The status of an attempt to process a message. +#[derive(PartialEq)] +enum MessageExecutionStatus { + /// There is not enough weight remaining at present. + InsufficientWeight, + /// There will never be enough weight. + Overweight, + /// The message was processed successfully. + Processed, + /// The message was processed and resulted in a permanent error. + Unprocessable, +} + +impl Pallet { + /// Knit `origin` into the ready ring right at the end. + /// + /// Return the two ready ring neighbours of `origin`. + fn ready_ring_knit(origin: &MessageOriginOf) -> Result>, ()> { + if let Some(head) = ServiceHead::::get() { + let mut head_book_state = BookStateFor::::get(&head); + let mut head_neighbours = head_book_state.ready_neighbours.take().ok_or(())?; + let tail = head_neighbours.prev; + head_neighbours.prev = origin.clone(); + head_book_state.ready_neighbours = Some(head_neighbours); + BookStateFor::::insert(&head, head_book_state); + + let mut tail_book_state = BookStateFor::::get(&tail); + let mut tail_neighbours = tail_book_state.ready_neighbours.take().ok_or(())?; + tail_neighbours.next = origin.clone(); + tail_book_state.ready_neighbours = Some(tail_neighbours); + BookStateFor::::insert(&tail, tail_book_state); + + Ok(Neighbours { next: head, prev: tail }) + } else { + ServiceHead::::put(origin); + Ok(Neighbours { next: origin.clone(), prev: origin.clone() }) + } + } + + fn ready_ring_unknit(origin: &MessageOriginOf, neighbours: Neighbours>) { + if origin == &neighbours.next { + debug_assert!( + origin == &neighbours.prev, + "unknitting from single item ring; outgoing must be only item" + ); + // Service queue empty. + ServiceHead::::kill(); + } else { + BookStateFor::::mutate(&neighbours.next, |book_state| { + if let Some(ref mut n) = book_state.ready_neighbours { + n.prev = neighbours.prev.clone() + } + }); + BookStateFor::::mutate(&neighbours.prev, |book_state| { + if let Some(ref mut n) = book_state.ready_neighbours { + n.next = neighbours.next.clone() + } + }); + if let Some(head) = ServiceHead::::get() { + if &head == origin { + ServiceHead::::put(neighbours.next); + } + } else { + defensive!("`ServiceHead` must be some if there was a ready queue"); + } + } + } + + /// Tries to bump the current `ServiceHead` to the next ready queue. + /// + /// Returns the current head if it got be bumped and `None` otherwise. + fn bump_service_head(weight: &mut WeightMeter) -> Option> { + if !weight.check_accrue(T::WeightInfo::bump_service_head()) { + return None + } + + if let Some(head) = ServiceHead::::get() { + let mut head_book_state = BookStateFor::::get(&head); + if let Some(head_neighbours) = head_book_state.ready_neighbours.take() { + ServiceHead::::put(&head_neighbours.next); + Some(head) + } else { + None + } + } else { + None + } + } + + fn do_enqueue_message( + origin: &MessageOriginOf, + message: BoundedSlice>, + ) { + let mut book_state = BookStateFor::::get(origin); + book_state.message_count.saturating_inc(); + book_state + .size + // This should be payload size, but here the payload *is* the message. + .saturating_accrue(message.len() as u64); + + if book_state.end > book_state.begin { + debug_assert!(book_state.ready_neighbours.is_some(), "Must be in ready ring if ready"); + // Already have a page in progress - attempt to append. + let last = book_state.end - 1; + let mut page = match Pages::::get(origin, last) { + Some(p) => p, + None => { + defensive!("Corruption: referenced page doesn't exist."); + return + }, + }; + if page.try_append_message::(message).is_ok() { + Pages::::insert(origin, last, &page); + BookStateFor::::insert(origin, book_state); + return + } + } else { + debug_assert!( + book_state.ready_neighbours.is_none(), + "Must not be in ready ring if not ready" + ); + // insert into ready queue. + match Self::ready_ring_knit(origin) { + Ok(neighbours) => book_state.ready_neighbours = Some(neighbours), + Err(()) => { + defensive!("Ring state invalid when knitting"); + }, + } + } + // No room on the page or no page - link in a new page. + book_state.end.saturating_inc(); + book_state.count.saturating_inc(); + let page = Page::from_message::(message); + Pages::::insert(origin, book_state.end - 1, page); + // NOTE: `T::QueueChangeHandler` is called by the caller. + BookStateFor::::insert(origin, book_state); + } + + /// Try to execute a single message that was marked as overweight. + /// + /// The `weight_limit` is the weight that can be consumed to execute the message. The base + /// weight of the function it self must be measured by the caller. + pub fn do_execute_overweight( + origin: MessageOriginOf, + page_index: PageIndex, + index: T::Size, + weight_limit: Weight, + ) -> Result> { + let mut book_state = BookStateFor::::get(&origin); + let mut page = Pages::::get(&origin, page_index).ok_or(Error::::NoPage)?; + let (pos, is_processed, payload) = + page.peek_index(index.into() as usize).ok_or(Error::::NoMessage)?; + let payload_len = payload.len() as u64; + ensure!( + page_index < book_state.begin || + (page_index == book_state.begin && pos < page.first.into() as usize), + Error::::Queued + ); + ensure!(!is_processed, Error::::AlreadyProcessed); + use MessageExecutionStatus::*; + let mut weight_counter = WeightMeter::from_limit(weight_limit); + match Self::process_message_payload( + origin.clone(), + page_index, + index, + payload, + &mut weight_counter, + Weight::MAX, + // ^^^ We never recognise it as permanently overweight, since that would result in an + // additional overweight event being deposited. + ) { + Overweight | InsufficientWeight => Err(Error::::InsufficientWeight), + Unprocessable | Processed => { + page.note_processed_at_pos(pos); + book_state.message_count.saturating_dec(); + book_state.size.saturating_reduce(payload_len); + let page_weight = if page.remaining.is_zero() { + debug_assert!( + page.remaining_size.is_zero(), + "no messages remaining; no space taken; qed" + ); + Pages::::remove(&origin, page_index); + debug_assert!(book_state.count >= 1, "page exists, so book must have pages"); + book_state.count.saturating_dec(); + T::WeightInfo::execute_overweight_page_removed() + // no need to consider .first or ready ring since processing an overweight page + // would not alter that state. + } else { + Pages::::insert(&origin, page_index, page); + T::WeightInfo::execute_overweight_page_updated() + }; + BookStateFor::::insert(&origin, &book_state); + T::QueueChangeHandler::on_queue_changed( + origin, + book_state.message_count, + book_state.size, + ); + Ok(weight_counter.consumed.saturating_add(page_weight)) + }, + } + } + + /// Remove a stale page or one which has no more messages remaining to be processed. + fn do_reap_page(origin: &MessageOriginOf, page_index: PageIndex) -> DispatchResult { + let mut book_state = BookStateFor::::get(origin); + // definitely not reapable if the page's index is no less than the `begin`ning of ready + // pages. + ensure!(page_index < book_state.begin, Error::::NotReapable); + + let page = Pages::::get(origin, page_index).ok_or(Error::::NoPage)?; + + // definitely reapable if the page has no messages in it. + let reapable = page.remaining.is_zero(); + + // also reapable if the page index has dropped below our watermark. + let cullable = || { + let total_pages = book_state.count; + let ready_pages = book_state.end.saturating_sub(book_state.begin).min(total_pages); + + // The number of stale pages - i.e. pages which contain unprocessed overweight messages. + // We would prefer to keep these around but will restrict how far into history they can + // extend if we notice that there's too many of them. + // + // We don't know *where* in history these pages are so we use a dynamic formula which + // reduces the historical time horizon as the stale pages pile up and increases it as + // they reduce. + let stale_pages = total_pages - ready_pages; + + // The maximum number of stale pages (i.e. of overweight messages) allowed before + // culling can happen at all. Once there are more stale pages than this, then historical + // pages may be dropped, even if they contain unprocessed overweight messages. + let max_stale = T::MaxStale::get(); + + // The amount beyond the maximum which are being used. If it's not beyond the maximum + // then we exit now since no culling is needed. + let overflow = match stale_pages.checked_sub(max_stale + 1) { + Some(x) => x + 1, + None => return false, + }; + + // The special formula which tells us how deep into index-history we will pages. As + // the overflow is greater (and thus the need to drop items from storage is more urgent) + // this is reduced, allowing a greater range of pages to be culled. + // With a minimum `overflow` (`1`), this returns `max_stale ** 2`, indicating we only + // cull beyond that number of indices deep into history. + // At this overflow increases, our depth reduces down to a limit of `max_stale`. We + // never want to reduce below this since this will certainly allow enough pages to be + // culled in order to bring `overflow` back to zero. + let backlog = (max_stale * max_stale / overflow).max(max_stale); + + let watermark = book_state.begin.saturating_sub(backlog); + page_index < watermark + }; + ensure!(reapable || cullable(), Error::::NotReapable); + + Pages::::remove(origin, page_index); + debug_assert!(book_state.count > 0, "reaping a page implies there are pages"); + book_state.count.saturating_dec(); + book_state.message_count.saturating_reduce(page.remaining.into() as u64); + book_state.size.saturating_reduce(page.remaining_size.into() as u64); + BookStateFor::::insert(origin, &book_state); + T::QueueChangeHandler::on_queue_changed( + origin.clone(), + book_state.message_count, + book_state.size, + ); + Self::deposit_event(Event::PageReaped { origin: origin.clone(), index: page_index }); + + Ok(()) + } + + /// Execute any messages remaining to be processed in the queue of `origin`, using up to + /// `weight_limit` to do so. Any messages which would take more than `overweight_limit` to + /// execute are deemed overweight and ignored. + fn service_queue( + origin: MessageOriginOf, + weight: &mut WeightMeter, + overweight_limit: Weight, + ) -> (bool, Option>) { + if !weight.check_accrue( + T::WeightInfo::service_queue_base().saturating_add(T::WeightInfo::ready_ring_unknit()), + ) { + return (false, None) + } + + let mut book_state = BookStateFor::::get(&origin); + let mut total_processed = 0; + + while book_state.end > book_state.begin { + let (processed, status) = + Self::service_page(&origin, &mut book_state, weight, overweight_limit); + total_processed.saturating_accrue(processed); + match status { + // Store the page progress and do not go to the next one. + PageExecutionStatus::Bailed => break, + // Go to the next page if this one is at the end. + PageExecutionStatus::NoMore => (), + }; + book_state.begin.saturating_inc(); + } + let next_ready = book_state.ready_neighbours.as_ref().map(|x| x.next.clone()); + if book_state.begin >= book_state.end && total_processed > 0 { + // No longer ready - unknit. + if let Some(neighbours) = book_state.ready_neighbours.take() { + Self::ready_ring_unknit(&origin, neighbours); + } else { + defensive!("Freshly processed queue must have been ready"); + } + } + BookStateFor::::insert(&origin, &book_state); + if total_processed > 0 { + T::QueueChangeHandler::on_queue_changed( + origin, + book_state.message_count, + book_state.size, + ); + } + (total_processed > 0, next_ready) + } + + /// Service as many messages of a page as possible. + /// + /// Returns how many messages were processed and the page's status. + fn service_page( + origin: &MessageOriginOf, + book_state: &mut BookStateOf, + weight: &mut WeightMeter, + overweight_limit: Weight, + ) -> (u32, PageExecutionStatus) { + use PageExecutionStatus::*; + if !weight.check_accrue( + T::WeightInfo::service_page_base_completion() + .max(T::WeightInfo::service_page_base_no_completion()), + ) { + return (0, Bailed) + } + + let page_index = book_state.begin; + let mut page = match Pages::::get(origin, page_index) { + Some(p) => p, + None => { + defensive!("message-queue: referenced page not found"); + return (0, NoMore) + }, + }; + + let mut total_processed = 0; + + // Execute as many messages as possible. + let status = loop { + use ItemExecutionStatus::*; + match Self::service_page_item( + origin, + page_index, + book_state, + &mut page, + weight, + overweight_limit, + ) { + Bailed => break PageExecutionStatus::Bailed, + NoItem => break PageExecutionStatus::NoMore, + // Keep going as long as we make progress... + Executed(true) => total_processed.saturating_inc(), + Executed(false) => (), + } + }; + + if page.is_complete() { + debug_assert!(status != Bailed, "we never bail if a page became complete"); + Pages::::remove(origin, page_index); + debug_assert!(book_state.count > 0, "completing a page implies there are pages"); + book_state.count.saturating_dec(); + } else { + Pages::::insert(origin, page_index, page); + } + (total_processed, status) + } + + /// Execute the next message of a page. + pub(crate) fn service_page_item( + origin: &MessageOriginOf, + page_index: PageIndex, + book_state: &mut BookStateOf, + page: &mut PageOf, + weight: &mut WeightMeter, + overweight_limit: Weight, + ) -> ItemExecutionStatus { + // This ugly pre-checking is needed for the invariant + // "we never bail if a page became complete". + if page.is_complete() { + return ItemExecutionStatus::NoItem + } + if !weight.check_accrue(T::WeightInfo::service_page_item()) { + return ItemExecutionStatus::Bailed + } + + let payload = &match page.peek_first() { + Some(m) => m, + None => return ItemExecutionStatus::NoItem, + }[..]; + + use MessageExecutionStatus::*; + let is_processed = match Self::process_message_payload( + origin.clone(), + page_index, + page.first_index, + payload.deref(), + weight, + overweight_limit, + ) { + InsufficientWeight => return ItemExecutionStatus::Bailed, + Processed | Unprocessable => true, + Overweight => false, + }; + + if is_processed { + book_state.message_count.saturating_dec(); + book_state.size.saturating_reduce(payload.len() as u64); + } + page.skip_first(is_processed); + ItemExecutionStatus::Executed(is_processed) + } + + /// Print the pages in each queue and the messages in each page. + /// + /// Processed messages are prefixed with a `*` and the current `begin`ning page with a `>`. + /// + /// # Example output + /// + /// ```text + /// queue Here: + /// page 0: [] + /// > page 1: [] + /// page 2: ["\0weight=4", "\0c", ] + /// page 3: ["\0bigbig 1", ] + /// page 4: ["\0bigbig 2", ] + /// page 5: ["\0bigbig 3", ] + /// ``` + #[cfg(feature = "std")] + pub fn debug_info() -> String { + let mut info = String::new(); + for (origin, book_state) in BookStateFor::::iter() { + let mut queue = format!("queue {:?}:\n", &origin); + let mut pages = Pages::::iter_prefix(&origin).collect::>(); + pages.sort_by(|(a, _), (b, _)| a.cmp(b)); + for (page_index, mut page) in pages.into_iter() { + let page_info = if book_state.begin == page_index { ">" } else { " " }; + let mut page_info = format!( + "{} page {} ({:?} first, {:?} last, {:?} remain): [ ", + page_info, page_index, page.first, page.last, page.remaining + ); + for i in 0..u32::MAX { + if let Some((_, processed, message)) = + page.peek_index(i.try_into().expect("std-only code")) + { + let msg = String::from_utf8_lossy(message.deref()); + if processed { + page_info.push('*'); + } + page_info.push_str(&format!("{:?}, ", msg)); + page.skip_first(true); + } else { + break + } + } + page_info.push_str("]\n"); + queue.push_str(&page_info); + } + info.push_str(&queue); + } + info + } + + /// Process a single message. + /// + /// The base weight of this function needs to be accounted for by the caller. `weight` is the + /// remaining weight to process the message. `overweight_limit` is the maximum weight that a + /// message can ever consume. Messages above this limit are marked as permanently overweight. + fn process_message_payload( + origin: MessageOriginOf, + page_index: PageIndex, + message_index: T::Size, + message: &[u8], + weight: &mut WeightMeter, + overweight_limit: Weight, + ) -> MessageExecutionStatus { + let hash = T::Hashing::hash(message); + use ProcessMessageError::Overweight; + match T::MessageProcessor::process_message(message, origin.clone(), weight.remaining()) { + Err(Overweight(w)) if w.any_gt(overweight_limit) => { + // Permanently overweight. + Self::deposit_event(Event::::OverweightEnqueued { + hash, + origin, + page_index, + message_index, + }); + MessageExecutionStatus::Overweight + }, + Err(Overweight(_)) => { + // Temporarily overweight - save progress and stop processing this + // queue. + MessageExecutionStatus::InsufficientWeight + }, + Err(error) => { + // Permanent error - drop + Self::deposit_event(Event::::ProcessingFailed { hash, origin, error }); + MessageExecutionStatus::Unprocessable + }, + Ok((success, weight_used)) => { + // Success + weight.defensive_saturating_accrue(weight_used); + let event = Event::::Processed { hash, origin, weight_used, success }; + Self::deposit_event(event); + MessageExecutionStatus::Processed + }, + } + } +} + +/// Provides a [`sp_core::Get`] to access the `MEL` of a [`codec::MaxEncodedLen`] type. +pub struct MaxEncodedLenOf(sp_std::marker::PhantomData); +impl Get for MaxEncodedLenOf { + fn get() -> u32 { + T::max_encoded_len() as u32 + } +} + +/// Calculates the maximum message length and exposed it through the [`codec::MaxEncodedLen`] trait. +pub struct MaxMessageLen( + sp_std::marker::PhantomData<(Origin, Size, HeapSize)>, +); +impl, HeapSize: Get> Get + for MaxMessageLen +{ + fn get() -> u32 { + (HeapSize::get().into()).saturating_sub(ItemHeader::::max_encoded_len() as u32) + } +} + +/// The maximal message length. +pub type MaxMessageLenOf = + MaxMessageLen, ::Size, ::HeapSize>; +/// The maximal encoded origin length. +pub type MaxOriginLenOf = MaxEncodedLenOf>; +/// The `MessageOrigin` of this pallet. +pub type MessageOriginOf = <::MessageProcessor as ProcessMessage>::Origin; +/// The maximal heap size of a page. +pub type HeapSizeU32Of = IntoU32<::HeapSize, ::Size>; +/// The [`Page`] of this pallet. +pub type PageOf = Page<::Size, ::HeapSize>; +/// The [`BookState`] of this pallet. +pub type BookStateOf = BookState>; + +/// Converts a [`sp_core::Get`] with returns a type that can be cast into an `u32` into a `Get` +/// which returns an `u32`. +pub struct IntoU32(sp_std::marker::PhantomData<(T, O)>); +impl, O: Into> Get for IntoU32 { + fn get() -> u32 { + T::get().into() + } +} + +impl ServiceQueues for Pallet { + type OverweightMessageAddress = (MessageOriginOf, PageIndex, T::Size); + + fn service_queues(weight_limit: Weight) -> Weight { + // The maximum weight that processing a single message may take. + let overweight_limit = weight_limit; + let mut weight = WeightMeter::from_limit(weight_limit); + + let mut next = match Self::bump_service_head(&mut weight) { + Some(h) => h, + None => return weight.consumed, + }; + // The last queue that did not make any progress. + // The loop aborts as soon as it arrives at this queue again without making any progress + // on other queues in between. + let mut last_no_progress = None; + + loop { + let (progressed, n) = Self::service_queue(next.clone(), &mut weight, overweight_limit); + next = match n { + Some(n) => + if !progressed { + if last_no_progress == Some(n.clone()) { + break + } + if last_no_progress.is_none() { + last_no_progress = Some(next.clone()) + } + n + } else { + last_no_progress = None; + n + }, + None => break, + } + } + weight.consumed + } + + /// Execute a single overweight message. + /// + /// The weight limit must be enough for `execute_overweight` and the message execution itself. + fn execute_overweight( + weight_limit: Weight, + (message_origin, page, index): Self::OverweightMessageAddress, + ) -> Result { + let mut weight = WeightMeter::from_limit(weight_limit); + if !weight.check_accrue( + T::WeightInfo::execute_overweight_page_removed() + .max(T::WeightInfo::execute_overweight_page_updated()), + ) { + return Err(ExecuteOverweightError::InsufficientWeight) + } + + Pallet::::do_execute_overweight(message_origin, page, index, weight.remaining()).map_err( + |e| match e { + Error::::InsufficientWeight => ExecuteOverweightError::InsufficientWeight, + _ => ExecuteOverweightError::NotFound, + }, + ) + } +} + +impl EnqueueMessage> for Pallet { + type MaxMessageLen = + MaxMessageLen<::Origin, T::Size, T::HeapSize>; + + fn enqueue_message( + message: BoundedSlice, + origin: ::Origin, + ) { + Self::do_enqueue_message(&origin, message); + let book_state = BookStateFor::::get(&origin); + T::QueueChangeHandler::on_queue_changed(origin, book_state.message_count, book_state.size); + } + + fn enqueue_messages<'a>( + messages: impl Iterator>, + origin: ::Origin, + ) { + for message in messages { + Self::do_enqueue_message(&origin, message); + } + let book_state = BookStateFor::::get(&origin); + T::QueueChangeHandler::on_queue_changed(origin, book_state.message_count, book_state.size); + } + + fn sweep_queue(origin: MessageOriginOf) { + if !BookStateFor::::contains_key(&origin) { + return + } + let mut book_state = BookStateFor::::get(&origin); + book_state.begin = book_state.end; + if let Some(neighbours) = book_state.ready_neighbours.take() { + Self::ready_ring_unknit(&origin, neighbours); + } + BookStateFor::::insert(&origin, &book_state); + } + + fn footprint(origin: MessageOriginOf) -> Footprint { + let book_state = BookStateFor::::get(&origin); + Footprint { count: book_state.message_count, size: book_state.size } + } +} diff --git a/frame/message-queue/src/mock.rs b/frame/message-queue/src/mock.rs new file mode 100644 index 0000000000000..bb9942443e226 --- /dev/null +++ b/frame/message-queue/src/mock.rs @@ -0,0 +1,312 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +#![cfg(test)] + +pub use super::mock_helpers::*; +use super::*; + +use crate as pallet_message_queue; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, +}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; +use sp_std::collections::btree_map::BTreeMap; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event}, + } +); +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); +} +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type RuntimeCall = RuntimeCall; + type Hashing = BlakeTwo256; + type AccountId = u64; + 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 SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} +parameter_types! { + pub const HeapSize: u32 = 24; + pub const MaxStale: u32 = 2; + pub const ServiceWeight: Option = Some(Weight::from_parts(10, 10)); +} +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = MockedWeightInfo; + type MessageProcessor = RecordingMessageProcessor; + type Size = u32; + type QueueChangeHandler = RecordingQueueChangeHandler; + type HeapSize = HeapSize; + type MaxStale = MaxStale; + type ServiceWeight = ServiceWeight; +} + +/// Mocked `WeightInfo` impl with allows to set the weight per call. +pub struct MockedWeightInfo; + +parameter_types! { + /// Storage for `MockedWeightInfo`, do not use directly. + pub static WeightForCall: BTreeMap = Default::default(); +} + +/// Set the return value for a function from the `WeightInfo` trait. +impl MockedWeightInfo { + /// Set the weight of a specific weight function. + pub fn set_weight(call_name: &str, weight: Weight) { + let mut calls = WeightForCall::get(); + calls.insert(call_name.into(), weight); + WeightForCall::set(calls); + } +} + +impl crate::weights::WeightInfo for MockedWeightInfo { + fn reap_page() -> Weight { + WeightForCall::get().get("reap_page").copied().unwrap_or_default() + } + fn execute_overweight_page_updated() -> Weight { + WeightForCall::get() + .get("execute_overweight_page_updated") + .copied() + .unwrap_or_default() + } + fn execute_overweight_page_removed() -> Weight { + WeightForCall::get() + .get("execute_overweight_page_removed") + .copied() + .unwrap_or_default() + } + fn service_page_base_completion() -> Weight { + WeightForCall::get() + .get("service_page_base_completion") + .copied() + .unwrap_or_default() + } + fn service_page_base_no_completion() -> Weight { + WeightForCall::get() + .get("service_page_base_no_completion") + .copied() + .unwrap_or_default() + } + fn service_queue_base() -> Weight { + WeightForCall::get().get("service_queue_base").copied().unwrap_or_default() + } + fn bump_service_head() -> Weight { + WeightForCall::get().get("bump_service_head").copied().unwrap_or_default() + } + fn service_page_item() -> Weight { + WeightForCall::get().get("service_page_item").copied().unwrap_or_default() + } + fn ready_ring_knit() -> Weight { + WeightForCall::get().get("ready_ring_knit").copied().unwrap_or_default() + } + fn ready_ring_unknit() -> Weight { + WeightForCall::get().get("ready_ring_unknit").copied().unwrap_or_default() + } +} + +parameter_types! { + pub static MessagesProcessed: Vec<(Vec, MessageOrigin)> = vec![]; +} + +/// A message processor which records all processed messages into [`MessagesProcessed`]. +pub struct RecordingMessageProcessor; +impl ProcessMessage for RecordingMessageProcessor { + /// The transport from where a message originates. + type Origin = MessageOrigin; + + /// Process the given message, using no more than `weight_limit` in weight to do so. + /// + /// Consumes exactly `n` weight of all components if it starts `weight=n` and `1` otherwise. + /// Errors if given the `weight_limit` is insufficient to process the message or if the message + /// is `badformat`, `corrupt` or `unsupported` with the respective error. + fn process_message( + message: &[u8], + origin: Self::Origin, + weight_limit: Weight, + ) -> Result<(bool, Weight), ProcessMessageError> { + processing_message(message)?; + + let weight = if message.starts_with(&b"weight="[..]) { + let mut w: u64 = 0; + for &c in &message[7..] { + if (b'0'..=b'9').contains(&c) { + w = w * 10 + (c - b'0') as u64; + } else { + break + } + } + w + } else { + 1 + }; + let weight = Weight::from_parts(weight, weight); + + if weight.all_lte(weight_limit) { + let mut m = MessagesProcessed::get(); + m.push((message.to_vec(), origin)); + MessagesProcessed::set(m); + Ok((true, weight)) + } else { + Err(ProcessMessageError::Overweight(weight)) + } + } +} + +/// Processed a mocked message. Messages that end with `badformat`, `corrupt` or `unsupported` will +/// fail with the respective error. +fn processing_message(msg: &[u8]) -> Result<(), ProcessMessageError> { + let msg = String::from_utf8_lossy(msg); + if msg.ends_with("badformat") { + Err(ProcessMessageError::BadFormat) + } else if msg.ends_with("corrupt") { + Err(ProcessMessageError::Corrupt) + } else if msg.ends_with("unsupported") { + Err(ProcessMessageError::Unsupported) + } else { + Ok(()) + } +} + +parameter_types! { + pub static NumMessagesProcessed: usize = 0; + pub static NumMessagesErrored: usize = 0; +} + +/// Similar to [`RecordingMessageProcessor`] but only counts the number of messages processed and +/// does always consume one weight per message. +/// +/// The [`RecordingMessageProcessor`] is a bit too slow for the integration tests. +pub struct CountingMessageProcessor; +impl ProcessMessage for CountingMessageProcessor { + type Origin = MessageOrigin; + + fn process_message( + message: &[u8], + _origin: Self::Origin, + weight_limit: Weight, + ) -> Result<(bool, Weight), ProcessMessageError> { + if let Err(e) = processing_message(message) { + NumMessagesErrored::set(NumMessagesErrored::get() + 1); + return Err(e) + } + let weight = Weight::from_parts(1, 1); + + if weight.all_lte(weight_limit) { + NumMessagesProcessed::set(NumMessagesProcessed::get() + 1); + Ok((true, weight)) + } else { + Err(ProcessMessageError::Overweight(weight)) + } + } +} + +parameter_types! { + /// Storage for `RecordingQueueChangeHandler`, do not use directly. + pub static QueueChanges: Vec<(MessageOrigin, u64, u64)> = vec![]; +} + +/// Records all queue changes into [`QueueChanges`]. +pub struct RecordingQueueChangeHandler; +impl OnQueueChanged for RecordingQueueChangeHandler { + fn on_queue_changed(id: MessageOrigin, items_count: u64, items_size: u64) { + QueueChanges::mutate(|cs| cs.push((id, items_count, items_size))); + } +} + +/// Create new test externalities. +/// +/// Is generic since it is used by the unit test, integration tests and benchmarks. +pub fn new_test_ext() -> sp_io::TestExternalities +where + ::BlockNumber: From, +{ + sp_tracing::try_init_simple(); + WeightForCall::take(); + QueueChanges::take(); + NumMessagesErrored::take(); + let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| frame_system::Pallet::::set_block_number(1.into())); + ext +} + +/// Set the weight of a specific weight function. +pub fn set_weight(name: &str, w: Weight) { + MockedWeightInfo::set_weight::(name, w); +} + +/// Assert that exactly these pages are present. Assumes `Here` origin. +pub fn assert_pages(indices: &[u32]) { + assert_eq!(Pages::::iter().count(), indices.len()); + for i in indices { + assert!(Pages::::contains_key(MessageOrigin::Here, i)); + } +} + +/// Build a ring with three queues: `Here`, `There` and `Everywhere(0)`. +pub fn build_triple_ring() { + use MessageOrigin::*; + build_ring::(&[Here, There, Everywhere(0)]) +} + +/// Shim to get rid of the annoying `::` everywhere. +pub fn assert_ring(queues: &[MessageOrigin]) { + super::mock_helpers::assert_ring::(queues); +} + +pub fn knit(queue: &MessageOrigin) { + super::mock_helpers::knit::(queue); +} + +pub fn unknit(queue: &MessageOrigin) { + super::mock_helpers::unknit::(queue); +} diff --git a/frame/message-queue/src/mock_helpers.rs b/frame/message-queue/src/mock_helpers.rs new file mode 100644 index 0000000000000..39d961d8fc558 --- /dev/null +++ b/frame/message-queue/src/mock_helpers.rs @@ -0,0 +1,185 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Std setup helpers for testing and benchmarking. +//! +//! Cannot be put into mock.rs since benchmarks require no-std and mock.rs is std. + +use crate::*; +use frame_support::traits::Defensive; + +/// Converts `Self` into a `Weight` by using `Self` for all components. +pub trait IntoWeight { + fn into_weight(self) -> Weight; +} + +impl IntoWeight for u64 { + fn into_weight(self) -> Weight { + Weight::from_parts(self, self) + } +} + +/// Mocked message origin for testing. +#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, TypeInfo, Debug)] +pub enum MessageOrigin { + Here, + There, + Everywhere(u32), +} + +impl From for MessageOrigin { + fn from(i: u32) -> Self { + Self::Everywhere(i) + } +} + +/// Processes any message and consumes (1, 1) weight per message. +pub struct NoopMessageProcessor; +impl ProcessMessage for NoopMessageProcessor { + type Origin = MessageOrigin; + + fn process_message( + _message: &[u8], + _origin: Self::Origin, + weight_limit: Weight, + ) -> Result<(bool, Weight), ProcessMessageError> { + let weight = Weight::from_parts(1, 1); + + if weight.all_lte(weight_limit) { + Ok((true, weight)) + } else { + Err(ProcessMessageError::Overweight(weight)) + } + } +} + +/// Create a message from the given data. +pub fn msg>(x: &'static str) -> BoundedSlice { + BoundedSlice::defensive_truncate_from(x.as_bytes()) +} + +pub fn vmsg(x: &'static str) -> Vec { + x.as_bytes().to_vec() +} + +/// Create a page from a single message. +pub fn page(msg: &[u8]) -> PageOf { + PageOf::::from_message::(msg.try_into().unwrap()) +} + +pub fn single_page_book() -> BookStateOf { + BookState { begin: 0, end: 1, count: 1, ready_neighbours: None, message_count: 0, size: 0 } +} + +pub fn empty_book() -> BookStateOf { + BookState { begin: 0, end: 1, count: 1, ready_neighbours: None, message_count: 0, size: 0 } +} + +/// Returns a full page of messages with their index as payload and the number of messages. +pub fn full_page() -> (PageOf, usize) { + let mut msgs = 0; + let mut page = PageOf::::default(); + for i in 0..u32::MAX { + let r = i.using_encoded(|d| page.try_append_message::(d.try_into().unwrap())); + if r.is_err() { + break + } else { + msgs += 1; + } + } + assert!(msgs > 0, "page must hold at least one message"); + (page, msgs) +} + +/// Returns a page filled with empty messages and the number of messages. +pub fn book_for(page: &PageOf) -> BookStateOf { + BookState { + count: 1, + begin: 0, + end: 1, + ready_neighbours: None, + message_count: page.remaining.into() as u64, + size: page.remaining_size.into() as u64, + } +} + +/// Assert the last event that was emitted. +#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] +pub fn assert_last_event(generic_event: ::RuntimeEvent) { + assert!( + !frame_system::Pallet::::block_number().is_zero(), + "The genesis block has n o events" + ); + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +/// Provide a setup for `bump_service_head`. +pub fn setup_bump_service_head( + current: <::MessageProcessor as ProcessMessage>::Origin, + next: <::MessageProcessor as ProcessMessage>::Origin, +) { + let mut book = single_page_book::(); + book.ready_neighbours = Some(Neighbours::> { prev: next.clone(), next }); + ServiceHead::::put(¤t); + BookStateFor::::insert(¤t, &book); +} + +/// Knit a queue into the ready-ring and write it back to storage. +pub fn knit(o: &<::MessageProcessor as ProcessMessage>::Origin) { + let mut b = BookStateFor::::get(o); + b.ready_neighbours = crate::Pallet::::ready_ring_knit(o).ok().defensive(); + BookStateFor::::insert(o, b); +} + +/// Unknit a queue into the ready-ring and write it back to storage. +pub fn unknit(o: &<::MessageProcessor as ProcessMessage>::Origin) { + let mut b = BookStateFor::::get(o); + crate::Pallet::::ready_ring_unknit(o, b.ready_neighbours.unwrap()); + b.ready_neighbours = None; + BookStateFor::::insert(o, b); +} + +/// Build a ring with three queues: `Here`, `There` and `Everywhere(0)`. +pub fn build_ring( + queues: &[<::MessageProcessor as ProcessMessage>::Origin], +) { + for queue in queues { + BookStateFor::::insert(queue, empty_book::()); + } + for queue in queues { + knit::(queue); + } + assert_ring::(queues); +} + +/// Check that the Ready Ring consists of `queues` in that exact order. +/// +/// Also check that all backlinks are valid and that the first element is the service head. +pub fn assert_ring( + queues: &[<::MessageProcessor as ProcessMessage>::Origin], +) { + for (i, origin) in queues.iter().enumerate() { + let book = BookStateFor::::get(origin); + assert_eq!( + book.ready_neighbours, + Some(Neighbours { + prev: queues[(i + queues.len() - 1) % queues.len()].clone(), + next: queues[(i + 1) % queues.len()].clone(), + }) + ); + } + assert_eq!(ServiceHead::::get(), queues.first().cloned()); +} diff --git a/frame/message-queue/src/tests.rs b/frame/message-queue/src/tests.rs new file mode 100644 index 0000000000000..103fb690ddba7 --- /dev/null +++ b/frame/message-queue/src/tests.rs @@ -0,0 +1,1092 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for Message Queue Pallet. + +#![cfg(test)] + +use crate::{mock::*, *}; + +use frame_support::{assert_noop, assert_ok, assert_storage_noop, StorageNoopGuard}; +use rand::{rngs::StdRng, Rng, SeedableRng}; + +#[test] +fn mocked_weight_works() { + new_test_ext::().execute_with(|| { + assert!(::WeightInfo::service_queue_base().is_zero()); + }); + new_test_ext::().execute_with(|| { + set_weight("service_queue_base", Weight::MAX); + assert_eq!(::WeightInfo::service_queue_base(), Weight::MAX); + }); + // The externalities reset it. + new_test_ext::().execute_with(|| { + assert!(::WeightInfo::service_queue_base().is_zero()); + }); +} + +#[test] +fn enqueue_within_one_page_works() { + new_test_ext::().execute_with(|| { + use MessageOrigin::*; + MessageQueue::enqueue_message(msg("a"), Here); + MessageQueue::enqueue_message(msg("b"), Here); + MessageQueue::enqueue_message(msg("c"), Here); + assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(b"a".to_vec(), Here), (b"b".to_vec(), Here)]); + + assert_eq!(MessageQueue::service_queues(2.into_weight()), 1.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(b"c".to_vec(), Here)]); + + assert_eq!(MessageQueue::service_queues(2.into_weight()), 0.into_weight()); + assert!(MessagesProcessed::get().is_empty()); + + MessageQueue::enqueue_messages([msg("a"), msg("b"), msg("c")].into_iter(), There); + + assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); + assert_eq!( + MessagesProcessed::take(), + vec![(b"a".to_vec(), There), (b"b".to_vec(), There),] + ); + + MessageQueue::enqueue_message(msg("d"), Everywhere(1)); + + assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); + assert_eq!(MessageQueue::service_queues(2.into_weight()), 0.into_weight()); + assert_eq!( + MessagesProcessed::take(), + vec![(b"c".to_vec(), There), (b"d".to_vec(), Everywhere(1))] + ); + }); +} + +#[test] +fn queue_priority_retains() { + new_test_ext::().execute_with(|| { + use MessageOrigin::*; + assert_ring(&[]); + MessageQueue::enqueue_message(msg("a"), Everywhere(1)); + assert_ring(&[Everywhere(1)]); + MessageQueue::enqueue_message(msg("b"), Everywhere(2)); + assert_ring(&[Everywhere(1), Everywhere(2)]); + MessageQueue::enqueue_message(msg("c"), Everywhere(3)); + assert_ring(&[Everywhere(1), Everywhere(2), Everywhere(3)]); + MessageQueue::enqueue_message(msg("d"), Everywhere(2)); + assert_ring(&[Everywhere(1), Everywhere(2), Everywhere(3)]); + // service head is 1, it will process a, leaving service head at 2. it also processes b but + // doees not empty queue 2, so service head will end at 2. + assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); + assert_eq!( + MessagesProcessed::take(), + vec![(vmsg("a"), Everywhere(1)), (vmsg("b"), Everywhere(2)),] + ); + assert_ring(&[Everywhere(2), Everywhere(3)]); + // service head is 2, so will process d first, then c. + assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); + assert_eq!( + MessagesProcessed::get(), + vec![(vmsg("d"), Everywhere(2)), (vmsg("c"), Everywhere(3)),] + ); + assert_ring(&[]); + }); +} + +#[test] +fn queue_priority_reset_once_serviced() { + new_test_ext::().execute_with(|| { + use MessageOrigin::*; + MessageQueue::enqueue_message(msg("a"), Everywhere(1)); + MessageQueue::enqueue_message(msg("b"), Everywhere(2)); + MessageQueue::enqueue_message(msg("c"), Everywhere(3)); + // service head is 1, it will process a, leaving service head at 2. it also processes b and + // empties queue 2, so service head will end at 3. + assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); + MessageQueue::enqueue_message(msg("d"), Everywhere(2)); + // service head is 3, so will process c first, then d. + assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); + + assert_eq!( + MessagesProcessed::get(), + vec![ + (vmsg("a"), Everywhere(1)), + (vmsg("b"), Everywhere(2)), + (vmsg("c"), Everywhere(3)), + (vmsg("d"), Everywhere(2)), + ] + ); + }); +} + +#[test] +fn service_queues_basic_works() { + use MessageOrigin::*; + new_test_ext::().execute_with(|| { + MessageQueue::enqueue_messages(vec![msg("a"), msg("ab"), msg("abc")].into_iter(), Here); + MessageQueue::enqueue_messages(vec![msg("x"), msg("xy"), msg("xyz")].into_iter(), There); + assert_eq!(QueueChanges::take(), vec![(Here, 3, 6), (There, 3, 6)]); + + // Service one message from `Here`. + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("a"), Here)]); + assert_eq!(QueueChanges::take(), vec![(Here, 2, 5)]); + + // Service one message from `There`. + ServiceHead::::set(There.into()); + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("x"), There)]); + assert_eq!(QueueChanges::take(), vec![(There, 2, 5)]); + + // Service the remaining from `Here`. + ServiceHead::::set(Here.into()); + assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("ab"), Here), (vmsg("abc"), Here)]); + assert_eq!(QueueChanges::take(), vec![(Here, 0, 0)]); + + // Service all remaining messages. + assert_eq!(MessageQueue::service_queues(Weight::MAX), 2.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("xy"), There), (vmsg("xyz"), There)]); + assert_eq!(QueueChanges::take(), vec![(There, 0, 0)]); + }); +} + +#[test] +fn service_queues_failing_messages_works() { + use MessageOrigin::*; + new_test_ext::().execute_with(|| { + set_weight("service_page_item", 1.into_weight()); + MessageQueue::enqueue_message(msg("badformat"), Here); + MessageQueue::enqueue_message(msg("corrupt"), Here); + MessageQueue::enqueue_message(msg("unsupported"), Here); + // Starts with three pages. + assert_pages(&[0, 1, 2]); + + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_last_event::( + Event::ProcessingFailed { + hash: ::Hashing::hash(b"badformat"), + origin: MessageOrigin::Here, + error: ProcessMessageError::BadFormat, + } + .into(), + ); + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_last_event::( + Event::ProcessingFailed { + hash: ::Hashing::hash(b"corrupt"), + origin: MessageOrigin::Here, + error: ProcessMessageError::Corrupt, + } + .into(), + ); + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_last_event::( + Event::ProcessingFailed { + hash: ::Hashing::hash(b"unsupported"), + origin: MessageOrigin::Here, + error: ProcessMessageError::Unsupported, + } + .into(), + ); + // All pages removed. + assert_pages(&[]); + }); +} + +#[test] +fn reap_page_permanent_overweight_works() { + use MessageOrigin::*; + new_test_ext::().execute_with(|| { + // Create 10 pages more than the stale limit. + let n = (MaxStale::get() + 10) as usize; + for _ in 0..n { + MessageQueue::enqueue_message(msg("weight=2"), Here); + } + assert_eq!(Pages::::iter().count(), n); + assert_eq!(QueueChanges::take().len(), n); + // Mark all pages as stale since their message is permanently overweight. + MessageQueue::service_queues(1.into_weight()); + + // Check that we can reap everything below the watermark. + let max_stale = MaxStale::get(); + for i in 0..n as u32 { + let b = BookStateFor::::get(Here); + let stale_pages = n as u32 - i; + let overflow = stale_pages.saturating_sub(max_stale + 1) + 1; + let backlog = (max_stale * max_stale / overflow).max(max_stale); + let watermark = b.begin.saturating_sub(backlog); + + if i >= watermark { + break + } + assert_ok!(MessageQueue::do_reap_page(&Here, i)); + assert_eq!(QueueChanges::take(), vec![(Here, b.message_count - 1, b.size - 8)]); + } + + // Cannot reap any more pages. + for (o, i, _) in Pages::::iter() { + assert_noop!(MessageQueue::do_reap_page(&o, i), Error::::NotReapable); + assert!(QueueChanges::take().is_empty()); + } + }); +} + +#[test] +fn reaping_overweight_fails_properly() { + use MessageOrigin::*; + assert_eq!(MaxStale::get(), 2, "The stale limit is two"); + + new_test_ext::().execute_with(|| { + // page 0 + MessageQueue::enqueue_message(msg("weight=4"), Here); + MessageQueue::enqueue_message(msg("a"), Here); + // page 1 + MessageQueue::enqueue_message(msg("weight=4"), Here); + MessageQueue::enqueue_message(msg("b"), Here); + // page 2 + MessageQueue::enqueue_message(msg("weight=4"), Here); + MessageQueue::enqueue_message(msg("c"), Here); + // page 3 + MessageQueue::enqueue_message(msg("bigbig 1"), Here); + // page 4 + MessageQueue::enqueue_message(msg("bigbig 2"), Here); + // page 5 + MessageQueue::enqueue_message(msg("bigbig 3"), Here); + // Double-check that exactly these pages exist. + assert_pages(&[0, 1, 2, 3, 4, 5]); + + assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("a"), Here), (vmsg("b"), Here)]); + // 2 stale now. + + // Nothing reapable yet, because we haven't hit the stale limit. + for (o, i, _) in Pages::::iter() { + assert_noop!(MessageQueue::do_reap_page(&o, i), Error::::NotReapable); + } + assert_pages(&[0, 1, 2, 3, 4, 5]); + + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("c"), Here)]); + // 3 stale now: can take something 4 pages in history. + + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("bigbig 1"), Here)]); + + // Nothing reapable yet, because we haven't hit the stale limit. + for (o, i, _) in Pages::::iter() { + assert_noop!(MessageQueue::do_reap_page(&o, i), Error::::NotReapable); + } + assert_pages(&[0, 1, 2, 4, 5]); + + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("bigbig 2"), Here)]); + assert_pages(&[0, 1, 2, 5]); + + // First is now reapable as it is too far behind the first ready page (5). + assert_ok!(MessageQueue::do_reap_page(&Here, 0)); + // Others not reapable yet, because we haven't hit the stale limit. + for (o, i, _) in Pages::::iter() { + assert_noop!(MessageQueue::do_reap_page(&o, i), Error::::NotReapable); + } + assert_pages(&[1, 2, 5]); + + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("bigbig 3"), Here)]); + + assert_noop!(MessageQueue::do_reap_page(&Here, 0), Error::::NoPage); + assert_noop!(MessageQueue::do_reap_page(&Here, 3), Error::::NoPage); + assert_noop!(MessageQueue::do_reap_page(&Here, 4), Error::::NoPage); + // Still not reapable, since the number of stale pages is only 2. + for (o, i, _) in Pages::::iter() { + assert_noop!(MessageQueue::do_reap_page(&o, i), Error::::NotReapable); + } + }); +} + +#[test] +fn service_queue_bails() { + // Not enough weight for `service_queue_base`. + new_test_ext::().execute_with(|| { + set_weight("service_queue_base", 2.into_weight()); + let mut meter = WeightMeter::from_limit(1.into_weight()); + + assert_storage_noop!(MessageQueue::service_queue(0u32.into(), &mut meter, Weight::MAX)); + assert!(meter.consumed.is_zero()); + }); + // Not enough weight for `ready_ring_unknit`. + new_test_ext::().execute_with(|| { + set_weight("ready_ring_unknit", 2.into_weight()); + let mut meter = WeightMeter::from_limit(1.into_weight()); + + assert_storage_noop!(MessageQueue::service_queue(0u32.into(), &mut meter, Weight::MAX)); + assert!(meter.consumed.is_zero()); + }); + // Not enough weight for `service_queue_base` and `ready_ring_unknit`. + new_test_ext::().execute_with(|| { + set_weight("service_queue_base", 2.into_weight()); + set_weight("ready_ring_unknit", 2.into_weight()); + + let mut meter = WeightMeter::from_limit(3.into_weight()); + assert_storage_noop!(MessageQueue::service_queue(0.into(), &mut meter, Weight::MAX)); + assert!(meter.consumed.is_zero()); + }); +} + +#[test] +fn service_page_works() { + use super::integration_test::Test; // Run with larger page size. + use MessageOrigin::*; + use PageExecutionStatus::*; + new_test_ext::().execute_with(|| { + set_weight("service_page_base_completion", 2.into_weight()); + set_weight("service_page_item", 3.into_weight()); + + let (page, mut msgs) = full_page::(); + assert!(msgs >= 10, "pre-condition: need at least 10 msgs per page"); + let mut book = book_for::(&page); + Pages::::insert(Here, 0, page); + + // Call it a few times each with a random weight limit. + let mut rng = rand::rngs::StdRng::seed_from_u64(42); + while msgs > 0 { + let process = rng.gen_range(0..=msgs); + msgs -= process; + + // Enough weight to process `process` messages. + let mut meter = WeightMeter::from_limit(((2 + (3 + 1) * process) as u64).into_weight()); + System::reset_events(); + let (processed, status) = + crate::Pallet::::service_page(&Here, &mut book, &mut meter, Weight::MAX); + assert_eq!(processed as usize, process); + assert_eq!(NumMessagesProcessed::take(), process); + assert_eq!(System::events().len(), process); + if msgs == 0 { + assert_eq!(status, NoMore); + } else { + assert_eq!(status, Bailed); + } + } + assert!(!Pages::::contains_key(Here, 0), "The page got removed"); + }); +} + +// `service_page` does nothing when called with an insufficient weight limit. +#[test] +fn service_page_bails() { + // Not enough weight for `service_page_base_completion`. + new_test_ext::().execute_with(|| { + set_weight("service_page_base_completion", 2.into_weight()); + let mut meter = WeightMeter::from_limit(1.into_weight()); + + let (page, _) = full_page::(); + let mut book = book_for::(&page); + Pages::::insert(MessageOrigin::Here, 0, page); + + assert_storage_noop!(MessageQueue::service_page( + &MessageOrigin::Here, + &mut book, + &mut meter, + Weight::MAX + )); + assert!(meter.consumed.is_zero()); + }); + // Not enough weight for `service_page_base_no_completion`. + new_test_ext::().execute_with(|| { + set_weight("service_page_base_no_completion", 2.into_weight()); + let mut meter = WeightMeter::from_limit(1.into_weight()); + + let (page, _) = full_page::(); + let mut book = book_for::(&page); + Pages::::insert(MessageOrigin::Here, 0, page); + + assert_storage_noop!(MessageQueue::service_page( + &MessageOrigin::Here, + &mut book, + &mut meter, + Weight::MAX + )); + assert!(meter.consumed.is_zero()); + }); +} + +#[test] +fn service_page_item_bails() { + new_test_ext::().execute_with(|| { + let _guard = StorageNoopGuard::default(); + let (mut page, _) = full_page::(); + let mut weight = WeightMeter::from_limit(10.into_weight()); + let overweight_limit = 10.into_weight(); + set_weight("service_page_item", 11.into_weight()); + + assert_eq!( + MessageQueue::service_page_item( + &MessageOrigin::Here, + 0, + &mut book_for::(&page), + &mut page, + &mut weight, + overweight_limit, + ), + ItemExecutionStatus::Bailed + ); + }); +} + +#[test] +fn bump_service_head_works() { + use MessageOrigin::*; + new_test_ext::().execute_with(|| { + // Create a ready ring with three queues. + BookStateFor::::insert(Here, empty_book::()); + knit(&Here); + BookStateFor::::insert(There, empty_book::()); + knit(&There); + BookStateFor::::insert(Everywhere(0), empty_book::()); + knit(&Everywhere(0)); + + // Bump 99 times. + for i in 0..99 { + let current = MessageQueue::bump_service_head(&mut WeightMeter::max_limit()).unwrap(); + assert_eq!(current, [Here, There, Everywhere(0)][i % 3]); + } + + // The ready ring is intact and the service head is still `Here`. + assert_ring(&[Here, There, Everywhere(0)]); + }); +} + +/// `bump_service_head` does nothing when called with an insufficient weight limit. +#[test] +fn bump_service_head_bails() { + new_test_ext::().execute_with(|| { + set_weight("bump_service_head", 2.into_weight()); + setup_bump_service_head::(0.into(), 10.into()); + + let _guard = StorageNoopGuard::default(); + let mut meter = WeightMeter::from_limit(1.into_weight()); + assert!(MessageQueue::bump_service_head(&mut meter).is_none()); + assert_eq!(meter.consumed, 0.into_weight()); + }); +} + +#[test] +fn bump_service_head_trivial_works() { + new_test_ext::().execute_with(|| { + set_weight("bump_service_head", 2.into_weight()); + let mut meter = WeightMeter::max_limit(); + + assert_eq!(MessageQueue::bump_service_head(&mut meter), None, "Cannot bump"); + assert_eq!(meter.consumed, 2.into_weight()); + + setup_bump_service_head::(0.into(), 1.into()); + + assert_eq!(MessageQueue::bump_service_head(&mut meter), Some(0.into())); + assert_eq!(ServiceHead::::get().unwrap(), 1.into(), "Bumped the head"); + assert_eq!(meter.consumed, 4.into_weight()); + + assert_eq!(MessageQueue::bump_service_head(&mut meter), None, "Cannot bump"); + assert_eq!(meter.consumed, 6.into_weight()); + }); +} + +#[test] +fn bump_service_head_no_head_noops() { + use MessageOrigin::*; + new_test_ext::().execute_with(|| { + // Create a ready ring with three queues. + BookStateFor::::insert(Here, empty_book::()); + knit(&Here); + BookStateFor::::insert(There, empty_book::()); + knit(&There); + BookStateFor::::insert(Everywhere(0), empty_book::()); + knit(&Everywhere(0)); + + // But remove the service head. + ServiceHead::::kill(); + + // Nothing happens. + assert_storage_noop!(MessageQueue::bump_service_head(&mut WeightMeter::max_limit())); + }); +} + +#[test] +fn service_page_item_consumes_correct_weight() { + new_test_ext::().execute_with(|| { + let mut page = page::(b"weight=3"); + let mut weight = WeightMeter::from_limit(10.into_weight()); + let overweight_limit = 0.into_weight(); + set_weight("service_page_item", 2.into_weight()); + + assert_eq!( + MessageQueue::service_page_item( + &MessageOrigin::Here, + 0, + &mut book_for::(&page), + &mut page, + &mut weight, + overweight_limit + ), + ItemExecutionStatus::Executed(true) + ); + assert_eq!(weight.consumed, 5.into_weight()); + }); +} + +/// `service_page_item` skips a permanently `Overweight` message and marks it as `unprocessed`. +#[test] +fn service_page_item_skips_perm_overweight_message() { + new_test_ext::().execute_with(|| { + let mut page = page::(b"TooMuch"); + let mut weight = WeightMeter::from_limit(2.into_weight()); + let overweight_limit = 0.into_weight(); + set_weight("service_page_item", 2.into_weight()); + + assert_eq!( + crate::Pallet::::service_page_item( + &MessageOrigin::Here, + 0, + &mut book_for::(&page), + &mut page, + &mut weight, + overweight_limit + ), + ItemExecutionStatus::Executed(false) + ); + assert_eq!(weight.consumed, 2.into_weight()); + assert_last_event::( + Event::OverweightEnqueued { + hash: ::Hashing::hash(b"TooMuch"), + origin: MessageOrigin::Here, + message_index: 0, + page_index: 0, + } + .into(), + ); + + // Check that the message was skipped. + let (pos, processed, payload) = page.peek_index(0).unwrap(); + assert_eq!(pos, 0); + assert!(!processed); + assert_eq!(payload, b"TooMuch".encode()); + }); +} + +#[test] +fn peek_index_works() { + use super::integration_test::Test; // Run with larger page size. + new_test_ext::().execute_with(|| { + // Fill a page with messages. + let (mut page, msgs) = full_page::(); + let msg_enc_len = ItemHeader::<::Size>::max_encoded_len() + 4; + + for i in 0..msgs { + // Skip all even messages. + page.skip_first(i % 2 == 0); + // Peek each message and check that it is correct. + let (pos, processed, payload) = page.peek_index(i).unwrap(); + assert_eq!(pos, msg_enc_len * i); + assert_eq!(processed, i % 2 == 0); + // `full_page` uses the index as payload. + assert_eq!(payload, (i as u32).encode()); + } + }); +} + +#[test] +fn peek_first_and_skip_first_works() { + use super::integration_test::Test; // Run with larger page size. + new_test_ext::().execute_with(|| { + // Fill a page with messages. + let (mut page, msgs) = full_page::(); + + for i in 0..msgs { + let msg = page.peek_first().unwrap(); + // `full_page` uses the index as payload. + assert_eq!(msg.deref(), (i as u32).encode()); + page.skip_first(i % 2 == 0); // True of False should not matter here. + } + assert!(page.peek_first().is_none(), "Page must be at the end"); + + // Check that all messages were correctly marked as (un)processed. + for i in 0..msgs { + let (_, processed, _) = page.peek_index(i).unwrap(); + assert_eq!(processed, i % 2 == 0); + } + }); +} + +#[test] +fn note_processed_at_pos_works() { + use super::integration_test::Test; // Run with larger page size. + new_test_ext::().execute_with(|| { + let (mut page, msgs) = full_page::(); + + for i in 0..msgs { + let (pos, processed, _) = page.peek_index(i).unwrap(); + assert!(!processed); + assert_eq!(page.remaining as usize, msgs - i); + + page.note_processed_at_pos(pos); + + let (_, processed, _) = page.peek_index(i).unwrap(); + assert!(processed); + assert_eq!(page.remaining as usize, msgs - i - 1); + } + // `skip_first` still works fine. + for _ in 0..msgs { + page.peek_first().unwrap(); + page.skip_first(false); + } + assert!(page.peek_first().is_none()); + }); +} + +#[test] +fn note_processed_at_pos_idempotent() { + let (mut page, _) = full_page::(); + page.note_processed_at_pos(0); + + let original = page.clone(); + page.note_processed_at_pos(0); + assert_eq!(page.heap, original.heap); +} + +#[test] +fn is_complete_works() { + use super::integration_test::Test; // Run with larger page size. + new_test_ext::().execute_with(|| { + let (mut page, msgs) = full_page::(); + assert!(msgs > 3, "Boring"); + let msg_enc_len = ItemHeader::<::Size>::max_encoded_len() + 4; + + assert!(!page.is_complete()); + for i in 0..msgs { + if i % 2 == 0 { + page.skip_first(false); + } else { + page.note_processed_at_pos(msg_enc_len * i); + } + } + // Not complete since `skip_first` was called with `false`. + assert!(!page.is_complete()); + for i in 0..msgs { + if i % 2 == 0 { + assert!(!page.is_complete()); + let (pos, _, _) = page.peek_index(i).unwrap(); + page.note_processed_at_pos(pos); + } + } + assert!(page.is_complete()); + assert_eq!(page.remaining_size, 0); + // Each message is marked as processed. + for i in 0..msgs { + let (_, processed, _) = page.peek_index(i).unwrap(); + assert!(processed); + } + }); +} + +#[test] +fn page_from_message_basic_works() { + assert!(MaxMessageLenOf::::get() > 0, "pre-condition unmet"); + let mut msg: BoundedVec> = Default::default(); + msg.bounded_resize(MaxMessageLenOf::::get() as usize, 123); + + let page = PageOf::::from_message::(msg.as_bounded_slice()); + assert_eq!(page.remaining, 1); + assert_eq!(page.remaining_size as usize, msg.len()); + assert!(page.first_index == 0 && page.first == 0 && page.last == 0); + + // Verify the content of the heap. + let mut heap = Vec::::new(); + let header = + ItemHeader::<::Size> { payload_len: msg.len() as u32, is_processed: false }; + heap.extend(header.encode()); + heap.extend(msg.deref()); + assert_eq!(page.heap, heap); +} + +#[test] +fn page_try_append_message_basic_works() { + use super::integration_test::Test; // Run with larger page size. + + let mut page = PageOf::::default(); + let mut msgs = 0; + // Append as many 4-byte message as possible. + for i in 0..u32::MAX { + let r = i.using_encoded(|i| page.try_append_message::(i.try_into().unwrap())); + if r.is_err() { + break + } else { + msgs += 1; + } + } + let expected_msgs = (::HeapSize::get()) / + (ItemHeader::<::Size>::max_encoded_len() as u32 + 4); + assert_eq!(expected_msgs, msgs, "Wrong number of messages"); + assert_eq!(page.remaining, msgs); + assert_eq!(page.remaining_size, msgs * 4); + + // Verify that the heap content is correct. + let mut heap = Vec::::new(); + for i in 0..msgs { + let header = ItemHeader::<::Size> { payload_len: 4, is_processed: false }; + heap.extend(header.encode()); + heap.extend(i.encode()); + } + assert_eq!(page.heap, heap); +} + +#[test] +fn page_try_append_message_max_msg_len_works_works() { + use super::integration_test::Test; // Run with larger page size. + + // We start off with an empty page. + let mut page = PageOf::::default(); + // … and append a message with maximum possible length. + let msg = vec![123u8; MaxMessageLenOf::::get() as usize]; + // … which works. + page.try_append_message::(BoundedSlice::defensive_truncate_from(&msg)) + .unwrap(); + // Now we cannot append *anything* since the heap is full. + page.try_append_message::(BoundedSlice::defensive_truncate_from(&[])) + .unwrap_err(); + assert_eq!(page.heap.len(), ::HeapSize::get() as usize); +} + +#[test] +fn page_try_append_message_with_remaining_size_works_works() { + use super::integration_test::Test; // Run with larger page size. + let header_size = ItemHeader::<::Size>::max_encoded_len(); + + // We start off with an empty page. + let mut page = PageOf::::default(); + let mut remaining = ::HeapSize::get() as usize; + let mut msgs = Vec::new(); + let mut rng = StdRng::seed_from_u64(42); + // Now we keep appending messages with different lengths. + while remaining >= header_size { + let take = rng.gen_range(0..=(remaining - header_size)); + let msg = vec![123u8; take]; + page.try_append_message::(BoundedSlice::defensive_truncate_from(&msg)) + .unwrap(); + remaining -= take + header_size; + msgs.push(msg); + } + // Cannot even fit a single header in there now. + assert!(remaining < header_size); + assert_eq!(::HeapSize::get() as usize - page.heap.len(), remaining); + assert_eq!(page.remaining as usize, msgs.len()); + assert_eq!( + page.remaining_size as usize, + msgs.iter().fold(0, |mut a, m| { + a += m.len(); + a + }) + ); + // Verify the heap content. + let mut heap = Vec::new(); + for msg in msgs.into_iter() { + let header = ItemHeader::<::Size> { + payload_len: msg.len() as u32, + is_processed: false, + }; + heap.extend(header.encode()); + heap.extend(msg); + } + assert_eq!(page.heap, heap); +} + +// `Page::from_message` does not panic when called with the maximum message and origin lengths. +#[test] +fn page_from_message_max_len_works() { + let max_msg_len: usize = MaxMessageLenOf::::get() as usize; + + let page = PageOf::::from_message::(vec![1; max_msg_len][..].try_into().unwrap()); + + assert_eq!(page.remaining, 1); +} + +#[test] +fn sweep_queue_works() { + use MessageOrigin::*; + new_test_ext::().execute_with(|| { + build_triple_ring(); + + let book = BookStateFor::::get(Here); + assert!(book.begin != book.end); + // Removing the service head works + assert_eq!(ServiceHead::::get(), Some(Here)); + MessageQueue::sweep_queue(Here); + assert_ring(&[There, Everywhere(0)]); + // The book still exits, but has updated begin and end. + let book = BookStateFor::::get(Here); + assert_eq!(book.begin, book.end); + + // Removing something that is not the service head works. + assert!(ServiceHead::::get() != Some(Everywhere(0))); + MessageQueue::sweep_queue(Everywhere(0)); + assert_ring(&[There]); + // The book still exits, but has updated begin and end. + let book = BookStateFor::::get(Everywhere(0)); + assert_eq!(book.begin, book.end); + + MessageQueue::sweep_queue(There); + // The book still exits, but has updated begin and end. + let book = BookStateFor::::get(There); + assert_eq!(book.begin, book.end); + assert_ring(&[]); + + // Sweeping a queue never calls OnQueueChanged. + assert!(QueueChanges::take().is_empty()); + }) +} + +/// Test that `sweep_queue` also works if the ReadyRing wraps around. +#[test] +fn sweep_queue_wraps_works() { + use MessageOrigin::*; + new_test_ext::().execute_with(|| { + BookStateFor::::insert(Here, empty_book::()); + knit(&Here); + + MessageQueue::sweep_queue(Here); + let book = BookStateFor::::get(Here); + assert!(book.ready_neighbours.is_none()); + }); +} + +#[test] +fn sweep_queue_invalid_noops() { + use MessageOrigin::*; + new_test_ext::().execute_with(|| { + assert_storage_noop!(MessageQueue::sweep_queue(Here)); + }); +} + +#[test] +fn footprint_works() { + new_test_ext::().execute_with(|| { + let origin = MessageOrigin::Here; + let (page, msgs) = full_page::(); + let book = book_for::(&page); + BookStateFor::::insert(origin, book); + + let info = MessageQueue::footprint(origin); + assert_eq!(info.count as usize, msgs); + assert_eq!(info.size, page.remaining_size as u64); + + // Sweeping a queue never calls OnQueueChanged. + assert!(QueueChanges::take().is_empty()); + }) +} + +/// The footprint of an invalid queue is the default footprint. +#[test] +fn footprint_invalid_works() { + new_test_ext::().execute_with(|| { + let origin = MessageOrigin::Here; + assert_eq!(MessageQueue::footprint(origin), Default::default()); + }) +} + +/// The footprint of a swept queue is still correct. +#[test] +fn footprint_on_swept_works() { + use MessageOrigin::*; + new_test_ext::().execute_with(|| { + let mut book = empty_book::(); + book.message_count = 3; + book.size = 10; + BookStateFor::::insert(Here, &book); + knit(&Here); + + MessageQueue::sweep_queue(Here); + let fp = MessageQueue::footprint(Here); + assert_eq!(fp.count, 3); + assert_eq!(fp.size, 10); + }) +} + +#[test] +fn execute_overweight_works() { + new_test_ext::().execute_with(|| { + set_weight("bump_service_head", 1.into_weight()); + set_weight("service_queue_base", 1.into_weight()); + set_weight("service_page_base_completion", 1.into_weight()); + + // Enqueue a message + let origin = MessageOrigin::Here; + MessageQueue::enqueue_message(msg("weight=6"), origin); + // Load the current book + let book = BookStateFor::::get(origin); + assert_eq!(book.message_count, 1); + assert!(Pages::::contains_key(origin, 0)); + + // Mark the message as permanently overweight. + assert_eq!(MessageQueue::service_queues(4.into_weight()), 4.into_weight()); + assert_eq!(QueueChanges::take(), vec![(origin, 1, 8)]); + assert_last_event::( + Event::OverweightEnqueued { + hash: ::Hashing::hash(b"weight=6"), + origin: MessageOrigin::Here, + message_index: 0, + page_index: 0, + } + .into(), + ); + + // Now try to execute it with too few weight. + let consumed = + ::execute_overweight(5.into_weight(), (origin, 0, 0)); + assert_eq!(consumed, Err(ExecuteOverweightError::InsufficientWeight)); + + // Execute it with enough weight. + assert_eq!(Pages::::iter().count(), 1); + assert!(QueueChanges::take().is_empty()); + let consumed = + ::execute_overweight(7.into_weight(), (origin, 0, 0)) + .unwrap(); + assert_eq!(consumed, 6.into_weight()); + assert_eq!(QueueChanges::take(), vec![(origin, 0, 0)]); + // There is no message left in the book. + let book = BookStateFor::::get(origin); + assert_eq!(book.message_count, 0); + // And no more pages. + assert_eq!(Pages::::iter().count(), 0); + + // Doing it again with enough weight will error. + let consumed = + ::execute_overweight(70.into_weight(), (origin, 0, 0)); + assert_eq!(consumed, Err(ExecuteOverweightError::NotFound)); + assert!(QueueChanges::take().is_empty()); + assert!(!Pages::::contains_key(origin, 0), "Page is gone"); + }); +} + +/// Checks that (un)knitting the ready ring works with just one queue. +/// +/// This case is interesting since it wraps and a lot of `mutate` now operate on the same object. +#[test] +fn ready_ring_knit_basic_works() { + use MessageOrigin::*; + + new_test_ext::().execute_with(|| { + BookStateFor::::insert(Here, empty_book::()); + + for i in 0..10 { + if i % 2 == 0 { + knit(&Here); + assert_ring(&[Here]); + } else { + unknit(&Here); + assert_ring(&[]); + } + } + assert_ring(&[]); + }); +} + +#[test] +fn ready_ring_knit_and_unknit_works() { + use MessageOrigin::*; + + new_test_ext::().execute_with(|| { + // Place three queues into the storage. + BookStateFor::::insert(Here, empty_book::()); + BookStateFor::::insert(There, empty_book::()); + BookStateFor::::insert(Everywhere(0), empty_book::()); + + // Knit them into the ready ring. + assert_ring(&[]); + knit(&Here); + assert_ring(&[Here]); + knit(&There); + assert_ring(&[Here, There]); + knit(&Everywhere(0)); + assert_ring(&[Here, There, Everywhere(0)]); + + // Now unknit… + unknit(&Here); + assert_ring(&[There, Everywhere(0)]); + unknit(&There); + assert_ring(&[Everywhere(0)]); + unknit(&Everywhere(0)); + assert_ring(&[]); + }); +} + +#[test] +fn enqueue_message_works() { + use MessageOrigin::*; + let max_msg_per_page = ::HeapSize::get() as u64 / + (ItemHeader::<::Size>::max_encoded_len() as u64 + 1); + + new_test_ext::().execute_with(|| { + // Enqueue messages which should fill three pages. + let n = max_msg_per_page * 3; + for i in 1..=n { + MessageQueue::enqueue_message(msg("a"), Here); + assert_eq!(QueueChanges::take(), vec![(Here, i, i)], "OnQueueChanged not called"); + } + assert_eq!(Pages::::iter().count(), 3); + + // Enqueue one more onto page 4. + MessageQueue::enqueue_message(msg("abc"), Here); + assert_eq!(QueueChanges::take(), vec![(Here, n + 1, n + 3)]); + assert_eq!(Pages::::iter().count(), 4); + + // Check the state. + assert_eq!(BookStateFor::::iter().count(), 1); + let book = BookStateFor::::get(Here); + assert_eq!(book.message_count, n + 1); + assert_eq!(book.size, n + 3); + assert_eq!((book.begin, book.end), (0, 4)); + assert_eq!(book.count as usize, Pages::::iter().count()); + }); +} + +#[test] +fn enqueue_messages_works() { + use MessageOrigin::*; + let max_msg_per_page = ::HeapSize::get() as u64 / + (ItemHeader::<::Size>::max_encoded_len() as u64 + 1); + + new_test_ext::().execute_with(|| { + // Enqueue messages which should fill three pages. + let n = max_msg_per_page * 3; + let msgs = vec![msg("a"); n as usize]; + + // Now queue all messages at once. + MessageQueue::enqueue_messages(msgs.into_iter(), Here); + // The changed handler should only be called once. + assert_eq!(QueueChanges::take(), vec![(Here, n, n)], "OnQueueChanged not called"); + assert_eq!(Pages::::iter().count(), 3); + + // Enqueue one more onto page 4. + MessageQueue::enqueue_message(msg("abc"), Here); + assert_eq!(QueueChanges::take(), vec![(Here, n + 1, n + 3)]); + assert_eq!(Pages::::iter().count(), 4); + + // Check the state. + assert_eq!(BookStateFor::::iter().count(), 1); + let book = BookStateFor::::get(Here); + assert_eq!(book.message_count, n + 1); + assert_eq!(book.size, n + 3); + assert_eq!((book.begin, book.end), (0, 4)); + assert_eq!(book.count as usize, Pages::::iter().count()); + }); +} diff --git a/frame/message-queue/src/weights.rs b/frame/message-queue/src/weights.rs new file mode 100644 index 0000000000000..cd9268ffde224 --- /dev/null +++ b/frame/message-queue/src/weights.rs @@ -0,0 +1,216 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_message_queue +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-12-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// /home/benchbot/cargo_target_dir/production/substrate +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_message_queue +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/message-queue/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_message_queue. +pub trait WeightInfo { + fn ready_ring_knit() -> Weight; + fn ready_ring_unknit() -> Weight; + fn service_queue_base() -> Weight; + fn service_page_base_completion() -> Weight; + fn service_page_base_no_completion() -> Weight; + fn service_page_item() -> Weight; + fn bump_service_head() -> Weight; + fn reap_page() -> Weight; + fn execute_overweight_page_removed() -> Weight; + fn execute_overweight_page_updated() -> Weight; +} + +/// Weights for pallet_message_queue using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: MessageQueue ServiceHead (r:1 w:0) + // Storage: MessageQueue BookStateFor (r:2 w:2) + fn ready_ring_knit() -> Weight { + // Minimum execution time: 12_330 nanoseconds. + Weight::from_ref_time(12_711_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: MessageQueue BookStateFor (r:2 w:2) + // Storage: MessageQueue ServiceHead (r:1 w:1) + fn ready_ring_unknit() -> Weight { + // Minimum execution time: 12_322 nanoseconds. + Weight::from_ref_time(12_560_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + // Storage: MessageQueue BookStateFor (r:1 w:1) + fn service_queue_base() -> Weight { + // Minimum execution time: 4_652 nanoseconds. + Weight::from_ref_time(4_848_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: MessageQueue Pages (r:1 w:1) + fn service_page_base_completion() -> Weight { + // Minimum execution time: 7_115 nanoseconds. + Weight::from_ref_time(7_407_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: MessageQueue Pages (r:1 w:1) + fn service_page_base_no_completion() -> Weight { + // Minimum execution time: 6_974 nanoseconds. + Weight::from_ref_time(7_200_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn service_page_item() -> Weight { + // Minimum execution time: 79_657 nanoseconds. + Weight::from_ref_time(80_050_000) + } + // Storage: MessageQueue ServiceHead (r:1 w:1) + // Storage: MessageQueue BookStateFor (r:1 w:0) + fn bump_service_head() -> Weight { + // Minimum execution time: 7_598 nanoseconds. + Weight::from_ref_time(8_118_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: MessageQueue BookStateFor (r:1 w:1) + // Storage: MessageQueue Pages (r:1 w:1) + fn reap_page() -> Weight { + // Minimum execution time: 60_562 nanoseconds. + Weight::from_ref_time(61_430_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: MessageQueue BookStateFor (r:1 w:1) + // Storage: MessageQueue Pages (r:1 w:1) + fn execute_overweight_page_removed() -> Weight { + // Minimum execution time: 74_582 nanoseconds. + Weight::from_ref_time(75_445_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: MessageQueue BookStateFor (r:1 w:1) + // Storage: MessageQueue Pages (r:1 w:1) + fn execute_overweight_page_updated() -> Weight { + // Minimum execution time: 87_526 nanoseconds. + Weight::from_ref_time(88_055_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: MessageQueue ServiceHead (r:1 w:0) + // Storage: MessageQueue BookStateFor (r:2 w:2) + fn ready_ring_knit() -> Weight { + // Minimum execution time: 12_330 nanoseconds. + Weight::from_ref_time(12_711_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: MessageQueue BookStateFor (r:2 w:2) + // Storage: MessageQueue ServiceHead (r:1 w:1) + fn ready_ring_unknit() -> Weight { + // Minimum execution time: 12_322 nanoseconds. + Weight::from_ref_time(12_560_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) + } + // Storage: MessageQueue BookStateFor (r:1 w:1) + fn service_queue_base() -> Weight { + // Minimum execution time: 4_652 nanoseconds. + Weight::from_ref_time(4_848_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: MessageQueue Pages (r:1 w:1) + fn service_page_base_completion() -> Weight { + // Minimum execution time: 7_115 nanoseconds. + Weight::from_ref_time(7_407_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: MessageQueue Pages (r:1 w:1) + fn service_page_base_no_completion() -> Weight { + // Minimum execution time: 6_974 nanoseconds. + Weight::from_ref_time(7_200_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + fn service_page_item() -> Weight { + // Minimum execution time: 79_657 nanoseconds. + Weight::from_ref_time(80_050_000) + } + // Storage: MessageQueue ServiceHead (r:1 w:1) + // Storage: MessageQueue BookStateFor (r:1 w:0) + fn bump_service_head() -> Weight { + // Minimum execution time: 7_598 nanoseconds. + Weight::from_ref_time(8_118_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: MessageQueue BookStateFor (r:1 w:1) + // Storage: MessageQueue Pages (r:1 w:1) + fn reap_page() -> Weight { + // Minimum execution time: 60_562 nanoseconds. + Weight::from_ref_time(61_430_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: MessageQueue BookStateFor (r:1 w:1) + // Storage: MessageQueue Pages (r:1 w:1) + fn execute_overweight_page_removed() -> Weight { + // Minimum execution time: 74_582 nanoseconds. + Weight::from_ref_time(75_445_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: MessageQueue BookStateFor (r:1 w:1) + // Storage: MessageQueue Pages (r:1 w:1) + fn execute_overweight_page_updated() -> Weight { + // Minimum execution time: 87_526 nanoseconds. + Weight::from_ref_time(88_055_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } +} diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 86ca63c753bea..25ac602681cc0 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -19,6 +19,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } [dev-dependencies] pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } @@ -42,5 +43,6 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "sp-weights/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 78533540be98f..2e0d0c6be1db5 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -73,7 +73,6 @@ use frame_support::{ weights::{Weight, WeightMeter}, }; use frame_system::{self as system}; -pub use pallet::*; use scale_info::TypeInfo; use sp_io::hashing::blake2_256; use sp_runtime::{ @@ -81,6 +80,8 @@ use sp_runtime::{ BoundedVec, RuntimeDebug, }; use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*}; + +pub use pallet::*; pub use weights::WeightInfo; /// Just a simple index for naming period tasks. diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index e5ba98fe0c5bb..63c86c1f68459 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -112,6 +112,12 @@ pub use voting::{ mod preimages; pub use preimages::{Bounded, BoundedInline, FetchResult, Hash, QueryPreimage, StorePreimage}; +mod messages; +pub use messages::{ + EnqueueMessage, ExecuteOverweightError, Footprint, ProcessMessage, ProcessMessageError, + ServiceQueues, +}; + #[cfg(feature = "try-runtime")] mod try_runtime; #[cfg(feature = "try-runtime")] diff --git a/frame/support/src/traits/messages.rs b/frame/support/src/traits/messages.rs new file mode 100644 index 0000000000000..9b86c421ad9e0 --- /dev/null +++ b/frame/support/src/traits/messages.rs @@ -0,0 +1,202 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Traits for managing message queuing and handling. + +use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::{ConstU32, Get, TypedGet}; +use sp_runtime::{traits::Convert, BoundedSlice, RuntimeDebug}; +use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; +use sp_weights::Weight; + +/// Errors that can happen when attempting to process a message with +/// [`ProcessMessage::process_message()`]. +#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, TypeInfo, RuntimeDebug)] +pub enum ProcessMessageError { + /// The message data format is unknown (e.g. unrecognised header) + BadFormat, + /// The message data is bad (e.g. decoding returns an error). + Corrupt, + /// The message format is unsupported (e.g. old XCM version). + Unsupported, + /// Message processing was not attempted because it was not certain that the weight limit + /// would be respected. The parameter gives the maximum weight which the message could take + /// to process. + Overweight(Weight), +} + +/// Can process messages from a specific origin. +pub trait ProcessMessage { + /// The transport from where a message originates. + type Origin: FullCodec + MaxEncodedLen + Clone + Eq + PartialEq + TypeInfo + Debug; + + /// Process the given message, using no more than `weight_limit` in weight to do so. + fn process_message( + message: &[u8], + origin: Self::Origin, + weight_limit: Weight, + ) -> Result<(bool, Weight), ProcessMessageError>; +} + +/// Errors that can happen when attempting to execute an overweight message with +/// [`ServiceQueues::execute_overweight()`]. +#[derive(Eq, PartialEq, RuntimeDebug)] +pub enum ExecuteOverweightError { + /// The referenced message was not found. + NotFound, + /// The available weight was insufficient to execute the message. + InsufficientWeight, +} + +/// Can service queues and execute overweight messages. +pub trait ServiceQueues { + /// Addresses a specific overweight message. + type OverweightMessageAddress; + + /// Service all message queues in some fair manner. + /// + /// - `weight_limit`: The maximum amount of dynamic weight that this call can use. + /// + /// Returns the dynamic weight used by this call; is never greater than `weight_limit`. + fn service_queues(weight_limit: Weight) -> Weight; + + /// Executes a message that could not be executed by [`Self::service_queues()`] because it was + /// temporarily overweight. + fn execute_overweight( + _weight_limit: Weight, + _address: Self::OverweightMessageAddress, + ) -> Result { + Err(ExecuteOverweightError::NotFound) + } +} + +/// The resource footprint of a queue. +#[derive(Default, Copy, Clone, Eq, PartialEq, RuntimeDebug)] +pub struct Footprint { + pub count: u64, + pub size: u64, +} + +/// Can enqueue messages for multiple origins. +pub trait EnqueueMessage { + /// The maximal length any enqueued message may have. + type MaxMessageLen: Get; + + /// Enqueue a single `message` from a specific `origin`. + fn enqueue_message(message: BoundedSlice, origin: Origin); + + /// Enqueue multiple `messages` from a specific `origin`. + fn enqueue_messages<'a>( + messages: impl Iterator>, + origin: Origin, + ); + + /// Any remaining unprocessed messages should happen only lazily, not proactively. + fn sweep_queue(origin: Origin); + + /// Return the state footprint of the given queue. + fn footprint(origin: Origin) -> Footprint; +} + +impl EnqueueMessage for () { + type MaxMessageLen = ConstU32<0>; + fn enqueue_message(_: BoundedSlice, _: Origin) {} + fn enqueue_messages<'a>( + _: impl Iterator>, + _: Origin, + ) { + } + fn sweep_queue(_: Origin) {} + fn footprint(_: Origin) -> Footprint { + Footprint::default() + } +} + +/// Transform the origin of an [`EnqueueMessage`] via `C::convert`. +pub struct TransformOrigin(PhantomData<(E, O, N, C)>); +impl, O: MaxEncodedLen, N: MaxEncodedLen, C: Convert> EnqueueMessage + for TransformOrigin +{ + type MaxMessageLen = E::MaxMessageLen; + + fn enqueue_message(message: BoundedSlice, origin: N) { + E::enqueue_message(message, C::convert(origin)); + } + + fn enqueue_messages<'a>( + messages: impl Iterator>, + origin: N, + ) { + E::enqueue_messages(messages, C::convert(origin)); + } + + fn sweep_queue(origin: N) { + E::sweep_queue(C::convert(origin)); + } + + fn footprint(origin: N) -> Footprint { + E::footprint(C::convert(origin)) + } +} + +/// Handles incoming messages for a single origin. +pub trait HandleMessage { + /// The maximal length any enqueued message may have. + type MaxMessageLen: Get; + + /// Enqueue a single `message` with an implied origin. + fn handle_message(message: BoundedSlice); + + /// Enqueue multiple `messages` from an implied origin. + fn handle_messages<'a>( + messages: impl Iterator>, + ); + + /// Any remaining unprocessed messages should happen only lazily, not proactively. + fn sweep_queue(); + + /// Return the state footprint of the queue. + fn footprint() -> Footprint; +} + +/// Adapter type to transform an [`EnqueueMessage`] with an origin into a [`HandleMessage`] impl. +pub struct EnqueueWithOrigin(PhantomData<(E, O)>); +impl, O: TypedGet> HandleMessage for EnqueueWithOrigin +where + O::Type: MaxEncodedLen, +{ + type MaxMessageLen = E::MaxMessageLen; + + fn handle_message(message: BoundedSlice) { + E::enqueue_message(message, O::get()); + } + + fn handle_messages<'a>( + messages: impl Iterator>, + ) { + E::enqueue_messages(messages, O::get()); + } + + fn sweep_queue() { + E::sweep_queue(O::get()); + } + + fn footprint() -> Footprint { + E::footprint(O::get()) + } +} diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index 42ef5a34e4c30..999d8585c221a 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` @@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) - and 161 others + and 162 others = note: required for `Bar` to implement `StaticTypeInfo` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 461d63ebb0d9c..e2870ffb9e86f 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` @@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) - and 161 others + and 162 others = note: required for `Bar` to implement `StaticTypeInfo` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` diff --git a/primitives/core/src/bounded/bounded_vec.rs b/primitives/core/src/bounded/bounded_vec.rs index 2f39f3340ce50..6e1e1c7cfda64 100644 --- a/primitives/core/src/bounded/bounded_vec.rs +++ b/primitives/core/src/bounded/bounded_vec.rs @@ -675,6 +675,13 @@ impl> BoundedVec { } } +impl BoundedVec { + /// Return a [`BoundedSlice`] with the content and bound of [`Self`]. + pub fn as_bounded_slice(&self) -> BoundedSlice { + BoundedSlice(&self.0[..], PhantomData::default()) + } +} + impl Default for BoundedVec { fn default() -> Self { // the bound cannot be below 0, which is satisfied by an empty vector diff --git a/primitives/weights/src/weight_meter.rs b/primitives/weights/src/weight_meter.rs index d03e72968bb09..17c5da1502e9e 100644 --- a/primitives/weights/src/weight_meter.rs +++ b/primitives/weights/src/weight_meter.rs @@ -71,6 +71,12 @@ impl WeightMeter { time.max(pov) } + /// Consume some weight and defensively fail if it is over the limit. Saturate in any case. + pub fn defensive_saturating_accrue(&mut self, w: Weight) { + self.consumed.saturating_accrue(w); + debug_assert!(self.consumed.all_lte(self.limit), "Weight counter overflow"); + } + /// Consume the given weight after checking that it can be consumed. Otherwise do nothing. pub fn check_accrue(&mut self, w: Weight) -> bool { self.consumed.checked_add(&w).map_or(false, |test| { From f0b6e79a8d21856743acc5370b5d5c3271048cb9 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Fri, 9 Dec 2022 13:47:04 +0100 Subject: [PATCH 1457/1472] zombienet timings adjusted (#12890) * zombinet tests: add some timeout to allow net spin-up Sometimes tests are failing at first try, as the pods were not up yet. Adding timeout should allow the network to spin up properly. * initial timeout increased to 30s --- zombienet/0000-block-building/block-building.zndsl | 4 ++-- zombienet/0001-basic-warp-sync/test-warp-sync.zndsl | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/zombienet/0000-block-building/block-building.zndsl b/zombienet/0000-block-building/block-building.zndsl index c53e50915c202..86a54773484b3 100644 --- a/zombienet/0000-block-building/block-building.zndsl +++ b/zombienet/0000-block-building/block-building.zndsl @@ -2,8 +2,8 @@ Description: Block building Network: ./block-building.toml Creds: config -alice: is up -bob: is up +alice: is up within 30 seconds +bob: is up within 30 seconds alice: reports node_roles is 4 bob: reports node_roles is 4 diff --git a/zombienet/0001-basic-warp-sync/test-warp-sync.zndsl b/zombienet/0001-basic-warp-sync/test-warp-sync.zndsl index 1ccacb2e6d038..8ceb61c8b039d 100644 --- a/zombienet/0001-basic-warp-sync/test-warp-sync.zndsl +++ b/zombienet/0001-basic-warp-sync/test-warp-sync.zndsl @@ -2,10 +2,10 @@ Description: Warp sync Network: ./test-warp-sync.toml Creds: config -alice: is up -bob: is up -charlie: is up -dave: is up +alice: is up within 30 seconds +bob: is up within 30 seconds +charlie: is up within 30 seconds +dave: is up within 30 seconds alice: reports node_roles is 1 bob: reports node_roles is 1 From 9931220910f9fb65227fe4571842f800d61c7b95 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Fri, 9 Dec 2022 21:50:57 +0200 Subject: [PATCH 1458/1472] Move import queue out of `sc-network` (#12764) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move import queue out of `sc-network` Add supplementary asynchronous API for the import queue which means it can be run as an independent task and communicated with through the `ImportQueueService`. This commit removes removes block and justification imports from `sc-network` and provides `ChainSync` with a handle to import queue so it can import blocks and justifications. Polling of the import queue is moved complete out of `sc-network` and `sc_consensus::Link` is implemented for `ChainSyncInterfaceHandled` so the import queue can still influence the syncing process. * Fix tests * Apply review comments * Apply suggestions from code review Co-authored-by: Bastian Köcher * Update client/network/sync/src/lib.rs Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- Cargo.lock | 2 + client/consensus/common/Cargo.toml | 1 + client/consensus/common/src/import_queue.rs | 23 +- .../common/src/import_queue/basic_queue.rs | 69 ++- .../common/src/import_queue/buffered_link.rs | 32 +- .../consensus/common/src/import_queue/mock.rs | 46 ++ client/network/common/src/sync.rs | 28 +- client/network/src/behaviour.rs | 31 +- client/network/src/config.rs | 7 - client/network/src/lib.rs | 9 +- client/network/src/protocol.rs | 107 +--- client/network/src/service.rs | 88 +--- client/network/src/service/metrics.rs | 10 - .../network/src/service/tests/chain_sync.rs | 106 ++-- client/network/src/service/tests/mod.rs | 40 +- client/network/sync/Cargo.toml | 1 + client/network/sync/src/lib.rs | 483 ++++++++++++------ client/network/sync/src/mock.rs | 14 +- client/network/sync/src/service/chain_sync.rs | 53 ++ client/network/sync/src/service/mock.rs | 33 +- client/network/sync/src/tests.rs | 3 + client/network/test/src/lib.rs | 12 +- client/service/src/builder.rs | 6 +- client/service/src/chain_ops/import_blocks.rs | 2 +- 24 files changed, 716 insertions(+), 490 deletions(-) create mode 100644 client/consensus/common/src/import_queue/mock.rs diff --git a/Cargo.lock b/Cargo.lock index 41c641cf05963..8225e557141d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7328,6 +7328,7 @@ dependencies = [ "futures-timer", "libp2p", "log", + "mockall", "parking_lot 0.12.1", "sc-client-api", "sc-utils", @@ -7929,6 +7930,7 @@ dependencies = [ "sp-runtime", "sp-test-primitives", "sp-tracing", + "substrate-prometheus-endpoint", "substrate-test-runtime-client", "thiserror", "tokio", diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 971ee71ab8040..b61c6a4334285 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -18,6 +18,7 @@ futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" +mockall = "0.11.2" parking_lot = "0.12.1" serde = { version = "1.0", features = ["derive"] } thiserror = "1.0.30" diff --git a/client/consensus/common/src/import_queue.rs b/client/consensus/common/src/import_queue.rs index 3741fa99663cd..d49b240ef3489 100644 --- a/client/consensus/common/src/import_queue.rs +++ b/client/consensus/common/src/import_queue.rs @@ -53,6 +53,7 @@ pub type DefaultImportQueue = mod basic_queue; pub mod buffered_link; +pub mod mock; /// Shared block import struct used by the queue. pub type BoxBlockImport = @@ -105,10 +106,10 @@ pub trait Verifier: Send + Sync { /// Blocks import queue API. /// /// The `import_*` methods can be called in order to send elements for the import queue to verify. -/// Afterwards, call `poll_actions` to determine how to respond to these elements. -pub trait ImportQueue: Send { +pub trait ImportQueueService: Send { /// Import bunch of blocks. fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>); + /// Import block justifications. fn import_justifications( &mut self, @@ -117,12 +118,26 @@ pub trait ImportQueue: Send { number: NumberFor, justifications: Justifications, ); - /// Polls for actions to perform on the network. - /// +} + +#[async_trait::async_trait] +pub trait ImportQueue: Send { + /// Get a copy of the handle to [`ImportQueueService`]. + fn service(&self) -> Box>; + + /// Get a reference to the handle to [`ImportQueueService`]. + fn service_ref(&mut self) -> &mut dyn ImportQueueService; + /// This method should behave in a way similar to `Future::poll`. It can register the current /// task and notify later when more actions are ready to be polled. To continue the comparison, /// it is as if this method always returned `Poll::Pending`. fn poll_actions(&mut self, cx: &mut futures::task::Context, link: &mut dyn Link); + + /// Start asynchronous runner for import queue. + /// + /// Takes an object implementing [`Link`] which allows the import queue to + /// influece the synchronization process. + async fn run(self, link: Box>); } /// Hooks that the verification queue can use to influence the synchronization diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index 0e607159b75c3..20e8d262cacda 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -34,7 +34,8 @@ use crate::{ import_queue::{ buffered_link::{self, BufferedLinkReceiver, BufferedLinkSender}, import_single_block_metered, BlockImportError, BlockImportStatus, BoxBlockImport, - BoxJustificationImport, ImportQueue, IncomingBlock, Link, RuntimeOrigin, Verifier, + BoxJustificationImport, ImportQueue, ImportQueueService, IncomingBlock, Link, + RuntimeOrigin, Verifier, }, metrics::Metrics, }; @@ -42,10 +43,8 @@ use crate::{ /// Interface to a basic block import queue that is importing blocks sequentially in a separate /// task, with plugable verification. pub struct BasicQueue { - /// Channel to send justification import messages to the background task. - justification_sender: TracingUnboundedSender>, - /// Channel to send block import messages to the background task. - block_import_sender: TracingUnboundedSender>, + /// Handle for sending justification and block import messages to the background task. + handle: BasicQueueHandle, /// Results coming from the worker task. result_port: BufferedLinkReceiver, _phantom: PhantomData, @@ -54,8 +53,7 @@ pub struct BasicQueue { impl Drop for BasicQueue { fn drop(&mut self) { // Flush the queue and close the receiver to terminate the future. - self.justification_sender.close_channel(); - self.block_import_sender.close_channel(); + self.handle.close(); self.result_port.close(); } } @@ -95,11 +93,37 @@ impl BasicQueue { future.boxed(), ); - Self { justification_sender, block_import_sender, result_port, _phantom: PhantomData } + Self { + handle: BasicQueueHandle::new(justification_sender, block_import_sender), + result_port, + _phantom: PhantomData, + } } } -impl ImportQueue for BasicQueue { +#[derive(Clone)] +struct BasicQueueHandle { + /// Channel to send justification import messages to the background task. + justification_sender: TracingUnboundedSender>, + /// Channel to send block import messages to the background task. + block_import_sender: TracingUnboundedSender>, +} + +impl BasicQueueHandle { + pub fn new( + justification_sender: TracingUnboundedSender>, + block_import_sender: TracingUnboundedSender>, + ) -> Self { + Self { justification_sender, block_import_sender } + } + + pub fn close(&mut self) { + self.justification_sender.close_channel(); + self.block_import_sender.close_channel(); + } +} + +impl ImportQueueService for BasicQueueHandle { fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>) { if blocks.is_empty() { return @@ -138,12 +162,39 @@ impl ImportQueue for BasicQueue } } } +} + +#[async_trait::async_trait] +impl ImportQueue for BasicQueue { + /// Get handle to [`ImportQueueService`]. + fn service(&self) -> Box> { + Box::new(self.handle.clone()) + } + /// Get a reference to the handle to [`ImportQueueService`]. + fn service_ref(&mut self) -> &mut dyn ImportQueueService { + &mut self.handle + } + + /// Poll actions from network. fn poll_actions(&mut self, cx: &mut Context, link: &mut dyn Link) { if self.result_port.poll_actions(cx, link).is_err() { log::error!(target: "sync", "poll_actions: Background import task is no longer alive"); } } + + /// Start asynchronous runner for import queue. + /// + /// Takes an object implementing [`Link`] which allows the import queue to + /// influece the synchronization process. + async fn run(mut self, mut link: Box>) { + loop { + if let Err(_) = self.result_port.next_action(&mut *link).await { + log::error!(target: "sync", "poll_actions: Background import task is no longer alive"); + return + } + } + } } /// Messages destinated to the background worker. diff --git a/client/consensus/common/src/import_queue/buffered_link.rs b/client/consensus/common/src/import_queue/buffered_link.rs index 5d418dddf0853..e6d3b212fdbac 100644 --- a/client/consensus/common/src/import_queue/buffered_link.rs +++ b/client/consensus/common/src/import_queue/buffered_link.rs @@ -80,7 +80,7 @@ impl Clone for BufferedLinkSender { } /// Internal buffered message. -enum BlockImportWorkerMsg { +pub enum BlockImportWorkerMsg { BlocksProcessed(usize, usize, Vec<(BlockImportResult, B::Hash)>), JustificationImported(RuntimeOrigin, B::Hash, NumberFor, bool), RequestJustification(B::Hash, NumberFor), @@ -122,6 +122,18 @@ pub struct BufferedLinkReceiver { } impl BufferedLinkReceiver { + /// Send action for the synchronization to perform. + pub fn send_actions(&mut self, msg: BlockImportWorkerMsg, link: &mut dyn Link) { + match msg { + BlockImportWorkerMsg::BlocksProcessed(imported, count, results) => + link.blocks_processed(imported, count, results), + BlockImportWorkerMsg::JustificationImported(who, hash, number, success) => + link.justification_imported(who, &hash, number, success), + BlockImportWorkerMsg::RequestJustification(hash, number) => + link.request_justification(&hash, number), + } + } + /// Polls for the buffered link actions. Any enqueued action will be propagated to the link /// passed as parameter. /// @@ -138,15 +150,17 @@ impl BufferedLinkReceiver { Poll::Pending => break Ok(()), }; - match msg { - BlockImportWorkerMsg::BlocksProcessed(imported, count, results) => - link.blocks_processed(imported, count, results), - BlockImportWorkerMsg::JustificationImported(who, hash, number, success) => - link.justification_imported(who, &hash, number, success), - BlockImportWorkerMsg::RequestJustification(hash, number) => - link.request_justification(&hash, number), - } + self.send_actions(msg, &mut *link); + } + } + + /// Poll next element from import queue and send the corresponding action command over the link. + pub async fn next_action(&mut self, link: &mut dyn Link) -> Result<(), ()> { + if let Some(msg) = self.rx.next().await { + self.send_actions(msg, link); + return Ok(()) } + Err(()) } /// Close the channel. diff --git a/client/consensus/common/src/import_queue/mock.rs b/client/consensus/common/src/import_queue/mock.rs new file mode 100644 index 0000000000000..67deee9514a1c --- /dev/null +++ b/client/consensus/common/src/import_queue/mock.rs @@ -0,0 +1,46 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; + +mockall::mock! { + pub ImportQueueHandle {} + + impl ImportQueueService for ImportQueueHandle { + fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>); + fn import_justifications( + &mut self, + who: RuntimeOrigin, + hash: B::Hash, + number: NumberFor, + justifications: Justifications, + ); + } +} + +mockall::mock! { + pub ImportQueue {} + + #[async_trait::async_trait] + impl ImportQueue for ImportQueue { + fn service(&self) -> Box>; + fn service_ref(&mut self) -> &mut dyn ImportQueueService; + fn poll_actions<'a>(&mut self, cx: &mut futures::task::Context<'a>, link: &mut dyn Link); + async fn run(self, link: Box>); + } +} diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index bed9935698769..5e8219c550d19 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -24,9 +24,7 @@ pub mod warp; use libp2p::PeerId; use message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}; -use sc_consensus::{ - import_queue::RuntimeOrigin, BlockImportError, BlockImportStatus, IncomingBlock, -}; +use sc_consensus::{import_queue::RuntimeOrigin, IncomingBlock}; use sp_consensus::BlockOrigin; use sp_runtime::{ traits::{Block as BlockT, NumberFor}, @@ -317,6 +315,12 @@ pub trait ChainSync: Send { response: BlockResponse, ) -> Result, BadPeer>; + /// Procss received block data. + fn process_block_response_data( + &mut self, + blocks_to_import: Result, BadPeer>, + ); + /// Handle a response from the remote to a justification request that we made. /// /// `request` must be the original request that triggered `response`. @@ -326,17 +330,6 @@ pub trait ChainSync: Send { response: BlockResponse, ) -> Result, BadPeer>; - /// A batch of blocks have been processed, with or without errors. - /// - /// Call this when a batch of blocks have been processed by the import - /// queue, with or without errors. - fn on_blocks_processed( - &mut self, - imported: usize, - count: usize, - results: Vec<(Result>, BlockImportError>, Block::Hash)>, - ) -> Box), BadPeer>>>; - /// Call this when a justification has been processed by the import queue, /// with or without errors. fn on_justification_import( @@ -378,7 +371,7 @@ pub trait ChainSync: Send { /// Call when a peer has disconnected. /// Canceled obsolete block request may result in some blocks being ready for /// import, so this functions checks for such blocks and returns them. - fn peer_disconnected(&mut self, who: &PeerId) -> Option>; + fn peer_disconnected(&mut self, who: &PeerId); /// Return some key metrics. fn metrics(&self) -> Metrics; @@ -395,7 +388,10 @@ pub trait ChainSync: Send { /// Internally calls [`ChainSync::poll_block_announce_validation()`] and /// this function should be polled until it returns [`Poll::Pending`] to /// consume all pending events. - fn poll(&mut self, cx: &mut std::task::Context) -> Poll>; + fn poll( + &mut self, + cx: &mut std::task::Context, + ) -> Poll>; /// Send block request to peer fn send_block_request(&mut self, who: PeerId, request: BlockRequest); diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 48d6127f642c3..3a977edbca574 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -32,7 +32,6 @@ use libp2p::{ NetworkBehaviour, }; -use sc_consensus::import_queue::{IncomingBlock, RuntimeOrigin}; use sc_network_common::{ protocol::{ event::DhtEvent, @@ -43,18 +42,14 @@ use sc_network_common::{ }; use sc_peerset::{PeersetHandle, ReputationChange}; use sp_blockchain::HeaderBackend; -use sp_consensus::BlockOrigin; -use sp_runtime::{ - traits::{Block as BlockT, NumberFor}, - Justifications, -}; +use sp_runtime::traits::Block as BlockT; use std::{collections::HashSet, time::Duration}; pub use crate::request_responses::{InboundFailure, OutboundFailure, RequestId, ResponseFailure}; /// General behaviour of the network. Combines all protocols together. #[derive(NetworkBehaviour)] -#[behaviour(out_event = "BehaviourOut")] +#[behaviour(out_event = "BehaviourOut")] pub struct Behaviour where B: BlockT, @@ -72,10 +67,7 @@ where } /// Event generated by `Behaviour`. -pub enum BehaviourOut { - BlockImport(BlockOrigin, Vec>), - JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), - +pub enum BehaviourOut { /// Started a random iterative Kademlia discovery query. RandomKademliaStarted, @@ -107,10 +99,7 @@ pub enum BehaviourOut { }, /// A request protocol handler issued reputation changes for the given peer. - ReputationChanges { - peer: PeerId, - changes: Vec, - }, + ReputationChanges { peer: PeerId, changes: Vec }, /// Opened a substream with the given node with the given notifications protocol. /// @@ -306,13 +295,9 @@ fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole { } } -impl From> for BehaviourOut { +impl From> for BehaviourOut { fn from(event: CustomMessageOutcome) -> Self { match event { - CustomMessageOutcome::BlockImport(origin, blocks) => - BehaviourOut::BlockImport(origin, blocks), - CustomMessageOutcome::JustificationImport(origin, hash, nb, justification) => - BehaviourOut::JustificationImport(origin, hash, nb, justification), CustomMessageOutcome::NotificationStreamOpened { remote, protocol, @@ -344,7 +329,7 @@ impl From> for BehaviourOut { } } -impl From for BehaviourOut { +impl From for BehaviourOut { fn from(event: request_responses::Event) -> Self { match event { request_responses::Event::InboundRequest { peer, protocol, result } => @@ -357,14 +342,14 @@ impl From for BehaviourOut { } } -impl From for BehaviourOut { +impl From for BehaviourOut { fn from(event: peer_info::PeerInfoEvent) -> Self { let peer_info::PeerInfoEvent::Identified { peer_id, info } = event; BehaviourOut::PeerIdentify { peer_id, info } } } -impl From for BehaviourOut { +impl From for BehaviourOut { fn from(event: DiscoveryOut) -> Self { match event { DiscoveryOut::UnroutablePeer(_peer_id) => { diff --git a/client/network/src/config.rs b/client/network/src/config.rs index b10612dd17094..52993e2519400 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -40,7 +40,6 @@ use libp2p::{ multiaddr, Multiaddr, }; use prometheus_endpoint::Registry; -use sc_consensus::ImportQueue; use sc_network_common::{ config::{MultiaddrWithPeerId, NonDefaultSetConfig, SetConfig, TransportConfig}, sync::ChainSync, @@ -82,12 +81,6 @@ where /// name on the wire. pub fork_id: Option, - /// Import queue to use. - /// - /// The import queue is the component that verifies that blocks received from other nodes are - /// valid. - pub import_queue: Box>, - /// Instance of chain sync implementation. pub chain_sync: Box>, diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index f3faa44ee6dbd..f185458e0dace 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -258,6 +258,7 @@ pub mod network_state; #[doc(inline)] pub use libp2p::{multiaddr, Multiaddr, PeerId}; pub use protocol::PeerInfo; +use sc_consensus::{JustificationSyncLink, Link}; pub use sc_network_common::{ protocol::{ event::{DhtEvent, Event}, @@ -297,11 +298,15 @@ const MAX_CONNECTIONS_ESTABLISHED_INCOMING: u32 = 10_000; /// Abstraction over syncing-related services pub trait ChainSyncInterface: - NetworkSyncForkRequest> + Send + Sync + NetworkSyncForkRequest> + JustificationSyncLink + Link + Send + Sync { } impl ChainSyncInterface for T where - T: NetworkSyncForkRequest> + Send + Sync + T: NetworkSyncForkRequest> + + JustificationSyncLink + + Link + + Send + + Sync { } diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 8c1dd39b49be3..10eb31b595253 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -29,32 +29,26 @@ use libp2p::{ }, Multiaddr, PeerId, }; -use log::{debug, error, info, log, trace, warn, Level}; +use log::{debug, error, log, trace, warn, Level}; use lru::LruCache; use message::{generic::Message as GenericMessage, Message}; use notifications::{Notifications, NotificationsOut}; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; use sc_client_api::HeaderBackend; -use sc_consensus::import_queue::{ - BlockImportError, BlockImportStatus, IncomingBlock, RuntimeOrigin, -}; use sc_network_common::{ config::NonReservedPeerMode, error, protocol::{role::Roles, ProtocolName}, sync::{ message::{BlockAnnounce, BlockAnnouncesHandshake, BlockData, BlockResponse, BlockState}, - BadPeer, ChainSync, ImportResult, OnBlockData, PollBlockAnnounceValidation, PollResult, - SyncStatus, + BadPeer, ChainSync, PollBlockAnnounceValidation, SyncStatus, }, utils::{interval, LruHashSet}, }; use sp_arithmetic::traits::SaturatedConversion; -use sp_consensus::BlockOrigin; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, CheckedSub, Header as HeaderT, NumberFor, Zero}, - Justifications, }; use std::{ collections::{HashMap, HashSet, VecDeque}, @@ -481,12 +475,7 @@ where } if let Some(_peer_data) = self.peers.remove(&peer) { - if let Some(OnBlockData::Import(origin, blocks)) = - self.chain_sync.peer_disconnected(&peer) - { - self.pending_messages - .push_back(CustomMessageOutcome::BlockImport(origin, blocks)); - } + self.chain_sync.peer_disconnected(&peer); self.default_peers_set_no_slot_connected_peers.remove(&peer); Ok(()) } else { @@ -785,25 +774,13 @@ where }], }, ); + self.chain_sync.process_block_response_data(blocks_to_import); if is_best { self.pending_messages.push_back(CustomMessageOutcome::PeerNewBest(who, number)); } - match blocks_to_import { - Ok(OnBlockData::Import(origin, blocks)) => - CustomMessageOutcome::BlockImport(origin, blocks), - Ok(OnBlockData::Request(peer, req)) => { - self.chain_sync.send_block_request(peer, req); - CustomMessageOutcome::None - }, - Ok(OnBlockData::Continue) => CustomMessageOutcome::None, - Err(BadPeer(id, repu)) => { - self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); - self.peerset_handle.report_peer(id, repu); - CustomMessageOutcome::None - }, - } + CustomMessageOutcome::None } /// Call this when a block has been finalized. The sync layer may have some additional @@ -812,58 +789,6 @@ where self.chain_sync.on_block_finalized(&hash, *header.number()) } - /// Request a justification for the given block. - /// - /// Uses `protocol` to queue a new justification request and tries to dispatch all pending - /// requests. - pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { - self.chain_sync.request_justification(hash, number) - } - - /// Clear all pending justification requests. - pub fn clear_justification_requests(&mut self) { - self.chain_sync.clear_justification_requests(); - } - - /// A batch of blocks have been processed, with or without errors. - /// Call this when a batch of blocks have been processed by the importqueue, with or without - /// errors. - pub fn on_blocks_processed( - &mut self, - imported: usize, - count: usize, - results: Vec<(Result>, BlockImportError>, B::Hash)>, - ) { - let results = self.chain_sync.on_blocks_processed(imported, count, results); - for result in results { - match result { - Ok((id, req)) => self.chain_sync.send_block_request(id, req), - Err(BadPeer(id, repu)) => { - self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); - self.peerset_handle.report_peer(id, repu) - }, - } - } - } - - /// Call this when a justification has been processed by the import queue, with or without - /// errors. - pub fn justification_import_result( - &mut self, - who: PeerId, - hash: B::Hash, - number: NumberFor, - success: bool, - ) { - self.chain_sync.on_justification_import(hash, number, success); - if !success { - info!("💔 Invalid justification provided by {} for #{}", who, hash); - self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); - self.peerset_handle - .report_peer(who, sc_peerset::ReputationChange::new_fatal("Invalid justification")); - } - } - /// Set whether the syncing peers set is in reserved-only mode. pub fn set_reserved_only(&self, reserved_only: bool) { self.peerset_handle.set_reserved_only(HARDCODED_PEERSETS_SYNC, reserved_only); @@ -997,8 +922,6 @@ where #[derive(Debug)] #[must_use] pub enum CustomMessageOutcome { - BlockImport(BlockOrigin, Vec>), - JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), /// Notification protocols have been opened with a remote. NotificationStreamOpened { remote: PeerId, @@ -1106,23 +1029,9 @@ where // Process any received requests received from `NetworkService` and // check if there is any block announcement validation finished. while let Poll::Ready(result) = self.chain_sync.poll(cx) { - match result { - PollResult::Import(import) => self.pending_messages.push_back(match import { - ImportResult::BlockImport(origin, blocks) => - CustomMessageOutcome::BlockImport(origin, blocks), - ImportResult::JustificationImport(origin, hash, number, justifications) => - CustomMessageOutcome::JustificationImport( - origin, - hash, - number, - justifications, - ), - }), - PollResult::Announce(announce) => - match self.process_block_announce_validation_result(announce) { - CustomMessageOutcome::None => {}, - outcome => self.pending_messages.push_back(outcome), - }, + match self.process_block_announce_validation_result(result) { + CustomMessageOutcome::None => {}, + outcome => self.pending_messages.push_back(outcome), } } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index d35594a07e38a..08e498299a1d3 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -54,7 +54,6 @@ use libp2p::{ use log::{debug, error, info, trace, warn}; use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; -use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; use sc_network_common::{ config::{MultiaddrWithPeerId, TransportConfig}, error::Error, @@ -450,7 +449,6 @@ where is_major_syncing, network_service: swarm, service, - import_queue: params.import_queue, from_service, event_streams: out_events::OutChannels::new(params.metrics_registry.as_ref())?, peers_notifications_sinks, @@ -748,13 +746,11 @@ impl sc_consensus::JustificationSyncLink for NetworkSe /// On success, the justification will be passed to the import queue that was part at /// initialization as part of the configuration. fn request_justification(&self, hash: &B::Hash, number: NumberFor) { - let _ = self - .to_worker - .unbounded_send(ServiceToWorkerMsg::RequestJustification(*hash, number)); + let _ = self.chain_sync_service.request_justification(hash, number); } fn clear_justification_requests(&self) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::ClearJustificationRequests); + let _ = self.chain_sync_service.clear_justification_requests(); } } @@ -1208,8 +1204,6 @@ impl<'a> NotificationSenderReadyT for NotificationSenderReady<'a> { /// /// Each entry corresponds to a method of `NetworkService`. enum ServiceToWorkerMsg { - RequestJustification(B::Hash, NumberFor), - ClearJustificationRequests, AnnounceBlock(B::Hash, Option>), GetValue(KademliaKey), PutValue(KademliaKey, Vec), @@ -1261,8 +1255,6 @@ where service: Arc>, /// The *actual* network. network_service: Swarm>, - /// The import queue that was passed at initialization. - import_queue: Box>, /// Messages from the [`NetworkService`] that must be processed. from_service: TracingUnboundedReceiver>, /// Senders for events that happen on the network. @@ -1290,10 +1282,6 @@ where fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context) -> Poll { let this = &mut *self; - // Poll the import queue for actions to perform. - this.import_queue - .poll_actions(cx, &mut NetworkLink { protocol: &mut this.network_service }); - // At the time of writing of this comment, due to a high volume of messages, the network // worker sometimes takes a long time to process the loop below. When that happens, the // rest of the polling is frozen. In order to avoid negative side-effects caused by this @@ -1322,16 +1310,6 @@ where .behaviour_mut() .user_protocol_mut() .announce_block(hash, data), - ServiceToWorkerMsg::RequestJustification(hash, number) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .request_justification(&hash, number), - ServiceToWorkerMsg::ClearJustificationRequests => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .clear_justification_requests(), ServiceToWorkerMsg::GetValue(key) => this.network_service.behaviour_mut().get_value(key), ServiceToWorkerMsg::PutValue(key, value) => @@ -1435,23 +1413,6 @@ where match poll_value { Poll::Pending => break, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::BlockImport(origin, blocks))) => { - if let Some(metrics) = this.metrics.as_ref() { - metrics.import_queue_blocks_submitted.inc(); - } - this.import_queue.import_blocks(origin, blocks); - }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::JustificationImport( - origin, - hash, - nb, - justifications, - ))) => { - if let Some(metrics) = this.metrics.as_ref() { - metrics.import_queue_justifications_submitted.inc(); - } - this.import_queue.import_justifications(origin, hash, nb, justifications); - }, Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::InboundRequest { protocol, result, @@ -1952,51 +1913,6 @@ where { } -// Implementation of `import_queue::Link` trait using the available local variables. -struct NetworkLink<'a, B, Client> -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - protocol: &'a mut Swarm>, -} - -impl<'a, B, Client> Link for NetworkLink<'a, B, Client> -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn blocks_processed( - &mut self, - imported: usize, - count: usize, - results: Vec<(Result>, BlockImportError>, B::Hash)>, - ) { - self.protocol - .behaviour_mut() - .user_protocol_mut() - .on_blocks_processed(imported, count, results) - } - fn justification_imported( - &mut self, - who: PeerId, - hash: &B::Hash, - number: NumberFor, - success: bool, - ) { - self.protocol - .behaviour_mut() - .user_protocol_mut() - .justification_import_result(who, *hash, number, success); - } - fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { - self.protocol - .behaviour_mut() - .user_protocol_mut() - .request_justification(hash, number) - } -} - fn ensure_addresses_consistent_with_transport<'a>( addresses: impl Iterator, transport: &TransportConfig, diff --git a/client/network/src/service/metrics.rs b/client/network/src/service/metrics.rs index db1b6f7f6500d..a099bba716eb9 100644 --- a/client/network/src/service/metrics.rs +++ b/client/network/src/service/metrics.rs @@ -53,8 +53,6 @@ pub struct Metrics { pub connections_opened_total: CounterVec, pub distinct_peers_connections_closed_total: Counter, pub distinct_peers_connections_opened_total: Counter, - pub import_queue_blocks_submitted: Counter, - pub import_queue_justifications_submitted: Counter, pub incoming_connections_errors_total: CounterVec, pub incoming_connections_total: Counter, pub issued_light_requests: Counter, @@ -103,14 +101,6 @@ impl Metrics { "substrate_sub_libp2p_distinct_peers_connections_opened_total", "Total number of connections opened with distinct peers" )?, registry)?, - import_queue_blocks_submitted: prometheus::register(Counter::new( - "substrate_import_queue_blocks_submitted", - "Number of blocks submitted to the import queue.", - )?, registry)?, - import_queue_justifications_submitted: prometheus::register(Counter::new( - "substrate_import_queue_justifications_submitted", - "Number of justifications submitted to the import queue.", - )?, registry)?, incoming_connections_errors_total: prometheus::register(CounterVec::new( Opts::new( "substrate_sub_libp2p_incoming_connections_handshake_errors_total", diff --git a/client/network/src/service/tests/chain_sync.rs b/client/network/src/service/tests/chain_sync.rs index bd4967f25973a..0f47b64c352f2 100644 --- a/client/network/src/service/tests/chain_sync.rs +++ b/client/network/src/service/tests/chain_sync.rs @@ -86,27 +86,26 @@ async fn normal_network_poll_no_peers() { #[tokio::test] async fn request_justification() { - // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be - // called) - let chain_sync_service = - Box::new(MockChainSyncInterface::::new()); - - // build `ChainSync` and verify that call to `request_justification()` is made - let mut chain_sync = - Box::new(MockChainSync::::new()); - let hash = H256::random(); let number = 1337u64; - chain_sync - .expect_request_justification() + // build `ChainSyncInterface` provider and and expect + // `JustificationSyncLink::request_justification() to be called once + let mut chain_sync_service = + Box::new(MockChainSyncInterface::::new()); + + chain_sync_service + .expect_justification_sync_link_request_justification() .withf(move |in_hash, in_number| &hash == in_hash && &number == in_number) .once() .returning(|_, _| ()); + // build `ChainSync` and set default expecations for it + let mut chain_sync = MockChainSync::::new(); + set_default_expecations_no_peers(&mut chain_sync); let mut network = TestNetworkBuilder::new(Handle::current()) - .with_chain_sync((chain_sync, chain_sync_service)) + .with_chain_sync((Box::new(chain_sync), chain_sync_service)) .build(); // send "request justifiction" message and poll the network @@ -121,17 +120,20 @@ async fn request_justification() { #[tokio::test] async fn clear_justification_requests() { - // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be - // called) - let chain_sync_service = + // build `ChainSyncInterface` provider and expect + // `JustificationSyncLink::clear_justification_requests()` to be called + let mut chain_sync_service = Box::new(MockChainSyncInterface::::new()); - // build `ChainSync` and verify that call to `clear_justification_requests()` is made + chain_sync_service + .expect_justification_sync_link_clear_justification_requests() + .once() + .returning(|| ()); + + // build `ChainSync` and set default expecations for it let mut chain_sync = Box::new(MockChainSync::::new()); - chain_sync.expect_clear_justification_requests().once().returning(|| ()); - set_default_expecations_no_peers(&mut chain_sync); let mut network = TestNetworkBuilder::new(Handle::current()) .with_chain_sync((chain_sync, chain_sync_service)) @@ -235,19 +237,13 @@ async fn on_block_finalized() { // and verify that connection to the peer is closed #[tokio::test] async fn invalid_justification_imported() { - struct DummyImportQueue( - Arc< - RwLock< - Option<( - PeerId, - substrate_test_runtime_client::runtime::Hash, - sp_runtime::traits::NumberFor, - )>, - >, - >, - ); + struct DummyImportQueueHandle; - impl sc_consensus::ImportQueue for DummyImportQueue { + impl + sc_consensus::import_queue::ImportQueueService< + substrate_test_runtime_client::runtime::Block, + > for DummyImportQueueHandle + { fn import_blocks( &mut self, _origin: sp_consensus::BlockOrigin, @@ -265,7 +261,23 @@ async fn invalid_justification_imported() { _justifications: sp_runtime::Justifications, ) { } + } + struct DummyImportQueue( + Arc< + RwLock< + Option<( + PeerId, + substrate_test_runtime_client::runtime::Hash, + sp_runtime::traits::NumberFor, + )>, + >, + >, + DummyImportQueueHandle, + ); + + #[async_trait::async_trait] + impl sc_consensus::ImportQueue for DummyImportQueue { fn poll_actions( &mut self, _cx: &mut futures::task::Context, @@ -275,13 +287,40 @@ async fn invalid_justification_imported() { link.justification_imported(peer, &hash, number, false); } } + + fn service( + &self, + ) -> Box< + dyn sc_consensus::import_queue::ImportQueueService< + substrate_test_runtime_client::runtime::Block, + >, + > { + Box::new(DummyImportQueueHandle {}) + } + + fn service_ref( + &mut self, + ) -> &mut dyn sc_consensus::import_queue::ImportQueueService< + substrate_test_runtime_client::runtime::Block, + > { + &mut self.1 + } + + async fn run( + self, + _link: Box>, + ) { + } } let justification_info = Arc::new(RwLock::new(None)); let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let (service1, mut event_stream1) = TestNetworkBuilder::new(Handle::current()) - .with_import_queue(Box::new(DummyImportQueue(justification_info.clone()))) + .with_import_queue(Box::new(DummyImportQueue( + justification_info.clone(), + DummyImportQueueHandle {}, + ))) .with_listen_addresses(vec![listen_addr.clone()]) .build() .start_network(); @@ -331,6 +370,7 @@ async fn disconnect_peer_using_chain_sync_handle() { let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); let listen_addr = config::build_multiaddr![Memory(rand::random::())]; + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (chain_sync_network_provider, chain_sync_network_handle) = sc_network_sync::service::network::NetworkServiceProvider::new(); let handle_clone = chain_sync_network_handle.clone(); @@ -344,7 +384,9 @@ async fn disconnect_peer_using_chain_sync_handle() { Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), 1u32, None, + None, chain_sync_network_handle.clone(), + import_queue, ProtocolName::from("block-request"), ProtocolName::from("state-request"), None, @@ -353,7 +395,7 @@ async fn disconnect_peer_using_chain_sync_handle() { let (node1, mut event_stream1) = TestNetworkBuilder::new(Handle::current()) .with_listen_addresses(vec![listen_addr.clone()]) - .with_chain_sync((Box::new(chain_sync), chain_sync_service)) + .with_chain_sync((Box::new(chain_sync), Box::new(chain_sync_service))) .with_chain_sync_network((chain_sync_network_provider, chain_sync_network_handle)) .with_client(client.clone()) .build() diff --git a/client/network/src/service/tests/mod.rs b/client/network/src/service/tests/mod.rs index f8635e39e9da9..fa1486a791213 100644 --- a/client/network/src/service/tests/mod.rs +++ b/client/network/src/service/tests/mod.rs @@ -21,7 +21,7 @@ use crate::{config, ChainSyncInterface, NetworkService, NetworkWorker}; use futures::prelude::*; use libp2p::Multiaddr; use sc_client_api::{BlockBackend, HeaderBackend}; -use sc_consensus::ImportQueue; +use sc_consensus::{ImportQueue, Link}; use sc_network_common::{ config::{ NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, @@ -93,6 +93,7 @@ impl TestNetwork { struct TestNetworkBuilder { import_queue: Option>>, + link: Option>>, client: Option>, listen_addresses: Vec, set_config: Option, @@ -106,6 +107,7 @@ impl TestNetworkBuilder { pub fn new(rt_handle: Handle) -> Self { Self { import_queue: None, + link: None, client: None, listen_addresses: Vec::new(), set_config: None, @@ -212,13 +214,14 @@ impl TestNetworkBuilder { } } - let import_queue = self.import_queue.unwrap_or(Box::new(sc_consensus::BasicQueue::new( - PassThroughVerifier(false), - Box::new(client.clone()), - None, - &sp_core::testing::TaskExecutor::new(), - None, - ))); + let mut import_queue = + self.import_queue.unwrap_or(Box::new(sc_consensus::BasicQueue::new( + PassThroughVerifier(false), + Box::new(client.clone()), + None, + &sp_core::testing::TaskExecutor::new(), + None, + ))); let protocol_id = ProtocolId::from("test-protocol-name"); let fork_id = Some(String::from("test-fork-id")); @@ -289,15 +292,23 @@ impl TestNetworkBuilder { Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), network_config.max_parallel_downloads, None, + None, chain_sync_network_handle, + import_queue.service(), block_request_protocol_config.name.clone(), state_request_protocol_config.name.clone(), None, ) .unwrap(); - (Box::new(chain_sync), chain_sync_service) + if let None = self.link { + self.link = Some(Box::new(chain_sync_service.clone())); + } + (Box::new(chain_sync), Box::new(chain_sync_service)) }); + let mut link = self + .link + .unwrap_or(Box::new(sc_network_sync::service::mock::MockChainSyncInterface::new())); let handle = self.rt_handle.clone(); let executor = move |f| { @@ -316,7 +327,6 @@ impl TestNetworkBuilder { chain: client.clone(), protocol_id, fork_id, - import_queue, chain_sync, chain_sync_service, metrics_registry: None, @@ -333,6 +343,16 @@ impl TestNetworkBuilder { self.rt_handle.spawn(async move { let _ = chain_sync_network_provider.run(service).await; }); + self.rt_handle.spawn(async move { + loop { + futures::future::poll_fn(|cx| { + import_queue.poll_actions(cx, &mut *link); + std::task::Poll::Ready(()) + }) + .await; + tokio::time::sleep(std::time::Duration::from_millis(250)).await; + } + }); TestNetwork::new(worker, self.rt_handle) } diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 086ab3c30cc25..e29d8047161ce 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -28,6 +28,7 @@ prost = "0.11" smallvec = "1.8.0" thiserror = "1.0" fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-network-common = { version = "0.10.0-dev", path = "../common" } diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 697445334a073..75eda91219ec8 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -54,9 +54,12 @@ use futures::{ }; use libp2p::{request_response::OutboundFailure, PeerId}; use log::{debug, error, info, trace, warn}; +use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use prost::Message; use sc_client_api::{BlockBackend, ProofProvider}; -use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; +use sc_consensus::{ + import_queue::ImportQueueService, BlockImportError, BlockImportStatus, IncomingBlock, +}; use sc_network_common::{ config::{ NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, @@ -71,8 +74,8 @@ use sc_network_common::{ warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, WarpSyncProvider}, BadPeer, ChainSync as ChainSyncT, ImportResult, Metrics, OnBlockData, OnBlockJustification, OnStateData, OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, - OpaqueStateResponse, PeerInfo, PeerRequest, PollBlockAnnounceValidation, PollResult, - SyncMode, SyncState, SyncStatus, + OpaqueStateResponse, PeerInfo, PeerRequest, PollBlockAnnounceValidation, SyncMode, + SyncState, SyncStatus, }, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; @@ -233,6 +236,32 @@ impl Default for AllowedRequests { } } +struct SyncingMetrics { + pub import_queue_blocks_submitted: Counter, + pub import_queue_justifications_submitted: Counter, +} + +impl SyncingMetrics { + fn register(registry: &Registry) -> Result { + Ok(Self { + import_queue_blocks_submitted: register( + Counter::new( + "substrate_sync_import_queue_blocks_submitted", + "Number of blocks submitted to the import queue.", + )?, + registry, + )?, + import_queue_justifications_submitted: register( + Counter::new( + "substrate_sync_import_queue_justifications_submitted", + "Number of justifications submitted to the import queue.", + )?, + registry, + )?, + }) + } +} + struct GapSync { blocks: BlockCollection, best_queued_number: NumberFor, @@ -311,6 +340,10 @@ pub struct ChainSync { warp_sync_protocol_name: Option, /// Pending responses pending_responses: FuturesUnordered>, + /// Handle to import queue. + import_queue: Box>, + /// Metrics. + metrics: Option, } /// All the data we have about a Peer that we are trying to sync with @@ -961,6 +994,19 @@ where Ok(self.validate_and_queue_blocks(new_blocks, gap)) } + fn process_block_response_data(&mut self, blocks_to_import: Result, BadPeer>) { + match blocks_to_import { + Ok(OnBlockData::Import(origin, blocks)) => self.import_blocks(origin, blocks), + Ok(OnBlockData::Request(peer, req)) => self.send_block_request(peer, req), + Ok(OnBlockData::Continue) => {}, + Err(BadPeer(id, repu)) => { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(id, repu); + }, + } + } + fn on_block_justification( &mut self, who: PeerId, @@ -1016,156 +1062,6 @@ where Ok(OnBlockJustification::Nothing) } - fn on_blocks_processed( - &mut self, - imported: usize, - count: usize, - results: Vec<(Result>, BlockImportError>, B::Hash)>, - ) -> Box), BadPeer>>> { - trace!(target: "sync", "Imported {} of {}", imported, count); - - let mut output = Vec::new(); - - let mut has_error = false; - for (_, hash) in &results { - self.queue_blocks.remove(hash); - self.blocks.clear_queued(hash); - if let Some(gap_sync) = &mut self.gap_sync { - gap_sync.blocks.clear_queued(hash); - } - } - for (result, hash) in results { - if has_error { - break - } - - if result.is_err() { - has_error = true; - } - - match result { - Ok(BlockImportStatus::ImportedKnown(number, who)) => - if let Some(peer) = who { - self.update_peer_common_number(&peer, number); - }, - Ok(BlockImportStatus::ImportedUnknown(number, aux, who)) => { - if aux.clear_justification_requests { - trace!( - target: "sync", - "Block imported clears all pending justification requests {}: {:?}", - number, - hash, - ); - self.clear_justification_requests(); - } - - if aux.needs_justification { - trace!( - target: "sync", - "Block imported but requires justification {}: {:?}", - number, - hash, - ); - self.request_justification(&hash, number); - } - - if aux.bad_justification { - if let Some(ref peer) = who { - warn!("💔 Sent block with bad justification to import"); - output.push(Err(BadPeer(*peer, rep::BAD_JUSTIFICATION))); - } - } - - if let Some(peer) = who { - self.update_peer_common_number(&peer, number); - } - let state_sync_complete = - self.state_sync.as_ref().map_or(false, |s| s.target() == hash); - if state_sync_complete { - info!( - target: "sync", - "State sync is complete ({} MiB), restarting block sync.", - self.state_sync.as_ref().map_or(0, |s| s.progress().size / (1024 * 1024)), - ); - self.state_sync = None; - self.mode = SyncMode::Full; - output.extend(self.restart()); - } - let warp_sync_complete = self - .warp_sync - .as_ref() - .map_or(false, |s| s.target_block_hash() == Some(hash)); - if warp_sync_complete { - info!( - target: "sync", - "Warp sync is complete ({} MiB), restarting block sync.", - self.warp_sync.as_ref().map_or(0, |s| s.progress().total_bytes / (1024 * 1024)), - ); - self.warp_sync = None; - self.mode = SyncMode::Full; - output.extend(self.restart()); - } - let gap_sync_complete = - self.gap_sync.as_ref().map_or(false, |s| s.target == number); - if gap_sync_complete { - info!( - target: "sync", - "Block history download is complete." - ); - self.gap_sync = None; - } - }, - Err(BlockImportError::IncompleteHeader(who)) => - if let Some(peer) = who { - warn!( - target: "sync", - "💔 Peer sent block with incomplete header to import", - ); - output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER))); - output.extend(self.restart()); - }, - Err(BlockImportError::VerificationFailed(who, e)) => - if let Some(peer) = who { - warn!( - target: "sync", - "💔 Verification failed for block {:?} received from peer: {}, {:?}", - hash, - peer, - e, - ); - output.push(Err(BadPeer(peer, rep::VERIFICATION_FAIL))); - output.extend(self.restart()); - }, - Err(BlockImportError::BadBlock(who)) => - if let Some(peer) = who { - warn!( - target: "sync", - "💔 Block {:?} received from peer {} has been blacklisted", - hash, - peer, - ); - output.push(Err(BadPeer(peer, rep::BAD_BLOCK))); - }, - Err(BlockImportError::MissingState) => { - // This may happen if the chain we were requesting upon has been discarded - // in the meantime because other chain has been finalized. - // Don't mark it as bad as it still may be synced if explicitly requested. - trace!(target: "sync", "Obsolete block {:?}", hash); - }, - e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => { - warn!(target: "sync", "💔 Error importing block {:?}: {}", hash, e.unwrap_err()); - self.state_sync = None; - self.warp_sync = None; - output.extend(self.restart()); - }, - Err(BlockImportError::Cancelled) => {}, - }; - } - - self.allowed_requests.set_all(); - Box::new(output.into_iter()) - } - fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor, success: bool) { let finalization_result = if success { Ok((hash, number)) } else { Err(()) }; self.extra_justifications @@ -1331,7 +1227,7 @@ where } } - fn peer_disconnected(&mut self, who: &PeerId) -> Option> { + fn peer_disconnected(&mut self, who: &PeerId) { self.blocks.clear_peer_download(who); if let Some(gap_sync) = &mut self.gap_sync { gap_sync.blocks.clear_peer_download(who) @@ -1343,8 +1239,13 @@ where target.peers.remove(who); !target.peers.is_empty() }); + let blocks = self.ready_blocks(); - (!blocks.is_empty()).then(|| self.validate_and_queue_blocks(blocks, false)) + if let Some(OnBlockData::Import(origin, blocks)) = + (!blocks.is_empty()).then(|| self.validate_and_queue_blocks(blocks, false)) + { + self.import_blocks(origin, blocks); + } } fn metrics(&self) -> Metrics { @@ -1421,22 +1322,56 @@ where .map_err(|error: codec::Error| error.to_string()) } - fn poll(&mut self, cx: &mut std::task::Context) -> Poll> { + fn poll( + &mut self, + cx: &mut std::task::Context, + ) -> Poll> { while let Poll::Ready(Some(event)) = self.service_rx.poll_next_unpin(cx) { match event { ToServiceCommand::SetSyncForkRequest(peers, hash, number) => { self.set_sync_fork_request(peers, &hash, number); }, + ToServiceCommand::RequestJustification(hash, number) => + self.request_justification(&hash, number), + ToServiceCommand::ClearJustificationRequests => self.clear_justification_requests(), + ToServiceCommand::BlocksProcessed(imported, count, results) => { + for result in self.on_blocks_processed(imported, count, results) { + match result { + Ok((id, req)) => self.send_block_request(id, req), + Err(BadPeer(id, repu)) => { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(id, repu) + }, + } + } + }, + ToServiceCommand::JustificationImported(peer, hash, number, success) => { + self.on_justification_import(hash, number, success); + if !success { + info!(target: "sync", "💔 Invalid justification provided by {} for #{}", peer, hash); + self.network_service + .disconnect_peer(peer, self.block_announce_protocol_name.clone()); + self.network_service.report_peer( + peer, + sc_peerset::ReputationChange::new_fatal("Invalid justification"), + ); + } + }, } } self.process_outbound_requests(); - if let Poll::Ready(result) = self.poll_pending_responses(cx) { - return Poll::Ready(PollResult::Import(result)) + while let Poll::Ready(result) = self.poll_pending_responses(cx) { + match result { + ImportResult::BlockImport(origin, blocks) => self.import_blocks(origin, blocks), + ImportResult::JustificationImport(who, hash, number, justifications) => + self.import_justifications(who, hash, number, justifications), + } } if let Poll::Ready(announce) = self.poll_block_announce_validation(cx) { - return Poll::Ready(PollResult::Announce(announce)) + return Poll::Ready(announce) } Poll::Pending @@ -1494,11 +1429,13 @@ where block_announce_validator: Box + Send>, max_parallel_downloads: u32, warp_sync_provider: Option>>, + metrics_registry: Option<&Registry>, network_service: service::network::NetworkServiceHandle, + import_queue: Box>, block_request_protocol_name: ProtocolName, state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, - ) -> Result<(Self, Box>, NonDefaultSetConfig), ClientError> { + ) -> Result<(Self, ChainSyncInterfaceHandle, NonDefaultSetConfig), ClientError> { let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync"); let block_announce_config = Self::get_block_announce_proto_config( protocol_id, @@ -1544,10 +1481,22 @@ where .clone() .into(), pending_responses: Default::default(), + import_queue, + metrics: if let Some(r) = &metrics_registry { + match SyncingMetrics::register(r) { + Ok(metrics) => Some(metrics), + Err(err) => { + error!(target: "sync", "Failed to register metrics for ChainSync: {err:?}"); + None + }, + } + } else { + None + }, }; sync.reset_sync_start_point()?; - Ok((sync, Box::new(ChainSyncInterfaceHandle::new(tx)), block_announce_config)) + Ok((sync, ChainSyncInterfaceHandle::new(tx), block_announce_config)) } /// Returns the median seen block number. @@ -2173,8 +2122,10 @@ where if request.fields == BlockAttributes::JUSTIFICATION { match self.on_block_justification(peer_id, block_response) { Ok(OnBlockJustification::Nothing) => None, - Ok(OnBlockJustification::Import { peer, hash, number, justifications }) => - Some(ImportResult::JustificationImport(peer, hash, number, justifications)), + Ok(OnBlockJustification::Import { peer, hash, number, justifications }) => { + self.import_justifications(peer, hash, number, justifications); + None + }, Err(BadPeer(id, repu)) => { self.network_service .disconnect_peer(id, self.block_announce_protocol_name.clone()); @@ -2184,8 +2135,10 @@ where } } else { match self.on_block_data(&peer_id, Some(request), block_response) { - Ok(OnBlockData::Import(origin, blocks)) => - Some(ImportResult::BlockImport(origin, blocks)), + Ok(OnBlockData::Import(origin, blocks)) => { + self.import_blocks(origin, blocks); + None + }, Ok(OnBlockData::Request(peer, req)) => { self.send_block_request(peer, req); None @@ -2712,6 +2665,182 @@ where }, } } + + fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>) { + if let Some(metrics) = &self.metrics { + metrics.import_queue_blocks_submitted.inc(); + } + + self.import_queue.import_blocks(origin, blocks); + } + + fn import_justifications( + &mut self, + peer: PeerId, + hash: B::Hash, + number: NumberFor, + justifications: Justifications, + ) { + if let Some(metrics) = &self.metrics { + metrics.import_queue_justifications_submitted.inc(); + } + + self.import_queue.import_justifications(peer, hash, number, justifications); + } + + /// A batch of blocks have been processed, with or without errors. + /// + /// Call this when a batch of blocks have been processed by the import + /// queue, with or without errors. + fn on_blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, B::Hash)>, + ) -> Box), BadPeer>>> { + trace!(target: "sync", "Imported {} of {}", imported, count); + + let mut output = Vec::new(); + + let mut has_error = false; + for (_, hash) in &results { + self.queue_blocks.remove(hash); + self.blocks.clear_queued(hash); + if let Some(gap_sync) = &mut self.gap_sync { + gap_sync.blocks.clear_queued(hash); + } + } + for (result, hash) in results { + if has_error { + break + } + + if result.is_err() { + has_error = true; + } + + match result { + Ok(BlockImportStatus::ImportedKnown(number, who)) => + if let Some(peer) = who { + self.update_peer_common_number(&peer, number); + }, + Ok(BlockImportStatus::ImportedUnknown(number, aux, who)) => { + if aux.clear_justification_requests { + trace!( + target: "sync", + "Block imported clears all pending justification requests {}: {:?}", + number, + hash, + ); + self.clear_justification_requests(); + } + + if aux.needs_justification { + trace!( + target: "sync", + "Block imported but requires justification {}: {:?}", + number, + hash, + ); + self.request_justification(&hash, number); + } + + if aux.bad_justification { + if let Some(ref peer) = who { + warn!("💔 Sent block with bad justification to import"); + output.push(Err(BadPeer(*peer, rep::BAD_JUSTIFICATION))); + } + } + + if let Some(peer) = who { + self.update_peer_common_number(&peer, number); + } + let state_sync_complete = + self.state_sync.as_ref().map_or(false, |s| s.target() == hash); + if state_sync_complete { + info!( + target: "sync", + "State sync is complete ({} MiB), restarting block sync.", + self.state_sync.as_ref().map_or(0, |s| s.progress().size / (1024 * 1024)), + ); + self.state_sync = None; + self.mode = SyncMode::Full; + output.extend(self.restart()); + } + let warp_sync_complete = self + .warp_sync + .as_ref() + .map_or(false, |s| s.target_block_hash() == Some(hash)); + if warp_sync_complete { + info!( + target: "sync", + "Warp sync is complete ({} MiB), restarting block sync.", + self.warp_sync.as_ref().map_or(0, |s| s.progress().total_bytes / (1024 * 1024)), + ); + self.warp_sync = None; + self.mode = SyncMode::Full; + output.extend(self.restart()); + } + let gap_sync_complete = + self.gap_sync.as_ref().map_or(false, |s| s.target == number); + if gap_sync_complete { + info!( + target: "sync", + "Block history download is complete." + ); + self.gap_sync = None; + } + }, + Err(BlockImportError::IncompleteHeader(who)) => + if let Some(peer) = who { + warn!( + target: "sync", + "💔 Peer sent block with incomplete header to import", + ); + output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER))); + output.extend(self.restart()); + }, + Err(BlockImportError::VerificationFailed(who, e)) => + if let Some(peer) = who { + warn!( + target: "sync", + "💔 Verification failed for block {:?} received from peer: {}, {:?}", + hash, + peer, + e, + ); + output.push(Err(BadPeer(peer, rep::VERIFICATION_FAIL))); + output.extend(self.restart()); + }, + Err(BlockImportError::BadBlock(who)) => + if let Some(peer) = who { + warn!( + target: "sync", + "💔 Block {:?} received from peer {} has been blacklisted", + hash, + peer, + ); + output.push(Err(BadPeer(peer, rep::BAD_BLOCK))); + }, + Err(BlockImportError::MissingState) => { + // This may happen if the chain we were requesting upon has been discarded + // in the meantime because other chain has been finalized. + // Don't mark it as bad as it still may be synced if explicitly requested. + trace!(target: "sync", "Obsolete block {:?}", hash); + }, + e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => { + warn!(target: "sync", "💔 Error importing block {:?}: {}", hash, e.unwrap_err()); + self.state_sync = None; + self.warp_sync = None; + output.extend(self.restart()); + }, + Err(BlockImportError::Cancelled) => {}, + }; + } + + self.allowed_requests.set_all(); + Box::new(output.into_iter()) + } } // This is purely during a backwards compatible transitionary period and should be removed @@ -3089,6 +3218,7 @@ mod test { let block_announce_validator = Box::new(DefaultBlockAnnounceValidator); let peer_id = PeerId::random(); + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let (mut sync, _, _) = ChainSync::new( @@ -3100,7 +3230,9 @@ mod test { block_announce_validator, 1, None, + None, chain_sync_network_handle, + import_queue, ProtocolName::from("block-request"), ProtocolName::from("state-request"), None, @@ -3151,6 +3283,7 @@ mod test { #[test] fn restart_doesnt_affect_peers_downloading_finality_data() { let mut client = Arc::new(TestClientBuilder::new().build()); + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); @@ -3163,7 +3296,9 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 1, None, + None, chain_sync_network_handle, + import_queue, ProtocolName::from("block-request"), ProtocolName::from("state-request"), None, @@ -3330,6 +3465,7 @@ mod test { sp_tracing::try_init_simple(); let mut client = Arc::new(TestClientBuilder::new().build()); + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); @@ -3342,7 +3478,9 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 5, None, + None, chain_sync_network_handle, + import_queue, ProtocolName::from("block-request"), ProtocolName::from("state-request"), None, @@ -3453,6 +3591,7 @@ mod test { }; let mut client = Arc::new(TestClientBuilder::new().build()); + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let info = client.info(); @@ -3466,7 +3605,9 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 5, None, + None, chain_sync_network_handle, + import_queue, ProtocolName::from("block-request"), ProtocolName::from("state-request"), None, @@ -3584,6 +3725,7 @@ mod test { fn can_sync_huge_fork() { sp_tracing::try_init_simple(); + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); @@ -3619,7 +3761,9 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 5, None, + None, chain_sync_network_handle, + import_queue, ProtocolName::from("block-request"), ProtocolName::from("state-request"), None, @@ -3722,6 +3866,7 @@ mod test { fn syncs_fork_without_duplicate_requests() { sp_tracing::try_init_simple(); + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); @@ -3757,7 +3902,9 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 5, None, + None, chain_sync_network_handle, + import_queue, ProtocolName::from("block-request"), ProtocolName::from("state-request"), None, @@ -3881,6 +4028,7 @@ mod test { #[test] fn removes_target_fork_on_disconnect() { sp_tracing::try_init_simple(); + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); @@ -3895,7 +4043,9 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 1, None, + None, chain_sync_network_handle, + import_queue, ProtocolName::from("block-request"), ProtocolName::from("state-request"), None, @@ -3921,6 +4071,7 @@ mod test { #[test] fn can_import_response_with_missing_blocks() { sp_tracing::try_init_simple(); + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client2 = Arc::new(TestClientBuilder::new().build()); @@ -3937,7 +4088,9 @@ mod test { Box::new(DefaultBlockAnnounceValidator), 1, None, + None, chain_sync_network_handle, + import_queue, ProtocolName::from("block-request"), ProtocolName::from("state-request"), None, diff --git a/client/network/sync/src/mock.rs b/client/network/sync/src/mock.rs index 48d72c425bd03..b59ea7e4fea70 100644 --- a/client/network/sync/src/mock.rs +++ b/client/network/sync/src/mock.rs @@ -21,11 +21,10 @@ use futures::task::Poll; use libp2p::PeerId; -use sc_consensus::{BlockImportError, BlockImportStatus}; use sc_network_common::sync::{ message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}, BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, - OpaqueBlockResponse, PeerInfo, PollBlockAnnounceValidation, PollResult, SyncStatus, + OpaqueBlockResponse, PeerInfo, PollBlockAnnounceValidation, SyncStatus, }; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -60,17 +59,12 @@ mockall::mock! { request: Option>, response: BlockResponse, ) -> Result, BadPeer>; + fn process_block_response_data(&mut self, blocks_to_import: Result, BadPeer>); fn on_block_justification( &mut self, who: PeerId, response: BlockResponse, ) -> Result, BadPeer>; - fn on_blocks_processed( - &mut self, - imported: usize, - count: usize, - results: Vec<(Result>, BlockImportError>, Block::Hash)>, - ) -> Box), BadPeer>>>; fn on_justification_import( &mut self, hash: Block::Hash, @@ -89,7 +83,7 @@ mockall::mock! { &mut self, cx: &mut std::task::Context<'a>, ) -> Poll>; - fn peer_disconnected(&mut self, who: &PeerId) -> Option>; + fn peer_disconnected(&mut self, who: &PeerId); fn metrics(&self) -> Metrics; fn block_response_into_blocks( &self, @@ -99,7 +93,7 @@ mockall::mock! { fn poll<'a>( &mut self, cx: &mut std::task::Context<'a>, - ) -> Poll>; + ) -> Poll>; fn send_block_request( &mut self, who: PeerId, diff --git a/client/network/sync/src/service/chain_sync.rs b/client/network/sync/src/service/chain_sync.rs index cf07c65ee3109..50ded5b643dea 100644 --- a/client/network/sync/src/service/chain_sync.rs +++ b/client/network/sync/src/service/chain_sync.rs @@ -17,6 +17,7 @@ // along with this program. If not, see . use libp2p::PeerId; +use sc_consensus::{BlockImportError, BlockImportStatus, JustificationSyncLink, Link}; use sc_network_common::service::NetworkSyncForkRequest; use sc_utils::mpsc::TracingUnboundedSender; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -25,9 +26,18 @@ use sp_runtime::traits::{Block as BlockT, NumberFor}; #[derive(Debug)] pub enum ToServiceCommand { SetSyncForkRequest(Vec, B::Hash, NumberFor), + RequestJustification(B::Hash, NumberFor), + ClearJustificationRequests, + BlocksProcessed( + usize, + usize, + Vec<(Result>, BlockImportError>, B::Hash)>, + ), + JustificationImported(PeerId, B::Hash, NumberFor, bool), } /// Handle for communicating with `ChainSync` asynchronously +#[derive(Clone)] pub struct ChainSyncInterfaceHandle { tx: TracingUnboundedSender>, } @@ -56,3 +66,46 @@ impl NetworkSyncForkRequest> .unbounded_send(ToServiceCommand::SetSyncForkRequest(peers, hash, number)); } } + +impl JustificationSyncLink for ChainSyncInterfaceHandle { + /// Request a justification for the given block from the network. + /// + /// On success, the justification will be passed to the import queue that was part at + /// initialization as part of the configuration. + fn request_justification(&self, hash: &B::Hash, number: NumberFor) { + let _ = self.tx.unbounded_send(ToServiceCommand::RequestJustification(*hash, number)); + } + + fn clear_justification_requests(&self) { + let _ = self.tx.unbounded_send(ToServiceCommand::ClearJustificationRequests); + } +} + +impl Link for ChainSyncInterfaceHandle { + fn blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, B::Hash)>, + ) { + let _ = self + .tx + .unbounded_send(ToServiceCommand::BlocksProcessed(imported, count, results)); + } + + fn justification_imported( + &mut self, + who: PeerId, + hash: &B::Hash, + number: NumberFor, + success: bool, + ) { + let _ = self + .tx + .unbounded_send(ToServiceCommand::JustificationImported(who, *hash, number, success)); + } + + fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { + let _ = self.tx.unbounded_send(ToServiceCommand::RequestJustification(*hash, number)); + } +} diff --git a/client/network/sync/src/service/mock.rs b/client/network/sync/src/service/mock.rs index c8a29e1fba8ea..d8aad2fa7bac1 100644 --- a/client/network/sync/src/service/mock.rs +++ b/client/network/sync/src/service/mock.rs @@ -18,6 +18,7 @@ use futures::channel::oneshot; use libp2p::{Multiaddr, PeerId}; +use sc_consensus::{BlockImportError, BlockImportStatus}; use sc_network_common::{ config::MultiaddrWithPeerId, protocol::ProtocolName, @@ -29,13 +30,43 @@ use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::collections::HashSet; mockall::mock! { - pub ChainSyncInterface {} + pub ChainSyncInterface { + pub fn justification_sync_link_request_justification(&self, hash: &B::Hash, number: NumberFor); + pub fn justification_sync_link_clear_justification_requests(&self); + } impl NetworkSyncForkRequest> for ChainSyncInterface { fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor); } + + impl sc_consensus::Link for ChainSyncInterface { + fn blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, B::Hash)>, + ); + fn justification_imported( + &mut self, + who: PeerId, + hash: &B::Hash, + number: NumberFor, + success: bool, + ); + fn request_justification(&mut self, hash: &B::Hash, number: NumberFor); + } +} + +impl sc_consensus::JustificationSyncLink for MockChainSyncInterface { + fn request_justification(&self, hash: &B::Hash, number: NumberFor) { + self.justification_sync_link_request_justification(hash, number); + } + + fn clear_justification_requests(&self) { + self.justification_sync_link_clear_justification_requests(); + } } mockall::mock! { diff --git a/client/network/sync/src/tests.rs b/client/network/sync/src/tests.rs index a03e657f03ab2..61de08443a6c2 100644 --- a/client/network/sync/src/tests.rs +++ b/client/network/sync/src/tests.rs @@ -37,6 +37,7 @@ use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _ // poll `ChainSync` and verify that a new sync fork request has been registered #[tokio::test] async fn delegate_to_chainsync() { + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let (mut chain_sync, chain_sync_service, _) = ChainSync::new( sc_network_common::sync::SyncMode::Full, @@ -47,7 +48,9 @@ async fn delegate_to_chainsync() { Box::new(DefaultBlockAnnounceValidator), 1u32, None, + None, chain_sync_network_handle, + import_queue, ProtocolName::from("block-request"), ProtocolName::from("state-request"), None, diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index d3642e69cb632..173ca81653b1a 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -43,8 +43,8 @@ use sc_client_api::{ }; use sc_consensus::{ BasicQueue, BlockCheckParams, BlockImport, BlockImportParams, BoxJustificationImport, - ForkChoiceStrategy, ImportResult, JustificationImport, JustificationSyncLink, LongestChain, - Verifier, + ForkChoiceStrategy, ImportQueue, ImportResult, JustificationImport, JustificationSyncLink, + LongestChain, Verifier, }; use sc_network::{ config::{NetworkConfiguration, RequestResponseConfig, Role, SyncMode}, @@ -896,7 +896,9 @@ where block_announce_validator, network_config.max_parallel_downloads, Some(warp_sync), + None, chain_sync_network_handle, + import_queue.service(), block_request_protocol_config.name.clone(), state_request_protocol_config.name.clone(), Some(warp_protocol_config.name.clone()), @@ -915,9 +917,8 @@ where chain: client.clone(), protocol_id, fork_id, - import_queue, chain_sync: Box::new(chain_sync), - chain_sync_service, + chain_sync_service: Box::new(chain_sync_service.clone()), metrics_registry: None, block_announce_config, request_response_protocol_configs: [ @@ -936,6 +937,9 @@ where self.rt_handle().spawn(async move { chain_sync_network_provider.run(service).await; }); + self.rt_handle().spawn(async move { + import_queue.run(Box::new(chain_sync_service)).await; + }); self.mut_peers(move |peers| { for peer in peers.iter_mut() { diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index dd89ce6dff10a..7153672030d6a 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -853,7 +853,9 @@ where block_announce_validator, config.network.max_parallel_downloads, warp_sync_provider, + config.prometheus_config.as_ref().map(|config| config.registry.clone()).as_ref(), chain_sync_network_handle, + import_queue.service(), block_request_protocol_config.name.clone(), state_request_protocol_config.name.clone(), warp_sync_protocol_config.as_ref().map(|config| config.name.clone()), @@ -877,9 +879,8 @@ where chain: client.clone(), protocol_id: protocol_id.clone(), fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), - import_queue: Box::new(import_queue), chain_sync: Box::new(chain_sync), - chain_sync_service, + chain_sync_service: Box::new(chain_sync_service.clone()), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_announce_config, request_response_protocol_configs: request_response_protocol_configs @@ -925,6 +926,7 @@ where Some("networking"), chain_sync_network_provider.run(network.clone()), ); + spawn_handle.spawn("import-queue", None, import_queue.run(Box::new(chain_sync_service))); let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc"); diff --git a/client/service/src/chain_ops/import_blocks.rs b/client/service/src/chain_ops/import_blocks.rs index c0612124dd0c2..ca09c1658d72f 100644 --- a/client/service/src/chain_ops/import_blocks.rs +++ b/client/service/src/chain_ops/import_blocks.rs @@ -157,7 +157,7 @@ fn import_block_to_queue( let (header, extrinsics) = signed_block.block.deconstruct(); let hash = header.hash(); // import queue handles verification and importing it into the client. - queue.import_blocks( + queue.service_ref().import_blocks( BlockOrigin::File, vec![IncomingBlock:: { hash, From 15cfd9c5dbbfa1f3ed49623eb55b67354d1645e9 Mon Sep 17 00:00:00 2001 From: tgmichel Date: Fri, 9 Dec 2022 20:55:56 +0100 Subject: [PATCH 1459/1472] Trace response payload in default `jsonrpsee` middleware (#12886) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Trace result in default `jsonrpsee` middleware * `rpc_metrics::extra` Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- client/rpc-servers/src/middleware.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/rpc-servers/src/middleware.rs b/client/rpc-servers/src/middleware.rs index 0d77442323241..9e0d422b2350e 100644 --- a/client/rpc-servers/src/middleware.rs +++ b/client/rpc-servers/src/middleware.rs @@ -204,8 +204,9 @@ impl RpcMiddleware { } /// Called once the JSON-RPC request is finished and response is sent to the output buffer. - fn on_response(&self, _result: &str, started_at: std::time::Instant) { + fn on_response(&self, result: &str, started_at: std::time::Instant) { log::trace!(target: "rpc_metrics", "[{}] on_response started_at={:?}", self.transport_label, started_at); + log::trace!(target: "rpc_metrics::extra", "[{}] result={:?}", self.transport_label, result); self.metrics.requests_finished.with_label_values(&[self.transport_label]).inc(); } } From 33e6029e4c75bab850aac1d10925e2b327e9c4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 10 Dec 2022 14:28:36 +0100 Subject: [PATCH 1460/1472] Ensure that we inform all tasks to stop before starting the 60 seconds shutdown (#12897) * Ensure that we inform all tasks to stop before starting the 60 seconds shutdown The change of waiting in maximum 60 seconds for the node to shutdown actually introduced a bug. We were actually waiting always 60 seconds as we didn't informed our tasks to shutdown. The solution to this problem is to drop the task manager as this will then inform all tasks to end. It also adds tests to ensure that the behaviors work as expected. (This should already have been done in the first pr! :() * ".git/.scripts/fmt.sh" 1 Co-authored-by: command-bot <> --- Cargo.lock | 1 + client/cli/Cargo.toml | 1 + client/cli/src/runner.rs | 211 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 8225e557141d1..110f6fcdc9a19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7227,6 +7227,7 @@ dependencies = [ "clap 4.0.11", "fdlimit", "futures", + "futures-timer", "libp2p", "log", "names", diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 2f079a0c7c56f..fd84ff4d4574b 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -49,6 +49,7 @@ sp-version = { version = "5.0.0", path = "../../primitives/version" } [dev-dependencies] tempfile = "3.1.0" +futures-timer = "3.0.1" [features] default = ["rocksdb"] diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index c976c319708c2..d4191feddfa90 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -145,8 +145,14 @@ impl Runner { E: std::error::Error + Send + Sync + 'static + From, { self.print_node_infos(); + let mut task_manager = self.tokio_runtime.block_on(initialize(self.config))?; let res = self.tokio_runtime.block_on(main(task_manager.future().fuse())); + // We need to drop the task manager here to inform all tasks that they should shut down. + // + // This is important to be done before we instruct the tokio runtime to shutdown. Otherwise + // the tokio runtime will wait the full 60 seconds for all tasks to stop. + drop(task_manager); // Give all futures 60 seconds to shutdown, before tokio "leaks" them. self.tokio_runtime.shutdown_timeout(Duration::from_secs(60)); @@ -208,3 +214,208 @@ pub fn print_node_infos(config: &Configuration) { ); info!("⛓ Native runtime: {}", C::native_runtime_version(&config.chain_spec)); } + +#[cfg(test)] +mod tests { + use std::{ + path::PathBuf, + sync::atomic::{AtomicU64, Ordering}, + }; + + use sc_network::config::NetworkConfiguration; + use sc_service::{Arc, ChainType, GenericChainSpec, NoExtension}; + use sp_runtime::create_runtime_str; + use sp_version::create_apis_vec; + + use super::*; + + struct Cli; + + impl SubstrateCli for Cli { + fn author() -> String { + "test".into() + } + + fn impl_name() -> String { + "yep".into() + } + + fn impl_version() -> String { + "version".into() + } + + fn description() -> String { + "desc".into() + } + + fn support_url() -> String { + "no.pe".into() + } + + fn copyright_start_year() -> i32 { + 2042 + } + + fn load_spec( + &self, + _: &str, + ) -> std::result::Result, String> { + Err("nope".into()) + } + + fn native_runtime_version( + _: &Box, + ) -> &'static sp_version::RuntimeVersion { + const VERSION: sp_version::RuntimeVersion = sp_version::RuntimeVersion { + spec_name: create_runtime_str!("spec"), + impl_name: create_runtime_str!("name"), + authoring_version: 0, + spec_version: 0, + impl_version: 0, + apis: create_apis_vec!([]), + transaction_version: 2, + state_version: 0, + }; + + &VERSION + } + } + + fn create_runner() -> Runner { + let runtime = build_runtime().unwrap(); + + let runner = Runner::new( + Configuration { + impl_name: "spec".into(), + impl_version: "3".into(), + role: sc_service::Role::Authority, + tokio_handle: runtime.handle().clone(), + transaction_pool: Default::default(), + network: NetworkConfiguration::new_memory(), + keystore: sc_service::config::KeystoreConfig::InMemory, + keystore_remote: None, + database: sc_client_db::DatabaseSource::ParityDb { path: PathBuf::from("db") }, + trie_cache_maximum_size: None, + state_pruning: None, + blocks_pruning: sc_client_db::BlocksPruning::KeepAll, + chain_spec: Box::new(GenericChainSpec::from_genesis( + "test", + "test_id", + ChainType::Development, + || unimplemented!("Not required in tests"), + Vec::new(), + None, + None, + None, + None, + NoExtension::None, + )), + wasm_method: Default::default(), + wasm_runtime_overrides: None, + execution_strategies: Default::default(), + rpc_http: None, + rpc_ws: None, + rpc_ipc: None, + rpc_ws_max_connections: None, + rpc_cors: None, + rpc_methods: Default::default(), + rpc_max_payload: None, + rpc_max_request_size: None, + rpc_max_response_size: None, + rpc_id_provider: None, + rpc_max_subs_per_conn: None, + ws_max_out_buffer_capacity: None, + prometheus_config: None, + telemetry_endpoints: None, + default_heap_pages: None, + offchain_worker: Default::default(), + force_authoring: false, + disable_grandpa: false, + dev_key_seed: None, + tracing_targets: None, + tracing_receiver: Default::default(), + max_runtime_instances: 8, + announce_block: true, + base_path: None, + informant_output_format: Default::default(), + runtime_cache_size: 2, + }, + runtime, + ) + .unwrap(); + + runner + } + + #[test] + fn ensure_run_until_exit_informs_tasks_to_end() { + let runner = create_runner(); + + let counter = Arc::new(AtomicU64::new(0)); + let counter2 = counter.clone(); + + runner + .run_node_until_exit(move |cfg| async move { + let task_manager = TaskManager::new(cfg.tokio_handle.clone(), None).unwrap(); + let (sender, receiver) = futures::channel::oneshot::channel(); + + // We need to use `spawn_blocking` here so that we get a dedicated thread for our + // future. This is important for this test, as otherwise tokio can just "drop" the + // future. + task_manager.spawn_handle().spawn_blocking("test", None, async move { + let _ = sender.send(()); + loop { + counter2.fetch_add(1, Ordering::Relaxed); + futures_timer::Delay::new(Duration::from_millis(50)).await; + } + }); + + task_manager.spawn_essential_handle().spawn_blocking("test2", None, async { + // Let's stop this essential task directly when our other task started. + // It will signal that the task manager should end. + let _ = receiver.await; + }); + + Ok::<_, sc_service::Error>(task_manager) + }) + .unwrap_err(); + + let count = counter.load(Ordering::Relaxed); + + // Ensure that our counting task was running for less than 30 seconds. + // It should be directly killed, but for CI and whatever we are being a little bit more + // "relaxed". + assert!((count as u128) < (Duration::from_secs(30).as_millis() / 50)); + } + + /// This test ensures that `run_node_until_exit` aborts waiting for "stuck" tasks after 60 + /// seconds, aka doesn't wait until they are finished (which may never happen). + #[test] + fn ensure_run_until_exit_is_not_blocking_indefinitely() { + let runner = create_runner(); + + runner + .run_node_until_exit(move |cfg| async move { + let task_manager = TaskManager::new(cfg.tokio_handle.clone(), None).unwrap(); + let (sender, receiver) = futures::channel::oneshot::channel(); + + // We need to use `spawn_blocking` here so that we get a dedicated thread for our + // future. This future is more blocking code that will never end. + task_manager.spawn_handle().spawn_blocking("test", None, async move { + let _ = sender.send(()); + loop { + std::thread::sleep(Duration::from_secs(30)); + } + }); + + task_manager.spawn_essential_handle().spawn_blocking("test2", None, async { + // Let's stop this essential task directly when our other task started. + // It will signal that the task manager should end. + let _ = receiver.await; + }); + + Ok::<_, sc_service::Error>(task_manager) + }) + .unwrap_err(); + } +} From 2f0d59d766ff79ca2b552216a411c8e2b1762da4 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Sat, 10 Dec 2022 23:52:23 +0100 Subject: [PATCH 1461/1472] Safe desired targets call (#12826) * checked call for desired targets * fix compile * fmt * fix tests * cleaner with and_then --- frame/election-provider-multi-phase/src/lib.rs | 10 +++++----- .../election-provider-multi-phase/src/signed.rs | 10 ++++++---- frame/election-provider-support/src/lib.rs | 16 +++++++--------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 2d49cd79dbcad..cd70514fd3461 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1409,12 +1409,12 @@ impl Pallet { return Err(ElectionError::DataProvider("Snapshot too big for submission.")) } - let mut desired_targets = - T::DataProvider::desired_targets().map_err(ElectionError::DataProvider)?; + let mut desired_targets = as ElectionProviderBase>::desired_targets_checked() + .map_err(|e| ElectionError::DataProvider(e))?; - // If `desired_targets` > `targets.len()`, cap `desired_targets` to that - // level and emit a warning - let max_desired_targets: u32 = (targets.len() as u32).min(T::MaxWinners::get()); + // If `desired_targets` > `targets.len()`, cap `desired_targets` to that level and emit a + // warning + let max_desired_targets: u32 = targets.len() as u32; if desired_targets > max_desired_targets { log!( warn, diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 9d629ad77fd79..12d39e83b6c09 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -594,10 +594,12 @@ mod tests { DesiredTargets::set(4); MaxWinners::set(3); - let (_, _, actual_desired_targets) = MultiPhase::create_snapshot_external().unwrap(); - - // snapshot is created with min of desired_targets and MaxWinners - assert_eq!(actual_desired_targets, 3); + // snapshot not created because data provider returned an unexpected number of + // desired_targets + assert_noop!( + MultiPhase::create_snapshot_external(), + ElectionError::DataProvider("desired_targets must not be greater than MaxWinners."), + ); }) } diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 38924a18e2f54..8b26148844c39 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -386,15 +386,13 @@ pub trait ElectionProviderBase { /// checked call to `Self::DataProvider::desired_targets()` ensuring the value never exceeds /// [`Self::MaxWinners`]. fn desired_targets_checked() -> data_provider::Result { - match Self::DataProvider::desired_targets() { - Ok(desired_targets) => - if desired_targets <= Self::MaxWinners::get() { - Ok(desired_targets) - } else { - Err("desired_targets should not be greater than MaxWinners") - }, - Err(e) => Err(e), - } + Self::DataProvider::desired_targets().and_then(|desired_targets| { + if desired_targets <= Self::MaxWinners::get() { + Ok(desired_targets) + } else { + Err("desired_targets must not be greater than MaxWinners.") + } + }) } } From 0ba5206f670d7029dcab20d4a6df05e796fe6716 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 12 Dec 2022 09:10:18 +1100 Subject: [PATCH 1462/1472] Fix typo (#12900) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02f8a7591acc5..7d8c7e575581c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Then try out one of the [tutorials](https://docs.substrate.io/tutorials/). ## Community & Support -Join the highly active and supportive community on the [Susbstrate Stack Exchange](https://substrate.stackexchange.com/) to ask questions about use and problems you run into using this software. +Join the highly active and supportive community on the [Substrate Stack Exchange](https://substrate.stackexchange.com/) to ask questions about use and problems you run into using this software. Please do report bugs and [issues here](https://github.com/paritytech/substrate/issues) for anything you suspect requires action in the source. ## Contributions & Code of Conduct From 9772209ee962fe36c3502afb638e1bd835c23d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 11 Dec 2022 23:18:59 +0100 Subject: [PATCH 1463/1472] ValidateUnsigned: Improve docs. (#12870) * ValidateUnsigned: Improve docs. * Review comments --- primitives/runtime/src/traits.rs | 33 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 6af711cba8e50..c69f8616b4be5 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1335,12 +1335,13 @@ pub trait GetNodeBlockType { type NodeBlock: self::Block; } -/// Something that can validate unsigned extrinsics for the transaction pool. +/// Provide validation for unsigned extrinsics. /// -/// Note that any checks done here are only used for determining the validity of -/// the transaction for the transaction pool. -/// During block execution phase one need to perform the same checks anyway, -/// since this function is not being called. +/// This trait provides two functions [`pre_dispatch`](Self::pre_dispatch) and +/// [`validate_unsigned`](Self::validate_unsigned). The [`pre_dispatch`](Self::pre_dispatch) +/// function is called right before dispatching the call wrapped by an unsigned extrinsic. The +/// [`validate_unsigned`](Self::validate_unsigned) function is mainly being used in the context of +/// the transaction pool to check the validity of the call wrapped by an unsigned extrinsic. pub trait ValidateUnsigned { /// The call to validate type Call; @@ -1348,13 +1349,15 @@ pub trait ValidateUnsigned { /// Validate the call right before dispatch. /// /// This method should be used to prevent transactions already in the pool - /// (i.e. passing `validate_unsigned`) from being included in blocks - /// in case we know they now became invalid. + /// (i.e. passing [`validate_unsigned`](Self::validate_unsigned)) from being included in blocks + /// in case they became invalid since being added to the pool. /// - /// By default it's a good idea to call `validate_unsigned` from within - /// this function again to make sure we never include an invalid transaction. + /// By default it's a good idea to call [`validate_unsigned`](Self::validate_unsigned) from + /// within this function again to make sure we never include an invalid transaction. Otherwise + /// the implementation of the call or this method will need to provide proper validation to + /// ensure that the transaction is valid. /// - /// Changes made to storage WILL be persisted if the call returns `Ok`. + /// Changes made to storage *WILL* be persisted if the call returns `Ok`. fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { Self::validate_unsigned(TransactionSource::InBlock, call) .map(|_| ()) @@ -1363,8 +1366,14 @@ pub trait ValidateUnsigned { /// Return the validity of the call /// - /// This doesn't execute any side-effects; it merely checks - /// whether the transaction would panic if it were included or not. + /// This method has no side-effects. It merely checks whether the call would be rejected + /// by the runtime in an unsigned extrinsic. + /// + /// The validity checks should be as lightweight as possible because every node will execute + /// this code before the unsigned extrinsic enters the transaction pool and also periodically + /// afterwards to ensure the validity. To prevent dos-ing a network with unsigned + /// extrinsics, these validity checks should include some checks around uniqueness, for example, + /// like checking that the unsigned extrinsic was send by an authority in the active set. /// /// Changes made to storage should be discarded by caller. fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity; From 06090ab35255833d892016dfc74fdc9d2d2fe06f Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 12 Dec 2022 11:32:55 +0100 Subject: [PATCH 1464/1472] rpc server with HTTP/WS on the same socket (#12663) * jsonrpsee v0.16 add backwards compatibility run old http server on http only * cargo fmt * update jsonrpsee 0.16.1 * less verbose cors log * fix nit in log: WS -> HTTP * revert needless changes in Cargo.lock * remove unused features in tower * fix nits; add client-core feature * jsonrpsee v0.16.2 --- Cargo.lock | 165 ++++++++++-------- bin/node-template/node/Cargo.toml | 2 +- bin/node/cli/Cargo.toml | 2 +- bin/node/rpc/Cargo.toml | 2 +- client/beefy/rpc/Cargo.toml | 2 +- client/beefy/rpc/src/lib.rs | 2 +- client/consensus/babe/rpc/Cargo.toml | 2 +- client/consensus/manual-seal/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/finality-grandpa/rpc/src/lib.rs | 2 +- client/merkle-mountain-range/rpc/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-servers/Cargo.toml | 5 +- client/rpc-servers/src/lib.rs | 142 ++++++++------- client/rpc-servers/src/middleware.rs | 130 +++++--------- client/rpc-spec-v2/Cargo.toml | 2 +- client/rpc-spec-v2/src/chain_spec/tests.rs | 2 +- client/rpc/Cargo.toml | 2 +- client/rpc/src/author/tests.rs | 2 +- client/rpc/src/chain/tests.rs | 2 +- client/rpc/src/state/mod.rs | 3 +- client/rpc/src/state/tests.rs | 2 +- client/rpc/src/system/tests.rs | 2 +- client/service/Cargo.toml | 2 +- client/service/src/lib.rs | 50 ++---- client/sync-state-rpc/Cargo.toml | 2 +- frame/transaction-payment/rpc/Cargo.toml | 2 +- utils/frame/remote-externalities/src/lib.rs | 120 ++++++++----- utils/frame/rpc/client/Cargo.toml | 2 +- utils/frame/rpc/client/src/lib.rs | 5 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- utils/frame/rpc/support/Cargo.toml | 4 +- utils/frame/rpc/system/Cargo.toml | 2 +- 33 files changed, 355 insertions(+), 317 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 110f6fcdc9a19..2f2b4aa7cf35d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,7 +288,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.9", ] [[package]] @@ -2293,7 +2293,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.9", "waker-fn", ] @@ -2350,7 +2350,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.9", "pin-utils", "slab", ] @@ -2667,15 +2667,21 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.6", + "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" @@ -2710,7 +2716,7 @@ dependencies = [ "httparse", "httpdate", "itoa 1.0.4", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.9", "socket2", "tokio", "tower-service", @@ -2907,24 +2913,23 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd0d559d5e679b1ab2f869b486a11182923863b1b3ee8b421763cdd707b783a" +checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" dependencies = [ "jsonrpsee-core", - "jsonrpsee-http-server", "jsonrpsee-proc-macros", + "jsonrpsee-server", "jsonrpsee-types", "jsonrpsee-ws-client", - "jsonrpsee-ws-server", "tracing", ] [[package]] name = "jsonrpsee-client-transport" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8752740ecd374bcbf8b69f3e80b0327942df76f793f8d4e60d3355650c31fb74" +checksum = "965de52763f2004bc91ac5bcec504192440f0b568a5d621c59d9dbd6f886c3fb" dependencies = [ "futures-util", "http", @@ -2943,9 +2948,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3dc3e9cf2ba50b7b1d7d76a667619f82846caa39e8e8daa8a4962d74acaddca" +checksum = "a4e70b4439a751a5de7dd5ed55eacff78ebf4ffe0fc009cb1ebb11417f5b536b" dependencies = [ "anyhow", "arrayvec 0.7.2", @@ -2956,10 +2961,8 @@ dependencies = [ "futures-timer", "futures-util", "globset", - "http", "hyper", "jsonrpsee-types", - "lazy_static", "parking_lot 0.12.1", "rand 0.8.5", "rustc-hash", @@ -2969,45 +2972,48 @@ dependencies = [ "thiserror", "tokio", "tracing", - "tracing-futures", - "unicase", ] [[package]] -name = "jsonrpsee-http-server" -version = "0.15.1" +name = "jsonrpsee-proc-macros" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa6da1e4199c10d7b1d0a6e5e8bd8e55f351163b6f4b3cbb044672a69bd4c1c" +dependencies = [ + "heck", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03802f0373a38c2420c70b5144742d800b509e2937edc4afb116434f07120117" +checksum = "1fb69dad85df79527c019659a992498d03f8495390496da2f07e6c24c2b356fc" dependencies = [ "futures-channel", "futures-util", + "http", "hyper", "jsonrpsee-core", "jsonrpsee-types", "serde", "serde_json", + "soketto", "tokio", + "tokio-stream", + "tokio-util", + "tower", "tracing", - "tracing-futures", -] - -[[package]] -name = "jsonrpsee-proc-macros" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd67957d4280217247588ac86614ead007b301ca2fa9f19c19f880a536f029e3" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", ] [[package]] name = "jsonrpsee-types" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e290bba767401b646812f608c099b922d8142603c9e73a50fb192d3ac86f4a0d" +checksum = "5bd522fe1ce3702fd94812965d7bb7a3364b1c9aba743944c5a00529aae80f8c" dependencies = [ "anyhow", "beef", @@ -3019,9 +3025,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee5feddd5188e62ac08fcf0e56478138e581509d4730f3f7be9b57dd402a4ff" +checksum = "0b83daeecfc6517cfe210df24e570fb06213533dfb990318fae781f4c7119dd9" dependencies = [ "http", "jsonrpsee-client-transport", @@ -3029,26 +3035,6 @@ dependencies = [ "jsonrpsee-types", ] -[[package]] -name = "jsonrpsee-ws-server" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d488ba74fb369e5ab68926feb75a483458b88e768d44319f37e4ecad283c7325" -dependencies = [ - "futures-channel", - "futures-util", - "http", - "jsonrpsee-core", - "jsonrpsee-types", - "serde_json", - "soketto", - "tokio", - "tokio-stream", - "tokio-util", - "tracing", - "tracing-futures", -] - [[package]] name = "k256" version = "0.11.5" @@ -6334,9 +6320,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -8110,11 +8096,14 @@ name = "sc-rpc-server" version = "4.0.0-dev" dependencies = [ "futures", + "http", "jsonrpsee", "log", "serde_json", "substrate-prometheus-endpoint", "tokio", + "tower", + "tower-http", ] [[package]] @@ -8822,6 +8811,7 @@ dependencies = [ "bytes", "flate2", "futures", + "http", "httparse", "log", "rand 0.8.5", @@ -10297,7 +10287,7 @@ dependencies = [ "mio", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.9", "signal-hook-registry", "socket2", "tokio-macros", @@ -10333,7 +10323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" dependencies = [ "futures-core", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.9", "tokio", ] @@ -10360,7 +10350,7 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.9", "tokio", "tracing", ] @@ -10374,6 +10364,41 @@ dependencies = [ "serde", ] +[[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.1" @@ -10387,7 +10412,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ "cfg-if", - "pin-project-lite 0.2.6", + "log", + "pin-project-lite 0.2.9", "tracing-attributes", "tracing-core", ] @@ -10657,15 +10683,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.4" diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index d609edc88401d..2ea841093d0e2 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -43,7 +43,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" } # These dependencies are used for the node template's RPCs -jsonrpsee = { version = "0.15.1", features = ["server"] } +jsonrpsee = { version = "0.16.2", features = ["server"] } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 2ca37e7febe16..4ee4bcd033921 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -39,7 +39,7 @@ array-bytes = "4.1" clap = { version = "4.0.9", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } -jsonrpsee = { version = "0.15.1", features = ["server"] } +jsonrpsee = { version = "0.16.2", features = ["server"] } futures = "0.3.21" log = "0.4.17" rand = "0.8" diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 9d2810413613f..f34922a287dfe 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.15.1", features = ["server"] } +jsonrpsee = { version = "0.16.2", features = ["server"] } node-primitives = { version = "2.0.0", path = "../primitives" } pallet-transaction-payment-rpc = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/rpc/" } mmr-rpc = { version = "4.0.0-dev", path = "../../../client/merkle-mountain-range/rpc/" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index d27225824539a..f5b5770153477 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://substrate.io" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } log = "0.4" parking_lot = "0.12.1" serde = { version = "1.0.136", features = ["derive"] } diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index d29ed433c38db..59a133b86214e 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -172,7 +172,7 @@ mod tests { }; use beefy_primitives::{known_payloads, Payload, SignedCommitment}; use codec::{Decode, Encode}; - use jsonrpsee::{types::EmptyParams, RpcModule}; + use jsonrpsee::{types::EmptyServerParams as EmptyParams, RpcModule}; use sp_runtime::traits::{BlakeTwo256, Hash}; use substrate_test_runtime_client::runtime::Block; diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index d0a65a3fc3193..4f5aaf85494b9 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } futures = "0.3.21" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0" diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index cf151424c2ee5..fb89445a97002 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } assert_matches = "1.3.0" async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 7be77c122bab2..252c5e3871a64 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" [dependencies] finality-grandpa = { version = "0.16.0", features = ["derive-codec"] } futures = "0.3.16" -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } log = "0.4.8" parity-scale-codec = { version = "3.0.0", features = ["derive"] } serde = { version = "1.0.105", features = ["derive"] } diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index 85df72de77b54..dfdad666ba8f3 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -138,7 +138,7 @@ mod tests { use std::{collections::HashSet, convert::TryInto, sync::Arc}; use jsonrpsee::{ - types::{EmptyParams, SubscriptionId}, + types::{EmptyServerParams as EmptyParams, SubscriptionId}, RpcModule, }; use parity_scale_codec::{Decode, Encode}; diff --git a/client/merkle-mountain-range/rpc/Cargo.toml b/client/merkle-mountain-range/rpc/Cargo.toml index ca14544000bdb..dcc5e49c52051 100644 --- a/client/merkle-mountain-range/rpc/Cargo.toml +++ b/client/merkle-mountain-range/rpc/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index cb82a3b26706b..c46488db2d8e1 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -28,4 +28,4 @@ sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" } sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } sp-version = { version = "5.0.0", path = "../../primitives/version" } -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["server", "client-core", "macros"] } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index a3e64c367afb6..b494749ffd26a 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -14,8 +14,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" -jsonrpsee = { version = "0.15.1", features = ["server"] } +jsonrpsee = { version = "0.16.2", features = ["server"] } log = "0.4.17" serde_json = "1.0.85" tokio = { version = "1.22.0", features = ["parking_lot"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } +tower-http = { version = "0.3.4", features = ["cors"] } +tower = "0.4.13" +http = "0.2.8" diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 7eb825e169bfa..1fa2ba81d8672 100644 --- a/client/rpc-servers/src/lib.rs +++ b/client/rpc-servers/src/lib.rs @@ -21,17 +21,21 @@ #![warn(missing_docs)] use jsonrpsee::{ - http_server::{AccessControlBuilder, HttpServerBuilder, HttpServerHandle}, - ws_server::{WsServerBuilder, WsServerHandle}, + server::{ + middleware::proxy_get_request::ProxyGetRequestLayer, AllowHosts, ServerBuilder, + ServerHandle, + }, RpcModule, }; use std::{error::Error as StdError, net::SocketAddr}; -pub use crate::middleware::{RpcMetrics, RpcMiddleware}; +pub use crate::middleware::RpcMetrics; +use http::header::HeaderValue; pub use jsonrpsee::core::{ id_providers::{RandomIntegerIdProvider, RandomStringIdProvider}, traits::IdProvider, }; +use tower_http::cors::{AllowOrigin, CorsLayer}; const MEGABYTE: usize = 1024 * 1024; @@ -46,12 +50,11 @@ const WS_MAX_SUBS_PER_CONN: usize = 1024; pub mod middleware; -/// Type alias for http server -pub type HttpServer = HttpServerHandle; -/// Type alias for ws server -pub type WsServer = WsServerHandle; +/// Type alias JSON-RPC server +pub type Server = ServerHandle; -/// WebSocket specific settings on the server. +/// Server config. +#[derive(Debug, Clone)] pub struct WsConfig { /// Maximum connections. pub max_connections: Option, @@ -67,8 +70,8 @@ impl WsConfig { // Deconstructs the config to get the finalized inner values. // // `Payload size` or `max subs per connection` bigger than u32::MAX will be truncated. - fn deconstruct(self) -> (u32, u32, u64, u32) { - let max_conns = self.max_connections.unwrap_or(WS_MAX_CONNECTIONS) as u64; + fn deconstruct(self) -> (u32, u32, u32, u32) { + let max_conns = self.max_connections.unwrap_or(WS_MAX_CONNECTIONS) as u32; let max_payload_in_mb = payload_size_or_default(self.max_payload_in_mb) as u32; let max_payload_out_mb = payload_size_or_default(self.max_payload_out_mb) as u32; let max_subs_per_conn = self.max_subs_per_conn.unwrap_or(WS_MAX_SUBS_PER_CONN) as u32; @@ -86,31 +89,27 @@ pub async fn start_http( metrics: Option, rpc_api: RpcModule, rt: tokio::runtime::Handle, -) -> Result> { - let max_payload_in = payload_size_or_default(max_payload_in_mb); - let max_payload_out = payload_size_or_default(max_payload_out_mb); +) -> Result> { + let max_payload_in = payload_size_or_default(max_payload_in_mb) as u32; + let max_payload_out = payload_size_or_default(max_payload_out_mb) as u32; + let host_filter = hosts_filter(cors.is_some(), &addrs); - let mut acl = AccessControlBuilder::new(); + let middleware = tower::ServiceBuilder::new() + // Proxy `GET /health` requests to internal `system_health` method. + .layer(ProxyGetRequestLayer::new("/health", "system_health")?) + .layer(try_into_cors(cors)?); - if let Some(cors) = cors { - // Whitelist listening address. - // NOTE: set_allowed_hosts will whitelist both ports but only one will used. - acl = acl.set_allowed_hosts(format_allowed_hosts(&addrs[..]))?; - acl = acl.set_allowed_origins(cors)?; - }; - - let builder = HttpServerBuilder::new() - .max_request_body_size(max_payload_in as u32) - .max_response_body_size(max_payload_out as u32) - .set_access_control(acl.build()) - .health_api("/health", "system_health")? - .custom_tokio_runtime(rt); + let builder = ServerBuilder::new() + .max_request_body_size(max_payload_in) + .max_response_body_size(max_payload_out) + .set_host_filtering(host_filter) + .set_middleware(middleware) + .custom_tokio_runtime(rt) + .http_only(); let rpc_api = build_rpc_api(rpc_api); let (handle, addr) = if let Some(metrics) = metrics { - let middleware = RpcMiddleware::new(metrics, "http".into()); - let builder = builder.set_middleware(middleware); - let server = builder.build(&addrs[..]).await?; + let server = builder.set_logger(metrics).build(&addrs[..]).await?; let addr = server.local_addr(); (server.start(rpc_api)?, addr) } else { @@ -120,16 +119,16 @@ pub async fn start_http( }; log::info!( - "Running JSON-RPC HTTP server: addr={}, allowed origins={:?}", + "Running JSON-RPC HTTP server: addr={}, allowed origins={}", addr.map_or_else(|_| "unknown".to_string(), |a| a.to_string()), - cors + format_cors(cors) ); Ok(handle) } -/// Start WS server listening on given address. -pub async fn start_ws( +/// Start a JSON-RPC server listening on given address that supports both HTTP and WS. +pub async fn start( addrs: [SocketAddr; 2], cors: Option<&Vec>, ws_config: WsConfig, @@ -137,27 +136,26 @@ pub async fn start_ws( rpc_api: RpcModule, rt: tokio::runtime::Handle, id_provider: Option>, -) -> Result> { +) -> Result> { let (max_payload_in, max_payload_out, max_connections, max_subs_per_conn) = ws_config.deconstruct(); - let mut acl = AccessControlBuilder::new(); + let host_filter = hosts_filter(cors.is_some(), &addrs); - if let Some(cors) = cors { - // Whitelist listening address. - // NOTE: set_allowed_hosts will whitelist both ports but only one will used. - acl = acl.set_allowed_hosts(format_allowed_hosts(&addrs[..]))?; - acl = acl.set_allowed_origins(cors)?; - }; + let middleware = tower::ServiceBuilder::new() + // Proxy `GET /health` requests to internal `system_health` method. + .layer(ProxyGetRequestLayer::new("/health", "system_health")?) + .layer(try_into_cors(cors)?); - let mut builder = WsServerBuilder::new() + let mut builder = ServerBuilder::new() .max_request_body_size(max_payload_in) .max_response_body_size(max_payload_out) .max_connections(max_connections) .max_subscriptions_per_connection(max_subs_per_conn) .ping_interval(std::time::Duration::from_secs(30)) - .custom_tokio_runtime(rt) - .set_access_control(acl.build()); + .set_host_filtering(host_filter) + .set_middleware(middleware) + .custom_tokio_runtime(rt); if let Some(provider) = id_provider { builder = builder.set_id_provider(provider); @@ -167,9 +165,7 @@ pub async fn start_ws( let rpc_api = build_rpc_api(rpc_api); let (handle, addr) = if let Some(metrics) = metrics { - let middleware = RpcMiddleware::new(metrics, "ws".into()); - let builder = builder.set_middleware(middleware); - let server = builder.build(&addrs[..]).await?; + let server = builder.set_logger(metrics).build(&addrs[..]).await?; let addr = server.local_addr(); (server.start(rpc_api)?, addr) } else { @@ -179,23 +175,14 @@ pub async fn start_ws( }; log::info!( - "Running JSON-RPC WS server: addr={}, allowed origins={:?}", + "Running JSON-RPC WS server: addr={}, allowed origins={}", addr.map_or_else(|_| "unknown".to_string(), |a| a.to_string()), - cors + format_cors(cors) ); Ok(handle) } -fn format_allowed_hosts(addrs: &[SocketAddr]) -> Vec { - let mut hosts = Vec::with_capacity(addrs.len() * 2); - for addr in addrs { - hosts.push(format!("localhost:{}", addr.port())); - hosts.push(format!("127.0.0.1:{}", addr.port())); - } - hosts -} - fn build_rpc_api(mut rpc_api: RpcModule) -> RpcModule { let mut available_methods = rpc_api.method_names().collect::>(); available_methods.sort(); @@ -214,3 +201,40 @@ fn build_rpc_api(mut rpc_api: RpcModule) -> RpcModu fn payload_size_or_default(size_mb: Option) -> usize { size_mb.map_or(RPC_MAX_PAYLOAD_DEFAULT, |mb| mb.saturating_mul(MEGABYTE)) } + +fn hosts_filter(enabled: bool, addrs: &[SocketAddr]) -> AllowHosts { + if enabled { + // NOTE The listening addresses are whitelisted by default. + let mut hosts = Vec::with_capacity(addrs.len() * 2); + for addr in addrs { + hosts.push(format!("localhost:{}", addr.port()).into()); + hosts.push(format!("127.0.0.1:{}", addr.port()).into()); + } + AllowHosts::Only(hosts) + } else { + AllowHosts::Any + } +} + +fn try_into_cors( + maybe_cors: Option<&Vec>, +) -> Result> { + if let Some(cors) = maybe_cors { + let mut list = Vec::new(); + for origin in cors { + list.push(HeaderValue::from_str(origin)?); + } + Ok(CorsLayer::new().allow_origin(AllowOrigin::list(list))) + } else { + // allow all cors + Ok(CorsLayer::permissive()) + } +} + +fn format_cors(maybe_cors: Option<&Vec>) -> String { + if let Some(cors) = maybe_cors { + format!("{:?}", cors) + } else { + format!("{:?}", ["*"]) + } +} diff --git a/client/rpc-servers/src/middleware.rs b/client/rpc-servers/src/middleware.rs index 9e0d422b2350e..1c25ac1dfd1b3 100644 --- a/client/rpc-servers/src/middleware.rs +++ b/client/rpc-servers/src/middleware.rs @@ -16,9 +16,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! RPC middlware to collect prometheus metrics on RPC calls. +//! RPC middleware to collect prometheus metrics on RPC calls. -use jsonrpsee::core::middleware::{Headers, HttpMiddleware, MethodKind, Params, WsMiddleware}; +use jsonrpsee::server::logger::{HttpRequest, Logger, MethodKind, Params, TransportProtocol}; use prometheus_endpoint::{ register, Counter, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry, U64, @@ -54,9 +54,9 @@ pub struct RpcMetrics { calls_started: CounterVec, /// Number of calls completed. calls_finished: CounterVec, - /// Number of Websocket sessions opened (Websocket only). + /// Number of Websocket sessions opened. ws_sessions_opened: Option>, - /// Number of Websocket sessions closed (Websocket only). + /// Number of Websocket sessions closed. ws_sessions_closed: Option>, } @@ -139,62 +139,61 @@ impl RpcMetrics { } } -#[derive(Clone)] -/// Middleware for RPC calls -pub struct RpcMiddleware { - metrics: RpcMetrics, - transport_label: &'static str, -} +impl Logger for RpcMetrics { + type Instant = std::time::Instant; -impl RpcMiddleware { - /// Create a new [`RpcMiddleware`] with the provided [`RpcMetrics`]. - pub fn new(metrics: RpcMetrics, transport_label: &'static str) -> Self { - Self { metrics, transport_label } + fn on_connect( + &self, + _remote_addr: SocketAddr, + _request: &HttpRequest, + transport: TransportProtocol, + ) { + if let TransportProtocol::WebSocket = transport { + self.ws_sessions_opened.as_ref().map(|counter| counter.inc()); + } } - /// Called when a new JSON-RPC request comes to the server. - fn on_request(&self) -> std::time::Instant { + fn on_request(&self, transport: TransportProtocol) -> Self::Instant { + let transport_label = transport_label_str(transport); let now = std::time::Instant::now(); - self.metrics.requests_started.with_label_values(&[self.transport_label]).inc(); + self.requests_started.with_label_values(&[transport_label]).inc(); now } - /// Called on each JSON-RPC method call, batch requests will trigger `on_call` multiple times. - fn on_call(&self, name: &str, params: Params, kind: MethodKind) { + fn on_call(&self, name: &str, params: Params, kind: MethodKind, transport: TransportProtocol) { + let transport_label = transport_label_str(transport); log::trace!( target: "rpc_metrics", "[{}] on_call name={} params={:?} kind={}", - self.transport_label, + transport_label, name, params, kind, ); - self.metrics - .calls_started - .with_label_values(&[self.transport_label, name]) - .inc(); + self.calls_started.with_label_values(&[transport_label, name]).inc(); } - /// Called on each JSON-RPC method completion, batch requests will trigger `on_result` multiple - /// times. - fn on_result(&self, name: &str, success: bool, started_at: std::time::Instant) { + fn on_result( + &self, + name: &str, + success: bool, + started_at: Self::Instant, + transport: TransportProtocol, + ) { + let transport_label = transport_label_str(transport); let micros = started_at.elapsed().as_micros(); log::debug!( target: "rpc_metrics", "[{}] {} call took {} μs", - self.transport_label, + transport_label, name, micros, ); - self.metrics - .calls_time - .with_label_values(&[self.transport_label, name]) - .observe(micros as _); + self.calls_time.with_label_values(&[transport_label, name]).observe(micros as _); - self.metrics - .calls_finished + self.calls_finished .with_label_values(&[ - self.transport_label, + transport_label, name, // the label "is_error", so `success` should be regarded as false // and vice-versa to be registrered correctly. @@ -203,58 +202,23 @@ impl RpcMiddleware { .inc(); } - /// Called once the JSON-RPC request is finished and response is sent to the output buffer. - fn on_response(&self, result: &str, started_at: std::time::Instant) { - log::trace!(target: "rpc_metrics", "[{}] on_response started_at={:?}", self.transport_label, started_at); - log::trace!(target: "rpc_metrics::extra", "[{}] result={:?}", self.transport_label, result); - self.metrics.requests_finished.with_label_values(&[self.transport_label]).inc(); - } -} - -impl WsMiddleware for RpcMiddleware { - type Instant = std::time::Instant; - - fn on_connect(&self, _remote_addr: SocketAddr, _headers: &Headers) { - self.metrics.ws_sessions_opened.as_ref().map(|counter| counter.inc()); - } - - fn on_request(&self) -> Self::Instant { - self.on_request() - } - - fn on_call(&self, name: &str, params: Params, kind: MethodKind) { - self.on_call(name, params, kind) + fn on_response(&self, result: &str, started_at: Self::Instant, transport: TransportProtocol) { + let transport_label = transport_label_str(transport); + log::trace!(target: "rpc_metrics", "[{}] on_response started_at={:?}", transport_label, started_at); + log::trace!(target: "rpc_metrics::extra", "[{}] result={:?}", transport_label, result); + self.requests_finished.with_label_values(&[transport_label]).inc(); } - fn on_result(&self, name: &str, success: bool, started_at: Self::Instant) { - self.on_result(name, success, started_at) - } - - fn on_response(&self, _result: &str, started_at: Self::Instant) { - self.on_response(_result, started_at) - } - - fn on_disconnect(&self, _remote_addr: SocketAddr) { - self.metrics.ws_sessions_closed.as_ref().map(|counter| counter.inc()); + fn on_disconnect(&self, _remote_addr: SocketAddr, transport: TransportProtocol) { + if let TransportProtocol::WebSocket = transport { + self.ws_sessions_closed.as_ref().map(|counter| counter.inc()); + } } } -impl HttpMiddleware for RpcMiddleware { - type Instant = std::time::Instant; - - fn on_request(&self, _remote_addr: SocketAddr, _headers: &Headers) -> Self::Instant { - self.on_request() - } - - fn on_call(&self, name: &str, params: Params, kind: MethodKind) { - self.on_call(name, params, kind) - } - - fn on_result(&self, name: &str, success: bool, started_at: Self::Instant) { - self.on_result(name, success, started_at) - } - - fn on_response(&self, _result: &str, started_at: Self::Instant) { - self.on_response(_result, started_at) +fn transport_label_str(t: TransportProtocol) -> &'static str { + match t { + TransportProtocol::Http => "http", + TransportProtocol::WebSocket => "ws", } } diff --git a/client/rpc-spec-v2/Cargo.toml b/client/rpc-spec-v2/Cargo.toml index a0ae3038378ff..930aeb4bd8956 100644 --- a/client/rpc-spec-v2/Cargo.toml +++ b/client/rpc-spec-v2/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } # Internal chain structures for "chain_spec". sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } # Pool for submitting extrinsics required by "transaction" diff --git a/client/rpc-spec-v2/src/chain_spec/tests.rs b/client/rpc-spec-v2/src/chain_spec/tests.rs index 6c078b2974e98..6f662ba422bc4 100644 --- a/client/rpc-spec-v2/src/chain_spec/tests.rs +++ b/client/rpc-spec-v2/src/chain_spec/tests.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::*; -use jsonrpsee::{types::EmptyParams, RpcModule}; +use jsonrpsee::{types::EmptyServerParams as EmptyParams, RpcModule}; use sc_chain_spec::Properties; const CHAIN_NAME: &'static str = "TEST_CHAIN_NAME"; diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index d690e2c7b4cf1..a241807cc242b 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" hash-db = { version = "0.15.2", default-features = false } -jsonrpsee = { version = "0.15.1", features = ["server"] } +jsonrpsee = { version = "0.16.2", features = ["server"] } lazy_static = { version = "1.4.0", optional = true } log = "0.4.17" parking_lot = "0.12.1" diff --git a/client/rpc/src/author/tests.rs b/client/rpc/src/author/tests.rs index f969812e5b14c..573d01630de32 100644 --- a/client/rpc/src/author/tests.rs +++ b/client/rpc/src/author/tests.rs @@ -23,7 +23,7 @@ use assert_matches::assert_matches; use codec::Encode; use jsonrpsee::{ core::Error as RpcError, - types::{error::CallError, EmptyParams}, + types::{error::CallError, EmptyServerParams as EmptyParams}, RpcModule, }; use sc_transaction_pool::{BasicPool, FullChainApi}; diff --git a/client/rpc/src/chain/tests.rs b/client/rpc/src/chain/tests.rs index 1e6dbd5aca148..224d021f9409e 100644 --- a/client/rpc/src/chain/tests.rs +++ b/client/rpc/src/chain/tests.rs @@ -19,7 +19,7 @@ use super::*; use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; -use jsonrpsee::types::EmptyParams; +use jsonrpsee::types::EmptyServerParams as EmptyParams; use sc_block_builder::BlockBuilderProvider; use sp_consensus::BlockOrigin; use sp_rpc::list::ListOrValue; diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index 7213e4360ae2b..fd802e5a80391 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -28,9 +28,8 @@ use std::sync::Arc; use crate::SubscriptionTaskExecutor; use jsonrpsee::{ - core::{Error as JsonRpseeError, RpcResult}, + core::{server::rpc_module::SubscriptionSink, Error as JsonRpseeError, RpcResult}, types::SubscriptionResult, - ws_server::SubscriptionSink, }; use sc_rpc_api::{state::ReadProof, DenyUnsafe}; diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 53dd8ebf50499..3ef59e5ca9a7c 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -23,7 +23,7 @@ use assert_matches::assert_matches; use futures::executor; use jsonrpsee::{ core::Error as RpcError, - types::{error::CallError as RpcCallError, EmptyParams, ErrorObject}, + types::{error::CallError as RpcCallError, EmptyServerParams as EmptyParams, ErrorObject}, }; use sc_block_builder::BlockBuilderProvider; use sc_rpc_api::DenyUnsafe; diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index 2f91648008ff7..00ab9c46861e2 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -21,7 +21,7 @@ use assert_matches::assert_matches; use futures::prelude::*; use jsonrpsee::{ core::Error as RpcError, - types::{error::CallError, EmptyParams}, + types::{error::CallError, EmptyServerParams as EmptyParams}, RpcModule, }; use sc_network::{self, config::Role, PeerId}; diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 87949ef12d888..4d1d267d45c97 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -22,7 +22,7 @@ test-helpers = [] runtime-benchmarks = ["sc-client-db/runtime-benchmarks"] [dependencies] -jsonrpsee = { version = "0.15.1", features = ["server"] } +jsonrpsee = { version = "0.16.2", features = ["server"] } thiserror = "1.0.30" futures = "0.3.21" rand = "0.7.3" diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 091b4bbe9fe5f..f0e3f72510c28 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -43,7 +43,6 @@ use log::{debug, error, warn}; use sc_client_api::{blockchain::HeaderBackend, BlockBackend, BlockchainEvents, ProofProvider}; use sc_network::PeerId; use sc_network_common::{config::MultiaddrWithPeerId, service::NetworkBlock}; -use sc_rpc_server::WsConfig; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; use sp_consensus::SyncOracle; @@ -294,20 +293,9 @@ async fn build_network_future< // Wrapper for HTTP and WS servers that makes sure they are properly shut down. mod waiting { - pub struct HttpServer(pub Option); + pub struct Server(pub Option); - impl Drop for HttpServer { - fn drop(&mut self) { - if let Some(server) = self.0.take() { - // This doesn't not wait for the server to be stopped but fires the signal. - let _ = server.stop(); - } - } - } - - pub struct WsServer(pub Option); - - impl Drop for WsServer { + impl Drop for Server { fn drop(&mut self) { if let Some(server) = self.0.take() { // This doesn't not wait for the server to be stopped but fires the signal. @@ -326,9 +314,6 @@ fn start_rpc_servers( where R: Fn(sc_rpc::DenyUnsafe) -> Result, Error>, { - let (max_request_size, ws_max_response_size, http_max_response_size) = - legacy_cli_parsing(config); - fn deny_unsafe(addr: SocketAddr, methods: &RpcMethods) -> sc_rpc::DenyUnsafe { let is_exposed_addr = !addr.ip().is_loopback(); match (is_exposed_addr, methods) { @@ -337,6 +322,9 @@ where } } + let (max_request_size, ws_max_response_size, http_max_response_size) = + legacy_cli_parsing(config); + let random_port = |mut addr: SocketAddr| { addr.set_port(0); addr @@ -346,6 +334,7 @@ where .rpc_ws .unwrap_or_else(|| "127.0.0.1:9944".parse().expect("valid sockaddr; qed")); let ws_addr2 = random_port(ws_addr); + let http_addr = config .rpc_http .unwrap_or_else(|| "127.0.0.1:9933".parse().expect("valid sockaddr; qed")); @@ -353,29 +342,29 @@ where let metrics = sc_rpc_server::RpcMetrics::new(config.prometheus_registry())?; + let server_config = sc_rpc_server::WsConfig { + max_connections: config.rpc_ws_max_connections, + max_payload_in_mb: max_request_size, + max_payload_out_mb: ws_max_response_size, + max_subs_per_conn: config.rpc_max_subs_per_conn, + }; + let http_fut = sc_rpc_server::start_http( [http_addr, http_addr2], config.rpc_cors.as_ref(), max_request_size, http_max_response_size, metrics.clone(), - gen_rpc_module(deny_unsafe(ws_addr, &config.rpc_methods))?, + gen_rpc_module(deny_unsafe(http_addr, &config.rpc_methods))?, config.tokio_handle.clone(), ); - let ws_config = WsConfig { - max_connections: config.rpc_ws_max_connections, - max_payload_in_mb: max_request_size, - max_payload_out_mb: ws_max_response_size, - max_subs_per_conn: config.rpc_max_subs_per_conn, - }; - - let ws_fut = sc_rpc_server::start_ws( + let ws_fut = sc_rpc_server::start( [ws_addr, ws_addr2], config.rpc_cors.as_ref(), - ws_config, - metrics, - gen_rpc_module(deny_unsafe(http_addr, &config.rpc_methods))?, + server_config.clone(), + metrics.clone(), + gen_rpc_module(deny_unsafe(ws_addr, &config.rpc_methods))?, config.tokio_handle.clone(), rpc_id_provider, ); @@ -383,8 +372,7 @@ where match tokio::task::block_in_place(|| { config.tokio_handle.block_on(futures::future::try_join(http_fut, ws_fut)) }) { - Ok((http, ws)) => - Ok(Box::new((waiting::HttpServer(Some(http)), waiting::WsServer(Some(ws))))), + Ok((http, ws)) => Ok(Box::new((waiting::Server(Some(http)), waiting::Server(Some(ws))))), Err(e) => Err(Error::Application(e)), } } diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 9730eb56e9bd6..a72b4106ba873 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" thiserror = "1.0.30" diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index 06dcaca937381..b77143201ffd4 100644 --- a/frame/transaction-payment/rpc/Cargo.toml +++ b/frame/transaction-payment/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 86cfc767bf3b5..4f95331c03bc8 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -39,7 +39,9 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; -use substrate_rpc_client::{rpc_params, ws_client, ChainApi, ClientT, StateApi, WsClient}; +use substrate_rpc_client::{ + rpc_params, ws_client, BatchRequestBuilder, ChainApi, ClientT, StateApi, WsClient, +}; type KeyValue = (StorageKey, StorageData); type TopKeyValues = Vec; @@ -334,33 +336,50 @@ where log::debug!(target: LOG_TARGET, "Querying a total of {} keys", keys.len()); let mut key_values: Vec = vec![]; + let mut batch_success = true; + let client = self.as_online().rpc_client(); for chunk_keys in keys.chunks(BATCH_SIZE) { - let batch = chunk_keys - .iter() - .cloned() - .map(|key| ("state_getStorage", rpc_params![key, at])) - .collect::>(); - - let values = client.batch_request::>(batch).await.map_err(|e| { - log::error!( - target: LOG_TARGET, - "failed to execute batch: {:?}. Error: {:?}", - chunk_keys.iter().map(HexDisplay::from).collect::>(), - e - ); - "batch failed." - })?; + let mut batch = BatchRequestBuilder::new(); - assert_eq!(chunk_keys.len(), values.len()); + for key in chunk_keys.iter() { + batch + .insert("state_getStorage", rpc_params![key, at]) + .map_err(|_| "Invalid batch params")?; + } + + let batch_response = + client.batch_request::>(batch).await.map_err(|e| { + log::error!( + target: LOG_TARGET, + "failed to execute batch: {:?}. Error: {:?}", + chunk_keys.iter().map(HexDisplay::from).collect::>(), + e + ); + "batch failed." + })?; + + assert_eq!(chunk_keys.len(), batch_response.len()); + + for (key, maybe_value) in chunk_keys.into_iter().zip(batch_response) { + match maybe_value { + Ok(Some(v)) => { + key_values.push((key.clone(), v)); + }, + Ok(None) => { + log::warn!( + target: LOG_TARGET, + "key {:?} had none corresponding value.", + &key + ); + key_values.push((key.clone(), StorageData(vec![]))); + }, + Err(e) => { + log::error!(target: LOG_TARGET, "key {:?} failed: {:?}", &key, e); + batch_success = false; + }, + }; - for (idx, key) in chunk_keys.iter().enumerate() { - let maybe_value = values[idx].clone(); - let value = maybe_value.unwrap_or_else(|| { - log::warn!(target: LOG_TARGET, "key {:?} had none corresponding value.", &key); - StorageData(vec![]) - }); - key_values.push((key.clone(), value)); if key_values.len() % (10 * BATCH_SIZE) == 0 { let ratio: f64 = key_values.len() as f64 / keys_count as f64; log::debug!( @@ -374,7 +393,11 @@ where } } - Ok(key_values) + if batch_success { + Ok(key_values) + } else { + Err("batch failed.") + } } /// Get the values corresponding to `child_keys` at the given `prefixed_top_key`. @@ -385,12 +408,14 @@ where at: B::Hash, ) -> Result, &'static str> { let mut child_kv_inner = vec![]; + let mut batch_success = true; + for batch_child_key in child_keys.chunks(BATCH_SIZE) { - let batch_request = batch_child_key - .iter() - .cloned() - .map(|key| { - ( + let mut batch_request = BatchRequestBuilder::new(); + + for key in batch_child_key { + batch_request + .insert( "childstate_getStorage", rpc_params![ PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), @@ -398,8 +423,8 @@ where at ], ) - }) - .collect::>(); + .map_err(|_| "Invalid batch params")?; + } let batch_response = self .as_online() @@ -418,17 +443,32 @@ where assert_eq!(batch_child_key.len(), batch_response.len()); - for (idx, key) in batch_child_key.iter().enumerate() { - let maybe_value = batch_response[idx].clone(); - let value = maybe_value.unwrap_or_else(|| { - log::warn!(target: LOG_TARGET, "key {:?} had none corresponding value.", &key); - StorageData(vec![]) - }); - child_kv_inner.push((key.clone(), value)); + for (key, maybe_value) in batch_child_key.iter().zip(batch_response) { + match maybe_value { + Ok(Some(v)) => { + child_kv_inner.push((key.clone(), v)); + }, + Ok(None) => { + log::warn!( + target: LOG_TARGET, + "key {:?} had none corresponding value.", + &key + ); + child_kv_inner.push((key.clone(), StorageData(vec![]))); + }, + Err(e) => { + log::error!(target: LOG_TARGET, "key {:?} failed: {:?}", &key, e); + batch_success = false; + }, + }; } } - Ok(child_kv_inner) + if batch_success { + Ok(child_kv_inner) + } else { + Err("batch failed.") + } } pub(crate) async fn rpc_child_get_keys( diff --git a/utils/frame/rpc/client/Cargo.toml b/utils/frame/rpc/client/Cargo.toml index bbe8879818092..ee9982971cee3 100644 --- a/utils/frame/rpc/client/Cargo.toml +++ b/utils/frame/rpc/client/Cargo.toml @@ -12,7 +12,7 @@ description = "Shared JSON-RPC client" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.15.1", features = ["ws-client"] } +jsonrpsee = { version = "0.16.2", features = ["ws-client"] } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } async-trait = "0.1.57" serde = "1" diff --git a/utils/frame/rpc/client/src/lib.rs b/utils/frame/rpc/client/src/lib.rs index 254cc193c0e67..a211fc6c6983e 100644 --- a/utils/frame/rpc/client/src/lib.rs +++ b/utils/frame/rpc/client/src/lib.rs @@ -43,7 +43,10 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::collections::VecDeque; pub use jsonrpsee::{ - core::client::{ClientT, Subscription, SubscriptionClientT}, + core::{ + client::{ClientT, Subscription, SubscriptionClientT}, + params::BatchRequestBuilder, + }, rpc_params, ws_client::{WsClient, WsClientBuilder}, }; diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 4886563a99440..3a1b4b8b6cbf8 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -25,7 +25,7 @@ sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } trie-db = "0.24.0" -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } # Substrate Dependencies sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 119acbd937c8a..d098877e7302c 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -jsonrpsee = { version = "0.15.1", features = ["jsonrpsee-types"] } +jsonrpsee = { version = "0.16.2", features = ["jsonrpsee-types"] } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } @@ -25,7 +25,7 @@ sp-storage = { version = "7.0.0", path = "../../../../primitives/storage" } [dev-dependencies] scale-info = "2.1.1" -jsonrpsee = { version = "0.15.1", features = ["ws-client", "jsonrpsee-types"] } +jsonrpsee = { version = "0.16.2", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.22.0" sp-core = { version = "7.0.0", path = "../../../../primitives/core" } sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 56b8a79f8c080..92cf6882a10f1 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde_json = "1" codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.15.1", features = ["server"] } +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } futures = "0.3.21" log = "0.4.17" frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" } From e5d5d88d0d0e79042393c8bc85e5e9ebe6a24000 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 12 Dec 2022 11:48:43 +0100 Subject: [PATCH 1465/1472] `pallet-message-queue`: Fix license (#12895) * Fix license Signed-off-by: Oliver Tale-Yazdi * Add mock doc Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/message-queue/src/benchmarking.rs | 31 +++++++++++---------- frame/message-queue/src/integration_test.rs | 31 +++++++++++---------- frame/message-queue/src/lib.rs | 31 +++++++++++---------- frame/message-queue/src/mock.rs | 27 ++++++++++-------- frame/message-queue/src/mock_helpers.rs | 31 +++++++++++---------- 5 files changed, 79 insertions(+), 72 deletions(-) diff --git a/frame/message-queue/src/benchmarking.rs b/frame/message-queue/src/benchmarking.rs index c0ff20431d00e..9cd6b75e4d0ae 100644 --- a/frame/message-queue/src/benchmarking.rs +++ b/frame/message-queue/src/benchmarking.rs @@ -1,18 +1,19 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Benchmarking for the message queue pallet. diff --git a/frame/message-queue/src/integration_test.rs b/frame/message-queue/src/integration_test.rs index a9b6ee9bd2214..f4b1b7a125449 100644 --- a/frame/message-queue/src/integration_test.rs +++ b/frame/message-queue/src/integration_test.rs @@ -1,18 +1,19 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Stress tests pallet-message-queue. Defines its own runtime config to use larger constants for //! `HeapSize` and `MaxStale`. diff --git a/frame/message-queue/src/lib.rs b/frame/message-queue/src/lib.rs index 9b976c48245c9..6945ff1b1e549 100644 --- a/frame/message-queue/src/lib.rs +++ b/frame/message-queue/src/lib.rs @@ -1,18 +1,19 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! # Generalized Message Queue Pallet //! diff --git a/frame/message-queue/src/mock.rs b/frame/message-queue/src/mock.rs index bb9942443e226..7159840d1c01b 100644 --- a/frame/message-queue/src/mock.rs +++ b/frame/message-queue/src/mock.rs @@ -1,18 +1,21 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Substrate. -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . +//! Test helpers and runtime setup for the message queue pallet. #![cfg(test)] diff --git a/frame/message-queue/src/mock_helpers.rs b/frame/message-queue/src/mock_helpers.rs index 39d961d8fc558..f12cf4cc41073 100644 --- a/frame/message-queue/src/mock_helpers.rs +++ b/frame/message-queue/src/mock_helpers.rs @@ -1,18 +1,19 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Std setup helpers for testing and benchmarking. //! From b3d9f3c57e7f799d49442e3456614431f2d0e51a Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 12 Dec 2022 15:32:41 +0100 Subject: [PATCH 1466/1472] Use explicit call indices (#12891) * frame-system: explicit call index Signed-off-by: Oliver Tale-Yazdi * Use explicit call indices Signed-off-by: Oliver Tale-Yazdi * pallet-template: explicit call index Signed-off-by: Oliver Tale-Yazdi * DNM: Temporarily require call_index Signed-off-by: Oliver Tale-Yazdi * Revert "DNM: Temporarily require call_index" This reverts commit c4934e312e12af72ca05a8029d7da753a9c99346. Signed-off-by: Oliver Tale-Yazdi --- bin/node-template/pallets/template/src/lib.rs | 2 ++ frame/alliance/src/lib.rs | 18 ++++++++++++ frame/assets/src/lib.rs | 28 +++++++++++++++++++ frame/atomic-swap/src/lib.rs | 3 ++ frame/authorship/src/lib.rs | 1 + frame/babe/src/lib.rs | 3 ++ frame/bags-list/src/lib.rs | 2 ++ frame/balances/src/lib.rs | 6 ++++ frame/benchmarking/src/tests.rs | 3 ++ frame/benchmarking/src/tests_instance.rs | 2 ++ frame/bounties/src/lib.rs | 9 ++++++ frame/child-bounties/src/lib.rs | 7 +++++ frame/collective/src/lib.rs | 7 +++++ frame/collective/src/tests.rs | 1 + frame/contracts/src/lib.rs | 9 ++++++ frame/conviction-voting/src/lib.rs | 6 ++++ frame/democracy/src/lib.rs | 18 ++++++++++++ .../election-provider-multi-phase/src/lib.rs | 5 ++++ frame/elections-phragmen/src/lib.rs | 6 ++++ frame/examples/basic/src/lib.rs | 2 ++ frame/examples/offchain-worker/src/lib.rs | 3 ++ frame/executive/src/lib.rs | 7 +++++ frame/fast-unstake/src/lib.rs | 3 ++ frame/grandpa/src/lib.rs | 3 ++ frame/identity/src/lib.rs | 15 ++++++++++ frame/im-online/src/lib.rs | 1 + frame/indices/src/lib.rs | 5 ++++ frame/lottery/src/lib.rs | 4 +++ frame/membership/src/lib.rs | 7 +++++ frame/message-queue/src/lib.rs | 2 ++ frame/multisig/src/lib.rs | 4 +++ frame/nicks/src/lib.rs | 4 +++ frame/nis/src/lib.rs | 4 +++ frame/node-authorization/src/lib.rs | 9 ++++++ frame/nomination-pools/src/lib.rs | 14 ++++++++++ frame/preimage/src/lib.rs | 4 +++ frame/proxy/src/lib.rs | 10 +++++++ frame/ranked-collective/src/lib.rs | 6 ++++ frame/recovery/src/lib.rs | 9 ++++++ frame/referenda/src/lib.rs | 8 ++++++ frame/remark/src/lib.rs | 1 + frame/root-offences/src/lib.rs | 1 + frame/root-testing/src/lib.rs | 1 + frame/scheduler/src/lib.rs | 6 ++++ frame/scheduler/src/mock.rs | 2 ++ frame/scored-pool/src/lib.rs | 5 ++++ frame/session/src/lib.rs | 2 ++ frame/society/src/lib.rs | 12 ++++++++ frame/staking/src/pallet/mod.rs | 25 +++++++++++++++++ frame/state-trie-migration/src/lib.rs | 6 ++++ frame/sudo/src/lib.rs | 4 +++ frame/sudo/src/mock.rs | 2 ++ frame/support/test/tests/pallet.rs | 3 ++ .../test/tests/pallet_compatibility.rs | 1 + .../tests/pallet_compatibility_instance.rs | 1 + frame/support/test/tests/pallet_instance.rs | 2 ++ frame/support/test/tests/storage_layers.rs | 1 + frame/system/src/lib.rs | 8 ++++++ frame/timestamp/src/lib.rs | 1 + frame/tips/src/lib.rs | 6 ++++ frame/transaction-storage/src/lib.rs | 3 ++ frame/treasury/src/lib.rs | 5 ++++ frame/uniques/src/lib.rs | 26 +++++++++++++++++ frame/utility/src/lib.rs | 6 ++++ frame/utility/src/tests.rs | 4 +++ frame/vesting/src/lib.rs | 5 ++++ frame/whitelist/src/lib.rs | 4 +++ 67 files changed, 403 insertions(+) diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index 28d36ac2c6321..4630e344add31 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -64,6 +64,7 @@ pub mod pallet { impl Pallet { /// An example dispatchable that takes a singles value as a parameter, writes the value to /// storage and emits an event. This function must be dispatched by a signed extrinsic. + #[pallet::call_index(0)] #[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { // Check that the extrinsic was signed and get the signer. @@ -81,6 +82,7 @@ pub mod pallet { } /// An example dispatchable that may throw a custom error. + #[pallet::call_index(1)] #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] pub fn cause_error(origin: OriginFor) -> DispatchResult { let _who = ensure_signed(origin)?; diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 7e03da9ac1c7b..790c3c384e701 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -503,6 +503,7 @@ pub mod pallet { /// Add a new proposal to be voted on. /// /// Must be called by a Fellow. + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::propose_proposed( *length_bound, // B T::MaxFellows::get(), // M @@ -524,6 +525,7 @@ pub mod pallet { /// Add an aye or nay vote for the sender to the given proposal. /// /// Must be called by a Fellow. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::vote(T::MaxFellows::get()))] pub fn vote( origin: OriginFor, @@ -541,6 +543,7 @@ pub mod pallet { /// Close a vote that is either approved, disapproved, or whose voting period has ended. /// /// Must be called by a Fellow. + #[pallet::call_index(2)] #[pallet::weight({ let b = *length_bound; let m = T::MaxFellows::get(); @@ -573,6 +576,7 @@ pub mod pallet { /// The Alliance must be empty, and the call must provide some founding members. /// /// Must be called by the Root origin. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::init_members( fellows.len() as u32, allies.len() as u32, @@ -623,6 +627,7 @@ pub mod pallet { /// Disband the Alliance, remove all active members and unreserve deposits. /// /// Witness data must be set. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::disband( witness.fellow_members, witness.ally_members, @@ -673,6 +678,7 @@ pub mod pallet { } /// Set a new IPFS CID to the alliance rule. + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::set_rule())] pub fn set_rule(origin: OriginFor, rule: Cid) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; @@ -684,6 +690,7 @@ pub mod pallet { } /// Make an announcement of a new IPFS CID about alliance issues. + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::announce())] pub fn announce(origin: OriginFor, announcement: Cid) -> DispatchResult { T::AnnouncementOrigin::ensure_origin(origin)?; @@ -699,6 +706,7 @@ pub mod pallet { } /// Remove an announcement. + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::remove_announcement())] pub fn remove_announcement(origin: OriginFor, announcement: Cid) -> DispatchResult { T::AnnouncementOrigin::ensure_origin(origin)?; @@ -716,6 +724,7 @@ pub mod pallet { } /// Submit oneself for candidacy. A fixed deposit is reserved. + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::join_alliance())] pub fn join_alliance(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -752,6 +761,7 @@ pub mod pallet { /// A Fellow can nominate someone to join the alliance as an Ally. There is no deposit /// required from the nominator or nominee. + #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::nominate_ally())] pub fn nominate_ally(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { let nominator = ensure_signed(origin)?; @@ -776,6 +786,7 @@ pub mod pallet { } /// Elevate an Ally to Fellow. + #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::elevate_ally())] pub fn elevate_ally(origin: OriginFor, ally: AccountIdLookupOf) -> DispatchResult { T::MembershipManager::ensure_origin(origin)?; @@ -792,6 +803,7 @@ pub mod pallet { /// As a member, give a retirement notice and start a retirement period required to pass in /// order to retire. + #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::give_retirement_notice())] pub fn give_retirement_notice(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -814,6 +826,7 @@ pub mod pallet { /// /// This can only be done once you have called `give_retirement_notice` and the /// `RetirementPeriod` has passed. + #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::retire())] pub fn retire(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -836,6 +849,7 @@ pub mod pallet { } /// Kick a member from the Alliance and slash its deposit. + #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::kick_member())] pub fn kick_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::MembershipManager::ensure_origin(origin)?; @@ -853,6 +867,7 @@ pub mod pallet { } /// Add accounts or websites to the list of unscrupulous items. + #[pallet::call_index(14)] #[pallet::weight(T::WeightInfo::add_unscrupulous_items(items.len() as u32, T::MaxWebsiteUrlLength::get()))] pub fn add_unscrupulous_items( origin: OriginFor, @@ -882,6 +897,7 @@ pub mod pallet { } /// Deem some items no longer unscrupulous. + #[pallet::call_index(15)] #[pallet::weight(>::WeightInfo::remove_unscrupulous_items( items.len() as u32, T::MaxWebsiteUrlLength::get() ))] @@ -907,6 +923,7 @@ pub mod pallet { /// Close a vote that is either approved, disapproved, or whose voting period has ended. /// /// Must be called by a Fellow. + #[pallet::call_index(16)] #[pallet::weight({ let b = *length_bound; let m = T::MaxFellows::get(); @@ -934,6 +951,7 @@ pub mod pallet { /// Abdicate one's position as a voting member and just be an Ally. May be used by Fellows /// who do not want to leave the Alliance but do not have the capacity to participate /// operationally for some time. + #[pallet::call_index(17)] #[pallet::weight(T::WeightInfo::abdicate_fellow_status())] pub fn abdicate_fellow_status(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 2902477d0f2b5..629a0243cfc80 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -563,6 +563,7 @@ pub mod pallet { /// Emits `Created` event when successful. /// /// Weight: `O(1)` + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::create())] pub fn create( origin: OriginFor, @@ -620,6 +621,7 @@ pub mod pallet { /// Emits `ForceCreated` event when successful. /// /// Weight: `O(1)` + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::force_create())] pub fn force_create( origin: OriginFor, @@ -645,6 +647,7 @@ pub mod pallet { /// asset. /// /// The asset class must be frozen before calling `start_destroy`. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::start_destroy())] pub fn start_destroy(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let maybe_check_owner = match T::ForceOrigin::try_origin(origin) { @@ -667,6 +670,7 @@ pub mod pallet { /// asset. /// /// Each call emits the `Event::DestroyedAccounts` event. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::destroy_accounts(T::RemoveItemsLimit::get()))] pub fn destroy_accounts( origin: OriginFor, @@ -690,6 +694,7 @@ pub mod pallet { /// asset. /// /// Each call emits the `Event::DestroyedApprovals` event. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::destroy_approvals(T::RemoveItemsLimit::get()))] pub fn destroy_approvals( origin: OriginFor, @@ -711,6 +716,7 @@ pub mod pallet { /// asset. /// /// Each successful call emits the `Event::Destroyed` event. + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::finish_destroy())] pub fn finish_destroy(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let _ = ensure_signed(origin)?; @@ -730,6 +736,7 @@ pub mod pallet { /// /// Weight: `O(1)` /// Modes: Pre-existing balance of `beneficiary`; Account pre-existence of `beneficiary`. + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::mint())] pub fn mint( origin: OriginFor, @@ -759,6 +766,7 @@ pub mod pallet { /// /// Weight: `O(1)` /// Modes: Post-existence of `who`; Pre & post Zombie-status of `who`. + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::burn())] pub fn burn( origin: OriginFor, @@ -793,6 +801,7 @@ pub mod pallet { /// Weight: `O(1)` /// Modes: Pre-existence of `target`; Post-existence of sender; Account pre-existence of /// `target`. + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( origin: OriginFor, @@ -826,6 +835,7 @@ pub mod pallet { /// Weight: `O(1)` /// Modes: Pre-existence of `target`; Post-existence of sender; Account pre-existence of /// `target`. + #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::transfer_keep_alive())] pub fn transfer_keep_alive( origin: OriginFor, @@ -860,6 +870,7 @@ pub mod pallet { /// Weight: `O(1)` /// Modes: Pre-existence of `dest`; Post-existence of `source`; Account pre-existence of /// `dest`. + #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::force_transfer())] pub fn force_transfer( origin: OriginFor, @@ -887,6 +898,7 @@ pub mod pallet { /// Emits `Frozen`. /// /// Weight: `O(1)` + #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::freeze())] pub fn freeze( origin: OriginFor, @@ -923,6 +935,7 @@ pub mod pallet { /// Emits `Thawed`. /// /// Weight: `O(1)` + #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::thaw())] pub fn thaw( origin: OriginFor, @@ -958,6 +971,7 @@ pub mod pallet { /// Emits `Frozen`. /// /// Weight: `O(1)` + #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::freeze_asset())] pub fn freeze_asset(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -984,6 +998,7 @@ pub mod pallet { /// Emits `Thawed`. /// /// Weight: `O(1)` + #[pallet::call_index(14)] #[pallet::weight(T::WeightInfo::thaw_asset())] pub fn thaw_asset(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -1011,6 +1026,7 @@ pub mod pallet { /// Emits `OwnerChanged`. /// /// Weight: `O(1)` + #[pallet::call_index(15)] #[pallet::weight(T::WeightInfo::transfer_ownership())] pub fn transfer_ownership( origin: OriginFor, @@ -1054,6 +1070,7 @@ pub mod pallet { /// Emits `TeamChanged`. /// /// Weight: `O(1)` + #[pallet::call_index(16)] #[pallet::weight(T::WeightInfo::set_team())] pub fn set_team( origin: OriginFor, @@ -1098,6 +1115,7 @@ pub mod pallet { /// Emits `MetadataSet`. /// /// Weight: `O(1)` + #[pallet::call_index(17)] #[pallet::weight(T::WeightInfo::set_metadata(name.len() as u32, symbol.len() as u32))] pub fn set_metadata( origin: OriginFor, @@ -1122,6 +1140,7 @@ pub mod pallet { /// Emits `MetadataCleared`. /// /// Weight: `O(1)` + #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::clear_metadata())] pub fn clear_metadata(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let origin = ensure_signed(origin)?; @@ -1153,6 +1172,7 @@ pub mod pallet { /// Emits `MetadataSet`. /// /// Weight: `O(N + S)` where N and S are the length of the name and symbol respectively. + #[pallet::call_index(19)] #[pallet::weight(T::WeightInfo::force_set_metadata(name.len() as u32, symbol.len() as u32))] pub fn force_set_metadata( origin: OriginFor, @@ -1204,6 +1224,7 @@ pub mod pallet { /// Emits `MetadataCleared`. /// /// Weight: `O(1)` + #[pallet::call_index(20)] #[pallet::weight(T::WeightInfo::force_clear_metadata())] pub fn force_clear_metadata( origin: OriginFor, @@ -1243,6 +1264,7 @@ pub mod pallet { /// Emits `AssetStatusChanged` with the identity of the asset. /// /// Weight: `O(1)` + #[pallet::call_index(21)] #[pallet::weight(T::WeightInfo::force_asset_status())] pub fn force_asset_status( origin: OriginFor, @@ -1299,6 +1321,7 @@ pub mod pallet { /// Emits `ApprovedTransfer` on success. /// /// Weight: `O(1)` + #[pallet::call_index(22)] #[pallet::weight(T::WeightInfo::approve_transfer())] pub fn approve_transfer( origin: OriginFor, @@ -1325,6 +1348,7 @@ pub mod pallet { /// Emits `ApprovalCancelled` on success. /// /// Weight: `O(1)` + #[pallet::call_index(23)] #[pallet::weight(T::WeightInfo::cancel_approval())] pub fn cancel_approval( origin: OriginFor, @@ -1361,6 +1385,7 @@ pub mod pallet { /// Emits `ApprovalCancelled` on success. /// /// Weight: `O(1)` + #[pallet::call_index(24)] #[pallet::weight(T::WeightInfo::force_cancel_approval())] pub fn force_cancel_approval( origin: OriginFor, @@ -1410,6 +1435,7 @@ pub mod pallet { /// Emits `TransferredApproved` on success. /// /// Weight: `O(1)` + #[pallet::call_index(25)] #[pallet::weight(T::WeightInfo::transfer_approved())] pub fn transfer_approved( origin: OriginFor, @@ -1434,6 +1460,7 @@ pub mod pallet { /// - `id`: The identifier of the asset for the account to be created. /// /// Emits `Touched` event when successful. + #[pallet::call_index(26)] #[pallet::weight(T::WeightInfo::mint())] pub fn touch(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { let id: T::AssetId = id.into(); @@ -1448,6 +1475,7 @@ pub mod pallet { /// - `allow_burn`: If `true` then assets may be destroyed in order to complete the refund. /// /// Emits `Refunded` event when successful. + #[pallet::call_index(27)] #[pallet::weight(T::WeightInfo::mint())] pub fn refund( origin: OriginFor, diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 9c6056497118c..66628e8e6f242 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -243,6 +243,7 @@ pub mod pallet { /// - `duration`: Locked duration of the atomic swap. For safety reasons, it is recommended /// that the revealer uses a shorter duration than the counterparty, to prevent the /// situation where the revealer reveals the proof too late around the end block. + #[pallet::call_index(0)] #[pallet::weight(T::DbWeight::get().reads_writes(1, 1).ref_time().saturating_add(40_000_000))] pub fn create_swap( origin: OriginFor, @@ -278,6 +279,7 @@ pub mod pallet { /// - `proof`: Revealed proof of the claim. /// - `action`: Action defined in the swap, it must match the entry in blockchain. Otherwise /// the operation fails. This is used for weight calculation. + #[pallet::call_index(1)] #[pallet::weight( T::DbWeight::get().reads_writes(1, 1) .saturating_add(action.weight()) @@ -318,6 +320,7 @@ pub mod pallet { /// /// - `target`: Target of the original atomic swap. /// - `hashed_proof`: Hashed proof of the original atomic swap. + #[pallet::call_index(2)] #[pallet::weight(T::DbWeight::get().reads_writes(1, 1).ref_time().saturating_add(40_000_000))] pub fn cancel_swap( origin: OriginFor, diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index c08e773abe3a7..a40f32d36c265 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -237,6 +237,7 @@ pub mod pallet { #[pallet::call] impl Pallet { /// Provide a set of uncles. + #[pallet::call_index(0)] #[pallet::weight((0, DispatchClass::Mandatory))] pub fn set_uncles(origin: OriginFor, new_uncles: Vec) -> DispatchResult { ensure_none(origin)?; diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index eadaa036332fa..1a9b3200087ae 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -403,6 +403,7 @@ pub mod pallet { /// the equivocation proof and validate the given key ownership proof /// against the extracted offender. If both are valid, the offence will /// be reported. + #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::report_equivocation( key_owner_proof.validator_count(), ))] @@ -424,6 +425,7 @@ pub mod pallet { /// block authors will call it (validated in `ValidateUnsigned`), as such /// if the block author is defined it will be defined as the equivocation /// reporter. + #[pallet::call_index(1)] #[pallet::weight(::WeightInfo::report_equivocation( key_owner_proof.validator_count(), ))] @@ -445,6 +447,7 @@ pub mod pallet { /// the next call to `enact_epoch_change`. The config will be activated one epoch after. /// Multiple calls to this method will replace any existing planned config change that had /// not been enacted yet. + #[pallet::call_index(2)] #[pallet::weight(::WeightInfo::plan_config_change())] pub fn plan_config_change( origin: OriginFor, diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 2b48fbf0ca630..1ffdf29345513 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -224,6 +224,7 @@ pub mod pallet { /// `ScoreProvider`. /// /// If `dislocated` does not exists, it returns an error. + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::rebag_non_terminal().max(T::WeightInfo::rebag_terminal()))] pub fn rebag(origin: OriginFor, dislocated: AccountIdLookupOf) -> DispatchResult { ensure_signed(origin)?; @@ -242,6 +243,7 @@ pub mod pallet { /// Only works if /// - both nodes are within the same bag, /// - and `origin` has a greater `Score` than `lighter`. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::put_in_front_of())] pub fn put_in_front_of( origin: OriginFor, diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 381a0ffceeb85..57f76b1ff679d 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -282,6 +282,7 @@ pub mod pallet { /// --------------------------------- /// - Origin account is already in memory, so no DB operations for them. /// # + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( origin: OriginFor, @@ -307,6 +308,7 @@ pub mod pallet { /// it will reset the account nonce (`frame_system::AccountNonce`). /// /// The dispatch origin for this call is `root`. + #[pallet::call_index(1)] #[pallet::weight( T::WeightInfo::set_balance_creating() // Creates a new account. .max(T::WeightInfo::set_balance_killing()) // Kills an existing account. @@ -360,6 +362,7 @@ pub mod pallet { /// - Same as transfer, but additional read and write because the source account is not /// assumed to be in the overlay. /// # + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::force_transfer())] pub fn force_transfer( origin: OriginFor, @@ -385,6 +388,7 @@ pub mod pallet { /// 99% of the time you want [`transfer`] instead. /// /// [`transfer`]: struct.Pallet.html#method.transfer + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::transfer_keep_alive())] pub fn transfer_keep_alive( origin: OriginFor, @@ -414,6 +418,7 @@ pub mod pallet { /// keep the sender account alive (true). # /// - O(1). Just like transfer, but reading the user's transferable balance first. /// # + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::transfer_all())] pub fn transfer_all( origin: OriginFor, @@ -432,6 +437,7 @@ pub mod pallet { /// Unreserve some balance from a user by force. /// /// Can only be called by ROOT. + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::force_unreserve())] pub fn force_unreserve( origin: OriginFor, diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index 88a7d6d0286b2..1499f9c182fce 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -51,6 +51,7 @@ mod pallet_test { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(0)] pub fn set_value(origin: OriginFor, n: u32) -> DispatchResult { let _sender = ensure_signed(origin)?; @@ -58,12 +59,14 @@ mod pallet_test { Ok(()) } + #[pallet::call_index(1)] #[pallet::weight(0)] pub fn dummy(origin: OriginFor, _n: u32) -> DispatchResult { let _sender = ensure_none(origin)?; Ok(()) } + #[pallet::call_index(2)] #[pallet::weight(0)] pub fn always_error(_origin: OriginFor) -> DispatchResult { return Err("I always fail".into()) diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index 7e1cd48840687..ecc0a78a199b9 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -61,6 +61,7 @@ mod pallet_test { where ::OtherEvent: Into<>::RuntimeEvent>, { + #[pallet::call_index(0)] #[pallet::weight(0)] pub fn set_value(origin: OriginFor, n: u32) -> DispatchResult { let _sender = ensure_signed(origin)?; @@ -68,6 +69,7 @@ mod pallet_test { Ok(()) } + #[pallet::call_index(1)] #[pallet::weight(0)] pub fn dummy(origin: OriginFor, _n: u32) -> DispatchResult { let _sender = ensure_none(origin)?; diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 2e350dd1e2484..eb92c774f86e3 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -333,6 +333,7 @@ pub mod pallet { /// - `fee`: The curator fee. /// - `value`: The total payment amount of this bounty, curator fee included. /// - `description`: The description of this bounty. + #[pallet::call_index(0)] #[pallet::weight(>::WeightInfo::propose_bounty(description.len() as u32))] pub fn propose_bounty( origin: OriginFor, @@ -352,6 +353,7 @@ pub mod pallet { /// # /// - O(1). /// # + #[pallet::call_index(1)] #[pallet::weight(>::WeightInfo::approve_bounty())] pub fn approve_bounty( origin: OriginFor, @@ -383,6 +385,7 @@ pub mod pallet { /// # /// - O(1). /// # + #[pallet::call_index(2)] #[pallet::weight(>::WeightInfo::propose_curator())] pub fn propose_curator( origin: OriginFor, @@ -432,6 +435,7 @@ pub mod pallet { /// # /// - O(1). /// # + #[pallet::call_index(3)] #[pallet::weight(>::WeightInfo::unassign_curator())] pub fn unassign_curator( origin: OriginFor, @@ -517,6 +521,7 @@ pub mod pallet { /// # /// - O(1). /// # + #[pallet::call_index(4)] #[pallet::weight(>::WeightInfo::accept_curator())] pub fn accept_curator( origin: OriginFor, @@ -559,6 +564,7 @@ pub mod pallet { /// # /// - O(1). /// # + #[pallet::call_index(5)] #[pallet::weight(>::WeightInfo::award_bounty())] pub fn award_bounty( origin: OriginFor, @@ -606,6 +612,7 @@ pub mod pallet { /// # /// - O(1). /// # + #[pallet::call_index(6)] #[pallet::weight(>::WeightInfo::claim_bounty())] pub fn claim_bounty( origin: OriginFor, @@ -669,6 +676,7 @@ pub mod pallet { /// # /// - O(1). /// # + #[pallet::call_index(7)] #[pallet::weight(>::WeightInfo::close_bounty_proposed() .max(>::WeightInfo::close_bounty_active()))] pub fn close_bounty( @@ -760,6 +768,7 @@ pub mod pallet { /// # /// - O(1). /// # + #[pallet::call_index(8)] #[pallet::weight(>::WeightInfo::extend_bounty_expiry())] pub fn extend_bounty_expiry( origin: OriginFor, diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 2dfe0660ad68e..9eb784eaccd23 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -237,6 +237,7 @@ pub mod pallet { /// - `parent_bounty_id`: Index of parent bounty for which child-bounty is being added. /// - `value`: Value for executing the proposal. /// - `description`: Text description for the child-bounty. + #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::add_child_bounty(description.len() as u32))] pub fn add_child_bounty( origin: OriginFor, @@ -311,6 +312,7 @@ pub mod pallet { /// - `child_bounty_id`: Index of child bounty. /// - `curator`: Address of child-bounty curator. /// - `fee`: payment fee to child-bounty curator for execution. + #[pallet::call_index(1)] #[pallet::weight(::WeightInfo::propose_curator())] pub fn propose_curator( origin: OriginFor, @@ -380,6 +382,7 @@ pub mod pallet { /// /// - `parent_bounty_id`: Index of parent bounty. /// - `child_bounty_id`: Index of child bounty. + #[pallet::call_index(2)] #[pallet::weight(::WeightInfo::accept_curator())] pub fn accept_curator( origin: OriginFor, @@ -456,6 +459,7 @@ pub mod pallet { /// /// - `parent_bounty_id`: Index of parent bounty. /// - `child_bounty_id`: Index of child bounty. + #[pallet::call_index(3)] #[pallet::weight(::WeightInfo::unassign_curator())] pub fn unassign_curator( origin: OriginFor, @@ -570,6 +574,7 @@ pub mod pallet { /// - `parent_bounty_id`: Index of parent bounty. /// - `child_bounty_id`: Index of child bounty. /// - `beneficiary`: Beneficiary account. + #[pallet::call_index(4)] #[pallet::weight(::WeightInfo::award_child_bounty())] pub fn award_child_bounty( origin: OriginFor, @@ -636,6 +641,7 @@ pub mod pallet { /// /// - `parent_bounty_id`: Index of parent bounty. /// - `child_bounty_id`: Index of child bounty. + #[pallet::call_index(5)] #[pallet::weight(::WeightInfo::claim_child_bounty())] pub fn claim_child_bounty( origin: OriginFor, @@ -745,6 +751,7 @@ pub mod pallet { /// /// - `parent_bounty_id`: Index of parent bounty. /// - `child_bounty_id`: Index of child bounty. + #[pallet::call_index(6)] #[pallet::weight(::WeightInfo::close_child_bounty_added() .max(::WeightInfo::close_child_bounty_active()))] pub fn close_child_bounty( diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 06d5b1fab78e7..c522b71891b3c 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -372,6 +372,7 @@ pub mod pallet { /// - `P` storage mutations (codec `O(M)`) for updating the votes for each proposal /// - 1 storage write (codec `O(1)`) for deleting the old `prime` and setting the new one /// # + #[pallet::call_index(0)] #[pallet::weight(( T::WeightInfo::set_members( *old_count, // M @@ -429,6 +430,7 @@ pub mod pallet { /// - DB: 1 read (codec `O(M)`) + DB access of `proposal` /// - 1 event /// # + #[pallet::call_index(1)] #[pallet::weight(( T::WeightInfo::execute( *length_bound, // B @@ -492,6 +494,7 @@ pub mod pallet { /// - 1 storage write `Voting` (codec `O(M)`) /// - 1 event /// # + #[pallet::call_index(2)] #[pallet::weight(( if *threshold < 2 { T::WeightInfo::propose_execute( @@ -557,6 +560,7 @@ pub mod pallet { /// - 1 storage mutation `Voting` (codec `O(M)`) /// - 1 event /// # + #[pallet::call_index(3)] #[pallet::weight((T::WeightInfo::vote(T::MaxMembers::get()), DispatchClass::Operational))] pub fn vote( origin: OriginFor, @@ -610,6 +614,7 @@ pub mod pallet { /// - any mutations done while executing `proposal` (`P1`) /// - up to 3 events /// # + #[pallet::call_index(4)] #[pallet::weight(( { let b = *length_bound; @@ -653,6 +658,7 @@ pub mod pallet { /// * Reads: Proposals /// * Writes: Voting, Proposals, ProposalOf /// # + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::disapprove_proposal(T::MaxProposals::get()))] pub fn disapprove_proposal( origin: OriginFor, @@ -695,6 +701,7 @@ pub mod pallet { /// - any mutations done while executing `proposal` (`P1`) /// - up to 3 events /// # + #[pallet::call_index(6)] #[pallet::weight(( { let b = *length_bound; diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 3d1540a8c3b5c..648b6f88ec86c 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -69,6 +69,7 @@ mod mock_democracy { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(0)] pub fn external_propose_majority(origin: OriginFor) -> DispatchResult { T::ExternalMajorityOrigin::ensure_origin(origin)?; diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 4bbb311313d61..06d817785cc39 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -385,6 +385,7 @@ pub mod pallet { as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode, { /// Deprecated version if [`Self::call`] for use in an in-storage `Call`. + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::call().saturating_add(>::compat_weight(*gas_limit)))] #[allow(deprecated)] #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `call`")] @@ -407,6 +408,7 @@ pub mod pallet { } /// Deprecated version if [`Self::instantiate_with_code`] for use in an in-storage `Call`. + #[pallet::call_index(1)] #[pallet::weight( T::WeightInfo::instantiate_with_code(code.len() as u32, salt.len() as u32) .saturating_add(>::compat_weight(*gas_limit)) @@ -436,6 +438,7 @@ pub mod pallet { } /// Deprecated version if [`Self::instantiate`] for use in an in-storage `Call`. + #[pallet::call_index(2)] #[pallet::weight( T::WeightInfo::instantiate(salt.len() as u32).saturating_add(>::compat_weight(*gas_limit)) )] @@ -481,6 +484,7 @@ pub mod pallet { /// To avoid this situation a constructor could employ access control so that it can /// only be instantiated by permissioned entities. The same is true when uploading /// through [`Self::instantiate_with_code`]. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::upload_code(code.len() as u32))] pub fn upload_code( origin: OriginFor, @@ -497,6 +501,7 @@ pub mod pallet { /// /// A code can only be removed by its original uploader (its owner) and only if it is /// not used by any contract. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::remove_code())] pub fn remove_code( origin: OriginFor, @@ -518,6 +523,7 @@ pub mod pallet { /// This does **not** change the address of the contract in question. This means /// that the contract address is no longer derived from its code hash after calling /// this dispatchable. + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::set_code())] pub fn set_code( origin: OriginFor, @@ -563,6 +569,7 @@ pub mod pallet { /// * If the account is a regular account, any value will be transferred. /// * If no account exists and the call value is not less than `existential_deposit`, /// a regular account will be created and any value will be transferred. + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::call().saturating_add(*gas_limit))] pub fn call( origin: OriginFor, @@ -619,6 +626,7 @@ pub mod pallet { /// - The smart-contract account is created at the computed address. /// - The `value` is transferred to the new account. /// - The `deploy` function is executed in the context of the newly-created account. + #[pallet::call_index(7)] #[pallet::weight( T::WeightInfo::instantiate_with_code(code.len() as u32, salt.len() as u32) .saturating_add(*gas_limit) @@ -661,6 +669,7 @@ pub mod pallet { /// This function is identical to [`Self::instantiate_with_code`] but without the /// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary /// must be supplied. + #[pallet::call_index(8)] #[pallet::weight( T::WeightInfo::instantiate(salt.len() as u32).saturating_add(*gas_limit) )] diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index 3ecc6e56be94e..141e9690fa29d 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -208,6 +208,7 @@ pub mod pallet { /// - `vote`: The vote configuration. /// /// Weight: `O(R)` where R is the number of polls the voter has voted on. + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::vote_new().max(T::WeightInfo::vote_existing()))] pub fn vote( origin: OriginFor, @@ -243,6 +244,7 @@ pub mod pallet { /// voted on. Weight is initially charged as if maximum votes, but is refunded later. // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure // because a valid delegation cover decoding a direct voting with max votes. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::delegate(T::MaxVotes::get()))] pub fn delegate( origin: OriginFor, @@ -274,6 +276,7 @@ pub mod pallet { /// voted on. Weight is initially charged as if maximum votes, but is refunded later. // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure // because a valid delegation cover decoding a direct voting with max votes. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::undelegate(T::MaxVotes::get().into()))] pub fn undelegate( origin: OriginFor, @@ -293,6 +296,7 @@ pub mod pallet { /// - `target`: The account to remove the lock on. /// /// Weight: `O(R)` with R number of vote of target. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::unlock())] pub fn unlock( origin: OriginFor, @@ -334,6 +338,7 @@ pub mod pallet { /// /// Weight: `O(R + log R)` where R is the number of polls that `target` has voted on. /// Weight is calculated for the maximum number of vote. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::remove_vote())] pub fn remove_vote( origin: OriginFor, @@ -360,6 +365,7 @@ pub mod pallet { /// /// Weight: `O(R + log R)` where R is the number of polls that `target` has voted on. /// Weight is calculated for the maximum number of vote. + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::remove_other_vote())] pub fn remove_other_vote( origin: OriginFor, diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index cf954d4800eee..2c65e5d94bc46 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -549,6 +549,7 @@ pub mod pallet { /// - `value`: The amount of deposit (must be at least `MinimumDeposit`). /// /// Emits `Proposed`. + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::propose())] pub fn propose( origin: OriginFor, @@ -591,6 +592,7 @@ pub mod pallet { /// must have funds to cover the deposit, equal to the original deposit. /// /// - `proposal`: The index of the proposal to second. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::second())] pub fn second( origin: OriginFor, @@ -616,6 +618,7 @@ pub mod pallet { /// /// - `ref_index`: The index of the referendum to vote for. /// - `vote`: The vote configuration. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::vote_new().max(T::WeightInfo::vote_existing()))] pub fn vote( origin: OriginFor, @@ -634,6 +637,7 @@ pub mod pallet { /// -`ref_index`: The index of the referendum to cancel. /// /// Weight: `O(1)`. + #[pallet::call_index(3)] #[pallet::weight((T::WeightInfo::emergency_cancel(), DispatchClass::Operational))] pub fn emergency_cancel( origin: OriginFor, @@ -656,6 +660,7 @@ pub mod pallet { /// The dispatch origin of this call must be `ExternalOrigin`. /// /// - `proposal_hash`: The preimage hash of the proposal. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::external_propose())] pub fn external_propose( origin: OriginFor, @@ -684,6 +689,7 @@ pub mod pallet { /// pre-scheduled `external_propose` call. /// /// Weight: `O(1)` + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::external_propose_majority())] pub fn external_propose_majority( origin: OriginFor, @@ -705,6 +711,7 @@ pub mod pallet { /// pre-scheduled `external_propose` call. /// /// Weight: `O(1)` + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::external_propose_default())] pub fn external_propose_default( origin: OriginFor, @@ -731,6 +738,7 @@ pub mod pallet { /// Emits `Started`. /// /// Weight: `O(1)` + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::fast_track())] pub fn fast_track( origin: OriginFor, @@ -783,6 +791,7 @@ pub mod pallet { /// Emits `Vetoed`. /// /// Weight: `O(V + log(V))` where V is number of `existing vetoers` + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::veto_external())] pub fn veto_external(origin: OriginFor, proposal_hash: H256) -> DispatchResult { let who = T::VetoOrigin::ensure_origin(origin)?; @@ -817,6 +826,7 @@ pub mod pallet { /// - `ref_index`: The index of the referendum to cancel. /// /// # Weight: `O(1)`. + #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::cancel_referendum())] pub fn cancel_referendum( origin: OriginFor, @@ -849,6 +859,7 @@ pub mod pallet { /// voted on. Weight is charged as if maximum votes. // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure // because a valid delegation cover decoding a direct voting with max votes. + #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::delegate(T::MaxVotes::get()))] pub fn delegate( origin: OriginFor, @@ -877,6 +888,7 @@ pub mod pallet { /// voted on. Weight is charged as if maximum votes. // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure // because a valid delegation cover decoding a direct voting with max votes. + #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::undelegate(T::MaxVotes::get()))] pub fn undelegate(origin: OriginFor) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -889,6 +901,7 @@ pub mod pallet { /// The dispatch origin of this call must be _Root_. /// /// Weight: `O(1)`. + #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::clear_public_proposals())] pub fn clear_public_proposals(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; @@ -903,6 +916,7 @@ pub mod pallet { /// - `target`: The account to remove the lock on. /// /// Weight: `O(R)` with R number of vote of target. + #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::unlock_set(T::MaxVotes::get()).max(T::WeightInfo::unlock_remove(T::MaxVotes::get())))] pub fn unlock(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { ensure_signed(origin)?; @@ -938,6 +952,7 @@ pub mod pallet { /// /// Weight: `O(R + log R)` where R is the number of referenda that `target` has voted on. /// Weight is calculated for the maximum number of vote. + #[pallet::call_index(14)] #[pallet::weight(T::WeightInfo::remove_vote(T::MaxVotes::get()))] pub fn remove_vote(origin: OriginFor, index: ReferendumIndex) -> DispatchResult { let who = ensure_signed(origin)?; @@ -959,6 +974,7 @@ pub mod pallet { /// /// Weight: `O(R + log R)` where R is the number of referenda that `target` has voted on. /// Weight is calculated for the maximum number of vote. + #[pallet::call_index(15)] #[pallet::weight(T::WeightInfo::remove_other_vote(T::MaxVotes::get()))] pub fn remove_other_vote( origin: OriginFor, @@ -987,6 +1003,7 @@ pub mod pallet { /// /// Weight: `O(p)` (though as this is an high-privilege dispatch, we assume it has a /// reasonable value). + #[pallet::call_index(16)] #[pallet::weight((T::WeightInfo::blacklist(), DispatchClass::Operational))] pub fn blacklist( origin: OriginFor, @@ -1036,6 +1053,7 @@ pub mod pallet { /// - `prop_index`: The index of the proposal to cancel. /// /// Weight: `O(p)` where `p = PublicProps::::decode_len()` + #[pallet::call_index(17)] #[pallet::weight(T::WeightInfo::cancel_proposal())] pub fn cancel_proposal( origin: OriginFor, diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index cd70514fd3461..4704eaffa0bfe 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -892,6 +892,7 @@ pub mod pallet { /// putting their authoring reward at risk. /// /// No deposit or reward is associated with this submission. + #[pallet::call_index(0)] #[pallet::weight(( T::WeightInfo::submit_unsigned( witness.voters, @@ -941,6 +942,7 @@ pub mod pallet { /// Dispatch origin must be aligned with `T::ForceOrigin`. /// /// This check can be turned off by setting the value to `None`. + #[pallet::call_index(1)] #[pallet::weight(T::DbWeight::get().writes(1))] pub fn set_minimum_untrusted_score( origin: OriginFor, @@ -959,6 +961,7 @@ pub mod pallet { /// The solution is not checked for any feasibility and is assumed to be trustworthy, as any /// feasibility check itself can in principle cause the election process to fail (due to /// memory/weight constrains). + #[pallet::call_index(2)] #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] pub fn set_emergency_election_result( origin: OriginFor, @@ -996,6 +999,7 @@ pub mod pallet { /// /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution /// might be rewarded, slashed, or get all or a part of the deposit back. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::submit())] pub fn submit( origin: OriginFor, @@ -1065,6 +1069,7 @@ pub mod pallet { /// /// This can only be called when [`Phase::Emergency`] is enabled, as an alternative to /// calling [`Call::set_emergency_election_result`]. + #[pallet::call_index(4)] #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] pub fn governance_fallback( origin: OriginFor, diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 165a8fcab429b..1cfdc25fd9b47 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -309,6 +309,7 @@ pub mod pallet { /// # /// We assume the maximum weight among all 3 cases: vote_equal, vote_more and vote_less. /// # + #[pallet::call_index(0)] #[pallet::weight( T::WeightInfo::vote_more(votes.len() as u32) .max(T::WeightInfo::vote_less(votes.len() as u32)) @@ -371,6 +372,7 @@ pub mod pallet { /// This removes the lock and returns the deposit. /// /// The dispatch origin of this call must be signed and be a voter. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::remove_voter())] pub fn remove_voter(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -394,6 +396,7 @@ pub mod pallet { /// # /// The number of current candidates must be provided as witness data. /// # + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::submit_candidacy(*candidate_count))] pub fn submit_candidacy( origin: OriginFor, @@ -438,6 +441,7 @@ pub mod pallet { /// # /// The type of renouncing must be provided as witness data. /// # + #[pallet::call_index(3)] #[pallet::weight(match *renouncing { Renouncing::Candidate(count) => T::WeightInfo::renounce_candidacy_candidate(count), Renouncing::Member => T::WeightInfo::renounce_candidacy_members(), @@ -500,6 +504,7 @@ pub mod pallet { /// If we have a replacement, we use a small weight. Else, since this is a root call and /// will go into phragmen, we assume full block for now. /// # + #[pallet::call_index(4)] #[pallet::weight(if *rerun_election { T::WeightInfo::remove_member_without_replacement() } else { @@ -535,6 +540,7 @@ pub mod pallet { /// # /// The total number of voters and those that are defunct must be provided as witness data. /// # + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::clean_defunct_voters(*_num_voters, *_num_defunct))] pub fn clean_defunct_voters( origin: OriginFor, diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 256529421caae..d5045157dade7 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -497,6 +497,7 @@ pub mod pallet { // // The weight for this extrinsic we rely on the auto-generated `WeightInfo` from the // benchmark toolchain. + #[pallet::call_index(0)] #[pallet::weight( ::WeightInfo::accumulate_dummy() )] @@ -541,6 +542,7 @@ pub mod pallet { // // The weight for this extrinsic we use our own weight object `WeightForSetDummy` to // determine its weight + #[pallet::call_index(1)] #[pallet::weight(WeightForSetDummy::(>::from(100u32)))] pub fn set_dummy( origin: OriginFor, diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index fdf8b61a01acd..46ff7725e3b16 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -229,6 +229,7 @@ pub mod pallet { /// working and receives (and provides) meaningful data. /// This example is not focused on correctness of the oracle itself, but rather its /// purpose is to showcase offchain worker capabilities. + #[pallet::call_index(0)] #[pallet::weight(0)] pub fn submit_price(origin: OriginFor, price: u32) -> DispatchResultWithPostInfo { // Retrieve sender of the transaction. @@ -254,6 +255,7 @@ pub mod pallet { /// /// This example is not focused on correctness of the oracle itself, but rather its /// purpose is to showcase offchain worker capabilities. + #[pallet::call_index(1)] #[pallet::weight(0)] pub fn submit_price_unsigned( origin: OriginFor, @@ -270,6 +272,7 @@ pub mod pallet { Ok(().into()) } + #[pallet::call_index(2)] #[pallet::weight(0)] pub fn submit_price_unsigned_with_signed_payload( origin: OriginFor, diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 5a4ef92b1c874..6f59ac72eb2fd 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -674,6 +674,7 @@ mod tests { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(100)] pub fn some_function(origin: OriginFor) -> DispatchResult { // NOTE: does not make any different. @@ -681,36 +682,42 @@ mod tests { Ok(()) } + #[pallet::call_index(1)] #[pallet::weight((200, DispatchClass::Operational))] pub fn some_root_operation(origin: OriginFor) -> DispatchResult { frame_system::ensure_root(origin)?; Ok(()) } + #[pallet::call_index(2)] #[pallet::weight(0)] pub fn some_unsigned_message(origin: OriginFor) -> DispatchResult { frame_system::ensure_none(origin)?; Ok(()) } + #[pallet::call_index(3)] #[pallet::weight(0)] pub fn allowed_unsigned(origin: OriginFor) -> DispatchResult { frame_system::ensure_root(origin)?; Ok(()) } + #[pallet::call_index(4)] #[pallet::weight(0)] pub fn unallowed_unsigned(origin: OriginFor) -> DispatchResult { frame_system::ensure_root(origin)?; Ok(()) } + #[pallet::call_index(5)] #[pallet::weight((0, DispatchClass::Mandatory))] pub fn inherent_call(origin: OriginFor) -> DispatchResult { frame_system::ensure_none(origin)?; Ok(()) } + #[pallet::call_index(6)] #[pallet::weight(0)] pub fn calculate_storage_root(_origin: OriginFor) -> DispatchResult { let root = sp_io::storage::root(sp_runtime::StateVersion::V1); diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 618afa63c2c4c..7f226826cbc53 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -228,6 +228,7 @@ pub mod pallet { /// If the check fails, the stash remains chilled and waiting for being unbonded as in with /// the normal staking system, but they lose part of their unbonding chunks due to consuming /// the chain's resources. + #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::register_fast_unstake())] pub fn register_fast_unstake(origin: OriginFor) -> DispatchResult { let ctrl = ensure_signed(origin)?; @@ -257,6 +258,7 @@ pub mod pallet { /// Note that the associated stash is still fully unbonded and chilled as a consequence of /// calling `register_fast_unstake`. This should probably be followed by a call to /// `Staking::rebond`. + #[pallet::call_index(1)] #[pallet::weight(::WeightInfo::deregister())] pub fn deregister(origin: OriginFor) -> DispatchResult { let ctrl = ensure_signed(origin)?; @@ -282,6 +284,7 @@ pub mod pallet { /// Control the operation of this pallet. /// /// Dispatch origin must be signed by the [`Config::ControlOrigin`]. + #[pallet::call_index(2)] #[pallet::weight(::WeightInfo::control())] pub fn control(origin: OriginFor, unchecked_eras_to_check: EraIndex) -> DispatchResult { let _ = T::ControlOrigin::ensure_origin(origin)?; diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index fe5b9861853bf..c6b7fd251661f 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -193,6 +193,7 @@ pub mod pallet { /// equivocation proof and validate the given key ownership proof /// against the extracted offender. If both are valid, the offence /// will be reported. + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::report_equivocation(key_owner_proof.validator_count()))] pub fn report_equivocation( origin: OriginFor, @@ -213,6 +214,7 @@ pub mod pallet { /// block authors will call it (validated in `ValidateUnsigned`), as such /// if the block author is defined it will be defined as the equivocation /// reporter. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::report_equivocation(key_owner_proof.validator_count()))] pub fn report_equivocation_unsigned( origin: OriginFor, @@ -240,6 +242,7 @@ pub mod pallet { /// block of all validators of the new authority set. /// /// Only callable by root. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::note_stalled())] pub fn note_stalled( origin: OriginFor, diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 95f5a84d8abb7..8eab2c67418a1 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -284,6 +284,7 @@ pub mod pallet { /// - One storage mutation (codec `O(R)`). /// - One event. /// # + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::add_registrar(T::MaxRegistrars::get()))] pub fn add_registrar( origin: OriginFor, @@ -329,6 +330,7 @@ pub mod pallet { /// - One storage mutation (codec-read `O(X' + R)`, codec-write `O(X + R)`). /// - One event. /// # + #[pallet::call_index(1)] #[pallet::weight( T::WeightInfo::set_identity( T::MaxRegistrars::get(), // R T::MaxAdditionalFields::get(), // X @@ -404,6 +406,7 @@ pub mod pallet { // N storage items for N sub accounts. Right now the weight on this function // is a large overestimate due to the fact that it could potentially write // to 2 x T::MaxSubAccounts::get(). + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::set_subs_old(T::MaxSubAccounts::get()) // P: Assume max sub accounts removed. .saturating_add(T::WeightInfo::set_subs_new(subs.len() as u32)) // S: Assume all subs are new. )] @@ -475,6 +478,7 @@ pub mod pallet { /// - `2` storage reads and `S + 2` storage deletions. /// - One event. /// # + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::clear_identity( T::MaxRegistrars::get(), // R T::MaxSubAccounts::get(), // S @@ -526,6 +530,7 @@ pub mod pallet { /// - Storage: 1 read `O(R)`, 1 mutate `O(X + R)`. /// - One event. /// # + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::request_judgement( T::MaxRegistrars::get(), // R T::MaxAdditionalFields::get(), // X @@ -588,6 +593,7 @@ pub mod pallet { /// - One storage mutation `O(R + X)`. /// - One event /// # + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::cancel_request( T::MaxRegistrars::get(), // R T::MaxAdditionalFields::get(), // X @@ -636,6 +642,7 @@ pub mod pallet { /// - One storage mutation `O(R)`. /// - Benchmark: 7.315 + R * 0.329 µs (min squares analysis) /// # + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] // R pub fn set_fee( origin: OriginFor, @@ -674,6 +681,7 @@ pub mod pallet { /// - One storage mutation `O(R)`. /// - Benchmark: 8.823 + R * 0.32 µs (min squares analysis) /// # + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] // R pub fn set_account_id( origin: OriginFor, @@ -713,6 +721,7 @@ pub mod pallet { /// - One storage mutation `O(R)`. /// - Benchmark: 7.464 + R * 0.325 µs (min squares analysis) /// # + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] // R pub fn set_fields( origin: OriginFor, @@ -761,6 +770,7 @@ pub mod pallet { /// - Storage: 1 read `O(R)`, 1 mutate `O(R + X)`. /// - One event. /// # + #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::provide_judgement( T::MaxRegistrars::get(), // R T::MaxAdditionalFields::get(), // X @@ -834,6 +844,7 @@ pub mod pallet { /// - `S + 2` storage mutations. /// - One event. /// # + #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::kill_identity( T::MaxRegistrars::get(), // R T::MaxSubAccounts::get(), // S @@ -874,6 +885,7 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_ and the sender must have a registered /// sub identity of `sub`. + #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::add_sub(T::MaxSubAccounts::get()))] pub fn add_sub( origin: OriginFor, @@ -909,6 +921,7 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_ and the sender must have a registered /// sub identity of `sub`. + #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::rename_sub(T::MaxSubAccounts::get()))] pub fn rename_sub( origin: OriginFor, @@ -930,6 +943,7 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_ and the sender must have a registered /// sub identity of `sub`. + #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::remove_sub(T::MaxSubAccounts::get()))] pub fn remove_sub(origin: OriginFor, sub: AccountIdLookupOf) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -959,6 +973,7 @@ pub mod pallet { /// /// NOTE: This should not normally be used, but is provided in the case that the non- /// controller of an account is maliciously registered as a sub-account. + #[pallet::call_index(14)] #[pallet::weight(T::WeightInfo::quit_sub(T::MaxSubAccounts::get()))] pub fn quit_sub(origin: OriginFor) -> DispatchResult { let sender = ensure_signed(origin)?; diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 342522ff29b19..f23e610a4874d 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -474,6 +474,7 @@ pub mod pallet { /// # // NOTE: the weight includes the cost of validate_unsigned as it is part of the cost to // import block with such an extrinsic. + #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::validate_unsigned_and_then_heartbeat( heartbeat.validators_len as u32, heartbeat.network_state.external_addresses.len() as u32, diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index 41893254c3c97..95d3cf4b2eed1 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -98,6 +98,7 @@ pub mod pallet { /// ------------------- /// - DB Weight: 1 Read/Write (Accounts) /// # + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::claim())] pub fn claim(origin: OriginFor, index: T::AccountIndex) -> DispatchResult { let who = ensure_signed(origin)?; @@ -131,6 +132,7 @@ pub mod pallet { /// - Reads: Indices Accounts, System Account (recipient) /// - Writes: Indices Accounts, System Account (recipient) /// # + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( origin: OriginFor, @@ -171,6 +173,7 @@ pub mod pallet { /// ------------------- /// - DB Weight: 1 Read/Write (Accounts) /// # + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::free())] pub fn free(origin: OriginFor, index: T::AccountIndex) -> DispatchResult { let who = ensure_signed(origin)?; @@ -207,6 +210,7 @@ pub mod pallet { /// - Reads: Indices Accounts, System Account (original owner) /// - Writes: Indices Accounts, System Account (original owner) /// # + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::force_transfer())] pub fn force_transfer( origin: OriginFor, @@ -245,6 +249,7 @@ pub mod pallet { /// ------------------- /// - DB Weight: 1 Read/Write (Accounts) /// # + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::freeze())] pub fn freeze(origin: OriginFor, index: T::AccountIndex) -> DispatchResult { let who = ensure_signed(origin)?; diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index c501a30ef5f4a..3255062e3fe7f 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -296,6 +296,7 @@ pub mod pallet { /// should listen for the `TicketBought` event. /// /// This extrinsic must be called by a signed origin. + #[pallet::call_index(0)] #[pallet::weight( T::WeightInfo::buy_ticket() .saturating_add(call.get_dispatch_info().weight) @@ -317,6 +318,7 @@ pub mod pallet { /// provided by this pallet, which uses storage to determine the valid calls. /// /// This extrinsic must be called by the Manager origin. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::set_calls(calls.len() as u32))] pub fn set_calls( origin: OriginFor, @@ -344,6 +346,7 @@ pub mod pallet { /// * `length`: How long the lottery should run for starting at the current block. /// * `delay`: How long after the lottery end we should wait before picking a winner. /// * `repeat`: If the lottery should repeat when completed. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::start_lottery())] pub fn start_lottery( origin: OriginFor, @@ -376,6 +379,7 @@ pub mod pallet { /// The lottery will continue to run to completion. /// /// This extrinsic must be called by the `ManagerOrigin`. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::stop_repeat())] pub fn stop_repeat(origin: OriginFor) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 4191bbcc5d86e..77b53aa72dad8 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -166,6 +166,7 @@ pub mod pallet { /// Add a member `who` to the set. /// /// May only be called from `T::AddOrigin`. + #[pallet::call_index(0)] #[pallet::weight(50_000_000)] pub fn add_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::AddOrigin::ensure_origin(origin)?; @@ -188,6 +189,7 @@ pub mod pallet { /// Remove a member `who` from the set. /// /// May only be called from `T::RemoveOrigin`. + #[pallet::call_index(1)] #[pallet::weight(50_000_000)] pub fn remove_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::RemoveOrigin::ensure_origin(origin)?; @@ -211,6 +213,7 @@ pub mod pallet { /// May only be called from `T::SwapOrigin`. /// /// Prime membership is *not* passed from `remove` to `add`, if extant. + #[pallet::call_index(2)] #[pallet::weight(50_000_000)] pub fn swap_member( origin: OriginFor, @@ -244,6 +247,7 @@ pub mod pallet { /// pass `members` pre-sorted. /// /// May only be called from `T::ResetOrigin`. + #[pallet::call_index(3)] #[pallet::weight(50_000_000)] pub fn reset_members(origin: OriginFor, members: Vec) -> DispatchResult { T::ResetOrigin::ensure_origin(origin)?; @@ -266,6 +270,7 @@ pub mod pallet { /// May only be called from `Signed` origin of a current member. /// /// Prime membership is passed from the origin account to `new`, if extant. + #[pallet::call_index(4)] #[pallet::weight(50_000_000)] pub fn change_key(origin: OriginFor, new: AccountIdLookupOf) -> DispatchResult { let remove = ensure_signed(origin)?; @@ -300,6 +305,7 @@ pub mod pallet { /// Set the prime member. Must be a current member. /// /// May only be called from `T::PrimeOrigin`. + #[pallet::call_index(5)] #[pallet::weight(50_000_000)] pub fn set_prime(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::PrimeOrigin::ensure_origin(origin)?; @@ -313,6 +319,7 @@ pub mod pallet { /// Remove the prime member if it exists. /// /// May only be called from `T::PrimeOrigin`. + #[pallet::call_index(6)] #[pallet::weight(50_000_000)] pub fn clear_prime(origin: OriginFor) -> DispatchResult { T::PrimeOrigin::ensure_origin(origin)?; diff --git a/frame/message-queue/src/lib.rs b/frame/message-queue/src/lib.rs index 6945ff1b1e549..8d9faebe0517f 100644 --- a/frame/message-queue/src/lib.rs +++ b/frame/message-queue/src/lib.rs @@ -575,6 +575,7 @@ pub mod pallet { #[pallet::call] impl Pallet { /// Remove a page which has no more messages remaining to be processed or is stale. + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::reap_page())] pub fn reap_page( origin: OriginFor, @@ -595,6 +596,7 @@ pub mod pallet { /// of the message. /// /// Benchmark complexity considerations: O(index + weight_limit). + #[pallet::call_index(1)] #[pallet::weight( T::WeightInfo::execute_overweight_page_updated().max( T::WeightInfo::execute_overweight_page_removed()).saturating_add(*weight_limit) diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index ae4efb76335a0..076a289e06519 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -272,6 +272,7 @@ pub mod pallet { /// - DB Weight: None /// - Plus Call Weight /// # + #[pallet::call_index(0)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( @@ -365,6 +366,7 @@ pub mod pallet { /// - Writes: Multisig Storage, [Caller Account] /// - Plus Call Weight /// # + #[pallet::call_index(1)] #[pallet::weight({ let s = other_signatories.len() as u32; let z = call.using_encoded(|d| d.len()) as u32; @@ -428,6 +430,7 @@ pub mod pallet { /// - Read: Multisig Storage, [Caller Account] /// - Write: Multisig Storage, [Caller Account] /// # + #[pallet::call_index(2)] #[pallet::weight({ let s = other_signatories.len() as u32; @@ -480,6 +483,7 @@ pub mod pallet { /// - Read: Multisig Storage, [Caller Account], Refund Account /// - Write: Multisig Storage, [Caller Account], Refund Account /// # + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::cancel_as_multi(other_signatories.len() as u32))] pub fn cancel_as_multi( origin: OriginFor, diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index b3238630d3174..79daeb9bdb9a8 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -135,6 +135,7 @@ pub mod pallet { /// - One storage read/write. /// - One event. /// # + #[pallet::call_index(0)] #[pallet::weight(50_000_000)] pub fn set_name(origin: OriginFor, name: Vec) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -167,6 +168,7 @@ pub mod pallet { /// - One storage read/write. /// - One event. /// # + #[pallet::call_index(1)] #[pallet::weight(70_000_000)] pub fn clear_name(origin: OriginFor) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -193,6 +195,7 @@ pub mod pallet { /// - One storage read/write. /// - One event. /// # + #[pallet::call_index(2)] #[pallet::weight(70_000_000)] pub fn kill_name(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; @@ -220,6 +223,7 @@ pub mod pallet { /// - One storage read/write. /// - One event. /// # + #[pallet::call_index(3)] #[pallet::weight(70_000_000)] pub fn force_name( origin: OriginFor, diff --git a/frame/nis/src/lib.rs b/frame/nis/src/lib.rs index 97f727c241479..dff64625a3654 100644 --- a/frame/nis/src/lib.rs +++ b/frame/nis/src/lib.rs @@ -520,6 +520,7 @@ pub mod pallet { /// /// Complexities: /// - `Queues[duration].len()` (just take max). + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::place_bid_max())] pub fn place_bid( origin: OriginFor, @@ -581,6 +582,7 @@ pub mod pallet { /// /// - `amount`: The amount of the previous bid. /// - `duration`: The duration of the previous bid. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::retract_bid(T::MaxQueueLen::get()))] pub fn retract_bid( origin: OriginFor, @@ -615,6 +617,7 @@ pub mod pallet { /// Ensure we have sufficient funding for all potential payouts. /// /// - `origin`: Must be accepted by `FundOrigin`. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::fund_deficit())] pub fn fund_deficit(origin: OriginFor) -> DispatchResult { T::FundOrigin::ensure_origin(origin)?; @@ -636,6 +639,7 @@ pub mod pallet { /// - `index`: The index of the receipt. /// - `portion`: If `Some`, then only the given portion of the receipt should be thawed. If /// `None`, then all of it should be. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::thaw())] pub fn thaw( origin: OriginFor, diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index bd1b14d10b013..543ba24500ebc 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -210,6 +210,7 @@ pub mod pallet { /// May only be called from `T::AddOrigin`. /// /// - `node`: identifier of the node. + #[pallet::call_index(0)] #[pallet::weight((T::WeightInfo::add_well_known_node(), DispatchClass::Operational))] pub fn add_well_known_node( origin: OriginFor, @@ -239,6 +240,7 @@ pub mod pallet { /// May only be called from `T::RemoveOrigin`. /// /// - `node`: identifier of the node. + #[pallet::call_index(1)] #[pallet::weight((T::WeightInfo::remove_well_known_node(), DispatchClass::Operational))] pub fn remove_well_known_node(origin: OriginFor, node: PeerId) -> DispatchResult { T::RemoveOrigin::ensure_origin(origin)?; @@ -264,6 +266,7 @@ pub mod pallet { /// /// - `remove`: the node which will be moved out from the list. /// - `add`: the node which will be put in the list. + #[pallet::call_index(2)] #[pallet::weight((T::WeightInfo::swap_well_known_node(), DispatchClass::Operational))] pub fn swap_well_known_node( origin: OriginFor, @@ -300,6 +303,7 @@ pub mod pallet { /// May only be called from `T::ResetOrigin`. /// /// - `nodes`: the new nodes for the allow list. + #[pallet::call_index(3)] #[pallet::weight((T::WeightInfo::reset_well_known_nodes(), DispatchClass::Operational))] pub fn reset_well_known_nodes( origin: OriginFor, @@ -318,6 +322,7 @@ pub mod pallet { /// PeerId, so claim it right away! /// /// - `node`: identifier of the node. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::claim_node())] pub fn claim_node(origin: OriginFor, node: PeerId) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -335,6 +340,7 @@ pub mod pallet { /// needs to reach consensus among the network participants. /// /// - `node`: identifier of the node. + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::remove_claim())] pub fn remove_claim(origin: OriginFor, node: PeerId) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -355,6 +361,7 @@ pub mod pallet { /// /// - `node`: identifier of the node. /// - `owner`: new owner of the node. + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::transfer_node())] pub fn transfer_node( origin: OriginFor, @@ -378,6 +385,7 @@ pub mod pallet { /// /// - `node`: identifier of the node. /// - `connections`: additonal nodes from which the connections are allowed. + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::add_connections())] pub fn add_connections( origin: OriginFor, @@ -412,6 +420,7 @@ pub mod pallet { /// /// - `node`: identifier of the node. /// - `connections`: additonal nodes from which the connections are not allowed anymore. + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::remove_connections())] pub fn remove_connections( origin: OriginFor, diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 9ca9539b3dca8..fd533ee3762b4 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1506,6 +1506,7 @@ pub mod pallet { /// * This call will *not* dust the member account, so the member must have at least /// `existential deposit + amount` in their account. /// * Only a pool with [`PoolState::Open`] can be joined + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::join())] pub fn join( origin: OriginFor, @@ -1563,6 +1564,7 @@ pub mod pallet { // NOTE: this transaction is implemented with the sole purpose of readability and // correctness, not optimization. We read/write several storage items multiple times instead // of just once, in the spirit reusing code. + #[pallet::call_index(1)] #[pallet::weight( T::WeightInfo::bond_extra_transfer() .max(T::WeightInfo::bond_extra_reward()) @@ -1605,6 +1607,7 @@ pub mod pallet { /// /// The member will earn rewards pro rata based on the members stake vs the sum of the /// members in the pools stake. Rewards do not "expire". + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::claim_payout())] pub fn claim_payout(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -1644,6 +1647,7 @@ pub mod pallet { /// [`Call::pool_withdraw_unbonded`] can be called to try and minimize unlocking chunks. If /// there are too many unlocking chunks, the result of this call will likely be the /// `NoMoreChunks` error from the staking system. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::unbond())] pub fn unbond( origin: OriginFor, @@ -1719,6 +1723,7 @@ pub mod pallet { /// can be cleared by withdrawing. In the case there are too many unlocking chunks, the user /// would probably see an error like `NoMoreChunks` emitted from the staking system when /// they attempt to unbond. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::pool_withdraw_unbonded(*num_slashing_spans))] pub fn pool_withdraw_unbonded( origin: OriginFor, @@ -1753,6 +1758,7 @@ pub mod pallet { /// # Note /// /// If the target is the depositor, the pool will be destroyed. + #[pallet::call_index(5)] #[pallet::weight( T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans) )] @@ -1874,6 +1880,7 @@ pub mod pallet { /// /// In addition to `amount`, the caller will transfer the existential deposit; so the caller /// needs at have at least `amount + existential_deposit` transferrable. + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::create())] pub fn create( origin: OriginFor, @@ -1898,6 +1905,7 @@ pub mod pallet { /// /// same as `create` with the inclusion of /// * `pool_id` - `A valid PoolId. + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::create())] pub fn create_with_pool_id( origin: OriginFor, @@ -1922,6 +1930,7 @@ pub mod pallet { /// /// This directly forward the call to the staking pallet, on behalf of the pool bonded /// account. + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::nominate(validators.len() as u32))] pub fn nominate( origin: OriginFor, @@ -1944,6 +1953,7 @@ pub mod pallet { /// 1. signed by the state toggler, or the root role of the pool, /// 2. if the pool conditions to be open are NOT met (as described by `ok_to_be_open`), and /// then the state of the pool can be permissionlessly changed to `Destroying`. + #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::set_state())] pub fn set_state( origin: OriginFor, @@ -1972,6 +1982,7 @@ pub mod pallet { /// /// The dispatch origin of this call must be signed by the state toggler, or the root role /// of the pool. + #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::set_metadata(metadata.len() as u32))] pub fn set_metadata( origin: OriginFor, @@ -2003,6 +2014,7 @@ pub mod pallet { /// * `max_pools` - Set [`MaxPools`]. /// * `max_members` - Set [`MaxPoolMembers`]. /// * `max_members_per_pool` - Set [`MaxPoolMembersPerPool`]. + #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::set_configs())] pub fn set_configs( origin: OriginFor, @@ -2039,6 +2051,7 @@ pub mod pallet { /// /// It emits an event, notifying UIs of the role change. This event is quite relevant to /// most pool members and they should be informed of changes to pool roles. + #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::update_roles())] pub fn update_roles( origin: OriginFor, @@ -2091,6 +2104,7 @@ pub mod pallet { /// /// This directly forward the call to the staking pallet, on behalf of the pool bonded /// account. + #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::chill())] pub fn chill(origin: OriginFor, pool_id: PoolId) -> DispatchResult { let who = ensure_signed(origin)?; diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 6549832c11f5d..bf7d602057cac 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -153,6 +153,7 @@ pub mod pallet { /// /// If the preimage was previously requested, no fees or deposits are taken for providing /// the preimage. Otherwise, a deposit is taken proportional to the size of the preimage. + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::note_preimage(bytes.len() as u32))] pub fn note_preimage(origin: OriginFor, bytes: Vec) -> DispatchResultWithPostInfo { // We accept a signed origin which will pay a deposit, or a root origin where a deposit @@ -172,6 +173,7 @@ pub mod pallet { /// /// - `hash`: The hash of the preimage to be removed from the store. /// - `len`: The length of the preimage of `hash`. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::unnote_preimage())] pub fn unnote_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { let maybe_sender = Self::ensure_signed_or_manager(origin)?; @@ -182,6 +184,7 @@ pub mod pallet { /// /// If the preimage requests has already been provided on-chain, we unreserve any deposit /// a user may have paid, and take the control of the preimage out of their hands. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::request_preimage())] pub fn request_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; @@ -192,6 +195,7 @@ pub mod pallet { /// Clear a previously made request for a preimage. /// /// NOTE: THIS MUST NOT BE CALLED ON `hash` MORE TIMES THAN `request_preimage`. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::unrequest_preimage())] pub fn unrequest_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 5c07a2b012243..d98534d16a21b 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -191,6 +191,7 @@ pub mod pallet { /// - `real`: The account that the proxy will make a call on behalf of. /// - `force_proxy_type`: Specify the exact proxy type to be used and checked for this call. /// - `call`: The call to be made by the `real` account. + #[pallet::call_index(0)] #[pallet::weight({ let di = call.get_dispatch_info(); (T::WeightInfo::proxy(T::MaxProxies::get()) @@ -224,6 +225,7 @@ pub mod pallet { /// - `proxy_type`: The permissions allowed for this proxy account. /// - `delay`: The announcement period required of the initial proxy. Will generally be /// zero. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::add_proxy(T::MaxProxies::get()))] pub fn add_proxy( origin: OriginFor, @@ -243,6 +245,7 @@ pub mod pallet { /// Parameters: /// - `proxy`: The account that the `caller` would like to remove as a proxy. /// - `proxy_type`: The permissions currently enabled for the removed proxy account. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::remove_proxy(T::MaxProxies::get()))] pub fn remove_proxy( origin: OriginFor, @@ -261,6 +264,7 @@ pub mod pallet { /// /// WARNING: This may be called on accounts created by `pure`, however if done, then /// the unreserved fees will be inaccessible. **All access to this account will be lost.** + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::remove_proxies(T::MaxProxies::get()))] pub fn remove_proxies(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -288,6 +292,7 @@ pub mod pallet { /// same sender, with the same parameters. /// /// Fails if there are insufficient funds to pay for deposit. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::create_pure(T::MaxProxies::get()))] pub fn create_pure( origin: OriginFor, @@ -335,6 +340,7 @@ pub mod pallet { /// /// Fails with `NoPermission` in case the caller is not a previously created pure /// account whose `pure` call has corresponding parameters. + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::kill_pure(T::MaxProxies::get()))] pub fn kill_pure( origin: OriginFor, @@ -372,6 +378,7 @@ pub mod pallet { /// Parameters: /// - `real`: The account that the proxy will make a call on behalf of. /// - `call_hash`: The hash of the call to be made by the `real` account. + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::announce(T::MaxPending::get(), T::MaxProxies::get()))] pub fn announce( origin: OriginFor, @@ -421,6 +428,7 @@ pub mod pallet { /// Parameters: /// - `real`: The account that the proxy will make a call on behalf of. /// - `call_hash`: The hash of the call to be made by the `real` account. + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::remove_announcement( T::MaxPending::get(), T::MaxProxies::get() @@ -447,6 +455,7 @@ pub mod pallet { /// Parameters: /// - `delegate`: The account that previously announced the call. /// - `call_hash`: The hash of the call to be made. + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::reject_announcement( T::MaxPending::get(), T::MaxProxies::get() @@ -476,6 +485,7 @@ pub mod pallet { /// - `real`: The account that the proxy will make a call on behalf of. /// - `force_proxy_type`: Specify the exact proxy type to be used and checked for this call. /// - `call`: The call to be made by the `real` account. + #[pallet::call_index(9)] #[pallet::weight({ let di = call.get_dispatch_info(); (T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get()) diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 33aed2704918c..b057a57508023 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -470,6 +470,7 @@ pub mod pallet { /// - `rank`: The rank to give the new member. /// /// Weight: `O(1)` + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::add_member())] pub fn add_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { let _ = T::PromoteOrigin::ensure_origin(origin)?; @@ -483,6 +484,7 @@ pub mod pallet { /// - `who`: Account of existing member. /// /// Weight: `O(1)` + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::promote_member(0))] pub fn promote_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { let max_rank = T::PromoteOrigin::ensure_origin(origin)?; @@ -497,6 +499,7 @@ pub mod pallet { /// - `who`: Account of existing member of rank greater than zero. /// /// Weight: `O(1)`, less if the member's index is highest in its rank. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::demote_member(0))] pub fn demote_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { let max_rank = T::DemoteOrigin::ensure_origin(origin)?; @@ -528,6 +531,7 @@ pub mod pallet { /// - `min_rank`: The rank of the member or greater. /// /// Weight: `O(min_rank)`. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::remove_member(*min_rank as u32))] pub fn remove_member( origin: OriginFor, @@ -562,6 +566,7 @@ pub mod pallet { /// fee. /// /// Weight: `O(1)`, less if there was no previous vote on the poll by the member. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::vote())] pub fn vote( origin: OriginFor, @@ -618,6 +623,7 @@ pub mod pallet { /// Transaction fees are waived if the operation is successful. /// /// Weight `O(max)` (less if there are fewer items to remove than `max`). + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::cleanup_poll(*max))] pub fn cleanup_poll( origin: OriginFor, diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index 18d3d48dc024c..9c57ca79d2e47 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -374,6 +374,7 @@ pub mod pallet { /// Parameters: /// - `account`: The recovered account you want to make a call on-behalf-of. /// - `call`: The call you want to make with the recovered account. + #[pallet::call_index(0)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( @@ -403,6 +404,7 @@ pub mod pallet { /// Parameters: /// - `lost`: The "lost account" to be recovered. /// - `rescuer`: The "rescuer account" which can call as the lost account. + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::set_recovered())] pub fn set_recovered( origin: OriginFor, @@ -437,6 +439,7 @@ pub mod pallet { /// friends. /// - `delay_period`: The number of blocks after a recovery attempt is initialized that /// needs to pass before the account can be recovered. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::create_recovery(friends.len() as u32))] pub fn create_recovery( origin: OriginFor, @@ -488,6 +491,7 @@ pub mod pallet { /// Parameters: /// - `account`: The lost account that you want to recover. This account needs to be /// recoverable (i.e. have a recovery configuration). + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::initiate_recovery())] pub fn initiate_recovery( origin: OriginFor, @@ -532,6 +536,7 @@ pub mod pallet { /// /// The combination of these two parameters must point to an active recovery /// process. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::vouch_recovery(T::MaxFriends::get()))] pub fn vouch_recovery( origin: OriginFor, @@ -575,6 +580,7 @@ pub mod pallet { /// Parameters: /// - `account`: The lost account that you want to claim has been successfully recovered by /// you. + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::claim_recovery(T::MaxFriends::get()))] pub fn claim_recovery( origin: OriginFor, @@ -622,6 +628,7 @@ pub mod pallet { /// /// Parameters: /// - `rescuer`: The account trying to rescue this recoverable account. + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::close_recovery(T::MaxFriends::get()))] pub fn close_recovery( origin: OriginFor, @@ -659,6 +666,7 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_ and must be a /// recoverable account (i.e. has a recovery configuration). + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::remove_recovery(T::MaxFriends::get()))] pub fn remove_recovery(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -681,6 +689,7 @@ pub mod pallet { /// /// Parameters: /// - `account`: The recovered account you are able to call on-behalf-of. + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::cancel_recovered())] pub fn cancel_recovered( origin: OriginFor, diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 2bb01baa0cd3a..0b846faf88558 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -397,6 +397,7 @@ pub mod pallet { /// - `enactment_moment`: The moment that the proposal should be enacted. /// /// Emits `Submitted`. + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::submit())] pub fn submit( origin: OriginFor, @@ -444,6 +445,7 @@ pub mod pallet { /// posted. /// /// Emits `DecisionDepositPlaced`. + #[pallet::call_index(1)] #[pallet::weight(ServiceBranch::max_weight_of_deposit::())] pub fn place_decision_deposit( origin: OriginFor, @@ -471,6 +473,7 @@ pub mod pallet { /// refunded. /// /// Emits `DecisionDepositRefunded`. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::refund_decision_deposit())] pub fn refund_decision_deposit( origin: OriginFor, @@ -500,6 +503,7 @@ pub mod pallet { /// - `index`: The index of the referendum to be cancelled. /// /// Emits `Cancelled`. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::cancel())] pub fn cancel(origin: OriginFor, index: ReferendumIndex) -> DispatchResult { T::CancelOrigin::ensure_origin(origin)?; @@ -524,6 +528,7 @@ pub mod pallet { /// - `index`: The index of the referendum to be cancelled. /// /// Emits `Killed` and `DepositSlashed`. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::kill())] pub fn kill(origin: OriginFor, index: ReferendumIndex) -> DispatchResult { T::KillOrigin::ensure_origin(origin)?; @@ -544,6 +549,7 @@ pub mod pallet { /// /// - `origin`: must be `Root`. /// - `index`: the referendum to be advanced. + #[pallet::call_index(5)] #[pallet::weight(ServiceBranch::max_weight_of_nudge::())] pub fn nudge_referendum( origin: OriginFor, @@ -570,6 +576,7 @@ pub mod pallet { /// `DecidingCount` is not yet updated. This means that we should either: /// - begin deciding another referendum (and leave `DecidingCount` alone); or /// - decrement `DecidingCount`. + #[pallet::call_index(6)] #[pallet::weight(OneFewerDecidingBranch::max_weight::())] pub fn one_fewer_deciding( origin: OriginFor, @@ -603,6 +610,7 @@ pub mod pallet { /// refunded. /// /// Emits `SubmissionDepositRefunded`. + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::refund_submission_deposit())] pub fn refund_submission_deposit( origin: OriginFor, diff --git a/frame/remark/src/lib.rs b/frame/remark/src/lib.rs index b61c79f7f273d..80fe393c20f4a 100644 --- a/frame/remark/src/lib.rs +++ b/frame/remark/src/lib.rs @@ -62,6 +62,7 @@ pub mod pallet { #[pallet::call] impl Pallet { /// Index and store data off chain. + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::store(remark.len() as u32))] pub fn store(origin: OriginFor, remark: Vec) -> DispatchResultWithPostInfo { ensure!(!remark.is_empty(), Error::::Empty); diff --git a/frame/root-offences/src/lib.rs b/frame/root-offences/src/lib.rs index 298fe0078a6a6..ed039f46becc8 100644 --- a/frame/root-offences/src/lib.rs +++ b/frame/root-offences/src/lib.rs @@ -81,6 +81,7 @@ pub mod pallet { #[pallet::call] impl Pallet { /// Allows the `root`, for example sudo to create an offence. + #[pallet::call_index(0)] #[pallet::weight(T::DbWeight::get().reads(2))] pub fn create_offence( origin: OriginFor, diff --git a/frame/root-testing/src/lib.rs b/frame/root-testing/src/lib.rs index 25d66cfac202d..da67904967853 100644 --- a/frame/root-testing/src/lib.rs +++ b/frame/root-testing/src/lib.rs @@ -45,6 +45,7 @@ pub mod pallet { #[pallet::call] impl Pallet { /// A dispatch that will fill the block weight up to the given ratio. + #[pallet::call_index(0)] #[pallet::weight(*_ratio * T::BlockWeights::get().max_block)] pub fn fill_block(origin: OriginFor, _ratio: Perbill) -> DispatchResult { ensure_root(origin)?; diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 2e0d0c6be1db5..d6a66c5e2cb2c 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -297,6 +297,7 @@ pub mod pallet { #[pallet::call] impl Pallet { /// Anonymously schedule a task. + #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::schedule(T::MaxScheduledPerBlock::get()))] pub fn schedule( origin: OriginFor, @@ -318,6 +319,7 @@ pub mod pallet { } /// Cancel an anonymously scheduled task. + #[pallet::call_index(1)] #[pallet::weight(::WeightInfo::cancel(T::MaxScheduledPerBlock::get()))] pub fn cancel(origin: OriginFor, when: T::BlockNumber, index: u32) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; @@ -327,6 +329,7 @@ pub mod pallet { } /// Schedule a named task. + #[pallet::call_index(2)] #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] pub fn schedule_named( origin: OriginFor, @@ -350,6 +353,7 @@ pub mod pallet { } /// Cancel a named scheduled task. + #[pallet::call_index(3)] #[pallet::weight(::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))] pub fn cancel_named(origin: OriginFor, id: TaskName) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; @@ -363,6 +367,7 @@ pub mod pallet { /// # /// Same as [`schedule`]. /// # + #[pallet::call_index(4)] #[pallet::weight(::WeightInfo::schedule(T::MaxScheduledPerBlock::get()))] pub fn schedule_after( origin: OriginFor, @@ -388,6 +393,7 @@ pub mod pallet { /// # /// Same as [`schedule_named`](Self::schedule_named). /// # + #[pallet::call_index(5)] #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] pub fn schedule_named_after( origin: OriginFor, diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 61efdfb67b73e..0aaac56667dcb 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -72,6 +72,7 @@ pub mod logger { where ::RuntimeOrigin: OriginTrait, { + #[pallet::call_index(0)] #[pallet::weight(*weight)] pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { Self::deposit_event(Event::Logged(i, weight)); @@ -81,6 +82,7 @@ pub mod logger { Ok(()) } + #[pallet::call_index(1)] #[pallet::weight(*weight)] pub fn log_without_filter(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { Self::deposit_event(Event::Logged(i, weight)); diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index a015c1c568153..5db9c6506d770 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -311,6 +311,7 @@ pub mod pallet { /// /// The `index` parameter of this function must be set to /// the index of the transactor in the `Pool`. + #[pallet::call_index(0)] #[pallet::weight(0)] pub fn submit_candidacy(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -340,6 +341,7 @@ pub mod pallet { /// /// The `index` parameter of this function must be set to /// the index of the transactor in the `Pool`. + #[pallet::call_index(1)] #[pallet::weight(0)] pub fn withdraw_candidacy(origin: OriginFor, index: u32) -> DispatchResult { let who = ensure_signed(origin)?; @@ -358,6 +360,7 @@ pub mod pallet { /// /// The `index` parameter of this function must be set to /// the index of `dest` in the `Pool`. + #[pallet::call_index(2)] #[pallet::weight(0)] pub fn kick( origin: OriginFor, @@ -382,6 +385,7 @@ pub mod pallet { /// /// The `index` parameter of this function must be set to /// the index of the `dest` in the `Pool`. + #[pallet::call_index(3)] #[pallet::weight(0)] pub fn score( origin: OriginFor, @@ -421,6 +425,7 @@ pub mod pallet { /// (this happens each `Period`). /// /// May only be called from root. + #[pallet::call_index(4)] #[pallet::weight(0)] pub fn change_member_count(origin: OriginFor, count: u32) -> DispatchResult { ensure_root(origin)?; diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 7b97a20860175..4e2caf5e0874e 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -595,6 +595,7 @@ pub mod pallet { /// - DbReads per key id: `KeyOwner` /// - DbWrites per key id: `KeyOwner` /// # + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::set_keys())] pub fn set_keys(origin: OriginFor, keys: T::Keys, proof: Vec) -> DispatchResult { let who = ensure_signed(origin)?; @@ -620,6 +621,7 @@ pub mod pallet { /// - DbWrites: `NextKeys`, `origin account` /// - DbWrites per key id: `KeyOwner` /// # + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::purge_keys())] pub fn purge_keys(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 73a09490ea579..0edf00ff80f6e 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -711,6 +711,7 @@ pub mod pallet { /// /// Total Complexity: O(M + B + C + logM + logB + X) /// # + #[pallet::call_index(0)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn bid(origin: OriginFor, value: BalanceOf) -> DispatchResult { let who = ensure_signed(origin)?; @@ -750,6 +751,7 @@ pub mod pallet { /// /// Total Complexity: O(B + X) /// # + #[pallet::call_index(1)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn unbid(origin: OriginFor, pos: u32) -> DispatchResult { let who = ensure_signed(origin)?; @@ -822,6 +824,7 @@ pub mod pallet { /// /// Total Complexity: O(M + B + C + logM + logB + X) /// # + #[pallet::call_index(2)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn vouch( origin: OriginFor, @@ -873,6 +876,7 @@ pub mod pallet { /// /// Total Complexity: O(B) /// # + #[pallet::call_index(3)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn unvouch(origin: OriginFor, pos: u32) -> DispatchResult { let voucher = ensure_signed(origin)?; @@ -914,6 +918,7 @@ pub mod pallet { /// /// Total Complexity: O(M + logM + C) /// # + #[pallet::call_index(4)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn vote( origin: OriginFor, @@ -950,6 +955,7 @@ pub mod pallet { /// /// Total Complexity: O(M + logM) /// # + #[pallet::call_index(5)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn defender_vote(origin: OriginFor, approve: bool) -> DispatchResult { let voter = ensure_signed(origin)?; @@ -984,6 +990,7 @@ pub mod pallet { /// /// Total Complexity: O(M + logM + P + X) /// # + #[pallet::call_index(6)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn payout(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -1026,6 +1033,7 @@ pub mod pallet { /// /// Total Complexity: O(1) /// # + #[pallet::call_index(7)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn found( origin: OriginFor, @@ -1060,6 +1068,7 @@ pub mod pallet { /// /// Total Complexity: O(1) /// # + #[pallet::call_index(8)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn unfound(origin: OriginFor) -> DispatchResult { let founder = ensure_signed(origin)?; @@ -1105,6 +1114,7 @@ pub mod pallet { /// /// Total Complexity: O(M + logM + B) /// # + #[pallet::call_index(9)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn judge_suspended_member( origin: OriginFor, @@ -1182,6 +1192,7 @@ pub mod pallet { /// /// Total Complexity: O(M + logM + B + X) /// # + #[pallet::call_index(10)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn judge_suspended_candidate( origin: OriginFor, @@ -1255,6 +1266,7 @@ pub mod pallet { /// /// Total Complexity: O(1) /// # + #[pallet::call_index(11)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn set_max_members(origin: OriginFor, max: u32) -> DispatchResult { ensure_root(origin)?; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 8fddba2150370..9dc39dd4a2116 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -831,6 +831,7 @@ pub mod pallet { /// unless the `origin` falls below _existential deposit_ and gets removed as dust. /// ------------------ /// # + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::bond())] pub fn bond( origin: OriginFor, @@ -900,6 +901,7 @@ pub mod pallet { /// - Independent of the arguments. Insignificant complexity. /// - O(1). /// # + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::bond_extra())] pub fn bond_extra( origin: OriginFor, @@ -953,6 +955,7 @@ pub mod pallet { /// Emits `Unbonded`. /// /// See also [`Call::withdraw_unbonded`]. + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::unbond())] pub fn unbond( origin: OriginFor, @@ -1032,6 +1035,7 @@ pub mod pallet { /// Complexity O(S) where S is the number of slashing spans to remove /// NOTE: Weight annotation is the kill scenario, we refund otherwise. /// # + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans))] pub fn withdraw_unbonded( origin: OriginFor, @@ -1079,6 +1083,7 @@ pub mod pallet { /// Effects will be felt at the beginning of the next era. /// /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::validate())] pub fn validate(origin: OriginFor, prefs: ValidatorPrefs) -> DispatchResult { let controller = ensure_signed(origin)?; @@ -1122,6 +1127,7 @@ pub mod pallet { /// which is capped at CompactAssignments::LIMIT (T::MaxNominations). /// - Both the reads and writes follow a similar pattern. /// # + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::nominate(targets.len() as u32))] pub fn nominate( origin: OriginFor, @@ -1190,6 +1196,7 @@ pub mod pallet { /// - Contains one read. /// - Writes are limited to the `origin` account key. /// # + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::chill())] pub fn chill(origin: OriginFor) -> DispatchResult { let controller = ensure_signed(origin)?; @@ -1214,6 +1221,7 @@ pub mod pallet { /// - Read: Ledger /// - Write: Payee /// # + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::set_payee())] pub fn set_payee( origin: OriginFor, @@ -1242,6 +1250,7 @@ pub mod pallet { /// - Read: Bonded, Ledger New Controller, Ledger Old Controller /// - Write: Bonded, Ledger New Controller, Ledger Old Controller /// # + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::set_controller())] pub fn set_controller( origin: OriginFor, @@ -1270,6 +1279,7 @@ pub mod pallet { /// Weight: O(1) /// Write: Validator Count /// # + #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::set_validator_count())] pub fn set_validator_count( origin: OriginFor, @@ -1294,6 +1304,7 @@ pub mod pallet { /// # /// Same as [`Self::set_validator_count`]. /// # + #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::set_validator_count())] pub fn increase_validator_count( origin: OriginFor, @@ -1319,6 +1330,7 @@ pub mod pallet { /// # /// Same as [`Self::set_validator_count`]. /// # + #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::set_validator_count())] pub fn scale_validator_count(origin: OriginFor, factor: Percent) -> DispatchResult { ensure_root(origin)?; @@ -1349,6 +1361,7 @@ pub mod pallet { /// - Weight: O(1) /// - Write: ForceEra /// # + #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::force_no_eras())] pub fn force_no_eras(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; @@ -1372,6 +1385,7 @@ pub mod pallet { /// - Weight: O(1) /// - Write ForceEra /// # + #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::force_new_era())] pub fn force_new_era(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; @@ -1382,6 +1396,7 @@ pub mod pallet { /// Set the validators who cannot be slashed (if any). /// /// The dispatch origin must be Root. + #[pallet::call_index(14)] #[pallet::weight(T::WeightInfo::set_invulnerables(invulnerables.len() as u32))] pub fn set_invulnerables( origin: OriginFor, @@ -1395,6 +1410,7 @@ pub mod pallet { /// Force a current staker to become completely unstaked, immediately. /// /// The dispatch origin must be Root. + #[pallet::call_index(15)] #[pallet::weight(T::WeightInfo::force_unstake(*num_slashing_spans))] pub fn force_unstake( origin: OriginFor, @@ -1420,6 +1436,7 @@ pub mod pallet { /// The election process starts multiple blocks before the end of the era. /// If this is called just before a new era is triggered, the election process may not /// have enough blocks to get a result. + #[pallet::call_index(16)] #[pallet::weight(T::WeightInfo::force_new_era_always())] pub fn force_new_era_always(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; @@ -1432,6 +1449,7 @@ pub mod pallet { /// Can be called by the `T::SlashCancelOrigin`. /// /// Parameters: era and indices of the slashes for that era to kill. + #[pallet::call_index(17)] #[pallet::weight(T::WeightInfo::cancel_deferred_slash(slash_indices.len() as u32))] pub fn cancel_deferred_slash( origin: OriginFor, @@ -1477,6 +1495,7 @@ pub mod pallet { /// NOTE: weights are assuming that payouts are made to alive stash account (Staked). /// Paying even a dead controller is cheaper weight-wise. We don't do any refunds here. /// # + #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( T::MaxNominatorRewardedPerValidator::get() ))] @@ -1498,6 +1517,7 @@ pub mod pallet { /// - Bounded by `MaxUnlockingChunks`. /// - Storage changes: Can't increase storage, only decrease it. /// # + #[pallet::call_index(19)] #[pallet::weight(T::WeightInfo::rebond(T::MaxUnlockingChunks::get() as u32))] pub fn rebond( origin: OriginFor, @@ -1542,6 +1562,7 @@ pub mod pallet { /// It can be called by anyone, as long as `stash` meets the above requirements. /// /// Refunds the transaction fees upon successful execution. + #[pallet::call_index(20)] #[pallet::weight(T::WeightInfo::reap_stash(*num_slashing_spans))] pub fn reap_stash( origin: OriginFor, @@ -1574,6 +1595,7 @@ pub mod pallet { /// /// Note: Making this call only makes sense if you first set the validator preferences to /// block any further nominations. + #[pallet::call_index(21)] #[pallet::weight(T::WeightInfo::kick(who.len() as u32))] pub fn kick(origin: OriginFor, who: Vec>) -> DispatchResult { let controller = ensure_signed(origin)?; @@ -1621,6 +1643,7 @@ pub mod pallet { /// to kick people under the new limits, `chill_other` should be called. // We assume the worst case for this call is either: all items are set or all items are // removed. + #[pallet::call_index(22)] #[pallet::weight( T::WeightInfo::set_staking_configs_all_set() .max(T::WeightInfo::set_staking_configs_all_remove()) @@ -1681,6 +1704,7 @@ pub mod pallet { /// /// This can be helpful if bond requirements are updated, and we need to remove old users /// who do not satisfy these requirements. + #[pallet::call_index(23)] #[pallet::weight(T::WeightInfo::chill_other())] pub fn chill_other(origin: OriginFor, controller: T::AccountId) -> DispatchResult { // Anyone can call this function. @@ -1743,6 +1767,7 @@ pub mod pallet { /// Force a validator to have at least the minimum commission. This will not affect a /// validator who already has a commission greater than or equal to the minimum. Any account /// can call this. + #[pallet::call_index(24)] #[pallet::weight(T::WeightInfo::force_apply_min_commission())] pub fn force_apply_min_commission( origin: OriginFor, diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index aab92e678e88c..823ea08a0b573 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -546,6 +546,7 @@ pub mod pallet { /// Control the automatic migration. /// /// The dispatch origin of this call must be [`Config::ControlOrigin`]. + #[pallet::call_index(0)] #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] pub fn control_auto_migration( origin: OriginFor, @@ -577,6 +578,7 @@ pub mod pallet { /// Based on the documentation of [`MigrationTask::migrate_until_exhaustion`], the /// recommended way of doing this is to pass a `limit` that only bounds `count`, as the /// `size` limit can always be overwritten. + #[pallet::call_index(1)] #[pallet::weight( // the migration process Pallet::::dynamic_weight(limits.item, * real_size_upper) @@ -648,6 +650,7 @@ pub mod pallet { /// /// This does not affect the global migration process tracker ([`MigrationProcess`]), and /// should only be used in case any keys are leftover due to a bug. + #[pallet::call_index(2)] #[pallet::weight( T::WeightInfo::migrate_custom_top_success() .max(T::WeightInfo::migrate_custom_top_fail()) @@ -704,6 +707,7 @@ pub mod pallet { /// /// This does not affect the global migration process tracker ([`MigrationProcess`]), and /// should only be used in case any keys are leftover due to a bug. + #[pallet::call_index(3)] #[pallet::weight( T::WeightInfo::migrate_custom_child_success() .max(T::WeightInfo::migrate_custom_child_fail()) @@ -764,6 +768,7 @@ pub mod pallet { } /// Set the maximum limit of the signed migration. + #[pallet::call_index(4)] #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] pub fn set_signed_max_limits( origin: OriginFor, @@ -783,6 +788,7 @@ pub mod pallet { /// /// In case you mess things up, you can also, in principle, use this to reset the migration /// process. + #[pallet::call_index(5)] #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] pub fn force_set_progress( origin: OriginFor, diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index c18ced8911193..0867f24b1691e 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -148,6 +148,7 @@ pub mod pallet { /// - One DB write (event). /// - Weight of derivative `call` execution + 10,000. /// # + #[pallet::call_index(0)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); (dispatch_info.weight, dispatch_info.class) @@ -176,6 +177,7 @@ pub mod pallet { /// - O(1). /// - The weight of this call is defined by the caller. /// # + #[pallet::call_index(1)] #[pallet::weight((*_weight, call.get_dispatch_info().class))] pub fn sudo_unchecked_weight( origin: OriginFor, @@ -202,6 +204,7 @@ pub mod pallet { /// - Limited storage reads. /// - One DB change. /// # + #[pallet::call_index(2)] #[pallet::weight(0)] pub fn set_key( origin: OriginFor, @@ -229,6 +232,7 @@ pub mod pallet { /// - One DB write (event). /// - Weight of derivative `call` execution + 10,000. /// # + #[pallet::call_index(3)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index db2ad4d563910..639e81ceaa308 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -49,6 +49,7 @@ pub mod logger { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(*weight)] pub fn privileged_i32_log( origin: OriginFor, @@ -62,6 +63,7 @@ pub mod logger { Ok(().into()) } + #[pallet::call_index(1)] #[pallet::weight(*weight)] pub fn non_privileged_log( origin: OriginFor, diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 0fd32dad2242a..c0376d5aa450f 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -192,6 +192,7 @@ pub mod pallet { T::AccountId: From + From + SomeAssociation1, { /// Doc comment put in metadata + #[pallet::call_index(0)] #[pallet::weight(Weight::from_ref_time(*_foo as u64))] pub fn foo( origin: OriginFor, @@ -206,6 +207,7 @@ pub mod pallet { } /// Doc comment put in metadata + #[pallet::call_index(1)] #[pallet::weight(1)] pub fn foo_storage_layer( _origin: OriginFor, @@ -220,6 +222,7 @@ pub mod pallet { } // Test for DispatchResult return type + #[pallet::call_index(2)] #[pallet::weight(1)] pub fn foo_no_post_info(_origin: OriginFor) -> DispatchResult { Ok(()) diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index 398137d644ee4..300fb9a40cf4e 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -141,6 +141,7 @@ pub mod pallet { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(>::into(new_value.clone()))] pub fn set_dummy( origin: OriginFor, diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index e8b5fe9fa33d4..79370d911b943 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -127,6 +127,7 @@ pub mod pallet { #[pallet::call] impl, I: 'static> Pallet { + #[pallet::call_index(0)] #[pallet::weight(>::into(new_value.clone()))] pub fn set_dummy( origin: OriginFor, diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 7e05e2ecf783b..d8ad13ceda1dd 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -82,6 +82,7 @@ pub mod pallet { #[pallet::call] impl, I: 'static> Pallet { /// Doc comment put in metadata + #[pallet::call_index(0)] #[pallet::weight(Weight::from_ref_time(*_foo as u64))] pub fn foo( origin: OriginFor, @@ -93,6 +94,7 @@ pub mod pallet { } /// Doc comment put in metadata + #[pallet::call_index(1)] #[pallet::weight(1)] pub fn foo_storage_layer( origin: OriginFor, diff --git a/frame/support/test/tests/storage_layers.rs b/frame/support/test/tests/storage_layers.rs index 6fbbb8ac67bd7..cff81c0bea2ed 100644 --- a/frame/support/test/tests/storage_layers.rs +++ b/frame/support/test/tests/storage_layers.rs @@ -46,6 +46,7 @@ pub mod pallet { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(1)] pub fn set_value(_origin: OriginFor, value: u32) -> DispatchResult { Value::::put(value); diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index f7e3849beeb8d..b41083538a325 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -372,6 +372,7 @@ pub mod pallet { /// # /// - `O(1)` /// # + #[pallet::call_index(0)] #[pallet::weight(T::SystemWeightInfo::remark(_remark.len() as u32))] pub fn remark(origin: OriginFor, _remark: Vec) -> DispatchResultWithPostInfo { ensure_signed_or_root(origin)?; @@ -379,6 +380,7 @@ pub mod pallet { } /// Set the number of pages in the WebAssembly environment's heap. + #[pallet::call_index(1)] #[pallet::weight((T::SystemWeightInfo::set_heap_pages(), DispatchClass::Operational))] pub fn set_heap_pages(origin: OriginFor, pages: u64) -> DispatchResultWithPostInfo { ensure_root(origin)?; @@ -399,6 +401,7 @@ pub mod pallet { /// The weight of this function is dependent on the runtime, but generally this is very /// expensive. We will treat this as a full block. /// # + #[pallet::call_index(2)] #[pallet::weight((T::BlockWeights::get().max_block, DispatchClass::Operational))] pub fn set_code(origin: OriginFor, code: Vec) -> DispatchResultWithPostInfo { ensure_root(origin)?; @@ -416,6 +419,7 @@ pub mod pallet { /// - 1 event. /// The weight of this function is dependent on the runtime. We will treat this as a full /// block. # + #[pallet::call_index(3)] #[pallet::weight((T::BlockWeights::get().max_block, DispatchClass::Operational))] pub fn set_code_without_checks( origin: OriginFor, @@ -427,6 +431,7 @@ pub mod pallet { } /// Set some items of storage. + #[pallet::call_index(4)] #[pallet::weight(( T::SystemWeightInfo::set_storage(items.len() as u32), DispatchClass::Operational, @@ -443,6 +448,7 @@ pub mod pallet { } /// Kill some items from storage. + #[pallet::call_index(5)] #[pallet::weight(( T::SystemWeightInfo::kill_storage(keys.len() as u32), DispatchClass::Operational, @@ -459,6 +465,7 @@ pub mod pallet { /// /// **NOTE:** We rely on the Root origin to provide us the number of subkeys under /// the prefix we are removing to accurately calculate the weight of this function. + #[pallet::call_index(6)] #[pallet::weight(( T::SystemWeightInfo::kill_prefix(_subkeys.saturating_add(1)), DispatchClass::Operational, @@ -474,6 +481,7 @@ pub mod pallet { } /// Make some on-chain remark and emit event. + #[pallet::call_index(7)] #[pallet::weight(T::SystemWeightInfo::remark_with_event(remark.len() as u32))] pub fn remark_with_event( origin: OriginFor, diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index 6a7f849d1329a..e859474c2cb9e 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -198,6 +198,7 @@ pub mod pallet { /// `on_finalize`) /// - 1 event handler `on_timestamp_set`. Must be `O(1)`. /// # + #[pallet::call_index(0)] #[pallet::weight(( T::WeightInfo::set(), DispatchClass::Mandatory diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index 9313a26e52e00..dd9ebc9813233 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -235,6 +235,7 @@ pub mod pallet { /// - DbReads: `Reasons`, `Tips` /// - DbWrites: `Reasons`, `Tips` /// # + #[pallet::call_index(0)] #[pallet::weight(>::WeightInfo::report_awesome(reason.len() as u32))] pub fn report_awesome( origin: OriginFor, @@ -292,6 +293,7 @@ pub mod pallet { /// - DbReads: `Tips`, `origin account` /// - DbWrites: `Reasons`, `Tips`, `origin account` /// # + #[pallet::call_index(1)] #[pallet::weight(>::WeightInfo::retract_tip())] pub fn retract_tip(origin: OriginFor, hash: T::Hash) -> DispatchResult { let who = ensure_signed(origin)?; @@ -330,6 +332,7 @@ pub mod pallet { /// - DbReads: `Tippers`, `Reasons` /// - DbWrites: `Reasons`, `Tips` /// # + #[pallet::call_index(2)] #[pallet::weight(>::WeightInfo::tip_new(reason.len() as u32, T::Tippers::max_len() as u32))] pub fn tip_new( origin: OriginFor, @@ -384,6 +387,7 @@ pub mod pallet { /// - DbReads: `Tippers`, `Tips` /// - DbWrites: `Tips` /// # + #[pallet::call_index(3)] #[pallet::weight(>::WeightInfo::tip(T::Tippers::max_len() as u32))] pub fn tip( origin: OriginFor, @@ -417,6 +421,7 @@ pub mod pallet { /// - DbReads: `Tips`, `Tippers`, `tip finder` /// - DbWrites: `Reasons`, `Tips`, `Tippers`, `tip finder` /// # + #[pallet::call_index(4)] #[pallet::weight(>::WeightInfo::close_tip(T::Tippers::max_len() as u32))] pub fn close_tip(origin: OriginFor, hash: T::Hash) -> DispatchResult { ensure_signed(origin)?; @@ -443,6 +448,7 @@ pub mod pallet { /// `T` is charged as upper bound given by `ContainsLengthBound`. /// The actual cost depends on the implementation of `T::Tippers`. /// # + #[pallet::call_index(5)] #[pallet::weight(>::WeightInfo::slash_tip(T::Tippers::max_len() as u32))] pub fn slash_tip(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::RejectOrigin::ensure_origin(origin)?; diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index 07144c5617113..cda7610efdf87 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -188,6 +188,7 @@ pub mod pallet { /// - n*log(n) of data size, as all data is pushed to an in-memory trie. /// Additionally contains a DB write. /// # + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::store(data.len() as u32))] pub fn store(origin: OriginFor, data: Vec) -> DispatchResult { ensure!(data.len() > 0, Error::::EmptyTransaction); @@ -236,6 +237,7 @@ pub mod pallet { /// # /// - Constant. /// # + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::renew())] pub fn renew( origin: OriginFor, @@ -281,6 +283,7 @@ pub mod pallet { /// There's a DB read for each transaction. /// Here we assume a maximum of 100 probed transactions. /// # + #[pallet::call_index(2)] #[pallet::weight((T::WeightInfo::check_proof_max(), DispatchClass::Mandatory))] pub fn check_proof( origin: OriginFor, diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 4aa00c348585c..0ffc53d8b7978 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -350,6 +350,7 @@ pub mod pallet { /// - DbReads: `ProposalCount`, `origin account` /// - DbWrites: `ProposalCount`, `Proposals`, `origin account` /// # + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::propose_spend())] pub fn propose_spend( origin: OriginFor, @@ -380,6 +381,7 @@ pub mod pallet { /// - DbReads: `Proposals`, `rejected proposer account` /// - DbWrites: `Proposals`, `rejected proposer account` /// # + #[pallet::call_index(1)] #[pallet::weight((T::WeightInfo::reject_proposal(), DispatchClass::Operational))] pub fn reject_proposal( origin: OriginFor, @@ -410,6 +412,7 @@ pub mod pallet { /// - DbReads: `Proposals`, `Approvals` /// - DbWrite: `Approvals` /// # + #[pallet::call_index(2)] #[pallet::weight((T::WeightInfo::approve_proposal(T::MaxApprovals::get()), DispatchClass::Operational))] pub fn approve_proposal( origin: OriginFor, @@ -431,6 +434,7 @@ pub mod pallet { /// /// NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the /// beneficiary. + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::spend())] pub fn spend( origin: OriginFor, @@ -472,6 +476,7 @@ pub mod pallet { /// - `ProposalNotApproved`: The `proposal_id` supplied was not found in the approval queue, /// i.e., the proposal has not been approved. This could also mean the proposal does not /// exist altogether, thus there is no way it would have been approved in the first place. + #[pallet::call_index(4)] #[pallet::weight((T::WeightInfo::remove_approval(), DispatchClass::Operational))] pub fn remove_approval( origin: OriginFor, diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 185d8fc0c8edd..8157817d4166e 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -449,6 +449,7 @@ pub mod pallet { /// Emits `Created` event when successful. /// /// Weight: `O(1)` + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::create())] pub fn create( origin: OriginFor, @@ -485,6 +486,7 @@ pub mod pallet { /// Emits `ForceCreated` event when successful. /// /// Weight: `O(1)` + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::force_create())] pub fn force_create( origin: OriginFor, @@ -520,6 +522,7 @@ pub mod pallet { /// - `n = witness.items` /// - `m = witness.item_metadatas` /// - `a = witness.attributes` + #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::destroy( witness.items, witness.item_metadatas, @@ -555,6 +558,7 @@ pub mod pallet { /// Emits `Issued` event when successful. /// /// Weight: `O(1)` + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::mint())] pub fn mint( origin: OriginFor, @@ -584,6 +588,7 @@ pub mod pallet { /// /// Weight: `O(1)` /// Modes: `check_owner.is_some()`. + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::burn())] pub fn burn( origin: OriginFor, @@ -622,6 +627,7 @@ pub mod pallet { /// Emits `Transferred`. /// /// Weight: `O(1)` + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( origin: OriginFor, @@ -658,6 +664,7 @@ pub mod pallet { /// is not permitted to call it. /// /// Weight: `O(items.len())` + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::redeposit(items.len() as u32))] pub fn redeposit( origin: OriginFor, @@ -718,6 +725,7 @@ pub mod pallet { /// Emits `Frozen`. /// /// Weight: `O(1)` + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::freeze())] pub fn freeze( origin: OriginFor, @@ -749,6 +757,7 @@ pub mod pallet { /// Emits `Thawed`. /// /// Weight: `O(1)` + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::thaw())] pub fn thaw( origin: OriginFor, @@ -779,6 +788,7 @@ pub mod pallet { /// Emits `CollectionFrozen`. /// /// Weight: `O(1)` + #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::freeze_collection())] pub fn freeze_collection( origin: OriginFor, @@ -806,6 +816,7 @@ pub mod pallet { /// Emits `CollectionThawed`. /// /// Weight: `O(1)` + #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::thaw_collection())] pub fn thaw_collection( origin: OriginFor, @@ -835,6 +846,7 @@ pub mod pallet { /// Emits `OwnerChanged`. /// /// Weight: `O(1)` + #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::transfer_ownership())] pub fn transfer_ownership( origin: OriginFor, @@ -883,6 +895,7 @@ pub mod pallet { /// Emits `TeamChanged`. /// /// Weight: `O(1)` + #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::set_team())] pub fn set_team( origin: OriginFor, @@ -923,6 +936,7 @@ pub mod pallet { /// Emits `ApprovedTransfer` on success. /// /// Weight: `O(1)` + #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::approve_transfer())] pub fn approve_transfer( origin: OriginFor, @@ -976,6 +990,7 @@ pub mod pallet { /// Emits `ApprovalCancelled` on success. /// /// Weight: `O(1)` + #[pallet::call_index(14)] #[pallet::weight(T::WeightInfo::cancel_approval())] pub fn cancel_approval( origin: OriginFor, @@ -1028,6 +1043,7 @@ pub mod pallet { /// Emits `ItemStatusChanged` with the identity of the item. /// /// Weight: `O(1)` + #[pallet::call_index(15)] #[pallet::weight(T::WeightInfo::force_item_status())] pub fn force_item_status( origin: OriginFor, @@ -1077,6 +1093,7 @@ pub mod pallet { /// Emits `AttributeSet`. /// /// Weight: `O(1)` + #[pallet::call_index(16)] #[pallet::weight(T::WeightInfo::set_attribute())] pub fn set_attribute( origin: OriginFor, @@ -1139,6 +1156,7 @@ pub mod pallet { /// Emits `AttributeCleared`. /// /// Weight: `O(1)` + #[pallet::call_index(17)] #[pallet::weight(T::WeightInfo::clear_attribute())] pub fn clear_attribute( origin: OriginFor, @@ -1188,6 +1206,7 @@ pub mod pallet { /// Emits `MetadataSet`. /// /// Weight: `O(1)` + #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::set_metadata())] pub fn set_metadata( origin: OriginFor, @@ -1250,6 +1269,7 @@ pub mod pallet { /// Emits `MetadataCleared`. /// /// Weight: `O(1)` + #[pallet::call_index(19)] #[pallet::weight(T::WeightInfo::clear_metadata())] pub fn clear_metadata( origin: OriginFor, @@ -1299,6 +1319,7 @@ pub mod pallet { /// Emits `CollectionMetadataSet`. /// /// Weight: `O(1)` + #[pallet::call_index(20)] #[pallet::weight(T::WeightInfo::set_collection_metadata())] pub fn set_collection_metadata( origin: OriginFor, @@ -1356,6 +1377,7 @@ pub mod pallet { /// Emits `CollectionMetadataCleared`. /// /// Weight: `O(1)` + #[pallet::call_index(21)] #[pallet::weight(T::WeightInfo::clear_collection_metadata())] pub fn clear_collection_metadata( origin: OriginFor, @@ -1392,6 +1414,7 @@ pub mod pallet { /// ownership transferal. /// /// Emits `OwnershipAcceptanceChanged`. + #[pallet::call_index(22)] #[pallet::weight(T::WeightInfo::set_accept_ownership())] pub fn set_accept_ownership( origin: OriginFor, @@ -1428,6 +1451,7 @@ pub mod pallet { /// - `max_supply`: The maximum amount of items a collection could have. /// /// Emits `CollectionMaxSupplySet` event when successful. + #[pallet::call_index(23)] #[pallet::weight(T::WeightInfo::set_collection_max_supply())] pub fn set_collection_max_supply( origin: OriginFor, @@ -1467,6 +1491,7 @@ pub mod pallet { /// /// Emits `ItemPriceSet` on success if the price is not `None`. /// Emits `ItemPriceRemoved` on success if the price is `None`. + #[pallet::call_index(24)] #[pallet::weight(T::WeightInfo::set_price())] pub fn set_price( origin: OriginFor, @@ -1489,6 +1514,7 @@ pub mod pallet { /// - `bid_price`: The price the sender is willing to pay. /// /// Emits `ItemBought` on success. + #[pallet::call_index(25)] #[pallet::weight(T::WeightInfo::buy_item())] #[transactional] pub fn buy_item( diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 00cb18e1b23aa..2d60ae15679d5 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -181,6 +181,7 @@ pub mod pallet { /// `BatchInterrupted` event is deposited, along with the number of successful calls made /// and the error of the failed call. If all were successful, then the `BatchCompleted` /// event is deposited. + #[pallet::call_index(0)] #[pallet::weight({ let dispatch_infos = calls.iter().map(|call| call.get_dispatch_info()).collect::>(); let dispatch_weight = dispatch_infos.iter() @@ -254,6 +255,7 @@ pub mod pallet { /// NOTE: Prior to version *12, this was called `as_limited_sub`. /// /// The dispatch origin for this call must be _Signed_. + #[pallet::call_index(1)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( @@ -302,6 +304,7 @@ pub mod pallet { /// # /// - Complexity: O(C) where C is the number of calls to be batched. /// # + #[pallet::call_index(2)] #[pallet::weight({ let dispatch_infos = calls.iter().map(|call| call.get_dispatch_info()).collect::>(); let dispatch_weight = dispatch_infos.iter() @@ -377,6 +380,7 @@ pub mod pallet { /// - One DB write (event). /// - Weight of derivative `call` execution + T::WeightInfo::dispatch_as(). /// # + #[pallet::call_index(3)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( @@ -414,6 +418,7 @@ pub mod pallet { /// # /// - Complexity: O(C) where C is the number of calls to be batched. /// # + #[pallet::call_index(4)] #[pallet::weight({ let dispatch_infos = calls.iter().map(|call| call.get_dispatch_info()).collect::>(); let dispatch_weight = dispatch_infos.iter() @@ -481,6 +486,7 @@ pub mod pallet { /// Root origin to specify the weight of the call. /// /// The dispatch origin for this call must be _Root_. + #[pallet::call_index(5)] #[pallet::weight((*_weight, call.get_dispatch_info().class))] pub fn with_weight( origin: OriginFor, diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index d48ce139d839c..f9d6a16c1a0d4 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -53,11 +53,13 @@ pub mod example { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(*_weight)] pub fn noop(_origin: OriginFor, _weight: Weight) -> DispatchResult { Ok(()) } + #[pallet::call_index(1)] #[pallet::weight(*_start_weight)] pub fn foobar( origin: OriginFor, @@ -78,6 +80,7 @@ pub mod example { } } + #[pallet::call_index(2)] #[pallet::weight(0)] pub fn big_variant(_origin: OriginFor, _arg: [u8; 400]) -> DispatchResult { Ok(()) @@ -105,6 +108,7 @@ mod mock_democracy { #[pallet::call] impl Pallet { + #[pallet::call_index(3)] #[pallet::weight(0)] pub fn external_propose_majority(origin: OriginFor) -> DispatchResult { T::ExternalMajorityOrigin::ensure_origin(origin)?; diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index a92f94baf6cf9..3439608af3ce4 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -303,6 +303,7 @@ pub mod pallet { /// - Reads: Vesting Storage, Balances Locks, [Sender Account] /// - Writes: Vesting Storage, Balances Locks, [Sender Account] /// # + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::vest_locked(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) .max(T::WeightInfo::vest_unlocked(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES)) )] @@ -326,6 +327,7 @@ pub mod pallet { /// - Reads: Vesting Storage, Balances Locks, Target Account /// - Writes: Vesting Storage, Balances Locks, Target Account /// # + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::vest_other_locked(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) .max(T::WeightInfo::vest_other_unlocked(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES)) )] @@ -352,6 +354,7 @@ pub mod pallet { /// - Reads: Vesting Storage, Balances Locks, Target Account, [Sender Account] /// - Writes: Vesting Storage, Balances Locks, Target Account, [Sender Account] /// # + #[pallet::call_index(2)] #[pallet::weight( T::WeightInfo::vested_transfer(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) )] @@ -383,6 +386,7 @@ pub mod pallet { /// - Reads: Vesting Storage, Balances Locks, Target Account, Source Account /// - Writes: Vesting Storage, Balances Locks, Target Account, Source Account /// # + #[pallet::call_index(3)] #[pallet::weight( T::WeightInfo::force_vested_transfer(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) )] @@ -417,6 +421,7 @@ pub mod pallet { /// /// - `schedule1_index`: index of the first schedule to merge. /// - `schedule2_index`: index of the second schedule to merge. + #[pallet::call_index(4)] #[pallet::weight( T::WeightInfo::not_unlocking_merge_schedules(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) .max(T::WeightInfo::unlocking_merge_schedules(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES)) diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index 1b2dc9415607e..8a5666331c7e9 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -119,6 +119,7 @@ pub mod pallet { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::whitelist_call())] pub fn whitelist_call(origin: OriginFor, call_hash: PreimageHash) -> DispatchResult { T::WhitelistOrigin::ensure_origin(origin)?; @@ -136,6 +137,7 @@ pub mod pallet { Ok(()) } + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::remove_whitelisted_call())] pub fn remove_whitelisted_call( origin: OriginFor, @@ -152,6 +154,7 @@ pub mod pallet { Ok(()) } + #[pallet::call_index(2)] #[pallet::weight( T::WeightInfo::dispatch_whitelisted_call(*call_encoded_len) .saturating_add(*call_weight_witness) @@ -190,6 +193,7 @@ pub mod pallet { Ok(actual_weight.into()) } + #[pallet::call_index(3)] #[pallet::weight({ let call_weight = call.get_dispatch_info().weight; let call_len = call.encoded_size() as u32; From f3c95e63ab92154a102aca61b6e5a206c7e3b32c Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Mon, 12 Dec 2022 16:22:47 +0100 Subject: [PATCH 1467/1472] Pin canonincalized block (#12902) --- client/state-db/src/noncanonical.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index df09a9c017747..7cb3017966b0f 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -38,6 +38,7 @@ pub struct NonCanonicalOverlay { // would be deleted but kept around because block is pinned, ref counted. pinned: HashMap, pinned_insertions: HashMap, u32)>, + last_canon_pinned: Option, } #[cfg_attr(test, derive(PartialEq, Debug))] @@ -225,6 +226,7 @@ impl NonCanonicalOverlay { pinned: Default::default(), pinned_insertions: Default::default(), values, + last_canon_pinned: None, }) } @@ -367,6 +369,16 @@ impl NonCanonicalOverlay { .position(|overlay| overlay.hash == *hash) .ok_or(StateDbError::InvalidBlock)?; + // No failures are possible beyond this point. + + // Unpin previously canonicalized block + if let Some(prev_hash) = self.last_canon_pinned.take() { + self.unpin(&prev_hash); + } + // Force pin canonicalized block so that it is no discarded immediately + self.pin(hash); + self.last_canon_pinned = Some(hash.clone()); + let mut discarded_journals = Vec::new(); let mut discarded_blocks = Vec::new(); for (i, overlay) in level.blocks.into_iter().enumerate() { @@ -680,6 +692,7 @@ mod tests { db.commit(&overlay.insert(&h2, 11, &h1, make_changeset(&[5], &[3])).unwrap()); let mut commit = CommitSet::default(); overlay.canonicalize(&h1, &mut commit).unwrap(); + overlay.unpin(&h1); db.commit(&commit); assert_eq!(overlay.levels.len(), 1); @@ -707,15 +720,16 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h1, &mut commit).unwrap(); db.commit(&commit); - assert!(!contains(&overlay, 5)); + assert!(contains(&overlay, 5)); assert!(contains(&overlay, 7)); assert_eq!(overlay.levels.len(), 1); - assert_eq!(overlay.parents.len(), 1); + assert_eq!(overlay.parents.len(), 2); let mut commit = CommitSet::default(); overlay.canonicalize(&h2, &mut commit).unwrap(); + assert!(!contains(&overlay, 5)); db.commit(&commit); assert_eq!(overlay.levels.len(), 0); - assert_eq!(overlay.parents.len(), 0); + assert_eq!(overlay.parents.len(), 1); assert!(db.data_eq(&make_db(&[1, 4, 6, 7, 8]))); } @@ -732,6 +746,8 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h_1, &mut commit).unwrap(); db.commit(&commit); + // explicitly unpin last block + overlay.unpin(&h_1); assert!(!contains(&overlay, 1)); } @@ -818,6 +834,8 @@ mod tests { // canonicalize 1. 2 and all its children should be discarded let mut commit = CommitSet::default(); overlay.canonicalize(&h_1, &mut commit).unwrap(); + // explicitly unpin last block + overlay.unpin(&h_1); db.commit(&commit); assert_eq!(overlay.levels.len(), 2); assert_eq!(overlay.parents.len(), 6); @@ -838,6 +856,7 @@ mod tests { // canonicalize 1_2. 1_1 and all its children should be discarded let mut commit = CommitSet::default(); overlay.canonicalize(&h_1_2, &mut commit).unwrap(); + overlay.unpin(&h_1_2); db.commit(&commit); assert_eq!(overlay.levels.len(), 1); assert_eq!(overlay.parents.len(), 3); @@ -854,6 +873,7 @@ mod tests { // canonicalize 1_2_2 let mut commit = CommitSet::default(); overlay.canonicalize(&h_1_2_2, &mut commit).unwrap(); + overlay.unpin(&h_1_2_2); db.commit(&commit); assert_eq!(overlay.levels.len(), 0); assert_eq!(overlay.parents.len(), 0); @@ -964,6 +984,7 @@ mod tests { assert!(contains(&overlay, 1)); overlay.unpin(&h_21); assert!(!contains(&overlay, 1)); + overlay.unpin(&h_12); assert!(overlay.pinned.is_empty()); } @@ -998,6 +1019,7 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h21, &mut commit).unwrap(); // h11 should stay in the DB + overlay.unpin(&h21); db.commit(&commit); assert!(!contains(&overlay, 21)); } From d4837cb5ede0c4a17a1aca8a72a48fbac11e9ef7 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 12 Dec 2022 17:05:13 +0000 Subject: [PATCH 1468/1472] Remove implicit approval chilling upon slash. (#12420) * don't read slashing spans when taking election snapshot * update cargo.toml * bring back remote test * fix merge stuff * fix npos-voters function sig * remove as much redundant diff as you can * Update frame/staking/src/pallet/mod.rs Co-authored-by: Andronik * fix * Update frame/staking/src/pallet/impls.rs * update lock * fix all tests * review comments * fmt * fix offence bench * clippy * ".git/.scripts/bench-bot.sh" pallet dev pallet_staking Co-authored-by: Andronik Co-authored-by: Ankan Co-authored-by: command-bot <> --- .../election-provider-multi-phase/src/lib.rs | 3 + frame/offences/benchmarking/src/lib.rs | 14 +- frame/staking/src/benchmarking.rs | 11 +- frame/staking/src/pallet/impls.rs | 37 +- frame/staking/src/pallet/mod.rs | 7 +- frame/staking/src/slashing.rs | 10 +- frame/staking/src/tests.rs | 330 +++++---- frame/staking/src/weights.rs | 631 +++++++++--------- utils/frame/remote-externalities/src/lib.rs | 29 +- 9 files changed, 526 insertions(+), 546 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 4704eaffa0bfe..6c4a55800f7e8 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -2293,6 +2293,8 @@ mod tests { assert_eq!(MultiPhase::elect().unwrap_err(), ElectionError::Fallback("NoFallback.")); // phase is now emergency. assert_eq!(MultiPhase::current_phase(), Phase::Emergency); + // snapshot is still there until election finalizes. + assert!(MultiPhase::snapshot().is_some()); assert_eq!( multi_phase_events(), @@ -2318,6 +2320,7 @@ mod tests { // phase is now emergency. assert_eq!(MultiPhase::current_phase(), Phase::Emergency); assert!(MultiPhase::queued_solution().is_none()); + assert!(MultiPhase::snapshot().is_some()); // no single account can trigger this assert_noop!( diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 555ec42882ee1..e5ec2952f8114 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -308,17 +308,20 @@ benchmarks! { let slash_amount = slash_fraction * bond_amount; let reward_amount = slash_amount.saturating_mul(1 + n) / 2; let reward = reward_amount / r; + let slash_report = |id| core::iter::once( + ::RuntimeEvent::from(StakingEvent::::SlashReported{ validator: id, fraction: slash_fraction, slash_era: 0}) + ); let slash = |id| core::iter::once( - ::RuntimeEvent::from(StakingEvent::::Slashed{staker: id, amount: BalanceOf::::from(slash_amount)}) + ::RuntimeEvent::from(StakingEvent::::Slashed{ staker: id, amount: BalanceOf::::from(slash_amount) }) ); let balance_slash = |id| core::iter::once( - ::RuntimeEvent::from(pallet_balances::Event::::Slashed{who: id, amount: slash_amount.into()}) + ::RuntimeEvent::from(pallet_balances::Event::::Slashed{ who: id, amount: slash_amount.into() }) ); let chill = |id| core::iter::once( - ::RuntimeEvent::from(StakingEvent::::Chilled{stash: id}) + ::RuntimeEvent::from(StakingEvent::::Chilled{ stash: id }) ); let balance_deposit = |id, amount: u32| - ::RuntimeEvent::from(pallet_balances::Event::::Deposit{who: id, amount: amount.into()}); + ::RuntimeEvent::from(pallet_balances::Event::::Deposit{ who: id, amount: amount.into() }); let mut first = true; let slash_events = raw_offenders.into_iter() .flat_map(|offender| { @@ -328,6 +331,7 @@ benchmarks! { }); let mut events = chill(offender.stash.clone()).map(Into::into) + .chain(slash_report(offender.stash.clone()).map(Into::into)) .chain(balance_slash(offender.stash.clone()).map(Into::into)) .chain(slash(offender.stash).map(Into::into)) .chain(nom_slashes) @@ -407,6 +411,7 @@ benchmarks! { System::::event_count(), 0 + 1 // offence + 3 // reporter (reward + endowment) + + 1 // offenders reported + 2 // offenders slashed + 1 // offenders chilled + 2 * n // nominators slashed @@ -443,6 +448,7 @@ benchmarks! { System::::event_count(), 0 + 1 // offence + 3 // reporter (reward + endowment) + + 1 // offenders reported + 2 // offenders slashed + 1 // offenders chilled + 2 * n // nominators slashed diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index dcb861e2ce419..8409b5413f992 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -792,12 +792,10 @@ benchmarks! { } get_npos_voters { - // number of validator intention. + // number of validator intention. we will iterate all of them. let v in (MaxValidators::::get() / 2) .. MaxValidators::::get(); - // number of nominator intention. + // number of nominator intention. we will iterate all of them. let n in (MaxNominators::::get() / 2) .. MaxNominators::::get(); - // total number of slashing spans. Assigned to validators randomly. - let s in 1 .. 20; let validators = create_validators_with_nominators_for_era::( v, n, T::MaxNominations::get() as usize, false, None @@ -806,9 +804,8 @@ benchmarks! { .map(|v| T::Lookup::lookup(v).unwrap()) .collect::>(); - (0..s).for_each(|index| { - add_slashing_spans::(&validators[index as usize], 10); - }); + assert_eq!(Validators::::count(), v); + assert_eq!(Nominators::::count(), n); let num_voters = (v + n) as usize; }: { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index c22a2bd2d1f77..6729a2ca32ecc 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -40,7 +40,7 @@ use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, EraIndex, SessionIndex, Stake, StakingInterface, }; -use sp_std::{collections::btree_map::BTreeMap, prelude::*}; +use sp_std::prelude::*; use crate::{ log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf, @@ -351,6 +351,7 @@ impl Pallet { } } + /// Start a new era. It does: /// /// * Increment `active_era.index`, /// * reset `active_era.start`, @@ -704,11 +705,6 @@ impl Pallet { /// `maybe_max_len` can imposes a cap on the number of voters returned; /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. - /// - /// ### Slashing - /// - /// All votes that have been submitted before the last non-zero slash of the corresponding - /// target are *auto-chilled*, but still count towards the limit imposed by `maybe_max_len`. pub fn get_npos_voters(maybe_max_len: Option) -> Vec> { let max_allowed_len = { let all_voter_count = T::VoterList::count() as usize; @@ -719,7 +715,6 @@ impl Pallet { // cache a few things. let weight_of = Self::weight_of_fn(); - let slashing_spans = >::iter().collect::>(); let mut voters_seen = 0u32; let mut validators_taken = 0u32; @@ -737,18 +732,12 @@ impl Pallet { None => break, }; - if let Some(Nominations { submitted_in, mut targets, suppressed: _ }) = - >::get(&voter) - { - // if this voter is a nominator: - targets.retain(|stash| { - slashing_spans - .get(stash) - .map_or(true, |spans| submitted_in >= spans.last_nonzero_slash()) - }); - if !targets.len().is_zero() { + if let Some(Nominations { targets, .. }) = >::get(&voter) { + if !targets.is_empty() { all_voters.push((voter.clone(), weight_of(&voter), targets)); nominators_taken.saturating_inc(); + } else { + // Technically should never happen, but not much we can do about it. } } else if Validators::::contains_key(&voter) { // if this voter is a validator: @@ -771,18 +760,14 @@ impl Pallet { warn, "DEFENSIVE: invalid item in `VoterList`: {:?}, this nominator probably has too many nominations now", voter - ) + ); } } // all_voters should have not re-allocated. debug_assert!(all_voters.capacity() == max_allowed_len); - Self::register_weight(T::WeightInfo::get_npos_voters( - validators_taken, - nominators_taken, - slashing_spans.len() as u32, - )); + Self::register_weight(T::WeightInfo::get_npos_voters(validators_taken, nominators_taken)); log!( info, @@ -1285,6 +1270,12 @@ where disable_strategy, }); + Self::deposit_event(Event::::SlashReported { + validator: stash.clone(), + fraction: *slash_fraction, + slash_era, + }); + if let Some(mut unapplied) = unapplied { let nominators_len = unapplied.others.len() as u64; let reporters_len = details.reporters.len() as u64; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 9dc39dd4a2116..fda455ca3c166 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -517,7 +517,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn slashing_spans)] #[pallet::unbounded] - pub(crate) type SlashingSpans = + pub type SlashingSpans = StorageMap<_, Twox64Concat, T::AccountId, slashing::SlashingSpans>; /// Records information about the maximum slash of a stash within a slashing span, @@ -671,8 +671,11 @@ pub mod pallet { EraPaid { era_index: EraIndex, validator_payout: BalanceOf, remainder: BalanceOf }, /// The nominator has been rewarded by this amount. Rewarded { stash: T::AccountId, amount: BalanceOf }, - /// One staker (and potentially its nominators) has been slashed by the given amount. + /// A staker (validator or nominator) has been slashed by the given amount. Slashed { staker: T::AccountId, amount: BalanceOf }, + /// A slash for the given validator, for the given percentage of their stake, at the given + /// era as been reported. + SlashReported { validator: T::AccountId, fraction: Perbill, slash_era: EraIndex }, /// An old slashing report from a prior era was discarded because it could /// not be processed. OldSlashingReportDiscarded { session_index: SessionIndex }, diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index a1900136d64fd..aeea0a1a58c63 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -239,9 +239,9 @@ pub(crate) fn compute_slash( return None } - let (prior_slash_p, _era_slash) = + let prior_slash_p = as Store>::ValidatorSlashInEra::get(¶ms.slash_era, params.stash) - .unwrap_or((Perbill::zero(), Zero::zero())); + .map_or(Zero::zero(), |(prior_slash_proportion, _)| prior_slash_proportion); // compare slash proportions rather than slash values to avoid issues due to rounding // error. @@ -390,9 +390,7 @@ fn slash_nominators( let mut era_slash = as Store>::NominatorSlashInEra::get(¶ms.slash_era, stash) .unwrap_or_else(Zero::zero); - era_slash += own_slash_difference; - as Store>::NominatorSlashInEra::insert(¶ms.slash_era, stash, &era_slash); era_slash @@ -411,12 +409,10 @@ fn slash_nominators( let target_span = spans.compare_and_update_span_slash(params.slash_era, era_slash); if target_span == Some(spans.span_index()) { - // End the span, but don't chill the nominator. its nomination - // on this validator will be ignored in the future. + // end the span, but don't chill the nominator. spans.end_span(params.now); } } - nominators_slashed.push((stash.clone(), nom_slashed)); } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 78429122d00f1..3e0a62f53d886 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2845,6 +2845,8 @@ fn deferred_slashes_are_deferred() { assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; + System::reset_events(); + on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), @@ -2853,6 +2855,9 @@ fn deferred_slashes_are_deferred() { &[Perbill::from_percent(10)], ); + // nominations are not removed regardless of the deferring. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); @@ -2866,8 +2871,6 @@ fn deferred_slashes_are_deferred() { assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); - System::reset_events(); - // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. mock::start_active_era(4); @@ -2875,15 +2878,16 @@ fn deferred_slashes_are_deferred() { assert_eq!(Balances::free_balance(11), 900); assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); - assert_eq!( - staking_events_since_last_call(), - vec![ - Event::StakersElected, - Event::EraPaid { era_index: 3, validator_payout: 11075, remainder: 33225 }, + assert!(matches!( + staking_events_since_last_call().as_slice(), + &[ + Event::Chilled { stash: 11 }, + Event::SlashReported { validator: 11, slash_era: 1, .. }, + .., Event::Slashed { staker: 11, amount: 100 }, Event::Slashed { staker: 101, amount: 12 } ] - ); + )); }) } @@ -2896,25 +2900,29 @@ fn retroactive_deferred_slashes_two_eras_before() { let exposure_11_at_era1 = Staking::eras_stakers(active_era(), 11); mock::start_active_era(3); + + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + + System::reset_events(); on_offence_in_era( &[OffenceDetails { offender: (11, exposure_11_at_era1), reporters: vec![] }], &[Perbill::from_percent(10)], 1, // should be deferred for two full eras, and applied at the beginning of era 4. DisableStrategy::Never, ); - System::reset_events(); mock::start_active_era(4); - assert_eq!( - staking_events_since_last_call(), - vec![ - Event::StakersElected, - Event::EraPaid { era_index: 3, validator_payout: 7100, remainder: 21300 }, + assert!(matches!( + staking_events_since_last_call().as_slice(), + &[ + Event::Chilled { stash: 11 }, + Event::SlashReported { validator: 11, slash_era: 1, .. }, + .., Event::Slashed { staker: 11, amount: 100 }, - Event::Slashed { staker: 101, amount: 12 }, + Event::Slashed { staker: 101, amount: 12 } ] - ); + )); }) } @@ -2932,35 +2940,29 @@ fn retroactive_deferred_slashes_one_before() { assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 100)); mock::start_active_era(3); + System::reset_events(); on_offence_in_era( &[OffenceDetails { offender: (11, exposure_11_at_era1), reporters: vec![] }], &[Perbill::from_percent(10)], 2, // should be deferred for two full eras, and applied at the beginning of era 5. DisableStrategy::Never, ); - System::reset_events(); mock::start_active_era(4); - assert_eq!( - staking_events_since_last_call(), - vec![ - Event::StakersElected, - Event::EraPaid { era_index: 3, validator_payout: 11075, remainder: 33225 } - ] - ); assert_eq!(Staking::ledger(10).unwrap().total, 1000); // slash happens after the next line. + mock::start_active_era(5); - assert_eq!( - staking_events_since_last_call(), - vec![ - Event::StakersElected, - Event::EraPaid { era_index: 4, validator_payout: 11075, remainder: 33225 }, + assert!(matches!( + staking_events_since_last_call().as_slice(), + &[ + Event::SlashReported { validator: 11, slash_era: 2, .. }, + .., Event::Slashed { staker: 11, amount: 100 }, Event::Slashed { staker: 101, amount: 12 } ] - ); + )); // their ledger has already been slashed. assert_eq!(Staking::ledger(10).unwrap().total, 900); @@ -3068,6 +3070,7 @@ fn remove_deferred() { mock::start_active_era(2); // reported later, but deferred to start of era 4 as well. + System::reset_events(); on_offence_in_era( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], &[Perbill::from_percent(15)], @@ -3094,19 +3097,18 @@ fn remove_deferred() { // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. - System::reset_events(); mock::start_active_era(4); - // the first slash for 10% was cancelled, but the 15% one - assert_eq!( - staking_events_since_last_call(), - vec![ - Event::StakersElected, - Event::EraPaid { era_index: 3, validator_payout: 11075, remainder: 33225 }, + // the first slash for 10% was cancelled, but the 15% one not. + assert!(matches!( + staking_events_since_last_call().as_slice(), + &[ + Event::SlashReported { validator: 11, slash_era: 1, .. }, + .., Event::Slashed { staker: 11, amount: 50 }, Event::Slashed { staker: 101, amount: 7 } ] - ); + )); let slash_10 = Perbill::from_percent(10); let slash_15 = Perbill::from_percent(15); @@ -3196,6 +3198,9 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); + // 100 has approval for 11 as of now + assert!(Staking::nominators(101).unwrap().targets.contains(&11)); + // 11 and 21 both have the support of 100 let exposure_11 = Staking::eras_stakers(active_era(), &11); let exposure_21 = Staking::eras_stakers(active_era(), &21); @@ -3208,23 +3213,29 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid &[Perbill::from_percent(10)], ); + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, + Event::Chilled { stash: 11 }, + Event::SlashReported { + validator: 11, + fraction: Perbill::from_percent(10), + slash_era: 1 + }, + Event::Slashed { staker: 11, amount: 100 }, + Event::Slashed { staker: 101, amount: 12 }, + ] + ); + // post-slash balance let nominator_slash_amount_11 = 125 / 10; assert_eq!(Balances::free_balance(11), 900); assert_eq!(Balances::free_balance(101), 2000 - nominator_slash_amount_11); - // This is the best way to check that the validator was chilled; `get` will - // return default value. - for (stash, _) in ::Validators::iter() { - assert!(stash != 11); - } - - let nominations = ::Nominators::get(&101).unwrap(); - - // and make sure that the vote will be ignored even if the validator - // re-registers. - let last_slash = ::SlashingSpans::get(&11).unwrap().last_nonzero_slash(); - assert!(nominations.submitted_in < last_slash); + // check that validator was chilled. + assert!(::Validators::iter().all(|(stash, _)| stash != 11)); // actually re-bond the slashed validator assert_ok!(Staking::validate(RuntimeOrigin::signed(10), Default::default())); @@ -3233,11 +3244,12 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid let exposure_11 = Staking::eras_stakers(active_era(), &11); let exposure_21 = Staking::eras_stakers(active_era(), &21); - // 10 is re-elected, but without the support of 100 - assert_eq!(exposure_11.total, 900); - - // 20 is re-elected, with the (almost) entire support of 100 - assert_eq!(exposure_21.total, 1000 + 500 - nominator_slash_amount_11); + // 11's own expo is reduced. sum of support from 11 is less (448), which is 500 + // 900 + 146 + assert!(matches!(exposure_11, Exposure { own: 900, total: 1046, .. })); + // 1000 + 342 + assert!(matches!(exposure_21, Exposure { own: 1000, total: 1342, .. })); + assert_eq!(500 - 146 - 342, nominator_slash_amount_11); }); } @@ -3256,12 +3268,40 @@ fn non_slashable_offence_doesnt_disable_validator() { &[Perbill::zero()], ); + // it does NOT affect the nominator. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + // offence that slashes 25% of the bond on_offence_now( &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], &[Perbill::from_percent(25)], ); + // it DOES NOT affect the nominator. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, + Event::Chilled { stash: 11 }, + Event::SlashReported { + validator: 11, + fraction: Perbill::from_percent(0), + slash_era: 1 + }, + Event::Chilled { stash: 21 }, + Event::SlashReported { + validator: 21, + fraction: Perbill::from_percent(25), + slash_era: 1 + }, + Event::Slashed { staker: 21, amount: 250 }, + Event::Slashed { staker: 101, amount: 94 } + ] + ); + // the offence for validator 10 wasn't slashable so it wasn't disabled assert!(!is_disabled(10)); // whereas validator 20 gets disabled @@ -3288,6 +3328,9 @@ fn slashing_independent_of_disabling_validator() { DisableStrategy::Always, ); + // nomination remains untouched. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + // offence that slashes 25% of the bond, BUT not disabling on_offence_in_era( &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], @@ -3296,6 +3339,31 @@ fn slashing_independent_of_disabling_validator() { DisableStrategy::Never, ); + // nomination remains untouched. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, + Event::Chilled { stash: 11 }, + Event::SlashReported { + validator: 11, + fraction: Perbill::from_percent(0), + slash_era: 1 + }, + Event::Chilled { stash: 21 }, + Event::SlashReported { + validator: 21, + fraction: Perbill::from_percent(25), + slash_era: 1 + }, + Event::Slashed { staker: 21, amount: 250 }, + Event::Slashed { staker: 101, amount: 94 } + ] + ); + // the offence for validator 10 was explicitly disabled assert!(is_disabled(10)); // whereas validator 20 is explicitly not disabled @@ -3370,6 +3438,9 @@ fn disabled_validators_are_kept_disabled_for_whole_era() { &[Perbill::from_percent(25)], ); + // nominations are not updated. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + // validator 10 should not be disabled since the offence wasn't slashable assert!(!is_disabled(10)); // validator 20 gets disabled since it got slashed @@ -3387,6 +3458,9 @@ fn disabled_validators_are_kept_disabled_for_whole_era() { &[Perbill::from_percent(25)], ); + // nominations are not updated. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + advance_session(); // and both are disabled in the last session of the era @@ -3503,18 +3577,10 @@ fn zero_slash_keeps_nominators() { assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); - // This is the best way to check that the validator was chilled; `get` will - // return default value. - for (stash, _) in ::Validators::iter() { - assert!(stash != 11); - } - - let nominations = ::Nominators::get(&101).unwrap(); - - // and make sure that the vote will not be ignored, because the slash was - // zero. - let last_slash = ::SlashingSpans::get(&11).unwrap().last_nonzero_slash(); - assert!(nominations.submitted_in >= last_slash); + // 11 is still removed.. + assert!(::Validators::iter().all(|(stash, _)| stash != 11)); + // but their nominations are kept. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); }); } @@ -4380,15 +4446,14 @@ mod election_data_provider { // we assume a network only wants up to 1000 validators in most cases, thus having 2000 // candidates is as high as it gets. let validators = 2000; - // we assume the worse case: each validator also has a slashing span. - let slashing_spans = validators; let mut nominators = 1000; - while ::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) - .all_lt(Weight::from_parts( + while ::WeightInfo::get_npos_voters(validators, nominators).all_lt( + Weight::from_parts( 2u64 * frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, u64::MAX, - )) { + ), + ) { nominators += 1; } @@ -4410,49 +4475,6 @@ mod election_data_provider { }) } - #[test] - fn voters_exclude_slashed() { - ExtBuilder::default().build_and_execute(|| { - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); - assert_eq!( - ::electing_voters(None) - .unwrap() - .iter() - .find(|x| x.0 == 101) - .unwrap() - .2, - vec![11, 21] - ); - - start_active_era(1); - add_slash(&11); - - // 11 is gone. - start_active_era(2); - assert_eq!( - ::electing_voters(None) - .unwrap() - .iter() - .find(|x| x.0 == 101) - .unwrap() - .2, - vec![21] - ); - - // resubmit and it is back - assert_ok!(Staking::nominate(RuntimeOrigin::signed(100), vec![11, 21])); - assert_eq!( - ::electing_voters(None) - .unwrap() - .iter() - .find(|x| x.0 == 101) - .unwrap() - .2, - vec![11, 21] - ); - }) - } - #[test] fn respects_snapshot_len_limits() { ExtBuilder::default() @@ -4489,10 +4511,26 @@ mod election_data_provider { fn only_iterates_max_2_times_max_allowed_len() { ExtBuilder::default() .nominate(false) - // the other nominators only nominate 21 - .add_staker(61, 60, 2_000, StakerStatus::::Nominator(vec![21])) - .add_staker(71, 70, 2_000, StakerStatus::::Nominator(vec![21])) - .add_staker(81, 80, 2_000, StakerStatus::::Nominator(vec![21])) + // the best way to invalidate a bunch of nominators is to have them nominate a lot of + // ppl, but then lower the MaxNomination limit. + .add_staker( + 61, + 60, + 2_000, + StakerStatus::::Nominator(vec![21, 22, 23, 24, 25]), + ) + .add_staker( + 71, + 70, + 2_000, + StakerStatus::::Nominator(vec![21, 22, 23, 24, 25]), + ) + .add_staker( + 81, + 80, + 2_000, + StakerStatus::::Nominator(vec![21, 22, 23, 24, 25]), + ) .build_and_execute(|| { // all voters ordered by stake, assert_eq!( @@ -4500,10 +4538,7 @@ mod election_data_provider { vec![61, 71, 81, 11, 21, 31] ); - run_to_block(25); - - // slash 21, the only validator nominated by our first 3 nominators - add_slash(&21); + MaxNominations::set(2); // we want 2 voters now, and in maximum we allow 4 iterations. This is what happens: // 61 is pruned; @@ -4523,55 +4558,6 @@ mod election_data_provider { }); } - // Even if some of the higher staked nominators are slashed, we still get up to max len voters - // by adding more lower staked nominators. In other words, we assert that we keep on adding - // valid nominators until we reach max len voters; which is opposed to simply stopping after we - // have iterated max len voters, but not adding all of them to voters due to some nominators not - // having valid targets. - #[test] - fn get_max_len_voters_even_if_some_nominators_are_slashed() { - ExtBuilder::default() - .nominate(false) - .add_staker(61, 60, 20, StakerStatus::::Nominator(vec![21])) - .add_staker(71, 70, 10, StakerStatus::::Nominator(vec![11, 21])) - .add_staker(81, 80, 10, StakerStatus::::Nominator(vec![11, 21])) - .build_and_execute(|| { - // given our voters ordered by stake, - assert_eq!( - ::VoterList::iter().collect::>(), - vec![11, 21, 31, 61, 71, 81] - ); - - // we take 4 voters - assert_eq!( - Staking::electing_voters(Some(4)) - .unwrap() - .iter() - .map(|(stash, _, _)| stash) - .copied() - .collect::>(), - vec![11, 21, 31, 61], - ); - - // roll to session 5 - run_to_block(25); - - // slash 21, the only validator nominated by 61. - add_slash(&21); - - // we take 4 voters; 71 and 81 are replacing the ejected ones. - assert_eq!( - Staking::electing_voters(Some(4)) - .unwrap() - .iter() - .map(|(stash, _, _)| stash) - .copied() - .collect::>(), - vec![11, 31, 71, 81], - ); - }); - } - #[test] fn estimate_next_election_works() { ExtBuilder::default().session_per_era(5).period(5).build_and_execute(|| { diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 56374ffbc4b62..21fc3d6f077bc 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,24 +18,25 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-12-12, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_staking // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/staking/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_staking +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/staking/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -70,7 +71,7 @@ pub trait WeightInfo { fn rebond(l: u32, ) -> Weight; fn reap_stash(s: u32, ) -> Weight; fn new_era(v: u32, n: u32, ) -> Weight; - fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight; + fn get_npos_voters(v: u32, n: u32, ) -> Weight; fn get_npos_targets(v: u32, ) -> Weight; fn set_staking_configs_all_set() -> Weight; fn set_staking_configs_all_remove() -> Weight; @@ -87,10 +88,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 53_097 nanoseconds. - Weight::from_ref_time(53_708_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Minimum execution time: 56_034 nanoseconds. + Weight::from_ref_time(56_646_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -98,10 +99,10 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListNodes (r:3 w:3) // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Minimum execution time: 92_199 nanoseconds. - Weight::from_ref_time(93_541_000 as u64) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().writes(7 as u64)) + // Minimum execution time: 94_354 nanoseconds. + Weight::from_ref_time(95_318_000) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Nominators (r:1 w:0) @@ -113,10 +114,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 98_227 nanoseconds. - Weight::from_ref_time(99_070_000 as u64) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(8 as u64)) + // Minimum execution time: 99_960 nanoseconds. + Weight::from_ref_time(101_022_000) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(8)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -124,12 +125,12 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 45_058 nanoseconds. - Weight::from_ref_time(46_592_713 as u64) - // Standard Error: 413 - .saturating_add(Weight::from_ref_time(63_036 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 45_819 nanoseconds. + Weight::from_ref_time(48_073_614) + // Standard Error: 1_410 + .saturating_add(Weight::from_ref_time(62_881).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -146,10 +147,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - // Minimum execution time: 86_087 nanoseconds. - Weight::from_ref_time(87_627_894 as u64) - .saturating_add(T::DbWeight::get().reads(13 as u64)) - .saturating_add(T::DbWeight::get().writes(11 as u64)) + // Minimum execution time: 86_035 nanoseconds. + Weight::from_ref_time(89_561_735) + .saturating_add(T::DbWeight::get().reads(13)) + .saturating_add(T::DbWeight::get().writes(11)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) @@ -163,22 +164,22 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 67_690 nanoseconds. - Weight::from_ref_time(68_348_000 as u64) - .saturating_add(T::DbWeight::get().reads(11 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + // Minimum execution time: 68_748 nanoseconds. + Weight::from_ref_time(69_285_000) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(5)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 43_512 nanoseconds. - Weight::from_ref_time(47_300_477 as u64) - // Standard Error: 11_609 - .saturating_add(Weight::from_ref_time(6_770_405 as u64).saturating_mul(k as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(k as u64))) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) + // Minimum execution time: 41_641 nanoseconds. + Weight::from_ref_time(48_919_231) + // Standard Error: 11_548 + .saturating_add(Weight::from_ref_time(6_901_201).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinNominatorBond (r:1 w:0) @@ -193,13 +194,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 74_296 nanoseconds. - Weight::from_ref_time(73_201_782 as u64) - // Standard Error: 5_007 - .saturating_add(Weight::from_ref_time(2_810_370 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + // Minimum execution time: 75_097 nanoseconds. + Weight::from_ref_time(74_052_497) + // Standard Error: 6_784 + .saturating_add(Weight::from_ref_time(2_842_146).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Validators (r:1 w:0) @@ -209,59 +210,59 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 66_605 nanoseconds. - Weight::from_ref_time(67_279_000 as u64) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + // Minimum execution time: 67_307 nanoseconds. + Weight::from_ref_time(67_838_000) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - // Minimum execution time: 18_897 nanoseconds. - Weight::from_ref_time(19_357_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 18_831 nanoseconds. + Weight::from_ref_time(19_047_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - // Minimum execution time: 26_509 nanoseconds. - Weight::from_ref_time(26_961_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 27_534 nanoseconds. + Weight::from_ref_time(27_806_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - // Minimum execution time: 5_025 nanoseconds. - Weight::from_ref_time(5_240_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_211 nanoseconds. + Weight::from_ref_time(5_372_000) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 5_107 nanoseconds. - Weight::from_ref_time(5_320_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_382 nanoseconds. + Weight::from_ref_time(5_654_000) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 5_094 nanoseconds. - Weight::from_ref_time(5_377_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_618 nanoseconds. + Weight::from_ref_time(5_714_000) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Minimum execution time: 5_219 nanoseconds. - Weight::from_ref_time(5_434_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_589 nanoseconds. + Weight::from_ref_time(5_776_000) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_122 nanoseconds. - Weight::from_ref_time(5_977_533 as u64) - // Standard Error: 34 - .saturating_add(Weight::from_ref_time(10_205 as u64).saturating_mul(v as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_541 nanoseconds. + Weight::from_ref_time(6_479_253) + // Standard Error: 49 + .saturating_add(Weight::from_ref_time(10_125).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) @@ -278,23 +279,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 80_216 nanoseconds. - Weight::from_ref_time(86_090_609 as u64) - // Standard Error: 2_006 - .saturating_add(Weight::from_ref_time(1_039_308 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(11 as u64)) - .saturating_add(T::DbWeight::get().writes(12 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + // Minimum execution time: 81_041 nanoseconds. + Weight::from_ref_time(88_526_481) + // Standard Error: 11_494 + .saturating_add(Weight::from_ref_time(1_095_933).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(12)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 92_034 nanoseconds. - Weight::from_ref_time(896_585_370 as u64) - // Standard Error: 58_231 - .saturating_add(Weight::from_ref_time(4_908_277 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 92_308 nanoseconds. + Weight::from_ref_time(900_351_007) + // Standard Error: 59_145 + .saturating_add(Weight::from_ref_time(4_944_988).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) @@ -307,14 +308,14 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 127_936 nanoseconds. - Weight::from_ref_time(184_556_084 as u64) - // Standard Error: 26_981 - .saturating_add(Weight::from_ref_time(21_786_304 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) + // Minimum execution time: 131_855 nanoseconds. + Weight::from_ref_time(197_412_779) + // Standard Error: 21_283 + .saturating_add(Weight::from_ref_time(22_093_758).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) @@ -328,14 +329,14 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 157_778 nanoseconds. - Weight::from_ref_time(223_306_359 as u64) - // Standard Error: 27_216 - .saturating_add(Weight::from_ref_time(30_612_663 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(10 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(n as u64))) + // Minimum execution time: 163_118 nanoseconds. + Weight::from_ref_time(229_356_697) + // Standard Error: 30_740 + .saturating_add(Weight::from_ref_time(31_575_360).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) @@ -345,12 +346,12 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 92_880 nanoseconds. - Weight::from_ref_time(94_434_663 as u64) - // Standard Error: 1_734 - .saturating_add(Weight::from_ref_time(34_453 as u64).saturating_mul(l as u64)) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().writes(8 as u64)) + // Minimum execution time: 94_048 nanoseconds. + Weight::from_ref_time(95_784_236) + // Standard Error: 2_313 + .saturating_add(Weight::from_ref_time(52_798).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(8)) } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) @@ -367,16 +368,15 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 92_334 nanoseconds. - Weight::from_ref_time(95_207_614 as u64) - // Standard Error: 1_822 - .saturating_add(Weight::from_ref_time(1_036_787 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(12 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + // Minimum execution time: 93_342 nanoseconds. + Weight::from_ref_time(95_756_184) + // Standard Error: 2_067 + .saturating_add(Weight::from_ref_time(1_090_785).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(12)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } // Storage: VoterList CounterForListNodes (r:1 w:0) - // Storage: Staking SlashingSpans (r:1 w:0) // Storage: VoterList ListBags (r:200 w:0) // Storage: VoterList ListNodes (r:101 w:0) // Storage: Staking Nominators (r:101 w:0) @@ -395,20 +395,19 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 535_169 nanoseconds. - Weight::from_ref_time(548_667_000 as u64) - // Standard Error: 1_759_252 - .saturating_add(Weight::from_ref_time(58_283_319 as u64).saturating_mul(v as u64)) - // Standard Error: 175_299 - .saturating_add(Weight::from_ref_time(13_578_512 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(207 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(v as u64))) - .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(v as u64))) + // Minimum execution time: 506_874 nanoseconds. + Weight::from_ref_time(507_798_000) + // Standard Error: 1_802_261 + .saturating_add(Weight::from_ref_time(59_874_736).saturating_mul(v.into())) + // Standard Error: 179_585 + .saturating_add(Weight::from_ref_time(13_668_574).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(206)) + .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) } // Storage: VoterList CounterForListNodes (r:1 w:0) - // Storage: Staking SlashingSpans (r:21 w:0) // Storage: VoterList ListBags (r:200 w:0) // Storage: VoterList ListNodes (r:1500 w:0) // Storage: Staking Nominators (r:1500 w:0) @@ -417,29 +416,27 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Ledger (r:1500 w:0) /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. - /// The range of component `s` is `[1, 20]`. - fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { - // Minimum execution time: 25_323_129 nanoseconds. - Weight::from_ref_time(25_471_672_000 as u64) - // Standard Error: 266_391 - .saturating_add(Weight::from_ref_time(6_665_504 as u64).saturating_mul(v as u64)) - // Standard Error: 266_391 - .saturating_add(Weight::from_ref_time(6_956_606 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(202 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(v as u64))) - .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + fn get_npos_voters(v: u32, n: u32, ) -> Weight { + // Minimum execution time: 24_634_585 nanoseconds. + Weight::from_ref_time(24_718_377_000) + // Standard Error: 324_839 + .saturating_add(Weight::from_ref_time(3_654_508).saturating_mul(v.into())) + // Standard Error: 324_839 + .saturating_add(Weight::from_ref_time(2_927_535).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(201)) + .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) } // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_905_036 nanoseconds. - Weight::from_ref_time(78_163_554 as u64) - // Standard Error: 23_723 - .saturating_add(Weight::from_ref_time(9_784_870 as u64).saturating_mul(v as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + // Minimum execution time: 4_805_490 nanoseconds. + Weight::from_ref_time(118_475_494) + // Standard Error: 26_332 + .saturating_add(Weight::from_ref_time(9_635_188).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -448,9 +445,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_096 nanoseconds. - Weight::from_ref_time(10_538_000 as u64) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + // Minimum execution time: 10_816 nanoseconds. + Weight::from_ref_time(11_242_000) + .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -459,9 +456,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_045 nanoseconds. - Weight::from_ref_time(9_379_000 as u64) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + // Minimum execution time: 9_581 nanoseconds. + Weight::from_ref_time(10_383_000) + .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) @@ -474,18 +471,18 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Minimum execution time: 81_457 nanoseconds. - Weight::from_ref_time(82_410_000 as u64) - .saturating_add(T::DbWeight::get().reads(11 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + // Minimum execution time: 83_669 nanoseconds. + Weight::from_ref_time(84_772_000) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 19_684 nanoseconds. - Weight::from_ref_time(20_059_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 20_553 nanoseconds. + Weight::from_ref_time(20_933_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } } @@ -497,10 +494,10 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 53_097 nanoseconds. - Weight::from_ref_time(53_708_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + // Minimum execution time: 56_034 nanoseconds. + Weight::from_ref_time(56_646_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -508,10 +505,10 @@ impl WeightInfo for () { // Storage: VoterList ListNodes (r:3 w:3) // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Minimum execution time: 92_199 nanoseconds. - Weight::from_ref_time(93_541_000 as u64) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) - .saturating_add(RocksDbWeight::get().writes(7 as u64)) + // Minimum execution time: 94_354 nanoseconds. + Weight::from_ref_time(95_318_000) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().writes(7)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking Nominators (r:1 w:0) @@ -523,10 +520,10 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 98_227 nanoseconds. - Weight::from_ref_time(99_070_000 as u64) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().writes(8 as u64)) + // Minimum execution time: 99_960 nanoseconds. + Weight::from_ref_time(101_022_000) + .saturating_add(RocksDbWeight::get().reads(12)) + .saturating_add(RocksDbWeight::get().writes(8)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -534,12 +531,12 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 45_058 nanoseconds. - Weight::from_ref_time(46_592_713 as u64) - // Standard Error: 413 - .saturating_add(Weight::from_ref_time(63_036 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 45_819 nanoseconds. + Weight::from_ref_time(48_073_614) + // Standard Error: 1_410 + .saturating_add(Weight::from_ref_time(62_881).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) @@ -556,10 +553,10 @@ impl WeightInfo for () { // Storage: Staking Payee (r:0 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - // Minimum execution time: 86_087 nanoseconds. - Weight::from_ref_time(87_627_894 as u64) - .saturating_add(RocksDbWeight::get().reads(13 as u64)) - .saturating_add(RocksDbWeight::get().writes(11 as u64)) + // Minimum execution time: 86_035 nanoseconds. + Weight::from_ref_time(89_561_735) + .saturating_add(RocksDbWeight::get().reads(13)) + .saturating_add(RocksDbWeight::get().writes(11)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) @@ -573,22 +570,22 @@ impl WeightInfo for () { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 67_690 nanoseconds. - Weight::from_ref_time(68_348_000 as u64) - .saturating_add(RocksDbWeight::get().reads(11 as u64)) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) + // Minimum execution time: 68_748 nanoseconds. + Weight::from_ref_time(69_285_000) + .saturating_add(RocksDbWeight::get().reads(11)) + .saturating_add(RocksDbWeight::get().writes(5)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 43_512 nanoseconds. - Weight::from_ref_time(47_300_477 as u64) - // Standard Error: 11_609 - .saturating_add(Weight::from_ref_time(6_770_405 as u64).saturating_mul(k as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(k as u64))) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) + // Minimum execution time: 41_641 nanoseconds. + Weight::from_ref_time(48_919_231) + // Standard Error: 11_548 + .saturating_add(Weight::from_ref_time(6_901_201).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinNominatorBond (r:1 w:0) @@ -603,13 +600,13 @@ impl WeightInfo for () { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 74_296 nanoseconds. - Weight::from_ref_time(73_201_782 as u64) - // Standard Error: 5_007 - .saturating_add(Weight::from_ref_time(2_810_370 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + // Minimum execution time: 75_097 nanoseconds. + Weight::from_ref_time(74_052_497) + // Standard Error: 6_784 + .saturating_add(Weight::from_ref_time(2_842_146).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(12)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Validators (r:1 w:0) @@ -619,59 +616,59 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 66_605 nanoseconds. - Weight::from_ref_time(67_279_000 as u64) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + // Minimum execution time: 67_307 nanoseconds. + Weight::from_ref_time(67_838_000) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - // Minimum execution time: 18_897 nanoseconds. - Weight::from_ref_time(19_357_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 18_831 nanoseconds. + Weight::from_ref_time(19_047_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - // Minimum execution time: 26_509 nanoseconds. - Weight::from_ref_time(26_961_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 27_534 nanoseconds. + Weight::from_ref_time(27_806_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - // Minimum execution time: 5_025 nanoseconds. - Weight::from_ref_time(5_240_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_211 nanoseconds. + Weight::from_ref_time(5_372_000) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 5_107 nanoseconds. - Weight::from_ref_time(5_320_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_382 nanoseconds. + Weight::from_ref_time(5_654_000) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 5_094 nanoseconds. - Weight::from_ref_time(5_377_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_618 nanoseconds. + Weight::from_ref_time(5_714_000) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Minimum execution time: 5_219 nanoseconds. - Weight::from_ref_time(5_434_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_589 nanoseconds. + Weight::from_ref_time(5_776_000) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_122 nanoseconds. - Weight::from_ref_time(5_977_533 as u64) - // Standard Error: 34 - .saturating_add(Weight::from_ref_time(10_205 as u64).saturating_mul(v as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_541 nanoseconds. + Weight::from_ref_time(6_479_253) + // Standard Error: 49 + .saturating_add(Weight::from_ref_time(10_125).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking SlashingSpans (r:1 w:0) @@ -688,23 +685,23 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 80_216 nanoseconds. - Weight::from_ref_time(86_090_609 as u64) - // Standard Error: 2_006 - .saturating_add(Weight::from_ref_time(1_039_308 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(11 as u64)) - .saturating_add(RocksDbWeight::get().writes(12 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + // Minimum execution time: 81_041 nanoseconds. + Weight::from_ref_time(88_526_481) + // Standard Error: 11_494 + .saturating_add(Weight::from_ref_time(1_095_933).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(11)) + .saturating_add(RocksDbWeight::get().writes(12)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) } // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 92_034 nanoseconds. - Weight::from_ref_time(896_585_370 as u64) - // Standard Error: 58_231 - .saturating_add(Weight::from_ref_time(4_908_277 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 92_308 nanoseconds. + Weight::from_ref_time(900_351_007) + // Standard Error: 59_145 + .saturating_add(Weight::from_ref_time(4_944_988).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) @@ -717,14 +714,14 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 127_936 nanoseconds. - Weight::from_ref_time(184_556_084 as u64) - // Standard Error: 26_981 - .saturating_add(Weight::from_ref_time(21_786_304 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(9 as u64)) - .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(n as u64))) + // Minimum execution time: 131_855 nanoseconds. + Weight::from_ref_time(197_412_779) + // Standard Error: 21_283 + .saturating_add(Weight::from_ref_time(22_093_758).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(9)) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(2)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) } // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) @@ -738,14 +735,14 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 157_778 nanoseconds. - Weight::from_ref_time(223_306_359 as u64) - // Standard Error: 27_216 - .saturating_add(Weight::from_ref_time(30_612_663 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(10 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(n as u64))) + // Minimum execution time: 163_118 nanoseconds. + Weight::from_ref_time(229_356_697) + // Standard Error: 30_740 + .saturating_add(Weight::from_ref_time(31_575_360).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(10)) + .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) @@ -755,12 +752,12 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 92_880 nanoseconds. - Weight::from_ref_time(94_434_663 as u64) - // Standard Error: 1_734 - .saturating_add(Weight::from_ref_time(34_453 as u64).saturating_mul(l as u64)) - .saturating_add(RocksDbWeight::get().reads(9 as u64)) - .saturating_add(RocksDbWeight::get().writes(8 as u64)) + // Minimum execution time: 94_048 nanoseconds. + Weight::from_ref_time(95_784_236) + // Standard Error: 2_313 + .saturating_add(Weight::from_ref_time(52_798).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(9)) + .saturating_add(RocksDbWeight::get().writes(8)) } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) @@ -777,16 +774,15 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 92_334 nanoseconds. - Weight::from_ref_time(95_207_614 as u64) - // Standard Error: 1_822 - .saturating_add(Weight::from_ref_time(1_036_787 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().writes(12 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + // Minimum execution time: 93_342 nanoseconds. + Weight::from_ref_time(95_756_184) + // Standard Error: 2_067 + .saturating_add(Weight::from_ref_time(1_090_785).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(12)) + .saturating_add(RocksDbWeight::get().writes(12)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) } // Storage: VoterList CounterForListNodes (r:1 w:0) - // Storage: Staking SlashingSpans (r:1 w:0) // Storage: VoterList ListBags (r:200 w:0) // Storage: VoterList ListNodes (r:101 w:0) // Storage: Staking Nominators (r:101 w:0) @@ -805,20 +801,19 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 535_169 nanoseconds. - Weight::from_ref_time(548_667_000 as u64) - // Standard Error: 1_759_252 - .saturating_add(Weight::from_ref_time(58_283_319 as u64).saturating_mul(v as u64)) - // Standard Error: 175_299 - .saturating_add(Weight::from_ref_time(13_578_512 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(207 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(v as u64))) - .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(v as u64))) + // Minimum execution time: 506_874 nanoseconds. + Weight::from_ref_time(507_798_000) + // Standard Error: 1_802_261 + .saturating_add(Weight::from_ref_time(59_874_736).saturating_mul(v.into())) + // Standard Error: 179_585 + .saturating_add(Weight::from_ref_time(13_668_574).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(206)) + .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) } // Storage: VoterList CounterForListNodes (r:1 w:0) - // Storage: Staking SlashingSpans (r:21 w:0) // Storage: VoterList ListBags (r:200 w:0) // Storage: VoterList ListNodes (r:1500 w:0) // Storage: Staking Nominators (r:1500 w:0) @@ -827,29 +822,27 @@ impl WeightInfo for () { // Storage: Staking Ledger (r:1500 w:0) /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. - /// The range of component `s` is `[1, 20]`. - fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { - // Minimum execution time: 25_323_129 nanoseconds. - Weight::from_ref_time(25_471_672_000 as u64) - // Standard Error: 266_391 - .saturating_add(Weight::from_ref_time(6_665_504 as u64).saturating_mul(v as u64)) - // Standard Error: 266_391 - .saturating_add(Weight::from_ref_time(6_956_606 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(202 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(v as u64))) - .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + fn get_npos_voters(v: u32, n: u32, ) -> Weight { + // Minimum execution time: 24_634_585 nanoseconds. + Weight::from_ref_time(24_718_377_000) + // Standard Error: 324_839 + .saturating_add(Weight::from_ref_time(3_654_508).saturating_mul(v.into())) + // Standard Error: 324_839 + .saturating_add(Weight::from_ref_time(2_927_535).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(201)) + .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) } // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_905_036 nanoseconds. - Weight::from_ref_time(78_163_554 as u64) - // Standard Error: 23_723 - .saturating_add(Weight::from_ref_time(9_784_870 as u64).saturating_mul(v as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + // Minimum execution time: 4_805_490 nanoseconds. + Weight::from_ref_time(118_475_494) + // Standard Error: 26_332 + .saturating_add(Weight::from_ref_time(9_635_188).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -858,9 +851,9 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_096 nanoseconds. - Weight::from_ref_time(10_538_000 as u64) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + // Minimum execution time: 10_816 nanoseconds. + Weight::from_ref_time(11_242_000) + .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -869,9 +862,9 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_045 nanoseconds. - Weight::from_ref_time(9_379_000 as u64) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + // Minimum execution time: 9_581 nanoseconds. + Weight::from_ref_time(10_383_000) + .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) @@ -884,17 +877,17 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Minimum execution time: 81_457 nanoseconds. - Weight::from_ref_time(82_410_000 as u64) - .saturating_add(RocksDbWeight::get().reads(11 as u64)) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + // Minimum execution time: 83_669 nanoseconds. + Weight::from_ref_time(84_772_000) + .saturating_add(RocksDbWeight::get().reads(11)) + .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 19_684 nanoseconds. - Weight::from_ref_time(20_059_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 20_553 nanoseconds. + Weight::from_ref_time(20_933_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } } diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 4f95331c03bc8..db062e246ceef 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -776,6 +776,8 @@ impl Builder { /// Inject a hashed prefix. This is treated as-is, and should be pre-hashed. /// + /// Only relevant is `Mode::Online` is being used. Noop otherwise. + /// /// This should be used to inject a "PREFIX", like a storage (double) map. pub fn inject_hashed_prefix(mut self, hashed: &[u8]) -> Self { self.hashed_prefixes.push(hashed.to_vec()); @@ -785,6 +787,8 @@ impl Builder { /// Just a utility wrapper of [`Self::inject_hashed_prefix`] that injects /// [`DEFAULT_CHILD_STORAGE_KEY_PREFIX`] as a prefix. /// + /// Only relevant is `Mode::Online` is being used. Noop otherwise. + /// /// If set, this will guarantee that the child-tree data of ALL pallets will be downloaded. /// /// This is not needed if the entire state is being downloaded. @@ -800,6 +804,8 @@ impl Builder { /// Inject a hashed key to scrape. This is treated as-is, and should be pre-hashed. /// + /// Only relevant is `Mode::Online` is being used. Noop otherwise. + /// /// This should be used to inject a "KEY", like a storage value. pub fn inject_hashed_key(mut self, hashed: &[u8]) -> Self { self.hashed_keys.push(hashed.to_vec()); @@ -951,7 +957,6 @@ mod tests { #[cfg(all(test, feature = "remote-test"))] mod remote_tests { use super::test_prelude::*; - const REMOTE_INACCESSIBLE: &'static str = "Can't reach the remote node. Is it running?"; #[tokio::test] async fn offline_else_online_works() { @@ -970,7 +975,7 @@ mod remote_tests { )) .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); // this shows that in the second run, we are not using the remote @@ -988,7 +993,7 @@ mod remote_tests { )) .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); let to_delete = std::fs::read_dir(Path::new(".")) @@ -1018,7 +1023,7 @@ mod remote_tests { })) .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); } @@ -1033,7 +1038,7 @@ mod remote_tests { })) .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); Builder::::new() @@ -1044,7 +1049,7 @@ mod remote_tests { })) .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); } @@ -1059,7 +1064,7 @@ mod remote_tests { })) .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); Builder::::new() @@ -1070,7 +1075,7 @@ mod remote_tests { })) .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); } @@ -1085,7 +1090,7 @@ mod remote_tests { })) .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); let to_delete = std::fs::read_dir(Path::new(".")) @@ -1126,7 +1131,7 @@ mod remote_tests { .inject_default_child_tree_prefix() .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); let to_delete = std::fs::read_dir(Path::new(".")) @@ -1164,7 +1169,7 @@ mod remote_tests { })) .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); let to_delete = std::fs::read_dir(Path::new(".")) @@ -1203,7 +1208,7 @@ mod remote_tests { })) .build() .await - .expect(REMOTE_INACCESSIBLE) + .unwrap() .execute_with(|| {}); } } From 2a0eeff4008573f6ead70eb9bd43cf6d268d2e7d Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Mon, 12 Dec 2022 23:20:21 +0100 Subject: [PATCH 1469/1472] bounties calls docs fix (#12909) Co-authored-by: parity-processbot <> --- frame/bounties/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index eb92c774f86e3..c3c2c08d24b2a 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -151,8 +151,7 @@ pub enum BountyStatus { Approved, /// The bounty is funded and waiting for curator assignment. Funded, - /// A curator has been proposed by the `ApproveOrigin`. Waiting for acceptance from the - /// curator. + /// A curator has been proposed. Waiting for acceptance from the curator. CuratorProposed { /// The assigned curator of this bounty. curator: AccountId, @@ -348,7 +347,7 @@ pub mod pallet { /// Approve a bounty proposal. At a later time, the bounty will be funded and become active /// and the original deposit will be returned. /// - /// May only be called from `T::ApproveOrigin`. + /// May only be called from `T::SpendOrigin`. /// /// # /// - O(1). @@ -380,7 +379,7 @@ pub mod pallet { /// Assign a curator to a funded bounty. /// - /// May only be called from `T::ApproveOrigin`. + /// May only be called from `T::SpendOrigin`. /// /// # /// - O(1). From 01efa856c6bb6fd120203afddd06c7b9719eddc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Pa=C4=8Dandi?= <3002868+Dinonard@users.noreply.github.com> Date: Tue, 13 Dec 2022 12:09:26 +0100 Subject: [PATCH 1470/1472] pallet-contracts migration pre-upgrade fix for v8 (#12905) * Only run pre-v8 migration check for versions older than 8 * Logix fix --- frame/contracts/src/migration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index aa04d8b9b1084..56d688abc7309 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -69,7 +69,7 @@ impl OnRuntimeUpgrade for Migration { fn pre_upgrade() -> Result, &'static str> { let version = >::on_chain_storage_version(); - if version == 8 { + if version == 7 { v8::pre_upgrade::()?; } From 13664c388d59b4c83dcb90a27700a9b68abe0305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Silva=20de=20Souza?= <77391175+joao-paulo-parity@users.noreply.github.com> Date: Tue, 13 Dec 2022 08:42:50 -0300 Subject: [PATCH 1471/1472] use custom environment for publishing crates (#12912) --- scripts/ci/gitlab/pipeline/publish.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 9053035a61cdb..381a1bc420ef3 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -211,6 +211,9 @@ update-node-template: # to roughly 202 minutes of delay, or 3h and 22 minutes. As such, the job needs to have a much # higher timeout than average. timeout: 5h + # A custom publishing environment is used for us to be able to set up protected secrets + # specifically for it + environment: publish-crates script: - rusty-cachier snapshot create - git clone From 93fa104fd4d4762c4d5c01257820bd3acf24a17b Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Tue, 13 Dec 2022 17:54:50 +0200 Subject: [PATCH 1472/1472] [contracts] Add debug buffer limit + enforcement (#12845) * Add debug buffer limit + enforcement Add debug buffer limit + enforcement * use BoundedVec for the debug buffer * revert schedule (debug buf len limit not needed anymore) * return DispatchError * addressed review comments --- bin/node/runtime/src/lib.rs | 1 + frame/contracts/src/exec.rs | 84 ++++++++++++++++++++++------- frame/contracts/src/lib.rs | 22 +++++--- frame/contracts/src/tests.rs | 1 + frame/contracts/src/wasm/mod.rs | 4 +- frame/contracts/src/wasm/runtime.rs | 4 +- 6 files changed, 86 insertions(+), 30 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 7cd42be73a19b..00d2a54d1e774 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1216,6 +1216,7 @@ impl pallet_contracts::Config for Runtime { type MaxCodeLen = ConstU32<{ 128 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; type UnsafeUnstableInterface = ConstBool; + type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; } impl pallet_sudo::Config for Runtime { diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index c0cf6a9f4c4c4..945095dc20329 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -18,8 +18,8 @@ use crate::{ gas::GasMeter, storage::{self, Storage, WriteOutcome}, - BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Determinism, Error, Event, Nonce, - Pallet as Contracts, Schedule, + BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, DebugBufferVec, Determinism, Error, + Event, Nonce, Pallet as Contracts, Schedule, }; use frame_support::{ crypto::ecdsa::ECDSAExt, @@ -279,7 +279,7 @@ pub trait Ext: sealing::Sealed { /// when the code is executing on-chain. /// /// Returns `true` if debug message recording is enabled. Otherwise `false` is returned. - fn append_debug_buffer(&mut self, msg: &str) -> bool; + fn append_debug_buffer(&mut self, msg: &str) -> Result; /// Call some dispatchable and return the result. fn call_runtime(&self, call: ::RuntimeCall) -> DispatchResultWithPostInfo; @@ -409,7 +409,7 @@ pub struct Stack<'a, T: Config, E> { /// /// All the bytes added to this field should be valid UTF-8. The buffer has no defined /// structure and is intended to be shown to users as-is for debugging purposes. - debug_message: Option<&'a mut Vec>, + debug_message: Option<&'a mut DebugBufferVec>, /// The determinism requirement of this call stack. determinism: Determinism, /// No executable is held by the struct but influences its behaviour. @@ -617,7 +617,7 @@ where schedule: &'a Schedule, value: BalanceOf, input_data: Vec, - debug_message: Option<&'a mut Vec>, + debug_message: Option<&'a mut DebugBufferVec>, determinism: Determinism, ) -> Result { let (mut stack, executable) = Self::new( @@ -652,7 +652,7 @@ where value: BalanceOf, input_data: Vec, salt: &[u8], - debug_message: Option<&'a mut Vec>, + debug_message: Option<&'a mut DebugBufferVec>, ) -> Result<(T::AccountId, ExecReturnValue), ExecError> { let (mut stack, executable) = Self::new( FrameArgs::Instantiate { @@ -681,7 +681,7 @@ where storage_meter: &'a mut storage::meter::Meter, schedule: &'a Schedule, value: BalanceOf, - debug_message: Option<&'a mut Vec>, + debug_message: Option<&'a mut DebugBufferVec>, determinism: Determinism, ) -> Result<(Self, E), ExecError> { let (first_frame, executable, nonce) = Self::new_frame( @@ -1328,14 +1328,16 @@ where &mut self.top_frame_mut().nested_gas } - fn append_debug_buffer(&mut self, msg: &str) -> bool { + fn append_debug_buffer(&mut self, msg: &str) -> Result { if let Some(buffer) = &mut self.debug_message { if !msg.is_empty() { - buffer.extend(msg.as_bytes()); + buffer + .try_extend(&mut msg.bytes()) + .map_err(|_| Error::::DebugBufferExhausted)?; } - true + Ok(true) } else { - false + Ok(false) } } @@ -2503,12 +2505,16 @@ mod tests { #[test] fn printing_works() { let code_hash = MockLoader::insert(Call, |ctx, _| { - ctx.ext.append_debug_buffer("This is a test"); - ctx.ext.append_debug_buffer("More text"); + ctx.ext + .append_debug_buffer("This is a test") + .expect("Maximum allowed debug buffer size exhausted!"); + ctx.ext + .append_debug_buffer("More text") + .expect("Maximum allowed debug buffer size exhausted!"); exec_success() }); - let mut debug_buffer = Vec::new(); + let mut debug_buffer = DebugBufferVec::::try_from(Vec::new()).unwrap(); ExtBuilder::default().build().execute_with(|| { let min_balance = ::Currency::minimum_balance(); @@ -2531,18 +2537,22 @@ mod tests { .unwrap(); }); - assert_eq!(&String::from_utf8(debug_buffer).unwrap(), "This is a testMore text"); + assert_eq!(&String::from_utf8(debug_buffer.to_vec()).unwrap(), "This is a testMore text"); } #[test] fn printing_works_on_fail() { let code_hash = MockLoader::insert(Call, |ctx, _| { - ctx.ext.append_debug_buffer("This is a test"); - ctx.ext.append_debug_buffer("More text"); + ctx.ext + .append_debug_buffer("This is a test") + .expect("Maximum allowed debug buffer size exhausted!"); + ctx.ext + .append_debug_buffer("More text") + .expect("Maximum allowed debug buffer size exhausted!"); exec_trapped() }); - let mut debug_buffer = Vec::new(); + let mut debug_buffer = DebugBufferVec::::try_from(Vec::new()).unwrap(); ExtBuilder::default().build().execute_with(|| { let min_balance = ::Currency::minimum_balance(); @@ -2565,7 +2575,43 @@ mod tests { assert!(result.is_err()); }); - assert_eq!(&String::from_utf8(debug_buffer).unwrap(), "This is a testMore text"); + assert_eq!(&String::from_utf8(debug_buffer.to_vec()).unwrap(), "This is a testMore text"); + } + + #[test] + fn debug_buffer_is_limited() { + let code_hash = MockLoader::insert(Call, move |ctx, _| { + ctx.ext.append_debug_buffer("overflowing bytes")?; + exec_success() + }); + + // Pre-fill the buffer up to its limit + let mut debug_buffer = + DebugBufferVec::::try_from(vec![0u8; DebugBufferVec::::bound()]).unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let schedule: Schedule = ::Schedule::get(); + let min_balance = ::Currency::minimum_balance(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + set_balance(&ALICE, min_balance * 10); + place_contract(&BOB, code_hash); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap(); + assert_err!( + MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + Some(&mut debug_buffer), + Determinism::Deterministic, + ) + .map_err(|e| e.error), + Error::::DebugBufferExhausted + ); + }); } #[test] diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 06d817785cc39..b76acf9d1db08 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -142,6 +142,7 @@ type BalanceOf = type CodeVec = BoundedVec::MaxCodeLen>; type RelaxedCodeVec = WeakBoundedVec::MaxCodeLen>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; +type DebugBufferVec = BoundedVec::MaxDebugBufferLen>; /// Used as a sentinel value when reading and writing contract memory. /// @@ -344,6 +345,10 @@ pub mod pallet { /// Do **not** set to `true` on productions chains. #[pallet::constant] type UnsafeUnstableInterface: Get; + + /// The maximum length of the debug buffer in bytes. + #[pallet::constant] + type MaxDebugBufferLen: Get; } #[pallet::hooks] @@ -863,6 +868,9 @@ pub mod pallet { CodeRejected, /// An indetermistic code was used in a context where this is not permitted. Indeterministic, + /// The debug buffer size used during contract execution exceeded the limit determined by + /// the `MaxDebugBufferLen` pallet config parameter. + DebugBufferExhausted, } /// A mapping from an original code hash to the original code, untouched by instrumentation. @@ -961,7 +969,7 @@ where debug: bool, determinism: Determinism, ) -> ContractExecResult> { - let mut debug_message = if debug { Some(Vec::new()) } else { None }; + let mut debug_message = if debug { Some(DebugBufferVec::::default()) } else { None }; let output = Self::internal_call( origin, dest, @@ -977,7 +985,7 @@ where gas_consumed: output.gas_meter.gas_consumed(), gas_required: output.gas_meter.gas_required(), storage_deposit: output.storage_deposit, - debug_message: debug_message.unwrap_or_default(), + debug_message: debug_message.unwrap_or_default().to_vec(), } } @@ -1003,7 +1011,7 @@ where salt: Vec, debug: bool, ) -> ContractInstantiateResult> { - let mut debug_message = if debug { Some(Vec::new()) } else { None }; + let mut debug_message = if debug { Some(DebugBufferVec::::default()) } else { None }; let output = Self::internal_instantiate( origin, value, @@ -1022,7 +1030,7 @@ where gas_consumed: output.gas_meter.gas_consumed(), gas_required: output.gas_meter.gas_required(), storage_deposit: output.storage_deposit, - debug_message: debug_message.unwrap_or_default(), + debug_message: debug_message.unwrap_or_default().to_vec(), } } @@ -1113,7 +1121,7 @@ where gas_limit: Weight, storage_deposit_limit: Option>, data: Vec, - debug_message: Option<&mut Vec>, + debug_message: Option<&mut DebugBufferVec>, determinism: Determinism, ) -> InternalCallOutput { let mut gas_meter = GasMeter::new(gas_limit); @@ -1156,7 +1164,7 @@ where code: Code>, data: Vec, salt: Vec, - mut debug_message: Option<&mut Vec>, + mut debug_message: Option<&mut DebugBufferVec>, ) -> InternalInstantiateOutput { let mut storage_deposit = Default::default(); let mut gas_meter = GasMeter::new(gas_limit); @@ -1172,7 +1180,7 @@ where TryInstantiate::Skip, ) .map_err(|(err, msg)| { - debug_message.as_mut().map(|buffer| buffer.extend(msg.as_bytes())); + debug_message.as_mut().map(|buffer| buffer.try_extend(&mut msg.bytes())); err })?; // The open deposit will be charged during execution when the diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index a467800dfe15b..6121d880ca8c5 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -415,6 +415,7 @@ impl Config for Test { type MaxCodeLen = ConstU32<{ 128 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; type UnsafeUnstableInterface = UnstableInterface; + type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; } pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index e9e6b42dc3f8a..d85dac95cc712 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -594,9 +594,9 @@ mod tests { fn gas_meter(&mut self) -> &mut GasMeter { &mut self.gas_meter } - fn append_debug_buffer(&mut self, msg: &str) -> bool { + fn append_debug_buffer(&mut self, msg: &str) -> Result { self.debug_buffer.extend(msg.as_bytes()); - true + Ok(true) } fn call_runtime( &self, diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index b933688eb61ec..50ad9996e6eb6 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -2395,11 +2395,11 @@ pub mod env { str_len: u32, ) -> Result { ctx.charge_gas(RuntimeCosts::DebugMessage)?; - if ctx.ext.append_debug_buffer("") { + if ctx.ext.append_debug_buffer("")? { let data = ctx.read_sandbox_memory(memory, str_ptr, str_len)?; let msg = core::str::from_utf8(&data).map_err(|_| >::DebugMessageInvalidUTF8)?; - ctx.ext.append_debug_buffer(msg); + ctx.ext.append_debug_buffer(msg)?; return Ok(ReturnCode::Success) } Ok(ReturnCode::LoggingDisabled)

(slot, epoch_data); expected_author.and_then(|p| { @@ -382,7 +382,7 @@ where body: Vec, storage_changes: StorageChanges<>::Transaction, B>, public: Self::Claim, - _epoch: Self::EpochData, + _epoch: Self::AuxData, ) -> Result< sc_consensus::BlockImportParams>::Transaction>, sp_consensus::Error, diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index aef4785b7bb81..109e5aade02a7 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -729,7 +729,6 @@ where BS: BackoffAuthoringBlocksStrategy> + Sync, Error: std::error::Error + Send + From + From + 'static, { - type EpochData = ViableEpochDescriptor, Epoch>; type Claim = (PreDigest, AuthorityId); type SyncOracle = SO; type JustificationSyncLink = L; @@ -737,6 +736,7 @@ where Pin> + Send + 'static>>; type Proposer = E::Proposer; type BlockImport = I; + type AuxData = ViableEpochDescriptor, Epoch>; fn logging_target(&self) -> &'static str { "babe" @@ -746,11 +746,7 @@ where &mut self.block_import } - fn epoch_data( - &self, - parent: &B::Header, - slot: Slot, - ) -> Result { + fn aux_data(&self, parent: &B::Header, slot: Slot) -> Result { self.epoch_changes .shared_data() .epoch_descriptor_for_child_of( @@ -763,7 +759,7 @@ where .ok_or(sp_consensus::Error::InvalidAuthoritiesSet) } - fn authorities_len(&self, epoch_descriptor: &Self::EpochData) -> Option { + fn authorities_len(&self, epoch_descriptor: &Self::AuxData) -> Option { self.epoch_changes .shared_data() .viable_epoch(epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) @@ -823,7 +819,7 @@ where body: Vec, storage_changes: StorageChanges<>::Transaction, B>, (_, public): Self::Claim, - epoch_descriptor: Self::EpochData, + epoch_descriptor: Self::AuxData, ) -> Result< sc_consensus::BlockImportParams>::Transaction>, sp_consensus::Error, diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 7c5d5d4a73bc1..6225bbbda1745 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -101,8 +101,8 @@ pub trait SimpleSlotWorker { /// Data associated with a slot claim. type Claim: Send + Sync + 'static; - /// Epoch data necessary for authoring. - type EpochData: Send + Sync + 'static; + /// Auxiliary data necessary for authoring. + type AuxData: Send + Sync + 'static; /// The logging target to use when logging messages. fn logging_target(&self) -> &'static str; @@ -110,29 +110,28 @@ pub trait SimpleSlotWorker { /// A handle to a `BlockImport`. fn block_import(&mut self) -> &mut Self::BlockImport; - /// Returns the epoch data necessary for authoring. For time-dependent epochs, - /// use the provided slot number as a canonical source of time. - fn epoch_data( + /// Returns the auxiliary data necessary for authoring. + fn aux_data( &self, header: &B::Header, slot: Slot, - ) -> Result; + ) -> Result; - /// Returns the number of authorities given the epoch data. + /// Returns the number of authorities. /// None indicate that the authorities information is incomplete. - fn authorities_len(&self, epoch_data: &Self::EpochData) -> Option; + fn authorities_len(&self, aux_data: &Self::AuxData) -> Option; /// Tries to claim the given slot, returning an object with claim data if successful. async fn claim_slot( &self, header: &B::Header, slot: Slot, - epoch_data: &Self::EpochData, + aux_data: &Self::AuxData, ) -> Option; /// Notifies the given slot. Similar to `claim_slot`, but will be called no matter whether we /// need to author blocks or not. - fn notify_slot(&self, _header: &B::Header, _slot: Slot, _epoch_data: &Self::EpochData) {} + fn notify_slot(&self, _header: &B::Header, _slot: Slot, _aux_data: &Self::AuxData) {} /// Return the pre digest data to include in a block authored with the given claim. fn pre_digest_data(&self, slot: Slot, claim: &Self::Claim) -> Vec; @@ -145,7 +144,7 @@ pub trait SimpleSlotWorker { body: Vec, storage_changes: StorageChanges<>::Transaction, B>, public: Self::Claim, - epoch: Self::EpochData, + epoch: Self::AuxData, ) -> Result< sc_consensus::BlockImportParams>::Transaction>, sp_consensus::Error, @@ -268,12 +267,12 @@ pub trait SimpleSlotWorker { Delay::new(proposing_remaining_duration) }; - let epoch_data = match self.epoch_data(&slot_info.chain_head, slot) { - Ok(epoch_data) => epoch_data, + let aux_data = match self.aux_data(&slot_info.chain_head, slot) { + Ok(aux_data) => aux_data, Err(err) => { warn!( target: logging_target, - "Unable to fetch epoch data at block {:?}: {}", + "Unable to fetch auxiliary data for block {:?}: {}", slot_info.chain_head.hash(), err, ); @@ -290,9 +289,9 @@ pub trait SimpleSlotWorker { }, }; - self.notify_slot(&slot_info.chain_head, slot, &epoch_data); + self.notify_slot(&slot_info.chain_head, slot, &aux_data); - let authorities_len = self.authorities_len(&epoch_data); + let authorities_len = self.authorities_len(&aux_data); if !self.force_authoring() && self.sync_oracle().is_offline() && @@ -309,7 +308,7 @@ pub trait SimpleSlotWorker { return None } - let claim = self.claim_slot(&slot_info.chain_head, slot, &epoch_data).await?; + let claim = self.claim_slot(&slot_info.chain_head, slot, &aux_data).await?; if self.should_backoff(slot, &slot_info.chain_head) { return None @@ -351,7 +350,7 @@ pub trait SimpleSlotWorker { body.clone(), proposal.storage_changes, claim, - epoch_data, + aux_data, ) .await { From 2a6c314cdce2b7813fbe2af2d21388ff5ededcbe Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Tue, 27 Sep 2022 13:44:20 +0200 Subject: [PATCH 1209/1472] Pallet staking events to named enum (#12342) * Pallet staking events to named enum * fmt * update np staking tests * update remaining events * update benchmarks * Update frame/nomination-pools/test-staking/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/staking/src/pallet/mod.rs * Update frame/staking/src/pallet/mod.rs * Update frame/staking/src/lib.rs * Update frame/staking/src/pallet/impls.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: parity-processbot <> Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- .../nomination-pools/test-staking/src/lib.rs | 109 ++++++++++++------ frame/offences/benchmarking/src/lib.rs | 4 +- frame/staking/src/lib.rs | 4 +- frame/staking/src/pallet/impls.rs | 26 +++-- frame/staking/src/pallet/mod.rs | 60 +++++----- frame/staking/src/slashing.rs | 5 +- frame/staking/src/tests.rs | 55 +++++---- 7 files changed, 165 insertions(+), 98 deletions(-) diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs index 7d848e98174b4..00e0e40ce33b0 100644 --- a/frame/nomination-pools/test-staking/src/lib.rs +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -41,7 +41,10 @@ fn pool_lifecycle_e2e() { // have the pool nominate. assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 50),]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -56,7 +59,10 @@ fn pool_lifecycle_e2e() { assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Bonded(POOL1_BONDED, 10), StakingEvent::Bonded(POOL1_BONDED, 10),] + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + ] ); assert_eq!( pool_events_since_last_call(), @@ -87,8 +93,8 @@ fn pool_lifecycle_e2e() { assert_eq!( staking_events_since_last_call(), vec![ - StakingEvent::Unbonded(POOL1_BONDED, 10), - StakingEvent::Unbonded(POOL1_BONDED, 10), + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, ] ); assert_eq!( @@ -131,7 +137,7 @@ fn pool_lifecycle_e2e() { assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Withdrawn(POOL1_BONDED, 20),] + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },] ); assert_eq!( pool_events_since_last_call(), @@ -155,7 +161,10 @@ fn pool_lifecycle_e2e() { assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Chilled(POOL1_BONDED), StakingEvent::Unbonded(POOL1_BONDED, 50),] + vec![ + StakingEvent::Chilled { stash: POOL1_BONDED }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, + ] ); assert_eq!( pool_events_since_last_call(), @@ -169,7 +178,7 @@ fn pool_lifecycle_e2e() { // pools is fully destroyed now. assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Withdrawn(POOL1_BONDED, 50),] + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] ); assert_eq!( pool_events_since_last_call(), @@ -193,7 +202,10 @@ fn pool_slash_e2e() { assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -210,7 +222,10 @@ fn pool_slash_e2e() { assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Bonded(POOL1_BONDED, 20), StakingEvent::Bonded(POOL1_BONDED, 20)] + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 } + ] ); assert_eq!( pool_events_since_last_call(), @@ -230,8 +245,8 @@ fn pool_slash_e2e() { assert_eq!( staking_events_since_last_call(), vec![ - StakingEvent::Unbonded(POOL1_BONDED, 10), - StakingEvent::Unbonded(POOL1_BONDED, 10) + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 } ] ); assert_eq!( @@ -253,9 +268,9 @@ fn pool_slash_e2e() { assert_eq!( staking_events_since_last_call(), vec![ - StakingEvent::Unbonded(POOL1_BONDED, 10), - StakingEvent::Unbonded(POOL1_BONDED, 10), - StakingEvent::Unbonded(POOL1_BONDED, 10), + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, ] ); @@ -278,7 +293,10 @@ fn pool_slash_e2e() { 2, // slash era 2, affects chunks at era 5 onwards. ); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 30)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -302,7 +320,10 @@ fn pool_slash_e2e() { unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5) } ); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Unbonded(POOL1_BONDED, 5)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }] + ); assert_eq!( pool_events_since_last_call(), vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5, era: 6 }] @@ -327,7 +348,7 @@ fn pool_slash_e2e() { assert_eq!( staking_events_since_last_call(), // a 10 (un-slashed) + 10/2 (slashed) balance from 10 has also been unlocked - vec![StakingEvent::Withdrawn(POOL1_BONDED, 15 + 10 + 15)] + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 + 10 + 15 }] ); // now, finally, we can unbond the depositor further than their current limit. @@ -336,7 +357,7 @@ fn pool_slash_e2e() { assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, 10)] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }] ); assert_eq!( pool_events_since_last_call(), @@ -361,7 +382,7 @@ fn pool_slash_e2e() { assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Withdrawn(POOL1_BONDED, 10)] + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }] ); assert_eq!( pool_events_since_last_call(), @@ -388,7 +409,10 @@ fn pool_slash_proportional() { assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -406,9 +430,9 @@ fn pool_slash_proportional() { assert_eq!( staking_events_since_last_call(), vec![ - StakingEvent::Bonded(POOL1_BONDED, bond), - StakingEvent::Bonded(POOL1_BONDED, bond), - StakingEvent::Bonded(POOL1_BONDED, bond), + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, ] ); assert_eq!( @@ -428,7 +452,7 @@ fn pool_slash_proportional() { assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] ); assert_eq!( pool_events_since_last_call(), @@ -445,7 +469,7 @@ fn pool_slash_proportional() { assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] ); assert_eq!( pool_events_since_last_call(), @@ -462,7 +486,7 @@ fn pool_slash_proportional() { assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] ); assert_eq!( pool_events_since_last_call(), @@ -486,7 +510,10 @@ fn pool_slash_proportional() { 100, ); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 50)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -517,7 +544,10 @@ fn pool_slash_non_proportional_only_bonded_pool() { // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -531,7 +561,7 @@ fn pool_slash_non_proportional_only_bonded_pool() { assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Bonded(POOL1_BONDED, bond)] + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] ); assert_eq!( pool_events_since_last_call(), @@ -543,7 +573,7 @@ fn pool_slash_non_proportional_only_bonded_pool() { assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, bond)] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] ); assert_eq!( pool_events_since_last_call(), @@ -567,7 +597,10 @@ fn pool_slash_non_proportional_only_bonded_pool() { 100, ); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 30)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] + ); assert_eq!( pool_events_since_last_call(), vec![PoolsEvent::PoolSlashed { pool_id: 1, balance: 10 }] @@ -590,7 +623,10 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -604,7 +640,7 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Bonded(POOL1_BONDED, bond)] + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] ); assert_eq!( pool_events_since_last_call(), @@ -616,7 +652,7 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, bond)] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] ); assert_eq!( pool_events_since_last_call(), @@ -640,7 +676,10 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { 100, ); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 50)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] + ); assert_eq!( pool_events_since_last_call(), vec![ diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index c9498214eade4..555ec42882ee1 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -309,13 +309,13 @@ benchmarks! { let reward_amount = slash_amount.saturating_mul(1 + n) / 2; let reward = reward_amount / r; let slash = |id| core::iter::once( - ::RuntimeEvent::from(StakingEvent::::Slashed(id, BalanceOf::::from(slash_amount))) + ::RuntimeEvent::from(StakingEvent::::Slashed{staker: id, amount: BalanceOf::::from(slash_amount)}) ); let balance_slash = |id| core::iter::once( ::RuntimeEvent::from(pallet_balances::Event::::Slashed{who: id, amount: slash_amount.into()}) ); let chill = |id| core::iter::once( - ::RuntimeEvent::from(StakingEvent::::Chilled(id)) + ::RuntimeEvent::from(StakingEvent::::Chilled{stash: id}) ); let balance_deposit = |id, amount: u32| ::RuntimeEvent::from(pallet_balances::Event::::Deposit{who: id, amount: amount.into()}); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index df568d6b596ba..eb30671d35a57 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -953,7 +953,9 @@ where if bonded_eras.first().filter(|(_, start)| offence_session >= *start).is_some() { R::report_offence(reporters, offence) } else { - >::deposit_event(Event::::OldSlashingReportDiscarded(offence_session)); + >::deposit_event(Event::::OldSlashingReportDiscarded { + session_index: offence_session, + }); Ok(()) } } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 399f50aaed865..6da27da362b53 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -181,14 +181,20 @@ impl Pallet { let validator_exposure_part = Perbill::from_rational(exposure.own, exposure.total); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; - Self::deposit_event(Event::::PayoutStarted(era, ledger.stash.clone())); + Self::deposit_event(Event::::PayoutStarted { + era_index: era, + validator_stash: ledger.stash.clone(), + }); let mut total_imbalance = PositiveImbalanceOf::::zero(); // We can now make total validator payout: if let Some(imbalance) = Self::make_payout(&ledger.stash, validator_staking_payout + validator_commission_payout) { - Self::deposit_event(Event::::Rewarded(ledger.stash, imbalance.peek())); + Self::deposit_event(Event::::Rewarded { + stash: ledger.stash, + amount: imbalance.peek(), + }); total_imbalance.subsume(imbalance); } @@ -208,7 +214,8 @@ impl Pallet { if let Some(imbalance) = Self::make_payout(&nominator.who, nominator_reward) { // Note: this logic does not count payouts for `RewardDestination::None`. nominator_payout_count += 1; - let e = Event::::Rewarded(nominator.who.clone(), imbalance.peek()); + let e = + Event::::Rewarded { stash: nominator.who.clone(), amount: imbalance.peek() }; Self::deposit_event(e); total_imbalance.subsume(imbalance); } @@ -232,7 +239,7 @@ impl Pallet { let chilled_as_validator = Self::do_remove_validator(stash); let chilled_as_nominator = Self::do_remove_nominator(stash); if chilled_as_validator || chilled_as_nominator { - Self::deposit_event(Event::::Chilled(stash.clone())); + Self::deposit_event(Event::::Chilled { stash: stash.clone() }); } } @@ -391,13 +398,18 @@ impl Pallet { let era_duration = (now_as_millis_u64 - active_era_start).saturated_into::(); let staked = Self::eras_total_stake(&active_era.index); let issuance = T::Currency::total_issuance(); - let (validator_payout, rest) = T::EraPayout::era_payout(staked, issuance, era_duration); + let (validator_payout, remainder) = + T::EraPayout::era_payout(staked, issuance, era_duration); - Self::deposit_event(Event::::EraPaid(active_era.index, validator_payout, rest)); + Self::deposit_event(Event::::EraPaid { + era_index: active_era.index, + validator_payout, + remainder, + }); // Set ending era reward. >::insert(&active_era.index, validator_payout); - T::RewardRemainder::on_unbalanced(T::Currency::issue(rest)); + T::RewardRemainder::on_unbalanced(T::Currency::issue(remainder)); // Clear offending validators. >::kill(); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 4db3870c62d8b..6e97697736223 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -653,39 +653,36 @@ pub mod pallet { pub enum Event { /// The era payout has been set; the first balance is the validator-payout; the second is /// the remainder from the maximum amount of reward. - /// \[era_index, validator_payout, remainder\] - EraPaid(EraIndex, BalanceOf, BalanceOf), - /// The nominator has been rewarded by this amount. \[stash, amount\] - Rewarded(T::AccountId, BalanceOf), + EraPaid { era_index: EraIndex, validator_payout: BalanceOf, remainder: BalanceOf }, + /// The nominator has been rewarded by this amount. + Rewarded { stash: T::AccountId, amount: BalanceOf }, /// One staker (and potentially its nominators) has been slashed by the given amount. - /// \[staker, amount\] - Slashed(T::AccountId, BalanceOf), + Slashed { staker: T::AccountId, amount: BalanceOf }, /// An old slashing report from a prior era was discarded because it could - /// not be processed. \[session_index\] - OldSlashingReportDiscarded(SessionIndex), + /// not be processed. + OldSlashingReportDiscarded { session_index: SessionIndex }, /// A new set of stakers was elected. StakersElected, /// An account has bonded this amount. \[stash, amount\] /// /// NOTE: This event is only emitted when funds are bonded via a dispatchable. Notably, /// it will not be emitted for staking rewards when they are added to stake. - Bonded(T::AccountId, BalanceOf), - /// An account has unbonded this amount. \[stash, amount\] - Unbonded(T::AccountId, BalanceOf), + Bonded { stash: T::AccountId, amount: BalanceOf }, + /// An account has unbonded this amount. + Unbonded { stash: T::AccountId, amount: BalanceOf }, /// An account has called `withdraw_unbonded` and removed unbonding chunks worth `Balance` - /// from the unlocking queue. \[stash, amount\] - Withdrawn(T::AccountId, BalanceOf), - /// A nominator has been kicked from a validator. \[nominator, stash\] - Kicked(T::AccountId, T::AccountId), + /// from the unlocking queue. + Withdrawn { stash: T::AccountId, amount: BalanceOf }, + /// A nominator has been kicked from a validator. + Kicked { nominator: T::AccountId, stash: T::AccountId }, /// The election failed. No new era is planned. StakingElectionFailed, /// An account has stopped participating as either a validator or nominator. - /// \[stash\] - Chilled(T::AccountId), - /// The stakers' rewards are getting paid. \[era_index, validator_stash\] - PayoutStarted(EraIndex, T::AccountId), + Chilled { stash: T::AccountId }, + /// The stakers' rewards are getting paid. + PayoutStarted { era_index: EraIndex, validator_stash: T::AccountId }, /// A validator has set their preferences. - ValidatorPrefsSet(T::AccountId, ValidatorPrefs), + ValidatorPrefsSet { stash: T::AccountId, prefs: ValidatorPrefs }, } #[pallet::error] @@ -850,7 +847,7 @@ pub mod pallet { let stash_balance = T::Currency::free_balance(&stash); let value = value.min(stash_balance); - Self::deposit_event(Event::::Bonded(stash.clone(), value)); + Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: value }); let item = StakingLedger { stash, total: value, @@ -911,7 +908,7 @@ pub mod pallet { T::VoterList::on_update(&stash, Self::weight_of(&ledger.stash)).defensive(); } - Self::deposit_event(Event::::Bonded(stash, extra)); + Self::deposit_event(Event::::Bonded { stash, amount: extra }); } Ok(()) } @@ -994,7 +991,7 @@ pub mod pallet { .defensive(); } - Self::deposit_event(Event::::Unbonded(ledger.stash, value)); + Self::deposit_event(Event::::Unbonded { stash: ledger.stash, amount: value }); } Ok(()) } @@ -1050,7 +1047,7 @@ pub mod pallet { if ledger.total < old_total { // Already checked that this won't overflow by entry condition. let value = old_total - ledger.total; - Self::deposit_event(Event::::Withdrawn(stash, value)); + Self::deposit_event(Event::::Withdrawn { stash, amount: value }); } Ok(post_info_weight.into()) @@ -1088,7 +1085,7 @@ pub mod pallet { Self::do_remove_nominator(stash); Self::do_add_validator(stash, prefs.clone()); - Self::deposit_event(Event::::ValidatorPrefsSet(ledger.stash, prefs)); + Self::deposit_event(Event::::ValidatorPrefsSet { stash: ledger.stash, prefs }); Ok(()) } @@ -1471,7 +1468,10 @@ pub mod pallet { // Last check: the new active amount of ledger must be more than ED. ensure!(ledger.active >= T::Currency::minimum_balance(), Error::::InsufficientBond); - Self::deposit_event(Event::::Bonded(ledger.stash.clone(), rebonded_value)); + Self::deposit_event(Event::::Bonded { + stash: ledger.stash.clone(), + amount: rebonded_value, + }); // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); @@ -1546,10 +1546,10 @@ pub mod pallet { if let Some(ref mut nom) = maybe_nom { if let Some(pos) = nom.targets.iter().position(|v| v == stash) { nom.targets.swap_remove(pos); - Self::deposit_event(Event::::Kicked( - nom_stash.clone(), - stash.clone(), - )); + Self::deposit_event(Event::::Kicked { + nominator: nom_stash.clone(), + stash: stash.clone(), + }); } } }); diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index f3272a25fab5c..a1900136d64fd 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -626,7 +626,10 @@ pub fn do_slash( >::update_ledger(&controller, &ledger); // trigger the event - >::deposit_event(super::Event::::Slashed(stash.clone(), value)); + >::deposit_event(super::Event::::Slashed { + staker: stash.clone(), + amount: value, + }); } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 6798a78030f9e..8ec98da99ecb1 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -303,7 +303,11 @@ fn rewards_should_work() { assert_eq!(mock::RewardRemainderUnbalanced::get(), maximum_payout - total_payout_0,); assert_eq!( *mock::staking_events().last().unwrap(), - Event::EraPaid(0, total_payout_0, maximum_payout - total_payout_0) + Event::EraPaid { + era_index: 0, + validator_payout: total_payout_0, + remainder: maximum_payout - total_payout_0 + } ); mock::make_all_reward_payment(0); @@ -341,7 +345,11 @@ fn rewards_should_work() { ); assert_eq!( *mock::staking_events().last().unwrap(), - Event::EraPaid(1, total_payout_1, maximum_payout - total_payout_1) + Event::EraPaid { + era_index: 1, + validator_payout: total_payout_1, + remainder: maximum_payout - total_payout_1 + } ); mock::make_all_reward_payment(1); @@ -1645,7 +1653,7 @@ fn rebond_emits_right_value_in_event() { }) ); // Event emitted should be correct - assert_eq!(*staking_events().last().unwrap(), Event::Bonded(11, 100)); + assert_eq!(*staking_events().last().unwrap(), Event::Bonded { stash: 11, amount: 100 }); // Re-bond way more than available Staking::rebond(RuntimeOrigin::signed(10), 100_000).unwrap(); @@ -1660,7 +1668,7 @@ fn rebond_emits_right_value_in_event() { }) ); // Event emitted should be correct, only 800 - assert_eq!(*staking_events().last().unwrap(), Event::Bonded(11, 800)); + assert_eq!(*staking_events().last().unwrap(), Event::Bonded { stash: 11, amount: 800 }); }); } @@ -2870,9 +2878,9 @@ fn deferred_slashes_are_deferred() { staking_events_since_last_call(), vec![ Event::StakersElected, - Event::EraPaid(3, 11075, 33225), - Event::Slashed(11, 100), - Event::Slashed(101, 12) + Event::EraPaid { era_index: 3, validator_payout: 11075, remainder: 33225 }, + Event::Slashed { staker: 11, amount: 100 }, + Event::Slashed { staker: 101, amount: 12 } ] ); }) @@ -2901,9 +2909,9 @@ fn retroactive_deferred_slashes_two_eras_before() { staking_events_since_last_call(), vec![ Event::StakersElected, - Event::EraPaid(3, 7100, 21300), - Event::Slashed(11, 100), - Event::Slashed(101, 12) + Event::EraPaid { era_index: 3, validator_payout: 7100, remainder: 21300 }, + Event::Slashed { staker: 11, amount: 100 }, + Event::Slashed { staker: 101, amount: 12 }, ] ); }) @@ -2934,7 +2942,10 @@ fn retroactive_deferred_slashes_one_before() { mock::start_active_era(4); assert_eq!( staking_events_since_last_call(), - vec![Event::StakersElected, Event::EraPaid(3, 11075, 33225)] + vec![ + Event::StakersElected, + Event::EraPaid { era_index: 3, validator_payout: 11075, remainder: 33225 } + ] ); assert_eq!(Staking::ledger(10).unwrap().total, 1000); @@ -2944,9 +2955,9 @@ fn retroactive_deferred_slashes_one_before() { staking_events_since_last_call(), vec![ Event::StakersElected, - Event::EraPaid(4, 11075, 33225), - Event::Slashed(11, 100), - Event::Slashed(101, 12) + Event::EraPaid { era_index: 4, validator_payout: 11075, remainder: 33225 }, + Event::Slashed { staker: 11, amount: 100 }, + Event::Slashed { staker: 101, amount: 12 } ] ); @@ -3090,9 +3101,9 @@ fn remove_deferred() { staking_events_since_last_call(), vec![ Event::StakersElected, - Event::EraPaid(3, 11075, 33225), - Event::Slashed(11, 50), - Event::Slashed(101, 7) + Event::EraPaid { era_index: 3, validator_payout: 11075, remainder: 33225 }, + Event::Slashed { staker: 11, amount: 50 }, + Event::Slashed { staker: 101, amount: 7 } ] ); @@ -4057,7 +4068,7 @@ fn offences_weight_calculated_correctly() { &one_offender, &[Perbill::from_percent(50)], 0, - DisableStrategy::WhenSlashed + DisableStrategy::WhenSlashed{} ), one_offence_unapplied_weight ); @@ -4955,10 +4966,10 @@ fn min_commission_works() { // event emitted should be correct assert_eq!( *staking_events().last().unwrap(), - Event::ValidatorPrefsSet( - 11, - ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } - ) + Event::ValidatorPrefsSet { + stash: 11, + prefs: ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } + } ); assert_ok!(Staking::set_staking_configs( From 74daaf1eb23686991a40c6cc361940421322472b Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Tue, 27 Sep 2022 17:44:16 +0200 Subject: [PATCH 1210/1472] [fix] Bound staking ledger correctly with MaxUnlockingChunks from configuration (#12343) * used maxunlockingchunks from config * mhl MaxUnlockingChunks * no migration needed * changes as per requested * fmt * fix tests * fix benchmark * warning in the doc for abrupt changes in the config * less unnecessary details in the test * fix tests Co-authored-by: mrisholukamba Co-authored-by: parity-processbot <> --- frame/staking/src/benchmarking.rs | 4 +- frame/staking/src/lib.rs | 7 +--- frame/staking/src/mock.rs | 3 +- frame/staking/src/pallet/mod.rs | 27 +++++++++----- frame/staking/src/tests.rs | 61 +++++++++++++++++++++++++++++-- 5 files changed, 80 insertions(+), 22 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 1ea05bba3b579..c7e6936ac75d8 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -613,7 +613,7 @@ benchmarks! { } rebond { - let l in 1 .. MaxUnlockingChunks::get() as u32; + let l in 1 .. T::MaxUnlockingChunks::get() as u32; // clean up any existing state. clear_validators_and_nominators::(); @@ -764,7 +764,7 @@ benchmarks! { #[extra] do_slash { - let l in 1 .. MaxUnlockingChunks::get() as u32; + let l in 1 .. T::MaxUnlockingChunks::get() as u32; let (stash, controller) = create_stash_controller::(0, 100, Default::default())?; let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); let unlock_chunk = UnlockChunk::> { diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index eb30671d35a57..a0144463540be 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -301,7 +301,6 @@ mod pallet; use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ - parameter_types, traits::{Currency, Defensive, Get}, weights::Weight, BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, @@ -349,10 +348,6 @@ type NegativeImbalanceOf = <::Currency as Currency< type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -parameter_types! { - pub MaxUnlockingChunks: u32 = 32; -} - /// Information regarding the active era (era in used in session). #[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ActiveEraInfo { @@ -465,7 +460,7 @@ pub struct StakingLedger { /// Any balance that is becoming free, which may eventually be transferred out of the stash /// (assuming it doesn't get slashed first). It is assumed that this will be treated as a first /// in, first out queue where the new (higher value) eras get pushed on the back. - pub unlocking: BoundedVec>, MaxUnlockingChunks>, + pub unlocking: BoundedVec>, T::MaxUnlockingChunks>, /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. pub claimed_rewards: BoundedVec, diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 385087f9bec41..3a9351ef4a271 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -237,6 +237,7 @@ parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub static MaxNominations: u32 = 16; pub static HistoryDepth: u32 = 80; + pub static MaxUnlockingChunks: u32 = 32; pub static RewardOnUnbalanceWasCalled: bool = false; pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); } @@ -301,7 +302,7 @@ impl crate::pallet::pallet::Config for Test { // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. type VoterList = VoterBagsList; type TargetList = UseValidatorsMap; - type MaxUnlockingChunks = ConstU32<32>; + type MaxUnlockingChunks = MaxUnlockingChunks; type HistoryDepth = HistoryDepth; type OnStakerSlash = OnStakerSlashMock; type BenchmarkingConfig = TestBenchmarkingConfig; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 6e97697736223..560c3b6ed830c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -43,9 +43,9 @@ pub use impls::*; use crate::{ slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout, - EraRewardPoints, Exposure, Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, - PositiveImbalanceOf, Releases, RewardDestination, SessionInterface, StakingLedger, - UnappliedSlash, UnlockChunk, ValidatorPrefs, + EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, + Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, + ValidatorPrefs, }; const STAKING_ID: LockIdentifier = *b"staking "; @@ -142,8 +142,9 @@ pub mod pallet { /// /// Note: `HistoryDepth` is used as the upper bound for the `BoundedVec` /// item `StakingLedger.claimed_rewards`. Setting this value lower than - /// the existing value can lead to inconsistencies and will need to be - /// handled properly in a migration. + /// the existing value can lead to inconsistencies in the + /// `StakingLedger` and will need to be handled properly in a migration. + /// The test `reducing_history_depth_abrupt` shows this effect. #[pallet::constant] type HistoryDepth: Get; @@ -237,8 +238,16 @@ pub mod pallet { /// VALIDATOR. type TargetList: SortedListProvider>; - /// The maximum number of `unlocking` chunks a [`StakingLedger`] can have. Effectively - /// determines how many unique eras a staker may be unbonding in. + /// The maximum number of `unlocking` chunks a [`StakingLedger`] can + /// have. Effectively determines how many unique eras a staker may be + /// unbonding in. + /// + /// Note: `MaxUnlockingChunks` is used as the upper bound for the + /// `BoundedVec` item `StakingLedger.unlocking`. Setting this value + /// lower than the existing value can lead to inconsistencies in the + /// `StakingLedger` and will need to be handled properly in a runtime + /// migration. The test `reducing_max_unlocking_chunks_abrupt` shows + /// this effect. #[pallet::constant] type MaxUnlockingChunks: Get; @@ -940,7 +949,7 @@ pub mod pallet { let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; ensure!( - ledger.unlocking.len() < MaxUnlockingChunks::get() as usize, + ledger.unlocking.len() < T::MaxUnlockingChunks::get() as usize, Error::::NoMoreChunks, ); @@ -1454,7 +1463,7 @@ pub mod pallet { /// - Bounded by `MaxUnlockingChunks`. /// - Storage changes: Can't increase storage, only decrease it. /// # - #[pallet::weight(T::WeightInfo::rebond(MaxUnlockingChunks::get() as u32))] + #[pallet::weight(T::WeightInfo::rebond(T::MaxUnlockingChunks::get() as u32))] pub fn rebond( origin: OriginFor, #[pallet::compact] value: BalanceOf, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 8ec98da99ecb1..4812c105c0d80 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -17,7 +17,7 @@ //! Tests for the module. -use super::{ConfigOp, Event, MaxUnlockingChunks, *}; +use super::{ConfigOp, Event, *}; use frame_election_provider_support::{ElectionProvider, SortedListProvider, Support}; use frame_support::{ assert_noop, assert_ok, assert_storage_noop, bounded_vec, @@ -1354,7 +1354,8 @@ fn too_many_unbond_calls_should_not_work() { ExtBuilder::default().build_and_execute(|| { let mut current_era = 0; // locked at era MaxUnlockingChunks - 1 until 3 - for i in 0..MaxUnlockingChunks::get() - 1 { + + for i in 0..<::MaxUnlockingChunks as Get>::get() - 1 { // There is only 1 chunk per era, so we need to be in a new era to create a chunk. current_era = i as u32; mock::start_active_era(current_era); @@ -1369,7 +1370,7 @@ fn too_many_unbond_calls_should_not_work() { assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); assert_eq!( Staking::ledger(&10).unwrap().unlocking.len(), - MaxUnlockingChunks::get() as usize + <::MaxUnlockingChunks as Get>::get() as usize ); // can't do more. assert_noop!(Staking::unbond(RuntimeOrigin::signed(10), 1), Error::::NoMoreChunks); @@ -5494,7 +5495,7 @@ fn pre_bonding_era_cannot_be_claimed() { } #[test] -fn reducing_history_depth_without_migration() { +fn reducing_history_depth_abrupt() { // Verifies initial conditions of mock ExtBuilder::default().nominate(false).build_and_execute(|| { let original_history_depth = HistoryDepth::get(); @@ -5571,3 +5572,55 @@ fn reducing_history_depth_without_migration() { HistoryDepth::set(original_history_depth); }); } + +#[test] +fn reducing_max_unlocking_chunks_abrupt() { + // Concern is on validators only + // By Default 11, 10 are stash and ctrl and 21,20 + ExtBuilder::default().build_and_execute(|| { + // given a staker at era=10 and MaxUnlockChunks set to 2 + MaxUnlockingChunks::set(2); + start_active_era(10); + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 300, RewardDestination::Staked)); + assert!(matches!(Staking::ledger(4), Some(_))); + + // when staker unbonds + assert_ok!(Staking::unbond(RuntimeOrigin::signed(4), 20)); + + // then an unlocking chunk is added at `current_era + bonding_duration` + // => 10 + 3 = 13 + let expected_unlocking: BoundedVec, MaxUnlockingChunks> = + bounded_vec![UnlockChunk { value: 20 as Balance, era: 13 as EraIndex }]; + assert!(matches!(Staking::ledger(4), + Some(StakingLedger { + unlocking, + .. + }) if unlocking==expected_unlocking)); + + // when staker unbonds at next era + start_active_era(11); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(4), 50)); + // then another unlock chunk is added + let expected_unlocking: BoundedVec, MaxUnlockingChunks> = + bounded_vec![UnlockChunk { value: 20, era: 13 }, UnlockChunk { value: 50, era: 14 }]; + assert!(matches!(Staking::ledger(4), + Some(StakingLedger { + unlocking, + .. + }) if unlocking==expected_unlocking)); + + // when staker unbonds further + start_active_era(12); + // then further unbonding not possible + assert_noop!(Staking::unbond(RuntimeOrigin::signed(4), 20), Error::::NoMoreChunks); + + // when max unlocking chunks is reduced abruptly to a low value + MaxUnlockingChunks::set(1); + // then unbond, rebond ops are blocked with ledger in corrupt state + assert_noop!(Staking::unbond(RuntimeOrigin::signed(4), 20), Error::::NotController); + assert_noop!(Staking::rebond(RuntimeOrigin::signed(4), 100), Error::::NotController); + + // reset the ledger corruption + MaxUnlockingChunks::set(2); + }) +} From 94b9646177430adb74d7e4737c98ba333f91c451 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 27 Sep 2022 19:31:12 +0200 Subject: [PATCH 1211/1472] [Feature] Add deposit to fast-unstake (#12366) * [Feature] Add deposit to fast-unstake * disable on ErasToCheckPerBlock == 0 * removed signed ext * remove obsolete import * remove some obsolete stuff * fix some comments * fixed all the comments * remove obsolete imports * fix some tests * CallNotAllowed tests * Update frame/fast-unstake/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fix tests * fix deregister + tests * more fixes * make sure we go above existential deposit * fixed the last test * some nit fixes * fix node * fix bench * last bench fix * Update frame/fast-unstake/src/lib.rs * ".git/.scripts/fmt.sh" 1 Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: command-bot <> --- bin/node/runtime/src/lib.rs | 3 +- frame/fast-unstake/src/benchmarking.rs | 8 +- frame/fast-unstake/src/lib.rs | 105 +++++--- frame/fast-unstake/src/mock.rs | 19 +- frame/fast-unstake/src/tests.rs | 333 ++++++++++++++++--------- frame/fast-unstake/src/types.rs | 83 +----- 6 files changed, 313 insertions(+), 238 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8ed5f1c847f5e..aa1a525bf095c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -581,8 +581,9 @@ impl pallet_staking::Config for Runtime { impl pallet_fast_unstake::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type SlashPerEra = ConstU128<{ DOLLARS }>; type ControlOrigin = frame_system::EnsureRoot; + type Deposit = ConstU128<{ DOLLARS }>; + type DepositCurrency = Balances; type WeightInfo = (); } diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs index 5690d5ce6f29f..8770cc6b64c0d 100644 --- a/frame/fast-unstake/src/benchmarking.rs +++ b/frame/fast-unstake/src/benchmarking.rs @@ -110,18 +110,18 @@ fn on_idle_full_block() { benchmarks! { // on_idle, we we don't check anyone, but fully unbond and move them to another pool. on_idle_unstake { + ErasToCheckPerBlock::::put(1); let who = create_unexposed_nominator::(); assert_ok!(FastUnstake::::register_fast_unstake( RawOrigin::Signed(who.clone()).into(), )); - ErasToCheckPerBlock::::put(1); // run on_idle once. This will check era 0. assert_eq!(Head::::get(), None); on_idle_full_block::(); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: who.clone(), checked: vec![0].try_into().unwrap() }) + Some(UnstakeRequest { stash: who.clone(), checked: vec![0].try_into().unwrap(), deposit: T::Deposit::get() }) ); } : { @@ -162,7 +162,7 @@ benchmarks! { let checked: frame_support::BoundedVec<_, _> = (1..=u).rev().collect::>().try_into().unwrap(); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: who.clone(), checked }) + Some(UnstakeRequest { stash: who.clone(), checked, deposit: T::Deposit::get() }) ); assert!(matches!( fast_unstake_events::().last(), @@ -171,6 +171,7 @@ benchmarks! { } register_fast_unstake { + ErasToCheckPerBlock::::put(1); let who = create_unexposed_nominator::(); whitelist_account!(who); assert_eq!(Queue::::count(), 0); @@ -182,6 +183,7 @@ benchmarks! { } deregister { + ErasToCheckPerBlock::::put(1); let who = create_unexposed_nominator::(); assert_ok!(FastUnstake::::register_fast_unstake( RawOrigin::Signed(who.clone()).into(), diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 7fbac8560ea6c..ed26d6b436e1d 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -81,7 +81,10 @@ pub mod pallet { use super::*; use crate::types::*; use frame_election_provider_support::ElectionProvider; - use frame_support::pallet_prelude::*; + use frame_support::{ + pallet_prelude::*, + traits::{Defensive, ReservableCurrency}, + }; use frame_system::{pallet_prelude::*, RawOrigin}; use pallet_staking::Pallet as Staking; use sp_runtime::{ @@ -90,7 +93,6 @@ pub mod pallet { }; use sp_staking::EraIndex; use sp_std::{prelude::*, vec::Vec}; - pub use types::PreventStakingOpsIfUnbonding; pub use weights::WeightInfo; #[derive(scale_info::TypeInfo, codec::Encode, codec::Decode, codec::MaxEncodedLen)] @@ -113,10 +115,12 @@ pub mod pallet { + IsType<::RuntimeEvent> + TryInto>; - /// The amount of balance slashed per each era that was wastefully checked. - /// - /// A reasonable value could be `runtime_weight_to_fee(weight_per_era_check)`. - type SlashPerEra: Get>; + /// The currency used for deposits. + type DepositCurrency: ReservableCurrency>; + + /// Deposit to take for unstaking, to make sure we're able to slash the it in order to cover + /// the costs of resources on unsuccessful unstake. + type Deposit: Get>; /// The origin that can control this pallet. type ControlOrigin: frame_support::traits::EnsureOrigin; @@ -128,13 +132,13 @@ pub mod pallet { /// The current "head of the queue" being unstaked. #[pallet::storage] pub type Head = - StorageValue<_, UnstakeRequest>, OptionQuery>; + StorageValue<_, UnstakeRequest, BalanceOf>, OptionQuery>; /// The map of all accounts wishing to be unstaked. /// - /// Keeps track of `AccountId` wishing to unstake. + /// Keeps track of `AccountId` wishing to unstake and it's corresponding deposit. #[pallet::storage] - pub type Queue = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>; + pub type Queue = CountedStorageMap<_, Twox64Concat, T::AccountId, BalanceOf>; /// Number of eras to check per block. /// @@ -177,6 +181,8 @@ pub mod pallet { NotQueued, /// The provided un-staker is already in Head, and cannot deregister. AlreadyHead, + /// The call is not allowed at this point because the pallet is not active. + CallNotAllowed, } #[pallet::hooks] @@ -214,6 +220,8 @@ pub mod pallet { pub fn register_fast_unstake(origin: OriginFor) -> DispatchResult { let ctrl = ensure_signed(origin)?; + ensure!(ErasToCheckPerBlock::::get() != 0, >::CallNotAllowed); + let ledger = pallet_staking::Ledger::::get(&ctrl).ok_or(Error::::NotController)?; ensure!(!Queue::::contains_key(&ledger.stash), Error::::AlreadyQueued); @@ -231,8 +239,10 @@ pub mod pallet { Staking::::chill(RawOrigin::Signed(ctrl.clone()).into())?; Staking::::unbond(RawOrigin::Signed(ctrl).into(), ledger.total)?; + T::DepositCurrency::reserve(&ledger.stash, T::Deposit::get())?; + // enqueue them. - Queue::::insert(ledger.stash, ()); + Queue::::insert(ledger.stash, T::Deposit::get()); Ok(()) } @@ -246,6 +256,9 @@ pub mod pallet { #[pallet::weight(::WeightInfo::deregister())] pub fn deregister(origin: OriginFor) -> DispatchResult { let ctrl = ensure_signed(origin)?; + + ensure!(ErasToCheckPerBlock::::get() != 0, >::CallNotAllowed); + let stash = pallet_staking::Ledger::::get(&ctrl) .map(|l| l.stash) .ok_or(Error::::NotController)?; @@ -254,7 +267,17 @@ pub mod pallet { Head::::get().map_or(true, |UnstakeRequest { stash, .. }| stash != stash), Error::::AlreadyHead ); - Queue::::remove(stash); + let deposit = Queue::::take(stash.clone()); + + if let Some(deposit) = deposit.defensive() { + let remaining = T::DepositCurrency::unreserve(&stash, deposit); + if !remaining.is_zero() { + frame_support::defensive!("`not enough balance to unreserve`"); + ErasToCheckPerBlock::::put(0); + Self::deposit_event(Event::::InternalError) + } + } + Ok(()) } @@ -315,18 +338,23 @@ pub mod pallet { return T::DbWeight::get().reads(2) } - let UnstakeRequest { stash, mut checked } = match Head::::take().or_else(|| { - // NOTE: there is no order guarantees in `Queue`. - Queue::::drain() - .map(|(stash, _)| UnstakeRequest { stash, checked: Default::default() }) - .next() - }) { - None => { - // There's no `Head` and nothing in the `Queue`, nothing to do here. - return T::DbWeight::get().reads(4) - }, - Some(head) => head, - }; + let UnstakeRequest { stash, mut checked, deposit } = + match Head::::take().or_else(|| { + // NOTE: there is no order guarantees in `Queue`. + Queue::::drain() + .map(|(stash, deposit)| UnstakeRequest { + stash, + deposit, + checked: Default::default(), + }) + .next() + }) { + None => { + // There's no `Head` and nothing in the `Queue`, nothing to do here. + return T::DbWeight::get().reads(4) + }, + Some(head) => head, + }; log!( debug, @@ -381,9 +409,16 @@ pub mod pallet { num_slashing_spans, ); - log!(info, "unstaked {:?}, outcome: {:?}", stash, result); + let remaining = T::DepositCurrency::unreserve(&stash, deposit); + if !remaining.is_zero() { + frame_support::defensive!("`not enough balance to unreserve`"); + ErasToCheckPerBlock::::put(0); + Self::deposit_event(Event::::InternalError) + } else { + log!(info, "unstaked {:?}, outcome: {:?}", stash, result); + Self::deposit_event(Event::::Unstaked { stash, result }); + } - Self::deposit_event(Event::::Unstaked { stash, result }); ::WeightInfo::on_idle_unstake() } else { // eras remaining to be checked. @@ -406,22 +441,18 @@ pub mod pallet { // the last 28 eras, have registered yourself to be unstaked, midway being checked, // you are exposed. if is_exposed { - let amount = T::SlashPerEra::get() - .saturating_mul(eras_checked.saturating_add(checked.len() as u32).into()); - pallet_staking::slashing::do_slash::( - &stash, - amount, - &mut Default::default(), - &mut Default::default(), - current_era, - ); - log!(info, "slashed {:?} by {:?}", stash, amount); - Self::deposit_event(Event::::Slashed { stash, amount }); + T::DepositCurrency::slash_reserved(&stash, deposit); + log!(info, "slashed {:?} by {:?}", stash, deposit); + Self::deposit_event(Event::::Slashed { stash, amount: deposit }); } else { // Not exposed in these eras. match checked.try_extend(unchecked_eras_to_check.clone().into_iter()) { Ok(_) => { - Head::::put(UnstakeRequest { stash: stash.clone(), checked }); + Head::::put(UnstakeRequest { + stash: stash.clone(), + checked, + deposit, + }); Self::deposit_event(Event::::Checking { stash, eras: unchecked_eras_to_check, diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index 62f343709e245..4c4c5f9ff26fd 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -164,12 +164,13 @@ impl Convert for U256ToBalance { } parameter_types! { - pub static SlashPerEra: u32 = 100; + pub static DepositAmount: u128 = 7; } impl fast_unstake::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type SlashPerEra = SlashPerEra; + type Deposit = DepositAmount; + type DepositCurrency = Balances; type ControlOrigin = frame_system::EnsureRoot; type WeightInfo = (); } @@ -213,11 +214,11 @@ impl Default for ExtBuilder { fn default() -> Self { Self { exposed_nominators: vec![ - (1, 2, 100), - (3, 4, 100), - (5, 6, 100), - (7, 8, 100), - (9, 10, 100), + (1, 2, 7 + 100), + (3, 4, 7 + 100), + (5, 6, 7 + 100), + (7, 8, 7 + 100), + (9, 10, 7 + 100), ], } } @@ -270,8 +271,8 @@ impl ExtBuilder { .into_iter() .map(|(_, ctrl, balance)| (ctrl, balance * 2)), ) - .chain(validators_range.clone().map(|x| (x, 100))) - .chain(nominators_range.clone().map(|x| (x, 100))) + .chain(validators_range.clone().map(|x| (x, 7 + 100))) + .chain(nominators_range.clone().map(|x| (x, 7 + 100))) .collect::>(), } .assimilate_storage(&mut storage); diff --git a/frame/fast-unstake/src/tests.rs b/frame/fast-unstake/src/tests.rs index 5586443ce797c..6e617fd992028 100644 --- a/frame/fast-unstake/src/tests.rs +++ b/frame/fast-unstake/src/tests.rs @@ -35,6 +35,7 @@ fn test_setup_works() { #[test] fn register_works() { ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); // Controller account registers for fast unstake. assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); // Ensure stash is in the queue. @@ -42,9 +43,38 @@ fn register_works() { }); } +#[test] +fn register_insufficient_funds_fails() { + use pallet_balances::Error as BalancesError; + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + ::DepositCurrency::make_free_balance_be(&1, 3); + + // Controller account registers for fast unstake. + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), + BalancesError::::InsufficientBalance, + ); + + // Ensure stash is in the queue. + assert_eq!(Queue::::get(1), None); + }); +} + +#[test] +fn register_disabled_fails() { + ExtBuilder::default().build_and_execute(|| { + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), + Error::::CallNotAllowed + ); + }); +} + #[test] fn cannot_register_if_not_bonded() { ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); // Mint accounts 1 and 2 with 200 tokens. for _ in 1..2 { let _ = Balances::make_free_balance_be(&1, 200); @@ -60,8 +90,9 @@ fn cannot_register_if_not_bonded() { #[test] fn cannot_register_if_in_queue() { ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); // Insert some Queue item - Queue::::insert(1, ()); + Queue::::insert(1, 10); // Cannot re-register, already in queue assert_noop!( FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), @@ -73,8 +104,13 @@ fn cannot_register_if_in_queue() { #[test] fn cannot_register_if_head() { ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); // Insert some Head item for stash - Head::::put(UnstakeRequest { stash: 1, checked: bounded_vec![] }); + Head::::put(UnstakeRequest { + stash: 1, + checked: bounded_vec![], + deposit: DepositAmount::get(), + }); // Controller attempts to regsiter assert_noop!( FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), @@ -86,6 +122,7 @@ fn cannot_register_if_head() { #[test] fn cannot_register_if_has_unlocking_chunks() { ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); // Start unbonding half of staked tokens assert_ok!(Staking::unbond(RuntimeOrigin::signed(2), 50_u128)); // Cannot register for fast unstake with unlock chunks active @@ -99,18 +136,37 @@ fn cannot_register_if_has_unlocking_chunks() { #[test] fn deregister_works() { ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + + assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + // Controller account registers for fast unstake. assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(::DepositCurrency::reserved_balance(&1), DepositAmount::get()); + // Controller then changes mind and deregisters. assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(2))); + assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + // Ensure stash no longer exists in the queue. assert_eq!(Queue::::get(1), None); }); } +#[test] +fn deregister_disabled_fails() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + ErasToCheckPerBlock::::put(0); + assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(2)), Error::::CallNotAllowed); + }); +} + #[test] fn cannot_deregister_if_not_controller() { ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); // Controller account registers for fast unstake. assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); // Stash tries to deregister. @@ -121,6 +177,7 @@ fn cannot_deregister_if_not_controller() { #[test] fn cannot_deregister_if_not_queued() { ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); // Controller tries to deregister without first registering assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(2)), Error::::NotQueued); }); @@ -129,10 +186,15 @@ fn cannot_deregister_if_not_queued() { #[test] fn cannot_deregister_already_head() { ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); // Controller attempts to register, should fail assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); // Insert some Head item for stash. - Head::::put(UnstakeRequest { stash: 1, checked: bounded_vec![] }); + Head::::put(UnstakeRequest { + stash: 1, + checked: bounded_vec![], + deposit: DepositAmount::get(), + }); // Controller attempts to deregister assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(2)), Error::::AlreadyHead); }); @@ -165,14 +227,14 @@ mod on_idle { // set up Queue item assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(())); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); // call on_idle with no remaining weight FastUnstake::on_idle(System::block_number(), Weight::from_ref_time(0)); // assert nothing changed in Queue and Head assert_eq!(Head::::get(), None); - assert_eq!(Queue::::get(1), Some(())); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); }); } @@ -185,7 +247,7 @@ mod on_idle { // given assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(())); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); assert_eq!(Queue::::count(), 1); assert_eq!(Head::::get(), None); @@ -204,7 +266,11 @@ mod on_idle { ); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3] + }) ); // when: another 1 era. @@ -220,7 +286,11 @@ mod on_idle { ); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) ); // when: then 5 eras, we only need 2 more. @@ -242,7 +312,11 @@ mod on_idle { ); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) ); // when: not enough weight to unstake: @@ -254,7 +328,11 @@ mod on_idle { assert_eq!(fast_unstake_events_since_last_call(), vec![]); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) ); // when: enough weight to get over at least one iteration: then we are unblocked and can @@ -285,12 +363,16 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // given + assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(6))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(8))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(10))); + assert_eq!(::DepositCurrency::reserved_balance(&1), DepositAmount::get()); + assert_eq!(Queue::::count(), 5); assert_eq!(Head::::get(), None); @@ -300,7 +382,11 @@ mod on_idle { // then assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) ); assert_eq!(Queue::::count(), 4); @@ -317,10 +403,16 @@ mod on_idle { // then assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 5, checked: bounded_vec![3, 2, 1, 0] }), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 5, + checked: bounded_vec![3, 2, 1, 0] + }), ); assert_eq!(Queue::::count(), 3); + assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + assert_eq!( fast_unstake_events_since_last_call(), vec![ @@ -340,9 +432,9 @@ mod on_idle { // register multi accounts for fast unstake assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(())); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); - assert_eq!(Queue::::get(3), Some(())); + assert_eq!(Queue::::get(3), Some(DepositAmount::get())); // assert 2 queue items are in Queue & None in Head to start with assert_eq!(Queue::::count(), 2); @@ -391,7 +483,7 @@ mod on_idle { // register for fast unstake assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(())); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); // process on idle next_block(true); @@ -402,7 +494,11 @@ mod on_idle { // assert head item present assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) ); next_block(true); @@ -425,9 +521,11 @@ mod on_idle { ErasToCheckPerBlock::::put(BondingDuration::get() + 1); CurrentEra::::put(BondingDuration::get()); + Balances::make_free_balance_be(&2, 100); + // register for fast unstake assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(())); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); // process on idle next_block(true); @@ -438,7 +536,11 @@ mod on_idle { // assert head item present assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) ); next_block(true); @@ -464,7 +566,7 @@ mod on_idle { // register for fast unstake assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(())); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); // process on idle next_block(true); @@ -475,28 +577,44 @@ mod on_idle { // assert head item present assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3] + }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1] + }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) ); next_block(true); @@ -529,30 +647,46 @@ mod on_idle { // register for fast unstake assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - assert_eq!(Queue::::get(1), Some(())); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3] + }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1] + }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 1, 0] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) ); // when: a new era happens right before one is free. @@ -567,6 +701,7 @@ mod on_idle { stash: 1, // note era 0 is pruned to keep the vector length sane. checked: bounded_vec![3, 2, 1, 4], + deposit: DepositAmount::get(), }) ); @@ -602,13 +737,21 @@ mod on_idle { next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3] + }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) ); // when @@ -618,13 +761,21 @@ mod on_idle { next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) ); // then we register a new era. @@ -636,14 +787,22 @@ mod on_idle { next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 4] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 4] + }) ); // progress to end next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3, 2, 4, 1] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 4, 1] + }) ); // but notice that we don't care about era 0 instead anymore! we're done. @@ -669,7 +828,6 @@ mod on_idle { fn exposed_nominator_cannot_unstake() { ExtBuilder::default().build_and_execute(|| { ErasToCheckPerBlock::::put(1); - SlashPerEra::set(7); CurrentEra::::put(BondingDuration::get()); // create an exposed nominator in era 1 @@ -686,6 +844,7 @@ mod on_idle { )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed])); + Balances::make_free_balance_be(&exposed, 100_000); // register the exposed one. assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed))); @@ -693,23 +852,30 @@ mod on_idle { next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: exposed, checked: bounded_vec![3] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: exposed, + checked: bounded_vec![3] + }) ); next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: exposed, checked: bounded_vec![3, 2] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: exposed, + checked: bounded_vec![3, 2] + }) ); next_block(true); assert_eq!(Head::::get(), None); assert_eq!( fast_unstake_events_since_last_call(), - // we slash them by 21, since we checked 3 eras in total (3, 2, 1). vec![ Event::Checking { stash: exposed, eras: vec![3] }, Event::Checking { stash: exposed, eras: vec![2] }, - Event::Slashed { stash: exposed, amount: 3 * 7 } + Event::Slashed { stash: exposed, amount: DepositAmount::get() } ] ); }); @@ -721,7 +887,6 @@ mod on_idle { // same as the previous check, but we check 2 eras per block, and we make the exposed be // exposed in era 0, so that it is detected halfway in a check era. ErasToCheckPerBlock::::put(2); - SlashPerEra::set(7); CurrentEra::::put(BondingDuration::get()); // create an exposed nominator in era 1 @@ -729,7 +894,7 @@ mod on_idle { pallet_staking::ErasStakers::::mutate(0, VALIDATORS_PER_ERA, |expo| { expo.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); }); - Balances::make_free_balance_be(&exposed, 100); + Balances::make_free_balance_be(&exposed, DepositAmount::get() + 100); assert_ok!(Staking::bond( RuntimeOrigin::signed(exposed), exposed, @@ -745,17 +910,21 @@ mod on_idle { next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: exposed, checked: bounded_vec![3, 2] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: exposed, + checked: bounded_vec![3, 2] + }) ); next_block(true); assert_eq!(Head::::get(), None); assert_eq!( fast_unstake_events_since_last_call(), - // we slash them by 28, since we checked 4 eras in total. + // we slash them vec![ Event::Checking { stash: exposed, eras: vec![3, 2] }, - Event::Slashed { stash: exposed, amount: 4 * 7 } + Event::Slashed { stash: exposed, amount: DepositAmount::get() } ] ); }); @@ -786,7 +955,7 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), - vec![Event::Slashed { stash: 100, amount: 100 }] + vec![Event::Slashed { stash: 100, amount: DepositAmount::get() }] ); }); } @@ -798,7 +967,7 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // create a new validator that 100% not exposed. - Balances::make_free_balance_be(&42, 100); + Balances::make_free_balance_be(&42, 100 + DepositAmount::get()); assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 42, 10, RewardDestination::Staked)); assert_ok!(Staking::validate(RuntimeOrigin::signed(42), Default::default())); @@ -809,7 +978,11 @@ mod on_idle { next_block(true); assert_eq!( Head::::get(), - Some(UnstakeRequest { stash: 42, checked: bounded_vec![3, 2, 1, 0] }) + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 42, + checked: bounded_vec![3, 2, 1, 0] + }) ); next_block(true); assert_eq!(Head::::get(), None); @@ -824,69 +997,3 @@ mod on_idle { }); } } - -mod signed_extension { - use super::*; - use sp_runtime::traits::SignedExtension; - - const STAKING_CALL: crate::mock::RuntimeCall = - crate::mock::RuntimeCall::Staking(pallet_staking::Call::::chill {}); - - #[test] - fn does_nothing_if_not_queued() { - ExtBuilder::default().build_and_execute(|| { - assert!(PreventStakingOpsIfUnbonding::::new() - .pre_dispatch(&1, &STAKING_CALL, &Default::default(), Default::default()) - .is_ok()); - }) - } - - #[test] - fn prevents_queued() { - ExtBuilder::default().build_and_execute(|| { - // given: stash for 2 is 1. - // when - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - - // then - // stash can't. - assert!(PreventStakingOpsIfUnbonding::::new() - .pre_dispatch(&1, &STAKING_CALL, &Default::default(), Default::default()) - .is_err()); - - // controller can't. - assert!(PreventStakingOpsIfUnbonding::::new() - .pre_dispatch(&2, &STAKING_CALL, &Default::default(), Default::default()) - .is_err()); - }) - } - - #[test] - fn prevents_head_stash() { - ExtBuilder::default().build_and_execute(|| { - // given: stash for 2 is 1. - // when - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); - - ErasToCheckPerBlock::::put(1); - CurrentEra::::put(BondingDuration::get()); - next_block(true); - - assert_eq!( - Head::::get(), - Some(UnstakeRequest { stash: 1, checked: bounded_vec![3] }) - ); - - // then - // stash can't - assert!(PreventStakingOpsIfUnbonding::::new() - .pre_dispatch(&2, &STAKING_CALL, &Default::default(), Default::default()) - .is_err()); - - // controller can't - assert!(PreventStakingOpsIfUnbonding::::new() - .pre_dispatch(&1, &STAKING_CALL, &Default::default(), Default::default()) - .is_err()); - }) - } -} diff --git a/frame/fast-unstake/src/types.rs b/frame/fast-unstake/src/types.rs index 2ddb8dca27e9e..08b9ab4326eb2 100644 --- a/frame/fast-unstake/src/types.rs +++ b/frame/fast-unstake/src/types.rs @@ -17,14 +17,12 @@ //! Types used in the Fast Unstake pallet. -use crate::*; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - traits::{Currency, Get, IsSubType}, + traits::{Currency, Get}, BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use scale_info::TypeInfo; -use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidityError}; use sp_staking::EraIndex; use sp_std::{fmt::Debug, prelude::*}; @@ -36,80 +34,15 @@ pub type BalanceOf = <::Currency as Currency< #[derive( Encode, Decode, EqNoBound, PartialEqNoBound, Clone, TypeInfo, RuntimeDebugNoBound, MaxEncodedLen, )] -pub struct UnstakeRequest> { +pub struct UnstakeRequest< + AccountId: Eq + PartialEq + Debug, + MaxChecked: Get, + Balance: PartialEq + Debug, +> { /// Their stash account. pub(crate) stash: AccountId, /// The list of eras for which they have been checked. pub(crate) checked: BoundedVec, -} - -#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo, RuntimeDebugNoBound)] -#[scale_info(skip_type_params(T))] -pub struct PreventStakingOpsIfUnbonding(sp_std::marker::PhantomData); - -impl PreventStakingOpsIfUnbonding { - pub fn new() -> Self { - Self(Default::default()) - } -} - -impl sp_runtime::traits::SignedExtension - for PreventStakingOpsIfUnbonding -where - ::RuntimeCall: IsSubType>, -{ - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = (); - type Pre = (); - const IDENTIFIER: &'static str = "PreventStakingOpsIfUnbonding"; - - fn additional_signed(&self) -> Result { - Ok(()) - } - - fn pre_dispatch( - self, - // NOTE: we want to prevent this stash-controller pair from doing anything in the - // staking system as long as they are registered here. - stash_or_controller: &Self::AccountId, - call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, - _len: usize, - ) -> Result { - // we don't check this in the tx-pool as it requires a storage read. - if >>::is_sub_type(call).is_some() { - let check_stash = |stash: &T::AccountId| { - if Queue::::contains_key(&stash) || - Head::::get().map_or(false, |u| &u.stash == stash) - { - Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) - } else { - Ok(()) - } - }; - match ( - // mapped from controller. - pallet_staking::Ledger::::get(&stash_or_controller), - // mapped from stash. - pallet_staking::Bonded::::get(&stash_or_controller), - ) { - (Some(ledger), None) => { - // it is a controller. - check_stash(&ledger.stash) - }, - (_, Some(_)) => { - // it's a stash. - let stash = stash_or_controller; - check_stash(stash) - }, - (None, None) => { - // They are not a staker -- let them execute. - Ok(()) - }, - } - } else { - Ok(()) - } - } + /// Deposit to be slashed if the unstake was unsuccessful. + pub(crate) deposit: Balance, } From 2ee4cb47fa01ad6c7d6c94acf3370fd26470b388 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Wed, 28 Sep 2022 04:14:01 +0800 Subject: [PATCH 1212/1472] Add missing CountedStorageMap in pallet::storage error info (#12356) --- frame/support/procedural/src/pallet/parse/storage.rs | 4 ++-- .../test/tests/pallet_ui/storage_not_storage_type.stderr | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 321c4dd5d4914..b16ff05803d98 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -555,8 +555,8 @@ fn process_generics( found => { let msg = format!( "Invalid pallet::storage, expected ident: `StorageValue` or \ - `StorageMap` or `StorageDoubleMap` or `StorageNMap` in order to expand metadata, \ - found `{}`.", + `StorageMap` or `CountedStorageMap` or `StorageDoubleMap` or `StorageNMap` \ + in order to expand metadata, found `{}`.", found, ); return Err(syn::Error::new(segment.ident.span(), msg)) diff --git a/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr b/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr index 4fd59183282d0..223e9cfa3e9f8 100644 --- a/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr +++ b/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr @@ -1,4 +1,4 @@ -error: Invalid pallet::storage, expected ident: `StorageValue` or `StorageMap` or `StorageDoubleMap` or `StorageNMap` in order to expand metadata, found `u8`. +error: Invalid pallet::storage, expected ident: `StorageValue` or `StorageMap` or `CountedStorageMap` or `StorageDoubleMap` or `StorageNMap` in order to expand metadata, found `u8`. --> $DIR/storage_not_storage_type.rs:19:16 | 19 | type Foo = u8; From 17c07af0b953b84dbe89341294e98e586f9b4591 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 28 Sep 2022 18:21:53 +0800 Subject: [PATCH 1213/1472] Add storage size component to weights (#12277) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add storage size component to weights * Rename storage_size to proof_size * Update primitives/weights/src/weight_v2.rs Co-authored-by: Oliver Tale-Yazdi * Fixes * cargo fmt * Implement custom Decode and CompactAs * Add missing import * Fixes * Remove CompactAs implementation * Properly migrate from 1D weight * Remove #[pallet::compact] from Weight parameters * More #[pallet::compact] removals * Add unit tests * Set appropriate default block proof size * cargo fmt * Remove nonsensical weight constant * Test only for the reference time weight in frame_system::limits * Only check for reference time weight on idle * Use destructuring syntax * Update test expectations * Fixes * Fixes * Fixes * Correctly migrate from 1D weights * cargo fmt * Migrate using extra extrinsics instead of custom Decode * Fixes * Silence dispatch call warnings that were previously allowed * Fix gas_left test * Use OldWeight instead of u64 * Fixes * Only check for reference time weight in election provider * Fix test expectations * Fix test expectations * Use only reference time weight in grandpa test * Use only reference time weight in examples test * Use only reference time weight in examples test * Fix test expectations Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Alexander Theißen --- frame/alliance/src/lib.rs | 62 ++++- frame/babe/src/tests.rs | 3 +- frame/collective/src/lib.rs | 69 +++++- frame/contracts/src/lib.rs | 179 ++++++++++++++- frame/contracts/src/wasm/mod.rs | 15 +- .../election-provider-multi-phase/src/lib.rs | 9 +- .../src/unsigned.rs | 9 +- frame/examples/basic/src/tests.rs | 6 +- frame/executive/src/lib.rs | 7 +- frame/grandpa/src/tests.rs | 3 +- .../procedural/src/pallet/expand/call.rs | 20 ++ .../procedural/src/pallet/parse/call.rs | 3 + ...age_ensure_span_are_ok_on_wrong_gen.stderr | 6 +- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 6 +- .../pallet_ui/storage_info_unsatisfied.stderr | 2 +- .../storage_info_unsatisfied_nmap.stderr | 2 +- frame/system/src/limits.rs | 21 +- frame/transaction-payment/src/types.rs | 5 +- primitives/weights/src/lib.rs | 21 +- primitives/weights/src/weight_v2.rs | 211 ++++++++++++------ 20 files changed, 531 insertions(+), 128 deletions(-) diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 2ef6718538122..24111b44ced9e 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -120,7 +120,7 @@ use frame_support::{ ChangeMembers, Currency, Get, InitializeMembers, IsSubType, OnUnbalanced, ReservableCurrency, }, - weights::Weight, + weights::{OldWeight, Weight}, }; use pallet_identity::IdentityField; @@ -620,25 +620,22 @@ pub mod pallet { .max(T::WeightInfo::close_early_disapproved(x, y, p2)) .max(T::WeightInfo::close_approved(b, x, y, p2)) .max(T::WeightInfo::close_disapproved(x, y, p2)) - .saturating_add(p1) + .saturating_add(p1.into()) })] - pub fn close( + #[allow(deprecated)] + #[deprecated(note = "1D weight is used in this extrinsic, please migrate to use `close`")] + pub fn close_old_weight( origin: OriginFor, proposal_hash: T::Hash, #[pallet::compact] index: ProposalIndex, - #[pallet::compact] proposal_weight_bound: Weight, + #[pallet::compact] proposal_weight_bound: OldWeight, #[pallet::compact] length_bound: u32, ) -> DispatchResultWithPostInfo { + let proposal_weight_bound: Weight = proposal_weight_bound.into(); let who = ensure_signed(origin)?; ensure!(Self::has_voting_rights(&who), Error::::NoVotingRights); - let info = T::ProposalProvider::close_proposal( - proposal_hash, - index, - proposal_weight_bound, - length_bound, - )?; - Ok(info.into()) + Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) } /// Initialize the Alliance, onboard founders, fellows, and allies. @@ -985,6 +982,34 @@ pub mod pallet { Self::deposit_event(Event::UnscrupulousItemRemoved { items }); Ok(()) } + + /// Close a vote that is either approved, disapproved, or whose voting period has ended. + /// + /// Requires the sender to be a founder or fellow. + #[pallet::weight({ + let b = *length_bound; + let x = T::MaxFounders::get(); + let y = T::MaxFellows::get(); + let p1 = *proposal_weight_bound; + let p2 = T::MaxProposals::get(); + T::WeightInfo::close_early_approved(b, x, y, p2) + .max(T::WeightInfo::close_early_disapproved(x, y, p2)) + .max(T::WeightInfo::close_approved(b, x, y, p2)) + .max(T::WeightInfo::close_disapproved(x, y, p2)) + .saturating_add(p1) + })] + pub fn close( + origin: OriginFor, + proposal_hash: T::Hash, + #[pallet::compact] index: ProposalIndex, + proposal_weight_bound: Weight, + #[pallet::compact] length_bound: u32, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!(Self::has_voting_rights(&who), Error::::NoVotingRights); + + Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) + } } } @@ -1197,4 +1222,19 @@ impl, I: 'static> Pallet { } res } + + fn do_close( + proposal_hash: T::Hash, + index: ProposalIndex, + proposal_weight_bound: Weight, + length_bound: u32, + ) -> DispatchResultWithPostInfo { + let info = T::ProposalProvider::close_proposal( + proposal_hash, + index, + proposal_weight_bound, + length_bound, + )?; + Ok(info.into()) + } } diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 8d2a9b326cd0f..d4132e6378540 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -852,7 +852,8 @@ fn valid_equivocation_reports_dont_pay_fees() { .get_dispatch_info(); // it should have non-zero weight and the fee has to be paid. - assert!(info.weight.all_gt(Weight::zero())); + // TODO: account for proof size weight + assert!(info.weight.ref_time() > 0); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index ae68ae2fe3e16..06d5b1fab78e7 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -57,7 +57,7 @@ use frame_support::{ traits::{ Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers, StorageVersion, }, - weights::Weight, + weights::{OldWeight, Weight}, }; #[cfg(test)] @@ -620,17 +620,20 @@ pub mod pallet { .max(T::WeightInfo::close_early_disapproved(m, p2)) .max(T::WeightInfo::close_approved(b, m, p2)) .max(T::WeightInfo::close_disapproved(m, p2)) - .saturating_add(p1) + .saturating_add(p1.into()) }, DispatchClass::Operational ))] - pub fn close( + #[allow(deprecated)] + #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `close`")] + pub fn close_old_weight( origin: OriginFor, proposal_hash: T::Hash, #[pallet::compact] index: ProposalIndex, - #[pallet::compact] proposal_weight_bound: Weight, + #[pallet::compact] proposal_weight_bound: OldWeight, #[pallet::compact] length_bound: u32, ) -> DispatchResultWithPostInfo { + let proposal_weight_bound: Weight = proposal_weight_bound.into(); let _ = ensure_signed(origin)?; Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) @@ -659,6 +662,64 @@ pub mod pallet { let proposal_count = Self::do_disapprove_proposal(proposal_hash); Ok(Some(T::WeightInfo::disapprove_proposal(proposal_count)).into()) } + + /// Close a vote that is either approved, disapproved or whose voting period has ended. + /// + /// May be called by any signed account in order to finish voting and close the proposal. + /// + /// If called before the end of the voting period it will only close the vote if it is + /// has enough votes to be approved or disapproved. + /// + /// If called after the end of the voting period abstentions are counted as rejections + /// unless there is a prime member set and the prime member cast an approval. + /// + /// If the close operation completes successfully with disapproval, the transaction fee will + /// be waived. Otherwise execution of the approved operation will be charged to the caller. + /// + /// + `proposal_weight_bound`: The maximum amount of weight consumed by executing the closed + /// proposal. + /// + `length_bound`: The upper bound for the length of the proposal in storage. Checked via + /// `storage::read` so it is `size_of::() == 4` larger than the pure length. + /// + /// # + /// ## Weight + /// - `O(B + M + P1 + P2)` where: + /// - `B` is `proposal` size in bytes (length-fee-bounded) + /// - `M` is members-count (code- and governance-bounded) + /// - `P1` is the complexity of `proposal` preimage. + /// - `P2` is proposal-count (code-bounded) + /// - DB: + /// - 2 storage reads (`Members`: codec `O(M)`, `Prime`: codec `O(1)`) + /// - 3 mutations (`Voting`: codec `O(M)`, `ProposalOf`: codec `O(B)`, `Proposals`: codec + /// `O(P2)`) + /// - any mutations done while executing `proposal` (`P1`) + /// - up to 3 events + /// # + #[pallet::weight(( + { + let b = *length_bound; + let m = T::MaxMembers::get(); + let p1 = *proposal_weight_bound; + let p2 = T::MaxProposals::get(); + T::WeightInfo::close_early_approved(b, m, p2) + .max(T::WeightInfo::close_early_disapproved(m, p2)) + .max(T::WeightInfo::close_approved(b, m, p2)) + .max(T::WeightInfo::close_disapproved(m, p2)) + .saturating_add(p1) + }, + DispatchClass::Operational + ))] + pub fn close( + origin: OriginFor, + proposal_hash: T::Hash, + #[pallet::compact] index: ProposalIndex, + proposal_weight_bound: Weight, + #[pallet::compact] length_bound: u32, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + + Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) + } } } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index fc44e4507ca00..f9a1c8decf042 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -113,7 +113,7 @@ use frame_support::{ tokens::fungible::Inspect, ConstU32, Contains, Currency, Get, Randomness, ReservableCurrency, Time, }, - weights::Weight, + weights::{OldWeight, Weight}, BoundedVec, WeakBoundedVec, }; use frame_system::{limits::BlockWeights, Pallet as System}; @@ -429,15 +429,18 @@ pub mod pallet { /// * If the account is a regular account, any value will be transferred. /// * If no account exists and the call value is not less than `existential_deposit`, /// a regular account will be created and any value will be transferred. - #[pallet::weight(T::WeightInfo::call().saturating_add(*gas_limit))] - pub fn call( + #[pallet::weight(T::WeightInfo::call().saturating_add((*gas_limit).into()))] + #[allow(deprecated)] + #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `call`")] + pub fn call_old_weight( origin: OriginFor, dest: AccountIdLookupOf, #[pallet::compact] value: BalanceOf, - #[pallet::compact] gas_limit: Weight, + #[pallet::compact] gas_limit: OldWeight, storage_deposit_limit: Option< as codec::HasCompact>::Type>, data: Vec, ) -> DispatchResultWithPostInfo { + let gas_limit: Weight = gas_limit.into(); let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; let mut output = Self::internal_call( @@ -485,17 +488,22 @@ pub mod pallet { /// - The `deploy` function is executed in the context of the newly-created account. #[pallet::weight( T::WeightInfo::instantiate_with_code(code.len() as u32, salt.len() as u32) - .saturating_add(*gas_limit) + .saturating_add((*gas_limit).into()) )] - pub fn instantiate_with_code( + #[allow(deprecated)] + #[deprecated( + note = "1D weight is used in this extrinsic, please migrate to `instantiate_with_code`" + )] + pub fn instantiate_with_code_old_weight( origin: OriginFor, #[pallet::compact] value: BalanceOf, - #[pallet::compact] gas_limit: Weight, + #[pallet::compact] gas_limit: OldWeight, storage_deposit_limit: Option< as codec::HasCompact>::Type>, code: Vec, data: Vec, salt: Vec, ) -> DispatchResultWithPostInfo { + let gas_limit: Weight = gas_limit.into(); let origin = ensure_signed(origin)?; let code_len = code.len() as u32; let salt_len = salt.len() as u32; @@ -526,17 +534,20 @@ pub mod pallet { /// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary /// must be supplied. #[pallet::weight( - T::WeightInfo::instantiate(salt.len() as u32).saturating_add(*gas_limit) + T::WeightInfo::instantiate(salt.len() as u32).saturating_add((*gas_limit).into()) )] - pub fn instantiate( + #[allow(deprecated)] + #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `instantiate`")] + pub fn instantiate_old_weight( origin: OriginFor, #[pallet::compact] value: BalanceOf, - #[pallet::compact] gas_limit: Weight, + #[pallet::compact] gas_limit: OldWeight, storage_deposit_limit: Option< as codec::HasCompact>::Type>, code_hash: CodeHash, data: Vec, salt: Vec, ) -> DispatchResultWithPostInfo { + let gas_limit: Weight = gas_limit.into(); let origin = ensure_signed(origin)?; let salt_len = salt.len() as u32; let mut output = Self::internal_instantiate( @@ -639,6 +650,154 @@ pub mod pallet { Ok(()) }) } + + /// Makes a call to an account, optionally transferring some balance. + /// + /// # Parameters + /// + /// * `dest`: Address of the contract to call. + /// * `value`: The balance to transfer from the `origin` to `dest`. + /// * `gas_limit`: The gas limit enforced when executing the constructor. + /// * `storage_deposit_limit`: The maximum amount of balance that can be charged from the + /// caller to pay for the storage consumed. + /// * `data`: The input data to pass to the contract. + /// + /// * If the account is a smart-contract account, the associated code will be + /// executed and any value will be transferred. + /// * If the account is a regular account, any value will be transferred. + /// * If no account exists and the call value is not less than `existential_deposit`, + /// a regular account will be created and any value will be transferred. + #[pallet::weight(T::WeightInfo::call().saturating_add(*gas_limit))] + pub fn call( + origin: OriginFor, + dest: AccountIdLookupOf, + #[pallet::compact] value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + data: Vec, + ) -> DispatchResultWithPostInfo { + let gas_limit: Weight = gas_limit.into(); + let origin = ensure_signed(origin)?; + let dest = T::Lookup::lookup(dest)?; + let mut output = Self::internal_call( + origin, + dest, + value, + gas_limit, + storage_deposit_limit.map(Into::into), + data, + None, + ); + if let Ok(retval) = &output.result { + if retval.did_revert() { + output.result = Err(>::ContractReverted.into()); + } + } + output.gas_meter.into_dispatch_result(output.result, T::WeightInfo::call()) + } + + /// Instantiates a new contract from the supplied `code` optionally transferring + /// some balance. + /// + /// This dispatchable has the same effect as calling [`Self::upload_code`] + + /// [`Self::instantiate`]. Bundling them together provides efficiency gains. Please + /// also check the documentation of [`Self::upload_code`]. + /// + /// # Parameters + /// + /// * `value`: The balance to transfer from the `origin` to the newly created contract. + /// * `gas_limit`: The gas limit enforced when executing the constructor. + /// * `storage_deposit_limit`: The maximum amount of balance that can be charged/reserved + /// from the caller to pay for the storage consumed. + /// * `code`: The contract code to deploy in raw bytes. + /// * `data`: The input data to pass to the contract constructor. + /// * `salt`: Used for the address derivation. See [`Pallet::contract_address`]. + /// + /// Instantiation is executed as follows: + /// + /// - The supplied `code` is instrumented, deployed, and a `code_hash` is created for that + /// code. + /// - If the `code_hash` already exists on the chain the underlying `code` will be shared. + /// - The destination address is computed based on the sender, code_hash and the salt. + /// - The smart-contract account is created at the computed address. + /// - The `value` is transferred to the new account. + /// - The `deploy` function is executed in the context of the newly-created account. + #[pallet::weight( + T::WeightInfo::instantiate_with_code(code.len() as u32, salt.len() as u32) + .saturating_add(*gas_limit) + )] + pub fn instantiate_with_code( + origin: OriginFor, + #[pallet::compact] value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + code: Vec, + data: Vec, + salt: Vec, + ) -> DispatchResultWithPostInfo { + let origin = ensure_signed(origin)?; + let code_len = code.len() as u32; + let salt_len = salt.len() as u32; + let mut output = Self::internal_instantiate( + origin, + value, + gas_limit, + storage_deposit_limit.map(Into::into), + Code::Upload(Bytes(code)), + data, + salt, + None, + ); + if let Ok(retval) = &output.result { + if retval.1.did_revert() { + output.result = Err(>::ContractReverted.into()); + } + } + output.gas_meter.into_dispatch_result( + output.result.map(|(_address, result)| result), + T::WeightInfo::instantiate_with_code(code_len, salt_len), + ) + } + + /// Instantiates a contract from a previously deployed wasm binary. + /// + /// This function is identical to [`Self::instantiate_with_code`] but without the + /// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary + /// must be supplied. + #[pallet::weight( + T::WeightInfo::instantiate(salt.len() as u32).saturating_add(*gas_limit) + )] + pub fn instantiate( + origin: OriginFor, + #[pallet::compact] value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + code_hash: CodeHash, + data: Vec, + salt: Vec, + ) -> DispatchResultWithPostInfo { + let origin = ensure_signed(origin)?; + let salt_len = salt.len() as u32; + let mut output = Self::internal_instantiate( + origin, + value, + gas_limit, + storage_deposit_limit.map(Into::into), + Code::Existing(code_hash), + data, + salt, + None, + ); + if let Ok(retval) = &output.result { + if retval.1.did_revert() { + output.result = Err(>::ContractReverted.into()); + } + } + output.gas_meter.into_dispatch_result( + output.result.map(|(_address, output)| output), + T::WeightInfo::instantiate(salt_len), + ) + } } #[pallet::event] diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 126a37e9401ec..d8b4cd245356e 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -274,7 +274,11 @@ mod tests { BalanceOf, CodeHash, Error, Pallet as Contracts, }; use assert_matches::assert_matches; - use frame_support::{assert_ok, dispatch::DispatchResultWithPostInfo, weights::Weight}; + use frame_support::{ + assert_ok, + dispatch::DispatchResultWithPostInfo, + weights::{OldWeight, Weight}, + }; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pretty_assertions::assert_eq; use sp_core::{Bytes, H256}; @@ -1545,10 +1549,11 @@ mod tests { let output = execute(CODE_GAS_LEFT, vec![], &mut ext).unwrap(); - let gas_left = Weight::decode(&mut &*output.data).unwrap(); + let OldWeight(gas_left) = OldWeight::decode(&mut &*output.data).unwrap(); let actual_left = ext.gas_meter.gas_left(); - assert!(gas_left.all_lt(gas_limit), "gas_left must be less than initial"); - assert!(gas_left.all_gt(actual_left), "gas_left must be greater than final"); + // TODO: account for proof size weight + assert!(gas_left < gas_limit.ref_time(), "gas_left must be less than initial"); + assert!(gas_left > actual_left.ref_time(), "gas_left must be greater than final"); } const CODE_VALUE_TRANSFERRED: &str = r#" @@ -1946,7 +1951,7 @@ mod tests { )] ); - assert!(mock_ext.gas_meter.gas_left().all_gt(Weight::zero())); + assert!(mock_ext.gas_meter.gas_left().ref_time() > 0); } const CODE_DEPOSIT_EVENT_MAX_TOPICS: &str = r#" diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 05353e5a3ac61..bba8139f38f44 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1008,8 +1008,10 @@ pub mod pallet { // unlikely to ever return an error: if phase is signed, snapshot will exist. let size = Self::snapshot_metadata().ok_or(Error::::MissingSnapshotMetadata)?; + // TODO: account for proof size weight ensure!( - Self::solution_weight_of(&raw_solution, size).all_lt(T::SignedMaxWeight::get()), + Self::solution_weight_of(&raw_solution, size).ref_time() < + T::SignedMaxWeight::get().ref_time(), Error::::SignedTooMuchWeight, ); @@ -2336,8 +2338,9 @@ mod tests { }; let mut active = 1; - while weight_with(active) - .all_lte(::BlockWeights::get().max_block) || + // TODO: account for proof size weight + while weight_with(active).ref_time() <= + ::BlockWeights::get().max_block.ref_time() || active == all_voters { active += 1; diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 833f80c90d13e..281ac37421174 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -638,7 +638,8 @@ impl Miner { }; let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result { - if current_weight.all_lt(max_weight) { + // TODO: account for proof size weight + if current_weight.ref_time() < max_weight.ref_time() { let next_voters = voters.checked_add(step); match next_voters { Some(voters) if voters < max_voters => Ok(voters), @@ -673,7 +674,8 @@ impl Miner { // Time to finish. We might have reduced less than expected due to rounding error. Increase // one last time if we have any room left, the reduce until we are sure we are below limit. - while voters < max_voters && weight_with(voters + 1).all_lt(max_weight) { + // TODO: account for proof size weight + while voters < max_voters && weight_with(voters + 1).ref_time() < max_weight.ref_time() { voters += 1; } while voters.checked_sub(1).is_some() && weight_with(voters).any_gt(max_weight) { @@ -681,8 +683,9 @@ impl Miner { } let final_decision = voters.min(size.voters); + // TODO: account for proof size weight debug_assert!( - weight_with(final_decision).all_lte(max_weight), + weight_with(final_decision).ref_time() <= max_weight.ref_time(), "weight_with({}) <= {}", final_decision, max_weight, diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index db4787eaa0faa..97fbddfbc41e0 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -191,11 +191,13 @@ fn weights_work() { let default_call = pallet_example_basic::Call::::accumulate_dummy { increase_by: 10 }; let info1 = default_call.get_dispatch_info(); // aka. `let info = as GetDispatchInfo>::get_dispatch_info(&default_call);` - assert!(info1.weight.all_gt(Weight::zero())); + // TODO: account for proof size weight + assert!(info1.weight.ref_time() > 0); // `set_dummy` is simpler than `accumulate_dummy`, and the weight // should be less. let custom_call = pallet_example_basic::Call::::set_dummy { new_value: 20 }; let info2 = custom_call.get_dispatch_info(); - assert!(info1.weight.all_gt(info2.weight)); + // TODO: account for proof size weight + assert!(info1.weight.ref_time() > info2.weight.ref_time()); } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index a41c82da5757c..014c7a2bc02a6 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -459,7 +459,8 @@ where let max_weight = >::get().max_block; let remaining_weight = max_weight.saturating_sub(weight.total()); - if remaining_weight.all_gt(Weight::zero()) { + // TODO: account for proof size weight + if remaining_weight.ref_time() > 0 { let used_weight = >::on_idle( block_number, remaining_weight, @@ -938,13 +939,13 @@ mod tests { block_import_works_inner( new_test_ext_v0(1), array_bytes::hex_n_into_unchecked( - "1039e1a4bd0cf5deefe65f313577e70169c41c7773d6acf31ca8d671397559f5", + "0d786e24c1f9e6ce237806a22c005bbbc7dee4edd6692b6c5442843d164392de", ), ); block_import_works_inner( new_test_ext(1), array_bytes::hex_n_into_unchecked( - "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5", + "348485a4ab856467b440167e45f99b491385e8528e09b0e51f85f814a3021c93", ), ); } diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 775eda58c03e0..5d2ebdf29cb6b 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -856,7 +856,8 @@ fn valid_equivocation_reports_dont_pay_fees() { .get_dispatch_info(); // it should have non-zero weight and the fee has to be paid. - assert!(info.weight.all_gt(Weight::zero())); + // TODO: account for proof size weight + assert!(info.weight.ref_time() > 0); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 18d5adee63ad6..39d16109aa8fa 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -16,6 +16,7 @@ // limitations under the License. use crate::{pallet::Def, COUNTER}; +use quote::ToTokens; use syn::spanned::Spanned; /// @@ -158,6 +159,24 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { }); } + // Extracts #[allow] attributes, necessary so that we don't run into compiler warnings + let maybe_allow_attrs = methods + .iter() + .map(|method| { + method + .attrs + .iter() + .find(|attr| { + if let Ok(syn::Meta::List(syn::MetaList { path, .. })) = attr.parse_meta() { + path.segments.last().map(|seg| seg.ident == "allow").unwrap_or(false) + } else { + false + } + }) + .map_or(proc_macro2::TokenStream::new(), |attr| attr.to_token_stream()) + }) + .collect::>(); + quote::quote_spanned!(span => #[doc(hidden)] pub mod __substrate_call_check { @@ -289,6 +308,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::sp_tracing::enter_span!( #frame_support::sp_tracing::trace_span!(stringify!(#fn_name)) ); + #maybe_allow_attrs <#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* ) .map(Into::into).map_err(Into::into) }, diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index 336e08c3d39b7..f7b2c9544d831 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -61,6 +61,8 @@ pub struct CallVariantDef { pub call_index: u8, /// Docs, used for metadata. pub docs: Vec, + /// Attributes annotated at the top of the dispatchable function. + pub attrs: Vec, } /// Attributes for functions in call impl block. @@ -287,6 +289,7 @@ impl CallDef { call_index: final_index, args, docs, + attrs: method.attrs.clone(), }); } else { let msg = "Invalid pallet::call, only method accepted"; diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index 5d159ec961c7f..b0716d569409c 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) - and 159 others + and 160 others = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 4671855431b27..926dc92530659 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) - and 159 others + and 160 others = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 278 others + and 279 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index d9cd20711403d..563190a06f76f 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -13,5 +13,5 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 76 others + and 77 others = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 9a4e8d740cb2c..c10005223b674 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -13,6 +13,6 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 76 others + and 77 others = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index e182eb626424d..cfc1d261baa01 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -207,7 +207,7 @@ pub struct BlockWeights { impl Default for BlockWeights { fn default() -> Self { - Self::with_sensible_defaults(1u32 * constants::WEIGHT_PER_SECOND, DEFAULT_NORMAL_RATIO) + Self::with_sensible_defaults(1u64 * constants::WEIGHT_PER_SECOND, DEFAULT_NORMAL_RATIO) } } @@ -224,6 +224,7 @@ impl BlockWeights { } let mut error = ValidationErrors::default(); + // TODO: account for proof size weight in the assertions below for class in DispatchClass::all() { let weights = self.per_class.get(*class); let max_for_class = or_max(weights.max_total); @@ -232,18 +233,16 @@ impl BlockWeights { // Make sure that if total is set it's greater than base_block && // base_for_class error_assert!( - (max_for_class.all_gt(self.base_block) && max_for_class.all_gt(base_for_class)) - || max_for_class == Weight::zero(), + (max_for_class.ref_time() > self.base_block.ref_time() && max_for_class.ref_time() > base_for_class.ref_time()) + || max_for_class.ref_time() == 0, &mut error, "[{:?}] {:?} (total) has to be greater than {:?} (base block) & {:?} (base extrinsic)", class, max_for_class, self.base_block, base_for_class, ); // Max extrinsic can't be greater than max_for_class. error_assert!( - weights - .max_extrinsic - .unwrap_or(Weight::zero()) - .all_lte(max_for_class.saturating_sub(base_for_class)), + weights.max_extrinsic.unwrap_or(Weight::zero()).ref_time() <= + max_for_class.saturating_sub(base_for_class).ref_time(), &mut error, "[{:?}] {:?} (max_extrinsic) can't be greater than {:?} (max for class)", class, @@ -252,14 +251,14 @@ impl BlockWeights { ); // Max extrinsic should not be 0 error_assert!( - weights.max_extrinsic.unwrap_or_else(Weight::max_value).all_gt(Weight::zero()), + weights.max_extrinsic.unwrap_or_else(Weight::max_value).ref_time() > 0, &mut error, "[{:?}] {:?} (max_extrinsic) must not be 0. Check base cost and average initialization cost.", class, weights.max_extrinsic, ); // Make sure that if reserved is set it's greater than base_for_class. error_assert!( - reserved.all_gt(base_for_class) || reserved == Weight::zero(), + reserved.ref_time() > base_for_class.ref_time() || reserved.ref_time() == 0, &mut error, "[{:?}] {:?} (reserved) has to be greater than {:?} (base extrinsic) if set", class, @@ -268,7 +267,7 @@ impl BlockWeights { ); // Make sure max block is greater than max_total if it's set. error_assert!( - self.max_block.all_gte(weights.max_total.unwrap_or(Weight::zero())), + self.max_block.ref_time() >= weights.max_total.unwrap_or(Weight::zero()).ref_time(), &mut error, "[{:?}] {:?} (max block) has to be greater than {:?} (max for class)", class, @@ -277,7 +276,7 @@ impl BlockWeights { ); // Make sure we can fit at least one extrinsic. error_assert!( - self.max_block.all_gt(base_for_class + self.base_block), + self.max_block.ref_time() > (base_for_class + self.base_block).ref_time(), &mut error, "[{:?}] {:?} (max block) must fit at least one extrinsic {:?} (base weight)", class, diff --git a/frame/transaction-payment/src/types.rs b/frame/transaction-payment/src/types.rs index 1f41ba7b0b72e..fff41ef6937f5 100644 --- a/frame/transaction-payment/src/types.rs +++ b/frame/transaction-payment/src/types.rs @@ -140,7 +140,8 @@ mod tests { partial_fee: 1_000_000_u64, }; - let json_str = r#"{"weight":{"ref_time":5},"class":"normal","partialFee":"1000000"}"#; + let json_str = + r#"{"weight":{"ref_time":5,"proof_size":0},"class":"normal","partialFee":"1000000"}"#; assert_eq!(serde_json::to_string(&info).unwrap(), json_str); assert_eq!(serde_json::from_str::>(json_str).unwrap(), info); @@ -157,7 +158,7 @@ mod tests { partial_fee: u128::max_value(), }; - let json_str = r#"{"weight":{"ref_time":5},"class":"normal","partialFee":"340282366920938463463374607431768211455"}"#; + let json_str = r#"{"weight":{"ref_time":5,"proof_size":0},"class":"normal","partialFee":"340282366920938463463374607431768211455"}"#; assert_eq!(serde_json::to_string(&info).unwrap(), json_str); assert_eq!(serde_json::from_str::>(json_str).unwrap(), info); diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs index d260f73d41268..e1ac7fcd4e892 100644 --- a/primitives/weights/src/lib.rs +++ b/primitives/weights/src/lib.rs @@ -30,7 +30,7 @@ extern crate self as sp_weights; mod weight_v2; -use codec::{Decode, Encode}; +use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -53,6 +53,25 @@ pub mod constants { pub const WEIGHT_PER_NANOS: Weight = Weight::from_ref_time(1_000); } +/// The old weight type. +/// +/// NOTE: This type exists purely for compatibility purposes! Use [`weight_v2::Weight`] in all other +/// cases. +#[derive( + Decode, + Encode, + CompactAs, + PartialEq, + Eq, + Clone, + Copy, + RuntimeDebug, + Default, + MaxEncodedLen, + TypeInfo, +)] +pub struct OldWeight(pub u64); + /// The weight of database operations that the runtime can invoke. /// /// NOTE: This is currently only measured in computational time, and will probably diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index af0f469ebaaeb..a8eaf79a28711 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; +use codec::{Decode, Encode, MaxEncodedLen}; use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign}; use sp_arithmetic::traits::{Bounded, CheckedAdd, CheckedSub, Zero}; use sp_debug_derive::RuntimeDebug; @@ -23,22 +23,22 @@ use sp_debug_derive::RuntimeDebug; use super::*; #[derive( - Encode, - Decode, - MaxEncodedLen, - TypeInfo, - Eq, - PartialEq, - Copy, - Clone, - RuntimeDebug, - Default, - CompactAs, + Encode, Decode, MaxEncodedLen, TypeInfo, Eq, PartialEq, Copy, Clone, RuntimeDebug, Default, )] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct Weight { + #[codec(compact)] /// The weight of computational time used based on some reference hardware. ref_time: u64, + #[codec(compact)] + /// The weight of storage space used by proof of validity. + proof_size: u64, +} + +impl From for Weight { + fn from(old: OldWeight) -> Self { + Weight::from_ref_time(old.0) + } } impl Weight { @@ -48,71 +48,118 @@ impl Weight { self } + /// Set the storage size part of the weight. + pub const fn set_proof_size(mut self, c: u64) -> Self { + self.proof_size = c; + self + } + /// Return the reference time part of the weight. pub const fn ref_time(&self) -> u64 { self.ref_time } - /// Return a mutable reference time part of the weight. + /// Return the storage size part of the weight. + pub const fn proof_size(&self) -> u64 { + self.proof_size + } + + /// Return a mutable reference to the reference time part of the weight. pub fn ref_time_mut(&mut self) -> &mut u64 { &mut self.ref_time } - pub const MAX: Self = Self { ref_time: u64::MAX }; + /// Return a mutable reference to the storage size part of the weight. + pub fn proof_size_mut(&mut self) -> &mut u64 { + &mut self.proof_size + } + + pub const MAX: Self = Self { ref_time: u64::MAX, proof_size: u64::MAX }; /// Get the conservative min of `self` and `other` weight. pub fn min(&self, other: Self) -> Self { - Self { ref_time: self.ref_time.min(other.ref_time) } + Self { + ref_time: self.ref_time.min(other.ref_time), + proof_size: self.proof_size.min(other.proof_size), + } } /// Get the aggressive max of `self` and `other` weight. pub fn max(&self, other: Self) -> Self { - Self { ref_time: self.ref_time.max(other.ref_time) } + Self { + ref_time: self.ref_time.max(other.ref_time), + proof_size: self.proof_size.max(other.proof_size), + } } /// Try to add some `other` weight while upholding the `limit`. pub fn try_add(&self, other: &Self, limit: &Self) -> Option { let total = self.checked_add(other)?; - if total.ref_time > limit.ref_time { + if total.any_gt(*limit) { None } else { Some(total) } } - /// Construct [`Weight`] with reference time weight. + /// Construct [`Weight`] with reference time weight and 0 storage size weight. pub const fn from_ref_time(ref_time: u64) -> Self { - Self { ref_time } + Self { ref_time, proof_size: 0 } + } + + /// Construct [`Weight`] with storage size weight and 0 reference time weight. + pub const fn from_proof_size(proof_size: u64) -> Self { + Self { ref_time: 0, proof_size } + } + + /// Construct [`Weight`] with weight components, namely reference time and storage size weights. + pub const fn from_components(ref_time: u64, proof_size: u64) -> Self { + Self { ref_time, proof_size } } /// Saturating [`Weight`] addition. Computes `self + rhs`, saturating at the numeric bounds of /// all fields instead of overflowing. pub const fn saturating_add(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time.saturating_add(rhs.ref_time) } + Self { + ref_time: self.ref_time.saturating_add(rhs.ref_time), + proof_size: self.proof_size.saturating_add(rhs.proof_size), + } } /// Saturating [`Weight`] subtraction. Computes `self - rhs`, saturating at the numeric bounds /// of all fields instead of overflowing. pub const fn saturating_sub(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time.saturating_sub(rhs.ref_time) } + Self { + ref_time: self.ref_time.saturating_sub(rhs.ref_time), + proof_size: self.proof_size.saturating_sub(rhs.proof_size), + } } /// Saturating [`Weight`] scalar multiplication. Computes `self.field * scalar` for all fields, /// saturating at the numeric bounds of all fields instead of overflowing. pub const fn saturating_mul(self, scalar: u64) -> Self { - Self { ref_time: self.ref_time.saturating_mul(scalar) } + Self { + ref_time: self.ref_time.saturating_mul(scalar), + proof_size: self.proof_size.saturating_mul(scalar), + } } /// Saturating [`Weight`] scalar division. Computes `self.field / scalar` for all fields, /// saturating at the numeric bounds of all fields instead of overflowing. pub const fn saturating_div(self, scalar: u64) -> Self { - Self { ref_time: self.ref_time.saturating_div(scalar) } + Self { + ref_time: self.ref_time.saturating_div(scalar), + proof_size: self.proof_size.saturating_div(scalar), + } } /// Saturating [`Weight`] scalar exponentiation. Computes `self.field.pow(exp)` for all fields, /// saturating at the numeric bounds of all fields instead of overflowing. pub const fn saturating_pow(self, exp: u32) -> Self { - Self { ref_time: self.ref_time.saturating_pow(exp) } + Self { + ref_time: self.ref_time.saturating_pow(exp), + proof_size: self.proof_size.saturating_pow(exp), + } } /// Increment [`Weight`] by `amount` via saturating addition. @@ -122,124 +169,144 @@ impl Weight { /// Checked [`Weight`] addition. Computes `self + rhs`, returning `None` if overflow occurred. pub const fn checked_add(&self, rhs: &Self) -> Option { - match self.ref_time.checked_add(rhs.ref_time) { - Some(ref_time) => Some(Self { ref_time }), - None => None, - } + let ref_time = match self.ref_time.checked_add(rhs.ref_time) { + Some(t) => t, + None => return None, + }; + let proof_size = match self.proof_size.checked_add(rhs.proof_size) { + Some(s) => s, + None => return None, + }; + Some(Self { ref_time, proof_size }) } /// Checked [`Weight`] subtraction. Computes `self - rhs`, returning `None` if overflow /// occurred. pub const fn checked_sub(&self, rhs: &Self) -> Option { - match self.ref_time.checked_sub(rhs.ref_time) { - Some(ref_time) => Some(Self { ref_time }), - None => None, - } + let ref_time = match self.ref_time.checked_sub(rhs.ref_time) { + Some(t) => t, + None => return None, + }; + let proof_size = match self.proof_size.checked_sub(rhs.proof_size) { + Some(s) => s, + None => return None, + }; + Some(Self { ref_time, proof_size }) } /// Checked [`Weight`] scalar multiplication. Computes `self.field * scalar` for each field, /// returning `None` if overflow occurred. pub const fn checked_mul(self, scalar: u64) -> Option { - match self.ref_time.checked_mul(scalar) { - Some(ref_time) => Some(Self { ref_time }), - None => None, - } + let ref_time = match self.ref_time.checked_mul(scalar) { + Some(t) => t, + None => return None, + }; + let proof_size = match self.proof_size.checked_mul(scalar) { + Some(s) => s, + None => return None, + }; + Some(Self { ref_time, proof_size }) } /// Checked [`Weight`] scalar division. Computes `self.field / scalar` for each field, returning /// `None` if overflow occurred. pub const fn checked_div(self, scalar: u64) -> Option { - match self.ref_time.checked_div(scalar) { - Some(ref_time) => Some(Self { ref_time }), - None => None, - } + let ref_time = match self.ref_time.checked_div(scalar) { + Some(t) => t, + None => return None, + }; + let proof_size = match self.proof_size.checked_div(scalar) { + Some(s) => s, + None => return None, + }; + Some(Self { ref_time, proof_size }) } /// Return a [`Weight`] where all fields are zero. pub const fn zero() -> Self { - Self { ref_time: 0 } + Self { ref_time: 0, proof_size: 0 } } /// Constant version of Add with u64. /// /// Is only overflow safe when evaluated at compile-time. pub const fn add(self, scalar: u64) -> Self { - Self { ref_time: self.ref_time + scalar } + Self { ref_time: self.ref_time + scalar, proof_size: self.proof_size + scalar } } /// Constant version of Sub with u64. /// /// Is only overflow safe when evaluated at compile-time. pub const fn sub(self, scalar: u64) -> Self { - Self { ref_time: self.ref_time - scalar } + Self { ref_time: self.ref_time - scalar, proof_size: self.proof_size - scalar } } /// Constant version of Div with u64. /// /// Is only overflow safe when evaluated at compile-time. pub const fn div(self, scalar: u64) -> Self { - Self { ref_time: self.ref_time / scalar } + Self { ref_time: self.ref_time / scalar, proof_size: self.proof_size / scalar } } /// Constant version of Mul with u64. /// /// Is only overflow safe when evaluated at compile-time. pub const fn mul(self, scalar: u64) -> Self { - Self { ref_time: self.ref_time * scalar } + Self { ref_time: self.ref_time * scalar, proof_size: self.proof_size * scalar } } /// Returns true if any of `self`'s constituent weights is strictly greater than that of the /// `other`'s, otherwise returns false. pub const fn any_gt(self, other: Self) -> bool { - self.ref_time > other.ref_time + self.ref_time > other.ref_time || self.proof_size > other.proof_size } /// Returns true if all of `self`'s constituent weights is strictly greater than that of the /// `other`'s, otherwise returns false. pub const fn all_gt(self, other: Self) -> bool { - self.ref_time > other.ref_time + self.ref_time > other.ref_time && self.proof_size > other.proof_size } /// Returns true if any of `self`'s constituent weights is strictly less than that of the /// `other`'s, otherwise returns false. pub const fn any_lt(self, other: Self) -> bool { - self.ref_time < other.ref_time + self.ref_time < other.ref_time || self.proof_size < other.proof_size } /// Returns true if all of `self`'s constituent weights is strictly less than that of the /// `other`'s, otherwise returns false. pub const fn all_lt(self, other: Self) -> bool { - self.ref_time < other.ref_time + self.ref_time < other.ref_time && self.proof_size < other.proof_size } /// Returns true if any of `self`'s constituent weights is greater than or equal to that of the /// `other`'s, otherwise returns false. pub const fn any_gte(self, other: Self) -> bool { - self.ref_time >= other.ref_time + self.ref_time >= other.ref_time || self.proof_size >= other.proof_size } /// Returns true if all of `self`'s constituent weights is greater than or equal to that of the /// `other`'s, otherwise returns false. pub const fn all_gte(self, other: Self) -> bool { - self.ref_time >= other.ref_time + self.ref_time >= other.ref_time && self.proof_size >= other.proof_size } /// Returns true if any of `self`'s constituent weights is less than or equal to that of the /// `other`'s, otherwise returns false. pub const fn any_lte(self, other: Self) -> bool { - self.ref_time <= other.ref_time + self.ref_time <= other.ref_time || self.proof_size <= other.proof_size } /// Returns true if all of `self`'s constituent weights is less than or equal to that of the /// `other`'s, otherwise returns false. pub const fn all_lte(self, other: Self) -> bool { - self.ref_time <= other.ref_time + self.ref_time <= other.ref_time && self.proof_size <= other.proof_size } /// Returns true if any of `self`'s constituent weights is equal to that of the `other`'s, /// otherwise returns false. pub const fn any_eq(self, other: Self) -> bool { - self.ref_time == other.ref_time + self.ref_time == other.ref_time || self.proof_size == other.proof_size } // NOTE: `all_eq` does not exist, as it's simply the `eq` method from the `PartialEq` trait. @@ -258,14 +325,20 @@ impl Zero for Weight { impl Add for Weight { type Output = Self; fn add(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time + rhs.ref_time } + Self { + ref_time: self.ref_time + rhs.ref_time, + proof_size: self.proof_size + rhs.proof_size, + } } } impl Sub for Weight { type Output = Self; fn sub(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time - rhs.ref_time } + Self { + ref_time: self.ref_time - rhs.ref_time, + proof_size: self.proof_size - rhs.proof_size, + } } } @@ -275,7 +348,7 @@ where { type Output = Self; fn mul(self, b: T) -> Self { - Self { ref_time: b * self.ref_time } + Self { ref_time: b * self.ref_time, proof_size: b * self.proof_size } } } @@ -285,7 +358,10 @@ macro_rules! weight_mul_per_impl { impl Mul for $t { type Output = Weight; fn mul(self, b: Weight) -> Weight { - Weight { ref_time: self * b.ref_time } + Weight { + ref_time: self * b.ref_time, + proof_size: self * b.proof_size, + } } } )* @@ -305,7 +381,10 @@ macro_rules! weight_mul_primitive_impl { impl Mul for $t { type Output = Weight; fn mul(self, b: Weight) -> Weight { - Weight { ref_time: u64::from(self) * b.ref_time } + Weight { + ref_time: u64::from(self) * b.ref_time, + proof_size: u64::from(self) * b.proof_size, + } } } )* @@ -320,7 +399,7 @@ where { type Output = Self; fn div(self, b: T) -> Self { - Self { ref_time: self.ref_time / b } + Self { ref_time: self.ref_time / b, proof_size: self.proof_size / b } } } @@ -338,7 +417,7 @@ impl CheckedSub for Weight { impl core::fmt::Display for Weight { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Weight(ref_time: {})", self.ref_time) + write!(f, "Weight(ref_time: {}, proof_size: {})", self.ref_time, self.proof_size) } } @@ -353,12 +432,18 @@ impl Bounded for Weight { impl AddAssign for Weight { fn add_assign(&mut self, other: Self) { - *self = Self { ref_time: self.ref_time + other.ref_time }; + *self = Self { + ref_time: self.ref_time + other.ref_time, + proof_size: self.proof_size + other.proof_size, + }; } } impl SubAssign for Weight { fn sub_assign(&mut self, other: Self) { - *self = Self { ref_time: self.ref_time - other.ref_time }; + *self = Self { + ref_time: self.ref_time - other.ref_time, + proof_size: self.proof_size - other.proof_size, + }; } } From 01a905e304f2b6b2c1caf4c12b622edb12b265fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 28 Sep 2022 14:37:03 +0200 Subject: [PATCH 1214/1472] pallet-utility: Only disallow the `None` origin (#12351) --- frame/utility/src/lib.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 819314f3d8454..9ae89097a9bc3 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -63,7 +63,7 @@ use frame_support::{ }; use sp_core::TypeId; use sp_io::hashing::blake2_256; -use sp_runtime::traits::{Dispatchable, TrailingZeroInput}; +use sp_runtime::traits::{BadOrigin, Dispatchable, TrailingZeroInput}; use sp_std::prelude::*; pub use weights::WeightInfo; @@ -203,7 +203,12 @@ pub mod pallet { origin: OriginFor, calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { - let is_root = ensure_signed_or_root(origin.clone())?.is_none(); + // Do not allow the `None` origin. + if ensure_none(origin.clone()).is_ok() { + return Err(BadOrigin.into()) + } + + let is_root = ensure_root(origin.clone()).is_ok(); let calls_len = calls.len(); ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); @@ -319,7 +324,12 @@ pub mod pallet { origin: OriginFor, calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { - let is_root = ensure_signed_or_root(origin.clone())?.is_none(); + // Do not allow the `None` origin. + if ensure_none(origin.clone()).is_ok() { + return Err(BadOrigin.into()) + } + + let is_root = ensure_root(origin.clone()).is_ok(); let calls_len = calls.len(); ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); @@ -426,7 +436,12 @@ pub mod pallet { origin: OriginFor, calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { - let is_root = ensure_signed_or_root(origin.clone())?.is_none(); + // Do not allow the `None` origin. + if ensure_none(origin.clone()).is_ok() { + return Err(BadOrigin.into()) + } + + let is_root = ensure_root(origin.clone()).is_ok(); let calls_len = calls.len(); ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); From 1b1a5e12c0e391c7ed4e3ffa332eb2fe928d257f Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 28 Sep 2022 14:43:04 +0200 Subject: [PATCH 1215/1472] Fix staking migration (#12373) Causing issues on Kusama... Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/staking/src/migrations.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 8f37ae30dd056..f2ccb4f8b096f 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -40,10 +40,14 @@ pub mod v12 { "Expected v11 before upgrading to v12" ); - frame_support::ensure!( - T::HistoryDepth::get() == HistoryDepth::::get(), - "Provided value of HistoryDepth should be same as the existing storage value" - ); + if HistoryDepth::::exists() { + frame_support::ensure!( + T::HistoryDepth::get() == HistoryDepth::::get(), + "Provided value of HistoryDepth should be same as the existing storage value" + ); + } else { + log::info!("No HistoryDepth in storage; nothing to remove"); + } Ok(Default::default()) } From 0ec4373d9c1252b60f0a3512fd910b1d48af385a Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 29 Sep 2022 04:38:12 +0900 Subject: [PATCH 1216/1472] Support running the pallet benchmarks analysis without running the benchmarks (#12361) * Support running the pallet benchmarks analysis without running the benchmarks * Rename `override-results` to `json-input` and update the help comment * ".git/.scripts/fmt.sh" 1 Co-authored-by: command-bot <> --- frame/benchmarking/src/utils.rs | 20 ++++-- .../benchmarking-cli/src/pallet/command.rs | 67 +++++++++++++++++-- .../frame/benchmarking-cli/src/pallet/mod.rs | 10 ++- 3 files changed, 82 insertions(+), 15 deletions(-) diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index b483208e3ef69..753e8c1c684ee 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -23,14 +23,14 @@ use frame_support::{ traits::StorageInfo, }; #[cfg(feature = "std")] -use serde::Serialize; +use serde::{Deserialize, Serialize}; use sp_io::hashing::blake2_256; use sp_runtime::traits::TrailingZeroInput; use sp_std::{prelude::Box, vec::Vec}; use sp_storage::TrackedStorageKey; /// An alphabet of possible parameters to use for benchmarking. -#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Clone, Copy, PartialEq, Debug)] #[allow(missing_docs)] #[allow(non_camel_case_types)] @@ -71,7 +71,7 @@ impl std::fmt::Display for BenchmarkParameter { } /// The results of a single of benchmark. -#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Clone, PartialEq, Debug)] pub struct BenchmarkBatch { /// The pallet containing this benchmark. @@ -89,7 +89,7 @@ pub struct BenchmarkBatch { // TODO: could probably make API cleaner here. /// The results of a single of benchmark, where time and db results are separated. -#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Clone, PartialEq, Debug)] pub struct BenchmarkBatchSplitResults { /// The pallet containing this benchmark. @@ -110,7 +110,7 @@ pub struct BenchmarkBatchSplitResults { /// Result from running benchmarks on a FRAME pallet. /// Contains duration of the function call in nanoseconds along with the benchmark parameters /// used for that benchmark result. -#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] pub struct BenchmarkResult { pub components: Vec<(BenchmarkParameter, u32)>, @@ -121,7 +121,7 @@ pub struct BenchmarkResult { pub writes: u32, pub repeat_writes: u32, pub proof_size: u32, - #[cfg_attr(feature = "std", serde(skip_serializing))] + #[cfg_attr(feature = "std", serde(skip))] pub keys: Vec<(Vec, u32, u32, bool)>, } @@ -141,6 +141,14 @@ mod serde_as_str { let s = std::str::from_utf8(value).map_err(serde::ser::Error::custom)?; serializer.collect_str(s) } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: serde::de::Deserializer<'de>, + { + let s: &str = serde::de::Deserialize::deserialize(deserializer)?; + Ok(s.into()) + } } /// Possible errors returned from the benchmarking pipeline. diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 6870ec386d23d..72592617c52ac 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -134,6 +134,20 @@ impl PalletCmd { }; } + if let Some(json_input) = &self.json_input { + let raw_data = match std::fs::read(json_input) { + Ok(raw_data) => raw_data, + Err(error) => + return Err(format!("Failed to read {:?}: {}", json_input, error).into()), + }; + let batches: Vec = match serde_json::from_slice(&raw_data) { + Ok(batches) => batches, + Err(error) => + return Err(format!("Failed to deserialize {:?}: {}", json_input, error).into()), + }; + return self.output_from_results(&batches) + } + let spec = config.chain_spec; let strategy = self.execution.unwrap_or(ExecutionStrategy::Native); let pallet = self.pallet.clone().unwrap_or_default(); @@ -396,8 +410,16 @@ impl PalletCmd { // Combine all of the benchmark results, so that benchmarks of the same pallet/function // are together. - let batches: Vec = combine_batches(batches, batches_db); + let batches = combine_batches(batches, batches_db); + self.output(&batches, &storage_info, &component_ranges) + } + fn output( + &self, + batches: &[BenchmarkBatchSplitResults], + storage_info: &[StorageInfo], + component_ranges: &HashMap<(Vec, Vec), Vec>, + ) -> Result<()> { // Jsonify the result and write it to a file or stdout if desired. if !self.jsonify(&batches)? { // Print the summary only if `jsonify` did not write to stdout. @@ -412,10 +434,45 @@ impl PalletCmd { Ok(()) } + fn output_from_results(&self, batches: &[BenchmarkBatchSplitResults]) -> Result<()> { + let mut component_ranges = + HashMap::<(Vec, Vec), HashMap>::new(); + for batch in batches { + let range = component_ranges + .entry((batch.pallet.clone(), batch.benchmark.clone())) + .or_default(); + for result in &batch.time_results { + for (param, value) in &result.components { + let name = param.to_string(); + let (ref mut min, ref mut max) = range.entry(name).or_insert((*value, *value)); + if *value < *min { + *min = *value; + } + if *value > *max { + *max = *value; + } + } + } + } + + let component_ranges: HashMap<_, _> = component_ranges + .into_iter() + .map(|(key, ranges)| { + let ranges = ranges + .into_iter() + .map(|(name, (min, max))| ComponentRange { name, min, max }) + .collect(); + (key, ranges) + }) + .collect(); + + self.output(batches, &[], &component_ranges) + } + /// Jsonifies the passed batches and writes them to stdout or into a file. /// Can be configured via `--json` and `--json-file`. /// Returns whether it wrote to stdout. - fn jsonify(&self, batches: &Vec) -> Result { + fn jsonify(&self, batches: &[BenchmarkBatchSplitResults]) -> Result { if self.json_output || self.json_file.is_some() { let json = serde_json::to_string_pretty(&batches) .map_err(|e| format!("Serializing into JSON: {:?}", e))?; @@ -432,11 +489,7 @@ impl PalletCmd { } /// Prints the results as human-readable summary without raw timing data. - fn print_summary( - &self, - batches: &Vec, - storage_info: &Vec, - ) { + fn print_summary(&self, batches: &[BenchmarkBatchSplitResults], storage_info: &[StorageInfo]) { for batch in batches.iter() { // Print benchmark metadata println!( diff --git a/utils/frame/benchmarking-cli/src/pallet/mod.rs b/utils/frame/benchmarking-cli/src/pallet/mod.rs index b8c1f7b905c0c..0e698c4e73910 100644 --- a/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -35,11 +35,11 @@ fn parse_pallet_name(pallet: &str) -> String { #[derive(Debug, clap::Parser)] pub struct PalletCmd { /// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`). - #[clap(short, long, parse(from_str = parse_pallet_name), required_unless_present = "list")] + #[clap(short, long, parse(from_str = parse_pallet_name), required_unless_present_any = ["list", "json-input"])] pub pallet: Option, /// Select an extrinsic inside the pallet to benchmark, or `*` for all. - #[clap(short, long, required_unless_present = "list")] + #[clap(short, long, required_unless_present_any = ["list", "json-input"])] pub extrinsic: Option, /// Select how many samples we should take across the variable components. @@ -166,4 +166,10 @@ pub struct PalletCmd { /// template for that purpose. #[clap(long)] pub no_storage_info: bool, + + /// A path to a `.json` file with existing benchmark results generated with `--json` or + /// `--json-file`. When specified the benchmarks are not actually executed, and the data for + /// the analysis is read from this file. + #[clap(long)] + pub json_input: Option, } From d66adfabd7911bf01ab01ec96ec4228307a03e07 Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Wed, 28 Sep 2022 22:00:33 +0200 Subject: [PATCH 1217/1472] fix: typo in AllPalletsWithSystem deprecated msg (#12379) --- frame/support/procedural/src/construct_runtime/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index e20cb61b7aec1..73d0d54343eb9 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -422,7 +422,7 @@ fn decl_all_pallets<'a>( /// All pallets included in the runtime as a nested tuple of types in reversed order. /// Excludes the System pallet. #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] + `AllPalletsWithSystem or AllPalletsWithoutSystem`")] pub type AllPalletsWithoutSystemReversed = ( #(#names,)* ); } }); @@ -433,7 +433,7 @@ fn decl_all_pallets<'a>( #attr /// All pallets included in the runtime as a nested tuple of types in reversed order. #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] + `AllPalletsWithSystem or AllPalletsWithoutSystem`")] pub type AllPalletsWithSystemReversed = ( #(#names,)* ); } }); @@ -447,7 +447,7 @@ fn decl_all_pallets<'a>( /// All pallets included in the runtime as a nested tuple of types in reversed order. /// With the system pallet first. #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] + `AllPalletsWithSystem or AllPalletsWithoutSystem`")] pub type AllPalletsReversedWithSystemFirst = ( #(#names,)* ); } }); From 96de768061b182934b2d824b2fe76effb5b4db85 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Wed, 28 Sep 2022 22:04:14 +0200 Subject: [PATCH 1218/1472] New Pallet: Root offences (#11943) * root-offences pallet * fix errors * cleaned up a bit * remove unwrap() * new pallet is getting compiled * remove unnecessary type annotations * remove more unnecessary type annotations * addidtional cleaning * commit * cleaned up * fix in logic * add event * removed Clone trait from AccountId * test module * remove unused imports * fmt * fix * separate into functions, still messy * test * first test * fmt * cleaned up a bit * separate into mock.rs and tests.rs * basic docs for now * pallet_staking GenesisiConfig * fix * added start_session * passing tests * impl GenesisConfig for pallet_session * updated event * Update frame/root-offences/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/root-offences/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * remove * Update frame/root-offences/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * docs * Update frame/root-offences/README.md Co-authored-by: Andronik * Update frame/root-offences/Cargo.toml Co-authored-by: Andronik * license header Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Andronik --- Cargo.lock | 22 ++ Cargo.toml | 1 + frame/nomination-pools/src/lib.rs | 2 +- frame/root-offences/Cargo.toml | 51 +++++ frame/root-offences/README.md | 5 + frame/root-offences/src/lib.rs | 131 +++++++++++ frame/root-offences/src/mock.rs | 356 ++++++++++++++++++++++++++++++ frame/root-offences/src/tests.rs | 94 ++++++++ 8 files changed, 661 insertions(+), 1 deletion(-) create mode 100644 frame/root-offences/Cargo.toml create mode 100644 frame/root-offences/README.md create mode 100644 frame/root-offences/src/lib.rs create mode 100644 frame/root-offences/src/mock.rs create mode 100644 frame/root-offences/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index a9a0eef551179..de50d4ec27105 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6197,6 +6197,28 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-root-offences" +version = "1.0.0" +dependencies = [ + "frame-election-provider-support", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-offences", + "pallet-session", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + [[package]] name = "pallet-scheduler" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 018355df6c9fd..25f12a2c9fd3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -135,6 +135,7 @@ members = [ "frame/staking/reward-fn", "frame/state-trie-migration", "frame/sudo", + "frame/root-offences", "frame/support", "frame/support/procedural", "frame/support/procedural/tools", diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 28d10ce573401..9e77adaeee677 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2523,7 +2523,7 @@ impl Pallet { impl OnStakerSlash> for Pallet { fn on_slash( pool_account: &T::AccountId, - // Bonded balance is always read directly from staking, therefore we need not update + // Bonded balance is always read directly from staking, therefore we don't need to update // anything here. slashed_bonded: BalanceOf, slashed_unlocking: &BTreeMap>, diff --git a/frame/root-offences/Cargo.toml b/frame/root-offences/Cargo.toml new file mode 100644 index 0000000000000..ea6a6527848aa --- /dev/null +++ b/frame/root-offences/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "pallet-root-offences" +version = "1.0.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME root offences pallet" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } + +pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = "../../frame/session", default-features = false } +pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../frame/staking" } +pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../frame/offences" } + +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } + +[dev-dependencies] +pallet-balances = { version = "4.0.0-dev", path = "../balances" } +pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } +pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } + +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } + +frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } + +[features] +runtime-benchmarks = [] +try-runtime = ["frame-support/try-runtime"] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "pallet-session/std", + "pallet-staking/std", + "pallet-offences/std", + "scale-info/std", + "sp-runtime/std", +] diff --git a/frame/root-offences/README.md b/frame/root-offences/README.md new file mode 100644 index 0000000000000..a2c5261b6985a --- /dev/null +++ b/frame/root-offences/README.md @@ -0,0 +1,5 @@ +# Sudo Offences Pallet + +Pallet that allows the root to create an offence. + +NOTE: This pallet should only be used for testing purposes. \ No newline at end of file diff --git a/frame/root-offences/src/lib.rs b/frame/root-offences/src/lib.rs new file mode 100644 index 0000000000000..b4b549627f3fa --- /dev/null +++ b/frame/root-offences/src/lib.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Sudo Offences Pallet +//! Pallet that allows the root to create an offence. +//! +//! NOTE: This pallet should be used for testing purposes. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +use pallet_session::historical::IdentificationTuple; +use pallet_staking::{BalanceOf, Exposure, ExposureOf, Pallet as Staking}; +use sp_runtime::Perbill; +use sp_staking::offence::{DisableStrategy, OnOffenceHandler}; + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: + frame_system::Config + + pallet_staking::Config + + pallet_session::Config::AccountId> + + pallet_session::historical::Config< + FullIdentification = Exposure< + ::AccountId, + BalanceOf, + >, + FullIdentificationOf = ExposureOf, + > + { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// An offence was created by root. + OffenceCreated { offenders: Vec<(T::AccountId, Perbill)> }, + } + + #[pallet::error] + pub enum Error { + /// Failed to get the active era from the staking pallet. + FailedToGetActiveEra, + } + + type OffenceDetails = sp_staking::offence::OffenceDetails< + ::AccountId, + IdentificationTuple, + >; + + #[pallet::call] + impl Pallet { + /// Allows the `root`, for example sudo to create an offence. + #[pallet::weight(T::DbWeight::get().reads(2))] + pub fn create_offence( + origin: OriginFor, + offenders: Vec<(T::AccountId, Perbill)>, + ) -> DispatchResult { + ensure_root(origin)?; + + let slash_fraction = + offenders.clone().into_iter().map(|(_, fraction)| fraction).collect::>(); + let offence_details = Self::get_offence_details(offenders.clone())?; + + Self::submit_offence(&offence_details, &slash_fraction); + Self::deposit_event(Event::OffenceCreated { offenders }); + Ok(()) + } + } + + impl Pallet { + /// Returns a vector of offenders that are going to be slashed. + fn get_offence_details( + offenders: Vec<(T::AccountId, Perbill)>, + ) -> Result>, DispatchError> { + let now = Staking::::active_era() + .map(|e| e.index) + .ok_or(Error::::FailedToGetActiveEra)?; + + Ok(offenders + .clone() + .into_iter() + .map(|(o, _)| OffenceDetails:: { + offender: (o.clone(), Staking::::eras_stakers(now, o)), + reporters: vec![], + }) + .collect()) + } + + /// Submits the offence by calling the `on_offence` function. + fn submit_offence(offenders: &[OffenceDetails], slash_fraction: &[Perbill]) { + let session_index = as frame_support::traits::ValidatorSet>::session_index(); + + as OnOffenceHandler< + T::AccountId, + IdentificationTuple, + Weight, + >>::on_offence(&offenders, &slash_fraction, session_index, DisableStrategy::WhenSlashed); + } + } +} diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs new file mode 100644 index 0000000000000..3f0a26afc1358 --- /dev/null +++ b/frame/root-offences/src/mock.rs @@ -0,0 +1,356 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate as root_offences; + +use frame_election_provider_support::{onchain, SequentialPhragmen}; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64, GenesisBuild, Hooks, OneSessionHandler}, +}; +use pallet_staking::StakerStatus; +use sp_core::H256; +use sp_runtime::{ + curve::PiecewiseLinear, + testing::{Header, UintAuthorityId}, + traits::{BlakeTwo256, IdentityLookup, Zero}, +}; +use sp_staking::{EraIndex, SessionIndex}; +use sp_std::collections::btree_map::BTreeMap; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; +type AccountId = u64; +type Balance = u64; +type BlockNumber = u64; + +pub const INIT_TIMESTAMP: u64 = 30_000; +pub const BLOCK_TIME: u64 = 1000; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, + Session: pallet_session::{Pallet, Call, Storage, Event, Config}, + RootOffences: root_offences::{Pallet, Call, Storage, Event}, + Historical: pallet_session::historical::{Pallet, Storage}, + } +); + +/// Another session handler struct to test on_disabled. +pub struct OtherSessionHandler; +impl OneSessionHandler for OtherSessionHandler { + type Key = UintAuthorityId; + + fn on_genesis_session<'a, I: 'a>(_: I) + where + I: Iterator, + AccountId: 'a, + { + } + + fn on_new_session<'a, I: 'a>(_: bool, _: I, _: I) + where + I: Iterator, + AccountId: 'a, + { + } + + fn on_disabled(_validator_index: u32) {} +} + +impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { + type Public = UintAuthorityId; +} + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); +} + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type RuntimeCall = RuntimeCall; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); +} + +pallet_staking_reward_curve::build! { + const REWARD_CURVE: PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000u64, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + +pub struct OnChainSeqPhragmen; +impl onchain::Config for OnChainSeqPhragmen { + type System = Test; + type Solver = SequentialPhragmen; + type DataProvider = Staking; + type WeightInfo = (); +} + +pub struct OnStakerSlashMock(core::marker::PhantomData); +impl sp_staking::OnStakerSlash for OnStakerSlashMock { + fn on_slash( + _pool_account: &AccountId, + slashed_bonded: Balance, + slashed_chunks: &BTreeMap, + ) { + LedgerSlashPerEra::set((slashed_bonded, slashed_chunks.clone())); + } +} + +parameter_types! { + pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; + pub static Offset: BlockNumber = 0; + pub const Period: BlockNumber = 1; + pub static SessionsPerEra: SessionIndex = 3; + pub static SlashDeferDuration: EraIndex = 0; + pub const BondingDuration: EraIndex = 3; + pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); + pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(75); +} + +impl pallet_staking::Config for Test { + type MaxNominations = ConstU32<16>; + type Currency = Balances; + type CurrencyBalance = ::Balance; + type UnixTime = Timestamp; + type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; + type RewardRemainder = (); + type RuntimeEvent = RuntimeEvent; + type Slash = (); + type Reward = (); + type SessionsPerEra = SessionsPerEra; + type SlashDeferDuration = SlashDeferDuration; + type SlashCancelOrigin = frame_system::EnsureRoot; + type BondingDuration = BondingDuration; + type SessionInterface = Self; + type EraPayout = pallet_staking::ConvertCurve; + type NextNewSession = Session; + type MaxNominatorRewardedPerValidator = ConstU32<64>; + type OffendingValidatorsThreshold = OffendingValidatorsThreshold; + type ElectionProvider = onchain::UnboundedExecution; + type GenesisElectionProvider = Self::ElectionProvider; + type TargetList = pallet_staking::UseValidatorsMap; + type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type OnStakerSlash = OnStakerSlashMock; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type WeightInfo = (); +} + +impl pallet_session::historical::Config for Test { + type FullIdentification = pallet_staking::Exposure; + type FullIdentificationOf = pallet_staking::ExposureOf; +} + +sp_runtime::impl_opaque_keys! { + pub struct SessionKeys { + pub other: OtherSessionHandler, + } +} + +impl pallet_session::Config for Test { + type SessionManager = pallet_session::historical::NoteHistoricalRoot; + type Keys = SessionKeys; + type ShouldEndSession = pallet_session::PeriodicSessions; + type SessionHandler = (OtherSessionHandler,); + type RuntimeEvent = RuntimeEvent; + type ValidatorId = AccountId; + type ValidatorIdOf = pallet_staking::StashOf; + type NextSessionRotation = pallet_session::PeriodicSessions; + type WeightInfo = (); +} + +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; +} + +pub struct ExtBuilder { + validator_count: u32, + minimum_validator_count: u32, + invulnerables: Vec, + balance_factor: Balance, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + validator_count: 2, + minimum_validator_count: 0, + invulnerables: vec![], + balance_factor: 1, + } + } +} + +impl ExtBuilder { + fn build(self) -> sp_io::TestExternalities { + let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + //controllers + (10, self.balance_factor * 50), + (20, self.balance_factor * 50), + (30, self.balance_factor * 50), + (40, self.balance_factor * 50), + // stashes + (11, self.balance_factor * 1000), + (21, self.balance_factor * 1000), + (31, self.balance_factor * 500), + (41, self.balance_factor * 1000), + ], + } + .assimilate_storage(&mut storage) + .unwrap(); + + let stakers = vec![ + // (stash, ctrl, stake, status) + // these two will be elected in the default test where we elect 2. + (11, 10, 1000, StakerStatus::::Validator), + (21, 20, 1000, StakerStatus::::Validator), + // a loser validator + (31, 30, 500, StakerStatus::::Validator), + // an idle validator + (41, 40, 1000, StakerStatus::::Idle), + ]; + + let _ = pallet_staking::GenesisConfig:: { + stakers: stakers.clone(), + ..Default::default() + }; + + let _ = pallet_staking::GenesisConfig:: { + stakers: stakers.clone(), + validator_count: self.validator_count, + minimum_validator_count: self.minimum_validator_count, + invulnerables: self.invulnerables, + slash_reward_fraction: Perbill::from_percent(10), + ..Default::default() + } + .assimilate_storage(&mut storage); + + let _ = pallet_session::GenesisConfig:: { + keys: stakers + .into_iter() + .map(|(id, ..)| (id, id, SessionKeys { other: id.into() })) + .collect(), + } + .assimilate_storage(&mut storage); + + storage.into() + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + let mut ext = self.build(); + ext.execute_with(test); + } +} + +/// Progresses from the current block number (whatever that may be) to the `P * session_index + 1`. +pub(crate) fn start_session(session_index: SessionIndex) { + let end: u64 = if Offset::get().is_zero() { + (session_index as u64) * Period::get() + } else { + Offset::get() + (session_index.saturating_sub(1) as u64) * Period::get() + }; + run_to_block(end); + // session must have progressed properly. + assert_eq!( + Session::current_index(), + session_index, + "current session index = {}, expected = {}", + Session::current_index(), + session_index, + ); +} + +/// Progress to the given block, triggering session and era changes as we progress. +/// +/// This will finalize the previous block, initialize up to the given block, essentially simulating +/// a block import/propose process where we first initialize the block, then execute some stuff (not +/// in the function), and then finalize the block. +pub(crate) fn run_to_block(n: BlockNumber) { + Staking::on_finalize(System::block_number()); + for b in (System::block_number() + 1)..=n { + System::set_block_number(b); + Session::on_initialize(b); + >::on_initialize(b); + Timestamp::set_timestamp(System::block_number() * BLOCK_TIME + INIT_TIMESTAMP); + if b != n { + Staking::on_finalize(System::block_number()); + } + } +} + +pub(crate) fn active_era() -> EraIndex { + Staking::active_era().unwrap().index +} diff --git a/frame/root-offences/src/tests.rs b/frame/root-offences/src/tests.rs new file mode 100644 index 0000000000000..a8b7d0a6d6aca --- /dev/null +++ b/frame/root-offences/src/tests.rs @@ -0,0 +1,94 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use frame_support::{assert_err, assert_ok}; +use mock::{active_era, start_session, Balances, ExtBuilder, RootOffences, RuntimeOrigin, System}; + +#[test] +fn create_offence_fails_given_signed_origin() { + use sp_runtime::traits::BadOrigin; + ExtBuilder::default().build_and_execute(|| { + let offenders = (&[]).to_vec(); + assert_err!(RootOffences::create_offence(RuntimeOrigin::signed(1), offenders), BadOrigin); + }) +} + +#[test] +fn create_offence_works_given_root_origin() { + ExtBuilder::default().build_and_execute(|| { + start_session(1); + + assert_eq!(active_era(), 0); + + assert_eq!(Balances::free_balance(11), 1000); + + let offenders = [(11, Perbill::from_percent(50))].to_vec(); + assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); + + System::assert_last_event(Event::OffenceCreated { offenders }.into()); + // the slash should be applied right away. + assert_eq!(Balances::free_balance(11), 500); + + // the other validator should keep his balance, because we only created + // an offences for the first validator. + assert_eq!(Balances::free_balance(21), 1000); + }) +} + +#[test] +fn create_offence_wont_slash_non_active_validators() { + ExtBuilder::default().build_and_execute(|| { + start_session(1); + + assert_eq!(active_era(), 0); + + // 31 is not an active validator. + assert_eq!(Balances::free_balance(31), 500); + + let offenders = [(31, Perbill::from_percent(20)), (11, Perbill::from_percent(20))].to_vec(); + assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); + + System::assert_last_event(Event::OffenceCreated { offenders }.into()); + + // so 31 didn't get slashed. + assert_eq!(Balances::free_balance(31), 500); + + // but 11 is an active validator so he got slashed. + assert_eq!(Balances::free_balance(11), 800); + }) +} + +#[test] +fn create_offence_wont_slash_idle() { + ExtBuilder::default().build_and_execute(|| { + start_session(1); + + assert_eq!(active_era(), 0); + + // 41 is idle. + assert_eq!(Balances::free_balance(41), 1000); + + let offenders = [(41, Perbill::from_percent(50))].to_vec(); + assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); + + System::assert_last_event(Event::OffenceCreated { offenders }.into()); + + // 41 didn't get slashed. + assert_eq!(Balances::free_balance(41), 1000); + }) +} From e7f994d1e797420f252dd24714b029071ccbc46c Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Wed, 28 Sep 2022 22:52:16 +0200 Subject: [PATCH 1219/1472] bounding staking: `BoundedElectionProvider` trait (#12362) * add a bounded election provider trait * extract common trait election provider base * fmt * only bound the outer support vector * fix tests * docs * fix rust docs * fmt * fix rustdocs * docs * improve docs * small doc change --- .../election-provider-multi-phase/src/lib.rs | 16 ++-- .../election-provider-multi-phase/src/mock.rs | 5 +- frame/election-provider-support/src/lib.rs | 83 ++++++++++++------- .../election-provider-support/src/onchain.rs | 27 +++--- frame/fast-unstake/src/lib.rs | 5 +- frame/fast-unstake/src/mock.rs | 4 +- primitives/npos-elections/src/lib.rs | 14 ++-- 7 files changed, 99 insertions(+), 55 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index bba8139f38f44..649aec30c58b3 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -231,7 +231,8 @@ use codec::{Decode, Encode}; use frame_election_provider_support::{ - ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolution, + ElectionDataProvider, ElectionProvider, ElectionProviderBase, InstantElectionProvider, + NposSolution, }; use frame_support::{ dispatch::DispatchClass, @@ -289,7 +290,7 @@ pub type SolutionTargetIndexOf = as NposSolution>::TargetIndex pub type SolutionAccuracyOf = ::MinerConfig> as NposSolution>::Accuracy; /// The fallback election type. -pub type FallbackErrorOf = <::Fallback as ElectionProvider>::Error; +pub type FallbackErrorOf = <::Fallback as ElectionProviderBase>::Error; /// Configuration for the benchmarks of the pallet. pub trait BenchmarkingConfig { @@ -312,7 +313,7 @@ pub trait BenchmarkingConfig { /// A fallback implementation that transitions the pallet to the emergency phase. pub struct NoFallback(sp_std::marker::PhantomData); -impl ElectionProvider for NoFallback { +impl ElectionProviderBase for NoFallback { type AccountId = T::AccountId; type BlockNumber = T::BlockNumber; type DataProvider = T::DataProvider; @@ -321,7 +322,9 @@ impl ElectionProvider for NoFallback { fn ongoing() -> bool { false } +} +impl ElectionProvider for NoFallback { fn elect() -> Result, Self::Error> { // Do nothing, this will enable the emergency phase. Err("NoFallback.") @@ -1563,7 +1566,7 @@ impl Pallet { >::take() .ok_or(ElectionError::::NothingQueued) .or_else(|_| { - T::Fallback::elect() + ::elect() .map(|supports| ReadySolution { supports, score: Default::default(), @@ -1598,7 +1601,7 @@ impl Pallet { } } -impl ElectionProvider for Pallet { +impl ElectionProviderBase for Pallet { type AccountId = T::AccountId; type BlockNumber = T::BlockNumber; type Error = ElectionError; @@ -1610,7 +1613,9 @@ impl ElectionProvider for Pallet { _ => true, } } +} +impl ElectionProvider for Pallet { fn elect() -> Result, Self::Error> { match Self::do_elect() { Ok(supports) => { @@ -1627,7 +1632,6 @@ impl ElectionProvider for Pallet { } } } - /// convert a DispatchError to a custom InvalidTransaction with the inner code being the error /// number. pub fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 34aa2e1bbfc58..c1c53a3980676 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -297,7 +297,7 @@ impl onchain::Config for OnChainSeqPhragmen { } pub struct MockFallback; -impl ElectionProvider for MockFallback { +impl ElectionProviderBase for MockFallback { type AccountId = AccountId; type BlockNumber = u64; type Error = &'static str; @@ -306,7 +306,8 @@ impl ElectionProvider for MockFallback { fn ongoing() -> bool { false } - +} +impl ElectionProvider for MockFallback { fn elect() -> Result, Self::Error> { Self::elect_with_bounds(Bounded::max_value(), Bounded::max_value()) } diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 0bf62bd8c35cd..5ee65e102bd06 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -20,10 +20,11 @@ //! This crate provides two traits that could interact to enable extensible election functionality //! within FRAME pallets. //! -//! Something that will provide the functionality of election will implement [`ElectionProvider`], -//! whilst needing an associated [`ElectionProvider::DataProvider`], which needs to be fulfilled by -//! an entity implementing [`ElectionDataProvider`]. Most often, *the data provider is* the receiver -//! of the election, resulting in a diagram as below: +//! Something that will provide the functionality of election will implement +//! [`ElectionProvider`] and its parent-trait [`ElectionProviderBase`], whilst needing an +//! associated [`ElectionProviderBase::DataProvider`], which needs to be +//! fulfilled by an entity implementing [`ElectionDataProvider`]. Most often, *the data provider is* +//! the receiver of the election, resulting in a diagram as below: //! //! ```ignore //! ElectionDataProvider @@ -131,12 +132,16 @@ //! type DataProvider: ElectionDataProvider; //! } //! -//! impl ElectionProvider for GenericElectionProvider { +//! impl ElectionProviderBase for GenericElectionProvider { //! type AccountId = AccountId; //! type BlockNumber = BlockNumber; //! type Error = &'static str; //! type DataProvider = T::DataProvider; //! fn ongoing() -> bool { false } +//! +//! } +//! +//! impl ElectionProvider for GenericElectionProvider { //! fn elect() -> Result, Self::Error> { //! Self::DataProvider::electable_targets(None) //! .map_err(|_| "failed to elect") @@ -177,8 +182,8 @@ pub use frame_support::{traits::Get, weights::Weight, BoundedVec, RuntimeDebug}; /// Re-export some type as they are used in the interface. pub use sp_arithmetic::PerThing; pub use sp_npos_elections::{ - Assignment, BalancingConfig, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128, - Support, Supports, VoteWeight, + Assignment, BalancingConfig, BoundedSupports, ElectionResult, Error, ExtendedBalance, + IdentifierT, PerThing128, Support, Supports, VoteWeight, }; pub use traits::NposSolution; @@ -349,12 +354,12 @@ pub trait ElectionDataProvider { fn clear() {} } -/// Something that can compute the result of an election and pass it back to the caller. +/// Base trait for [`ElectionProvider`] and [`BoundedElectionProvider`]. It is +/// meant to be used only with an extension trait that adds an election +/// functionality. /// -/// This trait only provides an interface to _request_ an election, i.e. -/// [`ElectionProvider::elect`]. That data required for the election need to be passed to the -/// implemented of this trait through [`ElectionProvider::DataProvider`]. -pub trait ElectionProvider { +/// Data can be bounded or unbounded and is fetched from [`Self::DataProvider`]. +pub trait ElectionProviderBase { /// The account identifier type. type AccountId; @@ -372,24 +377,39 @@ pub trait ElectionProvider { /// Indicate if this election provider is currently ongoing an asynchronous election or not. fn ongoing() -> bool; +} - /// Elect a new set of winners, without specifying any bounds on the amount of data fetched from - /// [`Self::DataProvider`]. An implementation could nonetheless impose its own custom limits. - /// - /// The result is returned in a target major format, namely as *vector of supports*. - /// - /// This should be implemented as a self-weighing function. The implementor should register its - /// appropriate weight at the end of execution with the system pallet directly. +/// Elect a new set of winners, bounded by `MaxWinners`. +/// +/// Returns a result in bounded, target major format, namely as +/// *BoundedVec<(AccountId, Vec), MaxWinners>*. +pub trait BoundedElectionProvider: ElectionProviderBase { + /// The upper bound on election winners. + type MaxWinners: Get; + /// Performs the election. This should be implemented as a self-weighing function. The + /// implementor should register its appropriate weight at the end of execution with the + /// system pallet directly. + fn elect() -> Result, Self::Error>; +} + +/// Same a [`BoundedElectionProvider`], but no bounds are imposed on the number +/// of winners. +/// +/// The result is returned in a target major format, namely as +///*Vec<(AccountId, Vec)>*. +pub trait ElectionProvider: ElectionProviderBase { + /// Performs the election. This should be implemented as a self-weighing + /// function, similar to [`BoundedElectionProvider::elect()`]. fn elect() -> Result, Self::Error>; } -/// A sub-trait of the [`ElectionProvider`] for cases where we need to be sure an election needs to -/// happen instantly, not asynchronously. +/// A sub-trait of the [`ElectionProvider`] for cases where we need to be sure +/// an election needs to happen instantly, not asynchronously. /// /// The same `DataProvider` is assumed to be used. /// -/// Consequently, allows for control over the amount of data that is being fetched from the -/// [`ElectionProvider::DataProvider`]. +/// Consequently, allows for control over the amount of data that is being +/// fetched from the [`ElectionProviderBase::DataProvider`]. pub trait InstantElectionProvider: ElectionProvider { /// Elect a new set of winners, but unlike [`ElectionProvider::elect`] which cannot enforce /// bounds, this trait method can enforce bounds on the amount of data provided by the @@ -410,7 +430,7 @@ pub trait InstantElectionProvider: ElectionProvider { pub struct NoElection(sp_std::marker::PhantomData); #[cfg(feature = "std")] -impl ElectionProvider +impl ElectionProviderBase for NoElection<(AccountId, BlockNumber, DataProvider)> where DataProvider: ElectionDataProvider, @@ -420,15 +440,22 @@ where type Error = &'static str; type DataProvider = DataProvider; - fn elect() -> Result, Self::Error> { - Err(" cannot do anything.") - } - fn ongoing() -> bool { false } } +#[cfg(feature = "std")] +impl ElectionProvider + for NoElection<(AccountId, BlockNumber, DataProvider)> +where + DataProvider: ElectionDataProvider, +{ + fn elect() -> Result, Self::Error> { + Err(" cannot do anything.") + } +} + /// A utility trait for something to implement `ElectionDataProvider` in a sensible way. /// /// This is generic over `AccountId` and it can represent a validator, a nominator, or any other diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 10c3519d03df6..88aa6ca7267a0 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -20,7 +20,8 @@ //! careful when using it onchain. use crate::{ - Debug, ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolver, WeightInfo, + Debug, ElectionDataProvider, ElectionProvider, ElectionProviderBase, InstantElectionProvider, + NposSolver, WeightInfo, }; use frame_support::{dispatch::DispatchClass, traits::Get}; use sp_npos_elections::*; @@ -133,15 +134,6 @@ fn elect_with( } impl ElectionProvider for UnboundedExecution { - type AccountId = ::AccountId; - type BlockNumber = ::BlockNumber; - type Error = Error; - type DataProvider = T::DataProvider; - - fn ongoing() -> bool { - false - } - fn elect() -> Result, Self::Error> { // This should not be called if not in `std` mode (and therefore neither in genesis nor in // testing) @@ -156,6 +148,17 @@ impl ElectionProvider for UnboundedExecution { } } +impl ElectionProviderBase for UnboundedExecution { + type AccountId = ::AccountId; + type BlockNumber = ::BlockNumber; + type Error = Error; + type DataProvider = T::DataProvider; + + fn ongoing() -> bool { + false + } +} + impl InstantElectionProvider for UnboundedExecution { fn elect_with_bounds( max_voters: usize, @@ -165,7 +168,7 @@ impl InstantElectionProvider for UnboundedExecution { } } -impl ElectionProvider for BoundedExecution { +impl ElectionProviderBase for BoundedExecution { type AccountId = ::AccountId; type BlockNumber = ::BlockNumber; type Error = Error; @@ -174,7 +177,9 @@ impl ElectionProvider for BoundedExecution { fn ongoing() -> bool { false } +} +impl ElectionProvider for BoundedExecution { fn elect() -> Result, Self::Error> { elect_with::(Some(T::VotersBound::get() as usize), Some(T::TargetsBound::get() as usize)) } diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index ed26d6b436e1d..8fdb7a79dd537 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -80,7 +80,7 @@ macro_rules! log { pub mod pallet { use super::*; use crate::types::*; - use frame_election_provider_support::ElectionProvider; + use frame_election_provider_support::ElectionProviderBase; use frame_support::{ pallet_prelude::*, traits::{Defensive, ReservableCurrency}, @@ -330,7 +330,8 @@ pub mod pallet { } } - if ::ElectionProvider::ongoing() { + if <::ElectionProvider as ElectionProviderBase>::ongoing() + { // NOTE: we assume `ongoing` does not consume any weight. // there is an ongoing election -- we better not do anything. Imagine someone is not // exposed anywhere in the last era, and the snapshot for the election is already diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index 4c4c5f9ff26fd..dc2c694d52956 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -104,7 +104,7 @@ parameter_types! { } pub struct MockElection; -impl frame_election_provider_support::ElectionProvider for MockElection { +impl frame_election_provider_support::ElectionProviderBase for MockElection { type AccountId = AccountId; type BlockNumber = BlockNumber; type DataProvider = Staking; @@ -113,7 +113,9 @@ impl frame_election_provider_support::ElectionProvider for MockElection { fn ongoing() -> bool { Ongoing::get() } +} +impl frame_election_provider_support::ElectionProvider for MockElection { fn elect() -> Result, Self::Error> { Err(()) } diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index dd2a9bf198f8d..514ded67ad38b 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -74,17 +74,16 @@ #![cfg_attr(not(feature = "std"), no_std)] +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; use sp_arithmetic::{traits::Zero, Normalizable, PerThing, Rational128, ThresholdOrd}; -use sp_core::RuntimeDebug; +use sp_core::{bounded::BoundedVec, RuntimeDebug}; use sp_std::{ cell::RefCell, cmp::Ordering, collections::btree_map::BTreeMap, prelude::*, rc::Rc, vec, }; -use codec::{Decode, Encode, MaxEncodedLen}; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; - #[cfg(test)] mod mock; #[cfg(test)] @@ -451,6 +450,11 @@ impl Default for Support { /// The main advantage of this is that it is encodable. pub type Supports = Vec<(A, Support)>; +/// Same as `Supports` bounded by `MaxWinners`. +/// +/// To note, the inner `Support` is still unbounded. +pub type BoundedSupports = BoundedVec<(A, Support), MaxWinners>; + /// Linkage from a winner to their [`Support`]. /// /// This is more helpful than a normal [`Supports`] as it allows faster error checking. From 427fd09bcb193c1e79dec85b1e207c718b686c35 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Thu, 29 Sep 2022 09:28:22 +0300 Subject: [PATCH 1220/1472] BEEFY: impl TypeInfo for SignedCommitment (#12382) --- primitives/beefy/src/commitment.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index 4880d4b69ab01..0e22c8d56d937 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -16,6 +16,7 @@ // limitations under the License. use codec::{Decode, Encode, Error, Input}; +use scale_info::TypeInfo; use sp_std::{cmp, prelude::*}; use crate::ValidatorSetId; @@ -39,7 +40,7 @@ pub mod known_payload_ids { /// Identifiers MUST be sorted by the [`BeefyPayloadId`] to allow efficient lookup of expected /// value. Duplicated identifiers are disallowed. It's okay for different implementations to only /// support a subset of possible values. -#[derive(Decode, Encode, Debug, PartialEq, Eq, Clone, Ord, PartialOrd, Hash)] +#[derive(Decode, Encode, Debug, PartialEq, Eq, Clone, Ord, PartialOrd, Hash, TypeInfo)] pub struct Payload(Vec<(BeefyPayloadId, Vec)>); impl Payload { @@ -80,7 +81,7 @@ impl Payload { /// height [block_number](Commitment::block_number). /// GRANDPA validators collect signatures on commitments and a stream of such signed commitments /// (see [SignedCommitment]) forms the BEEFY protocol. -#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] +#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, TypeInfo)] pub struct Commitment { /// A collection of payloads to be signed, see [`Payload`] for details. /// @@ -138,7 +139,7 @@ where /// Note that SCALE-encoding of the structure is optimized for size efficiency over the wire, /// please take a look at custom [`Encode`] and [`Decode`] implementations and /// `CompactSignedCommitment` struct. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, TypeInfo)] pub struct SignedCommitment { /// The commitment signatures are collected for. pub commitment: Commitment, From 61b9a4d1a8a9bf39c1d89a8dd02f82785c10860c Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 29 Sep 2022 23:48:10 +0800 Subject: [PATCH 1221/1472] Properly set the max proof size weight on defaults and tests (#12383) * Properly set the max proof size weight on defaults and tests * cargo fmt * Set proper max proof size for contracts pallet tests * Properly set max proof size for node * Properly set max proof size for frame system mock * Update test expectations * Update test expectations * Properly set max proof size for balances mock * Update test expectations * Update test expectations * Properly set max proof size for democracy mock * Properly set max proof size for scheduler mock * Properly set max proof size for fast unstake mock * Properly set max proof size for tx payment mock * Properly set max proof size for elections phragmen mock * Properly set max proof size for node template --- bin/node-template/runtime/src/lib.rs | 7 +- bin/node/runtime/src/impls.rs | 2 +- bin/node/runtime/src/lib.rs | 4 +- frame/balances/src/tests_composite.rs | 4 +- frame/balances/src/tests_local.rs | 4 +- frame/balances/src/tests_reentrancy.rs | 4 +- frame/contracts/src/tests.rs | 14 +- frame/democracy/src/tests.rs | 4 +- .../election-provider-multi-phase/src/lib.rs | 9 +- .../election-provider-multi-phase/src/mock.rs | 7 +- .../src/signed.rs | 9 +- .../src/unsigned.rs | 292 +++++++++++++++--- frame/elections-phragmen/src/lib.rs | 4 +- frame/executive/src/lib.rs | 5 +- frame/fast-unstake/src/mock.rs | 4 +- frame/grandpa/src/tests.rs | 3 +- frame/scheduler/src/mock.rs | 4 +- frame/system/src/extensions/check_weight.rs | 20 +- frame/system/src/limits.rs | 24 +- frame/system/src/mock.rs | 2 +- .../asset-tx-payment/src/tests.rs | 2 +- frame/transaction-payment/src/lib.rs | 2 +- 22 files changed, 323 insertions(+), 107 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index f801068b10fda..1d0e18d31bf80 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -139,8 +139,11 @@ parameter_types! { pub const BlockHashCount: BlockNumber = 2400; pub const Version: RuntimeVersion = VERSION; /// We allow for 2 seconds of compute with a 6 second average block time. - pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights - ::with_sensible_defaults(2u64 * WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::with_sensible_defaults( + (2u64 * WEIGHT_PER_SECOND).set_proof_size(u64::MAX), + NORMAL_DISPATCH_RATIO, + ); pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); pub const SS58Prefix: u8 = 42; diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index fb2f3cec65290..0f9ed6e275196 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -224,7 +224,7 @@ mod multiplier_tests { fn multiplier_can_grow_from_zero() { // if the min is too small, then this will not change, and we are doomed forever. // the weight is 1/100th bigger than target. - run_with_system_weight(target() * 101 / 100, || { + run_with_system_weight(target().set_ref_time(target().ref_time() * 101 / 100), || { let next = runtime_multiplier_update(min_multiplier()); assert!(next > min_multiplier(), "{:?} !>= {:?}", next, min_multiplier()); }) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index aa1a525bf095c..5e4fdb4748d15 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -170,8 +170,8 @@ const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used /// by Operational extrinsics. const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -/// We allow for 2 seconds of compute with a 6 second average block time. -const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND.saturating_mul(2); +/// We allow for 2 seconds of compute with a 6 second average block time, with maximum proof size. +const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND.saturating_mul(2).set_proof_size(u64::MAX); parameter_types! { pub const BlockHashCount: BlockNumber = 2400; diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 1e38d611773d4..f8a8fdd1851d4 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -47,7 +47,9 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); + frame_system::limits::BlockWeights::simple_max( + frame_support::weights::Weight::from_ref_time(1024).set_proof_size(u64::MAX), + ); pub static ExistentialDeposit: u64 = 0; } impl frame_system::Config for Test { diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index e080eafb66067..152a5da37410f 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -48,7 +48,9 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); + frame_system::limits::BlockWeights::simple_max( + frame_support::weights::Weight::from_ref_time(1024).set_proof_size(u64::MAX), + ); pub static ExistentialDeposit: u64 = 0; } impl frame_system::Config for Test { diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index fa2eb0e488e7d..90363140000e8 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -51,7 +51,9 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); + frame_system::limits::BlockWeights::simple_max( + frame_support::weights::Weight::from_ref_time(1024).set_proof_size(u64::MAX), + ); pub static ExistentialDeposit: u64 = 0; } impl frame_system::Config for Test { diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index a56e4f5564845..e5893c3dbd112 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -279,7 +279,9 @@ impl RegisteredChainExtension for TempStorageExtension { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2u64 * WEIGHT_PER_SECOND); + frame_system::limits::BlockWeights::simple_max( + (2u64 * WEIGHT_PER_SECOND).set_proof_size(u64::MAX), + ); pub static ExistentialDeposit: u64 = 1; } impl frame_system::Config for Test { @@ -413,7 +415,7 @@ pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]); pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]); -pub const GAS_LIMIT: Weight = Weight::from_ref_time(100_000_000_000); +pub const GAS_LIMIT: Weight = Weight::from_ref_time(100_000_000_000).set_proof_size(u64::MAX); pub struct ExtBuilder { existential_deposit: u64, @@ -628,7 +630,7 @@ fn deposit_event_max_value_limit() { RuntimeOrigin::signed(ALICE), addr.clone(), 0, - GAS_LIMIT * 2, // we are copying a huge buffer, + GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2), // we are copying a huge buffer, None, ::Schedule::get().limits.payload_len.encode(), )); @@ -769,7 +771,7 @@ fn storage_max_value_limit() { RuntimeOrigin::signed(ALICE), addr.clone(), 0, - GAS_LIMIT * 2, // we are copying a huge buffer + GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2), // we are copying a huge buffer None, ::Schedule::get().limits.payload_len.encode(), )); @@ -2543,7 +2545,7 @@ fn gas_estimation_nested_call_fixed_limit() { ALICE, addr_caller, 0, - Weight::from_ref_time(result.gas_required), + Weight::from_ref_time(result.gas_required).set_proof_size(u64::MAX), Some(result.storage_deposit.charge_or_zero()), input, false, @@ -2613,7 +2615,7 @@ fn gas_estimation_call_runtime() { ALICE, addr_caller, 0, - Weight::from_ref_time(result.gas_required), + Weight::from_ref_time(result.gas_required).set_proof_size(u64::MAX), None, call.encode(), false, diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 17b35ee3c38cd..03d7216fd5aaa 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -78,7 +78,9 @@ impl Contains for BaseFilter { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(1_000_000)); + frame_system::limits::BlockWeights::simple_max( + Weight::from_ref_time(1_000_000).set_proof_size(u64::MAX), + ); } impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 649aec30c58b3..fb17bd25ea541 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1011,10 +1011,8 @@ pub mod pallet { // unlikely to ever return an error: if phase is signed, snapshot will exist. let size = Self::snapshot_metadata().ok_or(Error::::MissingSnapshotMetadata)?; - // TODO: account for proof size weight ensure!( - Self::solution_weight_of(&raw_solution, size).ref_time() < - T::SignedMaxWeight::get().ref_time(), + Self::solution_weight_of(&raw_solution, size).all_lt(T::SignedMaxWeight::get()), Error::::SignedTooMuchWeight, ); @@ -2342,9 +2340,8 @@ mod tests { }; let mut active = 1; - // TODO: account for proof size weight - while weight_with(active).ref_time() <= - ::BlockWeights::get().max_block.ref_time() || + while weight_with(active) + .all_lte(::BlockWeights::get().max_block) || active == all_voters { active += 1; diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index c1c53a3980676..d3082be0cf750 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -26,7 +26,7 @@ pub use frame_support::{assert_noop, assert_ok, pallet_prelude::GetDefault}; use frame_support::{ bounded_vec, parameter_types, traits::{ConstU32, Hooks}, - weights::Weight, + weights::{constants, Weight}, BoundedVec, }; use multi_phase::unsigned::{IndexAssignmentOf, VoterOf}; @@ -227,7 +227,10 @@ const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); parameter_types! { pub const ExistentialDeposit: u64 = 1; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights - ::with_sensible_defaults(2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); + ::with_sensible_defaults( + Weight::from_components(2u64 * constants::WEIGHT_PER_SECOND.ref_time(), u64::MAX), + NORMAL_DISPATCH_RATIO, + ); } impl pallet_balances::Config for Runtime { diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 1cf071e6796f1..2e01d99be0a42 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -957,7 +957,7 @@ mod tests { #[test] fn cannot_consume_too_much_future_weight() { ExtBuilder::default() - .signed_weight(Weight::from_ref_time(40)) + .signed_weight(Weight::from_ref_time(40).set_proof_size(u64::MAX)) .mock_weight_info(MockedWeightInfo::Basic) .build_and_execute(|| { roll_to(15); @@ -973,11 +973,14 @@ mod tests { // default solution will have 5 edges (5 * 5 + 10) assert_eq!(solution_weight, Weight::from_ref_time(35)); assert_eq!(raw.solution.voter_count(), 5); - assert_eq!(::SignedMaxWeight::get(), Weight::from_ref_time(40)); + assert_eq!( + ::SignedMaxWeight::get(), + Weight::from_ref_time(40).set_proof_size(u64::MAX) + ); assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(raw.clone()))); - ::set(Weight::from_ref_time(30)); + ::set(Weight::from_ref_time(30).set_proof_size(u64::MAX)); // note: resubmitting the same solution is technically okay as long as the queue has // space. diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 281ac37421174..025ff832bb08a 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -638,8 +638,7 @@ impl Miner { }; let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result { - // TODO: account for proof size weight - if current_weight.ref_time() < max_weight.ref_time() { + if current_weight.all_lt(max_weight) { let next_voters = voters.checked_add(step); match next_voters { Some(voters) if voters < max_voters => Ok(voters), @@ -674,8 +673,7 @@ impl Miner { // Time to finish. We might have reduced less than expected due to rounding error. Increase // one last time if we have any room left, the reduce until we are sure we are below limit. - // TODO: account for proof size weight - while voters < max_voters && weight_with(voters + 1).ref_time() < max_weight.ref_time() { + while voters < max_voters && weight_with(voters + 1).all_lt(max_weight) { voters += 1; } while voters.checked_sub(1).is_some() && weight_with(voters).any_gt(max_weight) { @@ -683,9 +681,8 @@ impl Miner { } let final_decision = voters.min(size.voters); - // TODO: account for proof size weight debug_assert!( - weight_with(final_decision).ref_time() <= max_weight.ref_time(), + weight_with(final_decision).all_lte(max_weight), "weight_with({}) <= {}", final_decision, max_weight, @@ -703,151 +700,346 @@ mod max_weight { fn find_max_voter_binary_search_works() { let w = SolutionOrSnapshotSize { voters: 10, targets: 0 }; MockWeightInfo::set(crate::mock::MockedWeightInfo::Complex); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::zero()), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1)), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(999)), 0); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::zero().set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(999).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1000).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1001).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1990)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1990).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1999).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2000).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2001).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2010)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2010).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2990)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2990).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2999).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(3000).set_proof_size(u64::MAX) + ), 3 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3333)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(3333).set_proof_size(u64::MAX) + ), 3 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(5500)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(5500).set_proof_size(u64::MAX) + ), 5 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(7777)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(7777).set_proof_size(u64::MAX) + ), 7 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(9999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(9999).set_proof_size(u64::MAX) + ), 9 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(10_000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(10_000).set_proof_size(u64::MAX) + ), 10 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(10_999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(10_999).set_proof_size(u64::MAX) + ), 10 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(11_000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(11_000).set_proof_size(u64::MAX) + ), 10 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(22_000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(22_000).set_proof_size(u64::MAX) + ), 10 ); let w = SolutionOrSnapshotSize { voters: 1, targets: 0 }; - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(0)), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1)), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(999)), 0); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(0).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(999).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1000).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1001).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1990)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1990).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1999).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2000).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2001).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2010)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2010).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3333)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(3333).set_proof_size(u64::MAX) + ), 1 ); let w = SolutionOrSnapshotSize { voters: 2, targets: 0 }; - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(0)), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1)), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(999)), 0); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(0).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(999).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1000).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1001).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1999).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2000).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2001).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2010)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2010).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3333)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(3333).set_proof_size(u64::MAX) + ), 2 ); } @@ -1131,7 +1323,7 @@ mod tests { #[test] fn miner_trims_weight() { ExtBuilder::default() - .miner_weight(Weight::from_ref_time(100)) + .miner_weight(Weight::from_ref_time(100).set_proof_size(u64::MAX)) .mock_weight_info(crate::mock::MockedWeightInfo::Basic) .build_and_execute(|| { roll_to(25); @@ -1149,7 +1341,7 @@ mod tests { assert_eq!(raw.solution.voter_count(), 5); // now reduce the max weight - ::set(Weight::from_ref_time(25)); + ::set(Weight::from_ref_time(25).set_proof_size(u64::MAX)); let (raw, witness) = MultiPhase::mine_solution().unwrap(); let solution_weight = ::solution_weight( diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 0616087d975e8..165a8fcab429b 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1174,7 +1174,9 @@ mod tests { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); + frame_system::limits::BlockWeights::simple_max( + frame_support::weights::Weight::from_ref_time(1024).set_proof_size(u64::MAX), + ); } impl frame_system::Config for Test { diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 014c7a2bc02a6..b7884efccf685 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -459,8 +459,7 @@ where let max_weight = >::get().max_block; let remaining_weight = max_weight.saturating_sub(weight.total()); - // TODO: account for proof size weight - if remaining_weight.ref_time() > 0 { + if remaining_weight.all_gt(Weight::zero()) { let used_weight = >::on_idle( block_number, remaining_weight, @@ -768,7 +767,7 @@ mod tests { frame_system::limits::BlockWeights::builder() .base_block(Weight::from_ref_time(10)) .for_class(DispatchClass::all(), |weights| weights.base_extrinsic = Weight::from_ref_time(5)) - .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = Weight::from_ref_time(1024).into()) + .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = Weight::from_ref_time(1024).set_proof_size(u64::MAX).into()) .build_or_panic(); pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 10, diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index dc2c694d52956..71fc2d4ba905a 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -32,7 +32,9 @@ pub type T = Runtime; parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2u64 * WEIGHT_PER_SECOND); + frame_system::limits::BlockWeights::simple_max( + (2u64 * WEIGHT_PER_SECOND).set_proof_size(u64::MAX), + ); } impl frame_system::Config for Runtime { diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 5d2ebdf29cb6b..626decd12821e 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -856,8 +856,7 @@ fn valid_equivocation_reports_dont_pay_fees() { .get_dispatch_info(); // it should have non-zero weight and the fee has to be paid. - // TODO: account for proof size weight - assert!(info.weight.ref_time() > 0); + assert!(info.weight.any_gt(Weight::zero())); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 6f6667590a6c3..6aaad13e48183 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -118,7 +118,9 @@ impl Contains for BaseFilter { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(2_000_000_000_000)); + frame_system::limits::BlockWeights::simple_max( + Weight::from_ref_time(2_000_000_000_000).set_proof_size(u64::MAX), + ); } impl system::Config for Test { type BaseCallFilter = BaseFilter; diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index 15a88913cd337..5c3b80f59bfa8 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -310,7 +310,7 @@ mod tests { check(|max, len| { assert_ok!(CheckWeight::::do_pre_dispatch(max, len)); assert_eq!(System::block_weight().total(), Weight::MAX); - assert!(System::block_weight().total().all_gt(block_weight_limit())); + assert!(System::block_weight().total().ref_time() > block_weight_limit().ref_time()); }); check(|max, len| { assert_ok!(CheckWeight::::do_validate(max, len)); @@ -367,7 +367,7 @@ mod tests { new_test_ext().execute_with(|| { System::register_extra_weight_unchecked(Weight::MAX, DispatchClass::Normal); assert_eq!(System::block_weight().total(), Weight::MAX); - assert!(System::block_weight().total().all_gt(block_weight_limit())); + assert!(System::block_weight().total().ref_time() > block_weight_limit().ref_time()); }); } @@ -392,8 +392,8 @@ mod tests { assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); assert_eq!(System::block_weight().total(), Weight::from_ref_time(768)); assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); - assert_eq!(block_weight_limit(), Weight::from_ref_time(1024)); - assert_eq!(System::block_weight().total(), block_weight_limit()); + assert_eq!(block_weight_limit(), Weight::from_ref_time(1024).set_proof_size(u64::MAX)); + assert_eq!(System::block_weight().total(), block_weight_limit().set_proof_size(0)); // Checking single extrinsic should not take current block weight into account. assert_eq!(CheckWeight::::check_extrinsic_weight(&rest_operational), Ok(())); }); @@ -417,8 +417,8 @@ mod tests { // Extra 20 here from block execution + base extrinsic weight assert_eq!(System::block_weight().total(), Weight::from_ref_time(266)); assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); - assert_eq!(block_weight_limit(), Weight::from_ref_time(1024)); - assert_eq!(System::block_weight().total(), block_weight_limit()); + assert_eq!(block_weight_limit(), Weight::from_ref_time(1024).set_proof_size(u64::MAX)); + assert_eq!(System::block_weight().total(), block_weight_limit().set_proof_size(0)); }); } @@ -669,7 +669,7 @@ mod tests { assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); assert_eq!(System::block_weight().total(), Weight::from_ref_time(768)); assert_ok!(CheckWeight::::do_pre_dispatch(&mandatory, len)); - assert_eq!(block_weight_limit(), Weight::from_ref_time(1024)); + assert_eq!(block_weight_limit(), Weight::from_ref_time(1024).set_proof_size(u64::MAX)); assert_eq!(System::block_weight().total(), Weight::from_ref_time(1024 + 768)); assert_eq!(CheckWeight::::check_extrinsic_weight(&mandatory), Ok(())); }); @@ -682,11 +682,11 @@ mod tests { .base_block(Weight::zero()) .for_class(DispatchClass::non_mandatory(), |w| { w.base_extrinsic = Weight::zero(); - w.max_total = Some(Weight::from_ref_time(20)); + w.max_total = Some(Weight::from_ref_time(20).set_proof_size(u64::MAX)); }) .for_class(DispatchClass::Mandatory, |w| { w.base_extrinsic = Weight::zero(); - w.reserved = Some(Weight::from_ref_time(5)); + w.reserved = Some(Weight::from_ref_time(5).set_proof_size(u64::MAX)); w.max_total = None; }) .build_or_panic(); @@ -695,7 +695,7 @@ mod tests { DispatchClass::Operational => Weight::from_ref_time(10), DispatchClass::Mandatory => Weight::zero(), }); - assert_eq!(maximum_weight.max_block, all_weight.total()); + assert_eq!(maximum_weight.max_block, all_weight.total().set_proof_size(u64::MAX)); // fits into reserved let mandatory1 = DispatchInfo { diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index cfc1d261baa01..07ad240afe159 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -207,7 +207,10 @@ pub struct BlockWeights { impl Default for BlockWeights { fn default() -> Self { - Self::with_sensible_defaults(1u64 * constants::WEIGHT_PER_SECOND, DEFAULT_NORMAL_RATIO) + Self::with_sensible_defaults( + Weight::from_components(constants::WEIGHT_PER_SECOND.ref_time(), u64::MAX), + DEFAULT_NORMAL_RATIO, + ) } } @@ -224,7 +227,6 @@ impl BlockWeights { } let mut error = ValidationErrors::default(); - // TODO: account for proof size weight in the assertions below for class in DispatchClass::all() { let weights = self.per_class.get(*class); let max_for_class = or_max(weights.max_total); @@ -233,16 +235,18 @@ impl BlockWeights { // Make sure that if total is set it's greater than base_block && // base_for_class error_assert!( - (max_for_class.ref_time() > self.base_block.ref_time() && max_for_class.ref_time() > base_for_class.ref_time()) - || max_for_class.ref_time() == 0, + (max_for_class.all_gt(self.base_block) && max_for_class.all_gt(base_for_class)) + || max_for_class == Weight::zero(), &mut error, "[{:?}] {:?} (total) has to be greater than {:?} (base block) & {:?} (base extrinsic)", class, max_for_class, self.base_block, base_for_class, ); // Max extrinsic can't be greater than max_for_class. error_assert!( - weights.max_extrinsic.unwrap_or(Weight::zero()).ref_time() <= - max_for_class.saturating_sub(base_for_class).ref_time(), + weights + .max_extrinsic + .unwrap_or(Weight::zero()) + .all_lte(max_for_class.saturating_sub(base_for_class)), &mut error, "[{:?}] {:?} (max_extrinsic) can't be greater than {:?} (max for class)", class, @@ -251,14 +255,14 @@ impl BlockWeights { ); // Max extrinsic should not be 0 error_assert!( - weights.max_extrinsic.unwrap_or_else(Weight::max_value).ref_time() > 0, + weights.max_extrinsic.unwrap_or_else(Weight::max_value).all_gt(Weight::zero()), &mut error, "[{:?}] {:?} (max_extrinsic) must not be 0. Check base cost and average initialization cost.", class, weights.max_extrinsic, ); // Make sure that if reserved is set it's greater than base_for_class. error_assert!( - reserved.ref_time() > base_for_class.ref_time() || reserved.ref_time() == 0, + reserved.all_gt(base_for_class) || reserved == Weight::zero(), &mut error, "[{:?}] {:?} (reserved) has to be greater than {:?} (base extrinsic) if set", class, @@ -267,7 +271,7 @@ impl BlockWeights { ); // Make sure max block is greater than max_total if it's set. error_assert!( - self.max_block.ref_time() >= weights.max_total.unwrap_or(Weight::zero()).ref_time(), + self.max_block.all_gte(weights.max_total.unwrap_or(Weight::zero())), &mut error, "[{:?}] {:?} (max block) has to be greater than {:?} (max for class)", class, @@ -276,7 +280,7 @@ impl BlockWeights { ); // Make sure we can fit at least one extrinsic. error_assert!( - self.max_block.ref_time() > (base_for_class + self.base_block).ref_time(), + self.max_block.all_gt(base_for_class + self.base_block), &mut error, "[{:?}] {:?} (max block) must fit at least one extrinsic {:?} (base weight)", class, diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index b6fc121612050..d31a1b08667e5 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -41,7 +41,7 @@ frame_support::construct_runtime!( ); const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -const MAX_BLOCK_WEIGHT: Weight = Weight::from_ref_time(1024); +const MAX_BLOCK_WEIGHT: Weight = Weight::from_ref_time(1024).set_proof_size(u64::MAX); parameter_types! { pub Version: RuntimeVersion = RuntimeVersion { diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index cdf7d17898145..e775f3aa92990 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -71,7 +71,7 @@ impl Get for BlockWeights { weights.base_extrinsic = ExtrinsicBaseWeight::get().into(); }) .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = Weight::from_ref_time(1024).into(); + weights.max_total = Weight::from_ref_time(1024).set_proof_size(u64::MAX).into(); }) .build_or_panic() } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 1ad6a2b3b3b6f..80297d1a0d362 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -889,7 +889,7 @@ mod tests { weights.base_extrinsic = ExtrinsicBaseWeight::get().into(); }) .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = Weight::from_ref_time(1024).into(); + weights.max_total = Weight::from_ref_time(1024).set_proof_size(u64::MAX).into(); }) .build_or_panic() } From c2026ca6e9b2a24d8ae1a05c5b3784ffa0748946 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 30 Sep 2022 11:14:13 +0800 Subject: [PATCH 1222/1472] Carry over where clauses defined in Config to Call and Hook (#12388) --- frame/support/procedural/src/pallet/expand/call.rs | 2 +- frame/support/procedural/src/pallet/expand/hooks.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 39d16109aa8fa..6b166e6726d38 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -32,7 +32,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { (span, where_clause, methods, docs) }, - None => (def.item.span(), None, Vec::new(), Vec::new()), + None => (def.item.span(), def.config.where_clause.clone(), Vec::new(), Vec::new()), }; let frame_support = &def.frame_support; let frame_system = &def.frame_system; diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index 48d4aec436d40..d8d009cf3c940 100644 --- a/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/frame/support/procedural/src/pallet/expand/hooks.rs @@ -26,7 +26,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { let has_runtime_upgrade = hooks.has_runtime_upgrade; (where_clause, span, has_runtime_upgrade) }, - None => (None, def.pallet_struct.attr_span, false), + None => (def.config.where_clause.clone(), def.pallet_struct.attr_span, false), }; let frame_support = &def.frame_support; From dbb72f3fd98253b72c0090375b738b9d00995090 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Fri, 30 Sep 2022 12:06:46 +0200 Subject: [PATCH 1223/1472] unsafe_pruning flag removed (#12385) --- client/cli/src/config.rs | 11 ----------- client/cli/src/params/import_params.rs | 12 ------------ 2 files changed, 23 deletions(-) diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index fad2ec7bc4a93..77689708a231f 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -659,17 +659,6 @@ pub trait CliConfiguration: Sized { } } - if self.import_params().map_or(false, |p| { - #[allow(deprecated)] - p.unsafe_pruning - }) { - // according to https://github.com/substrate/issues/8103; - warn!( - "WARNING: \"--unsafe-pruning\" CLI-flag is deprecated and has no effect. \ - In future builds it will be removed, and providing this flag will lead to an error." - ); - } - Ok(()) } } diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index c851050838965..3cd9fd83bd31b 100644 --- a/client/cli/src/params/import_params.rs +++ b/client/cli/src/params/import_params.rs @@ -41,18 +41,6 @@ pub struct ImportParams { #[clap(flatten)] pub database_params: DatabaseParams, - /// THIS IS A DEPRECATED CLI-ARGUMENT. - /// - /// It has been preserved in order to not break the compatibility with the existing scripts. - /// Enabling this option will lead to a runtime warning. - /// In future this option will be removed completely, thus specifying it will lead to a start - /// up error. - /// - /// Details: - #[clap(long)] - #[deprecated = "According to https://github.com/paritytech/substrate/issues/8103"] - pub unsafe_pruning: bool, - /// Method for executing Wasm runtime code. #[clap( long = "wasm-execution", From 952030cfa6f11be6aef938e5359064c4cf6b30a9 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Fri, 30 Sep 2022 13:46:48 +0300 Subject: [PATCH 1224/1472] pallet-mmr: generate historical proofs (#12324) * BEEFY: generate historical proofs Signed-off-by: Serban Iorga * Update frame/merkle-mountain-range/rpc/src/lib.rs Co-authored-by: Adrian Catangiu * Update primitives/merkle-mountain-range/src/lib.rs Co-authored-by: Adrian Catangiu * Update frame/merkle-mountain-range/src/lib.rs Co-authored-by: Adrian Catangiu * cargo fmt * fix off-by-one in leaves powerset generation * test all possible mmr sizes for historical proofs * remove now redundant simple_historical_proof * cargo fmt Signed-off-by: Serban Iorga Co-authored-by: Adrian Catangiu Co-authored-by: Robert Hambrock --- bin/node/runtime/src/lib.rs | 39 ++- client/beefy/src/tests.rs | 7 + frame/merkle-mountain-range/rpc/src/lib.rs | 49 ++++ frame/merkle-mountain-range/src/lib.rs | 22 +- frame/merkle-mountain-range/src/tests.rs | 276 +++++++++++++++++++- primitives/merkle-mountain-range/src/lib.rs | 11 +- 6 files changed, 379 insertions(+), 25 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 5e4fdb4748d15..4fa4049e22682 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2011,10 +2011,7 @@ impl_runtime_apis! { } } - impl pallet_mmr::primitives::MmrApi< - Block, - mmr::Hash, - > for Runtime { + impl pallet_mmr::primitives::MmrApi for Runtime { fn generate_proof(leaf_index: pallet_mmr::primitives::LeafIndex) -> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof), mmr::Error> { @@ -2049,11 +2046,35 @@ impl_runtime_apis! { Ok(Mmr::mmr_root()) } - fn generate_batch_proof(leaf_indices: Vec) - -> Result<(Vec, mmr::BatchProof), mmr::Error> - { - Mmr::generate_batch_proof(leaf_indices) - .map(|(leaves, proof)| (leaves.into_iter().map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)).collect(), proof)) + fn generate_batch_proof( + leaf_indices: Vec, + ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { + Mmr::generate_batch_proof(leaf_indices).map(|(leaves, proof)| { + ( + leaves + .into_iter() + .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)) + .collect(), + proof, + ) + }) + } + + fn generate_historical_batch_proof( + leaf_indices: Vec, + leaves_count: pallet_mmr::primitives::LeafIndex, + ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { + Mmr::generate_historical_batch_proof(leaf_indices, leaves_count).map( + |(leaves, proof)| { + ( + leaves + .into_iter() + .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)) + .collect(), + proof, + ) + }, + ) } fn verify_batch_proof(leaves: Vec, proof: mmr::BatchProof) diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 26c85592ecb85..3e49f4e05cc91 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -277,6 +277,13 @@ macro_rules! create_test_api { unimplemented!() } + fn generate_historical_batch_proof( + _leaf_indices: Vec, + _leaves_count: LeafIndex + ) -> Result<(Vec, BatchProof), MmrError> { + unimplemented!() + } + fn verify_batch_proof(_leaves: Vec, _proof: BatchProof) -> Result<(), MmrError> { unimplemented!() } diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 75032d40f492a..e939ff8ae7cd0 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -128,6 +128,31 @@ pub trait MmrApi { leaf_indices: Vec, at: Option, ) -> RpcResult>; + + /// Generate a MMR proof for the given `leaf_indices` of the MMR that had `leaves_count` leaves. + /// + /// This method calls into a runtime with MMR pallet included and attempts to generate + /// a MMR proof for the set of leaves at the given `leaf_indices` with MMR fixed to the state + /// with exactly `leaves_count` leaves. `leaves_count` must be larger than all `leaf_indices` + /// for the function to succeed. + /// + /// Optionally, a block hash at which the runtime should be queried can be specified. + /// Note that specifying the block hash isn't super-useful here, unless you're generating + /// proof using non-finalized blocks where there are several competing forks. That's because + /// MMR state will be fixed to the state with `leaves_count`, which already points to some + /// historical block. + /// + /// Returns the leaves and a proof for these leaves (compact encoding, i.e. hash of + /// the leaves). Both parameters are SCALE-encoded. + /// The order of entries in the `leaves` field of the returned struct + /// is the same as the order of the entries in `leaf_indices` supplied + #[method(name = "mmr_generateHistoricalBatchProof")] + fn generate_historical_batch_proof( + &self, + leaf_indices: Vec, + leaves_count: LeafIndex, + at: Option, + ) -> RpcResult>; } /// MMR RPC methods. @@ -192,6 +217,30 @@ where Ok(LeafBatchProof::new(block_hash, leaves, proof)) } + + fn generate_historical_batch_proof( + &self, + leaf_indices: Vec, + leaves_count: LeafIndex, + at: Option<::Hash>, + ) -> RpcResult::Hash>> { + let api = self.client.runtime_api(); + let block_hash = at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash); + + let (leaves, proof) = api + .generate_historical_batch_proof_with_context( + &BlockId::hash(block_hash), + sp_core::ExecutionContext::OffchainCall(None), + leaf_indices, + leaves_count, + ) + .map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; + + Ok(LeafBatchProof::new(block_hash, leaves, proof)) + } } /// Converts a mmr-specific error into a [`CallError`]. diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 9f989847af0f9..8b4f2b60bc198 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -330,7 +330,27 @@ impl, I: 'static> Pallet { (Vec>, primitives::BatchProof<>::Hash>), primitives::Error, > { - let mmr: ModuleMmr = mmr::Mmr::new(Self::mmr_leaves()); + Self::generate_historical_batch_proof(leaf_indices, Self::mmr_leaves()) + } + + /// Generate a MMR proof for the given `leaf_indices` for the MMR of `leaves_count` size. + /// + /// Note this method can only be used from an off-chain context + /// (Offchain Worker or Runtime API call), since it requires + /// all the leaves to be present. + /// It may return an error or panic if used incorrectly. + pub fn generate_historical_batch_proof( + leaf_indices: Vec, + leaves_count: LeafIndex, + ) -> Result< + (Vec>, primitives::BatchProof<>::Hash>), + primitives::Error, + > { + if leaves_count > Self::mmr_leaves() { + return Err(Error::InvalidLeavesCount) + } + + let mmr: ModuleMmr = mmr::Mmr::new(leaves_count); mmr.generate_batch_proof(leaf_indices) } diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index d6886f90a5da7..bcb775ba02819 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -227,7 +227,8 @@ fn should_generate_proofs_correctly() { let _ = env_logger::try_init(); let mut ext = new_test_ext(); // given - ext.execute_with(|| add_blocks(7)); + let num_blocks: u64 = 7; + ext.execute_with(|| add_blocks(num_blocks as usize)); ext.persist_offchain_overlay(); // Try to generate proofs now. This requires the offchain extensions to be present @@ -241,6 +242,23 @@ fn should_generate_proofs_correctly() { crate::Pallet::::generate_batch_proof(vec![leaf_index]).unwrap() }) .collect::>(); + // when generate historical proofs for all leaves + let historical_proofs = (0_u64..crate::NumberOfLeaves::::get()) + .into_iter() + .map(|leaf_index| { + let mut proofs = vec![]; + for leaves_count in leaf_index + 1..=num_blocks { + proofs.push( + crate::Pallet::::generate_historical_batch_proof( + vec![leaf_index], + leaves_count, + ) + .unwrap(), + ) + } + proofs + }) + .collect::>(); // then assert_eq!( @@ -258,6 +276,79 @@ fn should_generate_proofs_correctly() { } ) ); + assert_eq!( + historical_proofs[0][0], + ( + vec![Compact::new(((0, H256::repeat_byte(1)).into(), LeafData::new(1).into(),))], + BatchProof { leaf_indices: vec![0], leaf_count: 1, items: vec![] } + ) + ); + + // D + // / \ + // / \ + // A B C + // / \ / \ / \ + // 1 2 3 4 5 6 7 + // + // we're proving 3 => we need { 4, A, C++7 } + assert_eq!( + proofs[2], + ( + vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], + BatchProof { + leaf_indices: vec![2], + leaf_count: 7, + items: vec![ + hex("1b14c1dc7d3e4def11acdf31be0584f4b85c3673f1ff72a3af467b69a3b0d9d0"), + hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854"), + hex("dca421199bdcc55bb773c6b6967e8d16675de69062b52285ca63685241fdf626"), + ], + } + ) + ); + // A + // / \ + // 1 2 3 + // + // we're proving 3 => we need { A } + assert_eq!( + historical_proofs[2][0], + ( + vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], + BatchProof { + leaf_indices: vec![2], + leaf_count: 3, + items: vec![hex( + "672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854" + ),], + } + ) + ); + // D + // / \ + // / \ + // A B + // / \ / \ + // 1 2 3 4 5 + // we're proving 3 => we need { 4, A, 5 } + assert_eq!( + historical_proofs[2][2], + ( + vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], + BatchProof { + leaf_indices: vec![2], + leaf_count: 5, + items: vec![ + hex("1b14c1dc7d3e4def11acdf31be0584f4b85c3673f1ff72a3af467b69a3b0d9d0"), + hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854"), + hex("3b031d22e24f1126c8f7d2f394b663f9b960ed7abbedb7152e17ce16112656d0") + ], + } + ) + ); + assert_eq!(historical_proofs[2][4], proofs[2]); + assert_eq!( proofs[4], ( @@ -273,6 +364,21 @@ fn should_generate_proofs_correctly() { } ) ); + assert_eq!( + historical_proofs[4][0], + ( + vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], + BatchProof { + leaf_indices: vec![4], + leaf_count: 5, + items: vec![hex( + "ae88a0825da50e953e7a359c55fe13c8015e48d03d301b8bdfc9193874da9252" + ),], + } + ) + ); + assert_eq!(historical_proofs[4][2], proofs[4]); + assert_eq!( proofs[6], ( @@ -287,6 +393,7 @@ fn should_generate_proofs_correctly() { } ) ); + assert_eq!(historical_proofs[6][0], proofs[6]); }); } @@ -302,9 +409,8 @@ fn should_generate_batch_proof_correctly() { // to retrieve full leaf data. register_offchain_ext(&mut ext); ext.execute_with(|| { - // when generate proofs for all leaves + // when generate proofs for a batch of leaves let (.., proof) = crate::Pallet::::generate_batch_proof(vec![0, 4, 5]).unwrap(); - // then assert_eq!( proof, @@ -318,6 +424,28 @@ fn should_generate_batch_proof_correctly() { ], } ); + + // when generate historical proofs for a batch of leaves + let (.., historical_proof) = + crate::Pallet::::generate_historical_batch_proof(vec![0, 4, 5], 6).unwrap(); + // then + assert_eq!( + historical_proof, + BatchProof { + leaf_indices: vec![0, 4, 5], + leaf_count: 6, + items: vec![ + hex("ad4cbc033833612ccd4626d5f023b9dfc50a35e838514dd1f3c86f8506728705"), + hex("cb24f4614ad5b2a5430344c99545b421d9af83c46fd632d70a332200884b4d46"), + ], + } + ); + + // when generate historical proofs for a batch of leaves + let (.., historical_proof) = + crate::Pallet::::generate_historical_batch_proof(vec![0, 4, 5], 7).unwrap(); + // then + assert_eq!(historical_proof, proof); }); } @@ -338,11 +466,33 @@ fn should_verify() { // when crate::Pallet::::generate_batch_proof(vec![5]).unwrap() }); + let (simple_historical_leaves, simple_historical_proof5) = ext.execute_with(|| { + // when + crate::Pallet::::generate_historical_batch_proof(vec![5], 6).unwrap() + }); + let (advanced_historical_leaves, advanced_historical_proof5) = ext.execute_with(|| { + // when + crate::Pallet::::generate_historical_batch_proof(vec![5], 7).unwrap() + }); ext.execute_with(|| { add_blocks(7); // then assert_eq!(crate::Pallet::::verify_leaves(leaves, proof5), Ok(())); + assert_eq!( + crate::Pallet::::verify_leaves( + simple_historical_leaves, + simple_historical_proof5 + ), + Ok(()) + ); + assert_eq!( + crate::Pallet::::verify_leaves( + advanced_historical_leaves, + advanced_historical_proof5 + ), + Ok(()) + ); }); } @@ -350,16 +500,40 @@ fn should_verify() { fn should_verify_batch_proofs() { fn generate_and_verify_batch_proof( ext: &mut sp_io::TestExternalities, - leaves: &Vec, + leaf_indices: &Vec, blocks_to_add: usize, ) { - let (leaves, proof) = ext - .execute_with(|| crate::Pallet::::generate_batch_proof(leaves.to_vec()).unwrap()); + let (leaves, proof) = ext.execute_with(|| { + crate::Pallet::::generate_batch_proof(leaf_indices.to_vec()).unwrap() + }); + + let mmr_size = ext.execute_with(|| crate::Pallet::::mmr_leaves()); + let min_mmr_size = leaf_indices.iter().max().unwrap() + 1; + + // generate historical proofs for all possible mmr sizes, + // lower bound being index of highest leaf to be proven + let historical_proofs = (min_mmr_size..=mmr_size) + .map(|mmr_size| { + ext.execute_with(|| { + crate::Pallet::::generate_historical_batch_proof( + leaf_indices.to_vec(), + mmr_size, + ) + .unwrap() + }) + }) + .collect::>(); ext.execute_with(|| { add_blocks(blocks_to_add); // then assert_eq!(crate::Pallet::::verify_leaves(leaves, proof), Ok(())); + historical_proofs.iter().for_each(|(leaves, proof)| { + assert_eq!( + crate::Pallet::::verify_leaves(leaves.clone(), proof.clone()), + Ok(()) + ); + }); }) } @@ -378,7 +552,7 @@ fn should_verify_batch_proofs() { ext.persist_offchain_overlay(); // generate powerset (skipping empty set) of all possible leaf combinations for mmr size n - let leaves_set: Vec> = (0..n).into_iter().powerset().skip(1).collect(); + let leaves_set: Vec> = (0..=n).into_iter().powerset().skip(1).collect(); leaves_set.iter().for_each(|leaves_subset| { generate_and_verify_batch_proof(&mut ext, leaves_subset, 0); @@ -393,7 +567,7 @@ fn should_verify_batch_proofs() { ext.persist_offchain_overlay(); // generate all possible 2-leaf combinations for mmr size n - let leaves_set: Vec> = (0..n).into_iter().combinations(2).collect(); + let leaves_set: Vec> = (0..=n).into_iter().combinations(2).collect(); leaves_set.iter().for_each(|leaves_subset| { generate_and_verify_batch_proof(&mut ext, leaves_subset, 0); @@ -414,7 +588,13 @@ fn verification_should_be_stateless() { // Start off with chain initialisation and storing indexing data off-chain // (MMR Leafs) let mut ext = new_test_ext(); - ext.execute_with(|| add_blocks(7)); + let (root_6, root_7) = ext.execute_with(|| { + add_blocks(6); + let root_6 = crate::Pallet::::mmr_root_hash(); + add_blocks(1); + let root_7 = crate::Pallet::::mmr_root_hash(); + (root_6, root_7) + }); ext.persist_offchain_overlay(); // Try to generate proof now. This requires the offchain extensions to be present @@ -424,12 +604,27 @@ fn verification_should_be_stateless() { // when crate::Pallet::::generate_batch_proof(vec![5]).unwrap() }); - let root = ext.execute_with(|| crate::Pallet::::mmr_root_hash()); + let (_, historical_proof5) = ext.execute_with(|| { + // when + crate::Pallet::::generate_historical_batch_proof(vec![5], 6).unwrap() + }); // Verify proof without relying on any on-chain data. let leaf = crate::primitives::DataOrHash::Data(leaves[0].clone()); assert_eq!( - crate::verify_leaves_proof::<::Hashing, _>(root, vec![leaf], proof5), + crate::verify_leaves_proof::<::Hashing, _>( + root_7, + vec![leaf.clone()], + proof5 + ), + Ok(()) + ); + assert_eq!( + crate::verify_leaves_proof::<::Hashing, _>( + root_6, + vec![leaf], + historical_proof5 + ), Ok(()) ); } @@ -441,7 +636,13 @@ fn should_verify_batch_proof_statelessly() { // Start off with chain initialisation and storing indexing data off-chain // (MMR Leafs) let mut ext = new_test_ext(); - ext.execute_with(|| add_blocks(7)); + let (root_6, root_7) = ext.execute_with(|| { + add_blocks(6); + let root_6 = crate::Pallet::::mmr_root_hash(); + add_blocks(1); + let root_7 = crate::Pallet::::mmr_root_hash(); + (root_6, root_7) + }); ext.persist_offchain_overlay(); // Try to generate proof now. This requires the offchain extensions to be present @@ -451,12 +652,15 @@ fn should_verify_batch_proof_statelessly() { // when crate::Pallet::::generate_batch_proof(vec![0, 4, 5]).unwrap() }); - let root = ext.execute_with(|| crate::Pallet::::mmr_root_hash()); + let (historical_leaves, historical_proof) = ext.execute_with(|| { + // when + crate::Pallet::::generate_historical_batch_proof(vec![0, 4, 5], 6).unwrap() + }); // Verify proof without relying on any on-chain data. assert_eq!( crate::verify_leaves_proof::<::Hashing, _>( - root, + root_7, leaves .into_iter() .map(|leaf| crate::primitives::DataOrHash::Data(leaf)) @@ -465,6 +669,17 @@ fn should_verify_batch_proof_statelessly() { ), Ok(()) ); + assert_eq!( + crate::verify_leaves_proof::<::Hashing, _>( + root_6, + historical_leaves + .into_iter() + .map(|leaf| crate::primitives::DataOrHash::Data(leaf)) + .collect(), + historical_proof + ), + Ok(()) + ); } #[test] @@ -721,3 +936,36 @@ fn should_verify_canonicalized() { assert_eq!(crate::Pallet::::verify_leaves(leaves, proofs), Ok(())); }); } + +#[test] +fn does_not_panic_when_generating_historical_proofs() { + let _ = env_logger::try_init(); + let mut ext = new_test_ext(); + + // given 7 blocks (7 MMR leaves) + ext.execute_with(|| add_blocks(7)); + ext.persist_offchain_overlay(); + + // Try to generate historical proof with invalid arguments. This requires the offchain + // extensions to be present to retrieve full leaf data. + register_offchain_ext(&mut ext); + ext.execute_with(|| { + // when leaf index is invalid + assert_eq!( + crate::Pallet::::generate_historical_batch_proof(vec![10], 7), + Err(Error::LeafNotFound), + ); + + // when leaves count is invalid + assert_eq!( + crate::Pallet::::generate_historical_batch_proof(vec![3], 100), + Err(Error::InvalidLeavesCount), + ); + + // when both leaf index and leaves count are invalid + assert_eq!( + crate::Pallet::::generate_historical_batch_proof(vec![10], 100), + Err(Error::InvalidLeavesCount), + ); + }); +} diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 29a7e3d1a6fb6..c40a594739ec1 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -402,6 +402,8 @@ pub enum Error { PalletNotIncluded, /// Cannot find the requested leaf index InvalidLeafIndex, + /// The provided leaves count is larger than the actual leaves count. + InvalidLeavesCount, } impl Error { @@ -455,7 +457,14 @@ sp_api::decl_runtime_apis! { fn mmr_root() -> Result; /// Generate MMR proof for a series of leaves under given indices. - fn generate_batch_proof(leaf_indices: Vec) -> Result<(Vec, BatchProof), Error>; + fn generate_batch_proof(leaf_indices: Vec) + -> Result<(Vec, BatchProof), Error>; + + /// Generate MMR proof for a series of leaves under given indices, using MMR at given `leaves_count` size. + fn generate_historical_batch_proof( + leaf_indices: Vec, + leaves_count: LeafIndex + ) -> Result<(Vec, BatchProof), Error>; /// Verify MMR proof against on-chain MMR for a batch of leaves. /// From 37664fe5b3513eb996225f016eceaf74963b8133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Sun, 2 Oct 2022 17:16:45 +0200 Subject: [PATCH 1225/1472] Remove contracts RPCs (#12358) * Remove contracts RPCs * Remove serde as RPC serialization is no longer needed * Rename folder to match crate name * Compile fix * Remove Byte wrapper --- Cargo.lock | 26 +- Cargo.toml | 4 +- bin/node/rpc/Cargo.toml | 1 - bin/node/rpc/src/lib.rs | 3 - bin/node/runtime/Cargo.toml | 6 +- bin/node/runtime/src/lib.rs | 2 +- frame/contracts/Cargo.toml | 2 +- .../{common => primitives}/Cargo.toml | 8 - .../{common => primitives}/README.md | 0 .../{common => primitives}/src/lib.rs | 91 +-- frame/contracts/rpc/Cargo.toml | 30 - frame/contracts/rpc/README.md | 3 - frame/contracts/rpc/runtime-api/README.md | 7 - frame/contracts/rpc/src/lib.rs | 524 ------------------ .../{rpc => }/runtime-api/Cargo.toml | 12 +- frame/contracts/runtime-api/README.md | 7 + .../{rpc => }/runtime-api/src/lib.rs | 6 +- frame/contracts/src/exec.rs | 27 +- frame/contracts/src/lib.rs | 8 +- frame/contracts/src/tests.rs | 15 +- frame/contracts/src/wasm/mod.rs | 103 ++-- frame/contracts/src/wasm/runtime.rs | 10 +- 22 files changed, 103 insertions(+), 792 deletions(-) rename frame/contracts/{common => primitives}/Cargo.toml (70%) rename frame/contracts/{common => primitives}/README.md (100%) rename frame/contracts/{common => primitives}/src/lib.rs (74%) delete mode 100644 frame/contracts/rpc/Cargo.toml delete mode 100644 frame/contracts/rpc/README.md delete mode 100644 frame/contracts/rpc/runtime-api/README.md delete mode 100644 frame/contracts/rpc/src/lib.rs rename frame/contracts/{rpc => }/runtime-api/Cargo.toml (78%) create mode 100644 frame/contracts/runtime-api/README.md rename frame/contracts/{rpc => }/runtime-api/src/lib.rs (94%) diff --git a/Cargo.lock b/Cargo.lock index de50d4ec27105..723a09ee9a39f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3371,7 +3371,7 @@ dependencies = [ "pallet-collective", "pallet-contracts", "pallet-contracts-primitives", - "pallet-contracts-rpc-runtime-api", + "pallet-contracts-runtime-api", "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", @@ -4825,7 +4825,6 @@ version = "3.0.0-dev" dependencies = [ "jsonrpsee", "node-primitives", - "pallet-contracts-rpc", "pallet-mmr-rpc", "pallet-transaction-payment-rpc", "sc-chain-spec", @@ -5530,10 +5529,6 @@ version = "6.0.0" dependencies = [ "bitflags", "parity-scale-codec", - "scale-info", - "serde", - "sp-core", - "sp-rpc", "sp-runtime", "sp-std", ] @@ -5548,24 +5543,7 @@ dependencies = [ ] [[package]] -name = "pallet-contracts-rpc" -version = "4.0.0-dev" -dependencies = [ - "jsonrpsee", - "pallet-contracts-primitives", - "pallet-contracts-rpc-runtime-api", - "parity-scale-codec", - "serde", - "serde_json", - "sp-api", - "sp-blockchain", - "sp-core", - "sp-rpc", - "sp-runtime", -] - -[[package]] -name = "pallet-contracts-rpc-runtime-api" +name = "pallet-contracts-runtime-api" version = "4.0.0-dev" dependencies = [ "pallet-contracts-primitives", diff --git a/Cargo.toml b/Cargo.toml index 25f12a2c9fd3f..02bc6aede8669 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,8 +86,8 @@ members = [ "frame/child-bounties", "frame/collective", "frame/contracts", - "frame/contracts/rpc", - "frame/contracts/rpc/runtime-api", + "frame/contracts/primitives", + "frame/contracts/runtime-api", "frame/conviction-voting", "frame/democracy", "frame/fast-unstake", diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 0b69ae27010fa..1f93feabf2f1e 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -14,7 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.15.1", features = ["server"] } node-primitives = { version = "2.0.0", path = "../primitives" } -pallet-contracts-rpc = { version = "4.0.0-dev", path = "../../../frame/contracts/rpc/" } pallet-mmr-rpc = { version = "3.0.0", path = "../../../frame/merkle-mountain-range/rpc/" } pallet-transaction-payment-rpc = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/rpc/" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 0e6b04087fa63..94e01619c6e63 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -108,7 +108,6 @@ where + Send + 'static, C::Api: substrate_frame_rpc_system::AccountNonceApi, - C::Api: pallet_contracts_rpc::ContractsRuntimeApi, C::Api: pallet_mmr_rpc::MmrRuntimeApi::Hash>, C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, C::Api: BabeApi, @@ -118,7 +117,6 @@ where B: sc_client_api::Backend + Send + Sync + 'static, B::State: sc_client_api::backend::StateBackend>, { - use pallet_contracts_rpc::{Contracts, ContractsApiServer}; use pallet_mmr_rpc::{Mmr, MmrApiServer}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; use sc_consensus_babe_rpc::{Babe, BabeApiServer}; @@ -150,7 +148,6 @@ where // Making synchronous calls in light client freezes the browser currently, // more context: https://github.com/paritytech/substrate/pull/3480 // These RPCs should use an asynchronous caller instead. - io.merge(Contracts::new(client.clone()).into_rpc())?; io.merge(Mmr::new(client.clone()).into_rpc())?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; io.merge( diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index e722024231651..ac3afc19da50f 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -61,8 +61,8 @@ pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../ pallet-child-bounties = { version = "4.0.0-dev", default-features = false, path = "../../../frame/child-bounties" } pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../../../frame/collective" } pallet-contracts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts" } -pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../../frame/contracts/common/" } -pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/rpc/runtime-api/" } +pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../../frame/contracts/primitives/" } +pallet-contracts-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/runtime-api/" } pallet-conviction-voting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/conviction-voting" } pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" } pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" } @@ -139,7 +139,7 @@ std = [ "pallet-collective/std", "pallet-contracts/std", "pallet-contracts-primitives/std", - "pallet-contracts-rpc-runtime-api/std", + "pallet-contracts-runtime-api/std", "pallet-conviction-voting/std", "pallet-democracy/std", "pallet-elections-phragmen/std", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4fa4049e22682..f0c68b5b225cd 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1942,7 +1942,7 @@ impl_runtime_apis! { } } - impl pallet_contracts_rpc_runtime_api::ContractsApi< + impl pallet_contracts_runtime_api::ContractsApi< Block, AccountId, Balance, BlockNumber, Hash, > for Runtime diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 30fbad680ebe5..7c3b677e06436 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -36,7 +36,7 @@ rand_pcg = { version = "0.3", optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "common" } +pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "primitives" } pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/primitives/Cargo.toml similarity index 70% rename from frame/contracts/common/Cargo.toml rename to frame/contracts/primitives/Cargo.toml index 49d7973ab155f..64e332007350b 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/primitives/Cargo.toml @@ -15,23 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bitflags = "1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -serde = { version = "1", features = ["derive"], optional = true } # Substrate Dependencies (This crate should not rely on frame) -sp-core = { version = "6.0.0", path = "../../../primitives/core", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc", optional = true } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-core/std", "sp-runtime/std", "sp-std/std", - "sp-rpc", - "serde", ] diff --git a/frame/contracts/common/README.md b/frame/contracts/primitives/README.md similarity index 100% rename from frame/contracts/common/README.md rename to frame/contracts/primitives/README.md diff --git a/frame/contracts/common/src/lib.rs b/frame/contracts/primitives/src/lib.rs similarity index 74% rename from frame/contracts/common/src/lib.rs rename to frame/contracts/primitives/src/lib.rs index f810725afcd36..5daf875ac2651 100644 --- a/frame/contracts/common/src/lib.rs +++ b/frame/contracts/primitives/src/lib.rs @@ -21,32 +21,16 @@ use bitflags::bitflags; use codec::{Decode, Encode}; -use sp_core::Bytes; use sp_runtime::{ traits::{Saturating, Zero}, DispatchError, RuntimeDebug, }; use sp_std::prelude::*; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; - -#[cfg(feature = "std")] -use sp_rpc::number::NumberOrHex; - /// Result type of a `bare_call` or `bare_instantiate` call. /// /// It contains the execution result together with some auxiliary information. #[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "std", - serde( - rename_all = "camelCase", - bound(serialize = "R: Serialize, Balance: Copy + Into"), - bound(deserialize = "R: Deserialize<'de>, Balance: TryFrom") - ) -)] pub struct ContractResult { /// How much gas was consumed during execution. pub gas_consumed: u64, @@ -80,7 +64,6 @@ pub struct ContractResult { /// /// The debug message is never generated during on-chain execution. It is reserved for /// RPC calls. - #[cfg_attr(feature = "std", serde(with = "as_string"))] pub debug_message: Vec, /// The execution result of the wasm code. pub result: R, @@ -113,8 +96,6 @@ pub enum ContractAccessError { bitflags! { /// Flags used by a contract to customize exit behaviour. #[derive(Encode, Decode)] - #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] - #[cfg_attr(feature = "std", serde(rename_all = "camelCase", transparent))] pub struct ReturnFlags: u32 { /// If this bit is set all changes made by the contract execution are rolled back. const REVERT = 0x0000_0001; @@ -123,13 +104,11 @@ bitflags! { /// Output of a contract call or instantiation which ran to completion. #[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct ExecReturnValue { /// Flags passed along by `seal_return`. Empty when `seal_return` was never called. pub flags: ReturnFlags, /// Buffer passed along by `seal_return`. Empty when `seal_return` was never called. - pub data: Bytes, + pub data: Vec, } impl ExecReturnValue { @@ -141,8 +120,6 @@ impl ExecReturnValue { /// The result of a successful contract instantiation. #[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct InstantiateReturnValue { /// The output of the called constructor. pub result: ExecReturnValue, @@ -152,63 +129,40 @@ pub struct InstantiateReturnValue { /// The result of succesfully uploading a contract. #[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "std", - serde( - rename_all = "camelCase", - bound(serialize = "CodeHash: Serialize, Balance: Copy + Into"), - bound(deserialize = "CodeHash: Deserialize<'de>, Balance: TryFrom") - ) -)] pub struct CodeUploadReturnValue { /// The key under which the new code is stored. pub code_hash: CodeHash, /// The deposit that was reserved at the caller. Is zero when the code already existed. - #[cfg_attr(feature = "std", serde(with = "as_hex"))] pub deposit: Balance, } /// Reference to an existing code hash or a new wasm module. #[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub enum Code { /// A wasm module as raw bytes. - Upload(Bytes), + Upload(Vec), /// The code hash of an on-chain wasm blob. Existing(Hash), } impl>, Hash> From for Code { fn from(from: T) -> Self { - Code::Upload(Bytes(from.into())) + Code::Upload(from.into()) } } /// The amount of balance that was either charged or refunded in order to pay for storage. #[derive(Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, Clone)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "std", - serde( - rename_all = "camelCase", - bound(serialize = "Balance: Copy + Into"), - bound(deserialize = "Balance: TryFrom") - ) -)] pub enum StorageDeposit { /// The transaction reduced storage consumption. /// /// This means that the specified amount of balance was transferred from the involved /// contracts to the call origin. - #[cfg_attr(feature = "std", serde(with = "as_hex"))] Refund(Balance), /// The transaction increased overall storage usage. /// /// This means that the specified amount of balance was transferred from the call origin /// to the contracts involved. - #[cfg_attr(feature = "std", serde(with = "as_hex"))] Charge(Balance), } @@ -295,42 +249,3 @@ where } } } - -#[cfg(feature = "std")] -mod as_string { - use super::*; - use serde::{ser::Error, Deserializer, Serializer}; - - pub fn serialize(bytes: &Vec, serializer: S) -> Result { - std::str::from_utf8(bytes) - .map_err(|e| S::Error::custom(format!("Debug buffer contains invalid UTF8: {}", e)))? - .serialize(serializer) - } - - pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result, D::Error> { - Ok(String::deserialize(deserializer)?.into_bytes()) - } -} - -#[cfg(feature = "std")] -mod as_hex { - use super::*; - use serde::{de::Error as _, Deserializer, Serializer}; - - pub fn serialize(balance: &Balance, serializer: S) -> Result - where - S: Serializer, - Balance: Copy + Into, - { - Into::::into(*balance).serialize(serializer) - } - - pub fn deserialize<'de, D, Balance>(deserializer: D) -> Result - where - D: Deserializer<'de>, - Balance: TryFrom, - { - Balance::try_from(NumberOrHex::deserialize(deserializer)?) - .map_err(|_| D::Error::custom("Cannot decode NumberOrHex to Balance")) - } -} diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml deleted file mode 100644 index 7876c7cba40d0..0000000000000 --- a/frame/contracts/rpc/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "pallet-contracts-rpc" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "Node-specific RPC methods for interaction with contracts." -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } -serde = { version = "1", features = ["derive"] } - -# Substrate Dependencies -pallet-contracts-primitives = { version = "6.0.0", path = "../common" } -pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } -sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } - -[dev-dependencies] -serde_json = "1" diff --git a/frame/contracts/rpc/README.md b/frame/contracts/rpc/README.md deleted file mode 100644 index be6df237bf60d..0000000000000 --- a/frame/contracts/rpc/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Node-specific RPC methods for interaction with contracts. - -License: Apache-2.0 \ No newline at end of file diff --git a/frame/contracts/rpc/runtime-api/README.md b/frame/contracts/rpc/runtime-api/README.md deleted file mode 100644 index d57f29a93bd1d..0000000000000 --- a/frame/contracts/rpc/runtime-api/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Runtime API definition required by Contracts RPC extensions. - -This API should be imported and implemented by the runtime, -of a node that wants to use the custom RPC extension -adding Contracts access methods. - -License: Apache-2.0 \ No newline at end of file diff --git a/frame/contracts/rpc/src/lib.rs b/frame/contracts/rpc/src/lib.rs deleted file mode 100644 index 1df7a5753f77e..0000000000000 --- a/frame/contracts/rpc/src/lib.rs +++ /dev/null @@ -1,524 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Node-specific RPC methods for interaction with contracts. - -#![warn(unused_crate_dependencies)] - -use std::{marker::PhantomData, sync::Arc}; - -use codec::Codec; -use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, - proc_macros::rpc, - types::error::{CallError, ErrorCode, ErrorObject}, -}; -use pallet_contracts_primitives::{ - Code, CodeUploadResult, ContractExecResult, ContractInstantiateResult, -}; -use serde::{Deserialize, Serialize}; -use sp_api::ProvideRuntimeApi; -use sp_blockchain::HeaderBackend; -use sp_core::Bytes; -use sp_rpc::number::NumberOrHex; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT}, -}; - -pub use pallet_contracts_rpc_runtime_api::ContractsApi as ContractsRuntimeApi; - -const RUNTIME_ERROR: i32 = 1; -const CONTRACT_DOESNT_EXIST: i32 = 2; -const KEY_DECODING_FAILED: i32 = 3; - -pub type Weight = u64; - -/// A rough estimate of how much gas a decent hardware consumes per second, -/// using native execution. -/// This value is used to set the upper bound for maximal contract calls to -/// prevent blocking the RPC for too long. -/// -/// As 1 gas is equal to 1 weight we base this on the conducted benchmarks which -/// determined runtime weights: -/// -const GAS_PER_SECOND: Weight = 1_000_000_000_000; - -/// The maximum amount of weight that the call and instantiate rpcs are allowed to consume. -/// This puts a ceiling on the weight limit that is supplied to the rpc as an argument. -const GAS_LIMIT: Weight = 5 * GAS_PER_SECOND; - -/// A private newtype for converting `ContractAccessError` into an RPC error. -struct ContractAccessError(pallet_contracts_primitives::ContractAccessError); - -impl From for JsonRpseeError { - fn from(e: ContractAccessError) -> Self { - use pallet_contracts_primitives::ContractAccessError::*; - match e.0 { - DoesntExist => CallError::Custom(ErrorObject::owned( - CONTRACT_DOESNT_EXIST, - "The specified contract doesn't exist.", - None::<()>, - )) - .into(), - KeyDecodingFailed => CallError::Custom(ErrorObject::owned( - KEY_DECODING_FAILED, - "Failed to decode the specified storage key.", - None::<()>, - )) - .into(), - } - } -} - -/// A struct that encodes RPC parameters required for a call to a smart-contract. -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] -pub struct CallRequest { - origin: AccountId, - dest: AccountId, - value: NumberOrHex, - gas_limit: NumberOrHex, - storage_deposit_limit: Option, - input_data: Bytes, -} - -/// A struct that encodes RPC parameters required to instantiate a new smart-contract. -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] -pub struct InstantiateRequest { - origin: AccountId, - value: NumberOrHex, - gas_limit: NumberOrHex, - storage_deposit_limit: Option, - code: Code, - data: Bytes, - salt: Bytes, -} - -/// A struct that encodes RPC parameters required for a call to upload a new code. -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] -pub struct CodeUploadRequest { - origin: AccountId, - code: Bytes, - storage_deposit_limit: Option, -} - -/// Contracts RPC methods. -#[rpc(client, server)] -pub trait ContractsApi -where - Balance: Copy + TryFrom + Into, -{ - /// Executes a call to a contract. - /// - /// This call is performed locally without submitting any transactions. Thus executing this - /// won't change any state. Nonetheless, the calling state-changing contracts is still possible. - /// - /// This method is useful for calling getter-like methods on contracts or to dry-run a - /// a contract call in order to determine the `gas_limit`. - #[method(name = "contracts_call")] - fn call( - &self, - call_request: CallRequest, - at: Option, - ) -> RpcResult>; - - /// Instantiate a new contract. - /// - /// This instantiate is performed locally without submitting any transactions. Thus the contract - /// is not actually created. - /// - /// This method is useful for UIs to dry-run contract instantiations. - #[method(name = "contracts_instantiate")] - fn instantiate( - &self, - instantiate_request: InstantiateRequest, - at: Option, - ) -> RpcResult>; - - /// Upload new code without instantiating a contract from it. - /// - /// This upload is performed locally without submitting any transactions. Thus executing this - /// won't change any state. - /// - /// This method is useful for UIs to dry-run code upload. - #[method(name = "contracts_upload_code")] - fn upload_code( - &self, - upload_request: CodeUploadRequest, - at: Option, - ) -> RpcResult>; - - /// Returns the value under a specified storage `key` in a contract given by `address` param, - /// or `None` if it is not set. - #[method(name = "contracts_getStorage")] - fn get_storage( - &self, - address: AccountId, - key: Bytes, - at: Option, - ) -> RpcResult>; -} - -/// Contracts RPC methods. -pub struct Contracts { - client: Arc, - _marker: PhantomData, -} - -impl Contracts { - /// Create new `Contracts` with the given reference to the client. - pub fn new(client: Arc) -> Self { - Self { client, _marker: Default::default() } - } -} - -#[async_trait] -impl - ContractsApiServer< - ::Hash, - <::Header as HeaderT>::Number, - AccountId, - Balance, - Hash, - > for Contracts -where - Block: BlockT, - Client: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - Client::Api: ContractsRuntimeApi< - Block, - AccountId, - Balance, - <::Header as HeaderT>::Number, - Hash, - >, - AccountId: Codec, - Balance: Codec + Copy + TryFrom + Into, - Hash: Codec, -{ - fn call( - &self, - call_request: CallRequest, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); - - let CallRequest { origin, dest, value, gas_limit, storage_deposit_limit, input_data } = - call_request; - - let value: Balance = decode_hex(value, "balance")?; - let gas_limit: u64 = decode_hex(gas_limit, "weight")?; - let storage_deposit_limit: Option = - storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; - limit_gas(gas_limit)?; - - api.call(&at, origin, dest, value, gas_limit, storage_deposit_limit, input_data.to_vec()) - .map_err(runtime_error_into_rpc_err) - } - - fn instantiate( - &self, - instantiate_request: InstantiateRequest, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); - - let InstantiateRequest { - origin, - value, - gas_limit, - storage_deposit_limit, - code, - data, - salt, - } = instantiate_request; - - let value: Balance = decode_hex(value, "balance")?; - let gas_limit: u64 = decode_hex(gas_limit, "weight")?; - let storage_deposit_limit: Option = - storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; - limit_gas(gas_limit)?; - - api.instantiate( - &at, - origin, - value, - gas_limit, - storage_deposit_limit, - code, - data.to_vec(), - salt.to_vec(), - ) - .map_err(runtime_error_into_rpc_err) - } - - fn upload_code( - &self, - upload_request: CodeUploadRequest, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); - - let CodeUploadRequest { origin, code, storage_deposit_limit } = upload_request; - - let storage_deposit_limit: Option = - storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; - - api.upload_code(&at, origin, code.to_vec(), storage_deposit_limit) - .map_err(runtime_error_into_rpc_err) - } - - fn get_storage( - &self, - address: AccountId, - key: Bytes, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - let result = api - .get_storage(&at, address, key.to_vec()) - .map_err(runtime_error_into_rpc_err)? - .map_err(ContractAccessError)? - .map(Bytes); - - Ok(result) - } -} - -/// Converts a runtime trap into an RPC error. -fn runtime_error_into_rpc_err(err: impl std::fmt::Debug) -> JsonRpseeError { - CallError::Custom(ErrorObject::owned( - RUNTIME_ERROR, - "Runtime error", - Some(format!("{:?}", err)), - )) - .into() -} - -fn decode_hex>(from: H, name: &str) -> RpcResult { - from.try_into().map_err(|_| { - JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - ErrorCode::InvalidParams.code(), - format!("{:?} does not fit into the {} type", from, name), - None::<()>, - ))) - }) -} - -fn limit_gas(gas_limit: Weight) -> RpcResult<()> { - if gas_limit > GAS_LIMIT { - Err(JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - ErrorCode::InvalidParams.code(), - format!( - "Requested gas limit is greater than maximum allowed: {} > {}", - gas_limit, GAS_LIMIT - ), - None::<()>, - )))) - } else { - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use pallet_contracts_primitives::{ContractExecResult, ContractInstantiateResult}; - use sp_core::U256; - - fn trim(json: &str) -> String { - json.chars().filter(|c| !c.is_whitespace()).collect() - } - - #[test] - fn call_request_should_serialize_deserialize_properly() { - type Req = CallRequest; - let req: Req = serde_json::from_str( - r#" - { - "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", - "dest": "5DRakbLVnjVrW6niwLfHGW24EeCEvDAFGEXrtaYS5M4ynoom", - "value": "0x112210f4B16c1cb1", - "gasLimit": 1000000000000, - "storageDepositLimit": 5000, - "inputData": "0x8c97db39" - } - "#, - ) - .unwrap(); - assert_eq!(req.gas_limit.into_u256(), U256::from(0xe8d4a51000u64)); - assert_eq!(req.storage_deposit_limit.map(|l| l.into_u256()), Some(5000.into())); - assert_eq!(req.value.into_u256(), U256::from(1234567890987654321u128)); - } - - #[test] - fn instantiate_request_should_serialize_deserialize_properly() { - type Req = InstantiateRequest; - let req: Req = serde_json::from_str( - r#" - { - "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", - "value": "0x88", - "gasLimit": 42, - "code": { "existing": "0x1122" }, - "data": "0x4299", - "salt": "0x9988" - } - "#, - ) - .unwrap(); - - assert_eq!(req.origin, "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"); - assert_eq!(req.value.into_u256(), 0x88.into()); - assert_eq!(req.gas_limit.into_u256(), 42.into()); - assert_eq!(req.storage_deposit_limit, None); - assert_eq!(&*req.data, [0x42, 0x99].as_ref()); - assert_eq!(&*req.salt, [0x99, 0x88].as_ref()); - let code = match req.code { - Code::Existing(hash) => hash, - _ => panic!("json encoded an existing hash"), - }; - assert_eq!(&code, "0x1122"); - } - - #[test] - fn code_upload_request_should_serialize_deserialize_properly() { - type Req = CodeUploadRequest; - let req: Req = serde_json::from_str( - r#" - { - "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", - "code": "0x8c97db39", - "storageDepositLimit": 5000 - } - "#, - ) - .unwrap(); - assert_eq!(req.origin, "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"); - assert_eq!(&*req.code, [0x8c, 0x97, 0xdb, 0x39].as_ref()); - assert_eq!(req.storage_deposit_limit.map(|l| l.into_u256()), Some(5000.into())); - } - - #[test] - fn call_result_should_serialize_deserialize_properly() { - fn test(expected: &str) { - let res: ContractExecResult = serde_json::from_str(expected).unwrap(); - let actual = serde_json::to_string(&res).unwrap(); - assert_eq!(actual, trim(expected).as_str()); - } - test( - r#"{ - "gasConsumed": 5000, - "gasRequired": 8000, - "storageDeposit": {"charge": 42000}, - "debugMessage": "HelloWorld", - "result": { - "Ok": { - "flags": 5, - "data": "0x1234" - } - } - }"#, - ); - test( - r#"{ - "gasConsumed": 3400, - "gasRequired": 5200, - "storageDeposit": {"refund": 12000}, - "debugMessage": "HelloWorld", - "result": { - "Err": "BadOrigin" - } - }"#, - ); - } - - #[test] - fn instantiate_result_should_serialize_deserialize_properly() { - fn test(expected: &str) { - let res: ContractInstantiateResult = - serde_json::from_str(expected).unwrap(); - let actual = serde_json::to_string(&res).unwrap(); - assert_eq!(actual, trim(expected).as_str()); - } - test( - r#"{ - "gasConsumed": 5000, - "gasRequired": 8000, - "storageDeposit": {"refund": 12000}, - "debugMessage": "HelloWorld", - "result": { - "Ok": { - "result": { - "flags": 5, - "data": "0x1234" - }, - "accountId": "5CiPP" - } - } - }"#, - ); - test( - r#"{ - "gasConsumed": 3400, - "gasRequired": 5200, - "storageDeposit": {"charge": 0}, - "debugMessage": "HelloWorld", - "result": { - "Err": "BadOrigin" - } - }"#, - ); - } - - #[test] - fn code_upload_result_should_serialize_deserialize_properly() { - fn test(expected: &str) { - let res: CodeUploadResult = serde_json::from_str(expected).unwrap(); - let actual = serde_json::to_string(&res).unwrap(); - assert_eq!(actual, trim(expected).as_str()); - } - test( - r#"{ - "Ok": { - "codeHash": 4711, - "deposit": 99 - } - }"#, - ); - test( - r#"{ - "Err": "BadOrigin" - }"#, - ); - } -} diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/runtime-api/Cargo.toml similarity index 78% rename from frame/contracts/rpc/runtime-api/Cargo.toml rename to frame/contracts/runtime-api/Cargo.toml index bd07d577ec272..05b0e05d4c568 100644 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ b/frame/contracts/runtime-api/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "pallet-contracts-rpc-runtime-api" +name = "pallet-contracts-runtime-api" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" -description = "Runtime API definition required by Contracts RPC extensions." +description = "Runtime API definition used to provide dry-run capabilities" readme = "README.md" [package.metadata.docs.rs] @@ -17,10 +17,10 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # Substrate Dependencies -pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../common" } -sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../../primitives/std" } +pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../primitives" } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } [features] default = ["std"] diff --git a/frame/contracts/runtime-api/README.md b/frame/contracts/runtime-api/README.md new file mode 100644 index 0000000000000..fed285b23b2ac --- /dev/null +++ b/frame/contracts/runtime-api/README.md @@ -0,0 +1,7 @@ +Runtime API definition used to provide dry-run capabilities + +This API should be imported and implemented by the runtime, +of a node that wants to provide clients with dry-run +capabilities. + +License: Apache-2.0 \ No newline at end of file diff --git a/frame/contracts/rpc/runtime-api/src/lib.rs b/frame/contracts/runtime-api/src/lib.rs similarity index 94% rename from frame/contracts/rpc/runtime-api/src/lib.rs rename to frame/contracts/runtime-api/src/lib.rs index 9765b37057c7b..79fd20c8c0163 100644 --- a/frame/contracts/rpc/runtime-api/src/lib.rs +++ b/frame/contracts/runtime-api/src/lib.rs @@ -15,11 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Runtime API definition required by Contracts RPC extensions. +//! Runtime API definition used to provide dry-run capabilities. //! //! This API should be imported and implemented by the runtime, -//! of a node that wants to use the custom RPC extension -//! adding Contracts access methods. +//! of a node that wants to provide clients with dry-run +//! capabilities. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 6260dd41de707..bf35410d0bd4b 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1384,7 +1384,6 @@ mod tests { use frame_system::{EventRecord, Phase}; use pallet_contracts_primitives::ReturnFlags; use pretty_assertions::assert_eq; - use sp_core::Bytes; use sp_runtime::{traits::Hash, DispatchError}; use std::{ cell::RefCell, @@ -1517,7 +1516,7 @@ mod tests { } fn exec_success() -> ExecResult { - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) } fn exec_trapped() -> ExecResult { @@ -1586,7 +1585,7 @@ mod tests { let success_ch = MockLoader::insert(Call, move |ctx, _| { assert_eq!(ctx.ext.value_transferred(), value); - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) }); ExtBuilder::default().build().execute_with(|| { @@ -1621,13 +1620,13 @@ mod tests { let success_ch = MockLoader::insert(Call, move |ctx, _| { assert_eq!(ctx.ext.value_transferred(), value); - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) }); let delegate_ch = MockLoader::insert(Call, move |ctx, _| { assert_eq!(ctx.ext.value_transferred(), value); let _ = ctx.ext.delegate_call(success_ch, Vec::new())?; - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) }); ExtBuilder::default().build().execute_with(|| { @@ -1662,7 +1661,7 @@ mod tests { let dest = BOB; let return_ch = MockLoader::insert(Call, |_, _| { - Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Bytes(Vec::new()) }) + Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Vec::new() }) }); ExtBuilder::default().build().execute_with(|| { @@ -1715,7 +1714,7 @@ mod tests { let origin = ALICE; let dest = BOB; let return_ch = MockLoader::insert(Call, |_, _| { - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(vec![1, 2, 3, 4]) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![1, 2, 3, 4] }) }); ExtBuilder::default().build().execute_with(|| { @@ -1736,7 +1735,7 @@ mod tests { let output = result.unwrap(); assert!(!output.did_revert()); - assert_eq!(output.data, Bytes(vec![1, 2, 3, 4])); + assert_eq!(output.data, vec![1, 2, 3, 4]); }); } @@ -1747,7 +1746,7 @@ mod tests { let origin = ALICE; let dest = BOB; let return_ch = MockLoader::insert(Call, |_, _| { - Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Bytes(vec![1, 2, 3, 4]) }) + Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![1, 2, 3, 4] }) }); ExtBuilder::default().build().execute_with(|| { @@ -1768,7 +1767,7 @@ mod tests { let output = result.unwrap(); assert!(output.did_revert()); - assert_eq!(output.data, Bytes(vec![1, 2, 3, 4])); + assert_eq!(output.data, vec![1, 2, 3, 4]); }); } @@ -2115,7 +2114,7 @@ mod tests { #[test] fn instantiation_work_with_success_output() { let dummy_ch = MockLoader::insert(Constructor, |_, _| { - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(vec![80, 65, 83, 83]) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![80, 65, 83, 83] }) }); ExtBuilder::default().existential_deposit(15).build().execute_with(|| { @@ -2140,7 +2139,7 @@ mod tests { &[], None, ), - Ok((address, ref output)) if output.data == Bytes(vec![80, 65, 83, 83]) => address + Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address ); // Check that the newly created account has the expected code hash and @@ -2159,7 +2158,7 @@ mod tests { #[test] fn instantiation_fails_with_failing_output() { let dummy_ch = MockLoader::insert(Constructor, |_, _| { - Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Bytes(vec![70, 65, 73, 76]) }) + Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![70, 65, 73, 76] }) }); ExtBuilder::default().existential_deposit(15).build().execute_with(|| { @@ -2184,7 +2183,7 @@ mod tests { &[], None, ), - Ok((address, ref output)) if output.data == Bytes(vec![70, 65, 73, 76]) => address + Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address ); // Check that the account has not been created. diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index f9a1c8decf042..3aeb8742705c2 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -123,7 +123,7 @@ use pallet_contracts_primitives::{ StorageDeposit, }; use scale_info::TypeInfo; -use sp_core::{crypto::UncheckedFrom, Bytes}; +use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup}; use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; @@ -512,7 +512,7 @@ pub mod pallet { value, gas_limit, storage_deposit_limit.map(Into::into), - Code::Upload(Bytes(code)), + Code::Upload(code), data, salt, None, @@ -743,7 +743,7 @@ pub mod pallet { value, gas_limit, storage_deposit_limit.map(Into::into), - Code::Upload(Bytes(code)), + Code::Upload(code), data, salt, None, @@ -1234,7 +1234,7 @@ where let try_exec = || { let schedule = T::Schedule::get(); let (extra_deposit, executable) = match code { - Code::Upload(Bytes(binary)) => { + Code::Upload(binary) => { let executable = PrefabWasmModule::from_code(binary, &schedule, origin.clone()) .map_err(|(err, msg)| { debug_message.as_mut().map(|buffer| buffer.extend(msg.as_bytes())); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index e5893c3dbd112..b4a8f8f4c834f 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -44,7 +44,6 @@ use frame_support::{ }; use frame_system::{self as system, EventRecord, Phase}; use pretty_assertions::{assert_eq, assert_ne}; -use sp_core::Bytes; use sp_io::hashing::blake2_256; use sp_keystore::{testing::KeyStore, KeystoreExt}; use sp_runtime::{ @@ -1722,7 +1721,7 @@ fn chain_extension_works() { let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false); assert_eq!(TestExtension::last_seen_buffer(), input); - assert_eq!(result.result.unwrap().data, Bytes(input)); + assert_eq!(result.result.unwrap().data, input); // 1 = treat inputs as integer primitives and store the supplied integers Contracts::bare_call( @@ -1787,7 +1786,7 @@ fn chain_extension_works() { .result .unwrap(); assert_eq!(result.flags, ReturnFlags::REVERT); - assert_eq!(result.data, Bytes(vec![42, 99])); + assert_eq!(result.data, vec![42, 99]); // diverging to second chain extension that sets flags to 0x1 and returns a fixed buffer // We set the MSB part to 1 (instead of 0) which routes the request into the second @@ -1804,7 +1803,7 @@ fn chain_extension_works() { .result .unwrap(); assert_eq!(result.flags, ReturnFlags::REVERT); - assert_eq!(result.data, Bytes(vec![0x4B, 0x1D])); + assert_eq!(result.data, vec![0x4B, 0x1D]); // Diverging to third chain extension that is disabled // We set the MSB part to 2 (instead of 0) which routes the request into the third extension @@ -2672,7 +2671,7 @@ fn ecdsa_recover() { .result .unwrap(); assert!(!result.did_revert()); - assert_eq!(result.data.as_ref(), &EXPECTED_COMPRESSED_PUBLIC_KEY); + assert_eq!(result.data, EXPECTED_COMPRESSED_PUBLIC_KEY); }) } @@ -3503,7 +3502,7 @@ fn contract_reverted() { .result .unwrap(); assert_eq!(result.result.flags, flags); - assert_eq!(result.result.data.0, buffer); + assert_eq!(result.result.data, buffer); assert!(!>::contains_key(result.account_id)); // Pass empty flags and therefore successfully instantiate the contract for later use. @@ -3539,7 +3538,7 @@ fn contract_reverted() { .result .unwrap(); assert_eq!(result.flags, flags); - assert_eq!(result.data.0, buffer); + assert_eq!(result.data, buffer); }); } @@ -3559,7 +3558,7 @@ fn code_rejected_error_works() { 0, GAS_LIMIT, None, - Code::Upload(Bytes(wasm)), + Code::Upload(wasm), vec![], vec![], true, diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index d8b4cd245356e..b341ae3bd155d 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -281,7 +281,7 @@ mod tests { }; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pretty_assertions::assert_eq; - use sp_core::{Bytes, H256}; + use sp_core::H256; use sp_runtime::DispatchError; use std::{ borrow::BorrowMut, @@ -341,8 +341,8 @@ mod tests { } /// The call is mocked and just returns this hardcoded value. - fn call_return_data() -> Bytes { - Bytes(vec![0xDE, 0xAD, 0xBE, 0xEF]) + fn call_return_data() -> Vec { + vec![0xDE, 0xAD, 0xBE, 0xEF] } impl Default for MockExt { @@ -404,7 +404,7 @@ mod tests { }); Ok(( Contracts::::contract_address(&ALICE, &code_hash, salt), - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }, + ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }, )) } fn set_code_hash(&mut self, hash: CodeHash) -> Result<(), DispatchError> { @@ -804,7 +804,7 @@ mod tests { let mut mock_ext = MockExt::default(); let input = vec![0xff, 0x2a, 0x99, 0x88]; let result = execute(CODE, input.clone(), &mut mock_ext).unwrap(); - assert_eq!(result.data.0, input); + assert_eq!(result.data, input); assert_eq!( &mock_ext.calls, &[CallEntry { to: ALICE, value: 0x2a, data: input, allows_reentry: true }] @@ -907,15 +907,15 @@ mod tests { // value does not exist -> sentinel value returned let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); // value did exist -> success let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1,); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1,); // value did exist -> success (zero sized type) let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0,); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0,); } #[test] @@ -977,13 +977,13 @@ mod tests { let input = (63, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // sentinel returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); // value exists let input = (64, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // true as u32 returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1); // getter does not remove the value from storage assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]); @@ -991,7 +991,7 @@ mod tests { let input = (19, [2u8; 19]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // true as u32 returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); // getter does not remove the value from storage assert_eq!(ext.storage.get(&[2u8; 19].to_vec()).unwrap(), &([] as [u8; 0])); } @@ -1234,7 +1234,7 @@ mod tests { let output = execute(CODE_ECDSA_TO_ETH_ADDRESS, vec![], MockExt::default()).unwrap(); assert_eq!( output, - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes([0x02; 20].to_vec()) } + ExecReturnValue { flags: ReturnFlags::empty(), data: [0x02; 20].to_vec() } ); } @@ -1311,7 +1311,7 @@ mod tests { assert_eq!( output, - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes([0x22; 32].to_vec()) } + ExecReturnValue { flags: ReturnFlags::empty(), data: [0x22; 32].to_vec() } ); } @@ -1630,10 +1630,7 @@ mod tests { fn return_from_start_fn() { let output = execute(CODE_RETURN_FROM_START_FN, vec![], MockExt::default()).unwrap(); - assert_eq!( - output, - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(vec![1, 2, 3, 4]) } - ); + assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: vec![1, 2, 3, 4] }); } const CODE_TIMESTAMP_NOW: &str = r#" @@ -1902,15 +1899,13 @@ mod tests { output, ExecReturnValue { flags: ReturnFlags::empty(), - data: Bytes( - ( - array_bytes::hex2array_unchecked::<32>( - "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F" - ), - 42u64, - ) - .encode() - ), + data: ( + array_bytes::hex2array_unchecked::<32>( + "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F" + ), + 42u64, + ) + .encode() }, ); } @@ -2124,7 +2119,7 @@ mod tests { output, ExecReturnValue { flags: ReturnFlags::empty(), - data: Bytes(array_bytes::hex2bytes_unchecked("445566778899")), + data: array_bytes::hex2bytes_unchecked("445566778899"), } ); assert!(!output.did_revert()); @@ -2143,7 +2138,7 @@ mod tests { output, ExecReturnValue { flags: ReturnFlags::REVERT, - data: Bytes(array_bytes::hex2bytes_unchecked("5566778899")), + data: array_bytes::hex2bytes_unchecked("5566778899"), } ); assert!(output.did_revert()); @@ -2306,7 +2301,7 @@ mod tests { let result = execute(CODE_CALL_RUNTIME, call.encode(), &mut ext).unwrap(); assert_eq!(*ext.runtime_calls.borrow(), vec![call]); // 0 = ReturnCode::Success - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); } #[test] @@ -2371,19 +2366,19 @@ mod tests { // value did not exist before -> sentinel returned let input = ([1u8; 32], [42u8, 48]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[42u8, 48]); // value do exist -> length of old value returned let input = ([1u8; 32], [0u8; 0]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 2); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 2); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[0u8; 0]); // value do exist -> length of old value returned (test for zero sized val) let input = ([1u8; 32], [99u8]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[99u8]); } @@ -2442,19 +2437,19 @@ mod tests { // value did not exist before -> sentinel returned let input = (32, [1u8; 32], [42u8, 48]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[42u8, 48]); // value do exist -> length of old value returned let input = (32, [1u8; 32], [0u8; 0]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 2); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 2); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[0u8; 0]); // value do exist -> length of old value returned (test for zero sized val) let input = (32, [1u8; 32], [99u8]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[99u8]); } @@ -2527,7 +2522,7 @@ mod tests { let input = (63, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::KeyNotFound as u32 ); @@ -2535,21 +2530,21 @@ mod tests { let input = (64, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::Success as u32 ); assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]); - assert_eq!(&result.data.0[4..], &[42u8]); + assert_eq!(&result.data[4..], &[42u8]); // value exists (test for 0 sized) let input = (19, [2u8; 19]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::Success as u32 ); assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), Some(&vec![])); - assert_eq!(&result.data.0[4..], &([] as [u8; 0])); + assert_eq!(&result.data[4..], &([] as [u8; 0])); } #[test] @@ -2611,14 +2606,14 @@ mod tests { let input = (32, [3u8; 32]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // sentinel returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); assert_eq!(ext.storage.get(&[3u8; 32].to_vec()), None); // value did exist let input = (64, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // length returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1); // value cleared assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None); @@ -2626,14 +2621,14 @@ mod tests { let input = (63, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // sentinel returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None); // value exists let input = (19, [2u8; 19]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // length returned (test for 0 sized) - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); // value cleared assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None); } @@ -2710,7 +2705,7 @@ mod tests { let input = (63, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::KeyNotFound as u32 ); @@ -2718,21 +2713,21 @@ mod tests { let input = (64, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::Success as u32 ); assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None); - assert_eq!(&result.data.0[4..], &[42u8]); + assert_eq!(&result.data[4..], &[42u8]); // value did exist -> length returned (test for 0 sized) let input = (19, [2u8; 19]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::Success as u32 ); assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None); - assert_eq!(&result.data.0[4..], &[0u8; 0]); + assert_eq!(&result.data[4..], &[0u8; 0]); } #[test] @@ -2769,10 +2764,7 @@ mod tests { let output = execute(CODE_IS_CONTRACT, vec![], MockExt::default()).unwrap(); // The mock ext just always returns 1u32 (`true`). - assert_eq!( - output, - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(1u32.encode()) }, - ); + assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: 1u32.encode() },); } #[test] @@ -2906,10 +2898,7 @@ mod tests { let output = execute(CODE_CALLER_IS_ORIGIN, vec![], MockExt::default()).unwrap(); // The mock ext just always returns 0u32 (`false`) - assert_eq!( - output, - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(0u32.encode()) }, - ); + assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: 0u32.encode() },); } #[test] diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index edd413aa45bf0..3296492994071 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -30,7 +30,7 @@ use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight}; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pallet_contracts_proc_macro::define_env; -use sp_core::{crypto::UncheckedFrom, Bytes}; +use sp_core::crypto::UncheckedFrom; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; use sp_runtime::traits::{Bounded, Zero}; use sp_sandbox::SandboxMemory; @@ -483,10 +483,10 @@ where TrapReason::Return(ReturnData { flags, data }) => { let flags = ReturnFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?; - Ok(ExecReturnValue { flags, data: Bytes(data) }) + Ok(ExecReturnValue { flags, data }) }, TrapReason::Termination => - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }), + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }), TrapReason::SupervisorError(error) => return Err(error.into()), } } @@ -494,7 +494,7 @@ where // Check the exact type of the error. match sandbox_result { // No traps were generated. Proceed normally. - Ok(_) => Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }), + Ok(_) => Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }), // `Error::Module` is returned only if instantiation or linking failed (i.e. // wasm binary tried to import a function that is not provided by the host). // This shouldn't happen because validation process ought to reject such binaries. @@ -879,7 +879,7 @@ where if let Ok(return_value) = call_outcome { return Err(TrapReason::Return(ReturnData { flags: return_value.flags.bits(), - data: return_value.data.0, + data: return_value.data, })) } } From 9472af8e2af41b47a471c084035bf8aecf61d8da Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 3 Oct 2022 16:00:57 +0300 Subject: [PATCH 1226/1472] Beefy on-demand justifications as a custom RequestResponse protocol (#12124) * client/beefy: create communication module and move gossip there * client/beefy: move beefy_protocol_name module to communication * client/beefy: move notification module under communication * client/beefy: add incoming request_response protocol handler * client/beefy: keep track of connected peers and their progress * client/beefy: add logic for generating Justif requests * client/beefy: cancel outdated on-demand justification requests * try Andre's suggestion for JustificationEngine * justif engine add justifs validation * client/beefy: impl OnDemandJustificationsEngine async next() * move beefy proto name test * client/beefy: initialize OnDemandJustificationsEngine * client/tests: allow for custom req-resp protocols * client/beefy: on-demand-justif: implement simple peer selection strategy * client/beefy: fix voter initialization Fix corner case where voter gets a single burst of finality notifications just when it starts. The notification stream was consumed by "wait_for_pallet" logic, then main loop would subscribe to finality notifications, but by that time some notifications might've been lost. Fix this by subscribing the main loop to notifications before waiting for pallet to become available. Share the same stream with the main loop so that notifications for blocks before pallet available are ignored, while _all_ notifications after pallet available are processed. Add regression test for this. Signed-off-by: acatangiu * client/beefy: make sure justif requests are always out for mandatory blocks * client/beefy: add test for on-demand justifications sync * client/beefy: tweak main loop event processing order * client/beefy: run on-demand-justif-handler under same async task as voter * client/beefy: add test for known-peers * client/beefy: reorg request-response module * client/beefy: add issue references for future work todos * client/beefy: consolidate on-demand-justifications engine state machine Signed-off-by: acatangiu * client/beefy: fix for polkadot companion * client/beefy: implement review suggestions * cargo fmt and clippy * fix merge damage * fix rust-doc * fix merge damage * fix merge damage * client/beefy: add test for justif proto name Signed-off-by: acatangiu --- client/beefy/rpc/src/lib.rs | 6 +- .../beefy/src/{ => communication}/gossip.rs | 20 +- client/beefy/src/communication/mod.rs | 118 +++++++ .../src/{ => communication}/notification.rs | 0 client/beefy/src/communication/peers.rs | 131 ++++++++ .../incoming_requests_handler.rs | 193 ++++++++++++ .../src/communication/request_response/mod.rs | 101 ++++++ .../outgoing_requests_engine.rs | 245 +++++++++++++++ client/beefy/src/import.rs | 2 +- client/beefy/src/lib.rs | 131 ++++---- client/beefy/src/round.rs | 20 +- client/beefy/src/tests.rs | 287 ++++++++++++------ client/beefy/src/worker.rs | 166 +++++++--- client/network/test/src/lib.rs | 7 +- 14 files changed, 1208 insertions(+), 219 deletions(-) rename client/beefy/src/{ => communication}/gossip.rs (94%) create mode 100644 client/beefy/src/communication/mod.rs rename client/beefy/src/{ => communication}/notification.rs (100%) create mode 100644 client/beefy/src/communication/peers.rs create mode 100644 client/beefy/src/communication/request_response/incoming_requests_handler.rs create mode 100644 client/beefy/src/communication/request_response/mod.rs create mode 100644 client/beefy/src/communication/request_response/outgoing_requests_engine.rs diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 3be182ceb8f39..0af474116e6d0 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -35,7 +35,9 @@ use jsonrpsee::{ }; use log::warn; -use beefy_gadget::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}; +use beefy_gadget::communication::notification::{ + BeefyBestBlockStream, BeefyVersionedFinalityProofStream, +}; mod notification; @@ -165,8 +167,8 @@ mod tests { use super::*; use beefy_gadget::{ + communication::notification::BeefyVersionedFinalityProofSender, justification::BeefyVersionedFinalityProof, - notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofSender}, }; use beefy_primitives::{known_payload_ids, Payload, SignedCommitment}; use codec::{Decode, Encode}; diff --git a/client/beefy/src/gossip.rs b/client/beefy/src/communication/gossip.rs similarity index 94% rename from client/beefy/src/gossip.rs rename to client/beefy/src/communication/gossip.rs index 02d5efe9e0e58..6c41a2e48932a 100644 --- a/client/beefy/src/gossip.rs +++ b/client/beefy/src/communication/gossip.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{collections::BTreeMap, time::Duration}; +use std::{collections::BTreeMap, sync::Arc, time::Duration}; use sc_network::PeerId; use sc_network_gossip::{MessageIntent, ValidationResult, Validator, ValidatorContext}; @@ -28,13 +28,12 @@ use log::{debug, trace}; use parking_lot::{Mutex, RwLock}; use wasm_timer::Instant; +use crate::{communication::peers::KnownPeers, keystore::BeefyKeystore}; use beefy_primitives::{ crypto::{Public, Signature}, VoteMessage, }; -use crate::keystore::BeefyKeystore; - // Timeout for rebroadcasting messages. const REBROADCAST_AFTER: Duration = Duration::from_secs(60 * 5); @@ -103,17 +102,19 @@ where topic: B::Hash, known_votes: RwLock>, next_rebroadcast: Mutex, + known_peers: Arc>>, } impl GossipValidator where B: Block, { - pub fn new() -> GossipValidator { + pub fn new(known_peers: Arc>>) -> GossipValidator { GossipValidator { topic: topic::(), known_votes: RwLock::new(KnownVotes::new()), next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), + known_peers, } } @@ -165,6 +166,7 @@ where if BeefyKeystore::verify(&msg.id, &msg.signature, &msg.commitment.encode()) { self.known_votes.write().add_known(&round, msg_hash); + self.known_peers.lock().note_vote_for(*sender, round); return ValidationResult::ProcessAndKeep(self.topic) } else { // TODO: report peer @@ -271,7 +273,7 @@ mod tests { #[test] fn note_and_drop_round_works() { - let gv = GossipValidator::::new(); + let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); gv.note_round(1u64); @@ -298,7 +300,7 @@ mod tests { #[test] fn note_same_round_twice() { - let gv = GossipValidator::::new(); + let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); gv.note_round(3u64); gv.note_round(7u64); @@ -355,7 +357,7 @@ mod tests { #[test] fn should_avoid_verifying_signatures_twice() { - let gv = GossipValidator::::new(); + let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); let sender = sc_network::PeerId::random(); let mut context = TestContext; @@ -391,7 +393,7 @@ mod tests { #[test] fn messages_allowed_and_expired() { - let gv = GossipValidator::::new(); + let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); let sender = sc_network::PeerId::random(); let topic = Default::default(); let intent = MessageIntent::Broadcast; @@ -434,7 +436,7 @@ mod tests { #[test] fn messages_rebroadcast() { - let gv = GossipValidator::::new(); + let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); let sender = sc_network::PeerId::random(); let topic = Default::default(); diff --git a/client/beefy/src/communication/mod.rs b/client/beefy/src/communication/mod.rs new file mode 100644 index 0000000000000..93646677c0ecd --- /dev/null +++ b/client/beefy/src/communication/mod.rs @@ -0,0 +1,118 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Communication streams for the BEEFY networking protocols. + +pub mod notification; +pub mod request_response; + +pub(crate) mod gossip; +pub(crate) mod peers; + +pub(crate) mod beefy_protocol_name { + use array_bytes::bytes2hex; + use sc_network::ProtocolName; + + /// BEEFY votes gossip protocol name suffix. + const GOSSIP_NAME: &str = "/beefy/1"; + /// BEEFY justifications protocol name suffix. + const JUSTIFICATIONS_NAME: &str = "/beefy/justifications/1"; + + /// Old names for the gossip protocol, used for backward compatibility. + pub(super) const LEGACY_NAMES: [&str; 1] = ["/paritytech/beefy/1"]; + + /// Name of the votes gossip protocol used by BEEFY. + /// + /// Must be registered towards the networking in order for BEEFY voter to properly function. + pub fn gossip_protocol_name>( + genesis_hash: Hash, + fork_id: Option<&str>, + ) -> ProtocolName { + let genesis_hash = genesis_hash.as_ref(); + if let Some(fork_id) = fork_id { + format!("/{}/{}{}", bytes2hex("", genesis_hash), fork_id, GOSSIP_NAME).into() + } else { + format!("/{}{}", bytes2hex("", genesis_hash), GOSSIP_NAME).into() + } + } + + /// Name of the BEEFY justifications request-response protocol. + pub fn justifications_protocol_name>( + genesis_hash: Hash, + fork_id: Option<&str>, + ) -> ProtocolName { + let genesis_hash = genesis_hash.as_ref(); + if let Some(fork_id) = fork_id { + format!("/{}/{}{}", bytes2hex("", genesis_hash), fork_id, JUSTIFICATIONS_NAME).into() + } else { + format!("/{}{}", bytes2hex("", genesis_hash), JUSTIFICATIONS_NAME).into() + } + } +} + +/// Returns the configuration value to put in +/// [`sc_network::config::NetworkConfiguration::extra_sets`]. +/// For standard protocol name see [`beefy_protocol_name::gossip_protocol_name`]. +pub fn beefy_peers_set_config( + gossip_protocol_name: sc_network::ProtocolName, +) -> sc_network_common::config::NonDefaultSetConfig { + let mut cfg = + sc_network_common::config::NonDefaultSetConfig::new(gossip_protocol_name, 1024 * 1024); + + cfg.allow_non_reserved(25, 25); + cfg.add_fallback_names(beefy_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect()); + cfg +} + +#[cfg(test)] +mod tests { + use super::*; + + use sp_core::H256; + + #[test] + fn beefy_protocols_names() { + use beefy_protocol_name::{gossip_protocol_name, justifications_protocol_name}; + // Create protocol name using random genesis hash. + let genesis_hash = H256::random(); + let genesis_hex = array_bytes::bytes2hex("", genesis_hash.as_ref()); + + let expected_gossip_name = format!("/{}/beefy/1", genesis_hex); + let gossip_proto_name = gossip_protocol_name(&genesis_hash, None); + assert_eq!(gossip_proto_name.to_string(), expected_gossip_name); + + let expected_justif_name = format!("/{}/beefy/justifications/1", genesis_hex); + let justif_proto_name = justifications_protocol_name(&genesis_hash, None); + assert_eq!(justif_proto_name.to_string(), expected_justif_name); + + // Create protocol name using hardcoded genesis hash. Verify exact representation. + let genesis_hash = [ + 50, 4, 60, 123, 58, 106, 216, 246, 194, 188, 139, 193, 33, 212, 202, 171, 9, 55, 123, + 94, 8, 43, 12, 251, 187, 57, 173, 19, 188, 74, 205, 147, + ]; + let genesis_hex = "32043c7b3a6ad8f6c2bc8bc121d4caab09377b5e082b0cfbbb39ad13bc4acd93"; + + let expected_gossip_name = format!("/{}/beefy/1", genesis_hex); + let gossip_proto_name = gossip_protocol_name(&genesis_hash, None); + assert_eq!(gossip_proto_name.to_string(), expected_gossip_name); + + let expected_justif_name = format!("/{}/beefy/justifications/1", genesis_hex); + let justif_proto_name = justifications_protocol_name(&genesis_hash, None); + assert_eq!(justif_proto_name.to_string(), expected_justif_name); + } +} diff --git a/client/beefy/src/notification.rs b/client/beefy/src/communication/notification.rs similarity index 100% rename from client/beefy/src/notification.rs rename to client/beefy/src/communication/notification.rs diff --git a/client/beefy/src/communication/peers.rs b/client/beefy/src/communication/peers.rs new file mode 100644 index 0000000000000..0e20a0f4e0ff6 --- /dev/null +++ b/client/beefy/src/communication/peers.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Logic for keeping track of BEEFY peers. + +// TODO (issue #12296): replace this naive peer tracking with generic one that infers data +// from multiple network protocols. + +use sc_network::PeerId; +use sp_runtime::traits::{Block, NumberFor, Zero}; +use std::collections::{HashMap, VecDeque}; + +struct PeerData { + last_voted_on: NumberFor, +} + +impl Default for PeerData { + fn default() -> Self { + PeerData { last_voted_on: Zero::zero() } + } +} + +/// Keep a simple map of connected peers +/// and the most recent voting round they participated in. +pub struct KnownPeers { + live: HashMap>, +} + +impl KnownPeers { + pub fn new() -> Self { + Self { live: HashMap::new() } + } + + /// Add new connected `peer`. + pub fn add_new(&mut self, peer: PeerId) { + self.live.entry(peer).or_default(); + } + + /// Note vote round number for `peer`. + pub fn note_vote_for(&mut self, peer: PeerId, round: NumberFor) { + let data = self.live.entry(peer).or_default(); + data.last_voted_on = round.max(data.last_voted_on); + } + + /// Remove connected `peer`. + pub fn remove(&mut self, peer: &PeerId) { + self.live.remove(peer); + } + + /// Return _filtered and cloned_ list of peers that have voted on `block` or higher. + pub fn at_least_at_block(&self, block: NumberFor) -> VecDeque { + self.live + .iter() + .filter_map(|(k, v)| (v.last_voted_on >= block).then_some(k)) + .cloned() + .collect() + } + + /// Answer whether `peer` is part of `KnownPeers` set. + pub fn contains(&self, peer: &PeerId) -> bool { + self.live.contains_key(peer) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_track_known_peers_progress() { + let (alice, bob, charlie) = (PeerId::random(), PeerId::random(), PeerId::random()); + let mut peers = KnownPeers::::new(); + assert!(peers.live.is_empty()); + + // Alice and Bob new connected peers. + peers.add_new(alice); + peers.add_new(bob); + // 'Tracked' Bob seen voting for 5. + peers.note_vote_for(bob, 5); + // Previously unseen Charlie now seen voting for 10. + peers.note_vote_for(charlie, 10); + + assert_eq!(peers.live.len(), 3); + assert!(peers.contains(&alice)); + assert!(peers.contains(&bob)); + assert!(peers.contains(&charlie)); + + // Get peers at block >= 5 + let at_5 = peers.at_least_at_block(5); + // Should be Bob and Charlie + assert_eq!(at_5.len(), 2); + assert!(at_5.contains(&bob)); + assert!(at_5.contains(&charlie)); + + // 'Tracked' Alice seen voting for 10. + peers.note_vote_for(alice, 10); + + // Get peers at block >= 9 + let at_9 = peers.at_least_at_block(9); + // Should be Charlie and Alice + assert_eq!(at_9.len(), 2); + assert!(at_9.contains(&charlie)); + assert!(at_9.contains(&alice)); + + // Remove Alice + peers.remove(&alice); + assert_eq!(peers.live.len(), 2); + assert!(!peers.contains(&alice)); + + // Get peers at block >= 9 + let at_9 = peers.at_least_at_block(9); + // Now should be just Charlie + assert_eq!(at_9.len(), 1); + assert!(at_9.contains(&charlie)); + } +} diff --git a/client/beefy/src/communication/request_response/incoming_requests_handler.rs b/client/beefy/src/communication/request_response/incoming_requests_handler.rs new file mode 100644 index 0000000000000..c0910a60fba3b --- /dev/null +++ b/client/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -0,0 +1,193 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Helper for handling (i.e. answering) BEEFY justifications requests from a remote peer. + +use beefy_primitives::BEEFY_ENGINE_ID; +use codec::Decode; +use futures::{ + channel::{mpsc, oneshot}, + StreamExt, +}; +use log::{debug, trace}; +use sc_client_api::BlockBackend; +use sc_network::{config as netconfig, config::RequestResponseConfig, PeerId, ReputationChange}; +use sc_network_common::protocol::ProtocolName; +use sp_runtime::{generic::BlockId, traits::Block}; +use std::{marker::PhantomData, sync::Arc}; + +use crate::communication::request_response::{ + on_demand_justifications_protocol_config, Error, JustificationRequest, +}; + +/// A request coming in, including a sender for sending responses. +#[derive(Debug)] +pub(crate) struct IncomingRequest { + /// `PeerId` of sending peer. + pub peer: PeerId, + /// The sent request. + pub payload: JustificationRequest, + /// Sender for sending response back. + pub pending_response: oneshot::Sender, +} + +impl IncomingRequest { + /// Create new `IncomingRequest`. + pub fn new( + peer: PeerId, + payload: JustificationRequest, + pending_response: oneshot::Sender, + ) -> Self { + Self { peer, payload, pending_response } + } + + /// Try building from raw network request. + /// + /// This function will fail if the request cannot be decoded and will apply passed in + /// reputation changes in that case. + /// + /// Params: + /// - The raw request to decode + /// - Reputation changes to apply for the peer in case decoding fails. + pub fn try_from_raw( + raw: netconfig::IncomingRequest, + reputation_changes: Vec, + ) -> Result { + let netconfig::IncomingRequest { payload, peer, pending_response } = raw; + let payload = match JustificationRequest::decode(&mut payload.as_ref()) { + Ok(payload) => payload, + Err(err) => { + let response = netconfig::OutgoingResponse { + result: Err(()), + reputation_changes, + sent_feedback: None, + }; + if let Err(_) = pending_response.send(response) { + return Err(Error::DecodingErrorNoReputationChange(peer, err)) + } + return Err(Error::DecodingError(peer, err)) + }, + }; + Ok(Self::new(peer, payload, pending_response)) + } +} + +/// Receiver for incoming BEEFY justifications requests. +/// +/// Takes care of decoding and handling of invalid encoded requests. +pub(crate) struct IncomingRequestReceiver { + raw: mpsc::Receiver, +} + +impl IncomingRequestReceiver { + pub fn new(inner: mpsc::Receiver) -> Self { + Self { raw: inner } + } + + /// Try to receive the next incoming request. + /// + /// Any received request will be decoded, on decoding errors the provided reputation changes + /// will be applied and an error will be reported. + pub async fn recv(&mut self, reputation_changes: F) -> Result, Error> + where + B: Block, + F: FnOnce() -> Vec, + { + let req = match self.raw.next().await { + None => return Err(Error::RequestChannelExhausted), + Some(raw) => IncomingRequest::::try_from_raw(raw, reputation_changes())?, + }; + Ok(req) + } +} + +/// Handler for incoming BEEFY justifications requests from a remote peer. +pub struct BeefyJustifsRequestHandler { + pub(crate) request_receiver: IncomingRequestReceiver, + pub(crate) justif_protocol_name: ProtocolName, + pub(crate) client: Arc, + pub(crate) _block: PhantomData, +} + +impl BeefyJustifsRequestHandler +where + B: Block, + Client: BlockBackend + Send + Sync, +{ + /// Create a new [`BeefyJustifsRequestHandler`]. + pub fn new>( + genesis_hash: Hash, + fork_id: Option<&str>, + client: Arc, + ) -> (Self, RequestResponseConfig) { + let (request_receiver, config) = + on_demand_justifications_protocol_config(genesis_hash, fork_id); + let justif_protocol_name = config.name.clone(); + + (Self { request_receiver, justif_protocol_name, client, _block: PhantomData }, config) + } + + /// Network request-response protocol name used by this handler. + pub fn protocol_name(&self) -> ProtocolName { + self.justif_protocol_name.clone() + } + + // Sends back justification response if justification found in client backend. + fn handle_request(&self, request: IncomingRequest) -> Result<(), Error> { + // TODO (issue #12293): validate `request` and change peer reputation for invalid requests. + + let maybe_encoded_proof = self + .client + .justifications(&BlockId::Number(request.payload.begin)) + .map_err(Error::Client)? + .and_then(|justifs| justifs.get(BEEFY_ENGINE_ID).cloned()) + // No BEEFY justification present. + .ok_or(()); + + request + .pending_response + .send(netconfig::OutgoingResponse { + result: maybe_encoded_proof, + reputation_changes: Vec::new(), + sent_feedback: None, + }) + .map_err(|_| Error::SendResponse) + } + + /// Run [`BeefyJustifsRequestHandler`]. + pub async fn run(mut self) { + trace!(target: "beefy::sync", "🥩 Running BeefyJustifsRequestHandler"); + + while let Ok(request) = self.request_receiver.recv(|| vec![]).await { + let peer = request.peer; + match self.handle_request(request) { + Ok(()) => { + debug!( + target: "beefy::sync", + "🥩 Handled BEEFY justification request from {:?}.", peer + ) + }, + Err(e) => { + // TODO (issue #12293): apply reputation changes here based on error type. + debug!( + target: "beefy::sync", + "🥩 Failed to handle BEEFY justification request from {:?}: {}", peer, e, + ) + }, + } + } + } +} diff --git a/client/beefy/src/communication/request_response/mod.rs b/client/beefy/src/communication/request_response/mod.rs new file mode 100644 index 0000000000000..c83bb9d57e91b --- /dev/null +++ b/client/beefy/src/communication/request_response/mod.rs @@ -0,0 +1,101 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Request/response protocol for syncing BEEFY justifications. + +mod incoming_requests_handler; +pub(crate) mod outgoing_requests_engine; + +pub use incoming_requests_handler::BeefyJustifsRequestHandler; + +use futures::channel::mpsc; +use std::time::Duration; + +use codec::{Decode, Encode, Error as CodecError}; +use sc_network::{config::RequestResponseConfig, PeerId}; +use sp_runtime::traits::{Block, NumberFor}; + +use crate::communication::beefy_protocol_name::justifications_protocol_name; +use incoming_requests_handler::IncomingRequestReceiver; + +// 10 seems reasonable, considering justifs are explicitly requested only +// for mandatory blocks, by nodes that are syncing/catching-up. +const JUSTIF_CHANNEL_SIZE: usize = 10; + +const MAX_RESPONSE_SIZE: u64 = 1024 * 1024; +const JUSTIF_REQUEST_TIMEOUT: Duration = Duration::from_secs(3); + +/// Get the configuration for the BEEFY justifications Request/response protocol. +/// +/// Returns a receiver for messages received on this protocol and the requested +/// `ProtocolConfig`. +/// +/// Consider using [`BeefyJustifsRequestHandler`] instead of this low-level function. +pub(crate) fn on_demand_justifications_protocol_config>( + genesis_hash: Hash, + fork_id: Option<&str>, +) -> (IncomingRequestReceiver, RequestResponseConfig) { + let name = justifications_protocol_name(genesis_hash, fork_id); + let fallback_names = vec![]; + let (tx, rx) = mpsc::channel(JUSTIF_CHANNEL_SIZE); + let rx = IncomingRequestReceiver::new(rx); + let cfg = RequestResponseConfig { + name, + fallback_names, + max_request_size: 32, + max_response_size: MAX_RESPONSE_SIZE, + // We are connected to all validators: + request_timeout: JUSTIF_REQUEST_TIMEOUT, + inbound_queue: Some(tx), + }; + (rx, cfg) +} + +/// BEEFY justification request. +#[derive(Debug, Clone, Encode, Decode)] +pub struct JustificationRequest { + /// Start collecting proofs from this block. + pub begin: NumberFor, +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error(transparent)] + Client(#[from] sp_blockchain::Error), + + #[error(transparent)] + RuntimeApi(#[from] sp_api::ApiError), + + /// Decoding failed, we were able to change the peer's reputation accordingly. + #[error("Decoding request failed for peer {0}.")] + DecodingError(PeerId, #[source] CodecError), + + /// Decoding failed, but sending reputation change failed. + #[error("Decoding request failed for peer {0}, and changing reputation failed.")] + DecodingErrorNoReputationChange(PeerId, #[source] CodecError), + + /// Incoming request stream exhausted. Should only happen on shutdown. + #[error("Incoming request channel got closed.")] + RequestChannelExhausted, + + #[error("Failed to send response.")] + SendResponse, + + #[error("Received invalid response.")] + InvalidResponse, +} diff --git a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs new file mode 100644 index 0000000000000..e22958e19cd2e --- /dev/null +++ b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -0,0 +1,245 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Generating request logic for request/response protocol for syncing BEEFY justifications. + +use beefy_primitives::{crypto::AuthorityId, BeefyApi, ValidatorSet}; +use codec::Encode; +use futures::{ + channel::{oneshot, oneshot::Canceled}, + stream::{self, StreamExt}, +}; +use log::{debug, error, warn}; +use parking_lot::Mutex; +use sc_network::{PeerId, ProtocolName}; +use sc_network_common::{ + request_responses::{IfDisconnected, RequestFailure}, + service::NetworkRequest, +}; +use sp_api::ProvideRuntimeApi; +use sp_runtime::{ + generic::BlockId, + traits::{Block, NumberFor}, +}; +use std::{collections::VecDeque, result::Result, sync::Arc}; + +use crate::{ + communication::request_response::{Error, JustificationRequest}, + justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, + KnownPeers, +}; + +/// Response type received from network. +type Response = Result, RequestFailure>; +/// Used to receive a response from the network. +type ResponseReceiver = oneshot::Receiver; + +enum State { + Idle(stream::Pending>), + AwaitingResponse(PeerId, NumberFor, stream::Once), +} + +pub struct OnDemandJustificationsEngine { + network: Arc, + runtime: Arc, + protocol_name: ProtocolName, + + live_peers: Arc>>, + peers_cache: VecDeque, + + state: State, +} + +impl OnDemandJustificationsEngine +where + B: Block, + R: ProvideRuntimeApi, + R::Api: BeefyApi, +{ + pub fn new( + network: Arc, + runtime: Arc, + protocol_name: ProtocolName, + live_peers: Arc>>, + ) -> Self { + Self { + network, + runtime, + protocol_name, + live_peers, + peers_cache: VecDeque::new(), + state: State::Idle(stream::pending()), + } + } + + fn reset_peers_cache_for_block(&mut self, block: NumberFor) { + // TODO (issue #12296): replace peer selection with generic one that involves all protocols. + self.peers_cache = self.live_peers.lock().at_least_at_block(block); + } + + fn try_next_peer(&mut self) -> Option { + // TODO (issue #12296): replace peer selection with generic one that involves all protocols. + let live = self.live_peers.lock(); + while let Some(peer) = self.peers_cache.pop_front() { + if live.contains(&peer) { + return Some(peer) + } + } + None + } + + fn request_from_peer(&mut self, peer: PeerId, block: NumberFor) { + debug!(target: "beefy::sync", "🥩 requesting justif #{:?} from peer {:?}", block, peer); + + let payload = JustificationRequest:: { begin: block }.encode(); + + let (tx, rx) = oneshot::channel(); + + self.network.start_request( + peer, + self.protocol_name.clone(), + payload, + tx, + IfDisconnected::ImmediateError, + ); + + self.state = State::AwaitingResponse(peer, block, stream::once(rx)); + } + + /// If no other request is in progress, start new justification request for `block`. + pub fn request(&mut self, block: NumberFor) { + // ignore new requests while there's already one pending + match &self.state { + State::AwaitingResponse(_, _, _) => return, + State::Idle(_) => (), + } + self.reset_peers_cache_for_block(block); + + // Start the requests engine - each unsuccessful received response will automatically + // trigger a new request to the next peer in the `peers_cache` until there are none left. + if let Some(peer) = self.try_next_peer() { + self.request_from_peer(peer, block); + } else { + debug!(target: "beefy::sync", "🥩 no good peers to request justif #{:?} from", block); + } + } + + /// Cancel any pending request for block numbers smaller or equal to `block`. + pub fn cancel_requests_older_than(&mut self, block: NumberFor) { + match &self.state { + State::AwaitingResponse(_, number, _) if *number <= block => { + debug!( + target: "beefy::sync", + "🥩 cancel pending request for justification #{:?}", + number + ); + self.state = State::Idle(stream::pending()); + }, + _ => (), + } + } + + fn process_response( + &mut self, + peer: PeerId, + block: NumberFor, + validator_set: &ValidatorSet, + response: Result, + ) -> Result, Error> { + response + .map_err(|e| { + debug!( + target: "beefy::sync", + "🥩 for on demand justification #{:?}, peer {:?} hung up: {:?}", + block, peer, e + ); + Error::InvalidResponse + })? + .map_err(|e| { + debug!( + target: "beefy::sync", + "🥩 for on demand justification #{:?}, peer {:?} error: {:?}", + block, peer, e + ); + Error::InvalidResponse + }) + .and_then(|encoded| { + decode_and_verify_finality_proof::(&encoded[..], block, &validator_set).map_err( + |e| { + debug!( + target: "beefy::sync", + "🥩 for on demand justification #{:?}, peer {:?} responded with invalid proof: {:?}", + block, peer, e + ); + Error::InvalidResponse + }, + ) + }) + } + + pub async fn next(&mut self) -> Option> { + let (peer, block, resp) = match &mut self.state { + State::Idle(pending) => { + let _ = pending.next().await; + // This never happens since 'stream::pending' never generates any items. + return None + }, + State::AwaitingResponse(peer, block, receiver) => { + let resp = receiver.next().await?; + (*peer, *block, resp) + }, + }; + // We received the awaited response. Our 'stream::once()' receiver will never generate any + // other response, meaning we're done with current state. Move the engine to `State::Idle`. + self.state = State::Idle(stream::pending()); + + let block_id = BlockId::number(block); + let validator_set = self + .runtime + .runtime_api() + .validator_set(&block_id) + .map_err(|e| { + error!(target: "beefy::sync", "🥩 Runtime API error {:?} in on-demand justif engine.", e); + e + }) + .ok()? + .or_else(|| { + error!(target: "beefy::sync", "🥩 BEEFY pallet not available for block {:?}.", block); + None + })?; + + self.process_response(peer, block, &validator_set, resp) + .map_err(|_| { + // No valid justification received, try next peer in our set. + if let Some(peer) = self.try_next_peer() { + self.request_from_peer(peer, block); + } else { + warn!(target: "beefy::sync", "🥩 ran out of peers to request justif #{:?} from", block); + } + }) + .map(|proof| { + debug!( + target: "beefy::sync", + "🥩 received valid on-demand justif #{:?} from {:?}", + block, peer + ); + proof + }) + .ok() + } +} diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index db4d8bfba7450..89a4517334189 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -33,8 +33,8 @@ use sc_client_api::backend::Backend; use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResult}; use crate::{ + communication::notification::BeefyVersionedFinalityProofSender, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, - notification::BeefyVersionedFinalityProofSender, }; /// A block-import handler for BEEFY. diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index ad527b2929585..7407f101e99a5 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -17,10 +17,12 @@ // along with this program. If not, see . use beefy_primitives::{BeefyApi, MmrRootHash}; +use parking_lot::Mutex; use prometheus::Registry; -use sc_client_api::{Backend, BlockchainEvents, Finalizer}; +use sc_client_api::{Backend, BlockBackend, BlockchainEvents, Finalizer}; use sc_consensus::BlockImport; use sc_network::ProtocolName; +use sc_network_common::service::NetworkRequest; use sc_network_gossip::Network as GossipNetwork; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; @@ -28,68 +30,38 @@ use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_keystore::SyncCryptoStorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::Block; -use std::sync::Arc; +use std::{marker::PhantomData, sync::Arc}; mod error; -mod gossip; mod keystore; mod metrics; mod round; mod worker; +pub mod communication; pub mod import; pub mod justification; -pub mod notification; #[cfg(test)] mod tests; use crate::{ - import::BeefyBlockImport, - notification::{ - BeefyBestBlockSender, BeefyBestBlockStream, BeefyVersionedFinalityProofSender, - BeefyVersionedFinalityProofStream, + communication::{ + notification::{ + BeefyBestBlockSender, BeefyBestBlockStream, BeefyVersionedFinalityProofSender, + BeefyVersionedFinalityProofStream, + }, + peers::KnownPeers, + request_response::{ + outgoing_requests_engine::OnDemandJustificationsEngine, BeefyJustifsRequestHandler, + }, }, + import::BeefyBlockImport, }; -pub use beefy_protocol_name::standard_name as protocol_standard_name; - -pub(crate) mod beefy_protocol_name { - use sc_chain_spec::ChainSpec; - use sc_network::ProtocolName; - - const NAME: &str = "/beefy/1"; - /// Old names for the notifications protocol, used for backward compatibility. - pub(crate) const LEGACY_NAMES: [&str; 1] = ["/paritytech/beefy/1"]; - - /// Name of the notifications protocol used by BEEFY. - /// - /// Must be registered towards the networking in order for BEEFY to properly function. - pub fn standard_name>( - genesis_hash: &Hash, - chain_spec: &Box, - ) -> ProtocolName { - let genesis_hash = genesis_hash.as_ref(); - let chain_prefix = match chain_spec.fork_id() { - Some(fork_id) => format!("/{}/{}", array_bytes::bytes2hex("", genesis_hash), fork_id), - None => format!("/{}", array_bytes::bytes2hex("", genesis_hash)), - }; - format!("{}{}", chain_prefix, NAME).into() - } -} - -/// Returns the configuration value to put in -/// [`sc_network::config::NetworkConfiguration::extra_sets`]. -/// For standard protocol name see [`beefy_protocol_name::standard_name`]. -pub fn beefy_peers_set_config( - protocol_name: ProtocolName, -) -> sc_network_common::config::NonDefaultSetConfig { - let mut cfg = sc_network_common::config::NonDefaultSetConfig::new(protocol_name, 1024 * 1024); - - cfg.allow_non_reserved(25, 25); - cfg.add_fallback_names(beefy_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect()); - cfg -} +pub use communication::beefy_protocol_name::{ + gossip_protocol_name, justifications_protocol_name as justifs_protocol_name, +}; /// A convenience BEEFY client trait that defines all the type bounds a BEEFY client /// has to satisfy. Ideally that should actually be a trait alias. Unfortunately as @@ -159,13 +131,13 @@ where { // Voter -> RPC links let (to_rpc_justif_sender, from_voter_justif_stream) = - notification::BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = - notification::BeefyBestBlockStream::::channel(); + BeefyBestBlockStream::::channel(); // BlockImport -> Voter links let (to_voter_justif_sender, from_block_import_justif_stream) = - notification::BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); // BlockImport let import = @@ -180,6 +152,24 @@ where (import, voter_links, rpc_links) } +/// BEEFY gadget network parameters. +pub struct BeefyNetworkParams +where + B: Block, + N: GossipNetwork + NetworkRequest + SyncOracle + Send + Sync + 'static, +{ + /// Network implementing gossip, requests and sync-oracle. + pub network: Arc, + /// Chain specific BEEFY gossip protocol name. See + /// [`communication::beefy_protocol_name::gossip_protocol_name`]. + pub gossip_protocol_name: ProtocolName, + /// Chain specific BEEFY on-demand justifications protocol name. See + /// [`communication::beefy_protocol_name::justifications_protocol_name`]. + pub justifications_protocol_name: ProtocolName, + + pub _phantom: PhantomData, +} + /// BEEFY gadget initialization parameters. pub struct BeefyParams where @@ -188,7 +178,7 @@ where C: Client, R: ProvideRuntimeApi, R::Api: BeefyApi + MmrApi, - N: GossipNetwork + Clone + SyncOracle + Send + Sync + 'static, + N: GossipNetwork + NetworkRequest + SyncOracle + Send + Sync + 'static, { /// BEEFY client pub client: Arc, @@ -198,16 +188,16 @@ where pub runtime: Arc, /// Local key store pub key_store: Option, - /// Gossip network - pub network: N, + /// BEEFY voter network params + pub network_params: BeefyNetworkParams, /// Minimal delta between blocks, BEEFY should vote for pub min_block_delta: u32, /// Prometheus metric registry pub prometheus_registry: Option, - /// Chain specific GRANDPA protocol name. See [`beefy_protocol_name::standard_name`]. - pub protocol_name: ProtocolName, /// Links between the block importer, the background voter and the RPC layer. pub links: BeefyVoterLinks, + /// Handler for incoming BEEFY justifications requests from a remote peer. + pub on_demand_justifications_handler: BeefyJustifsRequestHandler, } /// Start the BEEFY gadget. @@ -217,32 +207,43 @@ pub async fn start_beefy_gadget(beefy_params: BeefyParams, - C: Client, + C: Client + BlockBackend, R: ProvideRuntimeApi, R::Api: BeefyApi + MmrApi, - N: GossipNetwork + Clone + SyncOracle + Send + Sync + 'static, + N: GossipNetwork + NetworkRequest + SyncOracle + Send + Sync + 'static, { let BeefyParams { client, backend, runtime, key_store, - network, + network_params, min_block_delta, prometheus_registry, - protocol_name, links, + on_demand_justifications_handler, } = beefy_params; - let sync_oracle = network.clone(); - let gossip_validator = Arc::new(gossip::GossipValidator::new()); + let BeefyNetworkParams { network, gossip_protocol_name, justifications_protocol_name, .. } = + network_params; + + let known_peers = Arc::new(Mutex::new(KnownPeers::new())); + let gossip_validator = + Arc::new(communication::gossip::GossipValidator::new(known_peers.clone())); let gossip_engine = sc_network_gossip::GossipEngine::new( - network, - protocol_name, + network.clone(), + gossip_protocol_name, gossip_validator.clone(), None, ); + let on_demand_justifications = OnDemandJustificationsEngine::new( + network.clone(), + runtime.clone(), + justifications_protocol_name, + known_peers.clone(), + ); + let metrics = prometheus_registry.as_ref().map(metrics::Metrics::register).and_then( |result| match result { @@ -261,10 +262,12 @@ where client, backend, runtime, - sync_oracle, + network, key_store: key_store.into(), + known_peers, gossip_engine, gossip_validator, + on_demand_justifications, links, metrics, min_block_delta, @@ -272,5 +275,5 @@ where let worker = worker::BeefyWorker::<_, _, _, _, _>::new(worker_params); - worker.run().await + futures::future::join(worker.run(), on_demand_justifications_handler.run()).await; } diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index c96613eb38a95..45d346ccd85eb 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -33,7 +33,7 @@ use sp_runtime::traits::{Block, NumberFor}; /// whether the local `self` validator has voted/signed. /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). -#[derive(Default)] +#[derive(Debug, Default)] struct RoundTracker { self_vote: bool, votes: HashMap, @@ -69,6 +69,7 @@ pub fn threshold(authorities: usize) -> usize { /// Only round numbers > `best_done` are of interest, all others are considered stale. /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). +#[derive(Debug)] pub(crate) struct Rounds { rounds: BTreeMap<(Payload, NumberFor), RoundTracker>, session_start: NumberFor, @@ -135,7 +136,7 @@ where } } - pub(crate) fn try_conclude( + pub(crate) fn should_conclude( &mut self, round: &(P, NumberFor), ) -> Option>> { @@ -148,7 +149,6 @@ where if done { let signatures = self.rounds.remove(round)?.votes; - self.conclude(round.1); Some( self.validators() .iter() @@ -279,7 +279,7 @@ mod tests { true )); // round not concluded - assert!(rounds.try_conclude(&round).is_none()); + assert!(rounds.should_conclude(&round).is_none()); // self vote already present, should not self vote assert!(!rounds.should_self_vote(&round)); @@ -296,7 +296,7 @@ mod tests { (Keyring::Dave.public(), Keyring::Dave.sign(b"I am committed")), false )); - assert!(rounds.try_conclude(&round).is_none()); + assert!(rounds.should_conclude(&round).is_none()); // add 2nd good vote assert!(rounds.add_vote( @@ -305,7 +305,7 @@ mod tests { false )); // round not concluded - assert!(rounds.try_conclude(&round).is_none()); + assert!(rounds.should_conclude(&round).is_none()); // add 3rd good vote assert!(rounds.add_vote( @@ -314,7 +314,8 @@ mod tests { false )); // round concluded - assert!(rounds.try_conclude(&round).is_some()); + assert!(rounds.should_conclude(&round).is_some()); + rounds.conclude(round.1); // Eve is a validator, but round was concluded, adding vote disallowed assert!(!rounds.add_vote( @@ -432,11 +433,12 @@ mod tests { assert_eq!(3, rounds.rounds.len()); // conclude unknown round - assert!(rounds.try_conclude(&(H256::from_low_u64_le(5), 5)).is_none()); + assert!(rounds.should_conclude(&(H256::from_low_u64_le(5), 5)).is_none()); assert_eq!(3, rounds.rounds.len()); // conclude round 2 - let signatures = rounds.try_conclude(&(H256::from_low_u64_le(2), 2)).unwrap(); + let signatures = rounds.should_conclude(&(H256::from_low_u64_le(2), 2)).unwrap(); + rounds.conclude(2); assert_eq!(1, rounds.rounds.len()); assert_eq!( diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 3e49f4e05cc91..8057bd7cab7a5 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -21,10 +21,9 @@ use futures::{future, stream::FuturesUnordered, Future, StreamExt}; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, sync::Arc, task::Poll}; +use std::{collections::HashMap, marker::PhantomData, sync::Arc, task::Poll}; use tokio::{runtime::Runtime, time::Duration}; -use sc_chain_spec::{ChainSpec, GenericChainSpec}; use sc_client_api::HeaderBackend; use sc_consensus::{ BlockImport, BlockImportParams, BoxJustificationImport, ForkChoiceStrategy, ImportResult, @@ -33,7 +32,7 @@ use sc_consensus::{ use sc_keystore::LocalKeystore; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, - TestNetFactory, + PeersFullClient, TestNetFactory, }; use sc_utils::notification::NotificationReceiver; @@ -42,6 +41,7 @@ use beefy_primitives::{ BeefyApi, ConsensusLog, MmrRootHash, ValidatorSet, VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, }; +use sc_network::{config::RequestResponseConfig, ProtocolName}; use sp_mmr_primitives::{ BatchProof, EncodableOpaqueLeaf, Error as MmrError, LeafIndex, MmrApi, Proof, }; @@ -60,11 +60,21 @@ use sp_runtime::{ use substrate_test_runtime_client::{runtime::Header, ClientExt}; use crate::{ - beefy_block_import_and_links, beefy_protocol_name, justification::*, - keystore::tests::Keyring as BeefyKeyring, BeefyRPCLinks, BeefyVoterLinks, + beefy_block_import_and_links, + communication::request_response::{ + on_demand_justifications_protocol_config, BeefyJustifsRequestHandler, + }, + gossip_protocol_name, + justification::*, + keystore::tests::Keyring as BeefyKeyring, + BeefyRPCLinks, BeefyVoterLinks, }; -pub(crate) const BEEFY_PROTOCOL_NAME: &'static str = "/beefy/1"; +const GENESIS_HASH: H256 = H256::zero(); +fn beefy_gossip_proto_name() -> ProtocolName { + gossip_protocol_name(GENESIS_HASH, None) +} + const GOOD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0xbf); const BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x42); @@ -89,35 +99,12 @@ impl BuildStorage for Genesis { } } -#[test] -fn beefy_protocol_name() { - let chain_spec = GenericChainSpec::::from_json_bytes( - &include_bytes!("../../chain-spec/res/chain_spec.json")[..], - ) - .unwrap() - .cloned_box(); - - // Create protocol name using random genesis hash. - let genesis_hash = H256::random(); - let expected = format!("/{}/beefy/1", array_bytes::bytes2hex("", genesis_hash.as_ref())); - let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); - assert_eq!(proto_name.to_string(), expected); - - // Create protocol name using hardcoded genesis hash. Verify exact representation. - let genesis_hash = [ - 50, 4, 60, 123, 58, 106, 216, 246, 194, 188, 139, 193, 33, 212, 202, 171, 9, 55, 123, 94, - 8, 43, 12, 251, 187, 57, 173, 19, 188, 74, 205, 147, - ]; - let expected = - "/32043c7b3a6ad8f6c2bc8bc121d4caab09377b5e082b0cfbbb39ad13bc4acd93/beefy/1".to_string(); - let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); - assert_eq!(proto_name.to_string(), expected); -} - #[derive(Default)] pub(crate) struct PeerData { pub(crate) beefy_rpc_links: Mutex>>, pub(crate) beefy_voter_links: Mutex>>, + pub(crate) beefy_justif_req_handler: + Mutex>>, } #[derive(Default)] @@ -126,23 +113,34 @@ pub(crate) struct BeefyTestNet { } impl BeefyTestNet { - pub(crate) fn new(n_authority: usize, n_full: usize) -> Self { - let mut net = BeefyTestNet { peers: Vec::with_capacity(n_authority + n_full) }; - for _ in 0..n_authority { - net.add_authority_peer(); - } - for _ in 0..n_full { - net.add_full_peer(); + pub(crate) fn new(n_authority: usize) -> Self { + let mut net = BeefyTestNet { peers: Vec::with_capacity(n_authority) }; + + for i in 0..n_authority { + let (rx, cfg) = on_demand_justifications_protocol_config(GENESIS_HASH, None); + let justif_protocol_name = cfg.name.clone(); + + net.add_authority_peer(vec![cfg]); + + let client = net.peers[i].client().as_client(); + let justif_handler = BeefyJustifsRequestHandler { + request_receiver: rx, + justif_protocol_name, + client, + _block: PhantomData, + }; + *net.peers[i].data.beefy_justif_req_handler.lock() = Some(justif_handler); } net } - pub(crate) fn add_authority_peer(&mut self) { + pub(crate) fn add_authority_peer(&mut self, req_resp_cfgs: Vec) { self.add_full_peer_with_config(FullPeerConfig { - notifications_protocols: vec![BEEFY_PROTOCOL_NAME.into()], + notifications_protocols: vec![beefy_gossip_proto_name()], + request_response_protocols: req_resp_cfgs, is_authority: true, ..Default::default() - }) + }); } pub(crate) fn generate_blocks_and_sync( @@ -198,6 +196,7 @@ impl TestNetFactory for BeefyTestNet { let peer_data = PeerData { beefy_rpc_links: Mutex::new(Some(rpc_links)), beefy_voter_links: Mutex::new(Some(voter_links)), + ..Default::default() }; (BlockImportAdapter::new(block_import), None, peer_data) } @@ -215,11 +214,8 @@ impl TestNetFactory for BeefyTestNet { } fn add_full_peer(&mut self) { - self.add_full_peer_with_config(FullPeerConfig { - notifications_protocols: vec![BEEFY_PROTOCOL_NAME.into()], - is_authority: false, - ..Default::default() - }) + // `add_authority_peer()` used instead. + unimplemented!() } } @@ -354,7 +350,7 @@ where API: ProvideRuntimeApi + Default + Sync + Send, API::Api: BeefyApi + MmrApi, { - let voters = FuturesUnordered::new(); + let tasks = FuturesUnordered::new(); for (peer_id, key, api) in peers.into_iter() { let peer = &net.peers[peer_id]; @@ -362,31 +358,40 @@ where let keystore = create_beefy_keystore(*key); let (_, _, peer_data) = net.make_block_import(peer.client().clone()); - let PeerData { beefy_rpc_links, beefy_voter_links } = peer_data; + let PeerData { beefy_rpc_links, beefy_voter_links, .. } = peer_data; let beefy_voter_links = beefy_voter_links.lock().take(); *peer.data.beefy_rpc_links.lock() = beefy_rpc_links.lock().take(); *peer.data.beefy_voter_links.lock() = beefy_voter_links.clone(); + let on_demand_justif_handler = peer.data.beefy_justif_req_handler.lock().take().unwrap(); + + let network_params = crate::BeefyNetworkParams { + network: peer.network_service().clone(), + gossip_protocol_name: beefy_gossip_proto_name(), + justifications_protocol_name: on_demand_justif_handler.protocol_name(), + _phantom: PhantomData, + }; + let beefy_params = crate::BeefyParams { client: peer.client().as_client(), backend: peer.client().as_backend(), runtime: api.clone(), key_store: Some(keystore), - network: peer.network_service().clone(), + network_params, links: beefy_voter_links.unwrap(), min_block_delta, prometheus_registry: None, - protocol_name: BEEFY_PROTOCOL_NAME.into(), + on_demand_justifications_handler: on_demand_justif_handler, }; - let gadget = crate::start_beefy_gadget::<_, _, _, _, _>(beefy_params); + let task = crate::start_beefy_gadget::<_, _, _, _, _>(beefy_params); fn assert_send(_: &T) {} - assert_send(&gadget); - voters.push(gadget); + assert_send(&task); + tasks.push(task); } - voters.for_each(|_| async move {}) + tasks.for_each(|_| async move {}) } fn block_until(future: impl Future + Unpin, net: &Arc>, runtime: &mut Runtime) { @@ -404,18 +409,19 @@ fn run_for(duration: Duration, net: &Arc>, runtime: &mut Run pub(crate) fn get_beefy_streams( net: &mut BeefyTestNet, - peers: &[BeefyKeyring], + // peer index and key + peers: impl Iterator, ) -> (Vec>, Vec>>) { let mut best_block_streams = Vec::new(); let mut versioned_finality_proof_streams = Vec::new(); - for peer_id in 0..peers.len() { - let beefy_rpc_links = net.peer(peer_id).data.beefy_rpc_links.lock().clone().unwrap(); + peers.for_each(|(index, _)| { + let beefy_rpc_links = net.peer(index).data.beefy_rpc_links.lock().clone().unwrap(); let BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream } = beefy_rpc_links; best_block_streams.push(from_voter_best_beefy_stream.subscribe()); versioned_finality_proof_streams.push(from_voter_justif_stream.subscribe()); - } + }); (best_block_streams, versioned_finality_proof_streams) } @@ -493,18 +499,24 @@ fn streams_empty_after_timeout( fn finalize_block_and_wait_for_beefy( net: &Arc>, - peers: &[BeefyKeyring], + // peer index and key + peers: impl Iterator + Clone, runtime: &mut Runtime, finalize_targets: &[u64], expected_beefy: &[u64], ) { - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); for block in finalize_targets { let finalize = BlockId::number(*block); - for i in 0..peers.len() { - net.lock().peer(i).client().as_client().finalize_block(finalize, None).unwrap(); - } + peers.clone().for_each(|(index, _)| { + net.lock() + .peer(index) + .client() + .as_client() + .finalize_block(finalize, None) + .unwrap(); + }) } if expected_beefy.is_empty() { @@ -524,12 +536,12 @@ fn beefy_finalizing_blocks() { sp_tracing::try_init_simple(); let mut runtime = Runtime::new().unwrap(); - let peers = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); let session_len = 10; let min_block_delta = 4; - let mut net = BeefyTestNet::new(2, 0); + let mut net = BeefyTestNet::new(2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); @@ -542,17 +554,18 @@ fn beefy_finalizing_blocks() { // Minimum BEEFY block delta is 4. + let peers = peers.into_iter().enumerate(); // finalize block #5 -> BEEFY should finalize #1 (mandatory) and #5 from diff-power-of-two rule. - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[5], &[1, 5]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[5], &[1, 5]); // GRANDPA finalize #10 -> BEEFY finalize #10 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[10]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[10], &[10]); // GRANDPA finalize #18 -> BEEFY finalize #14, then #18 (diff-power-of-two rule) - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[18], &[14, 18]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[18], &[14, 18]); // GRANDPA finalize #20 -> BEEFY finalize #20 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[20], &[20]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[20], &[20]); // GRANDPA finalize #21 -> BEEFY finalize nothing (yet) because min delta is 4 finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[21], &[]); @@ -563,12 +576,12 @@ fn lagging_validators() { sp_tracing::try_init_simple(); let mut runtime = Runtime::new().unwrap(); - let peers = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); let session_len = 30; let min_block_delta = 1; - let mut net = BeefyTestNet::new(2, 0); + let mut net = BeefyTestNet::new(2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); @@ -578,13 +591,20 @@ fn lagging_validators() { let net = Arc::new(Mutex::new(net)); + let peers = peers.into_iter().enumerate(); // finalize block #15 -> BEEFY should finalize #1 (mandatory) and #9, #13, #14, #15 from // diff-power-of-two rule. - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[15], &[1, 9, 13, 14, 15]); + finalize_block_and_wait_for_beefy( + &net, + peers.clone(), + &mut runtime, + &[15], + &[1, 9, 13, 14, 15], + ); // Alice finalizes #25, Bob lags behind let finalize = BlockId::number(25); - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY let timeout = Some(Duration::from_millis(250)); @@ -592,21 +612,21 @@ fn lagging_validators() { streams_empty_after_timeout(versioned_finality_proof, &net, &mut runtime, None); // Bob catches up and also finalizes #25 - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); // expected beefy finalizes block #17 from diff-power-of-two wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[23, 24, 25]); wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[23, 24, 25]); // Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32 - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[30, 32], &[30, 31, 32]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[30, 32], &[30, 31, 32]); // Verify that session-boundary votes get buffered by client and only processed once // session-boundary block is GRANDPA-finalized (this guarantees authenticity for the new session // validator set). // Alice finalizes session-boundary mandatory block #60, Bob lags behind - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); let finalize = BlockId::number(60); net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY @@ -617,7 +637,7 @@ fn lagging_validators() { // Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60) let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); - // verify beefy skips intermediary votes, and successfully finalizes mandatory block #40 + // verify beefy skips intermediary votes, and successfully finalizes mandatory block #60 wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]); wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[60]); } @@ -627,13 +647,12 @@ fn correct_beefy_payload() { sp_tracing::try_init_simple(); let mut runtime = Runtime::new().unwrap(); - let peers = - &[BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave]; - let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave]; + let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); let session_len = 20; let min_block_delta = 2; - let mut net = BeefyTestNet::new(4, 0); + let mut net = BeefyTestNet::new(4); // Alice, Bob, Charlie will vote on good payloads let good_api = Arc::new(four_validators::TestApi {}); @@ -649,15 +668,16 @@ fn correct_beefy_payload() { let bad_peers = vec![(3, &BeefyKeyring::Dave, bad_api)]; runtime.spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); - // push 10 blocks + // push 12 blocks net.generate_blocks_and_sync(12, session_len, &validator_set, false); let net = Arc::new(Mutex::new(net)); + let peers = peers.into_iter().enumerate(); // with 3 good voters and 1 bad one, consensus should happen and best blocks produced. finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[1, 9]); let (best_blocks, versioned_finality_proof) = - get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]); + get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); // now 2 good validators and 1 bad one are voting net.lock() @@ -686,7 +706,7 @@ fn correct_beefy_payload() { // 3rd good validator catches up and votes as well let (best_blocks, versioned_finality_proof) = - get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]); + get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); net.lock() .peer(2) .client() @@ -707,11 +727,11 @@ fn beefy_importing_blocks() { sp_tracing::try_init_simple(); - let mut net = BeefyTestNet::new(2, 0); + let mut net = BeefyTestNet::new(2); let client = net.peer(0).client().clone(); let (mut block_import, _, peer_data) = net.make_block_import(client.clone()); - let PeerData { beefy_rpc_links: _, beefy_voter_links } = peer_data; + let PeerData { beefy_voter_links, .. } = peer_data; let justif_stream = beefy_voter_links.lock().take().unwrap().from_block_import_justif_stream; let params = |block: Block, justifications: Option| { @@ -826,18 +846,18 @@ fn voter_initialization() { // after waiting for BEEFY pallet availability. let mut runtime = Runtime::new().unwrap(); - let peers = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); let session_len = 5; // Should vote on all mandatory blocks no matter the `min_block_delta`. let min_block_delta = 10; - let mut net = BeefyTestNet::new(2, 0); + let mut net = BeefyTestNet::new(2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); - // push 30 blocks + // push 26 blocks net.generate_blocks_and_sync(26, session_len, &validator_set, false); let net = Arc::new(Mutex::new(net)); @@ -846,9 +866,90 @@ fn voter_initialization() { // Expect voters to pick up all of them and BEEFY-finalize the mandatory blocks of each session. finalize_block_and_wait_for_beefy( &net, - peers, + peers.into_iter().enumerate(), &mut runtime, &[1, 6, 10, 17, 24, 26], &[1, 5, 10, 15, 20, 25], ); } + +#[test] +fn on_demand_beefy_justification_sync() { + sp_tracing::try_init_simple(); + + let mut runtime = Runtime::new().unwrap(); + let all_peers = + [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave]; + let validator_set = ValidatorSet::new(make_beefy_ids(&all_peers), 0).unwrap(); + let session_len = 5; + let min_block_delta = 5; + + let mut net = BeefyTestNet::new(4); + + // Alice, Bob, Charlie start first and make progress through voting. + let api = Arc::new(four_validators::TestApi {}); + let fast_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; + let voting_peers = + fast_peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); + runtime.spawn(initialize_beefy(&mut net, voting_peers, min_block_delta)); + + // Dave will start late and have to catch up using on-demand justification requests (since + // in this test there is no block import queue to automatically import justifications). + let dave = vec![(3, &BeefyKeyring::Dave, api)]; + // Instantiate but don't run Dave, yet. + let dave_task = initialize_beefy(&mut net, dave, min_block_delta); + let dave_index = 3; + + // push 30 blocks + net.generate_blocks_and_sync(30, session_len, &validator_set, false); + + let fast_peers = fast_peers.into_iter().enumerate(); + let net = Arc::new(Mutex::new(net)); + // With 3 active voters and one inactive, consensus should happen and blocks BEEFY-finalized. + // Need to finalize at least one block in each session, choose randomly. + finalize_block_and_wait_for_beefy( + &net, + fast_peers.clone(), + &mut runtime, + &[1, 6, 10, 17, 24], + &[1, 5, 10, 15, 20], + ); + + // Spawn Dave, he's now way behind voting and can only catch up through on-demand justif sync. + runtime.spawn(dave_task); + // give Dave a chance to spawn and init. + run_for(Duration::from_millis(400), &net, &mut runtime); + + let (dave_best_blocks, _) = + get_beefy_streams(&mut net.lock(), [(dave_index, BeefyKeyring::Dave)].into_iter()); + net.lock() + .peer(dave_index) + .client() + .as_client() + .finalize_block(BlockId::number(1), None) + .unwrap(); + // Give Dave task some cpu cycles to process the finality notification, + run_for(Duration::from_millis(100), &net, &mut runtime); + // freshly spun up Dave now needs to listen for gossip to figure out the state of his peers. + + // Have the other peers do some gossip so Dave finds out about their progress. + finalize_block_and_wait_for_beefy(&net, fast_peers, &mut runtime, &[25], &[25]); + + // Now verify Dave successfully finalized #1 (through on-demand justification request). + wait_for_best_beefy_blocks(dave_best_blocks, &net, &mut runtime, &[1]); + + // Give Dave all tasks some cpu cycles to burn through their events queues, + run_for(Duration::from_millis(100), &net, &mut runtime); + // then verify Dave catches up through on-demand justification requests. + finalize_block_and_wait_for_beefy( + &net, + [(dave_index, BeefyKeyring::Dave)].into_iter(), + &mut runtime, + &[6, 10, 17, 24, 26], + &[5, 10, 15, 20, 25], + ); + + let all_peers = all_peers.into_iter().enumerate(); + // Now that Dave has caught up, sanity check voting works for all of them. + finalize_block_and_wait_for_beefy(&net, all_peers, &mut runtime, &[30], &[30]); +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 6e8c89d804984..832b43315515f 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -24,10 +24,15 @@ use std::{ }; use codec::{Codec, Decode, Encode}; -use futures::{stream::Fuse, StreamExt}; +use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn}; +use parking_lot::Mutex; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; +use sc_network_common::{ + protocol::event::Event as NetEvent, + service::{NetworkEventStream, NetworkRequest}, +}; use sc_network_gossip::GossipEngine; use sp_api::{BlockId, ProvideRuntimeApi}; @@ -48,14 +53,17 @@ use beefy_primitives::{ }; use crate::{ + communication::{ + gossip::{topic, GossipValidator}, + request_response::outgoing_requests_engine::OnDemandJustificationsEngine, + }, error::Error, - gossip::{topic, GossipValidator}, justification::BeefyVersionedFinalityProof, keystore::BeefyKeystore, metric_inc, metric_set, metrics::Metrics, round::Rounds, - BeefyVoterLinks, Client, + BeefyVoterLinks, Client, KnownPeers, }; enum RoundAction { @@ -113,6 +121,17 @@ impl VoterOracle { } } + /// Return current pending mandatory block, if any. + pub fn mandatory_pending(&self) -> Option> { + self.sessions.front().and_then(|round| { + if round.mandatory_done() { + None + } else { + Some(round.session_start()) + } + }) + } + /// Return `(A, B)` tuple representing inclusive [A, B] interval of votes to accept. pub fn accepted_interval( &self, @@ -175,29 +194,35 @@ impl VoterOracle { } } -pub(crate) struct WorkerParams { +pub(crate) struct WorkerParams { pub client: Arc, pub backend: Arc, pub runtime: Arc, - pub sync_oracle: SO, + pub network: N, pub key_store: BeefyKeystore, + pub known_peers: Arc>>, pub gossip_engine: GossipEngine, pub gossip_validator: Arc>, + pub on_demand_justifications: OnDemandJustificationsEngine, pub links: BeefyVoterLinks, pub metrics: Option, pub min_block_delta: u32, } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker { +pub(crate) struct BeefyWorker { // utilities client: Arc, backend: Arc, runtime: Arc, - sync_oracle: SO, + network: N, key_store: BeefyKeystore, + + // communication + known_peers: Arc>>, gossip_engine: GossipEngine, gossip_validator: Arc>, + on_demand_justifications: OnDemandJustificationsEngine, // channels /// Links between the block importer, the background voter and the RPC layer. @@ -218,14 +243,14 @@ pub(crate) struct BeefyWorker { voting_oracle: VoterOracle, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, C: Client, R: ProvideRuntimeApi, R::Api: BeefyApi + MmrApi, - SO: SyncOracle + Send + Sync + Clone + 'static, + N: NetworkEventStream + NetworkRequest + SyncOracle + Send + Sync + Clone + 'static, { /// Return a new BEEFY worker instance. /// @@ -233,15 +258,17 @@ where /// BEEFY pallet has been deployed on-chain. /// /// The BEEFY pallet is needed in order to keep track of the BEEFY authority set. - pub(crate) fn new(worker_params: WorkerParams) -> Self { + pub(crate) fn new(worker_params: WorkerParams) -> Self { let WorkerParams { client, backend, runtime, key_store, - sync_oracle, + network, gossip_engine, gossip_validator, + on_demand_justifications, + known_peers, links, metrics, min_block_delta, @@ -256,10 +283,12 @@ where client: client.clone(), backend, runtime, - sync_oracle, + network, + known_peers, key_store, gossip_engine, gossip_validator, + on_demand_justifications, links, metrics, best_grandpa_block_header: last_finalized_header, @@ -366,8 +395,6 @@ where { if let Some(new_validator_set) = find_authorities_change::(&header) { self.init_session_at(new_validator_set, *header.number()); - // TODO (grandpa-bridge-gadget/issues/20): when adding SYNC protocol, - // fire up a request for justification for this mandatory block here. } } } @@ -408,7 +435,10 @@ where let block_num = signed_commitment.commitment.block_number; let best_grandpa = *self.best_grandpa_block_header.number(); match self.voting_oracle.triage_round(block_num, best_grandpa)? { - RoundAction::Process => self.finalize(justification)?, + RoundAction::Process => { + debug!(target: "beefy", "🥩 Process justification for round: {:?}.", block_num); + self.finalize(justification)? + }, RoundAction::Enqueue => { debug!(target: "beefy", "🥩 Buffer justification for round: {:?}.", block_num); self.pending_justifications.entry(block_num).or_insert(justification); @@ -429,7 +459,7 @@ where let rounds = self.voting_oracle.rounds_mut().ok_or(Error::UninitSession)?; if rounds.add_vote(&round, vote, self_vote) { - if let Some(signatures) = rounds.try_conclude(&round) { + if let Some(signatures) = rounds.should_conclude(&round) { self.gossip_validator.conclude_round(round.1); let block_num = round.1; @@ -474,6 +504,8 @@ where self.best_beefy_block = Some(block_num); metric_set!(self, beefy_best_block, block_num); + self.on_demand_justifications.cancel_requests_older_than(block_num); + if let Err(e) = self.backend.append_justification( BlockId::Number(block_num), (BEEFY_ENGINE_ID, finality_proof.clone().encode()), @@ -735,7 +767,7 @@ where let at = BlockId::hash(notif.header.hash()); if let Some(active) = self.runtime.runtime_api().validator_set(&at).ok().flatten() { self.initialize_voter(¬if.header, active); - if !self.sync_oracle.is_major_syncing() { + if !self.network.is_major_syncing() { if let Err(err) = self.try_to_vote() { debug!(target: "beefy", "🥩 {}", err); } @@ -768,6 +800,7 @@ where self.wait_for_runtime_pallet(&mut finality_notifications).await; trace!(target: "beefy", "🥩 BEEFY pallet available, starting voter."); + let mut network_events = self.network.event_stream("network-gossip").fuse(); let mut votes = Box::pin( self.gossip_engine .messages_for(topic::()) @@ -788,15 +821,38 @@ where // The branches below only change 'state', actual voting happen afterwards, // based on the new resulting 'state'. futures::select_biased! { + // Use `select_biased!` to prioritize order below. + // Make sure to pump gossip engine. + _ = gossip_engine => { + error!(target: "beefy", "🥩 Gossip engine has terminated, closing worker."); + return; + }, + // Keep track of connected peers. + net_event = network_events.next() => { + if let Some(net_event) = net_event { + self.handle_network_event(net_event); + } else { + error!(target: "beefy", "🥩 Network events stream terminated, closing worker."); + return; + } + }, + // Process finality notifications first since these drive the voter. notification = finality_notifications.next() => { if let Some(notification) = notification { self.handle_finality_notification(¬ification); } else { + error!(target: "beefy", "🥩 Finality stream terminated, closing worker."); return; } }, - // TODO: when adding SYNC protocol, join the on-demand justifications stream to - // this one, and handle them both here. + // Process incoming justifications as these can make some in-flight votes obsolete. + justif = self.on_demand_justifications.next().fuse() => { + if let Some(justif) = justif { + if let Err(err) = self.triage_incoming_justif(justif) { + debug!(target: "beefy", "🥩 {}", err); + } + } + }, justif = block_import_justif.next() => { if let Some(justif) = justif { // Block import justifications have already been verified to be valid @@ -805,9 +861,11 @@ where debug!(target: "beefy", "🥩 {}", err); } } else { + error!(target: "beefy", "🥩 Block import stream terminated, closing worker."); return; } }, + // Finally process incoming votes. vote = votes.next() => { if let Some(vote) = vote { // Votes have already been verified to be valid by the gossip validator. @@ -815,13 +873,10 @@ where debug!(target: "beefy", "🥩 {}", err); } } else { + error!(target: "beefy", "🥩 Votes gossiping stream terminated, closing worker."); return; } }, - _ = gossip_engine => { - error!(target: "beefy", "🥩 Gossip engine has terminated."); - return; - } } // Handle pending justifications and/or votes for now GRANDPA finalized blocks. @@ -829,8 +884,14 @@ where debug!(target: "beefy", "🥩 {}", err); } - // Don't bother voting during major sync. - if !self.sync_oracle.is_major_syncing() { + // Don't bother voting or requesting justifications during major sync. + if !self.network.is_major_syncing() { + // If the current target is a mandatory block, + // make sure there's also an on-demand justification request out for it. + if let Some(block) = self.voting_oracle.mandatory_pending() { + // This only starts new request if there isn't already an active one. + self.on_demand_justifications.request(block); + } // There were external events, 'state' is changed, author a vote if needed/possible. if let Err(err) = self.try_to_vote() { debug!(target: "beefy", "🥩 {}", err); @@ -840,6 +901,20 @@ where } } } + + /// Update known peers based on network events. + fn handle_network_event(&mut self, event: NetEvent) { + match event { + NetEvent::SyncConnected { remote } => { + self.known_peers.lock().add_new(remote); + }, + NetEvent::SyncDisconnected { remote } => { + self.known_peers.lock().remove(&remote); + }, + // We don't care about other events. + _ => (), + } + } } /// Extract the MMR root hash from a digest in the given header, if it exists. @@ -932,11 +1007,11 @@ where pub(crate) mod tests { use super::*; use crate::{ + communication::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, keystore::tests::Keyring, - notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, tests::{ create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi, - BeefyPeer, BeefyTestNet, BEEFY_PROTOCOL_NAME, + BeefyPeer, BeefyTestNet, }, BeefyRPCLinks, }; @@ -979,21 +1054,29 @@ pub(crate) mod tests { let api = Arc::new(TestApi {}); let network = peer.network_service().clone(); - let sync_oracle = network.clone(); - let gossip_validator = Arc::new(crate::gossip::GossipValidator::new()); + let known_peers = Arc::new(Mutex::new(KnownPeers::new())); + let gossip_validator = Arc::new(GossipValidator::new(known_peers.clone())); let gossip_engine = - GossipEngine::new(network, BEEFY_PROTOCOL_NAME, gossip_validator.clone(), None); + GossipEngine::new(network.clone(), "/beefy/1", gossip_validator.clone(), None); + let on_demand_justifications = OnDemandJustificationsEngine::new( + network.clone(), + api.clone(), + "/beefy/justifs/1".into(), + known_peers.clone(), + ); let worker_params = crate::worker::WorkerParams { client: peer.client().as_client(), backend: peer.client().as_backend(), runtime: api, key_store: Some(keystore).into(), + known_peers, links, gossip_engine, gossip_validator, min_block_delta, metrics: None, - sync_oracle, + network, + on_demand_justifications, }; BeefyWorker::<_, _, _, _, _>::new(worker_params) } @@ -1245,7 +1328,7 @@ pub(crate) mod tests { fn keystore_vs_validator_set() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1, 0); + let mut net = BeefyTestNet::new(1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); // keystore doesn't contain other keys than validators' @@ -1266,13 +1349,15 @@ pub(crate) mod tests { #[test] fn should_finalize_correctly() { - let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1, 0); + let keys = [Keyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(&keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1); let backend = net.peer(0).client().as_backend(); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); - let (mut best_block_streams, mut finality_proofs) = get_beefy_streams(&mut net, keys); + let keys = keys.iter().cloned().enumerate(); + let (mut best_block_streams, mut finality_proofs) = + get_beefy_streams(&mut net, keys.clone()); let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); let mut finality_proof = finality_proofs.drain(..).next().unwrap(); @@ -1294,7 +1379,8 @@ pub(crate) mod tests { })); // unknown hash for block #1 - let (mut best_block_streams, mut finality_proofs) = get_beefy_streams(&mut net, keys); + let (mut best_block_streams, mut finality_proofs) = + get_beefy_streams(&mut net, keys.clone()); let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); let mut finality_proof = finality_proofs.drain(..).next().unwrap(); let justif = create_finality_proof(1); @@ -1355,7 +1441,7 @@ pub(crate) mod tests { fn should_init_session() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1, 0); + let mut net = BeefyTestNet::new(1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); assert!(worker.voting_oracle.sessions.is_empty()); @@ -1389,7 +1475,7 @@ pub(crate) mod tests { fn should_triage_votes_and_process_later() { let keys = &[Keyring::Alice, Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1, 0); + let mut net = BeefyTestNet::new(1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); fn new_vote( @@ -1450,7 +1536,7 @@ pub(crate) mod tests { fn should_initialize_correct_voter() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); - let mut net = BeefyTestNet::new(1, 0); + let mut net = BeefyTestNet::new(1); let backend = net.peer(0).client().as_backend(); // push 15 blocks with `AuthorityChange` digests every 10 blocks diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 2f6b788e368b3..9d5abf98ceff0 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -48,7 +48,7 @@ use sc_consensus::{ Verifier, }; use sc_network::{ - config::{NetworkConfiguration, Role, SyncMode}, + config::{NetworkConfiguration, RequestResponseConfig, Role, SyncMode}, Multiaddr, NetworkService, NetworkWorker, }; use sc_network_common::{ @@ -688,6 +688,8 @@ pub struct FullPeerConfig { pub block_announce_validator: Option + Send + Sync>>, /// List of notification protocols that the network must support. pub notifications_protocols: Vec, + /// List of request-response protocols that the network must support. + pub request_response_protocols: Vec, /// The indices of the peers the peer should be connected to. /// /// If `None`, it will be connected to all other peers. @@ -790,6 +792,9 @@ where network_config.transport = TransportConfig::MemoryOnly; network_config.listen_addresses = vec![listen_addr.clone()]; network_config.allow_non_globals_in_dht = true; + network_config + .request_response_protocols + .extend(config.request_response_protocols); network_config.extra_sets = config .notifications_protocols .into_iter() From 25795506052363e8b5795eb3526e61ef2a27d89a Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 3 Oct 2022 15:17:59 +0200 Subject: [PATCH 1227/1472] Fix `Weight::is_zero` (#12396) * Fix Weight::is_zero Signed-off-by: Oliver Tale-Yazdi * Add test Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- primitives/weights/src/weight_v2.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index a8eaf79a28711..8596a782c1fa7 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -318,7 +318,7 @@ impl Zero for Weight { } fn is_zero(&self) -> bool { - self.ref_time == 0 + self == &Self::zero() } } @@ -447,3 +447,16 @@ impl SubAssign for Weight { }; } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_zero_works() { + assert!(Weight::zero().is_zero()); + assert!(!Weight::from_components(1, 0).is_zero()); + assert!(!Weight::from_components(0, 1).is_zero()); + assert!(!Weight::MAX.is_zero()); + } +} From 1b23ec9f6d7880b358072b97d0030d3352cb20aa Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 3 Oct 2022 23:50:00 +0800 Subject: [PATCH 1228/1472] Remove unnecessary Clone trait bounds on CountedStorageMap (#12402) * Remove unnecessary Clone trait bounds on CountedStorageMap * cargo fmt --- .../support/src/storage/types/counted_map.rs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index c4027acfe7232..8c19434767f49 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -143,10 +143,7 @@ where } /// Store a value to be associated with the given key from the map. - pub fn insert + Clone, ValArg: EncodeLike>( - key: KeyArg, - val: ValArg, - ) { + pub fn insert, ValArg: EncodeLike>(key: KeyArg, val: ValArg) { if !::Map::contains_key(Ref::from(&key)) { CounterFor::::mutate(|value| value.saturating_inc()); } @@ -154,7 +151,7 @@ where } /// Remove the value under a key. - pub fn remove + Clone>(key: KeyArg) { + pub fn remove>(key: KeyArg) { if ::Map::contains_key(Ref::from(&key)) { CounterFor::::mutate(|value| value.saturating_dec()); } @@ -162,7 +159,7 @@ where } /// Mutate the value under a key. - pub fn mutate + Clone, R, F: FnOnce(&mut QueryKind::Query) -> R>( + pub fn mutate, R, F: FnOnce(&mut QueryKind::Query) -> R>( key: KeyArg, f: F, ) -> R { @@ -173,7 +170,7 @@ where /// Mutate the item, only if an `Ok` value is returned. pub fn try_mutate(key: KeyArg, f: F) -> Result where - KeyArg: EncodeLike + Clone, + KeyArg: EncodeLike, F: FnOnce(&mut QueryKind::Query) -> Result, { Self::try_mutate_exists(key, |option_value_ref| { @@ -187,7 +184,7 @@ where } /// Mutate the value under a key. Deletes the item if mutated to a `None`. - pub fn mutate_exists + Clone, R, F: FnOnce(&mut Option) -> R>( + pub fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( key: KeyArg, f: F, ) -> R { @@ -200,7 +197,7 @@ where /// or if the storage item does not exist (`None`), independent of the `QueryType`. pub fn try_mutate_exists(key: KeyArg, f: F) -> Result where - KeyArg: EncodeLike + Clone, + KeyArg: EncodeLike, F: FnOnce(&mut Option) -> Result, { ::Map::try_mutate_exists(key, |option_value| { @@ -222,7 +219,7 @@ where } /// Take the value under a key. - pub fn take + Clone>(key: KeyArg) -> QueryKind::Query { + pub fn take>(key: KeyArg) -> QueryKind::Query { let removed_value = ::Map::mutate_exists(key, |value| value.take()); if removed_value.is_some() { CounterFor::::mutate(|value| value.saturating_dec()); @@ -240,7 +237,7 @@ where /// `[item]`. Any default value set for the storage item will be ignored on overwrite. pub fn append(key: EncodeLikeKey, item: EncodeLikeItem) where - EncodeLikeKey: EncodeLike + Clone, + EncodeLikeKey: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, Value: StorageAppend, @@ -355,7 +352,7 @@ where /// Is only available if `Value` of the storage implements [`StorageTryAppend`]. pub fn try_append(key: KArg, item: EncodeLikeItem) -> Result<(), ()> where - KArg: EncodeLike + Clone, + KArg: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, Value: StorageTryAppend, From 6d7f76b5de00d4d4fdc55596abe86beb7d55f0b3 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 4 Oct 2022 09:58:05 +0300 Subject: [PATCH 1229/1472] docs/CODEOWNERS: add @acatangiu as MMR owner (#12406) --- docs/CODEOWNERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 0b9e6e7783058..cf2067d19450d 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -36,11 +36,13 @@ /client/consensus/pow/ @sorpaas /primitives/consensus/pow/ @sorpaas -# BEEFY +# BEEFY, MMR /client/beefy/ @acatangiu /frame/beefy/ @acatangiu /frame/beefy-mmr/ @acatangiu +/frame/merkle-mountain-range/ @acatangiu /primitives/beefy/ @acatangiu +/primitives/merkle-mountain-range/ @acatangiu # Contracts /frame/contracts/ @athei From 594d71afca8e70ed84297b01472bb1250d89ebd1 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 4 Oct 2022 17:01:50 +0900 Subject: [PATCH 1230/1472] Add @koute to `docs/CODEOWNERS` and update stale paths (#12408) --- docs/CODEOWNERS | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index cf2067d19450d..133ba7b094d43 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -24,8 +24,19 @@ /.gitlab-ci.yml @paritytech/ci # Sandboxing capability of Substrate Runtime -/primitives/sr-sandbox/ @pepyakin -/primitives/core/src/sandbox.rs @pepyakin +/primitives/sandbox/ @pepyakin @koute + +# WASM executor, low-level client <-> WASM interface and other WASM-related code +/client/executor/ @koute +/client/allocator/ @koute +/primitives/wasm-interface/ @koute +/primitives/runtime-interface/ @koute +/primitives/panic-handler/ @koute +/utils/wasm-builder/ @koute + +# Systems-related bits and bobs on the client side +/client/sysinfo/ @koute +/client/tracing/ @koute # GRANDPA, BABE, consensus stuff /frame/babe/ @andresilva From e77cbe39c4d1bfd978bb03c686fc9f60d86a3d06 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Tue, 4 Oct 2022 11:47:13 +0300 Subject: [PATCH 1231/1472] BEEFY: Simplify hashing for pallet-beefy-mmr (#12393) * beefy-mmr: reuse sp_runtime::traits::Keccak256 * beefy-mmr: use sp_runtime::traits:Hash for generating merkle proofs * beefy-mmr: use sp_runtime::traits:Hash for validating merkle proofs * beefy-mmr: remove primitives::Hasher and primitives::Hash * fixes * beefy-mmr: reduce the number of generic parameters for merkle_root() * fix * compute upper Vec capacity more accurately --- Cargo.lock | 2 +- frame/beefy-mmr/primitives/Cargo.toml | 8 +- frame/beefy-mmr/primitives/src/lib.rs | 236 ++++++++++++-------------- frame/beefy-mmr/src/lib.rs | 27 +-- frame/beefy-mmr/src/mock.rs | 3 +- 5 files changed, 118 insertions(+), 158 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 723a09ee9a39f..2f0a2df0f101b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -525,7 +525,7 @@ dependencies = [ "env_logger", "log", "sp-api", - "tiny-keccak", + "sp-runtime", ] [[package]] diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/frame/beefy-mmr/primitives/Cargo.toml index 1aa2573c7f680..a097da0fc30fd 100644 --- a/frame/beefy-mmr/primitives/Cargo.toml +++ b/frame/beefy-mmr/primitives/Cargo.toml @@ -11,10 +11,10 @@ homepage = "https://substrate.io" [dependencies] array-bytes = { version = "4.1", optional = true } log = { version = "0.4", default-features = false, optional = true } -tiny-keccak = { version = "2.0.2", features = ["keccak"], optional = true } beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/beefy" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } [dev-dependencies] array-bytes = "4.1" @@ -22,9 +22,9 @@ env_logger = "0.9" [features] debug = ["array-bytes", "log"] -default = ["debug", "keccak", "std"] -keccak = ["tiny-keccak"] +default = ["debug", "std"] std = [ "beefy-primitives/std", - "sp-api/std" + "sp-api/std", + "sp-runtime/std" ] diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/frame/beefy-mmr/primitives/src/lib.rs index 38831d7914715..f56be8bcafe5b 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/frame/beefy-mmr/primitives/src/lib.rs @@ -25,88 +25,49 @@ //! compilation targets. //! //! Merkle Tree is constructed from arbitrary-length leaves, that are initially hashed using the -//! same [Hasher] as the inner nodes. +//! same hasher as the inner nodes. //! Inner nodes are created by concatenating child hashes and hashing again. The implementation //! does not perform any sorting of the input data (leaves) nor when inner nodes are created. //! //! If the number of leaves is not even, last leave (hash of) is promoted to the upper layer. -#[cfg(not(feature = "std"))] -extern crate alloc; -#[cfg(not(feature = "std"))] -use alloc::vec::Vec; +pub use sp_runtime::traits::Keccak256; +use sp_runtime::{app_crypto::sp_core, sp_std, traits::Hash as HashT}; +use sp_std::{vec, vec::Vec}; use beefy_primitives::mmr::{BeefyAuthoritySet, BeefyNextAuthoritySet}; -/// Supported hashing output size. -/// -/// The size is restricted to 32 bytes to allow for a more optimised implementation. -pub type Hash = [u8; 32]; - -/// Generic hasher trait. -/// -/// Implement the function to support custom way of hashing data. -/// The implementation must return a [Hash](type@Hash) type, so only 32-byte output hashes are -/// supported. -pub trait Hasher { - /// Hash given arbitrary-length piece of data. - fn hash(data: &[u8]) -> Hash; -} - -#[cfg(feature = "keccak")] -mod keccak256 { - use tiny_keccak::{Hasher as _, Keccak}; - - /// Keccak256 hasher implementation. - pub struct Keccak256; - impl Keccak256 { - /// Hash given data. - pub fn hash(data: &[u8]) -> super::Hash { - ::hash(data) - } - } - impl super::Hasher for Keccak256 { - fn hash(data: &[u8]) -> super::Hash { - let mut keccak = Keccak::v256(); - keccak.update(data); - let mut output = [0_u8; 32]; - keccak.finalize(&mut output); - output - } - } -} -#[cfg(feature = "keccak")] -pub use keccak256::Keccak256; - /// Construct a root hash of a Binary Merkle Tree created from given leaves. /// /// See crate-level docs for details about Merkle Tree construction. /// /// In case an empty list of leaves is passed the function returns a 0-filled hash. -pub fn merkle_root(leaves: I) -> Hash +pub fn merkle_root(leaves: I) -> H::Output where - H: Hasher, - I: IntoIterator, - T: AsRef<[u8]>, + H: HashT, + H::Output: Default + AsRef<[u8]>, + I: IntoIterator, + I::Item: AsRef<[u8]>, { - let iter = leaves.into_iter().map(|l| H::hash(l.as_ref())); - merkelize::(iter, &mut ()) + let iter = leaves.into_iter().map(|l| ::hash(l.as_ref())); + merkelize::(iter, &mut ()).into() } -fn merkelize(leaves: I, visitor: &mut V) -> Hash +fn merkelize(leaves: I, visitor: &mut V) -> H::Output where - H: Hasher, - V: Visitor, - I: Iterator, + H: HashT, + H::Output: Default + AsRef<[u8]>, + V: Visitor, + I: Iterator, { - let upper = Vec::with_capacity(leaves.size_hint().0); + let upper = Vec::with_capacity((leaves.size_hint().1.unwrap_or(0).saturating_add(1)) / 2); let mut next = match merkelize_row::(leaves, upper, visitor) { Ok(root) => return root, - Err(next) if next.is_empty() => return Hash::default(), + Err(next) if next.is_empty() => return H::Output::default(), Err(next) => next, }; - let mut upper = Vec::with_capacity((next.len() + 1) / 2); + let mut upper = Vec::with_capacity((next.len().saturating_add(1)) / 2); loop { visitor.move_up(); @@ -125,14 +86,14 @@ where /// /// The structure contains all necessary data to later on verify the proof and the leaf itself. #[derive(Debug, PartialEq, Eq)] -pub struct MerkleProof { +pub struct MerkleProof { /// Root hash of generated merkle tree. - pub root: Hash, + pub root: H, /// Proof items (does not contain the leaf hash, nor the root obviously). /// /// This vec contains all inner node hashes necessary to reconstruct the root hash given the /// leaf hash. - pub proof: Vec, + pub proof: Vec, /// Number of leaves in the original tree. /// /// This is needed to detect a case where we have an odd number of leaves that "get promoted" @@ -141,14 +102,14 @@ pub struct MerkleProof { /// Index of the leaf the proof is for (0-based). pub leaf_index: usize, /// Leaf content. - pub leaf: T, + pub leaf: L, } /// A trait of object inspecting merkle root creation. /// /// It can be passed to [`merkelize_row`] or [`merkelize`] functions and will be notified /// about tree traversal. -trait Visitor { +trait Visitor { /// We are moving one level up in the tree. fn move_up(&mut self); @@ -158,13 +119,13 @@ trait Visitor { /// The method will also visit the `root` hash (level 0). /// /// The `index` is an index of `left` item. - fn visit(&mut self, index: usize, left: &Option, right: &Option); + fn visit(&mut self, index: usize, left: &Option, right: &Option); } /// No-op implementation of the visitor. -impl Visitor for () { +impl Visitor for () { fn move_up(&mut self) {} - fn visit(&mut self, _index: usize, _left: &Option, _right: &Option) {} + fn visit(&mut self, _index: usize, _left: &Option, _right: &Option) {} } /// Construct a Merkle Proof for leaves given by indices. @@ -177,16 +138,17 @@ impl Visitor for () { /// # Panic /// /// The function will panic if given `leaf_index` is greater than the number of leaves. -pub fn merkle_proof(leaves: I, leaf_index: usize) -> MerkleProof +pub fn merkle_proof(leaves: I, leaf_index: usize) -> MerkleProof where - H: Hasher, + H: HashT, + H::Output: Default + Copy + AsRef<[u8]>, I: IntoIterator, I::IntoIter: ExactSizeIterator, T: AsRef<[u8]>, { let mut leaf = None; let iter = leaves.into_iter().enumerate().map(|(idx, l)| { - let hash = H::hash(l.as_ref()); + let hash = ::hash(l.as_ref()); if idx == leaf_index { leaf = Some(l); } @@ -194,23 +156,23 @@ where }); /// The struct collects a proof for single leaf. - struct ProofCollection { - proof: Vec, + struct ProofCollection { + proof: Vec, position: usize, } - impl ProofCollection { + impl ProofCollection { fn new(position: usize) -> Self { ProofCollection { proof: Default::default(), position } } } - impl Visitor for ProofCollection { + impl Visitor for ProofCollection { fn move_up(&mut self) { self.position /= 2; } - fn visit(&mut self, index: usize, left: &Option, right: &Option) { + fn visit(&mut self, index: usize, left: &Option, right: &Option) { // we are at left branch - right goes to the proof. if self.position == index { if let Some(right) = right { @@ -238,7 +200,7 @@ where collect_proof .proof .iter() - .map(|s| array_bytes::bytes2hex("", s)) + .map(|s| array_bytes::bytes2hex("", s.as_ref())) .collect::>() ); @@ -250,25 +212,19 @@ where /// Can be either a value that needs to be hashed first, /// or the hash itself. #[derive(Debug, PartialEq, Eq)] -pub enum Leaf<'a> { +pub enum Leaf<'a, H> { /// Leaf content. Value(&'a [u8]), /// Hash of the leaf content. - Hash(Hash), + Hash(H), } -impl<'a, T: AsRef<[u8]>> From<&'a T> for Leaf<'a> { +impl<'a, H, T: AsRef<[u8]>> From<&'a T> for Leaf<'a, H> { fn from(v: &'a T) -> Self { Leaf::Value(v.as_ref()) } } -impl<'a> From for Leaf<'a> { - fn from(v: Hash) -> Self { - Leaf::Hash(v) - } -} - /// Verify Merkle Proof correctness versus given root hash. /// /// The proof is NOT expected to contain leaf hash as the first @@ -277,45 +233,47 @@ impl<'a> From for Leaf<'a> { /// /// The proof must not contain the root hash. pub fn verify_proof<'a, H, P, L>( - root: &'a Hash, + root: &'a H::Output, proof: P, number_of_leaves: usize, leaf_index: usize, leaf: L, ) -> bool where - H: Hasher, - P: IntoIterator, - L: Into>, + H: HashT, + H::Output: PartialEq + AsRef<[u8]>, + P: IntoIterator, + L: Into>, { if leaf_index >= number_of_leaves { return false } let leaf_hash = match leaf.into() { - Leaf::Value(content) => H::hash(content), + Leaf::Value(content) => ::hash(content), Leaf::Hash(hash) => hash, }; - let mut combined = [0_u8; 64]; + let hash_len = ::LENGTH; + let mut combined = vec![0_u8; hash_len * 2]; let mut position = leaf_index; let mut width = number_of_leaves; let computed = proof.into_iter().fold(leaf_hash, |a, b| { if position % 2 == 1 || position + 1 == width { - combined[0..32].copy_from_slice(&b); - combined[32..64].copy_from_slice(&a); + combined[..hash_len].copy_from_slice(&b.as_ref()); + combined[hash_len..].copy_from_slice(&a.as_ref()); } else { - combined[0..32].copy_from_slice(&a); - combined[32..64].copy_from_slice(&b); + combined[..hash_len].copy_from_slice(&a.as_ref()); + combined[hash_len..].copy_from_slice(&b.as_ref()); } - let hash = H::hash(&combined); + let hash = ::hash(&combined); #[cfg(feature = "debug")] log::debug!( "[verify_proof]: (a, b) {:?}, {:?} => {:?} ({:?}) hash", - array_bytes::bytes2hex("", &a), - array_bytes::bytes2hex("", &b), - array_bytes::bytes2hex("", &hash), - array_bytes::bytes2hex("", &combined) + array_bytes::bytes2hex("", &a.as_ref()), + array_bytes::bytes2hex("", &b.as_ref()), + array_bytes::bytes2hex("", &hash.as_ref()), + array_bytes::bytes2hex("", &combined.as_ref()) ); position /= 2; width = ((width - 1) / 2) + 1; @@ -332,20 +290,22 @@ where /// empty iterator) an `Err` with the inner nodes of upper layer is returned. fn merkelize_row( mut iter: I, - mut next: Vec, + mut next: Vec, visitor: &mut V, -) -> Result> +) -> Result> where - H: Hasher, - V: Visitor, - I: Iterator, + H: HashT, + H::Output: AsRef<[u8]>, + V: Visitor, + I: Iterator, { #[cfg(feature = "debug")] log::debug!("[merkelize_row]"); next.clear(); + let hash_len = ::LENGTH; let mut index = 0; - let mut combined = [0_u8; 64]; + let mut combined = vec![0_u8; hash_len * 2]; loop { let a = iter.next(); let b = iter.next(); @@ -354,17 +314,17 @@ where #[cfg(feature = "debug")] log::debug!( " {:?}\n {:?}", - a.as_ref().map(|s| array_bytes::bytes2hex("", s)), - b.as_ref().map(|s| array_bytes::bytes2hex("", s)) + a.as_ref().map(|s| array_bytes::bytes2hex("", s.as_ref())), + b.as_ref().map(|s| array_bytes::bytes2hex("", s.as_ref())) ); index += 2; match (a, b) { (Some(a), Some(b)) => { - combined[0..32].copy_from_slice(&a); - combined[32..64].copy_from_slice(&b); + combined[..hash_len].copy_from_slice(a.as_ref()); + combined[hash_len..].copy_from_slice(b.as_ref()); - next.push(H::hash(&combined)); + next.push(::hash(&combined)); }, // Odd number of items. Promote the item to the upper layer. (Some(a), None) if !next.is_empty() => { @@ -377,7 +337,7 @@ where #[cfg(feature = "debug")] log::debug!( "[merkelize_row] Next: {:?}", - next.iter().map(|s| array_bytes::bytes2hex("", s)).collect::>() + next.iter().map(|s| array_bytes::bytes2hex("", s.as_ref())).collect::>() ); return Err(next) }, @@ -389,7 +349,6 @@ sp_api::decl_runtime_apis! { /// API useful for BEEFY light clients. pub trait BeefyMmrApi where - H: From + Into, BeefyAuthoritySet: sp_api::Decode, { /// Return the currently active BEEFY authority set proof. @@ -403,6 +362,7 @@ sp_api::decl_runtime_apis! { #[cfg(test)] mod tests { use super::*; + use crate::sp_core::H256; #[test] fn should_generate_empty_root() { @@ -411,11 +371,11 @@ mod tests { let data: Vec<[u8; 1]> = Default::default(); // when - let out = merkle_root::(data); + let out = merkle_root::(data); // then assert_eq!( - array_bytes::bytes2hex("", &out), + array_bytes::bytes2hex("", out.as_ref()), "0000000000000000000000000000000000000000000000000000000000000000" ); } @@ -429,11 +389,11 @@ mod tests { )]; // when - let out = merkle_root::(data); + let out = merkle_root::(data); // then assert_eq!( - array_bytes::bytes2hex("", &out), + array_bytes::bytes2hex("", out.as_ref()), "aeb47a269393297f4b0a3c9c9cfd00c7a4195255274cf39d83dabc2fcc9ff3d7" ); } @@ -448,11 +408,11 @@ mod tests { ]; // when - let out = merkle_root::(data); + let out = merkle_root::(data); // then assert_eq!( - array_bytes::bytes2hex("", &out), + array_bytes::bytes2hex("", out.as_ref()), "697ea2a8fe5b03468548a7a413424a6292ab44a82a6f5cc594c3fa7dda7ce402" ); } @@ -461,7 +421,10 @@ mod tests { fn should_generate_root_complex() { let _ = env_logger::try_init(); let test = |root, data| { - assert_eq!(array_bytes::bytes2hex("", &merkle_root::(data)), root); + assert_eq!( + array_bytes::bytes2hex("", &merkle_root::(data).as_ref()), + root + ); }; test( @@ -521,18 +484,19 @@ mod tests { // then assert_eq!( - array_bytes::bytes2hex("", &proof0.root), - array_bytes::bytes2hex("", &proof1.root) + array_bytes::bytes2hex("", &proof0.root.as_ref()), + array_bytes::bytes2hex("", &proof1.root.as_ref()) ); assert_eq!( - array_bytes::bytes2hex("", &proof2.root), - array_bytes::bytes2hex("", &proof1.root) + array_bytes::bytes2hex("", &proof2.root.as_ref()), + array_bytes::bytes2hex("", &proof1.root.as_ref()) ); assert!(!verify_proof::( &array_bytes::hex2array_unchecked( "fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239" - ), + ) + .into(), proof0.proof, data.len(), proof0.leaf_index, @@ -540,7 +504,7 @@ mod tests { )); assert!(!verify_proof::( - &proof0.root, + &proof0.root.into(), vec![], data.len(), proof0.leaf_index, @@ -796,9 +760,10 @@ mod tests { "0xA4cDc98593CE52d01Fe5Ca47CB3dA5320e0D7592", "0xc26B34D375533fFc4c5276282Fa5D660F3d8cbcB", ]; - let root = array_bytes::hex2array_unchecked( + let root: H256 = array_bytes::hex2array_unchecked( "72b0acd7c302a84f1f6b6cefe0ba7194b7398afb440e1b44a9dbbe270394ca53", - ); + ) + .into(); let data = addresses .into_iter() @@ -808,7 +773,10 @@ mod tests { for l in 0..data.len() { // when let proof = merkle_proof::(data.clone(), l); - assert_eq!(array_bytes::bytes2hex("", &proof.root), array_bytes::bytes2hex("", &root)); + assert_eq!( + array_bytes::bytes2hex("", &proof.root.as_ref()), + array_bytes::bytes2hex("", &root.as_ref()) + ); assert_eq!(proof.leaf_index, l); assert_eq!(&proof.leaf, &data[l]); @@ -831,16 +799,20 @@ mod tests { proof: vec![ array_bytes::hex2array_unchecked( "340bcb1d49b2d82802ddbcf5b85043edb3427b65d09d7f758fbc76932ad2da2f" - ), + ) + .into(), array_bytes::hex2array_unchecked( "ba0580e5bd530bc93d61276df7969fb5b4ae8f1864b4a28c280249575198ff1f" - ), + ) + .into(), array_bytes::hex2array_unchecked( "d02609d2bbdb28aa25f58b85afec937d5a4c85d37925bce6d0cf802f9d76ba79" - ), + ) + .into(), array_bytes::hex2array_unchecked( "ae3f8991955ed884613b0a5f40295902eea0e0abe5858fc520b72959bc016d4e" - ), + ) + .into(), ], number_of_leaves: data.len(), leaf_index: data.len() - 1, diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 456d6e77aa8eb..5b82c89ce84b6 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -33,7 +33,7 @@ //! //! and thanks to versioning can be easily updated in the future. -use sp_runtime::traits::{Convert, Hash, Member}; +use sp_runtime::traits::{Convert, Member}; use sp_std::prelude::*; use beefy_primitives::{ @@ -142,10 +142,7 @@ pub mod pallet { StorageValue<_, BeefyNextAuthoritySet>, ValueQuery>; } -impl LeafDataProvider for Pallet -where - MerkleRootOf: From + Into, -{ +impl LeafDataProvider for Pallet { type LeafData = MmrLeaf< ::BlockNumber, ::Hash, @@ -163,19 +160,9 @@ where } } -impl beefy_merkle_tree::Hasher for Pallet -where - MerkleRootOf: Into, -{ - fn hash(data: &[u8]) -> beefy_merkle_tree::Hash { - ::Hashing::hash(data).into() - } -} - impl beefy_primitives::OnNewValidatorSet<::BeefyId> for Pallet where T: pallet::Config, - MerkleRootOf: From + Into, { /// Compute and cache BEEFY authority sets based on updated BEEFY validator sets. fn on_new_validator_set( @@ -190,10 +177,7 @@ where } } -impl Pallet -where - MerkleRootOf: From + Into, -{ +impl Pallet { /// Return the currently active BEEFY authority set proof. pub fn authority_set_proof() -> BeefyAuthoritySet> { Pallet::::beefy_authorities() @@ -220,7 +204,10 @@ where .map(T::BeefyAuthorityToMerkleLeaf::convert) .collect::>(); let len = beefy_addresses.len() as u32; - let root = beefy_merkle_tree::merkle_root::(beefy_addresses).into(); + let root = beefy_merkle_tree::merkle_root::<::Hashing, _>( + beefy_addresses, + ) + .into(); BeefyAuthoritySet { id, len, root } } } diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 602d0aa5fe1a6..0a64ad3fc9976 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -147,9 +147,10 @@ impl BeefyDataProvider> for DummyDataProvider { fn extra_data() -> Vec { let mut col = vec![(15, vec![1, 2, 3]), (5, vec![4, 5, 6])]; col.sort(); - beefy_merkle_tree::merkle_root::, _, _>( + beefy_merkle_tree::merkle_root::<::Hashing, _>( col.into_iter().map(|pair| pair.encode()), ) + .as_ref() .to_vec() } } From 005195011f303bf5e2e468dbf379dd42971bf6ae Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 4 Oct 2022 14:34:54 +0300 Subject: [PATCH 1232/1472] client/beefy: small code improvements (#12414) * client/beefy: remove bounds on type definitions * client/beefy: remove gossip protocol legacy name * client/beefy: simplify justification request response engine Signed-off-by: Adrian Catangiu --- client/beefy/src/communication/mod.rs | 5 --- .../outgoing_requests_engine.rs | 34 ++++++++----------- client/beefy/src/lib.rs | 16 ++------- 3 files changed, 17 insertions(+), 38 deletions(-) diff --git a/client/beefy/src/communication/mod.rs b/client/beefy/src/communication/mod.rs index 93646677c0ecd..91798d4ae0d33 100644 --- a/client/beefy/src/communication/mod.rs +++ b/client/beefy/src/communication/mod.rs @@ -33,9 +33,6 @@ pub(crate) mod beefy_protocol_name { /// BEEFY justifications protocol name suffix. const JUSTIFICATIONS_NAME: &str = "/beefy/justifications/1"; - /// Old names for the gossip protocol, used for backward compatibility. - pub(super) const LEGACY_NAMES: [&str; 1] = ["/paritytech/beefy/1"]; - /// Name of the votes gossip protocol used by BEEFY. /// /// Must be registered towards the networking in order for BEEFY voter to properly function. @@ -73,9 +70,7 @@ pub fn beefy_peers_set_config( ) -> sc_network_common::config::NonDefaultSetConfig { let mut cfg = sc_network_common::config::NonDefaultSetConfig::new(gossip_protocol_name, 1024 * 1024); - cfg.allow_non_reserved(25, 25); - cfg.add_fallback_names(beefy_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect()); cfg } diff --git a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs index e22958e19cd2e..c4d3c926190e6 100644 --- a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -20,10 +20,7 @@ use beefy_primitives::{crypto::AuthorityId, BeefyApi, ValidatorSet}; use codec::Encode; -use futures::{ - channel::{oneshot, oneshot::Canceled}, - stream::{self, StreamExt}, -}; +use futures::channel::{oneshot, oneshot::Canceled}; use log::{debug, error, warn}; use parking_lot::Mutex; use sc_network::{PeerId, ProtocolName}; @@ -50,8 +47,8 @@ type Response = Result, RequestFailure>; type ResponseReceiver = oneshot::Receiver; enum State { - Idle(stream::Pending>), - AwaitingResponse(PeerId, NumberFor, stream::Once), + Idle, + AwaitingResponse(PeerId, NumberFor, ResponseReceiver), } pub struct OnDemandJustificationsEngine { @@ -83,7 +80,7 @@ where protocol_name, live_peers, peers_cache: VecDeque::new(), - state: State::Idle(stream::pending()), + state: State::Idle, } } @@ -118,15 +115,14 @@ where IfDisconnected::ImmediateError, ); - self.state = State::AwaitingResponse(peer, block, stream::once(rx)); + self.state = State::AwaitingResponse(peer, block, rx); } /// If no other request is in progress, start new justification request for `block`. pub fn request(&mut self, block: NumberFor) { // ignore new requests while there's already one pending - match &self.state { - State::AwaitingResponse(_, _, _) => return, - State::Idle(_) => (), + if matches!(self.state, State::AwaitingResponse(_, _, _)) { + return } self.reset_peers_cache_for_block(block); @@ -148,7 +144,7 @@ where "🥩 cancel pending request for justification #{:?}", number ); - self.state = State::Idle(stream::pending()); + self.state = State::Idle; }, _ => (), } @@ -194,19 +190,19 @@ where pub async fn next(&mut self) -> Option> { let (peer, block, resp) = match &mut self.state { - State::Idle(pending) => { - let _ = pending.next().await; - // This never happens since 'stream::pending' never generates any items. + State::Idle => { + futures::pending!(); + // Doesn't happen as 'futures::pending!()' is an 'await' barrier that never passes. return None }, State::AwaitingResponse(peer, block, receiver) => { - let resp = receiver.next().await?; + let resp = receiver.await; (*peer, *block, resp) }, }; - // We received the awaited response. Our 'stream::once()' receiver will never generate any - // other response, meaning we're done with current state. Move the engine to `State::Idle`. - self.state = State::Idle(stream::pending()); + // We received the awaited response. Our 'receiver' will never generate any other response, + // meaning we're done with current state. Move the engine to `State::Idle`. + self.state = State::Idle; let block_id = BlockId::number(block); let validator_set = self diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 7407f101e99a5..760fc753b18a3 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -153,11 +153,7 @@ where } /// BEEFY gadget network parameters. -pub struct BeefyNetworkParams -where - B: Block, - N: GossipNetwork + NetworkRequest + SyncOracle + Send + Sync + 'static, -{ +pub struct BeefyNetworkParams { /// Network implementing gossip, requests and sync-oracle. pub network: Arc, /// Chain specific BEEFY gossip protocol name. See @@ -171,15 +167,7 @@ where } /// BEEFY gadget initialization parameters. -pub struct BeefyParams -where - B: Block, - BE: Backend, - C: Client, - R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi, - N: GossipNetwork + NetworkRequest + SyncOracle + Send + Sync + 'static, -{ +pub struct BeefyParams { /// BEEFY client pub client: Arc, /// Client Backend From 07e5ec5eb8a9c470bf7dc9afbdb3ac0579be4f4b Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 4 Oct 2022 14:26:14 +0200 Subject: [PATCH 1233/1472] [Fix] Rename VoterBagsList -> VoterList to match pdot (#12416) --- bin/node/runtime/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f0c68b5b225cd..c2d29731ea2e6 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -569,7 +569,7 @@ impl pallet_staking::Config for Runtime { type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::UnboundedExecution; - type VoterList = VoterBagsList; + type VoterList = VoterList; // This a placeholder, to be introduced in the next PR as an instance of bags-list type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; @@ -1651,7 +1651,7 @@ construct_runtime!( Gilt: pallet_gilt, Uniques: pallet_uniques, TransactionStorage: pallet_transaction_storage, - VoterBagsList: pallet_bags_list::, + VoterList: pallet_bags_list::, StateTrieMigration: pallet_state_trie_migration, ChildBounties: pallet_child_bounties, Referenda: pallet_referenda, @@ -1739,7 +1739,7 @@ mod benches { [pallet_alliance, Alliance] [pallet_assets, Assets] [pallet_babe, Babe] - [pallet_bags_list, VoterBagsList] + [pallet_bags_list, VoterList] [pallet_balances, Balances] [pallet_bounties, Bounties] [pallet_child_bounties, ChildBounties] From d11dd02dda6a00800a13cd59a0c2f07ac75e082d Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Tue, 4 Oct 2022 15:15:57 +0200 Subject: [PATCH 1234/1472] Use saturating add for alliance::disband witness data (#12418) --- frame/alliance/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 24111b44ced9e..fca17e69c7652 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -706,7 +706,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::disband( witness.voting_members, witness.ally_members, - witness.voting_members + witness.ally_members, + witness.voting_members.saturating_add(witness.ally_members), ))] pub fn disband( origin: OriginFor, From 91d072df4273bbc04f8152099b23a66a0c1d531b Mon Sep 17 00:00:00 2001 From: Chevdor Date: Tue, 4 Oct 2022 21:30:45 +0200 Subject: [PATCH 1235/1472] Bump prost to 0.11+ (#12419) --- Cargo.lock | 16 ++++++++-------- client/authority-discovery/Cargo.toml | 4 ++-- client/network/Cargo.toml | 2 +- client/network/common/Cargo.toml | 2 +- client/network/light/Cargo.toml | 4 ++-- client/network/sync/Cargo.toml | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f0a2df0f101b..a35dbba7d089e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7830,8 +7830,8 @@ dependencies = [ "libp2p", "log", "parity-scale-codec", - "prost 0.10.3", - "prost-build 0.10.4", + "prost 0.11.0", + "prost-build 0.11.1", "quickcheck", "rand 0.7.3", "sc-client-api", @@ -8486,7 +8486,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "pin-project", - "prost 0.10.3", + "prost 0.11.0", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8553,7 +8553,7 @@ dependencies = [ "libp2p", "linked_hash_set", "parity-scale-codec", - "prost-build 0.10.4", + "prost-build 0.11.1", "sc-consensus", "sc-peerset", "serde", @@ -8595,8 +8595,8 @@ dependencies = [ "libp2p", "log", "parity-scale-codec", - "prost 0.10.3", - "prost-build 0.10.4", + "prost 0.11.0", + "prost-build 0.11.1", "sc-client-api", "sc-network-common", "sc-peerset", @@ -8617,8 +8617,8 @@ dependencies = [ "log", "lru", "parity-scale-codec", - "prost 0.10.3", - "prost-build 0.10.4", + "prost 0.11.0", + "prost-build 0.11.1", "quickcheck", "sc-block-builder", "sc-client-api", diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index d9e9df4f2a97c..37377cdc6dde3 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } @@ -23,7 +23,7 @@ futures-timer = "3.0.1" ip_network = "0.4.1" libp2p = { version = "0.46.1", default-features = false, features = ["kad"] } log = "0.4.17" -prost = "0.10" +prost = "0.11" rand = "0.7.2" thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index e96749df40aa2..8e3d68851c423 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -33,7 +33,7 @@ log = "0.4.17" lru = "0.7.5" parking_lot = "0.12.1" pin-project = "1.0.10" -prost = "0.10" +prost = "0.11" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 1ee7b15538366..0e9801ec79e63 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dependencies] async-trait = "0.1.57" diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index c2a77c3b577ba..a1a5dcf85eb5d 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dependencies] array-bytes = "4.1" @@ -24,7 +24,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ futures = "0.3.21" libp2p = "0.46.1" log = "0.4.16" -prost = "0.10" +prost = "0.11" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-network-common = { version = "0.10.0-dev", path = "../common" } diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 269214aeff3f7..24d418f7233d7 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dependencies] array-bytes = "4.1" @@ -25,7 +25,7 @@ futures = "0.3.21" libp2p = "0.46.1" log = "0.4.17" lru = "0.7.5" -prost = "0.10" +prost = "0.11" smallvec = "1.8.0" thiserror = "1.0" fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } From 241b0d0455453499763d0db0b4ea4188012b372f Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Wed, 5 Oct 2022 00:16:07 +0200 Subject: [PATCH 1236/1472] Improved election pallet testing (#12327) * Improved election pallet testing * fmt * remove comment * more checks * fixes in logic * roll_to_signed * switch to roll_to_signed * Update frame/election-provider-multi-phase/src/mock.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * remove useless checks * remove warning * add checks to signed.rs * add some checks to unsigned.rs * fmt * use roll_to_signed and roll_to_unsigned * remove nonsense * remove even more nonsense * fix * fix * remove useless checks Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: parity-processbot <> --- .../election-provider-multi-phase/src/lib.rs | 161 +++++++++++++++--- .../election-provider-multi-phase/src/mock.rs | 11 ++ .../src/signed.rs | 130 +++++++++++--- .../src/unsigned.rs | 75 +++++--- 4 files changed, 305 insertions(+), 72 deletions(-) diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index fb17bd25ea541..3dc6161bb202a 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1842,9 +1842,9 @@ mod tests { use super::*; use crate::{ mock::{ - multi_phase_events, raw_solution, roll_to, AccountId, ExtBuilder, MockWeightInfo, - MockedWeightInfo, MultiPhase, Runtime, RuntimeOrigin, SignedMaxSubmissions, System, - TargetIndex, Targets, + multi_phase_events, raw_solution, roll_to, roll_to_signed, roll_to_unsigned, AccountId, + ExtBuilder, MockWeightInfo, MockedWeightInfo, MultiPhase, Runtime, RuntimeOrigin, + SignedMaxSubmissions, System, TargetIndex, Targets, }, Phase, }; @@ -1868,7 +1868,7 @@ mod tests { assert!(MultiPhase::snapshot().is_none()); assert_eq!(MultiPhase::round(), 1); - roll_to(15); + roll_to_signed(); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); assert!(MultiPhase::snapshot().is_some()); @@ -1879,7 +1879,7 @@ mod tests { assert!(MultiPhase::snapshot().is_some()); assert_eq!(MultiPhase::round(), 1); - roll_to(25); + roll_to_unsigned(); assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); assert_eq!( multi_phase_events(), @@ -1912,11 +1912,29 @@ mod tests { roll_to(44); assert!(MultiPhase::current_phase().is_off()); - roll_to(45); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); roll_to(55); assert!(MultiPhase::current_phase().is_unsigned_open_at(55)); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + }, + Event::SignedPhaseStarted { round: 2 }, + Event::UnsignedPhaseStarted { round: 2 } + ] + ); }) } @@ -1940,6 +1958,21 @@ mod tests { assert!(MultiPhase::current_phase().is_off()); assert!(MultiPhase::snapshot().is_none()); + + assert_eq!( + multi_phase_events(), + vec![ + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + } + ] + ); }); } @@ -1952,7 +1985,7 @@ mod tests { roll_to(19); assert!(MultiPhase::current_phase().is_off()); - roll_to(20); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); assert!(MultiPhase::snapshot().is_some()); @@ -1963,6 +1996,21 @@ mod tests { assert!(MultiPhase::current_phase().is_off()); assert!(MultiPhase::snapshot().is_none()); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + } + ] + ) }); } @@ -1985,6 +2033,14 @@ mod tests { assert_ok!(MultiPhase::elect()); assert!(MultiPhase::current_phase().is_off()); + + assert_eq!( + multi_phase_events(), + vec![Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { minimal_stake: 0, sum_stake: 0, sum_stake_squared: 0 } + }] + ); }); } @@ -1993,16 +2049,13 @@ mod tests { // An early termination in the signed phase, with no queued solution. ExtBuilder::default().build_and_execute(|| { // Signed phase started at block 15 and will end at 25. - roll_to(14); - assert_eq!(MultiPhase::current_phase(), Phase::Off); - roll_to(15); + roll_to_signed(); assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!(MultiPhase::round(), 1); // An unexpected call to elect. - roll_to(20); assert_ok!(MultiPhase::elect()); // We surely can't have any feasible solutions. This will cause an on-chain election. @@ -2031,10 +2084,8 @@ mod tests { // an early termination in the signed phase, with no queued solution. ExtBuilder::default().build_and_execute(|| { // signed phase started at block 15 and will end at 25. - roll_to(14); - assert_eq!(MultiPhase::current_phase(), Phase::Off); - roll_to(15); + roll_to_signed(); assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!(MultiPhase::round(), 1); @@ -2052,7 +2103,6 @@ mod tests { } // an unexpected call to elect. - roll_to(20); assert_ok!(MultiPhase::elect()); // all storage items must be cleared. @@ -2062,16 +2112,38 @@ mod tests { assert!(MultiPhase::desired_targets().is_none()); assert!(MultiPhase::queued_solution().is_none()); assert!(MultiPhase::signed_submissions().is_empty()); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Slashed { account: 99, value: 5 }, + Event::Slashed { account: 99, value: 5 }, + Event::Slashed { account: 99, value: 5 }, + Event::Slashed { account: 99, value: 5 }, + Event::Slashed { account: 99, value: 5 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + } + ] + ); }) } #[test] fn check_events_with_compute_signed() { ExtBuilder::default().build_and_execute(|| { - roll_to(14); - assert_eq!(MultiPhase::current_phase(), Phase::Off); - - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); @@ -2106,7 +2178,7 @@ mod tests { #[test] fn check_events_with_compute_unsigned() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // ensure we have snapshots in place. @@ -2125,7 +2197,6 @@ mod tests { )); assert!(MultiPhase::queued_solution().is_some()); - roll_to(30); assert_ok!(MultiPhase::elect()); assert_eq!( @@ -2153,7 +2224,7 @@ mod tests { #[test] fn fallback_strategy_works() { ExtBuilder::default().onchain_fallback(true).build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); // Zilch solutions thus far, but we get a result. @@ -2166,11 +2237,27 @@ mod tests { (30, Support { total: 40, voters: vec![(2, 5), (4, 5), (30, 30)] }), (40, Support { total: 60, voters: vec![(2, 5), (3, 10), (4, 5), (40, 40)] }) ] - ) + ); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + } + ] + ); }); ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); // Zilch solutions thus far. @@ -2178,13 +2265,22 @@ mod tests { assert_eq!(MultiPhase::elect().unwrap_err(), ElectionError::Fallback("NoFallback.")); // phase is now emergency. assert_eq!(MultiPhase::current_phase(), Phase::Emergency); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFailed + ] + ); }) } #[test] fn governance_fallback_works() { ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); // Zilch solutions thus far. @@ -2243,9 +2339,16 @@ mod tests { assert_eq!(MultiPhase::current_phase(), Phase::Off); // On-chain backup works though. - roll_to(29); let supports = MultiPhase::elect().unwrap(); assert!(supports.len() > 0); + + assert_eq!( + multi_phase_events(), + vec![Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { minimal_stake: 0, sum_stake: 0, sum_stake_squared: 0 } + }] + ); }); } @@ -2269,6 +2372,8 @@ mod tests { let err = MultiPhase::elect().unwrap_err(); assert_eq!(err, ElectionError::Fallback("NoFallback.")); assert_eq!(MultiPhase::current_phase(), Phase::Emergency); + + assert_eq!(multi_phase_events(), vec![Event::ElectionFailed]); }); } @@ -2282,7 +2387,7 @@ mod tests { crate::mock::MaxElectingVoters::set(2); // Signed phase opens just fine. - roll_to(15); + roll_to_signed(); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!( @@ -2295,7 +2400,7 @@ mod tests { #[test] fn untrusted_score_verification_is_respected() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert_eq!(MultiPhase::current_phase(), Phase::Signed); // set the solution balancing to get the desired score. diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index d3082be0cf750..2615d863c91e0 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -99,6 +99,17 @@ pub fn roll_to(n: BlockNumber) { } } +pub fn roll_to_unsigned() { + while !matches!(MultiPhase::current_phase(), Phase::Unsigned(_)) { + roll_to(System::block_number() + 1); + } +} +pub fn roll_to_signed() { + while !matches!(MultiPhase::current_phase(), Phase::Signed) { + roll_to(System::block_number() + 1); + } +} + pub fn roll_to_with_ocw(n: BlockNumber) { let now = System::block_number(); for i in now + 1..=n { diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 2e01d99be0a42..175c92757f35e 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -528,10 +528,11 @@ mod tests { use super::*; use crate::{ mock::{ - balances, raw_solution, roll_to, Balances, ExtBuilder, MockedWeightInfo, MultiPhase, - Runtime, RuntimeOrigin, SignedMaxRefunds, SignedMaxSubmissions, SignedMaxWeight, + balances, multi_phase_events, raw_solution, roll_to, roll_to_signed, Balances, + ExtBuilder, MockedWeightInfo, MultiPhase, Runtime, RuntimeOrigin, SignedMaxRefunds, + SignedMaxSubmissions, SignedMaxWeight, }, - Error, Perbill, Phase, + Error, Event, Perbill, Phase, }; use frame_support::{assert_noop, assert_ok, assert_storage_noop}; @@ -555,7 +556,7 @@ mod tests { #[test] fn should_pay_deposit() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); @@ -565,13 +566,21 @@ mod tests { assert_eq!(balances(&99), (95, 5)); assert_eq!(MultiPhase::signed_submissions().iter().next().unwrap().deposit, 5); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false } + ] + ); }) } #[test] fn good_solution_is_rewarded() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); @@ -582,13 +591,22 @@ mod tests { assert!(MultiPhase::finalize_signed_phase()); assert_eq!(balances(&99), (100 + 7 + 8, 0)); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Rewarded { account: 99, value: 7 } + ] + ); }) } #[test] fn bad_solution_is_slashed() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let mut solution = raw_solution(); @@ -604,13 +622,22 @@ mod tests { assert!(!MultiPhase::finalize_signed_phase()); // and the bond is gone. assert_eq!(balances(&99), (95, 0)); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Slashed { account: 99, value: 5 } + ] + ); }) } #[test] fn suppressed_solution_gets_bond_back() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let mut solution = raw_solution(); @@ -633,13 +660,22 @@ mod tests { assert_eq!(balances(&99), (100 + 7 + 8, 0)); // 999 gets everything back, including the call fee. assert_eq!(balances(&999), (100 + 8, 0)); + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Rewarded { account: 99, value: 7 } + ] + ); }) } #[test] fn cannot_submit_worse_with_full_queue() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for s in 0..SignedMaxSubmissions::get() { @@ -667,7 +703,7 @@ mod tests { #[test] fn call_fee_refund_is_limited_by_signed_max_refunds() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); assert_eq!(SignedMaxRefunds::get(), 1); assert!(SignedMaxSubmissions::get() > 2); @@ -683,7 +719,7 @@ mod tests { assert_eq!(balances(&account), (95, 5)); } - assert!(MultiPhase::finalize_signed_phase()); + assert_ok!(MultiPhase::do_elect()); for s in 0..SignedMaxSubmissions::get() { let account = 99 + s as u64; @@ -699,6 +735,26 @@ mod tests { assert_eq!(balances(&account), (100, 0)); } } + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Rewarded { account: 99, value: 7 }, + Event::ElectionFinalized { + compute: ElectionCompute::Signed, + score: ElectionScore { + minimal_stake: 40, + sum_stake: 100, + sum_stake_squared: 5200 + } + } + ] + ); }); } @@ -708,7 +764,7 @@ mod tests { .signed_max_submission(1) .better_signed_threshold(Perbill::from_percent(20)) .build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let mut solution = RawSolution { @@ -747,13 +803,27 @@ mod tests { }; assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + prev_ejected: true + } + ] + ); }) } #[test] fn weakest_is_removed_if_better_provided() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for s in 0..SignedMaxSubmissions::get() { @@ -800,7 +870,7 @@ mod tests { #[test] fn replace_weakest_works() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for s in 1..SignedMaxSubmissions::get() { @@ -847,7 +917,7 @@ mod tests { #[test] fn early_ejected_solution_gets_bond_back() { ExtBuilder::default().signed_deposit(2, 0, 0).build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for s in 0..SignedMaxSubmissions::get() { @@ -878,7 +948,7 @@ mod tests { #[test] fn equally_good_solution_is_not_accepted() { ExtBuilder::default().signed_max_submission(3).build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for i in 0..SignedMaxSubmissions::get() { @@ -915,7 +985,7 @@ mod tests { // - bad_solution_is_slashed // - suppressed_solution_gets_bond_back ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); assert_eq!(balances(&99), (100, 0)); @@ -951,6 +1021,17 @@ mod tests { assert_eq!(balances(&999), (95, 0)); // 9999 gets everything back, including the call fee. assert_eq!(balances(&9999), (100 + 8, 0)); + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Slashed { account: 999, value: 5 }, + Event::Rewarded { account: 99, value: 7 } + ] + ); }) } @@ -960,7 +1041,7 @@ mod tests { .signed_weight(Weight::from_ref_time(40).set_proof_size(u64::MAX)) .mock_weight_info(MockedWeightInfo::Basic) .build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let (raw, witness) = MultiPhase::mine_solution().unwrap(); @@ -994,7 +1075,7 @@ mod tests { #[test] fn insufficient_deposit_does_not_store_submission() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); @@ -1014,7 +1095,7 @@ mod tests { #[test] fn insufficient_deposit_with_full_queue_works_properly() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for s in 0..SignedMaxSubmissions::get() { @@ -1060,7 +1141,7 @@ mod tests { #[test] fn finalize_signed_phase_is_idempotent_given_submissions() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); @@ -1073,6 +1154,15 @@ mod tests { // calling it again doesn't change anything assert_storage_noop!(MultiPhase::finalize_signed_phase()); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Rewarded { account: 99, value: 7 } + ] + ); }) } } diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 025ff832bb08a..7340605dfe621 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -1050,11 +1050,12 @@ mod tests { use super::*; use crate::{ mock::{ - roll_to, roll_to_with_ocw, trim_helpers, witness, BlockNumber, ExtBuilder, Extrinsic, - MinerMaxWeight, MultiPhase, Runtime, RuntimeCall, RuntimeOrigin, System, - TestNposSolution, TrimHelpers, UnsignedPhase, + multi_phase_events, roll_to, roll_to_signed, roll_to_unsigned, roll_to_with_ocw, + trim_helpers, witness, BlockNumber, ExtBuilder, Extrinsic, MinerMaxWeight, MultiPhase, + Runtime, RuntimeCall, RuntimeOrigin, System, TestNposSolution, TrimHelpers, + UnsignedPhase, }, - CurrentPhase, InvalidTransaction, Phase, QueuedSolution, TransactionSource, + CurrentPhase, Event, InvalidTransaction, Phase, QueuedSolution, TransactionSource, TransactionValidityError, }; use codec::Decode; @@ -1100,7 +1101,7 @@ mod tests { )); // signed - roll_to(15); + roll_to_signed(); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert!(matches!( ::validate_unsigned( @@ -1116,7 +1117,7 @@ mod tests { )); // unsigned - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); assert!(::validate_unsigned( @@ -1147,7 +1148,7 @@ mod tests { #[test] fn validate_unsigned_retracts_low_score() { ExtBuilder::default().desired_targets(0).build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); let solution = RawSolution:: { @@ -1193,7 +1194,7 @@ mod tests { #[test] fn validate_unsigned_retracts_incorrect_winner_count() { ExtBuilder::default().desired_targets(1).build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); let raw = RawSolution:: { @@ -1222,7 +1223,7 @@ mod tests { .miner_tx_priority(20) .desired_targets(0) .build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); let solution = RawSolution:: { @@ -1253,7 +1254,7 @@ mod tests { Some(\"PreDispatchWrongWinnerCount\") })")] fn unfeasible_solution_panics() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // This is in itself an invalid BS solution. @@ -1275,7 +1276,7 @@ mod tests { deprive validator from their authoring reward.")] fn wrong_witness_panics() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // This solution is unfeasible as well, but we won't even get there. @@ -1299,7 +1300,7 @@ mod tests { #[test] fn miner_works() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // ensure we have snapshots in place. @@ -1317,6 +1318,17 @@ mod tests { witness )); assert!(MultiPhase::queued_solution().is_some()); + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Unsigned, + prev_ejected: false + } + ] + ); }) } @@ -1326,7 +1338,7 @@ mod tests { .miner_weight(Weight::from_ref_time(100).set_proof_size(u64::MAX)) .mock_weight_info(crate::mock::MockedWeightInfo::Basic) .build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); let (raw, witness) = MultiPhase::mine_solution().unwrap(); @@ -1360,7 +1372,7 @@ mod tests { fn miner_will_not_submit_if_not_enough_winners() { let (mut ext, _) = ExtBuilder::default().desired_targets(8).build_offchainify(0); ext.execute_with(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // Force the number of winners to be bigger to fail @@ -1386,7 +1398,7 @@ mod tests { .add_voter(8, 5, bounded_vec![10]) .better_unsigned_threshold(Perbill::from_percent(50)) .build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); assert_eq!(MultiPhase::desired_targets().unwrap(), 1); @@ -1488,7 +1500,7 @@ mod tests { ext.execute_with(|| { let offchain_repeat = ::OffchainRepeat::get(); - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // first execution -- okay. @@ -1529,7 +1541,7 @@ mod tests { let guard = StorageValueRef::persistent(&OFFCHAIN_LOCK); let last_block = StorageValueRef::persistent(OFFCHAIN_LAST_BLOCK); - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // initially, the lock is not set. @@ -1550,7 +1562,7 @@ mod tests { // ensure that if the guard is in hold, a new execution is not allowed. let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); ext.execute_with(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // artificially set the value, as if another thread is mid-way. @@ -1578,7 +1590,7 @@ mod tests { fn ocw_only_runs_when_unsigned_open_now() { let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); ext.execute_with(|| { - roll_to(25); + roll_to_unsigned(); assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); // we must clear the offchain storage to ensure the offchain execution check doesn't get @@ -1658,6 +1670,21 @@ mod tests { // the submitted solution changes because the cache was cleared. assert_eq!(tx_cache_1, tx_cache_3); + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + } + ] + ); }) } @@ -1797,7 +1824,7 @@ mod tests { #[test] fn trim_assignments_length_does_not_modify_when_short_enough() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); // given let TrimHelpers { mut assignments, encoded_size_of, .. } = trim_helpers(); @@ -1822,7 +1849,7 @@ mod tests { #[test] fn trim_assignments_length_modifies_when_too_long() { ExtBuilder::default().build().execute_with(|| { - roll_to(25); + roll_to_unsigned(); // given let TrimHelpers { mut assignments, encoded_size_of, .. } = trim_helpers(); @@ -1848,7 +1875,7 @@ mod tests { #[test] fn trim_assignments_length_trims_lowest_stake() { ExtBuilder::default().build().execute_with(|| { - roll_to(25); + roll_to_unsigned(); // given let TrimHelpers { voters, mut assignments, encoded_size_of, voter_index } = @@ -1911,7 +1938,7 @@ mod tests { // or when we trim it to zero. ExtBuilder::default().build_and_execute(|| { // we need snapshot for `trim_helpers` to work. - roll_to(25); + roll_to_unsigned(); let TrimHelpers { mut assignments, encoded_size_of, .. } = trim_helpers(); assert!(assignments.len() > 0); @@ -1933,7 +1960,7 @@ mod tests { #[test] fn mine_solution_solutions_always_within_acceptable_length() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); // how long would the default solution be? let solution = MultiPhase::mine_solution().unwrap(); From 7a8de4995715cc6cd11a79eb262bf41e5b190943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 5 Oct 2022 13:10:20 +0200 Subject: [PATCH 1237/1472] Adapt `pallet-contracts` to WeightV2 (#12421) * Replace contract access weight by proper PoV component * Return the whole weight struct from dry-runs * Fixup `seal_call` and `seal_instantiate` * Fix duplicate extrinsics * Remove ContractAccessWeight from runtime * Fix doc link * Remove leftover debugging output --- Cargo.lock | 1 + bin/node/runtime/src/lib.rs | 1 - frame/contracts/primitives/Cargo.toml | 1 + frame/contracts/primitives/src/lib.rs | 11 +- frame/contracts/src/gas.rs | 61 +++++---- frame/contracts/src/lib.rs | 181 +++++-------------------- frame/contracts/src/tests.rs | 36 ++--- frame/contracts/src/wasm/code_cache.rs | 15 +- 8 files changed, 96 insertions(+), 211 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a35dbba7d089e..309742e5bf17e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5531,6 +5531,7 @@ dependencies = [ "parity-scale-codec", "sp-runtime", "sp-std", + "sp-weights", ] [[package]] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index c2d29731ea2e6..4898312f9608f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1175,7 +1175,6 @@ impl pallet_contracts::Config for Runtime { type DeletionWeightLimit = DeletionWeightLimit; type Schedule = Schedule; type AddressGenerator = pallet_contracts::DefaultAddressGenerator; - type ContractAccessWeight = pallet_contracts::DefaultContractAccessWeight; type MaxCodeLen = ConstU32<{ 128 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; } diff --git a/frame/contracts/primitives/Cargo.toml b/frame/contracts/primitives/Cargo.toml index 64e332007350b..c8b7c4a2f7c37 100644 --- a/frame/contracts/primitives/Cargo.toml +++ b/frame/contracts/primitives/Cargo.toml @@ -19,6 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = # Substrate Dependencies (This crate should not rely on frame) sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-weights = { version = "4.0.0", default-features = false, path = "../../../primitives/weights" } [features] default = ["std"] diff --git a/frame/contracts/primitives/src/lib.rs b/frame/contracts/primitives/src/lib.rs index 5daf875ac2651..4faea9eb3ee75 100644 --- a/frame/contracts/primitives/src/lib.rs +++ b/frame/contracts/primitives/src/lib.rs @@ -26,17 +26,18 @@ use sp_runtime::{ DispatchError, RuntimeDebug, }; use sp_std::prelude::*; +use sp_weights::Weight; /// Result type of a `bare_call` or `bare_instantiate` call. /// /// It contains the execution result together with some auxiliary information. #[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] pub struct ContractResult { - /// How much gas was consumed during execution. - pub gas_consumed: u64, - /// How much gas is required as gas limit in order to execute this call. + /// How much weight was consumed during execution. + pub gas_consumed: Weight, + /// How much weight is required as gas limit in order to execute this call. /// - /// This value should be used to determine the gas limit for on-chain execution. + /// This value should be used to determine the weight limit for on-chain execution. /// /// # Note /// @@ -44,7 +45,7 @@ pub struct ContractResult { /// is used. Currently, only `seal_call_runtime` makes use of pre charging. /// Additionally, any `seal_call` or `seal_instantiate` makes use of pre-charging /// when a non-zero `gas_limit` argument is supplied. - pub gas_required: u64, + pub gas_required: Weight, /// How much balance was deposited and reserved during execution in order to pay for storage. /// /// The storage deposit is never actually charged from the caller in case of [`Self::result`] diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index 215b4d42daa06..d0076652dd6d4 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -107,32 +107,45 @@ where /// /// Passing `0` as amount is interpreted as "all remaining gas". pub fn nested(&mut self, amount: Weight) -> Result { - let amount = if amount == Weight::zero() { self.gas_left } else { amount }; - // NOTE that it is ok to allocate all available gas since it still ensured // by `charge` that it doesn't reach zero. - if self.gas_left.any_lt(amount) { - Err(>::OutOfGas.into()) - } else { - self.gas_left -= amount; - Ok(GasMeter::new(amount)) - } + let amount = Weight::from_components( + if amount.ref_time().is_zero() { + self.gas_left().ref_time() + } else { + amount.ref_time() + }, + if amount.proof_size().is_zero() { + self.gas_left().proof_size() + } else { + amount.proof_size() + }, + ); + self.gas_left = self.gas_left.checked_sub(&amount).ok_or_else(|| >::OutOfGas)?; + Ok(GasMeter::new(amount)) } /// Absorb the remaining gas of a nested meter after we are done using it. pub fn absorb_nested(&mut self, nested: Self) { - if self.gas_left == Weight::zero() { + if self.gas_left.ref_time().is_zero() { // All of the remaining gas was inherited by the nested gas meter. When absorbing // we can therefore safely inherit the lowest gas that the nested gas meter experienced // as long as it is lower than the lowest gas that was experienced by the parent. // We cannot call `self.gas_left_lowest()` here because in the state that this // code is run the parent gas meter has `0` gas left. - self.gas_left_lowest = nested.gas_left_lowest().min(self.gas_left_lowest); + *self.gas_left_lowest.ref_time_mut() = + nested.gas_left_lowest().ref_time().min(self.gas_left_lowest.ref_time()); } else { // The nested gas meter was created with a fixed amount that did not consume all of the // parents (self) gas. The lowest gas that self will experience is when the nested // gas was pre charged with the fixed amount. - self.gas_left_lowest = self.gas_left_lowest(); + *self.gas_left_lowest.ref_time_mut() = self.gas_left_lowest().ref_time(); + } + if self.gas_left.proof_size().is_zero() { + *self.gas_left_lowest.proof_size_mut() = + nested.gas_left_lowest().proof_size().min(self.gas_left_lowest.proof_size()); + } else { + *self.gas_left_lowest.proof_size_mut() = self.gas_left_lowest().proof_size(); } self.gas_left += nested.gas_left; } @@ -155,17 +168,11 @@ where ErasedToken { description: format!("{:?}", token), token: Box::new(token) }; self.tokens.push(erased_tok); } - let amount = token.weight(); - let new_value = self.gas_left.checked_sub(&amount); - - // We always consume the gas even if there is not enough gas. - self.gas_left = new_value.unwrap_or_else(Zero::zero); - - match new_value { - Some(_) => Ok(ChargedAmount(amount)), - None => Err(Error::::OutOfGas.into()), - } + // It is OK to not charge anything on failure because we always charge _before_ we perform + // any action + self.gas_left = self.gas_left.checked_sub(&amount).ok_or_else(|| Error::::OutOfGas)?; + Ok(ChargedAmount(amount)) } /// Adjust a previously charged amount down to its actual amount. @@ -298,20 +305,16 @@ mod tests { assert!(gas_meter.charge(SimpleToken(1)).is_err()); } - // Make sure that if the gas meter is charged by exceeding amount then not only an error - // returned for that charge, but also for all consequent charges. - // - // This is not strictly necessary, because the execution should be interrupted immediately - // if the gas meter runs out of gas. However, this is just a nice property to have. + // Make sure that the gas meter does not charge in case of overcharger #[test] - fn overcharge_is_unrecoverable() { + fn overcharge_does_not_charge() { let mut gas_meter = GasMeter::::new(Weight::from_ref_time(200)); // The first charge is should lead to OOG. assert!(gas_meter.charge(SimpleToken(300)).is_err()); - // The gas meter is emptied at this moment, so this should also fail. - assert!(gas_meter.charge(SimpleToken(1)).is_err()); + // The gas meter should still contain the full 200. + assert!(gas_meter.charge(SimpleToken(200)).is_ok()); } // Charging the exact amount that the user paid for should be diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 3aeb8742705c2..0c90c3ff433b4 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -107,7 +107,7 @@ use crate::{ }; use codec::{Encode, HasCompact}; use frame_support::{ - dispatch::{DispatchClass, Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, + dispatch::{Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, ensure, traits::{ tokens::fungible::Inspect, ConstU32, Contains, Currency, Get, Randomness, @@ -116,7 +116,7 @@ use frame_support::{ weights::{OldWeight, Weight}, BoundedVec, WeakBoundedVec, }; -use frame_system::{limits::BlockWeights, Pallet as System}; +use frame_system::Pallet as System; use pallet_contracts_primitives::{ Code, CodeUploadResult, CodeUploadReturnValue, ContractAccessError, ContractExecResult, ContractInstantiateResult, ExecReturnValue, GetStorageResult, InstantiateReturnValue, @@ -199,29 +199,6 @@ where } } -/// A conservative implementation to be used for [`pallet::Config::ContractAccessWeight`]. -/// -/// This derives the weight from the [`BlockWeights`] passed as `B` and the `maxPovSize` passed -/// as `P`. The default value for `P` is the `maxPovSize` used by Polkadot and Kusama. -/// -/// It simply charges from the weight meter pro rata: If loading the contract code would consume -/// 50% of the max storage proof then this charges 50% of the max block weight. -pub struct DefaultContractAccessWeight, const P: u32 = 5_242_880>( - PhantomData, -); - -impl, const P: u32> Get for DefaultContractAccessWeight { - fn get() -> Weight { - let block_weights = B::get(); - block_weights - .per_class - .get(DispatchClass::Normal) - .max_total - .unwrap_or(block_weights.max_block) / - u64::from(P) - } -} - #[frame_support::pallet] pub mod pallet { use super::*; @@ -334,27 +311,6 @@ pub mod pallet { #[pallet::constant] type DepositPerByte: Get>; - /// The weight per byte of code that is charged when loading a contract from storage. - /// - /// Currently, FRAME only charges fees for computation incurred but not for PoV - /// consumption caused for storage access. This is usually not exploitable because - /// accessing storage carries some substantial weight costs, too. However in case - /// of contract code very much PoV consumption can be caused while consuming very little - /// computation. This could be used to keep the chain busy without paying the - /// proper fee for it. Until this is resolved we charge from the weight meter for - /// contract access. - /// - /// For more information check out: - /// - /// [`DefaultContractAccessWeight`] is a safe default to be used for Polkadot or Kusama - /// parachains. - /// - /// # Note - /// - /// This is only relevant for parachains. Set to zero in case of a standalone chain. - #[pallet::constant] - type ContractAccessWeight: Get; - /// The amount of balance a caller has to pay for each storage item. /// /// # Note @@ -413,23 +369,8 @@ pub mod pallet { T::AccountId: AsRef<[u8]>, as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode, { - /// Makes a call to an account, optionally transferring some balance. - /// - /// # Parameters - /// - /// * `dest`: Address of the contract to call. - /// * `value`: The balance to transfer from the `origin` to `dest`. - /// * `gas_limit`: The gas limit enforced when executing the constructor. - /// * `storage_deposit_limit`: The maximum amount of balance that can be charged from the - /// caller to pay for the storage consumed. - /// * `data`: The input data to pass to the contract. - /// - /// * If the account is a smart-contract account, the associated code will be - /// executed and any value will be transferred. - /// * If the account is a regular account, any value will be transferred. - /// * If no account exists and the call value is not less than `existential_deposit`, - /// a regular account will be created and any value will be transferred. - #[pallet::weight(T::WeightInfo::call().saturating_add((*gas_limit).into()))] + /// Deprecated version if [`Self::call`] for use in an in-storage `Call`. + #[pallet::weight(T::WeightInfo::call().saturating_add(>::compat_weight(*gas_limit)))] #[allow(deprecated)] #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `call`")] pub fn call_old_weight( @@ -440,55 +381,20 @@ pub mod pallet { storage_deposit_limit: Option< as codec::HasCompact>::Type>, data: Vec, ) -> DispatchResultWithPostInfo { - let gas_limit: Weight = gas_limit.into(); - let origin = ensure_signed(origin)?; - let dest = T::Lookup::lookup(dest)?; - let mut output = Self::internal_call( + Self::call( origin, dest, value, - gas_limit, - storage_deposit_limit.map(Into::into), + >::compat_weight(gas_limit), + storage_deposit_limit, data, - None, - ); - if let Ok(retval) = &output.result { - if retval.did_revert() { - output.result = Err(>::ContractReverted.into()); - } - } - output.gas_meter.into_dispatch_result(output.result, T::WeightInfo::call()) + ) } - /// Instantiates a new contract from the supplied `code` optionally transferring - /// some balance. - /// - /// This dispatchable has the same effect as calling [`Self::upload_code`] + - /// [`Self::instantiate`]. Bundling them together provides efficiency gains. Please - /// also check the documentation of [`Self::upload_code`]. - /// - /// # Parameters - /// - /// * `value`: The balance to transfer from the `origin` to the newly created contract. - /// * `gas_limit`: The gas limit enforced when executing the constructor. - /// * `storage_deposit_limit`: The maximum amount of balance that can be charged/reserved - /// from the caller to pay for the storage consumed. - /// * `code`: The contract code to deploy in raw bytes. - /// * `data`: The input data to pass to the contract constructor. - /// * `salt`: Used for the address derivation. See [`Pallet::contract_address`]. - /// - /// Instantiation is executed as follows: - /// - /// - The supplied `code` is instrumented, deployed, and a `code_hash` is created for that - /// code. - /// - If the `code_hash` already exists on the chain the underlying `code` will be shared. - /// - The destination address is computed based on the sender, code_hash and the salt. - /// - The smart-contract account is created at the computed address. - /// - The `value` is transferred to the new account. - /// - The `deploy` function is executed in the context of the newly-created account. + /// Deprecated version if [`Self::instantiate_with_code`] for use in an in-storage `Call`. #[pallet::weight( T::WeightInfo::instantiate_with_code(code.len() as u32, salt.len() as u32) - .saturating_add((*gas_limit).into()) + .saturating_add(>::compat_weight(*gas_limit)) )] #[allow(deprecated)] #[deprecated( @@ -503,38 +409,20 @@ pub mod pallet { data: Vec, salt: Vec, ) -> DispatchResultWithPostInfo { - let gas_limit: Weight = gas_limit.into(); - let origin = ensure_signed(origin)?; - let code_len = code.len() as u32; - let salt_len = salt.len() as u32; - let mut output = Self::internal_instantiate( + Self::instantiate_with_code( origin, value, - gas_limit, - storage_deposit_limit.map(Into::into), - Code::Upload(code), + >::compat_weight(gas_limit), + storage_deposit_limit, + code, data, salt, - None, - ); - if let Ok(retval) = &output.result { - if retval.1.did_revert() { - output.result = Err(>::ContractReverted.into()); - } - } - output.gas_meter.into_dispatch_result( - output.result.map(|(_address, result)| result), - T::WeightInfo::instantiate_with_code(code_len, salt_len), ) } - /// Instantiates a contract from a previously deployed wasm binary. - /// - /// This function is identical to [`Self::instantiate_with_code`] but without the - /// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary - /// must be supplied. + /// Deprecated version if [`Self::instantiate`] for use in an in-storage `Call`. #[pallet::weight( - T::WeightInfo::instantiate(salt.len() as u32).saturating_add((*gas_limit).into()) + T::WeightInfo::instantiate(salt.len() as u32).saturating_add(>::compat_weight(*gas_limit)) )] #[allow(deprecated)] #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `instantiate`")] @@ -547,27 +435,14 @@ pub mod pallet { data: Vec, salt: Vec, ) -> DispatchResultWithPostInfo { - let gas_limit: Weight = gas_limit.into(); - let origin = ensure_signed(origin)?; - let salt_len = salt.len() as u32; - let mut output = Self::internal_instantiate( + Self::instantiate( origin, value, - gas_limit, - storage_deposit_limit.map(Into::into), - Code::Existing(code_hash), + >::compat_weight(gas_limit), + storage_deposit_limit, + code_hash, data, salt, - None, - ); - if let Ok(retval) = &output.result { - if retval.1.did_revert() { - output.result = Err(>::ContractReverted.into()); - } - } - output.gas_meter.into_dispatch_result( - output.result.map(|(_address, output)| output), - T::WeightInfo::instantiate(salt_len), ) } @@ -1059,8 +934,8 @@ where ); ContractExecResult { result: output.result.map_err(|r| r.error), - gas_consumed: output.gas_meter.gas_consumed().ref_time(), - gas_required: output.gas_meter.gas_required().ref_time(), + gas_consumed: output.gas_meter.gas_consumed(), + gas_required: output.gas_meter.gas_required(), storage_deposit: output.storage_deposit, debug_message: debug_message.unwrap_or_default(), } @@ -1104,8 +979,8 @@ where .result .map(|(account_id, result)| InstantiateReturnValue { result, account_id }) .map_err(|e| e.error), - gas_consumed: output.gas_meter.gas_consumed().ref_time(), - gas_required: output.gas_meter.gas_required().ref_time(), + gas_consumed: output.gas_meter.gas_consumed(), + gas_required: output.gas_meter.gas_required(), storage_deposit: output.storage_deposit, debug_message: debug_message.unwrap_or_default(), } @@ -1287,4 +1162,12 @@ where fn min_balance() -> BalanceOf { >>::minimum_balance() } + + /// Convert a 1D Weight to a 2D weight. + /// + /// Used by backwards compatible extrinsics. We cannot just set the proof to zero + /// or an old `Call` will just fail. + fn compat_weight(gas_limit: OldWeight) -> Weight { + Weight::from(gas_limit).set_proof_size(u64::from(T::MaxCodeLen::get()) * 2) + } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index b4a8f8f4c834f..6a2144840143a 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -26,8 +26,8 @@ use crate::{ tests::test_utils::{get_contract, get_contract_checked}, wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, - BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, - DefaultContractAccessWeight, DeletionQueue, Error, Pallet, Schedule, + BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, DeletionQueue, + Error, Pallet, Schedule, }; use assert_matches::assert_matches; use codec::Encode; @@ -404,7 +404,6 @@ impl Config for Test { type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; type AddressGenerator = DefaultAddressGenerator; - type ContractAccessWeight = DefaultContractAccessWeight; type MaxCodeLen = ConstU32<{ 128 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; } @@ -414,7 +413,7 @@ pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]); pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]); -pub const GAS_LIMIT: Weight = Weight::from_ref_time(100_000_000_000).set_proof_size(u64::MAX); +pub const GAS_LIMIT: Weight = Weight::from_ref_time(100_000_000_000).set_proof_size(256 * 1024); pub struct ExtBuilder { existential_deposit: u64, @@ -674,7 +673,7 @@ fn run_out_of_gas() { RuntimeOrigin::signed(ALICE), addr, // newly created account 0, - Weight::from_ref_time(1_000_000_000_000), + Weight::from_ref_time(1_000_000_000_000).set_proof_size(u64::MAX), None, vec![], ), @@ -1760,7 +1759,7 @@ fn chain_extension_works() { false, ); assert_ok!(result.result); - assert_eq!(result.gas_consumed, gas_consumed + 42); + assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 42); let result = Contracts::bare_call( ALICE, addr.clone(), @@ -1771,7 +1770,7 @@ fn chain_extension_works() { false, ); assert_ok!(result.result); - assert_eq!(result.gas_consumed, gas_consumed + 95); + assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 95); // 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer let result = Contracts::bare_call( @@ -2409,10 +2408,11 @@ fn reinstrument_does_charge() { let result2 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); assert!(!result2.result.unwrap().did_revert()); - assert!(result2.gas_consumed > result1.gas_consumed); + assert!(result2.gas_consumed.ref_time() > result1.gas_consumed.ref_time()); assert_eq!( - result2.gas_consumed, - result1.gas_consumed + ::WeightInfo::reinstrument(code_len).ref_time(), + result2.gas_consumed.ref_time(), + result1.gas_consumed.ref_time() + + ::WeightInfo::reinstrument(code_len).ref_time(), ); }); } @@ -2536,7 +2536,7 @@ fn gas_estimation_nested_call_fixed_limit() { assert_ok!(&result.result); // We have a subcall with a fixed gas limit. This constitutes precharging. - assert!(result.gas_required > result.gas_consumed); + assert!(result.gas_required.ref_time() > result.gas_consumed.ref_time()); // Make the same call using the estimated gas. Should succeed. assert_ok!( @@ -2544,7 +2544,7 @@ fn gas_estimation_nested_call_fixed_limit() { ALICE, addr_caller, 0, - Weight::from_ref_time(result.gas_required).set_proof_size(u64::MAX), + result.gas_required, Some(result.storage_deposit.charge_or_zero()), input, false, @@ -2557,6 +2557,7 @@ fn gas_estimation_nested_call_fixed_limit() { #[test] #[cfg(feature = "unstable-interface")] fn gas_estimation_call_runtime() { + use codec::Decode; let (caller_code, caller_hash) = compile_module::("call_runtime").unwrap(); let (callee_code, callee_hash) = compile_module::("dummy").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { @@ -2591,7 +2592,7 @@ fn gas_estimation_call_runtime() { let call = RuntimeCall::Contracts(crate::Call::call { dest: addr_callee, value: 0, - gas_limit: GAS_LIMIT / 3, + gas_limit: GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() / 3), storage_deposit_limit: None, data: vec![], }); @@ -2604,9 +2605,10 @@ fn gas_estimation_call_runtime() { call.encode(), false, ); - assert_ok!(&result.result); - - assert!(result.gas_required > result.gas_consumed); + // contract encodes the result of the dispatch runtime + let outcome = u32::decode(&mut result.result.unwrap().data.as_ref()).unwrap(); + assert_eq!(outcome, 0); + assert!(result.gas_required.ref_time() > result.gas_consumed.ref_time()); // Make the same call using the required gas. Should succeed. assert_ok!( @@ -2614,7 +2616,7 @@ fn gas_estimation_call_runtime() { ALICE, addr_caller, 0, - Weight::from_ref_time(result.gas_required).set_proof_size(u64::MAX), + result.gas_required, None, call.encode(), false, diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 137eccf3db686..09e51d981360b 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -228,16 +228,11 @@ impl Token for CodeToken { // contract code. This is why we subtract `T::*::(0)`. We need to do this at this // point because when charging the general weight for calling the contract we not know the // size of the contract. - let ref_time_weight = match *self { + match *self { Reinstrument(len) => T::WeightInfo::reinstrument(len), - Load(len) => { - let computation = T::WeightInfo::call_with_code_per_byte(len) - .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)); - let bandwidth = T::ContractAccessWeight::get().saturating_mul(len as u64); - computation.max(bandwidth) - }, - }; - - ref_time_weight + Load(len) => T::WeightInfo::call_with_code_per_byte(len) + .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)) + .set_proof_size(len.into()), + } } } From 2cd40882d27ef10437c691b2705e67fa97f7c074 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Wed, 5 Oct 2022 17:11:50 +0300 Subject: [PATCH 1238/1472] MMR: impl `TypeInfo` for some structures (#12423) * BEEFY client: avoid unnecessary clone * MMR: impl TypeInfo for some structures --- Cargo.lock | 1 + client/beefy/rpc/src/lib.rs | 2 +- client/beefy/src/worker.rs | 2 +- primitives/beefy/src/mmr.rs | 4 ++-- primitives/merkle-mountain-range/Cargo.toml | 1 + primitives/merkle-mountain-range/src/lib.rs | 5 +++-- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 309742e5bf17e..647511373cc31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9999,6 +9999,7 @@ dependencies = [ "array-bytes", "log", "parity-scale-codec", + "scale-info", "serde", "sp-api", "sp-core", diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 0af474116e6d0..6f21abc616db8 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -84,7 +84,7 @@ impl From for JsonRpseeError { // Provides RPC methods for interacting with BEEFY. #[rpc(client, server)] pub trait BeefyApi { - /// Returns the block most recently finalized by BEEFY, alongside side its justification. + /// Returns the block most recently finalized by BEEFY, alongside its justification. #[subscription( name = "beefy_subscribeJustifications" => "beefy_justifications", unsubscribe = "beefy_unsubscribeJustifications", diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 832b43315515f..5bdc72357c412 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -508,7 +508,7 @@ where if let Err(e) = self.backend.append_justification( BlockId::Number(block_num), - (BEEFY_ENGINE_ID, finality_proof.clone().encode()), + (BEEFY_ENGINE_ID, finality_proof.encode()), ) { error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, finality_proof); } diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 761eee9f8ef85..471cb96841b8e 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -44,7 +44,7 @@ impl BeefyDataProvider> for () { } /// A standard leaf that gets added every block to the MMR constructed by Substrate's `pallet_mmr`. -#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] pub struct MmrLeaf { /// Version of the leaf format. /// @@ -73,7 +73,7 @@ pub struct MmrLeaf { /// Given that adding new struct elements in SCALE is backward compatible (i.e. old format can be /// still decoded, the new fields will simply be ignored). We expect the major version to be bumped /// very rarely (hopefuly never). -#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode)] +#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] pub struct MmrLeafVersion(u8); impl MmrLeafVersion { /// Create new version object from `major` and `minor` components. diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index e7e203942e845..0be53132f3eec 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -13,6 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index c40a594739ec1..7a26cae839ea9 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -20,6 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] +use scale_info::TypeInfo; use sp_debug_derive::RuntimeDebug; use sp_runtime::traits; #[cfg(not(feature = "std"))] @@ -69,7 +70,7 @@ impl OnNewRoot for () { } /// A MMR proof data for one of the leaves. -#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq)] +#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] pub struct Proof { /// The index of the leaf the proof is for. pub leaf_index: LeafIndex, @@ -352,7 +353,7 @@ impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3); impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3, E:4); /// A MMR proof data for a group of leaves. -#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq)] +#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] pub struct BatchProof { /// The indices of the leaves the proof is for. pub leaf_indices: Vec, From 4cd3248c6ac9e29a45e2b52b92859cbe12769500 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 5 Oct 2022 16:45:56 +0200 Subject: [PATCH 1239/1472] Don't send back empty proofs if light request fails (#12372) --- .../src/light_client_requests/handler.rs | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/client/network/light/src/light_client_requests/handler.rs b/client/network/light/src/light_client_requests/handler.rs index 727a9b0d7e820..5efdc3ff6a18b 100644 --- a/client/network/light/src/light_client_requests/handler.rs +++ b/client/network/light/src/light_client_requests/handler.rs @@ -28,7 +28,7 @@ use futures::{channel::mpsc, prelude::*}; use libp2p::PeerId; use log::{debug, trace}; use prost::Message; -use sc_client_api::{BlockBackend, ProofProvider, StorageProof}; +use sc_client_api::{BlockBackend, ProofProvider}; use sc_network_common::{ config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, @@ -176,12 +176,15 @@ where let block = Decode::decode(&mut request.block.as_ref())?; - let proof = + let response = match self .client .execution_proof(&BlockId::Hash(block), &request.method, &request.data) { - Ok((_, proof)) => proof, + Ok((_, proof)) => { + let r = schema::v1::light::RemoteCallResponse { proof: proof.encode() }; + Some(schema::v1::light::response::Response::RemoteCallResponse(r)) + }, Err(e) => { trace!( "remote call request from {} ({} at {:?}) failed with: {}", @@ -190,16 +193,11 @@ where request.block, e, ); - StorageProof::empty() + None }, }; - let response = { - let r = schema::v1::light::RemoteCallResponse { proof: proof.encode() }; - schema::v1::light::response::Response::RemoteCallResponse(r) - }; - - Ok(schema::v1::light::Response { response: Some(response) }) + Ok(schema::v1::light::Response { response }) } fn on_remote_read_request( @@ -221,11 +219,14 @@ where let block = Decode::decode(&mut request.block.as_ref())?; - let proof = match self + let response = match self .client .read_proof(&BlockId::Hash(block), &mut request.keys.iter().map(AsRef::as_ref)) { - Ok(proof) => proof, + Ok(proof) => { + let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; + Some(schema::v1::light::response::Response::RemoteReadResponse(r)) + }, Err(error) => { trace!( "remote read request from {} ({} at {:?}) failed with: {}", @@ -234,16 +235,11 @@ where request.block, error, ); - StorageProof::empty() + None }, }; - let response = { - let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; - schema::v1::light::response::Response::RemoteReadResponse(r) - }; - - Ok(schema::v1::light::Response { response: Some(response) }) + Ok(schema::v1::light::Response { response }) } fn on_remote_read_child_request( @@ -271,14 +267,17 @@ where Some((ChildType::ParentKeyId, storage_key)) => Ok(ChildInfo::new_default(storage_key)), None => Err(sp_blockchain::Error::InvalidChildStorageKey), }; - let proof = match child_info.and_then(|child_info| { + let response = match child_info.and_then(|child_info| { self.client.read_child_proof( &BlockId::Hash(block), &child_info, &mut request.keys.iter().map(AsRef::as_ref), ) }) { - Ok(proof) => proof, + Ok(proof) => { + let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; + Some(schema::v1::light::response::Response::RemoteReadResponse(r)) + }, Err(error) => { trace!( "remote read child request from {} ({} {} at {:?}) failed with: {}", @@ -288,16 +287,11 @@ where request.block, error, ); - StorageProof::empty() + None }, }; - let response = { - let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; - schema::v1::light::response::Response::RemoteReadResponse(r) - }; - - Ok(schema::v1::light::Response { response: Some(response) }) + Ok(schema::v1::light::Response { response }) } } From 87224cf2cdafbacd0acac33c43a1063c02e02147 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Wed, 5 Oct 2022 17:11:05 +0200 Subject: [PATCH 1240/1472] Implement `Clone` and `Default` for `Config` (#12397) * Implement `Clone` and `Default` for `Config` * `cargo fmt` * Remove default config implementation --- client/executor/wasmtime/src/runtime.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 5925a1792aef2..e3509351022bc 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -544,6 +544,7 @@ pub struct Semantics { pub max_memory_size: Option, } +#[derive(Clone)] pub struct Config { /// The WebAssembly standard requires all imports of an instantiated module to be resolved, /// otherwise, the instantiation fails. If this option is set to `true`, then this behavior is From eefba93cf62ff80e1011dbe1cd3a543b711f7bb9 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 5 Oct 2022 19:21:37 +0100 Subject: [PATCH 1241/1472] Bound uses of `Call` (#11649) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Introduce preimages module in traits * Multisize Preimages * Len not actually necessary * Tweaks to the preimage API * Fixes * Get Scheduler building with new API * Scheduler tests pass * Bounded Scheduler 🎉 * Use Agenda holes and introduce IncompleteSince to avoid need to reschedule * Tests pass with new weight system * New benchmarks * Add missing file * Drop preimage when permenantly overeight * Drop preimage when permenantly overeight * Referenda uses latest preimage API * Testing ok * Adding tests Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Add preimage migration Signed-off-by: Oliver Tale-Yazdi * Docs * Remove dbg * Refactor Democracy * Refactor Democracy * Add final MEL * Remove silly maps * Fixes * Minor refactor * Formatting * Fixes * Fixes * Fixes * Update frame/preimage/src/lib.rs Co-authored-by: Shawn Tabrizi * Add migrations to Democracy * WIP Signed-off-by: Oliver Tale-Yazdi * Resolve conflicts Signed-off-by: Oliver Tale-Yazdi * Revert "Resolve conflicts" This reverts commit a89cd0a073a7aabbb8ce6bcb12d4687717aac60e. * Undo wrong resolves... Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * Make compile Signed-off-by: Oliver Tale-Yazdi * massage clippy Signed-off-by: Oliver Tale-Yazdi * More clippy Signed-off-by: Oliver Tale-Yazdi * clippy annoyance Signed-off-by: Oliver Tale-Yazdi * clippy annoyance Signed-off-by: Oliver Tale-Yazdi * Fix benchmarks Signed-off-by: Oliver Tale-Yazdi * add missing file * Test Signed-off-by: Oliver Tale-Yazdi * More tests Signed-off-by: Oliver Tale-Yazdi * Clippy harassment Signed-off-by: Oliver Tale-Yazdi * Add test Signed-off-by: Oliver Tale-Yazdi * clippy Signed-off-by: Oliver Tale-Yazdi * Fixup tests Signed-off-by: Oliver Tale-Yazdi * Remove old stuff Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Test trait functions Signed-off-by: Oliver Tale-Yazdi * Update pallet-ui tests Why is this needed? Should not be the case unless master is broken... Signed-off-by: Oliver Tale-Yazdi * More scheduler trait test Signed-off-by: Oliver Tale-Yazdi * More tests Signed-off-by: Oliver Tale-Yazdi * Apply review suggestion Signed-off-by: Oliver Tale-Yazdi * Beauty fixes Signed-off-by: Oliver Tale-Yazdi * Add Scheduler test migration_v3_to_v4_works Signed-off-by: Oliver Tale-Yazdi * Merge fixup Signed-off-by: Oliver Tale-Yazdi * Keep referenda benchmarks instantiatable Signed-off-by: Oliver Tale-Yazdi * Update weights Signed-off-by: Oliver Tale-Yazdi * Use new scheduler weight functions Signed-off-by: Oliver Tale-Yazdi * Use new democracy weight functions Signed-off-by: Oliver Tale-Yazdi * Use weight compare functions Signed-off-by: Oliver Tale-Yazdi * Update pallet-ui tests Signed-off-by: Oliver Tale-Yazdi * More renaming… Signed-off-by: Oliver Tale-Yazdi * More renaming… Signed-off-by: Oliver Tale-Yazdi * Add comment Signed-off-by: Oliver Tale-Yazdi * Implement OnRuntimeUpgrade for scheduler::v3_to_v4 migration Put the migration into a proper `MigrateToV4` struct and implement the OnRuntimeUpgrade hooks for it. Also move the test to use that instead. This should make it easier for adding it to Polkadot. Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * Handle undecodable Agendas Signed-off-by: Oliver Tale-Yazdi * Remove trash Signed-off-by: Oliver Tale-Yazdi * Fix test Signed-off-by: Oliver Tale-Yazdi * Use new OnRuntimeUpgrade functions Signed-off-by: Oliver Tale-Yazdi * fix test Signed-off-by: Oliver Tale-Yazdi * Fix BoundedSlice::truncate_from Co-authored-by: jakoblell Signed-off-by: Oliver Tale-Yazdi * Fix pre_upgrade hook return values Signed-off-by: Oliver Tale-Yazdi * Add more error logging Signed-off-by: Oliver Tale-Yazdi * Find too large preimages in the pre_upgrade hook Signed-off-by: Oliver Tale-Yazdi * Test that too large Calls in agendas are ignored Signed-off-by: Oliver Tale-Yazdi * Use new OnRuntimeUpgrade hooks Why did the CI not catch this?! Signed-off-by: Oliver Tale-Yazdi * works fine - just more logs Signed-off-by: Oliver Tale-Yazdi * Fix staking migration Causing issues on Kusama... Signed-off-by: Oliver Tale-Yazdi * Fix UI tests No idea why this is needed. This is actually undoing an earlier change. Maybe the CI has different rustc versions!? Signed-off-by: Oliver Tale-Yazdi * Remove multisig's Calls (#12072) * Remove multisig's Calls * Multisig: Fix tests and re-introduce reserve logic (#12241) * Fix tests and re-introduce reserve logic * fix benches * add todo * remove irrelevant bench * [Feature] Add a migration that drains and refunds stored calls (#12313) * [Feature] Add a migration that drains and refunds stored calls * migration fixes * fixes * address review comments * consume the whole block weight * fix assertions * license header * fix interface Co-authored-by: parity-processbot <> Co-authored-by: parity-processbot <> Co-authored-by: Roman Useinov * Fix test Signed-off-by: Oliver Tale-Yazdi * Fix multisig benchmarks Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/bench-bot.sh" pallet dev pallet_democracy * ".git/.scripts/bench-bot.sh" pallet dev pallet_scheduler * ".git/.scripts/bench-bot.sh" pallet dev pallet_preimage Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi Co-authored-by: parity-processbot <> Co-authored-by: Roman Useinov --- Cargo.lock | 4 + bin/node/runtime/src/lib.rs | 16 +- frame/bounties/src/lib.rs | 2 +- frame/contracts/src/storage.rs | 2 +- frame/conviction-voting/src/lib.rs | 2 +- frame/democracy/Cargo.toml | 7 +- frame/democracy/src/benchmarking.rs | 394 ++--- frame/democracy/src/conviction.rs | 16 +- frame/democracy/src/lib.rs | 746 +++------ frame/democracy/src/migrations.rs | 236 +++ frame/democracy/src/tests.rs | 76 +- frame/democracy/src/tests/cancellation.rs | 30 +- frame/democracy/src/tests/decoders.rs | 40 +- frame/democracy/src/tests/delegation.rs | 8 +- .../democracy/src/tests/external_proposing.rs | 104 +- frame/democracy/src/tests/fast_tracking.rs | 27 +- frame/democracy/src/tests/lock_voting.rs | 36 +- frame/democracy/src/tests/preimage.rs | 237 --- frame/democracy/src/tests/public_proposals.rs | 61 +- frame/democracy/src/tests/scheduling.rs | 35 +- frame/democracy/src/tests/voting.rs | 10 +- frame/democracy/src/types.rs | 28 +- frame/democracy/src/vote.rs | 48 +- frame/democracy/src/vote_threshold.rs | 6 +- frame/democracy/src/weights.rs | 346 ++-- frame/identity/src/tests.rs | 2 +- frame/multisig/Cargo.toml | 3 + frame/multisig/src/benchmarking.rs | 124 +- frame/multisig/src/lib.rs | 148 +- frame/multisig/src/migrations.rs | 86 + frame/multisig/src/tests.rs | 293 +--- frame/nicks/src/lib.rs | 4 +- frame/preimage/Cargo.toml | 6 +- frame/preimage/src/benchmarking.rs | 26 +- frame/preimage/src/lib.rs | 237 ++- frame/preimage/src/migration.rs | 263 +++ frame/preimage/src/mock.rs | 1 - frame/preimage/src/tests.rs | 279 +++- frame/preimage/src/weights.rs | 124 +- frame/recovery/src/lib.rs | 4 +- frame/referenda/src/benchmarking.rs | 16 +- frame/referenda/src/lib.rs | 104 +- frame/referenda/src/mock.rs | 18 +- frame/referenda/src/tests.rs | 32 +- frame/referenda/src/types.rs | 22 +- frame/scheduler/src/benchmarking.rs | 323 ++-- frame/scheduler/src/lib.rs | 984 +++++++---- frame/scheduler/src/migration.rs | 402 +++++ frame/scheduler/src/mock.rs | 56 +- frame/scheduler/src/tests.rs | 1482 ++++++++++++----- frame/scheduler/src/weights.rs | 316 ++-- .../src/construct_runtime/expand/origin.rs | 27 +- frame/support/src/dispatch.rs | 21 +- frame/support/src/traits.rs | 15 +- frame/support/src/traits/dispatch.rs | 38 +- frame/support/src/traits/misc.rs | 2 +- frame/support/src/traits/preimages.rs | 317 ++++ frame/support/src/traits/schedule.rs | 99 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 6 +- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 6 +- .../pallet_ui/storage_info_unsatisfied.stderr | 2 +- .../storage_info_unsatisfied_nmap.stderr | 2 +- frame/system/src/lib.rs | 5 +- frame/whitelist/src/mock.rs | 1 - primitives/core/src/bounded/bounded_vec.rs | 30 +- primitives/runtime/src/lib.rs | 55 +- test-utils/runtime/src/lib.rs | 35 +- 67 files changed, 5067 insertions(+), 3466 deletions(-) create mode 100644 frame/democracy/src/migrations.rs delete mode 100644 frame/democracy/src/tests/preimage.rs create mode 100644 frame/multisig/src/migrations.rs create mode 100644 frame/preimage/src/migration.rs create mode 100644 frame/scheduler/src/migration.rs create mode 100644 frame/support/src/traits/preimages.rs diff --git a/Cargo.lock b/Cargo.lock index 647511373cc31..53f370a930626 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5581,7 +5581,9 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "pallet-balances", + "pallet-preimage", "pallet-scheduler", "parity-scale-codec", "scale-info", @@ -5899,6 +5901,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "pallet-balances", "parity-scale-codec", "scale-info", @@ -6065,6 +6068,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "pallet-balances", "parity-scale-codec", "scale-info", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4898312f9608f..d10448cc2d183 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -340,8 +340,6 @@ impl pallet_proxy::Config for Runtime { parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; - // Retry a scheduled item every 10 blocks (1 minute) until the preimage exists. - pub const NoPreimagePostponement: Option = Some(10); } impl pallet_scheduler::Config for Runtime { @@ -351,11 +349,10 @@ impl pallet_scheduler::Config for Runtime { type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureRoot; - type MaxScheduledPerBlock = ConstU32<50>; + type MaxScheduledPerBlock = ConstU32<512>; type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; - type PreimageProvider = Preimage; - type NoPreimagePostponement = NoPreimagePostponement; + type Preimages = Preimage; } parameter_types! { @@ -370,7 +367,6 @@ impl pallet_preimage::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type MaxSize = PreimageMaxSize; type BaseDeposit = PreimageBaseDeposit; type ByteDeposit = PreimageByteDeposit; } @@ -862,6 +858,7 @@ impl pallet_referenda::Config for Runtime { type UndecidingTimeout = UndecidingTimeout; type AlarmInterval = AlarmInterval; type Tracks = TracksInfo; + type Preimages = Preimage; } impl pallet_referenda::Config for Runtime { @@ -881,6 +878,7 @@ impl pallet_referenda::Config for Runtime { type UndecidingTimeout = UndecidingTimeout; type AlarmInterval = AlarmInterval; type Tracks = TracksInfo; + type Preimages = Preimage; } impl pallet_ranked_collective::Config for Runtime { @@ -909,7 +907,6 @@ parameter_types! { } impl pallet_democracy::Config for Runtime { - type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type Currency = Balances; type EnactmentPeriod = EnactmentPeriod; @@ -949,14 +946,15 @@ impl pallet_democracy::Config for Runtime { // only do it once and it lasts only for the cool-off period. type VetoOrigin = pallet_collective::EnsureMember; type CooloffPeriod = CooloffPeriod; - type PreimageByteDeposit = PreimageByteDeposit; - type OperationalPreimageOrigin = pallet_collective::EnsureMember; type Slash = Treasury; type Scheduler = Scheduler; type PalletsOrigin = OriginCaller; type MaxVotes = ConstU32<100>; type WeightInfo = pallet_democracy::weights::SubstrateWeight; type MaxProposals = MaxProposals; + type Preimages = Preimage; + type MaxDeposits = ConstU32<100>; + type MaxBlacklisted = ConstU32<100>; } parameter_types! { diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index b95940a2835ce..d947226f87fa0 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -819,7 +819,7 @@ impl, I: 'static> Pallet { value: BalanceOf, ) -> DispatchResult { let bounded_description: BoundedVec<_, _> = - description.try_into().map_err(|()| Error::::ReasonTooBig)?; + description.try_into().map_err(|_| Error::::ReasonTooBig)?; ensure!(value >= T::BountyValueMinimum::get(), Error::::InvalidValue); let index = Self::bounty_count(); diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index c3fc0840d8649..cf10c3225c920 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -340,7 +340,7 @@ where let queue: Vec = (0..T::DeletionQueueDepth::get()) .map(|_| DeletedContract { trie_id: TrieId::default() }) .collect(); - let bounded: BoundedVec<_, _> = queue.try_into().unwrap(); + let bounded: BoundedVec<_, _> = queue.try_into().map_err(|_| ()).unwrap(); >::put(bounded); } } diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index 534941d6f7f66..b876a9354ee59 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -400,7 +400,7 @@ impl, I: 'static> Pallet { Err(i) => { votes .try_insert(i, (poll_index, vote)) - .map_err(|()| Error::::MaxVotesReached)?; + .map_err(|_| Error::::MaxVotesReached)?; }, } // Shouldn't be possible to fail, but we handle it gracefully. diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index f0ab3162c892b..e50d39ff76902 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -24,11 +24,13 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +log = { version = "0.4.17", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } [features] default = ["std"] @@ -42,6 +44,7 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "sp-core/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -49,4 +52,4 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] -try-runtime = ["frame-support/try-runtime"] +try-runtime = ["frame-support/try-runtime",] diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index ab7ee3331e319..424192e2521da 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -22,24 +22,16 @@ use super::*; use frame_benchmarking::{account, benchmarks, whitelist_account}; use frame_support::{ assert_noop, assert_ok, - codec::Decode, - traits::{ - schedule::DispatchTime, Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable, - }, + traits::{Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable}, }; -use frame_system::{Pallet as System, RawOrigin}; -use sp_runtime::traits::{BadOrigin, Bounded, One}; +use frame_system::RawOrigin; +use sp_core::H256; +use sp_runtime::{traits::Bounded, BoundedVec}; use crate::Pallet as Democracy; +const REFERENDUM_COUNT_HINT: u32 = 10; const SEED: u32 = 0; -const MAX_REFERENDUMS: u32 = 99; -const MAX_SECONDERS: u32 = 100; -const MAX_BYTES: u32 = 16_384; - -fn assert_last_event(generic_event: ::RuntimeEvent) { - frame_system::Pallet::::assert_last_event(generic_event.into()); -} fn funded_account(name: &'static str, index: u32) -> T::AccountId { let caller: T::AccountId = account(name, index, SEED); @@ -49,37 +41,32 @@ fn funded_account(name: &'static str, index: u32) -> T::AccountId { caller } -fn add_proposal(n: u32) -> Result { +fn make_proposal(n: u32) -> BoundedCallOf { + let call: CallOf = frame_system::Call::remark { remark: n.encode() }.into(); + ::Preimages::bound(call).unwrap() +} + +fn add_proposal(n: u32) -> Result { let other = funded_account::("proposer", n); let value = T::MinimumDeposit::get(); - let proposal_hash: T::Hash = T::Hashing::hash_of(&n); - - Democracy::::propose(RawOrigin::Signed(other).into(), proposal_hash, value)?; - - Ok(proposal_hash) + let proposal = make_proposal::(n); + Democracy::::propose(RawOrigin::Signed(other).into(), proposal.clone(), value)?; + Ok(proposal.hash()) } -fn add_referendum(n: u32) -> Result { - let proposal_hash: T::Hash = T::Hashing::hash_of(&n); +fn add_referendum(n: u32) -> (ReferendumIndex, H256) { let vote_threshold = VoteThreshold::SimpleMajority; - - Democracy::::inject_referendum( - T::LaunchPeriod::get(), - proposal_hash, - vote_threshold, - 0u32.into(), - ); - let referendum_index: ReferendumIndex = ReferendumCount::::get() - 1; - T::Scheduler::schedule_named( - (DEMOCRACY_ID, referendum_index).encode(), - DispatchTime::At(2u32.into()), - None, - 63, - frame_system::RawOrigin::Root.into(), - Call::enact_proposal { proposal_hash, index: referendum_index }.into(), + let proposal = make_proposal::(n); + let hash = proposal.hash(); + ( + Democracy::::inject_referendum( + T::LaunchPeriod::get(), + proposal, + vote_threshold, + 0u32.into(), + ), + hash, ) - .map_err(|_| "failed to schedule named")?; - Ok(referendum_index) } fn account_vote(b: BalanceOf) -> AccountVote> { @@ -97,95 +84,90 @@ benchmarks! { } let caller = funded_account::("caller", 0); - let proposal_hash: T::Hash = T::Hashing::hash_of(&0); + let proposal = make_proposal::(0); let value = T::MinimumDeposit::get(); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), proposal_hash, value) + }: _(RawOrigin::Signed(caller), proposal, value) verify { assert_eq!(Democracy::::public_props().len(), p as usize, "Proposals not created."); } second { - let s in 0 .. MAX_SECONDERS; - let caller = funded_account::("caller", 0); - let proposal_hash = add_proposal::(s)?; + add_proposal::(0)?; // Create s existing "seconds" - for i in 0 .. s { + // we must reserve one deposit for the `proposal` and one for our benchmarked `second` call. + for i in 0 .. T::MaxDeposits::get() - 2 { let seconder = funded_account::("seconder", i); - Democracy::::second(RawOrigin::Signed(seconder).into(), 0, u32::MAX)?; + Democracy::::second(RawOrigin::Signed(seconder).into(), 0)?; } let deposits = Democracy::::deposit_of(0).ok_or("Proposal not created")?; - assert_eq!(deposits.0.len(), (s + 1) as usize, "Seconds not recorded"); + assert_eq!(deposits.0.len(), (T::MaxDeposits::get() - 1) as usize, "Seconds not recorded"); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), 0, u32::MAX) + }: _(RawOrigin::Signed(caller), 0) verify { let deposits = Democracy::::deposit_of(0).ok_or("Proposal not created")?; - assert_eq!(deposits.0.len(), (s + 2) as usize, "`second` benchmark did not work"); + assert_eq!(deposits.0.len(), (T::MaxDeposits::get()) as usize, "`second` benchmark did not work"); } vote_new { - let r in 1 .. MAX_REFERENDUMS; - let caller = funded_account::("caller", 0); let account_vote = account_vote::(100u32.into()); // We need to create existing direct votes - for i in 0 .. r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; + for i in 0 .. T::MaxVotes::get() - 1 { + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; } let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; - assert_eq!(votes.len(), r as usize, "Votes were not recorded."); + assert_eq!(votes.len(), (T::MaxVotes::get() - 1) as usize, "Votes were not recorded."); - let referendum_index = add_referendum::(r)?; + let ref_index = add_referendum::(T::MaxVotes::get() - 1).0; whitelist_account!(caller); - }: vote(RawOrigin::Signed(caller.clone()), referendum_index, account_vote) + }: vote(RawOrigin::Signed(caller.clone()), ref_index, account_vote) verify { let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; - assert_eq!(votes.len(), (r + 1) as usize, "Vote was not recorded."); + assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was not recorded."); } vote_existing { - let r in 1 .. MAX_REFERENDUMS; - let caller = funded_account::("caller", 0); let account_vote = account_vote::(100u32.into()); // We need to create existing direct votes - for i in 0 ..=r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; + for i in 0..T::MaxVotes::get() { + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; } let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; - assert_eq!(votes.len(), (r + 1) as usize, "Votes were not recorded."); + assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Votes were not recorded."); // Change vote from aye to nay let nay = Vote { aye: false, conviction: Conviction::Locked1x }; let new_vote = AccountVote::Standard { vote: nay, balance: 1000u32.into() }; - let referendum_index = Democracy::::referendum_count() - 1; + let ref_index = Democracy::::referendum_count() - 1; // This tests when a user changes a vote whitelist_account!(caller); - }: vote(RawOrigin::Signed(caller.clone()), referendum_index, new_vote) + }: vote(RawOrigin::Signed(caller.clone()), ref_index, new_vote) verify { let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; - assert_eq!(votes.len(), (r + 1) as usize, "Vote was incorrectly added"); - let referendum_info = Democracy::::referendum_info(referendum_index) + assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was incorrectly added"); + let referendum_info = Democracy::::referendum_info(ref_index) .ok_or("referendum doesn't exist")?; let tally = match referendum_info { ReferendumInfo::Ongoing(r) => r.tally, @@ -196,61 +178,55 @@ benchmarks! { emergency_cancel { let origin = T::CancellationOrigin::successful_origin(); - let referendum_index = add_referendum::(0)?; - assert_ok!(Democracy::::referendum_status(referendum_index)); - }: _(origin, referendum_index) + let ref_index = add_referendum::(0).0; + assert_ok!(Democracy::::referendum_status(ref_index)); + }: _(origin, ref_index) verify { // Referendum has been canceled assert_noop!( - Democracy::::referendum_status(referendum_index), + Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid, ); } blacklist { - let p in 1 .. T::MaxProposals::get(); - // Place our proposal at the end to make sure it's worst case. - for i in 0 .. p - 1 { + for i in 0 .. T::MaxProposals::get() - 1 { add_proposal::(i)?; } // We should really add a lot of seconds here, but we're not doing it elsewhere. + // Add a referendum of our proposal. + let (ref_index, hash) = add_referendum::(0); + assert_ok!(Democracy::::referendum_status(ref_index)); // Place our proposal in the external queue, too. - let hash = T::Hashing::hash_of(&0); assert_ok!( - Democracy::::external_propose(T::ExternalOrigin::successful_origin(), hash) + Democracy::::external_propose(T::ExternalOrigin::successful_origin(), make_proposal::(0)) ); let origin = T::BlacklistOrigin::successful_origin(); - // Add a referendum of our proposal. - let referendum_index = add_referendum::(0)?; - assert_ok!(Democracy::::referendum_status(referendum_index)); - }: _(origin, hash, Some(referendum_index)) + }: _(origin, hash, Some(ref_index)) verify { // Referendum has been canceled assert_noop!( - Democracy::::referendum_status(referendum_index), + Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid ); } // Worst case scenario, we external propose a previously blacklisted proposal external_propose { - let v in 1 .. MAX_VETOERS as u32; - let origin = T::ExternalOrigin::successful_origin(); - let proposal_hash = T::Hashing::hash_of(&0); + let proposal = make_proposal::(0); // Add proposal to blacklist with block number 0 - let addresses = (0..v) + let addresses: BoundedVec<_, _> = (0..(T::MaxBlacklisted::get() - 1)) .into_iter() .map(|i| account::("blacklist", i, SEED)) - .collect::>(); - Blacklist::::insert( - proposal_hash, - (T::BlockNumber::zero(), addresses), - ); - }: _(origin, proposal_hash) + .collect::>() + .try_into() + .unwrap(); + Blacklist::::insert(proposal.hash(), (T::BlockNumber::zero(), addresses)); + }: _(origin, proposal) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -258,8 +234,8 @@ benchmarks! { external_propose_majority { let origin = T::ExternalMajorityOrigin::successful_origin(); - let proposal_hash = T::Hashing::hash_of(&0); - }: _(origin, proposal_hash) + let proposal = make_proposal::(0); + }: _(origin, proposal) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -267,8 +243,8 @@ benchmarks! { external_propose_default { let origin = T::ExternalDefaultOrigin::successful_origin(); - let proposal_hash = T::Hashing::hash_of(&0); - }: _(origin, proposal_hash) + let proposal = make_proposal::(0); + }: _(origin, proposal) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -276,8 +252,9 @@ benchmarks! { fast_track { let origin_propose = T::ExternalDefaultOrigin::successful_origin(); - let proposal_hash: T::Hash = T::Hashing::hash_of(&0); - Democracy::::external_propose_default(origin_propose, proposal_hash)?; + let proposal = make_proposal::(0); + let proposal_hash = proposal.hash(); + Democracy::::external_propose_default(origin_propose, proposal)?; // NOTE: Instant origin may invoke a little bit more logic, but may not always succeed. let origin_fast_track = T::FastTrackOrigin::successful_origin(); @@ -289,17 +266,15 @@ benchmarks! { } veto_external { - // Existing veto-ers - let v in 0 .. MAX_VETOERS as u32; - - let proposal_hash: T::Hash = T::Hashing::hash_of(&v); + let proposal = make_proposal::(0); + let proposal_hash = proposal.hash(); let origin_propose = T::ExternalDefaultOrigin::successful_origin(); - Democracy::::external_propose_default(origin_propose, proposal_hash)?; + Democracy::::external_propose_default(origin_propose, proposal)?; - let mut vetoers: Vec = Vec::new(); - for i in 0 .. v { - vetoers.push(account::("vetoer", i, SEED)); + let mut vetoers: BoundedVec = Default::default(); + for i in 0 .. (T::MaxBlacklisted::get() - 1) { + vetoers.try_push(account::("vetoer", i, SEED)).unwrap(); } vetoers.sort(); Blacklist::::insert(proposal_hash, (T::BlockNumber::zero(), vetoers)); @@ -310,42 +285,27 @@ benchmarks! { verify { assert!(NextExternal::::get().is_none()); let (_, new_vetoers) = >::get(&proposal_hash).ok_or("no blacklist")?; - assert_eq!(new_vetoers.len(), (v + 1) as usize, "vetoers not added"); + assert_eq!(new_vetoers.len(), T::MaxBlacklisted::get() as usize, "vetoers not added"); } cancel_proposal { - let p in 1 .. T::MaxProposals::get(); - // Place our proposal at the end to make sure it's worst case. - for i in 0 .. p { + for i in 0 .. T::MaxProposals::get() { add_proposal::(i)?; } - let cancel_origin = T::CancelProposalOrigin::successful_origin(); }: _(cancel_origin, 0) cancel_referendum { - let referendum_index = add_referendum::(0)?; - }: _(RawOrigin::Root, referendum_index) - - cancel_queued { - let r in 1 .. MAX_REFERENDUMS; - - for i in 0..r { - add_referendum::(i)?; // This add one element in the scheduler - } - - let referendum_index = add_referendum::(r)?; - }: _(RawOrigin::Root, referendum_index) + let ref_index = add_referendum::(0).0; + }: _(RawOrigin::Root, ref_index) - // This measures the path of `launch_next` external. Not currently used as we simply - // assume the weight is `MaxBlockWeight` when executing. #[extra] on_initialize_external { - let r in 0 .. MAX_REFERENDUMS; + let r in 0 .. REFERENDUM_COUNT_HINT; for i in 0..r { - add_referendum::(i)?; + add_referendum::(i); } assert_eq!(Democracy::::referendum_count(), r, "referenda not created"); @@ -354,8 +314,8 @@ benchmarks! { LastTabledWasExternal::::put(false); let origin = T::ExternalMajorityOrigin::successful_origin(); - let proposal_hash = T::Hashing::hash_of(&r); - let call = Call::::external_propose_majority { proposal_hash }; + let proposal = make_proposal::(r); + let call = Call::::external_propose_majority { proposal }; call.dispatch_bypass_filter(origin)?; // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -379,14 +339,12 @@ benchmarks! { } } - // This measures the path of `launch_next` public. Not currently used as we simply - // assume the weight is `MaxBlockWeight` when executing. #[extra] on_initialize_public { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); for i in 0..r { - add_referendum::(i)?; + add_referendum::(i); } assert_eq!(Democracy::::referendum_count(), r, "referenda not created"); @@ -415,10 +373,10 @@ benchmarks! { // No launch no maturing referenda. on_initialize_base { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); for i in 0..r { - add_referendum::(i)?; + add_referendum::(i); } for (key, mut info) in ReferendumInfoOf::::iter() { @@ -445,10 +403,10 @@ benchmarks! { } on_initialize_base_with_launch_period { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); for i in 0..r { - add_referendum::(i)?; + add_referendum::(i); } for (key, mut info) in ReferendumInfoOf::::iter() { @@ -477,7 +435,7 @@ benchmarks! { } delegate { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); let initial_balance: BalanceOf = 100u32.into(); let delegated_balance: BalanceOf = 1000u32.into(); @@ -504,8 +462,8 @@ benchmarks! { let account_vote = account_vote::(initial_balance); // We need to create existing direct votes for the `new_delegate` for i in 0..r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_idx, account_vote)?; + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_index, account_vote)?; } let votes = match VotingOf::::get(&new_delegate) { Voting::Direct { votes, .. } => votes, @@ -529,7 +487,7 @@ benchmarks! { } undelegate { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); let initial_balance: BalanceOf = 100u32.into(); let delegated_balance: BalanceOf = 1000u32.into(); @@ -553,10 +511,10 @@ benchmarks! { // We need to create votes direct votes for the `delegate` let account_vote = account_vote::(initial_balance); for i in 0..r { - let ref_idx = add_referendum::(i)?; + let ref_index = add_referendum::(i).0; Democracy::::vote( RawOrigin::Signed(the_delegate.clone()).into(), - ref_idx, + ref_index, account_vote )?; } @@ -580,71 +538,9 @@ benchmarks! { }: _(RawOrigin::Root) - note_preimage { - // Num of bytes in encoded proposal - let b in 0 .. MAX_BYTES; - - let caller = funded_account::("caller", 0); - let encoded_proposal = vec![1; b as usize]; - whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), encoded_proposal.clone()) - verify { - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - match Preimages::::get(proposal_hash) { - Some(PreimageStatus::Available { .. }) => (), - _ => return Err("preimage not available".into()) - } - } - - note_imminent_preimage { - // Num of bytes in encoded proposal - let b in 0 .. MAX_BYTES; - - // d + 1 to include the one we are testing - let encoded_proposal = vec![1; b as usize]; - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - let block_number = T::BlockNumber::one(); - Preimages::::insert(&proposal_hash, PreimageStatus::Missing(block_number)); - - let caller = funded_account::("caller", 0); - let encoded_proposal = vec![1; b as usize]; - whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), encoded_proposal.clone()) - verify { - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - match Preimages::::get(proposal_hash) { - Some(PreimageStatus::Available { .. }) => (), - _ => return Err("preimage not available".into()) - } - } - - reap_preimage { - // Num of bytes in encoded proposal - let b in 0 .. MAX_BYTES; - - let encoded_proposal = vec![1; b as usize]; - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - - let submitter = funded_account::("submitter", b); - Democracy::::note_preimage(RawOrigin::Signed(submitter).into(), encoded_proposal.clone())?; - - // We need to set this otherwise we get `Early` error. - let block_number = T::VotingPeriod::get() + T::EnactmentPeriod::get() + T::BlockNumber::one(); - System::::set_block_number(block_number); - - assert!(Preimages::::contains_key(proposal_hash)); - - let caller = funded_account::("caller", 0); - whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), proposal_hash, u32::MAX) - verify { - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - assert!(!Preimages::::contains_key(proposal_hash)); - } - // Test when unlock will remove locks unlock_remove { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); let locker = funded_account::("locker", 0); let locker_lookup = T::Lookup::unlookup(locker.clone()); @@ -653,9 +549,9 @@ benchmarks! { let small_vote = account_vote::(base_balance); // Vote and immediately unvote for i in 0 .. r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote)?; - Democracy::::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_idx)?; + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?; + Democracy::::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?; } let caller = funded_account::("caller", 0); @@ -669,7 +565,7 @@ benchmarks! { // Test when unlock will set a new value unlock_set { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); let locker = funded_account::("locker", 0); let locker_lookup = T::Lookup::unlookup(locker.clone()); @@ -677,14 +573,14 @@ benchmarks! { let base_balance: BalanceOf = 100u32.into(); let small_vote = account_vote::(base_balance); for i in 0 .. r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote)?; + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?; } // Create a big vote so lock increases let big_vote = account_vote::(base_balance * 10u32.into()); - let referendum_index = add_referendum::(r)?; - Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), referendum_index, big_vote)?; + let ref_index = add_referendum::(r).0; + Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, big_vote)?; let votes = match VotingOf::::get(&locker) { Voting::Direct { votes, .. } => votes, @@ -695,7 +591,7 @@ benchmarks! { let voting = VotingOf::::get(&locker); assert_eq!(voting.locked_balance(), base_balance * 10u32.into()); - Democracy::::remove_vote(RawOrigin::Signed(locker.clone()).into(), referendum_index)?; + Democracy::::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?; let caller = funded_account::("caller", 0); whitelist_account!(caller); @@ -709,18 +605,18 @@ benchmarks! { let voting = VotingOf::::get(&locker); // Note that we may want to add a `get_lock` api to actually verify - assert_eq!(voting.locked_balance(), base_balance); + assert_eq!(voting.locked_balance(), if r > 0 { base_balance } else { 0u32.into() }); } remove_vote { - let r in 1 .. MAX_REFERENDUMS; + let r in 1 .. T::MaxVotes::get(); let caller = funded_account::("caller", 0); let account_vote = account_vote::(100u32.into()); for i in 0 .. r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; } let votes = match VotingOf::::get(&caller) { @@ -729,9 +625,9 @@ benchmarks! { }; assert_eq!(votes.len(), r as usize, "Votes not created"); - let referendum_index = r - 1; + let ref_index = r - 1; whitelist_account!(caller); - }: _(RawOrigin::Signed(caller.clone()), referendum_index) + }: _(RawOrigin::Signed(caller.clone()), ref_index) verify { let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, @@ -742,15 +638,15 @@ benchmarks! { // Worst case is when target == caller and referendum is ongoing remove_other_vote { - let r in 1 .. MAX_REFERENDUMS; + let r in 1 .. T::MaxVotes::get(); let caller = funded_account::("caller", r); let caller_lookup = T::Lookup::unlookup(caller.clone()); let account_vote = account_vote::(100u32.into()); for i in 0 .. r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; } let votes = match VotingOf::::get(&caller) { @@ -759,9 +655,9 @@ benchmarks! { }; assert_eq!(votes.len(), r as usize, "Votes not created"); - let referendum_index = r - 1; + let ref_index = r - 1; whitelist_account!(caller); - }: _(RawOrigin::Signed(caller.clone()), caller_lookup, referendum_index) + }: _(RawOrigin::Signed(caller.clone()), caller_lookup, ref_index) verify { let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, @@ -770,54 +666,6 @@ benchmarks! { assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed"); } - #[extra] - enact_proposal_execute { - // Num of bytes in encoded proposal - let b in 0 .. MAX_BYTES; - - let proposer = funded_account::("proposer", 0); - let raw_call = Call::note_preimage { encoded_proposal: vec![1; b as usize] }; - let generic_call: T::Proposal = raw_call.into(); - let encoded_proposal = generic_call.encode(); - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - Democracy::::note_preimage(RawOrigin::Signed(proposer).into(), encoded_proposal)?; - - match Preimages::::get(proposal_hash) { - Some(PreimageStatus::Available { .. }) => (), - _ => return Err("preimage not available".into()) - } - }: enact_proposal(RawOrigin::Root, proposal_hash, 0) - verify { - // Fails due to mismatched origin - assert_last_event::(Event::::Executed { ref_index: 0, result: Err(BadOrigin.into()) }.into()); - } - - #[extra] - enact_proposal_slash { - // Num of bytes in encoded proposal - let b in 0 .. MAX_BYTES; - - let proposer = funded_account::("proposer", 0); - // Random invalid bytes - let encoded_proposal = vec![200; b as usize]; - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - Democracy::::note_preimage(RawOrigin::Signed(proposer).into(), encoded_proposal)?; - - match Preimages::::get(proposal_hash) { - Some(PreimageStatus::Available { .. }) => (), - _ => return Err("preimage not available".into()) - } - let origin = RawOrigin::Root.into(); - let call = Call::::enact_proposal { proposal_hash, index: 0 }.encode(); - }: { - assert_eq!( - as Decode>::decode(&mut &*call) - .expect("call is encoded above, encoding must be correct") - .dispatch_bypass_filter(origin), - Err(Error::::PreimageInvalid.into()) - ); - } - impl_benchmark_test_suite!( Democracy, crate::tests::new_test_ext(), diff --git a/frame/democracy/src/conviction.rs b/frame/democracy/src/conviction.rs index 57d631e8c1f4c..a938d8a4e6852 100644 --- a/frame/democracy/src/conviction.rs +++ b/frame/democracy/src/conviction.rs @@ -18,7 +18,7 @@ //! The conviction datatype. use crate::types::Delegations; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ traits::{Bounded, CheckedDiv, CheckedMul, Zero}, @@ -27,7 +27,19 @@ use sp_runtime::{ use sp_std::{prelude::*, result::Result}; /// A value denoting the strength of conviction of a vote. -#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo)] +#[derive( + Encode, + MaxEncodedLen, + Decode, + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + RuntimeDebug, + TypeInfo, +)] pub enum Conviction { /// 0.1x votes, unlocked. None, diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 3c1be19103998..cf954d4800eee 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -152,21 +152,20 @@ #![recursion_limit = "256"] #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode, Input}; +use codec::{Decode, Encode}; use frame_support::{ ensure, traits::{ defensive_prelude::*, - schedule::{DispatchTime, Named as ScheduleNamed}, - BalanceStatus, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, - ReservableCurrency, WithdrawReasons, + schedule::{v3::Named as ScheduleNamed, DispatchTime}, + Bounded, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, QueryPreimage, + ReservableCurrency, StorePreimage, WithdrawReasons, }, weights::Weight, }; -use scale_info::TypeInfo; use sp_runtime::{ - traits::{Bounded, Dispatchable, Hash, Saturating, StaticLookup, Zero}, - ArithmeticError, DispatchError, DispatchResult, RuntimeDebug, + traits::{Bounded as ArithBounded, One, Saturating, StaticLookup, Zero}, + ArithmeticError, DispatchError, DispatchResult, }; use sp_std::prelude::*; @@ -188,12 +187,9 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; -const DEMOCRACY_ID: LockIdentifier = *b"democrac"; +pub mod migrations; -/// The maximum number of vetoers on a single proposal used to compute Weight. -/// -/// NOTE: This is not enforced by any logic. -pub const MAX_VETOERS: u32 = 100; +const DEMOCRACY_ID: LockIdentifier = *b"democrac"; /// A proposal index. pub type PropIndex = u32; @@ -206,58 +202,36 @@ type BalanceOf = type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; +pub type CallOf = ::RuntimeCall; +pub type BoundedCallOf = Bounded>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum PreimageStatus { - /// The preimage is imminently needed at the argument. - Missing(BlockNumber), - /// The preimage is available. - Available { - data: Vec, - provider: AccountId, - deposit: Balance, - since: BlockNumber, - /// None if it's not imminent. - expiry: Option, - }, -} - -impl PreimageStatus { - fn to_missing_expiry(self) -> Option { - match self { - PreimageStatus::Missing(expiry) => Some(expiry), - _ => None, - } - } -} - -// A value placed in storage that represents the current version of the Democracy storage. -// This value is used by the `on_runtime_upgrade` logic to determine whether we run -// storage migration logic. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] -enum Releases { - V1, -} - #[frame_support::pallet] pub mod pallet { use super::{DispatchResult, *}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use sp_core::H256; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] pub trait Config: frame_system::Config + Sized { - type Proposal: Parameter - + Dispatchable - + From>; + type WeightInfo: WeightInfo; type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// The Scheduler. + type Scheduler: ScheduleNamed, Self::PalletsOrigin>; + + /// The Preimage provider. + type Preimages: QueryPreimage + StorePreimage; + /// Currency type for this pallet. type Currency: ReservableCurrency + LockableCurrency; @@ -289,6 +263,39 @@ pub mod pallet { #[pallet::constant] type MinimumDeposit: Get>; + /// Indicator for whether an emergency origin is even allowed to happen. Some chains may + /// want to set this permanently to `false`, others may want to condition it on things such + /// as an upgrade having happened recently. + #[pallet::constant] + type InstantAllowed: Get; + + /// Minimum voting period allowed for a fast-track referendum. + #[pallet::constant] + type FastTrackVotingPeriod: Get; + + /// Period in blocks where an external proposal may not be re-submitted after being vetoed. + #[pallet::constant] + type CooloffPeriod: Get; + + /// The maximum number of votes for an account. + /// + /// Also used to compute weight, an overly big value can + /// lead to extrinsic with very big weight: see `delegate` for instance. + #[pallet::constant] + type MaxVotes: Get; + + /// The maximum number of public proposals that can exist at any time. + #[pallet::constant] + type MaxProposals: Get; + + /// The maximum number of deposits a public proposal may have at any time. + #[pallet::constant] + type MaxDeposits: Get; + + /// The maximum number of items which can be blacklisted. + #[pallet::constant] + type MaxBlacklisted: Get; + /// Origin from which the next tabled referendum may be forced. This is a normal /// "super-majority-required" referendum. type ExternalOrigin: EnsureOrigin; @@ -311,16 +318,6 @@ pub mod pallet { /// origin. It retains its threshold method. type InstantOrigin: EnsureOrigin; - /// Indicator for whether an emergency origin is even allowed to happen. Some chains may - /// want to set this permanently to `false`, others may want to condition it on things such - /// as an upgrade having happened recently. - #[pallet::constant] - type InstantAllowed: Get; - - /// Minimum voting period allowed for a fast-track referendum. - #[pallet::constant] - type FastTrackVotingPeriod: Get; - /// Origin from which any referendum may be cancelled in an emergency. type CancellationOrigin: EnsureOrigin; @@ -331,79 +328,39 @@ pub mod pallet { type CancelProposalOrigin: EnsureOrigin; /// Origin for anyone able to veto proposals. - /// - /// # Warning - /// - /// The number of Vetoers for a proposal must be small, extrinsics are weighted according to - /// [MAX_VETOERS](./const.MAX_VETOERS.html) type VetoOrigin: EnsureOrigin; - /// Period in blocks where an external proposal may not be re-submitted after being vetoed. - #[pallet::constant] - type CooloffPeriod: Get; - - /// The amount of balance that must be deposited per byte of preimage stored. - #[pallet::constant] - type PreimageByteDeposit: Get>; - - /// An origin that can provide a preimage using operational extrinsics. - type OperationalPreimageOrigin: EnsureOrigin; - - /// Handler for the unbalanced reduction when slashing a preimage deposit. - type Slash: OnUnbalanced>; - - /// The Scheduler. - type Scheduler: ScheduleNamed; - /// Overarching type of all pallets origins. type PalletsOrigin: From>; - /// The maximum number of votes for an account. - /// - /// Also used to compute weight, an overly big value can - /// lead to extrinsic with very big weight: see `delegate` for instance. - #[pallet::constant] - type MaxVotes: Get; - - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; - - /// The maximum number of public proposals that can exist at any time. - #[pallet::constant] - type MaxProposals: Get; + /// Handler for the unbalanced reduction when slashing a preimage deposit. + type Slash: OnUnbalanced>; } - // TODO: Refactor public proposal queue into its own pallet. - // https://github.com/paritytech/substrate/issues/5322 /// The number of (public) proposals that have been made so far. #[pallet::storage] #[pallet::getter(fn public_prop_count)] pub type PublicPropCount = StorageValue<_, PropIndex, ValueQuery>; - /// The public proposals. Unsorted. The second item is the proposal's hash. + /// The public proposals. Unsorted. The second item is the proposal. #[pallet::storage] #[pallet::getter(fn public_props)] - pub type PublicProps = - StorageValue<_, Vec<(PropIndex, T::Hash, T::AccountId)>, ValueQuery>; + pub type PublicProps = StorageValue< + _, + BoundedVec<(PropIndex, BoundedCallOf, T::AccountId), T::MaxProposals>, + ValueQuery, + >; /// Those who have locked a deposit. /// /// TWOX-NOTE: Safe, as increasing integer keys are safe. #[pallet::storage] #[pallet::getter(fn deposit_of)] - pub type DepositOf = - StorageMap<_, Twox64Concat, PropIndex, (Vec, BalanceOf)>; - - /// Map of hashes to the proposal preimage, along with who registered it and their deposit. - /// The block number is the block at which it was deposited. - // TODO: Refactor Preimages into its own pallet. - // https://github.com/paritytech/substrate/issues/5322 - #[pallet::storage] - pub type Preimages = StorageMap< + pub type DepositOf = StorageMap< _, - Identity, - T::Hash, - PreimageStatus, T::BlockNumber>, + Twox64Concat, + PropIndex, + (BoundedVec, BalanceOf), >; /// The next free referendum index, aka the number of referenda started so far. @@ -426,7 +383,7 @@ pub mod pallet { _, Twox64Concat, ReferendumIndex, - ReferendumInfo>, + ReferendumInfo, BalanceOf>, >; /// All votes for a particular voter. We store the balance for the number of votes that we @@ -438,14 +395,12 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - Voting, T::AccountId, T::BlockNumber>, + Voting, T::AccountId, T::BlockNumber, T::MaxVotes>, ValueQuery, >; /// True if the last referendum tabled was submitted externally. False if it was a public /// proposal. - // TODO: There should be any number of tabling origins, not just public and "external" - // (council). https://github.com/paritytech/substrate/issues/5322 #[pallet::storage] pub type LastTabledWasExternal = StorageValue<_, bool, ValueQuery>; @@ -454,23 +409,21 @@ pub mod pallet { /// - `LastTabledWasExternal` is `false`; or /// - `PublicProps` is empty. #[pallet::storage] - pub type NextExternal = StorageValue<_, (T::Hash, VoteThreshold)>; + pub type NextExternal = StorageValue<_, (BoundedCallOf, VoteThreshold)>; /// A record of who vetoed what. Maps proposal hash to a possible existent block number /// (until when it may not be resubmitted) and who vetoed it. #[pallet::storage] - pub type Blacklist = - StorageMap<_, Identity, T::Hash, (T::BlockNumber, Vec)>; + pub type Blacklist = StorageMap< + _, + Identity, + H256, + (T::BlockNumber, BoundedVec), + >; /// Record of all proposals that have been subject to emergency cancellation. #[pallet::storage] - pub type Cancellations = StorageMap<_, Identity, T::Hash, bool, ValueQuery>; - - /// Storage version of the pallet. - /// - /// New networks start with last version. - #[pallet::storage] - pub(crate) type StorageVersion = StorageValue<_, Releases>; + pub type Cancellations = StorageMap<_, Identity, H256, bool, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig { @@ -490,7 +443,6 @@ pub mod pallet { PublicPropCount::::put(0 as PropIndex); ReferendumCount::::put(0 as ReferendumIndex); LowestUnbaked::::put(0 as ReferendumIndex); - StorageVersion::::put(Releases::V1); } } @@ -500,7 +452,7 @@ pub mod pallet { /// A motion has been proposed by a public account. Proposed { proposal_index: PropIndex, deposit: BalanceOf }, /// A public proposal has been tabled for referendum vote. - Tabled { proposal_index: PropIndex, deposit: BalanceOf, depositors: Vec }, + Tabled { proposal_index: PropIndex, deposit: BalanceOf }, /// An external proposal has been tabled. ExternalTabled, /// A referendum has begun. @@ -511,31 +463,14 @@ pub mod pallet { NotPassed { ref_index: ReferendumIndex }, /// A referendum has been cancelled. Cancelled { ref_index: ReferendumIndex }, - /// A proposal has been enacted. - Executed { ref_index: ReferendumIndex, result: DispatchResult }, /// An account has delegated their vote to another account. Delegated { who: T::AccountId, target: T::AccountId }, /// An account has cancelled a previous delegation operation. Undelegated { account: T::AccountId }, /// An external proposal has been vetoed. - Vetoed { who: T::AccountId, proposal_hash: T::Hash, until: T::BlockNumber }, - /// A proposal's preimage was noted, and the deposit taken. - PreimageNoted { proposal_hash: T::Hash, who: T::AccountId, deposit: BalanceOf }, - /// A proposal preimage was removed and used (the deposit was returned). - PreimageUsed { proposal_hash: T::Hash, provider: T::AccountId, deposit: BalanceOf }, - /// A proposal could not be executed because its preimage was invalid. - PreimageInvalid { proposal_hash: T::Hash, ref_index: ReferendumIndex }, - /// A proposal could not be executed because its preimage was missing. - PreimageMissing { proposal_hash: T::Hash, ref_index: ReferendumIndex }, - /// A registered preimage was removed and the deposit collected by the reaper. - PreimageReaped { - proposal_hash: T::Hash, - provider: T::AccountId, - deposit: BalanceOf, - reaper: T::AccountId, - }, + Vetoed { who: T::AccountId, proposal_hash: H256, until: T::BlockNumber }, /// A proposal_hash has been blacklisted permanently. - Blacklisted { proposal_hash: T::Hash }, + Blacklisted { proposal_hash: H256 }, /// An account has voted in a referendum Voted { voter: T::AccountId, ref_index: ReferendumIndex, vote: AccountVote> }, /// An account has secconded a proposal @@ -564,20 +499,8 @@ pub mod pallet { NoProposal, /// Identity may not veto a proposal twice AlreadyVetoed, - /// Preimage already noted - DuplicatePreimage, - /// Not imminent - NotImminent, - /// Too early - TooEarly, - /// Imminent - Imminent, - /// Preimage not found - PreimageMissing, /// Vote given for invalid referendum ReferendumInvalid, - /// Invalid preimage - PreimageInvalid, /// No proposals waiting NoneWaiting, /// The given account did not vote on the referendum. @@ -601,8 +524,8 @@ pub mod pallet { WrongUpperBound, /// Maximum number of votes reached. MaxVotesReached, - /// Maximum number of proposals reached. - TooManyProposals, + /// Maximum number of items reached. + TooMany, /// Voting period too low VotingPeriodLow, } @@ -626,12 +549,10 @@ pub mod pallet { /// - `value`: The amount of deposit (must be at least `MinimumDeposit`). /// /// Emits `Proposed`. - /// - /// Weight: `O(p)` #[pallet::weight(T::WeightInfo::propose())] pub fn propose( origin: OriginFor, - proposal_hash: T::Hash, + proposal: BoundedCallOf, #[pallet::compact] value: BalanceOf, ) -> DispatchResult { let who = ensure_signed(origin)?; @@ -640,7 +561,8 @@ pub mod pallet { let index = Self::public_prop_count(); let real_prop_count = PublicProps::::decode_len().unwrap_or(0) as u32; let max_proposals = T::MaxProposals::get(); - ensure!(real_prop_count < max_proposals, Error::::TooManyProposals); + ensure!(real_prop_count < max_proposals, Error::::TooMany); + let proposal_hash = proposal.hash(); if let Some((until, _)) = >::get(proposal_hash) { ensure!( @@ -650,10 +572,14 @@ pub mod pallet { } T::Currency::reserve(&who, value)?; + + let depositors = BoundedVec::<_, T::MaxDeposits>::truncate_from(vec![who.clone()]); + DepositOf::::insert(index, (depositors, value)); + PublicPropCount::::put(index + 1); - >::insert(index, (&[&who][..], value)); - >::append((index, proposal_hash, who)); + PublicProps::::try_append((index, proposal, who)) + .map_err(|_| Error::::TooMany)?; Self::deposit_event(Event::::Proposed { proposal_index: index, deposit: value }); Ok(()) @@ -665,23 +591,19 @@ pub mod pallet { /// must have funds to cover the deposit, equal to the original deposit. /// /// - `proposal`: The index of the proposal to second. - /// - `seconds_upper_bound`: an upper bound on the current number of seconds on this - /// proposal. Extrinsic is weighted according to this value with no refund. - /// - /// Weight: `O(S)` where S is the number of seconds a proposal already has. - #[pallet::weight(T::WeightInfo::second(*seconds_upper_bound))] + #[pallet::weight(T::WeightInfo::second())] pub fn second( origin: OriginFor, #[pallet::compact] proposal: PropIndex, - #[pallet::compact] seconds_upper_bound: u32, ) -> DispatchResult { let who = ensure_signed(origin)?; let seconds = Self::len_of_deposit_of(proposal).ok_or(Error::::ProposalMissing)?; - ensure!(seconds <= seconds_upper_bound, Error::::WrongUpperBound); + ensure!(seconds < T::MaxDeposits::get(), Error::::TooMany); let mut deposit = Self::deposit_of(proposal).ok_or(Error::::ProposalMissing)?; T::Currency::reserve(&who, deposit.1)?; - deposit.0.push(who.clone()); + let ok = deposit.0.try_push(who.clone()).is_ok(); + debug_assert!(ok, "`seconds` is below static limit; `try_insert` should succeed; qed"); >::insert(proposal, deposit); Self::deposit_event(Event::::Seconded { seconder: who, prop_index: proposal }); Ok(()) @@ -694,12 +616,7 @@ pub mod pallet { /// /// - `ref_index`: The index of the referendum to vote for. /// - `vote`: The vote configuration. - /// - /// Weight: `O(R)` where R is the number of referendums the voter has voted on. - #[pallet::weight( - T::WeightInfo::vote_new(T::MaxVotes::get()) - .max(T::WeightInfo::vote_existing(T::MaxVotes::get())) - )] + #[pallet::weight(T::WeightInfo::vote_new().max(T::WeightInfo::vote_existing()))] pub fn vote( origin: OriginFor, #[pallet::compact] ref_index: ReferendumIndex, @@ -725,7 +642,7 @@ pub mod pallet { T::CancellationOrigin::ensure_origin(origin)?; let status = Self::referendum_status(ref_index)?; - let h = status.proposal_hash; + let h = status.proposal.hash(); ensure!(!>::contains_key(h), Error::::AlreadyCanceled); >::insert(h, true); @@ -739,20 +656,20 @@ pub mod pallet { /// The dispatch origin of this call must be `ExternalOrigin`. /// /// - `proposal_hash`: The preimage hash of the proposal. - /// - /// Weight: `O(V)` with V number of vetoers in the blacklist of proposal. - /// Decoding vec of length V. Charged as maximum - #[pallet::weight(T::WeightInfo::external_propose(MAX_VETOERS))] - pub fn external_propose(origin: OriginFor, proposal_hash: T::Hash) -> DispatchResult { + #[pallet::weight(T::WeightInfo::external_propose())] + pub fn external_propose( + origin: OriginFor, + proposal: BoundedCallOf, + ) -> DispatchResult { T::ExternalOrigin::ensure_origin(origin)?; ensure!(!>::exists(), Error::::DuplicateProposal); - if let Some((until, _)) = >::get(proposal_hash) { + if let Some((until, _)) = >::get(proposal.hash()) { ensure!( >::block_number() >= until, Error::::ProposalBlacklisted, ); } - >::put((proposal_hash, VoteThreshold::SuperMajorityApprove)); + >::put((proposal, VoteThreshold::SuperMajorityApprove)); Ok(()) } @@ -770,10 +687,10 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::external_propose_majority())] pub fn external_propose_majority( origin: OriginFor, - proposal_hash: T::Hash, + proposal: BoundedCallOf, ) -> DispatchResult { T::ExternalMajorityOrigin::ensure_origin(origin)?; - >::put((proposal_hash, VoteThreshold::SimpleMajority)); + >::put((proposal, VoteThreshold::SimpleMajority)); Ok(()) } @@ -791,10 +708,10 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::external_propose_default())] pub fn external_propose_default( origin: OriginFor, - proposal_hash: T::Hash, + proposal: BoundedCallOf, ) -> DispatchResult { T::ExternalDefaultOrigin::ensure_origin(origin)?; - >::put((proposal_hash, VoteThreshold::SuperMajorityAgainst)); + >::put((proposal, VoteThreshold::SuperMajorityAgainst)); Ok(()) } @@ -805,7 +722,7 @@ pub mod pallet { /// The dispatch of this call must be `FastTrackOrigin`. /// /// - `proposal_hash`: The hash of the current external proposal. - /// - `voting_period`: The period that is allowed for voting on this proposal. + /// - `voting_period`: The period that is allowed for voting on this proposal. Increased to /// Must be always greater than zero. /// For `FastTrackOrigin` must be equal or greater than `FastTrackVotingPeriod`. /// - `delay`: The number of block after voting has ended in approval and this should be @@ -817,7 +734,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::fast_track())] pub fn fast_track( origin: OriginFor, - proposal_hash: T::Hash, + proposal_hash: H256, voting_period: T::BlockNumber, delay: T::BlockNumber, ) -> DispatchResult { @@ -836,20 +753,21 @@ pub mod pallet { T::InstantOrigin::ensure_origin(ensure_instant)?; ensure!(T::InstantAllowed::get(), Error::::InstantNotAllowed); } + ensure!(voting_period > T::BlockNumber::zero(), Error::::VotingPeriodLow); - let (e_proposal_hash, threshold) = + let (ext_proposal, threshold) = >::get().ok_or(Error::::ProposalMissing)?; ensure!( threshold != VoteThreshold::SuperMajorityApprove, Error::::NotSimpleMajority, ); - ensure!(proposal_hash == e_proposal_hash, Error::::InvalidHash); + ensure!(proposal_hash == ext_proposal.hash(), Error::::InvalidHash); >::kill(); let now = >::block_number(); Self::inject_referendum( now.saturating_add(voting_period), - proposal_hash, + ext_proposal, threshold, delay, ); @@ -865,22 +783,24 @@ pub mod pallet { /// Emits `Vetoed`. /// /// Weight: `O(V + log(V))` where V is number of `existing vetoers` - #[pallet::weight(T::WeightInfo::veto_external(MAX_VETOERS))] - pub fn veto_external(origin: OriginFor, proposal_hash: T::Hash) -> DispatchResult { + #[pallet::weight(T::WeightInfo::veto_external())] + pub fn veto_external(origin: OriginFor, proposal_hash: H256) -> DispatchResult { let who = T::VetoOrigin::ensure_origin(origin)?; - if let Some((e_proposal_hash, _)) = >::get() { - ensure!(proposal_hash == e_proposal_hash, Error::::ProposalMissing); + if let Some((ext_proposal, _)) = NextExternal::::get() { + ensure!(proposal_hash == ext_proposal.hash(), Error::::ProposalMissing); } else { return Err(Error::::NoProposal.into()) } let mut existing_vetoers = - >::get(&proposal_hash).map(|pair| pair.1).unwrap_or_else(Vec::new); + >::get(&proposal_hash).map(|pair| pair.1).unwrap_or_default(); let insert_position = existing_vetoers.binary_search(&who).err().ok_or(Error::::AlreadyVetoed)?; + existing_vetoers + .try_insert(insert_position, who.clone()) + .map_err(|_| Error::::TooMany)?; - existing_vetoers.insert(insert_position, who.clone()); let until = >::block_number().saturating_add(T::CooloffPeriod::get()); >::insert(&proposal_hash, (until, existing_vetoers)); @@ -907,21 +827,6 @@ pub mod pallet { Ok(()) } - /// Cancel a proposal queued for enactment. - /// - /// The dispatch origin of this call must be _Root_. - /// - /// - `which`: The index of the referendum to cancel. - /// - /// Weight: `O(D)` where `D` is the items in the dispatch queue. Weighted as `D = 10`. - #[pallet::weight((T::WeightInfo::cancel_queued(10), DispatchClass::Operational))] - pub fn cancel_queued(origin: OriginFor, which: ReferendumIndex) -> DispatchResult { - ensure_root(origin)?; - T::Scheduler::cancel_named((DEMOCRACY_ID, which).encode()) - .map_err(|_| Error::::ProposalMissing)?; - Ok(()) - } - /// Delegate the voting power (with some given conviction) of the sending account. /// /// The balance delegated is locked for as long as it's delegated, and thereafter for the @@ -991,135 +896,6 @@ pub mod pallet { Ok(()) } - /// Register the preimage for an upcoming proposal. This doesn't require the proposal to be - /// in the dispatch queue but does require a deposit, returned once enacted. - /// - /// The dispatch origin of this call must be _Signed_. - /// - /// - `encoded_proposal`: The preimage of a proposal. - /// - /// Emits `PreimageNoted`. - /// - /// Weight: `O(E)` with E size of `encoded_proposal` (protected by a required deposit). - #[pallet::weight(T::WeightInfo::note_preimage(encoded_proposal.len() as u32))] - pub fn note_preimage(origin: OriginFor, encoded_proposal: Vec) -> DispatchResult { - Self::note_preimage_inner(ensure_signed(origin)?, encoded_proposal)?; - Ok(()) - } - - /// Same as `note_preimage` but origin is `OperationalPreimageOrigin`. - #[pallet::weight(( - T::WeightInfo::note_preimage(encoded_proposal.len() as u32), - DispatchClass::Operational, - ))] - pub fn note_preimage_operational( - origin: OriginFor, - encoded_proposal: Vec, - ) -> DispatchResult { - let who = T::OperationalPreimageOrigin::ensure_origin(origin)?; - Self::note_preimage_inner(who, encoded_proposal)?; - Ok(()) - } - - /// Register the preimage for an upcoming proposal. This requires the proposal to be - /// in the dispatch queue. No deposit is needed. When this call is successful, i.e. - /// the preimage has not been uploaded before and matches some imminent proposal, - /// no fee is paid. - /// - /// The dispatch origin of this call must be _Signed_. - /// - /// - `encoded_proposal`: The preimage of a proposal. - /// - /// Emits `PreimageNoted`. - /// - /// Weight: `O(E)` with E size of `encoded_proposal` (protected by a required deposit). - #[pallet::weight(T::WeightInfo::note_imminent_preimage(encoded_proposal.len() as u32))] - pub fn note_imminent_preimage( - origin: OriginFor, - encoded_proposal: Vec, - ) -> DispatchResultWithPostInfo { - Self::note_imminent_preimage_inner(ensure_signed(origin)?, encoded_proposal)?; - // We check that this preimage was not uploaded before in - // `note_imminent_preimage_inner`, thus this call can only be successful once. If - // successful, user does not pay a fee. - Ok(Pays::No.into()) - } - - /// Same as `note_imminent_preimage` but origin is `OperationalPreimageOrigin`. - #[pallet::weight(( - T::WeightInfo::note_imminent_preimage(encoded_proposal.len() as u32), - DispatchClass::Operational, - ))] - pub fn note_imminent_preimage_operational( - origin: OriginFor, - encoded_proposal: Vec, - ) -> DispatchResultWithPostInfo { - let who = T::OperationalPreimageOrigin::ensure_origin(origin)?; - Self::note_imminent_preimage_inner(who, encoded_proposal)?; - // We check that this preimage was not uploaded before in - // `note_imminent_preimage_inner`, thus this call can only be successful once. If - // successful, user does not pay a fee. - Ok(Pays::No.into()) - } - - /// Remove an expired proposal preimage and collect the deposit. - /// - /// The dispatch origin of this call must be _Signed_. - /// - /// - `proposal_hash`: The preimage hash of a proposal. - /// - `proposal_length_upper_bound`: an upper bound on length of the proposal. Extrinsic is - /// weighted according to this value with no refund. - /// - /// This will only work after `VotingPeriod` blocks from the time that the preimage was - /// noted, if it's the same account doing it. If it's a different account, then it'll only - /// work an additional `EnactmentPeriod` later. - /// - /// Emits `PreimageReaped`. - /// - /// Weight: `O(D)` where D is length of proposal. - #[pallet::weight(T::WeightInfo::reap_preimage(*proposal_len_upper_bound))] - pub fn reap_preimage( - origin: OriginFor, - proposal_hash: T::Hash, - #[pallet::compact] proposal_len_upper_bound: u32, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - ensure!( - Self::pre_image_data_len(proposal_hash)? <= proposal_len_upper_bound, - Error::::WrongUpperBound, - ); - - let (provider, deposit, since, expiry) = >::get(&proposal_hash) - .and_then(|m| match m { - PreimageStatus::Available { provider, deposit, since, expiry, .. } => - Some((provider, deposit, since, expiry)), - _ => None, - }) - .ok_or(Error::::PreimageMissing)?; - - let now = >::block_number(); - let (voting, enactment) = (T::VotingPeriod::get(), T::EnactmentPeriod::get()); - let additional = if who == provider { Zero::zero() } else { enactment }; - ensure!( - now >= since.saturating_add(voting).saturating_add(additional), - Error::::TooEarly - ); - ensure!(expiry.map_or(true, |e| now > e), Error::::Imminent); - - let res = - T::Currency::repatriate_reserved(&provider, &who, deposit, BalanceStatus::Free); - debug_assert!(res.is_ok()); - >::remove(&proposal_hash); - Self::deposit_event(Event::::PreimageReaped { - proposal_hash, - provider, - deposit, - reaper: who, - }); - Ok(()) - } - /// Unlock tokens that have an expired lock. /// /// The dispatch origin of this call must be _Signed_. @@ -1127,10 +903,7 @@ pub mod pallet { /// - `target`: The account to remove the lock on. /// /// Weight: `O(R)` with R number of vote of target. - #[pallet::weight( - T::WeightInfo::unlock_set(T::MaxVotes::get()) - .max(T::WeightInfo::unlock_remove(T::MaxVotes::get())) - )] + #[pallet::weight(T::WeightInfo::unlock_set(T::MaxVotes::get()).max(T::WeightInfo::unlock_remove(T::MaxVotes::get())))] pub fn unlock(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { ensure_signed(origin)?; let target = T::Lookup::lookup(target)?; @@ -1199,17 +972,6 @@ pub mod pallet { Ok(()) } - /// Enact a proposal from a referendum. For now we just make the weight be the maximum. - #[pallet::weight(T::BlockWeights::get().max_block)] - pub fn enact_proposal( - origin: OriginFor, - proposal_hash: T::Hash, - index: ReferendumIndex, - ) -> DispatchResult { - ensure_root(origin)?; - Self::do_enact_proposal(proposal_hash, index) - } - /// Permanently place a proposal into the blacklist. This prevents it from ever being /// proposed again. /// @@ -1225,21 +987,21 @@ pub mod pallet { /// /// Weight: `O(p)` (though as this is an high-privilege dispatch, we assume it has a /// reasonable value). - #[pallet::weight((T::WeightInfo::blacklist(T::MaxProposals::get()), DispatchClass::Operational))] + #[pallet::weight((T::WeightInfo::blacklist(), DispatchClass::Operational))] pub fn blacklist( origin: OriginFor, - proposal_hash: T::Hash, + proposal_hash: H256, maybe_ref_index: Option, ) -> DispatchResult { T::BlacklistOrigin::ensure_origin(origin)?; // Insert the proposal into the blacklist. - let permanent = (T::BlockNumber::max_value(), Vec::::new()); + let permanent = (T::BlockNumber::max_value(), BoundedVec::::default()); Blacklist::::insert(&proposal_hash, permanent); // Remove the queued proposal, if it's there. PublicProps::::mutate(|props| { - if let Some(index) = props.iter().position(|p| p.1 == proposal_hash) { + if let Some(index) = props.iter().position(|p| p.1.hash() == proposal_hash) { let (prop_index, ..) = props.remove(index); if let Some((whos, amount)) = DepositOf::::take(prop_index) { for who in whos.into_iter() { @@ -1250,14 +1012,14 @@ pub mod pallet { }); // Remove the external queued referendum, if it's there. - if matches!(NextExternal::::get(), Some((h, ..)) if h == proposal_hash) { + if matches!(NextExternal::::get(), Some((p, ..)) if p.hash() == proposal_hash) { NextExternal::::kill(); } // Remove the referendum, if it's there. if let Some(ref_index) = maybe_ref_index { if let Ok(status) = Self::referendum_status(ref_index) { - if status.proposal_hash == proposal_hash { + if status.proposal.hash() == proposal_hash { Self::internal_cancel_referendum(ref_index); } } @@ -1274,7 +1036,7 @@ pub mod pallet { /// - `prop_index`: The index of the proposal to cancel. /// /// Weight: `O(p)` where `p = PublicProps::::decode_len()` - #[pallet::weight(T::WeightInfo::cancel_proposal(T::MaxProposals::get()))] + #[pallet::weight(T::WeightInfo::cancel_proposal())] pub fn cancel_proposal( origin: OriginFor, #[pallet::compact] prop_index: PropIndex, @@ -1294,6 +1056,25 @@ pub mod pallet { } } +pub trait EncodeInto: Encode { + fn encode_into + Default>(&self) -> T { + let mut t = T::default(); + self.using_encoded(|data| { + if data.len() <= t.as_mut().len() { + t.as_mut()[0..data.len()].copy_from_slice(data); + } else { + // encoded self is too big to fit into a T. hash it and use the first bytes of that + // instead. + let hash = sp_io::hashing::blake2_256(data); + let l = t.as_mut().len().min(hash.len()); + t.as_mut()[0..l].copy_from_slice(&hash[0..l]); + } + }); + t + } +} +impl EncodeInto for T {} + impl Pallet { // exposed immutables. @@ -1306,7 +1087,7 @@ impl Pallet { /// Get all referenda ready for tally at block `n`. pub fn maturing_referenda_at( n: T::BlockNumber, - ) -> Vec<(ReferendumIndex, ReferendumStatus>)> { + ) -> Vec<(ReferendumIndex, ReferendumStatus, BalanceOf>)> { let next = Self::lowest_unbaked(); let last = Self::referendum_count(); Self::maturing_referenda_at_inner(n, next..last) @@ -1315,7 +1096,7 @@ impl Pallet { fn maturing_referenda_at_inner( n: T::BlockNumber, range: core::ops::Range, - ) -> Vec<(ReferendumIndex, ReferendumStatus>)> { + ) -> Vec<(ReferendumIndex, ReferendumStatus, BalanceOf>)> { range .into_iter() .map(|i| (i, Self::referendum_info(i))) @@ -1331,13 +1112,13 @@ impl Pallet { /// Start a referendum. pub fn internal_start_referendum( - proposal_hash: T::Hash, + proposal: BoundedCallOf, threshold: VoteThreshold, delay: T::BlockNumber, ) -> ReferendumIndex { >::inject_referendum( >::block_number().saturating_add(T::VotingPeriod::get()), - proposal_hash, + proposal, threshold, delay, ) @@ -1353,8 +1134,8 @@ impl Pallet { /// Ok if the given referendum is active, Err otherwise fn ensure_ongoing( - r: ReferendumInfo>, - ) -> Result>, DispatchError> { + r: ReferendumInfo, BalanceOf>, + ) -> Result, BalanceOf>, DispatchError> { match r { ReferendumInfo::Ongoing(s) => Ok(s), _ => Err(Error::::ReferendumInvalid.into()), @@ -1363,7 +1144,7 @@ impl Pallet { fn referendum_status( ref_index: ReferendumIndex, - ) -> Result>, DispatchError> { + ) -> Result, BalanceOf>, DispatchError> { let info = ReferendumInfoOf::::get(ref_index).ok_or(Error::::ReferendumInvalid)?; Self::ensure_ongoing(info) } @@ -1388,11 +1169,9 @@ impl Pallet { votes[i].1 = vote; }, Err(i) => { - ensure!( - votes.len() as u32 <= T::MaxVotes::get(), - Error::::MaxVotesReached - ); - votes.insert(i, (ref_index, vote)); + votes + .try_insert(i, (ref_index, vote)) + .map_err(|_| Error::::MaxVotesReached)?; }, } Self::deposit_event(Event::::Voted { voter: who.clone(), ref_index, vote }); @@ -1606,14 +1385,14 @@ impl Pallet { /// Start a referendum fn inject_referendum( end: T::BlockNumber, - proposal_hash: T::Hash, + proposal: BoundedCallOf, threshold: VoteThreshold, delay: T::BlockNumber, ) -> ReferendumIndex { let ref_index = Self::referendum_count(); ReferendumCount::::put(ref_index + 1); let status = - ReferendumStatus { end, proposal_hash, threshold, delay, tally: Default::default() }; + ReferendumStatus { end, proposal, threshold, delay, tally: Default::default() }; let item = ReferendumInfo::Ongoing(status); >::insert(ref_index, item); Self::deposit_event(Event::::Started { ref_index, threshold }); @@ -1659,14 +1438,10 @@ impl Pallet { if let Some((depositors, deposit)) = >::take(prop_index) { // refund depositors - for d in &depositors { + for d in depositors.iter() { T::Currency::unreserve(d, deposit); } - Self::deposit_event(Event::::Tabled { - proposal_index: prop_index, - deposit, - depositors, - }); + Self::deposit_event(Event::::Tabled { proposal_index: prop_index, deposit }); Self::inject_referendum( now.saturating_add(T::VotingPeriod::get()), proposal, @@ -1680,71 +1455,35 @@ impl Pallet { } } - fn do_enact_proposal(proposal_hash: T::Hash, index: ReferendumIndex) -> DispatchResult { - let preimage = >::take(&proposal_hash); - if let Some(PreimageStatus::Available { data, provider, deposit, .. }) = preimage { - if let Ok(proposal) = T::Proposal::decode(&mut &data[..]) { - let err_amount = T::Currency::unreserve(&provider, deposit); - debug_assert!(err_amount.is_zero()); - Self::deposit_event(Event::::PreimageUsed { proposal_hash, provider, deposit }); - - let res = proposal - .dispatch(frame_system::RawOrigin::Root.into()) - .map(|_| ()) - .map_err(|e| e.error); - Self::deposit_event(Event::::Executed { ref_index: index, result: res }); - - Ok(()) - } else { - T::Slash::on_unbalanced(T::Currency::slash_reserved(&provider, deposit).0); - Self::deposit_event(Event::::PreimageInvalid { - proposal_hash, - ref_index: index, - }); - Err(Error::::PreimageInvalid.into()) - } - } else { - Self::deposit_event(Event::::PreimageMissing { proposal_hash, ref_index: index }); - Err(Error::::PreimageMissing.into()) - } - } - fn bake_referendum( now: T::BlockNumber, index: ReferendumIndex, - status: ReferendumStatus>, + status: ReferendumStatus, BalanceOf>, ) -> bool { let total_issuance = T::Currency::total_issuance(); let approved = status.threshold.approved(status.tally, total_issuance); if approved { Self::deposit_event(Event::::Passed { ref_index: index }); - if status.delay.is_zero() { - let _ = Self::do_enact_proposal(status.proposal_hash, index); - } else { - let when = now.saturating_add(status.delay); - // Note that we need the preimage now. - Preimages::::mutate_exists( - &status.proposal_hash, - |maybe_pre| match *maybe_pre { - Some(PreimageStatus::Available { ref mut expiry, .. }) => - *expiry = Some(when), - ref mut a => *a = Some(PreimageStatus::Missing(when)), - }, - ); - - if T::Scheduler::schedule_named( - (DEMOCRACY_ID, index).encode(), - DispatchTime::At(when), - None, - 63, - frame_system::RawOrigin::Root.into(), - Call::enact_proposal { proposal_hash: status.proposal_hash, index }.into(), - ) - .is_err() - { - frame_support::print("LOGIC ERROR: bake_referendum/schedule_named failed"); - } + // Actually `hold` the proposal now since we didn't hold it when it came in via the + // submit extrinsic and we now know that it will be needed. This will be reversed by + // Scheduler pallet once it is executed which assumes that we will already have placed + // a `hold` on it. + T::Preimages::hold(&status.proposal); + + // Earliest it can be scheduled for is next block. + let when = now.saturating_add(status.delay.max(One::one())); + if T::Scheduler::schedule_named( + (DEMOCRACY_ID, index).encode_into(), + DispatchTime::At(when), + None, + 63, + frame_system::RawOrigin::Root.into(), + status.proposal, + ) + .is_err() + { + frame_support::print("LOGIC ERROR: bake_referendum/schedule_named failed"); } } else { Self::deposit_event(Event::::NotPassed { ref_index: index }); @@ -1780,11 +1519,10 @@ impl Pallet { if Self::launch_next(now).is_ok() { weight = max_block_weight; } else { - weight = - weight.saturating_add(T::WeightInfo::on_initialize_base_with_launch_period(r)); + weight.saturating_accrue(T::WeightInfo::on_initialize_base_with_launch_period(r)); } } else { - weight = weight.saturating_add(T::WeightInfo::on_initialize_base(r)); + weight.saturating_accrue(T::WeightInfo::on_initialize_base(r)); } // tally up votes for any expiring referenda. @@ -1795,8 +1533,8 @@ impl Pallet { } // Notes: - // * We don't consider the lowest unbaked to be the last maturing in case some refendum have - // longer voting period than others. + // * We don't consider the lowest unbaked to be the last maturing in case some referenda + // have a longer voting period than others. // * The iteration here shouldn't trigger any storage read that are not in cache, due to // `maturing_referenda_at_inner` having already read them. // * We shouldn't iterate more than `LaunchPeriod/VotingPeriod + 1` times because the number @@ -1822,116 +1560,6 @@ impl Pallet { // `Compact`. decode_compact_u32_at(&>::hashed_key_for(proposal)) } - - /// Check that pre image exists and its value is variant `PreimageStatus::Missing`. - /// - /// This check is done without getting the complete value in the runtime to avoid copying a big - /// value in the runtime. - fn check_pre_image_is_missing(proposal_hash: T::Hash) -> DispatchResult { - // To decode the enum variant we only need the first byte. - let mut buf = [0u8; 1]; - let key = >::hashed_key_for(proposal_hash); - let bytes = sp_io::storage::read(&key, &mut buf, 0).ok_or(Error::::NotImminent)?; - // The value may be smaller that 1 byte. - let mut input = &buf[0..buf.len().min(bytes as usize)]; - - match input.read_byte() { - Ok(0) => Ok(()), // PreimageStatus::Missing is variant 0 - Ok(1) => Err(Error::::DuplicatePreimage.into()), - _ => { - sp_runtime::print("Failed to decode `PreimageStatus` variant"); - Err(Error::::NotImminent.into()) - }, - } - } - - /// Check that pre image exists, its value is variant `PreimageStatus::Available` and decode - /// the length of `data: Vec` fields. - /// - /// This check is done without getting the complete value in the runtime to avoid copying a big - /// value in the runtime. - /// - /// If the pre image is missing variant or doesn't exist then the error `PreimageMissing` is - /// returned. - fn pre_image_data_len(proposal_hash: T::Hash) -> Result { - // To decode the `data` field of Available variant we need: - // * one byte for the variant - // * at most 5 bytes to decode a `Compact` - let mut buf = [0u8; 6]; - let key = >::hashed_key_for(proposal_hash); - let bytes = sp_io::storage::read(&key, &mut buf, 0).ok_or(Error::::PreimageMissing)?; - // The value may be smaller that 6 bytes. - let mut input = &buf[0..buf.len().min(bytes as usize)]; - - match input.read_byte() { - Ok(1) => (), // Check that input exists and is second variant. - Ok(0) => return Err(Error::::PreimageMissing.into()), - _ => { - sp_runtime::print("Failed to decode `PreimageStatus` variant"); - return Err(Error::::PreimageMissing.into()) - }, - } - - // Decode the length of the vector. - let len = codec::Compact::::decode(&mut input) - .map_err(|_| { - sp_runtime::print("Failed to decode `PreimageStatus` variant"); - DispatchError::from(Error::::PreimageMissing) - })? - .0; - - Ok(len) - } - - // See `note_preimage` - fn note_preimage_inner(who: T::AccountId, encoded_proposal: Vec) -> DispatchResult { - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - ensure!(!>::contains_key(&proposal_hash), Error::::DuplicatePreimage); - - let deposit = >::from(encoded_proposal.len() as u32) - .saturating_mul(T::PreimageByteDeposit::get()); - T::Currency::reserve(&who, deposit)?; - - let now = >::block_number(); - let a = PreimageStatus::Available { - data: encoded_proposal, - provider: who.clone(), - deposit, - since: now, - expiry: None, - }; - >::insert(proposal_hash, a); - - Self::deposit_event(Event::::PreimageNoted { proposal_hash, who, deposit }); - - Ok(()) - } - - // See `note_imminent_preimage` - fn note_imminent_preimage_inner( - who: T::AccountId, - encoded_proposal: Vec, - ) -> DispatchResult { - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - Self::check_pre_image_is_missing(proposal_hash)?; - let status = Preimages::::get(&proposal_hash).ok_or(Error::::NotImminent)?; - let expiry = status.to_missing_expiry().ok_or(Error::::DuplicatePreimage)?; - - let now = >::block_number(); - let free = >::zero(); - let a = PreimageStatus::Available { - data: encoded_proposal, - provider: who.clone(), - deposit: Zero::zero(), - since: now, - expiry: Some(expiry), - }; - >::insert(proposal_hash, a); - - Self::deposit_event(Event::::PreimageNoted { proposal_hash, who, deposit: free }); - - Ok(()) - } } /// Decode `Compact` from the trie at given key. diff --git a/frame/democracy/src/migrations.rs b/frame/democracy/src/migrations.rs new file mode 100644 index 0000000000000..3ec249c1d981c --- /dev/null +++ b/frame/democracy/src/migrations.rs @@ -0,0 +1,236 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Storage migrations for the preimage pallet. + +use super::*; +use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade, BoundedVec}; +use sp_core::H256; + +/// The log target. +const TARGET: &'static str = "runtime::democracy::migration::v1"; + +/// The original data layout of the democracy pallet without a specific version number. +mod v0 { + use super::*; + + #[storage_alias] + pub type PublicProps = StorageValue< + Pallet, + Vec<(PropIndex, ::Hash, ::AccountId)>, + ValueQuery, + >; + + #[storage_alias] + pub type NextExternal = + StorageValue, (::Hash, VoteThreshold)>; + + #[cfg(feature = "try-runtime")] + #[storage_alias] + pub type ReferendumInfoOf = StorageMap< + Pallet, + frame_support::Twox64Concat, + ReferendumIndex, + ReferendumInfo< + ::BlockNumber, + ::Hash, + BalanceOf, + >, + >; +} + +pub mod v1 { + use super::*; + + /// Migration for translating bare `Hash`es into `Bounded`s. + pub struct Migration(sp_std::marker::PhantomData); + + impl> OnRuntimeUpgrade for Migration { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + assert_eq!(StorageVersion::get::>(), 0, "can only upgrade from version 0"); + + let props_count = v0::PublicProps::::get().len(); + log::info!(target: TARGET, "{} public proposals will be migrated.", props_count,); + ensure!(props_count <= T::MaxProposals::get() as usize, "too many proposals"); + + let referenda_count = v0::ReferendumInfoOf::::iter().count(); + log::info!(target: TARGET, "{} referenda will be migrated.", referenda_count); + + Ok((props_count as u32, referenda_count as u32).encode()) + } + + #[allow(deprecated)] + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + if StorageVersion::get::>() != 0 { + log::warn!( + target: TARGET, + "skipping on_runtime_upgrade: executed on wrong storage version.\ + Expected version 0" + ); + return weight + } + + ReferendumInfoOf::::translate( + |index, old: ReferendumInfo>| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + log::info!(target: TARGET, "migrating referendum #{:?}", &index); + Some(match old { + ReferendumInfo::Ongoing(status) => + ReferendumInfo::Ongoing(ReferendumStatus { + end: status.end, + proposal: Bounded::from_legacy_hash(status.proposal), + threshold: status.threshold, + delay: status.delay, + tally: status.tally, + }), + ReferendumInfo::Finished { approved, end } => + ReferendumInfo::Finished { approved, end }, + }) + }, + ); + + let props = v0::PublicProps::::take() + .into_iter() + .map(|(i, hash, a)| (i, Bounded::from_legacy_hash(hash), a)) + .collect::>(); + let bounded = BoundedVec::<_, T::MaxProposals>::truncate_from(props.clone()); + PublicProps::::put(bounded); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + if props.len() as u32 > T::MaxProposals::get() { + log::error!( + target: TARGET, + "truncated {} public proposals to {}; continuing", + props.len(), + T::MaxProposals::get() + ); + } + + if let Some((hash, threshold)) = v0::NextExternal::::take() { + log::info!(target: TARGET, "migrating next external proposal"); + NextExternal::::put((Bounded::from_legacy_hash(hash), threshold)); + } + + StorageVersion::new(1).put::>(); + + weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + assert_eq!(StorageVersion::get::>(), 1, "must upgrade"); + + let (old_props_count, old_ref_count): (u32, u32) = + Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + let new_props_count = crate::PublicProps::::get().len() as u32; + assert_eq!(new_props_count, old_props_count, "must migrate all public proposals"); + let new_ref_count = crate::ReferendumInfoOf::::iter().count() as u32; + assert_eq!(new_ref_count, old_ref_count, "must migrate all referenda"); + + log::info!( + target: TARGET, + "{} public proposals migrated, {} referenda migrated", + new_props_count, + new_ref_count, + ); + Ok(()) + } + } +} + +#[cfg(test)] +#[cfg(feature = "try-runtime")] +mod test { + use super::*; + use crate::{ + tests::{Test as T, *}, + types::*, + }; + use frame_support::bounded_vec; + + #[allow(deprecated)] + #[test] + fn migration_works() { + new_test_ext().execute_with(|| { + assert_eq!(StorageVersion::get::>(), 0); + // Insert some values into the v0 storage: + + // Case 1: Ongoing referendum + let hash = H256::repeat_byte(1); + let status = ReferendumStatus { + end: 1u32.into(), + proposal: hash.clone(), + threshold: VoteThreshold::SuperMajorityApprove, + delay: 1u32.into(), + tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() }, + }; + v0::ReferendumInfoOf::::insert(1u32, ReferendumInfo::Ongoing(status)); + + // Case 2: Finished referendum + v0::ReferendumInfoOf::::insert( + 2u32, + ReferendumInfo::Finished { approved: true, end: 123u32.into() }, + ); + + // Case 3: Public proposals + let hash2 = H256::repeat_byte(2); + v0::PublicProps::::put(vec![ + (3u32, hash.clone(), 123u64), + (4u32, hash2.clone(), 123u64), + ]); + + // Case 4: Next external + v0::NextExternal::::put((hash.clone(), VoteThreshold::SuperMajorityApprove)); + + // Migrate. + let state = v1::Migration::::pre_upgrade().unwrap(); + let _weight = v1::Migration::::on_runtime_upgrade(); + v1::Migration::::post_upgrade(state).unwrap(); + // Check that all values got migrated. + + // Case 1: Ongoing referendum + assert_eq!( + ReferendumInfoOf::::get(1u32), + Some(ReferendumInfo::Ongoing(ReferendumStatus { + end: 1u32.into(), + proposal: Bounded::from_legacy_hash(hash), + threshold: VoteThreshold::SuperMajorityApprove, + delay: 1u32.into(), + tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() }, + })) + ); + // Case 2: Finished referendum + assert_eq!( + ReferendumInfoOf::::get(2u32), + Some(ReferendumInfo::Finished { approved: true, end: 123u32.into() }) + ); + // Case 3: Public proposals + let props: BoundedVec<_, ::MaxProposals> = bounded_vec![ + (3u32, Bounded::from_legacy_hash(hash), 123u64), + (4u32, Bounded::from_legacy_hash(hash2), 123u64) + ]; + assert_eq!(PublicProps::::get(), props); + // Case 4: Next external + assert_eq!( + NextExternal::::get(), + Some((Bounded::from_legacy_hash(hash), VoteThreshold::SuperMajorityApprove)) + ); + }); + } +} diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 03d7216fd5aaa..eceb1a3400bba 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -19,11 +19,11 @@ use super::*; use crate as pallet_democracy; -use codec::Encode; use frame_support::{ assert_noop, assert_ok, ord_parameter_types, parameter_types, traits::{ - ConstU32, ConstU64, Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize, SortedMembers, + ConstU32, ConstU64, Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize, + SortedMembers, StorePreimage, }, weights::Weight, }; @@ -35,14 +35,12 @@ use sp_runtime::{ traits::{BadOrigin, BlakeTwo256, IdentityLookup}, Perbill, }; - mod cancellation; mod decoders; mod delegation; mod external_proposing; mod fast_tracking; mod lock_voting; -mod preimage; mod public_proposals; mod scheduling; mod voting; @@ -63,6 +61,7 @@ frame_support::construct_runtime!( { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Preimage: pallet_preimage, Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event}, Democracy: pallet_democracy::{Pallet, Call, Storage, Config, Event}, } @@ -78,13 +77,11 @@ impl Contains for BaseFilter { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max( - Weight::from_ref_time(1_000_000).set_proof_size(u64::MAX), - ); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::constants::WEIGHT_PER_SECOND.set_proof_size(u64::MAX)); } impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; - type BlockWeights = (); + type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; @@ -111,6 +108,16 @@ impl frame_system::Config for Test { parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; } + +impl pallet_preimage::Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type BaseDeposit = ConstU64<0>; + type ByteDeposit = ConstU64<0>; +} + impl pallet_scheduler::Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; @@ -118,11 +125,10 @@ impl pallet_scheduler::Config for Test { type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureRoot; - type MaxScheduledPerBlock = (); + type MaxScheduledPerBlock = ConstU32<100>; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; - type PreimageProvider = (); - type NoPreimagePostponement = (); + type Preimages = (); } impl pallet_balances::Config for Test { @@ -158,7 +164,6 @@ impl SortedMembers for OneToFive { } impl Config for Test { - type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type Currency = pallet_balances::Pallet; type EnactmentPeriod = ConstU64<2>; @@ -167,6 +172,8 @@ impl Config for Test { type VoteLockingPeriod = ConstU64<3>; type FastTrackVotingPeriod = ConstU64<2>; type MinimumDeposit = ConstU64<1>; + type MaxDeposits = ConstU32<1000>; + type MaxBlacklisted = ConstU32<5>; type ExternalOrigin = EnsureSignedBy; type ExternalMajorityOrigin = EnsureSignedBy; type ExternalDefaultOrigin = EnsureSignedBy; @@ -176,16 +183,15 @@ impl Config for Test { type CancelProposalOrigin = EnsureRoot; type VetoOrigin = EnsureSignedBy; type CooloffPeriod = ConstU64<2>; - type PreimageByteDeposit = PreimageByteDeposit; type Slash = (); type InstantOrigin = EnsureSignedBy; type InstantAllowed = InstantAllowed; type Scheduler = Scheduler; type MaxVotes = ConstU32<100>; - type OperationalPreimageOrigin = EnsureSignedBy; type PalletsOrigin = OriginCaller; type WeightInfo = (); type MaxProposals = ConstU32<100>; + type Preimages = Preimage; } pub fn new_test_ext() -> sp_io::TestExternalities { @@ -203,12 +209,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ext } -/// Execute the function two times, with `true` and with `false`. -pub fn new_test_ext_execute_with_cond(execute: impl FnOnce(bool) -> () + Clone) { - new_test_ext().execute_with(|| (execute.clone())(false)); - new_test_ext().execute_with(|| execute(true)); -} - #[test] fn params_should_work() { new_test_ext().execute_with(|| { @@ -218,44 +218,22 @@ fn params_should_work() { }); } -fn set_balance_proposal(value: u64) -> Vec { - RuntimeCall::Balances(pallet_balances::Call::set_balance { - who: 42, - new_free: value, - new_reserved: 0, - }) - .encode() +fn set_balance_proposal(value: u64) -> BoundedCallOf { + let inner = pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 }; + let outer = RuntimeCall::Balances(inner); + Preimage::bound(outer).unwrap() } #[test] fn set_balance_proposal_is_correctly_filtered_out() { for i in 0..10 { - let call = RuntimeCall::decode(&mut &set_balance_proposal(i)[..]).unwrap(); + let call = Preimage::realize(&set_balance_proposal(i)).unwrap().0; assert!(!::BaseCallFilter::contains(&call)); } } -fn set_balance_proposal_hash(value: u64) -> H256 { - BlakeTwo256::hash(&set_balance_proposal(value)[..]) -} - -fn set_balance_proposal_hash_and_note(value: u64) -> H256 { - let p = set_balance_proposal(value); - let h = BlakeTwo256::hash(&p[..]); - match Democracy::note_preimage(RuntimeOrigin::signed(6), p) { - Ok(_) => (), - Err(x) if x == Error::::DuplicatePreimage.into() => (), - Err(x) => panic!("{:?}", x), - } - h -} - fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult { - Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal_hash(value), delay) -} - -fn propose_set_balance_and_note(who: u64, value: u64, delay: u64) -> DispatchResult { - Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal_hash_and_note(value), delay) + Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal(value), delay) } fn next_block() { @@ -272,7 +250,7 @@ fn fast_forward_to(n: u64) { fn begin_referendum() -> ReferendumIndex { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); fast_forward_to(2); 0 } diff --git a/frame/democracy/src/tests/cancellation.rs b/frame/democracy/src/tests/cancellation.rs index b98e51aa3d4d1..ff046d612c026 100644 --- a/frame/democracy/src/tests/cancellation.rs +++ b/frame/democracy/src/tests/cancellation.rs @@ -24,7 +24,7 @@ fn cancel_referendum_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); @@ -42,37 +42,13 @@ fn cancel_referendum_should_work() { }); } -#[test] -fn cancel_queued_should_work() { - new_test_ext().execute_with(|| { - System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); - - // start of 2 => next referendum scheduled. - fast_forward_to(2); - - assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1))); - - fast_forward_to(4); - - assert!(pallet_scheduler::Agenda::::get(6)[0].is_some()); - - assert_noop!( - Democracy::cancel_queued(RuntimeOrigin::root(), 1), - Error::::ProposalMissing - ); - assert_ok!(Democracy::cancel_queued(RuntimeOrigin::root(), 0)); - assert!(pallet_scheduler::Agenda::::get(6)[0].is_none()); - }); -} - #[test] fn emergency_cancel_should_work() { new_test_ext().execute_with(|| { System::set_block_number(0); let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 2, ); @@ -86,7 +62,7 @@ fn emergency_cancel_should_work() { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 2, ); diff --git a/frame/democracy/src/tests/decoders.rs b/frame/democracy/src/tests/decoders.rs index 1fbb88060549b..1c8b9c3d980f9 100644 --- a/frame/democracy/src/tests/decoders.rs +++ b/frame/democracy/src/tests/decoders.rs @@ -18,7 +18,10 @@ //! The for various partial storage decoders use super::*; -use frame_support::storage::{migration, unhashed}; +use frame_support::{ + storage::{migration, unhashed}, + BoundedVec, +}; #[test] fn test_decode_compact_u32_at() { @@ -42,7 +45,8 @@ fn test_decode_compact_u32_at() { fn len_of_deposit_of() { new_test_ext().execute_with(|| { for l in vec![0, 1, 200, 1000] { - let value: (Vec, u64) = ((0..l).map(|_| Default::default()).collect(), 3u64); + let value: (BoundedVec, u64) = + ((0..l).map(|_| Default::default()).collect::>().try_into().unwrap(), 3u64); DepositOf::::insert(2, value); assert_eq!(Democracy::len_of_deposit_of(2), Some(l)); } @@ -51,35 +55,3 @@ fn len_of_deposit_of() { assert_eq!(Democracy::len_of_deposit_of(2), None); }) } - -#[test] -fn pre_image() { - new_test_ext().execute_with(|| { - let key = Default::default(); - let missing = PreimageStatus::Missing(0); - Preimages::::insert(key, missing); - assert_noop!(Democracy::pre_image_data_len(key), Error::::PreimageMissing); - assert_eq!(Democracy::check_pre_image_is_missing(key), Ok(())); - - Preimages::::remove(key); - assert_noop!(Democracy::pre_image_data_len(key), Error::::PreimageMissing); - assert_noop!(Democracy::check_pre_image_is_missing(key), Error::::NotImminent); - - for l in vec![0, 10, 100, 1000u32] { - let available = PreimageStatus::Available { - data: (0..l).map(|i| i as u8).collect(), - provider: 0, - deposit: 0, - since: 0, - expiry: None, - }; - - Preimages::::insert(key, available); - assert_eq!(Democracy::pre_image_data_len(key), Ok(l)); - assert_noop!( - Democracy::check_pre_image_is_missing(key), - Error::::DuplicatePreimage - ); - } - }) -} diff --git a/frame/democracy/src/tests/delegation.rs b/frame/democracy/src/tests/delegation.rs index 4c5ee79286055..bca7cb9524112 100644 --- a/frame/democracy/src/tests/delegation.rs +++ b/frame/democracy/src/tests/delegation.rs @@ -24,7 +24,7 @@ fn single_proposal_should_work_with_delegation() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); fast_forward_to(2); @@ -75,7 +75,7 @@ fn cyclic_delegation_should_unwind() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); fast_forward_to(2); @@ -100,7 +100,7 @@ fn single_proposal_should_work_with_vote_and_delegation() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); fast_forward_to(2); @@ -122,7 +122,7 @@ fn single_proposal_should_work_with_undelegation() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); // Delegate and undelegate vote. assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); diff --git a/frame/democracy/src/tests/external_proposing.rs b/frame/democracy/src/tests/external_proposing.rs index fda555b9c3459..4cfdd2aa74a3d 100644 --- a/frame/democracy/src/tests/external_proposing.rs +++ b/frame/democracy/src/tests/external_proposing.rs @@ -23,35 +23,29 @@ use super::*; fn veto_external_works() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(2), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); assert!(>::exists()); - let h = set_balance_proposal_hash_and_note(2); + let h = set_balance_proposal(2).hash(); assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h)); // cancelled. assert!(!>::exists()); // fails - same proposal can't be resubmitted. assert_noop!( - Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),), Error::::ProposalBlacklisted ); fast_forward_to(1); // fails as we're still in cooloff period. assert_noop!( - Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),), Error::::ProposalBlacklisted ); fast_forward_to(2); // works; as we're out of the cooloff period. - assert_ok!(Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(2), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); assert!(>::exists()); // 3 can't veto the same thing twice. @@ -68,14 +62,11 @@ fn veto_external_works() { fast_forward_to(3); // same proposal fails as we're still in cooloff assert_noop!( - Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2)), Error::::ProposalBlacklisted ); // different proposal works fine. - assert_ok!(Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(3), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(3),)); }); } @@ -84,22 +75,16 @@ fn external_blacklisting_should_work() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(2), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); - let hash = set_balance_proposal_hash(2); + let hash = set_balance_proposal(2).hash(); assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None)); fast_forward_to(2); assert_noop!(Democracy::referendum_status(0), Error::::ReferendumInvalid); assert_noop!( - Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(2), - ), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2)), Error::::ProposalBlacklisted, ); }); @@ -110,15 +95,12 @@ fn external_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!( - Democracy::external_propose(RuntimeOrigin::signed(1), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(1), set_balance_proposal(2),), BadOrigin, ); - assert_ok!(Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(2), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); assert_noop!( - Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(1),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(1),), Error::::DuplicateProposal ); fast_forward_to(2); @@ -126,7 +108,7 @@ fn external_referendum_works() { Democracy::referendum_status(0), Ok(ReferendumStatus { end: 4, - proposal_hash: set_balance_proposal_hash(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -140,22 +122,19 @@ fn external_majority_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!( - Democracy::external_propose_majority( - RuntimeOrigin::signed(1), - set_balance_proposal_hash(2) - ), + Democracy::external_propose_majority(RuntimeOrigin::signed(1), set_balance_proposal(2)), BadOrigin, ); assert_ok!(Democracy::external_propose_majority( RuntimeOrigin::signed(3), - set_balance_proposal_hash_and_note(2) + set_balance_proposal(2) )); fast_forward_to(2); assert_eq!( Democracy::referendum_status(0), Ok(ReferendumStatus { end: 4, - proposal_hash: set_balance_proposal_hash(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SimpleMajority, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -169,22 +148,19 @@ fn external_default_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!( - Democracy::external_propose_default( - RuntimeOrigin::signed(3), - set_balance_proposal_hash(2) - ), + Democracy::external_propose_default(RuntimeOrigin::signed(3), set_balance_proposal(2)), BadOrigin, ); assert_ok!(Democracy::external_propose_default( RuntimeOrigin::signed(1), - set_balance_proposal_hash_and_note(2) + set_balance_proposal(2) )); fast_forward_to(2); assert_eq!( Democracy::referendum_status(0), Ok(ReferendumStatus { end: 4, - proposal_hash: set_balance_proposal_hash(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SuperMajorityAgainst, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -197,11 +173,8 @@ fn external_default_referendum_works() { fn external_and_public_interleaving_works() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(1), - )); - assert_ok!(propose_set_balance_and_note(6, 2, 2)); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(1),)); + assert_ok!(propose_set_balance(6, 2, 2)); fast_forward_to(2); @@ -210,17 +183,14 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(0), Ok(ReferendumStatus { end: 4, - proposal_hash: set_balance_proposal_hash_and_note(1), + proposal: set_balance_proposal(1), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); // replenish external - assert_ok!(Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(3), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(3),)); fast_forward_to(4); @@ -229,7 +199,7 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(1), Ok(ReferendumStatus { end: 6, - proposal_hash: set_balance_proposal_hash_and_note(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -244,17 +214,14 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(2), Ok(ReferendumStatus { end: 8, - proposal_hash: set_balance_proposal_hash_and_note(3), + proposal: set_balance_proposal(3), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); // replenish external - assert_ok!(Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(5), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(5),)); fast_forward_to(8); @@ -263,18 +230,15 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(3), Ok(ReferendumStatus { end: 10, - proposal_hash: set_balance_proposal_hash_and_note(5), + proposal: set_balance_proposal(5), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); // replenish both - assert_ok!(Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(7), - )); - assert_ok!(propose_set_balance_and_note(6, 4, 2)); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(7),)); + assert_ok!(propose_set_balance(6, 4, 2)); fast_forward_to(10); @@ -283,16 +247,16 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(4), Ok(ReferendumStatus { end: 12, - proposal_hash: set_balance_proposal_hash_and_note(4), + proposal: set_balance_proposal(4), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); // replenish public again - assert_ok!(propose_set_balance_and_note(6, 6, 2)); + assert_ok!(propose_set_balance(6, 6, 2)); // cancel external - let h = set_balance_proposal_hash_and_note(7); + let h = set_balance_proposal(7).hash(); assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h)); fast_forward_to(12); @@ -302,7 +266,7 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(5), Ok(ReferendumStatus { end: 14, - proposal_hash: set_balance_proposal_hash_and_note(6), + proposal: set_balance_proposal(6), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, diff --git a/frame/democracy/src/tests/fast_tracking.rs b/frame/democracy/src/tests/fast_tracking.rs index 8fef985c8561c..97bb7a63908ab 100644 --- a/frame/democracy/src/tests/fast_tracking.rs +++ b/frame/democracy/src/tests/fast_tracking.rs @@ -23,14 +23,14 @@ use super::*; fn fast_track_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); - let h = set_balance_proposal_hash_and_note(2); + let h = set_balance_proposal(2).hash(); assert_noop!( Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2), Error::::ProposalMissing ); assert_ok!(Democracy::external_propose_majority( RuntimeOrigin::signed(3), - set_balance_proposal_hash_and_note(2) + set_balance_proposal(2) )); assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin); assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 2, 0)); @@ -38,7 +38,7 @@ fn fast_track_referendum_works() { Democracy::referendum_status(0), Ok(ReferendumStatus { end: 2, - proposal_hash: set_balance_proposal_hash_and_note(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SimpleMajority, delay: 0, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -51,14 +51,14 @@ fn fast_track_referendum_works() { fn instant_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); - let h = set_balance_proposal_hash_and_note(2); + let h = set_balance_proposal(2).hash(); assert_noop!( Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2), Error::::ProposalMissing ); assert_ok!(Democracy::external_propose_majority( RuntimeOrigin::signed(3), - set_balance_proposal_hash_and_note(2) + set_balance_proposal(2) )); assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin); assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 1, 0), BadOrigin); @@ -76,7 +76,7 @@ fn instant_referendum_works() { Democracy::referendum_status(0), Ok(ReferendumStatus { end: 1, - proposal_hash: set_balance_proposal_hash_and_note(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SimpleMajority, delay: 0, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -93,7 +93,7 @@ fn instant_next_block_referendum_backed() { let majority_origin_id = 3; let instant_origin_id = 6; let voting_period = 1; - let proposal_hash = set_balance_proposal_hash_and_note(2); + let proposal = set_balance_proposal(2); let delay = 2; // has no effect on test // init @@ -103,13 +103,13 @@ fn instant_next_block_referendum_backed() { // propose with majority origin assert_ok!(Democracy::external_propose_majority( RuntimeOrigin::signed(majority_origin_id), - proposal_hash + proposal.clone() )); // fast track with instant origin and voting period pointing to the next block assert_ok!(Democracy::fast_track( RuntimeOrigin::signed(instant_origin_id), - proposal_hash, + proposal.hash(), voting_period, delay )); @@ -119,7 +119,7 @@ fn instant_next_block_referendum_backed() { Democracy::referendum_status(0), Ok(ReferendumStatus { end: start_block_number + voting_period, - proposal_hash, + proposal, threshold: VoteThreshold::SimpleMajority, delay, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -143,11 +143,8 @@ fn instant_next_block_referendum_backed() { fn fast_track_referendum_fails_when_no_simple_majority() { new_test_ext().execute_with(|| { System::set_block_number(0); - let h = set_balance_proposal_hash_and_note(2); - assert_ok!(Democracy::external_propose( - RuntimeOrigin::signed(2), - set_balance_proposal_hash_and_note(2) - )); + let h = set_balance_proposal(2).hash(); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2))); assert_noop!( Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2), Error::::NotSimpleMajority diff --git a/frame/democracy/src/tests/lock_voting.rs b/frame/democracy/src/tests/lock_voting.rs index de1137f03fd38..540198ecf33a1 100644 --- a/frame/democracy/src/tests/lock_voting.rs +++ b/frame/democracy/src/tests/lock_voting.rs @@ -43,7 +43,7 @@ fn lock_voting_should_work() { System::set_block_number(0); let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); @@ -59,7 +59,7 @@ fn lock_voting_should_work() { assert_eq!(Balances::locks(i), vec![the_lock(i * 10)]); } - fast_forward_to(2); + fast_forward_to(3); // Referendum passed; 1 and 5 didn't get their way and can now reap and unlock. assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(1), r)); @@ -126,13 +126,13 @@ fn no_locks_without_conviction_should_work() { System::set_block_number(0); let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(0, 10))); - fast_forward_to(2); + fast_forward_to(3); assert_eq!(Balances::free_balance(42), 2); assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(2), 1, r)); @@ -146,7 +146,7 @@ fn lock_voting_should_work_with_delegation() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); @@ -167,28 +167,16 @@ fn lock_voting_should_work_with_delegation() { fn setup_three_referenda() -> (u32, u32, u32) { System::set_block_number(0); - let r1 = Democracy::inject_referendum( - 2, - set_balance_proposal_hash_and_note(2), - VoteThreshold::SimpleMajority, - 0, - ); + let r1 = + Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0); assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r1, aye(4, 10))); - let r2 = Democracy::inject_referendum( - 2, - set_balance_proposal_hash_and_note(2), - VoteThreshold::SimpleMajority, - 0, - ); + let r2 = + Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0); assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r2, aye(3, 20))); - let r3 = Democracy::inject_referendum( - 2, - set_balance_proposal_hash_and_note(2), - VoteThreshold::SimpleMajority, - 0, - ); + let r3 = + Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0); assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r3, aye(2, 50))); fast_forward_to(2); @@ -306,7 +294,7 @@ fn locks_should_persist_from_voting_to_delegation() { System::set_block_number(0); let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SimpleMajority, 0, ); diff --git a/frame/democracy/src/tests/preimage.rs b/frame/democracy/src/tests/preimage.rs deleted file mode 100644 index 39536eab8009b..0000000000000 --- a/frame/democracy/src/tests/preimage.rs +++ /dev/null @@ -1,237 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The preimage tests. - -use super::*; - -#[test] -fn missing_preimage_should_fail() { - new_test_ext().execute_with(|| { - let r = Democracy::inject_referendum( - 2, - set_balance_proposal_hash(2), - VoteThreshold::SuperMajorityApprove, - 0, - ); - assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); - - next_block(); - next_block(); - - assert_eq!(Balances::free_balance(42), 0); - }); -} - -#[test] -fn preimage_deposit_should_be_required_and_returned() { - new_test_ext_execute_with_cond(|operational| { - // fee of 100 is too much. - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 100); - assert_noop!( - if operational { - Democracy::note_preimage_operational(RuntimeOrigin::signed(6), vec![0; 500]) - } else { - Democracy::note_preimage(RuntimeOrigin::signed(6), vec![0; 500]) - }, - BalancesError::::InsufficientBalance, - ); - // fee of 1 is reasonable. - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); - let r = Democracy::inject_referendum( - 2, - set_balance_proposal_hash_and_note(2), - VoteThreshold::SuperMajorityApprove, - 0, - ); - assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); - - assert_eq!(Balances::reserved_balance(6), 12); - - next_block(); - next_block(); - - assert_eq!(Balances::reserved_balance(6), 0); - assert_eq!(Balances::free_balance(6), 60); - assert_eq!(Balances::free_balance(42), 2); - }); -} - -#[test] -fn preimage_deposit_should_be_reapable_earlier_by_owner() { - new_test_ext_execute_with_cond(|operational| { - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); - assert_ok!(if operational { - Democracy::note_preimage_operational(RuntimeOrigin::signed(6), set_balance_proposal(2)) - } else { - Democracy::note_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2)) - }); - - assert_eq!(Balances::reserved_balance(6), 12); - - next_block(); - assert_noop!( - Democracy::reap_preimage( - RuntimeOrigin::signed(6), - set_balance_proposal_hash(2), - u32::MAX - ), - Error::::TooEarly - ); - next_block(); - assert_ok!(Democracy::reap_preimage( - RuntimeOrigin::signed(6), - set_balance_proposal_hash(2), - u32::MAX - )); - - assert_eq!(Balances::free_balance(6), 60); - assert_eq!(Balances::reserved_balance(6), 0); - }); -} - -#[test] -fn preimage_deposit_should_be_reapable() { - new_test_ext_execute_with_cond(|operational| { - assert_noop!( - Democracy::reap_preimage( - RuntimeOrigin::signed(5), - set_balance_proposal_hash(2), - u32::MAX - ), - Error::::PreimageMissing - ); - - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); - assert_ok!(if operational { - Democracy::note_preimage_operational(RuntimeOrigin::signed(6), set_balance_proposal(2)) - } else { - Democracy::note_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2)) - }); - assert_eq!(Balances::reserved_balance(6), 12); - - next_block(); - next_block(); - next_block(); - assert_noop!( - Democracy::reap_preimage( - RuntimeOrigin::signed(5), - set_balance_proposal_hash(2), - u32::MAX - ), - Error::::TooEarly - ); - - next_block(); - assert_ok!(Democracy::reap_preimage( - RuntimeOrigin::signed(5), - set_balance_proposal_hash(2), - u32::MAX - )); - assert_eq!(Balances::reserved_balance(6), 0); - assert_eq!(Balances::free_balance(6), 48); - assert_eq!(Balances::free_balance(5), 62); - }); -} - -#[test] -fn noting_imminent_preimage_for_free_should_work() { - new_test_ext_execute_with_cond(|operational| { - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); - - let r = Democracy::inject_referendum( - 2, - set_balance_proposal_hash(2), - VoteThreshold::SuperMajorityApprove, - 1, - ); - assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); - - assert_noop!( - if operational { - Democracy::note_imminent_preimage_operational( - RuntimeOrigin::signed(6), - set_balance_proposal(2), - ) - } else { - Democracy::note_imminent_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2)) - }, - Error::::NotImminent - ); - - next_block(); - - // Now we're in the dispatch queue it's all good. - assert_ok!(Democracy::note_imminent_preimage( - RuntimeOrigin::signed(6), - set_balance_proposal(2) - )); - - next_block(); - - assert_eq!(Balances::free_balance(42), 2); - }); -} - -#[test] -fn reaping_imminent_preimage_should_fail() { - new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash_and_note(2); - let r = Democracy::inject_referendum(3, h, VoteThreshold::SuperMajorityApprove, 1); - assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); - next_block(); - next_block(); - assert_noop!( - Democracy::reap_preimage(RuntimeOrigin::signed(6), h, u32::MAX), - Error::::Imminent - ); - }); -} - -#[test] -fn note_imminent_preimage_can_only_be_successful_once() { - new_test_ext().execute_with(|| { - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); - - let r = Democracy::inject_referendum( - 2, - set_balance_proposal_hash(2), - VoteThreshold::SuperMajorityApprove, - 1, - ); - assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); - next_block(); - - // First time works - assert_ok!(Democracy::note_imminent_preimage( - RuntimeOrigin::signed(6), - set_balance_proposal(2) - )); - - // Second time fails - assert_noop!( - Democracy::note_imminent_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2)), - Error::::DuplicatePreimage - ); - - // Fails from any user - assert_noop!( - Democracy::note_imminent_preimage(RuntimeOrigin::signed(5), set_balance_proposal(2)), - Error::::DuplicatePreimage - ); - }); -} diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs index c52533e46ccc5..f48824dc95c5d 100644 --- a/frame/democracy/src/tests/public_proposals.rs +++ b/frame/democracy/src/tests/public_proposals.rs @@ -22,9 +22,9 @@ use super::*; #[test] fn backing_for_should_work() { new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(1, 2, 2)); - assert_ok!(propose_set_balance_and_note(1, 4, 4)); - assert_ok!(propose_set_balance_and_note(1, 3, 3)); + assert_ok!(propose_set_balance(1, 2, 2)); + assert_ok!(propose_set_balance(1, 4, 4)); + assert_ok!(propose_set_balance(1, 3, 3)); assert_eq!(Democracy::backing_for(0), Some(2)); assert_eq!(Democracy::backing_for(1), Some(4)); assert_eq!(Democracy::backing_for(2), Some(3)); @@ -34,11 +34,11 @@ fn backing_for_should_work() { #[test] fn deposit_for_proposals_should_be_taken() { new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(1, 2, 5)); - assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0, u32::MAX)); - assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); + assert_ok!(propose_set_balance(1, 2, 5)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); assert_eq!(Balances::free_balance(1), 5); assert_eq!(Balances::free_balance(2), 15); assert_eq!(Balances::free_balance(5), 35); @@ -48,11 +48,11 @@ fn deposit_for_proposals_should_be_taken() { #[test] fn deposit_for_proposals_should_be_returned() { new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(1, 2, 5)); - assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0, u32::MAX)); - assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX)); + assert_ok!(propose_set_balance(1, 2, 5)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); fast_forward_to(3); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 20); @@ -77,30 +77,19 @@ fn poor_proposer_should_not_work() { #[test] fn poor_seconder_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(2, 2, 11)); + assert_ok!(propose_set_balance(2, 2, 11)); assert_noop!( - Democracy::second(RuntimeOrigin::signed(1), 0, u32::MAX), + Democracy::second(RuntimeOrigin::signed(1), 0), BalancesError::::InsufficientBalance ); }); } -#[test] -fn invalid_seconds_upper_bound_should_not_work() { - new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(1, 2, 5)); - assert_noop!( - Democracy::second(RuntimeOrigin::signed(2), 0, 0), - Error::::WrongUpperBound - ); - }); -} - #[test] fn cancel_proposal_should_work() { new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(1, 2, 2)); - assert_ok!(propose_set_balance_and_note(1, 4, 4)); + assert_ok!(propose_set_balance(1, 2, 2)); + assert_ok!(propose_set_balance(1, 4, 4)); assert_noop!(Democracy::cancel_proposal(RuntimeOrigin::signed(1), 0), BadOrigin); assert_ok!(Democracy::cancel_proposal(RuntimeOrigin::root(), 0)); System::assert_last_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); @@ -113,10 +102,10 @@ fn cancel_proposal_should_work() { fn blacklisting_should_work() { new_test_ext().execute_with(|| { System::set_block_number(0); - let hash = set_balance_proposal_hash(2); + let hash = set_balance_proposal(2).hash(); - assert_ok!(propose_set_balance_and_note(1, 2, 2)); - assert_ok!(propose_set_balance_and_note(1, 4, 4)); + assert_ok!(propose_set_balance(1, 2, 2)); + assert_ok!(propose_set_balance(1, 4, 4)); assert_noop!(Democracy::blacklist(RuntimeOrigin::signed(1), hash, None), BadOrigin); assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None)); @@ -124,11 +113,11 @@ fn blacklisting_should_work() { assert_eq!(Democracy::backing_for(0), None); assert_eq!(Democracy::backing_for(1), Some(4)); - assert_noop!(propose_set_balance_and_note(1, 2, 2), Error::::ProposalBlacklisted); + assert_noop!(propose_set_balance(1, 2, 2), Error::::ProposalBlacklisted); fast_forward_to(2); - let hash = set_balance_proposal_hash(4); + let hash = set_balance_proposal(4).hash(); assert_ok!(Democracy::referendum_status(0)); assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, Some(0))); assert_noop!(Democracy::referendum_status(0), Error::::ReferendumInvalid); @@ -139,9 +128,9 @@ fn blacklisting_should_work() { fn runners_up_should_come_after() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 2)); - assert_ok!(propose_set_balance_and_note(1, 4, 4)); - assert_ok!(propose_set_balance_and_note(1, 3, 3)); + assert_ok!(propose_set_balance(1, 2, 2)); + assert_ok!(propose_set_balance(1, 4, 4)); + assert_ok!(propose_set_balance(1, 3, 3)); fast_forward_to(2); assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1))); fast_forward_to(4); diff --git a/frame/democracy/src/tests/scheduling.rs b/frame/democracy/src/tests/scheduling.rs index 4b5fe8dd9c1c3..5e133f38945d6 100644 --- a/frame/democracy/src/tests/scheduling.rs +++ b/frame/democracy/src/tests/scheduling.rs @@ -24,7 +24,7 @@ fn simple_passing_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); @@ -43,7 +43,7 @@ fn simple_failing_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); @@ -62,13 +62,13 @@ fn ooo_inject_referendums_should_work() { new_test_ext().execute_with(|| { let r1 = Democracy::inject_referendum( 3, - set_balance_proposal_hash_and_note(3), + set_balance_proposal(3), VoteThreshold::SuperMajorityApprove, 0, ); let r2 = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); @@ -77,11 +77,13 @@ fn ooo_inject_referendums_should_work() { assert_eq!(tally(r2), Tally { ayes: 1, nays: 0, turnout: 10 }); next_block(); - assert_eq!(Balances::free_balance(42), 2); assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r1, aye(1))); assert_eq!(tally(r1), Tally { ayes: 1, nays: 0, turnout: 10 }); + next_block(); + assert_eq!(Balances::free_balance(42), 2); + next_block(); assert_eq!(Balances::free_balance(42), 3); }); @@ -92,7 +94,7 @@ fn delayed_enactment_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 1, ); @@ -118,19 +120,19 @@ fn lowest_unbaked_should_be_sensible() { new_test_ext().execute_with(|| { let r1 = Democracy::inject_referendum( 3, - set_balance_proposal_hash_and_note(1), + set_balance_proposal(1), VoteThreshold::SuperMajorityApprove, 0, ); let r2 = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); let r3 = Democracy::inject_referendum( 10, - set_balance_proposal_hash_and_note(3), + set_balance_proposal(3), VoteThreshold::SuperMajorityApprove, 0, ); @@ -141,16 +143,19 @@ fn lowest_unbaked_should_be_sensible() { assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); - - // r2 is approved - assert_eq!(Balances::free_balance(42), 2); + // r2 ends with approval assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); - - // r1 is approved - assert_eq!(Balances::free_balance(42), 1); + // r1 ends with approval assert_eq!(Democracy::lowest_unbaked(), 3); assert_eq!(Democracy::lowest_unbaked(), Democracy::referendum_count()); + + // r2 is executed + assert_eq!(Balances::free_balance(42), 2); + + next_block(); + // r1 is executed + assert_eq!(Balances::free_balance(42), 1); }); } diff --git a/frame/democracy/src/tests/voting.rs b/frame/democracy/src/tests/voting.rs index 59d0cd6bc50ef..482cd430e0e7f 100644 --- a/frame/democracy/src/tests/voting.rs +++ b/frame/democracy/src/tests/voting.rs @@ -63,7 +63,7 @@ fn split_vote_cancellation_should_work() { fn single_proposal_should_work() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); let r = 0; assert!(Democracy::referendum_info(r).is_none()); @@ -76,7 +76,7 @@ fn single_proposal_should_work() { Democracy::referendum_status(0), Ok(ReferendumStatus { end: 4, - proposal_hash: set_balance_proposal_hash_and_note(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 1, nays: 0, turnout: 10 }, @@ -106,7 +106,7 @@ fn controversial_voting_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); @@ -132,7 +132,7 @@ fn controversial_low_turnout_voting_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); @@ -156,7 +156,7 @@ fn passing_low_turnout_voting_should_work() { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); diff --git a/frame/democracy/src/types.rs b/frame/democracy/src/types.rs index 52ab8a40eb3e3..4b7f1a0fac45c 100644 --- a/frame/democracy/src/types.rs +++ b/frame/democracy/src/types.rs @@ -18,7 +18,7 @@ //! Miscellaneous additional datatypes. use crate::{AccountVote, Conviction, Vote, VoteThreshold}; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Saturating, Zero}, @@ -26,7 +26,7 @@ use sp_runtime::{ }; /// Info regarding an ongoing referendum. -#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, MaxEncodedLen, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct Tally { /// The number of aye votes, expressed in terms of post-conviction lock-vote. pub ayes: Balance, @@ -37,7 +37,9 @@ pub struct Tally { } /// Amount of votes and capital placed in delegation for an account. -#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive( + Encode, MaxEncodedLen, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, +)] pub struct Delegations { /// The number of votes (this is post-conviction). pub votes: Balance, @@ -160,12 +162,12 @@ impl< } /// Info regarding an ongoing referendum. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub struct ReferendumStatus { +#[derive(Encode, MaxEncodedLen, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub struct ReferendumStatus { /// When voting on this referendum will end. pub end: BlockNumber, - /// The hash of the proposal being voted on. - pub proposal_hash: Hash, + /// The proposal being voted on. + pub proposal: Proposal, /// The thresholding mechanism to determine whether it passed. pub threshold: VoteThreshold, /// The delay (in blocks) to wait after a successful referendum before deploying. @@ -175,23 +177,23 @@ pub struct ReferendumStatus { } /// Info regarding a referendum, present or past. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub enum ReferendumInfo { +#[derive(Encode, MaxEncodedLen, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub enum ReferendumInfo { /// Referendum is happening, the arg is the block number at which it will end. - Ongoing(ReferendumStatus), + Ongoing(ReferendumStatus), /// Referendum finished at `end`, and has been `approved` or rejected. Finished { approved: bool, end: BlockNumber }, } -impl ReferendumInfo { +impl ReferendumInfo { /// Create a new instance. pub fn new( end: BlockNumber, - proposal_hash: Hash, + proposal: Proposal, threshold: VoteThreshold, delay: BlockNumber, ) -> Self { - let s = ReferendumStatus { end, proposal_hash, threshold, delay, tally: Tally::default() }; + let s = ReferendumStatus { end, proposal, threshold, delay, tally: Tally::default() }; ReferendumInfo::Ongoing(s) } } diff --git a/frame/democracy/src/vote.rs b/frame/democracy/src/vote.rs index c74623d4dfeb8..122f54febd8cf 100644 --- a/frame/democracy/src/vote.rs +++ b/frame/democracy/src/vote.rs @@ -18,11 +18,12 @@ //! The vote datatype. use crate::{Conviction, Delegations, ReferendumIndex}; -use codec::{Decode, Encode, EncodeLike, Input, Output}; +use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen, Output}; +use frame_support::traits::Get; use scale_info::TypeInfo; use sp_runtime::{ traits::{Saturating, Zero}, - RuntimeDebug, + BoundedVec, RuntimeDebug, }; use sp_std::prelude::*; @@ -39,6 +40,12 @@ impl Encode for Vote { } } +impl MaxEncodedLen for Vote { + fn max_encoded_len() -> usize { + 1 + } +} + impl EncodeLike for Vote {} impl Decode for Vote { @@ -66,7 +73,7 @@ impl TypeInfo for Vote { } /// A vote for a referendum of a particular account. -#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, MaxEncodedLen, Decode, Copy, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] pub enum AccountVote { /// A standard vote, one-way (approve or reject) with a given amount of conviction. Standard { vote: Vote, balance: Balance }, @@ -107,7 +114,18 @@ impl AccountVote { /// A "prior" lock, i.e. a lock for some now-forgotten reason. #[derive( - Encode, Decode, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo, + Encode, + MaxEncodedLen, + Decode, + Default, + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + RuntimeDebug, + TypeInfo, )] pub struct PriorLock(BlockNumber, Balance); @@ -131,13 +149,15 @@ impl PriorLock { +#[derive(Clone, Encode, Decode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] +#[codec(mel_bound(skip_type_params(MaxVotes)))] +#[scale_info(skip_type_params(MaxVotes))] +pub enum Voting> { /// The account is voting directly. `delegations` is the total amount of post-conviction voting /// weight that it controls from those that have delegated to it. Direct { /// The current votes of the account. - votes: Vec<(ReferendumIndex, AccountVote)>, + votes: BoundedVec<(ReferendumIndex, AccountVote), MaxVotes>, /// The total amount of delegations that this account has received. delegations: Delegations, /// Any pre-existing locks from past voting/delegating activity. @@ -155,20 +175,24 @@ pub enum Voting { }, } -impl Default - for Voting +impl> Default + for Voting { fn default() -> Self { Voting::Direct { - votes: Vec::new(), + votes: Default::default(), delegations: Default::default(), prior: PriorLock(Zero::zero(), Default::default()), } } } -impl - Voting +impl< + Balance: Saturating + Ord + Zero + Copy, + BlockNumber: Ord + Copy + Zero, + AccountId, + MaxVotes: Get, + > Voting { pub fn rejig(&mut self, now: BlockNumber) { match self { diff --git a/frame/democracy/src/vote_threshold.rs b/frame/democracy/src/vote_threshold.rs index 443d6b1166198..e8ef91def9820 100644 --- a/frame/democracy/src/vote_threshold.rs +++ b/frame/democracy/src/vote_threshold.rs @@ -18,7 +18,7 @@ //! Voting thresholds. use crate::Tally; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -26,7 +26,9 @@ use sp_runtime::traits::{IntegerSquareRoot, Zero}; use sp_std::ops::{Add, Div, Mul, Rem}; /// A means of determining if a vote is past pass threshold. -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, sp_runtime::RuntimeDebug, TypeInfo)] +#[derive( + Clone, Copy, PartialEq, Eq, Encode, MaxEncodedLen, Decode, sp_runtime::RuntimeDebug, TypeInfo, +)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum VoteThreshold { /// A supermajority of approvals is needed to pass this vote. diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 272921ed3a15d..0a3b717938022 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,22 +18,24 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_democracy // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --pallet=pallet_democracy +// --chain=dev // --output=./frame/democracy/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -45,27 +47,23 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_democracy. pub trait WeightInfo { fn propose() -> Weight; - fn second(s: u32, ) -> Weight; - fn vote_new(r: u32, ) -> Weight; - fn vote_existing(r: u32, ) -> Weight; + fn second() -> Weight; + fn vote_new() -> Weight; + fn vote_existing() -> Weight; fn emergency_cancel() -> Weight; - fn blacklist(p: u32, ) -> Weight; - fn external_propose(v: u32, ) -> Weight; + fn blacklist() -> Weight; + fn external_propose() -> Weight; fn external_propose_majority() -> Weight; fn external_propose_default() -> Weight; fn fast_track() -> Weight; - fn veto_external(v: u32, ) -> Weight; - fn cancel_proposal(p: u32, ) -> Weight; + fn veto_external() -> Weight; + fn cancel_proposal() -> Weight; fn cancel_referendum() -> Weight; - fn cancel_queued(r: u32, ) -> Weight; fn on_initialize_base(r: u32, ) -> Weight; fn on_initialize_base_with_launch_period(r: u32, ) -> Weight; fn delegate(r: u32, ) -> Weight; fn undelegate(r: u32, ) -> Weight; fn clear_public_proposals() -> Weight; - fn note_preimage(b: u32, ) -> Weight; - fn note_imminent_preimage(b: u32, ) -> Weight; - fn reap_preimage(b: u32, ) -> Weight; fn unlock_remove(r: u32, ) -> Weight; fn unlock_set(r: u32, ) -> Weight; fn remove_vote(r: u32, ) -> Weight; @@ -80,125 +78,103 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - Weight::from_ref_time(48_328_000 as u64) + Weight::from_ref_time(57_410_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy DepositOf (r:1 w:1) - fn second(s: u32, ) -> Weight { - Weight::from_ref_time(30_923_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(s as u64)) + fn second() -> Weight { + Weight::from_ref_time(49_224_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - fn vote_new(r: u32, ) -> Weight { - Weight::from_ref_time(40_345_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(140_000 as u64).saturating_mul(r as u64)) + fn vote_new() -> Weight { + Weight::from_ref_time(60_933_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - fn vote_existing(r: u32, ) -> Weight { - Weight::from_ref_time(39_853_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(r as u64)) + fn vote_existing() -> Weight { + Weight::from_ref_time(60_393_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - Weight::from_ref_time(19_364_000 as u64) + Weight::from_ref_time(24_588_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) + // Storage: Democracy DepositOf (r:1 w:1) + // Storage: System Account (r:1 w:1) // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Blacklist (r:0 w:1) - // Storage: Democracy DepositOf (r:1 w:1) - // Storage: System Account (r:1 w:1) - fn blacklist(p: u32, ) -> Weight { - Weight::from_ref_time(57_708_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + fn blacklist() -> Weight { + Weight::from_ref_time(91_226_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) - fn external_propose(v: u32, ) -> Weight { - Weight::from_ref_time(10_714_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(v as u64)) + fn external_propose() -> Weight { + Weight::from_ref_time(18_898_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - Weight::from_ref_time(3_697_000 as u64) + Weight::from_ref_time(5_136_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - Weight::from_ref_time(3_831_000 as u64) + Weight::from_ref_time(5_243_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - Weight::from_ref_time(20_271_000 as u64) + Weight::from_ref_time(24_275_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) - fn veto_external(v: u32, ) -> Weight { - Weight::from_ref_time(21_319_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(v as u64)) + fn veto_external() -> Weight { + Weight::from_ref_time(30_988_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) - fn cancel_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(43_960_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(p as u64)) + fn cancel_proposal() -> Weight { + Weight::from_ref_time(78_515_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - Weight::from_ref_time(13_475_000 as u64) + Weight::from_ref_time(16_155_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) - fn cancel_queued(r: u32, ) -> Weight { - Weight::from_ref_time(24_320_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(560_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:1 w:0) + // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { - Weight::from_ref_time(3_428_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_171_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(7_007_000 as u64) + // Standard Error: 2_686 + .saturating_add(Weight::from_ref_time(2_288_781 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -208,33 +184,36 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy LastTabledWasExternal (r:1 w:0) // Storage: Democracy NextExternal (r:1 w:0) // Storage: Democracy PublicProps (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:1 w:0) + // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - Weight::from_ref_time(7_867_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_177_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(9_528_000 as u64) + // Standard Error: 2_521 + .saturating_add(Weight::from_ref_time(2_291_780 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:3 w:3) - // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(37_902_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(4_335_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(46_787_000 as u64) + // Standard Error: 2_943 + .saturating_add(Weight::from_ref_time(3_460_194 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(r as u64))) } // Storage: Democracy VotingOf (r:2 w:2) - // Storage: Democracy ReferendumInfoOf (r:1 w:1) + // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(21_272_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(4_351_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(29_789_000 as u64) + // Standard Error: 2_324 + .saturating_add(Weight::from_ref_time(3_360_918 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) @@ -242,69 +221,48 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - Weight::from_ref_time(4_913_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - fn note_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(27_986_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - fn note_imminent_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(20_058_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - // Storage: System Account (r:1 w:0) - fn reap_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(28_619_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) + Weight::from_ref_time(6_519_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { - Weight::from_ref_time(26_619_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(28_884_000 as u64) + // Standard Error: 2_631 + .saturating_add(Weight::from_ref_time(163_516 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { - Weight::from_ref_time(25_373_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(33_498_000 as u64) + // Standard Error: 622 + .saturating_add(Weight::from_ref_time(133_421 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) + /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_961_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(18_201_000 as u64) + // Standard Error: 1_007 + .saturating_add(Weight::from_ref_time(152_699 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) + /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_992_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(18_455_000 as u64) + // Standard Error: 951 + .saturating_add(Weight::from_ref_time(150_907 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -317,125 +275,103 @@ impl WeightInfo for () { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - Weight::from_ref_time(48_328_000 as u64) + Weight::from_ref_time(57_410_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy DepositOf (r:1 w:1) - fn second(s: u32, ) -> Weight { - Weight::from_ref_time(30_923_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(s as u64)) + fn second() -> Weight { + Weight::from_ref_time(49_224_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - fn vote_new(r: u32, ) -> Weight { - Weight::from_ref_time(40_345_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(140_000 as u64).saturating_mul(r as u64)) + fn vote_new() -> Weight { + Weight::from_ref_time(60_933_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - fn vote_existing(r: u32, ) -> Weight { - Weight::from_ref_time(39_853_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(r as u64)) + fn vote_existing() -> Weight { + Weight::from_ref_time(60_393_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - Weight::from_ref_time(19_364_000 as u64) + Weight::from_ref_time(24_588_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) + // Storage: Democracy DepositOf (r:1 w:1) + // Storage: System Account (r:1 w:1) // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Blacklist (r:0 w:1) - // Storage: Democracy DepositOf (r:1 w:1) - // Storage: System Account (r:1 w:1) - fn blacklist(p: u32, ) -> Weight { - Weight::from_ref_time(57_708_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + fn blacklist() -> Weight { + Weight::from_ref_time(91_226_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) - fn external_propose(v: u32, ) -> Weight { - Weight::from_ref_time(10_714_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(v as u64)) + fn external_propose() -> Weight { + Weight::from_ref_time(18_898_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - Weight::from_ref_time(3_697_000 as u64) + Weight::from_ref_time(5_136_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - Weight::from_ref_time(3_831_000 as u64) + Weight::from_ref_time(5_243_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - Weight::from_ref_time(20_271_000 as u64) + Weight::from_ref_time(24_275_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) - fn veto_external(v: u32, ) -> Weight { - Weight::from_ref_time(21_319_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(v as u64)) + fn veto_external() -> Weight { + Weight::from_ref_time(30_988_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) - fn cancel_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(43_960_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(p as u64)) + fn cancel_proposal() -> Weight { + Weight::from_ref_time(78_515_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - Weight::from_ref_time(13_475_000 as u64) + Weight::from_ref_time(16_155_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) - fn cancel_queued(r: u32, ) -> Weight { - Weight::from_ref_time(24_320_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(560_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:1 w:0) + // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { - Weight::from_ref_time(3_428_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_171_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(7_007_000 as u64) + // Standard Error: 2_686 + .saturating_add(Weight::from_ref_time(2_288_781 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) @@ -445,33 +381,36 @@ impl WeightInfo for () { // Storage: Democracy LastTabledWasExternal (r:1 w:0) // Storage: Democracy NextExternal (r:1 w:0) // Storage: Democracy PublicProps (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:1 w:0) + // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - Weight::from_ref_time(7_867_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_177_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(9_528_000 as u64) + // Standard Error: 2_521 + .saturating_add(Weight::from_ref_time(2_291_780 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:3 w:3) - // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(37_902_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(4_335_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(46_787_000 as u64) + // Standard Error: 2_943 + .saturating_add(Weight::from_ref_time(3_460_194 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(r as u64))) } // Storage: Democracy VotingOf (r:2 w:2) - // Storage: Democracy ReferendumInfoOf (r:1 w:1) + // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(21_272_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(4_351_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(29_789_000 as u64) + // Standard Error: 2_324 + .saturating_add(Weight::from_ref_time(3_360_918 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) @@ -479,69 +418,48 @@ impl WeightInfo for () { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - Weight::from_ref_time(4_913_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - fn note_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(27_986_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - fn note_imminent_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(20_058_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - // Storage: System Account (r:1 w:0) - fn reap_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(28_619_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) + Weight::from_ref_time(6_519_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { - Weight::from_ref_time(26_619_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(28_884_000 as u64) + // Standard Error: 2_631 + .saturating_add(Weight::from_ref_time(163_516 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { - Weight::from_ref_time(25_373_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(33_498_000 as u64) + // Standard Error: 622 + .saturating_add(Weight::from_ref_time(133_421 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) + /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_961_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(18_201_000 as u64) + // Standard Error: 1_007 + .saturating_add(Weight::from_ref_time(152_699 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) + /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_992_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(18_455_000 as u64) + // Standard Error: 951 + .saturating_add(Weight::from_ref_time(150_907 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 747d1e9f27106..20628da50937a 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -268,7 +268,7 @@ fn registration_should_work() { let mut three_fields = ten(); three_fields.additional.try_push(Default::default()).unwrap(); three_fields.additional.try_push(Default::default()).unwrap(); - assert_eq!(three_fields.additional.try_push(Default::default()), Err(())); + assert!(three_fields.additional.try_push(Default::default()).is_err()); assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_eq!(Identity::identity(10).unwrap().info, ten()); assert_eq!(Balances::free_balance(10), 90); diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index 6c8b5fbaa7362..bfd0870d30c22 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -22,6 +22,9 @@ sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +# third party +log = { version = "0.4.17", default-features = false } + [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } sp-core = { version = "6.0.0", path = "../../primitives/core" } diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index c0b0097b07236..d949414e31cb3 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -31,7 +31,7 @@ const SEED: u32 = 0; fn setup_multi( s: u32, z: u32, -) -> Result<(Vec, OpaqueCall), &'static str> { +) -> Result<(Vec, Box<::RuntimeCall>), &'static str> { let mut signatories: Vec = Vec::new(); for i in 0..s { let signatory = account("signatory", i, SEED); @@ -44,8 +44,7 @@ fn setup_multi( // Must first convert to runtime call type. let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![0; z as usize] }.into(); - let call_data = OpaqueCall::::from_encoded(call.encode()); - Ok((signatories, call_data)) + Ok((signatories, Box::new(call))) } benchmarks! { @@ -74,35 +73,15 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(call.encoded()); - let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); - let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - // Whitelist caller account from further DB operations. - let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, false, Weight::zero()) - verify { - assert!(Multisigs::::contains_key(multi_account_id, call_hash)); - assert!(!Calls::::contains_key(call_hash)); - } - - as_multi_create_store { - // Signatories, need at least 2 total people - let s in 2 .. T::MaxSignatories::get() as u32; - // Transaction Length - let z in 0 .. 10_000; - let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, true, Weight::zero()) + }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, Weight::zero()) verify { assert!(Multisigs::::contains_key(multi_account_id, call_hash)); - assert!(Calls::::contains_key(call_hash)); } as_multi_approve { @@ -111,49 +90,22 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(call.encoded()); - let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); - let mut signatories2 = signatories.clone(); - let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - // before the call, get the timepoint - let timepoint = Multisig::::timepoint(); - // Create the multi, storing for worst case - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?; - assert!(Calls::::contains_key(call_hash)); - let caller2 = signatories2.remove(0); - // Whitelist caller account from further DB operations. - let caller_key = frame_system::Account::::hashed_key_for(&caller2); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::zero()) - verify { - let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; - assert_eq!(multisig.approvals.len(), 2); - } - - as_multi_approve_store { - // Signatories, need at least 3 people (so we don't complete the multisig) - let s in 3 .. T::MaxSignatories::get() as u32; - // Transaction Length - let z in 0 .. 10_000; - let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; // before the call, get the timepoint let timepoint = Multisig::::timepoint(); - // Create the multi, not storing - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), false, Weight::zero())?; - assert!(!Calls::::contains_key(call_hash)); + // Create the multi + Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?; let caller2 = signatories2.remove(0); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, true, Weight::zero()) + }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::zero()) verify { let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; assert_eq!(multisig.approvals.len(), 2); - assert!(Calls::::contains_key(call_hash)); } as_multi_complete { @@ -162,27 +114,27 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; // before the call, get the timepoint let timepoint = Multisig::::timepoint(); - // Create the multi, storing it for worst case - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?; + // Create the multi + Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?; // Everyone except the first person approves for i in 1 .. s - 1 { let mut signatories_loop = signatories2.clone(); let caller_loop = signatories_loop.remove(i as usize); let o = RawOrigin::Signed(caller_loop).into(); - Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, Weight::zero())?; + Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), Weight::zero())?; } let caller2 = signatories2.remove(0); assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::MAX) + }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::MAX) verify { assert!(!Multisigs::::contains_key(&multi_account_id, call_hash)); } @@ -195,7 +147,7 @@ benchmarks! { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); @@ -214,7 +166,7 @@ benchmarks! { let mut signatories2 = signatories.clone(); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi @@ -224,7 +176,6 @@ benchmarks! { signatories, None, call, - false, Weight::zero() )?; let caller2 = signatories2.remove(0); @@ -237,45 +188,6 @@ benchmarks! { assert_eq!(multisig.approvals.len(), 2); } - approve_as_multi_complete { - // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get() as u32; - // Transaction Length, not a component - let z = 10_000; - let (mut signatories, call) = setup_multi::(s, z)?; - let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); - let mut signatories2 = signatories.clone(); - let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let call_hash = blake2_256(call.encoded()); - // before the call, get the timepoint - let timepoint = Multisig::::timepoint(); - // Create the multi - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?; - // Everyone except the first person approves - for i in 1 .. s - 1 { - let mut signatories_loop = signatories2.clone(); - let caller_loop = signatories_loop.remove(i as usize); - let o = RawOrigin::Signed(caller_loop).into(); - Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, Weight::zero())?; - } - let caller2 = signatories2.remove(0); - assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); - // Whitelist caller account from further DB operations. - let caller_key = frame_system::Account::::hashed_key_for(&caller2); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: approve_as_multi( - RawOrigin::Signed(caller2), - s as u16, - signatories2, - Some(timepoint), - call_hash, - Weight::MAX - ) - verify { - assert!(!Multisigs::::contains_key(multi_account_id, call_hash)); - } - cancel_as_multi { // Signatories, need at least 2 people let s in 2 .. T::MaxSignatories::get() as u32; @@ -284,20 +196,18 @@ benchmarks! { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); let timepoint = Multisig::::timepoint(); // Create the multi let o = RawOrigin::Signed(caller.clone()).into(); - Multisig::::as_multi(o, s as u16, signatories.clone(), None, call, true, Weight::zero())?; + Multisig::::as_multi(o, s as u16, signatories.clone(), None, call, Weight::zero())?; assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); - assert!(Calls::::contains_key(call_hash)); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); }: _(RawOrigin::Signed(caller), s as u16, signatories, timepoint, call_hash) verify { assert!(!Multisigs::::contains_key(multi_account_id, call_hash)); - assert!(!Calls::::contains_key(call_hash)); } impl_benchmark_test_suite!(Multisig, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 3bdb47ffc4568..e3031cc830209 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -47,6 +47,7 @@ #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; +pub mod migrations; mod tests; pub mod weights; @@ -57,7 +58,7 @@ use frame_support::{ PostDispatchInfo, }, ensure, - traits::{Currency, Get, ReservableCurrency, WrapperKeepOpaque}, + traits::{Currency, Get, ReservableCurrency}, weights::Weight, RuntimeDebug, }; @@ -73,6 +74,20 @@ pub use weights::WeightInfo; pub use pallet::*; +/// The log target of this pallet. +pub const LOG_TARGET: &'static str = "runtime::multisig"; + +// syntactic sugar for logging. +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: crate::LOG_TARGET, + concat!("[{:?}] ✍️ ", $patter), >::block_number() $(, $values)* + ) + }; +} + type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -100,12 +115,10 @@ pub struct Multisig { approvals: Vec, } -type OpaqueCall = WrapperKeepOpaque<::RuntimeCall>; - type CallHash = [u8; 32]; enum CallOrHash { - Call(OpaqueCall, bool), + Call(::RuntimeCall), Hash([u8; 32]), } @@ -152,9 +165,13 @@ pub mod pallet { type WeightInfo: WeightInfo; } + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); /// The set of open multisig operations. @@ -168,10 +185,6 @@ pub mod pallet { Multisig, T::AccountId>, >; - #[pallet::storage] - pub type Calls = - StorageMap<_, Identity, [u8; 32], (OpaqueCall, T::AccountId, BalanceOf)>; - #[pallet::error] pub enum Error { /// Threshold must be 2 or greater. @@ -343,13 +356,13 @@ pub mod pallet { /// taken for its lifetime of `DepositBase + threshold * DepositFactor`. /// ------------------------------- /// - DB Weight: - /// - Reads: Multisig Storage, [Caller Account], Calls (if `store_call`) - /// - Writes: Multisig Storage, [Caller Account], Calls (if `store_call`) + /// - Reads: Multisig Storage, [Caller Account] + /// - Writes: Multisig Storage, [Caller Account] /// - Plus Call Weight /// # #[pallet::weight({ let s = other_signatories.len() as u32; - let z = call.encoded_len() as u32; + let z = call.using_encoded(|d| d.len()) as u32; T::WeightInfo::as_multi_create(s, z) .max(T::WeightInfo::as_multi_create_store(s, z)) @@ -362,8 +375,7 @@ pub mod pallet { threshold: u16, other_signatories: Vec, maybe_timepoint: Option>, - call: OpaqueCall, - store_call: bool, + call: Box<::RuntimeCall>, max_weight: Weight, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -372,7 +384,7 @@ pub mod pallet { threshold, other_signatories, maybe_timepoint, - CallOrHash::Call(call, store_call), + CallOrHash::Call(*call), max_weight, ) } @@ -462,8 +474,8 @@ pub mod pallet { /// - Storage: removes one item. /// ---------------------------------- /// - DB Weight: - /// - Read: Multisig Storage, [Caller Account], Refund Account, Calls - /// - Write: Multisig Storage, [Caller Account], Refund Account, Calls + /// - Read: Multisig Storage, [Caller Account], Refund Account + /// - Write: Multisig Storage, [Caller Account], Refund Account /// # #[pallet::weight(T::WeightInfo::cancel_as_multi(other_signatories.len() as u32))] pub fn cancel_as_multi( @@ -489,7 +501,6 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&m.depositor, m.deposit); debug_assert!(err_amount.is_zero()); >::remove(&id, &call_hash); - Self::clear_call(&call_hash); Self::deposit_event(Event::MultisigCancelled { cancelling: who, @@ -531,13 +542,12 @@ impl Pallet { let id = Self::multi_account_id(&signatories, threshold); // Threshold > 1; this means it's a multi-step operation. We extract the `call_hash`. - let (call_hash, call_len, maybe_call, store) = match call_or_hash { - CallOrHash::Call(call, should_store) => { - let call_hash = blake2_256(call.encoded()); - let call_len = call.encoded_len(); - (call_hash, call_len, Some(call), should_store) + let (call_hash, call_len, maybe_call) = match call_or_hash { + CallOrHash::Call(call) => { + let (call_hash, call_len) = call.using_encoded(|d| (blake2_256(d), d.len())); + (call_hash, call_len, Some(call)) }, - CallOrHash::Hash(h) => (h, 0, None, false), + CallOrHash::Hash(h) => (h, 0, None), }; // Branch on whether the operation has already started or not. @@ -556,13 +566,7 @@ impl Pallet { } // We only bother fetching/decoding call if we know that we're ready to execute. - let maybe_approved_call = if approvals >= threshold { - Self::get_call(&call_hash, maybe_call.as_ref()) - } else { - None - }; - - if let Some((call, call_len)) = maybe_approved_call { + if let Some(call) = maybe_call.filter(|_| approvals >= threshold) { // verify weight ensure!( call.get_dispatch_info().weight.all_lte(max_weight), @@ -572,7 +576,6 @@ impl Pallet { // Clean up storage before executing call to avoid an possibility of reentrancy // attack. >::remove(&id, call_hash); - Self::clear_call(&call_hash); T::Currency::unreserve(&m.depositor, m.deposit); let result = call.dispatch(RawOrigin::Signed(id.clone()).into()); @@ -596,19 +599,6 @@ impl Pallet { // We cannot dispatch the call now; either it isn't available, or it is, but we // don't have threshold approvals even with our signature. - // Store the call if desired. - let stored = if let Some(data) = maybe_call.filter(|_| store) { - Self::store_call_and_reserve( - who.clone(), - &call_hash, - data, - BalanceOf::::zero(), - )?; - true - } else { - false - }; - if let Some(pos) = maybe_pos { // Record approval. m.approvals.insert(pos, who.clone()); @@ -622,17 +612,11 @@ impl Pallet { } else { // If we already approved and didn't store the Call, then this was useless and // we report an error. - ensure!(stored, Error::::AlreadyApproved); + Err(Error::::AlreadyApproved)? } - let final_weight = if stored { - T::WeightInfo::as_multi_approve_store( - other_signatories_len as u32, - call_len as u32, - ) - } else { - T::WeightInfo::as_multi_approve(other_signatories_len as u32, call_len as u32) - }; + let final_weight = + T::WeightInfo::as_multi_approve(other_signatories_len as u32, call_len as u32); // Call is not made, so the actual weight does not include call Ok(Some(final_weight).into()) } @@ -643,14 +627,7 @@ impl Pallet { // Just start the operation by recording it in storage. let deposit = T::DepositBase::get() + T::DepositFactor::get() * threshold.into(); - // Store the call if desired. - let stored = if let Some(data) = maybe_call.filter(|_| store) { - Self::store_call_and_reserve(who.clone(), &call_hash, data, deposit)?; - true - } else { - T::Currency::reserve(&who, deposit)?; - false - }; + T::Currency::reserve(&who, deposit)?; >::insert( &id, @@ -664,58 +641,13 @@ impl Pallet { ); Self::deposit_event(Event::NewMultisig { approving: who, multisig: id, call_hash }); - let final_weight = if stored { - T::WeightInfo::as_multi_create_store(other_signatories_len as u32, call_len as u32) - } else { - T::WeightInfo::as_multi_create(other_signatories_len as u32, call_len as u32) - }; + let final_weight = + T::WeightInfo::as_multi_create(other_signatories_len as u32, call_len as u32); // Call is not made, so the actual weight does not include call Ok(Some(final_weight).into()) } } - /// Place a call's encoded data in storage, reserving funds as appropriate. - /// - /// We store `data` here because storing `call` would result in needing another `.encode`. - /// - /// Returns a `bool` indicating whether the data did end up being stored. - fn store_call_and_reserve( - who: T::AccountId, - hash: &[u8; 32], - data: OpaqueCall, - other_deposit: BalanceOf, - ) -> DispatchResult { - ensure!(!Calls::::contains_key(hash), Error::::AlreadyStored); - let deposit = other_deposit + - T::DepositBase::get() + - T::DepositFactor::get() * - BalanceOf::::from(((data.encoded_len() + 31) / 32) as u32); - T::Currency::reserve(&who, deposit)?; - Calls::::insert(&hash, (data, who, deposit)); - Ok(()) - } - - /// Attempt to decode and return the call, provided by the user or from storage. - fn get_call( - hash: &[u8; 32], - maybe_known: Option<&OpaqueCall>, - ) -> Option<(::RuntimeCall, usize)> { - maybe_known.map_or_else( - || { - Calls::::get(hash) - .and_then(|(data, ..)| Some((data.try_decode()?, data.encoded_len()))) - }, - |data| Some((data.try_decode()?, data.encoded_len())), - ) - } - - /// Attempt to remove a call from storage, returning any deposit on it to the owner. - fn clear_call(hash: &[u8; 32]) { - if let Some((_, who, deposit)) = Calls::::take(hash) { - T::Currency::unreserve(&who, deposit); - } - } - /// The current `Timepoint`. pub fn timepoint() -> Timepoint { Timepoint { diff --git a/frame/multisig/src/migrations.rs b/frame/multisig/src/migrations.rs new file mode 100644 index 0000000000000..5085297cde433 --- /dev/null +++ b/frame/multisig/src/migrations.rs @@ -0,0 +1,86 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Migrations for Multisig Pallet + +use super::*; +use frame_support::{ + dispatch::GetStorageVersion, + traits::{OnRuntimeUpgrade, WrapperKeepOpaque}, + Identity, +}; + +#[cfg(feature = "try-runtime")] +use frame_support::ensure; + +pub mod v1 { + use super::*; + + type OpaqueCall = WrapperKeepOpaque<::RuntimeCall>; + + #[frame_support::storage_alias] + type Calls = StorageMap< + Pallet, + Identity, + [u8; 32], + (OpaqueCall, ::AccountId, BalanceOf), + >; + + pub struct MigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + let onchain = Pallet::::on_chain_storage_version(); + + ensure!(onchain < 1, "this migration can be deleted"); + + log!(info, "Number of calls to refund and delete: {}", Calls::::iter().count()); + + Ok(Vec::new()) + } + + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); + + if onchain > 0 { + log!(info, "MigrateToV1 should be removed"); + return T::DbWeight::get().reads(1) + } + + Calls::::drain().for_each(|(_call_hash, (_data, caller, deposit))| { + T::Currency::unreserve(&caller, deposit); + }); + + current.put::>(); + + ::BlockWeights::get().max_block + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + let onchain = Pallet::::on_chain_storage_version(); + ensure!(onchain < 2, "this migration needs to be removed"); + ensure!(onchain == 1, "this migration needs to be run"); + ensure!( + Calls::::iter().count() == 0, + "there are some dangling calls that need to be destroyed and refunded" + ); + Ok(()) + } + } +} diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index b24a06f454368..f753b6f386c56 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -34,7 +34,6 @@ use sp_runtime::{ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; -type OpaqueCall = super::OpaqueCall; frame_support::construct_runtime!( pub enum Test where @@ -130,8 +129,8 @@ fn now() -> Timepoint { Multisig::timepoint() } -fn call_transfer(dest: u64, value: u64) -> RuntimeCall { - RuntimeCall::Balances(BalancesCall::transfer { dest, value }) +fn call_transfer(dest: u64, value: u64) -> Box { + Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest, value })) } #[test] @@ -144,14 +143,12 @@ fn multisig_deposit_is_taken_and_returned() { let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); assert_ok!(Multisig::as_multi( RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), Weight::zero() )); assert_eq!(Balances::free_balance(1), 2); @@ -162,8 +159,7 @@ fn multisig_deposit_is_taken_and_returned() { 2, vec![1, 3], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, call_weight )); assert_eq!(Balances::free_balance(1), 5); @@ -171,96 +167,6 @@ fn multisig_deposit_is_taken_and_returned() { }); } -#[test] -fn multisig_deposit_is_taken_and_returned_with_call_storage() { - new_test_ext().execute_with(|| { - let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); - - let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); - assert_ok!(Multisig::as_multi( - RuntimeOrigin::signed(1), - 2, - vec![2, 3], - None, - OpaqueCall::from_encoded(data), - true, - Weight::zero() - )); - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::reserved_balance(1), 5); - - assert_ok!(Multisig::approve_as_multi( - RuntimeOrigin::signed(2), - 2, - vec![1, 3], - Some(now()), - hash, - call_weight - )); - assert_eq!(Balances::free_balance(1), 5); - assert_eq!(Balances::reserved_balance(1), 0); - }); -} - -#[test] -fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() { - new_test_ext().execute_with(|| { - let multi = Multisig::multi_account_id(&[1, 2, 3][..], 3); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); - - let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); - - assert_ok!(Multisig::approve_as_multi( - RuntimeOrigin::signed(1), - 3, - vec![2, 3], - None, - hash, - Weight::zero() - )); - assert_eq!(Balances::free_balance(1), 1); - assert_eq!(Balances::reserved_balance(1), 4); - - assert_ok!(Multisig::as_multi( - RuntimeOrigin::signed(2), - 3, - vec![1, 3], - Some(now()), - OpaqueCall::from_encoded(data), - true, - Weight::zero() - )); - assert_eq!(Balances::free_balance(2), 3); - assert_eq!(Balances::reserved_balance(2), 2); - assert_eq!(Balances::free_balance(1), 1); - assert_eq!(Balances::reserved_balance(1), 4); - - assert_ok!(Multisig::approve_as_multi( - RuntimeOrigin::signed(3), - 3, - vec![1, 2], - Some(now()), - hash, - call_weight - )); - assert_eq!(Balances::free_balance(1), 5); - assert_eq!(Balances::reserved_balance(1), 0); - assert_eq!(Balances::free_balance(2), 5); - assert_eq!(Balances::reserved_balance(2), 0); - }); -} - #[test] fn cancel_multisig_returns_deposit() { new_test_ext().execute_with(|| { @@ -298,8 +204,8 @@ fn timepoint_checking_works() { assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); - let call = call_transfer(6, 15).encode(); - let hash = blake2_256(&call); + let call = call_transfer(6, 15); + let hash = blake2_256(&call.encode()); assert_noop!( Multisig::approve_as_multi( @@ -328,8 +234,7 @@ fn timepoint_checking_works() { 2, vec![1, 3], None, - OpaqueCall::from_encoded(call.clone()), - false, + call.clone(), Weight::zero() ), Error::::NoTimepoint, @@ -341,8 +246,7 @@ fn timepoint_checking_works() { 2, vec![1, 3], Some(later), - OpaqueCall::from_encoded(call), - false, + call, Weight::zero() ), Error::::WrongTimepoint, @@ -350,41 +254,6 @@ fn timepoint_checking_works() { }); } -#[test] -fn multisig_2_of_3_works_with_call_storing() { - new_test_ext().execute_with(|| { - let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); - - let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); - assert_ok!(Multisig::as_multi( - RuntimeOrigin::signed(1), - 2, - vec![2, 3], - None, - OpaqueCall::from_encoded(data), - true, - Weight::zero() - )); - assert_eq!(Balances::free_balance(6), 0); - - assert_ok!(Multisig::approve_as_multi( - RuntimeOrigin::signed(2), - 2, - vec![1, 3], - Some(now()), - hash, - call_weight - )); - assert_eq!(Balances::free_balance(6), 15); - }); -} - #[test] fn multisig_2_of_3_works() { new_test_ext().execute_with(|| { @@ -395,8 +264,7 @@ fn multisig_2_of_3_works() { let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); + let hash = blake2_256(&call.encode()); assert_ok!(Multisig::approve_as_multi( RuntimeOrigin::signed(1), 2, @@ -412,8 +280,7 @@ fn multisig_2_of_3_works() { 2, vec![1, 3], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, call_weight )); assert_eq!(Balances::free_balance(6), 15); @@ -430,8 +297,7 @@ fn multisig_3_of_3_works() { let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); + let hash = blake2_256(&call.encode()); assert_ok!(Multisig::approve_as_multi( RuntimeOrigin::signed(1), 3, @@ -455,8 +321,7 @@ fn multisig_3_of_3_works() { 3, vec![1, 2], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, call_weight )); assert_eq!(Balances::free_balance(6), 15); @@ -492,68 +357,6 @@ fn cancel_multisig_works() { }); } -#[test] -fn cancel_multisig_with_call_storage_works() { - new_test_ext().execute_with(|| { - let call = call_transfer(6, 15).encode(); - let hash = blake2_256(&call); - assert_ok!(Multisig::as_multi( - RuntimeOrigin::signed(1), - 3, - vec![2, 3], - None, - OpaqueCall::from_encoded(call), - true, - Weight::zero() - )); - assert_eq!(Balances::free_balance(1), 4); - assert_ok!(Multisig::approve_as_multi( - RuntimeOrigin::signed(2), - 3, - vec![1, 3], - Some(now()), - hash, - Weight::zero() - )); - assert_noop!( - Multisig::cancel_as_multi(RuntimeOrigin::signed(2), 3, vec![1, 3], now(), hash), - Error::::NotOwner, - ); - assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash),); - assert_eq!(Balances::free_balance(1), 10); - }); -} - -#[test] -fn cancel_multisig_with_alt_call_storage_works() { - new_test_ext().execute_with(|| { - let call = call_transfer(6, 15).encode(); - let hash = blake2_256(&call); - assert_ok!(Multisig::approve_as_multi( - RuntimeOrigin::signed(1), - 3, - vec![2, 3], - None, - hash, - Weight::zero() - )); - assert_eq!(Balances::free_balance(1), 6); - assert_ok!(Multisig::as_multi( - RuntimeOrigin::signed(2), - 3, - vec![1, 3], - Some(now()), - OpaqueCall::from_encoded(call), - true, - Weight::zero() - )); - assert_eq!(Balances::free_balance(2), 8); - assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash)); - assert_eq!(Balances::free_balance(1), 10); - assert_eq!(Balances::free_balance(2), 10); - }); -} - #[test] fn multisig_2_of_3_as_multi_works() { new_test_ext().execute_with(|| { @@ -564,14 +367,12 @@ fn multisig_2_of_3_as_multi_works() { let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); assert_ok!(Multisig::as_multi( RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), Weight::zero() )); assert_eq!(Balances::free_balance(6), 0); @@ -581,8 +382,7 @@ fn multisig_2_of_3_as_multi_works() { 2, vec![1, 3], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, call_weight )); assert_eq!(Balances::free_balance(6), 15); @@ -599,18 +399,15 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { let call1 = call_transfer(6, 10); let call1_weight = call1.get_dispatch_info().weight; - let data1 = call1.encode(); let call2 = call_transfer(7, 5); let call2_weight = call2.get_dispatch_info().weight; - let data2 = call2.encode(); assert_ok!(Multisig::as_multi( RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data1.clone()), - false, + call1.clone(), Weight::zero() )); assert_ok!(Multisig::as_multi( @@ -618,8 +415,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { 2, vec![1, 3], None, - OpaqueCall::from_encoded(data2.clone()), - false, + call2.clone(), Weight::zero() )); assert_ok!(Multisig::as_multi( @@ -627,8 +423,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { 2, vec![1, 2], Some(now()), - OpaqueCall::from_encoded(data1), - false, + call1, call1_weight )); assert_ok!(Multisig::as_multi( @@ -636,8 +431,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { 2, vec![1, 2], Some(now()), - OpaqueCall::from_encoded(data2), - false, + call2, call2_weight )); @@ -656,15 +450,13 @@ fn multisig_2_of_3_cannot_reissue_same_call() { let call = call_transfer(6, 10); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); + let hash = blake2_256(&call.encode()); assert_ok!(Multisig::as_multi( RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), Weight::zero() )); assert_ok!(Multisig::as_multi( @@ -672,8 +464,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { 2, vec![1, 3], Some(now()), - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), call_weight )); assert_eq!(Balances::free_balance(multi), 5); @@ -683,8 +474,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { 2, vec![2, 3], None, - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), Weight::zero() )); assert_ok!(Multisig::as_multi( @@ -692,8 +482,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { 2, vec![1, 2], Some(now()), - OpaqueCall::from_encoded(data), - false, + call.clone(), call_weight )); @@ -714,15 +503,14 @@ fn multisig_2_of_3_cannot_reissue_same_call() { #[test] fn minimum_threshold_check_works() { new_test_ext().execute_with(|| { - let call = call_transfer(6, 15).encode(); + let call = call_transfer(6, 15); assert_noop!( Multisig::as_multi( RuntimeOrigin::signed(1), 0, vec![2], None, - OpaqueCall::from_encoded(call.clone()), - false, + call.clone(), Weight::zero() ), Error::::MinimumThreshold, @@ -733,8 +521,7 @@ fn minimum_threshold_check_works() { 1, vec![2], None, - OpaqueCall::from_encoded(call.clone()), - false, + call.clone(), Weight::zero() ), Error::::MinimumThreshold, @@ -745,15 +532,14 @@ fn minimum_threshold_check_works() { #[test] fn too_many_signatories_fails() { new_test_ext().execute_with(|| { - let call = call_transfer(6, 15).encode(); + let call = call_transfer(6, 15); assert_noop!( Multisig::as_multi( RuntimeOrigin::signed(1), 2, vec![2, 3, 4], None, - OpaqueCall::from_encoded(call), - false, + call.clone(), Weight::zero() ), Error::::TooManySignatories, @@ -815,8 +601,8 @@ fn multisig_1_of_3_works() { assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); - let call = call_transfer(6, 15).encode(); - let hash = blake2_256(&call); + let call = call_transfer(6, 15); + let hash = blake2_256(&call.encode()); assert_noop!( Multisig::approve_as_multi( RuntimeOrigin::signed(1), @@ -834,17 +620,15 @@ fn multisig_1_of_3_works() { 1, vec![2, 3], None, - OpaqueCall::from_encoded(call), - false, + call.clone(), Weight::zero() ), Error::::MinimumThreshold, ); - let boxed_call = Box::new(call_transfer(6, 15)); assert_ok!(Multisig::as_multi_threshold_1( RuntimeOrigin::signed(1), vec![2, 3], - boxed_call + call_transfer(6, 15) )); assert_eq!(Balances::free_balance(6), 15); @@ -871,14 +655,12 @@ fn weight_check_works() { assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); - let data = call.encode(); assert_ok!(Multisig::as_multi( RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), Weight::zero() )); assert_eq!(Balances::free_balance(6), 0); @@ -889,8 +671,7 @@ fn weight_check_works() { 2, vec![1, 3], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, Weight::zero() ), Error::::MaxWeightTooLow, @@ -911,8 +692,7 @@ fn multisig_handles_no_preimage_after_all_approve() { let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); + let hash = blake2_256(&call.encode()); assert_ok!(Multisig::approve_as_multi( RuntimeOrigin::signed(1), 3, @@ -944,8 +724,7 @@ fn multisig_handles_no_preimage_after_all_approve() { 3, vec![1, 2], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, call_weight )); assert_eq!(Balances::free_balance(6), 15); diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 953cf39cd12db..b3238630d3174 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -140,7 +140,7 @@ pub mod pallet { let sender = ensure_signed(origin)?; let bounded_name: BoundedVec<_, _> = - name.try_into().map_err(|()| Error::::TooLong)?; + name.try_into().map_err(|_| Error::::TooLong)?; ensure!(bounded_name.len() >= T::MinLength::get() as usize, Error::::TooShort); let deposit = if let Some((_, deposit)) = >::get(&sender) { @@ -229,7 +229,7 @@ pub mod pallet { T::ForceOrigin::ensure_origin(origin)?; let bounded_name: BoundedVec<_, _> = - name.try_into().map_err(|()| Error::::TooLong)?; + name.try_into().map_err(|_| Error::::TooLong)?; let target = T::Lookup::lookup(target)?; let deposit = >::get(&target).map(|x| x.1).unwrap_or_else(Zero::zero); >::insert(&target, (bounded_name, deposit)); diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 9a5cc186cca64..77046f4fb58b6 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -19,6 +19,7 @@ sp-core = { version = "6.0.0", default-features = false, optional = true, path = sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +log = { version = "0.4.17", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } @@ -36,10 +37,13 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "scale-info/std", "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", ] -try-runtime = ["frame-support/try-runtime"] +try-runtime = [ + "frame-support/try-runtime", +] diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index 3c7be9db573f4..8a61d7d780bfd 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -35,7 +35,7 @@ fn funded_account(name: &'static str, index: u32) -> T::AccountId { } fn preimage_and_hash() -> (Vec, T::Hash) { - sized_preimage_and_hash::(T::MaxSize::get()) + sized_preimage_and_hash::(MAX_SIZE) } fn sized_preimage_and_hash(size: u32) -> (Vec, T::Hash) { @@ -48,7 +48,7 @@ fn sized_preimage_and_hash(size: u32) -> (Vec, T::Hash) { benchmarks! { // Expensive note - will reserve. note_preimage { - let s in 0 .. T::MaxSize::get(); + let s in 0 .. MAX_SIZE; let caller = funded_account::("caller", 0); whitelist_account!(caller); let (preimage, hash) = sized_preimage_and_hash::(s); @@ -58,7 +58,7 @@ benchmarks! { } // Cheap note - will not reserve since it was requested. note_requested_preimage { - let s in 0 .. T::MaxSize::get(); + let s in 0 .. MAX_SIZE; let caller = funded_account::("caller", 0); whitelist_account!(caller); let (preimage, hash) = sized_preimage_and_hash::(s); @@ -69,7 +69,7 @@ benchmarks! { } // Cheap note - will not reserve since it's the manager. note_no_deposit_preimage { - let s in 0 .. T::MaxSize::get(); + let s in 0 .. MAX_SIZE; let (preimage, hash) = sized_preimage_and_hash::(s); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); }: note_preimage(T::ManagerOrigin::successful_origin(), preimage) @@ -101,10 +101,12 @@ benchmarks! { let (preimage, hash) = preimage_and_hash::(); let noter = funded_account::("noter", 0); whitelist_account!(noter); - assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter).into(), preimage)); + assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter.clone()).into(), preimage)); }: _(T::ManagerOrigin::successful_origin(), hash) verify { - assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + let deposit = T::BaseDeposit::get() + T::ByteDeposit::get() * MAX_SIZE.into(); + let s = RequestStatus::Requested { deposit: Some((noter, deposit)), count: 1, len: Some(MAX_SIZE) }; + assert_eq!(StatusFor::::get(&hash), Some(s)); } // Cheap request - would unreserve the deposit but none was held. request_no_deposit_preimage { @@ -112,14 +114,16 @@ benchmarks! { assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { - assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + let s = RequestStatus::Requested { deposit: None, count: 2, len: Some(MAX_SIZE) }; + assert_eq!(StatusFor::::get(&hash), Some(s)); } // Cheap request - the preimage is not yet noted, so deposit to unreserve. request_unnoted_preimage { let (_, hash) = preimage_and_hash::(); }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { - assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + let s = RequestStatus::Requested { deposit: None, count: 1, len: None }; + assert_eq!(StatusFor::::get(&hash), Some(s)); } // Cheap request - the preimage is already requested, so just a counter bump. request_requested_preimage { @@ -127,7 +131,8 @@ benchmarks! { assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { - assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(2))); + let s = RequestStatus::Requested { deposit: None, count: 2, len: None }; + assert_eq!(StatusFor::::get(&hash), Some(s)); } // Expensive unrequest - last reference and it's noted, so will destroy the preimage. @@ -154,7 +159,8 @@ benchmarks! { assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) verify { - assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + let s = RequestStatus::Requested { deposit: None, count: 1, len: None }; + assert_eq!(StatusFor::::get(&hash), Some(s)); } impl_benchmark_test_suite!(Preimage, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 90f5ac175f540..e899d3643dbbf 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -30,6 +30,7 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; #[cfg(test)] mod mock; #[cfg(test)] @@ -37,15 +38,18 @@ mod tests; pub mod weights; use sp_runtime::traits::{BadOrigin, Hash, Saturating}; -use sp_std::prelude::*; +use sp_std::{borrow::Cow, prelude::*}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::Pays, ensure, pallet_prelude::Get, - traits::{Currency, PreimageProvider, PreimageRecipient, ReservableCurrency}, - BoundedVec, + traits::{ + Currency, Defensive, FetchResult, Hash as PreimageHash, PreimageProvider, + PreimageRecipient, QueryPreimage, ReservableCurrency, StorePreimage, + }, + BoundedSlice, BoundedVec, }; use scale_info::TypeInfo; pub use weights::WeightInfo; @@ -59,20 +63,27 @@ pub use pallet::*; #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] pub enum RequestStatus { /// The associated preimage has not yet been requested by the system. The given deposit (if - /// some) is being held until either it becomes requested or the user retracts the primage. - Unrequested(Option<(AccountId, Balance)>), + /// some) is being held until either it becomes requested or the user retracts the preimage. + Unrequested { deposit: (AccountId, Balance), len: u32 }, /// There are a non-zero number of outstanding requests for this hash by this chain. If there - /// is a preimage registered, then it may be removed iff this counter becomes zero. - Requested(u32), + /// is a preimage registered, then `len` is `Some` and it may be removed iff this counter + /// becomes zero. + Requested { deposit: Option<(AccountId, Balance)>, count: u32, len: Option }, } type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +/// Maximum size of preimage we can store is 4mb. +const MAX_SIZE: u32 = 4 * 1024 * 1024; + #[frame_support::pallet] pub mod pallet { use super::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. @@ -88,9 +99,6 @@ pub mod pallet { /// manage existing preimages. type ManagerOrigin: EnsureOrigin; - /// Max size allowed for a preimage. - type MaxSize: Get; - /// The base deposit for placing a preimage on chain. type BaseDeposit: Get>; @@ -100,6 +108,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData); #[pallet::event] @@ -116,7 +125,7 @@ pub mod pallet { #[pallet::error] pub enum Error { /// Preimage is too large to store on-chain. - TooLarge, + TooBig, /// Preimage has already been noted on-chain. AlreadyNoted, /// The user is not authorized to perform this action. @@ -134,10 +143,9 @@ pub mod pallet { pub(super) type StatusFor = StorageMap<_, Identity, T::Hash, RequestStatus>>; - /// The preimages stored by this pallet. #[pallet::storage] pub(super) type PreimageFor = - StorageMap<_, Identity, T::Hash, BoundedVec>; + StorageMap<_, Identity, (T::Hash, u32), BoundedVec>>; #[pallet::call] impl Pallet { @@ -150,9 +158,7 @@ pub mod pallet { // We accept a signed origin which will pay a deposit, or a root origin where a deposit // is not taken. let maybe_sender = Self::ensure_signed_or_manager(origin)?; - let bounded_vec = - BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; - let system_requested = Self::note_bytes(bounded_vec, maybe_sender.as_ref())?; + let (system_requested, _) = Self::note_bytes(bytes.into(), maybe_sender.as_ref())?; if system_requested || maybe_sender.is_none() { Ok(Pays::No.into()) } else { @@ -161,6 +167,11 @@ pub mod pallet { } /// Clear an unrequested preimage from the runtime storage. + /// + /// If `len` is provided, then it will be a much cheaper operation. + /// + /// - `hash`: The hash of the preimage to be removed from the store. + /// - `len`: The length of the preimage of `hash`. #[pallet::weight(T::WeightInfo::unnote_preimage())] pub fn unnote_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { let maybe_sender = Self::ensure_signed_or_manager(origin)?; @@ -203,41 +214,46 @@ impl Pallet { /// Store some preimage on chain. /// + /// If `maybe_depositor` is `None` then it is also requested. If `Some`, then it is not. + /// /// We verify that the preimage is within the bounds of what the pallet supports. /// /// If the preimage was requested to be uploaded, then the user pays no deposits or tx fees. fn note_bytes( - preimage: BoundedVec, + preimage: Cow<[u8]>, maybe_depositor: Option<&T::AccountId>, - ) -> Result { + ) -> Result<(bool, T::Hash), DispatchError> { let hash = T::Hashing::hash(&preimage); - ensure!(!PreimageFor::::contains_key(hash), Error::::AlreadyNoted); + let len = preimage.len() as u32; + ensure!(len <= MAX_SIZE, Error::::TooBig); - // We take a deposit only if there is a provided depositor, and the preimage was not + // We take a deposit only if there is a provided depositor and the preimage was not // previously requested. This also allows the tx to pay no fee. - let was_requested = match (StatusFor::::get(hash), maybe_depositor) { - (Some(RequestStatus::Requested(..)), _) => true, - (Some(RequestStatus::Unrequested(..)), _) => + let status = match (StatusFor::::get(hash), maybe_depositor) { + (Some(RequestStatus::Requested { count, deposit, .. }), _) => + RequestStatus::Requested { count, deposit, len: Some(len) }, + (Some(RequestStatus::Unrequested { .. }), Some(_)) => return Err(Error::::AlreadyNoted.into()), - (None, None) => { - StatusFor::::insert(hash, RequestStatus::Unrequested(None)); - false - }, + (Some(RequestStatus::Unrequested { len, deposit }), None) => + RequestStatus::Requested { deposit: Some(deposit), count: 1, len: Some(len) }, + (None, None) => RequestStatus::Requested { count: 1, len: Some(len), deposit: None }, (None, Some(depositor)) => { let length = preimage.len() as u32; let deposit = T::BaseDeposit::get() .saturating_add(T::ByteDeposit::get().saturating_mul(length.into())); T::Currency::reserve(depositor, deposit)?; - let status = RequestStatus::Unrequested(Some((depositor.clone(), deposit))); - StatusFor::::insert(hash, status); - false + RequestStatus::Unrequested { deposit: (depositor.clone(), deposit), len } }, }; + let was_requested = matches!(status, RequestStatus::Requested { .. }); + StatusFor::::insert(hash, status); + + let _ = Self::insert(&hash, preimage) + .defensive_proof("Unable to insert. Logic error in `note_bytes`?"); - PreimageFor::::insert(hash, preimage); Self::deposit_event(Event::Noted { hash }); - Ok(was_requested) + Ok((was_requested, hash)) } // This function will add a hash to the list of requested preimages. @@ -245,19 +261,15 @@ impl Pallet { // If the preimage already exists before the request is made, the deposit for the preimage is // returned to the user, and removed from their management. fn do_request_preimage(hash: &T::Hash) { - let count = StatusFor::::get(hash).map_or(1, |x| match x { - RequestStatus::Requested(mut count) => { - count.saturating_inc(); - count - }, - RequestStatus::Unrequested(None) => 1, - RequestStatus::Unrequested(Some((owner, deposit))) => { - // Return the deposit - the preimage now has outstanding requests. - T::Currency::unreserve(&owner, deposit); - 1 - }, - }); - StatusFor::::insert(hash, RequestStatus::Requested(count)); + let (count, len, deposit) = + StatusFor::::get(hash).map_or((1, None, None), |x| match x { + RequestStatus::Requested { mut count, len, deposit } => { + count.saturating_inc(); + (count, len, deposit) + }, + RequestStatus::Unrequested { deposit, len } => (1, Some(len), Some(deposit)), + }); + StatusFor::::insert(hash, RequestStatus::Requested { count, len, deposit }); if count == 1 { Self::deposit_event(Event::Requested { hash: *hash }); } @@ -265,6 +277,8 @@ impl Pallet { // Clear a preimage from the storage of the chain, returning any deposit that may be reserved. // + // If `len` is provided, it will be a much cheaper operation. + // // If `maybe_owner` is provided, we verify that it is the correct owner before clearing the // data. fn do_unnote_preimage( @@ -272,51 +286,101 @@ impl Pallet { maybe_check_owner: Option, ) -> DispatchResult { match StatusFor::::get(hash).ok_or(Error::::NotNoted)? { - RequestStatus::Unrequested(Some((owner, deposit))) => { + RequestStatus::Requested { deposit: Some((owner, deposit)), count, len } => { ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::::NotAuthorized); T::Currency::unreserve(&owner, deposit); + StatusFor::::insert( + hash, + RequestStatus::Requested { deposit: None, count, len }, + ); + Ok(()) }, - RequestStatus::Unrequested(None) => { + RequestStatus::Requested { deposit: None, .. } => { ensure!(maybe_check_owner.is_none(), Error::::NotAuthorized); + Self::do_unrequest_preimage(hash) + }, + RequestStatus::Unrequested { deposit: (owner, deposit), len } => { + ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::::NotAuthorized); + T::Currency::unreserve(&owner, deposit); + StatusFor::::remove(hash); + + Self::remove(hash, len); + Self::deposit_event(Event::Cleared { hash: *hash }); + Ok(()) }, - RequestStatus::Requested(_) => return Err(Error::::Requested.into()), } - StatusFor::::remove(hash); - PreimageFor::::remove(hash); - Self::deposit_event(Event::Cleared { hash: *hash }); - Ok(()) } /// Clear a preimage request. fn do_unrequest_preimage(hash: &T::Hash) -> DispatchResult { match StatusFor::::get(hash).ok_or(Error::::NotRequested)? { - RequestStatus::Requested(mut count) if count > 1 => { + RequestStatus::Requested { mut count, len, deposit } if count > 1 => { count.saturating_dec(); - StatusFor::::insert(hash, RequestStatus::Requested(count)); + StatusFor::::insert(hash, RequestStatus::Requested { count, len, deposit }); }, - RequestStatus::Requested(count) => { + RequestStatus::Requested { count, len, deposit } => { debug_assert!(count == 1, "preimage request counter at zero?"); - PreimageFor::::remove(hash); - StatusFor::::remove(hash); - Self::deposit_event(Event::Cleared { hash: *hash }); + match (len, deposit) { + // Preimage was never noted. + (None, _) => StatusFor::::remove(hash), + // Preimage was noted without owner - just remove it. + (Some(len), None) => { + Self::remove(hash, len); + StatusFor::::remove(hash); + Self::deposit_event(Event::Cleared { hash: *hash }); + }, + // Preimage was noted with owner - move to unrequested so they can get refund. + (Some(len), Some(deposit)) => { + StatusFor::::insert(hash, RequestStatus::Unrequested { deposit, len }); + }, + } }, - RequestStatus::Unrequested(_) => return Err(Error::::NotRequested.into()), + RequestStatus::Unrequested { .. } => return Err(Error::::NotRequested.into()), } Ok(()) } + + fn insert(hash: &T::Hash, preimage: Cow<[u8]>) -> Result<(), ()> { + BoundedSlice::>::try_from(preimage.as_ref()) + .map(|s| PreimageFor::::insert((hash, s.len() as u32), s)) + } + + fn remove(hash: &T::Hash, len: u32) { + PreimageFor::::remove((hash, len)) + } + + fn have(hash: &T::Hash) -> bool { + Self::len(hash).is_some() + } + + fn len(hash: &T::Hash) -> Option { + use RequestStatus::*; + match StatusFor::::get(hash) { + Some(Requested { len: Some(len), .. }) | Some(Unrequested { len, .. }) => Some(len), + _ => None, + } + } + + fn fetch(hash: &T::Hash, len: Option) -> FetchResult { + let len = len.or_else(|| Self::len(hash)).ok_or(DispatchError::Unavailable)?; + PreimageFor::::get((hash, len)) + .map(|p| p.into_inner()) + .map(Into::into) + .ok_or(DispatchError::Unavailable) + } } impl PreimageProvider for Pallet { fn have_preimage(hash: &T::Hash) -> bool { - PreimageFor::::contains_key(hash) + Self::have(hash) } fn preimage_requested(hash: &T::Hash) -> bool { - matches!(StatusFor::::get(hash), Some(RequestStatus::Requested(..))) + matches!(StatusFor::::get(hash), Some(RequestStatus::Requested { .. })) } fn get_preimage(hash: &T::Hash) -> Option> { - PreimageFor::::get(hash).map(|preimage| preimage.to_vec()) + Self::fetch(hash, None).ok().map(Cow::into_owned) } fn request_preimage(hash: &T::Hash) { @@ -330,15 +394,60 @@ impl PreimageProvider for Pallet { } impl PreimageRecipient for Pallet { - type MaxSize = T::MaxSize; + type MaxSize = ConstU32; // 2**22 fn note_preimage(bytes: BoundedVec) { // We don't really care if this fails, since that's only the case if someone else has // already noted it. - let _ = Self::note_bytes(bytes, None); + let _ = Self::note_bytes(bytes.into_inner().into(), None); } fn unnote_preimage(hash: &T::Hash) { + // Should never fail if authorization check is skipped. + let res = Self::do_unrequest_preimage(hash); + debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?"); + } +} + +impl> QueryPreimage for Pallet { + fn len(hash: &T::Hash) -> Option { + Pallet::::len(hash) + } + + fn fetch(hash: &T::Hash, len: Option) -> FetchResult { + Pallet::::fetch(hash, len) + } + + fn is_requested(hash: &T::Hash) -> bool { + matches!(StatusFor::::get(hash), Some(RequestStatus::Requested { .. })) + } + + fn request(hash: &T::Hash) { + Self::do_request_preimage(hash) + } + + fn unrequest(hash: &T::Hash) { + let res = Self::do_unrequest_preimage(hash); + debug_assert!(res.is_ok(), "do_unrequest_preimage failed - counter underflow?"); + } +} + +impl> StorePreimage for Pallet { + const MAX_LENGTH: usize = MAX_SIZE as usize; + + fn note(bytes: Cow<[u8]>) -> Result { + // We don't really care if this fails, since that's only the case if someone else has + // already noted it. + let maybe_hash = Self::note_bytes(bytes, None).map(|(_, h)| h); + // Map to the correct trait error. + if maybe_hash == Err(DispatchError::from(Error::::TooBig)) { + Err(DispatchError::Exhausted) + } else { + maybe_hash + } + } + + fn unnote(hash: &T::Hash) { // Should never fail if authorization check is skipped. let res = Self::do_unnote_preimage(hash, None); debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?"); diff --git a/frame/preimage/src/migration.rs b/frame/preimage/src/migration.rs new file mode 100644 index 0000000000000..a5d15c23c758a --- /dev/null +++ b/frame/preimage/src/migration.rs @@ -0,0 +1,263 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Storage migrations for the preimage pallet. + +use super::*; +use frame_support::{ + storage_alias, + traits::{ConstU32, OnRuntimeUpgrade}, +}; +use sp_std::collections::btree_map::BTreeMap; + +/// The log target. +const TARGET: &'static str = "runtime::preimage::migration::v1"; + +/// The original data layout of the preimage pallet without a specific version number. +mod v0 { + use super::*; + + #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] + pub enum RequestStatus { + Unrequested(Option<(AccountId, Balance)>), + Requested(u32), + } + + #[storage_alias] + pub type PreimageFor = StorageMap< + Pallet, + Identity, + ::Hash, + BoundedVec>, + >; + + #[storage_alias] + pub type StatusFor = StorageMap< + Pallet, + Identity, + ::Hash, + RequestStatus<::AccountId, BalanceOf>, + >; + + /// Returns the number of images or `None` if the storage is corrupted. + #[cfg(feature = "try-runtime")] + pub fn image_count() -> Option { + let images = v0::PreimageFor::::iter_values().count() as u32; + let status = v0::StatusFor::::iter_values().count() as u32; + + if images == status { + Some(images) + } else { + None + } + } +} + +pub mod v1 { + use super::*; + + /// Migration for moving preimage from V0 to V1 storage. + /// + /// Note: This needs to be run with the same hashing algorithm as before + /// since it is not re-hashing the preimages. + pub struct Migration(sp_std::marker::PhantomData); + + impl OnRuntimeUpgrade for Migration { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + assert_eq!(StorageVersion::get::>(), 0, "can only upgrade from version 0"); + + let images = v0::image_count::().expect("v0 storage corrupted"); + log::info!(target: TARGET, "Migrating {} images", &images); + Ok((images as u32).encode()) + } + + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + if StorageVersion::get::>() != 0 { + log::warn!( + target: TARGET, + "skipping MovePreimagesIntoBuckets: executed on wrong storage version.\ + Expected version 0" + ); + return weight + } + + let status = v0::StatusFor::::drain().collect::>(); + weight.saturating_accrue(T::DbWeight::get().reads(status.len() as u64)); + + let preimages = v0::PreimageFor::::drain().collect::>(); + weight.saturating_accrue(T::DbWeight::get().reads(preimages.len() as u64)); + + for (hash, status) in status.into_iter() { + let preimage = if let Some(preimage) = preimages.get(&hash) { + preimage + } else { + log::error!(target: TARGET, "preimage not found for hash {:?}", &hash); + continue + }; + let len = preimage.len() as u32; + if len > MAX_SIZE { + log::error!( + target: TARGET, + "preimage too large for hash {:?}, len: {}", + &hash, + len + ); + continue + } + + let status = match status { + v0::RequestStatus::Unrequested(deposit) => match deposit { + Some(deposit) => RequestStatus::Unrequested { deposit, len }, + // `None` depositor becomes system-requested. + None => + RequestStatus::Requested { deposit: None, count: 1, len: Some(len) }, + }, + v0::RequestStatus::Requested(count) if count == 0 => { + log::error!(target: TARGET, "preimage has counter of zero: {:?}", hash); + continue + }, + v0::RequestStatus::Requested(count) => + RequestStatus::Requested { deposit: None, count, len: Some(len) }, + }; + log::trace!(target: TARGET, "Moving preimage {:?} with len {}", hash, len); + + crate::StatusFor::::insert(hash, status); + crate::PreimageFor::::insert(&(hash, len), preimage); + + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + StorageVersion::new(1).put::>(); + + weight.saturating_add(T::DbWeight::get().writes(1)) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let old_images: u32 = + Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + let new_images = image_count::().expect("V1 storage corrupted"); + + if new_images != old_images { + log::error!( + target: TARGET, + "migrated {} images, expected {}", + new_images, + old_images + ); + } + assert_eq!(StorageVersion::get::>(), 1, "must upgrade"); + Ok(()) + } + } + + /// Returns the number of images or `None` if the storage is corrupted. + #[cfg(feature = "try-runtime")] + pub fn image_count() -> Option { + // Use iter_values() to ensure that the values are decodable. + let images = crate::PreimageFor::::iter_values().count() as u32; + let status = crate::StatusFor::::iter_values().count() as u32; + + if images == status { + Some(images) + } else { + None + } + } +} + +#[cfg(test)] +#[cfg(feature = "try-runtime")] +mod test { + use super::*; + use crate::mock::{Test as T, *}; + + use frame_support::bounded_vec; + + #[test] + fn migration_works() { + new_test_ext().execute_with(|| { + assert_eq!(StorageVersion::get::>(), 0); + // Insert some preimages into the v0 storage: + + // Case 1: Unrequested without deposit + let (p, h) = preimage::(128); + v0::PreimageFor::::insert(h, p); + v0::StatusFor::::insert(h, v0::RequestStatus::Unrequested(None)); + // Case 2: Unrequested with deposit + let (p, h) = preimage::(1024); + v0::PreimageFor::::insert(h, p); + v0::StatusFor::::insert(h, v0::RequestStatus::Unrequested(Some((1, 1)))); + // Case 3: Requested by 0 (invalid) + let (p, h) = preimage::(8192); + v0::PreimageFor::::insert(h, p); + v0::StatusFor::::insert(h, v0::RequestStatus::Requested(0)); + // Case 4: Requested by 10 + let (p, h) = preimage::(65536); + v0::PreimageFor::::insert(h, p); + v0::StatusFor::::insert(h, v0::RequestStatus::Requested(10)); + + assert_eq!(v0::image_count::(), Some(4)); + assert_eq!(v1::image_count::(), None, "V1 storage should be corrupted"); + + let state = v1::Migration::::pre_upgrade().unwrap(); + let _w = v1::Migration::::on_runtime_upgrade(); + v1::Migration::::post_upgrade(state).unwrap(); + + // V0 and V1 share the same prefix, so `iter_values` still counts the same. + assert_eq!(v0::image_count::(), Some(3)); + assert_eq!(v1::image_count::(), Some(3)); // One gets skipped therefore 3. + assert_eq!(StorageVersion::get::>(), 1); + + // Case 1: Unrequested without deposit becomes system-requested + let (p, h) = preimage::(128); + assert_eq!(crate::PreimageFor::::get(&(h, 128)), Some(p)); + assert_eq!( + crate::StatusFor::::get(h), + Some(RequestStatus::Requested { deposit: None, count: 1, len: Some(128) }) + ); + // Case 2: Unrequested with deposit becomes unrequested + let (p, h) = preimage::(1024); + assert_eq!(crate::PreimageFor::::get(&(h, 1024)), Some(p)); + assert_eq!( + crate::StatusFor::::get(h), + Some(RequestStatus::Unrequested { deposit: (1, 1), len: 1024 }) + ); + // Case 3: Requested by 0 should be skipped + let (_, h) = preimage::(8192); + assert_eq!(crate::PreimageFor::::get(&(h, 8192)), None); + assert_eq!(crate::StatusFor::::get(h), None); + // Case 4: Requested by 10 becomes requested by 10 + let (p, h) = preimage::(65536); + assert_eq!(crate::PreimageFor::::get(&(h, 65536)), Some(p)); + assert_eq!( + crate::StatusFor::::get(h), + Some(RequestStatus::Requested { deposit: None, count: 10, len: Some(65536) }) + ); + }); + } + + /// Returns a preimage with a given size and its hash. + fn preimage( + len: usize, + ) -> (BoundedVec>, ::Hash) { + let p = bounded_vec![1; len]; + let h = ::Hashing::hash_of(&p); + (p, h) + } +} diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index e12598a35b4bb..ce74ea65bd8aa 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -105,7 +105,6 @@ impl Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureSignedBy; - type MaxSize = ConstU32<1024>; type BaseDeposit = ConstU64<2>; type ByteDeposit = ConstU64<1>; } diff --git a/frame/preimage/src/tests.rs b/frame/preimage/src/tests.rs index e6b64ae16dd8c..f480b9c36b670 100644 --- a/frame/preimage/src/tests.rs +++ b/frame/preimage/src/tests.rs @@ -17,11 +17,35 @@ //! # Scheduler tests. +#![cfg(test)] + use super::*; use crate::mock::*; -use frame_support::{assert_noop, assert_ok}; +use frame_support::{ + assert_err, assert_noop, assert_ok, assert_storage_noop, bounded_vec, + traits::{Bounded, BoundedInline, Hash as PreimageHash}, + StorageNoopGuard, +}; use pallet_balances::Error as BalancesError; +use sp_core::{blake2_256, H256}; + +/// Returns one `Inline`, `Lookup` and `Legacy` item each with different data and hash. +pub fn make_bounded_values() -> (Bounded>, Bounded>, Bounded>) { + let data: BoundedInline = bounded_vec![1]; + let inline = Bounded::>::Inline(data); + + let data = vec![1, 2]; + let hash: H256 = blake2_256(&data[..]).into(); + let len = data.len() as u32; + let lookup = Bounded::>::unrequested(hash, len); + + let data = vec![1, 2, 3]; + let hash: H256 = blake2_256(&data[..]).into(); + let legacy = Bounded::>::Legacy { hash, dummy: Default::default() }; + + (inline, lookup, legacy) +} #[test] fn user_note_preimage_works() { @@ -56,10 +80,7 @@ fn manager_note_preimage_works() { assert!(Preimage::have_preimage(&h)); assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); - assert_noop!( - Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]), - Error::::AlreadyNoted - ); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); }); } @@ -130,14 +151,16 @@ fn requested_then_noted_preimage_cannot_be_unnoted() { new_test_ext().execute_with(|| { assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); - assert_noop!( - Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])), - Error::::Requested - ); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1]))); + // it's still here. let h = hashed([1]); assert!(Preimage::have_preimage(&h)); assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + + // now it's gone + assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert!(!Preimage::have_preimage(&hashed([1]))); }); } @@ -145,15 +168,16 @@ fn requested_then_noted_preimage_cannot_be_unnoted() { fn request_note_order_makes_no_difference() { let one_way = new_test_ext().execute_with(|| { assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); - assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), ) }); new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); let other_way = ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), @@ -189,6 +213,7 @@ fn request_user_note_order_makes_no_difference() { new_test_ext().execute_with(|| { assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); let other_way = ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), @@ -226,8 +251,240 @@ fn user_noted_then_requested_preimage_is_refunded_once_only() { assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); // Still have reserve from `vec[1; 3]`. assert_eq!(Balances::reserved_balance(2), 5); assert_eq!(Balances::free_balance(2), 95); }); } + +#[test] +fn noted_preimage_use_correct_map() { + new_test_ext().execute_with(|| { + // Add one preimage per bucket... + for i in 0..7 { + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![0; 128 << (i * 2)])); + } + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![0; MAX_SIZE as usize])); + assert_eq!(PreimageFor::::iter().count(), 8); + + // All are present + assert_eq!(StatusFor::::iter().count(), 8); + + // Now start removing them again... + for i in 0..7 { + assert_ok!(Preimage::unnote_preimage( + RuntimeOrigin::signed(1), + hashed(vec![0; 128 << (i * 2)]) + )); + } + assert_eq!(PreimageFor::::iter().count(), 1); + assert_ok!(Preimage::unnote_preimage( + RuntimeOrigin::signed(1), + hashed(vec![0; MAX_SIZE as usize]) + )); + assert_eq!(PreimageFor::::iter().count(), 0); + + // All are gone + assert_eq!(StatusFor::::iter().count(), 0); + }); +} + +/// The `StorePreimage` and `QueryPreimage` traits work together. +#[test] +fn query_and_store_preimage_workflow() { + new_test_ext().execute_with(|| { + let _guard = StorageNoopGuard::default(); + let data: Vec = vec![1; 512]; + let encoded = data.encode(); + + // Bound an unbound value. + let bound = Preimage::bound(data.clone()).unwrap(); + let (len, hash) = (bound.len().unwrap(), bound.hash()); + + assert_eq!(hash, blake2_256(&encoded).into()); + assert_eq!(bound.len(), Some(len)); + assert!(bound.lookup_needed(), "Should not be Inlined"); + assert_eq!(bound.lookup_len(), Some(len)); + + // The value is requested and available. + assert!(Preimage::is_requested(&hash)); + assert!(::have(&bound)); + assert_eq!(Preimage::len(&hash), Some(len)); + + // It can be fetched with length. + assert_eq!(Preimage::fetch(&hash, Some(len)).unwrap(), encoded); + // ... and without length. + assert_eq!(Preimage::fetch(&hash, None).unwrap(), encoded); + // ... but not with wrong length. + assert_err!(Preimage::fetch(&hash, Some(0)), DispatchError::Unavailable); + + // It can be peeked and decoded correctly. + assert_eq!(Preimage::peek::>(&bound).unwrap(), (data.clone(), Some(len))); + // Request it two more times. + assert_eq!(Preimage::pick::>(hash, len), bound); + Preimage::request(&hash); + // It is requested thrice. + assert!(matches!( + StatusFor::::get(&hash).unwrap(), + RequestStatus::Requested { count: 3, .. } + )); + + // It can be realized and decoded correctly. + assert_eq!(Preimage::realize::>(&bound).unwrap(), (data.clone(), Some(len))); + assert!(matches!( + StatusFor::::get(&hash).unwrap(), + RequestStatus::Requested { count: 2, .. } + )); + // Dropping should unrequest. + Preimage::drop(&bound); + assert!(matches!( + StatusFor::::get(&hash).unwrap(), + RequestStatus::Requested { count: 1, .. } + )); + + // Is still available. + assert!(::have(&bound)); + // Manually unnote it. + Preimage::unnote(&hash); + // Is not available anymore. + assert!(!::have(&bound)); + assert_err!(Preimage::fetch(&hash, Some(len)), DispatchError::Unavailable); + // And not requested since the traits assume permissioned origin. + assert!(!Preimage::is_requested(&hash)); + + // No storage changes remain. Checked by `StorageNoopGuard`. + }); +} + +/// The request function behaves as expected. +#[test] +fn query_preimage_request_works() { + new_test_ext().execute_with(|| { + let _guard = StorageNoopGuard::default(); + let data: Vec = vec![1; 10]; + let hash: PreimageHash = blake2_256(&data[..]).into(); + + // Request the preimage. + ::request(&hash); + + // The preimage is requested with unknown length and cannot be fetched. + assert!(::is_requested(&hash)); + assert!(::len(&hash).is_none()); + assert_noop!(::fetch(&hash, None), DispatchError::Unavailable); + + // Request again. + ::request(&hash); + // The preimage is still requested. + assert!(::is_requested(&hash)); + assert!(::len(&hash).is_none()); + assert_noop!(::fetch(&hash, None), DispatchError::Unavailable); + // But there is only one entry in the map. + assert_eq!(StatusFor::::iter().count(), 1); + + // Un-request the preimage. + ::unrequest(&hash); + // It is still requested. + assert!(::is_requested(&hash)); + // Un-request twice. + ::unrequest(&hash); + // It is not requested anymore. + assert!(!::is_requested(&hash)); + // And there is no entry in the map. + assert_eq!(StatusFor::::iter().count(), 0); + }); +} + +/// The `QueryPreimage` functions can be used together with `Bounded` values. +#[test] +fn query_preimage_hold_and_drop_work() { + new_test_ext().execute_with(|| { + let _guard = StorageNoopGuard::default(); + let (inline, lookup, legacy) = make_bounded_values(); + + // `hold` does nothing for `Inline` values. + assert_storage_noop!(::hold(&inline)); + // `hold` requests `Lookup` values. + ::hold(&lookup); + assert!(::is_requested(&lookup.hash())); + // `hold` requests `Legacy` values. + ::hold(&legacy); + assert!(::is_requested(&legacy.hash())); + + // There are two values requested in total. + assert_eq!(StatusFor::::iter().count(), 2); + + // Cleanup by dropping both. + ::drop(&lookup); + assert!(!::is_requested(&lookup.hash())); + ::drop(&legacy); + assert!(!::is_requested(&legacy.hash())); + + // There are no values requested anymore. + assert_eq!(StatusFor::::iter().count(), 0); + }); +} + +/// The `StorePreimage` trait works as expected. +#[test] +fn store_preimage_basic_works() { + new_test_ext().execute_with(|| { + let _guard = StorageNoopGuard::default(); + let data: Vec = vec![1; 512]; // Too large to inline. + let encoded = Cow::from(data.encode()); + + // Bound the data. + let bound = ::bound(data.clone()).unwrap(); + // The preimage can be peeked. + assert_ok!(::peek(&bound)); + // Un-note the preimage. + ::unnote(&bound.hash()); + // The preimage cannot be peeked anymore. + assert_err!(::peek(&bound), DispatchError::Unavailable); + // Noting the wrong pre-image does not make it peek-able. + assert_ok!(::note(Cow::Borrowed(&data))); + assert_err!(::peek(&bound), DispatchError::Unavailable); + + // Manually note the preimage makes it peek-able again. + assert_ok!(::note(encoded.clone())); + // Noting again works. + assert_ok!(::note(encoded)); + assert_ok!(::peek(&bound)); + + // Cleanup. + ::unnote(&bound.hash()); + let data_hash = blake2_256(&data); + ::unnote(&data_hash.into()); + + // No storage changes remain. Checked by `StorageNoopGuard`. + }); +} + +#[test] +fn store_preimage_note_too_large_errors() { + new_test_ext().execute_with(|| { + // Works with `MAX_LENGTH`. + let len = ::MAX_LENGTH; + let data = vec![0u8; len]; + assert_ok!(::note(data.into())); + + // Errors with `MAX_LENGTH+1`. + let data = vec![0u8; len + 1]; + assert_err!(::note(data.into()), DispatchError::Exhausted); + }); +} + +#[test] +fn store_preimage_bound_too_large_errors() { + new_test_ext().execute_with(|| { + // Using `MAX_LENGTH` number of bytes in a vector does not work + // since SCALE prepends the length. + let len = ::MAX_LENGTH; + let data: Vec = vec![0; len]; + assert_err!(::bound(data.clone()), DispatchError::Exhausted); + + // Works with `MAX_LENGTH-4`. + let data: Vec = vec![0; len - 4]; + assert_ok!(::bound(data.clone())); + }); +} diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index ad9e3e569e733..186c41b798c6b 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -18,22 +18,24 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_preimage // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --pallet=pallet_preimage +// --chain=dev // --output=./frame/preimage/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -61,88 +63,90 @@ pub trait WeightInfo { /// Weights for pallet_preimage using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(32_591_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:0) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(23_350_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(1_681 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:0) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(21_436_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - Weight::from_ref_time(44_380_000 as u64) + Weight::from_ref_time(44_567_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - Weight::from_ref_time(30_280_000 as u64) + Weight::from_ref_time(30_065_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - Weight::from_ref_time(42_809_000 as u64) + Weight::from_ref_time(28_470_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - Weight::from_ref_time(28_964_000 as u64) + Weight::from_ref_time(14_601_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - Weight::from_ref_time(17_555_000 as u64) + Weight::from_ref_time(20_121_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - Weight::from_ref_time(7_745_000 as u64) + Weight::from_ref_time(9_440_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - Weight::from_ref_time(29_758_000 as u64) + Weight::from_ref_time(29_013_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - Weight::from_ref_time(18_360_000 as u64) + Weight::from_ref_time(9_223_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - Weight::from_ref_time(7_439_000 as u64) + Weight::from_ref_time(9_252_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -150,88 +154,90 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(32_591_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:0) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(23_350_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(1_681 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:0) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(21_436_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - Weight::from_ref_time(44_380_000 as u64) + Weight::from_ref_time(44_567_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - Weight::from_ref_time(30_280_000 as u64) + Weight::from_ref_time(30_065_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - Weight::from_ref_time(42_809_000 as u64) + Weight::from_ref_time(28_470_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - Weight::from_ref_time(28_964_000 as u64) + Weight::from_ref_time(14_601_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - Weight::from_ref_time(17_555_000 as u64) + Weight::from_ref_time(20_121_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - Weight::from_ref_time(7_745_000 as u64) + Weight::from_ref_time(9_440_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - Weight::from_ref_time(29_758_000 as u64) + Weight::from_ref_time(29_013_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - Weight::from_ref_time(18_360_000 as u64) + Weight::from_ref_time(9_223_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - Weight::from_ref_time(7_439_000 as u64) + Weight::from_ref_time(9_252_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index 0b6b7b0f51d9a..18d3d48dc024c 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -452,7 +452,7 @@ pub mod pallet { ensure!(!friends.is_empty(), Error::::NotEnoughFriends); ensure!(threshold as usize <= friends.len(), Error::::NotEnoughFriends); let bounded_friends: FriendsOf = - friends.try_into().map_err(|()| Error::::MaxFriends)?; + friends.try_into().map_err(|_| Error::::MaxFriends)?; ensure!(Self::is_sorted_and_unique(&bounded_friends), Error::::NotSorted); // Total deposit is base fee + number of friends * factor fee let friend_deposit = T::FriendDepositFactor::get() @@ -554,7 +554,7 @@ pub mod pallet { Err(pos) => active_recovery .friends .try_insert(pos, who.clone()) - .map_err(|()| Error::::MaxFriends)?, + .map_err(|_| Error::::MaxFriends)?, } // Update storage with the latest details >::insert(&lost, &rescuer, active_recovery); diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 45ec894e2c2c0..bc6fb31bf1127 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -24,10 +24,10 @@ use frame_benchmarking::{account, benchmarks_instance_pallet, whitelist_account} use frame_support::{ assert_ok, dispatch::UnfilteredDispatchable, - traits::{Currency, EnsureOrigin}, + traits::{Bounded, Currency, EnsureOrigin}, }; use frame_system::RawOrigin; -use sp_runtime::traits::{Bounded, Hash}; +use sp_runtime::traits::Bounded as ArithBounded; const SEED: u32 = 0; @@ -42,6 +42,12 @@ fn funded_account, I: 'static>(name: &'static str, index: u32) -> T caller } +fn dummy_call, I: 'static>() -> Bounded<>::RuntimeCall> { + let inner = frame_system::Call::remark { remark: vec![] }; + let call = >::RuntimeCall::from(inner); + T::Preimages::bound(call).unwrap() +} + fn create_referendum, I: 'static>() -> (T::RuntimeOrigin, ReferendumIndex) { let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin(); if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { @@ -50,9 +56,9 @@ fn create_referendum, I: 'static>() -> (T::RuntimeOrigin, Referendu } let proposal_origin = Box::new(RawOrigin::Root.into()); - let proposal_hash = T::Hashing::hash_of(&0); + let proposal = dummy_call::(); let enactment_moment = DispatchTime::After(0u32.into()); - let call = Call::::submit { proposal_origin, proposal_hash, enactment_moment }; + let call = crate::Call::::submit { proposal_origin, proposal, enactment_moment }; assert_ok!(call.dispatch_bypass_filter(origin.clone())); let index = ReferendumCount::::get() - 1; (origin, index) @@ -196,7 +202,7 @@ benchmarks_instance_pallet! { }: _( origin, Box::new(RawOrigin::Root.into()), - T::Hashing::hash_of(&0), + dummy_call::(), DispatchTime::After(0u32.into()) ) verify { let index = ReferendumCount::::get().checked_sub(1).unwrap(); diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 739f0dbc30ed4..1bdc19d49c414 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -69,11 +69,11 @@ use frame_support::{ ensure, traits::{ schedule::{ - v2::{Anon as ScheduleAnon, Named as ScheduleNamed}, - DispatchTime, MaybeHashed, + v3::{Anon as ScheduleAnon, Named as ScheduleNamed}, + DispatchTime, }, - Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, - ReservableCurrency, VoteTally, + Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, + ReservableCurrency, StorePreimage, VoteTally, }, BoundedVec, }; @@ -92,10 +92,10 @@ use self::branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch}; pub use self::{ pallet::*, types::{ - BalanceOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted, - NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, ReferendumInfoOf, - ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, TrackIdOf, TrackInfo, - TrackInfoOf, TracksInfo, VotesOf, + BalanceOf, BoundedCallOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, + InsertSorted, NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, + ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, + TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf, }, weights::WeightInfo, }; @@ -149,23 +149,16 @@ pub mod pallet { // System level stuff. type RuntimeCall: Parameter + Dispatchable - + From>; + + From> + + IsType<::RuntimeCall> + + From>; type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// The Scheduler. - type Scheduler: ScheduleAnon< - Self::BlockNumber, - CallOf, - PalletsOriginOf, - Hash = Self::Hash, - > + ScheduleNamed< - Self::BlockNumber, - CallOf, - PalletsOriginOf, - Hash = Self::Hash, - >; + type Scheduler: ScheduleAnon, PalletsOriginOf> + + ScheduleNamed, PalletsOriginOf>; /// Currency type for this pallet. type Currency: ReservableCurrency; // Origins and unbalances. @@ -221,6 +214,9 @@ pub mod pallet { Self::BlockNumber, RuntimeOrigin = ::PalletsOrigin, >; + + /// The preimage provider. + type Preimages: QueryPreimage + StorePreimage; } /// The next free referendum index, aka the number of referenda started so far. @@ -259,8 +255,8 @@ pub mod pallet { index: ReferendumIndex, /// The track (and by extension proposal dispatch origin) of this referendum. track: TrackIdOf, - /// The hash of the proposal up for referendum. - proposal_hash: T::Hash, + /// The proposal for the referendum. + proposal: BoundedCallOf, }, /// The decision deposit has been placed. DecisionDepositPlaced { @@ -293,8 +289,8 @@ pub mod pallet { index: ReferendumIndex, /// The track (and by extension proposal dispatch origin) of this referendum. track: TrackIdOf, - /// The hash of the proposal up for referendum. - proposal_hash: T::Hash, + /// The proposal for the referendum. + proposal: BoundedCallOf, /// The current tally of votes in this referendum. tally: T::Tally, }, @@ -381,7 +377,7 @@ pub mod pallet { /// - `origin`: must be `SubmitOrigin` and the account must have `SubmissionDeposit` funds /// available. /// - `proposal_origin`: The origin from which the proposal should be executed. - /// - `proposal_hash`: The hash of the proposal preimage. + /// - `proposal`: The proposal. /// - `enactment_moment`: The moment that the proposal should be enacted. /// /// Emits `Submitted`. @@ -389,7 +385,7 @@ pub mod pallet { pub fn submit( origin: OriginFor, proposal_origin: Box>, - proposal_hash: T::Hash, + proposal: BoundedCallOf, enactment_moment: DispatchTime, ) -> DispatchResult { let who = T::SubmitOrigin::ensure_origin(origin)?; @@ -403,11 +399,12 @@ pub mod pallet { r }); let now = frame_system::Pallet::::block_number(); - let nudge_call = Call::nudge_referendum { index }; + let nudge_call = + T::Preimages::bound(CallOf::::from(Call::nudge_referendum { index }))?; let status = ReferendumStatus { track, origin: *proposal_origin, - proposal_hash, + proposal: proposal.clone(), enactment: enactment_moment, submitted: now, submission_deposit, @@ -419,7 +416,7 @@ pub mod pallet { }; ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); - Self::deposit_event(Event::::Submitted { index, track, proposal_hash }); + Self::deposit_event(Event::::Submitted { index, track, proposal }); Ok(()) } @@ -651,7 +648,8 @@ impl, I: 'static> Polling for Pallet { let mut status = ReferendumStatusOf:: { track: class, origin: frame_support::dispatch::RawOrigin::Root.into(), - proposal_hash: ::hash_of(&index), + proposal: T::Preimages::bound(CallOf::::from(Call::nudge_referendum { index })) + .map_err(|_| ())?, enactment: DispatchTime::After(Zero::zero()), submitted: now, submission_deposit: Deposit { who: dummy_account_id, amount: Zero::zero() }, @@ -709,18 +707,18 @@ impl, I: 'static> Pallet { track: &TrackInfoOf, desired: DispatchTime, origin: PalletsOriginOf, - call_hash: T::Hash, + call: BoundedCallOf, ) { let now = frame_system::Pallet::::block_number(); let earliest_allowed = now.saturating_add(track.min_enactment_period); let desired = desired.evaluate(now); let ok = T::Scheduler::schedule_named( - (ASSEMBLY_ID, "enactment", index).encode(), + (ASSEMBLY_ID, "enactment", index).using_encoded(sp_io::hashing::blake2_256), DispatchTime::At(desired.max(earliest_allowed)), None, 63, origin, - MaybeHashed::Hash(call_hash), + call, ) .is_ok(); debug_assert!(ok, "LOGIC ERROR: bake_referendum/schedule_named failed"); @@ -728,7 +726,7 @@ impl, I: 'static> Pallet { /// Set an alarm to dispatch `call` at block number `when`. fn set_alarm( - call: impl Into>, + call: BoundedCallOf, when: T::BlockNumber, ) -> Option<(T::BlockNumber, ScheduleAddressOf)> { let alarm_interval = T::AlarmInterval::get().max(One::one()); @@ -739,7 +737,7 @@ impl, I: 'static> Pallet { None, 128u8, frame_system::RawOrigin::Root.into(), - MaybeHashed::Value(call.into()), + call, ) .ok() .map(|x| (when, x)); @@ -776,7 +774,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::::DecisionStarted { index, tally: status.tally.clone(), - proposal_hash: status.proposal_hash, + proposal: status.proposal.clone(), track: status.track, }); let confirming = if is_passing { @@ -843,12 +841,21 @@ impl, I: 'static> Pallet { let alarm_interval = T::AlarmInterval::get().max(One::one()); let when = (next_block + alarm_interval - One::one()) / alarm_interval * alarm_interval; + let call = match T::Preimages::bound(CallOf::::from(Call::one_fewer_deciding { + track, + })) { + Ok(c) => c, + Err(_) => { + debug_assert!(false, "Unable to create a bounded call from `one_fewer_deciding`??",); + return + }, + }; let maybe_result = T::Scheduler::schedule( DispatchTime::At(when), None, 128u8, frame_system::RawOrigin::Root.into(), - MaybeHashed::Value(Call::one_fewer_deciding { track }.into()), + call, ); debug_assert!( maybe_result.is_ok(), @@ -871,7 +878,18 @@ impl, I: 'static> Pallet { if status.alarm.as_ref().map_or(true, |&(when, _)| when != alarm) { // Either no alarm or one that was different Self::ensure_no_alarm(status); - status.alarm = Self::set_alarm(Call::nudge_referendum { index }, alarm); + let call = + match T::Preimages::bound(CallOf::::from(Call::nudge_referendum { index })) { + Ok(c) => c, + Err(_) => { + debug_assert!( + false, + "Unable to create a bounded call from `nudge_referendum`??", + ); + return false + }, + }; + status.alarm = Self::set_alarm(call, alarm); true } else { false @@ -987,14 +1005,8 @@ impl, I: 'static> Pallet { // Passed! Self::ensure_no_alarm(&mut status); Self::note_one_fewer_deciding(status.track); - let (desired, call_hash) = (status.enactment, status.proposal_hash); - Self::schedule_enactment( - index, - track, - desired, - status.origin, - call_hash, - ); + let (desired, call) = (status.enactment, status.proposal); + Self::schedule_enactment(index, track, desired, status.origin, call); Self::deposit_event(Event::::Confirmed { index, tally: status.tally, diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 920e529bf05ca..c98fbf9a676b1 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -24,7 +24,7 @@ use frame_support::{ assert_ok, ord_parameter_types, parameter_types, traits::{ ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling, - PreimageRecipient, SortedMembers, + SortedMembers, }, weights::Weight, }; @@ -32,7 +32,7 @@ use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, Hash, IdentityLookup}, + traits::{BlakeTwo256, IdentityLookup}, DispatchResult, Perbill, }; @@ -97,7 +97,6 @@ impl pallet_preimage::Config for Test { type WeightInfo = (); type Currency = Balances; type ManagerOrigin = EnsureRoot; - type MaxSize = ConstU32<4096>; type BaseDeposit = (); type ByteDeposit = (); } @@ -111,8 +110,7 @@ impl pallet_scheduler::Config for Test { type MaxScheduledPerBlock = ConstU32<100>; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; - type PreimageProvider = Preimage; - type NoPreimagePostponement = ConstU64<10>; + type Preimages = Preimage; } impl pallet_balances::Config for Test { type MaxReserves = (); @@ -229,6 +227,7 @@ impl Config for Test { type UndecidingTimeout = ConstU64<20>; type AlarmInterval = AlarmInterval; type Tracks = TestTracksInfo; + type Preimages = Preimage; } pub fn new_test_ext() -> sp_io::TestExternalities { @@ -306,14 +305,13 @@ pub fn set_balance_proposal(value: u64) -> Vec { .encode() } -pub fn set_balance_proposal_hash(value: u64) -> H256 { +pub fn set_balance_proposal_bounded(value: u64) -> BoundedCallOf { let c = RuntimeCall::Balances(pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0, }); - >::note_preimage(c.encode().try_into().unwrap()); - BlakeTwo256::hash_of(&c) + ::bound(c).unwrap() } #[allow(dead_code)] @@ -321,7 +319,7 @@ pub fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult { Referenda::submit( RuntimeOrigin::signed(who), Box::new(frame_system::RawOrigin::Root.into()), - set_balance_proposal_hash(value), + set_balance_proposal_bounded(value), DispatchTime::After(delay), ) } @@ -449,7 +447,7 @@ impl RefState { assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), Box::new(frame_support::dispatch::RawOrigin::Root.into()), - set_balance_proposal_hash(1), + set_balance_proposal_bounded(1), DispatchTime::At(10), )); assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index 778d00e516693..355ce3021b87f 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -44,7 +44,7 @@ fn basic_happy_path_works() { assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), - set_balance_proposal_hash(1), + set_balance_proposal_bounded(1), DispatchTime::At(10), )); assert_eq!(Balances::reserved_balance(&1), 2); @@ -175,7 +175,7 @@ fn queueing_works() { assert_ok!(Referenda::submit( RuntimeOrigin::signed(5), Box::new(RawOrigin::Root.into()), - set_balance_proposal_hash(0), + set_balance_proposal_bounded(0), DispatchTime::After(0), )); assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(5), 0)); @@ -187,7 +187,7 @@ fn queueing_works() { assert_ok!(Referenda::submit( RuntimeOrigin::signed(i), Box::new(RawOrigin::Root.into()), - set_balance_proposal_hash(i), + set_balance_proposal_bounded(i), DispatchTime::After(0), )); assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(i), i as u32)); @@ -272,7 +272,7 @@ fn auto_timeout_should_happen_with_nothing_but_submit() { assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), - set_balance_proposal_hash(1), + set_balance_proposal_bounded(1), DispatchTime::At(20), )); run_to(20); @@ -292,13 +292,13 @@ fn tracks_are_distinguished() { assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), - set_balance_proposal_hash(1), + set_balance_proposal_bounded(1), DispatchTime::At(10), )); assert_ok!(Referenda::submit( RuntimeOrigin::signed(2), Box::new(RawOrigin::None.into()), - set_balance_proposal_hash(2), + set_balance_proposal_bounded(2), DispatchTime::At(20), )); @@ -315,7 +315,7 @@ fn tracks_are_distinguished() { ReferendumInfo::Ongoing(ReferendumStatus { track: 0, origin: OriginCaller::system(RawOrigin::Root), - proposal_hash: set_balance_proposal_hash(1), + proposal: set_balance_proposal_bounded(1), enactment: DispatchTime::At(10), submitted: 1, submission_deposit: Deposit { who: 1, amount: 2 }, @@ -331,7 +331,7 @@ fn tracks_are_distinguished() { ReferendumInfo::Ongoing(ReferendumStatus { track: 1, origin: OriginCaller::system(RawOrigin::None), - proposal_hash: set_balance_proposal_hash(2), + proposal: set_balance_proposal_bounded(2), enactment: DispatchTime::At(20), submitted: 1, submission_deposit: Deposit { who: 2, amount: 2 }, @@ -350,13 +350,13 @@ fn tracks_are_distinguished() { #[test] fn submit_errors_work() { new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); // No track for Signed origins. assert_noop!( Referenda::submit( RuntimeOrigin::signed(1), Box::new(RawOrigin::Signed(2).into()), - h, + h.clone(), DispatchTime::At(10), ), Error::::NoTrack @@ -381,7 +381,7 @@ fn decision_deposit_errors_work() { let e = Error::::NotOngoing; assert_noop!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0), e); - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), @@ -403,7 +403,7 @@ fn refund_deposit_works() { let e = Error::::BadReferendum; assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(1), 0), e); - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), @@ -425,7 +425,7 @@ fn refund_deposit_works() { #[test] fn cancel_works() { new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), @@ -444,7 +444,7 @@ fn cancel_works() { #[test] fn cancel_errors_works() { new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), @@ -462,7 +462,7 @@ fn cancel_errors_works() { #[test] fn kill_works() { new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), @@ -482,7 +482,7 @@ fn kill_works() { #[test] fn kill_errors_works() { new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index a6311e5f925be..2ce93cb6adc3c 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -19,7 +19,10 @@ use super::*; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; -use frame_support::{traits::schedule::Anon, Parameter}; +use frame_support::{ + traits::{schedule::v3::Anon, Bounded}, + Parameter, +}; use scale_info::TypeInfo; use sp_arithmetic::{Rounding::*, SignedRounding::*}; use sp_runtime::{FixedI64, PerThing, RuntimeDebug}; @@ -31,6 +34,7 @@ pub type NegativeImbalanceOf = <>::Currency as Currency< ::AccountId, >>::NegativeImbalance; pub type CallOf = >::RuntimeCall; +pub type BoundedCallOf = Bounded<>::RuntimeCall>; pub type VotesOf = >::Votes; pub type TallyOf = >::Tally; pub type PalletsOriginOf = @@ -39,7 +43,7 @@ pub type ReferendumInfoOf = ReferendumInfo< TrackIdOf, PalletsOriginOf, ::BlockNumber, - ::Hash, + BoundedCallOf, BalanceOf, TallyOf, ::AccountId, @@ -49,7 +53,7 @@ pub type ReferendumStatusOf = ReferendumStatus< TrackIdOf, PalletsOriginOf, ::BlockNumber, - ::Hash, + BoundedCallOf, BalanceOf, TallyOf, ::AccountId, @@ -160,7 +164,7 @@ pub struct ReferendumStatus< TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, - Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Call: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, @@ -171,7 +175,7 @@ pub struct ReferendumStatus< /// The origin for this referendum. pub(crate) origin: RuntimeOrigin, /// The hash of the proposal up for referendum. - pub(crate) proposal_hash: Hash, + pub(crate) proposal: Call, /// The time the proposal should be scheduled for enactment. pub(crate) enactment: DispatchTime, /// The time of submission. Once `UndecidingTimeout` passes, it may be closed by anyone if it @@ -197,7 +201,7 @@ pub enum ReferendumInfo< TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Moment: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, - Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Call: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, @@ -209,7 +213,7 @@ pub enum ReferendumInfo< TrackId, RuntimeOrigin, Moment, - Hash, + Call, Balance, Tally, AccountId, @@ -232,12 +236,12 @@ impl< TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, - Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Call: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, - > ReferendumInfo + > ReferendumInfo { /// Take the Decision Deposit from `self`, if there is one. Returns an `Err` if `self` is not /// in a valid state for the Decision Deposit to be refunded. diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 9397c66170425..aaa30fd88ffda 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -18,201 +18,219 @@ //! Scheduler pallet benchmarking. use super::*; -use frame_benchmarking::benchmarks; +use frame_benchmarking::{account, benchmarks}; use frame_support::{ ensure, - traits::{OnInitialize, PreimageProvider, PreimageRecipient}, + traits::{schedule::Priority, BoundedInline}, }; -use sp_runtime::traits::Hash; +use frame_system::RawOrigin; use sp_std::{prelude::*, vec}; use crate::Pallet as Scheduler; -use frame_system::Pallet as System; +use frame_system::Call as SystemCall; + +const SEED: u32 = 0; const BLOCK_NUMBER: u32 = 2; type SystemOrigin = ::RuntimeOrigin; -/// Add `n` named items to the schedule. +/// Add `n` items to the schedule. /// /// For `resolved`: +/// - ` /// - `None`: aborted (hash without preimage) /// - `Some(true)`: hash resolves into call if possible, plain call otherwise /// - `Some(false)`: plain call -fn fill_schedule( - when: T::BlockNumber, - n: u32, +fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { + let t = DispatchTime::At(when); + let origin: ::PalletsOrigin = frame_system::RawOrigin::Root.into(); + for i in 0..n { + let call = make_call::(None); + let period = Some(((i + 100).into(), 100)); + let name = u32_to_name(i); + Scheduler::::do_schedule_named(name, t, period, 0, origin.clone(), call)?; + } + ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); + Ok(()) +} + +fn u32_to_name(i: u32) -> TaskName { + i.using_encoded(blake2_256) +} + +fn make_task( periodic: bool, named: bool, - resolved: Option, -) -> Result<(), &'static str> { - for i in 0..n { - // Named schedule is strictly heavier than anonymous - let (call, hash) = call_and_hash::(i); - let call_or_hash = match resolved { - Some(true) => { - T::PreimageProvider::note_preimage(call.encode().try_into().unwrap()); - if T::PreimageProvider::have_preimage(&hash) { - CallOrHashOf::::Hash(hash) - } else { - call.into() - } + signed: bool, + maybe_lookup_len: Option, + priority: Priority, +) -> ScheduledOf { + let call = make_call::(maybe_lookup_len); + let maybe_periodic = match periodic { + true => Some((100u32.into(), 100)), + false => None, + }; + let maybe_id = match named { + true => Some(u32_to_name(0)), + false => None, + }; + let origin = make_origin::(signed); + Scheduled { maybe_id, priority, call, maybe_periodic, origin, _phantom: PhantomData } +} + +fn bounded(len: u32) -> Option::RuntimeCall>> { + let call = + <::RuntimeCall>::from(SystemCall::remark { remark: vec![0; len as usize] }); + T::Preimages::bound(call).ok() +} + +fn make_call(maybe_lookup_len: Option) -> Bounded<::RuntimeCall> { + let bound = BoundedInline::bound() as u32; + let mut len = match maybe_lookup_len { + Some(len) => len.min(T::Preimages::MAX_LENGTH as u32 - 2).max(bound) - 3, + None => bound.saturating_sub(4), + }; + + loop { + let c = match bounded::(len) { + Some(x) => x, + None => { + len -= 1; + continue }, - Some(false) => call.into(), - None => CallOrHashOf::::Hash(hash), }; - let period = match periodic { - true => Some(((i + 100).into(), 100)), - false => None, - }; - let t = DispatchTime::At(when); - let origin = frame_system::RawOrigin::Root.into(); - if named { - Scheduler::::do_schedule_named(i.encode(), t, period, 0, origin, call_or_hash)?; + if c.lookup_needed() == maybe_lookup_len.is_some() { + break c + } + if maybe_lookup_len.is_some() { + len += 1; } else { - Scheduler::::do_schedule(t, period, 0, origin, call_or_hash)?; + if len > 0 { + len -= 1; + } else { + break c + } } } - ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); - Ok(()) } -fn call_and_hash(i: u32) -> (::RuntimeCall, T::Hash) { - // Essentially a no-op call. - let call: ::RuntimeCall = frame_system::Call::remark { remark: i.encode() }.into(); - let hash = T::Hashing::hash_of(&call); - (call, hash) +fn make_origin(signed: bool) -> ::PalletsOrigin { + match signed { + true => frame_system::RawOrigin::Signed(account("origin", 0, SEED)).into(), + false => frame_system::RawOrigin::Root.into(), + } +} + +fn dummy_counter() -> WeightCounter { + WeightCounter { used: Weight::zero(), limit: Weight::MAX } } benchmarks! { - on_initialize_periodic_named_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, true, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s * 2); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } + // `service_agendas` when no work is done. + service_agendas_base { + let now = T::BlockNumber::from(BLOCK_NUMBER); + IncompleteSince::::put(now - One::one()); + }: { + Scheduler::::service_agendas(&mut dummy_counter(), now, 0); + } verify { + assert_eq!(IncompleteSince::::get(), Some(now - One::one())); } - on_initialize_named_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, true, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s * 2); - assert!(Agenda::::iter().count() == 0); + // `service_agenda` when no work is done. + service_agenda_base { + let now = BLOCK_NUMBER.into(); + let s in 0 .. T::MaxScheduledPerBlock::get(); + fill_schedule::(now, s)?; + let mut executed = 0; + }: { + Scheduler::::service_agenda(&mut dummy_counter(), &mut executed, now, now, 0); + } verify { + assert_eq!(executed, 0); } - on_initialize_periodic_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, false, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s * 2); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } + // `service_task` when the task is a non-periodic, non-named, non-fetched call which is not + // dispatched (e.g. due to being overweight). + service_task_base { + let now = BLOCK_NUMBER.into(); + let task = make_task::(false, false, false, None, 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { + //assert_eq!(result, Ok(())); } - on_initialize_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, false, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s * 2); - assert!(Agenda::::iter().count() == 0); + // `service_task` when the task is a non-periodic, non-named, fetched call (with a known + // preimage length) and which is not dispatched (e.g. due to being overweight). + service_task_fetched { + let s in (BoundedInline::bound() as u32) .. (T::Preimages::MAX_LENGTH as u32); + let now = BLOCK_NUMBER.into(); + let task = make_task::(false, false, false, Some(s), 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { } - on_initialize_named_aborted { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, true, None)?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), 0); - if let Some(delay) = T::NoPreimagePostponement::get() { - assert_eq!(Agenda::::get(when + delay).len(), s as usize); - } else { - assert!(Agenda::::iter().count() == 0); - } + // `service_task` when the task is a non-periodic, named, non-fetched call which is not + // dispatched (e.g. due to being overweight). + service_task_named { + let now = BLOCK_NUMBER.into(); + let task = make_task::(false, true, false, None, 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { } - on_initialize_aborted { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, false, None)?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), 0); - if let Some(delay) = T::NoPreimagePostponement::get() { - assert_eq!(Agenda::::get(when + delay).len(), s as usize); - } else { - assert!(Agenda::::iter().count() == 0); - } + // `service_task` when the task is a periodic, non-named, non-fetched call which is not + // dispatched (e.g. due to being overweight). + service_task_periodic { + let now = BLOCK_NUMBER.into(); + let task = make_task::(true, false, false, None, 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { } - on_initialize_periodic_named { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, true, Some(false))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } + // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight. + execute_dispatch_signed { + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX }; + let origin = make_origin::(true); + let call = T::Preimages::realize(&make_call::(None)).unwrap().0; + }: { + assert!(Scheduler::::execute_dispatch(&mut counter, origin, call).is_ok()); } - - on_initialize_periodic { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, false, Some(false))?; - }: { Scheduler::::on_initialize(when); } verify { - assert_eq!(System::::event_count(), s); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } } - on_initialize_named { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, true, Some(false))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s); - assert!(Agenda::::iter().count() == 0); + // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight. + execute_dispatch_unsigned { + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX }; + let origin = make_origin::(false); + let call = T::Preimages::realize(&make_call::(None)).unwrap().0; + }: { + assert!(Scheduler::::execute_dispatch(&mut counter, origin, call).is_ok()); } - - on_initialize { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, false, Some(false))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } verify { - assert_eq!(System::::event_count(), s); - assert!(Agenda::::iter().count() == 0); } schedule { - let s in 0 .. T::MaxScheduledPerBlock::get(); + let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); let when = BLOCK_NUMBER.into(); let periodic = Some((T::BlockNumber::one(), 100)); let priority = 0; // Essentially a no-op call. - let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); - let call = Box::new(CallOrHashOf::::Value(inner_call)); + let call = Box::new(SystemCall::set_storage { items: vec![] }.into()); - fill_schedule::(when, s, true, true, Some(false))?; - let schedule_origin = T::ScheduleOrigin::successful_origin(); - }: _>(schedule_origin, when, periodic, priority, call) + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, when, periodic, priority, call) verify { ensure!( Agenda::::get(when).len() == (s + 1) as usize, @@ -224,13 +242,13 @@ benchmarks! { let s in 1 .. T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, true, Some(false))?; + fill_schedule::(when, s)?; assert_eq!(Agenda::::get(when).len(), s as usize); let schedule_origin = T::ScheduleOrigin::successful_origin(); }: _>(schedule_origin, when, 0) verify { ensure!( - Lookup::::get(0.encode()).is_none(), + Lookup::::get(u32_to_name(0)).is_none(), "didn't remove from lookup" ); // Removed schedule is NONE @@ -241,18 +259,16 @@ benchmarks! { } schedule_named { - let s in 0 .. T::MaxScheduledPerBlock::get(); - let id = s.encode(); + let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); + let id = u32_to_name(s); let when = BLOCK_NUMBER.into(); let periodic = Some((T::BlockNumber::one(), 100)); let priority = 0; // Essentially a no-op call. - let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); - let call = Box::new(CallOrHashOf::::Value(inner_call)); + let call = Box::new(SystemCall::set_storage { items: vec![] }.into()); - fill_schedule::(when, s, true, true, Some(false))?; - let schedule_origin = T::ScheduleOrigin::successful_origin(); - }: _>(schedule_origin, id, when, periodic, priority, call) + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, id, when, periodic, priority, call) verify { ensure!( Agenda::::get(when).len() == (s + 1) as usize, @@ -264,12 +280,11 @@ benchmarks! { let s in 1 .. T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, true, Some(false))?; - let schedule_origin = T::ScheduleOrigin::successful_origin(); - }: _>(schedule_origin, 0.encode()) + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, u32_to_name(0)) verify { ensure!( - Lookup::::get(0.encode()).is_none(), + Lookup::::get(u32_to_name(0)).is_none(), "didn't remove from lookup" ); // Removed schedule is NONE diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 143fa37a9261d..b5ea0deeba9a3 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -52,27 +52,33 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; #[cfg(test)] mod mock; #[cfg(test)] mod tests; pub mod weights; -use codec::{Codec, Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::{DispatchError, DispatchResult, Dispatchable, GetDispatchInfo, Parameter}, + dispatch::{ + DispatchError, DispatchResult, Dispatchable, GetDispatchInfo, Parameter, RawOrigin, + }, + ensure, traits::{ schedule::{self, DispatchTime, MaybeHashed}, - EnsureOrigin, Get, IsType, OriginTrait, PalletInfoAccess, PrivilegeCmp, StorageVersion, + Bounded, CallerTrait, EnsureOrigin, Get, Hash as PreimageHash, IsType, OriginTrait, + PalletInfoAccess, PrivilegeCmp, QueryPreimage, StorageVersion, StorePreimage, }, weights::Weight, }; -use frame_system::{self as system, ensure_signed}; +use frame_system::{self as system}; pub use pallet::*; use scale_info::TypeInfo; +use sp_io::hashing::blake2_256; use sp_runtime::{ traits::{BadOrigin, One, Saturating, Zero}, - RuntimeDebug, + BoundedVec, RuntimeDebug, }; use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*}; pub use weights::WeightInfo; @@ -96,24 +102,25 @@ struct ScheduledV1 { /// Information regarding an item to be executed in the future. #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] -#[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct ScheduledV3 { +#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub struct Scheduled { /// The unique identity for this task, if there is one. - maybe_id: Option>, + maybe_id: Option, /// This task's priority. priority: schedule::Priority, /// The call to be dispatched. call: Call, /// If the call is periodic, then this points to the information concerning that. maybe_periodic: Option>, - /// The origin to dispatch the call. + /// The origin with which to dispatch the call. origin: PalletsOrigin, _phantom: PhantomData, } -use crate::ScheduledV3 as ScheduledV2; +use crate::{Scheduled as ScheduledV3, Scheduled as ScheduledV2}; -pub type ScheduledV2Of = ScheduledV3< +pub type ScheduledV2Of = ScheduledV2< + Vec, ::RuntimeCall, ::BlockNumber, ::PalletsOrigin, @@ -121,57 +128,54 @@ pub type ScheduledV2Of = ScheduledV3< >; pub type ScheduledV3Of = ScheduledV3< + Vec, CallOrHashOf, ::BlockNumber, ::PalletsOrigin, ::AccountId, >; -pub type ScheduledOf = ScheduledV3Of; - -/// The current version of Scheduled struct. -pub type Scheduled = - ScheduledV2; +pub type ScheduledOf = Scheduled< + TaskName, + Bounded<::RuntimeCall>, + ::BlockNumber, + ::PalletsOrigin, + ::AccountId, +>; -#[cfg(feature = "runtime-benchmarks")] -mod preimage_provider { - use frame_support::traits::PreimageRecipient; - pub trait PreimageProviderAndMaybeRecipient: PreimageRecipient {} - impl> PreimageProviderAndMaybeRecipient for T {} +struct WeightCounter { + used: Weight, + limit: Weight, } - -#[cfg(not(feature = "runtime-benchmarks"))] -mod preimage_provider { - use frame_support::traits::PreimageProvider; - pub trait PreimageProviderAndMaybeRecipient: PreimageProvider {} - impl> PreimageProviderAndMaybeRecipient for T {} +impl WeightCounter { + fn check_accrue(&mut self, w: Weight) -> bool { + let test = self.used.saturating_add(w); + if test.any_gt(self.limit) { + false + } else { + self.used = test; + true + } + } + fn can_accrue(&mut self, w: Weight) -> bool { + self.used.saturating_add(w).all_lte(self.limit) + } } -pub use preimage_provider::PreimageProviderAndMaybeRecipient; - pub(crate) trait MarginalWeightInfo: WeightInfo { - fn item(periodic: bool, named: bool, resolved: Option) -> Weight { - match (periodic, named, resolved) { - (_, false, None) => Self::on_initialize_aborted(2) - Self::on_initialize_aborted(1), - (_, true, None) => - Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1), - (false, false, Some(false)) => Self::on_initialize(2) - Self::on_initialize(1), - (false, true, Some(false)) => - Self::on_initialize_named(2) - Self::on_initialize_named(1), - (true, false, Some(false)) => - Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1), - (true, true, Some(false)) => - Self::on_initialize_periodic_named(2) - Self::on_initialize_periodic_named(1), - (false, false, Some(true)) => - Self::on_initialize_resolved(2) - Self::on_initialize_resolved(1), - (false, true, Some(true)) => - Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1), - (true, false, Some(true)) => - Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1), - (true, true, Some(true)) => - Self::on_initialize_periodic_named_resolved(2) - - Self::on_initialize_periodic_named_resolved(1), + fn service_task(maybe_lookup_len: Option, named: bool, periodic: bool) -> Weight { + let base = Self::service_task_base(); + let mut total = match maybe_lookup_len { + None => base, + Some(l) => Self::service_task_fetched(l as u32), + }; + if named { + total.saturating_accrue(Self::service_task_named().saturating_sub(base)); } + if periodic { + total.saturating_accrue(Self::service_task_periodic().saturating_sub(base)); + } + total } } impl MarginalWeightInfo for T {} @@ -179,11 +183,7 @@ impl MarginalWeightInfo for T {} #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{ - dispatch::PostDispatchInfo, - pallet_prelude::*, - traits::{schedule::LookupError, PreimageProvider}, - }; + use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*}; use frame_system::pallet_prelude::*; /// The current storage version. @@ -192,7 +192,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::without_storage_info] pub struct Pallet(_); /// `system::Config` should always be included in our implied traits. @@ -207,7 +206,9 @@ pub mod pallet { + IsType<::RuntimeOrigin>; /// The caller origin, overarching type of all pallets origins. - type PalletsOrigin: From> + Codec + Clone + Eq + TypeInfo; + type PalletsOrigin: From> + + CallerTrait + + MaxEncodedLen; /// The aggregated call type. type RuntimeCall: Parameter @@ -217,8 +218,7 @@ pub mod pallet { > + GetDispatchInfo + From>; - /// The maximum weight that may be scheduled per block for any dispatchables of less - /// priority than `schedule::HARD_DEADLINE`. + /// The maximum weight that may be scheduled per block for any dispatchables. #[pallet::constant] type MaximumWeight: Get; @@ -235,7 +235,6 @@ pub mod pallet { type OriginPrivilegeCmp: PrivilegeCmp; /// The maximum number of scheduled calls in the queue for a single block. - /// Not strictly enforced, but used for weight estimation. #[pallet::constant] type MaxScheduledPerBlock: Get; @@ -243,21 +242,29 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The preimage provider with which we look up call hashes to get the call. - type PreimageProvider: PreimageProviderAndMaybeRecipient; - - /// If `Some` then the number of blocks to postpone execution for when the item is delayed. - type NoPreimagePostponement: Get>; + type Preimages: QueryPreimage + StorePreimage; } - /// Items to be executed, indexed by the block number that they should be executed on. #[pallet::storage] - pub type Agenda = - StorageMap<_, Twox64Concat, T::BlockNumber, Vec>>, ValueQuery>; + pub type IncompleteSince = StorageValue<_, T::BlockNumber>; - /// Lookup from identity to the block number and index of the task. + /// Items to be executed, indexed by the block number that they should be executed on. + #[pallet::storage] + pub type Agenda = StorageMap< + _, + Twox64Concat, + T::BlockNumber, + BoundedVec>, T::MaxScheduledPerBlock>, + ValueQuery, + >; + + /// Lookup from a name to the block number and index of the task. + /// + /// For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4 + /// identities. #[pallet::storage] pub(crate) type Lookup = - StorageMap<_, Twox64Concat, Vec, TaskAddress>; + StorageMap<_, Twox64Concat, TaskName, TaskAddress>; /// Events type. #[pallet::event] @@ -270,15 +277,15 @@ pub mod pallet { /// Dispatched some task. Dispatched { task: TaskAddress, - id: Option>, + id: Option<[u8; 32]>, result: DispatchResult, }, /// The call for the provided hash was not found so the task has been aborted. - CallLookupFailed { - task: TaskAddress, - id: Option>, - error: LookupError, - }, + CallUnavailable { task: TaskAddress, id: Option<[u8; 32]> }, + /// The given task was unable to be renewed since the agenda is full at that block. + PeriodicFailed { task: TaskAddress, id: Option<[u8; 32]> }, + /// The given task can never be executed since it is overweight. + PermanentlyOverweight { task: TaskAddress, id: Option<[u8; 32]> }, } #[pallet::error] @@ -291,134 +298,18 @@ pub mod pallet { TargetBlockNumberInPast, /// Reschedule failed because it does not change scheduled time. RescheduleNoChange, + /// Attempt to use a non-named function on a named task. + Named, } #[pallet::hooks] impl Hooks> for Pallet { /// Execute the scheduled calls fn on_initialize(now: T::BlockNumber) -> Weight { - let limit = T::MaximumWeight::get(); - - let mut queued = Agenda::::take(now) - .into_iter() - .enumerate() - .filter_map(|(index, s)| Some((index as u32, s?))) - .collect::>(); - - if queued.len() as u32 > T::MaxScheduledPerBlock::get() { - log::warn!( - target: "runtime::scheduler", - "Warning: This block has more items queued in Scheduler than \ - expected from the runtime configuration. An update might be needed." - ); - } - - queued.sort_by_key(|(_, s)| s.priority); - - let next = now + One::one(); - - let mut total_weight: Weight = T::WeightInfo::on_initialize(0); - for (order, (index, mut s)) in queued.into_iter().enumerate() { - let named = if let Some(ref id) = s.maybe_id { - Lookup::::remove(id); - true - } else { - false - }; - - let (call, maybe_completed) = s.call.resolved::(); - s.call = call; - - let resolved = if let Some(completed) = maybe_completed { - T::PreimageProvider::unrequest_preimage(&completed); - true - } else { - false - }; - - let call = match s.call.as_value().cloned() { - Some(c) => c, - None => { - // Preimage not available - postpone until some block. - total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); - if let Some(delay) = T::NoPreimagePostponement::get() { - let until = now.saturating_add(delay); - if let Some(ref id) = s.maybe_id { - let index = Agenda::::decode_len(until).unwrap_or(0); - Lookup::::insert(id, (until, index as u32)); - } - Agenda::::append(until, Some(s)); - } - continue - }, - }; - - let periodic = s.maybe_periodic.is_some(); - let call_weight = call.get_dispatch_info().weight; - let mut item_weight = T::WeightInfo::item(periodic, named, Some(resolved)); - let origin = <::RuntimeOrigin as From>::from( - s.origin.clone(), - ) - .into(); - if ensure_signed(origin).is_ok() { - // Weights of Signed dispatches expect their signing account to be whitelisted. - item_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - } - - // We allow a scheduled call if any is true: - // - It's priority is `HARD_DEADLINE` - // - It does not push the weight past the limit. - // - It is the first item in the schedule - let hard_deadline = s.priority <= schedule::HARD_DEADLINE; - let test_weight = - total_weight.saturating_add(call_weight).saturating_add(item_weight); - if !hard_deadline && order > 0 && test_weight.any_gt(limit) { - // Cannot be scheduled this block - postpone until next. - total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); - if let Some(ref id) = s.maybe_id { - // NOTE: We could reasonably not do this (in which case there would be one - // block where the named and delayed item could not be referenced by name), - // but we will do it anyway since it should be mostly free in terms of - // weight and it is slightly cleaner. - let index = Agenda::::decode_len(next).unwrap_or(0); - Lookup::::insert(id, (next, index as u32)); - } - Agenda::::append(next, Some(s)); - continue - } - - let dispatch_origin = s.origin.clone().into(); - let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) { - Ok(post_info) => (post_info.actual_weight, Ok(())), - Err(error_and_info) => - (error_and_info.post_info.actual_weight, Err(error_and_info.error)), - }; - let actual_call_weight = maybe_actual_call_weight.unwrap_or(call_weight); - total_weight.saturating_accrue(item_weight); - total_weight.saturating_accrue(actual_call_weight); - - Self::deposit_event(Event::Dispatched { - task: (now, index), - id: s.maybe_id.clone(), - result, - }); - - if let &Some((period, count)) = &s.maybe_periodic { - if count > 1 { - s.maybe_periodic = Some((period, count - 1)); - } else { - s.maybe_periodic = None; - } - let wake = now + period; - // If scheduled is named, place its information in `Lookup` - if let Some(ref id) = s.maybe_id { - let wake_index = Agenda::::decode_len(wake).unwrap_or(0); - Lookup::::insert(id, (wake, wake_index as u32)); - } - Agenda::::append(wake, Some(s)); - } - } - total_weight + let mut weight_counter = + WeightCounter { used: Weight::zero(), limit: T::MaximumWeight::get() }; + Self::service_agendas(&mut weight_counter, now, u32::max_value()); + weight_counter.used } } @@ -431,7 +322,7 @@ pub mod pallet { when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box<::RuntimeCall>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::RuntimeOrigin::from(origin); @@ -440,7 +331,7 @@ pub mod pallet { maybe_periodic, priority, origin.caller().clone(), - *call, + T::Preimages::bound(*call)?, )?; Ok(()) } @@ -458,11 +349,11 @@ pub mod pallet { #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] pub fn schedule_named( origin: OriginFor, - id: Vec, + id: TaskName, when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box<::RuntimeCall>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::RuntimeOrigin::from(origin); @@ -472,14 +363,14 @@ pub mod pallet { maybe_periodic, priority, origin.caller().clone(), - *call, + T::Preimages::bound(*call)?, )?; Ok(()) } /// Cancel a named scheduled task. #[pallet::weight(::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))] - pub fn cancel_named(origin: OriginFor, id: Vec) -> DispatchResult { + pub fn cancel_named(origin: OriginFor, id: TaskName) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::RuntimeOrigin::from(origin); Self::do_cancel_named(Some(origin.caller().clone()), id)?; @@ -497,7 +388,7 @@ pub mod pallet { after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box<::RuntimeCall>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::RuntimeOrigin::from(origin); @@ -506,7 +397,7 @@ pub mod pallet { maybe_periodic, priority, origin.caller().clone(), - *call, + T::Preimages::bound(*call)?, )?; Ok(()) } @@ -519,11 +410,11 @@ pub mod pallet { #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] pub fn schedule_named_after( origin: OriginFor, - id: Vec, + id: TaskName, after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box<::RuntimeCall>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::RuntimeOrigin::from(origin); @@ -533,41 +424,70 @@ pub mod pallet { maybe_periodic, priority, origin.caller().clone(), - *call, + T::Preimages::bound(*call)?, )?; Ok(()) } } } -impl Pallet { - /// Migrate storage format from V1 to V3. +impl> Pallet { + /// Migrate storage format from V1 to V4. /// /// Returns the weight consumed by this migration. - pub fn migrate_v1_to_v3() -> Weight { + pub fn migrate_v1_to_v4() -> Weight { + use migration::v1 as old; let mut weight = T::DbWeight::get().reads_writes(1, 1); + // Delete all undecodable values. + // `StorageMap::translate` is not enough since it just skips them and leaves the keys in. + let keys = old::Agenda::::iter_keys().collect::>(); + for key in keys { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if let Err(_) = old::Agenda::::try_get(&key) { + weight.saturating_accrue(T::DbWeight::get().writes(1)); + old::Agenda::::remove(&key); + log::warn!("Deleted undecodable agenda"); + } + } + Agenda::::translate::< Vec::RuntimeCall, T::BlockNumber>>>, _, >(|_, agenda| { - Some( + Some(BoundedVec::truncate_from( agenda .into_iter() .map(|schedule| { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - schedule.map(|schedule| ScheduledV3 { - maybe_id: schedule.maybe_id, - priority: schedule.priority, - call: schedule.call.into(), - maybe_periodic: schedule.maybe_periodic, - origin: system::RawOrigin::Root.into(), - _phantom: Default::default(), + schedule.and_then(|schedule| { + if let Some(id) = schedule.maybe_id.as_ref() { + let name = blake2_256(id); + if let Some(item) = old::Lookup::::take(id) { + Lookup::::insert(name, item); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + + let call = T::Preimages::bound(schedule.call).ok()?; + + if call.lookup_needed() { + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + } + + Some(Scheduled { + maybe_id: schedule.maybe_id.map(|x| blake2_256(&x[..])), + priority: schedule.priority, + call, + maybe_periodic: schedule.maybe_periodic, + origin: system::RawOrigin::Root.into(), + _phantom: Default::default(), + }) }) }) .collect::>(), - ) + )) }); #[allow(deprecated)] @@ -577,34 +497,62 @@ impl Pallet { &[], ); - StorageVersion::new(3).put::(); + StorageVersion::new(4).put::(); weight + T::DbWeight::get().writes(2) } - /// Migrate storage format from V2 to V3. + /// Migrate storage format from V2 to V4. /// /// Returns the weight consumed by this migration. - pub fn migrate_v2_to_v3() -> Weight { + pub fn migrate_v2_to_v4() -> Weight { + use migration::v2 as old; let mut weight = T::DbWeight::get().reads_writes(1, 1); + // Delete all undecodable values. + // `StorageMap::translate` is not enough since it just skips them and leaves the keys in. + let keys = old::Agenda::::iter_keys().collect::>(); + for key in keys { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if let Err(_) = old::Agenda::::try_get(&key) { + weight.saturating_accrue(T::DbWeight::get().writes(1)); + old::Agenda::::remove(&key); + log::warn!("Deleted undecodable agenda"); + } + } + Agenda::::translate::>>, _>(|_, agenda| { - Some( + Some(BoundedVec::truncate_from( agenda .into_iter() .map(|schedule| { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - schedule.map(|schedule| ScheduledV3 { - maybe_id: schedule.maybe_id, - priority: schedule.priority, - call: schedule.call.into(), - maybe_periodic: schedule.maybe_periodic, - origin: schedule.origin, - _phantom: Default::default(), + schedule.and_then(|schedule| { + if let Some(id) = schedule.maybe_id.as_ref() { + let name = blake2_256(id); + if let Some(item) = old::Lookup::::take(id) { + Lookup::::insert(name, item); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + + let call = T::Preimages::bound(schedule.call).ok()?; + if call.lookup_needed() { + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + } + + Some(Scheduled { + maybe_id: schedule.maybe_id.map(|x| blake2_256(&x[..])), + priority: schedule.priority, + call, + maybe_periodic: schedule.maybe_periodic, + origin: schedule.origin, + _phantom: Default::default(), + }) }) }) .collect::>(), - ) + )) }); #[allow(deprecated)] @@ -614,34 +562,140 @@ impl Pallet { &[], ); - StorageVersion::new(3).put::(); + StorageVersion::new(4).put::(); weight + T::DbWeight::get().writes(2) } - #[cfg(feature = "try-runtime")] - pub fn pre_migrate_to_v3() -> Result<(), &'static str> { - Ok(()) - } + /// Migrate storage format from V3 to V4. + /// + /// Returns the weight consumed by this migration. + #[allow(deprecated)] + pub fn migrate_v3_to_v4() -> Weight { + use migration::v3 as old; + let mut weight = T::DbWeight::get().reads_writes(2, 1); + + // Delete all undecodable values. + // `StorageMap::translate` is not enough since it just skips them and leaves the keys in. + let blocks = old::Agenda::::iter_keys().collect::>(); + for block in blocks { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if let Err(_) = old::Agenda::::try_get(&block) { + weight.saturating_accrue(T::DbWeight::get().writes(1)); + old::Agenda::::remove(&block); + log::warn!("Deleted undecodable agenda of block: {:?}", block); + } + } - #[cfg(feature = "try-runtime")] - pub fn post_migrate_to_v3() -> Result<(), &'static str> { - use frame_support::dispatch::GetStorageVersion; + Agenda::::translate::>>, _>(|block, agenda| { + log::info!("Migrating agenda of block: {:?}", &block); + Some(BoundedVec::truncate_from( + agenda + .into_iter() + .map(|schedule| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + schedule + .and_then(|schedule| { + if let Some(id) = schedule.maybe_id.as_ref() { + let name = blake2_256(id); + if let Some(item) = old::Lookup::::take(id) { + Lookup::::insert(name, item); + log::info!("Migrated name for id: {:?}", id); + } else { + log::error!("No name in Lookup for id: {:?}", &id); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } else { + log::info!("Schedule is unnamed"); + } + + let call = match schedule.call { + MaybeHashed::Hash(h) => { + let bounded = Bounded::from_legacy_hash(h); + // Check that the call can be decoded in the new runtime. + if let Err(err) = T::Preimages::peek::< + ::RuntimeCall, + >(&bounded) + { + log::error!( + "Dropping undecodable call {}: {:?}", + &h, + &err + ); + return None + } + weight.saturating_accrue(T::DbWeight::get().reads(1)); + log::info!("Migrated call by hash, hash: {:?}", h); + bounded + }, + MaybeHashed::Value(v) => { + let call = T::Preimages::bound(v) + .map_err(|e| { + log::error!("Could not bound Call: {:?}", e) + }) + .ok()?; + if call.lookup_needed() { + weight.saturating_accrue( + T::DbWeight::get().reads_writes(0, 1), + ); + } + log::info!( + "Migrated call by value, hash: {:?}", + call.hash() + ); + call + }, + }; + + Some(Scheduled { + maybe_id: schedule.maybe_id.map(|x| blake2_256(&x[..])), + priority: schedule.priority, + call, + maybe_periodic: schedule.maybe_periodic, + origin: schedule.origin, + _phantom: Default::default(), + }) + }) + .or_else(|| { + log::info!("Schedule in agenda for block {:?} is empty - nothing to do here.", &block); + None + }) + }) + .collect::>(), + )) + }); - assert!(Self::current_storage_version() == 3); - for k in Agenda::::iter_keys() { - let _ = Agenda::::try_get(k).map_err(|()| "Invalid item in Agenda")?; - } - Ok(()) + #[allow(deprecated)] + frame_support::storage::migration::remove_storage_prefix( + Self::name().as_bytes(), + b"StorageVersion", + &[], + ); + + StorageVersion::new(4).put::(); + + weight + T::DbWeight::get().writes(2) } +} +impl Pallet { /// Helper to migrate scheduler when the pallet origin type has changed. pub fn migrate_origin + codec::Decode>() { Agenda::::translate::< - Vec, T::BlockNumber, OldOrigin, T::AccountId>>>, + Vec< + Option< + Scheduled< + TaskName, + Bounded<::RuntimeCall>, + T::BlockNumber, + OldOrigin, + T::AccountId, + >, + >, + >, _, >(|_, agenda| { - Some( + Some(BoundedVec::truncate_from( agenda .into_iter() .map(|schedule| { @@ -655,7 +709,7 @@ impl Pallet { }) }) .collect::>(), - ) + )) }); } @@ -676,34 +730,64 @@ impl Pallet { Ok(when) } + fn place_task( + when: T::BlockNumber, + what: ScheduledOf, + ) -> Result, (DispatchError, ScheduledOf)> { + let maybe_name = what.maybe_id; + let index = Self::push_to_agenda(when, what)?; + let address = (when, index); + if let Some(name) = maybe_name { + Lookup::::insert(name, address) + } + Self::deposit_event(Event::Scheduled { when: address.0, index: address.1 }); + Ok(address) + } + + fn push_to_agenda( + when: T::BlockNumber, + what: ScheduledOf, + ) -> Result)> { + let mut agenda = Agenda::::get(when); + let index = if (agenda.len() as u32) < T::MaxScheduledPerBlock::get() { + // will always succeed due to the above check. + let _ = agenda.try_push(Some(what)); + agenda.len() as u32 - 1 + } else { + if let Some(hole_index) = agenda.iter().position(|i| i.is_none()) { + agenda[hole_index] = Some(what); + hole_index as u32 + } else { + return Err((DispatchError::Exhausted, what)) + } + }; + Agenda::::insert(when, agenda); + Ok(index) + } + fn do_schedule( when: DispatchTime, maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOrHashOf, + call: Bounded<::RuntimeCall>, ) -> Result, DispatchError> { let when = Self::resolve_time(when)?; - call.ensure_requested::(); // sanitize maybe_periodic let maybe_periodic = maybe_periodic .filter(|p| p.1 > 1 && !p.0.is_zero()) // Remove one from the number of repetitions since we will schedule one now. .map(|(p, c)| (p, c - 1)); - let s = Some(Scheduled { + let task = Scheduled { maybe_id: None, priority, call, maybe_periodic, origin, - _phantom: PhantomData::::default(), - }); - Agenda::::append(when, s); - let index = Agenda::::decode_len(when).unwrap_or(1) as u32 - 1; - Self::deposit_event(Event::Scheduled { when, index }); - - Ok((when, index)) + _phantom: PhantomData, + }; + Self::place_task(when, task).map_err(|x| x.0) } fn do_cancel( @@ -713,7 +797,7 @@ impl Pallet { let scheduled = Agenda::::try_mutate(when, |agenda| { agenda.get_mut(index as usize).map_or( Ok(None), - |s| -> Result>, DispatchError> { + |s| -> Result>, DispatchError> { if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) { if matches!( T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin), @@ -727,7 +811,7 @@ impl Pallet { ) })?; if let Some(s) = scheduled { - s.call.ensure_unrequested::(); + T::Preimages::drop(&s.call); if let Some(id) = s.maybe_id { Lookup::::remove(id); } @@ -748,27 +832,23 @@ impl Pallet { return Err(Error::::RescheduleNoChange.into()) } - Agenda::::try_mutate(when, |agenda| -> DispatchResult { + let task = Agenda::::try_mutate(when, |agenda| { let task = agenda.get_mut(index as usize).ok_or(Error::::NotFound)?; - let task = task.take().ok_or(Error::::NotFound)?; - Agenda::::append(new_time, Some(task)); - Ok(()) + ensure!(!matches!(task, Some(Scheduled { maybe_id: Some(_), .. })), Error::::Named); + task.take().ok_or(Error::::NotFound) })?; - - let new_index = Agenda::::decode_len(new_time).unwrap_or(1) as u32 - 1; Self::deposit_event(Event::Canceled { when, index }); - Self::deposit_event(Event::Scheduled { when: new_time, index: new_index }); - Ok((new_time, new_index)) + Self::place_task(new_time, task).map_err(|x| x.0) } fn do_schedule_named( - id: Vec, + id: TaskName, when: DispatchTime, maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOrHashOf, + call: Bounded<::RuntimeCall>, ) -> Result, DispatchError> { // ensure id it is unique if Lookup::::contains_key(&id) { @@ -777,32 +857,24 @@ impl Pallet { let when = Self::resolve_time(when)?; - call.ensure_requested::(); - // sanitize maybe_periodic let maybe_periodic = maybe_periodic .filter(|p| p.1 > 1 && !p.0.is_zero()) // Remove one from the number of repetitions since we will schedule one now. .map(|(p, c)| (p, c - 1)); - let s = Scheduled { - maybe_id: Some(id.clone()), + let task = Scheduled { + maybe_id: Some(id), priority, call, maybe_periodic, origin, _phantom: Default::default(), }; - Agenda::::append(when, Some(s)); - let index = Agenda::::decode_len(when).unwrap_or(1) as u32 - 1; - let address = (when, index); - Lookup::::insert(&id, &address); - Self::deposit_event(Event::Scheduled { when, index }); - - Ok(address) + Self::place_task(when, task).map_err(|x| x.0) } - fn do_cancel_named(origin: Option, id: Vec) -> DispatchResult { + fn do_cancel_named(origin: Option, id: TaskName) -> DispatchResult { Lookup::::try_mutate_exists(id, |lookup| -> DispatchResult { if let Some((when, index)) = lookup.take() { let i = index as usize; @@ -815,7 +887,7 @@ impl Pallet { ) { return Err(BadOrigin.into()) } - s.call.ensure_unrequested::(); + T::Preimages::drop(&s.call); } *s = None; } @@ -830,42 +902,245 @@ impl Pallet { } fn do_reschedule_named( - id: Vec, + id: TaskName, new_time: DispatchTime, ) -> Result, DispatchError> { let new_time = Self::resolve_time(new_time)?; - Lookup::::try_mutate_exists( - id, - |lookup| -> Result, DispatchError> { - let (when, index) = lookup.ok_or(Error::::NotFound)?; + let lookup = Lookup::::get(id); + let (when, index) = lookup.ok_or(Error::::NotFound)?; - if new_time == when { - return Err(Error::::RescheduleNoChange.into()) - } + if new_time == when { + return Err(Error::::RescheduleNoChange.into()) + } - Agenda::::try_mutate(when, |agenda| -> DispatchResult { - let task = agenda.get_mut(index as usize).ok_or(Error::::NotFound)?; - let task = task.take().ok_or(Error::::NotFound)?; - Agenda::::append(new_time, Some(task)); + let task = Agenda::::try_mutate(when, |agenda| { + let task = agenda.get_mut(index as usize).ok_or(Error::::NotFound)?; + task.take().ok_or(Error::::NotFound) + })?; + Self::deposit_event(Event::Canceled { when, index }); + Self::place_task(new_time, task).map_err(|x| x.0) + } +} - Ok(()) - })?; +enum ServiceTaskError { + /// Could not be executed due to missing preimage. + Unavailable, + /// Could not be executed due to weight limitations. + Overweight, +} +use ServiceTaskError::*; - let new_index = Agenda::::decode_len(new_time).unwrap_or(1) as u32 - 1; - Self::deposit_event(Event::Canceled { when, index }); - Self::deposit_event(Event::Scheduled { when: new_time, index: new_index }); +impl Pallet { + /// Service up to `max` agendas queue starting from earliest incompletely executed agenda. + fn service_agendas(weight: &mut WeightCounter, now: T::BlockNumber, max: u32) { + if !weight.check_accrue(T::WeightInfo::service_agendas_base()) { + return + } + + let mut incomplete_since = now + One::one(); + let mut when = IncompleteSince::::take().unwrap_or(now); + let mut executed = 0; + + let max_items = T::MaxScheduledPerBlock::get(); + let mut count_down = max; + let service_agenda_base_weight = T::WeightInfo::service_agenda_base(max_items); + while count_down > 0 && when <= now && weight.can_accrue(service_agenda_base_weight) { + if !Self::service_agenda(weight, &mut executed, now, when, u32::max_value()) { + incomplete_since = incomplete_since.min(when); + } + when.saturating_inc(); + count_down.saturating_dec(); + } + incomplete_since = incomplete_since.min(when); + if incomplete_since <= now { + IncompleteSince::::put(incomplete_since); + } + } + + /// Returns `true` if the agenda was fully completed, `false` if it should be revisited at a + /// later block. + fn service_agenda( + weight: &mut WeightCounter, + executed: &mut u32, + now: T::BlockNumber, + when: T::BlockNumber, + max: u32, + ) -> bool { + let mut agenda = Agenda::::get(when); + let mut ordered = agenda + .iter() + .enumerate() + .filter_map(|(index, maybe_item)| { + maybe_item.as_ref().map(|item| (index as u32, item.priority)) + }) + .collect::>(); + ordered.sort_by_key(|k| k.1); + let within_limit = + weight.check_accrue(T::WeightInfo::service_agenda_base(ordered.len() as u32)); + debug_assert!(within_limit, "weight limit should have been checked in advance"); + + // Items which we know can be executed and have postponed for execution in a later block. + let mut postponed = (ordered.len() as u32).saturating_sub(max); + // Items which we don't know can ever be executed. + let mut dropped = 0; + + for (agenda_index, _) in ordered.into_iter().take(max as usize) { + let task = match agenda[agenda_index as usize].take() { + None => continue, + Some(t) => t, + }; + let base_weight = T::WeightInfo::service_task( + task.call.lookup_len().map(|x| x as usize), + task.maybe_id.is_some(), + task.maybe_periodic.is_some(), + ); + if !weight.can_accrue(base_weight) { + postponed += 1; + break + } + let result = Self::service_task(weight, now, when, agenda_index, *executed == 0, task); + agenda[agenda_index as usize] = match result { + Err((Unavailable, slot)) => { + dropped += 1; + slot + }, + Err((Overweight, slot)) => { + postponed += 1; + slot + }, + Ok(()) => { + *executed += 1; + None + }, + }; + } + if postponed > 0 || dropped > 0 { + Agenda::::insert(when, agenda); + } else { + Agenda::::remove(when); + } + postponed == 0 + } - *lookup = Some((new_time, new_index)); + /// Service (i.e. execute) the given task, being careful not to overflow the `weight` counter. + /// + /// This involves: + /// - removing and potentially replacing the `Lookup` entry for the task. + /// - realizing the task's call which can include a preimage lookup. + /// - Rescheduling the task for execution in a later agenda if periodic. + fn service_task( + weight: &mut WeightCounter, + now: T::BlockNumber, + when: T::BlockNumber, + agenda_index: u32, + is_first: bool, + mut task: ScheduledOf, + ) -> Result<(), (ServiceTaskError, Option>)> { + if let Some(ref id) = task.maybe_id { + Lookup::::remove(id); + } - Ok((new_time, new_index)) + let (call, lookup_len) = match T::Preimages::peek(&task.call) { + Ok(c) => c, + Err(_) => return Err((Unavailable, Some(task))), + }; + + weight.check_accrue(T::WeightInfo::service_task( + lookup_len.map(|x| x as usize), + task.maybe_id.is_some(), + task.maybe_periodic.is_some(), + )); + + match Self::execute_dispatch(weight, task.origin.clone(), call) { + Err(Unavailable) => { + debug_assert!(false, "Checked to exist with `peek`"); + Self::deposit_event(Event::CallUnavailable { + task: (when, agenda_index), + id: task.maybe_id, + }); + Err((Unavailable, Some(task))) + }, + Err(Overweight) if is_first => { + T::Preimages::drop(&task.call); + Self::deposit_event(Event::PermanentlyOverweight { + task: (when, agenda_index), + id: task.maybe_id, + }); + Err((Unavailable, Some(task))) + }, + Err(Overweight) => Err((Overweight, Some(task))), + Ok(result) => { + Self::deposit_event(Event::Dispatched { + task: (when, agenda_index), + id: task.maybe_id, + result, + }); + if let &Some((period, count)) = &task.maybe_periodic { + if count > 1 { + task.maybe_periodic = Some((period, count - 1)); + } else { + task.maybe_periodic = None; + } + let wake = now.saturating_add(period); + match Self::place_task(wake, task) { + Ok(_) => {}, + Err((_, task)) => { + // TODO: Leave task in storage somewhere for it to be rescheduled + // manually. + T::Preimages::drop(&task.call); + Self::deposit_event(Event::PeriodicFailed { + task: (when, agenda_index), + id: task.maybe_id, + }); + }, + } + } else { + T::Preimages::drop(&task.call); + } + Ok(()) }, - ) + } + } + + /// Make a dispatch to the given `call` from the given `origin`, ensuring that the `weight` + /// counter does not exceed its limit and that it is counted accurately (e.g. accounted using + /// post info if available). + /// + /// NOTE: Only the weight for this function will be counted (origin lookup, dispatch and the + /// call itself). + fn execute_dispatch( + weight: &mut WeightCounter, + origin: T::PalletsOrigin, + call: ::RuntimeCall, + ) -> Result { + let base_weight = match origin.as_system_ref() { + Some(&RawOrigin::Signed(_)) => T::WeightInfo::execute_dispatch_signed(), + _ => T::WeightInfo::execute_dispatch_unsigned(), + }; + let call_weight = call.get_dispatch_info().weight; + // We only allow a scheduled call if it cannot push the weight past the limit. + let max_weight = base_weight.saturating_add(call_weight); + + if !weight.can_accrue(max_weight) { + return Err(Overweight) + } + + let dispatch_origin = origin.into(); + let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) { + Ok(post_info) => (post_info.actual_weight, Ok(())), + Err(error_and_info) => + (error_and_info.post_info.actual_weight, Err(error_and_info.error)), + }; + let call_weight = maybe_actual_call_weight.unwrap_or(call_weight); + weight.check_accrue(base_weight); + weight.check_accrue(call_weight); + Ok(result) } } -impl schedule::v2::Anon::RuntimeCall, T::PalletsOrigin> - for Pallet +impl> + schedule::v2::Anon::RuntimeCall, T::PalletsOrigin> for Pallet { type Address = TaskAddress; type Hash = T::Hash; @@ -877,6 +1152,8 @@ impl schedule::v2::Anon::RuntimeCall, T origin: T::PalletsOrigin, call: CallOrHashOf, ) -> Result { + let call = call.as_value().ok_or(DispatchError::CannotLookup)?; + let call = T::Preimages::bound(call)?.transmute(); Self::do_schedule(when, maybe_periodic, priority, origin, call) } @@ -896,8 +1173,8 @@ impl schedule::v2::Anon::RuntimeCall, T } } -impl schedule::v2::Named::RuntimeCall, T::PalletsOrigin> - for Pallet +impl> + schedule::v2::Named::RuntimeCall, T::PalletsOrigin> for Pallet { type Address = TaskAddress; type Hash = T::Hash; @@ -910,23 +1187,108 @@ impl schedule::v2::Named::RuntimeCall, origin: T::PalletsOrigin, call: CallOrHashOf, ) -> Result { - Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ()) + let call = call.as_value().ok_or(())?; + let call = T::Preimages::bound(call).map_err(|_| ())?.transmute(); + let name = blake2_256(&id[..]); + Self::do_schedule_named(name, when, maybe_periodic, priority, origin, call).map_err(|_| ()) } fn cancel_named(id: Vec) -> Result<(), ()> { - Self::do_cancel_named(None, id).map_err(|_| ()) + let name = blake2_256(&id[..]); + Self::do_cancel_named(None, name).map_err(|_| ()) } fn reschedule_named( id: Vec, when: DispatchTime, ) -> Result { - Self::do_reschedule_named(id, when) + let name = blake2_256(&id[..]); + Self::do_reschedule_named(name, when) } fn next_dispatch_time(id: Vec) -> Result { - Lookup::::get(id) + let name = blake2_256(&id[..]); + Lookup::::get(name) .and_then(|(when, index)| Agenda::::get(when).get(index as usize).map(|_| when)) .ok_or(()) } } + +impl schedule::v3::Anon::RuntimeCall, T::PalletsOrigin> + for Pallet +{ + type Address = TaskAddress; + + fn schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: schedule::Priority, + origin: T::PalletsOrigin, + call: Bounded<::RuntimeCall>, + ) -> Result { + Self::do_schedule(when, maybe_periodic, priority, origin, call) + } + + fn cancel((when, index): Self::Address) -> Result<(), DispatchError> { + Self::do_cancel(None, (when, index)).map_err(map_err_to_v3_err::) + } + + fn reschedule( + address: Self::Address, + when: DispatchTime, + ) -> Result { + Self::do_reschedule(address, when).map_err(map_err_to_v3_err::) + } + + fn next_dispatch_time((when, index): Self::Address) -> Result { + Agenda::::get(when) + .get(index as usize) + .ok_or(DispatchError::Unavailable) + .map(|_| when) + } +} + +use schedule::v3::TaskName; + +impl schedule::v3::Named::RuntimeCall, T::PalletsOrigin> + for Pallet +{ + type Address = TaskAddress; + + fn schedule_named( + id: TaskName, + when: DispatchTime, + maybe_periodic: Option>, + priority: schedule::Priority, + origin: T::PalletsOrigin, + call: Bounded<::RuntimeCall>, + ) -> Result { + Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call) + } + + fn cancel_named(id: TaskName) -> Result<(), DispatchError> { + Self::do_cancel_named(None, id).map_err(map_err_to_v3_err::) + } + + fn reschedule_named( + id: TaskName, + when: DispatchTime, + ) -> Result { + Self::do_reschedule_named(id, when).map_err(map_err_to_v3_err::) + } + + fn next_dispatch_time(id: TaskName) -> Result { + Lookup::::get(id) + .and_then(|(when, index)| Agenda::::get(when).get(index as usize).map(|_| when)) + .ok_or(DispatchError::Unavailable) + } +} + +/// Maps a pallet error to an `schedule::v3` error. +fn map_err_to_v3_err(err: DispatchError) -> DispatchError { + if err == DispatchError::from(Error::::NotFound) { + DispatchError::Unavailable + } else { + err + } +} diff --git a/frame/scheduler/src/migration.rs b/frame/scheduler/src/migration.rs new file mode 100644 index 0000000000000..6769d20023196 --- /dev/null +++ b/frame/scheduler/src/migration.rs @@ -0,0 +1,402 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Migrations for the scheduler pallet. + +use super::*; +use frame_support::traits::OnRuntimeUpgrade; + +/// The log target. +const TARGET: &'static str = "runtime::scheduler::migration"; + +pub mod v1 { + use super::*; + use frame_support::pallet_prelude::*; + + #[frame_support::storage_alias] + pub(crate) type Agenda = StorageMap< + Pallet, + Twox64Concat, + ::BlockNumber, + Vec< + Option< + ScheduledV1<::RuntimeCall, ::BlockNumber>, + >, + >, + ValueQuery, + >; + + #[frame_support::storage_alias] + pub(crate) type Lookup = StorageMap< + Pallet, + Twox64Concat, + Vec, + TaskAddress<::BlockNumber>, + >; +} + +pub mod v2 { + use super::*; + use frame_support::pallet_prelude::*; + + #[frame_support::storage_alias] + pub(crate) type Agenda = StorageMap< + Pallet, + Twox64Concat, + ::BlockNumber, + Vec>>, + ValueQuery, + >; + + #[frame_support::storage_alias] + pub(crate) type Lookup = StorageMap< + Pallet, + Twox64Concat, + Vec, + TaskAddress<::BlockNumber>, + >; +} + +pub mod v3 { + use super::*; + use frame_support::pallet_prelude::*; + + #[frame_support::storage_alias] + pub(crate) type Agenda = StorageMap< + Pallet, + Twox64Concat, + ::BlockNumber, + Vec>>, + ValueQuery, + >; + + #[frame_support::storage_alias] + pub(crate) type Lookup = StorageMap< + Pallet, + Twox64Concat, + Vec, + TaskAddress<::BlockNumber>, + >; + + /// Migrate the scheduler pallet from V3 to V4. + pub struct MigrateToV4(sp_std::marker::PhantomData); + + impl> OnRuntimeUpgrade for MigrateToV4 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + assert_eq!(StorageVersion::get::>(), 3, "Can only upgrade from version 3"); + + let agendas = Agenda::::iter_keys().count() as u32; + let decodable_agendas = Agenda::::iter_values().count() as u32; + if agendas != decodable_agendas { + // This is not necessarily an error, but can happen when there are Calls + // in an Agenda that are not valid anymore with the new runtime. + log::error!( + target: TARGET, + "Can only decode {} of {} agendas - others will be dropped", + decodable_agendas, + agendas + ); + } + log::info!(target: TARGET, "Trying to migrate {} agendas...", decodable_agendas); + + // Check that no agenda overflows `MaxScheduledPerBlock`. + let max_scheduled_per_block = T::MaxScheduledPerBlock::get() as usize; + for (block_number, agenda) in Agenda::::iter() { + if agenda.iter().cloned().filter_map(|s| s).count() > max_scheduled_per_block { + log::error!( + target: TARGET, + "Would truncate agenda of block {:?} from {} items to {} items.", + block_number, + agenda.len(), + max_scheduled_per_block, + ); + return Err("Agenda would overflow `MaxScheduledPerBlock`.") + } + } + // Check that bounding the calls will not overflow `MAX_LENGTH`. + let max_length = T::Preimages::MAX_LENGTH as usize; + for (block_number, agenda) in Agenda::::iter() { + for schedule in agenda.iter().cloned().filter_map(|s| s) { + match schedule.call { + frame_support::traits::schedule::MaybeHashed::Value(call) => { + let l = call.using_encoded(|c| c.len()); + if l > max_length { + log::error!( + target: TARGET, + "Call in agenda of block {:?} is too large: {} byte", + block_number, + l, + ); + return Err("Call is too large.") + } + }, + _ => (), + } + } + } + + Ok((decodable_agendas as u32).encode()) + } + + fn on_runtime_upgrade() -> Weight { + let version = StorageVersion::get::>(); + if version != 3 { + log::warn!( + target: TARGET, + "skipping v3 to v4 migration: executed on wrong storage version.\ + Expected version 3, found {:?}", + version, + ); + return T::DbWeight::get().reads(1) + } + + crate::Pallet::::migrate_v3_to_v4() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + assert_eq!(StorageVersion::get::>(), 4, "Must upgrade"); + + // Check that everything decoded fine. + for k in crate::Agenda::::iter_keys() { + assert!(crate::Agenda::::try_get(k).is_ok(), "Cannot decode V4 Agenda"); + } + + let old_agendas: u32 = + Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + let new_agendas = crate::Agenda::::iter_keys().count() as u32; + if old_agendas != new_agendas { + // This is not necessarily an error, but can happen when there are Calls + // in an Agenda that are not valid anymore in the new runtime. + log::error!( + target: TARGET, + "Did not migrate all Agendas. Previous {}, Now {}", + old_agendas, + new_agendas, + ); + } else { + log::info!(target: TARGET, "Migrated {} agendas.", new_agendas); + } + + Ok(()) + } + } +} + +#[cfg(test)] +#[cfg(feature = "try-runtime")] +mod test { + use super::*; + use crate::mock::*; + use frame_support::Hashable; + use sp_std::borrow::Cow; + use substrate_test_utils::assert_eq_uvec; + + #[test] + #[allow(deprecated)] + fn migration_v3_to_v4_works() { + new_test_ext().execute_with(|| { + // Assume that we are at V3. + StorageVersion::new(3).put::(); + + // Call that will be bounded to a `Lookup`. + let large_call = + RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 1024] }); + // Call that can be inlined. + let small_call = + RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 10] }); + // Call that is already hashed and can will be converted to `Legacy`. + let hashed_call = + RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 2048] }); + let bound_hashed_call = Preimage::bound(hashed_call.clone()).unwrap(); + assert!(bound_hashed_call.lookup_needed()); + // A Call by hash that will fail to decode becomes `None`. + let trash_data = vec![255u8; 1024]; + let undecodable_hash = Preimage::note(Cow::Borrowed(&trash_data)).unwrap(); + + for i in 0..2u64 { + let k = i.twox_64_concat(); + let old = vec![ + Some(ScheduledV3Of:: { + maybe_id: None, + priority: i as u8 + 10, + call: small_call.clone().into(), + maybe_periodic: None, // 1 + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV3Of:: { + maybe_id: Some(vec![i as u8; 32]), + priority: 123, + call: large_call.clone().into(), + maybe_periodic: Some((4u64, 20)), + origin: signed(i), + _phantom: PhantomData::::default(), + }), + Some(ScheduledV3Of:: { + maybe_id: Some(vec![255 - i as u8; 320]), + priority: 123, + call: MaybeHashed::Hash(bound_hashed_call.hash()), + maybe_periodic: Some((8u64, 10)), + origin: signed(i), + _phantom: PhantomData::::default(), + }), + Some(ScheduledV3Of:: { + maybe_id: Some(vec![i as u8; 320]), + priority: 123, + call: MaybeHashed::Hash(undecodable_hash.clone()), + maybe_periodic: Some((4u64, 20)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ]; + frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); + } + + let state = v3::MigrateToV4::::pre_upgrade().unwrap(); + let _w = v3::MigrateToV4::::on_runtime_upgrade(); + v3::MigrateToV4::::post_upgrade(state).unwrap(); + + let mut x = Agenda::::iter().map(|x| (x.0, x.1.into_inner())).collect::>(); + x.sort_by_key(|x| x.0); + + let bound_large_call = Preimage::bound(large_call).unwrap(); + assert!(bound_large_call.lookup_needed()); + let bound_small_call = Preimage::bound(small_call).unwrap(); + assert!(!bound_small_call.lookup_needed()); + + let expected = vec![ + ( + 0, + vec![ + Some(ScheduledOf:: { + maybe_id: None, + priority: 10, + call: bound_small_call.clone(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&[0u8; 32])), + priority: 123, + call: bound_large_call.clone(), + maybe_periodic: Some((4u64, 20)), + origin: signed(0), + _phantom: PhantomData::::default(), + }), + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&[255u8; 320])), + priority: 123, + call: Bounded::from_legacy_hash(bound_hashed_call.hash()), + maybe_periodic: Some((8u64, 10)), + origin: signed(0), + _phantom: PhantomData::::default(), + }), + None, + ], + ), + ( + 1, + vec![ + Some(ScheduledOf:: { + maybe_id: None, + priority: 11, + call: bound_small_call.clone(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&[1u8; 32])), + priority: 123, + call: bound_large_call.clone(), + maybe_periodic: Some((4u64, 20)), + origin: signed(1), + _phantom: PhantomData::::default(), + }), + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&[254u8; 320])), + priority: 123, + call: Bounded::from_legacy_hash(bound_hashed_call.hash()), + maybe_periodic: Some((8u64, 10)), + origin: signed(1), + _phantom: PhantomData::::default(), + }), + None, + ], + ), + ]; + for (outer, (i, j)) in x.iter().zip(expected.iter()).enumerate() { + assert_eq!(i.0, j.0); + for (inner, (x, y)) in i.1.iter().zip(j.1.iter()).enumerate() { + assert_eq!(x, y, "at index: outer {} inner {}", outer, inner); + } + } + assert_eq_uvec!(x, expected); + + assert_eq!(StorageVersion::get::(), 4); + }); + } + + #[test] + #[allow(deprecated)] + fn migration_v3_to_v4_too_large_calls_are_ignored() { + new_test_ext().execute_with(|| { + // Assume that we are at V3. + StorageVersion::new(3).put::(); + + let too_large_call = RuntimeCall::System(frame_system::Call::remark { + remark: vec![0; ::Preimages::MAX_LENGTH + 1], + }); + + let i = 0u64; + let k = i.twox_64_concat(); + let old = vec![Some(ScheduledV3Of:: { + maybe_id: None, + priority: 1, + call: too_large_call.clone().into(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + })]; + frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); + + // The pre_upgrade hook fails: + let err = v3::MigrateToV4::::pre_upgrade().unwrap_err(); + assert!(err.contains("Call is too large")); + // But the migration itself works: + let _w = v3::MigrateToV4::::on_runtime_upgrade(); + + let mut x = Agenda::::iter().map(|x| (x.0, x.1.into_inner())).collect::>(); + x.sort_by_key(|x| x.0); + // The call becomes `None`. + let expected = vec![(0, vec![None])]; + assert_eq_uvec!(x, expected); + + assert_eq!(StorageVersion::get::(), 4); + }); + } + + fn signed(i: u64) -> OriginCaller { + system::RawOrigin::Signed(i).into() + } +} diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 6aaad13e48183..61efdfb67b73e 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -124,7 +124,7 @@ parameter_types! { } impl system::Config for Test { type BaseCallFilter = BaseFilter; - type BlockWeights = (); + type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = RocksDbWeight; type RuntimeOrigin = RuntimeOrigin; @@ -151,10 +151,6 @@ impl system::Config for Test { impl logger::Config for Test { type RuntimeEvent = RuntimeEvent; } -parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; - pub const NoPreimagePostponement: Option = Some(2); -} ord_parameter_types! { pub const One: u64 = 1; } @@ -164,11 +160,54 @@ impl pallet_preimage::Config for Test { type WeightInfo = (); type Currency = (); type ManagerOrigin = EnsureRoot; - type MaxSize = ConstU32<1024>; type BaseDeposit = (); type ByteDeposit = (); } +pub struct TestWeightInfo; +impl WeightInfo for TestWeightInfo { + fn service_agendas_base() -> Weight { + Weight::from_ref_time(0b0000_0001) + } + fn service_agenda_base(i: u32) -> Weight { + Weight::from_ref_time((i << 8) as u64 + 0b0000_0010) + } + fn service_task_base() -> Weight { + Weight::from_ref_time(0b0000_0100) + } + fn service_task_periodic() -> Weight { + Weight::from_ref_time(0b0000_1100) + } + fn service_task_named() -> Weight { + Weight::from_ref_time(0b0001_0100) + } + fn service_task_fetched(s: u32) -> Weight { + Weight::from_ref_time((s << 8) as u64 + 0b0010_0100) + } + fn execute_dispatch_signed() -> Weight { + Weight::from_ref_time(0b0100_0000) + } + fn execute_dispatch_unsigned() -> Weight { + Weight::from_ref_time(0b1000_0000) + } + fn schedule(_s: u32) -> Weight { + Weight::from_ref_time(50) + } + fn cancel(_s: u32) -> Weight { + Weight::from_ref_time(50) + } + fn schedule_named(_s: u32) -> Weight { + Weight::from_ref_time(50) + } + fn cancel_named(_s: u32) -> Weight { + Weight::from_ref_time(50) + } +} +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * + BlockWeights::get().max_block; +} + impl Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; @@ -177,10 +216,9 @@ impl Config for Test { type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EitherOfDiverse, EnsureSignedBy>; type MaxScheduledPerBlock = ConstU32<10>; - type WeightInfo = (); + type WeightInfo = TestWeightInfo; type OriginPrivilegeCmp = EqualPrivilegeOnly; - type PreimageProvider = Preimage; - type NoPreimagePostponement = NoPreimagePostponement; + type Preimages = Preimage; } pub type LoggerCall = logger::Call; diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index f6db70ae42d49..033d787946709 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -23,7 +23,7 @@ use crate::mock::{ }; use frame_support::{ assert_err, assert_noop, assert_ok, - traits::{Contains, GetStorageVersion, OnInitialize, PreimageProvider}, + traits::{Contains, GetStorageVersion, OnInitialize, QueryPreimage, StorePreimage}, Hashable, }; use sp_runtime::traits::Hash; @@ -33,9 +33,15 @@ use substrate_test_utils::assert_eq_uvec; fn basic_scheduling_works() { new_test_ext().execute_with(|| { let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into())); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap() + )); run_to_block(3); assert!(logger::log().is_empty()); run_to_block(4); @@ -49,51 +55,19 @@ fn basic_scheduling_works() { fn scheduling_with_preimages_works() { new_test_ext().execute_with(|| { let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); let hash = ::Hashing::hash_of(&call); - let hashed = MaybeHashed::Hash(hash); + let len = call.using_encoded(|x| x.len()) as u32; + let hashed = Preimage::pick(hash, len); assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); - assert!(Preimage::preimage_requested(&hash)); + assert!(Preimage::is_requested(&hash)); run_to_block(3); assert!(logger::log().is_empty()); run_to_block(4); - assert!(!Preimage::have_preimage(&hash)); - assert!(!Preimage::preimage_requested(&hash)); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -#[test] -fn scheduling_with_preimage_postpones_correctly() { - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); - let hash = ::Hashing::hash_of(&call); - let hashed = MaybeHashed::Hash(hash); - - assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); - assert!(Preimage::preimage_requested(&hash)); - - run_to_block(4); - // #4 empty due to no preimage - assert!(logger::log().is_empty()); - - // Register preimage. - assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); - - run_to_block(5); - // #5 empty since postponement is 2 blocks. - assert!(logger::log().is_empty()); - - run_to_block(6); - // #6 is good. + assert!(!Preimage::len(&hash).is_some()); + assert!(!Preimage::is_requested(&hash)); assert_eq!(logger::log(), vec![(root(), 42u32)]); - assert!(!Preimage::have_preimage(&hash)); - assert!(!Preimage::preimage_requested(&hash)); - run_to_block(100); assert_eq!(logger::log(), vec![(root(), 42u32)]); }); @@ -104,10 +78,16 @@ fn schedule_after_works() { new_test_ext().execute_with(|| { run_to_block(2); let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 - assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call.into())); + assert_ok!(Scheduler::do_schedule( + DispatchTime::After(3), + None, + 127, + root(), + Preimage::bound(call).unwrap() + )); run_to_block(5); assert!(logger::log().is_empty()); run_to_block(6); @@ -122,9 +102,15 @@ fn schedule_after_zero_works() { new_test_ext().execute_with(|| { run_to_block(2); let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call.into())); + assert_ok!(Scheduler::do_schedule( + DispatchTime::After(0), + None, + 127, + root(), + Preimage::bound(call).unwrap() + )); // Will trigger on the next block. run_to_block(3); assert_eq!(logger::log(), vec![(root(), 42u32)]); @@ -142,8 +128,11 @@ fn periodic_scheduling_works() { Some((3, 3)), 127, root(), - RuntimeCall::Logger(logger::Call::log { i: 42, weight: Weight::from_ref_time(1000) }) - .into() + Preimage::bound(RuntimeCall::Logger(logger::Call::log { + i: 42, + weight: Weight::from_ref_time(10) + })) + .unwrap() )); run_to_block(3); assert!(logger::log().is_empty()); @@ -166,10 +155,17 @@ fn periodic_scheduling_works() { fn reschedule_works() { new_test_ext().execute_with(|| { let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( - Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into()).unwrap(), + Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap() + ) + .unwrap(), (4, 0) ); @@ -198,16 +194,16 @@ fn reschedule_works() { fn reschedule_named_works() { new_test_ext().execute_with(|| { let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(4), None, 127, root(), - call.into(), + Preimage::bound(call).unwrap(), ) .unwrap(), (4, 0) @@ -216,13 +212,10 @@ fn reschedule_named_works() { run_to_block(3); assert!(logger::log().is_empty()); - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), - (6, 0) - ); + assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)).unwrap(), (6, 0)); assert_noop!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)), + Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)), Error::::RescheduleNoChange ); @@ -241,16 +234,16 @@ fn reschedule_named_works() { fn reschedule_named_perodic_works() { new_test_ext().execute_with(|| { let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(4), Some((3, 3)), 127, root(), - call.into(), + Preimage::bound(call).unwrap(), ) .unwrap(), (4, 0) @@ -259,14 +252,8 @@ fn reschedule_named_perodic_works() { run_to_block(3); assert!(logger::log().is_empty()); - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(5)).unwrap(), - (5, 0) - ); - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), - (6, 0) - ); + assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(5)).unwrap(), (5, 0)); + assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)).unwrap(), (6, 0)); run_to_block(5); assert!(logger::log().is_empty()); @@ -275,7 +262,7 @@ fn reschedule_named_perodic_works() { assert_eq!(logger::log(), vec![(root(), 42u32)]); assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(10)).unwrap(), + Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(10)).unwrap(), (10, 0) ); @@ -298,13 +285,16 @@ fn cancel_named_scheduling_works_with_normal_cancel() { new_test_ext().execute_with(|| { // at #4. Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(4), None, 127, root(), - RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) - .into(), + Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), ) .unwrap(); let i = Scheduler::do_schedule( @@ -312,13 +302,16 @@ fn cancel_named_scheduling_works_with_normal_cancel() { None, 127, root(), - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) - .into(), + Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })) + .unwrap(), ) .unwrap(); run_to_block(3); assert!(logger::log().is_empty()); - assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); + assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); assert_ok!(Scheduler::do_cancel(None, i)); run_to_block(100); assert!(logger::log().is_empty()); @@ -330,35 +323,44 @@ fn cancel_named_periodic_scheduling_works() { new_test_ext().execute_with(|| { // at #4, every 3 blocks, 3 times. Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(4), Some((3, 3)), 127, root(), - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) - .into(), + Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })) + .unwrap(), ) .unwrap(); // same id results in error. assert!(Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(4), None, 127, root(), - RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) - .into(), + Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10) + })) + .unwrap(), ) .is_err()); // different id is ok. Scheduler::do_schedule_named( - 2u32.encode(), + [2u8; 32], DispatchTime::At(8), None, 127, root(), - RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) - .into(), + Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), ) .unwrap(); run_to_block(3); @@ -366,7 +368,7 @@ fn cancel_named_periodic_scheduling_works() { run_to_block(4); assert_eq!(logger::log(), vec![(root(), 42u32)]); run_to_block(6); - assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); + assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); run_to_block(100); assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); }); @@ -374,28 +376,23 @@ fn cancel_named_periodic_scheduling_works() { #[test] fn scheduler_respects_weight_limits() { + let max_weight: Weight = ::MaximumWeight::get(); new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 * 2 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: MaximumSchedulerWeight::get() / 2 - }) - .into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 * 2 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: MaximumSchedulerWeight::get() / 2 - }) - .into(), + Preimage::bound(call).unwrap(), )); // 69 and 42 do not fit together run_to_block(4); @@ -405,62 +402,128 @@ fn scheduler_respects_weight_limits() { }); } +/// Permanently overweight calls are not deleted but also not executed. #[test] -fn scheduler_respects_hard_deadlines_more() { +fn scheduler_does_not_delete_permanently_overweight_call() { + let max_weight: Weight = ::MaximumWeight::get(); new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, - 0, + 127, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: MaximumSchedulerWeight::get() / 2 - }) - .into(), + Preimage::bound(call).unwrap(), )); + // Never executes. + run_to_block(100); + assert_eq!(logger::log(), vec![]); + + // Assert the `PermanentlyOverweight` event. + assert_eq!( + System::events().last().unwrap().event, + crate::Event::PermanentlyOverweight { task: (4, 0), id: None }.into(), + ); + // The call is still in the agenda. + assert!(Agenda::::get(4)[0].is_some()); + }); +} + +#[test] +fn scheduler_handles_periodic_failure() { + let max_weight: Weight = ::MaximumWeight::get(); + let max_per_block = ::MaxScheduledPerBlock::get(); + + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 }); + let bound = Preimage::bound(call).unwrap(); + assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), - None, - 0, + Some((4, u32::MAX)), + 127, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: MaximumSchedulerWeight::get() / 2 - }) - .into(), + bound.clone(), + )); + // Executes 5 times till block 20. + run_to_block(20); + assert_eq!(logger::log().len(), 5); + + // Block 28 will already be full. + for _ in 0..max_per_block { + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(28), + None, + 120, + root(), + bound.clone(), + )); + } + + // Going to block 24 will emit a `PeriodicFailed` event. + run_to_block(24); + assert_eq!(logger::log().len(), 6); + + assert_eq!( + System::events().last().unwrap().event, + crate::Event::PeriodicFailed { task: (24, 0), id: None }.into(), + ); + }); +} + +#[test] +fn scheduler_handles_periodic_unavailable_preimage() { + let max_weight: Weight = ::MaximumWeight::get(); + + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 }); + let hash = ::Hashing::hash_of(&call); + let len = call.using_encoded(|x| x.len()) as u32; + let bound = Preimage::pick(hash, len); + assert_ok!(Preimage::note(call.encode().into())); + + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + Some((4, u32::MAX)), + 127, + root(), + bound.clone(), )); - // With base weights, 69 and 42 should not fit together, but do because of hard - // deadlines + // Executes 1 times till block 4. run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); + assert_eq!(logger::log().len(), 1); + + // Unnote the preimage. + Preimage::unnote(&hash); + + // Does not ever execute again. + run_to_block(100); + assert_eq!(logger::log().len(), 1); + + // The preimage is not requested anymore. + assert!(!Preimage::is_requested(&hash)); }); } #[test] fn scheduler_respects_priority_ordering() { + let max_weight: Weight = ::MaximumWeight::get(); new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 1, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: MaximumSchedulerWeight::get() / 2 - }) - .into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 0, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: MaximumSchedulerWeight::get() / 2 - }) - .into(), + Preimage::bound(call).unwrap(), )); run_to_block(4); assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); @@ -470,35 +533,30 @@ fn scheduler_respects_priority_ordering() { #[test] fn scheduler_respects_priority_ordering_with_soft_deadlines() { new_test_ext().execute_with(|| { - let max_weight = MaximumSchedulerWeight::get() - <() as WeightInfo>::on_initialize(0); - let item_weight = - <() as WeightInfo>::on_initialize(1) - <() as WeightInfo>::on_initialize(0); + let max_weight: Weight = ::MaximumWeight::get(); + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 5 * 2 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 255, root(), - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 2 - item_weight }) - .into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 5 * 2 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 2 - item_weight }) - .into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { i: 2600, weight: max_weight / 5 * 4 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 126, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 2600, - weight: max_weight / 2 - item_weight + Weight::from_ref_time(1) - }) - .into(), + Preimage::bound(call).unwrap(), )); // 2600 does not fit with 69 or 42, but has higher priority, so will go through @@ -513,90 +571,96 @@ fn scheduler_respects_priority_ordering_with_soft_deadlines() { #[test] fn on_initialize_weight_is_correct() { new_test_ext().execute_with(|| { - let base_weight = <() as WeightInfo>::on_initialize(0); - let call_weight = MaximumSchedulerWeight::get() / 4; + let call_weight = Weight::from_ref_time(25); // Named + let call = RuntimeCall::Logger(LoggerCall::log { + i: 3, + weight: call_weight + Weight::from_ref_time(1), + }); assert_ok!(Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(3), None, 255, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 3, - weight: call_weight + Weight::from_ref_time(1) - }) - .into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: call_weight + Weight::from_ref_time(2), + }); // Anon Periodic assert_ok!(Scheduler::do_schedule( DispatchTime::At(2), Some((1000, 3)), 128, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: call_weight + Weight::from_ref_time(2) - }) - .into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: call_weight + Weight::from_ref_time(3), + }); // Anon assert_ok!(Scheduler::do_schedule( DispatchTime::At(2), None, 127, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: call_weight + Weight::from_ref_time(3) - }) - .into(), + Preimage::bound(call).unwrap(), )); // Named Periodic + let call = RuntimeCall::Logger(LoggerCall::log { + i: 2600, + weight: call_weight + Weight::from_ref_time(4), + }); assert_ok!(Scheduler::do_schedule_named( - 2u32.encode(), + [2u8; 32], DispatchTime::At(1), Some((1000, 3)), 126, root(), - RuntimeCall::Logger(LoggerCall::log { - i: 2600, - weight: call_weight + Weight::from_ref_time(4) - }) - .into(), + Preimage::bound(call).unwrap(), )); // Will include the named periodic only - let actual_weight = Scheduler::on_initialize(1); assert_eq!( - actual_weight, - base_weight + - call_weight + Weight::from_ref_time(4) + - <() as MarginalWeightInfo>::item(true, true, Some(false)) + Scheduler::on_initialize(1), + TestWeightInfo::service_agendas_base() + + TestWeightInfo::service_agenda_base(1) + + ::service_task(None, true, true) + + TestWeightInfo::execute_dispatch_unsigned() + + call_weight + Weight::from_ref_time(4) ); + assert_eq!(IncompleteSince::::get(), None); assert_eq!(logger::log(), vec![(root(), 2600u32)]); // Will include anon and anon periodic - let actual_weight = Scheduler::on_initialize(2); assert_eq!( - actual_weight, - base_weight + - call_weight + Weight::from_ref_time(2) + - <() as MarginalWeightInfo>::item(false, false, Some(false)) + + Scheduler::on_initialize(2), + TestWeightInfo::service_agendas_base() + + TestWeightInfo::service_agenda_base(2) + + ::service_task(None, false, true) + + TestWeightInfo::execute_dispatch_unsigned() + call_weight + Weight::from_ref_time(3) + - <() as MarginalWeightInfo>::item(true, false, Some(false)) + ::service_task(None, false, false) + + TestWeightInfo::execute_dispatch_unsigned() + + call_weight + Weight::from_ref_time(2) ); + assert_eq!(IncompleteSince::::get(), None); assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); // Will include named only - let actual_weight = Scheduler::on_initialize(3); assert_eq!( - actual_weight, - base_weight + - call_weight + Weight::from_ref_time(1) + - <() as MarginalWeightInfo>::item(false, true, Some(false)) + Scheduler::on_initialize(3), + TestWeightInfo::service_agendas_base() + + TestWeightInfo::service_agenda_base(1) + + ::service_task(None, true, false) + + TestWeightInfo::execute_dispatch_unsigned() + + call_weight + Weight::from_ref_time(1) ); + assert_eq!(IncompleteSince::::get(), None); assert_eq!( logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)] @@ -604,35 +668,33 @@ fn on_initialize_weight_is_correct() { // Will contain none let actual_weight = Scheduler::on_initialize(4); - assert_eq!(actual_weight, base_weight); + assert_eq!( + actual_weight, + TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(0) + ); }); } #[test] fn root_calls_works() { new_test_ext().execute_with(|| { - let call = Box::new( - RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) - .into(), - ); - let call2 = Box::new( - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) - .into(), + let call = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); + assert_ok!( + Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 4, None, 127, call,) ); - assert_ok!(Scheduler::schedule_named( - RuntimeOrigin::root(), - 1u32.encode(), - 4, - None, - 127, - call, - )); assert_ok!(Scheduler::schedule(RuntimeOrigin::root(), 4, None, 127, call2)); run_to_block(3); // Scheduled calls are in the agenda. assert_eq!(Agenda::::get(4).len(), 2); assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(RuntimeOrigin::root(), 1u32.encode())); + assert_ok!(Scheduler::cancel_named(RuntimeOrigin::root(), [1u8; 32])); assert_ok!(Scheduler::cancel(RuntimeOrigin::root(), 4, 1)); // Scheduled calls are made NONE, so should not effect state run_to_block(100); @@ -645,29 +707,30 @@ fn fails_to_schedule_task_in_the_past() { new_test_ext().execute_with(|| { run_to_block(3); - let call1 = Box::new( - RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) - .into(), - ); - let call2 = Box::new( - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) - .into(), - ); - let call3 = Box::new( - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) - .into(), - ); - assert_err!( - Scheduler::schedule_named(RuntimeOrigin::root(), 1u32.encode(), 2, None, 127, call1), + let call1 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); + let call3 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); + + assert_noop!( + Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 2, None, 127, call1), Error::::TargetBlockNumberInPast, ); - assert_err!( + assert_noop!( Scheduler::schedule(RuntimeOrigin::root(), 2, None, 127, call2), Error::::TargetBlockNumberInPast, ); - assert_err!( + assert_noop!( Scheduler::schedule(RuntimeOrigin::root(), 3, None, 127, call3), Error::::TargetBlockNumberInPast, ); @@ -675,19 +738,19 @@ fn fails_to_schedule_task_in_the_past() { } #[test] -fn should_use_orign() { +fn should_use_origin() { new_test_ext().execute_with(|| { - let call = Box::new( - RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) - .into(), - ); - let call2 = Box::new( - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) - .into(), - ); + let call = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), - 1u32.encode(), + [1u8; 32], 4, None, 127, @@ -698,7 +761,7 @@ fn should_use_orign() { // Scheduled calls are in the agenda. assert_eq!(Agenda::::get(4).len(), 2); assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), 1u32.encode())); + assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), [1u8; 32])); assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1)); // Scheduled calls are made NONE, so should not effect state run_to_block(100); @@ -707,20 +770,20 @@ fn should_use_orign() { } #[test] -fn should_check_orign() { +fn should_check_origin() { new_test_ext().execute_with(|| { - let call = Box::new( - RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }) - .into(), - ); - let call2 = Box::new( - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }) - .into(), - ); + let call = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); assert_noop!( Scheduler::schedule_named( system::RawOrigin::Signed(2).into(), - 1u32.encode(), + [1u8; 32], 4, None, 127, @@ -736,25 +799,19 @@ fn should_check_orign() { } #[test] -fn should_check_orign_for_cancel() { +fn should_check_origin_for_cancel() { new_test_ext().execute_with(|| { - let call = Box::new( - RuntimeCall::Logger(LoggerCall::log_without_filter { - i: 69, - weight: Weight::from_ref_time(1000), - }) - .into(), - ); - let call2 = Box::new( - RuntimeCall::Logger(LoggerCall::log_without_filter { - i: 42, - weight: Weight::from_ref_time(1000), - }) - .into(), - ); + let call = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter { + i: 42, + weight: Weight::from_ref_time(10), + })); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), - 1u32.encode(), + [1u8; 32], 4, None, 127, @@ -766,14 +823,11 @@ fn should_check_orign_for_cancel() { assert_eq!(Agenda::::get(4).len(), 2); assert!(logger::log().is_empty()); assert_noop!( - Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), 1u32.encode()), + Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), [1u8; 32]), BadOrigin ); assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin); - assert_noop!( - Scheduler::cancel_named(system::RawOrigin::Root.into(), 1u32.encode()), - BadOrigin - ); + assert_noop!(Scheduler::cancel_named(system::RawOrigin::Root.into(), [1u8; 32]), BadOrigin); assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin); run_to_block(5); assert_eq!( @@ -787,7 +841,7 @@ fn should_check_orign_for_cancel() { } #[test] -fn migration_to_v3_works() { +fn migration_to_v4_works() { new_test_ext().execute_with(|| { for i in 0..3u64 { let k = i.twox_64_concat(); @@ -807,7 +861,7 @@ fn migration_to_v3_works() { priority: 123, call: RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(1000), + weight: Weight::from_ref_time(10), }), maybe_periodic: Some((456u64, 10)), }), @@ -815,103 +869,109 @@ fn migration_to_v3_works() { frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); } - Scheduler::migrate_v1_to_v3(); - - assert_eq_uvec!( - Agenda::::iter().collect::>(), - vec![ - ( - 0, - vec![ - Some(ScheduledV3Of:: { - maybe_id: None, - priority: 10, - call: RuntimeCall::Logger(LoggerCall::log { - i: 96, - weight: Weight::from_ref_time(100) - }) - .into(), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV3Of:: { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 1, - vec![ - Some(ScheduledV3Of:: { - maybe_id: None, - priority: 11, - call: RuntimeCall::Logger(LoggerCall::log { - i: 96, - weight: Weight::from_ref_time(100) - }) - .into(), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV3Of:: { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 2, - vec![ - Some(ScheduledV3Of:: { - maybe_id: None, - priority: 12, - call: RuntimeCall::Logger(LoggerCall::log { - i: 96, - weight: Weight::from_ref_time(100) - }) - .into(), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV3Of:: { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ) - ] - ); + Scheduler::migrate_v1_to_v4(); + + let mut x = Agenda::::iter().map(|x| (x.0, x.1.into_inner())).collect::>(); + x.sort_by_key(|x| x.0); + let expected = vec![ + ( + 0, + vec![ + Some(ScheduledOf:: { + maybe_id: None, + priority: 10, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100), + })) + .unwrap(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&b"test"[..])), + priority: 123, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ], + ), + ( + 1, + vec![ + Some(ScheduledOf:: { + maybe_id: None, + priority: 11, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100), + })) + .unwrap(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&b"test"[..])), + priority: 123, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ], + ), + ( + 2, + vec![ + Some(ScheduledOf:: { + maybe_id: None, + priority: 12, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100), + })) + .unwrap(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&b"test"[..])), + priority: 123, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ], + ), + ]; + for (i, j) in x.iter().zip(expected.iter()) { + assert_eq!(i.0, j.0); + for (x, y) in i.1.iter().zip(j.1.iter()) { + assert_eq!(x, y); + } + } + assert_eq_uvec!(x, expected); assert_eq!(Scheduler::current_storage_version(), 3); }); @@ -922,29 +982,29 @@ fn test_migrate_origin() { new_test_ext().execute_with(|| { for i in 0..3u64 { let k = i.twox_64_concat(); - let old: Vec, u64, u32, u64>>> = vec![ + let old: Vec, u64, u32, u64>>> = vec![ Some(Scheduled { maybe_id: None, priority: i as u8 + 10, - call: RuntimeCall::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100), - }) - .into(), + })) + .unwrap(), origin: 3u32, maybe_periodic: None, _phantom: Default::default(), }), None, Some(Scheduled { - maybe_id: Some(b"test".to_vec()), + maybe_id: Some(blake2_256(&b"test"[..])), priority: 123, origin: 2u32, - call: RuntimeCall::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(1000), - }) - .into(), + weight: Weight::from_ref_time(10), + })) + .unwrap(), maybe_periodic: Some((456u64, 10)), _phantom: Default::default(), }), @@ -965,32 +1025,32 @@ fn test_migrate_origin() { Scheduler::migrate_origin::(); assert_eq_uvec!( - Agenda::::iter().collect::>(), + Agenda::::iter().map(|x| (x.0, x.1.into_inner())).collect::>(), vec![ ( 0, vec![ - Some(ScheduledV2::, u64, OriginCaller, u64> { + Some(ScheduledOf:: { maybe_id: None, priority: 10, - call: RuntimeCall::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) - }) - .into(), + })) + .unwrap(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), }), None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), + Some(Scheduled { + maybe_id: Some(blake2_256(&b"test"[..])), priority: 123, - call: RuntimeCall::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), + weight: Weight::from_ref_time(10) + })) + .unwrap(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), @@ -1000,27 +1060,27 @@ fn test_migrate_origin() { ( 1, vec![ - Some(ScheduledV2 { + Some(Scheduled { maybe_id: None, priority: 11, - call: RuntimeCall::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) - }) - .into(), + })) + .unwrap(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), }), None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), + Some(Scheduled { + maybe_id: Some(blake2_256(&b"test"[..])), priority: 123, - call: RuntimeCall::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), + weight: Weight::from_ref_time(10) + })) + .unwrap(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), @@ -1030,27 +1090,27 @@ fn test_migrate_origin() { ( 2, vec![ - Some(ScheduledV2 { + Some(Scheduled { maybe_id: None, priority: 12, - call: RuntimeCall::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) - }) - .into(), + })) + .unwrap(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), }), None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), + Some(Scheduled { + maybe_id: Some(blake2_256(&b"test"[..])), priority: 123, - call: RuntimeCall::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), + weight: Weight::from_ref_time(10) + })) + .unwrap(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), @@ -1061,3 +1121,649 @@ fn test_migrate_origin() { ); }); } + +#[test] +fn postponed_named_task_cannot_be_rescheduled() { + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let hash = ::Hashing::hash_of(&call); + let len = call.using_encoded(|x| x.len()) as u32; + let hashed = Preimage::pick(hash, len); + let name: [u8; 32] = hash.as_ref().try_into().unwrap(); + + let address = Scheduler::do_schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + hashed.clone(), + ) + .unwrap(); + assert!(Preimage::is_requested(&hash)); + assert!(Lookup::::contains_key(name)); + + // Run to a very large block. + run_to_block(10); + // It was not executed. + assert!(logger::log().is_empty()); + assert!(Preimage::is_requested(&hash)); + // Postponing removes the lookup. + assert!(!Lookup::::contains_key(name)); + + // The agenda still contains the call. + let agenda = Agenda::::iter().collect::>(); + assert_eq!(agenda.len(), 1); + assert_eq!( + agenda[0].1, + vec![Some(Scheduled { + maybe_id: Some(name), + priority: 127, + call: hashed, + maybe_periodic: None, + origin: root().into(), + _phantom: Default::default(), + })] + ); + + // Finally add the preimage. + assert_ok!(Preimage::note(call.encode().into())); + run_to_block(1000); + // It did not execute. + assert!(logger::log().is_empty()); + assert!(Preimage::is_requested(&hash)); + + // Manually re-schedule the call by name does not work. + assert_err!( + Scheduler::do_reschedule_named(name, DispatchTime::At(1001)), + Error::::NotFound + ); + // Manually re-scheduling the call by address errors. + assert_err!( + Scheduler::do_reschedule(address, DispatchTime::At(1001)), + Error::::Named + ); + }); +} + +/// Using the scheduler as `v3::Anon` works. +#[test] +fn scheduler_v3_anon_basic_works() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + + // Schedule a call. + let _address = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + // Executes in block 4. + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // ... but not again. + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn scheduler_v3_anon_cancel_works() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + + // Schedule a call. + let address = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + // Cancel the call. + assert_ok!(>::cancel(address)); + // It did not get executed. + run_to_block(100); + assert!(logger::log().is_empty()); + // Cannot cancel again. + assert_err!(>::cancel(address), DispatchError::Unavailable); + }); +} + +#[test] +fn scheduler_v3_anon_reschedule_works() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + + // Schedule a call. + let address = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + + // Cannot re-schedule into the same block. + assert_noop!( + >::reschedule(address, DispatchTime::At(4)), + Error::::RescheduleNoChange + ); + // Cannot re-schedule into the past. + assert_noop!( + >::reschedule(address, DispatchTime::At(3)), + Error::::TargetBlockNumberInPast + ); + // Re-schedule to block 5. + assert_ok!(>::reschedule(address, DispatchTime::At(5))); + // Scheduled for block 5. + run_to_block(4); + assert!(logger::log().is_empty()); + run_to_block(5); + // Does execute in block 5. + assert_eq!(logger::log(), vec![(root(), 42)]); + // Cannot re-schedule executed task. + assert_noop!( + >::reschedule(address, DispatchTime::At(10)), + DispatchError::Unavailable + ); + }); +} + +/// Cancelling a call and then scheduling a second call for the same +/// block results in different addresses. +#[test] +fn scheduler_v3_anon_schedule_does_not_resuse_addr() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + + // Schedule both calls. + let addr_1 = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call.clone()).unwrap(), + ) + .unwrap(); + // Cancel the call. + assert_ok!(>::cancel(addr_1)); + let addr_2 = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + + // Should not re-use the address. + assert!(addr_1 != addr_2); + }); +} + +#[test] +fn scheduler_v3_anon_next_schedule_time_works() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + + // Schedule a call. + let address = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + + // Scheduled for block 4. + assert_eq!(>::next_dispatch_time(address), Ok(4)); + // Block 4 executes it. + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42)]); + + // It has no dispatch time anymore. + assert_noop!( + >::next_dispatch_time(address), + DispatchError::Unavailable + ); + }); +} + +/// Re-scheduling a task changes its next dispatch time. +#[test] +fn scheduler_v3_anon_reschedule_and_next_schedule_time_work() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + + // Schedule a call. + let old_address = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + + // Scheduled for block 4. + assert_eq!(>::next_dispatch_time(old_address), Ok(4)); + // Re-schedule to block 5. + let address = + >::reschedule(old_address, DispatchTime::At(5)).unwrap(); + assert!(address != old_address); + // Scheduled for block 5. + assert_eq!(>::next_dispatch_time(address), Ok(5)); + + // Block 4 does nothing. + run_to_block(4); + assert!(logger::log().is_empty()); + // Block 5 executes it. + run_to_block(5); + assert_eq!(logger::log(), vec![(root(), 42)]); + }); +} + +#[test] +fn scheduler_v3_anon_schedule_agenda_overflows() { + use frame_support::traits::schedule::v3::Anon; + let max: u32 = ::MaxScheduledPerBlock::get(); + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + + // Schedule the maximal number allowed per block. + for _ in 0..max { + >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + } + + // One more time and it errors. + assert_noop!( + >::schedule(DispatchTime::At(4), None, 127, root(), bound,), + DispatchError::Exhausted + ); + + run_to_block(4); + // All scheduled calls are executed. + assert_eq!(logger::log().len() as u32, max); + }); +} + +/// Cancelling and scheduling does not overflow the agenda but fills holes. +#[test] +fn scheduler_v3_anon_cancel_and_schedule_fills_holes() { + use frame_support::traits::schedule::v3::Anon; + let max: u32 = ::MaxScheduledPerBlock::get(); + assert!(max > 3, "This test only makes sense for MaxScheduledPerBlock > 3"); + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + let mut addrs = Vec::<_>::default(); + + // Schedule the maximal number allowed per block. + for _ in 0..max { + addrs.push( + >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(), + ); + } + // Cancel three of them. + for addr in addrs.into_iter().take(3) { + >::cancel(addr).unwrap(); + } + // Schedule three new ones. + for i in 0..3 { + let (_block, index) = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + assert_eq!(i, index); + } + + run_to_block(4); + // Maximum number of calls are executed. + assert_eq!(logger::log().len() as u32, max); + }); +} + +/// Re-scheduling does not overflow the agenda but fills holes. +#[test] +fn scheduler_v3_anon_reschedule_fills_holes() { + use frame_support::traits::schedule::v3::Anon; + let max: u32 = ::MaxScheduledPerBlock::get(); + assert!(max > 3, "pre-condition: This test only makes sense for MaxScheduledPerBlock > 3"); + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + let mut addrs = Vec::<_>::default(); + + // Schedule the maximal number allowed per block. + for _ in 0..max { + addrs.push( + >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(), + ); + } + let mut new_addrs = Vec::<_>::default(); + // Reversed last three elements of block 4. + let last_three = addrs.into_iter().rev().take(3).collect::>(); + // Re-schedule three of them to block 5. + for addr in last_three.iter().cloned() { + new_addrs + .push(>::reschedule(addr, DispatchTime::At(5)).unwrap()); + } + // Re-scheduling them back into block 3 should result in the same addrs. + for (old, want) in new_addrs.into_iter().zip(last_three.into_iter().rev()) { + let new = >::reschedule(old, DispatchTime::At(4)).unwrap(); + assert_eq!(new, want); + } + + run_to_block(4); + // Maximum number of calls are executed. + assert_eq!(logger::log().len() as u32, max); + }); +} + +/// Re-scheduling into the same block produces a different address +/// if there is still space in the agenda. +#[test] +fn scheduler_v3_anon_reschedule_does_not_resuse_addr_if_agenda_not_full() { + use frame_support::traits::schedule::v3::Anon; + let max: u32 = ::MaxScheduledPerBlock::get(); + assert!(max > 1, "This test only makes sense for MaxScheduledPerBlock > 1"); + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + + // Schedule both calls. + let addr_1 = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call.clone()).unwrap(), + ) + .unwrap(); + // Cancel the call. + assert_ok!(>::cancel(addr_1)); + let addr_2 = >::schedule( + DispatchTime::At(5), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + // Re-schedule `call` to block 4. + let addr_3 = >::reschedule(addr_2, DispatchTime::At(4)).unwrap(); + + // Should not re-use the address. + assert!(addr_1 != addr_3); + }); +} + +/// The scheduler can be used as `v3::Named` trait. +#[test] +fn scheduler_v3_named_basic_works() { + use frame_support::traits::schedule::v3::Named; + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let name = [1u8; 32]; + + // Schedule a call. + let _address = >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + // Executes in block 4. + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // ... but not again. + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +/// A named task can be cancelled by its name. +#[test] +fn scheduler_v3_named_cancel_named_works() { + use frame_support::traits::schedule::v3::Named; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + let name = [1u8; 32]; + + // Schedule a call. + >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + // Cancel the call by name. + assert_ok!(>::cancel_named(name)); + // It did not get executed. + run_to_block(100); + assert!(logger::log().is_empty()); + // Cannot cancel again. + assert_noop!(>::cancel_named(name), DispatchError::Unavailable); + }); +} + +/// A named task can also be cancelled by its address. +#[test] +fn scheduler_v3_named_cancel_without_name_works() { + use frame_support::traits::schedule::v3::{Anon, Named}; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + let name = [1u8; 32]; + + // Schedule a call. + let address = >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + // Cancel the call by address. + assert_ok!(>::cancel(address)); + // It did not get executed. + run_to_block(100); + assert!(logger::log().is_empty()); + // Cannot cancel again. + assert_err!(>::cancel(address), DispatchError::Unavailable); + }); +} + +/// A named task can be re-scheduled by its name but not by its address. +#[test] +fn scheduler_v3_named_reschedule_named_works() { + use frame_support::traits::schedule::v3::{Anon, Named}; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let name = [1u8; 32]; + + // Schedule a call. + let address = >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + + // Cannot re-schedule by address. + assert_noop!( + >::reschedule(address, DispatchTime::At(10)), + Error::::Named, + ); + // Cannot re-schedule into the same block. + assert_noop!( + >::reschedule_named(name, DispatchTime::At(4)), + Error::::RescheduleNoChange + ); + // Cannot re-schedule into the past. + assert_noop!( + >::reschedule_named(name, DispatchTime::At(3)), + Error::::TargetBlockNumberInPast + ); + // Re-schedule to block 5. + assert_ok!(>::reschedule_named(name, DispatchTime::At(5))); + // Scheduled for block 5. + run_to_block(4); + assert!(logger::log().is_empty()); + run_to_block(5); + // Does execute in block 5. + assert_eq!(logger::log(), vec![(root(), 42)]); + // Cannot re-schedule executed task. + assert_noop!( + >::reschedule_named(name, DispatchTime::At(10)), + DispatchError::Unavailable + ); + // Also not by address. + assert_noop!( + >::reschedule(address, DispatchTime::At(10)), + DispatchError::Unavailable + ); + }); +} + +#[test] +fn scheduler_v3_named_next_schedule_time_works() { + use frame_support::traits::schedule::v3::{Anon, Named}; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + let name = [1u8; 32]; + + // Schedule a call. + let address = >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + + // Scheduled for block 4. + assert_eq!(>::next_dispatch_time(name), Ok(4)); + // Also works by address. + assert_eq!(>::next_dispatch_time(address), Ok(4)); + // Block 4 executes it. + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42)]); + + // It has no dispatch time anymore. + assert_noop!( + >::next_dispatch_time(name), + DispatchError::Unavailable + ); + // Also not by address. + assert_noop!( + >::next_dispatch_time(address), + DispatchError::Unavailable + ); + }); +} diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index afbcf9373b2de..cb72fe3e2fdda 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,22 +18,24 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_scheduler // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --pallet=pallet_scheduler +// --chain=dev // --output=./frame/scheduler/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -44,16 +46,14 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_scheduler. pub trait WeightInfo { - fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight; - fn on_initialize_named_resolved(s: u32, ) -> Weight; - fn on_initialize_periodic_resolved(s: u32, ) -> Weight; - fn on_initialize_resolved(s: u32, ) -> Weight; - fn on_initialize_named_aborted(s: u32, ) -> Weight; - fn on_initialize_aborted(s: u32, ) -> Weight; - fn on_initialize_periodic_named(s: u32, ) -> Weight; - fn on_initialize_periodic(s: u32, ) -> Weight; - fn on_initialize_named(s: u32, ) -> Weight; - fn on_initialize(s: u32, ) -> Weight; + fn service_agendas_base() -> Weight; + fn service_agenda_base(s: u32, ) -> Weight; + fn service_task_base() -> Weight; + fn service_task_fetched(s: u32, ) -> Weight; + fn service_task_named() -> Weight; + fn service_task_periodic() -> Weight; + fn execute_dispatch_signed() -> Weight; + fn execute_dispatch_unsigned() -> Weight; fn schedule(s: u32, ) -> Weight; fn cancel(s: u32, ) -> Weight; fn schedule_named(s: u32, ) -> Weight; @@ -63,149 +63,84 @@ pub trait WeightInfo { /// Weights for pallet_scheduler using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(9_994_000 as u64) - // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(19_843_000 as u64).saturating_mul(s as u64)) + // Storage: Scheduler IncompleteSince (r:1 w:1) + fn service_agendas_base() -> Weight { + Weight::from_ref_time(4_992_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(s as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(10_318_000 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(15_451_000 as u64).saturating_mul(s as u64)) + /// The range of component `s` is `[0, 512]`. + fn service_agenda_base(s: u32, ) -> Weight { + Weight::from_ref_time(4_320_000 as u64) + // Standard Error: 619 + .saturating_add(Weight::from_ref_time(336_713 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(s as u64))) } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_675_000 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(17_019_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(s as u64))) + fn service_task_base() -> Weight { + Weight::from_ref_time(10_864_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) - fn on_initialize_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_934_000 as u64) - // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(14_134_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:0) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(7_279_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(5_388_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:0) - fn on_initialize_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(8_619_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_969_000 as u64).saturating_mul(s as u64)) + /// The range of component `s` is `[128, 4194304]`. + fn service_task_fetched(s: u32, ) -> Weight { + Weight::from_ref_time(24_586_000 as u64) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(1_138 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) } - // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_named(s: u32, ) -> Weight { - Weight::from_ref_time(16_129_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(9_772_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + fn service_task_named() -> Weight { + Weight::from_ref_time(13_127_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) } - // Storage: Scheduler Agenda (r:2 w:2) - fn on_initialize_periodic(s: u32, ) -> Weight { - Weight::from_ref_time(15_785_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(7_208_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + fn service_task_periodic() -> Weight { + Weight::from_ref_time(11_053_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named(s: u32, ) -> Weight { - Weight::from_ref_time(15_778_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(5_597_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + fn execute_dispatch_signed() -> Weight { + Weight::from_ref_time(4_158_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) - fn on_initialize(s: u32, ) -> Weight { - Weight::from_ref_time(15_912_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(4_530_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + fn execute_dispatch_unsigned() -> Weight { + Weight::from_ref_time(4_104_000 as u64) } // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { - Weight::from_ref_time(18_013_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(20_074_000 as u64) + // Standard Error: 765 + .saturating_add(Weight::from_ref_time(343_285 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) + /// The range of component `s` is `[1, 512]`. fn cancel(s: u32, ) -> Weight { - Weight::from_ref_time(18_131_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(21_509_000 as u64) + // Standard Error: 708 + .saturating_add(Weight::from_ref_time(323_013 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { - Weight::from_ref_time(21_230_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(98_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(22_427_000 as u64) + // Standard Error: 850 + .saturating_add(Weight::from_ref_time(357_265 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { - Weight::from_ref_time(20_139_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(22_875_000 as u64) + // Standard Error: 693 + .saturating_add(Weight::from_ref_time(336_643 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -213,149 +148,84 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(9_994_000 as u64) - // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(19_843_000 as u64).saturating_mul(s as u64)) + // Storage: Scheduler IncompleteSince (r:1 w:1) + fn service_agendas_base() -> Weight { + Weight::from_ref_time(4_992_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(s as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(10_318_000 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(15_451_000 as u64).saturating_mul(s as u64)) + /// The range of component `s` is `[0, 512]`. + fn service_agenda_base(s: u32, ) -> Weight { + Weight::from_ref_time(4_320_000 as u64) + // Standard Error: 619 + .saturating_add(Weight::from_ref_time(336_713 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(s as u64))) } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_675_000 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(17_019_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(s as u64))) + fn service_task_base() -> Weight { + Weight::from_ref_time(10_864_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) - fn on_initialize_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_934_000 as u64) - // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(14_134_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:0) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(7_279_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(5_388_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:0) - fn on_initialize_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(8_619_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_969_000 as u64).saturating_mul(s as u64)) + /// The range of component `s` is `[128, 4194304]`. + fn service_task_fetched(s: u32, ) -> Weight { + Weight::from_ref_time(24_586_000 as u64) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(1_138 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } - // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_named(s: u32, ) -> Weight { - Weight::from_ref_time(16_129_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(9_772_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + fn service_task_named() -> Weight { + Weight::from_ref_time(13_127_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) } - // Storage: Scheduler Agenda (r:2 w:2) - fn on_initialize_periodic(s: u32, ) -> Weight { - Weight::from_ref_time(15_785_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(7_208_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + fn service_task_periodic() -> Weight { + Weight::from_ref_time(11_053_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named(s: u32, ) -> Weight { - Weight::from_ref_time(15_778_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(5_597_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + fn execute_dispatch_signed() -> Weight { + Weight::from_ref_time(4_158_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) - fn on_initialize(s: u32, ) -> Weight { - Weight::from_ref_time(15_912_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(4_530_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + fn execute_dispatch_unsigned() -> Weight { + Weight::from_ref_time(4_104_000 as u64) } // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { - Weight::from_ref_time(18_013_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(20_074_000 as u64) + // Standard Error: 765 + .saturating_add(Weight::from_ref_time(343_285 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) + /// The range of component `s` is `[1, 512]`. fn cancel(s: u32, ) -> Weight { - Weight::from_ref_time(18_131_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(21_509_000 as u64) + // Standard Error: 708 + .saturating_add(Weight::from_ref_time(323_013 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { - Weight::from_ref_time(21_230_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(98_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(22_427_000 as u64) + // Standard Error: 850 + .saturating_add(Weight::from_ref_time(357_265 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { - Weight::from_ref_time(20_139_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(22_875_000 as u64) + // Standard Error: 693 + .saturating_add(Weight::from_ref_time(336_643 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index acbcb65a3e986..1551d85ea4c96 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -169,6 +169,10 @@ pub fn expand_outer_origin( &self.caller } + fn into_caller(self) -> Self::PalletsOrigin { + self.caller + } + fn try_with_caller( mut self, f: impl FnOnce(Self::PalletsOrigin) -> Result, @@ -190,13 +194,6 @@ pub fn expand_outer_origin( fn signed(by: Self::AccountId) -> Self { #system_path::RawOrigin::Signed(by).into() } - - fn as_signed(self) -> Option { - match self.caller { - OriginCaller::system(#system_path::RawOrigin::Signed(by)) => Some(by), - _ => None, - } - } } #[derive( @@ -215,7 +212,6 @@ pub fn expand_outer_origin( // For backwards compatibility and ease of accessing these functions. #[allow(dead_code)] impl RuntimeOrigin { - #[doc = #doc_string_none_origin] pub fn none() -> Self { ::none() @@ -238,6 +234,21 @@ pub fn expand_outer_origin( } } + impl #scrate::traits::CallerTrait<<#runtime as #system_path::Config>::AccountId> for OriginCaller { + fn into_system(self) -> Option<#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> { + match self { + OriginCaller::system(x) => Some(x), + _ => None, + } + } + fn as_system_ref(&self) -> Option<&#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> { + match &self { + OriginCaller::system(o) => Some(o), + _ => None, + } + } + } + impl TryFrom for #system_path::Origin<#runtime> { type Error = OriginCaller; fn try_from(x: OriginCaller) diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index db2bc90658ee2..d497a672e2970 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -3181,8 +3181,8 @@ mod tests { dispatch::{DispatchClass, DispatchInfo, Pays}, metadata::*, traits::{ - CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize, - OnRuntimeUpgrade, PalletInfo, + CallerTrait, CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, + OnInitialize, OnRuntimeUpgrade, PalletInfo, }, }; use sp_weights::RuntimeDbWeight; @@ -3300,6 +3300,16 @@ mod tests { } } + impl CallerTrait<::AccountId> for OuterOrigin { + fn into_system(self) -> Option::AccountId>> { + unimplemented!("Not required in tests!") + } + + fn as_system_ref(&self) -> Option<&RawOrigin<::AccountId>> { + unimplemented!("Not required in tests!") + } + } + impl crate::traits::OriginTrait for OuterOrigin { type Call = ::RuntimeCall; type PalletsOrigin = OuterOrigin; @@ -3325,6 +3335,10 @@ mod tests { unimplemented!("Not required in tests!") } + fn into_caller(self) -> Self::PalletsOrigin { + unimplemented!("Not required in tests!") + } + fn try_with_caller( self, _f: impl FnOnce(Self::PalletsOrigin) -> Result, @@ -3344,6 +3358,9 @@ mod tests { fn as_signed(self) -> Option { unimplemented!("Not required in tests!") } + fn as_system_ref(&self) -> Option<&RawOrigin> { + unimplemented!("Not required in tests!") + } } impl system::Config for TraitImpl { diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index d51c32649a797..302d3354dae5e 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -58,10 +58,11 @@ pub use misc::{ Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, DefensiveSaturating, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, - IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider, - PreimageRecipient, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime, - WrapperKeepOpaque, WrapperOpaque, + IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, + SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime, WrapperKeepOpaque, WrapperOpaque, }; +#[allow(deprecated)] +pub use misc::{PreimageProvider, PreimageRecipient}; #[doc(hidden)] pub use misc::{DEFENSIVE_OP_INTERNAL_ERROR, DEFENSIVE_OP_PUBLIC_ERROR}; @@ -96,8 +97,9 @@ mod dispatch; #[allow(deprecated)] pub use dispatch::EnsureOneOf; pub use dispatch::{ - AsEnsureOriginWithArg, EitherOf, EitherOfDiverse, EnsureOrigin, EnsureOriginWithArg, - MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess, UnfilteredDispatchable, + AsEnsureOriginWithArg, CallerTrait, EitherOf, EitherOfDiverse, EnsureOrigin, + EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess, + UnfilteredDispatchable, }; mod voting; @@ -106,6 +108,9 @@ pub use voting::{ U128CurrencyToVote, VoteTally, }; +mod preimages; +pub use preimages::{Bounded, BoundedInline, FetchResult, Hash, QueryPreimage, StorePreimage}; + #[cfg(feature = "try-runtime")] mod try_runtime; #[cfg(feature = "try-runtime")] diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index c0e7e32a5529e..b96cfae4500e2 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -236,17 +236,25 @@ pub trait UnfilteredDispatchable { fn dispatch_bypass_filter(self, origin: Self::RuntimeOrigin) -> DispatchResultWithPostInfo; } +/// The trait implemented by the overarching enumeration of the different pallets' origins. +/// Unlike `OriginTrait` impls, this does not include any kind of dispatch/call filter. Also, this +/// trait is more flexible in terms of how it can be used: it is a `Parameter` and `Member`, so it +/// can be used as dispatchable parameters as well as in storage items. +pub trait CallerTrait: Parameter + Member + From> { + /// Extract the signer from the message if it is a `Signed` origin. + fn into_system(self) -> Option>; + + /// Extract a reference to the system-level `RawOrigin` if it is that. + fn as_system_ref(&self) -> Option<&RawOrigin>; +} + /// Methods available on `frame_system::Config::RuntimeOrigin`. pub trait OriginTrait: Sized { /// Runtime call type, as in `frame_system::Config::Call` type Call; /// The caller origin, overarching type of all pallets origins. - type PalletsOrigin: Parameter - + Member - + Into - + From> - + MaxEncodedLen; + type PalletsOrigin: Into + CallerTrait + MaxEncodedLen; /// The AccountId used across the system. type AccountId; @@ -266,9 +274,12 @@ pub trait OriginTrait: Sized { /// For root origin caller, the filters are bypassed and true is returned. fn filter_call(&self, call: &Self::Call) -> bool; - /// Get the caller. + /// Get a reference to the caller (`CallerTrait` impl). fn caller(&self) -> &Self::PalletsOrigin; + /// Consume `self` and return the caller. + fn into_caller(self) -> Self::PalletsOrigin; + /// Do something with the caller, consuming self but returning it if the caller was unused. fn try_with_caller( self, @@ -285,7 +296,20 @@ pub trait OriginTrait: Sized { fn signed(by: Self::AccountId) -> Self; /// Extract the signer from the message if it is a `Signed` origin. - fn as_signed(self) -> Option; + fn as_signed(self) -> Option { + self.into_caller().into_system().and_then(|s| { + if let RawOrigin::Signed(who) = s { + Some(who) + } else { + None + } + }) + } + + /// Extract a reference to the sytsem origin, if that's what the caller is. + fn as_system_ref(&self) -> Option<&RawOrigin> { + self.caller().as_system_ref() + } } #[cfg(test)] diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 7fc4a6fb08a5a..5a976478fa7c4 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -932,7 +932,7 @@ pub trait PreimageRecipient: PreimageProvider { /// Maximum size of a preimage. type MaxSize: Get; - /// Store the bytes of a preimage on chain. + /// Store the bytes of a preimage on chain infallible due to the bounded type. fn note_preimage(bytes: crate::BoundedVec); /// Clear a previously noted preimage. This is infallible and should be treated more like a diff --git a/frame/support/src/traits/preimages.rs b/frame/support/src/traits/preimages.rs new file mode 100644 index 0000000000000..594532ba96903 --- /dev/null +++ b/frame/support/src/traits/preimages.rs @@ -0,0 +1,317 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Stuff for dealing with 32-byte hashed preimages. + +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use sp_core::{RuntimeDebug, H256}; +use sp_io::hashing::blake2_256; +use sp_runtime::{traits::ConstU32, DispatchError}; +use sp_std::borrow::Cow; + +pub type Hash = H256; +pub type BoundedInline = crate::BoundedVec>; + +#[derive( + Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, scale_info::TypeInfo, RuntimeDebug, +)] +#[codec(mel_bound())] +pub enum Bounded { + /// A Blake2 256 hash with no preimage length. We + /// do not support creation of this except for transitioning from legacy state. + /// In the future we will make this a pure `Dummy` item storing only the final `dummy` field. + Legacy { hash: Hash, dummy: sp_std::marker::PhantomData }, + /// A an bounded `Call`. Its encoding must be at most 128 bytes. + Inline(BoundedInline), + /// A Blake2-256 hash of the call together with an upper limit for its size. + Lookup { hash: Hash, len: u32 }, +} + +impl Bounded { + /// Casts the wrapped type into something that encodes alike. + /// + /// # Examples + /// ``` + /// use frame_support::traits::Bounded; + /// + /// // Transmute from `String` to `&str`. + /// let x: Bounded = Bounded::Inline(Default::default()); + /// let _: Bounded<&str> = x.transmute(); + /// ``` + pub fn transmute(self) -> Bounded + where + T: Encode + EncodeLike, + { + use Bounded::*; + match self { + Legacy { hash, .. } => Legacy { hash, dummy: sp_std::marker::PhantomData }, + Inline(x) => Inline(x), + Lookup { hash, len } => Lookup { hash, len }, + } + } + + /// Returns the hash of the preimage. + /// + /// The hash is re-calculated every time if the preimage is inlined. + pub fn hash(&self) -> H256 { + use Bounded::*; + match self { + Legacy { hash, .. } => *hash, + Inline(x) => blake2_256(x.as_ref()).into(), + Lookup { hash, .. } => *hash, + } + } +} + +// The maximum we expect a single legacy hash lookup to be. +const MAX_LEGACY_LEN: u32 = 1_000_000; + +impl Bounded { + /// Returns the length of the preimage or `None` if the length is unknown. + pub fn len(&self) -> Option { + match self { + Self::Legacy { .. } => None, + Self::Inline(i) => Some(i.len() as u32), + Self::Lookup { len, .. } => Some(*len), + } + } + + /// Returns whether the image will require a lookup to be peeked. + pub fn lookup_needed(&self) -> bool { + match self { + Self::Inline(..) => false, + Self::Legacy { .. } | Self::Lookup { .. } => true, + } + } + + /// The maximum length of the lookup that is needed to peek `Self`. + pub fn lookup_len(&self) -> Option { + match self { + Self::Inline(..) => None, + Self::Legacy { .. } => Some(MAX_LEGACY_LEN), + Self::Lookup { len, .. } => Some(*len), + } + } + + /// Constructs a `Lookup` bounded item. + pub fn unrequested(hash: Hash, len: u32) -> Self { + Self::Lookup { hash, len } + } + + /// Constructs a `Legacy` bounded item. + #[deprecated = "This API is only for transitioning to Scheduler v3 API"] + pub fn from_legacy_hash(hash: impl Into) -> Self { + Self::Legacy { hash: hash.into(), dummy: sp_std::marker::PhantomData } + } +} + +pub type FetchResult = Result, DispatchError>; + +/// A interface for looking up preimages from their hash on chain. +pub trait QueryPreimage { + /// Returns whether a preimage exists for a given hash and if so its length. + fn len(hash: &Hash) -> Option; + + /// Returns the preimage for a given hash. If given, `len` must be the size of the preimage. + fn fetch(hash: &Hash, len: Option) -> FetchResult; + + /// Returns whether a preimage request exists for a given hash. + fn is_requested(hash: &Hash) -> bool; + + /// Request that someone report a preimage. Providers use this to optimise the economics for + /// preimage reporting. + fn request(hash: &Hash); + + /// Cancel a previous preimage request. + fn unrequest(hash: &Hash); + + /// Request that the data required for decoding the given `bounded` value is made available. + fn hold(bounded: &Bounded) { + use Bounded::*; + match bounded { + Inline(..) => {}, + Legacy { hash, .. } | Lookup { hash, .. } => Self::request(hash), + } + } + + /// No longer request that the data required for decoding the given `bounded` value is made + /// available. + fn drop(bounded: &Bounded) { + use Bounded::*; + match bounded { + Inline(..) => {}, + Legacy { hash, .. } | Lookup { hash, .. } => Self::unrequest(hash), + } + } + + /// Check to see if all data required for the given `bounded` value is available for its + /// decoding. + fn have(bounded: &Bounded) -> bool { + use Bounded::*; + match bounded { + Inline(..) => true, + Legacy { hash, .. } | Lookup { hash, .. } => Self::len(hash).is_some(), + } + } + + /// Create a `Bounded` instance based on the `hash` and `len` of the encoded value. This may not + /// be `peek`-able or `realize`-able. + fn pick(hash: Hash, len: u32) -> Bounded { + Self::request(&hash); + Bounded::Lookup { hash, len } + } + + /// Convert the given `bounded` instance back into its original instance, also returning the + /// exact size of its encoded form if it needed to be looked-up from a stored preimage). + /// + /// NOTE: This does not remove any data needed for realization. If you will no longer use the + /// `bounded`, call `realize` instead or call `drop` afterwards. + fn peek(bounded: &Bounded) -> Result<(T, Option), DispatchError> { + use Bounded::*; + match bounded { + Inline(data) => T::decode(&mut &data[..]).ok().map(|x| (x, None)), + Lookup { hash, len } => { + let data = Self::fetch(hash, Some(*len))?; + T::decode(&mut &data[..]).ok().map(|x| (x, Some(data.len() as u32))) + }, + Legacy { hash, .. } => { + let data = Self::fetch(hash, None)?; + T::decode(&mut &data[..]).ok().map(|x| (x, Some(data.len() as u32))) + }, + } + .ok_or(DispatchError::Corruption) + } + + /// Convert the given `bounded` value back into its original instance. If successful, + /// `drop` any data backing it. This will not break the realisability of independently + /// created instances of `Bounded` which happen to have identical data. + fn realize(bounded: &Bounded) -> Result<(T, Option), DispatchError> { + let r = Self::peek(bounded)?; + Self::drop(bounded); + Ok(r) + } +} + +/// A interface for managing preimages to hashes on chain. +/// +/// Note that this API does not assume any underlying user is calling, and thus +/// does not handle any preimage ownership or fees. Other system level logic that +/// uses this API should implement that on their own side. +pub trait StorePreimage: QueryPreimage { + /// The maximum length of preimage we can store. + /// + /// This is the maximum length of the *encoded* value that can be passed to `bound`. + const MAX_LENGTH: usize; + + /// Request and attempt to store the bytes of a preimage on chain. + /// + /// May return `DispatchError::Exhausted` if the preimage is just too big. + fn note(bytes: Cow<[u8]>) -> Result; + + /// Attempt to clear a previously noted preimage. Exactly the same as `unrequest` but is + /// provided for symmetry. + fn unnote(hash: &Hash) { + Self::unrequest(hash) + } + + /// Convert an otherwise unbounded or large value into a type ready for placing in storage. The + /// result is a type whose `MaxEncodedLen` is 131 bytes. + /// + /// NOTE: Once this API is used, you should use either `drop` or `realize`. + fn bound(t: T) -> Result, DispatchError> { + let data = t.encode(); + let len = data.len() as u32; + Ok(match BoundedInline::try_from(data) { + Ok(bounded) => Bounded::Inline(bounded), + Err(unbounded) => Bounded::Lookup { hash: Self::note(unbounded.into())?, len }, + }) + } +} + +impl QueryPreimage for () { + fn len(_: &Hash) -> Option { + None + } + fn fetch(_: &Hash, _: Option) -> FetchResult { + Err(DispatchError::Unavailable) + } + fn is_requested(_: &Hash) -> bool { + false + } + fn request(_: &Hash) {} + fn unrequest(_: &Hash) {} +} + +impl StorePreimage for () { + const MAX_LENGTH: usize = 0; + fn note(_: Cow<[u8]>) -> Result { + Err(DispatchError::Exhausted) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{bounded_vec, BoundedVec}; + + #[test] + fn bounded_size_is_correct() { + assert_eq!(> as MaxEncodedLen>::max_encoded_len(), 131); + } + + #[test] + fn bounded_basic_works() { + let data: BoundedVec = bounded_vec![b'a', b'b', b'c']; + let len = data.len() as u32; + let hash = blake2_256(&data).into(); + + // Inline works + { + let bound: Bounded> = Bounded::Inline(data.clone()); + assert_eq!(bound.hash(), hash); + assert_eq!(bound.len(), Some(len)); + assert!(!bound.lookup_needed()); + assert_eq!(bound.lookup_len(), None); + } + // Legacy works + { + let bound: Bounded> = Bounded::Legacy { hash, dummy: Default::default() }; + assert_eq!(bound.hash(), hash); + assert_eq!(bound.len(), None); + assert!(bound.lookup_needed()); + assert_eq!(bound.lookup_len(), Some(1_000_000)); + } + // Lookup works + { + let bound: Bounded> = Bounded::Lookup { hash, len: data.len() as u32 }; + assert_eq!(bound.hash(), hash); + assert_eq!(bound.len(), Some(len)); + assert!(bound.lookup_needed()); + assert_eq!(bound.lookup_len(), Some(len)); + } + } + + #[test] + fn bounded_transmuting_works() { + let data: BoundedVec = bounded_vec![b'a', b'b', b'c']; + + // Transmute a `String` into a `&str`. + let x: Bounded = Bounded::Inline(data.clone()); + let y: Bounded<&str> = x.transmute(); + assert_eq!(y, Bounded::Inline(data)); + } +} diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 0dbbbd9e2a553..b8e6a7f807904 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -17,6 +17,8 @@ //! Traits and associated utilities for scheduling dispatchables in FRAME. +#[allow(deprecated)] +use super::PreimageProvider; use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{traits::Saturating, DispatchError, RuntimeDebug}; @@ -128,6 +130,7 @@ impl MaybeHashed { } } +// TODO: deprecate pub mod v1 { use super::*; @@ -283,6 +286,7 @@ pub mod v1 { } } +// TODO: deprecate pub mod v2 { use super::*; @@ -375,6 +379,97 @@ pub mod v2 { } } -pub use v1::*; +pub mod v3 { + use super::*; + use crate::traits::Bounded; -use super::PreimageProvider; + /// A type that can be used as a scheduler. + pub trait Anon { + /// An address which can be used for removing a scheduled task. + type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + Debug + TypeInfo; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// This is not named. + fn schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Bounded, + ) -> Result; + + /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that, + /// also. + /// + /// Will return an `Unavailable` error if the `address` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + /// + /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For + /// that, you must name the task explicitly using the `Named` trait. + fn cancel(address: Self::Address) -> Result<(), DispatchError>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. For periodic tasks, + /// this dispatch is guaranteed to succeed only before the *initial* execution; for + /// others, use `reschedule_named`. + /// + /// Will return an `Unavailable` error if the `address` is invalid. + fn reschedule( + address: Self::Address, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an `Unavailable` error if the `address` is invalid. + fn next_dispatch_time(address: Self::Address) -> Result; + } + + pub type TaskName = [u8; 32]; + + /// A type that can be used as a scheduler. + pub trait Named { + /// An address which can be used for removing a scheduled task. + type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + sp_std::fmt::Debug; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// - `id`: The identity of the task. This must be unique and will return an error if not. + fn schedule_named( + id: TaskName, + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Bounded, + ) -> Result; + + /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances + /// of that, also. + /// + /// Will return an `Unavailable` error if the `id` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + fn cancel_named(id: TaskName) -> Result<(), DispatchError>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. + /// + /// Will return an `Unavailable` error if the `id` is invalid. + fn reschedule_named( + id: TaskName, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an `Unavailable` error if the `id` is invalid. + fn next_dispatch_time(id: TaskName) -> Result; + } +} + +pub use v1::*; diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index b0716d569409c..b8a9a1128d669 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 280 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) - and 160 others + and 161 others = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 280 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 926dc92530659..5032f63bc1b1b 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 280 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) - and 160 others + and 161 others = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 280 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index 563190a06f76f..8d3d7a71a313e 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -13,5 +13,5 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 77 others + and 78 others = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index c10005223b674..ebf24a1232e3c 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -13,6 +13,6 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 77 others + and 78 others = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index dc74157da79de..7577d0dc6b158 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -222,7 +222,10 @@ pub mod pallet { + OriginTrait; /// The aggregated `RuntimeCall` type. - type RuntimeCall: Dispatchable + Debug; + type RuntimeCall: Parameter + + Dispatchable + + Debug + + From>; /// Account index (aka nonce) type. This stores the number of previous transactions /// associated with a sender account. diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs index 44aea86be6f19..d4446cb8031ab 100644 --- a/frame/whitelist/src/mock.rs +++ b/frame/whitelist/src/mock.rs @@ -96,7 +96,6 @@ impl pallet_preimage::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type MaxSize = ConstU32<{ 4096 * 1024 }>; // PreimageMaxSize Taken from Polkadot as reference. type BaseDeposit = ConstU64<1>; type ByteDeposit = ConstU64<1>; type WeightInfo = (); diff --git a/primitives/core/src/bounded/bounded_vec.rs b/primitives/core/src/bounded/bounded_vec.rs index 85f2bed316793..1832e43e8646c 100644 --- a/primitives/core/src/bounded/bounded_vec.rs +++ b/primitives/core/src/bounded/bounded_vec.rs @@ -276,6 +276,14 @@ impl<'a, T, S> sp_std::iter::IntoIterator for BoundedSlice<'a, T, S> { } } +impl<'a, T, S: Get> BoundedSlice<'a, T, S> { + /// Create an instance from the first elements of the given slice (or all of it if it is smaller + /// than the length bound). + pub fn truncate_from(s: &'a [T]) -> Self { + Self(&s[0..(s.len().min(S::get() as usize))], PhantomData) + } +} + impl> Decode for BoundedVec { fn decode(input: &mut I) -> Result { let inner = Vec::::decode(input)?; @@ -620,12 +628,12 @@ impl> BoundedVec { /// # Panics /// /// Panics if `index > len`. - pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), ()> { + pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), T> { if self.len() < Self::bound() { self.0.insert(index, element); Ok(()) } else { - Err(()) + Err(element) } } @@ -635,12 +643,12 @@ impl> BoundedVec { /// # Panics /// /// Panics if the new capacity exceeds isize::MAX bytes. - pub fn try_push(&mut self, element: T) -> Result<(), ()> { + pub fn try_push(&mut self, element: T) -> Result<(), T> { if self.len() < Self::bound() { self.0.push(element); Ok(()) } else { - Err(()) + Err(element) } } } @@ -673,13 +681,13 @@ where } impl> TryFrom> for BoundedVec { - type Error = (); + type Error = Vec; fn try_from(t: Vec) -> Result { if t.len() <= Self::bound() { // explicit check just above Ok(Self::unchecked_from(t)) } else { - Err(()) + Err(t) } } } @@ -886,6 +894,16 @@ pub mod test { use super::*; use crate::{bounded_vec, ConstU32}; + #[test] + fn slice_truncate_from_works() { + let bounded = BoundedSlice::>::truncate_from(&[1, 2, 3, 4, 5]); + assert_eq!(bounded.deref(), &[1, 2, 3, 4]); + let bounded = BoundedSlice::>::truncate_from(&[1, 2, 3, 4]); + assert_eq!(bounded.deref(), &[1, 2, 3, 4]); + let bounded = BoundedSlice::>::truncate_from(&[1, 2, 3]); + assert_eq!(bounded.deref(), &[1, 2, 3]); + } + #[test] fn slide_works() { let mut b: BoundedVec> = bounded_vec![0, 1, 2, 3, 4, 5]; diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 8017a6ac529a2..96706dd919650 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -547,6 +547,12 @@ pub enum DispatchError { /// The number of transactional layers has been reached, or we are not in a transactional /// layer. Transactional(TransactionalError), + /// Resources exhausted, e.g. attempt to read/write data which is too large to manipulate. + Exhausted, + /// The state is corrupt; this is generally not going to fix itself. + Corruption, + /// Some resource (e.g. a preimage) is unavailable right now. This might fix itself later. + Unavailable, } /// Result of a `Dispatchable` which contains the `DispatchResult` and additional information about @@ -671,18 +677,21 @@ impl From<&'static str> for DispatchError { impl From for &'static str { fn from(err: DispatchError) -> &'static str { + use DispatchError::*; match err { - DispatchError::Other(msg) => msg, - DispatchError::CannotLookup => "Cannot lookup", - DispatchError::BadOrigin => "Bad origin", - DispatchError::Module(ModuleError { message, .. }) => - message.unwrap_or("Unknown module error"), - DispatchError::ConsumerRemaining => "Consumer remaining", - DispatchError::NoProviders => "No providers", - DispatchError::TooManyConsumers => "Too many consumers", - DispatchError::Token(e) => e.into(), - DispatchError::Arithmetic(e) => e.into(), - DispatchError::Transactional(e) => e.into(), + Other(msg) => msg, + CannotLookup => "Cannot lookup", + BadOrigin => "Bad origin", + Module(ModuleError { message, .. }) => message.unwrap_or("Unknown module error"), + ConsumerRemaining => "Consumer remaining", + NoProviders => "No providers", + TooManyConsumers => "Too many consumers", + Token(e) => e.into(), + Arithmetic(e) => e.into(), + Transactional(e) => e.into(), + Exhausted => "Resources exhausted", + Corruption => "State corrupt", + Unavailable => "Resource unavailable", } } } @@ -698,33 +707,37 @@ where impl traits::Printable for DispatchError { fn print(&self) { + use DispatchError::*; "DispatchError".print(); match self { - Self::Other(err) => err.print(), - Self::CannotLookup => "Cannot lookup".print(), - Self::BadOrigin => "Bad origin".print(), - Self::Module(ModuleError { index, error, message }) => { + Other(err) => err.print(), + CannotLookup => "Cannot lookup".print(), + BadOrigin => "Bad origin".print(), + Module(ModuleError { index, error, message }) => { index.print(); error.print(); if let Some(msg) = message { msg.print(); } }, - Self::ConsumerRemaining => "Consumer remaining".print(), - Self::NoProviders => "No providers".print(), - Self::TooManyConsumers => "Too many consumers".print(), - Self::Token(e) => { + ConsumerRemaining => "Consumer remaining".print(), + NoProviders => "No providers".print(), + TooManyConsumers => "Too many consumers".print(), + Token(e) => { "Token error: ".print(); <&'static str>::from(*e).print(); }, - Self::Arithmetic(e) => { + Arithmetic(e) => { "Arithmetic error: ".print(); <&'static str>::from(*e).print(); }, - Self::Transactional(e) => { + Transactional(e) => { "Transactional error: ".print(); <&'static str>::from(*e).print(); }, + Exhausted => "Resources exhausted".print(), + Corruption => "State corrupt".print(), + Unavailable => "Resource unavailable".print(), } } } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index a64e3f25ef041..3db0e5510057b 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -37,8 +37,9 @@ use trie_db::{Trie, TrieMut}; use cfg_if::cfg_if; use frame_support::{ + dispatch::RawOrigin, parameter_types, - traits::{ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem}, + traits::{CallerTrait, ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem}, weights::{RuntimeDbWeight, Weight}, }; use frame_system::limits::{BlockLength, BlockWeights}; @@ -119,7 +120,7 @@ pub fn native_version() -> NativeVersion { } /// Calls in transactions. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct Transfer { pub from: AccountId, pub to: AccountId, @@ -150,7 +151,7 @@ impl Transfer { } /// Extrinsic for test-runtime. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum Extrinsic { AuthoritiesChange(Vec), Transfer { @@ -446,11 +447,22 @@ impl GetRuntimeBlockType for Runtime { #[derive(Clone, RuntimeDebug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct RuntimeOrigin; -impl From> for RuntimeOrigin { - fn from(_o: frame_system::Origin) -> Self { +impl From::AccountId>> for RuntimeOrigin { + fn from(_: RawOrigin<::AccountId>) -> Self { unimplemented!("Not required in tests!") } } + +impl CallerTrait<::AccountId> for RuntimeOrigin { + fn into_system(self) -> Option::AccountId>> { + unimplemented!("Not required in tests!") + } + + fn as_system_ref(&self) -> Option<&RawOrigin<::AccountId>> { + unimplemented!("Not required in tests!") + } +} + impl From for Result, RuntimeOrigin> { fn from(_origin: RuntimeOrigin) -> Result, RuntimeOrigin> { unimplemented!("Not required in tests!") @@ -482,6 +494,10 @@ impl frame_support::traits::OriginTrait for RuntimeOrigin { unimplemented!("Not required in tests!") } + fn into_caller(self) -> Self::PalletsOrigin { + unimplemented!("Not required in tests!") + } + fn try_with_caller( self, _f: impl FnOnce(Self::PalletsOrigin) -> Result, @@ -501,6 +517,9 @@ impl frame_support::traits::OriginTrait for RuntimeOrigin { fn as_signed(self) -> Option { unimplemented!("Not required in tests!") } + fn as_system_ref(&self) -> Option<&RawOrigin> { + unimplemented!("Not required in tests!") + } } #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] @@ -583,6 +602,12 @@ parameter_types! { BlockWeights::with_sensible_defaults(Weight::from_ref_time(4 * 1024 * 1024), Perbill::from_percent(75)); } +impl From> for Extrinsic { + fn from(_: frame_system::Call) -> Self { + unimplemented!("Not required in tests!") + } +} + impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; From fc67cbb66d8c484bc7b7506fc1300344d12ecbad Mon Sep 17 00:00:00 2001 From: Andronik Date: Wed, 5 Oct 2022 23:07:15 +0200 Subject: [PATCH 1242/1472] update kvdb & co (#12312) * upgrade kvdb & co * remove patch * update Cargo.lock * upgrade impl-serde * fix parsing test * actually fix it * FFS --- Cargo.lock | 89 +++++++++---------------- bin/node/bench/Cargo.toml | 6 +- bin/node/bench/src/tempdb.rs | 13 ++-- bin/node/inspect/src/lib.rs | 4 +- client/db/Cargo.toml | 8 +-- client/db/src/upgrade.rs | 9 ++- client/informant/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/state-db/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/arithmetic/fuzzer/Cargo.toml | 2 +- primitives/core/Cargo.toml | 6 +- primitives/core/src/uint.rs | 3 - primitives/database/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/storage/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 4 +- primitives/version/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 4 +- utils/frame/benchmarking-cli/Cargo.toml | 4 +- 24 files changed, 73 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53f370a930626..52b74628f07d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -551,19 +551,18 @@ checksum = "50ae17cabbc8a38a1e3e4c1a6a664e9a09672dc14d0896fa8d865d3a5a446b07" [[package]] name = "bincode" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "byteorder", "serde", ] [[package]] name = "bindgen" -version = "0.59.2" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" dependencies = [ "bitflags", "cexpr", @@ -778,9 +777,9 @@ dependencies = [ [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" @@ -981,7 +980,7 @@ checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c" dependencies = [ "glob", "libc", - "libloading 0.7.0", + "libloading", ] [[package]] @@ -2063,9 +2062,9 @@ dependencies = [ [[package]] name = "fixed-hash" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", "rand 0.8.5", @@ -2442,18 +2441,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "fs-swap" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d47dad3685eceed8488986cad3d5027165ea5edb164331770e2059555f10a5" -dependencies = [ - "lazy_static", - "libc", - "libloading 0.5.2", - "winapi", -] - [[package]] name = "fs2" version = "0.4.3" @@ -3055,9 +3042,9 @@ dependencies = [ [[package]] name = "impl-serde" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" dependencies = [ "serde", ] @@ -3449,9 +3436,9 @@ dependencies = [ [[package]] name = "kvdb" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a301d8ecb7989d4a6e2c57a49baca77d353bdbf879909debe3f375fe25d61f86" +checksum = "585089ceadba0197ffe9af6740ab350b325e3c1f5fccfbc3522e0250c750409b" dependencies = [ "parity-util-mem", "smallvec", @@ -3459,9 +3446,9 @@ dependencies = [ [[package]] name = "kvdb-memorydb" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece7e668abd21387aeb6628130a6f4c802787f014fa46bc83221448322250357" +checksum = "40d109c87bfb7759edd2a49b2649c1afe25af785d930ad6a38479b4dc70dd873" dependencies = [ "kvdb", "parity-util-mem", @@ -3470,15 +3457,13 @@ dependencies = [ [[package]] name = "kvdb-rocksdb" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca7fbdfd71cd663dceb0faf3367a99f8cf724514933e9867cec4995b6027cbc1" +checksum = "c076cc2cdbac89b9910c853a36c957d3862a779f31c2661174222cefb49ee597" dependencies = [ - "fs-swap", "kvdb", "log", "num_cpus", - "owning_ref", "parity-util-mem", "parking_lot 0.12.1", "regex", @@ -3522,16 +3507,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "libloading" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" -dependencies = [ - "cc", - "winapi", -] - [[package]] name = "libloading" version = "0.7.0" @@ -4065,9 +4040,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.6.1+6.28.2" +version = "0.8.0+7.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc587013734dadb7cf23468e531aa120788b87243648be42e2d3a072186291" +checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" dependencies = [ "bindgen", "bzip2-sys", @@ -4364,9 +4339,9 @@ dependencies = [ [[package]] name = "memory-db" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6566c70c1016f525ced45d7b7f97730a2bafb037c788211d0c186ef5b2189f0a" +checksum = "34ac11bb793c28fa095b7554466f53b3a60a2cd002afdac01bcf135cbd73a269" dependencies = [ "hash-db", "hashbrown 0.12.3", @@ -6637,9 +6612,9 @@ checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" [[package]] name = "parity-util-mem" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c32561d248d352148124f036cac253a644685a21dc9fea383eb4907d7bd35a8f" +checksum = "0d32c34f4f5ca7f9196001c0aba5a1f9a5a12382c8944b8b0f90233282d1e8f8" dependencies = [ "cfg-if 1.0.0", "hashbrown 0.12.3", @@ -7011,9 +6986,9 @@ dependencies = [ [[package]] name = "primitive-types" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +checksum = "5cfd65aea0c5fa0bfcc7c9e7ca828c921ef778f43d325325ec84bda371bfa75a" dependencies = [ "fixed-hash", "impl-codec", @@ -7637,9 +7612,9 @@ dependencies = [ [[package]] name = "rocksdb" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620f4129485ff1a7128d184bc687470c21c7951b64779ebc9cfdad3dcd920290" +checksum = "7e9562ea1d70c0cc63a34a22d977753b50cca91cc6b6527750463bd5dd8697bc" dependencies = [ "libc", "librocksdb-sys", @@ -10938,9 +10913,9 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.4.2+5.2.1-patched.2" +version = "0.5.1+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5844e429d797c62945a566f8da4e24c7fe3fbd5d6617fd8bf7a0b7dc1ee0f22e" +checksum = "931e876f91fed0827f863a2d153897790da0b24d882c721a79cb3beb0b903261" dependencies = [ "cc", "fs_extra", @@ -11203,9 +11178,9 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" [[package]] name = "trie-bench" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5704f0d6130bd83608e4370c19e20c8a6ec03e80363e493d0234efca005265a" +checksum = "f0dae77b1daad50cd3ed94c506d2dab27e2e47f7b5153a6d4b1992bb3f6028cb" dependencies = [ "criterion", "hash-db", @@ -11792,7 +11767,7 @@ dependencies = [ "enum-iterator", "enumset", "leb128", - "libloading 0.7.0", + "libloading", "loupe", "object 0.28.3", "rkyv", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index a9c367ae8aa3d..42953da837100 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -23,8 +23,8 @@ sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machi serde = "1.0.136" serde_json = "1.0.85" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } -kvdb = "0.11.0" -kvdb-rocksdb = "0.15.1" +kvdb = "0.12.0" +kvdb-rocksdb = "0.16.0" sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } @@ -37,7 +37,7 @@ tempfile = "3.1.0" fs_extra = "1" rand = { version = "0.7.2", features = ["small_rng"] } lazy_static = "1.4.0" -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } parity-db = { version = "0.3" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } diff --git a/bin/node/bench/src/tempdb.rs b/bin/node/bench/src/tempdb.rs index 22c5980fd6524..eb3bb1d3fccd7 100644 --- a/bin/node/bench/src/tempdb.rs +++ b/bin/node/bench/src/tempdb.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use kvdb::{DBTransaction, KeyValueDB}; +use kvdb::{DBKeyValue, DBTransaction, KeyValueDB}; use kvdb_rocksdb::{Database, DatabaseConfig}; use std::{io, path::PathBuf, sync::Arc}; @@ -38,7 +38,7 @@ impl KeyValueDB for ParityDbWrapper { } /// Get a value by partial key. Only works for flushed data. - fn get_by_prefix(&self, _col: u32, _prefix: &[u8]) -> Option> { + fn get_by_prefix(&self, _col: u32, _prefix: &[u8]) -> io::Result>> { unimplemented!() } @@ -56,7 +56,7 @@ impl KeyValueDB for ParityDbWrapper { } /// Iterate over flushed data for a given column. - fn iter<'a>(&'a self, _col: u32) -> Box, Box<[u8]>)> + 'a> { + fn iter<'a>(&'a self, _col: u32) -> Box> + 'a> { unimplemented!() } @@ -65,12 +65,7 @@ impl KeyValueDB for ParityDbWrapper { &'a self, _col: u32, _prefix: &'a [u8], - ) -> Box, Box<[u8]>)> + 'a> { - unimplemented!() - } - - /// Attempt to replace this database with a new one located at the given path. - fn restore(&self, _new_db: &str) -> io::Result<()> { + ) -> Box> + 'a> { unimplemented!() } } diff --git a/bin/node/inspect/src/lib.rs b/bin/node/inspect/src/lib.rs index b37c5aa7ca2e8..aacae0ff7a0d9 100644 --- a/bin/node/inspect/src/lib.rs +++ b/bin/node/inspect/src/lib.rs @@ -296,7 +296,7 @@ mod tests { let b2 = ExtrinsicAddress::from_str("0 0"); let b3 = ExtrinsicAddress::from_str("0x0012345f"); - assert_eq!(e0, Err("Extrinsic index missing: example \"5:0\"".into())); + assert_eq!(e0, Ok(ExtrinsicAddress::Bytes(vec![0x12, 0x34]))); assert_eq!( b0, Ok(ExtrinsicAddress::Block( @@ -305,7 +305,7 @@ mod tests { )) ); assert_eq!(b1, Ok(ExtrinsicAddress::Block(BlockAddress::Number(1234), 0))); - assert_eq!(b2, Ok(ExtrinsicAddress::Block(BlockAddress::Number(0), 0))); + assert_eq!(b2, Ok(ExtrinsicAddress::Bytes(vec![0, 0]))); assert_eq!(b3, Ok(ExtrinsicAddress::Bytes(vec![0, 0x12, 0x34, 0x5f]))); } } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 7f564ae642433..b21038b77564f 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } hash-db = "0.15.2" -kvdb = "0.11.0" -kvdb-memorydb = "0.11.0" -kvdb-rocksdb = { version = "0.15.2", optional = true } +kvdb = "0.12.0" +kvdb-memorydb = "0.12.0" +kvdb-rocksdb = { version = "0.16.0", optional = true } linked-hash-map = "0.5.4" log = "0.4.17" parity-db = "0.3.16" @@ -36,7 +36,7 @@ sp-trie = { version = "6.0.0", path = "../../primitives/trie" } [dev-dependencies] criterion = "0.3.3" -kvdb-rocksdb = "0.15.1" +kvdb-rocksdb = "0.16.0" rand = "0.8.4" tempfile = "3.1.0" quickcheck = { version = "1.0.3", default-features = false } diff --git a/client/db/src/upgrade.rs b/client/db/src/upgrade.rs index 292905663a20b..51750bf689759 100644 --- a/client/db/src/upgrade.rs +++ b/client/db/src/upgrade.rs @@ -115,7 +115,7 @@ pub fn upgrade_db(db_path: &Path, db_type: DatabaseType) -> Upgra /// 2) transactions column is added; fn migrate_1_to_2(db_path: &Path, _db_type: DatabaseType) -> UpgradeResult<()> { let db_cfg = DatabaseConfig::with_columns(V1_NUM_COLUMNS); - let db = Database::open(&db_cfg, db_path)?; + let mut db = Database::open(&db_cfg, db_path)?; db.add_column().map_err(Into::into) } @@ -126,7 +126,10 @@ fn migrate_2_to_3(db_path: &Path, _db_type: DatabaseType) -> Upgr let db = Database::open(&db_cfg, db_path)?; // Get all the keys we need to update - let keys: Vec<_> = db.iter(columns::JUSTIFICATIONS).map(|entry| entry.0).collect(); + let keys: Vec<_> = db + .iter(columns::JUSTIFICATIONS) + .map(|r| r.map(|e| e.0)) + .collect::>()?; // Read and update each entry let mut transaction = db.transaction(); @@ -152,7 +155,7 @@ fn migrate_2_to_3(db_path: &Path, _db_type: DatabaseType) -> Upgr /// 2) BODY_INDEX column is added; fn migrate_3_to_4(db_path: &Path, _db_type: DatabaseType) -> UpgradeResult<()> { let db_cfg = DatabaseConfig::with_columns(V3_NUM_COLUMNS); - let db = Database::open(&db_cfg, db_path)?; + let mut db = Database::open(&db_cfg, db_path)?; db.add_column().map_err(Into::into) } diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index b3ac5d892fd58..073199d005fd1 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -17,7 +17,7 @@ ansi_term = "0.12.1" futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.17" -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index e46c65cf018f5..42bd2ae7276e2 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -80,7 +80,7 @@ sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sc-sysinfo = { version = "6.0.0-dev", path = "../sysinfo" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } -parity-util-mem = { version = "0.11.0", default-features = false, features = [ +parity-util-mem = { version = "0.12.0", default-features = false, features = [ "primitive-types", ] } async-trait = "0.1.57" diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 4243968ec79b4..7f9a502aef8e9 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } log = "0.4.17" -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } parity-util-mem-derive = "0.1.0" parking_lot = "0.12.1" sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index cd7cb297e8c4a..5e005f5523ae8 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -18,7 +18,7 @@ futures = "0.3.21" futures-timer = "3.0.2" linked-hash-map = "0.5.4" log = "0.4.17" -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } parking_lot = "0.12.1" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 98db3aa6aa49d..be9cb1f1bf316 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -44,7 +44,7 @@ serde_json = "1.0.85" assert_matches = "1.3.0" pretty_assertions = "1.2.1" frame-system = { version = "4.0.0-dev", path = "../system" } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } [features] default = ["std"] diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index d7046b3254699..60eac2247e830 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -28,7 +28,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] criterion = "0.3" -primitive-types = "0.11.1" +primitive-types = "0.12.0" sp-core = { version = "6.0.0", features = ["full_crypto"], path = "../core" } rand = "0.7.2" diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index 990106f990323..b1ffa746b6b63 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] honggfuzz = "0.5.49" num-bigint = "0.2" -primitive-types = "0.11.1" +primitive-types = "0.12.0" sp-arithmetic = { version = "5.0.0", path = ".." } [[bin]] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 65d989a74c030..b7bc6dfdce496 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -21,8 +21,8 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } -primitive-types = { version = "0.11.1", default-features = false, features = ["codec", "scale-info"] } -impl-serde = { version = "0.3.0", optional = true } +primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info"] } +impl-serde = { version = "0.4.0", optional = true } wasmi = { version = "0.13", optional = true } hash-db = { version = "0.15.2", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } @@ -40,7 +40,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } futures = { version = "0.3.21", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/core/src/uint.rs b/primitives/core/src/uint.rs index f4eb3a19ac36c..4bf914bde2ee1 100644 --- a/primitives/core/src/uint.rs +++ b/primitives/core/src/uint.rs @@ -35,7 +35,6 @@ mod tests { ($name::from(2), "0x2"), ($name::from(10), "0xa"), ($name::from(15), "0xf"), - ($name::from(15), "0xf"), ($name::from(16), "0x10"), ($name::from(1_000), "0x3e8"), ($name::from(100_000), "0x186a0"), @@ -52,8 +51,6 @@ mod tests { assert!(ser::from_str::<$name>("\"0x\"").unwrap_err().is_data()); assert!(ser::from_str::<$name>("\"0xg\"").unwrap_err().is_data()); assert!(ser::from_str::<$name>("\"\"").unwrap_err().is_data()); - assert!(ser::from_str::<$name>("\"10\"").unwrap_err().is_data()); - assert!(ser::from_str::<$name>("\"0\"").unwrap_err().is_data()); } }; } diff --git a/primitives/database/Cargo.toml b/primitives/database/Cargo.toml index a3f09536f4f5c..f19a647fed032 100644 --- a/primitives/database/Cargo.toml +++ b/primitives/database/Cargo.toml @@ -11,5 +11,5 @@ documentation = "https://docs.rs/sp-database" readme = "README.md" [dependencies] -kvdb = "0.11.0" +kvdb = "0.12.0" parking_lot = "0.12.1" diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 51367d40d0cd0..e7f0cee3f140f 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -22,7 +22,7 @@ sp-runtime-interface-proc-macro = { version = "5.0.0", path = "proc-macro" } sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["bytes"] } static_assertions = "1.0.0" -primitive-types = { version = "0.11.1", default-features = false } +primitive-types = { version = "0.12.0", default-features = false } sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } impl-trait-for-tuples = "0.2.2" diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 1d1a7a2c38b1d..01594ed69e312 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -19,7 +19,7 @@ either = { version = "1.5", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } paste = "1.0" rand = { version = "0.7.2", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index b37a4eb4b331d..d04a88d129d34 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -impl-serde = { version = "0.3.1", optional = true } +impl-serde = { version = "0.4.0", optional = true } ref-cast = "1.0.0" serde = { version = "1.0.136", features = ["derive"], optional = true } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 2a20addf66b2b..28fa6e6213daf 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 6d2d57b590e6a..2636648f40387 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -24,7 +24,7 @@ hashbrown = { version = "0.12.3", optional = true } hash-db = { version = "0.15.2", default-features = false } lazy_static = { version = "1.4.0", optional = true } lru = { version = "0.7.5", optional = true } -memory-db = { version = "0.29.0", default-features = false } +memory-db = { version = "0.30.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } @@ -38,7 +38,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] array-bytes = "4.1" criterion = "0.3.3" -trie-bench = "0.31.0" +trie-bench = "0.32.0" trie-standardmap = "0.15.2" sp-runtime = { version = "6.0.0", path = "../runtime" } diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 1750ebb8cd90b..0dcbbd81fd93f 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -impl-serde = { version = "0.3.1", optional = true } +impl-serde = { version = "0.4.0", optional = true } parity-wasm = { version = "0.45", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 744cc527e6012..698351cd69f64 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } -memory-db = { version = "0.29.0", default-features = false } +memory-db = { version = "0.30.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -42,7 +42,7 @@ sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = sp-trie = { version = "6.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } trie-db = { version = "0.24.0", default-features = false } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } sp-state-machine = { version = "0.12.0", default-features = false, path = "../../primitives/state-machine" } sp-externalities = { version = "0.12.0", default-features = false, path = "../../primitives/externalities" } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 108d0d338c2b3..8eedcb870a3d0 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -22,11 +22,11 @@ handlebars = "4.2.2" hash-db = "0.15.2" Inflector = "0.11.4" itertools = "0.10.3" -kvdb = "0.11.0" +kvdb = "0.12.0" lazy_static = "1.4.0" linked-hash-map = "0.5.4" log = "0.4.17" -memory-db = "0.29.0" +memory-db = "0.30.0" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.136" From f447beec6eefbf452520b90cb0d199eaaf114342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 6 Oct 2022 10:11:53 +0200 Subject: [PATCH 1243/1472] Use `Option` for contract dry-runs (#12429) --- Cargo.lock | 14 +---- Cargo.toml | 1 - bin/node/runtime/Cargo.toml | 2 - bin/node/runtime/src/lib.rs | 15 +++-- frame/contracts/Cargo.toml | 1 + frame/contracts/runtime-api/Cargo.toml | 34 ----------- frame/contracts/runtime-api/README.md | 7 --- frame/contracts/runtime-api/src/lib.rs | 85 -------------------------- frame/contracts/src/lib.rs | 57 ++++++++++++++++- 9 files changed, 65 insertions(+), 151 deletions(-) delete mode 100644 frame/contracts/runtime-api/Cargo.toml delete mode 100644 frame/contracts/runtime-api/README.md delete mode 100644 frame/contracts/runtime-api/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 52b74628f07d3..9136df1cd9299 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3358,7 +3358,6 @@ dependencies = [ "pallet-collective", "pallet-contracts", "pallet-contracts-primitives", - "pallet-contracts-runtime-api", "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", @@ -5487,6 +5486,7 @@ dependencies = [ "scale-info", "serde", "smallvec", + "sp-api", "sp-core", "sp-io", "sp-keystore", @@ -5518,18 +5518,6 @@ dependencies = [ "syn", ] -[[package]] -name = "pallet-contracts-runtime-api" -version = "4.0.0-dev" -dependencies = [ - "pallet-contracts-primitives", - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 02bc6aede8669..e203cbbee7e0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,7 +87,6 @@ members = [ "frame/collective", "frame/contracts", "frame/contracts/primitives", - "frame/contracts/runtime-api", "frame/conviction-voting", "frame/democracy", "frame/fast-unstake", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index ac3afc19da50f..6940e968e28e7 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -62,7 +62,6 @@ pallet-child-bounties = { version = "4.0.0-dev", default-features = false, path pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../../../frame/collective" } pallet-contracts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts" } pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../../frame/contracts/primitives/" } -pallet-contracts-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/runtime-api/" } pallet-conviction-voting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/conviction-voting" } pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" } pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" } @@ -139,7 +138,6 @@ std = [ "pallet-collective/std", "pallet-contracts/std", "pallet-contracts-primitives/std", - "pallet-contracts-runtime-api/std", "pallet-conviction-voting/std", "pallet-democracy/std", "pallet-elections-phragmen/std", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index d10448cc2d183..4a35b972ff7de 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1939,33 +1939,32 @@ impl_runtime_apis! { } } - impl pallet_contracts_runtime_api::ContractsApi< - Block, AccountId, Balance, BlockNumber, Hash, - > - for Runtime + impl pallet_contracts::ContractsApi for Runtime { fn call( origin: AccountId, dest: AccountId, value: Balance, - gas_limit: u64, + gas_limit: Option, storage_deposit_limit: Option, input_data: Vec, ) -> pallet_contracts_primitives::ContractExecResult { - Contracts::bare_call(origin, dest, value, Weight::from_ref_time(gas_limit), storage_deposit_limit, input_data, true) + let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); + Contracts::bare_call(origin, dest, value, gas_limit, storage_deposit_limit, input_data, true) } fn instantiate( origin: AccountId, value: Balance, - gas_limit: u64, + gas_limit: Option, storage_deposit_limit: Option, code: pallet_contracts_primitives::Code, data: Vec, salt: Vec, ) -> pallet_contracts_primitives::ContractInstantiateResult { - Contracts::bare_instantiate(origin, value, Weight::from_ref_time(gas_limit), storage_deposit_limit, code, data, salt, true) + let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); + Contracts::bare_instantiate(origin, value, gas_limit, storage_deposit_limit, code, data, salt, true) } fn upload_code( diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 7c3b677e06436..7483ec8935890 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -38,6 +38,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "primitives" } pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/contracts/runtime-api/Cargo.toml b/frame/contracts/runtime-api/Cargo.toml deleted file mode 100644 index 05b0e05d4c568..0000000000000 --- a/frame/contracts/runtime-api/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "pallet-contracts-runtime-api" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "Runtime API definition used to provide dry-run capabilities" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } - -# Substrate Dependencies -pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../primitives" } -sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } - -[features] -default = ["std"] -std = [ - "sp-api/std", - "codec/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", - "pallet-contracts-primitives/std", -] diff --git a/frame/contracts/runtime-api/README.md b/frame/contracts/runtime-api/README.md deleted file mode 100644 index fed285b23b2ac..0000000000000 --- a/frame/contracts/runtime-api/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Runtime API definition used to provide dry-run capabilities - -This API should be imported and implemented by the runtime, -of a node that wants to provide clients with dry-run -capabilities. - -License: Apache-2.0 \ No newline at end of file diff --git a/frame/contracts/runtime-api/src/lib.rs b/frame/contracts/runtime-api/src/lib.rs deleted file mode 100644 index 79fd20c8c0163..0000000000000 --- a/frame/contracts/runtime-api/src/lib.rs +++ /dev/null @@ -1,85 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Runtime API definition used to provide dry-run capabilities. -//! -//! This API should be imported and implemented by the runtime, -//! of a node that wants to provide clients with dry-run -//! capabilities. - -#![cfg_attr(not(feature = "std"), no_std)] - -use codec::Codec; -use pallet_contracts_primitives::{ - Code, CodeUploadResult, ContractExecResult, ContractInstantiateResult, GetStorageResult, -}; -use sp_std::vec::Vec; - -sp_api::decl_runtime_apis! { - /// The API to interact with contracts without using executive. - pub trait ContractsApi where - AccountId: Codec, - Balance: Codec, - BlockNumber: Codec, - Hash: Codec, - { - /// Perform a call from a specified account to a given contract. - /// - /// See `pallet_contracts::Pallet::call`. - fn call( - origin: AccountId, - dest: AccountId, - value: Balance, - gas_limit: u64, - storage_deposit_limit: Option, - input_data: Vec, - ) -> ContractExecResult; - - /// Instantiate a new contract. - /// - /// See `pallet_contracts::Pallet::instantiate`. - fn instantiate( - origin: AccountId, - value: Balance, - gas_limit: u64, - storage_deposit_limit: Option, - code: Code, - data: Vec, - salt: Vec, - ) -> ContractInstantiateResult; - - - /// Upload new code without instantiating a contract from it. - /// - /// See `pallet_contracts::Pallet::upload_code`. - fn upload_code( - origin: AccountId, - code: Vec, - storage_deposit_limit: Option, - ) -> CodeUploadResult; - - /// Query a given storage key in a given contract. - /// - /// Returns `Ok(Some(Vec))` if the storage value exists under the given key in the - /// specified account and `Ok(None)` if it doesn't. If the account specified by the address - /// doesn't exist, or doesn't have a contract then `Err` is returned. - fn get_storage( - address: AccountId, - key: Vec, - ) -> GetStorageResult; - } -} diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 0c90c3ff433b4..794b172cc6282 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -105,7 +105,7 @@ use crate::{ wasm::{OwnerInfo, PrefabWasmModule}, weights::WeightInfo, }; -use codec::{Encode, HasCompact}; +use codec::{Codec, Encode, HasCompact}; use frame_support::{ dispatch::{Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, ensure, @@ -1171,3 +1171,58 @@ where Weight::from(gas_limit).set_proof_size(u64::from(T::MaxCodeLen::get()) * 2) } } + +sp_api::decl_runtime_apis! { + /// The API used to dry-run contract interactions. + pub trait ContractsApi where + AccountId: Codec, + Balance: Codec, + BlockNumber: Codec, + Hash: Codec, + { + /// Perform a call from a specified account to a given contract. + /// + /// See [`crate::Pallet::bare_call`]. + fn call( + origin: AccountId, + dest: AccountId, + value: Balance, + gas_limit: Option, + storage_deposit_limit: Option, + input_data: Vec, + ) -> ContractExecResult; + + /// Instantiate a new contract. + /// + /// See `[crate::Pallet::bare_instantiate]`. + fn instantiate( + origin: AccountId, + value: Balance, + gas_limit: Option, + storage_deposit_limit: Option, + code: Code, + data: Vec, + salt: Vec, + ) -> ContractInstantiateResult; + + + /// Upload new code without instantiating a contract from it. + /// + /// See [`crate::Pallet::bare_upload_code`]. + fn upload_code( + origin: AccountId, + code: Vec, + storage_deposit_limit: Option, + ) -> CodeUploadResult; + + /// Query a given storage key in a given contract. + /// + /// Returns `Ok(Some(Vec))` if the storage value exists under the given key in the + /// specified account and `Ok(None)` if it doesn't. If the account specified by the address + /// doesn't exist, or doesn't have a contract then `Err` is returned. + fn get_storage( + address: AccountId, + key: Vec, + ) -> GetStorageResult; + } +} From 3cb5a4069974cdfae3f6aad18626e1dde19ce3fb Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 6 Oct 2022 12:20:27 +0300 Subject: [PATCH 1244/1472] Add pluggable BEEFY payload constructors (#12428) * primitives/beefy: move Payload to its own file * primitives/beefy: add Payload tests * primitives/beefy: add MmrRootProvider as custom BEEFY payload provider * client/beefy: use generic BEEFY 'PayloadProvider' * primitives/beefy: rename Payload::new to Payload::from_single_entry for clarity * fix visibility * fix cargo doc --- Cargo.lock | 1 + client/beefy/rpc/src/lib.rs | 5 +- client/beefy/src/communication/gossip.rs | 8 +- client/beefy/src/justification.rs | 4 +- client/beefy/src/lib.rs | 13 ++- client/beefy/src/tests.rs | 5 +- client/beefy/src/worker.rs | 90 ++++++------------- primitives/beefy/Cargo.toml | 2 + primitives/beefy/src/commitment.rs | 82 ++++-------------- primitives/beefy/src/lib.rs | 7 +- primitives/beefy/src/mmr.rs | 105 ++++++++++++++++++++++- primitives/beefy/src/payload.rs | 105 +++++++++++++++++++++++ primitives/beefy/src/witness.rs | 8 +- 13 files changed, 284 insertions(+), 151 deletions(-) create mode 100644 primitives/beefy/src/payload.rs diff --git a/Cargo.lock b/Cargo.lock index 9136df1cd9299..a6a7c09514325 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -539,6 +539,7 @@ dependencies = [ "sp-application-crypto", "sp-core", "sp-keystore", + "sp-mmr-primitives", "sp-runtime", "sp-std", ] diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 6f21abc616db8..d29ed433c38db 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -170,7 +170,7 @@ mod tests { communication::notification::BeefyVersionedFinalityProofSender, justification::BeefyVersionedFinalityProof, }; - use beefy_primitives::{known_payload_ids, Payload, SignedCommitment}; + use beefy_primitives::{known_payloads, Payload, SignedCommitment}; use codec::{Decode, Encode}; use jsonrpsee::{types::EmptyParams, RpcModule}; use sp_runtime::traits::{BlakeTwo256, Hash}; @@ -266,7 +266,8 @@ mod tests { } fn create_finality_proof() -> BeefyVersionedFinalityProof { - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); BeefyVersionedFinalityProof::::V1(SignedCommitment { commitment: beefy_primitives::Commitment { payload, diff --git a/client/beefy/src/communication/gossip.rs b/client/beefy/src/communication/gossip.rs index 6c41a2e48932a..520548b943f96 100644 --- a/client/beefy/src/communication/gossip.rs +++ b/client/beefy/src/communication/gossip.rs @@ -237,8 +237,7 @@ mod tests { use crate::keystore::{tests::Keyring, BeefyKeystore}; use beefy_primitives::{ - crypto::Signature, known_payload_ids, Commitment, MmrRootHash, Payload, VoteMessage, - KEY_TYPE, + crypto::Signature, known_payloads, Commitment, MmrRootHash, Payload, VoteMessage, KEY_TYPE, }; use super::*; @@ -348,7 +347,10 @@ mod tests { } fn dummy_vote(block_number: u64) -> VoteMessage { - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, MmrRootHash::default().encode()); + let payload = Payload::from_single_entry( + known_payloads::MMR_ROOT_ID, + MmrRootHash::default().encode(), + ); let commitment = Commitment { payload, block_number, validator_set_id: 0 }; let signature = sign_commitment(&Keyring::Alice, &commitment); diff --git a/client/beefy/src/justification.rs b/client/beefy/src/justification.rs index d9be18593dac7..7243c692727f0 100644 --- a/client/beefy/src/justification.rs +++ b/client/beefy/src/justification.rs @@ -81,7 +81,7 @@ fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { use beefy_primitives::{ - known_payload_ids, Commitment, Payload, SignedCommitment, VersionedFinalityProof, + known_payloads, Commitment, Payload, SignedCommitment, VersionedFinalityProof, }; use substrate_test_runtime_client::runtime::Block; @@ -94,7 +94,7 @@ pub(crate) mod tests { keys: &[Keyring], ) -> BeefyVersionedFinalityProof { let commitment = Commitment { - payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), block_number: block_num, validator_set_id: validator_set.id(), }; diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 760fc753b18a3..1c61cac072207 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use beefy_primitives::{BeefyApi, MmrRootHash}; +use beefy_primitives::{BeefyApi, MmrRootHash, PayloadProvider}; use parking_lot::Mutex; use prometheus::Registry; use sc_client_api::{Backend, BlockBackend, BlockchainEvents, Finalizer}; @@ -167,11 +167,13 @@ pub struct BeefyNetworkParams { } /// BEEFY gadget initialization parameters. -pub struct BeefyParams { +pub struct BeefyParams { /// BEEFY client pub client: Arc, /// Client Backend pub backend: Arc, + /// BEEFY Payload provider + pub payload_provider: P, /// Runtime Api Provider pub runtime: Arc, /// Local key store @@ -191,11 +193,12 @@ pub struct BeefyParams { /// Start the BEEFY gadget. /// /// This is a thin shim around running and awaiting a BEEFY worker. -pub async fn start_beefy_gadget(beefy_params: BeefyParams) +pub async fn start_beefy_gadget(beefy_params: BeefyParams) where B: Block, BE: Backend, C: Client + BlockBackend, + P: PayloadProvider, R: ProvideRuntimeApi, R::Api: BeefyApi + MmrApi, N: GossipNetwork + NetworkRequest + SyncOracle + Send + Sync + 'static, @@ -203,6 +206,7 @@ where let BeefyParams { client, backend, + payload_provider, runtime, key_store, network_params, @@ -249,6 +253,7 @@ where let worker_params = worker::WorkerParams { client, backend, + payload_provider, runtime, network, key_store: key_store.into(), @@ -261,7 +266,7 @@ where min_block_delta, }; - let worker = worker::BeefyWorker::<_, _, _, _, _>::new(worker_params); + let worker = worker::BeefyWorker::<_, _, _, _, _, _>::new(worker_params); futures::future::join(worker.run(), on_demand_justifications_handler.run()).await; } diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 8057bd7cab7a5..24cf89acd5734 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -38,6 +38,7 @@ use sc_utils::notification::NotificationReceiver; use beefy_primitives::{ crypto::{AuthorityId, Signature}, + mmr::MmrRootProvider, BeefyApi, ConsensusLog, MmrRootHash, ValidatorSet, VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, }; @@ -372,10 +373,12 @@ where justifications_protocol_name: on_demand_justif_handler.protocol_name(), _phantom: PhantomData, }; + let payload_provider = MmrRootProvider::new(api.clone()); let beefy_params = crate::BeefyParams { client: peer.client().as_client(), backend: peer.client().as_backend(), + payload_provider, runtime: api.clone(), key_store: Some(keystore), network_params, @@ -384,7 +387,7 @@ where prometheus_registry: None, on_demand_justifications_handler: on_demand_justif_handler, }; - let task = crate::start_beefy_gadget::<_, _, _, _, _>(beefy_params); + let task = crate::start_beefy_gadget::<_, _, _, _, _, _>(beefy_params); fn assert_send(_: &T) {} assert_send(&task); diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 5bdc72357c412..a21807c8ee875 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -48,7 +48,7 @@ use sp_runtime::{ use beefy_primitives::{ crypto::{AuthorityId, Signature}, - known_payload_ids, BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, SignedCommitment, + BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, PayloadProvider, SignedCommitment, ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, }; @@ -194,9 +194,10 @@ impl VoterOracle { } } -pub(crate) struct WorkerParams { +pub(crate) struct WorkerParams { pub client: Arc, pub backend: Arc, + pub payload_provider: P, pub runtime: Arc, pub network: N, pub key_store: BeefyKeystore, @@ -210,10 +211,11 @@ pub(crate) struct WorkerParams { } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker { +pub(crate) struct BeefyWorker { // utilities client: Arc, backend: Arc, + payload_provider: P, runtime: Arc, network: N, key_store: BeefyKeystore, @@ -243,11 +245,12 @@ pub(crate) struct BeefyWorker { voting_oracle: VoterOracle, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, C: Client, + P: PayloadProvider, R: ProvideRuntimeApi, R::Api: BeefyApi + MmrApi, N: NetworkEventStream + NetworkRequest + SyncOracle + Send + Sync + Clone + 'static, @@ -258,10 +261,11 @@ where /// BEEFY pallet has been deployed on-chain. /// /// The BEEFY pallet is needed in order to keep track of the BEEFY authority set. - pub(crate) fn new(worker_params: WorkerParams) -> Self { + pub(crate) fn new(worker_params: WorkerParams) -> Self { let WorkerParams { client, backend, + payload_provider, runtime, key_store, network, @@ -282,6 +286,7 @@ where BeefyWorker { client: client.clone(), backend, + payload_provider, runtime, network, known_peers, @@ -299,17 +304,6 @@ where } } - /// Simple wrapper that gets MMR root from header digests or from client state. - fn get_mmr_root_digest(&self, header: &B::Header) -> Option { - find_mmr_root_digest::(header).or_else(|| { - self.runtime - .runtime_api() - .mmr_root(&BlockId::hash(header.hash())) - .ok() - .and_then(|r| r.ok()) - }) - } - /// Verify `active` validator set for `block` against the key store /// /// We want to make sure that we have _at least one_ key in our keystore that @@ -621,13 +615,12 @@ where }; let target_hash = target_header.hash(); - let mmr_root = if let Some(hash) = self.get_mmr_root_digest(&target_header) { + let payload = if let Some(hash) = self.payload_provider.payload(&target_header) { hash } else { warn!(target: "beefy", "🥩 No MMR root digest found for: {:?}", target_hash); return Ok(()) }; - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, mmr_root.encode()); let rounds = self.voting_oracle.rounds_mut().ok_or(Error::UninitSession)?; if !rounds.should_self_vote(&(payload.clone(), target_number)) { @@ -917,20 +910,6 @@ where } } -/// Extract the MMR root hash from a digest in the given header, if it exists. -fn find_mmr_root_digest(header: &B::Header) -> Option -where - B: Block, -{ - let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); - - let filter = |log: ConsensusLog| match log { - ConsensusLog::MmrRoot(root) => Some(root), - _ => None, - }; - header.digest().convert_first(|l| l.try_to(id).and_then(filter)) -} - /// Scan the `header` digest log for a BEEFY validator set change. Return either the new /// validator set or `None` in case no validator set change has been signaled. fn find_authorities_change(header: &B::Header) -> Option> @@ -1016,8 +995,8 @@ pub(crate) mod tests { BeefyRPCLinks, }; + use beefy_primitives::{known_payloads, mmr::MmrRootProvider}; use futures::{executor::block_on, future::poll_fn, task::Poll}; - use sc_client_api::{Backend as BackendT, HeaderBackend}; use sc_network::NetworkService; use sc_network_test::{PeersFullClient, TestNetFactory}; @@ -1032,7 +1011,14 @@ pub(crate) mod tests { peer: &BeefyPeer, key: &Keyring, min_block_delta: u32, - ) -> BeefyWorker>> { + ) -> BeefyWorker< + Block, + Backend, + PeersFullClient, + MmrRootProvider, + TestApi, + Arc>, + > { let keystore = create_beefy_keystore(*key); let (to_rpc_justif_sender, from_voter_justif_stream) = @@ -1064,9 +1050,11 @@ pub(crate) mod tests { "/beefy/justifs/1".into(), known_peers.clone(), ); + let payload_provider = MmrRootProvider::new(api.clone()); let worker_params = crate::worker::WorkerParams { client: peer.client().as_client(), backend: peer.client().as_backend(), + payload_provider, runtime: api, key_store: Some(keystore).into(), known_peers, @@ -1078,7 +1066,7 @@ pub(crate) mod tests { network, on_demand_justifications, }; - BeefyWorker::<_, _, _, _, _>::new(worker_params) + BeefyWorker::<_, _, _, _, _, _>::new(worker_params) } #[test] @@ -1300,30 +1288,6 @@ pub(crate) mod tests { assert_eq!(extracted, Some(validator_set)); } - #[test] - fn extract_mmr_root_digest() { - let mut header = Header::new( - 1u32.into(), - Default::default(), - Default::default(), - Default::default(), - Digest::default(), - ); - - // verify empty digest shows nothing - assert!(find_mmr_root_digest::(&header).is_none()); - - let mmr_root_hash = H256::random(); - header.digest_mut().push(DigestItem::Consensus( - BEEFY_ENGINE_ID, - ConsensusLog::::MmrRoot(mmr_root_hash).encode(), - )); - - // verify validator set is correctly extracted from digest - let extracted = find_mmr_root_digest::(&header); - assert_eq!(extracted, Some(mmr_root_hash)); - } - #[test] fn keystore_vs_validator_set() { let keys = &[Keyring::Alice]; @@ -1363,7 +1327,7 @@ pub(crate) mod tests { let create_finality_proof = |block_num: NumberFor| { let commitment = Commitment { - payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), block_number: block_num, validator_set_id: validator_set.id(), }; @@ -1482,7 +1446,7 @@ pub(crate) mod tests { block_number: NumberFor, ) -> VoteMessage, AuthorityId, Signature> { let commitment = Commitment { - payload: Payload::new(*b"BF", vec![]), + payload: Payload::from_single_entry(*b"BF", vec![]), block_number, validator_set_id: 0, }; @@ -1574,7 +1538,7 @@ pub(crate) mod tests { // import/append BEEFY justification for session boundary block 10 let commitment = Commitment { - payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), block_number: 10, validator_set_id: validator_set.id(), }; @@ -1608,7 +1572,7 @@ pub(crate) mod tests { // import/append BEEFY justification for block 12 let commitment = Commitment { - payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), block_number: 12, validator_set_id: validator_set.id(), }; diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 1c1afde36ce5c..fe6ce23337c86 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -18,6 +18,7 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../merkle-mountain-range" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } @@ -33,6 +34,7 @@ std = [ "sp-api/std", "sp-application-crypto/std", "sp-core/std", + "sp-mmr-primitives/std", "sp-runtime/std", "sp-std/std", ] diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index 0e22c8d56d937..5765ff3609dbb 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -19,61 +19,7 @@ use codec::{Decode, Encode, Error, Input}; use scale_info::TypeInfo; use sp_std::{cmp, prelude::*}; -use crate::ValidatorSetId; - -/// Id of different payloads in the [`Commitment`] data -pub type BeefyPayloadId = [u8; 2]; - -/// Registry of all known [`BeefyPayloadId`]. -pub mod known_payload_ids { - use crate::BeefyPayloadId; - - /// A [`Payload`](super::Payload) identifier for Merkle Mountain Range root hash. - /// - /// Encoded value should contain a [`crate::MmrRootHash`] type (i.e. 32-bytes hash). - pub const MMR_ROOT_ID: BeefyPayloadId = *b"mh"; -} - -/// A BEEFY payload type allowing for future extensibility of adding additional kinds of payloads. -/// -/// The idea is to store a vector of SCALE-encoded values with an extra identifier. -/// Identifiers MUST be sorted by the [`BeefyPayloadId`] to allow efficient lookup of expected -/// value. Duplicated identifiers are disallowed. It's okay for different implementations to only -/// support a subset of possible values. -#[derive(Decode, Encode, Debug, PartialEq, Eq, Clone, Ord, PartialOrd, Hash, TypeInfo)] -pub struct Payload(Vec<(BeefyPayloadId, Vec)>); - -impl Payload { - /// Construct a new payload given an initial vallue - pub fn new(id: BeefyPayloadId, value: Vec) -> Self { - Self(vec![(id, value)]) - } - - /// Returns a raw payload under given `id`. - /// - /// If the [`BeefyPayloadId`] is not found in the payload `None` is returned. - pub fn get_raw(&self, id: &BeefyPayloadId) -> Option<&Vec> { - let index = self.0.binary_search_by(|probe| probe.0.cmp(id)).ok()?; - Some(&self.0[index].1) - } - - /// Returns a decoded payload value under given `id`. - /// - /// In case the value is not there or it cannot be decoded does not match `None` is returned. - pub fn get_decoded(&self, id: &BeefyPayloadId) -> Option { - self.get_raw(id).and_then(|raw| T::decode(&mut &raw[..]).ok()) - } - - /// Push a `Vec` with a given id into the payload vec. - /// This method will internally sort the payload vec after every push. - /// - /// Returns self to allow for daisy chaining. - pub fn push_raw(mut self, id: BeefyPayloadId, value: Vec) -> Self { - self.0.push((id, value)); - self.0.sort_by_key(|(id, _)| *id); - self - } -} +use crate::{Payload, ValidatorSetId}; /// A commitment signed by GRANDPA validators as part of BEEFY protocol. /// @@ -302,13 +248,11 @@ impl From> for VersionedFinalityProof { #[cfg(test)] mod tests { - use sp_core::{keccak_256, Pair}; - use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr}; - use super::*; + use crate::{crypto, known_payloads, KEY_TYPE}; use codec::Decode; - - use crate::{crypto, KEY_TYPE}; + use sp_core::{keccak_256, Pair}; + use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr}; type TestCommitment = Commitment; type TestSignedCommitment = SignedCommitment; @@ -341,7 +285,8 @@ mod tests { #[test] fn commitment_encode_decode() { // given - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; @@ -362,7 +307,8 @@ mod tests { #[test] fn signed_commitment_encode_decode() { // given - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; @@ -396,7 +342,8 @@ mod tests { #[test] fn signed_commitment_count_signatures() { // given - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; @@ -421,7 +368,8 @@ mod tests { block_number: u128, validator_set_id: crate::ValidatorSetId, ) -> TestCommitment { - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); Commitment { payload, block_number, validator_set_id } } @@ -441,7 +389,8 @@ mod tests { #[test] fn versioned_commitment_encode_decode() { - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; @@ -467,7 +416,8 @@ mod tests { #[test] fn large_signed_commitment_encode_decode() { // given - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index 87f1b8756af65..705366e1b4778 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -33,12 +33,11 @@ mod commitment; pub mod mmr; +mod payload; pub mod witness; -pub use commitment::{ - known_payload_ids, BeefyPayloadId, Commitment, Payload, SignedCommitment, - VersionedFinalityProof, -}; +pub use commitment::{Commitment, SignedCommitment, VersionedFinalityProof}; +pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; use codec::{Codec, Decode, Encode}; use scale_info::TypeInfo; diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 471cb96841b8e..b479d979f13f3 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -17,8 +17,8 @@ //! BEEFY + MMR utilties. //! -//! While BEEFY can be used completely indepentently as an additional consensus gadget, -//! it is designed around a main use case of making bridging standalone networks together. +//! While BEEFY can be used completely independently as an additional consensus gadget, +//! it is designed around a main use case of bridging standalone networks together. //! For that use case it's common to use some aggregated data structure (like MMR) to be //! used in conjunction with BEEFY, to be able to efficiently prove any past blockchain data. //! @@ -26,9 +26,13 @@ //! but we imagine they will be useful for other chains that either want to bridge with Polkadot //! or are completely standalone, but heavily inspired by Polkadot. -use crate::Vec; +use crate::{crypto::AuthorityId, ConsensusLog, MmrRootHash, Vec, BEEFY_ENGINE_ID}; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +use sp_runtime::{ + generic::OpaqueDigestItemId, + traits::{Block, Header}, +}; /// A provider for extra data that gets added to the Mmr leaf pub trait BeefyDataProvider { @@ -121,9 +125,78 @@ pub struct BeefyAuthoritySet { /// Details of the next BEEFY authority set. pub type BeefyNextAuthoritySet = BeefyAuthoritySet; +/// Extract the MMR root hash from a digest in the given header, if it exists. +pub fn find_mmr_root_digest(header: &B::Header) -> Option { + let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); + + let filter = |log: ConsensusLog| match log { + ConsensusLog::MmrRoot(root) => Some(root), + _ => None, + }; + header.digest().convert_first(|l| l.try_to(id).and_then(filter)) +} + +#[cfg(feature = "std")] +pub use mmr_root_provider::MmrRootProvider; +#[cfg(feature = "std")] +mod mmr_root_provider { + use super::*; + use crate::{known_payloads, payload::PayloadProvider, Payload}; + use sp_api::ProvideRuntimeApi; + use sp_mmr_primitives::MmrApi; + use sp_runtime::generic::BlockId; + use sp_std::{marker::PhantomData, sync::Arc}; + + /// A [`crate::Payload`] provider where payload is Merkle Mountain Range root hash. + /// + /// Encoded payload contains a [`crate::MmrRootHash`] type (i.e. 32-bytes hash). + pub struct MmrRootProvider { + runtime: Arc, + _phantom: PhantomData, + } + + impl MmrRootProvider + where + B: Block, + R: ProvideRuntimeApi, + R::Api: MmrApi, + { + /// Create new BEEFY Payload provider with MMR Root as payload. + pub fn new(runtime: Arc) -> Self { + Self { runtime, _phantom: PhantomData } + } + + /// Simple wrapper that gets MMR root from header digests or from client state. + fn mmr_root_from_digest_or_runtime(&self, header: &B::Header) -> Option { + find_mmr_root_digest::(header).or_else(|| { + self.runtime + .runtime_api() + .mmr_root(&BlockId::hash(header.hash())) + .ok() + .and_then(|r| r.ok()) + }) + } + } + + impl PayloadProvider for MmrRootProvider + where + B: Block, + R: ProvideRuntimeApi, + R::Api: MmrApi, + { + fn payload(&self, header: &B::Header) -> Option { + self.mmr_root_from_digest_or_runtime(header).map(|mmr_root| { + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, mmr_root.encode()) + }) + } + } +} + #[cfg(test)] mod tests { use super::*; + use crate::H256; + use sp_runtime::{traits::BlakeTwo256, Digest, DigestItem, OpaqueExtrinsic}; #[test] fn should_construct_version_correctly() { @@ -147,4 +220,30 @@ mod tests { fn should_panic_if_minor_too_large() { MmrLeafVersion::new(0, 32); } + + #[test] + fn extract_mmr_root_digest() { + type Header = sp_runtime::generic::Header; + type Block = sp_runtime::generic::Block; + let mut header = Header::new( + 1u64, + Default::default(), + Default::default(), + Default::default(), + Digest::default(), + ); + + // verify empty digest shows nothing + assert!(find_mmr_root_digest::(&header).is_none()); + + let mmr_root_hash = H256::random(); + header.digest_mut().push(DigestItem::Consensus( + BEEFY_ENGINE_ID, + ConsensusLog::::MmrRoot(mmr_root_hash).encode(), + )); + + // verify validator set is correctly extracted from digest + let extracted = find_mmr_root_digest::(&header); + assert_eq!(extracted, Some(mmr_root_hash)); + } } diff --git a/primitives/beefy/src/payload.rs b/primitives/beefy/src/payload.rs new file mode 100644 index 0000000000000..0f23c3f381f19 --- /dev/null +++ b/primitives/beefy/src/payload.rs @@ -0,0 +1,105 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_runtime::traits::Block; +use sp_std::prelude::*; + +/// Id of different payloads in the [`crate::Commitment`] data. +pub type BeefyPayloadId = [u8; 2]; + +/// Registry of all known [`BeefyPayloadId`]. +pub mod known_payloads { + use crate::BeefyPayloadId; + + /// A [`Payload`](super::Payload) identifier for Merkle Mountain Range root hash. + /// + /// Encoded value should contain a [`crate::MmrRootHash`] type (i.e. 32-bytes hash). + pub const MMR_ROOT_ID: BeefyPayloadId = *b"mh"; +} + +/// A BEEFY payload type allowing for future extensibility of adding additional kinds of payloads. +/// +/// The idea is to store a vector of SCALE-encoded values with an extra identifier. +/// Identifiers MUST be sorted by the [`BeefyPayloadId`] to allow efficient lookup of expected +/// value. Duplicated identifiers are disallowed. It's okay for different implementations to only +/// support a subset of possible values. +#[derive(Decode, Encode, Debug, PartialEq, Eq, Clone, Ord, PartialOrd, Hash, TypeInfo)] +pub struct Payload(Vec<(BeefyPayloadId, Vec)>); + +impl Payload { + /// Construct a new payload given an initial vallue + pub fn from_single_entry(id: BeefyPayloadId, value: Vec) -> Self { + Self(vec![(id, value)]) + } + + /// Returns a raw payload under given `id`. + /// + /// If the [`BeefyPayloadId`] is not found in the payload `None` is returned. + pub fn get_raw(&self, id: &BeefyPayloadId) -> Option<&Vec> { + let index = self.0.binary_search_by(|probe| probe.0.cmp(id)).ok()?; + Some(&self.0[index].1) + } + + /// Returns a decoded payload value under given `id`. + /// + /// In case the value is not there or it cannot be decoded does not match `None` is returned. + pub fn get_decoded(&self, id: &BeefyPayloadId) -> Option { + self.get_raw(id).and_then(|raw| T::decode(&mut &raw[..]).ok()) + } + + /// Push a `Vec` with a given id into the payload vec. + /// This method will internally sort the payload vec after every push. + /// + /// Returns self to allow for daisy chaining. + pub fn push_raw(mut self, id: BeefyPayloadId, value: Vec) -> Self { + self.0.push((id, value)); + self.0.sort_by_key(|(id, _)| *id); + self + } +} + +/// Trait for custom BEEFY payload providers. +pub trait PayloadProvider { + /// Provide BEEFY payload if available for `header`. + fn payload(&self, header: &B::Header) -> Option; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn payload_methods_work_as_expected() { + let id1: BeefyPayloadId = *b"hw"; + let msg1: String = "1. Hello World!".to_string(); + let id2: BeefyPayloadId = *b"yb"; + let msg2: String = "2. Yellow Board!".to_string(); + let id3: BeefyPayloadId = *b"cs"; + let msg3: String = "3. Cello Cord!".to_string(); + + let payload = Payload::from_single_entry(id1, msg1.encode()) + .push_raw(id2, msg2.encode()) + .push_raw(id3, msg3.encode()); + + assert_eq!(payload.get_decoded(&id1), Some(msg1)); + assert_eq!(payload.get_decoded(&id2), Some(msg2)); + assert_eq!(payload.get_raw(&id3), Some(&msg3.encode())); + assert_eq!(payload.get_raw(&known_payloads::MMR_ROOT_ID), None); + } +} diff --git a/primitives/beefy/src/witness.rs b/primitives/beefy/src/witness.rs index cebfc3de85049..2c45e0ade90c4 100644 --- a/primitives/beefy/src/witness.rs +++ b/primitives/beefy/src/witness.rs @@ -81,7 +81,7 @@ mod tests { use super::*; use codec::Decode; - use crate::{crypto, known_payload_ids, Payload, KEY_TYPE}; + use crate::{crypto, known_payloads, Payload, KEY_TYPE}; type TestCommitment = Commitment; type TestSignedCommitment = SignedCommitment; @@ -111,8 +111,10 @@ mod tests { } fn signed_commitment() -> TestSignedCommitment { - let payload = - Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".as_bytes().to_vec()); + let payload = Payload::from_single_entry( + known_payloads::MMR_ROOT_ID, + "Hello World!".as_bytes().to_vec(), + ); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; From a84def97102166643bc3c807ae69892551c47536 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Thu, 6 Oct 2022 14:12:51 +0200 Subject: [PATCH 1245/1472] Maximum value for `MultiplierUpdate` (#12282) * Maximum value for MultiplierUpdate * Update frame/transaction-payment/src/lib.rs Co-authored-by: Stephen Shelton * Update lib.rs * return constant * fix in runtime * Update frame/transaction-payment/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/transaction-payment/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fixes * remove unused import * Update lib.rs * more readable * fix * fix nits Co-authored-by: Stephen Shelton Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- bin/node/runtime/src/impls.rs | 5 +++-- bin/node/runtime/src/lib.rs | 12 +++++++++--- frame/transaction-payment/src/lib.rs | 26 ++++++++++++++++++++------ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 0f9ed6e275196..0a5c797ba729f 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -126,8 +126,8 @@ mod multiplier_tests { use crate::{ constants::{currency::*, time::*}, - AdjustmentVariable, MinimumMultiplier, Runtime, RuntimeBlockWeights as BlockWeights, - System, TargetBlockFullness, TransactionPayment, + AdjustmentVariable, MaximumMultiplier, MinimumMultiplier, Runtime, + RuntimeBlockWeights as BlockWeights, System, TargetBlockFullness, TransactionPayment, }; use frame_support::{ dispatch::DispatchClass, @@ -156,6 +156,7 @@ mod multiplier_tests { TargetBlockFullness, AdjustmentVariable, MinimumMultiplier, + MaximumMultiplier, >::convert(fm) } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4a35b972ff7de..34f6988c31643 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -65,7 +65,7 @@ use sp_runtime::{ curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ - self, BlakeTwo256, Block as BlockT, ConvertInto, NumberFor, OpaqueKeys, + self, BlakeTwo256, Block as BlockT, Bounded, ConvertInto, NumberFor, OpaqueKeys, SaturatedConversion, StaticLookup, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, @@ -443,6 +443,7 @@ parameter_types! { pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(1, 100_000); pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000_000u128); + pub MaximumMultiplier: Multiplier = Bounded::max_value(); } impl pallet_transaction_payment::Config for Runtime { @@ -451,8 +452,13 @@ impl pallet_transaction_payment::Config for Runtime { type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; type LengthToFee = ConstantMultiplier; - type FeeMultiplierUpdate = - TargetedFeeAdjustment; + type FeeMultiplierUpdate = TargetedFeeAdjustment< + Self, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, + >; } impl pallet_asset_tx_payment::Config for Runtime { diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 80297d1a0d362..ce85bf93a90a7 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -127,12 +127,14 @@ type BalanceOf = <::OnChargeTransaction as OnChargeTransaction -pub struct TargetedFeeAdjustment(sp_std::marker::PhantomData<(T, S, V, M)>); +pub struct TargetedFeeAdjustment(sp_std::marker::PhantomData<(T, S, V, M, X)>); /// Something that can convert the current multiplier to the next one. pub trait MultiplierUpdate: Convert { - /// Minimum multiplier + /// Minimum multiplier. Any outcome of the `convert` function should be at least this. fn min() -> Multiplier; + /// Maximum multiplier. Any outcome of the `convert` function should be less or equal this. + fn max() -> Multiplier; /// Target block saturation level fn target() -> Perquintill; /// Variability factor @@ -143,6 +145,9 @@ impl MultiplierUpdate for () { fn min() -> Multiplier { Default::default() } + fn max() -> Multiplier { + ::max_value() + } fn target() -> Perquintill { Default::default() } @@ -151,16 +156,20 @@ impl MultiplierUpdate for () { } } -impl MultiplierUpdate for TargetedFeeAdjustment +impl MultiplierUpdate for TargetedFeeAdjustment where T: frame_system::Config, S: Get, V: Get, M: Get, + X: Get, { fn min() -> Multiplier { M::get() } + fn max() -> Multiplier { + X::get() + } fn target() -> Perquintill { S::get() } @@ -169,18 +178,20 @@ where } } -impl Convert for TargetedFeeAdjustment +impl Convert for TargetedFeeAdjustment where T: frame_system::Config, S: Get, V: Get, M: Get, + X: Get, { fn convert(previous: Multiplier) -> Multiplier { // Defensive only. The multiplier in storage should always be at most positive. Nonetheless // we recover here in case of errors, because any value below this would be stale and can // never change. let min_multiplier = M::get(); + let max_multiplier = X::get(); let previous = previous.max(min_multiplier); let weights = T::BlockWeights::get(); @@ -217,11 +228,11 @@ where if positive { let excess = first_term.saturating_add(second_term).saturating_mul(previous); - previous.saturating_add(excess).max(min_multiplier) + previous.saturating_add(excess).max(min_multiplier).min(max_multiplier) } else { // Defensive-only: first_term > second_term. Safe subtraction. let negative = first_term.saturating_sub(second_term).saturating_mul(previous); - previous.saturating_sub(negative).max(min_multiplier) + previous.saturating_sub(negative).max(min_multiplier).min(max_multiplier) } } } @@ -233,6 +244,9 @@ impl> MultiplierUpdate for ConstFeeMultiplier { fn min() -> Multiplier { M::get() } + fn max() -> Multiplier { + M::get() + } fn target() -> Perquintill { Default::default() } From f77f788c8cd8692f716a54f13c434a8774246d7a Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 6 Oct 2022 16:31:56 -0400 Subject: [PATCH 1246/1472] macro stubs for all pallet:: macros to improve documentation visibility and discovery + revamp of pallet macro documentation (#12334) * proof of concept working for pallet::whitelist_storage * fix comments * pallet macros docs rewrite WIP * fix issue with cargo fmt cobbling links * tweak capitalization * fix docs for storage_version * fix docs for pallet::hooks * fix several comments * fix invalid link * fix wrapping and add missing links for pallet::hooks docs * run rewrap on all text blocks in frame_support::pallet docs * cargo fmt * fix up pallet::call_index docs * fix docs for pallet::extra_constants * fix docs for pallet::error * fix docs for pallet::event * fix docs for pallet::event * * fix docs for pallet::storage * fix docs for pallet::getter * fix docs for pallet::storage_prefix * fix docs for pallet::unbounded * fix docs for pallet::whitelist_storage * fix docs for #[cfg(..)] (for storage items and attributes) * fix docs for pallet::storage macro expansion * fix docs for pallet::type_value * fix docs for pallet::genesis_config * fix docs for pallet::genesis_build * fix docs for pallet::inherent * fix docs for pallet::validate_unsigned * fix docs for pallet::origin * fix docs for general notes on instantiable pallets * fix docs for example of a non-instantiable pallet * fix docs for example of an instantiable pallet * fix docs for upgrade guidelines * fix docs for upgrade guidelines * fix docs for upgrade checking and final notes * fix some examples near the beginning * extract docs for `pallet::whitelist_storage` * add docs for pallet_macro_stub * fix order of pallet::config and pallet::constant * set up stub for pallet::config * set up stub for pallet::constant * fix * set up stub for pallet::disable_frame_system_supertrait_check * set up stub for pallet::generate_storage_info * set up stub for pallet::storage_version * set up stub for pallet::hooks * set up stub for pallet::weight * set up stub for pallet::compact * set up stub for pallet::call_index * set up stub for pallet::extra_constants * set up stub for pallet::error * set up stub for pallet::event * set up stub for pallet::generate_deposit * set up stub for pallet::storage * set up stub for pallet::getter * set up stub for pallet::storage_prefix * set up stub for pallet::unbounded * set up stub for pallet::type_value * set up stub for pallet::genesis_config * set up stub for pallet::genesis_build * set up stub for pallet::inherent * set up stub for pallet::validate_unsigned * set up stub for pallet::origin * fix comment * cargo fmt * tweak error message * Update frame/support/procedural/src/lib.rs Co-authored-by: Keith Yeung * Update frame/support/procedural/src/lib.rs Co-authored-by: Keith Yeung * switch order of derives Co-authored-by: Squirrel * tweak wording Co-authored-by: Squirrel * add more context info about `MAX_MODULE_ERROR_ENCODED_SIZE` Co-authored-by: Squirrel * tweak wording about where clause Co-authored-by: Squirrel * clarify wording about system/events key Co-authored-by: Squirrel * use "The Event enum" instead of "item" Co-authored-by: Squirrel * fix bad wording Co-authored-by: Squirrel * use enum instead of type Co-authored-by: Squirrel * expect => expects Co-authored-by: Squirrel * add additional note about storage prefix Co-authored-by: Squirrel * clearer note about GenesisConfig Co-authored-by: Squirrel * Use "The impl" instead of "The item" Co-authored-by: Squirrel * add note and link to tight-coupling docs Co-authored-by: Squirrel * cargo fmt * remove spaces around parenthesis * fix missing text for pallet::config * fix issue with pallet::constant intro * fix wording about codec index * fix pallet::error wording * fix comment about 1 byte => 256 errors * fix where clause comment * fix comment about where pallet events are stored * rewrap some text * fix pallet::storage docs * fix pallet::storage_prefix docs * tweak docs for pallet::genesis_build * tweak docs for pallet::config * specify that pallet::event must be present if pallet::config is present * add note about why we would want to bypass the supertrait check * mention that pallet::generate_store attribute is only valid on pallet struct * add note about adding new calls to the end to maintain existing order * add note about pallet::type_value and pallet::storage Co-authored-by: Squirrel * add note about using pallet::type_value alongside pallet::storage * include warning about modifying disaptchables on other pallet::call_index docs page * fix incorrect comment * add much more information for pallet::inherent * move pallet::pallet macro expansion notes back to their rightful place * re-run CI * fix macro expansion appearing in wrong place for pallet::pallet * replicate pallet::pallet docs on the pallet::pallet macro stub * force CI re-run Co-authored-by: Keith Yeung Co-authored-by: Squirrel Co-authored-by: parity-processbot <> --- frame/support/procedural/src/lib.rs | 680 +++++++++++++++++++- frame/support/src/lib.rs | 964 ++++++++++++++++------------ 2 files changed, 1223 insertions(+), 421 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 0f72b28748cee..ccff5488c93be 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -36,6 +36,7 @@ mod transactional; mod tt_macro; use proc_macro::TokenStream; +use quote::quote; use std::{cell::RefCell, str::FromStr}; pub(crate) use storage::INHERENT_INSTANCE_NAME; @@ -402,7 +403,49 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { construct_runtime::construct_runtime(input) } -/// Macro to define a pallet. Docs are at `frame_support::pallet`. +/// The pallet struct placeholder `#[pallet::pallet]` is mandatory and allows you to specify +/// pallet information. +/// +/// The struct must be defined as follows: +/// ```ignore +/// #[pallet::pallet] +/// pub struct Pallet(_); +/// ``` +/// I.e. a regular struct definition named `Pallet`, with generic T and no where clause. +/// +/// ## Macro expansion: +/// +/// The macro adds this attribute to the struct definition: +/// ```ignore +/// #[derive( +/// frame_support::CloneNoBound, +/// frame_support::EqNoBound, +/// frame_support::PartialEqNoBound, +/// frame_support::RuntimeDebugNoBound, +/// )] +/// ``` +/// and replaces the type `_` with `PhantomData`. It also implements on the pallet: +/// * `GetStorageVersion` +/// * `OnGenesis`: contains some logic to write the pallet version into storage. +/// * `PalletErrorTypeInfo`: provides the type information for the pallet error, if defined. +/// +/// It declares `type Module` type alias for `Pallet`, used by `construct_runtime`. +/// +/// It implements `PalletInfoAccess` on `Pallet` to ease access to pallet information given by +/// `frame_support::traits::PalletInfo`. (The implementation uses the associated type +/// `frame_system::Config::PalletInfo`). +/// +/// It implements `StorageInfoTrait` on `Pallet` which give information about all storages. +/// +/// If the attribute `generate_store` is set then the macro creates the trait `Store` and +/// implements it on `Pallet`. +/// +/// If the attribute `set_storage_max_encoded_len` is set then the macro calls +/// `StorageInfoTrait` for each storage in the implementation of `StorageInfoTrait` for the +/// pallet. Otherwise it implements `StorageInfoTrait` for the pallet using the +/// `PartialStorageInfoTrait` implementation of storages. +/// +/// See `frame_support::pallet` docs for more info. #[proc_macro_attribute] pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream { pallet::pallet(attr, item) @@ -583,3 +626,638 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { .unwrap_or_else(|r| r.into_compile_error()) .into() } + +/// Used internally to decorate pallet attribute macro stubs when they are erroneously used +/// outside of a pallet module +fn pallet_macro_stub() -> TokenStream { + quote!(compile_error!( + "This attribute can only be used from within a pallet module marked with `#[frame_support::pallet]`" + )) + .into() +} + +/// The mandatory attribute `#[pallet::config]` defines the configurable options for the pallet. +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::config] +/// pub trait Config: frame_system::Config + $optionally_some_other_supertraits +/// $optional_where_clause +/// { +/// ... +/// } +/// ``` +/// +/// I.e. a regular trait definition named `Config`, with the supertrait +/// `frame_system::pallet::Config`, and optionally other supertraits and a where clause. +/// (Specifying other supertraits here is known as [tight +/// coupling](https://docs.substrate.io/reference/how-to-guides/pallet-design/use-tight-coupling/)) +/// +/// The associated type `RuntimeEvent` is reserved. If defined, it must have the bounds +/// `From` and `IsType<::RuntimeEvent>`. +/// +/// [`pallet::event`](`macro@event`) must be present if `RuntimeEvent` exists as a config item +/// in your `#[pallet::config]`. +#[proc_macro_attribute] +pub fn config(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by `Get` +/// from [`pallet::config`](`macro@config`) into metadata, e.g.: +/// +/// ```ignore +/// #[pallet::config] +/// pub trait Config: frame_system::Config { +/// #[pallet::constant] +/// type Foo: Get; +/// } +/// ``` +#[proc_macro_attribute] +pub fn constant(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// To bypass the `frame_system::Config` supertrait check, use the attribute +/// `pallet::disable_frame_system_supertrait_check`, e.g.: +/// +/// ```ignore +/// #[pallet::config] +/// #[pallet::disable_frame_system_supertrait_check] +/// pub trait Config: pallet_timestamp::Config {} +/// ``` +/// +/// NOTE: Bypassing the `frame_system::Config` supertrait check is typically desirable when you +/// want to write an alternative to the `frame_system` pallet. +#[proc_macro_attribute] +pub fn disable_frame_system_supertrait_check(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// To generate a `Store` trait associating all storages, annotate your `Pallet` struct with +/// the attribute `#[pallet::generate_store($vis trait Store)]`, e.g.: +/// +/// ```ignore +/// #[pallet::pallet] +/// #[pallet::generate_store(pub(super) trait Store)] +/// pub struct Pallet(_); +/// ``` +/// More precisely, the `Store` trait contains an associated type for each storage. It is +/// implemented for `Pallet` allowing access to the storage from pallet struct. +/// +/// Thus when defining a storage named `Foo`, it can later be accessed from `Pallet` using +/// `::Foo`. +/// +/// NOTE: this attribute is only valid when applied _directly_ to your `Pallet` struct +/// definition. +#[proc_macro_attribute] +pub fn generate_store(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// To generate the full storage info (used for PoV calculation) use the attribute +/// `#[pallet::generate_storage_info]`, e.g.: +/// +/// ```ignore +/// #[pallet::pallet] +/// #[pallet::generate_storage_info] +/// pub struct Pallet(_); +/// ``` +/// +/// This requires all storage items to implement the trait `StorageInfoTrait`, thus all keys +/// and value types must be bound by `MaxEncodedLen`. Individual storages can opt-out from this +/// constraint by using [`#[pallet::unbounded]`](`macro@unbounded`) (see +/// [`#[pallet::storage]`](`macro@storage`) for more info). +#[proc_macro_attribute] +pub fn generate_storage_info(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// Because the `pallet::pallet` macro implements `GetStorageVersion`, the current storage +/// version needs to be communicated to the macro. This can be done by using the +/// `pallet::storage_version` attribute: +/// +/// ```ignore +/// const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); +/// +/// #[pallet::pallet] +/// #[pallet::storage_version(STORAGE_VERSION)] +/// pub struct Pallet(_); +/// ``` +/// +/// If not present, the current storage version is set to the default value. +#[proc_macro_attribute] +pub fn storage_version(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::hooks]` attribute allows you to specify a `Hooks` implementation for +/// `Pallet` that specifies pallet-specific logic. +/// +/// The item the attribute attaches to must be defined as follows: +/// ```ignore +/// #[pallet::hooks] +/// impl Hooks> for Pallet $optional_where_clause { +/// ... +/// } +/// ``` +/// I.e. a regular trait implementation with generic bound: `T: Config`, for the trait +/// `Hooks>` (they are defined in preludes), for the type `Pallet` and +/// with an optional where clause. +/// +/// If no `#[pallet::hooks]` exists, then the following default implementation is +/// automatically generated: +/// ```ignore +/// #[pallet::hooks] +/// impl Hooks> for Pallet {} +/// ``` +/// +/// ## Macro expansion +/// +/// The macro implements the traits `OnInitialize`, `OnIdle`, `OnFinalize`, `OnRuntimeUpgrade`, +/// `OffchainWorker`, and `IntegrityTest` using the provided `Hooks` implementation. +/// +/// NOTE: `OnRuntimeUpgrade` is implemented with `Hooks::on_runtime_upgrade` and some +/// additional logic. E.g. logic to write the pallet version into storage. +/// +/// NOTE: The macro also adds some tracing logic when implementing the above traits. The +/// following hooks emit traces: `on_initialize`, `on_finalize` and `on_runtime_upgrade`. +#[proc_macro_attribute] +pub fn hooks(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// Each dispatchable needs to define a weight with `#[pallet::weight($expr)]` attribute, the +/// first argument must be `origin: OriginFor`. +#[proc_macro_attribute] +pub fn weight(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// Compact encoding for arguments can be achieved via `#[pallet::compact]`. The function must +/// return a `DispatchResultWithPostInfo` or `DispatchResult`. +#[proc_macro_attribute] +pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// Each dispatchable may also be annotated with the `#[pallet::call_index($idx)]` attribute, +/// which explicitly defines the codec index for the dispatchable function in the `Call` enum. +/// +/// All call indexes start from 0, until it encounters a dispatchable function with a defined +/// call index. The dispatchable function that lexically follows the function with a defined +/// call index will have that call index, but incremented by 1, e.g. if there are 3 +/// dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` +/// has a call index of 10, then `fn qux` will have an index of 11, instead of 1. +/// +/// All arguments must implement [`Debug`], [`PartialEq`], [`Eq`], `Decode`, `Encode`, and +/// [`Clone`]. For ease of use, bound by the trait `frame_support::pallet_prelude::Member`. +/// +/// If no `#[pallet::call]` exists, then a default implementation corresponding to the +/// following code is automatically generated: +/// +/// ```ignore +/// #[pallet::call] +/// impl Pallet {} +/// ``` +/// +/// **WARNING**: modifying dispatchables, changing their order, removing some, etc., must be +/// done with care. Indeed this will change the outer runtime call type (which is an enum with +/// one variant per pallet), this outer runtime call can be stored on-chain (e.g. in +/// `pallet-scheduler`). Thus migration might be needed. To mitigate against some of this, the +/// `#[pallet::call_index($idx)]` attribute can be used to fix the order of the dispatchable so +/// that the `Call` enum encoding does not change after modification. As a general rule of +/// thumb, it is therefore adventageous to always add new calls to the end so you can maintain +/// the existing order of calls. +/// +/// ### Macro expansion +/// +/// The macro creates an enum `Call` with one variant per dispatchable. This enum implements: +/// [`Clone`], [`Eq`], [`PartialEq`], [`Debug`] (with stripped implementation in `not("std")`), +/// `Encode`, `Decode`, `GetDispatchInfo`, `GetCallName`, and `UnfilteredDispatchable`. +/// +/// The macro implements the `Callable` trait on `Pallet` and a function `call_functions` +/// which returns the dispatchable metadata. +#[proc_macro_attribute] +pub fn call_index(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// Allows you to define some extra constants to be added into constant metadata. +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::extra_constants] +/// impl Pallet where $optional_where_clause { +/// /// $some_doc +/// $vis fn $fn_name() -> $some_return_type { +/// ... +/// } +/// ... +/// } +/// ``` +/// I.e. a regular rust `impl` block with some optional where clause and functions with 0 args, +/// 0 generics, and some return type. +/// +/// ## Macro expansion +/// +/// The macro add some extra constants to pallet constant metadata. +#[proc_macro_attribute] +pub fn extra_constants(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::error]` attribute allows you to define an error enum that will be returned +/// from the dispatchable when an error occurs. The information for this error type is then +/// stored in metadata. +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::error] +/// pub enum Error { +/// /// $some_optional_doc +/// $SomeFieldLessVariant, +/// /// $some_more_optional_doc +/// $SomeVariantWithOneField(FieldType), +/// ... +/// } +/// ``` +/// I.e. a regular enum named `Error`, with generic `T` and fieldless or multiple-field +/// variants. +/// +/// Any field type in the enum variants must implement `TypeInfo` in order to be properly used +/// in the metadata, and its encoded size should be as small as possible, preferably 1 byte in +/// size in order to reduce storage size. The error enum itself has an absolute maximum encoded +/// size specified by `MAX_MODULE_ERROR_ENCODED_SIZE`. +/// +/// (1 byte can still be 256 different errors. The more specific the error, the easier it is to +/// diagnose problems and give a better experience to the user. Don't skimp on having lots of +/// individual error conditions.) +/// +/// Field types in enum variants must also implement `PalletError`, otherwise the pallet will +/// fail to compile. Rust primitive types have already implemented the `PalletError` trait +/// along with some commonly used stdlib types such as [`Option`] and `PhantomData`, and hence +/// in most use cases, a manual implementation is not necessary and is discouraged. +/// +/// The generic `T` must not bound anything and a `where` clause is not allowed. That said, +/// bounds and/or a where clause should not needed for any use-case. +/// +/// ## Macro expansion +/// +/// The macro implements the [`Debug`] trait and functions `as_u8` using variant position, and +/// `as_str` using variant doc. +/// +/// The macro also implements `From>` for `&'static str` and `From>` for +/// `DispatchError`. +#[proc_macro_attribute] +pub fn error(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::event]` attribute allows you to define pallet events. Pallet events are +/// stored under the `system` / `events` key when the block is applied (and then replaced when +/// the next block writes it's events). +/// +/// The Event enum must be defined as follows: +/// +/// ```ignore +/// #[pallet::event] +/// #[pallet::generate_deposit($visibility fn deposit_event)] // Optional +/// pub enum Event<$some_generic> $optional_where_clause { +/// /// Some doc +/// $SomeName($SomeType, $YetanotherType, ...), +/// ... +/// } +/// ``` +/// +/// I.e. an enum (with named or unnamed fields variant), named `Event`, with generic: none or +/// `T` or `T: Config`, and optional w here clause. +/// +/// Each field must implement [`Clone`], [`Eq`], [`PartialEq`], `Encode`, `Decode`, and +/// [`Debug`] (on std only). For ease of use, bound by the trait `Member`, available in +/// `frame_support::pallet_prelude`. +#[proc_macro_attribute] +pub fn event(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The attribute `#[pallet::generate_deposit($visibility fn deposit_event)]` generates a +/// helper function on `Pallet` that handles deposit events. +/// +/// NOTE: For instantiable pallets, the event must be generic over `T` and `I`. +/// +/// ## Macro expansion +/// +/// The macro will add on enum `Event` the attributes: +/// * `#[derive(frame_support::CloneNoBound)]` +/// * `#[derive(frame_support::EqNoBound)]` +/// * `#[derive(frame_support::PartialEqNoBound)]` +/// * `#[derive(frame_support::RuntimeDebugNoBound)]` +/// * `#[derive(codec::Encode)]` +/// * `#[derive(codec::Decode)]` +/// +/// The macro implements `From>` for (). +/// +/// The macro implements a metadata function on `Event` returning the `EventMetadata`. +/// +/// If `#[pallet::generate_deposit]` is present then the macro implements `fn deposit_event` on +/// `Pallet`. +#[proc_macro_attribute] +pub fn generate_deposit(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::storage]` attribute lets you define some abstract storage inside of runtime +/// storage and also set its metadata. This attribute can be used multiple times. +/// +/// Item should be defined as: +/// +/// ```ignore +/// #[pallet::storage] +/// #[pallet::getter(fn $getter_name)] // optional +/// $vis type $StorageName<$some_generic> $optional_where_clause +/// = $StorageType<$generic_name = $some_generics, $other_name = $some_other, ...>; +/// ``` +/// +/// or with unnamed generic: +/// +/// ```ignore +/// #[pallet::storage] +/// #[pallet::getter(fn $getter_name)] // optional +/// $vis type $StorageName<$some_generic> $optional_where_clause +/// = $StorageType<_, $some_generics, ...>; +/// ``` +/// +/// I.e. it must be a type alias, with generics: `T` or `T: Config`. The aliased type must be +/// one of `StorageValue`, `StorageMap` or `StorageDoubleMap`. The generic arguments of the +/// storage type can be given in two manners: named and unnamed. For named generic arguments, +/// the name for each argument should match the name defined for it on the storage struct: +/// * `StorageValue` expects `Value` and optionally `QueryKind` and `OnEmpty`, +/// * `StorageMap` expects `Hasher`, `Key`, `Value` and optionally `QueryKind` and `OnEmpty`, +/// * `CountedStorageMap` expects `Hasher`, `Key`, `Value` and optionally `QueryKind` and `OnEmpty`, +/// * `StorageDoubleMap` expects `Hasher1`, `Key1`, `Hasher2`, `Key2`, `Value` and optionally +/// `QueryKind` and `OnEmpty`. +/// +/// For unnamed generic arguments: Their first generic must be `_` as it is replaced by the +/// macro and other generic must declared as a normal generic type declaration. +/// +/// The `Prefix` generic written by the macro is generated using +/// `PalletInfo::name::>()` and the name of the storage type. E.g. if runtime names +/// the pallet "MyExample" then the storage `type Foo = ...` should use the prefix: +/// `Twox128(b"MyExample") ++ Twox128(b"Foo")`. +/// +/// For the `CountedStorageMap` variant, the `Prefix` also implements +/// `CountedStorageMapInstance`. It also associates a `CounterPrefix`, which is implemented the +/// same as above, but the storage prefix is prepend with `"CounterFor"`. E.g. if runtime names +/// the pallet "MyExample" then the storage `type Foo = CountedStorageaMap<...>` will store +/// its counter at the prefix: `Twox128(b"MyExample") ++ Twox128(b"CounterForFoo")`. +/// +/// E.g: +/// +/// ```ignore +/// #[pallet::storage] +/// pub(super) type MyStorage = StorageMap; +/// ``` +/// +/// In this case the final prefix used by the map is `Twox128(b"MyExample") ++ +/// Twox128(b"OtherName")`. +#[proc_macro_attribute] +pub fn storage(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The optional attribute `#[pallet::getter(fn $my_getter_fn_name)]` allows you to define a +/// getter function on `Pallet`. +/// +/// Also see [`pallet::storage`](`macro@storage`) +#[proc_macro_attribute] +pub fn getter(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The optional attribute `#[pallet::storage_prefix = "SomeName"]` allows you to define the +/// storage prefix to use. This is helpful if you wish to rename the storage field but don't +/// want to perform a migration. +/// +/// E.g: +/// +/// ```ignore +/// #[pallet::storage] +/// #[pallet::storage_prefix = "foo"] +/// #[pallet::getter(fn my_storage)] +/// pub(super) type MyStorage = StorageMap; +/// ``` +/// +/// or +/// +/// ```ignore +/// #[pallet::storage] +/// #[pallet::getter(fn my_storage)] +/// pub(super) type MyStorage = StorageMap<_, Blake2_128Concat, u32, u32>; +/// ``` +#[proc_macro_attribute] +pub fn storage_prefix(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The optional attribute `#[pallet::unbounded]` declares the storage as unbounded. When +/// implementating the storage info (when `#[pallet::generate_storage_info]` is specified on +/// the pallet struct placeholder), the size of the storage will be declared as unbounded. This +/// can be useful for storage which can never go into PoV (Proof of Validity). +#[proc_macro_attribute] +pub fn unbounded(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The optional attribute `#[pallet::whitelist_storage]` will declare the +/// storage as whitelisted from benchmarking. Doing so will exclude reads of +/// that value's storage key from counting towards weight calculations during +/// benchmarking. +/// +/// This attribute should only be attached to storages that are known to be +/// read/used in every block. This will result in a more accurate benchmarking weight. +/// +/// ### Example +/// ```ignore +/// #[pallet::storage] +/// #[pallet::whitelist_storage] +/// pub(super) type Number = StorageValue<_, T::BlockNumber, ValueQuery>; +/// ``` +/// +/// NOTE: As with all `pallet::*` attributes, this one _must_ be written as +/// `#[pallet::whitelist_storage]` and can only be placed inside a `pallet` module in order for +/// it to work properly. +#[proc_macro_attribute] +pub fn whitelist_storage(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::type_value]` attribute lets you define a struct implementing the `Get` trait +/// to ease the use of storage types. This attribute is meant to be used alongside +/// [`#[pallet::storage]`](`macro@storage`) to define a storage's default value. This attribute +/// can be used multiple times. +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::type_value] +/// fn $MyDefaultName<$some_generic>() -> $default_type $optional_where_clause { $expr } +/// ``` +/// +/// I.e.: a function definition with generics none or `T: Config` and a returned type. +/// +/// E.g.: +/// +/// ```ignore +/// #[pallet::type_value] +/// fn MyDefault() -> T::Balance { 3.into() } +/// ``` +/// +/// ## Macro expansion +/// +/// The macro renames the function to some internal name, generates a struct with the original +/// name of the function and its generic, and implements `Get<$ReturnType>` by calling the user +/// defined function. +#[proc_macro_attribute] +pub fn type_value(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::genesis_config]` attribute allows you to define the genesis configuration +/// for the pallet. +/// +/// Item is defined as either an enum or a struct. It needs to be public and implement the +/// trait `GenesisBuild` with [`#[pallet::genesis_build]`](`macro@genesis_build`). The type +/// generics are constrained to be either none, or `T` or `T: Config`. +/// +/// E.g: +/// +/// ```ignore +/// #[pallet::genesis_config] +/// pub struct GenesisConfig { +/// _myfield: BalanceOf, +/// } +/// ``` +#[proc_macro_attribute] +pub fn genesis_config(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::genesis_build]` attribute allows you to define how `genesis_configuration` +/// is built. This takes as input the `GenesisConfig` type (as `self`) and constructs the pallet's +/// initial state. +/// +/// The impl must be defined as: +/// +/// ```ignore +/// #[pallet::genesis_build] +/// impl GenesisBuild for GenesisConfig<$maybe_generics> { +/// fn build(&self) { $expr } +/// } +/// ``` +/// +/// I.e. a trait implementation with generic `T: Config`, of trait `GenesisBuild` on +/// type `GenesisConfig` with generics none or `T`. +/// +/// E.g.: +/// +/// ```ignore +/// #[pallet::genesis_build] +/// impl GenesisBuild for GenesisConfig { +/// fn build(&self) {} +/// } +/// ``` +/// +/// ## Macro expansion +/// +/// The macro will add the following attribute: +/// * `#[cfg(feature = "std")]` +/// +/// The macro will implement `sp_runtime::BuildModuleGenesisStorage` using `()` as a second +/// generic for non-instantiable pallets. +#[proc_macro_attribute] +pub fn genesis_build(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::inherent]` attribute allows the pallet to provide some +/// [inherent](https://docs.substrate.io/fundamentals/transaction-types/#inherent-transactions). +/// An inherent is some piece of data that is inserted by a block authoring node at block +/// creation time and can either be accepted or rejected by validators based on whether the +/// data falls within an acceptable range. +/// +/// The most common inherent is the `timestamp` that is inserted into every block. Since there +/// is no way to validate timestamps, validators simply check that the timestamp reported by +/// the block authoring node falls within an acceptable range. +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::inherent] +/// impl ProvideInherent for Pallet { +/// // ... regular trait implementation +/// } +/// ``` +/// +/// I.e. a trait implementation with bound `T: Config`, of trait `ProvideInherent` for type +/// `Pallet`, and some optional where clause. +/// +/// ## Macro expansion +/// +/// The macro currently makes no use of this information, but it might use this information in +/// the future to give information directly to `construct_runtime`. +#[proc_macro_attribute] +pub fn inherent(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::validate_unsigned]` attribute allows the pallet to validate some unsigned +/// transaction: +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::validate_unsigned] +/// impl ValidateUnsigned for Pallet { +/// // ... regular trait implementation +/// } +/// ``` +/// +/// I.e. a trait implementation with bound `T: Config`, of trait `ValidateUnsigned` for type +/// `Pallet`, and some optional where clause. +/// +/// NOTE: There is also the `sp_runtime::traits::SignedExtension` trait that can be used to add +/// some specific logic for transaction validation. +/// +/// ## Macro expansion +/// +/// The macro currently makes no use of this information, but it might use this information in +/// the future to give information directly to `construct_runtime`. +#[proc_macro_attribute] +pub fn validate_unsigned(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::origin]` attribute allows you to define some origin for the pallet. +/// +/// Item must be either a type alias, an enum, or a struct. It needs to be public. +/// +/// E.g.: +/// +/// ```ignore +/// #[pallet::origin] +/// pub struct Origin(PhantomData<(T)>); +/// ``` +/// +/// **WARNING**: modifying origin changes the outer runtime origin. This outer runtime origin +/// can be stored on-chain (e.g. in `pallet-scheduler`), thus any change must be done with care +/// as it might require some migration. +/// +/// NOTE: for instantiable pallets, the origin must be generic over `T` and `I`. +#[proc_macro_attribute] +pub fn origin(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 51aa05261dac3..9b0ee84c34d8a 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -744,7 +744,7 @@ macro_rules! assert_err { /// Assert an expression returns an error specified. /// -/// This can be used on`DispatchResultWithPostInfo` when the post info should +/// This can be used on `DispatchResultWithPostInfo` when the post info should /// be ignored. #[macro_export] macro_rules! assert_err_ignore_postinfo { @@ -1399,6 +1399,7 @@ pub mod pallet_prelude { PartialEqNoBound, RuntimeDebug, RuntimeDebugNoBound, Twox128, Twox256, Twox64Concat, }; pub use codec::{Decode, Encode, MaxEncodedLen}; + pub use frame_support::pallet_macros::*; pub use scale_info::TypeInfo; pub use sp_runtime::{ traits::{MaybeSerializeDeserialize, Member, ValidateUnsigned}, @@ -1413,38 +1414,133 @@ pub mod pallet_prelude { pub use sp_weights::Weight; } -/// `pallet` attribute macro allows to define a pallet to be used in `construct_runtime!`. +/// The `pallet` attribute macro defines a pallet that can be used with +/// [`construct_runtime!`]. It must be attached to a module named `pallet` as follows: /// -/// It is define by a module item: /// ```ignore /// #[pallet] /// pub mod pallet { -/// ... +/// ... /// } /// ``` /// -/// Inside the module the macro will parse item with the attribute: `#[pallet::*]`, some -/// attributes are mandatory, some other optional. -/// -/// The attribute are explained with the syntax of non instantiable pallets, to see how pallet -/// with instance work see below example. +/// Note that various types can be automatically imported using +/// [`frame_support::pallet_prelude`] and `frame_system::pallet_prelude`: /// -/// Note various type can be automatically imported using pallet_prelude in frame_support and -/// frame_system: /// ```ignore /// #[pallet] /// pub mod pallet { -/// use frame_support::pallet_prelude::*; -/// use frame_system::pallet_prelude::*; -/// ... +/// use frame_support::pallet_prelude::*; +/// use frame_system::pallet_prelude::*; +/// ... /// } /// ``` /// -/// # Config trait: `#[pallet::config]` mandatory +/// # pallet::* Attributes +/// +/// The `pallet` macro will parse any items within your `pallet` module that are annotated with +/// `#[pallet::*]` attributes. Some of these attributes are mandatory and some are optional, +/// and they can attach to different types of items within your pallet depending on the +/// attribute in question. The full list of `#[pallet::*]` attributes is shown below in the +/// order in which they are mentioned in this document: +/// +/// * [`pallet::pallet`](#pallet-struct-placeholder-palletpallet-mandatory) +/// * [`pallet::config`](#config-trait-palletconfig-mandatory) +/// * [`pallet::constant`](#palletconstant) +/// * [`pallet::disable_frame_system_supertrait_check`](#disable_supertrait_check) +/// * [`pallet::generate_store($vis trait Store)`](#palletgenerate_storevis-trait-store) +/// * [`pallet::generate_storage_info`](#palletgenerate_storage_info) +/// * [`pallet::storage_version`](#palletstorage_version) +/// * [`pallet::hooks`](#hooks-pallethooks-optional) +/// * [`pallet::call`](#call-palletcall-optional) +/// * [`pallet::weight($expr)`](#palletweightexpr) +/// * [`pallet::compact`](#palletcompact-some_arg-some_type) +/// * [`pallet::call_index($idx)`](#palletcall_indexidx) +/// * [`pallet::extra_constants`](#extra-constants-palletextra_constants-optional) +/// * [`pallet::error`](#error-palleterror-optional) +/// * [`pallet::event`](#event-palletevent-optional) +/// * [`pallet::generate_deposit($visibility fn +/// deposit_event)`](#palletgenerate_depositvisibility-fn-deposit_event) +/// * [`pallet::storage`](#storage-palletstorage-optional) +/// * [`pallet::getter(fn $my_getter_fn_name)`](#palletgetterfn-my_getter_fn_name-optional) +/// * [`pallet::storage_prefix = "SomeName"`](#palletstorage_prefix--somename-optional) +/// * [`pallet::unbounded`](#palletunbounded-optional) +/// * [`pallet::whitelist_storage`](#palletwhitelist_storage-optional) +/// * [`cfg(..)`](#cfg-for-storage) (on storage items) +/// * [`pallet::type_value`](#type-value-pallettype_value-optional) +/// * [`pallet::genesis_config`](#genesis-config-palletgenesis_config-optional) +/// * [`pallet::genesis_build`](#genesis-build-palletgenesis_build-optional) +/// * [`pallet::inherent`](#inherent-palletinherent-optional) +/// * [`pallet::validate_unsigned`](#validate-unsigned-palletvalidate_unsigned-optional) +/// * [`pallet::origin`](#origin-palletorigin-optional) +/// +/// Note that at compile-time, the `#[pallet]` macro will analyze and expand all of these +/// attributes, ultimately removing their AST nodes before they can be parsed as real +/// attribute macro calls. This means that technically we do not need attribute macro +/// definitions for any of these attributes, however, for consistency and discoverability +/// reasons, we still maintain stub attribute macro definitions for all of these attributes in +/// the [`pallet_macros`] module which is automatically included in all pallets as part of the +/// pallet prelude. The actual "work" for all of these attribute macros can be found in the +/// macro expansion for `#[pallet]`. +/// +/// Also note that in this document, pallet attributes are explained using the syntax of +/// non-instantiable pallets. For an example of an instantiable pallet, see [this +/// example](#example-of-an-instantiable-pallet). +/// +/// # Pallet struct placeholder: `#[pallet::pallet]` (mandatory) +/// +/// The pallet struct placeholder `#[pallet::pallet]` is mandatory and allows you to specify +/// pallet information. +/// +/// The struct must be defined as follows: +/// ```ignore +/// #[pallet::pallet] +/// pub struct Pallet(_); +/// ``` +/// I.e. a regular struct definition named `Pallet`, with generic T and no where clause. /// -/// The trait defining generics of the pallet. +/// ## Macro expansion: +/// +/// The macro adds this attribute to the struct definition: +/// ```ignore +/// #[derive( +/// frame_support::CloneNoBound, +/// frame_support::EqNoBound, +/// frame_support::PartialEqNoBound, +/// frame_support::RuntimeDebugNoBound, +/// )] +/// ``` +/// and replaces the type `_` with `PhantomData`. It also implements on the pallet: +/// * [`GetStorageVersion`](`traits::GetStorageVersion`) +/// * [`OnGenesis`](`traits::OnGenesis`): contains some logic to write the pallet version into +/// storage. +/// * `PalletErrorTypeInfo`: provides the type information for the pallet error, if defined. +/// +/// It declares `type Module` type alias for `Pallet`, used by `construct_runtime`. +/// +/// It implements [`PalletInfoAccess`](`traits::PalletInfoAccess') on `Pallet` to ease access +/// to pallet information given by [`frame_support::traits::PalletInfo`]. (The implementation +/// uses the associated type `frame_system::Config::PalletInfo`). +/// +/// It implements [`StorageInfoTrait`](`traits::StorageInfoTrait`) on `Pallet` which give +/// information about all storages. +/// +/// If the attribute `generate_store` is set then the macro creates the trait `Store` and +/// implements it on `Pallet`. +/// +/// If the attribute `set_storage_max_encoded_len` is set then the macro calls +/// [`StorageInfoTrait`](`traits::StorageInfoTrait`) for each storage in the implementation of +/// [`StorageInfoTrait`](`traits::StorageInfoTrait`) for the pallet. Otherwise it implements +/// [`StorageInfoTrait`](`traits::StorageInfoTrait`) for the pallet using the +/// [`PartialStorageInfoTrait`](`traits::PartialStorageInfoTrait`) implementation of storages. +/// +/// # Config trait: `#[pallet::config]` (mandatory) +/// +/// The mandatory attribute `#[pallet::config]` defines the configurable options for the +/// pallet. +/// +/// Item must be defined as: /// -/// Item must be defined as /// ```ignore /// #[pallet::config] /// pub trait Config: frame_system::Config + $optionally_some_other_supertraits @@ -1453,74 +1549,103 @@ pub mod pallet_prelude { /// ... /// } /// ``` -/// I.e. a regular trait definition named `Config`, with supertrait `frame_system::Config`, -/// optionally other supertrait and where clause. /// -/// The associated type `RuntimeEvent` is reserved, if defined it must bounds -/// `From` and `IsType<::RuntimeEvent>`, see -/// `#[pallet::event]` for more information. +/// I.e. a regular trait definition named `Config`, with the supertrait +/// `frame_system::pallet::Config`, and optionally other supertraits and a where clause. +/// (Specifying other supertraits here is known as [tight +/// coupling](https://docs.substrate.io/reference/how-to-guides/pallet-design/use-tight-coupling/)) +/// +/// The associated type `RuntimeEvent` is reserved. If defined, it must have the bounds +/// `From` and `IsType<::RuntimeEvent>`. +/// +/// [`pallet::event`](`frame_support::pallet_macros::event`) must be present if `RuntimeEvent` +/// exists as a config item in your `#[pallet::config]`. +/// +/// Also see [`pallet::config`](`frame_support::pallet_macros::config`) +/// +/// ## `pallet::constant` +/// +/// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by +/// [`Get`](crate::traits::Get) from [`pallet::config`](#palletconfig) into metadata, e.g.: /// -/// To put `Get` associated type into metadatas, use the attribute `#[pallet::constant]`, e.g.: /// ```ignore /// #[pallet::config] /// pub trait Config: frame_system::Config { -/// #[pallet::constant] -/// type Foo: Get; +/// #[pallet::constant] +/// type Foo: Get; /// } /// ``` /// +/// Also see [`pallet::constant`](`frame_support::pallet_macros::constant`) +/// +/// ## `pallet::disable_frame_system_supertrait_check` +/// +/// /// To bypass the `frame_system::Config` supertrait check, use the attribute -/// `#[pallet::disable_frame_system_supertrait_check]`, e.g.: +/// `pallet::disable_frame_system_supertrait_check`, e.g.: +/// /// ```ignore /// #[pallet::config] /// #[pallet::disable_frame_system_supertrait_check] /// pub trait Config: pallet_timestamp::Config {} /// ``` /// -/// ### Macro expansion: +/// NOTE: Bypassing the `frame_system::Config` supertrait check is typically desirable when you +/// want to write an alternative to the `frame_system` pallet. /// -/// The macro expand pallet constant metadata with the information given by -/// `#[pallet::constant]`. +/// Also see +/// [`pallet::disable_frame_system_supertrait_check`](`frame_support::pallet_macros::disable_frame_system_supertrait_check`) /// -/// # Pallet struct placeholder: `#[pallet::pallet]` mandatory +/// ## Macro expansion: /// -/// The placeholder struct, on which is implemented pallet informations. +/// The macro expands pallet constant metadata with the information given by +/// `#[pallet::constant]`. /// -/// Item must be defined as followed: -/// ```ignore -/// #[pallet::pallet] -/// pub struct Pallet(_); -/// ``` -/// I.e. a regular struct definition named `Pallet`, with generic T and no where clause. +/// # `pallet::generate_store($vis trait Store)` +/// +/// To generate a `Store` trait associating all storages, annotate your `Pallet` struct with +/// the attribute `#[pallet::generate_store($vis trait Store)]`, e.g.: /// -/// To generate a `Store` trait associating all storages, use the attribute -/// `#[pallet::generate_store($vis trait Store)]`, e.g.: /// ```ignore /// #[pallet::pallet] /// #[pallet::generate_store(pub(super) trait Store)] /// pub struct Pallet(_); /// ``` -/// More precisely the store trait contains an associated type for each storage. It is -/// implemented for `Pallet` allowing to access the storage from pallet struct. +/// More precisely, the `Store` trait contains an associated type for each storage. It is +/// implemented for `Pallet` allowing access to the storage from pallet struct. /// /// Thus when defining a storage named `Foo`, it can later be accessed from `Pallet` using /// `::Foo`. /// +/// NOTE: this attribute is only valid when applied _directly_ to your `Pallet` struct +/// definition. +/// +/// Also see [`pallet::generate_store`](`frame_support::pallet_macros::generate_store`). +/// +/// # `pallet::generate_storage_info` +/// /// To generate the full storage info (used for PoV calculation) use the attribute /// `#[pallet::generate_storage_info]`, e.g.: +/// /// ```ignore /// #[pallet::pallet] /// #[pallet::generate_storage_info] /// pub struct Pallet(_); /// ``` /// -/// This require all storage to implement the trait [`traits::StorageInfoTrait`], thus all keys -/// and value types must bound [`pallet_prelude::MaxEncodedLen`]. -/// Some individual storage can opt-out from this constraint by using `#[pallet::unbounded]`, -/// see `#[pallet::storage]` documentation. +/// This requires all storage items to implement the trait [`traits::StorageInfoTrait`], thus +/// all keys and value types must be bound by [`pallet_prelude::MaxEncodedLen`]. Individual +/// storages can opt-out from this constraint by using `#[pallet::unbounded]` (see +/// `#[pallet::storage]` for more info). /// -/// As the macro implements [`traits::GetStorageVersion`], the current storage version needs to -/// be communicated to the macro. This can be done by using the `storage_version` attribute: +/// Also see [`pallet::generate_storage_info`](`frame_support::pallet_macros::generate_storage_info`) +/// +/// # `pallet::storage_version` +/// +/// Because the [`pallet::pallet`](#pallet-struct-placeholder-palletpallet-mandatory) macro +/// implements [`traits::GetStorageVersion`], the current storage version needs to be +/// communicated to the macro. This can be done by using the `pallet::storage_version` +/// attribute: /// /// ```ignore /// const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); @@ -1532,75 +1657,34 @@ pub mod pallet_prelude { /// /// If not present, the current storage version is set to the default value. /// -/// ### Macro expansion: -/// -/// The macro add this attribute to the struct definition: -/// ```ignore -/// #[derive( -/// frame_support::CloneNoBound, -/// frame_support::EqNoBound, -/// frame_support::PartialEqNoBound, -/// frame_support::RuntimeDebugNoBound, -/// )] -/// ``` -/// and replace the type `_` by `PhantomData`. -/// -/// It implements on pallet: -/// * [`traits::GetStorageVersion`] -/// * [`traits::OnGenesis`]: contains some logic to write pallet version into storage. -/// * `PalletErrorTypeInfo`: provides the type information for the pallet error, if defined. -/// -/// It declares `type Module` type alias for `Pallet`, used by [`construct_runtime`]. -/// -/// It implements [`traits::PalletInfoAccess`] on `Pallet` to ease access to pallet -/// informations given by [`frame_support::traits::PalletInfo`]. -/// (The implementation uses the associated type `frame_system::Config::PalletInfo`). -/// -/// It implements [`traits::StorageInfoTrait`] on `Pallet` which give information about all -/// storages. -/// -/// If the attribute generate_store is set then the macro creates the trait `Store` and -/// implements it on `Pallet`. -/// -/// If the attribute set_storage_max_encoded_len is set then the macro call -/// [`traits::StorageInfoTrait`] for each storage in the implementation of -/// [`traits::StorageInfoTrait`] for the pallet. -/// Otherwise it implements [`traits::StorageInfoTrait`] for the pallet using the -/// [`traits::PartialStorageInfoTrait`] implementation of storages. +/// Also see [`pallet::storage_version`](`frame_support::pallet_macros::storage_version`) /// -/// # Hooks: `#[pallet::hooks]` optional +/// # Hooks: `#[pallet::hooks]` (optional) /// -/// Implementation of `Hooks` on `Pallet` allowing to define some specific pallet logic. +/// The `pallet::hooks` attribute allows you to specify a `Hooks` implementation for `Pallet` +/// that specifies pallet-specific logic. /// -/// Item must be defined as +/// The item the attribute attaches to must be defined as follows: /// ```ignore /// #[pallet::hooks] /// impl Hooks> for Pallet $optional_where_clause { +/// ... /// } /// ``` /// I.e. a regular trait implementation with generic bound: `T: Config`, for the trait -/// `Hooks>` (they are defined in preludes), for the type `Pallet` -/// and with an optional where clause. +/// `Hooks>` (they are defined in preludes), for the type `Pallet` and +/// with an optional where clause. /// -/// If no `#[pallet::hooks]` exists, then a default implementation corresponding to the -/// following code is automatically generated: +/// If no `#[pallet::hooks]` exists, then the following default implementation is +/// automatically generated: /// ```ignore /// #[pallet::hooks] /// impl Hooks> for Pallet {} /// ``` /// -/// ### Macro expansion: -/// -/// The macro implements the traits `OnInitialize`, `OnIdle`, `OnFinalize`, `OnRuntimeUpgrade`, -/// `OffchainWorker`, `IntegrityTest` using `Hooks` implementation. -/// -/// NOTE: OnRuntimeUpgrade is implemented with `Hooks::on_runtime_upgrade` and some additional -/// logic. E.g. logic to write pallet version into storage. +/// Also see [`pallet::hooks`](`frame_support::pallet_macros::hooks`) /// -/// NOTE: The macro also adds some tracing logic when implementing the above traits. The -/// following hooks emit traces: `on_initialize`, `on_finalize` and `on_runtime_upgrade`. -/// -/// # Call: `#[pallet::call]` optional +/// # Call: `#[pallet::call]` (optional) /// /// Implementation of pallet dispatchables. /// @@ -1622,53 +1706,50 @@ pub mod pallet_prelude { /// } /// ``` /// I.e. a regular type implementation, with generic `T: Config`, on type `Pallet`, with -/// optional where clause. +/// an optional where clause. +/// +/// ## `#[pallet::weight($expr)]` +/// +/// Each dispatchable needs to define a weight with `#[pallet::weight($expr)]` attribute, the +/// first argument must be `origin: OriginFor`. +/// +/// Also see [`pallet::weight`](`frame_support::pallet_macros::weight`) +/// +/// ### `#[pallet::compact] $some_arg: $some_type` +/// +/// Compact encoding for arguments can be achieved via `#[pallet::compact]`. The function must +/// return a `DispatchResultWithPostInfo` or `DispatchResult`. /// -/// Each dispatchable needs to define a weight with `#[pallet::weight($expr)]` attribute, -/// the first argument must be `origin: OriginFor`, compact encoding for argument can be -/// used using `#[pallet::compact]`, function must return `DispatchResultWithPostInfo` or -/// `DispatchResult`. +/// Also see [`pallet::compact`](`frame_support::pallet_macros::compact`) +/// +/// ## `#[pallet::call_index($idx)]` /// /// Each dispatchable may also be annotated with the `#[pallet::call_index($idx)]` attribute, -/// which defines and sets the codec index for the dispatchable function in the `Call` enum. +/// which explicitly defines the codec index for the dispatchable function in the `Call` enum. /// /// All call indexes start from 0, until it encounters a dispatchable function with a defined /// call index. The dispatchable function that lexically follows the function with a defined /// call index will have that call index, but incremented by 1, e.g. if there are 3 -/// dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` has -/// a call index of 10, then `fn qux` will have an index of 11, instead of 1. -/// -/// All arguments must implement `Debug`, `PartialEq`, `Eq`, `Decode`, `Encode`, `Clone`. For -/// ease of use, bound the trait `Member` available in frame_support::pallet_prelude. +/// dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` +/// has a call index of 10, then `fn qux` will have an index of 11, instead of 1. /// -/// If no `#[pallet::call]` exists, then a default implementation corresponding to the -/// following code is automatically generated: -/// ```ignore -/// #[pallet::call] -/// impl Pallet {} -/// ``` -/// -/// **WARNING**: modifying dispatchables, changing their order, removing some must be done with -/// care. Indeed this will change the outer runtime call type (which is an enum with one -/// variant per pallet), this outer runtime call can be stored on-chain (e.g. in -/// pallet-scheduler). Thus migration might be needed. To mitigate against some of this, the +/// **WARNING**: modifying dispatchables, changing their order, removing some, etc., must be +/// done with care. Indeed this will change the outer runtime call type (which is an enum with +/// one variant per pallet), this outer runtime call can be stored on-chain (e.g. in +/// `pallet-scheduler`). Thus migration might be needed. To mitigate against some of this, the /// `#[pallet::call_index($idx)]` attribute can be used to fix the order of the dispatchable so -/// that the `Call` enum encoding does not change after modification. -/// -/// ### Macro expansion +/// that the `Call` enum encoding does not change after modification. As a general rule of +/// thumb, it is therefore adventageous to always add new calls to the end so you can maintain +/// the existing order of calls. /// -/// The macro creates an enum `Call` with one variant per dispatchable. This enum implements: -/// `Clone`, `Eq`, `PartialEq`, `Debug` (with stripped implementation in `not("std")`), -/// `Encode`, `Decode`, `GetDispatchInfo`, `GetCallName`, `UnfilteredDispatchable`. +/// Also see [`pallet::call_index`](`frame_support::pallet_macros::call_index`) /// -/// The macro implement the `Callable` trait on `Pallet` and a function `call_functions` which -/// returns the dispatchable metadata. +/// # Extra constants: `#[pallet::extra_constants]` (optional) /// -/// # Extra constants: `#[pallet::extra_constants]` optional -/// -/// Allow to define some extra constants to put into constant metadata. +/// Allows you to define some extra constants to be added into constant metadata. /// /// Item must be defined as: +/// /// ```ignore /// #[pallet::extra_constants] /// impl Pallet where $optional_where_clause { @@ -1679,19 +1760,23 @@ pub mod pallet_prelude { /// ... /// } /// ``` -/// I.e. a regular rust implement block with some optional where clause and functions with 0 -/// args, 0 generics, and some return type. +/// I.e. a regular rust `impl` block with some optional where clause and functions with 0 args, +/// 0 generics, and some return type. /// -/// ### Macro expansion +/// ## Macro expansion /// -/// The macro add some extra constant to pallet constant metadata. +/// The macro add some extra constants to pallet constant metadata. /// -/// # Error: `#[pallet::error]` optional +/// Also see: [`pallet::extra_constants`](`frame_support::pallet_macros::extra_constants`) /// -/// Allow to define an error type to be return from dispatchable on error. -/// This error type informations are put into metadata. +/// # Error: `#[pallet::error]` (optional) +/// +/// The `#[pallet::error]` attribute allows you to define an error enum that will be returned +/// from the dispatchable when an error occurs. The information for this error type is then +/// stored in metadata. /// /// Item must be defined as: +/// /// ```ignore /// #[pallet::error] /// pub enum Error { @@ -1702,7 +1787,7 @@ pub mod pallet_prelude { /// ... /// } /// ``` -/// I.e. a regular rust enum named `Error`, with generic `T` and fieldless or multiple-field +/// I.e. a regular enum named `Error`, with generic `T` and fieldless or multiple-field /// variants. /// /// Any field type in the enum variants must implement [`scale_info::TypeInfo`] in order to be @@ -1710,29 +1795,28 @@ pub mod pallet_prelude { /// preferably 1 byte in size in order to reduce storage size. The error enum itself has an /// absolute maximum encoded size specified by [`MAX_MODULE_ERROR_ENCODED_SIZE`]. /// +/// (1 byte can still be 256 different errors. The more specific the error, the easier it is to +/// diagnose problems and give a better experience to the user. Don't skimp on having lots of +/// individual error conditions.) +/// /// Field types in enum variants must also implement [`PalletError`](traits::PalletError), /// otherwise the pallet will fail to compile. Rust primitive types have already implemented /// the [`PalletError`](traits::PalletError) trait along with some commonly used stdlib types -/// such as `Option` and `PhantomData`, and hence in most use cases, a manual implementation is -/// not necessary and is discouraged. +/// such as [`Option`] and [`PhantomData`](`frame_support::dispatch::marker::PhantomData`), and +/// hence in most use cases, a manual implementation is not necessary and is discouraged. /// -/// The generic `T` mustn't bound anything and where clause is not allowed. But bounds and -/// where clause shouldn't be needed for any usecase. +/// The generic `T` must not bound anything and a `where` clause is not allowed. That said, +/// bounds and/or a where clause should not needed for any use-case. /// -/// ### Macro expansion +/// Also see: [`pallet::error`](`frame_support::pallet_macros::error`) /// -/// The macro implements `Debug` trait and functions `as_u8` using variant position, and -/// `as_str` using variant doc. +/// # Event: `#[pallet::event]` (optional) /// -/// The macro implements `From>` for `&'static str`. -/// The macro implements `From>` for `DispatchError`. +/// Allows you to define pallet events. Pallet events are stored under the `system` / `events` +/// key when the block is applied (and then replaced when the next block writes it's events). /// -/// # Event: `#[pallet::event]` optional +/// The Event enum must be defined as follows: /// -/// Allow to define pallet events, pallet events are stored in the block when they deposited -/// (and removed in next block). -/// -/// Item is defined as: /// ```ignore /// #[pallet::event] /// #[pallet::generate_deposit($visibility fn deposit_event)] // Optional @@ -1742,157 +1826,174 @@ pub mod pallet_prelude { /// ... /// } /// ``` -/// I.e. an enum (with named or unnamed fields variant), named Event, with generic: none or `T` -/// or `T: Config`, and optional where clause. /// -/// Each field must implement `Clone`, `Eq`, `PartialEq`, `Encode`, `Decode`, and `Debug` (on -/// std only). -/// For ease of use, bound the trait `Member` available in frame_support::pallet_prelude. +/// I.e. an enum (with named or unnamed fields variant), named `Event`, with generic: none or +/// `T` or `T: Config`, and optional w here clause. /// -/// The attribute `#[pallet::generate_deposit($visibility fn deposit_event)]` generate a helper -/// function on `Pallet` to deposit event. +/// Each field must implement [`Clone`], [`Eq`], [`PartialEq`], [`Encode`], [`Decode`], and +/// [`Debug`] (on std only). For ease of use, bound by the trait +/// [`Member`](`frame_support::pallet_prelude::Member`), available in +/// frame_support::pallet_prelude. /// -/// NOTE: For instantiable pallet, event must be generic over T and I. +/// Also see [`pallet::event`](`frame_support::pallet_macros::event`) /// -/// ### Macro expansion: +/// ## `#[pallet::generate_deposit($visibility fn deposit_event)]` /// -/// Macro will add on enum `Event` the attributes: -/// * `#[derive(frame_support::CloneNoBound)]`, -/// * `#[derive(frame_support::EqNoBound)]`, -/// * `#[derive(frame_support::PartialEqNoBound)]`, -/// * `#[derive(codec::Encode)]`, -/// * `#[derive(codec::Decode)]`, -/// * `#[derive(frame_support::RuntimeDebugNoBound)]` +/// The attribute `#[pallet::generate_deposit($visibility fn deposit_event)]` generates a +/// helper function on `Pallet` that handles deposit events. /// -/// Macro implements `From>` for (). +/// NOTE: For instantiable pallets, the event must be generic over `T` and `I`. /// -/// Macro implements metadata function on `Event` returning the `EventMetadata`. +/// Also see [`pallet::generate_deposit`](`frame_support::pallet_macros::generate_deposit`) /// -/// If `#[pallet::generate_deposit]` then macro implement `fn deposit_event` on `Pallet`. +/// # Storage: `#[pallet::storage]` (optional) /// -/// # Storage: `#[pallet::storage]` optional +/// The `#[pallet::storage]` attribute lets you define some abstract storage inside of runtime +/// storage and also set its metadata. This attribute can be used multiple times. /// -/// Allow to define some abstract storage inside runtime storage and also set its metadata. -/// This attribute can be used multiple times. +/// Item should be defined as: /// -/// Item is defined as: /// ```ignore /// #[pallet::storage] /// #[pallet::getter(fn $getter_name)] // optional /// $vis type $StorageName<$some_generic> $optional_where_clause /// = $StorageType<$generic_name = $some_generics, $other_name = $some_other, ...>; /// ``` -/// or with unnamed generic +/// +/// or with unnamed generic: +/// /// ```ignore /// #[pallet::storage] /// #[pallet::getter(fn $getter_name)] // optional /// $vis type $StorageName<$some_generic> $optional_where_clause /// = $StorageType<_, $some_generics, ...>; /// ``` -/// I.e. it must be a type alias, with generics: `T` or `T: Config`, aliased type must be one -/// of `StorageValue`, `StorageMap` or `StorageDoubleMap` (defined in frame_support). -/// The generic arguments of the storage type can be given in two manner: named and unnamed. -/// For named generic argument: the name for each argument is the one as define on the storage -/// struct: -/// * [`pallet_prelude::StorageValue`] expect `Value` and optionally `QueryKind` and `OnEmpty`, -/// * [`pallet_prelude::StorageMap`] expect `Hasher`, `Key`, `Value` and optionally `QueryKind` -/// and `OnEmpty`, -/// * [`pallet_prelude::CountedStorageMap`] expect `Hasher`, `Key`, `Value` and optionally -/// `QueryKind` and `OnEmpty`, -/// * [`pallet_prelude::StorageDoubleMap`] expect `Hasher1`, `Key1`, `Hasher2`, `Key2`, `Value` -/// and optionally `QueryKind` and `OnEmpty`. -/// -/// For unnamed generic argument: Their first generic must be `_` as it is replaced by the -/// macro and other generic must declared as a normal declaration of type generic in rust. -/// -/// The Prefix generic written by the macro is generated using -/// `PalletInfo::name::>()` and the name of the storage type. -/// E.g. if runtime names the pallet "MyExample" then the storage `type Foo = ...` use the -/// prefix: `Twox128(b"MyExample") ++ Twox128(b"Foo")`. /// -/// For the `CountedStorageMap` variant, the Prefix also implements -/// `CountedStorageMapInstance`. It associate a `CounterPrefix`, which is implemented same as -/// above, but the storage prefix is prepend with `"CounterFor"`. -/// E.g. if runtime names the pallet "MyExample" then the storage -/// `type Foo = CountedStorageaMap<...>` will store its counter at the prefix: -/// `Twox128(b"MyExample") ++ Twox128(b"CounterForFoo")`. +/// I.e. it must be a type alias, with generics: `T` or `T: Config`. The aliased type must be +/// one of [`StorageValue`](`pallet_prelude::StorageValue`), +/// [`StorageMap`](`pallet_prelude::StorageMap`) or +/// [`StorageDoubleMap`](`pallet_prelude::StorageDoubleMap`). The generic arguments of the +/// storage type can be given in two manners: named and unnamed. For named generic arguments, +/// the name for each argument should match the name defined for it on the storage struct: +/// * [`StorageValue`](`pallet_prelude::StorageValue`) expects `Value` and optionally +/// `QueryKind` and `OnEmpty`, +/// * [`StorageMap`](`pallet_prelude::StorageMap`) expects `Hasher`, `Key`, `Value` and +/// optionally `QueryKind` and `OnEmpty`, +/// * [`CountedStorageMap`](`pallet_prelude::CountedStorageMap`) expects `Hasher`, `Key`, +/// `Value` and optionally `QueryKind` and `OnEmpty`, +/// * [`StorageDoubleMap`](`pallet_prelude::StorageDoubleMap`) expects `Hasher1`, `Key1`, +/// `Hasher2`, `Key2`, `Value` and optionally `QueryKind` and `OnEmpty`. +/// +/// For unnamed generic arguments: Their first generic must be `_` as it is replaced by the +/// macro and other generic must declared as a normal generic type declaration. +/// +/// The `Prefix` generic written by the macro is generated using +/// `PalletInfo::name::>()` and the name of the storage type. E.g. if runtime names +/// the pallet "MyExample" then the storage `type Foo = ...` should use the prefix: +/// `Twox128(b"MyExample") ++ Twox128(b"Foo")`. +/// +/// For the [`CountedStorageMap`](`pallet_prelude::CountedStorageMap`) variant, the `Prefix` +/// also implements +/// [`CountedStorageMapInstance`](`frame_support::storage::types::CountedStorageMapInstance`). +/// It also associates a [`CounterPrefix`](`pallet_prelude::CounterPrefix'), which is +/// implemented the same as above, but the storage prefix is prepend with `"CounterFor"`. E.g. +/// if runtime names the pallet "MyExample" then the storage `type Foo = +/// CountedStorageaMap<...>` will store its counter at the prefix: `Twox128(b"MyExample") ++ +/// Twox128(b"CounterForFoo")`. /// /// E.g: +/// /// ```ignore /// #[pallet::storage] /// pub(super) type MyStorage = StorageMap; /// ``` -/// In this case the final prefix used by the map is -/// `Twox128(b"MyExample") ++ Twox128(b"OtherName")`. /// -/// The optional attribute `#[pallet::getter(fn $my_getter_fn_name)]` allows to define a +/// In this case the final prefix used by the map is `Twox128(b"MyExample") ++ +/// Twox128(b"OtherName")`. +/// +/// Also see [`pallet::storage`](`frame_support::pallet_macros::storage`) +/// +/// ## `#[pallet::getter(fn $my_getter_fn_name)]` (optional) +/// +/// The optional attribute `#[pallet::getter(fn $my_getter_fn_name)]` allows you to define a /// getter function on `Pallet`. /// -/// The optional attribute `#[pallet::storage_prefix = "SomeName"]` allow to define the storage -/// prefix to use, see how `Prefix` generic is implemented above. +/// Also see [`pallet::getter`](`frame_support::pallet_macros::getter`) +/// +/// ## `#[pallet::storage_prefix = "SomeName"]` (optional) +/// +/// The optional attribute `#[pallet::storage_prefix = "SomeName"]` allows you to define the +/// storage prefix to use, see how `Prefix` generic is implemented above. This is helpful if +/// you wish to rename the storage field but don't want to perform a migration. /// /// E.g: +/// /// ```ignore /// #[pallet::storage] /// #[pallet::storage_prefix = "foo"] /// #[pallet::getter(fn my_storage)] /// pub(super) type MyStorage = StorageMap; /// ``` +/// /// or +/// /// ```ignore /// #[pallet::storage] /// #[pallet::getter(fn my_storage)] /// pub(super) type MyStorage = StorageMap<_, Blake2_128Concat, u32, u32>; /// ``` /// -/// The optional attribute `#[pallet::unbounded]` allows to declare the storage as unbounded. -/// When implementating the storage info (when `#[pallet::generate_storage_info]` is specified -/// on the pallet struct placeholder), the size of the storage will be declared as unbounded. -/// This can be useful for storage which can never go into PoV (Proof of Validity). +/// Also see [`pallet::storage_prefix`](`frame_support::pallet_macros::storage_prefix`) +/// +/// ## `#[pallet::unbounded]` (optional) +/// +/// The optional attribute `#[pallet::unbounded]` declares the storage as unbounded. When +/// implementating the storage info (when `#[pallet::generate_storage_info]` is specified on +/// the pallet struct placeholder), the size of the storage will be declared as unbounded. This +/// can be useful for storage which can never go into PoV (Proof of Validity). +/// +/// Also see [`pallet::unbounded`](`frame_support::pallet_macros::unbounded`) +/// +/// ## `#[pallet::whitelist_storage]` (optional) /// +/// The optional attribute `#[pallet::whitelist_storage]` will declare the storage as +/// whitelisted from benchmarking. +/// +/// See +/// [`pallet::whitelist_storage`](frame_support::pallet_macros::whitelist_storage) +/// for more info. +/// +/// ## `#[cfg(..)]` (for storage) /// The optional attributes `#[cfg(..)]` allow conditional compilation for the storage. /// /// E.g: +/// /// ```ignore /// #[cfg(feature = "my-feature")] /// #[pallet::storage] /// pub(super) type MyStorage = StorageValue; /// ``` /// -/// The optional attribute `#[pallet::whitelist_storage]` will declare the -/// storage as whitelisted from benchmarking. Doing so will exclude reads of -/// that value's storage key from counting towards weight calculations during -/// benchmarking. -/// -/// This attribute should only be attached to storages that are known to be -/// read/used in every block. This will result in a more accurate benchmarking weight. -/// -/// ### Example -/// ```ignore -/// #[pallet::storage] -/// #[pallet::whitelist_storage] -/// pub(super) type Number = StorageValue<_, T::BlockNumber, ValueQuery>; -/// ``` -/// /// All the `cfg` attributes are automatically copied to the items generated for the storage, /// i.e. the getter, storage prefix, and the metadata element etc. /// /// Any type placed as the `QueryKind` parameter must implement /// [`frame_support::storage::types::QueryKindTrait`]. There are 3 implementations of this /// trait by default: -/// 1. [`frame_support::storage::types::OptionQuery`], the default `QueryKind` used when this -/// type parameter is omitted. Specifying this as the `QueryKind` would cause storage map -/// APIs that return a `QueryKind` to instead return an `Option`, returning `Some` when a -/// value does exist under a specified storage key, and `None` otherwise. -/// 2. [`frame_support::storage::types::ValueQuery`] causes storage map APIs that return a -/// `QueryKind` to instead return the value type. In cases where a value does not exist -/// under a specified storage key, the `OnEmpty` type parameter on `QueryKindTrait` is used -/// to return an appropriate value. -/// 3. [`frame_support::storage::types::ResultQuery`] causes storage map APIs that return a -/// `QueryKind` to instead return a `Result`, with `T` being the value type and `E` -/// being the pallet error type specified by the `#[pallet::error]` attribute. In cases -/// where a value does not exist under a specified storage key, an `Err` with the specified -/// pallet error variant is returned. +/// +/// 1. [`OptionQuery`](`frame_support::storage::types::OptionQuery`), the default `QueryKind` +/// used when this type parameter is omitted. Specifying this as the `QueryKind` would cause +/// storage map APIs that return a `QueryKind` to instead return an [`Option`], returning +/// `Some` when a value does exist under a specified storage key, and `None` otherwise. +/// 2. [`ValueQuery`](`frame_support::storage::types::ValueQuery`) causes storage map APIs that +/// return a `QueryKind` to instead return the value type. In cases where a value does not +/// exist under a specified storage key, the `OnEmpty` type parameter on `QueryKindTrait` is +/// used to return an appropriate value. +/// 3. [`ResultQuery`](`frame_support::storage::types::ResultQuery`) causes storage map APIs +/// that return a `QueryKind` to instead return a `Result`, with `T` being the value +/// type and `E` being the pallet error type specified by the `#[pallet::error]` attribute. +/// In cases where a value does not exist under a specified storage key, an `Err` with the +/// specified pallet error variant is returned. /// /// NOTE: If the `QueryKind` generic parameter is still generic at this stage or is using some /// type alias then the generation of the getter might fail. In this case the getter can be @@ -1902,60 +2003,62 @@ pub mod pallet_prelude { /// usable at all). We use [`StorageHasher::METADATA`] for the metadata of the hasher of the /// storage item. Thus generic hasher is supported. /// -/// ### Macro expansion +/// ## Macro expansion /// /// For each storage item the macro generates a struct named /// `_GeneratedPrefixForStorage$NameOfStorage`, and implements /// [`StorageInstance`](traits::StorageInstance) on it using the pallet and storage name. It -/// then uses it as the first generic of the aliased type. -/// For `CountedStorageMap`, `CountedStorageMapInstance` is implemented, and another similar -/// struct is generated. +/// then uses it as the first generic of the aliased type. For +/// [`CountedStorageMap`](`pallet_prelude::CountedStorageMap`), +/// [`CountedStorageMapInstance`](`frame_support::storage::types::CountedStorageMapInstance`) +/// is implemented, and another similar struct is generated. /// -/// For named generic, the macro will reorder the generics, and remove the names. +/// For a named generic, the macro will reorder the generics, and remove the names. /// -/// The macro implements the function `storage_metadata` on `Pallet` implementing the metadata -/// for all storage items based on their kind: +/// The macro implements the function `storage_metadata` on the `Pallet` implementing the +/// metadata for all storage items based on their kind: /// * for a storage value, the type of the value is copied into the metadata /// * for a storage map, the type of the values and the key's type is copied into the metadata -/// * for a storage double map, the type of the values, and the types of key1 and key2 are +/// * for a storage double map, the type of the values, and the types of `key1` and `key2` are /// copied into the metadata. /// -/// # Type value: `#[pallet::type_value]` optional +/// # Type value: `#[pallet::type_value]` (optional) +/// +/// The `#[pallet::type_value]` attribute lets you define a struct implementing the +/// [`Get`](crate::traits::Get) trait to ease use of storage types. This attribute is meant to +/// be used alongside [`#[pallet::storage]`](#storage-palletstorage-optional) to define a +/// storage's default value. This attribute can be used multiple times. /// -/// Helper to define a struct implementing `Get` trait. To ease use of storage types. -/// This attribute can be used multiple time. +/// Item must be defined as: /// -/// Item is defined as /// ```ignore /// #[pallet::type_value] /// fn $MyDefaultName<$some_generic>() -> $default_type $optional_where_clause { $expr } /// ``` +/// /// I.e.: a function definition with generics none or `T: Config` and a returned type. /// /// E.g.: +/// /// ```ignore /// #[pallet::type_value] /// fn MyDefault() -> T::Balance { 3.into() } /// ``` /// -/// NOTE: This attribute is meant to be used alongside `#[pallet::storage]` to defined some -/// specific default value in storage. -/// -/// ### Macro expansion -/// -/// Macro renames the function to some internal name, generate a struct with the original name -/// of the function and its generic, and implement `Get<$ReturnType>` by calling the user -/// defined function. +/// Also see [`pallet::type_value`](`frame_support::pallet_macros::type_value`) /// -/// # Genesis config: `#[pallet::genesis_config]` optional +/// # Genesis config: `#[pallet::genesis_config]` (optional) /// -/// Allow to define the genesis configuration of the pallet. +/// The `#[pallet::genesis_config]` attribute allows you to define the genesis configuration +/// for the pallet. /// -/// Item is defined as either an enum or a struct. -/// It needs to be public and implement trait GenesisBuild with `#[pallet::genesis_build]`. -/// The type generics is constrained to be either none, or `T` or `T: Config`. +/// Item is defined as either an enum or a struct. It needs to be public and implement the +/// trait [`GenesisBuild`](`traits::GenesisBuild`) with +/// [`#[pallet::genesis_build]`](#genesis-build-palletgenesis_build-optional). The type +/// generics are constrained to be either none, or `T` or `T: Config`. /// /// E.g: +/// /// ```ignore /// #[pallet::genesis_config] /// pub struct GenesisConfig { @@ -1963,31 +2066,28 @@ pub mod pallet_prelude { /// } /// ``` /// -/// ### Macro expansion +/// Also see [`pallet::genesis_config`](`frame_support::pallet_macros::genesis_config`) /// -/// Macro will add the following attribute on it: -/// * `#[cfg(feature = "std")]` -/// * `#[derive(Serialize, Deserialize)]` -/// * `#[serde(rename_all = "camelCase")]` -/// * `#[serde(deny_unknown_fields)]` -/// * `#[serde(bound(serialize = ""))]` -/// * `#[serde(bound(deserialize = ""))]` +/// # Genesis build: `#[pallet::genesis_build]` (optional) /// -/// # Genesis build: `#[pallet::genesis_build]` optional +/// The `#[pallet::genesis_build]` attribute allows you to define how `genesis_configuration` +/// is built. This takes as input the `GenesisConfig` type (as `self`) and constructs the +/// pallet's initial state. /// -/// Allow to define how genesis_configuration is built. +/// The impl must be defined as: /// -/// Item is defined as /// ```ignore /// #[pallet::genesis_build] /// impl GenesisBuild for GenesisConfig<$maybe_generics> { /// fn build(&self) { $expr } /// } /// ``` -/// I.e. a rust trait implementation with generic `T: Config`, of trait `GenesisBuild` on +/// +/// I.e. a trait implementation with generic `T: Config`, of trait `GenesisBuild` on /// type `GenesisConfig` with generics none or `T`. /// /// E.g.: +/// /// ```ignore /// #[pallet::genesis_build] /// impl GenesisBuild for GenesisConfig { @@ -1995,87 +2095,93 @@ pub mod pallet_prelude { /// } /// ``` /// -/// ### Macro expansion +/// Also see [`pallet::genesis_build`](`frame_support::pallet_macros::genesis_build`) /// -/// Macro will add the following attribute on it: -/// * `#[cfg(feature = "std")]` +/// # Inherent: `#[pallet::inherent]` (optional) /// -/// Macro will implement `sp_runtime::BuildModuleGenesisStorage` using `()` as second generic -/// for non-instantiable pallets. +/// The `#[pallet::inherent]` attribute allows the pallet to provide some +/// [inherent](https://docs.substrate.io/fundamentals/transaction-types/#inherent-transactions). +/// An inherent is some piece of data that is inserted by a block authoring node at block +/// creation time and can either be accepted or rejected by validators based on whether the +/// data falls within an acceptable range. /// -/// # Inherent: `#[pallet::inherent]` optional +/// The most common inherent is the `timestamp` that is inserted into every block. Since there +/// is no way to validate timestamps, validators simply check that the timestamp reported by +/// the block authoring node falls within an acceptable range. /// -/// Allow the pallet to provide some inherent: +/// Item must be defined as: /// -/// Item is defined as: /// ```ignore /// #[pallet::inherent] /// impl ProvideInherent for Pallet { /// // ... regular trait implementation /// } /// ``` -/// I.e. a trait implementation with bound `T: Config`, of trait `ProvideInherent` for type -/// `Pallet`, and some optional where clause. /// -/// ### Macro expansion +/// I.e. a trait implementation with bound `T: Config`, of trait +/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`) for type `Pallet`, and some +/// optional where clause. +/// +/// Also see [`pallet::inherent`](`frame_support::pallet_macros::inherent`) /// -/// Macro make currently no use of this information, but it might use this information in the -/// future to give information directly to construct_runtime. +/// # Validate unsigned: `#[pallet::validate_unsigned]` (optional) /// -/// # Validate unsigned: `#[pallet::validate_unsigned]` optional +/// The `#[pallet::validate_unsigned]` attribute allows the pallet to validate some unsigned +/// transaction: /// -/// Allow the pallet to validate some unsigned transaction: +/// Item must be defined as: /// -/// Item is defined as: /// ```ignore /// #[pallet::validate_unsigned] /// impl ValidateUnsigned for Pallet { /// // ... regular trait implementation /// } /// ``` -/// I.e. a trait implementation with bound `T: Config`, of trait `ValidateUnsigned` for type -/// `Pallet`, and some optional where clause. /// -/// NOTE: There is also `sp_runtime::traits::SignedExtension` that can be used to add some -/// specific logic for transaction validation. +/// I.e. a trait implementation with bound `T: Config`, of trait +/// [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) for type `Pallet`, and some +/// optional where clause. /// -/// ### Macro expansion +/// NOTE: There is also the [`sp_runtime::traits::SignedExtension`] trait that can be used to +/// add some specific logic for transaction validation. /// -/// Macro make currently no use of this information, but it might use this information in the -/// future to give information directly to construct_runtime. +/// Also see [`pallet::validate_unsigned`](`frame_support::pallet_macros::validate_unsigned`) /// -/// # Origin: `#[pallet::origin]` optional +/// # Origin: `#[pallet::origin]` (optional) /// -/// Allow to define some origin for the pallet. +/// The `#[pallet::origin]` attribute allows you to define some origin for the pallet. /// -/// Item must be either a type alias or an enum or a struct. It needs to be public. +/// Item must be either a type alias, an enum, or a struct. It needs to be public. /// /// E.g.: +/// /// ```ignore /// #[pallet::origin] /// pub struct Origin(PhantomData<(T)>); /// ``` /// /// **WARNING**: modifying origin changes the outer runtime origin. This outer runtime origin -/// can be stored on-chain (e.g. in pallet-scheduler), thus any change must be done with care +/// can be stored on-chain (e.g. in `pallet-scheduler`), thus any change must be done with care /// as it might require some migration. /// -/// NOTE: for instantiable pallet, origin must be generic over T and I. +/// NOTE: for instantiable pallets, the origin must be generic over `T` and `I`. /// -/// # General notes on instantiable pallet +/// Also see [`pallet::origin`](`frame_support::pallet_macros::origin`) /// -/// An instantiable pallet is one where Config is generic, i.e. `Config`. This allow runtime -/// to implement multiple instance of the pallet, by using different type for the generic. -/// This is the sole purpose of the generic `I`. -/// But because `PalletInfo` requires `Pallet` placeholder to be static it is important to -/// bound `'static` whenever `PalletInfo` can be used. -/// And in order to have instantiable pallet usable as a regular pallet without instance, it is -/// important to bound `= ()` on every types. +/// # General notes on instantiable pallets /// -/// Thus impl bound look like `impl, I: 'static>`, and types look like +/// An instantiable pallet is one where Config is generic, i.e. `Config`. This allows +/// runtime to implement multiple instances of the pallet, by using different types for the +/// generic. This is the sole purpose of the generic `I`, but because +/// [`PalletInfo`](`traits::PalletInfo`) requires the `Pallet` placeholder to be static, it is +/// important to bound by `'static` whenever [`PalletInfo`](`traits::PalletInfo`) can be used. +/// Additionally, in order to make an instantiable pallet usable as a regular pallet without an +/// instance, it is important to bound by `= ()` on every type. +/// +/// Thus impl bound looks like `impl, I: 'static>`, and types look like /// `SomeType` or `SomeType, I: 'static = ()>`. /// -/// # Example for pallet without instance. +/// # Example of a non-instantiable pallet /// /// ``` /// pub use pallet::*; // reexport in crate namespace for `construct_runtime!` @@ -2269,7 +2375,7 @@ pub mod pallet_prelude { /// } /// ``` /// -/// # Example for pallet with instance. +/// # Example of an instantiable pallet /// /// ``` /// pub use pallet::*; @@ -2400,28 +2506,28 @@ pub mod pallet_prelude { /// } /// ``` /// -/// ## Upgrade guidelines: +/// # Upgrade guidelines /// /// 1. Export the metadata of the pallet for later checks /// - run your node with the pallet active /// - query the metadata using the `state_getMetadata` RPC and curl, or use `subsee -p /// > meta.json` -/// 2. generate the template upgrade for the pallet provided by decl_storage -/// with environment variable `PRINT_PALLET_UPGRADE`: -/// `PRINT_PALLET_UPGRADE=1 cargo check -p my_pallet` This template can be -/// used as information it contains all information for storages, genesis -/// config and genesis build. -/// 3. reorganize pallet to have trait `Config`, `decl_*` macros, `ValidateUnsigned`, -/// `ProvideInherent`, `Origin` all together in one file. Suggested order: -/// * Config, -/// * decl_module, -/// * decl_event, -/// * decl_error, -/// * decl_storage, -/// * origin, -/// * validate_unsigned, -/// * provide_inherent, -/// so far it should compile and all be correct. +/// 2. Generate the template upgrade for the pallet provided by `decl_storage` with the +/// environment variable `PRINT_PALLET_UPGRADE`: `PRINT_PALLET_UPGRADE=1 cargo check -p +/// my_pallet`. This template can be used as it contains all information for storages, +/// genesis config and genesis build. +/// 3. Reorganize the pallet to have the trait `Config`, `decl_*` macros, +/// [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`), +/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`), and Origin` all together in one +/// file. Suggested order: +/// * `Config`, +/// * `decl_module`, +/// * `decl_event`, +/// * `decl_error`, +/// * `decl_storage`, +/// * `origin`, +/// * `validate_unsigned`, +/// * `provide_inherent`, so far it should compile and all be correct. /// 4. start writing the new pallet module /// ```ignore /// pub use pallet::*; @@ -2441,16 +2547,17 @@ pub mod pallet_prelude { /// } /// ``` /// 5. **migrate Config**: move trait into the module with -/// * all const in decl_module to `#[pallet::constant]` -/// * add bound `IsType<::RuntimeEvent>` to `type RuntimeEvent` +/// * all const in `decl_module` to [`#[pallet::constant]`](#palletconstant) +/// * add the bound `IsType<::RuntimeEvent>` to `type +/// RuntimeEvent` /// 7. **migrate decl_module**: write: /// ```ignore /// #[pallet::hooks] /// impl Hooks for Pallet { /// } /// ``` -/// and write inside -/// `on_initialize`, `on_finalize`, `on_runtime_upgrade`, `offchain_worker`, `integrity_test`. +/// and write inside `on_initialize`, `on_finalize`, `on_runtime_upgrade`, +/// `offchain_worker`, and `integrity_test`. /// /// then write: /// ```ignore @@ -2458,25 +2565,26 @@ pub mod pallet_prelude { /// impl Pallet { /// } /// ``` -/// and write inside all the calls in decl_module with a few changes in the signature: -/// - origin must now be written completely, e.g. `origin: OriginFor` -/// - result type must be `DispatchResultWithPostInfo`, you need to write it and also you -/// might -/// need to put `Ok(().into())` at the end or the function. -/// - `#[compact]` must now be written `#[pallet::compact]` -/// - `#[weight = ..]` must now be written `#[pallet::weight(..)]` -/// -/// 7. **migrate event**: -/// rewrite as a simple enum under with the attribute `#[pallet::event]`, -/// use `#[pallet::generate_deposit($vis fn deposit_event)]` to generate deposit_event, -/// 8. **migrate error**: rewrite it with attribute `#[pallet::error]`. -/// 9. **migrate storage**: -/// decl_storage provide an upgrade template (see 3.). All storages, genesis config, genesis -/// build and default implementation of genesis config can be taken from it directly. -/// -/// Otherwise here is the manual process: -/// -/// first migrate the genesis logic. write: +/// and write inside all the calls in `decl_module` with a few changes in the signature: +/// - origin must now be written completely, e.g. `origin: OriginFor` +/// - result type must be `DispatchResultWithPostInfo`, you need to write it and also you +/// might need to put `Ok(().into())` at the end or the function. +/// - `#[compact]` must now be written +/// [`#[pallet::compact]`](#palletcompact-some_arg-some_type) +/// - `#[weight = ..]` must now be written [`#[pallet::weight(..)]`](#palletweightexpr) +/// +/// 7. **migrate event**: rewrite as a simple enum with the attribute +/// [`#[pallet::event]`](#event-palletevent-optional), use [`#[pallet::generate_deposit($vis +/// fn deposit_event)]`](#event-palletevent-optional) to generate `deposit_event`, +/// 8. **migrate error**: rewrite it with attribute +/// [`#[pallet::error]`](#error-palleterror-optional). +/// 9. **migrate storage**: `decl_storage` provide an upgrade template (see 3.). All storages, +/// genesis config, genesis build and default implementation of genesis config can be +/// taken from it directly. +/// +/// Otherwise here is the manual process: +/// +/// first migrate the genesis logic. write: /// ```ignore /// #[pallet::genesis_config] /// struct GenesisConfig { @@ -2494,79 +2602,85 @@ pub mod pallet_prelude { /// } /// } /// ``` -/// for each storages, if it contains config(..) then add a fields, and make its default to the -/// value in `= ..;` or the type default if none, if it contains no build then also add the -/// logic to build the value. -/// for each storages if it contains build(..) then add the logic to genesis_build. -/// -/// NOTE: in decl_storage: is executed first the individual config and build and at the end the -/// add_extra_genesis build -/// -/// Once this is done you can migrate storage individually, a few notes: -/// - for private storage use `pub(crate) type ` or `pub(super) type` or nothing, -/// - for storage with `get(fn ..)` use `#[pallet::getter(fn ...)]` -/// - for storage with value being `Option<$something>` make generic `Value` being -/// `$something` -/// and generic `QueryKind` being `OptionQuery` (note: this is default). Otherwise make -/// `Value` the complete value type and `QueryKind` being `ValueQuery`. -/// - for storage with default value: `= $expr;` provide some specific OnEmpty generic. To do -/// so -/// use of `#[pallet::type_value]` to generate the wanted struct to put. -/// example: `MyStorage: u32 = 3u32` would be written: -/// ```ignore +/// for each storage, if it contains `config(..)` then add fields, and make it default to +/// the value in `= ..;` or the type default if none, if it contains no build then also add +/// the logic to build the value. for each storage if it contains `build(..)` then add the +/// logic to `genesis_build`. +/// +/// NOTE: within `decl_storage`: the individual config is executed first, followed by the +/// build and finally the `add_extra_genesis` build. +/// +/// Once this is done you can migrate storages individually, a few notes: +/// - for private storage use `pub(crate) type ` or `pub(super) type` or nothing, +/// - for storages with `get(fn ..)` use [`#[pallet::getter(fn +/// ...)]`](#palletgetterfn-my_getter_fn_name-optional) +/// - for storages with value being `Option<$something>` make generic `Value` being +/// `$something` and generic `QueryKind` being `OptionQuery` (note: this is default). +/// Otherwise make `Value` the complete value type and `QueryKind` being `ValueQuery`. +/// - for storages with default value: `= $expr;` provide some specific `OnEmpty` generic. +/// To do so use of `#[pallet::type_value]` to generate the wanted struct to put. +/// example: `MyStorage: u32 = 3u32` would be written: +/// +/// ```ignore /// #[pallet::type_value] fn MyStorageOnEmpty() -> u32 { 3u32 } /// #[pallet::storage] /// pub(super) type MyStorage = StorageValue<_, u32, ValueQuery, MyStorageOnEmpty>; /// ``` /// -/// NOTE: `decl_storage` also generates functions `assimilate_storage` and `build_storage` -/// directly on GenesisConfig, those are sometimes used in tests. In order not to break they -/// can be implemented manually, one can implement those functions by calling `GenesisBuild` -/// implementation. -/// -/// 10. **migrate origin**: move the origin to the pallet module under `#[pallet::origin]` -/// 11. **migrate validate_unsigned**: move the `ValidateUnsigned` implementation to the pallet -/// module under `#[pallet::validate_unsigned]` -/// 12. **migrate provide_inherent**: move the `ProvideInherent` implementation to the pallet -/// module under `#[pallet::inherent]` +/// NOTE: `decl_storage` also generates the functions `assimilate_storage` and +/// `build_storage` directly on `GenesisConfig`, and these are sometimes used in tests. +/// In order not to break they can be implemented manually, one can implement those +/// functions by calling the `GenesisBuild` implementation. +/// 10. **migrate origin**: move the origin to the pallet module to be under a +/// [`#[pallet::origin]`](#origin-palletorigin-optional) attribute +/// 11. **migrate validate_unsigned**: move the +/// [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) implementation to the pallet +/// module under a +/// [`#[pallet::validate_unsigned]`](#validate-unsigned-palletvalidate_unsigned-optional) +/// attribute +/// 12. **migrate provide_inherent**: move the +/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`) implementation to the pallet +/// module under a [`#[pallet::inherent]`](#inherent-palletinherent-optional) attribute /// 13. rename the usage of `Module` to `Pallet` inside the crate. -/// 14. migration is done, now double check migration with the checking migration guidelines. +/// 14. migration is done, now double check the migration with the checking migration +/// guidelines shown below. /// -/// ## Checking upgrade guidelines: +/// # Checking upgrade guidelines: /// /// * compare metadata. Use [subsee](https://github.com/ascjones/subsee) to fetch the metadata -/// and do a diff of the resulting json before and after migration. This checks for: -/// * call, names, signature, docs -/// * event names, docs -/// * error names, docs -/// * storage names, hasher, prefixes, default value -/// * error , error, constant, +/// and do a diff of the resulting json before and after migration. This checks for: +/// * call, names, signature, docs +/// * event names, docs +/// * error names, docs +/// * storage names, hasher, prefixes, default value +/// * error, error, constant /// * manually check that: -/// * `Origin` is moved inside the macro under `#[pallet::origin]` if it exists -/// * `ValidateUnsigned` is moved inside the macro under `#[pallet::validate_unsigned)]` if it -/// exists -/// * `ProvideInherent` is moved inside macro under `#[pallet::inherent)]` if it exists -/// * `on_initialize`/`on_finalize`/`on_runtime_upgrade`/`offchain_worker` are moved to -/// `Hooks` -/// implementation -/// * storages with `config(..)` are converted to `GenesisConfig` field, and their default is -/// `= $expr;` if the storage have default value -/// * storages with `build($expr)` or `config(..)` are built in `GenesisBuild::build` -/// * `add_extra_genesis` fields are converted to `GenesisConfig` field with their correct -/// default if specified -/// * `add_extra_genesis` build is written into `GenesisBuild::build` +/// * `Origin` was moved inside the macro under +/// [`#[pallet::origin]`](#origin-palletorigin-optional) if it exists +/// * [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) was moved inside the macro +/// under +/// [`#[pallet::validate_unsigned)]`](#validate-unsigned-palletvalidate_unsigned-optional) +/// if it exists +/// * [`ProvideInherent`](`pallet_prelude::ProvideInherent`) was moved inside the macro +/// under [`#[pallet::inherent)]`](#inherent-palletinherent-optional) if it exists +/// * `on_initialize` / `on_finalize` / `on_runtime_upgrade` / `offchain_worker` were moved +/// to the `Hooks` implementation +/// * storages with `config(..)` were converted to `GenesisConfig` field, and their default +/// is `= $expr;` if the storage has a default value +/// * storages with `build($expr)` or `config(..)` were built in `GenesisBuild::build` +/// * `add_extra_genesis` fields were converted to `GenesisConfig` field with their correct +/// default if specified +/// * `add_extra_genesis` build was written into `GenesisBuild::build` /// * storage items defined with [`pallet`] use the name of the pallet provided by -/// [`traits::PalletInfo::name`] as `pallet_prefix` (in `decl_storage`, storage items used the -/// `pallet_prefix` given as input of `decl_storage` with the syntax `as Example`). -/// Thus a runtime using the pallet must be careful with this change. -/// To handle this change: -/// * either ensure that the name of the pallet given to `construct_runtime!` is the same -/// as the name the pallet was giving to `decl_storage`, -/// * or do a storage migration from the old prefix used to the new prefix used. -/// -/// NOTE: The prefixes used by storage items are in the metadata. Thus, ensuring the metadata -/// hasn't changed does ensure that the `pallet_prefix`s used by the storage items haven't -/// changed. +/// [`traits::PalletInfo::name`] as `pallet_prefix` (in `decl_storage`, storage items used +/// the `pallet_prefix` given as input of `decl_storage` with the syntax `as Example`). Thus +/// a runtime using the pallet must be careful with this change. To handle this change: +/// * either ensure that the name of the pallet given to `construct_runtime!` is the same +/// as the name the pallet was giving to `decl_storage`, +/// * or do a storage migration from the old prefix used to the new prefix used. +/// +/// NOTE: The prefixes used by storage items are in metadata. Thus, ensuring the metadata +/// hasn't changed ensures that the `pallet_prefix`s used by the storage items haven't changed. /// /// # Notes when macro fails to show proper error message spans: /// @@ -2581,3 +2695,13 @@ pub mod pallet_prelude { /// ``` /// * use the newest nightly possible. pub use frame_support_procedural::pallet; + +/// Contains macro stubs for all of the pallet:: macros +pub mod pallet_macros { + pub use frame_support_procedural::{ + call_index, compact, config, constant, disable_frame_system_supertrait_check, error, event, + extra_constants, generate_deposit, generate_storage_info, generate_store, genesis_build, + genesis_config, getter, hooks, inherent, origin, storage, storage_prefix, storage_version, + type_value, unbounded, validate_unsigned, weight, whitelist_storage, + }; +} From 4a5a9dea00c9b4e4d34ff56368451aa4dac09d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 7 Oct 2022 12:46:57 +0200 Subject: [PATCH 1247/1472] Upgrade pin-project (#12426) This fixes some warnings on latest nightly. --- Cargo.lock | 8 ++++---- client/network/Cargo.toml | 2 +- client/network/transactions/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- client/telemetry/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a6a7c09514325..6cb440433f204 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6805,18 +6805,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 8e3d68851c423..08d0f28394af0 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -32,7 +32,7 @@ linked-hash-map = "0.5.4" log = "0.4.17" lru = "0.7.5" parking_lot = "0.12.1" -pin-project = "1.0.10" +pin-project = "1.0.12" prost = "0.11" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml index 5578bb2c7191e..3b60497d42b9b 100644 --- a/client/network/transactions/Cargo.toml +++ b/client/network/transactions/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3.21" hex = "0.4.0" libp2p = "0.46.1" log = "0.4.17" -pin-project = "1.0.10" +pin-project = "1.0.12" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } sc-network-common = { version = "0.10.0-dev", path = "../common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 42bd2ae7276e2..308da96fbbe77 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -31,7 +31,7 @@ parking_lot = "0.12.1" log = "0.4.17" futures-timer = "3.0.1" exit-future = "0.2.0" -pin-project = "1.0.10" +pin-project = "1.0.12" hash-db = "0.15.2" serde = "1.0.136" serde_json = "1.0.85" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 4be7c186720fc..0be1268e13d43 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.21" libp2p = { version = "0.46.1", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.17" parking_lot = "0.12.1" -pin-project = "1.0.10" +pin-project = "1.0.12" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" From a8e951d094273322e79f4ac8b66dd3715fd5c076 Mon Sep 17 00:00:00 2001 From: Koute Date: Fri, 7 Oct 2022 23:16:41 +0900 Subject: [PATCH 1248/1472] Extend the lower bounds of some of the benchmarks to also include `0` (#12386) * Extend the lower bounds of some of the benchmarks to also include `0` * Fix verify snippet for `pallet_bounties/spend_funds` --- frame/alliance/src/benchmarking.rs | 8 +- frame/benchmarking/src/baseline.rs | 2 +- frame/bounties/src/benchmarking.rs | 10 ++- frame/collective/src/benchmarking.rs | 77 ++++++++++---------- frame/elections-phragmen/src/benchmarking.rs | 2 +- frame/examples/basic/src/benchmarking.rs | 8 +- frame/gilt/src/benchmarking.rs | 4 +- frame/identity/src/benchmarking.rs | 24 +++--- frame/ranked-collective/src/benchmarking.rs | 2 +- frame/staking/src/benchmarking.rs | 11 +-- frame/system/benchmarking/src/lib.rs | 51 ++++++++----- 11 files changed, 109 insertions(+), 90 deletions(-) diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index e07d7c44a97ff..e2e1579fcc9b4 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -832,8 +832,8 @@ benchmarks_instance_pallet! { } add_unscrupulous_items { - let n in 1 .. T::MaxUnscrupulousItems::get(); - let l in 1 .. T::MaxWebsiteUrlLength::get(); + let n in 0 .. T::MaxUnscrupulousItems::get(); + let l in 0 .. T::MaxWebsiteUrlLength::get(); set_members::(); @@ -856,8 +856,8 @@ benchmarks_instance_pallet! { } remove_unscrupulous_items { - let n in 1 .. T::MaxUnscrupulousItems::get(); - let l in 1 .. T::MaxWebsiteUrlLength::get(); + let n in 0 .. T::MaxUnscrupulousItems::get(); + let l in 0 .. T::MaxWebsiteUrlLength::get(); set_members::(); diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 6a310330cafb1..5fd845551daca 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -90,7 +90,7 @@ benchmarks! { } sr25519_verification { - let i in 1 .. 100; + let i in 0 .. 100; let public = SignerId::generate_pair(None); diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 6ccd587cebc10..07dd781c29af3 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -197,7 +197,7 @@ benchmarks_instance_pallet! { } spend_funds { - let b in 1 .. 100; + let b in 0 .. 100; setup_pot_account::(); create_approved_bounties::(b)?; @@ -214,9 +214,13 @@ benchmarks_instance_pallet! { ); } verify { - ensure!(budget_remaining < BalanceOf::::max_value(), "Budget not used"); ensure!(missed_any == false, "Missed some"); - assert_last_event::(Event::BountyBecameActive { index: b - 1 }.into()) + if b > 0 { + ensure!(budget_remaining < BalanceOf::::max_value(), "Budget not used"); + assert_last_event::(Event::BountyBecameActive { index: b - 1 }.into()) + } else { + ensure!(budget_remaining == BalanceOf::::max_value(), "Budget used"); + } } impl_benchmark_test_suite!(Bounties, crate::tests::new_test_ext(), crate::tests::Test) diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index 7c444dbaa7b6a..fcebacf5762e7 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -36,68 +36,69 @@ fn assert_last_event, I: 'static>(generic_event: >:: benchmarks_instance_pallet! { set_members { - let m in 1 .. T::MaxMembers::get(); - let n in 1 .. T::MaxMembers::get(); - let p in 1 .. T::MaxProposals::get(); + let m in 0 .. T::MaxMembers::get(); + let n in 0 .. T::MaxMembers::get(); + let p in 0 .. T::MaxProposals::get(); // Set old members. // We compute the difference of old and new members, so it should influence timing. let mut old_members = vec![]; - let mut last_old_member = account::("old member", 0, SEED); for i in 0 .. m { - last_old_member = account::("old member", i, SEED); - old_members.push(last_old_member.clone()); + let old_member = account::("old member", i, SEED); + old_members.push(old_member); } let old_members_count = old_members.len() as u32; Collective::::set_members( SystemOrigin::Root.into(), old_members.clone(), - Some(last_old_member.clone()), + old_members.last().cloned(), T::MaxMembers::get(), )?; - // Set a high threshold for proposals passing so that they stay around. - let threshold = m.max(2); - // Length of the proposals should be irrelevant to `set_members`. - let length = 100; - for i in 0 .. p { - // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = SystemCall::::remark { - remark: vec![i as u8; length] - }.into(); - Collective::::propose( - SystemOrigin::Signed(last_old_member.clone()).into(), - threshold, - Box::new(proposal.clone()), - MAX_BYTES, - )?; - let hash = T::Hashing::hash_of(&proposal); - // Vote on the proposal to increase state relevant for `set_members`. - // Not voting for `last_old_member` because they proposed and not voting for the first member - // to keep the proposal from passing. - for j in 2 .. m - 1 { - let voter = &old_members[j as usize]; - let approve = true; - Collective::::vote( - SystemOrigin::Signed(voter.clone()).into(), - hash, - i, - approve, + // If there were any old members generate a bunch of proposals. + if m > 0 { + // Set a high threshold for proposals passing so that they stay around. + let threshold = m.max(2); + // Length of the proposals should be irrelevant to `set_members`. + let length = 100; + for i in 0 .. p { + // Proposals should be different so that different proposal hashes are generated + let proposal: T::Proposal = SystemCall::::remark { + remark: vec![i as u8; length] + }.into(); + Collective::::propose( + SystemOrigin::Signed(old_members.last().unwrap().clone()).into(), + threshold, + Box::new(proposal.clone()), + MAX_BYTES, )?; + let hash = T::Hashing::hash_of(&proposal); + // Vote on the proposal to increase state relevant for `set_members`. + // Not voting for last old member because they proposed and not voting for the first member + // to keep the proposal from passing. + for j in 2 .. m - 1 { + let voter = &old_members[j as usize]; + let approve = true; + Collective::::vote( + SystemOrigin::Signed(voter.clone()).into(), + hash, + i, + approve, + )?; + } } } // Construct `new_members`. // It should influence timing since it will sort this vector. let mut new_members = vec![]; - let mut last_member = account::("member", 0, SEED); for i in 0 .. n { - last_member = account::("member", i, SEED); - new_members.push(last_member.clone()); + let member = account::("member", i, SEED); + new_members.push(member); } - }: _(SystemOrigin::Root, new_members.clone(), Some(last_member), T::MaxMembers::get()) + }: _(SystemOrigin::Root, new_members.clone(), new_members.last().cloned(), T::MaxMembers::get()) verify { new_members.sort(); assert_eq!(Collective::::members(), new_members); diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 22d00a912a4f7..06ac8d7c60162 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -362,7 +362,7 @@ benchmarks! { // total number of voters. let v in (T::MaxVoters::get() / 2) .. T::MaxVoters::get(); // those that are defunct and need removal. - let d in 1 .. (T::MaxVoters::get() / 2); + let d in 0 .. (T::MaxVoters::get() / 2); // remove any previous stuff. clean::(); diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index 93e14f358208e..4d1659af46460 100644 --- a/frame/examples/basic/src/benchmarking.rs +++ b/frame/examples/basic/src/benchmarking.rs @@ -34,22 +34,22 @@ use frame_system::RawOrigin; // Details on using the benchmarks macro can be seen at: // https://paritytech.github.io/substrate/master/frame_benchmarking/trait.Benchmarking.html#tymethod.benchmarks benchmarks! { - // This will measure the execution time of `set_dummy` for b in [1..1000] range. + // This will measure the execution time of `set_dummy` for b in [0..1000] range. set_dummy_benchmark { // This is the benchmark setup phase - let b in 1 .. 1000; + let b in 0 .. 1000; }: set_dummy(RawOrigin::Root, b.into()) // The execution phase is just running `set_dummy` extrinsic call verify { // This is the optional benchmark verification phase, asserting certain states. assert_eq!(Pallet::::dummy(), Some(b.into())) } - // This will measure the execution time of `accumulate_dummy` for b in [1..1000] range. + // This will measure the execution time of `accumulate_dummy` for b in [0..1000] range. // The benchmark execution phase is shorthanded. When the name of the benchmark case is the same // as the extrinsic call. `_(...)` is used to represent the extrinsic name. // The benchmark verification phase is omitted. accumulate_dummy { - let b in 1 .. 1000; + let b in 0 .. 1000; // The caller account is whitelisted for DB reads/write by the benchmarking macro. let caller: T::AccountId = whitelisted_caller(); }: _(RawOrigin::Signed(caller), b.into()) diff --git a/frame/gilt/src/benchmarking.rs b/frame/gilt/src/benchmarking.rs index 1767a8da4def0..92ebf81854f23 100644 --- a/frame/gilt/src/benchmarking.rs +++ b/frame/gilt/src/benchmarking.rs @@ -97,7 +97,7 @@ benchmarks! { pursue_target_per_item { // bids taken - let b in 1..T::MaxQueueLen::get(); + let b in 0..T::MaxQueueLen::get(); let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, T::MinFreeze::get() * BalanceOf::::from(b + 1)); @@ -113,7 +113,7 @@ benchmarks! { pursue_target_per_queue { // total queues hit - let q in 1..T::QueueCount::get(); + let q in 0..T::QueueCount::get(); let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, T::MinFreeze::get() * BalanceOf::::from(q + 1)); diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index c66658b92b0d2..c628387a4d22e 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -130,7 +130,7 @@ benchmarks! { set_identity { let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let x in 1 .. T::MaxAdditionalFields::get(); + let x in 0 .. T::MaxAdditionalFields::get(); let caller = { // The target user let caller: T::AccountId = whitelisted_caller(); @@ -166,7 +166,7 @@ benchmarks! { set_subs_new { let caller: T::AccountId = whitelisted_caller(); // Create a new subs vec with s sub accounts - let s in 1 .. T::MaxSubAccounts::get() => (); + let s in 0 .. T::MaxSubAccounts::get() => (); let subs = create_sub_accounts::(&caller, s)?; ensure!(SubsOf::::get(&caller).1.len() == 0, "Caller already has subs"); }: set_subs(RawOrigin::Signed(caller.clone()), subs) @@ -177,7 +177,7 @@ benchmarks! { set_subs_old { let caller: T::AccountId = whitelisted_caller(); // Give them p many previous sub accounts. - let p in 1 .. T::MaxSubAccounts::get() => { + let p in 0 .. T::MaxSubAccounts::get() => { let _ = add_sub_accounts::(&caller, p)?; }; // Remove all subs. @@ -198,12 +198,12 @@ benchmarks! { let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let s in 1 .. T::MaxSubAccounts::get() => { + let s in 0 .. T::MaxSubAccounts::get() => { // Give them s many sub accounts let caller: T::AccountId = whitelisted_caller(); let _ = add_sub_accounts::(&caller, s)?; }; - let x in 1 .. T::MaxAdditionalFields::get(); + let x in 0 .. T::MaxAdditionalFields::get(); // Create their main identity with x additional fields let info = create_identity_info::(x); @@ -233,7 +233,7 @@ benchmarks! { let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let x in 1 .. T::MaxAdditionalFields::get() => { + let x in 0 .. T::MaxAdditionalFields::get() => { // Create their main identity with x additional fields let info = create_identity_info::(x); let caller: T::AccountId = whitelisted_caller(); @@ -251,7 +251,7 @@ benchmarks! { let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let x in 1 .. T::MaxAdditionalFields::get() => { + let x in 0 .. T::MaxAdditionalFields::get() => { // Create their main identity with x additional fields let info = create_identity_info::(x); let caller: T::AccountId = whitelisted_caller(); @@ -332,7 +332,7 @@ benchmarks! { let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - let x in 1 .. T::MaxAdditionalFields::get(); + let x in 0 .. T::MaxAdditionalFields::get(); let info = create_identity_info::(x); let info_hash = T::Hashing::hash_of(&info); @@ -348,8 +348,8 @@ benchmarks! { kill_identity { let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let s in 1 .. T::MaxSubAccounts::get(); - let x in 1 .. T::MaxAdditionalFields::get(); + let s in 0 .. T::MaxSubAccounts::get(); + let x in 0 .. T::MaxAdditionalFields::get(); let target: T::AccountId = account("target", 0, SEED); let target_origin: ::RuntimeOrigin = RawOrigin::Signed(target.clone()).into(); @@ -379,7 +379,7 @@ benchmarks! { } add_sub { - let s in 1 .. T::MaxSubAccounts::get() - 1; + let s in 0 .. T::MaxSubAccounts::get() - 1; let caller: T::AccountId = whitelisted_caller(); let _ = add_sub_accounts::(&caller, s)?; @@ -415,7 +415,7 @@ benchmarks! { } quit_sub { - let s in 1 .. T::MaxSubAccounts::get() - 1; + let s in 0 .. T::MaxSubAccounts::get() - 1; let caller: T::AccountId = whitelisted_caller(); let sup = account("super", 0, SEED); diff --git a/frame/ranked-collective/src/benchmarking.rs b/frame/ranked-collective/src/benchmarking.rs index a4d074450e836..eb629b330abb2 100644 --- a/frame/ranked-collective/src/benchmarking.rs +++ b/frame/ranked-collective/src/benchmarking.rs @@ -138,7 +138,7 @@ benchmarks_instance_pallet! { } cleanup_poll { - let n in 1 .. 100; + let n in 0 .. 100; // Create a poll let class = T::Polls::classes().into_iter().next().unwrap(); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index c7e6936ac75d8..dcb861e2ce419 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -88,6 +88,7 @@ pub fn create_validator_with_nominators( points_total += 10; points_individual.push((v_stash.clone(), 10)); + let original_nominator_count = Nominators::::count(); let mut nominators = Vec::new(); // Give the validator n nominators, but keep total users in the system the same. @@ -114,7 +115,7 @@ pub fn create_validator_with_nominators( assert_eq!(new_validators.len(), 1); assert_eq!(new_validators[0], v_stash, "Our validator was not selected!"); assert_ne!(Validators::::count(), 0); - assert_ne!(Nominators::::count(), 0); + assert_eq!(Nominators::::count(), original_nominator_count + nominators.len() as u32); // Give Era Points let reward = EraRewardPoints:: { @@ -544,7 +545,7 @@ benchmarks! { } payout_stakers_dead_controller { - let n in 1 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, T::MaxNominatorRewardedPerValidator::get() as u32, @@ -577,7 +578,7 @@ benchmarks! { } payout_stakers_alive_staked { - let n in 1 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, T::MaxNominatorRewardedPerValidator::get() as u32, @@ -695,7 +696,7 @@ benchmarks! { new_era { let v in 1 .. 10; - let n in 1 .. 100; + let n in 0 .. 100; create_validators_with_nominators_for_era::( v, @@ -714,7 +715,7 @@ benchmarks! { #[extra] payout_all { let v in 1 .. 10; - let n in 1 .. 100; + let n in 0 .. 100; create_validators_with_nominators_for_era::( v, n, diff --git a/frame/system/benchmarking/src/lib.rs b/frame/system/benchmarking/src/lib.rs index dbe38da5775a7..0f7603fe1dd9f 100644 --- a/frame/system/benchmarking/src/lib.rs +++ b/frame/system/benchmarking/src/lib.rs @@ -64,7 +64,7 @@ benchmarks! { #[skip_meta] set_storage { - let i in 1 .. 1000; + let i in 0 .. 1000; // Set up i items to add let mut items = Vec::new(); @@ -72,56 +72,69 @@ benchmarks! { let hash = (i, j).using_encoded(T::Hashing::hash).as_ref().to_vec(); items.push((hash.clone(), hash.clone())); } + + let items_to_verify = items.clone(); }: _(RawOrigin::Root, items) verify { - let last_hash = (i, i - 1).using_encoded(T::Hashing::hash); - let value = storage::unhashed::get_raw(last_hash.as_ref()).ok_or("No value stored")?; - assert_eq!(value, last_hash.as_ref().to_vec()); + // Verify that they're actually in the storage. + for (item, _) in items_to_verify { + let value = storage::unhashed::get_raw(&item).ok_or("No value stored")?; + assert_eq!(value, *item); + } } #[skip_meta] kill_storage { - let i in 1 .. 1000; + let i in 0 .. 1000; // Add i items to storage - let mut items = Vec::new(); + let mut items = Vec::with_capacity(i as usize); for j in 0 .. i { let hash = (i, j).using_encoded(T::Hashing::hash).as_ref().to_vec(); storage::unhashed::put_raw(&hash, &hash); items.push(hash); } - // We will verify this value is removed - let last_hash = (i, i - 1).using_encoded(T::Hashing::hash); - let value = storage::unhashed::get_raw(last_hash.as_ref()).ok_or("No value stored")?; - assert_eq!(value, last_hash.as_ref().to_vec()); + // Verify that they're actually in the storage. + for item in &items { + let value = storage::unhashed::get_raw(item).ok_or("No value stored")?; + assert_eq!(value, *item); + } + let items_to_verify = items.clone(); }: _(RawOrigin::Root, items) verify { - assert_eq!(storage::unhashed::get_raw(last_hash.as_ref()), None); + // Verify that they're not in the storage anymore. + for item in items_to_verify { + assert!(storage::unhashed::get_raw(&item).is_none()); + } } #[skip_meta] kill_prefix { - let p in 1 .. 1000; + let p in 0 .. 1000; let prefix = p.using_encoded(T::Hashing::hash).as_ref().to_vec(); + let mut items = Vec::with_capacity(p as usize); // add p items that share a prefix for i in 0 .. p { let hash = (p, i).using_encoded(T::Hashing::hash).as_ref().to_vec(); let key = [&prefix[..], &hash[..]].concat(); storage::unhashed::put_raw(&key, &key); + items.push(key); } - // We will verify this value is removed - let last_hash = (p, p - 1).using_encoded(T::Hashing::hash).as_ref().to_vec(); - let last_key = [&prefix[..], &last_hash[..]].concat(); - let value = storage::unhashed::get_raw(&last_key).ok_or("No value stored")?; - assert_eq!(value, last_key); - + // Verify that they're actually in the storage. + for item in &items { + let value = storage::unhashed::get_raw(item).ok_or("No value stored")?; + assert_eq!(value, *item); + } }: _(RawOrigin::Root, prefix, p) verify { - assert_eq!(storage::unhashed::get_raw(&last_key), None); + // Verify that they're not in the storage anymore. + for item in items { + assert!(storage::unhashed::get_raw(&item).is_none()); + } } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); From 1a5cdc81c711bc3a7464f24ccd2e1ba20a5ea594 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Fri, 7 Oct 2022 17:19:10 +0300 Subject: [PATCH 1249/1472] BEEFY: Define a `BeefyVerify` trait for signatures (#12299) * Define CustomVerify trait Signed-off-by: Serban Iorga * Use ECDSA CustomVerify for MultiSignature Signed-off-by: Serban Iorga * beefy: small simplifications Signed-off-by: Serban Iorga * Revert "Use ECDSA CustomVerify for MultiSignature" This reverts commit 136cff82505662dd92c864491814629d2bc349f0. * Revert "Define CustomVerify trait" This reverts commit adf91e9e6d1bdea6f00831f6067b74c3d945f9a2. * Define BeefyAuthorityId and BeefyVerify traits * Improve BeefyVerify unit tests Co-authored-by: Robert Hambrock * fmt & import sp_core::blake2_256 * Renamings * remove SignerToAccountId * fix Signed-off-by: Serban Iorga Co-authored-by: Robert Hambrock --- Cargo.lock | 1 + client/beefy/src/keystore.rs | 9 ++--- frame/beefy-mmr/src/lib.rs | 8 +--- primitives/beefy/Cargo.toml | 2 + primitives/beefy/src/lib.rs | 75 ++++++++++++++++++++++++++++++++++- primitives/core/src/crypto.rs | 5 +++ 6 files changed, 87 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6cb440433f204..49b3dd3cf957b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -538,6 +538,7 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-core", + "sp-io", "sp-keystore", "sp-mmr-primitives", "sp-runtime", diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index b0259a42075ea..886c00fc5d817 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -19,12 +19,13 @@ use sp_application_crypto::RuntimeAppPublic; use sp_core::keccak_256; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_runtime::traits::Keccak256; use log::warn; use beefy_primitives::{ crypto::{Public, Signature}, - KEY_TYPE, + BeefyVerify, KEY_TYPE, }; use crate::error; @@ -98,11 +99,7 @@ impl BeefyKeystore { /// /// Return `true` if the signature is authentic, `false` otherwise. pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool { - let msg = keccak_256(message); - let sig = sig.as_ref(); - let public = public.as_ref(); - - sp_core::ecdsa::Pair::verify_prehashed(sig, &msg, public) + BeefyVerify::::verify(sig, message, public) } } diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 5b82c89ce84b6..0b7fc22cd279b 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -73,12 +73,8 @@ where /// Convert BEEFY secp256k1 public keys into Ethereum addresses pub struct BeefyEcdsaToEthereum; impl Convert> for BeefyEcdsaToEthereum { - fn convert(a: beefy_primitives::crypto::AuthorityId) -> Vec { - sp_core::ecdsa::Public::try_from(a.as_ref()) - .map_err(|_| { - log::error!(target: "runtime::beefy", "Invalid BEEFY PublicKey format!"); - }) - .unwrap_or(sp_core::ecdsa::Public::from_raw([0u8; 33])) + fn convert(beefy_id: beefy_primitives::crypto::AuthorityId) -> Vec { + sp_core::ecdsa::Public::from(beefy_id) .to_eth_address() .map(|v| v.to_vec()) .map_err(|_| { diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index fe6ce23337c86..f85e2edf4f442 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -18,6 +18,7 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-io = { version = "6.0.0", default-features = false, path = "../io" } sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../merkle-mountain-range" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } @@ -34,6 +35,7 @@ std = [ "sp-api/std", "sp-application-crypto/std", "sp-core/std", + "sp-io/std", "sp-mmr-primitives/std", "sp-runtime/std", "sp-std/std", diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index 705366e1b4778..453eb67315d4e 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -41,12 +41,30 @@ pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; use codec::{Codec, Decode, Encode}; use scale_info::TypeInfo; +use sp_application_crypto::RuntimeAppPublic; use sp_core::H256; +use sp_runtime::traits::Hash; use sp_std::prelude::*; /// Key type for BEEFY module. pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"beef"); +/// Trait representing BEEFY authority id. +pub trait BeefyAuthorityId: RuntimeAppPublic {} + +/// Means of verification for a BEEFY authority signature. +/// +/// Accepts custom hashing fn for the message and custom convertor fn for the signer. +pub trait BeefyVerify { + /// Type of the signer. + type Signer: BeefyAuthorityId; + + /// Verify a signature. + /// + /// Return `true` if signature is valid for the value. + fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool; +} + /// BEEFY cryptographic types /// /// This module basically introduces three crypto types: @@ -60,7 +78,9 @@ pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::Ke /// The current underlying crypto scheme used is ECDSA. This can be changed, /// without affecting code restricted against the above listed crypto types. pub mod crypto { + use super::{BeefyAuthorityId, BeefyVerify, Hash}; use sp_application_crypto::{app_crypto, ecdsa}; + use sp_core::crypto::Wraps; app_crypto!(ecdsa, crate::KEY_TYPE); /// Identity of a BEEFY authority using ECDSA as its crypto. @@ -68,6 +88,26 @@ pub mod crypto { /// Signature for a BEEFY authority using ECDSA as its crypto. pub type AuthoritySignature = Signature; + + impl BeefyAuthorityId for AuthorityId {} + + impl BeefyVerify for AuthoritySignature + where + ::Output: Into<[u8; 32]>, + { + type Signer = AuthorityId; + + fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool { + let msg_hash = ::hash(msg).into(); + match sp_io::crypto::secp256k1_ecdsa_recover_compressed( + self.as_inner_ref().as_ref(), + &msg_hash, + ) { + Ok(raw_pubkey) => raw_pubkey.as_ref() == AsRef::<[u8]>::as_ref(signer), + _ => false, + } + } + } } /// The `ConsensusEngineId` of BEEFY. @@ -180,7 +220,8 @@ sp_api::decl_runtime_apis! { mod tests { use super::*; use sp_application_crypto::ecdsa::{self, Public}; - use sp_core::Pair; + use sp_core::{blake2_256, crypto::Wraps, keccak_256, Pair}; + use sp_runtime::traits::{BlakeTwo256, Keccak256}; #[test] fn validator_set() { @@ -194,4 +235,36 @@ mod tests { assert_eq!(validators.id(), set_id); assert_eq!(validators.validators(), &vec![alice.public()]); } + + #[test] + fn beefy_verify_works() { + let msg = &b"test-message"[..]; + let (pair, _) = crypto::Pair::generate(); + + let keccak_256_signature: crypto::Signature = + pair.as_inner_ref().sign_prehashed(&keccak_256(msg)).into(); + + let blake2_256_signature: crypto::Signature = + pair.as_inner_ref().sign_prehashed(&blake2_256(msg)).into(); + + // Verification works if same hashing function is used when signing and verifying. + assert!(BeefyVerify::::verify(&keccak_256_signature, msg, &pair.public())); + assert!(BeefyVerify::::verify(&blake2_256_signature, msg, &pair.public())); + // Verification fails if distinct hashing functions are used when signing and verifying. + assert!(!BeefyVerify::::verify(&blake2_256_signature, msg, &pair.public())); + assert!(!BeefyVerify::::verify(&keccak_256_signature, msg, &pair.public())); + + // Other public key doesn't work + let (other_pair, _) = crypto::Pair::generate(); + assert!(!BeefyVerify::::verify( + &keccak_256_signature, + msg, + &other_pair.public() + )); + assert!(!BeefyVerify::::verify( + &blake2_256_signature, + msg, + &other_pair.public() + )); + } } diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index db855620a8f0d..06703acea7202 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -984,6 +984,11 @@ pub trait IsWrappedBy: From + Into { pub trait Wraps: Sized { /// The inner type it is wrapping. type Inner: IsWrappedBy; + + /// Get a reference to the inner type that is wrapped. + fn as_inner_ref(&self) -> &Self::Inner { + Self::Inner::from_ref(self) + } } impl IsWrappedBy for T From b7c05622d0912816ac055fe086769f1e2fce575d Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Sat, 8 Oct 2022 13:26:31 -0600 Subject: [PATCH 1250/1472] fix comment math (#12452) --- frame/ranked-collective/src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index fa3a473fe7d73..111c5f70efdfa 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -199,11 +199,11 @@ impl Convert for Unit { /// Vote-weight scheme where all voters get one vote plus an additional vote for every excess rank /// they have. I.e.: /// -/// - Each member with no excess rank gets 1 vote; +/// - Each member with an excess rank of 0 gets 1 vote; /// - ...with an excess rank of 1 gets 2 votes; -/// - ...with an excess rank of 2 gets 2 votes; -/// - ...with an excess rank of 3 gets 3 votes; -/// - ...with an excess rank of 4 gets 4 votes. +/// - ...with an excess rank of 2 gets 3 votes; +/// - ...with an excess rank of 3 gets 4 votes; +/// - ...with an excess rank of 4 gets 5 votes. pub struct Linear; impl Convert for Linear { fn convert(r: Rank) -> Votes { @@ -214,11 +214,11 @@ impl Convert for Linear { /// Vote-weight scheme where all voters get one vote plus additional votes for every excess rank /// they have incrementing by one vote for each excess rank. I.e.: /// -/// - Each member with no excess rank gets 1 vote; -/// - ...with an excess rank of 1 gets 2 votes; -/// - ...with an excess rank of 2 gets 3 votes; -/// - ...with an excess rank of 3 gets 6 votes; -/// - ...with an excess rank of 4 gets 10 votes. +/// - Each member with an excess rank of 0 gets 1 vote; +/// - ...with an excess rank of 1 gets 3 votes; +/// - ...with an excess rank of 2 gets 6 votes; +/// - ...with an excess rank of 3 gets 10 votes; +/// - ...with an excess rank of 4 gets 15 votes. pub struct Geometric; impl Convert for Geometric { fn convert(r: Rank) -> Votes { From 460fff965a2fd25d3a75ef436ec265b4c2af47a0 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 8 Oct 2022 23:15:25 +0200 Subject: [PATCH 1251/1472] Remove "to_block" field from BlockRequests (#12447) * Remove "to_block" field from BlockRequests * Maybe fix the tests --- client/network/common/src/sync/message.rs | 2 -- client/network/sync/src/lib.rs | 9 +-------- client/network/sync/src/schema/api.v1.proto | 2 -- client/network/sync/src/warp.rs | 1 - 4 files changed, 1 insertion(+), 13 deletions(-) diff --git a/client/network/common/src/sync/message.rs b/client/network/common/src/sync/message.rs index 27ab2704e6471..db9f747108c9f 100644 --- a/client/network/common/src/sync/message.rs +++ b/client/network/common/src/sync/message.rs @@ -158,8 +158,6 @@ pub mod generic { pub fields: BlockAttributes, /// Start from this block. pub from: FromBlock, - /// End at this block. An implementation defined maximum is used when unspecified. - pub to: Option, /// Sequence direction. pub direction: Direction, /// Maximum number of blocks to return. An implementation defined maximum is used when diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 6ad4a8fbbdcc5..6348490351140 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -650,7 +650,6 @@ where id: 0, fields: BlockAttributes::JUSTIFICATION, from: FromBlock::Hash(request.0), - to: None, direction: Direction::Ascending, max: Some(1), }; @@ -1608,7 +1607,6 @@ where FromBlock::Number(n) => Some(schema::v1::block_request::FromBlock::Number(n.encode())), }, - to_block: request.to.map(|h| h.encode()).unwrap_or_default(), direction: request.direction as i32, max_blocks: request.max.unwrap_or(0), support_multiple_justifications: true, @@ -2252,7 +2250,6 @@ fn ancestry_request(block: NumberFor) -> BlockRequest { id: 0, fields: BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION, from: FromBlock::Number(block), - to: None, direction: Direction::Ascending, max: Some(1), } @@ -2368,7 +2365,6 @@ fn peer_block_request( id: 0, fields: attrs, from, - to: None, direction: Direction::Descending, max: Some((range.end - range.start).saturated_into::()), }; @@ -2402,7 +2398,6 @@ fn peer_gap_block_request( id: 0, fields: attrs, from, - to: None, direction: Direction::Descending, max: Some((range.end - range.start).saturated_into::()), }; @@ -2452,7 +2447,6 @@ fn fork_sync_request( id: 0, fields: attributes, from: FromBlock::Hash(*hash), - to: None, direction: Direction::Descending, max: Some(count), }, @@ -2702,8 +2696,7 @@ mod test { assert!(sync.justification_requests().any(|(p, r)| { p == peer_id3 && r.fields == BlockAttributes::JUSTIFICATION && - r.from == FromBlock::Hash(b1_hash) && - r.to == None + r.from == FromBlock::Hash(b1_hash) })); assert_eq!( diff --git a/client/network/sync/src/schema/api.v1.proto b/client/network/sync/src/schema/api.v1.proto index b51137d1d51d4..203b157470a58 100644 --- a/client/network/sync/src/schema/api.v1.proto +++ b/client/network/sync/src/schema/api.v1.proto @@ -23,8 +23,6 @@ message BlockRequest { // Start with given block number. bytes number = 3; } - // End at this block. An implementation defined maximum is used when unspecified. - bytes to_block = 4; // optional // Sequence direction. Direction direction = 5; // Maximum number of blocks to return. An implementation defined maximum is used when unspecified. diff --git a/client/network/sync/src/warp.rs b/client/network/sync/src/warp.rs index 4f2a71d98613e..ab8a7c66b9856 100644 --- a/client/network/sync/src/warp.rs +++ b/client/network/sync/src/warp.rs @@ -193,7 +193,6 @@ where fields: BlockAttributes::HEADER | BlockAttributes::BODY | BlockAttributes::JUSTIFICATION, from: FromBlock::Hash(header.hash()), - to: Some(header.hash()), direction: Direction::Ascending, max: Some(1), }; From 73c4f94ce0cb41e35bd7fbc7095590b98a351dbb Mon Sep 17 00:00:00 2001 From: Leszek Wiesner Date: Sun, 9 Oct 2022 11:22:43 +0200 Subject: [PATCH 1252/1472] Vesting pallet - make WithdrawReasons configurable (#12109) * Vesting pallet - make WithdrawReasons configurable * Update `pallet-vesting` README Co-authored-by: parity-processbot <> --- bin/node/runtime/src/lib.rs | 5 ++++- frame/vesting/README.md | 3 ++- frame/vesting/src/lib.rs | 13 ++++++++++--- frame/vesting/src/mock.rs | 5 ++++- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 34f6988c31643..142173621036d 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -34,7 +34,7 @@ use frame_support::{ traits::{ AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, - LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, + LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, WithdrawReasons, }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, @@ -1374,6 +1374,8 @@ impl pallet_society::Config for Runtime { parameter_types! { pub const MinVestedTransfer: Balance = 100 * DOLLARS; + pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = + WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); } impl pallet_vesting::Config for Runtime { @@ -1382,6 +1384,7 @@ impl pallet_vesting::Config for Runtime { type BlockNumberToBalance = ConvertInto; type MinVestedTransfer = MinVestedTransfer; type WeightInfo = pallet_vesting::weights::SubstrateWeight; + type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; // `VestingInfo` encode length is 36bytes. 28 schedules gets encoded as 1009 bytes, which is the // highest number of schedules that encodes less than 2^10. const MAX_VESTING_SCHEDULES: u32 = 28; diff --git a/frame/vesting/README.md b/frame/vesting/README.md index c3800eb994d4d..b19a60c5b6824 100644 --- a/frame/vesting/README.md +++ b/frame/vesting/README.md @@ -7,7 +7,8 @@ A simple module providing a means of placing a linear curve on an account's locked balance. This module ensures that there is a lock in place preventing the balance to drop below the *unvested* -amount for any reason other than transaction fee payment. +amount for reason other than the ones specified in `UnvestedFundsAllowedWithdrawReasons` +configuration value. As the amount vested increases over time, the amount unvested reduces. However, locks remain in place and explicit action is needed on behalf of the user to ensure that the amount locked is diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 1ca8d41f9a41c..a92f94baf6cf9 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -24,7 +24,8 @@ //! //! A simple pallet providing a means of placing a linear curve on an account's locked balance. This //! pallet ensures that there is a lock in place preventing the balance to drop below the *unvested* -//! amount for any reason other than transaction fee payment. +//! amount for any reason other than the ones specified in `UnvestedFundsAllowedWithdrawReasons` +//! configuration value. //! //! As the amount vested increases over time, the amount unvested reduces. However, locks remain in //! place and explicit action is needed on behalf of the user to ensure that the amount locked is @@ -170,6 +171,10 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + /// Reasons that determine under which conditions the balance may drop below + /// the unvested amount. + type UnvestedFundsAllowedWithdrawReasons: Get; + /// Maximum number of vesting schedules an account may have at a given moment. const MAX_VESTING_SCHEDULES: u32; } @@ -249,7 +254,9 @@ pub mod pallet { Vesting::::try_append(who, vesting_info) .expect("Too many vesting schedules at genesis."); - let reasons = WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE; + let reasons = + WithdrawReasons::except(T::UnvestedFundsAllowedWithdrawReasons::get()); + T::Currency::set_lock(VESTING_ID, who, locked, reasons); } } @@ -569,7 +576,7 @@ impl Pallet { T::Currency::remove_lock(VESTING_ID, who); Self::deposit_event(Event::::VestingCompleted { account: who.clone() }); } else { - let reasons = WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE; + let reasons = WithdrawReasons::except(T::UnvestedFundsAllowedWithdrawReasons::get()); T::Currency::set_lock(VESTING_ID, who, total_locked_now, reasons); Self::deposit_event(Event::::VestingUpdated { account: who.clone(), diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index c4e520b37c8c8..0bd371a0353f1 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -17,7 +17,7 @@ use frame_support::{ parameter_types, - traits::{ConstU32, ConstU64, GenesisBuild}, + traits::{ConstU32, ConstU64, GenesisBuild, WithdrawReasons}, }; use sp_core::H256; use sp_runtime::{ @@ -87,6 +87,8 @@ impl pallet_balances::Config for Test { } parameter_types! { pub const MinVestedTransfer: u64 = 256 * 2; + pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = + WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); pub static ExistentialDeposit: u64 = 0; } impl Config for Test { @@ -96,6 +98,7 @@ impl Config for Test { const MAX_VESTING_SCHEDULES: u32 = 3; type MinVestedTransfer = MinVestedTransfer; type WeightInfo = (); + type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; } pub struct ExtBuilder { From 0c1ccdaa53556a106aa69c23f19527e435970237 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Mon, 10 Oct 2022 10:10:53 +0300 Subject: [PATCH 1253/1472] Move block announcement protocol config out of `Protocol` (#12441) * Move Role(s) to `sc-network-common` * Introduce `NotificationHandshake` type * Move block announce protocol config creation to `ChainSync` * Include block announcement into `notification_protocols` * Apply review comments * Remove unneeded include * Add missing include * Apply review comments --- .../src/communication/gossip.rs | 2 +- .../src/communication/tests.rs | 5 +- client/finality-grandpa/src/lib.rs | 1 + client/network-gossip/src/bridge.rs | 2 +- client/network-gossip/src/state_machine.rs | 2 +- client/network-gossip/src/validator.rs | 2 +- client/network/Cargo.toml | 2 +- client/network/common/src/config.rs | 28 ++++ client/network/common/src/protocol.rs | 1 + client/network/common/src/protocol/event.rs | 24 +-- client/network/common/src/protocol/role.rs | 121 ++++++++++++++ client/network/common/src/sync/message.rs | 28 +++- client/network/src/behaviour.rs | 5 +- client/network/src/config.rs | 29 +--- client/network/src/lib.rs | 3 +- client/network/src/protocol.rs | 151 ++++-------------- client/network/src/protocol/message.rs | 60 +------ client/network/src/service.rs | 14 +- client/network/src/service/tests.rs | 110 ++++++++++++- client/network/sync/src/lib.rs | 73 ++++++++- client/network/test/src/lib.rs | 19 ++- client/network/transactions/src/lib.rs | 6 +- client/service/src/builder.rs | 14 ++ 23 files changed, 439 insertions(+), 263 deletions(-) create mode 100644 client/network/common/src/protocol/role.rs diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 95efedf7b23b7..1ba5e0da33c96 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -90,7 +90,7 @@ use parity_scale_codec::{Decode, Encode}; use prometheus_endpoint::{register, CounterVec, Opts, PrometheusError, Registry, U64}; use rand::seq::SliceRandom; use sc_network::{PeerId, ReputationChange}; -use sc_network_common::protocol::event::ObservedRole; +use sc_network_common::protocol::role::ObservedRole; use sc_network_gossip::{MessageIntent, ValidatorContext}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index b73f6cdecdd4f..eab7bb2df50cf 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -28,10 +28,7 @@ use parity_scale_codec::Encode; use sc_network::{config::Role, Multiaddr, PeerId, ReputationChange}; use sc_network_common::{ config::MultiaddrWithPeerId, - protocol::{ - event::{Event as NetworkEvent, ObservedRole}, - ProtocolName, - }, + protocol::{event::Event as NetworkEvent, role::ObservedRole, ProtocolName}, service::{ NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkSyncForkRequest, NotificationSender, NotificationSenderError, diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index d5c05fea78aa2..a7326d57c2bf0 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -695,6 +695,7 @@ pub fn grandpa_peers_set_config( fallback_names: grandpa_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect(), // Notifications reach ~256kiB in size at the time of writing on Kusama and Polkadot. max_notification_size: 1024 * 1024, + handshake: None, set_config: sc_network_common::config::SetConfig { in_peers: 0, out_peers: 0, diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 121fa6dc9a50d..5563b3be35e8d 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -317,7 +317,7 @@ mod tests { use quickcheck::{Arbitrary, Gen, QuickCheck}; use sc_network_common::{ config::MultiaddrWithPeerId, - protocol::event::ObservedRole, + protocol::role::ObservedRole, service::{ NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, NotificationSender, NotificationSenderError, diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 30a2e9d1494be..600383cf5f70d 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -22,7 +22,7 @@ use ahash::AHashSet; use libp2p::PeerId; use lru::LruCache; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; -use sc_network_common::protocol::{event::ObservedRole, ProtocolName}; +use sc_network_common::protocol::{role::ObservedRole, ProtocolName}; use sp_runtime::traits::{Block as BlockT, Hash, HashFor}; use std::{collections::HashMap, iter, sync::Arc, time, time::Instant}; diff --git a/client/network-gossip/src/validator.rs b/client/network-gossip/src/validator.rs index 185c2cfeed2c7..77dcc3bdc8791 100644 --- a/client/network-gossip/src/validator.rs +++ b/client/network-gossip/src/validator.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use libp2p::PeerId; -use sc_network_common::protocol::event::ObservedRole; +use sc_network_common::protocol::role::ObservedRole; use sp_runtime::traits::Block as BlockT; /// Validates consensus messages. diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 08d0f28394af0..99e6c9e708e7f 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -57,7 +57,7 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3" -async-std = "1.11.0" +async-std = { version = "1.11.0", features = ["attributes"] } rand = "0.7.2" tempfile = "3.1.0" sc-network-light = { version = "0.10.0-dev", path = "./light" } diff --git a/client/network/common/src/config.rs b/client/network/common/src/config.rs index fb23cd0174922..e4a7f04c8d6e8 100644 --- a/client/network/common/src/config.rs +++ b/client/network/common/src/config.rs @@ -20,6 +20,7 @@ use crate::protocol; +use codec::Encode; use libp2p::{multiaddr, Multiaddr, PeerId}; use std::{fmt, str, str::FromStr}; @@ -199,6 +200,30 @@ impl Default for SetConfig { } } +/// Custom handshake for the notification protocol +#[derive(Debug, Clone)] +pub struct NotificationHandshake(Vec); + +impl NotificationHandshake { + /// Create new `NotificationHandshake` from an object that implements `Encode` + pub fn new(handshake: H) -> Self { + Self(handshake.encode()) + } + + /// Create new `NotificationHandshake` from raw bytes + pub fn from_bytes(bytes: Vec) -> Self { + Self(bytes) + } +} + +impl std::ops::Deref for NotificationHandshake { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + /// Extension to [`SetConfig`] for sets that aren't the default set. /// /// > **Note**: As new fields might be added in the future, please consider using the `new` method @@ -218,6 +243,8 @@ pub struct NonDefaultSetConfig { /// If a fallback is used, it will be reported in /// `sc_network::protocol::event::Event::NotificationStreamOpened::negotiated_fallback` pub fallback_names: Vec, + /// Handshake of the protocol + pub handshake: Option, /// Maximum allowed size of single notifications. pub max_notification_size: u64, /// Base configuration. @@ -231,6 +258,7 @@ impl NonDefaultSetConfig { notifications_protocol, max_notification_size, fallback_names: Vec::new(), + handshake: None, set_config: SetConfig { in_peers: 0, out_peers: 0, diff --git a/client/network/common/src/protocol.rs b/client/network/common/src/protocol.rs index 11edc373a2620..04bfaedbcac71 100644 --- a/client/network/common/src/protocol.rs +++ b/client/network/common/src/protocol.rs @@ -27,6 +27,7 @@ use std::{ use libp2p::core::upgrade; pub mod event; +pub mod role; /// The protocol name transmitted on the wire. #[derive(Debug, Clone)] diff --git a/client/network/common/src/protocol/event.rs b/client/network/common/src/protocol/event.rs index 3d8c183da495c..236913df1b120 100644 --- a/client/network/common/src/protocol/event.rs +++ b/client/network/common/src/protocol/event.rs @@ -20,6 +20,7 @@ //! events that happen on the network like DHT get/put results received. use super::ProtocolName; +use crate::protocol::role::ObservedRole; use bytes::Bytes; use libp2p::{core::PeerId, kad::record::Key}; @@ -97,26 +98,3 @@ pub enum Event { messages: Vec<(ProtocolName, Bytes)>, }, } - -/// Role that the peer sent to us during the handshake, with the addition of what our local node -/// knows about that peer. -/// -/// > **Note**: This enum is different from the `Role` enum. The `Role` enum indicates what a -/// > node says about itself, while `ObservedRole` is a `Role` merged with the -/// > information known locally about that node. -#[derive(Debug, Clone)] -pub enum ObservedRole { - /// Full node. - Full, - /// Light node. - Light, - /// Third-party authority. - Authority, -} - -impl ObservedRole { - /// Returns `true` for `ObservedRole::Light`. - pub fn is_light(&self) -> bool { - matches!(self, Self::Light) - } -} diff --git a/client/network/common/src/protocol/role.rs b/client/network/common/src/protocol/role.rs new file mode 100644 index 0000000000000..ed22830fd7170 --- /dev/null +++ b/client/network/common/src/protocol/role.rs @@ -0,0 +1,121 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use codec::{self, Encode, EncodeLike, Input, Output}; + +/// Role that the peer sent to us during the handshake, with the addition of what our local node +/// knows about that peer. +/// +/// > **Note**: This enum is different from the `Role` enum. The `Role` enum indicates what a +/// > node says about itself, while `ObservedRole` is a `Role` merged with the +/// > information known locally about that node. +#[derive(Debug, Clone)] +pub enum ObservedRole { + /// Full node. + Full, + /// Light node. + Light, + /// Third-party authority. + Authority, +} + +impl ObservedRole { + /// Returns `true` for `ObservedRole::Light`. + pub fn is_light(&self) -> bool { + matches!(self, Self::Light) + } +} + +/// Role of the local node. +#[derive(Debug, Clone)] +pub enum Role { + /// Regular full node. + Full, + /// Actual authority. + Authority, +} + +impl Role { + /// True for [`Role::Authority`]. + pub fn is_authority(&self) -> bool { + matches!(self, Self::Authority) + } +} + +impl std::fmt::Display for Role { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Full => write!(f, "FULL"), + Self::Authority => write!(f, "AUTHORITY"), + } + } +} + +bitflags::bitflags! { + /// Bitmask of the roles that a node fulfills. + pub struct Roles: u8 { + /// No network. + const NONE = 0b00000000; + /// Full node, does not participate in consensus. + const FULL = 0b00000001; + /// Light client node. + const LIGHT = 0b00000010; + /// Act as an authority + const AUTHORITY = 0b00000100; + } +} + +impl Roles { + /// Does this role represents a client that holds full chain data locally? + pub fn is_full(&self) -> bool { + self.intersects(Self::FULL | Self::AUTHORITY) + } + + /// Does this role represents a client that does not participates in the consensus? + pub fn is_authority(&self) -> bool { + *self == Self::AUTHORITY + } + + /// Does this role represents a client that does not hold full chain data locally? + pub fn is_light(&self) -> bool { + !self.is_full() + } +} + +impl<'a> From<&'a Role> for Roles { + fn from(roles: &'a Role) -> Self { + match roles { + Role::Full => Self::FULL, + Role::Authority => Self::AUTHORITY, + } + } +} + +impl Encode for Roles { + fn encode_to(&self, dest: &mut T) { + dest.push_byte(self.bits()) + } +} + +impl EncodeLike for Roles {} + +impl codec::Decode for Roles { + fn decode(input: &mut I) -> Result { + Self::from_bits(input.read_byte()?).ok_or_else(|| codec::Error::from("Invalid bytes")) + } +} diff --git a/client/network/common/src/sync/message.rs b/client/network/common/src/sync/message.rs index db9f747108c9f..346f1dbce9bcc 100644 --- a/client/network/common/src/sync/message.rs +++ b/client/network/common/src/sync/message.rs @@ -19,10 +19,12 @@ //! Network packet message types. These get serialized and put into the lower level protocol //! payload. +use crate::protocol::role::Roles; + use bitflags::bitflags; use codec::{Decode, Encode, Error, Input, Output}; pub use generic::{BlockAnnounce, FromBlock}; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; /// Type alias for using the block request type using block type parameters. pub type BlockRequest = @@ -218,3 +220,27 @@ pub mod generic { } } } + +/// Handshake sent when we open a block announces substream. +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] +pub struct BlockAnnouncesHandshake { + /// Roles of the node. + pub roles: Roles, + /// Best block number. + pub best_number: NumberFor, + /// Best block hash. + pub best_hash: B::Hash, + /// Genesis block hash. + pub genesis_hash: B::Hash, +} + +impl BlockAnnouncesHandshake { + pub fn build( + roles: Roles, + best_number: NumberFor, + best_hash: B::Hash, + genesis_hash: B::Hash, + ) -> Self { + Self { genesis_hash, roles, best_number, best_hash } + } +} diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 14962c837aa10..b31f36eb46692 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -19,7 +19,7 @@ use crate::{ discovery::{DiscoveryBehaviour, DiscoveryConfig, DiscoveryOut}, peer_info, - protocol::{message::Roles, CustomMessageOutcome, NotificationsSink, Protocol}, + protocol::{CustomMessageOutcome, NotificationsSink, Protocol}, request_responses, }; @@ -41,7 +41,8 @@ use sc_consensus::import_queue::{IncomingBlock, RuntimeOrigin}; use sc_network_common::{ config::ProtocolId, protocol::{ - event::{DhtEvent, ObservedRole}, + event::DhtEvent, + role::{ObservedRole, Roles}, ProtocolName, }, request_responses::{IfDisconnected, ProtocolConfig, RequestFailure}, diff --git a/client/network/src/config.rs b/client/network/src/config.rs index b2adfa81d065b..db3e8f0b98a33 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -23,6 +23,7 @@ pub use sc_network_common::{ config::ProtocolId, + protocol::role::Role, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, @@ -93,6 +94,9 @@ where /// Registry for recording prometheus metrics to. pub metrics_registry: Option, + /// Block announce protocol configuration + pub block_announce_config: NonDefaultSetConfig, + /// Request response configuration for the block request protocol. /// /// [`RequestResponseConfig::name`] is used to tag outgoing block requests with the correct @@ -130,31 +134,6 @@ where pub request_response_protocol_configs: Vec, } -/// Role of the local node. -#[derive(Debug, Clone)] -pub enum Role { - /// Regular full node. - Full, - /// Actual authority. - Authority, -} - -impl Role { - /// True for [`Role::Authority`]. - pub fn is_authority(&self) -> bool { - matches!(self, Self::Authority { .. }) - } -} - -impl fmt::Display for Role { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Full => write!(f, "FULL"), - Self::Authority { .. } => write!(f, "AUTHORITY"), - } - } -} - /// Sync operation mode. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum SyncMode { diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index d17f47328b804..27f2a938154fe 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -260,7 +260,8 @@ pub use libp2p::{multiaddr, Multiaddr, PeerId}; pub use protocol::PeerInfo; pub use sc_network_common::{ protocol::{ - event::{DhtEvent, Event, ObservedRole}, + event::{DhtEvent, Event}, + role::ObservedRole, ProtocolName, }, request_responses::{IfDisconnected, RequestFailure}, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index fbf651de9d49a..325e044527efa 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -31,10 +31,7 @@ use libp2p::{ Multiaddr, PeerId, }; use log::{debug, error, info, log, trace, warn, Level}; -use message::{ - generic::{Message as GenericMessage, Roles}, - Message, -}; +use message::{generic::Message as GenericMessage, Message}; use notifications::{Notifications, NotificationsOut}; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; use sc_client_api::HeaderBackend; @@ -42,13 +39,14 @@ use sc_consensus::import_queue::{ BlockImportError, BlockImportStatus, IncomingBlock, RuntimeOrigin, }; use sc_network_common::{ - config::{NonReservedPeerMode, ProtocolId}, + config::NonReservedPeerMode, error, - protocol::ProtocolName, + protocol::{role::Roles, ProtocolName}, request_responses::RequestFailure, sync::{ message::{ - BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, BlockState, + BlockAnnounce, BlockAnnouncesHandshake, BlockAttributes, BlockData, BlockRequest, + BlockResponse, BlockState, }, warp::{EncodedProof, WarpProofRequest}, BadPeer, ChainSync, OnBlockData, OnBlockJustification, OnStateData, OpaqueBlockRequest, @@ -85,8 +83,6 @@ const TICK_TIMEOUT: time::Duration = time::Duration::from_millis(1100); /// Maximum number of known block hashes to keep for a peer. const MAX_KNOWN_BLOCKS: usize = 1024; // ~32kb per peer + LruHashSet overhead -/// Maximum allowed size for a block announce. -const MAX_BLOCK_ANNOUNCE_SIZE: u64 = 1024 * 1024; /// Maximum size used for notifications in the block announce and transaction protocols. // Must be equal to `max(MAX_BLOCK_ANNOUNCE_SIZE, MAX_TRANSACTIONS_SIZE)`. @@ -235,30 +231,6 @@ pub struct PeerInfo { pub best_number: ::Number, } -/// Handshake sent when we open a block announces substream. -#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] -struct BlockAnnouncesHandshake { - /// Roles of the node. - roles: Roles, - /// Best block number. - best_number: NumberFor, - /// Best block hash. - best_hash: B::Hash, - /// Genesis block hash. - genesis_hash: B::Hash, -} - -impl BlockAnnouncesHandshake { - fn build( - roles: Roles, - best_number: NumberFor, - best_hash: B::Hash, - genesis_hash: B::Hash, - ) -> Self { - Self { genesis_hash, roles, best_number, best_hash } - } -} - impl Protocol where B: BlockT, @@ -268,12 +240,10 @@ where pub fn new( roles: Roles, chain: Arc, - protocol_id: ProtocolId, - fork_id: &Option, network_config: &config::NetworkConfiguration, - notifications_protocols_handshakes: Vec>, metrics_registry: Option<&Registry>, chain_sync: Box>, + block_announces_protocol: sc_network_common::config::NonDefaultSetConfig, ) -> error::Result<(Self, sc_peerset::PeersetHandle, Vec<(PeerId, Multiaddr)>)> { let info = chain.info(); @@ -365,51 +335,24 @@ where sc_peerset::Peerset::from_config(sc_peerset::PeersetConfig { sets }) }; - let block_announces_protocol = { - let genesis_hash = - chain.hash(0u32.into()).ok().flatten().expect("Genesis block exists; qed"); - let genesis_hash = genesis_hash.as_ref(); - if let Some(fork_id) = fork_id { - format!( - "/{}/{}/block-announces/1", - array_bytes::bytes2hex("", genesis_hash), - fork_id - ) - } else { - format!("/{}/block-announces/1", array_bytes::bytes2hex("", genesis_hash)) - } - }; - - let legacy_ba_protocol_name = format!("/{}/block-announces/1", protocol_id.as_ref()); - let behaviour = { - let best_number = info.best_number; - let best_hash = info.best_hash; - let genesis_hash = info.genesis_hash; - - let block_announces_handshake = - BlockAnnouncesHandshake::::build(roles, best_number, best_hash, genesis_hash) - .encode(); - - let sync_protocol_config = notifications::ProtocolConfig { - name: block_announces_protocol.into(), - fallback_names: iter::once(legacy_ba_protocol_name.into()).collect(), - handshake: block_announces_handshake, - max_notification_size: MAX_BLOCK_ANNOUNCE_SIZE, - }; - Notifications::new( peerset, - iter::once(sync_protocol_config).chain( - network_config.extra_sets.iter().zip(notifications_protocols_handshakes).map( - |(s, hs)| notifications::ProtocolConfig { - name: s.notifications_protocol.clone(), - fallback_names: s.fallback_names.clone(), - handshake: hs, - max_notification_size: s.max_notification_size, - }, - ), - ), + // NOTE: Block announcement protocol is still very much hardcoded into `Protocol`. + // This protocol must be the first notification protocol given to + // `Notifications` + iter::once(notifications::ProtocolConfig { + name: block_announces_protocol.notifications_protocol.clone(), + fallback_names: block_announces_protocol.fallback_names.clone(), + handshake: block_announces_protocol.handshake.as_ref().unwrap().to_vec(), + max_notification_size: block_announces_protocol.max_notification_size, + }) + .chain(network_config.extra_sets.iter().map(|s| notifications::ProtocolConfig { + name: s.notifications_protocol.clone(), + fallback_names: s.fallback_names.clone(), + handshake: s.handshake.as_ref().map_or(roles.encode(), |h| (*h).to_vec()), + max_notification_size: s.max_notification_size, + })), ) }; @@ -437,10 +380,8 @@ where }, peerset_handle: peerset_handle.clone(), behaviour, - notification_protocols: network_config - .extra_sets - .iter() - .map(|s| s.notifications_protocol.clone()) + notification_protocols: iter::once(block_announces_protocol.notifications_protocol) + .chain(network_config.extra_sets.iter().map(|s| s.notifications_protocol.clone())) .collect(), bad_handshake_substreams: Default::default(), metrics: if let Some(r) = metrics_registry { @@ -469,10 +410,7 @@ where pub fn disconnect_peer(&mut self, peer_id: &PeerId, protocol_name: ProtocolName) { if let Some(position) = self.notification_protocols.iter().position(|p| *p == protocol_name) { - self.behaviour.disconnect_peer( - peer_id, - sc_peerset::SetId::from(position + NUM_HARDCODED_PEERSETS), - ); + self.behaviour.disconnect_peer(peer_id, sc_peerset::SetId::from(position)); } else { warn!(target: "sub-libp2p", "disconnect_peer() with invalid protocol name") } @@ -1095,8 +1033,7 @@ where /// Sets the list of reserved peers for the given protocol/peerset. pub fn set_reserved_peerset_peers(&self, protocol: ProtocolName, peers: HashSet) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.peerset_handle - .set_reserved_peers(sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), peers); + self.peerset_handle.set_reserved_peers(sc_peerset::SetId::from(index), peers); } else { error!( target: "sub-libp2p", @@ -1109,10 +1046,7 @@ where /// Removes a `PeerId` from the list of reserved peers. pub fn remove_set_reserved_peer(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.peerset_handle.remove_reserved_peer( - sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), - peer, - ); + self.peerset_handle.remove_reserved_peer(sc_peerset::SetId::from(index), peer); } else { error!( target: "sub-libp2p", @@ -1125,8 +1059,7 @@ where /// Adds a `PeerId` to the list of reserved peers. pub fn add_set_reserved_peer(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.peerset_handle - .add_reserved_peer(sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), peer); + self.peerset_handle.add_reserved_peer(sc_peerset::SetId::from(index), peer); } else { error!( target: "sub-libp2p", @@ -1148,8 +1081,7 @@ where /// Add a peer to a peers set. pub fn add_to_peers_set(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.peerset_handle - .add_to_peers_set(sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), peer); + self.peerset_handle.add_to_peers_set(sc_peerset::SetId::from(index), peer); } else { error!( target: "sub-libp2p", @@ -1162,10 +1094,7 @@ where /// Remove a peer from a peers set. pub fn remove_from_peers_set(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.peerset_handle.remove_from_peers_set( - sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), - peer, - ); + self.peerset_handle.remove_from_peers_set(sc_peerset::SetId::from(index), peer); } else { error!( target: "sub-libp2p", @@ -1627,14 +1556,12 @@ where } } else { match ( - message::Roles::decode_all(&mut &received_handshake[..]), + Roles::decode_all(&mut &received_handshake[..]), self.peers.get(&peer_id), ) { (Ok(roles), _) => CustomMessageOutcome::NotificationStreamOpened { remote: peer_id, - protocol: self.notification_protocols - [usize::from(set_id) - NUM_HARDCODED_PEERSETS] - .clone(), + protocol: self.notification_protocols[usize::from(set_id)].clone(), negotiated_fallback, roles, notifications_sink, @@ -1646,9 +1573,7 @@ where // TODO: remove this after https://github.com/paritytech/substrate/issues/5685 CustomMessageOutcome::NotificationStreamOpened { remote: peer_id, - protocol: self.notification_protocols - [usize::from(set_id) - NUM_HARDCODED_PEERSETS] - .clone(), + protocol: self.notification_protocols[usize::from(set_id)].clone(), negotiated_fallback, roles: peer.info.roles, notifications_sink, @@ -1672,9 +1597,7 @@ where } else { CustomMessageOutcome::NotificationStreamReplaced { remote: peer_id, - protocol: self.notification_protocols - [usize::from(set_id) - NUM_HARDCODED_PEERSETS] - .clone(), + protocol: self.notification_protocols[usize::from(set_id)].clone(), notifications_sink, } }, @@ -1699,9 +1622,7 @@ where } else { CustomMessageOutcome::NotificationStreamClosed { remote: peer_id, - protocol: self.notification_protocols - [usize::from(set_id) - NUM_HARDCODED_PEERSETS] - .clone(), + protocol: self.notification_protocols[usize::from(set_id)].clone(), } } }, @@ -1734,9 +1655,7 @@ where _ if self.bad_handshake_substreams.contains(&(peer_id, set_id)) => CustomMessageOutcome::None, _ => { - let protocol_name = self.notification_protocols - [usize::from(set_id) - NUM_HARDCODED_PEERSETS] - .clone(); + let protocol_name = self.notification_protocols[usize::from(set_id)].clone(); CustomMessageOutcome::NotificationsReceived { remote: peer_id, messages: vec![(protocol_name, message.freeze())], diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index 3e1281753b82c..ef652387d2c7d 100644 --- a/client/network/src/protocol/message.rs +++ b/client/network/src/protocol/message.rs @@ -21,7 +21,7 @@ pub use self::generic::{ RemoteCallRequest, RemoteChangesRequest, RemoteChangesResponse, RemoteHeaderRequest, - RemoteHeaderResponse, RemoteReadChildRequest, RemoteReadRequest, Roles, + RemoteHeaderResponse, RemoteReadChildRequest, RemoteReadRequest, }; use codec::{Decode, Encode}; use sc_client_api::StorageProof; @@ -57,11 +57,11 @@ pub struct RemoteReadResponse { /// Generic types. pub mod generic { use super::{RemoteCallResponse, RemoteReadResponse}; - use bitflags::bitflags; - use codec::{Decode, Encode, Input, Output}; + use codec::{Decode, Encode, Input}; use sc_client_api::StorageProof; use sc_network_common::{ message::RequestId, + protocol::role::Roles, sync::message::{ generic::{BlockRequest, BlockResponse}, BlockAnnounce, @@ -69,60 +69,6 @@ pub mod generic { }; use sp_runtime::ConsensusEngineId; - bitflags! { - /// Bitmask of the roles that a node fulfills. - pub struct Roles: u8 { - /// No network. - const NONE = 0b00000000; - /// Full node, does not participate in consensus. - const FULL = 0b00000001; - /// Light client node. - const LIGHT = 0b00000010; - /// Act as an authority - const AUTHORITY = 0b00000100; - } - } - - impl Roles { - /// Does this role represents a client that holds full chain data locally? - pub fn is_full(&self) -> bool { - self.intersects(Self::FULL | Self::AUTHORITY) - } - - /// Does this role represents a client that does not participates in the consensus? - pub fn is_authority(&self) -> bool { - *self == Self::AUTHORITY - } - - /// Does this role represents a client that does not hold full chain data locally? - pub fn is_light(&self) -> bool { - !self.is_full() - } - } - - impl<'a> From<&'a crate::config::Role> for Roles { - fn from(roles: &'a crate::config::Role) -> Self { - match roles { - crate::config::Role::Full => Self::FULL, - crate::config::Role::Authority { .. } => Self::AUTHORITY, - } - } - } - - impl codec::Encode for Roles { - fn encode_to(&self, dest: &mut T) { - dest.push_byte(self.bits()) - } - } - - impl codec::EncodeLike for Roles {} - - impl codec::Decode for Roles { - fn decode(input: &mut I) -> Result { - Self::from_bits(input.read_byte()?).ok_or_else(|| codec::Error::from("Invalid bytes")) - } - } - /// Consensus is mostly opaque to us #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct ConsensusMessage { diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 180482e75ece2..28e479b702779 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -34,14 +34,10 @@ use crate::{ network_state::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, - protocol::{ - self, message::generic::Roles, NotificationsSink, NotifsHandlerError, PeerInfo, Protocol, - Ready, - }, + protocol::{self, NotificationsSink, NotifsHandlerError, PeerInfo, Protocol, Ready}, transport, ReputationChange, }; -use codec::Encode as _; use futures::{channel::oneshot, prelude::*}; use libp2p::{ core::{either::EitherError, upgrade, ConnectedPoint, Executor}, @@ -222,19 +218,13 @@ where local_peer_id.to_base58(), ); - let default_notif_handshake_message = Roles::from(¶ms.role).encode(); - let (protocol, peerset_handle, mut known_addresses) = Protocol::new( From::from(¶ms.role), params.chain.clone(), - params.protocol_id.clone(), - ¶ms.fork_id, ¶ms.network_config, - (0..params.network_config.extra_sets.len()) - .map(|_| default_notif_handshake_message.clone()) - .collect(), params.metrics_registry.as_ref(), params.chain_sync, + params.block_announce_config, )?; // List of multiaddresses that we know in the network. diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index c8f137f79c6dc..7c651c675b83e 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -20,10 +20,15 @@ use crate::{config, NetworkService, NetworkWorker}; use futures::prelude::*; use libp2p::PeerId; +use sc_client_api::{BlockBackend, HeaderBackend}; use sc_network_common::{ - config::{MultiaddrWithPeerId, NonDefaultSetConfig, ProtocolId, SetConfig, TransportConfig}, - protocol::event::Event, + config::{ + MultiaddrWithPeerId, NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, + ProtocolId, SetConfig, TransportConfig, + }, + protocol::{event::Event, role::Roles}, service::{NetworkEventStream, NetworkNotification, NetworkPeers, NetworkStateInfo}, + sync::message::BlockAnnouncesHandshake, }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ @@ -31,7 +36,7 @@ use sc_network_sync::{ ChainSync, }; use sp_consensus::block_validation::DefaultBlockAnnounceValidator; -use sp_runtime::traits::{Block as BlockT, Header as _}; +use sp_runtime::traits::{Block as BlockT, Header as _, Zero}; use std::{sync::Arc, time::Duration}; use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; @@ -132,7 +137,33 @@ fn build_test_full_node( None, ) .unwrap(); + + let block_announce_config = NonDefaultSetConfig { + notifications_protocol: BLOCK_ANNOUNCE_PROTO_NAME.into(), + fallback_names: vec![], + max_notification_size: 1024 * 1024, + handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::< + substrate_test_runtime_client::runtime::Block, + >::build( + Roles::from(&config::Role::Full), + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ))), + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + }; + let worker = NetworkWorker::new(config::Params { + block_announce_config, role: config::Role::Full, executor: None, network_config, @@ -161,6 +192,7 @@ fn build_test_full_node( (service, event_stream) } +const BLOCK_ANNOUNCE_PROTO_NAME: &str = "/block-announces"; const PROTOCOL_NAME: &str = "/foo"; /// Builds two nodes and their associated events stream. @@ -178,6 +210,7 @@ fn build_nodes_one_proto() -> ( notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, + handshake: None, set_config: Default::default(), }], listen_addresses: vec![listen_addr.clone()], @@ -190,6 +223,7 @@ fn build_nodes_one_proto() -> ( notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, + handshake: None, set_config: SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -368,6 +402,7 @@ fn lots_of_incoming_peers_works() { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, + handshake: None, set_config: SetConfig { in_peers: u32::MAX, ..Default::default() }, }], transport: TransportConfig::MemoryOnly, @@ -387,6 +422,7 @@ fn lots_of_incoming_peers_works() { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, + handshake: None, set_config: SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr.clone(), @@ -504,6 +540,7 @@ fn fallback_name_working() { notifications_protocol: NEW_PROTOCOL_NAME.into(), fallback_names: vec![PROTOCOL_NAME.into()], max_notification_size: 1024 * 1024, + handshake: None, set_config: Default::default(), }], listen_addresses: vec![listen_addr.clone()], @@ -516,6 +553,7 @@ fn fallback_name_working() { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, + handshake: None, set_config: SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -561,6 +599,72 @@ fn fallback_name_working() { }); } +// Disconnect peer by calling `Protocol::disconnect_peer()` with the supplied block announcement +// protocol name and verify that `SyncDisconnected` event is emitted +#[async_std::test] +async fn disconnect_sync_peer_using_block_announcement_protocol_name() { + let listen_addr = config::build_multiaddr![Memory(rand::random::())]; + + let (node1, mut events_stream1) = build_test_full_node(config::NetworkConfiguration { + extra_sets: vec![NonDefaultSetConfig { + notifications_protocol: PROTOCOL_NAME.into(), + fallback_names: vec![], + max_notification_size: 1024 * 1024, + handshake: None, + set_config: Default::default(), + }], + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + ..config::NetworkConfiguration::new_local() + }); + + let (node2, mut events_stream2) = build_test_full_node(config::NetworkConfiguration { + extra_sets: vec![NonDefaultSetConfig { + notifications_protocol: PROTOCOL_NAME.into(), + fallback_names: Vec::new(), + max_notification_size: 1024 * 1024, + handshake: None, + set_config: SetConfig { + reserved_nodes: vec![MultiaddrWithPeerId { + multiaddr: listen_addr, + peer_id: node1.local_peer_id(), + }], + ..Default::default() + }, + }], + listen_addresses: vec![], + transport: TransportConfig::MemoryOnly, + ..config::NetworkConfiguration::new_local() + }); + + loop { + match events_stream1.next().await.unwrap() { + Event::NotificationStreamOpened { .. } => break, + _ => {}, + }; + } + + loop { + match events_stream2.next().await.unwrap() { + Event::NotificationStreamOpened { .. } => break, + _ => {}, + }; + } + + // disconnect peer using `PROTOCOL_NAME`, verify `NotificationStreamClosed` event is emitted + node2.disconnect_peer(node1.local_peer_id(), PROTOCOL_NAME.into()); + assert!(std::matches!( + events_stream2.next().await, + Some(Event::NotificationStreamClosed { .. }) + )); + let _ = events_stream2.next().await; // ignore the reopen event + + // now disconnect using the block announcement protocol, verify that `SyncDisconnected` is + // emitted + node2.disconnect_peer(node1.local_peer_id(), BLOCK_ANNOUNCE_PROTO_NAME.into()); + assert!(std::matches!(events_stream2.next().await, Some(Event::SyncDisconnected { .. }))); +} + #[test] #[should_panic(expected = "don't match the transport")] fn ensure_listen_addresses_consistent_with_transport_memory() { diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 6348490351140..280e530eca9a9 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -50,15 +50,21 @@ use log::{debug, error, info, trace, warn}; use prost::Message; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; -use sc_network_common::sync::{ - message::{ - BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, - FromBlock, +use sc_network_common::{ + config::{ + NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, + }, + protocol::role::Roles, + sync::{ + message::{ + BlockAnnounce, BlockAnnouncesHandshake, BlockAttributes, BlockData, BlockRequest, + BlockResponse, Direction, FromBlock, + }, + warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, WarpSyncProvider}, + BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, OnStateData, + OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, + PollBlockAnnounceValidation, SyncMode, SyncState, SyncStatus, }, - warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, WarpSyncProvider}, - BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, OnStateData, - OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, - PollBlockAnnounceValidation, SyncMode, SyncState, SyncStatus, }; use sp_arithmetic::traits::Saturating; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; @@ -76,6 +82,7 @@ use sp_runtime::{ }; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, + iter, ops::Range, pin::Pin, sync::Arc, @@ -121,6 +128,9 @@ const MAJOR_SYNC_BLOCKS: u8 = 5; /// Number of peers that need to be connected before warp sync is started. const MIN_PEERS_TO_START_WARP_SYNC: usize = 3; +/// Maximum allowed size for a block announce. +const MAX_BLOCK_ANNOUNCE_SIZE: u64 = 1024 * 1024; + mod rep { use sc_peerset::ReputationChange as Rep; /// Reputation change when a peer sent us a message that led to a @@ -2231,6 +2241,53 @@ where } None } + + /// Get config for the block announcement protocol + pub fn get_block_announce_proto_config( + &self, + protocol_id: ProtocolId, + fork_id: &Option, + roles: Roles, + best_number: NumberFor, + best_hash: B::Hash, + genesis_hash: B::Hash, + ) -> NonDefaultSetConfig { + let block_announces_protocol = { + let genesis_hash = genesis_hash.as_ref(); + if let Some(ref fork_id) = fork_id { + format!( + "/{}/{}/block-announces/1", + array_bytes::bytes2hex("", genesis_hash), + fork_id + ) + } else { + format!("/{}/block-announces/1", array_bytes::bytes2hex("", genesis_hash)) + } + }; + + NonDefaultSetConfig { + notifications_protocol: block_announces_protocol.into(), + fallback_names: iter::once( + format!("/{}/block-announces/1", protocol_id.as_ref()).into(), + ) + .collect(), + max_notification_size: MAX_BLOCK_ANNOUNCE_SIZE, + handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( + roles, + best_number, + best_hash, + genesis_hash, + ))), + // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement + // protocol is still hardcoded into the peerset. + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + } + } } // This is purely during a backwards compatible transitionary period and should be removed diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 9d5abf98ceff0..a7c58631dc0f7 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -55,7 +55,7 @@ use sc_network_common::{ config::{ MultiaddrWithPeerId, NonDefaultSetConfig, NonReservedPeerMode, ProtocolId, TransportConfig, }, - protocol::ProtocolName, + protocol::{role::Roles, ProtocolName}, service::{NetworkBlock, NetworkStateInfo, NetworkSyncForkRequest}, sync::warp::{AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider}, }; @@ -77,7 +77,7 @@ use sp_core::H256; use sp_runtime::{ codec::{Decode, Encode}, generic::{BlockId, OpaqueDigestItemId}, - traits::{Block as BlockT, Header as HeaderT, NumberFor}, + traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, Justification, Justifications, }; use substrate_test_runtime_client::AccountKeyring; @@ -802,6 +802,7 @@ where notifications_protocol: p, fallback_names: Vec::new(), max_notification_size: 1024 * 1024, + handshake: None, set_config: Default::default(), }) .collect(); @@ -879,6 +880,19 @@ where Some(warp_sync), ) .unwrap(); + let block_announce_config = chain_sync.get_block_announce_proto_config( + protocol_id.clone(), + &fork_id, + Roles::from(if config.is_authority { &Role::Authority } else { &Role::Full }), + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ); + let network = NetworkWorker::new(sc_network::config::Params { role: if config.is_authority { Role::Authority } else { Role::Full }, executor: None, @@ -889,6 +903,7 @@ where import_queue, chain_sync: Box::new(chain_sync), metrics_registry: None, + block_announce_config, block_request_protocol_config, state_request_protocol_config, light_client_request_protocol_config, diff --git a/client/network/transactions/src/lib.rs b/client/network/transactions/src/lib.rs index b75bd411b39c4..5239a94ef23f3 100644 --- a/client/network/transactions/src/lib.rs +++ b/client/network/transactions/src/lib.rs @@ -35,10 +35,7 @@ use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network_common::{ config::{NonDefaultSetConfig, NonReservedPeerMode, ProtocolId, SetConfig}, error, - protocol::{ - event::{Event, ObservedRole}, - ProtocolName, - }, + protocol::{event::Event, role::ObservedRole, ProtocolName}, service::{NetworkEventStream, NetworkNotification, NetworkPeers}, utils::{interval, LruHashSet}, ExHashT, @@ -145,6 +142,7 @@ impl TransactionsHandlerPrototype { notifications_protocol: self.protocol_name.clone(), fallback_names: self.fallback_protocol_names.clone(), max_notification_size: MAX_TRANSACTIONS_SIZE, + handshake: None, set_config: SetConfig { in_peers: 0, out_peers: 0, diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index dfd532a14c172..4301e17a8c31e 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -40,6 +40,7 @@ use sc_keystore::LocalKeystore; use sc_network::{config::SyncMode, NetworkService}; use sc_network_bitswap::BitswapRequestHandler; use sc_network_common::{ + protocol::role::Roles, service::{NetworkStateInfo, NetworkStatusProvider}, sync::warp::WarpSyncProvider, }; @@ -843,6 +844,18 @@ where config.network.max_parallel_downloads, warp_sync_provider, )?; + let block_announce_config = chain_sync.get_block_announce_proto_config( + protocol_id.clone(), + &config.chain_spec.fork_id().map(ToOwned::to_owned), + Roles::from(&config.role.clone()), + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ); request_response_protocol_configs.push(config.network.ipfs_server.then(|| { let (handler, protocol_config) = BitswapRequestHandler::new(client.clone()); @@ -865,6 +878,7 @@ where import_queue: Box::new(import_queue), chain_sync: Box::new(chain_sync), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), + block_announce_config, block_request_protocol_config, state_request_protocol_config, warp_sync_protocol_config, From df81976c40e2e0573d59c51e12eb3c15c3ff3057 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 10 Oct 2022 16:25:11 +0200 Subject: [PATCH 1254/1472] Dont ignore errors in pallet benchmarking (#12449) Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- .../benchmarking-cli/src/pallet/command.rs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 72592617c52ac..daf4aa74e1394 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -297,16 +297,15 @@ impl PalletCmd { for (s, selected_components) in all_components.iter().enumerate() { // First we run a verification if !self.no_verify { - // Dont use these results since verification code will add overhead let state = &state_without_tracking; - let _results = StateMachine::new( + let result = StateMachine::new( state, &mut changes, &executor, "Benchmark_dispatch_benchmark", &( - &pallet.clone(), - &extrinsic.clone(), + &pallet, + &extrinsic, &selected_components.clone(), true, // run verification code 1, // no need to do internal repeats @@ -321,6 +320,20 @@ impl PalletCmd { .map_err(|e| { format!("Error executing and verifying runtime benchmark: {}", e) })?; + // Dont use these results since verification code will add overhead. + let _batch = + , String> as Decode>::decode( + &mut &result[..], + ) + .map_err(|e| format!("Failed to decode benchmark results: {:?}", e))? + .map_err(|e| { + format!( + "Benchmark {}::{} failed: {}", + String::from_utf8_lossy(&pallet), + String::from_utf8_lossy(&extrinsic), + e + ) + })?; } // Do one loop of DB tracking. { From 9672c362240d77d11f3bd56c701743f0ed86f84b Mon Sep 17 00:00:00 2001 From: Vlad Date: Mon, 10 Oct 2022 21:04:51 +0300 Subject: [PATCH 1255/1472] Update UI tests for Rust 1.64 (#12440) * Update UI tests for Rust 1.64 * Test with the staging image * Switch back to production --- .../no_std_genesis_config.stderr | 2 +- .../pallet_error_too_large.stderr | 2 +- .../undefined_call_part.stderr | 2 +- .../undefined_event_part.stderr | 2 +- .../undefined_genesis_config_part.stderr | 2 +- .../undefined_inherent_part.stderr | 12 +++++------ .../undefined_origin_part.stderr | 8 +++++-- .../undefined_validate_unsigned_part.stderr | 21 ++++++++++++------- ...ed_keyword_two_times_integrity_test.stderr | 2 +- ...ved_keyword_two_times_on_initialize.stderr | 4 ++-- .../tests/derive_no_bound_ui/debug.stderr | 4 ++-- .../call_argument_invalid_bound.stderr | 2 +- .../call_argument_invalid_bound_2.stderr | 16 +++++++------- .../call_argument_invalid_bound_3.stderr | 2 +- .../pallet_ui/event_field_not_member.stderr | 2 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 4 ++-- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 4 ++-- .../ui/impl_incorrect_method_signature.stderr | 17 +++++++++++++-- ...reference_in_impl_runtime_apis_call.stderr | 16 ++++++++++++-- 19 files changed, 80 insertions(+), 44 deletions(-) diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr index 1f08ab87c1f79..26c0717c0ad37 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr @@ -10,7 +10,7 @@ error: `Pallet` does not have the std feature enabled, this will cause the `test 49 | | } | |_^ | - = note: this error originates in the macro `test_pallet::__substrate_genesis_config_check::is_std_enabled_for_genesis` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `test_pallet::__substrate_genesis_config_check::is_std_enabled_for_genesis` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `GenesisConfig` in crate `test_pallet` --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 diff --git a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr index 161873866b6f3..99a543eef7a8a 100644 --- a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr +++ b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr @@ -10,4 +10,4 @@ error[E0080]: evaluation of constant value failed 83 | | } | |_^ the evaluated program panicked at 'The maximum encoded size of the error type in the `Pallet` pallet exceeds `MAX_MODULE_ERROR_ENCODED_SIZE`', $DIR/tests/construct_runtime_ui/pallet_error_too_large.rs:74:1 | - = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr index c162a22bb87b0..6baf01e866f64 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr @@ -13,4 +13,4 @@ error: `Pallet` does not have #[pallet::call] defined, perhaps you should remove 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_call_check::is_call_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_call_check::is_call_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index 920e627d43c31..8f2bf7be15749 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::event] defined, perhaps you should remov 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_event_check::is_event_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_event_check::is_event_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `Event` in module `pallet` --> tests/construct_runtime_ui/undefined_event_part.rs:49:1 diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr index 1bc109a45ac57..aae3aaa80c865 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::genesis_config] defined, perhaps you sho 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_genesis_config_check::is_genesis_config_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_genesis_config_check::is_genesis_config_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `GenesisConfig` in module `pallet` --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr index 9f646469d86a8..74af0c264cd5e 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr @@ -13,13 +13,13 @@ error: `Pallet` does not have #[pallet::inherent] defined, perhaps you should re 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_inherent_check::is_inherent_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_inherent_check::is_inherent_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `create_inherent` found for struct `pallet::Pallet` in the current scope --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `create_inherent` not found for this + | -------------------- function or associated item `create_inherent` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where @@ -39,7 +39,7 @@ error[E0599]: no function or associated item named `is_inherent` found for struc --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `is_inherent` not found for this + | -------------------- function or associated item `is_inherent` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where @@ -59,7 +59,7 @@ error[E0599]: no function or associated item named `check_inherent` found for st --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `check_inherent` not found for this + | -------------------- function or associated item `check_inherent` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where @@ -79,7 +79,7 @@ error[E0599]: no associated item named `INHERENT_IDENTIFIER` found for struct `p --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ associated item `INHERENT_IDENTIFIER` not found for this + | -------------------- associated item `INHERENT_IDENTIFIER` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where @@ -99,7 +99,7 @@ error[E0599]: no function or associated item named `is_inherent_required` found --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `is_inherent_required` not found for this + | -------------------- function or associated item `is_inherent_required` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr index b93a2a92911ea..1a8fe64da1758 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::origin] defined, perhaps you should remo 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_origin_check::is_origin_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_origin_check::is_origin_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `Origin` in module `pallet` --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 @@ -56,6 +56,10 @@ error[E0282]: type annotations needed ... | 57 | | } 58 | | } - | |_^ cannot infer type for type parameter `AccountId` declared on the enum `RawOrigin` + | |_^ cannot infer type of the type parameter `AccountId` declared on the enum `RawOrigin` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider specifying the generic argument + | +58 | }:: + | +++++++++++++ diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr index a5e4fe3c1cd5a..6f0b13c58933e 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr @@ -13,22 +13,27 @@ error: `Pallet` does not have #[pallet::validate_unsigned] defined, perhaps you 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no variant or associated item named `Pallet` found for enum `RuntimeCall` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:56:3 | -49 | construct_runtime! { - | ------------------ variant or associated item `Pallet` not found here -... -56 | Pallet: pallet::{Pallet, ValidateUnsigned}, - | ^^^^^^ variant or associated item not found in `RuntimeCall` +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, +... | +56 | | Pallet: pallet::{Pallet, ValidateUnsigned}, + | | ^^^^^^ variant or associated item not found in `RuntimeCall` +57 | | } +58 | | } + | |_- variant or associated item `Pallet` not found for this enum error[E0599]: no function or associated item named `pre_dispatch` found for struct `pallet::Pallet` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `pre_dispatch` not found for this + | -------------------- function or associated item `pre_dispatch` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where @@ -49,7 +54,7 @@ error[E0599]: no function or associated item named `validate_unsigned` found for --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `validate_unsigned` not found for this + | -------------------- function or associated item `validate_unsigned` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr index 47ff1c8af8cd2..4212707599d41 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr @@ -10,7 +10,7 @@ error: `integrity_test` can only be passed once as input. 7 | | } | |_^ | - = note: this error originates in the macro `$crate::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::decl_module` which comes from the expansion of the macro `frame_support::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0601]: `main` function not found in crate `$CRATE` --> tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs:7:2 diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr index bfefadee99403..94bde853e4cc8 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr @@ -1,5 +1,5 @@ error: `on_initialize` can only be passed once as input. - --> $DIR/reserved_keyword_two_times_on_initialize.rs:1:1 + --> tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs:1:1 | 1 | / frame_support::decl_module! { 2 | | pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { @@ -10,4 +10,4 @@ error: `on_initialize` can only be passed once as input. 11 | | } | |_^ | - = note: this error originates in the macro `$crate::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::decl_module` which comes from the expansion of the macro `frame_support::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/derive_no_bound_ui/debug.stderr b/frame/support/test/tests/derive_no_bound_ui/debug.stderr index 7580cab2ea0b3..acc7f80b37663 100644 --- a/frame/support/test/tests/derive_no_bound_ui/debug.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/debug.stderr @@ -1,8 +1,8 @@ error[E0277]: `::C` doesn't implement `std::fmt::Debug` - --> $DIR/debug.rs:7:2 + --> tests/derive_no_bound_ui/debug.rs:7:2 | 7 | c: T::C, | ^ `::C` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::C` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = note: required for the cast from `::C` to the object type `dyn std::fmt::Debug` diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index 1d581ea7ed572..86e8d33c8dad1 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -6,7 +6,7 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&::Bar` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound.rs:20:36 diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index b1487776eac50..c6acccaaba7d4 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -6,7 +6,7 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&::Bar` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 @@ -21,21 +21,23 @@ error[E0369]: binary operation `==` cannot be applied to type `&::Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:1:1 | -1 | / #[frame_support::pallet] +1 | #[frame_support::pallet] + | ^----------------------- + | | + | _in this procedural macro expansion + | | 2 | | mod pallet { 3 | | use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; 4 | | use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; ... | 16 | | 17 | | #[pallet::call] - | |__________________- required by a bound introduced by this call -... -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar` + | |__________________^ the trait `WrapperTypeEncode` is not implemented for `::Bar` | = note: required because of the requirements on the impl of `Encode` for `::Bar` + = note: this error originates in the derive macro `frame_support::codec::Encode` which comes from the expansion of the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound_2.rs:17:12 diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr index a0418760ba7e2..4a0b2ea67c7d6 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr @@ -7,7 +7,7 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` = help: the trait `std::fmt::Debug` is not implemented for `Bar` = note: add `#[derive(Debug)]` to `Bar` or manually `impl std::fmt::Debug for Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Bar` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&Bar` to the object type `dyn std::fmt::Debug` help: consider annotating `Bar` with `#[derive(Debug)]` | 17 | #[derive(Debug)] diff --git a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr index 92623e0329fe3..f95da9deef90a 100644 --- a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr +++ b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr @@ -18,4 +18,4 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&::Bar` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index b8a9a1128d669..cced83f207c41 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 280 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 280 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 5032f63bc1b1b..ab377e05d3901 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 280 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 280 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr index 2c47c2f480add..f5b6ac1da4576 100644 --- a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr +++ b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr @@ -18,5 +18,18 @@ note: type in trait error[E0308]: mismatched types --> tests/ui/impl_incorrect_method_signature.rs:19:11 | -19 | fn test(data: String) {} - | ^^^^ expected `u64`, found struct `std::string::String` +17 | / sp_api::impl_runtime_apis! { +18 | | impl self::Api for Runtime { +19 | | fn test(data: String) {} + | | ^^^^ expected `u64`, found struct `std::string::String` +20 | | } +... | +32 | | } +33 | | } + | |_- arguments to this function are incorrect + | +note: associated function defined here + --> tests/ui/impl_incorrect_method_signature.rs:13:6 + | +13 | fn test(data: u64); + | ^^^^ diff --git a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index 479e1cf05a9d1..6a99dcd3a1aed 100644 --- a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -18,9 +18,21 @@ note: type in trait error[E0308]: mismatched types --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:19:11 | -19 | fn test(data: &u64) { - | ^^^^^^^ expected `u64`, found `&u64` +17 | / sp_api::impl_runtime_apis! { +18 | | impl self::Api for Runtime { +19 | | fn test(data: &u64) { + | | ^^^^^^^ expected `u64`, found `&u64` +20 | | unimplemented!() +... | +34 | | } +35 | | } + | |_- arguments to this function are incorrect + | +note: associated function defined here + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:13:6 | +13 | fn test(data: u64); + | ^^^^ help: consider removing the borrow | 19 - fn test(data: &u64) { From 488fc24d98cfe643402b86990ae0aff27ba927b3 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 11 Oct 2022 11:49:12 +0300 Subject: [PATCH 1256/1472] rpc: Implement `transaction` RPC API (#12328) * rpc/tx: Add transaction structures for serialization Signed-off-by: Alexandru Vasile * rpc/tx: Add public facing `TransactionEvent` To circumvent the fact that serde does not allow mixing `#[serde(tag = "event")]` with `#[serde(tag = "event", content = "block")]` the public facing subscription structure is serialized and deserialized to an intermmediate representation. Signed-off-by: Alexandru Vasile * rpc/tx: Add trait for the `transaction` API Signed-off-by: Alexandru Vasile * rpc/tx: Convert RPC errors to transaction events Signed-off-by: Alexandru Vasile * rpc/tx: Implement `transaction` RPC methods Signed-off-by: Alexandru Vasile * tx-pool: Propagate tx index to events Signed-off-by: Alexandru Vasile * tx-pool: Adjust testing to reflect tx index in events Signed-off-by: Alexandru Vasile * rpc/tx: Convert tx-pool events for the new RPC spec Signed-off-by: Alexandru Vasile * rpc/tx: Convert tx-pool `FinalityTimeout` event to `Dropped` Signed-off-by: Alexandru Vasile * service: Enable the `transaction` API Signed-off-by: Alexandru Vasile * rpc/tx: Add tests for tx event encoding and decoding Signed-off-by: Alexandru Vasile * tx: Add indentation for subscriptions Signed-off-by: Alexandru Vasile * rpc/tx: Fix documentation Signed-off-by: Alexandru Vasile * rpc/tx: Serialize usize to hex Signed-off-by: Alexandru Vasile * tx-pool: Rename closure parameters Signed-off-by: Alexandru Vasile * service: Separate RPC spec versions Signed-off-by: Alexandru Vasile * rpc/tx: Use `H256` for testing block's hash Signed-off-by: Alexandru Vasile * rpc/tx: Serialize numbers as string Signed-off-by: Alexandru Vasile * tx-pool: Backward compatibility with RPC v1 Signed-off-by: Alexandru Vasile * Update client/rpc-spec-v2/src/transaction/transaction.rs Co-authored-by: Niklas Adolfsson * rpc/tx: Remove comment about serde clone Signed-off-by: Alexandru Vasile * rpc/tx: Use RPC custom error code for invalid tx format Signed-off-by: Alexandru Vasile * Update client/rpc-spec-v2/src/transaction/event.rs Co-authored-by: James Wilson * rpc/tx: Adjust internal structures for serialization/deserialization Signed-off-by: Alexandru Vasile Signed-off-by: Alexandru Vasile Co-authored-by: Niklas Adolfsson Co-authored-by: James Wilson --- Cargo.lock | 11 + client/rpc-spec-v2/Cargo.toml | 10 + client/rpc-spec-v2/src/lib.rs | 4 + client/rpc-spec-v2/src/transaction/api.rs | 37 ++ client/rpc-spec-v2/src/transaction/error.rs | 100 +++++ client/rpc-spec-v2/src/transaction/event.rs | 353 ++++++++++++++++++ client/rpc-spec-v2/src/transaction/mod.rs | 38 ++ .../src/transaction/transaction.rs | 208 +++++++++++ client/service/Cargo.toml | 1 + client/service/src/builder.rs | 12 + client/transaction-pool/api/Cargo.toml | 3 + client/transaction-pool/api/src/lib.rs | 62 ++- client/transaction-pool/src/graph/listener.rs | 17 +- client/transaction-pool/src/graph/pool.rs | 4 +- client/transaction-pool/src/graph/watcher.rs | 8 +- client/transaction-pool/tests/pool.rs | 41 +- 16 files changed, 873 insertions(+), 36 deletions(-) create mode 100644 client/rpc-spec-v2/src/transaction/api.rs create mode 100644 client/rpc-spec-v2/src/transaction/error.rs create mode 100644 client/rpc-spec-v2/src/transaction/event.rs create mode 100644 client/rpc-spec-v2/src/transaction/mod.rs create mode 100644 client/rpc-spec-v2/src/transaction/transaction.rs diff --git a/Cargo.lock b/Cargo.lock index 49b3dd3cf957b..04b90dfffba1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8792,10 +8792,19 @@ dependencies = [ name = "sc-rpc-spec-v2" version = "0.10.0-dev" dependencies = [ + "futures", "hex", "jsonrpsee", + "parity-scale-codec", "sc-chain-spec", + "sc-transaction-pool-api", + "serde", "serde_json", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-runtime", + "thiserror", "tokio", ] @@ -8848,6 +8857,7 @@ dependencies = [ "sc-offchain", "sc-rpc", "sc-rpc-server", + "sc-rpc-spec-v2", "sc-sysinfo", "sc-telemetry", "sc-tracing", @@ -9068,6 +9078,7 @@ dependencies = [ "futures", "log", "serde", + "serde_json", "sp-blockchain", "sp-runtime", "thiserror", diff --git a/client/rpc-spec-v2/Cargo.toml b/client/rpc-spec-v2/Cargo.toml index 12dec7464e6d0..885d415eb50d2 100644 --- a/client/rpc-spec-v2/Cargo.toml +++ b/client/rpc-spec-v2/Cargo.toml @@ -16,7 +16,17 @@ targets = ["x86_64-unknown-linux-gnu"] jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } # Internal chain structures for "chain_spec". sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } +# Pool for submitting extrinsics required by "transaction" +sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +codec = { package = "parity-scale-codec", version = "3.0.0" } +thiserror = "1.0" +serde = "1.0" hex = "0.4" +futures = "0.3.21" [dev-dependencies] serde_json = "1.0" diff --git a/client/rpc-spec-v2/src/lib.rs b/client/rpc-spec-v2/src/lib.rs index 297fda13172d6..f4b9d2f95bf97 100644 --- a/client/rpc-spec-v2/src/lib.rs +++ b/client/rpc-spec-v2/src/lib.rs @@ -24,3 +24,7 @@ #![deny(unused_crate_dependencies)] pub mod chain_spec; +pub mod transaction; + +/// Task executor that is being used by RPC subscriptions. +pub type SubscriptionTaskExecutor = std::sync::Arc; diff --git a/client/rpc-spec-v2/src/transaction/api.rs b/client/rpc-spec-v2/src/transaction/api.rs new file mode 100644 index 0000000000000..2f0c799f1cc19 --- /dev/null +++ b/client/rpc-spec-v2/src/transaction/api.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! API trait for transactions. + +use crate::transaction::event::TransactionEvent; +use jsonrpsee::proc_macros::rpc; +use sp_core::Bytes; + +#[rpc(client, server)] +pub trait TransactionApi { + /// Submit an extrinsic to watch. + /// + /// See [`TransactionEvent`](crate::transaction::event::TransactionEvent) for details on + /// transaction life cycle. + #[subscription( + name = "transaction_unstable_submitAndWatch" => "transaction_unstable_submitExtrinsic", + unsubscribe = "transaction_unstable_unwatch", + item = TransactionEvent, + )] + fn submit_and_watch(&self, bytes: Bytes); +} diff --git a/client/rpc-spec-v2/src/transaction/error.rs b/client/rpc-spec-v2/src/transaction/error.rs new file mode 100644 index 0000000000000..72a5959992f9e --- /dev/null +++ b/client/rpc-spec-v2/src/transaction/error.rs @@ -0,0 +1,100 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Transaction RPC errors. +//! +//! Errors are interpreted as transaction events for subscriptions. + +use crate::transaction::event::{TransactionError, TransactionEvent}; +use sc_transaction_pool_api::error::Error as PoolError; +use sp_runtime::transaction_validity::InvalidTransaction; + +/// Transaction RPC errors. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Transaction pool error. + #[error("Transaction pool error: {}", .0)] + Pool(#[from] PoolError), + /// Verification error. + #[error("Extrinsic verification error: {}", .0)] + Verification(Box), +} + +impl From for TransactionEvent { + fn from(e: Error) -> Self { + match e { + Error::Verification(e) => TransactionEvent::Invalid(TransactionError { + error: format!("Verification error: {}", e), + }), + Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Custom(e))) => + TransactionEvent::Invalid(TransactionError { + error: format!("Invalid transaction with custom error: {}", e), + }), + Error::Pool(PoolError::InvalidTransaction(e)) => { + let msg: &str = e.into(); + TransactionEvent::Invalid(TransactionError { + error: format!("Invalid transaction: {}", msg), + }) + }, + Error::Pool(PoolError::UnknownTransaction(e)) => { + let msg: &str = e.into(); + TransactionEvent::Invalid(TransactionError { + error: format!("Unknown transaction validity: {}", msg), + }) + }, + Error::Pool(PoolError::TemporarilyBanned) => + TransactionEvent::Invalid(TransactionError { + error: "Transaction is temporarily banned".into(), + }), + Error::Pool(PoolError::AlreadyImported(_)) => + TransactionEvent::Invalid(TransactionError { + error: "Transaction is already imported".into(), + }), + Error::Pool(PoolError::TooLowPriority { old, new }) => + TransactionEvent::Invalid(TransactionError { + error: format!( + "The priority of the transactin is too low (pool {} > current {})", + old, new + ), + }), + Error::Pool(PoolError::CycleDetected) => TransactionEvent::Invalid(TransactionError { + error: "The transaction contains a cyclic dependency".into(), + }), + Error::Pool(PoolError::ImmediatelyDropped) => + TransactionEvent::Invalid(TransactionError { + error: "The transaction could not enter the pool because of the limit".into(), + }), + Error::Pool(PoolError::Unactionable) => TransactionEvent::Invalid(TransactionError { + error: "Transaction cannot be propagated and the local node does not author blocks" + .into(), + }), + Error::Pool(PoolError::NoTagsProvided) => TransactionEvent::Invalid(TransactionError { + error: "Transaction does not provide any tags, so the pool cannot identify it" + .into(), + }), + Error::Pool(PoolError::InvalidBlockId(_)) => + TransactionEvent::Invalid(TransactionError { + error: "The provided block ID is not valid".into(), + }), + Error::Pool(PoolError::RejectedFutureTransaction) => + TransactionEvent::Invalid(TransactionError { + error: "The pool is not accepting future transactions".into(), + }), + } + } +} diff --git a/client/rpc-spec-v2/src/transaction/event.rs b/client/rpc-spec-v2/src/transaction/event.rs new file mode 100644 index 0000000000000..3c75eaff10fd4 --- /dev/null +++ b/client/rpc-spec-v2/src/transaction/event.rs @@ -0,0 +1,353 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! The transaction's event returned as json compatible object. + +use serde::{Deserialize, Serialize}; + +/// The transaction was broadcasted to a number of peers. +/// +/// # Note +/// +/// The RPC does not guarantee that the peers have received the +/// transaction. +/// +/// When the number of peers is zero, the event guarantees that +/// shutting down the local node will lead to the transaction +/// not being included in the chain. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionBroadcasted { + /// The number of peers the transaction was broadcasted to. + #[serde(with = "as_string")] + pub num_peers: usize, +} + +/// The transaction was included in a block of the chain. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionBlock { + /// The hash of the block the transaction was included into. + pub hash: Hash, + /// The index (zero-based) of the transaction within the body of the block. + #[serde(with = "as_string")] + pub index: usize, +} + +/// The transaction could not be processed due to an error. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionError { + /// Reason of the error. + pub error: String, +} + +/// The transaction was dropped because of exceeding limits. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionDropped { + /// True if the transaction was broadcasted to other peers and + /// may still be included in the block. + pub broadcasted: bool, + /// Reason of the event. + pub error: String, +} + +/// Possible transaction status events. +/// +/// The status events can be grouped based on their kinds as: +/// +/// 1. Runtime validated the transaction: +/// - `Validated` +/// +/// 2. Inside the `Ready` queue: +/// - `Broadcast` +/// +/// 3. Leaving the pool: +/// - `BestChainBlockIncluded` +/// - `Invalid` +/// +/// 4. Block finalized: +/// - `Finalized` +/// +/// 5. At any time: +/// - `Dropped` +/// - `Error` +/// +/// The subscription's stream is considered finished whenever the following events are +/// received: `Finalized`, `Error`, `Invalid` or `Dropped`. However, the user is allowed +/// to unsubscribe at any moment. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +// We need to manually specify the trait bounds for the `Hash` trait to ensure `into` and +// `from` still work. +#[serde(bound( + serialize = "Hash: Serialize + Clone", + deserialize = "Hash: Deserialize<'de> + Clone" +))] +#[serde(into = "TransactionEventIR", from = "TransactionEventIR")] +pub enum TransactionEvent { + /// The transaction was validated by the runtime. + Validated, + /// The transaction was broadcasted to a number of peers. + Broadcasted(TransactionBroadcasted), + /// The transaction was included in a best block of the chain. + /// + /// # Note + /// + /// This may contain `None` if the block is no longer a best + /// block of the chain. + BestChainBlockIncluded(Option>), + /// The transaction was included in a finalized block. + Finalized(TransactionBlock), + /// The transaction could not be processed due to an error. + Error(TransactionError), + /// The transaction is marked as invalid. + Invalid(TransactionError), + /// The client was not capable of keeping track of this transaction. + Dropped(TransactionDropped), +} + +/// Intermediate representation (IR) for the transaction events +/// that handles block events only. +/// +/// The block events require a JSON compatible interpretation similar to: +/// +/// ```json +/// { event: "EVENT", block: { hash: "0xFF", index: 0 } } +/// ``` +/// +/// This IR is introduced to circumvent that the block events need to +/// be serialized/deserialized with "tag" and "content", while other +/// events only require "tag". +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "event", content = "block")] +enum TransactionEventBlockIR { + /// The transaction was included in the best block of the chain. + BestChainBlockIncluded(Option>), + /// The transaction was included in a finalized block of the chain. + Finalized(TransactionBlock), +} + +/// Intermediate representation (IR) for the transaction events +/// that handles non-block events only. +/// +/// The non-block events require a JSON compatible interpretation similar to: +/// +/// ```json +/// { event: "EVENT", num_peers: 0 } +/// ``` +/// +/// This IR is introduced to circumvent that the block events need to +/// be serialized/deserialized with "tag" and "content", while other +/// events only require "tag". +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "event")] +enum TransactionEventNonBlockIR { + Validated, + Broadcasted(TransactionBroadcasted), + Error(TransactionError), + Invalid(TransactionError), + Dropped(TransactionDropped), +} + +/// Intermediate representation (IR) used for serialization/deserialization of the +/// [`TransactionEvent`] in a JSON compatible format. +/// +/// Serde cannot mix `#[serde(tag = "event")]` with `#[serde(tag = "event", content = "block")]` +/// for specific enum variants. Therefore, this IR is introduced to circumvent this +/// restriction, while exposing a simplified [`TransactionEvent`] for users of the +/// rust ecosystem. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(bound(serialize = "Hash: Serialize", deserialize = "Hash: Deserialize<'de>"))] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +enum TransactionEventIR { + Block(TransactionEventBlockIR), + NonBlock(TransactionEventNonBlockIR), +} + +impl From> for TransactionEventIR { + fn from(value: TransactionEvent) -> Self { + match value { + TransactionEvent::Validated => + TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Validated), + TransactionEvent::Broadcasted(event) => + TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Broadcasted(event)), + TransactionEvent::BestChainBlockIncluded(event) => + TransactionEventIR::Block(TransactionEventBlockIR::BestChainBlockIncluded(event)), + TransactionEvent::Finalized(event) => + TransactionEventIR::Block(TransactionEventBlockIR::Finalized(event)), + TransactionEvent::Error(event) => + TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Error(event)), + TransactionEvent::Invalid(event) => + TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Invalid(event)), + TransactionEvent::Dropped(event) => + TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Dropped(event)), + } + } +} + +impl From> for TransactionEvent { + fn from(value: TransactionEventIR) -> Self { + match value { + TransactionEventIR::NonBlock(status) => match status { + TransactionEventNonBlockIR::Validated => TransactionEvent::Validated, + TransactionEventNonBlockIR::Broadcasted(event) => + TransactionEvent::Broadcasted(event), + TransactionEventNonBlockIR::Error(event) => TransactionEvent::Error(event), + TransactionEventNonBlockIR::Invalid(event) => TransactionEvent::Invalid(event), + TransactionEventNonBlockIR::Dropped(event) => TransactionEvent::Dropped(event), + }, + TransactionEventIR::Block(block) => match block { + TransactionEventBlockIR::Finalized(event) => TransactionEvent::Finalized(event), + TransactionEventBlockIR::BestChainBlockIncluded(event) => + TransactionEvent::BestChainBlockIncluded(event), + }, + } + } +} + +/// Serialize and deserialize helper as string. +mod as_string { + use super::*; + use serde::{Deserializer, Serializer}; + + pub fn serialize(data: &usize, serializer: S) -> Result { + data.to_string().serialize(serializer) + } + + pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result { + String::deserialize(deserializer)? + .parse() + .map_err(|e| serde::de::Error::custom(format!("Parsing failed: {}", e))) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::H256; + + #[test] + fn validated_event() { + let event: TransactionEvent<()> = TransactionEvent::Validated; + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"validated"}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn broadcasted_event() { + let event: TransactionEvent<()> = + TransactionEvent::Broadcasted(TransactionBroadcasted { num_peers: 2 }); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"broadcasted","numPeers":"2"}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn best_chain_event() { + let event: TransactionEvent<()> = TransactionEvent::BestChainBlockIncluded(None); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"bestChainBlockIncluded","block":null}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + + let event: TransactionEvent = + TransactionEvent::BestChainBlockIncluded(Some(TransactionBlock { + hash: H256::from_low_u64_be(1), + index: 2, + })); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"bestChainBlockIncluded","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":"2"}}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn finalized_event() { + let event: TransactionEvent = TransactionEvent::Finalized(TransactionBlock { + hash: H256::from_low_u64_be(1), + index: 10, + }); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"finalized","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":"10"}}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn error_event() { + let event: TransactionEvent<()> = + TransactionEvent::Error(TransactionError { error: "abc".to_string() }); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"error","error":"abc"}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn invalid_event() { + let event: TransactionEvent<()> = + TransactionEvent::Invalid(TransactionError { error: "abc".to_string() }); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"invalid","error":"abc"}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn dropped_event() { + let event: TransactionEvent<()> = TransactionEvent::Dropped(TransactionDropped { + broadcasted: true, + error: "abc".to_string(), + }); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"dropped","broadcasted":true,"error":"abc"}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } +} diff --git a/client/rpc-spec-v2/src/transaction/mod.rs b/client/rpc-spec-v2/src/transaction/mod.rs new file mode 100644 index 0000000000000..bb983894a428c --- /dev/null +++ b/client/rpc-spec-v2/src/transaction/mod.rs @@ -0,0 +1,38 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate transaction API. +//! +//! The transaction methods allow submitting a transaction and subscribing to +//! its status updates generated by the chain. +//! +//! # Note +//! +//! Methods are prefixed by `transaction`. + +pub mod api; +pub mod error; +pub mod event; +pub mod transaction; + +pub use api::TransactionApiServer; +pub use event::{ + TransactionBlock, TransactionBroadcasted, TransactionDropped, TransactionError, + TransactionEvent, +}; +pub use transaction::Transaction; diff --git a/client/rpc-spec-v2/src/transaction/transaction.rs b/client/rpc-spec-v2/src/transaction/transaction.rs new file mode 100644 index 0000000000000..e2cf736dff17a --- /dev/null +++ b/client/rpc-spec-v2/src/transaction/transaction.rs @@ -0,0 +1,208 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! API implementation for submitting transactions. + +use crate::{ + transaction::{ + api::TransactionApiServer, + error::Error, + event::{ + TransactionBlock, TransactionBroadcasted, TransactionDropped, TransactionError, + TransactionEvent, + }, + }, + SubscriptionTaskExecutor, +}; +use jsonrpsee::{ + core::async_trait, + types::{ + error::{CallError, ErrorObject}, + SubscriptionResult, + }, + SubscriptionSink, +}; +use sc_transaction_pool_api::{ + error::IntoPoolError, BlockHash, TransactionFor, TransactionPool, TransactionSource, + TransactionStatus, +}; +use std::sync::Arc; + +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_core::Bytes; +use sp_runtime::{generic, traits::Block as BlockT}; + +use codec::Decode; +use futures::{FutureExt, StreamExt, TryFutureExt}; + +/// An API for transaction RPC calls. +pub struct Transaction { + /// Substrate client. + client: Arc, + /// Transactions pool. + pool: Arc, + /// Executor to spawn subscriptions. + executor: SubscriptionTaskExecutor, +} + +impl Transaction { + /// Creates a new [`Transaction`]. + pub fn new(client: Arc, pool: Arc, executor: SubscriptionTaskExecutor) -> Self { + Transaction { client, pool, executor } + } +} + +/// Currently we treat all RPC transactions as externals. +/// +/// Possibly in the future we could allow opt-in for special treatment +/// of such transactions, so that the block authors can inject +/// some unique transactions via RPC and have them included in the pool. +const TX_SOURCE: TransactionSource = TransactionSource::External; + +/// Extrinsic has an invalid format. +/// +/// # Note +/// +/// This is similar to the old `author` API error code. +const BAD_FORMAT: i32 = 1001; + +#[async_trait] +impl TransactionApiServer> for Transaction +where + Pool: TransactionPool + Sync + Send + 'static, + Pool::Hash: Unpin, + ::Hash: Unpin, + Client: HeaderBackend + ProvideRuntimeApi + Send + Sync + 'static, +{ + fn submit_and_watch(&self, mut sink: SubscriptionSink, xt: Bytes) -> SubscriptionResult { + // This is the only place where the RPC server can return an error for this + // subscription. Other defects must be signaled as events to the sink. + let decoded_extrinsic = match TransactionFor::::decode(&mut &xt[..]) { + Ok(decoded_extrinsic) => decoded_extrinsic, + Err(e) => { + let err = CallError::Custom(ErrorObject::owned( + BAD_FORMAT, + format!("Extrinsic has invalid format: {}", e), + None::<()>, + )); + let _ = sink.reject(err); + return Ok(()) + }, + }; + + let best_block_hash = self.client.info().best_hash; + + let submit = self + .pool + .submit_and_watch( + &generic::BlockId::hash(best_block_hash), + TX_SOURCE, + decoded_extrinsic, + ) + .map_err(|e| { + e.into_pool_error() + .map(Error::from) + .unwrap_or_else(|e| Error::Verification(Box::new(e))) + }); + + let fut = async move { + match submit.await { + Ok(stream) => { + let mut state = TransactionState::new(); + let stream = + stream.filter_map(|event| async move { state.handle_event(event) }); + sink.pipe_from_stream(stream.boxed()).await; + }, + Err(err) => { + // We have not created an `Watcher` for the tx. Make sure the + // error is still propagated as an event. + let event: TransactionEvent<::Hash> = err.into(); + sink.pipe_from_stream(futures::stream::once(async { event }).boxed()).await; + }, + }; + }; + + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + Ok(()) + } +} + +/// The transaction's state that needs to be preserved between +/// multiple events generated by the transaction-pool. +/// +/// # Note +/// +/// In the future, the RPC server can submit only the last event when multiple +/// identical events happen in a row. +#[derive(Clone, Copy)] +struct TransactionState { + /// True if the transaction was previously broadcasted. + broadcasted: bool, +} + +impl TransactionState { + /// Construct a new [`TransactionState`]. + pub fn new() -> Self { + TransactionState { broadcasted: false } + } + + /// Handle events generated by the transaction-pool and convert them + /// to the new API expected state. + #[inline] + pub fn handle_event( + &mut self, + event: TransactionStatus, + ) -> Option> { + match event { + TransactionStatus::Ready | TransactionStatus::Future => + Some(TransactionEvent::::Validated), + TransactionStatus::Broadcast(peers) => { + // Set the broadcasted flag once if we submitted the transaction to + // at least one peer. + self.broadcasted = self.broadcasted || !peers.is_empty(); + + Some(TransactionEvent::Broadcasted(TransactionBroadcasted { + num_peers: peers.len(), + })) + }, + TransactionStatus::InBlock((hash, index)) => + Some(TransactionEvent::BestChainBlockIncluded(Some(TransactionBlock { + hash, + index, + }))), + TransactionStatus::Retracted(_) => Some(TransactionEvent::BestChainBlockIncluded(None)), + TransactionStatus::FinalityTimeout(_) => + Some(TransactionEvent::Dropped(TransactionDropped { + broadcasted: self.broadcasted, + error: "Maximum number of finality watchers has been reached".into(), + })), + TransactionStatus::Finalized((hash, index)) => + Some(TransactionEvent::Finalized(TransactionBlock { hash, index })), + TransactionStatus::Usurped(_) => Some(TransactionEvent::Invalid(TransactionError { + error: "Extrinsic was rendered invalid by another extrinsic".into(), + })), + TransactionStatus::Dropped => Some(TransactionEvent::Invalid(TransactionError { + error: "Extrinsic dropped from the pool due to exceeding limits".into(), + })), + TransactionStatus::Invalid => Some(TransactionEvent::Invalid(TransactionError { + error: "Extrinsic marked as invalid".into(), + })), + } + } +} diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 308da96fbbe77..a0c8f21effec1 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -69,6 +69,7 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/a sp-transaction-storage-proof = { version = "4.0.0-dev", path = "../../primitives/transaction-storage-proof" } sc-rpc-server = { version = "4.0.0-dev", path = "../rpc-servers" } sc-rpc = { version = "4.0.0-dev", path = "../rpc" } +sc-rpc-spec-v2 = { version = "0.10.0-dev", path = "../rpc-spec-v2" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-builder" } sc-informant = { version = "0.10.0-dev", path = "../informant" } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 4301e17a8c31e..987198d4b7f48 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -57,6 +57,7 @@ use sc_rpc::{ system::SystemApiServer, DenyUnsafe, SubscriptionTaskExecutor, }; +use sc_rpc_spec_v2::transaction::TransactionApiServer; use sc_telemetry::{telemetry, ConnectionMessage, Telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sc_transaction_pool_api::MaintainedTransactionPool; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; @@ -673,6 +674,13 @@ where (chain, state, child_state) }; + let transaction_v2 = sc_rpc_spec_v2::transaction::Transaction::new( + client.clone(), + transaction_pool.clone(), + task_executor.clone(), + ) + .into_rpc(); + let author = sc_rpc::author::Author::new( client.clone(), transaction_pool, @@ -690,6 +698,10 @@ where rpc_api.merge(offchain).map_err(|e| Error::Application(e.into()))?; } + // Part of the RPC v2 spec. + rpc_api.merge(transaction_v2).map_err(|e| Error::Application(e.into()))?; + + // Part of the old RPC spec. rpc_api.merge(chain).map_err(|e| Error::Application(e.into()))?; rpc_api.merge(author).map_err(|e| Error::Application(e.into()))?; rpc_api.merge(system).map_err(|e| Error::Application(e.into()))?; diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index d34ffe512b023..1ab0f32bc8bad 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -15,3 +15,6 @@ serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } + +[dev-dependencies] +serde_json = "1.0" diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index 0ebb8f9d4cd9c..c0a94516ffc97 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -108,15 +108,18 @@ pub enum TransactionStatus { Ready, /// The transaction has been broadcast to the given peers. Broadcast(Vec), - /// Transaction has been included in block with given hash. - InBlock(BlockHash), + /// Transaction has been included in block with given hash + /// at the given position. + #[serde(with = "v1_compatible")] + InBlock((BlockHash, TxIndex)), /// The block this transaction was included in has been retracted. Retracted(BlockHash), /// Maximum number of finality watchers has been reached, /// old watchers are being removed. FinalityTimeout(BlockHash), - /// Transaction has been finalized by a finality-gadget, e.g GRANDPA - Finalized(BlockHash), + /// Transaction has been finalized by a finality-gadget, e.g GRANDPA. + #[serde(with = "v1_compatible")] + Finalized((BlockHash, TxIndex)), /// Transaction has been replaced in the pool, by another transaction /// that provides the same tags. (e.g. same (sender, nonce)). Usurped(Hash), @@ -143,6 +146,8 @@ pub type TransactionFor